makefile010075500020550007177000000140770665315321300136110ustar00clevecompmath00000400000006drivers : cd A2 ; make all_drivers cd BKL ; make all_drivers cd BPG ; make all_drivers cd Chv ; make all_drivers cd ChvList ; make all_drivers cd ChvManager ; make all_drivers cd Coords ; make all_drivers cd DSTree ; make all_drivers cd DV ; make all_drivers cd DenseMtx ; make all_drivers cd Drand ; make all_drivers cd EGraph ; make all_drivers cd ETree ; make all_drivers cd FrontMtx ; make all_drivers cd GPart ; make all_drivers cd Graph ; make all_drivers cd I2Ohash ; make all_drivers cd IIheap ; make all_drivers cd IV ; make all_drivers cd IVL ; make all_drivers cd Ideq ; make all_drivers cd InpMtx ; make all_drivers cd Lock ; make all_drivers cd MPI ; make all_drivers cd MSMD ; make all_drivers cd MT ; make all_drivers cd Network ; make all_drivers cd PatchAndGoInfo ; make all_drivers cd Pencil ; make all_drivers cd Perm ; make all_drivers cd SemiImplMtx ; make all_drivers cd SolveMap ; make all_drivers cd SubMtx ; make all_drivers cd SubMtxList ; make all_drivers cd SubMtxManager ; make all_drivers cd SymbFac ; make all_drivers cd Tree ; make all_drivers cd Utilities ; make all_drivers cd ZV ; make all_drivers cd misc ; make all_drivers clean : cd A2 ; make clean cd BKL ; make clean cd BPG ; make clean cd Chv ; make clean cd ChvList ; make clean cd ChvManager ; make clean cd Coords ; make clean cd DSTree ; make clean cd DV ; make clean cd DenseMtx ; make clean cd Drand ; make clean cd EGraph ; make clean cd ETree ; make clean cd FrontMtx ; make clean cd GPart ; make clean cd Graph ; make clean cd I2Ohash ; make clean cd IIheap ; make clean cd IV ; make clean cd IVL ; make clean cd Ideq ; make clean cd InpMtx ; make clean cd Lock ; make clean cd MPI ; make clean cd MSMD ; make clean cd MT ; make clean cd Network ; make clean cd PatchAndGoInfo ; make clean cd Pencil ; make clean cd Perm ; make clean cd SemiImplMtx ; make clean cd SolveMap ; make clean cd SubMtx ; make clean cd SubMtxList ; make clean cd SubMtxManager ; make clean cd SymbFac ; make clean cd Tree ; make clean cd Utilities ; make clean cd ZV ; make clean cd misc ; make clean cd documentation ; make clean - rm -f *.o *.a lib : cd A2 ; make lib cd BKL ; make lib cd BPG ; make lib cd Chv ; make lib cd ChvList ; make lib cd ChvManager ; make lib cd Coords ; make lib cd DSTree ; make lib cd DV ; make lib cd DenseMtx ; make lib cd Drand ; make lib cd EGraph ; make lib cd ETree ; make lib cd FrontMtx ; make lib cd GPart ; make lib cd Graph ; make lib cd I2Ohash ; make lib cd IIheap ; make lib cd IV ; make lib cd IVL ; make lib cd Ideq ; make lib cd InpMtx ; make lib cd Lock ; make lib cd MSMD ; make lib cd Network ; make lib cd PatchAndGoInfo ; make lib cd Pencil ; make lib cd Perm ; make lib cd SemiImplMtx ; make lib cd SolveMap ; make lib cd SubMtx ; make lib cd SubMtxList ; make lib cd SubMtxManager ; make lib cd SymbFac ; make lib cd Tree ; make lib cd Utilities ; make lib cd ZV ; make lib cd misc ; make lib #cd MPI ; make lib #cd MT ; make lib global : cd A2/src ; make -f makeGlobalLib cd BKL/src ; make -f makeGlobalLib cd BPG/src ; make -f makeGlobalLib cd Chv/src ; make -f makeGlobalLib cd ChvList/src ; make -f makeGlobalLib cd ChvManager/src ; make -f makeGlobalLib cd Coords/src ; make -f makeGlobalLib cd DSTree/src ; make -f makeGlobalLib cd DV/src ; make -f makeGlobalLib cd DenseMtx/src ; make -f makeGlobalLib cd Drand/src ; make -f makeGlobalLib cd EGraph/src ; make -f makeGlobalLib cd ETree/src ; make -f makeGlobalLib cd FrontMtx/src ; make -f makeGlobalLib cd GPart/src ; make -f makeGlobalLib cd Graph/src ; make -f makeGlobalLib cd I2Ohash/src ; make -f makeGlobalLib cd IIheap/src ; make -f makeGlobalLib cd IV/src ; make -f makeGlobalLib cd IVL/src ; make -f makeGlobalLib cd Ideq/src ; make -f makeGlobalLib cd InpMtx/src ; make -f makeGlobalLib cd Lock/src ; make -f makeGlobalLib cd MSMD/src ; make -f makeGlobalLib cd Network/src ; make -f makeGlobalLib cd PatchAndGoInfo/src ; make -f makeGlobalLib cd Pencil/src ; make -f makeGlobalLib cd Perm/src ; make -f makeGlobalLib cd SemiImplMtx/src ; make -f makeGlobalLib cd SolveMap/src ; make -f makeGlobalLib cd SubMtx/src ; make -f makeGlobalLib cd SubMtxList/src ; make -f makeGlobalLib cd SubMtxManager/src ; make -f makeGlobalLib cd SymbFac/src ; make -f makeGlobalLib cd Tree/src ; make -f makeGlobalLib cd Utilities/src ; make -f makeGlobalLib cd ZV/src ; make -f makeGlobalLib cd misc/src ; make -f makeGlobalLib #cd MPI/src ; make -f makeGlobalLib #cd MT/src ; make -f makeGlobalLib makeLib010075500020550007177000000050220663577111600133760ustar00clevecompmath00000400000006#! /usr/local/gnu/bin/perl # #----------------------------------------------------------------------- # # purpose : to help create the spooles.a library from scratch # # the spooles.a library is a global library and contains all spooles # methods. (this is in contrast to local libraries that contain # methods for only one object, e.g., A2/src/A2.a) # # the spooles.a library is usually created once, by executing # "make global" in the spooles directory, which compiles each # and every source file in all the object/src directories. # (not quite true, just every src file that is found in # object/src/makefile, which is considered as gospel.) # the "make global" command goes into each object's src directory, # calls this perl script to create a makefile that will compile # each src file and load into the spooles.a library, and then # executes that makefile and removes it. # # for those systems that do not have perl installed, we have a # makeGlobalLib makefile in each object's src directory. # typing "make Global" in the spooles directory will use # this makefile. unfortunately, each object's /src/makefile # and /src/makeGlobalLib are separate and must be kept up to date # manually. (i.e., add another src file to /src/makefile and you # must add the same to /src/makeGlobalLib). # # this is my second perl script, so don't laugh, # just send me comments and suggestions. # # created -- 98dec16, cca # #----------------------------------------------------------------------- # # open the makefile to extract out the src file names # $makefile = "makefile" ; open( MAKEFILE, $makefile ) or die "Cannot open $makefile" ; # # read in each line, look for $(OBJ).a(srcname.o) # put srcname into the @srcnames array # while ( $line = ) { chop($line) ; if ( $line =~ /OBJ =/ ) { ($first, $objname) = split /OBJ = /, $line } if ( $line =~ /\$\(OBJ\)\.a\(/ ) { ($first, $second) = split /\$\(OBJ\)\.a\(/, $line ; ($srcname, $remainder) = split /\.o\)/, $second ; $srcname = $srcname . ".c" ; push @srcnames, $srcname } } # # now start printing the makefile to stdout # print "\ninclude ../../Make.inc" ; print "\n" ; print "\nOBJ = $objname" ; print "\n\nSRC = " ; foreach $src ( @srcnames ) { $srcname = " \\\n " . $src ; print $srcname ; } print "\n\nOBJ_FILES = \$\{SRC:.c=.o\}" ; print "\n\n" ; print <<'EOF' ; .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a EOF bin/perl # #----------------------------------------------------------------------- # # purpose : to help create the spooles.a library from scratch # # the spooles.a library is a global library and contains all spooles # methods. (this is in contrast to local libraries that contain # methods for only one object, e.g., A2/src/A2.a) # # the spooles.a library is usually created once, by executing # "make global" in the spooles directory, which compiles each # and every source file in all tupdLib010075500020550007177000000105450663577101000132500ustar00clevecompmath00000400000006#! /usr/local/gnu/bin/perl # #----------------------------------------------------------------------- # # purpose : to provide incremental updates to the spooles.a library # # the spooles.a library is a global library and contains all spooles # methods. (this is in contrast to local libraries that contain # methods for only one object, e.g., A2/src/A2.a) # # the spooles.a library is usually created once, by executing # "make global" in the spooles directory, which compiles each # and every source file in all the object/src directories. # on many systems this can take quite a long time. # # there are times when we make a change to one method and want to # update the spooles.a library. calling "make global" in the # spooles directory would compile all the source once again. # # what is needed is a way to compile only those src files that # need to be compiled. well, we haven't quite achieved this. # what this perl script helps do is to create a makefile (written # to stdout) that will compile all src files that are more recent # than spooles.a library. this perl script is called when # executing "make updateLib" within the object's src directory. # # this works well in some cases. for example, let us say that we # are working in the FrontMtx/drivers directory and we see that # the A2/src/QRreduce.c file needs a change. we open another window, # move to the A2/src directory, and make the change in QRreduce.c. # we then execute "make updateLib", which first calls this # script to generate a makefile that will compile QRreduce.c # and load into spooles.a. the makefile is then executed to perform # that operation, and then removed. we have a good incremental # change to the global spooles.a library. # # here is a second case where it doesn't work as well. assume again # that we are working in the FrontMtx/drivers directory, and we # see that changes need to be made to two different src files, # the first A2/src/QRreduce.c and the second SubMtx/src/util.c. # we edit the two source files and then need to update the spooles.a # library. # # we first go to the A2/src directory and execute "make updateLib" # then the QRreduce.c file gets compiled and loaded into spooles.a. # we then go to the SubMtx/src directory and execute "make updateLib" # and the util.c file # is NOT compiled and loaded into the library. # this is because spooles.a is more recent the SubMtx/src/util.c, # because spooles.a was just modified when A2/src/QRreduce.c was # compiled and loaded. # # i presently don't know of a clean solution to this problem # (and am open to suggestions). a decent workaround is this. # (1) go to A2/src, modify QRreduce.c, then "make updateLib" # (2) go to SubMtx/src, modify util.c, then "make updateLib" # here the util.c file is more recent than spooles.a. in other words, # update the library after each src file is changed. # # this is my first perl script, so don't laugh, # just send me comments and suggestions. # # created -- 98dec16, cca # #----------------------------------------------------------------------- # # open the makefile to extract out the src file names # $makefile = "makefile" ; open( MAKEFILE, $makefile ) or die "Cannot open $makefile" ; # # get the last modification time for ../../spooles.a # if ( -e "../../spooles.a" ) { $lib_time = -M "../../spooles.a" ; } # # read in each line, look for $(OBJ).a(srcname.o) # put srcname into the @srcnames array # while ( $line = ) { chop($line) ; if ( $line =~ /OBJ =/ ) { ($first, $objname) = split /OBJ = /, $line } if ( $line =~ /\$\(OBJ\)\.a\(/ ) { ($first, $second) = split /\$\(OBJ\)\.a\(/, $line ; ($srcname, $remainder) = split /\.o\)/, $second ; $srcname = $srcname . ".c" ; # # get the last modification time for srcname.c # $srcname_time = -M $srcname ; if ( (! -e "../../spooles.a") or ($srcname_time < $lib_time) ) { push @srcnames, $srcname } } } # # now start printing the makefile to stdout # print "\ninclude ../../Make.inc" ; print "\n" ; print "\nOBJ = $objname" ; print "\n\nSRC = " ; foreach $src ( @srcnames ) { $srcname = " \\\n " . $src ; print $srcname ; } print "\n\nOBJ_FILES = \$\{SRC:.c=.o\}" ; print "\n\n" ; print <<'EOF' ; .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a EOF dotar010075500020550007177000000147130665014247000131420ustar00clevecompmath00000400000006#! /bin/csh -f tar -cvf spooles.2.2.tar \ makefile \ makeLib \ updLib \ dotar \ cfiles.h \ timings.h \ DLIST.h \ SPOOLES.h \ Make.inc \ *.html \ A2.h \ A2/{*.h,makefile} \ A2/src/{makefile,makeGlobalLib,*.c} \ A2/drivers/{do*,makefile,*.c} \ A2/doc \ BKL.h \ BKL/{*.h,makefile} \ BKL/src/{makefile,makeGlobalLib,*.c} \ BKL/doc \ BPG.h \ BPG/{*.h,makefile} \ BPG/src/{makefile,makeGlobalLib,*.c} \ BPG/drivers/{do*,makefile,*.c} \ BPG/doc \ Chv.h \ Chv/{*.h,makefile} \ Chv/src/{makefile,makeGlobalLib,*.c} \ Chv/drivers/{do*,makefile,*.c} \ Chv/doc \ ChvList.h \ ChvList/{*.h,makefile} \ ChvList/src/{makefile,makeGlobalLib,*.c} \ ChvList/doc \ ChvManager.h \ ChvManager/{*.h,makefile} \ ChvManager/src/{makefile,makeGlobalLib,*.c} \ ChvManager/doc \ Coords.h \ Coords/{*.h,makefile} \ Coords/src/{makefile,makeGlobalLib,*.c} \ Coords/drivers/{do*,makefile,*.c} \ Coords/doc \ DSTree.h \ DSTree/{*.h,makefile} \ DSTree/src/{makefile,makeGlobalLib,*.c} \ DSTree/drivers/{do*,makefile,*.c,cutoff.dvf} \ DSTree/doc \ DV.h \ DV/{*.h,makefile} \ DV/src/{makefile,makeGlobalLib,*.c} \ DV/drivers/{makefile,makeGlobalLib,*.c} \ DV/doc \ DenseMtx.h \ DenseMtx/{*.h,makefile} \ DenseMtx/src/{makefile,makeGlobalLib,*.c} \ DenseMtx/doc \ Drand.h \ Drand/{*.h,makefile} \ Drand/src/{makefile,makeGlobalLib,*.c} \ Drand/drivers/{do*,makefile,*.c} \ Drand/doc \ EGraph.h \ EGraph/{*.h,makefile} \ EGraph/src/{makefile,makeGlobalLib,*.c} \ EGraph/drivers/{do*,makefile,*.c} \ EGraph/doc \ ETree.h \ ETree/{*.h,makefile} \ ETree/src/{makefile,makeGlobalLib,*.c} \ ETree/drivers/{do*,makefile,*.c} \ ETree/doc \ Eigen.h \ Eigen/{*.h,makefile} \ Eigen/srcST/{makefile,makeGlobalLib,*.c} \ Eigen/srcMT/{makefile,makeGlobalLib,*.c} \ Eigen/srcMPI/{makefile,makeGlobalLib,*.c} \ Eigen/drivers/{do*,makefile,*.c,*.inp,*.pg} \ Eigen/doc \ FrontMtx.h \ FrontMtx/{*.h,makefile} \ FrontMtx/src/{makefile,makeGlobalLib,*.c} \ FrontMtx/drivers/{do*,makefile,*.c} \ FrontMtx/doc \ GPart.h \ GPart/{*.h,makefile} \ GPart/src/{makefile,makeGlobalLib,*.c} \ GPart/drivers/{do*,makefile,*.c} \ GPart/doc \ Graph.h \ Graph/{*.h,makefile} \ Graph/src/{makefile,makeGlobalLib,*.c} \ Graph/drivers/{do*,makefile,*.c} \ Graph/doc \ I2Ohash.h \ I2Ohash/{*.h,makefile} \ I2Ohash/src/{makefile,makeGlobalLib,*.c} \ I2Ohash/drivers/{makefile,makeGlobalLib,*.c} \ I2Ohash/doc \ IIheap.h \ IIheap/{*.h,makefile} \ IIheap/src/{makefile,makeGlobalLib,*.c} \ IIheap/doc \ ILUMtx.h \ ILUMtx/{*.h,makefile} \ ILUMtx/src/{makefile,makeGlobalLib,*.c} \ ILUMtx/drivers/{do*,makefile,*.c} \ ILUMtx/doc \ IV.h \ IV/{*.h,makefile} \ IV/src/{makefile,makeGlobalLib,*.c} \ IV/drivers/{do*,makefile,*.c} \ IV/doc \ IVL.h \ IVL/{*.h,makefile} \ IVL/src/{makefile,makeGlobalLib,*.c} \ IVL/doc \ IVL/drivers/{do*,makefile,*.c} \ Ideq.h \ Ideq/{*.h,makefile} \ Ideq/src/{makefile,makeGlobalLib,*.c} \ Ideq/doc \ InpMtx.h \ InpMtx/{*.h,makefile} \ InpMtx/src/{makefile,makeGlobalLib,*.c} \ InpMtx/drivers/{do*,makefile,*.c} \ InpMtx/doc \ Iter.h \ Iter/{*.h,makefile} \ Iter/src/{makefile,makeGlobalLib,*.c} \ Iter/drivers/{do*,makefile,*.c} \ Iter/doc \ LinSol.h \ LinSol/{*.h,makefile} \ LinSol/srcST/{makefile,makeGlobalLib,*.c} \ LinSol/srcMT/{makefile,makeGlobalLib,*.c} \ LinSol/srcMPI/{makefile,makeGlobalLib,*.c} \ LinSol/drivers/{do*,makefile,*.c,*.input,*.pg} \ LinSol/doc \ Lock.h \ Lock/{*.h,makefile} \ Lock/src/{makefile,makeGlobalLib,*.c} \ Lock/doc \ MPI.h \ MPI/{*.h,makefile} \ MPI/src/{makefile,makeGlobalLib,*.c} \ MPI/drivers/{do*,makefile,*.c,*.input,*.pg} \ MPI/doc \ MSMD.h \ MSMD/{*.h,makefile} \ MSMD/src/{makefile,makeGlobalLib,*.c} \ MSMD/drivers/{do*,makefile,*.c} \ MSMD/doc \ MT.h \ MT/{*.h,makefile} \ MT/src/{makefile,makeGlobalLib,*.c} \ MT/drivers/{do*,makefile,*.c,*.input} \ MT/doc \ Network.h \ Network/{*.h,makefile} \ Network/src/{makefile,makeGlobalLib,*.c} \ Network/doc \ PatchAndGoInfo.h \ PatchAndGoInfo/{*.h,makefile} \ PatchAndGoInfo/src/{makefile,makeGlobalLib,*.c} \ PatchAndGoInfo/doc \ Pencil.h \ Pencil/{*.h,makefile} \ Pencil/src/{makefile,makeGlobalLib,*.c} \ Pencil/doc \ Perm.h \ Perm/{*.h,makefile} \ Perm/src/{makefile,makeGlobalLib,*.c} \ Perm/drivers/{do*,makefile,*.c} \ Perm/doc \ SemiImplMtx.h \ SemiImplMtx/{*.h,makefile} \ SemiImplMtx/src/{makefile,makeGlobalLib,*.c} \ SemiImplMtx/drivers/{do*,makefile,*.c} \ SemiImplMtx/doc \ SolveMap.h \ SolveMap/{*.h,makefile} \ SolveMap/src/{makefile,makeGlobalLib,*.c} \ SolveMap/doc \ SubMtx.h \ SubMtx/{*.h,makefile} \ SubMtx/src/{makefile,makeGlobalLib,*.c} \ SubMtx/drivers/{do*,makefile,*.c,*submtx*} \ SubMtx/doc \ SubMtxList.h \ SubMtxList/{*.h,makefile} \ SubMtxList/src/{makefile,makeGlobalLib,*.c} \ SubMtxList/doc \ SubMtxManager.h \ SubMtxManager/{*.h,makefile} \ SubMtxManager/src/{makefile,makeGlobalLib,*.c} \ SubMtxManager/doc \ SymbFac.h \ SymbFac/{*.h,makefile} \ SymbFac/src/{makefile,makeGlobalLib,*.c} \ SymbFac/drivers/{do*,makefile,*.c} \ SymbFac/doc \ Tree.h \ Tree/{*.h,makefile} \ Tree/src/{makefile,makeGlobalLib,*.c} \ Tree/drivers/{do*,makefile,*.c} \ Tree/doc \ Utilities.h \ Utilities/{*.h,makefile} \ Utilities/src/{makefile,makeGlobalLib,*.c} \ Utilities/drivers/{do*,makefile,*.c} \ Utilities/doc \ ZV.h \ ZV/{*.h,makefile} \ ZV/src/{makefile,makeGlobalLib,*.c} \ ZV/drivers/{do*,makefile,*.c} \ ZV/doc \ misc.h \ misc/{*.h,makefile} \ misc/src/{makefile,makeGlobalLib,*.c} \ misc/drivers/{do*,makefile,*.c,*.input} \ misc/doc \ Matrices \ documentation GPart/doc \ Graph.h \ Graph/{*.h,makefcfiles.h010064400020550007177000000001120653501574700135150ustar00clevecompmath00000400000006#ifndef _cFILES_ #define _cFILES_ #include "Utilities/Utilities.h" #endif timings.h010064400020550007177000000003270653503456600137320ustar00clevecompmath00000400000006#ifndef _TIMINGS_ #define _TIMINGS_ #include static struct timeval TV ; static struct timezone TZ ; #define MARKTIME(t) \ gettimeofday(&TV, &TZ) ; \ t = (TV.tv_sec + 0.000001*TV.tv_usec) #endif SPOOLES.h010064400020550007177000000005570660544611500134040ustar00clevecompmath00000400000006#ifndef _SPOOLES_ #define _SPOOLES_ #define SPOOLES_INDICES_ONLY 0 #define SPOOLES_REAL 1 #define SPOOLES_COMPLEX 2 #define SPOOLES_SYMMETRIC 0 #define SPOOLES_HERMITIAN 1 #define SPOOLES_NONSYMMETRIC 2 #define SPOOLES_NO_PIVOTING 0 #define SPOOLES_PIVOTING 1 #define SPOOLES_BY_ROWS 1 #define SPOOLES_BY_COLUMNS 2 #endif Make.inc010064400020550007177000000060120665072610700134510ustar00clevecompmath00000400000006.POSIX: #---------------------------------------- # # file created 98jun18, cca, (cleve.ashcraft@boeing.com) # based on work by clay breshears (clay@turing.wes.hpc.mil) # (much appreciated) # #---------------------------------------- # # place your favorite compiler here # # for solaris # # CC = gcc CC = /usr/lang-4.0/bin/cc # # for sgi # # CC = cc # # for hp # # CC = /opt/mpi/bin/mpicc # #---------------------------------------- # # set the compiler flags # # OPTLEVEL = # OPTLEVEL = -g -v OPTLEVEL = -O # OPTLEVEL = -xO5 -v # OPTLEVEL = -O3 # OPTLEVEL = -O4 # CFLAGS = -Wall -g # CFLAGS = -Wall -pg # CFLAGS = $(OPTLEVEL) -D_POSIX_C_SOURCE=199506L CFLAGS = $(OPTLEVEL) # CFLAGS = -Wall $(OPTLEVEL) # #---------------------------------------- # # set any load flags # # LDFLAGS = -Wl,+parallel -Wl,+tm,spp2000 # for hp exemplar LDFLAGS = # #--------------------------------------------------------------------- # # set any thread libraries # # THREAD_LIBS = # THREAD_LIBS = -D_REENTRANT=199506L -lpthread THREAD_LIBS = -D_POSIX_C_SOURCE=199506L -lpthread # THREAD_LIBS = -lpthread # #--------------------------------------------------------------------- # # set the purify environment (a memory monitoring tool) # PURIFY = # PURIFY = /usr/local/purify-4.0.1/purify # # purify wouldn't work with the newest version of the gcc library, # so we had to force loading the old version # PURIFY_GCC_VERSION = # PURIFY_GCC_VERSION = -V 2.7.2 # #--------------------------------------------------------------------- # # set the archive flags # AR = ar ARFLAGS = rv # #--------------------------------------------------------------------- # # set the ranlib environment # (if ranlib is not needed, we echo the library name) # # RANLIB = ranlib RANLIB = echo # #--------------------------------------------------------------------- # # set suffix rule *.c --> *.o # .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $< # #--------------------------------------------------------------------- # # set suffix rule *.c --> *.a # .c.a : $(PURIFY) $(CC) -c $(CFLAGS) $< $(AR) $(ARFLAGS) $@ $*.o rm -f $*.o # #--------------------------------------------------------------------- # # MPI install library # # MPI_INSTALL_DIR = MPI_INSTALL_DIR = /usr/local/mpich-1.0.13 # #--------------------------------------------------------------------- # # MPI library path # # for sgi # # MPI_LIB_PATH = # # for solaris # MPI_LIB_PATH = -L$(MPI_INSTALL_DIR)/lib/solaris/ch_p4 # # for hp # # MPI_LIB_PATH = # #--------------------------------------------------------------------- # # MPI libraries # # for solaris # MPI_LIBS = $(MPI_LIB_PATH) -D_REENTRANT -lmpi -lsocket -lnsl -lthread # # for sgi # # MPI_LIBS = $(MPI_LIB_PATH) -lmpi -lpthread # # for hp # MPI_LIBS = -lpthread # MPI_LIBS = $(MPI_LIB_PATH) -lpthread # #--------------------------------------------------------------------- # # MPI include path # # MPI_INCLUDE_DIR = MPI_INCLUDE_DIR = -I$(MPI_INSTALL_DIR)/include # #--------------------------------------------------------------------- spooles.2.2.html010064400020550007177000000170720665070017500147600ustar00clevecompmath00000400000006 SPOOLES 2.2 : SParse Object Oriented Linear Equations Solver

SPOOLES 2.2 : SParse Object Oriented Linear Equations Solver


SPOOLES is a library for solving sparse real and complex linear systems of equations, written in the C language using object oriented design. At present, there is the following functionality:
  1. Compute multiple minimum degree, generalized nested dissection and multisection orderings of matrices with symmetric structure.

  2. Factor and solve square linear systems of equations with symmetric structure, with or without pivoting for stability. The factorization can be symmetric LDLT, Hermitian LDLH, or nonsymmetric LDU. A direct factorization or a drop tolerance factorization can be computed. The factors and solve can be done in serial mode, multithreaded with Solaris or POSIX threads, or with MPI.

  3. Factor and solve overdetermined full rank systems of equations using a multifrontal QR factorization, in serial or using POSIX threads.

  4. Solve square linear systems using a variety of Krylov iterative methods. The preconditioner is a drop tolerance factorization, with or without pivoting for stability.


The SPOOLES library has been developed by members of the Mathematics and Engineering Analysis Unit of Boeing Phantom Works. The library was supported in part by DARPA contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.

Individuals who have contributed to this package include:
  1. Cleve Ashcraft, Boeing Phantom Works
  2. Roger Grimes, Boeing Phantom Works
  3. Joseph Liu, York University
  4. Jim Patterson, Boeing Phantom Works
  5. Dan Pierce, Boeing Phantom Works
  6. Yichi Pierce, Boeing Phantom Works
  7. Peter Schartz, CSAR Corporation
  8. Juergen Schulze, University of Paderborn
  9. Wei-Pai Tang, University of Waterloo
  10. David Wah, Boeing Phantom Works
  11. Jason Wu, Boeing Phantom Works

This release is entirely within the public domain; there are no licensing restrictions, and there is no warranty of any sort.

Contact cleve.ashcraft@boeing.com for more information, comments and bug reports.


The library is available as a gzip'd, tar'd file that contains the entire source, drivers and LaTeX documentation. There are seven Postscript files that contain documentation.

  1. install.ps.gz --- "SPOOLES 2.2 Installation Manual", 7 pages, describes the library's structure and installation procedures.

  2. ReferenceManual.ps.gz --- "The Reference Manual for SPOOLES, Release 2.2: An Object Oriented Software Library for Solving Sparse Linear Systems of Equations", over 400 pages, every object, method and driver is documented.

  3. fronttrees.ps.gz --- "Ordering Sparse Matrices and Transforming Front Trees", 20, pages, describes the different ordering methods in the library and the effect of the front trees on performance.

  4. LinSol.ps.gz --- "Wrapper Objects for Solving a Linear System of Equations using SPOOLES 2.2", 58 pages, provides the most gentle introduction to the library, documents a set of software objects written to incorporate the SPOOLES linear solver into the CSAR-Nastran finite element software package.

  5. AllInOne.ps.gz --- "Solving Linear Systems using SPOOLES 2.2", 54 pages, contains example programs with commentary, a general introduction to the library, much more detail than the "Wrapper Objects" document immediately above.

  6. Eigen.ps.gz --- "Integrating the SPOOLES 2.2 Sparse Linear Algebra Library into the LANCZOS Block-Shifted Lanczos Eigensolver", 42 pages, documents a set of software objects written to incorporate the SPOOLES linear solver into an eigenanalysis package, also funded by DARPA contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.

  7. PP99.ps.gz "SPOOLES: An Object-Oriented Sparse Matrix Library", a paper to be included in the Proceedings of the 1999 SIAM Conference on Parallel Processing for Scientific Computing, March 22-27, 1999.

  8. spooles.2.2.tar.gz --- gzip'd, tar'd file of library


Changes since the 2.0 release.

  1. Semi-implicit factorizations to reduce storage and/or operation counts for direct and approximate factorizations. (See the SemiImplMtx directory.)

  2. Krylov solvers for real SPD, symmetric indefinite, and nonsymmetric linear systems. (See the Iter directory.) The preconditioner is a drop tolerance approximate factorization obtained from the FrontMtx object. There also exists a simpler ILU drop tolerance factorization in the ILUMtx directory.

  3. There is a "patch-and-go" functionality for factorizations that must be modified on the fly. One application is found in singular or near singular matrices from structural analysis applications. Another application is for matrices from interior point methods. In both cases, the presence of a zero or small pivot element requires special handling.

  4. There is a "wrapper" object to solve linear systems found in the LinSol directory. It was used to incorporate the SPOOLES library into the CSAR-Nastran finite element package.

  5. There is a "wrapper" object used in an eigenanalysis package found in the Eigen directory.

  6. Several bugs were fixed in the multithreaded and MPI solvers. Users of the SPOOLES 2.0 versions should upgrade.

  7. The user manual and reference manual documentation has been reorganized. There is a new documentation directory, with five subdirectories:

    1. documentation/Install holds "SPOOLES 2.2 Installation Manual", the installation manual.

    2. documentation/AllInOne holds "Solving Linear Systems using SPOOLES 2.2", the driver programs manual.

    3. documentation/FrontTrees holds "Ordering Sparse Matrices and Transforming Front Trees", the ordering manual.

    4. documentation/ReferenceManual holds "The Reference Manual for SPOOLES, Release 2.2: An Object Oriented Software Library for Solving Sparse Linear Systems of Equations", the complete reference manual.

    5. documentation/PP99 holds "SPOOLES: An Object-Oriented Sparse Matrix Library", a paper to be included in the Proceedings of the 1999 SIAM Conference on Parallel Processing for Scientific Computing, March 22-27, 1999.


Changes since the 1.0 release.

  1. Complex linear systems are now supported

  2. Factor storage has been reorganized to improve parallel solves

  3. Several bugs in the MPI solvers have been fixed


A2.h010064400020550007177000000000640653410636700125160ustar00clevecompmath00000400000006#ifndef _A2_ #define _A2_ #include "A2/A2.h" #endif A2/A2.h010064400020550007177000000566060663577240000127740ustar00clevecompmath00000400000006/* A2.h */ #include "../cfiles.h" #include "../SPOOLES.h" #include "../ZV.h" #include "../IV.h" #include "../DV.h" /*====================================================================*/ /* ----------------------------------------------------------- the A2 structure holds a 2-d dense array of double complex type -- type of entries 1 -- real 2 -- complex n1 -- number of rows (first dimension) n2 -- number of columns (second dimension) inc1 -- increment in storage along first dimension, when inc1 == 1, the storage is column major inc2 -- increment in storage along second dimension, when inc2 == 1, the storage is row major nowned -- number of owned entries starting at entries when > 0, storage pointed to by entries has been allocated here and can be free'd. when = 0, storage pointed to by entries has not been allocated here and cannot be free'd. entries -- base address for the entries if real then entry(i,j) is found in entries[i*inc1 + j*inc2] else entry(i,j) is found in entries[2*(i*inc1 + j*inc2)] and entries[2*(i*inc1 + j*inc2)+1] endif ----------------------------------------------------------- */ typedef struct _A2 { int type ; int n1 ; int n2 ; int inc1 ; int inc2 ; int nowned ; double *entries ; } A2 ; #define A2_IS_REAL(chv) ((chv)->type == SPOOLES_REAL) #define A2_IS_COMPLEX(chv) ((chv)->type == SPOOLES_COMPLEX) #define A2_STRICT_LOWER 1 #define A2_LOWER 2 #define A2_DIAGONAL 3 #define A2_UPPER 4 #define A2_STRICT_UPPER 5 #define A2_ALL_ENTRIES 6 #define A2_BY_ROWS 0 #define A2_BY_COLUMNS 1 /*====================================================================*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98may01, cca ----------------------- */ A2 * A2_new ( void ) ; /* ----------------------- set the default fields created -- 98may01, cca ----------------------- */ void A2_setDefaultFields ( A2 *mtx ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may01, cca -------------------------------------------------- */ void A2_clearData ( A2 *mtx ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98may01, cca ------------------------------------------ */ void A2_free ( A2 *mtx ) ; /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------- return the number of rows in the array created -- 98may01, cca -------------------------------------- */ int A2_nrow ( A2 *mtx ) ; /* ----------------------------------------- return the number of columns in the array created -- 98may01, cca ----------------------------------------- */ int A2_ncol ( A2 *mtx ) ; /* -------------------------- return the first increment created -- 98may01, cca -------------------------- */ int A2_inc1 ( A2 *mtx ) ; /* --------------------------- return the second increment created -- 98may01, cca --------------------------- */ int A2_inc2 ( A2 *mtx ) ; /* ------------------------------- return a pointer to the entries created -- 98may01, cca ------------------------------- */ double * A2_entries ( A2 *mtx ) ; /* -------------------------------------------- return a pointer to the first entry in a row created -- 98may01, cca -------------------------------------------- */ double * A2_row ( A2 *mtx, int irow ) ; /* ----------------------------------------------- return a pointer to the first entry in a column created -- 98may01, cca ----------------------------------------------- */ double * A2_column ( A2 *mtx, int jcol ) ; /* ------------------------------------------- fill *pValue with the entry in (irow, jcol) created -- 98may01, cca ------------------------------------------- */ void A2_realEntry ( A2 *mtx, int irow, int jcol, double *pValue ) ; /* --------------------------------------------------- fill (*pReal,*pImag) with the entry in (irow, jcol) created -- 98may01, cca --------------------------------------------------- */ void A2_complexEntry ( A2 *mtx, int irow, int jcol, double *pReal, double *pImag ) ; /* ----------------------------------------- set the entry in (irow, jcol) to be value created -- 98may01, cca ----------------------------------------- */ void A2_setRealEntry ( A2 *mtx, int irow, int jcol, double value ) ; /* ----------------------------------------------- set the entry in (irow, jcol) to be (real,imag) created -- 98may01, cca ----------------------------------------------- */ void A2_setComplexEntry ( A2 *mtx, int irow, int jcol, double real, double imag ) ; /* --------------------------------------- fill pointers to the matrix first entry in row irow and column jcol created -- 98may01, cca --------------------------------------- */ void A2_pointerToRealEntry ( A2 *mtx, int irow, int jcol, double **ppValue ) ; /* --------------------------------------- fill pointers to the matrix first entry in row irow and column jcol created -- 98may01, cca --------------------------------------- */ void A2_pointerToComplexEntry ( A2 *mtx, int irow, int jcol, double **ppReal, double **ppImag ) ; /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ initializer. sets the n1, n2, inc1 and inc2 fields. must have mtx != NULL type = SPOOLES_REAL or SPOOLES_COMPLEX n1, n2, inc1, inc2 > 0 (inc1 = 1 and inc2 = nrow) or (inc1 = ncol and inc2 = 1) if entries is NULL then entries are allocated and zeroed. else mtx->nowned is set to 0 mtx->entries is set to entries. endif n1, n2, inc1, inc2 set created -- 98apr15, cca ------------------------------------------------------------------ */ void A2_init ( A2 *mtx, int type, int n1, int n2, int inc1, int inc2, double *entries ) ; /* -------------------------------------------------- submatrix initializer A(0:lastrow-firstrow,0:lastcol-firstcol) = B(firstrow:lastrow, firstcol:lastcol) created -- 98apr15, cca -------------------------------------------------- */ void A2_subA2 ( A2 *mtxA, A2 *mtxB, int firstrow, int lastrow, int firstcol, int lastcol ) ; /* ------------------------------------------------------------------------ ----- methods found in norms.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------- return the entry of maximum magnitude created -- 98apr15, cca ------------------------------------- */ double A2_maxabs ( A2 *a ) ; /* --------------------------------------- return the frobenius norm of the matrix created -- 98apr15, cca --------------------------------------- */ double A2_frobNorm ( A2 *mtx ) ; /* --------------------------------- return the one-norm of the matrix created -- 98apr15, cca --------------------------------- */ double A2_oneNorm ( A2 *mtx ) ; /* -------------------------------------- return the infinity-norm of the matrix created -- 98apr15, cca -------------------------------------- */ double A2_infinityNorm ( A2 *mtx ) ; /* ---------------------------------- return the one-norm of column jcol created -- 98apr15, cca ---------------------------------- */ double A2_oneNormOfColumn ( A2 *mtx, int jcol ) ; /* ---------------------------------- return the two-norm of column jcol created -- 98apr15, cca ---------------------------------- */ double A2_twoNormOfColumn ( A2 *mtx, int jcol ) ; /* --------------------------------------- return the infinity-norm of column jcol created -- 98apr15, cca --------------------------------------- */ double A2_infinityNormOfColumn ( A2 *mtx, int jcol ) ; /* ------------------------------- return the one-norm of row irow created -- 98apr15, cca ------------------------------- */ double A2_oneNormOfRow ( A2 *mtx, int irow ) ; /* ------------------------------- return the two-norm of row irow created -- 98apr15, cca ------------------------------- */ double A2_twoNormOfRow ( A2 *mtx, int irow ) ; /* ------------------------------------ return the infinity-norm of row irow created -- 98apr15, cca ------------------------------------ */ double A2_infinityNormOfRow ( A2 *mtx, int irow ) ; /* ------------------------------------------------------------------------ ----- methods found in sort.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------- permute the rows of the matrix A(*,*) = A(index(*),*) this method calls A2_sortRowsUp but does not overwrite the index[] vector created -- 98apr15, cca ----------------------------------------- */ void A2_permuteRows ( A2 *mtx, int nrow, int index[] ) ; /* ----------------------------------------- permute the columns of the matrix A(*,*) = A(*,index(*)) this method calls A2_sortColumnsUp but does not overwrite the index[] vector created -- 98apr15, cca ----------------------------------------- */ void A2_permuteColumns ( A2 *mtx, int ncol, int index[] ) ; /* ---------------------------------------------- sort the rows of the matrix in ascending order of the rowids[] vector. on return, rowids is in asending order. return value is the number of row swaps made. created -- 98apr15, cca ---------------------------------------------- */ int A2_sortRowsUp ( A2 *mtx, int nrow, int rowids[] ) ; /* ------------------------------------------------- sort the columns of the matrix in ascending order of the colids[] vector. on return, colids is in asending order. return value is the number of column swaps made. created -- 98apr15, cca ------------------------------------------------- */ int A2_sortColumnsUp ( A2 *mtx, int ncol, int colids[] ) ; /* ------------------------------------------------------------------------ ----- methods found in QRreduce.c -------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- purpose -- compute A = QR, where Q is a product of householder vectors, (I - beta_j v_j v_j^T). on return, v_j is found in the lower triangle of A, v_j(j) = 1.0. return value -- # of floating point operations created -- 98may25, cca -------------------------------------------------------------- */ double A2_QRreduce ( A2 *mtxA, DV *workDV, int msglvl, FILE *msgFile ) ; /* ----------------------------------------------------------- A contains the following data from the A = QR factorization A(1:ncolA,1:ncolA) = R A(j+1:nrowA,j) is v_j, the j-th householder vector, where v_j[j] = 1.0 NOTE: A and Q must be column major created -- 98dec10, cca ----------------------------------------------------------- */ void A2_computeQ ( A2 *Q, A2 *A, DV *workDV, int msglvl, FILE *msgFile ) ; /* ----------------------------------------------------------- A contains the following data from the A = QR factorization A(1:ncolA,1:ncolA) = R A(j+1:nrowA,j) is v_j, the j-th householder vector, where v_j[j] = 1.0 we compute Y = Q^T X when A is real and Y = Q^H X when A is complex NOTE: A, Y and X must be column major. NOTE: Y and X can be the same object, in which case X is overwritten with Y created -- 98dec10, cca ----------------------------------------------------------- */ void A2_applyQT ( A2 *Y, A2 *A, A2 *X, DV *workDV, int msglvl, FILE *msgFile ) ; /* ------------------------------------------------------------------------ ----- methods found in copyEntriesToVector.c --------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------------------- purpose -- copy entries to a vector. the portion copied can be a union of the strict lower portion, the diagonal portion, and the strict upper portion. there is one restriction, if the strict lower and strict upper are to be copied, the diagonal will also be copied. length -- length of dvec[] dvec[] -- vector to receive matrix entries copyflag -- flag to denote what part of the entries to move A2_STRICT_LOWER --> move strict lower entries A2_LOWER --> move lower entries (includes the diagonal) A2_DIAGONAL --> move diagonal entries A2_UPPER --> move upper entries (includes the diagonal) A2_STRICT_UPPER --> move strict upper entries A2_ALL_ENTRIES --> move all entries storeflag -- flag to denote how to store entries in dvec[] A2_BY_ROWS --> store by rows A2_BY_COLUMNS --> store by columns return value -- number of entries copied created -- 97jun03, cca, dkw modified -- 98may25, cca ---------------------------------------------------------------- */ int A2_copyEntriesToVector ( A2 *mtx, int length, double *dvec, int copyflag, int storeflag ) ; /* ------------------------------------------------------------------------ ----- methods found in makeStaircase.c --------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------------- purpose -- to permute the rows so the matrix is in staircase form created -- 98may25, cca ----------------------------------------------------------------- */ void A2_makeStaircase ( A2 *mtxA ) ; /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ---------------------------------------------- return the number of bytes taken by the object created -- 98may01, cca ---------------------------------------------- */ int A2_sizeOf ( A2 *mtx ) ; /* --------------------------------------------------------------- shift the base of the entries and adjust dimensions mtx(0:n1-rowoff-1,0:n2-coloff-1) = mtx(rowoff:n1-1,coloff:n2-1) created -- 98may01, cca --------------------------------------------------------------- */ void A2_shiftBase ( A2 *mtx, int rowoff, int coloff ) ; /* -------------------------------------------------------------- returns 1 if the storage is row major, otherwise returns zero. created -- 98may01, cca -------------------------------------------------------------- */ int A2_rowMajor ( A2 *mtx ) ; /* ----------------------------------------------------------------- returns 1 if the storage is column major, otherwise returns zero. created -- 98may01, cca ----------------------------------------------------------------- */ int A2_columnMajor ( A2 *mtx ) ; /* ----------------------- transpose the matrix created -- 98may01, cca ----------------------- */ void A2_transpose ( A2 *mtx ) ; /* ---------------------------- extract row[*] = mtx(irow,*) created -- 98may01, cca ---------------------------- */ void A2_extractRow ( A2 *mtx, double row[], int irow ) ; /* ---------------------------- extract col[*] = mtx(*,jcol) created -- 98may01, cca ---------------------------- */ void A2_extractColumn ( A2 *mtx, double col[], int jcol ) ; /* ----------------------- set mtx(irow,*) = y[*] created -- 98may01, cca ----------------------- */ void A2_setRow ( A2 *mtx, double row[], int irow ) ; /* ----------------------- set mtx(*,jcol) = y[*] created -- 98may01, cca ----------------------- */ void A2_setColumn ( A2 *mtx, double col[], int jcol ) ; /* ---------------------------- extract row[*] = mtx(irow,*) created -- 98may01, cca ---------------------------- */ void A2_extractRowDV ( A2 *mtx, DV *rowDV, int irow ) ; /* ---------------------------- extract row[*] = mtx(irow,*) created -- 98may01, cca ---------------------------- */ void A2_extractRowZV ( A2 *mtx, ZV *rowZV, int irow ) ; /* ---------------------------- extract col[*] = mtx(*,jcol) created -- 98may01, cca ---------------------------- */ void A2_extractColumnDV ( A2 *mtx, DV *colDV, int jcol ) ; /* ---------------------------- extract col[*] = mtx(*,jcol) created -- 98may01, cca ---------------------------- */ void A2_extractColumnZV ( A2 *mtx, ZV *colZV, int jcol ) ; /* ----------------------- set mtx(irow,*) = y[*] created -- 98may01, cca ----------------------- */ void A2_setRowDV ( A2 *mtx, DV *rowDV, int irow ) ; /* ----------------------- set mtx(irow,*) = y[*] created -- 98may01, cca ----------------------- */ void A2_setRowZV ( A2 *mtx, ZV *rowZV, int irow ) ; /* ----------------------- set mtx(*,jcol) = y[*] created -- 98may01, cca ----------------------- */ void A2_setColumnDV ( A2 *mtx, DV *colDV, int jcol ) ; /* ----------------------- set mtx(*,jcol) = y[*] created -- 98may01, cca ----------------------- */ void A2_setColumnZV ( A2 *mtx, ZV *colZV, int jcol ) ; /* ------------------------------------------------------------- fill the matrix with uniform random numbers in [lower, upper] created -- 98may01, cca ------------------------------------------------------------- */ void A2_fillRandomUniform ( A2 *a, double lower, double upper, int seed ) ; /* ----------------------------------------------- fill the matrix with normal(0,1) random numbers created -- 98may01, cca ----------------------------------------------- */ void A2_fillRandomNormal ( A2 *a, double mean, double variance, int seed ) ; /* ---------------------------------------- fill the matrix with the identity matrix created -- 98may01, cca ---------------------------------------- */ void A2_fillWithIdentity ( A2 *a ) ; /* -------------------------- fill the matrix with zeros created -- 98may01, cca -------------------------- */ void A2_zero ( A2 *a ) ; /* ---------------------------- copy one matrix into another A := B created -- 98may01, cca ---------------------------- */ void A2_copy ( A2 *A, A2 *B ) ; /* -------------------------------- subtract one matrix from another A := A - B created -- 98may01, cca ---------------------------- */ void A2_sub ( A2 *A, A2 *B ) ; /* --------------------------- swap two rows of the matrix created -- 98may01, cca --------------------------- */ void A2_swapRows ( A2 *a, int irow1, int irow2 ) ; /* ------------------------------ swap two columns of the matrix created -- 98may01, cca ------------------------------ */ void A2_swapColumns ( A2 *a, int jcol1, int jcol2 ) ; /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------- purpose -- to read in the object from a file input -- fn -- filename, must be *.a2b or *.a2f return value -- 1 if success, 0 if failure created -- 98may01, cca -------------------------------------------- */ int A2_readFromFile ( A2 *mtx, char *fn ) ; /* -------------------------------------------------- purpose -- to read an object from a formatted file return value -- 1 if success, 0 if failure created -- 98may01, cca -------------------------------------------------- */ int A2_readFromFormattedFile ( A2 *mtx, FILE *fp ) ; /* ----------------------------------------------- purpose -- to read an object from a binary file return value -- 1 if success, 0 if failure created -- 98may01, cca ----------------------------------------------- */ int A2_readFromBinaryFile ( A2 *mtx, FILE *fp ) ; /* --------------------------------------- purpose -- to write an object to a file input -- fn -- filename *.a2b -- binary *.a2f -- formatted anything else -- for human eye created -- 98may01, cca --------------------------------------- */ void A2_writeToFile ( A2 *mtx, char *fn ) ; /* ------------------------------------------------- purpose -- to write an object to a formatted file created -- 98may01, cca ------------------------------------------------- */ void A2_writeToFormattedFile ( A2 *mtx, FILE *fp ) ; /* -------------------------------------------------------- purpose -- to write an adjacency object to a binary file created -- 98may01, cca -------------------------------------------------------- */ void A2_writeToBinaryFile ( A2 *mtx, FILE *fp ) ; /* ---------------------------------------------- purpose -- to write the object for a human eye created -- 98may01, cca ---------------------------------------------- */ void A2_writeForHumanEye ( A2 *mtx, FILE *fp ) ; /* -------------------------------------- purpose -- to write out the statistics created -- 98may01, cca -------------------------------------- */ void A2_writeStats ( A2 *mtx, FILE *fp ) ; /* ----------------------------------------------- purpose -- to write the matrix in matlab format created -- 98may01, cca ----------------------------------------------- */ void A2_writeForMatlab ( A2 *mtx, char *mtxname, FILE *fp ) ; /*====================================================================*/ can be a union of the strict lower portion, the diagonal portion, and the strict upper A2/makefile010064400020550007177000000002230663622347600140460ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean A2/src/makefile010064400020550007177000000011550663576715600146510ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = A2 $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(copyEntriesToVector.o) \ $(OBJ).a(init.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(makeStaircase.o) \ $(OBJ).a(norms.o) \ $(OBJ).a(QRreduce.o) \ $(OBJ).a(sort.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG A2/src/makeGlobalLib010064400020550007177000000006460663576034100155520ustar00clevecompmath00000400000006include ../../Make.inc OBJ = A2 SRC = basics.c \ copyEntriesToVector.c \ init.c \ instance.c \ IO.c \ makeStaircase.c \ norms.c \ QRreduce.c \ sort.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a A2/src/IO.c010064400020550007177000000325100654225131300135770ustar00clevecompmath00000400000006/* IO.c */ #include "../A2.h" static const char *suffixb = ".a2b" ; static const char *suffixf = ".a2f" ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to read in the object from a file input -- fn -- filename, must be *.a2b or *.a2f return value -- 1 if success, 0 if failure created -- 98may01, cca -------------------------------------------- */ int A2_readFromFile ( A2 *mtx, char *fn ) { FILE *fp ; int fnlength, rc = 0, sulength ; /* --------------- check the input --------------- */ if ( mtx == NULL || fn == NULL ) { fprintf(stderr, "\n error in A2_readFromFile(%p,%s)" "\n bad input", mtx, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in A2_readFromFile(%s)" "\n unable to open file %s", fn, fn) ; } else { rc = A2_readFromBinaryFile(mtx, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in A2_readFromFile(%s)" "\n unable to open file %s", fn, fn) ; } else { rc = A2_readFromFormattedFile(mtx, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in A2_readFromFile(%s)" "\n bad A2 file name %s," "\n must end in %s (binary) or %s (formatted)\n", fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in A2_readFromFile(%s)" "\n bad A2 file name %s," "\n must end in %s (binary) or %s (formatted)\n", fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to read an object from a formatted file return value -- 1 if success, 0 if failure created -- 98may01, cca -------------------------------------------------- */ int A2_readFromFormattedFile ( A2 *mtx, FILE *fp ) { int rc, size ; int itemp[5] ; /* --------------- check the input --------------- */ if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n error in A2_readFromFormattedFile(%p,%p)" "\n bad input", mtx, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ A2_clearData(mtx) ; /* ----------------------------------------------------------- read in the five scalar parameters: type n1, n2, inc1, inc2 ----------------------------------------------------------- */ if ( (rc = IVfscanf(fp, 5, itemp)) != 5 ) { fprintf(stderr, "\n error in A2_readFromFormattedFile()" "\n %d items of %d read\n", rc, 5) ; return(0) ; } /* --------------------- initialize the object --------------------- */ A2_init(mtx, itemp[0], itemp[1], itemp[2], itemp[3], itemp[4], NULL) ; /* ---------------------------- read in the entries[] vector ---------------------------- */ if ( (size = 1 + (mtx->n1-1)*mtx->inc1 + (mtx->n2-1)*mtx->inc2) > 0 ) { if ( A2_IS_REAL(mtx) ) { if ( (rc = DVfscanf(fp, size, mtx->entries)) != size ) { fprintf(stderr, "\n error in A2_readFromFormattedFile" "\n %d items of %d read\n", rc, size) ; return(0) ; } } else if ( A2_IS_COMPLEX(mtx) ) { if ( (rc = DVfscanf(fp, 2*size, mtx->entries)) != 2*size ) { fprintf(stderr, "\n error in A2_readFromFormattedFile" "\n %d items of %d read\n", rc, 2*size) ; return(0) ; } } } return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to read an object from a binary file return value -- 1 if success, 0 if failure created -- 98may01, cca ----------------------------------------------- */ int A2_readFromBinaryFile ( A2 *mtx, FILE *fp ) { int rc, size ; int itemp[5] ; /* --------------- check the input --------------- */ if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in A2_readFromBinaryFile(%p,%p)" "\n bad input", mtx, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ A2_clearData(mtx) ; /* ------------------------------------------------------------ read in the five scalar parameters: type, n1, n2, inc1, inc2 ------------------------------------------------------------ */ if ( (rc = fread((char *) itemp, sizeof(int), 5, fp)) != 5 ) { fprintf(stderr, "\n error in A2_readFromBinaryFile" "\n %d items of %d read\n", rc, 5) ; return(0) ; } fprintf(stdout, "\n itemp = {%d, %d, %d, %d, %d}", itemp[0], itemp[1], itemp[2], itemp[3], itemp[4]) ; fflush(stdout) ; /* --------------------- initialize the object --------------------- */ A2_init(mtx, itemp[0], itemp[1], itemp[2], itemp[3], itemp[4], NULL) ; /* ---------------------------- read in the entries[] vector ---------------------------- */ if ( (size = 1 + (mtx->n1-1)*mtx->inc1 + (mtx->n2-1)*mtx->inc2) > 0 ) { if ( A2_IS_REAL(mtx) ) { if ( (rc = fread(mtx->entries, sizeof(double), size, fp)) != size ) { fprintf(stderr, "\n error in A2_readFromBinaryFile" "\n %d items of %d read\n", rc, size) ; return(0) ; } } else if ( A2_IS_COMPLEX(mtx) ) { if ( (rc = fread(mtx->entries, sizeof(double), 2*size, fp)) != 2*size ) { fprintf(stderr, "\n error in A2_readFromBinaryFile" "\n %d items of %d read\n", rc, 2*size) ; return(0) ; } } } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- to write an object to a file input -- fn -- filename *.a2b -- binary *.a2f -- formatted anything else -- for human eye created -- 98may01, cca --------------------------------------- */ void A2_writeToFile ( A2 *mtx, char *fn ) { FILE *fp ; int fnlength, sulength ; /* --------------- check the input --------------- */ if ( mtx == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in A2_writeToFile(%p,%s)" "\n bad input", mtx, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in A2_writeToFile()" "\n unable to open file %s", fn) ; } else { A2_writeToBinaryFile(mtx, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in A2_writeToFile()" "\n unable to open file %s", fn) ; } else { A2_writeToFormattedFile(mtx, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in A2_writeToFile()" "\n unable to open file %s", fn) ; } else { A2_writeForHumanEye(mtx, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in A2_writeToFile" "\n unable to open file %s", fn) ; } else { A2_writeForHumanEye(mtx, fp) ; fclose(fp) ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to write an object to a formatted file created -- 98may01, cca ------------------------------------------------- */ void A2_writeToFormattedFile ( A2 *mtx, FILE *fp ) { int size ; if ( mtx == NULL || fp == NULL ) { return ; } fprintf(fp, "\n %d %d %d %d %d", mtx->type, mtx->n1, mtx->n2, mtx->inc1, mtx->inc2) ; if ( (size = 1 + (mtx->n1-1)*mtx->inc1 + (mtx->n2-1)*mtx->inc2) > 0 && mtx->entries != NULL ) { if ( A2_IS_REAL(mtx) ) { DVfprintf(fp, size, mtx->entries) ; } else if ( A2_IS_COMPLEX(mtx) ) { DVfprintf(fp, 2*size, mtx->entries) ; } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to write an adjacency object to a binary file created -- 98may01, cca -------------------------------------------------------- */ void A2_writeToBinaryFile ( A2 *mtx, FILE *fp ) { int size ; if ( fp == NULL ) { return ; } fwrite((void *) &mtx->type, sizeof(int), 1, fp) ; fwrite((void *) &mtx->n1, sizeof(int), 1, fp) ; fwrite((void *) &mtx->n2, sizeof(int), 1, fp) ; fwrite((void *) &mtx->inc1, sizeof(int), 1, fp) ; fwrite((void *) &mtx->inc2, sizeof(int), 1, fp) ; if ( (size = 1 + (mtx->n1-1)*mtx->inc1 + (mtx->n2-1)*mtx->inc2) > 0 && mtx->entries != NULL ) { if ( A2_IS_REAL(mtx) ) { fwrite((void *) &mtx->entries, sizeof(double), size, fp) ; } else if ( A2_IS_COMPLEX(mtx) ) { fwrite((void *) &mtx->entries, sizeof(double), 2*size, fp) ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to write the object for a human eye created -- 98may01, cca ---------------------------------------------- */ void A2_writeForHumanEye ( A2 *mtx, FILE *fp ) { int i, j, jfirst, jlast, loc ; if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in A2_writeForHumanEye(%p,%p)" "\n bad input\n", mtx, fp) ; exit(-1) ; } A2_writeStats(mtx, fp) ; if ( A2_IS_REAL(mtx) ) { for ( jfirst = 0 ; jfirst < mtx->n2 ; jfirst += 4 ) { jlast = jfirst + 3 ; if ( jlast >= mtx->n2 ) { jlast = mtx->n2 - 1 ; } fprintf(fp, "\n ") ; for ( j = jfirst ; j <= jlast ; j++ ) { fprintf(fp, "%19d", j) ; } for ( i = 0 ; i < mtx->n1 ; i++ ) { fprintf(fp, "\n%4d", i) ; for ( j = jfirst ; j <= jlast ; j++ ) { fprintf(fp, "%19.11e", mtx->entries[i*mtx->inc1 + j*mtx->inc2]) ; } } } } else if ( A2_IS_COMPLEX(mtx) ) { for ( jfirst = 0 ; jfirst < mtx->n2 ; jfirst += 2 ) { jlast = jfirst + 1 ; if ( jlast >= mtx->n2 ) { jlast = mtx->n2 - 1 ; } fprintf(fp, "\n ") ; for ( j = jfirst ; j <= jlast ; j++ ) { fprintf(fp, "%36d", j) ; } for ( i = 0 ; i < mtx->n1 ; i++ ) { fprintf(fp, "\n%4d", i) ; for ( j = jfirst ; j <= jlast ; j++ ) { loc = 2*(i*mtx->inc1 + j*mtx->inc2) ; fprintf(fp, " (%16.9e,%16.9e*i)", mtx->entries[loc], mtx->entries[loc+1]) ; } } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- to write out the statistics created -- 98may01, cca -------------------------------------- */ void A2_writeStats ( A2 *mtx, FILE *fp ) { if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in A2_writeStats(%p,%p)" "\n bad input\n", mtx, fp) ; exit(-1) ; } if ( A2_IS_REAL(mtx) ) { fprintf(fp, "\n A2 : double 2D array object :") ; } else if ( A2_IS_COMPLEX(mtx) ) { fprintf(fp, "\n A2 : double complex 2D array object :") ; } fprintf(fp, "\n %d x %d matrix, inc1 = %d, inc2 = %d," "\n nowned = %d, %d entries allocated, occupies %d bytes" "\n entries = %p, maxabs = %20.12e", mtx->n1, mtx->n2, mtx->inc1, mtx->inc2, mtx->nowned, mtx->n1*mtx->n2, A2_sizeOf(mtx), mtx->entries, A2_maxabs(mtx)) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to write the matrix in matlab format created -- 98may01, cca ----------------------------------------------- */ void A2_writeForMatlab ( A2 *mtx, char *mtxname, FILE *fp ) { int irow, jcol, ncol, nrow ; if ( mtx == NULL || mtxname == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in A2_writeForMatlab(%p,%p,%p)" "\n bad input\n", mtx, mtxname, fp) ; exit(-1) ; } nrow = A2_nrow(mtx) ; ncol = A2_ncol(mtx) ; for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { if ( A2_IS_REAL(mtx) ) { double value ; A2_realEntry(mtx, irow, jcol, &value) ; fprintf(fp, "\n %s(%d,%d) = %24.16e ;", mtxname, irow+1, jcol+1, value) ; } else if ( A2_IS_COMPLEX(mtx) ) { double imag, real ; A2_complexEntry(mtx, irow, jcol, &real, &imag) ; fprintf(fp, "\n %s(%d,%d) = %24.16e + %24.16e*i ;", mtxname, irow+1, jcol+1, real, imag) ; } } } return ; } /*--------------------------------------------------------------------*/ tx->inc1 + (mtx->n2-1)*mtx->inc2) > 0 ) { if ( A2_IS_REAL(mtx) ) { if ( (rc = DVfscanf(fp, size, mtx->entries)) != size ) { fprintf(stderr, "\n error in A2_readFromFoA2/src/QRreduce.c010064400020550007177000001026040664345125000150100ustar00clevecompmath00000400000006/* QRreduce.c */ #include "../A2.h" /*--------------------------------------------------------------------*/ static int copyIntoVec1 ( A2 *mtxA, double H0[], int msglvl, FILE *msgFile ) ; static double getHouseholderVector1 ( int type, int n, double H0[], double *pbeta0, int msglvl, FILE *msgFile ) ; static double computeW1 ( A2 *mtxA, double H0[], double W0[], int msglvl, FILE *msgFile ) ; static double updateA1 ( A2 *mtxA, double H0[], double beta0, double W0[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- compute A = QR, where Q is a product of householder vectors, (I - beta_j v_j v_j^T). on return, v_j is found in the lower triangle of A, v_j(j) = 1.0. return value -- # of floating point operations created -- 98may25, cca -------------------------------------------------------------- */ double A2_QRreduce ( A2 *mtxA, DV *workDV, int msglvl, FILE *msgFile ) { A2 tempA ; double nops ; double beta0 ; double *colA, *H0, *W0 ; int inc1, inc2, jcol, lastrow, length, ncolA, nrowA, nstep ; /* --------------- check the input --------------- */ if ( mtxA == NULL || workDV == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in A2_QRreduce()" "\n bad input\n") ; exit(-1) ; } if ( ! (A2_IS_REAL(mtxA) || A2_IS_COMPLEX(mtxA)) ) { fprintf(stderr, "\n fatal error in A2_QRreduce()" "\n matrix must be real or complex\n") ; exit(-1) ; } nrowA = A2_nrow(mtxA) ; ncolA = A2_ncol(mtxA) ; inc1 = A2_inc1(mtxA) ; inc2 = A2_inc2(mtxA) ; if ( A2_IS_REAL(mtxA) ) { DV_setSize(workDV, nrowA + ncolA) ; H0 = DV_entries(workDV) ; W0 = H0 + nrowA ; } else if ( A2_IS_COMPLEX(mtxA) ) { DV_setSize(workDV, 2*(nrowA + ncolA)) ; H0 = DV_entries(workDV) ; W0 = H0 + 2*nrowA ; } /* ------------------------------------------------- determine the number of steps = min(ncolA, nrowA) ------------------------------------------------- */ nstep = (ncolA <= nrowA) ? ncolA : nrowA ; /* ------------------- loop over the steps ------------------- */ nops = 0.0 ; for ( jcol = 0 ; jcol < nstep ; jcol++ ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n %% jcol = %d", jcol) ; } /* ---------------------------------- copy the column of A into a vector and find the last nonzero element ---------------------------------- */ A2_subA2(&tempA, mtxA, jcol, nrowA-1, jcol, ncolA-1) ; length = 1 + copyIntoVec1(&tempA, H0, msglvl, msgFile) ; lastrow = jcol + length - 1 ; if ( msglvl > 5 ) { fprintf(msgFile, "\n %% return from copyIntoVec1, length = %d, lastrow = %d", length, lastrow) ; } /* ------------------------------ compute the Householder vector and place into the column of A ------------------------------ */ colA = A2_column(mtxA, jcol) ; if ( A2_IS_REAL(mtxA) ) { nops += getHouseholderVector1(SPOOLES_REAL, length, H0, &beta0, msglvl, msgFile) ; A2_subA2(&tempA, mtxA, jcol, lastrow, jcol, jcol) ; A2_setColumn(&tempA, H0, 0) ; H0[0] = 1.0 ; } else if ( A2_IS_COMPLEX(mtxA) ) { nops += getHouseholderVector1(SPOOLES_COMPLEX, length, H0, &beta0, msglvl, msgFile) ; A2_subA2(&tempA, mtxA, jcol, lastrow, jcol, jcol) ; A2_setColumn(&tempA, H0, 0) ; H0[0] = 1.0 ; H0[1] = 0.0 ; } if ( msglvl > 5 && jcol == 0 ) { fprintf(msgFile, "\n %% beta0 = %12.4e;", beta0) ; } if ( beta0 != 0.0 && jcol + 1 < ncolA ) { A2_subA2(&tempA, mtxA, jcol, lastrow, jcol+1, ncolA-1) ; /* ------------------------------------------------ compute w = v^T * A(jcol:lastrow,jcol+1:nrowA-1) ------------------------------------------------ */ if ( msglvl > 3 ) { fprintf(msgFile, "\n %% compute w") ; } nops += computeW1(&tempA, H0, W0, msglvl, msgFile) ; /* ------------------------------------------------- update A(jcol:lastrow,jcol+1:nrowA-1) -= beta*v*w ------------------------------------------------- */ if ( msglvl > 3 ) { fprintf(msgFile, "\n %% update A") ; } nops += updateA1(&tempA, H0, beta0, W0, msglvl, msgFile) ; } } return(nops) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- copy the first column of mtxA into the vector H0[] created -- 98may30, cca -------------------------------------------------- */ static int copyIntoVec1 ( A2 *mtxA, double H0[], int msglvl, FILE *msgFile ) { double ival, rval ; double *colA ; int ii, inc1, irow, jj, lastrow, ncolA, nrowA ; /* ---------------------------------- copy the column of A into a vector and find the last nonzero element ---------------------------------- */ nrowA = mtxA->n1 ; ncolA = mtxA->n2 ; inc1 = mtxA->inc1 ; lastrow = -1 ; colA = A2_column(mtxA, 0) ; if ( A2_IS_REAL(mtxA) ) { for ( irow = ii = jj = 0 ; irow < nrowA ; irow++, ii += inc1, jj++ ) { rval = colA[ii] ; if ( rval != 0.0 ) { H0[jj] = rval ; lastrow = irow ; } } } else if ( A2_IS_COMPLEX(mtxA) ) { for ( irow = ii = jj = 0 ; irow < nrowA ; irow++, ii += 2*inc1, jj += 2 ) { rval = colA[ii] ; ival = colA[ii+1] ; if ( rval != 0.0 || ival != 0.0 ) { H0[jj] = rval ; H0[jj+1] = ival ; lastrow = irow ; } } } return(lastrow) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- compute a householder transformation (I - beta*v*v^H)x = alpha*e_1 where v[0] = 1.0 on input, H0 contains x, on output, beta0 contains beta H0[0] = alpha H0[1:n-1] = v[1:n] ; created -- 98may30, cca ---------------------------------------------------------------- */ static double getHouseholderVector1 ( int type, int n, double H0[], double *pbeta0, int msglvl, FILE *msgFile ) { double beta0, ifac, ival, nops, normx, rfac, rval, sigma, sum, v0imag, v0real, y0imag, y0real ; int ii, jj ; /* -------------------------------------------- compute ||H0(1:n-1)||_2^2 and the row that contains the last nonzero entry -------------------------------------------- */ sigma = 0.0 ; beta0 = 0.0 ; nops = 0.0 ; if ( type == SPOOLES_REAL ) { for ( ii = 1 ; ii < n ; ii++ ) { rval = H0[ii] ; sigma += rval*rval ; } nops += 2*(n-1) ; } else if ( type == SPOOLES_COMPLEX ) { for ( ii = 1, jj = 2 ; ii < n ; ii++, jj += 2 ) { rval = H0[jj] ; ival = H0[jj+1] ; sigma += rval*rval + ival*ival ; } nops += 4*(n-1) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% sigma = %12.4e", sigma) ; } if ( sigma != 0.0 ) { /* -------------------------------------------- there are nonzero entries below the diagonal -------------------------------------------- */ if ( type == SPOOLES_REAL ) { rval = H0[0] ; if ( rval == 0.0 ) { normx = sqrt(sigma) ; v0real = normx ; y0real = - normx ; nops++ ; } else { normx = sqrt(sigma + rval*rval) ; rfac = normx/fabs(rval) ; v0real = rval*(1 + rfac) ; y0real = -rfac*rval ; nops += 7 ; } } else if ( type == SPOOLES_COMPLEX ) { rval = H0[0] ; ival = H0[1] ; if ( rval == 0.0 && ival == 0.0 ) { normx = sqrt(sigma) ; v0real = normx ; v0imag = 0.0 ; y0real = - normx ; y0imag = 0.0 ; nops += 2 ; } else { normx = sqrt(sigma + rval*rval + ival*ival) ; rfac = normx/Zabs(rval, ival) ; v0real = rval + rfac*rval ; v0imag = ival + rfac*ival ; y0real = -rfac*rval ; y0imag = -rfac*ival ; nops += 16 ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% normx = %12.4e", normx) ; } /* ------------------------------------- scale u so u1 = 1.0 and compute beta0 ------------------------------------- */ if ( type == SPOOLES_REAL ) { rfac = 1./v0real ; for ( ii = 1 ; ii < n ; ii++ ) { H0[ii] *= rfac ; } sum = 1.0 ; for ( ii = 1 ; ii < n ; ii++ ) { rval = H0[ii] ; sum += rval*rval ; } nops += 3*(n-1) ; beta0 = 2./sum ; /* rfac = 1./v0real ; sum = 1.0 ; for ( ii = 1 ; ii < n ; ii++ ) { rval = H0[ii] = rfac*H0[ii] ; sum += rval*rval ; } nops += 3*(n-1) ; beta0 = 2./sum ; */ } else if ( type == SPOOLES_COMPLEX ) { Zrecip(v0real, v0imag, &rfac, &ifac) ; sum = 1.0 ; for ( ii = 1, jj = 2 ; ii < n ; ii++, jj += 2 ) { rval = H0[jj] ; ival = H0[jj+1] ; H0[jj] = rfac*rval - ifac*ival ; H0[jj+1] = rfac*ival + ifac*rval ; rval = H0[jj] ; ival = H0[jj+1] ; sum += rval*rval + ival*ival ; } nops += 10*(n-1) + 5 ; beta0 = 2./sum ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n %% sum = %12.4e, beta0 = %12.4e", sum, beta0) ; } /* --------------------------------------------- set the first entry of the transformed column --------------------------------------------- */ if ( type == SPOOLES_REAL ) { H0[0] = y0real ; } else if ( type == SPOOLES_COMPLEX ) { H0[0] = y0real ; H0[1] = y0imag ; } } *pbeta0 = beta0 ; /* fprintf(msgFile, "\n H0") ; DVfprintf(msgFile, n, H0) ; */ return(nops) ; } /*--------------------------------------------------------------------*/ /* ----------------------- compute W0 = v^H * A created -- 98may30, cca ----------------------- */ static double computeW1 ( A2 *mtxA, double H0[], double W0[], int msglvl, FILE *msgFile ) { double nops ; int inc1, inc2, ncolA, nrowA ; if ( msglvl > 5 ) { fprintf(msgFile, "\n %% inside computeW1, nrow %d, ncol %d", mtxA->n1, mtxA->n2) ; } nrowA = mtxA->n1 ; ncolA = mtxA->n2 ; inc1 = mtxA->inc1 ; inc2 = mtxA->inc2 ; if ( inc1 != 1 && inc2 != 1 ) { fprintf(stderr, "\n error in computeW1" "\n inc1 = %d, inc2 = %d\n", inc1, inc2) ; exit(-1) ; } nops = 0.0 ; if ( A2_IS_REAL(mtxA) ) { int irow, jcol ; if ( inc1 == 1 ) { double sums[3] ; double *colA0, *colA1, *colA2 ; /* ---------------------------- A is column major, compute W(j) = H0^T * A(*,j) ---------------------------- */ for ( jcol = 0 ; jcol < ncolA - 2 ; jcol += 3 ) { colA0 = A2_column(mtxA, jcol) ; colA1 = A2_column(mtxA, jcol+1) ; colA2 = A2_column(mtxA, jcol+2) ; DVdot13(nrowA, H0, colA0, colA1, colA2, sums) ; W0[jcol] = sums[0] ; W0[jcol+1] = sums[1] ; W0[jcol+2] = sums[2] ; nops += 6*nrowA ; } if ( jcol == ncolA - 2 ) { colA0 = A2_column(mtxA, jcol) ; colA1 = A2_column(mtxA, jcol+1) ; DVdot12(nrowA, H0, colA0, colA1, sums) ; W0[jcol] = sums[0] ; W0[jcol+1] = sums[1] ; nops += 4*nrowA ; } else if ( jcol == ncolA - 1 ) { colA0 = A2_column(mtxA, jcol) ; DVdot11(nrowA, H0, colA0, sums) ; W0[jcol] = sums[0] ; nops += 2*nrowA ; } } else { double alpha[3] ; double *rowA0, *rowA1, *rowA2 ; /* ------------------------------- A is row major compute W := W + H0(j) * A(j,*) ------------------------------- */ DVzero(ncolA, W0) ; for ( irow = 0 ; irow < nrowA - 2 ; irow += 3 ) { rowA0 = A2_row(mtxA, irow) ; rowA1 = A2_row(mtxA, irow+1) ; rowA2 = A2_row(mtxA, irow+2) ; alpha[0] = H0[irow] ; alpha[1] = H0[irow+1] ; alpha[2] = H0[irow+2] ; DVaxpy13(ncolA, W0, alpha, rowA0, rowA1, rowA2) ; nops += 6*ncolA ; } if ( irow == nrowA - 2 ) { rowA0 = A2_row(mtxA, irow) ; rowA1 = A2_row(mtxA, irow+1) ; alpha[0] = H0[irow] ; alpha[1] = H0[irow+1] ; DVaxpy12(ncolA, W0, alpha, rowA0, rowA1) ; nops += 4*ncolA ; } else if ( irow == nrowA - 1 ) { rowA0 = A2_row(mtxA, irow) ; alpha[0] = H0[irow] ; DVaxpy11(ncolA, W0, alpha, rowA0) ; nops += 2*ncolA ; } } } else if ( A2_IS_COMPLEX(mtxA) ) { int irow, jcol ; if ( inc1 == 1 ) { double sums[6] ; double *colA0, *colA1, *colA2 ; /* ---------------------------- A is column major compute W(j) = H0^H * A(*,j) ---------------------------- */ for ( jcol = 0 ; jcol < ncolA - 2 ; jcol += 3 ) { colA0 = A2_column(mtxA, jcol) ; colA1 = A2_column(mtxA, jcol+1) ; colA2 = A2_column(mtxA, jcol+2) ; ZVdotC13(nrowA, H0, colA0, colA1, colA2, sums) ; W0[2*jcol] = sums[0] ; W0[2*jcol+1] = sums[1] ; W0[2*(jcol+1)] = sums[2] ; W0[2*(jcol+1)+1] = sums[3] ; W0[2*(jcol+2)] = sums[4] ; W0[2*(jcol+2)+1] = sums[5] ; nops += 24*nrowA ; } if ( jcol == ncolA - 2 ) { colA0 = A2_column(mtxA, jcol) ; colA1 = A2_column(mtxA, jcol+1) ; ZVdotC12(nrowA, H0, colA0, colA1, sums) ; W0[2*jcol] = sums[0] ; W0[2*jcol+1] = sums[1] ; W0[2*(jcol+1)] = sums[2] ; W0[2*(jcol+1)+1] = sums[3] ; nops += 16*nrowA ; } else if ( jcol == ncolA - 1 ) { colA0 = A2_column(mtxA, jcol) ; ZVdotC11(nrowA, H0, colA0, sums) ; W0[2*jcol] = sums[0] ; W0[2*jcol+1] = sums[1] ; nops += 8*nrowA ; } } else { double alpha[6] ; double *rowA0, *rowA1, *rowA2 ; /* --------------------------------- A is row major compute W := W + H0(j)^H * A(j,*) --------------------------------- */ DVzero(2*ncolA, W0) ; for ( irow = 0 ; irow < nrowA - 2 ; irow += 3 ) { rowA0 = A2_row(mtxA, irow) ; rowA1 = A2_row(mtxA, irow+1) ; rowA2 = A2_row(mtxA, irow+2) ; alpha[0] = H0[2*irow] ; alpha[1] = -H0[2*irow+1] ; alpha[2] = H0[2*(irow+1)] ; alpha[3] = -H0[2*(irow+1)+1] ; alpha[4] = H0[2*(irow+2)] ; alpha[5] = -H0[2*(irow+2)+1] ; ZVaxpy13(ncolA, W0, alpha, rowA0, rowA1, rowA2) ; nops += 24*ncolA ; } if ( irow == nrowA - 2 ) { rowA0 = A2_row(mtxA, irow) ; rowA1 = A2_row(mtxA, irow+1) ; alpha[0] = H0[2*irow] ; alpha[1] = -H0[2*irow+1] ; alpha[2] = H0[2*(irow+1)] ; alpha[3] = -H0[2*(irow+1)+1] ; ZVaxpy12(ncolA, W0, alpha, rowA0, rowA1) ; nops += 16*ncolA ; } else if ( irow == nrowA - 1 ) { rowA0 = A2_row(mtxA, irow) ; alpha[0] = H0[2*irow] ; alpha[1] = -H0[2*irow+1] ; ZVaxpy11(ncolA, W0, alpha, rowA0) ; nops += 8*ncolA ; } } } return(nops) ; } /*--------------------------------------------------------------------*/ /* --------------------------------- compute A := A - H0 * beta0 * W0 created -- 98may30, cca --------------------------------- */ static double updateA1 ( A2 *mtxA, double H0[], double beta0, double W0[], int msglvl, FILE *msgFile ) { double nops ; int inc1, inc2, ncolA, nrowA ; if ( msglvl > 5 ) { fprintf(msgFile, "\n %% inside updateA1, nrow %d, ncol %d", mtxA->n1, mtxA->n2) ; } nrowA = mtxA->n1 ; ncolA = mtxA->n2 ; inc1 = mtxA->inc1 ; inc2 = mtxA->inc2 ; nops = 0.0 ; if ( A2_IS_REAL(mtxA) ) { int irow, jcol ; if ( inc1 == 1 ) { double alpha[3] ; double *colA0, *colA1, *colA2 ; /* ----------------------------------------- A is column major compute A(:,jcol) -= beta * W0(jcol) * H0 ----------------------------------------- */ for ( jcol = 0 ; jcol < ncolA - 2 ; jcol += 3 ) { colA0 = A2_column(mtxA, jcol) ; colA1 = A2_column(mtxA, jcol+1) ; colA2 = A2_column(mtxA, jcol+2) ; alpha[0] = -beta0 * W0[jcol] ; alpha[1] = -beta0 * W0[jcol+1] ; alpha[2] = -beta0 * W0[jcol+2] ; DVaxpy31(nrowA, colA0, colA1, colA2, alpha, H0) ; nops += 6*nrowA ; } if ( jcol == ncolA - 2 ) { colA0 = A2_column(mtxA, jcol) ; colA1 = A2_column(mtxA, jcol+1) ; alpha[0] = -beta0 * W0[jcol] ; alpha[1] = -beta0 * W0[jcol+1] ; DVaxpy21(nrowA, colA0, colA1, alpha, H0) ; nops += 4*nrowA ; } else if ( jcol == ncolA - 1 ) { colA0 = A2_column(mtxA, jcol) ; alpha[0] = -beta0 * W0[jcol] ; DVaxpy11(nrowA, colA0, alpha, H0) ; nops += 2*nrowA ; } } else { double alpha[3] ; double *rowA0, *rowA1, *rowA2 ; /* ----------------------------------------- A is row major compute A(irow,:) -= H0[irow]*beta0*W0(:) ----------------------------------------- */ for ( irow = 0 ; irow < nrowA - 2 ; irow += 3 ) { rowA0 = A2_row(mtxA, irow) ; rowA1 = A2_row(mtxA, irow+1) ; rowA2 = A2_row(mtxA, irow+2) ; alpha[0] = -beta0 * H0[irow] ; alpha[1] = -beta0 * H0[irow+1] ; alpha[2] = -beta0 * H0[irow+2] ; DVaxpy31(ncolA, rowA0, rowA1, rowA2, alpha, W0) ; nops += 6*ncolA + 3 ; } if ( irow == nrowA - 2 ) { rowA0 = A2_row(mtxA, irow) ; rowA1 = A2_row(mtxA, irow+1) ; alpha[0] = -beta0 * H0[irow] ; alpha[1] = -beta0 * H0[irow+1] ; DVaxpy21(ncolA, rowA0, rowA1, alpha, W0) ; nops += 4*ncolA + 2 ; } else if ( irow == nrowA - 1 ) { rowA0 = A2_row(mtxA, irow) ; alpha[0] = -beta0 * H0[irow] ; DVaxpy11(ncolA, rowA0, alpha, W0) ; nops += 2*ncolA + 1 ; } } } else if ( A2_IS_COMPLEX(mtxA) ) { int irow, jcol ; if ( inc1 == 1 ) { double alpha[6] ; double *colA0, *colA1, *colA2 ; /* ----------------------------------------- A is column major compute A(:,jcol) -= beta * W0(jcol) * H0 ----------------------------------------- */ for ( jcol = 0 ; jcol < ncolA - 2 ; jcol += 3 ) { colA0 = A2_column(mtxA, jcol) ; colA1 = A2_column(mtxA, jcol+1) ; colA2 = A2_column(mtxA, jcol+2) ; alpha[0] = -beta0 * W0[2*jcol] ; alpha[1] = -beta0 * W0[2*jcol+1] ; alpha[2] = -beta0 * W0[2*(jcol+1)] ; alpha[3] = -beta0 * W0[2*(jcol+1)+1] ; alpha[4] = -beta0 * W0[2*(jcol+2)] ; alpha[5] = -beta0 * W0[2*(jcol+2)+1] ; ZVaxpy31(nrowA, colA0, colA1, colA2, alpha, H0) ; nops += 24*nrowA ; } if ( jcol == ncolA - 2 ) { colA0 = A2_column(mtxA, jcol) ; colA1 = A2_column(mtxA, jcol+1) ; alpha[0] = -beta0 * W0[2*jcol] ; alpha[1] = -beta0 * W0[2*jcol+1] ; alpha[2] = -beta0 * W0[2*(jcol+1)] ; alpha[3] = -beta0 * W0[2*(jcol+1)+1] ; ZVaxpy21(nrowA, colA0, colA1, alpha, H0) ; nops += 16*nrowA ; } else if ( jcol == ncolA - 1 ) { colA0 = A2_column(mtxA, jcol) ; alpha[0] = -beta0 * W0[2*jcol] ; alpha[1] = -beta0 * W0[2*jcol+1] ; ZVaxpy11(nrowA, colA0, alpha, H0) ; nops += 8*nrowA ; } } else { double alpha[6] ; double *rowA0, *rowA1, *rowA2 ; /* ----------------------------------------- A is row major compute A(irow,:) -= H0[irow]*beta0*W0(:) ----------------------------------------- */ for ( irow = 0 ; irow < nrowA - 2 ; irow += 3 ) { rowA0 = A2_row(mtxA, irow) ; rowA1 = A2_row(mtxA, irow+1) ; rowA2 = A2_row(mtxA, irow+2) ; alpha[0] = -beta0 * H0[2*irow] ; alpha[1] = -beta0 * H0[2*irow+1] ; alpha[2] = -beta0 * H0[2*(irow+1)] ; alpha[3] = -beta0 * H0[2*(irow+1)+1] ; alpha[4] = -beta0 * H0[2*(irow+2)] ; alpha[5] = -beta0 * H0[2*(irow+2)+1] ; ZVaxpy31(ncolA, rowA0, rowA1, rowA2, alpha, W0) ; nops += 24*ncolA + 12 ; } if( irow == nrowA - 2 ) { rowA0 = A2_row(mtxA, irow) ; rowA1 = A2_row(mtxA, irow+1) ; alpha[0] = -beta0 * H0[2*irow] ; alpha[1] = -beta0 * H0[2*irow+1] ; alpha[2] = -beta0 * H0[2*(irow+1)] ; alpha[3] = -beta0 * H0[2*(irow+1)+1] ; ZVaxpy21(ncolA, rowA0, rowA1, alpha, W0) ; nops += 16*ncolA + 8 ; } else if( irow == nrowA - 1 ) { rowA0 = A2_row(mtxA, irow) ; alpha[0] = -beta0 * H0[2*irow] ; alpha[1] = -beta0 * H0[2*irow+1] ; ZVaxpy11(ncolA, rowA0, alpha, W0) ; nops += 8*ncolA + 4 ; } } } return(nops) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- A contains the following data from the A = QR factorization A(1:ncolA,1:ncolA) = R A(j+1:nrowA,j) is v_j, the j-th householder vector, where v_j[j] = 1.0 NOTE: A and Q must be column major created -- 98dec10, cca ----------------------------------------------------------- */ void A2_computeQ ( A2 *Q, A2 *A, DV *workDV, int msglvl, FILE *msgFile ) { double *betas ; int irowA, jcolA, ncolA, nrowA ; /* --------------- check the input --------------- */ if ( Q == NULL ) { fprintf(stderr, "\n fatal error in A2_computeQ()" "\n Q is NULL\n") ; exit(-1) ; } if ( A == NULL ) { fprintf(stderr, "\n fatal error in A2_computeQ()" "\n A is NULL\n") ; exit(-1) ; } if ( workDV == NULL ) { fprintf(stderr, "\n fatal error in A2_computeQ()" "\n workDV is NULL\n") ; exit(-1) ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n fatal error in A2_computeQ()" "\n msglvl > 0 and msgFile is NULL\n") ; exit(-1) ; } nrowA = A2_nrow(A) ; ncolA = A2_ncol(A) ; if ( nrowA <= 0 ) { fprintf(stderr, "\n fatal error in A2_computeQ()" "\n nrowA = %d\n", nrowA) ; exit(-1) ; } if ( ncolA <= 0 ) { fprintf(stderr, "\n fatal error in A2_computeQ()" "\n ncolA = %d\n", nrowA) ; exit(-1) ; } if ( nrowA != A2_nrow(Q) ) { fprintf(stderr, "\n fatal error in A2_computeQ()" "\n nrowA = %d, nrowQ = %d\n", nrowA, A2_nrow(Q)) ; exit(-1) ; } if ( ncolA != A2_ncol(Q) ) { fprintf(stderr, "\n fatal error in A2_computeQ()" "\n ncolA = %d, ncolQ = %d\n", ncolA, A2_ncol(Q)) ; exit(-1) ; } switch ( A->type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n fatal error in A2_computeQ()" "\n invalid type for A\n") ; exit(-1) ; } if ( A->type != Q->type ) { fprintf(stderr, "\n fatal error in A2_computeQ()" "\n A->type = %d, Q->type = %d\n", A->type, Q->type) ; exit(-1) ; } if ( A2_inc1(A) != 1 ) { fprintf(stderr, "\n fatal error in A2_computeQ()" "\n A->inc1 = %d \n", A2_inc1(A)) ; exit(-1) ; } if ( A2_inc1(Q) != 1 ) { fprintf(stderr, "\n fatal error in A2_computeQ()" "\n Q->inc1 = %d, \n", A2_inc1(Q)) ; exit(-1) ; } /* -------------------------------------------------- compute the beta values, beta_j = 2./(V_j^H * V_j) -------------------------------------------------- */ DV_setSize(workDV, ncolA) ; betas = DV_entries(workDV) ; if ( A2_IS_REAL(A) ) { int irowA, jcolA ; double sum ; double *colA ; for ( jcolA = 0 ; jcolA < ncolA ; jcolA++ ) { sum = 1.0 ; colA = A2_column(A, jcolA) ; for ( irowA = jcolA + 1 ; irowA < nrowA ; irowA++ ) { sum += colA[irowA] * colA[irowA] ; } betas[jcolA] = 2./sum ; } } else { double ival, rval, sum ; double *colA ; for ( jcolA = 0 ; jcolA < ncolA ; jcolA++ ) { sum = 1.0 ; colA = A2_column(A, jcolA) ; for ( irowA = jcolA + 1 ; irowA < nrowA ; irowA++ ) { rval = colA[2*irowA] ; ival = colA[2*irowA+1] ; sum += rval*rval + ival*ival ; } betas[jcolA] = 2./sum ; } } /* ------------------------------------------- loop over the number of householder vectors ------------------------------------------- */ for ( jcolA = 0 ; jcolA < ncolA ; jcolA++ ) { double *V, *X ; int jcolV ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n %% jcolA = %d", jcolA) ; fflush(msgFile) ; } /* ------------------ set X[] to e_jcolA ------------------ */ X = A2_column(Q, jcolA) ; if ( A2_IS_REAL(Q) ) { DVzero(nrowA, X) ; X[jcolA] = 1.0 ; } else { DVzero(2*nrowA, X) ; X[2*jcolA] = 1.0 ; } for ( jcolV = jcolA ; jcolV >= 0 ; jcolV-- ) { double beta ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %% jcolV = %d", jcolV) ; fflush(msgFile) ; } /* ----------------------------------------------------- update X = (I - beta_jcolV * V_jcolV * V_jcolV^T)X = X - beta_jcolV * V_jcolV * V_jcolV^T * X = X - (beta_jcolV * V_jcolV^T * X) * V_jcolV ----------------------------------------------------- */ V = A2_column(A, jcolV) ; beta = betas[jcolV] ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %% beta = %12.4e", beta) ; fflush(msgFile) ; } if ( A2_IS_REAL(Q) ) { double fac, sum = X[jcolV] ; int irow ; for ( irow = jcolV + 1 ; irow < nrowA ; irow++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n %% V[%d] = %12.4e, X[%d] = %12.4e", irow, V[irow], irow, X[irow]) ; fflush(msgFile) ; } sum += V[irow] * X[irow] ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n %% sum = %12.4e", sum) ; fflush(msgFile) ; } fac = beta * sum ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %% fac = %12.4e", fac) ; fflush(msgFile) ; } X[jcolV] -= fac ; for ( irow = jcolV + 1 ; irow < nrowA ; irow++ ) { X[irow] -= fac * V[irow] ; } } else { double rfac, ifac, rsum = X[2*jcolV], isum = X[2*jcolV+1] ; int irow ; for ( irow = jcolV + 1 ; irow < nrowA ; irow++ ) { double Vi, Vr, Xi, Xr ; Vr = V[2*irow] ; Vi = V[2*irow+1] ; Xr = X[2*irow] ; Xi = X[2*irow+1] ; rsum += Vr*Xr + Vi*Xi ; isum += Vr*Xi - Vi*Xr ; } rfac = beta * rsum ; ifac = beta * isum ; X[2*jcolV] -= rfac ; X[2*jcolV+1] -= ifac ; for ( irow = jcolV + 1 ; irow < nrowA ; irow++ ) { double Vi, Vr ; Vr = V[2*irow] ; Vi = V[2*irow+1] ; X[2*irow] -= rfac*Vr - ifac*Vi ; X[2*irow+1] -= rfac*Vi + ifac*Vr ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- A contains the following data from the A = QR factorization A(1:ncolA,1:ncolA) = R A(j+1:nrowA,j) is v_j, the j-th householder vector, where v_j[j] = 1.0 we compute Y = Q^T X when A is real and Y = Q^H X when A is complex NOTE: A, Y and X must be column major. NOTE: Y and X can be the same object, in which case X is overwritten with Y created -- 98dec10, cca ----------------------------------------------------------- */ void A2_applyQT ( A2 *Y, A2 *A, A2 *X, DV *workDV, int msglvl, FILE *msgFile ) { double *betas ; int irowA, jcolA, jcolX, ncolA, ncolX, nrowA ; /* --------------- check the input --------------- */ if ( A == NULL ) { fprintf(stderr, "\n fatal error in A2_applyQT()" "\n A is NULL\n") ; exit(-1) ; } if ( X == NULL ) { fprintf(stderr, "\n fatal error in A2_applyQT()" "\n X is NULL\n") ; exit(-1) ; } if ( workDV == NULL ) { fprintf(stderr, "\n fatal error in A2_applyQT()" "\n workDV is NULL\n") ; exit(-1) ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n fatal error in A2_applyQT()" "\n msglvl > 0 and msgFile is NULL\n") ; exit(-1) ; } nrowA = A2_nrow(A) ; ncolA = A2_ncol(A) ; ncolX = A2_ncol(X) ; if ( nrowA <= 0 ) { fprintf(stderr, "\n fatal error in A2_applyQT()" "\n nrowA = %d\n", nrowA) ; exit(-1) ; } if ( ncolA <= 0 ) { fprintf(stderr, "\n fatal error in A2_applyQT()" "\n ncolA = %d\n", nrowA) ; exit(-1) ; } if ( nrowA != A2_nrow(X) ) { fprintf(stderr, "\n fatal error in A2_applyQT()" "\n nrowA = %d, nrowX = %d\n", nrowA, A2_nrow(X)) ; exit(-1) ; } switch ( A->type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n fatal error in A2_applyQT()" "\n invalid type for A\n") ; exit(-1) ; } if ( A->type != X->type ) { fprintf(stderr, "\n fatal error in A2_applyQT()" "\n A->type = %d, X->type = %d\n", A->type, X->type) ; exit(-1) ; } if ( A2_inc1(A) != 1 ) { fprintf(stderr, "\n fatal error in A2_applyQT()" "\n A->inc1 = %d \n", A2_inc1(A)) ; exit(-1) ; } if ( A2_inc1(X) != 1 ) { fprintf(stderr, "\n fatal error in A2_applyQT()" "\n X->inc1 = %d, \n", A2_inc1(X)) ; exit(-1) ; } /* -------------------------------------------------- compute the beta values, beta_j = 2./(V_j^H * V_j) -------------------------------------------------- */ DV_setSize(workDV, ncolA) ; betas = DV_entries(workDV) ; if ( A2_IS_REAL(A) ) { int irowA, jcolA ; double sum ; double *colA ; for ( jcolA = 0 ; jcolA < ncolA ; jcolA++ ) { sum = 1.0 ; colA = A2_column(A, jcolA) ; for ( irowA = jcolA + 1 ; irowA < nrowA ; irowA++ ) { sum += colA[irowA] * colA[irowA] ; } betas[jcolA] = 2./sum ; } } else { double ival, rval, sum ; double *colA ; for ( jcolA = 0 ; jcolA < ncolA ; jcolA++ ) { sum = 1.0 ; colA = A2_column(A, jcolA) ; for ( irowA = jcolA + 1 ; irowA < nrowA ; irowA++ ) { rval = colA[2*irowA] ; ival = colA[2*irowA+1] ; sum += rval*rval + ival*ival ; } betas[jcolA] = 2./sum ; } } /* ------------------------------------------ loop over the number of columns in X and Y ------------------------------------------ */ for ( jcolX = 0 ; jcolX < ncolX ; jcolX++ ) { double *V, *colX, *colY ; int jcolV ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n %% jcolX = %d", jcolX) ; fflush(msgFile) ; } /* ------------------------------- copy X(:,jcolX) into Y(:,jcolX) ------------------------------- */ colY = A2_column(Y, jcolX) ; colX = A2_column(X, jcolX) ; if ( A2_IS_REAL(A) ) { DVcopy(nrowA, colY, colX) ; } else { DVcopy(2*nrowA, colY, colX) ; } for ( jcolV = 0 ; jcolV < ncolA ; jcolV++ ) { double beta ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %% jcolV = %d", jcolV) ; fflush(msgFile) ; } /* ------------------------------------------------------------ update colY = (I - beta_jcolV * V_jcolV * V_jcolV^T)colY = colY - beta_jcolV * V_jcolV * V_jcolV^T * colY = colY - (beta_jcolV * V_jcolV^T * Y) * V_jcolV ------------------------------------------------------------ */ V = A2_column(A, jcolV) ; beta = betas[jcolV] ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %% beta = %12.4e", beta) ; fflush(msgFile) ; } if ( A2_IS_REAL(A) ) { double fac, sum = colY[jcolV] ; int irow ; for ( irow = jcolV + 1 ; irow < nrowA ; irow++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n %% V[%d] = %12.4e, X[%d] = %12.4e", irow, V[irow], irow, colY[irow]) ; fflush(msgFile) ; } sum += V[irow] * colY[irow] ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n %% sum = %12.4e", sum) ; fflush(msgFile) ; } fac = beta * sum ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %% fac = %12.4e", fac) ; fflush(msgFile) ; } colY[jcolV] -= fac ; for ( irow = jcolV + 1 ; irow < nrowA ; irow++ ) { colY[irow] -= fac * V[irow] ; } } else { double rfac, ifac, rsum = colY[2*jcolV], isum = colY[2*jcolV+1] ; int irow ; for ( irow = jcolV + 1 ; irow < nrowA ; irow++ ) { double Vi, Vr, Yi, Yr ; Vr = V[2*irow] ; Vi = V[2*irow+1] ; Yr = colY[2*irow] ; Yi = colY[2*irow+1] ; rsum += Vr*Yr + Vi*Yi ; isum += Vr*Yi - Vi*Yr ; } rfac = beta * rsum ; ifac = beta * isum ; colY[2*jcolV] -= rfac ; colY[2*jcolV+1] -= ifac ; for ( irow = jcolV + 1 ; irow < nrowA ; irow++ ) { double Vi, Vr ; Vr = V[2*irow] ; Vi = V[2*irow+1] ; colY[2*irow] -= rfac*Vr - ifac*Vi ; colY[2*irow+1] -= rfac*Vi + ifac*Vr ; } } } } return ; } /*--------------------------------------------------------------------*/ ---------------------------- */ DV_setSize(workDV, ncolA) ; betas = DV_entries(workDV) ; if ( A2_IS_REAL(A) ) { int iroA2/src/basics.c010064400020550007177000000043170663576661000145560ustar00clevecompmath00000400000006/* basics.c */ #include "../A2.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98may01, cca ----------------------- */ A2 * A2_new ( void ) { A2 *mtx ; ALLOCATE(mtx, struct _A2, 1) ; A2_setDefaultFields(mtx) ; return(mtx) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98may01, cca ----------------------- */ void A2_setDefaultFields ( A2 *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_setDefaultFields(%p)" "\n bad input", mtx) ; exit(-1) ; } mtx->type = SPOOLES_REAL ; mtx->n1 = 0 ; mtx->inc1 = 0 ; mtx->n2 = 0 ; mtx->inc2 = 0 ; mtx->nowned = 0 ; mtx->entries = NULL ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may01, cca -------------------------------------------------- */ void A2_clearData ( A2 *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_clearData(%p)" "\n bad input\n", mtx) ; exit(-1) ; } /* ------------------------------------- free the entries if present and owned ------------------------------------- */ if ( mtx->nowned > 0 && mtx->entries != NULL ) { DVfree(mtx->entries) ; } /* ---------------------- set the default fields ---------------------- */ A2_setDefaultFields(mtx) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98may01, cca ------------------------------------------ */ void A2_free ( A2 *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_free(%p)" "\n bad input\n", mtx) ; exit(-1) ; } A2_clearData(mtx) ; FREE(mtx) ; return ; } /*--------------------------------------------------------------------*/ A2/src/copyEntriesToVector.c010064400020550007177000000377710653410576300173100ustar00clevecompmath00000400000006/* copyEntriesToVector.c */ #include "../A2.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- copy entries to a vector. the portion copied can be a union of the strict lower portion, the diagonal portion, and the strict upper portion. there is one restriction, if the strict lower and strict upper are to be copied, the diagonal will also be copied. length -- length of dvec[] dvec[] -- vector to receive matrix entries copyflag -- flag to denote what part of the entries to move A2_STRICT_LOWER --> move strict lower entries A2_LOWER --> move lower entries (includes the diagonal) A2_DIAGONAL --> move diagonal entries A2_UPPER --> move upper entries (includes the diagonal) A2_STRICT_UPPER --> move strict upper entries A2_ALL_ENTRIES --> move all entries storeflag -- flag to denote how to store entries in dvec[] A2_BY_ROWS --> store by rows A2_BY_COLUMNS --> store by columns return value -- number of entries copied created -- 97jun03, cca, dkw modified -- 98may25, cca ---------------------------------------------------------------- */ int A2_copyEntriesToVector ( A2 *mtx, int length, double *dvec, int copyflag, int storeflag ) { int inc1, inc2, kk, ncol, ndiag, nent, nrow ; /* -------------------------------------------- check the input, get dimensions and pointers and check that length is large enough -------------------------------------------- */ if ( mtx == NULL || length < 0 || dvec == NULL ) { fprintf(stderr, "\n fatal error in A2_copyEntriesToVector(%p,%d,%p,,%d,%d)" "\n bad input\n", mtx, length, dvec, copyflag, storeflag) ; exit(-1) ; } if ( copyflag < 1 || copyflag > 6 ) { fprintf(stderr, "\n fatal error in A2_copyEntriesToVector(%p,%d,%p,%d,%d)" "\n bad input\n" "\n copyflag = %d, must be\n" "\n 1 --> strictly lower entries" "\n 2 --> lower entries" "\n 3 --> diagonal entries" "\n 4 --> strictly upper entries" "\n 5 --> upper entries" "\n 6 --> all entries", mtx, length, dvec, copyflag, storeflag, copyflag) ; exit(-1) ; } if ( storeflag < 0 || storeflag > 1 ) { fprintf(stderr, "\n fatal error in A2_copyEntriesToVector(%p,%d,%p,%d,%d)" "\n bad input\n" "\n storeflag = %d, must be\n" "\n 0 --> store by rows" "\n 1 --> store by columns", mtx, length, dvec, copyflag, storeflag, storeflag) ; exit(-1) ; } nrow = mtx->n1 ; ncol = mtx->n2 ; inc1 = mtx->inc1 ; inc2 = mtx->inc2 ; if ( nrow >= ncol ) { ndiag = ncol ; } else { ndiag = nrow ; } /* ------------------------------------------ compute the number of entries to be copied ------------------------------------------ */ switch ( copyflag ) { case A2_STRICT_LOWER : /* strictly lower entries */ nent = (ndiag*(ndiag - 1))/2 + (nrow - ndiag)*ncol ; break ; case A2_LOWER : /* lower entries */ nent = (ndiag*(ndiag + 1))/2 + (nrow - ndiag)*ncol ; break ; case A2_DIAGONAL : /* diagonal entries */ nent = ndiag ; break ; case A2_UPPER : /* upper entries */ nent = (ndiag*(ndiag + 1))/2 + (ncol - ndiag)*nrow ; break ; case A2_STRICT_UPPER : /* strictly upper entries */ nent = (ndiag*(ndiag - 1))/2 + (ncol - ndiag)*nrow ; break ; case A2_ALL_ENTRIES : /* all entries */ nent = nrow*ncol ; break ; default : break ; } if ( nent > length ) { fprintf(stderr, "\n fatal error in A2_copyEntriesToVector(%p,%d,%p,%d,%d)" "\n nent = %d, buffer length = %d", mtx, length, dvec, copyflag, storeflag, nent, length) ; exit(-1) ; } /* -------------------------------------------- make life simple, unit stride through dvec[] -------------------------------------------- */ kk = 0 ; if ( storeflag == A2_BY_ROWS ) { int irow, jstart, jcol, jend, jj ; double *row ; /* -------------- loop over rows -------------- */ switch ( copyflag ) { case A2_STRICT_LOWER : /* ---------------------- strictly lower entries ---------------------- */ if ( A2_IS_REAL(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < nrow ; irow++, row += inc1 ) { jstart = 0 ; jend = (irow < ndiag) ? irow - 1 : ndiag - 1 ; for ( jcol = jstart, jj = jcol*inc2 ; jcol <= jend ; jcol++, jj += inc2, kk++ ) { dvec[kk] = row[jj] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < nrow ; irow++, row += 2*inc1 ) { jstart = 0 ; jend = (irow < ndiag) ? irow - 1 : ndiag - 1 ; for ( jcol = jstart, jj = jcol*inc2 ; jcol <= jend ; jcol++, jj += inc2, kk++ ) { dvec[2*kk] = row[2*jj] ; dvec[2*kk+1] = row[2*jj+1] ; } } } break ; case A2_LOWER : /* ------------------------------------ lower entries including the diagonal ------------------------------------ */ if ( A2_IS_REAL(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < nrow ; irow++, row += inc1 ) { jstart = 0 ; jend = (irow < ndiag) ? irow : ndiag - 1 ; for ( jcol = jstart, jj = jcol*inc2 ; jcol <= jend ; jcol++, jj += inc2, kk++ ) { dvec[kk] = row[jj] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < nrow ; irow++, row += 2*inc1 ) { jstart = 0 ; jend = (irow < ndiag) ? irow : ndiag - 1 ; for ( jcol = jstart, jj = jcol*inc2 ; jcol <= jend ; jcol++, jj += inc2, kk++ ) { dvec[2*kk] = row[2*jj] ; dvec[2*kk+1] = row[2*jj+1] ; } } } break ; case A2_DIAGONAL : /* ----------------- just the diagonal ----------------- */ if ( A2_IS_REAL(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < ndiag ; irow++, row += inc1, kk++ ) { dvec[kk] = row[irow*inc2] ; } } else if ( A2_IS_COMPLEX(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < ndiag ; irow++, row += 2*inc1, kk++ ) { dvec[2*kk] = row[2*irow*inc2] ; dvec[2*kk+1] = row[2*irow*inc2+1] ; } } break ; case A2_UPPER : /* ------------------------------------ upper entries including the diagonal ------------------------------------ */ if ( A2_IS_REAL(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < nrow ; irow++, row += inc1 ) { jstart = irow ; jend = ncol - 1 ; for ( jcol = jstart, jj = jcol*inc2 ; jcol <= jend ; jcol++, jj += inc2, kk++ ) { dvec[kk] = row[jj] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < nrow ; irow++, row += 2*inc1 ) { jstart = irow ; jend = ncol - 1 ; for ( jcol = jstart, jj = jcol*inc2 ; jcol <= jend ; jcol++, jj += inc2, kk++ ) { dvec[2*kk] = row[2*jj] ; dvec[2*kk+1] = row[2*jj+1] ; } } } break ; case A2_STRICT_UPPER : /* -------------------------- strictly the upper entries -------------------------- */ if ( A2_IS_REAL(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < nrow ; irow++, row += inc1 ) { jstart = irow + 1 ; jend = ncol - 1 ; for ( jcol = jstart, jj = jcol*inc2 ; jcol <= jend ; jcol++, jj += inc2, kk++ ) { dvec[kk] = row[jj] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < nrow ; irow++, row += 2*inc1 ) { jstart = irow + 1 ; jend = ncol - 1 ; for ( jcol = jstart, jj = jcol*inc2 ; jcol <= jend ; jcol++, jj += inc2, kk++ ) { dvec[2*kk] = row[2*jj] ; dvec[2*kk+1] = row[2*jj+1] ; } } } break ; case A2_ALL_ENTRIES : /* ----------- all entries ----------- */ if ( A2_IS_REAL(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < nrow ; irow++, row += inc1 ) { jstart = 0 ; jend = ncol - 1 ; for ( jcol = jstart, jj = 0 ; jcol <= jend ; jcol++, jj += inc2, kk++ ) { dvec[kk] = row[jj] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { for ( irow = 0, row = mtx->entries, kk = 0 ; irow < nrow ; irow++, row += 2*inc1 ) { jstart = 0 ; jend = ncol - 1 ; for ( jcol = jstart, jj = 0 ; jcol <= jend ; jcol++, jj += inc2, kk++ ) { dvec[2*kk] = row[2*jj] ; dvec[2*kk+1] = row[2*jj+1] ; } } } break ; default : break ; } } else { int iend, ii, irow, istart, jcol ; double *col ; /* ----------------- loop over columns ----------------- */ kk = 0 ; switch ( copyflag ) { case A2_STRICT_LOWER : /* ---------------------- strictly lower entries ---------------------- */ if ( A2_IS_REAL(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ncol ; jcol++, col += inc2 ) { istart = jcol + 1 ; iend = nrow - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1, kk++ ) { dvec[kk] = col[ii] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ncol ; jcol++, col += 2*inc2 ) { istart = jcol + 1 ; iend = nrow - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1, kk++ ) { dvec[2*kk] = col[2*ii] ; dvec[2*kk+1] = col[2*ii+1] ; } } } break ; case A2_LOWER : /* ------------------------------------ lower entries including the diagonal ------------------------------------ */ if ( A2_IS_REAL(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ncol ; jcol++, col += inc2 ) { istart = jcol ; iend = nrow - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1, kk++ ) { dvec[kk] = col[ii] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ncol ; jcol++, col += 2*inc2 ) { istart = jcol ; iend = nrow - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1, kk++ ) { dvec[2*kk] = col[2*ii] ; dvec[2*kk+1] = col[2*ii+1] ; } } } break ; case A2_DIAGONAL : /* ----------------- just the diagonal ----------------- */ if ( A2_IS_REAL(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ndiag ; jcol++, col += inc2, kk++ ) { dvec[kk] = col[jcol*inc1] ; } } else if ( A2_IS_COMPLEX(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ndiag ; jcol++, col += 2*inc2, kk++ ) { dvec[2*kk] = col[2*jcol*inc1] ; dvec[2*kk+1] = col[2*jcol*inc1+1] ; } } break ; case A2_UPPER : /* ------------------------------------ upper entries including the diagonal ------------------------------------ */ if ( A2_IS_REAL(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ncol ; jcol++, col += inc2 ) { istart = 0 ; iend = (jcol < ndiag) ? jcol : ndiag - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1, kk++ ) { dvec[kk] = col[ii] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ncol ; jcol++, col += 2*inc2 ) { istart = 0 ; iend = (jcol < ndiag) ? jcol : ndiag - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1, kk++ ) { dvec[2*kk] = col[2*ii] ; dvec[2*kk+1] = col[2*ii+1] ; } } } break ; case A2_STRICT_UPPER : /* -------------------------- strictly the upper entries -------------------------- */ if ( A2_IS_REAL(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ncol ; jcol++, col += inc2 ) { istart = 0 ; iend = (jcol < ndiag) ? jcol - 1 : ndiag - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1, kk++ ) { dvec[kk] = col[ii] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ncol ; jcol++, col += 2*inc2 ) { istart = 0 ; iend = (jcol < ndiag) ? jcol - 1 : ndiag - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1, kk++ ) { dvec[2*kk] = col[2*ii] ; dvec[2*kk+1] = col[2*ii+1] ; } } } break ; case A2_ALL_ENTRIES : /* ----------- all entries ----------- */ if ( A2_IS_REAL(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ncol ; jcol++, col += inc2 ) { istart = 0 ; iend = nrow - 1 ; for ( irow = istart, ii = 0 ; irow <= iend ; irow++, ii += inc1, kk++ ) { dvec[kk] = col[ii] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { for ( jcol = 0, col = mtx->entries, kk = 0 ; jcol < ncol ; jcol++, col += 2*inc2 ) { istart = 0 ; iend = nrow - 1 ; for ( irow = istart, ii = 0 ; irow <= iend ; irow++, ii += inc1, kk++ ) { dvec[2*kk] = col[2*ii] ; dvec[2*kk+1] = col[2*ii+1] ; } } } break ; default : break ; } } return(kk) ; } /*--------------------------------------------------------------------*/ row ; A2/src/init.c010064400020550007177000000115540653410576300142500ustar00clevecompmath00000400000006/* init.c */ #include "../A2.h" /*====================================================================*/ /* ------------------------------------------------------------------ initializer. sets the n1, n2, inc1 and inc2 fields. must have mtx != NULL type = SPOOLES_REAL or SPOOLES_COMPLEX n1, n2, inc1, inc2 > 0 (inc1 = 1 and inc2 = nrow) or (inc1 = ncol and inc2 = 1) if entries is NULL then entries are allocated and zeroed. else mtx->nowned is set to 0 mtx->entries is set to entries. endif n1, n2, inc1, inc2 set created -- 98apr15, cca ------------------------------------------------------------------ */ void A2_init ( A2 *mtx, int type, int n1, int n2, int inc1, int inc2, double *entries ) { /* --------------- check the input --------------- */ if ( mtx == NULL || n1 <= 0 || n2 <= 0 || inc1 <= 0 || inc2 <= 0 ) { fprintf(stderr, "\n fatal error in A2_init(%p,%d,%d,%d,%d,%p)" "\n bad input\n", mtx, n1, n2, inc1, inc2, entries) ; exit(-1) ; } if ( type != SPOOLES_REAL && type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error in A2_init(%p,%d,%d,%d,%d,%p)" "\n bad type %d\n", mtx, n1, n2, inc1, inc2, entries, type) ; exit(-1) ; } if ( entries == NULL && !( (inc1 == 1 && inc2 == n1) || (inc1 == n2 && inc2 == 1) ) ) { /* --------------------------------------------------------------- whoa, when we own the data we can only initialize a full matrix --------------------------------------------------------------- */ fprintf(stderr, "\n fatal error in A2_init(%p,%d,%d,%d,%d,%p)" "\n entries is not NULL and we have bad increments" "\n inc1 = %d, inc2 = %d, nrow = %d, ncol = %d\n", mtx, n1, n2, inc1, inc2, entries, inc1, inc2, n1, n2) ; exit(-1) ; } if ( entries != NULL ) { /* ---------------------------- set pointer to these entries ---------------------------- */ if ( mtx->entries != NULL ) { DVfree(mtx->entries) ; } mtx->nowned = 0 ; mtx->entries = entries ; } else { int nbytesNeeded, nbytesPresent ; /* ---------------------------- allocate and own the entries ---------------------------- */ if ( mtx->type == SPOOLES_REAL ) { nbytesPresent = mtx->nowned * sizeof(double) ; } else if ( mtx->type == SPOOLES_COMPLEX ) { nbytesPresent = 2 * mtx->nowned * sizeof(double) ; } else { nbytesPresent = 0 ; } if ( type == SPOOLES_REAL ) { nbytesNeeded = n1 * n2 * sizeof(double) ; } else if ( type == SPOOLES_COMPLEX ) { nbytesNeeded = 2 * n1 * n2 * sizeof(double) ; } if ( nbytesNeeded > nbytesPresent ) { DVfree(mtx->entries) ; mtx->nowned = n1 * n2 ; if ( type == SPOOLES_REAL ) { mtx->entries = DVinit(n1*n2, 0.0) ; } else if ( type == SPOOLES_COMPLEX ) { mtx->entries = DVinit(2*n1*n2, 0.0) ; } } } mtx->type = type ; mtx->n1 = n1 ; mtx->n2 = n2 ; mtx->inc1 = inc1 ; mtx->inc2 = inc2 ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- submatrix initializer A(0:lastrow-firstrow,0:lastcol-firstcol) = B(firstrow:lastrow, firstcol:lastcol) created -- 98apr15, cca -------------------------------------------------- */ void A2_subA2 ( A2 *mtxA, A2 *mtxB, int firstrow, int lastrow, int firstcol, int lastcol ) { /* --------------- check the input --------------- */ if ( mtxA == NULL || mtxB == NULL || firstrow < 0 || lastrow >= mtxB->n1 || firstcol < 0 || lastcol >= mtxB->n2 ) { fprintf(stderr, "\n fatal error in A2_subA2(%p,%p,%d,%d,%d,%d)" "\n bad input\n", mtxA, mtxB, firstrow, lastrow, firstcol, lastcol) ; if ( mtxA != NULL ) { fprintf(stderr, "\n first A2") ; A2_writeForHumanEye(mtxA, stderr) ; } if ( mtxB != NULL ) { fprintf(stderr, "\n second A2") ; A2_writeForHumanEye(mtxB, stderr) ; } exit(-1) ; } if ( ! (A2_IS_REAL(mtxB) || A2_IS_COMPLEX(mtxB)) ) { fprintf(stderr, "\n fatal error in A2_subA2(%p,%p,%d,%d,%d,%d)" "\n bad type %d\n", mtxA, mtxB, firstrow, lastrow, firstcol, lastcol, mtxB->type) ; exit(-1) ; } mtxA->type = mtxB->type ; mtxA->inc1 = mtxB->inc1 ; mtxA->inc2 = mtxB->inc2 ; mtxA->n1 = lastrow - firstrow + 1 ; mtxA->n2 = lastcol - firstcol + 1 ; if ( A2_IS_REAL(mtxB) ) { mtxA->entries = mtxB->entries + firstrow*mtxB->inc1 + firstcol*mtxB->inc2 ; } else if ( A2_IS_COMPLEX(mtxB) ) { mtxA->entries = mtxB->entries + 2*(firstrow*mtxB->inc1 + firstcol*mtxB->inc2) ; } mtxA->nowned = 0 ; return ; } /*--------------------------------------------------------------------*/ A2/src/instance.c010064400020550007177000000350670653501110100150750ustar00clevecompmath00000400000006/* instance.c */ #include "../A2.h" /*--------------------------------------------------------------------*/ /* -------------------------------------- return the number of rows in the array created -- 98may01, cca -------------------------------------- */ int A2_nrow ( A2 *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_nrow(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(mtx->n1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- return the number of columns in the array created -- 98may01, cca ----------------------------------------- */ int A2_ncol ( A2 *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_ncol(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(mtx->n2) ; } /*--------------------------------------------------------------------*/ /* -------------------------- return the first increment created -- 98may01, cca -------------------------- */ int A2_inc1 ( A2 *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_inc1(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(mtx->inc1) ; } /*--------------------------------------------------------------------*/ /* --------------------------- return the second increment created -- 98may01, cca --------------------------- */ int A2_inc2 ( A2 *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_inc2(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(mtx->inc2) ; } /*--------------------------------------------------------------------*/ /* ------------------------------- return a pointer to the entries created -- 98may01, cca ------------------------------- */ double * A2_entries ( A2 *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_entries(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(mtx->entries) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- return a pointer to the first entry in a row created -- 98may01, cca -------------------------------------------- */ double * A2_row ( A2 *mtx, int irow ) { double *row ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_row(%p,%d)" "\n bad input\n", mtx, irow) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in A2_row(%p,%d)" "\n bad structure, entries is NULL\n", mtx, irow) ; exit(-1) ; } if ( irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_row(%p,%d)" "\n bad input, irow = %d, n1 = %d\n", mtx, irow, irow, mtx->n1) ; exit(-1) ; } if ( A2_IS_REAL(mtx) ) { row = mtx->entries + irow*mtx->inc1 ; } else if ( A2_IS_COMPLEX(mtx) ) { row = mtx->entries + 2*irow*mtx->inc1 ; } else { fprintf(stderr, "\n fatal error in A2_row(%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX", mtx, irow, mtx->type) ; exit(-1) ; } return(row) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- return a pointer to the first entry in a column created -- 98may01, cca ----------------------------------------------- */ double * A2_column ( A2 *mtx, int jcol ) { double *col ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_column(%p,%d)" "\n bad input\n", mtx, jcol) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in A2_column(%p,%d)" "\n bad structure, entries is NULL\n", mtx, jcol) ; exit(-1) ; } if ( jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_column(%p,%d)" "\n bad input, jcol = %d, n2 = %d\n", mtx, jcol, jcol, mtx->n2) ; exit(-1) ; } if ( A2_IS_REAL(mtx) ) { col = mtx->entries + jcol*mtx->inc2 ; } else if ( A2_IS_COMPLEX(mtx) ) { col = mtx->entries + 2*jcol*mtx->inc2 ; } else { fprintf(stderr, "\n fatal error in A2_col(%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX", mtx, jcol, mtx->type) ; exit(-1) ; } return(col) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- fill *pValue with the entry in (irow, jcol) created -- 98may01, cca ------------------------------------------- */ void A2_realEntry ( A2 *mtx, int irow, int jcol, double *pValue ) { int loc ; /* --------------- check the input --------------- */ if ( mtx == NULL || pValue == NULL ) { fprintf(stderr, "\n fatal error in A2_realEntry(%p,%d,%d,%p)" "\n bad input\n", mtx, irow, jcol, pValue) ; exit(-1) ; } if ( ! A2_IS_REAL(mtx) ) { fprintf(stderr, "\n fatal error in A2_realEntry(%p,%d,%d,%p)" "\n bad type %d, must be SPOOLES_REAL\n", mtx, irow, jcol, pValue, mtx->type) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in A2_realEntry(%p,%d,%d,%p)" "\n bad structure, entries is NULL\n", mtx, irow, jcol, pValue) ; exit(-1) ; } if ( irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_realEntry(%p,%d,%d,%p)" "\n bad input, irow = %d, n1 = %d\n", mtx, irow, jcol, pValue, irow, mtx->n1) ; exit(-1) ; } if ( jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_realEntry(%p,%d,%d,%p)" "\n bad input, jcol = %d, n2 = %d\n", mtx, irow, jcol, pValue, jcol, mtx->n2) ; exit(-1) ; } loc = irow*mtx->inc1 + jcol*mtx->inc2 ; *pValue = mtx->entries[loc] ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- fill (*pReal,*pImag) with the entry in (irow, jcol) created -- 98may01, cca --------------------------------------------------- */ void A2_complexEntry ( A2 *mtx, int irow, int jcol, double *pReal, double *pImag ) { int loc ; /* --------------- check the input --------------- */ if ( mtx == NULL || pReal == NULL || pImag == NULL ) { fprintf(stderr, "\n fatal error in A2_complexEntry(%p,%d,%d,%p,%p)" "\n bad input\n", mtx, irow, jcol, pReal, pImag) ; exit(-1) ; } if ( ! A2_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in A2_complexEntry(%p,%d,%d,%p,%p)" "\n bad type %d, must be SPOOLES_COMPLEX\n", mtx, irow, jcol, pReal, pImag, mtx->type) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in A2_complexEntry(%p,%d,%d,%p,%p)" "\n bad structure, entries is NULL\n", mtx, irow, jcol, pReal, pImag) ; exit(-1) ; } if ( irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_complexEntry(%p,%d,%d,%p,%p)" "\n bad input, irow = %d, n1 = %d\n", mtx, irow, jcol, pReal, pImag, irow, mtx->n1) ; exit(-1) ; } if ( jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_complexEntry(%p,%d,%d,%p,%p)" "\n bad input, jcol = %d, n2 = %d\n", mtx, irow, jcol, pReal, pImag, jcol, mtx->n2) ; exit(-1) ; } loc = 2*(irow*mtx->inc1 + jcol*mtx->inc2) ; *pReal = mtx->entries[loc] ; *pImag = mtx->entries[loc+1] ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- set the entry in (irow, jcol) to be value created -- 98may01, cca ----------------------------------------- */ void A2_setRealEntry ( A2 *mtx, int irow, int jcol, double value ) { int loc ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_setRealEntry(%p,%d,%d,%f)" "\n bad input\n", mtx, irow, jcol, value) ; exit(-1) ; } if ( ! A2_IS_REAL(mtx) ) { fprintf(stderr, "\n fatal error in A2_setRealEntry(%p,%d,%d,%f)" "\n bad type %d, must be SPOOLES_REAL\n", mtx, irow, jcol, value, mtx->type) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in A2_setRealEntry(%p,%d,%d,%f)" "\n bad structure, entries is NULL\n", mtx, irow, jcol, value) ; exit(-1) ; } if ( irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_setRealEntry(%p,%d,%d,%f)" "\n bad input, irow = %d, n1 = %d\n", mtx, irow, jcol, value, irow, mtx->n1) ; exit(-1) ; } if ( jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_setRealEntry(%p,%d,%d,%f)" "\n bad input, jcol = %d, n2 = %d\n", mtx, irow, jcol, value, jcol, mtx->n2) ; exit(-1) ; } loc = irow*mtx->inc1 + jcol*mtx->inc2 ; mtx->entries[loc] = value ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- set the entry in (irow, jcol) to be (real,imag) created -- 98may01, cca ----------------------------------------------- */ void A2_setComplexEntry ( A2 *mtx, int irow, int jcol, double real, double imag ) { int loc ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_setComplexEntry(%p,%d,%d,%f,%f)" "\n bad input\n", mtx, irow, jcol, real, imag) ; exit(-1) ; } if ( ! A2_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in A2_setComplexEntry(%p,%d,%d,%f,%f)" "\n bad type %d, must be SPOOLES_COMPLEX\n", mtx, irow, jcol, real, imag, mtx->type) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in A2_setComplexEntry(%p,%d,%d,%f,%f)" "\n bad structure, entries is NULL\n", mtx, irow, jcol, real, imag) ; exit(-1) ; } if ( irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_setComplexEntry(%p,%d,%d,%f,%f)" "\n bad input, irow = %d, n1 = %d\n", mtx, irow, jcol, real, imag, irow, mtx->n1) ; exit(-1) ; } if ( jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_setComplexEntry(%p,%d,%d,%f,%f)" "\n bad input, jcol = %d, n2 = %d\n", mtx, irow, jcol, real, imag, jcol, mtx->n2) ; exit(-1) ; } loc = 2*(irow*mtx->inc1 + jcol*mtx->inc2) ; mtx->entries[loc] = real ; mtx->entries[loc+1] = imag ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- fill pointers to the matrix first entry in row irow and column jcol created -- 98may01, cca --------------------------------------- */ void A2_pointerToRealEntry ( A2 *mtx, int irow, int jcol, double **ppValue ) { int loc ; /* --------------- check the input --------------- */ if ( mtx == NULL || ppValue == NULL ) { fprintf(stderr, "\n fatal error in A2_pointerToRealEntry(%p,%d,%d,%p)" "\n bad input\n", mtx, irow, jcol, ppValue) ; exit(-1) ; } if ( ! A2_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in A2_pointerToRealEntry(%p,%d,%d,%p)" "\n bad type %d, must be SPOOLES_COMPLEX\n", mtx, irow, jcol, ppValue, mtx->type) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in A2_pointerToRealEntry(%p,%d,%d,%p)" "\n bad structure, entries is NULL\n", mtx, irow, jcol, ppValue) ; exit(-1) ; } if ( irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_pointerToRealEntry(%p,%d,%d,%p)" "\n bad input, irow = %d, n1 = %d\n", mtx, irow, jcol, ppValue, irow, mtx->n1) ; exit(-1) ; } if ( jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_pointerToRealEntry(%p,%d,%d,%p)" "\n bad input, jcol = %d, n2 = %d\n", mtx, irow, jcol, ppValue, jcol, mtx->n2) ; exit(-1) ; } loc = irow*mtx->inc1 + jcol*mtx->inc2 ; *ppValue = mtx->entries + loc ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- fill pointers to the matrix first entry in row irow and column jcol created -- 98may01, cca --------------------------------------- */ void A2_pointerToComplexEntry ( A2 *mtx, int irow, int jcol, double **ppReal, double **ppImag ) { int loc ; /* --------------- check the input --------------- */ if ( mtx == NULL || ppReal == NULL || ppImag == NULL ) { fprintf(stderr, "\n fatal error in A2_pointerToComplexEntry(%p,%d,%d,%p,%p)" "\n bad input\n", mtx, irow, jcol, ppReal, ppImag) ; exit(-1) ; } if ( ! A2_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in A2_pointerToComplexEntry(%p,%d,%d,%p,%p)" "\n bad type %d, must be SPOOLES_COMPLEX\n", mtx, irow, jcol, ppReal, ppImag, mtx->type) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in A2_pointerToComplexEntry(%p,%d,%d,%p,%p)" "\n bad structure, entries is NULL\n", mtx, irow, jcol, ppReal, ppImag) ; exit(-1) ; } if ( irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_pointerToComplexEntry(%p,%d,%d,%p,%p)" "\n bad input, irow = %d, n1 = %d\n", mtx, irow, jcol, ppReal, ppImag, irow, mtx->n1) ; exit(-1) ; } if ( jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_pointerToComplexEntry(%p,%d,%d,%p,%p)" "\n bad input, jcol = %d, n2 = %d\n", mtx, irow, jcol, ppReal, ppImag, jcol, mtx->n2) ; exit(-1) ; } loc = 2*(irow*mtx->inc1 + jcol*mtx->inc2) ; *ppReal = mtx->entries + loc ; *ppImag = mtx->entries + loc + 1 ; return ; } /*--------------------------------------------------------------------*/ "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX", mtx, jcol, mtx->type) ; exit(-1) ; } return(col) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- fill *pValue with the entry in (irow, jcol) created -- 98may01, cca ------------------------------------------- */ void A2_realEntry ( A2 *mtx, int irow, int jcol, A2/src/makeStaircase.c010064400020550007177000000034420653410576300160560ustar00clevecompmath00000400000006/* makeStaircase.c */ #include "../A2.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- to permute the rows so the matrix is in staircase form created -- 98may25, cca ----------------------------------------------------------------- */ void A2_makeStaircase ( A2 *mtxA ) { double imag, real, value ; int irow, jcol, ncol, nrow ; int *firstnonzero ; /* -------------- check the data -------------- */ if ( mtxA == NULL ) { fprintf(stderr, "\n fatal error in A2_staircase(%p)" "\n bad input\n", mtxA) ; exit(-1) ; } nrow = A2_nrow(mtxA) ; ncol = A2_ncol(mtxA) ; /* --------------------------------------------- fill firstnonzero[irow] with the first column that contains a nonzero entry in this row. --------------------------------------------- */ firstnonzero = IVinit(nrow, -1) ; for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { if ( A2_IS_REAL(mtxA) ) { A2_realEntry(mtxA, irow, jcol, &value) ; if ( value != 0.0 ) { break ; } } else if ( A2_IS_COMPLEX(mtxA) ) { A2_complexEntry(mtxA, irow, jcol, &real, &imag) ; if ( real != 0.0 || imag != 0.0 ) { break ; } } } firstnonzero[irow] = jcol ; } /* --------------------------------------------------- sort the rows in the order of their leading nonzero --------------------------------------------------- */ A2_sortRowsUp(mtxA, nrow, firstnonzero) ; /* ------------------------ free the working storage ------------------------ */ IVfree(firstnonzero) ; return ; } /*--------------------------------------------------------------------*/ A2/src/norms.c010064400020550007177000000472070653410576300144470ustar00clevecompmath00000400000006/* norms.c */ #include "../A2.h" #define CAUTIOUS 1 /*--------------------------------------------------------------------*/ /* ------------------------------------- return the entry of maximum magnitude created -- 98apr15, cca ------------------------------------- */ double A2_maxabs ( A2 *a ) { double maxval, val ; double *entries, *row ; int inc1, inc2, irow, jcol, kk, n1, n2 ; /* --------------- check the input --------------- */ if ( a == NULL || (n1 = a->n1) < 0 || (n2 = a->n2) < 0 || (inc1 = a->inc1) < 0 || (inc2 = a->inc2) < 0 ) { fprintf(stderr, "\n fatal error in A2_maxabs(%p)" "\n bad input\n", a ) ; exit(-1) ; } if ( ! (A2_IS_REAL(a) || A2_IS_COMPLEX(a)) ) { fprintf(stderr, "\n fatal error in A2_maxabs(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", a, a->type) ; exit(-1) ; } entries = a->entries ; maxval = 0.0 ; row = entries ; if ( A2_IS_REAL(a) ) { for ( irow = 0 ; irow < n1 ; irow++ ) { for ( jcol = 0, kk = 0 ; jcol < n2 ; jcol++, kk += inc2 ) { val = fabs(row[kk]) ; if ( maxval < val ) { maxval = val ; } } row += inc1 ; } } else if ( A2_IS_COMPLEX(a) ) { for ( irow = 0 ; irow < n1 ; irow++ ) { for ( jcol = 0, kk = 0 ; jcol < n2 ; jcol++, kk += inc2 ) { val = Zabs(row[2*kk], row[2*kk+1]) ; if ( maxval < val ) { maxval = val ; } } row += inc1 ; } } return(maxval) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- return the frobenius norm of the matrix created -- 98apr15, cca --------------------------------------- */ double A2_frobNorm ( A2 *mtx ) { double norm ; int ncol, nrow ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_frobNorm(%p) " "\n bad input\n", mtx) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_frobNorm(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, mtx->type) ; exit(-1) ; } if ( (nrow = mtx->n1) <= 0 || (ncol = mtx->n2) <= 0 ) { return(0.0) ; } norm = 0 ; if ( A2_IS_REAL(mtx) ) { if ( mtx->inc1 == 1 ) { double *col ; int inc2 = mtx->inc2, irow, jcol ; for ( jcol = 0, col = mtx->entries ; jcol < ncol ; jcol++, col += inc2 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { norm += col[irow]*col[irow] ; } } } else if ( mtx->inc2 == 1 ) { double *row ; int inc1 = mtx->inc1, irow, jcol ; for ( irow = 0, row = mtx->entries ; irow < nrow ; irow++, row += inc1 ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { norm += row[jcol]*row[jcol] ; } } } else { double *entries = mtx->entries ; int inc1 = mtx->inc1, inc2 = mtx->inc2, irow, jcol, loc ; for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { loc = irow*inc1 + jcol*inc2 ; norm += entries[loc]*entries[loc] ; } } } } else if ( A2_IS_COMPLEX(mtx) ) { if ( mtx->inc1 == 1 ) { double *col ; int inc2 = mtx->inc2, irow, jcol ; for ( jcol = 0, col = mtx->entries ; jcol < ncol ; jcol++, col += 2*inc2 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { norm += col[2*irow]*col[2*irow] + col[2*irow+1]*col[2*irow+1] ; } } } else if ( mtx->inc2 == 1 ) { double *row ; int inc1 = mtx->inc1, irow, jcol ; for ( irow = 0, row = mtx->entries ; irow < nrow ; irow++, row += 2*inc1 ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { norm += row[2*jcol]*row[2*jcol] + row[2*jcol+1]*row[2*jcol+1] ; } } } else { double *entries = mtx->entries ; int inc1 = mtx->inc1, inc2 = mtx->inc2, irow, jcol, loc ; for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { loc = irow*inc1 + jcol*inc2 ; norm += entries[2*loc]*entries[2*loc] + entries[2*loc+1]*entries[2*loc+1] ; } } } } norm = sqrt(norm) ; return(norm) ; } /*--------------------------------------------------------------------*/ /* --------------------------------- return the one-norm of the matrix created -- 98apr15, cca --------------------------------- */ double A2_oneNorm ( A2 *mtx ) { double norm ; int ncol, nrow ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_oneNorm(%p) " "\n bad input\n", mtx) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_oneNorm(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, mtx->type) ; exit(-1) ; } if ( (nrow = mtx->n1) <= 0 || (ncol = mtx->n2) <= 0 ) { return(0.0) ; } norm = 0.0 ; if ( A2_IS_REAL(mtx) ) { if ( mtx->inc1 == 1 ) { double sum ; double *col ; int inc2 = mtx->inc2, irow, jcol ; for ( jcol = 0, col = mtx->entries ; jcol < ncol ; jcol++, col += inc2 ) { sum = 0.0 ; for ( irow = 0 ; irow < nrow ; irow++ ) { sum += fabs(col[irow]) ; } if ( norm < sum ) { norm = sum ; } } } else { double sum ; double *col ; int inc1 = mtx->inc1, inc2 = mtx->inc2, irow, jcol, kk ; for ( jcol = 0, col = mtx->entries ; jcol < ncol ; jcol++, col += inc2 ) { sum = 0.0 ; for ( irow = 0, kk = 0 ; irow < nrow ; irow++, kk += inc1 ) { sum += fabs(col[kk]) ; } if ( norm < sum ) { norm = sum ; } } } } else if ( A2_IS_COMPLEX(mtx) ) { if ( mtx->inc1 == 1 ) { double sum ; double *col ; int inc2 = mtx->inc2, irow, jcol ; for ( jcol = 0, col = mtx->entries ; jcol < ncol ; jcol++, col += 2*inc2 ) { sum = 0.0 ; for ( irow = 0 ; irow < nrow ; irow++ ) { sum += Zabs(col[2*irow], col[2*irow+1]) ; } if ( norm < sum ) { norm = sum ; } } } else { double sum ; double *col ; int inc1 = mtx->inc1, inc2 = mtx->inc2, irow, jcol, kk ; for ( jcol = 0, col = mtx->entries ; jcol < ncol ; jcol++, col += 2*inc2 ) { sum = 0.0 ; for ( irow = 0, kk = 0 ; irow < nrow ; irow++, kk += inc1 ) { sum += Zabs(col[2*kk], col[2*kk+1]) ; } if ( norm < sum ) { norm = sum ; } } } } return(norm) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- return the infinity-norm of the matrix created -- 98apr15, cca -------------------------------------- */ double A2_infinityNorm ( A2 *mtx ) { double norm ; int ncol, nrow ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_infinityNorm(%p) " "\n bad input\n", mtx) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_infinityNorm(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, mtx->type) ; exit(-1) ; } if ( (nrow = mtx->n1) <= 0 || (ncol = mtx->n2) <= 0 ) { return(0.0) ; } norm = 0.0 ; if ( A2_IS_REAL(mtx) ) { if ( mtx->inc2 == 1 ) { double sum ; double *row = mtx->entries ; int inc1 = mtx->inc1, irow, jcol ; for ( irow = 0 ; irow < nrow ; irow++, row += inc1 ) { for ( jcol = 0, sum = 0.0 ; jcol < ncol ; jcol++ ) { sum += fabs(row[jcol]) ; } if ( norm < sum ) { norm = sum ; } } } else { double sum ; double *row = mtx->entries ; int inc1 = mtx->inc1, inc2 = mtx->inc2, irow, jcol, kk ; for ( irow = 0 ; irow < nrow ; irow++, row += inc1 ) { sum = 0.0 ; for ( jcol = 0, kk = 0 ; jcol < ncol ; jcol++, kk += inc2 ) { sum += fabs(row[kk]) ; } if ( norm < sum ) { norm = sum ; } } } } else if ( A2_IS_COMPLEX(mtx) ) { if ( mtx->inc2 == 1 ) { double sum ; double *row ; int inc1 = mtx->inc1, irow, jcol ; for ( irow = 0, row = mtx->entries ; irow < nrow ; irow++, row += 2*inc1 ) { sum = 0.0 ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { sum += Zabs(row[2*jcol], row[2*jcol+1]) ; } if ( norm < sum ) { norm = sum ; } } } else { double sum ; double *row ; int inc1 = mtx->inc1, inc2 = mtx->inc2, irow, jcol, kk ; for ( irow = 0, row = mtx->entries ; irow < nrow ; irow++, row += 2*inc1 ) { sum = 0.0 ; for ( jcol = 0, kk = 0 ; jcol < ncol ; jcol++, kk += inc2 ) { sum += Zabs(row[2*kk], row[2*kk+1]) ; } if ( norm < sum ) { norm = sum ; } } } } return(norm) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- return the one-norm of column jcol created -- 98apr15, cca ---------------------------------- */ double A2_oneNormOfColumn ( A2 *mtx, int jcol ) { double sum ; double *col ; int inc1, irow, kk, nrow ; /* --------------- check the input --------------- */ if ( mtx == NULL || mtx->entries == NULL || jcol < 0 || jcol > mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_oneNormOfColumn(%p,%d)" "\n bad input\n", mtx, jcol) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_oneNormOfColumn(%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, jcol, mtx->type) ; exit(-1) ; } nrow = mtx->n1 ; sum = 0.0 ; if ( A2_IS_REAL(mtx) ) { col = mtx->entries + jcol*mtx->inc2 ; if ( (inc1 = mtx->inc1) == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { sum += fabs(col[irow]) ; } } else { for ( irow = 0, kk = 0 ; irow < nrow ; irow++, kk += inc1 ) { sum += fabs(col[kk]) ; } } } else if ( A2_IS_COMPLEX(mtx) ) { col = mtx->entries + 2*jcol*mtx->inc2 ; if ( (inc1 = mtx->inc1) == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { sum += Zabs(col[2*irow], col[2*irow+1]) ; } } else { for ( irow = 0, kk = 0 ; irow < nrow ; irow++, kk += inc1 ) { sum += Zabs(col[2*kk], col[2*kk+1]) ; } } } return(sum) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- return the two-norm of column jcol created -- 98apr15, cca ---------------------------------- */ double A2_twoNormOfColumn ( A2 *mtx, int jcol ) { double sum ; double *col ; int inc1, irow, kk, nrow ; /* --------------- check the input --------------- */ if ( mtx == NULL || mtx->entries == NULL || jcol < 0 || jcol > mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_twoNormOfColumn(%p,%d)" "\n bad input\n", mtx, jcol) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_twoNormOfColumn(%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, jcol, mtx->type) ; exit(-1) ; } nrow = mtx->n1 ; sum = 0.0 ; if ( A2_IS_REAL(mtx) ) { col = mtx->entries + jcol*mtx->inc2 ; if ( (inc1 = mtx->inc1) == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { sum += col[irow]*col[irow] ; } } else { for ( irow = 0, kk = 0 ; irow < nrow ; irow++, kk += inc1 ) { sum += col[kk]*col[kk] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { col = mtx->entries + 2*jcol*mtx->inc2 ; if ( (inc1 = mtx->inc1) == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { sum += col[2*irow]*col[2*irow] + col[2*irow+1]*col[2*irow+1] ; } } else { for ( irow = 0, kk = 0 ; irow < nrow ; irow++, kk += inc1 ) { sum += col[2*kk]*col[2*kk] + col[2*kk+1]*col[2*kk+1] ; } } } sum = sqrt(sum) ; return(sum) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- return the infinity-norm of column jcol created -- 98apr15, cca --------------------------------------- */ double A2_infinityNormOfColumn ( A2 *mtx, int jcol ) { double norm, val ; double *col ; int inc1, irow, kk, nrow ; /* --------------- check the input --------------- */ if ( mtx == NULL || mtx->entries == NULL || jcol < 0 || jcol > mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_infinityNormOfColumn(%p,%d)" "\n bad input\n", mtx, jcol) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_infinityNormOfColumn(%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, jcol, mtx->type) ; exit(-1) ; } nrow = mtx->n1 ; norm = 0.0 ; if ( A2_IS_REAL(mtx) ) { col = mtx->entries + jcol*mtx->inc2 ; if ( (inc1 = mtx->inc1) == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { val = fabs(col[irow]) ; if ( norm < val ) { norm = val ; } } } else { for ( irow = 0, kk = 0 ; irow < nrow ; irow++, kk += inc1 ) { val = fabs(col[kk]) ; if ( norm < val ) { norm = val ; } } } } else if ( A2_IS_COMPLEX(mtx) ) { col = mtx->entries + 2*jcol*mtx->inc2 ; if ( (inc1 = mtx->inc1) == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { val = Zabs(col[2*irow], col[2*irow+1]) ; if ( norm < val ) { norm = val ; } } } else { for ( irow = 0, kk = 0 ; irow < nrow ; irow++, kk += inc1 ) { val = Zabs(col[2*kk], col[2*kk+1]) ; if ( norm < val ) { norm = val ; } } } } return(norm) ; } /*--------------------------------------------------------------------*/ /* ------------------------------- return the one-norm of row irow created -- 98apr15, cca ------------------------------- */ double A2_oneNormOfRow ( A2 *mtx, int irow ) { double sum ; double *row ; int inc2, jcol, kk, ncol ; /* --------------- check the input --------------- */ if ( mtx == NULL || mtx->entries == NULL || irow < 0 || irow > mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_oneNormOfRow(%p,%d)" "\n bad input\n", mtx, irow) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_oneNormOfRow(%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, irow, mtx->type) ; exit(-1) ; } ncol = mtx->n2 ; sum = 0.0 ; if ( A2_IS_REAL(mtx) ) { row = mtx->entries + irow*mtx->inc1 ; if ( (inc2 = mtx->inc2) == 1 ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { sum += fabs(row[jcol]) ; } } else { for ( jcol = 0, kk = 0 ; jcol < ncol ; jcol++, kk += inc2 ) { sum += fabs(row[kk]) ; } } } else if ( A2_IS_COMPLEX(mtx) ) { row = mtx->entries + 2*irow*mtx->inc1 ; if ( (inc2 = mtx->inc2) == 1 ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { sum += Zabs(row[2*jcol], row[2*jcol+1]) ; } } else { for ( jcol = 0, kk = 0 ; jcol < ncol ; jcol++, kk += inc2 ) { sum += Zabs(row[2*kk], row[2*kk+1]) ; } } } return(sum) ; } /*--------------------------------------------------------------------*/ /* ------------------------------- return the two-norm of row irow created -- 98apr15, cca ------------------------------- */ double A2_twoNormOfRow ( A2 *mtx, int irow ) { double sum ; double *row ; int inc2, jcol, kk, ncol ; /* --------------- check the input --------------- */ if ( mtx == NULL || mtx->entries == NULL || irow < 0 || irow > mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_twoNormOfRow(%p,%d)" "\n bad input\n", mtx, irow) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_twoNormOfRow(%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, irow, mtx->type) ; exit(-1) ; } ncol = mtx->n2 ; sum = 0.0 ; if ( A2_IS_REAL(mtx) ) { row = mtx->entries + irow*mtx->inc1 ; if ( (inc2 = mtx->inc2) == 1 ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { sum += row[jcol]*row[jcol] ; } } else { for ( jcol = 0, kk = 0 ; jcol < ncol ; jcol++, kk += inc2 ) { sum += row[kk]*row[kk] ; } } } else if ( A2_IS_COMPLEX(mtx) ) { row = mtx->entries + 2*irow*mtx->inc1 ; if ( (inc2 = mtx->inc2) == 1 ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { sum += row[2*jcol]*row[2*jcol] + row[2*jcol+1]*row[2*jcol+1] ; } } else { for ( jcol = 0, kk = 0 ; jcol < ncol ; jcol++, kk += inc2 ) { sum += row[2*kk]*row[2*kk] + row[2*kk+1]*row[2*kk+1] ; } } } sum = sqrt(sum) ; return(sum) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ return the infinity-norm of row irow created -- 98apr15, cca ------------------------------------ */ double A2_infinityNormOfRow ( A2 *mtx, int irow ) { double norm, val ; double *row ; int inc2, jcol, kk, ncol ; /* --------------- check the input --------------- */ if ( mtx == NULL || mtx->entries == NULL || irow < 0 || irow > mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_infinityNormOfRow(%p,%d)" "\n bad input\n", mtx, irow) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_infinityNormOfRow(%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, irow, mtx->type) ; exit(-1) ; } ncol = mtx->n2 ; norm = 0.0 ; if ( A2_IS_REAL(mtx) ) { row = mtx->entries + irow*mtx->inc1 ; if ( (inc2 = mtx->inc2) == 1 ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { val = fabs(row[jcol]) ; if ( norm < val ) { norm = val ; } } } else { for ( jcol = 0, kk = 0 ; jcol < ncol ; jcol++, kk += inc2 ) { val = fabs(row[kk]) ; if ( norm < val ) { norm = val ; } } } } else if ( A2_IS_COMPLEX(mtx) ) { row = mtx->entries + 2*irow*mtx->inc1 ; if ( (inc2 = mtx->inc2) == 1 ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { val = Zabs(row[2*jcol], row[2*jcol+1]) ; if ( norm < val ) { norm = val ; } } } else { for ( jcol = 0, kk = 0 ; jcol < ncol ; jcol++, kk += inc2 ) { val = Zabs(row[2*kk], row[2*kk+1]) ; if ( norm < val ) { norm = val ; } } } } return(norm) ; } /*--------------------------------------------------------------------*/ } } return(norm) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- return the one-norm of column jcol created -- 98apr15, cca ---------------------------------- */ double A2_oneNormOfColumn ( A2 *mtx, int jcol ) { double sum ; double *col ; int inc1, irow, kk, nrow ; /* A2/src/sort.c010064400020550007177000000155510653410576300142750ustar00clevecompmath00000400000006/* sort.c */ #include "../A2.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------- permute the rows of the matrix A(*,*) = A(index(*),*) this method calls A2_sortRowsUp but does not overwrite the index[] vector created -- 98apr15, cca ----------------------------------------- */ void A2_permuteRows ( A2 *mtx, int nrow, int index[] ) { int *rowids ; /* --------------- check the input --------------- */ if ( mtx == NULL || nrow < 0 || nrow > mtx->n1 || index == NULL ) { fprintf(stderr, "\n fatal error in A2_permuteRows(%p,%d,%p)" "\n bad input\n", mtx, nrow, index) ; exit(-1) ; } rowids = IVinit(nrow, -1) ; IVcopy(nrow, rowids, index) ; A2_sortRowsUp(mtx, nrow, rowids) ; IVfree(rowids) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- permute the columns of the matrix A(*,*) = A(*,index(*)) this method calls A2_sortColumnsUp but does not overwrite the index[] vector created -- 98apr15, cca ----------------------------------------- */ void A2_permuteColumns ( A2 *mtx, int ncol, int index[] ) { int *colids ; /* --------------- check the input --------------- */ if ( mtx == NULL || ncol < 0 || ncol > mtx->n2 || index == NULL ) { fprintf(stderr, "\n fatal error in A2_permuteColumns(%p,%d,%p)" "\n bad input\n", mtx, ncol, index) ; exit(-1) ; } colids = IVinit(ncol, -1) ; IVcopy(ncol, colids, index) ; A2_sortColumnsUp(mtx, ncol, colids) ; IVfree(colids) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- sort the rows of the matrix in ascending order of the rowids[] vector. on return, rowids is in asending order. return value is the number of row swaps made. created -- 98apr15, cca ---------------------------------------------- */ int A2_sortRowsUp ( A2 *mtx, int nrow, int rowids[] ) { int ii, minrow, minrowid, nswap, target ; /* --------------- check the input --------------- */ if ( mtx == NULL || mtx->n1 < nrow || nrow < 0 || rowids == NULL ) { fprintf(stderr, "\n fatal error in A2_sortRowsUp(%p,%d,%p)" "\n bad input\n", mtx, nrow, rowids) ; if ( mtx != NULL ) { A2_writeStats(mtx, stderr) ; } exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_sortRowsUp(%p,%d,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, nrow, rowids, mtx->type) ; exit(-1) ; } nswap = 0 ; if ( mtx->inc1 == 1 ) { double *dvtmp ; int jcol, ncol ; int *ivtmp ; /* --------------------------------------------------- matrix is stored by columns, so permute each column --------------------------------------------------- */ ivtmp = IVinit(nrow, -1) ; if ( A2_IS_REAL(mtx) ) { dvtmp = DVinit(nrow, 0.0) ; } else if ( A2_IS_COMPLEX(mtx) ) { dvtmp = DVinit(2*nrow, 0.0) ; } IVramp(nrow, ivtmp, 0, 1) ; IV2qsortUp(nrow, rowids, ivtmp) ; ncol = mtx->n2 ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { if ( A2_IS_REAL(mtx) ) { DVcopy(nrow, dvtmp, A2_column(mtx, jcol)) ; DVgather(nrow, A2_column(mtx, jcol), dvtmp, ivtmp) ; } else if ( A2_IS_COMPLEX(mtx) ) { ZVcopy(nrow, dvtmp, A2_column(mtx, jcol)) ; ZVgather(nrow, A2_column(mtx, jcol), dvtmp, ivtmp) ; } } IVfree(ivtmp) ; DVfree(dvtmp) ; } else { /* ---------------------------------------- use a simple insertion sort to swap rows ---------------------------------------- */ for ( target = 0 ; target < nrow ; target++ ) { minrow = target ; minrowid = rowids[target] ; for ( ii = target + 1 ; ii < nrow ; ii++ ) { if ( minrowid > rowids[ii] ) { minrow = ii ; minrowid = rowids[ii] ; } } if ( minrow != target ) { rowids[minrow] = rowids[target] ; rowids[target] = minrowid ; A2_swapRows(mtx, target, minrow) ; nswap++ ; } } } return(nswap) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- sort the columns of the matrix in ascending order of the colids[] vector. on return, colids is in asending order. return value is the number of column swaps made. created -- 98apr15, cca ------------------------------------------------- */ int A2_sortColumnsUp ( A2 *mtx, int ncol, int colids[] ) { int ii, mincol, mincolid, nswap, target ; /* --------------- check the input --------------- */ if ( mtx == NULL || mtx->n2 < ncol || ncol < 0 || colids == NULL ) { fprintf(stderr, "\n fatal error in A2_sortColumnsUp(%p,%d,%p)" "\n bad input\n", mtx, ncol, colids) ; if ( mtx != NULL ) { A2_writeStats(mtx, stderr) ; } exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_sortColumnsUp(%p,%d,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, ncol, colids, mtx->type) ; exit(-1) ; } nswap = 0 ; if ( mtx->inc2 == 1 ) { double *dvtmp ; int irow, nrow ; int *ivtmp ; /* --------------------------------------------------- matrix is stored by rows, so permute each row --------------------------------------------------- */ ivtmp = IVinit(ncol, -1) ; if ( A2_IS_REAL(mtx) ) { dvtmp = DVinit(ncol, 0.0) ; } else if ( A2_IS_COMPLEX(mtx) ) { dvtmp = DVinit(2*ncol, 0.0) ; } IVramp(ncol, ivtmp, 0, 1) ; IV2qsortUp(ncol, colids, ivtmp) ; nrow = mtx->n1 ; for ( irow = 0 ; irow < nrow ; irow++ ) { if ( A2_IS_REAL(mtx) ) { DVcopy(ncol, dvtmp, A2_row(mtx, irow)) ; DVgather(ncol, A2_row(mtx, irow), dvtmp, ivtmp) ; } else if ( A2_IS_COMPLEX(mtx) ) { ZVcopy(ncol, dvtmp, A2_row(mtx, irow)) ; ZVgather(ncol, A2_row(mtx, irow), dvtmp, ivtmp) ; } } IVfree(ivtmp) ; DVfree(dvtmp) ; } else { /* ---------------------------------------- use a simple insertion sort to swap cols ---------------------------------------- */ for ( target = 0 ; target < ncol ; target++ ) { mincol = target ; mincolid = colids[target] ; for ( ii = target + 1 ; ii < ncol ; ii++ ) { if ( mincolid > colids[ii] ) { mincol = ii ; mincolid = colids[ii] ; } } if ( mincol != target ) { colids[mincol] = colids[target] ; colids[target] = mincolid ; A2_swapColumns(mtx, target, mincol) ; nswap++ ; } } } return(nswap) ; } /*--------------------------------------------------------------------*/ A2/src/util.c010064400020550007177000001031710653410576300142570ustar00clevecompmath00000400000006/* util.c */ #include "../A2.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 98may01, cca ---------------------------------------------- */ int A2_sizeOf ( A2 *mtx ) { int nbytes ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_sizeOf(%p)" "\n bad input\n", mtx) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_sizeOf(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, mtx->type) ; exit(-1) ; } if ( A2_IS_REAL(mtx) ) { nbytes = sizeof(struct _A2) + mtx->nowned*sizeof(double) ; } else if ( A2_IS_COMPLEX(mtx) ) { nbytes = sizeof(struct _A2) + 2*mtx->nowned*sizeof(double) ; } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- shift the base of the entries and adjust dimensions mtx(0:n1-rowoff-1,0:n2-coloff-1) = mtx(rowoff:n1-1,coloff:n2-1) created -- 98may01, cca --------------------------------------------------------------- */ void A2_shiftBase ( A2 *mtx, int rowoff, int coloff ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_shiftbase(%p,%d,%d)" "\n bad input\n", mtx, rowoff, coloff) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_shiftBase(%p,%d,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, rowoff, coloff, mtx->type) ; exit(-1) ; } mtx->n1 -= rowoff ; mtx->n2 -= coloff ; if ( A2_IS_REAL(mtx) ) { mtx->entries += rowoff*mtx->inc1 + coloff*mtx->inc2 ; } else if ( A2_IS_COMPLEX(mtx) ) { mtx->entries += 2*(rowoff*mtx->inc1 + coloff*mtx->inc2) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- returns 1 if the storage is row major, otherwise returns zero. created -- 98may01, cca -------------------------------------------------------------- */ int A2_rowMajor ( A2 *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_rowMajor(%p)" "\n bad input\n", mtx) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_rowMajor(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, mtx->type) ; exit(-1) ; } if ( mtx->inc2 == 1 ) { return(1) ; } else { return(0) ; } } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- returns 1 if the storage is column major, otherwise returns zero. created -- 98may01, cca ----------------------------------------------------------------- */ int A2_columnMajor ( A2 *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_columnMajor(%p)" "\n bad input\n", mtx) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_columnMajor(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, mtx->type) ; exit(-1) ; } if ( mtx->inc1 == 1 ) { return(1) ; } else { return(0) ; } } /*--------------------------------------------------------------------*/ /* ----------------------- transpose the matrix created -- 98may01, cca ----------------------- */ void A2_transpose ( A2 *mtx ) { int inc1, n1 ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in A2_transpose(%p)" "\n bad input\n", mtx) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_transpose(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, mtx->type) ; exit(-1) ; } n1 = mtx->n1 ; mtx->n1 = mtx->n2 ; mtx->n2 = n1 ; inc1 = mtx->inc1 ; mtx->inc1 = mtx->inc2 ; mtx->inc2 = inc1 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- extract row[*] = mtx(irow,*) created -- 98may01, cca ---------------------------- */ void A2_extractRow ( A2 *mtx, double row[], int irow ) { double *entries ; int inc2, j, k, n2 ; /* --------------- check the input --------------- */ if ( mtx == NULL || row == NULL || mtx->entries == NULL || irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_extractRow(%p,%p,%d)" "\n bad input\n", mtx, row, irow) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_extractRow(%p,%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, row, irow, mtx->type) ; exit(-1) ; } k = irow * mtx->inc1 ; n2 = mtx->n2 ; inc2 = mtx->inc2 ; entries = mtx->entries ; if ( A2_IS_REAL(mtx) ) { for ( j = 0 ; j < n2 ; j++, k += inc2 ) { row[j] = entries[k] ; } } else if ( A2_IS_COMPLEX(mtx) ) { for ( j = 0 ; j < n2 ; j++, k += inc2 ) { row[2*j] = entries[2*k] ; row[2*j+1] = entries[2*k+1] ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- extract col[*] = mtx(*,jcol) created -- 98may01, cca ---------------------------- */ void A2_extractColumn ( A2 *mtx, double col[], int jcol ) { double *entries ; int i, inc1, k, n1 ; /* --------------- check the input --------------- */ if ( mtx == NULL || col == NULL || mtx->entries == NULL || jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_extractColumn(%p,%p,%d)" "\n bad input\n", mtx, col, jcol) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_extractColumn(%p,%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, col, jcol, mtx->type) ; exit(-1) ; } k = jcol * mtx->inc2 ; n1 = mtx->n1 ; inc1 = mtx->inc1 ; entries = mtx->entries ; if ( A2_IS_REAL(mtx) ) { for ( i = 0 ; i < n1 ; i++, k += inc1 ) { col[i] = entries[k] ; } } else if ( A2_IS_COMPLEX(mtx) ) { for ( i = 0 ; i < n1 ; i++, k += inc1 ) { col[2*i] = entries[2*k] ; col[2*i+1] = entries[2*k+1] ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------- set mtx(irow,*) = y[*] created -- 98may01, cca ----------------------- */ void A2_setRow ( A2 *mtx, double row[], int irow ) { double *entries ; int inc2, j, k, n2 ; /* --------------- check the input --------------- */ if ( mtx == NULL || row == NULL || irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_setRow(%p,%p,%d)" "\n bad input\n", mtx, row, irow) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_setRow(%p,%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, row, irow, mtx->type) ; exit(-1) ; } k = irow * mtx->inc1 ; n2 = mtx->n2 ; inc2 = mtx->inc2 ; entries = mtx->entries ; if ( A2_IS_REAL(mtx) ) { for ( j = 0 ; j < n2 ; j++, k += inc2 ) { entries[k] = row[j] ; } } else if ( A2_IS_COMPLEX(mtx) ) { for ( j = 0 ; j < n2 ; j++, k += inc2 ) { entries[2*k] = row[2*j] ; entries[2*k+1] = row[2*j+1] ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------- set mtx(*,jcol) = y[*] created -- 98may01, cca ----------------------- */ void A2_setColumn ( A2 *mtx, double col[], int jcol ) { double *entries ; int inc1, i, k, n1 ; /* --------------- check the input --------------- */ if ( mtx == NULL || col == NULL || jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_setColumn(%p,%p,%d)" "\n bad input\n", mtx, col, jcol) ; exit(-1) ; } if ( ! (A2_IS_REAL(mtx) || A2_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in A2_setColumn(%p,%p,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, col, jcol, mtx->type) ; exit(-1) ; } k = jcol * mtx->inc2 ; n1 = mtx->n1 ; inc1 = mtx->inc1 ; entries = mtx->entries ; if ( A2_IS_REAL(mtx) ) { for ( i = 0 ; i < n1 ; i++, k += inc1 ) { entries[k] = col[i] ; } } else if ( A2_IS_COMPLEX(mtx) ) { for ( i = 0 ; i < n1 ; i++, k += inc1 ) { entries[2*k] = col[2*i] ; entries[2*k+1] = col[2*i+1] ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- extract row[*] = mtx(irow,*) created -- 98may01, cca ---------------------------- */ void A2_extractRowDV ( A2 *mtx, DV *rowDV, int irow ) { double *entries, *row ; int inc2, j, k, n2 ; /* --------------- check the input --------------- */ if ( mtx == NULL || rowDV == NULL || mtx->entries == NULL || irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_extractRowDV(%p,%p,%d)" "\n bad input\n", mtx, rowDV, irow) ; exit(-1) ; } if ( ! A2_IS_REAL(mtx) ) { fprintf(stderr, "\n fatal error in A2_extractRowDV(%p,%p,%d)" "\n bad type %d, must be SPOOLES_REAL\n", mtx, rowDV, irow, mtx->type) ; exit(-1) ; } if ( DV_size(rowDV) < (n2 = mtx->n2) ) { DV_setSize(rowDV, n2) ; } row = DV_entries(rowDV) ; k = irow * mtx->inc1 ; inc2 = mtx->inc2 ; entries = mtx->entries ; for ( j = 0 ; j < n2 ; j++, k += inc2 ) { row[j] = entries[k] ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- extract row[*] = mtx(irow,*) created -- 98may01, cca ---------------------------- */ void A2_extractRowZV ( A2 *mtx, ZV *rowZV, int irow ) { double *entries, *row ; int inc2, j, k, n2 ; /* --------------- check the input --------------- */ if ( mtx == NULL || rowZV == NULL || mtx->entries == NULL || irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_extractRowZV(%p,%p,%d)" "\n bad input\n", mtx, rowZV, irow) ; exit(-1) ; } if ( ! A2_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in A2_extractRowZV(%p,%p,%d)" "\n bad type %d, must be SPOOLES_COMPLEX\n", mtx, rowZV, irow, mtx->type) ; exit(-1) ; } if ( ZV_size(rowZV) < (n2 = mtx->n2) ) { ZV_setSize(rowZV, n2) ; } row = ZV_entries(rowZV) ; k = irow * mtx->inc1 ; inc2 = mtx->inc2 ; entries = mtx->entries ; for ( j = 0 ; j < n2 ; j++, k += inc2 ) { row[2*j] = entries[2*k] ; row[2*j+1] = entries[2*k+1] ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- extract col[*] = mtx(*,jcol) created -- 98may01, cca ---------------------------- */ void A2_extractColumnDV ( A2 *mtx, DV *colDV, int jcol ) { double *entries, *col ; int i, inc1, k, n1 ; /* --------------- check the input --------------- */ if ( mtx == NULL || colDV == NULL || mtx->entries == NULL || jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_extractColumnDV(%p,%p,%d)" "\n bad input\n", mtx, colDV, jcol) ; exit(-1) ; } if ( ! A2_IS_REAL(mtx) ) { fprintf(stderr, "\n fatal error in A2_extractColumnDV(%p,%p,%d)" "\n bad type %d, must be SPOOLES_REAL\n", mtx, colDV, jcol, mtx->type) ; exit(-1) ; } if ( DV_size(colDV) < (n1 = mtx->n1) ) { DV_setSize(colDV, n1) ; } col = DV_entries(colDV) ; k = jcol * mtx->inc2 ; inc1 = mtx->inc1 ; entries = mtx->entries ; for ( i = 0 ; i < n1 ; i++, k += inc1 ) { col[i] = entries[k] ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- extract col[*] = mtx(*,jcol) created -- 98may01, cca ---------------------------- */ void A2_extractColumnZV ( A2 *mtx, ZV *colZV, int jcol ) { double *entries, *col ; int i, inc1, k, n1 ; /* --------------- check the input --------------- */ if ( mtx == NULL || colZV == NULL || mtx->entries == NULL || jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_extractColumnZV(%p,%p,%d)" "\n bad input\n", mtx, colZV, jcol) ; exit(-1) ; } if ( ! A2_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in A2_extractColumnZV(%p,%p,%d)" "\n bad type %d, must be SPOOLES_COMPLEX\n", mtx, colZV, jcol, mtx->type) ; exit(-1) ; } if ( ZV_size(colZV) < (n1 = mtx->n1) ) { ZV_setSize(colZV, n1) ; } col = ZV_entries(colZV) ; k = jcol * mtx->inc2 ; inc1 = mtx->inc1 ; entries = mtx->entries ; for ( i = 0 ; i < n1 ; i++, k += inc1 ) { col[2*i] = entries[2*k] ; col[2*i+1] = entries[2*k+1] ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------- set mtx(irow,*) = y[*] created -- 98may01, cca ----------------------- */ void A2_setRowDV ( A2 *mtx, DV *rowDV, int irow ) { double *entries, *row ; int inc2, j, k, n2 ; /* --------------- check the input --------------- */ if ( mtx == NULL || rowDV == NULL || DV_size(rowDV) != (n2 = mtx->n2) || irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_setRowDV(%p,%p,%d)" "\n bad input\n", mtx, rowDV, irow) ; exit(-1) ; } if ( ! A2_IS_REAL(mtx) ) { fprintf(stderr, "\n fatal error in A2_setRowDV(%p,%p,%d)" "\n bad type %d, must be SPOOLES_REAL\n", mtx, rowDV, irow, mtx->type) ; exit(-1) ; } k = irow * mtx->inc1 ; inc2 = mtx->inc2 ; entries = mtx->entries ; row = DV_entries(rowDV) ; for ( j = 0 ; j < n2 ; j++, k += inc2 ) { entries[k] = row[j] ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------- set mtx(irow,*) = y[*] created -- 98may01, cca ----------------------- */ void A2_setRowZV ( A2 *mtx, ZV *rowZV, int irow ) { double *entries, *row ; int inc2, j, k, n2 ; /* --------------- check the input --------------- */ if ( mtx == NULL || rowZV == NULL || ZV_size(rowZV) != (n2 = mtx->n2) || irow < 0 || irow >= mtx->n1 ) { fprintf(stderr, "\n fatal error in A2_setRowZV(%p,%p,%d)" "\n bad input\n", mtx, rowZV, irow) ; exit(-1) ; } if ( ! A2_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in A2_setRowZV(%p,%p,%d)" "\n bad type %d, must be SPOOLES_COMPLEX\n", mtx, rowZV, irow, mtx->type) ; exit(-1) ; } k = irow * mtx->inc1 ; inc2 = mtx->inc2 ; entries = mtx->entries ; row = ZV_entries(rowZV) ; for ( j = 0 ; j < n2 ; j++, k += inc2 ) { entries[2*k] = row[2*j] ; entries[2*k+1] = row[2*j+1] ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------- set mtx(*,jcol) = y[*] created -- 98may01, cca ----------------------- */ void A2_setColumnDV ( A2 *mtx, DV *colDV, int jcol ) { double *col, *entries ; int inc1, i, k, n1 ; /* --------------- check the input --------------- */ if ( mtx == NULL || colDV == NULL || DV_size(colDV) != (n1 = mtx->n1) || jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_setColumnDV(%p,%p,%d)" "\n bad input\n", mtx, colDV, jcol) ; exit(-1) ; } if ( ! A2_IS_REAL(mtx) ) { fprintf(stderr, "\n fatal error in A2_setColumnDV(%p,%p,%d)" "\n bad type %d, must be SPOOLES_REAL\n", mtx, colDV, jcol, mtx->type) ; exit(-1) ; } k = jcol * mtx->inc2 ; inc1 = mtx->inc1 ; entries = mtx->entries ; col = DV_entries(colDV) ; for ( i = 0 ; i < n1 ; i++, k += inc1 ) { entries[k] = col[i] ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------- set mtx(*,jcol) = y[*] created -- 98may01, cca ----------------------- */ void A2_setColumnZV ( A2 *mtx, ZV *colZV, int jcol ) { double *col, *entries ; int inc1, i, k, n1 ; /* --------------- check the input --------------- */ if ( mtx == NULL || colZV == NULL || ZV_size(colZV) != (n1 = mtx->n1) || jcol < 0 || jcol >= mtx->n2 ) { fprintf(stderr, "\n fatal error in A2_setColumnZV(%p,%p,%d)" "\n bad input\n", mtx, colZV, jcol) ; exit(-1) ; } if ( ! A2_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in A2_setColumnZV(%p,%p,%d)" "\n bad type %d, must be SPOOLES_COMPLEX\n", mtx, colZV, jcol, mtx->type) ; exit(-1) ; } k = jcol * mtx->inc2 ; inc1 = mtx->inc1 ; entries = mtx->entries ; col = ZV_entries(colZV) ; for ( i = 0 ; i < n1 ; i++, k += inc1 ) { entries[2*k] = col[2*i] ; entries[2*k+1] = col[2*i+1] ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- fill the matrix with uniform random numbers in [lower, upper] created -- 98may01, cca ------------------------------------------------------------- */ void A2_fillRandomUniform ( A2 *a, double lower, double upper, int seed ) { double *entries ; int i, inc1, inc2, j, loc, n1, n2 ; Drand drand ; /* --------------- check the input --------------- */ if ( a == NULL || (n1 = a->n1) <= 0 || (n2 = a->n2) <= 0 || (inc1 = a->inc1) <= 0 || (inc2 = a->inc2) <= 0 || (entries = a->entries) == NULL ) { fprintf(stderr, "\n fatal error in A2_fillRandomUniform(%p,%f,%f,%d)" "\n bad input\n", a, lower, upper, seed) ; exit(-1) ; } if ( ! (A2_IS_REAL(a) || A2_IS_COMPLEX(a)) ) { fprintf(stderr, "\n fatal error in A2_fillRandomUniform(%p,%f,%f,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", a, lower, upper, seed, a->type) ; exit(-1) ; } /* ---------------- fill the entries ---------------- */ Drand_setDefaultFields(&drand) ; Drand_init(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, lower, upper) ; for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { loc = i*inc1 + j*inc2 ; if ( A2_IS_REAL(a) ) { entries[loc] = Drand_value(&drand) ; } else if ( A2_IS_COMPLEX(a) ) { entries[2*loc] = Drand_value(&drand) ; entries[2*loc+1] = Drand_value(&drand) ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- fill the matrix with normal(0,1) random numbers created -- 98may01, cca ----------------------------------------------- */ void A2_fillRandomNormal ( A2 *a, double mean, double variance, int seed ) { double *entries ; int i, inc1, inc2, j, loc, n1, n2 ; Drand drand ; /* --------------- check the input --------------- */ if ( a == NULL || (n1 = a->n1) <= 0 || (n2 = a->n2) <= 0 || (inc1 = a->inc1) <= 0 || (inc2 = a->inc2) <= 0 || (entries = a->entries) == NULL ) { fprintf(stderr, "\n fatal error in A2_fillRandomNormal(%p,%d)" "\n bad input\n", a, seed) ; exit(-1) ; } if ( ! (A2_IS_REAL(a) || A2_IS_COMPLEX(a)) ) { fprintf(stderr, "\n fatal error in A2_fillRandomNormal(%p,%f,%f,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", a, mean, variance, seed, a->type) ; exit(-1) ; } /* ---------------- fill the entries ---------------- */ Drand_setDefaultFields(&drand) ; Drand_init(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, mean, variance) ; for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { loc = i*inc1 + j*inc2 ; if ( A2_IS_REAL(a) ) { entries[loc] = Drand_value(&drand) ; } else if ( A2_IS_COMPLEX(a) ) { entries[2*loc] = Drand_value(&drand) ; entries[2*loc+1] = Drand_value(&drand) ; } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- fill the matrix with the identity matrix created -- 98may01, cca ---------------------------------------- */ void A2_fillWithIdentity ( A2 *a ) { double *entries ; int ii, inc, inc1, inc2, j, n ; /* --------------- check the input --------------- */ if ( a == NULL || (n = a->n1) <= 0 || n != a->n2 || (inc1 = a->inc1) <= 0 || (inc2 = a->inc2) <= 0 || (inc1 != 1 && inc2 != 1) || (entries = a->entries) == NULL ) { fprintf(stderr, "\n fatal error in A2_fillWithIdentity(%p)" "\n bad input\n", a) ; exit(-1) ; } if ( ! (A2_IS_REAL(a) || A2_IS_COMPLEX(a)) ) { fprintf(stderr, "\n fatal error in A2_fillWithIdentity(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", a, a->type) ; exit(-1) ; } inc = (inc1 == 1) ? inc2 : inc1 ; A2_zero(a) ; for ( j = 0, ii = 0 ; j < n ; j++, ii += inc + 1 ) { if ( A2_IS_REAL(a) ) { entries[ii] = 1.0 ; } else if ( A2_IS_COMPLEX(a) ) { entries[2*ii] = 1.0 ; } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------- fill the matrix with zeros created -- 98may01, cca -------------------------- */ void A2_zero ( A2 *a ) { double *entries ; int i, inc1, inc2, j, loc, n1, n2 ; /* --------------- check the input --------------- */ if ( a == NULL || (n1 = a->n1) <= 0 || (n2 = a->n2) <= 0 || (inc1 = a->inc1) <= 0 || (inc2 = a->inc2) <= 0 || (entries = a->entries) == NULL ) { fprintf(stderr, "\n fatal error in A2_zero(%p)" "\n bad input\n", a) ; exit(-1) ; } if ( ! (A2_IS_REAL(a) || A2_IS_COMPLEX(a)) ) { fprintf(stderr, "\n fatal error in A2_zero(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", a, a->type) ; exit(-1) ; } for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { loc =i*inc1 + j*inc2 ; if ( A2_IS_REAL(a) ) { entries[loc] = 0.0 ; } else if ( A2_IS_COMPLEX(a) ) { entries[2*loc] = 0.0 ; entries[2*loc+1] = 0.0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- copy one matrix into another A := B created -- 98may01, cca ---------------------------- */ void A2_copy ( A2 *A, A2 *B ) { double *entA, *entB ; int inc1A, inc1B, inc2A, inc2B, irow, jcol, locA, locB, ncol, ncolA, ncolB, nrow, nrowA, nrowB ; /* --------------- check the input --------------- */ if ( A == NULL || (nrowA = A->n1) < 0 || (ncolA = A->n2) < 0 || (inc1A = A->inc1) <= 0 || (inc2A = A->inc2) <= 0 || (entA = A->entries) == NULL || B == NULL || (nrowB = B->n1) < 0 || (ncolB = B->n2) < 0 || (inc1B = B->inc1) <= 0 || (inc2B = B->inc2) <= 0 || (entB = B->entries) == NULL ) { fprintf(stderr, "\n fatal error in A2_copy(%p,%p)" "\n bad input\n", A, B) ; if ( A != NULL ) { fprintf(stderr, "\n\n first A2 object") ; A2_writeStats(A, stderr) ; } if ( B != NULL ) { fprintf(stderr, "\n\n second A2 object") ; A2_writeStats(B, stderr) ; } exit(-1) ; } if ( ! (A2_IS_REAL(A) || A2_IS_COMPLEX(A)) ) { fprintf(stderr, "\n fatal error in A2_copy(%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", A, B, A->type) ; exit(-1) ; } if ( ! (A2_IS_REAL(B) || A2_IS_COMPLEX(B)) ) { fprintf(stderr, "\n fatal error in A2_copy(%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", A, B, B->type) ; exit(-1) ; } if ( A->type != B->type ) { fprintf(stderr, "\n fatal error in A2_copy(%p,%p)" "\n A's type %d, B's type = %d, must be the same\n", A, B, A->type, B->type) ; exit(-1) ; } nrow = (nrowA <= nrowB) ? nrowA : nrowB ; ncol = (ncolA <= ncolB) ? ncolA : ncolB ; if ( A2_IS_REAL(A) ) { if ( inc1A == 1 && inc1B == 1 ) { double *colA = entA, *colB = entB ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { for ( irow = 0 ; irow < nrow ; irow++ ) { colA[irow] = colB[irow] ; } colA += inc2A ; colB += inc2B ; } } else if ( inc2A == 1 && inc2B == 1 ) { double *rowA = entA, *rowB = entB ; for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { rowA[jcol] = rowB[jcol] ; } rowA += 2*inc1A ; } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { locA = irow*inc1A + jcol*inc2A ; locB = irow*inc1B + jcol*inc2B ; entA[locA] = entB[locB] ; } } } } else if ( A2_IS_COMPLEX(A) ) { if ( inc1A == 1 && inc1B == 1 ) { double *colA = entA, *colB = entB ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { for ( irow = 0 ; irow < nrow ; irow++ ) { colA[2*irow] = colB[2*irow] ; colA[2*irow+1] = colB[2*irow+1] ; } colA += 2*inc2A ; colB += 2*inc2B ; } } else if ( inc2A == 1 && inc2B == 1 ) { double *rowA = entA, *rowB = entB ; for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { rowA[2*jcol] = rowB[2*jcol] ; rowA[2*jcol+1] = rowB[2*jcol+1] ; } rowA += 2*inc1A ; rowB += 2*inc1B ; } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { locA = irow*inc1A + jcol*inc2A ; locB = irow*inc1B + jcol*inc2B ; entA[2*locA] = entB[2*locB] ; entA[2*locA+1] = entB[2*locB+1] ; } } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- subtract one matrix from another A := A - B created -- 98may01, cca ---------------------------- */ void A2_sub ( A2 *A, A2 *B ) { double *entA, *entB ; int inc1A, inc1B, inc2A, inc2B, irow, jcol, locA, locB, ncol, ncolA, ncolB, nrow, nrowA, nrowB ; /* --------------- check the input --------------- */ if ( A == NULL || B == NULL || (nrowA = A->n1) <= 0 || (ncolA = A->n2) <= 0 || (inc1A = A->inc1) <= 0 || (inc2A = A->inc2) <= 0 || (nrowB = B->n1) <= 0 || (ncolB = B->n2) <= 0 || (inc1B = B->inc1) <= 0 || (inc2B = B->inc2) <= 0 || (entA = A->entries) == NULL || (entB = B->entries) == NULL ) { fprintf(stderr, "\n fatal error in A2_sub(%p,%p)" "\n bad input\n", A, B) ; if ( A != NULL ) { fprintf(stderr, "\n\n first A2 object") ; A2_writeStats(A, stderr) ; } if ( B != NULL ) { fprintf(stderr, "\n\n second A2 object") ; A2_writeStats(B, stderr) ; } exit(-1) ; } if ( ! (A2_IS_REAL(A) || A2_IS_COMPLEX(A)) ) { fprintf(stderr, "\n fatal error in A2_sub(%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", A, B, A->type) ; exit(-1) ; } if ( ! (A2_IS_REAL(B) || A2_IS_COMPLEX(B)) ) { fprintf(stderr, "\n fatal error in A2_sub(%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", A, B, B->type) ; exit(-1) ; } if ( A->type != B->type ) { fprintf(stderr, "\n fatal error in A2_sub(%p,%p)" "\n A's type %d, B's type = %d, must be the same\n", A, B, A->type, B->type) ; exit(-1) ; } /* fprintf(stdout, "\n debug : A") ; A2_writeForHumanEye(A, stdout) ; fprintf(stdout, "\n debug : B") ; A2_writeForHumanEye(B, stdout) ; */ nrow = (nrowA <= nrowB) ? nrowA : nrowB ; ncol = (ncolA <= ncolB) ? ncolA : ncolB ; if ( A2_IS_REAL(A) ) { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { locA = irow*inc1A + jcol*inc2A ; locB = irow*inc1B + jcol*inc2B ; entA[locA] -= entB[locB] ; } } } else if ( A2_IS_COMPLEX(A) ) { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { locA = irow*inc1A + jcol*inc2A ; locB = irow*inc1B + jcol*inc2B ; entA[2*locA] -= entB[2*locB] ; entA[2*locA+1] -= entB[2*locB+1] ; } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------- swap two rows of the matrix created -- 98may01, cca --------------------------- */ void A2_swapRows ( A2 *a, int irow1, int irow2 ) { double temp ; double *row1, *row2 ; int inc2, j, k, n2 ; /* ----------- check input ----------- */ if ( a == NULL || irow1 < 0 || irow1 >= a->n1 || irow2 < 0 || irow2 >= a->n1 ) { fprintf(stderr, "\n fatal error in A2_swapRows(%p,%d,%d)" "\n bad input\n", a, irow1, irow2) ; exit(-1) ; } if ( a->n1 <= 0 || a->inc1 <= 0 || (n2 = a->n2) <= 0 || (inc2 = a->inc2) <= 0 || a->entries == NULL ) { fprintf(stderr, "\n fatal error in A2_swapRows(%p,%d,%d)" "\n bad structure\n", a, irow1, irow2) ; exit(-1) ; } if ( ! (A2_IS_REAL(a) || A2_IS_COMPLEX(a)) ) { fprintf(stderr, "\n fatal error in A2_swapRows(%p,%d,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", a, irow1, irow2, a->type) ; exit(-1) ; } if ( irow1 == irow2 ) { return ; } if ( A2_IS_REAL(a) ) { row1 = a->entries + irow1*a->inc1 ; row2 = a->entries + irow2*a->inc1 ; if ( inc2 == 1 ) { for ( j = 0 ; j < n2 ; j++ ) { temp = row1[j] ; row1[j] = row2[j] ; row2[j] = temp ; } } else { for ( j = 0, k = 0 ; j < n2 ; j++, k += inc2 ) { temp = row1[k] ; row1[k] = row2[k] ; row2[k] = temp ; } } } else if ( A2_IS_COMPLEX(a) ) { row1 = a->entries + 2*irow1*a->inc1 ; row2 = a->entries + 2*irow2*a->inc1 ; if ( inc2 == 1 ) { for ( j = 0 ; j < n2 ; j++ ) { temp = row1[2*j] ; row1[2*j] = row2[2*j] ; row2[2*j] = temp ; temp = row1[2*j+1] ; row1[2*j+1] = row2[2*j+1] ; row2[2*j+1] = temp ; } } else { for ( j = 0, k = 0 ; j < n2 ; j++, k += inc2 ) { temp = row1[2*k] ; row1[2*k] = row2[2*k] ; row2[2*k] = temp ; temp = row1[2*k+1] ; row1[2*k+1] = row2[2*k+1] ; row2[2*k+1] = temp ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------ swap two columns of the matrix created -- 98may01, cca ------------------------------ */ void A2_swapColumns ( A2 *a, int jcol1, int jcol2 ) { double temp ; double *col1, *col2 ; int i, inc1, k, n1 ; /* ----------- check input ----------- */ if ( a == NULL || jcol1 < 0 || jcol1 >= a->n2 || jcol2 < 0 || jcol2 >= a->n2 ) { fprintf(stderr, "\n fatal error in A2_swapColumns(%p,%d,%d)" "\n bad input\n", a, jcol1, jcol2) ; exit(-1) ; } if ( (n1 = a->n1) <= 0 || (inc1 = a->inc1) <= 0 || a->n2 <= 0 || a->inc2 <= 0 || a->entries == NULL ) { fprintf(stderr, "\n fatal error in A2_swapColumns(%p,%d,%d)" "\n bad structure\n", a, jcol1, jcol2) ; exit(-1) ; } if ( ! (A2_IS_REAL(a) || A2_IS_COMPLEX(a)) ) { fprintf(stderr, "\n fatal error in A2_swapColumns(%p,%d,%d)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", a, jcol1, jcol2, a->type) ; exit(-1) ; } if ( jcol1 == jcol2 ) { return ; } if ( A2_IS_REAL(a) ) { col1 = a->entries + jcol1*a->inc2 ; col2 = a->entries + jcol2*a->inc2 ; if ( inc1 == 1 ) { for ( i = 0 ; i < n1 ; i++ ) { temp = col1[i] ; col1[i] = col2[i] ; col2[i] = temp ; } } else { for ( i = 0, k = 0 ; i < n1 ; i++, k += inc1 ) { temp = col1[k] ; col1[k] = col2[k] ; col2[k] = temp ; } } } else if ( A2_IS_COMPLEX(a) ) { col1 = a->entries + 2*jcol1*a->inc2 ; col2 = a->entries + 2*jcol2*a->inc2 ; if ( inc1 == 1 ) { for ( i = 0 ; i < n1 ; i++ ) { temp = col1[2*i] ; col1[2*i] = col2[2*i] ; col2[2*i] = temp ; temp = col1[2*i+1] ; col1[2*i+1] = col2[2*i+1] ; col2[2*i+1] = temp ; } } else { for ( i = 0, k = 0 ; i < n1 ; i++, k += inc1 ) { temp = col1[2*k] ; col1[2*k] = col2[2*k] ; col2[2*k] = temp ; temp = col1[2*k+1] ; col1[2*k+1] = col2[2*k+1] ; col2[2*k+1] = temp ; } } } return ; } /*--------------------------------------------------------------------*/ c1) <= 0 || (inc2B = B->inc2) <= 0 || (entB = B->entries) == NULL ) { fprintf(stderr, "\n fatal error in A2_copy(%p,%p)" "\n bad input\n", A, B) ; if ( A != NULL ) { fprintf(stderr, "\n\n first A2 object") ; A2_writeStats(A, stderr) ; } if ( B != NULL ) { fprintf(stderr, "\n\n second A2 object") ; A2_writeStats(B, stderr) ; } exiA2/drivers/do_QR010075500020550007177000000004710664345132100147510ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = stdout set type = 2 set nrow = 10 set ncol = 5 set inc1 = $ncol set inc1 = 1 set inc2 = 1 set inc2 = $nrow set seed = 1 set ncolX = $ncol set ncolX = 6 set type = 2 testQR $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed $ncolX A2/drivers/do_norms010075500020550007177000000004000653503537700155660ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = stdout set type = 2 set nrow = 10 set ncol = 20 set inc1 = $ncol set inc1 = 1 set inc2 = 1 set inc2 = $nrow set seed = 1 test_norms $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed A2/drivers/makefile010064400020550007177000000006330665314230700155210ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- DRIVERS = test_norms testQR LIBS = ../../spooles.a -lm drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testQR : testQR.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} test_norms : test_norms.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIF_GCC_VERSION} ${LIBS} A2/drivers/testQR.c010064400020550007177000000147130664345076500154240ustar00clevecompmath00000400000006/* testQR.c */ #include "../A2.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------------------------------- test the A2_QRreduce(), A2_QRcomputeQ() and A2_applyQT() methods created -- 98dec10, cca ---------------------------------------------------------------- */ { A2 *A, *Q, *R, *X, *Y ; double nops, t1, t2 ; DV workDV ; FILE *msgFile ; int inc1, inc2, irow, jcol, msglvl, nrow, ncol, ncolX, seed, type ; if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow ncol inc1 inc2 seed ncolX" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- entries type" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- # of rows in A" "\n ncol -- # of columns in A" "\n inc1 -- row increment, must be ncol" "\n inc2 -- column increment, must be 1" "\n seed -- random number seed" "\n ncolX -- # of columns in X" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; nrow = atoi(argv[4]) ; ncol = atoi(argv[5]) ; inc1 = atoi(argv[6]) ; inc2 = atoi(argv[7]) ; if ( type < 1 || type > 2 || nrow < 0 || ncol < 0 || inc1 < 1 || inc2 < 1 ) { fprintf(stderr, "\n fatal error, type %d, nrow %d, ncol %d, inc1 %d, inc2 %d", type, nrow, ncol, inc1, inc2) ; exit(-1) ; } seed = atoi(argv[8]) ; ncolX = atoi(argv[9]) ; fprintf(msgFile, "\n\n %% %s :" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% nrow = %d" "\n %% ncol = %d" "\n %% inc1 = %d" "\n %% inc2 = %d" "\n %% seed = %d" "\n %% ncolX = %d" "\n", argv[0], msglvl, argv[2], type, nrow, ncol, inc1, inc2, seed, ncolX) ; if ( inc1 != 1 && inc2 != 1 ) { fprintf(stderr, "\n inc1 = %d, inc2 = %d\n", inc1, inc2) ; exit(-1) ; } /* ----------------------------- initialize the matrix objects ----------------------------- */ MARKTIME(t1) ; A = A2_new() ; A2_init(A, type, nrow, ncol, inc1, inc2, NULL) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; MARKTIME(t1) ; A2_fillRandomUniform(A, -1, 1, seed++) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to fill matrix with random numbers", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n matrix A") ; A2_writeForHumanEye(A, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n %% matrix A") ; A2_writeForMatlab(A, "A", msgFile) ; } /* -------------------- compute the R matrix -------------------- */ DV_setDefaultFields(&workDV) ; /* ------------------ use rank-1 updates ------------------ */ MARKTIME(t1) ; nops = A2_QRreduce(A, &workDV, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : rank-1: %.3f to compute R, %.0f ops, %.3f mflops", t2 - t1, nops, 1.e-6*nops/(t2-t1)) ; /* ---------------------- write out the R matrix ---------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n %% matrix R") ; R = A2_new() ; A2_subA2(R, A, 0, ncol - 1, 0, ncol - 1) ; A2_writeForMatlab(R, "R", msgFile) ; fprintf(msgFile, "\n for jj = 1:%d" "\n for ii = jj+1:%d" "\n R(ii,jj) = 0.0 ;" "\n end" "\n end", ncol, ncol) ; fflush(msgFile) ; A2_free(R) ; } /* ------------------------------- check the error |A^H*A - R^H*R| ------------------------------- */ if ( msglvl > 1 ) { if ( type == SPOOLES_REAL ) { fprintf(msgFile, "\n emtx1 = transpose(A)*A - transpose(R)*R ;" "\n error = max(max(abs(emtx1))) " ) ; } else if ( type == SPOOLES_COMPLEX ) { fprintf(msgFile, "\n emtx1 = ctranspose(A)*A - ctranspose(R)*R ;" "\n error = max(max(abs(emtx1))) " ) ; } DV_clearData(&workDV) ; } if ( inc1 == 1 ) { /* --------- compute Q --------- */ Q = A2_new() ; A2_init(Q, type, nrow, ncol, inc1, inc2, NULL) ; A2_computeQ(Q, A, &workDV, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %% matrix Q") ; A2_writeForMatlab(Q, "Q", msgFile) ; fprintf(msgFile, "\n emtx2 = A - Q * R ;" "\n error = max(max(abs(emtx2))) " ) ; } A2_free(Q) ; /* --------------------------------------------------- create a matrix X with the same number of rows as A --------------------------------------------------- */ MARKTIME(t1) ; X = A2_new() ; A2_init(X, type, nrow, ncolX, inc1, inc2, NULL) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; MARKTIME(t1) ; A2_fillRandomUniform(X, -1, 1, seed++) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to fill matrix with random numbers", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n matrix X") ; A2_writeForHumanEye(X, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n %% matrix X") ; A2_writeForMatlab(X, "X", msgFile) ; } /* ------------------- compute Y = Q^T * X ------------------- */ MARKTIME(t1) ; Y = A2_new() ; A2_init(Y, type, nrow, ncolX, inc1, inc2, NULL) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; A2_applyQT(Y, A, X, &workDV, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %% matrix Y") ; A2_writeForMatlab(Y, "Y", msgFile) ; fprintf(msgFile, "\n [Qexact,Rexact] = qr(A) ;") ; if ( A2_IS_REAL(A) ) { fprintf(msgFile, "\n emtx3 = Y - transpose(Qexact) * X ;") ; } else { fprintf(msgFile, "\n emtx3 = Y - ctranspose(Qexact) * X ;") ; } fprintf(msgFile, "\n error = max(max(abs(emtx3))) " ) ; } A2_free(Q) ; A2_free(X) ; A2_free(Y) ; } /* ------------------------ free the working storage ------------------------ */ DV_clearData(&workDV) ; A2_free(A) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ A2/drivers/test_norms.c010064400020550007177000000111360653503473300163640ustar00clevecompmath00000400000006/* test_norms.c */ #include "../A2.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------- simple test program created -- 98apr15, cca ----------------------- */ { A2 *A ; double t1, t2, value ; FILE *msgFile ; int inc1, inc2, irow, jcol, msglvl, nrow, ncol, seed, type ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow ncol inc1 inc2 seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- entries type" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- # of rows " "\n ncol -- # of columns " "\n inc1 -- row increment " "\n inc2 -- column increment " "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; nrow = atoi(argv[4]) ; ncol = atoi(argv[5]) ; inc1 = atoi(argv[6]) ; inc2 = atoi(argv[7]) ; if ( type < 1 || type > 2 || nrow < 0 || ncol < 0 || inc1 < 1 || inc2 < 1 ) { fprintf(stderr, "\n fatal error, type %d, nrow %d, ncol %d, inc1 %d, inc2 %d", type, nrow, ncol, inc1, inc2) ; exit(-1) ; } seed = atoi(argv[7]) ; fprintf(msgFile, "\n\n %% %s :" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% nrow = %d" "\n %% ncol = %d" "\n %% inc1 = %d" "\n %% inc2 = %d" "\n %% seed = %d" "\n", argv[0], msglvl, argv[2], type, nrow, ncol, inc1, inc2, seed) ; /* ----------------------------- initialize the matrix objects ----------------------------- */ MARKTIME(t1) ; A = A2_new() ; A2_init(A, type, nrow, ncol, inc1, inc2, NULL) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; MARKTIME(t1) ; A2_fillRandomUniform(A, -1, 1, seed) ; seed++ ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to fill matrix with random numbers", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n matrix A") ; A2_writeForHumanEye(A, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n %% matrix A") ; A2_writeForMatlab(A, "A", msgFile) ; } /* ------------- get the norms ------------- */ value = A2_maxabs(A) ; fprintf(msgFile, "\n error_maxabs = abs(%20.12e - max(max(abs(A))))", value) ; value = A2_frobNorm(A) ; fprintf(msgFile, "\n error_frob = abs(%20.12e - norm(A, 'fro'))", value) ; value = A2_oneNorm(A) ; fprintf(msgFile, "\n error_one = abs(%20.12e - norm(A, 1))", value) ; value = A2_infinityNorm(A) ; fprintf(msgFile, "\n error_inf = abs(%20.12e - norm(A, inf))", value) ; for ( irow = 0 ; irow < nrow ; irow++ ) { value = A2_infinityNormOfRow(A, irow) ; fprintf(msgFile, "\n error_infNormsOfRows(%d) = abs(%20.12e - norm(A(%d,:), inf)) ;", irow+1, value, irow+1) ; value = A2_oneNormOfRow(A, irow) ; fprintf(msgFile, "\n error_oneNormsOfRows(%d) = abs(%20.12e - norm(A(%d,:), 1)) ;", irow+1, value, irow+1) ; value = A2_twoNormOfRow(A, irow) ; fprintf(msgFile, "\n error_twoNormsOfRows(%d) = abs(%20.12e - norm(A(%d,:), 2)) ;", irow+1, value, irow+1) ; } for ( jcol = 0 ; jcol < ncol ; jcol++ ) { value = A2_infinityNormOfColumn(A, jcol) ; fprintf(msgFile, "\n error_infNormsOfColumns(%d) = abs(%20.12e - norm(A(:,%d), inf)) ;", jcol+1, value, jcol+1) ; value = A2_oneNormOfColumn(A, jcol) ; fprintf(msgFile, "\n error_oneNormsOfColumns(%d) = abs(%20.12e - norm(A(:,%d), 1)) ;", jcol+1, value, jcol+1) ; value = A2_twoNormOfColumn(A, jcol) ; fprintf(msgFile, "\n error_twoNormsOfColumns(%d) = abs(%20.12e - norm(A(:,%d), 2)) ;", jcol+1, value, jcol+1) ; } fprintf(msgFile, "\n error_in_row_norms = [ max(error_infNormsOfRows) " "\n max(error_oneNormsOfRows) " "\n max(error_twoNormsOfRows) ]" "\n error_in_column_norms = [ max(error_infNormsOfColumns) " "\n max(error_oneNormsOfColumns) " "\n max(error_twoNormsOfColumns) ]") ; fprintf(msgFile, "\n") ; /* ------------------------ free the working storage ------------------------ */ A2_free(A) ; return(1) ; } /*--------------------------------------------------------------------*/ A2/doc/004275500020550007177000000000000665023214000131035ustar00clevecompmath00000400000006A2/doc/main.tex010064400020550007177000000011470662233054400145550ustar00clevecompmath00000400000006% % main TeX file % % \documentstyle[leqno,11pt,twoside]{report} \documentclass[leqno,10pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt A2} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt A2} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} A2/doc/intro.tex010064400020550007177000000005260653502077100147650ustar00clevecompmath00000400000006\par \chapter{{\tt A2}: Real or complex 2-D array} \par The {\tt A2} object is one way to store and operate on and with a dense matrix. The matrix can contain either double precision real or complex entries. It is used as a lower level object for the {\tt DenseMtx} object, and during the $QR$ factorization to hold a staircase matrix. \par A2/doc/dataStructure.tex010064400020550007177000000031520653501644300164630ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:A2:dataStructure} \par \par The {\tt A2} structure has six fields. \begin{itemize} \item {\tt int type} : type of entries, {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item {\tt int n1} : size in first dimension, number of rows \item {\tt int n2} : size in second dimension, number of columns \item {\tt int inc1} : increment or stride in first dimension \item {\tt int inc2} : increment or stride in second dimension \item {\tt int nowned} : the number of entries that are ``owned'' by this object. When {\tt nowned > 0}, {\tt entries} points to storage for {\tt nowned} entries, ({\tt nowned} {\tt double}'s for the real case, {\tt 2*nowned} {\tt double}'s for the complex case), that have been allocated by this object and can be free'd by the object. When {\tt nowned == 0} but {\tt n1 > 0} and {\tt n2 > 0}, this object points to entries that have been allocated elsewhere, and these entries will not be free'd by this object. \item {\tt double *entries} : pointer to the base address of the {\it double} vector \end{itemize} One can query the properties of the front matrix object using these simple macros. \begin{itemize} \item {\tt A2\_IS\_REAL(mtx)} is {\tt 1} if {\tt mtx} has real entries and {\tt 0} otherwise. \item {\tt A2\_IS\_COMPLEX(mtx)} is {\tt 1} if {\tt mtx} has complex entries and {\tt 0} otherwise. \end{itemize} The {\tt A2\_copyEntriesToVector()} method uses the following constants: {\tt A2\_STRICT\_LOWER}, {\tt A2\_LOWER}, {\tt A2\_DIAGONAL}, {\tt A2\_UPPER}, {\tt A2\_STRICT\_UPPER}, {\tt A2\_ALL\_ENTRIES}, {\tt A2\_BY\_ROWS} and {\tt A2\_BY\_COLUMNS}. d} entries, ({\tt nowned} {\tt double}'s for the real case, {\tt 2*nowned} {\tt double}'s for the complex case), that have been allocated by this object and can be free'd by the object. When {\tt nowned == 0} but {\tt n1 > 0} and {\tt n2 > 0}, this object points to entries that have been allocated elsewhere, and these entries will not be free'd by this object. \item {\tt double *entries} : pointer toA2/doc/proto.tex010064400020550007177000001173110665016244600150020ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt A2} methods} \label{section:A2:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt A2} object. \par \subsection{Basic methods} \label{subsection:A2:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} A2 * A2_new ( void ) ; \end{verbatim} \index{A2_new@{\tt A2\_new()}} This method simply allocates storage for the {\tt A2} structure and then sets the default fields by a call to {\tt A2\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_setDefaultFields ( A2 *mtx ) ; \end{verbatim} \index{A2_setDefaultFields@{\tt A2\_setDefaultFields()}} The structure's fields are set to default values: {\tt type} = {\tt SPOOLES\_REAL}, {\tt n1} = {\tt inc1} = {\tt n2} = {\tt inc2} = {\tt nowned} = 0 and {\tt entries} = {\tt NULL} . \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_clearData ( A2 *mtx ) ; \end{verbatim} \index{A2_clearData@{\tt A2\_clearData()}} This method clears the object and free's any owned data. If {\tt nowned > 0} and {\tt entries} is not {\tt NULL}, then {\tt DVfree(entries)} is called to free the storage. It calls {\tt A2\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_free ( A2 *mtx ) ; \end{verbatim} \index{A2_free@{\tt A2\_free()}} This method releases any storage by a call to {\tt A2\_clearData()} and then free the space for {\tt mtx}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:A2:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int A2_nrow ( A2 *mtx ) ; \end{verbatim} \index{A2_nrow@{\tt A2\_nrow()}} This method returns the number of rows in the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_ncol ( A2 *mtx ) ; \end{verbatim} \index{A2_ncol@{\tt A2\_ncol()}} This method returns the number of columns in the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_inc1 ( A2 *mtx ) ; \end{verbatim} \index{A2_inc1@{\tt A2\_inc1()}} This method returns the primary increment, the stride in memory (with respect to real or complex entries) between adjacent entries in the same column. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_inc2 ( A2 *mtx ) ; \end{verbatim} \index{A2_inc2@{\tt A2\_inc2()}} This method returns the secondary increment, the stride in memory (with respect to real or complex entries) between adjacent entries in the same row. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double * A2_entries ( A2 *mtx ) ; \end{verbatim} \index{A2_entries@{\tt A2\_entries()}} This method returns a pointer to the base address of the entries. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double * A2_row ( A2 *mtx, int irow ) ; \end{verbatim} \index{A2_row@{\tt A2\_row()}} This method returns a pointer to the leading element of row {\tt irow}. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt entries} is {\tt NULL}, or if {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double * A2_column ( A2 *mtx, int jcol ) ; \end{verbatim} \index{A2_column@{\tt A2\_column()}} This method returns a pointer to the leading element of column {\tt jcol}. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt entries} is {\tt NULL}, or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_realEntry ( A2 *mtx, int irow, int jcol, double *pValue ) ; \end{verbatim} \index{A2_realEntry@{\tt A2\_realEntry()}} This method fills {\tt *pValue} with the entry in location {\tt (irow, jcol)}. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt pValue} is {\tt NULL}, or if the matrix is not real, or {\tt irow} is not in {\tt [0,n1-1]}, or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_complexEntry ( A2 *mtx, int irow, int jcol, double *pReal, double *pImag ) ; \end{verbatim} \index{A2_complexEntry@{\tt A2\_complexEntry()}} This method fills {\tt (*pReal,*pImag)} with the entry in location {\tt (irow, jcol)}. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pReal} or {\tt pImag} is {\tt NULL}, or if the matrix is not complex, or {\tt irow} is not in {\tt [0,n1-1]}, or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_setRealEntry ( A2 *mtx, int irow, int jcol, double value ) ; \end{verbatim} \index{A2_setRealEntry@{\tt A2\_setRealEntry()}} This method sets entry {\tt (irow,jcol)} to {\tt value}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if the matrix is not real, or {\tt irow} is not in {\tt [0,n1-1]} or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_setComplexEntry ( A2 *mtx, int irow, int jcol, double real, double imag ) ; \end{verbatim} \index{A2_setComplexEntry@{\tt A2\_setComplexEntry()}} This method sets entry {\tt (irow,jcol)} to {\tt (real,imag)}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if the matrix is not complex, or {\tt irow} is not in {\tt [0,n1-1]} or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_pointerToRealEntry ( A2 *mtx, int irow, int jcol, double **ppValue ) ; \end{verbatim} \index{A2_pointerToRealEntry@{\tt A2\_pointerToRealEntry()}} This method sets {\tt *ppValue} to the pointer of the {\tt (irow,jcol)} entry. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt ppValue} is {\tt NULL}, or if the matrix is not real, or if {\tt irow} is not in {\tt [0,n1-1]}, or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_pointerToComplexEntry ( A2 *mtx, int irow, int jcol, double **ppReal, double **ppImag ) ; \end{verbatim} \index{A2_pointerToComplexEntry@{\tt A2\_pointerToComplexEntry()}} This method sets {\tt *ppReal} to the pointer to the real part of the {\tt (irow,jcol)} entry, and sets {\tt *ppImag} to the pointer to the imaginary part of the {\tt (irow,jcol)} entry. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt ppReal} or {\tt ppImag} is {\tt NULL}, or if the matrix is not complex, or if {\tt irow} is not in {\tt [0,n1-1]}, or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialize methods} \label{subsection:A2:proto:initial} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void A2_init ( A2 *mtx, int type, int n1, int n2, int inc1, int inc2, double *entries ) ; \end{verbatim} \index{A2_init@{\tt A2\_init()}} This is the basic initializer method. We require that {\tt mtx} not be {\tt NULL}, {\tt type} be either {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, {\tt n1} and {\tt n2} both be positive, and both {\tt inc1} and {\tt inc2} both be positive and that one of them be equal to one. Also, we only initialize a full matrix, i.e., one of {\tt inc1 = 1} and {\tt inc2 = nrow} or {\tt inc1 = ncol} and {\tt inc2 = 1} must hold. \par The object is first cleared with a call to {\tt A2\_clearData()}. If {\tt entries} is {\tt NULL} then {\tt n1*n2} new entries are found, {\tt mtx->entries} is set to this address and {\tt nowned} is set to {\tt n1*n2}. If {\tt entries} is not {\tt NULL}, then {\tt mtx->entries} is set to {\tt entries} and {\tt nowned} is set to zero. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if {\tt n1}, {\tt n2}, {\tt inc1} or {\tt inc2} are less than or equal to zero, or if the matrix is not full matrix (i.e., {\tt inc1} must be {\tt 1} and {\tt inc2} must be {\tt n1}, {\it or} {\tt inc1} must be {\tt n2} and {\tt inc2} must be {\tt 1}), an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_subA2 ( A2 *mtxA, A2 *mtxB, int firstrow, int lastrow, int firstcol, int lastcol ) ; \end{verbatim} \index{A2_subA2@{\tt A2\_subA2()}} This initializer method makes the object {\tt mtxA} point into a submatrix of object {\tt mtxB}, as \begin{verbatim} A(0:lastrow-firstrow,0:lastcol-firstcol) = B(firstrow:lastrow, firstcol:lastcol) \end{verbatim} Note, {\tt firstrow}, {\tt lastrow}, {\tt firstcol} and {\tt lastcol} must satisfy {\tt 0 <= firstrow <= lastrow < mtxB->n1} and {\tt 0 <= firstcol <= lastcol < mtxB->n2}. Object {\tt mtxA} does not own its entries, but points into the entries of {\tt mtxB}. \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} are {\tt NULL}, or if {\tt firstrow} or {\tt lastrow} are out of range, or if {\tt firstcol} or {\tt lastcol} are out of range, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Methods used in the $QR$ factorization} \label{subsection:A2:proto:QR} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void A2_makeStaircase ( A2 *A ) ; \end{verbatim} \index{A2_makeStaircase@{\tt A2\_makeStaircase()}} This method permutes the rows of {\tt A} by the location of the leading nonzero of each row. Upon return, the matrix is in {\it staircase} form. \par \noindent {\it Error checking:} If {\tt A} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double A2_QRreduce ( A2 *A, DV *workDV, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{A2_QRreduce@{\tt A2\_QRreduce()}} This method computes $A = QR$ factorization. On return, the matrix $Q$ is not available, and $R$ is found in the upper triangle or upper trapezoid of {\tt A}. The Householder vectors are stored in the lower triangle of {\tt mtxA}, with $v_j(j) = 1.0$. The return value is the number of floating point operations that were executed. \par \noindent {\it Error checking:} If {\tt A} or {\tt workDV} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} if {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_computeQ ( A2 *Q, A2 *A, DV *workDV, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{A2_computeQ@{\tt A2\_computeQ()}} This method computes $Q$ from the $A = QR$ factorization computed in {\tt A2\_QRreduce()}. Note: {\tt A} and {\tt Q} must be column major. \par \noindent {\it Error checking:} If {\tt Q}, {\tt A} or {\tt workDV} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} if {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_applyQT ( A2 *Y, A2 *A, A2 *X, DV *workDV, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{A2_applyQT@{\tt A2\_applyQT()}} This method computes $Y = Q^T X$ (if real) or $Y = Q^H X$ (if complex), where $Q$ is stored in Householder vectors inside $A$. We assume that $A2\_reduce()$ has been previously called with $A$ as an argument. Since $Y$ is computed column-by-column, $X$ and $Y$ can be the same {\tt A2} object. The {\tt workDV} object is resized as necessary. Note: {\tt Y}, {\tt A} and {\tt X} must be column major. \par \noindent {\it Error checking:} If {\tt Y}, {\tt A}, {\tt X} or {\tt workDV} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} if {\tt NULL}, or if {\tt Y}, {\tt A} or {\tt X} is not column major, or if the types of {\tt Y}, {\tt A} and {\tt X} are not the same, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Norm methods} \label{subsection:A2:proto:norms} \par These methods return a norm of a row or a column, or the easily computable norms of the matrix. %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} double A2_maxabs ( A2 *mtx ) ; \end{verbatim} \index{A2_maxabs@{\tt A2\_maxabs()}} This method returns magnitude of the entry with largest magnitude. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double A2_frobNorm ( A2 *mtx ) ; \end{verbatim} \index{A2_frobNorm@{\tt A2\_frobNorm()}} This method returns the Frobenius norm of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double A2_oneNorm ( A2 *mtx ) ; \end{verbatim} \index{A2_oneNorm@{\tt A2\_oneNorm()}} This method returns the one norm of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double A2_infinityNorm ( A2 *mtx ) ; \end{verbatim} \index{A2_infinityNorm@{\tt A2\_infinityNorm()}} This method returns the infinity norm of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double A2_oneNormOfColumn ( A2 *mtx, int jcol ) ; \end{verbatim} \index{A2_oneNormOfColumn@{\tt A2\_oneNormOfColumn()}} This method returns the one-norm of column {\tt jcol} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double A2_twoNormOfColumn ( A2 *mtx, int jcol ) ; \end{verbatim} \index{A2_twoNormOfColumn@{\tt A2\_twoNormOfColumn()}} This method returns the two-norm of column {\tt jcol} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double A2_infinityNormOfColumn ( A2 *mtx, int jcol ) ; \end{verbatim} \index{A2_infinityNormOfColumn@{\tt A2\_infinityNormOfColumn()}} This method returns the infinity-norm of column {\tt jcol} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double A2_oneNormOfRow ( A2 *mtx, int irow ) ; \end{verbatim} \index{A2_oneNormOfRow@{\tt A2\_oneNormOfRow()}} This method returns the one-norm of row {\tt irow} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double A2_twoNormOfRow ( A2 *mtx, int irow ) ; \end{verbatim} \index{A2_twoNormOfRow@{\tt A2\_twoNormOfRow()}} This method returns the two-norm of row {\tt irow} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double A2_infinityNormOfRow ( A2 *mtx, int irow ) ; \end{verbatim} \index{A2_infinityNormOfRow@{\tt A2\_infinityNormOfRow()}} This method returns the infinity-norm of row {\tt irow} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Sort methods} \label{subsection:A2:proto:sort} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void A2_permuteRows ( A2 *mtx, int nrow, int index[] ) ; \end{verbatim} \index{A2_permuteRows@{\tt A2\_permuteRows()}} The {\tt index[]} vector contains the {\it row ids} of the leading {\tt nrow} rows. This method permutes the leading {\tt nrow} rows of the matrix so that the {\tt index[]} vector is in ascending order. This method calls {\tt A2\_permuteRows()} but does not overwrite the {\tt index[]} vector. \par \par \noindent {\it Error checking:} If {\tt mtx} or {\tt index[]} is {\tt NULL}, or if {\tt nrow < 0} or {\tt nrow > n1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_permuteColumns ( A2 *mtx, int nrow, int index[] ) ; \end{verbatim} \index{A2_permuteColumns@{\tt A2\_permuteColumns()}} The {\tt index[]} vector contains the {\it column ids} of the leading {\tt ncol} rows. This method permutes the leading {\tt ncol} columns of the matrix so that the {\tt index[]} vector is in ascending order. This method calls {\tt A2\_permuteColumns()} but does not overwrite the {\tt index[]} vector. \par \par \noindent {\it Error checking:} If {\tt mtx} or {\tt index[]} is {\tt NULL}, or if {\tt ncol < 0} or {\tt ncol > n2}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_sortRowsUp ( A2 *mtx, int nrow, int rowids[] ) ; \end{verbatim} \index{A2_sortRowsUp@{\tt A2\_sortRowsUp()}} This method sorts the leading {\tt nrow} rows of the matrix into ascending order with respect to the {\tt rowids[]} vector. The return value is the number of row swaps made. \par \par \noindent {\it Error checking:} If {\tt mtx} or {\tt rowids} is {\tt NULL}, or if {\tt nrow < 0} or {\tt nrow > n1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_sortColumnsUp ( A2 *mtx, int ncol, int colids[] ) ; \end{verbatim} \index{A2_sortColumnsUp@{\tt A2\_sortColumnsUp()}} This method sorts the leading {\tt ncol} columnss of the matrix into ascending order with respect to the {\tt colids[]} vector. The return value is the number of column swaps made. \par \par \noindent {\it Error checking:} If {\tt mtx} or {\tt colids} is {\tt NULL}, or if {\tt ncol < 0} or {\tt ncol > n2}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:A2:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int A2_sizeOf ( A2 *mtx ) ; \end{verbatim} \index{A2_sizeOf@{\tt A2\_sizeOf()}} This method returns the number of bytes owned by this object. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_shiftBase ( A2 *mtx, int rowoff, int coloff ) ; \end{verbatim} \index{A2_shiftbase@{\tt A2\_shiftBase()}} This method is used to shift the base of the entries and adjust dimensions of the {\tt A2} object. \begin{verbatim} mtx(0:n1-rowoff-1,0:n2-coloff-1) := mtx(rowoff:n1-1,coloff:n2-1) \end{verbatim} \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_rowMajor ( A2 *mtx ) ; \end{verbatim} \index{A2_rowMajor@{\tt A2\_rowMajor()}} This method returns 1 if the storage is row major, otherwise it returns zero. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_columnMajor ( A2 *mtx ) ; \end{verbatim} \index{A2_columnMajor@{\tt A2\_columnMajor()}} This method returns 1 if the storage is column major, otherwise it returns zero. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_transpose ( A2 *mtx ) ; \end{verbatim} \index{A2_transpose@{\tt A2\_transpose()}} This method replaces {\tt mtx} with its transpose. Note, this takes $O(1)$ operations since we just swap dimensions and increments. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_extractRow ( A2 *mtx, double row[], int irow ) ; \end{verbatim} \index{A2_extractRow@{\tt A2\_extractRow()}} This method fills the {\tt row[]} vector with row {\tt irow} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt entries} or {\tt row} are {\tt NULL}, or if {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_extractRowDV ( A2 *mtx, DV *rowDV, int irow ) ; \end{verbatim} \index{A2_extractRowDV@{\tt A2\_extractRowDV()}} This method fills the {\tt rowDV} object with row {\tt irow} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt rowDV} are {\tt NULL}, or if the matrix is not real, or if {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_extractRowZV ( A2 *mtx, ZV *rowZV, int irow ) ; \end{verbatim} \index{A2_extractRowZV@{\tt A2\_extractRowZV()}} This method fills the {\tt rowZV} object with row {\tt irow} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt rowZV} are {\tt NULL}, or if the matrix is not complex, or if {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_extractColumn ( A2 *mtx, double col[], int jcol ) ; \end{verbatim} \index{A2_extractColumn@{\tt A2\_extractColumn()}} This method fills the {\tt col[]} vector with column {\tt jcol} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt entries} or {\tt col} are {\tt NULL}, or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_extractColumnDV ( A2 *mtx, DV *colDV, int jcol ) ; \end{verbatim} \index{A2_extractColumnDV@{\tt A2\_extractColumnDV()}} This method fills the {\tt colDV} object with column {\tt jcol} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt colDV} are {\tt NULL}, or if the matrix is not complex, or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_extractColumnZV ( A2 *mtx, ZV *colZV, int jcol ) ; \end{verbatim} \index{A2_extractColumnZV@{\tt A2\_extractColumnZV()}} This method fills the {\tt colZV} object with column {\tt jcol} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt colZV} are {\tt NULL}, or if the matrix is not complex, or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_setRow ( A2 *mtx, double row[], int irow ) ; \end{verbatim} \index{A2_setRow@{\tt A2\_setRow()}} This method fills row {\tt irow} of the matrix with the entries in the {\tt row[]} vector. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt entries} or {\tt row[]} are {\tt NULL}, or if {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_setRowDV ( A2 *mtx, DV rowDV, int irow ) ; \end{verbatim} \index{A2_setRowDV@{\tt A2\_setRowDV()}} This method fills row {\tt irow} of the matrix with the entries in the {\tt rowDV} object. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt rowDV} are {\tt NULL}, or if the matrix is not real, or if {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_setRowZV ( A2 *mtx, ZV rowZV, int irow ) ; \end{verbatim} \index{A2_setRowZV@{\tt A2\_setRowZV()}} This method fills row {\tt irow} of the matrix with the entries in the {\tt rowZV} object. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt rowZV} are {\tt NULL}, or if the matrix is not complex, or if {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_setColumn ( A2 *mtx, double col[], int jcol ) ; \end{verbatim} \index{A2_setColumn@{\tt A2\_setColumn()}} This method fills column {\tt jcol} of the matrix with the entries in the {\tt col[]} vector. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt colZV} are {\tt NULL}, or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_setColumnDV ( A2 *mtx, DV colDV, int jcol ) ; \end{verbatim} \index{A2_setColumnDV@{\tt A2\_setColumnDV()}} This method fills column {\tt jcol} of the matrix with the entries in the {\tt colDV} object. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt colDV} are {\tt NULL}, or if the matrix is not complex, or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_setColumnZV ( A2 *mtx, ZV colZV, int jcol ) ; \end{verbatim} \index{A2_setColumnZV@{\tt A2\_setColumnZV()}} This method fills column {\tt jcol} of the matrix with the entries in the {\tt colZV} object. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt colZV} are {\tt NULL}, or if the matrix is not complex, or if {\tt jcol} is not in {\tt [0,n2-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_fillRandomUniform ( A2 *mtx, double lower, double upper, int seed ) ; \end{verbatim} \index{A2_fillRandomUniform@{\tt A2\_fillRandomUniform()}} This method fills the matrix with random numbers taken from a uniform distribution on {\tt [lower,upper]} using the {\tt Drand} object. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_fillRandomNormal ( A2 *mtx, double mean, double variance, int seed ) ; \end{verbatim} \index{A2_fillRandomNormal@{\tt A2\_fillRandomNormal()}} This method fills the matrix with random numbers taken from a normal distribution with mean {\tt mean} and variance {\tt variance} using the {\tt Drand} object. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_fillWithIdentity ( A2 *mtx ) ; \end{verbatim} \index{A2_fillWithIdentity@{\tt A2\_fillWithIdentity()}} This method fills the matrix with the identity matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL} or if {\tt n1 != n2}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_zero ( A2 *mtx ) ; \end{verbatim} \index{A2_zero@{\tt A2\_zero()}} This method fills the matrix with zeros. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_copy ( A2 *mtxA, A2 *mtxB ) ; \end{verbatim} \index{A2_copy@{\tt A2\_copy()}} This method copies entries from matrix {\tt mtxB} into matrix {\tt mtxA}. Note, {\tt mtxA} and {\tt mtxB} need not be of the same size, the leading {\tt min(mtxA->n1,mtxB->n1)} rows and {\tt min(mtxA->n2,mtxB->n2)} columns are copied. \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} is {\tt NULL}, or if the matrices are not of the same type, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_sub ( A2 *mtxA, A2 *mtxB ) ; \end{verbatim} \index{A2_sub@{\tt A2\_sub()}} This method subtracts entries in matrix {\tt mtxB} from entries in matrix {\tt mtxA}. Note, {\tt mtxA} and {\tt mtxB} need not be of the same size, the leading {\tt min(mtxA->n1,mtxB->n1)} rows and {\tt min(mtxA->n2,mtxB->n2)} columns are subtracted. \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} is {\tt NULL}, or if the matrices are not of the same type, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_swapRows ( A2 *mtx, int irow1, int irow2 ) ; \end{verbatim} \index{A2_swapRows@{\tt A2\_swapRows()}} This method swaps rows {\tt irow1} and {\tt irow2} of the matrix. \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} is {\tt NULL}, or if {\tt irow1} or {\tt irow2} are out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_swapColumns ( A2 *mtx, int irow1, int irow2 ) ; \end{verbatim} \index{A2_swapColumns@{\tt A2\_swapColumns()}} This method swaps columns {\tt jcol1} and {\tt jcol2} of the matrix. \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} is {\tt NULL}, or if {\tt jcol1} or {\tt jcol1} are out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_copyEntriesToVector ( A2 *mtx, int length, double dvec[], int copyflag, int storeflag ) ; \end{verbatim} \index{A2_copyEntriesToVector@{\tt A2\_copyEntriesToVector()}} This method copies selected entries from {\tt mtx} into the vector {\tt dvec[]} with length {\tt length}. The return value is the number of entries copied. This method is used during the $QR$ factorization to extract factor entries and update matrix entries from a front. All entries may be copied, or only the diagonal, lower or upper entries, and the entries may be copied to {\tt dvec[]} by rows or by columns. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt dvec} is {\tt NULL}, or if {\tt length} is not as large as the number of entries to be copied, or if {\tt copyflag} is not one of {\tt A2\_STRICT\_LOWER}, {\tt A2\_LOWER}, {\tt A2\_DIAGONAL}, {\tt A2\_UPPER}, {\tt A2\_STRICT\_UPPER} or {\tt A2\_ALL\_ENTRIES}, or if {\tt storeflag} is not one of {\tt A2\_BY\_ROWS} or {\tt A2\_BY\_COLUMNS}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:A2:proto:IO} \par There are the usual eight IO routines plus a method to write the object to a Matlab file. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int A2_readFromFile ( A2 *mtx, char *fn ) ; \end{verbatim} \index{A2_readFromFile@{\tt A2\_readFromFile()}} \par This method reads a {\tt A2} object from a file. It tries to open the file and if it is successful, it then calls {\tt A2\_readFromFormattedFile()} or {\tt A2\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.a2f} (for a formatted file) or {\tt *.a2b} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_readFromFormattedFile ( A2 *mtx, FILE *fp ) ; \end{verbatim} \index{A2_readFromFormattedFile@{\tt A2\_readFromFormattedFile()}} \par This method reads a {\tt A2} object from a formatted file whose pointer is {\tt fp}. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_readFromBinaryFile ( A2 *mtx, FILE *fp ) ; \end{verbatim} \index{A2_readFromBinaryFile@{\tt A2\_readFromBinaryFile()}} \par This method reads a {\tt A2} object from a binary file whose pointer is {\tt fp}. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_writeToFile ( A2 *mtx, char *fn ) ; \end{verbatim} \index{A2_writeToFile@{\tt A2\_writeToFile()}} \par This method writes a {\tt A2} object to a file. It tries to open the file and if it is successful, it then calls {\tt A2\_writeFromFormattedFile()} or {\tt A2\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.a2f} (for a formatted file) or {\tt *.a2b} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_writeToFormattedFile ( A2 *mtx, FILE *fp ) ; \end{verbatim} \index{A2_writeToFormattedFile@{\tt A2\_writeToFormattedFile()}} \par This method writes a {\tt A2} object to a formatted file whose pointer is {\tt fp}. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int A2_writeToBinaryFile ( A2 *mtx, FILE *fp ) ; \end{verbatim} \index{A2_writeToBinaryFile@{\tt A2\_writeToBinaryFile()}} \par This method writes a {\tt A2} object to a binary file whose pointer is {\tt fp}. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_writeForHumanEye ( A2 *mtx, FILE *fp ) ; \end{verbatim} \index{A2_writeForHumanEye@{\tt A2\_writeForHumanEye()}} \par This method writes a {\tt A2} object to a file in an easily readable format. The method {\tt A2\_writeStats()} is called to write out the header and statistics. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_writeStats ( A2 *mtx, FILE *fp ) ; \end{verbatim} \index{A2_writeStats@{\tt A2\_writeStats()}} \par This method writes a header and some statistics to a file. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_writeForMatlab ( A2 *mtx, char *mtxname, FILE *fp ) ; \end{verbatim} \index{A2_writeForMatlab@{\tt A2\_writeForMatlab()}} \par This method writes the entries of the matrix to a file in Matlab format. The name of the matrix is {\tt mtxname}. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt mtxname} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} tt Drand} object. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void A2_fillRandomNormal ( A2 *mtx, double mean, double variance, int seed ) ; \A2/doc/main.log010064400020550007177000000075110665016245300145420ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 16 JAN 1999 11:14 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. (intro.tex Chapter 1. LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 9. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 9. ) (dataStructure.tex LaTeX Font Info: Try loading font information for OMS+cmr on input line 9. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 9. Overfull \hbox (22.05931pt too wide) in paragraph at lines 44--54 \OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 A2[]copyEntriesToVector() \OT1/cmr/m/n/10 method uses the fol-low-ing con-stants: \OT1/cmtt/m/n/10 A2[]STRICT[]LOWER\OT1/ cmr/m/n/10 , \OT1/cmtt/m/n/10 A2[]LOWER\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 A2[]D IAGONAL\OT1/cmr/m/n/10 , [] ) (proto.tex [1 ] [2] [3] Overfull \hbox (9.5478pt too wide) in paragraph at lines 290--295 \OT1/cmr/m/n/10 Note, \OT1/cmtt/m/n/10 firstrow\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/ 10 lastrow\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 firstcol \OT1/cmr/m/n/10 and \OT1/ cmtt/m/n/10 lastcol \OT1/cmr/m/n/10 must sat-isfy \OT1/cmtt/m/n/10 0 <= firstro w <= lastrow < mtxB->n1 [] LaTeX Font Info: External font `cmex10' loaded for size (Font) <12> on input line 303. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 303. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 303. [4] [5] [6] [7] Overfull \hbox (0.273pt too wide) in paragraph at lines 776--779 []\OT1/cmr/m/n/10 This method fills the ma-trix with ran-dom num-bers taken fro m a uni-form dis-tri-bu-tion on \OT1/cmtt/m/n/10 [lower,upper] [] [8] [9]) (drivers.tex [10]) (main.ind [11] [12 ]) (main.aux) ) Here is how much of TeX's memory you used: 321 strings out of 10908 3334 string characters out of 72189 50228 words of memory out of 262141 3233 multiletter control sequences out of 9500 9705 words of font info for 35 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 23i,5n,21p,140b,423s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (12 pages, 42424 bytes). A2/doc/main.aux010064400020550007177000000032230665016245300145520ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt A2}: Real or complex 2-D array}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{1}} \newlabel{section:A2:dataStructure}{{1.1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt A2} methods}{1}} \newlabel{section:A2:proto}{{1.2}{1}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{2}} \newlabel{subsection:A2:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Instance methods}{2}} \newlabel{subsection:A2:proto:instance}{{1.2.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Initialize methods}{4}} \newlabel{subsection:A2:proto:initial}{{1.2.3}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Methods used in the $QR$ factorization}{4}} \newlabel{subsection:A2:proto:QR}{{1.2.4}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Norm methods}{5}} \newlabel{subsection:A2:proto:norms}{{1.2.5}{5}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.6}Sort methods}{6}} \newlabel{subsection:A2:proto:sort}{{1.2.6}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.7}Utility methods}{6}} \newlabel{subsection:A2:proto:utilities}{{1.2.7}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.8}IO methods}{9}} \newlabel{subsection:A2:proto:IO}{{1.2.8}{9}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs for the {\tt A2 object}}{10}} \newlabel{section:A2:drivers}{{1.3}{10}} A2/doc/main.idx010064400020550007177000000075420665016245300145510ustar00clevecompmath00000400000006\indexentry{A2_new@{\tt A2\_new()}}{2} \indexentry{A2_setDefaultFields@{\tt A2\_setDefaultFields()}}{2} \indexentry{A2_clearData@{\tt A2\_clearData()}}{2} \indexentry{A2_free@{\tt A2\_free()}}{2} \indexentry{A2_nrow@{\tt A2\_nrow()}}{2} \indexentry{A2_ncol@{\tt A2\_ncol()}}{2} \indexentry{A2_inc1@{\tt A2\_inc1()}}{2} \indexentry{A2_inc2@{\tt A2\_inc2()}}{2} \indexentry{A2_entries@{\tt A2\_entries()}}{2} \indexentry{A2_row@{\tt A2\_row()}}{3} \indexentry{A2_column@{\tt A2\_column()}}{3} \indexentry{A2_realEntry@{\tt A2\_realEntry()}}{3} \indexentry{A2_complexEntry@{\tt A2\_complexEntry()}}{3} \indexentry{A2_setRealEntry@{\tt A2\_setRealEntry()}}{3} \indexentry{A2_setComplexEntry@{\tt A2\_setComplexEntry()}}{3} \indexentry{A2_pointerToRealEntry@{\tt A2\_pointerToRealEntry()}}{3} \indexentry{A2_pointerToComplexEntry@{\tt A2\_pointerToComplexEntry()}}{3} \indexentry{A2_init@{\tt A2\_init()}}{4} \indexentry{A2_subA2@{\tt A2\_subA2()}}{4} \indexentry{A2_makeStaircase@{\tt A2\_makeStaircase()}}{4} \indexentry{A2_QRreduce@{\tt A2\_QRreduce()}}{4} \indexentry{A2_computeQ@{\tt A2\_computeQ()}}{4} \indexentry{A2_applyQT@{\tt A2\_applyQT()}}{5} \indexentry{A2_maxabs@{\tt A2\_maxabs()}}{5} \indexentry{A2_frobNorm@{\tt A2\_frobNorm()}}{5} \indexentry{A2_oneNorm@{\tt A2\_oneNorm()}}{5} \indexentry{A2_infinityNorm@{\tt A2\_infinityNorm()}}{5} \indexentry{A2_oneNormOfColumn@{\tt A2\_oneNormOfColumn()}}{5} \indexentry{A2_twoNormOfColumn@{\tt A2\_twoNormOfColumn()}}{5} \indexentry{A2_infinityNormOfColumn@{\tt A2\_infinityNormOfColumn()}}{5} \indexentry{A2_oneNormOfRow@{\tt A2\_oneNormOfRow()}}{5} \indexentry{A2_twoNormOfRow@{\tt A2\_twoNormOfRow()}}{6} \indexentry{A2_infinityNormOfRow@{\tt A2\_infinityNormOfRow()}}{6} \indexentry{A2_permuteRows@{\tt A2\_permuteRows()}}{6} \indexentry{A2_permuteColumns@{\tt A2\_permuteColumns()}}{6} \indexentry{A2_sortRowsUp@{\tt A2\_sortRowsUp()}}{6} \indexentry{A2_sortColumnsUp@{\tt A2\_sortColumnsUp()}}{6} \indexentry{A2_sizeOf@{\tt A2\_sizeOf()}}{6} \indexentry{A2_shiftbase@{\tt A2\_shiftBase()}}{6} \indexentry{A2_rowMajor@{\tt A2\_rowMajor()}}{7} \indexentry{A2_columnMajor@{\tt A2\_columnMajor()}}{7} \indexentry{A2_transpose@{\tt A2\_transpose()}}{7} \indexentry{A2_extractRow@{\tt A2\_extractRow()}}{7} \indexentry{A2_extractRowDV@{\tt A2\_extractRowDV()}}{7} \indexentry{A2_extractRowZV@{\tt A2\_extractRowZV()}}{7} \indexentry{A2_extractColumn@{\tt A2\_extractColumn()}}{7} \indexentry{A2_extractColumnDV@{\tt A2\_extractColumnDV()}}{7} \indexentry{A2_extractColumnZV@{\tt A2\_extractColumnZV()}}{7} \indexentry{A2_setRow@{\tt A2\_setRow()}}{7} \indexentry{A2_setRowDV@{\tt A2\_setRowDV()}}{8} \indexentry{A2_setRowZV@{\tt A2\_setRowZV()}}{8} \indexentry{A2_setColumn@{\tt A2\_setColumn()}}{8} \indexentry{A2_setColumnDV@{\tt A2\_setColumnDV()}}{8} \indexentry{A2_setColumnZV@{\tt A2\_setColumnZV()}}{8} \indexentry{A2_fillRandomUniform@{\tt A2\_fillRandomUniform()}}{8} \indexentry{A2_fillRandomNormal@{\tt A2\_fillRandomNormal()}}{8} \indexentry{A2_fillWithIdentity@{\tt A2\_fillWithIdentity()}}{8} \indexentry{A2_zero@{\tt A2\_zero()}}{8} \indexentry{A2_copy@{\tt A2\_copy()}}{8} \indexentry{A2_sub@{\tt A2\_sub()}}{9} \indexentry{A2_swapRows@{\tt A2\_swapRows()}}{9} \indexentry{A2_swapColumns@{\tt A2\_swapColumns()}}{9} \indexentry{A2_copyEntriesToVector@{\tt A2\_copyEntriesToVector()}}{9} \indexentry{A2_readFromFile@{\tt A2\_readFromFile()}}{9} \indexentry{A2_readFromFormattedFile@{\tt A2\_readFromFormattedFile()}}{9} \indexentry{A2_readFromBinaryFile@{\tt A2\_readFromBinaryFile()}}{9} \indexentry{A2_writeToFile@{\tt A2\_writeToFile()}}{10} \indexentry{A2_writeToFormattedFile@{\tt A2\_writeToFormattedFile()}}{10} \indexentry{A2_writeToBinaryFile@{\tt A2\_writeToBinaryFile()}}{10} \indexentry{A2_writeForHumanEye@{\tt A2\_writeForHumanEye()}}{10} \indexentry{A2_writeStats@{\tt A2\_writeStats()}}{10} \indexentry{A2_writeForMatlab@{\tt A2\_writeForMatlab()}}{10} A2/doc/main.ind010064400020550007177000000046120662233055400145300ustar00clevecompmath00000400000006\begin{theindex} \item {\tt A2\_clearData()}, 2 \item {\tt A2\_column()}, 3 \item {\tt A2\_columnMajor()}, 6 \item {\tt A2\_complexEntry()}, 3 \item {\tt A2\_copy()}, 8 \item {\tt A2\_copyEntriesToVector()}, 9 \item {\tt A2\_entries()}, 2 \item {\tt A2\_extractColumn()}, 7 \item {\tt A2\_extractColumnDV()}, 7 \item {\tt A2\_extractColumnZV()}, 7 \item {\tt A2\_extractRow()}, 7 \item {\tt A2\_extractRowDV()}, 7 \item {\tt A2\_extractRowZV()}, 7 \item {\tt A2\_fillRandomUniform()}, 8 \item {\tt A2\_fillWithIdentity()}, 8 \item {\tt A2\_free()}, 2 \item {\tt A2\_frobNorm()}, 5 \item {\tt A2\_inc1()}, 2 \item {\tt A2\_inc2()}, 2 \item {\tt A2\_infinityNorm()}, 5 \item {\tt A2\_infinityNormOfColumn()}, 5 \item {\tt A2\_infinityNormOfRow()}, 5 \item {\tt A2\_init()}, 4 \item {\tt A2\_makeStaircase()}, 4 \item {\tt A2\_maxabs()}, 5 \item {\tt A2\_ncol()}, 2 \item {\tt A2\_new()}, 2 \item {\tt A2\_nrow()}, 2 \item {\tt A2\_oneNorm()}, 5 \item {\tt A2\_oneNormOfColumn()}, 5 \item {\tt A2\_oneNormOfRow()}, 5 \item {\tt A2\_permuteColumns()}, 6 \item {\tt A2\_permuteRows()}, 6 \item {\tt A2\_pointerToComplexEntry()}, 3 \item {\tt A2\_pointerToRealEntry()}, 3 \item {\tt A2\_QRreduce2()}, 4 \item {\tt A2\_readFromBinaryFile()}, 9 \item {\tt A2\_readFromFile()}, 9 \item {\tt A2\_readFromFormattedFile()}, 9 \item {\tt A2\_realEntry()}, 3 \item {\tt A2\_row()}, 3 \item {\tt A2\_rowMajor()}, 6 \item {\tt A2\_setColumn()}, 8 \item {\tt A2\_setColumnDV()}, 8 \item {\tt A2\_setColumnZV()}, 8 \item {\tt A2\_setComplexEntry()}, 3 \item {\tt A2\_setDefaultFields()}, 2 \item {\tt A2\_setRealEntry()}, 3 \item {\tt A2\_setRow()}, 7 \item {\tt A2\_setRowDV()}, 7 \item {\tt A2\_setRowZV()}, 7 \item {\tt A2\_shiftBase()}, 6 \item {\tt A2\_sizeOf()}, 6 \item {\tt A2\_sortColumnsUp()}, 6 \item {\tt A2\_sortRowsUp()}, 6 \item {\tt A2\_sub()}, 8 \item {\tt A2\_subA2()}, 4 \item {\tt A2\_swapColumns()}, 9 \item {\tt A2\_swapRows()}, 8 \item {\tt A2\_transpose()}, 7 \item {\tt A2\_twoNormOfColumn()}, 5 \item {\tt A2\_twoNormOfRow()}, 5 \item {\tt A2\_writeForHumanEye()}, 10 \item {\tt A2\_writeForMatlab()}, 10 \item {\tt A2\_writeStats()}, 10 \item {\tt A2\_writeToBinaryFile()}, 10 \item {\tt A2\_writeToFile()}, 9 \item {\tt A2\_writeToFormattedFile()}, 9 \item {\tt A2\_zero()}, 8 \end{theindex} A2/doc/main.ilg010064400020550007177000000004570662233055400145340ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (69 entries accepted, 0 rejected). Sorting entries....done (417 comparisons). Generating output file main.ind....done (73 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. A2/doc/makefile010064400020550007177000000000270654276725700146230ustar00clevecompmath00000400000006clean : - rm -f *.dvi A2/doc/drivers.tex010064400020550007177000000055130653505661700153210ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt A2 object}} \label{section:A2:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} test_norms msglvl msgFile type nrow ncol inc1 inc2 seed \end{verbatim} This driver program tests the {\tt A2} norm methods. Use the script file {\tt do\_norms} for testing. When the output file is loaded into matlab, the last two lines contain matrices whose entries should all be around machine epsilon. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt nrow} parameter is the number of rows. \item The {\tt ncol} parameter is the number of rows. \item The {\tt inc1} parameter is the row increment. \item The {\tt inc2} parameter is the column increment. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_QR msglvl msgFile type nrow ncol inc1 inc2 seed \end{verbatim} This driver program tests the {\tt A2\_QRreduce()} and {\tt A2\_QRreduce2()} methods which reduce $A$ to $QR$ via rank-1 and rank-2 updates. Use the script file {\tt do\_QR} for testing. When {\tt msglvl > 1}, the matrix $A$ and matrices $R1$ and $R2$ (computed from {\tt A2\_QRreduce()} and {\tt A2\_QRreduce2()}, respectively) are printed to the message file. When the output file is loaded into matlab, the errors $A^TA - R_1^TR_1$ and $A^TA - R_2^TR_2$ (if $A$ is real) or the errors $A^HA - R_1^HR_1$ and $A^HA - R_2^HR_2$ (if $A$ is complex) are computed. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt nrow} parameter is the number of rows. \item The {\tt ncol} parameter is the number of rows. \item The {\tt inc1} parameter is the row increment. \item The {\tt inc2} parameter is the column increment. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} -------------------------------------------- \item \begin{verbatim} test_QR msglvl msgFile type nrow ncol inc1 inc2 seed \end{verbatim} This driver program tests the {\tt A2\_QRreduA2/doc/main.ps010064400020550007177000023122520663603715400144110ustar00clevecompmath00000400000006%!PS-Adobe-2.0 %%Creator: dvipsk 5.58f Copyright 1986, 1994 Radical Eye Software %%Title: main.dvi %%Pages: 12 %%PageOrder: Ascend %%BoundingBox: 0 0 612 792 %%DocumentFonts: CMBX12 CMTT12 CMR10 CMTT10 CMMI10 CMSY10 CMTI10 CMSL10 %%+ CMMI12 CMMI7 CMR7 %%DocumentPaperSizes: Letter %%EndComments %DVIPSCommandLine: dvips main -o %DVIPSParameters: dpi=600, comments removed %DVIPSSource: TeX output 1998.12.16:1512 %%BeginProcSet: tex.pro /TeXDict 250 dict def TeXDict begin /N{def}def /B{bind def}N /S{exch}N /X{S N}B /TR{translate}N /isls false N /vsize 11 72 mul N /hsize 8.5 72 mul N /landplus90{false}def /@rigin{isls{[0 landplus90{1 -1}{-1 1} ifelse 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[matrix currentmatrix{dup dup round sub abs 0.00001 lt{round}if} forall round exch round exch]setmatrix}N /@landscape{/isls true N}B /@manualfeed{statusdict /manualfeed true put}B /@copies{/#copies X}B /FMat[1 0 0 -1 0 0]N /FBB[0 0 0 0]N /nn 0 N /IE 0 N /ctr 0 N /df-tail{ /nn 8 dict N nn begin /FontType 3 N /FontMatrix fntrx N /FontBBox FBB N string /base X array /BitMaps X /BuildChar{CharBuilder}N /Encoding IE N end dup{/foo setfont}2 array copy cvx N load 0 nn put /ctr 0 N[}B /df{ /sf 1 N /fntrx FMat N df-tail}B /dfs{div /sf X /fntrx[sf 0 0 sf neg 0 0] N df-tail}B /E{pop nn dup definefont setfont}B /ch-width{ch-data dup length 5 sub get}B /ch-height{ch-data dup length 4 sub get}B /ch-xoff{ 128 ch-data dup length 3 sub get sub}B /ch-yoff{ch-data dup length 2 sub get 127 sub}B /ch-dx{ch-data dup length 1 sub get}B /ch-image{ch-data dup type /stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0 N /rw 0 N /rc 0 N /gp 0 N /cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S dup /base get 2 index get S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx 0 ch-xoff ch-yoff ch-height sub ch-xoff ch-width add ch-yoff setcachedevice ch-width ch-height true[1 0 0 -1 -.1 ch-xoff sub ch-yoff .1 sub]{ch-image}imagemask restore}B /D{/cc X dup type /stringtype ne{]} if nn /base get cc ctr put nn /BitMaps get S ctr S sf 1 ne{dup dup length 1 sub dup 2 index S get sf div put}if put /ctr ctr 1 add N}B /I{ cc 1 add D}B /bop{userdict /bop-hook known{bop-hook}if /SI save N @rigin 0 0 moveto /V matrix currentmatrix dup 1 get dup mul exch 0 get dup mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N /eop{SI restore userdict /eop-hook known{eop-hook}if showpage}N /@start{userdict /start-hook known{start-hook}if pop /VResolution X /Resolution X 1000 div /DVImag X /IE 256 array N 0 1 255{IE S 1 string dup 0 3 index put cvn put}for 65781.76 div /vsize X 65781.76 div /hsize X}N /p{show}N /RMat[1 0 0 -1 0 0]N /BDot 260 string N /rulex 0 N /ruley 0 N /v{/ruley X /rulex X V}B /V {}B /RV statusdict begin /product where{pop product dup length 7 ge{0 7 getinterval dup(Display)eq exch 0 4 getinterval(NeXT)eq or}{pop false} ifelse}{false}ifelse end{{gsave TR -.1 .1 TR 1 1 scale rulex ruley false RMat{BDot}imagemask grestore}}{{gsave TR -.1 .1 TR rulex ruley scale 1 1 false RMat{BDot}imagemask grestore}}ifelse B /QV{gsave newpath transform round exch round exch itransform moveto rulex 0 rlineto 0 ruley neg rlineto rulex neg 0 rlineto fill grestore}B /a{moveto}B /delta 0 N /tail {dup /delta X 0 rmoveto}B /M{S p delta add tail}B /b{S p tail}B /c{-4 M} B /d{-3 M}B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B /j{3 M}B /k{ 4 M}B /w{0 rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w}B /q{ p 1 w}B /r{p 2 w}B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p a}B /bos{/SS save N}B /eos{SS restore}B end %%EndProcSet %%BeginFont: CMBX12 %!PS-AdobeFont-1.1: CMBX12 1.0 %%CreationDate: 1991 Aug 20 16:34:54 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMBX12) readonly def /FamilyName (Computer Modern) readonly def /Weight (Bold) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /CMBX12 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 161 /Gamma put dup 162 /Delta put dup 163 /Theta put dup 164 /Lambda put dup 165 /Xi put dup 166 /Pi put dup 167 /Sigma put dup 168 /Upsilon put dup 169 /Phi put dup 170 /Psi put dup 173 /Omega put dup 174 /ff put dup 175 /fi put dup 176 /fl put dup 177 /ffi put dup 178 /ffl put dup 179 /dotlessi put dup 180 /dotlessj put dup 181 /grave put dup 182 /acute put dup 183 /caron put dup 184 /breve put dup 185 /macron put dup 186 /ring put dup 187 /cedilla put dup 188 /germandbls put dup 189 /ae put dup 190 /oe put dup 191 /oslash put dup 192 /AE put dup 193 /OE put dup 194 /Oslash put dup 195 /suppress put dup 196 /dieresis put dup 0 /Gamma put dup 1 /Delta put dup 2 /Theta put dup 3 /Lambda put dup 4 /Xi put dup 5 /Pi put dup 6 /Sigma put dup 7 /Upsilon put dup 8 /Phi put dup 9 /Psi put dup 10 /Omega put dup 11 /ff put dup 12 /fi put dup 13 /fl put dup 14 /ffi put dup 15 /ffl put dup 16 /dotlessi put dup 17 /dotlessj put dup 18 /grave put dup 19 /acute put dup 20 /caron put dup 21 /breve put dup 22 /macron put dup 23 /ring put dup 24 /cedilla put dup 25 /germandbls put dup 26 /ae put dup 27 /oe put dup 28 /oslash put dup 29 /AE put dup 30 /OE put dup 31 /Oslash put dup 32 /suppress put dup 33 /exclam put dup 34 /quotedblright put dup 35 /numbersign put dup 36 /dollar put dup 37 /percent put dup 38 /ampersand put dup 39 /quoteright put dup 40 /parenleft put dup 41 /parenright put dup 42 /asterisk put dup 43 /plus put dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 47 /slash put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 59 /semicolon put dup 60 /exclamdown put dup 61 /equal put dup 62 /questiondown put dup 63 /question put dup 64 /at put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /bracketleft put dup 92 /quotedblleft put dup 93 /bracketright put dup 94 /circumflex put dup 95 /dotaccent put dup 96 /quoteleft put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /endash put dup 124 /emdash put dup 125 /hungarumlaut put dup 126 /tilde put dup 127 /dieresis put dup 128 /suppress put dup 160 /space put readonly def /FontBBox{-53 -251 1139 750}readonly def /UniqueID 5000769 def currentdict end currentfile eexec 9B9C1569015F2C1D2BF560F4C0D52257BACDD6500ABDA5ED9835F6A016CFC8F00B6C052ED76A 87856B50F4D80DFAEB508C97F8281F3F88B17E4D3B90C0F65EC379791AACDC162A66CBBC5BE2 F53AAD8DE72DD113B55A022FBFEE658CB95F5BB32BA0357B5E050FDDF264A07470BEF1C52119 B6FBD5C77EBED964AC5A2BBEC9D8B3E48AE5BB003A63D545774B922B9D5FF6B0066ECE43645A 131879B032137D6D823385FE55F3402D557FD3B4486BE79011D1F5BFAE5C1F476EE6F05EB1D2 CAEB269958B194521197B312FCCED4867F3C8FBD030BD715D8FFDA1DCD454B174E7A1A97B59F E770E67702519D9D9B23D61AC08424D555242A8CA08C49AEF300945D99B999A79CE74804AE6B FDE623F4463371442F6523A5F6CE19C839A708C025132E22C696C8CCADE45680E5197189D0F9 8E7F0D5F955E353970B392CF530A68CC56B0035DDFBF206C3074BEEB0739DCBCA272A6E629FB 7AEA2C5BA7BAE50C7B4CA595DF78200C352997EC3EE564DF229FBB5473F5E8CCB1CC0153E9A7 E299A8EAA29B69D1B622B1F0CFFC58291248759607D91150CB0651120970DC9F743BEBEF44F6 AE92FACEC57658999C8BF01F60611560043962C0695E1BB87D090E0FDAAB659D6557208A660B E9AEEF8AE55F71B8BC76394D792967E41BD8023B6E7F8C3D9987D5E54C53BF2BBB32855B9464 73B44833BD78873DF8E4C7E668FFFF25AABB8DA4148F744B9D0524D6CB8281247B3052CC5D66 F3F1BCF8A56A3FB446EA587BD8BE30257652CEE035628AEDDFD8283B5AD21B8B1480AD24D898 970AC8A1E33E543CE4E3C48F9EE621C5CE3E8AE930F890011B630866C988606068D9E92396EB F51BB3DB204505FC3D09D4701AC703A14D92BBFE27BD7411B363A88E33A8E9A8025AC31F21E7 3DC52B333B918D0B1270C54873A490222D041A66E0192612BE6D2C88958A8F70C10390146EE5 091DF020AB97675E8E6901226EED50125D36C221BE8F20647442444B13F0325F899B8FA15E14 14119B45F920F73DC3496F6DE0DD4418A1181E791B49A52866C79D377494BEFF7F1B444111BC A4FC2BFB7279FA2938FA9BE2DE762F20D470813C4EE0034371812EFB9F87014528B7A09BE4F0 1F1F84DE922D6C66D7F6FF96A49233B2396D9C19B85B132FF565893AD3A11DDB88E469FC1DEC D51E5B3FADFD1E3E50914839DEE5D5D2B63F83E8A7953833EFE2492A30314F32E2BD9A758F2A BDA8107618EEF886F13905EECE29E3A0267FA506A77271C89450B6CB4320E2A9169EC494917A 370CE72227860BB7ECCA9D1DAC4AFDD4BC59CA1DFC10A5D530DC1E8AFA557BA49454F211BBB2 4B86044A9008092E262BBACE0C5F084A66DAB3BD57DF91E3D4440C9974666E46AF84B0C0F928 6045D15EF5C5E601CFC42D8D2A14117BF73DF97A8C602FAFA97F13823603CD70D202551F6BAE D6F13442564A85BAF8FC53676FCA540943F23146BEEF9691FC26B2C7327B63627570EAA85ACE 4938C3884221F1A91F5E57E303425C649D12E0977D78BC7D32CB30710817926509A49DAE5C95 30BD89B44C105695CE609BABD50A7A2CCDB30F679D849577A8E7C0300D2606DAC4658B4A0555 DF2D2740EC5F9D76270DAC943DA0E0271755607D355709DC9B0DB68098E3DED0C081DD742BFA 7C29090A2BDA699D4EBBAD79BB3B901E59159869FF13361A167ECDC51D1E655F475D453CCF93 5F637C2CF08B222968F2DA3D3630A9747CB5B8AC4B042BC44CC22A488CC8099AA15FA2C43D1B C9ADAFB2A4129E880F5CFCD563B41A16096EA07B96BCE2B2E81C89968F5A3949889EBDF25E07 042B81DFF462DB36311BB3FAF1387A3BFF193C09FF4972FF743A3FAC0DD57995444D2AE34BA0 A8AA9C69457654D2221C8927124BF9E1B2D768CF672CDE3A6945E627F11D1D08E1403A06ADDC A67CAA82958FFD15CE17CEB235F4CA05231E6E10CC2BC7803FC2F92CBFDCDD09F100A0CDA8B6 D73A1F2F4778BE732F2FFD8AF6170FC11D37A83C9260606E5EB14A411E1C7CD5B6D2E0D722A3 7A1F628512DD6598F9845398F854BB17DF1840FA7AF1CD58981A5EA8993F45CC1A3FFEB6BACA 6CF815DADCE91BB92C9BE218C4BD91EBEAEE4E17E302284B42FACDCC1ABA0C22A8FE7A30E401 6EC238B6A530112E7BC5371AB48E599F966C94EBDA672001483D1E35E683F93EBB02BA0F647C 6F79918B8E2D7C0D292F306BC366B9679A7A8A5998250DC90F0A752E5A23EDA3CD8B699BA875 E05D2B6758C1F886864764FE26BAAFD976AC47150B12B93C97315AB530EEF6A8F8D32B727F84 EB7C05DAEA7DF55B4847AD59DBEF771A5E47347E8A5872B4A2414EF8A4D1B37924BE9FC1DCCA A10D6E78817CDB99D5F42D5645454AA8D2151E48EEE83725BED583D358514F58A919256F22E1 AC4BF1CA50DF0F807470859EF15928B40B9C95B6116B1FFD997B32D93E38B128C9230D1A040F B8B3829FD409FE25BD28EA79BA3258B22F939D7985A98C8FAF502225F5100B3EF74E4520531D F8C8A2D3AC2D58E3253CB250D45E7E556DD90CEC4592C52D9156606C4DD6382BBAB9F31DCE02 BA08F28FFE973935DBF3C98DC25CFCF02ABAC24117B76E4792525848C321C47505D2FEED7623 6E9780014483026CC580F40C5F259AD273E1F24DB59B1639B1BCB62290D4AB2B2088FE370158 BF3C2431A00256C9658DD428D0DF17D1F89C7689E1E0C659B595C4C34BF20DE7F5C0F3649BE0 87B6DD06CFCC99E75CFFCBC48BB87101E0877A8FDB807754688211F442CEAB20069AFA09DB64 5E42B931FC22C739B14110DA27C7B04D591FF8DF2F8DEBDD2E8A443F37E7A75512ED33CB5A71 9E7082005E1F721484EDE774637BC948E02D3F6B044B10BB61A1A233938C3A916E90911328D7 3EEB236257DFE33BA5BD5BB8F51472AC89BAAF3F9E462F6BFEFABC6BB2A2A906A8E56A2A5AB7 312E2916065328E1E641C44336913473F2215707C8589C0BD6B3B8599531D10C1CF65D27567E EFF8C237141AD3696EBFB9FD0F4C7B4A21844B49CA7992D9A0EF837C2F3D3A2F8E2840B18968 4954F0957DB9ACDF6E4695C532312027093C7D0F81371452A1A53BB20114C06C068A7536E074 FDD44626B54496C92FF4F165B83DE07627DB4F0CD4722F4FDB11457FCAA43A82CB382178AB36 F347BAAE3251FED22CC067E92B812D3ACBC28A8FE180D155D9C5FBEC15659B06A82E27D6BDE2 7B009702E3B50797BBB275B2A60455FAEDC9BDC471A5851DA8196600C6FB6DECC045D3B2B38C AEC0DB9AA656277F3FA30F1BCB83147917E117A24514073D79F1BE0E5BF96B4D693349D78759 940EF4EA6B070E18870A8D6B2A0786D03F6012872AF771A623706A655D50D12663BD97FACEBB A4931766132796CE9409533394AA54084B952AD4E9E903F1E78A18AE224E1452E3EAFC9BB774 5131D76290E8C6EFEB4CBBBCD535BDDC3CE5A05CA2B4082AE44410C1E3412B0F6B7D85374D0F B877AD4925C4E51AD251BBBDADCB2CD0F5499E912E7D1F990FE5226CEF4CF5407E1391B5D4B3 3EF359429E92BEF23CD65434A96921B803C779AD7A7729CD428B6032147EB8D5820262B34A49 9B2F00E5E8D4A58220DD26BD583C474332F99F0FEFD5CE4967396CC85C8BC36088556B214FAA 19D7AEF255CFC8901B6170FFEBE5529301198328010992EEFED22015A09981E34213C4262351 738911A3C2B671357FFB5EAB7682DB8D397BAAEA9FBD77F82C0A79E7DCFAA3C6ED6883B61B3B 5111B88E2A942D7459AA5F53B51A25042668F5D5FF4A557301762A1D2AE18D80C484171D62E6 BD2C06E70C2AB20922247DE62912A28DEC4DAC4972F680E71E85EC91688DB753E7EE6DB6EE5E 8FAF7D27E0CC82F44DB9761DA4684F99FE3AC501583FFB4C46C006BDE1FBCBCCA4F3DD2CF4AF C0F291565180564913D487EBAF5A952EB8BFBFD3C6B4A5B039B9E7BA51319226C1C576E5E35F 334F7672A6F547A1F655FD7BE11DBD0384F33519E240C1E6D7190220F6B655234BF89916FE04 4B72DD365B5FEF3A883073304ABB1140CFF90AC69A1D97AE9C50BD4CC351C845C3948E2A9FCB 87F2008EB6CE3062850B9D62B9771562431D857DB4CAD5358CAC24C5611F0BCDB1827BDCC7B6 C3F11AB223EA3C628F9A13CCCEC21F9269A53396F580CEA765E84A2E35B26C65255B8C5A44B6 3A776A0F26951226838156AEF2CF8BF7D543E0B3BA996D17977BA5D485CFB7E6D486A5653550 1EF6A915AE5A9F085A5DA01CD63579CE067256494661DE2F0955BCB4D9DB4B3F80366CC82050 B10956B665F8EE8CE42FD744C123A7555150A08D2096F995592A208270271357BD8501E7180B D9AAC78029B6C34021474C4804523D5378E39DF856B0A472AE88BDE75ECF8AB07B83F5EF3D4C 9CDA72DB9E2F32DA943950DA10610D6618B3FEF5B75DFEFC72F64B8BFB700DA3C86594A8BE10 13C03ECB9C95DBAB90D2A05E3183A23280CD878A5B4DB7A6D6A47325B5DA70D4CF1CF8EB2EFA 7712169DEFA459545CA551A81021A587FFE5B8760A1A78897E9C9F34B167458AE9D6E56CA4E9 21620628AB8F73F73E174944623AC10FCF21644F64D7BBFC59CC02DBE0AD7C4409C6F66440B8 49668F7E2A0053BE5B5A825AAB22BB3434F7B2DA21214A3587CDACE32AEB83FA4A183C198C02 BD03648AC9278F3FC195E4E69B72A5CB745F081E32163A698FEC233F0AFA15939D940FBE917C 51CBC887E2EBD9DE24290790290042ED7F7DC16E866E5313A3E790BF7D8EA7D785E641054E5D B4D3FA933DAC53C3BE7E971C70388E6B8171A6FDE2055F3A8C490877A89F4790F57C0D61FBE7 8A39D7A0391C78C503AD0C38D88FA809F7B5F8E902018ED0F9777610A3D38ECE44C3903D9917 86338D7A9AC65FDDE2692C9344D55B1D9668775543BCCEF80299EC86DF2E36ACC5C4CB2B4B99 08D009E93D86CC368D00D4C5378D16DB76E705D5ADEFFE926658DAE283740BD3A89FD9A58C04 84537258493A0206FAE4E0BE0A29F79DA258C34801B4A43BCFD52E3569CA9C10E5685FAFC1BD 2F51DDC62F4337976463C0251737081A65516D01120E16EE8D5DF0B91BBB79DA0C5ED1EF4861 4F6EE3FD267346F3D2E27EB67A5525782F8317E3088DBE7B0E5F3A6511622457ADF255CAC387 F5C6F43FEE8E3B6376F840ACC54A59CA06239324D63084F4BC92CBC68C4AE84EF3E564022D31 38358ABF949BFCBD44F8844281223DAC02741A51851EBDF4CA1CE54A6B12735A0DFB27290382 D73A99AA9B3E6F6095F9ECF650A95E2DC65FE753CAA05A2FFBF69B80F15A6EA308D2BEE55654 263D6F89C3B5E221BBEEC02904F134CC2B658D48555101101CDA5F3A4CD7885F274D98F221A9 EF4B9F3BFA7A67E19DF1D51155116AE7BB81455C6A87F7B2F55FB0F87A2C993B6E580CB73D84 FFADE6F51C1AE0DBBE5F6C01D294D6A86634661692E48AE5F340F2DEDBDFC5C886CDBF5B9FA1 219F8A4942BBA3E3950B40EADED15480F3BD19EA73CD34C413E0F10B39302B1344C4583C806D F07025287630E2A058EE41E75FEA0DD30C5675CAA994FB6548403E4A974CB1C8B7E6FA451751 813DAA7A151B8DA6F6A83943D8C863A22ACA521CB48FF44005B755732CF460E576246923FB80 5EEB14273C11223EC80ADBA78310840E535C9035E64F74C153EDD5BC599B1A34CA78D097461E 96B316512232CD0055AF1432571BEF54A3C20B0821C1E70F5628C55FF91374C2DD41ED49EB38 A48CE23ECDE5396A1B067E1FEA6A3A76FB8D6FB64FA64CB8C0689492AEFB149EFA33273F4BB8 A54A81830843451E2249DAA708885617168901506D8847DAA295994F554F5A5246A7DE45CFDF E2A698ED607639CD8BF8038A936EA0F7010AF52FA87A215724A01D28A230C84AD8582152E0C5 859237D9B361733EE78ABF2FD1EF19F69E366BB89858BE92C3FB979215DDD2C3F05B9424D513 D8CDDDBA7614332F5F9D95B52A1D20EBD8821710A0D1CDD07272241F6420663959BD6F7DDFA7 1BEE74E03797DBB29082C414DCB96E0DAC42D630576FA4EACC54D150E3BFBFF35A28939BE164 4E12FD13F4FB0C05E89C0B58167E3D48C8378AC05805C98DF4F0F152C12C8F79EF93E5473BED 582362876286E71D119037C9E2BAF29E1DCFD46F5E5EC4B19E97C73DDE60D3CC50B696D7E62E 4312BE7587163D3ABC9EBFA9895535B704F7070D69F5B19E335E15EC9CE099A0EAC212A175AC CDF7C5312A927AA67473DF1F6F21E7D7467889EA082131E7223E4BF4A71271EFBF6102977DA8 54407DEE2CACB78146F78B23BFD7FFA492FFB3799AFA4BC88E686F0941DB77C845E4866B1E8B 5DA393B3D26E3841FBB7BB53E0DC558FEACAB01F8B5F7745E3BC8B823C5789BEE21493DF48A0 D8253B1DC1C879F824977C2AF5D39FCC7773483B7352176C0100F06D9DC8FDCC4B92B2EC113D DE787FFAA650308A720F7C69F712456B3A9F6A3BE1A4664FEFF85A251243AFB7E1748C12A64F 1C492A47830057C282F0825BBBFB73C82DC488C6D8A532AB60DA409E9BFEEF119A6D520FBEB7 BF4E561FFA8A9DB7E5A3FB8F177331EBB016D41131BF1F84B23FC2F003C248FA9F78DC13255F 35F5D269DAF722364DB47927F90E76DA79F7721B2C610F51DF3C28111D1463C44F96F6F9E847 31378BE592C0D97B8F2DB6E6F2CEF9CD3EF05F6AEBA16E02DA551D53D96B2A2976DF8E7FD23D 8B502E739D4B82C0220C6F3BE0C0F3EE31E3AEF001FFC4CD22D6E79EAAD191627A8BDECAAD17 D135E74AA817DBF43C3EE5923CC4F8B1FBA58F18891AC6BFFA484ED7652B37DBBF3AED56A2DA 5350807A71A369E08ACA1EEFED4BFBAE14580F8EE4BF718C15A0CA869EB567BCB97AAA3E0695 E5827274CDB917BD3D7D808BD98DAD257FA37D747C6669EE577C8FD8ABD025CE81BECD5210D1 5275B81236FDBA2740972C653D8641626C41DD2B72EA32393F3F5D8153D91C9C3A53B073FE66 9175FF999D6D07E9E306C98D1EDE9C2EF23FE83FB0A41F3981C62B4F39206946032D3D24A1FE 812088A332CB13456C8E25DC6787B4E2780893A3A4E005E10EFCB80A388A20D3CBDE094351E2 E9CC5913392A09B96CD320B23DC4992CC6CFAB53B513A2A9D044C299A3B2FBBD6B7F622CB380 1CEB1D7BF3AF0ABB5DA14AF5EC8E90DCDF6999BD1322218FEA4220E210FD6F81A21DDA2AC4CF 1C4DA55222B288D7FC9953751880DABEAB14976E8983F34F87C571CEDC1A3E0734E26864BEDD 4AA8A834E348D83D2B66FA86C1C0EDFEC28592283B075E85AEE3504593DFA740B82B292853BC 39348A54E93AB0A815742535A382B0FEE5B552F0F02366850F97DC9FCEE811B1188FE21663D4 C7505B7F243A9023EC54E2C2FA4E5800F600190C7B959AB5F0C67C82C305A2EE245B6D4EBEE0 A862D577F718CB719212550133120EABCB69F88B45CE14BDCFB88176EBA9A02797B395B022B3 99C6DD835C093D6C4758913B05C3D6340935E1E54DF4B9A2BC85BB6460656292E8FC57F332A7 E3D31EFBFC21FFAD5C08579A27AF547AB338BB2DF92E85D22B16903B3FEA1834B23590A2FD70 568F6E4D979B52879D12202BC250D9F59F1994E68A7774EAC77A0B43FA04CFD024E8CDC496E0 7DBD2B1939278DBF4E0BAB271F152470E8BE9190F39DCE106C8218AF820AF686FE79BAFBB0C2 A9FF956A72E9639268DBD561AD58660FEFADFE64E26E112E86619DA4114B7AFE5A28BB7EA87E 8D2A4E10735F5092B411C57605C10D38C1DF81DA3799C08C03E24827496CC88082FF78209151 840FE9C741B9B665495D50AF95DBCA1E04B84A4E17E2C25BC7A2FB1F8819638F852707E15016 157AF20893D6E9EDBEFBF30937CA50C7C6E7D389776E5C19FB78AD37ACF1B9E09C17E09358EF 3C42ACB14892ECC993D208624B3B8267962211E762E43D40C8E38AF8F87FE34743B8B3562401 DAE7020D87F0DC8F1D4C34C7B0AAC0329539F31C01C8BB434AE4F79CE6A5A1143621F71ADB4A 9354DFB795C5C078405662D58A1E9A8EBA25B7BB1B10A699A50BEB3D53440207429D692D939C 228D61F31B59A8E30DB0B661D98890E4F30C9D60C8B8E5BCBB61DA5FF3C5180CDBCCAABBB9BD A0AA52B126E408F0640BCDAE439F4EA033BF794282C2E8D11EA81081FFC0AC7C9860B9EB2E24 CF7BD764ED6583479F5F69809968E1730A3D520666A78CBE0D9043DA21AF1BE118B7C361D5BC AD5BCC44B1246E1C23D51019961BBC2C8878013F01AB5663F88AF58C122A720B37A58FEBD448 DC9B7E5D0CF899D4E30821E52C6E813B0D35BFD25E77AC15DDCC4DA4CF088A2E09634CC3D33F 0E5E01E64AC6F52A878A687EB5833F6603170E8A95F86612E6C64AC4D454DBC792AEA828675B 04B3FBC2A516D6DF08A8E6D5B2C4DD184083F7CE348FC6E00FCD2FEC3275B5B798998ED7D82E C26ABE6B84C9496669F6B91B850DE68C93D8C88C87DB649260899EA6D47C511DC61C55698B52 5D9AC30A25137A131E81D4C46EF4D10F1B22B19AFD9A25B2275649C2E0A36059B9112C3CE9EC E70F60BF199DC446E98298CC330E7C9BA5CBA216324AAA0D716A85941FD89FDC3418BBD50E6F 2065CAFAF0CB8BDB929C9AEE28C7ABBA000AA86878ED57FEFD9E8EBDA6FBB1F904434F54C8A5 23B2499B1976D751F39445A1B5DEAF740DC6167E4C686E57C85C9CC7928E81F5FBCBE180E351 58B0193C4A9366913D16F7CA770C5B339F767D1A6B78DEE14C41205024CB91C022AFC8C50E7B 46D599EC421F7932FFF7A5658514C04D79CE7888CAB8C0C2EB7AB618B457F7C87F3566ED1E6E 3A079B4138DB57172BD5749AC5E927014D994345222A9471799E453A42D9FF5DBE1E667D3330 DD78C367FAA10F4CA07BE0988888799391A326531D519C737DC4239B17C8517F0DA8579CAED0 F4435C49467B2DAFBC20DBA54DD3F1817F640B4102DA5959943291A2DF95120179030BEF4B89 D00C97589383C4DB1D12D1B0AA92644E331645C3D29D0E627EF393F8548DFA97BDEE2562852B 048B68DE53C73A34F6BFFD46B06531FB0DE9BFC1CCDACBC0E01AB74A7E1080C37DD61CFA5692 5977DEC172EEC9CEC0AB77CDFD5FFAB6BB9EF1D7D09E577E957A87899F231B07D0D56349CFAD B9304F8F0644433B373D652E961AF6E3F144076D0C64DED32EE2C4161CD1DEBECDFE672479C9 9500FD1B830202D5DEE3EFEC8D4C0117110626DD178DFCCE0F4B223410C3B27E5C1B4FCC9575 D2B54BA6D147912F88A301AE52324E8992F359C81DF160C062F978C70022C9518F61E3C0665A D283858A9A5444E48295B744A7B8361156D59AF3AD40CA71D441F3C8123C06A2CCF2854E6186 415ADDAA381348FD5EFC7750C33E9C7F4AA936F0BA0CD58343F1B9FF545138565223061ECB76 81BE43B021D629F6B11CE8D740AC875C5DBA8D4D1F241DCEC7B1931188609AA3246FD1AB4F76 A3BEE835B9BB0A0F042E2F79F49278FDEAFF07DAC5A3E697BBCCFF1CA9C4FCC3D3F0C6DD57B7 C30B241188D0FABB3C6447BB5F64776AA3270F56C4240A9BB282CC4F3B7EEC6A4C76523BD82C 603859E99D354B27151E90D488F1B38C89442C9066CFB7134303112CE4A49DC85F1D730C97F8 82A561906B6AB8701F90C79DF081A21671E7F4353B34E744CB825DE60DEE525CA9ECD73B2632 7C5CE54322CABE4FEE57ED2185C6FDF42BAD9FC37844B280E8B7B4FA9D0349C65BD24FEFFB55 DED55CABA317031F48F1A15710AA9B7B6B3BC1962C3A430B02B1DE05283386ED065946063D1B 469F939B3E7347C0E73E00BB1286731245F90573C9C81F478AB32F995F8DAECEE22982B2693D D0B0C8B9E6709C45EAD5C03EC0D56CEABCB52054F8EF3D81AD23729A174872535435165358B9 2B8A3BF046235333244465DB7D82EC059C586D7120C3166489FA8785FF7E7514C6307B477A7B 5E1BC04E5A40AAC790038E462C5B9EC505DBADD1DF4A91E4C4BB904E24C4D15830E9F83A938F 1A2B9640ECA597F78C330A2BA05C1BCFD0B414A70EF2C6F36971E77B9BDAD5B2CBDEE001FCC9 F407C6850468381FAFD112EEE30C4FDCA2349C940D22513C88F06E13E70A5956F9FC600FEC55 FE1C4A902C2C97618E6C5E10EF4C679296F5A1D076B78E365D947109D928D641C7CF8AE98204 6DCC359544BB0A031D21B0EE902FC526000D1105B30C4DAE93D2A00F9235A299978F22B7F596 9E20B200DCDD753FC301187E510F04A056D0B7DDE478DBF963CB77E3563547AB30CA42B02DB1 F3EB664B99722AD0BD3C68DD4AE1777B80A830CDE780E2AE13400ACB0027AC9A0B929915E196 4A4B030A15622071D62A4BC379CF1077ADBB17D870D641355F6AFF1180318BC7D00ADBCAE1CA 6B303D6D96FA5E01C48D367B0E161D37B64454E292A04F62A49974ED6A2862EF0EAF918F481F FDB142677AB8C292C0CBB170E1F5C61D52198EED8B445DC1806C424AFF7FE410AFFBFAD628CC BDE0D47515A3F76A0A635234FF38C200D43E64FB83565F8EEEAFED18DFB96C9C0F274A0B454D 1337C38F2DEFF120B5D96C1C34C470F5777E975CB078FB20FA4C64D5BB5AFF659949F7343457 4B597A5D5339F3AA378436360B2DBDD1312AF74F69655FEC1E0C54E8FF56AA83F9026E9D700E 6D07BEE86247803FC034EC026CFB805D8E8636C1D26629C1DA5820F973D6166AB3A667157FBF 3C111203C8E2AA0047A88229C584DE59E855690095298F20E9D5D5508509A2EF415B3D5D57F0 488CAE89785404E4FA2A952F812269E688E816E60760B864F03B6418E4A60E173C47D30DD5C5 D830A6C2DD7C033C283ECBB3A3E540D1B0411218E68D15373AEE1DCD3EB547504BEC9D409EE5 AC9BD6E25595B85BC081B63B8DDC04A7A73AF371E8B4CE4442D7E992D699B98187DE6EA37251 52CB1096CE26CBCD00F8556F280E070E792832D788079AAB8E19B6435F24AA5DF6EE06805FBB 10EB523D87526815958169FA3CC5023504BA39227BA2BF9BA68F7D2CC3D35E55E9D4D2E43F2B 1DCE3D4C340C1DDD30544A3B5DEF7C8AE1714B761D9BCB68BA2069865579E94C5C4F77C536CE 296DBB8591A9992E6B094B1E880BB3D386B62EB79AB2D2FF5232BF209E9492251434D1D1505F D4ED79BD3C5857139105E19EBA5291B872E9B521E605314931E4A6BDE8E6060483695E9ADDE1 D23A1EBCF65A1D70DDD30B4BDC41ACD776E4FE6F43562004D2C256A19341D8BB460569D0DC29 242082F57D911065EAA0FD333B1F536DEBD235510987C1C211AFF2CFA09FDA26AACE78EB9704 5F7F79F0629C29DFA844E61F1C908B25B378091B69A4631B123BA6357CA673747B2BADF8D7AA D722DB0C3C7F736A3B0486351B2E09F407F9F0999BA41962052F6A2BE21CE7F50F2FB327D4E8 717A6EE7698398164187446CBC66ECF404154914EA0B73B50079A31FB772F7B2F69C5C4D91C8 15FA0D16B80AF6934B57203D09C74E7E2AF81AB8E1262DA81C7D1B4AB465DCCE17702093486D CC4D1C2B42E82CB1AFAC08074E828C10FC504C352D555B3EBC718B177B453CCAFAC5F452928D 2D6F996ABBEA6F56AEA83DDAA2572539C9387BACB8F51794AFB53D8D0600A57C3F47068B7DC1 C87BD6AC0109E1071B08975D8C36A7622108873C66D4DD5F94ED291CCED279613F8E5D781EC7 9C45841AF61B11D4D63E9E81D0A1CDC746D5A2269B8FF812F360C715F72C12A95D259E9336E1 893B0B63490E45BAE5B218D48D4FB7F8AF334B0C8868E476B094718F125314677F70D55D8270 665BCAA9BF61237A4A51E538FF77B64AFA102FE54B2B376AB91FAA4DB74EBAF5A9E7EF7B3B92 D7632C29612A14F97D34BF6B0B350AB70FEE1D189C0B91565CF6CFD2B127F74202910FA0CDA0 99BE1AB21DF0790E11BE8CFF67E5D5F532C28984BE7F663CBE2DBD216EBFEC440AE57672D73E F239AB13FBF96F971714EC97DF0A817DD554F9C8E4F5D83097635665B9F9ED9FCA4B90F2F7C9 1500405E51709FC23339173A7AA82BFA6855A597407794D64DF5BC6BED7C9BE5467BADE6CBBA 350CC97E1946B831DCB9667EEB0F765938A366F0A2E9EDF7B18462A7562B16FC0571CF134521 9BA2B5DD81ABA342E3D5E669064558AF03F193BE70859357CF225BE8F4CA91BA6FD586FCBB19 36EFBB98CD53F4C20C6356EEABE99AA6EFE12344ED993F6900CEA58CEAA2C3CA11A9800EE66A 77F166796E50CF91CD03E7549BBE8A6DD164A5030601C38C4E27C7E6646241F3D7BB507B5768 30188BC6257B6EE2456D833E4DFDCA89CC9D42E9D633AA37FCF53B1FA3082DC71F07645C36E7 C28F7FFA23D2ABC86C35D233DB0D1A9E294D26C7735830EB84BA4A1462AE05273A1857F7B415 1195EE1544A159E20CC9A3D02D5080C1799834DAFDCD3519914BACC3DD0EFBBFC9AB8F5C642E E43A0A03DC418E30C692797ED182436FEB233D7DF3CF503BD04CA23EAC21BB125661A3486C63 3FB7DB486D2C92BA706653115D1CF76534161F2C0787E2DF2A7D3B17C25EAC19BE80B13C9B64 2E947BCEB6068FB0A784CFFF5ED7EDAA0ED85232A17843F3B8EA51869F928369467A1C0DFCD5 2D1B8DA34612ADDD5AB8B0DCB43D7069EC100F022DC0AA8A58DF4077C9B51FEB8C83489722AF 993FF35EB326CB03F366476975220493DC515C8B0E81E9E4A10C08A299A060A59D3AA36552C7 1DE029ADB6E935D83BFC60B4C8695DB88601B7175772253F71B47DF4570EC3CF45CB121F17A5 7893CD830AA443BBA910D2C17F16B92E97DFAB2CB1B127FD4301B4FB8B7D252FD241A3088EBB 74FE703AAEC0C4FA72750D805110A6385E63BA36479A57EF6503AD517D6068E46CD7CB598D1D B4DD9159099A971DCA8EC7B541F53640050297B51E7DEBDB6C8255D20E5A9002E06685981F70 27B83292D91BF860DC74FD97035918480ADA40A1CC39895717FE28F5D2F4287AAF9CF7476186 A47BFB88E148C84DE9252BA906AB9173C40E4260D753C2F26206DBF8DE9DC9F999DF84E14B77 EF8451C83068FF946A5BADD00C3FDC07898D356314F8174CE325CA1104294E3C04C1FE78BB87 C24F7FDC9A61A47839AF3BD717FE9A406AD590FF710FA3DBAB5A8C2C8D5E209FD764981F4F9B AB49C7BCBEB6F2FC6F120D00255A457EA8883E0E5AA8B73DAE41235D9CCD14CC870209635C1E C5C8FD4F1D3C8CF5B46B1B29A462A73EE776C3C4FA8BA77A96FF8C5E53CABAF07BA97C1B9765 98EF63DC102AE8F4178726ED80A86007ECDD4F1F2DB902A914B8713B267164227B87970BC84D ECCBA36FD9EC1541D774476BDBD010D056E919E324DBB8EF94E6FE323B74D823CDC39BA65DC4 CF79EFBD53275847EAD4436ADBB90A423EC11C7BC7D5F92EE8BD1185A6AE517E5BA092AC4DC3 65CD09B76918A17E47BE0ADB78DB14AFED185566501EA8E700BB8AB39DFBEC17FABD673D0064 8C7691C0B70981292C10E8C5685454B12697F4039B7A868E7500AD0940EB401405DD2111261D 76F6CAE355CAC9AE1D9494555540B3F0C70E612B62FFDBB46FBCDE3D92D789BCBA8C191DF73D 1B3664AFE893E74E061B53957FCC15651D7C8B2A6BEF972745DA44BD7C5E9E1811CE0B226EB8 A0FA1D9E65A5F7A67255E5D869B891CD2A7048683443BEB68F6F080FDDA4FBDDEA5354BB83B3 A66CA4D6222FAA71E961BD7B8D8A40EE15AB6F8E5F08D0C8CD8101F903FD01448A8F8AAA5ADD 78EBCC4CA1F1CCB3F7189379F1B8C78430471916B7DE75FBBECB451B4C1552971F76C77FD3DA 7BD8F4219C37EDE680061ECF469048E7AC2FCE74E9390FAB831234E94160A8897C22F410EB01 3749E0B1E31350D4FB24D4D1E42AFA8B560667E90AD4D3AD433F7E4867CF8FEBD10E897F163B 8FBD4649CCE6406653ECFC89E006D7F53A198313D2D70E44ED8D6E1AF4D028A2BA8B56171BC5 81A698A8D1482F293F3388E36E1295F70C016524408EA17B8A9AC5E5EC2CEC4A17EA1D4A9F95 87DC738D2F684F4C85EBA085729181FD6D492468C9B75CA04893BF655A536F7666666A54E9CF FAC2F7CB1FCB0300D173BDCF967FBE99FD66ECE5D5466E729C2CA6D649910E62C212E6ECB391 B5DCAFF8C2441F78C55D7A4522DBFB9E29F594D6D046F302F2DF18A4CCBD0FB9BC072787691E 3CEA1958375F9E693F6EF181C515254718CF96966EA02368602DD5C39E11A3C0763A3BD1D948 E80C085CA48FAB3C91BB1EC8952684B838A2BDF474CFA4F658BA40A551400336A3AF4228ABE1 26FA57C0BDC176274EE8A943482D3A883909006A8A4EE589541659A3F79575F0F80525199F52 2D6699B2E60F7D42D0A6897DCF801560DCB7285EB868BB90734412B0BAB00627CBB051A95544 9AF1A1DEDB97B169D48FCA4243C0DF6F630CDF0C6CE6C595609E6BE97A15D4CA210B2E10D2C2 A15D005017BC9674C8ADA52FC5C601E34FA33BD7976000D5590E8BA944C5588DD09D2739D54B 90E04C3048A9AC893177CDF6CF915B1B117A467D9DA6240E06621D94026ED305BA951037B0C4 1B81AA5F06119AB3E0D7A6C1D10B1ADF3C76C8BD7CDD8517D02C710AA48B42A9B9082731BA53 AFE1BEE778B2A14A3D8411DD9E806693C6C403770474BE70892A83129C91450A90A786EDAA5D C7F5F00A30D991045C7EF4929CA7BF663BA9115D9D32F2E65EDCDE9158D803385A8B2CF71AA8 70F4B05B475AC88C76E29A572A20570BC96E21489DA313BB670B6940FA8562BF9AC584312EE4 973B163DE0E417CB32A66724E8617152661666683FFF437ABC531F8A7C4973859A9A97E86CA5 02D9D4F63BE74048017A9E76598BFA5A50ACC823BA92740D9B9260A56E2F2BB7E64032E6A79F 017800666BB51C2F5CCA5B3966E7C608E7F9152DADE0C782CEF7DC785ADE657AB2B792553578 91A94C95319C2A385B766113ED7D87E8D74FA8FA72E163D54E07DC638C92570F5CD4C6CC5EA6 9E5B2D12AD68815F37517209CBF56CDE3B15C20D0A3F42DB87574EBD3F51CE770556E9C641AB B7E8513BCDF9D630D15F41F7C55CA229F1CFCDB456C9C45FE13C4144BAE9ED1E62C68EA466B4 7CE7D1F2BB3573E6E382E01E637822118099B18EB6B9F4733ECC2CB1FDC22065AC4C480B354E 7ACCB3A2CEC06E1D32DEF08CFC567273E3A74893688F767B86E30B2EDF454842C0B96F8A1721 050B7BF33BFBE167BA34D63F381EF5A35351BE8D7643A89CBC6809FEEE622FFFB1B7EEA7B1F0 D140930BBC6AF4AA6B9ECD64CC6FB79C999B914EB7D427183D41BC539A38E903F315BA6627D5 9FADFF710A81B23A5D684993DF1E1ED04EDE664F05DA10E8601FB33909C1A9BA6CD1CC544181 CFF9BBA596B0B0EFBBC7542AB8589BD5CAEA7C4FDD0607CFBE48AC53CDAE2944B86DC0C11986 5F916AABC627A9D20FDD79E8C62CFB3673BD29EE23F2B9BCA08467AE907D59F3FBBFC238FF23 B15303E623C9E6DE820810E19B47A8723C2B5141F3B0AC89725934EA7080F90197DDAB0AD4DA 98907EDF2464213FA29F0B14A9A2BF1920C7908787DCB5500AA7D27DA7EF5D15C7CEA19D58DD ED19854D37D24F4F863C02CE9348BE6A2214C728258F5790104581428E33502D34FCA3925ABC 5249EFD1372FE677793561625B75BE1FADA5AAE50B38E657DD80AD035A588C2C6F666E55C876 9A7932257B25B526F831AFD78B65057D3B6D39626D3521D2920A9D2B5BCAC0C684896AE016E0 D8BF361DC68FBE58BBF511E2C05F603AB07BB4D417A00F4A4FD0307C6A5FB67702B1B0678908 90EB03091975CD4E42269334A5E5DBFD776B35429721E589513F1312C33100FB9459FCA71766 0C0CA07F4EC7E799DF7117A096B1A5EDB41BD85C193FC11AA642CAD84288FD41251DC0D1871A 970FB66CCB957EE0C92F1CC4A1D5AD2A54595950062D885B4CA0FCF92C48F417E79D1A27D181 32C4BB84D5FA007ED0A38E16740D9638C264CB01194CDF428B840DDB21DDA112C352AE4CE983 6F303B4A68778FD10820A54AB50A0299AD7E0C75FA88CCFE3BC240A27509A3623A57B35480CF 6CFB39A28ED1945745C8C7D250140CCCE794B0D93F00278CB0CAD38029B0C9B723AA80EFA675 EE43AFA3EFC4384BD524EE051D27ABD21B2E2D6BFFAF1B6F1FA258918CB65FED56437EACC243 9B646FE845952AC70248A9CAFE886EB5C2083E9434C75A5C6D79BD250408CD9CEE45E3E15EBC BB635246B7233380B7FE8B1A0B18B678F4230808E48BBD980457CCB0CA8550F4E01FC89EAFFE 011BD6787B63AD6C116800C622B3E657B485D87B839889F071C2988CED7786AF2ABE03212AEF 97B0FF6591500014B0A188460F814C3C67B1A1E435D6DD6A1C748505312678B85B7AE9EBB880 CF0402EAAB49539288DD1FA78A8B00D654FA0E778382FC372C235B69D5D4AD284FC8B1A1F9D2 A06E0BAA7B99405BDBB7646888D8902F907E41036796D5CB431478DB858B2A2693E56377905C 30890C13B4FD088BD9545EB2E57E0D339BFE9C4C5A157E9856EECDD95C7F0008E4D802458FA5 E77EB7E104970DA2A83EE44705FC4B6AA2638FADCDFA8D041783A5E5A79518A9410A4FCAFA71 30A0A022083C5F36BB8C5C339E9F39EF79C8DCA9294190D02AC32A1395CDE6B35E1D22FCFF88 5A809AD1F94E9AF767A7CB627398A2043F93B42947D5A7B61968224A7585376E6409E98C091D 08AE8E9B2761C995709E7F2C1FDF573CB660392DFC4B9CD5CEDBCC06A3BD6873EBC39C07DC0C 067B21673B9CD246144A478BE0FAC9585242F0938F142D24ED5F6E2865238A1975A09A45BF8E B110BA16EB33E514B3F4581B2BE3B2D5CC58549EAFF5D9936E2102AD13BA32C32CA9DB3CDBCD 9EB5B7AFBEC3168BF3A4F8E52D3A3A178A35E152F96D619C75806DB974453800E4B2A546052D DE37A3588BA43C171DB5078C64557F86989C769655298EE6A23FDA1905A423EDC6A69E4A81C1 6DE852B1DFA65B4962151651169E33CE04D79600C1FCA9494533BD2B0BC117C2A6B920572FDE 2C20BDBC750C4591F0C3EF957328B5C38740853E13C4E525D33C3CA08251BB79C3A274A448CA 4AF4755FD55071D0A4439583462E66E434A0E55750D02AE2E56F72764BF88553DD1CC1AB6FBD B818794881272D351E9D33DE2B6945CA7F48DC9E7862840C07774CB0ED9012E1FC428F990392 753956DD8972775A1BC32917A4A79426FDE3B859451D6820B2D27B056FFC8D779D8158387949 CE1EBC9E660482C969A1440006E9B0526C17A8297D2DAB83DB20EB4A6E043F8D19DFCA4BC478 3FE49DA57F99776F99C53648371D88C9FAFD33481F3567B9F5000D2F631E8C9E9EE72F712298 A9E19867D22E87628EE8579F2EC09D6FA836D0011C73C2C7D8AFA7F9AB34C28B8D9C90CE9E41 109B24035477DD75B5DAA912FAF4841E8B9916653EB0DA935B54BAF3655953E0A7DB4901E7DA C00D01C07AF44A7DD106FDF8799A1F9DE4AF629C6A9C8D6ECCEFD0A44FB6718CC8A198F79BD1 B589F83B3CD92A95D639005D60C221F3829BC4E113D2FED0F29740A7DCED9154E2CB6B02678B 9F85D1951E6EEEADBC4EC7FFBA50C87B66C7D45D217A0A91263D15AD722402975CFC4B90B2FC AD630C2AA120FD0D6C263BD63FAF531BEA97993E73BB629D35DDB106B8EFC8F8124F1442453A 0586245FC6B44E5316C2A291A884302F750C2120D3868EB1C8C4CB62799DDC1DFE62B0C4D800 67207C194F3BA90FBE6339F98C7B1DF79487144E28DB29C57CC3F275BD8A66BAA89130F3E16F F9162DAB12C58C3FD9B062D4A8D0A4C215BA14EF1D7ABF92BF3887930E8A6099D54DD502AFCC 2F2FFFAFB8EFF2298141E7D48E671D99F093F0E7ACB5FB4363230758D7B81CB86B58E762FF1F 2F20DF1F0DC33DA8F618E87485478A97145C83D0C69D741A545CA4C91F21FBA87B25EE14D0CB 51EB473C1068225EC32200E7D4715E03742426CA000EF3B6E661A63C7EFDD89D687C07B86831 51C316070399C1AFA39576ED47BB18F999D06F7B0BCFDB35E9F2F6D495D4FE3B402B4FD6705D D5E2BFCA05B4220A360C9D808B52AC98D4DDF5B6D853C2AA82211E9D0F96B2002375238E1586 15FEA9A161EFD7DAA69B82EC279CE440755F57BF63B2079044A49FA5889B5DA2E800FBAA4793 73B10F93D5963B8FC6E57A34B3FA3E1C4332037A17B5282CB9A5160AB0D17E13D8ED1617C258 10DF28BAB41FACD21F31114A01DEDA3FF4199960B84A986DFBA78667B8E2CB1B47E7D3242FD7 C5AB801D2A0B7A133DF86291AC4DC49A4660230D90BBDCF739013D4F6CEA79A1216A8764ECD1 147832228491314B147EC9C8E2F993B940D876767DD3E7E8AE360BC5E6EDA9EB6308F30998BB 600B0848D1D858AA80EEE4778A7C3EBC13408A24A4EF51D013DC85137819E314FDD0184937D7 FDAF472D7FADF58CB0FF3D25ECAAA2898E391D93E993D24BD902C559733EBF55116D0D55D9B2 874CD649646E61C5461833F62AFB581E6012C8930ACE1C2A3CE51BED10266580B7414B543F7B EFA58E741A746A989815E25D20F104C081A7839C04D2F74EC149140D621273F0D9A5E9333278 612B73DFDBF108278582EDF0010EC2CD26B62E18C0CDC5ED5F9E29A0DF2055A097517B174A2F 92F614ABB9F52BB19ED260AA886E87488D81E4FDB334B2E5C882D8E7BED9D77AD1C7FD6441ED 445F04280E66294A259F8BB54CD414E48845C21EAE82337DE9A4566D5BE0952F09EFA6A9B4F0 E9A0D7F22B4824A1894C84DB3A4945E438AA6018FB67FDE9934327D47A4412988D21C7DD19A5 916D467419EA0F28E49816F57FA749E541D0459D87338BEB777E923EAB04ABD6505F69FFA311 267FAF0EE5CE0A99B5E60A89371A0906DBD1687E278CE40088702B3B0AE80802F1674A465EA5 2638F46D7D86A287AB78BA715E3D42FBBEE7C8967707A7E25DC9E0F309F484156A0FD2B55941 B103880E29B7086D604B666EBA5EDBFD91F0C80C15CE75665FE2A759248CC49CAF11DE03465A 564A94469A9D9021EB7055AB79B4A2CBE984CF5E5EB6A8A0B6EFD6249BE428788A44A92A077A EB1BEF546F1A1F003B8DD3DCCEDEBBB1782D769DE4E2268D8AD88FFF96433426365221699EE2 DF551789A3A11BB8CF89C874F7A97F666D609E14E58802E176C804618D14CD07D79BECD9D97D 9E1852A631B585648AFE1A4D3D848FD2A514857D02B817CBB6702D5D654955A39DE5AA1858F9 BD8DD56D0D40C64CB26BA9A934566D066D79F9D8C237786964218D794DBB39A1AFCDE7466F94 E2FC9F819D396DFD8784BE7FA5AA12DA11CDD6BCF74CBF8843C029BE70E0CC67974ED1E5B645 61EE9D259145414B51B07C362E710614B778BD72036B502A3791D3E17E1BCA74773BC1488F8F D87CDF23412C53304618365A06A41CF545FCE8A75F8882417E4B330738B5B6A008AA681595AB A5EB562A27D9210185D4006CF27AFA035ADC7CC4A5BC12FDC17D186DB3089B6524177D822459 5665415B277216BC8ECBB1A44CFD285CC550FE40945F809AC2C3BDB2220D24001A2D1781F860 4C4EFBA8CACB9DC84A986CD8C123EB82E8092F1D244690AC562B17CD2796B34EA1F8FAA4C1D0 1EB8630686259468473F5B6EF4553F42A97E5C90987D47EA0E0A582884037FEE85BB1A31B0EB E54D4BE1336D2EDBEB7073A37EC6A171280FCEE583979C4EC7FD555496011A983DCEBB1638E7 1A1998A1F46963637D15881A6084CA64541F18FD2F6BB1A2D6ECC2C9FECA9AABE5528173956B 8B1AE9CD064096DA93A47451EABBB6F66871D819348FDF933F6ACD6A1665DFABA9DFFA45AC7F 19576910EE2D29B55893C1C37C96111A4309FE3867982D442182B9EEA4223EB0AC1BF024EFFC B6B763F89789F2CCF741837E0D070CE490C98290BC3B7C1EB0F1F63897E97808395955E21DE5 D901298B8369941CF82758F8E50706842FEE4D5D3EAAF5B90CE83E28E102F0DD6DB09337B68B EDD79043C9ACD85456970ACFC4A3A7B5185F4CA5AE34292ABC51F08901E81B9305276A1FB4BA 7B6FD947D8DA0C247116A567BBF53394146A5C4F83067E1ED282582302A1910A7B9722451B60 1F86AE0F15A02075E9109F4320FF3C8593254A13C98C1E9E9BDFDDB990C5F509D72A9AEED360 D907821438A9B0171808E8A3D6C97C53858262A942F8AF989C42A59934C6CF38500FE955EA7D B23AA4A041C0F9FEE2083A1A7F80499191A5EBE1512E1FB59F6F2AF9B0A554CCB018C272B8B3 46B56251222CE57388554B40975B9077711A94505BD9437BA3FE1705ECB8E39EC490F5597F8D 5F3BE4AC1B544C6003923764739E900CC9AC92A1CC521A827EF69EA1144A8AC65A817EE6F9E9 279032D3EED5BF37EE84434CA0F045A292A8EF703C787FB99196438E79281F4148B13C6BFDBF DCDF079CB53021750E8F46C18EEBAEF2147ED9B6C743E349136F41D1F3CCC18749CD0BD08C80 C428C7EC37FA7ADBC24E31AC9A1DC0AB67486FEAB6DB8F8E25AF5564C2C43A64DF503A69A1B9 5FD86BEE84E8B672E34AB2985139024E58DE8B94740F1F4C7A68FBA709AD8069658F6D4E0DC4 74063F68F61F877E802BAD74E5FFC2B57639D6842E80EE741F9F659CD28ECA3976CBFE947429 51A0060705BDBAF15AE41E883F76911F7FEB57955E0355C301594A7B0F6223B603B94F201C43 CFDA55003ED5EC7372CCF2DDDF64B129638F12113E67A0D9140E7111F2CCED3E9A9B1F909C61 254848174B16CC5B192D48FBCCA707ECBD0F2CF43BA2819CF7F5BB74AAF99A37B56D7F6181EF BBBB62E18C26B79B691B22AD307DA6820639CF96C7A346EA38A7DBE38EC4A9D102976D8EA550 D1C94B32C0EE1469F76C3996CB82FFFE1F2571D96F173A6DDF5CB9A5F76C977DC9F316F25FC4 61040D8CBBCCCF9941D034F4ABADF1630DB3CFAB2B20FC47DB8D06B7E1846B518CE9E0C628D0 CAF7F80D5FF7B1B1DEB5018675A0FCFA07A996F3CD40B0F792338FA5B63131C88B2DD26ECB7D 0A97B28DC6CB48F50B02A7C208DA73CF5377C561A6E8D78AB59C282AEA1DE094EE74EF5E80F9 44025F7F9E00380308D75DD7E0C059A9A7317A488A007670BE08D38FCA8D197B03C483FA0F46 1EF4806CDC0B23F10E7CF09ECDB1395A1428B56B4EF3F1A89DB6FA66460DCF1ED1A157BCBB98 084F630377A92FFE603374BA934399723457DA7D0253863E7C8F5E3CB01BB74BA6753678EC36 6CA115B5836A1BD43155F956C7F107765D8E746E8BD0E11C2BC4F80EBAC352D85CC09EE42970 14D8791D481D2E1C654F4C267FAAE6C46D9780903DC788EA32436675CB65F8833D340F58675E 8731170473C45ECBD5AB02D77E252FEB8AC276D505EE1343F3F5F1046F29BF706C4C3F52E024 A0DBB4572AB187C8503BA0E9EB4969F44DB6068ED207B457896E9FD05411580988166437D89B 9F3AE0D16CB87A94843639CBBA97A156F8B07BF16C661F6F4929EE7CF184ADAC2DA87F2E7E90 BA4916B23CE8F1C6C3E452533BD39F9BC14F7B3422DBAAB75FA96C5EFA4B0CA4B1813E5D823C 4592A0C54320135B9E8FD92D9F75CF800EF2EA5AAB64149075C40617D405084F46AE813A6F78 F29F34441614BCD95FAAE355F771F53DA38E193D9F9460CFE4ED2F38918056DD5FE1C5E25394 5064B5E1F76F6E48949D3C021EC198E1AC5AED61CDDA8FDF39A3C121D263391A602163DDFA46 3E6749B01F4EDE29600C5FEA1DAFCD849F51AAFD04A0C8A504915A8CACB61FFD61E17C9B0EED 9590909B765CCE927136FF1FFB71D33A18C626AF34D52BFFD9FAA9538388A139DEDC21BB04CD 99173E96758B75E8053A5C27D9EB7A29D0CAD4F055A6ACF498EF1765CA08D669898D9EE0F30E 9BDC5774B83D6D7EE498997C2EBBA9D2AFC5251BAA4899CD0B64B543A67861314F4CA2F667A4 94C57C209AB2AF7EE8E4E5FC0FB0E24235F48D83CB44CD5D833076499AD6BC5FBC97A5F2ED11 731AA9D3146D4AE8D9E79D316667AC445EA9D63C5F2ADED44AEFBD382B7037ED814DEB9527F4 5E58047F3B1B3FCD0BED6478E17BD4DAFBD57F365B977FEC7D94BC31EFC2C1B4985DDB28705F EBF645E10124CFE0F1348B2F99073CF2F910AFFB284C17B436008E17E75B1E12D3A80E4AAEAA EC845628EA6BDB454F2E04D2168789AB27215C831C9EC510D46FD73821DDA2CEA3BE3CBD56AC 3C6527C43F233FBBC3FEE7D97EC19E9CEF7C98C0658B52AAEF32B5F053B6E1C9FAB55E026680 2B34235FBB374A421BD90722EC6C8455C3F657260AB830A1C32E8A04A159D8858238E6FA8525 96CD16D891BF65DAD55EFD61585FD7FEE57FBD8398591DE62535BA65B3B13F37C51F4E927100 5224ABD38B47F488A0E5A7EE5FBEE849E839E5764636C3AFCDC52881C7E187A46974B8C9DFA7 B27F01197C9660E0F489DA5FFE4B1000BC6290760B02D74FA0C1EF2D5BCD4E9B2C6AC41E3B76 3C946C2C648E12962BCF5BFAC0374CCC1F3659F91EB9821CADC614B4983C9C7AABA083E35CAE 18559FF42FB6A2E80BC8EAD7ECADAD0BB19D090067DEA2956A597AA9E5DF460F3E9B8E629BDC 1992EDD41A3277CD5808F2DC4B8C7FD9C69F08867FD68689D4BF50E9505E505AAC5134563675 72009E9B96E7ED4BBB366D08C41DC44491560A43D2BCAB86E6ADC9BC829CFF096C8181180BFC C249C3DB759B05978393F4B2380FB857D48380BFFAD9D00E445E620BB081CFD2FDA09105E182 FA8F8B72BA849CB74E4FA168C3E0EF861EA99615869BCFE9A70B0A44330387D1F2275FFC441B BD8DA42FF01816AAB6FAA53000C1ED613F6CDA9A0C00A18A9567881D39A369753E5725E3AF79 2FC729D3AF70D6039F7E71E05D4EEEB4800A09948AB2918DA9DB5FD672B2C951F512554B8A76 02295555E7CDF2F39BC048AC30479276B9EA4A0B56E88D1260017B9C2863DDECEA427A6CA9A3 8E92EE00FBE42438C84B9F394C7FEF519C6FE32644110398A8088371E4C0A0CBAE6F1DBDB864 B08C2984A600B2A2A4B1523F07D4F04D479D12F8AE39A602560784DA69BE1FC3361E9E9A9188 EC68019D2C29EC12A5452C27564F4808FCF7CB42638E838286A3F96CF603EF88FEF15E41620E 263F86E6DF082E3ACDF8C9700A1F7F167D8C7AF6B591EEE2A22B4DD38EDA5B3928D6527DA5BD C9537DB63A4031FF0F7057A4F42F535E7BC4297021526A79DD5ABE4F63D4EE9499A9B64E6575 0CAE0C6A280475D6376FB67B3D8A274CA3AD188F8DBC75CA19F1B281324E85927D912C89CE26 F423753B53A55C0D085E576F2EA05BD25C4C1CB67D0335BFB839420C14B5D5FFD66989FF2C59 2EB45947A81678EC6CD0D8693CEBEBB22A18F9FC5B25BB67A2AA8BEFCB08A47A637333DA4534 97C4A2CC411118B3F9C2363D144F7B71F72512C92762A90BCF9BE05AD62E5E37C36CCB796075 426C946A3EA7A7B2C3EB669566500259E2416F6F70182B1898BFA7A9C7A36A8D25380D3AA703 7C364321FFD9FB8CDE851B2F88DF2C4501CD51467F2DF02DE0CB4CD6B8D19CACF0C6E26E3080 E589C1246018A94A6667EB7B9AAAF40EBD8CF7EFBFD286C896068119F65EC69196FC9AF064DB 6641088B73D339235FD9FC8543E0074DA85899058920BE8C0B2E9AD854D230E3A6280F1C0940 064E99A15E36A1B60B71717FCB68AAF53FB877D48DD15B68EF58C51B36ACE7BBC95147BF984F 1C57C216ED78B32C54E66328E01117D813247073927EEC57D912BC848B912F360FDC3DD8BF20 33C5C9D445BB26F1E2E9193BEAEC0F262A3639AADE399DAA245D8974AC09B41B59C453ACBEF3 D92B86273D580929ED4BAA8033457B490C2C652FBB6896A782C05AE45406BAF49B1289EEDCF4 4493F9C3253D851ACE91A5B2853A22F00724470B9529C84DF49797F636B3D95D43E23AC3015E D9D9A78A3758963C1A82E7AB7A716BBF96EAFB1DD49D56A7C037886CA6F66D9679036FBEBDAD 86FDE112C44CDD7D1878EE00EF4F142A71A4A67AD34A9458A610AD82A7C6104AE60B0A4811F9 8084AEA6FAB407ED8C05311AB3A63049BAA67EFBAAC66B46F3FC4318A7A76BE15772513C5CBE 41A83B7BAEA045066D6BEE773D7C6A619F692A5999657F4ED2119E54117C8CF12528ED9BCA06 CBBB81DE3743020D146FF5B9572F7359A7AA29D616D48A64435155577F3446D9F4041F1F40BF A1B7C0A637921F5953D6459EF605A612CF3E05050100E101A4B07E7B22E68622349FD62AA0CD 8807399B223462CC2B2571896E36EAD5081A651DD4AECA736E04E11D172FCF656108BF725393 E6047E08280A4ADA62807FE911A15E7F5A1224DA23C47D3DF9A508F8BA13941C222162A54B84 44180D1F8270C48747274F55EF4CA73B14FDEE152D09AC094213266B6C47669E7B83DA8C8B94 C1D082E6EE5031017E112AF6F5ACF48AD3B1106AB79B6AB03C83B2928A17436BE7F09851589B 45D8C64EDAAB50C649D8F3F27BB16EF656CC8E0306E82C8237034A8C5803B0F3B1AECDC981BC D70FF6428B2995BE2C10290C630EA07E0AE82009F1D3696FFBE386749E71A4025DDE64309A0E 39A16ED744090224C6E7D167D9B8D09E083A748FF4A93D734EA6A74B031E9681152ABD0413A2 C81D5635E8A41C8CEC4A80D0AF319BE22FD450E357B0E8979FA8A229F6748053E911EB8C8C6B 601F915C32D89810C669024D98B7310238907E1535909A4D86047741CB9A60CE1745E67F10E5 C701B2D0516D8A701FA7DCDDC9B63C61825D19400A1580730001EA089C0F28227C19E15E0D65 C1CD06013331D365A5F7A967150966DEE3AA6FCE26C325E7D58DC98B2B1C1FBFB02214BC4B1A 9648ADF27DDCCC963EA7E093FD55731950E93604EC6025DD86E9287B0C67C6EA0D966603377A C3CD7B63102990A20AB67E8135E4D1A919F71C94B3DAD964B8ECAEEC67EDA37CCDCD05A1CD56 687A27B9A34CF64AA79F8122ACF294AF7DCEAB5089CEEA9844DF0963A89DACB9B335C79B4F2D 56A3A79912EC12D1997108AEC17D09BC5195504476738195A370BA31391216C1DA185C52EA3E C1663F0366CF3AD8AF5A8D249165E195C382D3ADB9DDA81E6CFD5111BA3A1F9E34925C96E50A F59FA2FF2AC7F3DC83934B34C6AFEAD5C77655486ED36D142E3816A1349A12E5040700169BFA F7BE4788032671F296076FCB427A76DF2834FB0386B2EBE115FDB5B5CE32D57A15410005208F C897D88EC8B2B46A870F0D476103548D553D2438222CEB4EC6897D2810DB5DADF53B5B6ADD9B 9A71EB194549B33B3BF7A68E97DE150F4D0252FF10808947A8C101176E95453A15D0E66D511F 04F38F403D391B3D288CCCF72DB576BC570A40D3E8E5D2E7DA7F30BC7935987669009525BA8A 455B82CBD926F9D1618FCA6DC148789ADFF738AC49633EEAF3B888661885457F4391CE7C1828 EED082EDB38D41FF225B33EA712F582D90F09C6330CAC12C489140DF4504C4DA101347C5114D 14C07D745E1FFB92896CCB79705BA14834A75F0F3DDFD1FCCDA8BC5DE059529680DF1876E41A F43FE1A14310AB93DB5E786A167E446FE4302025AF6B3D8D5C725636CDDF52C9816AB82B8CD4 83AABF7D64383CA9486ACD71DAD03CDCDF43E145CA1FC94D9ACD5420A01005666DE5FC83E43F 6A96A3F1670E75A23F740CF7A60E18171B14A94DA4D07C4147A23F89C97E6D00C96A14E66C22 EC782FA58FDE3AF40BB4A5C11AA5A9796025179AFD88D99F723B3973BB671E34D209DDB0EB6D C1732A128527B328DE5C4DBA0EEF997428A2E45CB00480C231B5D92225CFF3309F433B1D7A8F 69157A9604EDB80B3CEE8115D70EDF96DF018F7201FD18F06F3458CAF1159BF90CB565163926 BD8F4D0977FDD4695D035FFE9F78E9DAF495268A87F0F8E1BA42E1C4F4DD9B05356988E11BFD 95C1D802FFBE17FA86B5ECCB2B5E9CD88F207F90A3778748DFB87C512569A1469780A0FB01D5 A384E0CD78113ED23256AE529B7E781373B80BF1EE6E77F200F8D1FED4CBC879B5EC66FE7E13 AE60FBC69D4F2FB1FE730F186D3BDD4978CABF4CEEA2C7BC7C1F02D9E6AB312F6E8FAD1A0F70 67974F05648EE94D0EA8BF45D2F4EFDD5380125C4BCB71839761CA99CA4452A4140C13ABB97B 4DB59F6CC6A4308B8185DCB4E95AF89D58493209D8A9FBF86D999E67CC864DCF467258C5C605 03D54EC2F758C4DA866D8891016BF166091B12E72B1216CEEB2954ACC9B1DF4B640702923EA1 F340EDD3419E5FFBAF1BB29F51956ABB395B1AA815E103479DFE45B3677615C08AC770317269 7C7F5223C9547961A33FFC5D794C5CF7280C0417635B9A64B837C6CDF1940BF5D3A2CD9212D4 14A3167FF7C7A51C83889964D92FFE0D550CA7C102DE86C82BAB1DA3912F3190F00872ED9D0C 19AC14B72CA8FEF8B826B63A163022183F998CC7814D78D9D8C38AC122B1267CF92D075D8EBD 79E1209E8BD89B056E4CFAD4B1D6A822EECDBB2FF40DA248325DDE31A95EEB9EB75D699B9EA9 46ADD2365455D9F24A436476CE9E962E33E450C186A006EA57651AEB09D8DB7134D0520C1468 1BEE3EEF9F3A84177B6D5CCDCDEF2BE7DBEE03997F7B34FCCF9AB319F0680C03C2771B179EEA 27E1FA6B2EADAB7F6592538CC1ACCB5F64C3F7972943A942E7FC28DAB2D8BD0D4A585E94CD6B 467DEE7EB490397F3A6820B7CD9E043A785A26D0509FFC935900EADF6297B35ACA9239C776C2 B6A61523A529A54E01199B30522328053878C3DCECE69AC39BCF136290C5BC6CD04F5355723A 80C79624AEB7F76423400BEC6EA0531C57816DA649A44CB791275F8146C6F6AC95CCE9C7DF4D 18E8DE58B7F96F425D92C7D3449F1CF5E067442391F0F0441DC254A8A3D4C7597150331450B4 5BFC026AA5D0BEC87414AD2A6E07F5FD61218AB4D1AF843C2AB6696361DDED9A9E331F368824 22791FFBFD40927A9A65580CA9AA9CB36367C52559FC3209A96CFDA7478517C28ADEECB8C2EA E5F937AAABFD9CAE42C17749D721F19D318388F7F2E859EBD55AA68F41DED828451700EEBF9A 7763D95905407731A817A5E785509C123754F745600659A07EAF8C4D08FFE1E41AA8CB78CE5C FCF7293E5AF48777561A4231034DB95CC1196C847A1958C4F1AB2989F8364BB8BEBD6FAB569F C4CE68D99C7B7771665B895220261DAFFD471B89D2DE6066C8CEC85823898879291674D51382 6A44A5A2FCCD842B9CEEEA58DFE92B0A78D913DB57D8A15711609F451D60321AACE03FB0EAB5 BC4E05FC73C0E29B7AE92403439D3DDA8D36129B1CB0A760C0677745105F93936AD4AA8AB435 77C79E15150460A16F1C217152779715493F0396F46A80CC38E2C9991C9866796D03AC9DF4F5 C59547F4671C27A74010B946BEF91FDED2BCB2E88249B37FE24F6B642350AEE9FDE8AF9A1846 B5CB26DD18AA8785CC4B24A829B5F3E8293CB1CFE81797FEB369872B9530A3C0E966EA3A173D 25EC080F4B8FD4F556165CDF8B64563FE05611C9B3EE283D58BFD1B6A358DB387C4CCB3EA0F4 5CA7A1D1578BA672D16C1B200443BBF30EF30EA2A5CE8B4C0B3EF08067D319CAEA860E047CA4 3C1F7DE53CA65A7D92CF0579D13F5AE278C09D0DE5A169692AA07F740D829654F0680CAB9C79 87614B458A3CAD5F0E2BD34782705CDA7F9C0C00B5606E0323CE23C78B43ED2FE475FCEDE0BE 1440FE42F488209643F76CB8F4DBFA2D8F089C7B425FF199570FA1D811CA4EBCCE920CB75986 FAA11E1A666D3B821AD30CFB9648B97FA98EFB14D3EFE11B9E84FC33080755FD53825468775D 7460CC9758AEFF32610EABC33709088D60E7BA195279D2D1E7F8E2A5B3A427D0322B65D486D1 E623DA45652AB7F71EEDDEF1FC1AD31A5B4C620A85BF26D732F678FD79A2213F78DF9ABB79FF B9CE5AD8D59ABB59B75E48265E5F89994A4E3FE517980C63B94E0CB5C31C3858DFE6F6744682 D300A12844F97B4EB8DC14D52B1FADA4C2694596F889621F0C60D7F59909928D6B9C4BF0260C DD1E984C167D3BFA86145DC3733CAB12C945CE524341B6BE5BDBC882BA89B8493F4BB5DAAAC6 8265AC8F0D1D8781FEC6A913F6C967C2E6809E6E7DA7F55E99AF47FF083836E2D59B1DE167BF 7B85F21A51848D37345BD6617ACB7C939FCE5A99615CAA1592669199C54C616A00DC2858B1EE 3E06548146B81EBFEB1B52CD3033FE447CEA19567F80EB109C9F64EF24B2E067019DBA2C2608 FD901D7C9F6072226B543542D917D89731586A4B758ED05C95A2E8A264CC2AFA63F2A7952BBA E1A771122530B8770ED378FAE3AD93406107AFA5EFFCEC6C66CD3427BE67C8405536562F9039 033B25742F13ED631550799EE520ACD98B6AE8CE08C3951FA3D04D66E91D42D54431E7F4C36B F29B792922BCF1D85DB39D66B6FA92AEB89E2CFF9C0A150FC67A419D926F10F01A8F3E18DFEA 9470586ADD9DE03892B9E0989A2B1AAB57FAD07E5D9F7A5CB510AC82459949A286E4FBCA5199 54F1EC6118A03538FBCD4C0CF85AAFEAAB0390AE0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMTT12 %!PS-AdobeFont-1.1: CMTT12 1.0 %%CreationDate: 1991 Aug 20 16:45:46 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMTT12) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch true def end readonly def /FontName /CMTT12 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 161 /Gamma put dup 162 /Delta put dup 163 /Theta put dup 164 /Lambda put dup 165 /Xi put dup 166 /Pi put dup 167 /Sigma put dup 168 /Upsilon put dup 169 /Phi put dup 170 /Psi put dup 173 /Omega put dup 174 /arrowup put dup 175 /arrowdown put dup 176 /quotesingle put dup 177 /exclamdown put dup 178 /questiondown put dup 179 /dotlessi put dup 180 /dotlessj put dup 181 /grave put dup 182 /acute put dup 183 /caron put dup 184 /breve put dup 185 /macron put dup 186 /ring put dup 187 /cedilla put dup 188 /germandbls put dup 189 /ae put dup 190 /oe put dup 191 /oslash put dup 192 /AE put dup 193 /OE put dup 194 /Oslash put dup 195 /visiblespace put dup 196 /dieresis put dup 0 /Gamma put dup 1 /Delta put dup 2 /Theta put dup 3 /Lambda put dup 4 /Xi put dup 5 /Pi put dup 6 /Sigma put dup 7 /Upsilon put dup 8 /Phi put dup 9 /Psi put dup 10 /Omega put dup 11 /arrowup put dup 12 /arrowdown put dup 13 /quotesingle put dup 14 /exclamdown put dup 15 /questiondown put dup 16 /dotlessi put dup 17 /dotlessj put dup 18 /grave put dup 19 /acute put dup 20 /caron put dup 21 /breve put dup 22 /macron put dup 23 /ring put dup 24 /cedilla put dup 25 /germandbls put dup 26 /ae put dup 27 /oe put dup 28 /oslash put dup 29 /AE put dup 30 /OE put dup 31 /Oslash put dup 32 /visiblespace put dup 33 /exclam put dup 34 /quotedbl put dup 35 /numbersign put dup 36 /dollar put dup 37 /percent put dup 38 /ampersand put dup 39 /quoteright put dup 40 /parenleft put dup 41 /parenright put dup 42 /asterisk put dup 43 /plus put dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 47 /slash put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 59 /semicolon put dup 60 /less put dup 61 /equal put dup 62 /greater put dup 63 /question put dup 64 /at put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /bracketleft put dup 92 /backslash put dup 93 /bracketright put dup 94 /asciicircum put dup 95 /underscore put dup 96 /quoteleft put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /braceleft put dup 124 /bar put dup 125 /braceright put dup 126 /asciitilde put dup 127 /dieresis put dup 128 /visiblespace put dup 160 /space put readonly def /FontBBox{-1 -234 524 695}readonly def /UniqueID 5000833 def currentdict end currentfile eexec 9B9C1569015F2C1D2BF560F4C0D52257BACDD6500ABDA5ED9835F6A016CFC8F00B6C052ED76A 87856B50F4D80DFAEB508C97F8281F3F88B17E4D3B90C0F65EC379791AACDC162A66CBBC5BE2 F53AAD8DE72DD113B55A022FBFEE658CB95F5BB32BA0357B5E050FDDF264A07470BEF1C52119 B6FBD5C77EBED964AC5A2BBEC9D8B3E48AE5BB003A63D545774B922B9D5FF6B0066ECE43645A 131879B032137D6D823385FE55F3402D557FD3B4486BE79011D1F5B667EED85FADE30AB2EC4E 1C2F4FE750CF9A69506458071DE8896261C001B1C290937FA42A1FA87DE406E9F86A4C9C0F03 F69FBA719114F8AE51040A4C03A58B6F3DE027F6726F32743DCE739514C2C6F3C2DE1AEDDCFA 8EED7DA56DD68DBCDE33C29FF7A694769049E4325EC961B2DF16ADD2AD46F18781FBD63EEC62 C26F1DB41E6A666A09886382DCEBA91D8FF7CEDD64DDC8A2F15FE34076A064C46FEBD1F4DC37 07AEDE0CE8AF161BCB8E4ADA202D0954BACA5BE71C28AB8BF32FD72029AA07F27D658A68F454 A4BF386F6314224D16C7F0A8624F6B86319A4E2FD178F596F3B20DB032EA28C157A68A69FAD2 BC88881658D2286C0D4EF061BC070C3145F2A37EBEC03F51DE7CDA34CD977EEEBD86B00F9758 B3A496F41D9A74279EF3C6322DC54945F95062C5F37A1E51CF7EAF45F2B3634B2D7D01EC3B29 8FF35B6616CD3020E096F6C6AA2BF04C4A9361C19F3C67A28D936FFC8120F1E46980B29BF540 47C5F1FA48E67611A74FA4343384F802A4079B28B94681E119AB0C1692DE5BBF426440AD1023 506CB80732DEC64D9061869CB34DE924D2C26E404B7DBD9BE55B9C0C5AE3095C15D278ADBB49 12DF1484ED2D73128E5D9C1F1A3B9AC19E2CE5366C96644F5B3D3EEA589CAEDB586FD9B8F4DF 32EC910E9B7434D5BBE57E03892EB03890567DF5B811AFA0DA5E929D456AF3606092E69DD7FD 0FD505A1343C143D8CD853C485C30537C448AEA64F31F887275696A3272E00F8860E60AFB1A9 32247B70D45FEC9B75834DA16FE9B6D1977D6CF251568EC6E1B2321F0A168FE01CABB0DB855A 3C93DB62021467C39F33BE34A345A834C0F570EFC4E6810FAD9BFD353F241BF896E600111C2F AFA2E7CEBCF89378418F7FB54127058217A073788F37E315B5547BD1FB607460AF1C5A025B77 222E7599F1DDCFD5A604825E440FB0A5E2C8F2337A6A3E23591A2428B5187801786BC527CEEB 07E0479F2F46050658EAA3AA39A7FEA3F3E3F54CFF92DD7E2DD80087D9B54158BF6DA0D15B85 C7D7FC603FABFF9F14D3B9223600ECE9A913C077770B25519408B8D9A111D7A6FD94528B2EFD 4DFADA964A5060263366D3C3127C33CF0F01700942E1DAB4781962873F7E87F34B702C04EFAB 55CA34951EADA440B96837B566752ADFD20ECEFDB7E7783FB4ED521ED75E8472917DF30C394A 38B7203CE31DEFC6AD7C723E4C78239F35F1C3650F39AC87F5270132B617BA31E3ABD72E14C8 253FC4FAFD4D76B06B2DEA10F527C246DB1C9178DAE2C626854DA20D3997AD464466268D3645 2727FBEC29E1C15A0208DB47F4C49F6436CCB01EE8D499CEB56AEF12A2BD351ECDFA7C16DB36 5EC4F29E84CDEEB6C69406711DF79A53CEA0C23E13793221403D887FD83ECCA853181E013793 10D777DF4CD3085C894B27CF5573C1A39AEEA28BF9EEFE2949720B7ADDE635BE2ACF587E89AF 27F3FB94929AE2539FE9F7BC7DF6B0629F2003CB5C6E84B704B5453B2579CE0EE6A7D6B45867 24D1E87117E0391FAA87C44EA920DE04290B2C1095D9B3173DB9718B188FF8F57E674BA27AAA 37FB45B5254204F20DD420AA84F6010F512A1CFDF837A08EC7B0F25E97328B99BDBADF1F9A8C BA4D1FA311A416B185653ED2CEA3E77CB228AB746CEC1D1A6F46AACE75E57425A0C386BC43CC 92114FFC834F5A997549383E7BF2115532275A95815E0A1205831E90B7556E7D88CC17314CA7 EBC2221E9E2017095B5F3743AF3C34B3767083853EA9192579BEC83BC6EDC0FE4D5DD45D69FF 096DC155019D813B9940DD336A025C715EDD62BFBFAEAF49386CE28403CF87CE9F3E6CBF6338 EC09556303B9602B0EA318CC45E7905D43C74E88D8E6429C96D4E668A0D1F80BACF3C8ADFB81 26857A5F30BAC745EDBEFB8D56E0DFB96473C2867F06D98C43495EB9267F2948C8A30203C5AD 85D98C04554C2212119F947BAE7D5D5485D0FEA7F2A187FCBCB6A86A08CD6C9F02137AE82CC3 F90E175EC2F92B132D4CCBD5083F29FAE03B0A59071F9A0D947F5B1EBB91A8716E27BB0369C2 DBB201A59D837FCED4EBD4A30991E38849C7356A8A7B73A79A0E284A391BB70368495E950791 917BC308FF2E6A6F045592C60F3C6107A1ACAACA3BCF11269C9FCA80DDDD917FC689512F3604 01EE3E9BEE13926D486A4C6078AC32C3E6C9574DD3E777E1B65C9C920CD6A7E9AF7D26DF1CED 8810F0F68D82F386381B9CD8CACBD3DD3199E0A2ADAA11993B2D7AB5222293F744500DDD44D3 EB05663B97A087CD62E7726C4CE7BBBA46A43B340DA333326AC565C92E8081B6A44C272EE707 E58951714D4F864E6CC7339A448A2FE4030C8581563CC84FEB4CEFFD10B0A04FA4CCBB49422C 949E3075CDCFBE821FAD084F7B58AF48111DE80384F7CBEA2E5AB9D75994A01489A00F71B818 19BE8D5036476DB5CD3F63AB0BB0232F6907C7F8F90D9808BAC65B86D8C842FB4DA0963D60D4 428918EC71E3618B6743FC95499878D73CB72E0E936344C37621D19B8C9BFEA952AED28FA90B 08EC515A69B5148EB53A9CA6983A45DA53440E73308A85568A95C2BC299682A93C913511546D 6E7E4FCCFFF1A8D0364F20270BF4B161A5FA099BD14E1147B08794EEF74AC57E8D0FA62B595E D7CC33948FF5CBA1DF0C8E4224B98E03013D19294FC946CE648064668925C0E7E5AD39147B93 C4CB0D13BE84F557DE1FFC50586723C843490C804A9AAA45808781F40F09FB8F9F518B40F62F CA77C506A6DF9B6A053CE20F733155E4AB409A271BB5C7A9055A6190D044621389F3A9BC7E98 437127BA49D45C3EFF1FB8FCA8F8D728936E17895B6D666A958B9E84C3C8CC7C720D82446AEC 140F5AC5EEFC95541B549535E59B9C0040376A7F3CBC75A51FCF1739880A982B49E08345718A 7FAC7F005B22584D8914A4590F18D9825D3926A78DCBD1FFADC03B00C8CDFA6B5BC19EEAC5A9 4FCAE8BB23D901858C3E274D84BBE889580B65DCC75DB58536C4AB6E402BDC01DB039F692858 462BD53456468D2ABBE829A64BC47ACAAACC19587BAC5225D2CF31B60712E5BB9D4065A03925 639B8AC1475C5431344B4F05181E0B12C7D40AEF56DFFA7B7B3146CCDF7BD342ABD78DF93681 34C8545E09D76C2ACB79ECAD66D05FB8D5DF83A3F36221B6A4157FE39114B4CFC20C197893DC 26D6D3BEBB079D3CAABBBFB3489D46BF65B4644C92EBE8C870B10BB4246AF3C16DEBA71C1572 3F5DCD416FA8A35AEB2DBED7E2890DBCF327B9A1BDD8F327158F5CFA6613AC55B54BBE821CDD 2148E716BD8F1C3DA35FBDE6798B44D3973C677884376ADEEC4BB07F2FB93BC3010ECF6FC493 02B87247EB55D7C4EA57D0892D6AE86DF45C02AA7E59B1B1DC9CF62DAB182474688FCC120836 1EC9A586E6A212C32FC4913D1AD9D2718D879C1C57B81BFD1A24636375136BDB7A10D7C943E1 18B8DBF145D8C5D0507E5B67E683B75B392A9CA2B9F31C5E9CAD38B46CD365D796AE5B06FE59 3A7BEE53B7B3C5212AA5C6ECB06450E587974317197AC7C4BDBF4505A6F62FE7D28CA01D61E1 898E11FB892C46088F174594536B2AFFB1F4C06C48835EB430A21C8B2D5126334D4118D72F67 51011244A386C9F66901DA5C90F7F72572779934A66962B1FE168760F27030770F0BA6B55108 4B933F76DE3E4116B5366F93F795668797A97A8A9C581B3A200573A6B9D289D773B12F3B67DF 57A2ECD9A2CCA23C4D6917F8CBC5D21C9B5B8A7B0823DF0E570FB618C787D78D2DD9E0C1EE61 36C8DF3BF011BAE7D5909F2900AEC1EF6E0A2B51F82D402BB28FB3E745BFA92E66720FA0AD85 51EF7447E39DFD62086E0658FC0C6ACFFEAFC55245E1E28133E53A29687459E7EFF97328DBD2 3B85AB82EA25927299918CFB0270271307E7565BB7B077B7425681A6FE2D0B0082F62F3D461A C1094838097918C4284C7D2AF752D89EC9E0BB6369A9E4582195B8FCD616C0B3E15E9C5D0145 C8ADCF4175C4A55B4CAA16930059A30C533557D03264A5D255AACB9D3CE20DA2A9CE3490FAE9 F5F12C719CE5AACC06FFABC769A2C144B469F7ECE4F056E4C66D9510CE75AD52D3D881D71D22 C90524A566F5207EE0843A7EA235D1E7B6F5D7365785E21DEEF2B461A206A666B172F156E9C8 30DC2A2784F5FE2C25EEF48F63708994CB54C0AF1BF790F493F44407C0AB8EEB19606A187FDD D2D0CFE8C4B40413BAE547490BDD6A52D69B4AAD1D2676D88EA9F3E7BB389FC078B93C67BF47 127C286C48B66CAAFF5E7E8AFC3F2FCC65FAABD66B39EE80D33FDA99C44B9A1C8F94B4F94366 06F91150F8CAED3E6BA194D220C3FC9DAB3A42ABBA3D110045D3203B3F085C37F16FEE556F61 402FA5DAB44191B1592F88B5FFEA31C51E1B8EF02A692AC93B0781D32BD30B9FCA7F3CF6EF94 4AC7AE66416E97F80BE111CB0B7F5CA0BA5546EDA8F2F01E997FE0469A5EC986824055ADDBEF C5A66CE8CF6BA59C356219CCB32D458B9DB14A34FCF0544E7148C8164F36EB0B54AFFF5D0FD8 050233BB83DA5C0F9C30D20F41DC1A31F2BCDCB50855D0B2B171C04CB5798A4E6FD648086395 709294B9FE74DC5593440A585A4716496E57BF688CFF9D57502961FCBCDC212D47F027EB74C1 CBE000D139122B4675A37050A15C90F4E3C7E03539422956A2D909F53FAD6AFECF0DAF6A3AB9 051BEB6D780935F397D9567B73F8A201C4B6688114DB7D9AB953D6DE066D926C9E028C54DBEC 37A6118501E09A49CD64C0CEE80AC726AC8F273C93E50AF97726C1F592C5C100ED8217E057AA 4CBD11B0EAEE4C58BBF5C4040CFEDACF167A5EAC9605B9AD4904B557B0A2565BA0692057B8AA 63FCA8C88C7D4D02C6343FBBE65C37B717456FFB609E79C40CBFC00A2E408BD5171D44020176 05447F73393190287998E7C515D115B08B692A725A55C62F38EA91AFDE05404C8A2FCDA96C1A 2C94F196837DC250BABCAC9A2E242852450B5EC43CB90927AC2321866D52CF10D1AB637C929D 6C3500A405A6C9E2527B4AAE2A9043107547D69F02F652FD8160092E5926B9F556761A5AC7BA E9FE295CCF424C65D09290F6002EDDCF671C2E79768820B3D7AAC8A93D96B570BEADD291F94B 866313B290684EB5B864CD7D0AED407934B54DBD7A0F0D42D018541D46F06023F70952FC8AE9 C47B45A7DFFF666263CE7F844D26CCAE6662F68D82B4E61C676A3021F3B2A69BAAA7D084751F 764638E86F8191397CB55F8A50FC855375E1C27615D2313FE443B4ED59852A20656CA3FB018A EAFA5C494CCEFA7ED73119A8B72E6FA570271F5C4F9B7E17CA967A765302B02F4572EE924F4E D6F9E06752E4FCA351A9EDD922485487E223B4408D335F5CAA8608745D601C0CAFD4B066DF82 7C5C32437DCD4C2F72354A5DCBD461DC358BF3B5284DBB55E5DE6673480C331C561B9A31EAC7 D400D4B4AA714BC61EE01EF584B73762D5181760F82F31B3AF82A09418E0308B6FC0B9EBF75D F7A0CF2DDB5D4046B6CDAAFE9FFB76D83FF26B6DBF20F07A5C63B5508BFFBAB24F098F75D5B8 D025878AB6020591C7AB79B25693A09987307896F8EBFDC77A9C87758AF67F1DF4DD557B61DE 39661130AE6268DB29856733943C0275D0934CB512E50F436AA6B3065929D99E50C629B1BA7F 7102B41551CEEB2BDF211B27FC863F3B910CCB8886CE5C17F05D09184AABA0FE7C8A79A37DDE 680886ECFD40692FF71C6402F6A9B5B651BD53DFABB8A6B47DAA35D0B048E0D1CDD313D3A9DA 87F7E93A474D32EDECF006FD15D3C0D6CBA42DD22FAB6F546DDEBB827D89006156EF4FE9F3DB 46FFE0D128CF8537BC6744C22634A078825F5DF773CFFFD4B7A56580975A360C188AF5FB1EAF 54043C85E9F7D71D9BC7EB417EAFC6C5879878F405EF57682D7831A92AA8EA5BF71CA8363D00 281DDF930E81C6782C322F841CC3909997738B5511FBDF47429CF5EBF33E7A4C2E372D5A52D8 1B2EC98CCEA3B0E675CF2C3703F1A629843927766A7747E049323E2C22F85A58B927E8E41E59 34173DEAEBC37D9F66F9F27B8B7DB0CC2110390CFDEACFE8E51F4DC3C99FF8DE54A9057EF779 BC438CAF7B1899C01A1CF5FB2D6E572B55753C90FC41E99C5AF4B979F61211D1D32FC1DB9314 A9FB773E5D8A556E3699C1F196F0B4727D4003278AC43CD32939368C7733BC419D26FFEBADDA 523ACF07A230F446A1BCE99FAD2709FAAE5A0E617D8EF2EAC4BC01E5C76CF5587DCFB6816CAF 6F9E390C4B8947C9CE3AD29007742B2BB6C6FFE51FC20BBC8C17694A548AA61CFF6D6F318726 8C54E3E81F9FF3B0AEDD6EF44E1FCCBF5BF7FADE6D9252FE367931D28298923B478482713939 52255D1A66878C4D44768EC352C83AA97B35BA388A098186DF61D8ADA96C49B7D2388160A60E 1A8FA86CD71DAB040DFC26B6A6A681D9ECFCE51C7783AB4091429731829A59B2FB5E8818AE8E D733D1B55074D5B248F2A1A361087B4BFEDB91FAD81276EE08E6513A716E284C5AE0EFFDDDB1 E67BA59AE6B6A833057B69A350502ECE25C8F6AB28F2F35940EBFDF4BED3A3447FB00394301E F5B19998F1834EAF4070FADFE4B142F473FEC46D0A96E60C500D31170BC4834A0B1508FE55D9 343906CBEECED81AF972C50B9D04A3B29EEA90B76557DC3F18A9C57C852ECCA395E51F0E77CD CC135A6CB83AB71541D2850C85D8D4944D534F32227EA33A0E8840CD7B753D824254EE8D2829 3C40B21FADD0B0C0125E97E9930A0C727BBE3C8D0815DE74281DCA5E38D940973930274D0D2C EE698F578DC9C56DC080574DC3CB50787D357F8211A7A48730D033249503904659BF05D5ED5E 9190AEA4BDDCB1BE3A1A4C50B0D407A799FEE4878E5C30BFC0D9251B03CDD80D8FD4321AE249 E530AD243C671F34A53742F3D6A07645A2409A3707EFEF4E4F35398CFCBEF2510C94D45FE636 D80515FC13275FDFAE1D33BFE972FD44FEBB65A8C704B71DAB5E84316FD25801C35681E056A4 D21CBD6766ACB5461C55FEF91564244C6764E7EE15BD40A04744B458C2B6E93477C9FE9CCF42 9D4E5E98D2FDD6CB278023C682984A99979BC1A74BCC38A6D0D6C5A8683587E807D9AA7D4EDB E01115970AC85BAEB3839015CC2D2015AFB0E6C8346884F25AD8304F08E229EF2A3BA89DAE83 A2F22A34E861A634E9AED19BFD674A9DD3A9049172759E0D8BD4F1D79FA2F39251F099671D18 ED9FDC960137AC05EC03E5A62965BCF0BBD0BA69C8CC6A35192225F2E58023D0330EDDC612FB ADC69A0E9B8EF09AF0EA5AAF781C2716E8DCF253FCD750D8B5C829B2C62811F9EC9EE7A794E4 5858D26766ACD5101BEA259B6119588EC8A652AE2AD82C5F19CBDFCD8E5268A039469F8FA2B6 76638239737D495182ADE2E5E1069B54B0A272F173632515726A4DDCDC92FC3CAF236FEEB0D6 1FB16199E500F9456BB4C72A88A9C8B96D50446AA691CFA8C7FF7E58B49C40B50CFF81EC491B 8EC6A89DB049CAC589ABEBE717AE25A976FF9D7A16C654B53B08DAB2B983067F3C55842DCEBD FE839B0FB44E455A4ADEEF4B730E72FEF94A84FD26FCA4632E6D1ADE7BDEC2F107BBC6B6C476 4853C634B8B9EBD2ADD7F097041FD14414EAE550680242BB82CEA70A98866A444280325FEBE5 A346A103D268EE2332A08E9C7C31771CB2F9BB82D8E684A4C662C440A9591C56F84448001909 DFE801BFD354113071814A705FE28CC88E7A019C259E0D799CE896748B10F110D30A3D4144E6 59C7FEE3640A069C3EFAABE805826967BC07A7F625ED66C069C665F0A354CD318977F9C5F34F 1EF97C6372E94506A664E4D7ECAC7411FC8FE3A160F721A69B1C4DDEF146803821A795DA8BDA 9AF0FC130445B9F6FBAEC9FCB74DE5AF2A104A1E50E404380F20A8DE559C5458E6DA81BD5618 AD74EB0D6FBA61589CCA81A71558CBD7B7D4DAC6886E024E917DF2D5E3E8790DFADE1FDE7BB7 908EC62E12C3EDB23B412F1C330E89E0C18E65C675FB03366EDDEDC783CEFC84F71F7F68DCDA 94B672779C9FF82F974402A2A62CF047A5AB8D71633C457920D1B092ACC4F5795CA6D0DF2C43 C41640776EAFF464ABA9BB73972386B53C6A71FB621AD8F98C734C262A2212126812CFB65275 4212BC7FCA79E3B53D6C3CE762676F5880AD3DE63581A3CE3EF72A42B7E73CC6E23A6A0933D5 F5324380F8A53E98DF6BF77233C2B0EF534D569C0B3ADFECBE402CC5034857A1CBEA655B9D45 FFC54DB388A8141E4E6DC30270F9001603543B44C9AF54604B8AE1F2877A9A0ABF2E14015E4D 91E14A94B376F3CCA39D17AA21A07EA09D047691AA463EA1914121ED4277760D9766CE1A8C14 EB59A8ECFDC03061C9BDBAF8FAE84540CB0AF1EFFC17348CCF5090C72CDA21007ABABB67B0C3 EA8EE0B104046E6E77E4DC5D614DA2A5E3CF0AC6F98BD9AD8FB0486F7326DB53C89D3467F6E4 B9007DED8415DACB451E14281A6F0E3360C8B9993365E4689B53F96386C237D56A1474406388 35301465BBD6B3B8C943EFA7D6981902FE62EEDEDD267FBA38F1FC395EFA99342EB0FEB63521 2D561BC01F27874613B20C640E5A82D787F45CB4395D04CC699E70378C806AF923DF381CD1A3 7EBB28E9AECC1CDD167ADDFCDAF629403704702CD8FE167B25A4A185003A8B3B0F915EAFE06C CD3C9B0827B5CA8C1F574A26726307FDA1217026D04F48C9E2853A9576D32DD1817B5ED74FBF 68A7FD00FE3FFE84F76918087D43E0915560C78DBD151EB0AC294356575289780295D05CEE51 953F1C413AD2D60BC9CF2CB5724533D39B36AF05BBD15AE4066325A93EE9258D9A968CEFD692 11184CAD62E223FFDBF979673334E584B5B52EBE7526E4859B201CC38C22AEFED2E59D6C785E F1CBE25849BD1E7904E13B58F8B643E480BE312893276269ED4CF656D12A495941340EC5DB5E 2177B25390DE9071F34A44AC79620FDB558CC8766B4DC8111292F7757793B2A7D8DAFA9AAA57 0BED572C4325D65EF7A41A5C533132739FC0FFBECCE7EB19D69D4249F412D3D9B383F6E6D171 E3182BB107303AD650ABC00E1783410BF5F669EE91CBD30ED84E1E0A199A69F17204F043FF90 DB432A505502850D743716EDE4946011113ECB45AD46DEFAF0F299A698639DF3A1F133AB75D5 86BEFE281B8983550A3A22F239E654CDA506671D53C1E044440BF367A2C5F75C65E25419AFA6 74585D137365D4AE7B6716D3E8AA41D7ED2DD711B4ED75B88F12CCB3A6A0F7B2785743AA4E42 4AC7D5E8ADE9EF8F2F2B6C96A35C30F5A32575AD05FF47598B111CFA095BC77E29DA89E63D40 72F1FEF1E617B48B82D27CBD863A8683FBC6825448752F2944D3BA7D34464942A0AD6423EACC D2A28136FD1EA51D849667160E07A7C1CF1983AA4273D6D2CC936B18B4A43EB67678C2285246 64AE0ADDBB4325DB098CB246D9D0AC1B49456D30F3D06113FFBD255CB7713C7970C8A5D486A7 A42ACD0EE68939894772D6D4333B174C1B6C004F4D9AC917075DF0C10B404214C1881E531E16 000DDB9FBB93ADCB36690D064CD1131B5ECAFA201257A74DFB7DC4FB7478916D513FE138A725 A0545E916EE8D1C597B9AAB070C09E0539D1421FC84E1AFC9433D99F202E54F6CDA9D704566D EBA11F79C383433EEADD4EA8DAC0512F123D447BE2BEC0B176B8E4828622B6D14FCA0BCA414E 35FC210DFCCD31207097A211E3C6596E676E39E4EEEAFC12403887FFF032B325F621367A4459 06F4D78C7D136CA1A4B25EBE2400288DD85C70AD649B1A8E21A5666057D93F944AEDEC5C1102 61092DB8A07566D3C4843918FC70ACEB2CF648BCD73FCC4775CA0376D16A297938D6497A2E21 6F5FC72FAB216ABE6B00C487F65362E7FD8D61A8C99E068279A338828A119429D3B0495D12C9 E8881455D80684344F92D0306E501AA5A2E9102A67AD77BB77A2191EA1BBEB573A2D1437A542 A2808E5F358274308720B10447917870BD6846B2D4B2A2F9448D7F5A261A3A12267F5AAC2ECF DF284DCC39EF73E57A0A77EBA848F1139D73AC5F3298F0A2B431458EBBED3341AE9D40F5521E 864F57154271E27DE965512C85608CC7D5ED75AAB3FD2C096C5A6C23DD1A719BBC66A0ABED8E 270230C807187EA702B36305889D8807F2F7D75ECE5AA1F3D1D1C7E60675912CF34B1E0C306C 2B62C9FA7F51FD7D17BA7021A1BBD88B0D5D8C2C347F5D2DDD2AC27B089471F3DCE65474D000 4FFF976A6859780EC2A8E271F7CF08336E1B38D4DDAD20379E033F3F21945C0D79B46F876CDB 64DDE6B0D31BFF2D0F0EA5E37DA1BA958D3986FBF2425FD4D36ED0B07050F8631AB315619DF0 3F1B39B30CB93BC3DCA5283CC36BF9C29EF64B3660770E915B2C4C8A4416BFCB8D3213F725C8 4772C5F774FED4E6DB73D407972F896B05C7138539C729C2A20387AE91BC783F357CFC2FB1F1 B035ED416854385385DA6772225010F945313D2733C24396F863AD16058412A70306CB2DBB8F 6428D7B327521C951DD1F5BC489015DB31831F93B559CCAB8B914215C3E739BB558EAA8BAD63 C3B06F033DE0F9B6F5932C8500F00A14F974B645FE50ADF8E5246950B02E817919E7B2BC27B9 DF8E67564EA5B0B9897B46315CB71961B76D814E29C6174CE60EF242D7DA4D1EB465F72FC26B 0DA9D3BF154527BEA86286B8BE614839827A06D7328E20B7C0751C00DBACA3B3E548E093AB8A B726E2202E4F712B6DA77F09DC2AC9A389F9E02329680201A819D992F7D7E46F981CA81BD8BA 640F7D4EABA8A0313BBD3582FA19D6828C0B5BB4AB753422F647ED0AC4E2ED4B23ECA84B40C0 067ABFCCBBE0E30C5BE1E50C085244A308E8494091944FEF469A3B195BFDCB80621314F276A0 DC46A1FDA00C5F8DF059EEFB1E6DF6F2F7DCB0A52395B2DF0228464C753B3760B8AA15C297ED FE86D42D08E40286BFAFBC98DAA4528EBE9362CCA21937DFE8A53595BB590F0AFD86F92C0FF7 3CB21EA18D69CC3394A78AA12699A5431CC0E786DC0DFCE332D4850E8247586DC99B5A1BA337 400AED4246D717A48327CBB14B43A2DB10338D6573770BF9C4CBBDC028DB50F6A8A3038580F7 5F04D1849536340E3C283E8C318609FD20619C47B18022580FFA1559EB1D76CDB7683DD10933 2AB61CD004E2EA9EFA9467734ADC9052B769ADEC5142822028C6E590644ADBAA94655CA7539F 5615D40237507E4FEA65088BF2EDC65BCD163B979D67AAED3794C0744CA1E037EC158FC4AED2 59CD5AE2D6FE56BA985EE9FBE9CB3BEA352D7F5934F0A37655FDB297EBD9D72BAFE407ECA9CA 4AC0029C9916CE462833551A9CF7148E7045F4DBB8B868BB699BDD3D1AAC3B3BA5E8EE7274F7 4B0BB47EAE73DEE2895BF7EF789E313A226198D85B1805E5A7B771A879CD8421D3813119FACD 797463970536F95C52D77A4FDDA562CB33CED74277435C5FFDE717AE5717FFE46B35350B22BB F70BA6AFDC66BF0F6674BE52C9568531D36A8963CDBA1377915005443FC9374C9185C58CD25C EB096B0F86271F99AEED8BB365FF384CBFA5E826ABD30540E1162AE030E9033E6474B15FCB0A 71C9DEEA1762479412BA28E004431CA38AD42EB71BFE5B7E172714FD081F1600D0119768014F E219834913B26817D8BF37D51BB5C85AA3F46F06E4D78361ABCC4D2B66AB2EA51F308006E996 228F1C2C4709B809D05C0FBFA810446D07F7A0530C7B947448E310806FF1215FB2A293DBD04D 7C2C22573962D83F65AD82D770536FD354BDA1426A0B2757F7588F793C1F84343DD122419D91 BCABFAF04289A8A9F727BDD082D04640C1C0B4CE103D2919E53BE623F89B12D1F71363914D12 352A6A2D0A1E4E28FA43CC3C2893B64379C098DCAC2E5FC4BAA4C2410E92D3D4C7D8FDE9E552 330253F3F62721F69CAFF9539CE3F37984885642235F65BF484AD23C33C74A3B8DBF2C7393B2 6640638C4F3B4617A6C12CB760EFE5ECCA312972113089E2D924982D6912ED4B68FF99028440 226EB94D91F44C62D6878861FC7F47B8965D0C3AEE31D6F9FFFA92D63F8E7AC120B97CD905AF 68AA5119F08807E255E6AFA5EBE87CC238C0E35E133C3DB18CDB73AB421D600DC4B3CBF491FE B931A95C2167EDFD9BCB8F7821262546F61A13994498CFA00361D23D235762B2F36E5E96A310 F3685E61B5E4A08C1734F8D36F2F6B90E6E4FAAD352B070AA20DE71B9B829C2A9F854551182B A086EF04BAC9C50CB65684ABE48D4A5271CB7B869DE8E8AD503E493CB1DC442239D5B86FEDD8 8EF0C6A9729A92889CCA3BB785C5BFE760D2743B3386D3DBC41D8FD2DDA1D5BDBE2C648C118C DAA25E1097273F05C0C01DD339D7839BC389BE0FAC354C4B23561C1529B2AD6F8D019140B2E0 681BC9F5370D775BFB92F9E0112F1EC9F9C09B0BE4DE62D723A44C31060A507FA5A3B9068B4C 0AC83710D31DF2F161A3F5FA3E66127AF55A6419DF17976CAB2980CFB4CF5EBA41D4B16F69EE 5839AB4BD7AA2C1A8285CC2CABBD906045B6666116041D8A10ACB8B7675305A0C3F05FAF1DC4 D3EAEFDAA67EAD720E69C86260B3A26C99AE36B2BF548746DC150DE1D79FDD3C3C8BE6329787 F8B95F9D52D1EC3BFB87189362DBE13E4F6703C8B6615BD6D5BD610AAEAB4E4DB5A80B523362 53E104F40CDADAC5E33BFEF07317F6E45EF27DB4115676C7407B51A4080C86D7228AA4CFF41B 3E8810458856B987064A9DBCD6EC2A2C134D1B7F86CA1992D2F177B8CCCB6DB7362EC6C505C6 D2619D54434A03B702A5EC5D99965AD2830F3C9A6A621772EF498E5F4F34A2ACF85F8593C64D BF44E78D439CC105978AA1B77BEAB55A2927C45C2A775D66EC84E5934D9CC6C51580F6C70FF3 79B353F8F06C4C592268CFE979F2B171F07AE41FE6EFF0FAC3D64EC2C99D09DC32C0FF0005D6 8B5139AB63664D1E4BFADC5E51AD14E50BB49171467C793E7C33E0C83CD8E725774642B5FB20 284F2B4B0BD511DD99FAC6CC0662541CA12F2E97588ED5150555E7591DF2AD71990DC9D4027C 7C3922E0DD8E51B5A8A83B3F21B71A6A89C2069173A2DA9BFC5F76ACA58B3A970AC998394978 A356873F91C265A4E121F5E149EDACC2F614E59B5A9F7A9D0BC278F5F7FF575DAEC80908AE21 B72578A179F25A3236DAD66900AFFCD1C4DF57714243772903DBB704C5953450B0CE21F21042 6C335845BAA8D509BB4D0025750D6D2633142FD3BC368D4054A23F218B36CBEAFAF6BC06936A 6B72B5419271FE225839BA5687E967F392B8C782647AF4A206AFE5C5EF34EE98228E4D551131 37B10DEC2C1081AACCFA2F2916F2734C349AD7C167EB1873FF494678B0CC337073F5BF56E886 6A795D55C7C7535293E13A7886EEF83736CC11C57F2655607A9607A5C7A5000356AA3E696DD2 7641AC65719D7D5C0AF1F621CE70C03AC15222F7881B125EBDACCA3FD243E302904B8901EF4E CF7F885972EEAB3999E093DE43CCABFA927D415E7703909EE028FC98E978A934AF9500628A80 EFDEA8D72B199F12164E597FAFE7C085BF3D6CFEA62A10C5A0889E978024A45C2E4EE0B0D4EB E332752D57B28F52C77E4B7EE7F8217DD12294CEE9807645C4C1EB833247C19A41B6395727D9 D50708A0367DC931ADD77B4D977B0769E654DCCC17FCF05F7BA79978F9A970858EE1D1415554 A2667C479FE0BEAC02C26DEEA7D3F19E47A59A56BC45AB52102563951B7D84E57323021B4865 4E3C61E12E3F2FE08646BD52BBA29B61E3F9DCA9784724EED237CEF46E2E1F464EBB0B4BF694 E13C02CF2C421416764E731844C9BD69674D9D63643CBDC9DC5446A51EF3910BE8AB674FDA64 B52E8DE0D859650342A7B09195B41104CA58C1D8126ED46269013A99672217233B55D534C5E9 C4B35092B5849E159DE0F26A53DF170A092A5F04DDA515347E8C36E0BDF48D6460F212195D94 5300658B4E7F53BCF666DCFA459595E250F39B7E54C3364D18056CEC4921D86A54256750710C E0AD4A20930A40A02186021E7B010FBD2DD62E5CF5BFCA82E90F720D04922D4BDD0F50D1D51D 1B25A80E260E0E00899A702CF0FC9EAB51EC7F4CD9301A8CEF10B6CA1AA8829A5EEAF08A69D4 35A69BF691B7BD6CA4048725B963CEC24380063AD550BD418D8678F8289C2666404A817EF7F9 07AFD2575932D5A72964B1C92E44403110B79DD247A0571F37D9396F806B9C57C22B744F549D 2A946D14D838B63E6FE77099D63E76BE82E7107850D914B080CE2AC1C34F6DF81DAA4E14B33A 401FF86DBA292ABB27CB8F2E4E8DEB873465EF8E29C56FE0309BAC322B37D1A3AD19404713BE 77566F12DBA2A615952CC52473CC5C7554E054D246C71A96BE19042F85E696ED0A8BB8492D2A 9D2EF7E306A608A73B0751F965CCAD6C71BE26DD75AB06F13BA014F1A795F4249FF41C87764F A7596DFCEFD5FCEAC567EB760F7910BB19A122B27B687BE4BF8449B135D0637A5752011EE889 8F855A3883B81E8F8A8F4D4DB59BC4306F6890C1A6393404D63857B806BBD98638D9EBC162AC E5CE654500076639218E83407553B99844761B1B8B9E353CE111AB1A4AFA69B633C564A0A9EC E4BCA8F6566E8F856DFD616527AFACDD5C0C2A5AFA98852F165420EB33AB9892D62A86DEEBED 34BB7A6591274844BFC17249C04955DB780937A1AC9C231A5A0FD88E94C9AAE3E5C410730E69 26B92C63F4B13218EC7598E5640CFF74803712C681C5D01142F8D59F852ABEF10A720AC70A6B A97B1225178E9F04B1542A7A20417CEF1783DBB501E72569EC4DD9F6AAC17A5DB49C26DE1FE5 14F9029883DD2B5FAAB9B33D0D1B54C2EB17771D6F9CB2B3057E5644489C53C76B800B9894FE 2E9A750D11350C30BECC8DA4B15C153D3860CD5D7C65A655E9FFA4F29A109EC2AB7EE0ACF745 0CCB1CCFA23FE3ED28D4966BA6BBF15CC94781B2F46FE4614612DF12ED408A62938A760D81EC E1CB72DA11E59F4260CC0C1596FB1E71A8DA86D4CD2478F29DE9400314B79C5C96F465B63775 682026FB95BF23DFAD4B5344CEF2661F412980896CB656A00AC4C85BFAE906BFD4FC8E3FC494 251594DFCC39056F08A6CE5CAE362627AFFAF70A0DC1DC0ED201160E4F87499F94217103BA43 C7E4CB5A8F454F802DBBDFF5E9A6B204D761999CD2A2724371412AD58D974D55DA8EEF1EAEC3 E6E2C0A9357194295424886667382A48A7B4F1B4457E12F8B8DE868671C701E4EFF00340ED1E F32A19228C8E09CBED8D0FEB6CFDF88A53CD1577584E06579E3DDCD7AA4E88DA92FF4193AD56 96960D2F653667E3F120C6ABE0FFA2F6CF78645E079C46D8DCEFCD6FF61B653DDC85A49CEA8D 49F3EB111A650BDBF8F1DC379F60094E6D6DAE86FC7A6C45B0B0B62091ADF7C2FD1C68A938B9 C4FA888756B4EC2CFD9E530747BC9A6B539BE75BFD0C95489FB6CD05EB913217B3FC6DAB2BFE 006A6F68F5FD0BA803D3D9039EDE46F76852D12A3D5C9987ABFA0D6BF0330C8488CD5A863E6C 543A31B1DA6596165F195417E45226BCAEA6CAC112D27F53B10059B8880C89E53A2B101F30C6 356BEFC84A44A36C2138F0C96EC656DD61265DE095F6C038039397CCB2AC2B43C916AD2BB154 5264055E22473098B61F1AB184F9821436FCB338940C9A7B3DEF162FDEDB709F7D40BE2E6D4D 831FFDE9A1D531CE1618289BC635F5D1B00F4E3E83E656302075EBDF2D24B81AB3D46FA86C45 DE437E87233B543AB99F93C7D32DFCD9587C16BDC697614A2B049062798F0BAE90B8835E68AB 5EC7B74B8C5DFE6F2BC51E22BAE42756D4282915496C479B3352CF9DC3EB8B270ADE29DD3961 E16E71E5A07DDD8A42FE4BCC987E6035296E13C52D931C7491628B8EF9D391A34585557877B1 0DE2D4989C652EBB4A0AFF5FC62E63AC8861623AA84B6FB40BF1A4A379474F0245079390A211 742F49706553BB02E7E4C720D977C661CD225334CC8F2E9FDFE542FD1CE21B7D51E1FA28A7FE B1ED584E1ADA0B8BAA72EF99F5F7C2875C09E11A12D019EE7C51973A73791168297EEFE53A0D A28A104963C82C1F8B0A275CFDC6D954F7A786022B143A6B5E2531AF3EE0932B8B7871D38B48 7C23D099B484888D5799028084795326B45CC0AF0F4F38034475A04C44CCC197C0834C92CF12 22A5AD9ED5814578EF16461CF530DB0BDAE4B013AD95E991D51EA5625886A159484E0490DE92 C682F3BCFC84BC60F5633C98FFDF4E4DF11F9926FDEF3C5369EE89B5D0009249E33A6B5ACBBD 2CCD9B56DF174DD99671C9EC503B639D04154A0FF8B166E19AA4142DE404D2B39E95471CA353 BEC85E73FA3184C6DFE7756BCCD79FF30C612276D149547D74E68A74060E316728248FC29898 8C3B142B0269AF519376DC26AC896D95F1EDFB871449EADED36EC0D962D06121CD197B6C7587 0B5C9E7C06EC2D248E02838C78AB047FF8E2A8ECE9EF55416D72E5030893E6EEF91A0A7476B0 05FA6D276A00191FF46CE53CECB26D959E5438D07AAD9D3B5DDEF9889DD62A7C62FF5EA2F526 E2B3ECE0EF9BB9C62CDDACBAA995F334CC6F285120B390310E09BC0664C6E5F3DDBB7038288B DB5A3F410F53EC29A3C847DA5A290307E3C0A278B262C18FE5AB2A590F52EAE3AEC6110BA5C6 C4284F7BFF88FE93FDB0655C36F8D29859D8D838A050B3D41FD3EE7CB981FF512548BF7FCB4E 54ADEC95788A4ED708AD836B320B91670935621119CB73DAF0068DC9E65FF632F0936481CC75 55CAA6B2C5AD0C8EDFDB101407D4A0119E2124456E17019019FED2E098284CAB786FFB31122F 4F735776A97ED51F40D45FB280B935EA90CEB6AAAA6081CC70ECBE9F554B2BC67DC8793FFF81 6EAFD33B53CC1D6484DB93CE057FD1C54E633A5D8A1907B75086B3D4A93ED8FF3C32FD91280C 24CA4C96B707FBAF60A238822EB716F90EDE57229D505D2AC82B0567D9668275644ED0030F08 D76C24B3B8E927057477CA2BCF8292A8256594476511A19D1B4FF330B36F94AF99EC31A3E1C8 1334B18A31808828E55E9D64ECB717ED7BBD62D47137A2224465C3088340399DD8AE3DC04571 148AB3128639D9440F94A8D4F24BF84CF16A43B852EC488FB66ADD6318AAD54C6121EE0257CA 19526FD50754C2C995AA45DB5F2D20B010390B9210BBBC3E6E91B52BB606BC91E34F8C028317 40CD62A317804768228D54205E4CF5D51598314B9A80FCD1C5635757A46C438BDAAA197EEDD1 92D1D168ECD10EA495C1C3E095C4C6AB13C3274A64DCFF1227C31CB1765F8BE24A4CD83A1CA4 A7FD122A0880723700F10A59257B23DA50EAD4D82FB1D9C6DD5E5527E7C267907DA539CF95A2 65C766B7F45328F79F1813306F184568BC77CFF542C7C0876E2B437A0ACDF9FFE79E69F73AC6 32B535E68561C5DDD1D44A4F160C81400B77EC107D03E878B80A39E180D432046E1ABE60293C 5CB3C0F838E2881311F3E18F8093370CC018CC42B2CAB90B84CA722C36D20C4D26D1C47D60AE D7DF6CC89886C6280FA2CFA6F0190C85C312C9CF0A23D79E9DBE0C742CEEA394829D78572D81 4461E990CB133D20103B77416AF2680EAD7A87460785B5F7A19E9CC5DFB8C4DB0D0C4B795E35 5515CDCE324FEF9EBEA5B059FADA1C0C7AAB8D9DA95CCCEAA3D9A274592C9554B53938A39412 6E2F640653E21015266DCB33D660F0740AAB8EBC1E12DEE7725BB0FE290C63679517FD040236 D0976FD14B88EF81FC8643D3820B03E976DC7F09285B2DE889563FD68FBAACB52ED622669359 EDE41DA14C1B704166D181AC4B9B62A5275BDC9EE009543F592FCF84FDA8A14AC0C18C5F52C1 F39040C1BD4D5AA7BE0FA967B1FC460524752FC2960E7954738693FF18E31F8A8964CF8028BC A14BC661C6FB0F24CDB663F4A52972EA64110D3BAD36817975CEEA0B80A22DC3D3BF9FFCFBC5 DE5B22C89BDE64B240AA9BF50453C3B8F432797FCDC5BDF83F08EBDA7A10EC524C31E764CD1E D3CC4643E7555CEB59793DDF22950DB8C8C5EF8AE42F948319B5DC93943644B8611E8E23A0FC FA50895565DF07359A54038172A5009A41DA953CC0DC877552059038DA7E4025394BF74ED5ED 07DEFC25573809D6121C43DB5788F231CAAA92FE587569AC71C172EAA1079DD656DEE442D466 1552D10E17BC097E33C93549815B6C7936BA7FEF189D665A1488886C1DFF0BF5645ABF24AE1E 3094DDC9D4F89EB0C706C6B546A28B66DDD89DC4458C3D6AC25675127EB251ECC5AE020674B7 6689612418C7EFCAE5DAC7EEF8532F2744E5DBBDE4CBDA2A226FF09C9AD75D3CC16BFE4ADC78 B86CE0EE6456986DE74E0BE3E38E07890EE1C53C07FE188264850394753EE56D0E2F7B81B0E9 3BFA5841B2F13219A693E736D6AE8BD51A15B777FA0AE3647A538C8E081AECB737058C918085 13F07D6BF2788E792FD414CF79C953773A489DC8C1A5AB20A9C9BDEECCB69CD6E23EF7AF9594 8E6625DC3F0E9044AD3E786650C845DDF7A73AD8FDEBE33F68AECCF19C6DE8D792BFCE4CEB7A F5D21052D5E3BA72E225153A58E2D5980739041D0102A47248E26CE4ECF9DCA785330D6AA804 F8DECBF21A9A4462F74D10BC9549900721E53B1A2B1B98ABC0949B6A5EB058C682AF62D3F3E6 3DE91F213CFC03C670E2334CCA2B3D8B41D96FF3B2A1D5AA346890467BE931A6D909ED04B1A8 36276233C7E30002A47B35D7B6A918B2C34BCB3C225C02563FB80AB95E63F0A355C76D5BF1C4 AD481B4604B506B9C32BA27F4DF89E7737F124F29FC2CC721A4062E90DB04140FBCDCAE1AEA7 7EA1E679B2B963E50B238956C147970ED054C2F037F908E569ADB2CE6430A2F3F9FA788335FF FEE802BD84AB94377B7C336427235C1EEBD78794BB4F85B4CF55419220C79AF00A964CB33E65 E18359609628E556A84E06D60B8C781FDC356ABD98660F929F96E81FC105E41980F86F7EB877 DC83FCDF916319B73C46B832E150B01F948F4218180617411B7E4B5052F1F511E71B976225A6 5D79F5A8A055E7211A5120613616FF3E01B96EDC3FFC08D2AC92A3093BB6143EE4907AE5FFB3 1B5FB5C53B2D2634D9BC7230E0EFC16F9867BD7695BA8CDBF2140AC6183CD277B5FC6A0E71A5 327393211336D64936D43C5C922019AB4878047CAC2CEEFFE4A59D3BB0EC0F6DE845E5B175DD DBCB74B527837DA7E292189F4303EC7282CE013B7E3AEB0E3E07E56D5D77638C3408724978E0 7D3678F9C4EBFD2880DC4883314359833FA270B28D9116FFC3CA8F50C880A1F8602D47B9D454 1C68644591D67FAEC5EB46840A3D9362FCC091135E66EC9D79656627075CB7ECADCD7F8EDD1A 697C7A942360B1659209AA18C04B7A283281A27EBCF1F6234E8F1F0604E65C9DE7ADEF778ED9 E6ACFE640FDFB20C68591E8080BD1C31A09D69261EDC19A250490A51C1AF501A66FF341A708D 7AF211DA47C66C7A3161BB05CCE9E60A661896E7CD7771B1B48B2C3B795CE94A0391F1388AB9 5DD7F2F4FBBB8CAB870120F7E898DA8E99F245CDC728FC6507C4547FCCCF5E26BF2915BB3B6A 892415753729572B5E833CE0CAFEFB6715C2AD5B00529B5526657ED81E8F5823B2F9AD402E0F 60B398457EA0C86E245659578791D92402BC267389494D2E4E18F7CB6EB37426A18D575234C0 FD871EE805AB7886A683BEE4E05D2FA5A332D53683BA1781B00ABE05432FF548014621FC0529 4DE73AA4B59C2BDAFFD5A981B5DF1DBEC484DBA328AA110E28CC0D865D73AFDF1D241DE5546B 10588A46BF34C9345F987C495DEBA0E06CCCAB4871585E5FD1F82C253CB9A3F12EAF2347E66A 3E6629120080593D07924D6EDA6CCDED9C97E416C1263E49B1F7D94FB7843425291C9A79615B 645E173CEA7D027EDC804B1D36D0B3DD808EDCF89C6BDD57808F73EED83A4AF6F841331A0DBF DFB37C1AD39907683447DA9096B3FB77A3AB717BA42537B364667F114DE35A0D96D76048049F 648F610AF65E49A6E050D77AD5A3A2EDDA9BE71C110D6F5A9C5A9F3A9B8A4F25EBB0B19C63EA 7A8685314D46A0B1E2731921D38771882ACCE671450A95FCCFC13DCF5DF92D9828BC43B15AE1 9E6183C4B9D49F6A4F24F580379EC1AB20641F2BAD6C04C1A8AC71C557CF2B6729F1855AC6EE 270B93233CCCEFA99AC4405830CBC1629FABEB9621013518C7AF03D8A613D15ECFEE25954D98 889C90F58A39C9F724D7CBB21B622565E00B742475955B35ABFD65A02C85F3A83B60395BEAFA 86A64BB07D698798A866BAAE35EE91AB55CFA516E84213F47DBF67BB94171FFA4F9BAC54A998 E73F11EBF323B2DE85F77E242703AA9863881A62376B434CB3939BDFE84B1F4AF1F3A92FB1B1 102159B4356E5BD308E0CC9DFEEB78F514A005D00240BD7826F376AAFEC1D81FF6CF017A41A9 AEE1F8DAFB9F928DD110FEFCDDDF6AFDB8BDF9FBE75603CC2833614DC893DA48F8C1343628E9 B7021E6919167A4B263FE3600FB766606E23D8CD4A5BD3DA63148D40B0366E1B2A2E003E7A8B 64832FE3AEB64736B8FFD4A3BE9D3307AC8F0DDC61D6A391198CEE7D7F01C3C099B37635BBDC 61032CAA04EFE52113AEBB7290A9C2F5AB0C17B465C9F3956C954A3CA84587989AFFFF1D3B10 06D86C11FA183BC11BAB5D9B62C0DC936142844766B1A412DA4D3FCD5E53E5BD343A0C4E7007 F7A501D75DA2B9B0F29B57980FDBA557C92E6B2FD8D8DAEC867AE57C852F19BCC4B7898B34D7 C65C297AEE64F0BD75A6E00F7AD08ED07B74AE0801F1621E25A2A3A9FE51D8E5CFBF41206E2A 67E8E994BF25333F5A05DFD069F0CB45C9FA2F8DE1C6F11389868ADAF2E96189F8D3AF33118D 4CAB32DBDEACB223424B5AED2F7FA8E30D59DB5C26504FE0914B6B729E4AE84C0C4D965359FD 1B134625B131C3699C8568CEB046855DED5725D205AB35246888A6BC5364B5F59EC7E1DE44B8 C594E43F4785887E3691E208E7FA72080E05199B4C630AC7A3CD2C0FF0EDDFE623D2A9CC44C2 FAD9EB435306319B62A2BC0CC08DE031092C9F41A5E35D32E8DDA95B99A627DC63EF5A44B114 B80A1B6F824FF05DEED9F59B40FFA90EF0A9624E93828EA5013BEF7655957627480B2AEBC4F2 484AC084F1307697790B580359A99A327CE8AA56609A934AD32DD85B27B4ADF4937A0CD140CC E1D624D2093E751B6CF05D3268B8F9884FC64CFECA9818D2DF276279E0DB0D92485226CB1C91 8C03D47FCA46AFD7F0483FBABB80CE4BD671CBA56A63251661F1CDDC2B9B2A656F39A2A8F18F 0466BCBC6114BDAD0165730C4BA845CFBC12A3D027E38D54ED89A157BAAA94F302C255C1DD10 2F216AD664123117E085177B357E9648620F1A2C907169B14A87A7CAA9AE4D0B6C277F5B1431 1247AEB10C65CE3A1703E7438FB7BE81890A5E4C5B639645E90B6C93910DE2E2FD86C0E44712 1FE37FA66AD652989F52A257E975362C1A5EE4D4456D889F73110477347CA1AE273E45045754 6AF55296833FD83ED186E63C591A84008D34D925DB46042C1F05BE6E429E7F2E63B627F7B2FB 9E190F2EC24F5A3BC03E1D84D7C308FB3E5D8BF6EA42E6AB84EF0C4C082837D9C2876204DE71 ABFC4A0E580170E7338A2843F10423F784FD4141DFAA9BCADAB98169E9D874D4C6B088EBF07C AC2DAD3D569AED109C75237E004D7D16F51A4B76F4FA2200F5932F436744D65BAEECFD0126BA 948042F1174BB210FD3467C52DEE9F1058AFD38478486A515C580421B179B64CD44AB4507985 61B5C4A6B76253EBB04061D91323231AA4DCE16B266E9A4909CF6CFFB68E7F26BBB20894049B 8480B8BCE06D1EFF70FC5BEC4684B3E2DC0FC097DE6EFAB180673E6422ECE34C256C6E242DB9 EA31D1E3CD36967603BC5D7C886A6E53EF6298DC8540FA56BA31F9171E89FA3B4AC527FFBC92 9E3B32C15A05D52ACD3415C80CAF2697DE96346238603375B9AC2878AEE9652FF4BC2DBCDC2C 56C9E133F9A26790BF05744D730C2992DDD00528B52E9579E5BB7E4A6C2C4E1FD902429281A4 9238E38E6E6F01CBA1B2235C1C21C6840204027C0AA3D4D9EDD08DB513A9584A83BC5A17FE9F 2AE7C9AF494D5DCC3FA27831E82E9604646937241DD511AD8B1A495800EA4134E4622B33D04A 0F43BAA2C22EB3CEA8AC9619F65FF6D1828622DD70C9EE73A4A3BD96DBB852674B85550645DE F536D06FE1A819A1278724D3528E207FDA8EDE4F2BFB78534258EC4E9DDF094390DADC99B0EB 3B4CEA10A11DD8A265D4FE95062C2E38A67AA31421BD7A826A143E123E2F47B2455B5EB7E006 08FA2B677CA8C84E225004FFE3472F73335D2EBBE348D60FC93B692B2584F4FB70AE4A03472A DC0B22B2DAEBC1AD880AA8E42CEB861C9679B6D390E2A28762A6E17BA08E300913A7AB44F48F 52A522AC1F2D1E9B3A7241FD6C3FDE78AC147FA39F74D8CF34761398A445CFD4F76F013DC26C 040B637F86868ED89EDA4792A674ABDC27BF4CB7976BDB6EBB8760F390A87CB9A967F215738D A8174CCC502A151FB2B76864C1097503799FE658E9CECEB0D157CD55EE1C347DCAFEDDA62ADC 04F8E2D2506688B16C7AAB33DE08A767EA004C5E172A3AF59236AC58A473A2BABB771004F965 A617BA9DCC41678F5383067728ABF5C2B8D6631883C6793C25A040B8C6C81244A2834D27BE8F B81345E9A37612991D9F8CAEEBAF76647003F8EE3A536CBED2F05C2D5A23CC9162BC3E2E376B 87489EB21AF59A9715FE24E40B0C2B52E7059A995621B85399A97B1E6323D027E0893C97D5AC 9204129C8259A5631D5476D6579568FC6FB0C9C9814CC14A2E37274E93B98093BD3B098CA610 16C64B8E9955850F491A3FB44CD6D8F47B10CA825A5A41DC106136D87C40F7E94FF131F81212 742AC8FF1DF4D8A60106ECC3151D8EB1D02ACC30AF3FA413D397DF2FE235D6266412131A2F86 28205C407FE897724BCE54A8FE9C544970DE236EB1C9517BA5E4414FFC346754D8B8E2BD680D F3B92661051E7E4929F842CAA53D7C947BE00C5C23A4547487C7049DE63CF966D156F0E6E888 909FD551894A6E2A2F64933E639D8873A9F9AF7FB69431542AA6E28EA3433B50B36034936E98 9E7E2F566041D95145A45BED860799EEBCD61D57D9853331C0CBF4D3C9B73D445AEFA6FB8C06 82654A1C69882EAAA9EF6D95415C9FEEABE69DD6FD26FD16741A96D78270313DF0D874B5F044 BB3074BCF1A03206A45BC425E3FEF9589975825719C6B6E866A634021CCC47206B0ABDFA13BC 9489EE0B3CCF83B268B3908CC4CB2310C02E0EA8CBF08EC2ECEDECD1E388067500B6EF25937D D88EF68F77B34076B2AFF3BB9D3C04F811CFA309D9F824715C5B1524D1FF930C76D79119554D 6E186B6709C0EF0FBCD7921C256C42C41536C2DBC3D87800A4E0DC308251719CAFA133737CE9 8E711A13C35BA683D79BCAB512B5A16C5277AEC7680A6B8F12E83F6AF1163BEBF3C68EF9CC54 6D6221A5AD1C7E23E4025DC73E9E0609A51130491CECA6B4244F5F44866744A7AA6CE4A254E3 6B0CDDB5DDE478336241D941825FC38BACE3CBA8466FF4012318AD09546C6E3DE8417A5C750C 8AB0BFB307077E56C9B3A60FA407FEBC8E2B574E11C77778D72D43BDB1327D2C7B5FCD6A17FF E02276132214C408765440E01F2A787DBE497F4378CE47AB16BB547AEAA321E38317B1EB3A32 C37D7C65CF4DCAA8DE9949453593435CC9F2DE5F3901BA59220C9205840F60494DA87EF62349 4303B2A7C889A003C74E9F0DA9D2C8BCE2123F7CAED5CDA4C54A090830AD1151A0EE620983FB B07F1F98AB5FCE07DAF258B01298778FE752AC0E70BD3F58C8E43BE1C5CA093896C1DBDFC5F3 E117014C1FDCA8C820C605142C3C4C949D583B45B68A9B062ED9AA5E89DCDAAAEAA309503F34 9A330C2CC45CDC9C975999764B2B7B27A05EC6B1C880129CD122A8C83B4D5B5969D16137462E 4CFD940A0972BCD78FBB298EED78225690588A32EF2554C04B5D42C9864736BA20CC08633B2D 547CE1E209A8A2A021FA83D05BC05AE6FB714D7B45A76AD1E0E07B6EC1A91F3557047E13BFB7 E0C0E363E4AD9C583F794ECB15756D3DA1075936A33EABDE36D1213F7DFC1F2E8C92B70739AA 7E747DB7C08BC77B9E9481146977A11E98F3863F27391A0A0F63FF684DCBC957217A29CCA37E 6A1FEED928E80325B04080C2CBA0F2B4C74A8614C08D419BCE99FE4C086C758B0BA23F275412 B4A3A16D9E2EA569A6E4656073756CE08B88A700C836B231C28E62D6A6D432AC8567C93591FB 2EECDDB2940B1C39C3D29DCEBCAF6E7CDDB61F89EA5A9E440C2E97FD04CA5E6AAE9C67A478ED 87780A8584272164C41B757220EDF415096A7349E7545E8C6F04FA7016AD4678712B7848BC77 B3C0C7F2DCEEC77BD6BF8805B12E90E0C0A163DB0A27FEADCBB5166E8FAA4DFE237C04E2B4A9 C69778FD43DD6B98CDF597BF0B3C35AE85A4BA48927325BC7AD59C0145F35891E9E051BC48D8 448A5CDA8A4D7F7744A7C0D9255C32839A66E8505DA51B56C2509005DD446B2CB08B46417A58 BAAEDCE67AA392D4C12447D021B7757262C7625C6C42A3D65BD5380E58B80FB18913DD298A94 75A555635F7E3468B6C33851DA238AD2C6B46B86D43AD830F3ECB8B633033C6B8CDCF3CE86FB 9984AF44DC129731F4935B5052D2A69C34A74954AA899E9AC33DCA41D7F7E8728A6C815D4BEE 1DE25622AC387C4BCB86FA9A28DCADDBB8C4F783853420FDDB196C4FC5969F039CB3F2925D04 E9BD5DFE69E812E086CC7997A675A860CDD6ADAE88966BC55FF8B76EB76F4B2B1B957A2C000B C71B9EC5B79EF4EC9F2A2123575DD2DEB30335A85C6BF4CD4F3A0E78C5855A3CB531DC0B4AC1 874A211B0346347ABDDF82435BCA9502454FC95BAE2F5833FBBD1C6624F1076E707235B8EE05 B2334F208810D4382BC1430E779CE360BC622E850AA96994F12B616E3CEAFCF982884AADDB6B 6437A48280EFF0F119B016FF787CC05606411B1C086C67FCD01DA8EB3C2880C939AD143DC95B 1C164A19377B06A313D5C34D2F1365F6D7F46726105B4D76838CBE1469F9D3A33FB07AA2B387 2859E28984006FAAD16751D619173095230483731666360933B4622080238CFB7C5B199DDBFD 8BABC9E36E23B9246ADA37DE17B6B8795E75AEE77E830A8C2C2020AF1F5B740A91042A9119EB 4555DB534F51B56FE92AE8A475B09D65C572F5FF54FD6AAA8933B4153DEC2ABA5F5C58EF7026 A77818F5FB32DCA9D52479B009B626BE665ABB2FD01D8A1D9350615180D3B978D312722C9803 56161A2B861D308FB89A01D92FA8E81D9DBFACCD035E936BF9EB76599C59AF3B6906ECC1BEF5 6FD2724B2B3AD3C363AD5F20E3039CA7883DD83114DED0427BF8EE9D8B41A8E646EE9B6F949D 7C1E0230F35C5BE6DB05E6DAB7E2780C9FDEE34CDAC5EB8AEC92645ACE83F38A7C270C0DD303 88A1CA18FDD1A38097BE733F6AA279D0861BBAFECF9EF7293518F5343D3FABB1CBB8BAF9EEEB 4EA21EBFDCFCC6191EE3FB98EBB22AC7D1FC4EBDA4337DC1F155D6B10A8DA925738C76EEF7B2 82D0177AF7694A576AF9B186CED25823E6BB856D89AC769D68F66D23F9A5FEF24680A13DD44A 7B31D9201726D2F24FF22D48B4FCA4E3FE08862942C602217A75338470120427C05448403DBF 6B729D06336145B4C1B91E65C5EB0E9D7521D273916D5A8B17579C8F4F698B7211488A87C1D5 4CFD50D017BA0FD348FC0F61CCC82DD98324CB3D3AB9D4F6FD396681DEC984C33778AD67E239 46E492019E84D2FD6C7CDC1F825FFD6F4216E3C926F5B12D6E3E9FD5662B5735FD0681C932C5 C7492153904A4CA41E94D1EA57008CD4BFFFF93F918D0C3C4ABD27DBAEA4D65527F667E4E711 468A3EAD84935566857FC972A605379FC4B63C9C27CC73600591AD8C7BC47625C61CA69B4540 EFAA53D37A73B028FFDD08A772FCBC499C01F5A8220D17A8AFF37D3A0DE7236EC77569D193FF 67172E449A49BCD6BBFB77F19209EF351E15D0FC9E146B84B79A7E099A255B663728E833C25C 4AB2D4D2833644EF9E3029B7AFD7736ACD3E58E794261B1CDE1490442085C4F848F6B3958AB4 DE052674386B590AF64B66173B311402CBD30C91CA3B07DAA67DA0A057DDECBB3B19FD6B3F7A 1C232BFD49BFBB30C2BA6F48DFCE34A2FFCB911041C1FEAE5887A739A8E079ABC623529BB250 8899AEC0F861B06056B68AC9B5C7DBE9F7A00337823D8747655497E65EC053F98FF65EF4FBC9 09579E206C33D0178D6C2D60939BB8CD94A80AAB56B660443492CDF0CB9CC3023F00B0B39F80 9C062027FF1CD3409673BCA5DDD3CBE7FF21C94CC7E84FFD488A99D21A703DEFEF9BAA490C59 3B0F47BCB348D1683E02170054496E415494190D5DB20A96C3C1D2D593D3E25EA65997FC07ED D68BA0AF1CC34320385235BA488DD44F3EE33F6A290993A387998ABC0D6D906BECA5F58FD14B 52D2DBFC847A708F8EB3712813AB23D8C85AAECC1E6F54ECD758D08CC3DBA223A5C50909B029 ED521C20CB444A2DBBF9C8A0C4C21EB4140F7FC7E0497D5E21039CBA96876AF926E4A7565A26 C7E203BC5A547CBCC4223F903B8FD833BE6CABB94E7E3801689B73CB037A35E2418C9F4B15BB 902FE80F463D81DDC0904ADE5CEAA569A58C88688F70223B69E8A1028A79DA63CDA3F47BE4AD F06BF087A5B616A95A6D54D89F4C22276835E1412C89A6339F87A1E8DA230CA7985C33BEE355 E18CE97E53030BE021DD3FB3AE2C261430996652216E74C295077660F4C3094E1F1882ED7236 D492B7D91655C1EB5F35B10BCC14E50927D68215323C2B0680174C2376A816AE9BFB5D6ED92D E760A9A808A4F151228BDFD462BEE8AC251DCF4286839EC0B254BE7B454012EB50A10DC9FE30 3C28F27AA0D401F37FC59B9FC40F5C0DD5563D4B06AF82C0983B43E95483372AA545CD8E8B11 EF00B8BC09534DA1B9E66C4E84DB2988AD3726EAFAF12699C6F1BA1CCAA51FCBFE6D45B3E95F 55D2D238AF847B1EC69F92CC536548BAF8B41241580CA88FFEBB394EBDC7C22C24FB0D470A6E CA4AFA718E6DFB3E5FC6E21577D67A07E29BF8B7059938F86F0D877D53BEEE0A1C11356E1D07 554770F23EB78AF92E113F1DCC916285CF8BA2BB246F8FCF76C49DCB74E2A1074ACDF7AC19F2 2B953E49D7857750C1434A8886A151D150FD6D9DDDC5D078BA46980F3F1A7CC1E2C67276A31C 75F198B56BBF328B3B17F386AEA047233B67BC93A4F76376AA4C092694E881687E589F4E2317 1BA3DF6BE35A16526921B16266B8BCA3545EEFFE1B9F2BA347E20C2F094632269AB26982F9D1 C3A43238C4D973B15B896080286AB6F093446841139AB22E0FA0F4788B96C02F24123CC6ADE3 9B02B45641A9464106804BFE9E88AD3751F11430811DD264A5E92D09E3B212825320B4AE29B6 BC0E65C9784B68B05C4CD1648AA20DC5375E59E678038E6CB1F4C0A0393B32EBAD4E6E8913ED C147412D3F035431E9F28902618BBDB11E9C9902F9D462A6014B5ACA9B50829EF93F5D7E45F7 413982AAB70AC6A8313DFB9F93D8E867FB7F848DD34E497575CE012D36AE468A00F72125874B 6C4D6916EEA2117B3A1A78199EFDBE7A8944C34D835DC6005D00167A4A9FDA2019AA0FA521DC 4729DE8EF77DD4D2C4289542133C5124DF315974272178AEB8932B41203C5DE0CF2E9E79FA25 0426B474068F9A3AA907C15E72F881C12D4A43E2B783E8DEDC4A8ECB51ACB5955B82D496689C 7AB9BCBD634DB3DA04716E240857129CAACDE83E956CD89ECE290C69D15B4F206B13B722CACD A803E376D985CFF24E477B964BCCC6084348F01A4125585945BAFFCF31C3B30A01ECAB7FEA50 970C3F938261608690AF59E3C42A87C085569498D6BD29C1CA59FCE1E05BABCDD02E752E42BE 145E88D703DA34D5290F8B495A4C8F9DA813454A1ED5488C067D85E98A64FF9D0ED467347BCA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMR10 %!PS-AdobeFont-1.1: CMR10 1.00B %%CreationDate: 1992 Feb 19 19:54:52 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.00B) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMR10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /CMR10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 161 /Gamma put dup 162 /Delta put dup 163 /Theta put dup 164 /Lambda put dup 165 /Xi put dup 166 /Pi put dup 167 /Sigma put dup 168 /Upsilon put dup 169 /Phi put dup 170 /Psi put dup 173 /Omega put dup 174 /ff put dup 175 /fi put dup 176 /fl put dup 177 /ffi put dup 178 /ffl put dup 179 /dotlessi put dup 180 /dotlessj put dup 181 /grave put dup 182 /acute put dup 183 /caron put dup 184 /breve put dup 185 /macron put dup 186 /ring put dup 187 /cedilla put dup 188 /germandbls put dup 189 /ae put dup 190 /oe put dup 191 /oslash put dup 192 /AE put dup 193 /OE put dup 194 /Oslash put dup 195 /suppress put dup 196 /dieresis put dup 0 /Gamma put dup 1 /Delta put dup 2 /Theta put dup 3 /Lambda put dup 4 /Xi put dup 5 /Pi put dup 6 /Sigma put dup 7 /Upsilon put dup 8 /Phi put dup 9 /Psi put dup 10 /Omega put dup 11 /ff put dup 12 /fi put dup 13 /fl put dup 14 /ffi put dup 15 /ffl put dup 16 /dotlessi put dup 17 /dotlessj put dup 18 /grave put dup 19 /acute put dup 20 /caron put dup 21 /breve put dup 22 /macron put dup 23 /ring put dup 24 /cedilla put dup 25 /germandbls put dup 26 /ae put dup 27 /oe put dup 28 /oslash put dup 29 /AE put dup 30 /OE put dup 31 /Oslash put dup 32 /suppress put dup 33 /exclam put dup 34 /quotedblright put dup 35 /numbersign put dup 36 /dollar put dup 37 /percent put dup 38 /ampersand put dup 39 /quoteright put dup 40 /parenleft put dup 41 /parenright put dup 42 /asterisk put dup 43 /plus put dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 47 /slash put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 59 /semicolon put dup 60 /exclamdown put dup 61 /equal put dup 62 /questiondown put dup 63 /question put dup 64 /at put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /bracketleft put dup 92 /quotedblleft put dup 93 /bracketright put dup 94 /circumflex put dup 95 /dotaccent put dup 96 /quoteleft put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /endash put dup 124 /emdash put dup 125 /hungarumlaut put dup 126 /tilde put dup 127 /dieresis put dup 128 /suppress put dup 160 /space put readonly def /FontBBox{-251 -250 1009 969}readonly def /UniqueID 5000793 def currentdict end currentfile eexec 8053514D28EC28DA1630165FAB262882D3FCA78881823C5537FE6C3DDA8EE5B897E17CB027F5 C73FDBB56B0A7C25FC3512B55FE8F3ACFBFFCC7F4A382D8299CC8FD37D3CEA49DABDCA92847A F0560B404EF71134B0F3D99934FC9D0B4E602011B9CFB856C23F958F3C5A2FBE0EF8587D1F57 74879C324E51FCB22888B74F241550D7401EB990D4F3A7AF635198422283CAC1B6CD446DDBCB D915DB9BFF88844E784C6BF7389803D9450B0C21756A017306457C7E62C1D269F306BD3402E2 66DEFC3B5E7D8A8D2F5BF0FE6DDD40D07391DF4FAD4A6018DCE29A2B8F692B29F2023A7C0E66 DE8ED85C14F1F8492167357F51A7E84CC5D92E0FEE4D81CF7FBC8DE52D2E7BB57142033993F9 C08C315ABADE8DBC4A732E84E142D3BEE51557910E12CD8AA37C459A5E6B7F5269F59078ABA3 BE4641A11AC48D0B625C8325B38EC08E4C9E5E7FED976A5650D99D82114F449B9CA14C4EC957 702295A39A93EF93F61899B8EA06B092C3C1E503E6E436E0A9FA22576C8930AB3DC8C20F5D82 B69CDDF8FF4DACFA9C54BED5A3AA3EA5B129FE96BE632843B9B6BC91B615581A985DB56B1E01 CA60EE69CA92CF5C0882ECE62EDAD3E106D835348822400F0B66AF658F2AE56ED08F8B001057 1807009B73AB12A8CF14CA6C71F03C2A48C500F9D62266AF154A6375FF600D9BAC3F05CE3414 2D6867A79581C533176BB2F3117336671E2E44638A97167E2EA9644E31EA16C2AD2990EA33C5 4001E0C8156E6DE8AB6A4D40A7137BA275F39589FEA2E2DB8256ADC103D6F9CC038037A47E8F D469C5F98A5E3C15BD4ACE40D340018B1CFF7D1ED8ABB0AC57B5B5A2C20A51957B96C453EDB7 DAE5AFFD91A46D938FE0A13363001D844DED4323F1EE6D30012AEA19B024A552315505535C85 DC26BAD31E09C50E6512802976D298C4E90D0044C362E6BF3AB362A454EE93DE25CE54411090 C29E9D75C80CE26A84404BD9DE3AEE0E3F921AC587F907572B8354A5C3165EEA7E8B2BA4E333 802132F760B41A900C698EB3D2738BEA0AAF7AAE96A558F08B61AEC7C7D65B2889BB7B99800C FFEE5BA19AC90FCE11437BE1DDFCF0BCA5670B543B9644A71C8726D0C1005ABDB96F6E0CF7CA AA3195017CA81519151C2C0B04F81E717C0691B63A76E9B25329CE2625B711CB7BF99D23EC2B B5EC8AEFB8C1A3B422AD617B3DA4D49685FD44CC21A1FE5E1541163AB3E1594601D63C7E9880 1D7746474377CE93F81404F3570AFBD5DBFE77578605917AB96963987E6EFC2D3F99FA56ECAE 6422579852567F90CC90E4EF6D6F71D1858270205477E221018A375CA83C572B3F972C5181D1 8643CECB04909D84CF767174B3C0C8EC69BF1E9FDFBC0FC7ED97EC67D878EA4DDAC8CAA522FD C6932DF721B81AF837AB56B547D4799241310D6692918FCF8A46189A78D6638AAD7CB4462D87 74EC73D184076595C94C0B4A8233CD34F2D92F6FF94F941DFD589DEF2CE790D5CB2159B95333 8C7384CB68C11779120A68BFA20B993D8C0313987EB96A2EAA2C11CFD838E6AA48A89E6DDEF3 FAE1A1B078BE9787140270556A96E2725A8CF1AD46FB52938900730154AEC60F544C3D49F176 3861F54B46A3B70315B46EBE51C42FABEA87A5339ECE2B64270749188D73A07E0E3866EF9AAE A996FA92AB443C08FB8A840DED26BA68E94CC23CC1F6968B0F3C7E8F4FC0C5CAD0F7A332E7F9 55287ACF2485539C7B652F7A29D9E4AEC20A8E023AEDE26BD4C761BD3561269FAAC6FD5A651F FFF9211F8DF220994DAD6D105A92D5794CF2AA526B2143C7150BA584A2B597F6982403D93073 CB066B569BACF95DA04B4202BD24059A8DBDD3ED8AA9E89B2788F3B078A81A557BC743C12A1E 00FDEFFD030C032E81DE3142A106C0EDE1BC9D566440BCEC4260295CEACDD54BD0E25F6B9DD8 FAC41F453BCC731777E1E6ACAF37A8178D11BE1BEDD6681815F3D5EE8D240B7CE9B14FCFAFD5 04216F26DC2827FB0F6158416EB24F8BD7616EBBFE9378718824CC6E51135F8F489E9A55A0F8 40608A99A32EADE4251F27FF86EC7F324DC9B534D7135E30F2EC1B6D93D7DB919651E03F30A8 82F2DFA457D307F17751532AD70E632A04A63CA1A507FC6AF4073126BE0127D86974B426F489 FF62A53C1986FD048AD76454D42BE16A6060101239B138BB638765C46EB006F7F8DD312337BE 08D4381272FCEFBD74B7B2EC098B436365586A832721A0113B2BF1D853FA8B062BEEA25CABC6 0998CF4D38B49A3F4BCB372198A196C9EB6DF2CBE59A59858AE212031C9AD7FBB9C3E8E9E6DE 45DCCA521F3AF361282F7B3EC507C8B3AFCF18B9678EBB2F11C01C9DC3C4FD3134C5A3DF6B6F 4C75EC985466C4F505847F1475C91E5D83A6BF754837DA02F9E868EB0DD76EC4D31C8B1ED935 ACCA73E1CB9B4192BB0A853F947228C3064E8F923A9133EEC9C52C626E29689DD54FA433B970 2636FBD87C5D81C4F278168783509D5F4256C77A855C97A48D18DE6EE1D47C7C33E9AD227ED7 02F120303731BEA6F3055D764046EED36A06C75855A928084C5773168AB985DEA7CD767C780A 91E740E6E088CB93D43A489145030221DE0E1B2DBE954EF414B9568F3B1C5329F5FCBEE927AA 23309AD22E10F9349B6CADE7A090D19B9460405CDEB89BF1617B2C297AF5629458235F1B8C95 F5BC442DEBB34DA5D20B11E96660CE9E5CD19A84AA54F42B106FC87C7C0405B0CBBC249950D3 A7C353D691D77BA031C840C8F43A220CFC749CE34C2791DD627CA074753963D2E59794496D55 AEC96FFD48EAFDB29F8ABC8D91932DD5B01F65EBDA034BEF3C7219E097670621058662C5BBFA A939DEBF999E9F68E5C4E64CBB0774A9A186E741346103865FEFB088AF547545CF7763DA0664 96986377B587EFCA5C9EDF22EC13D1AA6F483C4A0ADDFE395F83534D7BE5285E6A207D53A8A9 60ED89E9BD27AFCBBDA23B2D9876A8D8CFCC299990D521E076CF8387D514570871376C21509B 95EA15CCFC7278851F14DE8308B72E111893F0338488BCEDD0F2F8EAF07326BF97C3727459EC 89F8121C96A45E3DB1C63D478D0A6DA5F5E6834938EF1CA41B910F25A82F2774E3CAE9F1909D BE21EE8E003E27B84C43B39FE247B8E19538648F246D325357A246365B9B2B13DC68CDD7E44D 99D86C642565B1FC376D2E530048B27A7C44B6811719054D3AC99CBBF5665AE76F11E2781B8C 040F73454BC794B1432E6C3A58BBB8CBEF345D3178C8D01D6B26BF7F485A5C3BD36DD01F39B0 34E536ABDC6632EB4038FCCAE0453E85B3BED8C3D4620A2AA2DABD0CD93090E9B8E964C491C3 AEE45B592E4EB12970647E2A5E68BDA429F53074257C02975268F8C28F06350C26646D658008 FAB0562F40644EDB0FBAB79826B16CFFEF1302C8A13173CC9CF7C8FC906693E486FF096B2D18 E96841A5FA8A34A5B4B68462BFFA48102464DC22EB50F1F80A26E929D4CDC4B90589266915E8 433D46D433ED8920543777360D25546794CD9A3A1EACE8AF188CC18DDB9DD1659F9FA462A5AC E6A6AD068140356E8C1E48DEFD171947F78F086C6E267FEF13D16EE68D0FB0AAE589F7E090F0 88FE80BD6CF8EC0EDD28C735748FC6E7FD421E33B16EA6319937D2D63A94AD76F95B61813DB1 81A113274D5F3B4DF5EE90E69FAFCAFBE4466F5D5F48EEA62A7CDCD4F9418437707F706B290B 86C30FEED99522875EF5E2D491920983BF4E9F1C71F20F1B9645E30521EBF2F1C9010103C60A 9A6DB7E6297F7C3E29CB150307FB7A1A1A94710EDDC6AE88742CC7044492DD7A217583C99A6B E7B720246FDAA00683A3B82EF6BFA87F2FCD741AD8BBA68B751740435DC6AFB1BB88D1593DB1 52CE92C19E1AB29C8E8FE89477CDDBBE29B8DCF1EA6F70990BE9A0425000404F2F5DFBAFA35E 70BB87066464C992343E8BEC66EF483DCE474F3ED7953DC1F6BBC14EB3495704D1765D0B3285 A05AE494342F6B70D9A4241291B3147C77A8AC0E08E5BFE60C8B6E2048876A6CBFAD8EFE4860 95DA764F4AB9E4D8153F89BFA2D9BF2759826EC18F64F1AB083949F4BC127411A477D4C24D7E 0FB0C96A96A31386CC5892B398D48750FD09638BA6D62CC685688E79AF31F13B744F395984B2 0AA483FDA558C6A91CB9AAE9053E7A5B5B8659BF0631C543F4C370FFB006290353908786BB5D B373233C12F3506E2C4DB0D59C1EA8EA75A7662B90C4AC1561303F4FB8536C1534FEAE4ED772 DCB49734F5285FAFC99FBB081ABC3DBE87180D9BDE2A844B054D8BBBBEF5CEB39F5CADE252EC 6164A74E75625050CEAB8FD8D8513550D4420FDFE6FDDCBB816E204115614FE82CEF36DB23A7 DD31CE6FC923B575EAABEBB5820BB2739CCBB41BE2A4A95CFFEC9332DACF05936A3194AB4F77 39E5B4A868A7CAD3B1D940056F84B41E81B072C02C0D0BDE7C64DEF54B1097F68368AC0B39E0 DF5E5733FEACF02EF12A1CD0ABB0805C2F7E7FD7C824D9B348E893D68F3F31B807829015C54B 8D2AA7E8DAA14A364428F3E706FC649E274E47914452704B1BC56A41CAAC736C8826B7BACA1D 4FAEBFEDDD0EE8FE3BCB53EE291356B7A4B699C33CD7EAAC34E3B92E7F3ABC32852453259908 74E34513647D521ADA13F83584CEF20DC503EB352BF881AAD4C00894CC581A819CA7CDE96A9F 8DBFC22767B215141C8677BFE6F1F0DEE4254986AE871F87BCCDCC10E2298BBD90A625337936 3FFB2B093C2F54001070E655E9C4CD389266DE373971BB763279F9EFC4E5A223990153618C66 54B5740049A3DE2A80D613CD5AC5BACD34315C43996D1A420DDDFE7365060EAC81AF060B8344 3FA8176CBE3F4C2EA819B493FB5B4A2E4A0039F028CAB0B47FC70F178DF04C7CD4DA22BFBBE5 344C9E9CDF1020AC1A43C8E5B9D19B621565A6DAB2B1CB6CDE2524B33FB1DA6B5988F5BE4E73 08A17C73E406DBCB51FEB3D79B84FF8B0284F7EA92BEB9CBA6CD5999CA7DD20EC02E000FB48C DCA51B8E747C0E25B28431543D9095482657364ACC1C647B2140C502623F7B9E3F335C2E44DB 33DB82C01AE27AF66BC2284971A5249911D897263210DE4A9A65232738D83D10AEA8C5D3C687 128B64EAE94D6FB30B7BA9105BA8E01BC9925C312CCD8BD273E904D8FF13F4DF7EDD21C23D0C 09A32A4C90B0577ABE7AAA53E836CA60B1697621049BB36F8013026D77910193742725574222 DDD3ADF4E872E6D57C1DED571A1636893DD7F49D8280233CFF4339B075628AB591783783548F 17134E69EC5EC25B3B8036039DA276BA1507649E7DF1EF9E29F0AF07BEEEA346D470B4F1DF92 5040602539BD1D8218384B53BDF16C74A1A6BA2A7871B67E06CCC015BECF2F020295E27CFAD6 2D3EB7831922FAB24780FB158C21E769875373606E1BA9BDA9F15352EB5413FFE162EB2AC194 4BD7D980D232A2F3DB3CD38390E0DCE3241113CEAAC83EE29B2980EA6DDDD4EF5727024E4343 AFF44318AA1382662A78A41BFD6ED98264A6B0BC629CF924EA0A635B0885D682C26819043E39 ED44241D4E8B50AB92256F9431A8123117D77891AFFE4E2833BC0517DE287A747E88409CC30D 7D098A4FC80C6D91534304E7FDA873FEFF704EC1F7450226F09D5E89E245622973D9A789736C 71E6651182BABE81ACA969C62E1458FA67A3B9D38CF364F383E719F7066D2839D95F262F8A5A F87DEF903EC3269466519E68E857088D318839FD0B0E51A6D358A93A543E2401F57FF7E970F8 BB7BEB37BEACAA000EC58DF62D2064EB45A81144C146B744B10406EAC2C1E350E2DC328B6A83 9DF820B289A84167B404BA1FC63E453DE7B58A9EF959D7E2FC1DAEB5CE90A1DD935E8C5D7DE7 E2684FF0502901BB451FAF9ACB439F548657E3BE938E7A2B5924DDA2E7010CD26A181D84A5D7 5294F6E56DFF88F3C207C9D457CDDBF2D3037AC9A93CE9D53FA0CAA4F21057762954580F0F2D 47AF43D5D7679A9D44D45D682EE73493A2B8C390E24EF27C84E701C879BBB1FAD6BC8B89BB27 959EE86BE486786D1C81612D9546AB59D5216367C027B5B0F51A41C9AE2778A04965A846990D 1727F3F3E09AD0B913C9742371AB5669A2CF4863833A19CE69FF161B1D6BB0CD61272CF94526 4584ECDCD290E2767F087A836F12AACBECAC49C3FB28A605C6220E8233EA2C9AEFDA87EA2CF9 D3D52FD6D16612AD07279DDFC4F20B59C905A146B1F4A51547DB82758886E9D3609B495BD941 616057E460B94856191791A2D16B90A7C33534A9DBAE17C96D68E009219857FBC92EBE189875 EFABA56704CC9305DE0D32C4CA5293B306A4EE9DCBB131C128626C4171EBCB2DEE830B9BCB98 B4FE23BC63C9186C21EB7D9CDFE2E685399D57D6D1A857C11FFE47F6D0BB79839B6C88702EAF 6A59BEFDC8B35A03768AF411EA16C277F7EFBADA006619B31CD2EAB657BBC8CD4A44340F4D9F D34007ADDDF2DCAC3058D22267490E90657808CC716B7EC3444638215495A7BF077956F16EE3 053864EBD2EAE7B210EA370D71414952F2076D689ABD98E76030D92E4D49A79734FEA3F05719 8F8DE62F64468D06D0E6443EEE3F2677049B08E8A09907A2785D91C009F8FAF6F1DF1CC39D0A E11E8F1C939A0C13E49A448E89B0EDA7CCEF06166A8449B358B0C661E40A7935A6E4F866ECE4 23CE4C978CF749F3B2B8AAB56AEEEDD498DB77143F77B4FEDF5C6502A3D2AB4D0BDB8EE456D7 DA3B9CC800DA8D0CCAAD981DA5193A528C7B5628F065B7FD1DDB0FBC4A74C32751E8B4747206 8A3A6F380CE2258D33FC49780EF2570FD279BBB54D4246F40CFA9F13AA9E13C6CC030DC19960 115C2DAECF52027F917D3D9D44C60B0B2D1030EDC6BB055926CCC512AC2BAFAE7C12D8ED487D D3901FC2842D3A7A69117A8B82292FEA44FBD40BF6C27686EAB94A520F63B77B82D5425478D7 4B5E4E81A8439F560B1CE7C626E51CC3EFB877A9AF37BFCC1A72D40855995DF53B3F4451CC29 A5600CEA6B2FD2BD9DDF106FB7B6B6E19477426212F3B5C25DCB1B777B643A318046E02ABBEB 67201DD98D892D6E13B0853CC206B62AC7E7D386A77C6C9A3817FFD5009D515EB5F770DCA0BC 4D9DE562EFDAAACEDE34096EF6DCEE08C735DA36893C41592443E0B69446B93EE9F758EB75C2 4FCC4E8193A1F77999F2D4395E1BD24909CB805CE3A26A47ECF376A79F480C9402DCF3A86BFA 971DB7C977F813C21AC8C071B6F210B251695A40B735D7F8E27F9DA47AF7FDE2A6E7321488DB E7555BA82E23FA2DE3092227E1A21C5E6DF4EC83A0578B4E99FF377C9E655D7D6DE412CF0F67 D3ECA45624BD1AD4EE76AAA5F99C73A1FB470C8C7EA472890E1436BB51FE764F95810DA0C3FF D1C3136223F6610F3B226978B8F9E35C9B09DC863C05DF439717251910A64E4AFAF2323CE1D2 A168DC57CB1F4F2F9D24071F49444B1A5C6956F236734816FA3147656FD7C5F547748AF983E5 529FA4787E540BDC4023377A7B7E248A37550CB0FD519F30F1BA3A323D171612F802068AE4FE FF8D067185F9E5211B1218656EFFB8762824E05EDBD304B71678B3C4808F7819AF193B247D3D 7A3EE51986157E6D101C07A521379A097751CC6C53FC6AA6519E2D0093AD0CCC5145F4D788F0 46EABE997100DEFFC6B7D79BEE09A92E34BCC15124D2405BB614B4E265378126544D041C4A16 71E65832930D6F15E11387F39862F9BCD513CC611A9F9ECDFA53175DADF03BAAF5C32FCCAEFF 3446E67A62D3B15294E426310F64B6509E88D3225DF909BE2C73A9CC8CC643645B394CC3F5C6 1FEB91F1522CE9882A60504C14C69CE7089F3EE5B3202D3E5C2C2A98B8A4C8655A911EE03DBE 72E474EFE0A0B1FB9062E474DDAE008B0ACE5016AEFBB40F157B9BF07ACBCA319380105AFD61 5DA19C9F932BC8D14480F6AC4E607FD4A7C34AAC43CD26301EAACAB8A4DC8584EFEB56A2E569 5E84030F39501223DF87FD3F16D3950713C483D8164FE2A180AFD985C11D55A9E22A61F0C5FD 3A0036DC51904A84B07D409388B897FC92C1C91A971B2482E668A27386B33494F751B5B9EC4C 5ED765A88F5A675960AA7F644E77696BEE684E098C69A8119BCA27067E52E1FA95C3E54CFA56 8FEB54B92C3A8A2DA2CB44C9DA1DA7BAE1B05087D025F767658D885E89D654620C2827013ECC B38C7021F83863313BF35116AEB2669FFABD5F1F035C23BF0244099A32D2FD13EE00C09E30EA 3BFE334227C6A143CB716A3C584B6ADD52C6370F7BA917855F2295B9DFF2BCA64A0504D0E557 861EFB856A19CE99B64EB7EAD11C2474E79D5EC30DE5DDD094AC37D8EE50C4F4D39E32E284B2 F347848ACACCF519272AA1FEE3000AC3A495B54385CB50373AB7B790B473D0449B7622AD526A 1BAC985945964D6D2B05089ADCF9DB30F1032639205877D7E78DB7F9B136055C1451663CE4D3 9FE864E02B1339006A1065FB76C6E438EB132629AF5E1FCF6022E608674E3546CB02A893B558 F3B2C76BD0A897B4EDE61A21B8F6C34FFE820D66F3B89EDEA86E13EF5CF0E33E82BAC2B4CE6C DDDB572ED1C9AD69FF853ABC58C0CACFFC0D86D80D7C8D10139ED4C9DDA73C4B56E375CA70FC E18EB1E322F046A4A44AD7F2731BC2059E391688C03B86B305E9BD9BAB8F3D1B6EE52789D559 A5200AC84183FEE544DB210122C74BB2CA648599DB3CD1AF261567B84AEB332F0647288F8F8B 01D5068D74D7E89472D8DF3E901F6B523FE04C519843E0B730F403BB99CAD493201F950E943D B95FC52B13A3AD8CCC6478D5CBE5DD019BED1ACE4D02E09353E6E31B9A9EA9C76D89D9490D71 3CA451693D235A0C8B0A3DED5CF2A846ECE5CAF52627ACDBE76CF57A09CF6768D0A53906B15A FC5183B9DE1029D19E64B64BC2E075B536663C524BFE35C9E412A7C0D23D316E0645BAA41DF9 ABA61284F801F7CB852F49B24A96CD4C743F9B1D1A69F3E30808282C32C2C4655715D8F3AD53 F3FDE97823989864479EABAB5876C77CC134EB66C688BE3777C74B3A87EF1616DDE5A8A46185 997DF2FAFF5518EA7AEC3379730BC509D09C5C378B47DA67F9F5740B641DC790766896352D0B E0EE84D686496066469C995583EDA0BFA51178091918D2B9EE8CED4163E45FA312885A64F177 F03E6D77DD649C7D71B47FE885D72887927AC070CC64E825917776264E722AA6157C22A429BC 0D38B56E5A0D6473FCCAFCC17B4BD8860ADDB9BC33E2FDED66EF95205FFF084578C37913E205 9CB3C1ECFA4142C0A2AD1781C373CB6FE9819F4CF8E5B5774D7A6BABB1FAA71D0C96175B9DFC 08A3154C2F1AD566E0D03E6A01D3848F0C6C06755A0511948D51FE8626A32AE97CEE9C01E15E A61A556170E7E4D3697783BD42D586535C38CCA8D543A9AAA828C4813E89BC30B686049910A6 C01D7FDCC55895A3F7019B0CC78C23925D8CC1207C51FA19E6B8992A289EDD5669C33186A7E8 38D5A0A3C101C82558785010F877B05D943C5F874D0524622D43EEE25CA87C2AA4553804CB6A D1508B9406BB1CDF868DCFFD19483BF1D8EE2844E62A2E1CD09807983B7742A841BA2A03D8A9 2568624EF3C504F9B2F4389E23E323D1FA1F4F0670711DA7D827400F36C9FC870EA2553C7E25 45E2A5086FED5BF966114D5FB48721AF70E04393326BDE080D3082C292C9C251E2D82C0C3F03 04E9A46203E0E5E76829E21A3B961F02AFAEA15397F0060E5059A5FC66A2B622AF1D62FCAC51 6EC3327C95A0C2810EB42A7209D12E90D1D41EF442D0F3DE55493615D4135B4F44BD09759657 58B16A8DF9D39E78A73DF41C2EFBACC2C91ABF75C849E2BBCBAD263F8577E16D60BB6BD463DF 3A4BAC62F28B44CE08BF52A268AC27779E3A317B965A44321615891B627541C53768F33694D6 EE76903BBED8ACC45FA00EEFD20224E09D95E93605987839D92C4E0E1853D8C3F25FDF0A8268 B38A6B8D9286535A49B25631BF31451F81B5ABCBA66A07056EE34EC320367DCE6CFA97113291 32E1155535F8094570639F9FC72E1ADBB4EA99EF7C7CFCEE8D74C2AC70927CA9973C4E1C4DB1 13613466EAB58C0037BA93230A3D6EF41739122912A15319374C6A6D7FEDA8B1DC15EDD2F286 12EDD846D8AA051F24523BF92C6920C2AE3CEED5868BDA6ECD483ED181AB69CCE78668A087DE 0A00A960810675F75412A8EB6018C638583DFB07B4B4CA48C2D3A7CD407F552DDD7A91556004 2B173D2DFE64EAA41500FDB64FE572E09D06BEE892AAF0CD711F3D6752302EA4F69AEA675A48 EE69C2416805E7E6EAD9889FE072F1C2F5D3A89D277A90DC9EA38271DA1A455CCB3598FA99C5 5A788073DC12B2265D409DE2DE24FB4399E911CA80169AD5812BCAB83BD0692C37A1B8053585 BD7303C20B6A06BDE9873823DE9E9EDD9F403E78E7C386341919035561CB94379210A5E14CB7 43687CD843FB306B6946D8BB1C290D802EE3F096F54D70743B22E661F81C89F190971F27FF9B 0E6C273CE3B35E6F5A586B411F6CF55C2909AD70D348C6F6322EF1DD08EA36F1B99ED590D012 3DB978BCFF31E5EE9EC3FB969E71C0864757AEEF1750ACD6A6F08A086CCF15E65A712ED37564 B73DCF2A5E86E05C7725DE9F13DF59ED3E92438D9017754365735E5731853520D9771223DE22 52388C4C6F7FF44614112780B14180C0CE01C50F94BDE65F4692CFF4B52F6D9D1FB562475BF9 E94120A510389E9B3574C62FE0CD45E19615971BECB8C2388B4D5D095B914E6F887F3F708D7A 65B516758CF5EEEE4DD127315FC3EF04CD5915978141B2CEFB3D2C0FB5DD64E25EEFC85CB2F8 80CC6AD20B9C9F0C1256A9C4E8CEB2B400C8D50079E6F58F7A064CCA9FC3EEAA7F7C34BC51D6 799520C5534EEC1A1EFCC52B9ED43E7695ACAF3EC4590D9C0BC16915769DEEF8F39BF7992449 4888D4DCA2484053A29598DEC70C2BF94BC2494BE4841F9676DE13196AF9B9A329DA016F17F6 2ED26A75CA3089750BE5DE919429B989EEB4C10C20AB764BA2C4035F14264B055771B6AB98E0 D673580FDEBADD2719C80E9B8322112C9AAA9AD2329B045EFFA948AF1EF7B0038B4D3C068CDE 62E5F808213F4A04D4979BFDFFFAC94483C546B35E965D4D0625FC01856623E146EF193A5538 09C0D1E182E8D7759CD2B467A84254A2EABCEAF9E764A05BBB84522353B2505C56115F489E4A 906064C9C5266F823741A1BD1695796BCDAD01B38003522EEF9FFB7FB7F79F8D6C43B6685C17 F72F06060993C9A30F8E31AE8CAE4F3BAD51D8262688A6443CE6A07C1CF676CC4F755849E2F9 DA19B14130FC72E31BC6E4E062C041EAC5EAC486032535FEDC0DA2F8BDFEE2B72C1BF0BE510D BA08E0A5700FAF1686EAA93420F20F92C0516609ADAC4F7EAFB5FB2CCDA18BB3FEE2702A462F 8AE39A733B0699D29FDA1E821FB03964F477A2FF5580FA4874F60D6F3505A4287E17AC2BF565 9E42FD41F257EF45798CE2D8E09C0593FE7C41E67D79316E8D61CDEEEEEEC60EFC9BF26E803F 5C3EE7404D05ED2018F8C9DD0EBEC3BD39E20AFFB51582BD5049DE9AD7437849330674FD17CE 6B9B6F646F9CB66CB5DE5457BD512BECCAED183FD5C5D834846E6F8BE301FB267A4A67758590 3CE45864294FEACC65B46D604D84D846098339D20FE034B77A49DDF85718CF9DE18D10028B37 15994C5F2571EA3DC7E98F66601C647C80839E3F3477D78584870837F653243BEF6FF49C347C 5FE9C7F45A28F7BAC5AD9929D508628CDBBD4EED3295F06CEB89D378632C34D514A0B22BEFA7 E090AFBE45EA64C03BD1367B63763F4570D25F59E83D344E8DDCD26CA66C1787FF09EFB314E4 CDAA3BCAF8C94372828623E973768B6FAB1327C6CF5BEDCD37972CC2505B12D2A26F7D5AC9E3 F623024A9370A44BC95FB17C035F71BB43853DC7CA66BBA610CC29FAE5636B21C2366F88675E C0EB2BE3C127BFD579CF818ED98D657779430F5C75A0CB97A52F3547907BFE2AD55A59B0B5A0 DF0D25000907FDB6D5781EA549FA89078516665CBEF095D9411A2DD1CF6A355BC77E2447ABDD 21DA230AA18D5E130DFEC1B75E5C1F6CB9D3C860A95E9FD960EB8D73EED1E168E357CF305786 A8F01B63EA2D9301A6A3F886CBE4F678BF1BA1CAD67F3924B6408561A435E0720DCDD29C53AA 53C1747BA074E6588B3AB7B66B5686AA58EC9BFE7DC107D97B8EE627C9E79601B95791704FCE 469944BC90EC77AE5A9A5F2A73A4894712899DEF4BA334DB850A7187988BFC315A5E207AA6D5 76741B3068F18C7AD741B6A4B6DEBF5A3C3E178D10E25FDDE0A01AFD5EEF225849E3B5BF1846 28EE473A34303C2524D78B8E7B8D9308F1A90852C8463AC1997C91DD233CCB7E4A16E95CCAA0 E4AD48E2C499397A4F558C23360EDE957D872238A446C39024A369429B2CE348AA5FAB425897 EE02B71F085DE26264002AD168130598150C4F560E0510A135014E55A74F65B4CE7E1A96146C 609280B49F0AF1830C3C8A6045BC7774D3895348962A7AEE947AC962547AA28B02608CE2F91F EC34848EC86C4BF8507A9C0AE9A0697699531E11ED9E85CCF52231672F0879B801860B013181 5CCFC49012F03305D6D382E4E4565BD1D2F860EA8BD636D8582FD332972F1CBE62844355C933 786BE37490A7EE43217854DF7797EB8680B93D9220F643DD70B2993A7A0A194159A9BE04441F 478A77B3D2CC38302701166DEA70D72224C9481BE0E68BB6802BC6E9D131C3B3FED642779139 5CB3393D4817AAAEDD39AFD6508C9CB4FD67FD3BC18C65F27203AE022A522C1B750960B7A745 0EEB8718DC911D645198227B2E729B6CA4149EB9D21369500208D94593A087C76205D1046B91 4C31FB5F5D6FA1EFC908532B27AFBF73C27E2FC9228ABF72920CE48C03E3381A952A0B1F25A9 9EDCD216B154AE6279B33315E822EACF095C00D7359EA834885DB0E6D07BAA9091FB364CFD43 E378ED0C06B9A1F7C3A7922C85DAF6CAC5FC111A51292D4C7D43E9773F262AA032782252CEBF 2274842EA390B0056C3E0BBAF1DFE11D91679F6313316735FF6820166D4FDDD7E76A72469529 1E224466ED210C82AE79C44A828E7B625F872C5A3723FF9A09E7D77D0555C9984F7EFCBF3B9A 1B156E5047E312C8CB86D26B0E6345FCE3BCF8D0196C95C5AEDED0403733EB6BDE2F6A65CD1A 0FE13DE66A2DDB3F912ABBFE0CD59D4A6D9299E1309CF7494C93896FE76C132FFB98E3315B28 950E21CACA613DA51EA612678FE24DB3B04BA25EAD7E2A020318D2C79619B78BAEB21AEE2E60 69D8470392695EDFBFE2DFBC2274D8BC8BB3551CA84E341419C7E718187260497EDCAFB7F588 D1C7663CCBF8DDF1FE23C48D1A9B211BB0C75871CF8DE53C45A00E601F87BD65B9471CCC46D4 481C5E83BA65153CE608D5FF6595FCED940CC0999FAFB2F44E0055E57E59C73BF3AD6FF70CC5 A0F32A97D61CDCBEDDD34A295A3A7A9DF1EDD9169616D1F8D4C5E20A86DD2FA590B46A974D11 45FE89D1F0664C3E0FEF70DF6D393AE7CF0B662E285C02E9C447672F73E90138E68F216C0072 F5BBAB3943B40D24FB09841E142889A4B927E4A7F762E0ABDE430D6C4D8026F76A62B3B35BF9 53B1EC19932E8E24EF20D2A50BD0EC86D6C0A61D1B206AFDB625353E1FDC15F96F3A48303DC6 CDB7E4131FB3B6E7D80B1B332673F6D1DDA6BCD90F359014D59EB5445FB90E31E51D9E1962D8 20792C2AC64E60125B0EE5CBBE02AC8BB9CA43A2961A5012E0BAFB42DA92DCC8948B043F0F98 C522149E57FE699C9BCA6DF84D5FEB2F55C49407AA52345AF0F2B39C360876D5A6FD1C3C6D42 82F070B8AE2DD3BB78DD78C7801A235EEF4A700128A9CFC7CC3B122CE69DBF577F6531B7898B A31A1B915CCACC4B3B1226104877EF805795A93A2F2EB41CCB759441A17E6B7B033094D0861A 5A55F80D94B203FEC9582926A9CB5F8CB395C110ECE72754485D674DF6CC0BB84882BA26FC17 01E3B2530A2D44DB5E8702DF2CDC597A8BD9CC12E95B7D274A51136B61E49C7F920BE8E6E17F 1B20EFD1F6F84ECF575B2CCB40AD7876E8B8C7B083E2CF8253D06CC4F6CC2A5FDBBD8CE6986E 18F759ABB35F7E77AEF16D5BB2DFBB457DA2ABDB2148EEBD4F88DE2B9B3244FF78BCEF9F98D9 3AFEF587269D7952B9557D0EC61FB268980730EF3B6C5CF569EA19DEDD3AAFEC29D8FB9DBC80 43E7C702920C678DEFE3017BD9791D74A6CE7A6BA312EC7407D2771A6F22E3E81EA35351C3CB BDA7A7A5256C67AB65C84F0193D75209307DA141DC60D87B33684BCAAEAC9047A0F3861EC185 132A14F5F48F19E38E132FEE76B5D7C70AFD29FE30411C5B7D624BD75FBF27D89844B1845F02 7B866433344AF2DBF37587F2144E40358096A2F6CB884595E57C3A21A1B5FD1A9E007C530FBB 2FA384169531124511C0E643D093478AAFD5CBDEC5EB0EF47546A893EF0D04E30A89BC3D4516 351662F937F26C80CA874E471EABA85AB541F51FE6F94E01BA628A0EA320FF000A2C3B93162B 40E33F49C81F759B0CDFC167B5E06A6B2592D78794A4A91A03F9F95AAB96850F726DE1782B03 F66CF1C647872FE423AB0DAD21098C19A267859AB150D8CEE49EA83C0984C348D06E99EDB60D 797683B4B5255E3C521619DA2C26038BEEA2C6C013383A30D6155C3C6FECB3FEBF3205D291B3 E26CB6F76AB6E222FAE350EF49B9C15AB1DBCAE734E377610A27B1013F0AC3B11E9235E952F6 C65DAEB43581FE06E04BD94DBDD42AADE4CD6B475DA642910A0240BCFBB2848039B614F11B5C 0DE8B157BA49EC715748F2857009BBB3A0B550B4EB88631B53A69F025F61E4F0A1BF13265E20 78C6291C114B8ED63A7F3A2D3FA6EA7BDA7445CE3DFA913FAB9FC964D6A5599175CE8EDE602C 7F17CC5E9390AF0D3148FBE8E7D5C8780DF83D34E4C1CFC0BA9DB11975A171928147D4053086 BB7A29B4CB6620278E5D7D42B5778DB639D37D3149B525FA9A2B972D3F33A2E6735130446448 EABC73AD3E00E0B2F5E774ADC1AA4E9ECA4C0E5DC2AEF0F7DAA42D37CAFBCF8FE67CDD3E7C02 413E617562850E2EE2E68744895071D192B4505470D228C8CE86FF4B650F07E454F8DF8F5376 8226231441DC5A026FB268E920C71680BB1426E4FFB38B27A019398C3CBBBEBA91C4988E10E3 D873D3A7C8FC4FAA207B94A23E653BD646505B8688530D3DD734EB22AEDEAEE8274FB964378E 744E82C76A1E65E40A60DA47189ADB7FEF7006F180C2AEDE96672B55E12700D795951BFE14DF F7EAFCF483E8036C07226D1259883EC8380404BA3523D786E55685878EA1CC6F9D2B32DD91AE 126BECFDC77B9825D602E3F18EA08021413BC95E5F64A120D41C719CD786BF2EF3E1A9B5CF28 D80F65B01191653515BE6B53E59834541465F45839682F587530B63A3BA92D74062042AAA119 12B071EC81BF6667D22DC7302F0A5299F3F3432FD03820E43BCE1007BBF0620163A0AE9C1A62 B6FF44204FFA819F9D85849D450ABEFF5F3EE19B3FCA8EEB405ADB8A05C4809BCA050F846975 C56B5079AE720299A7ECC8D846776048693005704658E43640CD89E6149093B4778AB677B379 7DE560AEB7E09DBE57D723A4AA62EE8C42A83C10418133D262E5E9CBD39532F3881662FB84C3 8F33ED685443965795C725956506FB106FE0960832A2C292560D3A43EEB72F4355B836CF5044 767477AAD5346469F8E4E90F712DF820A0B7183C0FF090444A994D81E2941EA3C373282BF57B 9952FEE56B1B0B7AD89AEC79A85DC03FD2A35F5B87E061D15B65A48398F836788F6B41C749DB F425391D99F0B31420DEB5C800EE281A427DB0C1FF7E03105C434F95907BD74775C980B4AB46 A88652C8D59BE6CDB3531123CB25E9AF5CDADC324AAEFB9F8DC7E1EF4D288C6DA52487B922A9 C9526875CB3E528AB79122F9886517E892115104A20A8EB4CA7628083B24C0B0F0DD2BB0D35E 3E1D3BD0D50135F7B7F1F5FA5349C9953C4F61F00EF5F11E662AD12E8D9F156E32B845FB8E12 1297658DBFCD943F1AAA74F38D43EBD080C41DDC92101722D829DFD3EA37DD5120803EB06734 6B636815A8738403DBC18BB8D8164A8E450A7273F8164031290B465A44A268CAA510E9EFBB71 114E603718BBE415F2426ED24BA413B286C42902D8C5E483070D3A3C57058E6D640369797383 5C78166A00C235F8B4A4D155E723010F7500A7179625D248F2DCD8A368AA5FC85600143AE81E BE8D901EF42702D30AA628595AD111ABF0E1E06A7939420D648F03FC840A51919C588BE0F7B3 BF71B51EC7DED081D0E2FACC72D65C77FD6864A2A30748803D0558ED2BEC1FC3A91710CC9F6B 2C8A66F8C4EB43635926CB75B89AF438F224DCC5A542C653790E2CB2831E6AC5590BA51EFF51 40C5F620102ADA7E964D21ED4E7AA39B2735E67E1862227C6E1DA2210EA7080000E90162F5F5 2677F188D75022B9A6173AA3F4E45449348EFA7A4D119A8C4682A1E205DD922BD9D65A5620A8 D9D103B853D56B872122F3B649565C904E6284D66979793B16C853BECCF478864EB043CFB096 42F0675D88E62AAA8088291E844F34AE84CE4A93721B4F262E0BFE50BC17184D4A2A469FFA94 8671A565C708A79A8DA61041C5F60B1D82A50C52A6E145FEBDBC69CD0F32D81382EAB87FE7EA 2EBAB016E169E5092C277D28A0C1197B760AE2EE5E307FE6B23D120605E03374AFA65DE773C9 B543D6B6321732A158873823AACEDAC38B2AE5DC0DD9EC0BC159C6861C99B18722B6C84CE819 07EA32F1D8434B6CD6C68523720859F1C1663A921B7DA0DE2A9775B181AFF992AB12E1A1F3E4 54E7342B9947D893557DEA500F36598D00064657C8B952E299D679BA20D0583FD6869F131495 6CF2D1D8E81A0C20556F28F8729ADC075535CF1006D8F1750E479AC6066823B31E969ACDC75F 62EF2704DB581A7B4FBCD22ED0A794B52494A69F4D57816E604BEDB0C1CEECCD3F80B6B50C76 065503F13C1DD3834D7DB2BF297B0C8B4875985310DDF076F0D6721FC205C9C0957E43E07EE2 CFE21647A2BFBAB8136866C9C4EC51706D04E2408E72B6106F02085E5213C5D88BA0B90E0078 FCD4A4214120820F0809736F4E3C06C6E0E6B4468A4089236565AD25A85730BFC3E476E5F0A4 DE180BE7A504ED02596543DF24359B7EAB8E5CB1AF98528D4F0FA8DF2EDF90C2C6D75600BC94 61924029635FA8E2BF07BE105288333A93A0A70A6C4A7F6D8D5F3EE677A017478747CAC65A57 A0FAE14371CB16FD6C39BAAFEC9AEA1CEED0E66F30E5F4B5D0E8D9D56DAC6D552163270CEDDA 49E5272BC389831BF07FCE638F7299F5C0FE332B7E29089D77B0140604B8AC0377C10C002046 8F250B3F03BBB37DC29F5B1CB2189063B8BB0F278AFF414A86A2F8A18FF13EBEFF00B4D723E4 90B2947195648367E0A7DFBCED6EFAA53EF849C79DEE21E5665409A44422C3A36FFB74FDFD10 17D31C32F9E269640AC36C3A519DB5F76198F1AF12F71ABBDF8CE85E7E6C2ADABE4B47897CF2 4A1C7B5934494F07790965C18296B977E332BD853232F2E2BE755F36AB8B1773964A689E1BA8 48F9F7F01BC585E125F00B90576FF82BB1BF90557D064D38079520D19DAE87A298514BAF1ED0 0B89467F5FD445762B80F1EE8E67FEBE8B5B2558B32CE738201712612A56D824983EB5403A70 6383D135BA5F1EDCE9833B81465B34244901802B7684AB914548C88C32FE91DFB0917751D843 5058ACBF0BB78D11118F14A0B9411BAA1A6E04088543E99B70130884BA971F4DD03F1AA3F9DE 4B1935663AAC294C9597AE21EB145DB431FFFDBF163B23F3C2675662C37CA63569A818D47B85 3B59983C8B6EE24560B2C7D426283995D86A7DFEC4B6558BCDED8A74D214BB6C86CFB902CEAD F6C5FEFFCD06777DD761F9F9EEF09E9A510E0DA31C3B847130961459642DB3E533407A19AE36 00973E4F70EF0912C462769AE399EC9861AE5D2A243CA6538943520DCDB2A86633F3D95F1F14 E6D63126FF361FD287539C686CA9A6E4B46154467CE9CF10EAA3DE0EFEFDD09BF305A5584C29 DAC82DF9418734B01CCCB57666E0EB5E5617EFFA3059FBEC27D3DFF8DAAD45EEBDADBD272AE7 9909A4CD3476F9E1275298429DDA620C15B1E229135A472B013F5457269B9682A3D41E20C66E EB7B874F26FA9CE0B2C8658937711366BD4BEC4F30A14BB1FECA238CE9476D66D1BF4259941F 61A7DE0FEBA45E5002A9AC44A7587FB206277C01F479D7CFCE8809687AAED92F7D148432CE8B AC0AD62DFF7640554D59E88CD83022A8A42D2CAD6EC197BEFB73669DB969D468E7519943F53D D324F2E9795526537393C3E5298B9F4E9961A182A324DE0D8109539FD483E1C6B0588584A30C B5052487BA59B78E2959B3A2BF30DB1374D585BDDA52E088AA672AF40A933C94CE9B9F63FC83 ED72B19AB818CBF269FC03F38DD982A48B8206307A10E6833B3CD33869526F10FE1C92F7D0DD 56C163CE8F04442CB0DF0E496F2A1DCCBA88D0BF260C0EB856E081EED167C6EC1D8105B2D3F1 73D367CC27D0F26FD89995A2EDC6D1A215F57847F7236753FBEAB4954510CA68688E51034121 F2CD0D46C7B8E89E138FC4EE229245D537F8F5009B76D6117403E10DB46109C7B58A67E0C14E 6347DDE8242030734D02A5C3986148528BF20973DF3D17DA67E53334B678643F09B7F887CD90 87A6F635FA5FAD0A2EE43668A8B1973A42866A399B280787809820D0AB51787DF2A3907A564D 10FACA4D9B6349C60852C06444FA49F8E2563ADBB0EFE7B8250142BB06FC4C93C81BD8B51F85 86AFCE9678D4373ECF051908E3435470C360935180B80B2C03B5033E2AE1B256B426E09FEC5F 902F7A8878B3ADE833EA39EF3D0AAC1160E1AC3FC15170DC3FAF6D17664E6292C51B268666DA DB416E5738176D6CEF2152B529C6DBEA6E563B5F7DEBDA3E49EE6EFCB88677EA2AAD003CF528 6B21E648EC332F0F0579EE648925B05D50261FCEC1BD57A22E58595CF326B5FDB2FFD9B8DC79 4C5E7854EF9EA34411546D28C5112B9DE1C25B861233341B2CC117C9C310160F612AC6F13F53 4DFAAEC92D6B2CBD9C3F3C0CED06B910260F7A2DD09B1B9D44346CC5A7D10B4D637275D505D1 301078EC936B96BCCD9A2B783A93019C5B769C15636CD94E9D4A24BEA9521A41703FD6F4EE8E 362FE33E21EAFF8AE02DEBBE9D9B379B7AA0AA0FE94C3320CA64F41FE488FB58CCC5F13314A9 F8A8428DD1D713C07489BB76A462E9C0E237FA5FCDFD3A0349B6B77067F055B7FB0F28953384 537535177D190465C354DFA1280FB3E804D3FC0D6E2FA88A5F2829E9AE07E9F7844463AB695D A17806C271E20C58939A04B5F8DF439659990D8D8F885F3A7A43A4BE49C7ABD03DAF5DC78CE6 6ACDE634AD08C33363EB642ABA7D9C34C71C74CCCBF7F4ADF9A201E203F6540BC467DB200646 9FCA0ED2234AB1A31E73FC05E8D8D906E40B3055B3696D72C48080934CC62E8E850350E70CB9 558CEBAE7EDDF38DFE79FB501A6EE6676F9B7697FB4A90B84CE04808434D244ED68AE441F19F FCB2E0E62DB832C31F7EE26D90CB6FEA5DAA44C297E51E6F9952C794562BF286BE8727262E51 5DF58D26BD9B97A5ECB5641D517DE35941143757645D511409808347297FD5D84E4BC1595158 9C4E272C6DB003B51628D3753DCE430C6154F4A7C5009CF5AA61D9CD61CFE3398701B65CAFC9 372339E6642D01C461EC04840A4F37E8289A232B1C06D659AB081C25CC56DCB1B914EDF4C7F2 3CA7598B264309A0CA15F079ACA4F69630C6AB6192EDD8A2350D3D1F239FCE30CEC5C7597971 6E22A6B3917E8F0A05D75F8D1EFE57E71836EF46D41E4CD87F11CD8857A3821E6A7E4D596C39 739424E37535699B423A22CB07CC47041D7B97260181794435F38CFAB11A7F571A725D084101 07FE3E53B16CAFF56F14B35CEB1363EF20271620260552B0B9FF5ACC9E8C508A0F07A4768AD1 77975F80D7EB3FB92B04A9AC5FCDD9738982DFE4B8DBD646D0F1035589116E961E1000B677DF 7B598EF17FB7442E07F625CC07E7B7BD4FDFED5CBA26EF286DB92F99CED631ADA9B6E4AB3654 C549D5539A2C6B2BEF7D9685F6C5BA2AE5273D15CA66EFC6FC14B3DC2FD47B50E6FE3678531F E11B861DA29708943D8914EC5B164EDBD2B04DA634314AA7EF8158C3F4311CE9FFD5973DA940 22C33E3A69931930572FD8DA9DCF8AB915CFF613E7628C5773652D55C64E1DCEAE37C879FC17 A35028F33B8D14731DC832193B35D6EAE7B2B5BBEAE7DAF05B3B34CA3235D81FA537EADC80DD C32567E15F80BB2A484CA51AA8F3C853696A740C271E1FB34D3DFA72394B88ECABC1F4E92CDE 907A139A5B57406DAA97AEA576412937FFE4E2689853C7B86FD869270B2FED848BDB95AB3E04 C77836021AE12BBDFB0BC68C09AA4F5B607D8B724C24CF6DCF4F54222CEE4EC643F1D4024C39 8ABD99169DE91191911AEFA67675C21D539DB7C39462FE640C5F9C9EB684C6037315B548DD49 F0C35252F2E9D5D4571880E66CDE49FA9653949D2F28AD44426978A2127122CD77B607E9D03C 74D9DD7D11E4A9AC2E3457FA9C79DB76AD398AD5743F6E077C36423E0DAFADD1D391EE4451D3 F94EC65470BC74FE2D2252F0540BED609F760145914E9437D9CAAC61BE91F76C5F1979C9C6A6 F73E690DDADE3B1295251F0E9DC3100CACBC3EC17689A8CE1AA3089A387B2727035514F69E27 048AAC20A38EE49ABC7928D0109D3B230B37F6092388AB62CA5B382DB76922CBBDA2D61B5745 6880763654B4D83478DB9C0F63790EA68F5C154EA4853D02B9A849FFD65684C368E68C6CEDCD 85BF1F041EBA86E9BDB490CD8CEF298DBA42ED4FAFD561C2CBA47869505575220B8E3390BA7D 411C2BB7B16578A834BB1504CFE2644713BB30F2C76D9DB397F45967B8F146E7C4782B203A97 BE20412D4B2B6D53511525292E48896BC91D3891300E48DB9B7A650DB26FDF8992063729A8FE 4E8C6F786FF4F4BCA2018C2861DE6002A8D4954BD7EC80CEAB7DAE6CD07586E733B1E862DA8B 1D4D2B0381058A810522C303C06AE34D5EA6F05C97B4FDB3FB1DEE799511F2EA9750D53E2A1E CB6058C9988B55BE1E6F1B682C689C996749691B6057DBCEEF6AB5EFCD604DF7420EB44763FC 30B4812891FB2B67402A24DEC15BA326BC89E6C574597178EC7CC644FBDAB6493E545D89CC86 BDF8826284E8697D2417FBC5630CFFF686E9F8F6C5F7788E975FA9F201FFD1E99B75E69C2395 F2EB3CD74E2E61B44049DF0B65F91195233228490EA9B9380800C1B43905B862770DD378C920 CC3EEA51351DDD3EF6C68302F96DCBE3D740F4A3E359419599817FE10E5EE241B516A7AB852D 01B570CA085D306C75BA899A5BE0F5BD883B1A6EDFA8EA72E5F66878BFE1208151032ADE4804 2F2C7DD0D66220F5EF66F4D3BEA1014EE7327242F8A8D948750934D22B7C36B2CBC01971D5CA B439BB320D7831FEF3C9785645D9996615DB538084C5072F2D20F6A8909C248AA6D34DEE11C9 1E5C41C931DD5076C9CE87398A58AB06A1AA7A07DDAC01B730957DFA34FCD86188DBCC7C8A94 101F09209E7B123FA9D671222BB65EAB845F7787EBF82A0F59A7EAC3CCD936F54A048AA9E36C 983FA1376E1F825FE112D4FAC62BCE3DCB285C5138215EEADC3FF9504496AEB0C443DC9EB28C 1C3F27BD1C449FB7ECC661697186F9C31CCB922F2B9C9CD4AFD63BA3CD71A95A52CCCD50C9C9 BE17A47D3123DB4898A75275D93D74EADFE72B7BE3679FDD9DAD4C885196194DBA0D297F8033 1B1471EF61A839DFB26FFF95487496B4280D02CBD88C1DFABB04F98207ACB5E5AD8B4D4D26FC 232FE653E9B30BD50930833E2B9D72A7A3C57C9744A0992131CF0AE770788FC6376FB187EB6F 1605CAD55B40D0B9132B1799170BA18EBB01A6B92D5CE2580E5D5BC15B14113CC32643C74805 17AC33E95FA1B318328613709D3B05296982772B4784B762103E906EABC30A8C542598B970BE 13D8F79EC2D4229118B8A71E708F049B728205008B75CC96661B1F19CB27320E6231644CABB8 E8A3C07ADD08A88F5BD1448FAECE9C2E9E959FF42AB856C9F0C45B170D4BD63743867FF08D0B C568D473801E2B40F9E99DA8DF577732784B52FAAD05893033ED069CC2996540E9BAE9916E13 9276031E66E1ED34CAC0228B8C7B8E0E0A8C9CBDEDFB20E406D5C2698733F1912BE83FC517C9 268D3287C66D5059D84F52604387E0684850DA394D1F2B4BBFBFDECD45BF88738074512A1905 70057E2275BA2803036A91F9A32E64CD7429AAAE7DD6D28C3159694901450896D483717E9ECC 4820349ED3E5FDEA88B1F9AE1A7E9A9090DADB0DEC035EA6EA90399F3A942E3401EBE5B483CF 0779ECA7685E8D278CDF6EA2FBD2A7CBF18314F5257756CD3E342479E3AB75A6DFD4F9D7C3B3 5AE5042A2B7FD3CF5C93ACBC3167BDC9A7F0D25D0CEC8F73D79A98EE89A769E5A41AAFE97D55 688F39C661B575A6601ADB6399B43DC5064D54F07E8299627A114254B11F1E8DDD1E7783CC7C ADB44A96E8E54CB72A448CD387FACC2BE66A5D9A4583EA6B1C0E4E7685739E22F50E52488EE8 D38903E9BDF9CED151FFBAB79C1E159A06C11C70D91E114ADD520627460CAF3E57F77063FCAD E73F05C563FB50CBF0F2913B6899926A6BFD891E986FC06001C9D8073A781F0981FE9D4C4D17 E49D1793608913238CBE6B973F9493DF8C7123702646446944399EE25B1E5A40D3AE74728879 203E2D5F005C3955382FA450B86A58C68BDAD3FE1793D8E184CE250070CC6F8C21E277DD506D 4C8064374CDB89D4C5EF1859FF45BCA98BB91FFF5E52BC1458991E9C296CE2F8BE62B7A34D2A DE95004D86ABB1925B24296C39130971B68A2B1228EBA1575447FEFF25F6D887EF14B66FEB4A 377F60681A4B44F63B6A067E367E379628CD7342D80B79913F4797FEA6506A56D47DDD7E0AE0 B06D1E9D52359EC8D1FFF0502D3D7898ED4642974DA2483F6D5F4F48FBA2862B9684DAD5F1FE 7434786F28446523FA121E0445942EA29694E03F2CE367B6EF118288033B36F87CD456F566A4 767D31794A827595EA4E03E805A5D0255463FFA40893B34EE0107FBC6CC1D25215A70FE0F9B5 526E65C3E50376D9555BCC9F60BDD3DDBAFAECEFE4659ABCE230EFCC3BF8BD7F7AC3F5CFEE3E AD7E09C9F2027DD12F7D85837C9A693A330281D730982A1A2B854D5BB19879DC69A0FDD1033A 7A858BF14C949B17D26B491B123F3DC89E67100412DD9DC767EC66FB690EA83850B80DCFAE83 EB437F5A5F4D22517DA8A21075D6A0CB1FCA94446C8138FE3F28B8BDBEEB3DCD67E4D6C9AB24 9F3BCAABF7EFFCF8162C37F3DDB6DBEA59D74D515BF19507880F19F99EC7AF622FD9ACE7BC07 5D853517B494438AD1B7BA2F0C696E77543EA59F951D5B8C2D364DA095F4B174C878FAB8CE90 B0312FC2D3C62B4A9F02166FA0EABC1FDFA7839A250BF3627D3AD5ADD5BDBCF75B271157E012 F723A51A76ECCACCCD693F81590D99FFF80B21C7FEBAAFB921C0A91AE44E8C3A870FDB69B2E7 7A65D13626A3113B069A1382AEA90C6076D4D4B553153B3CE24D1382117307E0D1195E39AB80 58E44DDB927058A8D71AE41B86ADD4692AF0E852F0C1C92A6B5CD4E7C49C7774BCE30E0F5256 4437E6553B1E6486FE7F8DC97451C934C3939EB137A8EC09486F10F2A7FC4BD3ACFF77F03B1D 92F19A015FF6F515E9963C870DB70977F9B697E07CEB75B9AE87B03FD70CE2008B941924DEF6 27DE71F750EF0F378CB2648EA07174E62FCA3FCBD6C6F1F91C9BA4EAB493E28751FBC57D6897 8F553DBD6759FA9CCA70AE9A7372A70CC6CE35137CBE4C289575555D92083E92DAA3845FB214 DAC0FDCB355A5C08A1F3647C85E3B747F1FEA12CF8AA1D2162E03221BDCDFDCAF4B74DC3ECE1 657CD9819BC34ECA91FE1E7987FD75D3E434307B208F2077457E99134E108E38B99B6D1D8DBB 530D3AC7CC5811A7FA92BB080D8E2A3A09CF3F6452941D063D275E2AC849E0B35B39C63551C1 90A43F3C3564AD6F153C44F67E6D50E311ED225861B94CD108D278A4785632CF7E47E89C8FF4 3114044CA9D48BC15C5EB1E9D1DD3965B84A20522340F81FD0EA60D7B763BDE818B5F9522634 7A5220F043B89DBC6A41DF825DDBBBB05736F7709B752B42A1FC78B1DC61EF6DFDE867C1EBBE 0E7F332C0BDCF86B706C2089EFCB1896B62ADBACD8E2358C75060046A54784A41F66B5DDE678 06625477FCA24396747DB263092F82314E7440FEA9CE8630FCC10D7F4BA6821613F64A16D00E 4BD9BCBB0EBF087C2A88720504CAC249D2B2E67A823C4F34260A7672E8D6E7AD168806779B39 ED0847E82037AF28416AD3B5C5C6823ED9D1912A6B45874E5C67B258DACDDF6BACF5D735899E A6C62DE3BCF40145859A58C0D744588D070AB252A26E87FBBF2CE51E95E5AF46AF3EEDEB147F 75EA1F698B2D3F582B76381780E2BA8F6F2AA75A0DF480A0B5BCE7C3EF61755A4D9BFD0E9AC8 5CF716407021CC32CB84C16A90C37E83EB5F0D6B7BEB221FDCE3F9A6701F6BA690748F767AAC D6F886F1B2A54037AE8D8B8546E9DD0ED71C2E03B1148BC4763F95CE2A92F2E29E3820F8BC5E 610200FBCA96221AC7CE0E8DE251618EBA754542FB8EDE1632D48C0D20E882F915BE1F742ECA 7FFEE8F323B05EACF81846F87CF833E6FD877E01172686BF92B875FC6977B3D524E8D8BF0215 C3D72182BF368C7F89506B058A2A6042CF86D8DE16BB8210321B5CB1CF42CC5DD52E29D82D9E 84C957E52BAE129068A6417FAC32427F8C1AF08E2CB44F7CBF3E8B1451DEB7B2CBC772227117 736D41FF4A6772569A4B2C2C48908A1E36FE12D950521F269A0DCC4449DB961E101D3203E88F 7910663B7C672EB85F26562A35A26871947B14D69F7E09153F1CC980F0663644C9EBE030EA87 1399577ECE5CFFD2B7490AC8CBC565359683207E92D072854E094E718CE9D4DF1117A46C223A 5F095DFF3C1721B52502F7366170444898620985ADD2CD198B292433C88ACF33C022AC15E910 E56EB3B821341BF3ADC6FBCF1CB7BA72A2318D1C6D36810768674C325CEC8B2F86E19A0CEB06 64AEC6E1F57BA2952DE44C1DC85FA8AFBA808459222C7608842D4DADE3C8D21210F366BCC222 BA7BA907328AF3304F9AE2A542FE84DCE9B4B3E13C23E687BC3360E578F660F31F948694ECB1 766365C13BEABAC7B589D2ECBA799491735B417532E392D56C9DE2B503C2A49CADA4280C863E D36CDF747D1BADF31AA0F4C6AB910BFB708F2B3D763C041836C9C4792C8CCCF39519F3B80BB2 0C7767314CFE03C5BE8FC81AEDF28ADA7C576135618BCE77ED1ED0ED1F8804D4DAFC126B4E94 83E61917775578AEBC58EE5823CCE006610FF2108E5EC5E9F6EE0B7B09BCD064A2EFCDF71CAB DBA10D0FE3DF95A68F85965CF756B19A9664A167263B2751A9B7CA9CD76905A9A16D070912C5 FD49959C93601DE4998FD65F6B506B9F54A16C92BB88C6CA8751CEFE60731952B2B9550251D0 612901121CCA0D3A8A51D7F1F5D9C771EB86BDCE40ACC8F35831C9E5ED6F5D5332275D01748F 88428E97DDD24A036CF030A8D04E3EEB7E86E6B6E6F01BBA6ECDA8B4806DB2DB9D053CA1299F 5C6D43A64ADE6A7A6F19AC608CEC86FD93407D6BD802EA487D7C46E5190B6B34266184235859 250E09C49583F8B856EC06E4C120A0E12E4E305540AC662E171DFE00F687EECB571D2DE79473 E7D22FE4BDB30B9A526F8D68B4129D71FB1620CB3182FAE6B55625F9C2664AAA3FFBF9B799E2 FC92EE7A19C5E37F0EF4B3A6A902CBED35E34E86D9B7E5E41E5ECAE9876A83B2F2BFB7038EA9 0A232AF9F300BFB6A45F55D73BCC6B9E5852395D5CD5C77819C568741A7FDBA3A2FFC81FB1B1 EA0D4D9B450199617FFA0BA8CE26FEAA16F62CBD663798FBB3CD164D6EE6E4F505067C0EC75C 1C5F81C699DF4165633E0708F8CD2BE2280350C902890FADE818E5B31A6FDB45F7A6F8E5F924 B4D670B9E3D4EFE00D2B04D6F433753454B3D3EFA16276577DE3F28D146907CB6C05570A6D4E DC284093A4B2588162BE6BC867A00CA1A9254234766503FCD3A0E29D9C5676EEABBB3E26FF09 1E21CA21FEB29365A56B6960E1E76796C097D80454261FB63D5F941B66D9DEDFF932793F1569 75004F36E2D91D2203049E5D9DE711D832E78CFA18E2B5348B74AA8605E6425D8099C6B10EF3 E4A299FB76F028BDCAF8ADEA2E908E3535BBA4B42A905F30D13129209DF390139E3C548087BB BB46621E71CDE60F450A8C61B247CEBEF47B5F311B3CDC843790CA79DD6C72AE76A679AF24D3 6D0B1B5388485F880096057CB6287845EE438CE1E6404C5BE7371EB6C060092ACC76AE336835 1D481984240E51E33061F1D9FCE34A4C65C441F5B4E4D0781103AE0B0CF637CA2FF26182B855 B696605FE114AB2F7DE5F016E396B5A4FEC79F05ED451EB3EA7CF718936E0CFD2F9CE7781162 825FD98BE70C3B16123F8D9B0C970DCB545A7CF6A8CA6B4FCAA319C6C4256B10D6D7AAD98931 40122431F2B0068C10D0398F55FB91DAF2C624A716726513EAADC369BB29FBD1B2B7DC5324D4 08B0B02E46ACCA565D1413D1F65F545603B06E28637C326053DDD2B78DA99BF320DA2A565258 CC9F548B2F87511C628610AA00A6C8F5CC5BA2CCB13BB9EC7F123EA7FC49EFBEAF5D7244EACA D013A08D3FE370767128687A488302AD3D95067AF108B76886ED16B59E7345DFD143A24CBD75 E828AE300CA7D24437D4A5F0038DD5265D82CBF39A4F8F542D491486F5BC3566931665909986 41510AC914312D22803F242311DFBA932BBBCA9DF24B56EB52209A5A9CC8AF2688B59F348E7B 8FB08281143B2C849BDA4FBDE9D8819E97589EC110FA9F31FF85D07B6D58D58CE5DAC7F22D0F 97468FC790D913622007DC8045E2D05DCCAF592A540870FB4EBBCE3B5AB9818D49B4E40FC919 FB8FD87617733360FCE02FDBA5E57B33461D5E085569129B5B7B657DB36D29E3F87E17E9C7B3 8F6F1FEFD369D314E329440BD0AC26697B34D4E87048EC54F7C381E66C908A658BA83A811285 E93E32BBC6C641BF0F2412C276B85CB18FED61F22ACA7FFDBD37B994314CE4B711B82402DD26 632B7DC376AFD3C4D66BE5E40E282B74FB120F6E4E144D90404C7A4513F2AB180E00FD410AB9 C10CE9B1C2A8EE695E4CEB0F1472A959E70899B1A07DCCB20546431FE6B541A05291D5DDA490 991BD3560490CAC148A2D623903B630DE49F10DDA865A74AF0866C2FCC595F6FD0A0CDC0A146 5398818C46554C37A4CB1E543C4760E804B39564BB853400D0E1E9DAAC58D0577AE177726D1B 9075BBC70B2AECC2F7F44D34F4C691485BBAE03E43E8BC5535CCDFB1CAD1D66F38A49001C4CE CBD71202FCC47BBD3B224812C677F4F9E4FD523D44EFCFB05A57E45AE2078E3E16DC785125D9 55D3B941F4FD72FF547B069EAB30BFD33E3EFF0686FC7E582CF73EEF9866D6E62C19AA005F73 4CD8FCC0A012F41F38107E135CE4C0AD8A8B81101FE4EF8F32065B2C279A435CF5A032DDCD52 9628509FB6773B475DC13517625705B5D3A9D9EF6995A37DD3F0D6CE5451845CF9151C40F990 60ED58E0F2CF5D6DD71944731CC4ED0FC72641E287E295CBB53AEEFC3FF3EC0A5DBAB8C3AD31 E5F6B339C1748A9E58851F6CDD6BF091227B2835761B7D9A10DF0242A7B61B39AEC0A0697F43 794FBD2A51A66F860FEA136A9D7DD82B42B61710909104E0FABABE3F5485CF1474D494B97508 DFF80A698BFA58ECB590D8C38873724BFBA60FB1150B04282AC1022A1214E9513D27C5D45DFB C47631BB27CFA2806C2CBB130DDA940B65E75F956846F4E6438773C94E8EAED71EBA5E87A886 DA7A846EE29A43CFC2D130A3FEB4762091B6AC357C973487573A230DFF74A29E203BD78B89E1 729B747FF9B58BF1FE5FAE6DD70E9DA091A330078845363681AC2BA501286DDA2038A0FE2235 C10656143783D50129A728B4EC2C64405B7C97AE562AFA240D35FD9E3A6E034683C60F32AC09 968A76C775D5547D85D7A3168D6F19F12FE132DEEF497E90951A56CB17E543A76F8A526B1B7C 481CEEA4F5FFC637DA5CE954A742BF39837F08DFD7156A4F4E4805494C1957B2577ADACC0D3B F9B0EFFA5860F454EC947625E70D7E4E652ACF276F57F2137F451540ADC35D501CFC1F7597A1 502A198EA502D67E7886790A84DD9D225E83D9ECAA18FF9EFFA77AAC3AE57D034E67CBA014C5 FE1E3403AE4277D864856FEFADD2EDDB1161E8595DB1B2CA6CCADC4253B95300ACEFFBF9C3B3 32E1FFD71B91898CD0EF1B9F64C3969FFBA7929BAFBDCCCB943373EFDBA057003069C4ACCBBD 82DF6ED1624FB8D0D4B3E561A05B13550A7EEE9AB35E47E9A96FE49EC2716AA68224E3A65AE1 E96D530FEE45054DDDCF949E7F3977334E3A9AE459085F366393D232B2CAA244B029F2BC602D 05B421E14C08563C4296D3E9AD328DC324EA5685E2FED03DFA3D3AFF2482EBB368484FF8D015 53CB8D5686067F99C5617FA2A7F6F183F4BEA8C1AC39AF726341501AC8875104D11DBF241B9D C9929A8B70ED71BD62AFAB7981E452086163DA2DE543E52D57AFD080AFE373E8E321670F8A47 4E9DFF36441F6C1A4D2AC6DA6E5C9FFC0C4EC9CDD8614C2D65D55019378D678CF46F483FA9EA 0152D9D3A12175774B56B11BE03362D2A36BA13945979C64163A696B0A6CC760BB6111EC47D0 A5260DFA7FD147FF35AB84DA889DCF4BA4146647D5BF8773096FAD1EC8001A6085C4F4721428 F4D4B85F1C03C71576F497D3A5A99392C647DD42F8804DA5D33CCDCE19DF1A16C143C449F1F9 37F6F75B05ABD0CE90E4EF696E1BCEFCD950634E414DC724B0084BCB515CD4ACD71A6CD3784A 402C3CF3ADAAFFB763C5F7E17BBBE19172E4455923BA48869B4D9D0C1EAA623D9C728D887C15 BB8377AC74239EFEF6389EA10C7C8820AAF857BF8EF2B64EAACF096B742ADB9B666D96715364 CF18D88AD8DA6A0CD303557F04908CD28D11ACB9A730AA3A37B6028914674816E6AC076C4559 A84880E82D433A5F5722531B0287F11B24AB4CECC2264BAB4E6601C990E32E1C5F9AEA52CA22 2D2698507A4B235531C3FB7E9FDF6FDA186888A74B902A0EF3457537233376E8667035C092CC C3797AD2FDFE1CC8BD71C49B91E4520091922CE87856F1DC60A209A9BC9D97B0141D8820E1F3 B86BFF25CD1BA07E5664D32C09CDAF569EC7815F41E0E8731E2FCE769BAFB3A751B3EB7082C4 992A4FD8BA363D0888FF39FF986B80D5568CDFE1DEEFF98CC54F05B842694BE023E0E0507DE4 7AC1B53BE427D31E0DC9CD5963BC3A5183C54D8C9046068BD6F300F4C0CDB8CB779E6828271D BB9EE44B70BDD1C1B5A345AF01E5E9A74260781AA473199CEFB232EE9C60D14DA8C5D3D22291 A33E592BB7FBE5E9B28F18EF70DD0877DBEB43EBCD12F9AC95B7D46A2E0DC88E3B7D34C6FB32 1593E7FD7C070D44037B2EB5C5E7F40C2BFA3A282D85932C19D3C3D07F5BD37C5CAB34816E9B 008BB5988A1703DD971AC36A0F1C61DE0828A6108A1454A17E63F68FC5604101184FAF38061C 515C0439010551A933CE9701EA75A59D88310C564CA3C4D9BAB34668C6ADA1792C550D08B029 5E6A2AC490B06A3BA9118ACA61A951BDC06EB5EA612992BAD973AD703F5B25D1007F47CD92E7 4D824140CE1A827616DF813898FBFE32C87E692FD324FE78FE9101B1789C8C094207BF77C290 16ECC3734E103ADE9FC7717ED2E6979BE347F72A514B943A7F1101ED25B0AFDCD6C8374182ED E624911F458A5EA76FA982C3CEDA0195275DD50BE2AB3FA62F5545F802CE3784159E281A810B 87DACB95D4D75AE2EED997DAD39BA7346083A046660F0D63D4416EC1AFBCDBFE18966B4C4C10 9D5C9E9DD7B1202D6AA73AFAFBC169E752DB200656FA28A29A9AEBFA1D4EAED03478778AFE82 E0AA2DB79ED37AF8C5B940ECC6A5FBF38762505235415B285C72DA21F4FF986376E407C04843 24B3A2ACFC6D796FF53B5412A1A73DBDAD921F402308041C18C5D7FD9705959A8C0F5EEA851B 5AB726748A6F0BAE196F879A3A1A5A87F7FC723B7A6E85189914EA451E2BE92B908AFCD4BE5D 3D2C6C1C40984D10483A9F85648CA31977A4CD0F9781CEA0EBFB97B8B07DA6FE5694C32F0B5D 23D58CB259E54C46DDABEAEC138EC1C5922337B8CB2741341E3DE7D141E7316B2F0DC75C1A62 ECD7106141548C31F7B90C0F70106E4E788FCE549DACF492225530F427A6BDFF5ACBAE8913C0 BBD9E3DEA41EE41FC7C13796A4A7D32AA56305F2420AA9BA5C0A0425861F97FC2B0D586678B9 5F28A395FC340E5CB4D0DE633E406347BB83E56126872B389CBD57C359807E3AE6CE23C5F1EF 746BE92625E161BAC1584CB79940DB009844EA870326A7BB6CC8FE67084726E36EACCDD1A5E1 87D49E1CAD01037E58EEA820171B29968A2E4A08352959052EF9CA920E736C7337D85A44A3DB 0DA96FB9BFC14177AFE17AAA27B79E1C92B4D53F4CB9C277BAB838C640EFAF3EF4D95CF7BC61 4F3EECEED6A657E1FB361302500E5DEA28E5B5EE4F3886C23F670090FCA5D2EBA7A5E4B3ED0F AEEA8A7E6DC041F9988D43F645BB388FBE848EE495B391FBA4C0C3939F3B5B3203A5527F397E D758BEE1E0F0FFE9A379DE0FD8CA3DB83B767C3BAA6214BE3FB012708F1327E1C96B8FE26597 A0B8403DE77750565067F42F1587B5EEB69D5024A807E98A3BEAF5FE5F88DECEF57F2FAD58E5 20D282ADEBD2051F086B3B871F0839C71379E6A0F800C7022978C84EF6363B7A79B10386E38E 8C7DDF0606ED85B780145FA4428DA212AE5386205BA129AD33D28BCC36A0B6CDEE13C37A6C2B 7456F0C3402FD5B3E3DCE43B479EF0F81DC571FD102BE21029C721E4148729755F19CFF14B1E 0E30CEFCC09D175AF0811BE99498F4A8632B85879AF0E005495FEF5548F2A1F8C989140726D5 4BA1FB448E54549A2434A1FBD152E7DF166EA70953C6595CF824CC77984DCB8F8807B7347131 CB727A589B651697C32E0D52BFC2B36B4C050CF9A1CE072746992EA2ED9B052DE1B2B9A21A89 682B2BE4A1328C769DBC40BD71202D0287D1F8B909AD0E95E5D80BF8314B457A042F304CA330 14D4578D50158EECDE6821D1B672B1973393FCFCD432EEB0EB4FB362DCD9B4B280EB5EE2091F A3853D779EDAC21A120FA7E03B339CED20115F404C3A086EED187281EC31F25A664811E2B712 351528C4F0ABCE55D29BDBC1E067C01CB44F8A3E094F104097C5A36DCD1CC621E32747176643 18D99F5F5D1EA11959CC751FF9F3739F735A12612629BD3346A840DADF0A61567D880597EDC2 2C70DD8EE5DA9171AE46A8D1D78A64DD2E0F01042CA59FF7F83EC74E1CC0E786DC17A112A062 7640B89D5F3EA4A57DAA15E9965A81021CF737E0108267C404ABED66D9CFFA22E05C351194A4 1913A0D12931F26477A06773829D8AEFB25184755DA27F5DF42B23F493D024CF38C544257830 1EE65AE593127DE8B9E0F19287015892DD881BBF034DF3C789470B567B7AE5130E821870E504 F893CF1844FE400752C5CA00371433A36DE4C96938F6B7FC81D26DEDCBB7AD4F2519857A81D4 F06F6A23A74825477C912968FC03B13DE8517BE24831C0E223A601AD7834A3CE0C7059822D1B 663094AA1D7DE8C524D1E0E5558C664655454A3AA0A5034B50429C5A2AF0C3C862C6D63C415D 92B2B720CEFCEA0D0C6CDEB5CD89EB701CB49CD568E39059E7B7DA7A85B44213F1060598CAA5 8D8830DF46C628B18F908DE0C7360B9175F698FF66C5E4EECBCC0010F43C251001F06C45AAA3 174C8841237E204AD5D7E1C403DFC40F9FD5F469C65625EBA0BC5DF2344228399846C285D9A9 6E21EEBCD9EA38F25584C5D4B7893E64AF5261656E3FFA0CB1FC10CB512328E87AE3C83CA38E 9CCF96AED112B93EF8E4D5CE7BF47E8A800E00C4A0AB624DC3C03089BD5C415E8BA33DB289F0 8E151E5E45865E9CE2EE9E160CF3646726DD25D5EABC96B72A7D2C89178FB92F0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMTT10 %!PS-AdobeFont-1.1: CMTT10 1.00B %%CreationDate: 1992 Apr 26 10:42:42 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.00B) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMTT10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch true def end readonly def /FontName /CMTT10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 161 /Gamma put dup 162 /Delta put dup 163 /Theta put dup 164 /Lambda put dup 165 /Xi put dup 166 /Pi put dup 167 /Sigma put dup 168 /Upsilon put dup 169 /Phi put dup 170 /Psi put dup 173 /Omega put dup 174 /arrowup put dup 175 /arrowdown put dup 176 /quotesingle put dup 177 /exclamdown put dup 178 /questiondown put dup 179 /dotlessi put dup 180 /dotlessj put dup 181 /grave put dup 182 /acute put dup 183 /caron put dup 184 /breve put dup 185 /macron put dup 186 /ring put dup 187 /cedilla put dup 188 /germandbls put dup 189 /ae put dup 190 /oe put dup 191 /oslash put dup 192 /AE put dup 193 /OE put dup 194 /Oslash put dup 195 /visiblespace put dup 196 /dieresis put dup 0 /Gamma put dup 1 /Delta put dup 2 /Theta put dup 3 /Lambda put dup 4 /Xi put dup 5 /Pi put dup 6 /Sigma put dup 7 /Upsilon put dup 8 /Phi put dup 9 /Psi put dup 10 /Omega put dup 11 /arrowup put dup 12 /arrowdown put dup 13 /quotesingle put dup 14 /exclamdown put dup 15 /questiondown put dup 16 /dotlessi put dup 17 /dotlessj put dup 18 /grave put dup 19 /acute put dup 20 /caron put dup 21 /breve put dup 22 /macron put dup 23 /ring put dup 24 /cedilla put dup 25 /germandbls put dup 26 /ae put dup 27 /oe put dup 28 /oslash put dup 29 /AE put dup 30 /OE put dup 31 /Oslash put dup 32 /visiblespace put dup 33 /exclam put dup 34 /quotedbl put dup 35 /numbersign put dup 36 /dollar put dup 37 /percent put dup 38 /ampersand put dup 39 /quoteright put dup 40 /parenleft put dup 41 /parenright put dup 42 /asterisk put dup 43 /plus put dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 47 /slash put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 59 /semicolon put dup 60 /less put dup 61 /equal put dup 62 /greater put dup 63 /question put dup 64 /at put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /bracketleft put dup 92 /backslash put dup 93 /bracketright put dup 94 /asciicircum put dup 95 /underscore put dup 96 /quoteleft put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /braceleft put dup 124 /bar put dup 125 /braceright put dup 126 /asciitilde put dup 127 /dieresis put dup 128 /visiblespace put dup 160 /space put readonly def /FontBBox{-4 -235 731 800}readonly def /UniqueID 5000832 def currentdict end currentfile eexec 8053514D28EC28DA1630165FAB262882D3FCA78881823C5537FE6C3DDA8EE5B897E17CB027F5 C73FDBB56B0A7C25FC3512B55FE8F3ACFBFFCC7F4A382D8299CC8FD37D3CEA49DABDCA92847A F0560B404EF71134B0F3D99934FC9D0B4E602011B9CFB856C23F958F3C5A2FBE0EF8587D1F57 74879C324E51FCB22888B74F241550D7401EB990D4F3A7AF635198422283CAC1B6CD446DDBCB D915DB9BFF88844E784C6BF7389803D9450B0C21756A017306462C563D51ECEFAACD079732F1 2C29315E4B9623A5752C6F1D8145869E120D910B2644887CEA7E30B15676A92537C29D3AA80D C30082ABA94B40990B82FB1A877E805E0C8C48F61E9F2EDAC05B944EE4D8084EC1D5CC517AAE EC5B3EA379DD011EEB454CECAB3AD2443C887C58278972355673E503AFFE0394FC7DB31DE364 E4F56C24033C7DF2265C56445EC63A1D5695A6041EA1B94407E1CDB7C5635603A4FD047E6EDC AEB2D0DA6C9E0E9396D51A4A58E8FDC1578730F992435560A6E2D3E3687703EE2F78F5896389 AC8470BC806169EB01762E89B6DC9ADF857EAD656620E2589AAE722C37A2ED7A2941C360B067 EE34D8D5CA3BF68DB725614D936BCB207781F4D4EC2AC67B13A5AD161F3F059ADD7B5E3D9048 31E31C20C04546FAE83CA93A35989E65C201756888F727B97E5313C9870EC96E4CEC3901EA03 A5C744754485E7D169BBC98BF872D0796E189D43B712950C3786257D8BE06AB6080B9D939231 3298327549A8A41C00A2CEA3690B4A333E45AA815A64FACAE1C2B44640860B8B8687AFBEFDBD 5B4A541A72514EE7D3E0752AF3E96A88C95D31FA16D34BA2F02FDB0088B165844F02611C734A DBCC2037BF741FDEA7E8BCDC130C70C33772F777D8BCDDF4611DB99001CCFF14D7AF2BB05DEF C3480BDAB312A0EFF2F375AFB4E0DF2F803C594B7C93F71CA4AF861AE1711932FEF19BFE2F9B 7ADB69D68E5A70EA4D1A3D5BD85231B16993F65EFB37A0A823F0542F8C2340A073DC1BE4A834 7F9D3068A6435CD8278B0DB1809E8AF9664C2C989B9F16873C009449B6284B85DA4DEE11C96A 05BA83292F0EDBD92CF674AAD6AC1A5FF966FFC37E88A66048DEED053565B55EF6BDB8C2F2F6 7832F8939A32442EA54F13D003494D6350A2864B427A9126A9C26A031909FE53FA8463B80C3F FD536C9A5DD29CEB03148DBC24C0033AEE72DDD159F2E8A6FC113F428070EB36CE5A38A72ED5 BD94D81AB4DAF08EBD42C8E5BC695622E02AECD4004E6D4CFE72534CA56291FF5F2F83361BCD B9489A993F663289B6DD492499DD5713227210F89370928ADA0085E2AF277F53E4CEC34D6C4B 8CD5F2E016052A04C20AAECE8B81AF9E9F33643C0FA69A5BA864D2A173221071A965F9970D72 93DCDE8C3FF60A86A4D3706850CBC45440DCD22F307261E2F6FAA3EE156A58069DF979C9B5EA A326C5A36B6E0FC0333D7B4046D636461CA2EF70648C37A953F96FAED6266EC9022753EBC390 BE93C0CCB7C318C4314D9F6E54274C8046A8C5CC7EEBE625BF59A03F5405733ED120841560CB 93210EA1EAAF3402ADCF1FAB986521BDB7CBA72A2353942FBEA4A0D1B67ECDE589A65AF8E7A5 FA4B87672AD55F57D783C66DE1D11E0A16BCF32530692380C730D12834777AC6750F85131D77 B0F53B626635CAD3BB8E9F0454FA085CBCCB0339034F5FB2E225E62CE12E8C792F5B7E234688 D2AA8F627A4670339E646399F91E94424263E5C12F9F3D411FA44449611EA9785A20FBA733FF 2A7892D1641F836CD42C58CCB81E41D6E2A5AE30FA18DE9846AD981923604C799B16A99779FC CBA11044740BBCC78116E857B4B390DE0E66921376101D621E1FA003F01AE344FEA0215F2577 E9C92C6AD07F2F4674A00FE42AC51FE5A9186C3C1956B535FF1DD64BA514534DDD73C0C61C54 FBD6FAC3B4FD9010FC55DF2A37A111BD1402D4E90FD8B3601DD3E9FE25634D709C289E524A66 DFC33CDA640D397269BD9ECB9D0EE84A7D7B93A97DC522A16B6965B7D5D7790A3002341ECB3E 80985371A5169B38133B13FC5C1DEBE2D90C43BA5D2CEC7D3B972D32AA1A932B750D6CC83439 73FBB9972D84670AC5CAC5D0B5E75CE021F99493CE29AE90BCA0CB75058BB0A47DFAE6C8D075 043BFD738991C2A0B80BE18386D7A6FAF89FEBC4AD142A1B0EEA8884EBFA87817E22C222170C B6D04BC6DDB541284E16400028EEA275244B69B033D200AD997BE7D1DEBE13CF783BE1137278 24006CE4B5E3F34D09FAB236749D3E72C033997A652982829376DF91ABF533F0100BF224C279 D3515176DFD56C325B3D7A3EFE0BEFF84233B5A7EE262557F84D754F03817C900945DBD5DC59 B46BE8847D1FBEDD70799DC42D0148841DE2F816F894ADD5EB2C0E1BF19F52558AF84DE5B693 86020DF814DE7647FD41127459D65798B06EC5D132AC0F181BE211624E97F8096C0A22E6B216 0878909D00A918E90B435C8C87D1033E40B56B4F15752D5A8AC019837604DB9E1AF709A2EA36 4F174DC2EB1957F0E5F477CE06A0EB78026BD1B23D76102C6862156C47040EC259FF4E89F83A 42D8DFE53F96127C8AB4037EFEF724ED011928C2CEECB4A8A4B5A480595A2AAF93228EE37205 2428BCCCB4685246BF3E9FFDB2845CA05DFD4902E74483626C2FEBB4E76C78B2AD6A96372D0E AE47FDF4B8D1F068FF0D1EED01C6860C86275A2EE3C2A97AA6033AAAC489E1A540432BF92A75 7205428AEE30CCD48DC234C521003D7EF7B88BDA8E72A12AD36C2BEAB1177CA82BB2458997A4 B5094A9DABAAE0A83D7ACF4F7727223303D5D8ACB9B265B3326CFB1AAC4BDB80B28E828DA936 BCA574722A73B05D447C9F7E506D78B33F582B3BBEA37BF8380CDD32B15E74ACFEA5BD635C2D FC3A6090E7D96DB7E9127A3660024258A3A7DA06D08C4691B19F88D0BC719B1414E953B26F09 6A0379BD71ADCE16DA6EB552A50EC318456CFDE8FBED1DD92200A9EBE83849AE3FDE58B5400E 0C173E01F5E23E883119421C7BF5F12ACAE87B3C3DF0D824A67A320273D41607306B14A63D46 2C042A6C6A31B92D54E01D7AFEE232DDAC002D012B950A71C2F065BD478196779544093A5B61 93247AAD7970AB5E306EDBDC24EB4C6B71A174ADC6565A99EBD7EC83E01ECEA533D364C2F07D 8A48C84C0A3941DD6B75422FCB49AE7BB79245CFE9ADC2C9B3E6B48A46867CC72F26D8C82C2B F5E8F60763CB9B473473F521FB016CD1D07B3216C496CDC68F72C6E9AC5B8193CB3E20EA84C5 A7CAE4905261B554D6BA006C787658463215646AE218972219EB34A5964F0A277A1D1A20CBBC 94FBE359573A672EFD0019B2C0A6A02F4B15D14B961383630F0CC578168F9DF7D33D3509CE75 D272141AC8EAD6C708227A193A5542A213E6435AB543754A75D066C000A1FA060053A862A013 799F762B5403BEF0E52C8208D3E690393BD3FF71C8EAA08C49C77F33BFD9A6F9370A88CDC3E5 B1012FB13C784E637A4891503B5FFB4A0BEB105458413D3FC880B92671E786BFD03F158429E1 E80EE252159C6B61079092C2035748A3C0D1B7C400B88666F94601D53C2EB3308AA791F66E40 DB8CD2CD53ABE4A018A2BEFF566806C6CA7108EFE8C70C7E4058853019425AA8EE77D3E75973 1A80FFFB59CDECD15D099E336A63A605DCCCAAD3FC55300B12402FB10A9FA4292D61F8967C21 8E008343617BE44D29AA7DD755609EBEEF555F8291543623BE6CDAD4F46CA20063DDE0EC4F24 B9052D6092BA0FB03EC7277643F178CFDD5314F597B93139183823C2049FA4FE0E1F7913348E B83F151E13251C3C2ED100CB9C907969669D98C5F349FD064A677FB689671C27B658C3118B20 6AFA9478A4F0AC3E6325139045C83C046D0F81BB002757DE25E9778A4D835E6D61E563293923 CCF415FF132B34BA9ADC441B806151561C59662867F91CDDA7579CB77326D5C34BE9149E9629 8787F98EAE3B5A2E2190D932581F36C547680C3266770786DF978FDFBF96D7DAD68969EFC46F 5A39567D97CCF08BD361FE650629A6CEC31DDF856640E6A2842447A87264503B7917AF46D7D5 14BDCC09B23E7DA51C47816EF27100FA60AE3FBDC320B6E792AF15CCE9412C8C80B3A46F5E31 E380D93EE3D17A5F674684AE28C56381892B66AA5A37B67B6E7CB9D65D359791E8EE0A36A4B6 537315C99505BF6264B6C3BDB62A368AA4C5784409166831B36AC6241C24C9EBEE261196E7C5 B55480CDFADA76C0F979FBFC9F3AB5A53CAC4C6DE0BC8CC9BC93221347EC17FC024CEF796410 67DE49A3460AE6C83464CE27DB329E16605DC22D727F578F14764720F4D6BDC24E171B27EAF1 43EB293A70525452FEE8100DBB2D7ABCC5177C7BA96CD07A8667103312BC495FD7813A5DC7BD 37C1C96B1DDD53841B9DE37C5BE008AD67706045EC1AB4F418F60A17C0786136A5B9617CAEA4 BF319CA20636691BCA83918785CC15FA19B4E8CB5AFFA398DCB868AE139124E6DF8BC1CA29C4 3E4F7D57AD6D625D570B498FD8D2B3FB7080E312D95DBED16A8FD3ADCFAC9FC0EDA131913647 6EA4C0FA1B6EEAC95FFC35326124EB2DDA055EC0FF6A304EF0CBFB3DEA094810A52D5193F041 D99872CC6A71DFE5B46ED2EFC3F45D6560276FDBA056A78F9D76EDA2467AD4C44930558DB88E ED42F6C88B0C1E3DD5101A6590ECBF56E32BE0BF76B515235D00121CF0ADC12346997AB62DC2 A1FC37DA89CC3992BC1C6D5380D0D5AB94551833B65A2336EBC9923E58CB1E47444BC6E49BE3 042C94624373B1C34F593E7C8E043A6DE75A27DE4E305272EC9996499517F1577DEE3F9ADC0E 3C21B61F81D165E903E1457BF33830E5369CFED65ABC46089647B5C01CD089DDCC7CB8CBBE01 EDD7BF01C3636CE3D274A7C59B937E4547BE0DDB0FE9616E0EBC5078ADF5D7C8984C5DC85FF5 099A00B84E44178D78B293288F664F19C7FFB7C52C04ADCF8718DBC94021C28290E2E5808687 5C2B23EDF938C52CF0274F8150CB577FA02A7BDDD290839B69F6D5AF1B70896ECBC07CA8F1F8 6EA38CFC5F852A5F5249BCF04A878BB56EAB61A1F53B60697DB77FEE8327166B399D413C62B7 42870C3D77544FBF9B63511669E778C3CB1C009D17EAA536B93EEB5D15DF014673A66B43A102 02C424DB51D501610A59B01D5ADDB4A62B7E86688D86A3786B08F14D5BBB93C63C88D7F70D57 4AD84DE70430799DB3C19FC1EBC35D44C8661ECC763B46445AED62F1BB25A6C7D1A7E8C685DD 1ECC9660FE97CE2CDF6D259CF0869BB93F00D98D4BF87969636FB6DDAA09FD32F6F31DA2F1B2 47ADFE919932298D32C8C96FE9DCE6F4A75F071EEA657935F7F30C32353DC4B25819F7070F6B 518C909BE0CEE0FB262EAC59C893DCA6C2B69CB0147206BDD4ECA2C4C8A232FE1B1DDB9C9B7E EE10FD8A0259364B697AB94D2481FF1751FA9782EB84DD7B481D0FE16D09AA95C00861F081C4 04B638F1086D8C108953B5828960BE46BAC02B635F7E4290EDECDE73860DDB2E987467C70E20 D93CAD40AE9BE998D64B3BD4D600EA6C8E2F5155A9264F9D090567FB7ABE1B4E2E1EC5D4E298 66D289B5647146B7989DBAFEFB7AC0DBEC9DE8D12749113212DA3C5E9CF4224825F9AAA5ABC1 662AE3B3FABD40D17408BBCB0FFAA37EA2C05569ADAE243114BE87B6421590A440036A071E70 B77968A4A6C6AA4FB68D32417DA597F5396A4ACDB74BDB1FDEA82BAD3B998B8399029F0726C8 F83C65AD45D14A1AEBC019F885BA60B0B6A260899BECA00C0F01E1AC25490DD78CF40924901F E877E66F23C977B8754623D1D0F7ABD00753C3A0D124FC297D647F78380C139C2F82EFA9C9D6 7600079805EA3BBB31C79716E3A4DACB2BB00A21F34220BE2A202FE29265024AAE48C23B0FCF 6142EC6587DA235577B6E57345FCDF32B83F6532023F8A3DDF97B01FBFC8B853E90536165AC9 29DF10E253D8C4569616F297F7E09C06489E67618FD7148E6A89E249C62898E64A03D958EB88 F6E3361F0EF2148BE4576E4D97D320B4CB7F412FEDBAABBFAE057AC533AF9CF9627BBFAED3A6 C6CA676148B005038149259589FE227CBB4B8576810EFACA8EBFB5B52ACD96B373462336D791 9FE2D926C0B23BAFA3024F15EA433414CEA280F1E20650F1EFDD04959A61A5C362C98B855361 F2971287F63D512AF98695C02A5473AC45088D478509C2BA84967AEC0FC1D538654523791773 D8A5B9D73C2EB52FEE2586333FBF6241A829811E06C2CE93EE1F0FA3CE620AD06984347CB30C 2AEC9CDB0F97CE991ADD184ABA3783B556662C833A874E5C38A64B6438CE5348ED802000631D B9B3B33F0D90941BA80E92D4F00C64E62A7A0520D94E76F782CC734DE498ECFF23A5F24BCAA9 7150F721064114CCA8CD690993A1274A5BD3F15A6D6EE5C237D7823E18661667B593FEFA30EC 07E974AC8C6629A8DCC41F3F02D14F620BD415841709E7296D2E606D040D29D501927F9CEE38 A4FEEC83A2FF45814700D41437C65AE671A5A6E83964EE131D909E56926D3BE03871341FF7FB BD19437C7A0C3FFE3D6B50479B56D774F8D2EFB59006AF71B47C7BED0DBFA8E8D95CEB3E5B1C 65111377CB66E0817B2AF45607708868976661C469D4C1A3719B90B43FAC9BD8F0FA5558DA8A 158B31D4866017BD8E144C630CB3FB547A0C6035D3D4565536D88D219D98FE96580B651FE0B6 4FF75E13BFB841137459E93A0779616B9F67865F5F72503E60EA30AC387ECB6BBB2039582DBD 891BB344D685BD7B4A44C73B3ACAF4BFD4170B2A529E8181763CF0990EEC3310B321F4D6D5F8 84824ACD20B409B7DAA1186B998DE184C41A1C815F09C5902EFA03BCD1AC9DB7B844353B399C 184088DA2DE7A98D789F1F7B56FD8375ECF32AC7AE6B9645C3EBD42D333061835230C4068720 4AB8AF146DB9E945A631AFA80CD3237A27C6ADA5DF3F1E65DD74289E58048A40AB6374A4F479 13A872042CCA0CF0BC34A30ABB0AB215BB09AA2FEF09CD664AC1F76736CB236AACB271B9783E 1A94EF666A52B5A56A0BC90DB43762B33CECA87E1C8BC43B6B1FC6F0D8D8829A1DDC6A87A8EC 8287A7D9FA52C848A76BF04EB015DC3C79DE6AACDF7316415280AFF2DFD989F8C7887253E6AD B49D6C78C8350F6764BA14AD14ADE05C76D9BC480B394753468AE029865248C2C760E3BBF647 178F10A294506950073262EAFF3E956E7484636D18F2F4B4AC01F7F3DBA5C647209C29CC0ECB 195764FE2AF2DB0C9086B587EC51A76AF1590D67102AD6BCEBF7B6D845FAE94D6BDF6BD0E910 14DD679F56DA651F747FD08494A136E401A8E23772D3EC931A7524673346AC575756E278AB36 4A1055CC920294D276373C881D8AB49CEC190A4DC921BBEB75A413CBCC503F96B862F1F446F2 CE232E45652292A02349D7856904B46F9606D6AC8446F91B03118E28ECB7DB4BFAA9D79A12ED 57B1F9086541F1D2AD9C55834A5061B1434BDA4F001BB74A3EBC61CE7D8353B6C57A7DAD0FD2 403CB55B1111DB56CA38D2F5BDF3FCB687B08BA9CA70380EF03E837B95CA0C7812EB9D7D0B51 00E052493BCFCC91B26D64B3B95BEA68F7AB187F5BC4B15CD5B2182103FF8C21D7B23FE7E302 69E19619103362EF40128B0E1A0285299853239D28EA3EAE1F32ADCC813FA4C2D2FE80D3124F 4BB2BC57F386DE387454AADAFF1CE4FE5769DB0B7A53B49DAF9E6B501834A117988081D2AF14 56160BDF52CE6E1EEB12FD7B4C8B4C8C71D766C71A99F768B16EF1574583006FBA51963655ED C565B7306093E356B223DBE43B25162600F4E0254F9D8BF36306ABAE55C77640A63F4F7EB19F 091F533DAEF035E5F7BFEEB59AF6A3DC336D953CDC9B527B1E6CB4E75BC0D6704AB8AFF7C511 35EE9EC739B4DB64B145E42D7CE5C33FA78310654E0E02359BD52B49074CDE8768741ACB2922 4EB52BABE235547A693E94D591673F5070045973D20AA8B76A525F6F3BC6E456A1BB17DB2556 04A60A8344A7CF57411CB1626CEB4E02375AD6F549E6B21AF25C18418908ED928057525C9C84 71F15F7EB1A471F57C314ED9EC16CA55B2D2492EF44BD9104AF9C7283FD1B192457AC32F8760 32F204BA71A9010FF71FA0A74E6649BC382F883FA09EC0C46410E3AA49A39CD0A56F30A74233 844F786EB37AE9E0FF1891EA5A7BA07A826D3A543462B30F5DDB9398B3618D06AEFC7221C8C5 D1313BDD8179E2C38571CE735ED88592E1464E0A27876F40C2AC6CDC00D6B6BB2093AB39C825 57D0DF90654D57EB09E4978BD9F5AEF16B76F80154EDC4CB61A17E2DEA5EAB9032101B259058 4600FE5F74E288B16B41B18D42410D91E391F31FBD5B9DBC1A42BBF529F33EDA35757560AC9A 13336809D78CA855015D9B3254F54FA9047CCAC1A1DECD2359FD6C5388A54F21C009402E5E6C 5B2E4A504FCFD286EB6448E94012BF6AEA62AB724D774589B1818D2372E76200C1E13194A2B3 4C2445AF8E6A63E7E270F54694CD71967FECB36CB10F9B7C7EB9C53B98128FA6A2D8171FB911 20FA46D522C6682030000BB239F8BF8D1D9A923AF7104DE7DE2125425951040FB14466EC2B77 E04DADC9CFA4E13C52CF0E75237E3CA0500857930D1B5BFF827AAAB103F5E220D1FA7FC206F3 6967E00346C436BF3D15B0DDED15E17A33EF57991C0727C12863177BE68654EB63B242CE4D8A B2992DDB37130156C9D380F721C6B954ED6062033A11291332F32763B7DE9A35CFD34DFE9D76 8C5187FAB040057769D2E52AFB30F7D5372165827680E85C3BC7645AF4441B11712C9DD1935D 32C58B92709B7ECAFB1F9008582C8E0FD93FDF6BA3F93E38666F37C79DA45E8A7F0017F3A887 A4F54923C9C107801AC9736E344693D57BA6648B44B9F6ACF6A9D940CA7960F35E0734213EBC 6745E5AB6424B0F1FADAEB69C35319266314003C80EF00DD1C373DB42EBCF5ABE5D16142B44D BAD5C8E9E291C912F828D2BAF4965CBE826AC4D2081C8C382752C3EE0BCFD391A46B2A304187 3BD2B28D7038EADFC4B031D06E4150801DDAC8B18264BE969DFA3C80C4FF17D29BAF3AF53F93 6DD506C33704055B0AC76E436F2D54F4AA3CBD545FF1B67CD57325D48F28F3F7FC171548C106 8AF2AF4414B92A014FAC72BB51A0279CB33B881DD767DFEAB867D0069273EE9DE19FF1D63A59 AE534DA02495E0E4E5AA0B52F923228AC819E084F4E94CA631BD44B01B3025D8CAAB06F57D23 1652FEFE73803221E39F284150DC944B0D2CD9A1F208AB552CA3C6A23D5ED3E0A350FBC963A3 16B37D2CDB610A9FCC069B7669E2CB7505DE6D003D7F4F695DB88BC696AB9F87CCCB1EB635BB CB1978F46F4D1EE5A5ACB380BB435E424A7FE8A20F6F3F1E8745781601D76567AD9C1076FA1A 1EFBDFF6F9969DF3C0F337B805B1AE318124274C0D7E0EC6F43299EE7DC48AFE50D428430524 73CCA6ECA462CE40CBD2ADDCE28D3676DD125D404EB2C2706170EB35DA0FF60C1A8A9E36A659 00C02D19219C6AF5BC3DBE759153B27658663F7C6ABA6327031A37F58F948FA4F636FA989C95 3FA91EE86B93617C3369C51841B3FC5A533FB1754ACFB5BC80E97B002B34388D365CE95067B7 F31DF8D6BB61DB83C0FC5C3FB54350C9B3A2F69153620AA7D2639116DB4A06166BB58FA0B9EC 87726935BC6324D503017B679F52840957DE5C018C4F02F86D2F555CBE67568AC075877B1B96 A759556EF292881CC358114E60A1B72F589F749E64BE973B6BF41692AA93F7604AD7D8376A94 37A13EBE498DEE73F6E22BACC58108C83791C496773240B7BCFE6702FEDB9C4A3BEC1CE45396 C5E88A770A61BCFE8755519D7E4007CFEE9919D528C651E40E05D7D03B28839255B7182CFAAF FEEAB7B7BD2DF6C56F52F7201351BA2B7705054B418E691276A78984A2EA2E7D991721C368BA 22A7C8B738F1A9266064FF5DC036A20C8570A2CC0BBF74B25D7A691A20A1C1A5FB1400C66AEB CD3013C43D1328F5F5D0635631A3A21AC4884F0306623EE1C2EAE491DCB845E34D749A6CE4CC 80B2E2049C0907249284BBBDBDE08588D5D1FE1031B2A2FF3756E7E2F670FF768F638D83216A 2270902867F072D9E4E6735CEDE427730B942FA67D89494D959D0FCCB923A85C07EA3272FE4D 018F1EB2A34FA95FDB6D31650AC2D6355EC338D36DE42547A6432CB847D27C74834036DB59A9 344F59C9F610091E2D5FA6157C8BA4232937DB379D43F922E2A7581819A4598B436C60510B95 6450A6DD2AC04FEC337B443463B4336008DB2289A8F9B126F0A998431D8E503B1781F42443E4 0BE700D6C47D1D65EDC74E665C0EA196767E46BB11BC0ED69199F32DA3F4398342DD22EFC529 6CB169043C3C902DF485A8B50A94C307FC14A6274570F878C6CBF18AF910EC20B0726684ED02 1F862FD1F9273F32826D6D9569BFCD3DAC8B6D9BEC14562E22031BD61B4CFDA7B2C95F25E78F 045E616A6090417F1DFC14A7A168B1B121C229598FDB040B336E1959BE810C03401D601A63E2 7F8D501F830A591884EDCFED1C2A44409DAB3CFCEF74FA27D44734D071E33EC9C23A525E4612 32135D02388D032BB8B9B8C1C8F46EDB55C98EAE149619244642D2926D3180BB66CB7D0C0146 561E452B59FC7437D42B5F3424D5F30509EF1914E75D4B73E483701026F269169934EA1AD0EE 3D1DBD25DE247F866E6FF52999DEFE6F5D5DDE98E974FF9DB4D9B99688652D209EC49AA0E0EC F73574CCC419039056CDD2D2EB3290D0784E295400ABE8331D978DE83A2B4001D35F51E39034 E0BF49945B9B7C4EA6CA382684B996F12EC9438567A20C6C7713D4A6CCB3389B2934E45A1796 42CC9E65199AD61C07769C3030D87E9F23E85469C583DB065691EE228FC2AF56632E9EF15646 67ABFDD20776425AE23D22C16C3C005518590DED8A5DB841CE25BFB4C1BEDA4FA6575726517A 269274B1517662BDFEEC6018FF525B4604446520067198FFE83C950F3D2880B5C9FB91DAA169 91BFE63CFB48A3EBF24B7A33F43E1C7827D81CA611DF3476CACCE15A7978271C3DE2B48E1929 B4233CE6A62F54BAC964C9ACBD1DC4B64C5CFAD4682FFC880B8B6E14DBA2234D6CE8F0494E02 9A2123FE0D63B39DF8DC30F65969B8A659C0C40DF04B603EDAE85E81E634E58D053FB8826603 96B30790E8D2613B273B238365F35F21631335882693410ECFA8749E23D34371FD28F3CE9AE7 192389D7162E3F180D161B3A46B371F27E4596209057C4EF994E2D63791F32B77F9ACCE54577 A56B50B4FA026D6C1573F45542D9B9338BBD2D4695F124C83D489606103807B66385C5E70078 5418C29853BEC2D18985AE0640DC7F2FEE566599EC473AB3E04052BCA6F6BB26C27D6CE87187 A3D4C69845A242FCAD1B66F5CD67D7F70422577DF10B05CC54D9F7FB036C289948F0387CBCEA D3A91CDEB9C2D1547BC6CB7B4A2581F39DBB75EA08A22542A723CDFFE7CFDE9D9FD926D1003B A3137A003FEFBB9FC84B0665D5B2DA9B37A3951A3E6EE16CE6F2216575C7C53061E5D64250C0 9E8EEA685306DD9F693CBBAFDEE2A6A188B21EC458230E078BF9C7CAFC1FD601449F647C4B59 B37CF7DB2B3070356900B3056B9272B476277AA35B97486585983EB96361D26F6714B49E000D 16007B397175B0AC21D7064AF77144D1C0800689468351A1605E21FE5175320701DFEFBAF066 2B93D79B0E5E7CCCCF8CEA636AB27E0A852F67B2C5F201081335D3C2B4EE9BC5D7F342B49848 E6DBC3D2BC0F4274C2C6F54DF2EB4A23D2D736BF0823581C1EB35C8C0471AD17FD0E177F4C85 A33522F002954E8BFB33C0ACE5DCF7B8310D71678C0EEB45A6F0014F0080B4DAF40BE2D890BD 3FD44E14F04AFF9FBA9D98466BDED50680BDFA0C95011E2026053FCF08E0C67AF107D50CE001 C7AAAE3FE75F5C3505BE54CC683FC9660425C17C9740D27C0634F04B784F758A6947A4F69010 8FACB2D6B08C7FAE8D40A4183CC6329F8B921660E54420E2FBC44E43724E8F30196888AECD45 5CFF68E47E28F68A8D82E0E7FDA8CCCE35EBDE0D146D120B1044A6E0BBD91B29A38FCF4DC8BE 9158C1C698DDEE07E0BB6D0AF5DFF5C1020E8406CD1449E012EEC3A82D6CDB42F8318BDFF262 54F3B528F01E8D09C147934DF965ECE201038EE90F5982CDA85381C2431A2BBC8DD5BA1FDB8D 9236B699215626F78172D3B4135716D592EC1DA0F30B6EFA498CC3192847C45F2019DC74F618 A7414DE75988D8AB737EE75A0CC778B00D6A84A647105664A6D147715C2CD14B78F261C05464 490115BEF6A00282BF422807BA6E62E5D6FDD7D838E8C39EC86970CC7D86BB6EF72E885987EC 8D919C37112C63FBE1993071D9B5B467E0917B35BBACB4ED99D4DD7E037B9AF008A5F7EB8308 037E0E5C6862864C9F77CE7054ECED04E93A1FE549E1200368F3702A95B519D50AC654CDE6ED 297A3C6A60EF1BB36A036900D4BE955EB4D72CB719B08694DCFB3125386C7CDA2DADD0AFE974 C974E18501F4A21AEFD4E0B4A9D2124EAD0F97C5F20F67C7100921B151E8D492B0D607D0A208 ADD6F315FAF3F054CDBB8EB9C5D39B56752B0AF1187F076A7CB7FC79DD1D01394FA6529C309A 77F74E0614E79A84FE47A6518F74376B4E4E76A6E0BBA7043066C177BC8B979A6F5EE3EB5BC3 16FF17BA8C4026F9BC861D524B223208CF94D89633DEDC9D80E79C0B8A620A5AF902879CEBDF 1E0EDE231BDBEF0BAB71952B8D04A1D572EC97FCA725883FB2D4CAB5572261FAC4BDF70615D1 5A1B79B856F0B393F2A065555FD2522EA74FED08700EFA68270627E09B91ED5D02299E75B066 C5908A5790E45376C149AD782BBC1DD01D49B555B7F3B4BE829E3D28878F575C778D26FA2CC1 74683854E0FA65D3969A3F9200F91258F274CF60978E45534514703BD6F1B7D69B41526CB310 2FC836D074C3FAD523CFE04EF705552C365A82E2376D208AC859E308CB61603C59C80FDBEE2D 15E1950EC314F2039B03B0FC16F45B2579CE2D45AEB8B978872E19E55CB9841859BC72AEFE96 BC6CD048DD1F2FDAF87E31AD8292B7BFB9623B1D1DF85325B5F757206F8228A5F81BB4D93A77 550632DDD41E61DECC1441152D3743A5074B6381F5842D8C9B5B468AF871978DA6B8A7301640 323C65FDDB483A6F7CC512D523AC9A2F47616BB4847A61D187408664C758A79904D81DD29127 9E8134FE1EE90AC55B2DA653FFD91E2D9D0B3594D19FF546DB593C8A699046C0F841B5F19758 749A14CFB0AB686D7E17C58468E950255FD299DC7E6435A303B5100FF844DCDF52E3FCDA4A20 8F42CC3BB0960E28B8ED5906AEE9C176BA5FDD3EF8BEF2A6C00E01D44AF23ED706E740ABA3D6 FE39A0E806A2FAC4E5D7BDF53322682A8D0DC5FE490815F388223B0316592FB2DA05434BF842 29DFB33DB898A5CC233102E29AB9C0DDEC5163E8D8E5FECF77C3D829FC98099C1F43A56161BD DE9373A14F69D5C35FB258CB96508DDB7B35A191C49ECD2A14C1907107BFB583E7B9BFCA5C7E E6D72F573E067990572BBC240D4C828E61F6394B4A071608637338987115F7437A65DF30ABBF 5DED1A9DD5059610EB306071E42F46A55EB396EA11832FEFD4BE1E6F8704E5124A162CF209D9 27F725D8D528408E8CDDA8BB494EB5EF2EF90DADEAF45E8624E89FE5080A04D2625DE67AD601 DFB2131AF164F8169239A4478434FC2C2D882FF899721938BD643A41298DF0BFE1EE3F3698C5 128028FF6BE57E6700B20649CEB0FB3C78B2BEF03BA238615FB8AE5201B111607CBE45241AF2 AD6473AA54E9739E20F3F84DDDE871F1C881705E2C75FD0143398D968F49BE08899FF79A6076 B4F283588F2DB488B2B58275E6E28739D80D0B4D18EE94EA308C01EA16F856C94C95DAAAA0AC A857F66E40498FD7CC3A8A98DB095BF04C6411A90A534E5FCFAFB3A2EAF29D2C9B24863F1D9E 12A63FEF41A06F1BA5D26962C6A12D1A73DA880AD379F14BF568C90F206CFB6D5D53FF552D15 C261F08B12965ACC6D86C25C0D1278A0F929EB931436A24875A01CC6E793EBBE243D880F9D38 9C96E63793DD75CECD3D86895117F3AE55D9921A1968AAC765AA2B99AA4B21B203EE68F644EC 5C1E965BE0885CEFD3FD0A2E0537BD02EB24102C8F3B365E255AEEBBC1CEDC7BC2A8DD1EAEC5 7EC0E642A22805F2BC745A778E25A9723B420C1FFCDD3E641445E18AE18097A7A8E54E1C9DDA 53E7EBD84CE3C18D56BBDC54C180E899D4BCF87C1CED04E10C401FDB83C6F353A28688BA6317 D51A09250E1C2C63A6F9E8707D4B578CC61CC39E60B29EC86FE27FE12CD893C0C4CE3EC5F88E 837623E202D5CF939AD560888684DF0A6C0BEBC5478F588F5234EDC52384895A564AF2145FE1 E11228F9BF5106D900011F9A9A953B768B5CFDD595987C6F5A1F2031261C2AAB5B5CEDB11F76 BED3147F301F821662B24D3FEED7A7A2D08F1009BD80593A7B885A4998E59683EC88DEC130BF CA01BD0A9265D74CC75A2560280FEF13012351B99176CE25E7BBB0E3CFB46BD5D7C64494478C 87E7060C80CA5D5AC356CFE128783D6513670E1574FB06F009BB2671F0201B847460A54C669D 8059A0056B75EAA5236216911B9FF62DB67979DE3DF71977EA93B3626961CE1D174A10B675A5 763B8126E0E7E9D862ED49D82F1CFAB85CE6C94AED40A3E28EC2C7130C1BB420AB7DB578EAF4 D81E4FADECC7E639F154D90E1194E1FBA01F611AAF2D634CAC03A34E9E25CD247DA54A1FB27B 2888342850824E004B167D9EE44BCFB4541344E4F7884591622DB99132B1AF86A261CA17DA15 FD4A2584681C7189FE4CE25B2986CDDED549BB0DA8C06FDEBF64C80B0B1A89D2585B9190EF58 847BA4559EFB7C7BAAE64D37D95549061A8064637238FE3DE8AE31F06AE4E7FA588F85C45766 EED78D8E2D9E8D96E40CD161D820C00CB0312463FEDE8441E6CD3AA8777F8D4FA553FE9A747B 416A83FA728A52AC033A2DC128EFAE88808CCC435F1FD45CBCF963B263E714CD8C11715B4BFD 8E0F5613101E11720C2EBEED9879894FC85927DD8303B990A2062198CE7F3A0A48528FE25497 0DDBEBCA2C1A2160548C1E97EF58769EB684598ABA001EC66A278D4E353CDCFFF720AFDE2481 B9DBCAC57EE38D9C464FC1F331A45D1CEEB585388E00B139F638BAED8F6ADF8D11FBD0677716 AB72017C1349B72739749FFD24D00D8435AFE78805E455DAD15F6F4500A041E25E4E890DC0FB A5E88B7354302F59D03203997948AEF1FD05116A2856CC2A44BD0C2147C7CFE5AE9A9575A49E 1EDAFB0FE0C7F18D1466946398B8099D3CD61F38950BADDAB531B2757395B3718FD42651344F CBB9AE1783CEEBD9F1AE5260AFEE7A037D195E25C673BE0389CA160BBF2D117DDFCC409DDB63 DCD48185ADF29955FDB42537EC1C19A0B5E51D8785F06769C0ADCC90F5632A9F58F89D333F04 623ADC50F2C78661B84FADFC524445374F394EF24EBB0FCF338FE9F86B654F112E8C987BE7A9 A23C0AE29841F69B6F936E22507882D1A557E36B4F9F2C3D5D054A0167CF2890EDC16E5D260F 3D48E5117E6B8758DA5CB55694862564D0060AFB15641040F1BFC982926BDD21FAEA2264C8BC 94F5E4F882DC8772C4A0E049AD5561F0F240C28F7F863AA572E1743E27C1E9C1FD00D0C501E3 A90E9F86536B2695B38955C97095E1892ADFC6A6BE12A986F2C79F218B1F0BE6BF3364A29B20 3FDDE896664EACA5D770C769A36BCB8AA57083B55E9A31457EA37E4B83EA4C28EAADF56256CC 630EC37F5CA96952F816EC04A3797A8DD0A33CFF1C4171AE5163D786105B0AFC689BC96336B5 B28396E0F56193E684163234A361A57C826E805477BFA84F78BED285E64C5C0B0173A82EEC75 A897AA2739DB136529C9CA30E67832981685D75F7B51360A97256CF5CF87E2A0CD4FCB59E64B 3B506871549892DE880F4C39D40865E1A643D72B5CF0AD4A56FF0A6E68B356E2FF10265B069E 954D2E1C5F6D0BF4633F5CA75617C42D53A35AF4EA98654303B54BF58EA419F054E4786704AB 99B67A3F293A027B6F3D6EC6ED3AAF74B7CFE18ACEFE143F65CD7774191CBB8F00B3027BA684 194B6CBE20796A9A85E205D774C47EDD8D68D754C8EED1211044BB4DCC0E7E14A1F1EB857BB2 5D4191E0984EEFDBB7CD70958673AD34A0D182687DADC837139F087F94F526B93189C2AD5495 56621F38A8D492B144881C69C76E611DEEE5606E8D9A3620B946571711ABC30BD4C2BD2153D5 E557F53B667F996199989CB477381AAF8B554E4B0D0B3B41CD2DA66E120856DDFBE6894484C8 8EC36E804C598C9DE38490313ABFC3B2E9E67F6E304B347F537995416CF9B00CD0DA9045003D 7D3F6C7F358C00BCF66C9924D4D0ABF8BA9EAB1F37ABC4FC276D18ABCD2CF5E583004A4787A1 0DD260923D86CD83BCB52B8E1A7643EC39F4EAAE5F4C7FA0B93177D273492F0EE0688F63A0C7 765168619C5793BFF01FB5E65557D3452BDB63377DEA0462A0294114C125D79A59BAA2DB0B61 0E9A5DDBA3A298AB82E721674656EBADAF525861D924DD0BE6182B74B548ED0912E6D0216F94 D2DE6103F81C8DFEE4E771DA478E303D5A19170CC4CCE2DECDFCE2260A491DC221A04CE42EA8 2AC34011E8DF80DDDBB11D5CD87C77EFEB80179BB5834D4D4F84CD7ED478DC2D5D6C20E9F666 B5345B4C34DA11391C607CB413BC8C7169ACB9C2BA5CD27436B274C5342B2AF7AF334A2D6307 6DA21B66E87F86F916C03AE2D514931A8251DF60C4E50780F4622279B8A8612377401411A808 2EE7A7363381C053BB136FBEF76B96B3AD7D1018C9991A4D17CE2F3B626169F606787B2A54EE FA97EDA191919F4C9511ADA863E93135BE665ADBE9C523813004175CDA72A880C72FE711ABC6 7446CBD6DB20D7EE6C0EC8CE999A4E28B7125086B0600AB0F34C5AF47892FE3FB9403AF0EB4C 7C8E39E2229A2512A6944119F10C7136F81385372B28D39F1850E77DDF02E7A0FE4063915E12 BCCEFA52086840D7E26B6FB8BCE852311CAD8B0FECA03DC393B896B0EF334BD4A25D80EFCFAE 9398CE495A8176810DF51AC2C7D6145DFCE312860248C802EA7373D7B1F59BAE9A8EBC594E2B 11C184AD793E8F9F0C03F2BD30EB454101EE8ED0FB66B9AE0594897F908273E591849F822285 35D122BEAED330283C76080394C89B534029B637E895A8F1A36B01CCDA7924FE2AC9F0442520 47D9979C77F4F52442A806A9CC723EDAFC8B9AE8AB884E9AC1309C9E55AE8B5935AB1F70F413 41E718E995262DAA8716A2BE97F1506441317E556690684E040D23A1B83A32B747E7C44F3046 58E9B8A364028086EA8BB8E654B4612BA44D8E39A1163E7103912B98894A79BD5EAE70815A16 8229B8965DF0D76B20B081B527F16039AD39FE609510F68BD48D8B6CFE02A9784E282FE64DC3 061AC3094BF3BE7E9E7F7EC1807F0EEBB0225CB37A4443CD9E4B2F25DAC8196ADA984DC31CD3 52424CAB7FD0497A3FBF2F02435B8E661F0F73D21DA704FA37C69407AE9DF10DB5723CF9AEF4 0D3A860F9027D0B1431CD2A92409E1E4D986D34B64DE243CA561293D0569648D5BC9CAD90581 C666709DED4565C386907F9397C442A2C0D358701AC2AF50D5F376B384D52E395D52BF6A741D 18E6AD76914D68C7E3FE1246CEAE4BFFFFEFBD7178BD8EBD239EF6D5D59F2BD71E899E763A3B EE734080790DE33CD9D0FE3D1289E80C3EB0C8ACAFD4F3BD4DF6537B1ACD2BBCA186CE615A9D 0F0735048268D370AE929E84D2953882F8762D3819F61C0ED85A115C6037BCB108B66C7CD1C8 3673914FE883AE6331BF32C3E199F7235FEFF1895577D216C8ED6E77DC5708F4CBA32CF1EEB1 3D9C0145713A954072637DB4FCC1C1FDF0B5FE965DB518500063090DA4BEB238EF9F67F92B1B ABD56D2D82975D246E6AFA021E0C23E88A70554C2B5F0A328BE693E22400BA163AEA84453BFB 05396E1C1A90AE9EE51F5C8A98EACE0A0CCDFE699B5DD368CBC7F6FB25A237FF848C01414DE5 63BC991CC1A0A5AE840E8EC328303206D4FDC06BC7D89EB8498B611A91DC1037378AFFBF21EE 248D15C95BC9F07A856771546E28EF1954445155DF4689527EE4B72A3F54D2F66696371B6AB5 848A50D4A3F5534BE82FF257BF014769B253DEE02AC57A1CC3325B5DC44895D210671E7C77B3 0C8266A1C9D9552DBEB49177A44A6F5F018C1D6DAD19F65C5ABA1F7FE55D80E93507338B0F0B 3FEFA0565E6BF4334D98AE53911433146731E6399A8E5783BDBEFA8EF739FEC5353E07E423DF FE5CAA3DA0A486E4DA42E84618ED89E60ECC6E103BE8E61ED5C396EE9D800CC83AFB6E532BFD DD96ADDAD7DD85146F410B40C43BF1F12BC27E07982099BC4718170D8043297DB95A571E1268 638621D6E295CAA2739F9251E7644EEA31715A42FC9A56EC891B5366F3C4F26C77AAEBDC1BC1 FDD5E1AF4A140D6AE1EAAF67C0C28B2B4F886F0D8674B7C0FA6E7AE7F05D56457D1A9E055C2B 30B809E3A84E706CE981107FC33D61FB6B6BBC9FE5952EFAAB183C994A2C606AEDA95E949231 926FA1CFEFF17B86469CB504ACAB435E8CDC732380E4B887DD9E08618BB8134F4E75417EE647 8B9BFB11DA7595E042B8D1BA639A1606441872AC2BBF7065341604565B8D266D64340B9B1810 8B9A065E9614107C3B2A6E1E7FC4C65331D63278F113D9724A92C0AE7A1F98D5C07DD09A7802 A77F14A551508B77316E4DF79497DA97823812A6153D81DF7F172C96E5827A5BEC3BF2401009 E212C8AD794D49548485B72C67DB2815DDDC3055ADB819C1461DBCF71FE60F7E0D5BBFD010ED BDB843603BF2DBF73B69A9685CB4D282B4B5CFBD47D805B9E9BF38949A59B4DBEE9FFFD200E1 8E163866CFB2300DC446A7F7BFD22AA5474B706573FB73336840A60CD62906CACA961B801AF7 8DE0CEF472C0B96413847AE7A911CD28638F44BD04E6D1A1F6847A50407CA9A351B914EC5906 540B097448B4473F56E77E568DC0822CB54B312E4F9AE5742F6E61C1A5557BC04BC08F39AAA4 2AB36A10996E1412D7B046EBE11C4131F1859178DFE84AC8CFBE05CC3B919D5BC91DF294640D 4FD5835CC5CDA37E9062634745E5F3D3C310CF73F810100EF5945725FBF38496AC8763E28B9E 69566C0F8032129D569ED8B93FB794473094700911A2090A9F6D8FC5186ED4DB8648C32BA583 65D1DC247BA2FE69FE4A42F5423EC4A8D1B9B07A836B83201EC205D158A80A8918143CAED74A 60A4D022EFEE3C44FA24FAAFD7E0B08106AC9B851DF68C1643D9BCDDC72905440C980113BD78 91394313840F7B4ACFD26CA6C1FC757436AE7D499801FE39594393E0FB3699AE6A7F387AAA2A 6D955739B2729CBD00BEFFE282E12D0E938D512C451E186E82703BFAC1FC85C57957B482CABD 8D3032CEC83C3F75D981129A6B5736577CF55C417D11F26BA143D197B53FD97B7766971DBDC2 BE12F9EFA47A0DAF683F504EF5726AAFDF01FF5B5D941722C6D1973FF92DEFA5DAAE8554DD48 B01FF2660B6A31A210F504BEF75C1E8EA6E243972114DB296D19C790F1806E58CEF7F17673EE 6254A4D8D14C3ECF591AEBBC869861604E181BC8E70E19A178F0118FA307C16778810FDBDA4B 148BA33FF3A4B38F3175267E7924E7912C52CD78352688C45644794CBB843A501F6DCB88BAB4 6CBBD6F36E31DD0FDFE755081BF4F0168AC57D32E63BCD9E95C6C55D9E56690B7ABCBFB535C8 0AF3825F921CF6C3953E40BAEC3795A32B04328750932DDA02B0408EB74210EAA082D7E81C04 DEFE9E7923DBC0A175EE616161F96FEA8BC29953EC47B82951DDFD4996A6573C40220A36355A C3E696C07F61D6C0B16D2124F2CAC8766C65BBC7B8BC8B8B0D5D766533868A1664E319719863 F29BB802EEAEB5D384E95FB9A784F894CE477D8A41DF73E6B560447644F54EE71741AA8C3CFC F40547426B5D397F873D38051A1C37C05DC2BF7C77F4068D01DBB0E5FC2E3CF2524774C37525 8AB840929F058BB06B958E6C9157425C3D7A2C047272C387E92ED820C92583E3624E6E498A5C 23264DE1CD9000C7B97081E40023C071EC3968D22331DA058AB5DC1A4039B0A313D70255281A B7CDF91FCB32A991EEB82E6AFB4313D4E236E57819ED4739863997EFBF139624F650842DCF91 A3782B41851EDA4B45FD9E46BD4002379C66F700AFCF7B04328948841749EDC07B03277B01DC DF1527F14E261788FBD4D326177246589B5D6003653154D8CF5B262FFEF2BC3C5A4F2C1000CF 1E22408F1C4C972969EA4156B3B0DE2905EDCC99326C3F72438C659BCFE4E420C643BF6FE226 5CE6EC9092859A20C8A8D0BBEE2FC3FB0D14217E973E4C7B318CB7A8F6ECE8021EFBA044B1FD CA1BB763C1E37D622F833FAC366C66CCB1C44D8EDD405087D720BAB0EC695D22D86272BFD95F 35FEBDE770C397DA6D5B212AF2DBF1A16FF5F125F3F524F53B98BA064535346D0DCDD2CC02E1 C55EA0E0F847F766720D6A9D45B9D9776F35B65DA3D8A3C78BB235B0E5FF8819217B77B86A46 FA0ECC6ACA8C6A053562FAFFD3350F2A056D2622A3A4D673A6A586A03042815ABA31AEAA78F1 09410D270DDE0CC99110A420B54AD9CE4B54D4687B07EB3AF950C1D4B88B0AFC37D792407D94 50EC4D77EE6DDFF803CFD0F67354DE749FCCBFE296924AEC3A305857E94B65E91FDD9F11B289 CA47B191C7613DF209896366E9D07431BEA6A229652AB7FE6A210277334784C8D6627D7D8ECA 43D4B8E75E1E6AE21651E7B9942FC0E781D502D8D51D7ED6F9576A12A2CDC40F3781AB70437F 9D958EB6477833B9B85F391AA10201E89C70C0A6B053E5D95A550BD380809C3D9249602F7EFD 81EF86F7BEA0CEBEE78FF7E51FFDC2CAC7BC2692E3096A1642F40687ADC3CAB1626F7311CDC3 B1EDBCF3BC8A56153580484B30875BD19B65F77320A26A4540C1079D23B07C48FE5D69EBD7E8 AC5C11333D9837FD706D1C52FDCC2AE9D13B3CEAD494B7D0AF602A57E5032F872EF41C71BD1C 53896529E6050BFB85998F489CDCEFFCF9B70E5D7371422F031AC9C00D00E8C436B6EC76C9A1 1B9F92AEF7246D46EA779C051C539A5D0B537F05ACAB9C2C22BE43EEA3D56F52CC7087EBA41A 894CF633481422F5E6270A4E6445496DD020BD3CD846F98CB64061BC16E6C7E5430EC1BBE8CA 2A9390EC2B3EBF282226EB70D5AAB4B911EF1347299FDE67868D6C1ECD96B2A8377068808629 E2BEF81138EE0966A059BB6058CDB7D418CD5F217DE21C03C596471AD4125FF448B5DE9D50EF DA9CCF04B3D4D74B452BD00C7AE549FD0F2F1E7919DEC06ACB53D39A38E75397296A32E61A43 5D4554A1DB7757288ED367DC6989FAE7F428A8E28E806EF90C4CE040D1478FBE47E2CED9C3C2 4716AB2E4A138046BF7F7C5C6ADBC75A3283CCB5F9F53E1FF05D09186C8EAD24CE641DF1844B A76AA15586A93049EA5C279CD92F070B162F59A7023B716D9901F332C7C05DF88C27BEB76A50 4BFB2F9DD053627942AD6F04315B51140A6DD16A9CE1A4AF46AF3EEDEB07EFF17F6BCC85BD86 6E763C64CE25F9F9D278F04AC4B12A03EA26BE39FEC35434A1A105DD410FFFE7B99C0AADA93C 6A834BA7774BAA5C01D2A8D89812433D5AFA22507ECE5014737136641953F6B053E93500B069 34C25D5F2E7F45B00D78A4702A086AD89A965EBFAEDE1CCB95DCB9B8F0BC376CF29EAB1288CE A94F572383D358AA48EE8DFF88B20A78262813BC1A2849716F6FE7295CC153069E511281DE2E 1135B90F14A9AF09AB377E76A38D0A8C87AA352130228BE170E0845B1FD3C115E7BCD94A807D 0B079CF9D0A4FBA455CA2CE547F24A5AF1A58EE39CA617E2C15ADFD2AF1B6625EB8310CF7831 EA2744FB523816373E69139B2014771C6D7C9DE12CDC486943D716B9ED76F5500455641DBC52 D5D20D43A41D28FBD23D557AFE215ED0E7B9ABED8A5F908CC8331E3FB61C9A9E73546AF3ED88 A024607B738849BCF80112E995BEB93433174D2FA06F12B159979743EA404625BA7448F54DE4 46C9252A6A2769506905F8448A938EC2BF8EEF3F73BD5C7B5B5DD81416DCE2EC74AA7ED2D510 CC6F591D0C51F2DC4B8379D06775F0C2BEF70343097C44EC7FA8F711A745F3330DF7B8BB7742 EDE598BED07CC879A10B0B34B20335A36383A01057A53A5243363855C70AFF48F259A5B2882B B302D320E533225326249E426BA07FBE02C76D5193DBDAA10FB23DFFEAC7E2AD096F324E86E5 A6B76FCD07D6129338D14A893EE8D92F71A9DE75D6195F71DBB650F0AF3989A02002DC32D1EA DCDB40CA3ADB7B50286F2618EC285B822EBE484E9AD72591F5DDB07F3A31EA9FFC3B26039676 D1BB14983439F0E7517674C9E36D1F86FF8032E6BF2801ADA6BD004454BC61FBDF33A2788CEA 419B4BA1A0AC2E19660D6173F539E7EFE000AB18CE9F724E5CC641D6052A70F994A38E050030 ED2CF32A037B56E9CB96C149A10F34932FEB06AAF48C2BD54D25B58412CA1FEC65891DB9064F 3CAF93D6FCC90EDCB298BCD09ED00AB7B46F5E776DB5AE0E397F8E780C4F9F19A339CFF8C9D6 6920AC9E95B3D90F335B7B5BBEA40082EE405AFEB3397A4090BF854F0A34DDBB7D80FC30BDF6 DA9032106C0A090004D0DAD25B27B99470796E5C4402D05D82FE0533A2FC0641E06086D5A63D FB4C9E35A8A6ECAA9259F93B812796C4A331895EA2547ECEA1EB254B1AB777FD3EF87E583817 4BD6919E04FA04FF349906D4AA7AD2CE33BA754276E5712F3EF752065019563446103EF6713F E9ABEEB69D73A66FE463A37EFBD1A37A53B42F445D13DC40C1042C38B09478E35901501053E5 6E98C2EC86B364594FA23DEB6EC3D4B16C41A5FE34A13B880066B3DDFE51D5DD7C74CAE27085 9934A57FDE18D4BCCEA46CF0B05C2EDED63629700526B0FC9B40A3ED89A3718DDF61A554FAC0 6F4722CBCC8FAABD7960DD7D733A73E820787F5AE1F5B0526A76FE49057AFAA7D42654C95B39 C9294C20F36694DEE69404A8F1FAE78CD75FBF9F59AA7D9887DF8783775F26CFACBA6CB01B30 602446E1754E2F6BC3CA692B4A6F078736F9FC74312DD87AD5974C45B386CDC5E64205AFAEED 297B40BEDD7630660FF644A7A9734113E58ED8893C3B93A73F183C1CCE12035FFEE9A515C349 16A92220D07F065436313638617BF3780BE2C9173472B8A69E9EF800CD93709AAFECC61734D5 DFBE4DF2AA1AF855786753A0CF176BF74CCB46D2CF239BFC37B2554F17C1DCBD693786A0B5EB 82831F9E8A4B42EFAEA6B10E7942AD1B783B1D644DBA9B5EE4B45CFC496FDA6F98881689760F 734AA938CDEA288427833C4F24999E85DC610EF3A484587266F72E1D9EC3ED7798DD3A9EFAD9 854133875C0F42453C21287E5A4D1854CDD50DF26F572A5933CBF0944F611366C6E6E3B80D2C 4C44DD99E80FB8351C9DFBF38CA541892804DC2FBD14B1CB344555FE484BF649C9308B751AE3 F27D7FA779B59C3D796493D14426A31C4825DAE251B80D462C98F287C5E60B782153854E29FC 3BF95B2C4B3A987909ED65D3345F947DF42A7C0249602EC342404301F2D1D1DF0CB61DDC5F38 C3A967A0CBB707EF6D2458AC4F51388F803C2D4ABAE337F604D8508BF79A9A1BC185C5030DEF FAC72A16CB51EA6FA8DA134DEE3EF13226FC0C5C5A00573CCC71B7F414E93442B0558A328805 786DBAF0E9470431002F0EA58A40AC74DBD1805734CEC67FF5B8E3AD354FCF9AAA26FC636EA3 0B026DDB98B7749DE54C37EED9B0C614C1CC5F1DBFD618BE5728772E67F85AFE1DA3E907AD8A BF69F6CA96E5452DDE3C047E35FC55AE164729E59AE10FE733FE1B58FAB7EBAB46120ADFBE71 3529D6B8728C772DCF0B43D42E9D7B7DE2FD45B042DABB9D573FD68BBDAFD6E26ECA6672A425 5D591136049F9C2CD467299EEE7766880F5B174C2CD570011824C958D102EB97BDEEDADC9B07 33BDDF99CF1C20136F34EE2461C6D5CD1A77DA5A901A66B2E3D57910CEBB30C60AB149336F2A 91A9CCD9C6771D4A48DF99FA4683DB39A8161B83CD29E70D51E2ECDA3DD5A34455585899F61E 7E4FC376111D29CAB945D3FFA57E7DB12B894948A37DCB2BA9E79537E3FF095C81CDC6A4B228 19D7E579355B281A4F44C5F475AC8F984B78A91B20D4B11EB47BE5905059A211A6696DC066D2 A5792F6AA667BD5AFE92C81CCE1753DD689FA80010DBC4E0BC917CD4FC8171C991D6FCBE5D42 CCD8EA0017C0DA02CF307EF321A0F883FE33731655A5528AF87F05C406C7A05DDFD4D6889654 99A3ACA7E82F3F2D85941653AC8E45C3956CFFDAF91CEF1F1AEBA26EE5495A3A28073D190A38 1DF5F2384D12C1FDE082378B6FCEED74831C12A54337D64A6352E2EA85E67DE10B4CB5E09E5A B6A356F2345EB68EDE34CCCBFA9AA7DE38B5FBFDC6973531B20F85D127EAA05DF03AD933D546 0C50933F551493AE28544F62D126F2964E834DAA0C652C2EB4DE3B0FEF10C974FCC7C10F0196 AB56D47E268AF927A96EAFADA234F1030E58A257163B72793D8340957515D2E7FF6153923E5E 3EE290B6284960967479B4D81BAEB242B327D6B2D0FF46F77E43B4A0F820F66204D507E7C1E7 BBAF0927478F9F9F7121E11CA789C0E0418217CDAF10875F96FD05D49913091B920DCA3BB373 99A1D88109D834742524CDA2FEC84E86F232E5DD433F924E9E01BF6E446A63DC40741D349420 26DBFC8D3888A3A834BD4AEF3F5D38000FE075AFD4CB3DEC0415EFE16FA1820341A48EC4B3A1 086BBF729E68EC9DA96296A4C9D551E099E3D3BD8F464FAA5735B99963DE4C2AC96BD0FAEC57 E61C59133EF494085A9DD295B45B5B86307C7FA720F7170DEE2728CC31C58BA1360EF0733918 D1663BD355295CB8363E9C53B1F271D5CAA6D53B80D8DAA29E9B834271422637CCBE92D7D9F2 7B3D3BFB8B3FDE5C6959CD831B09948F92943A455E911801BB69CDC4AF15ED67529D529B9915 2AB50B8ADA7690135C54465F46AA2D6E17FBC36E92E3C9A2EE01CA9693646DDBCCB439F3405E A6C6FB477B56BEF0FA5C5EBCC067C959C4453046959C4A9F1B166AACE020CA94F082899CD9B0 FEC62E8B60851D872E56D48C6CD9D69D5540D1B3F1102E0B641BC40E17FD99A9FCF1048E44F6 ABF60352446E3C8520273DED902ED39EB7BAE21995A6F48D89A74A31C40E585D6206D90434DF E9E3FD3DAF501AA292BDAE3040FCE06586D10B19612590DF6D9D60C086C9BE4D2467DFC042D3 4BC7C37C93E58924BDF35C5380B84B5BB19F3658696D32AD3E48F95A0EBD2005E50423C9E3F5 DF1DF53F001CF6A914D3F7545531E578422D99F9D914C7D83FAB83424C583F4A78C51B194E0C 5A80BD051BB9C62553EC3443315DED169EA666119BF3C5730391FC08EBFE0F2B8D6B18EF38FE 726E9EB4C41E11C9A22351C374341AB728D0224582689A104A8B3E7DE0FCAE31EE8BD13397DF DFD04211B18938BCA715A66A1C7AEC553A14C20C909AFD757241C62DCA34D6CF7ABA262066C6 3BDA13D3ED508F90AC4CC8F34A3C7B8596A47A24B0C048898CA14D7DBE9C48B8D1DF2057BF83 1C0C89C470F3E526DCC94D247E54757DE9AB8516A1EDE99EA0902025818A06C68064AA4A7706 3908CCFFE4751E161EBB1F5BF09AB351D39D0FC2CB8021B73A8CBFC7BE80FF63577CD226554F A9DB429B058B02314ADC063D859740747B54961512B3160EA441AD31F6DC6A0D8AE9BA50B0DB 545870A451690DADBE35FD8BF54D32C06BAC67C886516BDC7FC91CB9B6435525073E37CF4670 708805243C6F9809C610CCA49C7D53A638B04B15FE1FDC4F6C2C6C274D18DE17284A4A6E871C 22D1D525C23FFD924AAD6367E6F3E576667A2766102BA4754E6E3BF0F854B328874BEAE2065B 5984E0FD540F228BC854E6DDE07788975FA64CB562656490CD30C95D4DDBD8171E4FB1A2B5C6 D50755375446CDD0B405B47143538D4FDBDA098AF40A06B1CF7A0565009458CD116069C86746 DAD2C0E2F24AF45B40BE740E7485BAA6B776D99ABA9BB0A25C53E3AA56EDAAC25BCA78BA2A7D 0AE5DC30D2D80493F95AE152DC0C07946BC5B5EEC417E1903B3ADA7D1738A3EFCD223F743CDB 75F34A83E3EE70339BE05C352D8A8C3D3BB7B3F934A43C26EB2A849A2B390D779C9989E57006 AE913F406998391013A463175E9E4C8DFA17ADD0A743322734CE5BEA82CD7A4CC1115FB00D1B 212C8A340B0AFE77568219B9A3C523090ECE0515CA21C05264BF1934F557AA0197934B8D27DC 634A30C5C325309E6E7704E97BA8C06A8200B041FCBD0D539D972FFC6B1250F047C4D6C5D549 7B3FDDC7DFC0AE135AF47C31446D8EBB91190847F870897CD034F87F76C4AB03901B37B18746 0A32360B86D753C9FA87EFA92B79919BC2D181A81CEA92C438E05EB257839443FDB5E96A4CC9 898801D4D69EABCE3B92AB3427930C462290300E334EC1DBC9E54453F466B9CE2374CAB66535 DCF6312784A708A25165D6667088BEC143F05A827EBA0A9F6AB536B69F8EECC44CA548F7072D B51B6A189B4260ABF269B0A1869763ADA330A595CEBE655FAAD08D62415ED6587B393360DD36 6E5350EBBBC3098317B97581BE36742DCC36CCDBB3B42420C791A20CD92FE82947EE6144787C 4C3A6EAE1B13EB6BCF4D0BFDCF25DC941B47FEEBDF2D49293DAADE949AE1CE74037676E01A39 C2AAC54ECE35A8630A1756AB03059A7456E1048033C7F1248324643395FA6FACAB5E915F76D4 40CBF009E1AB1F39E87D9D5F2B5F6BEB9034A987A18F05A558C173B145BB865FBD5EEEAC935C 70E207BFCD63C514FFEA2250B6EBB33EAFCDA4CCFD0503E5842D6B1E27E546BE5FBED519603A EE73CBF5B83C51C1BAE439A559477FD7BABE6B33AFF69EBBA394355679A1518928FBEED5A751 6488EDC265BE1C1BAED666E33FC9CFFC35347FF8834489A916F048B25E96AD4E8DEE3AE05C75 D3AECEB30547329D9FFC69BA98E2FBB7D1D78FB6355CCDA87826AACCE1AD13C39D718AE32310 14EEEA3A5C79309FF453C8461A4C66C3751F1CBC06CB25B9DC60BF3583B142AFB8334EE23DF3 C69F8AC7C2CBEE75CD7F4A33DAB9C8481B6282FC58ED195F1780E493541C208686B71EAAD9F5 358C0DE284D54F0B6341807BE697E3D737BA6D7796529FC73843722507DFC1598C1B808BDC6B 12A4259862FE387617B2E189B194D96AC95DA4DE3663FBB4770341BCEEF13C75D76C655B40FF EBC66713A3416E7BE641F5F8875D36495DE4E94A8B6508E6F3EDABAB9FF52829CC674340DB57 B248864BB9365AEA3A6C84B6A1D0D6928D275B5A79ECADBC1836F4768A715556B98FAF6AB81B 289831B71AAD06F5217610CD7BF4F92B48F7681EEC635B26E9DA602962E4BB9B3FC4E561E629 767C0816DDF8073E7E387A125FD81592A714B58A03768A8309BFFE17F7BF45FC0C0820F0137B 398E2DFA6376F9A7808E9F7987F7E8D4898CC8D16500BF4BBD6BE2B9A166DF05DA84AAA132EC B88A11BE7929811EAEA87299F26CCC439A374173B6AB3CACC2645781F787F3EEEDCE87427F6F FDCE837946A0D5171769FB3F150A51E16448C08B8F8D78CFAE3A98D5F18F26E745CF9DC64403 91AECB0B61C713978EA17623CC5ECCD22F4BFA6E655BD0A3212B9E2ED3BA6E85D61F099983AA 1EA8CF1D1D852C03B2BD92F0F51E09C154DA9EC5C879CF489BF99923DB4D9B68A6EC66EF1D37 B8A1B27D50CB931B87E74B65A9130423C162E66AF90B61A32C63B1C92F9A01C4A3917407FE69 A2F64FA60C808EEDD1825A02C9AC689641B6AD379D64F153D063CF3664751B06FAE88D17014E 5E0B0DB0D41A5817149DF3773F81541EBA95093B338EA9CA58ADEE6578A540B59927384F0F08 536A57686AAB0AD877E29AB626E9B14FA7B1C4710300583DD5AF73098E1CF1B807D647149523 E1B64427E7E5D1CE78EE1E7025A34041E87D9F6A97CD1B37BE324571FF184EF3DB86EBF77894 5F7277D0C194419CCE2546727552660115002034E6DA52BDF3FA669EA30318BEDDA7E7C02588 8C1DEC52925AF96697919C162167E3746FDA83CBFEB79DF4D2E8576C8F186C31ED02BB428817 B0F8BDA82D74DB4903CC1F7B18872EBE75C7EEF577BE9309DEA7ADA7565B6943A28BAB624C0E 7FD1783314A82C41097031886D8D70FDF368E95BAD9CED5F620A11031ED312FFC1C2A587BB5A 6570AD89CC3FFF6F5AF56C361BA367A5FAF9C1E4D9F2F799479730FAD7DDE0F1557225054646 9C9C64EA50DD1071701D2E0CF69F227C2400F01B5ADBD34887C95CE68F26A6879CD224D2B1C1 8F11E02E3CD42E35D3C3D30084688F798FF91EB3D0A82F11AC9212B2F7D9E135BD3411CC7188 76775573497F2E5D97F5FD3D0C8AD2FEF53654D0E016A39D4E5717D09CCC87367E1F3193A4ED 5714F783794436403209E50D8B96533F76CC66151CC6124CD63F33BD572D25FF824AD44D5163 7BBB017453E4B3B37C0140075422BCAC441047654119577EC6ECFF0B580655C21772F99DE072 503A7688E22BDD7723AE7E7537ABEDA2064A1C48424B0BFCE52607CAC741B762622E6BDE5B27 794B4989FFE55F4F2EBF290B0FFB53C62A2BF670946C8CFD089242341637B237C37269FC32B3 E61A27DDEDDAF2897844A3AAC99E2E23AD7EF3010D2AD92EA14FCA6D68448E961212AD79962F 1608F0193E7C301F5117C3B7CA92DCD9613F4F90FE4235916F17598AE3CBD144CCFE9F2937FB 44CE9CEA13CB7298B02621DDCDF2CCEAC48D2A22177E244592FDB96BC75B0D4D9C2108DE86A0 1D197E13FDF277FEC5D59A04380AAEE76ED736324239FE2103240000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMMI10 %!PS-AdobeFont-1.1: CMMI10 1.100 %%CreationDate: 1996 Jul 23 07:53:57 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.100) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMMI10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /CMMI10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 161 /Gamma put dup 162 /Delta put dup 163 /Theta put dup 164 /Lambda put dup 165 /Xi put dup 166 /Pi put dup 167 /Sigma put dup 168 /Upsilon put dup 169 /Phi put dup 170 /Psi put dup 173 /Omega put dup 174 /alpha put dup 175 /beta put dup 176 /gamma put dup 177 /delta put dup 178 /epsilon1 put dup 179 /zeta put dup 180 /eta put dup 181 /theta put dup 182 /iota put dup 183 /kappa put dup 184 /lambda put dup 185 /mu put dup 186 /nu put dup 187 /xi put dup 188 /pi put dup 189 /rho put dup 190 /sigma put dup 191 /tau put dup 192 /upsilon put dup 193 /phi put dup 194 /chi put dup 195 /psi put dup 196 /tie put dup 0 /Gamma put dup 1 /Delta put dup 2 /Theta put dup 3 /Lambda put dup 4 /Xi put dup 5 /Pi put dup 6 /Sigma put dup 7 /Upsilon put dup 8 /Phi put dup 9 /Psi put dup 10 /Omega put dup 11 /alpha put dup 12 /beta put dup 13 /gamma put dup 14 /delta put dup 15 /epsilon1 put dup 16 /zeta put dup 17 /eta put dup 18 /theta put dup 19 /iota put dup 20 /kappa put dup 21 /lambda put dup 22 /mu put dup 23 /nu put dup 24 /xi put dup 25 /pi put dup 26 /rho put dup 27 /sigma put dup 28 /tau put dup 29 /upsilon put dup 30 /phi put dup 31 /chi put dup 32 /psi put dup 33 /omega put dup 34 /epsilon put dup 35 /theta1 put dup 36 /pi1 put dup 37 /rho1 put dup 38 /sigma1 put dup 39 /phi1 put dup 40 /arrowlefttophalf put dup 41 /arrowleftbothalf put dup 42 /arrowrighttophalf put dup 43 /arrowrightbothalf put dup 44 /arrowhookleft put dup 45 /arrowhookright put dup 46 /triangleright put dup 47 /triangleleft put dup 48 /zerooldstyle put dup 49 /oneoldstyle put dup 50 /twooldstyle put dup 51 /threeoldstyle put dup 52 /fouroldstyle put dup 53 /fiveoldstyle put dup 54 /sixoldstyle put dup 55 /sevenoldstyle put dup 56 /eightoldstyle put dup 57 /nineoldstyle put dup 58 /period put dup 59 /comma put dup 60 /less put dup 61 /slash put dup 62 /greater put dup 63 /star put dup 64 /partialdiff put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /flat put dup 92 /natural put dup 93 /sharp put dup 94 /slurbelow put dup 95 /slurabove put dup 96 /lscript put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /dotlessi put dup 124 /dotlessj put dup 125 /weierstrass put dup 126 /vector put dup 127 /tie put dup 128 /psi put dup 160 /space put readonly def /FontBBox{-32 -250 1048 750}readonly def /UniqueID 5087385 def currentdict end currentfile eexec 80347982AB3942D930E069A70D0D48311D725E830D1C76FBA12E12486E989C9874C2B527F092 5722787027F44470D484262C360CDFDDDF3657533A57BB16F73048BFBBFCB73A650484015441 FDC837ADD94AC8FBD2022E3EC8F115D4B4BB7B7F15388F22CC6198EFE768BD9FCEB3446EE4A8 DC27D6CD152485384EF5F59381FFDA43F2D20C8FB08AA27AB2015B774DB10DACFDCD33E60F17 8C461553146AB427BDD7DA12534BA078AD3D780414930DA4F8D58ABEFD45DB119B10EB409DD8 97923C6E705479464A4B310B58348C4B42393988FEF4925CF984423AAF65FEA9F0E64629953B CF50B919D968D99BD185F83112B2759CC411764E9BDE677F57C5EE5AC555448D5F81A16259DE D1E11BF4119D53E8AB07A802DF900D3A2D5CCC1C6876D29C5E9EFFB7AF3EF83400B0910C0787 3A8C56FA7B1EB1BA426043B00CC95DBEDC6E136CBBBCB3F67509964F9F281EBF81FE5B018122 EAF66C4A838487E82E186E006093042848A903EFB3469AB6B4049767AADB95C30408DFD58D8A 10F4CB22168DECD9F3EE100F07B49AA44C92139B669CC312BA20192454EB2375BE6284B02665 9D964B96AE82D4942E758027FCF23C25ED01115AF27CE7F20EFE2A822BB684004F20243A49C9 E93301FC21B80815C033C3E2BA58EF53DA2157D524B395F2B37ABCA13BC6A2F42E824AB7E471 06176B0D6DB267FBB795AC7425582DF2E3DC55863468A9200742BD7B552C48F8CF58BC21343B D3B95ABFA140F33F37C6F3F78B0D8A5154EB7C1F62EC598267F13E841A3E64172663935AC8B6 65D86540D316DDECE329C008049C5E74B27D59022C5515059BC3B89370B1BC6A169C888BB325 E0B74282D6F053A50DA4024ED1E433271A32AB8C17D41C632B41CF9F3ECD5FE124DAF7AEA7CE 8A63047B245822930D517DF7BAAAFA69D2D17F7D93CEBD47DEB85405D720DE0BB4DCAE731A8E 27BDBB6E6BE38D168B7DAFF815ACFC32CE367374BF9FD98C0AE5BA1BCCDB84D94B5C173ABC92 F7D18E19A68F64A2241A0A1639108DC46B8A04EAD17662B7BBFF3D3D9A95D5937698573BFAC6 4973DC8D8B8D9F68C52D0C133119ECA4FAE72F7553D276C817003234A98337D7C037C0F1BCE8 A80457113BCD97515C002D20F836FA086A3277727873EC2B64A92BEDB01193491134B6692A08 DE4A201A3F11DBE070D797F7629AD487D2B8DBF89A0631956C93864A4460AA3BCC8EC6B98DB7 5209AA1B4A2E2B1B9866CC7F3BEE4E0EB0DD68627A97A3FE6141FAF10A2CE00391796C5438DB AD93FBD065D1ED7E8B7879E0D1BE9AC145B9AA91756EB6EB81146048072303229CB8DCEB133E 572EC8E2BC954BADCE75356EC8EA0C7F76CA08533E874BBAEAADB89D86CEB974A52DE0F9A434 80E5076265AA6EE49ECC896182E6091EB30B7DA8CD0E3A26AE7FC03BA5C0D56526ECC6F2D6F6 91D84DC9E7DF306863FE0B6DAB3CBC588C28292DF3F7A47D9C4E3652C72F6BBFB3F4983CAF59 C7D877103DE7AD73F95A100AE860B4E55814F00A7026C306E85B8A48F8F69CA48AE710950A2A 1F2892F31A3849CF917002086DCA5F66B84EFEECADAACEB33A0932E394A5E17628D52E725FC0 C69E8B00C9DF81DFA32B2970756D947A9F56831B19FA3A2F2795017381C05919032FC19A6B8E D2D0188DC35923F486A62C8AE61E0A5BC681A57DC20223629C0339F67D689B63D842909188E2 CB82A4E0471B9F17CB8FDC6A6D2C3AA6FEA17A756B4D4860FB72B50CC39CC7E5329DC202A5D9 0160DCECB7ED07B9CFAEB7E766887C9B93727E5DF348FD2F5158A2424F443A8C72811CFC9CD9 E2CE8219667D7364E85BB01D8CBD63CC11533CB0D14B793D5E1DA99278E636CFE6A34AB61D46 44DFB5939746F67C71EA1632A43F457583D3478D159400E04CB7BFD0011048ECFE912EA5B72F 6C01F941C78CE1FDFE23370848D6DB1C88D27C9118B3C8C8CF0BBF33FF12B509D3594E187F52 05B9E96F9854002E8944B8126A8B2B41BD572E7FE727B10441F3B4B303FB576084008DF04128 F28A3BA5BF987BDD3AD278F316615D70634C47E6C924A9CC634A249D1D57DF395AFFD6B0C524 68061B62CCB46EC8CF95AE99EFA5DEAADC48F433ACE21B45CB502F37F06EF95B4D8880FCE2EA E511E2F7130A96097066127391923616B95EB7E3D70CAED613BAE4F2D65E6AB1F81D63745FCF A57A9BC5788BD1288607539A0EB5D7C139FCAC70436ABE12B7D57C1D915C3AE1575CC7EEDC26 297231B8A510CEECD3F0B291782BB1C342BD44219F004AC2F1A869F1448354BE54DD59CC8CC8 DEB38E3B8F4899845DA13CCB707CC10D715B01CF3D7D3BD1246A449F90E96D40BC79F879B7AF 43B7A09D9DD4884F7563910E4CDA099284CF094D1D0246583B01F1E687F0A365B463E7C7B4F3 70E924900712B02B20792D0DB404E08ED5ABBCA0F1F447292857A96F3F73CCCBC73F223C7FFB BC96E095E349CC72D2A37DC40D196FB55782050E83C7097617FE0D2C663D32A7F03460EBF9E1 904A12877EE0D4A4053BD5B673B3B65BDBAF76D7BE76E4F49A0C0912A87BF7BFEE30BC1E91A9 55729D55B0691D2E573B7CA693ADA3E865E87F4C48122AB163919CEDEEAB29E83020E4391D59 00AE2FF0F086AB51FEA2FBE72549C4CD3A674C8EEC28AF24EE314876F4ECB7F161CB9F55A2FD 8611C48F3E8396DF873D8EFD9141474A86B8906CC01736588436A3636933ED22C8B8D97611D6 26BA7667B33BBB0DDD4EE1FDA2E89A3F03A18516456C029B96AB181F945C6C81990E19A732E9 ADE2DC846D19386E874ECF08F33C48C812BD31E6056FB1ECB4049E6C66A5FC814A77709745E6 9A645627D45362E798F3336BD9996C42B37134CCBD6A4BBE9D938DAF6EC6240A4C4F4DBD4E68 1C77127B4D3DCBC7D770AF6FE20529F19FB6B332D0B6CC01B4E4B2ECFA05F2F768775B311574 F662C4487683A979D3A65E824E55EECBF4789664EE971B374F62F34918524BF9671A57C8A7BE A7518A1D5FD3B27A5D116A6B0F9E3A9E4CE276A5D103FE6A4FA0E28B6F68F5A4D89C032B298C B03ECBB2E1D94A4199C6255D93BB029AFAA00B7D6E658713FAF433F2777FA3A0AF6F898D88A4 D32FC6C3E0D8BFC67CA1AD7B9D6FEC4A2A99325D83CBF1F6165842FA8D033D7682EE635A5DC1 185DE824BDB8EA5BC7F3BC046E83527228F17459BA440F783D08F1DD156DC0BEE9E8EAB6F8B9 950C39DC03000F0488EA4071047ED99C550FB8AB843AA639B6289B7284EA8E69AC785AA88066 D9F3D4090D01878D960DEAE07C2A13B8015556AB50AEF2BB8FA969764D3CB40AD44D5A9E548D E2BD511FB8E38AD40181ED288C8FF88B04120295677DC6228939DFC33B7764BA80C32D4664B6 61D7407309CDDC605428A7F4CED1F86708466E0BA2F05D4DD7244A803341D0B0D86E48DECC59 25A75DC331472BBF13E3D024B85ECF438073303ABCA65B8309BC57E64AA97C244F6B89E82B17 F68D520E28182F101116F48A34E349107DCC6ADD53F2084CD42720E35946F520E56669BD5EAF BB02185D6EADF788D2AAF54D2E2C2ECACDFC7C91765BAF663BE838114B333687A1B7DBCD498C 8A28876426B354E6B5556EA862DE3C0305645B75235A32A2AD5DA5C9B9CA573D6C88A3CB4CA8 847F60F731454F264150DE6EFDB9BE02E6F5B868DEDC1E7C55F2C46F99F80AFE84260B4D94FC 5947754F7D98E96D932DD3D13E78ADF22B9A06360B38E7395B7E2339C07FEA445F16C2022C0E B8CEA6EF469AEFBA3A398FBF747F271C26E1870A86732E4D23B9BD9A564CAB079620105583FA E5EEDA2B5395E39DAA46FE5865D29ECDBCAB4D5FFF236CA8834777B0D1CD347DEEA5EFA2F387 006125E46AF358867E7CCA258AD4A5222373749041225381D44BDB3BFB3661FC5CB3EF365444 B2D19559411E3861C3468AD08A3330D842F16439E1C7CC62F639EACE059BAD656B292C9D8C3F F72FB53CBFC7F942A57C78A9B4EE3C531413D57C2EBAABF4F32956626AFCE2BA1F7FECF1D36B B77BFA4DEC303C0F3B0B011BF3A079A32DE973D5198F82771ABE8017F9D0D40473B996CFAD73 A36D4DC52BB211880E1924CF30E191C1BBA6FE59F54E0F0DC2471BF45830ECD99893A96E136B 1A45EC4EA86E357A5A8BB49B2161AC9A7472454D5BF9748F34177036D448D14BE4171F0B81DA E7008F0C3ED828FEB647F0D06661ECD3997B3D87648CA02D3B6BC5AF94CBCFA12EA2B41DDE42 B61DA7C83CD97B66C7C0EE10EF0A4EC5E063A24B5AE434C55753E6A8245A0F745669801755DE 324CE91D1CEE35E5B44CA4D6CE8DC88E15057A20B14035DB0B84B4E9D938F68236992C1A5F3F 7620D04972807F8C4FBB3A610B5E3C5295E2A34C14504E2DD400019A770A8F28344B981DC493 976B115228E575B89406EAEB7FAE63933FD79FD29A1A489DC4B5C516F09830CF7DF23889ED50 2457176F21D1D3D192EC42A5C39E7D301D4BD47CD9B56191C5CB0D1923AE941B336451EC95B9 519326AC3014798A56C22A9CB24FDDC6C46184F14B6068854D0FDA7192F97F7B783B7F51053B 3DCFF411F4C965649F7E61880B194037C6C69CB15907E7989F4188B1B1FA92CCB2EC1F43DD09 6B3B1D991DE5882F43AF1E023F2A4437F684757EAFAA011EE65F1D9507E79C44873366253EB7 84CDE128401BCFFCCCFC56DC8900376552F45397EF8F5D40D5D1BEE737C6C307A475819A5D33 7F4B02BF28461EA571CDD79F39F9491B37108525EC550E9D8A90AE63D56A1A733CCA38407505 C1A7690C67529EF6E51E117ED62274135F8744241CF456F827E15D512E78DFF679A117FCD7EB 45D7818BFE675607F002E8902B6A179B4210296EB19A6B5BC646371784FF5137220B6FB81DE4 5FCD8901A4A0FCEBFCED40F456F6F09D59C66B0BDE0EDFF2070D64B1EEEAB48C1885A939463C 4ED7E10D194A31F9859D58F160C881C7E7679052EF3D0BD0037088C5BE74CF9CD8B441655AC4 C21C063D5CF157E63D154E2A3C0FA0A1B796B7EE86207252EAB2A8F6BCED4901CFD178EF5B0C BF5EE7CD9270AD1B1055025C14AAA045A9C2D6F01A9AA133870EFE0A7FC63104EC2B4AFBC027 7013E787E82B9581B38E70F585F4F2E01E4E7804ABE534F97D8F92C460A609492ABAE7D236E2 70CA04C2E5ADAEC2BFF1F219208B2F8BF5CFB5F13EE94D3B9A601DCC6D9AB03EF624DDF287A3 A950856F44B3A31E54D64468BF8BF92F4432937DE368FD31D7A2E0710CAAB3D479B52105E910 787A4C6A97C11496550971442CD159755924C31ABDCEA68A874A9C6529DB2563BE8880576C07 7C4C5A20262C89FF4391ABB2DFCF24500708D191BDE0FE49FF456AF3D8355E56B0729BFDEC11 884ECCC7CC061B44F48766D6C2F31793A5898A8F5900587995A2A19FF4619131F5E665C98C19 1C2D6F9511DA129C471823E78138C038B17314B37FED7AD3190C938F040BA89E65EA6DF47460 6138937EB395AFFD6CCB55FC0371F8BA2650CF2846015A912D67A848D29B06563A76A65B5CDD EF34D1B76DDDB801B3CC0B910B8487BE26DAC3695DDDEFDED0347228D046AE30B64637C3DB66 35E697493A0E72AE1C2CFC611BB42F9138F608DB7DE51CDE8520CAEBBEB05A29F7578395CBBA 7B01DCF6AE7664EEA3DC1554A62028DBB478A18F6EB6EC084917427CF6D40689468406C923BE 93E0A8DFC250DE798B7211E91855FF7CD3DFDC9D0F67E52DF1AC3C2020B593C77E8A5E6FC3D5 7AF2957B4F876A90A9493941F316AC9C1CD05F73C1301537574A7EF78D73D23C31C1D4689387 A2D4396185442858A745B98D81F2580586C88D6CF54AEE1517549241B59292C8DA1F6FAFC3F6 1F2E82315ECF37E5E8306F4FD0FB4B4D0BBDEDD2BA55ACA3EA3EB02705571DBCDF339F326842 0DA8A59DDBF5CF721D9BAC5A1BE8CB3C0B4FF98D6B15A2DF24215EF121CC06F4700F2609C817 C7C4A0659AEF7C646DDF125E9ACE18348DA6770D3DFA3B9486D9971834A7EA6881368A9612F5 293601FAE200974434D1C24354AC8E9335D5DCFC27D447CCAE4B0923CF15178484B24C944FBD 847A64B146D0F77DEB7665247E855C600237B1E311FAAAB4E80A2B8058F6F26054D111E94142 1A2A143F3C4106A506F844DCB8EEEE5ABB05C2D0B4563C1D1080B42EC330D3DEBE87B65D9FE0 A684FB5D125F7EC7ADD81FA8D82E938BD2AD25E1DF6E473BFD81659317C91BD2256FB4164888 73DD9D67CA6D52BD2C5524903C68989C3F5132F029EF0A078B8C2DB830186A2DC9CC47B9E6AD 6AAC42FC7A12BF5FB5386C558A73DD4AD02D7DD4FDAB2152B138326D968EF837B79A3BA3C0FC A3A629D8143DD8B974F8326851AFE08BAEC65344751A2B076D71EF4F49148E6FC9F3CD520645 604726239FCB202117EE1CAA906E37AD6CADB6AB92B1D31D277FA27F6930ACB68D128CD0AD70 60C4960C4B409664C8580F1C5F3B93E673A74B8094284837117A644F0CA9398FDAE7CBB29DB6 AAD38CE5CDF855E84B3794DEB9362E1DAFFF74ED1E87561A4D33A7B6C93D18F231ED180B0D11 2D789C9E7B35B31EEF4D5FE50329D6AE3E9324DCD038EDF01F1B10E249CE33E8BC8E77E84483 96FB9B74B316EE1A78F2463AF742CC468215923BFC5477A74A353A3CB7286AF8D782111B09CC 436ED7E7126E5C70122E81142DA5F1056694F2CE5D5706C6C3DD6384CC42563E5BEA094392D2 876486F313B8409A2A03CE6718B7F5A58A6BDC7D7E3967D6F7D2F2A1652D578C0C43438B67F2 E67AFCEFE2F1A031330A1337D7442AA8D15A4B1B0DDF56AE3477599A1C04370BB06C5075A9CD D5D9A6BD26B3901F46D90B45098E5940B44BD1485840CB585B8B8BA7CD45625803FC1420C850 F434E84DF2CDB1C6E2B48716DC287BDBDE64CF54C9EF6C3DF4BC3452798A72DF4C2AEA80415C 9521648EBE5B65ED763B5A393AAAAC1227C1E017DF5FF4F2428423373BD6D5FD39D90599D30F 8D39740D6255FB22ADECA70C5EC3A8F87A59EF93EBE91BFD0C9AA2BEE6B3748B3914752F0E5A 34D2624FAABCD7EAE3D4051B088C9AE1105B541DC62EEBFB0161D05818A73DE9606A3BE82B2A 37D1F7F22CA33F57AA00A40F3189FB57BB46658710E278833C08F3C5D428BCA99ED499E1B3AE 16892C9ABAAF45E29C7036D1B0EF9F17FC51399EE7E7BD85EC424EC4AC17275D980FFD2EB1BB 92E78B2B38868AE908740E0CC26F414334CEF4E8CF5222F46E1AA40E0032E59FFCBB395B4ECA 2573730D1965B2D4939F24A154B6E44334BC0C465360BC2827B14E03E0F428DF065E9F36D256 E9A76F41C0F81747DE63134EFC9CEE6DDFF528FD0FE979237FDDA7782127B2A44B2F97A2611E FB1B03BC3846CC19C86330F9D2B4B557D47B5367D597E4964257C0109A26DEB44CCA07186DF2 D26769BBCD6BC499B3717D6DEC05675016943C69EF60BE9E2A004340202288D22D6476A05A27 FFB9A4C7A2AB606619ADF733C05C38C80B1E2300CF34A1E32213B83735EF20991D4C487472B0 571AF8F33EAC2B12E0F302C63371A42F1F27DF2027211D6ED6EF86766E35151B67AAABBA4B46 9F5F2164CECB46FB0866EEA5480B615D6F9BEC31CFC9A898148363C039BA8DD87FE65F1F9C8F 754A1D38B643BDED590D7E4B45DA77B64FDC835CB412C5CBA906DC46A7C9D3584B4EA5F7701F 257DF04B12274B3833957D2869D52433EBD119E69278D93D7423C0AC9AF9DE81B6CB125C02E5 723C495492060D6CC6B4BCBA6033601A6BB3131A474BB29FF433A1F3FA9EDADAB29F591F029F ECBFC5CBD578BF738D57F8AC962C6C4196FECD4CCE3B8679A2B805E736ED48F01E027151421D 1AC18D5473F299FD612542DF45DF5E8CDE582D236BA5A3A7554C7111BD2D9AE4BFD5D53C025B BB737716686C68645C01327F7E91AAAC5FB9B31EC344CD1BE4427C612F3E397C8C9756C7B30C D4A31FFC6EA5C0BBB2453D2FC5AF8CECC5BF27F3D22E919E9B4C70BDE1E55A39461821B30266 B8DD029B63683997CE276A28EB79E52DB38E3E00FC6C9F0C98A2ADE2A3FCCF651329F33E754A A2637EE13D8F0275BD9E3670E9B6DF5E5C7B60FF2E9BC284895179A6B54A6501B09C90CE1F53 7B181DB63CFA3502B27699C0FA32BFAEF33560EAF17035A22B24AD1A92204835506F9AB0636C 7E1C4B9BDE7B1E3C85A6746574082D5A66DD35BF0925B91BC10F973B607D990EA83AFE2B43D0 D12B61D5246A4B2E6399C626A2215C6B477B33355DB9977D26F0F4E0E750EFD66855852780E4 70DAE19BE56CCAD5DA484E8A1405860F582219BD238F18084A13DBA3BB6673190846660FD16F 243A0188B6626FBE383F47C9D115AC75810B9FC34F56F4B223D6ECEC3CC04A64D56CC48029DB AD5CB5723F037904AA357A377635B0693F08BE60F7AE5E4825C939A53D481553C1E5A5D57DF6 073D9E94E402AEC39387B6534B10D27E16A85F20F20D17627EE9CFBF60CE0B42C6472C7A21ED 5FB251748D454C7B7FC51C447C6AEE85E84FD3112EAFB348EC75D99D8FE3F1942C261D1D8FE2 1CF2D4A7350F05B983594E1F47BE21E1BA9A263273ED14B9161B494D50B9B9EB5FFBDFB088CC 1CFE9A639A8E405BED650531A96D1C3313617FE5E0DAB14A2E3E95CD4A0B018A08AFFF8C5E0B 9728642B9BB9905689CC6FEBD1072CC9881DB5BD7F102BD4CEAC2D861F3AEF8F1E24DEB48A0D E5C10011828BF7F0EFDA8992F6EC5C053F050790739D0D9D04272FE9FAC41B86562075AB2030 C9329A89224DE27FA74F61FD49D8CF7F13F0A5E69600E075A6090AECB2DB740A6507AA28A7F1 57B20558FFA64A4DE9DEC8F877EB9DF61ECE54E3281AE89C207005EA3C9F5E64F2966BAE9DB2 21365367B95AD4107A842FA8AEDA660FE530D0B37E5B8E46A2956E7DAF0A5231E33FB6D96395 CFC427B7F6866C1730BD33BF55A4C43A769585D54699B5B956751B6E441ADD82A2E5ABD2B9D3 3608E9333F408B931E77D48258415A789435EAFB9A164E651162F587565CC912731A5F840D03 9CB7EA0D281A34BBAB93238A449D8E8DDCF9B36DF3D8DD2DFDC5278B98F0BC3E070E3C354A3A 39F9A97A92397D6D0F618F522A600035529518D6D90420A8D79AA2AA712CADAFBF5DCAB8E183 D4AB84232717D60DA8C9711DD697F2F46A2223DC3E48008DCFC18618C35D237FC2D7A84F709F D570BAD4BA6D5BB74835E3540746B0535F04EAC2EF06A74134742AC32E0C4D2A726EB4155C23 3275C7348BBA01064F695ADFC933B502006D654C2B21213918E177D3E4751908A3A6FEB3E612 268DBF27A6C253738D34396F50EE834F075AA4AEF14FF3A3BD5CB25DF06253212F75ABFC9BDF 7F480D66719C3A5619DABBE3EAD77F6AD80A6B7A6D83AF722BACC170293F9A5E51BF9B4152E6 4DA40806AF4417E4FD9308A4D8EA2645EFAA35B30A6214DCAA83E2F531DBB02AFF7015EA1149 A333CD619B7B614BA3B5069ACFD80C2D4DD5D19BAD17C3AC5FCDA1818719A9CAD9913E187027 7B6383290E27702BD87E10AB54B531B0A7662398585F7B67CFA1EB1E252E5C477025D77AD4D9 D7D943C3B5F6127EF5BF7F422CA9AF4A648E4213E1D6A9B6F02AE5119F91385B93F00C438A27 ABA9D0D1E52AF1CAC6A56C9E2FE7D5D37B9EFC4BAC853C23D07531F8F7879313247F9A978468 5048DB25AF1CC60602089DBA16F25E9AB0855D83BA874C00E28ED5633EB234EA457467BFC887 27A17C570FFB595ED41AA2EAD4D68703D0D70EF899E43E3ABFAF95447349DC61EE1F070E8F5F 580D691D80913A1DE2EED591859D684670E5CB9E3CD6354DBB51F66B5DB8469364E709033D02 C5F13179E5400C71A9A82FD4FDCB5DC94E53B116506B41EBA9B34741D3B5BAC7468FC68527A1 E51C12A45DC6A61C55B21CD9F8C3FCDBCD037044833BEF5B8EFEAE27A1C406DF2DF775BDBA2B 055C86BDD754577C83632A70D63023D3A80ACFCF501D3407CD7B880D7BF5C9A6EF55F643AEFC 6306BD9080505AB7395F809BA5BDC8CF5BF56BFF4D2F2DA56425FE88211CA111426425D4BD5D 1D606C1377C2EB7014A6EC0392D74A059E5CA21BB6C505DF776AAC0704488DADC008DC89843F 73806262ECB38180595CEAFC29311113C41E8FEC8A6BC75A4CD616A02607B1B0C3F4C2423C98 F45B76ABB69CA4E43F37E2F3CBE32A0947B8FABB8664C0070D72B4A464381DCBAF741319E659 7D5E648BA2A11F5B7CE3A45A83E094A1537E7E7DE0150210A675EA77F9B563423F71B2221AD3 FFF529649172CCE6F6493AFA7D2FBCC812C269309C426E8570C6992255BB8CA8157C9F2958E4 C63FC2CDCCA1A3EC1AF935CC9C35B71CF779E87B51A16DC602BFDB4C9CA1653E1BD1AA6DACB8 C038276107AD61D6E33D65B6B98E28091D4568B49DEDB9E9023F2977B4FE952FECCB1ADE607E 3C60D74DE8662C1A08C6C4F6A8E50F91C62D104A7812DFC67EAADB90E674686585680A0F2EB9 8CC92A793F13DF552E6C695623CD5F161A15807FB396DE2C4B32E0E168D765EC0AC448089A24 5B65FEE72EB77E1593EF910B1750BD29BD0DCF35890311254BE990D9E4B558753B34600C67F2 6B24E701287462CF8A7CCBDA97CFE5060A8C36F8CFFC8A50555C576B443D6556E14541F7C5EF 1B6E11CE520946F91918E10E90BA750FAEB158A82317039AB53ABFBE65B0D3989FE4128FCC22 124E162D559F03AB07E2FF289087B48582428CB9B124BAEF00A16D4678C0708BB70F692F8ECD 4D417B8DA0371716D3B5939D56D8AEC084CC07D0FF21A5F69C1EFCCE09FEE5466D7944B1598A 8152EA86FD11F3FD1FFC2D0BE04EC6C36CFC39CD29DF6F32E4A030548333EC9C9ED69471A989 368488364FA7C8D83992D35E01868114852B9BC5E66B43BDA19F82102261426FFA730C327C16 A92C2D840BC951183A666C4761B2383EA8698B5740671142E07B5161B7988D39239AA04934A1 928EE775D311C59F12D3BEEF3CE7EC9BF6DBC9DBBFFA124AD23568747DEE4AFE3310D19FD2F0 31D782E4FC8980D315FED5BE69715AE90F45A26D5DEF008316DB5237B6254EC881F5F42B22A7 70A9998430DFC54E223E1CB1F2C3CC21CC968C3A9CAD2F935699129A0B05E76D7850FA8F630A 6A76B6B428F022C17F7E72A0AD107F044CE76574ECDE1F674DEB9DFCFA5C860F199490958B06 18F599CFDAC6B2FC5040C32D1632428D250F97A5E5C686C2767808C71A3D6E86F619D651EE5F BEE3F6EBB220CF2E34E3D0B7B9EC38F2B0FC78085867579D98DFF2DEE6ED400B19E34237FCD7 5BCB901F2E6A3DE5D721A239BFB003CB4F5C58DE63E8F7F8A6647C06275236ACB4C1199EF950 EE7CC5FA7B0CBD4852B3062C1CB39137C29289A42CBAD2BEFB0116F948EFA5637F75C0325848 86F85008300C3B12E01D9B15E5EFF2D44FBB3C6FF28694298FD8F8DFA6817138DD586FA00D0A D7EBF5CD8A63949B54AC4D90FC8863490561EACA5207259A76E3EF1890A2B59099C14BD58F42 CF224C34F1305F4E30E9F12E7AF0519E80938035A2728D433D75211C73B9740EBA4926B9676D 874E41953C4E59A48579D3ACC872952A65ADE2ABEDD6128CE9C40B058D126C68EA0D40B0A081 CE1604CDD5EEA12AC901CC12AF8771E39B66487A9C94B35D882D46C5F3C43BE6AF8654CB09EA 74A24A58CBFF5A25EBF7D98E08DB4CAE7D71F112503FE689A27D75DE94B94D7F0A8F6F4F9CC8 29C1A441EBF4A22A85FF6479AFBB1A4252AFD7FABA9B1CAF518F1A2C67392B44FF9E173A6621 8C1DA8CED86B17861052E3F9B758D06CF8864B7B8B7B55322A5E50629229FB515754697C0269 41F7AAA8C6D0AD6682440A4908BDFF03C4D413C3A7353F6C9275788610F8C8340EA671506F17 4EC79EB0EBEC7BE8E62470601B32ABAC9AA3E2678367063A57CD950349635726DB14DE55B488 8E481DE009CCE2676EBC510CD94A12ACDA187D096ED6417AA1E8B781299CED175C4243EE8D51 E1AC2382FFCBA41F49D19F60761052E59B75A2D0D4CD2EA45B1859CF449B7DB95FA7311F52EC 28A8D028D2343A958DD54500756D2CC13BA81E72B69F01DBFB636C9299A2F0D3A147740AED1F D12C59B2D7D8F0761A86B140D3545F38A21A8D6205A57CB7160FD7C5971266FB21A518CFC331 39AFB70DA7485350EE8FB0134762604617AF0ED255F06616DE76569F48A2474D7F56A1829DF3 0034F290B30E3F2B34C433C11C1DBA265059490AD1704DA42526125EB03298F86C56495FF67E 63B06416A7B4FA2C2D086FB7E9A7EC218DE891051219E566566FC1B9C16EDE9FD2293183CD29 16E3572B0D770356EB2BDD7FD92794C270D364D12D14DB02C65A6E6D636C8DC0150372FAA09E 488E28525048EE8A866FE1ECC868F6059597225BB1C588A12349996BFAD2F6D0131F04185E1E FD125A2B4C4B8F2C32B6A307874B0D94DAA68CCBBF71D8427FBE1ACC6B3B279A52AA66CD6F5A 5B1E3DE70523ABA543F44074A6491ACEFBC6DAC617F805F99CFDC01BB5DD8500265878FEB2D4 E75BC616D30F63D11EBAAB94EA65A4BF64A484210A08C0604BF0BC0275899F5AF6D217B914F6 AC9AA108F921309F9580701530CA11E8B5AF77D22767151FC64BE8AA6E4EA7B595E7AD726ADF A2872D007EBBC41EDB3380CED9743A88424A665E37B941DE405DB5BDFCF89D4F8BFA6A636C97 3254709C81BC54570266EE5FC66FE4717CCBCA5CC309755E8AA8915E16E4C3D032E2D295A2E3 9F81AA5E712A29DF3D6F1DA12B51D414E60FFDA3499CBB74847210196C06FDC32A42E3417319 8ED7A9EEE1CB52E97C221C79D0BE506C6C8B493EADA00E172112B0B525E9EBE24A081518432A F7BE557EF7F37D1CC2DF1E86AF4EF353E8DFD731EEA986E5C203B343320BC3D35F4FA4423FBF CBEEB1BC75F27A40F4D9F5F5282828E9545EF54F5BDED9915385E400BA937594325973069070 71E72887D2C648989B7A4183FA3E750FECF13B04FDB5FFADA6DAC6DEFDF7CBEEA85EB154EBAC F8758A185B3EDE6F3BCC0CCF0A878DEC6D1121198361FEBE57819539E575A6E0CD675A3535A1 A245CCE669B1C31D3E87998A956EE116369CAB04EF8506ACF9E8BD2E4E43BEBDC9A067C4F1AD A019503E9725E1C44BDCC4BE132F5BA29B56B7E281400019A9122D02D49C768346D1B7E30BDE 6E184E0107507C10C132939A052E6084B66B3A30B6F4E855D489F12C9AFCE7714E68869683A5 C74A5697CF1B4D4B9BFF4E9098E98FBBA712E4E717EBFE6BA439CECD1A99F6C372D264A4A255 C3B99A41A2F04DFF796C9EECCC20AD43B5002E8E3CFD9F09831F4F02F9327E23F291C755D3A6 E57D012F519FA46A63B32FF9A98C3640517D077EE1A472CD000A80467B28027AFFBC9904D19C EBA6FAC4F1EA359AF2F3142FCBD6C28C1F2B2DDFB1D6799888DAADFFAA52EDFEEEDA38F3F94A 79C79507BDB7782C779374A9BF2B0CB7FC5A216CCE50B8446FE894E9419E3EC6F37817CFA6AD 52434F2415369128209778A9BB1A81EE08E4F0842BC8CE8890636D6144E9BBB416344D9DEA5E 65719B332F66F9CFEDA829FC0AEF7919253ED138C92C0FF7BA23BA9EE1841A4491ECC983B1C1 162B30B75F8DB608CD41FB8FA402AC96CE57D6E27060CB88BCB47FFF9132B63814964E162EDC F06A2F9452EEE25E1DD7340FBB273F1759BF9FAA1B2D252563A97ADFB26412C605C2C87F5725 753497293A53FE3B708D2394E19BC998AAE5580A62BA5924A00C90EEF883A69C3310C64E52BB C41B70B89DFEEF80B73556FAD1D947A079E8D0BE5BBDBBCC689E6C379F5F6430E44D937696CF 99C6F3A226E27E567D945BAB4997BA2A7C04FE4D9C2CA4691B687B2EABE5188E302493326FAB C6B5876541C4666A26B3B65C228AADCAC6BC98760F3D3735B89B2A2E3D43FC4CF6ACD11C96FC 6C3610ABDAAEB5FD4C7FEC50474BEAF06684A49B6B245956FC2936A68551DF931353C2939326 36FDF56F0DA797EC113DCCFF2E3409557028151EEF5AC29077BB032800F10E47F79CCA5C6F5D D75FA56638FA4E59A085532C7D830808B122DCA20D9FE537A04F5279E6F96AF0F0D180EC5243 0438E8CD1A7C79CA9340C0639367FB2AF768F36637D67F7DC6C71B14DB7A35C567A66E460EC7 0B91357D13AC281D18617A861AC04A6B73608467999B1DB7D06A52832482FB4153D95E6AD9A9 885137C837BCB0D9F2AF4BBAD66C9AD04265A9BFD47DF89D6E2E990DA21CAA3883B815F541A5 9FCCD6DC47830E5E32AC631EB16E1784D94F5A31523D31509B4FDA3F13CB6D0535C7B9D5FC50 EAE72B74C5596E271CFDFACCCBB66735C67C32560667A2AF34EC48F09C574B30D4510E8BEF41 E6EC0DF52C2B26344B9EB25501BC1207C24B8844DB1852366A48A991C345A8B1484A19E7AC52 BF541D2F95EFC749AAEB3859E9030FB12EA35ECE6739FFDFF7A6809848FE1C04A6046CADB0A1 2F541366B97451BB8D3AE48E96B7E97B5BBE5ABA1B460820B24115A03DC01721F7A423650DAC 1E6C305FA5178FCAB92386687B1D1ED0B07ABE6E80A7A46143C05D8A9C8976FE3D1761C05766 12CB9AACB370ABB8352694514954D538CA0F19197EBB5A93A2BB940FC8B5256B183C769D382F 61B0AF9C9A98FDE7BA8BF56C4F4882E0209FE14108BBBECBB8338A768692CE2499F2B612B6DE 3D617D16B5AA3BF42ED95A2B2BBC438461FF8136420417E2CD2B1A8FF07F1FFE31A9DC926D59 B968CDA1E6946260224CB22E598B1452AD408C56E8D085F90404DEE4FC07062C72BB12564162 33385EEB99F2B67C5A0D6B1044D29D972567AB47FC55BC918A704DDC2F30F12A148E660CB724 0A412C6FCDA1A34B7B8AC1025F384C41CBD2773FA11A868349DB8EB97AB311220261493A57E2 D48A2492A23F0DD6DE1F1A3D84F4F665EED8A7163C7A339D669ABE07A854E4B614C126CFB10A E94E76E20C0B855AF9E96C46BE1DCEDAD02CA27692F792AD423135E4BB034395C71C6A87BB23 A549D63823FA513320AA22C24CB1EB499F150BE279199BDBE09FA0E5D2B0394FED0CD68E13AB B329304424D14D1BF7C2DB7D5D78F7A857FF6FE7A9E121D3BC71D3E178779FEDB2F966A92EEB 6CEAE29A21461DA66535E418972DA8337358AC715E50562508CD7330FFB465FCB613BF5AFEAA 2D2E13CEF53DCCFEC3D7029CE1088E73174A9D226E174AC7A80EAF60CFADD4BC51F934F794BF 24AEED2FDA5486D883BD597EC42D4201B49BA0F89401129B0094188B698D09B1E82E2898E1E1 3FAFDE14F40E3F7B8E5CC25FBC45F123F48FA0D0A7846D4F94C27CD4635C8EB988C92C03F824 FC4C0E7DF36F0E01D36B4349FEAF75EB5D8C23E513E65F247F0CB86709944007B62313F4BFD4 E3499B67CD55A3DE0A1E030B74BC3A97B7D9AF2EDFA06A41BF4BBBA292BFB500255247026812 4B13EF6135E45E213C46AB4BC40EC5F57FDFFC62233A1D294EF1A0984F4399C925B42A2F597A 64044943D0DC84247E98D231C2D35986C58A0C62006C1E4C0D6FDC531BDF7FFF5183DF316D61 185BF17326E745C5B533E0B7A51433FF5691D84DF17AFEBF80303F9D5F05C797B3E767D788A3 BDD1191D7A6D576FE079784263E782CC6B284AE0D59EA5D60842BF0A7F55CE33067076597578 60AB8F0609E46E9B4036DDD034F5AB39D1B0A639BC8BD55FD4C800CF360014D16BFD3828ECBF 97409AF47EA32B61F162BFB3C58DCE3039692C566BF70B2A8B6F2CED7479DB7C0FE286EAE554 B601025D57AA3F26F1F6E85D17FA279899FB61BE82B59F6C70E0ACC2E600652304FFEF3E6771 C348E2C088F7837A7CF37CD1C74CF0B78299D26B5EC1AE192471FBD996FA3FFE6169087957C9 50B70C7BD174722FA2EBB27F6542F526D3D0842F17449389F3E6CE0B5712CDC5B1CEAE6C7776 0B8B41E8444FB992928844B224F4FFBE0A4EB44027E0A75E74DFADFAAF1566F957C1999F768C AC8A735F17DF653F58BB9BA4AF0985A0CB32FABBE787B9A133B8AE7D68C1B41FD3E138DD26AC 083DFE79A8C879256E5BBBD14E7B31478E3DE8ABA60893ED06F2C6479445644E795F46A9C95F 308867AFE83D0CB1DDA4C68E8634DA9E30694ACE6EA93AF1D1E9670616A7AD444F9B6CE89978 062B81346D81DC0C058F3740FBD591408A8A4F6EEBAFB5D7772FEE8F467B83713448DBDDB5D0 90E6481BBD8636BA2FD30B79E9AAE4A98E673094FA6A597A8F0DF0B74C9BB69AF42F5FD4DB7A 0468409A39EA5CF8D4882B9606E881A59A729EECF60339D5225090157843A69CEE675AA56785 8B49FAA306D8A8D6BD630D7E38C54E88CCD548F96B22E93F780CCC6FBAD75976AA2D966FD300 429B03F166E241C575A0469C17E427ED8502CE6A49A8CE1AFA36D2BB914A2E0F2BE4B2794D3A E15C8E5914B36BF9880B575D65B86C1D620B3BD6F9587EEB090CCF1AC48C73930D76614BDB37 BE7FF457AD7E07D812D10C2E425334E0E66F83F024F2FBC764F7E9C9D07A35EB9297BC7AA519 14BAA5055D2034DDC15AEC3EAC9311D99A0B9DA9DF9642FC4D5CE51ACCFF41402B227B0528A3 4B6FBBB1F9AFDCE1706BEACC566F054B3BFEF75D735D5C92656AA780E9F78D3D67933C74BB7B 7E1A3BA96BC716BEFB31099771D1348611184BF76E78E0B75655C18C42DFD2B39F3377633FF4 CBE887574EC8AF654E91294504A59D04417F01E8C6C0EC71802D74F55020B6D15AD0333F5F50 4EAEE5C47BDA9E373C09581B8DE96B4E6FDC76A8DD8F7B4FDF62DC852973B828F2F4FCD97C90 17EDC5E0A6BDF87511A896327E39267E86C851C08317E13B413C7FA7C4B180244D1A26524368 621142189D70F26DCE33CE009EFCC33BC35B211C67C9FFD68DE3AFDE61BF54A485312D6D66E1 6BA9022B97C73D77ED530E606F54ABE858F2210821328018168BC89B5D1F0EFA0C02E4C2CA7C C4B2BB366131DDC427504AD454F6E8A314D9A5A4994F21607A2991083331F559B29930DDF0E7 CC86A2DA421AB5E26341F26B5C9B9F1772F0B244B62C4686A2813DE622267588C0E5DB3CB458 D2C490768FD6A0AD83DF55504C3E791554FA56A474C44A26256BA539416ED3BDB54EDC8A3AC8 61CE565A334ABC80B8DB73490595E01986B45B0D82693C41DA5BFAF12B9EFEE509F25EC7678C C1E4EF735FFEF5158E0AB72DC3939E4F361ECA40DA40368D5516A55444957866029259BC233F C3F000F54CA33E2B82C999674B22725990A9BA8DDDA889F8DCA18A64EE31C4C82DB2BD653E55 5B147536E03C8D550CCDAE2E891D81772E10A1FC43DF9A600E025E028704D40AAF27750C81D3 F0A8E2BA60FAA0F3F4F5BD7F66C690944EA6254A33DF2A503715510772F9D8822EB0DCD03FF9 2500374920E0AB941100569ECC2C26C393DD56EE48BC914794696A4211212E8A77B1A653EE24 A02BFC350E7E8577FFA1FF9F11B587E61C08EAE8D88B073B780F5FC2FA97F6B5DC9F7439D84D 3ECC2C67B8100EAB30D6CD8F07F2F2426749A47C7EE77541FB716463F8703B6BCB80F5BD066E 94CA265473CF95D4ACEE36D05CB22C83DCC8B27C7B6BCDAB943C899937C29FE456D9D71B748F 1B57625597D7EF30813823DF79B8E368D864FFBB72251DF04F862AB1D808E25B506804443959 3BC6A7DABE86E0793C0186D7DF54BBC6012FDE7E30C4FE5DC9FAC9171D62CE801C5B77540930 F5604850AEB85A13E06620150AA55137F66E6DFC97EB36A16A9311A97039EFFBF3E5080760CC EB073475C1E9B07E1E23FE1F65ADD9F68EAE159984DC1BE07365EA94A90E2305A90D33C46245 6CB031BB031F0D34B570F42507560AB26AE4B64772CDFF3034681B7E3CC6B610FCAA65187436 00CD4889AC7551F101B927F16188792AA47EA95BB05E2EBE5C96E92CBD487106FBF63CC9DF2D D0E0C2339402875887CBF2DFB17C3E32E1DA3EABEEA3EE9CB461A7898A1AFE29609E67AD6DD5 7C91964296FBC5F09F4DB2C8315B1F7D9D324A8F745BDFE3EC7903279D78DE6E129D81CFFC2E 674714666791C5A6DA8484577531BED634A6F7EA50448E68D959F743279B9A80C8885CFEE79F 47DF6B9196F79FA4383B8681ED4754F901BD36C5A63FB1582857254DF71516F53D04F8617898 1F3E9D10558C4C7E613754D3CF26957E0AEE795F9DEE25EFA913D3623D98C1F96E0AF34F67B4 306BF5F593A96ED074700673DBECDC9B2BB27558525BA7544029DD9DB5828C6D8E563B5BE801 3E96131B9E2B11D67DAF49A1ADFAE1FC536F4DEC7C75DCBE0D6741697FCFB8EC8D2D3DC85FBE 8225A86EAB86652E0D32A00E59985E495D975EFF48812495EFD19DD9CCD93141D361B0D1DEE4 8ADC0611D1DE2E8EECD62FE9A162542BCAD738167AC417A156212A8229EF17605EE9A3E2AF8B 5795784CB576C5D2C8688A849E2F04B7A2310958CEF0380AB87E39F1D0270E002A11B97F866E 77C1CF7AAFAE209A57AD12DB90DB20026D92F123F3293ECA4AB07B86CE5A9EE650D3D1491156 A6199132B271607782E30F03E4A333E5E0960F798EAA25418313DF13C5D4BB186C37DFBD0392 459885CAC59FE71D22B1BA70083CC6D81F800F1033FE0A250DAF09E03CDE1865FBA52D2AF2D1 FD4072AE40706C969C1BB778CC4EEB3FCF993DADCA323BA2C6B72FC9B2C4679B9868B19A7E58 40041BAA7629877B130A05D1594C855B4853E70C8A1D1F58A20438C39C1E3800FDBEA47EC323 831783457FB0BAF72C02F0EF8BECC7D5940CFDB008CD258C094980C358471A2C6102C83EAA60 5523C535EDF3A96E699AC6627C5DABBBEDC9D06FA6906A3E524C2103CAE0E2DB5F926A1FB5A9 ADEDF9AA8663B026115791B810FE0EF2CC1E1BE6E7FFF7DDDBD27CDA85A34B3548B2129A5DCD 9071BCF917D9C6BFAE79F41DF7FFD4303525FCEE0F8D47179ACF13FF109E748B83584AE2C8C5 7FE3392653DE7EC742918F68F86E4694A8C9C3115A9E459DC45557A492DAEBBC306B73DFBE5D 27DE382E17AB54A77475A79E38BBC97FA60C738C9B017BFA6AB85960F34632C6010E321668EF 6647698D00DA3407DE9599736E3106D8C30A13C63D8B447506768A6771A3C18C7028C1E28983 1DBADBDDC8BABF7F5D2FE992594CE0F01ED186A4226F8B312329D30431148743E29A1C4E81B8 DC2290CCCB1B1781A397D4510DD2D08C81862C66353CB95DC06C67F2D783F0826CE879CE8BB7 6C93F57A64CA5EF9A563470B1143DB3ABEF694645337284C1EED1B94A8EB67F62AF99CCF1263 EE69F09109AA7AAF5F39A9488C7F0A1B3B59CCCF641B0789305B3E27B6DBC105C385B06EEAB8 CF7BB5A6A514BD597A401590DD3D8DA4E0C291621D9F2D9964A408FF77025134020215A605D7 77D1E509789DDBB548DD22A7C5A0C9FC6F2B84F9B94067AFD956AFCA3DF219F51671692A7EB4 8B0E91741BA2D2F3F533AA458F7C373ED76A155C18094E372F8C4766C93C33B142C87068E00F 9CB93ABAE9291F33D1AF2560892C50A3EE480BC84C46DBAED662A4BD34774E36310D91BFC3ED B9BFF3D0061C5FB6207042680713CA4C272126A4D40352320CF87AA4C0AAB5B77E2B53792F62 6048BDB646480C5FDC25725FB6A11424D3F521D72730490ACD0DB15B91E94B11CDB8350BE714 1209FAFE5222129CA80113D1CAAFC9E5F84269080AD8ADD155BA2307F82D8DA59AF65A328A81 EEABA59183F6F12B9AD4EC9A10EF0732ED2F05A3BEE8C396B3663E993B02D145A5EE5F66E30E CEAD5A7FEBC39BF46EC8F6C4CF2B31129084A58664C4A4B413F99B831807561415A15E5EEC49 585CE724128F53C19786921430DD793960103153BC86F58C760132356E51BB62F093B97A4ECC 7DEDD70427F00B45C644C523EFE1597912C4D9F53FA7E8FC6C3608338BAA4637D6EF1EEE30D1 CFE8DF2545A07388D8376499566AEEA76CB191E8DB5FE05C9D91622F262BF5564ADC064A5B3C AA5569EC5233DE0A488CB544533FBAAF602CE67E0B09F9BBE7E0BADA637D26A7085E80BF5DF2 E06690306186F13A400B726A9BC0021A34BA050079520CBA61CC3D3C61DB0E5909C2FCC82E31 4DAEDD2228D3D4173163FAABFCCE8C4ED96829B0289799755C4484CBA8FEC61C3F53D2319010 62677888699BDB42672629733D4FB910C73B307E8DCB837F53346759455702F04A42CC42325C 29D16F4ADEC550CA0CF5C9B7EC60038D7F444883FEE1A93EE0673F67798AAA71AB3B1EDF95BA 0DFF0F45DC9D6E0588089553A091962BDB39B2D19B9395380DE4D8615F054AE7A1D8B26A16B3 A0611469ADA90C9A3818D08C89A7CA26B0CF98DEF23C8C123977F2087107A1550AC33C50F076 A30B84519EB46669EDA19728C6F4455D41DE791CAC6DEDA07A108670972C428438719F847BD6 FBA1CE8E7101E972A7D5924E749A2916FBED44BCDB2954510BA71142D7708B38DB6DF559823C AD34881594717BE8D205679137747AF78A8AFB389175B5826903CD5819726980A7981098B02B 2F4B47DCDFD89653538327E431B843B4FBE0F0703BC3E211BA7BBD965B0407E31946757D1009 BB2EFF7E611654857FC11756351C0E2732BC8B99B20EC5E520AC9CC638010215CD5D7AAC58C8 BC907B6010F6CB74396B7486C0906F9B879B67814A23FA9E89C79F2019A935125EBCFBC931BB 9EEAE79ED464065D458E49AA025660B1543B0588B97C0D755430EFB05154814F5FCF0E58F03D 3DCF0C01197A4D4B1D94B0357CFCC6B6D9BED2F84C084AC953B3B247B46706C71E8BD717B93D 602241B21096C3E6B271B758CC50F2657481ABFB0A80B54B0D2F0AC2B14D0F552815885B2EE6 399ED0A9A2D3C133305339D97E44CA08D52C9071B8F34D06B2DEAD4549C591719BEF6194DEBF 8E7064C18B15DF49A73FBD1B32C1F16413F462857A76345A462419B74DA65FFCFDA65075CF3C 6201C6710BECB92696653C0B927000B26F5289CA6FDEE0EC2C39945ADFEAAFE397907A92D266 EC4568635EC21FB10C18BB9FF8B975ECC778C77B7E8E66C9D508E23E136F7B1C2E6E03AAFF8C E77008005B13217B9293CE534416FBA358F1CD5CF26314E4E6880641D8B987DC504CD4F3E384 06E63B8EC62CDF13D0C739F60799AE269706761BDC78A9F80F726739DB2C211949BF1CB2F947 7E17227E18D43A875FE5ACE8446A887A14C77D01B5C9FF11C3AFCCD91C2411072632375C3F99 8343651BC7F583ABE03439CEBD67BBB3335B94193CB3CF36210C431A202B12EBD03D1AF9C6DB B1F255D8C101BC17E301B4D37C8EC7DA0F797767C6EA0166C74411F7A5D54B7E7AA4CD62C856 99F314E11014CEC46FD5BB0C0B69A397A60D4DFEDA87B095341DF659CE1BC3A151376C2E7BE1 1A548D84F0F5777FA0C07DF33068C2EDB144719CEE27D1F6DB1FD83F254BE273BBA9CC1FB51D B3ACA31D8BBE5AEA00F61C23BA566415E9A0E1ABC230F46E40065C0D9F2F7245C138149BE9FE 0FB69C0B945DC165176EDFFCABF56B9FAB33DFBE78966064DA91DB7706BB6C6F04AD34E042F4 C6FA48B0B9F96BF5CF68253F9AF738CF671AB6B553E23F34B6771E4BF150E6B6B0B170DD494A 8D1ACB6786CEF859F934CC7736A170BBA986EC19430D19B9F090ABADF9AC0943F36685966113 9C7645141E8A7A2DFE554F8397FB10064996783310500165171D8420D1ED8BCE593C42805A2F 9EFCB4B88D09AC7E6A4B23C21A84B94F823CB3AFE754E79B9C77D2C3E29D5D4BB0F29569875D 71D142362E1FAD2AD2186258D1DF52692311F53A608A276F70AAFAB6E301FC586B0F4C6D364B C2F1815FDEE94EEE51BB72236F3D4B64DCECE6C7B21176CC09E6904DCC1FBDAB59260507D488 5F24270FE2A6F133D47CC2AF2AB27637ECF40EF51D8CC1352EBA3EF27C745663350C4EE97B0C D24ED09A5BB618024436FAD4BC458A6B259BAE107DA6FDD814B646E95B1F39CA2C7E9EA5B156 A44FCF514EF96C5865DA6D96FA8876325A9F83B75C5D156ACDA42A69ACDAA7BB306A5807B013 38297F76D0CA3CA851F9178168CC5B1ED97E4723201DA85D59FA9E3EC837297AB2759B02F921 CA65072573A35A942DA915675DE04A02E5221B62D9EF635444A37E1686A816BC71F496678378 0A328F17D3F8D3754AD2606524C0FABD57F1D02676154BCE181F8B97CE2B0C0E0F06988F5AEB 5AA15E7B3A5F2080F7347D950D3B005E462336AAFF1504378DEF84AA51AA528C2CD232EF2382 63BFD3388D0FD290DC4558EAF24F56B0F74A674A3CB2E61A88F5F4E97CB9997B380B68572043 4CFC4362BA7B23C804C22793341388502F4AA4ADABE34DE967FCB82E12616A22067947F4CD26 AB2762ACE46046E73FAE30959005EB576A10FEAC6F307233BAC38DE2D70D037F56C0B0ECA2F3 A48D4C0CF69CAE3CE44B08E5B10D3F938131F5F5E6F4A9E211312B04709E73B246639938CDAC FE24396907B7C5677335988E9D6EA7BE4D7F6850AD924E44D85D494023EF0AF57918EA99A779 34F389A5EBCC42E26B85E47EF7BCC2375DF221BB5E0294E3FFA8A51838D9ED322FB0979FEB0D 26D4E36244F5B0557EF0101B5C3D6241A1EFAB943FD5ADE870AF75E24F25772BB65B26CA14A7 034C1F69CCD38DE4AC79A8D0311978A8134810437E5A04B3363F16D4EE6D23853BC1298853AA FD9C619279AB747475BD433D2186040A934A0F05B294D28FE45801A802DBD20AF0887B9B00BA 5C4D885643B7A645E990A49A8111E6ABDDBFF944070678E003591249551C1FD79B40795C8CE6 1F8FCF78D1BE0A44A2D32C199E46DF4A734206BD97A0954BB778C0BCA6EC76162FC4222AFEF0 4DB282A73412FFC5EF9BAB16CFFA50A8A259BA0FA1BABDA8BBDE95A321AB4196D58C12D8AF91 89EEDE485B3C951AFE3230189BADAF0652535CFEF04777F0C183489D90CADF9A6553473A18A9 A36EAE70ACD5E815C03E9964703BDDC7706FD7D14B668EA1176E438E49350DC8807A6E4EE528 33C6D110475AE6F96B6318A989B6BDC1D88D28C26606E3D71380CF186C2997E8194513D3F43F 9F570BF9C3CBF688060A12885355038E9754F89DBBD90C25FCC2922F11FF1934AAFB0EA11F8B DB6C3257D7BA0F8E2AC7365A9FC76D3029325506AE25D8DE203D295617F85EBFA351FBCD7956 11D6FDA7F3BF6E34DF41B13138ADAF0F570BEF6784FFB896388ECC95087E0B7F425B6758D8A5 98D41A87B3F0075508B708675C56726022F450D6DAA8B60134BAD5328A36424C609E99B31480 01DBC05881FD423B95EC9772B9AD22A992062736432C390F55D692C90AC64A1272F3414C537D FDEAF1BDBF157726C59083DD303A6E1DED50C6F5B94C61E81F9F138FD8AC67B673AB38E5CA16 6611C6726DECC1C0647D6188085056CB939E2B1D66E25BEBEAECE4B97DD342078BAB4867B7E3 CDBD2C68B9E7D88BE56D90573085C9DF10E10B19EBE83C8A1C41F58BE78B93040C928FED3B1E 98F354823619ECF7C5764F2D98E958A375A5F0CA5D884389DE854F91A766295B01FF8CDD420B D2A52A41A0759ECED87DEAE73D27A1DACB0D0F7E4658FB724BCCEFA08B0C3D5BDC9CDD6A9463 6F8B7B4EB66971E8C599D5F15BAFEB89258185E3E935C15CE57AA6CF4F2CF79BACD605747AC4 EB081FC98BBF61D2623350375B860155B90EE6A159DEDCF7A33604D7E83C50AE7804E9A43462 2239C5A7D891859D31CF7A37DF61BAB489D857E93D5C2C8CAEE4C61E7F4E3316DC35FF616189 7D5529EB2656ABC3367ADAC4EA3342C2EF308DA183C6F40402E231586A37198970612951B383 FBA8E8C375123429CEC97A52B455CA8B384913E1527E77EC48AE423B6BE28F3F8E0FE77F8D19 7BC6FE350D817C8858CE5BABB5A6BC1276F905BA942A1601784CE8E8ED96DDEEE65D9EDE4FC7 D5BC5BFF2FC3A966FD25961A430A063DF3D8766631774C9625F1CAC03C135B6B122D4B5F68C0 659B1B2CB634D067218E127A589F87FD1EC9715443A08284837ED2BBDDE3325B7EC288992F1B 5166EA175EFA6FDA164E8391DE99E4A88F43199C3DBD617667D6FCC2561A1642F45D76564EA5 B0E925BC960CFCA1194F67743B854899EF834404C8596279150CC61909F367EB17924CA9FCEF E89FCB940710E470A5E7C9CFEBBB8B8EBB2CA8CABD973EC4D8F32DF8A39E6ED4C520BF932FD6 7BA02EADA63CF55F33EC75216F75E29E2D6937379D61EFA2C7F83A187FF93E4F17A66CA3ECEB 26B9199E1915922667CD1793FD0842E6648FF80150D7A0A447F5FFA2B8C36507F7DECDE7EB99 2FEE6E9C8E32D9BD971771ED9D0B3E95190550058FF0E6F80576ECCE287AD895AD56DC8F78D1 9FD04ED854529719471333B1C313A002D8166BB91B2983E99A09812E9BEB52F5EDA7391DA5A2 FECE694761350B089DE41343F04DC45E1B4231F265844CBCD770EF5BE05B2F97434CAF711D61 6613108312D08A9B4D3A55B2DEDAF47CD5BBC2718DA7D18A7079FAC6A7D4F7CB4F09D4B027E0 5629C14EE77663D8B29EC009924B41F873E4024E092DF7343A1864C80B6EB8E4FABFAA90F5D3 9154FC4D14438A502E60B5AF432A90C7A48C523B4267534F171FDC02E57B9EF3867758A97BBF 9CDB99DC41758BAD49A7D780FA0BF66851B52D46BFA8B96E60BE89E4A5E78BAAB8736ABBE338 C1283CC1D2BC3A07F982122A3289E35CB097BE9C27274BDF3ED19EE8628BDB48FD587159E7E4 84F6F5005F22E636719F9327173693810F978816F739574DB0382222B9B717E394DA21A4F80D 5A95C552264DFA0727FED213EEF886C149D392E900DC4DDD0CCEC84C5DE5DFA3DD5F903B93FC 649FD661BF20618BCDAAEFBF9C71CFC11B8C68143068B78FCB3354FF5555A9774FAAE88328BE D4C4996679E9285A00C12B32757C74E8FEF1ED1EEACCEA315D56DF2E814F2C8D75E80D3836DB 71C5D1CF0055A01C1EF725AB4858D73CD089B3A66968C2604F97C861A7484BE84BF95DBBA43E A6EA2C455574B715825DBCA643BB023B77D3CEC870FD30899E7788986813915FCD3F909E3D59 6281B4D858A29465DBFA76EBA156B0761180BEBE2A6C218A51A67D400DCE29A3F19538DC28F2 9971A8B01B4C27A42FD9AD8A89B7FA5F188D3135B5567C8E0B87912EEF813FB15C63BC9260EC 3D7A6909D2295C0C31DC77B0A468CA4B7F801BB06A0486470201437ED678AFEC280DBF80C771 823FB23A5AF549CFF74620AB2EE1EFC50EE09F4A0BB4AB05579670940D20F01C61C7461F08DD 8560F5C1E0C73E0DBFC8532155A5F92162F05D19E6634446EEFFB764B9BF4B5E695E9B4D8037 8EC8406C588C3EB7C919BF154BDA4A878B45479F6111798DD6FAE11A29EA1E44934C82E6A68B 0025491A69037808D3FCBDCC7C80ED848EBEC3F7CA954CEC873F4E404A699A7A980BD66E9E81 2BF39C85C55A010D95B9AA147E5826D0DC8EFFAC979ED602F7414DD64CBF2518A5B71AF4B6FF 0F59657D2412B47391921252D0A723DCF2EEE67AB89F8C12D3EC1089DA75F364E4E6E1041007 2144CB14352C56F9D8D180E45861FDD26B68A02B5A86560F3EADF5367D8B06876ED8F79BC79C 3602569AECED48BE6423888D86C3DCD811CC26C29239210EAF574CE8730016A3AABF2BAA31F4 8CE3BCC43DDC31DF81883CA92F2CD4A7B1E136AF70037AD22207F8F5E5EC06ECA4C9EE9B199E 15590E9F59D11688D22CF11060E87423F3E01EF613FC230FDDF599D1277CB7FE6AAE4312282C 4BA8A28D794628136FA0C5EEE83CC6ACFD043AE7FD985D226AE4D91D00218964C161C4A0B147 E58A4D143917A592A8FBBA3215D1E3AF1CB952BF418C9B07A5ECA3457B591A0E9C49234DB043 99EFCF129AEA7A96694BED7073AE4502979F2F0286085B799669DC8EC22ADCA51E92EB0E2633 651E822F4910B716DE01CF09B631187A6B9935D43DCD1C68111B850B7F21EE142A7A48836D8D E7F4E63D72B515728D9AFA7B11118DAE383ADF97CDB92C17075F437FA0BDF5250C251013B612 C593D93E8F9ADDEB8C03E1D38F56E6EC42C7FDE744866D4B873B725074754CDC10CB0262403B 9740596A661A2DBF057144991F0A1A4FE3E316095978A88CF38BB1B5DD0FF4E8BCCF1C7D5636 9CAD0C2EC29D56A6CD2535EF610026AD120B4BBD5151EDDC7F385B229E79B22121416E74463C 4D5246501C7B6632ADD04F8C460C7D5A505F29BB3F45343ED5D576302FF9D8EC1F400B190922 BBE646CD809A6BF2E0EB9E7AC66422EACFFA93876695B8E88ECA149CE738586A0CAF105CA587 8572E58ACF6D523F2BF3D410A8E79507A0E480AF8C618FBB459AC768CFD240F32B0B69265332 20552D8325D058C2D30B5A437AAC867CB5BB6C007717FF089C65FFA92C5C8D159E0833C54C53 040D448B93FB48B5FF2395E4774BA3764B6EDFA7EEECDB2B9736E5D7E427CE883C67AAB05B08 26CD91AF342E32F2179CB109F2228138978ABB9C8EB9B555C1269FBD12975929E91AEECF0915 D6B2068C7B2DF726FEC9DA54ACBD64AA808FCE20A34EE78463C4A831E33F94A268C5454A1CD2 E05A662786E7392B24EF94B7EDCF28428B52FD85DD03F7B38000F38C4C80BDBDA46F62B9A964 FD0B5B33F3B8FABE28538632F1B229418E1AFD6FE9263CC220BAD30170816AAE06D54541F854 B68CF72E08DFD272021DCE628962A7BD962564C054C0E6AB2742846899F9D0DC9424D820FB28 9EC582BF3B56C48D32DB2768406491C837B125B62AEF198E85D6D579899EE59B53271EC329B2 83DD4C498294A27DF14A783C517288E3B6B4CDEFD2489398B71A712AB154E55499E016D7862A 14BFBCEE308D95509CCFFCED78FF3C55510CF91DA90F10D3203706F0592400847639F47C8A70 D98F48339A3D7017A8C8462D6316BAC13DF9E12A49805E695A1C632C63E223A2799C84DAD656 DA6ED692520DB379C727B8375DF9D548F693BFD9509B3028B1EA529AA6EB737380A4FDE879A6 CC623AE8F5F992523E167791F3D33BFDDE0A516C6901A202A5C154A0E69CC5FECC0B75E61B9E D91834B659805E8B7BF32FBDC4DAF5520A27D508689F692F1D69D4E0B00DD7AA134C1357DE1B F8804FD534600ADA4790738325759F35D9DC3B077FE48817AA57CAF862713E617BF7BF09344A 74BD13F118D26D30C1511B20327C460D270E5475371AA26BEFFEF03B66564E0E669724E38959 73D98C7150F035FB52D8D328EEDB5C85E7EA7BE5373E514BCF881C4147DA0C1656523A95B63F 86B3017B93AF76536DC19979B9F617CC855DC3B8FAF171780D352F93AA78C3F25A0AF51FAE91 878FDA9DA3B094876526BF6D68A650008DC13D0F17F8445236FDCE4F725A82AA5403B568F65A 087169993A3E81684234620F58568D2801F344F5667140F9DAF63DED0AE4AE391F717AAE8B56 6347257987D49186C82B911A98F94DF8292DF7ECD76FF09EAC1400B6C34658B9025AC42B7DBC EFA9173258680D929ECBFAD99CE071C35DD8D34126A036DAB27B3F2A0F4B79A509433784D317 7324A8DBD271401AC904E072ED118331DACC31CF4EE21D1A9D805971DBE8D17AD377FAB5450D 1C0448C6C65FE4E8EC9B4BC1FFA74D7D0CDC6D0CBF0C1F905DB3F02B944281CCC10165CDD730 2F4DDF57865D32D47C8C26FBD0D410E4DEC820B5D6EA0DD6B1769AC0550F15AE88C0EFEDBEE8 4B75949453669DCF1B447821480ACFE750D13F8A3E574F7687949B525B278DB75C3102FD4706 6AFC56C4588A258813C3C53DF147FA5F225E901A297E5E322920F131093304BB9B2895E46DBB 1D020EE684B08C64E1A159A6829DE9510E5E985F53454EC367507D4B84B80E28133254B7B60A C194C776F734D6E8837CE23EDC94531AD2E46DC6BDC1E921CAB4FF785DCAE7B556706FDED6AB 4763153EC5F4B2E10491E5E427DC327C21B26DB2AC272588FC41FC5490A102ED1C2AD82B0811 C34CC8DB42CE97B4B24E194CAF230E58A04943934351805A9A0C5975E98C0F11CB0AE28C5ED9 8E52CF035F823FD449436B20CC0A913B7606A6FB2CCF4C7A12714C99B60940CCFE9CE26B22D5 DC1FFFA01C8E4A04AF28C9CA3F2A7CB2B33A725C456EFF23BB62B69878F8FB185F653F41C596 C9BB7C7A17CD9B5A07FC405AE7E182567621FA75FFBCFEF42E7373B2B15CAE76D7C07BE16A23 086500A789CCE988CAB9B321CF969A79132544B7D9503C7D30A4C86D8601743449D619A5CA87 879AFCEDA5D16FE6B31E17529D17A95C027D481B6C11FE9477412DED852C15A026E36735239B F5063B7FDA776C1282B9F50F602526F355AC3516E5DF327C227EDD44E453B27D7074E0F9D9C1 9FAA49D3DE5138498B0569B4FCFF2041977F69484CCB916856DF1F07E40B450C250BE68FFCF4 D159FB8F1208EA8904567BD552116A28A95425CDA95D4FDC06E59449065B65DD2B7047BDACDC 29A66C8FAC9BF2EFD6886FD859BB0F256B21EF2AA03E6EFA6A614B222B84B7E6BBF2824713CF D214DA92F04543AE0011D51A50FD08C4FE4BDFDB9E184EB32C399D3A2FA71059CFB9F6AE1CCC DB4CAADBAE20AE4F65BC58334164F127DE5C476EA5BBA3644F2F24F0DBADD3D1E80DA16A6483 64C1BF86D0A76523317C7D4F46C419FA31BF86D5B700CFA640273BBB9D6C8AF13E7CAF3A2510 01F06DC2D4C8F57AAE5A8B4E4379163D732756D3A7B97C778DC8637D06EC36A951DAC426C14A 58DF97D2777E7B45EF2C3F9D35202015E420C5E35301AF195403F3ACE5FD4040ECAE467282C5 1E7A6AFC69936F6D81216FB0B2E3B3DD942DB10D9BBCE24E186AD3D46B49414CE148AFAB9C95 8E7339664510E2CC5624DB80A708A040C0EB2E48E8CC67EAEE7856DD36BA948C8A8AEB120BC3 28BCA0A629FEAEC6419D70CB8469D82931C1B08B8EF46865819F4D6E3D2A9BA5EA2ED7E7221A ADB2660B474E576DA104AE298ABAD60F6607D9D03C9AF768707D5F2F299927D14BE80E258469 066AD3C2BD0ECE20975A061977CD4A1246E6B545E7E9788BD51E04DFD285F9636C663D7C6AF3 64ADDFD0336C6CD6A46A43EB252D2B72DF3B52050D4C2B20DA4F6CCCB1C1CA85EE1C9A5501FB 22EB7FDFBFD0838F0359E295D3176EC8F0A2A7A262155DD2F20CD2632FFC30E4F274AF926570 85147A75942D1611D5B0407504708CF782398C366A02AD6A8B103DF8E615126B33DA380BC2AA 1160FA63665B883A5A4A7CE7514DDDAF8E65508B2B6FC341A00DE2E976C07A499BC758ADDA72 B65780DD06133027E1D7FAFBD4CF7085091ED9DD98D91E4EB4BC0BD4DFBEBC947544A96F47C6 4E1CA2BEA3E739A65BECDE6B2CF0713743B881F403AA40AEE5A726A8B54659852EA518675CAE 5089758C77C82EFBA56DF329AB46166154F0780319347A050002319438096D4EF7F851876CE4 07D436299F7D3A0FB6E8816C37A028D62426BC615FD635060F1C69E3E7FF6D9262E06679E415 088687B4E65813C86D481C41B5D74E0C208882B13EF4EEAE0C60850DC1BF54075F41763705E3 CFF0B9FFACB9E2922B40AA7209970FA5F3563D7E6E4D3D2249E7E946E97B5FA40291742EF9BF A2DC7D4E5EE1A25F6D0D930A50262F17F38744D7A07FA9B6DB3C4D7CC96DDA023AE2F3DDC571 FF48135434E354979EAFDF625460CBEA8B65B63BC612E44D05CC3C3FB186403F994FD1919A62 44E728857A54DF535AE149D405CE6C83C96A6DC117BF178E088556E12D3FD88017FD2C031059 1A89077E0D6455E76A3C8AE37B8DF495083B9EDAFAC2E3322C07209A21B5C33AC6AF3DBB527D C1AE916CBA52E68C2A851EB073D09CDECF8C3AEC94F5728F202BEF1083215895FB76B791CA26 6B925512AD89EBDB53AC81DCA3EF1796D1E91AE23E5C60DF72549D625AD1BA68D4B7B5C338B2 1496653F61F735A9D60C437A6397899304B3EA36BA2AE138A700681EABB177D32CD0DCC8B226 982EC3BB7EC84A831569BB9A3BF30FB4A56D947464B1F7B49DDA4621907F605A238D6C5A1F21 439FB67080A3AA1864CDACED6A37D1FDA3E95EB8E70CB3B78D2CA77BAB36D6FBFF8CE6AB6EA9 78C1C8FCA06C3112FA831E693BE7562B859AAE3AAFDBBD0B119392037F1658D9FF7473B2D4EC D67B80F2EC39CB32391E41E2F8466B9BDBE8E134186312F0C97F2ACD4EB52F835D00880928EE 1DCA94DC6A6E25ECC61B5E549D1B8A2C130D61EA7A42465F0EF3E3AB242799D2639AE4B2CD23 6F195D3EE06665DC3674C8CD681E0B49C7E5B95E4DDFBA0FC01DFEC2E17A77F16116AD14296C 0825E9859CE22241EFC60ECDC3F4C56D22EE448F8263394CA1848F95AE78D46DA9FE03328476 8058CC5A4CE269EBD36B01D04B772864E136FB076154A52C165A9A0ED6A9415474890E85738F C1E112B733B2CB78D73A294367C4A6B33D15CCAF851135BEABDA0AE764091A3EA5B65D0BFB32 36760AB084F8C9C16F1E93A7531EAF2130CDB62A8DB7B42040D0A92F2B20DA2FA00A73738BF8 AA9DB2581B00857BD6D781A2C78D83792012C83D4908012347ED651A2FDF54C70D53910D6DC6 D2D278872C6E7D58019E8D04407A1A720FEFDDD6EBD79B98B77A4FAEE6EEE00F2985F8B674C6 A27D04C992B7E8B53A1E621F9D3C66DEE950E1F705D02DDB78A081CFB94006AAC8105F5D3E46 5796D2C10018F65869FF73D7A9ADB035FB37EDFFEB469D7670A13A43DF3CE14D277AEABA3833 83D36460880D924138C8A8374AF1031AFA2654D5A118A82149072BCC38F87096D240B55679D8 221041F2F7934C27D3F1B543B6761CD2D2D42BC27D7C16317D651C2E041ABFC027D3472514ED 04642E58C1E729945761DE2758A438569DDB55505284045153837A29D3BFA889C6AABB26C108 F27571D832CD930D39CFE96814370B2EA5A39376975E378B752E6E14FF1322942114E4119A30 7CEF2711AF296AE3F88D550163EAD08B2B515364854990F25AABB23D975FC84DA81CF63A416B 32AF608508DDFF86CC694A6B668B3F382E3E3AF223623A65AAB3EB16D000D86D663EC6031D2C DE50D54A55EDF6C7E47B4903C9922BAA00D2C00798CD367613F7549D9873AC4EDD3C2E8A044B AE53643AAE392DAC91F6D335112C2DD4B188C5F1EF1E5E42457E4C2F2D2A282EA3D2E9BCBCCC 6DDA43161DF8F8985745E86461108E080F647C09B183ED67257381C512947CE954FD786F0B86 A62E40327AAF77C3F5265A47BFEE2F3919A7073E84C49DB01295C730AD18F45364E2F19BEE93 8B7C92235D9E32754139E8C2F64C738A5716EE5BF2C68D09DA48166FB2490EC874C723D6E72F AB7C597CCD0ED2398BB9D99159E2D4A3FE605ACF6F7A5D4A00BB9156FABAD02D727437448B75 E6F08F1C5F17B251412C2E698CA1FD7D8D7A80AC6C7343CC7CEA23245812247F35F0F4480E10 A1D8F9D8446EE41E435166DBA0CA3B29155146C96C05FF1FD2661DBFD9AD2A7341362BF8C2A6 C10B91541D2E4CB6F8AA01F1C90E118E0DB81FC03048F54677CF96075EDA05B928E200E1620D EFCACFC777BC76E3C911229C64699560D630BADFFB00206E4DE61E3D06959B2C4486FF5DC7BB B22C634D8B136077E5062096D3C99B142E2D1AA6C26E58AFECDC55A8B90441C0459140363FFE 8928C20BF64C8BCE4DD15EC806A2AC7CB1DD58E67B69A34B28C4164BB0262FF9267544A6A905 AC3290DDA8F97CCAFC12083485AF20B6875B355D98CB5E45DFBAFD80FD63DD590A2EBE0B0429 2A1D37C906FF3042E608B3D983DE1D829FAA8B658584600E5EEEE90FB0CB13EC9633B148B696 30B8A4617527B0049E107F4F7E14BF421DF26B08BF193EF2650E7930F567BF3A05CF55F3BE9E 651C2273F5DB3C4D08D9100CBF5F5672C702696D823A43082A79B159DFD315278DEDA56458D0 B8208C7FE90808E0D0566CC2A176131AFCA80DC312C9F7E4C25A0E949AA384CE254B885CFD9F E74E88B40862238868C3F7D1B435DAA876B5875563C3C5BB3B962BAE3F9909BBB96997A76533 95C7CBB41D74347B78547085368A5B2D18CFC3AC56DCD1D9D5A53EA63F4241F1B35C15913F4F 773A48F42B4D04B594F33FF14C0B16989C4354C2DB18EFB3132AC64D02C86EA8198461F700B9 8BE371A968C0865BEE44E8DF5A7AE98B738C034CCF07E1CAE4FBFB8A50C9C31362845BFB67E0 0732FC33378066D3B8F1D69224E627103CB706AA5B6F3E4DEC74445625CB052F5AC48681CD3B 204574A1041CEDB74A51D4D21B37D465593A7E8F7AC1184C5EC7AB9875852D88E15AA1C5203B BD9DA15C25BF2E908C97678DE40D9A8226BE09A735156D1AA028955ABFF46DA51C07E8E1234C 9FD06F9B54C0E8ABB2AC28721F5CE5473077BC6A4AFD0EC98F4FC29BCFB29BDFE99D931BA28E 200F5D58136F63C5D18B4917F79F9650343873C44F8F9F699A0F5495237E2E748B3E5C3DCCC5 9DDAF98E1C4F5252F0C52D2BC4399510496E4844A6392F984204282ED84398E7C8862D9462FB AD609A8C85945B758B88E37A2A412380B6DC884BCE142DDEA569227FE306C6B4274C07CDCAB4 B48EC1806E45A27109D0B142FB3C84019F4C1C275E8309696F966705B06292C8F8622FE8DE52 6C591659D7780D424E8ED1D83F59A0289DC59556A84B5EE4BB34DAD12A92974CEF6901517285 42E222B0C32B05B2C3D819A40C4BFAD0E080E60AA633D91ADEB117434C58A7BBB334503FB9D6 85166DA7425F35097878325385C28C2F1B10CE6AF452AE0FE66C89A9426D1B25196D06CB9271 C6E973F2FD6722B1EC18162175A9C00CD155FF3EE679FFECE6889B2EF40D682FA2972EA03622 24A1C43282A08753A5205D3BAEC16DF17AB6F6162F9A61292F32F2D9DA34A45F3DFF377848B6 E5CAADF938BBC92D8553556817316F4F8F8D54983D8D72C2145D4D83682CA5D528867E8CE66C 050FE52B0269FDC98E5B48A185B979B45CCA3D99C870B1049461007CA15F4DBCE8A306D460D8 F6B44A2506FD7217F11B69A0077D3B7C2F016ED954BA5E58C9B51750E4FBE8E88E4B0AD59B1B 9969BB9494CC19C030DDF9F586D80CDD03FDA4D655D90AFCD4CFC93ED8B70C13FEB1B3F052DE FF4EAC734E8C1FA2B4AE1423E78E529443074F58E3F5D84DC1E8AF60866E49AC96210FB526F1 B4DD10AA19C53B92973CA6E13B60D319FAD574A46301A80D69737B9F60B4466B94F4AC8DF508 0C92A7359ECF6883D87D1BD45037F84CDFC93F9CF0B7D8D8795EA37B8A0CFDDB837D8F9A2327 42995FF55E0C38E2CC9E57E10C5C5D6E9EC93650DC90A82F545E54C66133F9381262E21CBC52 CD865192A781BEDB71AF318DC25239D64CF458839FC2C809EAF85AF1AD027E0BA8BC70AEB164 8F345E7B6043BF59FE71C0B20F8BD21CC93C9A426E80D62AD487A60654EBF0E364D99B90574F 072C52775B239A0DF62F256F44870302D077D114DBF83715E4A07069104876317FBAA1F7ADF9 F99DDFEACEDADB48B397B7EB2A37E190729F6D31474F4F6E2644C697E0FD8836DE337E05A8B1 B8CBB7A5A6BE292FDA3FEE754C5F9FCCD6E4528349392FAC86F7E6BFC953ED5378B7C5EA0D8B 2AFA34DF6360198E5FC5ADFEB120D9FC498D8DAC8644E9643AF39DA434BDC546FD2BCAC23511 AB1687B7943F299285D071115B4CBD650F356E75F478C5505A7FF036BEBE3682C3A00D047626 1791CF08EAAEFA6F9333C66CCF5C9E59C14829B853A660F3FE3CCA0F1F869E3A31D089E373DD A04D765D25FB0B6BF205A9FD881F00E99113C5DBFD2FBD7ED608C32E9D51FDF6454557DC52D7 2EECDEF0AC2D8E89706809648515BD4037379C6057BB89AC4B6768DBBBFB672329D3C21036A4 804682C6CFAADDAC7723C715842B25B03FA1F12A2291125F34EF7DEDF897EF4A7506F804E337 0814F4B62612B35ACD43A33A3ADC76815D29178EF7B6D2C170FCC1AF75A9157239DDC78A5FAD 4B7B759755F63031B1A7A6F6C9FAD4CA3B4F36E065E3BC3ECE67C990411940787058AA52A00C 51E29250B624EAF70C9E236898B1E2491256E9C4399ED8ED5B19F5941E76F51B8F16EB0A96A2 9FB928E35ECFDCA1BED3B12D5B5CA1D55BB2E4AD69FA1BCEC3876142B7A194388538F5BFB028 402E52505302F482BFA1D6C2492FFF4C7C882B6260215B52279E25E8D797222A2E4473CB30A4 489A6F2C566A79E9FD940BA0E15C52C8044B4C725358C667522E784194F87C543D9F77342757 2CEF02F46AACBB4EDEECC15C3E813C67E68EC8485112A1E19054AE9B877B857D9466E69E81F6 C24BA540A3D716F2E92659D252692C1D5DEF79BBA8C6A7BBE9EAA7CFB7721810FEC93F176E8B 9DBA3BEEEAEFDB577C14D52D2676566F0D04DE6931DC8ADCCB09022D30B84E9703CE37845966 5946CA535D26B3094D1B493A5695DA6DCF79527B841194790AF65EA24FAB98EC08F519743248 FC600029F2469C8FCCB2B27182928BE3F1AA4405E14C7AB842A370E45D48AB1EEEC9168825E9 88147928854FCF974821B19B65D9FFD57333D3EC10B21588F04F652A218D8E5CEC3ED25BB6CD 5EB1789E3CFAAACD95B72455C5BE8FFAEE0636C0788A587C992E6D1FA1E2D5EC8EEA82B6F75F 413707DA0EC878352E92FBB1608506CC3A4D1F676D364524C8B72C3AD5867E03B7642F335B4E 0DD6B59957CAA5C0131C8A58E0F95EC0DC6D75837291A7C1DADBE3F92642D2CD4C0EAB79CC23 7BCB33E4631BB90B0CE4D63A936348B7CC37AA207BCA6410F010890F23F6B3F6DA3C7A0643A4 44D2E3D226C754C1598D72AD25C25BF5FDC1895E6D23B9632646EF4F314BDFFA94971BF6FCCF 20EC37B31520221BE10025C386A8A1B3280BB47FCE113BB4A5F29AB70059611EEAB412C0A969 3E30993FC944B38B11211594B5AD84B0D622255A372F56A150BDA57451FCF52F3DBA2DF25BC4 16759E32B7B19309C1FA25AE1C33D668145F2E645107CCAC86E741342CA4301685936E12234C 8D612F9314090D5C9209F5D154E678BFA3985B03CE6635AB80B8ED2630B41D7D223E6ED1625B FCC417BBC3C9E5BCA6256260A06923EC1B9D2DA78C8B55B05CADB5785C838CFF582FE167CFFF 88167D7FB3B90B276F5D6F78E919FEBE8F9B58915129CD7AE5CCA6CA9885D22CF7084994D101 B81A675D0314C93041B5DA1899B36DA5DB30676B5F1FC0F3A98A33916B47E0496E3DDB771098 9AAB7642A1F77E5CF5EA22F75432DCB7DD2AEA6FC7BF8C9FA07C7F28F7D37CC13D3586D4EB49 CF579A95DD3ADE1DE06869687639267085352DAA0A19E8F95E4A7E31FF0D17CC87373690D263 4852D465CE0FEC652FB6D710163C738CFB030BD4935EFF80F7DE7D7F06F0FDB1F4C10B07938A C60C74E442E1F3A6BCC8BBDC7814B6E710C41AE1E157538871AFE3518CA8834A4B4DBC59CCCB 6DA74715ECFA03E98289479C36D00DD0D125B12F63B45E112C7AA1C5E60B986E74E56CF95C80 198381207AF0CF5F17A6635E2AA89293E67D2C549D110A2A57C02C581166747BA758DE5D5F10 686029D7F0A82E7E4889BA7160762431E00091524EA5B12C9D4493F0CDCE0B4DD38EC792B4A9 2B0DC4539A51FF1D613E75D981BBB9C20B3D53400AEAC4970FF843EFCE5EB250C1283AEB8315 73AE15427928CC2A9C0C3B04B7CEF0DBAE549AE82AD2FAB68F5D7463420EAC2CBDF421BDC88F 2A6B10521913C6BFC6258598EE979570E9E555F475B1B26721F94A5462135E9705FA27259BB9 564253D058772483B35A487ACD624B8D9FA02EE6BABD73D308EC29A30CC32BF271CF95B3B070 160E31B8649192444A80DBEB812D1D4F4BE00FFEE6BF7E4CEA75A1142ACDC28EE252228DAD93 7A69B3580830CA904CD6F5CD01977F6FBA3A13E89667DDFC777F48DB2736D78856BAEEFC2E41 C82C82466D361AA2D02FE20568F584088F4038B72E10695253D8E095DE4288A48605FF431809 8801CD4FCA473F8C3316E8FF9CEB463D3AC98EFD0E30EB743E250B974E758E86DF712E13453A E6882333F16696A670D28AA612FB9A03D46C4A866155D21AE216E7017F06C6459708EFAA13DC 465BF43EC202C8F556945FDA8F0E06A527A368C577BD0E5857F35C0AE8D0401EC43D1FF17760 A7D9893DBBCFFC86BE0747E7E6E07736EF0146BFF75DE5715E45F8EE823070433000BF015DD9 44265CEE7BA9BDD434A1D78E419608A4B19C0F74CBBA354BBCCBC13D0BBE4BF95072C69762D2 318D2E637A918ACA900ED1D59011198197E8DCD7D1CCC1F43890453AF9F70F821234C94E6F35 5E494C38E279E28C60BCC6C4132405B8CD1523A1BD77A4CBFA12C6009F5669AE3363A405EEA2 8E7A28044EC8B461B342654B2C24D50F43CBF0887C60C225409A289EA660B77F2286ACAFF8C4 656D4A369D39875D0F10436857033D2C5AD5E2619557B4F2C88A753249C2DA0552BAF19916F4 6F7F3A1F1356AD2F047B55F002D0509E266C184A77C6FD56071A28089B1082C0E80985242C8E 3169E754E5CAE6AB2EC06B5D8F1189E325485950ADA8A30F12BE6872D8393BA32C1ECD6A80DB 0FDF54919E9A7D9DA15C1BB823881033ACA8C21F3B806722F5277AACAB4A4E80222B3536E50A 2E5BEE34484310CEA6573B48F992D2B361B13F3BBD14A1E65C58B6D71CE393C3F340FF9806B5 4D82C04076AA5A4343E53785B3BED4C8A78593988BF3432A217AB637583E2898257BE5EAA11B 84231F6C9761F74DC75FFCD351F3C4101A69C98877EE17AD11541D7F57F6F5293CB956A7633F 541EAF253262699FC79E4A396C5D3289C3CAD0C31AC6CD59E794C80617E102B306EAD89EA036 85508781C79645ABF8BE697710D4D5821D1512467B66DB602A2DA5E46F646D685E09E0528C47 9C6E9D6A5503B99104E0A5535E0A62683E520063BF2698701896B39D26FE9D2FF2BA0BAACA77 A75FF905B3CAF7C7C8A5243C54469EBA42D0ECB15AFF53770C93A32B18205D2FD601F88A36F5 3B93CDB0A247C4E5750000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMSY10 %!PS-AdobeFont-1.1: CMSY10 1.0 %%CreationDate: 1991 Aug 15 07:20:57 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMSY10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.035 def /isFixedPitch false def end readonly def /FontName /CMSY10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 161 /minus put dup 162 /periodcentered put dup 163 /multiply put dup 164 /asteriskmath put dup 165 /divide put dup 166 /diamondmath put dup 167 /plusminus put dup 168 /minusplus put dup 169 /circleplus put dup 170 /circleminus put dup 173 /circlemultiply put dup 174 /circledivide put dup 175 /circledot put dup 176 /circlecopyrt put dup 177 /openbullet put dup 178 /bullet put dup 179 /equivasymptotic put dup 180 /equivalence put dup 181 /reflexsubset put dup 182 /reflexsuperset put dup 183 /lessequal put dup 184 /greaterequal put dup 185 /precedesequal put dup 186 /followsequal put dup 187 /similar put dup 188 /approxequal put dup 189 /propersubset put dup 190 /propersuperset put dup 191 /lessmuch put dup 192 /greatermuch put dup 193 /precedes put dup 194 /follows put dup 195 /arrowleft put dup 196 /spade put dup 0 /minus put dup 1 /periodcentered put dup 2 /multiply put dup 3 /asteriskmath put dup 4 /divide put dup 5 /diamondmath put dup 6 /plusminus put dup 7 /minusplus put dup 8 /circleplus put dup 9 /circleminus put dup 10 /circlemultiply put dup 11 /circledivide put dup 12 /circledot put dup 13 /circlecopyrt put dup 14 /openbullet put dup 15 /bullet put dup 16 /equivasymptotic put dup 17 /equivalence put dup 18 /reflexsubset put dup 19 /reflexsuperset put dup 20 /lessequal put dup 21 /greaterequal put dup 22 /precedesequal put dup 23 /followsequal put dup 24 /similar put dup 25 /approxequal put dup 26 /propersubset put dup 27 /propersuperset put dup 28 /lessmuch put dup 29 /greatermuch put dup 30 /precedes put dup 31 /follows put dup 32 /arrowleft put dup 33 /arrowright put dup 34 /arrowup put dup 35 /arrowdown put dup 36 /arrowboth put dup 37 /arrownortheast put dup 38 /arrowsoutheast put dup 39 /similarequal put dup 40 /arrowdblleft put dup 41 /arrowdblright put dup 42 /arrowdblup put dup 43 /arrowdbldown put dup 44 /arrowdblboth put dup 45 /arrownorthwest put dup 46 /arrowsouthwest put dup 47 /proportional put dup 48 /prime put dup 49 /infinity put dup 50 /element put dup 51 /owner put dup 52 /triangle put dup 53 /triangleinv put dup 54 /negationslash put dup 55 /mapsto put dup 56 /universal put dup 57 /existential put dup 58 /logicalnot put dup 59 /emptyset put dup 60 /Rfractur put dup 61 /Ifractur put dup 62 /latticetop put dup 63 /perpendicular put dup 64 /aleph put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /union put dup 92 /intersection put dup 93 /unionmulti put dup 94 /logicaland put dup 95 /logicalor put dup 96 /turnstileleft put dup 97 /turnstileright put dup 98 /floorleft put dup 99 /floorright put dup 100 /ceilingleft put dup 101 /ceilingright put dup 102 /braceleft put dup 103 /braceright put dup 104 /angbracketleft put dup 105 /angbracketright put dup 106 /bar put dup 107 /bardbl put dup 108 /arrowbothv put dup 109 /arrowdblbothv put dup 110 /backslash put dup 111 /wreathproduct put dup 112 /radical put dup 113 /coproduct put dup 114 /nabla put dup 115 /integral put dup 116 /unionsq put dup 117 /intersectionsq put dup 118 /subsetsqequal put dup 119 /supersetsqequal put dup 120 /section put dup 121 /dagger put dup 122 /daggerdbl put dup 123 /paragraph put dup 124 /club put dup 125 /diamond put dup 126 /heart put dup 127 /spade put dup 128 /arrowleft put readonly def /FontBBox{-29 -960 1116 775}readonly def /UniqueID 5000820 def currentdict end currentfile eexec 9B9C1569015F2C1D2BF560F4C0D52257BAC8CED9B09A275AB231194ECF82935205826F4E975D CECEC72B2CF3A18899CCDE1FD935D09D813B096CC6B83CDF4F23B9A60DB41F9976AC333263C9 08DCEFCDBD4C8402ED00A36E7487634D089FD45AF4A38A56A4412C3B0BAFFAEB717BF0DE9FFB 7A8460BF475A6718B0C73C571145D026957276530530A2FBEFC6C8F67052788E6703BB5EE495 33870BCA1F113AD83750D597B842D8D96C423BA1273DDD32F3A54A912A443FCD44F7C3A6FE39 56B0AA1E784AAEC6FCE08DAE0C76DA9D0A3EBA57B98A6233D9E9F0C3F00FCC6B2C6A9BA23AF3 89E6DFFF4EFEC3DE05D6276C6BE417703CE508377F25960EF4ED83B49B01B873F3A639CE00F3 56229B6477A081933FEF3BB80E2B9DFFA7F75567B1FA4D739B772F8D674E567534C6C5BBF1CF 615372BE20B18472F7AA58BE8C216DBDDF81CC0A86B6D8318CA68FE22C8AF13B54D7576FE4CA 5A7AF9005EA5CC4EDB79C0AB668E4FEC4B7F5A9EB5F0E4C088CD818ECC4FEB4B40EC8BD2981B F2336074B64C4302807FA25AFE29D1EDFF68FBD0141698DA0A0FD3FE352AEF6618408EBA8063 0FBCF58909B21CA4B9514EB27F9FC7B78FF460D374798DABAB857F6DD422BC7983C7CA213870 1652B6C3901B98B43B641F905F54AFBE00822DD60E2BCEB957BCE7CABFC51F153F3DE4095395 28E20DEE4B8C15E2AEAEA9A46FFADE11A3EBFA3456633B298DEC6DDA6D6CA41DAE03F5C6B56F 68E58C0706D3A97E34FD845F8F2C6126BB6FFB72FF4005A1385A1EF92F2BC0FE7441C157B1E4 AFFA17A5D2057DC2BA87A77C45F8442A36BB895C4FC24FC83BE3831D0588E9D66DC2E71D11E8 8E9F110493314AE48233D708568062829ECB94AF0441975CD8F1FDF4F626E6B0DB35683B790B EFD89B94894C3CCC5AE9A57EDE5B4C5F71CE1A7C5F34108EF589711E2E4572D90CB501068859 E2E333876FC9251E6A574543E1C2E7A55E186CC9A194DBDA51724FFFE506B0B754666C59F449 3D069431CDF764DD7E62720625B3E02C1403427A93362205A4BA5AA6727E3D486795D7EA749D AA5A46A7C3FF9EBE73DE35ED38DE2A0E9BA7FD370B5B702E21DDD6A69A6B2E2916A5A93849D9 24B844C3A0334A0D2C95E089BF141DF55E25620BB31DA68962DD3C51A9336EB11FCB737E6906 EABA756BF7B55EEADE38994C5FE146FDF725AC74CCACD70BBB292DAA5B1C60CD39AC60239B12 33579444E8846826D3983B0D6A8C5BE07DFE43961897355ED8E72CC4A4257620EB7E113EE988 D0E8F7947CC822D8563B7BD56D69F144159293E3E2CDED7068F6E3046F14AD559D712D7FED96 740C962CD9EBA9CBDB0B45D5DD9A05C0CE28DD27D2FE6B7169B409BD1E080B32D6D9F2061BD1 B9292D0506D482354F59DB8BD14F8D975B8A30B212F524C8664E5BD9C170BB0488CABFB0BDFD D18BD44D443B08FB2781840ADDC9BD22376AB814B0429D7B0664B96E183A2675A28B68F1FB6F 88132C796CE2AAB0B9409396552D7C16F6ABF5B85E93B397A9E1CB74F610E81319CCDEEB6D31 EA13F95F792841402245230868FF37BC57995ACA98FCA2DF474817BF96B0ECDD4F42DE20A007 49A91297CB25EF1C7AD56C5D87256AB41195624F1977ECF9246D7B1DB6CDBFCC654AD428932E 5C0DEE8CBAE5D2CDA5F56C16D62BCB93B05BC6CB5E13247F59F321B3B824A73D4261C6A85609 ABCB95C4B14FB51FA0B8826A05696617A2DB092D909FFED178BA62599012D08EE433E800B54C 77C15DCF02086B1F04935F7B79EF163384FD4137391F5E4936EC38677BFBA1B4204F5F80505F 68CAA8F538EB157E9708306A9745D2E2855EF01450E3D2F8BD3C4C5B4F3697A51038011D41F1 6E4C7781B4EECCCFB86EE892AD6E9A2C69C1AB0B11DE2BF88964E5DAE8A3389F18DF163B375D 17895F0D91D4D52C3A5BE455196251EF12B8742CB54D14611BF5227EE52BF8F464EF8860579F B8BB6191E9AE46F27BE34D732C2DEC814D00FB9763848F847AA9FAA73CE9053719C781C3B3A5 F27E614187D3F00A330C2F76496BF32E924E27ECFB6C459353845D446F642061864356CCAAA2 BF7443515645B51F4DFF4E244F8B7A556EE38389EE3BBF9E69BD72D6BC0D134E134D6FF43608 75EB8838A885DC681004EF4383CAFEEDC688FE4735F5AAA4A11B1BE4D956AE9CBF8D8FDDBC29 A600215C189BC812A1F441FF1CA1FD6C5F3C4013528961E676FE3C9ACA3D44B913F51DEFD42D D4F67BE410C4152B675731F18315030FC2CA4BCFAF5C5BCADBBCBA4664FCE78984D5C8997B40 088F68F31C8D54D44575ED23533BA3A504C1BC90794AB111F1C011BE57696786AE25551ED73C 35F6A343579DE01675DCFE26ABDE7A3CF73C121B7C33CD3D42BBCFCED99CCFEC4AE08EBF2AF4 FADEAB53F6A2076F8189503DD57F84AE53CAD55D97D3734E706D9442FB175B5CC032EC649776 00A369007A47B17569E32C5BCF5722AB7CE03EDC4DB3C1B3D31A73D3BD274C53359C6BE06BB9 3D0026080B9D76F51DC69AF96C8F73B83BC8CEB5D788E69571EDC574E71C06B3504141D47179 24EFC2CDD8D0CB9645A06922CDE8EF7B297BCFDC0C9D8C65A0D0CE542BAD98B08BF75D814CAA C3C51877584EDD5412CAF5C69599666DB2E5571E5662B3DA510358234D553A54025C8DCE413A CD0B4FFB252BAEE591382C0C0A293011F3649508A2C7DAC8F153B869C77D148A0A81AAE057B8 D32CFDA1750180C98F70A8D0FC62A976F785B6F67E9665D1A54C2F591E4B9BC1B8CD0B23E6B5 3CE5EE85995417A8199F68DF12C88173F69D45D8E6208DF7E1315CD08C9F0945FA751B9400A4 F44F1977355C5FAE4EA84342F04AE3E785DEC832DE82B9C6D57835734080DF60C2AA44702FC5 BEA1AF1455DA321341F3613442D63F6B547FED5707EF114B654E0DA6ED340A9372DA4A99A987 CBE785342FA9D2E98789417B87BFAACCD46C16D11B5C6ADBD5619770810A39D74BE2620CD99E 49A9DC91E7E6D0B6AABE9AFDFA8D532FFF1310E0FCC91C0B103340E0F1371FE7801B9EEC0F67 A7C7A26D18FDDADBEF951FCE20EF0558B9F32C560E41A87AD4A94DD0E0F1DC333F6667C22C65 D995B27D25371579458748E078D5EDA6ED9F84ADB3D35547FED29BE03ADB683BA50A9E1CF955 CDA99F95EC45B6B23F43A05D0607CAFDFB9E1D830613C22F1C583A65381CA5C8A736A8B34DBE 70C116699E3144AAD48CFC32405F67614FEAFDAF0106B39EE47B8902B1511665BE23981ABC5C 4E148F6685ECD9575C66DD36A22E41198227E7D7433ED856151154E478D51F5B093AB0A7A923 197864F4FD6AFA7282DA51534B0F9BD0FF070795BF954E02204BCC3B0907CCCA5F3C478F7EA5 402556883EDA2211C394C0D6E921F502368BA96DF89C39B9A36805BC76FA3C3FD390B0B75262 7D8774F66D18A074BBD255B9FB2A2FE94BB30A928243B9F308BB789FA83E6BA7B94946DA5B70 A5047B8D9BD59EEC2DE5A21A7AB0A826CF02CB675CB5C2EA3B774647962CF7DEB01554CAB8A7 B949723EB847A544E8C839F36C10E9BAB10C3E4B05CF6CC46CC6A567D9BAC1DDA8825C726450 68690EC820633567BB2275BD1271E284193C4402D5AE384669294AF99467162E790B3CE41F0B BADEEE07EE77BC47CFBAA76F28DF5F7B870F95B04A8DBD85454405DFCA87B6B4DC65B3D5F125 65BAD0D22082001D0061F10991F3E1682527EFBC3EE8F072F4BF29F3EB210E403B142B82B97D 6AB9A5CA512E448EFA90F8043495C2FC11730F67949E0F54544094592989D7A1CEB43AFD0BF5 0EF49C81C996469F52451CA818176ED2AA6FF8276030EC931A9CA6BA331A4B463CFE77161410 C4E8EFAF9395F51D13D1BCB2841DF7DB65FA51ECE17B5A321B37AF3215A69E72A74C4FDED676 7930CEA4517DF9A7148A0041F4745E4E594B0219C9AFC5EE8059BA9BBF415302A9CDC48D0460 516A270EBDA3A6997EC4335EDC0F20FF994C69A486316AEEB8584D0DDAFF255F7FFB07C77E29 D58D32BEB7F337E28DA97B8C7C44F8452D9C629C38E03F402824B24CBCBC6B4980559921D69A A48F593C4791B32FF0C6DB1546E37F831A82E3EC733773310157F50DB7AF0684981345E7E23A 7284029CB27BBC36D2D41EDD1CF0C3E30895D9DE0A2319A746127C37B6F08BB7F9A414FC9FCD 2C17998F7E6CE30C395E2BFC589CC0FEDFE92C659E4078DC7F83E9418B340BBEB23B52D45983 24238EA02C94591014A4D7C12451F7BF20F3F9DD26C515877D6C33A2166A4E433A1748AA192B C0D33F1C4FA89397E39AB886AC737440C31FAA635676A62E6D3F194A668FD0F8FE5B6A8BA3F4 B4BA2198C837E4B9CA708754CD0804AC78C9218A770AB3EF5765E14A69D14C3367F842B72352 3AB69E5E4FDE7893F99C88273DF486B4080089A0DA5136C59E1DDC48FC71C1E9C8C591E8BE5D 3C9426A657E65FF430EB154E2DFDF4333FCAFC588B61F8071F65CC8D1CB15E27A425ABBB0D78 BC366BFC4F88122C66DB571555B5D6E028912BFD89CF3E0E56C464392A4D505A4F7E23CBC169 CEEAAD218C7553668F549AF2CBF9A297805B3453B7C61112BF8E6325B7569E38F635B2E13B28 AA8F7188E4C94E3E047B6A6ECC050ED9F3A43B131193D84B32C0FF1406B9B66E3627719A781B 676DDACC16915ED237D6B1342F3A9D981D9E96A1A8D5827BF165BB901800D6C900A53271C906 D3D106D26636438E1B5A0C9C97CEF25F0C8B4B5C037C10A9295DA210CDD608ED6E0B77CF2EEA C5DC2FCB7B5FD0122A3C3A03DCFF782E3C877F210425F9FF99235A969ECA67AA7AA290130D3A 64D6165CCE3AC29C5EE3B4B86EA3AB78373C664DBF6B99949EE56B0BF0F94838701D554B26BC 45C4DF406D9015CD0B2147D338D1C71F7738E3B922291C96DAB5D9230190FE3299551698D8B1 4EF02F5948BF5B5E4BE42849C001CCDBFC06DEE4FF6B12832575D1E5863F1190BCE902A650C1 BF869CE7082C9388A1DAC4CA0E02967E3937BA91CDE0E931BDC07DBD87BF028F46CD00E7A7C2 D26362E0FC0BF267D6DD23E1DB2CF41C3BDCC785F2A8D12067CCF81E1F113DA147CAE6B729AD E0F85369AD28239F35C7C5CAC87CDEBA07AB233B9321055B972A98CEF27C1B41EC063015E8D1 A2DB01AFFBF0BE01C43DA54A86F199E68432106D252837759AE1618D7008D615AA436341DD35 583DF423EACC1B48D568FF5985145CCC285B2803F03B5B046E7514A8024FD786D3033AF60962 0004CBC2609766039EA8B28086019E4BDA30113CC40E854A159D86AC49E50D894595349E8B37 97239DA96F55B565D5185E630DF0BDD44612DC4E83D31BD8A4372AFD5420F6B379EB8D7373AF 3C91C999CDBF3AD418DB84AE6629D44EB28AA5EE9583686EE4F9435DF0971A3059BEAF8651E7 4E33E7B712174BF952795561BE53B5926CDDE509665488354D5C3E288CA7B679B9B969C9C6B0 44AD882905663D1F5AE476951A637D4125E26575B2CAF43DFE5C6181238D78E0F41F7F798F03 FBE9390561CFAD3F29E9DBBE20EE524344A7E3A730C529A2BD8506FEF7D571AB99A36E136C67 897F7C38582782BD04DC799F8F66432E0D5AFCD239185E95C8B6842CFF16F2CC128B8FEFEED6 95C85E4FD702A60553A254E9EE2AF1A0313A5D2AB5EB559064480B13412085120CB6C90B1AA0 8AE1FBEC261077B9FE65E3FACF4DF582E89B68A4422D0460DE7A8523B51928F1416A9AE025F9 541FB5FD5A9AB5508ACF97EA891BC25EA5FB8C7C58310720CC40B8366A806DE9E4DED30426B1 E7E9D9C145969B2B6D27CFD7F7BB7B2265E79B4BB865B0645209728891A88C68B20E681B4472 CD3105C2238931FD048B43400A9819425A2071367B962C69374A22A06990EA59D0FDE438D552 2432C1BDA7A54E52B594B662740FE6923CD04DC2E7B05748A8BEC182DD5079DD44C0FDE807B6 BF4025992BC6B6F24C2CCFF8385CCD37167BFAC7934E521BB7327D8E88B018877D690F959245 FB26551A75A06E6AD8E5B1C2363D2493FD947431050608AB63F15D1966D6BFE4F1A5AFDE5BCE 8B08E91CF0514B4CE56E1C62BFF778159B77A5919DA5F4619F7A580D6053126AFBD8363082DC 12A405201442BA72742E26C7C8D3430263C9A0EF34E0205065977E7952CBE0FDEFB3902D7716 7F088103CB7D4A508C867077CEEA5D1FCBBC1AEE5F26AA7A85FAD4FA3C0D9207AF49B373F70D 0FCBA87AEAFC7298793693865C156FC0E0E8E7B31AFA7C473275CD08B7BEC07BEEEE402AC272 C666C61F5BA5C1C513DE5909D2998EF7C439ECF9926DB57E82772263979BEFB72DCCB5842BFB BA0EB1586CFDDFEF3A63F1B4FCCE3894E981D6268A62D1D39F918D4F296381D5AB356450FB31 CAE01FD7F36718C7A54D503EBCB479CA191D5DBBBC08723B8279F2491931D2BF54BA9A93C214 549F66C3C314EE37B5A9951D62A6776E6C7B4989BCA05ACDEAD7DEEC09BA97A0DFDAD7429E3F 480806EB9C7A3865B5A0648530247CCB71AA31E1F8971D9649D6A430BD8753FFD295F30E4E7E CCAEB12F4A5D9B7902FF57B08B3ECB4593C988758CED4A394E412FD5A132CAC5DD3DA61CA3A1 3E91703702388EAAD89443E70F7D037C9FA28BE7C8261EACBB7AF473EEDB0645BAF01C5F506B A85813FD1D5164F541E0E85D228E92E60D9BF5C108674C621D38E726D2E219411759E8063C2D 2E64120C66BB2A8F6F00289C3BFADDDFAFADC3285CD6AE1E624A59D7621276362382D2156A49 319A5B1E2B6B6D9B9346A59E1A4E9214C66E17C3EB5A31B394EE2F030C88FEBFF5C659E29FD0 5F57C35B8C986ED1B6FE33ABAC7334FA0653DE6A935CD0CFB4F785F80DEE2D651BE3418CC83B 18B5B4C176DE3263ED6B4F64D4395A48C2C5CF13B8D21D63D85E2228F6373BB766D288CE9D05 AAF98D0848D1AAA42CA0629165C7417E47906AF4ACB4353CFE396B82BEE33EFCFA2531DB7237 9E81F0389A72E0A1D423E1DF66772732EBCFF12D3F83DDF18C46A00297345166F3C3E7B11974 D70AB02EC9629D4AF1F2857FE14D86C9B47B79AD89044CCE0AC09FFA4621608F7AABC07C0C76 60B96C4EE1456B998F509F7D77C9C194A148C48B48738A6A0AC12E50137764914BF6696B7049 C8F13763949F04D6A5302B9E266EB035A11FF5EAFD296F209A3FDDBEB62F1C7064CE0C449A70 A29012E041EDFB71C9F93BEEF2A564FF2D8B248579769A81617ED8DE4F232577E0CD2CD650C2 DD3329069017B0B427651E532CB6D7602A81BE2626EA6AB6D0C85D69BFD8772D62DF7F6C86EF 67C8FBD17F2D2DF34DC52256C72181093E4C876D86C9A66C91A8AB1E01285763EA93EA6B7A4E 6131497BFC536F69B7C02D28E4645CC6FE5D061495512429A1D3752BC565F769A4475E2C415E 8CA4985CBB329D49B8AFD45498CA630C3CE56E7E26CC0C4FA9446D3A402D66E39E3E3210644F C9A9E0E4445180C672C32734872703910DAE90D102252EB56864F1CB6D1FB8E4A51335136989 08C42B718DDFC4008264791D325E6633CAC13611B10672C263BACF0820F84B7134EDC9E2373A 61C9C8665B25AB7A583A4983D30386AD84EA9C7E021F64C9E54F3F9B3A3D3267EDE3787DC949 BFB2AAFF21B6CECB88129DE3200AD2693B8B454B18CAB17134A471540C009EE8DEFFD2C70AF0 A98320EDFD6909B0B17C3F4B857D1FE5D963EDEEDD8CD3077A2980FD1AB6DD9AF5B151BBF7CD 6B645FFC9C103E45552F43CB401BD5F084116D21C958E1C1450973C0C393F4BA75A9EB1C5438 9CF6C840FEB5BFFF673E058D8738CE2BB8C07CF0B2B5A837948FED64FD7244D5B5C53303C50F 1187FD6B085A9BB6E5DED081B78F4E486E0E17811A552AAFC50A69CDACF0838029D3DA87BFAA 13D89DE7960E332650E5986F940C4493102DE366D8D574776E019205B25F16B6FFED5AEA7C87 BB558497FD216D2937452B62D8A63D5EC72AF5B83E91BB72BD04CB724B4083C60D2CA9D125A6 9DB5D2F4212BD48BAB37FCC933C471245AB99284671F9E3E7E6A9076117F5CCC8D469B929BD7 C4B677DE5BD0272D78BC0434B4A1B4BFF267C4FB588631B1BC3DE1DCC912E3902D96F16B2A35 0775BED06BEB2F1B7B530CE45337F744FE08822331E4D2913849A0890434088063B0307DB4EF A561810F9C2073B890C67108A95CA581632553F76DFCE780AA175675B186D24379074DBAE021 89DCDFE396A8FC790699C3ED4B7799B30F119D60EA3754549A3CA44CC2F17744DA59E11550D2 B0604AB45A2FFE69ADE126FF2F92CC75EB1D8FA6CF2C2FA2DFB49C1D16F8074A7D7115339E93 C09265B38789A6816B12C803178A72C7C51CF78557D3BEB2D3D5F0A4C53511158145EFD256E7 89DF517BAE8DA9B9B4C494AE42712EFECAB7A7D5BF4668F1FCC23EDAC598CC414BEE707C4C33 1F02821C296725BD4F14F5BC97A15B8ACED9CF5EEA5BAAA216EC582692F7A210BE4F6A41E96C E3A8C65AFDDBE800E035BF0595C7AC0D12B87B4D409DD6772D125249F273108ABBA0973A7CEF 4F1ECA5C9A17FE3071E54E68507DFD8EC6B787DBC547A90C43AD42856C26324178F2E6D2CA3E 9043188372819D3F02A9125A3BFE766E7D19027CFE5980F5E1E1A7033A5BF236169FDBBFD2F7 3EC6D56375B09FA750EB4741E101241CA191B49DE9C681E42849E23E17B81973E903F52B9AAE B07855AD04C30DF51C9D9B54F718C7A11038F8DF63DCFE6C2728E69E33AD933A517CB08D3DCC 7681F673B2E17FC38DEF47E2A2F7FE7173C3B6922EB57CD9D7988F6D3A768E56B46AB8C7EB9C ADDACEFC45E1E245563C0A52F719FCC81C635F159013EFFD5432C697C105CDDCDE49CB5C5696 3CFCC2BC4506BB906910876395C8239C8E5C161471B3A85A353ECA17FC9BC12B805B05D53AB5 BEE2625109ED742C14ED2B08C5D19E7B4D9700D6D3191358D481D2C0C74EE8BDB1B7C40C36FB B823E5502F9ED6367AF146BC4E07B428F90B1E42E6D470958FFFB5C863E73B1904CE37B9A8E5 90196BF43079DC61FA5BACA8F312E8E8A9B707DBF255BC5B3DC1DF58D374702DDB45265644A7 BE315FCA2665192E5DAB08A6BEF085AC370FB81F2267D4D1E05BD8D69BD3D01A1498020A03CB BB8BB7A095F10C9D88DA27301FBA0AFBA4D3B056D38EE6A6BBC532B464630BDDBD4CCBA50C2D B04E49AB8E596923BA3495E7566268B226353E7DCA7B11F28E795CC39F974F426149E0C625A7 EF0B4CEF3E3A5C0A964BEDDC2AB981E564817B963022BBBEC1BE0FAE2E05B6F5F41648FC17F7 9A65162E31A88D0ADB71557142D8545CF2F2EA1A0362E2FDE496923A87C8578D5482C51C52BE 0852326DE3D75F2C6C3EF3024EBEA779DD63F39BB8E2726A7B49A901E3BDDF9586DE02082B13 86FB777D9F09DE377682E14AFDDDAC3E81F485B21CB2537130EB6F69A77B87A702E24BBC2070 6467E82621211300687F18FC809E976FD8EF3932E5213EEBDB9D184D31433B353CAC68BDE9C9 6DA802FACDD168E79491070754E5DE227FE2DBA96C51C16D8C8F0EA9B302A398B2F9491562DF 08AA4C97324B6FF2FAC68A5D079AAC79CF77F0249A0D1C42F441BA372744951077F8DCF83A26 575EC5A87AD6DD4F95EAA1B7F9393C27ACD5F79CE6031E808E13A55C3829D158D1E59E177FE5 0E87F3CB39A81F14F35645FCAF56EB49F5EC78EDB848B396C72F5D928E3561240E2DEDACB37A 994154940F412456119657381B52EAEBD728B026E87FEB8D7EA1EE49067C5D6BDBC56C578728 820D583CAC747F243F6F4A59DCD5B91CFF0232F18183E8E25C76A2C7D53E6823899D43FDAC50 4221799C56EA08F26BD03501FABFDCF4CAFB9E7E2ECF335D8C25F99D40D91B8C93BCEC6B11ED 9671985B8BFCDACFD77CBBDEA246417FFCE021DE54FD0AE4CA7AA19A9458426161513A0F5D7D 4BE2A6DFBB4D6D060E5EFB596F76083B53EBDFBBA1EEB78137466AEC283FFD78BDB6DFFF9748 E47A24614104CEA06D88693EF2203D8792EA5333A697E7B7CB488C01FD76AE792AF0B8F88F02 7CD4BC3EE5D4A09B968DE6B56DC55419A716DBDDB733F1B86A27CDFB8B3AC29DA7613E6D9042 CE9F648A058E2321DDBC10E3374366D6BC4CD910DFF41037CC909580F4650338C9CDF3EB01CA E0D33DD1E1B41524E0F27A77337BEBB6E91542F599C9C7A1A4551D90537F985CA14DB562DC34 A07F072202E86FCED29D1181A2B1D57CBB62BF6E5E7702A00592F8B018A12C826E569B7103B7 8124D887F03A935B54255DCA6A01F433308A55A71B305EF69ED070CD7CDA1AED6BAB529BB506 970B92DF62DE28C05F21C5FAB79AE4BF3A8B2865C408553CF4CC12E3DC69A0E3A683A637D2BA 187CC5C615056B1853B349A1B88EEDCD9748FCBDDAE70100551ECF0B897A0CEC97A456FCB787 49F74B25168181B75AD5F523F4408BBCCB011D55B83A63A0D96052FE523DD891664A613652AE 3A979AF585C69FC4C34CE353AB52C5DF99D6908E1CC86D89CB6A138F42FA4D472C48E334F334 9B2C47DBD9B6B6A92004B7D3C994EDF5B17F1FDDCAC72F8EF393838BF5280CEF41B803513605 381637E38638004FF04BBE10C46A8135E0B5DB123C0F2F6453C0B648124CD0C7E379742950E4 B7CF205BED93FF6C0439BB3BA0DA7B9C2C9FEC48B5E49E10F944D2F499C6FFD3250F8F7AC82C 93EE7C6B63056D1278871FED6BDDE70B1530118D556696CCD90FA33010B35AC56176D0BAF342 AA846BF7B1A95D98FB7C05D56B4FFCE922F6DF7A09BD8802CB536ECC23C89445544F922DE501 700910AB28C892BFB1548C48FD3D9B0BA4B5F5CA44DFE67A8E2D42FDA79F9473FC6EA646483E CEFFFC0254E3F930C4732C8AA392E4AB4E26064CB1A185BE4CF0677CF1706C4DC8BADF32285D 6D02D2C4806B6E0E2C5C2884F30EBF9BFA16BD7BC9E2B779173208C156927D2848DE30A5B3E8 622528D9DAA63E06D14E2E368FF5331279680849F8D9B5FEB448633D444CE06BA1F3C8831018 FE7BB9ADB9A896AA75F9E489E9B88342E424DFFE90976E4700E6C6EEDAE9BF6280AB78CC5805 93347841BF10EECEDB86AF0CD461336515CE50989396665CE975D1F1CB0BDC36B619F67CBDB7 B090B04F447463F62927FCD0E1EFA73BA22063732CB8557E27969D5945D8E82F4A5ADE094068 6AC760EA8FFD127653F954F0287C74109997F1B26328FA9556C42C7B01F0A810194A9CF0D716 D252504BFE2C2707456A4422E84AD233F4B32DE1A825F72C45083C7D7742B6168565D48AC1D5 2F9192ABB0D491A9A0A9416420474D9EAF1E146B2EF1F703B2B33838C4163DFCF8242CA6578F 37CDFD4144EFC3DBCE88D3754AF1765E677D670ADEB2FD2DF7882A4BBA95FDBAFCB9E09B7177 CEF80B03DE222CB6070D7D7E09FA2297EC831D561A2069F6E95E9EEA70E41B126893ACB834B1 778BF4CF338A63F53E4828D75ACC76E29EC822866AB6C5756BADDCE0E3181837E1F7DBAB1405 DAA2231B88E176444594000F12C8351354F3A5722E9E4C376B983CD441D6D465F3865C8111E4 7604C61A04CC59D185CDC89933B13B3A9A15360AAAFB18008FB2048000622905641874659693 57164FD31ABAE5FFD1C7210275EF0198C74BD7F04BC02F9012A6BF7A8B9CCD76D4F449DFB3CE 7CAA4FDB6E04DB1099861B53FE6A8497AE454438A0099C7F14AB799B9E8337128ABF5C523F79 49E9931D233E8466029DD3B7CE86298700771876032656034991E213CFB22FFC1DCBD88EB6CF 20EED29B983BEFC5889A4589428151A249BF85A7F38E5F70CB6F87A706A7A057F63CF366AFD6 AA4A481FCF7F848B650CB9442EDC33673CD98F8F895F4D82DDEC9AB457CF21EBD339769292E1 D17CA465997DCE5A6829C57392E08C8BE708ECED1A9AE4786EDA0095A05014D4AEB167C1D1E7 83F9EBAEA78816BCD4AFE2E5D356A30828E11A5641344B3D46A3E8AADCAF22DB74FF57EBEA7B 779B7C5DB027D6FDECBE1B0DA2EDF3219CEC627E64CB3142D303027F74E694A983B16B33FF62 D1B0E114CA59B30D2261AC4337DFFD0273ABC09B955E740E6ACB4F20969DA27883B3C162810F 194A9537F13E58865F2B4611D8B9A9C4A59586E583F9BCA6E8684C982FBB42AAFEB00F6A2428 75A8D5246830E5D9FA8B479C36225D60C79390094C3820D9D20483BD8B28C5979DC27905528F F829C14E346511BEFCCB0CC2DDFAAFFC69FA01F2DD592B0A554C8BB1D3DDEB53D871DE3048FB 9A816A40A5EBDC1EEF6725B59F6EFF26E4DA46360D4BFE49BF623955485875028F78DACE31A4 B8F4771090B36B82E0E91C9F6B63DEFCA85E751F3A1E6D47FD674B6B75D34CF5D230012A2A02 EA49017E9AE4E22440C836923450A7CBFE44FF5E90D9273FCE99A56CB0B4AE070410144DEA9C 75282AC74C8D426C20B54D48BF5E893D9AED7CCD4EDE4B3EBBF29320E9F98E36571E545C09DF 06B72ED2DFDF058446FE62D7F591326F7A0405718B97692CAC9B02D77A37662F0BB150102D5E 820309D5E1D4DBD95606111A4C5D0E606F890732383B96D58065880C679C4FCC3F4FDEB870E0 022EAA40D367A1CEE2E43C31B0ECE28481217A77201B361541D40C4C7ECBE26EE0263FA70942 A9C4F90B986284113943E170F7C6283447E8862701E31BB28A72DEAA7669688BEE2939086378 99339AD8C2C1BF9558B06446864DB50526FF514EBE3122A3059BF27307F10BA5B44ADE0EDB6E 2693D7DC2B80E1A84F635126960FDD3B6110E84922D484261C92C8055314E5A2E8FB6DB0A904 E291714B4B1D28E2F88734343E42C06ED7DFF193B1871B028E7A0AD51249B36258C0EF6A5165 F5B7AA3061F0ABD6BE779D7E845D6606C9576314C04E98902DFC7CD027934BFE804B12F01E9B 5438301E280AE84371CC2BECAA06AAC7A65BB6B3F7B642207D730AEFFD55ABB33B8FFE0FE0C7 B16356E092BB0360FB94F1E8A2FE7FA999CA66B6675025CA605A65540F6D5619887D7E1A6869 2B76EF901AABC5A15D529F5BFD446E04E95A1BE213EADB545806854ED5E346813ACC82C927E9 DD5B45DAA1C1D57A2B451FE91CCCDDACEDE657B9E37D605CD4D6001FAAA843B9EA84917602A6 7519B99DFCD39DA8DC60A1DF52A0A0C8CD35BF9069C1B8A534B4EFAAA4B42E932BC61FF11A84 6190E9BB2111D13F08570DD9C9934D0C1DB1EC459A3BACC8F10BCCAC2BC8270B7774BD3065C4 D146548D1959395266F420EA71C05EF4D37ED0EC391890BAD4D686D3D0994B98B9A2629C2B66 88E453167FC651BC70DCC608B453FEA208329E9B93BCAC1A7C9C5575B43D32708079AD2FEA25 DB03A13440388F8A4BF9C5D9CE42281284C0A1FEBE6B7BF94B58257DA32011484398DB2C2856 23803D4E578F30BAE73A57D039A2CDF56BC2A625CBADAF7FDDC7744E8586D8CAE909162D2A56 1FAF91099DF981C72617F43F1E8DBC986A1944B370DDEEA5CEDEA04C704BB45227680EE2A7A9 1D5F71C8B429D5A1E22C557932A19B669A6F7D60BE8B5A1A08538D5396492500E8A30D8F085B 9F1613E18FF8511D8F4ACEBC9DBD742C6F27AF4B62026BFCE268E3239ACF3CD0C54176F1839C 9CE2618F5680353A0D234181172DB3A14523D69A204CC7A5EA4A9CF1D78275804D60D41C364A 8725CB1B72759A30DC5E2920B76E1B486795CCFF14FE6615700ED97A1BD4CB16090CCD430640 36FC003368B1E949D23BE8E7CCD7F4FC6F54BF25174B56B42B505E99BAD37A9868A92C29DDC3 29F1D5A84806B9382870B3908CA87C3F840341E45731E5B7EF5B066AB120DB45D72B0E444BAA AF4E948B34D354C244263505EF3FA995E2DC1177B8EBC01A6E2C7AA5766CEE90D3AE7273D569 87BB665A43B4697A0EB98C120EFAB3C61684520E148FB5227939D6208E30CA72FE0D661B9792 C8656B44986ECDF77159F0ED52F695DCE64595A243B635A3B4D328F73D248E1F8D8244B2285C B5F6374E32B2FA7F2E29828E177F81938E2AA1C70EC9226DC45840F8F7CE4A377D32FE6C6550 61389B70C4A5AC6D62FC03BDC16B1C15A79DBC46623501D263A948BCB2747E85EC1D0DAAC606 206398A2FC008F369B673FE9C12A1D4D06D80D625F2412FD8912D625F182307FA2731435CDF2 0C944C2ACD5094A89530A6CF54BA8D347B3819B31ED56C55AB6CFFA8C8C3C0D3C6034FBA9FBB 373F08C76E79F50400FCF3D1F65CEEC11C3623706EEC7ACFE84B89510867C0B2FA6F25996733 E4CC394872726138D7456CB398052F4C03705E27BD85EE755F1992D1C6D330A95B6D208ADC76 D4CAE80A78C75AF6AE4976E564F859429ADC4DE87D26A9A6277E14016491D69C6B9368A6DBF7 2C68EE9B4B32CDBB6A186728B354B347DF5D5F33DB9CC2F757B113EFC0FB491ACDBCBCD70D0E 8E22322E6BD3336E642C6C48D6DD0DEC32C39D6E786A99702B83F644E3039DB0BC3BF91918E2 41A1D20AF0CED35FBBCF8892858762FFDF4D855DC043CF348F64B9F0EC40B0D58F1A267C6567 8609A29E8508F0F5367E0528845F666D3DEED15A880691675C9977278FE5A0C75C97F10E201E 97D255C40BE2DF023F3842ECCC0F474782716CC0697D2305D2894B2149C94ACBD4DB97A8CC49 317773662D6533D2E3BA293FF6EC3BF29B897723B200DA0875803B40FAD899E953168BDEDEC9 75D3461618652733F9F1AE97FA05454DA0C39B27308F81D6624E7ADD0E909A721B0B5B87C735 A0F81402E1BDD37437951BAE5735BD2D9C5A201DCFC832893AA343A6E4C8F879BF7ABA330F71 AD22AA121C49015A6E1B4DE63337C3C9B4BFC3E8456D25309AFB76665AF8D3558841D95E1577 87426288F3A108CC0388A47FC77672F9F837AAB1BB03395208BC7800F59D883023DE8DE4984D 3550AC1E435A4A9EBFB9024FEBB3997847FFB5AC94EFAC7E480B15F49EDC4E1EA47CA691AF89 E372FA1D51A68D417DF4D7011D8B129191F8CE9BFE2D80FC9391E51539A8EF2FACF34C91BCF3 C5C81BB7A3050E0EC13E3CC2D03387335B307D3CDEC0D43A6C2F348C3820CDE916070CDCB485 D1ED73B708BD083E4653EF4F4D1BEB104167E5C53243C72B5DA52CC360602297B86B012DAFA7 BB0D762D78D7AC49D84DB797D4BC25A89309E3715BAC2970BB31C959221EE2656BDD93B51D43 0644E3EE633EEDA51E1AFF403FAAF247B15DF007EEE990B21ED684D260AD6B76028F80D65884 4D4E8BBE91DB43DF55819FC456B9402805DF67958AFD45DBE94E54968ABD3AFD2C456B785092 7353FB25A936D9D554A21262A3CAE1692F978F58BA5DB38A55548529695BC0A455AFB4BE3128 FE733C7234154F4BA0F00CE4ABC7C240C9283831E9A7E0BECA118792AFF6CADF3FA74A572F1D B4789FA83E7E9881E48568814E40E4235A2ED72E8FBDE71ED0FD40D348F66D08E56256B0EA0B 46F54720DF7E39654B4B7B23CB4863AB341CB2045EF7A71A9AB550E1C14282FDA3B60D306906 09B9A2F535670C9F7C6062684E1062BF1B1675288E002412AE17FB3D63125C4A577D3BB97C12 F4CD925282737CE2DA3C2E11733BA9B5DCEAE115A0EDB3ACB8BDB1AC0F687C829EDA0022D654 DC3D051BB7325CFB66F96C7ACD1A8BAEF2BF65C167DF291DF762720D39904AE50708552D754F 8F43FC2D5B91B632D2BAF70C67D3AEA5CE731C380333E66A149E46B32412163C743D128F52C1 24CADFB65399355B4BBD4C0A3FA7C02DE323911051DA20124B77AB931989A74D584C0F6126E4 31C6DCCE725FE72F83CCD0CB35F2AC901501411270FE902BBA4E6A4C1DFDF12E2E857221702F F0749C495E170F01578BAB3827ABAD809BFED83F6FFB243F40DBED47F896DBD37CDB7D63FD08 673E13DC24F4052E1551BCC080685ACE8D3184AF5A1818B4D48811F32DF210C8F36FB6A20C9E 239FA888CF0EE5BD1A87F15C3C6A3E459BD006A69D2C027A09E83541D4ADDBE98FD665AECC35 C311871A4A67FD59EFC06B2CDAE51F00659B4C4F9F79DD824485BC073CEA94DBD45CDE541355 F7244F5B5BCC6C76D82FCD1CAD3E2D08175A375098DD8157B3E30184658EB500E224782ABBA1 297432CC25FB54ABC54C8CD85667DD42BFABFDE7FB7A4E83107AF3AA508F9B20650AB6D01CCD AD374C67F31A666BC1F505A6D94C0C94E4E73EFF7D57FF69F4F145504F60A032109AD829EA90 EC25B66869ED39434EBD3154E4CE7E044F01AB126454339B41193FA9618AD7B49CA2A9B2B595 684A35A5534CC19A989D5F09DBE09830284F895A4876FC5F7920061B06CCDCCF168D5022CD6E AFEE4D796BE4B9BA38C0AEABB4B195B81B621843DB7DF74790FB46F5C07426C8A4FD0D9F99B6 C0A26AECA5F89E36FA8DB06884AC9A3ABB1AFF9C6889BAEAF13CADEE3F0CE80E00EEA152BB64 85BFA7B5AA02BEE1905EC4F666449CADC026BA91B9ABFCC5C2002950D35ED46575004D566225 82500274E2ABD691D0013343966037685138B76C4218BA60855DD1A35E4505273C2CEA443018 DB1CDBAE7DBBD948C96F5DB10BCA8127CCCAB09705EEC19399F31F3F8AA774BD4EF950ABD0C9 1975B346E7CEE612B6A4FAB61E6CDCCDA47B51D499337B98B0B6EE8973317DEC69E6F1564868 A50EFDC5086C806759EA40BA0F036E86C8E76A6346609A7D87C6FB2FD5FCBD9B1744FED5F412 E3DC55E519A941C4193F66E6E4656D04BDBFAE608110803F9C72BA22DBEB7AF2068A1425EC76 E6574311E3E1200DFDFCB4A0830AFFAC7809FFE3404AC5EE8ED43BE8425C1A13904B1F9D220C 9A9A6B9295AD0B13BBD63E1AF6AEDFE6F54DA8AC585B2FD53AA94B2CB65377D10EE13460F6B3 08BB6B3476DDA5FDC5EE7DA695EF118D79051184BBAC35EE74D6F046F17166E0F12604157979 399734F16985182FF1BECD19131570B97A817C7467520EB148C3E2887020F8C09CEDE0A54A25 4E0311A504A411407EA89C2E916F60F32C4BF8456EC370ABF03D1B2D95C991464EC963368441 1664CB33186BF6F897706F7C500A9D0AAADAB811985D1B741AEBB6593FBA0E07E004E86D87CE A653B87CAB70900D1915CE3D19BE1969312EDBA894C541F1227586721DC33555FB28E81307EC F93F164399A58988FBECEFF7CB8D1A751B4FEE0AD6D2638B97016B2DBB034EBD0528BF06C08D E822804EECCD4C943ABAB45490FE47DE7584C569F9789E8C1F213C1924D196C63B3D57DF4385 FDB9BB4D584F6C4B736D32F0D533C3699E90D1E54C3F4ED914A788A0C364F7D5571EE6F61D85 E5CDF8315FDEC93DF38BC0C7E5BA9DAF885F99DFC9262F77BCD3137289B43D2C433111E8937B 5CBF3941AED5FDF09ECD0971144E020FC64656C88A01F9B749770DA845D7F690D1C12141C7DC 8724FEFBAE909D2E5383083402BF005598FA8B67301934E98FEED22625CC852AF51E7C647385 A14B49EAD19C2BBAF578D35943A3B8CC943A863187AA79836CB71DD8DBDE642E1813FF3C21C0 90F3A7BC39AAA1F5242E8BF68692A567578A4795ECF926CEA68CF77CD6B6520367BA3C98CF22 D618A2764323297D1F2E210637FB6CC84674F01C04CBAB1295558A148F7F94F64900596F834E E0F333DF86C59200992C77DC32EB5091B7F5E1061F75EE9AC11D4F7C18D975FB2AF04245638F 02FC7475556CC1BAC14F33D0F36CD94CA20CD24AB4B587B03D968175388ADA63FFC99E11B340 AFC6C97381612C825A4EF6201B13C813BF36F5897E6FE3D95BAE2BCE401CAF0F9D7F1D0729D5 0D6496CC99DBA29E2300A5307420DB31875196A26DCE6B59453A810B704FA8ED0E654B02C36D 7D3D870DE8CE82532009C4E9F93921A7B088EE995060AC598E84F5E1248864269A2358FF4463 A50134F113431776066909C2B52CE0114D3391142F298974219ECF3506BA1830359D186760DD C7E42E376A41B17ED88E6C429768C73F52095F491784661D89815ED8B71ABEEE1922DFAAC7DC FB2E427C480A235F533F523C7B4CCDF7D3E3E7C73BBE89CA8B04F89BF496310792B445122235 F55AC0660CAD4476ECAB30D3FC774ECB381ABFF4BF4E50BD0954E240AA7DDF07924D53BEEC0F F8DC680A30F8CBE921F5BCDB02BA1CAB4C15143898C5C6E9DB4B88818299C4CE29F78E88052A A3D4F68DFD93BFDD1CD6328AB1D2C2888FAEE513E922320FF0C084E617BD1EEE5442DAE79108 B34835214A330742AE9F99ECE561D29B09F611EEB154B1498929A4A6B3F09D63461489AD6EF3 15AF77054026DE9F8120FDE0BA8012710C75266B9C310D06A842451C5A2B1AAC9433E08CEB23 A872593F49C0397A1AE1A6443E4BB99C1E24AF85DFF91C97D4F400B3572BDF28174C5C358427 ED6CF1645BDC283910C47C8C5B112802E549F1D60E96C7FB2CD6F0648F2189B7FC0FA2652152 CDCFCB1B20367A2033AD1188576017E0F1272E701A5FC7BDEF08BC4104D728074573E40C87F1 A2520B3D02EB8CB23CBAE6449EE78BB857E3EE7FA228F91E8007B848E309B38873EF3FE1212C 1635404DB7A0BB06E21EC03E9BB358643F9E9972015362C58BB56BAFB7FAD31C60D0DDA2A30C 5B5FA028896FAAF05A73AB8610BC521DF0226A922DA532FED3E6619E58D9F76F3693269506F9 CAC08A56B7EBE8F9C8759D617BF44B03C2510C6235AE30109DF7DB6A7A391342AABE9D153366 69F98D88DFB213F19140A52BD39E2E66BE39BEFE92B98D7271917610BCC240AA5EB2406570DA 33CD0B66FB032241BB148A0F200E3937ABBACC878C934BB65A41D01805285754E9A3FD0DFAE2 2C434D1D86783EE2693D3FFDDD895F8FA00F83417BDDD173E11F9E1E4119AF293F58B5DECA41 B5D6F4AD983F668EC561EBD5F446B84FDCA10865202528F60BC54003413AFE4FE3E89FA6609F 2F21DE8D5AE7D701FD349DFAE556D6EDBB906DCBD5B67EB59B2B22AA1C26726A069F08AE407B 6AA179E313A4856F5878007837D6771DA41AFDC5F9C341F5505661DCF8D7E14A16E9AD360685 7F67D8E9C62E41E5A505895FD0386DA34679735DEC0E3F71385009C45C1D2B9FC124FF7844AB CB056798CBDD336AC5462BFA9C012966FC34D9628F962285857C14FCD4FF243AA312F6177937 3915880BB730E4F075DC14634C01317641C7E1C3994B40BB1BEB74DD2BED0D9D43DB000833A2 ACC8A6F297DB5E7962430CC727C03462E63C2DBAB60F6221BF5DD3FFB0DDE89EF98BC1A5C6C5 C59E6DA88A4DFA99F5DB8BAE29F26E34B421E7E74C2C05A8457F605FDB727DC1135AB363E3B3 9CA32B2385BA24C78A1E0C83D42C513E3383B28D9554D2F5DD6F4BA1FFAEDFFB8923C183E35F 75C57CF48893E4CCA18087CCF8C84795F8A31839EF6F6CA25CC154F6CA3970F60126B252465A 76B1EAE8B240FD387AB315E1E710A25B339DC2C0706DA7B1C47AD15D5B6837F7DBF5A95E98D0 EAEC6C121598076C6BA66E471C87F9947929E01B386BE55EFA5E6067CEDE9F54B0B278ACC43E 56987848ACD559621B05C67228622540EABE7183DBC1305FCA26654D9BBB734355ABC4AF90AD 7A7406D123A73695F77FB049B0CDD25170D8CF8F9A892D3636FB152688153F58E333849BE3E0 45F8E18A4EEF42F191FEA6F2FB54206C981FFCF827757A22E75A7FCF21459E7C42FD5194DA16 D0A33B32318FF5122EEF24C81D4C3B9391DC8D209EFF13FCB43FABF1FC67A712A53756EA65E8 1AED88C0BAE56CE5DB00F2F3BBD89AB87B9D4C12F35FF1C95D8F3DBB7AAB138E3C387C135A32 F00FED1C25B0F96895792B4F0276C3E2D702816D4A686DB2662E06451A3E1C3A5F6AE239B240 505ACD4DCE12BFFFE205016956C6D6B986D2163AB20EF7B02F27F9E0F3518E5E51D7B8A81B6C 6C0CE8A32956C435D20CC226D0F16C91662A32D05ED7F66B995F3753D05B91B030CDE048D7C8 2885174A896F22FCBE7625412362C5D6A664D9BA41504DF972B79C442B5232B8EB90DE4C29CF BA9EBBDFE5B37F91A630559F797C22149AF8852C5EC4AB945C8A042E5DE43080684F4908BAD9 69F290A1CA1FA0E916B6FB802C7B15D2A54C8AE8E4EDB91D926DC622DD5E42362B4BD9266222 21607EB032181D92A5A0666424921456F2198580910938EBEC7902B759EC3B66A10C946E53EE 98DD1D28970D44818C30C76FE735F2BEDE5526E47C64EF7D0D74C7564DBC64298D270B264658 6835DD7E6255EA99C66AB9817F4093FD2E219FD9E67BBACBAC0A9D3E678111BC985151D46E06 CB7B326E767512DCE309A0B40AEBDC854EE7A3060CF8418DCDEC028CE80577FCDCE3CDAB46CA F8A84A66E8860A034A390B444552D669C1C1BE764711367CC71152101FAF804C36E90D4E1BCA D89392929F998314FFEFAAC52FF96439F19C20D2EB9148BC6CD80C8B5624CBA39D84ACCD5525 23A42A4301C7DE9AA5637F717C46D0E57350BDBD4F0ECF575F19FE94D69C213777FB5ADD543D 485B47F3A76851E8C57AB9574A00E9A99641279642105707D75D97FD49E4FC53B79EEB0A8689 E88097CCB46CF8497977406081C7EF28A2E7169589F595997348991FFBBBDD8DEE44ACCB0C98 968A5814783927350D73DBFD9AC11A9F571AF46363E6709987C46EA207622FB319FD5519E7FC A3DFB9F784C1ECAD5472236CC2790015D4CF9F410004EC03AA9C247483F9134E742AFF8E3D7F 62778DC6E9CC87469D083E9849490B66FBA43769044FDAD7F59EBAFD5B07A7FE75F064CBC81E F7023AEB4162A787F1C4D4005998D969DE4C7ECB3A67861CC5E13F56F1EA7A4EB7521CF0E282 F513803658CFF5FA93EF5B15098FC2941FF4E0D6E2DD9CC056BEEF2C4E15DC0790291D385E09 1D2CC377FF252EBB7214C2CDC948A9FCBAC418A93CEDC58375E3DC347F872DF735D0127274DE 42F4E3709CD11CBB6A0320647CB97AE4531FDC8CE56ECA5CFE4DBB83B3C71BEF715ED3E0E001 F497042D7D9859A0FCFFA87D37FF66BBD4C420913CF0600FA055C3CDD6379C8DAF78C8A03267 EB381B64796CDC066833EAA949F74B0ADBE615F62C0517CE582A1DB047288C316A2B501D45A3 62B46CC674C913B8980DED11D1462B8C03EB3D93BFD47D33661C4FC89E49ACDC09DDF08B32E1 4F876BA1F0CE782F79DF52F10671BAE136A9B6D5120A011594F22864BC61600575D5D958678B 94D71991D55E26263141A80C091A2E356B9DFC5E718D0833309431DD80F5DC39AE470E1120E3 0A862464C96C1957C2CAA9DDB5FC3D1873C08A7726DECB5D73711461508D4F0EE3B3D9DE4BD4 24D60787721A2AB50ABF2F02AD9FB20E483025AFE53CCA0A54331ADE5D5859D3621820CA0E2E 3E7591BF4BC2004D0B5F7EC9A1141A36B0F1F9E32E46EA6C6730DE24D911748F83710F8A4F02 A7F5CD663967DAFAA7BCAC3E29D900677EB2351CFAF46A773D363CB7D48943E1E245068B8F4B 9434EE8F820B79832A8DCE28E3E36DBA17ECD3DC93F38F6BB4505BA7580B186C818A251E38CD 7DC03FA7EA1AB8D290514909F1AB56E1B2C6584E86EF32741B58C79EAEBDD62F7864C19554A1 9FFA1E73CF2C75D00C903BABA7E117E56B5EF27F53C94AE007DE0FA5726174D691F0CA7218BE E50892C6CEBED4CCE891EFA7714804AE54761D8F0379B063B8F8037A0B488A487FA3BD0D4B16 B34FD4B3E52646AC3509C5D4C7C191189FCEF1D1131B4DD9799DF6E8A556049E28C5ABD4216B 6CE52A1ECD99432D8316093235BE3D91885DBF346E18FA2BAFAE67B650467D23196FCEAEF414 8A2D9BA1F44B3B43563450F006D5767D86D942710A820EEF0BF57028B1F1291C69118901B5CC 99907C205C919C81E80ECEB1BEBDE1A67CB21D3D7AA431E0D1EDBC1F4DEE88E91FDA97DC4C2D 49215DD18458B42106B452362956D407C064E29048513A2CD4A534062EB007216961ED4566D8 CC190F990662F6C60703F35F0D8D643578E8205D1FCB0119C20D43BFD046842D885885127653 65E7A007E770CE8E8F5B20FAF8B602E8291D93A7B56F8B2E5A952BD803C196AE98C27272BEC7 9F806903EB3D3695782940138CCDBECFCC06B8A46907159095CCF0E792EAFC60435D33BC41C8 A28617BD5A5228172CA784690311898BFCB7A7B22CDA56A53467E6421C413689CD41D59A3FD7 FEFE1A8420695909716B8ED59AC6C3C83F5C0207463A369C369BCDBE4A9C35A49301C952664B AEF8BA31541DF5C1400B708EB3653AB8F8A7DFCBA52DB26A43CBAFAAC4960E4048EA7D164BA6 ABE831276534750D13251D9421BFBDDAC7E3A6C61948333060390FDB5DD7AB5A42CBE7B00367 5AADF5B52D8F709E45F66593B51519A4B37F8D0408554DD87783C103C31186E170788E8E4D5C 2D1368D35C90BFC155335AA4585F371BA0D2D36C12F70CCB54DD316DF4A5B928CD36921BDCD2 80996FF337E7AE9C4C0DA2ACB795614ACCA8BF9C5F5A270198A99B0BA923C041E65D34D346B2 ACFABC9A68B059FB4EDB2AA741A93D768E5FF077C0CABECB321866513057B12B25613F5B1B34 78334FC0FB18085E27A7361092F84F475BF19FC88CB9D9BA18AADC63AC383CB8266E01374F9E A36AADC06168E4772D6EF439FB8FFF2EFDDBAEDD8149168F8525EB7D8260A1E9165511AB194A 91CF9358F1DF26499505F3F2DFE1FBDC2E28C0E5CB48BBCE6D03EAC7A02AAD6DEEC7FE18703E 6DE77A677E9C2D6D56EE24769908189E8ACE09C55979830C1DEB6D7D00F931888C2450ADDFC4 15C25DF4787597D0E6499D3ADB097738BD599479CC4E3488524983DBE2BF7CA9DA2DF888C2A2 4A92B597FB8CB9B285A8201AA1BD6E3073C6B4828984E3EAAA4123A0C9053813FC43CD724BCA 03CAD9E401ECD7FEBC2C9D28363BC8F058AFE54E479D1B518061EAB166EDA2B3A0BFCB5DC88E BA7AD44AB66A74099007FBEA682E45DFE3E6F36ED2F18527AC2A3443897F6E1CE8DBEE7E03A1 C2D78D2BE6A6E7C6F43B828AF56BD8A86EDF9BFFFF971E1A9D56EB626AA2F112324A53AD874E 1B3166EE3AECEB372893205D3F147209C9DE0BA3AADA432773E150617A6B7E4EA8E636F99BE7 60B74902FEE6ECFFCFB1E039BFA7C15E9416CD2B5F0EE6EC50B42351B95B18BC1451F468092D 4F08477516A287D8020C67C29D0CDDFC48838C99B8166C20202D3F5B8555AD9AD5DC2CB946B6 B97FB0072EC9165EC95ACBEB8603D7DB6760B9011A68000687ABEF5966C357EA1E0F94767E2F 601DBD9F9FC01699BB0743B4C369B7D2B009CAF12354D81F73F1B1FBA08623B38E106CB11FFD 6E7A2B88F1F5C5C9380EA7159FF41591EB7E67FA45E4C4315B4708A5842A75B1B9C1CB4AC492 C26178CB5DA50F0E9571F9DDDC6E223B34006EBEF59549CC34548F815BED1B123B012BD2A6EF 67D97FD477B31C7F626FE9826107AA9ADEF80C1A36187E2453562217478157E3B0144158A69C 658517D4CB79600C700A2509EF75A45AD060D0294AB4BD9A5D2CD590340B79D4D8408E856958 D0F403F696B543195888A2DC7CF4CEC3A102814BAD5C169C3C911CF7AF7858ECC33716870D2E CCBA716B87B796159490F25C027D3F04717F355DAFD0DA4737B7F72DAB5D1CE95D11B4A8832A E3563F41BE06ADA6F45B38EC1BBF9FE0525FD46F0112B5CB0E947A701DAEE6664FD426271BB2 B63E4ABA8FC1037F8BBDBF97D3F1EC8C98DB89B3AAFC6D597EAD9EF2347CD5B3874138BEBEAE BB2690B8539DBD000922A141A7A6A2A74BEFD03BC165CF3C7C3B3F49552193A9B453A37D4F4D 0D9B8DB8896B27951EA7103EF7FCD483097A7997AAAC483762FDBED0FA53FCBFC245D32740B1 759947C74E3B19CF333F30B131A65784863F93F8DFE7B7309BD5D5887E943804C3B3B8C3C4A8 94BC3145AB7BDA6F33A0C72D5F70BD538EB8BDFA06FFDD053E6152B10A2CA929E9572783B01D 307B50E86A189F747E690DB2D0B3AA5590FEF074A2515F9DA7635EA85771B45EDD4A5CAE324D 81877E0B6E5C2157C03188725BD5924364E0A12350855E3B39C414127A33361DAA5BADDD1D50 5F386ED72E80CDAC8B0D9CD6A92C687F913D617A9295F75DC3C4EB08AE11047AB7041DE8EDAF E7DE24796CCB9D44640ADA774FCDEB8244C6672A4AE9B282997C5606423E149C4553B9E3E23A 2E03501A5A8BE7AEBC3C16B079C38D2A0690ADB258C414A44C2E080FEF8198107FE7B2A75D89 B4B097E42AA237F789EA7727B2B4BE0378D5DEC71E7062B088A76E92AB2EA36CCA35E39D8364 70B3FB7A7A1C07F37A9F37558C058582AE3F8EB48A11F9DF0A89796785D238393580ED4D425D B670687973E30EA79C5F778B42BAD782152CFC55E0D4E9B5F8F57E7627EEFBD9078A576A57B9 5E676B0CBCBEACC8C685716E7A925BB69072C9C9F94724E389D723EFEA841DAC245B613A3AA0 C6CADEE8CDC90C7881CE3D7657B16594740CC202D4E809F38F2CA4B219B928C335B51705B957 2459489E1C176FA365D867A723B699BE25CE1B51DADBD150A5CFC7AF8F6FA901B7F32BD2758D A52601332EDD0E1C2D334B5BA3B85CCE0F17D8ED535A8E4A9E6DB4F279F081F2BD2BCB319DDF 5E4A649EA13F6702A431E9C6509AE16F361E702BD804FEE570BD4FA7205B3B2531382FF34E8E F8C254253584CFFC2E955CA1BEC100A9A0A42D3F1CD1DAD265F9364D1CA695DF664856D6240A 46CC6473F64BF2608E21A184A475AA145BD925B00ED5CF2D4E845B3764797F3BAEC5FAE70C5B AA6721A0C0571F5864C8B2B2B782A4EE2DA6A91BE91F0A90C6D906103B07CE270FE326711A37 F52D3971C7B23EFFA647A2131980D6825B3DC2E2CDA81D696F9F84793FFA99C6B732939B09D8 11DA361B87FF76CD0F93C965E5292B7033870C44A584B2D2D5725F3C3CAA3713BEB980741DA3 DD6BBB035F2B998D8CB26FF81E3FD3BE87DF7501730B30ED40A1328B8608E0F0C50733EDCC10 AFFC4960B25BA762068BC7F64F878E2641D6077EA532761DE0DC35195DF0F32E410C6BD0227F 737E9167FCA17314BAF216B1A8FBA2DCEA54A863C384722376E8818D723F2EE9BF382652CE2F 635A30498688A711DBD62E9E6E40899A848BF8C35F9D5D5646510113AB8630014D640EB1937D 94654050B59DD22BF74B0C8A116EC54A108E6A6CC82E9874B0BE04191E9FA3E7F2072EB17F72 3FAC1BC71006597B99794AD61A993C36D1E5250C996D380090366F1AE783704041FE9BE38195 1C34150BE82DAFC805D10F73B6D0CF5103FC051DDCFC5AA91F5D7E8CE73C39EF9B7B0699CFB4 0943BF950B5E6750C0DB54B476CEE4719AE515E40A8EBADD57F80A6DF09EDEA191B00DFF801B 2BAB79C5657588ABB23584CEDB768DA618BD0B5D295A128DE877606D49A12FA73BC9DEA32310 0F2960C76E6E8B30401572527611119C3EE06D3B34CCA355B4B202682277464C8B6B197BECFF 0864FEB01BC53792AD1DF825A73E5F92B84AF103934A985D9C65A24FBDFA960325C7A73D2989 ECAC24CB3F8EF1C57EF43DA81D0B64A5306837F4361D8BDD4CFFD94D6DBF7A5F5342464205F1 B5EB6D724D9409ECC3166F3518B501750E89A9B7110FD7EFD43AF3C32E7B93BE8416B7A540DA EE25D1497DAFBE6D30995C0643431041D5B1272BBD2CE5FEEA317B42BA7E5910F75A91525C80 DBDD061D053815C0B251F1BEEBEDFB1567632C46D647A745A2DE0AA08EE35FCBF4D3710C8F5A A6A9E0DB9BB0962CBB7E4177EF3FA776DCEFB988833B0CFC39C8C6B7C89A713DD018A5D35126 4DF859AE5903A5757D5F039B3D65614F2597650BAAA3188D1AC6A8BB1DDE7DDBAD1EF9C4C980 3A3148F3F4AEEF706A7094175DDFDAA29B5F8A012FB8CB301450B4E78B58259DE6503679955F 5509F5025E4C799C55F0CF271717A296B096F03105E61DCEBF5D24698A96BB364AF38BA20D11 7D59E86030C17A30AEB4B1794A6D72E2B62DA0DF92047D6985DF1BC950BDFB38AE13E612E183 6DCFEFE4003A0F3CBC1A7C3398C0EC71A8AC8DB32BF58969635E46788A3DFD65EE12523B8FC6 70A727016094B8381403F7762D6E4329319927DC1534CDB25F620D3FDE4383943D9942F75523 CCAD080F5B1CA86159B6956CE56B5FB8A07B33451BADD7FB9ABABB37A10F04B58559BCE193DF AAD6A9F7763B11167E0B899B5B6E4591608E6B540A81CE22AE3C151A215F316E89D2D4F0FD87 D0E803EF412DED542C369615852466961517B5C77DB3C39ABBDE32E1F503476A8326FBB08A4B C9F04C202CF5A1896BD05EA8BEA583B10E5B5AD45963FC490BB9A9636381DFA47B42132D80CE 66F4BB1BF889DF9600B08038C1FC334E69A76D7FF65144B9E48D939E5497DC67D5374C4453BF B1A9FA6C6685F43B7BF9AC97298A3320DC74BBCD9A432B5D8F8F1CDCA9DCA04380A2D7B024A9 B0E2B4EE3E1325B3C0C4EB2B8A20C97D5DBB73AB15166DE381F7F83283F69479EEE7CD091F8E 4D6DD13C2E78E12FC59042701E7A3BEE3FBEC32693FA48EAC541B85465B9C62D21E71E463654 1395D0EC9846F16D599B28E53BC109C34F17C2A85FAFFAEAFD20DD89D53CF5638F9978618B61 0902E38A9E5A5D6C5B00264D30B4CBBAA2D511646B2CAEA65E716F31B1EF4F8CE618D9E61DED 2BE5D247D4E5FD9C51819F2FFBF3C6702210EE5509C942E781DB52ADB4A65F2DB3688F419447 0F33AA11384BB47EA644E48BC508F8C4F561FDE0B5879FC642A7A9E89F94B273892DDBC44E59 DC35EED991B4F4EBF0C9CBC525C572CCE29F3C7EB313D067885368C2EE54760A151982FDEF76 B90F50E763271B1FB242038148631DC2BA1A3204EF1206D0AFA7B78378AB031F9069B8639FC7 40D165EBF123F69A5F0DBEC5D7EE2016E262FA4B611C383E2BDAC77812774DE0591248C23038 B9CCD681FCB91DA754279FE274DEF1F3810617559F2EB5EB47FEDFDE4B5E6DCD68951E685AB5 06EFEABB70343C619507C4B78CE07D198413323BD6A4A33517EEF599D6F71BBEF63FF166D35E 9D2DBDEF74EBB3CC0A316D11167CE2F226F9F1FFDEBD612A2452934CDBC9AD1FE8FED8406FC8 DFF39820D6F74FFE9B4B70DAC1FBB22F5ECEFBD7591DD4365CCFD300AD9544C492A899173611 CBAEF46FFAF6F94367BA0FE02E198290BE926B80D9B626D15A0AC90D5C0B2A28D55D1323E0E7 FB203AB131D783F6E3F878D1AD7FAD7FACE0A9A91566A636E6FC041986FC25E6D59FD6D535FA 42C1952E7C0AB503A57DFBCA3ADCACF5AC748583F112F3EE9DE553112AD7ADDD4C15DB76F3A9 10058AEC9DFD32C233D5B9498C33E7BD33611EE3DCCE65712DEECF4670B51AE23C42E2512B62 A38D37201AD34EA9ABE5F0B99B223DAF1F96C3C1D4B2EF67FB0CE63B4E1C6EDE64A5D30DD3E1 0A6D4B92CE81C7DC1EEAF96F1F1DA540F94D6C4FDFCB72D408647A4877B54BCFA2626D4E110D E46938DDD15B14A4AD6F8044B7AA6371CE2F2EA1CA4A13ED372CE415ED370F5C6B2EF218102C 1A338C8C4D6004F4962065A028E68439AB20120B5846EE1B66B4396C8F3C73B9A65754D7CDC6 A5AA7E5B4B7A179AC0AC55346E084A7BEB4E344B817E1131C2AE566AD6115AEB56C3169DEE98 C52EE0AD6F4DDF4B05FB7A6B4D672D1328B539DADE8945E8E39873AC6331727D144AB149BEDE 92D7CDA9FFEDC8821A61726ACD8326AE6EBE5FC4FDC885BC16B1D1C22C757B8B594B29AFFD48 981DB54370FDA73FCFAA30DE3ED760B144404F38A4AC17817E52B0856ABE4459AA3721BDFF5D 2751CC876C1BB1FB64C380DB6181E2F3729F4AEB99C49B3D128D2661B2050DB77992E189DC35 5BCB9D15A819D60E831038FFD66708F50B2CD66B62BB8092A13D012FC70C815923E08297C7CC FAAC8EDEB41A52F041777881D67B19867C4B766C5BA0D18551CD1471D53489D807286A6BFAFA 46271735B699E48807BDA0C057CB88AAB5279F5E6F7ADFE5F34BDF3C81A1C5C83DF44D07CBF5 464A1E0A8F0CAFABFDA5992B64BDB9C13E743F44C2F4AF0C9A69503B14D0BB12D467F62EF24F 8EC8BCA1A1D2E4FBDDC856104A67946D4A87C08F38AECAA481D401A98C488E622CF8CC0B3205 1AF70DDDB4E73888FDCE173D8F5FA75062B974794E9FBD6C3499A3333DCA75C681C38345CBF0 75F6B8F49788DB4C4DC96B93F7A166D33BBCF7BD27778ED38290A439C1974AB944D04FB6151F DDAE7C736F1B0A21DDED2DAD0AEDDDFEEAD170E750F81B750ADDA463B2DA2693BA21197C9625 1CA59938E82E5BE892C6C659605C1558A6FEF114E30F0FDB712BF1DC93F2F3D876CF694C9FB3 1622FED5C30CFECAE5A637013C3036CDE5CB296A8710EA0141C47635B6758756CAFAB2A04B92 05564C82BFE89649B1DB5D5F255F925C754A4C3E81D0D040F6A5CD9B28D071687377437A47BD 692AE6867C940BB2CBD3E93EC8BAE25406DCCC2ED43D1F3906E39FB01E1057A837F70FE104AF 10E6AF578B8F557B4522D7BA0CF1C553438B7621921D297FABBBA97103E7F6BC35E48F745AF5 A1383F71CD46EE88A33F3989795F802F0CADD26839DF33C849032D7ADF508880B4C1252BF9D2 3F025344BEBEBAF35333E02DB37FD3F64CA9F17B789D55C7CE6DF7512660D4033C85C44B7144 46D9EEF2839E3D953F81BBB8CCBF7F4496E197786F43CD1CDC39602C40B402B7698E2080FB9B 217433D390BEF7A1B637EE1902D810B11BD1CA27DD4FBE2C58640A91B0229FA8F4C45D5660F4 72F10704E9B9970CB77CB14036C4D8603098B893DD139735CB18945BE26755506995DCC27E9F 94D1B63659B8399E9EDC933DE2E3DF9D113C1410898E2E7A2E40736A7FB7E9979FB0B5FFDCDB 2BF0C4D699EEC0B3D55B26A3FAA6C9E9D06ADB9F4CC1F14B0708986DD9F86601CC4CBD392B36 6F8B650B855919C8FA8BECC44E5B1DE3DE2453FF62E0EEC0F0CF86D2E165F1145D5E8C2EFBC0 9D96F537505EB861BE6D21E9C054C39627C804F05966EC1DCC8FB8558696EE825C11BA95CE2A 7EB40507EA5FA7DAB4DC07BB973B935DF8ECBE10DCE441B82E982FF92264975D92C6A4C7705E 90585A308CDBEBAC9B467522015D492B0A705C10F6C195196AE3C532913ECF9BDF3389A957A1 D6F552BFEE7B1F9648915AC3542FBB1A528CEC05370B2BDD7542685A8E4ED35BF2B8772EBC5D A1FB2E09782EA61A2B8772939F13531140277AC633BB0AB6F2D237399C78CA8DE0E2E271BA8D DEA24B3ECDB0F551107B3220E2C842F8082A75DFFF85DA55AA2D40518D7401179E6BC7E033C0 92E5F71D8A48F571F7C7CA5B6D0F5E4A109F39AA559CD30EF032766F692E47BF0EA5723C7758 A1392999A28F042005B7E667E62A09CD60F807BDADF794076F23211196024A47580DD9739FD1 0E53D04EE4EFDDF89FFD6E07F107CCD9634874E156849CCCF624FDB9C85145CA2057FDE5CE44 8E4510EF1B3FEF2A57E0125B37DF08CF935EE8FA0BAB7CE745C8CCFDAD35CA730A284C1DB31E F26ED4B5C397DDBB2A741049A120AC4D8FA9A2B91D3EEA75D61B28B19FA8789DC945588F17C1 4A81BABD6E0E5487E2BA1AAB46994D69F7E5A928CEEC73DB5317B3D58033895595A1A2188E45 7C1C8845CD7312029093574CFE59D8C25DFB577C949A5E4E56624BF9942AE6F8970A1BAED98F 135CA7565393E6C4F80F1A81930FC3F90342EFCC0819DD02CF88343D4955670DF65B59AB5F55 4BAFBF5A9404241A3274A7D2C90A1E49ACCFAE2FF5D9624E708A99A4C8104B76F8EFBA7A4753 05BF47661FFB2FBE93858CC5039B3279626A7F7B9A1E210662EF101252FA4F38DF01407F143C 007DFCE4FD95CA4FF7993FEB03B7CA5A6C1B6C770D684037AB195AD689100484E7D044834519 7D16231C3C129A3372574B1D261B458247A6604A8C3842EC7C6FEA54AE1EB01B6E7E922F28D5 6566CA27879BD0EC14C7DF9562BF8F934321335C26C8AD8477DB8CF0E267CF8BE322758CA333 7F010D2CF9C2C9BF88B51ED703E036B0BDBBFC3F92D7E0B4601573A0218552C5215532E9DCCA D95BDD11A0A9ADAE050C87364075B8072F819F49464E1BFD5EAF51EA922287EE507223F017C9 E898DF5E29F57AF38DD390F93F425BDFCA14492295773B5AAB849002C613A2B8BAF474C7FB1D BBF6B1599EFE3EC5A49F72A3B69F1F9073A5CC06E2B29FFFA1B689BD8FDDBA766254F68B1D85 C822EC842B897CBBE246CE8CE8BD44E718B10E0535423DE475643472152C4C607486AAF92A52 574BF6465DD6231305CC359045D3641076DBE7D55AD508D7383E5FAE63A768AC188DE72F7F29 4211E87A36F2F18015A3DEF4CC333A25926989AD4CBFE49FB9CF9FD2D9BD167117882F707842 DC72B1932492BCB7062D86EE51437B696BB597F657D482CA902E779B52C727F02010A21C3D17 F1750D4669743288DAF186CF289C59BB4E0AE268FC305ED2CD69EAC3047C1AB6A6751DC634F3 71841623B74EFC893094EAEBF841AC1F5A160427F3D810623098C1F36E0F553E51A11B0248E3 2E1E9B3B092FE2A6B785BFFE8BEC4F8BCFC164B5D7623C123C8C2087F256E2F9D71C363CFDA9 D097D8CA2A02E48FBCC9BFD5DE8ACA3D8461D78FC95CF53AC18EBD48E959E44B1039E84C7426 576CAD6FD4F07A9A328E86061E8DABECD9D87328AC532096DCDFA647DE1C049FA27EE5BC7717 22195AAA84338E6D63507BB45B560220FB24F93DECE0FF3B043D1912B28D4D913888E424E6A1 E139FE7A7DE79DF5DE84E31075A132179ADBEE07F794B129DE7BF93E2B45BF0100949B359CC2 EDF8B9701B4067DA2AFB6AE00EB03B79F2C0EF420B42D9FD22AF9FA5DC68BAF29DD90BC13826 2563BBECB07781B9A9FC1A98A53F9036B10C49123CDAD4EF342C5C0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMTI10 %!PS-AdobeFont-1.1: CMTI10 1.00B %%CreationDate: 1992 Feb 19 19:56:16 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.00B) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMTI10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /CMTI10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 161 /Gamma put dup 162 /Delta put dup 163 /Theta put dup 164 /Lambda put dup 165 /Xi put dup 166 /Pi put dup 167 /Sigma put dup 168 /Upsilon put dup 169 /Phi put dup 170 /Psi put dup 173 /Omega put dup 174 /ff put dup 175 /fi put dup 176 /fl put dup 177 /ffi put dup 178 /ffl put dup 179 /dotlessi put dup 180 /dotlessj put dup 181 /grave put dup 182 /acute put dup 183 /caron put dup 184 /breve put dup 185 /macron put dup 186 /ring put dup 187 /cedilla put dup 188 /germandbls put dup 189 /ae put dup 190 /oe put dup 191 /oslash put dup 192 /AE put dup 193 /OE put dup 194 /Oslash put dup 195 /suppress put dup 196 /dieresis put dup 0 /Gamma put dup 1 /Delta put dup 2 /Theta put dup 3 /Lambda put dup 4 /Xi put dup 5 /Pi put dup 6 /Sigma put dup 7 /Upsilon put dup 8 /Phi put dup 9 /Psi put dup 10 /Omega put dup 11 /ff put dup 12 /fi put dup 13 /fl put dup 14 /ffi put dup 15 /ffl put dup 16 /dotlessi put dup 17 /dotlessj put dup 18 /grave put dup 19 /acute put dup 20 /caron put dup 21 /breve put dup 22 /macron put dup 23 /ring put dup 24 /cedilla put dup 25 /germandbls put dup 26 /ae put dup 27 /oe put dup 28 /oslash put dup 29 /AE put dup 30 /OE put dup 31 /Oslash put dup 32 /suppress put dup 33 /exclam put dup 34 /quotedblright put dup 35 /numbersign put dup 36 /sterling put dup 37 /percent put dup 38 /ampersand put dup 39 /quoteright put dup 40 /parenleft put dup 41 /parenright put dup 42 /asterisk put dup 43 /plus put dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 47 /slash put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 59 /semicolon put dup 60 /exclamdown put dup 61 /equal put dup 62 /questiondown put dup 63 /question put dup 64 /at put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /bracketleft put dup 92 /quotedblleft put dup 93 /bracketright put dup 94 /circumflex put dup 95 /dotaccent put dup 96 /quoteleft put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /endash put dup 124 /emdash put dup 125 /hungarumlaut put dup 126 /tilde put dup 127 /dieresis put dup 128 /suppress put dup 160 /space put readonly def /FontBBox{-163 -250 1146 969}readonly def /UniqueID 5000828 def currentdict end currentfile eexec 8053514D28EC28DA1630165FAB262882D3FFD20326947B1065649B533EB5E9E3A88A87FE9879 18A687950B26F647D6E08BF14D983ED1D4A8CA1E2DA8D985F9442EB916F5B6ED0697AC7C33E1 E36A3BF460D34CE45F1631871097CB04F18E38894CF4AC1538EB19481311D24FE3BE7BEAA4A3 730E8B4831FE59D6D9CE2E46116B629C7BA2F9CE3ECBA2F43BC162A5A077CA1B2882A42AFDCE C3F4B75B5D63E0BC8E5DC95257766D8EA467AD9CBAF47BE60F797580CCED6884B3A68F70C91F 4FDF80FD00ED9139E7F480DC3A76AF72AD9B434187730BDFAEFE4CBFE5C7EDCAAF249204FD70 3011932E5A3C27BE468B7DAB69DAA18DBBB6335AB8DDFDC607961C7C02582763FA069D43563B A17704029945CF42FCB19CF78C51DF0EC4D851086D43C1AB38E865EF36865FFF3A08B01CBCB0 70BA4893F7482DC7819AD03D337E520E7D8CD83BB8AC7AFF4DF36751F4F12AAAEA2B6D7260C0 9A26E987C904003E07237DBCC4A8E4E85CD3259F40D3CAF55C742CBB40AD0DB1044C20A4F122 A63F7B811D945BFA69662189CE4D089464D2EAD9F6ED60B581B04114D5D45E97BE27A5763515 4E9B8464F2A0DF18DA855EB51B8F64D3054B0B2E84621F025A0776D16FEDB988A43D2D64C327 68DD106B9F541AE8E68AC0BB7399E16F4D4BA074B2152D0A4E9B5BFC21BFA0D531E28165E518 FFC054DD4ED0D74ECA079D20E79670419F92E03BCBFEECF3554D661596F6F29E12170804D15A 250D917FFE7A8B6E8FA530471ED97BA56481589A65CA13619129F1E26AFFE6C22F0C38540F8C E37EFB6E9E9B60B51A5A9CB4454FD7C7F92F2F9437159687AB590F35B946A54491A7739C9269 E0F1FB48B129811C82EDB3171CBD5105FE65906974DB8A7DA92F4F43DC7F6B366981146D86D2 3613A0B38D9D6191DB9FEA0172E982CB1CC50E382F69DA1B377C1BE9407F88A2A761B56F3984 67A057F35D18C01CC377E006182C891EC80272E22E3A5C7123CD27ECCDC87392A9FDF63BB40F 02B7649CFC53EF933C6518744CB89CBBD437830EF5B1D58B00B67BBCF4426DC1E6EF583B0B4A D3AEBD741E3FF0F729AE271F032019B1E7268043FD215BE590F9CF24DA14A90F1683AFCBA800 6CEF5D5632C2481FBC1BD8224E8952DEBB7C4596A237E5505AC143180956CA1F603EEC70CDB4 A33E1C4CA1744E08940CE778E246938429E09E84F5D90F2822272E697A2B4EC52EC64D678F49 D5AB137C105A467B7C4FB2B599B8536726935A90145F426D2F022DAD53995B991E97744C027F A0427CD1117AE246514032F3FBAAF6FE9B496D6A2BC8BFB77040D26EAA434609FE89C1FFFC3D 8081B8663582B893912B7C7C56E5753D23DC2FEF5C3AEFA09929F7470ABDDC99ECFCC44C9456 5201A19B8AFCFF6C98BDC87E6A7900F980EA0020FDC7ADBC97FF99578B809932DB7B9B6A7832 222855A0A586738DF9357FD3FE15B89218BDE940DC77842A8DDB973536AB81C2764AAEFED023 A7F0A3090FB38CD8D51AE7A65300CFE08B3574C621CB1A9F8EDBF84BB034A399F6F4237171C2 D38DA96707E2DAB287F025A8D50C192A6200C771DF9E79EFCF03E92C0EB5E66AA1D3A0AF1F40 789D9EC825336FB0FFBA43BCE0F388E21485B432E9BC85AD56413AEF3AC49035CFC5D31ABA69 7B505385DEC0D36F76849FC55012616820E4D2ECC1E05A16A98438A966526344DCBB7FD5A355 2EF61AB1CB2027674AAB594074DC7B4DDF7C815529B9ECDF39A148D855940D0A60AAD8F7A4CB 1B8C1402BFF8AB3EC10D088B6DC9B57E047CB7E1B66645986DC6C9736F707ACF15A687E04A8B D48189A4933945FB77522F1A4DF2A56479FD4EA1747671E0324590BAD27663DC32ADE591EC57 A1414B1332BE3EDC56D6E354CF94C1D793A9BEE0646C69C414ED22905F413CFA73F9291BA0D0 BCEC956B0F15FC29FA7B50C20CBFE3069F86439FD2454652C021183D3365EBB8A3632D338A85 D22BBF99D4E26AF8F5E9DFD464C9CF24FB59A2F5D08CE669207684835106491628AB823F335E 3D035C72FEEACF1B1957AA65F100480AD9D185E042E5732F86A8C1A74D3271741F115B15D54D 47CA2091597340C5165DE89E3389292B62F4C38D90C19390AB221460976A3BFBEA7130829D3F 749E5E555EDE6485F2045E6736617BAE92FD4B6286212DEDD3A130257A26C96B81B73059373A B37D1B5FEA8545E584B28D8D9C943AEC6D67C9C33BC448F42C56264CA8166302A6C58616C4E2 418BDBA38DD8059838A708E92A1DEAC20FC598D6B1D59D910B8DD3C9D249D55B2B61880BF682 A3DD3F28CE356CC554AEF00887EE102657670F51256DFD60B05937F2B4EDB62000588383AA24 5AE98F52EBCA209BCA0146A1BC9151106661CDACE63C5F043BB7C17DE121CEDBB2CEAA3B7537 7A842C58B8757196C529C828A5B1815D7FC80B98304A1FBAEDF32CD0C397F4469F42D36CB3B1 CF29F93FF29F6E4208CB5505F08428508CBEF9C8820310277FCD3E3D69210029606738ADF321 480B677B60D9AA7A1C3338B74CD5208B695EBE12824D05643257C55176931FEB01CDD048B787 0F1CA60BCF68D3BBC0DBCE536137F191FBD51FA9C55170FC801F6DF907E12C7C84704481CF4C 464C0014B93DC2B2F3346420FC8698B3397F567FD7B7A12A88BBDDF910BF6EA1EB7A1D45893D 0D50A0DF8EFE2119BC1DE67AA1F8E37B685DAF05544796DB85043111C781F18F249D5C89F463 3157B5375E46524DD71E1A373C984F7B273418F3CF69E085086B81F0CE832A74407D4BD3D57B B7692DC8313B5ACBF58288CF188509DECB393C91452BE861715591ED61BE38953264EE1FE854 4EDB10BD57576A42F4ACBEE31709E75F4B5E19E61C9EB07D0912ACA3FF457E4B7DC75A7F176B 5EE402CFEBD3F2AFEB06F55709AF93320CCF02343EB4E06A98200A4B8BC6A9B284771F239CAE 3B24E69BF3580EE9530CB0E5821E2BD42BCF4DE01656F02EC010FB1436E9C7420E1C9800AF06 C384BB3D13418B406330C755EFC0E390A25AB3EB067178D072BBD883ED6676BAEB11BB627D6E 3AC6DFD4EFF8D1C74216ABBB2504E0BE03FA43574FB09D0639CF4E1466C799486EECC518663D 2529AF8F9E9C01867962C5936AD3F34D9F62151A3EDFAC604859745C8BE54B96B9C9A766A589 FE16FBCC9463243A24F769F16B4E0D979BBB27D1CC41ED8088B5D5D39065010AD56E130B529F BDBB67100EBB288CA74A4FF762FA0D4F4DC509D2E40E550A6164C20D89D9716E44ACADF72C0F 75B44A025A3748BFD1C2413F444420DDD4BA0F451CBE8F70A848C7175530BA97BA140B88152B 733E59842545B1058B3C9C3087045FBD7CA16C6A7D35EC93D9F4020AF5CD96164103C60A8FEA B77EA9589A6C57F0DDF087C37D2F908E3ED142614B468C2C55C1061507993ACD42357D8DB592 260C6F387F3E68F346BDCC88AD2EC3F42BC9B8BF3923066623E6E7C603FA509FB89D3B6AEEAF 2F5D8DBAF5883766FA5FFB70632D1DFEAA43BBDBB479C67CD9101C73364360E07F71CD82C0B4 384A671FFC0B54192CC4E4D200BC108E94F27BE0D95E96B4A5E2A4EB1B8A1CD34D37BB15D3D8 95A0E2E9D1FF377A2EEABFC9D79E37BB4526A97E25BE20ED47F48919D0C8FD08616F28E955BF C850A75BEB2D9C495904690A16E14F9C349717A60191C1E3597273C7725D1999CCE450EB4018 7987D12A073A6F7B21504D6E352B005F0B76846D78EF496664B7688E340296E6409A0A514618 19DF537F25411604DAE5ED05D2BE1C84FEECF8A4D1E6979A4267DE24650F91595F5CBD8A557E 9D76BF0C0A012C697454B7923706970DAF97BEC8D19000FC6D9526896B0A7082A3E467DC78C2 4592707204325A38889B381AC8AD33BEB76B0E6F065D86A6337E2252359860E2EB3DD8EB957C D853FE1397479DD2AC5AF33E26A3895CF08286760D20552A65C9559B99CD1003DDA16CB0EAA2 35AA8894339CF6DADAE0AC5F0BADB255D9C9F9D480B9AC3810959E13D736AC95BA70B5B810A5 7FD0B6E986DC38DBB70A6F81F90A5458716DB0D3E121B6357D36D75429F9587541D4493D5298 354BB2745D6148314338C2761C4E84FB75EE364F44384D9B03B81C90F6D35FF36BA9296A7B1C 03661D7C4BEDD5E88924692F98E3269ADC4368A47E3729CE298E0A86A3DF13AA3754D4A59048 DA3AA3B2A48291FA5358F1FAE1E833E3FBF6EFFDDB6AA644BA2B7F1F4EA616A05AABAA9F7F05 F9525964A3A82BBD155C22AC47D00A01A81F5B85C7DEDD04E707AF0B01BEA577224814281123 93C8B2FF8181CAFFEBAEEF47FBE8D24B5E906011F1FD208B2A14AE81A0FACCCC85A7628FADCA B755A3BE8C0365485E2F8033FC40AF6F2F93A55366EDF457591FF993EA13BA6D12F31ED35385 EDF1FD7A9273208B118D2F105F4B2FD0745026F3133F78F624FE464061CABD65C13D22F08CC7 922E824F3244754E97AA93990FFE77D9ECA348DC30D7865A9AD09E67394A89536FFC851F486D 541A52CA40BA74EE0B312CE09168116A7375A426218224E725A871EBAC32E672718803840A5D D03861B6CA4D6BF8850B5A328435D0DD7DAA9DE329F123C1B658FFBC41DBC48F5E3160BC6091 3268DB289C3431B44DE07027E6FE9C079DD3FE1864A58AD2DB80F3E4BBC6897CE5BD288C2556 B1B17D67021B259C4ACF6993304F6AE48AE0292E8769A5D6BC943970383715F2D03F8D5956CF 8C86C0EAD6CCD278E4C415350AD8BB589466166B3EF12A36037BA29C14C387702C7EB301B4FC 58E8660F3738949D98E6A5537C4310992D7B96D7045647D32B892273F5ECEBA013932F923BCA AAC00D62DEB318DFF3288D73A38DBDF8B40F690EC4F246056E8869193F03FD2EFB8860DE3BE1 A30FE9D642A3DF5C59340394213CAC491A554C33A46898E797BE1BC70E04B586367D451D98D4 3F48BA27E21A00DF8F0792967BC7B7F6483E55C7D917B11E973F65DD003D5C732163D291763A 6C598628F789D4866B841B7E4321109277FB32DD682446363452F494CF0067D159C16352D9C2 60AAC8673C74E10517FF30F4C0C4F51CE71D2126155E22ED3D52A523DF27E556B0C1B3523354 6396F9921B62FE6BF3592222C9A868F6FF989C1E86C86575DA51D336CE9ABA13532A59C420AE 9979EAEA4DC665ADAE56B7C1F4AF84E9C5454E17AB14C6FB7E4BC58019DEA386A294B2F4C8E4 722BEF99833C5E7EEC04B49635496B5FC7D3D277B8AA40D9E87F154BAC8434B86332C628BF0F B2C5B0225DF39E5EB5760E19D21A7B899BECBD9C189C088F66651E5832DBE898DCD0B0D3E0C4 C0A7A81AD20EFD8F2ABB15010856DB816C72FCB7518839DEE4B259C6E88B9FA2B7FF3DCF2016 15D0047712D8EC796F99FA5D4FB2500F879B9EFCF03926C2F43C892FDE4B954FC5496E4D1A11 66AC197783FA28F54063FA50EBD85DE2A5481C387E9DBC573D8604642F932775B37949E92410 E339AE70A74BF7E83990E4A29649E2E4F9DCBF8E680F9B5E5D469924983D791217D043907B52 F8D3B3A8F80D1BC70CC13A00A1D60619E886593CE96331EDA74F52C79ACD9321DFA9A2B14740 6E937DE49ECCA2B605D7364AE9C9AD75DBAE4DE32033A8C7558ACFCF6B7B616DA13BBD800EFC CF68441503558C1E42B894FB730197B63D98F0FBB1573FF2DA8DDAE506FBD36F538FF7B84525 0989B8EB42290238DD2FB897F223A92510F6BAE5240C620D32F408F41B5043074C267709B800 EF5E78BC3A07083C74A7755DB20F73AB7EA69BE17674632CF4BD14DE5B5EE3CB2CAD485D7C57 73055D8AC16862EB87A584BFF94DB2CB3ADD7B7A3BB91202FA30903B403D7052FA1A7EF796E1 9C89229FC8E5B5457FD7FD56769A4A21A7A1D77EA6BE8FD42CE82D40F0FBD7DCB53E1DC0B2FA 5F9E55646285019CA7A780D6B47820124A9340669C6E5DBBB42E5E4561D068D3EFCCF308499D 3D4CBC3105FE9A03122E3E78518E6DB513AD56D20994794FAD9118EDB8964E24219E74CCF25B 4FAEE0086E487D7FBAB394059CFB6695D22D58387D547BCBE98D88F259DCDF1B2C2B68FDB052 FD1116D6B584970A7F8765E82BE89F08EDE9EBE22D24849593C2166A2F35CA1C5C423E0AB955 A87168EBF31521A06D5E888F15A66ABF2678E55F5998E868A14967943252DCDA93AD962BEA97 37A91E3AD4881A41F8D9ECA94B0A3F66A29DECF1A5154E2DA9E5F921484DE95A433354DD8F54 48D6C84B7D8A8B4CCC5A9FD2812C40146E1E34F049E97D5FA12420025BEF27EE4EED347816B2 F8BC817282011A9F467654D7D33F0ABC190634978931FAE58288F66A8D057AD853E6A1877239 095332735001B0D3A387410D82F8B150F5757E7FED55008556F8DACD57376D64EF29D14F2606 DFB3B35CC3AB3D78CE2D9FB33352D5CA2EBF74204CFDDBC3E2A4841934B14CBB3C1B55D6C68D 61087C8860AB978530CD76AB5778D854EE0D480C0622876701E257081B1862A0311ED3CAC02C 90CB20D0FE5ACD34A5BABE578D188E804FC6C27511A5C8D6AA7CC96E244598C7B9D6FDD0F731 20926C4436B0D0E6D549DE336C308355BC338CD10A0F43CACDA8DE545FCC4B33EF64C1125E8C CF9CE2AE9FF75FD93EBF6FA54A53EC4D13613B6F26F8534B8C829956E73039B5146FD549129B 40ADDE993CEFBBDBDBD029F96C5C4B68F9B2EEE6F9B5972053BDC16590FC6CFF24B8ED696BDA 5019A47B2FE78D3BBA20AEAAF10626A4536B43A196B6709D03A0E46640B1003979192F3D3190 458AB3FC9BA4E05E840409657C3D12D160C359BB902F7C090557AD37A72C04B7D39BC261FDB7 ED03D1F72932A8E15897F4871E852967BE07A0A41636E6E860887DA67415764AAD5E5E1525E2 4B6748823B012A0B7F78F686423382E18A8BB0908C9D6A3AC68759A8D5BF2BED2D55142C7F52 4B2CF5C7E699CEC25525172363EAE0132284AFE68F36D39F52D5E25C111F68237B41B9F69539 72E89CE7F43FF62938CE5D51D730D44CC79AF928D5FFCA2A27D679174D21ACB0C6F0B97BB119 6658C28722FF78EBA6033756277B14352B7349D9DE3BCC97B990086227F002BE7E5A930581F7 6A5712B0A8B4586F4149F2E46E5A7728B708BA5EB0388610EDED2B66C0B48AF87565CF9FC1C2 BF488B141981B906A938DA0A1500A07D149C336B2563BF25F03103FC515224C45EB8D05C3AA2 B9D1DD5A3753304FCAB6BA868C21D32E6D5B26ABDE7EAAB5B0250AF4F2F4E773FDF134EA6308 1405DF0E1C3E3557C8F94B242D6027D3D186A2CBB0867291D7135A3A80106193EBB57157FEE6 720B6E4E4E13AF432B1C197DCFA0BEAE1F6A7912EBC096D22E8B48D483A4DC1070FF8DFC422F A1971834C27FAB2CEFE8F811804DAD0E8A47566DDDB6157F766E21847A79698BC8616B68358B CBFAEBBCF88730E753EE02B2AB3C4D2F5D13E67C5F24F74C2D6B7C06FDCE184C7AB7478A3AF6 9CD1600B258CFD04E29E8A8D90782CA96740AD6FD48590435C47394EB7F73D0B213757BF50E5 5D9003B5F53E2E8DF40BCD0FA6B5A5B4A86E710161BE8FF0C0F4EE28A8119F1AF1A28F7638D0 F76D86B2F99A3B5691C1C3106BB4A7E254B5422780751FA1D76D8EFEC2A1C3275B98B0E3D595 24F933E4CFD96910E59082C59043AD8EF6802D99E07173F306290BB5CAD4B43B4F2786296359 E445DCAC16FF085ECB5EF331CA1BE4FD7875DF302A589EB8BF11D1A85419FDF10708D0D4F5A8 CDAB0C7F74D56296A3FB3C8D7CA5F80AA19122EADCFF9711E7CEC929B30B2ED69535CF3CF6A3 D7373D65ED5FBA3E5E4CFD14BA54EDDF0AA35867CB7ACEB44D12C3CF2909176E6219A0478F72 FE393C34B4C0B7F844AE17DB5AFFF0B216539365A8AFDA4616A202A10F148532BEC7DDB5C089 64BEFAD32C3D240D8080E3948799A5C99EA538CE687DB7093F151C0DCD4C810A83733AC953BF F76A0988B356FE694FFD6371E8ABF826269EF1FE6E1814B09D99EBF4E5A6949726B1064F16A5 D00AD8B86BB7A5F9B3252E4ACDA4DBA523F5D662E116C02C70088D8C6F93E3747D6E950D8BC2 A10FE920854D32DCCD9CD1D07A730CB2D02FF7134155FB2216ECE0E586BC9ED91EADAE541C2D 27F1E9FE1150F50E1860AC136674FDC9FC0C2BDA554269205458150EA28A3228E9A2A3372DE9 4888D001087F64CFEFA4710735621D6EF35228EE3B257F2C69151F6E119038DF1643C44850BD C04FB362276EA0E4FA4FBB5D635F98F4B1A0F9B070F1A38453FD6C651F0F90EE471148628FBE FFA386BCB1E6F63366EB7FEE4920776995E90E0684E05AA0A7EC40D727F4E3484B02A3E66CEE 07D18F115ECC0ED297F958E123298795150F427D12AC6BDD2EE0089FF6910AA577889C668AA8 BB5076EAF7609FC498C6C51D4231AB6B2E2850A51B59F94FBBC89206CA91FE9FA81AA9AA5D81 7AE5AA9A45A6FB85D5EF47492E95B9626C1FAA1F8DB33E8499712992CC43FBD7F2570B15EB0B F1DED971B2EBEABF24240034BFDABC06C5851E828980DDED018316093EA6988DA1F76DF79CFC 90AB99CAE0330B7F2DC517F7745EC3BA7096D76013D53F093D1C21A5D475ACEF361501A97F1F 034802DC3954294BFBD0F9BE301714D958D81EEF8A0872458529A155B0C79FB4685DDBFD2FBE E420EF4CE6442E3475211D10E50B9692DCD25E5C5473A817237552934848BFBE48347E38E0F4 D851E0C3374EE6A7915C702C7273050BD74A118FD3E84E0B45B4F3EA30F0AC4BC4689DEACD67 7DC7AA91E62889515D52AB416B38103308A7B301CA32E28EBFDF6FF2BB3D93E93AE5A40E9FA7 CABA10B5F934387FB0CFE936F32274624A21E87D4556022CA7447531307DD5BC906A7457C696 C7835FE81F3783AF019180AF5117B21ABF50EEA2195FB8C26738CFCF7065DE53F9E5C29EB097 4B70E9DFAB6EE3A342DEBC28F95BFE393037D80B3E027E8435CE534DF47C97D9506889A22504 4C018B53E519810AAE47E69F66BFF8545FC0EFDA675D3B0D9A4055CCE2FDBA4EFF27B2E638D3 12FD1F49FED76FADEFA163E01D3C7C244363B57D78C871E9EC5579BFA2B0D9A220A172E6E850 DED5D7B8D61ABBCB54540F23766DAC40293F129833995EFA7F52CADF88B7E00CE636CBEAC6EA 4A8B00E7925B0D1AA5A4CB818BDCA2E70E37161F3E717FF40FD6F4FE77755F5107B3579F262F B59712C1B56324F8AD7028DAE5112926DB9ADA0C28D7E8615D96BB8ACF3FD6546E47FB2F9D00 3C52C5175EBDE4DFC9E0DF447F4A8B5DE9370B4BF4DA5A84E435D53E28AB75966B41420D4D07 98B8779E18141D042351179C8EDE08307509711EB00474B6E4B12446184F4AA94AC5327D5B0D 2D3D20B4C4C135EE91B9E283ACE06DEB9C1715CA8B78CCE477131AB802E9F5514A82D55FD125 A93FFCB4385843D91C56AC170D442098EB5F4CC728AC8034A1BADF5390F1D53923A0BCDBF36E 55938B45F2D9BD8B10A7E5F5FB3245BACD83E9521CD85B194437A4CE9685570B3DA825A89657 AFB6A68A7AE6ADF3EF5D92AEDAA420BBE86B7C671245CB98307159AF74BE629A8F46476BE63F FA1628377D256A86DB6F28C9BECC892C2406F04FE381BA5A253829F4C07EBA8AC16BE5CB46D3 E63F1BAADCCE269C66133BE8CC60BCF6704721F6244CA012022BF3482C5B24C9DA23D9207557 8EED35640056DE0BC4C36EAA208D6FF1CCEBC602603EDC85EEE05D4DBCD6791156F6C1731231 E77AA5787240F70900CA7B8718CA1FE9BEC6F8EC59EADDAA18182181261815602583C85EBA52 4C7C18DC27C3A4E3CC14C7DFFB2FD1670B36F2F4D38590460DBAA3B6A992AC133605603AFBFE 7226049FE41E69F04C4A6B2A01D06F5519B55921F820D1A8D12F11A24C0323C35CA2025786D2 CB09A5AF4E3C2DE113D18FFAED07A354B72F2190767FE9A06AB3E9A88F8B00CBFA3C12B82DAA 7B436E20AFD8148006AE3E4968C2D8289F41CD7D4FFC61EAB1A12B60A3ADFDADCED9754F64A6 48A458AE66F5A44737B8D16F436321069FEAAB9AE8B0C10750B3C400C5C827BF3674F0F34213 2F9380ABB9A6EBD54E0E800840E24794EE8E3CF6C75AC62BFD288F05435340AA20425D1A9B75 939C627F825DE6EC589F1E40632C49379345DCE3B3A4966BA4611DE2342E31E79B25B33DEA83 08A96D57369CC8570E31DF0B9128B25A21B0FE44C4A61329DB4E50A43981686F9BB3FA50B4DC DFF19BA5B0EC564D94EE093D2DBBF135840EE31041AD4B3087FE733B9284B043E396535D0C2C 8987563C94E25F0553E1656E0A120685FCD1042A292C68254F3BADD5931398A725A13641E94D 7D4DD5445EC0C6B52194AF70E72BD7E1FC98418CDAB6C4C4684037976737FC783230E2812330 FEE33D693C37806192F7320FD35A415E7ABE07BAD0E1835EE01BB1953F50B636077FEAC98734 4DE0320EC693926A09A77712C8E01F1FC2E71FD4CBC088CFEBD6BFA203DDAD5F8F6D5CFE945A 635AC949400167568329315A02EC5DA3EC974EB10BBE0A050FDA62F29509734DAB2732E32560 9B85B7F6E72037375CC51C78304950215512966D69BBEC4575624074244219B2EFB7AFB8B5B7 3E95E8DD8B71189EF22837411EF1E1FE4A3B07F7CE3C26557949035A54316349139CAD64E170 B4301A92011EA16A3A5026E724F3D35923DD7F9595AD506B8D1ABBE47CE80846838A29BF7E0F 6FB8ADBF7B27E1D03B98E487BE18D1F5E374647D0BFE3B7A5347586424980E645166D73B0DE4 AC6EADB5680888D3E9D460C6831625FFC7C1FADE5AC680E00B6E5776680803A8FAB59DB1ED33 2B48F8ED919AFEFBBAC7CF977CBF3B8D5EA42AE9D24AA6F61D86CF496473FEBCCFC23E618885 D37D1F52D4AA63C1B0107F4444E85FE8D7A2F65E3183A026066444132CED223F436A33C0FE14 30960114978F32EF956D22AA61A7C0AD7A31785CC40E7144482277145878AC842B2CAD5095E6 1F1036C32E9DB8E771CDEFB32E1EE3D0ADCE43CB1BD8A4CAC9A68199AF84FF4185AB3E06C302 DBA3AAC3BC39A8B34B9815955338C6768E90819FDE9BCA59951D8150356F659F666DC08DAE42 B79D209CC2C305DA85B6E5BD4D471128D0A42A2FA4830C3E4BE1AB4E5754CB127766F80DE2F8 DDEA4A5408C6D3D84C357E78A6D2F46C9A3E376D01A4CF5458559A0BF1BA8B74B444294C6B09 7FF3EAF29A2853C30ADE3DCDF303AA4A3CAAF6728113EBD143B28EFCA63F6BC75E84DD59F823 F62562ADC55EA78031A27E95195D79CCEB5197AB7CBEF883BE62FE3A9390A0F4EF2A2CE81679 C8D73E5329A2C384A2E540DF0A88EA036835B03E17A605F1F350F0D5BAD65335863671CF5F08 776239DD1B623897751C22EDA66DA46475D0420DADB20EBC5A7F325073D00AB388457C99FD0F 90D1AF23394CC47CB8E520BAF775B53FD32573595AAB699FB443F766319AE602064858E50B29 DEEB433427D44C06F7BB6F34F7F85F671B9BE353A477A6B79D8E03BD8418242D0E67161B453A 5A28356BB9A8D9254DA9EA2847A26A8AF54640C65B2D84987038B16A232C40C4CD0A6C12B27B 801AE135CDC3A3B383BD511B42B664110B632A822827C024B4E390319845CC062CE0C339C718 C8179929DD3C590B8870B2CB4A1FB6B1D244DB5991783437AABC5E0D86C2E2BB4A57AE55C0FC 76DFF34D9CE4F9DB23099AAC53901D436A4B0A8E067ED08737C79B75D9CACE67325006A9BF5B D158103C8078B901170FC86A95BA7671197527852E6FE1540D7F44F369CF1C204AC545A2E704 AD937B06F5ED870623054CFBB8F04ACB4ADE6ADE3FF71525ECB8B0AD69D946E9CD1C160A39AC FEF4709AAB5F58FE637425B4C01F3AE3EA928F5A478481AF383CEF9EAC1BF1EA61A551DDCE84 48791464BAD9554CE870FB1E85F8C40579BB4D3E2CBBABCD1566FE49A2E17F7AF5E6896C2737 C8017829792CFCF9D753E0D328F96EFE2743CD3F351C7A5E7F76F7EF5C5974A172B7AB5EC867 7FC561CF78E6A732FF636E46BCDFB88B2EF788908F55EAD2F0C7889A22DEE98E56324BD89952 F6D389C98B3287FDCB14A6A45B3D9D3699297D97D69BD8CF7924D94FB0568043773A9A5ABA62 09900F550E82CA6853EB148B537B4F75F33DF6CB3BB0DE3B9F4C117D9D24654235F5EEF54362 4CC358DF759E9B9DDAA3E803C026B82E70A13FC633F0A6C3DCEF51F0B33E11045BEFCB233C5F 9EF1672699EE26A19765210D4CA63AC280231E062393165C2A0E98A0EA1B68B17B88D7B98279 6E8B943C3C889090CED654A29B0F6AF0ED78C8E36A5B753B18F5A571BCC68D3ECBCD50AC03C3 1B888E5D3DE12CC4149983AECFE36E2C3ABA05A3FFB4D0D05676D7CEBBAD026905841F484B90 E582E551638623876486AC664E131DAD613E02AB76F6F9E09390A864E045D567E67ED37B2076 540FBEC8F8B10CE78F1902C3582D625EEF170BB657A7F47A9AE02584A15ABB2607151563ABB2 0EA91FEDD2FAE81101CFFD5CEBB2B538AE0286BDF6C0144061C1283446AB96B4C1CDB8990B49 4F347D3F776EEA433FAC0BC2EB05FE18D8E7457E1AA6E685126CB494B48F98399190D70BEF9F 47573069D1664E4B0D8765A6C5081166C5A8BCED01B7EFA65EBF02839CA4123E9A8D565AA556 4095483F605048606288F7A26CE3A6EDD7E9109C6078431536BF06F93345329B4C7EE3AFF383 726341592756DAB03E82BE0B30059BEBEF482F3E2DE99CEE46421EA59EF355861E002A44E0FC A5A428336488F5B0B035989F7C569094E152EBCB52767A1296B72409391BFEE6185E10A29733 226ABEF840D10B4F028F4EDE303D245601734B388CB9717C4AECA1C4391ED4054137F6ECE8A9 33444E2A03F67985EDCB1B248E34C0EAE44F9C22AE1C4C57C8F6AAF83141744E81F86E3B952B 0D5045E9C725B23F696B79A60F47F7106F53E331C19CA9B3E54EF5DA6478EC11537572947185 3591F35BA2804F36982CD9A7E5A5963B79B15644CFC15913BE4186BB64BC08B0F4E7863E7A5C BBB251B2103B5E8322CDAA3A91D7C21455D7A02FC29EA9C9E1C8F021F39931A07080C140D8E8 A4AB3476B4009CC66B8A51E7C161DC2E716472CEF21B68C2E5877FDA42F02895E3A7641FE80F 2EED2B26682BAD62F860A9F149E17A7DE263437BC6335DF4979807EF19E4129459E2FE0136BA F9775D97A1DDD4DFC2D555695B59205105F096C80B52D4969551968FE51BA57A17F86177038C 3E09E53B8BB5AD475EB70684CDD7FD7B7746609B4353AF0171434C8050CD2948EB7FCFBE73F7 35BE287A5CA4E83AF8B4B26D9A939FD613AEF0F7B6D4126E15B0066F17DB8F57A513FE2C8F7D 5AEECEE35912F25251E8853EE3B0E5A2FDBD9182A6B9C99BC19FFE8D85DBC7146C5F8A8859AA CF8935B1A0A2189FFA3A4118F1478BED18AD6FA6AE328FD6B6F9E0DA13682D4525623975AA54 DE675E235A4E435ED2B9CB7248B0B1184D590988C9CC5C6C8C118540C67B7885FF522AB4880E 6E6B9C2B6FF111908C62F656F99C6904B57A21C049B5CA876931B05BD1B554E818A1751F62C6 7AE918082F25BB8B4AF8E9186EA7BB7769F924F8C189602BF190ECE0194A25277962C38E0321 F3095A27FB7DA0614F717C2E0A575ED37EB80D6B38AB8C09470D64BB28194F05AA151B3A46B3 71EF51E85C73FD3B9E3A7B476F9A21FFA3BAF12DC5F4AC4CD479795A2CDE98939AA074A317E0 B553267028940A5375A7EAA9A1185EDCF27AA619301751477CC3F672A3D59F6BED11792008F7 341A8DDA4F6BBF643A57ECECF19CC60884DEEA925C1EECAF3C024EF16B09BD5E0B6163CEFAE7 94F61137C44F1FCEAF3140FC223BCF203F663269AD41DC27C04652FA4070B9BEFC9AD37EE79E AE5E9D703D1E05B9A1AF54D84D5F97607D147A77F9B90FCC5ED6626D18E2296654634CB36FE9 44C321F1D1A10B1AFA8E7E158A32322B966B0F8ADA060308378FF18802BA6E8172D239D6C86B 2D5F9A159B13A29C4DBDB19E2D6EF3502230A46D4468172D8C2497B4F03BC25647589252623F 011CD0B852061893897DBD5FDF7F4282751267AD7D4914A199CB0F046B194C6277C4EFA5BF43 05F8B9D6E97897397E359BDB4CAB04BCC2A69413ABD55545D4B47741FE9C55BA58B460C6554F 00E57AB516B02EA6296E3B8A3D7CAC22D6807280F3E454708A2DF1F9037514CEAE8527659EA9 EA852CB07CE6A14745384866B2DFF0AB77F6BE544DA12DAEA95824C7563A56F24BF8DAB88093 31D11108CA50870DF03593C421D229497370BF92FCBCC0AC9B5F927322B896D96FF6437D6000 6732B9DE9DC0AC9DDB2DE9D44F7E9B92A93F5E36F618EAC8CE21829C0C094FC061C8428DCE42 C028B1CDD84980857A4DF74DE564B20FC20897E79A496DB3149848466B8A6BC493F3D4CC6D33 5B57BD84C9DF116A6FA286F7EE401E7312D078AD606E8FD969B69891013FCD1FEC68ACA9E3B7 9684EF7DE656DE419D92A46DED2C43EE1E3E23DA7FE60029E1F1511AD8DB52B2589C7618FE8F 2242956F1976E5C174412EA691747B4F1BFCD3C23A60A298B99ABAF7F5B491F254D90D40209C 23D0805128AD9506FE9ADD32562DBE0B81F2CA21592BD5E739EA8CC4D66690253BB5F9D3108B 9591C3906EEAD0C837902E28D45A68E61971D1706F40BF09DBFAAEE3579F403FAC996449E1E6 C75A24F8143D8A5B8BA6808555ADB90E32AF1039450F1A5ADB218825EBD38411EA7869AAC603 E46E14D98ECE5432098714D5B26B353DC418DF386549353C4AB62BBC637FEFF4F3D37AFB618C 6ABAC8F6F2DDE2EBABBC838E388BFF532938CFFD9EF0368A0601DD5FA4DAE6A9E866D9AD9EED A0FDB4767712518EBF3C7063FCDCACC116CD5D3585F52AC01B75DEAFA649A55FC114C2D6F568 C23B54C519B19189868B74D5019C643032308066D410977D5866B582FB82D6FD8350B123EE17 F24F2991C188F9C7B6F3B1A62F8F0BB3FDACBC48329898CCFF62A17D015336B0AB0D97BF3EC4 6EAA032A9E68A8EC0F84519950FF3030F88DDFC9342B5804F3E2EEBC2364C6640A10C1727105 AEF24B16F0CE008B4E9E669729CE5FFFB2124F4FE459AF66CBED05AAF92DF7008199A6904D52 7B510E54CA090441DB1AE6AE16D07AC5FCA4B3CDE7F89AF905FF9F87B8B56F4A45F653026066 34BEF03D3D5F3F24F655526CDCF2E897D9BEECEA419F0B8F36D83D42E14F51BF109A20E34E1C 6BB749D94101F4A59D0B2325AA66769655AD84C98240920FF1637EE4F1C026D06A0FC596D08A 637E8E87A48A8196AFDC361B0F84CAD1B2128B9AF38FB6B20B5979863DDFDD5673BF8F821D5F 64071838BD74742548031F16D5B054425EB649CFF0D130381048C7AC73FD5D15727BE7218882 19FF85A8B0654171835D937B61DCAE579F293CCDD51B0BFE7BCCB75E7EE1F2DF2CE6853539E7 CD74B8B1DE9C1562897A4810689A246DEDF8D702094408F8B6C62233F5FA83A379B3376B1C52 F35F15729BA9E65EEB7243A484CF7B1EAE66C20BF4FB6D95ABC1D72B3CB95D00934B8835D057 6C7E75D2F4766296DA85E684F82368DCA018AD9BBB2724B4A30C9E82F52961B2309C158A4F57 C85F898FE859375051A77A887FA4BDC0EA89CBF73DD8E6FD237B401424C2176D63B329909A50 0DEE911C7DF297D9516E04444CF2323731AD408C2B1D16138404DFAFB9AE239B4DF5475078E4 B8F201948C46776470C397C947B32215F5F4055803D382596310A776DC28D5B8F09EA2309A33 5D97A4DE952B8406F0135F3C38546D9D0BA146088BE38DB7FC1E9FF3B70C21FCFAB4C6C9F9D3 7D61EDAB276769538949DC39238D1EEF3DB92186EC56865DC0A9D69550547074A41C9A85080A DADD7FD96E23687898607A1AC8EDD58FEC4156587E7A41BDDA6377F0C436AD70C53663566C41 478B8C41517A1540A0F9BDB924D64F07556892C569A372662641016E2321FF875FDFD236CF98 1531AB156E2C793BE3E6354F074BCDD21EF4B7FBD9EDBA1D3DF52F80220D4C697497D6378817 B40F6CBD2CF458B492356EC2F171D584055FBE7ED48223596B6E72EA9003F1219BD79E05329F 564BFB6DE6A6F62C8838CFBAAA0054342DE83D409F7F29EE655D18DDC3DACD2A29B73C76F9E9 67365D3CD235184A268791343E09B7A30098B3691D18568579B465B13FAC70F7392A8BC44173 137E1F3D2748E0A67D7E9FD094E7AAEAE28D1FCC0D83FD68BDE7CCC21EC94E932D333B8A7623 FF1C3F69E9212900BEE3656124D0856695096DBADEC466D3DC6A466D4F5D5C60BBF3CA100581 36F453AD02474305F6427E6738C2728B446A0A6953C3E10BFE36DF5F3A3A447657FBAA426F0D BBCB0DEABC57F7EEE5D3CCB0937C7FD274192680DD79423CDCCA30BBF1EB2767178F8372ACCA A4E5E513D4D9BEFBD1C367BFB3588E396F0786C730D97F8BA01C5E060EEB124ADDFC8E68765A AF36768C1BBA0D7ABF871E43918D15636746D0F1E6AB2402DE58B57EF84AAE228D74A20D8340 B210496D69C3A5201A3233C324B03E53F591B6238E7367895BCE63BE3A16504AF90C8C042C83 A73F412A0B5EAB7F9A5BA7D112ED7D279A54066A8127F349053AC44E2F72E707D76CA68AD5FC 15AC3C31C1681BDBDF289C1D0BC2148699D02DA09CA4051A71FDD63A772990E58D4E97AEAE7B 20DB14643CA84604B4C692F23BC1630D516CE939EF865F7C44B8C7A182CF372A3B932B1D3014 58797977C90B57C5E12DE0B62A8D664C699182EFC6B13BD762D4C713A85E7DF5BB9A8207DEE3 C4959E4E4EA330CA2E5274725E735E485569D1EDA05F5997F16F7D5EB2947529CB70670698EC 06FD3FCAEF47AAFFA1712F5A2FBB7362EEF33E66F0493C30C0383CA6C3BB1AAEA99BA3904BA7 2C81F8E3D117B3A3603BA3BF9BEC83FD7820E3353D9666009922A40ACD570B752F58533C8996 9B08308A96E11C4ED57380CFA055CCAFA9558CA0CFDF832F0090580C7BD5779F8C1A0A9F0561 6384D9C885D1547F38986876971B2F5BB52871C05045E6514AF557EB57C5B2E86857FDD30F74 958EED440E691F004F51A5A23EAF9C03B2AFB28A6E16005B928EE533AE50529FF4D58CEC733F C6D9D6B9E235D5C39A8EBE9668C7AF0DCDDB318020E802AB5B95871B644FEF014265A3536D3F 4489C1A2BECF8D5D5D2D6EF984B5C4BA674C74ECA262FA2AA4A4B7164B04B9F4297482012336 12157A6BCD92A7F3E5B6F642135F344351A94EAD13A912DAE64A132519C58D68AA11BA75ACCB A26F84E0CE0B8B2DB3788327C615003DE8F723C6C51549709FAFF2C7DC76F773C55A44A26884 5D7968B52A7B495E93B22F128C569C23A29A5A662C939A16BE08DF74E525B40473EDADAC4DCF 5226409F9982E3F9F28B9F0CD6AEEE91EA3E41453BDB07E84A01E165797B7E0C88399DCDCC66 6581B746ED63D1B3FDB7731A98C2708DB56EDD25E6097A20094A11F79880CD47DEF83D4B0C0A BB991DB8C878B0874D099D7B5555CB668CD5B7BFCD2CBA76852F0874B906B1FC95616FE6237F 40D3FD63E29F593A8842B151221E63CE8E9AA2080E5DFD5E8C1959F97A4E570FE6CF8234EC4A 961BC15E46789446ADC12CF9D3E9DAE345230941F924FA7337C3585860A2870F388B14B29B76 FCCE9BCC0233EE7CE39A242B0537594D14288C00AA67A08443E69521452AAB22575449C2EE80 D0393ACD3F7C9378B4E49A5A4D0B707DAE8502791EBAAB3CEED7F2ED54585183AACFA76DC3CB ED28699CC8638293A2E885BCD88EB01C6E6C828C66F42F1D534A63B8606DFDF1CE4F8823D2B7 1DC2E9CDD74703EF1D9D1EE0CB7241505366136E256BE79C31EE8990B0CA49CD2729A34A92ED BE12A7738CD2E4F4002C9F6DA211D57AA3D713850239DBEB9AB648BD9D195B1741AAE2F1386F E88AE159B9E996E7D803E0AF11008B345BD743433F080E70A1415BEC71CA6C331A22629F80A2 880E7B112C9B6444E146566C9DC14C73C178D41F99CC78EC9D106F102A9C6435A507A2CC7C81 B4FD18FB4099D61D0228B82BE3755659968DCC18005EC289BDE509D5A98A0317150A2C8D5CBA B353BF310C39459AF38B3B6532928C478C5012AF23CA4B834B3519575DDA13BAD7CE1BCFEFE1 EEA9CDC76B5A076B14477C2EF875B310E9A3594A6DFE2A3AE2858049B280FECDFAF2AAF1AC77 99757A833D0770974495D7094F1C1E4A91F51978E49014DF917E74310CA1C70CDD6B4DC90420 33391B960FDC9E1945D256BC0F9DED7EE9235723A80BF0D51AD4F2F7E8AA91EC22CB53E485E9 35FC169AB85BB1CFEC6BD3E7F234AA6FDF26042C90E6A3BE33B3845A1C9D8967A752CF387BD1 7A76D07B7587E3AA378C07F47E452623FCD2C144723F5E40DEC0457C6E96C39D671484141AEE 45579E097FDD98BBD391DBABEFC70054B0729AF2678687D9ADBB29FE3316D622B62C27C5CAF9 4FE9843DE8ED1C21C9CE728C83248D77C6067EB67F12938759D82D41520A65668BCB3D45EBFA C664FFA0D2A0E7BBAFC03F8E849FD08727F06C24767CF30CAAD10F7F18F2E15E2AA8D3A3E49A 020F70CC20919E8AA33F46681F33E1706CD396F9C7C93A19038E5930EE5104A48C3F9B308E8B 88BA9CBE24BD3F26730CF157637DC8720BE68E01E4D511FB5C176C1C6EFD57E304A67FE102AC 289B422D7CF3FBD39CE39BAEB79A0AB979506460A29DB8AE1A2D90E9571081D1FAD999AF409D 632EE7B87E33157362DD18A086AE32C83AB8B960053B71D41D6B72523930794C2473DE9856D1 F9E889FDFD70A1B7D9E887CE1FF10A2DCE4EDECDC9C0FA1F56CAB503F54461F3D3FA5CA082AA 5E28D3CDCAD848BCE4C379276944C42AEC1D7E6C447ED4FD70BD545887F01CDC53C0E255246D 7496B987383E162DBDC1DAEC6CE801DD3193DAF1DDC1DEB9D982E736226A601FBC0DDE4D7B56 5BB1E87879443209517C058F68B9BBB48620B636846DEC19B8B2973B88A53F8B2E2C4EAD40CB EBC4C217612ECAAAEC2AC077E26E4FCDFDBB08DE8CABAB2C0FCFF66A040B9CC79752F1EBE58B 6BDE30FA17EDA0AA8709CFEA344CD1AA650A08DF25D4D16F6ADBE2135FFF9E7C903D7B7E8944 CD49F7612679C24DC4992DC27532CA3ACCED63CC6991F072875CDC4D1434FDC927FF15833CD6 B195BC1286CF6C34E3E0E1C7B00309D7F5DE3E24FD3B4B3BE0EA637A337C831903AE4A0CC7AB 6C8402333E66703FD34D1A67F580A4E63990C88AAFFC93CB6B4C9D985E39EA248AD715A853FD 7DAD6D1CBAA35019A2BAE759FD04ECCD4AB9705C2D22522BFD7ECAFCBF5D185C841DCFF8F141 458574398E865F5187A383B9172B85057D561B2515FF9FB9ECC617CDEC6F6572BDE8983939CA 5F47607BF5A5F6017835C1265EAC50FCBB54D7E122A9F862DDC5FA00CA937D4DE4E0A385E752 C1AB12570B0CB3B56AA751EFA9B06557BDC4C2634770B2DA7A4BFAB3FE332262BD6C49927CC7 D433AAAE9D0E77A06A4954A3A1E75C0F037163D17C4984BE3930FA529833A3C6E12433EDC336 24350B2EAA94A35C85FCCC1039C03145A77F811098013E850B768574E71287C35DE5DBADFAC8 4B34BA3DB23DD1110956F415BABFFEC9B79A1360B67A9A22D75C5D2994A81DD54D38630F049E C4F0CF38C692E0F7A372EC2562648AA5B63ABB616DE6041CE69EBE2FBF2E1A4EDAF57DD3378F A1A445E64A7900073558888857FAB7F83CE9EAB5F020479F6206DABD5E756A481E4DDF0A6446 34F63F796F3C062D4968BB1055279671DD762730FCCFF930CD60053C9F33A88C73F255254986 B3055B66A36EC266D73DE57B2AB53A079031EA57E2B10B0FCB2843FD5A1B7AE569C351D7A28B 0932EFC2F6FE1DB4C34569AFAE364BBE8C323FCE13190E6B21E6210B34D4892127D0EB8C617D BAD3AF3EA4CFEABA4E81AF57F6393C703006485397CF8C018A654ADE14BB99A8280028DFD8F2 F1C97945EC437026E2000760D3FFB033AB8719AD5924F37E8D2ADB1AF1F3BD9D5FB84BDA304F E1A47F12A13E79FD0B268B309D784C6F874D5ED89C0B8C6107A704F61B9489EB1EE372285876 83DC82FF74FD98CBDDF04BEDF35097E66154B7CC2130927C7A718F5F4B4338B2EB6FF0ADBA99 0B5E94CD21265EB13FAC95B9E976D1DF8FF2496A60A81B9599B3A07E5B3F074E201C46D7EBC8 C2B36F8011409D5D8430DB5267F2AA04EC5A000DE223D356574042C4FF128D902F1E1151A731 E54D07DCD0ACF614B19AB51F651C324ADB3D8EFCE74B3493F0D6E56D4248CB06648C28FDE0A6 341AE2792D29714C66C4BEBCA0A520FF3C312C67E442A9075375878C20EA6766369DD30647B9 36191BBC344AF10636E49A4AC2E45D2680366CA41A21D0E5DC1EAD87A13E1A0C079F396230BA CCD2C4CE3AB39081651CA121F35B285CD7ADC2067E121C4F3EE2AE45FA8EFCB563C6DA895FBE 84A0384AC9787D8C4A3BDB6E2E87A58B9FA4B595FCBA204488B377404DEE50823EEEF2221F1A C0AF2AB2761A265FE2C20D10E21B6E339A1D3A26F5B4B1A99D316C8CFEA7CCB52442D26C70E2 2563062E982BC256947CCF59C3E09FB1941D7B54E0A42466CF642DCA91FF9816E6F406E0F0EA 23ACC1959DAB7E7A8AEAAB05C2BBD5257B01CC8F0F111CF7360AC192C348BEAC6A273DAAF64D 54AEA7D49D786F98D7358E483609319699A1FAAAAADE42826EE0B30D277025161130414ED914 AF741854017A405F22CD4ACE4CDCA0833AD52F49142FB4C03924023CEE3F2489BB3CBE03B122 19B9CAFD7AB8AA59AF3239248BC9EF6816351F9AABF77792D7197945F00CBAF769F00005A615 B83447E173242A3BEA79E21FC28B383541388AB3D342EA87876F2CB55A02BC333A133FD05F47 1A3AB493674F17AAC890F14450EC5708063591FE5E6912E41F971362180FE085706C880ABF1F BEC092828608D1EF6C52D01A9F16FC32C420279C559BE5C673D2439E0D774648EA9EBF4D9A84 13E9AA815283E016FEBA6293838C81DE8C3E522AEAC857E4EA7891F81DEC06168B4A15E3668A 61B924B8EA6FD11AB0589A5D2B6AB3E5F50BD72BD2C55471C19EF542E278F3874EACF4B2C2DE 312C6100A3F6064EC98747C366874E2233E88F201098F75D4C275B2AE0CF6809BCE3892ED3FC DA718AE0F46EC1B624DCCBF6E84024AED20793FACF0D1FFD2775C6D6922F9377B1E79393F7C0 775F2455EDE1A4DC311EECB9F57C20599E469C497FC23DDDA0D9DCE6C3B036EFAD121522C580 31235EB8FB69FAEDAD0715E69EF1EC9701938DF927131C39848BEEB9FB862D13B8ADC13C86BD 963108F816A3424FB414EE57B3C7D8ACC56E8AF2EE316DCD3E04C6271D733DC9277729683120 30D87118E79006DD5AADF01BB94B308D6FECE272BCA13C7CFC41CE3C2FB964CA42599C73AC33 71BF648083FAF1D58F55BEB093E4A941856836C7B5B8FA689996ACA0CE9EF5E14A88DFD61853 2B692006A29EC8492F21910616731664C6629D5F0D6118BC6EF45536B987C0060A12BB18787C 14174F7EA6A16759986D2A279842FEC752604D479B74DED432D712CD3EEE397B541521E21F7C 3E5352CD5B98C4944FB08F9B1BC70F36288C273D1FD74B7A9A5565EA9E69FB3E4739A586858C 865122210125AB07E4AABF35AF7D2948B8B13F69499AEC43242457B93FE382DB7DCE515849D8 B91C96EE155BCBFB2F5160986EE46AE7EF74FF7870675B8E5D22FB8594F81D096A967185FD96 32B2BB96190790E203EF5F2B0772E456F981AEC9DF29D7D5BC5AADFFD9D95D0446573859EE08 6770C307B0A174DC9A5B9EF35D22DBF191FC1A2DFD554A0F8685A09D731509A80D2BAFE62989 7CFF3B8476E6904A16A99393C66D11E8CF7A5B7B195752E0523A743AB8CC4F3283A544CE0D48 5FDE0773B2E364D77519F7D1E9F822980C6593B1555F2BFC8398340C7C4A5D9711C20A2CCC91 1D72A669737548CCE5871FF08BF72C8C38E4645E5D4E4A10687B7C81C55DAB8D7DBCDA0A1C70 7AE4029DE0FC02378DA19CC5F818BAF6F88258430C122E6863238C0D3E027C3FE17E58083254 83AC041EA5331368879ACCBE672677C0D91826F066853E5CD2542E035F6FEB730EE21EEB7983 DFEEF31B1C803A4715E0BF3CCFCEDBEEC6F312F28F12C56739CE813F9F70649823E5A8AD5C3F 5B06F82231F02D2DAAB589ADEA88520C2B5FC2AD7610C5069C0DFA2E4D74AF220E665869798B 78C3E98EF345D16C60641B226F7A91AE700388A85F8933505BC0C3DE00944BF08A25B692C6C7 D9F46EDB6ED4503B187530B3B80198623B4FE031CAB4102A3B99CF68123A38DACA0E49B2AF73 362A601BE22299A166CACED06D3682820F3B97A546A093C9BAC6585CAB716611CEBC87841700 88E5FD0D31596D6CFEB292EDADA2B6C3397041A8C972EDDB817ACA9139F6C4B82E0D39D11CCC 87A191BD10E23EB94C55BC72F4758DC3240442DCB4A1D2C49A6A05256A22DF07703245443597 9EF2993370A2EC7D6A46E832FDEC1F425F9850535E34000440D72420263103170EA306B15596 086D2FB6DAF78202B2E7C7A82A74627613521CCCBC4F378E7C66F38F4947641FB07184F714D6 AA5EA036256C686948FAB99043D6EC0E5F5458C376DC98264E8D38BA725CC94753F37DFBBB15 57BB10F9B300BC91943220B4C2F20A43041A60C978F4A69A9536E02A8B088206391DCEC3B1D9 76C0E18642B3BDD7513757CCC85FBA444D3C007CC7CF3F9CE68B75B8BB43D3CF74D68DE3F789 19BF1DF0E6AD61BD6B3B57571C72E387B61077A28BD96087C28BFE4450696DE44EA50B375EDD 76840AE0BF7DF126F2A96B1F2C22ECC06F49F3B737C89256961378D6A462A201AE88A3DD9930 DEAFBFB4773AC710E922FD78328D0A7C1BD057381668A74F988BDBD94B3C8132C344C527FA5D 27D5B50AF2D9F809D665E931C1C8DCDC9ACEA44D76C2F8AEB30798C16A2EB75847E1B39A59F0 4D419F08F4281DEB5557A2D53492861C75D66F48DBD409B8DC951698FBC6BBE88D30E174784D 46A6E11E49264D19767C2F3E2B192841FB15BC169F2E37E6532BA7C805FA51C62957851F1E85 49C400B22DCE93ECF10861346A6532480A3D869186E42784FE0372B15FA990D9580A64910345 2CAE1B433A32BBCADF600EF2DF4A313889CA84749149239CE69B1BFDD816D572C359A9D83ACD 19EEBFB754D8A075876AA99E5C86751542329FC61D247D094094019E78B0101C865CB0F51EC0 F1003D5F23F7BF8BE9A53DAF2B6A00B0C138AFD94412DB581316BCCB2E294A1CA794EA15263D C759B61BB45E14A2C207A1AA2577D1D64E2D0C515B10EA68CD9200401F750971E80D251A7487 146A8AC453A5F809532354D3A36D612E3B8F7355D566F54AD4959D9207338987026DA48FC975 E43F8EF1595A56FFD4066258AB215E1608867C2BAB3006D78D46BEC9774884B1A958DCA0B0F7 FFA98C7B1BCFE8699E64A044502ABCE20B997A1B87B605DDB977CB7C66FB2B7496180390B6AA C711A63557163EEFB9F5C530451F70028D83509091497B388ABC1CEDBF30BB101EE4DC8AAB1C A4623FC6EAF5390F361E0DD80597C6BC9E8EAA52DFFB1FF652767AF4148D4F72C2B5239627F5 2784D54145D325C9545670EBFAD118C0F16AC402DCBB299F204CF42B7017F0D3CAAEC74620D5 AE7A2D66130B4202391E6FFFA18F3CC2A788127A185B4A9244E0E06F2EA056A3B377225229D6 FCBB56DDCBD32DBA30C613FED48D9890BE8722FD441DA56545BA40853F12ED9B596F999BB145 0F42423EC3ADA8DD8BBBA651DA6026397A46DFAD76888F612F6D1B7E1EEB959BBEC22AB7F4ED B6F8DBE76F162D394E61D225283BA461502306941DAEBA75FB6FBACAE056AF835B2FEDE6BE49 6AFD3CE06BBD8A34F77DE79CAB805A1F88241990D2B71DDCD53FFB3E536A22A7460A57CB8909 B1DB369CAE328564FC1E68E094A275B9D6A69156C1F1F52C251CB338D36BEE5B11A4DC3F83E5 35F91A3264E5C8E4F086B42B613F575753EA3D708A5F1AC195960BBBEAEF4DE6D1C58C45E6A7 C5AF1840CC3923B1A9DF2CFABCEBFD1F1386E0C61A1576CB7A348950F7556E315C255678D8AC 27DF7503051883B79A00D40E8FCE7B14A09A66908B367882CC808B9DEFF822DCAA1E648AA63C D984A5055D931D0DD82C3C65ED0A3EE3DBA7D5516BACD60A2DB25633AF6F864B307BEC9356C4 99422FED8B8449B142B4D12B0637EEB82BD5C3541537DB67B099B33A0407E988C0EED630D7D8 9042D25761A26E3C0A3C143C037B43FD10E01B759B07F4E7E92177CEE9AD78CFD7509B7DF136 EC05B5F373709D72B69EDD9FC4029479E77794D4A15C2DCD29A26AFB22D60185A9A57A4A0AD8 3F09C516844299CBD4CE4159CD7F9C191A003ED211FD86EC3DCBE38C6C8DEBBEF252229570AE 416387A4FC03ACD075EDB53989692FF3BDFED86E217EB9DE4F656B143773FB7326A2B44F1370 7A2273B774E59DF0A6DCAB9DB93D305B7DDF8A73796F8CDBB683B44BC63C15F8913A12ECBDEE 3920BD0E9A0FC81A97B59F5DC7E2B49C993A2D9CBA28D5704E15D702936934AAFC0CDC7447AB F7C2BC61F73C7BF1DBA55853A12705BE08AB6792ED0E84F07D86C53F2C22BAD9128013CC622E 42AA03A1BDCCA293A04B5F73D7A76CBDBC1F32B428039C3739FA5A1D75A84C29894833E77792 DD0FDE2C3CA782B634A2868D9C1218DD8F6B1806FE6D3DBF1CE9BE27674A3EBDDB38AED4C087 6A8D08A578977BA685410084BE04CC507AEAD5EAF285BC6A6E18FA2D6127E38188791363079E E07BCD68F53372CDEA2F98B9EDF558124C7047DEFD116E81DF56ABCD1668038734DF84F293A3 387777026646397E36F91B8E87D2DDADBC8E2738348E5B55815A5E060886AACD2515E71BDF94 589618CDC6B17EC6BB957246BCAD2F01009A8CC370BB18F389E8B6C9B4588F4F6DAE619898AE 0AFA7B359699E04DD41E73538D3CFA33437F3B97DDE51D5BDAD00C22E50E5D94315C45B569DD 9C24F2ECA30144DBFADC451C508F0E85DD9A6EC2878F06225359649AB459D50072A2D11E4F59 301CE94BD672640D3E3E6F58E335B7ECA974837CC0B5263E29D34C00B2FA9800E6CAD0D349C0 BC1CFD584CBD648BB3EBC9ADA8456D0C097DCB81C55AC72ACD223AC258F221141B8CF5555B0E 30DB348599139E6F9E7ABA032ACAEFED86735B6EC68A0CC9AF40911673896F8A53E68B442953 0336E94DACD1024D022970466091FC2DC415D5F45DE6D9A92180E0EF69DA37E014054FA5B164 155AA990E7461D372129C953413091580AA43605994E8FF02D5BC1E54F14F0A54E1CD7A51919 5240B2D624DCFF13877BE38A668B1856A0FF96C95C863BF1A84CED2B5B8AD7E2BEF463D74660 8B07BD3D0F3B315E0234EE06C78847FFBD738BC0C484F59A40E92F095C8EA0463A2F24275F8C A2ED85C86FC092B92F10B4A76E303C0F359C723FB5F2831178B35056DD45D01EFA8B73577467 B9466EDC9E7D1A5984A7FEBA05A72F23DA9612A6330D9D26220F90366C564C1846571790656D ABB3E1E90C9E6F82D974464FDD45D0BB9013AFA07842297E5735976DF70A3CF4A87B1B02C96E 4CFBD08A56391EBCD5453C9157199F006BE605A102B7E1F89199BF164B8BC15FA5AA18FCF3BC 787C016AF848697318A7A84DD40FB4B790F619243A48E75BB637641B5BF5601A7FA5A28D716D 11DCB9A2469FAF63F5448FDB8457FF2F30488A129F310982824DD303FB957DF6C783B8F19734 2C8CE62019F2284AAF444C7D6DCCD74411CD84C6F18C07EA34388C1D0F15FBBCCEEF8605F731 BAF5A006EB1E6B34CB567175C9FC0DED63DE0C466B4C35D3AA5F9FA84C50FE914A8F7321C7A6 6AE9215D079A80E8FAAE17E030FFFD006C54FEA36DB19EEC4814E26CF875F4BA2005DE4EF84B ABBD55C667DEEB8D5D3D83550E55B98CB00FB45D2587B1DF1A7F428184A8ED78D11DD2D96805 9B406C19303759E127397C65C4F546F7000100DD311AD2A38DED6B6C692F5431B34129EB9361 C1D190BF753E807B09831E901DED093A88E6624CF0F46BA8D422D1750C43E4CFF9BA6F76BF66 17CEB95FDF8F064CAA8996E5BF7B575EDA82D026BBA76D7DB5F54F097E7AE63663EC9938A2E6 031F94B273BE9936E69992753B967A42020C6140C5FEECC5703E5A565A27CDBE67617FFC7912 112B60C21262A92DCFFD31A4AEF1F00097958114317B153BF93F8C24B5AC9A6336E7D65BC42F 5A68FFF36A3A56260E4B9E7B655C5B9709684ED04D8CBDEE8BAFC1879148BF81A180B0F533AA CDD1F402B7A82968117002AB1E7A4E4B4CDD5838D7C0572E0F5FBD13A1D36549A96A7C42EE8C 4D6107E984285D89A18BDC711616A6C68B7A92A2A4DA76F295C99D2E5C754160EC9A51AE9F7A FFA41547B0EC4210B92D59193B81A973D9763C73661C1C7FD830EE2202A88CF2B6A79D438B53 2E1714D9DC2E3F8298EDD522FC082AAD25C3CDDD50CD1F132AF308874C1A1904E258098CD371 9BF236ABC9AD83F23BF276D48A13886F18857AC75105F0254205585BA1322F1DDA52C1A1A76C 18685B5C3DF7B59EAE4E55D87266F67258F14B700CB20664FAA502CE8420088CE1A316BA16D8 2ADBBCBCC4DC7F817DFCE3FB21FF498FB5CD956607775FE34B1FC20EC21676E3751A579B3FE9 DC4B7F7F99238898EFA6B10495E64ED9804AFE667ACAE7E8E1D7EB245163D0DDB4B74F755EB3 8B0C615B1B8FF6D1FB6830A1667810156129EA8A101B101046CAA3F7CD60E46D55BB2814D724 1B2590E151A05F234A3737CC0DDB57A6E3C8A4ECF0DEB12A8E78FD22B6650FBDAA1D6B342B23 1725B5E9B5C153FB08CC7B692FE7A2BBCE04651D3FD06DF84219655140F3A46CC167A9B56BED 00EF6981864B99057438C58F476CC445D5A1D2A0DC2BEA86DF1C81704179CBF01B843BB8FE79 CC5C6B1C966A49E61F6D453D448C9A6C1E5AC1356A67CD6C7E351D9857320BB6369A01F0D1EF ECC718940CAB37677E9F0E37E53FAA3DE8C0EED83071AE6499663CA8344F9359C2574672334A 1255F39DA556F5DD732A4E5E071D62C136FB70AFFBFFB0F8AD749401ADBA3F45D810AC46F4AD 4AC7201E1F15BAAB988A68C73E56A947E3C5DED28500C863AC2162A766771993D2C8D4BE69A3 18DB19521A39A303F031601535DD9741B619ED86820D586618A9B44AB0BE6A4642F9E5A11551 ABCEBB1068186B92AF140DD243645F3991B3553EFCBC10E47D13090E2F1D683584C29CFDB55B 8792FD23A55553ACA2A0C0FDC8AF21DC1BBE322B59515CA5B41A72652FE904200CB5069A09FD A144F121E7626D14C5FFD64E347D9ECED3211E71D620D2D0BB417C35F7A3437A06B4D25C9C54 0923ECAB9CF66234004827FD0904C52F477196FCD17638BCE24537545DF99148B19040C86C56 D4117D17FF23E01608DF1CFFADCE5376B51E3F8CDC3E5E0426C1C7A18FB858EECE4DD124A6F3 538E94B4B7F81BF87E676554DDEFE1ACFAD2B153676F15837EF9CA70678C77892ABEE7073CDD 353D35C351CD6FAC1E018EB5E26F32414831DD937F54F259A37F0BE85E510C1DFA2E52AF5020 B6CB17030ADB3DDC8B767CDAA84F78D00C92FC1EE4964E30A06E4B06CFDFD690F16BE59212EC 78EDE080D967FFBE3E7DE247E26F95ED65C8F047F049F555CB44F62060DBAB74B02277FCE39F B093DE6FB2E043F7B9BB6CE4800C03804094E366F32379FA5C6C42B37D60C5864840E7101DDD D5FCA36C2C3608F8199BBBFF02F7240722A8B16E2976998F6242E71D9DA971A522689D74B379 D0BA2059EF1105414082D60A09B518B36299EFA56432EF75FEF406CC7B81AEC55714C42AFF75 0DEEABC6233244A88E374F91C0581B84CDE79BF2BCA66AD00BC6074F4B0641751BC98FC52F9A 564B9B534E9FDA14A524956C12A4A74CDF8AC15371A4D4F75267FA5AC6F16ED895EA6811403E 576228E4E09FB5FA4CC8275241D1AF5533A0C9E598B1022CF78DFC144AE402D957BBB5A47969 BB7392DC9FCCB6D8947B5C5C2DDE1C98BFE6B3E26FB0B3618CCF74773388289D7943E144BFF9 CB5A4F30B23ED5F5AE2DB62F08F6E50CF99218E9A33BB82ED72F12C62B5D7ED7AD7375A77CB4 CE52AF221144BA7F9601EB8DFAA361FF21341432B8FD8B8226D1B5A2245F7356B3B84CE2D9CB 9C5EEB1CECA976ADD0592F78BB8C4D85E2D5C6179B30B3175B32F0D1F07F37114CD475FE918E 4DD983BF35C7F5CCB415CE41C071E10D5FA2C5B2277071539B6119028B41ABADDEAC18300A79 25FE207ED0697582E76EC0A60D2B6A29F007F7243B94AAD34FB0C46711C15A2108ABF238581A 5AC32FE07581261B47C375B57BC7F3AD6AFC71D80E6B5514CAF2C57BAE6D519F94BA2F95A9E7 ED06933113D29F48E625EE414A22850E5C24C768BDABAC2F5E5C4F7024C42368B5E161F27590 27D09A0F01177B756493BD4D453C4445C8A17CB42BF88B7ED5B0F34EC4D014EC373CD226299B CF096D059E8065FDDFBA19E58679EF30CFB577FF360E8C7BADE6303C599B8A5F5C1656BF651F 8CB9CBF05912D1852419BA583F54FD5F63ED121871DC1A5E040715CE5DFEE5C7B412E65AF9FB D38A3DA859DDF75F512809920948CDC124BCECC6D1B18E67B75CA8CCEBB488BD8684153DD906 6C7C92258D135BCC751607AD093BA50040A3CF04B7A5A53EC4A014D8B7FE016DE9481EB50F01 3694AA4C9336E122783CC4E964BFF0638AC69D2A174C2A39C458FB49E024A057A4ECB0A243F9 B33E2DEA9DCBED379CE14E8B66E72F3BF0598CD55B2A256F6B8419218E8D56512B57151B0FD8 98BF7C38B8FA6A82CB4EB965C8DAB45E80302D6DDDBA72029AF77228FE296D50919A280723DF A247E0C636CF6D1FF3A7E8F827B5AD52EA6282E4019CF1F01A9D09833F191C2092A8DB728451 F0B0FDA20EA34FA0F2DC3580AE0621A7303EECDC7CFAEEB307F2220199C01CBE42F27B67DB94 DFFF4EABC96828A41440177C5DB6F190C0B6015273D7F28EA79383D33E58F20290EB14B7F7B8 FCB6A4FF0AB89FCB001A26A356781AC30DE98F0F9A62F39EA367FBC1E4FA2FAC9A130B3357D4 726083F18D5E8961C52F937712CCA680CCF6E361A951461DB1558535C9B5DE9F1C8E153F8815 82B7EAC247BDF32D018129D6F95F9ED41E024D531C8EAFB376842C079E09EB9C44DC586EDEE0 2E335028E89C9DA2ADA468E9695B0B5093E88A6957318B03815BE318DD109CAF3243914CEF32 251EAA13815B23020312E3D17029F42D736A2D2CC20E8D64C5F0D0C49ECF4B1B769CC03EE45E 64A41917EC9118B9307B0CFBD4B1B784CD58E2AA0481CA12567BCA6BD3BD016E2FBAD4C3B8B4 FE9DCD1C5DABD829F6C908EF9B575F23D67AF3B52A3C7FE191BAECB8C3209D4E50E3A7445936 8824AE7DC4B5DC52CC95C765B79ADD7C93968205707963FA987D90F33A41B7C3411E59A1D125 BCE6B22F58A537899AFB2FFD2ABF4BE0A74FF60DA0046B0A5A641261FB23400CDBED14124988 D8D39640B84E950B6E428113BE2838B81F99E09F8E432369DB29B68B7131DC489CD5AA958354 12EA88CD6474C9FEEE3FC97AC2D22A583E52A2632865383DA3DFABD96C7FD5D564BF76B160BE F8B29737B6EA0A8CD493CF109A5F97BA1CF042958A0B5AAC40E42E963F331D7F63660233F45E 3015FEB3FDE4F960B8FD7791B4608075AC660317BCDF368BC7A08A584546C27769E695F18704 83BCA4E34D63F606CD3EA2CCD8DE3FFD00DDC952603A4D4BB6C3F35B3DBC3CBC0278A270FFF9 C73189B8846D7F67C5FE81BBD38432030DC0D1B58D7B73E1D87880F96E295552EBFC732E6156 2878B98575522DDB4D3BB3F2277BD1C822966465A8D6F9FEEC6CA0B925889DAA54C7D845C0C1 699194E1D238A8FC90E0C61EF1F7D29F86AEDC494FC3721ED813691E781223F7CDD16BDF1819 A11310696B6357E27EF4097E09ACA4641FB55D783591C72D0D51AD8695442FAA58A0C7B96C1E 199C6EB3064A1024CAE27A318A9931D7DD37D983AF159F5B3CFD45F92F54F15DA5D1A3CCA367 39E189C61436011974D89140209769E6B42BA729E115EFD02C6DF250818FE8FB91EE9E9698C7 2757B030CE4FDE201A69FE087FC9258058BA9C4D3DAB0B2481B5457259AE608C114FC811E33F 1514057F627556E6559354A8A660500CA2C95FC6608B4E067913C4FF08FDBC69740B2F2E2273 2CF091AC243182B5E20BCD0F3E77AE13B129297E4EE30762CE27ED963F1797326A39F70C9D58 EC4814F9922D19F8B12769831A710D7E825FB59C9C7DE4EC3ADD20D426A8356B1B7B03B48FC6 3630B5335EB9B68D3009C7686BCC986308CF9F23E3E8A9CBA4EC9F232D24DE48FE83C99B5F46 C0FA712EBB8AD4260E206BEEC28D55C1E26440EFEA87CC3A592B51E3C3415695D29ED1D3198A C2FC61330B0C123B279C265CCBE40C4F0B1242E94B354281F26A1BB0DD70A1D7AA7F2452F2EA 3FE1DA9EE43ECC38FEE27F53DB6D5D3880154014ABB1023E4FB3BA5458FB0314176E2DFDF445 0282C4F0D8778A5BB3619BCF34616339812956C733BDB6259ADFA887577840EBCDE82E3D4DBE B9294FB2A8713C1EA655EACE31249BE2431DE1D2E37154BF64BF99437DFE26DBEE3FA3051D10 3C0FC6F10A51499AA220C7B9A23125DE41FEAC02B74933B0B1F328AEB4906239BB13E0B24F83 075771870F01B4F4A970B075E5BFC1114552C22996286D9870F132FA9D64704BEB931F402B77 EF645665DDAD5EFC9D6CAB2096CA7CA4B5F4647B091BC893A70A1AE7779DC004288DBB2326AC CC9FF6A71FD892C58C7D69786B6CA0F5FE35DED10AEDEEE6286481FDD88F044567F9F1E372EF 832FA7C2906F96EFAB72DB5E62F8ADD0E7CD6523F6BE7FF913BEC986A00649D4E65049EB9502 EE1B35D9B016DDD80AA2795F880F38BAABA202FECADA6F67A22A353CF65242E4C3A0967AE33D 0C9660A7DBADB7364B8678B3196B1742DE4668942399A9214111010AE224D61FC53A1FF9975A FA8A588E434B69FEC33F33F1447DB75E2983795A3E2504FA3D59FB4462BCCC4DEA6A6797F792 0E04CD8F1213B8C08FB7D5DAE0657C096D9C2310DA574391716DE57AEFE730CB13C22E560D33 5C4708ADD66B789C08C9149F33D5D9D67FC6A6B98F92676D736C27D8CB351F85187BF845EB25 E50F68DB14771A7EBE930BE6079970859780B3C04A291461D2F7F34E31AC0A99C8C7D5EF7A65 0E067ADFF7DBBA16F8D987B35C5DABEC96EC16EF3657A9A67603C9B8DF5F5DBCA20E0C2542E9 7223F83295A6758EF54074B4C178C502318F4ABA81FA3D5E4E42F30E959A7A6A7D472ABE014E 5D3B6332C6CA5BAF3D028161E27FE8AD34811D12D394F08EBEF835F1D24EE4DBD8311398085C 790D4FA6BEAE0E82136B78439ACB61085C19F97B083A3BAE74ECD65265023556D41B4DB72841 B077F190BBB1BE10EE87FD812314C95A42490DFD9AF59B5F728A0CA112BFAB781323837664F8 F61D370B86C7386AC024BBCBD7B8402396A9AF17A7B9A601E03EA98B2050374C3D8A5A393ADD B28449FCD667E09F541BB2AC3D8D9006D823C8CF4AF6D30F250115437A583CF815038BB1D47F BD82C3B2A666D947EB9155E6843E74B3EF92F7452EB2AAA6D7E381AA76934E018FF2A33A30CE C26663C1785344743A8853D0E198896C92858DF3A6894632817D7E8DC03FF8BC68DC355B7158 1F6E9740A0CF7E06E12CFE531AE872FED8329C3C75FDD2B2B2FE2642342DC7AA1C1B4B404CBF BF22185C6C20239A075B7DEC651110A253AADF86E8D9A87F5C2C3B35BD60D7DBF44040EE96ED 65E9C7A3E69E25695C55A197BEC858E2027A59D6C8057A63DFC276BA2716DA969ACEFA3CF837 4BF4997692D00793E46AE663EB949E726CA39B42F999FCCB5D8C4586380AA5D7B7A2C6518603 2B5CEBD8CA1D52EBF48B48F7A4E1EEE090796DD37973004F20C04785B232332880C0F845BBE4 0E1AA7279DC85780B9EF863D9B6F036A2622684856CA0262484ADAFE8F19EBA3E1ACFDF56748 4E8A50AFB36BDCFBDE2A2CEB59792B1124448CA7EE428DBBA56A46051014E950F0C4E9B1FD13 5DD445AA9176C41576A9C94E03E91F4AD944876C917CF8A80927738CFB566CCA7C6D1E63F3BC E16F03F752B27F2446CC13E212A9A492C2B9D434EA054DD6CC5E5C896B2F326B0C356C0E15A6 26AD11C953C62273FEDDF4249A1AD770FE2EE39E901B3F54853050C1055BDC69805127BF8327 F99F5D1C3E10EEF3397280C7442F8304A3295C3D7EA1A965E1A3B5CA17FDAFE9BFFE9C1EAFF9 796D4C1BACFFA065779164D28F4F09F29453D9165DE14F1CA1D2AD02CB51F05FA98D04877BC1 59B0AAE4CF2DE93E26DEF60944D25E190746E5A661C25B33D9941C30CE1C99C9C471625A429C F69CFF9697383316A269E48B435EEFA2312D5E214E69E492A3E7BD429EDB4B56936A55CDE475 B576A849B81D798B00FDB9A6AE9D3ADC6AA58922E59FE95044F8284FA5ADAFF30DE88D484F7A 015B11D35DC50D9B454D6D169C3E251CA0E4FCCA8BD08D3B72B48E41EFBB7739DB1355A3B128 6E604EFED37E2F6F1FB16B688CA0DE86CACE2B6C3A10881C1157B772C89D74B3E885D00806D2 8C06429B9619DFB61A0492FFB491BC299E0EFE4EB37F61C4CFCE9819E0ABF678A02296233AE7 A4EE46ABA2377A22CEC36C2B6942EE227AB674DDF0182F6E54246E40A82948C7783913AF87D0 7EC0D21A82C0A3888E6F0913B2D41B64CA32667137A756691CBA4385F409B51150B43174FBE8 E3D903AC09912FF4821DF6A4E415D849DFABE544652B7CCBFB11B1E076A1BFF75F80094CC71A 178098082FE0AC069C234475FB052BDA47B65BE3860A05FB8E0CFAB1674D328F4B70408FE21E 91D3AD01A300446624833076DF98407D002F0EE7D948CC5A76E0F595EE5F1E8AB7D712319F08 FDD3B923870B0D4D0BDA7EDE7B8312522A2AC9CF50A0F4B50730AD4F64EF94F65F66D9D124D6 50966912F48C010B27214C26D8E09888ECAF4033E17E0E57F2E2AD2D04A5197C292B281E6894 9BAB3253BEFF0BC08B90097A93A1E6A077A54CA7958DE9491E10B6D272A5C76F9EF7B1A19320 858DD866E1FF46E1EB4A73E8F4F54F35C5BB33236EADCA1223D8D4227510498EDED173D78332 09665C9354DC9F58D837B666CE337C46AB0636B54793A5607E6603F5A807926EE0AC9CD2F138 68379DF3580501049A315CFBD9A4969D274DFEECD0B14304958FD571FBE2E4017B8A27853897 14BE4CA12EDBE0C0EB78BEFC76315AA8F60EACF53FFDB1D3F59BEFE9A89884484780772B6C24 E5BCFB06480D174CEA4BB5A0EA9E09E05B0EA39D5AD05F76F58BC9B57E96AF05DB72087FEAFC 32845684F0BCE34A303BCF991437990A1ABDA527256AE23AA1831D416958953226AC621F8430 2197FE4FFFF024D04F142D820B4F04461E2D4EA6787AB2484338F5D685726C9A9A9208D0D9E0 15588CEBC34190CA66556323C4EDDD2440480C205259A1B6F70CC95A0F0710EADDC72D4BE536 E6564D30EFF592B069762F924BA012DA684306B055A03671DB9B0924472F26266EF11DF861E4 DA81962856EF1BC4E989C72D475822734C1E3213CE7D7EB82CD1B8E9DA40D2CE26B476E9C716 14EB2936471196B81168F8B325222E545BDA1592F2C3C84A4FB9F977A67EE586485152B9F7C0 7D828C04E1C9B7ED189903FB44059FBD129491FBF6FE6B8124D666DE63A37263975174524E41 93D0F27CED49AF87126A7F7FC4F3F91C967E8DF5EB14DDFEEAC7C928FCF2A825D7FFD37907B7 46F313E5EEBBBE9B9BD9746FB41839CDC65BCD4DA7749A5B175D9D9CABDDF6A73ADE13261E53 3D3CA5A7BFF53842F7CADA3B286CA81DC5910B1D9B397BF711354EC2AD02B59D64D91EC6D5D5 FDC3A627C94D3E17F990B080F33CD206E690C05A8DC51684A659376FA6C3E411C24B701EEEA0 F77D3B95526D4AD25AF4B8FE1341A6037C25B10AC4851C84BD0F3855BEBD6CD10AE91050B027 02088E931CD96B6A99F3307CF11AD651B0FA04F917FB4B3739F66D63023E761611A9D300071D 3422C85D7EEA134CE7F5FD6D5C202A97671D1C078B7CA8B3805DD21B22BD5518C6B803008973 F42157EF1CB77174CBDE8823F80336BE2F5C01FA5A588802B245CCF6C1095E30AFFAE3D0E99C D7A1BCDE3582D2A3D355340E36943DDE7F764A7FE4B8321545BE04A8541830F50E58B7236438 2179CA6393F5E819B1DC84FC5783C92746C614F5C91F5BC180A896AF5093F46790966AA2CB68 5FFF37E7E3338997624D0F9DD447634C5DE26473606ACD6DBDCF1E8194D1596AF4505DDEE0D9 64DF9F9D5FABE81773BDF623F3A03A7C40A6255B303EB9A9536E0711CBFC90F292F571988DED C33661685A49D19009525BFDC2FC4DE5889294F0D77C147D41A45BA4F8E43651154266C38839 BE304F9DE6843AD2D6840138778056575BC410B21E7543654BF0DDDD0A732D540EAF7D5C383C B07F662F009CC862D9EE2B272ED4423EB4BBFEDFED2ACB7020369C996C612AEAF3447162F90C E2083977688AC315AEAD5C57F73CB8F54523296B261DB64F1ABF926C687B7AA5F7EC2472AD04 98BB0D4382E57C8DEB9CEE5ED7D3493C7557AB9C0E875181750EBF307CA650A66F13FC03A49C CF2573279A9501B2C0457FF0920ADD1E10E33B3EAC850A43B7D3C8D98988BB5117117AC5CC78 C434CF31F5074F2E2566CB519E0161FDA2BDF63F04E7E2BFF275208C2917923E0112EA910429 76E26D50365E9DAF859E0C7BE9DB46ADC226F0AF37EF7668C4901B9E7F0AC68288AA765F78A1 D2646C7E50DB75711941A21568E64AC109F5EAD56AB4AED35F881C6E24EF745D8F571C07C660 6C54F63ED9F8547C0689F6C9EBB770424390DEB4C3F851F201AA87ADAA8394040522A55800D1 CA8F6C9722994869623A94AACDC6D8EBEBC34EF82CAB787BF35F9AE176D96F2644A6CFE3FACE 3EFF5F5D0119FA9231578CFA5775DEAD271C175498287AC58C7326CAE5E00015BC02188DF6E1 471720F04818A47679ADBD5A6FEEF79CDF1242447427ABCF4A6557290F8ACAB7DA5F0F9F8C01 33725D75728FB1855A84B7962ABAC055B47FEE71672EF81C3B04781ABEC2B6C22CCE2D680746 14363903199A46C9D7ECFFFB73129E2FF044766A85B54F3EA13642713A0D27C6A83F61B9D31E BC98B29BEFC79DA3CB58230DC5CAC5D0F9C387835E0018403F0DCF8A18710388EBC37AA1C016 F775ADAA6657BAD29C5DCF2CAC2CD9FCE27D64ED247EAEE7ABADCC655797E05D18EA60D434FB 1C23228FBEAE9C973A3FC592C5C0E61FA72EB5F7221B4190B7337C9279F09D49E74BA3049071 96990E9E9C2D4CE64BEA214732083FD9F7C4495A2BE3A63D40EAA12B7423B03104E9119EFFAA C0064D86828E5CF9BF9E14DF4369292F0A59AF841485AEBFBAF378E9B52803FD51DEA582AD40 8E7CB1ACED2083F7C2E8CA017C4BA4E25CC46D7CB7E5895664A7B55CD0DA11BDDC6FDFC5E229 B7C0219C939D857F5CE4FB70D643760DAA0CE0A7B3AFB658AA3C93C41604873FE471B7064383 6DD1610B7CB9A045187E8EBA00DEAB7CBEED5ED430167519E1E8CB10D9E699987E0B71006D6A 62E8A5DDF6476BB85574A752C555309B6C9B722D924AB1DEF08F835E7303E2DD99301D1FEF41 74F4C098F282509C9D4B2C791399CB17D6060C1C0534A2FAF9F38678A59C28BBAE714899838B A844CC308BC59415A64CB477BE52E8F99B1D18152CF300844329E61B511846D5EE5F02A611A4 CE11DC0F0F2E45FA9A3839479291C5AF0979FFE489CDAA1B42D28499AFD966A0A1FCA6740D5E E217E10C0175469504582CF44E633199C18636DE5924825C247348B6ECAA36EE8BC620DA7597 0FAC33CD0E98904465D230B64E491637B7E6C3DB4D294CEFDFA02A23378DC81C5945AD36B8F2 F81426C0AE1C46DA56D3DDB54A3908868E868E1CCEC945D6849357A6D196D9CC4FB967B3CE52 3C95A84778DC7661B9E6C9D43B9DA85A8E706D71D5F8EB2FF2F5A84EB1B562608C0AAAC846BD 71471D84FBEB5A0FCA36D8E3A0F640552A98793E84B4F5568281696DADBB48781F23B2E0E687 DF38E4955D53F0FB3843489E826F7E20ED51D2A3EBCAF564740EC108AB27DC207271F7E63B37 991FAE2BDD8744A6304AC446DCB28279450671A8B00558E04C7110F878910E3E7C9C61EC79C9 65462D53F00AFCD3B4EF5AB74D5BE503A1FF7305796774B9BD429C7711505D53843F676371F5 8A5F2F6AE8C16421AFF3A455FC414F0B4AB198B4A9F7B27534BA01DEAE761FF6506EE5899B42 519BD46F91F6AD2DF528BC9736576BA9AC2D2FE8E2B4251E28BA44128A55EBA524F99F367B83 F7BDA7AFB8C531D54A197916584547B79AE434BF9AF50C333821453E1D4841B9A576BE1E3687 07B8637A493CFD11318797C931366B38AF77B9BF64D128A065BDA50725588C6E1AAE3F6EBDBA C8C7A3950B3FAF007C40A5D597D96580BD75FDAE0053CD8C62EA7CF631ECF3A643DE3DABE021 2CB7670FCC158C57A78D180045DC5660362A3F17739584277EA1ABFB6181B1517395C5E5594A 584E64A43DFEC71015F160886547F70A1D892DEC359CBB9DA5138AB29B5B1F8E56C136632A76 97246EC79A8221061CB212FA3A2A03FC38F55FD8512E327A6F1CB8E72881EE1B2E9FE43A6F79 424560F1D21B08B9F76873149DEAE9BE52ABFF904CFFB15CC603C7497F850B189ED11592B339 926CD928F8AF76E69829B2FCE988C6613C36D09AB944370DE24FF0A448BBA58E0CB4C7B63B25 20658143FFB8A042C40380FDB15693F4C49725C9C74ABA8C3C571DDA80545E2D92F721160877 2F49DD3FB42465F31282DC0E62DA7CE2A1B40C0868BA63026BBB56D35A47AD9A0D0E230AA7BF FC4B4AB1B5069EEBEE9395E815EDDE1BA254A80D8D38C7073E8AC15478138ED4A22DB36D9B4F DB930ECD4A3FA98B87B9D542505E5D0C993A374D8223C40DE43BE22DBCFC425CEA189C212A02 3874DDFAF5A1AC7F5F4F3A80C34269A6F5D7833C8F30E21D5BB548BE792F7D1149A94174C69E D90DA8B84F934634966B70D0465C1C2E4907A9AAA62459E010C1781A207CB49079A2BFD54372 1D8721ABB895BCDC58B96BC6DCA23C3930F72D1E6A9A2E61713BC3F2B4E6652F75E9FC54EE24 60DA11E071C968E00E9C706E5779D2601D97450D9FCE65BD1DFD4F5BD846625B6CA43877F2FE 6963728412EFC91273AF66AC82E95C79B4E0A949DC88D958BCF50F052D620B1FB8D3425792E9 C6388A42A31C799F31D29A4BAF8260E9A833C98153C80614F22E513BEB9430315878E6C3BB66 0231109B6E98D2ABA44D759D8792CD01B86071C2BE8162E31EDDEDCD1A5270889CD0AF7EC1D2 1D1A4AB2B6026BEE062673E1B74708088850395C7820935BD447898A1EA07F3D23BA73F662BE BBFB2F45ED608965D9E77432BDC514DF5F516D0316DDA35321F80C03926657E9A16132EF6290 953ED59CDA152C0F2DC38C275A675E2578CF870A448FDE7D73E679AE61E6BC311BB313BF975A E7648EDF1D084FDB3D61DC14BA882D489B2E469BF4E31EE93ACA0A9083747EDAA559D59204F1 CBD22778B5A2995F4328ABDA61E77708052B80F2F85FA83A3A3EB61C2114B597B787D286C9FC FC594D7E1B597CA3A19D95D7029B81AC8338FBB48A8C63D903B3BA18E17A4B3F4404B6CD6356 9ECC2EC3BE18A5B5F435501841E8DB11637DBCE823E13F48D07732B991412F1043DE7323E4AD 7FF80262A845491ED2D6F3305F4196E53AEBEEEB3D1D00EB1C8950B02BCFFC1E2AB41AB270B1 969BC515D519A69CEAFE551F3A1C96E803EBCF2FCAA1945BC5256B774E298711ACF5B81AFE0C 8051D3EA70579B2CA6476244BE68211DD20A9AAFCED929E0B817AA845E4C0F6A26F3119AEAE8 B04555F5D6EA3F7A49D4D7470B6D29F1A2C64BA1622D7EDFFC622C119A50119B7319BF947765 841871026085AE10C87D4F3D4BD5B837817FA725390E523F2E3F4E052F4DA11719D75F9416E6 8B36CE1517494AFAD0E1768817D39E7BCE4700AB207086FC8230F40000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMSL10 %!PS-AdobeFont-1.1: CMSL10 1.0 %%CreationDate: 1991 Aug 20 16:40:20 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMSL10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -9.46 def /isFixedPitch false def end readonly def /FontName /CMSL10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 161 /Gamma put dup 162 /Delta put dup 163 /Theta put dup 164 /Lambda put dup 165 /Xi put dup 166 /Pi put dup 167 /Sigma put dup 168 /Upsilon put dup 169 /Phi put dup 170 /Psi put dup 173 /Omega put dup 174 /ff put dup 175 /fi put dup 176 /fl put dup 177 /ffi put dup 178 /ffl put dup 179 /dotlessi put dup 180 /dotlessj put dup 181 /grave put dup 182 /acute put dup 183 /caron put dup 184 /breve put dup 185 /macron put dup 186 /ring put dup 187 /cedilla put dup 188 /germandbls put dup 189 /ae put dup 190 /oe put dup 191 /oslash put dup 192 /AE put dup 193 /OE put dup 194 /Oslash put dup 195 /suppress put dup 196 /dieresis put dup 0 /Gamma put dup 1 /Delta put dup 2 /Theta put dup 3 /Lambda put dup 4 /Xi put dup 5 /Pi put dup 6 /Sigma put dup 7 /Upsilon put dup 8 /Phi put dup 9 /Psi put dup 10 /Omega put dup 11 /ff put dup 12 /fi put dup 13 /fl put dup 14 /ffi put dup 15 /ffl put dup 16 /dotlessi put dup 17 /dotlessj put dup 18 /grave put dup 19 /acute put dup 20 /caron put dup 21 /breve put dup 22 /macron put dup 23 /ring put dup 24 /cedilla put dup 25 /germandbls put dup 26 /ae put dup 27 /oe put dup 28 /oslash put dup 29 /AE put dup 30 /OE put dup 31 /Oslash put dup 32 /suppress put dup 33 /exclam put dup 34 /quotedblright put dup 35 /numbersign put dup 36 /dollar put dup 37 /percent put dup 38 /ampersand put dup 39 /quoteright put dup 40 /parenleft put dup 41 /parenright put dup 42 /asterisk put dup 43 /plus put dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 47 /slash put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 59 /semicolon put dup 60 /exclamdown put dup 61 /equal put dup 62 /questiondown put dup 63 /question put dup 64 /at put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /bracketleft put dup 92 /quotedblleft put dup 93 /bracketright put dup 94 /circumflex put dup 95 /dotaccent put dup 96 /quoteleft put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /endash put dup 124 /emdash put dup 125 /hungarumlaut put dup 126 /tilde put dup 127 /dieresis put dup 128 /suppress put dup 160 /space put readonly def /FontBBox{-62 -250 1123 750}readonly def /UniqueID 5000798 def currentdict end currentfile eexec 9B9C1569015F2C1D2BF560F4C0D52257BACEE583A5C939393E012707B47E0C1FA47D284A1EDC 9D01A497D772BCA8C543388E6DC0D1E2C4944740470E0914F65EFB0737B0851B2BA713A9A00B 36D07DA6BCB52920B9B59EFE587734027A3C5E6566AAD332FE6FBCCED1417802822A3B81D618 7875263D6BBDA04BBCF6E4870FEEAD60F104BB3C5A766610DD11AEA64A6B107B0B04439FA288 8B8CC39232BB83F7695ABA81F0260CD5248B9E649CD800BCB325468C79FFACB9CD3036F2ED7B B65DC6F12E33DD6D45B61272314F98990D08C0F8274E999F4B46AF4B5C5DA923683C960FACE5 0087915D2044D7211A18E0C22967EF89552662BA990E2DFB9267E09E354F41E74D44BD80A2D9 05D2EDD60D8829E820C6AB0FDF322964C1ECB6569818A465D5266D3366D748B412446E602F0C C52F3CAD2213FF6AD92C04F6CE8BBA94890FB44EADC41A0C42EDA4FE9722E6D4B17A3F6D35CF 755D0A1C90D0C2033B16BA76C456137ACEE0112E35EDFB7206A9CB18DD9274401C70C3039059 A583940F44CC19FFED32940FE8203292E103D2ABCDA173DF85995AEE98BF4A1F65EAD55FB80B C0C737589FA10CF51999C634E05D80A7DFFB61433BBDBA17EA9A7B92F763586105C8277D6A96 1D092617C64745450B7DF4EFA70884F6017D9B0331814CF702F1140425EB8BF4C269EC042FDE 895A7F625C4832C1A143A14ABEB798E23B59F88EBD1414A66520435A4C8F5DD7A548A7D6A2FA 96F0995BC0FBCF91B1A1EB711026A99D2404B2103BB3626978385830A00A02B6AA820CF33785 F7AA45E267E6EBE7D737DED351C1D4E944733FEB30A3E6F81C1A7B74DDC9148B46B02A525539 C54A7EB25DEC18807557B6EA94C36DB0C91121160F61BD37CFF40BB2B11ACEB75F146BE38109 DAEB77803D8F580F9086BC460E5C96F764C1254E36FEB59F4CC13C5324B005B6F6841413C8EA B7B4E5B72AEAD11EA0263A0B48C3CBEF08D9B5E189B29EE33528A11EE8AF3C94A3B9FB78D072 BC94AA937198B5AD852CBD82C786CC2716CC460BFD982F678B878C63A4D86D72358F53C5E123 5A2B60667E258580BAA99E2EF0E686A3BEBF3DD92411AEE590232CF6883E760FA271D7009E9E 23D266E57ACF2CD8D58D980C95CCC8786F84CB36C254769FDE99B1255E27D8736B6810E047C8 3911E082A13343E7C192E15EA50199FFC0D26AC886CC0D57E50D1EDEE1597FBD16A7AA661C7E AAC62E09775DB8F10B7ED4BC31F714DD7F69C9229FB85CAC4591A88BDC376119D1E48C1532C2 D2F3EE465C7F6A2F797C63AF27D967C36D99E976590EC46550A4EABE857BE0131D4805C7B6EB 9C4953881F21B921A11A53D361B992C412726746872B1AFFDF6EDB0E4C7B5E9C61A03BE7F61A 5677753C51EA6A138E77F6DADBA32D1A22B06FF8184EC811E3F345A090E832F99DB19E98C752 69D157D54EAD3C059DF5EC1D51DD43C684D4E73DA01B24D978B906CE8300D3B0D64309FD2344 02168967E88FC59A1E2E8C0CC7E294D3BD8AB9AEE3C53728F3FBD6091A100A06C7071A27E69E 8ACD27591A060A3C6418F863E8AC6A53A7C83109FE6B5DD44918EA83196D02A495119D8EC4AA 0BFB3D475A449BC0E6062E25AFA16F391EDD7F4E31BB41C96AEB9456055A2D0E5BB63D3FB71A DFCE870CA8E4462F08A5302B9F456AEAFDFF6F2F0BB9F2D181BD2A33FD99500DDFEB64756308 8235616DB75DB8DCA428B4CB1E8DC19A797958D890885F78C53D3427914899652F3ADD72D170 68113BA323B138BE7CE35C8FAA2A96E2E31AEAAEA9589E8E7DDEE73FEF10F3506EB8483C1994 93E879ADBB0C6F97C97179297083811FB3079150F94A2A69B8A2406641643523B8CC7F5074EE 14681D43F01993B508E6CBA6D4006E49EE526CE54F78274DD0EE40ACE068F1DEC7CAB0283809 614950BD6CF6AD5E0B954461C0C2C55AD2125E91A8D8A8C0C57E3F43A513AF786A71EEC82BE7 C8E2A9F54642C8E645B76B3A6D11D02AD91DDDC910FFEF08F7487E1DF05447B0B81AB31B76BA F6067546554BAD268496252585FAACDCAEB4D2C56628F14056E88DF12584627B5896B695ECF0 AB1F2B2C47360B758B4BB765195369BF7603166A2C4F0811F693FAD575BA2DA2E666D4EC8A99 2197DCC4D4727C296E8F58E0D778EFF394B96EBCCE6F997369590FDF34547C52EC2049FA6781 29108BA1369CD93133DC5ABC3CB5B600A8306283DC2D3562F6C45A5E7EB6F8E4A4B10B090322 700653594B3AA15E50CA22A3F35319E18F25EBCB293197098C32F09F83077CC062C9D4313E1C 551D25BEAC502C9B0CF31FAB4FB7F2B24B9C3F21018DD790AD0EF161EA9856CD0286CFB8542D 12BE19704F424C0169FCE16501FB11241708E5E6BEDB8FB99134D2DA80BC08344F978739CF44 1996A23CE6F26E7DA1C171D5D1CD866858324791108717B8FA2FBA1BCF02167B2EFD8C1C7EB3 EE591550590A740ADEFFDB42424E5D945F852B356A2B03AFFB91FEC5B3809C4C12A3750F6BE5 99E0E87C2168EACF28796C6B5FA4C9F5DAE8238C518BAFAFA41AD1674B787118F7FA245A8EA6 3783F04F5377260B164D8FD9ACFE219AF8C6555939BC81B37DE0D6E8C2F34942FC608594888C 3C555C04515762E2B46AA284D0F016A7338F386D3E7A3769A6B8792D3301D46C7D95950BFCCA C2F89B8E97ECD518445510ABFF088ACA91A42C77FC17F07E1FD29A5390E1DB91A5A18990CAD9 D7B60E449B168B117C2409BD4344EC84AC4C2E0E9F5BE0F3A065B762987C4FBA75D3BA32033E 75D5D9EF2D2994C075639082FF92B9F13BA951B811896986961BA607A228427A4DBBC471B2C9 6CEFBC7AB0DF918698CB8B8220CA3A361ECCC83151E510B844318F3A80E19E8DB31DB029D232 E54EB5F6AF14A1F4C96CA565438127A7F7408C541147763AC01BD25232D5428987A996EB4BD8 3DD25A2D94A77D258E12720F566D778297AAE5B3A2BF84434CAAC48DD4BCA5C23BA925AC17BB C7D895FE5566590651C16CF1B7DFB661C40E5901E9A499E1E6115C50A54781038F4EE6712787 3E572D639F8F0FE940C3CDFE4E278726AD0A351C74ECDEDD4E881E519CCB9F914F9B7BCFEBE3 CA774E289F0B5458473F6299B295B184F412413A6F92ADC218DC39BB10C180EC7C87FFF7CE34 0F20D31E8BDC158850A84FE07966676408B9BBCB608C36F4770BA91DC4FF282F36DD280415E5 DFEBEB49A8B9A3E66DBB5121C041D348E26D7D5A451BA7DDC7939F027B1F23188AF16FD592A7 85F14D5AA453345471C150D8C8D5762061AAA58C1581AE4BB20D950270EEDF7E5FB5A1CA98F0 95102E65B059194730A0C7D857D455100DA7C5BCCD099485C7AFA4C26C192A5DC4B4913B045F DCFEEB3D4B2F5BA9E6EFCA196F84329BAE07EDDEF71B43C19E88B579E1645B5D78CA75F6ECF8 19BDD0ECB870736E41CB0851916CCEA25B96CA534CBBF90AD2731CA1F0DF467FC6F79C01A20E 978C0BA87E2E8AB62DB77E1DC771CC46B59FC384E65433F95A6BFA2E68BCECD8D05D55B2578D C48386DABC11CF6BC9D0F745B6715754AF5B0A1E27B5DDC81339F7492944F1EFB27044AABBDA DAA8F398FB93BF497178D827955849BFFC25B51E2D79C0B06C58C316DA6A161C48271A367992 4012D2F654A24C4EE9C85C4EFC7F8CEA0B634C1BC4006EA846788223FB4520871400B115C941 40F0C025E60DE4A6341BDDA6F2EDAD1AB9B708D7107A6072B9071CD407A2E9CC322C673E2F54 89C93CA7F1A8C3971304860173167F57909035CA0BBD66746DC06821D14D6288F65E26A9B3EC 38F01D834E05DB50DBF1E3F495123CF41528BE7889A591C473F64A38410E64AC935FECFA03EF A70895EBAD7A8FE077B78E4D5BDAFECC4B947E9B8673E4E421C4810ADD96EC9F234A87CF2CD4 11FD3F5544C96F22FCA6E8BD13F504DA7B5233CB0C91CF01DEF415D05C5851D5F68A1D6533F9 1651E236DA5FFAFB471BF904D32FCC15AB2CE83AAD14492B78DA24A8B5C7681837268FA3F568 FD9D51F9481598D750D55B34042698D798190106E717C760FD2F01CEE2E18D7571D3444CE4AD 1AE6517CDC98B5F1E57BBAE31DC064E1D5AC5F7B4759B8D9F85501278A52FF39720E2F617731 0B345F209D3CF1BDE450075AC8C83BB9466C2E86E5A109684BBD076030869C98885EC4B52100 A32AF6BC9CCFE8489C804F1B27F99292897213DB6B544BC74CE47812790D2A1DE19791DD75E7 49E1347B8327DF9811ACEE41A88C2F55C205C5E027A77C409E8953F25D5AD0BBA91F3623943C 8C8D3E154266CA313B86D1A0D7DF58292627DDC133F1CCAA287F06874B3DA26A5CF48FAFA205 39804EFB410B639E50FA1FE22D76A78EE2B66A00DDBD1C5F58F98D9FA31A88FE37F4532AA007 9D2D2D15A88D1AA43D95A11579D643C153B7AE0FCD7E36D3B48E2094DD252E331DB5F807DEFB 5CA4A2C11479FC64ED666C8F263225B56975B6975F97F3AB3BAF1A25383FFF31DC70D4A5C44B FD4E04CF463DB1945429971E77D04404B68B371AED13920E4BB261002F6BD5425F96B382E2B6 E7743F7989F5CC4DE43694A1CD0DE5E7FD32E3DC9F705594DD7FD7AEACC24E7555DFCA7FAFD1 69EBA46FFB66DA068992EE32BBABFAA426AD3BFCA46A9336CF5C34FF58DBD2E483DF67224D6E E510BD157617B2CEC6FD525584006C1C43A8AD7E3109DEFF944BE9B63E85C39BABB6D0A2DE79 5BD98817C8708D801884D1151CEAF460A68AFFF88D2337F3DCCE339F9EE039B229EDE0FDC588 E8347FC529176E97B767F7E32DDBB4BF5936C7B4010116B7BC254431EB65002CFBA9CA5F24ED 5E5CF504DD9F3855E0CCCD9E6E782F02AB663ABD3660D65F0BB8D8E5730C2223F896BECE22CB 9F12A93BF643EB1512280BDC2835C2F33C758E37D71BD43694A88F7484BE9EF538E2E22243A8 C76CD2D8CAC7C20501BA3B3727A756E7A638F60B68081DD742E847ECF3FE02FAE9CDA962BC6C F9A9FB5F48BF580513FA9C31B7CB6CFA0040EF6D37F7273BC120919B64CA8ED1B5C850544C46 B633C735FCC32A777531D014D3E01893B8FBB03962D3628157E777F802D98080F97730597C0B E2D576F1997F26EA4DB1462263429C633AEEE66579D00347DAE5DD57D2FF1AF1785271DDD2E1 C32608F129DFAB84277C68FE2935120940252E877C1D74734C24366C136C555B8EE218F31D96 CA92920E9C26EDEF3A2948F57973ADF8E3176A48AA4AB8DB74DD8FA7E0399FE0C1ED0E758B4C 463EF4A93F309DE86A37DB4A9B24DE503E9AA4E97615D805E62E7BCCF9DC6ED8BFE33FCF2188 D35630EDAE6C86C4A52B41B9878A77FA17C5A0E2E096FB2EEDC4E57DD3CC868E169ADCEA2ABC 540DAD20868C386AD4F86F144D5C569830B539815A4FD5F0B429C8C0134565E5493C1E6C53FF E60EA9DBCE84ABDB580A063B74C8E7D57C50D5CE7810362BFBC0F779762BEA1540EBC452FDE4 9A3AFFF755AD6FB3F0598DEC964CB45D6FFF3D6C503A9EA0E36BDF33319D99D0B9D998CF023F 1FEC5FF0BF73700BE310634A48D6561C03B7727E2CCCB825205AFF0893ADFBB914E95A804ED8 D29F8F6B32ECC2B7C2582294B39EBB9709AAA945F2AEE828825A7C8720BA676D6C91D451C0F6 EEC82052D72855365538A8F41C01DB81AD1F5245C48DE460546322D3D63BDEEDD85F0A177193 B8D32E6B4E92326AFB32BCCCE0F8ADE174BCE5ED5DD2E6EBF1B878EFEF452BA4C2CBDFB50F5F 3E269B0FE8C57ADD23C74A44C0479E570C5826F0EA15611D1498FCD7F24664092786A7B15F7B 3EC0AC2188F0C1A8D6F4A1B96C73D2B1B0C62E679F55712AEB7DD13265A54B8413AD426157C4 F032334C69AB7099F50FFE35A1C8128BA054B5B87F52A21A4AA78AAAB56FCDFAE341CD1E5129 0887F4BA8BE3E99A2E8A2C17CDB412935A77356C25C4E23758E0527E130AD3B91A2DDBCBF44C BCDEBC69967D7BA2A1A4B24CA5EBC0E58D0D2869D1F5002CAA9F92B77CB88C8C8EC5C65E7792 58D1C234305BD8288DD19D97011BA641333D65D6DA23BD23B932A5B449B33918CC32BE8A2C77 043C99B20FF158BF4F62B0BD6F6E00095C54F4A69C408C3C484499870381D4731883F3477596 A8678E6DDD8E92E0244DEF2A0529FE21D0CB1000F3E8587283D229EE7DA055A8BB235DA0248C 3949B17353FCCF81881B392A6A1FB089558A2F2CBC7EBFB334200EA31590B3E556EEBE1F9F5D DFD668559B8AA36CE74BA5003418EF25791D89DEA9FD53DFA38955FBC6EC0DC6B201D6B39FBB 34157C9A46D6C8AE42295DC8FE150A13C63E5710612952AC0504FB52F0B6CE5BB5762E7803FA 3B5A0CD0AFB951CB9D682271783B3AC4B62B2A89E50970A5A74359F3996D6E5B835005302A6E 736716023D5FCBA51E7BE70F98AB9FE5C0234B5208B6F79B463D4FBD73CA41C69296B7F845ED 85A962783BF8FC84867404002FD380257B5D86BAD10F5A5D20718B88AE6B0E686AC47575F585 8FB3A57FE6C65E7B7C6FE7A92CB6A00CD0056AD3BDF4AD9A05E94E875714CE8574F8C9295D3B 0C70535911368E24A0017A5B9DCC0F96132ED3939D7FE40A14BA042FDC46E9B00BE39C1BBDBF A6CA94BCAF4B19ADD148B1ABE84DB726647C7B5EF5AA5B61A57165EF07F2A75AF1F8CB7F575A E9586A9992DBD311C099F7B03C04625917B1F0A106124A5D31D571A1AFF6432F0CF6B2506030 6D6628412543083BED6D43E871DFFAAE6C286581AE9EEFA415DF0F6292C92A9C93ADEB1C9428 3288A2CCED9D52E7B2E414BBDD9C79F4C5EDD30C3617F074F5C99B93641A014ADF5D760F6930 9674194DE107CCC21736A112E5E8AA039C5683A26DB8080B9AAE9320FF235A80FF8C1417E819 8CFA337B543BB29B5AC738F81EF9725CFD81209C18B35E2013E5259D9E747AD2E3397137F799 17DC36ED1238B1315021BF7365263CC8570BA647894D0816FADE8A49F953822210F74E051A41 07F4549D8626DD1E7E752EE1C2E64D8E587BB54473A499CFDE3443575CAD85FEFF04629D8262 1FA99C5A86F68CB526FB5F70AC5E2D46C8D2039F4CCA16CDE3ABEE0BBF251631C65858B1D4AB AAF391296A1BBCA4D893F50ABA31C70B3D93C7CC5E5892CBD3E6B08EE368A4F800436674647E F336279581E99D6132FE670EA6020FFAC584DAD29177105F2F27050DF6A5766916307BEDA561 44385BA2676C990BC5C84B3BD1CB6D72C7FC78921D404EFBE0B18F79BCF997A869C6714AE509 5B563D99FA2EBEAD37943E60DE71279F5736A3123A42608A71B417B45E0AF2439C7530E8B375 2C9992E5B86719ABFC508A8C340ADA6616B76506FCF186B608BEA756D9302DB8B317AB46FEE0 F1C81BFF62E0E79C35A2FC542FDA21E017EBDF74EC7983D267C4CC9CECC0C6AF8499D5ABD25E 34559C6CAA96FFA6BE9C157ABD47B08F7E9527C52A8D52379DE137891D3A9F16C157099B46A9 595E517344B0F175B810948AC9A19E5984B0A75928417AFC6C1821116DFB702EFD72B8604A2A 618545BD8F9A8033F2C2674AE1E160C4C5966D94E99AB8DA360C6B2396238534283B0751BBB2 1C7A33E9C988C7E686B6AF18050531FDFDF7C07FE7B2AE9F7F8B76E6314052EF15E109A98D5B A6109CE8CE1476EED0189535B4830C30D98F4AA3A0431EFED99830A44976EF9C9D4E6D3006DB DEECE847774EFFA556CD66269064F999C1C3FD4D04B0225B5BA9A19B6F08EFD1B897097D6B50 3EF688C19AB39E73B73560DAE3A5665CD7C44A74E66A77207D3C628CF64688261115BA4C8ED7 870D40C98AFE7C39985053010F7DB7548E607D4DEC5647CFB4008DAFF783844105AAF6735EE7 302D82CB1B612DF8CC7D5E3530C2357F29E3A93C995984C2BC76E9D5A0B36D40BF0B57236C76 826208FADBB6504492B0BC3CCA7F63736CAF950F51426D48ACBF5270C2EB11D4F0B2E827CF96 9C76C470462AF179AD4F0B104912F668E9F013F17001BB15D81C157FFCAC211DAF3BCF800394 0D2EBA3A5DD6F0EC53121D4F06857F612B1B163837FA52D4E066D395CB5C8D7AE2C0828765D5 781CEE9063FF2CB77F78638C37403CD5935BB21555670A4757FB84D5E3AA14E4B9FE5AD786F2 349E667415869AB542D3D60D69F3D9D10940AA7572CB92F7F180882CD731793955AA135BACD8 60F03671292DDDDCC7F3178900EDED9F048EC8991C61791A7370788A18FFB35633784D40FE07 86523EC15014AD165081AF052D7D1B8CD6876B7AC3689499D3C51EBF0CCA34AEE9E9709723A6 D2CCFAD099A5B64E799C7CE9859BAA596B3F184B8D65DA85A2255E73CD46782D03FA37A90280 023F4452948195EDBBE46A26412FE743505DACDC4CDEDB389441664E16A5235E48E5AD6383DD E23E70FA58ADF16B95EAF4E753A77CCECAA67DCDF0C976187195E7BE0F12129FA9EFF7F4674A 55D18C9FD9254CCF9C49698ADE847200763206EF9189022292174137AD87BB36B9C4CC3A6FFE 57AF44ACF5C571E24F1F069C668D24DBAF04398A99E840289C183D9A7DD08BA8533D96165AA5 69FB085C8DB0CBB4711828081EEB8C0D72982BD87BBDAD292E66C859BED989DAA18689BA75BF 1F60FADB48D5810EC175CFBD58DD3D90FD9125FF38C7EFF3F4AE259686034D835A4F346A6AB9 AC3308E175D391E0BF085280F9F09B141D15E8B7011B4232681ACB895471AAEF96D2AD3874F4 88860E55BE833C117A3DC75AB6C200FB4F0FE69B590268002C3ABFB161A8DC3E31546C47E2BC 5E76B11EB3DE74719A209D9BD29C21055281C72014A0345B3751A648A000C00D5EC26941233F 4AA777CBB50B32FD943CEEF3DF54B848B8A867E269C718FA9AA7953505FA23EC36FAB543EC73 F461D0E3348F8C7428541BD5F0A783A53BF6243EF8EF9FE97265E297A4CA9C1D41A3BDBA5D11 D90FDA33102AD81545583A56810DE6DAB59D3615700B2D61E20D54EAB41FE56E8333D5C1CE87 8F94AC2A91A90335246A93B22F6645BB9CAAEEE67CCE6D188ECA9F006395316FE7CBBFF4A1F9 B8587327A06A06D6AF07CD358AD81638CF842A5CDBF234E0B4AB6F91411ADC5FEC43C434CD25 98DE0446981F0411215734ACCED6F9BFB10147921E4B1169CA68D43114E30FFC5F4F80CE4819 45A9B7D3B7AA30357964F4468A4E330BF710B6117122D954B62B3A7F8569B04306C8427E557B 5CAB8610488EFCB37C1C9CE9D78A8BAE7B07A845D273BF728F1E8E8D14B945B66D7ACE6B5FB9 C24470DA154183B4270D2D26C34BB4FE1F0DF5D89E7CCEEB1872B70E5F9165250B5ABF91FCF3 DD0163D4977B5D6760A78E02D72CDE1361967A139E77171BAF154E5FB7B0A08D7C0CD1FB488F 86FD03A95E0FA713FC32D0F32EF64944E997D994F05C39A7203DC192698B9AE8853BC335FD0A 4DFDA69BD76FC3BA41A7BE7849DDD8AA2E36D50CFC3F546000546E9640E97D44350B8141DFE5 07407BD20301B17CAD9DEB3DA9142F1D56C9D3D692A04E1B193666D134D94DD83085C58A775E DC226D7AD940638BB1DC9242EB076369E255890EADE45DD6F8062FF43DF8484823694229B0F4 A70F7E425EAC964B4E273E0091295067E33B84481C4127465C94E0F26CDD2E614186F2D0E327 ACA479C3DB100439C88BC2E1CE46310EE078475CE9302ACC45A3E323147E564DFA490AC918BD EDF874CDDD887ECD24236CF24788B267C9B52E64C39DBDB2817C92EE2E3A72706A40F0D8F9C5 DA4B7E16963A69340E408BF251FA0C7B11ABDADB8518284420C8674ABC70123F19DF8A0D28A5 AE3D5F4D8C2DE9161AC00EFAF1E66C2A4D2EA1A2FFB54A40F5380804E5E34BB361622E84174F A7471F76C7330415B8574173CA3887514023D407DC43EE656C8B48093CCEBBA03747E6186681 387A168AA48B64EB48FB2EEDF9EE0F8C95B4EE935D0E66A23E84297E7C6249E50206C3C64FDB 8E2F036DE02379B8B801F30FE90E78E36BCC805719153DB07CD4719F4EEB97D9B40004415CDB 1318194FEF144EB72B268F8CC8764BB63E7916E8DA3B9F970A71505AFB2FEEE7F286007AEA30 AF43270BC94FD8796C2710C228589D68AB8E851D286E5B99A71A957DE219B8AA930BA8C65E97 E0E2426B6EE723836DA8BB560CEE060E957ECEC44634C1A7F7E989D82C80D824D7FC296A9570 0273789678DE2BA11629BA605D2A7E10C6BDC6D5A4176FD501A8E31291FE3E0A0F8B0CC0B325 BCB55CF5A11B44E083798829E7CD392B1D256147615096B4F0B3B0C7A1EB610C4FD055E13C9E B356985B3494695DB11EE90EB581131B5F62338D01616B61FCB2C7E457A6CCA2289912548ADB 6922BD50C5DF753B6C1CB7EEB3338B790626AD94C09CDCA2FF6D7047F6FB57E0E3BC52D06348 E0A57A0B2B7BB6EDD2108E2A7BFFCACB01BA05C759CF36CD3D2C373CDF0EFCA0D74D6AF1422E 0D921AD574DB41DBABCDDBA2C7A8F89D4815730140FCE853D031744BFA8FDFE820858EB7DEF2 AE75D1895FEC5B2ADA98EF794B318F03E679FA8D65F4E6587D450DA3514435620FA67392FBAC 160B8E442497294C5FF530000882890D72C614D7D0B4CE5DC1C6BD52E3CB08437EAE8D1351CF C13021365C54E6A8B3EED4F8119FB8798D42620EC21EE29CD8FD32F8CA789EBB13189BD35EA5 EC489A7D7B06502CEDF7C8CA52BE6CC6F56F797FC5ADAE8DC28652A02C10DEA7BC697434688C 1537A5AE5FB586403075FFA5CB19722109E26116AF7DDD935A4D7E22C1BF62F8B2456698CBBD D8E1C2967D10FE84E07D08CAFE785C54FD380EB0AA8258369C72FD6A725A702E3DA0DB170E10 83802C1BD4783EEB55BEDBA33078C9EBA22F445063D5E035E04040E6E7937A3C6382B107222F 7DF04035E1E212CC2308BD871E4CE3CCDCE5C9EA2A09676544D3744E2AC4F657AC0D2C178E29 45A289A352156360A49AD007E4E0407A42F9648D8C402CAA1922D437D6B1B5D1562DEE4DE0A6 F272D802285B2F8F525EDC420C57CFF52B3BDA863DD6E1236A0AEE3819F3AB71F30AACD9C566 DE8BE9880A6FB83BCF75CB536D64938D5CFAD3FEC81543A5E022A4A68406566C1778D624667B E63A7EE6940F2007B8025DCDCC4541FB1169164EFC1D57FBB5C62AC2586B575F54715AF66C00 75B349EAAD2E9DC759A3EFC633E25704C81508F28C46D3E5A3061D23D47736455A8C881AD2FB FEBEFCF8A943CF30548B3F33B7AE45090FA0970878459E88A029F2FFD8FDD035098D60858F9D C8EB23F7C70A5AA9D781869FF8516F0A5D88B528F803D27D07EFBE58E9BB6639518A9B095EA5 B41ACB21B0C9ABB17F0E4010626BDB07BA23945B60BE41967BB9DE12EB643A1B837E0C3B7CBF 93752E25E7C7ED2A2A22ADBF32F27CB7697DF3025A55334B5B5F0CD0FA786C574CF6096627ED D630F20C107D2BDA0BC4B751C1121F2B8CC281264FA63F6503EE9EAE66C1D680DEB76A5A312A 21E84C6D40AF5ED739BAA3CB9963103BFC326CC43B5CEEFE36529597760643305F306A9C057F 477EBE0702F3C5572CFD96CCBC76210B043A4EDB6D612CD7E86315E21EC2A79C7881740C07B0 F8B3B2ED860DEBA53BB68E4160FBB41EA13B2A013DCE531E6D824F72B7595380F025335ECA5B EC0AABB3F3A6A40A90FDA324C844BF1DF7546A6A0E0FBD64B32BE7985E5F75922D306577A32F 6D3887EF119391DCA7F923DFDE861D637F17598CA17B80C61F44BA1FBAEA71136E0FF482814F E30CF6AF086D087B5AACFBF7E87B3C92B6760CD836DAC9C61BBD0E9ED174D79F14BBF0611FDE 6BCF3D78B7270BD867F1E63BC8DBF31534B62F80E81471C4063F144C89A5C30964B4862289C6 463633632C25134F82B7CB6B0C4CBA290A2B9FF27C7329ABD9C766CFCC1DC1A249272441604D FC41515DC472C5944A7D574CD580A174FDEFCC0814E87BBD8DA55EC796510807EF8C6EF1E512 FCC978A8A0608EECC26C89C090B2FFFAF4B6865FF253EDC5DE07F329987FC121372B0417B124 6776D18855EC98C4E36A1A56C5F0C76B74D6C100216F52D97F17F02E32F10EC2D20FCC5BA70A 9976431CB4BDDC31D264A65E76D19DC76A837EA5B63B1B79F2855E2DF1B53037FBB31F3CC08D 26C923F1E9AE67AF79F3BA42BF854DE1B051B27F960825E1CA37EEF05C4C367A370DFA9003D7 9556040345A7714FCFD13CFE692962510A7A695330EEB2D54D915D15863CD2DB1FFCF124722A 561B73DB6ED6317A43EC47FE0488E350CCDF7CB6BCDAA9CCCBE668F022E46F29C2BA216ED09A 0926A35CC5428F1922B8C50714776C11032FE4BB39C2BC87EBECC94BB92F6301A43A9B69C71C E01D9FDD2154753BDD928BE4F9BE517A047882C4E5E9338B34C47D0FC97354634A5D6AFB1D15 CD368B3AD7BCBDA8879977BE8ABD3AF0AF29A6D8CBB26E3D25FDBFCB8E4E92B6CC55838A3BDA 638FC21F10E535CF5A8688FC1CB45821AE4CE3DA53846B320E3705AE5E269D67C81E88E81633 FD7CC9B98BA631B723568FC204B6F119A82C06825694D307912D72FDDC346396A800E9453C9C 8200CE35A34C188E484D9ED8D69F4BA2CD07C3AD340BFA518C4C9EC80652A2314766F86FD820 33F77BCAA573E29B0BE6434DE1CA29E11629EEA6E35EAC754BAE39C4856AFB3D062947303FE4 57D28AA34F0A562C93E5C51C6C09E07979BBA00D495C40E5BA2126091EC3B6C3551DA750CF12 5F3B889A11E515863C90DE955617B4BEA129535E678231311D8A46DE332E674FDB9D459AFAF8 D3267CDFC8CAF0C4A0A1ABCF87AECE388EB3625F5E36484B3B648344CCE1EB5FACC781C7DBC0 D29AD03E7A9F6C9054055F95CAD9999BA1E256D00D32F9E3537B0DF314F873ACA8492F273732 192F335D073B8A3EEB6656F88A8C56BCBD37ECC7F459977044C04F9FF7132B37BDC7365285A2 D09ACA1242112DE8480D054F7F55E66F9F8454A074BE85D190058D874B10824A8ECDC4B36782 0D43EEA8CCA3296FB5D3B507D51B05F7D40ED134F9EA7DE8160DB1759595C645114C24A4C428 5DE1696EBF2C57F4C7EA2E6167B32AEE422C077B49795888CBE5B093E684111FBF3777A4B32E 8160AA43911E8069136D27137AA555494B8833FCD487F0CE8DAB8CEFF0565050818BA634AAE0 7D7847DA62B1D73F33A98FFAD21CEC7FC3309BA7D048794AEEA3DFD1207E8A9F1A5F8D94E493 DD1CD58683FCEE8EDC8B9F14B02CF1D3760601F5C04D2CBAB09A4A99572B98F0B935E925AEDF E46B01D7BD8CFEF25820705A9550EC734C42E235887090746B74EFDC6910C2BF0B2793C7C965 5D09BE751BB1BC35CDA8A473151A996B513D42CB889BFE8DAABE0560B4D36412064D54168066 60CCF64F51F0C49D9134E9C9CBAF5EC6BC6CF8BF6F86D9E653CAE648EFCC920F8F69185902A3 2D4D2EFB809888DB21F414E31DD84FF445C7BCC62B5797BC7775B3E01E90AC60AA99096A26C3 3214C790DCE924A9912E5EB02A60AE9108540F8B6F51F360CB2891FD49BA945B3468223CAC30 8A531F0F43892BDE186AA3C88F987C82BDC98B243150050E3A51AD335E2F3319323BD790E2D3 28D8C5B56222B68695B2477E7B366C90394DDD9D5CB5339714F9D1FD38421272442A45FE0FB2 017D8C79E681C19FC5274E489D2AE3C7749053DF29EC12256E42FB322C2D9BB5A3935B167D5C B963A0252792F800C705A19DF6BB7CEFD8DF4C36C26AC08DA3DA7AAC12638A1A6E4BE489B477 0D106A701EDBAC5B2966CC49E4676827A7E45431A76664BFF1E1F729AE3CD94BEABA0D14DD6D 70C0AA3FE63E9D3B70974E4F50A74D8F077FEF888C51E0108C25A68AEDD848356EE35362D594 38BADCD849C84D77443D0A731B6B234D9F390658A71EB844CAEF90D668DF751FD82259879A21 C0A88FDF718E9F45882C9EDD4E475298C9090C45DAD25385D4F5271043F6E736DF4EB0E9F30C DF0A8D043AAF0914E1DDCACFDEA4429FB397BAE765F4E01D73133E3D263C2D1FD33DCC1FDE28 94FE7C1C0CAA25462C6D013FA89C16163F05D137DC53B85911A4F107931C172AEE16314046F8 22EF3B0F183658B8A5ED13F9FA9B440D19D629F50C029D4054F9C58F12B58B551174C89A69B6 3050E4B6E6EDA5983BBA2ADDC8F80A2376640A1104BAF8C52AD460546481DE6648968A3E3F42 6284DF5E3076DC18173B4A870FACA3D6DB770776B4972A2E32B251C4AEB1AAEF13B15E3D9E1D 63853AF48D2113422778751790983BEB11C743ED0C6EB3A7D77D2BABF651440A27F91E891124 CF15284A64A876E3C16070D06451AF8C18553FD09A58378C05F6DED30A4048EFE67A85B50A03 48E862B93C289A4B0E087A592EA18907118AC2617C014959C8A36E492780114F893306F715C4 2886D33C9AE2B799B0EBA8D79D291C39CEF2E6AD5D911986D9E09CA2BC78BE64806CE49522B4 42A201EB57652DCA969219FC92A41EBBCBB0055AB8D1A911A74DA5DE63971B44EA61CBBA0CC9 D2135791819FB3D53E422EE1881549789A00C7F146AA676CB9A318F154837F005B18E4AAF199 F2BA5EB992C79B6A19D065A71C28CE7372A0F35517830F9CE98A743C49D7B03B1F3723B78B09 B6A9049FB83A2FCCEF599FBB6A0648E5C7B430B5B1B6337ABBF8584CB8BBBDC0D3D41EBC8E3B 9D5D3E3244B3CCC55B81B8895A97535DD5EE01C54748E6AA0ACF73D7E1CFD6DA3A957D68C701 E21BED2A7CC158541033557BC8200D6E013E6F00FB892D4F02956B2A8B7711C02BF425B82507 136AFA64715CB899A47BCBBA0023F8017EE019980F179551A854F71A7650B94FF77EF546EE55 1EBEF478216B9555053EF8139893CB28E8AE33D4EAE9DFE01B8105DBB9179ABC0FD28A3C365E 3C24A3A78C2CACBC1211E34BE6E8C6E9719051F76733C810A5F5E81D9E536D81EB3E33221123 EEBDFF127EEE2B66B9A3F704F5C063EE0DB831E41E663EB82FF6C59D17F64FD618C939C24D95 8EEE16FACF394A1F9FE4E869676A9D83FE632A9E68705CAF87A93E80E3A8434321B5E37D01AA E483A53537DC6A0D244B1BB9FA06A9B2D351AF8D4F1FB2DB78BD90DBB0744C20BB261E5E3580 B45BD723DC96D23CD22855F7284C4B3B0FC44EDC2301ACA114D2623ED39E8B28A77C0E847B8A D4BDE12670D4B70B7A5E058C8FAD82A5E6586F4C7EE28029DD41338C1BA13100644919F25ACD C4982AA4B1F1ED1BE6AA731210B2A124D103CD10CC58B306C10E3BF462FA279BC89861FDBE49 7643967800FB3FEFE0729A2C45F737F4744A7B72866D211661A189AEECF45CDF903BED916371 E1FBD6FA0BB7B3291183ECE4795776A77D00B3F6E506836D590E5506F5DA290F58DA3AD79A94 00013035C955019F33177A9C4DF53DA7A73E6382A34127C406456477EE517400BFD6F0EE81A4 DC1D4F6B153ECAD3AD0977633D5F899969D3083B893562CABEA9C661217D73439F9E01A1CA3B 10A4C0ACE022AD216641169F79093F785BE5A0F3BF91FD9D83DB8775ACBDCDFE88B4DE606F78 DDF007BD6D5AEBF3322EC3390B0582AA13F0AF2CF702AB56180B3CE019A9E0F65B710338A1F9 2CD87FFFB0499342853F9461C98C511E9CFDB4305D86F719A124CD13445FB8AEDB9C994261F5 3EE35076DF2DFA1A1C654F4F51FBD5CDF7864AD45A69DF8F40AA59F571B320C63BDDBBF05FCB 9490ED00D673E93703B80BDFD08F871A537979A9D4CB548E1A63887A92F63E47072693E76BE8 BB104126C38111E542338FBD2A0AEAE441A9CBFF971E2EC82D17AC3BB65C71FAB4ED5AA611AC 6A2DFF199D29748983D46C122E3BA0341D417D0CEEFDB49452A58BD4C57E54FC84145A497246 6861E96804CC2A792F13AE60176859887B61729EEF07A3974BB002E37713DD9E82B111F7423A F9F4B32AAC55C39BD88FEBD23499116E6BCC300027FBDE7131F4A6955042CDCE5601ECEC093E BE98DD6A6009CBC661CC5EA17791EE064DB5A00D307FC876527C28AC03E6922EF361726AC2AE F9BDC6067C2601A7E4C64DCFFEB7DC6368CE4CE59413A8C41263EE47D081602074BABBEACD2E 2DACFBA4E0EB822692F74140BC3459D6F772D3FDC2DEC09579E45353E4D6687FF81CFC85DF6C F5C1D43F8B7635A2AF85A6E853533643DA76CB9D9B8D06B14B9435A1D165E6ED695751C84F24 B72E857C6F67A6F7FE322C473A1CC6A789A2CD7D76B116FFAE837FC7522D0824756A3403AC80 CC1561729CDC3B74F36720BF292C53DA41F55D3D86A3187B597036025701826A02929D1D0827 F3799DEFBA6A0331D2BE5E2C1E529FA8278A6A46DCC9551DC74582C5468CCCD9E1219BFF5AE7 FB4D5B434C9310FB18A081CFE4DA6420A109856D37B404FCB373FE72636A8E07E5EE73A3E776 7E71A0551DE8875D8A1DC87602F5B24EA06689D3CBC3C6528953F6608B391E04FE7AF62D39A2 3F20003365E804089BC952E1A87F44A458E3C54228D10077B021D7E3F9D92CB235FC6CB114AB F793950D2E33F29199F1FC39E7E9AFE0DD1629B0588F67A68FBDBFB32BB9D0D73B75D565CF1F 4EA45F275C7DA0E5A637C6E9EB93E805BFED0236913BB1FF75B2F690BD0900EDE2EF180FA760 F43586397ED8567F35BEB11D12598FACD994EFF881F4D348FCE3AD5450C51EF9AFED4121188E 128C3DADEFEF49760E2CDAA224128CC289AA150EFB6C0F61476D2E05B1C12431867E53CE1D9A 0EC6A0E2AC5EAFF80D76BED553F71E7AD5612BF9A8988FC5662DB82B0CE0F46509527901F4DB 8ABCDCEE984035A5EC76EBD552C6F81B863368EA4095ECAC9C8E8F90184EA23096C0E5ADCFEC 2F80C9DFFB10BD5DC0B51E029AE718522957D4C85008E7BEB876511F2A7CC2FE47340678D050 C725188A9E9E24B89CF7D0772E9DD309F9B944BCA68DE36FAFDB5114AAF7EB75B0504D6BD953 458E3C9FFDA391FDF519F5A7A0D8E6661659663012E1656CE9D153628C7FD262C0D7A6E78560 56D44A67B7DAF19FBD15668576E6330E4CE8A48BD6DEE0741E5DC2ADD67D67E8BCFA69A94978 2E57BE3C1BFB75CC5A8E09672978AA5BE0F1CDD03319899D610E6B9668091F3BAD94725703BA E6B08AE39BAB413FF3E08A3582ABDE26CE29E0908E877981BAF319830ED3E22F3D7E77E7D8B3 08C145067B1DCEBFFB700AC401CDA58962E4D93BCE6BA28344D54E39BFEBF0C5BB4EDDBA930C A1A1515B2CC34AC00DEF0E935F259F40B4FDBB15C48B07FF22CC9594CBA7AF7E564D64E773A5 808BAA33050A95C6CFC1B14ACBE2FF58E2499DB21E785C5724B49CD825B901D0D2E1EC9D8BFE 5CB6E0A12E66FD0F887BF25B725C902FB37CA8DFAD8CE76AD0CF2A95496DF39E7E2ECF228611 68C47540EED09B9653B84FA84B3363D4883FAE2478567F026976EC7C6C19756CA62D83CEF310 130B6F230803A1052E1C59A3938D9DE010C20D578EB38F4CE3F45E37389C4989896E96EAFDDC 81D52102B05F06582C7F82964F342DA0247E9E2D20028765679B269C19E6F54B20B2B480F5ED 36C240D8755455875C6029CD7EEB170CF11125BAB8E788CA4FC21D6703DB98C91DF9F01C1296 7F2058018E2EE87D969AEF73256185DFF11BA33864374CDEEBBD25B6845679EF849F129A1041 FAE3E7690BF5EC50F0E39ECA3387B596CAD088A11DED7B1603A7BAC812A8EA932E774B6D4B71 FDEBFB4331F39DBB4D612589C45804FF2149B8BD95DC818379AC0923AE6893585A026EF40E00 2A81D4ECDCF1443D80CC34D2B18840B01271FF2C0EFB19471B875557B608451133702A9368B9 D6526C6CD65FE6DAC861BA625D30ACCEB59BC4857968BBE7D16B59A919C27E3E6FB60DFF5609 172B80EF520F027AD1F3977CB727F89883DF5FA39A0243CBD598C759B44D58F3A33B5DCF00F0 A0B759C0D452F04DD62575689ABEA0ADA1E2E3DD7208708A1119CC1533748E2D704F4E552B37 243AE84D2B8E9E42B19A7B8284FC0C58437198DA2145BA405E81A2CAC2C78A957F173A6D490B 9FB3A96F24913F25C757EA9E3C67C893D916FA4EC2C2B400FDFEEB5BDF219FDEC7787CA873FE C1441AD6B064951836CCBB22A23B4EA90BEF32009A4D0B6B5B7CA45A9865DE0FA04985E2790A 624A35098FC987C5DF6130134E1051A71F1BF31E75A9DD48A04F807858D19C114BCF9CB9FD53 42CA21DFA3857B3A4E8FB94392F5C73E03A6439B1BD7B413847306797F56A71192D2EB9D8FF8 91570B816E7CFF7FC612ABA9C9BB8F6B4217F8434078B0CB6BD4CDEE9FD78472FB11D5D7A0FE 71DC21FF44FD587441E69DC98D1CF86916D6FF078EE6883F36F53892782708EC1BCA3C41D524 FDC1B7E97CBDACEEC2DEEE2A2641979B583460D19AB369B48236A8A1065FE64BAC0ED0FCC0AD 7122CB8C3331A59392100FBC0D19C235164D2685BEECEE536FABBA39B941965EFC89C3A565E1 7B9739E48A733167B4DF46A74F00617373D40CDA19F23B566A55F565286565BA74FD97D997A8 E9218CC10A5FB9B6E98B7171C14955E644097A8A8737C0DB65A00A14C5513A0095B1F6961D9D 12E5FEE1F2906098458E2D1BDF059CFF4BF0209EBB3F3550423B8F7944600D78D0C0D28E35AA C7A28020D4674A252A06AD7FB419448E96EEB3A038E6B302EAA25322B511B449FF2B310F3651 EBEE9495FD9E5E87EE75AD8CCFA458D9EE7B2838DAB856FCD22E0253F49DBE0BE67FE42C3724 112E653448EAF8AABED801841D8A18857A5AB461F6D8A68BF67AA424D8D3C7691580915CB870 BEFC3B8F7954BF80FDCFA52BF3884C8CFB2BE5AFB4A367D352572D65971663A5E0F3F792FC34 A3F489F30E463E0C777E21A333B020AE0D797097B782B7B3FB0BBA508E3C23E7283F28F752CD 207BF9F4476F525AB997505561C49F5A21DD7AC7871BBA3AFF031E7C8D5C57EB663831054345 291D64379E56D1EB22A9DFC370B155BFF179925217C8551BFE05A05CDF4796BB33C4C56CCA99 B0953A9857EDF711480D024F1B7D8C92DE8D45EC5223FC5EB8A8947FC60D697ADF9F26BD04CA 8059C8D094112EC6707D4F04E040B5DAF82722AB36DAC3E8C14B90BF60C709A95588B75621CD 41488E45224FE4B5AA790FEF59B40057E96DA269685D5B9833A3EB3644B5B55C05CB0BDC6093 390CDFB650B07D8F63D8B696FBA5A5EC8C6C6C5A491861EB9DF931A8CEB34FEE8515694BF4B1 A54D0987EC4EE3FB102269BF6F2C1B7094A28DC47B73A5BB4E9BC28AAD00BD8889FCCB0CF152 DE16C584810572034C71B03D3CB1642D427D944766E842F0829B412C0A79A193B6D448C3ED0B 3EB0859AC2D7EACD64CB8CFE254BADE0642029AFA2DDA74A95DF07727EAFD6903CAA49A2C092 2E070B88C71AB787D7635401C9ECF389FBEDB026BCE47874EED6AF233842985E05B6A4D91FF0 E7EA1A203886B25D73A9DEAA231DD549ECF2A35E99F7D31555858BC1E012F248DE711E15882A 7CB3EF37DCA57F2BEB5DF90E8FBAFD429B2CF8E4F47F9C27164698C7B6967B69D32F7EFD03B3 1D076184B8949BC34EE548C5BE0D11B4403EFED30DE46201B40473C73DBE1B651CEFDA5F79F7 9B407BADB5C233750CA14DABE25858AB4E615336E569C01E45E071FB1DBB97866A56E1547028 566A938A7A67F615DDB69977A1CC00774280AD10C1D49ED41A7F2770DC213D9A864AF2E6DEF3 20DBEB30D88CCD5CD5401FDA993175738F4CE088162C2F84A79CBA23F8FD34A0C19225269F14 03D2D0899C69625EB651B3AA2CDD2B23060FBBD616F63E3105DBADA88F185FBBFFC29D738E93 A7A1DD3D21D56B05CF92FA8AD6BB4A18777CC8318CB216E09DB238CF7257A4647FD31CFCFBE5 B129E2A1CA5CE3627FEE9067457B1C76A665F6C02F0B24D9851E6D1F7BC8AB716A15707DDE5B 1BE727BA6C76B7EEBC7247A68960E26F9E20923DDFCD970A1C5FBC7254A2598B4DBB8EFC7667 FB1D5A2729BBD8CB35C5C34DCAFDA839F6B9CA0CC9D619BB97F3266B7961AFC24D794BB9A1DA 9E8193AD202A8C2818635F7BB2F40BE6CE5F89C516EFEE7930441AD73AE5789203C5CCA91C43 6820BDCC8FD95E1368A5B2584B3FA0794B4FEEA3C6C2109AC8C49F4BADB83965720DA2A06E96 24E3EC91B54B563369B83BC032610E8683DCFCAE0F27389A68879FB6DF81A3DDF4E3F30169A1 F7E9391176AF7B1DEBB3BFC35D9FBC41A227111C746E112915BC4A2775D4878ACAD09FE95C8B 7A2577B9561C106CC64A41A5C9457C5B46BB627DF5FCDF40F4B560F6570ED1E8F3B74DCC08E3 7259646714831A2D8BECED2BEE7505AE0239B6F5A66166239FAA4742DA864DF672949E01C9C2 DB390FC6080B9C98369679FEB3CAD92794AD0F54CEF49A6C7E5CAFB8EE4979C6003EEDD89B89 C3D01044E96B995A5BFDECE27A9BF22CC5019A26339950A9513B10691785F51551C2A3BBEAC1 72B4727EF5B1BC2F9FAD735BC06B95D4B22D594BB35932EBFEF502DD05911FDB2C94F6A0EE2A 519F2BD7F80AEFA0510721F1C2C976875C44EA32D7F897C10EFA968375D45BD97FFD9D5040EC 0B4EFEB802102208F2E2E8378BE4BA6FAC41D670C2922FAB9A4E43CFAF45E48E0B275406C703 625649DCB26068414005389E6666DD3F789E42A93CF4B0B6288FC46125FA21820795C8FABA70 798BBA7F6C5CCC50F320568B81E00D980327B0DF815928BF01EC24A54ACCBED6B8249E2086E4 93702F2CBF898EE7A7B5CDAE0862DD0F9B24DAAB1EF6103DE17FA777DE555F711B125C70BD15 326142F638238131B77E996960D4D011E8292035364F012C3EE54C5B90FEF3C17DA4472C6471 7274077BB2A8309A6DAD4CA45D9547E1786AD2C1552BF483D33F7E2747CD494B06D23EEAF598 F6FCD94C50C849838006299B4E2CBE9E4FBE4537BCC78888FA324C52D231CA5D500FCB53180C 1D3E48C8D78E1C9604277E9638B79B9055A7ECB660F887907EA5DD8D06A2CBC43E1D1AFA3D56 AECA021E3BBA63C047E7570CCE232B991BB84A2F36D9B161C79EDADD1D9CAD3C27A36B018437 D22862314012E2F44E8BE6E9638DB84E5C35743EF2BD654E47FA1A8AA7150ECA9BB984E745B0 ED168806F37E28BAF72D2AB872F812202C981D2CC7497D5E75888F69486A071807B03C6442AE 07ADB38426AD611FA73784B73C940D0086C57B802233B2184FEC8AA5A1168109B47DE1577A6D 7229A51029A5F9FB4AF863D3FBED56B66A7078A5ECC2096029BE79DBB55CBB13B8117E18BD4D 2FC772BE30786D29A4E1B3B67CE1B2D6F70865AF781C0E607C7B893EC859179F70F99D14C940 A4F49A5FEBB24AA35C3DF4C5D7A4C46B7ADB4E16283C5B362E7915CE0628AEF257842EB320DE 2AA902944111ADBC1FBFE5B9C084E33FB16B72FFD3767A29B307B6048CC15AAD6573920064AE 5C4598C093AFC67002F7DE9C25D727E6EB6BDD528C95EADA166CD721EEBACC95A88EF8103F6C 096EB2078C617F7B9A26A61277DE67EA8912A2F5EE8A863E152A2EA2F8B2AA852C0A94168F70 C5FC97F531D52C0DE9588F3A5BA28B69BBBA2770C42E3387130CB46BF84FFC85264C4C408C05 DC30ACA6C4EA6E27041004B4E9DD1105ED7BA8E1BFC2BC5FCF60E158B202F47D69BA2AFC12E0 E6ABA502C9256D7DF3112A91738366577D7706FB06DEA18CB0581FBE4A010B182BEA14999006 A122AF79C8DE0A8F5AE1ADE4BAAAEB74DFF512C57487A5C55FEC2B63880E9102D2BA36A51F0B 8B7E782C01269C001A7366DDE7539DD631D158EFF62DCA40B433311A5046CAC246AA4A6E22D6 B8C59C15838A348205C39D37A35559DD6E6A165D45519723702649991A32794D53CF3435D3BF F8E0D7E1380C59DF125CA55CD1B50FBE5F7623BEB33CBFB6D8E06CB7F242AC0BD2EBA5B745B6 5D8A288CD3B527E5D8CC8218CCC085B6B90D81D398BF6AC562B705E94F56545C538A22B79B91 5CCFEB125212A7A48B509A14872FC9749906482A97586DA6376CDA4FF6B97552E2C75AE50AA7 E651DA1140DA4B574BD8EB7C7C310DABF320FDB39374193F6E8F7FA212DE7F792C77AA5B3BC5 C4BBD419685D7DACA2D58676828214B10FAAF8ACD7EA0061CC2C22BCFA02415800BE52DC9384 63FAE05D6AE424A483D4FD9CF66DC9F8625FBA92F3066CE319FB0E76830A08A075D6811BE320 F0C57D5C9656CC607E3002BC2D091282E9BEB02977B07D9AE2F05B872480C56BA9602C2A4122 9E1A4AED07063907449E4C9DCB0C02B4D185CB74E4C7D7E3990AEA195D34A13BF4D06762B029 9DA48AE8E44F04AFB36D88605807B108EEA5C30A270C9AC1AB34406D545ED4E496D2FCAE02F9 AECEAEB4DAD787E2376EA5734B86CE2CF93D6F3DEF9A631DAA489427E2A4073ADD1F923DD727 09512C911323B4BB0A946EDA609ADC6D64EC631B8416824E45C6F4D0C0BD6B542E3B05980A3F 5FB0604BCDAF3E9ABE32028A819953BBAA7EC289C1C20D52E6135EECEE37D5FAF7BD7A4FDD76 4311911BA70632AB683D6BA7DE878217EA2A4DA8B9A7795897A1200664FBF15AAEE5EA03307E 3F1A666F54E4925ABA46820A429E6AE50531FACA7DF68EFD7393845792967D3595112E49A325 94865B3C2041F873688ECA3914D5E23D9CB13990F25D16ECA6BA04B93073EC6034A7A3A53FC7 5A44216CFCE89DE11B9DCBA67D01A313555761A3D95AF9CD4D71E2A69418517465DE8FA030EA 1D66E4E070DA950842A1953E54A3C7D589E2DFA503FA4CC5BC5205A9676F581764F07B99D37C 9D9700B0C99CFEAC9BDB1488107A06AD4701F385D482562D7E7773C6913FCE15C3CC5F14E670 7520FE31833F4A80D0CFF603295B23C54E75B963F5A95F2B5FCDA65FD7230C3D57B23B81C62D 57634011CFE6DAA959941B03FF0DBA3F49149951B3863BB98185E3FDED7979E22A386289EBB0 ECC33B30C543D40D4EAC093B2226870249B3FADD8FBC4281398153F1A62EC9CDB3794793E19F 1DA5AC996D75143D931E22FE99CAB83E0D370B755F35B1B826AAC1E473B3CE00BBEE4074DE62 AE63435585B041854BFEE360221E566BE84BF7DBA46A1BFBC92ED015BCD1ADF1563E23FCA208 DA7470B836B5367B317AB7EE24B41E1FE0AFB91C9A81FA37EEA89C380CC7B93D6289BACE012C B6FF57FDA6EFB360ED7D4CE5E95DEF15060B2AB087FA6AAC0D7148C30041EDB8C2B3436D4204 1EA6FD75A7FFB1B1E7AF1070E5AF5D4474BCA255046D2333963C92767EB7DCA9E42C67BE10C7 CA045164B2A3DD09EC51D4F85CA0BF63CED90D007B59A9F67DE9570BBB634B977F9ACC4F1558 018757634B990E585636ADE03E2608C32103DB38CC8E165511C6970B40395E0BCEC682D874E7 6FE3BD73690E999C1FFEA204968498C0418D936F22FDBEED39F0B0290F612977446D2A630511 9917DFBE4461FF46EFFAA47A3A1BEF21C26B185114F72D33E3C8F097466F1B623A7082FE976A 988071C6921518B42120E33E9099FA98BC341EFE2E48176AD0AA0F77A5EC8F822E81BFABE622 F5926E81BA7352D39D9D6FAF87CFC07460C1B17B3301D0F75AB8AFCA17FBBBB98485E6056566 2C32C34E091C472F4BBD5A145B4267003AFCA53418B60FD1DD836806E9E357E96D1C1C26CBCF 26A0C54EB70051CC0815C4C7ED7D2F1B24095C2A55E79D841531AEF0751A13C8BF6B01D00892 22BA047D603D5A8694BE6A6DF54489A90C04F2B9AD1B9A79FC5DAEDA36AEC8E34CDC9FEA16D9 5F2C510DC1151B63D4DE7A16F2C8A6095BAE51A4987174EAC75E538E4B475FC8F8AD73408A10 7340DC598FB313ED24D5EABD8DE013C4BE0305EF5BDB33EC7929D9DDD48958D4D154E3B918B7 4082A2D6893966A394D27EB8EB63451DCB7C7AC2F28CC496373F53C837D727BBE56852C185A6 9530ED11783E11492AF5575566E50CAEB574D35E3DC15051E9539BDEA7EFD32DDF85142D1FA3 E824EFF8301C6E36C4996F81846426F7EE6F327164245D84CE1842D021C729FD2B18B49D4794 CD5AA5DC0A36BC5FD1814B82CCF33A06BBD218C6118E5AE606196E287251A9CF85B35C6DE359 77CCBB59ECD183DB154D855DE416235736F39D355E776D8C27A01A57AB948EFB85DC4209FD11 C7C36719C8D3140C5B60649A0558D7FE3B3CA665D10566A57C48D1642B910945C18D0E1DF3B0 B06E56A6E260C9651010D077902637C6BC643EF05E0193BD98A84CEB16ED59FCD75E0D7CD6A6 EB2D2DF658AE486C065CC9BCB2C846C9D86C63A57D0A5593D2F79B8813CD2DC202982D07644C 5FFB764B543DB614A454ECE810F51779C870BF526680809D0E312CE3043DF638353749A4FD7E 1FC03853A2D7B03C746F151840454A0D0ED1BC2C0D9EB6361B5CDBD4AB588FB060A77B22C671 643F3D7022FC1795C79F949786874A070E9B22DE73612B09193E35F6C9481FBF1A521DD21C77 7AE537994176F96C9D9386D714D7DF557C4876DDF0D0123069AB873161009D620F32A677916A 91DD4C7017B55419E679C7B76CC0D596A717205B923280F05FDAA872855D97DC601B6B0BCE14 53669846F722C054FDC88839094D1C34E86859537C5EDC4B49C8D8DEF7D88FB23C6ED9E8D2EE 2020F9F0437B6C2CC10BF7B069EEDB3ADB29FB26ED95AA8DA3ECA644CA2DDA965E23068B40F0 A3348C28B086E88A8E2FD5C0DD2C38DAD55A875E80C6FE2B89F02EB4ABD59864AF87D0786D05 F44D5A70484462A3CCA42D73149BA69C3888973FE38D81F1F0BE92B358040147191ED68BA395 993B7C750695B415F0C8D4D41919FE52554F2294D58AA8B5C8A10A5546C1FC0EC969364178A4 5A39C7409D2D3F0D63DA29EDCACB1C842B5DE000BC656FF25A65CA7509A04C8C663E408C660A BBC6BFC29FEC5B21797FF93FC0326E6E6949EE8A57F10FE68BF036093B3246DCA2F186AAE675 05ED5131D21762916B9D33B28C7B005D8F1E27C7EBAEE959B90B56166D6C84881BB4ED570E89 15F708A20D646FAB59FC6D677F29414C06FE177200B278F5C4BFA0E454F86758DAF0EE806071 93CB1BDFA481CF62C2D03104FA17750E9308B36908D0D347750B863FB377DC07E669ED46AA3C C6839F8D7FDF4CDD80A74529BE168B02D29B9BAA88C3D6651C4E3FB4BE09D73B30F4E9C418C1 8568681AD8A9B1565E47C0C357D36BD7116F99B0160A26648EEE108915C44D435610285DA064 9EB6477A76CED18D1B2953B542B5FDB47848AC07A390D8576706F3A8384ADE1660872C944BC9 EC50CD01D6D530538933F117FBB88FA991EE92C07F59CEFD51BDC68668FB0E5FAE1010DDE5C3 C8B8B28B257C37FE98700AE8CFD6ACD2CD1F85F1C7545382A709714A351EF0F1B852B543F86B D4B1D894662EB0FCD74A6A582A8FD4069F0DD403C0D66909C44135B38E2566EF972CA301CF18 2F5C101DD0DB3C77819585A3DB0D37847DFDFD113DE80A720CB0C0C42EF0776E68C4041DC248 E01A0CCC112BB636B47712AA5A9C02FB1214BF9417B413325C36F4B20BCD7C323C84299EBF52 D238F32EF83ED5FB9C7CE70C289BB6B28CC40ADBCD4B325EE6ACA66963244AF021253A197232 1BE150767826C0CEAEF5D56D8C5682C71978B3E2BC078C9F9BFF661913E30CFB4B87AD2985B2 323E7867B5C4A2060B3EDAD8C26FFA843B3EFA6DA3EFD604BCFB47AC62DBF9163FAC2CEB295E 61115BFA2A30607852385D1E4B3F6E75FCCDBA36C5BE91BED15881478E53761EB91DD8A873EA BF48C564CD46100661A1FE1609953BFE2181C893C99137439C55B34357AECA4AE55D8CFD4313 E61DA972FD294B99ED3B516AD025A8E91FAAF4048406245D4403B588AA9F4EE013BB7C9B3161 0BD3F653398511039EFFCF061D09071433CEC17C29A8D31015FF9B609667D320E5D2079F30BA 0B439C45F3B0CC63661D0157D80FF7ADE609F53C2CF089559DBD44A5A715FEEFCC91641C1D2F B5FCE0A88162EF5417C3C828CC6832EB3EF953E9A06708EEEE65C2F4E5D146BC178CF476C2A0 FBC7B70601533535DA948773580AE24EAA9122ECA5EA7641C1FE5C5BD93E2A4B16EE0A26F68E ADFDA9BBB488D640CC9F7BA0036614994E3AAB632C2E360A3768C6D0D5D5BCEAFB9DF338BB49 61E5369627FF4BE3E800406E11668F13CB082E57CE2DE207B918D7B5283AF96CFE75AB736B85 33EA8C5218715B59B987667F49B34D78ACC16D4C6134FA5AFBA0C12A7573AEB9AB3EE8B95CBA E8EDB16D22A7EAD311CA0AA63AA5AE2FCC5659226971EA0A142D141C9414766966AC846A9121 BC657387AB15D4DDD48BF7D3FA223A1305A31EDCF0FBFC0D064B712D9A818E6A7C793831E56A 403F06F1086E8237094116B0E50EC7F62A965EE389240109460C407FA4C0AE572A17591D10CB 6019342DA6D4935C9E9753E20B58244AE53BDA788641CEBB4922791FA9B489A8783200D713C2 90A5ED8E216087CD37201523851D34A13F8B0D87A9B1656D9D2554FEEB638A4F53B4AF41314D C85439FC1228AC342EF74E35014B5D00B99E1CC1255CAE3E07343645B57B5D39FCEF11DAD18C F13361BCE148F93B2938F1D440AE4C7BABAE03AC75A6E0D259BCFE9F2AAAF45803C26BC06457 C6F2D7C9E5ADBB2C755277526213CBFE402876596DA525596AFD668888B84562297CB3A79331 8895C909DDC76654536109749D2E34D2D75646ED9396A8F83F91FBC985D97FCC03E523CD7C49 CBC62CA1BADBDA4910731A553BF805560139493068EA92E961890C197FC80536DDBFA500E158 D1D62A19450052F7F23C96865C97E683A433F19D62E8713099E6C3087500F2420EEC9AC0C5B4 697B77E9D448CE61514CD9B77E37F25FF425630F5E225CED3A6FBFFCACC8062A501B0931EB48 95D76DCF3F7C2E8E2CD691283D105DA62F64DAE7F4D6387AB8D9BDC49AE57A500FB53CB0A2AC 2B98B9E698B7115B7F2397E967E7FC8A5711610AB852D2A3B6FC1E367F5C32166ADD7CB15E9B E963516439778AB4CD95854E98C9F7FCE4A260F004567C6C8C5136467CC19C6DF152D4BCC386 3A819CE684F8696E39C7B2B0BCEFD72211E8CBE71C5C6705819C7ECF66BE32F58A01E28954FE D3D94F2D3895B12F130827CD467F10040F9A6399B01EF2381BE48764566AE694385D06C5683A 05F4961D8F6E052E02A8433586AC2B93282F4227E6BC1D3165D613A78F6B8D05B7DC19C49684 C76408CDC25F5A6409ABDAD97E61F03782FDC881F7F2AC03E5822E6F14BEEFF7FE8567687B3A 8B3E2A3A6C339C84F69F6F49980ED5C7719F372BC205478BD486DC4C8307BCD7E2F9B2244A8E F9D9CEBB84C61B8D37261B5C08FE431AC682E76512C5070E155F0FCD9344F3109369CF83BEDC 17EFF3E1C0A4C3BAEF7EE4066558667D5FDAD535DE80362A9454CDA73DFF44715192303E0D8A CF7279B9289FC09CCC90663703D680D66BCFEFE856ED7FE1BDF4409B8D560BBD053ACE898423 72B1ECC8C7D780A8D647DC1273A22803A055B5C45F6EA5A8DE5154EBB299BC8A5A7EA4F7DE2B 4016BB22B2DC8B773E57D78556DB34F1D690E207E267794A44FCD6A64373BEA8B94BAFC7697E C23A563399276BEB20CC51B9D395963236C2AE01376FB505B2D5DED6DB0E322A6D2CC9300990 1000A7DC5BFAB9B18BD04307B5724CFAC9037E44FB1C66E682272DD047CD78D63646514BBE21 86528D4260BA8AC0AEB05EE03C3B48949A298FA25BF44D60FA268864A4FBAC37DC5299BA8CDF CCA9FDD7B64F4978FE184FE745610F2C9302D752831581C27CA4E04456E50920C9D747ECED57 A80EF4DA1A5246E35BB607DD117BFED00684514FB6A3F4FE9139D263C4FB8A98AA314035A0A6 73F98B1FFE5EDDCB663E762F0D97FB1EEAD0191B23B708041CB916C9DED0D069D81A356211CA 2EA678E5D94BD73689C4DBC6EAB71D658A20EEC846E847EDC852DF7A4C1EE3D24C89B34AB325 8DE41141D81A97224661B6C386F1B1E75972E8206C1061602F50CD7B1F8C96EA70A4E2EB5E79 C17CA7D3AF2C55987E90233C324813580D71DD23A821BF78BC557D60E19319DB3AB27896A757 EBFF4CBA7F5823B2F32A23C1BF1A41C5D4172BE89635991C1F6DCF7E920C2DCE3154E6DEBF06 18822875D3181CB2050F429696481CCEB775B5FD4ADF7D970590CC6E323B44BDD981AB31CE8B FA58AA1ABC3AB05DAC977C74914CBA5620BBED4C48AF8B0D5EF351E9777B5E617E9AB7CB1483 80A166625E7749C77B1D7F1443BAE8B3FD262F53A9A59803617BB08E4AA9B7DE89BFB1DF1AFB 3ABB679F8A6CA32233E2A2A085EBD38DB28CA197DE55CC0B0131519A57A24886DD3E6AA49D26 7A54E686093A2F5A6C0EF360EFF07F29A027A0AB67CE26E6DD3113F443A6D9A0E7EB6CF8F7C5 3768471FD6643A1EC3D62D0C227690575DFE773BCB38F5D1414FE450F2354D178AA2C7D6CF9B 08F7242D03FB94C28BCD1D59F2979A9C586F208D148FDA27B5C3DD441E4F0C8BD8FE309CC796 81FB0EC929AB8DC26D4175E0FB6FC6020FD74C79290B212F14297ACBBB9EB97C6ADEACDCD2E7 EE063CAC88B43E031E1977820CB67147DF66D94916EE9B1620D62870DABCF17D270C385F8DDC DA288A7D1829F1D2F9885A63451118B8CE7B8BCFDB09BE6D16BC6E1B8D3112C2D667351D4DAE 2C22F5C0D05A44B305F7BE0270BBA58803D45402F637DCF0A9EC73B8F36FE1D883C318540FEF A8CB7623CA1162B813E2D092E8DD64E6BE418E3B6C57A711D9B2598DE1D0C1CE7FE33C8D1CC3 2062B3E2DD084A34591BC28C9C6B039ADAFA531C038C681B4C756D7F5E5640BA49C60A834F82 CABDC7C680517457410C6AE9BA06C236764C7FA69B5C8DC15120382A5DBE48DB0C61FFFEB654 25DE4E3FE0D483B311CB9A79B39AE091BCAE2ADA5E472C1D3B3B01DCB45880341E8AAFA7EE86 9C1322FB9D1FB44E3E6238D22A6CC81A94AA6549D1C2E18A5E38356A95D789106A019449261B 4ADFF9537351897ACD8BE2BA22EA3962888F26760DE96E7FB40E5573503D35F73484B41A2E27 458EE0CA07661151B3F7105057ACA6C4BE383C14EC320E5D779A05F51A8FEB66E926E12BF40C 697E411982D3F3DCAE665BD69691F7C2C757C0402A9927960C29395E7A288732311C2AE44DC4 3EECD68CFB55168676D316FF50F7E9FCED063708EFB3094E8EB27D6BEBC23F0172B158CF5664 0CEEB2BE322BA263C46E6415E2F680BF73CEF3091D82C6880746987EC3F0610226D904DCA8D4 5BA3918D807D46D50124ED6A276D0AB71C55980591F3E9E457BFB239A6F301CAF977AE8BC3A9 63CFD912A99E5380E675929FAA0398843B1C8CDB9A76CA5C32EFD17A9FAFA119295428106E59 ED046BA23E1A086E7168F2E62CBC0C83787D55292545E2FC7765A8EB7DD6B0C4C83EFD177266 F22CFAAC05D4EC307C8A329134ADAD218E786689C4668CBEC025130972D2ABF2BB611301415A 27CD13F2FB38A6D534491CB1B06CF3758DC3DB11B944E31BC7958DD35F7062F7E7E0B4157D10 56A250AC96C1ABC44DA1B9A0C85A17804D124523AE28DFDEE2753B7C2323D64E933D515C98B8 B21F83D2F1F2AB963B159850C87C3A93D2AF45582FA3B2F7E7A5ADF743D1720A55B0E9247F26 44FE0C470B337044363E19C583E0CAE7F0D28A46F4B53AE6F411E3466919CF0D9E4844CE2405 9081600A6E07486D3349415D42F126DA8F6350A01FDB437DE73568A6A391E9705397F46F38D4 A07623EBAC5C6908018331477C5F51D1FE5B08DD2EA49AB4AE25C3A8764719E48CE9312689D5 6965EF991567A46440DAF7755BE5B076683B76E0F5341D208A99A1AD21D8D88147990945B2C3 11F81951CACBB6E1B3B85AC6E594CF79D53EEAB974F9F4AD3739AF13873E00B02E9DB9D7105B EF02503B335DECD23913040D780996C9FE162E6B8DE40DBFB963D5539FA64B0B102D60A9F713 3FFAB1270BD688017D5912218EEA15D5E8E010AB98F46630DB351BD27C54FEE26F611C88BB70 93ECDCA5C704B6BF5E825F023361117F06EA28910989863FD9D7B4628887E6096F0D9E4578C8 D2C35B67C0F378EAE5A84908CAF59095621E708F12F7E32777D45BE7B8BA9B71D1B9047729A1 24D973AB1F0BE5A5037F5F324E0D6AA2E7A67FC9BBB684172484459BBCBD3F044F420A59943B 01FA28E8EAE00C24D22A9B1C5767E5F387172C963637BC2FC1D67048C31F6DF12CF5D2D82A3B 384AEE125CF6BD69189C8EE6DEE342B231E1CDD31837B44F8082DDF7C69D31CAD02944941CD7 B65B574E5491AC45DD3E2245C35918C59F623270963B0A8C7324F11095BBB4B996CB46BB10DA CFBBC13C288093649A6EFFCBF0B8FC0E599AE5FEF536B76CA82110B60A9CFE6AAE63561C8E1D D62E82138DE27FA1C09EE6B17233A54888AEC96CB24F7102669881C5FFBA815EA2E5A6B82B28 BE5F79707D143E57F998697E21BA3DB282FD48F60F97B8946D994532F60CE47E2EEF194F68C4 599A625ACA9CB0053570BC6F1C9F9BC118E74DACFAE7CA5AC6F7DAF6A87DEFBE708A71F0287C EDCC4D4636F1D29D8D2E37A59CEA504C0F4CB7574DB912B44094575D0D58BE147AEC8DA6CD08 857153BBD101568D01B1C3113A8E07E47B18CB70BBCB01409FE4C29C82D857DF1A23BC0AB3F7 60ED275AEEE0C77DB49E2DBFA196F05BA3B23A5D6D2E88CD35F20044A1FE077E67F1EFFB3FAB B138BC6979EF93FD6E6C3CDADFD3C4EB6AA21C91DBEC73B25DFD2E053284DC6137960F6FA11A CEB8D57E49D173587EAC967CD9CEA22A19A24DC75B568318077F591E12244731E8F3D088E0BE 9E7E6D5D088282C6C1FB678380A865CB4069EDDBA83821E8ED906EFA01AFE5B2DCD5ED968AAC 45E6725A45BB16487C54E2C2DB77316D4E7DF20E7EE2A673E22DEDB75BA93A7BA64558915248 0573177EE37E91726C3F0A0184D150AB6D96B585D137494F350DD8673DF86E67E60263BC09F8 230112B6A1C493B47B81DC9C547EB0322FB5668B524193F5DD31692E145B647979A00DC3D6DF D1369F1AC0F3DE009AE9C4192DAC360CBC9AAEB2E8D8B2B3FEDA5C31728E9247F21A9FE38E01 5DEDDF37922AF9B6F925FB9B2B1C4C9B2313C2F0EC9174945A992992970F703E74E730C1E064 D46456492A01A9DEB98A812C96689EE82AC21DD35541923144C5FE63630452374AF79A8B2B30 DDFAC7290092436E0B83AABA36F691EFC5F1A4779AA97FEFB999BDB136C544EBD586F45C9F65 B8F86875A9E5F83C01506B87704454A709F6255A530A298B4084C614C3BF2261C270CC46F7D4 011A9E2DA7B5E178CF82A0EFA49DA239EAFB101FDB64D7E9FF291484C2B47F8566C566C70E65 C1DD39383A25270FADEF54DF3582F415ED1E677720398B3F0279B2ABD7DA23E436FD8FD3B0A0 3B561140FC402F15CD911A8428B624AA72B605AD24696242D975D1A61A3D2B9BB3DBD61E2AD8 F9B473331C9440580C7F9858A2F3AFC73A202760E922DFBE5D1CA92FA95DFEB87398B41B31E9 C93C8D0473904520C05787DBE0F7AEB521D09E1D2A1B207AABF2569E52FEEA23645E1373305F 728A4208878F74BC0CBED5BF3A7CC248D9B9188DD63BC0514D8AACE61A1719D2FED0B54F6B49 A5D527F72934DADCF2B526A77BB081548AC134E3AA341DFAF597E254ACAA465340B9D680E3C7 686A6ADBA48115A2BBAD51B843C009EAFC83D9C6308F73E9FF16D9DB072C07B72AF1C5FED163 2C2350BBC268646B44040E43E8047BD65DDC8E25173134C3A2F56ADD1A32BB7293C0F18D80B8 6107769189163CD29DF6D7DCA78C33547386A682A562AAB6E0D586CE8E950F58997F7C1619EF E447D3A661BB7F708FBABE63DB2DCA42771286DCD39C218F04059076BB6ACBA068BBC51BFCB6 890A3348619F490967161F976C2F52331D8758C31F043236CF2CCA5A77D0CA769C1698E5928D 8FFA2D071A95BCACAE3E335282EF698FCC440266DB09440F8A829AE99A1CA03E8708C68436E1 A7AF28ED12D5A55847B2E3F759BA638B5412FFE0499AA94FA2F55C2C5B1FB235D6538D060DAE DB88A804552C92499E77AA473E1A2C51A45A328541667CE76905BB91C2A3F86F9DDF21C875B0 FF349EEDCA2CB28C1E0DB3360742DC4780C1107EB3DF5BDE81B4600AEAC642A78A387DBEB843 52C9614DA6856CACE1A4FA4640B487B448E63FE7E567F14AA6593C8404BF71475CC356EC6506 C740A5537AA47BAF743412F431FDAC842286CD399855CBCE1ACA5B60A9CC771F28A31B7DEE39 0C7B5B77DAEE9D88C39198263CCE4FD202416DC43F523B5833B964B4CF9569BDE488F15BCAEA ECD971457867CF607213509D18AD79964E47755EC4AC3D2346E67783C75A17EFC568C994C850 AB215821ADFED63454EFE286F217F741CE02361D79B18D977C78126F2536E3E09515188D4B73 9E11064AF5BCD86C45265782EF88488E6066C0B71A33448E6EB442ADFEEE2BC099B044B2335F 3D547545C6E603AC52E58AD347F9012ACF774A4B6E890E35643C469F50157E781E62F2CEA726 DD5FC10CF951DC17DBA7FB2FB6DD640B57319E247C499B7F6F075CAA26B230ED959DE657C2DA 2567C5453409ED2377D23AB36750E2063D63C14333FBDF27AE014A2CE001DAB27D22AF54573E 04C3CC0E77AC27FC21CAAB89CA0801D1AD357C3295E952954CF0A03E9D45382992AF2EA70A33 E94681A5E405D22923B991FACFA2643FD07DE00F0B5702BE9ECDDBACA40300E49C8A00EB47F6 15A8C6D79156B074B0AF9A67C9C34A6F18FC7E2C075DB37979A29A4ED6C5BE5E1DA15C4D7671 FA1EA5181964CFE9B211D27B75A370C9351B95505B54FAC043092B65735FF0BD6A3698241DD7 B516C058AF52192904C35E9BAA3D5D39D6318EF477BCE9D0CA2B55DB8E192D1A3FD3F023DB46 245721A1EF8F03CD710000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMMI12 %!PS-AdobeFont-1.1: CMMI12 1.100 %%CreationDate: 1996 Jul 27 08:57:55 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.100) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMMI12) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /CMMI12 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 161 /Gamma put dup 162 /Delta put dup 163 /Theta put dup 164 /Lambda put dup 165 /Xi put dup 166 /Pi put dup 167 /Sigma put dup 168 /Upsilon put dup 169 /Phi put dup 170 /Psi put dup 173 /Omega put dup 174 /alpha put dup 175 /beta put dup 176 /gamma put dup 177 /delta put dup 178 /epsilon1 put dup 179 /zeta put dup 180 /eta put dup 181 /theta put dup 182 /iota put dup 183 /kappa put dup 184 /lambda put dup 185 /mu put dup 186 /nu put dup 187 /xi put dup 188 /pi put dup 189 /rho put dup 190 /sigma put dup 191 /tau put dup 192 /upsilon put dup 193 /phi put dup 194 /chi put dup 195 /psi put dup 196 /tie put dup 0 /Gamma put dup 1 /Delta put dup 2 /Theta put dup 3 /Lambda put dup 4 /Xi put dup 5 /Pi put dup 6 /Sigma put dup 7 /Upsilon put dup 8 /Phi put dup 9 /Psi put dup 10 /Omega put dup 11 /alpha put dup 12 /beta put dup 13 /gamma put dup 14 /delta put dup 15 /epsilon1 put dup 16 /zeta put dup 17 /eta put dup 18 /theta put dup 19 /iota put dup 20 /kappa put dup 21 /lambda put dup 22 /mu put dup 23 /nu put dup 24 /xi put dup 25 /pi put dup 26 /rho put dup 27 /sigma put dup 28 /tau put dup 29 /upsilon put dup 30 /phi put dup 31 /chi put dup 32 /psi put dup 33 /omega put dup 34 /epsilon put dup 35 /theta1 put dup 36 /pi1 put dup 37 /rho1 put dup 38 /sigma1 put dup 39 /phi1 put dup 40 /arrowlefttophalf put dup 41 /arrowleftbothalf put dup 42 /arrowrighttophalf put dup 43 /arrowrightbothalf put dup 44 /arrowhookleft put dup 45 /arrowhookright put dup 46 /triangleright put dup 47 /triangleleft put dup 48 /zerooldstyle put dup 49 /oneoldstyle put dup 50 /twooldstyle put dup 51 /threeoldstyle put dup 52 /fouroldstyle put dup 53 /fiveoldstyle put dup 54 /sixoldstyle put dup 55 /sevenoldstyle put dup 56 /eightoldstyle put dup 57 /nineoldstyle put dup 58 /period put dup 59 /comma put dup 60 /less put dup 61 /slash put dup 62 /greater put dup 63 /star put dup 64 /partialdiff put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /flat put dup 92 /natural put dup 93 /sharp put dup 94 /slurbelow put dup 95 /slurabove put dup 96 /lscript put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /dotlessi put dup 124 /dotlessj put dup 125 /weierstrass put dup 126 /vector put dup 127 /tie put dup 128 /psi put dup 160 /space put readonly def /FontBBox{-30 -250 1026 750}readonly def /UniqueID 5087386 def currentdict end currentfile eexec 80347982AB3942D930E069A70D0D48311D725E830D1C76FBA12E12486E989C9874C2B527F092 5722787027F44470D484262C360CDFDDDF3657533A57BB16F73048BFBBFCB73A650484015441 FDC837ADD94AC8FBD2022E3EC8F115D4B4BB7B7F15388F22CC6198EFE768BD9FCEB3446EE4A8 DC27D6CD152485384EF5F59381FFDA43F2D20C8FB08AA27AB2015B774DB10DACFDCD33E60F17 8C461553146AB427BDD7DA12534BA078AD3D780414930E72218B3075925CE1192F11FC8530FC D5E3038E3A6A6DB2DCFBAE3B4653E7E02730314E02B54A1E296D2BEF8A79411D9225DAD7B4E6 D6F9CF0688B69BA21193BF1495807E7BCB09B7064E91FA0DED228E4209AAE407A7AACA60B107 6299AC4ABD23EF02F108765F0E3D91F92F3AFBFDED372FCF6E4B1416901517DA8F2FB3C9FE7A 87BCBE6FD36CD5B5823FDB74229036A63C3346A1093E6B1036902C1BF42FC317C80ABF04020A 47B344C36DE42F05C490A0FF44AB6D5249E9F552A8707BB7661E242644814001C8430EBD5E5F 0B944CEB666EE64359D663E355B2F17093A964139D17287F6CA6A024767EBA4FE4873855BABE 2F07B91560F68300B06DFE27264C163195D446980C35BCA0B48F7806626AE72636593A05BA40 3CE1C0F8B2CEA3ECD586E90AC17D034BA4AF708304F231313459FBBBFB97D4834D0395754AB3 F22D6495D2144087D448616FA1CE27BC50D346543287E3860D99B433624119BB9920A2113604 C0E260FD275BA55E0FD19C83E19ADDC3BAA1F32F6B7284038845CCEE71A3311DDB17B84975F7 A984BED7C6EC2A06E5B335A763D081C6273F86A46632FD9141A27902074FC860DF3A2EB59B89 774C767022DBB577E30DA128BD7706A43AF886D0C256B50FA968EF06776AAC0BA5387E9011EB 2334C1F42C090F06A1125C207EA6324E87F46414050D88004F564EA336A05016C7B7569E633F 7B7F1428C5CC47DA7C875218D4A1044E26A472B1FB52CE63ABF9B840B8F8BA45BCCFB65367C8 75DCBE1B0ADDEF3761E296DCDA097E86467463CB4B29CDC95ADA06A0476D0E5EF9EF7BC53AA5 3ACEC2BC5E00D557829294914BC7F823EC0729494005A45A1E1C68077EC42CBDA7E4097E07AB 30D8208B1DF2EBEE1E09D4EDC9035566A2B14689F0D5A5ADBA565896797AA61F06AAB496F2C0 B8CB2B37A35889DD87803AE6795B23AF56A8942EB93AD6F76EF05B3805BF383FF4575465A842 E8B4D5BCAE363EEACE407E5B5CE83B678A01249736ACEB146B9D4CB91B488251AB190026902B DAC96696DCB3B3D7ED4E8445130F4A63CF52FFE8D10402CAB38CCE75B08488074EE90A09EADD 649D834E8019D6245D65C701571C3411079E05C2E424AC7385B659302DB5802D10F7CC8CD9F6 EB6BE8994D4FBBEBB2CD064BF655598A1AF5CD5388A0802D8432345A57ED2C2E95492E3C4F0A 6EE1C5D9CE849D734B572E8F1774A46336B100F563EAF84082231E6BF148AFA5945F8B51E70B FB79E76A4BC5D2C152B1550C6CB6538011B31D5E979F30BB95D1A6146D6434565439388FE815 F560576B71D799F6DA1CD8A373A685278C5988DB3F0273B00248FFE450C14E2CC53A6BA589D9 50FD2E43BEEBE4E35838349CB201DD9498050267F593D748EF30C1AD484DB11539CB706F3C65 AFBE7778ED4470F51B026618A4A5FE1C7A9D93A5625226F4CF4DB4DF6BE1D1439003027A1CA5 DB1D288E109690E5EF1BB3D566F3C86302CE7501F09091AABDF84B8C78F71348F36170BE65FB CF5161148D69EBC91D28CEE15A3B44AEC6BBC8E5D6CECB8F9A2DACD7B66804EFFF08343CD925 A50AED2EC2C58C72FE198A93DED89695C15573BB95E4797BE8945D5DF06D1E0690E1DECB104A A9143111682831293FB6F9F781E9D540C5E7F25D463B7B211F3EA0642806A21EC62F52344D7D 8BB230477D85E39A4C63D2D2200716E419E3BC78482F9005A73C767797FB938F0FB985376468 0C984DCEFF25B10C08A5B355BFF4171B107270D868CC3578B7897B88D85115DF75D2661FC52E C614DB064549F7E7B7E69C93F8DF410552D18939D5CF32962EFA787949BED083525AE62E2119 CDF12FD932F96E9D5D5FC96D51912D763974377B69785E84BF9600A6A946CA8848124CB5EF09 2D4BB72DCA67ADF52D637B806E1FB9477E4BCB24E4780035F8A72BFBB670CB93298167CE1B3F 3715CFBDED1546BA7F974898F03B786B6ACBC9326A85BB29604CEEFEABE9DFF2CE9CD8963B11 04480AF7887FB85E8944357A91BCD3824DA9F5370E8ADA17BE9CF36ECFB861950F9DE73D2902 C3FF5F8E1228E64F190F523248EBA6CF6290A278AB09F7E636012754089BD49AF82EDF9F32EE 43320D24E393658B4238AF64E42189A11EC12E42453A6270E6D70C84CD902289335F2E9ED046 06368B7FE951B1294A17202F6B1BF8857F4536A105D746247407D8E2EEC70C7EA5C6CDC721E2 90A8B8D528BEC8582C35D2A6E6D30994346B5EC2477C2D0D5B97603C8C3423744D5E0C50EA75 095594BB24B9E34C0EA2AE82D3DB11DDC45A77CEFE93C4AA6642A9C76E34F576EF71FD60F41F 3E074E74952BC576E558036EB9892E016D3F46DA3517F884B49C3D69D0C3649C98E41FB7C830 0B18A7148E98EA399809D8201CA9FDFAEDFC2129A232ECFA32D630477943DF448491EE685180 82B5D1537739D91DB3DBCA594915B4255A55352C60F305ADCD9437B029660B36F214B027504B 7C535F36DF74C5BD51E0D060CDE000BD38F60BC7E6CEBDC8C31A63062F7A39CA1CA177548156 0AB53EDEAF31AED9C151115129B93CBE9D6834DF0DAE514726C6D0E6F4F99498EDA5C4625D02 33235FC57436AC454D9B10A08789CE55E4D845927899388441AB73F8A94384AFE061C52B6688 6F1F72563338A4D04114E2F357D59B68359F04823A7BCC5575453CCBA28A9C522E883627F225 B1892DA9337C3EAF3CEBF2428E47B86766AA1EE2DF228DDDF2D1368C63D5C00971EC12ADC6FA 3B4EC682F0B007D533BD2903282EC15E7717B99F6284E76FA24619A042574FDD792128C65EC8 793DA8790E56D7D9E5B9CC1921F1043459BB9025CD882DDA610F7F558281C56AAF82FA978923 6795037F2C385E11B9167812B1DA3C7322E73955E26C292F17EAD971551008DDBA460144372E 01BEE2DCFF4BF4A24816EA4CA2FD9D903838A0CE42D8D5D6D49140CA8A33B1E9085CBE8529F5 AC8401C4E59D28318D80655BFF40A0E3F2ED31A4304B731246BFB7D44AFDA6C2890885596CD3 600FBCF96A95191E8C5C840F2FEBB2C9999CC0636FEE70281BA69FA70B08A92C7E1D2BBB5DC3 A9AE2A8FDF8CABB6B2C6A92DC2E6A7EB6C5AC4CB6292FEC3260208564A0CAA8F0DB1B2AA6B5C FE7896EB3DFAB600CE834A60465BBA4CBF751FBB98DF440C587132294F6ED1E9E5503802BA9E 1107340F67AC3F37F3C097742E61E0BAA5F5020A4639ABC3B07D603EDF4CC7E80DD5675AFED9 B5DD4CCD35B299381FF7B38F413DA9CE41CFE08485BAC0993EFCD07FEA9E8C631EF2F249DBF7 36027109E752FB25E00DBEAA0C2014C2D8C87F4B3848BDB8AA593A6B6D55CB99D304EBFE2135 25BB3223F8366531386D7DB594683B2DAC4176929F6B39EC2EF57EF1C4E1CBA9736B73DCF25F DA39C525A330B58BE920654012784958D8C0A5A43CA3AAE4ECE338DB19B2704E653A26842CFD EE8A313475D33AFAF1270FD57B4EEFC9AC4F0BEC2CF23072E53814DBF8FAF283AA5C883DEB92 8B86E1A3206474D5C75D30F00D50A334E69292C6E0D385641D9FF891292D815A1D365F216FE5 F916842FB8E857E2627B09859D3203A6EBFB98B8E01ED264924B767CEBC5403ED88F382FC377 90842A8959ABECACBDE20B97846602D65050E198BE907BED14AF76A9131D9CB460C601CA387C 491531C23D166BF7200EBCD41ECC3FFCCE117C4EB1F05E1890645629C9767B83995458F7E14B 623933F466944752FAC277187C4FB209C879B5EB91698949AA1E343DFF3D7B96C388DA0E3013 A044E9D254A2691A5139B8FF7174E16822B76C39B250C28FDBAB74AF1A6A79E06EA996A4AB34 49EA126044B3C0880C40F4CBC7ADFB73CC5AB29E7D71B73F8C4D8D9243D6F0CBDCEBA54C4593 E48C600C3729953B2505D78177DD0C65DDFDD4BB7C6DCB2A973C99DB42513B334601BACB66D9 2D9F0CCBA5D566A42489E9461DDD246FD15C57F9836217CC8DECDD6A95E9CB0C66ACCDA835F1 2CA778BEC7C8B92417E0BDA48A04348229AB736DFE324B99996F80DDAC105A0F6DD69E330E9A 8DE1CD32FB3ADB7E0570111A0D08BC9475BBAB122097740B53A360A7DC2EBDD0CD94B37BF686 C84D1CE4F095B32E2EE46F85F44B6E3BB289401EE3BE0BBAD9A158D5B2B1D0645EDC72C8E4E9 B620A06788A0A9FBBBE63C76E857F37ACDA79D431C31D1698D8081F833412C0162BDFB90028D B30E89265D8A654FF316DBE54A8F1CCA426DB4DDCBE99ED97EAE070BC24A203FEE3296C28AD3 C89B444B3893E882A3D929F283CE822311846042111BC2CD2697E2FD93E171443CD04461EDF9 352B2AB5657C19644AC6E66543618FFF3DE61EB932DA8992070B58D804E6BF94D316500F89F3 122ED3996611EBE903C415744BE5477A8C4117E4F600316847BA54F193743594357CD8481301 C8A88E6718F3E192E07E1368F5CE727C7FEA501C3AB79F83F88D87CAB2AED90F3AE9408F9253 85C033C10B349CC339C4961430F9CCD84441FAF97DF300E7B0693C98083EEAD17D0903FCFCD4 B461892CD7D0C8FD7DBD317DCD9C8349FBC3C70AF56FC189981F061078ADE979A7D8C96EC0D7 96BD51E6BF7F7624C61E78EB045E87E48908A3D2F5AB35386D28E1FE52DDFAD920304060EE8E 24421F5962A6F7FFF72A62C14CC3F4325D69BBB80F097B1B91D3578943D6A409BD3A0A72E1B9 4A1B9A42317CC2D4F55634D8EF89D2637DD6D005B5F4DD8B143C451B1D0682F850A53FC8356F 5B730E55E111D362F977081DFE2651D28799948454A363B626827A2679AB6C8783FB6019EB6A B5D567729ADC1EC50E69D482DA0D90E087C5249BC7C6C1A7D5C1A16CA7E377C04BEC0DE8C408 08E0AA4CFE5724F650AAFEE416B7E0CE1F8520A03424A1629416CE7440A75A3928FA5A9A162B E53E4E58C01B97F466C0B42F573E67164A89812FE3D0D7398AEE02A2592FB12B8E8E21A91EDD 30E04F0423700F27966D0202C330F2B92927992E5FE433FDEF2BA9B10EE22E1DA359DD3B0F51 85237F2301AA1AB07AFA4BB389DDB9D1202BC8AFBB1AAA1D8E837D66F0AA7F5DB85E6B959270 6D3A17F2EB9C4B96F4F3C4D891656CDB37A9AB8620533D09813A0F11F5DA5EBF19D271C5E9FE 337D648E2F957BC8F0C150916FDEBEAB4903B861A71695C571B407E639A015EAC61627468A9B D5EAA936D207B24D8C4080BABA26787D70AAAFC39EF4FCF2EB8A933BE0BC303390B0C48F2B2F 9158EBAE3D3C97686ECB9B2783784E0637BE9682E8CB3C49042DEBAC265CFB046563DE793BA8 AD74AD18F915838B426FB64882E27263B200CBA65A4EFE9259C2D27A26FD55C2EFB45F7C3D29 EF476DC9CB5E196EAA9E7E85E3DF2976751D570E906C26FAD06C72C99ED9040340E17500DE0D F396F22034E1197A79CFC44D7A7F96C87B074BA8B6DBBC50CFC6CB082D0A393A8E2BDD0C1601 62FE5A200C4173BA464AA3ED63777577F29FE8494371579B64DA3A4983776E9F65A0783C49C4 862EF6C708E0E4913445F696C2365F027923EC02CD6B6381628172D7A134A51A44C2E0129FA4 7BFD89B4856E7EE723C57EDC17C2CBEA3CBDFF6833610605FD4F60E5790ADE33F42793400C02 C30D08FCB2F83E17E2DFA084D0247336E9CECA9EA5E055CD1BD669BD1A6A722C2EA05E3A4687 442E5BD475D7DF4531C1D6A26B407B47FEB9A36892E935A54B037BCA887CE6A1DB38B63222A4 F32E493C992E9F41996B0B1BE3E1A11DB0B75F3E4A0B871C28ADA0BD428A83989EA05610BFF3 61E7B9A3C9A79DE59911668E55C35D5A88D17C4A451DECE10F713C63BAF65109D6AA75BAA84C 3B030D6648582DF7A447A6AD3B14C88A9C68EFDA278BBEC86E7722A436678528118B797E14C1 4FD39670D78D5E7AEA9EBBD7F11F7EC716C4805289A4DA73F6A8D9A9518171CFDA5078C62257 275E7D4994640A512D282358BCFA01BFB455F557FC4A7A14A0827FE76F0975830E2F80D1CA20 E02291C50606EB76E3F4ACF136148F2882EEF4C28EB2A7707D4C97739B10EB907B16B36B2F22 766DB7500E7A2BC413618009A45F3E3E9964C423564E632455D7D3CDBA22F4DCFB642CEF710D D219ABCDE35F82BAB6120B244BB6DA19D8833620A30630F80F77BC8835424882E2C9FA2B6245 91B0C67C102CF79C513B350DBA95032572DA0AFD0B98615EBEA2B7F4FEAF4471E635651932A0 11586145B59E434F98A09E12FB1E6EBFEA29A4872FF8C6CDDF091938BBCC07AE13216AEA076D 9C4F9D22124EAD08D72ED2485B5AFCDDBBFFEA273675EECC236D14985668EC10E6FCEDCA91A7 0E2A2555E6531DF09BBC7F82A8CE0303B79B1273A67797AC9712692D3CD63789B1F295AE6241 2D5529D4C0B7904497B4D1507BBA5F4518264B49F9274FFEA226B736867FE02BCCCEFDE5F5BE A6B7B700FF2F46F1714DBA94DC38FB553DE129ED55EE9B94C05D36F9E09DDD6D792FA46D06A7 3B0B2F2C5CAE527467A234BB72CE3E05F6769287304E1C7AB220719BBCACA7A27213688D0B3E 1C05817C1977A2B58C1EF598A088374DD8A4D56D24C908147CD66EC69C0B7CFDDD23E55374FA 1168B7247CB19DD94C5A31FCE4694C139CE9CCFDA56E2388D8CBF003889EADD4F053E1B3083A 7C68652368F38BBEF23896D1B122B2EE87F94F00AB22B3500875A3B24527E837A380D96BBD59 18564078262501F903480CFAEF224601F7A8143D9FC1D23AC1ED76E3CA4EA6E021BECBCC4169 EBE3050980E13B30449D1892DF47D0BBFDBF846436377D2AC575EE07FFEFE4FEA2A212C78CBD C1F0B0CE6FDFFDDC3D31FE494DEB2A379C37F437669EC1F1EB272F81B982E2986CBCA0B2A965 AF5028863E0F0D9BA50D520C2CCB6E6844E64147CBE7F4FDEC6041BE659FEA0438652E4BB9D5 463388F19F3EBDE1EE1DA15344751A2B19E9B14DDEC1800702A9A0EF84FEBDD21E9DE5D6D50B A14383C86B69179F9BBD8ADF1829B5DF8EB13B7D9061E3DC2D0F00639B92AF612A166ED1C6B9 2CC42FBB47FEA59CE5953ED34C87CF9AAFCF9EB955382EF6704F58092872515D63A4B2D65846 4A59842E23F47B3876E31A2B17BBC7350AE308859F652A3AB9A0ACB88F37B815B5E0DBFFB6A6 95DE8BBB6D5D5E9EA2A8741B1D561E4E4BAC2AD1C9CB69B36D2D24FBF18F399CC1919A6501CC 5DDCE91F57B8AB1F134EA3481CB22AE36BF4C0EF95A6AA439E1F9C23005B8401A7D790D11B26 1A9A456BE3D2CC5B0D701E39BA0A50185F10AE44D2F859777286104003EA3DCC87BFFEA2EC65 E09F07D71B3A18934628C217C2B14C34330666F47004C5FB57462D4BF238FDE95CAD89F6646A 6CE22BE01E8BA630CDDBE313A4DF6BB771D5352ED25364D81062766D695A7516C3B603F0EF9A 78D194CC4ED49BF9FAD1DBBEFCE69F56EB63910B79A80EF6D46358E7AFCA155830D28536E127 542F9C37D02F247346FC2E4812259383290E38D6C982A0649454AC7B396AE01A57C65D532139 E17D8D6B06C47713E58589515EC5F40DB47E00656DD76C13EC229F75ED7962F2D7B28E33FEDE 7CB67B8ABEDC4299C524165B3F28A3E1A6B922BD468FD1FF57C0983597307B16F763E421045E 61D8D5A2E67DFA7D84633F0DAD76C606D901BFC9D5A22601833984A24650F478B6DE1AC903C8 B45097627DE2CBA95CD0A2D0EC9D80274F1BE77272913405A47682531275FD509F64A9756ECF CE1FEA7B1EB5B613D0A24143102DFD4EECE422F65A0239577E36245BD7EB1D3021B1258A397B A61E94115C7FF86C336A9A9C8F44C54F0381E612D3C9D60336E733D120F482F9C05598FA8935 CF0D400375DA9F4B59ABF635AD86C5905A5B3DFCAA59B591C8B9AD92CFEC270D512F83904853 10FAE867952824A98312DD6BD642FF7D69A5038B4996D765AE7BAA71249815DD6D9223D696BE AF2542BFDFDA1EC77A1FBE30B00B10D2F9D9A2EDCD9CCEDA4D2F0485D45D551356AD911D933C 18F607AA212BE08B92264443E5A93AEAA8DE39F8D683288A699AF5D256584D2CC3113B2AB808 229A9837F84B8C6E224ECB66D0DB565A8C4EE455F75EF3384702B3BB43FF12DC7DE5660ADB6D 5846E7F74833C990D84A8E32E4F4FC3E23556235599FB4E0CC2DA7E0383A3D6A1010FE79B4C5 9F44C16AA26C13B6CBB9AA878FDA8FE04130983DB97BC2424E974AFF12904EC88A6CF1BE342A 89EFAE736A720E89D2342B3AF0CA4250F945441292D9E02B4013C121E53F1553A173DC593D17 A96B97C4A20E83304AAE66475848C908FC713FA29D23EBF7B922ABB2B217F877FCB199999E6D 5D2A7462EFBA6A8FB5A1AA1829B2F1B99E75F17F768EC090CDAB200725FA84754201FD0A68D5 00D43BDFB3398917BE43B4477267BA6DC9AD5E78C3CD8ACFE51E60FC5BBCCE675765E28DD321 6668F93B192BAD3D53E2D0EB98D4F27DED7EE3713B2C96626D91F294282A156BD903F972FFC8 94406BC71D5DD265B69FE2C02F78302A5A21550159EFA31391D8E210121151E9745D5CA6D0D8 67AD8BFBCF9A9A40DA71C46B6EE6B1CFFE3C68778C96B760FEFC82652035B4818863FF131FC2 497B2DB1BA8BF7663800A9DFE8A1E3EEBFDE4913A1069E346ED5D55115C0E323F42647ACDAC6 83664DC38AD882DEEF01EB1B04D0086781EE9FE197C1AF0E6F6167F2B37BC84869FB82DF2E61 4694941DBAFEE1652013759A7F3C590FE845B564706B63D404B5D8945B0A01F9B88D3A20A98D A3C926904C92B9EDE21B57B11F7143586BEE73499B1123BFF5F559E3CD42F52A75B887644A85 3BA45A6045CDEB5D74FC32A66FD90E4C30161DEA1FBF7DC808C23F79CE19CC86ED8416C61104 83753AEE1188FDA50D780F902D23E3BC0AAD486E722037EBAED8EA35FEB0D9833A5998AEB5C9 0E61FE020E6FDBC0277DEFEF3C65C6CAB5CD9B2B88695EE3D2C69E9CB61468E59D2F7B1BCBA9 AD278EB0F2A36F8934832AEF1F507300110B71E82F4EE7CFE3306AA856EE47081DAFCA1FDDDB 27A16163E2B6000F54384636B807FBFDA3F70D0D8CD5BB6562361D132D1FEFCD781676E2A9FA 1E9C7BD18BEFA58A58574BABC67F4F0F6F86A7382CE998E02A64295EAB48A337FB8362E99394 93519DB11D41D4111DF41D683409DB1D981E903978F6465BF764121755DABEBCCF611DEE804E 3915B9810BCFD2377C26E19219B5E09DFC9F1A7B9C27D823B10F8F3024C405DA5CA6F06492A3 3544EE6E0090BC2F927F4B806019AD45B2D47CDBCE950C70BA3815BD5C4DEB594C71E4BEA659 DF6F0CA4C78BBCE6658960ABB11E7FA292BB05FE91EA037BF05BF3F0F79E4FF2691C5FE9F650 4B4D2DBC49ABA76BB332FBC667148EF3FB1014930C20FA3A55C08F073A188544BB87449359E7 52576993DB1EAB25F28813A9FC81792149609DEBFC3BBA4349BC1870D44E448BDE003DFF9F84 E275334E52C91366004D9605A9D0DE343D1D78A1B0B83549ED232ADA43AD4FC7D4DB01CDDD34 6B5D75E837FE444D814C230C90FE6EDD5CE3F98DBB365F1789EF9CFC0BF0BDBFAD6FE5F86823 1DAD2C9403728D103BD2DCBC02C9246EF14BCDE6A7C849F2E5AA5D7E529FA7E32CA5B28B2844 A93F2884FC8D5FE905981F450C83A53803C8928F870B4FB9FF402118227E8C5CB952394388E9 72302A1DA49D0D2C300AC8F589536E7A0115F1FFD413A243BCEE6854497B2A26B8A255176ACB 44A7A98B6A87BA69C1597CD19C60296EE8827076A004775D069976EDA3C4AE5413DF3DA3A427 48F6EED802B0C93BA98E4CB1647036DF08DD49637E11486030E2FEE2DD40C6B79E08960BB051 65B9EA12B72E5DC6D94B0288F549599BF1C0BC63E7E0CB39AD5A0ED6F5BFFCEC932A05884165 3B7C4AE87D72FCD622C35C44C49FC754438217FBAAA60BC16FC9E057025565AF67F9EAF50849 3F72A3DBF323D1D7A6DE8AAA1AEE726BA3800A46A4198805F943035C7FBAFFA2D09790D174F4 768054E2205045E4520F1E3758EAA353F833F82884761DB2506C24EC933811401AFC75620FA1 38207A2B9371D4EEB5B1A6BDE6423A83447A850208FE54F05BF2D2435C20A33DF95703B9FC35 E5AF43EB316AB76E4ED54427F3812019D707214CE633E0CE1419555CD1BDCF87F65DE2F6F443 86533D626AFC4406881852D075F2D227C83B397BBD7CD7103B5FE9C08CAB1CA45FD07D8BACA5 137B8C287B3BB0E607FDAAB753D204F408D8BED693F99D4E778F813DFCC269F84B0A47B1E598 606FD58914E15826D51B01094A3560AE82E993DAB6B6CFECBC0A6989860ECE90897F3507261E B39F4201050F0A35E4F1AD7C97D1193BD944AC797A8C70EDAFD7F4FD035A03C1159CCC94B93B ACAE57FFAD2D83DE3ED3BA231805E321137725912992F870C7ADE3764AFDCB60EA19A4D9387E D2C45D76A4335BBA8BD87AE5C4D331EF3D6EE98598C3BCCF259886CC13064C3AA17BD63A3597 547FCCDE53D8E1A005CBF93CBF31E77D053605DD182E53EFF89E7C16CA0B9CF7ABCA930E4D33 CA0E1E72FDB295FD586CAB13794B30A334E4F8F844CD632882F5F6107C45296556029C0DC3A7 395BA482AC29CF12EADCB7BBDBA81474E0D553570A0CB6D98E618ABA2EF560B0FF8F393669F0 48C473F39A2168015D74E77D502AB53434632986CEE6DB3F375B267871D7CB01BB51A34CF66C C32A3817E71E4C392C07BE9264B3B1085D8C1A63C3CF73CEEFE24A4DDED7F5867F79B0A95C76 91B7423B172CB5BA803FB5E407DFB9D5C736E604BCD86F9D9E74544A16831FD4846ED13AC8A2 FA34995A9ED4215C59CA4D2A9AEC17B3BA91CF85978EA1255A24E40FD48DE57EF46A368BEE26 574EDA1600B8EF817948C206F6F10BB2F4DD2E5DEEDAB1914D3F56EFC16CA9E19615D40239C9 79CA2C99BFA3711A9849D6303E7116D96C2F2E760019000737A8E26B8E48430210FE7A2B08D1 98A7D6EA21DB6DD184B9B8EF2133598BDB5311D7F904934AFACEB63E7BB89D9527922963FFA3 2D87FA6B652BE94953DE83FBA87FFC013794C55890947BFC8D6B5911D4CB3F90EC0F9739C098 A5C5B63731F2A97C921680248E4706584906733E91BF8DBDD6D3AFA269BF7A4C915ED8295966 87F8C1847A00A7A5E9C94ED168289A835A8A318A29E988AEB62773DD2CABB9C2340EA4B191D2 D8CE2DF301329AC6FC0D822AF0004761D695D1A94C8F2C9137D58BE9D79FB5F2F9120173AF4F 1312C31C9A18137145F35ABE045ABB69460F2CD8402D7022C1AC112735DF89AFD79A399EB7BE 25AAC7049BC76F3DF3EA82A671701AD2BDAE4B93DDDD8516D71E3A2201AD80767EC7642BD83F FE59F12CE9E9725D2F16A19514CF3C37E55D4F1B55D704100F44A7DCBB150985C0B41C5978D8 61362D0CAE67D93852E7723CE2054CB35C8E8527B66583F5E66085D2549AD623DAA57EE4F87C D91166A62B7ACDC9756FAD46FEEA9DE7B9F1AA264B370931F0FCDBC0A01EE30751D35B1C9B48 0D75B50F2D770CD53E95B33021BFB741C0F9989623B2DC26D25130276C7273595C51D45CB2A5 88F8082FB71EAAAB2B0F4E4F109D04174F908EEB4E7514937CE4D15452E34CC1482FD01E9D76 F48E38A106666C2C4C8EFA44F2DA41EB072328AD35E76841E9462B3FF981072D3624D128BA02 E31E107E639FFFF66D0946941FBB8D352CE607CD22F3F47AB7D9D47E23591EB9B646431A97E0 57ED7110B0B871723C82C72385F31EE576B2607BE8E6BD76C498EFC0F915352A7E983B895463 1D80825E45B1B424003897885EA225822041CA50DDE48FE4D056F55E42F5553D451434654B52 E764E05AADA718D27EE62A9690B99D34F33A3F41A68BF89057D3F0EEC777EB18B772A30E9302 9BCE79A229F14DFF1E9B5536090DA9514F6FEAD6F6577A91A3EEB21C1B007146ABF97DA8A354 39D02191CCBC44F74256785A7E43BDF1AAB080ABA8A6EFCDA47311F8586B57560DDB45F37129 16B31E7D34AEA7BBB7080C7CFCAC0CA7C87C0A86B8E058885487D4799681F1E214C36CD0ED7F 7F0B5D22A4AA5F484764A4B3927E2DBA79E5B841522A6448959A811FAEF38172D5B7656C8CD7 5BB415870DAE6E39DDBD1D23541725E0FCCB9846ABBAE3D9522C812B83AC18ADFE7A823734BB BE7D225392A114AC57AC4E00C2F2F0D8D765FE59ED70A28E73DAF9DD689FCD17BFE3F966DCC0 F5344C13E59530A0265ACA05D35B0422BB7C2899BFBF119A0A88FFC02F9678B756E13D4581D2 83F6184085BF1C747A7104DC485FAE721315A0610B9FA9C60C7C251AE88BBB1CB92A47348CC6 1949B8E8F8E4BC40AE27CFCDA32B5018B8F40877172E8671589E01D315242C172AA36DC33B72 F75DE90E7474E258A08A28A9BD19443E046403A6FBAC095BE1BCC39DB87BAFF7E691B6AF2FE9 3230A79A143092FA422D33DA2140A77401B36755C36184BE3FCBB0BFB64A77D484C074F60BD8 5C559C11ADE1C640691140E9456149CFB924E56AD3D66435DA8A8117C69F695883AB4CFF1F81 AA03595492FB2258CF6AEA9E03923E66B3541EAF48837AD6BEA9C87E3E2C0E595F8E49C7D13E C3E1905264F30801417237B595A590D1C2558F29723E3B36F8D2AB4E2D20CF3219EFD724A535 2EA36EE67CBDCAEF7D46B01B64A4300D955223C2B33FC50D9644AE6B237BA265FAB4DBA097C4 FEF74EC1D8BB521C51EE63FAF679D8F372D94C1F3093910B58B7B3C5A93B40A15DFABEFC734E E926458C5E73EC989D935EB849CE575D5A17ABBEEA8FD7B3D49F4C83DB8844FEEC2C5C60682E B6031570381806F2A414419B843C4E0B75CB28C491F8B60FB5B8644C1AD42D5ACCEA0147DBF3 B1E150C46FB7B95F94C514046FE4956601DA026A52DDFA6D0113F573949FCD4F62B7A675B854 8458B7AFBDEC22E26B8F155A5A9C31730B382846B77622AF2D4EAE72D6ECB385625F3AEEC3CC 64E1B66AEB9B1746AD7330FCE8B307E864D19230F657C27F75CDB7812F0FD5E78A8A6F9CDC2B AB26EECF2D3340F9DF33A34A7B32A7A8E907DCCA44850E15F1660EE31C04A988D687146E86CB 3A4B844345B54B72B4D062DD563E6E22BA5FDE9281F92713086EF3D1AF48D1BEBFB7B42FE26C 6E24F30F799F28EBBC30CD85C4B3CBF12FE829F003477EAEC472062B3338503D4327B11C05C7 A8AC2834FDC1380E10DE3F424C2058546552089B1907BF835381D2B8A2927AFA677559B14BCC F4C568A7BA7814B67DC37A42596CBBADEB56C2DA7EDFCDF638FE426416F0689589DB462C6A5D 7E91CBA44238DC81634642BA73E243B713F7FD77016EB939C04D9CACED02B29114758ECA032C D1D30A641843A9B06DE72EEFE1368896E58732BF5B2716197D53C1DA1DAE6EC8E95BE8781E3F BD1DA59CAB4AF93852203AA9C93F86AAF64733AC3532CDCE6DD76F3C463BAF5DDBBD0B81D344 5CDD95A41F605B1AF09F6444A4B67E964C2B1C7E3D4527B6A85011829CEDB1011B66308229AA A48654E1692CD5FBD96420A5A0A54CF5DBEB71F17F9B33E5AB1EBD059E1BD9FCD3BA4E4CD30A C39531441869A8589960CBECCA2171AA7BD97F273514C02F3D765434A7076D37EFD76854B253 5AF55012BA722BF89BBC6CBF848FE74E61E712EB03CB935191121C7F45797788A01A97FE857E 5773ED8A59D53EB491ED7CB9C8F08A44B03C0F828DA18EA302B59E821A2769C0C75FD1A1E3E1 FDF244BDD85D64E43B9779B81C4478271FAB8AB12F9756B0BE42D5DA8E4F9723380458E873E5 8EDF603A17816277136D8695A68D7314F3E53FE156C8D3A4F28DB1812445E67F893832498673 BA67D28F09B4EBA6959A993EDA798FE05E46A3BA00C1A00F18C2683047EFD4255C5F2258733C 400E8E2008F43AA140078662117B806F6A168B142757176AACFFC982EB36463FCB102E67276D 8DB5F3A61D62D732D7EE339EA973E4448C25C88EC0FD166B9BDA5E18B9F489C85B246947E983 095ED7D30E2E8991E173BA6B0482DED2FBB7594CEEB54140E58C34A579F3CCC46A2653199604 A6EEDBFD6E9CDF78D8441C12F8722F10974ECBEC054509ED994BD0D6B0B3E3A0AE7418EEB9B0 13C99F32F9DD20F08C58290FE67F6CD333D5F53CA6133FB594B51A297DF560BCBA323FA14523 8CB47DDDE7745D419A6F42953044132978A241D8B1B548C5ECA5D1681A4A109466845BF9C130 500592DEFF93918E93F4962354731BA9A2E537B6069C1054776F20D786078FFD8E7F0A7558EE D62E1C92196E80C301FADF8610D09D83EF79F5DF6B0C7E5429D0ADE1C609FF1AC8DEDEF00EA7 FBC9D4DB5C57313BA9F9E1074E76A6AC0C0BD5CD7B423EB4A1E4895F5BB5C139E03B4D8E5B4A 3BE9C98613891BFC0369863AF0B7A3F16C2730FB4380F6DE7EBFACF42EA816A976C72006694C AF0CFCBC3619E3488F4D8A930A195C891423E1620F8CECC40494E77769C70EFFB696F3439E96 F0A7F9908402BB1D4A79E9432013F5A5954520869ABFB679606DA06969A4F995D0043E927801 5991D1BA7691B44F2E42ABAD1BC6091AC67BD4A575289F76AAE24C910481392AC2081865D0AA 81A737DFCC31E11F15AE2DA3F65BBAEB8365AAC2166FD30A5AED6F58604C084B7259B932994B 85F4C43D07B8B51B97752990D04EBD4C4E43B7880ADC4158FD8E27231B26AF71C5D337803F47 7C8F45FDFEDD5DFCA4BC02C4AA0CCE461F1C889BDA97771CC1F0AE8DA165D5F1244D364C9A92 D6F509FBBBDA28A2FE9596A175C1017323915D753CBF4B0F916C16D28864DD8A8241991CAA5B 231F8BEFE7D1FE1332D4BB3CD66790CDD66B0B8DBE8D7CCDB8FEBCBD3446E4AE4BCA759D8D69 64457C5EB9136911A80022E96DD20CE7B8028215D79B831DFDA6F65537246F56AC19E9E3AFD4 E526B59E48E51F3E9E64BD3079CD3BA7AD0018D4B6C8DF2F00319312452209947188D575EE41 6D8F7E4B1D4ABB75D5F4CCB141624B12007D415C4D18B6A673E194DECB2BF1DFEC5A4F5CC1E9 FC6B179A37B239FAAF9A71CEECC5C57532CF57181C1E7F375B4E18EDFEEAAAE5EA1E2D9CBF26 D789048EB0E8A9AECAC59DE58258ADAAEC756850C12415196DBB828D7DD9F3A906FFC52DEB8D 3B23DE786F024BD9C40F9C58BF9D6C669F43E4A9078951D4BCDDB2CF7BAD6A2BCCA47B215846 35ECBEFA51B7A261935D17D6EBB454B48FECE0F3EA3A8FFCFB757D180781471F24DC80FB2992 51BF6D0E41E1AEDE304943A89803736485FF808D98937A1FAB46AD17EFE94848365C0BCECBB3 E1BAB1287E537BD166C0DCDFEE7B509A364FEB6BB3A3BA748281CB949653C676071B54690FC9 1390AC12CEDF2B9603FC1EA902CD89ECDBD57AE164FC341DFC38F3964F15B63A5E8B666E1803 8D6B93B7C24E65C82C9CC2A253EB9F975CFC227B6DCA80D77A473BCB812191A826B699FA28A4 CB6758CB385D88542B64F26C01E2727D9660DC37C7A44ADBDCA9F1B0C8C76E508A87659ECEDD 4CABED3C1DF20ED033B119DA1A91606FF725D4D73A38A8C0B44B4CC53C6A70794C22D63D7DED FEC693F4374766303C29128722CF195AAB86BE58A9BEF7495692FB6BC528882F63AE9FE3A153 F23CE5F4CF0A371C102F2E980391E504837671AC7857D1AD505C29B60CB2D88A833F542FE607 363E3125DEBA2088D697D9961B1488A22404D73049B19D90A697CE02BAF3BD2C0077A71B15C9 6D5FA22C815DC4C25978F3873BE805F69D9D1C2B337CAC808BB1F8C32AB5085BD4959852F9F5 7C0EA3C5E989FC483AF14F6E39354247548A09AA32D9BFDD9D9FB6DEC42242217DD73B4108C9 D47B6D27544D3DC92E00DC5FCFFBF829466345160FB29129FB395D8EC590E0655A89C2ADD203 4EA01AAEC90CBCA8038D2CA8B4C5F4247C918379C00C7F99620B00F54290D677CD8793ED6F2F B82255E970B14BF704C3EA59310E5483BA3564830CF7F4E70CE28763F78801FA8A18AE7A83D4 9EF16EA6206AD611919F285EA4E14F223C4F40E1BAF0538980DE9D68C65E0A226E39511EF690 61497F9805E1CCBED59AA1124FAFA8EE3DFD4FBF5F8DCB718B4AF88E1627E80D9EEDA5A8031B EAB89F28EECBDDDE0A85E1734EBA378C701E7AB5D802023C5A32854FD70F503A75C40650F44B 277AD2185149CAEB51C3AD04D50BA03885D07709399147ACBE525A38925E3878366C935D9482 A635211E3C7296B96AA447485767FDB35852D786826D3EBB9BE7BAF76A50F3CF220019A3D5A3 5E0B54EAC1CF3876EFDDE1E218E4234016B2DBB1A70E521E9A32CA3B3DDED1AF16A673716B22 4DADDE391C484F43B9DE6B96CBA03F03BC9A52CB2B9F56277C76A5ED5170D4895086C04B4BBE 97CE4EF93F599B3AF0E8FFBB1EBA45A07F752FA2AE997A3D9A57664B7668141CC8213ED2F7B5 F04D119C34FB2FADB40953DD4BA0936C2241443F6D353C7D64F723FAC645A189B789F8B18CBC 7D4C5382423B894D08AF70298883EDA6A309251C17B67F7CC5D83A44F410A948FEA3DB610547 AF8A28D4CD1D8E7A42BBBA7FD4610C372D1B2943ADC83E4E2C8A9BE8D5E1CF3B30137E7D38A2 A74614CA4E2CD7DEED7AA9BF2351C4465CD0CC2F78DED6C84EE4D71F0EC53CA9B0515FE66375 717E9AEDB2C49F19578566E4C3C95DA95E18BE73055EDF508DCF5B6A1FB414AFA486E7C4CFE8 5DDD518B068F27ED99ECC2D690626F04A4E1A7A33AE5763955991A023B78EB2ECA41C6945245 A48D40399AC799C8A8992EF69FE705AF9D1069A720EBE65DFDE46E1E8C599C7558FA6DCA4CFC EB620AD7F044DDB6E4437DE358DE669AAF3873B83DF068D187332735E3870BB95941D41CEEAC 1972DD0E11B08CE89CB0704F64E6015265DF13AF8B43620A53D84893E9DD25F71F4380191942 A3DFB0467835CC29A8B8C04D65BDFE9BA239BF469A3646A014E76B0D7B6AD3BB8EB80D7EF276 BE0D8F812D3A617C920BA7FA9D0CFD1C81E4ABE831638CDD28A065331008F3C85FAAFFF57737 D091503BF4C2932F6D40B3140312FE780DCB46A8871DD8414E5D54BB4E7C781B3BE1C35B54B3 B12A2156B29CC5CAFEE3BF0198B2407664676410401918505BDD29B6D369D98FF18A26C78CAD 9C6ED94F67DABB68ABB938FFA462B694070FD96627D0ADA7DC0748332ECD424FB258991CC8F0 698DE2D8D21DBA777A8E4A63C4C6FE680E42D99678D0314E5A2BE541AB96059C194CAAC8C526 3AB3F586E4B9D27C00AF372940C71F7B6F28366F04F0BB4195F1FC96A5D37CA226EE2E1815AF E24D238FA664DADC051790C3718F7B1E2CAC29413729ED3B3486B1250FB837EB2383D7205E42 249BA65165812181BECC4B6BFF113098E507B2E0E163605ED91FD4298728512EF81A91E2D31C 17EE6FB7A38E6DE02601572BEBA27ECA7DB2561CB555D0299505980EE1BA0ACB2CD0F549A253 C0042B0ABFE55D8FFFCA5473E169995C76CCA4D78802932A1F56B0EEC11FB04C65F350C1A1D8 7207D43F173FE0F3224AA99BC75564D72C8EF325F37133EF2D989F6A93340ADEC5EDA5D7438C 2FE1885C69B01463B3EDD534871C0760DFCA487A2A8AAF24FAA9744B273BAAC1FA8283601964 75F67B7F91C1D78C58FA0A60F07B69F57CCC0EB097C7F533AD5A9D962DF80AB3A54EBA2B5444 5F7A70D2DAAF9110165A52D5777D20B4FEFA3F686558F146BEB33A4F5623407028A3E5E6F9A4 FCBA726423EAE9362EDF2C3F5292C0F2B795BFF8B2F94E52E7F110B805875A32CED3A5F572F8 92FD981036A6FD652914D776FCA43C7799532794346D19A452B935B8B06B1380E1203A64FE53 ED7744C2A6A863376A67204A29922868B3B2E3CFF62F72C22A60D2ECF4F8714260BB106454D3 86404F3CDC03BB4DC0F0ABA36440BCC98CE2F5617E38519EEF3C9B2C430A1F8AC9DDE867EE66 B2ECC80B3B73288490825C6CA91637A6FF06DCFCB31434309A55D62F1A030DA9BB75494E2669 F9DF957BEDE2296AB61EB70F3191E9315A6A6832D271C4867BF19AC92E262A32CB690159B237 989BD66C205601F106BE4DFE3687318FFFA635FB8C540B439A939C96647497E49E7CE8F05492 CE6D3DC037A7420D37905F59035940D212F43983E14624E4BFC180F247F42727FCBB199D067C 0C9E1E9EDAB62FB5F94922A0BADFD7A83FAC18E62DA9AA6EB5AAFC890EDC9DB8B0115CDCDF4F AB34BA416524AFE52055987BC6C4B0412346FD34FF47CFB7FDCAFDD834CC20D60E6D9749E051 6D466D48C02FB8000186D057D06800461DE8847A1E91C54CAC011B8BEC1F6E6EF93B78A3B6B1 CB6161869A66E3C79F7D640BA2A3F9EA1C177E4CE9F06AC82F8044DC37407C9876F3171A9A4B 0FC412481B119E07D299C39040299F921DA197C7EFC2E950C1E01CBBA30AB7E85CA275F0AB6B 601E7CA2FEBA664388F2F621F7934F1F8E1461B8C62290EAD4F240B77BA8DBD4705A6A0D5EF6 A7A2006950BEA0EE3AE5935D685D13D752CB9E90593A09B285F3D05E9B1A2CE7DAC25E800EC7 5EABF0F3D0B18758B01B6E7766DFA8A2ACB7CA64EFF9B42CF7FF05C7699A4C2A21870C24154F DBB17569DCCB80A46F49E9AA0A3CADD76B8B91FC1ED92BAF2B2731B1B6EEC11A3E4C25AEFF80 420B6563220ACF67E9300338CE73EC10691ED248A0BF68C542D8F0A10E4A7FE8D0F87F837385 A01B8ECB255778EBEEEA80F5EC231AD83EAE0B42DD2DDDBECE2EADBBB23BCE762F6046162BFF 2B31AD5706ED0AFC0CFBF544E5BA6A3AEC0E1B1A3A3DD8EC92438FA7B66E2F636276325317F8 D07461E29702FA530B9D872884A59770E91C3648727C48C014DC6ACF5CAF29C8C51458E48D75 B11FDE9442737CC49022E9C480B374D73AD2BB80D2E0DA1D27B523AB400D3E71E128FB2767B2 AFD6CC169B431E7EEF34F531E133275509E0B26E86BE9D352E953D677843CC691948F72A6DF8 DA2A86ACB3056CA1687944DF70D56A6851C48B97769A23786FD2238F20C40214AEBDB28FC280 E21464B562DEBFAD67C19FE6453B5C68B46E6E30E584BE3D14B52F929EFB458A3EEF2CE19F9B 46EEEFFC431DBA2C2439B76F50FC06FC78721430E0D5396081DE648772E33BADD4F610A69D0B C1C668EBBAF72F8EA0BD00026345F4FDC968E5875EB432E55FC577A4B7BA63EC22F29CF3F769 DDF52BFCC25773274E73278BB043B9E455493F061714483BE31DB24742FF79A16D3EDD938810 9174CAAD33734080C68F07CCC9C6D02A25FB2BE71DF035B2C34233E29DF1C2B662879FAFA519 9D1213904AA0D636517495FF44C668631C963C573A62A655D8885E7C204C50633E753B22A507 9408624EE8E5CD8AA7233FB1C0B7A9F5815B0FC4DA9690DEBF4B62B4A8C8D3B1A73F7900A197 9CFF959D1458FB70330784F7CE6C89C1BF7A2E3A526B2BB0CF629070587E923437C8AD6B2087 023B053E550B96F4E4CFEBA86228D4758C3D92AD83B92BFF979B6500A1A9790A43AEB39F8929 26ADA055A2A606F623A9DAB347C8C40EFC651C641F0BF8C3909F1FD57AF97683926251E5D1BE 9ACF6DB22CC8CB3C64411B3D4AE2A238041094F0F6E57CBD019E5F6B570CA3BB75EDA7F1B7F1 5167EA330C6408986712E5FC2250F337531020CFFBDC9AE8068EADC5DE84C58A836AEBA5B72F E723C6080963FB68A7C35A9F74D49CC0FFB493C372D2C2EB8369A16F6105B0CC6D583FB16AED 9A549242FED2E1A05C9A0805072D30090BC73D0118AC4060B4521B203735A1322F188496C731 3B695B76DAB8A9B367EDA4AA9EEEB88C2A70A32077DBF3558A3C17D9AD2E16027C6CFF034C9D 0D3C5C79B51A58F292C5491B920B52C20E52503A648089FA45881CD62C2C879257BCB3A0D641 6C90C7FB68E3A09966EE72EFE495370FFD97027367190A4652FF3E5C0BC13CFCD9CDA202EFD5 3AB998FD8C43444B4A9076B1D6AEEA18AE71DE2CA91FC127ABA54FB425C2884C085CF4E200C9 F71E971B6647889296F13E3AA3BECE4CC5E961D26E6119E653C82D42F4E2C236A945605C1707 F898908C2EA375F3A9679572145A46D042B993BA5EA446D643EAA1951A0F3612F356FEF1900E F5F5D6403F8026DBAE83C3954861712A65D1FA16DC6CADA9768017F9F3ECF2E3E2D8A7627CB6 CE22AACDBBF63C1B9E46E9A3E89099AD74AD15FD9E1A877C492E53D78B087C7665A61DE06CA9 3523B2A1187C67627A672B5D912D6CD0ABB9957030023844481E0D2C5BBA533FB353A38154E8 6D946CCECAC4196DD1B5B92BF12A2C300D1BF5720605E2699135EA920DC598817A17469E06A2 2E83963E63BC14E73F44DD19206CF5993F9C4C843445591736FFBADA86DDCD378231FC0299C3 3507750B7E72B4C704721FEFFBA0DA4B0C4BB998E747B12555C4FC2B023FBE7BC88441711217 D0667A54F6313D5384403F1E7FDAEDC6E124ED95A4CBAA5596B0F83B933D9EAE4BE1F16D6017 02477D3D37149BE811C05255FA058535C7D3C30943556EF80F701C8BDAFCDCEF9E520F94A2F9 2E4220C302B9D73090D3C0C76EF28BA3ADC22A409AF12BB9CF3BCA5240CA3D0E01DCFC9C0077 78CD0C08AB2D980910D8FD8D9B6135AECB85E7E3D9DFF94CA9D35FDE86FDF4324B64C8DCFC26 C45C3FD1821951D1F718196A6F04D3453C04BA54DA87A3372C916A062DB9367B2230A6078387 8D0A6500E0F970BD635B271D593F5CA3062DFECA8D84C6C3484D6C81C328058125E7A1E6ECF0 65D23D6DD253AF681F9F65EA166D0081E9E246977EDD32343B709ADC09E59F4D7679010618A8 7D2E57B588A8F7A2B9CBC564116E89C5D4665992039B1058B0BF6C6CF242D0BCC114E00272DE 5102DAC8818C2AC9395AE5A2D5EB6B5475330B512A867AB70F5E4DBA6377BE976F8D871C597C D686AE04F8915F5F80BFD24350C5AD541E7CF5DD63487CA0774C7FC32CDB31D0AA04600267C0 D04B36A37EEF5191CB3BF7F9522880C29C6F3EAF0367D755AF1C225E5E9F50F92538B2FD1DD9 890813676800BA9D5C8D0E70B12E37E12D7F29BEBD4F064746E35C4CE9F7D1561A4B8C06CDA6 D2E9B54ED377D9E0A6221CC68A9DBF62F39330CA8733FB17D13C091C15BFDEC842957E797B4E 75CB7854EDD3828685CF9E07DB73BBF90218E81B1D762FAFC02B8321B1FDF13B9BF7CF0D271E 974DB4CE5C4A4C62920DCFAFA4F94E39989E95BE3099529024F56586810D15E3A87FBE974B40 B2A3745869B05EE5DCCC67B609DCFECC5BE2CF76B0EA694AD9A96059545628497EBD8912B3C4 7EF28D8B6B416B4CEDF00363B7EBA4162FCB83D374507B12BBE968139E81D573DC13F231F09D 88105E74DF38D8D554D8582534DD2DB85CC9A9DCDF50F22CB355826DEE570808F83D0EB4E12E 2A852591D2DC7AD3FD27CFC9F07E62CE81D1822ADEE41E079D50B56E4833E440E81D834F8911 D0A280FC151FF2C4DB4712B02E21BD8367E235E6E7068DCCC01107BE26779B29EAC37C4CF88A ED153AF4B49DFA66AA329FADEB5616AA95C088C67E8B036472234454499F6B501017CC7C93BF 5DE2B77C10DC1A71AF3A87B5621CD3B4B8B1ED8B0795B4AB99DB0D27EC028FFE4A3028928646 7512D7484970754C3704C4F257855A61909FD4CB7332E4AD6DFCF9A974D90B97881F4E70E123 CF1E667671E84AFC65BD589F2A1AF684DDA0170CC1FD0F5516D1473A108B99278E809CBD4298 0451F32EB59E50733B28A8A4E041BD3737FCD25F4DD714CA4C2DB68779F98BEA34C3FDE2306F 21DE98FFA7A1527FA7617C0686C80538E4AC46BCE0B3E7D8729A0B8857E013D1505B2A55D035 218760542026294442952C03665CAB32CB9322D6C79CD4FCDD6D31730BDE2975BE9D2783A4FC D3F2C6DBF54A826C909B40348640BB25EDE171ECE465C1D7B6C6D17C2DAB439EFE8CAFFAB89B 89F8F53066F767EE18255E5774F88B154A43A968073FD1FB64AAC49518160C0B05B2262D2C99 8E2CA2CEB4A294C50F943E853183304B358049AF56574CB2FBE28B0AC1E8DD780C913745A56F 448B355180389A0A9A62F626DB7D38C8A539699919CE67399B1BFC15DF29D2D8AA50E0D44644 41E92B842C366BEFACDA602B4B759DBF677EFD370FCBD578C52073D18219515D624C2C63D4AC C9F73966FFD4C8B3475823A0C3B97D583AD5CF4DBD4AEE999CA42D537F85F65DA7B0D876B563 6A2A4D13D77455E822DB8F88743389648277E646849723C550189AD6CF2FF4533E4D33114582 CD51BC59D174E65142FF14FEBE70D5518A00491AB48B748AC0AE6936F4553C20EE2F6D209C88 74AB668C7033F1E1C8254250E3B4DF1EDCF3EC7B6D075F8C70A8B72F948390F72AD35AD08A61 BD812BDCCF2491120D4D965B537FBC6B99D050CC8B1DAD9677D08884097DB2271FD2CC8774A5 FE286A409D820DBB2010898933E8DC863822B0E0F3FDB6DE8FFFAC023D82CCB0C6DB6F0780A2 A8C9846559B12606316BEFA9674B5EF246550352C088051E01C9A5953573972757854B61D258 625396EE7C66BE55332E103F9BF2A02F5777CD2A1EA82E948BD4FD34F1C43379702BA518D13B 96D99368F0224512183237C8F32421001C5C7AD10E1EC8DD90533CC3A4FFCF5CC373A0595916 69CFD6BBFA2C7C2BE12373FE97617EF2D998C5F79A45C1BBA4CFBB7D57934AD9208D5A194DD6 0A66AA202413A873AB0D4DF9166D4C359635C3B928628D7EA3F528BFBB36053E91A38C3B6CBA 8E3C9A2694AA59DDE6809FF9B67FC851C18569772240555B88F76F88D4569A7027AFF1880FF9 2F9E66EE8F6557E839B84B80066A6621F218A09598B6163AACF18E94C557A5AF84BE82E607E0 472B37F9AF5EB036EC0F2E9CED8F54112C68B2F35A10DA0A1A19F5B987C32D296F1110283E63 A40035125F4671759449E1D7707C494A3302D24B0D0341D4B93071B800310D260988D9D12E4A E4B30C311012485F95C1C96F2204520FF5E60692B32770CA9F6506C27AA832E5A52E2B431D52 698DFD007260E81109B773CC3D32A30304B88983ACE94087C3ECCFB850F47545E3663CD7D26D 53E16C7F7461BAADC34C78352B493E213C63C86928E7CE586F1BE4F970BAC01A2B76B2CDBFFF 5179F1D660A1867944F5413808411926D4F177AE46C5AB5486C75159B7222C70F5237417792D 685F69828FEAC8970974EA5638D1A77BD25351FE5545B6A803AFE3118D70642CB3C8473319F2 0159B1B4C81386AAF3B377B17ED43C4FD1915C6A057552CCA798AE60E04B70D881423972F24F 6B721785F8A76C8979099EB306D6A134CEF9CE30CB6C401A17BB1A8598FC5D955A6CB7EF8DCE 9FCC30F1F36D18911DE67B9B32BFC15E565BBCAF91FE1F62518D50347076A38389A7F74AC4E8 6D6812542BBC2024BC06FCA0023D9C35BDAEFF10E48F59B2AEF959204919FE177067F2BADE4A BF760E8D52B98E5870C18F5318AEF9147B827D756ABC7C96A8422F4A85CC5F51C444F655506F A8F669ACCB56FC0EED8453DFC1FA87CD76F452FF2E603F915B8E0CB12CEE06D674A8CA98BA60 BCCA4E955C18FDDBF06F041F1EE76641AC9DE747D91239140A4B6D3B2ABF193B9BD65293B85D 89B22B376F1CCAFE615547AD920F9704F22DCD00328A17251A6020C0D7C405820B369974230C CFFEC1D551C56E351945E58BF6863E9D7EA8ADA9C9AF074E2953B46AE02DFC18BBB47185F77C A6DB42B4BDC70046D3799F156CBFFEBA41754CE047F15036FCBBA65F509587F6934BBAC1738D 91C380AFCCC3DE8CDBCB4D7897025F1C1B62984ED2EAD6A873071077BECD0A7D7BFEF7B70411 8D2289F8157D85148D6543FF6032154207B840B8810087AEA35458C087EE9E941DAF0BCDF13D 32EA1CC13A04742675F5C986EEAF8993698B91BD38995BDDB9FC7864C515D4513D9E08049BA9 832E00C18660C2869B711D67CD11023F8906756BA83B512D159B9FFA301806EB28445912E2B7 18941EFB598E36D6B07CC0D6BE507DCD532FC2A261763A79C33B81CDC8D358F42550AED3BC6A 81B5AF1E8071F4C7467B74A4C9E4F34AAE28A3936798BF23FE0A01AF575C33DE07D33005BE56 51AFC11CDC5BFD3AF1794B70B2F1C35AED1E40EA954591A5C6A32A36F482A5939325113B28F2 18801A05BA5D7DD648BC78B1391B77677F22A4398F03F8273F0EFCCFEC1F3440C14671AB8E3A 7330D4CC2C9ECEF017095BBBE52E22CF056EF848E4528408FFABF3B6A777800A024C734F3625 2890F86DCD9D72D072608C157B4B188B8E86124613AFBC3F70A84B05C2D0B5CC1F3CBC0E62CB 98378349CAF187D71931130F0339574D25C6FADED7B44C30AB4428B536EF30E6F7D9CBDCF177 8E00171439AEF7894557D081584D24FFAA9A698ABFBE40A686B4DF85AE8E01D3017F8E44F4AC 0BAF459FF45055114EF642D902326EEC7918390B0F8CA10652605A805D21AC343A6F9124BB8B 30F6B7B4600E02E456D81AFD3C8B4BAB813BE21FD2E4A932CE37B4109D4334625D91E8117770 44C814279028167E979F46646B44F88E8D58335976D91ED7C17EAAFD2701B9791AED67FFE56E 168EC718CE363E7E63BFFDB98032FE540A455026461FFEA48A6ADEB93A30A33579069B3F85DA 18F4A36F564E8068EE58A2ACA1C2E6F980BEACE7495EF9912C735C71EB19E2D21647207578BD 81EC47B56A525CFD49121DC368165C78EB37A779557331BD714F018027894D80A2190B9CFBB2 E6C8BFC28134F8E1B5D6B81A98011D70CAB2029348991AAD30486C01C7066DB51ECC80B94540 B25A647A0DD86DA63907F740EC2E28E8EDEEEFBD06F0400DD8FB4804C5508FEBA5D24E67027A D9B00B5540560ACA90E7CD4059FEB0513C521668481F4F4D47F2DCCE610C47D4E1055FF2A0F4 08E8BE66798DAA1DC1533E3A8029435E62BE7368958BCD21464A688C330E85F652721E78D51F AA848627A6A4EC77AC2D4A7946E8079EFD34348301F49C7789941533287ECC7C48510AF957FB 8EEB9A908E963FAB3DA2B86D6B27F8C71713293CBE50A638B37D17F5D7F068B37F5B0F08C330 82B72B87986853337AC95E6E52EAE193AFB60088ADBB6E70ADC42C370B34290D1F82C226B855 69DB49EA39AD5B71957DE01E17E00D9084E9CA01845C0DDCD69127ECDE5519B6C712FC1D565C 3F3517B72BEF40736FE26010DAD917BBB9152557056C018A646B73EE74D805526FC0EE9B199E 040C3AE0330D92CB168541743C10455CABE8BD38342261872583D867E5BD74EF352B90BBE40B AE4F8207CFFBD65E1A8498ECB1CD55646CA1B2A9CA354EC38A15E53618A26980E652685EA67C F289956D2A4221372143FB29F835484FB2D817EE2D910A9F56079238E00B72E4218E1AFAF670 B347AABF87E5E38DE871C0BE5F23255358675C139DCAAE9D885EC1BA4471F4BCF3F1B9794E88 EE0DD0DD68370A510E50551D7E519EEFBBA62901E290E60439D162010192936B7CCE6F6E5125 6204DBBCFA9589A9B0AA7AF3E62573962A3714AC5B78747BB83B5046541E58A25948B6CB2CC6 0B0111148C49C1546A834C42CC910361986EB9F93DBC4D1B273EEF819B806F29E8FEBB91381F 94DF1906CA7D92BA2CB685D6DF4AF67F4C4A3461500D2A5B962630755B0343140C5AC3FC75C8 13105489B5523E80999CAD4F64322BD555A9C06F7BB447E2656C620F7FC4D381E2B8E2A67416 66623F9ECB5E0A7C15219234581ED24A21B5EEA120C167E96C316B8D72D2A92C93E455734E2B 98B0E37B59DD325FEC1994F84DCA5F0050C74D92E0AFD6A31A2DF2364E73AB2B54117C08EF46 842AE3207C3B70E88023AA7D0DEA7917D1C928252DFB1B09EE673D34E4BD4F7338A44627F7F5 F6F3914A6574A0709D0E9DF55ADE798B7239EF442798C4FBCC06289735722D2B219D889E2A6F ED824AC4CB429622E1B944E4E22987496FC86D7E9A74D70FCC368D3196BFB9F5FA512F74FE70 A3A9CC7653908A03777BF1D288D3F69281C9986C0B3A1C422533EC92394842AC60DAD1490F65 8D336F9CA9F1B7CA9E6F2F192148BF6F91794249A5CFC71E55725061C7ED18A48BEED9BDAB6B 57FC85EEEEF6F411D78EF75DE6CF77BEF012C45F22D420773E5FA5FF3E4B83015F3BBE352DDB F78B946A363D1C58B2AE353BA3DB66CC7F56A9DDE6BC979A2A884257FFDBB136CD8300B53D83 7D80D48F1A733FA5F519F8DF0A08009D0C5F99B1BE2273DDA102D1AED76D304A58FDE17F13C2 8FB7DD802687A8ED5D6C06CF3EE7CC0CA88A927845E4CABF5E0225A76B3BCEED4C2C56107605 DD4B9C118F8B2F7C00A4767FE7264D94127A5833C659433D9853C3FEF19E7656D36A76F44194 6547C3869E3C07F9B7BE373E12EE066619AEDAB6F43A3B55AA8AD8227EB1B4B8CAA4C8CA5110 858B30FFAC05BA4EAD421FE31B88DD09E2857F7C193581E6D287FC465E76559807B7043BB999 34F4D6779CEF1B87D6E5EF4A76C5E9130C29F418A2EE9AFC4CC2CCEE9279DC5E78C7A37DA5D0 0338A74CF5F43C73199ACA7150067A48249D79D3859DC624CD173208B7AA805B0AF7E3D77B34 9AD914385AB9A33AC7A6B7A46686F64A206C9D0089DA1B5F14E88C37FB21A0963F6064E4611B 96DDBE66EEA0A7C635AC16F1FDB158066DB65F7E6E195978DDF7B9DBD93ADCA33FFB67A90B66 89FAC7272DA97CEB6EBD380AF79D9CED6915FA9DE1C8F7E1CC9E2485ACCA3AEFC46EEE1A940F 2BFC0B97BEBE096872F179F62C2127BBF731896A51A04A17546D73AD8A6800E2E1E25A56675A 5BD7113F694DD3C2B9144F689A7245D0662C9810AEA97E0986F24892CD4FA2590A44FC0289DA B6883DC7E5A3FB476B457F83600710D9A9C6D02F6BDCCE009CED18DC4802EBD65E3B3BB7D4D0 AE73DCBA19476DE12527F2A91E2E0F3638540E2CD439E8363BFDCC202B0AA7003F575EEA6AB2 75D6347F8CAC6A46E3BE50360914888388337BB6836F5C364F923D5AEE67537831FA56457547 B48D3D5358A771004A8520A66CC14F24D84FFFFFA452963EB9320ACC3AC91A552690CB2C5CE3 A85B5BDDA8D98931E02C69185DABCA4F81D7CF58FF5DD31CBA75ACEA8D8F1085DC984D9AB9E2 0883A457C2A5331FD4FD5F7E17FB35FCF243E223A7B60499C99A00C5258021CD495A1E7296FF 0D2D082D42094C166EA832099339630881E218B555D8BF2661BCF41A27FE97B33C2E1A0317F1 D93C09BB3BC20DAEC46463D374546DD7824FEB6CF4A64087F80622DADC9804AED6707DC67AD0 AC1B30F4B0EE17A028C46D112F9E16F456211F8C21DFC4A197B16B9DC8741A6423B5D861192A 5FFA4B1ADC0EEB8CEAA21F4867E4E49824E638B052406040DEE67B2BA6312C2DE83BA17CED51 65FA30F2B34590DD5340705C8EE41CC3C592587F4FF95ACBD451510F3076699107A067BFCB85 AC77D80E928BC043E65C1D2E085D17280A4F7FAD5CECA74BAF6CA8991A90FAE70DF9E5AD27F3 8A773A1BFB78BE07113884AF0A09E896C54C42B41267D3D5CBDF2179B7D05EEC35E5DA9F9D6E D05735F16AFA7B8290B2A2088A8BC8F2808A2E601382B9C2127F1BA0B9916045747993F0C92D B542A4FE31A74C3E4AE074F92BB1E828BFCACFBD7A46BDD1A64E8D9D976E348897BA5FD84640 211A28C3D9960B948A2B1EE9560F2B399E41E0B0C54BC3BF880830DAB105C56E7837F89320E7 10AE7FC05256E5E70875CA4648B5ED67787FB1C24804389950C28EB7B1BCC922B5DEEEBB94FA 1BE0BA3324CF95764C2FB13EF20CDC3C9046EDD5E3D7CE15983D7127D9B0835B3546AD02B6EC 690AF4E54E8B17F0FC178E037E354D17467762B837611288F9AC543C04005E79803B4D804ABF 68EBB2BA44D2C762DA71E614F7545A1DE87AC789FD93855D920AD4BBD1ACD27AAFA5F3FE08D4 4EF8BEA457E58487EC6FA9BEC8C25F4CCA68E2C070139FC610D639099651EF1E2F77372AFFDA DA55CFE1E3ABD5BFF14738AB3035FCEF4FA7DACE79EA942499BF4B177DF06DD60F7CF6FE92F0 DA98E433D8AA773E6784220241BFC3F5CC3DC82183D2827CF0E240429FED566D8EFA32C5FE19 5CB88B933DA775502FF57D592173A0D24E15C4498FC321567DAC0C4B22861561FA6B95930E7C 429C869AF3758263AE8476444AFE52EB8763BB23C0A5A812C2874062ED7752C9C50F4CF3D315 85A9F2F1DA9D75B435C15C7E8C5FA71115452C699D7C7D11D3FD2FAF9FB4E20F96F39B319A9E 1E0F3E7336BAFADBF676F399C9A75D13159A2905B7F5E31A707EB833F8EE4442DA03ED80FAE0 AF2AF7F57FD700A3172504E2257CEDEAB4DA4EEE079EBDA6FC610F85399A80F74FE8CF772F42 E67E6606697F7B6C789D22C72DF61862F028B964DB3B3044641777D06ADED2BAB4F0F8C5D707 6175907A007EB4317E4766E6F2AC310FD4D0CDB962599D4171E48E9B9FC7D78B77602EC51265 627079AB66609899D250C9B5E33301450308CA0AAA70A841985981F0B12AC01CF739B7C6CB8A 1D6344184CA72D7F9A5E1DB94B872353AD8BE1D72E36C15D000E321EDF4B899709EF6A4C35EE 454262B63D555BDD32B01000B8C6F3912A8CE3DB7C3351EBE65245A78DDD8C77D6206ADA0F32 51D37ABB49368A5A4FA91D68A4DA3275FD9FE0123ACC017FD6E89A36E8C4FEE96CB5106DE457 CA3B44B3B52AF7BA773273E1B0FD745DDB287CA0616384B3B8FC8AEC3A9B900F8F0D37F9A6A4 DCFFB4CADDAEF7025244B622CF4A237B7BA49A0EE3B41D7B66DECB8017279D8569F9E5C4F4F8 4A5B8C80976FD8DA3BAD1A8B426ED7EA299AF0E761A8E4D5D273E61B1217BC14CC7D55C20A9A 19FB1AC1CD47FC7D45D85548A9856634094A814D2D96352783A8E9633B2FC45EC3710DCBABA2 A65A16EC34F5ABA221F6F0B6FFAB5BE886307EDCC05A0322A1A2FCCB1BCD1B650419F06C90CC 4CC05EBD269AF0CA49759C1B85406DEC0B594ADCDAB8A33DD48230DF93C15F209F8C4F4CE089 FC031B2BA6A3205A596F459A52938830E7A5693EED1B3B479579473E78309329569BE1B0E7FD 486B72F52D084AE936F59A98CD03AAB0703DCFA05073F2864F0E5E72801F3084A39799D9C8BE 580D43259711FD6B8252EAD8CC24791A6F3B8FA4514B9C01CC9DA37C10C7DBBC91D3B8CB53D0 C92ABD86DD16BBFBF344575DA3BE86D415DACA97A281DC657E783F838F6D40DF782AF3FB0B1C 692B8209F84476CC962807871CFEC07D24BE0DB2690017A8FD400AD5914F4F473BC2B71042B0 B172DB259BDFD8330D968EC9DFB842902419E4090F613D2476E7BC5A3E8C006DE2CF2E54E29D 53B1A065D5A7DDC7DC22A9B2B7535AE0EE1CA56214601498920FEF3E5CE1D1F321EDA290CE58 078E01F2296A345FB32E15FB452CD42C9C25F9513EEF35D604CC1E47ADD9F2C726D771D55B43 B079F88166D224CB150D459E59B478F566875AF92E80CB07BE80B693E9358A0E36E77356ECD8 B1DA13240C02BB370C4A96075ADC295834AFBA1BD74AB53C476F28E6AC7D597CF2CC716C58BC 92D5FBF696072508DB76A3AECE9B45D9D8C72783DF88F43E98F6D307AE518EA612DE8EFA61A4 E8518A5F2C31F17DC860FE3514A7100571CC9BF05309AB81D317F1D2A6008E223EA045F5DFD6 16E0FDADB5DD17929969ADAD1FAB246928351C7D4F9AE4324104065DFB3E48536D1658DF0638 C446217534037F601342BC1DC239DB63D8049E030FA9FBAF471CA3568214CE38D19008CAA834 60F51D50F0922838EBC7FBFF2D5562514A7A4693F865BB4DEE9024F03707D4D0610D1ECD1DEE A642D680AC9A6D14525AEF9A98E2CB1E17A8C45CBE0AA8A47A057A18D62E44807C5473B048C4 2522A14AECE3DC7775B805ECD60559C6FD0DA27C0FBC6282021895F4A3EF59C9EC3C4C0C1441 42A47B09001CA9D4356AF1301D3DF8C7A2401FF7D8A628E0F429A8AE351DD8E0C50980438F62 899040120998F4A7690FB2843260F71A1D764DD5B790539EFB88C9389668E71DEA8B8FBE0B9F 5B594EC7BF052FBAF43633821EC2B9B7E52D73EB8F104764D835128D9012DD1A949E2224FD09 06645276E097EB04DDB0390A3E79E0941365A24A68377B135D783328E5EC46F84291B36E0DAC C3DD74558EE652BBEECA9059454E22794E8D6FCF93940CA7E4F4952C4AD10C35E953B4986E66 EDBB77466BF03239DC1A01A2C41184946DCF60E068284713DD3D964762BCB58A7658E0D4181D 8D7A72F1CFE23FC2302AAA71C03D921E4A2F2324D97E19B7C6F74352A5C49293E819EFBB9243 346BC26740E472D7649B9EFCF4E1C3BCFC90BBAA8D06147044C017B3642310B17A9FC2CB825E C964E532DE75CD2BC37CA2A8D281BE7D88603005BD21706A530FF446A80E3B0E484D43044487 D16CB8B4182930F31B967760DD8B453C0D71CB5A45EFA634339806662683CD990754B54E8292 F70F2A09A06AC6817522A4DC69885007CE2FD18717F973F855F38B79369CF7F0BA790465BF3E 997AF50B6F5E486C96430F1ED59A83E079ACA43A6F315846109F457AFA26B570390DD15C9255 CC9FBADB58286FCAE12354E7F8C5010DA3AADC60F6984EFAD4075611D0DEFD5F5F2043EEB694 A7A500DA22188F9868837826BE5A762C73CC24B545A24DDE9FDD799AC6BF0D3E2EC2E9CC30C2 5B975E1EED99D4F9F3D1B6A2AA6B6504FCFA273AF1B2FEF5B8FBC6AD06F8EF01F262F664EEEC 1C05B4872832F55BE3F3B95A599197841F68F04FB1B3C6258EA5D87E33C68B6EC32B6A3AB7F7 78800C6F2B76EDC900CA6900FBE355B8E65CCFDD4BE56BBBDD5F112B515865CD20C297BD1214 999F272E96E83A40E56ED0F6ABB5EFC25CC6D74E0DB6C02D72741108AAF3EC7429769C432795 27FE20D669947DE4A257DC6ADA552C0BA018985FE493FC8D4D5B41FAAE51E0DF83382CE3EEAB D9F3742FB3F796C37B41F7BE4932A4E9A03E84152EA95CB6FC29F85D5EA7EDFFD7BEFBC9953A D60665707D55A8D55477961063F23B8701AF3330531875A48E88228FC014478EF756DA14327B BD7971CD4489015E39C8CD2AE6988CB81AD993AE94995F1CF7162B46678F71BE7EA163585A3B 11FE47C6013CEA210AC8CE590CDA41475E3B61C2854EFD59190B4E819F092C2E4062BE28A206 D086DF6EB29C26655E594DFC47EF872D878980A0DB181548EC9A5784B7A73C6EF38905A4352D E58D21F86ABB05D83E70EE3678141204F8EDC2A3908DF540DEFCDEBE1DF43B0A6D03C301D66B 8D3733D79410668AD3F2A59AB0748C4B467CBAFB5308DF268016D5015C314E981F16D101D2D9 11B5A9ED70B56D2C31653F7301AE015F54CC5F800BFBB536C2DA80CA2DF48ACA1DF7F586057C A4AF90E76378AF0A2CCAC5746E6B10BC16019D501289BB799D68A3A92B89BAB83469797F111A A357D01BD2B623524AD738ADB55E818243127CFF2A33C9B1400985A5E7AE14A702E3452F8E71 0F241F4D0B139176C799B373CBCAC14838DCEF8B174E7F675DD3E2688F46297023D84A361566 1EB93857E9B848881A94ED78DA985A5068CE4BD1187EEA3FAC10DE38FC3B6C8ECF2DDA03A0FF 79131577D4AFE99934A03C22CA30704EF981FFFA3EA894AD6699409F0EA09DDE6FABC3EC8DEB AE140CB66EE37331D20F2AB927E4283B8C767E10C4F340DBF1FE874C1A97B08BFD043CCC9B62 B1972BDFF67EBF7F3E3E45DAE0F22E6344CC1C89E9169D4F6C90F37740F5F76CA6306C16540D 4788469926B46236D22F62DE509565959550F9714EA9433D4704E27B81231B98798C0F888BFE BCA5D203CC480B92993FCB4ED21758D98146D6D54AF44DC8626EC46928EF941BB50483651893 B65C433759D2D0347B4219A61EAC415D880466B2D18FD91385ED688A7593F090608AEC4BFF5A 14FCF92AF9B3D1DFF5AD63F8617DC70539F2E142887DF3DD358DAD04C47E50E6EB0379C2A55F 730E70C019D4319F777F9F869BED86505D36D7EB23E568C659CB100D5486AFD3D28873E33E27 6014638C5F17D3A1F193353E251C1C619CE150FDDCD7506847C1FA251C3CD572E3F4E187A0AB 7625F02406F97A2F0B2EB917B31F499EC1D4B5A89E7B5C1DB6DE329F6126652C208C88C74C27 08FAE8800808CF465CE3FBD6C195728C093107C0E148D3035FD5822EA917B3C499F2BF1BEBCE 11AE998DE12845E6F500FC0D5DB06213AC2E5C581B73D50BB2E13D2E79344168D04CF4338634 05E9B1A75A21D4E0924BFA6BD675FF02FFDFC46E593ECB509BC78409C78CCA5317B499F1E654 2B94A75232B8A622DAA17FF41AAB7F469EE1750B43359A90DA3B2C6E7BA86E4752861EACF477 D0072C922DBCBFC452B5E1DB1A41778610E9AA58DBEB33FB649B2E33F8DE7B25F9BBD0E4D332 8031F8684094D1F0D581BE98C2042EA69C701BA70AD062EECD8DBF61644840E8C95D8A4234FC 1405D8D007C6E14D1A68E14B3F7D609855BCC1B40F1EA8C2B41E2C90D4FF7FAEE037FBA5B11D 073E1A61AB03D0F4BB19592B5524894F10F3B7F29B19803CD15B89C594A1A5B5FEEF7445A5E9 0DC3E39BDABF0A97963E2DF29BF8D9D4375F82284080F9DA5BE69810F211DDEE5352224B2025 1C3F8A55043A8FBBFE1E031CFD1D38DCB6C43588D92E58F739875F8E8C9194E5FC853DA1006A B74FABFA945E4F145E1EF3AC115D1FE242A3381530D171A5A932D881A1D060A64484AF6E8A44 430CC614D8750B3D12CD1576790A72BEBFF217D863BD3A3F1EF95EBDAE08FD3D5259C55E3B5E 89C14684B18833D86E5590165B43FDF869267CCCF305680124F25BCF086364046D03D2F869E1 F2AAE0B34D3CF7CDBE8BB1EBF1EC13C6DD91F459834F497F0CD23C90770655C1CD74A488B743 1B9F43CDA98ACD56592F3F3846A69512D114040A8086B4F5F068BB1908490EB22D4F8BFD033A D796EED2405C618D32F4D081476DF61A0D3A0CA91832E8B3C483E52D5C44D7512532D50F54C1 D1921748E58C7ED83854420D04B2718E0467B4BF0A0133B998723B12275EDB56B0A21C026F4F D2B028095E2FD904596285706FA970ED55A7073A08FFE87F5E063FE949B5CB379B2F7B5C7DA1 EA1977175FDE95CDF84123DCE6BCBBC5999CA4C61281109839429587BA0C76047F42F8ADF2DF 368EEF61E6C18DD432B7592C8F00B22C84EAA72CF9B13CF83DC48E9003499FEA6135B07D36C9 150F06178A79FD5BBD0960A8A0E729514DF63F4A6390FAFB12532070D75C75AB3EE9622CC919 D42AD3CCF3815C71B04C14966FD7416C9B7EE234E82F2E7184DDC489603B1D49CC85E86A7495 530F8C09B25442D242F9BBA6C47E97264DBE30B6213158D5E82B2FD86CAB00A53E83F53D7AC7 CD9E6B701D873A4555003CDFEB1D8B9A455EFBBD88E926299781888EB814D8B45EBA8A5C854F 17C03541E5B28C5399C922737C10DE4942DBEC96A4E803AA48D054BE1E9D9D75ABAB659B46C2 5E30BAC982EA3F1941F8753506A02076B26792144275F834221FE32C88A98E0266E3EDFDD08B 7BE24381069F7FA418343236EF117D207D9C999E8DC7E8BE5FC8D588FFB399191A6D060407B4 C94D30548435FD707155803D3981043484426F47028F0A551ED788463227586881256354209E 34208EF3315CDAC8291490C4C91037727D78E9EDCB2CD828BB161D17403B31AD5FB55A6BD1C7 A70800D0B252332F3D0F1AE764945A8BA4D5128FE48416FB2D8521D8774554006E75BB8149D2 792A24E264A445C138CAE70429F4115148FC46A64C1B1AA91035E5CAC7D56B94773E615382E1 FEE0EBA3C020228F1B1E903088A5B4CBACD287F60B7BC530F7E9024E1267B96DF8A0CEEDD429 A291F86F3117969AC46D6675D969A2C8392D00356FD2EEE67C5DBDC2896A290BE1E285342670 35170B245BD6677B670DBB926BB20F7E879A6F9AA49AF1B3CD57664DBCC19FC4E58772C4D284 E28E57346E44F5BB59E75FDFE66C68508EE98B87ACA3CE30C9B789B3E62AFAC20C45F143CCBA 978B7DE18085B6F1ADA0A33F119B09A7F051A1629CB8DB0EA094AC458863552BE4304A3A247F 43C5B0160C76FBF592C5A3319961305C1AF886A390267847D218ACD200948390C14A5B57B706 7915177734765739D8B4EBBFDE8253A1046DCA4E13F3A031A562E9B8BD88E5A4C848088B56B0 1EA525F94D32436087FA34C6EF4E5BDC32503A3C409A75E0DAD3148FB0AA6E913332D6ACEBD7 7C84DB1E4B110EC84109CAA6C4E9CEB0C18093F5E9BB96B6294B820C8B22AB831391F01231D5 2A8CA189D04E3329C94110EC07ECBBA15AAD2D50AA829BA960369723B6741278E39D9B7E9755 C7FA82C1E7117A1620B1502BB9B251782B7966F29D63CED01018741422D821A5D0FC4411DA57 9E7A47374CC143CA5AD4C9BCD2037BC993D94AFBA735523E4BF2488E36DDCD02B9B71AF3826B 58CFBB3D47247D7C560963DF43BDA8C9A1CF69571B29877F1210F13272AB725D27D3F5D0E4E9 7727A9A0E789484AE677A272F4A777AAD4263ACF572480892233A1DA23918B17D37EAC8FE8DA 16F52F1617EDB1AE936FB0037E0476D09FD278C556F9CFD899F41B8E1854D50457CB3CA6CA6B A8A964DDC0750432B59277F2982B9C19F6824A60ED7945C1C737914B75838D958D2FD8C6F8AA F6BBDFE6882891F91A2B441DA2D53082324D35FF12C7C4FD2698933654CF6A78FA370055B2AB 078086EBE0FB7A715DAEE6B202516B033567E9DE6CE9235C159C687A7039871CCD726CBFED14 43F99A8194340A84E529EEF8B6C423CF487045F3D4582D9335EC9394362E41FB2312315F737E 56F15AF4745C6A31E05AF56A7361E043EFAB8D5E219D292FB6512BFD552F2E378751ED4E90B5 453CFCD01E8BBD826E328B3D3F7943EC188EF170E2C0B3B5DAE662BFADAEBE50ABE0C3A7D605 0A3D978AADA8A23D1E65D280CE6649AA096704DC2206EE61CDC81E75E8B69D7A40FAF01519F3 831DBD268D116BE69D12D44EE05A6066930DA03890117CCFC9C2B324A93DE0E3B6AEE41990C5 D7760ACC6D3182EF6CA086D32EB717CB244E68EE027A4AD03CBAF40878342B8FCDFA4E866805 7912698691655E8581870BD730D941D662A88A9DA5202A368C9CB0BE0E8BC5984D3D54EA95D5 4A81FE8BE7C3F67223B985A28B35CAB59D28DA662DBA33C5FAAF5CDF8B5140343EF7A82C260F FBA07A7E905AC89452697690A5A121A199D2970F12E80341C295EFDD17D032A742A29FE30DA6 C2C44DC192630A57122D07A5196FBCD0EB56230971AF33AFFE68A833F583D634EFCA31FF46CF 4DA8DB9E7B4105E2029D2247FA0B575A881FBCD4C37D2E2F4AB7F7A51E1411EE00EDD0C754DA 938E017FA8E2F56297F7510E20BC275C569EEC62BEADEA90537CB47AF6F492C28F1A7D03D78C EB3A596E6D57C3D86B482D3EF2DCF352038DF4E9EC535E0536F5E75936810D3785A3439B2A28 8CCBEAC100768BBF846D0B8BC41F699703C47C15B26BCB542B007A34B4205AF6C7A7C7145258 D4C506D82AB9F04DEDDDACFEC874EA4947F65A9AB682E0C497EBDC0244B7D7C724C4A9BCDB29 173BF51A054C9046DBAAF2E681BF1426A8564F27299FC64E62A38CA5C757E422251F22FF16D9 823E0A5534076C8F12F586802F6C66A6E2BE16BA97963A521F9127DDBEE098C69DBA32488D44 C259B35C2E61AFF83817549CDEE368F7811DF262FC18BD60286622D2A4EA859B8860BF387A1E 95E0F7B72DB061F34671C902BA2803FBCDA7E06B26C00007153B1D89DCF4C71D2BC86BED5423 BF9661B41962038AFAA36424E74F319C5283A67EE3868BB8C73F9232B8FC8E31D1352A0213F4 03B1D157D6435D6509614C67DC0DAD5819DECAF98EF557931DF953A5662103C7A7F0A868657D C992E64AC488DC088B0CDF772DE91368B783FEC311BBB60F22BD0C7B4A7F7BED0F240F17F2AC 45A9A2E9F672A21DD41E4B075D54D4E80CFFBBD1DC391DD29107710F08EEBBC02E5A35B7C990 E78F686DDE2B2FAA499F285C4D8E7A10BC48663F30847145827173F9034E0E3D8E03635B1DC7 12573AD404EAF33A7A730B63BFC1D6F42429121EC13EA5D85A4D3DFA5488F4CE10E08F34EB83 C277291A1AF3B02625EA35E931EE4658E73C04A1FF4EA88662EE6C6105746B3FADCAC6FD670A FE2FACADB3480DAFEABA0A7F361DB527A073D01FC86AB5BE5FBD582783F3D26D1E0D44E1C577 CB63940BCACFE15570304F5518B4D9BEF913DD4255C76335723890F765847A3489F985B2E576 E078BB844F44572BB824E1865BC534572637E35625D4AC31B6AB5596E290D689874A3BE273C5 C1270478E7B925B08ED9E2E63233655625AF6A899BF73CD69903A27C8E06683AFED2E209D7E7 9D272344331267D189556BE3B62F0D2178E1505D20F916F12B5E0D80BB2E67467449ED1E20A1 EBB99DD097B651130C06E9284ECE3C91C5B8DE7B6DB935ACE4F9CA4560392893464DCFFDC463 537DDEFA8DAFE59C0C2C12C58D1E093817D36159B684EF38F45648119EA254BFEBB4DEF31286 9A8F296B5B3CF62538D1F38B9E1C273E1989F734E6F05A35269F082FAD95C5AEB719ADF7D99D D646C650A93D2FC8ED9A266C8AF3D49C0AD385674EDC63F7036CC5D02C088FEFB44C5E859E33 C5545E6C02178C69052C8E4DAD307D74873102339D631231F981A23725DC85A342D44BF632D1 6474F325A9308FD394DD9AEBED391D535B27C4D0FD2D147A4AA2932A19D832371080AB31299C 910A928694AEBDF4D966E0A1682CD98237D073C3DD6BC19F3E39D056154F763B45A6F192B7C9 71C60E6275F087C4A9C61D26DE070FB94450D8330847B826336A9B1056768643EF5CDAB3874A F8E64C01905981F1B61E3933FB844702B079622E17D958B64FE5D96E0B4DDD83D745E2AB1CFB 1786C07470474EC53339CEA8F0ECCF4B71ABCB0E578E9F0E9D760634708CEFA7EA5F7EBA4DC8 CD1C416F078756D6237409169AC9780BA8E6B6A29566C3C53BE9FDE79A78B471F05C9723F8F9 0DFB23158F7D3FBD767CBB437D85B1A825C1351108DFF112AA9749363175497638D4B9A2D8F4 34E56178925F00467E77245E1547CA9556579D202D7C94041D41E4DB05BCDCFE9F7483FAB1AA 8CCEE0BBD5AD3BDFA87640D0A4763718D1191BB487C9384841464993AECA21722558CBC1BFA1 E540C1D0FB477123281B2270ACF6207F2075A84C147DB4F45CD3B9AA97D9607D0DE09C4DACFD FFC9C889B31A211E8D6AB4967E68A90DE86212E23D7AA0266A5759C9D4165C98A4922ADCF6D8 209B82378A4175AC6B91A4EFBA924506F181F1917385C7A1AEC29501CC62473C225214028413 343CAC23EDD299D1627DE6E7CE9DE4B19104728A4876A0939E0DF5FD19D5DB6E8890DA1C259B 54BAFA5EDEC6E443732DF9B40594242C9862FE554C3D0869F7FF495DE0C192846A182C2E80B6 DA51CBDF5794B34978FB8BCD26CFCA6C46F5320F1AC0692FDCA4DEE5E4206841F46BE9BD1EAE 6C131ED3DBF52237120487C30CDAA32DDD8AFFC01E0CEEE85A7564CD3AD7386FF964C0544F62 6B924A1AD77A99C348FF7150F7896DFD839F6328E715BA33891CE00E8F469898F7AD75A626A0 D02C76EDA787D7B74E2C3EA9E018C4414FAD9732ACCC2386875298680D553E6DD873E8219E66 862DF3CBA71410374E6D7ACCCCC9C4CA389F96435064EF577DD391463D67F98789C42326A92C 758B017029538369BD530203A039E06167C536EF17500BCCEF386C77FA7BEEEEA2D87E9BD5A2 72ADD904E484E2D086D8CD6238F58B62FC39B7B53E64895FCE06A86DC2990151BE86D572E2FE E28F2C6DBBF43B6B3B76BD7BC543000BDFDEA65074309E291CEEF398C7755E73BB502C98DA18 8137CBF8984C341E55C498003CFECBFD0C63B2288FABC92EDBF7DB81A8A0785008C57517B36A 1D885BC80A684DF355077307A8AAC76FC9304279C6D96A130EBE61327D8D4A9BEDA3F944C528 A2C920FC7351DD7BEE534D57FD3D7429C1A245937A86F139FBE86BA87644502234204209FC6B A1CDD4213CE0C0F19B42B0E5BC4E97182C16069A852C75287AEEAEB719DCF15BBA17714CB534 060CC4AC13B4FA18122E5747F0EC59CF4BFDDBEDA2D802AD801D2AB1E148427AFA2DDD765C17 011FC1175FFD498AF19BDC51D4367AFD662FE538F244374FA7CF088D790523D5886F5A225955 9909E46A887C6B317A31618A4C7AF5C2512F83C7B4E9C441388F8216EE8AA2FB7B18D62E44E6 A37622153661F64C0E4AA570798BBA35187AFD393F384ED35DFD8D7CB9745FE36258AD50E5CE F99E364EE9440BABD3430230C6788C655871E034FCBE154D5859B78125017D08220D33BDE57A 0744FAD3F9EA4F70040F3A9BE483269B928600AA03CC0FB0EEDCD42731E06A2D7A95F1A8400000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMMI7 %!PS-AdobeFont-1.1: CMMI7 1.100 %%CreationDate: 1996 Jul 23 07:53:53 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.100) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMMI7) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /CMMI7 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 161 /Gamma put dup 162 /Delta put dup 163 /Theta put dup 164 /Lambda put dup 165 /Xi put dup 166 /Pi put dup 167 /Sigma put dup 168 /Upsilon put dup 169 /Phi put dup 170 /Psi put dup 173 /Omega put dup 174 /alpha put dup 175 /beta put dup 176 /gamma put dup 177 /delta put dup 178 /epsilon1 put dup 179 /zeta put dup 180 /eta put dup 181 /theta put dup 182 /iota put dup 183 /kappa put dup 184 /lambda put dup 185 /mu put dup 186 /nu put dup 187 /xi put dup 188 /pi put dup 189 /rho put dup 190 /sigma put dup 191 /tau put dup 192 /upsilon put dup 193 /phi put dup 194 /chi put dup 195 /psi put dup 196 /tie put dup 0 /Gamma put dup 1 /Delta put dup 2 /Theta put dup 3 /Lambda put dup 4 /Xi put dup 5 /Pi put dup 6 /Sigma put dup 7 /Upsilon put dup 8 /Phi put dup 9 /Psi put dup 10 /Omega put dup 11 /alpha put dup 12 /beta put dup 13 /gamma put dup 14 /delta put dup 15 /epsilon1 put dup 16 /zeta put dup 17 /eta put dup 18 /theta put dup 19 /iota put dup 20 /kappa put dup 21 /lambda put dup 22 /mu put dup 23 /nu put dup 24 /xi put dup 25 /pi put dup 26 /rho put dup 27 /sigma put dup 28 /tau put dup 29 /upsilon put dup 30 /phi put dup 31 /chi put dup 32 /psi put dup 33 /omega put dup 34 /epsilon put dup 35 /theta1 put dup 36 /pi1 put dup 37 /rho1 put dup 38 /sigma1 put dup 39 /phi1 put dup 40 /arrowlefttophalf put dup 41 /arrowleftbothalf put dup 42 /arrowrighttophalf put dup 43 /arrowrightbothalf put dup 44 /arrowhookleft put dup 45 /arrowhookright put dup 46 /triangleright put dup 47 /triangleleft put dup 48 /zerooldstyle put dup 49 /oneoldstyle put dup 50 /twooldstyle put dup 51 /threeoldstyle put dup 52 /fouroldstyle put dup 53 /fiveoldstyle put dup 54 /sixoldstyle put dup 55 /sevenoldstyle put dup 56 /eightoldstyle put dup 57 /nineoldstyle put dup 58 /period put dup 59 /comma put dup 60 /less put dup 61 /slash put dup 62 /greater put dup 63 /star put dup 64 /partialdiff put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /flat put dup 92 /natural put dup 93 /sharp put dup 94 /slurbelow put dup 95 /slurabove put dup 96 /lscript put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /dotlessi put dup 124 /dotlessj put dup 125 /weierstrass put dup 126 /vector put dup 127 /tie put dup 128 /psi put dup 160 /space put readonly def /FontBBox{0 -250 1171 750}readonly def /UniqueID 5087382 def currentdict end currentfile eexec 80347982AB3942D930E069A70D0D48311D725E830D1C76FBA12E12486E989C9874C2B527F092 5722787027F44470D484262C360CDFDDDF3657533A57BB16F73048BFBBFCB73A650484015441 FDC837ADD94AC8FBD2022E3EC8F115D4B4BB7B7F15388F22CC6198EFE768BD9FCEB3446EE4A8 DC27D6CD152485384EF5F59381FFDA43F2D20C8FB08AA27AB2015B774DB10DACFDCD33E60F17 8C461553146AB427BDD7DA12534BA078AD3D780414930F01BDAAE649990604A33AA9EAFFBE5B 5489E5C7C9FF9D9BE01B08220832C41CAAC64816B53BBC087AE4B621D2B44B21AE5E3F7FE4DD B05C675ABFE30510EEE4A7C874BB57B2FFE521A6875EDDFDFD18C78125BFCA5A097AAD361DD9 4DF46F14026C25EA988194899B95001209CB7009CEAD4B4EA03473EA120E7A7E341D4E392679 6347FDB3A124C29660AC09F4648B313CB58E824884382F24CE08D2EDC686923ACACE1201C16A 07A42803288CD0B946F7546510E95B1FA1CC96F0BF72AA823D8E83D7C68C752C82A54C752EED 2B1E699DE9DB1830272FFBF2F4996CCC2D6FE2AE272798989525EF3B67B0D09BFFCEF749A805 E5F76578222B9C4A8A09B13189A16AB746DDEF7875F1ECF83E568F493D82FF729BAA1E0834DB EC30A35D3C49C9B10C5E1D90C6E3C8FB737DF5CEB3299D960FB79632F91F257753B4D2E34E3F 54A26C7B950981FB7FE4DEE3315DB63E75B024B4D318BAEC8AAC9CDE186F6D65767DF1DBA351 24287C2E805BC660A3A227720AE4FA097F1D75107441C0A0FBB9EEC17D5516FA03B98756B7DF 7AC7EFF9C7A2364B9F691ED5CB692DFFF9DD80C761E9C4D5D6061782B327302C053CE1CD09BA 0605EBF761CF9B730524E1994E7DFAA956799D522EC53D5ACBA27A35C4D28279617771938ECE 58C5AB664AA00C1BC4EFBA2D15504247A68E3AF0F9BD59A12AC1D8764421DFEF5DFA13FBEE58 F5ECD4DEEB4CDA9FE9483C229AB29460B05559B035C73D6B88F6A384DE0E2DFAE4B1886F91E5 22D800B0AD40EAE57F680490FEA4A2EDA9F8F57AEA1A4315674BE45989C2293362DFBD0B5D90 A523A7B79DE04D6F7B9FFA9F9FF2F2F7A1645E6B6E199C88C8430208A7DF1F8F8839769A44B3 922B18294062582DFB8EB65D087635F1B602EFBD5AA1D63676616822AC40947E58D449F32261 43EFD388F810DB12077F5CBBD8D6CFEE0AD3EF2426BDD29BC2CFF5EF597390C78AE61291499B 076F95738E231EF838D1B7A8B67849CF0841EED6D31BFBCADA8BA9AE383F9C003F51EDA24EF1 EFEEC12CFDC7162781419BB65E62E3F68C7DB49F83D77ACB20C133BB4DA5194910855BFAB3BE B389D848D0C802AAE7856679DF31113FE859B64128FD104AE04F652EF18E8B3860E444BA0BC0 5DCC11227E2E578543477D34BD8EDD99F20E36A868A7B327AFDA18A903CD24C4DBE23FF7EF75 3527360098A9C4F73D5AAF334CD804BEBEB6BE1E24CD7840E6B3CE1724887746E4B8BD8ED0AC 5A6B573CED9C408B10A7BD1E457AE16A401F411F42D2E57E35A2A07B13AF2E091BC8426E30F5 89B95BAB58F8D5DC2B9E9D34034F16AF06DDFD549660B9144B64406978299C0B964B9688ECDD B66D004141F9A3BEB9EF7C418E89545F573C18F43AA2E3200EF93F8286DF556B1C8282349FAC 4F351B7F3BA92F33095D9786CFB2F66CE46F120B88A6E836866DD0A05A4BE4C611E25D32ECA4 C1FA3F2BEC2CF153C405C5DC2C9ABA91DD456BFACB2D7025650549E454927FB7F07DC0F215B6 00CB7090428F4BCB4A495C6501CCF0E0F171D9DBC6C799F3709C8EF3FCAF30567524C2EF71FD 1ACDB1C804591117ABB9E8F9AB16A19704A1747185680CACB1375902F4ABB547B838B98BD230 305CD0CA05AF58F40BE1C7854484AEC18A52EDCFC12F893819B94160F128D47378FF286A5342 2D35A7E7DAB8C164D68AE0F5974940AEC4EC48E725BFAA307E24072CC76C4B0FDD453DDA6178 FEAAB21B218C02631D1B6414DCC7FE08C805096031078414CB221F826B646FECF3AE2EBEEA3C 98E76C10F529D4AC720A4CF71D0A3BDE7AFF506E5D4C0DEEB952B7735E91484152B3523FD49E D9B495D05F8582F69D3D4BCA0482E5D8CC77658C4D9DF370D7A24A26DAE2A8C7A6BC3521B575 C3650BFAAE6B5140F5C98CAE76790CBA4D805A5814513553679CB1309A01CB066F8E6AF2B451 B1C5074B8355D3B84614A8DBC11A56FE2AC39A88E3D604A58BAB849AEB9781D924D0E521DDF4 499D03D1085A5609E0721A21D513121F07E6EBC0E57815C45C7A525EC3751F5F0118B8F24271 D42F467E0A994FC9D6024365A117B761E1049E8EF91D3E25A9A9E46898C4AB239D3D6F5AA425 B03C5752B6554754F4D3240BD2A7A7CA6D3A2C7226935D1FBA7652624EADC4638CF8F61BE95A 885E653270983BBAB4A774FFADB13B16D527A64B3D083F0B289DE3A7568A53509CEC86CF26EA 4CA57E9AEB7673D9400F466F2B5D8D4889E82235A3580C84EE00761152DC80147CAD523627DB 104D48CD2560DDE3C951CF8828D4C9658728DF842AD3495B87522901B0EEB874D3025B66B3C7 152C7DD8AD7DABDDB48E1CF7A1ABA3AB060EEEEB7963DFD47DEBD1342D5AE8640C0724E32D0A B2A849AC822D94A0D19E7159B4C47CC9BEF85C10F1E068E722068BEA6EE0ACB161A8188CDF81 91A2D9328322B0DCB922D87917CB5787965EB171DB8CD153A55429E67AC86C9DAEE90A31CD54 FD8F04ACB4356B6F09AB70E917A8A9500D916EDFADDCE5884443A7F98CFCAA0FD2899C7BE11F 62AE8D2F22A10917242A6689C91067EA4C543A40EF28BEBC4A7BBA2E17C541F4CD655146639F F67F5A2D79A55172F95C7746B3A61FE1EBB8F78C5AD4A5EFC3166FF4F8223E514F48755F41E2 4082CBA63A7D0090694CB3D2DEB4E8C2309FF8FDC6BD1AEDD17DEA1AAF4932D26FBAF0EE9402 A20FCEE267B5AC223C6FEE0AA5357C054815402C7CF9AE808C2E391237A1B2A15A107B43BEFA 57471427F92EC4ABED182101EC1D04F130FB1BFF36A2A3C2BA6C4184F718CB1DD9E2069050C1 CA58FEF786ADE0A56CD63CB671B7B9BBBBA6114E6B6CF6A5BFCA204F32AAA3E3FAD926C0B5B2 17DD5FFE78628D3EEC531D24876778FE60B241C8E7ADBCFBA8FAA66119C7992A393A2EBC9B79 0702B1519EFC2D0BCC420405340BEF3FBA7C1CF3C3FA5E3435A0CDB6BD0F55BEEA0BC44FF7A5 7FD0A1101A23D9F7AA41B61DE857737A40B51B5CC1040FFE623B583490830E3A063A75776CB9 4FB88151644CA3D357CD1123F51FEAE5953E6800CF6F2237036D0E201305DEC392DCC534F9FE 32D8A2233A4879330449F9258C7928E6382FC11820D5174836F0BE85D2BE4BACC40BD7072A3A C18FA136BD08466131A10097C04E1A9B3C174A0353B1A6DF71FA5DF2EF683FB258F528ADD303 4D069782A349E85B38CA468795D0747ADBA2B53AEEBB0086212103352A6C9FF80B04C8B21B04 50535C8465D2C1DDE0A494D6D74BBBB2396C4E99DFBC258A2AED6C472436C532BD84F21CB4E7 8232DD65101AF1779D28ECC5F1A9EF7BE55CB653E495A76F52F696A5A4AE898409BB839CA6CC 5DA7DB458C5697CAFEEE7A0190F1F624DF24ADB4FEFDA30CC64538BC587CBA897063BE93CF28 D52C63789281071A96A1F03DAC3F963DE386DF25564B559ACA5630A13E92F31F3AC9B0FC2F9A AFE50BF45CB7E371DBAB0B278D813EE22B224B0E4D196A6B5123B270CA8BF5160605B75441B0 3D1E2599A96A969CDC46C84AA6D4B94736C933BB94110D54E28898D5D852C18C4E2A9F893EA1 F34F4720BA1F4DA9D653186F5772C62AA8A0B210BF9B97CCFB86C192468C46780D8D5813618F 2F7B6937A7B2169194709837D7CBD6B7F237C2E106889E18C9B8F38D40A3723D4D53E8DA3CAB D136FCDE420380C8CC497248B0CB524AFA387235D306AE8ACF8E3BBB7D1BF0CE7207B5748448 AA9B09761254458D55660C98607DF8A08755A37905EF8C526D3BB696946F1CA3AAF32F98EE55 F6F38402CAC8CD83BCE04B1A21ECD92D7769C0D0AC9CFF0B1104467D9C76673ECA72C3EF1B09 09D63EBA2D97657200008AD9D8276ED370D36CF17424CB75E2988AEAA7F6C50720316367B99F 576061F846C6EE85C8A1EC7ED22FC68DD7E1B99522E836BC05E2C4414B65C9E31921766A4A27 D4C6332FE5B0464B11142355E17D550D22B4D9E3D7D0DEF2EC84BBC7ABD3A5DB6F6F49A0100E 20834C749E3C4168CA8AEC82B91598D41C81AE19FCE226C5C88EE3E98D844A373938B7D5A687 E319058E4D1A52CA431ACC7157898141CC7FC4822B943D836994ACEAC450D54F41FEB4561566 C08649128C779606EFD07B2C3B6D20674D64F39348391DCD3792D214631FFDA96BCC01E45C23 9CD6E2BD911709E352A909731049118940F6005941C41827951BA7B38A4E9B10528ABFF2C285 209F7DECC4FD0CF1C26C5D77D7AD6790E73C67E17DE719788BB65D76FC0F61D0825882570C98 2981A3CC1604D5FCDCF01C879A75DAD33E1A8450C732130F2544666FF692A2DCA278E717B8EC BFB8CBAB26583C8DAF6CEB4F060022CA3C8468CEB05B1634E6DD6ED8F759561219AFBFCF1D8C 1DDF83D242B0CC3D9659834998D1DF8CBA0D53D562C923A3A956266C1BAD118C4C4578880D34 A6404074B4662AAC6AF2F4C9C8FF606B195397B15AD308202F29C6185037F21D69E6D81912F8 3AC57FD1355EC90BEAB3F554029F226D62D5F2E5FA1D9C5B25C60DCE792BE2FF2C0C73B14715 86CF73D0D8B98F94C1E16DC03042664BEBC5114E260EF1B9319A7AAA1FDFDA71A943FF198E9C 148DBA217C32061A458063B0BC8F2911C55F7CA3A67C01B834164A286665434F426DB71DFFFE 23DB26B272270586DDB6CE820A6B04FA8670543AA9438EDF32EE3442F531FADF4915663A3D97 D02D258BE79FE4634417DA41A4383FFE35C2C2C07DF7210C7B767901E61E385DFF7242AC3692 D1E779D6C98705EBE246AA0BC17CF8DA99DEE86F7CC7053BB106E357BEAE7C0AD2ADC064FA42 C43C6EAF3AADF274C06499BBE30C7DBD639DE124F66C61899FFF5926501CFD11D937FA2E3FA3 2A35B6D655D15081252DA57F0356601E9E359903B2321950DF082BCE3750219EF3F74EA1CAC9 27EDA9061A282CA1AAE219BA9BCB79C477C8D174BB42DA6C3E7CAECC2448B2E1017AD7487B0B 80413B2E7EC6DA2FF9EFD0B57A3194D8DA6AE765FD6C1E5362B2AC7B4E26C02FCA754DB2C24E 824E309FC6C3A0F5AE9C723FCF77061EEA4E12A6D404A52D61DBBD5E64BFD3C392887667BFA5 229EBBFBDE6A065376D3AB8E48314912061E7940122DDA2D8ADEE2F637389E5F03849C89D275 903379B0949D679322D20C7716AE258855A25499C0E7F0A1B052B0AB19E1FA6C378771140E59 F28A013704514620A82B871F2309337C20A87C064338982C7A1F2642D69A95F785034EE7AE11 CD4A74C949A0B8983796925C8DF349D4B49B7E146FB8EE5B3B23B1173CFFFE2558EB7F89711B D270E07B1A61861D88C8E9AFC9DEF32347CCE521B9EFA2006415B31036A049F382306D7730EC D3D9D3F62DFBCF80DA2163D2E035E8D8C31D17CDE364EE8E81ED8B30B432960DE8A3EEC96C91 54457847C5EC4DAF8FA56D6F9D09430505CB8550A0C29D37029AE2BC42958620381C0CAC3BD3 16BAFD21AE70C5BD9E549B1C2FF7A94C7A23E75CB9B905AFBF0DD06A61EFE5DB5155DDDA0D79 BB7D2A804FDBD05B318E189382A835A8E819B0E4E9B4BDB0FCA344D82D039F7A16C50F08C18A D54A48283CBA7DAED367A8DC96F7410CA0257DB97AD7793E6F93B78B4B09B14021B6BBE2CE10 5A953C4859B8801D360FCC57258F6FEFF09255E35E60B0466930A6710BA100EE7244CF3BFBC8 29760D839DF1991D92D7D0DA34A93DA112760ACFF209222B681BA175CD5DF809874DC8A98C7B BA686AF0398FD54AD253350DC339ADDCDCBF239695E2DD2694775F33077E6EB7D5A257AB9E3C EF0C8B3C135929BD902BE3A8E8852B1655E62FEA58788C754C91C68B65561C6289EC2379EF6D D790FDA02BA18FD0451C692478BE003CFB5BD998B0DAC2F73024D157C85C2F5B51A064BB0820 6E23C852E5D81211FA3BDF714E0CA86E3D1B3CC4C66A42E5C0B1FF5FCAB27AF94A254F38D549 C0367C820CCF98EAE3FA52C2DD950ABDD6550C2412B4113D9D101E6060DE5E5E68CB882909D0 2DBCE4F6807779FD42C8A46912DA217ECC4C6EC2887473EAF94F37D7568EDA0AC4AD08518898 133F5D41640070F7317C6A4317C40AE3B0F69319AEA335C8AD2FDF52416F52D3533BD91A4775 FA03B671BFD39B54D8139DBB44709A43F25B842362D44F8CC6BE96E456CF57DA2DEF7130BF64 8AF46DD07231672A2D00D8F5702BF62E3E433C395C3EF99039DAE91B672C7107324E4525E46A C12D1FEFA0A884972A009B7164EE40ABCE8385A2EE5B12CE41287D1AA8DE6B2AA14DFF5A75D9 7445CFCB9FD76F77D7E3971506C84813BF7A50D844DA7B2B7743343DDDDAC10DF8D6D7D05C3E 25FE99391452A4C5DBBA01A528A9D4DFE0D7F719E462DA00F847CC43C245CEFBB9F139A3AD02 5B680CC8ED2F6202F6F14E68722EF9B6728609F1EAE3DC10642FB721370A22779F4634E7B242 34A1E16B339D8745DD7B1666907788BAD4460F1BD54F5E66469305B47C7F01841D3F9F2CB0E0 C419DB5F4015C2709B293C8BE41E4BD5B0EF4EE0200928A2BE5969BF06E4A465E581F52D3337 4A239FD72FCEA7B042C338C96CD153AE2B08A34B17CCF8423E8D72314F59E01E57038544038D 9C66F75A5B647C5CECE9A50CFB704F89E21659034C466EE75D3EBDE216D1B483156E3D017C19 0A62B0DC71BC36AF006EB820D8BFB5351E31FDC5189906F6318A6516C537A59D6E8D409E0DE0 B65ED4DD6FD08242771B95EE667BB1C28BB88EB31B9F7CFBC8F7F07700C899F97DCBECEAE2C9 8932A37CE0B98A66C0C104B2D02DE706E3B65AB49524EED7817260DCA01374D0F39D109DF408 6E66836E9DCE633197AA137D5366386788145B4E5BB2D927AE3EA9B6272D8E1622C52ACD4BCD 6236445B6FEA218AB243542F30F3B9E6C2AA2D6DFFD4E31AC0E64F458C22BBE36076F8E07979 AF576C421C998B51549723132F628CF7CAE98387BABDC26D9C002DF3948704C8E2D1C9349403 514300F721923D77E666B0BE624BB143ADB96FBAD1E9DD6F26603422AB466962781E7BB6D8C0 C50760C278A4E34A9DE1529622F6046BA2D6A97EA2570A4CD2FF2EDBE77657C261706B9FF4FD 51E44F9A33D48C3A0D44BC0D74AF3B401337A522BF51631CB5E51032C54BF20A3A30E0441C8E A734EAFE35F779D1596388F6F0D2D5D9E9CB8A17D77AA09E51A72340A0C81C714B1E7C9FE566 87908C8B6D6473A51973FE65136053A839458D942358C750110006A283F1B2DF4D594384C9F9 1502ACD2B31D446B1E32FD6018D6E9B7E7C8DCE31DA48D14501A541009A187057568C53AC65F 03DEA75EC1DAB78C6AECA02E92F70874E622A18787197DF8ABD3A0FD77914C07FCA2126BC875 AC498046954417D378F3F65B87988940A5F794246CDDF774D5F61AE75E7CC012307CDF469002 D4DE10D80744628813341292B6AC4E09BA6DEFA1E35B12AF906C6E88756D2F3C71A5BA43C192 CB83ACE0C0EED73F58D4412A29C637A367FE1134BCE8F0314E08A180FA8EFF635BD95D1FFC32 2E612A53E553A42DB0F15FD3F18E2AFBAA5C6EF5FCDD21F147D6D27202A403A404E8975BBD51 53F93D40D2798CA821DC595A357E46D5AD79E8D93E63C8256CED66D3D51F26EDB47639B5EE4D 9D14B62454702006EA66B7D71430C141A3762CE8A7EC32CF95E3208F71F0A8513A4B40105735 C3E7B4E1BF87C274ED324CD2298269C1CCB8721828D5DBDE8C1875FBC4971BB6996BB5B26330 FCEBB91D9C0198175289D863788E98520EE1ECB6617187C5602CE415DE45CE10FF7B5A717D90 E1F28BE96AC8EE2DCED981F92B65FF2ED70EECD785B19B1E6DCC64CF7D58CCD13EECB4B076C4 B96B4A00945CAE7976FBFB514E253261AE3FA0135E1F03E9785421F5BD640578933FCFDDC878 71A9E6BC165950A16C6B04A99382B5F1991CD82069DF6A2F96D664D7FE270816069B8BAD8F12 366F1D8B5DCAE13C7DE3B67D192084E0B3B55F3EE17DB978E2E026A6E7C1FCE12718F4BD1ABA FFBBC6D30A33B9D2B2CB741D7771519D4886345DCFF867C54FE348E07AD817EBB996F937AED8 04721D91787D4935FE847342D7D40D676C1C7BE4CB2192C1B832FCB27B2054007626E9A055ED E0AB360EB5517739E2F756D416C962B8A7B27ED92DE3086A1CD05D5480023565190C50D2F9B2 587E17EE9DC38742E006452A47DCBCB97FD145DF15F9653699F73A808E454F05879924F2284C 32C8AB6C92F8C43EA57FE61FC6278E88E7B4B570673824657594EFC71A1E75B99528A3E21BD8 E91CA28D6581F44BF957F6C76215DB28B0CEF44D8589163D51FB364CBC32BD310EE9916A37FF 808B53003706FE45287F5DF47713F808DAAE009A7742BFAA871A6017DF5F992D43930FED29BC 3CBCA69E1BBBB8CDD51B5720984BF1788DCB4E665B880CAA22570DA5557D24E90E0753F7A347 455FB53CCD5FF9C550752C065E6C4018583E64B41FECD7E07CF3D0DE2D5225184B164E4973F6 54E53D8E612DE5B5AA61753111C068A5010AE29993C0B067E0463B99E1FE237D3326AF97134E 2A0492C8B99658D55F37CE1C62D6A6CE8AF7C3AE2F994FF005A30E1CF62A9901F6DB108D8F9A CF443FF4CB58C5E2C4394D615A8C3EC9591BCF0F46CD8BBB1F70FD4B64E3ADB8E84675C0C0B5 748538E47539DE8D02BB30975D994D6B05DC6C28844ED9885E75C82BCD560CFBE660694190F9 BD00B1BD35D7C25B59B7052BDB507E56ED6CEE98E465E9386F188EB74CD163BC0C0D9406133A E37001AFC76A33F3470A12B769C4A319AA846552F5EEF093EB25872F8C549A74A8D3E26FB9A4 ABD083F8A65A131BFF54DED0813B71EB7C9886C0567D426A380FF44D50BCE0C975DC0AFFC7C1 38A58A7CA3E4F232A38CC6512D7B1BF6B7264E05E7270D53E21F59C49BF648C0FAE043DA737B 354C2E92BBA6BB1683CF490178F57B08D638626983D2FDCFA8D114FA6FA28F8A1405C9A41D45 1E605FDAEDF968F9777454A27302C13B96851DB850DB6A239097716EE06D81BBC644D2BA61D5 32F3B574EB90B6270E23626D0F3DEAB38486275BE5A9C4D3C7824F015DB1599EFFD4301AE22A 6799EF9137CBE9601A7EEC49380B315558B701F51A5521584F234B4BB681C7AA7A35DE3CC104 D1535C4D0C6E6217BDC149278DDB0DC5345F25DAD168913938884F0F2F31CB757FBE1807AA32 542615C7EACBEF02A3C70B76B657A11B4010316F103AE914780CDB0D68FC2A1B77299881348A 2FFC7DDE814E33B8950D063A298234DD78858B5CD426CAE70D6BB3C2C2D68779BD65079A562B EEF0D0585F10AB144507B191BCC1378D6C39E9F9B8F690C59F13B541AFCA46CFDE1950BB0FB4 E1C875BC6D4E46885BABE609246ED831FEBF88391741EBC271A3FB1459B2FF188E8154E5B321 6F8D96EE12D66EE3A7EA92FC7A682C2A8A5CE1AD403972964994A7D875A8E4962B29B4213ADC 2A4226026441A0A78117CB1694843DAA734BB00F706231339EADFA57163AD47E2904B680390D 43A03DD66C809516F9E9BFF08FD1356D99906B51CD059A4CC42E000F6E716D6161D7F540B78B BFAA9B71F8D063714321457055D7FC5D2D6715F36CBD718843FC8A5BD2681FD78FAC8B2D569B 1C85324C49ECDB618FAA1D0D4A1ED480B790C8B91F5F41A94BB7D351659AD3C73208011D9815 ACC432455CA6FDE68617992FFF3ACBF624B115E2706C7B59E1AB14B07AD9CF6E133E96345823 ACB0DC9E741F6EFE209CB421C88D674106A5152ECDD39E7DD7E364285D303E3B3191A835AC98 B0085062C1B6F540C70B015E795A699F80BAABF2648916304D88F5CC6B227172B415A76FD97A 452A20666D041C65D582D8AF60623D39CD56AE8C2FE9248E847AF48ECE5B93B2CCFD44E40363 7344F1647A71EAE6DD93DB79E63F12F6D54E2F221A6FA3E989FDBB31A08B012B7D086F907F84 6F7B4DEFD5DD4280A8BF45C0EDE89FA2197ED7FBA823ECF0204DF48D16F68E3EA6816DAFECC2 0DBFED24D87D215F9E9D47FF9C74A6F4B001A0873F4E8FB1B44F55F88E0039921DAD5F00575E FB10C1D5416E4C6CEE87256ECB0144B8295D7750091B7A79477844B10A3121AA89217AA83AB5 404272772A3FA4018F99F6FCED80130685A59712E423BCDB1FA71BA74C144F05ECB997DAF87C 2A0E4FE7E89C0F9CA82DADE5EFBFC76F6EB7662B2AFF5C2999979F663594C662F932B8F520BB EA0B23EA1918BCD6593DD5AF3ECC2BC8C6A8134D2274553B362E54A3689BE99BE3AE7884CE27 D4026E0073324485B921AC1B3A0F4E4A043BA747EF458F75D4CCA667B082B167FC09B9157072 110F3642515E83CF4BEC4380EFACE753795DCC7D8329D1B87673C2D1F1F0D46C3E5196ABAC42 32A7A526EFDE90DCE45641BA9F0DC547B2E748FC576A663878262A5C25915D9E0E46EBC98A5B CBC2383A79D03D03B9F7EEFA1B96181A08B56C620335C5819F877C1B52A1AE83664B21AB566B 278F3E216686DE8E522BE3BAFA7BD2DC45A2BDB517CAB22789467C683F58F4175A75EF221A26 04E3CE73FA72986A6B6375A8F086E622B4042D285595295BC95CBCA06A89708F25BB050AE446 AE814DC984311AA296B4B637515B1BFDB076CBDA94830A04D7415E85648D8B9ACD75DB396171 D373234034DE22118A612585DFE90207E979BFC630F4C890FCD62C17ED5B05B42FC5F41590F0 E2719AC55205EB81EFEC0A0319CDBAEB8E593F857E6948BF7261638CD9C21B7937A11B8A1AD9 D4FE3220C03499438D0E95244C9B1A359DF497A2DAD2ABB1BCD68DE427D503A16D87B1CD1645 53907FA63B1B5CCEE5E811DAD3D459CDED21997521D566BFB63298030CC53E9D5FDBBA67A042 49DF56F382D9FB03EB8B40B1DDAFBD21A5E7801B130DF79C2BF3808EB24BDB2FE1A4125E1530 B4E4B3978FC020E63A210CC0C1026A9E6EA7DF7EB5903908A41B56F170327D7C48FBF64DEDD1 93427A89C5C9F5C781C00348BFC659D12A8185F6B7BEDE00D8189ED019703054B4B15C454CF7 15FBD38939E9F7695AD745C1D23BA54F5C3833973D5529F2EAF4AE74ABF9B1ECC83FF48A9096 5283A5D9C8C697542983EA09118C8FAB68781A477309A59420110F57437A58C51358226524F1 1D1F3204006BF38208F87977530E4C36F672E58DA728FE388E7F814AE2B3E4A26AA1735EDB14 525D7F262B8EFECBA8717B59A6DC2F0E36CEC8BC1D7262F1E30C7C5716588538E80638989E24 ECCDAAF151164DB4364E081A8ABB9031B11074B8F3A44E6301DAC07FE19D958C769D79D2F0EA 00B9D84FA77B29DA250D16B4D5A3592253C423089F5ABD0CBFECCE1493FA58ED14C6E4AA43ED 7CCA905B947D1CF8891508F43616207E8E262E3B35EA00DA7341FED19C19374E3236A4E226F3 201B21AD68E5A0AF6D936F62A10EFBD6583BA422D2F8DD3C90737483EC63167FBA9C0537E342 B9B5C6DC03627743B7D3ACFF22F1ECD4DEEB1F89A9C3ACDBB26B891647BB16B36F94BAE52D37 F0DE80F7BE722A3BBDC3BE6389994B5B340E2C5B3DDAA2B99F121B3FBAC51655940550DC8961 51507FC9BE0D67D6E328D669CD22E0AF20CA846F357A59D681272B27B20F88008F4D8B7DD915 8F793D05473E75F0302DFF1C0940098094F57EDD1B681548A4C075D0510F1B2B4EC5F058F6FF D08F8CD51084E9385802CBE514DBBC015F670B6BD587120ECB173821D4DA64027E6C4572A2F4 41408F6C8D12FA159ADCF5B821F7E51F3AEC9572D198CBB446B4D57849AA4353E36D298A5803 65BA8EF4CCA88BE9B6A1058521F568FD4E399193CAF25C5C7FD91E89E30CF7D715B89BC1556A 64D1E348EC0B3AF17AD16A1BDC34D8FEAE1579A234E29D60F0096FDBBAEAC408A38749F05B33 FE7D38F2A1E1C59190D57A6D8A53E1FD661D07AB5C9A486EFF8E4E3085A0DD5E5FDD9DFBE19C E102556E147E40F28F00A892099C985E6BC49B5ABE8819EC5FEBF2F51C832D4A573D42C60441 42D2EE269F4E9D00AF2738BE1DD308DAFD8C64ABADAC79A528B6D0503F4BE90DC7790CCA4254 8F6C0C8153F35609B24879B0E4E3D53204F70635BE2AEA09B036F9E8D66C9CE34C0A253770DA BF992CD0BC8279A7D539A92E41DCFFBB6E82D48F1550B7B4E110A2B3F2430AF3A497AF89EDDE 9D78F3223C2628C6542260F9D209D7B14DB949864A097109C2DD030BEB71D26259CFD522E3D9 0167C07BE5FA624758CE4F6DD2F9BB05168443CB519696BB16F9F0177F63E309CD75E160E2F4 60926409D732403C9712A2815A8D53205DFCF1EBD0CB482907813A793DEE8870950F1A2450D7 606E5723F258CD34DF9ECD540B508E368204B46D39D4555F284ADA22FA5C7C9287DFCDA89B13 96B0F0883C5DCB3A7380F304D08F1177AD30F9DF1C91AF24B826394322DD114F90D154A11B3C 0F9FEF7A51A7BBC056087CCE66E8A8CB29A3ED832D26AA06CF54E85AB63AF744DC1FBDFDAF20 77A90F0AC6C4FF9AC47669428BFF213FB8622BBBCD892E268066CDC314491DE3686E7D588928 02B0524121D17FE77090F443EBE624A9293D2D2A74667FDA7ED2F387FA8E13418A30A01E9847 79BF72E1D621B34075283A8F8AE7592C87CAC8617493D0743CAED9C4C060EC7C1D88523B4CE6 ADE8962B2F2DD1E82FEA8CE611FFF799F264A013C918460EAF914D5F850DBEBB4588D7C8B968 134DAE1A27FE61CF03717808E2D5540BC3B223925EB49F303498D212E9C7A019E53C914B29EF 1B43FE3A076D9BE60FB2C6A8DDDC9D6FD12CFD21DE244B29CD672F1CA62B23275E192BF26781 6228FAFFB7CBB4EA0F93B8D4A1E07534AB638AA0383C44375FB6A22ADE028DCADDC3AAC01BAD A612EF3E8F5DE6004E98611B434E44746596D4CB43F0383A4034110FE43BFEB0A5DE7E1EA7F2 32BD4DDB54BC3787D4C91D07D67B0AC954BFA577E3E4268D576AC9D33FD0FD4D3AC2A51C5BAD 0668D90D133E4A3E46176B082D51658F91F89EF3E66B165B1417C397F0BF48E6CB6FB1A4B012 1217810933D7D075D1F35E2845B5C13398B3F0E6A966944FF39C939272F727DDD57767340E58 663808AD9F02BE01A31D6B539FF8173AA32229DF1566969F3F0382AA4F226BC2A860BB0665FB 72A1C0999011A954465B22D6955A38C73897E164A6D5630885986D0C7D29E1EAC78600AF08F7 D05A18687E7DEC72A042353946192CAE73A88FC31A750BD93BF1BD0C86C24A11F44F91E8EA2E D77C8BA2642256FD9C683BF81C1BB2102893EC70DA0995734277A0703A568E34EB54C1EDE675 C76288B67FB8346D17E2DE408934F353638321A73AAA5813E287783ED58E340AA204E6FB5FC0 BD913120ADCD5EADCCE3E3096C61F701C6AFB367DDCC13413B91308A88A8A8DE428AD14F3607 0B6406E3C26CE69A6FAE90B3E8A0EE84F28CFE2BA9DDAC21A36EE300192564F79CE9C03B0523 126D10259D3A8EEC4B37A4F11484DB511E866D843A538114EC8F512D253B074345ACB36E67AB AA65677B230314B49B6C4FA12ABC501E327C89B4DD0116027E2C5E48D8B3F33BF0D27F19D418 50F39C38DC8C514668BBDB60CDE73747DF89BA7D8D10AD2F0104B6EB12CC112DD0DA279AA6F3 A5EA2D9FD41E1B98678E3B69F76544B305F976FFC56AAE5623BCBC7756F6933689ACB649C230 D2C78DDBC7D6D779A1D89BBD44F92F6E277CB8F5FB641B752BD720215694CE0BA83E54BEF683 CA62EACC7E418F5545CB1E029B364948A0C8E8FB312A3F7B54DBE83E54CA2D63021600590DA1 8211C41DC19A8AF58BEBC8EEC2AF347DD5712007E000884EB55F415E008A0ECB0ECE3B3BA8E5 A8CAE5182BB7338E6A430424BB4D1B02062C8E94AF9DAE00DB64BDE19A2718C562E164900971 7F3DB0FB1ACBE4FA7443BF4B20A127102201C92E6E2D4A63344D09E3479D7FD94F028AD24FDF D6FD1FD992CDC27823B44928CD8792F3978E8FFE8C0D23315D2C838D2E05FED03E9DA7AE6D59 0541DB2BD29406036921108D3C6EDEBE7C0EC057D65DB37918978D3293516E590A6D7A9CA3BD 66F7B10ED5278264A4CA4D42415438945FF57147B91144B8E8EE82FA591FBF042A74C6FAFA4C DFFA1920C0DB032385B9B4F53594EE261993A05EB151EBF14EEA59FEDD78922739E12BA5DA70 F5747D5303581BBE76CE1664919DA2884FE0E8E89026E32CF0236AE8046114DDAAD6F8629C64 1617C5B163E74F2CFF2033F9D6DF892343B6953043CF89FC1BB0F4B0D64466074DD5A81BAFF4 EEDFF51D46293A7DAFA72B6E31F2C14967E7D057D913F06D9272D2866B901B47CF40F75F671A 22E0F43247C4AA800B4798C11F76F665E2BE64043EE69A3F2DDBB8F89AEE571C2756DD2FEFE4 4DF6E45BCB7F4F559605B7C9330E7E927170A98DEAA26403C12E3AFC095A509FD30C2FA316AD B89B1CD05D47FD617CC9F9A1335DB9DC3B9A92D6B0470B94622094BE2E1E22A8E971F4F9E708 B01B320A541231BC90DE41490573C306BA8F89AE3FE673AD42CD0DF3EC0AF572FEECE6500871 F1E92B06368D1E19B8DEE85B06E66ABB8545B9B29C5C73AC08231A6BAEABCF21EB5922C537BA B5D41F9A1EDD103D372BAD0CA062EC7C911632638A23D9EE96F9B68493BEAC9BC88A1047E04B 4B3A33E9377CEAD6B5EB707AB027CC014C4B05A00CF426F55BF5245E892E09D1188E149B6865 B999C8EAC788B4A8BFCA633119ACD1590D4D832927AB7966DE03F0180C9CEAA14F46371DAB37 4ED73B825E861B322BAE154BD8481BFC9D5829065E131940B51BBE8B0B33D06715E0580F6DA1 C384F3F60CFEA43F69E0DD5733EB473FD82036C7A054FBDFFF5074139C44866DE8CCD767ACB4 A8327464ECA92C8F75A6599E1832C409CB5EFD85C87208F2550345A1C2E8992669B4BEDD209F 907FB9A22326EF8030275B20CB4A4EB7FFD98D4E338C8C41D1FAD8514835CE20723E363C27DE 0EDA33A3F32AD08B861E48AD006937F00E46E7161E5F85F80E2F48FDB21CAC82F2E1489BC26A 37D6A104BBF174C5565FD8A061A53A3ABEC8E81E3E37EF67658116525192C26D305BF79E90A1 7907CA6940F2B2E7393CEECD3F3C3541C95643112B429A347973941A01AA9E149B50D60E03A0 4F2600FF80CA302C0E370C04DE81FF68ACF0B59D5A4ECCD132AF4306FA61699E6850D0703607 727D5B25949FA6AD8221CCEA3D1E390D5886F170309C60898C9B003F962AA1BE0FC8238A404D 0637D030434C7FADABF2D02FC4BD1FAB8AEE4FA10533B290AB5395B4A0F08F7C782BD5F03570 2CF648ACA90899CBABD4AD56A79BC92674B259A6B316477F39D26E403C43A2F5A91EA95C338F 3987ED1D7A840F5614EBBF419980698689BC1E24C4342FEFD6FB14D69F0C6C79012A576C4355 2E9DD81A97598F6D7573B5FC5F51F1B20402D19C9CD69BC714A9780E0D6F860572170AEFBCF4 5DC7910D7C521DFEC01B4BFDB162AEF15E3947CAABD0E66420C04C35052CB9B32D3073EAA3D5 5D5BAE74F3740D24770B999593E407E656916F42648026E04B1E8630F54C4EC62176190C33FE E9FDC8A4FA1A814C0CDC5B1CB0CEF1F652ADF5981CC5C6A8FF1739983161363B2A6BA9805D0E E92CD6C55127C6278B160E11575859C6096842F318840F4681B9AD238DDCDA218795B33275CC A265BC912008C68A0159D81F8CD35DF7E58DEDC5EB003FB2C16F14BEA012B8C740782D1DE84C EC6958FC681E712AF7FC33F0AF557E21412D263689B9D49E958A172989D3FF71FB35953024B0 F8B8BD722407949AEA81E0D53C90A4C1B3646D37E1A71E7B00889C33641B554D906CC354286A 087A3E211510A0224309E75147C7157A04015C02CF9695D22D0B180441365BA1387A24D31868 80D66871D40768E8FB2052A90666AF0B9E2872C8C44842CE0CBEC9AAE4DF1531DEEB1C7F2C65 3AA57C2F7E0DB8788602E5CE3C2D2DC745D8441765672E12D4506414D39789FBA5B91D7294E5 A50F3B1D8DF64F708CDFB5CD6103704B02F6F3C80492DDC7091F852BD227692917E06D62B7AE E13F95469C5BEB35AADA001595A002B41507DE3EDB7FF56A4E2B4A3EFC448BCEA31304CF68D9 3CBDC17D91E7FE51C64E6A6B38AEFE42FFC967006067673AD1EC4F59B32ACCE3D59F4CB11DDD 62C73D949ACDD9306D8B971C8CC2C897B9579658F0691156C395BC5A8B0AC90145605577CAD6 94540A79C2A342D71C88A39733BD4810A694ACD1698B98C73F7C3DD6B4E3B77EFC6B201FA628 7BE234347178599F7422C74B835D738FEC17230F72A4D33642F9D7CA390262D421AF23CD4B5D 85B9586F1A4FE2EA9DDD499F0F2E83878BD6EAD423AF05D097F93BC0C7450095EE0D41E0B047 3BAFB45A85C9F67DF23A0BC418893B3AF8DA4293A28A215908E91C286C38E1222DFCCE6B1ED2 0C6542F999C684E82B1C4A85A225BAF7507F422D15FDE1B9E692F13F67E542146F26C06789FF 2BDBD31FA54399A771396E73AC5748C643AD11CC8A44F92EB44528164B36F7BE1DDF3AF3B01E 89565D3727A9B76693EE7B853E3EE973D4BF4B67F15A91F079328E256D621BC40CAC8D45A1E4 688ECCE084B4AD28D2A09AA786D23781D596EB5674C4ED7EB1A8F3B723AD7E4920A56AF442D2 1E655D96AAE2DD6C13FBB0B0226CCA4704FA3F13CBF0687F9120787CC67AD3904C9CF174438E 141CD25CC1CDCD19E34DB22E24AFEDBA474E3ECB522AEB2B88B163CD5F08E0526F6D21C3BAEB 7B9B2E8DC551B436715A85E6BF2AEEC33610DE5E2057C44E07F7B5F265FDD9661078C39760C5 366F8F355AA3EF6AEB9B7A66F008172B48747E879E939E519CA3F94A92727B8656B49020A6E1 C9165593C663C7CAD7EBD4CB976D15DE9061C10F689496D086FDEC88BC0F9173EDD29EEFEFCB BC8A4001D628D7DEB6C4872C6848BFE45FD5F3D169CAD993A845E0685AB409E3B791C4E4DAB6 57308C0324681D4DEDE6344F371573F65A63CF5E0490AE55FB0237490FB1F33AF81BF4AA9282 95E1FBBA88FCB736877447A31E862B56E5D6DE8EE550A25F3A149D91B3D74CD8FCC760B8E742 10CA81DDD825B0F7E087CB91F1AF6DE9D6FA25625A075707567CB99F59DA31B32CA83495F5BB F381C1646E2C1ECEDE44F5B09DA16E12789DE1A19AE16D6464B208D2DC878694A8C5AD4910E1 30A691EA8C5042873C7746CE511B0D65E901C3B058FE14A5C4BD0F9D9BF8187F3407E22FBFE8 DC9BCFF51A217DDD70E89D362199217B6E1C2BF517B560983FCBFC9890750E093F3503BB8173 33BA7982D8E67609D856D5634305CF767A0BC4AAC478D17112EDE04C0D4EE807C48A699FCFD7 113BBF5381ACFEB58F8569ACDD9CCBB4B576CCB3D20FD7617689F47CC47974365A8645DB6208 CD9F2F85D00262CDFD3D532A26B9104B968CCB3BDBA732CF7DA7112E2958F88ABAB5645099AD D84D5A8E9B57B12BFCAD31CD2B55E4E4C65798ACA0CA326CC2D83699DE3F8934D807DB584B42 3D74BE293D5D1DF8B058E05C3853C1987BEAF53D1C2C8934E1EE0C742D639ED41CC9EA625340 B889217C03283DD930F0FE28B32E1200814DACEAE5636F9D822C1481A99C223F071A0D52ECC4 3CB4C9011A21A9E41F24FE2A3C621CBBF82087BDA5BCA81C45064DF7ED8545929240A8D1E89D F968F5B99FBBF8AEFDA604FBEB49474F89BFAC7809F03F43B2084997C45A1915933D4B63BFE4 DCE15228D327162E2487D394B31A187CB52CD3E6E4977FA03654A66643B179FF867252ECC23B 3B47C44B4F44D3BC2F45DB57F0EEE856BD7B9D44696ECE793DEDA96EF82C569D98A3709505EB B1347A5C9DFBDD229F33DF57A4B91D231ABC6A9BEF04C63853458CB72ACA266B82AE5AC41007 1D1501C251F72611B18033F2A24ECE213331F51A341F7F45C442549383F763E6CD05EB6B8AE5 C753BE9FAB2EDC52C9FA8A5E7B71936F0D6F7F4EA6E9A4C992689D22127D3BC0656602E18B54 A433A54A209B7FA87915CA722D7877CAB4EEBD4F42082BFF5D02FF66C5CA6C4383CFF3625B5E 1D7A7E286FBDD5AFE1573419FD61E6CA3B9EE56E81A489E71A7A47E876AEBC1B2D203458A476 E537F4293E431D8EB393EE2A72A866B3AA14F8DCBBD40A3CB70D33A058F664418475C85CA81F 1C03E57042A3D215955955131CE9506902BEBC9E32F31F8DEBD520373562495766613E00EFA1 EB1A37B9ECCF87036DB234F0A3C4D453945FFABBE5131220E0F0D4A0885E4E15DC818F2ACE29 D5DDF38A9F6443834A8AC9D7F435BAC03C8E4F362DF52DE3798F46D4B2AA8BF0AF07460ED6D2 9BE11ADBA6989E26A985256D73CB116EC540324DD73BCF9AD2876C08CE047218B645E2909207 A0B6496E74D279EC82DE3BFDD59C9A2D0FD10F8B273912B98FE5C20592BD08A5E48C9EE8C0D1 13E11BC1F28B0589290D92462535289DC5B03D99DEEDF348DE7C56396A0E04913B30CD8E97F9 AA523EC136E9238AF835FE9BAAA90B04B6129BECC1A27AC536B5A2641E66D7743E59167C31CF 6A5DBB8D78B22F4F3F7CB443D96F7CF1A11C66827FACECBA4710DA22FB43E5DB4105B2192E89 F3A61581D4FBB11C4772139A7D358611F2BEEBF9B94624A218AF0273E3DBDB13C1FB32E8A881 FD232CBABF890D98C8C943815369C924F7CCD0C246F900190D01DDE52D3BBD33FB139A665714 49A5A5E9625A6DFEDC464C5329C5482238EB4CB0BEB30CDF5F5D1599859DDF189C92659D6FBD 7AE7A28E9AEF1AE05F5E0ABAC06E9EA9BD4A18CBF04F19A14BAAF9DF322D9165F488C0D7F48E 6E7500698C5B214E84030F052EEA86281FEADDEB32E989438F611A02CE21B5DA88DA9F668313 E2AFE3D22C5505D7E5F0F8710479C1ADF2981B77D4B3BEF0B2D71D292C68703E6EB17726236F F801124296B39944C5821170BDBC889CB9797BB99077F3D7EE1853B600AA6B75E4640A6EF4A2 7414D9A0D72C3A6AE4338B15AC0DD43173B6A25B328D0ABF1F770E9BD0C707A3CFAE2EC296E5 286EB99AE7EFFB9DA63F521C2A78BB1377DDB1EDB7C4BF9333DC85DB8E8B25D54360388A6AC8 87543222421322F4E96C2D4D9D7C11F02E5F3AD60D6018FB00A4AC6B13393D3B41307514B881 38166ED7FBBBAEBCD60A157E7864749534D6E7DE4949917BD37DAD7960DED8BDCBDAE5441AF9 BDB8692F07C26FBCCB0EA38DE3E495C4CCFDFA55BDB76336EE6E25F03A882F3674A0EDB30F90 165C382C70B5DFB90FDBDD054BF5BDB8C89885B5C33303DCE12C5E6A9EE85740F7887C7EC3EC 8920E5C2241EA8EBA41C3234CBE5EB5D0E819F33E3674C3467C53E79B9307090EC7CA7BE967B 2DD3E436004FB4F544ADC4570D9ECC13F49BF8DB8CA3B736FEF89FB2097BB62E6BDDDEFC6AED C701D34E6728CF29E66CEB031071A6F5EB6631D6B5B45DC7E501A4DFC7363B6DE0C3E9DB0122 C9EFC8124D5B2FA7F3673070749CE63D7A8DB803FE2447A28621974B5F22F0F1FD1DC17DF692 CAEE180E7124D7EF21F0A86BA1C252A8FB0D4CE82CF9A413C371CCDCF191B73524E303C79BF6 23575AE895CB7DC72DDF373B3C3B737BBFD7B8BF38AA6CB748D13DA0115E58473D367FD01B54 C5C375536362A4592F158AA170A7A66AFA3337C9CDFAFE1E58B485A0A0F227FD2656C61C0745 832445C1B68C58B64920C013D956601C71E23010015AFF4CA9C8F74810EB3927801E5D722E8C 876B966521EE819D9386436E44F74FC8604C2323728398184B796F502D9D303770742A016A93 767A4808793E4BC1044C68C57CCA2138A9DFD2E276470E0B74E95BE8E7B315758282F791390F B401BF0959A06B9390D0885822171A4C0AAF216724B5ECF28FD57DFB31CD18CA3AF35976BF8F 5C9071958BEE66D2FDBF25E6BBC5B237E148997A7354C683211C0261C5C91C44A23CE2EB0C34 4F22239169BBC8D0C0EEF06FAA7778DBEB82EBF9647ADCA5EF1A855F9B4A20A2546D185C747C C3953EDC129105887CF30DBB5B29AFC1C9BB720290A0DB8BB8F4D0E2CEA6D861AE797E890CAC 83B24AB9CFF7942D455D5309368ABE63163F020FEFA2D9B709C8771EBDEA6DD264553B3F5CF7 0E38C049E9A62EF4EE3176BFD19698C6A378DC5B164481EF0843F3CE80CF9FF77B1CEA8E3CDA DBDB058EC9C8B54507940B7BEA3489616DB0DDF359C1A2B0CB1A0ECB0CE52992D274BC821267 59A0DCB7FA35F86A3E05F99244DB8D673400868B6DADDFFF7549769ACB0C699D0D492AB12A2D 18469912CEF2E99EC2E0809D629E9C2E70E727A0A2344CDD5D637B5E8545A9E497C55F24840D 0A98EF0A30E3BD26F1D372E722582981F2B482C3989DC4A20EB7C4DF3F13875B028BD6459B23 F000C625735CB2A21F4130ADE0C9E24E50751748B01AA5CD043A155AB235E17AEE0889D30C26 92938EEEF753FFB50BD36B10880164779345DE088E5455990116C7B431547DAA52FED151C2BD 12ED0A8FDCA774DF1928D9B70E608DD4F1E41781597BE465D07DB6992EB0D672401DB4F4036E DF614B773C1787CB28379FD8C580FA113447CDF5164410B7AAD24910722C19ECA808E1BD9CE4 380F73EB94B7C90DA086D646FA5715F41F8DC4A14645911CF4466C4933F35B0FC3CA053A3D02 5FC70F805ACF4D3F425054AE2A24A39E92852EB0D5314E537B64D7F3D5EEB0C15986E46ADF76 F113E6215C7616ECB2AFE489671C369B6C202549E88A5296A922FAB0AA2AC138E0DEBA913E95 AF9D3897BED45B4438CD76A7B478038C1D5F80B07A701BF3ABA74934D334B674E5F1A1B4ADCD B28A84051C239FF54F6673FAF62018DDDD74B2DCC9824A0030219C83FF495A21DCEC4BC7B46B AA81D25F0E0267E482303A75A57E0F07174B30E30D20DB77C22A8E1B9A8A5B8E3CD04211502E 862653023AAB3BF5ED7427792CC9B7557C2A86B2ADFFAAF6C73A0B613EB8DE9DA48A04AAF052 EB642547C7A4A68F5E6E62280C92433FF3F2F6CA8C35FD265BBFAEBE265304C5BEE42DE289F2 0E48EAD175FE7A791C7E4F3D9AD8791898E59CF47CAAEAD2F153447FE0E4EDE919C86FEDC2E8 A4B344DA381CA33F6D2C3FE4B2AD3E7B97EC9A4297E11C3A070D816D3B17D4F38054FD31B9EF 6508A5CF29DC51CFE31E9DDEC94126B1291F217C7BAF06EDDDEE5FD15E35264ABB118141EDF7 24EDA854A07CC060D61B6F7B865BBE70B12EADC484E098BCE5417A6A8451924623776D421E94 EE474E6248DBD23691B3BB5DC79DFD86015C4E504E931AF8AD4E5B31D828D5DCA3CC0ED49B2F 1A59B208464FB34B970B8D078211641D53EF40395D50BC72F0A609B94FEF0B503DDBBD170D0A 046FC5CC2E2EF321C3CBCBC2144DD02AE323E74520216776188BD42BE847CED4E6351BAD2E10 7CF2A2ECC2BAF59C5C6C201522F9EAFEB7CA64729168F0ABD4533B6E955C90505FACC5D85E38 0FA3A2634F7B157099F315A5C020D5B0E4A4E5EAF34FE5B349BAEE4587FB05797519EB3E3737 C3EB68CCD8243D13065DBF9DD397CA3283F879B9E9284F4DEBC0976AB87351BE2B467394DA9E FB51F9F9BC2559C75CEB098A3FBD7F47C8694AA70A914501454C7328A8ED6E1B37C3279FEF25 A772ED67BDD631BAD05BF42F15773A997BCC4F66D0C9365D202FA5C251B2EBEC85B8213F543D D477CD2B096BC4B5A08E38F9AB51544DF7E9DE3D2610819FDF2F0DE3F555804459814C560FD8 C9FC2548FDC1C5529ACC7FB3F379644E42BDD7A72A1473F5869D59174274D29EE5CA0CD7DA35 18BB184EF1D25BF08491EB9F6EC2F8E6FD328FC472B408C3906A585F34443C8BD5319FEF59C2 E4F08C6C3BB228696C111516D7BE90A390F79BE04949366715D9029F3CC09388ED1DC3223035 91A6A2A41CD9165E7135C04813C07AF62B0251215623E6EBDEEF870DFB00D4CC2498CDFBEA8C B6DE599D49589B0AFDA614DEB7D8B11E6369DDA10291031A0C7EF6BF602AFBFC34B348B74169 66FEF9D62B4681503EF346BB277682EBE0520DBB728B15A3E03E1D025DC97D615FEB60C4CBF6 D54A2633F68414333EDF22F1A7628F1C09EC01216F1270EF05D6696FDB961CC11CF21DA6AF4E E5CE6DDBDF3FEC42EFD105368D4465C8D5B726C1F7251E52321B2EBB8A2316E7471A9EFC5CA8 AEE99BC1681731D465C5385F2752E2A41ADC0652A48F46F2A09390C91B147E199A06240485A2 B1583969A79E22475A8C70ECA68D4DCCD292CD13CAF8BCD94310A6B84D25BD385D132ADC5B9E EBBE5A701A2FE4568A5FD348BC689676E4896A715C4C0D809E1B719933324D506430712B9E94 F84BF3A558B5FBF8465B458626D7C43317FD47F60F7311D772583DF6554D695FC4B8EAB89572 E8345CA1642F08AC3A404E65D09978121A2242DE8FDFF69DB980535DC3640E83CD4EC40075EE 9FB82BA5F13FA1CB36F55D0E7BF302FA0BB9F0E1D75BBD955F7A41EBCB296E31D4342F24A4AE 0B44F0FC9FE7EF5EDAD138B3A1E6B175CD412E7E877A2FB737CB4A2B023B148193D4D43EBF64 454A70C1728B4F4B8006A6DCA8EA77432A4A432A346DD5327ADED0381449C714077268BD531E BD2FA16CC331F5B2ADD5002DC3FD06D6C83A047208BF82D525645D4F57EEF0397FDD3839B201 366D4654F1798941CB1531807E9D736A4A22A35AB536D198972847727EB3C57B025E9724A257 13EA871C57FB185EAB6F47EDAAA3E47BD39AFE724C07336602E957B6E5C60207382BAE996FF9 A59C021F2F52787153D694B42A6F131761DE66891B98E7D7A3C462EC1AA3FA66CB576C1E8CCA 61E9E10D5E4AC16C1E2CCE7B3496421EBF04C0ADCD9AB839298B1179DA89DC23A95DC578A554 279C69E566151E482C607138662C75860CDEA52A964A8D5E8FD06AA569736889B256CB1FF0F7 87F83FFAD695656EC76F0163999E805976665723B349A3EECA090313C7598D57400DB216A156 39055A12807EF1FC9F4FC9F498240C9D977FA78E36CF483F676CC59643BBDFDACA56D59949A1 CB84DEF63AED2C20DCDFB5968689EC7DB2BCE1D79D300A6AF4A9CB50AD906FC410AEB10076E4 FC37FD1BC509C22037F7B8DBF0C8733D95D744D50CFE966B531A934BA9F6D5EE6DF802CBEEBC AEF2F7BF747B33D8A8EFAA29F22191F4F675CD9218E5AB3147D2E0522042A3C12EFAAC92BFDF 9C38BB37BA0E485D39C9D1DD5B39795DF00E19C459BF9CB7A4455A1A0AB6F522BCF7D4B0C739 3FAA6E33C6D9772D8CCB4AE4874ECC6999163C3841DD1EEF54E21843CD7E3995903F2BBB5E45 DCF8AD81BFD4069B1BD68295ABE9C3D4FE28F5CB88DACD3B808F0A9278148D79F9B3B3A7AC8B 344C65D4FCF37B517C64957303065C1BA77034B72D5C048C6586D9F568D52EB1301EE0D07FF0 B005CFD50726D3AD1A0AF19023432F315C93FCAF64E3ACA7029D8C98569989C8B2CFFE3C951B 625BD8390C25BE67041D603136B9870F1FC959A9E4CBC64A8A3F7FCD349B0E04E8B4F588F4EB 29184004E249D12E98DADEABE61D91CF3C799785BDC438C1C4C46BC4E7AB1298C4BDEC98A611 4FA01DD1801CEA5D1EAC4D5AAE3F0DFF73B0028A9D714B778913D4B3A733F9DA599E36FA43A2 A92F4F4C294B2CBA3EEC8AE82BD1787BCC331AF8096CFE42C2F723FEF5984273A69E851A6EB6 C9915C7C13C664855E56C04B2FADD6AEE0F26A44C66D98EB928F261B3E79C2409F77FE09E308 5A21F806E00DB4297659F8380C5828DD10D8025E9708923F90F494067450BA710AC2D579CE23 9F498F4FD3ED0DAB3B29C3AC70AF6D91E3F1796027CFECB939BD2F89420C9202A07F42AE794F E14741820D6D8599DFFD9D86B4AE1F3928EFC52D9E560C9E36FC9EF7B41BEFDFEB08D73680D9 6AF9F6070391EA61D36D677159BF92906B81EFA600BE7AA5E130DEA9F6E8B09006C44BCA359B FB5BB04C47678A7BEEC1A20F0A55E46CC4757C91683D0B9970B6E263234CC7AB727CF54C892F A2DA3FC638A0E5D7EB63EADD59CD99A1192BFF63F91F747F66E8AC5B9DEC88DB12B613F2F4A7 59211D2ECBF96FA1062F5A3A697102C9F777B40D8E22BE613F209B2C2C350A24D589CFA1A98A 5E93A8975F1E37AA0CE6B34CEC576D7E37BD0EF873274EF764447879340DCA1DC9932678CB87 0672C13931DA6BFCB81AE0B9CD88910D71BB5D4BBACDB805C75E08816FB0161B97A0F92F68C9 5B0AEF34B1EAE4EB2A2A264694CFB355F7179833E5B8FD25AF5A9FB6C3F45B29506C14071E01 563194BB9922E8D7EE4600ED6D47FE0606C20C573A3CE4CAF4103416D40FDD9C5EE641C393B7 5DF0C209553E28423C6464E1813D3AAB84B84D78197550F50ADA7EE37EB6AFB54421AAE33381 89C9F315E0A3F9667293013D4FC19462B1B3484F021B769F25EC77C42B95378F737B251E4244 04F273415C3AF2E125EE8D99FEC2971C8216DECF521B3C1ACC792513B369C40DE93A2B033EB9 5BE49362753C6D8B956B352147608D6DFC5FD4D6E5645B960E41AC1FF635369BE5827A5BA98A 0671B4E87A178A7B9DE73FD44430185F33B6B4446CCAAD4475C5379956613FF8B53788AFF5C7 C0BD04065EA6B2EC598A1074606ECD8AFCE6C8F7C4EF2D091A4981004FD95E6417FA6440BEBD FDF019845C86C9C8C6831A85BD0AFBF6399F2F8D8BBF8A7A5E28FAD827B796E1D29415F8AB8A 5866AF727E3A7963B74BB58865F1DACBD787038F1116E98625A04A457C0E1DC2A42F0CD2DB80 4E3F46DD916104AD1114323DE1F5FC9F3D1D3C277D6DAC86561EBBAEEAC35042F2E62DCB09FD EFCCC06A51061187A75D8D1CAEFD6B8738F672C2A2D1A6068BCA91D3CCCEEDD5BC93202FF55D B0DF6563390AAFDBCEF57B20797717478B89F52EC7897D54FA78ADFAE0C48209650F3290B79F B5A933ED7E0BCAA2C0C09A68812C29C66D106B8D6719B5916122F7EC14804F169DBC43CEB5BF EBD0328E25B2E96B35A7CB8D0E6FE0A714576C5F602B2305D4EE8209485A38065CD45CCA1F68 0B3B95C5E5B7F333907BEF1160D7B98F6446B3EB5A419B72AA240A526009C9E1A243E868FE20 72C3CB790AC815F1BF832A2351D258C1CEAD60A46216E751DF53645827BF020E14E2A8F54F59 1335CB64EC16B26C452ED5CCFD81B3871D380B689A62519627A1ACC30AC156D04BFCC5DBC764 31AF55CB8504F8A848DF4D19F5634141A6369853A9AE8EF2BAA91050D3AD6E891A62B4DC0F64 7F125DA38053E17B92AD02D4E675EA4B580474C223AB4C82A61A8E51AD915A34BC289693F238 3F5304FF76ACD18193A036065FC90F3F74FF964521E9D00457AECFE4CEA285B62728E21B120B B84DFD426132B9FF102CA09986E7EFED65706B46DD4739A7D44A290379E3B5A80D937018E081 F7FB57ABFB9C621C1F03A334A6BBDF6A08073E3308D5B9485748756E8CEA0F100C292FA9E712 2778333198B3181366E2F35C8E3727BD68BA143F2A7BCE6715E3517FFE4AF858C969CEEBE9D3 B0DF0B45513CE373B2345BF019FC25AD182D256644E836CEF3FC83F5EE13DC4E57E2BC1BB936 AF8B97445603B6F42DAA6BBDC5A7B382D6F64479C2532F5B9AACD85B0D9199663935B3548D0F 38CEE61504EA26737EE2AC186040AB43732B83DFBAF183FFBBDA9EB41BDB425F6175865C00C0 D8D91CE1481DCE2132160EB143EC76E45B9FBEEC7EB91320C7D6038985F57CCEC56ECBA5119D 31CCDB75D42908C606D550818FA00F884291E359AA0D84CFCB3CE0A322D711AA40520C964BF6 54081D0C3ABF19F36E614D67F0C27096E277F77C26498D6E7D2FBCD9BC765163AB5563354A64 5EC13C93EF7B2009F00C533EBB14C6C8220E6FC2D41D248885D131F4E677D4021E5FEF1AC8EC 742EE7EBE329BE95F3F1B4094CBA33B3283BFFF1DDDBC6BF61404F3C1BE8570D0B27C0318553 5B4E685A312CF5E6EAEFDEA4658E7388132EE3DE6FE9E4FEA5E956E48B4A738E281AEC651B12 A3417D6E1D6BF98326C0EF135194B5CA66682EBFAAEA521800DD38B686E451321744C866722C 39AD0D5C4526B6176289D7D66A6473602E72734EC03E3B88F7CB9A82A8A4D1922E85B0679D19 AE159993E9844008B3723491AAA066497E8739AFCBA1F6067A9E3A9EF4EBC3D18B1CA501B45F 787199BF18141E58D73897605F0A5BB66001B941AD42C8175AB8ECBD77FFA213419D8730C7D7 08A9AF0299650B2F40B07438AD2D286AD2365C71A3892A1B0ACD7F0942397426D68A09E564BD 9F3DD9E4FF5ECBCDEA45D2C8A8FEF41150B0D390C9637ED26834D2C8AAB19680E50AD13729B5 8F1FD1E60F4132575D0836C812C76608F6FAA47CA76CC744D9ED2B2FB504755E2BBFAD17E65D 16E33C9BAF3CFEFB143E4CD102A6E1AE57221F4C9090983A61196CB7EED63538B8EC9EBF24CC 59F79C200B8D87203CE7CC6D5AC0DA2008C5973422C593E8367E69CA0CCCA70BA930FD465DC2 5B35C201C6165D5FA0B0B2CEEA6B02822B4B2DE99E0FA79B1F85D8ABC8E05B0151CEDC95A6F0 762EF425F682D9F424A2FEDF438C0F545155B9A62EA64666E57646406425F59A6396DD449A64 B4D4C7A9D94A15EFF6A1613A8C34DBE77108E9E653BB1D25900A6DB95B46E08906DF3D1355CC 090FEE70B1A377747A45AFF889A69FCE8AD5B8BDD8C4B3BFF9437BC268695461614947C7750C 7942D17243ACFBB8568BDB4051A0A796E4E0E83E2F59072A87BEF5A9A71D753AECD10A7E9A8D 9FB9145200C541396E6176E0C33B3603D9C669FE983F6483B1F502D256E28DCC528660E57528 07B524A4A1CA46C94A29CA1EE8FA77E3E145985EDE8233D57238480A8A65E77ED3D40A4F0C11 E8FD582398B1BF0D6405716A4621AAE65491864AA035E6E5164191433D4739BE9B7216E1CF3A AEA646194F679CC0EBCCDE96665E55F2C7B5AA2538B59A39F3F969F12D4C5B193BA98CC998C6 9B6C7B37578792208B2846D35CA15C3CE3CD487D92945EA59B3B25BDDA864514D8770E2EA69B 27BA296103C56353AFF5913FF9D0A64B7F9AA68D4DA67851464DA2FD45230DB839580301B89B F1599F69E73984A957B8488D5A6C7B24A2C66A64CB3E6E57415BD7967FCC48334EEB4D54CE7A 07FB080F99B3EFD39312B60E1AB2D3592A263C832BAB2C358B6DDC09B3DF748DAF2713599282 5123BFACC654FC3015008D0793487C89462F5B0750DEA8D2DE0F71EB88B8470B6B69659522AD 602C218B719F03311E963D9E88FE7B57B143EDC15FD6F32D1AA7DE8021D045CDC66A41115C0E FE10FEE11E5E4EE83FB5CC856EDF767200101483257C631C23B7D1F12422DD8225FEF419BB3E 100303CC0DC516FF92301CD5C5B600A689EB58B55ED56F89BE67C3B3077A6E79BA76B21561A6 14AB9F31F2D384D729C58B6BBD9A8669DD177545E19A2FB9FB11F0A82121CA198CDB58325D2A 6ADA3F47DBFBB670A98FD82A0D2F4C8605B4F5B8A4114E3E054FA0C579A8704E822DC5ED27C7 4B769D7A666ED48A1224E829A580E84EE8BE56CDD488913F5B5E0B7EFE59DD5C97627E55139C 646279A2E57138CE98FD8FD979345CA0888A29270AD312CBE0D777FE99A1B738C4C91AA2AD5D 995B77CD6C9D42FC6ECB456E1745CE6C95C4DF7B23E89244BAE6F524D1262EBBE631AFD39EC7 9E4FFF0879195078CB88DB1610007AE087F9E326FE1D4E8BA4673141989FBE860BCFC561B199 151722390367C65C6B1CE7B2298F2C6C6A0776C6C5B26FF726677BF04F6A99E56A3C436F0A09 A469EC71E8A58F0211888F3FF770F5C589A8DA0E320AAD03A36555C1370DAB08FFC47189D84D 52791D6CFCBBC9AA147286ACF782F594C314F4659CFA953E4E8E104B90957964338C39A97A6B 440CAEF16B64E04DB2131DCCDD0FEDC418EABD3A9F102594757EF3E29E3CBF69A7BEA78F04BE 300B5DF41BA52E12128E0953E6C2680C53870EE27B4D85BA64D673D03FB27DC1303947C7A1EA 3419AA5EC56B2B47368378E8D2417BA5B0D9ED54F78EE3AC9740DD7E77DC2D0D6913C20619DE F8E160DC534E4FF87C0BFEDC2938101E55E2E44599F27AB1E344335352352188F9BBAF006F58 082DF83632F1ED5D6EA677294720FAE0A5EEC7581762D4664743487B277C2124DB838B8D73E1 3C62A6003C69CC7AF97EA4FACC316953DDC3770F3F1A5DB4E3AE71BCD1A5150E80BE1DCC1806 8501E74CDCE299E094A489253FA140A5FF8859154767CA07A76A4FFE8CCB1E70C0CBDE5F9F99 A59CD408532DBDC2A8481FA300A732A9BCDA01EED59914479249B335726475695BB218BD9D7A 32B5783835BDCA8E2624917E8B39113245CEBE014CF060D4F583F2E6F00F0A708FC452DB04AB ED88D49290C6EBE8D06A553321282D3ADEC8DE2D712F6CB7EBBAA3C89E2E910DA121352A4FDC BBB8FB932B220ADE4EF01A41CB6EA32D10A05E10D152B0650F5712A035E6B4C98A575026A95F 45BA6022E3AF9113246F541B7CB6D3037C9BA013816FCCCAC25FCBB186D8593FA293F9FB3972 B4F240EEC4D60808547748F93C12D3541B058894A5BFA0DCCC08E587574F2F5E23EC21653DC1 D65F6B79EE6FFB6BB4044838FB6BA3DEF1F3C11BBF80548C5B68102C513CA572EE12354280E5 D2B67C1F475DD7C436DDBA9BDD0CA3BCAB62506B58039CE8151084E1D1C17F2B3977C58FE2FD 4EE8590C288BA63AB2871D5BF04686F9B22D1E6DCE04A22FBECD1FC3971011F08CE7AC474229 D659A8AF49AFCA7D70643D18B835063A38D80B11B5A01B5FB7AAA27A2999ED348DE62C49475F C1B285D4F8F29A658700D139D3E82CAFA027527DE3BA2FEB989F09CD9560AE6810F62D8F8421 07011BD509DA46062894A14C5825937960A6424CC0868AC4912EBC4A13E00E10974729D7C9B5 D2689F92F573546B29AD861900C33C6938E9DA4158D971CF1F82E9122D20E137EDDB812C7F83 4E6C91BCEF7EC57BBBA041C5C7FCCF19CC1EB16C9CC1BC99E114F3C1B40278205C9FD46F111D 786D3E09B54A399574A4E97F874CEE4BFA8277BFE16D9A914AD34C088EDC2A8461D84B4AA348 97FC4A15706093EE21E599163273D9F3493E077E7925B1977F847F714DC62CB00972A47ED786 49436F3909B908748BB1A1B6309A44E0F10D638DF86B62AFB18FA8F319B60CCE3A298094A565 5340A7BCA2E97A12E339295EEDDF250DC8315ED5A0D27104800B2D7D19973C3756D02A5880D9 DE861E82506D0210B1C41CCA79A08A077783DAC1F8CDD32B851EF07470DDE47FAEEE495A38C5 4E33536CEDB7FD12F8FC1CE2733747651F8E877122312B79417824FE0EA42CA128E22D85C025 AA8E2540387B6FF5FC627A25155D3DA30F2499CA76B7D8A1874E4B38D43231A6D4C74EC82047 0B1A8112DC936841132DDACD87034DD0C420C7CD6A82242DADF8A664B43561C2C0F13D324018 47580BC0FED0CD3637031FCA5F1EFFA8C1A838609EC2649CAA2A5608990AB64EBA24B7B2DECF A6070CCA859AD570D43ADA3EF24DF280DFBD86B4C89CB0709531E96CC969522F7E138D1A590C 56AFD6F8039DADFA1FC3063E6F5B5421FACCF951418EFECA01A6504C6ECB5CD1471DDDB77DD7 7D025A1AE6ADB381D5DEAFEF1E2D3CB7442C934F7D8CFE122858EDA43A324E6E09909068F9D3 74BE10EB263494B7A1F9B29CFA91DC4E674BAC9C90121E083466DCFFED7DCFB8A124497C762B 68677F949B8DFBD3F75E752A77E51D9FE3FC5C0AA6988E15C8D9181A0AFD43DD59AB01BEFED8 3DEDDFE1F9624B1A23AE2ABEE75D74C2CE6983ECC17499C810744C626CCF72659306895F1181 C37627351050C9D4250FD3543B315CF9438CFA0C2204544EACB38642403D630B13C5B8EC0D86 27F1E530CE84F8CE9FD628A7DEBB55BCC0BE2E940ECCA659C377A9D61FDD8FACA3DBF8538728 9FC85D7F822B4AD6ED303DFA2F0062031F5361EE92C88B0DDC3D0473A2C8C8D598B54B9E9BA5 782D7BC7B6E756C13BE262CA6030E12AE1F98CE7FC060B3C75B3F9914EB1829806AF45C0E351 A91B0889B407329BC735C74289273DB2D80A64D9E9926C6E7EE85B173CDCA5CA81C49A93405C 6033E04145208C284F7DA7F9D8D7093D760A07FD48DD92855E0DF2E78347200D45C950A17F79 56F932977F07E81DC01713DA0273ABA5F375FA35E5BACB9AB264B8C5B3CA5D85AC907B8EC1C7 9232BDA1DAA755979BBBE971A9FE00B93ADA37038437FD3ADC8AB7AAB824532B50F34A41264D E0973DD8E70D9C7B688188AFE0A25B9C15E50990493BBBB36E68307D61F5673B4356F9C6AAD1 167E1915F752EC2085763BA31F3ACD0AE57B1E88A89BC4AF0EB7F701038E1FBBB223E592AC81 E67FE306DE7F9B7B5F7BDFA58DD338496922BD72D835992A660CDA654CB7C194BCFD39459B42 B5C64B4D5BAC18F09DF2C656AFF2079B80EF1210B2A0593531074424FA98CB24626AFDB73FCA F5C0305C8EF1DE2B25BA906C6E5E08BF235889970C4D9DCF3D747051E1647152F67D386CC6EE DE511D78BF2929AB0563496E18BA42FDD22ED69224F2E118F97EFED47A407EAF593DCAEF17DF 4748DD079D3E3C6CF2C9E7DE4C011F73BEFF6BFACE576F40A7FEE3F28096CC49B12AAA643AB3 772D6571306276A3277C901F05A2DAC692465799A5A443019BF49CB9FC4885A29BC1141FC242 B48394ADD9135C98C09AB3C4F95D70F9BABC3031DBEC15F0B884D73CFF0CA448B82C0C7D48C5 D2A948DE4C44EB822046094EE9480B9F8C96933CD2D9DF248A4F79F7A6CD7B1F53805EDF365A 99000FAA55DA74C8D00E7A4E68A49CDB94E872C8CD0AC1829AD471A63DF2CB485F6D40012481 8047E2E9F001E9DF715D04FA4669730CD8AB1977A157920398C25FC326446494D410A7436382 D7B4974B6D91F2CAC05C15F6E554B6FE9ACCD3AB3A6B0F143EC82774AE7DE962ED2C8CE1B2D8 592640E73BA5DD9FD4743B7B982E65D1F1FF9FC418FFFC0878BDD2237FD99BB86750F17E5953 60861F4094989F7B127A97B00820FF5B9E0208EAD330189561EB615B84E73F623D43A21AEA8B 08133A09D7B0B50EF1F9439CA0ECFC17CE4CD0A7EFCB3A9534A372238CB9C48AB56032FA1BBE CBBDA02ABD4FCE5C74CF1A21DB2C56CA2546B68BE0062A6E1194C5243E1B51D1DA56A3B33772 2372A504037C881311B0106C6DCEEF4F5E99F29E6BBCCF69E88FA6B4628091DF4005C7485452 7717CEB0F771C5520D0E8A6E9E1BAEA2B8333056E41F1ED8638AE2B9502444ECAA492B53C847 45D7F25A43DF8A637DBF4270FA0C6ED6E22351692DC37B2E89E73B217F8952E8175DB49CA80F FA20302D74838B145B0180A5EFEBB76A15EBEEF0620EAE4B599A2FDEA37D95B3AA6CBA4D841E E5CCEB5E62CF7AD26381AE2A67E114EF517C54ACABBDB05DD9A469D5D844B2D951B1250C9BC4 3E78228FB255F2B7C1369E9CCFAF5F14197936F794E871EAC1773D915610A913C1BE747CA4D1 F5BBD662A88DF31B50C62E60B096E603A38332BDD26199DEFF54025810B6129BA9112544FCC0 447D6C2C04F7CB612F0346864947C0FF26A0C3FAC6CC931D7CC1694041B6D8B7EABB00C28AFB 7E8211D06817A3D83DCB82AA90CBCB7205CAEA200414C77637FCA46BFC2A2D95CD3F970BAD20 311C40B2758172153C56A078B0B4F51DEAD18D45D14F0571E5C7A1E9A52A4147B9616167C1C3 D6FB50C633FD27256D31915924E2BBF53941D9D3695E1B8D2C967D2AE9595324070038162121 308E95453F979916FA18A734D6E38063C14D62E681339714C3E9B118ECFE97C274BE2B1E49B3 B3EF6DCA38A7FF8E4EBA868500CED102BBFA2584D707C584549405EC333E035656CBDE6270D2 0F2544177588DBBBF22B24078711E3245BA1A5D8987B967DA1D2D24D52C664CC0C00BEB0DD7A FA2805058FA11D5A076692BEE5D9952A82F81A8A35A7B685FCA302614B43AFB7F28D650A4608 4D081204F87C10B4E8F31C1534B3B3AE28439376DBC5B65DA91672AC4BC471CA97CC4FFAD1AC 83F7FB60100CC47F7960AB9F50D6FCB9469BB07E4962785107EDC8A11D7C5939445E9B44F411 4FCC4665FCF7D010BF8645F2BB0C4DB276FF547C051075456080522047A86204211B30D0DE14 8BF9C99547E29880ACD58D180A3C1109827CE75C717FF54FFD0C7493D5E96FBB36305F7791B4 5A491B6D10EF8582985A9917C42C6C3C35481B9874C482BDC942AF2315649518FE9E066F635E B6B47531A9FAA61D42CD1CC7BBF24D8DC8B85DD65A74DC3A51A8425F47B4A7B69B3679E7E770 FFF200933C58D9ABDBA5DADC0968771F9E9D8DCC4DBF96A9D95101C9F83B6A4AA460E4B67A59 6B7EC08BC4DC207C358352498BCA3CF64E92FDCF31D66481AFBD2FACD9A569FD8EB2F35506A0 08E4C6C954604477495E7FE83CE48F4A1CF3775E10D3DAC8F894D95CA791965AF07F03C17612 F0BAC9E681C9F90BE6A359816C27CF8A8AAB49E0726FAB1E4198AFF4B58944EA9209B9A61714 8291EB523520F22A28CB7570E11F4FF47316A8E783BF55CD9D514068576524BE2BAA8AD1D4BD AFF26BAAFF65A7F10B913B2959D64E7E7BF01FD6A85850382A435C1044AE9C6C6092CE8CF511 AF992911A3A056B2D1B968859A26DA0BA1931D7CA4E3A222256B52E3A7FCE13DA3A8B8D891BB 6B3A471574D1CD94C08D3F331439DF0B3B628D69351BDEAA8EC7A1414492F2D21693C7599EDF 513D3175AACF5B3D6229F1D47167838C93E2ABAB8519D754D6C49712BCCBAE9AF841758C72B6 345B8FFA6A86C9416036430D0CF66BA152095F9445D30D6B04183E6422167FBADC1D100C3822 3B302A173193F57DF346DAC5FF800F60D3F85C1D0CD61E7313CFB5A1D1A4EB68EA11DEDBABFF 7DAB695EB90BCAC1B0C332C7C87986779F6E29BE75A2CCC572D8EEDE4CC03ED28EDB49FC5645 58695EBDDEC86C2CCEEE1AD7515ECB254B62DC09808674836186516B927F4BF17E98456C89B7 9B67455D3FB5FCAC47319474928015DCB0A7DA5976085E41068E56772E770101D07585780FAE 00B6EF6E66D203B148EEC52A384638B00636B998FFBDEEA2041DB232CA9FD24D6B49E267C6E4 F23DF648D83E5948A361CC3921B84172D727E6C75615A121CA60A6355D521744493C96BC38A4 E9E29345A9FBC0E244E2EE8AD0554726465828E532F606983DA2A6F9A421AB1B9B149335395E 9D49FB36A80C5D7A9E51F19D5A0568EBD9C01A2C989123F9CE33469329F8149914097EC3B84A 1E557A614A455184C1CCDC17C45664BB1A8353EC6C9C04D219C4A58AD1E048027721E766E525 EA9F2CA909E50D9E98731315F37D7A9EEA606E642997CA65D1867190476CD4735DFE89F9C080 E2E21A9045AB22B89A49B9AE04D29EB7E86BCBC38347881656A7543B35B8A1CC1E9F36A5AF0F 2B0686F0176FFE8A70DC8F0AEA7A8A602CD4668AA13EDAE3C7565823A2C3B8F255142AD41CA6 E3849E1381DB533DD664C5CB43071AB7FB7235576029652669B50944F83C09D1312E68B443E7 CAC21D3B44BBA90182DDFA6606181A40CE8A52ADE608DD6979C5BCF5B02663EB211029D1D896 85A0945BD732B46E0DFD66D6D2B486F8A21181B562189D892BE877B146677259E25A855E971B C11246AC4756EECBCA899FEC5D0C938197C3F8426EB1EEC083B40BE472C925D4D91556AB253D 39906F3447CFEE0DD4484A71DE323F69D694CFB85AAD9DD1F9B4701DA649A696E6396EA4F9B9 B4F99FD84176B7ECACF20789226C65799CCB92BF1CE1008C7450CA1B985CB44062E0E86186E7 AB9073F0AB92CC2F3809A42781AB3DD9C4614E23DD5C46C7F9B0FBEECC276328768B5430890D BC40B50B863E2BA756E9A44334A32CE75B1E9F81B88253BC2444E11DB1E3E09441D189FBFE44 234B42F08FAA7E2BE38E153E030792716B3E2EA58A41FBB0E4383F8C20AC942BF4ED859B147B 5811F4EDC16482C8D6CCC8F9200D0D9C2044F920B53639BE73CB1C007794CF2964FD703A6477 44793F5CC0085B09E216B7E9E5DC415907EE3B0232B5CB2C624EC58B88AA23F70A77678BA96B AB458E65F53BF05556D804ACDF3A462DB96F9A3A88C53B9877EFCE00F34E99AB203AE7EB4403 3DF3A682439E71021366564EA5B0D35B8CBDABB87423F9631334AA897AA643DA267DC012C933 F98545990D3712C6D05171058FE57C856D01ED777E9AD97ADFD7753E390FC20E1594F385E617 BDB39DAFD08AB3DF38B55C8553DFA0382E569FF0C7F0A5EADD9C390C1F7353AC0CAC68D5D36B E24991DC0BC9AC88087533A2F41BA32A17D6D70B112B761B3B2BE907CB80E0293CD898C7B4CE D1E23D76890FA9C2D6A7BE6CC78EE3A86FEABE7D9AB3DB2F2BF8480B0BE3147A82DD2CAF8288 2EE7A8382E8CCACE81372F5BEF033AF074F21AB3704BCAB6622A8EAC63EA3F802C4099A4680E 80E0207B4E8F4AAD94BA83C27D93F13B8DF59E548FB34944D36C12896D9D9BF72CF473CDA0A8 20EFB2572F704C15CB1C96B8D54B27298DEBC877CBBE2D375995CCE8E5252685DE33E2F5FCF8 C524FA590E5444977668C1BB92F92D91290EA0F869B45F78658D189C72804BB37658631005D5 B6FF1AA7E2CA7B2CFA96277D353B04FA0AA2556CE136A4B4B360434CC37EC44AB995F5E03CF9 258A5D5D35A9D1C33E51375D5B1048ACE95B3B7CE85195839A546AF8F2965701E9DDB41DE2B3 BA34A61A0ABD02998AFFA17857149346BF4E75A42A750B6AF1D2B8D8DAAECA5FA8300D4C15F1 38E62CC089C6312C16B6647EC9610EF0AF2C9C909E21F7C59F9F25D0232C681A127BBEE90D6C 19E41F64789852DF921BE412438E422B7F43E167198E5DD670DC6F4072543E003C7D351FB5DA CEA72EA143ADA96EDCF91F3D672E178268BCD583FDC288B0771D1214C307232E7101FE8EE73D 16019CD43C7D4E0BE13F730BECDF9EA87A67E128D4E60C2104A36AB5BC411097F89F12564E1D 3BF17D9DD5D587C771D260CDCE41CE0F2F1DF995596651EEC623EA953EF8131D93BDF34DFA53 D25A7E20161C6B509E6C0D1E3BA2E3735B2765D9A69A7B1030A735B55FEE7E3C1539F0198640 59CED218174263933B3AFF5F4BBA7F651B365E27E7B0B36757D8EAE5E0D2EB01522D79193C93 84F8F611FE0B448307555BAAE615D204A407C7D49ED5DA1C14866C5A57A1BF319A2AD0B2B9B3 AC66F93514E87935BFD019FFF985CF0E57EFBC6F6A0E741B4E52623DCA9151ACBAC00D803E8C 66B6608695D88B188365AAAE11F7D2AF4F5151A1697736F90AE78AF147DD43A23B086BB39495 D5153BBBB1A3F1465DD219EB61D5C8E6F791EECAFC8D455BB423401B5DBE3F8A3C9E04198835 751E51E2DA6BE766175519E7CF26CE946310940205FB9928C0FD909764758E215F13DA4EF6C3 3BCA3E7F3EA96CE7C6CAC3CA449EC088BF3C8B54DCC433276DB76C33640CC4848FFCBC0BFD4B 3B0D3A3EDF142EE977A20A10F00EC0C19053C11F4CCEDC0C169F8D06E48B1CDB6F7F6446284D 951FD8E52F729CC16DA6BBD29F9DF9FAA96A023A7D039D4597D90E0E0B3C5A21BC26E4EA0956 D92FBD3C5B657D31E030AA1548810CEF44E42CF2A147CBFA8D3ED2AD4887A5206AB95ECF2DB8 3084CABB539BC368216B136B1808998D92467F3AD676035FAF715CA3A2D0E2813E8A3AC5FB71 1B6506DF9BCAF6C590666FC7A6F950A292FEF40CD5715F88AF0FB4A3C5DA4A4AA1E13BA6BC61 2F13A13D3A524DED5A78C3D73E389229E131D0BC3D58D179D925779E5836D4D0BB1349578EC2 82C37046A87F626B365EE9C35219F317354C9204467E3112F7AA7163E29521CCE0F7F0BEEF19 4DC68DA3409F33A55E86904E26AE8733B468BA029C6E71CB13239CD089710ACDB79F3DEC56D3 FBA5939F5FBE03E822DEFE7CC96AFE87926CCA04F3FE24F5FB86FBA339D109BE03C911786781 7C378D1D40A5670F97F17569E410654FDCDE83FC379B25FF051716E09FED8440BC435F79F8A5 80A7BB94E03B406E41DD8FF58A30CBF30B80883149C18B82C1631FB5EBB5362AD0D78857560C 08F3297BE612C4ED11B30435F99EF1D43611ED827DDAD258AD3E5B4C798420350A28BB23EC32 39675CB65D0CE3E08CAAF16FD943071F19D84A6FF8CA090DBF9A24205ADEB6CF31972747659C 58753B3438A0AF45D092705659BE42C74B5C38EAD7A65ED9E9AA99138FFA75E7F80953B90C5A 0A3564402E0EC23407A8A98353F51C31734BD9B2F239FD65A0411E946F29755D9D1B91C8A587 11CE35C158B28CA5C858F4807FDF26B972BD9E794324F2AFA43412F5EE8C804EAA5D1DB957DD 82ACEB2492F78C175BE221B5AE9E0D7A99057F2FF2FB55D42CC9CCF5866EB09D7C091331998C 693A9D1CE420069B24F0F982DF167372793E6A81EE2B9E844AA9C5EFC1E9B8FE8C05328050CE E5FC73F179057FEB7A2F843C0A96E22885EBD7ECFAE90EB0D59AE93728A3CB05C966F3D9ECB9 FBD23A5C1288C7C5F75903CA85BCE7387B9C7E473946FB7D46A0E4C9C96B44AD611A4D208F90 270C6F7298EAA515C370F751F8309EB588B8A67521918EE5D8282CE6E3DA1EA04A1C1AE24E2C C38E65C5ECE92DD0C982C54269EE1E963816422635BAEEC3458E86A821AB0092EA89538638D0 1872AF55CCED338177113B25F3BFAD8A6853C7A4AB4608E95414462EC826139C1B52ECC756ED 22AB7D50C8777736EB07586FA47A3ACCF9626A99011424D78664DA2C61AEE77356BC80EC0238 CE51926DBD899168E8D2794B4F63A6559C03DACC59C4014991C8D7049F58FEA38C9FE012D2F6 D344BC9BE54B40441229B6A8FB636CAA9188BD971E4892ED5EDED000F82610AB0E581FD0AE70 6F5A7794FC75146C4B2E3183FB051942ACCC088EBC4855483642EEA9E1CD17A2DDF76EBBEF29 B96D38769E444659688B63CE6116A0C9300190AAC8C3E31866B6F5D1048B8F4EC9263811B2F6 458978BD8F7D788CB21FFC394F5755E7D90A99533170D4C2AFD113FCE91022580034782A6A14 8391C7CCC4B8652E16AE26C00809DF6028BCA3E8F22774E493916EB9E0C3C3C2FC5752E0EAF6 B6F233C4A5FD689110C4B22FDAC40674C69C00BCE9D5246E7B3579FA776D2DDA7A1D768326FD 5D8B6F7E6083EF31025E17029631EEDC77EE0E3481FF180FC269C3525101577D145BE6C11A2E 7B1EEDF78F003FB99CE7C185A5711D4150F7C3AF25E98F036B48678B443CE762B33326B63B73 87E96878B084B3695B24FCC7FB49A6851EA40AB8BB7AE45C288C3CB4B1D9ACA0846BEC1E8955 4D23942EE66E911426C4EB4422CD6B5F519CB91E969D3F475C80668D4AE5CEAB15DFE7F64029 8178AC464AAE2C8198E1C12A2369D81E2CD1EFE2FB3E8C499D1F45BB2C1859F44DF0776EC3C5 6E6D31E587E6DA50CA97AAD5D8AC1E9EA7E5E7460000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMR7 %!PS-AdobeFont-1.1: CMR7 1.0 %%CreationDate: 1991 Aug 20 16:39:21 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMR7) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /CMR7 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 161 /Gamma put dup 162 /Delta put dup 163 /Theta put dup 164 /Lambda put dup 165 /Xi put dup 166 /Pi put dup 167 /Sigma put dup 168 /Upsilon put dup 169 /Phi put dup 170 /Psi put dup 173 /Omega put dup 174 /ff put dup 175 /fi put dup 176 /fl put dup 177 /ffi put dup 178 /ffl put dup 179 /dotlessi put dup 180 /dotlessj put dup 181 /grave put dup 182 /acute put dup 183 /caron put dup 184 /breve put dup 185 /macron put dup 186 /ring put dup 187 /cedilla put dup 188 /germandbls put dup 189 /ae put dup 190 /oe put dup 191 /oslash put dup 192 /AE put dup 193 /OE put dup 194 /Oslash put dup 195 /suppress put dup 196 /dieresis put dup 0 /Gamma put dup 1 /Delta put dup 2 /Theta put dup 3 /Lambda put dup 4 /Xi put dup 5 /Pi put dup 6 /Sigma put dup 7 /Upsilon put dup 8 /Phi put dup 9 /Psi put dup 10 /Omega put dup 11 /ff put dup 12 /fi put dup 13 /fl put dup 14 /ffi put dup 15 /ffl put dup 16 /dotlessi put dup 17 /dotlessj put dup 18 /grave put dup 19 /acute put dup 20 /caron put dup 21 /breve put dup 22 /macron put dup 23 /ring put dup 24 /cedilla put dup 25 /germandbls put dup 26 /ae put dup 27 /oe put dup 28 /oslash put dup 29 /AE put dup 30 /OE put dup 31 /Oslash put dup 32 /suppress put dup 33 /exclam put dup 34 /quotedblright put dup 35 /numbersign put dup 36 /dollar put dup 37 /percent put dup 38 /ampersand put dup 39 /quoteright put dup 40 /parenleft put dup 41 /parenright put dup 42 /asterisk put dup 43 /plus put dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 47 /slash put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 59 /semicolon put dup 60 /exclamdown put dup 61 /equal put dup 62 /questiondown put dup 63 /question put dup 64 /at put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /bracketleft put dup 92 /quotedblleft put dup 93 /bracketright put dup 94 /circumflex put dup 95 /dotaccent put dup 96 /quoteleft put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /endash put dup 124 /emdash put dup 125 /hungarumlaut put dup 126 /tilde put dup 127 /dieresis put dup 128 /suppress put dup 160 /space put readonly def /FontBBox{-27 -250 1122 750}readonly def /UniqueID 5000790 def currentdict end currentfile eexec 9B9C1569015F2C1D2BF560F4C0D52257BACDD6500ABDA5ED9835F6A016CFC8F00B6C052ED76A 87856B50F4D80DFAEB508C97F8281F3F88B17E4D3B90C0F65EC379791AACDC162A66CBBC5BE2 F53AAD8DE72DD113B55A022FBFEE658CB95F5BB32BA0357B5E050FDDF264A07470BEF1C52119 B6FBD5C77EBED964AC5A2BBEC9D8B3E48AE5BB003A63D545774B922B9D5FF6B0066ECE43645A 131879B032137D6D823385FE55F3402D557FD3B448685940729E6E22F4BE0E08C6505CBA868F 795093F556B64B808DD710EB936D3AC83E5783B5F7E56D363A59A026A5619A357D21C4E77BEA 121EB24B09027D1AAD93158EDF912940E91CD2F17922B358858946447773730BB19AF9E70453 E1B78D5EDC123B273A979891D6D5E624F4A388F3897E13B045E34B4EE2F5E4FC5E996D354964 0010C671DE14D18B0B3CD300E57DAC0322E59BFBF7B29422230870F5897FCFAAD4B50C7C1C58 EDCD119218163D6F6E5625CCB882DB7B6D09A1586508E8CB642A11C29A46915E4A96E282079C B21922C1C2E360B487A45302FD22EC8C5FAB63E54B5E844D4B17CA2FFF37C69C366DD72AD029 22C14C0932F65ED03E4219C117962EDBAD2DCDEAA9C10CE8AF38A4AE52E2B377245B0BE19A77 D6C936E7530CC4D0B78D0CC4A92698FA2870FA54F2D8503E2D17B3D52FB2FEBB09F2B2AF0C2A 1892039EBE19A690098799A858E3D39631BD6925A154D161DF3918074ADA6BD52BADDD0ADC3F 07E2D9F15E27CBF7FE8B98C407205C811121FA91E059F2F99322FED63F359AC9DA97AEC383F0 67F23E5DE33151E80F0A88AB50FE8FDAE4A5DE93C1AE2FDCA06150B37246140C0E87CB2325A6 0D2349162AE3AC93144EEE1E665A1289105318FDFE86B6E76251CB25ADC967D3D0B97FE5E279 E1161736AB22B4CA510B964342383A840DEFD38F96A7280E6AC134E48D740607FF2E7804164A 16D47735864DB8456CBE4233242EB3B447F7AD444DC16CFB69AB1E515B3C3579F0E847488107 99D7F2833DB6E76F6AD8C924532F8F5AFBCFD939544BB7DA501D8511E37090F3A56D06FBC17A 49C373426BC6D94E829A8CBFFF9A2502C915E2823AEAE70E39F00BA99F8E6094A024E3C48503 2A061769D653CDB17A06D8EC2F407C4B9217671851529647D0B9F261E39564C79FA0D79AA7CA F3D08556C66F08EDABC27870CAFC00F0F1828E93929116DEA5F038FBF92837E804DC9CAA7EC9 D967715C97C6D5770B5913C4513DD239F55EDB3D6E270E8D826F6B4D0E7192BF8A1200475AC8 E1A30A8F6B7428C8D321F93421F8A2F707548CB12C6963A2CA8C47FD7FCC6C4FE8CBB31985A8 9A0D0617119A892A61272ED8E264418418F2DFE0F5CE71FDF732F0DBE1DDCBCE2A7B6C2068D1 EB733FFEDB0EF64F9BAD513D3267870E0E90147C6B4BB9F60F99074CE5675F7C4FE9A4735BE7 E6D1081203DEE5A7DF96D68B2AAC736DF07BDD5BF994EC28EBE13D2ED5FF9EA89FC822339AA4 5DFE008523F617DAA3DB055EC593372FC2752BE8FF2FD825B13BF7A2FE7A0FBA28212C389C62 B64E9D156842356743272461B4B56B9FD5BB19AF45607E6E3424455A2ABBF21ECE6E2EAC5849 9533299F5A70391C4B7E9E95AC00A7593334FF183B9515F642EA934DAE6FB630EDED6B80389F 70ED5B3B96EC7C116B1124D4B6C90FE571E0A1339C714126128DBA4CAF5FC2C035579774D403 AB3BFDC134145AD2FC303F8C1FD5ECBBE201B8C93DC26497335822455921DD3B07853CE5B859 36F54745B3CF0AD0523D83B16C132E600FD7DC81B585E769207A4949ED024372D59254EB97AD F5990992CE479506FBE4A8BAF5B46C8FC13C7C0CC5270D37ED08FCADAE4AF27B0E64080FACF0 558C85048A599D567054DFB290683577296CF1613299E7354B90C2EB4512E05B3350F681BF64 12C688BB05C110110932935913B5F888C20546BD51E414DC04255FB51EC37CD47E975F97267F F78598952239F401E8704A903D9C8D7B3E72426FF13CDA6D912A4BAEBF04E9C2186290BD83D1 040CF238D04CCE1A1D177529EB8A27731C81393BB96D0858277AD5D0AE1935F89638D528B1B9 493532D7C81EA6020D0AAEDC98CC93F644EA5B5D134B8CD94A5E46B883E1F54A7A098F230C43 7B71049C0B2CA37B72915638F7088666438DB22AAAAFB84590BD7EBE4AA544506E19E547F3CA E50348674B3CA185B542FBFB2594A687814F0C330BED938D482F6D55DB7746AF7D052BEAA978 2E812369AB4AE39F0A9890DD75B6159731898692B986063985AFAFD8CA08714BD415180ED6AF DDE8D5719734C74A055FE635DB9B8908488EF1481D72A90C9E99614F973B243AE426DC24C4E8 A9A12D6D5E73FBA4EAE1BA66CC5B5B54357095A72C84C4E5ACC4D90038BEEEEB23E058079B32 05C0C4E0AFC015C650C4F4EB4578BF6DADC04E9228F5C304B2433F8D92FCCAFEDE671F2F1921 8D070E622F0F5A6F3BD95BCE78DDF81FAC393757517FE2E9C02B025B151541060B87C1844B3B C754BBD0C9F9255A9FEB28B14AFD3B71BD0A916CA17957E3B78539480868375EA6ED93BDA275 D793344BDE7E59DDA118414AD315BC177937E056EE85E41C94C370C5F5B8CC34D334A6085544 A3A2C0AC9245A3AD03C278B39ABE17F945E0AFABEA8F9551460C19B7E667DBF2BBDE697AE880 2196EA5205142720E966449D85FB59B9F711ECAEAEC9103D383F58EBD19E77837C42BC90E44F 0397E073656282F8359362FFD450FA089C6911577705EFCF9537DCB916B7EFB30B4055A6DDB5 03E2983D1BD53482600907D9160FAD04128F4DC6343242E0F33C22286E6C91819F2E760A1788 6917A12E6346794AB66BFCF02043371E13D3F355A20C583E484C94BD407DC2266529CC993243 D7708C22C4EE4EB9DC2AE1228961E6605299201CE90B1B0547B103C4854E186492F99623B8B2 5264C6FEB01C3D9E86B2BF8DF607A5CB944FCFB174C233D843793E87801AAFD289B7FBA2E2D7 0E3E08B121A872333FD4064A3BEFA3FC9DB8382F0286852E322CE17D6FB4B31858AAEAD12CBA FF2BE948CF19C1BB140114AE65D26101457B1CD95D1C9347528B09CEF9229913D349B5FF5F51 869A7E7D929B82F9736797F4C49DF52B2BB98BD87BC5483ADF1C1F620F70BBAEA51D554A1664 376C9FEAC4470E145C1138F27D16CF6C325A0A44C53A0ADEACB28CAFEF2A5A09FDB2968BB229 16F47193AB3504E23F103A993D67D48F2EFF36C306FACE6870C0216091A42531FB07605C0DFB 554E46660EB27A8503442812EA6AAE3D326A4F9EC58B6C732CCE096DD512A8BB8A8FA7CE09DE D476B24EDECD9E39F24E0A30BE0C7F0DE109CD0E66196F3D55BA8298C569C9FC1D36FED89E1D ACDCDD6A5E3E92D5201584982451C378F34EFA407B65F27235CDC570BB7965375902CC5E02C2 354145FF97AC9278BFC4191A286BC58CF9351220C57FC9C4CB450AE57D46C2169999973EC040 53F53FCBAB1681B17D6049F0F0786AEBB41B00C8CC615EB6A5FF5929283A93D22E28050D0D02 BCD0BD18818ED6836CDDA8DCA69093E03658D26EF757319CB1E738D7AC4BE9EB6D1356D9B34B 777E4FF4F2459288500E8564EA13633EAD85E614DD9CCA149CADE40F8D1DE3EAC49B16F9D954 953C19C66334B456260CB46C84CDD7D098D39E90920DAEC6D7A4523E54F6229231F5B5935B4B BE67A3AB87C2C8C2E539376665FDA5E14AE5F6EC57D1340527026C7B73B99F13E7DD22FAA6CE A155B79CBE80733A40E24B62A1FB88FDB4154283B8C5C377ED6FF43C975A01366BE13B9A1ECE A1954C62EBF209D4A0761C6D7FF6F1BCD1196E4080030EB2A8C4DAF3C941F3CD5FDB6EE95FC9 0824F9048296C56B3F787218F3D546BC2AFB2B2483E1ADDD112B7C892FD4BA8B158B579098EB B44BEFB1B312E0F42F08BF77B43B438A231C1110A56F89BB1E36CE90F5A5A69138B7A8D840EF ABBD0C63E459021227F62539C056E90C377C9563D1BAA4168EA5AABCDA5DED1BD8E58DAEC21E 20E651E0B783BF605DDF8F786928F7DDB085AF660EC41C26EB4BB70B6071F5F63D7427E3D54A 05F28178EA6A1C00EF8868D1FA78093A91D3E4BDCB4A40C814501456216D7D164C7A82B4BB5A 16220F7BBF07B9D11AFBDE09CAAB3FDBB6203C667EF450B644B7E536B1C80BAFB4B5E5295B74 7A08C4E843DFFE087DC105C9BDD9052BC2D86BEC218F9D49E2CB9618D9D4A3422F6849CCD5B2 41C0D0115DA98661ACFE49E8A8CEBE1ABD00E6662A2D8A9C0FF1A6808BB04D5E46467904C168 C65B7DBDD1A0B5456AEEA445CB22C77BF3F7350B13B4E2423CD11A84AB6834C1613B09BD7984 23F2249B32EC8290D679D14D3E0935AB5CB188D4F845ACFF621EE3E0206E6CCF2AE120114496 636F297929EA214D6416E639B5FF5B188F38C62FF67C969E3FC492237BC7D5D6BF16604C0C94 F2469C67A225F6CFE49EB45DB9423874BE7AC48A009D68D028245BF895C1D00C40592B68FFB7 642386887F137353293F9D506DBE742B322A5AF5677197B8DA6DBA4829F20A02E0F8A8CD140C 76F9BD9C730097E0E140EE2EA2F3C71C714C669DCEB650E87C98EDEBBCEA6A5966D8965AC0F8 DBBB858B77BFAC279AE094995CE9E7D78E387036652B0FB576EF90A777C664C80FD7C2C7B9FF EB52FFAD59629217F293F54552ECBCBD6F05B326AFEDB82B079D68104CA2660B9B43EEACFBA6 20EFE2B1CFFC84AD5F98AE71D4CE28197A7AB40EDE026A9986F73DD0213C1523112F64FF23C4 0A474FBC44E3266EE0AECAE9A823BF787861F3F9AE1BC0726A47D8F74B70D7899A5A2E40A2D0 B5F8E229023ECC4E5B30F914F3EFFD4481FCBAB37D8ABF4AD3759D2357BF5B7416CF9AE72A9D 0D9A10892A70FC0FA2F2C20CB2FD8D80CA9C7530CC1465D9115306EA5DD4F7D7FF60979628FD 78B6F0D429B642E44CE21929AE076BA999B78DFBAEBD38B0C261BC566C5161119CAFE5C3D0CD 02F149F5D24B241A9CEC58E9E2E9F72A2862E2103D86CE4D93E612CDB82AB33215C2AEBB8D30 E34EDA53222FE67843FD747F9CB1D7C2B4E87D71498A1D5BA282EA5BFB3FA18719124FD46A98 ACCE4BF97E480A13D5AB27689CEED619A8595E613201056C5E137F618E4F4B41B3B5F247D0A9 E786904DCB1E2AF7AE330C11E4CE29B6C75CA748584E83B5621F2321B730221A0A6AE75FF564 4FDF0FBDD7AF0627D4CA801D0EF9AD04C55C238013994B493B6E0CAA0C9EFB6A8FE46E8F120D 1CF4F60453A6858D2F49FBEB90D21CC6A67D2616A506795AD9BEDC96532336BF65679ADEE667 2E8FF95DA69F013D64D7121307B932BF2CA4FF2623DCFA5D8ADE618868D6FDF74FA9EB4B1D81 2C0F8596C9C14B807345EFF6534001FB3BFA4B5CF929767ADE5C5B1628A1EA2D0805E85042F1 E31099EFECF5A542BEADD11B41F1428FB471DEAD028B55BEE01F9429DFAC0A6BD3722C7EDF43 D73A222B883D305847A200043DCAB3CCE0ED7A22A16210700D98EC416164F8C5A8B13150308F 253797903F8515F065034EE7B5C42FA83CFFC6FFBA08BAB2969617C3D94213762C611E8DCD1A A82F90FFB2E2C0E570295EC8F36352583CC4C9DE7D1DF3E8774EA47EC79FB35FB6EB954E5733 32F582F2679B13E218526451AE5B5C7F0154B8769119E88A6E93BDE1655287CFA8663EAFDF09 C332666E2A14F562C146C9F5CB18BD22B70F98D3D0917AADC376463742BF897D7B1868EFB802 73CD69F079790DC6EA395987786A1EE6D649D725026D34F8A15FB57EABE12757E49F30D2B7DA FA80AAE0723F905CB1D4FA4C21AA68025986A45A6FCB4812B7B2698910E5FB950F2280E3A60A 0A7930270A93EF4F7929F2ADD145CA87872B8B713FAA428B10A1F419E985E740D2649A29A3A5 E0D691EC7EED9A5251A0D76D6A6D1F455D308BB7324B29A92CD01006ECEB1128DCDF5730DBA6 00B5881B7C3722C09074A51C45AA8C26A3D960944FB062A7BEE0B7FB1D06B5C3F0CE9F283625 2201E0B3121DC1813D955A3D11A3B41B1B1E74A2EE1E84364D05FA9A68405CBABDE0009B221A BEA1146608A26B66FA93D382DA5ADF94BA248F14035AB0C03EC49458C7AF3D9867682D1B0DD0 66136543EAD160500D49912C5EAC3B24CB12AB6504C837199186AAD6459B320D69265F230AF2 39890F5BCD0720FE71D3CC95295982EDE49A9D4FEF248F7FC3566796769A2A4B205E93DBC034 54162CD50442B11954667199F1C43FBBCA8C354F43DB19C1D096F9186A1B200DA03F81E08DDE 8DCB88B2FB1886D246933B5497EF4782DD56F5A54BA4D8A5227E4E5DE31B2231A26C44103F7D 556054A2D4CCB8F57D7F56DF346467CFAB794EE825F86F3C5E42339CA4415E8100715745C770 705F3156F7C4ADC9AA98D5B72909815EB12B55DEC84724575BD716F0607DE90DADCF41ABED55 CCA9CE2C075A851C9155523B109B6BA66A5DBBFE5159FDAA892BEB9BE909FA491B29A7395BC3 AD8BE8605AA7B57D10BC5F96A02080F39B111CB1D23300D3B6269C3A696363156D3D0E99BDAC 071BC920DA194859865F6AAFF48AE35E558B99E0E88D62F21B7C7A3640DF076EABB7B67025FB F9926E8C469BC5494D501DE9AA1565B428349511B5A2D3D9DDD67CC6E6F06D83B28857F46244 5F32AF11D71946359A66C9D7E6F1EDCCC0A295688E239D18E6FBEC696C21F5B2FBF01AFDA3EC 39F0A76E4B530528E302A73A75509A1035B4D55035475C984B66D0AEB7F423E4EDAF3F78BD97 35FE8FF17CCAEA7D245C0257650246C90BB99E1433A867237BC222BA0B96D4E332BCF48B8565 D9F00EAFD940C10F1EC44F4BABC9E4B74919039703BEEB805991F1CC3D9D7CC4CDAD755444A8 CFA2AA908D66B88B63551B7196413AD3614CDF428EF48CEA5396B5777C39CD7CD285E9A75ECC 5E028DD5C291E063326BE2421977DE683ECD670361645B6F4495ED0ADA49E2C3A341D1973B7E C21AB13BB4F8BBDAD0B31EC43B0F6A3268B1E667298D95B3BDA5DAD45D2241D851543FD03F1B 26B6172B88ED6B3A1641D4125AF70CC3A4D425D7226CB034B2BC7476EF5E08A1A33626EC8B67 6A9ED37CB0543443705BA5748BFD99EBAFE17085D1C20A85371481B1FE5F239986B5ED471B21 5F821BEBBFB2FEBD4AF60B53A1ABA5FBBA118C0F121A1183E8D1297DA1882DFA5140469B2522 5CDE835D18462BA08DAC0673A4FCC6172BEDE2FA38373DEBB9BBAB9CE158FBA3D831499928C4 059C086B4CB70DC0F2E48EE03FB4887CBB0B45F8FA04D7EF316C864055D55FFA990419D9A83B C08AF43EFC14870BB40840D12CEC93306A2355188F9367C512B4D0FC1E039AF8A85E29BD8BF1 BFA9476A3FA2876C58933F713F0B58CCDFC6914D7134E347F2816EEF956C6171B313BA58C7DE 279178B9BFFB30972D6B8D963202E4DFC92E9DE0BAF43878FBFA9A13F30EBE1C9EFA118ACF87 EDCA5E6DE8AD4F41C09F03465E20BE82CE8226395EAD99A8BB871D49E989E486626D73CF15BF A569F3CE25391F477047C402493A23B55F70462870EBA3A681A8F8D99CF7C2C81C70D705C392 ABB88587EB849662B365F85C241DD765B3C295F0B7E7EF57C7CAD259577D8BA18DF21E664888 EEF38DD5D9F984F9DF4B51E28563B787C8BA7A96BCC3EA9E3A26E9B0A9946E642CB59170A89D 526FD1096B7C09108806EEBCF387FB03959D54B418E76A6A638407ACB5AE8FA4A7A5185F905D C9A61FF94929D3C2BF0D92717D81B575FFE8D17E5ED3E5197CEE88521AD4F87CD5F57E87BC33 F077C90CD13297E91C49F226AC5A085B73254D5DD3871C97F873360FA05F8F7216C867C8411A DEB944B47BB5305C6E7B51A9E41916AACEE057976CF4BA417A67E68C4245E92953C609AF2B8F 658DCDE16D328DEFE4CF9EB05DE0ABA6F076122CAE1110EA641D1D886775B5C5908D4C32DEB6 F8537A35F6DC6A4F0E0216E93BBF3AC1EBB21EF00BD2D7CD787C17915788D0CB4062A0766593 1A30C43B483FA325F9F92F45CE6CB060300B818637507FC323EB5C1958FF94C7372726A7B68C 9F83B07036EF06FD57C4D174480FEEB0A6441FE2DE8243F4621B553FDAED2254E9EF5B848F63 2CEA1A6B9F3D2E1EF7F770F5404AE0F4F3C912EE3281F9596B42E01325E8923923703CF60F76 03B7FD89888FAD0ACAAAF1B1A6463A3E73525840E5616D5C8E7F66683F2135F3E4D0EE18FA84 32AEFD05C3569A4CF8EFA471F0A1490B4A55093A64659B9D112EC90F42FA874F3F8188100EA2 F157BB4F9F52A1B60C8ECEA96E222EE4AD0C6B70B2B43F367D4C933F425D49EEE4C7030EE050 DFA7CC6D044CB9E20ACCA84A80B9F1571927E2A312E5A9991244FDB6EBAE1BFCA4820C193703 951BACCF931B654D6BC3851324D3394A3BE41DE2523309D5FAE513F18CB65C9D135C5F8EFB7B 2622B991D8ACEB91880B22944D26909B3544578C19C1DE4A16CB7CE5FD26EDABE394AC53B2F4 66E27ED9FD7528B6F7CBE0C4EEDB4024C76EFA6EEE427598A18CAAABD3DAF43F462C138504AA D4517FE9A93E25D49314266CBE18585671EC97D8016DC14774CC105C2807E8D79E76613585EA 738B346C49534442BD3E36ABED00E8A6FF0C7BDC021B721E2DDC00B6C3E6F42A2F3C98DCF7DA A873FADE66D8EE0A21A958C725026F4A439BE96A9405C808649E54177BF01D6026A6B759BAE9 689995DE878DA4EC878A69BAF3C387CEDBD62092DEBE87A063E21D01F632C247EF3F07574282 EC0E245DFEACFDC38AA46171D82616E121BA73B684F869908E65AF1C63A2EB7E812EEFE3C3F4 954E10463359CC957EAEF32A49E1D341702F2DCBBF1522EDDF1DF96F8C679F752C130546594A 5759E7944CA62474D30F5373801F323747F58A04A8FA115AC67309FAFAC362D6AF9548199389 20277628E3771A03D50A13CF80031E63CD4834D0D47C5AC75B7B22182EB95D8DBF64E531E595 A1DC9B5D7D093698CEF3614BEE91F73E5625F425CCC3C4A364BAB995CAFE438D8961A14E67D0 C03D8CBDDC4CC8C34D7F9C2A815CCEAB4B398D21CD45423650D0A19A0AC8654175C7E9A43FD6 599D2875518A431517726948BD9FA0C7FBD59D0A62E979FD9254AF03D216FD75734BDA875F66 A31AAA8F131B49188AD3AEBF2DFCBADEC488DEE91589B08297A960E21B4C472B21BCF55E1430 E313E1BB32EA42921A240917EA08C90AF9CD982444B563C1B823104D34F64DF37742F42D75C6 D6B9214325CB6BEB0280F79723E9A975A499784C59F44FE5C8FBFC9FF7F5643A5BF9E6E0566D 5C3134CE761811A725D9BE99CF34DC682243774E6A13B21459C2242ED68DEA64E24E8DA19F08 99072C0CDB2A807283D5378CB7D087D1B01F92E47D1D96DB42B57FAB36CDBB73E1EBAA81D22C 521A573C18067FC8EA38713C959046C985593AED0DF31989DEB783AAA57ECF01606C675E5ADF 81D845A542D50AFD29C98CE67A38B210EE23C9A14D23043F91FBE77ED190B43EFBEEA41382FF 8DDCA4ABEE4665B67816531F07EB8043DECB836794615F3C334B8734A579FA0BFBEDDFE32A95 389C6110D09DE30091EF2F29A29206047E8378A870D9831DE115685B34066B9B507E8DCFD6F5 A23B5CFE5E74527B30705D010CDC71BD90DB9A9A53053F6B24E65DC4AA0F7DA29D4D66D9DE8C 11354821B14EE965F16597EDBC5BEE7D4683E20C06337CE21FD1A2A5D78FF1E945ED13ACB556 C70F89A08202663F2622CBCF480336B8CE580275514B24430C139284EEBF9FE81CBDE98C00B2 AB9F85BA64E2CFF0888DF49C600EBACADEEC43FC0A6E92C499416902CDF94B318AFF4F6F4923 044EB2EF3A88D0D94CD274F40488309E2A08C10EBAEFEB2759D9DC7DBE2C0E647F36C21220F1 1D88299117AC699EC7241EBB828A03D18A58F8C7AC0839E929F6F58CCB8613D8DDEF8FD6525E 069613D644653F6702B0B097A177A31FCED5F7131F8A3E5A420D6C7684F2BBEF5AA88FD91243 8F7F6D22263373CC04446A640953812419A21793A204146A1296565E9103C1DAA633DBC79BA9 E5504EE0743946C1FFFAA5357ECCD3A269B6A63CBA0C0A9C76BABDFB28B0CEBB607CFFBAA692 360697C69E1EDDA67E12874F3F1260753249307C4572F363033B902FA48FE237A4F65736BC9D A310CE406AB83059F02F94C8C9384F6811BF649506CAD6554912561ACEA6C1F4F1F2193643E7 5457E7207C55D0160BF194743BA207D4431FC2159A4D593EDE6B1AA19F96ED07CA67505EA417 C85A3AD0F87EABA0716C41BBBAF003881EE12CB4892184828BD1CDDC94AAE05C19999A6F1D2E 1DCE2A94C4C2902522E44B22131192CED3D42A3584C98C2D9301DB14EAE7474014C04AA8D2DE A1755E5F9037D3E3821042366455AE23CAC2BE67E0A595A033E98462E1008294A00E463212A2 6B4B941255523A3C9F39197151E388EDF193D510A23F3310E18FCD55019DE861208F9985BEDD 65AE125204A6DF7E8233A25AF7AA151C3F8BAE7F6864386FD22EC8A3F5A179D7C70FF9E71237 EBB2217D09DDCC061D57445E8B9665E22DDDFBA4CC18B5A9DFE15224697ECBF4E797E3042AE2 754EF1BB9D4652DA69A07F57EC6162EA26D4650FEAA52F9B39AEE8767C125BD7782D3605E19D FD2266E7A37B58146615D5BAE6B16633D5280D2CF0234B0114A91DD87AB6987FF0BF4D8014A5 24AE04E18813F88D00BECE288012E8A285214C8ACEB7A5EF665682D463462F04E4BA0852CDC9 8D6982DE873D1EC644F44B7FCE18778B9D8F130584CC3F3A8D7A51035F10167B8E572BE50997 EB738381421A763E96D785AE567981C1430CC18A79B8F57557588D3842795F2312C4D3E3DC3D 55D54A358A9C0B031E91185DFA97E0F5474CC93CC71BA796B4A842C8340360BC584A1477608B D95481DEA6DB57D819A8F36BC70C09889E2614A2BFF7C74D0D1D09E1454C58F7CA672ADF64D0 ACBD1F9D3AC9203D7D011658E361B499818B4BDAB372524A385E65D4882A442BF53DEF1FB2C7 460DB0F59ECA306C74AED3E29A94796F525E2D5DF9BE7A97CE6F0013C0F39476A7BCF610F4BB 5E83D2CF1A1D515F899C81BBB60646125408922B45689BDBD82F14A2B9BBE1F27254A5D1BAF1 3B2128846E4DD8468CDAB44B9F847D31DEE079DFE5FE51870FFE9F18CAA25A2FCB978A46D747 544F2FE51496D04EA5478B209FBE843025BC64B1CBB0DBD43DB01744C471327ACB3C77E4CB6F ADD41B9D4D1C0BD8CEB11AA2A239942C97D1F1594F6E4D9CC34285E4DC6F61E80CE1FEBAAD7F 9BFF9C00E0F06091EE76794F0B859B46447CD627DB60142A462A7A3E4403E839DC6D4F08BC6B 50E8300A76DE811EDD85431CCB895AF3045425F4099B1AECDEB7312E84DFDBB373309C9B1FF5 72ADC905A41421A77699C8885879F4939E7EE8888E7CF88EA12401C1154525807F96C6F192DC 5981ABBF512EC4B4092B515A14262519A630F20DC7CEB32AF0A2A10443EF54AC376851A23F6A AAC95DFC30D0E4CB5E14B5CC323CE4D95D3612D6B19A877973B42F32CC03EC67497E3D9AAB54 573B36B1DD5D096618A4ADD3A1FD077C1B00C7E6BAE8A90C606C979A2523D5AFB67730416FDB 1F28EB72E6F7079B84A903C68942C9A17B1D71C30CCD288ED9781E50212CD06E5EAC59D45034 36E3DF8ACF1F63A8B9A44C8D159C1981168E5C4BF7CD5C5069EFA0FEE41BAC93B1C0E0BD9F12 ABDBF5C8404B53C102DCD215889A49F23C435A962CAB0C48F763245F0BA1E3B61C6A6E305D8E D49FC181BB4E6DF8483102F70DA144937C8B5205D240D6616F1281E92C4CF018B5E26E74CA72 9A09D355F97BD76563A4D62A3D643D5C7BA4931B5A3E3A8079286D4365DA4E4F63236E4C5E61 F6743472B1AF5A5FC97BAD3D576865E55B3E4F214796C674C902691CF7FFFB9ADF45B6BFDE90 964E83FAACF3C1FA70C53F3D6EF18A8E13FF85EB35843E983393C292D1C4890F83A33DCE96D8 3C4D38B4AEB6B75B50E7EFFFFCCBEBA8EA3BDA064BDE07DC7726113C716FFA47A00D33F49115 4228B6A20737895E365B3EAD997F7D2F9999EE6F4713DD02AF593E6C105A27B9001E1FC7C57A C408DB6309A6AB2C3C6FC6BBE62588AABC4EC9420A72C6DE5C0554547069E15962A141C4E2DC 4B38BEAD55F8E08F14B9A455B81A5CA9191B588A5E587A1471E9F1B30A7A866B19BBADAF5AFD 8674423D799F515D2B59E289843B98E57F6D5105CF14929DE24DCD833BBD7FC14CD0AF34A8F0 7284049AED310B36D0C8559504248BA11B4C6697D5B74353375163290F23F63B2C611031295B 2A5183036A4DFAF1DABFB1669E534A8BB28ADB16EA52EB238A242757B8BAAF53E90C258AF04F 9DD1B00B100CC6A32390E6FE91F13F675A3B78F5E23646F1448F7D6421C38A58DAB20EF56170 BE71AA9CFC5EECBE809138A9FE8B46B8B30538174C23E6B5DC725F3A0507F944963D9FB47C82 58C4EF8F5D4AEA6A5860A95E0B96943452529441C4C6E8E299DB6CEA80CDF2DB74AC3A89911B 55E225B3F20D3D605979045C72B672DF80FF1F78CF4992816E27D225A66CCDE49F357E2447AB C6A570003AABF2F770E2DA3F0FA89E9A01AF0BA430C925E8F764C77B59FF767851A7D6570106 FB852F3047CB0AA041110529072160AD8EC569C8C1C5EAC5BA56EA030D104DA9C6D530C089DF 3E37148F4B8B0A005616F946C83A391DD7E7E776FB9DD3D52F06BDBB5CAF1227C4BA74861BC3 AA9A85055EFDBD275508DB8F68BC3CDF69DB4D1F825EED993B84FD63B237A38A4CBD9071D0CC DAD295F3947BCD1AB385BECC35725F4F287450A49F652347C9B836A8C46A58E044853760AB10 FA647FA9862705641B5C411A2EB69086B3488F4319068C959E5D369FF0FEC606665B6C19A567 9A96138A966AFC86F64F803F55829C8CFC184D20D97F1B625ADF7E260EE89F20987FF29DA9E0 5A4C12AD48B56404D0B2BFC398D5991C8CE5F81E67D71F31CC8A4A6D1EAE0DD4834EAF3F7DDD 6493DE2D1D31606241185A05EA75A6036AF2A4C60079A9E21A5F28502560FEBA1820361A4B0C 2D313742A2E6CAD252169103FBDF7590B38A60C227446E944ED13D91D5B3DCC6BC8A4737D4EB AC8BCFBC78E243296A76639D2726D968463E03E3BBAEF4CACE746BA11DE8DE942E1AA4AA29E3 993212FD27D3A23E55C731617AD58A98615DF3113A6537CCD5E4CA5EE7715F446C009F423622 CAF9293D9C25EA96CDEA869C00821CCF8E0E146A6977AF4FD1D6CB46D3A96CE4559D7EF177E1 9797615C95C51B2AC6DA1A3E700D4AAA84603E9E9B4B0F2C084CE4A17BB119B6C998045032C0 4AA21B8B4D5A0262387F884D5B21AACC93F1FB74EBBAAC13E092A860F9875B83A4F2BD56ECE6 B63CA3575EF0601F3D0FC09C5FE9D7B2523A88C37C3360FF2E8A3A0D6C6C9E448CA93728991E F2BE037DE5FB059A72ADB03B1FC85C49A84B2077D6ED25DDED1D0F9DF4F137E4556A9D066927 217488D7ED62E22313109634EC5B291842369E376F2D2302A3D9DB199F0AC48B228C8218ABE6 BE8503502672F984C8A7A97B8B6AF3EE1C15230C5DF8FBBD04D78B28C3CA61F568E0EEC6212C 3DD622884AF4740BAE327F89485685C94503D1D86AAA538110D7C9E520FA19C129BB994E3765 8B6F0D301C8899CB735BED20E929BA4E7B6F3592D5B945203639979C6A459BACD0B84B399828 3F3F8CEE039A3E78C76DBB58EC4311BACB39E1AB2B8C1E65AD657CBA210CEE930CBCCE737216 414A7CD90ABB953F27FDB0991D76A23B8122FE3A2CB26843A4DA6681ECF996E4AD7A1102F4B2 44AC4F6E431BA1E9F0EDDDE9DB9399AA8484917776F256803BA5983A2575D9371A08F2330CC3 44B89CBDFFC5004E00097A757C390984FDFDFFDC459EECB46A2A1C8AA6A1618C2B1B49224E76 0AB2EAF6893219EDB7E107208D95D4D3F49E221994647667DBB63634E327C4DB6585ABB58D3E B338F272AE572E9217D63CFA8F10C87CAB078B68F124E0537050B7DC1A0D1094B9AC9FC21F5B B17756D65C05801D59E58AA02C509CCA118CEFD2C91D6735C1DFD01DBF1B36F267C4DB0C3651 CC9F1B325915E23AA43EA1DA505179DC098A3DCB76DF83BE080B733DC252E0A00BD702BF57F1 923A978FAC404F82BF4DDAD59B16883CE7C6A0F84E4A4E58A38FF675335E5CA5D59EA3DF82C9 3BF0CDB775B533BFCE6237659D0B97476D2C14120A35BC6970EA9554FADAD6AA7EA674529B87 603342FAEA220B9A0FFDC1236FEA243892289258940C2DE850FA7F4A14B6039EB93ABE2D6B60 E78D92B66E53C40066138E63A10A3F5D8600A3974652D7EB79C12E16D5D83761AAEE32FBA99B 762B564374B60F3074040D30343159EFBCBC67FD1B621181DDDA4EAE32E38003E45B1A21A04E C69A3C05EC4A7A91E5CBA3FDB856D8127D9ED6C8E23EC8887D79ABD2FC139B5CB04D181E14A7 43AA5D5CE886607534117A5832DF964084FCE620A465CE886D1A23FF1CB0FB812117EDA34436 5AB72AC5128FA0FBDC426672391C4B61D3E60AF0815DA6D908BC6201F800C705A18A2343FF3D 485473FCA8DEB44D821066FE148D3CA23956C99D0BA4998A3E126A685B19585D7380354E8091 EDFC4E684AD032CB0DEFC5CB076A5AD1E9581E68B3826D09A96156E144733907A23FE62AE723 9871B1D7B790D74D7820F9A096399D9120D5A78E2EAD9D6BACC3DF32888E072021AF81166F6F EFF32EBAF11A8DECF4CEE3C07E9A30F175AA22C7C615ADA194480EEFF72FFF2E97BB0DCF5DC4 85428B08F173549A0132B396E7FF53B578AE0939DC0CEF80A537B1D713B4D6BFFC987B34943E ED13E4B723C85252F9561031F3E2144C7B8C8B5F3794435E1293E4106E8C0114A14AF6B37C7B 28F7EBE6D321C4BAB2DD04D08FF1D2EB4967092D52E8E5F1D04875FC7E00FFF8C3E9C7336CCC 8D709EA09DEEF006E5E809CFD7F377FC4BB8992DA3DF88159F1241F927E4701DAAEE33394645 B361BE7A137454A2150394309F69F41B8EAA3274D6E4AC2E9A94770BA1463A5B774AAD448F2B FCA1D220449D1D3D09BDE0F582E4C09E954ED577F7F9ECDC5023DDE9313D7E0AC83C496472BC 35FF3367B62F1FBA6EBBE44892F0CA9F48FB4DF1C2E6D95F030305694C91E5D2A49CECFA8A89 61877441513E02FE7700CC536BC6FD9622093892353F0A83AE630D5EFFAF0338924E2AC575AF 4E644413C29EAD6C123FEA2ECB5B4B49CFA4042C31F3D6FF535D3F881AA9935E2B5AE265207F 94254C9DAA2E7F8BC6FDB6662722CB19E35E4E10810C43B0A46450E0FF05236C08298E02667A 7E2F4F1777DDEACB198D3E65FE34C78A3C71A542A0223828BD7B57A49337852A7E38BE96C8D6 8B27947476892A6325597AF1607104A3AF0BD539A433B1CC09D23790DCE90812DF84BDBDD0F4 56BE6404F2E59EB8882779554667D48C007C2B6E31FD3691E97F76C06C659FB96A417D2088FA 984981311EC3217A9BF784E579CA42B4478F6530B3E9F0FA1D701D4D8F040B4173C8E1E0CE76 006A644DAA1611446FFAB2B218867985ED06DDF3053684F60B912AB11CE7B3425FF389107859 0A78768D85E21BBC09E3B315CF56F6F3532F3A6B1CA10034B80CAEF1E62C2D91FA0799ADBEE3 240BAC2A24F35015700D938DC7036245230BC3DACAB9520AA950D153AA79A0570BAAC57452F2 C958554992B0A965CCD7BD9C0971B6EE8357E3DD18CF5E6BEF5C74DA84CEE08E597A5DF7A21C 17BED630CB74F2F21EEC8B3C2C6DF46E0FF5D571BEFA8398D3EE38E905222C8E94ACE8612170 1195D40FCAAA271874A8E6AF62AC4D60558A485505F4301959417D3F996526A494A201C4CAF8 4BCA877DA39E1338BFE9EE163E28993545B5B989D5E8A0BA1E1439EF7C6AC1747E272716A30C CCE34112B67CA53ED3D2379C99E4264C37BC4BCB70118298D281B8056D809B82FEA6994952CB 5356BF3E41D19A2645A0139F44C7179B87174F4B5979B9B6E0ED55C00F4CF2299C6FB6C98010 E01608176D6BFF74674124669EC3D9EC262BE00B9F265C1BEDAEB13895CB58CE214F2D7FE619 762F2F1713A0829D3EB4E7FE6449A73C7C2EF52856226952B9EA375D9FE3E0FB79741ADACD2C 056BE97B93F09BE46C97E2B15B2A3C067172B90F41A8FF1952787EB93ADFB5D139B6E68ECE12 291B23AAF9EA86585AC48C85BF29259F01C2E158750E4FB1ED1F611669EBEFEDAFA8F1E8C285 A1068D065953207897F63C142234B79230FD7DAEC8CF3C178FF691F2D22BC2E17FD20D527954 B08837F88BAAA2878580E49A7D3D4B3BC91A228EA3B176020A049791F50F96266FAA79AA8551 A4DB3913346113ECBB742944417DDF2529568492D96F06360D20D644BBBB0F7136A38B813E20 8DE581E70648686C5C5C6E92FA752D8606B56143E6784E400411E2EAD4933F168C633812B2E8 208B964791DE0951EB3FF55BF687EC958399B4B34F70A80971D269AB955D8413B68E69821086 C71F87C1E60D5E78E721AFDE35380B930C41B72F4E8717393A013723C81497836A6D204368E0 2C8BBE44521C82CA5F8E3120E7ED232779C0544183865CC259A047ECC3EE5E139880FC96F6CF ECCAC3EDE4858F312BDA343B23E19703A3C624D99361C6900DC9BD1134001F17295B0C2EB754 4939E8572D50F04C0EB75EB20A88C91CFB5CD971A05876179FE794D4072D929423EA9CD398A8 D31B3CB32262800CB5EE1266111E0504C14C1FC08E60441E89E4DF7C91CC5FFB4EACF83D065A F32AB2366B0C0A844D28C803E33F1679EBDA804AFC0EF4BF320E21919959BE7B060E914F49CF 8A2CA28547DFB771DD7F78535FF95934CC749B5C7897EA9CB067F6D861064CAA233C3538F3E4 D5EAB1E756EFAE9F305B03E70E6AC14E0355AA871DF0001FC80620160DF7D218B64AA8C12802 CDC0CFD2E16E45FEB91D2A74E12031082E21A6CE76593E3C17A251E9B2EEE18A0E922DCEB758 DC42DE114893C36AFD4A6E3F1370E3D66B0CF40DF7B05473DA0B2C446385870327C847A5A052 81BAA0080C36EC65A10056619005B39D3BB17315EBE5187D1D69DBAEF5F89F280FB9F41F53C2 EE00A400CA8EED8E74337FD737ACD8EFD0D361E4C516B11DBAE751B408CC54D49FEAEAA64523 6FEA20CD8C326231E9131D003E74F1F8711C883E6AC50798C98758A226CA85949CE153D4F1F5 002E5EDB1C5AFDB33A3D5E6A4FFE73FDC25AED83C1C83533A5464B5EC8C0DBF39C3785BCF147 A4BC11648AAE5F2ABD1942B0412F5ED98A4B3A5BE1B679F66E0D0C43806A89A349F259DE095B 8538C45A1A14B320ED0C662129C881C6C70487D7EE3EADBDE833C415B992F25AB94E1F6FBB8A FDE188FBDAE860368558C1049BCE0E400368BD094C1EA808230998645B88163F77C1DDFB63B2 092FD1B772C7AC73B095AB8749E65C3DD040AE17206CA88B7507AB3321231CCF8B2144EA51EF CBDA013A011E1D18ECD5780A80C262BE5D6920178D2C129F87632A39289B032FA01FD6699ED2 E79EB18B0990B86F00C440B4A6CCCD109288A177E366D21CB16A569DEA5D20A732B10576182F 0EB68BF666B1004DC444960E579AA3FB762E529B6FE6D98E582B90EC73140BC67696DC49ED47 64615760C58E9329C02FCA556E23B11CAB4F516E609F6044FBE97289D4269AE5F78399432A57 5198596B1E19B201078C93D27BD18C8929F145415FE188C35DF3FD3A59A34AFA3C22CDC2757F 29AEA7B1D0D983F4D029E4071896437C8AD90459DAF4FD1FD173925A007A845844C6666CCD14 A9B4DAB72975E36B8C0CE9A63FA38AC0D0697F46180A06EFE2618B27FAE17F16A148792346AD 9C2C55E9836845B2A33E0F03CAEF4850C440BA483230CB078A72DA8482FC959B4EDB01FE8488 B7C5D7502F922ABF8A2195F17C2D3E974D2E5AD09E1E61FE5B723D5A4BD6336A259EA088E3E4 4FCA4DA49E017ACBA3C0D58F16A3A00E21D44F1F26693449D5D382A12C70C7959965479CCB12 5565DA2442641EA18B8DDD83D43F8177FD32298C0B3DA44D436C5AD9B85E47DF64BCA6898C1A 0EE73195F323D8B4B2442F15C7A73DA62009A31A45339DE6C491A04B5E4C383EF66A3749F6FE 7F53059F0A08C8DE4981D6A686B3503D0563A710D91B3D4587C3D12062ABC1210CADABC6F0BD 9C6F46C87C5B4F0445E7253145EE26BA9D839BF45E9DBF635644F412DD4B1738030CDCCC82CD 370587F4CBA6796A2727D3D4871BF0D8CCD867F2A0F32A3109F049AC032601BB5CCA0E6BA807 50F88F1BBF77557CCAFE6FA24B5B5D8FC4941C4113C4042FAC0D2FDD50B304BF290C26ACCF79 3E990B1A10520413679408F42399684D4ADA9CBD5C6660768DB2CE468DDF698D5BA1A73D3BBA 49E96320D04B006B5F6B0387DB59F2E20250E5DFEA9160BCBF855801BF6998D481612D82F7D8 D6AF0B2034C9AFD9BF26E8202D9E8DB1633167D0F073A013EEBF466A4FAA74B6A5055A74932E 64AA1B75A8708C9C6825141E85714C48FAE391D02A0CC9E537A7E11D1E1E3CD08DC693355957 7DF07821F6D6AA36154BD16E3D158DE669351A48CA71603C4CA0F364286D4A4EB1CB90CF20A9 DD2BCD0BE17C8C04098D9720F7F7ACB02EE63EA496E690AF57B02643AE9301F23D42AB02D414 5AFEA48D26118066FF99EF12C0EEFB4BABDCCDA95EB52AD64583C7EA5E54417C2805179F18F5 7A0CDC2C3CB502D4A01E5149C072C732BDCE5CCFE8EC465BD66691E1841956D79BD027535412 031A9603B1C24D3D16B0A3AA3F5E00FC84A30E28C617138828CFC30BC40AA24B94159AC5336E F47064572B18678738240635FD1DF47722DEA61933008B1022F9A258F47FA2AE762646EBD5C8 6B0C7F1983E306E0F42508DFD5B463E91147B198E31D30BC4A84D45C0631886D42204C196C98 01CD982ABC5387E9288CF00F0E5810C712DB51962982E3A91CAB88110C57FEF58D16621B3D6B 34C7E3FD7FDE1177869BE84FABB95D8F054A96375CB59C4711E5830D5FD13A7F4C14E4F2912A 2A4E8E3072776ABE39D3DEF4A62BB11A3A6006242437BF307DE502BF95EB193CE32BA6BB13A1 F219CA0F7EE76257B74C4DA5F0D7985BBA1A8750808D741C6080C024E78FC0F3BCD2E0DC8396 D434EC98BCC467F739AAC2E9BB78129CA55B53E08B20E35FC13B9AE4762BC784D49FDE8725AA EF34FEB464E3833F232F5D7B02BEB2D95B17949FB3624836CB344E64890D3BDCF5F459B1A1D9 7E41798A7F5EFD69F9C5ABEADA042F4F42D3C5ED8D50123F7B92CCA9D2C5806A4486032E827A 12F6F8D21A54CBBFF57088495FD86A7956D6C56C3D5B546F69ABAC67F386357E1C524679E62B AA462AE42B19754F8548C8F7BF74FA0192F53D408DC9C41AEDE772E28BC2D1FC39F5208257CC 05DABEC5F019D5EB9B22AA825D57D1BA2480EF6F1DE82C18106C6047A4E2342A460EE99856DD DC84D76A3D081B2C31A7820CDF58BA8C1CA26FC6D607FA9EB0EE5D328362971EB10AED06B8FA 23F49C996A1FF7D2A2224B4BB0F7E1E7297C4B330EFADC80A590C3F0C090F532678738380920 7DF928C685C48AF18AD3A9CE962F6F0A0723C6A84D318CBBABC8F763B47CB66E1B349E7864A7 A0BE27796467C403F9568070BF1D1A57EC7E97F22FF181FCA31C8FBBDFE1E4EA643FB5066D17 4381BE4131107072B59A83AF99BEF336B8F72B8658738A84F71C4D7EAD13D28B4E49FF90A96D 43B21A68979132CEADB2459B1107781A64073404D0F81A65EAC799E8E723E3C49CCA370F2A74 572C4B755E1C4F92CB37143954BA6C748FCFD2BC5F780C745B1F0F965E63CF53400B78F84BE1 0ACD20809DDD376D1A9B3C515D8F1781793CE9F8A4E769BB5AE25B36914932B1B0922212E4C2 41DFE0E7C24233AF5BFDC3ECA9C81FFE34931643515273378D2190DE75A4AE5C1B8CBC4A5C76 30008840DDA0E02E050CDFDB2BC5ED535A8E7698B4AB489313F7926AC1DEF01ED849ACEF2859 870C7EE12DB2B0508F4E58268306E709842EAB264EDAF84C93C15FBE45CC0350571C6368DE76 EDC307261C153B88D7605EA8F64EE7B1CAAFB5E6AA8606291D3198C1D3EC1725D7A8E97656AB 5113198CF6FC2B2515BCAD112592FB7A4BE9A281326F045A70BF02188837BD474DA9BC46D195 19267990A6DB0673901158567CE1D87C4FE76823076DE5B2A5C0225B7DB7BA7ED41F0AAEB535 5D6F0AB463CA0C2E8FD24ADC4DB9C32C5A0E3698FED1AF65AFB0183CC582897ECC050D288C9E 15EC7DA6C3EB200CDC2537DA19918D251D52F76E45075B02513A2DDA4548CD65AB129811EB12 C2E0861123CAE229993E9E43346907A4C60DD7E4B73F8B0A5EDDB30CB3D9D5D63C153CA32451 9843F9E9F22953C0916DB5E8D81DE8BC056030740772DF56F0E314D223C3B2836D34D61F77A1 05C32B57F7F1791B119B1D98D5710D4C44977C7877DA90D37D82DD9669F81E913B8AEF9AE22E FADC30D27FB913B94F8540022EC0554D6DA7D0C510398E1185C2441AD678ACC49485A48E6923 1139CE1D2626A2824FC04FCD35B8E52D9D3D9305C680B9BA341646FB2FCBCCA2B7787FA5DDC5 CC8713D431621DEACC951ED554572AB8020D7CD4A9C946BDCD2F58FE9AB0305C670E92C7E80A 079388C3FB1E85261BF22208A17E3E396D99324D215E85E282A47AEC771841BD13178FB8946B D6CE634A00D8BE0567C8735556194EBCD2D6B6AC3D5416597840A9FE2E231C8D92E044194C6A B8B4CA0301788FD2EE4747F48811341463DCD86F4B52F0AB5543FE931CED6D336D6DE4A2E1F9 1878ED8D2C238296752A29201B9CB8C063454D959C8D5AEC04AD76570E9CF59650E2B44B7E48 2B06C150C379EE272B7AF205F30CA1C2B6E30CB0D2E438DA4363A312BB1318C90EDEE938DB9F 0359B90FD6284681FD3CE99BC434616EDB354A62CE2BD42D784B742911003F05BA8BE03D1F52 FA8F0AC9F5879BC63B7829CCC64BE921E5CF2F6240FD6AD7A69D94B6340B818EE64A68FF894D 0AF596DA0DEBE47F306F764548A450A418A1C88875B8964FA725B65C77CCB6BC5939FE0E7625 74166CEF1839CDF76866B449AE2CFBD393E210EDD05D0526E454348059BF88B5AEED05841A10 C894A0C49026E064E385BAF440D7B975AEA6BF1267D360308829BD81DE6DB3D5BD47B66742D5 565607787CDB514F2C4B69FA22F053B22527B91FE4A3EBEDDA1352DBC0B4144DB5DC15AEB3C7 8CCF0CE264C76682FC1B7D3AA2566C8DD47787092AD80185D867DB7891E0CE12A52C954EFD3B 0CE23DC59C9B073685D14FC24A666DF88FCF20D0A93B4B28F8724F46D5368F2C195DC0EAB00A 03ED7A0531408D90884792E82A8B0FFC7CC6D1C2E1AB00E466744407FB81F6B9B20B0EAF2B50 A35EF6F78A9E9EC9D322515DDC6BF058B58CC6C036222F7434A1F27811CC551D36ED5169CF6F 0AA6D58563C8792D5B74F08BFF06189566F1D0C9E497CD116393EEEA1B853B5852F9221967EC 1DCFE14394C5A5C026093982FB19F166DC9F52053F1BC7F449E0285C1B9684D8853F587D408F 1C97BD1D082ABF41AB80F47D189DA6CAAD9F0A416CF040553DCE2A9C853A71151EC50CCC71A7 F6E0A0A9EFF458CCDCFB0D760AC0CB9B0BCE3D0979E898E42D43A78E17FAE3C33BAC5B4056FA D86567DBCEF75EEC322572144FC26D7F81DC9EA718D91B0892E5621BBAE940619EE3693E87FB A6BDBCD601FCAD972556DF2E1B0587A7BC8CBEDE01B02E19268F2D31C34712E4F4F29636E3A5 06013A7FDA0EB8C78FE7C2A561CD4F09D162C17BB69A13AA242B8E5B189010058A3005C16BE5 DE8975DC24D778EB03C2A59948C9BF3BB333AE0650E5DF0613C77A15F510ACB08C5C74519B79 C527B36BCE33BF023C9CAA159995F2992CC9731B6AB100604195DC5A79AC4A02D803A18683D3 9D25EBA9E584B3F3F64DF241E43B038C0D3111347CF2B421FB78FFCC03D3ED2A0C94D228AF07 C5FECCBC460541802660C19C05A52CD6C1CFF8CC805D43AF3D23FC9EC8408E73A49C1DFF48B8 6CD9B3104CA1515E98E41AB6496F4CF4218996692106BF443C933DB8A8CC275F5F1602881B68 B787738070A1B547D6EA0520CF599B4E674FE930596C8DDC4D1454B1DF79F092608FFAD0AC38 25A8A3EDB0C97C265B35EAA4A6D80C538BA24D209884A0BAB03847600E2623508DA7D8DA777A 168150698A63F5EA4ECD54309B4989ED2C7DFF8A3940384E5FE0295840C33A078C2860B65BE8 AA2B278185AA977110EB7B9A95BB0B52F1E124975D620E897FEBE57540103C873FDA64B37AA8 F82C56B1AA233ADC9B8864B820A76092E2B17EBDA1876D27B49FB5A1619881935FA499EF75EA AB18E4496BF7493420750B13D06BFBE1326406C72112F6A497459952C412535CA38D41900180 F41A47FF6859B2B8CC20C4243511BF0386261D45BDED1F8C15E01CEBB891A07128473972DE3C 0EAF60856001E6C966FC1822C5613A8D2D3704AF91C363898BE178366FB56673B9600E2F7F2A 7CAA391181D36880A86B5ED389C7FD49D231E3E82999932075696C52BA761EA299359837E712 BDB5761E8D5FC3E8C5051E8BC673BC050CC0172B9676943426C646EC18C222514D9F21BB37D4 2CF66168B74E6A4EE3CDDFA12A183697A121938BA5D51AD4C57A4BD603092DC42F6E8E15E986 D1A0153977BC89AAC6AA7C5576B3905131D1889C33E313BC29D642F84D5B5DB5D301813407D8 ECE2DE61207F07EE2F018E7CBF6C5C3B504C37400436B711756EA09327237F743D8111C9D78C A1186BF54B5487BED5F445857EF956C663F032EB59DFF3C4315F960E0F787F6553E11B34BAF3 B0FB6215866C80F47F52F9B67E878024F4C3ADC4C9018428BD04C6824BB1457CD59BB16FEFE2 AE1388FABE7B9C1C8ADA3491E64B6FABA0EB8EA80ACDA137CDEB8BCB39B5D1D038E7E664051B 76E86E4EC718D8B8EED85E5AB8CF85B6872D4E94A76D78C4358E5744023B705FE01D0B1848C9 2235AD874B45C4646E5C393157CBBBB6F08BCE4C6EA80A9A1276D9BD58E30015E20120CE473C AE89AD929A9AD4E6AA02F3090377853FF1190152E4D285B66B4CD78F29B18F856F460748A2F6 D2B1454D4BB1EE72C4D90FBE896AC81690D77BDC2A0FB9655683131B97C44AD1BAF39A3D8E30 16D847411668B1A56B8F34B40F48DE144330F7711EF447457D7FDC409D56E100D55A28CF188B D2DD182D29D5CE0050D6CD9EF549C9FEB628E20859C7E7C8D1D0A62D90E1AC0442B0B1AE7093 DA6797BB069D6FA94270F60D63E0CC361E9D95168DBD7F8314D5A6EB083AB1B6B4972A2E32B6 512AA3F8F4FBF5EBBC8EE7ECD5667F0DE7307C3642955FC083119BCC959BA8FF46D7608679F6 CCA0616825AD959761F6E1B8B77C134C33D20B98DDCC20E5A98E49CCB4EB395E6F299A411814 606AE676871914BEA847228F323852181EC68C2BE40A19F07B0617DB7E29DFBEF4DE984CC937 5581ACB67CB727A2FD95AD7954C77282EF61E432353555BA81F4B9E55E4E2A6E1DA1D3265856 769DE6AB519DCF2BB108D5D7A88C6ACA9B613134EA47198BCC2746A35E35281395A8D7E45036 51EF887F28C9FA6981BDE859B5AD042E6FCD25CAF05622B269B9DDC55832267E3276D8A605AB 8D0E690534CB1F5DDC8B22F05C2CD60D1020333CCE9F03E778E0C7F47A94DB9D692E80D19407 E4F287A1FE21C5A507497C2589080836B31E9D0C92E29FFFC0CB3B936B9EC41F3789F900D591 A8A7057284A64F16F5E280AF642A5257728F9667E9D977C7A9D2A4B5F0AA3DA9B8BF44D1F8CC 5FAA51234EA419D31144B7DAA62D51899A57B5F625657809065D9985664404356F107CDC6E6A C2AAADAD1EAA1491B5196059D0826C85FC2F0CD9320ABF52960AEF7509CDBBAF288D348B84D6 27AD28E4697D8888D5A8DDD5C3B6AE1DE6F24AF231265767089985766ACA72F5BDB495CFA767 3A183BF5EE172AB5E6CB623074E036A315DB038F7F4FD1021C6DD6BA078AD3A374B898F90914 E1E082C38EF669C2BEDA91F4262B350721D6AA0F6AD384ACC92A588FCB79941461FE8C336D85 5E77CE41575CF1E7E233EB10F86A9B1666D5D2379222C5873AB2112A78F7FA5D5788017C94F5 44152E703815C091213CB2DFB73B6D3107E708398B0B7E99E393DA14A2C5D7FBDC76B6DBB6F9 355D1EBC6E8C27C58E0A5A0EBEDCE34B80F0276833B836C142FC8BF803331A9B442F346A3E60 0A2BF964C6CC7ACEA399B2817DD63A886B62C7134D6725CB8D657B1F7628B013BF2BBEB523B4 D8CD01A6D4DCACC87AD88D0FBF8565031728D473C1F56B920334F9BE3297D5D9D13BABEF159D 95D044A594B0F9A5808319C56CE0D271F3655DCBEA72AAFB6275BB036864E9F5EB129ACDE00D BFCE57356F9C7348E6461043901A12664A19176214E442546CA0E2AD92B4A76F1D4FA8EE2E78 2806429EFD99F730D0A0FC0B3D94146E3B8100A202D20B43EF01D2A7352B6C0D72F57FA0F9F2 C80A84933C3233FB134E545F08F5203AD4E9A86AB08B80A78AC2E622507B6B2B7B3ED0432D6A 515757B02D6E1F3C1508F00AADC3D2EE15B5CDDAE5A3E1E45D7DC3935CF05596147BFF56A180 7F8F6A9C4A1A4780B9EBE18711BD28FE3AFCC7107368AE8F59ECC160AB493D58CA2A2BA7F17E 8665BC548E998BF7666AC6F41D9308A60169FFCB69D4A35BEC6F95DD8322F5772B97A1450947 44BCFBDFF1AA8C9900DB342E575ABC306CB00CF58AD5FC1640948A9659C9806DDD807331015C F9F35B8F662969B4043C3B2803C8FBF663DC427CC5EC8A3B5D19DC6248576274745B1315179A BB1A22BD3CD63BAA4C721F3D9E0B0851C71CD890A00B758FDCE1BA07BA757AF53A8AFC5DE21D 0BB65F1FCAA506CE41AD64933FC3DC0105BA561469A752B393354EBE44B6285B262626F0CFD3 89EF8BF3FBC27DDFCFE529F9A158D3DE78A900A9C075B1FBA4A9463279A06E45A9B54D9217C3 6EFF1260E6E4BA1B7FD4CE0B06E60254D5B9112D17408245988E9814B4DA07C828BBE90F846D 6926AE4133BBB22FA7A709B24A760182A3F135186AD6EEA89FC4E8E4CDD22328818C33F7B51D 3872BC59958E2D8E9FB8812597031B800416981EA2BC3D906EDACAC2C3F7DB135DEA0C089E1D F29D3058649EF749F0615371EC5C33B236EDBCBFDC2703FBABF8AB149307CA265EA2F31020C7 AB90FDE03717D7F9141806EB0F51D8044608ABB461363EDA2C51E2A03E4438164A1ED38BDA6A 0963D5C58B5B8160E70EF06F5BBDFA56362902D8825B7D9909267F00CBCA118D06FCFA297F96 BD2A217741A12C15A38E2C22A6C4075DD242807EC7C8833F0FE3D2CC1D192DD6DEF423BD89D9 4D220BE67EBDC5E051E015E89BB4975B559EC47AB22734BBA890504D2A182C565258DCD6D9AF F99726742D7D4DCD54C8451288744684D3DEB5C16CAE4A3D5E712E64EF5462B09C2FAF1EE71E 9A9E7D59A36FFBB2F3810CB5F57AF19B803DC7DD74C232A8C16E6CC952298CB0EC833519D900 50A2EF37221DD3C2EF17BA91D449F5585CD67A61BA5E50924B7284EB313FA38E722E40FF8C22 B85614D35EACFE3802E09FDEAE6BD67A8C9F258944C0274E7132188CAB333DA084FC83B01FEA 6960C8523EEEACA46F8A81D5CD76018F26B29959D4586DF9F1D37B10D33C54D8993B64943300 D58C20810D420A2FB777F989E9AF40F73F1A2FE89269BA0F8CF7028363548E20A0F09163AAC3 110EC78996C2988BC20912BD04FE1BB3CD8516E4D1BBCDD2C258B03980C399914D9AB61E67FA 273CAA1003D22A00B732DFFB659F634E236667085830535B9FA3A6FB09DA331E8EC879E5365A 180911204568524F45E0D6777D38BED818968E664FCB5D9298BB69009EDF7D417AFF14DDBEE0 07F23201A728B3E350825F7D30D82601908B47973995152E920E0FC4EB9C6C7F23FCC243D849 3BBA1CC6C48C34F2BBA180D46AAC7CA557D8A470503891A08332F22CE1878AA462D32D0D5F86 9FA4CEC032E385A311475FE853BDFA237D80A3765EDEEA4955C8AB844DBB144684EB1938B7B9 37B6BBDB35C6A240399596AB1DA8B1F8B76E1A65A59AA53E7FE5D99EB4F53EB86B828007AE49 1CBAAE32239ED78EC190CD7CDC81A0EC4B09E9C04DF92733DECF8984A0860D04EFFA220CD882 D27B6E3999690179C4B102458F78F61AB29A339A79D8063F547A588C8FEE8D391A660EC06631 FFF44042C125E6F2F2047022D78CDD3C2722B1CF366971B03CC722698D3342A6F92D39423D7B 73C60ACB78B3846B419EEF24EF6F14F6DE77DB07460D74C31B6673682884BF269FCBE690016B C966E9A7A16DA643565E7ED417B0DFAFC844282EE2FC8EED142923B4AB007D7FB72A8CDEA682 CF96051AA111B16579E0C9444486525F9CF12359A6BAE88E2CE869A75EBFAA6C35F5DFECC810 B8508B7C4709EE0E8CDE730E984C199A673BA85F51ACBA7508920D5FAE52FCE5089C5439BCEE F79EB48D8D6701333ACD8FDD10E156FB7C2FFBE0A104F7128F868B16149C7A280C2F53CBE2BF 22E3C342F11F49D2BBE5F7512BEF84FD218E97B1C0B7859F412155279BC80F1F6F1A54581496 B77C2C713FBD5B20785C57A0F4641FC0DF448D5E79F7125EBB17918C60385B79EF4345CDD44A 4AF266AC009BE62A9A6CD0752E266A9454FC1AC6F004704BC53D6414161F40CCB4F4CC2F2DA5 0D860E9EE2274026B0E84E110BE5D7198DB7A3330F02B913E11CA291B73CD0F9BA34B8272143 C96D13138F99C05A24D0F6A75C71D94A10ADBB1A47813307A5EDF32102AD9D25B89A64AB3A1E 6C4B87EC7416573B5AB977D672D9F6DDB48F710D4A4C9CEC91997C655276F25A00A570728709 2A79B33C5B79A43E44E5B175F576791ABCE72E9FCFDFD126649F8E59EC3248B15F262A00DB6E A3327FEA2F1F9F12DD23EBD73953F8593D303518F8E37E427C122E43A87803EB749C7C9899D3 99E98C44EB1BAB1C0D0A334EC3F5659014F2693119CA3D0FF7E78D1F263E8737175EF80596F8 7ABA98EBBA1BA57615D71C738DF9C2059916CAB7F2916ADE2CEF7F5962D1A2973E83DC17B803 3666CB270942CAA780D57A8ED1255C13F2EBC68F41A850A20F69FA7598E3D978C700DAAEC71B 45542712F6BCE8E043E94680BAE51345C254978AA287707499C7784EEF7212C2B6455F2C30EC 1B0637D6AF1EB17E185D2B0C756CDF6C3FDF6EB8F734012971B13A0CD95F38DFC84C965AF61E C31CB1830445F84A252423547ECFDA493A2A9C0F75FF5B7844764864A2FA724AE3DDB141A946 14D8B83C64F08DD9327357D58C3FB4B5AD4671866DAEAA3664514A1322D62AB645D4192112B3 738ED3A84281447597A84E0E0D377F881E5E02445EA5652713B4326A29B99F3FD64756F4C25B CE52A6015538BB7FC519725BE94885A5FB18359EF03D764A04F1B67ABC3567DA01FDAF7C7ECE 65A10B249BA50EA113D5B32C9B0044B01D74CCFB2638BA533E9BB53E257949FE1F29D7112A14 0E0B766A2F3968F35CD0A6F497B2A4585E1A49D6EF91464B8A01412F4DC4D1703CCF5A9B03E1 0B528FEE23FBAE3D419D11956B65D8E9D73298817C207981940C029C67246BD743AB4FC15EA9 6BD451E6C1E599C554AB55BA921EA5FF370EEF85C70B5E877873B376B2734B8E5A855BF00D19 F9B37D882840394CEB15AD2C7D8EE6F50E1DF3682BF863B7CDA4B491464E46E73BEC1BD2410C CFCED868896E83E230D69ED8E27673E5CF7628597BE47D05139DB3CEC1083AC21347C57D27CB 8B4085CCD54D50E4E7B6F0CB07A26DBCDB7522B5197ADC31E908079961D9B2D5D3CC0EE8055A D31DF8546E4E417F1488B6477833A5A86AB95F495665B34AE46CF8CC4C33367F462F426662D4 99BE68D634F025D8F712FBA6A4145E8FB090FF5B61CD70E5550209C92530AFE1BAB70B715893 BC3532B9EDD957279FD92142798BA005E3D6C0BC95EB6E451B078FC6B1ABAE3FE77855BD7354 F02EAAC338DBA19689823399BBFF119850CB442E5B7323B356341A4AD204E8E05489CDD464E7 FEF19C5BBF5B495D91F70525675E5591FDB276576D6DF322A1085391F89941AE1216724D6C42 704B2C920AAB2FD78BFB5481098939A0B2C7D1D5CB8AA7AA31507A117E2E9AAE05CE84BAF157 91DF6D594D62C3857DBE27335AA79C909E4C2C571E0C3E1E6DF11B4996B8BC9EAF76575BEBEE A7C51B2EB327CA1BC7684FFD06919FACD345D01BC3E1FDBF8DB5CDFECF107F7F5D5BE5E7A108 E189A0AC6DDA11749FF6EB3773DF65287E68C6F1FA8FFDBA58B9488186234E9D2B0F8A2EA96E 3C521AC756405853000FCDFCEEA528AEDD5E15FC8598F416456F52EF917DA951A0EBE9E6E863 F6CB778E0A5BE95D26A5D47C1EF7F07C10F2376D1869E05BE6DB2553126ACBCF4870385A1B1E 2FC1625B311752431EDBEAC958BEEFC8576C0FF32A26EA29D228E4E8D3D2B926150D736F13C9 1FABA41A9C3818775A536C2FE073D5830617559F2EAF8EAAEB3929AD970089443F934E1C937F FAF9CC5EF69DA9E747BAF74D1279C82D37CEE291ACA600DEA23514A55A54E5ACF8805D52DC78 C7E4D0DDC1A3D02772D731BEE16F452D9398043275A551A097670645A2A4CF093EC252192FD5 59A780F79EF21472A10ECAD1542577C352B54256E11B93F267D11515056267DCCDA2C5AC2134 C32798F5706223409005EEC21998752034A3CBC845885933BFDEE7D1CB32FA84797FED209590 2E36BB359E0E79E78E9162E8F8DFBC9796423BB4B98F9A9FBBCEA1DD5DB31D431706D80C5C29 64532ED8AF6510441BE3757F5D9B53B8D9FF2DC6CB4E1F8D1B47F553C8D6D1962E9DF2A97FBA 979FBFB52F4D4CBA08A5A268CDC5A9A6CC40738577EC1836BD04B3ACF76E899655CA496A1B9F 5C9472A90F59DDED0D4C368306F5E3824CF013A7391EFC56986E179C79343B763DA88DE7F1B5 1E2756031154F752F7BC2A858EAA35C549CC24C932DDF0459F4CA70925ACF39065440C6B2FE4 8018D07A0F5F1975CC52CE85F8C7511AE1043B4CB421F5095AA0E1E588412DFA0D86CA55BFFD F223EFC18D56DC7197AA1E8E08D4BACD388719AFDA2915579868B6B756A929B928EFDA008691 458FCA9FC5086D0FDFA6EDF122606C9ECA9C6D0163DE9F05F97E904BC6B1E0F538BDD9E1E5A3 63969EB55B4CAF47B2A55F27E9DEB5007942D2CB6A61AF76F7E3128B918D8C561C9A0510D5DC 8A8676DEEA7B0E5605F72BBBA35A6A24D6EA143CC8900D9A6F7755501969F25C3CC0F7928AA6 0E70FBB364CFD14531BD0B6B327A3AEAE1FB48C708CEFB4E369195ACB18A9F21177F868965E2 CA10074FEFFB10269E43C95B3BC7EEDE5DFA60998E7FEC6C568433F06EB48AE53D26C262E7C5 B349C64B493FFE2EE11D3D8CA4FF6B9CE4D37F4AD6765D37B3559106E3E80F2946E207523349 5048F3425505466F32FD35255978EA5467FC8FE4F6C147084E7A46C493876F647BD882CEE359 0D5B3EADEB5A72689DD0DB1C3A8B89771CFDF77D9637CB915DF7E0F8B1356477B35EEE547362 E97B58190EF9B3D4F442FAE6E7305DE0356CF604516912F4787EC315071578AC3DA58AD383D0 4840891CB3FA113EC89A2FA43E7CE250176A5DBCB516147CD09F5C11B2FA2C2B2D00D69FBF26 6D9B2E258ABA75883D48D100E04650F17DEFF97BF4C406DFEAE8A6202F56C18310BBA393553F 9BBFB054F5939FCDB910ACC0FB10ED21D7CF7A7430CCF97BE7FC77714DC4A287544DF41DB14D B5FBF780CF8754FA7422C3F57E62CCEEAD9AA3470000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginProcSet: texps.pro TeXDict begin /rf{findfont dup length 1 add dict begin{1 index /FID ne 2 index /UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]/Metrics exch def dict begin Encoding{exch dup type /integertype ne{pop pop 1 sub dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get div def} ifelse}forall Metrics /Metrics currentdict end def[2 index currentdict end definefont 3 -1 roll makefont /setfont load]cvx def}def /ObliqueSlant{dup sin S cos div neg}B /SlantFont{4 index mul add}def /ExtendFont{3 -1 roll mul exch}def /ReEncodeFont{/Encoding exch def}def end %%EndProcSet TeXDict begin 40258431 52099146 1000 600 600 (main.dvi) @start /Fa 205[33 33 49[{}2 58.333336 /CMR7 rf /Fb 149[27 21[39 11[54 72[{}3 58.333336 /CMMI7 rf /Fc 173[74 77 81[{}2 100.000000 /CMMI12 rf /Fd 133[50 59 3[62 44 44 46 2[56 62 93 31 2[31 62 1[34 51 62 50 1[54 11[86 1[62 3[84 88 106 3[42 6[80 9[56 56 56 56 56 56 56 56 2[31 46[{}33 100.000000 /CMBX12 rf /Fe 141[33 4[69 7[37 1[37 46 29[63 9[23 42 42 1[42 4[42 4[23 44[{}12 83.333336 /CMSL10 rf /Ff 139[62 4[62 4[62 4[62 1[62 62 32[62 14[62 50[{}8 119.999947 /CMTT12 rf /Fg 136[55 1[45 28 34 35 1[42 42 47 68 21 38 1[25 42 38 1[38 42 38 38 42 12[59 1[61 11[54 56 63 2[62 6[25 58[{}26 83.333336 /CMTI10 rf /Fh 240[42 14[65{}2 83.333336 /CMSY10 rf /Fi 134[71 2[71 75 52 53 55 1[75 67 75 112 3[37 75 67 41 61 75 60 1[65 13[75 2[92 11[103 16[67 67 67 2[37 46[{}25 119.999947 /CMBX12 rf /Fj 137[40 11[34 23[63 66 1[63 13[62 6[23 58[{}7 83.333336 /CMMI10 rf /Fk 133[44 44 44 44 44 44 44 44 44 1[44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 1[44 1[44 1[44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 2[44 44 44 44 44 44 44 44 44 2[44 44 44 44 44 7[44 44 44 1[44 44 44 1[44 44 44 6[44 33[{}67 83.333336 /CMTT10 rf /Fl 131[83 1[37 44 44 60 44 46 32 33 33 44 46 42 46 69 23 44 25 23 46 42 25 37 46 37 46 42 4[42 4[85 1[62 60 4[65 62 76 3[30 62 1[54 4[62 3[65 2[23 42 42 42 42 42 42 42 42 42 42 1[23 28 23 2[32 32 23 4[42 20[46 46 12[{}59 83.333336 /CMR10 rf /Fm 134[123 123 5[95 1[129 116 129 194 65 6[106 129 103 1[113 14[173 8[87 4[178 9[65 7[116 4[77 45[{}18 207.333359 /CMBX12 rf /Fn 190[106 14[106 50[{}2 207.333359 /CMTT12 rf /Fo 139[75 1[79 1[108 7[108 2[88 3[94 29[140 17[97 49[{}8 172.833374 /CMBX12 rf end %%EndProlog %%BeginSetup %%Feature: *Resolution 600dpi TeXDict begin %%PaperSize: Letter %%EndSetup %%Page: 1 1 1 0 bop 0 1034 a Fo(Chapter)65 b(1)0 1470 y Fn(A2)p Fm(:)103 b(Real)78 b(or)f(complex)g(2-D)h(arra)-6 b(y)0 1923 y Fl(The)29 b Fk(A2)g Fl(ob)5 b(ject)29 b(is)g(one)g(w)n(a)n(y)f(to)h (store)g(and)g(op)r(erate)f(on)h(and)g(with)h(a)f(dense)g(matrix.)42 b(The)29 b(matrix)g(can)g(con)n(tain)f(either)0 2023 y(double)35 b(precision)f(real)g(or)h(complex)f(en)n(tries.)59 b(It)36 b(is)f(used)g(as)f(a)h(lo)n(w)n(er)f(lev)n(el)g(ob)5 b(ject)35 b(for)g(the)g Fk(DenseMtx)d Fl(ob)5 b(ject,)37 b(and)0 2122 y(during)27 b(the)h Fj(QR)g Fl(factorization)e(to)i(hold)f (a)g(staircase)f(matrix.)0 2415 y Fi(1.1)135 b(Data)46 b(Structure)0 2617 y Fl(The)28 b Fk(A2)f Fl(structure)g(has)g(six)g (\014elds.)125 2789 y Fh(\017)41 b Fk(int)h(type)26 b Fl(:)37 b(t)n(yp)r(e)28 b(of)f(en)n(tries,)g Fk(SPOOLES)p 1527 2789 27 4 v 29 w(REAL)f Fl(or)g Fk(SPOOLES)p 2167 2789 V 29 w(COMPLEX)125 2948 y Fh(\017)41 b Fk(int)h(n1)27 b Fl(:)37 b(size)27 b(in)h(\014rst)f(dimension,)h(n)n(um)n(b)r(er)f(of) h(ro)n(ws)125 3106 y Fh(\017)41 b Fk(int)h(n2)27 b Fl(:)37 b(size)27 b(in)h(second)f(dimension,)g(n)n(um)n(b)r(er)h(of)f(columns) 125 3265 y Fh(\017)41 b Fk(int)h(inc1)26 b Fl(:)37 b(incremen)n(t)27 b(or)g(stride)g(in)h(\014rst)f(dimension)125 3423 y Fh(\017)41 b Fk(int)h(inc2)26 b Fl(:)37 b(incremen)n(t)27 b(or)g(stride)g(in)h (second)f(dimension)125 3581 y Fh(\017)41 b Fk(int)h(nowned)32 b Fl(:)49 b(the)35 b(n)n(um)n(b)r(er)f(of)g(en)n(tries)f(that)h(are)f (\\o)n(wned")g(b)n(y)g(this)i(ob)5 b(ject.)56 b(When)34 b Fk(nowned)41 b(>)j(0)p Fl(,)35 b Fk(entries)208 3681 y Fl(p)r(oin)n(ts)e(to)g(storage)e(for)i Fk(nowned)e Fl(en)n(tries,)j(\()p Fk(nowned)d(double)p Fl('s)g(for)i(the)h(real)e (case,)i Fk(2*nowned)c(double)p Fl('s)h(for)i(the)208 3781 y(complex)26 b(case\),)g(that)h(ha)n(v)n(e)f(b)r(een)h(allo)r (cated)f(b)n(y)h(this)g(ob)5 b(ject)26 b(and)h(can)f(b)r(e)h(free'd)g (b)n(y)g(the)g(ob)5 b(ject.)36 b(When)27 b Fk(nowned)208 3880 y(==)42 b(0)34 b Fl(but)g Fk(n1)43 b(>)g(0)34 b Fl(and)g Fk(n2)43 b(>)g(0)p Fl(,)35 b(this)f(ob)5 b(ject)34 b(p)r(oin)n(ts)g(to)g(en)n(tries)f(that)h(ha)n(v)n(e)f(b)r(een)h(allo)r (cated)g(elsewhere,)g(and)208 3980 y(these)27 b(en)n(tries)g(will)h (not)f(b)r(e)i(free'd)e(b)n(y)g(this)h(ob)5 b(ject.)125 4138 y Fh(\017)41 b Fk(double)g(*entries)24 b Fl(:)37 b(p)r(oin)n(ter)27 b(to)h(the)g(base)f(address)f(of)h(the)h Fg(double)h Fl(v)n(ector)0 4310 y(One)e(can)g(query)g(the)h(prop)r (erties)f(of)h(the)g(fron)n(t)f(matrix)g(ob)5 b(ject)27 b(using)g(these)h(simple)g(macros.)125 4482 y Fh(\017)41 b Fk(A2)p 301 4482 V 30 w(IS)p 419 4482 V 31 w(REAL\(mtx\))24 b Fl(is)j Fk(1)g Fl(if)h Fk(mtx)f Fl(has)g(real)g(en)n(tries)g(and)g Fk(0)g Fl(otherwise.)125 4640 y Fh(\017)41 b Fk(A2)p 301 4640 V 30 w(IS)p 419 4640 V 31 w(COMPLEX\(mtx\))22 b Fl(is)28 b Fk(1)f Fl(if)h Fk(mtx)f Fl(has)g(complex)g(en)n(tries)g (and)g Fk(0)g Fl(otherwise.)0 4812 y(The)18 b Fk(A2)p 254 4812 V 31 w(copyEntriesToVec)o(tor)o(\(\))12 b Fl(metho)r(d)19 b(uses)f(the)g(follo)n(wing)g(constan)n(ts:)31 b Fk(A2)p 2637 4812 V 30 w(STRICT)p 2931 4812 V 29 w(LOWER)p Fl(,)17 b Fk(A2)p 3308 4812 V 30 w(LOWER)p Fl(,)g Fk(A2)p 3686 4812 V 30 w(DIAGONAL)p Fl(,)0 4912 y Fk(A2)p 93 4912 V 31 w(UPPER)p Fl(,)25 b Fk(A2)p 480 4912 V 31 w(STRICT)p 775 4912 V 29 w(UPPER)p Fl(,)g Fk(A2)p 1160 4912 V 31 w(ALL)p 1323 4912 V 30 w(ENTRIES)p Fl(,)g Fk(A2)p 1797 4912 V 30 w(BY)p 1915 4912 V 31 w(ROWS)h Fl(and)h Fk(A2)p 2397 4912 V 31 w(BY)p 2516 4912 V 31 w(COLUMNS)p Fl(.)0 5204 y Fi(1.2)135 b(Protot)l(yp)t(es)46 b(and)f(descriptions)g(of)g Ff(A2)f Fi(metho)t(ds)0 5407 y Fl(This)28 b(section)f(con)n(tains)f (brief)i(descriptions)f(including)h(protot)n(yp)r(es)e(of)i(all)f (metho)r(ds)h(that)g(b)r(elong)f(to)g(the)h Fk(A2)f Fl(ob)5 b(ject.)1929 5656 y(1)p eop %%Page: 2 2 2 1 bop 0 100 a Fl(2)p 125 100 1212 4 v 1377 w Fk(A2)26 b Fe(:)37 b Fg(DRAFT)28 b Fe(Decem)n(b)r(er)f(16,)g(1998)p 2689 100 V 0 390 a Fd(1.2.1)112 b(Basic)38 b(metho)s(ds)0 573 y Fl(As)21 b(usual,)g(there)f(are)g(four)g(basic)g(metho)r(ds)g(to) h(supp)r(ort)f(ob)5 b(ject)20 b(creation,)h(setting)f(default)h (\014elds,)h(clearing)d(an)n(y)h(allo)r(cated)0 672 y(data,)27 b(and)h(free'ing)f(the)h(ob)5 b(ject.)101 889 y(1.)42 b Fk(A2)g(*)h(A2_new)f(\()h(void)f(\))h(;)208 1027 y Fl(This)28 b(metho)r(d)g(simply)h(allo)r(cates)e(storage)f(for)h(the)i Fk(A2)e Fl(structure)h(and)g(then)h(sets)f(the)g(default)h(\014elds)f (b)n(y)g(a)f(call)h(to)208 1127 y Fk(A2)p 301 1127 27 4 v 30 w(setDefaultFields)o(\(\))p Fl(.)101 1302 y(2.)42 b Fk(void)f(A2_setDefaultFiel)o(ds)c(\()43 b(A2)g(*mtx)f(\))h(;)208 1440 y Fl(The)34 b(structure's)h(\014elds)g(are)e(set)i(to)g(default)g (v)-5 b(alues:)51 b Fk(type)34 b Fl(=)g Fk(SPOOLES)p 2618 1440 V 29 w(REAL)p Fl(,)f Fk(n1)h Fl(=)h Fk(inc1)e Fl(=)h Fk(n2)h Fl(=)f Fk(inc2)f Fl(=)208 1539 y Fk(nowned)25 b Fl(=)i(0)g(and)h Fk(entries)c Fl(=)k Fk(NULL)e Fl(.)208 1677 y Fg(Err)l(or)k(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n(ted)h(and)f (the)h(program)e(exits.)101 1852 y(3.)42 b Fk(void)f(A2_clearData)e(\() k(A2)g(*mtx)f(\))h(;)208 1990 y Fl(This)32 b(metho)r(d)i(clears)d(the)j (ob)5 b(ject)32 b(and)h(free's)f(an)n(y)h(o)n(wned)f(data.)52 b(If)33 b Fk(nowned)41 b(>)j(0)32 b Fl(and)h Fk(entries)d Fl(is)j(not)g Fk(NULL)p Fl(,)208 2090 y(then)28 b Fk(DVfree\(entries\)) 21 b Fl(is)28 b(called)f(to)g(free)h(the)g(storage.)35 b(It)28 b(calls)e Fk(A2)p 2487 2090 V 31 w(setDefaultFields)o(\(\))p Fl(.)208 2227 y Fg(Err)l(or)k(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n (ted)h(and)f(the)h(program)e(exits.)101 2403 y(4.)42 b Fk(void)f(A2_free)g(\()i(A2)g(*mtx)f(\))h(;)208 2540 y Fl(This)27 b(metho)r(d)h(releases)e(an)n(y)h(storage)f(b)n(y)h(a)g (call)g(to)h Fk(A2)p 1975 2540 V 30 w(clearData\(\))c Fl(and)j(then)h(free)f(the)h(space)f(for)g Fk(mtx)p Fl(.)208 2678 y Fg(Err)l(or)j(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n(ted)h(and)f (the)h(program)e(exits.)0 2948 y Fd(1.2.2)112 b(Instance)38 b(metho)s(ds)101 3130 y Fl(1.)k Fk(int)g(A2_nrow)f(\()i(A2)g(*mtx)e(\)) j(;)208 3268 y Fl(This)27 b(metho)r(d)h(returns)f(the)h(n)n(um)n(b)r (er)f(of)h(ro)n(ws)e(in)i(the)g(matrix.)208 3405 y Fg(Err)l(or)i(che)l (cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d (message)i(is)g(prin)n(ted)h(and)f(the)h(program)e(exits.)101 3581 y(2.)42 b Fk(int)g(A2_ncol)f(\()i(A2)g(*mtx)e(\))j(;)208 3718 y Fl(This)27 b(metho)r(d)h(returns)f(the)h(n)n(um)n(b)r(er)f(of)h (columns)f(in)h(the)g(matrix.)208 3856 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i (is)g(prin)n(ted)h(and)f(the)h(program)e(exits.)101 4032 y(3.)42 b Fk(int)g(A2_inc1)f(\()i(A2)g(*mtx)e(\))j(;)208 4169 y Fl(This)33 b(metho)r(d)h(returns)e(the)i(primary)e(incremen)n (t,)i(the)g(stride)f(in)g(memory)g(\(with)h(resp)r(ect)f(to)g(real)f (or)h(complex)208 4269 y(en)n(tries\))27 b(b)r(et)n(w)n(een)g(adjacen)n (t)g(en)n(tries)g(in)h(the)g(same)f(column.)208 4406 y Fg(Err)l(or)j(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n(ted)h(and)f (the)h(program)e(exits.)101 4582 y(4.)42 b Fk(int)g(A2_inc2)f(\()i(A2)g (*mtx)e(\))j(;)208 4719 y Fl(This)28 b(metho)r(d)h(returns)f(the)h (secondary)e(incremen)n(t,)i(the)g(stride)g(in)g(memory)e(\(with)j (resp)r(ect)e(to)h(real)f(or)g(complex)208 4819 y(en)n(tries\))f(b)r (et)n(w)n(een)g(adjacen)n(t)g(en)n(tries)g(in)h(the)g(same)f(ro)n(w.) 208 4957 y Fg(Err)l(or)j(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n (ted)h(and)f(the)h(program)e(exits.)101 5132 y(5.)42 b Fk(double)f(*)i(A2_entries)c(\()k(A2)g(*mtx)f(\))h(;)208 5270 y Fl(This)27 b(metho)r(d)h(returns)f(a)g(p)r(oin)n(ter)g(to)h(the) g(base)f(address)f(of)i(the)g(en)n(tries.)208 5407 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n(ted)h(and)f(the)h (program)e(exits.)p eop %%Page: 3 3 3 2 bop 83 100 1212 4 v 1377 100 a Fk(A2)27 b Fe(:)37 b Fg(DRAFT)110 b Fe(Decem)n(b)r(er)28 b(16,)e(1998)p 2649 100 V 1212 w Fl(3)101 390 y(6.)42 b Fk(double)f(*)i(A2_row)e(\()i (A2)g(*mtx,)e(int)i(irow)f(\))h(;)208 540 y Fl(This)27 b(metho)r(d)h(returns)f(a)g(p)r(oin)n(ter)g(to)h(the)g(leading)f (elemen)n(t)h(of)f(ro)n(w)g Fk(irow)p Fl(.)208 690 y Fg(Err)l(or)k(che)l(cking:)41 b Fl(If)29 b Fk(mtx)f Fl(or)g Fk(entries)e Fl(is)j Fk(NULL)p Fl(,)e(or)h(if)i Fk(irow)d Fl(is)i(not)f(in)i Fk([0,n1-1])p Fl(,)c(an)i(error)f(message)g(is)i (prin)n(ted)208 790 y(and)e(the)h(program)e(exits.)101 990 y(7.)42 b Fk(double)f(*)i(A2_column)d(\()j(A2)g(*mtx,)e(int)h(jcol) g(\))i(;)208 1140 y Fl(This)27 b(metho)r(d)h(returns)f(a)g(p)r(oin)n (ter)g(to)h(the)g(leading)f(elemen)n(t)h(of)f(column)h Fk(jcol)p Fl(.)208 1290 y Fg(Err)l(or)j(che)l(cking:)41 b Fl(If)29 b Fk(mtx)f Fl(or)g Fk(entries)e Fl(is)j Fk(NULL)p Fl(,)e(or)h(if)i Fk(jcol)d Fl(is)i(not)f(in)i Fk([0,n2-1])p Fl(,)c(an)i(error)f(message)g(is)i(prin)n(ted)208 1390 y(and)e(the)h(program)e(exits.)101 1590 y(8.)42 b Fk(void)f (A2_realEntry)e(\()k(A2)g(*mtx,)f(int)g(irow,)f(int)i(jcol,)e(double)g (*pValue)g(\))i(;)208 1740 y Fl(This)27 b(metho)r(d)h(\014lls)g Fk(*pValue)d Fl(with)j(the)g(en)n(try)f(in)h(lo)r(cation)f Fk(\(irow,)41 b(jcol\))p Fl(.)208 1890 y Fg(Err)l(or)29 b(che)l(cking:)37 b Fl(If)27 b Fk(mtx)e Fl(or)g Fk(pValue)f Fl(is)i Fk(NULL)p Fl(,)f(or)g(if)i(the)g(matrix)e(is)h(not)h(real,)e (or)h Fk(irow)e Fl(is)i(not)g(in)h Fk([0,n1-1])p Fl(,)c(or)j(if)208 1990 y Fk(jcol)g Fl(is)h(not)h(in)g Fk([0,n2-1])p Fl(,)c(an)j(error)f (message)g(is)i(prin)n(ted)f(and)g(the)h(program)e(exits.)101 2190 y(9.)42 b Fk(void)f(A2_complexEntry)d(\()43 b(A2)g(*mtx,)e(int)i (irow,)e(int)i(jcol,)1210 2290 y(double)e(*pReal,)g(double)g(*pImag)g (\))i(;)208 2440 y Fl(This)27 b(metho)r(d)h(\014lls)g Fk(\(*pReal,*pImag\))21 b Fl(with)28 b(the)g(en)n(try)f(in)h(lo)r (cation)f Fk(\(irow,)41 b(jcol\))p Fl(.)208 2590 y Fg(Err)l(or)c(che)l (cking:)53 b Fl(If)36 b Fk(mtx)p Fl(,)f Fk(pReal)e Fl(or)i Fk(pImag)e Fl(is)i Fk(NULL)p Fl(,)e(or)h(if)i(the)f(matrix)g(is)g(not)g (complex,)h(or)e Fk(irow)g Fl(is)h(not)g(in)208 2690 y Fk([0,n1-1])p Fl(,)24 b(or)j(if)h Fk(jcol)e Fl(is)h(not)h(in)g Fk([0,n2-1])p Fl(,)c(an)j(error)f(message)g(is)i(prin)n(ted)f(and)h (the)g(program)d(exits.)60 2890 y(10.)41 b Fk(void)g(A2_setRealEntry)d (\()43 b(A2)g(*mtx,)e(int)i(irow,)e(int)i(jcol,)e(double)g(value)h(\))h (;)208 3040 y Fl(This)27 b(metho)r(d)h(sets)g(en)n(try)f Fk(\(irow,jcol\))c Fl(to)k Fk(value)p Fl(.)208 3190 y Fg(Err)l(or)h(che)l(cking:)37 b Fl(If)26 b Fk(mtx)e Fl(is)i Fk(NULL)p Fl(,)e(or)g(if)i(the)g(matrix)f(is)g(not)h(real,)f(or)f Fk(irow)g Fl(is)h(not)h(in)f Fk([0,n1-1])d Fl(or)j(if)h Fk(jcol)e Fl(is)h(not)208 3290 y(in)i Fk([0,n2-1])p Fl(,)e(an)i(error)f (message)g(is)h(prin)n(ted)h(and)f(the)h(program)e(exits.)60 3490 y(11.)41 b Fk(void)g(A2_setComplexEntr)o(y)d(\()43 b(A2)g(*mtx,)e(int)h(irow,)g(int)g(jcol,)1341 3590 y(double)f(real,)g (double)h(imag)f(\))j(;)208 3740 y Fl(This)27 b(metho)r(d)h(sets)g(en)n (try)f Fk(\(irow,jcol\))c Fl(to)k Fk(\(real,imag\))p Fl(.)208 3890 y Fg(Err)l(or)k(che)l(cking:)40 b Fl(If)29 b Fk(mtx)e Fl(is)h Fk(NULL)p Fl(,)f(or)h(if)h(the)g(matrix)f(is)g(not)h (complex,)f(or)f Fk(irow)g Fl(is)i(not)f(in)h Fk([0,n1-1])c Fl(or)j(if)h Fk(jcol)208 3989 y Fl(is)e(not)h(in)f Fk([0,n2-1])p Fl(,)e(an)i(error)f(message)g(is)i(prin)n(ted)f(and)g(the)h(program)e (exits.)60 4190 y(12.)41 b Fk(void)g(A2_pointerToRealE)o(ntr)o(y)c(\() 44 b(A2)e(*mtx,)g(int)g(irow,)g(int)g(jcol,)g(double)f(**ppValue)f(\))j (;)208 4340 y Fl(This)27 b(metho)r(d)h(sets)g Fk(*ppValue)c Fl(to)j(the)h(p)r(oin)n(ter)g(of)f(the)h Fk(\(irow,jcol\))23 b Fl(en)n(try)-7 b(.)208 4490 y Fg(Err)l(or)31 b(che)l(cking:)41 b Fl(If)30 b Fk(mtx)d Fl(or)h Fk(ppValue)e Fl(is)j Fk(NULL)p Fl(,)f(or)g(if)h(the)g(matrix)g(is)f(not)h(real,)g(or)f(if)h Fk(irow)e Fl(is)i(not)g(in)g Fk([0,n1-1])p Fl(,)208 4589 y(or)d(if)i Fk(jcol)e Fl(is)i(not)f(in)h Fk([0,n2-1])p Fl(,)d(an)i(error)f(message)g(is)h(prin)n(ted)h(and)f(the)h(program)e (exits.)60 4790 y(13.)41 b Fk(void)g(A2_pointerToCompl)o(exE)o(nt)o(ry) c(\()43 b(A2)g(*mtx,)f(int)g(irow,)f(int)i(jcol,)1602 4889 y(double)e(**ppReal,)f(double)h(**ppImag)g(\))i(;)208 5039 y Fl(This)26 b(metho)r(d)h(sets)f Fk(*ppReal)e Fl(to)i(the)h(p)r (oin)n(ter)g(to)f(the)h(real)e(part)h(of)h(the)g Fk(\(irow,jcol\))22 b Fl(en)n(try)-7 b(,)26 b(and)h(sets)f Fk(*ppImag)208 5139 y Fl(to)h(the)h(p)r(oin)n(ter)f(to)h(the)g(imaginary)e(part)h(of)g (the)h Fk(\(irow,jcol\))23 b Fl(en)n(try)-7 b(.)208 5289 y Fg(Err)l(or)30 b(che)l(cking:)38 b Fl(If)28 b Fk(mtx)p Fl(,)e Fk(ppReal)f Fl(or)i Fk(ppImag)e Fl(is)i Fk(NULL)p Fl(,)f(or)h(if)g(the)h(matrix)f(is)g(not)h(complex,)f(or)f(if)i Fk(irow)e Fl(is)h(not)h(in)208 5389 y Fk([0,n1-1])p Fl(,)c(or)j(if)h Fk(jcol)e Fl(is)h(not)h(in)g Fk([0,n2-1])p Fl(,)c(an)j(error)f(message) g(is)i(prin)n(ted)f(and)h(the)g(program)d(exits.)p eop %%Page: 4 4 4 3 bop 0 100 a Fl(4)p 125 100 1212 4 v 1377 w Fk(A2)26 b Fe(:)37 b Fg(DRAFT)28 b Fe(Decem)n(b)r(er)f(16,)g(1998)p 2689 100 V 0 390 a Fd(1.2.3)112 b(Initialize)38 b(metho)s(ds)101 573 y Fl(1.)k Fk(void)f(A2_init)g(\()i(A2)g(*mtx,)f(int)g(type,)f(int)i (n1,)f(int)h(n2,)f(int)g(inc1,)g(int)g(inc2,)905 673 y(double)f(*entries)f(\))j(;)208 811 y Fl(This)30 b(is)h(the)g(basic)f (initializer)h(metho)r(d.)47 b(W)-7 b(e)31 b(require)e(that)i Fk(mtx)f Fl(not)h(b)r(e)g Fk(NULL)p Fl(,)e Fk(type)g Fl(b)r(e)j(either)e Fk(SPOOLES)p 3702 811 27 4 v 29 w(REAL)208 911 y Fl(or)d Fk(SPOOLES)p 623 911 V 29 w(COMPLEX)p Fl(,)e Fk(n1)j Fl(and)g Fk(n2)g Fl(b)r(oth)h(b)r(e)g(p)r(ositiv)n(e,)f(and)h (b)r(oth)f Fk(inc1)f Fl(and)i Fk(inc2)e Fl(b)r(oth)i(b)r(e)f(p)r (ositiv)n(e)g(and)h(that)208 1010 y(one)g(of)h(them)h(b)r(e)f(equal)g (to)g(one.)44 b(Also,)30 b(w)n(e)g(only)f(initialize)i(a)e(full)i (matrix,)f(i.e.,)h(one)f(of)g Fk(inc1)42 b(=)h(1)30 b Fl(and)f Fk(inc2)42 b(=)208 1110 y(nrow)26 b Fl(or)g Fk(inc1)42 b(=)h(ncol)26 b Fl(and)i Fk(inc2)42 b(=)h(1)27 b Fl(m)n(ust)h(hold.)208 1248 y(The)g(ob)5 b(ject)29 b(is)f(\014rst)g(cleared)g(with)h(a)f(call)h(to)f Fk(A2)p 1780 1248 V 31 w(clearData\(\))p Fl(.)35 b(If)29 b Fk(entries)d Fl(is)i Fk(NULL)f Fl(then)i Fk(n1*n2)e Fl(new)i(en)n(tries)208 1348 y(are)h(found,)k Fk(mtx->entries)27 b Fl(is)32 b(set)f(to)h(this)g (address)f(and)h Fk(nowned)d Fl(is)j(set)g(to)g Fk(n1*n2)p Fl(.)48 b(If)32 b Fk(entries)d Fl(is)j(not)g Fk(NULL)p Fl(,)208 1447 y(then)c Fk(mtx->entries)22 b Fl(is)28 b(set)f(to)h Fk(entries)d Fl(and)i Fk(nowned)e Fl(is)j(set)f(to)h (zero.)208 1586 y Fg(Err)l(or)e(che)l(cking:)37 b Fl(If)25 b Fk(mtx)d Fl(is)i Fk(NULL)p Fl(,)f(or)g(if)h Fk(n1)p Fl(,)g Fk(n2)p Fl(,)g Fk(inc1)f Fl(or)g Fk(inc2)f Fl(are)h(less)h(than) g(or)f(equal)g(to)h(zero,)g(or)f(if)h(the)h(matrix)208 1685 y(is)k(not)h(full)h(matrix)e(\(i.e.,)i Fk(inc1)d Fl(m)n(ust)i(b)r(e)g Fk(1)f Fl(and)h Fk(inc2)e Fl(m)n(ust)i(b)r(e)g Fk(n1)p Fl(,)g Fg(or)g Fk(inc1)f Fl(m)n(ust)h(b)r(e)g Fk(n2)f Fl(and)h Fk(inc2)e Fl(m)n(ust)i(b)r(e)208 1785 y Fk(1)p Fl(\),)d(an)g(error)f(message)g(is)i(prin)n(ted)f(and)h(zero)e (is)i(returned.)101 1962 y(2.)42 b Fk(void)f(A2_subA2)g(\()i(A2)g (*mtxA,)e(A2)i(*mtxB,)905 2061 y(int)f(firstrow,)e(int)i(lastrow,)f (int)h(firstcol,)e(int)i(lastcol)f(\))i(;)208 2199 y Fl(This)27 b(initializer)g(metho)r(d)h(mak)n(es)f(the)h(ob)5 b(ject)27 b Fk(mtxA)f Fl(p)r(oin)n(t)i(in)n(to)f(a)h(submatrix)f(of)g (ob)5 b(ject)28 b Fk(mtxB)p Fl(,)e(as)208 2409 y Fk(A\(0:lastrow-fir)o (str)o(ow)o(,0)o(:la)o(st)o(col)o(-f)o(ir)o(stc)o(ol)o(\))38 b(=)43 b(B\(firstrow:lastr)o(ow)o(,)37 b(firstcol:lastcol\))208 2619 y Fl(Note,)20 b Fk(firstrow)p Fl(,)d Fk(lastrow)p Fl(,)g Fk(firstcol)f Fl(and)i Fk(lastcol)d Fl(m)n(ust)k(satisfy)f Fk(0)43 b(<=)g(firstrow)d(<=)j(lastrow)d(<)k(mtxB->n1)208 2719 y Fl(and)28 b Fk(0)43 b(<=)g(firstcol)d(<=)j(lastcol)e(<)i (mtxB->n2)p Fl(.)37 b(Ob)5 b(ject)28 b Fk(mtxA)f Fl(do)r(es)i(not)f(o)n (wn)g(its)h(en)n(tries,)f(but)i(p)r(oin)n(ts)e(in)n(to)208 2819 y(the)g(en)n(tries)e(of)i Fk(mtxB)p Fl(.)208 2957 y Fg(Err)l(or)i(che)l(cking:)39 b Fl(If)28 b Fk(mtxA)e Fl(or)h Fk(mtxB)f Fl(are)h Fk(NULL)p Fl(,)f(or)h(if)h Fk(firstrow)c Fl(or)j Fk(lastrow)e Fl(are)i(out)g(of)h(range,)e(or)h (if)h Fk(firstcol)208 3056 y Fl(or)e Fk(lastcol)f Fl(are)i(out)g(of)h (range,)e(an)h(error)f(message)g(is)i(prin)n(ted)f(and)h(zero)e(is)i (returned.)0 3328 y Fd(1.2.4)112 b(Metho)s(ds)39 b(used)f(in)g(the)f Fc(QR)i Fd(factorization)101 3511 y Fl(1.)j Fk(void)f(A2_makeStaircase) c(\()44 b(A2)e(*mtxA)g(\))h(;)208 3649 y Fl(This)34 b(metho)r(d)h(p)r (erm)n(utes)f(the)h(ro)n(ws)e(of)h Fk(mtxA)f Fl(b)n(y)i(the)f(lo)r (cation)g(of)h(the)f(leading)g(nonzero)f(of)i(eac)n(h)e(ro)n(w.)57 b(Up)r(on)208 3749 y(return,)27 b(the)h(matrix)f(is)g(in)h Fg(stair)l(c)l(ase)h Fl(form.)208 3887 y Fg(Err)l(or)h(che)l(cking:)38 b Fl(If)28 b Fk(mtxA)e Fl(is)i Fk(NULL)p Fl(,)e(an)h(error)f(message)g (is)i(prin)n(ted)f(and)h(the)g(program)d(exits.)101 4064 y(2.)42 b Fk(double)f(A2_QRreduce)e(\()k(A2)g(*mtxA,)e(DV)h(*workDV,)f (int)h(msglvl,)f(FILE)h(*msgFile)e(\))j(;)208 4202 y Fl(This)35 b(metho)r(d)h(computes)f Fj(A)h Fl(=)g Fj(QR)f Fl(factorization.)59 b(On)35 b(return,)i(the)f(matrix)e Fj(Q)h Fl(is)h(not)f(a)n(v)-5 b(ailable,)36 b(and)f Fj(R)h Fl(is)208 4302 y(found)f(in)h(the)g(upp)r(er)f(triangle)g(or)f(upp)r (er)i(trap)r(ezoid)e(of)i Fk(mtxA)p Fl(.)e(The)h(Householder)f(v)n (ectors)g(are)h(stored)f(in)i(the)208 4401 y(lo)n(w)n(er)28 b(triangle)h(of)h Fk(mtxA)p Fl(,)f(with)h Fj(v)1290 4413 y Fb(j)1326 4401 y Fl(\()p Fj(j)5 b Fl(\))27 b(=)g(1)p Fj(:)p Fl(0.)44 b(The)30 b(return)g(v)-5 b(alue)29 b(is)h(the)h(n)n(um) n(b)r(er)f(of)g(\015oating)f(p)r(oin)n(t)h(op)r(erations)208 4501 y(that)d(w)n(ere)g(executed.)208 4639 y Fg(Err)l(or)i(che)l (cking:)38 b Fl(If)27 b Fk(mtxA)e Fl(or)h Fk(workDV)f Fl(is)h Fk(NULL)p Fl(,)f(or)h(if)h Fk(msglvl)41 b(>)j(0)26 b Fl(and)g Fk(msgFile)e Fl(if)k Fk(NULL)p Fl(,)d(an)h(error)f(message)g (is)208 4739 y(prin)n(ted)i(and)g(the)h(program)e(exits.)101 4915 y(3.)42 b Fk(void)f(A2_computeQ)f(\()j(A2)f(*mtxQ,)g(A2)g(*mtxA,)f (DV)i(*workDV,)d(int)j(msglvl,)d(FILE)i(*msgFile)f(\))i(;)208 5054 y Fl(This)32 b(metho)r(d)h(computes)f Fj(Q)g Fl(from)g(the)g Fj(A)f Fl(=)g Fj(QR)h Fl(factorization)f(computed)i(in)f Fk(A2)p 2948 5054 V 31 w(QRreduce\(\))p Fl(.)46 b(Note:)h Fk(mtxA)208 5153 y Fl(and)27 b Fk(mtxQ)f Fl(m)n(ust)i(b)r(e)g(column)f (ma)5 b(jor.)208 5291 y Fg(Err)l(or)38 b(che)l(cking:)57 b Fl(If)37 b Fk(mtxQ)p Fl(,)e Fk(mtxA)g Fl(or)h Fk(workDV)e Fl(is)j Fk(NULL)p Fl(,)e(or)g(if)j Fk(msglvl)j(>)i(0)36 b Fl(and)h Fk(msgFile)c Fl(if)38 b Fk(NULL)p Fl(,)d(an)h(error)208 5391 y(message)26 b(is)h(prin)n(ted)h(and)f(the)h(program)e(exits.)p eop %%Page: 5 5 5 4 bop 83 100 1212 4 v 1377 100 a Fk(A2)27 b Fe(:)37 b Fg(DRAFT)110 b Fe(Decem)n(b)r(er)28 b(16,)e(1998)p 2649 100 V 1212 w Fl(5)0 390 y Fd(1.2.5)112 b(Norm)38 b(metho)s(ds)0 566 y Fl(These)27 b(metho)r(ds)h(return)f(a)g(norm)g(of) h(a)f(ro)n(w)g(or)f(a)h(column,)h(or)f(the)h(easily)f(computable)g (norms)g(of)g(the)h(matrix.)101 746 y(1.)42 b Fk(double)f(A2_maxabs)f (\()j(A2)f(*mtx)g(\))i(;)208 876 y Fl(This)27 b(metho)r(d)h(returns)f (magnitude)h(of)f(the)h(en)n(try)f(with)h(largest)e(magnitude.)208 1007 y Fg(Err)l(or)k(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n(ted)h(and)f (the)h(program)e(exits.)101 1168 y(2.)42 b Fk(double)f(A2_frobNorm)e (\()k(A2)g(*mtx)f(\))h(;)208 1299 y Fl(This)27 b(metho)r(d)h(returns)f (the)h(F)-7 b(rob)r(enius)27 b(norm)g(of)h(the)g(matrix.)208 1429 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n(ted)h(and)f (the)h(program)e(exits.)101 1591 y(3.)42 b Fk(double)f(A2_oneNorm)e(\() k(A2)g(*mtx)f(\))h(;)208 1721 y Fl(This)27 b(metho)r(d)h(returns)f(the) h(one)f(norm)g(of)h(the)g(matrix.)208 1852 y Fg(Err)l(or)i(che)l (cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d (message)i(is)g(prin)n(ted)h(and)f(the)h(program)e(exits.)101 2013 y(4.)42 b Fk(double)f(A2_infinityNorm)c(\()43 b(A2)g(*mtx)f(\))h (;)208 2144 y Fl(This)27 b(metho)r(d)h(returns)f(the)h(in\014nit)n(y)g (norm)f(of)h(the)g(matrix.)208 2274 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i (is)g(prin)n(ted)h(and)f(the)h(program)e(exits.)101 2436 y(5.)42 b Fk(double)f(A2_oneNormOfCol)o(umn)c(\()43 b(A2)g(*mtx,)e(int) i(jcol)f(\))h(;)208 2566 y Fl(This)27 b(metho)r(d)h(returns)f(the)h (one-norm)e(of)i(column)f Fk(jcol)f Fl(of)i(the)g(matrix.)208 2697 y Fg(Err)l(or)d(che)l(cking:)36 b Fl(If)22 b Fk(mtx)f Fl(is)h Fk(NULL)p Fl(,)e(or)i Fk(jcol)e Fl(is)i(not)g(in)g Fk([0,n2-1])p Fl(,)e(an)i(error)e(message)h(is)h(prin)n(ted)g(and)g (the)g(program)208 2796 y(exits.)101 2958 y(6.)42 b Fk(double)f (A2_twoNormOfCol)o(umn)c(\()43 b(A2)g(*mtx,)e(int)i(jcol)f(\))h(;)208 3088 y Fl(This)27 b(metho)r(d)h(returns)f(the)h(t)n(w)n(o-norm)e(of)h (column)h Fk(jcol)e Fl(of)i(the)g(matrix.)208 3219 y Fg(Err)l(or)d(che)l(cking:)36 b Fl(If)22 b Fk(mtx)f Fl(is)h Fk(NULL)p Fl(,)e(or)i Fk(jcol)e Fl(is)i(not)g(in)g Fk([0,n2-1])p Fl(,)e(an)i(error)e(message)h(is)h(prin)n(ted)g(and)g(the)g(program)208 3319 y(exits.)101 3480 y(7.)42 b Fk(double)f(A2_infinityNorm)o(OfC)o (ol)o(umn)c(\()43 b(A2)g(*mtx,)e(int)i(jcol)e(\))j(;)208 3611 y Fl(This)27 b(metho)r(d)h(returns)f(the)h(in\014nit)n(y-norm)f (of)h(column)f Fk(jcol)f Fl(of)i(the)g(matrix.)208 3741 y Fg(Err)l(or)d(che)l(cking:)36 b Fl(If)22 b Fk(mtx)f Fl(is)h Fk(NULL)p Fl(,)e(or)i Fk(jcol)e Fl(is)i(not)g(in)g Fk([0,n2-1])p Fl(,)e(an)i(error)e(message)h(is)h(prin)n(ted)g(and)g (the)g(program)208 3841 y(exits.)101 4002 y(8.)42 b Fk(double)f (A2_oneNormOfRow)c(\()43 b(A2)g(*mtx,)e(int)i(irow)f(\))h(;)208 4133 y Fl(This)27 b(metho)r(d)h(returns)f(the)h(one-norm)e(of)i(ro)n(w) e Fk(irow)g Fl(of)i(the)g(matrix.)208 4263 y Fg(Err)l(or)d(che)l (cking:)36 b Fl(If)22 b Fk(mtx)f Fl(is)h Fk(NULL)p Fl(,)e(or)i Fk(irow)e Fl(is)i(not)g(in)g Fk([0,n1-1])p Fl(,)e(an)i(error)e(message) h(is)h(prin)n(ted)g(and)g(the)g(program)208 4363 y(exits.)101 4524 y(9.)42 b Fk(double)f(A2_twoNormOfRow)c(\()43 b(A2)g(*mtx,)e(int)i (irow)f(\))h(;)208 4655 y Fl(This)27 b(metho)r(d)h(returns)f(the)h(t)n (w)n(o-norm)e(of)h(ro)n(w)g Fk(irow)f Fl(of)h(the)h(matrix.)208 4785 y Fg(Err)l(or)d(che)l(cking:)36 b Fl(If)22 b Fk(mtx)f Fl(is)h Fk(NULL)p Fl(,)e(or)i Fk(irow)e Fl(is)i(not)g(in)g Fk([0,n1-1])p Fl(,)e(an)i(error)e(message)h(is)h(prin)n(ted)g(and)g (the)g(program)208 4885 y(exits.)60 5046 y(10.)41 b Fk(double)g (A2_infinityNorm)o(OfR)o(ow)c(\()43 b(A2)g(*mtx,)e(int)i(irow)f(\))h(;) 208 5177 y Fl(This)27 b(metho)r(d)h(returns)f(the)h(in\014nit)n(y-norm) f(of)h(ro)n(w)e Fk(irow)g Fl(of)i(the)g(matrix.)208 5308 y Fg(Err)l(or)d(che)l(cking:)36 b Fl(If)22 b Fk(mtx)f Fl(is)h Fk(NULL)p Fl(,)e(or)i Fk(irow)e Fl(is)i(not)g(in)g Fk([0,n1-1])p Fl(,)e(an)i(error)e(message)h(is)h(prin)n(ted)g(and)g (the)g(program)208 5407 y(exits.)p eop %%Page: 6 6 6 5 bop 0 100 a Fl(6)p 125 100 1212 4 v 1377 w Fk(A2)26 b Fe(:)37 b Fg(DRAFT)28 b Fe(Decem)n(b)r(er)f(16,)g(1998)p 2689 100 V 0 390 a Fd(1.2.6)112 b(Sort)37 b(metho)s(ds)101 569 y Fl(1.)42 b Fk(void)f(A2_permuteRows)d(\()43 b(A2)g(*mtx,)f(int)g (nrow,)g(int)g(index[])f(\))i(;)208 702 y Fl(The)31 b Fk(index[])d Fl(v)n(ector)i(con)n(tains)g(the)i Fg(r)l(ow)h(ids)f Fl(of)f(the)g(leading)g Fk(nrow)f Fl(ro)n(ws.)46 b(This)31 b(metho)r(d)g(p)r(erm)n(utes)g(the)h(lead-)208 802 y(ing)37 b Fk(nrow)f Fl(ro)n(ws)g(of)h(the)h(matrix)f(so)g(that)h(the)f Fk(index[])e Fl(v)n(ector)h(is)i(in)f(ascending)g(order.)65 b(This)38 b(metho)r(d)g(calls)208 902 y Fk(A2)p 301 902 27 4 v 30 w(permuteRows\(\))22 b Fl(but)29 b(do)r(es)e(not)g(o)n(v)n (erwrite)f(the)i Fk(index[])d Fl(v)n(ector.)208 1035 y Fg(Err)l(or)31 b(che)l(cking:)43 b Fl(If)30 b Fk(mtx)e Fl(or)h Fk(index[])d Fl(is)k Fk(NULL)p Fl(,)d(or)i(if)h Fk(nrow)42 b(<)h(0)29 b Fl(or)g Fk(nrow)42 b(>)h(n1)p Fl(,)29 b(an)g(error)f(message)g(is)h(prin)n(ted)208 1135 y(and)e(the)h(program)e(exits.)101 1302 y(2.)42 b Fk(void)f(A2_permuteColumns)c(\()43 b(A2)g(*mtx,)e(int)i(nrow,)e(int) i(index[])d(\))k(;)208 1435 y Fl(The)35 b Fk(index[])e Fl(v)n(ector)i(con)n(tains)f(the)j Fg(c)l(olumn)g(ids)f Fl(of)g(the)g(leading)f Fk(ncol)f Fl(ro)n(ws.)60 b(This)36 b(metho)r(d)g(p)r(erm)n(utes)g(the)208 1535 y(leading)c Fk(ncol)f Fl(columns)i(of)f(the)i(matrix)e(so)g(that)h(the)g Fk(index[])d Fl(v)n(ector)i(is)h(in)g(ascending)f(order.)51 b(This)33 b(metho)r(d)208 1634 y(calls)27 b Fk(A2)p 486 1634 V 30 w(permuteColumns\(\))21 b Fl(but)28 b(do)r(es)g(not)f(o)n(v)n (erwrite)f(the)i Fk(index[])c Fl(v)n(ector.)208 1768 y Fg(Err)l(or)31 b(che)l(cking:)43 b Fl(If)30 b Fk(mtx)e Fl(or)h Fk(index[])d Fl(is)k Fk(NULL)p Fl(,)d(or)i(if)h Fk(ncol)42 b(<)h(0)29 b Fl(or)g Fk(ncol)42 b(>)h(n2)p Fl(,)29 b(an)g(error)f(message)g(is)h(prin)n(ted)208 1867 y(and)e(the)h(program)e(exits.)101 2035 y(3.)42 b Fk(int)g(A2_sortRowsUp)c(\()43 b(A2)g(*mtx,)f(int)g(nrow,)f(int)i (rowids[])d(\))j(;)208 2168 y Fl(This)e(metho)r(d)g(sorts)f(the)i (leading)e Fk(nrow)g Fl(ro)n(ws)f(of)i(the)h(matrix)e(in)n(to)h (ascending)f(order)g(with)i(resp)r(ect)f(to)g(the)208 2268 y Fk(rowids[])24 b Fl(v)n(ector.)36 b(The)27 b(return)g(v)-5 b(alue)28 b(is)f(the)h(n)n(um)n(b)r(er)g(of)f(ro)n(w)f(sw)n(aps)h (made.)208 2401 y Fg(Err)l(or)34 b(che)l(cking:)47 b Fl(If)32 b Fk(mtx)f Fl(or)g Fk(rowids)e Fl(is)j Fk(NULL)p Fl(,)e(or)h(if)i Fk(nrow)42 b(<)h(0)31 b Fl(or)g Fk(nrow)42 b(>)h(n1)p Fl(,)33 b(an)e(error)f(message)g(is)i(prin)n(ted)208 2501 y(and)27 b(the)h(program)e(exits.)101 2668 y(4.)42 b Fk(int)g(A2_sortColumnsUp)37 b(\()43 b(A2)g(*mtx,)e(int)i(ncol,)e (int)i(colids[])d(\))j(;)208 2801 y Fl(This)30 b(metho)r(d)i(sorts)d (the)j(leading)e Fk(ncol)f Fl(columnss)i(of)f(the)i(matrix)e(in)n(to)h (ascending)e(order)h(with)h(resp)r(ect)g(to)g(the)208 2901 y Fk(colids[])24 b Fl(v)n(ector.)36 b(The)27 b(return)g(v)-5 b(alue)28 b(is)f(the)h(n)n(um)n(b)r(er)g(of)f(column)h(sw)n(aps)e (made.)208 3034 y Fg(Err)l(or)34 b(che)l(cking:)47 b Fl(If)32 b Fk(mtx)f Fl(or)g Fk(colids)e Fl(is)j Fk(NULL)p Fl(,)e(or)h(if)i Fk(ncol)42 b(<)h(0)31 b Fl(or)g Fk(ncol)42 b(>)h(n2)p Fl(,)33 b(an)e(error)f(message)g(is)i(prin)n(ted)208 3134 y(and)27 b(the)h(program)e(exits.)0 3393 y Fd(1.2.7)112 b(Utilit)m(y)38 b(metho)s(ds)101 3571 y Fl(1.)k Fk(int)g(A2_sizeOf)e (\()j(A2)g(*mtx)f(\))h(;)208 3705 y Fl(This)27 b(metho)r(d)h(returns)f (the)h(n)n(um)n(b)r(er)f(of)h(b)n(ytes)f(o)n(wned)g(b)n(y)h(this)f(ob)5 b(ject.)208 3838 y Fg(Err)l(or)30 b(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)f Fl(an)i(error)d(message)h(is)i (prin)n(ted)f(and)h(the)g(program)d(exits.)101 4005 y(2.)42 b Fk(void)f(A2_shiftBase)e(\()k(A2)g(*mtx,)f(int)g(rowoff,)f(int)h (coloff)f(\))i(;)208 4139 y Fl(This)27 b(metho)r(d)h(is)g(used)f(to)h (shift)g(the)g(base)f(of)h(the)f(en)n(tries)g(and)h(adjust)g (dimensions)f(of)g(the)h Fk(A2)f Fl(ob)5 b(ject.)208 4339 y Fk(mtx\(0:n1-rowoff)o(-1,)o(0:)o(n2)o(-co)o(lo)o(ff-)o(1\))37 b(:=)43 b(mtx\(rowoff:n1-1)o(,co)o(lo)o(ff:)o(n2)o(-1)o(\))208 4539 y Fg(Err)l(or)30 b(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)f Fl(an)i(error)d(message)h(is)i(prin)n(ted)f (and)h(the)g(program)d(exits.)101 4706 y(3.)42 b Fk(int)g(A2_rowMajor)d (\()k(A2)g(*mtx)f(\))h(;)208 4840 y Fl(This)27 b(metho)r(d)h(returns)f (1)g(if)h(the)g(storage)e(is)i(ro)n(w)e(ma)5 b(jor,)26 b(otherwise)h(it)h(returns)f(zero.)208 4973 y Fg(Err)l(or)j(che)l (cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d (message)i(is)g(prin)n(ted)h(and)f(the)h(program)e(exits.)101 5140 y(4.)42 b Fk(int)g(A2_columnMajor)c(\()43 b(A2)g(*mtx)f(\))h(;)208 5274 y Fl(This)27 b(metho)r(d)h(returns)f(1)g(if)h(the)g(storage)e(is)i (column)f(ma)5 b(jor,)27 b(otherwise)f(it)i(returns)f(zero.)208 5407 y Fg(Err)l(or)j(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n(ted)h(and)f (the)h(program)e(exits.)p eop %%Page: 7 7 7 6 bop 83 100 1212 4 v 1377 100 a Fk(A2)27 b Fe(:)37 b Fg(DRAFT)110 b Fe(Decem)n(b)r(er)28 b(16,)e(1998)p 2649 100 V 1212 w Fl(7)101 390 y(5.)42 b Fk(void)f(A2_transpose)e(\()k (A2)g(*mtx)f(\))h(;)208 520 y Fl(This)36 b(metho)r(d)g(replaces)f Fk(mtx)g Fl(with)i(its)g(transp)r(ose.)61 b(Note,)39 b(this)d(tak)n(es)f Fj(O)r Fl(\(1\))i(op)r(erations)e(since)h(w)n(e)g (just)h(sw)n(ap)208 619 y(dimensions)27 b(and)g(incremen)n(ts.)208 749 y Fg(Err)l(or)j(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n(ted)h(and)f (the)h(program)e(exits.)101 908 y(6.)42 b Fk(void)f(A2_extractRow)e(\() k(A2)g(*mtx,)e(double)g(row[],)g(int)i(irow)f(\))h(;)208 1037 y Fl(This)27 b(metho)r(d)h(\014lls)g(the)g Fk(row[])d Fl(v)n(ector)i(with)h(ro)n(w)e Fk(irow)g Fl(of)i(the)g(matrix.)208 1167 y Fg(Err)l(or)33 b(che)l(cking:)46 b Fl(If)32 b Fk(mtx)p Fl(,)g Fk(entries)c Fl(or)j Fk(row)f Fl(are)g Fk(NULL)p Fl(,)g(or)h(if)g Fk(irow)f Fl(is)i(not)f(in)h Fk([0,n1-1])p Fl(,)d(an)i(error)e(message)h(is)208 1266 y(prin)n(ted)d(and)g(the)h(program)e(exits.)101 1425 y(7.)42 b Fk(void)f(A2_extractRowDV)d(\()43 b(A2)g(*mtx,)e(DV)i (*rowDV,)e(int)h(irow)g(\))h(;)208 1555 y Fl(This)27 b(metho)r(d)h(\014lls)g(the)g Fk(rowDV)d Fl(ob)5 b(ject)28 b(with)g(ro)n(w)e Fk(irow)g Fl(of)i(the)g(matrix.)208 1684 y Fg(Err)l(or)k(che)l(cking:)44 b Fl(If)31 b Fk(mtx)e Fl(or)h Fk(rowDV)e Fl(are)i Fk(NULL)p Fl(,)e(or)i(if)h(the)f(matrix)g (is)g(not)h(real,)f(or)f(if)i Fk(irow)e Fl(is)h(not)h(in)f Fk([0,n1-1])p Fl(,)208 1784 y(an)d(error)e(message)i(is)g(prin)n(ted)h (and)f(the)h(program)e(exits.)101 1943 y(8.)42 b Fk(void)f (A2_extractRowZV)d(\()43 b(A2)g(*mtx,)e(ZV)i(*rowZV,)e(int)h(irow)g(\)) h(;)208 2072 y Fl(This)27 b(metho)r(d)h(\014lls)g(the)g Fk(rowZV)d Fl(ob)5 b(ject)28 b(with)g(ro)n(w)e Fk(irow)g Fl(of)i(the)g(matrix.)208 2202 y Fg(Err)l(or)d(che)l(cking:)36 b Fl(If)23 b Fk(mtx)f Fl(or)f Fk(rowZV)g Fl(are)g Fk(NULL)p Fl(,)g(or)h(if)h(the)g(matrix)f(is)g(not)h(complex,)g(or)f(if)h Fk(irow)e Fl(is)h(not)g(in)h Fk([0,n1-1])p Fl(,)208 2301 y(an)k(error)e(message)i(is)g(prin)n(ted)h(and)f(the)h(program)e (exits.)101 2461 y(9.)42 b Fk(void)f(A2_extractColumn)c(\()44 b(A2)e(*mtx,)g(double)f(col[],)g(int)h(jcol)g(\))i(;)208 2590 y Fl(This)27 b(metho)r(d)h(\014lls)g(the)g Fk(col[])d Fl(v)n(ector)i(with)h(column)f Fk(jcol)f Fl(of)i(the)g(matrix.)208 2719 y Fg(Err)l(or)33 b(che)l(cking:)46 b Fl(If)32 b Fk(mtx)p Fl(,)g Fk(entries)c Fl(or)j Fk(col)f Fl(are)g Fk(NULL)p Fl(,)g(or)h(if)g Fk(jcol)f Fl(is)i(not)f(in)h Fk([0,n2-1])p Fl(,)d(an)i(error)e(message)h(is)208 2819 y(prin)n(ted)d(and)g(the)h(program)e(exits.)60 2978 y(10.)41 b Fk(void)g(A2_extractColumnD)o(V)d(\()43 b(A2)g(*mtx,)e(DV)i(*colDV,)e (int)h(jcol)g(\))h(;)208 3108 y Fl(This)27 b(metho)r(d)h(\014lls)g(the) g Fk(colDV)d Fl(ob)5 b(ject)28 b(with)g(column)g Fk(jcol)e Fl(of)h(the)h(matrix.)208 3237 y Fg(Err)l(or)d(che)l(cking:)36 b Fl(If)23 b Fk(mtx)f Fl(or)f Fk(colDV)g Fl(are)g Fk(NULL)p Fl(,)g(or)h(if)h(the)g(matrix)f(is)g(not)h(complex,)g(or)f(if)h Fk(jcol)e Fl(is)h(not)g(in)h Fk([0,n2-1])p Fl(,)208 3337 y(an)k(error)e(message)i(is)g(prin)n(ted)h(and)f(the)h(program)e (exits.)60 3496 y(11.)41 b Fk(void)g(A2_extractColumnZ)o(V)d(\()43 b(A2)g(*mtx,)e(ZV)i(*colZV,)e(int)h(jcol)g(\))h(;)208 3625 y Fl(This)27 b(metho)r(d)h(\014lls)g(the)g Fk(colZV)d Fl(ob)5 b(ject)28 b(with)g(column)g Fk(jcol)e Fl(of)h(the)h(matrix.)208 3755 y Fg(Err)l(or)d(che)l(cking:)36 b Fl(If)23 b Fk(mtx)f Fl(or)f Fk(colZV)g Fl(are)g Fk(NULL)p Fl(,)g(or)h(if)h(the)g(matrix)f (is)g(not)h(complex,)g(or)f(if)h Fk(jcol)e Fl(is)h(not)g(in)h Fk([0,n2-1])p Fl(,)208 3854 y(an)k(error)e(message)i(is)g(prin)n(ted)h (and)f(the)h(program)e(exits.)60 4014 y(12.)41 b Fk(void)g(A2_setRow)f (\()k(A2)e(*mtx,)g(double)f(row[],)g(int)h(irow)g(\))h(;)208 4143 y Fl(This)27 b(metho)r(d)h(\014lls)g(ro)n(w)e Fk(irow)g Fl(of)i(the)g(matrix)f(with)h(the)g(en)n(tries)f(in)h(the)g Fk(row[])d Fl(v)n(ector.)208 4272 y Fg(Err)l(or)k(che)l(cking:)39 b Fl(If)27 b Fk(mtx)p Fl(,)f Fk(entries)e Fl(or)j Fk(row[])e Fl(are)h Fk(NULL)p Fl(,)f(or)h(if)i Fk(irow)d Fl(is)i(not)g(in)h Fk([0,n1-1])p Fl(,)c(an)i(error)g(message)f(is)208 4372 y(prin)n(ted)i(and)g(the)h(program)e(exits.)60 4531 y(13.)41 b Fk(void)g(A2_setRowDV)f(\()j(A2)f(*mtx,)g(DV)h(rowDV,)e(int)h(irow)g (\))h(;)208 4661 y Fl(This)27 b(metho)r(d)h(\014lls)g(ro)n(w)e Fk(irow)g Fl(of)i(the)g(matrix)f(with)h(the)g(en)n(tries)f(in)h(the)g Fk(rowDV)d Fl(ob)5 b(ject.)208 4790 y Fg(Err)l(or)32 b(che)l(cking:)44 b Fl(If)31 b Fk(mtx)e Fl(or)h Fk(rowDV)e Fl(are)i Fk(NULL)p Fl(,)e(or)i(if)h(the)f(matrix)g(is)g(not)h(real,)f (or)f(if)i Fk(irow)e Fl(is)h(not)h(in)f Fk([0,n1-1])p Fl(,)208 4890 y(an)d(error)e(message)i(is)g(prin)n(ted)h(and)f(the)h (program)e(exits.)60 5049 y(14.)41 b Fk(void)g(A2_setRowZV)f(\()j(A2)f (*mtx,)g(ZV)h(rowZV,)e(int)h(irow)g(\))h(;)208 5178 y Fl(This)27 b(metho)r(d)h(\014lls)g(ro)n(w)e Fk(irow)g Fl(of)i(the)g(matrix)f(with)h(the)g(en)n(tries)f(in)h(the)g Fk(rowZV)d Fl(ob)5 b(ject.)208 5308 y Fg(Err)l(or)25 b(che)l(cking:)36 b Fl(If)23 b Fk(mtx)f Fl(or)f Fk(rowZV)g Fl(are)g Fk(NULL)p Fl(,)g(or)h(if)h(the)g(matrix)f(is)g(not)h(complex,) g(or)f(if)h Fk(irow)e Fl(is)h(not)g(in)h Fk([0,n1-1])p Fl(,)208 5407 y(an)k(error)e(message)i(is)g(prin)n(ted)h(and)f(the)h (program)e(exits.)p eop %%Page: 8 8 8 7 bop 0 100 a Fl(8)p 125 100 1212 4 v 1377 w Fk(A2)26 b Fe(:)37 b Fg(DRAFT)28 b Fe(Decem)n(b)r(er)f(16,)g(1998)p 2689 100 V 60 390 a Fl(15.)41 b Fk(void)g(A2_setColumn)e(\()k(A2)g (*mtx,)f(double)f(col[],)g(int)h(jcol)g(\))h(;)208 529 y Fl(This)27 b(metho)r(d)h(\014lls)g(column)f Fk(jcol)f Fl(of)i(the)g(matrix)f(with)h(the)g(en)n(tries)f(in)h(the)g Fk(col[])e Fl(v)n(ector.)208 668 y Fg(Err)l(or)32 b(che)l(cking:)45 b Fl(If)31 b Fk(mtx)e Fl(or)g Fk(colZV)g Fl(are)g Fk(NULL)p Fl(,)g(or)h(if)h Fk(jcol)e Fl(is)h(not)g(in)h Fk([0,n2-1])p Fl(,)d(an)i(error)f(message)g(is)h(prin)n(ted)208 767 y(and)d(the)h(program)e(exits.)60 945 y(16.)41 b Fk(void)g (A2_setColumnDV)d(\()43 b(A2)g(*mtx,)f(DV)g(colDV,)g(int)g(jcol)g(\))h (;)208 1084 y Fl(This)27 b(metho)r(d)h(\014lls)g(column)f Fk(jcol)f Fl(of)i(the)g(matrix)f(with)h(the)g(en)n(tries)f(in)h(the)g Fk(colDV)e Fl(ob)5 b(ject.)208 1223 y Fg(Err)l(or)25 b(che)l(cking:)36 b Fl(If)23 b Fk(mtx)f Fl(or)f Fk(colDV)g Fl(are)g Fk(NULL)p Fl(,)g(or)h(if)h(the)g(matrix)f(is)g(not)h(complex,) g(or)f(if)h Fk(jcol)e Fl(is)h(not)g(in)h Fk([0,n2-1])p Fl(,)208 1322 y(an)k(error)e(message)i(is)g(prin)n(ted)h(and)f(the)h (program)e(exits.)60 1500 y(17.)41 b Fk(void)g(A2_setColumnZV)d(\()43 b(A2)g(*mtx,)f(ZV)g(colZV,)g(int)g(jcol)g(\))h(;)208 1639 y Fl(This)27 b(metho)r(d)h(\014lls)g(column)f Fk(jcol)f Fl(of)i(the)g(matrix)f(with)h(the)g(en)n(tries)f(in)h(the)g Fk(colZV)e Fl(ob)5 b(ject.)208 1778 y Fg(Err)l(or)25 b(che)l(cking:)36 b Fl(If)23 b Fk(mtx)f Fl(or)f Fk(colZV)g Fl(are)g Fk(NULL)p Fl(,)g(or)h(if)h(the)g(matrix)f(is)g(not)h(complex,) g(or)f(if)h Fk(jcol)e Fl(is)h(not)g(in)h Fk([0,n2-1])p Fl(,)208 1878 y(an)k(error)e(message)i(is)g(prin)n(ted)h(and)f(the)h (program)e(exits.)60 2055 y(18.)41 b Fk(void)g(A2_fillRandomUnif)o(orm) c(\()43 b(A2)g(*mtx,)e(double)g(lower,)g(double)h(upper,)f(int)h(seed)g (\))h(;)208 2194 y Fl(This)18 b(metho)r(d)h(\014lls)f(the)h(matrix)f (with)h(random)e(n)n(um)n(b)r(ers)h(tak)n(en)g(from)g(a)g(uniform)g (distribution)h(on)f Fk([lower,upper])208 2294 y Fl(using)27 b(the)h Fk(Drand)d Fl(ob)5 b(ject.)208 2433 y Fg(Err)l(or)30 b(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n(ted)h(and)f(the)h(program)e (exits.)60 2610 y(19.)41 b Fk(void)g(A2_fillWithIdenti)o(ty)c(\()43 b(A2)g(*mtx)f(\))h(;)208 2749 y Fl(This)27 b(metho)r(d)h(\014lls)g(the) g(matrix)f(with)h(the)g(iden)n(tit)n(y)g(matrix.)208 2888 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)f Fl(or)h(if)h Fk(n1)43 b(!=)g(n2)p Fl(,)27 b(an)g(error)f(message)g(is)h(prin)n(ted)h(and)f(the)h(program)e (exits.)60 3066 y(20.)41 b Fk(void)g(A2_zero)g(\()i(A2)g(*mtx)f(\))h(;) 208 3205 y Fl(This)27 b(metho)r(d)h(\014lls)g(the)g(matrix)f(with)h (zeros.)208 3343 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(is)g Fk(NULL)p Fl(,)f(an)i(error)d(message)i(is)g(prin)n (ted)h(and)f(the)h(program)e(exits.)60 3521 y(21.)41 b Fk(void)g(A2_copy)g(\()i(A2)g(*mtxA,)e(A2)i(*mtxB)e(\))j(;)208 3660 y Fl(This)30 b(metho)r(d)h(copies)e(en)n(tries)h(from)g(matrix)g Fk(mtxB)f Fl(in)n(to)h(matrix)g Fk(mtxA)p Fl(.)f(Note,)i Fk(mtxA)e Fl(and)h Fk(mtxB)e Fl(need)j(not)f(b)r(e)h(of)208 3760 y(the)25 b(same)f(size,)h(the)g(leading)f Fk(min\(mtxA->n1,mtx)o (B-)o(>n)o(1\))18 b Fl(ro)n(ws)24 b(and)g Fk(min\(mtxA->n2,mtx)o(B->)o (n2)o(\))19 b Fl(columns)24 b(are)208 3859 y(copied.)208 3998 y Fg(Err)l(or)30 b(che)l(cking:)38 b Fl(If)28 b Fk(mtxA)e Fl(or)g Fk(mtxB)g Fl(is)i Fk(NULL)p Fl(,)d(or)i(if)h(the)g (matrices)e(are)h(not)g(of)h(the)f(same)g(t)n(yp)r(e,)h(an)f(error)e (message)208 4098 y(is)i(prin)n(ted)h(and)f(the)h(program)e(exits.)60 4276 y(22.)41 b Fk(void)g(A2_sub)h(\()h(A2)g(*mtxA,)e(A2)h(*mtxB)g(\))h (;)208 4414 y Fl(This)27 b(metho)r(d)h(subtracts)e(en)n(tries)h(in)h (matrix)e Fk(mtxB)g Fl(from)h(en)n(tries)g(in)g(matrix)g Fk(mtxA)p Fl(.)f(Note,)h Fk(mtxA)f Fl(and)h Fk(mtxB)f Fl(need)208 4514 y(not)34 b(b)r(e)h(of)g(the)f(same)g(size,)i(the)f (leading)f Fk(min\(mtxA->n1,mtxB)o(->)o(n1\))28 b Fl(ro)n(ws)33 b(and)h Fk(min\(mtxA->n2,mtx)o(B->)o(n2)o(\))208 4614 y Fl(columns)27 b(are)f(subtracted.)208 4752 y Fg(Err)l(or)k(che)l (cking:)38 b Fl(If)28 b Fk(mtxA)e Fl(or)g Fk(mtxB)g Fl(is)i Fk(NULL)p Fl(,)d(or)i(if)h(the)g(matrices)e(are)h(not)g(of)h(the)f (same)g(t)n(yp)r(e,)h(an)f(error)e(message)208 4852 y(is)i(prin)n(ted)h (and)f(the)h(program)e(exits.)60 5030 y(23.)41 b Fk(void)g(A2_swapRows) f(\()j(A2)f(*mtx,)g(int)g(irow1,)f(int)i(irow2)e(\))i(;)208 5169 y Fl(This)27 b(metho)r(d)h(sw)n(aps)f(ro)n(ws)f Fk(irow1)f Fl(and)j Fk(irow2)d Fl(of)j(the)g(matrix.)208 5308 y Fg(Err)l(or)34 b(che)l(cking:)49 b Fl(If)33 b Fk(mtxA)e Fl(or)h Fk(mtxB)f Fl(is)i Fk(NULL)p Fl(,)e(or)h(if)h Fk(irow1)e Fl(or)h Fk(irow2)e Fl(are)i(out)h(of)f(range,)h(an)f(error)f (message)g(is)208 5407 y(prin)n(ted)c(and)g(the)h(program)e(exits.)p eop %%Page: 9 9 9 8 bop 83 100 1212 4 v 1377 100 a Fk(A2)27 b Fe(:)37 b Fg(DRAFT)110 b Fe(Decem)n(b)r(er)28 b(16,)e(1998)p 2649 100 V 1212 w Fl(9)60 390 y(24.)41 b Fk(void)g(A2_swapColumns)d(\() 43 b(A2)g(*mtx,)f(int)g(irow1,)f(int)i(irow2)e(\))i(;)208 523 y Fl(This)27 b(metho)r(d)h(sw)n(aps)f(columns)g Fk(jcol1)f Fl(and)h Fk(jcol2)f Fl(of)h(the)h(matrix.)208 655 y Fg(Err)l(or)34 b(che)l(cking:)49 b Fl(If)33 b Fk(mtxA)e Fl(or)h Fk(mtxB)f Fl(is)i Fk(NULL)p Fl(,)e(or)h(if)h Fk(jcol1)e Fl(or)h Fk(jcol1)e Fl(are)i(out)h(of)f(range,)h(an)f(error)f(message)g(is)208 755 y(prin)n(ted)c(and)g(the)h(program)e(exits.)60 920 y(25.)41 b Fk(int)h(A2_copyEntriesTo)o(Ve)o(cto)o(r)37 b(\()44 b(A2)e(*mtx,)g(int)g(length,)f(double)g(dvec[],)1472 1020 y(int)h(copyflag,)e(int)i(storeflag)e(\))j(;)208 1153 y Fl(This)28 b(metho)r(d)h(copies)f(selected)g(en)n(tries)g(from)g Fk(mtx)f Fl(in)n(to)h(the)h(v)n(ector)e Fk(dvec[])f Fl(with)j(length)g Fk(length)p Fl(.)37 b(The)29 b(return)208 1252 y(v)-5 b(alue)34 b(is)h(the)g(n)n(um)n(b)r(er)g(of)g(en)n(tries)f(copied.)58 b(This)35 b(metho)r(d)g(is)g(used)g(during)f(the)h Fj(QR)h Fl(factorization)d(to)i(extract)208 1352 y(factor)25 b(en)n(tries)h(and)g(up)r(date)h(matrix)f(en)n(tries)g(from)g(a)g(fron) n(t.)36 b(All)27 b(en)n(tries)e(ma)n(y)h(b)r(e)h(copied,)f(or)g(only)g (the)h(diagonal,)208 1451 y(lo)n(w)n(er)f(or)g(upp)r(er)i(en)n(tries,)f (and)g(the)h(en)n(tries)f(ma)n(y)g(b)r(e)h(copied)f(to)h Fk(dvec[])d Fl(b)n(y)i(ro)n(ws)g(or)f(b)n(y)i(columns.)208 1584 y Fg(Err)l(or)c(che)l(cking:)36 b Fl(If)21 b Fk(mtx)g Fl(or)f Fk(dvec)g Fl(is)h Fk(NULL)p Fl(,)f(or)h(if)g Fk(length)e Fl(is)j(not)f(as)g(large)f(as)g(the)i(n)n(um)n(b)r(er)f(of) h(en)n(tries)e(to)i(b)r(e)f(copied,)208 1684 y(or)32 b(if)h Fk(copyflag)d Fl(is)i(not)h(one)g(of)g Fk(A2)p 1370 1684 27 4 v 30 w(STRICT)p 1664 1684 V 29 w(LOWER)p Fl(,)e Fk(A2)p 2055 1684 V 31 w(LOWER)p Fl(,)g Fk(A2)p 2448 1684 V 30 w(DIAGONAL)p Fl(,)f Fk(A2)p 2971 1684 V 31 w(UPPER)p Fl(,)h Fk(A2)p 3364 1684 V 30 w(STRICT)p 3658 1684 V 29 w(UPPER)208 1783 y Fl(or)f Fk(A2)p 406 1783 V 30 w(ALL)p 568 1783 V 30 w(ENTRIES)p Fl(,)f(or)h(if)h Fk(storeflag)d Fl(is)i(not)h(one)g(of)g Fk(A2)p 2145 1783 V 30 w(BY)p 2263 1783 V 31 w(ROWS)e Fl(or)i Fk(A2)p 2693 1783 V 30 w(BY)p 2811 1783 V 31 w(COLUMNS)p Fl(,)d(an)j(error)e (message)g(is)208 1883 y(prin)n(ted)e(and)g(the)h(program)e(exits.)0 2140 y Fd(1.2.8)112 b(IO)38 b(metho)s(ds)0 2317 y Fl(There)27 b(are)g(the)h(usual)f(eigh)n(t)g(IO)g(routines)g(plus)h(a)f(metho)r(d)h (to)g(write)f(the)h(ob)5 b(ject)28 b(to)f(a)g(Matlab)g(\014le.)101 2523 y(1.)42 b Fk(int)g(A2_readFromFile)37 b(\()43 b(A2)g(*mtx,)f(char) g(*fn)g(\))h(;)208 2656 y Fl(This)28 b(metho)r(d)i(reads)d(a)i Fk(A2)f Fl(ob)5 b(ject)28 b(from)h(a)f(\014le.)41 b(It)29 b(tries)f(to)h(op)r(en)g(the)g(\014le)g(and)f(if)i(it)f(is)f (successful,)h(it)g(then)h(calls)208 2755 y Fk(A2)p 301 2755 V 30 w(readFromFormatte)o(dFi)o(le)o(\(\))k Fl(or)39 b Fk(A2)p 1576 2755 V 30 w(readFromBinaryFil)o(e\()o(\))p Fl(,)e(closes)i(the)i(\014le)f(and)g(returns)f(the)h(v)-5 b(alue)208 2855 y(returned)27 b(from)g(the)h(called)f(routine.)208 2988 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)27 b Fk(mtx)e Fl(or)g Fk(fn)h Fl(are)g Fk(NULL)p Fl(,)f(or)g(if)i Fk(fn)f Fl(is)g(not)g(of)h(the)g(form)f Fk(*.a2f)e Fl(\(for)i(a)g(formatted)h (\014le\))g(or)e Fk(*.a2b)208 3087 y Fl(\(for)i(a)g(binary)g(\014le\),) h(an)f(error)f(message)g(is)i(prin)n(ted)f(and)h(the)g(metho)r(d)g (returns)f(zero.)101 3253 y(2.)42 b Fk(int)g(A2_readFromForma)o(tt)o (edF)o(il)o(e)c(\()43 b(A2)f(*mtx,)g(FILE)g(*fp)g(\))h(;)208 3385 y Fl(This)34 b(metho)r(d)h(reads)f(a)g Fk(A2)g Fl(ob)5 b(ject)34 b(from)g(a)g(formatted)h(\014le)g(whose)e(p)r(oin)n(ter)i(is) f Fk(fp)p Fl(.)57 b(If)35 b(there)g(are)e(no)h(errors)f(in)208 3485 y(reading)25 b(the)j(data,)e(the)i(v)-5 b(alue)26 b Fk(1)h Fl(is)g(returned.)36 b(If)27 b(an)g(IO)g(error)e(is)h(encoun)n (tered)g(from)h Fk(fscanf)p Fl(,)e(zero)h(is)g(returned.)208 3617 y Fg(Err)l(or)k(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(or)g Fk(fp)f Fl(are)h Fk(NULL)p Fl(,)f(an)h(error)f(message)g(is)i (prin)n(ted)f(and)h(zero)e(is)i(returned.)101 3783 y(3.)42 b Fk(int)g(A2_readFromBinar)o(yF)o(ile)37 b(\()43 b(A2)g(*mtx,)e(FILE)h (*fp)h(\))g(;)208 3915 y Fl(This)26 b(metho)r(d)h(reads)e(a)h Fk(A2)f Fl(ob)5 b(ject)27 b(from)f(a)g(binary)f(\014le)i(whose)e(p)r (oin)n(ter)h(is)g Fk(fp)p Fl(.)36 b(If)27 b(there)f(are)f(no)i(errors)d (in)i(reading)208 4015 y(the)i(data,)f(the)h(v)-5 b(alue)27 b Fk(1)g Fl(is)h(returned.)36 b(If)28 b(an)g(IO)f(error)f(is)h(encoun)n (tered)g(from)g Fk(fread)p Fl(,)f(zero)g(is)i(returned.)208 4148 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(or)g Fk(fp)f Fl(are)h Fk(NULL)p Fl(,)f(an)h(error)f(message)g(is)i (prin)n(ted)f(and)h(zero)e(is)i(returned.)101 4313 y(4.)42 b Fk(int)g(A2_writeToFile)c(\()43 b(A2)g(*mtx,)e(char)h(*fn)g(\))i(;) 208 4446 y Fl(This)31 b(metho)r(d)h(writes)f(a)g Fk(A2)g Fl(ob)5 b(ject)31 b(to)h(a)f(\014le.)49 b(It)32 b(tries)f(to)g(op)r(en) h(the)g(\014le)g(and)f(if)h(it)g(is)f(successful,)i(it)f(then)g(calls) 208 4545 y Fk(A2)p 301 4545 V 30 w(writeFromFormatt)o(edF)o(il)o(e\(\)) 24 b Fl(or)29 b Fk(A2)p 1600 4545 V 31 w(writeFromBinaryF)o(ile)o(\(\)) o Fl(,)d(closes)j(the)i(\014le)g(and)f(returns)g(the)h(v)-5 b(alue)208 4645 y(returned)27 b(from)g(the)h(called)f(routine.)208 4777 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)27 b Fk(mtx)e Fl(or)g Fk(fn)h Fl(are)g Fk(NULL)p Fl(,)f(or)g(if)i Fk(fn)f Fl(is)g(not)g(of)h(the)g(form)f Fk(*.a2f)e Fl(\(for)i(a)g(formatted)h (\014le\))g(or)e Fk(*.a2b)208 4877 y Fl(\(for)i(a)g(binary)g(\014le\),) h(an)f(error)f(message)g(is)i(prin)n(ted)f(and)h(the)g(metho)r(d)g (returns)f(zero.)101 5042 y(5.)42 b Fk(int)g(A2_writeToFormat)o(te)o (dFi)o(le)37 b(\()43 b(A2)g(*mtx,)e(FILE)h(*fp)h(\))g(;)208 5175 y Fl(This)23 b(metho)r(d)i(writes)e(a)h Fk(A2)f Fl(ob)5 b(ject)23 b(to)h(a)f(formatted)h(\014le)g(whose)f(p)r(oin)n (ter)h(is)f Fk(fp)p Fl(.)35 b(If)25 b(there)e(are)g(no)h(errors)d(in)j (writing)208 5275 y(the)k(data,)f(the)h(v)-5 b(alue)27 b Fk(1)g Fl(is)h(returned.)36 b(If)28 b(an)g(IO)f(error)f(is)h(encoun)n (tered)g(from)g Fk(fprintf)p Fl(,)e(zero)h(is)i(returned.)208 5407 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(or)g Fk(fp)f Fl(are)h Fk(NULL)p Fl(,)f(an)h(error)f(message)g(is)i (prin)n(ted)f(and)h(zero)e(is)i(returned.)p eop %%Page: 10 10 10 9 bop 0 100 a Fl(10)p 166 100 1191 4 v 1355 w Fk(A2)27 b Fe(:)37 b Fg(DRAFT)27 b Fe(Decem)n(b)r(er)h(16,)f(1998)p 2710 100 V 101 390 a Fl(6.)42 b Fk(int)g(A2_writeToBinary)o(Fi)o(le)37 b(\()43 b(A2)g(*mtx,)f(FILE)g(*fp)g(\))h(;)208 523 y Fl(This)29 b(metho)r(d)i(writes)e(a)h Fk(A2)f Fl(ob)5 b(ject)30 b(to)g(a)f(binary)h(\014le)g(whose)f(p)r(oin)n(ter)h(is)f Fk(fp)p Fl(.)44 b(If)30 b(there)g(are)f(no)g(errors)f(in)i(writing)208 622 y(the)e(data,)f(the)h(v)-5 b(alue)27 b Fk(1)g Fl(is)h(returned.)36 b(If)28 b(an)g(IO)f(error)f(is)h(encoun)n(tered)g(from)g Fk(fwrite)p Fl(,)e(zero)i(is)g(returned.)208 754 y Fg(Err)l(or)j(che)l (cking:)38 b Fl(If)28 b Fk(mtx)f Fl(or)g Fk(fp)f Fl(are)h Fk(NULL)p Fl(,)f(an)h(error)f(message)g(is)i(prin)n(ted)f(and)h(zero)e (is)i(returned.)101 920 y(7.)42 b Fk(void)f(A2_writeForHumanE)o(ye)c (\()43 b(A2)g(*mtx,)f(FILE)g(*fp)g(\))h(;)208 1052 y Fl(This)29 b(metho)r(d)g(writes)g(a)f Fk(A2)h Fl(ob)5 b(ject)28 b(to)h(a)g(\014le)g(in)g(an)g(easily)f(readable)g(format.)41 b(The)29 b(metho)r(d)g Fk(A2)p 3351 1052 27 4 v 31 w(writeStats\(\))208 1151 y Fl(is)e(called)g(to)h(write)f(out)h(the)g(header)e(and)i (statistics.)208 1284 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(or)g Fk(fp)f Fl(are)h Fk(NULL)p Fl(,)f(an)h(error)f(message)g(is)i(prin)n(ted)f(and)h(zero)e(is)i (returned.)101 1449 y(8.)42 b Fk(void)f(A2_writeStats)e(\()k(A2)g (*mtx,)e(FILE)h(*fp)g(\))i(;)208 1581 y Fl(This)27 b(metho)r(d)h (writes)f(a)h(header)e(and)i(some)f(statistics)g(to)h(a)f(\014le.)208 1713 y Fg(Err)l(or)j(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(or)g Fk(fp)f Fl(are)h Fk(NULL)p Fl(,)f(an)h(error)f(message)g(is)i (prin)n(ted)f(and)h(zero)e(is)i(returned.)101 1879 y(9.)42 b Fk(void)f(A2_writeForMatlab)c(\()43 b(A2)g(*mtx,)e(char)h(*mtxname,)e (FILE)i(*fp)h(\))g(;)208 2011 y Fl(This)31 b(metho)r(d)i(writes)e(the)i (en)n(tries)e(of)h(the)g(matrix)g(to)g(a)f(\014le)h(in)h(Matlab)e (format.)50 b(The)32 b(name)f(of)h(the)h(matrix)e(is)208 2110 y Fk(mtxname)p Fl(.)208 2243 y Fg(Err)l(or)f(che)l(cking:)38 b Fl(If)28 b Fk(mtx)p Fl(,)f Fk(mtxname)e Fl(or)h Fk(fp)h Fl(are)g Fk(NULL)p Fl(,)f(an)h(error)f(message)g(is)i(prin)n(ted)f(and) g(zero)g(is)g(returned.)0 2541 y Fi(1.3)135 b(Driv)l(er)46 b(programs)g(for)f(the)g Ff(A2)60 b(object)101 2748 y Fl(1.)42 b Fk(test_norms)d(msglvl)i(msgFile)g(type)h(nrow)g(ncol)g (inc1)g(inc2)f(seed)208 2880 y Fl(This)31 b(driv)n(er)f(program)f (tests)i(the)h Fk(A2)e Fl(norm)h(metho)r(ds.)48 b(Use)31 b(the)g(script)g(\014le)h Fk(do)p 2818 2880 V 30 w(norms)e Fl(for)g(testing.)48 b(When)32 b(the)208 2980 y(output)24 b(\014le)g(is)g(loaded)f(in)n(to)h(matlab,)g(the)h(last)e(t)n(w)n(o)h (lines)f(con)n(tain)h(matrices)f(whose)g(en)n(tries)g(should)h(all)g(b) r(e)g(around)208 3079 y(mac)n(hine)j(epsilon.)307 3260 y Fh(\017)41 b Fl(The)23 b Fk(msglvl)e Fl(parameter)g(determines)i(the) h(amoun)n(t)e(of)h(output.)36 b(Use)23 b Fk(msglvl)41 b(=)i(1)23 b Fl(for)g(just)g(timing)g(output.)307 3392 y Fh(\017)41 b Fl(The)32 b Fk(msgFile)c Fl(parameter)i(determines)h (the)h(message)e(\014le)i(|)f(if)h Fk(msgFile)d Fl(is)i Fk(stdout)p Fl(,)f(then)i(the)g(message)390 3492 y(\014le)c(is)f Fg(stdout)p Fl(,)h(otherwise)e(a)i(\014le)f(is)h(op)r(ened)f(with)i Fg(app)l(end)g Fl(status)e(to)g(receiv)n(e)g(an)n(y)g(output)h(data.) 307 3624 y Fh(\017)41 b Fl(The)28 b Fk(type)e Fl(parameter)g(denotes)h (the)h(t)n(yp)r(e)g(of)g(en)n(tries)f(|)g Fk(SPOOLES)p 2574 3624 V 29 w(REAL)f Fl(or)g Fk(SPOOLES)p 3214 3624 V 29 w(COMPLEX)307 3755 y Fh(\017)41 b Fl(The)28 b Fk(nrow)e Fl(parameter)g(is)h(the)h(n)n(um)n(b)r(er)g(of)f(ro)n(ws.)307 3887 y Fh(\017)41 b Fl(The)28 b Fk(ncol)e Fl(parameter)g(is)h(the)h(n)n (um)n(b)r(er)g(of)f(ro)n(ws.)307 4019 y Fh(\017)41 b Fl(The)28 b Fk(inc1)e Fl(parameter)g(is)h(the)h(ro)n(w)f(incremen)n(t.) 307 4151 y Fh(\017)41 b Fl(The)28 b Fk(inc2)e Fl(parameter)g(is)h(the)h (column)g(incremen)n(t.)307 4283 y Fh(\017)41 b Fl(The)28 b Fk(seed)e Fl(parameter)g(is)h(a)h(random)e(n)n(um)n(b)r(er)i(seed.) 101 4464 y(2.)42 b Fk(test_QR)e(msglvl)h(msgFile)g(type)h(nrow)g(ncol)g (inc1)g(inc2)g(seed)208 4596 y Fl(This)22 b(driv)n(er)g(program)e (tests)j(the)g Fk(A2)p 1376 4596 V 30 w(QRreduce\(\))c Fl(and)k Fk(A2)p 2110 4596 V 30 w(QRreduce2\(\))18 b Fl(metho)r(ds)23 b(whic)n(h)g(reduce)f Fj(A)h Fl(to)g Fj(QR)g Fl(via)208 4696 y(rank-1)g(and)i(rank-2)f(up)r(dates.)36 b(Use)25 b(the)h(script)f(\014le)h Fk(do)p 1979 4696 V 30 w(QR)f Fl(for)f(testing.)37 b(When)25 b Fk(msglvl)41 b(>)j(1)p Fl(,)25 b(the)h(matrix)f Fj(A)g Fl(and)208 4795 y(matrices)d Fj(R)q Fl(1)g(and)g Fj(R)q Fl(2)g(\(computed)h(from)g Fk(A2)p 1643 4795 V 30 w(QRreduce\(\))c Fl(and)k Fk(A2)p 2377 4795 V 30 w(QRreduce2\(\))p Fl(,)d(resp)r(ectiv)n(ely\))i(are)g (prin)n(ted)g(to)208 4895 y(the)h(message)e(\014le.)36 b(When)23 b(the)h(output)f(\014le)g(is)g(loaded)f(in)n(to)h(matlab,)h (the)f(errors)e Fj(A)2831 4865 y Fb(T)2883 4895 y Fj(A)9 b Fh(\000)g Fj(R)3092 4865 y Fb(T)3091 4916 y Fa(1)3144 4895 y Fj(R)3207 4907 y Fa(1)3267 4895 y Fl(and)23 b Fj(A)3486 4865 y Fb(T)3539 4895 y Fj(A)9 b Fh(\000)g Fj(R)3748 4865 y Fb(T)3747 4916 y Fa(2)3800 4895 y Fj(R)3863 4907 y Fa(2)208 4995 y Fl(\(if)28 b Fj(A)g Fl(is)f(real\))g(or)g(the)h (errors)d Fj(A)1226 4964 y Fb(H)1290 4995 y Fj(A)18 b Fh(\000)g Fj(R)1517 4964 y Fb(H)1516 5015 y Fa(1)1580 4995 y Fj(R)1643 5007 y Fa(1)1708 4995 y Fl(and)27 b Fj(A)1931 4964 y Fb(H)1995 4995 y Fj(A)18 b Fh(\000)g Fj(R)2222 4964 y Fb(H)2221 5015 y Fa(2)2285 4995 y Fj(R)2348 5007 y Fa(2)2413 4995 y Fl(\(if)28 b Fj(A)g Fl(is)g(complex\))f(are)g (computed.)307 5176 y Fh(\017)41 b Fl(The)23 b Fk(msglvl)e Fl(parameter)g(determines)i(the)h(amoun)n(t)e(of)h(output.)36 b(Use)23 b Fk(msglvl)41 b(=)i(1)23 b Fl(for)g(just)g(timing)g(output.) 307 5308 y Fh(\017)41 b Fl(The)32 b Fk(msgFile)c Fl(parameter)i (determines)h(the)h(message)e(\014le)i(|)f(if)h Fk(msgFile)d Fl(is)i Fk(stdout)p Fl(,)f(then)i(the)g(message)390 5407 y(\014le)c(is)f Fg(stdout)p Fl(,)h(otherwise)e(a)i(\014le)f(is)h(op)r (ened)f(with)i Fg(app)l(end)g Fl(status)e(to)g(receiv)n(e)g(an)n(y)g (output)h(data.)p eop %%Page: 11 11 11 10 bop 83 100 1191 4 v 1356 100 a Fk(A2)27 b Fe(:)37 b Fg(DRAFT)110 b Fe(Decem)n(b)r(er)28 b(16,)f(1998)p 2629 100 V 1191 w Fl(11)307 390 y Fh(\017)41 b Fl(The)28 b Fk(type)e Fl(parameter)g(denotes)h(the)h(t)n(yp)r(e)g(of)g(en)n (tries)f(|)g Fk(SPOOLES)p 2574 390 27 4 v 29 w(REAL)f Fl(or)g Fk(SPOOLES)p 3214 390 V 29 w(COMPLEX)307 523 y Fh(\017)41 b Fl(The)28 b Fk(nrow)e Fl(parameter)g(is)h(the)h(n)n(um)n (b)r(er)g(of)f(ro)n(ws.)307 656 y Fh(\017)41 b Fl(The)28 b Fk(ncol)e Fl(parameter)g(is)h(the)h(n)n(um)n(b)r(er)g(of)f(ro)n(ws.) 307 789 y Fh(\017)41 b Fl(The)28 b Fk(inc1)e Fl(parameter)g(is)h(the)h (ro)n(w)f(incremen)n(t.)307 922 y Fh(\017)41 b Fl(The)28 b Fk(inc2)e Fl(parameter)g(is)h(the)h(column)g(incremen)n(t.)307 1054 y Fh(\017)41 b Fl(The)28 b Fk(seed)e Fl(parameter)g(is)h(a)h (random)e(n)n(um)n(b)r(er)i(seed.)p eop %%Page: 12 12 12 11 bop 0 866 a Fm(Index)0 1281 y Fk(A2)p 93 1281 27 4 v 31 w(clearData\(\))p Fl(,)23 b(2)0 1381 y Fk(A2)p 93 1381 V 31 w(column\(\))p Fl(,)h(3)0 1482 y Fk(A2)p 93 1482 V 31 w(columnMajor\(\))p Fl(,)e(6)0 1583 y Fk(A2)p 93 1583 V 31 w(complexEntry\(\))p Fl(,)f(3)0 1683 y Fk(A2)p 93 1683 V 31 w(copy\(\))p Fl(,)k(8)0 1784 y Fk(A2)p 93 1784 V 31 w(copyEntriesToVe)o(cto)o(r\()o(\))p Fl(,)d(9)0 1885 y Fk(A2)p 93 1885 V 31 w(entries\(\))p Fl(,)i(2)0 1985 y Fk(A2)p 93 1985 V 31 w(extractColumn\(\))o Fl(,)e(7)0 2086 y Fk(A2)p 93 2086 V 31 w(extractColumnDV)o(\(\))p Fl(,)f(7)0 2187 y Fk(A2)p 93 2187 V 31 w(extractColumnZV)o(\(\))p Fl(,)g(7)0 2287 y Fk(A2)p 93 2287 V 31 w(extractRow\(\))p Fl(,)h(7)0 2388 y Fk(A2)p 93 2388 V 31 w(extractRowDV\(\))p Fl(,)f(7)0 2489 y Fk(A2)p 93 2489 V 31 w(extractRowZV\(\))p Fl(,)g(7)0 2589 y Fk(A2)p 93 2589 V 31 w(fillRandomUnifo)o(rm\()o(\))p Fl(,)g(8)0 2690 y Fk(A2)p 93 2690 V 31 w(fillWithIdentit)o(y\(\))o Fl(,)h(8)0 2790 y Fk(A2)p 93 2790 V 31 w(free\(\))p Fl(,)j(2)0 2891 y Fk(A2)p 93 2891 V 31 w(frobNorm\(\))p Fl(,)e(5)0 2992 y Fk(A2)p 93 2992 V 31 w(inc1\(\))p Fl(,)i(2)0 3092 y Fk(A2)p 93 3092 V 31 w(inc2\(\))p Fl(,)g(2)0 3193 y Fk(A2)p 93 3193 V 31 w(infinityNorm\(\))p Fl(,)c(5)0 3294 y Fk(A2)p 93 3294 V 31 w(infinityNormOfC)o(olu)o(mn)o(\(\))o Fl(,)h(5)0 3394 y Fk(A2)p 93 3394 V 31 w(infinityNormOfR)o(ow\()o(\))p Fl(,)f(5)0 3495 y Fk(A2)p 93 3495 V 31 w(init\(\))p Fl(,)k(4)0 3596 y Fk(A2)p 93 3596 V 31 w(makeStaircase\(\))o Fl(,)d(4)0 3696 y Fk(A2)p 93 3696 V 31 w(maxabs\(\))p Fl(,)i(5)0 3797 y Fk(A2)p 93 3797 V 31 w(ncol\(\))p Fl(,)h(2)0 3898 y Fk(A2)p 93 3898 V 31 w(new\(\))p Fl(,)g(2)0 3998 y Fk(A2)p 93 3998 V 31 w(nrow\(\))p Fl(,)g(2)0 4099 y Fk(A2)p 93 4099 V 31 w(oneNorm\(\))p Fl(,)f(5)0 4199 y Fk(A2)p 93 4199 V 31 w(oneNormOfColumn)o(\(\))p Fl(,)d(5)0 4300 y Fk(A2)p 93 4300 V 31 w(oneNormOfRow\(\))p Fl(,)g(5)0 4401 y Fk(A2)p 93 4401 V 31 w(permuteColumns\()o(\))p Fl(,)h(6)0 4501 y Fk(A2)p 93 4501 V 31 w(permuteRows\(\))p Fl(,)g(6)0 4602 y Fk(A2)p 93 4602 V 31 w(pointerToComple)o(xEn)o(tr)o (y\()o(\))p Fl(,)g(3)0 4703 y Fk(A2)p 93 4703 V 31 w(pointerToRealEn)o (try)o(\(\))o Fl(,)g(3)0 4803 y Fk(A2)p 93 4803 V 31 w(QRreduce2\(\))p Fl(,)h(4)0 4904 y Fk(A2)p 93 4904 V 31 w(readFromBinaryF)o(ile)o(\(\))o Fl(,)f(9)0 5005 y Fk(A2)p 93 5005 V 31 w(readFromFile\(\))p Fl(,)f(9)0 5105 y Fk(A2)p 93 5105 V 31 w(readFromFormatt)o(edF)o(il)o(e\()o(\))p Fl(,)h(9)0 5206 y Fk(A2)p 93 5206 V 31 w(realEntry\(\))p Fl(,)h(3)0 5307 y Fk(A2)p 93 5307 V 31 w(row\(\))p Fl(,)i(3)0 5407 y Fk(A2)p 93 5407 V 31 w(rowMajor\(\))p Fl(,)e(6)2095 1281 y Fk(A2)p 2188 1281 V 31 w(setColumn\(\))p Fl(,)g(8)2095 1380 y Fk(A2)p 2188 1380 V 31 w(setColumnDV\(\))p Fl(,)f(8)2095 1480 y Fk(A2)p 2188 1480 V 31 w(setColumnZV\(\))p Fl(,)g(8)2095 1580 y Fk(A2)p 2188 1580 V 31 w(setComplexEntry\()o(\))p Fl(,)g(3)2095 1679 y Fk(A2)p 2188 1679 V 31 w(setDefaultFields)o(\(\))o Fl(,)g(2)2095 1779 y Fk(A2)p 2188 1779 V 31 w(setRealEntry\(\))p Fl(,)g(3)2095 1879 y Fk(A2)p 2188 1879 V 31 w(setRow\(\))p Fl(,)i(7)2095 1978 y Fk(A2)p 2188 1978 V 31 w(setRowDV\(\))p Fl(,)f(7)2095 2078 y Fk(A2)p 2188 2078 V 31 w(setRowZV\(\))p Fl(,)g(7)2095 2177 y Fk(A2)p 2188 2177 V 31 w(shiftBase\(\))p Fl(,)g(6)2095 2277 y Fk(A2)p 2188 2277 V 31 w(sizeOf\(\))p Fl(,)h(6)2095 2377 y Fk(A2)p 2188 2377 V 31 w(sortColumnsUp\(\))p Fl(,)d(6)2095 2476 y Fk(A2)p 2188 2476 V 31 w(sortRowsUp\(\))p Fl(,)i(6)2095 2576 y Fk(A2)p 2188 2576 V 31 w(sub\(\))p Fl(,)j(8)2095 2676 y Fk(A2)p 2188 2676 V 31 w(subA2\(\))p Fl(,)f(4)2095 2775 y Fk(A2)p 2188 2775 V 31 w(swapColumns\(\))p Fl(,)d(9)2095 2875 y Fk(A2)p 2188 2875 V 31 w(swapRows\(\))p Fl(,)h(8)2095 2974 y Fk(A2)p 2188 2974 V 31 w(transpose\(\))p Fl(,)g(7)2095 3074 y Fk(A2)p 2188 3074 V 31 w(twoNormOfColumn\()o(\))p Fl(,)f(5)2095 3174 y Fk(A2)p 2188 3174 V 31 w(twoNormOfRow\(\))p Fl(,)g(5)2095 3273 y Fk(A2)p 2188 3273 V 31 w(writeForHumanEye)o(\(\))o Fl(,)g(10)2095 3373 y Fk(A2)p 2188 3373 V 31 w(writeForMatlab\(\))o Fl(,)g(10)2095 3473 y Fk(A2)p 2188 3473 V 31 w(writeStats\(\))p Fl(,)h(10)2095 3572 y Fk(A2)p 2188 3572 V 31 w(writeToBinaryFil)o(e\()o (\))p Fl(,)f(10)2095 3672 y Fk(A2)p 2188 3672 V 31 w(writeToFile\(\))p Fl(,)g(9)2095 3772 y Fk(A2)p 2188 3772 V 31 w(writeToFormatted)o(Fi)o (le\()o(\))p Fl(,)f(9)2095 3871 y Fk(A2)p 2188 3871 V 31 w(zero\(\))p Fl(,)k(8)1908 5656 y(12)p eop %%Trailer end userdict /end-hook known{end-hook}if %%EOF er)e(and)i (statistics.)208 1284 y Fg(Err)l(or)i(che)l(cking:)38 b Fl(If)28 b Fk(mtx)f Fl(or)g Fk(fp)f Fl(are)h Fk(NULL)p Fl(,)f(an)h(error)f(message)g(is)i(prin)n(ted)f(and)h(zero)e(is)i (returned.)101 1449 y(8.)42 b Fk(void)f(A2_writeStats)e(\()k(A2)g (*mtx,)e(FILE)h(*fp)g(\))i(;)208 1581 y Fl(This)27 b(metho)r(d)h (writes)f(a)h(header)e(BKL.h010064400020550007177000000000700653410640300126500ustar00clevecompmath00000400000006#ifndef _BKL_ #define _BKL_ #include "BKL/BKL.h" #endif BKL/BKL.h010064400020550007177000000212600653410612500132650ustar00clevecompmath00000400000006/* BKL.h */ #include "../BPG.h" #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- the BKL object handles the block kernihan-lin family of algorithms defined on bipartite graphs. bpg -- bipartite graph to work with, not free'd when BKL object is free'd ndom -- number of domains nseg -- number of segments nreg -- number of regions, nreg = ndom + nseg totweight -- total weight of the bipartite graph npass -- # of passes made npatch -- # of patches evaluated nflips -- # of domain flips that were executed nimprove -- # of improvement steps ngaineval -- # of gain evaluations colors -- map from regions to colors, size nreg cweights -- array to store color weights, cweights[0] -- separator weight cweights[1] -- black component weight cweights[2] -- white component weight regwghts -- vector of region weights. if the Graph g has vertex weights then regwght points to its vertex weights and is not free'd when the BKL object is free'd else regwghts is allocated and set to unit weights and free'd when the BKL object is free'd endif alpha -- cost function parameter cost = |S|(1 + alpha*max(|B|,|W|)/min(|B|,|W|)) created -- 95oct07, cca modified -- 95dec07, cca directory cleaned up, added some efficiency, inserted exhaustive search into fidmat procedure. ------------------------------------------------------------------- */ typedef struct _BKL BKL ; struct _BKL { BPG *bpg ; int ndom ; int nseg ; int nreg ; int totweight ; int npass ; int npatch ; int nflips ; int nimprove ; int ngaineval ; int *colors ; int cweights[3] ; int *regwghts ; float alpha ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor created -- 95oct07, cca ----------------------- */ BKL * BKL_new ( void ) ; /* ----------------------- set the default fields created -- 95oct07, cca ----------------------- */ void BKL_setDefaultFields ( BKL *bkl ) ; /* ----------------------- clear the data fields created -- 95oct07, cca ----------------------- */ void BKL_clearData ( BKL *bkl ) ; /* ----------------------- destructor created -- 95oct07, cca ----------------------- */ void BKL_free ( BKL *bkl ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------- initialize the object created -- 95oct07, cca ----------------------- */ void BKL_init ( BKL *bkl, BPG *bpg, float alpha ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------ set the colors of the domains and segments by coloring the domains black or white randomly. created -- 95oct07, cca ------------------------------------------------ */ void BKL_setRandomColors ( BKL *bkl, int seed ) ; /* ----------------------------------------- set the component weights. note, we assume the domain colors are set created -- 95oct07, cca ----------------------------------------- */ void BKL_setColorWeights ( BKL *bkl ) ; /* --------------------------------------- return the segment color, a function of the colors of its neighboring domains. created -- 95oct07, cca --------------------------------------- */ int BKL_segColor ( BKL *bkl, int iseg ) ; /* ----------------------- flip the domain created -- 95oct07, cca ----------------------- */ void BKL_flipDomain ( BKL *bkl, int idom ) ; /* ------------------------------ return the next domain to flip in a grey code sequence created -- 95oct07, cca ------------------------------ */ int BKL_greyCodeDomain ( BKL *bkl, int count ) ; /* ---------------------------------------------------------------- set the initial partition. flag -- specifies initial partition type flag == 1 --> random coloring of domains flag == 2 --> one black domain, (seed % ndom), rest are white flag == 3 --> one black pseudoperipheral domain, found using domain (seed % ndom) as root, rest are white flag == 4 --> roughly half-half split, breadth first search of domains, (seed % ndom) as root flag == 5 --> roughly half-half split, breadth first search of domains, (seed % ndom) as root to find a pseudoperipheral domain as root flag == 6 --> use domcolors[] to seed the colors[] array seed -- random number seed, for flag == 1, if seed > 0 then we call srand48(seed) to set the random number generator. domcolors -- vector of domain colors, used when flag == 6 created -- 95oct11, cca ---------------------------------------------------------------- */ float BKL_setInitPart ( BKL *bkl, int flag, int seed, int domcolors[] ) ; /* --------------------------------------------------- return 1 if the domain is adjacent to the separator created -- 95oct11, cca --------------------------------------------------- */ int BKL_domAdjToSep ( BKL *bkl, int dom ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in exhSearch.c ------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------------- perform an exhaustive search over a subspace of domains mdom -- number of domains in the subspace domids -- vector of domain ids, size mdom tcolors -- temporary vector to hold active domain colors, size mdom note : region colors and component weights of the best partition are left in bkl->colors[] and bkl->cweights[]. return value -- cost of best partition created -- 95oct07, cca -------------------------------------------------------------------- */ float BKL_exhSearch ( BKL *bkl, int mdom, int domids[], int tcolors[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in evalfcn.c --------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- evaluate the partition created -- 95oct07, cca ----------------------- */ float BKL_evalfcn ( BKL *bkl ) ; /* ----------------------- evaluate the partition created -- 95oct07, cca ----------------------- */ float BKL_eval ( BKL *bkl, int Sweight, int Bweight, int Wweight ) ; /* --------------------------------------------------------- evaluate the (deltaS, deltaB and deltaW) of a domain flip created -- 950ct11, cca --------------------------------------------------------- */ void BKL_evalgain ( BKL *bkl, int dom, int *pdeltaS, int *pdeltaB, int *pdeltaW ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in fidmat.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------ improve the partition using the FidMat algorithm created -- 95oct11, cca ------------------------------------------------ */ float BKL_fidmat ( BKL *bkl ) ; /*--------------------------------------------------------------------*/ BKL/makefile010064400020550007177000000001410663622354000142030ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean BKL/src/makefile010064400020550007177000000007170663602103500147760ustar00clevecompmath00000400000006include ../../Make.inc OBJ = BKL $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(evalfcn.o) \ $(OBJ).a(exhSearch.o) \ $(OBJ).a(fidmat.o) \ $(OBJ).a(init.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo lib $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG BKL/src/makeGlobalLib010064400020550007177000000006430660026074300157060ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = BKL SRC = basics.c \ evalfcn.c \ exhSearch.c \ fidmat.c \ init.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a BKL/src/basics.c010064400020550007177000000043040654221271200147020ustar00clevecompmath00000400000006/* basics.c */ #include "../BKL.h" /*--------------------------------------------------------------------*/ /* ----------------------- constructor created -- 95oct07, cca ----------------------- */ BKL * BKL_new ( void ) { BKL *bkl ; ALLOCATE(bkl, struct _BKL, 1) ; BKL_setDefaultFields(bkl) ; return(bkl) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 95oct07, cca ----------------------- */ void BKL_setDefaultFields ( BKL *bkl ) { if ( bkl == NULL ) { fprintf(stderr, "\n fatal error in BKL_setDefaultFields(%p)" "\n bad input\n", bkl) ; exit(-1) ; } bkl->bpg = NULL ; bkl->ndom = 0 ; bkl->nseg = 0 ; bkl->nreg = 0 ; bkl->totweight = 0 ; bkl->npass = 0 ; bkl->npatch = 0 ; bkl->nflips = 0 ; bkl->nimprove = 0 ; bkl->ngaineval = 0 ; bkl->colors = NULL ; bkl->alpha = 0.0 ; bkl->cweights[0] = bkl->cweights[1] = bkl->cweights[2] = 0 ; bkl->regwghts = NULL ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ clear the data fields created -- 95oct07, cca modified -- 95dec07, cca memory leak (bkl->regwghts) fixed ------------------------------------ */ void BKL_clearData ( BKL *bkl ) { if ( bkl == NULL ) { fprintf(stderr, "\n fatal error in BKL_clearData(%p)" "\n bad input\n", bkl) ; exit(-1) ; } if ( bkl->colors != NULL ) { IVfree(bkl->colors) ; } if ( bkl->bpg != NULL && bkl->bpg->graph != NULL && bkl->bpg->graph->vwghts == NULL && bkl->regwghts != NULL ) { IVfree(bkl->regwghts) ; } BKL_setDefaultFields(bkl) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- destructor created -- 95oct07, cca ----------------------- */ void BKL_free ( BKL *bkl ) { if ( bkl == NULL ) { fprintf(stderr, "\n fatal error in BKL_free(%p)" "\n bad input\n", bkl) ; exit(-1) ; } BKL_clearData(bkl) ; FREE(bkl) ; return ; } /*--------------------------------------------------------------------*/ BKL/src/evalfcn.c010064400020550007177000000104650653410612400150610ustar00clevecompmath00000400000006/* evalfcn.c */ #include "../BKL.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- evaluate the partition created -- 95oct07, cca ----------------------- */ float BKL_evalfcn ( BKL *bkl ) { float cost ; int wmax, wmin ; /* --------------- check the input --------------- */ if ( bkl == NULL ) { fprintf(stderr, "\n fatal error in BKL_evalfcn(%p)" "\n bad input\n", bkl) ; exit(-1) ; } if ( bkl->cweights[1] <= bkl->cweights[2] ) { wmin = bkl->cweights[1] ; wmax = bkl->cweights[2] ; } else { wmin = bkl->cweights[2] ; wmax = bkl->cweights[1] ; } if ( wmin == 0 ) { cost = ((float) bkl->totweight) * bkl->totweight ; } else { cost = bkl->cweights[0] * (1. + (bkl->alpha * wmax)/wmin) ; } return(cost) ; } /*--------------------------------------------------------------------*/ /* ----------------------- evaluate the partition created -- 95oct07, cca ----------------------- */ float BKL_eval ( BKL *bkl, int Sweight, int Bweight, int Wweight ) { float cost ; int wmax, wmin ; /* --------------- check the input --------------- */ if ( bkl == NULL ) { fprintf(stderr, "\n fatal error in BKL_evalfcn(%p)" "\n bad input\n", bkl) ; exit(-1) ; } if ( Bweight <= Wweight ) { wmin = Bweight ; wmax = Wweight ; } else { wmin = Wweight ; wmax = Bweight ; } if ( wmin == 0 ) { cost = ((float) bkl->totweight) * bkl->totweight ; } else { cost = Sweight * (1. + (bkl->alpha * wmax)/wmin) ; } return(cost) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- evaluate the (deltaS, deltaB and deltaW) of a domain flip created -- 950ct11, cca --------------------------------------------------------- */ void BKL_evalgain ( BKL *bkl, int dom, int *pdeltaS, int *pdeltaB, int *pdeltaW ) { int ii, newc, oldc, seg, size ; int *adj, *colors, *regwghts ; int stats[3] ; /* --------------- check the input --------------- */ if ( bkl == NULL || dom < 0 || dom >= bkl->ndom || pdeltaS == NULL || pdeltaB == NULL || pdeltaW == NULL ) { fprintf(stderr, "\n fatal error in BKL_evalGain(%p,%d,%p,%p,%p)" "\n bad input\n", bkl, dom, pdeltaS, pdeltaB, pdeltaW) ; exit(-1) ; } colors = bkl->colors ; regwghts = bkl->regwghts ; stats[0] = stats[1] = stats[2] = 0 ; /* --------------- flip the domain --------------- */ if ( colors[dom] == 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n domain %d, old color = 1, new color = 2", dom) ; fflush(stdout) ; #endif stats[1] -= regwghts[dom] ; stats[2] += regwghts[dom] ; colors[dom] = 2 ; } else { #if MYDEBUG > 0 fprintf(stdout, "\n domain %d, old color = 2, new color = 1", dom) ; fflush(stdout) ; #endif stats[2] -= regwghts[dom] ; stats[1] += regwghts[dom] ; colors[dom] = 1 ; } /* ------------------------------- loop over the adjacent segments ------------------------------- */ Graph_adjAndSize(bkl->bpg->graph, dom, &size, &adj) ; for ( ii = 0 ; ii < size ; ii++ ) { seg = adj[ii] ; oldc = colors[seg] ; newc = BKL_segColor(bkl, seg) ; #if MYDEBUG > 0 fprintf(stdout, "\n segment %d, weight = %d, old color = %d, new color = %d", seg, regwghts[seg], oldc, newc) ; fflush(stdout) ; #endif if ( oldc != newc ) { stats[oldc] -= regwghts[seg] ; stats[newc] += regwghts[seg] ; #if MYDEBUG > 0 fprintf(stdout, "\n stats = < %d %d %d >", stats[0], stats[1], stats[2]) ; fflush(stdout) ; #endif } } #if MYDEBUG > 0 fprintf(stdout, "\n stats = < %d %d %d > ", stats[0], stats[1], stats[2]) ; fflush(stdout) ; #endif /* ------------------------ set the output variables ------------------------ */ *pdeltaS = stats[0] ; *pdeltaB = stats[1] ; *pdeltaW = stats[2] ; /* -------------------- flip the domain back -------------------- */ if ( colors[dom] == 1 ) { colors[dom] = 2 ; } else { colors[dom] = 1 ; } /* --------------------------------- increment the number of gainevals --------------------------------- */ bkl->ngaineval++ ; return ; } /*--------------------------------------------------------------------*/ BKL/src/exhSearch.c010064400020550007177000000077720653410612400153640ustar00clevecompmath00000400000006/* exhSearch.c */ #include "../BKL.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- perform an exhaustive search over a subspace of domains mdom -- number of domains in the subspace domids -- vector of domain ids, size mdom tcolors -- temporary vector to hold active domain colors, size mdom note : region colors and component weights of the best partition are left in bkl->colors[] and bkl->cweights[]. return value -- cost of best partition created -- 95oct07, cca -------------------------------------------------------------------- */ float BKL_exhSearch ( BKL *bkl, int mdom, int domids[], int tcolors[] ) { float bestcost, newcost ; int idom, ierr, iflip, iloc, jloc, nflip ; int *colors ; /* --------------- check the input --------------- */ if ( bkl == NULL || mdom < 1 || domids == NULL || tcolors == NULL ) { fprintf(stderr, "\n fatal error in BKL_exhaustiveSearch(%p,%d,%p,%p)" "\n bad input\n", bkl, mdom, domids, tcolors) ; exit(-1) ; } colors = bkl->colors ; bkl->nflips = 0 ; #if MYDEBUG > 0 fprintf(stdout, "\n inside BKL_exhSearch(%p,%d,%p,%p)", bkl, mdom, domids, tcolors) ; fprintf(stdout, "\n bkl->nflips = %d", bkl->nflips) ; fflush(stdout) ; #endif /* --------------------------------------------- copy the present colors and component weights --------------------------------------------- */ for ( iloc = 0 ; iloc < mdom ; iloc++ ) { idom = domids[iloc] ; tcolors[iloc] = colors[idom] ; } /* --------------------- compute the best cost --------------------- */ bestcost = BKL_evalfcn(bkl) ; #if MYDEBUG > 0 fprintf(stdout, "\n inside BKL_exhSearch(%p,%d,%p,%p)", bkl, mdom, domids, tcolors) ; fprintf(stdout, "\n %d domain ids : ", mdom) ; IVfp80(stdout, mdom, domids, 20, &ierr) ; fprintf(stdout, "\n color weights < %6d %6d %6d >, cost %9.2f", bkl->cweights[0], bkl->cweights[1], bkl->cweights[2], bestcost) ; fflush(stdout) ; #endif #if MYDEBUG > 2 fprintf(stdout, "\n colors ") ; IVfp80(stdout, bkl->nreg, colors, 80, &ierr) ; fflush(stdout) ; #endif /* --------------------------------- count the number of flips to make --------------------------------- */ for ( idom = 0, nflip = 1 ; idom < mdom ; idom++ ) { nflip *= 2 ; } /* -------------------------- loop over the 2^mdom flips -------------------------- */ for ( iflip = 1 ; iflip < nflip ; iflip++ ) { iloc = BKL_greyCodeDomain(bkl, iflip) ; idom = domids[iloc] ; #if MYDEBUG > 1 fprintf(stdout, "\n FLIP %4d domain %4d", bkl->nflips, idom) ; fflush(stdout) ; #endif #if MYDEBUG > 2 fprintf(stdout, "\n colors before flip") ; IVfp80(stdout, bkl->nreg, colors, 80, &ierr) ; fflush(stdout) ; #endif BKL_flipDomain(bkl, idom) ; #if MYDEBUG > 2 fprintf(stdout, "\n colors after flip") ; IVfp80(stdout, bkl->nreg, colors, 80, &ierr) ; fprintf(stdout, "\n cweights : < %9d %9d %9d > ", bkl->cweights[0], bkl->cweights[1], bkl->cweights[2]) ; fflush(stdout) ; #endif newcost = BKL_evalfcn(bkl) ; #if MYDEBUG > 1 fprintf(stdout, ", < %6d %6d %6d >, cost %9.2f", bkl->cweights[0], bkl->cweights[1], bkl->cweights[2], newcost) ; fflush(stdout) ; #endif if ( newcost < bestcost ) { #if MYDEBUG > 1 fprintf(stdout, ", better") ; fflush(stdout) ; #endif bkl->nimprove++ ; for ( jloc = 0 ; jloc < mdom ; jloc++ ) { tcolors[jloc] = colors[domids[jloc]] ; } bestcost = newcost ; } } /* ----------------------------------------------------- restore the best colors and update the segment colors ----------------------------------------------------- */ for ( iloc = 0 ; iloc < mdom ; iloc++ ) { idom = domids[iloc] ; if ( colors[idom] != tcolors[iloc] ) { BKL_flipDomain(bkl, idom) ; } } return(bestcost) ; } /*--------------------------------------------------------------------*/ ------BKL/src/fidmat.c010064400020550007177000000235030661641632000147070ustar00clevecompmath00000400000006/* fidmat.c */ #include "../BKL.h" #define MYDEBUG 0 #define MAXNDOM_FOR_EXHAUSTIVE_SEARCH 8 /*--------------------------------------------------------------------*/ /* --------------------------- structure used in this file --------------------------- */ typedef struct _cell Cell ; struct _cell { int domid ; int deltaS ; int deltaB ; int deltaW ; Cell *prev ; Cell *next ; } ; static Cell Head, *head = &Head ; static Cell Undo, *undo = &Undo ; static float BKL_fidmatPass ( BKL *bkl, Cell cells[], int tags[], Graph *DomByDom, int npass ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- improve the partition using the FidMat algorithm created -- 95oct11, cca modified -- 95dec07, cca memory leak fixed, comments added, DomByDom inserted ------------------------------------------------------- */ float BKL_fidmat ( BKL *bkl ) { float cost ; int ndom ; /* --------------- check the input --------------- */ if ( bkl == NULL ) { fprintf(stderr, "\n fatal error in BKL_fidmat(%p)" "\n bad input\n", bkl) ; exit(-1) ; } ndom = bkl->ndom ; /* --------------------------------------------- if ndom <= MAXNDOM_FOR_EXHAUSTIVE_SEARCH then do exhaustive search else do fidmat sweeps endif --------------------------------------------- */ if ( ndom <= MAXNDOM_FOR_EXHAUSTIVE_SEARCH ) { int mdom, *domids, *tcolors ; /* -------------------- do exhaustive search -------------------- */ mdom = ndom - 1 ; domids = IVinit(mdom, -1) ; tcolors = IVinit(mdom, -1) ; IVramp(mdom, domids, 1, 1) ; BKL_exhSearch(bkl, mdom, domids, tcolors) ; IVfree(domids) ; IVfree(tcolors) ; cost = BKL_evalfcn(bkl) ; } else { Cell *cell, *cells ; float bestcost ; Graph *DomByDom ; int idom ; int *tags ; /* --------------------------------------------------- initialize the cell objects and the working vectors --------------------------------------------------- */ ALLOCATE(cells, struct _cell, ndom) ; tags = IVinit(ndom, -1) ; for ( idom = 0, cell = cells ; idom < ndom ; idom++, cell++ ) { cell->domid = idom ; cell->deltaS = cell->deltaB = cell->deltaW = 0 ; cell->prev = cell->next = cell ; } /* ------------------------------------- create the domain-domain Graph object ------------------------------------- */ DomByDom = BPG_makeGraphXbyX(bkl->bpg) ; #if MYDEBUG > 1 fprintf(stdout, "\n\n domain-domain Graph object") ; Graph_writeForHumanEye(DomByDom, stdout) ; fflush(stdout) ; #endif /* -------------------------- make the first fidmat pass -------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n\n pass %d, cost %.2f, < %d %d %d >", bkl->npass, BKL_evalfcn(bkl), bkl->cweights[0], bkl->cweights[1], bkl->cweights[2]) ; fflush(stdout) ; #endif bkl->npass = 1 ; bestcost = BKL_fidmatPass(bkl, cells, tags, DomByDom, bkl->npass) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n pass %d, cost %.2f, < %d %d %d >", bkl->npass, bestcost, bkl->cweights[0], bkl->cweights[1], bkl->cweights[2]) ; fflush(stdout) ; #endif /* --------------------------------------------------- make additional passes while the partition improves --------------------------------------------------- */ while ( 1 ) { bkl->npass++ ; cost = BKL_fidmatPass(bkl, cells, tags, DomByDom, bkl->npass) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n pass %d, cost %.2f, < %d %d %d >", bkl->npass, cost, bkl->cweights[0], bkl->cweights[1], bkl->cweights[2]) ; fflush(stdout) ; #endif if ( cost < bestcost ) { bestcost = cost ; } else { break ; } } /* ------------------------ free the working storage ------------------------ */ FREE(cells) ; IVfree(tags) ; Graph_free(DomByDom) ; } return(cost) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- make one pass of the FidMat algorithm created -- 95oct11, cca ------------------------------------- */ static float BKL_fidmatPass ( BKL *bkl, Cell cells[], int tags[], Graph *DomByDom, int npass ) { Cell *cell ; float bestcost, bettercost, cost ; int dom, dom2, ii, ndom, size ; int *cweights, *doms ; /* --------------- check the input --------------- */ if ( bkl == NULL || cells == NULL || tags == NULL || DomByDom == NULL ){ fprintf(stderr, "\n fatal error in BKL_fidmatPass(%p,%p,%p,%p,%d)" "\n bad input\n", bkl, cells, tags, DomByDom, npass) ; exit(-1) ; } ndom = bkl->ndom ; cweights = bkl->cweights ; /* ------------------------------ evaluate the current partition ------------------------------ */ bestcost = BKL_evalfcn(bkl) ; /* ----------------------------------------------------- fill the cells with domains adjacent to the separator ----------------------------------------------------- */ head->next = head->prev = head ; undo->next = undo->prev = undo ; for ( dom = 0 ; dom < ndom ; dom++ ) { cell = &cells[dom] ; cell->domid = dom ; cell->prev = cell->next = cell ; if ( BKL_domAdjToSep(bkl, dom) == 1 ) { /* ---------------------------------------- domain dom is adjacent to the separator evaluate its change and insert into list ---------------------------------------- */ BKL_evalgain(bkl, dom, &cell->deltaS, &cell->deltaB, &cell->deltaW) ; #if MYDEBUG > 1 fprintf(stdout, "\n loading domain %d, <%d %d %d>", dom, cell->deltaS, cell->deltaB, cell->deltaW) ; fflush(stdout) ; #endif DLIST_TAIL_INSERT(head, cell) ; } } /* --------------- loop over moves --------------- */ while ( head->next != head ) { /* ----------------------------------------------- find best move to make w.r.t. the cost function ----------------------------------------------- */ cell = head->next ; dom = cell->domid ; bettercost = BKL_eval(bkl, cweights[0] + cell->deltaS, cweights[1] + cell->deltaB, cweights[2] + cell->deltaW) ; #if MYDEBUG > 1 fprintf(stdout, "\n domain %d, move cost = %.1f", dom, bettercost) ; fflush(stdout) ; #endif for ( cell = cell->next ; cell != head ; cell = cell->next ) { cost = BKL_eval(bkl, cweights[0] + cell->deltaS, cweights[1] + cell->deltaB, cweights[2] + cell->deltaW) ; #if MYDEBUG > 1 fprintf(stdout, "\n domain %d, move cost = %.1f", cell->domid, cost) ; fflush(stdout) ; #endif if ( cost < bettercost ) { #if MYDEBUG > 1 fprintf(stdout, ", better") ; fflush(stdout) ; #endif dom = cell->domid ; bettercost = cost ; } } /* ----------------------------- remove the node from the list ----------------------------- */ cell = &cells[dom] ; DLIST_DELETE(cell) ; /* --------------- flip the domain --------------- */ #if MYDEBUG > 1 fprintf(stdout, "\n flipping domain %d, cweights <%d %d %d>", dom, cweights[0] + cell->deltaS, cweights[1] + cell->deltaB, cweights[2] + cell->deltaW) ; fflush(stdout) ; #endif BKL_flipDomain(bkl, dom) ; cost = BKL_eval(bkl, cweights[0], cweights[1], cweights[2]) ; #if MYDEBUG > 1 fprintf(stdout, ", cost = %.1f", cost) ; fflush(stdout) ; #endif if ( bestcost > cost ) { /* --------------------------------------------- better partition found, set undo list to NULL --------------------------------------------- */ bestcost = cost ; DLIST_DELETE(undo) ; bkl->nimprove++ ; } else { /* ---------------------------------------------- partition is not better, add move to undo list ---------------------------------------------- */ DLIST_HEAD_INSERT(undo, cell) ; } /* -------------------------- loop over adjacent domains -------------------------- */ tags[dom] = npass ; Graph_adjAndSize(DomByDom, dom, &size, &doms) ; for ( ii = 0 ; ii < size ; ii++ ) { dom2 = doms[ii] ; if ( tags[dom2] < npass && BKL_domAdjToSep(bkl, dom2) == 1 ) { /* ------------------------------------ domain dom2 has not yet been flipped and is adjacent to the separator ------------------------------------ */ #if MYDEBUG > 1 fprintf(stdout, "\n domain %d, not yet flipped, adj to separator", dom2) ; fflush(stdout) ; #endif cell = &cells[dom2] ; BKL_evalgain(bkl, dom2, &cell->deltaS, &cell->deltaB, &cell->deltaW) ; #if MYDEBUG > 1 fprintf(stdout, ", gain < %d %d %d >", cell->deltaS, cell->deltaB, cell->deltaW) ; fflush(stdout) ; #endif if ( cell->prev == cell ) { /* --------------------------------------------- domain is not on the list of domains eligible to move, insert on the tail of the list --------------------------------------------- */ DLIST_TAIL_INSERT(head, cell) ; } } } } /* ------------------------------------------------------- undo the flips of domains since the last best partition ------------------------------------------------------- */ while ( (cell = undo->next) != undo ) { #if MYDEBUG > 1 fprintf(stdout, "\n un-flipping domain %d", cell->domid) ; fflush(stdout) ; #endif DLIST_DELETE(cell) ; BKL_flipDomain(bkl, cell->domid) ; } return(bestcost) ; } /*--------------------------------------------------------------------*/ colors) ; cost = BKL_evalfcn(bkl) ; } else { Cell *cell, *cells ; float bestcost ; Graph *DomByDom ; int idom ; int *tags ; /* --------------------------BKL/src/init.c010064400020550007177000000021560653410612400144040ustar00clevecompmath00000400000006/* init.c */ #include "../BKL.h" /*--------------------------------------------------------------------*/ /* ----------------------- initialize the object created -- 95oct07, cca ----------------------- */ void BKL_init ( BKL *bkl, BPG *bpg, float alpha ) { /* --------------- check the input --------------- */ if ( bkl == NULL || bpg == NULL ) { fprintf(stderr, "\n fatal error in BKL_init(%p,%p,%f)" "\n bad input\n", bkl, bpg, alpha) ; exit(-1) ; } /* -------------- clear the data -------------- */ BKL_clearData(bkl) ; /* --------------------- initialize the fields --------------------- */ bkl->bpg = bpg ; bkl->ndom = bpg->nX ; bkl->nseg = bpg->nY ; bkl->nreg = bpg->nX + bpg->nY ; if ( bpg->graph->vwghts == NULL ) { bkl->totweight = bkl->nreg ; bkl->regwghts = IVinit(bkl->nreg, 1) ; } else { bkl->regwghts = bpg->graph->vwghts ; bkl->totweight = IVsum(bkl->nreg, bkl->regwghts) ; } bkl->colors = IVinit(bkl->nreg, 0) ; bkl->alpha = alpha ; return ; } /*--------------------------------------------------------------------*/ BKL/src/util.c010064400020550007177000000315700653410612400144200ustar00clevecompmath00000400000006/* util.c */ #include "../BKL.h" #include "../../Drand.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------ set the colors of the domains and segments by coloring the domains black or white randomly. created -- 95oct07, cca ------------------------------------------------ */ void BKL_setRandomColors ( BKL *bkl, int seed ) { int ireg, ndom, nreg ; int *colors ; Drand drand ; /* --------------- check the input --------------- */ if ( bkl == NULL || bkl->bpg == NULL ) { fprintf(stderr, "\n fatal error in BKL_setRandomColors(%p,%d)" "\n bad input\n", bkl, seed) ; exit(-1) ; } ndom = bkl->ndom ; nreg = bkl->nreg ; colors = bkl->colors ; Drand_setDefaultFields(&drand) ; Drand_init(&drand) ; Drand_setUniform(&drand, 0.0, 1.0) ; if ( seed > 0 ) { /* -------------------------- set the random number seed -------------------------- */ Drand_setSeed(&drand, seed) ; } /* ----------------- color the domains ----------------- */ for ( ireg = 0 ; ireg < ndom ; ireg++ ) { colors[ireg] = (Drand_value(&drand) < 0.5) ? 1 : 2 ; } /* -------------------------------------------- color the segments and set the color weights -------------------------------------------- */ BKL_setColorWeights(bkl) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- set the component weights. note, we assume the domain colors are set created -- 95oct07, cca modified -- 95dec07, cca error checking inserted for colors ----------------------------------------- */ void BKL_setColorWeights ( BKL *bkl ) { int c, ireg ; int *colors ; /* --------------- check the input --------------- */ if ( bkl == NULL ) { fprintf(stderr, "\n fatal error in BKL_setColorsWeights(%p)" "\n bad input\n", bkl) ; exit(-1) ; } colors = bkl->colors ; bkl->cweights[0] = bkl->cweights[1] = bkl->cweights[2] = 0 ; /* --------------------- check out the domains --------------------- */ for ( ireg = 0 ; ireg < bkl->ndom ; ireg++ ) { if ( (c = colors[ireg]) < 1 || 2 < c ) { fprintf(stderr, "\n fatal error in BKL_setColorWeights(%p)" "\n region %d has color %d", bkl, ireg, c) ; exit(-1) ; } bkl->cweights[c] += bkl->regwghts[ireg] ; } /* ------------------ color the segments ------------------ */ for ( ireg = bkl->ndom ; ireg < bkl->nreg ; ireg++ ) { if ( (c = BKL_segColor(bkl, ireg)) < 0 || 2 < c ) { fprintf(stderr, "\n fatal error in BKL_setColorWeights(%p)" "\n region %d has color %d", bkl, ireg, c) ; exit(-1) ; } colors[ireg] = c ; bkl->cweights[c] += bkl->regwghts[ireg] ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- return the segment color, a function of the colors of its neighboring domains. created -- 95oct07, cca --------------------------------------- */ int BKL_segColor ( BKL *bkl, int iseg ) { int color, ii, size ; int *adj, *colors ; /* --------------- check the input --------------- */ if ( bkl == NULL || iseg < bkl->ndom || iseg >= bkl->nreg ) { fprintf(stderr, "\n fatal error in BKL_segColor(%p,%d)" "\n bad input\n", bkl, iseg) ; exit(-1) ; } colors = bkl->colors ; /* ---------------------------------------------------- loop over adjacent domans, break if adjacent to two differently colored domains ---------------------------------------------------- */ Graph_adjAndSize(bkl->bpg->graph, iseg, &size, &adj) ; color = 0 ; if ( size > 0 ) { color = colors[adj[0]] ; for ( ii = 1 ; ii < size ; ii++ ) { if ( color != colors[adj[ii]] ) { color = 0 ; break ; } } } return(color) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- flip the domain created -- 95oct07, cca modified -- 95dec07, cca simple mod to segment loop made ---------------------------------- */ void BKL_flipDomain ( BKL *bkl, int idom ) { int ii, iseg, newcolor, oldcolor, size, wdom, wseg ; int *adj, *colors, *regwghts ; /* --------------- check the input --------------- */ if ( bkl == NULL || idom < 0 || idom >= bkl->ndom ) { fprintf(stderr, "\n fatal error in BKL_flipDomain(%p,%d)" "\n bad input\n", bkl, idom) ; exit(-1) ; } colors = bkl->colors ; regwghts = bkl->regwghts ; switch ( (oldcolor = colors[idom]) ) { case 1 : newcolor = 2 ; break ; case 2 : newcolor = 1 ; break ; default : fprintf(stderr, "\n fatal error in BKL_flipDomain(%p,%d)" "\n colors[%d] = %d\n", bkl, idom, idom, colors[idom]) ; exit(-1) ; } colors[idom] = newcolor ; /* -------------------------------------- adjust color weights for moving domain -------------------------------------- */ wdom = regwghts[idom] ; bkl->cweights[oldcolor] -= wdom ; bkl->cweights[newcolor] += wdom ; /* ------------------------------- loop over the adjacent segments ------------------------------- */ Graph_adjAndSize(bkl->bpg->graph, idom, &size, &adj) ; for ( ii = 0 ; ii < size ; ii++ ) { iseg = adj[ii] ; wseg = regwghts[iseg] ; #if MYDEBUG > 0 fprintf(stdout, "\n checking out segment %d, weight %d", iseg, wseg) ; #endif if ( (oldcolor = colors[iseg]) != (newcolor = BKL_segColor(bkl, iseg)) ) { bkl->cweights[oldcolor] -= wseg ; bkl->cweights[newcolor] += wseg ; colors[iseg] = newcolor ; } } /* ----------------------------- increment the number of flips ----------------------------- */ bkl->nflips++ ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------ return the next domain to flip in a grey code sequence created -- 95oct07, cca modified -- 95dec07, cca error message inserted ------------------------------ */ int BKL_greyCodeDomain ( BKL *bkl, int count ) { int chk, idom, res ; /* --------------- check the input --------------- */ if ( bkl == NULL ) { fprintf(stderr, "\n fatal error in BKL_greyCodeDomain(%p)" "\n bad input\n", bkl) ; exit(-1) ; } for ( idom = 0, res = 1, chk = 2 ; /* no test */ ; idom++, res = chk, chk *= 2 ) { if ( count % chk == res ) { return(idom) ; } } fprintf(stderr, "\n fatal error in BKL_greyCodeDomain(%p,%d)" "\n should never have reached this point\n", bkl, count) ; exit(-1) ; return(-2) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- set the initial partition. flag -- specifies initial partition type flag == 1 --> random coloring of domains flag == 2 --> one black domain, (seed % ndom), rest are white flag == 3 --> one black pseudoperipheral domain, found using domain (seed % ndom) as root, rest are white flag == 4 --> roughly half-half split, breadth first search of domains, (seed % ndom) as root flag == 5 --> roughly half-half split, breadth first search of domains, (seed % ndom) as root to find a pseudoperipheral domain as root flag == 6 --> use domcolors[] to seed the colors[] array seed -- random number seed, for flag == 1, if seed > 0 then we call set the random number generator. domcolors -- vector of domain colors, used when flag == 6 created -- 95oct11, cca modified -- 95nov30, cca switch for one and two domains inserted. ---------------------------------------------------------------- */ float BKL_setInitPart ( BKL *bkl, int flag, int seed, int domcolors[] ) { BPG *bpg ; float cost ; int dom, dom2, dsize, idom, ii, jj, last, ndom, now, root, seg, ssize ; int *colors, *cweights, *dadj, *list, *mark, *sadj ; /* --------------- check the input --------------- */ if ( bkl == NULL || flag < 1 || 6 < flag || (flag == 6 && domcolors == NULL) ) { fprintf(stderr, "\n fatal error in BKL_setInitPart(%p,%d,%d,%p)" "\n bad input\n", bkl, flag, seed, domcolors) ; exit(-1) ; } bpg = bkl->bpg ; ndom = bkl->ndom ; colors = bkl->colors ; cweights = bkl->cweights ; if ( ndom == 1 ) { colors[0] = 1 ; BKL_setColorWeights(bkl) ; } else if ( ndom == 2 ) { colors[0] = 1 ; colors[1] = 2 ; BKL_setColorWeights(bkl) ; } else { /* --------------------- switch over the cases --------------------- */ switch ( flag ) { case 1 : { Drand drand ; /* ------------- random colors ------------- */ Drand_setDefaultFields(&drand) ; Drand_init(&drand) ; Drand_setUniform(&drand, 0.0, 1.0) ; if ( seed > 0 ) { /* -------------------------- set the random number seed -------------------------- */ Drand_setSeed(&drand, seed) ; } for ( idom = 0 ; idom < ndom ; idom++ ) { colors[idom] = (Drand_value(&drand) < 0.5) ? 1 : 2 ; } BKL_setColorWeights(bkl) ; break ; } case 2 : case 3 : /* -------------------------------------------------------- one domain colored black = 1, the rest colored white = 2 domain is specified (flag = 2) or pseudoperipheral (flag = 3) -------------------------------------------------------- */ IVfill(ndom, colors, 2) ; if ( flag == 2 ) { colors[seed % ndom] = 1 ; } else { root = BPG_pseudoperipheralnode(bkl->bpg, seed % ndom) ; colors[root] = 1 ; } BKL_setColorWeights(bkl) ; break ; case 4 : case 5 : /* ---------------------------------------------- split using a random or pseudoperipheral node as a root of a breadth first traversal 1. color all domains white 2. color segments and get color weights 3. fill the list with the seed domain 4. do a breadth first traversal of the domains 5. flip the domain 6. if |B| >= |W| then break 7. add unmarked neighboring domains to list ---------------------------------------------- */ IVfill(ndom, colors, 2) ; BKL_setColorWeights(bkl) ; list = IVinit(ndom, -1) ; mark = IVinit(ndom, -1) ; if ( flag == 4 ) { list[0] = seed % ndom ; } else { list[0] = BPG_pseudoperipheralnode(bkl->bpg, seed % ndom) ; } now = last = 0 ; mark[list[0]] = 1 ; while ( now <= last ) { dom = list[now++] ; BKL_flipDomain(bkl, dom) ; if ( cweights[1] >= cweights[2] ) { break ; } Graph_adjAndSize(bpg->graph, dom, &dsize, &dadj) ; for ( ii = 0 ; ii < dsize ; ii++ ) { seg = dadj[ii] ; Graph_adjAndSize(bpg->graph, seg, &ssize, &sadj) ; for ( jj = 0 ; jj < ssize ; jj++ ) { dom2 = sadj[jj] ; if ( mark[dom2] == -1 ) { if ( last == ndom - 1 ) { fprintf(stderr, "\n fatal error in BKL_setInitPart(%p,%d,%d,%p)" "\n list[] size exceeded\n", bkl, flag, seed, domcolors) ; exit(-1) ; } mark[dom2] = 1 ; list[++last] = dom2 ; } } } } IVfree(list) ; IVfree(mark) ; BKL_setColorWeights(bkl) ; break ; case 6 : /* ------------------ copy domain colors ------------------ */ IVcopy(ndom, colors, domcolors) ; BKL_setColorWeights(bkl) ; break ; } } cost = BKL_evalfcn(bkl) ; return(cost) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- return 1 if the domain is adjacent to the separator created -- 95oct11, cca --------------------------------------------------- */ int BKL_domAdjToSep ( BKL *bkl, int dom ) { int ii, size ; int *adj, *colors ; /* --------------- check the input --------------- */ if ( bkl == NULL || dom < 0 || dom >= bkl->ndom ) { fprintf(stderr, "\n fatal error in BKL_domAdjToSep(%p,%d)" "\n bad input\n", bkl, dom) ; exit(-1) ; } colors = bkl->colors ; Graph_adjAndSize(bkl->bpg->graph, dom, &size, &adj) ; for ( ii = 0 ; ii < size ; ii++ ) { if ( colors[adj[ii]] == 0 ) { /* ------------------------------------- segment is on the separator, return 1 ------------------------------------- */ return(1) ; } } return(0) ; } /*--------------------------------------------------------------------*/ BKL/doc/004275500020550007177000000000000654276733000132675ustar00clevecompmath00000400000006BKL/doc/dataStructure.tex010064400020550007177000000035420653410612500166300ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:BKL:dataStructure} \par The {\tt BKL} object has the following fields. \begin{itemize} \item {\tt BPG *bpg} : pointer to a {\tt BPG} bipartite graph object, not owned by the {\tt BKL} object. \item {\tt int ndom} : number of domains, domain ids are in {\tt [0,ndom)} \item {\tt int nseg} : number of segments, segment ids are in {\tt [ndom,ndom + nseg)} \item {\tt int nreg} : number of regions, equal to {\tt ndom + nseg} \item {\tt int totweight} : total weight of the domains and segments \item {\tt int npass} : number of Fiduccia-Mattheyes passes \item {\tt int npatch} : number of patches evaluated, not used during the Fiduccia-Mattheyes algorithm \item {\tt int nflips} : number of domains that were flipped \item {\tt int nimprove} : number of improvements in the partition \item {\tt int ngaineval} : number of gain evaluations, roughly equivalent to the number of degree evaluations in the minimum degree algorithm \item {\tt int *colors} : pointer to an {\tt int} vector of size {\tt nreg}, {\tt colors[idom]} is {\tt 1} or {\tt 2} for domain {\tt idom}, {\tt colors[iseg]} is {\tt 0}, {\tt 1} or {\tt 2} for segment {\tt iseg}. \item {\tt int *cweights} : pointer to an {\tt int} vector of size 3, {\tt cweights[0]} contains the weight of the separator, {\tt cweights[1]} and {\tt cweights[2]} contains the weights of the two components \item {\tt int *regwghts} : pointer to an {\tt int} vector of size {\tt nreg}, used to store the weights of the domains and segments \item {\tt float alpha} : number used to store the partition evaluation parameter, the cost of the partition is \begin{verbatim} balance = max(cweights[1], cweights[2])/min(cweights[1], cweights[2]) ; cost = cweights[0]*(1. + alpha*balance) ; \end{verbatim} \end{itemize} ts, segment ids are in {\tt [ndom,ndom + nseg)} \item {\tt int nreg} : number of regions, equal to {\tt ndom + nseg} \item {\tt int totweight}BKL/doc/intro.tex010064400020550007177000000007160653410612500151310ustar00clevecompmath00000400000006\chapter{{\tt BKL}: Block Kernighan-Lin Object} \label{chapter:BKL} \par Our {\tt BKL} object is used to find an initial separator of a graph. Its input is a {\tt BPG} bipartite graph object that represents the domain-segment graph of a domain decomposition of the graph. After a call to the {\tt BKL\_fidmat()} method, the object contains a two-color partition of the graph that is accessible via the {\tt colors[]} and {\tt cweights[]} vectors of the object. BKL/doc/main.tex010064400020550007177000000011200665065616100147210ustar00clevecompmath00000400000006% % main TeX file % % \documentstyle[leqno,11pt,twoside]{report} \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt BKL} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt BKL} : {\it DRAFT} \quad \today \hrulefill} \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} BKL/doc/proto.tex010064400020550007177000000322300653410612500151350ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt BKL} methods} \label{section:BKL:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt BKL} object. \par \section{Basic methods} \label{subsection:BKL:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} BKL * BKL_new ( void ) ; \end{verbatim} \index{BKL_new@{\tt BKL\_new()}} This method simply allocates storage for the {\tt BKL} structure and then sets the default fields by a call to {\tt BKL\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void BKL_setDefaultFields ( BKL *bkl ) ; \end{verbatim} \index{BKL_setDefaultFields@{\tt BKL\_setDefaultFields()}} This method sets the fields of the structure to their default values: {\tt bpg}, {\tt colors} and {\tt regwghts} are set to {\tt NULL}, the {\tt int} parameters are set to zero, and the {\tt cweights} vector is filled with zeros. \par \noindent {\it Error checking:} If {\tt bkl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void BKL_clearData ( BKL *bkl ) ; \end{verbatim} \index{BKL_clearData@{\tt BKL\_clearData()}} This method clears any data allocated by the object, namely the {\tt colors} and {\tt regwghts} vectors. It then fills the structure's fields with default values with a call to {\tt BKL\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt bkl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void BKL_free ( BKL *bkl ) ; \end{verbatim} \index{BKL_free@{\tt BKL\_free()}} This method releases any storage by a call to {\tt BKL\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt bkl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:BKL:proto:initializers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void BKL_init ( BKL *bkl, BPG *bpg, float alpha ) ; \end{verbatim} \index{BKL_init@{\tt BKL\_init()}} This method initializes the {\tt BKL} object given a bipartite graph object and cost function parameter as input. Any previous data is cleared with a call to {\tt BKL\_clearData()}. The {\tt ndom}, {\tt nseg} and {\tt nreg} scalars are set, the {\tt regwghts[]} vector allocated and filled, and the {\tt colors[]} vector allocated and filled with zeros. \par \noindent {\it Error checking:} If {\tt bkl} or {\tt bpg} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:BKL:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void BKL_setRandomColors ( BKL *bkl, int seed ) ; \end{verbatim} \index{BKL_setRandomColors@{\tt BKL\_setRandomColors()}} If {\tt seed > 0} a random number generator is set using {\tt seed}. The domains are then colored {\tt 1} or {\tt 2} randomly and {\tt BKL\_setColorWeights()} is called to set the segment weights. \par \noindent {\it Error checking:} If {\tt bkl} or {\tt bkl->bpg} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void BKL_setColorWeights ( BKL *bkl ) ; \end{verbatim} \index{BKL_setColorWeights@{\tt BKL\_setColorWeights()}} This method sets the color weights for the region. It assumes that all domains are colored {\tt 1} or {\tt 2}. The segments are then colored. If a segment is adjacent only to domains of one color, its color is that color, otherwise its color is {\tt 0}. \par \noindent {\it Error checking:} If {\tt bkl} or {\tt bkl->bpg} is {\tt NULL}, an error message is printed and the program exits. The colors of the domains are checked to ensure they are {\tt 1} or {\tt 2}. %----------------------------------------------------------------------- \item \begin{verbatim} int BKL_segColor ( BKL *bkl, int iseg ) ; \end{verbatim} \index{BKL_segColor@{\tt BKL\_segColor()}} This method returns the color of segment {\tt iseg}. \par \noindent {\it Error checking:} If {\tt bkl} is {\tt NULL}, or if {\tt iseg} is not in {\tt [bkl->ndom, bkl->nreg)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void BKL_flipDomain ( BKL *bkl, int idom ) ; \end{verbatim} \index{BKL_flipDomain@{\tt BKL\_flipDomain()}} This method flips the color of domain {\tt idom}, adjusts the colors of neighboring segments and the {\tt cweights[]} vector. \par \noindent {\it Error checking:} If {\tt bkl} is {\tt NULL}, or if {\tt idom} is not in {\tt [0,bkl->ndom)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int BKL_greyCodeDomain ( BKL *bkl, int count ) ; \end{verbatim} \index{BKL_greyCodeDomain@{\tt BKL\_greyCodeDomain()}} This method returns the next domain id in a grey code sequence, used to exhaustively search of a subspace of partitions defined by set of candidate domains to flip. The value {\tt count} ranges from {\tt 1} to $2^{\mbox{\tt ndom}}$. \par \noindent {\it Error checking:} If {\tt bkl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} float BKL_setInitPart ( BKL *bkl, int flag, int seed, int domcolors[] ) ; \end{verbatim} \index{BKL_setInitPart@{\tt BKL\_setInitPart()}} This method sets the initial partition by coloring the domains and segments. The {\tt flag} parameter has the following values. \begin{itemize} \item {\tt flag = 1} $\longrightarrow$ random coloring of the domains \item {\tt flag = 2} $\longrightarrow$ one black domain, ({\tt seed} \% {\tt ndom}), rest are white \item {\tt flag = 3} $\longrightarrow$ one black pseudoperipheral domain, found using domain ({\tt seed} \% {\tt ndom}) as root, rest are white \item {\tt flag = 4} $\longrightarrow$ roughly half-half split, breadth first search of domains, ({\tt seed} \% {\tt ndom}) as root \item {\tt flag = 5} $\longrightarrow$ roughly half-half split, breadth first search of domains, ({\tt seed} \% {\tt ndom}) as root to find a pseudoperipheral domain as root \item {\tt flag = 6} $\longrightarrow$ use {\tt domcolors[]} to seed the {\tt colors[]} array \end{itemize} The {\tt seed} input parameter is for a random number generator. The {\tt domcolors[]} input array is used only for {\tt flag = 6}. \par \noindent {\it Error checking:} If {\tt bkl} is {\tt NULL}, or if {\tt flag = 6} and {\tt domcolors} is {\tt NULL}, or if {\tt flag} is not in {\tt [1,6]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int BKL_domAdjToSep ( BKL *bkl, int dom ) ; \end{verbatim} \index{BKL_domAdjToSep@{\tt BKL\_domAdjToSep()}} This method returns {\tt 1} if domain {\tt dom} is adjacent to the separator and {\tt 0} otherwise. \par \noindent {\it Error checking:} If {\tt bkl} is {\tt NULL}, or if {\tt dom} is not in {\tt [0,ndom)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Partition evaluation methods} \label{subsection:BKL:proto:evaluation} \par There are three functions that evaluate the cost of a partition. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void BKL_evalgain ( BKL *bkl, int dom, int *pdeltaS, int *pdeltaB, int *pdeltaW ) ; \end{verbatim} \index{BKL_evalgain@{\tt BKL\_evalgain()}} This method evaluates the change in the components $\Delta S$, $\Delta B$ and $\Delta W$ that would occur if domain {\tt dom} were to be flipped. These {\it gain} values are put into the storage pointed to by {\tt pdeltaS}, {\tt pdeltaB} and {\tt pdeltaW}. The method checks that {\tt bkl}, {\tt pdeltaS}, {\tt pdeltaB} and {\tt pdeltaW} are not {\tt NULL} and that {\tt idom} is in {\tt [0,bkl->ndom)}. \par \noindent {\it Error checking:} If {\tt bkl}, {\tt pdeltaS}, {\tt pdeltaB} or {\tt pdeltaW} is {\tt NULL}, or if {\tt dom} is not in {\tt [0,ndom)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} float BKL_evalfcn ( BKL *bkl ) ; \end{verbatim} \index{BKL_evalfcn@{\tt BKL\_evalfcn()}} The $|S|$, $|B|$ and $|W|$ values are taken from the {\tt cweights[]} vector. If $\min(|B|,|W|) > 0$, this function returns $$ |S|\left(1 + \alpha * \frac{\max(|B|,|W|)}{\min(|B|,|W|)} \right), $$ otherwise it returns $(|S| + |B| + |W|)^2$. \par \noindent {\it Error checking:} If {\tt bkl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} float BKL_eval ( BKL *bkl, int Sweight, int Bweight, int Wweight ) ; \end{verbatim} \index{BKL_eval@{\tt BKL\_eval()}} The $|S|$, $|B|$ and $|W|$ values are taken from the {\tt Sweight}, {\tt Bweight} and {\tt Wweight} parameters. If $\min(|B|,|W|) > 0$, this function returns $$ |S|\left(1 + \alpha * \frac{\max(|B|,|W|)}{\min(|B|,|W|)} \right), $$ otherwise it returns $(|S| + |B| + |W|)^2$. The method checks that {\tt bkl} is not {\tt NULL}. \par \noindent {\it Error checking:} If {\tt bkl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Partition improvement methods} \label{subsection:BKL:proto:improve} \par There are two functions that take a given partition and some input parameters and return a (hopefully) improved partition. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} float BKL_exhSearch ( BKL *bkl, int mdom, int domids[], int tcolors[] ) ; \end{verbatim} \index{BKL_exhSearch@{\tt BKL\_exhSearch()}} This method performs an exhaustive search of a subspace of partitions and returns the best partition. The starting partition is given by the {\tt BKL} object's {\tt colors[]} vector. The subspace of domains to flip is defined by the {\tt domids[mdom]} vector. The {\tt tcolors[]} vector is a work vector. There are $2^{\mbox{\tt mdom}}$ distinct partitions in the subspace to be explored. We flip the domains using a grey code sequence so a total of $2^{\mbox{\tt mdom}}$ domain flips are performed. The {\tt bkl->colors[]} vector is filled with the colors of the best partition and its cost is returned. \par \noindent {\it Error checking:} If {\tt bkl}, {\tt domids} or {\tt tcolors} is {\tt NULL}, or if {\tt mdom < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} float BKL_fidmat ( BKL *bkl ) ; \end{verbatim} \index{BKL_fidmat@{\tt BKL\_fidmat()}} If the number of domains is eight or less, an exhaustive search is made. Otherwise, this method finds a good partition using a variant of the Fiduccia-Mattheyes algorithm. At any step, only the domains that are adjacent to the separator are eligible to be flipped. For each eligible domain, we maintain $\Delta S$, $\Delta B$ and $\Delta W$, the change in the three component weights if this domain were to be flipped. These values must be updated whenever a neighboring domain has been flipped, and so is {\it local} information. The cost of the partition that would result if a domain were to be flipped is a function of the local information $\Delta S$, $\Delta B$ and $\Delta W$, as well as the present weights of the components (global information). At each step we evaluate the cost of the resulting partition for each domain that is eligible to be flipped. This is relatively expensive when compared to using a heap to contain $\Delta S$ for each domain, but we have found the resulting partitions to be better. The eligible domains are kept on a doubly linked list to allow easy insertions and deletions. \par \noindent {\it Error checking:} If {\tt bkl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} BKL/doc/main.log010064400020550007177000000042000653577076200147120ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 5 JUN 1998 06:26 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. ) (dataStructure.tex [1 ]) (proto.tex Overfull \hbox (15.59521pt too wide) in paragraph at lines 46--50 \elvrm tors. It then fills the struc-ture's fields with de-fault val-ues with a call to \elvtt BKL[]setDefaultFields()\elvrm . \hbox(7.60416+0.91246)x442.37993, glue set - 1.0 .\elvrm t .\elvrm o .\elvrm r .\elvrm s .\elvrm . .etc. [2] [3] Overfull \hbox (34.76115pt too wide) in paragraph at lines 231--231 [] []\elvtt void BKL_evalgain ( BKL *bkl, int dom, int *pdeltaS, int *pdeltaB, int *pdeltaW ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. [4]) (main.ind [5] [6 ]) (main.aux) ) Here is how much of TeX's memory you used: 206 strings out of 11977 2150 string characters out of 87269 33248 words of memory out of 262141 2143 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,6n,17p,180b,228s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (6 pages, 16376 bytes). BKL/doc/main.aux010064400020550007177000000026670653577076200147450ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space BKL}: Block Kernighan-Lin Object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \newlabel{chapter:BKL}{{1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:BKL:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space BKL} methods}{2}} \newlabel{section:BKL:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Basic methods}{2}} \newlabel{subsection:BKL:proto:basics}{{1.3}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.3.1}Initializer methods}{3}} \newlabel{subsection:BKL:proto:initializers}{{1.3.1}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.3.2}Utility methods}{3}} \newlabel{subsection:BKL:proto:utilities}{{1.3.2}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.3.3}Partition evaluation methods}{4}} \newlabel{subsection:BKL:proto:evaluation}{{1.3.3}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.3.4}Partition improvement methods}{5}} \newlabel{subsection:BKL:proto:improve}{{1.3.4}{5}} BKL/doc/main.idx010064400020550007177000000016070653577076200147250ustar00clevecompmath00000400000006\indexentry{BKL_new@{\tt BKL\_new()}}{2} \indexentry{BKL_setDefaultFields@{\tt BKL\_setDefaultFields()}}{2} \indexentry{BKL_clearData@{\tt BKL\_clearData()}}{2} \indexentry{BKL_free@{\tt BKL\_free()}}{2} \indexentry{BKL_init@{\tt BKL\_init()}}{3} \indexentry{BKL_setRandomColors@{\tt BKL\_setRandomColors()}}{3} \indexentry{BKL_setColorWeights@{\tt BKL\_setColorWeights()}}{3} \indexentry{BKL_segColor@{\tt BKL\_segColor()}}{3} \indexentry{BKL_flipDomain@{\tt BKL\_flipDomain()}}{3} \indexentry{BKL_greyCodeDomain@{\tt BKL\_greyCodeDomain()}}{3} \indexentry{BKL_setInitPart@{\tt BKL\_setInitPart()}}{3} \indexentry{BKL_domAdjToSep@{\tt BKL\_domAdjToSep()}}{4} \indexentry{BKL_evalgain@{\tt BKL\_evalgain()}}{4} \indexentry{BKL_evalfcn@{\tt BKL\_evalfcn()}}{4} \indexentry{BKL_eval@{\tt BKL\_eval()}}{5} \indexentry{BKL_exhSearch@{\tt BKL\_exhSearch()}}{5} \indexentry{BKL_fidmat@{\tt BKL\_fidmat()}}{5} BKL/doc/main.ind010064400020550007177000000011450653577076000147060ustar00clevecompmath00000400000006\begin{theindex} \item {\tt BKL\_clearData()}, 2 \item {\tt BKL\_domAdjToSep()}, 4 \item {\tt BKL\_eval()}, 5 \item {\tt BKL\_evalfcn()}, 4 \item {\tt BKL\_evalgain()}, 4 \item {\tt BKL\_exhSearch()}, 5 \item {\tt BKL\_fidmat()}, 5 \item {\tt BKL\_flipDomain()}, 3 \item {\tt BKL\_free()}, 2 \item {\tt BKL\_greyCodeDomain()}, 3 \item {\tt BKL\_init()}, 3 \item {\tt BKL\_new()}, 2 \item {\tt BKL\_segColor()}, 3 \item {\tt BKL\_setColorWeights()}, 3 \item {\tt BKL\_setDefaultFields()}, 2 \item {\tt BKL\_setInitPart()}, 3 \item {\tt BKL\_setRandomColors()}, 3 \end{theindex} BKL/doc/main.ilg010064400020550007177000000004560653577076000147130ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (17 entries accepted, 0 rejected). Sorting entries....done (68 comparisons). Generating output file main.ind....done (21 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. BKL/doc/makefile010064400020550007177000000000270654276733000147610ustar00clevecompmath00000400000006clean : - rm -f *.dvi BPG.h010064400020550007177000000000700653410640300126500ustar00clevecompmath00000400000006#ifndef _BPG_ #define _BPG_ #include "BPG/BPG.h" #endif BPG/BPG.h010064400020550007177000000247630653410612700133020ustar00clevecompmath00000400000006/* BPG.h */ #include "../Graph.h" #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------- the BPG object holds a bipartite graph. the edge set E \subseteq X \times Y, where X and Y are two sets of vertices, X = { 0, 1, ..., nX - 1} Y = { nX, nX + 1, ..., nX + nY - 1 } the BPG object contains a Graph object graph, a hack because C does not possess inheritance. created -- 95oct06, cca ---------------------------------------------- */ typedef struct _BPG BPG ; struct _BPG { int nX ; int nY ; Graph *graph ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- purpose -- create and return a new BPG object created -- 95oct06, cca ----------------------------------------------- */ BPG * BPG_new ( void ) ; /* ------------------------------------------------------ purpose -- set the default fields for the BPG object created -- 95oct06, cca ------------------------------------------------------ */ void BPG_setDefaultFields ( BPG *bpg ) ; /* -------------------------------- purpose -- clear the data fields created -- 95oct06, cca -------------------------------- */ void BPG_clearData ( BPG *bpg ) ; /* -------------------------------- purpose -- free the BPG object created -- 95oct06, cca -------------------------------- */ void BPG_free ( BPG *bpg ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in DM.c -------------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------- compute the generalized Dulmadge-Mendolsohn decomposition bpg -- BPG bipartite graph object dmflags -- flags vector / 0 if x in X_R dmflags[x] = | 1 if x in X_I \ 2 if x in X_E / 0 if y in Y_R dmflags[y] = | 1 if y in Y_I \ 2 if y in Y_E stats -- statistics vector stats[0] -- weight of X_I stats[1] -- weight of X_E stats[2] -- weight of X_R stats[3] -- weight of Y_I stats[4] -- weight of Y_E stats[5] -- weight of Y_R created -- 95oct12, cca --------------------------------------------------------- */ void BPG_DMdecomposition ( BPG *bpg, int dmflags[], int stats[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in maxFlow.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------- find the DM decomposition of a weighted bipartite graph using a simple max flow algorithm bpg -- BPG bipartite graph object dmflags -- flags vector / 0 if x in X_R dmflags[x] = | 1 if x in X_I \ 2 if x in X_E / 0 if y in Y_R dmflags[y] = | 1 if y in Y_I \ 2 if y in Y_E stats -- statistics vector stats[0] -- weight of X_I stats[1] -- weight of X_E stats[2] -- weight of X_R stats[3] -- weight of Y_I stats[4] -- weight of Y_E stats[5] -- weight of Y_R created -- 96mar08, cca ------------------------------------------------------- */ void BPG_DMviaMaxFlow ( BPG *bpg, int dmflags[], int stats[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------------------------------------------- initialize a BPG object, set bpg->nX = nX, bpg->nY = nY, and bpg->graph = graph. convert graph into bipartite form, i.e., adj(v) := adj(v) \cap {nX, ..., nX + nY - 1} for v in [0, nX) adj(v) := adj(v) \cap {0, ..., nX - 1} for v in [nX, nX+nY) created -- 95oct06, cca -------------------------------------------------------------------- */ void BPG_init ( BPG *bpg, int nX, int nY, Graph *graph ) ; /* ----------------------------------------------------------- initialize from a graph given a color vector and two target vectors. this method can be used to get the bipartite graph of the boundary of two components. graph -- graph from which to extract the bipartite graph colors -- vector of colors for the vertices cX -- color for the X vertices cY -- color for the Y vertices cmap -- map from vertices in g to vertices in bpg indX -- vector to hold the global indices in X indY -- vector to hold the global indices in Y created -- 95oct06, cca ----------------------------------------------------------- */ void BPG_initFromColoring ( BPG *bpg, Graph *graph, int colors[], int cX, int cY, int cmap[], int indX[], int indY[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------- purpose -- to read in a BPG object from a file input -- fn -- filename, must be *.bpgb or *.bpgf return value -- 1 if success, 0 if failure created -- 95oct06, cca ---------------------------------------------- */ int BPG_readFromFile ( BPG *bpg, char *fn ) ; /* -------------------------------------------------------- purpose -- to read a BPG object from a formatted file return value -- 1 if success, 0 if failure created -- 95oct06, cca -------------------------------------------------------- */ int BPG_readFromFormattedFile ( BPG *bpg, FILE *fp ) ; /* ---------------------------------------------------- purpose -- to read a BPG object from a binary file return value -- 1 if success, 0 if failure created -- 95oct06, cca ---------------------------------------------------- */ int BPG_readFromBinaryFile ( BPG *bpg, FILE *fp ) ; /* -------------------------------------------- purpose -- to write a BPG object to a file input -- fn -- filename *.bpgb -- binary *.bpgf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95oct06, cca -------------------------------------------- */ int BPG_writeToFile ( BPG *bpg, char *fn ) ; /* ------------------------------------------------------ purpose -- to write a BPG object to a formatted file return value -- 1 if success, 0 otherwise created -- 95oct06, cca ------------------------------------------------------ */ int BPG_writeToFormattedFile ( BPG *bpg, FILE *fp ) ; /* --------------------------------------------------- purpose -- to write a BPG object to a binary file return value -- 1 if success, 0 otherwise created -- 95oct06, cca --------------------------------------------------- */ int BPG_writeToBinaryFile ( BPG *bpg, FILE *fp ) ; /* ------------------------------------------------- purpose -- to write a BPG object for a human eye return value -- 1 if success, 0 otherwise created -- 95oct06, cca ------------------------------------------------- */ int BPG_writeForHumanEye ( BPG *bpg, FILE *fp ) ; /* ----------------------------------------------------------- purpose -- to write out the statistics for the BPG object return value -- 1 if success, 0 otherwise created -- 95oct06, cca ----------------------------------------------------------- */ int BPG_writeStats ( BPG *bpg, FILE *fp ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in makeGraphs.c ------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- purpose -- return the X by X graph where (x1,x2) is an edge if there exists a y in Y such that (x1,y) and (x2,y) are edges in the bipartite graph. created -- 95dec06, cca to be used in the BKL object. ----------------------------------------------------------- */ Graph * BPG_makeGraphXbyX ( BPG *bpg ) ; /* ----------------------------------------------------------- purpose -- return the Y by Y graph where (y1,y2) is an edge if there exists a x in X such that (x,y1) and (x,y2) are edges in the bipartite graph. created -- 95dec07, cca ----------------------------------------------------------- */ Graph * BPG_makeGraphYbyY ( BPG *bpg ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in pseudo.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------ return a pseudoperipheral node created -- 95oct07, cca ------------------------------ */ int BPG_pseudoperipheralnode ( BPG *bpg, int seed ) ; /* ---------------------------------------------------- return value -- # of vertices in the level structure created -- 95oct07, cca ---------------------------------------------------- */ int BPG_levelStructure ( BPG *bpg, int root, int list[], int dist[], int mark[], int tag ) ; /*--------------------------------------------------------------------*/ BPG/makefile010064400020550007177000000002230663622354200142060ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean BPG/src/makefile010064400020550007177000000007740663602114500150030ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = BPG $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(DM.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(makeGraphs.o) \ $(OBJ).a(maxFlow.o) \ $(OBJ).a(pseudo.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG BPG/src/makeGlobalLib010064400020550007177000000006570660026074700157170ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = BPG SRC = basics.c \ DM.c \ init.c \ IO.c \ makeGraphs.c \ maxFlow.c \ pseudo.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a BPG/src/DM.c010064400020550007177000001160650653410612600137500ustar00clevecompmath00000400000006/* DM.c */ #include "../../BPG.h" /*--------------------------------------------------------------------*/ /* ----------------- static prototypes ----------------- */ static void nonunitDM ( BPG *bpg, int dmflags[], int stats[], int msglvl, FILE *msgFile) ; static void unitDM ( BPG *bpg, int dmflags[], int stats[], int msglvl, FILE *msgFile) ; static int nonunitFindExposedNode ( BPG *bpg, int uexp, int list[], int link[], int mark[], int tag, int nvexp[], IVL *ivl, int msglvl, FILE *msgFile ) ; static int nonunitFindNmatch ( BPG *bpg, int uexp, int vexp, int nvexp[], int link[], IVL *ivl, int msglvl, FILE *msgFile ) ; static void nonunitFlipEdges ( BPG *bpg, int uexp, int vexp, int nmatch, int nvexp[], int link[], IVL *ivl, int msglvl, FILE *msgFile ) ; static void nonunitSetFlags ( BPG *bpg, int list[], int nvexp[], int mark[], IVL *ivl, int dmflags[], int stats[], int msglvl, FILE *msgFile ) ; static void unitFindMaxMatch ( BPG *bpg, int mate[], int msglvl, FILE *msgFile ) ; static int unitAugmentingPath ( BPG *bpg, int uexp, int mate[], int mark[], int link[], int list[], int msglvl, FILE *msgFile ) ; static void unitSetFlags ( BPG *bpg, int mate[], int dmflags[], int stats[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- compute the generalized Dulmadge-Mendolsohn decomposition bpg -- BPG bipartite graph object dmflags -- flags vector / 0 if x in X_R dmflags[x] = | 1 if x in X_I \ 2 if x in X_E / 0 if y in Y_R dmflags[y] = | 1 if y in Y_I \ 2 if y in Y_E stats -- statistics vector stats[0] -- weight of X_I stats[1] -- weight of X_E stats[2] -- weight of X_R stats[3] -- weight of Y_I stats[4] -- weight of Y_E stats[5] -- weight of Y_R created -- 95oct12, cca --------------------------------------------------------- */ void BPG_DMdecomposition ( BPG *bpg, int dmflags[], int stats[], int msglvl, FILE *msgFile ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n inside BPG_DMdecomposition") ; fflush(msgFile) ; } /* --------------- check the input --------------- */ if ( bpg == NULL || dmflags == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in BPG_DMdecomposition(%p,%p,%p,%d,%p)" "\n bad input\n", bpg, dmflags, stats, msglvl, msgFile) ; exit(-1) ; } if ( bpg->graph->type % 2 == 0 ) { /* ----------------- unit weight graph ----------------- */ unitDM(bpg, dmflags, stats, msglvl, msgFile) ; } else { /* -------------------- nonunit weight graph -------------------- */ nonunitDM(bpg, dmflags, stats, msglvl, msgFile) ; } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n leaving BPG_DMdecomposition") ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- compute the generalized Dulmadge-Mendolsohn decomposition for a nonunit weight graph. bpg -- BPG bipartite graph object dmflags -- flags vector / 0 if x in X_R dmflags[x] = | 1 if x in X_I \ 2 if x in X_E / 0 if y in Y_R dmflags[y] = | 1 if y in Y_I \ 2 if y in Y_E stats -- statistics vector stats[0] -- weight of X_I stats[1] -- weight of X_E stats[2] -- weight of X_R stats[3] -- weight of Y_I stats[4] -- weight of Y_E stats[5] -- weight of Y_R created -- 95oct12, cca --------------------------------------------------------- */ static void nonunitDM ( BPG *bpg, int dmflags[], int stats[], int msglvl, FILE *msgFile ) { int maxnXnY, nmatch, nX, nY, tag, x, xexp, y, yexp ; int *link, *list, *mark, *nvexp ; IVL *ivl ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n inside nonunitDM") ; fflush(msgFile) ; } /* --------------- check the input --------------- */ if ( bpg == NULL || dmflags == NULL || stats == NULL ) { fprintf(stderr, "\n fatal error in nonunitDM(%p,%p,%p)" "\n bad input\n", bpg, dmflags, stats) ; exit(-1) ; } nX = bpg->nX ; nY = bpg->nY ; maxnXnY = ( nX >= nY ) ? nX : nY ; /* ----------------------- create the working data ----------------------- */ list = IVinit(maxnXnY, -1) ; link = IVinit(nX+nY, -1) ; mark = IVinit(nX+nY, -1) ; nvexp = IVinit(nX+nY, 0) ; IVcopy(nX + nY, nvexp, bpg->graph->vwghts) ; ivl = IVL_new() ; IVL_setDefaultFields(ivl) ; IVL_init3(ivl, IVL_CHUNKED, nX + nY, nvexp) ; /* -------- DEBUG!!! -------- */ /* { int v ; for ( v = 0 ; v < nX + nY ; v++ ) { IVshuffle(bpg->g->adjIVL->sizes[v], bpg->g->adjIVL->p_vec[v], 57) ; } } */ /* ------------------------ loop over the x vertices ------------------------ */ for ( xexp = 0, tag = 1 ; xexp < nX ; xexp++ ) { while ( nvexp[xexp] > 0 ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n\n checking out %d, nvexp[%d] = %d", xexp, xexp, nvexp[xexp]) ; } yexp = nonunitFindExposedNode(bpg, xexp, list, link, mark, tag, nvexp, ivl, msglvl, msgFile) ; tag++ ; if ( yexp == -1 ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n exposed node %d, no alternating path", xexp) ; fflush(msgFile) ; } break ; } else { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n exposed node %d, alternating node ends at %d", xexp, yexp) ; fprintf(msgFile, "\n path : %d", yexp) ; x = link[yexp] ; while ( x != xexp ) { y = link[x] ; fprintf(msgFile, " --> %d ==> %d", x, y) ; x = link[y] ; } fprintf(msgFile, " --> %d", xexp) ; fflush(msgFile) ; } nmatch = nonunitFindNmatch(bpg, xexp, yexp, nvexp, link, ivl, msglvl, msgFile) ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n nmatch = %d", nmatch) ; } nonunitFlipEdges(bpg, xexp, yexp, nmatch, nvexp, link, ivl, msglvl, msgFile) ; } } } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n match IVL") ; IVL_writeForHumanEye(ivl, msgFile) ; } /* ------------- set the flags ------------- */ nonunitSetFlags(bpg, list, nvexp, mark, ivl, dmflags, stats, msglvl, msgFile) ; /* ------------------------ free the working storage ------------------------ */ IVfree(list) ; IVfree(link) ; IVfree(mark) ; IVfree(nvexp) ; IVL_free(ivl) ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n leaving nonunitDM") ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- find exposed node that is the endpoint of an alternating path that starts with uexp this method uses a breadth-first traversal uexp -- exposed node to be the start of the alternating path list -- list vector, size max(nX, nY) link -- link vector, used to define alternating path, size nX + nY mark -- mark vector, used to keep track of nodes in the tree tag -- unique tag for this call nvexp -- nvexp[u] = # of exposed vertices in u ivl -- IVL object to hold matched edges return value -- exposed node if exists, otherwise -1 created -- 95oct14, cca --------------------------------------------------------------------- */ static int nonunitFindExposedNode ( BPG *bpg, int uexp, int list[], int link[], int mark[], int tag, int nvexp[], IVL *ivl, int msglvl, FILE *msgFile ) { int ierr, ii, jj, last, now, u, unew, usize, v, vsize ; int *uadj, *vind ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n inside nonunitFindExposedNode(%d)", uexp) ; fflush(msgFile) ; } /* --------------- check the input --------------- */ if ( bpg == NULL || uexp < 0 || uexp > (bpg->nX + bpg->nY) || list == NULL || link == NULL || mark == NULL || nvexp == NULL || ivl == NULL ) { fprintf(stderr, "\n fatal error in nonunitFindExposedNode2(%p,%d,%p,%p,%p,%d,%p,%p)" "\n bad input\n", bpg, uexp, list, link, mark, tag, nvexp, ivl) ; exit(-1) ; } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n\n working on exposed %d, nvexp %d", uexp, nvexp[uexp]) ; } /* ----------------------------------- load the list with the exposed node ----------------------------------- */ now = last = 0 ; list[0] = u = uexp ; mark[u] = tag ; while ( now <= last ) { u = list[now++] ; Graph_adjAndSize(bpg->graph, u, &usize, &uadj) ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n checking out u = %d : ", u) ; IVfp80(msgFile, usize, uadj, 20, &ierr) ; fflush(msgFile) ; } for ( ii = 0 ; ii < usize ; ii++ ) { v = uadj[ii] ; if ( mark[v] != tag ) { mark[v] = tag ; link[v] = u ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n adding %d with nvexp[%d] = %d to tree", v, v, nvexp[v]) ; fflush(msgFile) ; } if ( nvexp[v] > 0 ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, ", exposed") ; fflush(msgFile) ; } return(v) ; } else { IVL_listAndSize(ivl, v, &vsize, &vind) ; for ( jj = 0 ; jj < vsize ; jj++ ) { unew = vind[jj] ; if ( unew == -1 ) { break ; } else if ( mark[unew] != tag ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n adding %d to tree", unew) ; fflush(msgFile) ; } mark[unew] = tag ; link[unew] = v ; list[++last] = unew ; } } } } } } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n leaving nonunitFindExposedNode") ; fflush(msgFile) ; } return(-1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- find the minimum number of match weights along the path from exposed node uexp to exposed node vexp. link -- link vector, used to define alternating path, size nX + nY nvexp -- nvexp[u] = # of exposed vertices in u return value -- minimum match weight created -- 95oct12, cca ------------------------------------------------------------------- */ static int nonunitFindNmatch ( BPG *bpg, int uexp, int vexp, int nvexp[], int link[], IVL *ivl, int msglvl, FILE *msgFile ) { int count, ii, msize, nmatch, u, v ; int *mind ; /* --------------- check the input --------------- */ if ( bpg == NULL || uexp < 0 || uexp > (bpg->nX + bpg->nY) || vexp < 0 || vexp > (bpg->nX + bpg->nY) || (uexp < bpg->nX && vexp < bpg->nX) || (uexp >= bpg->nX && vexp >= bpg->nX) || nvexp == NULL || link == NULL || ivl == NULL ) { fprintf(stderr, "\n fatal error in nonunitFindNmatch(%p,%d,%d,%p,%p,%p)" "\n bad input\n", bpg, uexp, vexp, nvexp, link, ivl) ; exit(-1) ; } /* ---------------------------------------------------------- set nmatch = min(# of exposed vertices in uexp and vexp) ---------------------------------------------------------- */ if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n nvexp[%d] = %d, nvexp[%d] = %d", uexp, nvexp[uexp], vexp, nvexp[vexp]) ; fflush(msgFile) ; } nmatch = (nvexp[uexp] <= nvexp[vexp]) ? nvexp[uexp] : nvexp[vexp] ; if ( nmatch == 1 ) { return(1) ; } /* --------------------------------------------------------------- find the minimum of the weight of the matched edges in the path --------------------------------------------------------------- */ u = link[vexp] ; while ( u != uexp ) { v = link[u] ; /* --------------------------------------------- count the number of times u is matched with v --------------------------------------------- */ IVL_listAndSize(ivl, u, &msize, &mind) ; for ( ii = 0, count = 0 ; ii < msize ; ii++ ) { if ( mind[ii] == -1 ) { break ; } else if ( mind[ii] == v ) { count++ ; } } /* --------------------- check the match count --------------------- */ if ( nmatch > count ) { nmatch = count ; if ( nmatch == 1 ) { return(1) ; } } u = link[v] ; } return(nmatch) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- given an alternating path, flip the edges uexp -- exposed node at start of path vexp -- exposed node at end of path nmatch -- number of matched edges to flip nvexp -- nvexp[u] = # of exposed vertices in u link -- link vector, used to define alternating path, size nX + nY ivl -- IVL object to hold matched edges created -- 95oct12, cca ------------------------------------------------------- */ static void nonunitFlipEdges ( BPG *bpg, int uexp, int vexp, int nmatch, int nvexp[], int link[], IVL *ivl, int msglvl, FILE *msgFile ) { int count, ierr, ii, msize, u, v, vnext ; int *mind ; /* --------------- check the input --------------- */ if ( bpg == NULL || uexp < 0 || uexp > (bpg->nX + bpg->nY) || vexp < 0 || vexp > (bpg->nX + bpg->nY) || (uexp < bpg->nX && vexp < bpg->nX) || (uexp >= bpg->nX && vexp >= bpg->nX) || nmatch <= 0 || nvexp == NULL || link == NULL || ivl == NULL ) { fprintf(stderr, "\n fatal error in BPG_flipMatch(%p,%d,%d,%d,%p,%p,%p)" "\n bad input\n", bpg, uexp, vexp, nmatch, nvexp, link, ivl) ; exit(-1) ; } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n match lists before edge swaps") ; IVL_listAndSize(ivl, vexp, &msize, &mind) ; fprintf(msgFile, "\n %d's match list :", vexp) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; u = link[vexp] ; while ( u != uexp ) { IVL_listAndSize(ivl, u, &msize, &mind) ; fprintf(msgFile, "\n %d's match list :", u) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; v = link[u] ; IVL_listAndSize(ivl, v, &msize, &mind) ; fprintf(msgFile, "\n %d's match list :", v) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; u = link[v] ; } IVL_listAndSize(ivl, uexp, &msize, &mind) ; fprintf(msgFile, "\n %d's match list :", uexp) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; fflush(msgFile) ; } if ( link[vexp] == uexp ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n simple case, %d <---> %d", uexp, vexp) ; fflush(msgFile) ; } /* ------------------------------------ simple case, uexp --> vexp 1. add to uexp's list 2. add to vexp's list ------------------------------------ */ IVL_listAndSize(ivl, uexp, &msize, &mind) ; for ( ii = 0, count = 0 ; ii < msize ; ii++ ) { if ( mind[ii] == -1 ) { mind[ii] = vexp ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n %d's list, mind[%d] = %d", uexp, ii, mind[ii]) ; fflush(msgFile) ; } if ( ++count == nmatch ) { break ; } } } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n %d's match list :", uexp) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; fflush(msgFile) ; } if ( count != nmatch ) { fprintf(stderr, "\n fatal error in BPG_flipMatch()" "\n uexp = %d, vexp = %d, count = %d, nmatch = %d" "\n u matches with ", uexp, vexp, count, nmatch) ; IVfp80(stderr, msize, mind, 12, &ierr) ; exit(-1) ; } IVL_listAndSize(ivl, vexp, &msize, &mind) ; for ( ii = 0, count = 0 ; ii < msize ; ii++ ) { if ( mind[ii] == -1 ) { mind[ii] = uexp ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n %d's list, mind[%d] = %d", vexp, ii, mind[ii]) ; fflush(msgFile) ; } if ( ++count == nmatch ) { break ; } } } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n %d's match list :", vexp) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; fflush(msgFile) ; } if ( count != nmatch ) { fprintf(stderr, "\n fatal error in BPG_flipMatch()" "\n uexp = %d, vexp = %d, count = %d, nmatch = %d" "\n v matches with ", uexp, vexp, count, nmatch) ; IVfp80(stderr, msize, mind, 12, &ierr) ; exit(-1) ; } } else { /* ------------------------------------------------------- uexp <--> v <==> u <--> v <==> u ... v <==> u <--> vexp deal with the middle edges ------------------------------------------------------- */ if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n complex case : %d <---> ... <---> %d", uexp, vexp) ; fflush(msgFile) ; } vnext = vexp ; u = link[vexp] ; while ( u != uexp ) { v = link[u] ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n checking out %d <===> %d <---> %d", v, u, vnext) ; fflush(msgFile) ; } /* ---------------------------------------------------------- check out u's list of matches, find if ( nmatch(u,v) == nmatch ) then replace with else if ( nmatch(u,v) > nmatch ) then replace with add else error endif ---------------------------------------------------------- */ IVL_listAndSize(ivl, u, &msize, &mind) ; for ( ii = 0, count = 0 ; ii < msize ; ii++ ) { if ( mind[ii] == v ) { mind[ii] = vnext ; if ( ++count == nmatch ) { break ; } } } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n %d's match list :", u) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; fflush(msgFile) ; } if ( count != nmatch ) { fprintf(stderr, "\n fatal error in BPG_flipMatch()" "\n u = %d, count = %d, nmatch = %d" "\n %d match list : ", u, count, nmatch, u) ; IVfp80(stderr, msize, mind, 12, &ierr) ; exit(-1) ; } IVL_listAndSize(ivl, v, &msize, &mind) ; for ( ii = 0, count = 0 ; ii < msize ; ii++ ) { if ( mind[ii] == u ) { mind[ii] = -1 ; if ( ++count == nmatch ) { break ; } } } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n %d's match list :", v) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; fflush(msgFile) ; } if ( count != nmatch ) { fprintf(stderr, "\n fatal error in BPG_flipMatch()" "\n v = %d, count = %d, nmatch = %d" "\n %d match list : ", v, count, nmatch, v) ; IVfp80(stderr, msize, mind, 12, &ierr) ; exit(-1) ; } IVL_listAndSize(ivl, vnext, &msize, &mind) ; for ( ii = 0, count = 0 ; ii < msize ; ii++ ) { if ( mind[ii] == -1 ) { mind[ii] = u ; if ( ++count == nmatch ) { break ; } } } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n %d's match list :", vnext) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; fflush(msgFile) ; } if ( count != nmatch ) { fprintf(stderr, "\n fatal error in BPG_flipMatch()" "\n vnext = %d, count = %d, nmatch = %d" "\n %d match list : ", vnext, count, nmatch, vnext) ; IVfp80(stderr, msize, mind, 12, &ierr) ; exit(-1) ; } /* --------------------------- on to the next matched pair --------------------------- */ vnext = v ; u = link[v] ; } IVL_listAndSize(ivl, uexp, &msize, &mind) ; for ( ii = 0, count = 0 ; ii < msize ; ii++ ) { if ( mind[ii] == -1 ) { mind[ii] = vnext ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n %d's list, mind[%d] = %d", uexp, ii, mind[ii]) ; fflush(msgFile) ; } if ( ++count == nmatch ) { break ; } } } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n %d's match list :", uexp) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; fflush(msgFile) ; } if ( count != nmatch ) { fprintf(stderr, "\n fatal error in BPG_flipMatch()" "\n uexp = %d, vnext = %d, count = %d, nmatch = %d" "\n u matches with ", uexp, vnext, count, nmatch) ; IVfp80(stderr, msize, mind, 12, &ierr) ; exit(-1) ; } IVL_listAndSize(ivl, vnext, &msize, &mind) ; for ( ii = 0, count = 0 ; ii < msize ; ii++ ) { if ( mind[ii] == -1 ) { mind[ii] = uexp ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n %d's list, mind[%d] = %d", vnext, ii, mind[ii]) ; fflush(msgFile) ; } if ( ++count == nmatch ) { break ; } } } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n %d's match list :", vnext) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; fflush(msgFile) ; } if ( count != nmatch ) { fprintf(stderr, "\n fatal error in BPG_flipMatch()" "\n vnext = %d, uexp = %d, count = %d, nmatch = %d" "\n v matches with ", vnext, uexp, count, nmatch) ; IVfp80(stderr, msize, mind, 12, &ierr) ; exit(-1) ; } } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n match lists after edge swaps") ; IVL_listAndSize(ivl, vexp, &msize, &mind) ; fprintf(msgFile, "\n %d's match list :", vexp) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; u = link[vexp] ; while ( u != uexp ) { IVL_listAndSize(ivl, u, &msize, &mind) ; fprintf(msgFile, "\n %d's match list :", u) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; v = link[u] ; IVL_listAndSize(ivl, v, &msize, &mind) ; fprintf(msgFile, "\n %d's match list :", v) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; u = link[v] ; } IVL_listAndSize(ivl, uexp, &msize, &mind) ; fprintf(msgFile, "\n %d's match list :", uexp) ; IVfp80(msgFile, msize, mind, 20, &ierr) ; fflush(msgFile) ; } /* ---------------------------------------------- decrement the nvexp[] values for uexp and vexp ---------------------------------------------- */ nvexp[uexp] -= nmatch ; nvexp[vexp] -= nmatch ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n nvexp[%d] = %d", uexp, nvexp[uexp]) ; fprintf(msgFile, ", nvexp[%d] = %d", vexp, nvexp[vexp]) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ given the maximum matching, set the flags for the DM decomposition list -- list vector, size max(nX, nY) nvexp -- nvexp[u] = # of exposed vertices in u mark -- mark vector, used to keep track of nodes in the tree ivl -- IVL object to hold matched edges dmflags -- flags vector / 0 if x in X_R dmflags[x] = | 1 if x in X_I \ 2 if x in X_E / 0 if y in Y_R dmflags[y] = | 1 if y in Y_I \ 2 if y in Y_E stats -- statistics vector stats[0] -- weight of X_I stats[1] -- weight of X_E stats[2] -- weight of X_R stats[3] -- weight of Y_I stats[4] -- weight of Y_E stats[5] -- weight of Y_R created -- 95oct14, cca ------------------------------------------------------------------ */ static void nonunitSetFlags ( BPG *bpg, int list[], int nvexp[], int mark[], IVL *ivl, int dmflags[], int stats[], int msglvl, FILE *msgFile ) { int ii, jj, last, now, nX, nY, x, xnew, xsize, xwght, y, ynew, ysize, ywght ; int *vwghts, *xadj, *yadj ; /* --------------- check the input --------------- */ if ( bpg == NULL || list == NULL || nvexp == NULL || mark == NULL || ivl == NULL || dmflags == NULL ) { fprintf(stderr, "\n fatal error in BPG_seDMflags(%p,%p,%p,%p,%p,%p,%p)" "\n bad input\n", bpg, list, nvexp, mark, ivl, dmflags, stats) ; exit(-1) ; } nX = bpg->nX ; nY = bpg->nY ; vwghts = bpg->graph->vwghts ; /* ---------------------------------------------- zero the dmflags[] vector and set mark[] to -1 ---------------------------------------------- */ IVzero(nX + nY, dmflags) ; IVfill(nX + nY, mark, -1) ; IVzero(6, stats) ; /* ------------------------------------- load the list with exposed nodes in X ------------------------------------- */ xwght = 0 ; last = -1 ; for ( x = 0 ; x < nX ; x++ ) { if ( nvexp[x] > 0 ) { list[++last] = x ; mark[x] = 1 ; } xwght += vwghts[x] ; } /* ------------------------------------------------------ drop an alternating level structure from the exposed nodes in X, and set dmflags[] for nodes in X_I and Y_E ------------------------------------------------------ */ now = 0 ; while ( now <= last ) { x = list[now++] ; dmflags[x] = 1 ; stats[0] += vwghts[x] ; Graph_adjAndSize(bpg->graph, x, &xsize, &xadj) ; for ( ii = 0 ; ii < xsize ; ii++ ) { y = xadj[ii] ; if ( mark[y] != 1 ) { mark[y] = 1 ; dmflags[y] = 2 ; stats[4] += vwghts[y] ; IVL_listAndSize(ivl, y, &ysize, &yadj) ; for ( jj = 0 ; jj < ysize ; jj++ ) { if ( (xnew = yadj[jj]) == -1 ) { break ; } else if ( mark[xnew] != 1 ) { mark[xnew] = 1 ; list[++last] = xnew ; } } } } } /* ------------------------------------- load the list with exposed nodes in Y ------------------------------------- */ ywght = 0 ; last = -1 ; for ( y = nX ; y < nX + nY ; y++ ) { if ( nvexp[y] > 0 ) { list[++last] = y ; mark[y] = 2 ; } ywght += vwghts[y] ; } /* ------------------------------------------------------ drop an alternating level structure from the exposed nodes in Y, and set dmflags[] for nodes in Y_I and X_E ------------------------------------------------------ */ now = 0 ; while ( now <= last ) { y = list[now++] ; dmflags[y] = 1 ; stats[3] += vwghts[y] ; Graph_adjAndSize(bpg->graph, y, &ysize, &yadj) ; for ( ii = 0 ; ii < ysize ; ii++ ) { x = yadj[ii] ; if ( mark[x] != 2 ) { mark[x] = 2 ; dmflags[x] = 2 ; stats[1] += vwghts[x] ; IVL_listAndSize(ivl, x, &xsize, &xadj) ; for ( jj = 0 ; jj < xsize ; jj++ ) { if ( (ynew = xadj[jj]) == -1 ) { break ; } else if ( mark[ynew] != 2 ) { mark[ynew] = 2 ; list[++last] = ynew ; } } } } } /* ------------------------------ set the weights of X_R and Y_R ------------------------------ */ stats[2] = xwght - stats[0] - stats[1] ; stats[5] = ywght - stats[3] - stats[4] ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- compute the generalized Dulmadge-Mendolsohn decomposition for a unit weight graph. bpg -- BPG bipartite graph object dmflags -- flags vector / 0 if x in X_R dmflags[x] = | 1 if x in X_I \ 2 if x in X_E / 0 if y in Y_R dmflags[y] = | 1 if y in Y_I \ 2 if y in Y_E stats -- statistics vector stats[0] -- weight of X_I stats[1] -- weight of X_E stats[2] -- weight of X_R stats[3] -- weight of Y_I stats[4] -- weight of Y_E stats[5] -- weight of Y_R created -- 95oct12, cca --------------------------------------------------------- */ static void unitDM ( BPG *bpg, int dmflags[], int stats[], int msglvl, FILE *msgFile ) { int nX, nY ; int *mate ; /* --------------- check the input --------------- */ if ( bpg == NULL || dmflags == NULL || stats == NULL ) { fprintf(stderr, "\n fatal error in unitDM(%p,%p,%p)" "\n bad input\n", bpg, dmflags, stats) ; exit(-1) ; } nX = bpg->nX ; nY = bpg->nY ; mate = IVinit(nX + nY, -1) ; if ( msglvl > 1 && msgFile != NULL ) { BPG_writeForHumanEye(bpg, msgFile) ; } /* ----------------------- find a maximum matching ----------------------- */ unitFindMaxMatch(bpg, mate, msglvl, msgFile) ; /* -------------------------------------- fill the dmflags[] and stats[] vectors -------------------------------------- */ unitSetFlags(bpg, mate, dmflags, stats, msglvl, msgFile) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- find a maximum matching for a unit weight graph created -- 95oct14, cca ----------------------------------------------- */ static void unitFindMaxMatch ( BPG *bpg, int mate[], int msglvl, FILE *msgFile ) { int nX, nY, rc, x, y ; int *link, *list, *mark ; /* --------------- check the input --------------- */ if ( bpg == NULL || mate == NULL ) { fprintf(stderr, "\n fatal error in unitFindMaxMatch(%p,%p)" "\n bad input\n", bpg, mate) ; exit(-1) ; } nX = bpg->nX ; nY = bpg->nY ; /* -------------------------- create the working storage -------------------------- */ mark = IVinit(nX + nY, -1) ; link = IVinit(nX + nY, -1) ; list = IVinit(nX + nY, -1) ; /* --------------------------------------------------------- look for an augmenting path rooted at each exposed vertex --------------------------------------------------------- */ if ( nX <= nY ) { for ( x = 0 ; x < nX ; x++ ) { if ( mate[x] == -1 ) { rc = unitAugmentingPath(bpg, x, mate, mark, link, list, msglvl, msgFile) ; } } } else { for ( y = nX ; y < nX + nY ; y++ ) { if ( mate[y] == -1 ) { rc = unitAugmentingPath(bpg, y, mate, mark, link, list, msglvl, msgFile) ; } } } /* ------------------------ free the working storage ------------------------ */ IVfree(mark) ; IVfree(link) ; IVfree(list) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- look for a augmenting path starting at node uexp. if one found, flip the match edges. return value -- 1 if success 0 otherwise created -- 95oct14, cca ------------------------------------------------- */ static int unitAugmentingPath ( BPG *bpg, int uexp, int mate[], int mark[], int link[], int list[], int msglvl, FILE *msgFile ) { int ii, last, nextv, now, u, usize, v ; int *uadj ; /* --------------- check the input --------------- */ if ( bpg == NULL || uexp < 0 || (bpg->nX + bpg->nY <= uexp) || mate == NULL || mark == NULL || link == NULL || list == NULL || mate[uexp] != -1 ) { fprintf(stderr, "\n fatal error in unitAugmentingPath(%p,%d,%p,%p,%p,%p)" "\n bad input\n", bpg, uexp, mate, mark, link, list) ; exit(-1) ; } if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n\n uexp = %d", uexp) ; } now = last = 0 ; list[0] = uexp ; mark[uexp] = uexp ; while ( now <= last ) { u = list[now++] ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n checking out %d", u) ; } Graph_adjAndSize(bpg->graph, u, &usize, &uadj) ; for ( ii = 0 ; ii < usize ; ii++ ) { v = uadj[ii] ; if ( mark[v] != uexp ) { /* ------------------------------------ v is not yet in the alternating tree ------------------------------------ */ if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n adding v = %d to tree", v) ; } mark[v] = uexp ; link[v] = u ; if ( mate[v] == -1 ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, ", exposed") ; } /* --------------------------------------------- v is exposed, flip the match edges and return --------------------------------------------- */ while ( v != -1 ) { u = link[v] ; nextv = mate[u] ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n setting %d <===> %d", v, u); } mate[u] = v ; mate[v] = u ; v = nextv ; } return(1) ; } else { /* ------------------------ put v's mate on the list ------------------------ */ if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n adding u = %d to tree", mate[v]) ; } list[++last] = mate[v] ; } } } } return(0) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ set the dmflags[] and stats[] arrays for a unit weight graph ------------------------------------------------------------ */ static void unitSetFlags ( BPG *bpg, int mate[], int dmflags[], int stats[], int msglvl, FILE *msgFile ) { int ierr, ii, last, now, nX, nY, x, xmate, xsize, y, ymate, ysize ; int *list, *xadj, *yadj ; /* --------------- check the input --------------- */ if ( bpg == NULL || mate == NULL || dmflags == NULL || stats == NULL ){ fprintf(stderr, "\n fatal error in unitSetFlags(%p,%p,%p,%p)" "\n bad input\n", bpg, mate, dmflags, stats) ; exit(-1) ; } nX = bpg->nX ; nY = bpg->nY ; list = IVinit(nX + nY, -1) ; /* -------------------------------------- zero the dmflags[] and stats[] vectors -------------------------------------- */ IVzero(nX + nY, dmflags) ; IVzero(6, stats) ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n MATE") ; IVfp80(msgFile, nX + nY, mate, 80, &ierr) ; } /* ------------------------------------- load the list with exposed nodes in X ------------------------------------- */ if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n\n exposed nodes in X") ; } last = -1 ; for ( x = 0 ; x < nX ; x++ ) { if ( mate[x] == -1 ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n loading x = %d", x) ; } list[++last] = x ; dmflags[x] = 1 ; } } /* ------------------------------------------------------ drop an alternating level structure from the exposed nodes in X, and set dmflags[] for nodes in X_I and Y_E ------------------------------------------------------ */ now = 0 ; while ( now <= last ) { x = list[now++] ; Graph_adjAndSize(bpg->graph, x, &xsize, &xadj) ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n adj(%d) :", x) ; IVfp80(msgFile, xsize, xadj, 10, &ierr) ; fflush(msgFile) ; } for ( ii = 0 ; ii < xsize ; ii++ ) { y = xadj[ii] ; if ( dmflags[y] == 0 ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n adding y = %d", y) ; } dmflags[y] = 2 ; if ( (xmate = mate[y]) == -1 ) { fprintf(stderr, "\n fatal error in unitSetFlags" "\n now = %d, x = %d, y = %d, mate = -1", now, x, y) ; fprintf(stderr, "\n adj(%d) :", x) ; IVfp80(stderr, xsize, xadj, 10, &ierr) ; exit(-1) ; } else if ( dmflags[xmate] == 0 ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n adding xmate = %d", xmate) ; } dmflags[xmate] = 1 ; list[++last] = xmate ; } } } } /* ------------------------------------- load the list with exposed nodes in Y ------------------------------------- */ if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n\n exposed nodes in X") ; } last = -1 ; for ( y = 0 ; y < nX + nY ; y++ ) { if ( mate[y] == -1 ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n loading y = %d", y) ; } list[++last] = y ; dmflags[y] = 1 ; } } /* ------------------------------------------------------ drop an alternating level structure from the exposed nodes in X, and set dmflags[] for nodes in X_I and Y_E ------------------------------------------------------ */ now = 0 ; while ( now <= last ) { y = list[now++] ; Graph_adjAndSize(bpg->graph, y, &ysize, &yadj) ; for ( ii = 0 ; ii < ysize ; ii++ ) { x = yadj[ii] ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n loading x = %d", x) ; } if ( dmflags[x] == 0 ) { dmflags[x] = 2 ; if ( (ymate = mate[x]) == -1 ) { fprintf(stderr, "\n fatal error in unitSetFlags" "\n x = %d, mate = -1", x) ; exit(-1) ; } else if ( dmflags[ymate] == 0 ) { if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n loading ymate = %d", ymate) ; } dmflags[ymate] = 1 ; list[++last] = ymate ; } } } } /* ------------------------ free the working storage ------------------------ */ IVfree(list) ; /* ------------------------------ set the weights of X_R and Y_R ------------------------------ */ stats[0] = stats[1] = stats[2] = stats[3] = stats[4] = stats[5] = 0 ; for ( x = 0 ; x < nX ; x++ ) { switch ( dmflags[x] ) { case 0 : stats[2]++ ; break ; case 1 : stats[0]++ ; break ; case 2 : stats[1]++ ; break ; } } for ( y = nX ; y < nX + nY ; y++ ) { switch ( dmflags[y] ) { case 0 : stats[5]++ ; break ; case 1 : stats[3]++ ; break ; case 2 : stats[4]++ ; break ; } } return ; } /*--------------------------------------------------------------------*/ check the input --------------- */ if ( bpg == NULL || dmflags == NULL || stats == NULL ) { fprintf(stderr, "\n fatal error in unitDM(%p,%p,%p)" "\n bad input\n", bpg, dmflags, stats) ; exit(-1) ; } nX = bpg->nX ; nY = bpg->nY ; mate = IVinit(nX + nY, -1) ; if ( msglvl > 1 && msgFile != NULL ) { BPG_writeForHumanEye(bpg, msgFile) ; } /* ----------------------- find a maximum matching ----------------------- */ unitFindMaxMBPG/src/IO.c010064400020550007177000000332710653410612600137540ustar00clevecompmath00000400000006/* IO.c */ #include "../BPG.h" static const char *suffixb = ".bpgb" ; static const char *suffixf = ".bpgf" ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to read in a BPG object from a file input -- fn -- filename, must be *.bpgb or *.bpgf return value -- 1 if success, 0 if failure created -- 95oct06, cca ---------------------------------------------- */ int BPG_readFromFile ( BPG *bpg, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( bpg == NULL || fn == NULL ) { fprintf(stderr, "\n error in BPG_readFromFile(%p,%s)" "\n bad input\n", bpg, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in BPG_readFromFile(%p,%s)" "\n unable to open file %s", bpg, fn, fn) ; rc = 0 ; } else { rc = BPG_readFromBinaryFile(bpg, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in BPG_readFromFile(%p,%s)" "\n unable to open file %s", bpg, fn, fn) ; rc = 0 ; } else { rc = BPG_readFromFormattedFile(bpg, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in BPG_readFromFile(%p,%s)" "\n bad BPG file name %s," "\n must end in %s (binary) or %s (formatted)\n", bpg, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in BPG_readFromFile(%p,%s)" "\n bad BPG file name %s," "\n must end in %s (binary) or %s (formatted)\n", bpg, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to read a BPG object from a formatted file return value -- 1 if success, 0 if failure created -- 95oct06, cca -------------------------------------------------------- */ int BPG_readFromFormattedFile ( BPG *bpg, FILE *fp ) { Graph *graph ; int nX, nY, rc ; int itemp[2] ; /* --------------- check the input --------------- */ if ( bpg == NULL || fp == NULL ) { fprintf(stderr, "\n error in BPG_readFromFormattedFile(%p,%p)" "\n bad input\n", bpg, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ BPG_clearData(bpg) ; /* ----------------- read in nX and nY ----------------- */ if ( (rc = IVfscanf(fp, 2, itemp)) != 2 ) { fprintf(stderr, "\n error in BPG_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", bpg, fp, rc, 2) ; return(0) ; } nX = itemp[0] ; nY = itemp[1] ; /* -------------------------------------------------- create the Graph IVL object, then read in its data -------------------------------------------------- */ graph = Graph_new() ; Graph_setDefaultFields(graph) ; rc = Graph_readFromFormattedFile(graph, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n error in BPG_readFromFormattedFile(%p,%p)" "\n trying to read in Graph" "\n return code %d from Graph_readFormattedFile(%p,%p)", bpg, fp, rc, graph, fp) ; return(0) ; } /* --------------------- initialize the object --------------------- */ BPG_init(bpg, nX, nY, graph) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to read a BPG object from a binary file return value -- 1 if success, 0 if failure created -- 95oct06, cca ---------------------------------------------------- */ int BPG_readFromBinaryFile ( BPG *bpg, FILE *fp ) { Graph *graph ; int nX, nY, rc ; int itemp[2] ; /* --------------- check the input --------------- */ if ( bpg == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in BPG_readFromBinaryFile(%p,%p)" "\n bad input\n", bpg, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ BPG_clearData(bpg) ; /* -------------------------------------------- read in the two scalar parameters, nX and nY -------------------------------------------- */ if ( (rc = fread((void *) itemp, sizeof(int), 2, fp)) != 2 ) { fprintf(stderr, "\n error in BPG_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", bpg, fp, rc, 2) ; return(0) ; } nX = itemp[0] ; nY = itemp[1] ; /* ---------------------------------------------- create the Grapg object, then read in its data ---------------------------------------------- */ graph = Graph_new() ; Graph_setDefaultFields(graph) ; rc = Graph_readFromBinaryFile(graph, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n error in BPG_readFromBinaryFile(%p,%p)" "\n trying to read in Graph" "\n return code %d from Graph_readBinaryFile(%p,%p)", bpg, fp, rc, graph, fp) ; return(0) ; } /* --------------------- initialize the object --------------------- */ BPG_init(bpg, nX, nY, graph) ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to write a BPG object to a file input -- fn -- filename *.bpgb -- binary *.bpgf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95oct06, cca -------------------------------------------- */ int BPG_writeToFile ( BPG *bpg, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( bpg == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in BPG_writeToFile(%p,%s)" "\n bad input\n", bpg, fn) ; return(0) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in BPG_writeToFile(%p,%s)" "\n unable to open file %s", bpg, fn, fn) ; rc = 0 ; } else { rc = BPG_writeToBinaryFile(bpg, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in BPG_writeToFile(%p,%s)" "\n unable to open file %s", bpg, fn, fn) ; rc = 0 ; } else { rc = BPG_writeToFormattedFile(bpg, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in BPG_writeToFile(%p,%s)" "\n unable to open file %s", bpg, fn, fn) ; rc = 0 ; } else { rc = BPG_writeForHumanEye(bpg, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in BPG_writeToFile(%p,%s)" "\n unable to open file %s", bpg, fn, fn) ; rc = 0 ; } else { rc = BPG_writeForHumanEye(bpg, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to write a BPG object to a formatted file return value -- 1 if success, 0 otherwise created -- 95oct06, cca ------------------------------------------------------ */ int BPG_writeToFormattedFile ( BPG *bpg, FILE *fp ) { int ierr, rc ; /* --------------- check the input --------------- */ if ( bpg == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in BPG_writeToFormattedFile(%p,%p)" "\n bad input\n", bpg, fp) ; return(0) ; } /* ----------------------------------- write out the two scalar parameters ----------------------------------- */ rc = fprintf(fp, "\n %d %d", bpg->nX, bpg->nY) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in BPG_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", bpg, fp, rc) ; return(0) ; } /* ------------------- write out the graph ------------------- */ rc = Graph_writeToFormattedFile(bpg->graph, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in BPG_writeToFormattedFile(%p,%p)" "\n rc = %d, return from Graph_writeToFormattedFile(%p,%p)" "\n while attempting to write out graph\n", bpg, fp, rc, bpg->graph, fp) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to write a BPG object to a binary file return value -- 1 if success, 0 otherwise created -- 95oct06, cca --------------------------------------------------- */ int BPG_writeToBinaryFile ( BPG *bpg, FILE *fp ) { int rc ; int itemp[6] ; /* --------------- check the input --------------- */ if ( bpg == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in BPG_writeToBinaryFile(%p,%p)" "\n bad input\n", bpg, fp) ; return(0) ; } /* ----------------------------------- write out the two scalar parameters ----------------------------------- */ itemp[0] = bpg->nX ; itemp[1] = bpg->nY ; rc = fwrite((void *) itemp, sizeof(int), 6, fp) ; if ( rc != 6 ) { fprintf(stderr, "\n error in BPG_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", bpg, fp, rc, 6) ; return(0) ; } /* ------------------- write out the graph ------------------- */ rc = Graph_writeToBinaryFile(bpg->graph, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in BPG_writeToBinaryFile(%p,%p)" "\n rc = %d, return from Graph_writeToBinaryFile(%p,%p)" "\n while attempting to write out graph\n", bpg, fp, rc, bpg->graph, fp) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to write a BPG object for a human eye return value -- 1 if success, 0 otherwise created -- 95oct06, cca ------------------------------------------------- */ int BPG_writeForHumanEye ( BPG *bpg, FILE *fp ) { int ierr, rc ; if ( bpg == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in BPG_writeForHumanEye(%p,%p)" "\n bad input\n", bpg, fp) ; exit(-1) ; } /* ------------------------ write out the statistics ------------------------ */ if ( (rc = BPG_writeStats(bpg, fp)) == 0 ) { fprintf(stderr, "\n fatal error in BPG_writeForHumanEye(%p,%p)" "\n rc = %d, return from BPG_writeStats(%p,%p)\n", bpg, fp, rc, bpg, fp) ; return(0) ; } fflush(fp) ; if ( bpg->graph != NULL ) { /* -------------------------- write out the Graph object -------------------------- */ fprintf(fp, "\n\n Graph object") ; rc = Graph_writeForHumanEye(bpg->graph, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in BPG_writeForHumanEye(%p,%p)" "\n rc = %d, return from Graph_writeForHumanEye(%p,%p)" "\n while attempting to write out graph\n", bpg, fp, rc, bpg->graph, fp) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to write out the statistics for the BPG object return value -- 1 if success, 0 otherwise created -- 95oct06, cca ----------------------------------------------------------- */ int BPG_writeStats ( BPG *bpg, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( bpg == NULL || fp == NULL ) { fprintf(stderr, "\n error in BPG_writeStats(%p,%p)" "\n bad input\n", bpg, fp) ; exit(-1) ; } if ( bpg->graph == NULL ) { fprintf(stderr, "\n warning in BPG_writeStats(%p,%p)" "\n bpg->graph = NULL\n", bpg, fp) ; return(1) ; } switch ( bpg->graph->type ) { case 0 : rc = fprintf(fp, "\n BPG : unweighted bpg object :") ; break ; case 1 : rc = fprintf(fp, "\n BPG : vertices weighted bpg object :") ; break ; case 2 : rc = fprintf(fp, "\n BPG : edges weighted bpg object :") ; break ; case 3 : rc = fprintf(fp, "\n BPG : vertices and edges weighted bpg object :") ; break ; default : fprintf(stderr, "\n fatal error in BPG_writeStats(%p,%p)" "\n invalid bpg->g->type = %d\n", bpg, fp, bpg->graph->type) ; return(0) ; } if ( rc < 0 ) { goto IO_error ; } fflush(fp) ; rc = fprintf(fp, " nX = %d, nY = %d", bpg->nX, bpg->nY) ; if ( rc < 0 ) { goto IO_error ; } fflush(fp) ; if ( bpg->graph != NULL ) { if ( bpg->graph->vwghts != NULL ) { rc = fprintf(fp, ", |X| = %d, |Y| = %d", IVsum(bpg->nX, bpg->graph->vwghts), IVsum(bpg->nY, bpg->graph->vwghts + bpg->nX)) ; } else { rc = fprintf(fp, ", |X| = %d, |Y| = %d", bpg->nX, bpg->nY) ; } } if ( rc < 0 ) { goto IO_error ; } fflush(fp) ; return(1) ; IO_error : fprintf(stderr, "\n fatal error in BPG_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", bpg, fp, rc) ; return(0) ; } /*--------------------------------------------------------------------*/ - write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in BPG_writeToFile(%p,%s)" "\n unable to BPG/src/basics.c010064400020550007177000000053170654221321500147060ustar00clevecompmath00000400000006/* basics.c */ #include "../BPG.h" #define MYTRACE 0 #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- create and return a new BPG object created -- 95oct06, cca ----------------------------------------------- */ BPG * BPG_new ( void ) { BPG *bpg ; #if MYTRACE > 0 fprintf(stdout, "\n just inside BPG_new()") ; fflush(stdout) ; #endif ALLOCATE(bpg, struct _BPG, 1) ; BPG_setDefaultFields(bpg) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving BPG_new()") ; fflush(stdout) ; #endif return(bpg) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- set the default fields for the BPG object created -- 95oct06, cca ------------------------------------------------------ */ void BPG_setDefaultFields ( BPG *bpg ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside BPG_setDefaultFields(%)", bpg) ; fflush(stdout) ; #endif if ( bpg == NULL ) { fprintf(stderr, "\n fatal error in BPG_setDefaultFields(%p)" "\n bipartite graph is NULL\n", bpg) ; exit(-1) ; } bpg->nX = 0 ; bpg->nY = 0 ; bpg->graph = NULL ; #if MYTRACE > 0 fprintf(stdout, "\n leaving BPG_setDefaultFields(%)", bpg) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- clear the data fields created -- 95oct06, cca -------------------------------- */ void BPG_clearData ( BPG *bpg ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside BPG_clearData(%)", bpg) ; fflush(stdout) ; #endif if ( bpg == NULL ) { fprintf(stderr, "\n fatal error in BPG_clearData(%p)" "\n bipartite graph is NULL\n", bpg) ; exit(-1) ; } if ( bpg->graph != NULL ) { Graph_free(bpg->graph) ; } BPG_setDefaultFields(bpg) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving BPG_clearData(%)", bpg) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- free the BPG object created -- 95oct06, cca -------------------------------- */ void BPG_free ( BPG *bpg ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside BPG_free(%)", bpg) ; fflush(stdout) ; #endif if ( bpg == NULL ) { fprintf(stderr, "\n fatal error in BPG_free(%p)" "\n bipartite graph is NULL\n", bpg) ; exit(-1) ; } BPG_clearData(bpg) ; FREE(bpg) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving BPG_free(%)", bpg) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ BPG/src/init.c010064400020550007177000000223600653410612600144050ustar00clevecompmath00000400000006/* init.c */ #include "../BPG.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- initialize a BPG object, set bpg->nX = nX, bpg->nY = nY, and bpg->g = g. convert g into bipartite form, i.e., adj(v) := adj(v) \cap {nX, ..., nX + nY - 1} for v in [0, nX) adj(v) := adj(v) \cap {0, ..., nX - 1} for v in [nX, nX+nY) created -- 95oct06, cca -------------------------------------------------------------------- */ void BPG_init ( BPG *bpg, int nX, int nY, Graph *graph ) { int ierr, ii, jj, v, vsize, w ; int *vadj ; IVL *adjIVL ; /* --------------- check the input --------------- */ if ( bpg == NULL || nX <= 0 || nY <= 0 || graph == NULL ) { fprintf(stderr, "\n fatal error in BPG_init(%p,%d,%d,%p)" "\n bad input\n", bpg, nX, nY, graph) ; exit(-1) ; } /* -------------- set the fields -------------- */ BPG_clearData(bpg) ; bpg->nX = nX ; bpg->nY = nY ; bpg->graph = graph ; /* ------------------------------------ work on the graph's adjacency lists, enforcing the bipartite property ------------------------------------ */ adjIVL = graph->adjIVL ; for ( v = 0 ; v < nX ; v++ ) { IVL_listAndSize(adjIVL, v, &vsize, &vadj) ; #if MYDEBUG > 0 fprintf(stdout, "\n old %d : ", v) ; IVfp80(stdout, vsize, vadj, 10, &ierr) ; fflush(stdout) ; #endif ii = 0, jj = vsize - 1 ; while ( ii <= jj ) { w = vadj[ii] ; if ( nX <= w && w < nX + nY ) { ii++ ; } else { vadj[ii] = vadj[jj] ; vadj[jj] = w ; jj-- ; } } vsize = ii ; #if MYDEBUG > 0 fprintf(stdout, "\n new %d : ", v) ; IVfp80(stdout, vsize, vadj, 10, &ierr) ; fflush(stdout) ; #endif IVL_setList(adjIVL, v, vsize, NULL) ; } for ( v = nX ; v < nX + nY ; v++ ) { IVL_listAndSize(adjIVL, v, &vsize, &vadj) ; #if MYDEBUG > 0 fprintf(stdout, "\n old %d : ", v) ; IVfp80(stdout, vsize, vadj, 10, &ierr) ; fflush(stdout) ; #endif ii = 0, jj = vsize - 1 ; while ( ii <= jj ) { w = vadj[ii] ; if ( 0 <= w && w < nX ) { ii++ ; } else { vadj[ii] = vadj[jj] ; vadj[jj] = w ; jj-- ; } } vsize = ii ; IVL_setList(adjIVL, v, vsize, NULL) ; #if MYDEBUG > 0 fprintf(stdout, "\n new %d : ", v) ; IVfp80(stdout, vsize, vadj, 10, &ierr) ; fflush(stdout) ; #endif } return ; } /*--------------------------------------------------------------------*/ #define MYDEBUG 0 /* ----------------------------------------------------------- initialize from a graph given a color vector and two target vectors. this method can be used to get the bipartite graph of the boundary of two components. graph -- graph from which to extract the bipartite graph colors -- vector of colors for the vertices cX -- color for the X vertices cY -- color for the Y vertices cmap -- map from vertices in g to vertices in bpg indX -- vector to hold the global indices in X indY -- vector to hold the global indices in Y created -- 95oct06, cca ----------------------------------------------------------- */ void BPG_initFromColoring ( BPG *bpg, Graph *graph, int colors[], int cX, int cY, int cmap[], int indX[], int indY[] ) { Graph *bpg_g ; int count, ierr, ii, iX, iy, msize, nV, nX, nY, v, vsize, w, x, y ; int *ewghts, *list, *vadj, *vewghts ; /* --------------- check the input --------------- */ if ( bpg == NULL || graph == NULL || colors == NULL || cX < 0 || cY < 0 || cX == cY || cmap == NULL ) { fprintf(stderr, "\n fatal error in BPG_initFromColoring(%p,%p,%p,%d,%d,%p)" "\n bad input\n", bpg, graph, colors, cX, cY, cmap) ; exit(-1) ; } BPG_clearData(bpg) ; nV = graph->nvtx ; IVfill(nV, cmap, -1) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n just inside BPG_initFromColoring(%p,%p,%p,%d,%d,%p)", bpg, graph, colors, cX, cY, cmap) ; fflush(stdout) ; #endif /* ------------------ get the X vertices ------------------ */ for ( v = 0, nX = 0 ; v < nV ; v++ ) { if ( colors[v] == cX ) { indX[nX] = v ; cmap[v] = nX++ ; } } /* ---------------------------------------------------- now get Y = {v | v \in \bnd{X} and colors[v] == cY } ---------------------------------------------------- */ nY = 0 ; for ( iX = 0 ; iX < nX ; iX++ ) { v = indX[iX] ; Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { if ( (w = vadj[ii]) < nV && colors[w] == cY && cmap[w] == -1 ) { indY[nY] = w ; cmap[w] = nX + nY++ ; } } } bpg->nX = nX ; bpg->nY = nY ; #if MYDEBUG > 0 fprintf(stdout, "\n indX(%d) :", nX) ; IVfp80(stdout, nX, indX, 15, &ierr) ; fprintf(stdout, "\n indY(%d) :", nY) ; IVfp80(stdout, nY, indY, 15, &ierr) ; fflush(stdout) ; #endif #if MYDEBUG > 1 fprintf(stdout, "\n cmap(%d) :", g->nvtx) ; IVfp80(stdout, graph->nvtx, cmap, 15, &ierr) ; fflush(stdout) ; #endif if ( bpg->nX == 0 || bpg->nY == 0 ) { fprintf(stderr, "\n fatal error in BPG_initFromColoring" "\n nX = %d, nY = %d", nX, nY) ; fprintf(stderr, "\n colors") ; IVfp80(stderr, nV, colors, 80, &ierr) ; fprintf(stderr, "\n graph") ; Graph_writeForHumanEye(graph, stderr) ; exit(-1) ; } /* -------------------------------------- initialize the bipartite graph's graph -------------------------------------- */ bpg->graph = bpg_g = Graph_new() ; Graph_init1(bpg_g, graph->type, nX + nY, 0, 0, IVL_CHUNKED, IVL_CHUNKED) ; /* ------------------------------------- set the vertex weights if appropriate ------------------------------------- */ if ( graph->type % 2 == 1 ) { for ( x = 0 ; x < nX ; x++ ) { v = indX[x] ; bpg_g->vwghts[x] = graph->vwghts[v] ; } for ( iy = 0, y = nX ; iy < nY ; iy++, y++ ) { v = indY[iy] ; bpg_g->vwghts[y] = graph->vwghts[v] ; } bpg_g->totvwght = IVsum(nX + nY, bpg_g->vwghts) ; #if MYDEBUG > 0 fprintf(stdout, "\n vertex weights for X") ; IVfp80(stdout, nX, bpg_g->vwghts, 80, &ierr) ; fprintf(stdout, "\n vertex weights for Y") ; IVfp80(stdout, nY, bpg_g->vwghts + nX, 80, &ierr) ; fprintf(stdout, "\n w(X) = %d", IVsum(nX, bpg_g->vwghts)) ; fprintf(stdout, "\n w(Y) = %d", IVsum(nY, bpg_g->vwghts + nX)) ; fflush(stdout) ; #endif } /* ----------------------------------------------- set the adjacency or adjacency and edge weights ----------------------------------------------- */ if ( graph->type < 2 ) { /* ------------------------------- adjacency only, no edge weights ------------------------------- */ msize = IVL_maxListSize(graph->adjIVL) ; list = IVinit2(msize) ; for ( x = 0 ; x < nX ; x++ ) { v = indX[x] ; Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0, count = 0 ; ii < vsize ; ii++ ) { if ( (w = vadj[ii]) < nV && colors[w] == cY ) { list[count++] = cmap[w] ; } } IVqsortUp(count, list) ; IVL_setList(bpg_g->adjIVL, x, count, list) ; #if MYDEBUG > 0 fprintf(stdout, "\n setting x (%d) list %d : ", x, indX[x]) ; IVfp80(stdout, count, list, 20, &ierr) ; fflush(stdout) ; #endif } for ( iy = 0, y = nX ; iy < nY ; iy++, y++ ) { v = indY[iy] ; Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0, count = 0 ; ii < vsize ; ii++ ) { if ( (w = vadj[ii]) < nV && colors[w] == cX ) { list[count++] = cmap[w] ; } } IVqsortUp(count, list) ; IVL_setList(bpg_g->adjIVL, y, count, list) ; #if MYDEBUG > 0 fprintf(stdout, "\n setting y (%d) list %d : ", y, indY[iy]) ; IVfp80(stdout, count, list, 20, &ierr) ; fflush(stdout) ; #endif } IVfree(list) ; } else { /* -------------------------- adjacency and edge weights -------------------------- */ msize = IVL_maxListSize(graph->adjIVL) ; list = IVinit2(msize) ; ewghts = IVinit2(msize) ; for ( x = 0 ; x < nX ; x++ ) { v = indX[x] ; Graph_adjAndEweights(graph, v, &vsize, &vadj, &vewghts) ; for ( ii = 0, count = 0 ; ii < vsize ; ii++ ) { if ( (w = vadj[ii]) < nV && colors[w] == cY ) { list[count] = cmap[w] ; ewghts[count] = vewghts[ii] ; count++ ; } } IV2qsortUp(count, list, ewghts) ; IVL_setList(bpg_g->adjIVL, x, count, list) ; IVL_setList(bpg_g->ewghtIVL, x, count, ewghts) ; } for ( iy = 0, y = nX ; iy < nY ; iy++, y++ ) { v = indY[iy] ; Graph_adjAndEweights(graph, v, &vsize, &vadj, &vewghts) ; for ( ii = 0, count = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( colors[w] == cX ) { list[count] = cmap[w] ; ewghts[count] = vewghts[ii] ; count++ ; } } IV2qsortUp(count, list, ewghts) ; IVL_setList(bpg_g->adjIVL, y, count, list) ; IVL_setList(bpg_g->ewghtIVL, y, count, ewghts) ; } IVfree(list) ; IVfree(ewghts) ; } bpg_g->nedges = IVsum(nX + nY, graph->adjIVL->sizes) ; return ; } /*--------------------------------------------------------------------*/ BPG/src/makeGraphs.c010064400020550007177000000100770653410612600155260ustar00clevecompmath00000400000006/* makeGraphXbyX.c */ #include "../BPG.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- return the X by X graph where (x1,x2) is an edge if there exists a y in Y such that (x1,y) and (x2,y) are edges in the bipartite graph. created -- 95dec06, cca to be used in the BKL object. ----------------------------------------------------------- */ Graph * BPG_makeGraphXbyX ( BPG *bpg ) { Graph *graph, *gXbyX ; int count, ii, jj, nX, x, xsize, y, ysize, z ; int *list, *mark, *xadj, *yadj ; /* --------------- check the input --------------- */ if ( bpg == NULL ) { fprintf(stdout, "\n fatal error in BPG_makeGraphXbyX(%p)" "\n bad input\n", bpg) ; exit(-1) ; } /* ---------------------- check for quick return ---------------------- */ if ( (graph = bpg->graph) == NULL || (nX = bpg->nX) <= 0 ) { return(NULL) ; } /* -------------------- initialize the graph -------------------- */ gXbyX = Graph_new() ; Graph_init1(gXbyX, graph->type, nX, 0, 0, IVL_CHUNKED, IVL_CHUNKED) ; /* -------------- fill the graph -------------- */ mark = IVinit(nX, -1) ; list = IVinit(nX, -1) ; for ( x = 0 ; x < nX ; x++ ) { Graph_adjAndSize(graph, x, &xsize, &xadj) ; mark[x] = x ; for ( ii = 0, count = 0 ; ii < xsize ; ii++ ) { y = xadj[ii] ; Graph_adjAndSize(graph, y, &ysize, &yadj) ; for ( jj = 0 ; jj < ysize ; jj++ ) { z = yadj[jj] ; if ( mark[z] != x ) { mark[z] = x ; list[count++] = z ; } } } if ( count > 0 ) { IVqsortUp(count, list) ; IVL_setList(gXbyX->adjIVL, x, count, list) ; } } IVfree(list) ; IVfree(mark) ; /* --------------------------------------- set vertex weight vector if appropriate --------------------------------------- */ if ( graph->type % 2 == 1 ) { IVcopy(nX, gXbyX->vwghts, graph->vwghts) ; } return(gXbyX) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- return the Y by Y graph where (y1,y2) is an edge if there exists a x in X such that (x,y1) and (x,y2) are edges in the bipartite graph. created -- 95dec07, cca ----------------------------------------------------------- */ Graph * BPG_makeGraphYbyY ( BPG *bpg ) { Graph *graph, *gYbyY ; int count, ii, jj, nX, nY, x, xsize, y, ysize, z ; int *list, *mark, *xadj, *yadj ; /* --------------- check the input --------------- */ if ( bpg == NULL ) { fprintf(stdout, "\n fatal error in BPG_makeGraphXbyX(%p)" "\n bad input\n", bpg) ; exit(-1) ; } /* ---------------------- check for quick return ---------------------- */ if ( (graph = bpg->graph) == NULL || (nY = bpg->nY) <= 0 ) { return(NULL) ; } nX = bpg->nX ; /* -------------------- initialize the graph -------------------- */ gYbyY = Graph_new() ; Graph_init1(gYbyY, graph->type, nY, 0, 0, IVL_CHUNKED, IVL_CHUNKED) ; /* -------------- fill the graph -------------- */ mark = IVinit(nY, -1) ; list = IVinit(nY, -1) ; for ( y = 0 ; y < nY ; y++ ) { Graph_adjAndSize(graph, nX + y, &ysize, &yadj) ; mark[y] = y ; for ( ii = 0, count = 0 ; ii < ysize ; ii++ ) { x = yadj[ii] ; Graph_adjAndSize(graph, x, &xsize, &xadj) ; for ( jj = 0 ; jj < xsize ; jj++ ) { z = xadj[jj] ; if ( mark[z] != y ) { mark[z] = y ; list[count++] = z ; } } } if ( count > 0 ) { IVqsortUp(count, list) ; IVL_setList(gYbyY->adjIVL, nX + y, count, list) ; } } IVfree(list) ; IVfree(mark) ; /* --------------------------------------- set vertex weight vector if appropriate --------------------------------------- */ if ( graph->type % 2 == 1 ) { IVcopy(nY, gYbyY->vwghts, graph->vwghts + nX) ; } return(gYbyY) ; } /*--------------------------------------------------------------------*/ BPG/src/maxFlow.c010064400020550007177000000507710653410612600150660ustar00clevecompmath00000400000006/* maxFlow.c */ #include "../BPG.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------- a Cell structure represent an edge (x,y) rxy -- residual for edge fxy -- flow for edge xnext -- next Cell in list for x ynext -- next Cell in list for y ---------------------------------------- */ typedef struct _Cell Cell ; struct _Cell { int x ; int y ; int rxy ; int fxy ; Cell *xnext ; Cell *ynext ; } ; /*--------------------------------------------------------------------*/ /* ----------------- static prototypes ----------------- */ static void setupCells(BPG *bpg, Cell ***pheads, Cell **pcells, int msglvl, FILE *msgFile) ; static int findFlowAugmentingPath(BPG *bpg, Cell *heads[], int xexp, int exp[], int par[], int labels[], int list[], int mark[], int tag, int msglvl, FILE *msgFile) ; static void augmentPath(BPG *bpg, int xexp, int yexp, int nvexp[], Cell *heads[], int labels[], int par[], int msglvl, FILE *msgFile) ; static void setDMflags(BPG *bpg, Cell *heads[], int nvexp[], int list[], int mark[], int dmflags[], int stats[], int msglvl, FILE *msgFile) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- find the DM decomposition of a weighted bipartite graph using a simple max flow algorithm bpg -- BPG bipartite graph object dmflags -- flags vector / 0 if x in X_R dmflags[x] = | 1 if x in X_I \ 2 if x in X_E / 0 if y in Y_R dmflags[y] = | 1 if y in Y_I \ 2 if y in Y_E stats -- statistics vector stats[0] -- weight of X_I stats[1] -- weight of X_E stats[2] -- weight of X_R stats[3] -- weight of Y_I stats[4] -- weight of Y_E stats[5] -- weight of Y_R created -- 96mar08, cca ------------------------------------------------------- */ void BPG_DMviaMaxFlow ( BPG *bpg, int dmflags[], int stats[], int msglvl, FILE *msgFile ) { int ierr, nX, nY, tag, x, xexp, y, yexp ; int *labels, *list, *mark, *nvexp, *par, *vwghts ; Cell *cell, *cells ; Cell **heads ; /* --------------- check the input --------------- */ if ( bpg == NULL || dmflags == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in BPG_DMviaMaxFlow(%p,%p,%p,%d,%p)" "\n bad input\n", bpg, dmflags, stats, msglvl, msgFile) ; exit(-1) ; } nX = bpg->nX ; nY = bpg->nY ; /* --------------------------------------------- set up the Cell structures and working arrays --------------------------------------------- */ setupCells(bpg, &heads, &cells, msglvl, msgFile) ; nvexp = IVinit(nX + nY, 1) ; if ( (vwghts = bpg->graph->vwghts) != NULL ) { IVcopy(nX + nY, nvexp, vwghts) ; } list = IVinit(nX + nY, -1) ; mark = IVinit(nX + nY, -1) ; par = IVinit(nX + nY, -1) ; labels = IVinit(nX + nY, -1) ; /* ------------------------ loop over the x vertices ------------------------ */ tag = 0 ; for ( xexp = 0 ; xexp < nX ; xexp++ ) { if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n checking out x node %d, exposure %d", xexp, nvexp[xexp]) ; } while ( nvexp[xexp] > 0 ) { yexp = findFlowAugmentingPath(bpg, heads, xexp, nvexp, par, labels, list, mark, tag, msglvl, msgFile) ; tag++ ; if ( yexp == -1 ) { /* ------------------------------------------------------- no flow augmenting path has been found, node is exposed ------------------------------------------------------- */ if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n node %d has exposure %d", xexp, nvexp[xexp]) ; } break ; } else { /* ---------------------------------------- flow augmenting path found, augment path ---------------------------------------- */ augmentPath(bpg, xexp, yexp, nvexp, heads, labels, par, msglvl, msgFile) ; } } } if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n after maximum flow found") ; for ( x = 0 ; x < nX ; x++ ) { fprintf(msgFile, "\n X node %d : ", x) ; for ( cell = heads[x] ; cell != NULL ; cell = cell->xnext ) { fprintf(msgFile, "\n (%3d,%3d,%3d)", cell->y, cell->fxy, cell->rxy) ; } } for ( y = nX ; y < nX + nY ; y++ ) { fprintf(msgFile, "\n Y node %d : ", y) ; for ( cell = heads[y] ; cell != NULL ; cell = cell->ynext ) { fprintf(msgFile, "\n (%3d,%3d,%3d)", cell->x, cell->fxy, cell->rxy) ; } } } /* ---------------- set the DM flags ---------------- */ setDMflags(bpg, heads, nvexp, list, mark, dmflags, stats, msglvl, msgFile) ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n X dmflags: ") ; IVfp80(msgFile, nX, dmflags, 12, &ierr) ; fprintf(msgFile, "\n Y dmflags: ") ; IVfp80(msgFile, nY, dmflags + nX, 12, &ierr) ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ IVfree(nvexp) ; IVfree(list) ; IVfree(mark) ; IVfree(par) ; IVfree(labels) ; FREE(heads) ; FREE(cells) ; return ; } /*--------------------------------------------------------------------*/ /* ------------ set up cells ------------ */ static void setupCells ( BPG *bpg, Cell ***pheads, Cell **pcells, int msglvl, FILE *msgFile ) { Cell *cell, *cells ; Cell **heads ; Graph *graph ; int ii, ncell, nX, nY, x, xsize, y ; int *vwghts, *xadj ; /* ------------------------- count the number of cells ------------------------- */ nX = bpg->nX ; nY = bpg->nY ; graph = bpg->graph ; ncell = 0 ; for ( x = 0 ; x < nX ; x++ ) { Graph_adjAndSize(graph, x, &xsize, &xadj) ; ncell += xsize ; } if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n %d cells required", ncell) ; fflush(msgFile) ; } /* ------------------------------------------------ allocate the storage and set pointers for return ------------------------------------------------ */ ALLOCATE(cells, struct _Cell, ncell) ; ALLOCATE(heads, struct _Cell *, nX + nY) ; *pcells = cells ; *pheads = heads ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n cells = %p", cells) ; fflush(msgFile) ; } for ( ii = 0 ; ii < nX + nY ; ii++ ) { heads[ii] = NULL ; } /* ---------------------------------- set the vertex fields of the cells ---------------------------------- */ for ( x = 0, cell = cells ; x < nX ; x++ ) { Graph_adjAndSize(graph, x, &xsize, &xadj) ; for ( ii = 0 ; ii < xsize ; ii++, cell++ ) { y = xadj[ii] ; cell->x = x ; cell->y = y ; } } /* -------------------------------- set the link fields of the cells -------------------------------- */ for ( ii = 0, cell = cells ; ii < ncell ; ii++, cell++ ) { x = cell->x ; cell->xnext = heads[x] ; heads[x] = cell ; y = cell->y ; cell->ynext = heads[y] ; heads[y] = cell ; } /* --------------------------------------------- set the residual and flow fields of the cells --------------------------------------------- */ if ( (vwghts = graph->vwghts) == NULL ) { for ( ii = 0, cell = cells ; ii < ncell ; ii++, cell++ ) { cell->rxy = 1 ; cell->fxy = 0 ; } } else { for ( ii = 0, cell = cells ; ii < ncell ; ii++, cell++ ) { x = cell->x ; y = cell->y ; cell->rxy = (vwghts[x] < vwghts[y]) ? vwghts[x] : vwghts[y] ; cell->fxy = 0 ; } } if ( msglvl > 2 && msgFile != NULL ) { for ( ii = 0, cell = cells ; ii < ncell ; ii++, cell++ ) { fprintf(msgFile, "\n cell %d, address %p : (x,y) = (%3d,%3d), r = %d, f = %d", ii, cell, cell->x, cell->y, cell->rxy, cell->fxy) ; } fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- search for a flow augmenting path starting at xexp created -- 96mar08, cca -------------------------------------------------- */ static int findFlowAugmentingPath ( BPG *bpg, Cell *heads[], int xexp, int exp[], int par[], int labels[], int list[], int mark[], int tag, int msglvl, FILE *msgFile ) { Cell *cell ; Graph *graph ; int last, now, nX, x, y ; /* --------------------------- get dimensions and pointers --------------------------- */ nX = bpg->nX ; graph = bpg->graph ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n FIND AUGMENTING PATH FOR NODE %d", xexp) ; fflush(msgFile) ; } /* ----------------------------------- mark the exposed node with the tag, label with its exposure, and put into the list for traversal ----------------------------------- */ mark[xexp] = tag ; list[0] = xexp ; labels[xexp] = exp[xexp] ; par[xexp] = -1 ; now = last = 0 ; while ( now <= last ) { /* ------------------------------- check out next node on the list ------------------------------- */ if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n list[%d] = %d", now, list[now]) ; fflush(msgFile) ; } if ( list[now] < nX ) { x = list[now++] ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, ", X node %d", x) ; fflush(msgFile) ; } for ( cell = heads[x] ; cell != NULL ; cell = cell->xnext ) { y = cell->y ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n adjacent Y node %d, mark %d, r %d", y, mark[y], cell->rxy) ; fflush(msgFile) ; } if ( mark[y] != tag && cell->rxy > 0 ) { /* ---------------------------------------------------------- y has not yet been visited and edge (x,y) is not saturated ---------------------------------------------------------- */ mark[y] = tag ; par[y] = x ; if ( labels[x] < cell->rxy ) { labels[y] = labels[x] ; } else { labels[y] = cell->rxy ; } if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, ", label = %d", labels[y]) ; fflush(msgFile) ; } if ( exp[y] > 0 ) { /* ---------------------------------- y is exposed, set label and return ---------------------------------- */ if ( labels[y] > exp[y] ) { labels[y] = exp[y] ; } if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n Y node %d is exposed, label = %d", y,labels[y]) ; fflush(msgFile) ; } return(y) ; } list[++last] = y ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, ", adding to list") ; fflush(msgFile) ; } } } } else { y = list[now++] ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, ", Y node %d", y) ; fflush(msgFile) ; } for ( cell = heads[y] ; cell != NULL ; cell = cell->ynext ) { x = cell->x ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n adjacent X node %d, mark %d, f %d", x, mark[x], cell->fxy) ; fflush(msgFile) ; } if ( mark[x] != tag && cell->fxy > 0 ) { /* -------------------------------------------------------- x has not yet been visited and there is flow from x to y -------------------------------------------------------- */ mark[x] = tag ; par[x] = y ; if ( labels[y] < cell->fxy ) { labels[x] = labels[y] ; } else { labels[x] = cell->fxy ; } if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, ", labels = %d", labels[x]) ; fflush(msgFile) ; } list[++last] = x ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, ", adding to list") ; fflush(msgFile) ; } } } } } return(-1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- given an augmenting path starting with xexp and ending with yexp, augment the path by the amount in labels[yexp] 96mar08, cca ----------------------------------------------------------------- */ static void augmentPath ( BPG *bpg, int xexp, int yexp, int nvexp[], Cell *heads[], int labels[], int par[], int msglvl, FILE *msgFile ) { Cell *cell ; int delta, x, y ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n AUGMENT PATH FOR NODE %d", xexp) ; fflush(msgFile) ; } /* --------------------------- start at the exposed y node --------------------------- */ delta = labels[yexp] ; y = yexp ; while ( 1 ) { x = par[y] ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n (x,y) = (%3d, %3d)", x, y) ; fflush(msgFile) ; } for ( cell = heads[y] ; cell != NULL ; cell = cell->ynext ) { if ( cell->x == x ) { cell->rxy -= delta ; cell->fxy += delta ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, ", r = %d, f = %d", cell->rxy, cell->fxy) ; fflush(msgFile) ; } break ; } } if ( cell == NULL ) { fprintf(stderr, "\n 1. error, x = %d, y = %d", x, y) ; exit(-1) ; } if ( x == xexp ) { break ; } y = par[x] ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n (x,y) = (%3d, %3d)", x, y) ; fflush(msgFile) ; } for ( cell = heads[x] ; cell != NULL ; cell = cell->xnext ) { if ( cell->y == y ) { cell->rxy += delta ; cell->fxy -= delta ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, ", r = %d, f = %d", cell->rxy, cell->fxy) ; fflush(msgFile) ; } break ; } } if ( cell == NULL ) { fprintf(stderr, "\n 2. error, x = %d, y = %d", x, y) ; exit(-1) ; } } nvexp[xexp] -= delta ; nvexp[yexp] -= delta ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- set the flags for the DM decomposition created -- 96mar08, cca -------------------------------------- */ static void setDMflags ( BPG *bpg, Cell *heads[], int nvexp[], int list[], int mark[], int dmflags[], int stats[], int msglvl, FILE *msgFile ) { Cell *cell ; int ierr, last, now, nX, nY, x, xwght, y, ywght ; int *vwghts ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n SET DM FLAGS") ; fflush(msgFile) ; } nX = bpg->nX ; nY = bpg->nY ; IVfill(nX + nY, dmflags, 0) ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n nvexp : ") ; IVfp80(msgFile, nX + nY, nvexp, 20, &ierr) ; fflush(msgFile) ; } /* ----------------------- load exposed nodes in X ----------------------- */ IVzero(nX + nY, mark) ; last = -1 ; for ( x = 0 ; x < nX ; x++ ) { if ( nvexp[x] > 0 ) { if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n X node %d is exposed", x) ; fflush(msgFile) ; } mark[x] = 1 ; list[++last] = x ; dmflags[x] = 1 ; } } if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n %d exposed X nodes :", last + 1) ; IVfp80(msgFile, 1 + last, list, 20, &ierr) ; fflush(msgFile) ; } /* --------------------------------------------------------------- drop an alternating level structure from the exposed nodes in X --------------------------------------------------------------- */ now = 0 ; while ( now <= last ) { if ( list[now] < nX ) { x = list[now++] ; dmflags[x] = 1 ; for ( cell = heads[x] ; cell != NULL ; cell = cell->xnext ) { y = cell->y ; /* if ( mark[y] != 1 && cell->rxy > 0 ) { */ if ( mark[y] != 1 ) { mark[y] = 1 ; list[++last] = y ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n adding Y node %d", y) ; fflush(msgFile) ; } } } } else { y = list[now++] ; dmflags[y] = 2 ; for ( cell = heads[y] ; cell != NULL ; cell = cell->ynext ) { x = cell->x ; if ( mark[x] != 1 && cell->fxy > 0 ) { mark[x] = 1 ; list[++last] = x ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n adding X node %d", x) ; fflush(msgFile) ; } } } } } /* ----------------------- load exposed nodes in Y ----------------------- */ IVzero(nX + nY, mark) ; last = -1 ; for ( y = nX ; y < nX + nY ; y++ ) { if ( nvexp[y] > 0 ) { if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n Y node %d is exposed", y) ; fflush(msgFile) ; } mark[y] = 1 ; list[++last] = y ; dmflags[y] = 1 ; } } if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n %d exposed Y nodes :", last + 1) ; IVfp80(msgFile, 1 + last, list, 20, &ierr) ; fflush(msgFile) ; } /* --------------------------------------------------------------- drop an alternating level structure from the exposed nodes in Y --------------------------------------------------------------- */ now = 0 ; while ( now <= last ) { if ( list[now] < nX ) { x = list[now++] ; dmflags[x] = 2 ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n checking out X node %d", x) ; fflush(msgFile) ; } for ( cell = heads[x] ; cell != NULL ; cell = cell->xnext ) { y = cell->y ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n adjacent Y node %d, mark %d, f %d", y, mark[y], cell->fxy) ; fflush(msgFile) ; } if ( mark[y] != 1 && cell->fxy > 0 ) { mark[y] = 1 ; list[++last] = y ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, ", adding ") ; fflush(msgFile) ; } } } } else { y = list[now++] ; dmflags[y] = 1 ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n checking out Y node %d", y) ; fflush(msgFile) ; } for ( cell = heads[y] ; cell != NULL ; cell = cell->ynext ) { x = cell->x ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n adjacent X node %d, mark %d, r %d", x, mark[x], cell->rxy) ; fflush(msgFile) ; } /* if ( mark[x] != 1 && cell->rxy > 0 ) { */ if ( mark[x] != 1 ) { mark[x] = 1 ; list[++last] = x ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, ", adding") ; fflush(msgFile) ; } } } } } /* -------------------------- fill the statistics vector -------------------------- */ IVzero(6, stats) ; vwghts = bpg->graph->vwghts ; for ( x = 0 ; x < nX ; x++ ) { xwght = (vwghts != NULL) ? vwghts[x] : 1 ; switch ( dmflags[x] ) { case 0 : stats[2] += xwght ; break ; case 1 : stats[0] += xwght ; break ; case 2 : stats[1] += xwght ; break ; default : fprintf(stderr, "\n fatal error in BPG_DMviaMaxFlow" "\n dmflags[%d] = %d\n", x, dmflags[x]) ; exit(-1) ; } } for ( y = nX ; y < nX + nY ; y++ ) { ywght = (vwghts != NULL) ? vwghts[y] : 1 ; switch ( dmflags[y] ) { case 0 : stats[5] += ywght ; break ; case 1 : stats[3] += ywght ; break ; case 2 : stats[4] += ywght ; break ; default : fprintf(stderr, "\n fatal error in BPG_DMviaMaxFlow" "\n dmflags[%d] = %d\n", y, dmflags[y]) ; exit(-1) ; } } return ; } /*--------------------------------------------------------------------*/ BPG/src/pseudo.c010064400020550007177000000076370653410612700147540ustar00clevecompmath00000400000006/* pseudo.c */ #include "../BPG.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------ return a pseudoperipheral node created -- 95oct07, cca ------------------------------ */ int BPG_pseudoperipheralnode ( BPG *bpg, int seed ) { int last, mate, oldrad, rad, root, tag ; int *dist, *list, *mark ; /* --------------- check the input --------------- */ if ( bpg == NULL ) { fprintf(stderr, "\n fatal error in BPG_pseudoperipheralnode(%p,%d)" "\n bad input\n", bpg, seed) ; exit(-1) ; } if ( seed < 0 ) { seed = - seed ; } seed = seed % (bpg->nX + bpg->nY) ; list = IVinit(bpg->nX + bpg->nY, -1) ; dist = IVinit(bpg->nX + bpg->nY, -1) ; mark = IVinit(bpg->nX + bpg->nY, -1) ; oldrad = 0 ; /* ------------------------------------------- drop a level structure from the seed vertex ------------------------------------------- */ tag = 1 ; last = BPG_levelStructure(bpg, seed, list, dist, mark, tag) ; mate = list[last] ; rad = dist[mate] ; #if MYDEBUG > 0 fprintf(stdout, "\n BPG_pseudoperipheralnode") ; fprintf(stdout, "\n node %d, mate %d, rad %d", seed, mate, rad) ; fflush(stdout) ; #endif /* ----------------------------------------------- loop while vertex with a larger radius is found ----------------------------------------------- */ while ( oldrad < rad ) { oldrad = rad ; root = mate ; tag++ ; last = BPG_levelStructure(bpg, root, list, dist, mark, tag) ; mate = list[last] ; rad = dist[mate] ; #if MYDEBUG > 0 fprintf(stdout, "\n node %d, mate %d, rad %d", root, mate, rad) ; fflush(stdout) ; #endif } #if MYDEBUG > 1 { int root ; for ( root = 0, tag++ ; root < bpg->nX ; root++, tag++ ) { last = BPG_levelStructure(bpg, root, list, dist, mark, tag) ; mate = list[last] ; rad = dist[mate] ; fprintf(stdout, "\n node %d, mate %d, rad %d", root, mate, rad) ; fflush(stdout) ; } } #endif /* ------------------------ free the working storage ------------------------ */ IVfree(list) ; IVfree(dist) ; IVfree(mark) ; return(root) ; } /*--------------------------------------------------------------------*/ #define MYDEBUG 0 /* ---------------------------------------------------- return value -- # of vertices in the level structure created -- 95oct07, cca ---------------------------------------------------- */ int BPG_levelStructure ( BPG *bpg, int root, int list[], int dist[], int mark[], int tag ) { int ii, jj, last, now, u, usize, v, vsize, w ; int *uadj, *vadj ; /* --------------- check the input --------------- */ if ( bpg == NULL || root < 0 || root >= bpg->nX + bpg->nY || list == NULL || dist == NULL || mark == NULL ) { fprintf(stderr, "\n fatal error in BPG_levelStructure(%p,%d,%p,%p,%p,%d)" "\n bad input\n", bpg, root, list, dist, mark, tag) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n inside BPG_levelStructure(%p,%d,%p,%p,%p,%d)", bpg, root, list, dist, mark, tag) ; fflush(stdout) ; #endif now = last = 0 ; list[0] = root ; dist[root] = 0 ; mark[root] = tag ; while ( now <= last ) { u = list[now++] ; #if MYDEBUG > 0 fprintf(stdout, "\n u = %d", u) ; fflush(stdout) ; #endif Graph_adjAndSize(bpg->graph, u, &usize, &uadj) ; for ( ii = 0 ; ii < usize ; ii++ ) { v = uadj[ii] ; Graph_adjAndSize(bpg->graph, v, &vsize, &vadj) ; for ( jj = 0 ; jj < vsize ; jj++ ) { w = vadj[jj] ; #if MYDEBUG > 0 fprintf(stdout, "\n w = %d", w) ; #endif if ( mark[w] != tag ) { #if MYDEBUG > 0 fprintf(stdout, ", adding to list, dist = %d", dist[u] + 1); fflush(stdout) ; #endif mark[w] = tag ; list[++last] = w ; dist[w] = dist[u] + 1 ; } } } } return(last) ; } /*--------------------------------------------------------------------*/ -------- check the input --------------- */ if ( bpg == NULL ) { fprintf(stderr, "\n fatBPG/drivers/doDM010075500020550007177000000005070654275531500147460ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = BCSSTK24 set msglvl = 1 set msgFile = stdout foreach icomp ( 1 2 ) echo ' matrix = ' $matrix set inBPGfile = $matrices/$matrix/sep$icomp.bpgf set msgFile = stats.$matrix set msgFile = stdout testDM $msglvl $msgFile $inBPGfile end BPG/drivers/doExtractBPG010075500020550007177000000014400654275533300164060ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = BCSSTK24 set inGraphFile = $matrices/$matrix/orig1.graphf set inCompidsIVfile = $matrices/$matrix/bkl.ivf set msglvl = 5 set msgFile = stdout set firstseed = 1 set lastseed = 2 set lastseed = 21 set lastseed = 6 set lastseed = 51 set lastseed = 11 set lastseed = 1 set alpha = 1.0 foreach icomp ( 1 2 ) echo ' matrix = ' $matrix set outMapIVfile = temp.ivf set outMapIVfile = none set outBPGfile = temp.bpgf set outBPGfile = none set msgFile = stdout @ seed = $firstseed while ( $seed <= $lastseed ) extractBPG $msglvl $msgFile $inGraphFile \ $inCompidsIVfile $icomp $outMapIVfile $outBPGfile @ seed = $seed + 1 end end BPG/drivers/makefile010064400020550007177000000010040665314231600156600ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testIO testDM extractBPG drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testIO : testIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testDM : testDM.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} extractBPG : extractBPG.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} BPG/drivers/extractBPG.c010064400020550007177000000134350654221343200163350ustar00clevecompmath00000400000006/* extractBPG.c */ #include "../BPG.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------------------------------------- extract a bipartite graph from a graph and a two-set partition created -- 96nov02, cca -------------------------------------------------------------- */ { char *inGraphFileName, *inCompidsIVfileName, *outBPGfileName, *outMapIVfileName ; double t1, t2 ; int msglvl, rc ; BPG *bpg ; FILE *msgFile ; Graph *graph ; int icomp, ierr, nvtx ; int *cmap, *compids, *indX, *indY ; IV *compidsIV ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile inCompidsIVfile" "\n icomp outBPGfile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n inCompidsIVfile -- input file, must be *.ivf or *.ivb" "\n icomp -- component for Y nodes" "\n outMapIVfile -- map output file, must be *.ivf or *.ivb" "\n outBPGfile -- output file, must be *.bpgf or *.bpgb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; inCompidsIVfileName = argv[4] ; icomp = atoi(argv[5]) ; outMapIVfileName = argv[6] ; outBPGfileName = argv[7] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n inCompidsIVfile -- %s" "\n icomp -- %d" "\n outMapIVfile -- %s" "\n outBPGfile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, inCompidsIVfileName, icomp, outMapIVfileName, outBPGfileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; nvtx = graph->nvtx ; /* ------------------------ read in the IV object ------------------------ */ if ( strcmp(inCompidsIVfileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } compidsIV = IV_new() ; MARKTIME(t1) ; rc = IV_readFromFile(compidsIV, inCompidsIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in compidsIV from file %s", t2 - t1, inCompidsIVfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, compidsIV, inCompidsIVfileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading IV object from file %s", inCompidsIVfileName) ; if ( msglvl > 2 ) { IV_writeForHumanEye(compidsIV, msgFile) ; } else { IV_writeStats(compidsIV, msgFile) ; } fflush(msgFile) ; /* --------------------------------------------------- extract out the bipartite graph that corresponds to the separator and its boundary in component icomp --------------------------------------------------- */ compids = IV_entries(compidsIV) ; cmap = IVinit(nvtx, -1) ; indX = IVinit(nvtx, -1) ; indY = IVinit(nvtx, -1) ; bpg = BPG_new() ; BPG_initFromColoring(bpg, graph, compids, 0, icomp, cmap, indX, indY) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n cmap[]") ; IVfp80(msgFile, nvtx, cmap, 80, &ierr) ; fprintf(msgFile, "\n\n indX[]") ; IVfp80(msgFile, bpg->nX, indX, 80, &ierr) ; fprintf(msgFile, "\n\n indY[]") ; IVfp80(msgFile, bpg->nY, indY, 80, &ierr) ; fprintf(msgFile, "\n\n bipartite graph") ; BPG_writeForHumanEye(bpg, msgFile) ; } else { BPG_writeStats(bpg, msgFile) ; } fflush(msgFile) ; /* ---------------------------------------------------------------- if the map vector is requested, create it and write it to a file ---------------------------------------------------------------- */ if ( strcmp(outMapIVfileName, "none") != 0 ) { IV mapIV ; IV_setDefaultFields(&mapIV) ; IV_init(&mapIV, bpg->nX + bpg->nY, NULL) ; IVcopy(bpg->nX, IV_entries(&mapIV), indX) ; IVcopy(bpg->nY, IV_entries(&mapIV) + bpg->nX, indY) ; if ( msglvl > 0 ) { IV_writeForHumanEye(&mapIV, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; rc = IV_writeToFile(&mapIV, outMapIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write mapIV to file %s", t2 - t1, outMapIVfileName) ; } /* ------------------------ write out the BPG object ------------------------ */ if ( strcmp(outBPGfileName, "none") != 0 ) { MARKTIME(t1) ; rc = BPG_writeToFile(bpg, outBPGfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write graph to file %s", t2 - t1, outBPGfileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from BPG_writeToFile(%p,%s)", rc, bpg, outBPGfileName) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ " "\n icomp outBPGfile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n inCompidsIVfile -- inputBPG/drivers/testDM.c010064400020550007177000000074340654221365300155410ustar00clevecompmath00000400000006/* testDM.c */ #include "../BPG.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------------------- read BPG from file and get the Dulmage-Mendelsohn decomposition created -- 96mar08, cca --------------------------------------------------------------- */ { char *inBPGFileName ; double t1, t2 ; int ierr, msglvl, rc ; int *dmflags, *stats ; BPG *bpg ; FILE *msgFile ; if ( argc != 4 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.bpgf or *.bpgb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inBPGFileName = argv[3] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n", argv[0], msglvl, argv[2], inBPGFileName) ; fflush(msgFile) ; /* ---------------------- read in the BPG object ---------------------- */ if ( strcmp(inBPGFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } bpg = BPG_new() ; MARKTIME(t1) ; rc = BPG_readFromFile(bpg, inBPGFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inBPGFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from BPG_readFromFile(%p,%s)", rc, bpg, inBPGFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading BPG object from file %s", inBPGFileName) ; if ( msglvl > 2 ) { BPG_writeForHumanEye(bpg, msgFile) ; } else { BPG_writeStats(bpg, msgFile) ; } fflush(msgFile) ; /* -------------------------------------------- test out the max flow DMdecomposition method -------------------------------------------- */ dmflags = IVinit(bpg->nX + bpg->nY, -1) ; stats = IVinit(6, 0) ; MARKTIME(t1) ; BPG_DMviaMaxFlow(bpg, dmflags, stats, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.5f : find DM via maxflow", t2 - t1) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n BPG_DMviaMaxFlow" "\n |X_I| = %6d, |X_E| = %6d, |X_R| = %6d" "\n |Y_I| = %6d, |Y_E| = %6d, |Y_R| = %6d", stats[0], stats[1], stats[2], stats[3], stats[4], stats[5]) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n dmflags") ; IVfp80(msgFile, bpg->nX + bpg->nY, dmflags, 80, &ierr) ; fflush(msgFile) ; } /* ------------------------------------------ test out the matching DMcomposition method ------------------------------------------ */ IVfill(bpg->nX + bpg->nY, dmflags, -1) ; IVfill(6, stats, -1) ; MARKTIME(t1) ; BPG_DMdecomposition(bpg, dmflags, stats, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.5f : find DM via matching", t2 - t1) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n BPG_DMdecomposition" "\n |X_I| = %6d, |X_E| = %6d, |X_R| = %6d" "\n |Y_I| = %6d, |Y_E| = %6d, |Y_R| = %6d", stats[0], stats[1], stats[2], stats[3], stats[4], stats[5]) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n dmflags") ; IVfp80(msgFile, bpg->nX + bpg->nY, dmflags, 80, &ierr) ; fflush(msgFile) ; } /* ---------------- free the storage ---------------- */ IVfree(dmflags) ; IVfree(stats) ; BPG_free(bpg) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ BPG/drivers/testIO.c010064400020550007177000000053500654221347000155400ustar00clevecompmath00000400000006/* testIO.c */ #include "../BPG.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- test BPG_readFromFile and BPG_writeToFile, useful for translating between formatted *.bpgf and binary *.bpgb files. created -- 96mar08, cca ------------------------------------------------- */ { char *inBPGFileName, *outBPGFileName ; double t1, t2 ; int msglvl, rc ; BPG *bpg ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.bpgf or *.bpgb" "\n outFile -- output file, must be *.bpgf or *.bpgb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inBPGFileName = argv[3] ; outBPGFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inBPGFileName, outBPGFileName) ; fflush(msgFile) ; /* ---------------------- read in the BPG object ---------------------- */ if ( strcmp(inBPGFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } bpg = BPG_new() ; MARKTIME(t1) ; rc = BPG_readFromFile(bpg, inBPGFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inBPGFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from BPG_readFromFile(%p,%s)", rc, bpg, inBPGFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading BPG object from file %s", inBPGFileName) ; if ( msglvl > 2 ) { BPG_writeForHumanEye(bpg, msgFile) ; } else { BPG_writeStats(bpg, msgFile) ; } fflush(msgFile) ; /* ------------------------ write out the BPG object ------------------------ */ if ( strcmp(outBPGFileName, "none") != 0 ) { MARKTIME(t1) ; rc = BPG_writeToFile(bpg, outBPGFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write graph to file %s", t2 - t1, outBPGFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from BPG_writeToFile(%p,%s)", rc, bpg, outBPGFileName) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ BPG/doc/004275500020550007177000000000000665014142600132575ustar00clevecompmath00000400000006BPG/doc/dataStructure.tex010064400020550007177000000007430653410612700166320ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:BPG:dataStructure} \par A bipartite graph is a triple $(X,Y,E)$ where $X$ and $Y$ are disjoint sets of vertices and $E \subseteq X \times Y$ is a set of edges connecting vertices in $X$ and $Y$. The {\tt BPG} structure has three fields. \begin{itemize} \item {\tt int nX} : number of vertices in $X$ \item {\tt int nY} : number of vertices in $Y$ \item {\tt Graph *graph} : pointer to a graph object $G = (X \cup Y), E)$. \end{itemize} BPG/doc/drivers.tex010064400020550007177000000126110653577162400154660ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt BPG} object} \label{section:BPG:drivers} \par This section contains brief descriptions of the driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program reads and write {\tt BPG} files, useful for converting formatted files to binary files and vice versa. One can also read in a {\tt BPG} file and print out just the header information (see the {\tt BPG\_writeStats()} method). \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt BPG} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt BPG} object. It must be of the form {\tt *.bpgf} or {\tt *.bpgb}. The {\tt BPG} object is read from the file via the {\tt BPG\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt BPG} object. If {\tt outFile} is {\tt none} then the {\tt BPG} object is not written to a file. Otherwise, the {\tt BPG\_writeToFile()} method is called to write the graph to a formatted file (if {\tt outFile} is of the form {\tt *.bpgf}), or a binary file (if {\tt outFile} is of the form {\tt *.bpgb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} extractBPG msglvl msgFile inGraphFile inCompidsIVfile icomp outMapFile outBPGfile \end{verbatim} This driver program reads in a {\tt Graph} object and an {\tt IV} object that contains the component ids. (A separator vertex has component id zero; other vertices have positive component ids to identify the subgraph that contains them.) It then extracts out the bipartite graph formed by the separator and nodes in the target component that are adjacent to the separator. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any message data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt inCompidsIVfile} parameter is the input file for the {\tt IV} object that contains the component ids. It must be of the form {\tt *.ivf} or {\tt *.ivb}. The {\tt IV} object is read from the file via the {\tt IV\_readFromFile()} method. \item The {\tt icomp} parameter defines the target component to form the $Y$ nodes of the bipartite graph. (The separator nodes, component zero, form the $X$ nodes.) \item The {\tt outMapFile} parameter is the output file for the {\tt IV} object that holds the map from vertices in the bipartite graph to vertices in the original graph. If {\tt outMapFile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the {\tt IV} object to a formatted file (if {\tt outMapFile} is of the form {\tt *.ivf}), or a binary file (if {\tt outMapFile} is of the form {\tt *.ivb}). \item The {\tt outBPGFile} parameter is the output file for the compressed {\tt BPG} object. If {\tt outBPGFile} is {\tt none} then the {\tt BPG} object is not written to a file. Otherwise, the {\tt BPG\_writeToFile()} method is called to write the graph to a formatted file (if {\tt outBPGFile} is of the form {\tt *.graphf}), or a binary file (if {\tt outBPGFile} is of the form {\tt *.graphb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testDM msglvl msgFile inBPGfile \end{verbatim} This driver program reads in a {\tt BPG} object from a file. It then finds the Dulmage-Mendelsohn decomposition using two methods. \begin{itemize} \item {\tt BPG\_DMdecomposition()} which uses matching techniques on the weighted graph. \item {\tt BPG\_DMviaMaxFlow()} which forms bipartite network and solves the max flow problem using a simple Ford-Fulkerson algorithm. \end{itemize} This provides a good check on the two programs (they must have the same output) and writes their execution times. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any message data. \item The {\tt inBPGFile} parameter is the input file for the {\tt BPG} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt BPG} object is read from the file via the {\tt BPG\_readFromFile()} method. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} BPG/doc/intro.tex010064400020550007177000000201530665023014600151260ustar00clevecompmath00000400000006\par \chapter{{\tt BPG}: Bipartite Graph Object} \label{chapter:BPG} \par The {\tt BPG} object is used to represent a bipartite graph. A bipartite graph naturally {\it is-a} graph, but since we are working in C, without inheritance, we have chosen to use the {\it has-a} relationship, i.e., our {\tt BPG} bipartite graph object {\it has-a} {\tt Graph} object inside itself. \par A bipartite graph is a triple $H = (X, Y, E)$ where $X$ and $Y$ are two disjoint sets of vertices and the edge set $E$ is a subset of $X \times Y$. In other words, nodes in $X$ are adjacent to node in $Y$, but no edge connects two vertices in $X$ or two vertices in $Y$. \par We do not support bipartite graphs that are {\it subgraphs} of other bipartite graphs (in the sense that there are {\tt Graph} objects that are subgraphs of other {\tt Graph} objects) because we haven't found any reason to do so. \par This bipartite graph object is very rudimentary. We have used it in two instances. \begin{itemize} \item Given a domain decomposition of a graph, we want to find a bisector of the graph that is a subset of the interface vertices. To do this we construct a bipartite graph such that the $X$ nodes are the domains and the $Y$ nodes are the segments (a partition of the interface vertices). We then apply a variant of the Kernighan-Lin algorithm to find an edge separator that is a subset of the segments. (Details are found in \cite{ash97-DDSEP}.) \item Given a 2-set partition of a graph $[S,B,W]$ where $S$ is the separator and $B$ and $W$ are the two components, we want to find an improved partition $[{\widehat S}, {\widehat B}, {\widehat W}]$. One way to do this is to construct a bipartite graph where $X = S$ and $Y = Adj(S) \cap B$ or $Y = Adj(S) \cap W$ and the edge set $E$ is constructed naturally from the appropriate edges in the graph. We then find the Dulmage-Mendelsohn decomposition of this bipartite graph to look for a better 2-set partition. (Details are found in \cite{ash98-maxflow}.) \end{itemize} Our bipartite graph object illustrates software in evolution. In both cases, our desired output is a separator and the problem can be formulated as a bipartite graph. Does the {\it data} (the bipartite graph) {\it own} the {\it process} (the Kernighan-Lin algorithm or the Dulmage-Mendelsohn decomposition)? Or does the process operate on the data? There is no cut and dried answer. In fact, we did it both ways. \par To find a separator from a domain decomposition, we took the approach that the process works on the data. (See the {\tt BKL} block Kernighan-Lin object.) The process was sufficiently involved that soon the {\tt BKL} code for the process outweighed (outline'd?) the {\tt BPG} code for the data. Now if someone wants to modify (and hopefully improve) the Kernighan-Lin process, they won't alter the behavior of the bipartite graph object. \par Finding the Dulmage-Mendelsohn decomposition of a bipartite graph is a little less clear cut. When the vertices in the bipartite graph have unit weight, the process is straightforward. \begin{itemize} \item Find a maximum matching. \item Drop an alternating level structure from exposed nodes in $X$. \item Drop an alternating level structure from exposed nodes in $Y$. \item Based on the two previous steps, partition $X$ into three pieces and $Y$ into three pieces and form a new separator from the pieces. \end{itemize} (If these terms are not familiar, see \cite{ash98-maxflow}; our present purpose is a discussion of software design, not algorithms.) A matching is a very common operation on a bipartite graph, so it is not unreasonable to expand the data object to include some mechanism for matching, e.g., a {\tt mate[]} vector. Finding a maximum matching is a bit more tricky for there are a number of algorithms to do so, some fast, some slow, some simple, some complex. Which to choose? \par If we only worked with unit weight bipartite graphs, then we probably would have added methods to find a maximum matching, and dropping alternating level structures, and then to find the Dulmage-Mendelsohn decomposition. If someone wanted to use a faster algorithm to find a maximum matching it would be a simple case of replacing a method. However, one of the strengths of this software package is that we do not work on unit weight graphs unless we have to, we work on the natural compressed graph. \par The Dulmage-Mendelsohn decomposition was not defined for non-unit weight graphs. We were in new territory, at least to us. We could always expand the weighted bipartite compressed graph into a larger unit weight graph, find the Dulmage-Mendelsohn decomposition and map it back to the weighted graph. (It turns out that the DM partition is conformal with the compressed graph, i.e., a weighted vertex is completely contained inside one of the six sets.) This would have been a very ugly feature of an otherwise clean code. \par Our first remedy was to design a method that found the DM decomposition of the unit weight graph while {\it using} the compressed graph plus a work vector whose size was the sum of the vertex weights. See the method {\tt BPG\_DMdecomposition()}. The code is appreciably faster than expanding the weighted graph to a unit weight graph, finding the decomposition and then mapping back. It is not really a method, but a module, for the fourteen hundred lines of code contain many static functions. Though the code is adequately documented, this isn't an algorithm that we felt like publicizing, so we export the method but not the internals. \par After some time, thought and reflection, we came to realize that we can find the decomposition by solving a max flow problem. In some sense this is obvious, for bipartite graph matching is nothing more than a special case of max flow. Just how to formulate the max flow problem is what eluded us for an embarassing amount of time. Once we were able to formulate the problem as max flow, we wrote a new method to find the decomposition for a weighted graph. The line count for {\tt BPG\_DMviaMaxFlow()} is about one half that of {\tt BPG\_DMdecomposition()} and it is easier to understand. Both methods use a simple Ford-Fulkerson augmenting flow approach. \par At this time we thought about writing an object to solve max flow problems and shifting most of the responsibility of finding the decomposition to a specialized object that solves a max flow problem on a bipartite network. Had we more time, we would have done so. The advantages are clear. In fact, that is the approach we have taken, but in a different context. To explain, we must return to our original problem. \par The goal is to improve a 2-set partition $[S,B,W]$. Let $B$ be the larger of $B$ and $W$. We look at the subgraph induced by $S \cup (Adj(S) \cap B)$. The goal is to find a set $Z \subseteq S$ that will be absorbed by the smaller component $W$ that results in a smaller separator. As a result, some nodes in $Adj(S) \cap B$ move from $B$ into the separator set. The DM decomposition lets us identify a set $Z$ that results in the {\it largest} decrease in the separator size. But, if we consider $S \cup (Adj(S) \cap B)$ to be a {\it wide} separator, the resulting separator ${\widehat S}$ need not be a separator with minimal weight that is found within the wide separator. The trick is that some nodes in $Adj(S) \cap B$ might be absorbed into $W$. \par One can find a separator with minimal weight from the wide separator $S \cup (Adj(S) \cap B)$, in fact from {\it any} wide separator that contains $S$, by solving a max flow problem. The drawback is that the network induced by $S \cup (Adj(S) \cap B)$ need not be bipartite. In other words, a bipartite induced graph necessarily implies two layers to the wide separator, but the converse does not hold. We were then free to examine wide separators that had more than two layers from which to find a minimal weight separator. It turns out that three layers is better than two, in practice. \par We did write a separate object to solve our max flow problem; see the {\tt Network} object. To smooth a separator, i.e., to improve a 2-set partition, we no longer have need of the bipartite graph object. We leave the two Dulmage-Mendelsohn methods in the {\tt BPG} object for historical and sentimental reasons. BPG/doc/main.aux010064400020550007177000000030230664720710700147200ustar00clevecompmath00000400000006\relax \citation{ash95-DDSEP} \citation{ash96-maxflow} \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt BPG}: Bipartite Graph Object}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:BPG}{{1}{1}} \citation{ash96-maxflow} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{3}} \newlabel{section:BPG:dataStructure}{{1.1}{3}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt BPG} methods}{3}} \newlabel{section:BPG:proto}{{1.2}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{3}} \newlabel{subsection:BPG:proto:basics}{{1.2.1}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Initializer methods}{4}} \newlabel{subsection:BPG:proto:initializers}{{1.2.2}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Generate induced graphs}{4}} \newlabel{subsection:BPG:proto:induced-graphs}{{1.2.3}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Utility methods}{4}} \newlabel{subsection:BPG:proto:utilities}{{1.2.4}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Dulmage-Mendelsohn decomposition method}{5}} \newlabel{subsection:BPG:proto:DM}{{1.2.5}{5}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.6}IO methods}{5}} \newlabel{subsection:BPG:proto:IO}{{1.2.6}{5}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs for the {\tt BPG} object}{6}} \newlabel{section:BPG:drivers}{{1.3}{6}} BPG/doc/main.log010064400020550007177000000062350664720710700147140ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 13 JAN 1999 13:21 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. (intro.tex Chapter 1. LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 12. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 12. LaTeX Font Info: Try loading font information for OMS+cmr on input line 27. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 27. LaTeX Warning: Citation `ash95-DDSEP' on page 1 undefined on input line 34. LaTeX Warning: Citation `ash96-maxflow' on page 1 undefined on input line 46. [1 ] LaTeX Warning: Citation `ash96-maxflow' on page 2 undefined on input line 83. [2]) (dataStructure.tex) (proto.tex [3] [4] Overfull \hbox (66.05252pt too wide) in paragraph at lines 260--262 []\OT1/cmr/m/n/10 This method has the same func-tion-al-ity, call-ing se-quence and re-turned val-ues as the pre-ced-ing \OT1/cmtt/m/n/10 BPG[]DMdecomposition () [] [5]) (drivers.tex [6]) (main.ind [7] [8 ]) (main.aux) LaTeX Warning: There were undefined references. ) Here is how much of TeX's memory you used: 310 strings out of 10908 3219 string characters out of 72189 50228 words of memory out of 262141 3227 multiletter control sequences out of 9500 7911 words of font info for 30 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 23i,7n,22p,164b,341s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (8 pages, 32148 bytes). BPG/doc/main.tex010064400020550007177000000011510664720707700147310ustar00clevecompmath00000400000006% % main TeX file % % \documentstyle[leqno,11pt,twoside]{report} \documentclass[leqno,10pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt BPG} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt BPG} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} BPG/doc/proto.tex010064400020550007177000000370240664721223500151500ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt BPG} methods} \label{section:BPG:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt BPG} object. \par \subsection{Basic methods} \label{subsection:BPG:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} BPG * BPG_new ( void ) ; \end{verbatim} \index{BPG_new@{\tt BPG\_new()}} This method simply allocates storage for the {\tt BPG} structure and then sets the default fields by a call to {\tt BPG\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void BPG_setDefaultFields ( BPG *bpg ) ; \end{verbatim} \index{BPG_setDefaultFields@{\tt BPG\_setDefaultFields()}} This method sets the fields of the structure to their default values: {\tt nX = nY = 0} and {\tt graph = NULL}. \par \noindent {\it Error checking:} If {\tt bpg} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void BPG_clearData ( BPG *bpg ) ; \end{verbatim} \index{BPG_clearData@{\tt BPG\_clearData()}} This method releases the storage for {\tt graph} via a call to {\tt Graph\_clearData()}, and then the structure's fields are then set to their default values with a call to {\tt BPG\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt bpg} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void BPG_free ( BPG *bpg ) ; \end{verbatim} \index{BPG_free@{\tt BPG\_free()}} This method releases any storage by a call to {\tt BPG\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt bpg} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:BPG:proto:initializers} \par There are two initializer methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void BPG_init ( BPG *bpg, int nX, int nY, Graph *graph ) ; \end{verbatim} \index{BPG_init@{\tt BPG\_init()}} This method initializes the {\tt BPG} object when all three of its fields are given in the calling sequence. The {\tt Graph} object has {\tt nX + nY} vertices. Note, the {\tt BPG} object now ``owns'' the {\tt Graph} object and so will free the {\tt Graph} object when it is free'd. The {\tt Graph} object may contains edges between nodes in {\tt X} and {\tt Y}, but these edges are swapped to the end of each adjacency list and the size of each list is then set. \par \noindent {\it Error checking:} If {\tt bpg} or {\tt graph} are {\tt NULL}, or if ${\tt nX} \le 0$, or if ${\tt nY} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void BPG_initFromColoring ( BPG *bpg, Graph *graph, int colors[], int cX, int cY, int cmap[], int indX[], int indY[] ) ; \end{verbatim} \index{BPG_initFromColoring@{\tt BPG\_initFromColoring()}} This method extracts a bipartite graph from a {\tt Graph} object where the {\tt X} vertices are those with {\tt cmap[]} value equal to {\tt cX} and the {\tt Y} vertices are those with {\tt cmap[]} value equal to {\tt cY}. The vectors {\tt indX[]} and {\tt indY[]} hold the global vertex ids of the {\tt X} and {\tt Y} vertices respectively. \par \noindent {\it Error checking:} If {\tt bpg}, {\tt graph}, {\tt colors} or {\tt cmap} are {\tt NULL}, or if ${\tt cX} \le 0$, or if ${\tt cY} \le 0$, or if ${\tt cX} = {\tt cY}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Generate induced graphs} \label{subsection:BPG:proto:induced-graphs} \par Sometimes we need to know which {\tt X} or {\tt Y} vertices share an edge, e.g., in the {\tt BKL} object we need the domain-domain adjacency graph (the domains are the {\tt X} vertices) to efficiently implement the Fiduccia-Mattheyses algorithm. We have two methods to generate the two induced graphs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Graph * BPG_makeGraphXbyX ( BPG *bpg ) ; \end{verbatim} \index{BPG_makeGraphXbyX@{\tt BPG\_makeGraphXbyX()}} This method constructs and returns a {\tt Graph} object whose vertices are {\tt X} and an edge {\tt (x1,x2)} is in the graph when there is a {\tt Y} vertex {\tt y} such that {\tt (x1,y)} and {\tt (x2,y)} are in the bipartite graph. \par \noindent {\it Error checking:} If {\tt bpg} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Graph * BPG_makeGraphYbyY ( BPG *bpg ) ; \end{verbatim} \index{BPG_makeGraphYbyY@{\tt BPG\_makeGraphYbyY()}} This method constructs and returns a {\tt Graph} object whose vertices are {\tt Y} and an edge {\tt (y1,y2)} is in the graph when there is a {\tt X} vertex {\tt x} such that {\tt (x,y1)} and {\tt (x,y2)} are in the bipartite graph. \par \noindent {\it Error checking:} If {\tt bpg} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:BPG:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BPG_pseudoperipheralnode ( BPG *bpg, int seed ) ; \end{verbatim} \index{BPG_pseudoperipheralnode@{\tt BPG\_pseudoperipheralnode()}} This method finds and returns a pseudoperipheral node for the bipartite graph. \par \noindent {\it Error checking:} If {\tt bpg} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int BPG_levelStructure ( BPG *bpg, int root, int list[], int dist[], int mark[], int tag ) ; \end{verbatim} \index{BPG_levelStructure@{\tt BPG\_levelStructure()}} This method drops a level structure from vertex {\tt root}, fills the {\tt dist[]} vector with the distances from {\tt root}, and returns the number of levels created. The {\tt mark[]} vector is used to mark nodes with the {\tt tag} value as they are placed in the level structure. The {\tt list[]} vector is used to accumulate the nodes as they are placed in the level structure. \par \noindent {\it Error checking:} If {\tt bpg}, {\tt list}, {\tt dist} or {\tt mark} is {\tt NULL}, or if {\tt root} is not in {\tt [0, nX+nY)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Dulmage-Mendelsohn decomposition method} \label{subsection:BPG:proto:DM} \par There is one method to find the Dulmage-Mendelsohn decomposition that uses matching when the graph is unit weight and a generalized matching technique otherwise. There is a second method to find the decomposition using a Ford-Fulkerson algorithm to find a max flow and a min-cut on a bipartite network. This has largely been superceded by the {\tt Network} object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void BPG_DMdecomposition ( BPG *bpg, int dmflags[], int stats[], int msglvl, FILE *msgFile ) \end{verbatim} \index{BPG_DMdecomposition@{\tt BPG\_DMdecomposition()}} This method constructs and returns the Dulmage-Mendelsohn decomposition for a unit weight graph and its generalization for a non-unit weight graph. On return, the {\tt dmflags[]} vector is filled with the following values: \begin{displaymath} \mbox{\tt dmflags[x]} = \begin{cases} 0 & \text{if \texttt{x} $\in X_R$} \\ 1 & \text{if \texttt{x} $\in X_I$} \\ 2 & \text{if \texttt{x} $\in X_E$} \end{cases} \qquad \mbox{\tt dmflags[y]} = \begin{cases} 0 & \text{if \texttt{y} $\in Y_R$} \\ 1 & \text{if \texttt{y} $\in Y_I$} \\ 2 & \text{if \texttt{y} $\in Y_E$} \end{cases} \end{displaymath} The set $X_I \cup Y_E$ contains all nodes that are reachable via alternating paths starting from exposed nodes in $X$. The set $Y_I \cup X_E$ contains all nodes that are reachable via alternating paths starting from exposed nodes in $Y$. The remaining two sets are $X_R = X \setminus (X_I \cup X_E)$ and $Y_R = Y \setminus (Y_I \cup Y_E)$. On return, the {\tt stats[]} vector is filled with the following values: \begin{center} \begin{tabular}{lllllll} {\tt stats[0]} & --- & weight of $X_I$ & \qquad & {\tt stats[3]} & --- & weight of $Y_I$ \\ {\tt stats[1]} & --- & weight of $X_E$ & \qquad & {\tt stats[4]} & --- & weight of $Y_E$ \\ {\tt stats[2]} & --- & weight of $X_R$ & \qquad & {\tt stats[5]} & --- & weight of $Y_R$ \end{tabular} \end{center} \par \noindent {\it Error checking:} If {\tt bpg}, {\tt dmflags} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void BPG_DMviaMaxFlow ( BPG *bpg, int dmflags[], int stats[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{BPG_DMviaMaxFlow@{\tt BPG\_DMviaMaxFlow()}} This method has the same functionality, calling sequence and returned values as the preceding {\tt BPG\_DMdecomposition()} method. \par \noindent {\it Error checking:} If {\tt bpg}, {\tt dmflags} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:BPG:proto:IO} \par There are the usual eight IO routines. The file structure of a {\tt BPG} object is simple: the two scalar fields {\tt nX} and {\tt nY} come first and the {\tt Graph} object follows. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BPG_readFromFile ( BPG *bpg, char *fn ) ; \end{verbatim} \index{BPG_readFromFile@{\tt BPG\_readFromFile()}} \par This method reads a {\tt BPG} object from a file. The method tries to open the file and if it is successful, it then calls {\tt BPG\_readFromFormattedFile()} or {\tt BPG\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt bpg} or {\tt fn} is {\tt NULL}, or if {\tt fn} is not of the form {\tt *.bpgf} (for a formatted file) or {\tt *.bpgb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int BPG_readFromFormattedFile ( BPG *bpg, FILE *fp ) ; \end{verbatim} \index{BPG_readFromFormattedFile@{\tt BPG\_readFromFormattedFile()}} \par This method reads a {\tt BPG} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt bpg} or {\tt fp} is {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int BPG_readFromBinaryFile ( BPG *bpg, FILE *fp ) ; \end{verbatim} \index{BPG_readFromBinaryFile@{\tt BPG\_readFromBinaryFile()}} \par This method reads a {\tt BPG} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt bpg} or {\tt fp} is {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int BPG_writeToFile ( BPG *bpg, char *fn ) ; \end{verbatim} \index{BPG_writeToFile@{\tt BPG\_writeToFile()}} \par This method writes a {\tt BPG} object to a file. The method tries to open the file and if it is successful, it then calls {\tt BPG\_writeFromFormattedFile()} or {\tt BPG\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt bpg} or {\tt fn} is {\tt NULL}, or if {\tt fn} is not of the form {\tt *.bpgf} (for a formatted file) or {\tt *.bpgb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int BPG_writeToFormattedFile ( BPG *bpg, FILE *fp ) ; \end{verbatim} \index{BPG_writeToFormattedFile@{\tt BPG\_writeToFormattedFile()}} \par This method writes a {\tt BPG} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt bpg} or {\tt fp} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int BPG_writeToBinaryFile ( BPG *bpg, FILE *fp ) ; \end{verbatim} \index{BPG_writeToBinaryFile@{\tt BPG\_writeToBinaryFile()}} \par This method writes a {\tt BPG} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt bpg} or {\tt fp} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int BPG_writeForHumanEye ( BPG *bpg, FILE *fp ) ; \end{verbatim} \index{BPG_writeForHumanEye@{\tt BPG\_writeForHumanEye()}} \par This method writes a {\tt BPG} object to a file in a human readable format. The method {\tt BPG\_writeStats()} is called to write out the header and statistics. Then the {\tt bpg->graph} object is written via a call to {\tt Graph\_writeForHumanEye()}. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt bpg} or {\tt fp} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int BPG_writeStats ( BPG *bpg, FILE *fp ) ; \end{verbatim} \index{BPG_writeStats@{\tt BPG\_writeStats()}} \par This method writes a header with statistics to a file. A header is written and the value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt bpg} or {\tt fp} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} BPG/doc/main.idx010064400020550007177000000023140664720710700147110ustar00clevecompmath00000400000006\indexentry{BPG_new@{\tt BPG\_new()}}{3} \indexentry{BPG_setDefaultFields@{\tt BPG\_setDefaultFields()}}{3} \indexentry{BPG_clearData@{\tt BPG\_clearData()}}{3} \indexentry{BPG_free@{\tt BPG\_free()}}{3} \indexentry{BPG_init@{\tt BPG\_init()}}{4} \indexentry{BPG_initFromColoring@{\tt BPG\_initFromColoring()}}{4} \indexentry{BPG_makeGraphXbyX@{\tt BPG\_makeGraphXbyX()}}{4} \indexentry{BPG_makeGraphYbyY@{\tt BPG\_makeGraphYbyY()}}{4} \indexentry{BPG_pseudoperipheralnode@{\tt BPG\_pseudoperipheralnode()}}{4} \indexentry{BPG_levelStructure@{\tt BPG\_levelStructure()}}{4} \indexentry{BPG_DMdecomposition@{\tt BPG\_DMdecomposition()}}{5} \indexentry{BPG_DMviaMaxFlow@{\tt BPG\_DMviaMaxFlow()}}{5} \indexentry{BPG_readFromFile@{\tt BPG\_readFromFile()}}{5} \indexentry{BPG_readFromFormattedFile@{\tt BPG\_readFromFormattedFile()}}{5} \indexentry{BPG_readFromBinaryFile@{\tt BPG\_readFromBinaryFile()}}{6} \indexentry{BPG_writeToFile@{\tt BPG\_writeToFile()}}{6} \indexentry{BPG_writeToFormattedFile@{\tt BPG\_writeToFormattedFile()}}{6} \indexentry{BPG_writeToBinaryFile@{\tt BPG\_writeToBinaryFile()}}{6} \indexentry{BPG_writeForHumanEye@{\tt BPG\_writeForHumanEye()}}{6} \indexentry{BPG_writeStats@{\tt BPG\_writeStats()}}{6} BPG/doc/main.ind010064400020550007177000000014360653577124600147110ustar00clevecompmath00000400000006\begin{theindex} \item {\tt BPG\_clearData()}, 4 \item {\tt BPG\_DMdecomposition()}, 5 \item {\tt BPG\_DMviaMaxFlow()}, 6 \item {\tt BPG\_free()}, 4 \item {\tt BPG\_init()}, 4 \item {\tt BPG\_initFromColoring()}, 4 \item {\tt BPG\_levelStructure()}, 5 \item {\tt BPG\_makeGraphXbyX()}, 5 \item {\tt BPG\_makeGraphYbyY()}, 5 \item {\tt BPG\_new()}, 4 \item {\tt BPG\_pseudoperipheralnode()}, 5 \item {\tt BPG\_readFromBinaryFile()}, 7 \item {\tt BPG\_readFromFile()}, 6 \item {\tt BPG\_readFromFormattedFile()}, 6 \item {\tt BPG\_setDefaultFields()}, 4 \item {\tt BPG\_writeForHumanEye()}, 7 \item {\tt BPG\_writeStats()}, 7 \item {\tt BPG\_writeToBinaryFile()}, 7 \item {\tt BPG\_writeToFile()}, 7 \item {\tt BPG\_writeToFormattedFile()}, 7 \end{theindex} BPG/doc/main.ilg010064400020550007177000000004560653577124600147130ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (20 entries accepted, 0 rejected). Sorting entries....done (81 comparisons). Generating output file main.ind....done (24 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. BPG/doc/makefile010064400020550007177000000000270654276733000147610ustar00clevecompmath00000400000006clean : - rm -f *.dvi Chv.h010064400020550007177000000000700657353753600130020ustar00clevecompmath00000400000006#ifndef _Chv_ #define _Chv_ #include "Chv/Chv.h" #endif Chv/Chv.h010064400020550007177000001000500657127607000135100ustar00clevecompmath00000400000006/* Chv.h */ #include "../SubMtx.h" #include "../PatchAndGoInfo.h" #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- basic chevron object, double complex id -- object's id nD -- number of rows and columns in the diagonal (1,1) block nL -- number of rows in the lower (2,1) block nU -- number of columns in the upper (1,2) block type -- type of chevron SPOOLES_REAL --> chevron has real entries SPOOLES_COMPLEX --> chevron has complex entries symflag -- symmetry flag SPOOLES_SYMMETRIC --> chevron is symmetric SPOOLES_HERMITIAN --> chevron is hermitian SPOOLES_NONSYMMETRIC --> chevron is nonsymmetric rowind -- pointer to the row indices colind -- pointer to the column indices entries -- pointer to the entries wrkDV -- working storage DV object next -- next Chv in a singly linked list -------------------------------------------------------------------- */ typedef struct _Chv Chv ; struct _Chv { int id ; int nD ; int nL ; int nU ; int type ; int symflag ; int *rowind ; int *colind ; double *entries ; DV wrkDV ; Chv *next ; } ; #define CHV_IS_REAL(chv) ((chv)->type == SPOOLES_REAL) #define CHV_IS_COMPLEX(chv) ((chv)->type == SPOOLES_COMPLEX) #define CHV_IS_SYMMETRIC(chv) ((chv)->symflag == SPOOLES_SYMMETRIC) #define CHV_IS_HERMITIAN(chv) ((chv)->symflag == SPOOLES_HERMITIAN) #define CHV_IS_NONSYMMETRIC(chv) ((chv)->symflag == SPOOLES_NONSYMMETRIC) /* ------------------------------------------------- example of storage layout for indices and entries nonsymmetric case, nD = 6, nL = 4, nU = 5 +---------------------------------------+ | 10 11 12 13 14 15 16 17 18 19 20 | | +-----------------------------------+ | | +---------------------------------+ | 9 | | 9 10 11 12 13 14 15 16 17 18 19 | | 8 | | 8 28 29 30 31 32 33 34 35 36 37 | | 7 | | 7 27 45 46 47 48 49 50 51 52 53 | | 6 | | 6 26 44 60 61 62 63 64 65 66 67 | | 5 | | 5 25 43 59 73 74 75 76 77 78 79 | | 4 | | 4 24 42 58 72 84 85 86 87 88 89 | | 3 | | 3 23 41 57 71 83 +--------------+ | 2 | | 2 22 40 56 70 82 | | 1 | | 1 21 39 55 69 81 | | 0 | | 0 20 38 54 68 80 | +---+ +------------------+ symmetric case, nD = 6, nU = 5 +---------------------------------+ | 0 1 2 3 4 5 6 7 8 9 10 | +---------------------------------+ +---------------------------------+ | 0 1 2 3 4 5 6 7 8 9 10 | | 11 12 13 14 15 16 17 18 19 20 | | 21 22 23 44 25 26 27 28 29 | | 30 31 32 33 34 35 36 37 | | 38 39 40 41 42 43 44 | | 45 46 47 48 49 50 | +---------------------------------+ ------------------------------------------------- */ /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98apr30, cca ----------------------- */ Chv * Chv_new ( void ) ; /* ----------------------- set the default fields created -- 98apr30, cca ----------------------- */ void Chv_setDefaultFields ( Chv *chv ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98apr30, cca -------------------------------------------------- */ void Chv_clearData ( Chv *chv ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98apr30, cca ------------------------------------------ */ void Chv_free ( Chv *chv ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------ return the number of bytes needed to store the chevron created -- 98apr30, cca ------------------------------------------------------ */ int Chv_nbytesNeeded ( int nD, int nL, int nU, int type, int symflag ) ; /* ---------------------------------------------------------------- return the number of bytes in the workspace owned by this object created -- 98apr30, cca ---------------------------------------------------------------- */ int Chv_nbytesInWorkspace ( Chv *chv ) ; /* ---------------------------------------------------------------- set the number of bytes in the workspace owned by this object created -- 98apr30, cca ---------------------------------------------------------------- */ void Chv_setNbytesInWorkspace ( Chv *chv, int nbytes ) ; /* ---------------------------- purpose -- set the fields created -- 98apr30, cca ---------------------------- */ void Chv_setFields ( Chv *chv, int id, int nD, int nL, int nU, int type, int symflag ) ; /* ---------------------------- purpose -- basic initializer created -- 98apr30, cca ---------------------------- */ void Chv_init ( Chv *chv, int id, int nD, int nL, int nU, int type, int symflag ) ; /* ------------------------------------ purpose -- initializer with pointers created -- 98apr30, cca ------------------------------------ */ void Chv_initWithPointers ( Chv *chv, int id, int nD, int nL, int nU, int type, int symflag, int *rowind, int *colind, double *entries ) ; /* ------------------------------------------------------------- purpose -- to initialize the object from its working storage, used when the object is an MPI message created -- 98apr30 ------------------------------------------------------------- */ void Chv_initFromBuffer ( Chv *chv ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------- return the id of the chevron created -- 98apr30, cca ---------------------------- */ int Chv_id ( Chv *chv ) ; /* ------------------------------------------------------------ return the type of the chevron return value = SPOOLES_REAL --> chevron is real return value = SPOOLES_COMPLEX --> chevron is complex created -- 98apr30, cca ------------------------------------------------------------ */ int Chv_type ( Chv *chv ) ; /* --------------------------------------------------------------- return the symmetry flag of the chevron return value = SPOOLES_SYMMETRIC --> chevron is symmetric return value = SPOOLES_HERMITIAN --> chevron is hermitian return value = SPOOLES_NONSYMMETRIC --> chevron is nonsymmetric created -- 98apr30, cca --------------------------------------------------------------- */ int Chv_symmetryFlag ( Chv *chv ) ; /* -------------------------------------------------- fill *pnD with nD, *pnL with nL, and *pnU with nU. created -- 98apr30, cca -------------------------------------------------- */ void Chv_dimensions ( Chv *chv, int *pnD, int *pnL, int *pnU ) ; /* ---------------------------------------------- fill *pnrow with nD + nL, *prowind with rowind created -- 98apr30, cca ---------------------------------------------- */ void Chv_rowIndices ( Chv *chv, int *pnrow, int **prowind ) ; /* ---------------------------------------------- fill *pncol with nD + nU, *pcolind with colind created -- 98apr30, cca ---------------------------------------------- */ void Chv_columnIndices ( Chv *chv, int *pncol, int **pcolind ) ; /* ---------------------------- return the number of entries created -- 98apr30, cca ---------------------------- */ int Chv_nent ( Chv *chv ) ; /* -------------------------------------------- fill *pentries with a pointer to the entries created -- 98apr30, cca -------------------------------------------- */ double * Chv_entries( Chv *chv ) ; /* ----------------------------------------- return the location of the diagonal entry for the ichv'th chevron created -- 98apr30, cca ----------------------------------------- */ double * Chv_diagLocation( Chv *chv, int ichv ) ; /* ---------------------------------------------- return a pointer to the start of the workspace created -- 98apr30, cca ---------------------------------------------- */ void * Chv_workspace( Chv *chv ) ; /* ------------------------------------ fill *pValue with entry (irow, jcol) created -- 98apr30, cca ------------------------------------ */ void Chv_realEntry ( Chv *chv, int irow, int jcol, double *pValue ) ; /* -------------------------------------------- fill (*pReal,*pImag) with entry (irow, jcol) created -- 98apr30, cca -------------------------------------------- */ void Chv_complexEntry ( Chv *chv, int irow, int jcol, double *pReal, double *pImag ) ; /* ----------------------------------------------------- fill *ppValue with the location of entry (irow, jcol) created -- 98apr30, cca ----------------------------------------------------- */ void Chv_locationOfRealEntry ( Chv *chv, int irow, int jcol, double **ppValue ) ; /* ---------------------------------------------------------- fill (*ppReal,*ppImag) with location of entry (irow, jcol) created -- 98apr30, cca ---------------------------------------------------------- */ void Chv_locationOfComplexEntry ( Chv *chv, int irow, int jcol, double **ppReal, double **ppImag ) ; /* ------------------------------------ set entry (irow, jcol) to value created -- 98apr30, cca ------------------------------------ */ void Chv_setRealEntry ( Chv *chv, int irow, int jcol, double value ) ; /* -------------------------------------------- fill (*pReal,*pImag) with entry (irow, jcol) created -- 98apr30, cca -------------------------------------------- */ void Chv_setComplexEntry ( Chv *chv, int irow, int jcol, double real, double imag ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in update.c ---------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- purpose -- perform the hermitian factor update T_{\bnd{I} \cap J, \bnd{I} \cap J} -= U_{I, \bnd{I} \cap J}^H D_{I, I} U_{I, \bnd{I} \cap J} and T_{\bnd{I} \cap J, \bnd{I} \cap \bnd{J}} -= U_{I, \bnd{I} \cap J}^H D_{I, I} U_{I, \bnd{I} \cap \bnd{J}} created -- 98apr17, cca --------------------------------------------------------------------- */ void Chv_updateH ( Chv *chvT, SubMtx *mtxD, SubMtx *mtxU, DV *tempDV ) ; /* --------------------------------------------------------------------- purpose -- perform the symmetric factor update T_{\bnd{I} \cap J, \bnd{I} \cap J} -= U_{I, \bnd{I} \cap J}^T D_{I, I} U_{I, \bnd{I} \cap J} and T_{\bnd{I} \cap J, \bnd{I} \cap \bnd{J}} -= U_{I, \bnd{I} \cap J}^T D_{I, I} U_{I, \bnd{I} \cap \bnd{J}} created -- 98apr17, cca --------------------------------------------------------------------- */ void Chv_updateS ( Chv *chvT, SubMtx *mtxD, SubMtx *mtxU, DV *tempDV ) ; /* --------------------------------------------------------------------- purpose -- perform the nonsymmetric factor update T_{\bnd{I} \cap J, \bnd{I} \cap J} -= L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap J} and T_{\bnd{I} \cap J, \bnd{I} \cap \bnd{J}} -= L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap \bnd{J}} and T_{\bnd{I} \cap \bnd{J}, \bnd{I} \cap J} -= L_{\bnd{I} \cap \bnd{J}, I} D_{I, I} U_{I, \bnd{I} \cap J} created -- 98feb27, cca --------------------------------------------------------------------- */ void Chv_updateN ( Chv *chvT, SubMtx *mtxL, SubMtx *mtxD, SubMtx *mtxU, DV *tempDV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in factor.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------ purpose -- to factor the front without pivoting return value -- # of eliminated rows and columns created -- 98aug27, cca ------------------------------------------------ */ int Chv_factorWithNoPivoting ( Chv *chv, PatchAndGoInfo *info ) ; /* ------------------------------------------------------------------ purpose -- factor the pivot chevron with pivoting ndelay -- number of delayed rows and columns pivotflag -- enable pivoting or not 0 --> no pivoting 1 --> enable pivoting pivotsizesIV -- IV object that holds the sizes of the pivots, used only when the front is symmetric or hermitian and pivoting is enabled workDV -- DV object used for working storage, resized as necessary tau -- upper bound on the magnitude of the entries in the factors, used only when pivoting is enabled pntest -- pointer to be incremented with the number of pivot tests return value -- # of eliminated rows and columns created -- 98aug27, cca ------------------------------------------------------------------ */ int Chv_factorWithPivoting ( Chv *chv, int ndelay, int pivotflag, IV *pivotsizesIV, DV *workDV, double tau, int *pntest ) ; /* --------------------------------------------------------- perform a rank one update using the first row and column. this is used in the (L + I)D(I + U) factorization return code --- 0 if the pivot was zero 1 if the pivot was nonzero created -- 98jan23, cca --------------------------------------------------------- */ int Chv_r1upd ( Chv *chv ) ; /* ------------------------------------------------------------------ perform a rank two update using the first two rows. used in the (U^T + I)D(I + U) and (U^H + I)D(I + U) factorizations return code --- 0 if the pivot was zero 1 if the pivot was nonzero created -- 98jan23, cca ------------------------------------------------------------------ */ int Chv_r2upd ( Chv *chv ) ; /* ------------------------------------------------------------------ purpose -- looking at just a single chevron inside the Chv object, find the absolute value of the diagonal element, and the maximum absolute values of the offdiagonal elements in the chevron's row and column. created -- 98aug26, cca ------------------------------------------------------------------ */ void Chv_maxabsInChevron ( Chv *chv, int ichv, double *pdiagmaxabs, double *prowmaxabs, double *pcolmaxabs ) ; /* ------------------------------------------------------- purpose -- zero the offdiagonal entries of chevron ichv created -- 98aug26, cca ------------------------------------------------------- */ void Chv_zeroOffdiagonalOfChevron ( Chv *chv, int ichv ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in swap.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------- swap rows irow and jrow created -- 98apr30, cca ----------------------- */ void Chv_swapRows ( Chv *chv, int irow, int jrow ) ; /* -------------------------- swap columns icol and jcol created -- 98apr30, cca -------------------------- */ void Chv_swapColumns ( Chv *chv, int icol, int jcol ) ; /* ------------------------------- swap rows and columns ii and jj created -- 98apr30, cca ------------------------------- */ void Chv_swapRowsAndColumns ( Chv *chv, int ii, int jj ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in search.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------- find the first unmarked entry in the diagonal with largest magnitude if ( mark[jj] == tag ) then we can compare this entry endif created -- 98apr30, cca ----------------------------------- */ int Chv_maxabsInDiagonal11 ( Chv *chv, int mark[], int tag, double *pmaxval ) ; /* -------------------------------------------- find the first unmarked entry in row irow with largest magnitude if ( colmark[jj] == tag ) then we can examined this entry endif only entries in the (1,1) block are examined created -- 98apr30, cca -------------------------------------------- */ int Chv_maxabsInRow11 ( Chv *chv, int irow, int colmark[], int tag, double *pmaxval ) ; /* -------------------------------------------- find the first unmarked entry in column jcol with largest magnitude if ( rowmark[ii] == tag ) then we can examined this entry endif only entries in the (1,1) block are examined created -- 98apr30, cca -------------------------------------------- */ int Chv_maxabsInColumn11 ( Chv *chv, int jcol, int rowmark[], int tag, double *pmaxval ) ; /* -------------------------------------- return the location of the first entry with largest magnitude in row irow. *pmaxval is filled with its magnitude. created -- 98apr30, cca -------------------------------------- */ int Chv_maxabsInRow ( Chv *chv, int irow, double *pmaxval ) ; /* -------------------------------------- return the location of the first entry with largest magnitude in column jcol. *pmaxval is filled with its magnitude. created -- 98apr30, cca -------------------------------------- */ int Chv_maxabsInColumn ( Chv *chv, int jcol, double *pmaxval ) ; /* ------------------------------------------------------------- return the magnitude of a quasimax entry from the unmarked rows and columns and fill *pirow and *pjcol with its location created -- 98apr30, cca ------------------------------------------------------------- */ double Chv_quasimax ( Chv *chv, int rowmark[], int colmark[], int tag, int *pirow, int *pjcol ) ; /* --------------------------------------------------------------- find a 1x1 or 2x2 pivot using the fast Bunch-Parlett algorithm. used only with symmetric chevrons. created -- 98apr30, cca --------------------------------------------------------------- */ void Chv_fastBunchParlettPivot ( Chv *chv, int mark[], int tag, int *pirow, int *pjcol ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in findPivot.c ------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- find and test a pivot workDV -- object that contains work vectors tau -- upper bound on magnitude of factor entries ndelay -- number of delayed rows and columns on input pirow -- pointer to be filled with pivot row pjcol -- pointer to be filled with pivot column pntest -- pointer to be incremented with the number of pivot tests return value -- size of pivot 0 --> pivot not found 1 --> 1x1 pivot in row *pirow and column *pjcol 2 --> 2x2 pivot in rows and columns *pirow and *pjcol, symmetric front only created -- 98jan24, cca ------------------------------------------------------------------ */ int Chv_findPivot ( Chv *chv, DV *workDV, double tau, int ndelay, int *pirow, int *pjcol, int *pntest ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in fill.c ------------------------------------------ ------------------------------------------------------------------------ */ /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in assemble.c -------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------------- add a scaled multiple of a simple chevron to a Chv object. the indices are offsets. note: for this purpose, (assembling original entries into the matrix), the row and column indices of the chevron are identical. also, the indices of both the Chv object and the chvind[] vector are assumed to be in ascending order. created -- 98apr30, cca ----------------------------------------------------------------- */ void Chv_addChevron ( Chv *chv, double alpha[], int ichv, int chvsize, int chvind[], double chvent[] ) ; /* -------------------------------------------------------------- assemble Chv object chvI into Chv object chvJ. note: the two objects must be of the same symmetry type, the row indices of chvI must nest into those of chvJ, the column indices of chvI must nest into those of chvJ. created -- 98apr30, cca -------------------------------------------------------------- */ void Chv_assembleChv ( Chv *chvJ, Chv *chvI ) ; /* ---------------------------------------------------------------- purpose -- assemble the postponed data from the children newchv -- Chv object to contain fully assembled front oldchv -- Chv object that contains former front firstchild -- pointer to first child in the list of children Chv objects to be merged into the new front return value -- # of delayed rows and columns added to the front created -- 98apr30, cca ---------------------------------------------------------------- */ int Chv_assemblePostponedData ( Chv *newchv, Chv *oldchv, Chv *firstchild ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in copy.c ------------------------------------------ ------------------------------------------------------------------------ */ #define CHV_STRICT_LOWER 1 #define CHV_DIAGONAL 2 #define CHV_STRICT_UPPER 3 #define CHV_STRICT_LOWER_11 4 #define CHV_LOWER_21 5 #define CHV_STRICT_UPPER_11 6 #define CHV_UPPER_12 7 #define CHV_BY_ROWS 0 #define CHV_BY_COLUMNS 1 /* ------------------------------------------------------------------- purpose -- copy entries to a vector. length -- length of dvec[] npivot -- number of pivots, may be 0 pivotsizes -- vector of pivot sizes, may be NULL dvec[] -- vector to receive matrix entries copyflag -- flag to denote what part of the entries to copy CHV_STRICT_LOWER --> copy strict lower entries CHV_DIAGONAL --> copy diagonal entries CHV_STRICT_UPPER --> copy strict upper entries CHV_STRICT_LOWER_11 --> copy strict lower entries in (1,1) block CHV_LOWER_21 --> copy lower entries in (2,1) block CHV_STRICT_UPPER_11 --> copy strict upper entries in (1,1) block CHV_UPPER_12 --> copy upper entries in (1,2) block storeflag -- flag to denote how to store entries in dvec[] CHV_BY_ROWS --> store by rows CHV_BY_COLUMNS --> store by columns return value -- number of entries copied created -- 97jun05, cca modified -- 98feb27, cca cases 4-7 inserted ------------------------------------------------------------------- */ int Chv_copyEntriesToVector ( Chv *chv, int npivot, int pivotsizes[], int length, double *dvec, int copyflag, int storeflag ) ; /* ------------------------------------------------------------------- purpose -- copy large entries to a vector. the portion copied can be a union of the strict lower portion, the diagonal portion, and the strict upper portion. there is one restriction, if the strict lower and strict upper are to be copied, the diagonal will also be copied. npivot -- number of pivots, may be 0 pivotsizes -- vector of pivot sizes, may be NULL sizes[] -- vector to receive row/column sizes ivec[] -- vector to receive row/column indices dvec[] -- vector to receive matrix entries copyflag -- flag to denote what part of the entries to copy CHV_STRICT_LOWER --> copy strict lower entries CHV_STRICT_UPPER --> copy strict upper entries CHV_STRICT_LOWER_11 --> copy strict lower entries in (1,1) block CHV_LOWER_21 --> copy lower entries in (2,1) block CHV_STRICT_UPPER_11 --> copy strict upper entries in (1,1) block CHV_UPPER_12 --> copy upper entries in (1,2) block storeflag -- flag to denote how to store entries in dvec[] CHV_BY_ROWS --> store by rows CHV_BY_COLUMNS --> store by columns droptol -- entry to be copied must be larger than this magnitude return value -- number of entries copied created -- 97jun05, cca modified -- 97feb27, cca cases 4-7 inserted ------------------------------------------------------------------- */ int Chv_copyBigEntriesToVector ( Chv *chv, int npivot, int pivotsizes[], int sizes[], int ivec[], double dvec[], int copyflag, int storeflag, double droptol ) ; /* ------------------------------------------------------------------- purpose -- return the number of entries in a portion of the object countflag -- which entries to count CHV_STRICT_LOWER --> copy strict lower entries CHV_STRICT_UPPER --> copy strict upper entries CHV_STRICT_LOWER_11 --> copy strict lower entries in (1,1) block CHV_LOWER_21 --> copy lower entries in (2,1) block CHV_STRICT_UPPER_11 --> copy strict upper entries in (1,1) block CHV_UPPER_12 --> copy upper entries in (1,2) block created -- 98feb27, cca ------------------------------------------------------------------- */ int Chv_countEntries ( Chv *chv, int npivot, int pivotsizes[], int countflag ) ; /* ------------------------------------------------------------------- purpose -- return the number of entries whose magnitude is larger than droptol. countflag -- which entries to count CHV_STRICT_LOWER --> copy strict lower entries CHV_STRICT_UPPER --> copy strict upper entries CHV_STRICT_LOWER_11 --> copy strict lower entries in (1,1) block CHV_LOWER_21 --> copy lower entries in (2,1) block CHV_STRICT_UPPER_11 --> copy strict upper entries in (1,1) block CHV_UPPER_12 --> copy upper entries in (1,2) block created -- 97jun07, cca modified -- 98feb27, cca cases 4-7 inserted ------------------------------------------------------------------- */ int Chv_countBigEntries ( Chv *chv, int npivot, int pivotsizes[], int countflag, double droptol ) ; /* ---------------------------------------------------------- purpose -- copy the trailing chevron that starts at offset created -- 97may16, cca ---------------------------------------------------------- */ void Chv_copyTrailingPortion ( Chv *chvI, Chv *chvJ, int offset ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------- shift the indices, entries and adjust the nD dimension. note: shift can be positive or negative created -- 98apr30, cca ------------------------------------------------------- */ void Chv_shift ( Chv *chv, int shift ) ; /* ---------------------------------------------------------- return the maximum magnitude of the entries in the chevron created -- 98apr30, cca ---------------------------------------------------------- */ double Chv_maxabs ( Chv *chv ) ; /* ------------------------------------------------------- return the frobenius norm of the entries in the chevron created -- 98apr30, cca ------------------------------------------------------- */ double Chv_frobNorm ( Chv *chv ) ; /* ----------------------- subtract chvI from chvJ created -- 98apr30, cca ----------------------- */ void Chv_sub ( Chv *chvJ, Chv *chvI ) ; /* ------------------------------- zero the entries in the chevron created -- 98apr30, cca ------------------------------- */ void Chv_zero ( Chv *chv ) ; /* ------------------------------- fill A2 object with (1,1) block created -- 98apr30, cca ------------------------------- */ void Chv_fill11block ( Chv *chv, A2 *mtx ) ; /* ------------------------------- fill A2 object with (1,2) block created -- 98apr30, cca ------------------------------- */ void Chv_fill12block ( Chv *chv, A2 *mtx ) ; /* ------------------------------- fill A2 object with (2,1) block created -- 98apr30, cca ------------------------------- */ void Chv_fill21block ( Chv *chv, A2 *mtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98apr30, cca ---------------------------------------- */ void Chv_writeForHumanEye ( Chv *chv, FILE *fp ) ; /* ------------------------------------------------ purpose -- write out the entries in matlab style created -- 98apr30, cca ------------------------------------------------ */ void Chv_writeForMatlab ( Chv *chv, char *chvname, FILE *fp ) ; /*--------------------------------------------------------------------*/ of a simple chevron to a Chv object. the indices are offsets. note: for this purpose, (assembling original entries into the matrix), the row and column indices of the chevron are identical. also, the indices of both the Chv object and the chvind[] vector are assumed to be in ascending order. created -- 98apr30, cca ----------------------------------------------------------------- */ void Chv_addChevron ( Chv *chv, double alpha[], Chv/makefile010064400020550007177000000002230663622354500143210ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd drivers ; make clean cd src ; make clean cd doc ; make clean Chv/src/makefile010064400020550007177000000012220663602127700151060ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Chv $(OBJ).a : \ $(OBJ).a(assemble.o) \ $(OBJ).a(basics.o) \ $(OBJ).a(copy.o) \ $(OBJ).a(factor.o) \ $(OBJ).a(findPivot.o) \ $(OBJ).a(init.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(search.o) \ $(OBJ).a(swap.o) \ $(OBJ).a(update.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG Chv/src/makeGlobalLib010064400020550007177000000010060660026075100160070ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Chv SRC = assemble.c \ basics.c \ copy.c \ factor.c \ findPivot.c \ init.c \ instance.c \ IO.c \ search.c \ swap.c \ update.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Chv/src/IO.c010064400020550007177000000141110657126731400140640ustar00clevecompmath00000400000006/* IO.c */ #include "../Chv.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98apr30, cca ---------------------------------------- */ void Chv_writeForHumanEye ( Chv *chv, FILE *fp ) { A2 mtx ; int ierr, ncol, nD, nL, nrow, nU ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( chv == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Chv_writeForHumanEye(%p,%p)" "\n bad input\n", chv, fp) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; fprintf(fp, "\n Chv object at address %p" "\n id = %d, nD = %d, nL = %d, nU = %d, type = %d, symflag = %d", chv, chv->id, nD, nL, nU, chv->type, chv->symflag) ; if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_SYMMETRIC(chv) ) { fprintf(fp, "\n chv is real and symmetric") ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { fprintf(fp, "\n chv is real and nonsymmetric") ; } else { fprintf(fp, "\n chv has unknown symmetry type %d", chv->symflag) ; } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_SYMMETRIC(chv) ) { fprintf(fp, "\n chv is complex and symmetric") ; } else if ( CHV_IS_HERMITIAN(chv) ) { fprintf(fp, "\n chv is complex and hermitian") ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { fprintf(fp, "\n chv is complex and nonsymmetric") ; } else { fprintf(fp, "\n chv has unknown symmetry type %d", chv->symflag) ; } } else { fprintf(fp, "\n chv has unknown type %d", chv->type) ; } Chv_rowIndices(chv, &nrow, &rowind) ; if ( nrow > 0 && rowind != NULL ) { fprintf(fp, "\n chv's row indices at %p", rowind) ; IVfp80(fp, nrow, rowind, 80, &ierr) ; } Chv_columnIndices(chv, &ncol, &colind) ; if ( ncol > 0 && colind != NULL ) { fprintf(fp, "\n chv's column indices at %p", colind) ; IVfp80(fp, ncol, colind, 80, &ierr) ; } /* -------------------- load the (1,1) block -------------------- */ A2_setDefaultFields(&mtx) ; Chv_fill11block(chv, &mtx) ; fprintf(fp, "\n (1,1) block") ; A2_writeForHumanEye(&mtx, fp) ; if ( nU > 0 ) { /* -------------------- load the (1,2) block -------------------- */ Chv_fill12block(chv, &mtx) ; fprintf(fp, "\n (1,2) block") ; A2_writeForHumanEye(&mtx, fp) ; } if ( nL > 0 && CHV_IS_NONSYMMETRIC(chv) == 1 ) { /* -------------------- load the (2,1) block -------------------- */ Chv_fill21block(chv, &mtx) ; fprintf(fp, "\n (2,1) block") ; A2_writeForHumanEye(&mtx, fp) ; } A2_clearData(&mtx) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- write out the entries in matlab style created -- 98apr30, cca ------------------------------------------------ */ void Chv_writeForMatlab ( Chv *chv, char *chvname, FILE *fp ) { int irow, jcol, ncol, nD, nL, nrow, nU ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( chv == NULL || chvname == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Chv_writeForMatlab(%p,%p,%p)" "\n bad input\n", chv, chvname, fp) ; exit(-1) ; } if ( ! (CHV_IS_REAL(chv) || CHV_IS_COMPLEX(chv)) ) { fprintf(stderr, "\n fatal error in Chv_writeForMatlab(%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, chvname, fp, chv->type) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; Chv_rowIndices(chv, &nrow, &rowind) ; Chv_columnIndices(chv, &ncol, &colind) ; if ( CHV_IS_REAL(chv) ) { double value ; /* ------------------------- write out the (1,1) block ------------------------- */ for ( irow = 0 ; irow < nD ; irow++ ) { for ( jcol = 0 ; jcol < nD ; jcol++ ) { Chv_realEntry(chv, irow, jcol, &value) ; fprintf(fp, "\n %s(%d,%d) = %20.12e ;", chvname, 1+rowind[irow], 1+colind[jcol], value) ; } } /* ------------------------- write out the (1,2) block ------------------------- */ for ( irow = 0 ; irow < nD ; irow++ ) { for ( jcol = nD ; jcol < ncol ; jcol++ ) { Chv_realEntry(chv, irow, jcol, &value) ; fprintf(fp, "\n %s(%d,%d) = %20.12e ;", chvname, 1+rowind[irow], 1+colind[jcol], value) ; } } /* ------------------------- write out the (2,1) block ------------------------- */ for ( irow = nD ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < nD ; jcol++ ) { Chv_realEntry(chv, irow, jcol, &value) ; fprintf(fp, "\n %s(%d,%d) = %20.12e ;", chvname, 1+rowind[irow], 1+colind[jcol], value) ; } } } else if ( CHV_IS_COMPLEX(chv) ) { double imag, real ; /* ------------------------- write out the (1,1) block ------------------------- */ for ( irow = 0 ; irow < nD ; irow++ ) { for ( jcol = 0 ; jcol < nD ; jcol++ ) { Chv_complexEntry(chv, irow, jcol, &real, &imag) ; fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", chvname, 1+rowind[irow], 1+colind[jcol], real, imag) ; } } /* ------------------------- write out the (1,2) block ------------------------- */ for ( irow = 0 ; irow < nD ; irow++ ) { for ( jcol = nD ; jcol < ncol ; jcol++ ) { Chv_complexEntry(chv, irow, jcol, &real, &imag) ; fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", chvname, 1+rowind[irow], 1+colind[jcol], real, imag) ; } } /* ------------------------- write out the (2,1) block ------------------------- */ for ( irow = nD ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < nD ; jcol++ ) { Chv_complexEntry(chv, irow, jcol, &real, &imag) ; fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", chvname, 1+rowind[irow], 1+colind[jcol], real, imag) ; } } } return ; } /*--------------------------------------------------------------------*/ --------------------------------*/ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98apr30, cca ---------------------------------------- */ void Chv_writeForHumanEye ( Chv *chv, FILE *fp ) { A2 mtx ; int ierr, ncol, nD, nL, nrow, nU ; int *colind, *rowind ; /* --------------- check the input --------------- */ iChv/src/assemble.c010064400020550007177000000543520660321513000153440ustar00clevecompmath00000400000006/* assemble.c */ #include "../Chv.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- add a scaled multiple of a simple chevron to a Chv object. the indices are offsets. note: for this purpose, (assembling original entries into the matrix), the row and column indices of the chevron are identical. also, the indices of both the Chv object and the chvind[] vector are assumed to be in ascending order. created -- 98apr30, cca ----------------------------------------------------------------- */ void Chv_addChevron ( Chv *chv, double alpha[], int ichv, int chvsize, int chvind[], double chvent[] ) { int ii, iloc, jcol, jj, jjfirst, jjlast, ncol, nD, nL, nU, offset ; int *colind ; double *diag ; /* --------------- check the input --------------- */ if ( chv == NULL || ichv < 0 || chvsize < 0 || chvind == NULL || chvent == NULL ) { fprintf(stderr, "\n fatal error in Chv_addChevron(%p,%p,%d,%d,%p,%p)" "\n bad input\n", chv, alpha, ichv, chvsize, chvind, chvent) ; exit(-1) ; } switch ( chv->type ) { case SPOOLES_REAL : switch ( chv->symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in Chv_addChevron()" "\n type is SPOOLES_REAL, symflag = %d" "\n must be SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC\n", chv->symflag) ; exit(-1) ; break ; } case SPOOLES_COMPLEX : switch ( chv->symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in Chv_addChevron()" "\n type is SPOOLES_REAL, symflag = %d" "\n must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN" "\n or SPOOLES_NONSYMMETRIC\n", chv->symflag) ; exit(-1) ; break ; } break ; default : fprintf(stderr, "\n fatal error in Chv_addChevron()" "\n type is %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv->type) ; exit(-1) ; break ; } #if MYDEBUG > 0 fprintf(stdout, "\n alpha = %f, ichv = %d, chvsize = %d", alpha, ichv, chvsize) ; #endif if ( chvsize == 0 || (CHV_IS_REAL(chv) && alpha[0] == 0.0) || (CHV_IS_COMPLEX(chv) && (alpha[0] == 0.0 && alpha[1] == 0.0)) ) { /* ---------------------------- quick return, nothing to add ---------------------------- */ return ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n Chv_addChevron(%d): ", ichv) ; IVfprintf(stdout, chvsize, chvind) ; DVfprintf(stdout, chvsize, chvent) ; fflush(stdout) ; #endif Chv_dimensions(chv, &nD, &nL, &nU) ; Chv_columnIndices(chv, &ncol, &colind) ; /* ------------------------------------- locate the chevron in the Chv object that will accumulate these entries ------------------------------------- */ for ( iloc = 0 ; iloc < nD ; iloc++ ) { if ( colind[iloc] == ichv ) { break ; } } if ( iloc == nD ) { /* -------------------------------------------- unable to assemble these entries, error exit -------------------------------------------- */ fprintf(stderr, "\n fatal error in Chv_addChevron(%p,%d,%d,%p,%p)" "\n chevron id %d not found in colind[]", chv, ichv, chvsize, chvind, chvent, ichv) ; exit(-1) ; } if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { /* --------------------- symmetric chevron get the local indices --------------------- */ jjlast = nD + nU - 1 ; for ( ii = 0, jj = iloc ; ii < chvsize ; ii++ ) { if ( (offset = chvind[ii]) < 0 ) { fprintf(stderr, "\n fatal error in Chv_addChevron(%p,%d,%d,%p,%p)" "\n ii %d, negative offset %d\n", chv, ichv, chvsize, chvind, chvent, ii, chvind[ii]) ; IVfprintf(stderr, chvsize, chvind) ; exit(-1) ; } jcol = ichv + offset ; #if MYDEBUG > 0 fprintf(stdout, "\n ii = %d, offset = %d, jcol = %d", ii, offset, jcol) ; fflush(stdout) ; #endif while ( jj <= jjlast && jcol != colind[jj] ) { jj++ ; } #if MYDEBUG > 0 fprintf(stdout, ", jj = %d", jj) ; fflush(stdout) ; #endif if ( jj > jjlast ) { fprintf(stderr, "\n fatal error in Chv_addChevron(%p,%d,%d,%p,%p)" "\n jcol %d not found in colind[]\n", chv, ichv, chvsize, chvind, chvent, jcol) ; fprintf(stderr, "\n colind") ; IVfprintf(stderr, ncol, colind) ; fprintf(stderr, "\n chvind") ; IVfprintf(stderr, chvsize, chvind) ; exit(-1) ; } chvind[ii] = jj ; } #if MYDEBUG > 0 fprintf(stdout, "\n local indices") ; IVfprintf(stdout, chvsize, chvind) ; fflush(stdout) ; #endif /* -------------------- assemble the chevron -------------------- */ if ( CHV_IS_REAL(chv) ) { diag = Chv_diagLocation(chv, iloc) - iloc ; #if MYDEBUG > 0 fprintf(stdout, "\n ichv = %d, iloc = %d, diag = %p" "\n chv->entries = %p, diag - chv->entries = %d", ichv, iloc, diag, chv->entries, diag - chv->entries) ; fflush(stdout) ; #endif if ( alpha[0] == 1.0 ) { for ( ii = 0 ; ii < chvsize ; ii++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n location %d", &diag[chvind[ii]] - chv->entries) ; fflush(stdout) ; #endif diag[chvind[ii]] += chvent[ii] ; } } else { for ( ii = 0 ; ii < chvsize ; ii++ ) { diag[chvind[ii]] += alpha[0]*chvent[ii] ; } } } else if ( CHV_IS_COMPLEX(chv) ) { diag = Chv_diagLocation(chv, iloc) - 2*iloc ; #if MYDEBUG > 0 fprintf(stdout, "\n ichv = %d, iloc = %d, diag = %p" "\n chv->entries = %p, diag - chv->entries = %d", ichv, iloc, diag, chv->entries, diag - chv->entries) ; fflush(stdout) ; #endif if ( alpha[0] == 1.0 && alpha[1] == 0.0 ) { for ( ii = 0 ; ii < chvsize ; ii++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n location %d", &diag[chvind[ii]] - chv->entries) ; fflush(stdout) ; #endif diag[2*chvind[ii]] += chvent[2*ii] ; diag[2*chvind[ii]+1] += chvent[2*ii+1] ; } } else if ( alpha[0] != 0.0 && alpha[1] == 0.0 ) { for ( ii = 0 ; ii < chvsize ; ii++ ) { diag[2*chvind[ii]] += alpha[0]*chvent[2*ii] ; diag[2*chvind[ii]+1] += alpha[0]*chvent[2*ii+1] ; } } else if ( CHV_IS_SYMMETRIC(chv) ) { double alphareal, alphaimag, xreal, ximag ; for ( ii = 0 ; ii < chvsize ; ii++ ) { alphareal = alpha[0] ; alphaimag = alpha[1] ; xreal = chvent[2*ii] ; ximag = chvent[2*ii+1] ; diag[2*chvind[ii]] += alphareal*xreal - alphaimag*ximag ; diag[2*chvind[ii]+1] += alphareal*ximag + alphaimag*xreal ; } } else { fprintf(stderr, "\n fatal error in Chv_addChevron()" "\n chevron is hermitian, but the scalar has nonzero imaginary part" "\n sum is no longer hermitian\n") ; exit(-1) ; } } /* ------------------------------------ restore the indices to their offsets ------------------------------------ */ for ( ii = 0 ; ii < chvsize ; ii++ ) { chvind[ii] = colind[chvind[ii]] - ichv ; } #if MYDEBUG > 0 fprintf(stdout, "\n restored indices") ; IVfprintf(stdout, chvsize, chvind) ; fflush(stdout) ; #endif } else if ( CHV_IS_NONSYMMETRIC(chv) ) { /* ----------------------------------------- nonsymmetric chevron, symmetric structure overwrite chvind[] with local indices ----------------------------------------- */ jjfirst = iloc ; jjlast = nD + nU - 1 ; for ( ii = 0, jj = jjlast ; ii < chvsize ; ii++ ) { if ( (offset = chvind[ii]) >= 0 ) { break ; } jcol = ichv - offset ; while ( jj >= jjfirst && jcol != colind[jj] ) { jj-- ; } if ( jj < jjfirst ) { fprintf(stderr, "\n fatal error in Chv_addChevron(%p,%d,%d,%p,%p)" "\n jcol %d not found in colind[]\n", chv, ichv, chvsize, chvind, chvent, jcol) ; exit(-1) ; } chvind[ii] = -jj + iloc ; } for ( jj = jjfirst ; ii < chvsize ; ii++ ) { jcol = ichv + chvind[ii] ; while ( jj <= jjlast && jcol != colind[jj] ) { jj++ ; } if ( jj > jjlast ) { fprintf(stderr, "\n fatal error in Chv_addChevron(%p,%d,%d,%p,%p)" "\n jcol %d not found in colind[]\n", chv, ichv, chvsize, chvind, chvent, jcol) ; exit(-1) ; } chvind[ii] = jj - iloc ; } #if MYDEBUG > 0 fprintf(stdout, "\n local indices") ; IVfprintf(stdout, chvsize, chvind) ; fflush(stdout) ; #endif /* -------------------- assemble the chevron -------------------- */ diag = Chv_diagLocation(chv, iloc) ; #if MYDEBUG > 0 fprintf(stdout, "\n ichv = %d, iloc = %d, diag = %p" "\n chv->entries = %p, diag - chv->entries = %d", ichv, iloc, diag, chv->entries, diag - chv->entries) ; fflush(stdout) ; #endif if ( CHV_IS_REAL(chv) ) { if ( alpha[0] == 1.0 ) { for ( ii = 0 ; ii < chvsize ; ii++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n diag[%d] += %12.4e, ii = %d", chvind[ii], chvent[ii], ii) ; fflush(stdout) ; #endif diag[chvind[ii]] += chvent[ii] ; } } else { for ( ii = 0 ; ii < chvsize ; ii++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n diag[%d] += %12.4e, ii = %d", chvind[ii], chvent[ii], ii) ; fflush(stdout) ; #endif diag[chvind[ii]] += alpha[0] * chvent[ii] ; } } } else if ( CHV_IS_COMPLEX(chv) ) { if ( alpha[0] == 1.0 && alpha[1] == 0.0 ) { for ( ii = 0 ; ii < chvsize ; ii++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n diag[%d] += %12.4e, ii = %d", chvind[ii], chvent[ii], ii) ; fflush(stdout) ; #endif diag[2*chvind[ii]] += chvent[2*ii] ; diag[2*chvind[ii]+1] += chvent[2*ii+1] ; } } else if ( alpha[0] != 1.0 && alpha[1] == 0.0 ) { for ( ii = 0 ; ii < chvsize ; ii++ ) { diag[2*chvind[ii]] += alpha[0] * chvent[2*ii] ; diag[2*chvind[ii]+1] += alpha[0] * chvent[2*ii+1] ; } } else { double alphareal, alphaimag, xreal, ximag ; for ( ii = 0 ; ii < chvsize ; ii++ ) { alphareal = alpha[0] ; alphaimag = alpha[1] ; xreal = chvent[2*ii] ; ximag = chvent[2*ii+1] ; diag[2*chvind[ii]] += alphareal*xreal - alphaimag*ximag ; diag[2*chvind[ii]+1] += alphareal*ximag + alphaimag*xreal ; } } } /* ------------------------------------ restore the indices to their offsets ------------------------------------ */ for ( ii = 0 ; ii < chvsize ; ii++ ) { if ( chvind[ii] < 0 ) { chvind[ii] = ichv - colind[iloc - chvind[ii]] ; } else { chvind[ii] = colind[chvind[ii] + iloc] - ichv ; } } #if MYDEBUG > 0 fprintf(stdout, "\n restored indices") ; IVfprintf(stdout, chvsize, chvind) ; fflush(stdout) ; #endif } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- assemble Chv object chvI into Chv object chvJ. note: the two objects must be of the same symmetry type, the row indices of chvI must nest into those of chvJ, the column indices of chvI must nest into those of chvJ. created -- 98apr30, cca -------------------------------------------------------------- */ void Chv_assembleChv ( Chv *chvJ, Chv *chvI ) { double *diagI, *diagJ ; int ii, ichvI, ichvJ, jj, ncolI, ncolJ, nDI, nDJ, nLI, nLJ, nrowI, nrowJ, nUI, nUJ, offset ; int *colindJ, *colindI, *rowindI, *rowindJ ; /* --------------- check the input --------------- */ if ( chvJ == NULL || chvI == NULL ) { fprintf(stderr, "\n fatal error in Chv_assembleChv(%p,%p)" "\n bad input\n", chvJ, chvI) ; exit(-1) ; } if ( !(CHV_IS_SYMMETRIC(chvI) || CHV_IS_HERMITIAN(chvI) || CHV_IS_NONSYMMETRIC(chvI) ) ) { fprintf(stderr, "\n fatal error in Chv_assembleChv(%p,%p)" "\n bad symflag %d\n", chvJ, chvI, chvI->symflag) ; exit(-1) ; } if ( chvI->symflag != chvJ->symflag ) { fprintf(stderr, "\n fatal error in Chv_assembleChv(%p,%p)" "\n chvI->symflag = %d, chvJ->symflag = %d\n", chvJ, chvI, chvI->symflag, chvJ->symflag) ; exit(-1) ; } /* ------------------------------------- get the dimensions of the two objects ------------------------------------- */ Chv_dimensions(chvJ, &nDJ, &nLJ, &nUJ) ; Chv_dimensions(chvI, &nDI, &nLI, &nUI) ; if ( nDI + nLI > nDJ + nLJ || nDI + nUI > nDJ + nUJ ) { fprintf(stderr, "\n fatal error in Chv_assembleChv(%p,%p)" "\n bad dimensions" "\n nDI = %d, nLI = %d, nUI = %d" "\n nDI = %d, nLI = %d, nUI = %d", chvJ, chvI, nDI, nLI, nUI, nDJ, nLJ, nUJ) ; exit(-1) ; } /* ----------------- get the local ids ----------------- */ Chv_columnIndices(chvJ, &ncolJ, &colindJ) ; Chv_columnIndices(chvI, &ncolI, &colindI) ; #if MYDEBUG > 0 fprintf(stdout, "\n colindI") ; IVfprintf(stdout, ncolI, colindI) ; fprintf(stdout, "\n colindJ") ; IVfprintf(stdout, ncolJ, colindJ) ; #endif for ( ii = 0, jj = 0 ; ii < ncolI ; ii++ ) { while ( jj < ncolJ && colindI[ii] != colindJ[jj] ) { #if MYDEBUG > 0 fprintf(stdout, "\n colindI[%d] = %d, colindJ[%d] = %d", ii, colindI[ii], jj, colindJ[jj]) ; #endif jj++ ; } if ( jj == ncolJ ) { break ; } colindI[ii] = jj ; } #if MYDEBUG > 0 fprintf(stdout, "\n local column indices") ; IVfprintf(stdout, ncolI, colindI) ; #endif if ( jj == ncolJ ) { fprintf(stderr, "\n fatal error in Chv_assembleChv(%p,%p)" "\n column indicesI do not nest in indicesJ\n", chvJ, chvI) ; fprintf(stderr, "\n colindI") ; IVfprintf(stderr, ncolI, colindI) ; fprintf(stderr, "\n colindJ") ; IVfprintf(stderr, ncolJ, colindJ) ; exit(-1) ; } if ( CHV_IS_SYMMETRIC(chvJ) || CHV_IS_HERMITIAN(chvJ) ) { /* ------------------- symmetric structure ------------------- */ nrowI = ncolI ; rowindI = colindI ; } else if ( CHV_IS_NONSYMMETRIC(chvJ) ) { /* ---------------------- nonsymmetric structure ---------------------- */ Chv_rowIndices(chvJ, &nrowJ, &rowindJ) ; Chv_rowIndices(chvI, &nrowI, &rowindI) ; #if MYDEBUG > 0 fprintf(stdout, "\n rowindI") ; IVfprintf(stdout, nrowI, rowindI) ; fprintf(stdout, "\n rowindJ") ; IVfprintf(stdout, nrowJ, rowindJ) ; #endif for ( ii = 0, jj = 0 ; ii < nrowI ; ii++ ) { while ( jj < nrowJ && rowindI[ii] != rowindJ[jj] ) { jj++ ; } if ( jj == nrowJ ) { break ; } rowindI[ii] = jj ; } if ( jj == nrowJ ) { fprintf(stderr, "\n fatal error in Chv_assembleChv(%p,%p)" "\n row indicesI do not nest in indicesJ\n", chvJ, chvI) ; fprintf(stderr, "\n rowindI") ; IVfprintf(stderr, nrowI, rowindI) ; fprintf(stderr, "\n rowindJ") ; IVfprintf(stderr, nrowJ, rowindJ) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n local row indices") ; IVfprintf(stdout, nrowI, rowindI) ; #endif } #if MYDEBUG > 0 fprintf(stdout, "\n local column indices") ; IVfprintf(stdout, ncolI, colindI) ; fprintf(stdout, "\n local row indices") ; IVfprintf(stdout, nrowI, rowindI) ; #endif /* --------------------------- loop over the chevrons in I --------------------------- */ for ( ichvI = 0 ; ichvI < nDI ; ichvI++ ) { ichvJ = colindI[ichvI] ; if ( ichvJ != rowindI[ichvI] ) { fprintf(stderr, "\n fatal error in Chv_assembleChv(%p,%p)" "\n ichvI = %d, ichvJ = %d, rowindI[ichvI] = %d", chvJ, chvI, ichvI, ichvJ, rowindI[ichvI]) ; exit(-1) ; } diagI = Chv_diagLocation(chvI, ichvI) ; diagJ = Chv_diagLocation(chvJ, ichvJ) ; #if MYDEBUG > 0 fprintf(stdout, "\n ichvI = %d, diagI - entriesI = %d" "\n ichvJ = %d, diagJ - entriesJ = %d", ichvI, diagI - chvI->entries, ichvJ, diagJ - chvJ->entries) ; #endif if ( CHV_IS_REAL(chvJ) ) { diagJ[0] += diagI[0] ; } else if ( CHV_IS_COMPLEX(chvJ) ) { diagJ[0] += diagI[0] ; diagJ[1] += diagI[1] ; } if ( CHV_IS_SYMMETRIC(chvJ) || CHV_IS_HERMITIAN(chvJ) ) { /* ---------------------- symmetric or hermitian ---------------------- */ if ( CHV_IS_REAL(chvJ) ) { for ( ii = ichvI + 1, jj = 1 ; ii < ncolI ; ii++, jj++ ) { offset = colindI[ii] - ichvJ ; #if MYDEBUG > 0 fprintf(stdout, "\n ii = %d, jj = %d, offset = %d", ii, jj, offset) ; #endif diagJ[offset] += diagI[jj] ; } } else if ( CHV_IS_COMPLEX(chvJ) ) { for ( ii = ichvI + 1, jj = 1 ; ii < ncolI ; ii++, jj++ ) { offset = colindI[ii] - ichvJ ; #if MYDEBUG > 0 fprintf(stdout, "\n ii = %d, jj = %d, offset = %d", ii, jj, offset) ; #endif diagJ[2*offset] += diagI[2*jj] ; diagJ[2*offset+1] += diagI[2*jj+1] ; } } } else if ( CHV_IS_NONSYMMETRIC(chvJ) ) { /* ------------ nonsymmetric ------------ */ if ( CHV_IS_REAL(chvJ) ) { for ( ii = ichvI + 1, jj = 1 ; ii < ncolI ; ii++, jj++ ) { offset = colindI[ii] - ichvJ ; #if MYDEBUG > 0 fprintf(stdout, "\n diagJ[%d] += diagI[%d]", offset, jj) ; #endif diagJ[offset] += diagI[jj] ; } for ( ii = ichvI + 1, jj = -1 ; ii < nrowI ; ii++, jj-- ) { offset = rowindI[ii] - ichvJ ; #if MYDEBUG > 0 fprintf(stdout, "\n diagJ[%d] += diagI[%d]", -offset, jj) ; #endif diagJ[-offset] += diagI[jj] ; } } else if ( CHV_IS_COMPLEX(chvJ) ) { for ( ii = ichvI + 1, jj = 1 ; ii < ncolI ; ii++, jj++ ) { offset = colindI[ii] - ichvJ ; #if MYDEBUG > 0 fprintf(stdout, "\n diagJ[%d] += diagI[%d]", offset, jj) ; #endif diagJ[2*offset] += diagI[2*jj] ; diagJ[2*offset+1] += diagI[2*jj+1] ; } for ( ii = ichvI + 1, jj = -1 ; ii < nrowI ; ii++, jj-- ) { offset = rowindI[ii] - ichvJ ; #if MYDEBUG > 0 fprintf(stdout, "\n diagJ[%d] += diagI[%d]", -offset, jj) ; #endif diagJ[-2*offset] += diagI[2*jj] ; diagJ[-2*offset+1] += diagI[2*jj+1] ; } } } } /* ------------------- restore the indices ------------------- */ for ( ii = 0 ; ii < ncolI ; ii++ ) { colindI[ii] = colindJ[colindI[ii]] ; } if ( CHV_IS_NONSYMMETRIC(chvJ) ) { for ( ii = 0 ; ii < nrowI ; ii++ ) { rowindI[ii] = rowindJ[rowindI[ii]] ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- assemble the postponed data from the children newchv -- Chv object to contain fully assembled front oldchv -- Chv object that contains former front firstchild -- pointer to first child in the list of children Chv objects to be merged into the new front return value -- # of delayed rows and columns added to the front created -- 98apr30, cca ---------------------------------------------------------------- */ int Chv_assemblePostponedData ( Chv *newchv, Chv *oldchv, Chv *firstchild ) { Chv *child ; int ierr, ndelay ; /* --------------- check the input --------------- */ if ( newchv == NULL || oldchv == NULL || firstchild == NULL ) { fprintf(stderr, "\n fatal error in Chv_assemblePostponedData(%p,%p,%p)" "\n bad input\n", newchv, oldchv, firstchild) ; exit(-1) ; } Chv_zero(newchv) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n inside Chv_assemblePostponedData, J = %d", oldchv->id) ; fprintf(stdout, "\n\n old chevron %d", oldchv->id) ; Chv_writeForHumanEye(oldchv, stdout) ; for ( child = firstchild ; child != NULL ; child = child->next ) { fprintf(stdout, "\n\n child %d", child->id) ; Chv_writeForHumanEye(child, stdout) ; } fprintf(stdout, "\n\n new chevron %d", newchv->id) ; Chv_writeForHumanEye(newchv, stdout) ; fflush(stdout) ; #endif /* ------------------------------------ copy the indices into the new object ------------------------------------ */ ndelay = 0 ; for ( child = firstchild ; child != NULL ; child = child->next ) { IVcopy(child->nD, newchv->colind + ndelay, child->colind) ; ndelay += child->nD ; } IVcopy(oldchv->nD + oldchv->nU, newchv->colind + ndelay, oldchv->colind) ; #if MYDEBUG > 0 fprintf(stdout, "\n ndelay = %d, new column indices", ndelay) ; IVfp80(stdout, newchv->nD + newchv->nU, newchv->colind, 80, &ierr) ; fflush(stdout) ; #endif if ( CHV_IS_NONSYMMETRIC(newchv) ) { ndelay = 0 ; for ( child = firstchild ; child != NULL ; child = child->next ) { IVcopy(child->nD, newchv->rowind + ndelay, child->rowind) ; ndelay += child->nD ; } IVcopy(oldchv->nD + oldchv->nU, newchv->rowind + ndelay, oldchv->rowind) ; #if MYDEBUG > 0 fprintf(stdout, "\n ndelay = %d, new row indices", ndelay) ; IVfp80(stdout, newchv->nD + newchv->nL, newchv->rowind, 80, &ierr) ; fflush(stdout) ; #endif } /* ------------------------ assemble the old chevron ------------------------ */ Chv_assembleChv(newchv, oldchv) ; #if MYDEBUG > 0 fprintf(stdout, "\n after merging old chevron") ; Chv_writeForHumanEye(newchv, stdout) ; #endif /* ------------------------------ assemble the children chevrons ------------------------------ */ for ( child = firstchild ; child != NULL ; child = child->next ) { Chv_assembleChv(newchv, child) ; #if MYDEBUG > 0 fprintf(stdout, "\n after merging child %d", child->id) ; Chv_writeForHumanEye(newchv, stdout) ; #endif } return(ndelay) ; } /*--------------------------------------------------------------------*/ || chvI == NULL ) { fprintf(stderr, "\n fatal error in Chv_assembleChv(%p,%p)" "\n bad input\n", chvJ, chvI) ; exit(-1) ; } if ( !(CHV_IS_SYMMETRIC(chvI) || CHV_IS_HERMITIAN(chvI) || CHV_IS_NONSYMMETRIC(chvI) ) ) { fprintf(stderr, "\n fatal Chv/src/basics.c010064400020550007177000000043670657126731400150350ustar00clevecompmath00000400000006/* basics.c */ #include "../Chv.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98apr30, cca ----------------------- */ Chv * Chv_new ( void ) { Chv *chv ; ALLOCATE(chv, struct _Chv, 1) ; Chv_setDefaultFields(chv) ; return(chv) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98apr30, cca ----------------------- */ void Chv_setDefaultFields ( Chv *chv ) { if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_setDefaultFields(%p)" "\n bad input", chv) ; exit(-1) ; } chv->id = -1 ; chv->nD = 0 ; chv->nL = 0 ; chv->nU = 0 ; chv->type = SPOOLES_REAL ; chv->symflag = SPOOLES_SYMMETRIC ; DV_setDefaultFields(&chv->wrkDV) ; chv->rowind = NULL ; chv->colind = NULL ; chv->entries = NULL ; chv->next = NULL ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98apr30, cca -------------------------------------------------- */ void Chv_clearData ( Chv *chv ) { /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_clearData(%p)" "\n bad input\n", chv) ; exit(-1) ; } /* ------------------------ free the working storage ------------------------ */ DV_clearData(&chv->wrkDV) ; /* ---------------------- set the default fields ---------------------- */ Chv_setDefaultFields(chv) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98apr30, cca ------------------------------------------ */ void Chv_free ( Chv *chv ) { if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_free(%p)" "\n bad input\n", chv) ; exit(-1) ; } Chv_clearData(chv) ; FREE(chv) ; return ; } /*--------------------------------------------------------------------*/ Chv/src/copy.c010064400020550007177000003303460657126731300145410ustar00clevecompmath00000400000006/* copyEntriesToVector.c */ #include "../Chv.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- copy entries to a vector. length -- length of dvec[] npivot -- number of pivots, may be 0 pivotsizes -- vector of pivot sizes, may be NULL dvec[] -- vector to receive matrix entries copyflag -- flag to denote what part of the entries to copy CHV_STRICT_LOWER --> copy strict lower entries CHV_DIAGONAL --> copy diagonal entries CHV_STRICT_UPPER --> copy strict upper entries CHV_STRICT_LOWER_11 --> copy strict lower entries in (1,1) block CHV_LOWER_21 --> copy lower entries in (2,1) block CHV_STRICT_UPPER_11 --> copy strict upper entries in (1,1) block CHV_UPPER_12 --> copy upper entries in (1,2) block storeflag -- flag to denote how to store entries in dvec[] CHV_BY_ROWS --> store by rows CHV_BY_COLUMNS --> store by columns return value -- number of entries copied created -- 97jun05, cca modified -- 98feb27, cca cases 4-7 inserted ------------------------------------------------------------------- */ int Chv_copyEntriesToVector ( Chv *chv, int npivot, int pivotsizes[], int length, double *dvec, int copyflag, int storeflag ) { double *entries ; int mm, ncol, nD, nent, nL, nrow, nU, symflag ; /* -------------------------------------------- check the input, get dimensions and pointers and check that length is large enough -------------------------------------------- */ if ( chv == NULL || length < 0 || dvec == NULL ) { fprintf(stderr, "\n fatal error in Chv_copyEntriesToVector(%p,%d,%p,,%d,%d)" "\n bad input\n", chv, length, dvec, copyflag, storeflag) ; exit(-1) ; } switch ( copyflag ) { case CHV_STRICT_LOWER : case CHV_DIAGONAL : case CHV_STRICT_UPPER : case CHV_STRICT_LOWER_11 : case CHV_LOWER_21 : case CHV_STRICT_UPPER_11 : case CHV_UPPER_12 : break ; default : fprintf(stderr, "\n fatal error in Chv_copyEntriesToVector(%p,%d,%p,%d,%d)" "\n bad input\n" "\n copyflag = %d, must be\n" "\n CHV_STRICT_LOWER --> copy strict lower entries" "\n CHV_DIAGONAL --> copy diagonal entries" "\n CHV_STRICT_UPPER --> copy strict upper entries" "\n CHV_STRICT_LOWER_11 --> copy strict lower entries in (1,1) block" "\n CHV_LOWER_21 --> copy lower entries in (2,1) block" "\n CHV_STRICT_UPPER_11 --> copy strict upper entries in (1,1) block" "\n CHV_UPPER_12 --> copy upper entries in (1,2) block" "\n", chv, length, dvec, copyflag, storeflag, copyflag) ; exit(-1) ; break ; } switch ( storeflag ) { case CHV_BY_ROWS : case CHV_BY_COLUMNS : break ; default : fprintf(stderr, "\n fatal error in Chv_copyEntriesToVector(%p,%d,%p,%d,%d)" "\n bad input\n" "\n storeflag = %d, must be\n" "\n CHV_BY_ROWS --> store by rows" "\n CHV_BY_COLUMNS --> store by columns" "\n", chv, length, dvec, copyflag, storeflag, storeflag) ; exit(-1) ; break ; } nD = chv->nD ; nL = chv->nL ; nU = chv->nU ; symflag = chv->symflag ; nrow = nD + nL ; ncol = nD + nU ; /* ------------------------------------------ compute the number of entries to be copied ------------------------------------------ */ switch ( copyflag ) { case CHV_STRICT_LOWER : /* strictly lower entries */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { fprintf(stderr, "\n fatal error in Chv_copyEntriesToVector(%p,%d,%p,%d,%d)" "\n symflag = %d, copyflag = %d", chv, length, dvec, copyflag, storeflag, symflag, copyflag) ; exit(-1) ; } nent = (nD*(nD-1))/2 + nD*nL ; break ; case CHV_DIAGONAL : /* diagonal entries */ if ( pivotsizes == NULL ) { nent = nD ; } else { int ipivot ; for ( ipivot = nent = 0 ; ipivot < npivot ; ipivot++ ) { nent += (pivotsizes[ipivot]*(pivotsizes[ipivot] + 1))/2 ; } } break ; case CHV_STRICT_UPPER : /* strictly upper entries */ if ( pivotsizes == NULL ) { nent = (nD*(nD-1))/2 + nD*nU ; } else { int first, ipivot ; for ( ipivot = first = nent = 0 ; ipivot < npivot ; ipivot++ ) { nent += first * pivotsizes[ipivot] ; first += pivotsizes[ipivot] ; } } break ; case CHV_STRICT_LOWER_11 : /* strictly lower entries in (1,1) block */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { fprintf(stderr, "\n fatal error in Chv_copyEntriesToVector(%p,%d,%p,%d,%d)" "\n symflag = %d, copyflag = %d", chv, length, dvec, copyflag, storeflag, symflag, copyflag) ; exit(-1) ; } nent = (nD*(nD-1))/2 ; break ; case CHV_LOWER_21 : /* lower entries in (2,1) block */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { fprintf(stderr, "\n fatal error in Chv_copyEntriesToVector(%p,%d,%p,%d,%d)" "\n symflag = %d, copyflag = %d", chv, length, dvec, copyflag, storeflag, symflag, copyflag) ; exit(-1) ; } nent = nD*nL ; break ; case CHV_STRICT_UPPER_11 : /* strictly upper entries in (1,1) block */ if ( pivotsizes == NULL ) { nent = (nD*(nD-1))/2 ; } else { int first, ipivot ; for ( ipivot = first = nent = 0 ; ipivot < npivot ; ipivot++ ) { nent += first * pivotsizes[ipivot] ; first += pivotsizes[ipivot] ; } } break ; case CHV_UPPER_12 : /* upper entries in (1,2) block */ nent = nD*nU ; break ; default : break ; } if ( nent > length ) { fprintf(stderr, "\n fatal error in Chv_copyEntriesToVector(%p,%d,%p,%d,%d)" "\n nent = %d, buffer length = %d", chv, length, dvec, copyflag, storeflag, nent, length) ; exit(-1) ; } /* -------------------------------------------- make life simple, unit stride through dvec[] -------------------------------------------- */ entries = Chv_entries(chv) ; mm = 0 ; switch ( copyflag ) { case CHV_STRICT_LOWER : /* ---------------------------------------- copy lower entries, pivotsizes[] is NULL ---------------------------------------- */ switch ( storeflag ) { case CHV_BY_ROWS : { /* ------------- store by rows ------------- */ int ii, jj, jjlast, kinc, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; jjlast = (ii < nD) ? (ii - 1) : (nD - 1) ; for ( jj = 0 ; jj <= jjlast ; jj++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc -= 2 ; } kstart-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; jjlast = (ii < nD) ? (ii - 1) : (nD - 1) ; for ( jj = 0 ; jj <= jjlast ; jj++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc -= 2 ; } kstart-- ; } } } break ; case CHV_BY_COLUMNS : { /* ---------------- store by columns ---------------- */ int ii, jj, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 2 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart - 1 ; for ( ii = jj + 1 ; ii < nrow ; ii++, kk--, mm++ ) { dvec[mm] = entries[kk] ; } kstart += stride ; stride -= 2 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart - 1 ; for ( ii = jj + 1 ; ii < nrow ; ii++, kk--, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride -= 2 ; } } } break ; } break ; case CHV_DIAGONAL : /* --------------------- copy diagonal entries --------------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int first, ii, jj, ipivot, kk, kstart, last, stride ; stride = nD + nU ; kstart = 0 ; if ( pivotsizes == NULL ) { if ( CHV_IS_REAL(chv) ) { for ( ii = 0, kk = kstart ; ii < nD ; ii++, mm++ ) { dvec[mm] = entries[kk] ; kk += stride ; stride-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0, kk = kstart ; ii < nD ; ii++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += stride ; stride-- ; } } } else { if ( CHV_IS_REAL(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( ii = first ; ii <= last ; ii++ ) { for ( jj = ii, kk = kstart ; jj <= last ; jj++, mm++, kk++ ) { dvec[mm] = entries[kk] ; } kstart += stride ; stride-- ; } } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( ii = first ; ii <= last ; ii++ ) { for ( jj = ii, kk = kstart ; jj <= last ; jj++, mm++, kk++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride-- ; } } } } } else { int ii, kk, stride ; kk = nD + nL - 1 ; stride = 2*nD + nL + nU - 2 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++, mm++ ) { dvec[mm] = entries[kk] ; kk += stride ; stride -= 2 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += stride ; stride -= 2 ; } } } break ; case CHV_STRICT_UPPER : /* ------------------------- copy strict upper entries ------------------------- */ switch ( storeflag ) { case CHV_BY_ROWS : /* ------------- store by rows ------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int first, ii, ipivot, jj, kk, kstart, last, stride ; kstart = 0 ; stride = nD + nU ; if ( pivotsizes == NULL ) { if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1 ; jj < ncol ; jj++, kk++, mm++ ) { dvec[mm] = entries[kk] ; } kstart += stride ; stride-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1 ; jj < ncol ; jj++, kk++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride-- ; } } } else { if ( CHV_IS_REAL(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( ii = first ; ii <= last ; ii++ ) { kk = kstart + last - ii + 1 ; for ( jj = last + 1 ; jj < ncol ; jj++, kk++, mm++ ) { dvec[mm] = entries[kk] ; } kstart += stride ; stride-- ; } first = last + 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( ii = first ; ii <= last ; ii++ ) { kk = kstart + last - ii + 1 ; for ( jj = last + 1 ; jj < ncol ; jj++, kk++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride-- ; } first = last + 1 ; } } } } else { int ii, jj, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 2 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1 ; jj < ncol ; jj++, kk++, mm++ ) { dvec[mm] = entries[kk] ; } kstart += stride ; stride -= 2 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1 ; jj < ncol ; jj++, kk++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride -= 2 ; } } } break ; case CHV_BY_COLUMNS : /* ---------------- store by columns ---------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int first, ii, iilast, ipivot, jj, kinc, kk, kstart, last, stride ; kstart = 0 ; stride = nD + nU - 1 ; if ( pivotsizes == NULL ) { if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc-- ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc-- ; } kstart++ ; } } } else { if ( CHV_IS_REAL(chv) ) { for ( ipivot = mm = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < first ; ii++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc-- ; } kstart++ ; } first = last + 1 ; } for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc-- ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = mm = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < first ; ii++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc-- ; } kstart++ ; } first = last + 1 ; } for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc-- ; } kstart++ ; } } } } else { int ii, iilast, jj, kinc, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 3 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc -= 2 ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc -= 2 ; } kstart++ ; } } } break ; default : break ; } break ; case CHV_STRICT_LOWER_11 : /* -------------------------------------------------------------- copy strict lower entries in (1,1) block, pivotsizes[] is NULL -------------------------------------------------------------- */ switch ( storeflag ) { case CHV_BY_ROWS : { /* ------------- store by rows ------------- */ int ii, jj, jjlast, kinc, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; kinc = stride ; jjlast = ii - 1 ; for ( jj = 0 ; jj <= jjlast ; jj++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc -= 2 ; } kstart-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; kinc = stride ; jjlast = ii - 1 ; for ( jj = 0 ; jj <= jjlast ; jj++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc -= 2 ; } kstart-- ; } } } break ; case CHV_BY_COLUMNS : { /* ---------------- store by columns ---------------- */ int ii, jj, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 2 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart - 1 ; for ( ii = jj + 1 ; ii < nD ; ii++, kk--, mm++ ) { dvec[mm] = entries[kk] ; } kstart += stride ; stride -= 2 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart - 1 ; for ( ii = jj + 1 ; ii < nD ; ii++, kk--, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride -= 2 ; } } } break ; } break ; case CHV_LOWER_21 : /* --------------------------------- copy lower entries in (2,1) block --------------------------------- */ switch ( storeflag ) { case CHV_BY_ROWS : { /* ------------- store by rows ------------- */ int ii, jj, kinc, kk, kstart, stride ; kstart = nL - 1 ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = nD, mm = 0 ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; for ( jj = 0 ; jj < nD ; jj++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc -= 2 ; } kstart-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = nD, mm = 0 ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; for ( jj = 0 ; jj < nD ; jj++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc -= 2 ; } kstart-- ; } } } break ; case CHV_BY_COLUMNS : { /* ---------------- store by columns ---------------- */ int ii, jj, kk, kstart, stride ; kstart = nL - 1 ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; for ( ii = nD ; ii < nrow ; ii++, kk--, mm++ ) { dvec[mm] = entries[kk] ; } kstart += stride ; stride -= 2 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; for ( ii = nD ; ii < nrow ; ii++, kk--, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride -= 2 ; } } } break ; } break ; case CHV_STRICT_UPPER_11 : /* ---------------------------------------- copy strict upper entries in (1,1) block ---------------------------------------- */ switch ( storeflag ) { case CHV_BY_ROWS : /* ------------- store by rows ------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int first, ii, ipivot, jj, kk, kstart, last, stride ; kstart = 0 ; stride = nD + nU ; if ( pivotsizes == NULL ) { if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1 ; jj < nD ; jj++, kk++, mm++ ) { dvec[mm] = entries[kk] ; } kstart += stride ; stride-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1 ; jj < nD ; jj++, kk++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride-- ; } } } else { if ( CHV_IS_REAL(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( ii = first ; ii <= last ; ii++ ) { kk = kstart + last - ii + 1 ; for ( jj = last + 1 ; jj < nD ; jj++, kk++, mm++ ){ dvec[mm] = entries[kk] ; } kstart += stride ; stride-- ; } first = last + 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( ii = first ; ii <= last ; ii++ ) { kk = kstart + last - ii + 1 ; for ( jj = last + 1 ; jj < nD ; jj++, kk++, mm++ ){ dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride-- ; } first = last + 1 ; } } } } else { int ii, jj, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 2 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1 ; jj < nD ; jj++, kk++, mm++ ) { dvec[mm] = entries[kk] ; } kstart += stride ; stride -= 2 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1 ; jj < nD ; jj++, kk++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride -= 2 ; } } } break ; case CHV_BY_COLUMNS : /* ---------------- store by columns ---------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int first, ii, iilast, ipivot, jj, kinc, kk, kstart, last, stride ; kstart = 0 ; stride = nD + nU - 1 ; if ( pivotsizes == NULL ) { if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc-- ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc-- ; } kstart++ ; } } } else { if ( CHV_IS_REAL(chv) ) { for ( ipivot = mm = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < first ; ii++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc-- ; } kstart++ ; } first = last + 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = mm = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < first ; ii++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc-- ; } kstart++ ; } first = last + 1 ; } } } } else { int ii, jj, kinc, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 3 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < jj ; ii++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc -= 2 ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < jj ; ii++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc -= 2 ; } kstart++ ; } } } break ; default : break ; } break ; case CHV_UPPER_12 : /* --------------------------------- copy upper entries in (1,2) block --------------------------------- */ switch ( storeflag ) { case CHV_BY_ROWS : /* ------------- store by rows ------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int ii, jj, kk, kstart, stride ; kstart = nD ; stride = nD + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; for ( jj = 0 ; jj < nU ; jj++, kk++, mm++ ) { dvec[mm] = entries[kk] ; } kstart += stride ; stride-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; for ( jj = 0 ; jj < nU ; jj++, kk++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride-- ; } } } else { int ii, jj, kk, kstart, stride ; kstart = 2*nD + nL - 1 ; stride = 2*nD + nL + nU - 3 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; for ( jj = nD ; jj < ncol ; jj++, kk++, mm++ ) { dvec[mm] = entries[kk] ; } kstart += stride ; stride -= 2 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; for ( jj = nD ; jj < ncol ; jj++, kk++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; } kstart += stride ; stride -= 2 ; } } } break ; case CHV_BY_COLUMNS : /* ---------------- store by columns ---------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int ii, jj, kinc, kk, kstart, stride ; kstart = nD ; stride = nD + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc-- ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc-- ; } kstart++ ; } } } else { int ii, jj, kinc, kk, kstart, stride ; kstart = 2*nD + nL - 1 ; stride = 2*nD + nL + nU - 3 ; if ( CHV_IS_REAL(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++, mm++ ) { dvec[mm] = entries[kk] ; kk += kinc ; kinc -= 2 ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++, mm++ ) { dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; kk += kinc ; kinc -= 2 ; } kstart++ ; } } } break ; default : break ; } break ; default : break ; } return(mm) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- copy large entries to a vector. the portion copied can be a union of the strict lower portion, the diagonal portion, and the strict upper portion. there is one restriction, if the strict lower and strict upper are to be copied, the diagonal will also be copied. npivot -- number of pivots, may be 0 pivotsizes -- vector of pivot sizes, may be NULL sizes[] -- vector to receive row/column sizes ivec[] -- vector to receive row/column indices dvec[] -- vector to receive matrix entries copyflag -- flag to denote what part of the entries to copy CHV_STRICT_LOWER --> copy strict lower entries CHV_STRICT_UPPER --> copy strict upper entries CHV_STRICT_LOWER_11 --> copy strict lower entries in (1,1) block CHV_LOWER_21 --> copy lower entries in (2,1) block CHV_STRICT_UPPER_11 --> copy strict upper entries in (1,1) block CHV_UPPER_12 --> copy upper entries in (1,2) block storeflag -- flag to denote how to store entries in dvec[] CHV_BY_ROWS --> store by rows CHV_BY_COLUMNS --> store by columns droptol -- entry to be copied must be larger than this magnitude return value -- number of entries copied created -- 97jun05, cca modified -- 97feb27, cca cases 4-7 inserted ------------------------------------------------------------------- */ int Chv_copyBigEntriesToVector ( Chv *chv, int npivot, int pivotsizes[], int sizes[], int ivec[], double dvec[], int copyflag, int storeflag, double droptol ) { double absval ; double *entries ; int mm, ncol, nD, nL, nrow, nU, symflag ; /* -------------------------------------------- check the input, get dimensions and pointers -------------------------------------------- */ if ( chv == NULL || sizes == NULL || ivec == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in Chv_copyBigEntriesToVector()" "\n chv %p, sizes %p, ivec %p, dvec %p" "\n bad input\n", chv, sizes, ivec, dvec) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n %% inside Chv_copyBigEntries, copyflag %d, storeflag %d", copyflag, storeflag) ; fflush(stdout) ; #endif switch ( copyflag ) { case CHV_STRICT_LOWER : case CHV_STRICT_UPPER : case CHV_STRICT_LOWER_11 : case CHV_LOWER_21 : case CHV_STRICT_UPPER_11 : case CHV_UPPER_12 : break ; default : fprintf(stderr, "\n fatal error in Chv_copyBigEntriesToVector(%p,%p,%p,%p,%d,%d)" "\n bad input\n" "\n copyflag = %d, must be\n" "\n 1 --> strictly lower entries" "\n 3 --> strictly upper entries" "\n 4 --> copy strict lower entries in (1,1) block" "\n 5 --> copy lower entries in (2,1) block" "\n 6 --> copy strict upper entries in (1,1) block" "\n 7 --> copy upper entries in (1,2) block", chv, sizes, ivec, dvec, copyflag, storeflag, copyflag) ; exit(-1) ; } if ( storeflag < 0 || storeflag > 1 ) { fprintf(stderr, "\n fatal error in Chv_copyBigEntriesToVector(%p,%p,%p,%p,%d,%d)" "\n bad input\n" "\n storeflag = %d, must be\n" "\n 0 --> store by rows" "\n 1 --> store by columns", chv, sizes, ivec, dvec, copyflag, storeflag, storeflag) ; exit(-1) ; } nD = chv->nD ; nL = chv->nL ; nU = chv->nU ; symflag = chv->symflag ; nrow = nD + nL ; ncol = nD + nU ; /* -------------------------------------------- make life simple, unit stride through dvec[] -------------------------------------------- */ entries = Chv_entries(chv) ; mm = 0 ; switch ( copyflag ) { case CHV_STRICT_LOWER : /* ---------------------------------------- copy lower entries, pivotsizes[] is NULL ---------------------------------------- */ switch ( storeflag ) { case CHV_BY_ROWS : { /* ------------- store by rows ------------- */ int count, ii, jj, jjlast, kinc, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; jjlast = (ii < nD) ? (ii - 1) : (nD - 1) ; for ( jj = count = 0 ; jj <= jjlast ; jj++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = jj ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } sizes[ii] = count ; kstart-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; jjlast = (ii < nD) ? (ii - 1) : (nD - 1) ; for ( jj = count = 0 ; jj <= jjlast ; jj++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = jj ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } sizes[ii] = count ; kstart-- ; } } } break ; case CHV_BY_COLUMNS : { /* ---------------- store by columns ---------------- */ int count, ii, jj, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 2 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart - 1 ; for ( ii = jj + 1, count = 0 ; ii < nrow ; ii++, kk-- ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } } kstart += stride ; stride -= 2 ; sizes[jj] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart - 1 ; for ( ii = jj + 1, count = 0 ; ii < nrow ; ii++, kk-- ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } } kstart += stride ; stride -= 2 ; sizes[jj] = count ; } } } break ; } break ; case CHV_STRICT_UPPER : /* ------------------------- copy strict upper entries ------------------------- */ switch ( storeflag ) { case CHV_BY_ROWS : /* ------------- store by rows ------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int count, first, ii, ipivot, jj, kk, kstart, last, stride ; kstart = 0 ; stride = nD + nU ; if ( pivotsizes == NULL ) { if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1, count = 0 ; jj < ncol ; jj++, kk++ ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[mm] = entries[kk] ; mm++, count++ ; } } kstart += stride ; stride-- ; sizes[ii] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1, count = 0 ; jj < ncol ; jj++, kk++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } } kstart += stride ; stride-- ; sizes[ii] = count ; } } } else { if ( CHV_IS_REAL(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( ii = first ; ii <= last ; ii++ ) { kk = kstart + last - ii + 1 ; for ( jj = last + 1, count = 0 ; jj < ncol ; jj++, kk++ ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[mm] = entries[kk] ; mm++, count++ ; } } kstart += stride ; stride-- ; sizes[ii] = count ; } first = last + 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( ii = first ; ii <= last ; ii++ ) { kk = kstart + last - ii + 1 ; for ( jj = last + 1, count = 0 ; jj < ncol ; jj++, kk++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } } kstart += stride ; stride-- ; sizes[ii] = count ; } first = last + 1 ; } } } } else { int count, ii, jj, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 2 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1, count = 0 ; jj < ncol ; jj++, kk++ ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[mm] = entries[kk] ; mm++, count++ ; } } kstart += stride ; stride -= 2 ; sizes[ii] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1, count = 0 ; jj < ncol ; jj++, kk++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } } kstart += stride ; stride -= 2 ; sizes[ii] = count ; } } } break ; case CHV_BY_COLUMNS : /* ---------------- store by columns ---------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int count, first, ii, iilast, ipivot, jj, kinc, kk, kstart, last, stride ; kstart = 0 ; stride = nD + nU - 1 ; if ( pivotsizes == NULL ) { if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = count = 0 ; ii <= iilast ; ii++ ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = count = 0 ; ii <= iilast ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj] = count ; } } } else { if ( CHV_IS_REAL(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = count = 0 ; ii < first ; ii++ ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj] = count ; } first = last + 1 ; } for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = count = 0 ; ii < nD ; ii++ ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = count = 0 ; ii < first ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj] = count ; } first = last + 1 ; } for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = count = 0 ; ii < nD ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj] = count ; } } } } else { int count, ii, iilast, jj, kinc, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 3 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = count = 0 ; ii <= iilast ; ii++ ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; sizes[jj] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = count = 0 ; ii <= iilast ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; sizes[jj] = count ; } } } break ; default : break ; } break ; case CHV_STRICT_LOWER_11 : /* ------------------------------------------------ copy entries in strict lower part of (1,1) block ------------------------------------------------ */ switch ( storeflag ) { case CHV_BY_ROWS : { /* ------------- store by rows ------------- */ int count, ii, jj, jjlast, kinc, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; kinc = stride ; jjlast = (ii < nD) ? (ii - 1) : (nD - 1) ; for ( jj = count = 0 ; jj <= jjlast ; jj++ ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } sizes[ii] = count ; kstart-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; kinc = stride ; jjlast = (ii < nD) ? (ii - 1) : (nD - 1) ; for ( jj = count = 0 ; jj <= jjlast ; jj++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } sizes[ii] = count ; kstart-- ; } } } break ; case CHV_BY_COLUMNS : { /* ---------------- store by columns ---------------- */ int count, ii, jj, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 2 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart - 1 ; for ( ii = jj + 1, count = 0 ; ii < nD ; ii++, kk-- ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } } kstart += stride ; stride -= 2 ; sizes[jj] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart - 1 ; for ( ii = jj + 1, count = 0 ; ii < nD ; ii++, kk-- ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } } kstart += stride ; stride -= 2 ; sizes[jj] = count ; } } } break ; } break ; case CHV_LOWER_21 : /* --------------------------- copy entries in (2,1) block --------------------------- */ switch ( storeflag ) { case CHV_BY_ROWS : { /* ------------- store by rows ------------- */ int count, ii, jj, kinc, kk, kstart, stride ; kstart = nL - 1 ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = nD ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; for ( jj = count = 0 ; jj < nD ; jj++ ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } sizes[ii-nD] = count ; kstart-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = nD ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; for ( jj = count = 0 ; jj < nD ; jj++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } sizes[ii-nD] = count ; kstart-- ; } } } break ; case CHV_BY_COLUMNS : { /* ---------------- store by columns ---------------- */ int count, ii, jj, kk, kstart, stride ; kstart = nL - 1 ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; for ( ii = nD, count = 0 ; ii < nrow ; ii++, kk-- ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } } kstart += stride ; stride -= 2 ; sizes[jj] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; for ( ii = nD, count = 0 ; ii < nrow ; ii++, kk-- ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } } kstart += stride ; stride -= 2 ; sizes[jj] = count ; } } } break ; } break ; case CHV_STRICT_UPPER_11 : /* ---------------------------------------- copy strict upper entries in (1,1) block ---------------------------------------- */ switch ( storeflag ) { case CHV_BY_ROWS : /* ------------- store by rows ------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int count, first, ii, ipivot, jj, kk, kstart, last, stride ; kstart = 0 ; stride = nD + nU ; if ( pivotsizes == NULL ) { if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1, count = 0 ; jj < nD ; jj++, kk++ ){ absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = jj ; dvec[mm] = entries[kk] ; mm++, count++ ; } } kstart += stride ; stride-- ; sizes[ii] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1, count = 0 ; jj < nD ; jj++, kk++ ){ absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = jj ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } } kstart += stride ; stride-- ; sizes[ii] = count ; } } } else { if ( CHV_IS_REAL(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( ii = first ; ii <= last ; ii++ ) { kk = kstart + last - ii + 1 ; for ( jj = last + 1, count = 0 ; jj < nD ; jj++, kk++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = jj ; dvec[mm] = entries[kk] ; mm++, count++ ; } } kstart += stride ; stride-- ; sizes[ii] = count ; } first = last + 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( ii = first ; ii <= last ; ii++ ) { kk = kstart + last - ii + 1 ; for ( jj = last + 1, count = 0 ; jj < nD ; jj++, kk++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = jj ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } } kstart += stride ; stride-- ; sizes[ii] = count ; } first = last + 1 ; } } } } else { int count, ii, jj, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 2 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1, count = 0 ; jj < nD ; jj++, kk++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% A(%d,%d) = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = jj ; dvec[mm] = entries[kk] ; mm++, count++ ; } } kstart += stride ; stride -= 2 ; sizes[ii] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart + 1 ; for ( jj = ii + 1, count = 0 ; jj < nD ; jj++, kk++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% A(%d,%d) = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = jj ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } } kstart += stride ; stride -= 2 ; sizes[ii] = count ; } } } break ; case CHV_BY_COLUMNS : /* ---------------- store by columns ---------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int count, first, ii, iilast, ipivot, jj, kinc, kk, kstart, last, stride ; kstart = 0 ; stride = nD + nU - 1 ; if ( pivotsizes == NULL ) { if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = count = 0 ; ii <= iilast ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = count = 0 ; ii <= iilast ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj] = count ; } } } else { if ( CHV_IS_REAL(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = count = 0 ; ii < first ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj] = count ; } first = last + 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = count = 0 ; ii < first ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj] = count ; } first = last + 1 ; } } } } else { int count, ii, iilast, jj, kinc, kk, kstart, stride ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 3 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = count = 0 ; ii <= iilast ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; sizes[jj] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = count = 0 ; ii <= iilast ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; sizes[jj] = count ; } } } break ; default : break ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% break from case CHV_STRICT_UPPER_11, mm = %d", mm) ; #endif break ; case CHV_UPPER_12 : /* --------------------------- copy entries in (1,2) block --------------------------- */ switch ( storeflag ) { case CHV_BY_ROWS : /* ------------- store by rows ------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int count, ii, jj, kk, kstart, stride ; kstart = nD ; stride = nD + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; for ( jj = nD, count = 0 ; jj < ncol ; jj++, kk++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = jj ; dvec[mm] = entries[kk] ; mm++, count++ ; } } kstart += stride ; stride-- ; sizes[ii] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; for ( jj = nD, count = 0 ; jj < ncol ; jj++, kk++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = jj ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } } kstart += stride ; stride-- ; sizes[ii] = count ; } } } else { int count, ii, jj, kk, kstart, stride ; kstart = 2*nD + nL - 1 ; stride = 2*nD + nL + nU - 3 ; for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; if ( CHV_IS_REAL(chv) ) { for ( jj = nD, count = 0 ; jj < ncol ; jj++, kk++ ) { absval = fabs(entries[kk]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[mm] = entries[kk] ; mm++, count++ ; } } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = nD, count = 0 ; jj < ncol ; jj++, kk++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; if ( absval >= droptol ) { ivec[mm] = jj ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } } } kstart += stride ; stride -= 2 ; sizes[ii] = count ; } } break ; case CHV_BY_COLUMNS : /* ---------------- store by columns ---------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int count, ii, jj, kinc, kk, kstart, stride ; kstart = nD ; stride = nD + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = count = 0 ; ii < nD ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj-nD] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = count = 0 ; ii < nD ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc-- ; } kstart++ ; sizes[jj-nD] = count ; } } } else { int count, ii, jj, kinc, kk, kstart, stride ; kstart = 2*nD + nL - 1 ; stride = 2*nD + nL + nU - 3 ; if ( CHV_IS_REAL(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = count = 0 ; ii < nD ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[mm] = entries[kk] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; sizes[jj-nD] = count ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = count = 0 ; ii < nD ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif ivec[mm] = ii ; dvec[2*mm] = entries[2*kk] ; dvec[2*mm+1] = entries[2*kk+1] ; mm++, count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; sizes[jj-nD] = count ; } } } break ; default : break ; } break ; default : break ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% return, mm = %d", mm) ; #endif return(mm) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- return the number of entries in a portion of the object countflag -- which entries to count CHV_STRICT_LOWER --> copy strict lower entries CHV_STRICT_UPPER --> copy strict upper entries CHV_STRICT_LOWER_11 --> copy strict lower entries in (1,1) block CHV_LOWER_21 --> copy lower entries in (2,1) block CHV_STRICT_UPPER_11 --> copy strict upper entries in (1,1) block CHV_UPPER_12 --> copy upper entries in (1,2) block created -- 98feb27, cca ------------------------------------------------------------------- */ int Chv_countEntries ( Chv *chv, int npivot, int pivotsizes[], int countflag ) { int count, nD, nL, nU ; /* -------------------------------------------- check the input, get dimensions and pointers -------------------------------------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_countEntries(%p,%d,%p,%d)" "\n bad input\n", chv, npivot, pivotsizes, countflag) ; exit(-1) ; } if ( countflag < 1 || countflag > 7 ) { fprintf(stderr, "\n fatal error in Chv_countEntries(%p,%d,%p,%d)" "\n bad input\n" "\n countflag = %d, must be\n" "\n 1 --> strictly lower entries" "\n 2 --> diagonal entries" "\n 3 --> strictly upper entries" "\n 4 --> strictly lower entries in (1,1) block" "\n 5 --> lower entries in (2,1) block" "\n 6 --> strictly upper entries in (1,1) block" "\n 7 --> upper entries in (1,2) block", chv, npivot, pivotsizes, countflag, countflag) ; exit(-1) ; } if ( (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv)) && (countflag == 1 || countflag == 4 || countflag == 5 ) ) { fprintf(stderr, "\n fatal error in Chv_countEntries(%p,%d,%p,%d)" "\n countflag = %d --> lower entries but chevron is symmetric", chv, npivot, pivotsizes, countflag, countflag) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; switch ( countflag ) { case CHV_STRICT_LOWER : /* strictly lower entries */ count = (nD*(nD-1))/2 + nD*nL ; break ; case CHV_DIAGONAL : /* diagonal entries */ if ( (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv)) && pivotsizes != NULL ) { count = 2*nD - npivot ; } else { count = nD ; } break ; case CHV_STRICT_UPPER : /* strictly upper entries */ if ( (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv)) && pivotsizes != NULL ) { count = (nD*(nD-1))/2 - nD + npivot + nD*nU ; } else { count = (nD*(nD-1))/2 + nD*nU ; } break ; case CHV_STRICT_LOWER_11 : /* strictly lower entries in (1,1) block */ count = (nD*(nD-1))/2 ; break ; case CHV_LOWER_21 : /* lower entries in (2,1) block */ count = nD*nL ; break ; case CHV_STRICT_UPPER_11 : /* strictly upper entries in (1,1) block */ if ( (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv)) && pivotsizes != NULL ) { count = (nD*(nD-1))/2 - nD + npivot ; } else { count = (nD*(nD-1))/2 ; } break ; case CHV_UPPER_12 : /* upper entries in (1,2) block */ count = nD*nU ; break ; } return(count) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- return the number of entries whose magnitude is larger than droptol. countflag -- which entries to count CHV_STRICT_LOWER --> copy strict lower entries CHV_STRICT_UPPER --> copy strict upper entries CHV_STRICT_LOWER_11 --> copy strict lower entries in (1,1) block CHV_LOWER_21 --> copy lower entries in (2,1) block CHV_STRICT_UPPER_11 --> copy strict upper entries in (1,1) block CHV_UPPER_12 --> copy upper entries in (1,2) block created -- 97jun07, cca modified -- 98feb27, cca cases 4-7 inserted ------------------------------------------------------------------- */ int Chv_countBigEntries ( Chv *chv, int npivot, int pivotsizes[], int countflag, double droptol ) { double absval ; double *entries ; int count, nD, nL, nU ; /* -------------------------------------------- check the input, get dimensions and pointers -------------------------------------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_countBigEntries(%p,%d,%p,%d,%f)" "\n bad input\n", chv, npivot, pivotsizes, countflag, droptol) ; exit(-1) ; } switch ( countflag ) { case CHV_STRICT_LOWER : case CHV_STRICT_UPPER : case CHV_STRICT_LOWER_11 : case CHV_LOWER_21 : case CHV_STRICT_UPPER_11 : case CHV_UPPER_12 : break ; default : fprintf(stderr, "\n fatal error in Chv_countBigEntries(%p,%d,%p,%d,%f)" "\n bad input\n" "\n countflag = %d, must be\n" "\n 1 --> strictly lower entries" "\n 3 --> strictly upper entries" "\n 4 --> count strict lower entries in (1,1) block" "\n 5 --> count lower entries in (2,1) block" "\n 6 --> count strict upper entries in (1,1) block" "\n 7 --> count upper entries in (1,2) block", chv, npivot, pivotsizes, countflag, droptol, countflag) ; exit(-1) ; } if ( (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv)) && (countflag == 1 || countflag == 4 || countflag == 5) ) { fprintf(stderr, "\n fatal error in Chv_countBigEntries(%p,%d,%p,%d,%f)" "\n countflag = %d --> lower entries but chevron is symmetric", chv, npivot, pivotsizes, countflag, droptol, countflag) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n %% inside Chv_countBigEntries, countflag %d", countflag) ; fflush(stdout) ; #endif Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; switch ( countflag ) { case CHV_STRICT_LOWER : { int ii, jj, jlast, kinc, kk, kstart, nrow, stride ; /* ----------------------------------------------------- count the number of big entries in the lower triangle ----------------------------------------------------- */ nrow = nD + nL ; count = 0 ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; jlast = (ii < nD) ? (ii - 1) : (nD - 1) ; for ( jj = 0 ; jj <= jlast ; jj++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; jlast = (ii < nD) ? (ii - 1) : (nD - 1) ; for ( jj = 0 ; jj <= jlast ; jj++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart-- ; } } } break ; case CHV_STRICT_UPPER : { int first, ii, iilast, ipivot, jj, kinc, kk, kstart, last, ncol, stride ; ncol = nD + nU ; if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { #if MYDEBUG > 0 fprintf(stdout, "\n symmetric chevron, npivot = %d, pivotsizes = %p", npivot, pivotsizes) ; #endif /* -------------------- chevron is symmetric -------------------- */ count = 0 ; kstart = 0 ; stride = nD + nU - 1 ; if ( pivotsizes == NULL ) { /* ------------- D is diagonal ------------- */ if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = 0 ; ii <= iilast ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = 0 ; ii <= iilast ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } } } else { /* --------------------------------- D can have 1 x 1 and 2 x 2 pivots --------------------------------- */ if ( CHV_IS_REAL(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n ipivot = %d, jj = %d, first = %d, last = %d, kstart = %d", ipivot, jj, first, last, kstart) ; #endif kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < first ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } first = last + 1 ; } for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n ipivot = %d, jj = %d, first = %d, last = %d, kstart = %d", ipivot, jj, first, last, kstart) ; #endif kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < first ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } first = last + 1 ; } for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } } } } else { /* -------------------------------------- chevron is nonsymmetric, D is diagonal -------------------------------------- */ count = 0 ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 3 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = 0 ; ii <= iilast ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; iilast = (jj < nD) ? (jj - 1) : (nD - 1) ; for ( ii = 0 ; ii <= iilast ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; } } } } break ; case CHV_STRICT_LOWER_11 : { int ii, jj, kinc, kk, kstart, nrow, stride ; /* ---------------------------------------- count the number of big entries in the strict lower triangle of the (1,1) block ---------------------------------------- */ nrow = nD + nL ; count = 0 ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; kinc = stride ; for ( jj = 0 ; jj < ii ; jj++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < nD ; ii++ ) { kk = kstart ; kinc = stride ; for ( jj = 0 ; jj < ii ; jj++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart-- ; } } } break ; case CHV_LOWER_21 : { int ii, jj, kinc, kk, kstart, nrow, stride ; /* -------------------------------------------------- count the number of big entries in the (2,1) block -------------------------------------------------- */ nrow = nD + nL ; count = 0 ; kstart = nL - 1 ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = nD ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; for ( jj = 0 ; jj < nD ; jj++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart-- ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = nD ; ii < nrow ; ii++ ) { kk = kstart ; kinc = stride ; for ( jj = 0 ; jj < nD ; jj++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart-- ; } } } break ; case CHV_STRICT_UPPER_11 : { /* --------------------------------------------------------------- count the number of big entries in the strict upper (1,1) block --------------------------------------------------------------- */ int first, ii, ipivot, jj, kinc, kk, kstart, last, ncol, stride ; ncol = nD + nU ; if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { #if MYDEBUG > 0 fprintf(stdout, "\n symmetric chevron, npivot = %d, pivotsizes = %p", npivot, pivotsizes) ; #endif /* -------------------- chevron is symmetric -------------------- */ count = 0 ; kstart = 0 ; stride = nD + nU - 1 ; if ( pivotsizes == NULL ) { /* ------------- D is diagonal ------------- */ if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < jj ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < jj ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } } } else { /* --------------------------------- D can have 1 x 1 and 2 x 2 pivots --------------------------------- */ if ( CHV_IS_REAL(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% ipivot = %d, jj = %d, first = %d, last = %d, kstart = %d", ipivot, jj, first, last, kstart) ; #endif kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < first ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } first = last + 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = first = 0 ; ipivot < npivot ; ipivot++ ) { last = first + pivotsizes[ipivot] - 1 ; for ( jj = first ; jj <= last ; jj++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% ipivot = %d, jj = %d, first = %d, last = %d, kstart = %d", ipivot, jj, first, last, kstart) ; #endif kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < first ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } first = last + 1 ; } } } } else { /* -------------------------------------- chevron is nonsymmetric, D is diagonal -------------------------------------- */ count = 0 ; kstart = nD + nL - 1 ; stride = 2*nD + nL + nU - 3 ; if ( CHV_IS_REAL(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < jj ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = 0 ; jj < nD ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < jj ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; } } } } break ; case CHV_UPPER_12 : { int ii, jj, kinc, kk, kstart, ncol, stride ; /* ---------------------------------------- count the big entries in the (1,2) block ---------------------------------------- */ ncol = nD + nU ; if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { #if MYDEBUG > 0 fprintf(stdout, "\n symmetric chevron, npivot = %d, pivotsizes = %p", npivot, pivotsizes) ; #endif /* -------------------- chevron is symmetric -------------------- */ count = 0 ; kstart = nD ; stride = nD + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc-- ; } kstart++ ; } } } else { /* ----------------------- chevron is nonsymmetric ----------------------- */ count = 0 ; kstart = 2*nD + nL - 1 ; stride = 2*nD + nL + nU - 3 ; if ( CHV_IS_REAL(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++ ) { absval = fabs(entries[kk]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( jj = nD ; jj < ncol ; jj++ ) { kk = kstart ; kinc = stride ; for ( ii = 0 ; ii < nD ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif if ( absval >= droptol ) { #if MYDEBUG > 0 fprintf(stdout, ", keep") ; #endif count++ ; } kk += kinc ; kinc -= 2 ; } kstart++ ; } } } } break ; default : break ; } return(count) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- purpose -- copy the trailing chevron that starts at offset created -- 97may16, cca ---------------------------------------------------------- */ void Chv_copyTrailingPortion ( Chv *chvI, Chv *chvJ, int offset ) { int first, ncolI, ncolJ, nDJ, nentToCopy, nLJ, nrowI, nrowJ, nUJ ; int *colindI, *colindJ, *rowindI, *rowindJ ; /* -------------- check the data -------------- */ if ( chvI == NULL || chvJ == NULL ) { fprintf(stderr, "\n fatal error in Chv_copyTrailingPortion(%p,%p,%d)" "\n bad input\n", chvI, chvJ, offset) ; exit(-1) ; } Chv_dimensions(chvJ, &nDJ, &nLJ, &nUJ) ; if ( offset < 0 || offset >= nDJ ) { fprintf(stderr, "\n fatal error in Chv_copyTrailingPortion(%p,%p,%d)" "\n nDJ = %d, offset = %d\n", chvI, chvJ, offset, nDJ, offset) ; exit(-1) ; } /* ---------------------------------------------- initialize the chvI object and find the number of and first location of the entries to copy ---------------------------------------------- */ Chv_columnIndices(chvJ, &ncolJ, &colindJ) ; if ( CHV_IS_SYMMETRIC(chvJ) || CHV_IS_HERMITIAN(chvJ) ) { Chv_init(chvI, chvJ->id, nDJ - offset, 0, nUJ, chvJ->type, chvJ->symflag) ; Chv_columnIndices(chvI, &ncolI, &colindI) ; IVcopy(nDJ + nUJ - offset, colindI, colindJ + offset) ; first = offset*(nDJ + nUJ) - (offset*(offset-1))/2 ; nentToCopy = (nDJ*(nDJ+1))/2 + nDJ*nUJ - first ; } else { Chv_rowIndices(chvJ, &nrowJ, &rowindJ) ; Chv_init(chvI, chvJ->id, nDJ - offset, nLJ, nUJ, chvJ->type, chvJ->symflag) ; Chv_columnIndices(chvI, &ncolI, &colindI) ; IVcopy(nDJ + nUJ - offset, colindI, colindJ + offset) ; Chv_rowIndices(chvI, &nrowI, &rowindI) ; IVcopy(nDJ + nLJ - offset, rowindI, rowindJ + offset) ; first = offset*(2*nDJ + nLJ + nUJ - offset) ; nentToCopy = nDJ*(nDJ + nLJ + nUJ) - first ; } if ( CHV_IS_REAL(chvJ) ) { DVcopy(nentToCopy, Chv_entries(chvI), Chv_entries(chvJ) + first) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { DVcopy(2*nentToCopy, Chv_entries(chvI), Chv_entries(chvJ) + 2*first); } return ; } /*--------------------------------------------------------------------*/ kinc = stride ; for ( ii = 0 ; ii < jj ; ii++ ) { absval = Zabs(entries[2*kk], entries[2*kk+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% |A(%d,%d)| = %20.12e, kk = %d", ii, jj, absval, kk) ; #endif Chv/src/factor.c010064400020550007177000001075200657404167000150400ustar00clevecompmath00000400000006/* factor.c */ #include "../Chv.h" #define MYDEBUG 0 #define MYCHECK 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to factor the front without pivoting return value -- # of eliminated rows and columns created -- 98aug27, cca ------------------------------------------------ */ int Chv_factorWithNoPivoting ( Chv *chv, PatchAndGoInfo *info ) { Chv wrkChv ; int ncol, nD, nelim, nrow ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_factorWithNoPivoting()" "\n bad input\n") ; exit(-1) ; } nD = chv->nD ; /* -------------------------- set up the working chevron -------------------------- */ Chv_setDefaultFields(&wrkChv) ; Chv_rowIndices(chv, &nrow, &rowind) ; Chv_columnIndices(chv, &ncol, &colind) ; Chv_initWithPointers(&wrkChv, chv->id, nD, chv->nL, chv->nU, chv->type, chv->symflag, rowind, colind, Chv_entries(chv)) ; /* ------------------------------------- switch over the patch-and-go strategy ------------------------------------- */ if ( info == NULL ) { /* ------------------ simple no pivoting ------------------ */ nelim = 0 ; while ( nelim < nD ) { if ( Chv_r1upd(&wrkChv) == 0 ) { break ; } Chv_shift(&wrkChv, 1) ; nelim++ ; } } else if ( info->strategy == 1 ) { double colmaxabs, diagabs, offmaxabs, rowmaxabs ; /* ---------------------------------------- Patch-and-go for optimization matrices. if |diag| < toosmall * max|offdiag| then diag = 1.0 offdiag = 0.0 endif ---------------------------------------- */ for ( nelim = 0 ; nelim < nD ; nelim++ ) { Chv_maxabsInChevron(&wrkChv, 0, &diagabs, &rowmaxabs, &colmaxabs); offmaxabs = (rowmaxabs >= colmaxabs) ? rowmaxabs : colmaxabs ; if ( diagabs <= info->toosmall * offmaxabs ) { if ( CHV_IS_REAL(chv) ) { wrkChv.entries[0] = 1.0 ; } else { wrkChv.entries[0] = 1.0 ; wrkChv.entries[1] = 0.0 ; } Chv_zeroOffdiagonalOfChevron(chv, 0) ; if ( info->fudgeIV != NULL ) { IV_push(info->fudgeIV, chv->colind[0]) ; } } Chv_r1upd(&wrkChv) ; Chv_shift(&wrkChv, 1) ; } } else if ( info->strategy == 2 ) { double colmaxabs, diagabs, olddiag, newdiag, offmaxabs, rowmaxabs ; /* ---------------------------------------------- Patch-and-go for structural analysis matrices. if |diag| < fudge then diag = fudge * max(max|offdiag|, 1.0) endif ---------------------------------------------- */ for ( nelim = 0 ; nelim < nD ; nelim++ ) { Chv_maxabsInChevron(&wrkChv, 0, &diagabs, &rowmaxabs, &colmaxabs); offmaxabs = (rowmaxabs >= colmaxabs) ? rowmaxabs : colmaxabs ; if ( diagabs <= info->fudge ) { olddiag = diagabs ; if ( offmaxabs < 1.0 ) { offmaxabs = 1.0 ; } if ( CHV_IS_REAL(chv) ) { wrkChv.entries[0] = newdiag = info->fudge * offmaxabs ; } else { wrkChv.entries[0] = newdiag = info->fudge * offmaxabs ; wrkChv.entries[1] = 0.0 ; } if ( info->fudgeIV != NULL ) { IV_push(info->fudgeIV, chv->colind[0]) ; } if ( info->fudgeDV != NULL ) { DV_push(info->fudgeDV, fabs(olddiag - newdiag)) ; } } Chv_r1upd(&wrkChv) ; Chv_shift(&wrkChv, 1) ; } } else { fprintf(stderr, "\n fatal error in Chv_factorWithNoPivoting()" "\n patch-and-go info != NULL, strategy = %d", info->strategy) ; exit(-1) ; } return(nelim) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- factor the pivot chevron with pivoting ndelay -- number of delayed rows and columns pivotflag -- enable pivoting or not 0 --> no pivoting 1 --> enable pivoting pivotsizesIV -- IV object that holds the sizes of the pivots, used only when the front is symmetric or hermitian and pivoting is enabled workDV -- DV object used for working storage, resized as necessary tau -- upper bound on the magnitude of the entries in the factors, used only when pivoting is enabled pntest -- pointer to be incremented with the number of pivot tests return value -- # of eliminated rows and columns created -- 98aug27, cca ------------------------------------------------------------------ */ int Chv_factorWithPivoting ( Chv *chv, int ndelay, int pivotflag, IV *pivotsizesIV, DV *workDV, double tau, int *pntest ) { Chv wrkChv ; int irow, jcol, ncol, nD, nelim, nrow, pivotsize ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( chv == NULL || pivotflag != 1 || ndelay < 0 ) { fprintf(stderr, "\n fatal error in Chv_factorWithPivoting()" "\n bad input\n") ; exit(-1) ; } if ( workDV == NULL ) { fprintf(stderr, "\n fatal error in Chv_factorWithPivoting()" "\n workDV is NULL \n") ; exit(-1) ; } if ( tau < 1.0 ) { fprintf(stderr, "\n fatal error in Chv_factorWithPivoting()" "\n tau = %f is invalid \n", tau) ; exit(-1) ; } if ( CHV_IS_REAL(chv) && CHV_IS_SYMMETRIC(chv) && pivotsizesIV == NULL ) { fprintf(stderr, "\n fatal error in Chv_factorWithPivoting()" "\n real symmetric front" "\n pivoting enabled, pivotsizesIV is NULL\n") ; exit(-1) ; } if ( CHV_IS_COMPLEX(chv) && (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv)) && pivotsizesIV == NULL ) { fprintf(stderr, "\n fatal error in Chv_factorWithPivoting()" "\n complex symmetric or hermitian front" "\n pivoting enabled, pivotsizesIV is NULL\n") ; exit(-1) ; } nD = chv->nD ; /* -------------------------- set up the working chevron -------------------------- */ Chv_setDefaultFields(&wrkChv) ; Chv_rowIndices(chv, &nrow, &rowind) ; Chv_columnIndices(chv, &ncol, &colind) ; Chv_initWithPointers(&wrkChv, chv->id, nD, chv->nL, chv->nU, chv->type, chv->symflag, rowind, colind, Chv_entries(chv)) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n after initializing wrkChv") ; Chv_writeForHumanEye(&wrkChv, stdout) ; fflush(stdout) ; #endif /* ----------------------------- switch over the symmetry flag ----------------------------- */ if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n pivoting, hermitian or symmetric front %d", chv->id) ; fflush(stdout) ; #endif /* ------------------------- symmetric structure front ------------------------- */ IV_setSize(pivotsizesIV, 0) ; nelim = 0 ; while ( nelim < nD ) { /* ------------------------- find the 1x1 or 2x2 pivot ------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n trying to find pivot, nelim = %d, nD = %d, ndelay = %d", nelim, nD, ndelay) ; fflush(stdout) ; #endif pivotsize = Chv_findPivot(&wrkChv, workDV, tau, ndelay, &irow, &jcol, pntest) ; if ( irow > jcol ) { int itemp = irow ; irow = jcol ; jcol = itemp ; } #if MYDEBUG > 0 fprintf(stdout, "\n pivotsize = %d, local irow = %d, local jcol = %d", pivotsize, irow, jcol) ; fflush(stdout) ; #endif irow += nelim ; jcol += nelim ; if ( pivotsize == 0 ) { /* --------------------------------- no pivot found, break out of loop --------------------------------- */ break ; } else { ndelay = 0 ; if ( irow == jcol ) { /* ------------------------------------------------------ 1x1 pivot found, swap row and column, update and shift ------------------------------------------------------ */ #if MYDEBUG > 0 fprintf(stdout, "\n\n before swaps") ; Chv_writeForHumanEye(chv, stdout) ; fflush(stdout) ; #endif Chv_swapRowsAndColumns(chv, nelim, irow) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n after swaps") ; Chv_writeForHumanEye(chv, stdout) ; fflush(stdout) ; #endif #if MYDEBUG > 0 fprintf(stdout, "\n\n nelim = %d, before update", nelim) ; Chv_writeForHumanEye(&wrkChv, stdout) ; fflush(stdout) ; #endif if ( Chv_r1upd(&wrkChv) == 0 ) { break ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n nelim = %d, after update", nelim) ; Chv_writeForHumanEye(&wrkChv, stdout) ; fflush(stdout) ; #endif Chv_shift(&wrkChv, 1) ; nelim++ ; IV_push(pivotsizesIV, 1) ; } else { /* -------------------------------------------------------- 2x2 pivot found, swap rows and columns, update and shift -------------------------------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n\n before swaps") ; Chv_writeForHumanEye(chv, stdout) ; fflush(stdout) ; #endif Chv_swapRowsAndColumns(chv, nelim, irow) ; Chv_swapRowsAndColumns(chv, nelim+1, jcol) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n after swaps") ; Chv_writeForHumanEye(chv, stdout) ; fflush(stdout) ; #endif #if MYDEBUG > 0 fprintf(stdout, "\n\n irow = %d, jcol = %d", irow, jcol) ; fprintf(stdout, "\n\n nelim = %d, before update", nelim) ; #endif #if MYDEBUG > 0 Chv_writeForHumanEye(&wrkChv, stdout) ; fflush(stdout) ; #endif if ( Chv_r2upd(&wrkChv) == 0 ) { break ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n nelim = %d, after update", nelim) ; Chv_writeForHumanEye(&wrkChv, stdout) ; fflush(stdout) ; #endif Chv_shift(&wrkChv, 2) ; nelim += 2 ; IV_push(pivotsizesIV, 2) ; } } #if MYDEBUG > 0 fprintf(stdout, "\n\n ok, done with this pivot") ; fflush(stdout) ; #endif } } else { /* ------------------ nonsymmetric front ------------------ */ nelim = 0 ; while ( nelim < nD ) { /* ------------------ find the 1x1 pivot ------------------ */ pivotsize = Chv_findPivot(&wrkChv, workDV, tau, ndelay, &irow, &jcol, pntest) ; irow += nelim ; jcol += nelim ; #if MYDEBUG > 0 fprintf(stdout, "\n\n irow = %d, jcol = %d", irow, jcol) ; fflush(stdout) ; #endif if ( pivotsize == 0 ) { /* --------------------------------- no pivot found, break out of loop --------------------------------- */ break ; } else { ndelay = 0 ; /* ------------------------------------------------------ 1x1 pivot found, swap row and column, update and shift ------------------------------------------------------ */ #if MYDEBUG > 1 fprintf(stdout, "\n\n before swaps") ; Chv_writeForHumanEye(chv, stdout) ; fflush(stdout) ; #endif Chv_swapRows(chv, nelim, irow) ; Chv_swapColumns(chv, nelim, jcol) ; #if MYDEBUG > 1 fprintf(stdout, "\n\n after swaps") ; Chv_writeForHumanEye(chv, stdout) ; fflush(stdout) ; #endif #if MYDEBUG > 0 fprintf(stdout, "\n\n nelim = %d, before update", nelim) ; fflush(stdout) ; #endif #if MYDEBUG > 1 Chv_writeForHumanEye(&wrkChv, stdout) ; fflush(stdout) ; #endif if ( Chv_r1upd(&wrkChv) == 0 ) { break ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n nelim = %d, after update", nelim) ; #endif #if MYDEBUG > 1 Chv_writeForHumanEye(&wrkChv, stdout) ; fflush(stdout) ; #endif Chv_shift(&wrkChv, 1) ; nelim++ ; } } } return(nelim) ; } /*--------------------------------------------------------------------*/ static int symmetric1x1 ( Chv *chv ) ; static int nonsym1x1 ( Chv *chv) ; static int symmetric2x2 ( Chv *chv ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- perform a rank one update using the first row and column. this is used in the (L + I)D(I + U) factorization return code --- 0 if the pivot was zero 1 if the pivot was nonzero created -- 98jan23, cca --------------------------------------------------------- */ int Chv_r1upd ( Chv *chv ) { int rc = 0 ; if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_r1upd(%p)" "\n bad input\n", chv) ; exit(-1) ; } if ( CHV_IS_NONSYMMETRIC(chv) ) { rc = nonsym1x1(chv) ; } else if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { rc = symmetric1x1(chv) ; } else { fprintf(stderr, "\n fatal error in Chv_r1upd(%p)" "\n symflag = %d\n", chv, chv->symflag) ; exit(-1) ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ perform a rank two update using the first two rows. used in the (U^T + I)D(I + U) and (U^H + I)D(I + U) factorizations return code --- 0 if the pivot was zero 1 if the pivot was nonzero created -- 98jan23, cca ------------------------------------------------------------------ */ int Chv_r2upd ( Chv *chv ) { int rc = 0 ; if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_r2upd(%p)" "\n bad input\n", chv) ; exit(-1) ; } if ( !(CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv)) ) { fprintf(stderr, "\n fatal error in Chv_r2upd(%p)" "\n symflag = %d\n", chv, chv->symflag) ; exit(-1) ; } rc = symmetric2x2(chv) ; return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ perform an internal rank-1 update for a symmetric chevron return code --- 0 if the pivot was zero 1 if the pivot was nonzero created -- 98jan23, cca ------------------------------------------------------------ */ static int symmetric1x1 ( Chv *chv ) { double dimag, dreal, fac1, fac2, limag, lreal, uimag, ureal ; double *entries ; int dloc, dstride, kchv, nD, nL, nU, uijloc, ukbeg, usize ; /* ------------------------------------- get dimensions and pointer to entries ------------------------------------- */ Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; #if MYDEBUG > 0 fprintf(stdout, "\n nD = %d, nL = %d, nU = %d, entries = %p", nD, nL, nU, entries) ; #endif /* ---------------------------------------------- dloc : offset to the first diagonal element dstride : stride to next diagonal element usize : size of first row in upper part ---------------------------------------------- */ dloc = 0 ; dstride = nD + nU ; usize = nD + nU - 1 ; #if MYDEBUG > 0 fprintf(stdout, "\n dloc = %d, dstride = %d, usize = %d", dloc, dstride, usize) ; #endif /* ---------------------- check for a zero pivot ---------------------- */ if ( CHV_IS_REAL(chv) ) { dreal = entries[dloc] ; if ( dreal == 0.0 ) { return(0) ; } fac1 = 1./dreal ; } else if ( CHV_IS_COMPLEX(chv) ) { dreal = entries[2*dloc] ; dimag = entries[2*dloc+1] ; if ( dreal == 0.0 && dimag == 0.0 ) { return(0) ; } #if MYDEBUG > 0 fprintf(stdout, "\n chv->id = %d : (dreal,dimag) = <%12.4e,%12.4e>", chv->id, dreal, dimag) ; fprintf(stdout, "\n (dreal,dimag) = <%12.4e,%12.4e>", dreal, dimag) ; #endif /* ------------------------------ compute (fac1,fac2) = 1/d(0,0) ------------------------------ */ if ( CHV_IS_HERMITIAN(chv) ) { fac1 = 1./dreal ; fac2 = 0.0 ; entries[2*dloc+1] = 0.0 ; } else { Zrecip(dreal, dimag, &fac1, &fac2) ; } #if MYDEBUG > 0 fprintf(stdout, "\n 1/(dreal,dimag) = <%12.4e,%12.4e>", fac1, fac2) ; #endif } /* ------------------------ scale the first row of U ------------------------ */ if ( CHV_IS_REAL(chv) ) { DVscale(usize, &entries[1], fac1) ; } else if ( CHV_IS_HERMITIAN(chv) ) { DVscale(2*usize, &entries[2], fac1) ; } else { ZVscale(usize, &entries[2], fac1, fac2) ; } /* ------------------------------------ loop over the following chevrons uijloc -- offset into uij multiplier ------------------------------------ */ uijloc = dloc + 1 ; for ( kchv = 1 ; kchv < nD ; kchv++ ) { /* -------------------------------------------------- dloc now points to next diagonal location ukbeg -- offset into start of row in upper part -------------------------------------------------- */ dloc += dstride ; ukbeg = dloc + 1 ; #if MYDEBUG > 0 fprintf(stdout, "\n kchv = %5d, dloc = %5d" "\n uijloc = %5d, usize = %5d, ukbeg = %5d", kchv, dloc, uijloc, usize, ukbeg) ; #endif /* ------------------------------------ pull out the multiplier coefficients ------------------------------------ */ if ( CHV_IS_REAL(chv) ) { ureal = entries[uijloc] ; lreal = dreal*ureal ; } else if ( CHV_IS_COMPLEX(chv) ) { ureal = entries[2*uijloc] ; uimag = entries[2*uijloc+1] ; if (CHV_IS_HERMITIAN(chv) ) { lreal = dreal*ureal ; limag = -dreal*uimag ; } else { lreal = dreal*ureal - dimag*uimag ; limag = dreal*uimag + dimag*ureal ; } #if MYDEBUG > 0 fprintf(stdout, "\n (lreal,limag) = <%12.4e,%12.4e>" "\n (ureal,uimag) = <%12.4e,%12.4e>", lreal, limag, ureal, uimag) ; #endif } /* ------------------------------------------------- update the upper row including the diagonal entry ------------------------------------------------- */ if ( CHV_IS_REAL(chv) ) { DVaxpy(usize, &entries[dloc], -lreal, &entries[uijloc]) ; } else if ( CHV_IS_COMPLEX(chv) ) { ZVaxpy(usize, &entries[2*dloc], -lreal, -limag, &entries[2*uijloc]) ; } /* ---------------------------------- adjust offsets and diagonal stride ---------------------------------- */ uijloc++ ; dstride-- ; usize-- ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ perform an internal rank-1 update for a nonsymmetric chevron return code --- 0 if the pivot was zero 1 if the pivot was nonzero created -- 98jan23, cca ------------------------------------------------------------ */ static int nonsym1x1 ( Chv *chv ) { double dimag, dreal, fac1, fac2, limag, lreal, uimag, ureal ; double *entries ; int dloc, dstride, kchv, ljiloc, lkbeg, lsize, nD, nL, nU, uijloc, ukbeg, usize ; /* ------------------------------------- get dimensions and pointer to entries ------------------------------------- */ Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; #if MYDEBUG > 0 fprintf(stdout, "\n nD = %d, nL = %d, nU = %d, entries = %p", nD, nL, nU, entries) ; #endif /* ---------------------------------------------- dloc : offset to the first diagonal element dstride : stride to next diagonal element lsize : size of first column in lower part usize : size of first row in upper part ---------------------------------------------- */ dloc = nD + nL - 1 ; dstride = 2*nD + nL + nU - 2 ; lsize = nD + nL - 1 ; usize = nD + nU - 1 ; #if MYDEBUG > 0 fprintf(stdout, "\n dloc = %d, dstride = %d, lsize = %d, usize = %d", dloc, dstride, lsize, usize) ; #endif /* ---------------------- check for a zero pivot ---------------------- */ if ( CHV_IS_REAL(chv) ) { dreal = entries[dloc] ; if ( dreal == 0.0 ) { return(0) ; } } else if ( CHV_IS_COMPLEX(chv) ) { dreal = entries[2*dloc] ; dimag = entries[2*dloc+1] ; if ( dreal == 0.0 && dimag == 0.0 ) { return(0) ; } #if MYDEBUG > 0 fprintf(stdout, "\n (dreal,dimag) = <%12.4e,%12.4e>", dreal, dimag) ; #endif } /* ----------------------------------------- compute the inverse of the diagonal pivot real: fac1 = 1/d(0,0) complex: (fac1,fac2) = 1/d(0,0) ----------------------------------------- */ if ( CHV_IS_REAL(chv) ) { fac1 = 1./dreal ; } else if ( CHV_IS_COMPLEX(chv) ) { Zrecip(dreal, dimag, &fac1, &fac2) ; #if MYDEBUG > 0 fprintf(stdout, "\n 1/(dreal,dimag) = <%12.4e,%12.4e>", fac1, fac2) ; #endif } /* --------------------------- scale the first column of L (fac1,fac2) = 1/d(0,0) --------------------------- */ if ( CHV_IS_REAL(chv) ) { DVscale(lsize, entries, fac1) ; } else if ( CHV_IS_COMPLEX(chv) ) { ZVscale(lsize, entries, fac1, fac2) ; #if MYDEBUG > 2 { double real, imag ; int irow ; fprintf(stdout, "\n entries in L after scaling") ; for ( irow = 1 ; irow < nD + nL ; irow++ ) { Chv_entry(chv, irow, 0, &real, &imag) ; fprintf(stdout, "\n %% A(%d,%d) = %20.12e + %20.12ei", irow, 0, real, imag) ; } } #endif } /* ------------------------------------ loop over the following chevrons ljiloc -- offset into lij multiplier uijloc -- offset into uij multiplier ------------------------------------ */ ljiloc = dloc - 1 ; uijloc = dloc + 1 ; for ( kchv = 1 ; kchv < nD ; kchv++ ) { /* -------------------------------------------------- dloc now points to next diagonal location lsize and usize decremented lkbeg -- offset into start of column in lower part ukbeg -- offset into start of row in upper part -------------------------------------------------- */ dloc += dstride ; lsize-- ; usize-- ; lkbeg = dloc - lsize ; ukbeg = dloc + 1 ; #if MYDEBUG > 0 fprintf(stdout, "\n kchv = %5d, dloc = %5d" "\n ljiloc = %5d, uijloc = %5d" "\n lsize = %5d, usize = %5d" "\n lkbeg = %5d, ukbeg = %5d", kchv, dloc, ljiloc, uijloc, lsize, usize, lkbeg, ukbeg) ; #endif /* ------------------------------------ pull out the multiplier coefficients ------------------------------------ */ if ( CHV_IS_REAL(chv) ) { lreal = entries[ljiloc] ; ureal = entries[uijloc] ; } else if ( CHV_IS_COMPLEX(chv) ) { lreal = entries[2*ljiloc] ; limag = entries[2*ljiloc+1] ; ureal = entries[2*uijloc] ; uimag = entries[2*uijloc+1] ; #if MYDEBUG > 0 fprintf(stdout, "\n (lreal,limag) = <%12.4e,%12.4e>" "\n (ureal,uimag) = <%12.4e,%12.4e>", lreal, limag, ureal, uimag) ; #endif } /* ------------------------- update the diagonal entry ------------------------- */ if ( CHV_IS_REAL(chv) ) { entries[dloc] -= lreal*ureal ; } else if ( CHV_IS_COMPLEX(chv) ) { entries[2*dloc] -= lreal*ureal - limag*uimag ; entries[2*dloc+1] -= lreal*uimag + limag*ureal ; } /* ----------------------- update the lower column ----------------------- */ if ( CHV_IS_REAL(chv) ) { DVaxpy(lsize, &entries[lkbeg], -ureal, entries) ; } else if ( CHV_IS_COMPLEX(chv) ) { ZVaxpy(lsize, &entries[2*lkbeg], -ureal, -uimag, entries) ; } /* -------------------- update the upper row -------------------- */ if ( CHV_IS_REAL(chv) ) { DVaxpy(usize, &entries[ukbeg], -lreal, &entries[uijloc+1]) ; } else if ( CHV_IS_COMPLEX(chv) ) { ZVaxpy(usize, &entries[2*ukbeg], -lreal, -limag, &entries[2*uijloc+2]) ; } /* ---------------------------------- adjust offsets and diagonal stride ---------------------------------- */ ljiloc-- ; uijloc++ ; dstride -= 2 ; } /* ------------------ scale the row of U ------------------ */ usize = nD + nU - 1 ; if ( CHV_IS_REAL(chv) ) { DVscale(usize, &entries[nD+nL], fac1) ; } else if ( CHV_IS_COMPLEX(chv) ) { ZVscale(usize, &entries[2*(nD+nL)], fac1, fac2) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- perform an internal rank-2 update for a hermitian or symmetric chevron return code --- 0 if the pivot was zero 1 if the pivot was nonzero created -- 98jan23, cca ------------------------------------- */ static int symmetric2x2 ( Chv *chv ) { double areal, aimag, breal, bimag, creal, cimag, ereal, eimag, freal, fimag, greal, gimag, l0imag, l1imag, l0real, l1real, u0imag, u1imag, u0real, u1real ; double *entries ; int dloc, dstride, kchv, nD, nL, nU, rc, u0jloc, u1jloc, ukbeg, usize ; /* ------------------------------------- get dimensions and pointer to entries ------------------------------------- */ Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; #if MYDEBUG > 0 fprintf(stdout, "\n nD = %d, nL = %d, nU = %d, entries = %p", nD, nL, nU, entries) ; #endif /* ---------------------------------------- check for a zero pivot D = [ a b ] for hermitian [ conj(b) c ] D = [ a b ] for symmetric [ b c ] compute the inverse of D E = inv(D) = [ e f ] for hermitian [ conj(f) g ] E = inv(D) = [ e f ] for symmetric [ f g ] ---------------------------------------- */ if ( CHV_IS_REAL(chv) ) { double denom ; areal = entries[0] ; breal = entries[1] ; creal = entries[nD+nU] ; if ( (denom = areal*creal - breal*breal) == 0.0 ) { rc = 0 ; } else { rc = 1 ; denom = 1./denom ; ereal = creal*denom ; freal = -breal*denom ; greal = areal*denom ; } } else if ( CHV_IS_COMPLEX(chv) ) { areal = entries[0] ; aimag = entries[1] ; breal = entries[2] ; bimag = entries[3] ; creal = entries[2*(nD+nU)] ; cimag = entries[2*(nD+nU)+1] ; #if MYDEBUG > 0 if ( CHV_IS_HERMITIAN(chv) ) { fprintf(stdout, "\n hermitian D = [ <%12.4e,%12.4e> <%12.4e,%12.4e> ]" "\n [ <%12.4e,%12.4e> <%12.4e,%12.4e> ]", areal, aimag, breal, bimag, breal, -bimag, creal, cimag) ; } else { fprintf(stdout, "\n symmetric D = [ <%12.4e,%12.4e> <%12.4e,%12.4e> ]" "\n [ <%12.4e,%12.4e> <%12.4e,%12.4e> ]", areal, aimag, breal, bimag, breal, bimag, creal, cimag) ; } #endif if ( CHV_IS_HERMITIAN(chv) ) { rc = Zrecip2(areal, 0.0, breal, bimag, breal, -bimag, creal, 0.0, &ereal, NULL, &freal, &fimag, NULL, NULL, &greal, NULL) ; eimag = gimag = 0.0 ; } else { rc = Zrecip2(areal, aimag, breal, bimag, breal, bimag, creal, cimag, &ereal, &eimag, &freal, &fimag, NULL, NULL, &greal, &gimag) ; } } else { fprintf(stderr, "\n fatal error in Chv_symmetric2x2" "\n chevron must be real or complex") ; exit(-1) ; } if ( rc == 0 ) { /* ------------------------- pivot is singular, return ------------------------- */ return(0) ; } #if MYDEBUG > 0 if ( CHV_IS_HERMITIAN(chv) ) { fprintf(stdout, "\n hermitian DINV = [ <%12.4e,%12.4e> <%12.4e,%12.4e> ]" "\n [ <%12.4e,%12.4e> <%12.4e,%12.4e> ]", ereal, eimag, freal, fimag, freal, -fimag, greal, gimag) ; } else { fprintf(stdout, "\n symmetric DINV = [ <%12.4e,%12.4e> <%12.4e,%12.4e> ]" "\n [ <%12.4e,%12.4e> <%12.4e,%12.4e> ]", ereal, eimag, freal, fimag, freal, fimag, greal, gimag) ; } #endif /* ----------------------------- scale the first two rows of U ----------------------------- */ u0jloc = 2 ; u1jloc = nD + nU + 1 ; usize = nD + nU - 2 ; if ( CHV_IS_REAL(chv) ) { DVscale2(usize, &entries[u0jloc], &entries[u1jloc], ereal, freal, freal, greal) ; } else if ( CHV_IS_HERMITIAN(chv) ) { ZVscale2(usize, &entries[2*u0jloc], &entries[2*u1jloc], ereal, 0.0, freal, fimag, freal, -fimag, greal, 0.0) ; } else { ZVscale2(usize, &entries[2*u0jloc], &entries[2*u1jloc], ereal, eimag, freal, fimag, freal, fimag, greal, gimag) ; } #if MYDEBUG > 2 { double real, imag ; int irow, jcol ; fprintf(stdout, "\n entries in U after scaling") ; for ( irow = 0 ; irow <= 1 ; irow++ ) { for ( jcol = 2 ; jcol < nD + nU ; jcol++ ) { Chv_entry(chv, 0, jcol, &real, &imag) ; fprintf(stdout, "\n %% A(%d,%d) = %20.12e + %20.12ei", 0, jcol, real, imag) ; } } } #endif /* ------------------------------------ loop over the following chevrons u0jloc -- offset into u0j multiplier u1jloc -- offset into u1j multiplier ------------------------------------ */ usize = nD + nU - 2 ; dloc = nD + nU ; dstride = nD + nU - 1 ; for ( kchv = 2 ; kchv < nD ; kchv++ ) { /* -------------------------------------------------- dloc now points to next diagonal location ukbeg -- offset into start of row in upper part -------------------------------------------------- */ dloc += dstride ; ukbeg = dloc + 1 ; #if MYDEBUG > 0 fprintf(stdout, "\n kchv = %5d, dloc = %5d" "\n u0jloc = %5d, u1jloc = %d, usize = %5d, ukbeg = %5d", kchv, dloc, u0jloc, u1jloc, usize, ukbeg) ; #endif /* ------------------------------------ pull out the multiplier coefficients ------------------------------------ */ if ( CHV_IS_REAL(chv) ) { u0real = entries[u0jloc] ; u1real = entries[u1jloc] ; l0real = u0real*areal + u1real*breal ; l1real = u0real*breal + u1real*creal ; } else if ( CHV_IS_COMPLEX(chv) ) { u0real = entries[2*u0jloc] ; u0imag = entries[2*u0jloc+1] ; u1real = entries[2*u1jloc] ; u1imag = entries[2*u1jloc+1] ; if ( CHV_IS_HERMITIAN(chv) ) { l0real = u0real*areal + u1real*breal - u1imag*bimag ; l0imag = -u0imag*areal - u1real*bimag - u1imag*breal ; l1real = u0real*breal + u0imag*bimag + u1real*creal ; l1imag = u0real*bimag - u0imag*breal - u1imag*creal ; } else { l0real = u0real*areal - u0imag*aimag + u1real*breal - u1imag*bimag ; l0imag = u0real*aimag + u0imag*areal + u1real*bimag + u1imag*breal ; l1real = u0real*breal - u0imag*bimag + u1real*creal - u1imag*cimag ; l1imag = u0real*bimag + u0imag*breal + u1real*cimag + u1imag*creal ; } #if MYDEBUG > 0 fprintf(stdout, "\n (l0real,l0imag) = <%12.4e,%12.4e>" "\n (l1real,l1imag) = <%12.4e,%12.4e>", l0real, l0imag, l1real, l1imag) ; #endif } /* ------------------------------------------------- update the upper row including the diagonal entry ------------------------------------------------- */ if ( CHV_IS_REAL(chv) ) { DVaxpy2(usize, &entries[dloc], -l0real, &entries[u0jloc], -l1real, &entries[u1jloc]) ; } else if ( CHV_IS_COMPLEX(chv) ) { ZVaxpy2(usize, &entries[2*dloc], -l0real, -l0imag, &entries[2*u0jloc], -l1real, -l1imag, &entries[2*u1jloc]) ; } /* ---------------------------------- adjust offsets and diagonal stride ---------------------------------- */ u0jloc++ ; u1jloc++ ; dstride-- ; usize-- ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- looking at just a single chevron inside the Chv object, find the absolute value of the diagonal element, and the maximum absolute values of the offdiagonal elements in the chevron's row and column. created -- 98aug26, cca ------------------------------------------------------------------ */ void Chv_maxabsInChevron ( Chv *chv, int ichv, double *pdiagmaxabs, double *prowmaxabs, double *pcolmaxabs ) { double *pdiag ; int length, loc, nD, nL, nU ; /* --------------- check the input --------------- */ if ( chv == NULL || ichv < 0 || ichv >= chv->nD || pdiagmaxabs == NULL || prowmaxabs == NULL || pcolmaxabs == NULL ) { fprintf(stderr, "\n fatal error in Chv_maxabsInChevron()" "\n bad input\n") ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; pdiag = Chv_diagLocation(chv, ichv) ; length = nD - ichv - 1 + nU ; if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_SYMMETRIC(chv) ) { *pdiagmaxabs = fabs(*pdiag) ; *prowmaxabs = DVmaxabs(length, pdiag + 1, &loc) ; *pcolmaxabs = *prowmaxabs ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { *pdiagmaxabs = fabs(*pdiag) ; *prowmaxabs = DVmaxabs(length, pdiag + 1, &loc) ; *pcolmaxabs = DVmaxabs(length, pdiag - length, &loc) ; } else { fprintf(stderr, "\n fatal error in Chv_maxabsInChevron()" "\n chv is real, chv->symflag = %d" "\n must be symmetric or nonsymmetric\n", chv->symflag) ; exit(-1) ; } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { *pdiagmaxabs = Zabs(*pdiag, *(pdiag+1)) ; *prowmaxabs = ZVmaxabs(length, pdiag + 2) ; *pcolmaxabs = *prowmaxabs ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { *pdiagmaxabs = Zabs(*pdiag, *(pdiag+1)) ; *prowmaxabs = ZVmaxabs(length, pdiag + 2) ; *pcolmaxabs = ZVmaxabs(length, pdiag - 2*length) ; } else { fprintf(stderr, "\n fatal error in Chv_maxabsInChevron()" "\n chv is complex, chv->symflag = %d" "\n must be symmetric or nonsymmetric\n", chv->symflag) ; exit(-1) ; } } else { fprintf(stderr, "\n fatal error in Chv_maxabsInChevron()" "\n chv->type = %d, must be real or complex\n", chv->type) ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- zero the offdiagonal entries of chevron ichv created -- 98aug26, cca ------------------------------------------------------- */ void Chv_zeroOffdiagonalOfChevron ( Chv *chv, int ichv ) { double *pdiag ; int length, nD, nL, nU ; /* --------------- check the input --------------- */ if ( chv == NULL || ichv < 0 || ichv >= chv->nD ) { fprintf(stderr, "\n fatal error in Chv_zeroOffdiagonalOfChevron()" "\n bad input\n") ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; pdiag = Chv_diagLocation(chv, ichv) ; length = nD - ichv - 1 + nU ; if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_SYMMETRIC(chv) ) { DVzero(length, pdiag+1) ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { DVzero(length, pdiag + 1) ; DVzero(length, pdiag - length) ; } else { fprintf(stderr, "\n fatal error in Chv_zeroOffdiagonalOfChevron()" "\n chv is real, chv->symflag = %d" "\n must be symmetric or nonsymmetric\n", chv->symflag) ; exit(-1) ; } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { ZVzero(length, pdiag+2) ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { ZVzero(length, pdiag+2) ; ZVzero(length, pdiag-2*length) ; } else { fprintf(stderr, "\n fatal error in Chv_zeroOffdiagonalOfChevron()" "\n chv is complex, chv->symflag = %d" "\n must be symmetric or nonsymmetric\n", chv->symflag) ; exit(-1) ; } } else { fprintf(stderr, "\n fatal error in Chv_zeroOffdiagonalOfChevron()" "\n chv->type = %d, must be real or complex\n", chv->type) ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ ntries[2] ; bimag = entries[3] ; creal = entries[2*(nD+nU)] ; cimag = entries[2*(nD+nU)+1] ; #if MYDEBUG > 0 if ( CHV_IS_HERMITIAN(chv) ) { fprintf(stdout, Chv/src/findPivot.c010064400020550007177000000440720657126731400155300ustar00clevecompmath00000400000006/* findPivot.c */ #include "../Chv.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ static int findPivotSH ( Chv *chv, DV *workDV, double tau, int ndelay, int *pirow, int *pjcol, int *pntest ) ; static int findPivotN ( Chv *chv, DV *workDV, double tau, int ndelay, int *pirow, int *pjcol, int *pntest ) ; static int nonsym1x1 ( Chv *chv, int irow, int jcol, double tau, double rowmaxes[], double colmaxes[] ) ; static int sym1x1 ( Chv *chv, int irow, double tau, double rowmaxes[] ); static int sym2x2 ( Chv *chv, int irow, int jcol, double tau, double rowmaxes[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- find and test a pivot workDV -- object that contains work vectors tau -- upper bound on magnitude of factor entries ndelay -- number of delayed rows and columns on input pirow -- pointer to be filled with pivot row pjcol -- pointer to be filled with pivot column pntest -- pointer to be incremented with the number of pivot tests return value -- size of pivot 0 --> pivot not found 1 --> 1x1 pivot in row *pirow and column *pjcol 2 --> 2x2 pivot in rows and columns *pirow and *pjcol, symmetric front only created -- 98jan24, cca ------------------------------------------------------------------ */ int Chv_findPivot ( Chv *chv, DV *workDV, double tau, int ndelay, int *pirow, int *pjcol, int *pntest ) { int rc ; /* --------------- check the input --------------- */ if ( chv == NULL || workDV == NULL || tau < 1.0 || ndelay < 0 || pirow == NULL || pjcol == NULL || pntest == NULL ) { fprintf(stderr, "\n fatal error in Chv_findPivot(%p,%p,%f,%d,%p,%p,%p)" "\n bad input\n", chv, workDV, tau, ndelay, pirow, pjcol, pntest) ; exit(-1) ; } if ( !(CHV_IS_REAL(chv) || CHV_IS_COMPLEX(chv)) ) { fprintf(stderr, "\n fatal error in Chv_findPivot(%p,%p,%f,%d,%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, workDV, tau, ndelay, pirow, pjcol, pntest, chv->type) ; exit(-1) ; } if ( !(CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) || CHV_IS_NONSYMMETRIC(chv)) ) { fprintf(stderr, "\n fatal error in Chv_findPivot(%p,%p,%f,%d,%p,%p,%p)" "\n bad symflag %d" "\n must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or CHV_NONSYMMETRIC\n", chv, workDV, tau, ndelay, pirow, pjcol, pntest, chv->symflag) ; exit(-1) ; } if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { rc = findPivotSH(chv, workDV, tau, ndelay, pirow, pjcol, pntest) ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { rc = findPivotN(chv, workDV, tau, ndelay, pirow, pjcol, pntest) ; } else { fprintf(stderr, "\n fatal error in Chv_findPivot(%p,%p,%f,%d,%p,%p,%p)" "\n bad symflag %d\n", chv, workDV, tau, ndelay, pirow, pjcol, pntest, chv->symflag) ; exit(-1) ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- find and test a pivot for a symmetric or hermitian matrix workDV -- object that contains work vectors tau -- upper bound on magnitude of factor entries ndelay -- number of delayed rows and columns on input pirow -- pointer to be filled with pivot row pjcol -- pointer to be filled with pivot column pntest -- pointer to be incremented with the number of pivot tests return value -- size of pivot 0 --> pivot not found 1 --> 1x1 pivot in row *pirow and column *pjcol 2 --> 2x2 pivot in rows and columns *pirow and *pjcol, symmetric front only created -- 98apr18, cca -------------------------------------------------------------------- */ static int findPivotSH ( Chv *chv, DV *workDV, double tau, int ndelay, int *pirow, int *pjcol, int *pntest ) { double maxval ; double *rowmaxes ; int ii, irow, jrow, krow, ncand, nD, ndouble, ntest, pivotsize, tag, untag ; int *rowids, *rowmark ; untag = 0 ; tag = 1 ; nD = chv->nD ; #if MYDEBUG > 0 fprintf(stdout, "\n %% findPivotSH, id = %d, nD = %d, nL = %d, nU = %d, ndelay = %d", chv->id, chv->nD, chv->nL, chv->nU, ndelay) ; fflush(stdout) ; #endif *pirow = *pjcol = -1 ; ntest = *pntest ; /* ------------------------------------ symmetric front, set up work vectors ------------------------------------ */ if ( sizeof(int) == sizeof(double) ) { ndouble = 3*nD ; } else if ( 2*sizeof(int) == sizeof(double) ) { ndouble = 2*nD ; } DV_setSize(workDV, ndouble) ; rowmaxes = DV_entries(workDV) ; DVfill(nD, rowmaxes, 0.0) ; rowmark = (int *) (rowmaxes + nD) ; rowids = rowmark + nD ; if ( ndelay > 0 ) { IVfill(ndelay, rowmark, untag) ; IVfill(nD - ndelay, rowmark + ndelay, tag) ; } else { IVfill(nD, rowmark, tag) ; } ncand = 0 ; do { pivotsize = 0 ; /* -------------------- find candidate pivot -------------------- */ Chv_fastBunchParlettPivot(chv, rowmark, tag, &irow, &jrow) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% FBP: irow = %d, jrow = %d", irow, jrow) ; if ( irow != -1 ) { double imag, real ; Chv_entry(chv, irow, irow, &real, &imag) ; fprintf(stdout, "\n%% entry(%d,%d) = %20.12e + %20.12e*i", irow, irow, real, imag) ; if ( jrow != irow ) { Chv_entry(chv, irow, jrow, &real, &imag) ; fprintf(stdout, "\n%% entry(%d,%d) = %20.12e + %20.12e*i", irow, jrow, real, imag) ; Chv_entry(chv, jrow, jrow, &real, &imag) ; fprintf(stdout, "\n%% entry(%d,%d) = %20.12e + %20.12e*i", jrow, jrow, real, imag) ; } } fflush(stdout) ; #endif if ( irow == -1 ) { /* ---------------------------------------------- unable to find pivot, break out of search loop ---------------------------------------------- */ pivotsize = 0 ; break ; } else { /* ------------------------------- (irow,jrow) is a possible pivot mark as visited and get row max ------------------------------- */ Chv_maxabsInRow(chv, irow, &maxval) ; rowmaxes[irow] = maxval ; rowmark[irow] = untag ; if ( irow != jrow ) { Chv_maxabsInRow(chv, jrow, &maxval) ; rowmaxes[jrow] = maxval ; rowmark[jrow] = untag ; } if ( irow == jrow ) { /* ------------------ test the 1x1 pivot ------------------ */ pivotsize = sym1x1(chv, irow, tau, rowmaxes) ; ntest++ ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% pivotsize from sym1x1 = %d", pivotsize) ; #endif if ( pivotsize == 1 ) { *pirow = irow ; *pjcol = jrow ; } else { for ( ii = 0 ; ii < ncand ; ii++ ) { /* ---------------------------------- test the 2x2 pivot (irow, krow) where krow is a previous candidate ---------------------------------- */ krow = rowids[ii] ; pivotsize = sym2x2(chv, irow, krow, tau, rowmaxes) ; ntest++ ; if ( pivotsize == 2 ) { *pirow = irow ; *pjcol = krow ; break ; } } } } else { /* ------------------------------- test the 2x2 pivot (irow, jrow) ------------------------------- */ pivotsize = sym2x2(chv, irow, jrow, tau, rowmaxes) ; ntest++ ; if ( pivotsize == 2 ) { *pirow = irow ; *pjcol = jrow ; } else { for ( ii = 0 ; ii < ncand ; ii++ ) { krow = rowids[ii] ; /* ---------------------------------- test the 2x2 pivot (irow, krow) where krow is a previous candidate ---------------------------------- */ pivotsize = sym2x2(chv, irow, krow, tau, rowmaxes) ; ntest++ ; if ( pivotsize == 2 ) { *pirow = irow ; *pjcol = krow ; break ; } /* ---------------------------------- test the 2x2 pivot (jrow, krow) where krow is a previous candidate ---------------------------------- */ pivotsize = sym2x2(chv, jrow, krow, tau, rowmaxes) ; ntest++ ; if ( pivotsize == 2 ) { *pirow = jrow ; *pjcol = krow ; break ; } } } } if ( pivotsize == 0 ) { /* ------------------------ add new candidate row(s) ------------------------ */ rowids[ncand++] = irow ; if ( irow != jrow ) { rowids[ncand++] = jrow ; } } } } while ( pivotsize == 0 ) ; *pntest = ntest ; return(pivotsize) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- find and test a pivot for a nonsymmetric matrix workDV -- object that contains work vectors tau -- upper bound on magnitude of factor entries ndelay -- number of delayed rows and columns on input pirow -- pointer to be filled with pivot row pjcol -- pointer to be filled with pivot column pntest -- pointer to be incremented with the number of pivot tests return value -- size of pivot 0 --> pivot not found 1 --> 1x1 pivot in row *pirow and column *pjcol 2 --> 2x2 pivot in rows and columns *pirow and *pjcol, symmetric front only created -- 98jan24, cca ------------------------------------------------------------------ */ static int findPivotN ( Chv *chv, DV *workDV, double tau, int ndelay, int *pirow, int *pjcol, int *pntest ) { double maxval ; double *colmaxes, *rowmaxes ; int icol, ii, irow, jcol, jrow, ncand, nD, ndouble, ntest, pivotsize, tag, untag ; int *colids, *colmark, *rowids, *rowmark ; untag = 0 ; tag = 1 ; nD = chv->nD ; #if MYDEBUG > 0 fprintf(stdout, "\n %% Chv_findPivot, id = %d, nD = %d, nL = %d, nU = %d, ndelay = %d", chv->id, chv->nD, chv->nL, chv->nU, ndelay) ; fflush(stdout) ; #endif *pirow = *pjcol = -1 ; ntest = *pntest ; /* ------------------- set up work vectors ------------------- */ if ( sizeof(int) == sizeof(double) ) { ndouble = 6*nD ; } else if ( 2*sizeof(int) == sizeof(double) ) { ndouble = 4*nD ; } DV_setSize(workDV, ndouble) ; rowmaxes = DV_entries(workDV) ; colmaxes = rowmaxes + nD ; DVfill(nD, rowmaxes, 0.0) ; DVfill(nD, colmaxes, 0.0) ; rowmark = (int *) (colmaxes + nD) ; colmark = rowmark + nD ; rowids = colmark + nD ; colids = rowids + nD ; if ( ndelay > 0 ) { IVfill(ndelay, rowmark, untag) ; IVfill(nD - ndelay, rowmark + ndelay, tag) ; IVfill(ndelay, colmark, untag) ; IVfill(nD - ndelay, colmark + ndelay, tag) ; } else { IVfill(nD, rowmark, tag) ; IVfill(nD, colmark, tag) ; } ncand = 0 ; do { pivotsize = 0 ; /* -------------------- find candidate pivot -------------------- */ Chv_quasimax(chv, rowmark, colmark, tag, &irow, &jcol) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% quasimax: irow = %d, jcol = %d", irow, jcol) ; if ( irow != -1 ) { double imag, real ; Chv_entry(chv, irow, jcol, &real, &imag) ; fprintf(stdout, "\n%% entry(%d,%d) = %20.12e + %20.12e*i", irow, jcol, real, imag) ; } fflush(stdout) ; #endif if ( irow == -1 ) { /* ---------------------------------------------- unable to find pivot, break out of search loop ---------------------------------------------- */ break ; } else { /* ------------------------------------------------------------ find the row max for row irow and column max for column jcol ------------------------------------------------------------ */ Chv_maxabsInRow(chv, irow, &maxval) ; rowmaxes[irow] = maxval ; Chv_maxabsInColumn(chv, jcol, &maxval) ; colmaxes[jcol] = maxval ; rowmark[irow] = untag ; colmark[jcol] = untag ; /* ------------------------------------- test the (irow,jcol) entry as a pivot ------------------------------------- */ pivotsize = nonsym1x1(chv, irow, jcol, tau, rowmaxes, colmaxes) ; ntest++ ; if ( pivotsize == 1 ) { *pirow = irow ; *pjcol = jcol ; } else { /* --------------------------------------- test the other matrix entries as pivots --------------------------------------- */ for ( ii = 0 ; ii < ncand ; ii++ ) { jrow = rowids[ii] ; icol = colids[ii] ; /* -------------------------- test the (irow,icol) entry -------------------------- */ pivotsize = nonsym1x1(chv, irow, icol, tau, rowmaxes, colmaxes) ; ntest++ ; if ( pivotsize == 1 ) { *pirow = irow ; *pjcol = icol ; break ; } /* -------------------------- test the (jrow,jcol) entry -------------------------- */ pivotsize = nonsym1x1(chv, jrow, jcol, tau, rowmaxes, colmaxes) ; ntest++ ; if ( pivotsize == 1 ) { *pirow = jrow ; *pjcol = jcol ; break ; } } /* ---------------------------------------------- no pivots found, add irow to candidate row ids and add jcol to candidate column ids ---------------------------------------------- */ rowids[ncand] = irow ; colids[ncand] = jcol ; ncand++ ; } } } while ( pivotsize == 0 ) ; *pntest = ntest ; return(pivotsize) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- return 1 if the nonsymmetric 1x1 pivot passes return 0 otherwise created -- 98jan24, cca --------------------------------------------- */ static int nonsym1x1 ( Chv *chv, int irow, int jcol, double tau, double rowmaxes[], double colmaxes[] ) { double cutoff, magn ; int rc ; if ( CHV_IS_REAL(chv) ) { double value ; Chv_realEntry(chv, irow, jcol, &value) ; magn = fabs(value) ; } else if ( CHV_IS_COMPLEX(chv) ) { double imag, real ; Chv_complexEntry(chv, irow, jcol, &real, &imag) ; magn = Zabs(real, imag) ; } cutoff = tau * magn ; #if MYDEBUG > 0 fprintf(stdout, "\n %% magn = %12.4e, cutoff = %12.4e", magn, cutoff) ; fprintf(stdout, "\n %% rowmaxes[%d] = %12.4e, colmaxes[%d] = %12.4e", irow, rowmaxes[irow], jcol, colmaxes[jcol]) ; #endif if ( rowmaxes[irow] <= cutoff && colmaxes[jcol] <= cutoff ) { rc = 1 ; } else { rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ return 1 if the symmetric 1x1 pivot passes return 0 otherwise created -- 98jan24, cca ------------------------------------------ */ static int sym1x1 ( Chv *chv, int irow, double tau, double rowmaxes[] ) { double cutoff ; int rc ; if ( CHV_IS_REAL(chv) ) { double value ; Chv_realEntry(chv, irow, irow, &value) ; cutoff = tau * fabs(value) ; } else if ( CHV_IS_COMPLEX(chv) ) { double imag, real ; Chv_complexEntry(chv, irow, irow, &real, &imag) ; cutoff = tau * Zabs(real, imag) ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% cutoff = %12.4e, rowmaxes[%d] = %12.4e", cutoff, irow, rowmaxes[irow]) ; #endif if ( rowmaxes[irow] <= cutoff ) { rc = 1 ; } else { rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ return 2 if the symmetric 2x2 pivot passes return 0 otherwise created -- 98jan24, cca ------------------------------------------ */ static int sym2x2 ( Chv *chv, int irow, int jcol, double tau, double rowmaxes[] ) { double amag, bmag, cmag, denom, val1, val2 ; int rc ; if ( CHV_IS_REAL(chv) ) { double a, b, c ; Chv_realEntry(chv, irow, irow, &a) ; Chv_realEntry(chv, irow, jcol, &b) ; Chv_realEntry(chv, jcol, jcol, &c) ; amag = fabs(a) ; bmag = fabs(b) ; cmag = fabs(c) ; denom = fabs(a*c - b*b) ; } else if ( CHV_IS_COMPLEX(chv) ) { double aimag, areal, bimag, breal, cimag, creal, imag, real ; Chv_complexEntry(chv, irow, irow, &areal, &aimag) ; Chv_complexEntry(chv, irow, jcol, &breal, &bimag) ; Chv_complexEntry(chv, jcol, jcol, &creal, &cimag) ; if ( CHV_IS_HERMITIAN(chv) ) { amag = fabs(areal) ; bmag = Zabs(breal, bimag) ; cmag = fabs(creal) ; denom = fabs(areal*creal - breal*breal - bimag*bimag) ; } else if ( CHV_IS_SYMMETRIC(chv) ) { amag = Zabs(areal, aimag) ; bmag = Zabs(breal, bimag) ; cmag = Zabs(creal, cimag) ; real = areal*creal - aimag*cimag - breal*breal + bimag*bimag ; imag = areal*cimag + aimag*creal - 2*breal*bimag ; denom = Zabs(real, imag) ; } } #if MYDEBUG > 0 fprintf(stdout, "\n amag = %20.12e ; " "\n bmag = %20.12e ; " "\n cmag = %20.12e ; ", amag, bmag, cmag) ; #endif if ( denom == 0.0 ) { return(0) ; } val1 = (cmag*rowmaxes[irow] + bmag*rowmaxes[jcol])/denom ; val2 = (bmag*rowmaxes[irow] + amag*rowmaxes[jcol])/denom ; #if MYDEBUG > 0 fprintf(stdout, "\n %% sym2x2" "\n rowmax1 = %20.12e" "\n rowmax2 = %20.12e" "\n val1 = %20.12e" "\n val2 = %20.12e" "\n denom = %20.12e", rowmaxes[irow], rowmaxes[jcol], val1, val2, denom) ; #endif if ( val1 <= tau && val2 <= tau ) { rc = 2 ; } else { rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ ----------------- */ pivotsize = sym2x2(chv, irow, krow, tau, rowmaxes) ; ntest++ ; if ( pivotsize == 2 ) { *pirow = irow ; *pjcol = krow ; break ; } /* ---------------------------------- test the 2x2 pivot (jrow, krow) where krow is a previous candidate ---------------------------------- */ pivotsizChv/src/init.c010064400020550007177000000276420657126731400145350ustar00clevecompmath00000400000006/* init.c */ #include "../Chv.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ return the number of bytes needed to store the chevron created -- 98apr30, cca ------------------------------------------------------ */ int Chv_nbytesNeeded ( int nD, int nL, int nU, int type, int symflag ) { int nbytes, nent, nint ; /* -------------- check the data -------------- */ if ( nD < 0 || nL < 0 || nU < 0 ) { fprintf(stderr, "\n fatal error in Chv_nbytesNeeded()" "\n bad input, nD = %d, nL = %d, nU = %d\n", nD, nL, nU) ; exit(-1) ; } nbytes = 0 ; switch ( type ) { case SPOOLES_REAL : switch ( symflag ) { case SPOOLES_SYMMETRIC : nint = 6 + nD + nU ; nent = (nD*(nD+1))/2 + nD*nU ; break ; case SPOOLES_NONSYMMETRIC : nint = 6 + 2*nD + nL + nU ; nent = nD*(nD + nL + nU) ; break ; default : fprintf(stderr, "\n fatal error in Chv_nbytesNeeded()" "\n type = SPOOLES_REAL, invalid symflag = %d" "\n must be SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC\n", symflag) ; exit(-1) ; } if ( 2*sizeof(int) == sizeof(double) ) { nbytes = ((nint + 1)/2 + nent)*sizeof(double) ; } else if ( sizeof(int) == sizeof(double) ) { nbytes = (nint + nent)*sizeof(double) ; } else { fprintf(stderr, "\n fatal error in Chv_nbytesNeeded()" "\n sizeof(int) = %d, sizeof(double) = %d", sizeof(int), sizeof(double)) ; exit(-1) ; } break ; case SPOOLES_COMPLEX : switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN: nint = 6 + nD + nU ; nent = (nD*(nD+1))/2 + nD*nU ; break ; case SPOOLES_NONSYMMETRIC : nint = 6 + 2*nD + nL + nU ; nent = nD*(nD + nL + nU) ; break ; default : fprintf(stderr, "\n fatal error in Chv_nbytesNeeded()" "\n type = SPOOLES_COMPLEX, invalid symflag = %d" "\n must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN" "\n or SPOOLES_NONSYMMETRIC\n", symflag) ; exit(-1) ; } if ( 2*sizeof(int) == sizeof(double) ) { nbytes = ((nint + 1)/2 + 2*nent)*sizeof(double) ; } else if ( sizeof(int) == sizeof(double) ) { nbytes = (nint + 2*nent)*sizeof(double) ; } else { fprintf(stderr, "\n fatal error in Chv_nbytesNeeded()" "\n sizeof(int) = %d, sizeof(double) = %d", sizeof(int), sizeof(double)) ; exit(-1) ; } break ; default : fprintf(stderr, "\n fatal error in Chv_nbytesNeeded()" "\n invalid type = %d" "\n must be SPOOLES_REAL or SPOOLES_COMPLEX\n", type) ; break ; } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- return the number of bytes in the workspace owned by this object created -- 98apr30, cca ---------------------------------------------------------------- */ int Chv_nbytesInWorkspace ( Chv *chv ) { if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_nbytesInWorkspace(%p)" "\n bad input\n", chv) ; exit(-1) ; } return(sizeof(double)*DV_maxsize(&chv->wrkDV)) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- set the number of bytes in the workspace owned by this object created -- 98apr30, cca ---------------------------------------------------------------- */ void Chv_setNbytesInWorkspace ( Chv *chv, int nbytes ) { if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_setNbytesInWorkspace(%p,%d)" "\n bad input\n", chv, nbytes) ; exit(-1) ; } DV_setSize(&chv->wrkDV, nbytes/sizeof(double)) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- purpose -- set the fields created -- 98apr30, cca ---------------------------- */ void Chv_setFields ( Chv *chv, int id, int nD, int nL, int nU, int type, int symflag ) { double *dbuffer ; int nint ; int *ibuffer ; /* --------------- check the input --------------- */ if ( chv == NULL || nD <= 0 || nL < 0 || nU < 0 ) { fprintf(stderr, "\n fatal error in Chv_setFields()" "\n bad input, chv %p, nD %d, nL %d, nU %d\n", chv, nD, nL, nU) ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in Chv_setFields()" "\n type = SPOOLES_REAL, symflag = %d" "\n must be SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC\n", symflag) ; exit(-1) ; } break ; case SPOOLES_COMPLEX : switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in Chv_setFields()" "\n type = SPOOLES_COMPLEX, symflag = %d" "\n must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN" "\n or SPOOLES_NONSYMMETRIC\n", symflag) ; exit(-1) ; } break ; default : fprintf(stderr, "\n fatal error in Chv_setFields()" "\n type = %d" "\n must be SPOOLES_REAL or SPOOLES_COMPLEX\n", type) ; exit(-1) ; } dbuffer = DV_entries(&chv->wrkDV) ; ibuffer = (int *) dbuffer ; /* --------------------- set the scalar fields --------------------- */ chv->id = ibuffer[0] = id ; chv->nD = ibuffer[1] = nD ; chv->nL = ibuffer[2] = nL ; chv->nU = ibuffer[3] = nU ; chv->type = ibuffer[4] = type ; chv->symflag = ibuffer[5] = symflag ; /* ------------------------------------------- set the colind, rowind and entries pointers ------------------------------------------- */ chv->colind = ibuffer + 6 ; nint = 6 + nD + nU ; if ( symflag == SPOOLES_NONSYMMETRIC ) { chv->rowind = chv->colind + nD + nU ; nint += nD + nL ; } else { chv->rowind = NULL ; } if ( sizeof(int) == sizeof(double) ) { chv->entries = dbuffer + nint ; } else if ( 2*sizeof(int) == sizeof(double) ) { chv->entries = dbuffer + (nint + 1)/2 ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- purpose -- basic initializer created -- 98apr30, cca ---------------------------- */ void Chv_init ( Chv *chv, int id, int nD, int nL, int nU, int type, int symflag ) { int nbytes ; /* --------------- check the input --------------- */ if ( chv == NULL || nD <= 0 || nL < 0 || nU < 0 ) { fprintf(stderr, "\n fatal error in Chv_init()" "\n bad input, chv %p, nD %d, nL %d, nU %d\n", chv, nD, nL, nU) ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in Chv_init()" "\n type = SPOOLES_REAL, symflag = %d" "\n must be SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC\n", symflag) ; exit(-1) ; } break ; case SPOOLES_COMPLEX : switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in Chv_init()" "\n type = SPOOLES_COMPLEX, symflag = %d" "\n must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN" "\n or SPOOLES_NONSYMMETRIC\n", symflag) ; exit(-1) ; } break ; default : fprintf(stderr, "\n fatal error in Chv_init()" "\n type = %d" "\n must be SPOOLES_REAL or SPOOLES_COMPLEX\n", type) ; exit(-1) ; } /* ------------------------------------------------------- get and set the number of bytes needed in the workspace ------------------------------------------------------- */ nbytes = Chv_nbytesNeeded(nD, nL, nU, type, symflag) ; Chv_setNbytesInWorkspace(chv, nbytes) ; /* -------------- set the fields -------------- */ Chv_setFields(chv, id, nD, nL, nU, type, symflag) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ purpose -- initializer with pointers created -- 98apr30, cca ------------------------------------ */ void Chv_initWithPointers ( Chv *chv, int id, int nD, int nL, int nU, int type, int symflag, int *rowind, int *colind, double *entries ) { /* --------------- check the input --------------- */ if ( chv == NULL || nD <= 0 || nL < 0 || nU < 0 ) { fprintf(stderr, "\n fatal error in Chv_initWithPointers() " "\n chv = %p, nD = %d, nL = %d, nU = %d\n", chv, nD, nL, nU) ; exit(-1) ; } if ( entries == NULL || colind == NULL || (symflag == SPOOLES_NONSYMMETRIC && rowind == NULL) ) { fprintf(stderr, "\n fatal error in Chv_init()" "\n entries = %p, colind = %p, rowind = %p, symflag = %d\n", entries, colind, rowind, symflag) ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in Chv_initFromPointers()" "\n type = SPOOLES_REAL, symflag = %d" "\n must be SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC\n", symflag) ; exit(-1) ; } break ; case SPOOLES_COMPLEX : switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in Chv_initFromPointers()" "\n type = SPOOLES_COMPLEX, symflag = %d" "\n must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN" "\n or SPOOLES_NONSYMMETRIC\n", symflag) ; exit(-1) ; } break ; default : fprintf(stderr, "\n fatal error in Chv_initFromPointers()" "\n type = %d" "\n must be SPOOLES_REAL or SPOOLES_COMPLEX\n", type) ; exit(-1) ; } /* --------------------- set the scalar fields --------------------- */ chv->id = id ; chv->nD = nD ; chv->nL = nL ; chv->nU = nU ; chv->type = type ; chv->symflag = symflag ; /* -------------------------- set up the working storage -------------------------- */ chv->entries = entries ; chv->colind = colind ; if ( symflag == SPOOLES_NONSYMMETRIC ) { chv->rowind = rowind ; } else { chv->rowind = NULL ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- to initialize the object from its working storage, used when the object is an MPI message created -- 98apr30 ------------------------------------------------------------- */ void Chv_initFromBuffer ( Chv *chv ) { int *ibuffer ; /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_initFromBuffer(%p) " "\n bad input\n", chv) ; exit(-1) ; } ibuffer = (int *) DV_entries(&chv->wrkDV) ; Chv_setFields(chv, ibuffer[0], ibuffer[1], ibuffer[2], ibuffer[3], ibuffer[4], ibuffer[5]) ; return ; } /*--------------------------------------------------------------------*/ --------------------------------------------------------*/ /* -----------------------------Chv/src/instance.c010064400020550007177000000477370657126731400154050ustar00clevecompmath00000400000006/* instance.c */ #include "../Chv.h" /*--------------------------------------------------------------------*/ /* ---------------------------- return the id of the chevron created -- 98apr30, cca ---------------------------- */ int Chv_id ( Chv *chv ) { /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_id(%p)" "\n bad input\n", chv) ; exit(-1) ; } return(chv->id) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ return the type of the chevron return value = SPOOLES_REAL --> chevron is real return value = SPOOLES_COMPLEX --> chevron is complex created -- 98apr30, cca ------------------------------------------------------------ */ int Chv_type ( Chv *chv ) { /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_type(%p)" "\n bad input\n", chv) ; exit(-1) ; } return(chv->type) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ return the symmetry flag of the chevron return value = SPOOLES_SYMMETRIC --> chevron is symmetric return value = SPOOLES_HERMITIAN --> chevron is hermitian return value = SPOOLES_NONSYMMETRIC --> chevron is nonsymmetric created -- 98apr30, cca ------------------------------------------------------------ */ int Chv_symmetryFlag ( Chv *chv ) { /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_symmetryFlag(%p)" "\n bad input\n", chv) ; exit(-1) ; } return(chv->symflag) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- fill *pnD with nD, *pnL with nL, and *pnU with nU. created -- 98apr30, cca -------------------------------------------------- */ void Chv_dimensions ( Chv *chv, int *pnD, int *pnL, int *pnU ) { /* --------------- check the input --------------- */ if ( chv == NULL || pnD == NULL || pnL == NULL || pnU == NULL ) { fprintf(stderr, "\n fatal error in Chv_dimensions(%p,%p,%p,%p)" "\n bad input\n", chv, pnD, pnL, pnU) ; exit(-1) ; } *pnD = chv->nD ; *pnL = chv->nL ; *pnU = chv->nU ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- fill *pnrow with nD + nL, *prowind with rowind created -- 98apr30, cca ---------------------------------------------- */ void Chv_rowIndices ( Chv *chv, int *pnrow, int **prowind ) { /* --------------- check the input --------------- */ if ( chv == NULL || pnrow == NULL || prowind == NULL ) { fprintf(stderr, "\n fatal error in Chv_rowIndices(%p,%p,%p)" "\n bad input\n", chv, pnrow, prowind) ; exit(-1) ; } if ( CHV_IS_NONSYMMETRIC(chv) ) { *pnrow = chv->nD + chv->nL ; *prowind = chv->rowind ; } else if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { *pnrow = chv->nD + chv->nU ; *prowind = chv->colind ; } else { fprintf(stderr, "\n fatal error in Chv_rowIndices(%p,%p,%p)" "\n bad symflag = %d\n", chv, pnrow, prowind, chv->symflag) ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- fill *pncol with nD + nU, *pcolind with colind created -- 98apr30, cca ---------------------------------------------- */ void Chv_columnIndices ( Chv *chv, int *pncol, int **pcolind ) { /* --------------- check the input --------------- */ if ( chv == NULL || pncol == NULL || pcolind == NULL ) { fprintf(stderr, "\n fatal error in Chv_columnIndices(%p,%p,%p)" "\n bad input\n", chv, pncol, pcolind) ; exit(-1) ; } *pncol = chv->nD + chv->nU ; *pcolind = chv->colind ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- return the number of entries created -- 98apr30, cca ---------------------------- */ int Chv_nent ( Chv *chv ) { int nD, nent, nL, nU ; /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_nent(%p)" "\n bad input\n", chv) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { nent = (nD*(nD+1))/2 + nD*nU ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { nent = nD*(nD + nL + nU) ; } else { fprintf(stderr, "\n fatal error in Chv_nent(%p)" "\n bad symmetry flag %d\n", chv, chv->symflag) ; exit(-1) ; } return(nent) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- fill *pentries with a pointer to the entries created -- 98apr30, cca -------------------------------------------- */ double * Chv_entries( Chv *chv ) { /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_entries(%p)" "\n bad input\n", chv) ; exit(-1) ; } return(chv->entries) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- return the location of the diagonal entry for the ichv'th chevron created -- 98apr30, cca ----------------------------------------- */ double * Chv_diagLocation( Chv *chv, int ichv ) { double *diag ; /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_diagLocation(%p)" "\n bad input\n", chv) ; exit(-1) ; } if ( ichv < 0 || ichv > chv->nD ) { fprintf(stderr, "\n fatal error in Chv_diagLocation(%p)" "\n ichv = %d, nD = %d\n", chv, ichv, chv->nD) ; exit(-1) ; } if ( chv->entries == NULL ) { fprintf(stderr, "\n fatal error in Chv_diagLocation(%p)" "\n chv->entries is NULL\n", chv) ; exit(-1) ; } if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_SYMMETRIC(chv) ) { diag = chv->entries + ichv*(chv->nD + chv->nU) - (ichv*(ichv-1))/2 ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { diag = chv->entries + (2*ichv+1)*chv->nD + (ichv+1)*chv->nL + ichv*chv->nU - ichv*ichv - ichv - 1 ; } else { fprintf(stderr, "\n fatal error in Chv_diagLocation(%p)" "\n type is SPOOLES_REAL, symflag = %d" "\n not SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC\n", chv, chv->symflag) ; exit(-1) ; } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { diag = chv->entries + 2*(ichv*(chv->nD + chv->nU) - (ichv*(ichv-1))/2) ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { diag = chv->entries + 2*((2*ichv+1)*chv->nD + (ichv+1)*chv->nL + ichv*chv->nU - ichv*ichv - ichv - 1) ; } else { fprintf(stderr, "\n fatal error in Chv_diagLocation(%p)" "\n bad symflag = %d, type is SPOOLES_COMPLEX," "\n must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN" "\n or SPOOLES_NONSYMMETRIC\n", chv, chv->symflag) ; exit(-1) ; } } else { fprintf(stderr, "\n fatal error in Chv_diagLocation(%p)" "\n bad type = %d, not SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, chv->symflag) ; exit(-1) ; } return(diag) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return a pointer to the start of the workspace created -- 98apr30, cca ---------------------------------------------- */ void * Chv_workspace( Chv *chv ) { /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_workspace(%p)" "\n bad input\n", chv) ; exit(-1) ; } return((void *) DV_entries(&chv->wrkDV)) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ fill *pValue with entry (irow, jcol) created -- 98apr30, cca ------------------------------------ */ void Chv_realEntry ( Chv *chv, int irow, int jcol, double *pValue ) { int ichv, ncol, nD, nL, nrow, nU, off ; double *base ; /* --------------- check the input --------------- */ if ( chv == NULL || irow < 0 || jcol < 0 || pValue == NULL ) { fprintf(stderr, "\n fatal error in Chv_realEntry(%p,%d,%d,%p)" "\n bad input\n", chv, irow, jcol, pValue) ; exit(-1) ; } if ( ! CHV_IS_REAL(chv) ) { fprintf(stderr, "\n fatal error in Chv_realEntry(%p,%d,%d,%p)" "\n bad type %d, not SPOOLES_REAL\n", chv, irow, jcol, pValue, chv->type) ; exit(-1) ; } if ( ! (CHV_IS_SYMMETRIC(chv) || CHV_IS_NONSYMMETRIC(chv)) ) { fprintf(stderr, "\n fatal error in Chv_realEntry(%p,%d,%d,%p)" "\n bad symflag %d" "\n must be SPOOLES_SYMMETRIC of SPOOLES_NONSYMMETRIC\n", chv, irow, jcol, pValue, chv->symflag) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; ncol = nD + nU ; if ( CHV_IS_SYMMETRIC(chv) ) { nrow = ncol ; } else { nrow = nD + nL ; } if ( irow >= nrow || jcol >= ncol ) { fprintf(stderr, "\n fatal error in Chv_realEntry(%p,%d,%d,%p)" "\n irow = %d, jcol = %d, nrow = %d, ncol = %d\n", chv, irow, jcol, pValue, irow, jcol, nrow, ncol) ; exit(-1) ; } if ( irow >= nD && jcol >= nD ) { *pValue = 0.0 ; } else { ichv = (irow <= jcol) ? irow : jcol ; off = jcol - irow ; if ( CHV_IS_SYMMETRIC(chv) && off < 0 ) { off = -off ; } base = Chv_diagLocation(chv, ichv) ; *pValue = base[off] ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- fill (*pReal,*pImag) with entry (irow, jcol) created -- 98apr30, cca -------------------------------------------- */ void Chv_complexEntry ( Chv *chv, int irow, int jcol, double *pReal, double *pImag ) { int ichv, ncol, nD, nL, nrow, nU, off ; double *base ; /* --------------- check the input --------------- */ if ( chv == NULL || irow < 0 || jcol < 0 || pReal == NULL || pImag == NULL ) { fprintf(stderr, "\n fatal error in Chv_complexEntry(%p,%d,%d,%p,%p)" "\n bad input\n", chv, irow, jcol, pReal, pImag) ; exit(-1) ; } if ( ! CHV_IS_COMPLEX(chv) ) { fprintf(stderr, "\n fatal error in Chv_complexEntry(%p,%d,%d,%p,%p)" "\n bad type %d, not SPOOLES_COMPLEX\n", chv, irow, jcol, pReal, pImag, chv->type) ; exit(-1) ; } if ( ! (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) || CHV_IS_NONSYMMETRIC(chv)) ) { fprintf(stderr, "\n fatal error in Chv_complexEntry(%p,%d,%d,%p,%p)" "\n bad symflag %d, not SPOOLES_SYMMETRIC, " "\n SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC \n", chv, irow, jcol, pReal, pImag, chv->symflag) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; ncol = nD + nU ; if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { nrow = ncol ; } else { nrow = nD + nL ; } if ( irow >= nrow || jcol >= ncol ) { fprintf(stderr, "\n fatal error in Chv_complexEntry(%p,%d,%d,%p,%p)" "\n irow = %d, jcol = %d, nrow = %d, ncol = %d\n", chv, irow, jcol, pReal, pImag, irow, jcol, nrow, ncol) ; exit(-1) ; } if ( irow >= nD && jcol >= nD ) { *pReal = *pImag = 0.0 ; } else { ichv = (irow <= jcol) ? irow : jcol ; off = jcol - irow ; if ( off < 0 && (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv)) ) { off = -off ; } base = Chv_diagLocation(chv, ichv) ; *pReal = base[2*off] ; if ( irow > jcol && CHV_IS_HERMITIAN(chv) ) { *pImag = - base[2*off+1] ; } else { *pImag = base[2*off+1] ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- fill *ppValue with the location of entry (irow, jcol) created -- 98apr30, cca ----------------------------------------------------- */ void Chv_locationOfRealEntry ( Chv *chv, int irow, int jcol, double **ppValue ) { int ichv, ncol, nD, nL, nrow, nU, off ; double *base ; /* --------------- check the input --------------- */ if ( chv == NULL || irow < 0 || jcol < 0 || ppValue == NULL ) { fprintf(stderr, "\n fatal error in Chv_locationOfRealEntry(%p,%d,%d,%p)" "\n bad input\n", chv, irow, jcol, ppValue) ; exit(-1) ; } if ( ! CHV_IS_REAL(chv) ) { fprintf(stderr, "\n fatal error in Chv_locationOfRealEntry(%p,%d,%d,%p)" "\n bad type %d, not SPOOLES_REAL\n", chv, irow, jcol, ppValue, chv->type) ; exit(-1) ; } if ( ! (CHV_IS_SYMMETRIC(chv) || CHV_IS_NONSYMMETRIC(chv)) ) { fprintf(stderr, "\n fatal error in Chv_locationOfRealEntry(%p,%d,%d,%p)" "\n bad symflag %d, not SPOOLES_SYMMETRIC of SPOOLES_NONSYMMETRIC\n", chv, irow, jcol, ppValue, chv->symflag) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; ncol = nD + nU ; if ( CHV_IS_SYMMETRIC(chv) ) { nrow = ncol ; } else { nrow = nD + nL ; } if ( irow >= nrow || jcol >= ncol ) { fprintf(stderr, "\n fatal error in Chv_locationOfRealEntry(%p,%d,%d,%p)" "\n irow = %d, jcol = %d, nrow = %d, ncol = %d\n", chv, irow, jcol, ppValue, irow, jcol, nrow, ncol) ; exit(-1) ; } if ( irow >= nD && jcol >= nD ) { *ppValue = NULL ; } else { ichv = (irow <= jcol) ? irow : jcol ; off = jcol - irow ; if ( CHV_IS_SYMMETRIC(chv) && off < 0 ) { off = -off ; } base = Chv_diagLocation(chv, ichv) ; *ppValue = base + off ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- fill (*ppReal,*ppImag) with location of entry (irow, jcol) created -- 98apr30, cca ---------------------------------------------------------- */ void Chv_locationOfComplexEntry ( Chv *chv, int irow, int jcol, double **ppReal, double **ppImag ) { int ichv, ncol, nD, nL, nrow, nU, off ; double *base ; /* --------------- check the input --------------- */ if ( chv == NULL || irow < 0 || jcol < 0 || ppReal == NULL || ppImag == NULL ) { fprintf(stderr, "\n fatal error in Chv_locationOfComplexEntry(%p,%d,%d,%p,%p)" "\n bad input\n", chv, irow, jcol, ppReal, ppImag) ; exit(-1) ; } if ( ! CHV_IS_COMPLEX(chv) ) { fprintf(stderr, "\n fatal error in Chv_locationOfComplexEntry(%p,%d,%d,%p,%p)" "\n bad type %d, not SPOOLES_COMPLEX\n", chv, irow, jcol, ppReal, ppImag, chv->type) ; exit(-1) ; } if ( ! (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) || CHV_IS_NONSYMMETRIC(chv)) ) { fprintf(stderr, "\n fatal error in Chv_locationOfComplexEntry(%p,%d,%d,%p,%p)" "\n bad symflag %d" "\n not SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN" "\n or SPOOLES_NONSYMMETRIC \n", chv, irow, jcol, ppReal, ppImag, chv->symflag) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; ncol = nD + nU ; if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { nrow = ncol ; } else { nrow = nD + nL ; } if ( irow >= nrow || jcol >= ncol ) { fprintf(stderr, "\n fatal error in Chv_locationOfComplexEntry(%p,%d,%d,%p,%p)" "\n irow = %d, jcol = %d, nrow = %d, ncol = %d\n", chv, irow, jcol, ppReal, ppImag, irow, jcol, nrow, ncol) ; exit(-1) ; } if ( irow >= nD && jcol >= nD ) { *ppReal = *ppImag = NULL ; } else { ichv = (irow <= jcol) ? irow : jcol ; off = jcol - irow ; if ( off < 0 && (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv)) ) { off = -off ; } base = Chv_diagLocation(chv, ichv) ; *ppReal = base + 2*off ; *ppImag = base + 2*off + 1 ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ set entry (irow, jcol) to value created -- 98apr30, cca ------------------------------------ */ void Chv_setRealEntry ( Chv *chv, int irow, int jcol, double value ) { int ichv, ncol, nD, nL, nrow, nU, off ; double *base ; /* --------------- check the input --------------- */ if ( chv == NULL || irow < 0 || jcol < 0 ) { fprintf(stderr, "\n fatal error in Chv_setRealEntry(%p,%d,%d,%e)" "\n bad input\n", chv, irow, jcol, value) ; exit(-1) ; } if ( ! CHV_IS_REAL(chv) ) { fprintf(stderr, "\n fatal error in Chv_setRealEntry(%p,%d,%d,%e)" "\n bad type %d, not SPOOLES_REAL\n", chv, irow, jcol, value, chv->type) ; exit(-1) ; } if ( ! (CHV_IS_SYMMETRIC(chv) || CHV_IS_NONSYMMETRIC(chv)) ) { fprintf(stderr, "\n fatal error in Chv_setRealEntry(%p,%d,%d,%e)" "\n bad symflag %d" "\n must be SPOOLES_SYMMETRIC of SPOOLES_NONSYMMETRIC\n", chv, irow, jcol, value, chv->symflag) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; ncol = nD + nU ; if ( CHV_IS_SYMMETRIC(chv) ) { nrow = ncol ; } else { nrow = nD + nL ; } if ( irow >= nrow || jcol >= ncol ) { fprintf(stderr, "\n fatal error in Chv_setRealEntry(%p,%d,%d,%e)" "\n irow = %d, jcol = %d, nrow = %d, ncol = %d\n", chv, irow, jcol, value, irow, jcol, nrow, ncol) ; exit(-1) ; } if ( irow < nD || jcol < nD ) { ichv = (irow <= jcol) ? irow : jcol ; off = jcol - irow ; if ( CHV_IS_SYMMETRIC(chv) && off < 0 ) { off = -off ; } base = Chv_diagLocation(chv, ichv) ; base[off] = value ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- fill (*pReal,*pImag) with entry (irow, jcol) created -- 98apr30, cca -------------------------------------------- */ void Chv_setComplexEntry ( Chv *chv, int irow, int jcol, double real, double imag ) { int ichv, ncol, nD, nL, nrow, nU, off ; double *base ; /* --------------- check the input --------------- */ if ( chv == NULL || irow < 0 || jcol < 0 ) { fprintf(stderr, "\n fatal error in Chv_setComplexEntry(%p,%d,%d,%e,%e)" "\n bad input\n", chv, irow, jcol, real, imag) ; exit(-1) ; } if ( ! CHV_IS_COMPLEX(chv) ) { fprintf(stderr, "\n fatal error in Chv_setComplexEntry(%p,%d,%d,%e,%e)" "\n bad type %d, not SPOOLES_COMPLEX\n", chv, irow, jcol, real, imag, chv->type) ; exit(-1) ; } if ( ! (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) || CHV_IS_NONSYMMETRIC(chv)) ) { fprintf(stderr, "\n fatal error in Chv_setComplexEntry(%p,%d,%d,%e,%e)" "\n bad symflag %d" "\n not SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN" "\n or SPOOLES_NONSYMMETRIC \n", chv, irow, jcol, real, imag, chv->symflag) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; ncol = nD + nU ; if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { nrow = ncol ; } else { nrow = nD + nL ; } if ( irow >= nrow || jcol >= ncol ) { fprintf(stderr, "\n fatal error in Chv_setComplexEntry(%p,%d,%d,%e,%e)" "\n irow = %d, jcol = %d, nrow = %d, ncol = %d\n", chv, irow, jcol, real, imag, irow, jcol, nrow, ncol) ; exit(-1) ; } if ( irow < nD || jcol < nD ) { ichv = (irow <= jcol) ? irow : jcol ; off = jcol - irow ; if ( off < 0 && (CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv)) ) { off = -off ; } base = Chv_diagLocation(chv, ichv) ; base[2*off] = real ; base[2*off+1] = imag ; } return ; } /*--------------------------------------------------------------------*/ --------------------------------*Chv/src/search.c010064400020550007177000000656420657126731400150410ustar00clevecompmath00000400000006/* search.c */ #include "../Chv.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------- find the first unmarked entry in the diagonal with largest magnitude if ( mark[jj] == tag ) then we can compare this entry endif created -- 98apr30, cca ----------------------------------- */ int Chv_maxabsInDiagonal11 ( Chv *chv, int mark[], int tag, double *pmaxval ) { double maxval, val ; double *entries ; int jcol, jj, nD, nL, nU, off, stride ; /* -------------- check the data -------------- */ if ( chv == NULL || mark == NULL || pmaxval == NULL ) { fprintf(stderr, "\n fatal error in Chv_maxabsInDiagonal11(%p,%p,%d,%p)" "\n bad input\n", chv, mark, tag, pmaxval) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_NONSYMMETRIC(chv) ) { /* -------------------- nonsymmetric chevron -------------------- */ jcol = -1 ; maxval = 0.0 ; off = nD + nL - 1 ; stride = 2*nD + nL + nU - 2 ; for ( jj = 0 ; jj < nD ; jj++ ) { if ( mark[jj] == tag ) { val = fabs(entries[off]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } off += stride ; stride -= 2 ; } } else if ( CHV_IS_SYMMETRIC(chv) ) { /* ----------------- symmetric chevron ----------------- */ jcol = -1 ; maxval = 0.0 ; off = 0 ; stride = nD + nU ; for ( jj = 0 ; jj < nD ; jj++ ) { if ( mark[jj] == tag ) { val = fabs(entries[off]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } off += stride ; stride-- ; } } else { fprintf(stderr, "\n fatal error in Chv_maxabsInDiagonal11(%p,%p,%d,%p)" "\n type = SPOOLES_REAL, bad symflag %d \n", chv, mark, tag, pmaxval, chv->symflag) ; exit(-1) ; } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_NONSYMMETRIC(chv) ) { /* -------------------- nonsymmetric chevron -------------------- */ jcol = -1 ; maxval = 0.0 ; off = nD + nL - 1 ; stride = 2*nD + nL + nU - 2 ; for ( jj = 0 ; jj < nD ; jj++ ) { if ( mark[jj] == tag ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } off += stride ; stride -= 2 ; } } else if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { /* ------------------------------ hermitian or symmetric chevron ------------------------------ */ jcol = -1 ; maxval = 0.0 ; off = 0 ; stride = nD + nU ; for ( jj = 0 ; jj < nD ; jj++ ) { if ( mark[jj] == tag ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } off += stride ; stride-- ; } } else { fprintf(stderr, "\n fatal error in Chv_maxabsInDiagonal11(%p,%p,%d,%p)" "\n type = SPOOLES_COMPLEX, bad symflag %d \n", chv, mark, tag, pmaxval, chv->symflag) ; exit(-1) ; } } else { fprintf(stderr, "\n fatal error in Chv_maxabsInDiagonal11(%p,%p,%d,%p)" "\n bad type, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, mark, tag, pmaxval) ; exit(-1) ; } *pmaxval = maxval ; return(jcol) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- find the first unmarked entry in row irow with largest magnitude if ( colmark[jj] == tag ) then we can examined this entry endif only entries in the (1,1) block are examined created -- 98apr30, cca -------------------------------------------- */ int Chv_maxabsInRow11 ( Chv *chv, int irow, int colmark[], int tag, double *pmaxval ) { double maxval, val ; double *entries ; int jcol, jj, nD, nL, nU, off, stride ; /* -------------- check the data -------------- */ if ( chv == NULL || irow < 0 || colmark == NULL || pmaxval == NULL ) { fprintf(stderr, "\n fatal error in Chv_maxabsInRow11(%p,%d,%p,%d,%p)" "\n bad input\n", chv, irow, colmark, tag, pmaxval) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_NONSYMMETRIC(chv) ) { /* -------------------- nonsymmetric chevron -------------------- */ jcol = -1 ; maxval = 0.0 ; off = nD + nL - 1 - irow ; stride = 2*nD + nL + nU - 1 ; for ( jj = 0 ; jj < irow ; jj++ ) { if ( colmark[jj] == tag ) { val = fabs(entries[off]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } off += stride ; stride -= 2 ; } for ( jj = irow ; jj < nD ; jj++, off++ ) { if ( colmark[jj] == tag ) { val = fabs(entries[off]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } } } else if ( CHV_IS_SYMMETRIC(chv) ) { /* ----------------- symmetric chevron ----------------- */ jcol = -1 ; maxval = 0.0 ; off = irow ; stride = nD + nU - 1 ; for ( jj = 0 ; jj < irow ; jj++ ) { if ( colmark[jj] == tag ) { val = fabs(entries[off]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } off += stride ; stride-- ; } for ( jj = irow ; jj < nD ; jj++, off++ ) { if ( colmark[jj] == tag ) { val = fabs(entries[off]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } } } else { fprintf(stderr, "\n fatal error in Chv_maxabsInRow11(%p,%d,%p,%d,%p)" "\n type is SPOOLES_REAL, bad symflag %d \n", chv, irow, colmark, tag, pmaxval, chv->symflag) ; exit(-1) ; } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_NONSYMMETRIC(chv) ) { /* -------------------- nonsymmetric chevron -------------------- */ jcol = -1 ; maxval = 0.0 ; off = nD + nL - 1 - irow ; stride = 2*nD + nL + nU - 1 ; for ( jj = 0 ; jj < irow ; jj++ ) { if ( colmark[jj] == tag ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } off += stride ; stride -= 2 ; } for ( jj = irow ; jj < nD ; jj++, off++ ) { if ( colmark[jj] == tag ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } } } else if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { /* ------------------------------ hermitian or symmetric chevron ------------------------------ */ jcol = -1 ; maxval = 0.0 ; off = irow ; stride = nD + nU - 1 ; for ( jj = 0 ; jj < irow ; jj++ ) { if ( colmark[jj] == tag ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } off += stride ; stride-- ; } for ( jj = irow ; jj < nD ; jj++, off++ ) { if ( colmark[jj] == tag ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } } } else { fprintf(stderr, "\n fatal error in Chv_maxabsInRow11(%p,%d,%p,%d,%p)" "\n type is SPOOLES_COMPLEX, bad symflag %d \n", chv, irow, colmark, tag, pmaxval, chv->symflag) ; exit(-1) ; } } else { fprintf(stderr, "\n fatal error in Chv_maxabsInRow11(%p,%d,%p,%d,%p)" "\n bad type, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, irow, colmark, tag, pmaxval) ; exit(-1) ; } *pmaxval = maxval ; return(jcol) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- find the first unmarked entry in column jcol with largest magnitude if ( rowmark[ii] == tag ) then we can examined this entry endif only entries in the (1,1) block are examined created -- 98apr30, cca -------------------------------------------- */ int Chv_maxabsInColumn11 ( Chv *chv, int jcol, int rowmark[], int tag, double *pmaxval ) { double maxval, val ; double *entries ; int irow, ii, nD, nL, nU, off, stride ; /* -------------- check the data -------------- */ if ( chv == NULL || jcol < 0 || rowmark == NULL || pmaxval == NULL ) { fprintf(stderr, "\n fatal error in Chv_maxabsInColumn11(%p,%d,%p,%d,%p)" "\n bad input\n", chv, jcol, rowmark, tag, pmaxval) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; irow = -1 ; maxval = 0.0 ; if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_NONSYMMETRIC(chv) ) { /* -------------------- nonsymmetric chevron -------------------- */ maxval = 0.0 ; off = nD + nL + jcol - 1 ; stride = 2*nD + nL + nU - 3 ; for ( ii = 0 ; ii < jcol ; ii++ ) { if ( rowmark[ii] == tag ) { val = fabs(entries[off]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } off += stride ; stride -= 2 ; } for ( ii = jcol ; ii < nD ; ii++, off-- ) { if ( rowmark[ii] == tag ) { val = fabs(entries[off]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } } } else if ( CHV_IS_SYMMETRIC(chv) ) { /* ----------------- symmetric chevron ----------------- */ maxval = 0.0 ; off = jcol ; stride = nD + nU - 1 ; for ( ii = 0 ; ii < jcol ; ii++ ) { if ( rowmark[ii] == tag ) { val = fabs(entries[off]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } off += stride ; stride-- ; } for ( ii = jcol ; ii < nD ; ii++, off++ ) { if ( rowmark[ii] == tag ) { val = fabs(entries[off]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } } } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_NONSYMMETRIC(chv) ) { /* -------------------- nonsymmetric chevron -------------------- */ maxval = 0.0 ; off = nD + nL + jcol - 1 ; stride = 2*nD + nL + nU - 3 ; for ( ii = 0 ; ii < jcol ; ii++ ) { if ( rowmark[ii] == tag ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } off += stride ; stride -= 2 ; } for ( ii = jcol ; ii < nD ; ii++, off-- ) { if ( rowmark[ii] == tag ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } } } else if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { /* ------------------------------ hermitian or symmetric chevron ------------------------------ */ maxval = 0.0 ; off = jcol ; stride = nD + nU - 1 ; for ( ii = 0 ; ii < jcol ; ii++ ) { if ( rowmark[ii] == tag ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } off += stride ; stride-- ; } for ( ii = jcol ; ii < nD ; ii++, off++ ) { if ( rowmark[ii] == tag ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } } } } else { fprintf(stderr, "\n fatal error in Chv_maxabsInColumn11(%p,%d,%p,%d,%p)" "\n bad type, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, jcol, rowmark, tag, pmaxval) ; exit(-1) ; } *pmaxval = maxval ; return(irow) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- return the location of the first entry with largest magnitude in row irow. *pmaxval is filled with its magnitude. created -- 98apr30, cca -------------------------------------- */ int Chv_maxabsInRow ( Chv *chv, int irow, double *pmaxval ) { double maxval, val ; double *entries ; int jcol, jj, ncol, nD, nL, nU, off, stride ; /* -------------- check the data -------------- */ if ( chv == NULL || irow < 0 || pmaxval == NULL ) { fprintf(stderr, "\n fatal error in Chv_maxabsInRow(%p,%d,%p)" "\n bad input\n", chv, irow, pmaxval) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; ncol = nD + nU ; jcol = -1 ; maxval = 0.0 ; if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_NONSYMMETRIC(chv) ) { /* -------------------- nonsymmetric chevron -------------------- */ jcol = -1 ; maxval = 0.0 ; off = nD + nL - 1 - irow ; stride = 2*nD + nL + nU - 1 ; for ( jj = 0 ; jj < irow ; jj++ ) { val = fabs(entries[off]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } off += stride ; stride -= 2 ; } for ( jj = irow ; jj < ncol ; jj++, off++ ) { val = fabs(entries[off]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } } else if ( CHV_IS_SYMMETRIC(chv) ) { /* ----------------- symmetric chevron ----------------- */ jcol = -1 ; maxval = 0.0 ; off = irow ; stride = nD + nU - 1 ; for ( jj = 0 ; jj < irow ; jj++ ) { val = fabs(entries[off]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } off += stride ; stride-- ; } for ( jj = irow ; jj < ncol ; jj++, off++ ) { val = fabs(entries[off]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_NONSYMMETRIC(chv) ) { /* -------------------- nonsymmetric chevron -------------------- */ jcol = -1 ; maxval = 0.0 ; off = nD + nL - 1 - irow ; stride = 2*nD + nL + nU - 1 ; for ( jj = 0 ; jj < irow ; jj++ ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } off += stride ; stride -= 2 ; } for ( jj = irow ; jj < ncol ; jj++, off++ ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } } else if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { /* ------------------------------ hermitian or symmetric chevron ------------------------------ */ jcol = -1 ; maxval = 0.0 ; off = irow ; stride = nD + nU - 1 ; for ( jj = 0 ; jj < irow ; jj++ ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } off += stride ; stride-- ; } for ( jj = irow ; jj < ncol ; jj++, off++ ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( jcol == -1 || maxval < val ) { jcol = jj ; maxval = val ; } } } } else { fprintf(stderr, "\n fatal error in Chv_maxabsInRow(%p,%d,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX \n", chv, irow, pmaxval, chv->symflag) ; exit(-1) ; } *pmaxval = maxval ; return(jcol) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- return the location of the first entry with largest magnitude in column jcol. *pmaxval is filled with its magnitude. created -- 98apr30, cca -------------------------------------- */ int Chv_maxabsInColumn ( Chv *chv, int jcol, double *pmaxval ) { double maxval, val ; double *entries ; int irow, ii, nD, nL, nrow, nU, off, stride ; /* -------------- check the data -------------- */ if ( chv == NULL || jcol < 0 || pmaxval == NULL ) { fprintf(stderr, "\n fatal error in Chv_maxabsInColumn(%p,%d,%p)" "\n bad input\n", chv, jcol, pmaxval) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; nrow = nD + nL ; irow = -1 ; maxval = 0.0 ; if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_NONSYMMETRIC(chv) ) { /* -------------------- nonsymmetric chevron -------------------- */ maxval = 0.0 ; off = nD + nL + jcol - 1 ; stride = 2*nD + nL + nU - 3 ; for ( ii = 0 ; ii < jcol ; ii++ ) { val = fabs(entries[off]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } off += stride ; stride -= 2 ; } for ( ii = jcol ; ii < nrow ; ii++, off-- ) { val = fabs(entries[off]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } } else if ( CHV_IS_SYMMETRIC(chv) ) { /* ----------------- symmetric chevron ----------------- */ maxval = 0.0 ; off = jcol ; stride = nD + nU - 1 ; for ( ii = 0 ; ii < jcol ; ii++ ) { val = fabs(entries[off]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } off += stride ; stride-- ; } for ( ii = jcol ; ii < nrow ; ii++, off++ ) { val = fabs(entries[off]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_NONSYMMETRIC(chv) ) { /* -------------------- nonsymmetric chevron -------------------- */ maxval = 0.0 ; off = nD + nL + jcol - 1 ; stride = 2*nD + nL + nU - 3 ; for ( ii = 0 ; ii < jcol ; ii++ ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } off += stride ; stride -= 2 ; } for ( ii = jcol ; ii < nrow ; ii++, off-- ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } } else if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { /* ------------------------------ hermitian or symmetric chevron ------------------------------ */ maxval = 0.0 ; off = jcol ; stride = nD + nU - 1 ; for ( ii = 0 ; ii < jcol ; ii++ ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } off += stride ; stride-- ; } for ( ii = jcol ; ii < nrow ; ii++, off++ ) { val = Zabs(entries[2*off], entries[2*off+1]) ; if ( irow == -1 || maxval < val ) { irow = ii ; maxval = val ; } } } } else { fprintf(stderr, "\n fatal error in Chv_maxabsInColumn(%p,%d,%p)" "\n bad symflag %d \n", chv, jcol, pmaxval, chv->symflag) ; exit(-1) ; } *pmaxval = maxval ; return(irow) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- return the magnitude of a quasimax entry from the unmarked rows and columns and fill *pirow and *pjcol with its location created -- 98apr30, cca ------------------------------------------------------------- */ double Chv_quasimax ( Chv *chv, int rowmark[], int colmark[], int tag, int *pirow, int *pjcol ) { double maxval ; int irow, jcol, nD, qcol, qrow ; /* --------------- check the input --------------- */ if ( chv == NULL || rowmark == NULL || colmark == NULL || pirow == NULL || pjcol == NULL ) { fprintf(stderr, "\n fatal error in Chv_quasimax(%p,%p,%p,%d,%p,%p)" "\n bad input\n", chv, rowmark, colmark, tag, pirow, pjcol) ; exit(-1) ; } if ( ! CHV_IS_NONSYMMETRIC(chv) ) { fprintf(stderr, "\n fatal error in Chv_quasimax(%p,%p,%p,%d,%p,%p)" "\n chv->symflag = %d" "\n chevron is not symmetric or hermitian" "\n method cannot be used \n", chv, rowmark, colmark, tag, pirow, pjcol, chv->symflag) ; exit(-1) ; } nD = chv->nD ; /* ---------------------- set the default values ---------------------- */ *pirow = *pjcol = -1 ; maxval = 0.0 ; /* ----------------------- find an unmarked column ----------------------- */ for ( jcol = 0 ; jcol < nD ; jcol++ ) { if ( colmark[jcol] == tag ) { break ; } } if ( jcol == nD ) { /* --------------------------- no unmarked columns, return --------------------------- */ return(maxval) ; } /* ---------------------------------------- find a maxabs entry in the unmarked rows ---------------------------------------- */ irow = Chv_maxabsInColumn11(chv, jcol, rowmark, tag, &maxval) ; #if MYDEBUG > 0 fprintf(stdout, "\n first maxabs = %12.4e in (%d,%d)", Chv_entry(chv, irow, jcol), irow, jcol) ; fflush(stdout) ; #endif if ( irow == -1 ) { /* ------------------------ no unmarked rows, return ------------------------ */ return(maxval) ; } while ( 1 ) { /* ---------------------------------- find a new maxabs entry in the row ---------------------------------- */ qcol = Chv_maxabsInRow11(chv, irow, colmark, tag, &maxval) ; #if MYDEBUG > 0 fprintf(stdout, "\n new maxabs = %12.4e in (%d,%d)", Chv_entry(chv, irow, qcol), irow, qcol) ; fflush(stdout) ; #endif if ( qcol == jcol ) { /* -------------------------------------------- same as before, break out of the search loop -------------------------------------------- */ break ; } jcol = qcol ; /* ------------------------------------- find a new maxabs entry in the column ------------------------------------- */ qrow = Chv_maxabsInColumn11(chv, jcol, rowmark, tag, &maxval) ; #if MYDEBUG > 0 fprintf(stdout, "\n new maxabs = %12.4e in (%d,%d)", Chv_entry(chv, qrow, jcol), qrow, jcol) ; fflush(stdout) ; #endif if ( qrow == irow ) { /* -------------------------------------------- same as before, break out of the search loop -------------------------------------------- */ break ; } irow = qrow ; } /* -------------------------------------------------------- set the row and column where the quasimax entry is found -------------------------------------------------------- */ *pjcol = jcol ; *pirow = irow ; return(maxval) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- find a 1x1 or 2x2 pivot using the fast Bunch-Parlett algorithm. used only with symmetric chevrons. created -- 98apr30, cca --------------------------------------------------------------- */ void Chv_fastBunchParlettPivot ( Chv *chv, int mark[], int tag, int *pirow, int *pjcol ) { double maxdiag, gamma_r, gamma_s ; double *entries ; int nD, nL, nU, r, s, t ; /* -------------- check the data -------------- */ if ( chv == NULL || mark == NULL || pirow == NULL || pjcol == NULL ) { fprintf(stderr, "\n fatal error in Chv_fastBunchParlettPivot(%p,%p,%d,%p,%p)" "\n bad input\n", chv, mark, tag, pirow, pjcol) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; /* ---------------------- set the default values ---------------------- */ *pirow = *pjcol = -1 ; /* ------------------------------------------ find an unmarked entry of maximum magitude ------------------------------------------ */ r = Chv_maxabsInDiagonal11(chv, mark, tag, &maxdiag) ; if ( r == -1 ) { /* ------------------------------------------------------- all rows and columns are marked, return without success ------------------------------------------------------- */ *pirow = *pjcol = -1 ; return ; } /* ------------------------------------------------------------------- find the offdiagonal entry of maximum magnitude in row and column r ------------------------------------------------------------------- */ s = -1 ; gamma_r = 0.0 ; s = Chv_maxabsInRow11(chv, r, mark, tag, &gamma_r) ; if ( s == -1 ) { /* --------------------------------------------- r is the only unmarked row and column, return --------------------------------------------- */ *pirow = *pjcol = r ; return ; } if ( maxdiag >= 0.6404 * gamma_r ) { /* ------------------------- 1 x 1 pivot is acceptable ------------------------- */ *pirow = *pjcol = r ; return ; } else { /* --------------- loop until done --------------- */ while ( 1 ) { /* ---------------------------------------------- find t = index of max off diag entry in column s gamma_s is its magnitude ---------------------------------------------- */ t = Chv_maxabsInRow11(chv, s, mark, tag, &gamma_s) ; if ( t == r || gamma_s == gamma_r ) { /* ------------------------- 2 x 2 pivot is acceptable ------------------------- */ *pirow = r ; *pjcol = s ; return ; } else { /* -------------------------------- keep looking for a local maximum -------------------------------- */ r = s ; gamma_r = gamma_s ; s = t ; } } } return ; } /*--------------------------------------------------------------------*/ -------------------- return the location of the first entry with largest magnitude in cChv/src/swap.c010064400020550007177000000407360657126731400145430ustar00clevecompmath00000400000006/* swap.c */ #include "../Chv.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- swap rows irow and jrow created -- 98apr30, cca ----------------------- */ void Chv_swapRows ( Chv *chv, int irow, int jrow ) { double dtmp ; double *entries ; int ii, ioff, itmp, joff, nD, nL, nrow, nU, stride ; int *rowind ; /* --------------- check the input --------------- */ if ( chv == NULL || irow < 0 || jrow < 0 ) { fprintf(stderr, "\n fatal error in Chv_swapRows(%p,%d,%d)" "\n bad input\n", chv, irow, jrow) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout,"\n %% Chv_swapRows(%p,%d,%d)", chv, irow, jrow) ; fprintf(stdout,"\n %% chv->symflag = %d", chv->symflag) ; fflush(stdout) ; #endif if ( irow == jrow ) { return ; } Chv_dimensions(chv, &nD, &nL, &nU) ; if ( irow >= nD || jrow >= nD ) { fprintf(stderr, "\n fatal error in Chv_swapRows(%p,%d,%d)" "\n rows must be less than nD = %d", chv, irow, irow, nD) ; exit(-1) ; } entries = Chv_entries(chv) ; #if MYDEBUG > 0 fprintf(stdout,"\n %% nD = %d, nL = %d, nU = %d, entries = %p", nD, nL, nU, entries) ; fflush(stdout) ; #endif if ( entries == NULL ) { fprintf(stderr, "\n fatal error in Chv_swapRows(%p,%d,%d)" "\n bad input, entries = %p, nD = %d\n", chv, irow, jrow, entries, nD) ; exit(-1) ; } if ( ! (CHV_IS_REAL(chv) || CHV_IS_COMPLEX(chv)) ) { fprintf(stderr, "\n fatal error in Chv_swapRows(%p,%d,%d)" "\n type = %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, irow, jrow, chv->type) ; exit(-1) ; } if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { /* ------------------------------------------------ call method for hermitian and symmetric chevrons ------------------------------------------------ */ Chv_swapRowsAndColumns(chv, irow, jrow) ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { /* ------------------------ swap the two row indices ------------------------ */ #if MYDEBUG > 0 fprintf(stdout, "\n %% getting ready to swap row indices") ; fflush(stdout) ; #endif Chv_rowIndices(chv, &nrow, &rowind) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% before: rowind = %p, rowind[%d] = %d, rowind[%d] = %d", rowind, irow, rowind[irow], jrow, rowind[jrow]) ; IVfprintf(stdout, nrow, rowind) ; fflush(stdout) ; #endif itmp = rowind[irow] ; rowind[irow] = rowind[jrow] ; rowind[jrow] = itmp ; #if MYDEBUG > 0 fprintf(stdout, "\n %% after: rowind = %p, rowind[%d] = %d, rowind[%d] = %d", rowind, irow, rowind[irow], jrow, rowind[jrow]) ; IVfprintf(stdout, nrow, rowind) ; fflush(stdout) ; #endif /* -------------------------------------------------- set irow = min(irow, jrow), jrow = max(irow, jrow) -------------------------------------------------- */ if ( irow > jrow ) { itmp = irow ; irow = jrow ; jrow = itmp ; } /* -------------------------------- swap the entries in the two rows -------------------------------- */ ioff = nD + nL - 1 - irow ; joff = nD + nL - 1 - jrow ; stride = 2*nD + nL + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < irow ; ii++ ) { dtmp = entries[ioff] ; entries[ioff] = entries[joff] ; entries[joff] = dtmp ; ioff += stride, joff += stride, stride -= 2 ; } for ( ii = irow ; ii < jrow ; ii++ ) { dtmp = entries[ioff] ; entries[ioff] = entries[joff] ; entries[joff] = dtmp ; ioff += 1, joff += stride, stride -= 2 ; } for ( ii = jrow ; ii < nD + nU ; ii++ ) { dtmp = entries[ioff] ; entries[ioff] = entries[joff] ; entries[joff] = dtmp ; ioff += 1, joff += 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < irow ; ii++ ) { dtmp = entries[2*ioff] ; entries[2*ioff] = entries[2*joff] ; entries[2*joff] = dtmp ; dtmp = entries[2*ioff+1] ; entries[2*ioff+1] = entries[2*joff+1] ; entries[2*joff+1] = dtmp ; ioff += stride, joff += stride, stride -= 2 ; } for ( ii = irow ; ii < jrow ; ii++ ) { dtmp = entries[2*ioff] ; entries[2*ioff] = entries[2*joff] ; entries[2*joff] = dtmp ; dtmp = entries[2*ioff+1] ; entries[2*ioff+1] = entries[2*joff+1] ; entries[2*joff+1] = dtmp ; ioff += 1, joff += stride, stride -= 2 ; } for ( ii = jrow ; ii < nD + nU ; ii++ ) { dtmp = entries[2*ioff] ; entries[2*ioff] = entries[2*joff] ; entries[2*joff] = dtmp ; dtmp = entries[2*ioff+1] ; entries[2*ioff+1] = entries[2*joff+1] ; entries[2*joff+1] = dtmp ; ioff += 1, joff += 1 ; } } } else { fprintf(stderr, "\n fatal error in Chv_swapRows(%p,%d,%d)" "\n bad symmetryflag %d\n", chv, irow, jrow, chv->symflag) ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------- swap columns icol and jcol created -- 98apr30, cca -------------------------- */ void Chv_swapColumns ( Chv *chv, int icol, int jcol ) { double dtmp ; double *entries ; int ii, ioff, itmp, joff, ncol, nD, nL, nU, stride ; int *colind ; /* --------------- check the input --------------- */ if ( chv == NULL || icol < 0 || jcol < 0 ) { fprintf(stderr, "\n fatal error in Chv_swapColumns(%p,%d,%d)" "\n bad input\n", chv, icol, jcol) ; exit(-1) ; } if ( icol == jcol ) { return ; } Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; if ( entries == NULL || icol >= nD || jcol >= nD ) { fprintf(stderr, "\n fatal error in Chv_swapColumns(%p,%d,%d)" "\n bad input, entries = %p, nD = %d\n", chv, icol, jcol, entries, nD) ; exit(-1) ; } if ( ! (CHV_IS_REAL(chv) || CHV_IS_COMPLEX(chv)) ) { fprintf(stderr, "\n fatal error in Chv_swapColumns(%p,%d,%d)" "\n type = %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, icol, jcol, chv->type) ; exit(-1) ; } if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { /* ------------------------------------------------ call method for symmetric and hermitian chevrons ------------------------------------------------ */ Chv_swapRowsAndColumns(chv, icol, jcol) ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { /* --------------------------- swap the two column indices --------------------------- */ Chv_columnIndices(chv, &ncol, &colind) ; itmp = colind[icol] ; colind[icol] = colind[jcol] ; colind[jcol] = itmp ; /* -------------------------------------------------- set icol = min(icol, jcol), jcol = max(icol, jcol) -------------------------------------------------- */ if ( icol > jcol ) { itmp = icol ; icol = jcol ; jcol = itmp ; } /* ----------------------------------- swap the entries in the two columns ----------------------------------- */ ioff = nD + nL - 1 + icol ; joff = nD + nL - 1 + jcol ; stride = 2*nD + nL + nU - 3 ; if ( CHV_IS_REAL(chv) ) { for ( ii = 0 ; ii < icol ; ii++ ) { dtmp = entries[ioff] ; entries[ioff] = entries[joff] ; entries[joff] = dtmp ; ioff += stride, joff += stride, stride -= 2 ; } for ( ii = icol ; ii < jcol ; ii++ ) { dtmp = entries[ioff] ; entries[ioff] = entries[joff] ; entries[joff] = dtmp ; ioff -= 1, joff += stride, stride -= 2 ; } for ( ii = jcol ; ii < nD + nL ; ii++ ) { dtmp = entries[ioff] ; entries[ioff] = entries[joff] ; entries[joff] = dtmp ; ioff -= 1, joff -= 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ii = 0 ; ii < icol ; ii++ ) { dtmp = entries[2*ioff] ; entries[2*ioff] = entries[2*joff] ; entries[2*joff] = dtmp ; dtmp = entries[2*ioff+1] ; entries[2*ioff+1] = entries[2*joff+1] ; entries[2*joff+1] = dtmp ; ioff += stride, joff += stride, stride -= 2 ; } for ( ii = icol ; ii < jcol ; ii++ ) { dtmp = entries[2*ioff] ; entries[2*ioff] = entries[2*joff] ; entries[2*joff] = dtmp ; dtmp = entries[2*ioff+1] ; entries[2*ioff+1] = entries[2*joff+1] ; entries[2*joff+1] = dtmp ; ioff -= 1, joff += stride, stride -= 2 ; } for ( ii = jcol ; ii < nD + nL ; ii++ ) { dtmp = entries[2*ioff] ; entries[2*ioff] = entries[2*joff] ; entries[2*joff] = dtmp ; dtmp = entries[2*ioff+1] ; entries[2*ioff+1] = entries[2*joff+1] ; entries[2*joff+1] = dtmp ; ioff -= 1, joff -= 1 ; } } } else { fprintf(stderr, "\n fatal error in Chv_swapColumns(%p,%d,%d)" "\n bad symmetryflag %d\n", chv, icol, jcol, chv->symflag) ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------- swap rows and columns ii and jj created -- 98apr30, cca ------------------------------- */ void Chv_swapRowsAndColumns ( Chv *chv, int ii, int jj ) { double dtmp ; double *entries ; int iiloc, ioff, itmp, jjloc, joff, kk, ncol, nD, nL, nU, stride ; int *colind ; /* --------------- check the input --------------- */ if ( chv == NULL || ii < 0 || jj < 0 ) { fprintf(stderr, "\n fatal error in Chv_swapRowsAndColumns(%p,%d,%d)" "\n bad input\n", chv, ii, jj) ; exit(-1) ; } if ( ii == jj ) { return ; } Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; if ( entries == NULL || ii >= nD || jj >= nD ) { fprintf(stderr, "\n fatal error in Chv_swapRowsAndColumns(%p,%d,%d)" "\n bad input, entries = %p, nD = %d\n", chv, ii, jj, entries, nD) ; exit(-1) ; } if ( ! (CHV_IS_REAL(chv) || CHV_IS_COMPLEX(chv)) ) { fprintf(stderr, "\n fatal error in Chv_swapRowsAndColumns(%p,%d,%d)" "\n type = %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, ii, jj, chv->type) ; exit(-1) ; } if ( CHV_IS_NONSYMMETRIC(chv) ) { /* -------------------------------------- call methods for nonsymmetric chevrons -------------------------------------- */ Chv_swapRows(chv, ii, jj) ; Chv_swapColumns(chv, ii, jj) ; } else if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { /* --------------------------- swap the two column indices --------------------------- */ Chv_columnIndices(chv, &ncol, &colind) ; itmp = colind[ii] ; colind[ii] = colind[jj] ; colind[jj] = itmp ; /* -------------------------------------- set ii = min(ii, jj), jj = max(ii, jj) -------------------------------------- */ if ( ii > jj ) { itmp = ii ; ii = jj ; jj = itmp ; } /* ------------------------------------------ step 1, swap A(0:ii-1,ii) and A(0:ii-1,jj) ------------------------------------------ */ ioff = ii ; joff = jj ; stride = nD + nU - 1 ; if ( CHV_IS_REAL(chv) ) { for ( kk = 0 ; kk < ii ; kk++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n %% first step, kk = %d, ioff = %d, joff = %d, stride = %d", kk, ioff, joff, stride) ; #endif dtmp = entries[ioff] ; entries[ioff] = entries[joff] ; entries[joff] = dtmp ; ioff += stride, joff += stride, stride -= 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( kk = 0 ; kk < ii ; kk++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n %% first step, kk = %d, ioff = %d, joff = %d, stride = %d", kk, ioff, joff, stride) ; #endif dtmp = entries[2*ioff] ; entries[2*ioff] = entries[2*joff] ; entries[2*joff] = dtmp ; dtmp = entries[2*ioff+1] ; entries[2*ioff+1] = entries[2*joff+1] ; entries[2*joff+1] = dtmp ; ioff += stride, joff += stride, stride -= 1 ; } } iiloc = ioff ; /* ------------------------------------------- 2. swap A(ii,ii+1:jj-1) and A(ii+1:jj-1,jj) tricky part if hermitian ------------------------------------------- */ ioff++, joff += stride, stride -= 1 ; if ( CHV_IS_REAL(chv) ) { for ( kk = ii + 1 ; kk < jj ; kk++ ) { double aiikk, akkjj ; #if MYDEBUG > 0 fprintf(stdout, "\n\n second step, %% kk = %d, ioff = %d, joff = %d, stride = %d", kk, ioff, joff, stride) ; #endif aiikk = entries[ioff] ; akkjj = entries[joff] ; entries[ioff] = akkjj ; entries[joff] = aiikk ; ioff += 1, joff += stride, stride -= 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( kk = ii + 1 ; kk < jj ; kk++ ) { double imagiikk, imagkkjj, realiikk, realkkjj ; #if MYDEBUG > 0 fprintf(stdout, "\n\n second step, %% kk = %d, ioff = %d, joff = %d, stride = %d", kk, ioff, joff, stride) ; #endif realiikk = entries[2*ioff] ; imagiikk = entries[2*ioff+1] ; realkkjj = entries[2*joff] ; imagkkjj = entries[2*joff+1] ; entries[2*ioff] = realkkjj ; entries[2*joff] = realiikk ; if ( CHV_IS_SYMMETRIC(chv) ) { entries[2*ioff+1] = imagkkjj ; entries[2*joff+1] = imagiikk ; } else { entries[2*ioff+1] = -imagkkjj ; entries[2*joff+1] = -imagiikk ; } ioff += 1, joff += stride, stride -= 1 ; } if ( CHV_IS_HERMITIAN(chv) ) { /* ---------------------------------- set (ii,jj) entry to its conjugate ---------------------------------- */ entries[2*ioff+1] = -entries[2*ioff+1] ; } } jjloc = joff ; /* ----------------------------- 4. swap A(ii,ii) and A(jj,jj) ----------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n\n %% third step, iiloc = %d, jjloc = %d", iiloc, jjloc) ; #endif if ( CHV_IS_REAL(chv) ) { dtmp = entries[iiloc] ; entries[iiloc] = entries[jjloc] ; entries[jjloc] = dtmp ; } else if ( CHV_IS_COMPLEX(chv) ) { dtmp = entries[2*iiloc] ; entries[2*iiloc] = entries[2*jjloc] ; entries[2*jjloc] = dtmp ; dtmp = entries[2*iiloc+1] ; entries[2*iiloc+1] = entries[2*jjloc+1] ; entries[2*jjloc+1] = dtmp ; } /* ------------------------------------------------- swap 4. swap A(ii,jj+1:nD+nU-1) and A(jj,jj+1:nD+nU-1) ------------------------------------------------- */ ioff++, joff++ ; if ( CHV_IS_REAL(chv) ) { for ( kk = jj + 1 ; kk < nD + nU ; kk++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n %% fourth step, kk = %d, ioff = %d, joff = %d, stride = %d", kk, ioff, joff, stride) ; #endif dtmp = entries[ioff] ; entries[ioff] = entries[joff] ; entries[joff] = dtmp ; ioff += 1, joff += 1 ; } } else if ( CHV_IS_COMPLEX(chv) ) { for ( kk = jj + 1 ; kk < nD + nU ; kk++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n %% fourth step, kk = %d, ioff = %d, joff = %d, stride = %d", kk, ioff, joff, stride) ; #endif dtmp = entries[2*ioff] ; entries[2*ioff] = entries[2*joff] ; entries[2*joff] = dtmp ; dtmp = entries[2*ioff+1] ; entries[2*ioff+1] = entries[2*joff+1] ; entries[2*joff+1] = dtmp ; ioff += 1, joff += 1 ; } } } else { fprintf(stderr, "\n fatal error in Chv_swapRowsAndColumns(%p,%d,%d)" "\n bad symmetryflag %d\n", chv, ii, jj, chv->symflag) ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ Chv/src/update.c010064400020550007177000003410360657126731400150500ustar00clevecompmath00000400000006/* update.c */ #include "../Chv.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- perform the hermitian factor update T_{\bnd{I} \cap J, \bnd{I} \cap J} -= U_{I, \bnd{I} \cap J}^H D_{I, I} U_{I, \bnd{I} \cap J} and T_{\bnd{I} \cap J, \bnd{I} \cap \bnd{J}} -= U_{I, \bnd{I} \cap J}^H D_{I, I} U_{I, \bnd{I} \cap \bnd{J}} created -- 98apr17, cca --------------------------------------------------------------------- */ void Chv_updateH ( Chv *chvT, SubMtx *mtxD, SubMtx *mtxU, DV *tempDV ) { int firstInT, firstInU, jcolT, jcolU, lastInT, lastInU, ncolT, ncolU ; int *colindT, *colindU ; /* --------------- check the input --------------- */ if ( chvT == NULL || mtxD == NULL || mtxU == NULL || tempDV == NULL ) { fprintf(stderr, "\n fatal error in Chv_updateH(%p,%p,%p,%p)" "\n bad input\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } if ( ! CHV_IS_COMPLEX(chvT) ) { fprintf(stderr, "\n fatal error in Chv_updateH(%p,%p,%p,%p)" "\n bad input, chvT is not complex\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } if ( ! SUBMTX_IS_COMPLEX(mtxD) ) { fprintf(stderr, "\n fatal error in Chv_updateH(%p,%p,%p,%p)" "\n bad input, mtxD is not complex\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } if ( ! SUBMTX_IS_COMPLEX(mtxU) ) { fprintf(stderr, "\n fatal error in Chv_updateH(%p,%p,%p,%p)" "\n bad input, mtxU is not complex\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } Chv_columnIndices(chvT, &ncolT, &colindT) ; SubMtx_columnIndices(mtxU, &ncolU, &colindU) ; /* ----------------------------- locate first column of U in T ----------------------------- */ firstInT = colindT[0] ; lastInT = colindT[chvT->nD-1] ; for ( jcolU = 0 ; jcolU < ncolU ; jcolU++ ) { if ( firstInT <= colindU[jcolU] && colindU[jcolU] <= lastInT ) { break ; } } if ( (firstInU = jcolU) == ncolU ) { return ; } /* ---------------------------- locate last column of U in T ---------------------------- */ lastInU = firstInU ; for ( ; jcolU < ncolU ; jcolU++ ) { if ( colindU[jcolU] <= lastInT ) { lastInU = jcolU ; } else { break ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %% firstInU = %d, lastInU = %d", firstInU, lastInU) ; fflush(stdout) ; #endif /* ---------------------------------------------------------- overwrite supported column indices with indices local to T ---------------------------------------------------------- */ for ( jcolU = firstInU, jcolT = 0 ; jcolU < ncolU ; jcolU++ ) { while ( colindU[jcolU] != colindT[jcolT] ) { jcolT++ ; } colindU[jcolU] = jcolT ; } if ( SUBMTX_IS_DENSE_COLUMNS(mtxU) ) { double isum, rsum ; double sums[18] ; double *base0, *base1, *base2, *colU0, *colU1, *colU2, *entU, *rowUT0, *rowUT1, *rowUT2, *temp0, *temp1, *temp2 ; int ichv0, ichv1, ichv2, ii, inc1, inc2, irowUT, kloc0, kloc1, kloc2, nrowU ; SubMtx_denseInfo(mtxU, &nrowU, &ncolU, &inc1, &inc2, &entU) ; DV_setSize(tempDV, 6*nrowU) ; temp0 = DV_entries(tempDV) ; temp1 = temp0 + 2*nrowU ; temp2 = temp1 + 2*nrowU ; /* -------------------------------------------- loop over the rows of U^H in groups of three -------------------------------------------- */ rowUT0 = entU + 2*firstInU*nrowU ; for ( irowUT = firstInU ; irowUT <= lastInU - 2 ; irowUT += 3 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on rows %d, %d and %d", colindU[irowUT], colindU[irowUT+1], colindU[irowUT+2]) ; fflush(stdout) ; #endif rowUT1 = rowUT0 + 2*nrowU ; rowUT2 = rowUT1 + 2*nrowU ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - 2*ichv0 ; ichv1 = colindU[irowUT+1] ; base1 = Chv_diagLocation(chvT, ichv1) - 2*ichv1 ; ichv2 = colindU[irowUT+2] ; base2 = Chv_diagLocation(chvT, ichv2) - 2*ichv2 ; /* ------------------------------------ [ temp0 ] [ rowUT0 ]^H compute [ temp1 ] = [ rowUT1 ] * D [ temp2 ] [ rowUT2 ] ------------------------------------ */ DVzero(6*nrowU, temp0) ; SubMtx_scale3vec(mtxD, temp0, temp1, temp2, rowUT0, rowUT1, rowUT2) ; for ( ii = 0 ; ii < nrowU ; ii++ ) { temp0[2*ii+1] = -temp0[2*ii+1] ; temp1[2*ii+1] = -temp1[2*ii+1] ; temp2[2*ii+1] = -temp2[2*ii+1] ; } /* -------------------------------------------------- update the 3x3 upper triangle for these three rows -------------------------------------------------- */ colU0 = rowUT0 ; colU1 = rowUT1 ; colU2 = rowUT2 ; ZVdotU(nrowU, temp0, colU0, &rsum, &isum) ; /* if ( chvT->id != -1 ) { fprintf(stdout, "\n (%d,%d) : imag(diag) = %12.5e", chvT->id, mtxD->rowid, base0[2*ichv0+1]) ; } */ /* base0[2*ichv0] -= rsum ; base0[2*ichv0+1] -= isum ; */ base0[2*ichv0] -= rsum ; /* if ( chvT->id != -1 ) { fprintf(stdout, ", isum = %12.5e, imag(diag) = %12.5e", isum, base0[2*ichv0+1]) ; } */ ZVdotU(nrowU, temp0, colU1, &rsum, &isum) ; base0[2*ichv1] -= rsum ; base0[2*ichv1+1] -= isum ; ZVdotU(nrowU, temp0, colU2, &rsum, &isum) ; base0[2*ichv2] -= rsum ; base0[2*ichv2+1] -= isum ; ZVdotU(nrowU, temp1, colU1, &rsum, &isum) ; /* if ( chvT->id != -1 ) { fprintf(stdout, "\n (%d,%d) : imag(diag) = %12.5e", chvT->id, mtxD->rowid, base1[2*ichv1+1]) ; } */ /* base1[2*ichv1] -= rsum ; base1[2*ichv1+1] -= isum ; */ base1[2*ichv1] -= rsum ; /* if ( chvT->id != -1 ) { fprintf(stdout, ", isum = %12.5e, imag(diag) = %12.5e", isum, base1[2*ichv1+1]) ; } */ ZVdotU(nrowU, temp1, colU2, &rsum, &isum) ; base1[2*ichv2] -= rsum ; base1[2*ichv2+1] -= isum ; ZVdotU(nrowU, temp2, colU2, &rsum, &isum) ; /* if ( chvT->id != -1 ) { fprintf(stdout, "\n (%d,%d) : imag(diag) = %12.5e", chvT->id, mtxD->rowid, base2[2*ichv2+1]) ; } */ /* base2[2*ichv2] -= rsum ; base2[2*ichv2+1] -= isum ; */ base2[2*ichv2] -= rsum ; /* if ( chvT->id != -1 ) { fprintf(stdout, ", isum = %12.5e, imag(diag) = %12.5e", isum, base2[2*ichv2+1]) ; } */ colU0 = colU2 + 2*nrowU ; /* -------------------------------------- update the remainder of the three rows -------------------------------------- */ for ( jcolU = irowUT + 3 ; jcolU < ncolU - 2 ; jcolU += 3 ) { colU1 = colU0 + 2*nrowU ; colU2 = colU1 + 2*nrowU ; ZVdotU33(nrowU, temp0, temp1, temp2, colU0, colU1, colU2, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; kloc2 = 2*colindU[jcolU+2] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; base0[kloc2] -= sums[ 4] ; base0[kloc2+1] -= sums[ 5] ; base1[kloc0] -= sums[ 6] ; base1[kloc0+1] -= sums[ 7] ; base1[kloc1] -= sums[ 8] ; base1[kloc1+1] -= sums[ 9] ; base1[kloc2] -= sums[10] ; base1[kloc2+1] -= sums[11] ; base2[kloc0] -= sums[12] ; base2[kloc0+1] -= sums[13] ; base2[kloc1] -= sums[14] ; base2[kloc1+1] -= sums[15] ; base2[kloc2] -= sums[16] ; base2[kloc2+1] -= sums[17] ; colU0 = colU2 + 2*nrowU ; } if ( jcolU == ncolU - 2 ) { colU1 = colU0 + 2*nrowU ; ZVdotU32(nrowU, temp0, temp1, temp2, colU0, colU1, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; base1[kloc0] -= sums[ 4] ; base1[kloc0+1] -= sums[ 5] ; base1[kloc1] -= sums[ 6] ; base1[kloc1+1] -= sums[ 7] ; base2[kloc0] -= sums[ 8] ; base2[kloc0+1] -= sums[ 9] ; base2[kloc1] -= sums[10] ; base2[kloc1+1] -= sums[11] ; } else if ( jcolU == ncolU - 1 ) { ZVdotU31(nrowU, temp0, temp1, temp2, colU0, sums) ; kloc0 = 2*colindU[jcolU] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base1[kloc0] -= sums[ 2] ; base1[kloc0+1] -= sums[ 3] ; base2[kloc0] -= sums[ 4] ; base2[kloc0+1] -= sums[ 5] ; } rowUT0 = rowUT2 + 2*nrowU ; } if ( irowUT == lastInU - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on rows %d and %d", colindU[irowUT], colindU[irowUT+1]) ; fflush(stdout) ; #endif rowUT1 = rowUT0 + 2*nrowU ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - 2*ichv0 ; ichv1 = colindU[irowUT+1] ; base1 = Chv_diagLocation(chvT, ichv1) - 2*ichv1 ; /* ------------------------------------ [ temp0 ] [ rowUT0 ]^H compute [ temp1 ] = [ rowUT1 ] * D ------------------------------------ */ DVzero(4*nrowU, temp0) ; SubMtx_scale2vec(mtxD, temp0, temp1, rowUT0, rowUT1) ; for ( ii = 0 ; ii < nrowU ; ii++ ) { temp0[2*ii+1] = -temp0[2*ii+1] ; temp1[2*ii+1] = -temp1[2*ii+1] ; } /* ------------------------------------------------ update the 2x2 upper triangle for these two rows ------------------------------------------------ */ colU0 = rowUT0 ; colU1 = rowUT1 ; ZVdotU(nrowU, temp0, colU0, &rsum, &isum) ; /* if ( chvT->id != -1 ) { fprintf(stdout, "\n (%d,%d) : imag(diag) = %12.5e", chvT->id, mtxD->rowid, base0[2*ichv0+1]) ; } */ /* base0[2*ichv0] -= rsum ; base0[2*ichv0+1] -= isum ; */ base0[2*ichv0] -= rsum ; /* if ( chvT->id != -1 ) { fprintf(stdout, ", isum = %12.5e, imag(diag) = %12.5e", isum, base0[2*ichv0+1]) ; } */ ZVdotU(nrowU, temp0, colU1, &rsum, &isum) ; base0[2*ichv1] -= rsum ; base0[2*ichv1+1] -= isum ; ZVdotU(nrowU, temp1, colU1, &rsum, &isum) ; /* if ( chvT->id != -1 ) { fprintf(stdout, "\n (%d,%d) : imag(diag) = %12.5e", chvT->id, mtxD->rowid, base1[2*ichv1+1]) ; } */ /* base1[2*ichv1] -= rsum ; base1[2*ichv1+1] -= isum ; */ base1[2*ichv1] -= rsum ; /* if ( chvT->id != -1 ) { fprintf(stdout, ", isum = %12.5e, imag(diag) = %12.5e", isum, base1[2*ichv1+1]) ; } */ colU0 = colU1 + 2*nrowU ; /* ------------------------------------ update the remainder of the two rows ------------------------------------ */ for ( jcolU = irowUT + 2 ; jcolU < ncolU - 2 ; jcolU += 3 ) { colU1 = colU0 + 2*nrowU ; colU2 = colU1 + 2*nrowU ; ZVdotU23(nrowU, temp0, temp1, colU0, colU1, colU2, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; kloc2 = 2*colindU[jcolU+2] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; base0[kloc2] -= sums[ 4] ; base0[kloc2+1] -= sums[ 5] ; base1[kloc0] -= sums[ 6] ; base1[kloc0+1] -= sums[ 7] ; base1[kloc1] -= sums[ 8] ; base1[kloc1+1] -= sums[ 9] ; base1[kloc2] -= sums[10] ; base1[kloc2+1] -= sums[11] ; colU0 = colU2 + 2*nrowU ; } if ( jcolU == ncolU - 2 ) { colU1 = colU0 + 2*nrowU ; ZVdotU22(nrowU, temp0, temp1, colU0, colU1, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; base1[kloc0] -= sums[ 4] ; base1[kloc0+1] -= sums[ 5] ; base1[kloc1] -= sums[ 6] ; base1[kloc1+1] -= sums[ 7] ; } else if ( jcolU == ncolU - 1 ) { ZVdotU21(nrowU, temp0, temp1, colU0, sums) ; kloc0 = 2*colindU[jcolU] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base1[kloc0] -= sums[ 2] ; base1[kloc0+1] -= sums[ 3] ; } } else if ( irowUT == lastInU ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on row %d", colindU[irowUT]) ; fflush(stdout) ; #endif /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - 2*ichv0 ; /* ------------------------------------ compute [ temp0 ] = [ rowUT0 ]^H * D ------------------------------------ */ DVzero(2*nrowU, temp0) ; SubMtx_scale1vec(mtxD, temp0, rowUT0) ; for ( ii = 0 ; ii < nrowU ; ii++ ) { temp0[2*ii+1] = -temp0[2*ii+1] ; } /* ------------------------------------------ update the 1x1 upper triangle for this row ------------------------------------------ */ colU0 = rowUT0 ; ZVdotU(nrowU, temp0, colU0, &rsum, &isum) ; /* if ( chvT->id != -1 ) { fprintf(stdout, "\n (%d,%d) : imag(diag) = %12.5e", chvT->id, mtxD->rowid, base0[2*ichv0+1]) ; } */ /* base0[2*ichv0] -= rsum ; base0[2*ichv0+1] -= isum ; */ base0[2*ichv0] -= rsum ; /* if ( chvT->id != -1 ) { fprintf(stdout, ", isum = %12.5e, imag(diag) = %12.5e", isum, base0[2*ichv0+1]) ; } */ colU0 = colU0 + 2*nrowU ; /* ------------------------------- update the remainder of the row ------------------------------- */ for ( jcolU = irowUT + 1 ; jcolU < ncolU - 2 ; jcolU += 3 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on columns %d, %d and %d", jcolU, jcolU+1, jcolU+2) ; fflush(stdout) ; #endif colU1 = colU0 + 2*nrowU ; colU2 = colU1 + 2*nrowU ; ZVdotU13(nrowU, temp0, colU0, colU1, colU2, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; kloc2 = 2*colindU[jcolU+2] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; base0[kloc2] -= sums[ 4] ; base0[kloc2+1] -= sums[ 5] ; colU0 = colU2 + 2*nrowU ; } if ( jcolU == ncolU - 2 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on columns %d and %d", jcolU, jcolU+1) ; fflush(stdout) ; #endif colU1 = colU0 + 2*nrowU ; ZVdotU12(nrowU, temp0, colU0, colU1, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; } else if ( jcolU == ncolU - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on column %d", jcolU) ; fflush(stdout) ; #endif ZVdotU11(nrowU, temp0, colU0, sums) ; /* fprintf(stdout, "\n SUMS[0] = %12.4e, SUMS[1] = %12.4e", sums[0], sums[1]) ; */ kloc0 = 2*colindU[jcolU] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; /* fprintf(stdout, "\n base0[%d] = %12.4e, base0[%d] = %12.4e", kloc0, base0[kloc0], kloc0+1, base0[kloc0+1]) ; */ } } } else if ( SUBMTX_IS_SPARSE_COLUMNS(mtxU) ) { double isum, rsum ; double *base0, *colU0, *entU, *rowUT0, *temp0, *temp1 ; int ichv0, ii, iloc, irowUT, kloc0, nentU, nrowU, offset, rloc, sizeU, sizeUT ; int *indU, *indU0, *indUT0, *sizes ; SubMtx_sparseColumnsInfo(mtxU, &ncolU, &nentU, &sizes, &indU, &entU) ; nrowU = mtxU->nrow ; DV_setSize(tempDV, 4*nrowU) ; temp0 = DV_entries(tempDV) ; temp1 = temp0 + 2*nrowU ; /* ------------------------------------------- get the offset into the indices and entries ------------------------------------------- */ for ( jcolU = offset = 0 ; jcolU < firstInU ; jcolU++ ) { offset += sizes[jcolU] ; } /* ------------------------------------ loop over the supporting rows of U^H ------------------------------------ */ rowUT0 = entU + 2*offset ; indUT0 = indU + offset ; for ( irowUT = firstInU ; irowUT <= lastInU ; irowUT++ ) { if ( (sizeUT = sizes[irowUT]) > 0 ) { /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - 2*ichv0 ; /* ------------------------------------ compute [ temp0 ] = [ rowUT0 ]^H * D ------------------------------------ */ DVzero(4*nrowU, temp0) ; for ( ii = 0 ; ii < sizeUT ; ii++ ) { rloc = 2*indUT0[ii] ; iloc = rloc + 1 ; temp1[rloc] = rowUT0[2*ii] ; temp1[iloc] = rowUT0[2*ii+1] ; } SubMtx_scale1vec(mtxD, temp0, temp1) ; for ( ii = 0 ; ii < nrowU ; ii++ ) { temp0[2*ii+1] = -temp0[2*ii+1] ; } /* ------------------------------- loop over the following columns ------------------------------- */ colU0 = rowUT0 ; indU0 = indUT0 ; for ( jcolU = irowUT ; jcolU < ncolU ; jcolU++ ) { if ( (sizeU = sizes[jcolU]) > 0 ) { ZVdotiU(sizeU, temp0, indU0, colU0, &rsum, &isum) ; kloc0 = 2*colindU[jcolU] ; base0[kloc0] -= rsum ; base0[kloc0+1] -= isum ; colU0 += 2*sizeU ; indU0 += sizeU ; } } rowUT0 += 2*sizeUT ; indUT0 += sizeUT ; } } } else { fprintf(stderr, "\n fatal error in Chv_updateH(%p,%p,%p,%p)" "\n mtxU must have dense or sparse columns\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } /* --------------------------------------------------- overwrite the local indices with the global indices --------------------------------------------------- */ for ( jcolU = firstInU ; jcolU < ncolU ; jcolU++ ) { colindU[jcolU] = colindT[colindU[jcolU]] ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- perform the symmetric factor update T_{\bnd{I} \cap J, \bnd{I} \cap J} -= U_{I, \bnd{I} \cap J}^T D_{I, I} U_{I, \bnd{I} \cap J} and T_{\bnd{I} \cap J, \bnd{I} \cap \bnd{J}} -= U_{I, \bnd{I} \cap J}^T D_{I, I} U_{I, \bnd{I} \cap \bnd{J}} created -- 98apr17, cca --------------------------------------------------------------------- */ void Chv_updateS ( Chv *chvT, SubMtx *mtxD, SubMtx *mtxU, DV *tempDV ) { int firstInT, firstInU, jcolT, jcolU, lastInT, lastInU, ncolT, ncolU ; int *colindT, *colindU ; /* --------------- check the input --------------- */ if ( chvT == NULL || mtxD == NULL || mtxU == NULL || tempDV == NULL ) { fprintf(stderr, "\n fatal error in Chv_updateS(%p,%p,%p,%p)" "\n bad input\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } if ( CHV_IS_REAL(chvT) ) { if ( ! SUBMTX_IS_REAL(mtxD) || ! SUBMTX_IS_REAL(mtxU) ) { fprintf(stderr, "\n fatal error in Chv_updateT(%p,%p,%p,%p)" "\n chvT is real, but mtxD and/or mtxU are not\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } } else if ( CHV_IS_COMPLEX(chvT) ) { if ( ! SUBMTX_IS_COMPLEX(mtxD) || ! SUBMTX_IS_COMPLEX(mtxU) ) { fprintf(stderr, "\n fatal error in Chv_updateT(%p,%p,%p,%p)" "\n chvT is complex, but mtxD and/or mtxU are not\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } } else { fprintf(stderr, "\n fatal error in Chv_updateT(%p,%p,%p,%p)" "\n bad input, chvT is not real or complex\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } Chv_columnIndices(chvT, &ncolT, &colindT) ; SubMtx_columnIndices(mtxU, &ncolU, &colindU) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% Chv column indices") ; IVfprintf(stdout, ncolT, colindT) ; fprintf(stdout, "\n %% submtx column indices") ; IVfprintf(stdout, ncolU, colindU) ; fflush(stdout) ; #endif /* ----------------------------- locate first column of U in T ----------------------------- */ firstInT = colindT[0] ; lastInT = colindT[chvT->nD-1] ; for ( jcolU = 0 ; jcolU < ncolU ; jcolU++ ) { if ( firstInT <= colindU[jcolU] && colindU[jcolU] <= lastInT ) { break ; } } if ( (firstInU = jcolU) == ncolU ) { return ; } /* ---------------------------- locate last column of U in T ---------------------------- */ lastInU = firstInU ; for ( ; jcolU < ncolU ; jcolU++ ) { if ( colindU[jcolU] <= lastInT ) { lastInU = jcolU ; } else { break ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %% firstInU = %d, lastInU = %d", firstInU, lastInU) ; fflush(stdout) ; #endif /* ---------------------------------------------------------- overwrite supported column indices with indices local to T ---------------------------------------------------------- */ for ( jcolU = firstInU, jcolT = 0 ; jcolU < ncolU ; jcolU++ ) { while ( colindU[jcolU] != colindT[jcolT] ) { jcolT++ ; } colindU[jcolU] = jcolT ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% submtx column indices") ; IVfprintf(stdout, ncolU, colindU) ; fflush(stdout) ; #endif if ( CHV_IS_REAL(chvT) ) { if ( SUBMTX_IS_DENSE_COLUMNS(mtxU) ) { double sums[9] ; double *base0, *base1, *base2, *colU0, *colU1, *colU2, *entU, *rowUT0, *rowUT1, *rowUT2, *temp0, *temp1, *temp2 ; int ichv0, ichv1, ichv2, inc1, inc2, irowUT, kloc0, kloc1, kloc2, nrowU ; SubMtx_denseInfo(mtxU, &nrowU, &ncolU, &inc1, &inc2, &entU) ; DV_setSize(tempDV, 3*nrowU) ; temp0 = DV_entries(tempDV) ; temp1 = temp0 + nrowU ; temp2 = temp1 + nrowU ; /* -------------------------------------------- loop over the rows of U^T in groups of three -------------------------------------------- */ rowUT0 = entU + firstInU*nrowU ; for ( irowUT = firstInU ; irowUT <= lastInU - 2 ; irowUT += 3 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on rows %d, %d and %d", colindU[irowUT], colindU[irowUT+1], colindU[irowUT+2]) ; fflush(stdout) ; #endif rowUT1 = rowUT0 + nrowU ; rowUT2 = rowUT1 + nrowU ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - ichv0 ; ichv1 = colindU[irowUT+1] ; base1 = Chv_diagLocation(chvT, ichv1) - ichv1 ; ichv2 = colindU[irowUT+2] ; base2 = Chv_diagLocation(chvT, ichv2) - ichv2 ; /* ------------------------------------ [ temp0 ] [ rowUT0 ]^T compute [ temp1 ] = [ rowUT1 ] * D [ temp2 ] [ rowUT2 ] ------------------------------------ */ DVzero(3*nrowU, temp0) ; SubMtx_scale3vec(mtxD, temp0, temp1, temp2, rowUT0, rowUT1, rowUT2) ; /* -------------------------------------------------- update the 3x3 upper triangle for these three rows -------------------------------------------------- */ colU0 = rowUT0 ; colU1 = rowUT1 ; colU2 = rowUT2 ; base0[ichv0] -= DVdot(nrowU, temp0, colU0) ; base0[ichv1] -= DVdot(nrowU, temp0, colU1) ; base0[ichv2] -= DVdot(nrowU, temp0, colU2) ; base1[ichv1] -= DVdot(nrowU, temp1, colU1) ; base1[ichv2] -= DVdot(nrowU, temp1, colU2) ; base2[ichv2] -= DVdot(nrowU, temp2, colU2) ; colU0 = colU2 + nrowU ; /* -------------------------------------- update the remainder of the three rows -------------------------------------- */ for ( jcolU = irowUT + 3 ; jcolU < ncolU - 2 ; jcolU += 3 ) { colU1 = colU0 + nrowU ; colU2 = colU1 + nrowU ; DVdot33(nrowU, temp0, temp1, temp2, colU0, colU1, colU2, sums) ; kloc0 = colindU[jcolU] ; kloc1 = colindU[jcolU+1] ; kloc2 = colindU[jcolU+2] ; base0[kloc0] -= sums[0] ; base0[kloc1] -= sums[1] ; base0[kloc2] -= sums[2] ; base1[kloc0] -= sums[3] ; base1[kloc1] -= sums[4] ; base1[kloc2] -= sums[5] ; base2[kloc0] -= sums[6] ; base2[kloc1] -= sums[7] ; base2[kloc2] -= sums[8] ; colU0 = colU2 + nrowU ; } if ( jcolU == ncolU - 2 ) { colU1 = colU0 + nrowU ; DVdot32(nrowU, temp0, temp1, temp2, colU0, colU1, sums) ; kloc0 = colindU[jcolU] ; kloc1 = colindU[jcolU+1] ; base0[kloc0] -= sums[0] ; base0[kloc1] -= sums[1] ; base1[kloc0] -= sums[2] ; base1[kloc1] -= sums[3] ; base2[kloc0] -= sums[4] ; base2[kloc1] -= sums[5] ; } else if ( jcolU == ncolU - 1 ) { DVdot31(nrowU, temp0, temp1, temp2, colU0, sums) ; kloc0 = colindU[jcolU] ; base0[kloc0] -= sums[0] ; base1[kloc0] -= sums[1] ; base2[kloc0] -= sums[2] ; } rowUT0 = rowUT2 + nrowU ; } if ( irowUT == lastInU - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on rows %d and %d", colindU[irowUT], colindU[irowUT+1]) ; fflush(stdout) ; #endif rowUT1 = rowUT0 + nrowU ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - ichv0 ; ichv1 = colindU[irowUT+1] ; base1 = Chv_diagLocation(chvT, ichv1) - ichv1 ; /* ------------------------------------ [ temp0 ] [ rowUT0 ]^T compute [ temp1 ] = [ rowUT1 ] * D ------------------------------------ */ DVzero(2*nrowU, temp0) ; SubMtx_scale2vec(mtxD, temp0, temp1, rowUT0, rowUT1) ; /* ------------------------------------------------ update the 2x2 upper triangle for these two rows ------------------------------------------------ */ colU0 = rowUT0 ; colU1 = rowUT1 ; base0[ichv0] -= DVdot(nrowU, temp0, colU0) ; base0[ichv1] -= DVdot(nrowU, temp0, colU1) ; base1[ichv1] -= DVdot(nrowU, temp1, colU1) ; colU0 = colU1 + nrowU ; /* ------------------------------------ update the remainder of the two rows ------------------------------------ */ for ( jcolU = irowUT + 2 ; jcolU < ncolU - 2 ; jcolU += 3 ) { colU1 = colU0 + nrowU ; colU2 = colU1 + nrowU ; DVdot23(nrowU, temp0, temp1, colU0, colU1, colU2, sums) ; kloc0 = colindU[jcolU] ; kloc1 = colindU[jcolU+1] ; kloc2 = colindU[jcolU+2] ; base0[kloc0] -= sums[0] ; base0[kloc1] -= sums[1] ; base0[kloc2] -= sums[2] ; base1[kloc0] -= sums[3] ; base1[kloc1] -= sums[4] ; base1[kloc2] -= sums[5] ; colU0 = colU2 + nrowU ; } if ( jcolU == ncolU - 2 ) { colU1 = colU0 + nrowU ; DVdot22(nrowU, temp0, temp1, colU0, colU1, sums) ; kloc0 = colindU[jcolU] ; kloc1 = colindU[jcolU+1] ; base0[kloc0] -= sums[0] ; base0[kloc1] -= sums[1] ; base1[kloc0] -= sums[2] ; base1[kloc1] -= sums[3] ; } else if ( jcolU == ncolU - 1 ) { DVdot21(nrowU, temp0, temp1, colU0, sums) ; kloc0 = colindU[jcolU] ; base0[kloc0] -= sums[0] ; base1[kloc0] -= sums[1] ; } } else if ( irowUT == lastInU ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on row %d", colindU[irowUT]) ; fflush(stdout) ; #endif /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - ichv0 ; /* ------------------------------------ compute [ temp0 ] = [ rowUT0 ]^T * D ------------------------------------ */ DVzero(nrowU, temp0) ; SubMtx_scale1vec(mtxD, temp0, rowUT0) ; /* ------------------------------------------ update the 1x1 upper triangle for this row ------------------------------------------ */ colU0 = rowUT0 ; base0[ichv0] -= DVdot(nrowU, temp0, colU0) ; colU0 = colU0 + nrowU ; /* ------------------------------- update the remainder of the row ------------------------------- */ for ( jcolU = irowUT + 1 ; jcolU < ncolU - 2 ; jcolU += 3 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on columns %d, %d and %d", jcolU, jcolU+1, jcolU+2) ; fflush(stdout) ; #endif colU1 = colU0 + nrowU ; colU2 = colU1 + nrowU ; DVdot13(nrowU, temp0, colU0, colU1, colU2, sums) ; kloc0 = colindU[jcolU] ; kloc1 = colindU[jcolU+1] ; kloc2 = colindU[jcolU+2] ; base0[kloc0] -= sums[0] ; base0[kloc1] -= sums[1] ; base0[kloc2] -= sums[2] ; colU0 = colU2 + nrowU ; } if ( jcolU == ncolU - 2 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on columns %d and %d", jcolU, jcolU+1) ; fflush(stdout) ; #endif colU1 = colU0 + nrowU ; DVdot12(nrowU, temp0, colU0, colU1, sums) ; kloc0 = colindU[jcolU] ; kloc1 = colindU[jcolU+1] ; base0[kloc0] -= sums[0] ; base0[kloc1] -= sums[1] ; } else if ( jcolU == ncolU - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on column %d", jcolU) ; fflush(stdout) ; #endif DVdot11(nrowU, temp0, colU0, sums) ; kloc0 = colindU[jcolU] ; base0[kloc0] -= sums[0] ; } } } else if ( SUBMTX_IS_SPARSE_COLUMNS(mtxU) ) { double sum ; double *base0, *colU0, *entU, *rowUT0, *temp0, *temp1 ; int ichv0, ii, irowUT, kloc0, loc, nentU, nrowU, offset, sizeU, sizeUT ; int *indU, *indU0, *indUT0, *sizes ; SubMtx_sparseColumnsInfo(mtxU, &ncolU, &nentU, &sizes, &indU, &entU) ; nrowU = mtxU->nrow ; DV_setSize(tempDV, 2*nrowU) ; temp0 = DV_entries(tempDV) ; temp1 = temp0 + nrowU ; /* ------------------------------------------- get the offset into the indices and entries ------------------------------------------- */ for ( jcolU = offset = 0 ; jcolU < firstInU ; jcolU++ ) { offset += sizes[jcolU] ; } /* ------------------------------------ loop over the supporting rows of U^T ------------------------------------ */ rowUT0 = entU + offset ; indUT0 = indU + offset ; for ( irowUT = firstInU ; irowUT <= lastInU ; irowUT++ ) { if ( (sizeUT = sizes[irowUT]) > 0 ) { /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - ichv0 ; /* ------------------------------------ compute [ temp0 ] = [ rowUT0 ]^T * D ------------------------------------ */ DVzero(2*nrowU, temp0) ; for ( ii = 0 ; ii < sizeUT ; ii++ ) { loc = indUT0[ii] ; temp1[loc] = rowUT0[ii] ; } SubMtx_scale1vec(mtxD, temp0, temp1) ; /* ------------------------------- loop over the following columns ------------------------------- */ colU0 = rowUT0 ; indU0 = indUT0 ; for ( jcolU = irowUT ; jcolU < ncolU ; jcolU++ ) { if ( (sizeU = sizes[jcolU]) > 0 ) { sum = DVdoti(sizeU, temp0, indU0, colU0) ; kloc0 = colindU[jcolU] ; base0[kloc0] -= sum ; colU0 += sizeU ; indU0 += sizeU ; } } rowUT0 += sizeUT ; indUT0 += sizeUT ; } } } else { fprintf(stderr, "\n fatal error in Chv_updateT(%p,%p,%p,%p)" "\n bad input, mtxU must have dense or sparse columns\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } } else if ( CHV_IS_COMPLEX(chvT) ) { if ( SUBMTX_IS_DENSE_COLUMNS(mtxU) ) { double isum, rsum ; double sums[18] ; double *base0, *base1, *base2, *colU0, *colU1, *colU2, *entU, *rowUT0, *rowUT1, *rowUT2, *temp0, *temp1, *temp2 ; int ichv0, ichv1, ichv2, inc1, inc2, irowUT, kloc0, kloc1, kloc2, nrowU ; SubMtx_denseInfo(mtxU, &nrowU, &ncolU, &inc1, &inc2, &entU) ; DV_setSize(tempDV, 6*nrowU) ; temp0 = DV_entries(tempDV) ; temp1 = temp0 + 2*nrowU ; temp2 = temp1 + 2*nrowU ; /* -------------------------------------------- loop over the rows of U^T in groups of three -------------------------------------------- */ rowUT0 = entU + 2*firstInU*nrowU ; for ( irowUT = firstInU ; irowUT <= lastInU - 2 ; irowUT += 3 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on rows %d, %d and %d", colindU[irowUT], colindU[irowUT+1], colindU[irowUT+2]) ; fflush(stdout) ; #endif rowUT1 = rowUT0 + 2*nrowU ; rowUT2 = rowUT1 + 2*nrowU ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - 2*ichv0 ; ichv1 = colindU[irowUT+1] ; base1 = Chv_diagLocation(chvT, ichv1) - 2*ichv1 ; ichv2 = colindU[irowUT+2] ; base2 = Chv_diagLocation(chvT, ichv2) - 2*ichv2 ; /* ------------------------------------ [ temp0 ] [ rowUT0 ]^T compute [ temp1 ] = [ rowUT1 ] * D [ temp2 ] [ rowUT2 ] ------------------------------------ */ DVzero(6*nrowU, temp0) ; SubMtx_scale3vec(mtxD, temp0, temp1, temp2, rowUT0, rowUT1, rowUT2) ; /* -------------------------------------------------- update the 3x3 upper triangle for these three rows -------------------------------------------------- */ colU0 = rowUT0 ; colU1 = rowUT1 ; colU2 = rowUT2 ; ZVdotU(nrowU, temp0, colU0, &rsum, &isum) ; base0[2*ichv0] -= rsum ; base0[2*ichv0+1] -= isum ; ZVdotU(nrowU, temp0, colU1, &rsum, &isum) ; base0[2*ichv1] -= rsum ; base0[2*ichv1+1] -= isum ; ZVdotU(nrowU, temp0, colU2, &rsum, &isum) ; base0[2*ichv2] -= rsum ; base0[2*ichv2+1] -= isum ; ZVdotU(nrowU, temp1, colU1, &rsum, &isum) ; base1[2*ichv1] -= rsum ; base1[2*ichv1+1] -= isum ; ZVdotU(nrowU, temp1, colU2, &rsum, &isum) ; base1[2*ichv2] -= rsum ; base1[2*ichv2+1] -= isum ; ZVdotU(nrowU, temp2, colU2, &rsum, &isum) ; base2[2*ichv2] -= rsum ; base2[2*ichv2+1] -= isum ; colU0 = colU2 + 2*nrowU ; /* -------------------------------------- update the remainder of the three rows -------------------------------------- */ for ( jcolU = irowUT + 3 ; jcolU < ncolU - 2 ; jcolU += 3 ) { colU1 = colU0 + 2*nrowU ; colU2 = colU1 + 2*nrowU ; ZVdotU33(nrowU, temp0, temp1, temp2, colU0, colU1, colU2, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; kloc2 = 2*colindU[jcolU+2] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; base0[kloc2] -= sums[ 4] ; base0[kloc2+1] -= sums[ 5] ; base1[kloc0] -= sums[ 6] ; base1[kloc0+1] -= sums[ 7] ; base1[kloc1] -= sums[ 8] ; base1[kloc1+1] -= sums[ 9] ; base1[kloc2] -= sums[10] ; base1[kloc2+1] -= sums[11] ; base2[kloc0] -= sums[12] ; base2[kloc0+1] -= sums[13] ; base2[kloc1] -= sums[14] ; base2[kloc1+1] -= sums[15] ; base2[kloc2] -= sums[16] ; base2[kloc2+1] -= sums[17] ; colU0 = colU2 + 2*nrowU ; } if ( jcolU == ncolU - 2 ) { colU1 = colU0 + 2*nrowU ; ZVdotU32(nrowU, temp0, temp1, temp2, colU0, colU1, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; base1[kloc0] -= sums[ 4] ; base1[kloc0+1] -= sums[ 5] ; base1[kloc1] -= sums[ 6] ; base1[kloc1+1] -= sums[ 7] ; base2[kloc0] -= sums[ 8] ; base2[kloc0+1] -= sums[ 9] ; base2[kloc1] -= sums[10] ; base2[kloc1+1] -= sums[11] ; } else if ( jcolU == ncolU - 1 ) { ZVdotU31(nrowU, temp0, temp1, temp2, colU0, sums) ; kloc0 = 2*colindU[jcolU] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base1[kloc0] -= sums[ 2] ; base1[kloc0+1] -= sums[ 3] ; base2[kloc0] -= sums[ 4] ; base2[kloc0+1] -= sums[ 5] ; } rowUT0 = rowUT2 + 2*nrowU ; } if ( irowUT == lastInU - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on rows %d and %d", colindU[irowUT], colindU[irowUT+1]) ; fflush(stdout) ; #endif rowUT1 = rowUT0 + 2*nrowU ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - 2*ichv0 ; ichv1 = colindU[irowUT+1] ; base1 = Chv_diagLocation(chvT, ichv1) - 2*ichv1 ; /* ------------------------------------ [ temp0 ] [ rowUT0 ]^T compute [ temp1 ] = [ rowUT1 ] * D ------------------------------------ */ DVzero(4*nrowU, temp0) ; SubMtx_scale2vec(mtxD, temp0, temp1, rowUT0, rowUT1) ; /* ------------------------------------------------ update the 2x2 upper triangle for these two rows ------------------------------------------------ */ colU0 = rowUT0 ; colU1 = rowUT1 ; ZVdotU(nrowU, temp0, colU0, &rsum, &isum) ; base0[2*ichv0] -= rsum ; base0[2*ichv0+1] -= isum ; ZVdotU(nrowU, temp0, colU1, &rsum, &isum) ; base0[2*ichv1] -= rsum ; base0[2*ichv1+1] -= isum ; ZVdotU(nrowU, temp1, colU1, &rsum, &isum) ; base1[2*ichv1] -= rsum ; base1[2*ichv1+1] -= isum ; colU0 = colU1 + 2*nrowU ; /* ------------------------------------ update the remainder of the two rows ------------------------------------ */ for ( jcolU = irowUT + 2 ; jcolU < ncolU - 2 ; jcolU += 3 ) { colU1 = colU0 + 2*nrowU ; colU2 = colU1 + 2*nrowU ; ZVdotU23(nrowU, temp0, temp1, colU0, colU1, colU2, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; kloc2 = 2*colindU[jcolU+2] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; base0[kloc2] -= sums[ 4] ; base0[kloc2+1] -= sums[ 5] ; base1[kloc0] -= sums[ 6] ; base1[kloc0+1] -= sums[ 7] ; base1[kloc1] -= sums[ 8] ; base1[kloc1+1] -= sums[ 9] ; base1[kloc2] -= sums[10] ; base1[kloc2+1] -= sums[11] ; colU0 = colU2 + 2*nrowU ; } if ( jcolU == ncolU - 2 ) { colU1 = colU0 + 2*nrowU ; ZVdotU22(nrowU, temp0, temp1, colU0, colU1, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; base1[kloc0] -= sums[ 4] ; base1[kloc0+1] -= sums[ 5] ; base1[kloc1] -= sums[ 6] ; base1[kloc1+1] -= sums[ 7] ; } else if ( jcolU == ncolU - 1 ) { ZVdotU21(nrowU, temp0, temp1, colU0, sums) ; kloc0 = 2*colindU[jcolU] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base1[kloc0] -= sums[ 2] ; base1[kloc0+1] -= sums[ 3] ; } } else if ( irowUT == lastInU ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on row %d", colindU[irowUT]) ; fflush(stdout) ; #endif /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - 2*ichv0 ; /* ------------------------------------ compute [ temp0 ] = [ rowUT0 ]^T * D ------------------------------------ */ DVzero(2*nrowU, temp0) ; SubMtx_scale1vec(mtxD, temp0, rowUT0) ; /* ------------------------------------------ update the 1x1 upper triangle for this row ------------------------------------------ */ colU0 = rowUT0 ; ZVdotU(nrowU, temp0, colU0, &rsum, &isum) ; base0[2*ichv0] -= rsum ; base0[2*ichv0+1] -= isum ; colU0 = colU0 + 2*nrowU ; /* ------------------------------- update the remainder of the row ------------------------------- */ for ( jcolU = irowUT + 1 ; jcolU < ncolU - 2 ; jcolU += 3 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on columns %d, %d and %d", jcolU, jcolU+1, jcolU+2) ; fflush(stdout) ; #endif colU1 = colU0 + 2*nrowU ; colU2 = colU1 + 2*nrowU ; ZVdotU13(nrowU, temp0, colU0, colU1, colU2, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; kloc2 = 2*colindU[jcolU+2] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; base0[kloc2] -= sums[ 4] ; base0[kloc2+1] -= sums[ 5] ; colU0 = colU2 + 2*nrowU ; } if ( jcolU == ncolU - 2 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on columns %d and %d", jcolU, jcolU+1) ; fflush(stdout) ; #endif colU1 = colU0 + 2*nrowU ; ZVdotU12(nrowU, temp0, colU0, colU1, sums) ; kloc0 = 2*colindU[jcolU] ; kloc1 = 2*colindU[jcolU+1] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; base0[kloc1] -= sums[ 2] ; base0[kloc1+1] -= sums[ 3] ; } else if ( jcolU == ncolU - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on column %d", jcolU) ; fflush(stdout) ; #endif ZVdotU11(nrowU, temp0, colU0, sums) ; kloc0 = 2*colindU[jcolU] ; base0[kloc0] -= sums[ 0] ; base0[kloc0+1] -= sums[ 1] ; } } } else if ( SUBMTX_IS_SPARSE_COLUMNS(mtxU) ) { double isum, rsum ; double *base0, *colU0, *entU, *rowUT0, *temp0, *temp1 ; int ichv0, ii, iloc, irowUT, kloc0, nentU, nrowU, offset, rloc, sizeU, sizeUT ; int *indU, *indU0, *indUT0, *sizes ; SubMtx_sparseColumnsInfo(mtxU, &ncolU, &nentU, &sizes, &indU, &entU) ; nrowU = mtxU->nrow ; DV_setSize(tempDV, 4*nrowU) ; temp0 = DV_entries(tempDV) ; temp1 = temp0 + 2*nrowU ; /* ------------------------------------------- get the offset into the indices and entries ------------------------------------------- */ for ( jcolU = offset = 0 ; jcolU < firstInU ; jcolU++ ) { offset += sizes[jcolU] ; } /* ------------------------------------ loop over the supporting rows of U^T ------------------------------------ */ rowUT0 = entU + 2*offset ; indUT0 = indU + offset ; for ( irowUT = firstInU ; irowUT <= lastInU ; irowUT++ ) { if ( (sizeUT = sizes[irowUT]) > 0 ) { /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowUT] ; base0 = Chv_diagLocation(chvT, ichv0) - 2*ichv0 ; /* ------------------------------------ compute [ temp0 ] = [ rowUT0 ]^T * D ------------------------------------ */ DVzero(4*nrowU, temp0) ; for ( ii = 0 ; ii < sizeUT ; ii++ ) { rloc = 2*indUT0[ii] ; iloc = rloc + 1 ; temp1[rloc] = rowUT0[2*ii] ; temp1[iloc] = rowUT0[2*ii+1] ; } SubMtx_scale1vec(mtxD, temp0, temp1) ; /* ------------------------------- loop over the following columns ------------------------------- */ colU0 = rowUT0 ; indU0 = indUT0 ; for ( jcolU = irowUT ; jcolU < ncolU ; jcolU++ ) { if ( (sizeU = sizes[jcolU]) > 0 ) { ZVdotiU(sizeU, temp0, indU0, colU0, &rsum, &isum) ; kloc0 = 2*colindU[jcolU] ; base0[kloc0] -= rsum ; base0[kloc0+1] -= isum ; colU0 += 2*sizeU ; indU0 += sizeU ; } } rowUT0 += 2*sizeUT ; indUT0 += sizeUT ; } } } else { fprintf(stderr, "\n fatal error in Chv_updateT(%p,%p,%p,%p)" "\n bad input, mtxU must have dense or sparse columns\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } } /* --------------------------------------------------- overwrite the local indices with the global indices --------------------------------------------------- */ for ( jcolU = firstInU ; jcolU < ncolU ; jcolU++ ) { colindU[jcolU] = colindT[colindU[jcolU]] ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- perform the nonsymmetric factor update T_{\bnd{I} \cap J, \bnd{I} \cap J} -= L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap J} and T_{\bnd{I} \cap J, \bnd{I} \cap \bnd{J}} -= L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap \bnd{J}} and T_{\bnd{I} \cap \bnd{J}, \bnd{I} \cap J} -= L_{\bnd{I} \cap \bnd{J}, I} D_{I, I} U_{I, \bnd{I} \cap J} created -- 98feb27, cca --------------------------------------------------------------------- */ void Chv_updateN ( Chv *chvT, SubMtx *mtxL, SubMtx *mtxD, SubMtx *mtxU, DV *tempDV ) { int firstInT, firstInU, jcolT, jcolU, lastInT, lastInU, ncolT, ncolU ; int *colindT, *colindU ; /* --------------- check the input --------------- */ if ( chvT == NULL || mtxD == NULL || mtxU == NULL || tempDV == NULL ) { fprintf(stderr, "\n fatal error in Chv_updateN(%p,%p,%p,%p,%p)" "\n bad input\n", chvT, mtxL, mtxD, mtxU, tempDV) ; exit(-1) ; } if ( CHV_IS_REAL(chvT) ) { if ( ! SUBMTX_IS_REAL(mtxD) || ! SUBMTX_IS_REAL(mtxL) || ! SUBMTX_IS_REAL(mtxU) ) { fprintf(stderr, "\n fatal error in Chv_updateN(%p,%p,%p,%p)" "\n chvT is real, but mtxD, mtxL and/or mtxU are not\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } } else if ( CHV_IS_COMPLEX(chvT) ) { if ( ! SUBMTX_IS_COMPLEX(mtxD) || ! SUBMTX_IS_COMPLEX(mtxL) || ! SUBMTX_IS_COMPLEX(mtxU) ) { fprintf(stderr, "\n fatal error in Chv_updateN(%p,%p,%p,%p)" "\n chvT is complex, but mtxD, mtxL and/or mtxU are not\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } } else { fprintf(stderr, "\n fatal error in Chv_updateN(%p,%p,%p,%p)" "\n bad input, chvT is not real or complex\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } Chv_columnIndices(chvT, &ncolT, &colindT) ; SubMtx_columnIndices(mtxU, &ncolU, &colindU) ; /* ----------------------------- locate first column of U in T ----------------------------- */ firstInT = colindT[0] ; lastInT = colindT[chvT->nD-1] ; for ( jcolU = 0 ; jcolU < ncolU ; jcolU++ ) { if ( firstInT <= colindU[jcolU] && colindU[jcolU] <= lastInT ) { break ; } } if ( (firstInU = jcolU) == ncolU ) { return ; } /* ---------------------------- locate last column of U in T ---------------------------- */ lastInU = firstInU ; for ( ; jcolU < ncolU ; jcolU++ ) { if ( colindU[jcolU] <= lastInT ) { lastInU = jcolU ; } else { break ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %% firstInU = %d, lastInU = %d", firstInU, lastInU) ; fflush(stdout) ; #endif /* ---------------------------------------------------------- overwrite supported column indices with indices local to T ---------------------------------------------------------- */ for ( jcolU = firstInU, jcolT = 0 ; jcolU < ncolU ; jcolU++ ) { while ( colindU[jcolU] != colindT[jcolT] ) { jcolT++ ; } colindU[jcolU] = jcolT ; } if ( CHV_IS_REAL(chvT) ) { if ( SUBMTX_IS_DENSE_COLUMNS(mtxU) && SUBMTX_IS_DENSE_ROWS(mtxL) ) { double sums[9] ; double *base0, *base1, *base2, *colU0, *colU1, *colU2, *entL, *entU, *Ltemp0, *Ltemp1, *Ltemp2, *rowL0, *rowL1, *rowL2, *Utemp0, *Utemp1, *Utemp2 ; int ichv0, ichv1, ichv2, inc1, inc2, irowL, jcolU, loc, loc0, loc1, loc2, ncolL, nrowL, nrowU, offset ; SubMtx_denseInfo(mtxL, &nrowL, &ncolL, &inc1, &inc2, &entL) ; SubMtx_denseInfo(mtxU, &nrowU, &ncolU, &inc1, &inc2, &entU) ; DV_setSize(tempDV, 6*nrowU) ; Ltemp0 = DV_entries(tempDV) ; Ltemp1 = Ltemp0 + nrowU ; Ltemp2 = Ltemp1 + nrowU ; Utemp0 = Ltemp2 + nrowU ; Utemp1 = Utemp0 + nrowU ; Utemp2 = Utemp1 + nrowU ; /* ----------------------------------------------------- loop over the rows of L in groups of three updating the diagonal and upper blocks of the chevron ----------------------------------------------------- */ offset = firstInU*nrowU ; for ( irowL = firstInU ; irowL <= lastInU - 2 ; irowL += 3 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on rows %d, %d and %d", colindU[irowL], colindU[irowL+1], colindU[irowL+2]) ; fflush(stdout) ; #endif rowL0 = entL + offset ; rowL1 = rowL0 + nrowU ; rowL2 = rowL1 + nrowU ; colU0 = entU + offset ; colU1 = colU0 + nrowU ; colU2 = colU1 + nrowU ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowL] ; base0 = Chv_diagLocation(chvT, ichv0) ; ichv1 = colindU[irowL+1] ; base1 = Chv_diagLocation(chvT, ichv1) ; ichv2 = colindU[irowL+2] ; base2 = Chv_diagLocation(chvT, ichv2) ; /* ----------------------------------- [ Ltemp0 ] [ rowL0 ] compute [ Ltemp1 ] = [ rowL1 ] * D [ Ltemp2 ] [ rowL2 ] ----------------------------------- */ DVzero(3*nrowU, Ltemp0) ; SubMtx_scale3vec(mtxD, Ltemp0, Ltemp1, Ltemp2, rowL0, rowL1, rowL2) ; /* ----------------------------------- [ Utemp0 ] [ colU0 ] compute [ Utemp1 ] = D * [ colU0 ] [ Utemp2 ] [ colU0 ] ----------------------------------- */ DVzero(3*nrowU, Utemp0) ; SubMtx_scale3vec(mtxD, Utemp0, Utemp1, Utemp2, colU0, colU1, colU2) ; /* -------------------------------------------------------------- update the 3x3 diagonal block for these three rows and columns -------------------------------------------------------------- */ DVdot33(nrowU, Ltemp0, Ltemp1, Ltemp2, colU0, colU1, colU2, sums) ; /* ------------------------------------- inject the nine sums into the chevron ------------------------------------- */ base0[0] -= sums[0] ; loc = ichv1 - ichv0 ; base0[loc] -= sums[1] ; base0[-loc] -= sums[3] ; loc = ichv2 - ichv0 ; base0[loc] -= sums[2] ; base0[-loc] -= sums[6] ; base1[0] -= sums[4] ; loc = ichv2 - ichv1 ; base1[loc] -= sums[5] ; base1[-loc] -= sums[7] ; base2[0] -= sums[8] ; /* ------------------------------------------ update the lower and upper blocks together ------------------------------------------ */ rowL0 = rowL2 + nrowU ; colU0 = colU2 + nrowU ; for ( jcolU = irowL + 3 ; jcolU < ncolU - 2 ; jcolU += 3 ) { rowL1 = rowL0 + nrowU ; rowL2 = rowL1 + nrowU ; colU1 = colU0 + nrowU ; colU2 = colU1 + nrowU ; /* ------------------------------------------------------ get the local indices for these three rows and columns ------------------------------------------------------ */ loc0 = colindU[jcolU] ; loc1 = colindU[jcolU+1] ; loc2 = colindU[jcolU+2] ; /* --------------------- upper 3x3 block first --------------------- */ DVdot33(nrowU, Ltemp0, Ltemp1, Ltemp2, colU0, colU1, colU2, sums) ; /* ------------------------------------- inject the nine sums into the chevron ------------------------------------- */ base0 -= ichv0 ; base1 -= ichv1 ; base2 -= ichv2 ; base0[loc0] -= sums[0] ; base0[loc1] -= sums[1] ; base0[loc2] -= sums[2] ; base1[loc0] -= sums[3] ; base1[loc1] -= sums[4] ; base1[loc2] -= sums[5] ; base2[loc0] -= sums[6] ; base2[loc1] -= sums[7] ; base2[loc2] -= sums[8] ; base0 += ichv0 ; base1 += ichv1 ; base2 += ichv2 ; /* ---------------------- lower 3x3 block second ---------------------- */ DVdot33(nrowU, rowL0, rowL1, rowL2, Utemp0, Utemp1, Utemp2, sums) ; /* ------------------------------------- inject the nine sums into the chevron ------------------------------------- */ base0 += ichv0 ; base1 += ichv1 ; base2 += ichv2 ; base0[-loc0] -= sums[0] ; base1[-loc0] -= sums[1] ; base2[-loc0] -= sums[2] ; base0[-loc1] -= sums[3] ; base1[-loc1] -= sums[4] ; base2[-loc1] -= sums[5] ; base0[-loc2] -= sums[6] ; base1[-loc2] -= sums[7] ; base2[-loc2] -= sums[8] ; base0 -= ichv0 ; base1 -= ichv1 ; base2 -= ichv2 ; /* ------------------------------------- increment the row and column pointers ------------------------------------- */ rowL0 = rowL2 + nrowU ; colU0 = colU2 + nrowU ; } if ( jcolU == ncolU - 2 ) { rowL1 = rowL0 + nrowU ; colU1 = colU0 + nrowU ; /* ---------------------------------------------------- get the local indices for these two rows and columns ---------------------------------------------------- */ loc0 = colindU[jcolU] ; loc1 = colindU[jcolU+1] ; /* --------------------- upper 3x2 block first --------------------- */ DVdot32(nrowU, Ltemp0, Ltemp1, Ltemp2, colU0, colU1, sums) ; /* ------------------------------------ inject the six sums into the chevron ------------------------------------ */ base0 -= ichv0 ; base1 -= ichv1 ; base2 -= ichv2 ; base0[loc0] -= sums[0] ; base0[loc1] -= sums[1] ; base1[loc0] -= sums[2] ; base1[loc1] -= sums[3] ; base2[loc0] -= sums[4] ; base2[loc1] -= sums[5] ; base0 += ichv0 ; base1 += ichv1 ; base2 += ichv2 ; /* ---------------------- lower 2x3 block second ---------------------- */ DVdot23(nrowU, rowL0, rowL1, Utemp0, Utemp1, Utemp2, sums) ; /* ------------------------------------ inject the six sums into the chevron ------------------------------------ */ base0 += ichv0 ; base1 += ichv1 ; base2 += ichv2 ; base0[-loc0] -= sums[0] ; base1[-loc0] -= sums[1] ; base2[-loc0] -= sums[2] ; base0[-loc1] -= sums[3] ; base1[-loc1] -= sums[4] ; base2[-loc1] -= sums[5] ; base0 -= ichv0 ; base1 -= ichv1 ; base2 -= ichv2 ; } else if ( jcolU == ncolU - 1 ) { /* --------------------------------------------- get the local indices for this row and column --------------------------------------------- */ loc0 = colindU[jcolU] ; /* --------------------- upper 3x1 block first --------------------- */ DVdot31(nrowU, Ltemp0, Ltemp1, Ltemp2, colU0, sums) ; /* -------------------------------------- inject the three sums into the chevron -------------------------------------- */ base0 -= ichv0 ; base1 -= ichv1 ; base2 -= ichv2 ; base0[loc0] -= sums[0] ; base1[loc0] -= sums[1] ; base2[loc0] -= sums[2] ; base0 += ichv0 ; base1 += ichv1 ; base2 += ichv2 ; /* ---------------------- lower 1x3 block second ---------------------- */ DVdot13(nrowU, rowL0, Utemp0, Utemp1, Utemp2, sums) ; /* -------------------------------------- inject the three sums into the chevron -------------------------------------- */ base0 += ichv0 ; base1 += ichv1 ; base2 += ichv2 ; base0[-loc0] -= sums[0] ; base1[-loc0] -= sums[1] ; base2[-loc0] -= sums[2] ; base0 -= ichv0 ; base1 -= ichv1 ; base2 -= ichv2 ; } offset += 3*nrowU ; } if ( irowL == lastInU - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on rows %d and %d", colindU[irowL], colindU[irowL+1]) ; fflush(stdout) ; #endif rowL0 = entL + offset ; rowL1 = rowL0 + nrowU ; colU0 = entU + offset ; colU1 = colU0 + nrowU ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowL] ; base0 = Chv_diagLocation(chvT, ichv0) ; ichv1 = colindU[irowL+1] ; base1 = Chv_diagLocation(chvT, ichv1) ; /* ----------------------------------- [ Ltemp0 ] [ rowL0 ] compute [ Ltemp1 ] = [ rowL1 ] * D ----------------------------------- */ DVzero(2*nrowU, Ltemp0) ; SubMtx_scale2vec(mtxD, Ltemp0, Ltemp1, rowL0, rowL1) ; /* ----------------------------------- [ Utemp0 ] [ colU0 ] compute [ Utemp1 ] = D * [ colU0 ] ----------------------------------- */ DVzero(2*nrowU, Utemp0) ; SubMtx_scale2vec(mtxD, Utemp0, Utemp1, colU0, colU1) ; /* ------------------------------------------------------------ update the 2x2 diagonal block for these two rows and columns ------------------------------------------------------------ */ DVdot22(nrowU, Ltemp0, Ltemp1, colU0, colU1, sums) ; /* ------------------------------------- inject the four sums into the chevron ------------------------------------- */ base0[0] -= sums[ 0] ; loc = ichv1 - ichv0 ; base0[loc] -= sums[ 1] ; base0[-loc] -= sums[ 2] ; base1[0] -= sums[ 3] ; /* ------------------------------------------ update the lower and upper blocks together ------------------------------------------ */ rowL0 = rowL1 + nrowU ; colU0 = colU1 + nrowU ; for ( jcolU = irowL + 2 ; jcolU < ncolU - 2 ; jcolU += 3 ) { rowL1 = rowL0 + nrowU ; rowL2 = rowL1 + nrowU ; colU1 = colU0 + nrowU ; colU2 = colU1 + nrowU ; /* ------------------------------------------------------ get the local indices for these three rows and columns ------------------------------------------------------ */ loc0 = colindU[jcolU] ; loc1 = colindU[jcolU+1] ; loc2 = colindU[jcolU+2] ; /* --------------------- upper 2x3 block first --------------------- */ DVdot23(nrowU, Ltemp0, Ltemp1, colU0, colU1, colU2, sums) ; /* ------------------------------------ inject the six sums into the chevron ------------------------------------ */ base0 -= ichv0 ; base1 -= ichv1 ; base0[loc0] -= sums[0] ; base0[loc1] -= sums[1] ; base0[loc2] -= sums[2] ; base1[loc0] -= sums[3] ; base1[loc1] -= sums[4] ; base1[loc2] -= sums[5] ; base0 += ichv0 ; base1 += ichv1 ; /* ---------------------- lower 3x2 block second ---------------------- */ DVdot32(nrowU, rowL0, rowL1, rowL2, Utemp0, Utemp1, sums) ; /* ------------------------------------ inject the six sums into the chevron ------------------------------------ */ base0 += ichv0 ; base1 += ichv1 ; base0[-loc0] -= sums[0] ; base1[-loc0] -= sums[1] ; base0[-loc1] -= sums[2] ; base1[-loc1] -= sums[3] ; base0[-loc2] -= sums[4] ; base1[-loc2] -= sums[5] ; base0 -= ichv0 ; base1 -= ichv1 ; /* ------------------------------------- increment the row and column pointers ------------------------------------- */ rowL0 = rowL2 + nrowU ; colU0 = colU2 + nrowU ; } if ( jcolU == ncolU - 2 ) { rowL1 = rowL0 + nrowU ; colU1 = colU0 + nrowU ; /* ---------------------------------------------------- get the local indices for these two rows and columns ---------------------------------------------------- */ loc0 = colindU[jcolU] ; loc1 = colindU[jcolU+1] ; /* --------------------- upper 2x2 block first --------------------- */ DVdot22(nrowU, Ltemp0, Ltemp1, colU0, colU1, sums) ; /* ------------------------------------- inject the four sums into the chevron ------------------------------------- */ base0 -= ichv0 ; base1 -= ichv1 ; base0[loc0] -= sums[0] ; base0[loc1] -= sums[1] ; base1[loc0] -= sums[2] ; base1[loc1] -= sums[3] ; base0 += ichv0 ; base1 += ichv1 ; /* ---------------------- lower 2x2 block second ---------------------- */ DVdot22(nrowU, rowL0, rowL1, Utemp0, Utemp1, sums) ; /* ------------------------------------- inject the four sums into the chevron ------------------------------------- */ base0 += ichv0 ; base1 += ichv1 ; base0[-loc0] -= sums[0] ; base1[-loc0] -= sums[1] ; base0[-loc1] -= sums[2] ; base1[-loc1] -= sums[3] ; base0 -= ichv0 ; base1 -= ichv1 ; } else if ( jcolU == ncolU - 1 ) { /* --------------------------------------------- get the local indices for this row and column --------------------------------------------- */ loc0 = colindU[jcolU] ; /* --------------------- upper 2x1 block first --------------------- */ DVdot21(nrowU, Ltemp0, Ltemp1, colU0, sums) ; /* ------------------------------------ inject the two sums into the chevron ------------------------------------ */ base0 -= ichv0 ; base1 -= ichv1 ; base0[loc0] -= sums[0] ; base1[loc0] -= sums[1] ; base0 += ichv0 ; base1 += ichv1 ; /* ---------------------- lower 1x2 block second ---------------------- */ DVdot12(nrowU, rowL0, Utemp0, Utemp1, sums) ; /* ------------------------------------ inject the two sums into the chevron ------------------------------------ */ base0 += ichv0 ; base1 += ichv1 ; base0[-loc0] -= sums[0] ; base1[-loc0] -= sums[1] ; base0 -= ichv0 ; base1 -= ichv1 ; } } else if ( irowL == lastInU ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on row %d", colindU[irowL]) ; fflush(stdout) ; #endif rowL0 = entL + offset ; colU0 = entU + offset ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowL] ; base0 = Chv_diagLocation(chvT, ichv0) ; /* ----------------------------------- compute [ Ltemp0 ] = [ rowL0 ] * D ----------------------------------- */ DVzero(nrowU, Ltemp0) ; SubMtx_scale1vec(mtxD, Ltemp0, rowL0) ; /* ----------------------------------- compute [ Utemp0 ] = D * [ colU0 ] ----------------------------------- */ DVzero(nrowU, Utemp0) ; SubMtx_scale1vec(mtxD, Utemp0, colU0) ; /* ------------------------------------------------------------ update the 1x1 diagonal block for these two rows and columns ------------------------------------------------------------ */ DVdot11(nrowU, Ltemp0, colU0, sums) ; /* ------------------------------- inject the sum into the chevron ------------------------------- */ base0[0] -= sums[0] ; /* ------------------------------------------ update the lower and upper blocks together ------------------------------------------ */ rowL0 = rowL0 + nrowU ; colU0 = colU0 + nrowU ; for ( jcolU = irowL + 1 ; jcolU < ncolU - 2 ; jcolU += 3 ) { rowL1 = rowL0 + nrowU ; rowL2 = rowL1 + nrowU ; colU1 = colU0 + nrowU ; colU2 = colU1 + nrowU ; /* ------------------------------------------------------ get the local indices for these three rows and columns ------------------------------------------------------ */ loc0 = colindU[jcolU] ; loc1 = colindU[jcolU+1] ; loc2 = colindU[jcolU+2] ; /* --------------------- upper 1x3 block first --------------------- */ DVdot13(nrowU, Ltemp0, colU0, colU1, colU2, sums) ; /* -------------------------------------- inject the three sums into the chevron -------------------------------------- */ base0 -= ichv0 ; base0[loc0] -= sums[0] ; base0[loc1] -= sums[1] ; base0[loc2] -= sums[2] ; base0 += ichv0 ; /* ---------------------- lower 3x1 block second ---------------------- */ DVdot31(nrowU, rowL0, rowL1, rowL2, Utemp0, sums) ; /* -------------------------------------- inject the three sums into the chevron -------------------------------------- */ base0 += ichv0 ; base0[-loc0] -= sums[0] ; base0[-loc1] -= sums[1] ; base0[-loc2] -= sums[2] ; base0 -= ichv0 ; /* ------------------------------------- increment the row and column pointers ------------------------------------- */ rowL0 = rowL2 + nrowU ; colU0 = colU2 + nrowU ; } if ( jcolU == ncolU - 2 ) { rowL1 = rowL0 + nrowU ; colU1 = colU0 + nrowU ; /* ---------------------------------------------------- get the local indices for these two rows and columns ---------------------------------------------------- */ loc0 = colindU[jcolU] ; loc1 = colindU[jcolU+1] ; /* --------------------- upper 1x2 block first --------------------- */ DVdot12(nrowU, Ltemp0, colU0, colU1, sums) ; /* ------------------------------------ inject the two sums into the chevron ------------------------------------ */ base0 -= ichv0 ; base0[loc0] -= sums[0] ; base0[loc1] -= sums[1] ; base0 += ichv0 ; /* ---------------------- lower 2x1 block second ---------------------- */ DVdot21(nrowU, rowL0, rowL1, Utemp0, sums) ; /* ------------------------------------ inject the two sums into the chevron ------------------------------------ */ base0 += ichv0 ; base0[-loc0] -= sums[0] ; base0[-loc1] -= sums[1] ; base0 -= ichv0 ; } else if ( jcolU == ncolU - 1 ) { /* --------------------------------------------- get the local indices for this row and column --------------------------------------------- */ loc0 = colindU[jcolU] ; /* --------------------- upper 1x1 block first --------------------- */ DVdot11(nrowU, Ltemp0, colU0, sums) ; /* ------------------------------- inject the sum into the chevron ------------------------------- */ base0 -= ichv0 ; base0[loc0] -= sums[0] ; base0 += ichv0 ; /* ---------------------- lower 1x1 block second ---------------------- */ DVdot11(nrowU, rowL0, Utemp0, sums) ; /* ------------------------------- inject the sum into the chevron ------------------------------- */ base0 += ichv0 ; base0[-loc0] -= sums[0] ; base0 -= ichv0 ; } } } else if ( SUBMTX_IS_SPARSE_COLUMNS(mtxU) && SUBMTX_IS_SPARSE_ROWS(mtxL) ) { double *base, *colU0, *colU1, *entL, *entU, *rowL0, *rowL1, *temp0, *temp1, *temp2 ; int ichv, ii, irow0, irow1, jj, loc, ncolL, ncolU, nentL, nentU, nrowL, nrowU, offsetL, offsetU, sizeL0, sizeL1, sizeU0, sizeU1 ; int *indL, *indL0, *indL1, *indU, *indU0, *indU1, *sizesL, *sizesU ; SubMtx_sparseColumnsInfo(mtxU, &ncolU, &nentU, &sizesU, &indU, &entU) ; SubMtx_sparseRowsInfo(mtxL, &nrowL, &nentL, &sizesL, &indL, &entL) ; nrowU = mtxU->nrow ; ncolL = mtxL->ncol ; DV_setSize(tempDV, 3*nrowU) ; temp0 = DV_entries(tempDV) ; temp1 = temp0 + nrowU ; temp2 = temp1 + nrowU ; /* -------------------------------------------- get the offsets into the indices and entries -------------------------------------------- */ for ( jcolU = offsetL = offsetU = 0 ; jcolU < firstInU ; jcolU++ ) { offsetL += sizesL[jcolU] ; offsetU += sizesU[jcolU] ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n %% offsetL %d, offsetU %d", offsetL, offsetU) ; fflush(stdout) ; #endif /* --------------------------------------------------- loop over the supporting rows of L and columns of U --------------------------------------------------- */ for ( irow0 = firstInU ; irow0 <= lastInU ; irow0++ ) { rowL0 = entL + offsetL ; indL0 = indL + offsetL ; colU0 = entU + offsetU ; indU0 = indU + offsetU ; sizeL0 = sizesL[irow0] ; sizeU0 = sizesU[irow0] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% irow0 %d, offsetL %d, offsetU %d, sizeL0 %d, sizeU0 %d", irow0, offsetL, offsetU, sizeL0, sizeU0) ; fflush(stdout) ; #endif if ( sizeL0 > 0 || sizeU0 > 0 ) { /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv = colindU[irow0] ; base = Chv_diagLocation(chvT, ichv) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% ichv = %d, base = %p", ichv, base) ; fflush(stdout) ; #endif if ( sizeL0 > 0 ) { /* ---------------------------------- compute [ temp0 ] = D * [ rowL0 ] ---------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n\n %% loading temp1") ; fflush(stdout) ; #endif DVzero(2*nrowU, temp0) ; for ( ii = 0 ; ii < sizeL0 ; ii++ ) { jj = indL0[ii] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% ii = %d, jj = %d", ii, jj) ; fflush(stdout) ; #endif temp1[jj] = rowL0[ii] ; } SubMtx_scale1vec(mtxD, temp0, temp1) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% temp0 = L * D") ; DVfprintf(stdout, 2*nrowU, temp0) ; fflush(stdout) ; #endif } if ( sizeU0 > 0 ) { /* ---------------------------------- compute [ temp1 ] = D * [ colU0 ] ---------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n\n %% loading temp2") ; fflush(stdout) ; #endif DVzero(2*nrowU, temp1) ; for ( ii = 0 ; ii < sizeU0 ; ii++ ) { jj = indU0[ii] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% ii = %d, jj = %d", ii, jj) ; fflush(stdout) ; #endif temp2[jj] = colU0[ii] ; } SubMtx_scale1vec(mtxD, temp1, temp2) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% temp1 = D * U") ; DVfprintf(stdout, nrowU, temp1) ; fflush(stdout) ; #endif } if ( sizeL0 > 0 && sizeU0 > 0 ) { /* ------------------------- update the diagonal entry ------------------------- */ base[0] -= DVdoti(sizeU0, temp0, indU0, colU0) ; } /* ---------------------------------------- loop over the following rows and columns ---------------------------------------- */ if ( sizeU0 > 0 ) { /* ------------------------ update the lower entries ------------------------ */ base += ichv ; rowL1 = rowL0 + sizeL0 ; indL1 = indL0 + sizeL0 ; for ( irow1 = irow0 + 1 ; irow1 < ncolU ; irow1++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n %% irow1 %d, sizeL1 %d", irow1, sizesL[irow1]) ; fflush(stdout) ; #endif if ( (sizeL1 = sizesL[irow1]) > 0 ) { loc = colindU[irow1] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% base[%d] = %12.4e, base[%d] = %12.4e", -loc, base[-loc], -loc + 1, base[-loc+1]) ; fflush(stdout) ; #endif base[-loc] -= DVdoti(sizeL1, temp1, indL1, rowL1) ; rowL1 += sizeL1 ; indL1 += sizeL1 ; } } base -= ichv ; } if ( sizeL0 > 0 ) { /* ------------------------ update the upper entries ------------------------ */ base -= ichv ; colU1 = colU0 + sizeU0 ; indU1 = indU0 + sizeU0 ; for ( irow1 = irow0 + 1 ; irow1 < ncolU ; irow1++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n %% irow1 %d, sizeU1 %d", irow1, sizesU[irow1]) ; fflush(stdout) ; #endif if ( (sizeU1 = sizesU[irow1]) > 0 ) { loc = colindU[irow1] ; base[loc] -= DVdoti(sizeU1, temp0, indU1, colU1) ; colU1 += sizeU1 ; indU1 += sizeU1 ; } } base -= ichv ; } } offsetL += sizeL0 ; offsetU += sizeU0 ; } } else { fprintf(stderr, "\n fatal error in Chv_updateN(%p,%p,%p,%p)" "\n bad input, mtxU must have dense or sparse columns" "\n and mtxL must have dense or sparse rows\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } } else if ( CHV_IS_COMPLEX(chvT) ) { if ( SUBMTX_IS_DENSE_COLUMNS(mtxU) && SUBMTX_IS_DENSE_ROWS(mtxL) ) { double sums[18] ; double *base0, *base1, *base2, *colU0, *colU1, *colU2, *entL, *entU, *Ltemp0, *Ltemp1, *Ltemp2, *rowL0, *rowL1, *rowL2, *Utemp0, *Utemp1, *Utemp2 ; int ichv0, ichv1, ichv2, inc1, inc2, irowL, jcolU, loc, loc0, loc1, loc2, ncolL, nrowL, nrowU, offset ; SubMtx_denseInfo(mtxL, &nrowL, &ncolL, &inc1, &inc2, &entL) ; SubMtx_denseInfo(mtxU, &nrowU, &ncolU, &inc1, &inc2, &entU) ; DV_setSize(tempDV, 12*nrowU) ; Ltemp0 = DV_entries(tempDV) ; Ltemp1 = Ltemp0 + 2*nrowU ; Ltemp2 = Ltemp1 + 2*nrowU ; Utemp0 = Ltemp2 + 2*nrowU ; Utemp1 = Utemp0 + 2*nrowU ; Utemp2 = Utemp1 + 2*nrowU ; /* ----------------------------------------------------- loop over the rows of L in groups of three updating the diagonal and upper blocks of the chevron ----------------------------------------------------- */ offset = firstInU*nrowU ; for ( irowL = firstInU ; irowL <= lastInU - 2 ; irowL += 3 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on rows %d, %d and %d", colindU[irowL], colindU[irowL+1], colindU[irowL+2]) ; fflush(stdout) ; #endif rowL0 = entL + 2*offset ; rowL1 = rowL0 + 2*nrowU ; rowL2 = rowL1 + 2*nrowU ; colU0 = entU + 2*offset ; colU1 = colU0 + 2*nrowU ; colU2 = colU1 + 2*nrowU ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowL] ; base0 = Chv_diagLocation(chvT, ichv0) ; ichv1 = colindU[irowL+1] ; base1 = Chv_diagLocation(chvT, ichv1) ; ichv2 = colindU[irowL+2] ; base2 = Chv_diagLocation(chvT, ichv2) ; /* ----------------------------------- [ Ltemp0 ] [ rowL0 ] compute [ Ltemp1 ] = [ rowL1 ] * D [ Ltemp2 ] [ rowL2 ] ----------------------------------- */ DVzero(6*nrowU, Ltemp0) ; SubMtx_scale3vec(mtxD, Ltemp0, Ltemp1, Ltemp2, rowL0, rowL1, rowL2) ; /* ----------------------------------- [ Utemp0 ] [ colU0 ] compute [ Utemp1 ] = D * [ colU0 ] [ Utemp2 ] [ colU0 ] ----------------------------------- */ DVzero(6*nrowU, Utemp0) ; SubMtx_scale3vec(mtxD, Utemp0, Utemp1, Utemp2, colU0, colU1, colU2) ; /* -------------------------------------------------------------- update the 3x3 diagonal block for these three rows and columns -------------------------------------------------------------- */ ZVdotU33(nrowU, Ltemp0, Ltemp1, Ltemp2, colU0, colU1, colU2, sums) ; /* ------------------------------------- inject the nine sums into the chevron ------------------------------------- */ base0[0] -= sums[ 0] ; base0[1] -= sums[ 1] ; loc = 2*(ichv1 - ichv0) ; base0[loc] -= sums[ 2] ; base0[loc+1] -= sums[ 3] ; base0[-loc] -= sums[ 6] ; base0[-loc+1] -= sums[ 7] ; loc = 2*(ichv2 - ichv0) ; base0[loc] -= sums[ 4] ; base0[loc+1] -= sums[ 5] ; base0[-loc] -= sums[12] ; base0[-loc+1] -= sums[13] ; base1[0] -= sums[ 8] ; base1[1] -= sums[ 9] ; loc = 2*(ichv2 - ichv1) ; base1[loc] -= sums[10] ; base1[loc+1] -= sums[11] ; base1[-loc] -= sums[14] ; base1[-loc+1] -= sums[15] ; base2[0] -= sums[16] ; base2[1] -= sums[17] ; /* ------------------------------------------ update the lower and upper blocks together ------------------------------------------ */ rowL0 = rowL2 + 2*nrowU ; colU0 = colU2 + 2*nrowU ; for ( jcolU = irowL + 3 ; jcolU < ncolU - 2 ; jcolU += 3 ) { rowL1 = rowL0 + 2*nrowU ; rowL2 = rowL1 + 2*nrowU ; colU1 = colU0 + 2*nrowU ; colU2 = colU1 + 2*nrowU ; /* ------------------------------------------------------ get the local indices for these three rows and columns ------------------------------------------------------ */ loc0 = 2*colindU[jcolU] ; loc1 = 2*colindU[jcolU+1] ; loc2 = 2*colindU[jcolU+2] ; /* --------------------- upper 3x3 block first --------------------- */ ZVdotU33(nrowU, Ltemp0, Ltemp1, Ltemp2, colU0, colU1, colU2, sums) ; /* ------------------------------------- inject the nine sums into the chevron ------------------------------------- */ base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; base2 -= 2*ichv2 ; base0[loc0] -= sums[ 0] ; base0[loc0+1] -= sums[ 1] ; base0[loc1] -= sums[ 2] ; base0[loc1+1] -= sums[ 3] ; base0[loc2] -= sums[ 4] ; base0[loc2+1] -= sums[ 5] ; base1[loc0] -= sums[ 6] ; base1[loc0+1] -= sums[ 7] ; base1[loc1] -= sums[ 8] ; base1[loc1+1] -= sums[ 9] ; base1[loc2] -= sums[10] ; base1[loc2+1] -= sums[11] ; base2[loc0] -= sums[12] ; base2[loc0+1] -= sums[13] ; base2[loc1] -= sums[14] ; base2[loc1+1] -= sums[15] ; base2[loc2] -= sums[16] ; base2[loc2+1] -= sums[17] ; base0 += 2*ichv0 ; base1 += 2*ichv1 ; base2 += 2*ichv2 ; /* ---------------------- lower 3x3 block second ---------------------- */ ZVdotU33(nrowU, rowL0, rowL1, rowL2, Utemp0, Utemp1, Utemp2, sums) ; /* ------------------------------------- inject the nine sums into the chevron ------------------------------------- */ base0 += 2*ichv0 ; base1 += 2*ichv1 ; base2 += 2*ichv2 ; base0[-loc0] -= sums[ 0] ; base0[-loc0+1] -= sums[ 1] ; base1[-loc0] -= sums[ 2] ; base1[-loc0+1] -= sums[ 3] ; base2[-loc0] -= sums[ 4] ; base2[-loc0+1] -= sums[ 5] ; base0[-loc1] -= sums[ 6] ; base0[-loc1+1] -= sums[ 7] ; base1[-loc1] -= sums[ 8] ; base1[-loc1+1] -= sums[ 9] ; base2[-loc1] -= sums[10] ; base2[-loc1+1] -= sums[11] ; base0[-loc2] -= sums[12] ; base0[-loc2+1] -= sums[13] ; base1[-loc2] -= sums[14] ; base1[-loc2+1] -= sums[15] ; base2[-loc2] -= sums[16] ; base2[-loc2+1] -= sums[17] ; base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; base2 -= 2*ichv2 ; /* ------------------------------------- increment the row and column pointers ------------------------------------- */ rowL0 = rowL2 + 2*nrowU ; colU0 = colU2 + 2*nrowU ; } if ( jcolU == ncolU - 2 ) { rowL1 = rowL0 + 2*nrowU ; colU1 = colU0 + 2*nrowU ; /* ---------------------------------------------------- get the local indices for these two rows and columns ---------------------------------------------------- */ loc0 = 2*colindU[jcolU] ; loc1 = 2*colindU[jcolU+1] ; /* --------------------- upper 3x2 block first --------------------- */ ZVdotU32(nrowU, Ltemp0, Ltemp1, Ltemp2, colU0, colU1, sums) ; /* ------------------------------------ inject the six sums into the chevron ------------------------------------ */ base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; base2 -= 2*ichv2 ; base0[loc0] -= sums[ 0] ; base0[loc0+1] -= sums[ 1] ; base0[loc1] -= sums[ 2] ; base0[loc1+1] -= sums[ 3] ; base1[loc0] -= sums[ 4] ; base1[loc0+1] -= sums[ 5] ; base1[loc1] -= sums[ 6] ; base1[loc1+1] -= sums[ 7] ; base2[loc0] -= sums[ 8] ; base2[loc0+1] -= sums[ 9] ; base2[loc1] -= sums[10] ; base2[loc1+1] -= sums[11] ; base0 += 2*ichv0 ; base1 += 2*ichv1 ; base2 += 2*ichv2 ; /* ---------------------- lower 2x3 block second ---------------------- */ ZVdotU23(nrowU, rowL0, rowL1, Utemp0, Utemp1, Utemp2, sums) ; /* ------------------------------------ inject the six sums into the chevron ------------------------------------ */ base0 += 2*ichv0 ; base1 += 2*ichv1 ; base2 += 2*ichv2 ; base0[-loc0] -= sums[ 0] ; base0[-loc0+1] -= sums[ 1] ; base1[-loc0] -= sums[ 2] ; base1[-loc0+1] -= sums[ 3] ; base2[-loc0] -= sums[ 4] ; base2[-loc0+1] -= sums[ 5] ; base0[-loc1] -= sums[ 6] ; base0[-loc1+1] -= sums[ 7] ; base1[-loc1] -= sums[ 8] ; base1[-loc1+1] -= sums[ 9] ; base2[-loc1] -= sums[10] ; base2[-loc1+1] -= sums[11] ; base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; base2 -= 2*ichv2 ; } else if ( jcolU == ncolU - 1 ) { /* --------------------------------------------- get the local indices for this row and column --------------------------------------------- */ loc0 = 2*colindU[jcolU] ; /* --------------------- upper 3x1 block first --------------------- */ ZVdotU31(nrowU, Ltemp0, Ltemp1, Ltemp2, colU0, sums) ; /* -------------------------------------- inject the three sums into the chevron -------------------------------------- */ base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; base2 -= 2*ichv2 ; base0[loc0] -= sums[ 0] ; base0[loc0+1] -= sums[ 1] ; base1[loc0] -= sums[ 2] ; base1[loc0+1] -= sums[ 3] ; base2[loc0] -= sums[ 4] ; base2[loc0+1] -= sums[ 5] ; base0 += 2*ichv0 ; base1 += 2*ichv1 ; base2 += 2*ichv2 ; /* ---------------------- lower 1x3 block second ---------------------- */ ZVdotU13(nrowU, rowL0, Utemp0, Utemp1, Utemp2, sums) ; /* -------------------------------------- inject the three sums into the chevron -------------------------------------- */ base0 += 2*ichv0 ; base1 += 2*ichv1 ; base2 += 2*ichv2 ; base0[-loc0] -= sums[ 0] ; base0[-loc0+1] -= sums[ 1] ; base1[-loc0] -= sums[ 2] ; base1[-loc0+1] -= sums[ 3] ; base2[-loc0] -= sums[ 4] ; base2[-loc0+1] -= sums[ 5] ; base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; base2 -= 2*ichv2 ; } offset += 3*nrowU ; } if ( irowL == lastInU - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on rows %d and %d", colindU[irowL], colindU[irowL+1]) ; fflush(stdout) ; #endif rowL0 = entL + 2*offset ; rowL1 = rowL0 + 2*nrowU ; colU0 = entU + 2*offset ; colU1 = colU0 + 2*nrowU ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowL] ; base0 = Chv_diagLocation(chvT, ichv0) ; ichv1 = colindU[irowL+1] ; base1 = Chv_diagLocation(chvT, ichv1) ; /* ----------------------------------- [ Ltemp0 ] [ rowL0 ] compute [ Ltemp1 ] = [ rowL1 ] * D ----------------------------------- */ DVzero(4*nrowU, Ltemp0) ; SubMtx_scale2vec(mtxD, Ltemp0, Ltemp1, rowL0, rowL1) ; /* ----------------------------------- [ Utemp0 ] [ colU0 ] compute [ Utemp1 ] = D * [ colU0 ] ----------------------------------- */ DVzero(4*nrowU, Utemp0) ; SubMtx_scale2vec(mtxD, Utemp0, Utemp1, colU0, colU1) ; /* ------------------------------------------------------------ update the 2x2 diagonal block for these two rows and columns ------------------------------------------------------------ */ ZVdotU22(nrowU, Ltemp0, Ltemp1, colU0, colU1, sums) ; /* ------------------------------------- inject the four sums into the chevron ------------------------------------- */ base0[0] -= sums[ 0] ; base0[1] -= sums[ 1] ; loc = 2*(ichv1 - ichv0) ; base0[loc] -= sums[ 2] ; base0[loc+1] -= sums[ 3] ; base0[-loc] -= sums[ 4] ; base0[-loc+1] -= sums[ 5] ; base1[0] -= sums[ 6] ; base1[1] -= sums[ 7] ; /* ------------------------------------------ update the lower and upper blocks together ------------------------------------------ */ rowL0 = rowL1 + 2*nrowU ; colU0 = colU1 + 2*nrowU ; for ( jcolU = irowL + 2 ; jcolU < ncolU - 2 ; jcolU += 3 ) { rowL1 = rowL0 + 2*nrowU ; rowL2 = rowL1 + 2*nrowU ; colU1 = colU0 + 2*nrowU ; colU2 = colU1 + 2*nrowU ; /* ------------------------------------------------------ get the local indices for these three rows and columns ------------------------------------------------------ */ loc0 = 2*colindU[jcolU] ; loc1 = 2*colindU[jcolU+1] ; loc2 = 2*colindU[jcolU+2] ; /* --------------------- upper 2x3 block first --------------------- */ ZVdotU23(nrowU, Ltemp0, Ltemp1, colU0, colU1, colU2, sums) ; /* ------------------------------------ inject the six sums into the chevron ------------------------------------ */ base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; base0[loc0] -= sums[ 0] ; base0[loc0+1] -= sums[ 1] ; base0[loc1] -= sums[ 2] ; base0[loc1+1] -= sums[ 3] ; base0[loc2] -= sums[ 4] ; base0[loc2+1] -= sums[ 5] ; base1[loc0] -= sums[ 6] ; base1[loc0+1] -= sums[ 7] ; base1[loc1] -= sums[ 8] ; base1[loc1+1] -= sums[ 9] ; base1[loc2] -= sums[10] ; base1[loc2+1] -= sums[11] ; base0 += 2*ichv0 ; base1 += 2*ichv1 ; /* ---------------------- lower 3x2 block second ---------------------- */ ZVdotU32(nrowU, rowL0, rowL1, rowL2, Utemp0, Utemp1, sums) ; /* ------------------------------------ inject the six sums into the chevron ------------------------------------ */ base0 += 2*ichv0 ; base1 += 2*ichv1 ; base0[-loc0] -= sums[ 0] ; base0[-loc0+1] -= sums[ 1] ; base1[-loc0] -= sums[ 2] ; base1[-loc0+1] -= sums[ 3] ; base0[-loc1] -= sums[ 4] ; base0[-loc1+1] -= sums[ 5] ; base1[-loc1] -= sums[ 6] ; base1[-loc1+1] -= sums[ 7] ; base0[-loc2] -= sums[ 8] ; base0[-loc2+1] -= sums[ 9] ; base1[-loc2] -= sums[10] ; base1[-loc2+1] -= sums[11] ; base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; /* ------------------------------------- increment the row and column pointers ------------------------------------- */ rowL0 = rowL2 + 2*nrowU ; colU0 = colU2 + 2*nrowU ; } if ( jcolU == ncolU - 2 ) { rowL1 = rowL0 + 2*nrowU ; colU1 = colU0 + 2*nrowU ; /* ---------------------------------------------------- get the local indices for these two rows and columns ---------------------------------------------------- */ loc0 = 2*colindU[jcolU] ; loc1 = 2*colindU[jcolU+1] ; /* --------------------- upper 2x2 block first --------------------- */ ZVdotU22(nrowU, Ltemp0, Ltemp1, colU0, colU1, sums) ; /* ------------------------------------- inject the four sums into the chevron ------------------------------------- */ base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; base0[loc0] -= sums[ 0] ; base0[loc0+1] -= sums[ 1] ; base0[loc1] -= sums[ 2] ; base0[loc1+1] -= sums[ 3] ; base1[loc0] -= sums[ 4] ; base1[loc0+1] -= sums[ 5] ; base1[loc1] -= sums[ 6] ; base1[loc1+1] -= sums[ 7] ; base0 += 2*ichv0 ; base1 += 2*ichv1 ; /* ---------------------- lower 2x2 block second ---------------------- */ ZVdotU22(nrowU, rowL0, rowL1, Utemp0, Utemp1, sums) ; /* ------------------------------------- inject the four sums into the chevron ------------------------------------- */ base0 += 2*ichv0 ; base1 += 2*ichv1 ; base0[-loc0] -= sums[ 0] ; base0[-loc0+1] -= sums[ 1] ; base1[-loc0] -= sums[ 2] ; base1[-loc0+1] -= sums[ 3] ; base0[-loc1] -= sums[ 4] ; base0[-loc1+1] -= sums[ 5] ; base1[-loc1] -= sums[ 6] ; base1[-loc1+1] -= sums[ 7] ; base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; } else if ( jcolU == ncolU - 1 ) { /* --------------------------------------------- get the local indices for this row and column --------------------------------------------- */ loc0 = 2*colindU[jcolU] ; /* --------------------- upper 2x1 block first --------------------- */ ZVdotU21(nrowU, Ltemp0, Ltemp1, colU0, sums) ; /* ------------------------------------ inject the two sums into the chevron ------------------------------------ */ base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; base0[loc0] -= sums[ 0] ; base0[loc0+1] -= sums[ 1] ; base1[loc0] -= sums[ 2] ; base1[loc0+1] -= sums[ 3] ; base0 += 2*ichv0 ; base1 += 2*ichv1 ; /* ---------------------- lower 1x2 block second ---------------------- */ ZVdotU12(nrowU, rowL0, Utemp0, Utemp1, sums) ; /* ------------------------------------ inject the two sums into the chevron ------------------------------------ */ base0 += 2*ichv0 ; base1 += 2*ichv1 ; base0[-loc0] -= sums[ 0] ; base0[-loc0+1] -= sums[ 1] ; base1[-loc0] -= sums[ 2] ; base1[-loc0+1] -= sums[ 3] ; base0 -= 2*ichv0 ; base1 -= 2*ichv1 ; } } else if ( irowL == lastInU ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% working on row %d", colindU[irowL]) ; fflush(stdout) ; #endif rowL0 = entL + 2*offset ; colU0 = entU + 2*offset ; /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv0 = colindU[irowL] ; base0 = Chv_diagLocation(chvT, ichv0) ; /* ----------------------------------- compute [ Ltemp0 ] = [ rowL0 ] * D ----------------------------------- */ DVzero(2*nrowU, Ltemp0) ; SubMtx_scale1vec(mtxD, Ltemp0, rowL0) ; /* ----------------------------------- compute [ Utemp0 ] = D * [ colU0 ] ----------------------------------- */ DVzero(2*nrowU, Utemp0) ; SubMtx_scale1vec(mtxD, Utemp0, colU0) ; /* ------------------------------------------------------------ update the 1x1 diagonal block for these two rows and columns ------------------------------------------------------------ */ ZVdotU11(nrowU, Ltemp0, colU0, sums) ; /* ------------------------------- inject the sum into the chevron ------------------------------- */ base0[0] -= sums[ 0] ; base0[1] -= sums[ 1] ; /* ------------------------------------------ update the lower and upper blocks together ------------------------------------------ */ rowL0 = rowL0 + 2*nrowU ; colU0 = colU0 + 2*nrowU ; for ( jcolU = irowL + 1 ; jcolU < ncolU - 2 ; jcolU += 3 ) { rowL1 = rowL0 + 2*nrowU ; rowL2 = rowL1 + 2*nrowU ; colU1 = colU0 + 2*nrowU ; colU2 = colU1 + 2*nrowU ; /* ------------------------------------------------------ get the local indices for these three rows and columns ------------------------------------------------------ */ loc0 = 2*colindU[jcolU] ; loc1 = 2*colindU[jcolU+1] ; loc2 = 2*colindU[jcolU+2] ; /* --------------------- upper 1x3 block first --------------------- */ ZVdotU13(nrowU, Ltemp0, colU0, colU1, colU2, sums) ; /* -------------------------------------- inject the three sums into the chevron -------------------------------------- */ base0 -= 2*ichv0 ; base0[loc0] -= sums[ 0] ; base0[loc0+1] -= sums[ 1] ; base0[loc1] -= sums[ 2] ; base0[loc1+1] -= sums[ 3] ; base0[loc2] -= sums[ 4] ; base0[loc2+1] -= sums[ 5] ; base0 += 2*ichv0 ; /* ---------------------- lower 3x1 block second ---------------------- */ ZVdotU31(nrowU, rowL0, rowL1, rowL2, Utemp0, sums) ; /* -------------------------------------- inject the three sums into the chevron -------------------------------------- */ base0 += 2*ichv0 ; base0[-loc0] -= sums[ 0] ; base0[-loc0+1] -= sums[ 1] ; base0[-loc1] -= sums[ 2] ; base0[-loc1+1] -= sums[ 3] ; base0[-loc2] -= sums[ 4] ; base0[-loc2+1] -= sums[ 5] ; base0 -= 2*ichv0 ; /* ------------------------------------- increment the row and column pointers ------------------------------------- */ rowL0 = rowL2 + 2*nrowU ; colU0 = colU2 + 2*nrowU ; } if ( jcolU == ncolU - 2 ) { rowL1 = rowL0 + 2*nrowU ; colU1 = colU0 + 2*nrowU ; /* ---------------------------------------------------- get the local indices for these two rows and columns ---------------------------------------------------- */ loc0 = 2*colindU[jcolU] ; loc1 = 2*colindU[jcolU+1] ; /* --------------------- upper 1x2 block first --------------------- */ ZVdotU12(nrowU, Ltemp0, colU0, colU1, sums) ; /* ------------------------------------ inject the two sums into the chevron ------------------------------------ */ base0 -= 2*ichv0 ; base0[loc0] -= sums[ 0] ; base0[loc0+1] -= sums[ 1] ; base0[loc1] -= sums[ 2] ; base0[loc1+1] -= sums[ 3] ; base0 += 2*ichv0 ; /* ---------------------- lower 2x1 block second ---------------------- */ ZVdotU21(nrowU, rowL0, rowL1, Utemp0, sums) ; /* ------------------------------------ inject the two sums into the chevron ------------------------------------ */ base0 += 2*ichv0 ; base0[-loc0] -= sums[ 0] ; base0[-loc0+1] -= sums[ 1] ; base0[-loc1] -= sums[ 2] ; base0[-loc1+1] -= sums[ 3] ; base0 -= 2*ichv0 ; } else if ( jcolU == ncolU - 1 ) { /* --------------------------------------------- get the local indices for this row and column --------------------------------------------- */ loc0 = 2*colindU[jcolU] ; /* --------------------- upper 1x1 block first --------------------- */ ZVdotU11(nrowU, Ltemp0, colU0, sums) ; /* ------------------------------- inject the sum into the chevron ------------------------------- */ base0 -= 2*ichv0 ; base0[loc0] -= sums[ 0] ; base0[loc0+1] -= sums[ 1] ; base0 += 2*ichv0 ; /* ---------------------- lower 1x1 block second ---------------------- */ ZVdotU11(nrowU, rowL0, Utemp0, sums) ; /* ------------------------------- inject the sum into the chevron ------------------------------- */ base0 += 2*ichv0 ; base0[-loc0] -= sums[ 0] ; base0[-loc0+1] -= sums[ 1] ; base0 -= 2*ichv0 ; } } } else if ( SUBMTX_IS_SPARSE_COLUMNS(mtxU) && SUBMTX_IS_SPARSE_ROWS(mtxL) ) { double imag, real ; double *base, *colU0, *colU1, *entL, *entU, *rowL0, *rowL1, *temp0, *temp1, *temp2 ; int ichv, ii, irow0, irow1, jj, loc, ncolL, ncolU, nentL, nentU, nrowL, nrowU, offsetL, offsetU, sizeL0, sizeL1, sizeU0, sizeU1 ; int *indL, *indL0, *indL1, *indU, *indU0, *indU1, *sizesL, *sizesU ; SubMtx_sparseColumnsInfo(mtxU, &ncolU, &nentU, &sizesU, &indU, &entU) ; SubMtx_sparseRowsInfo(mtxL, &nrowL, &nentL, &sizesL, &indL, &entL) ; nrowU = mtxU->nrow ; ncolL = mtxL->ncol ; DV_setSize(tempDV, 6*nrowU) ; temp0 = DV_entries(tempDV) ; temp1 = temp0 + 2*nrowU ; temp2 = temp1 + 2*nrowU ; /* -------------------------------------------- get the offsets into the indices and entries -------------------------------------------- */ for ( jcolU = offsetL = offsetU = 0 ; jcolU < firstInU ; jcolU++ ) { offsetL += sizesL[jcolU] ; offsetU += sizesU[jcolU] ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n %% offsetL %d, offsetU %d", offsetL, offsetU) ; fflush(stdout) ; #endif /* --------------------------------------------------- loop over the supporting rows of L and columns of U --------------------------------------------------- */ for ( irow0 = firstInU ; irow0 <= lastInU ; irow0++ ) { rowL0 = entL + 2*offsetL ; indL0 = indL + offsetL ; colU0 = entU + 2*offsetU ; indU0 = indU + offsetU ; sizeL0 = sizesL[irow0] ; sizeU0 = sizesU[irow0] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% irow0 %d, offsetL %d, offsetU %d, sizeL0 %d, sizeU0 %d", irow0, offsetL, offsetU, sizeL0, sizeU0) ; fflush(stdout) ; #endif if ( sizeL0 > 0 || sizeU0 > 0 ) { /* ----------------------------------------------------- get base locations for the chevron's diagonal entries ----------------------------------------------------- */ ichv = colindU[irow0] ; base = Chv_diagLocation(chvT, ichv) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% ichv = %d, base = %p", ichv, base) ; fflush(stdout) ; #endif if ( sizeL0 > 0 ) { /* ---------------------------------- compute [ temp0 ] = D * [ rowL0 ] ---------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n\n %% loading temp1") ; fflush(stdout) ; #endif DVzero(4*nrowU, temp0) ; for ( ii = 0 ; ii < sizeL0 ; ii++ ) { jj = indL0[ii] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% ii = %d, jj = %d", ii, jj) ; fflush(stdout) ; #endif temp1[2*jj] = rowL0[2*ii] ; temp1[2*jj+1] = rowL0[2*ii+1] ; #if MYDEBUG > 0 fprintf(stdout, ", (%12.4e,%12.4e)", rowL0[2*ii], rowL0[2*ii+1]) ; fflush(stdout) ; #endif } SubMtx_scale1vec(mtxD, temp0, temp1) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% temp0 = L * D") ; DVfprintf(stdout, 2*nrowU, temp0) ; fflush(stdout) ; #endif } if ( sizeU0 > 0 ) { /* ---------------------------------- compute [ temp1 ] = D * [ colU0 ] ---------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n\n %% loading temp2") ; fflush(stdout) ; #endif DVzero(4*nrowU, temp1) ; for ( ii = 0 ; ii < sizeU0 ; ii++ ) { jj = indU0[ii] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% ii = %d, jj = %d", ii, jj) ; fflush(stdout) ; #endif temp2[2*jj] = colU0[2*ii] ; temp2[2*jj+1] = colU0[2*ii+1] ; #if MYDEBUG > 0 fprintf(stdout, ", (%12.4e,%12.4e)", colU0[2*ii], colU0[2*ii+1]) ; fflush(stdout) ; #endif } SubMtx_scale1vec(mtxD, temp1, temp2) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% temp1 = D * U") ; DVfprintf(stdout, 2*nrowU, temp1) ; fflush(stdout) ; #endif } if ( sizeL0 > 0 && sizeU0 > 0 ) { /* ------------------------- update the diagonal entry ------------------------- */ ZVdotiU(sizeU0, temp0, indU0, colU0, &real, &imag) ; base[0] -= real ; base[1] -= imag ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% sum = %12.4e + %12.4e*i, " "\n base[%d] = %12.4e, base[%d] = %12.4e ", real, imag, 0, base[0], 1, base[1]) ; fflush(stdout) ; #endif } /* ---------------------------------------- loop over the following rows and columns ---------------------------------------- */ if ( sizeU0 > 0 ) { /* ------------------------ update the lower entries ------------------------ */ base += 2*ichv ; rowL1 = rowL0 + 2*sizeL0 ; indL1 = indL0 + sizeL0 ; for ( irow1 = irow0 + 1 ; irow1 < ncolU ; irow1++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n %% irow1 %d, sizeL1 %d", irow1, sizesL[irow1]) ; fflush(stdout) ; #endif if ( (sizeL1 = sizesL[irow1]) > 0 ) { loc = 2*colindU[irow1] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% base[%d] = %12.4e, base[%d] = %12.4e", -loc, base[-loc], -loc + 1, base[-loc+1]) ; fflush(stdout) ; #endif ZVdotiU(sizeL1, temp1, indL1, rowL1, &real, &imag); base[-loc] -= real ; base[-loc+1] -= imag ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% sum = %12.4e + %12.4e*i, " "\n base[%d] = %12.4e, base[%d] = %12.4e ", real, imag, -loc, base[-loc], -loc + 1, base[-loc+1]) ; fflush(stdout) ; #endif rowL1 += 2*sizeL1 ; indL1 += sizeL1 ; } } base -= 2*ichv ; } if ( sizeL0 > 0 ) { /* ------------------------ update the upper entries ------------------------ */ base -= 2*ichv ; colU1 = colU0 + 2*sizeU0 ; indU1 = indU0 + sizeU0 ; for ( irow1 = irow0 + 1 ; irow1 < ncolU ; irow1++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n %% irow1 %d, sizeU1 %d", irow1, sizesU[irow1]) ; fflush(stdout) ; #endif if ( (sizeU1 = sizesU[irow1]) > 0 ) { loc = 2*colindU[irow1] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% base[%d] = %12.4e, base[%d] = %12.4e", loc, base[loc], loc + 1, base[loc+1]) ; fflush(stdout) ; #endif ZVdotiU(sizeU1, temp0, indU1, colU1, &real, &imag); base[loc] -= real ; base[loc+1] -= imag ; #if MYDEBUG > 0 fprintf(stdout, "\n\n %% sum = %12.4e + %12.4e*i, " "\n base[%d] = %12.4e, base[%d] = %12.4e ", real, imag, loc, base[loc], loc + 1, base[loc+1]) ; fflush(stdout) ; #endif colU1 += 2*sizeU1 ; indU1 += sizeU1 ; } } base -= ichv ; } } offsetL += sizeL0 ; offsetU += sizeU0 ; } } else { fprintf(stderr, "\n fatal error in Chv_updateN(%p,%p,%p,%p)" "\n bad input, mtxU must have dense or sparse columns" "\n and mtxL must have dense or sparse rows\n", chvT, mtxD, mtxU, tempDV) ; exit(-1) ; } } /* --------------------------------------------------- overwrite the local indices with the global indices --------------------------------------------------- */ for ( jcolU = firstInU ; jcolU < ncolU ; jcolU++ ) { colindU[jcolU] = colindT[colindU[jcolU]] ; } return ; } /*--------------------------------------------------------------------*/ = sums[ 2] ; base0[-loc1+1] -= sums[ 3] ; base0 -= 2*ichv0 ; } else if ( jcolU == ncolU - 1 ) { /* --------------------------------------------- get the local indices for this row and column --------------------------------------------- */ loc0 = 2*colindU[jcolU] ; /* --------------------- upper 1x1 block first --------------------- */ ZVdotU11(nrowU, Ltemp0, colChv/src/util.c010064400020550007177000000443770657126731400145530ustar00clevecompmath00000400000006/* util.c */ #include "../Chv.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- shift the indices, entries and adjust the nD dimension. note: shift can be positive or negative created -- 98apr30, cca ------------------------------------------------------- */ void Chv_shift ( Chv *chv, int shift ) { int ii, stride ; /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_shift(%p,%d)" "\n bad input\n", chv, shift) ; exit(-1) ; } if ( shift == 0 ) { return ; } if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_SYMMETRIC(chv) ) { /* -------------------- chevron is symmetric -------------------- */ chv->colind += shift ; if ( shift < 0 ) { stride = chv->nD + chv->nU + 1 ; for ( ii = shift ; ii < 0 ; ii++ ) { chv->entries -= stride ; stride++ ; } } else { stride = chv->nD + chv->nU ; for ( ii = 0 ; ii < shift ; ii++ ) { chv->entries += stride ; stride-- ; } } chv->nD -= shift ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { /* ----------------------- chevron is nonsymmetric ----------------------- */ chv->rowind += shift ; chv->colind += shift ; if ( shift < 0 ) { stride = 2*chv->nD + chv->nL + chv->nU + 1 ; for ( ii = shift ; ii < 0 ; ii++ ) { chv->entries -= stride ; stride += 2 ; } } else { stride = 2*chv->nD + chv->nL + chv->nU - 1 ; for ( ii = 0 ; ii < shift ; ii++ ) { chv->entries += stride ; stride -= 2 ; } } chv->nD -= shift ; } else { fprintf(stderr, "\n fatal error in Chv_shift(%p,%d)" "\n type is SPOOLES_REAL, symflag = %d" "\n must be SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC\n", chv, shift, chv->symflag) ; exit(-1) ; } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { /* -------------------- chevron is symmetric -------------------- */ chv->colind += shift ; if ( shift < 0 ) { stride = chv->nD + chv->nU + 1 ; for ( ii = shift ; ii < 0 ; ii++ ) { chv->entries -= 2*stride ; stride++ ; } } else { stride = chv->nD + chv->nU ; for ( ii = 0 ; ii < shift ; ii++ ) { chv->entries += 2*stride ; stride-- ; } } chv->nD -= shift ; } else if ( CHV_IS_NONSYMMETRIC(chv) ) { /* ----------------------- chevron is nonsymmetric ----------------------- */ chv->rowind += shift ; chv->colind += shift ; if ( shift < 0 ) { stride = 2*chv->nD + chv->nL + chv->nU + 1 ; for ( ii = shift ; ii < 0 ; ii++ ) { chv->entries -= 2*stride ; stride += 2 ; } } else { stride = 2*chv->nD + chv->nL + chv->nU - 1 ; for ( ii = 0 ; ii < shift ; ii++ ) { chv->entries += 2*stride ; stride -= 2 ; } } chv->nD -= shift ; } else { fprintf(stderr, "\n fatal error in Chv_shift(%p,%d)" "\n type is SPOOLES_COMPLEX, symflag = %d" "\n must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN" "\n or SPOOLES_NONSYMMETRIC\n", chv, shift, chv->symflag) ; exit(-1) ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- return the maximum magnitude of the entries in the chevron created -- 98apr30, cca ---------------------------------------------------------- */ double Chv_maxabs ( Chv *chv ) { double maxabs ; /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_maxabs(%p)" "\n bad input\n", chv) ; exit(-1) ; } maxabs = 0.0 ; if ( CHV_IS_REAL(chv) ) { int loc ; maxabs = DVmaxabs(Chv_nent(chv), Chv_entries(chv), &loc) ; } else if ( CHV_IS_COMPLEX(chv) ) { maxabs = ZVmaxabs(Chv_nent(chv), Chv_entries(chv)) ; } else { fprintf(stderr, "\n fatal error in Chv_maxabs(%p)" "\n type is %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, chv->type) ; exit(-1) ; } return(maxabs) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- return the frobenius norm of the entries in the chevron created -- 98apr30, cca ------------------------------------------------------- */ double Chv_frobNorm ( Chv *chv ) { double sum ; /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_frobNorm(%p)" "\n bad input\n", chv) ; exit(-1) ; } if ( CHV_IS_REAL(chv) ) { double value, *entries ; int ii, nent ; nent = Chv_nent(chv) ; entries = Chv_entries(chv) ; for ( ii = 0, sum = 0.0 ; ii < nent ; ii++ ) { value = entries[ii] ; sum += value*value ; } } else if ( CHV_IS_COMPLEX(chv) ) { double imag, real, *entries ; int ii, nent ; nent = Chv_nent(chv) ; entries = Chv_entries(chv) ; for ( ii = 0, sum = 0.0 ; ii < nent ; ii++ ) { real = entries[2*ii] ; imag = entries[2*ii+1] ; sum += real*real + imag*imag ; } } else { fprintf(stderr, "\n fatal error in Chv_frobNorm(%p)" "\n type is %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, chv->type) ; exit(-1) ; } return(sqrt(sum)) ; } /*--------------------------------------------------------------------*/ /* ----------------------- subtract chvI from chvJ created -- 98apr30, cca ----------------------- */ void Chv_sub ( Chv *chvJ, Chv *chvI ) { double *entriesI, *entriesJ ; int ii, nDI, nDJ, nent, nLI, nLJ, nUI, nUJ ; /* --------------- check the input --------------- */ if ( chvI == NULL || chvJ == NULL ) { fprintf(stderr, "\n fatal error in Chv_sub(%p,%p)" "\n bad input\n", chvI, chvJ) ; exit(-1) ; } Chv_dimensions(chvJ, &nDJ, &nLJ, &nUJ) ; Chv_dimensions(chvI, &nDI, &nLI, &nUI) ; if ( nDJ != nDI || nLJ != nLI || nUJ != nUI ) { fprintf(stderr, "\n fatal error in Chv_sub(%p,%p)" "\n dimensions do not match\n", chvJ, chvI) ; exit(-1) ; } entriesJ = Chv_entries(chvJ) ; entriesI = Chv_entries(chvI) ; if ( entriesJ == NULL || entriesI == NULL ) { fprintf(stderr, "\n fatal error in Chv_sub(%p,%p)" "\n entriesJ = %p, entriesI = %p\n", chvJ, chvI, entriesJ, entriesI) ; exit(-1) ; } if ( CHV_IS_REAL(chvJ) && CHV_IS_REAL(chvI) ) { nent = Chv_nent(chvJ) ; for ( ii = 0 ; ii < nent ; ii++ ) { entriesJ[ii] -= entriesI[ii] ; } } else if ( CHV_IS_COMPLEX(chvJ) && CHV_IS_COMPLEX(chvI) ) { nent = Chv_nent(chvJ) ; for ( ii = 0 ; ii < nent ; ii++ ) { entriesJ[2*ii] -= entriesI[2*ii] ; entriesJ[2*ii+1] -= entriesI[2*ii+1] ; } } else { fprintf(stderr, "\n fatal error in Chv_sub(%p,%p)" "\n typeJ = %d, typeI = %d" "\n both must be SPOOLES_REAL or SPOOLES_COMPLEX", chvJ, chvI, chvJ->type, chvI->type) ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------- zero the entries in the chevron created -- 98apr30, cca ------------------------------- */ void Chv_zero ( Chv *chv ) { /* --------------- check the input --------------- */ if ( chv == NULL ) { fprintf(stderr, "\n fatal error in Chv_zero(%p)" "\n bad input\n", chv) ; exit(-1) ; } if ( CHV_IS_REAL(chv) ) { DVzero(Chv_nent(chv), Chv_entries(chv)) ; } else if ( CHV_IS_COMPLEX(chv) ) { ZVzero(Chv_nent(chv), Chv_entries(chv)) ; } else { fprintf(stderr, "\n fatal error in Chv_zero(%p)" "\n type = %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", chv, chv->type) ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------- fill A2 object with (1,1) block created -- 98apr30, cca ------------------------------- */ void Chv_fill11block ( Chv *chv, A2 *mtx ) { double *entries ; int nD, nL, nU ; /* --------------- check the input --------------- */ if ( chv == NULL || mtx == NULL ) { fprintf(stderr, "\n fatal error in Chv_fill11block(%p,%p)" "\n bad input\n", chv, mtx) ; exit(-1) ; } if ( ! (CHV_IS_REAL(chv) || CHV_IS_COMPLEX(chv)) ) { fprintf(stderr, "\n fatal error in Chv_fill11block(%p,%p)" "\n type = %d, must be real or complex\n", chv, mtx, chv->type) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { A2_init(mtx, SPOOLES_REAL, nD, nD, 1, nD, NULL) ; A2_zero(mtx) ; if ( CHV_IS_SYMMETRIC(chv) ) { int ii, iioff, ioff, istride, jj ; /* ---------------- chv is symmetric ---------------- */ ioff = 0 ; istride = nD + nU ; for ( ii = 0 ; ii < nD ; ii++ ) { A2_setRealEntry(mtx, ii, ii, entries[ioff]) ; for ( jj = ii + 1, iioff = ioff + 1 ; jj < nD ; jj++, iioff++ ) { A2_setRealEntry(mtx, ii, jj, entries[iioff]) ; A2_setRealEntry(mtx, jj, ii, 0.0) ; } ioff += istride ; istride-- ; } } else if ( CHV_IS_NONSYMMETRIC(chv) ) { int ii, iioff, ioff, istride, jj ; /* --------------------- chv is nonsymmetric --------------------- */ ioff = nD + nL - 1 ; istride = 2*nD + nU + nL - 2 ; for ( ii = 0 ; ii < nD ; ii++ ) { A2_setRealEntry(mtx, ii, ii, entries[ioff]) ; for ( jj = ii + 1, iioff = ioff + 1 ; jj < nD ; jj++, iioff++ ) { A2_setRealEntry(mtx, ii, jj, entries[iioff]) ; } for ( jj = ii + 1, iioff = ioff - 1 ; jj < nD ; jj++, iioff-- ) { A2_setRealEntry(mtx, jj, ii, entries[iioff]) ; } ioff += istride ; istride -= 2 ; } } } else if ( CHV_IS_COMPLEX(chv) ) { A2_init(mtx, SPOOLES_COMPLEX, nD, nD, 1, nD, NULL) ; A2_zero(mtx) ; if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int ii, iioff, ioff, istride, jj ; /* ---------------- chv is symmetric ---------------- */ ioff = 0 ; istride = nD + nU ; for ( ii = 0 ; ii < nD ; ii++ ) { A2_setComplexEntry(mtx, ii, ii, entries[2*ioff], entries[2*ioff+1]) ; for ( jj = ii + 1, iioff = ioff + 1 ; jj < nD ; jj++, iioff++ ) { A2_setComplexEntry(mtx, ii, jj, entries[2*iioff], entries[2*iioff+1]) ; A2_setComplexEntry(mtx, jj, ii, 0.0, 0.0) ; } ioff += istride ; istride-- ; } } else if ( CHV_IS_NONSYMMETRIC(chv) ) { int ii, iioff, ioff, istride, jj ; /* --------------------- chv is nonsymmetric --------------------- */ ioff = nD + nL - 1 ; istride = 2*nD + nU + nL - 2 ; for ( ii = 0 ; ii < nD ; ii++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n ii %d, ioff %d, setting (%d,%d) = (%20.12e,%20.12e)", ii, ioff, ii, ii, entries[2*ioff], entries[2*ioff+1]) ; #endif A2_setComplexEntry(mtx, ii, ii, entries[2*ioff], entries[2*ioff+1]) ; for ( jj = ii + 1, iioff = ioff + 1 ; jj < nD ; jj++, iioff++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n jj %d, iioff %d, setting (%d,%d) = (%20.12e,%20.12e)", jj, iioff, ii, ii, entries[2*iioff], entries[2*iioff+1]) ; #endif A2_setComplexEntry(mtx, ii, jj, entries[2*iioff], entries[2*iioff+1]) ; } for ( jj = ii + 1, iioff = ioff - 1 ; jj < nD ; jj++, iioff-- ) { #if MYDEBUG > 0 fprintf(stdout, "\n jj %d, iioff %d, setting (%d,%d) = (%20.12e,%20.12e)", jj, iioff, ii, ii, entries[2*iioff], entries[2*iioff+1]) ; #endif A2_setComplexEntry(mtx, jj, ii, entries[2*iioff], entries[2*iioff+1]) ; } ioff += istride ; istride -= 2 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------- fill A2 object with (1,2) block created -- 98apr30, cca ------------------------------- */ void Chv_fill12block ( Chv *chv, A2 *mtx ) { double *entries ; int nD, nL, nU ; /* --------------- check the input --------------- */ if ( chv == NULL || mtx == NULL ) { fprintf(stderr, "\n fatal error in Chv_fill12block(%p,%p)" "\n bad input\n", chv, mtx) ; exit(-1) ; } if ( ! (CHV_IS_REAL(chv) || CHV_IS_COMPLEX(chv)) ) { fprintf(stderr, "\n fatal error in Chv_fill12block(%p,%p)" "\n type = %d, must be real or complex\n", chv, mtx, chv->type) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; /* --------------------------------- resize the A2 object as necessary --------------------------------- */ if ( CHV_IS_REAL(chv) ) { A2_init(mtx, SPOOLES_REAL, nD, nU, 1, nD, NULL) ; A2_zero(mtx) ; if ( CHV_IS_SYMMETRIC(chv) ) { int ii, iioff, ioff, istride, jj ; /* ------------------ chv is symmetric ------------------ */ ioff = 0 ; istride = nD + nU ; for ( ii = 0 ; ii < nD ; ii++ ) { for ( jj = 0, iioff = ioff + nD - ii ; jj < nU ; jj++, iioff++ ) { A2_setRealEntry(mtx, ii, jj, entries[iioff]) ; } ioff += istride ; istride-- ; } } else if ( CHV_IS_NONSYMMETRIC(chv) ) { int ii, iioff, ioff, istride, jj ; /* --------------------- chv is nonsymmetric --------------------- */ ioff = nD + nL - 1 ; istride = 2*nD + nU + nL - 2 ; for ( ii = 0 ; ii < nD ; ii++ ) { for ( jj = 0, iioff = ioff + nD - ii ; jj < nU ; jj++, iioff++ ) { A2_setRealEntry(mtx, ii, jj, entries[iioff]) ; } ioff += istride ; istride -= 2 ; } } } else if ( CHV_IS_COMPLEX(chv) ) { A2_init(mtx, SPOOLES_COMPLEX, nD, nU, 1, nD, NULL) ; A2_zero(mtx) ; if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { int ii, iioff, ioff, istride, jj ; /* ------------------ chv is symmetric ------------------ */ ioff = 0 ; istride = nD + nU ; for ( ii = 0 ; ii < nD ; ii++ ) { for ( jj = 0, iioff = ioff + nD - ii ; jj < nU ; jj++, iioff++ ) { A2_setComplexEntry(mtx, ii, jj, entries[2*iioff], entries[2*iioff+1]) ; #if MYDEBUG > 0 fprintf(stdout, "\n 21: ii %d, jj %d, iioff %d, setting (%d,%d) = (%20.12e,%20.12e)", ii, jj, iioff, ii, ii, entries[2*iioff], entries[2*iioff+1]) ; #endif } ioff += istride ; istride-- ; } } else if ( CHV_IS_NONSYMMETRIC(chv) ) { int ii, iioff, ioff, istride, jj ; /* --------------------- chv is nonsymmetric --------------------- */ ioff = nD + nL - 1 ; istride = 2*nD + nU + nL - 2 ; for ( ii = 0 ; ii < nD ; ii++ ) { for ( jj = 0, iioff = ioff + nD - ii ; jj < nU ; jj++, iioff++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n 21: ii %d, jj %d, iioff %d, setting (%d,%d) = (%20.12e,%20.12e)", ii, jj, iioff, ii, ii, entries[2*iioff], entries[2*iioff+1]) ; #endif A2_setComplexEntry(mtx, ii, jj, entries[2*iioff], entries[2*iioff+1]) ; } ioff += istride ; istride -= 2 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------- fill A2 object with (2,1) block created -- 98apr30, cca ------------------------------- */ void Chv_fill21block ( Chv *chv, A2 *mtx ) { double *entries ; int nD, nL, nU ; /* --------------- check the input --------------- */ if ( chv == NULL || mtx == NULL ) { fprintf(stderr, "\n fatal error in Chv_fillReal21block(%p,%p)" "\n bad input\n", chv, mtx) ; exit(-1) ; } if ( ! (CHV_IS_REAL(chv) || CHV_IS_COMPLEX(chv)) ) { fprintf(stderr, "\n fatal error in Chv_fill21block(%p,%p)" "\n type = %d, must be real or complex\n", chv, mtx, chv->type) ; exit(-1) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { int ii, iioff, ioff, istride, jj ; A2_init(mtx, SPOOLES_REAL, nL, nD, nD, 1, NULL) ; A2_zero(mtx) ; ioff = nD + nL - 1 ; istride = 2*nD + nU + nL - 2 ; for ( ii = 0 ; ii < nD ; ii++ ) { for ( jj = 0, iioff = ioff - nD + ii ; jj < nL ; jj++, iioff-- ) { A2_setRealEntry(mtx, jj, ii, entries[iioff]) ; } ioff += istride ; istride -= 2 ; } } else if ( CHV_IS_COMPLEX(chv) ) { int ii, iioff, ioff, istride, jj ; A2_init(mtx, SPOOLES_COMPLEX, nL, nD, nD, 1, NULL) ; A2_zero(mtx) ; ioff = nD + nL - 1 ; istride = 2*nD + nU + nL - 2 ; for ( ii = 0 ; ii < nD ; ii++ ) { for ( jj = 0, iioff = ioff - nD + ii ; jj < nL ; jj++, iioff-- ) { #if MYDEBUG > 0 fprintf(stdout, "\n 12: ii %d, jj %d, iioff %d, setting (%d,%d) = (%20.12e,%20.12e)", ii, jj, iioff, ii, ii, entries[2*iioff], entries[2*iioff+1]) ; #endif A2_setComplexEntry(mtx, jj, ii, entries[2*iioff], entries[2*iioff+1]) ; } ioff += istride ; istride -= 2 ; } } return ; } /*--------------------------------------------------------------------*/ ---------------------------- fill A2 object with (1,1) block created -- 98apr30, cca ------------------------------- */ void Chv_fill11block ( Chv *chv, A2 *mtx ) { double *entries ; int nD, nL, nU ; /* --------------- checChv/drivers/do_addChevron010075500020550007177000000006650657126731700170010ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = res set msgFile = stdout set type = 2 set symflag = 0 set nD = 9 set nU = 5 set alphareal = 1.0 set alphareal = 9.0 set alphaimag = 0.0 set alphaimag = 4.0 set seed = 7377 test_addChevron \ $msglvl $msgFile $nD $nU $type $symflag $seed $alphareal $alphaimag Chv/drivers/do_assmbChv010075500020550007177000000005660657126732000164640ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = res set msgFile = stdout set type = 2 set symflag = 2 set nDJ = 10 set nUJ = 12 set nDI = 7 set nUI = 8 set seed = 7387788 test_assmbChv \ $msglvl $msgFile $nDJ $nUJ $nDI $nUI $type $symflag $seed Chv/drivers/do_copyBigEntriesToVector010075500020550007177000000013220657126732000213210ustar00clevecompmath00000400000006#! /bin/csh -f # # test the ZChv_copyEntriesToVector() method # # created -- 98apr22, cca # set msglvl = 4 set msgFile = res set msgFile = stdout set type = 1 set symflag = 0 set nD = 6 set nU = 5 set pivotingflag = 1 set copyflag = 3 set storeflag = 0 set seed = 1 set droptol = 7.5e-1 foreach type ( 2 ) foreach symflag ( 2 ) foreach pivotingflag ( 1 ) foreach storeflag ( 1 ) test_copyBigEntriesToVector \ $msglvl $msgFile $nD $nU $type $symflag \ $pivotingflag $storeflag $seed $droptol end end end end Chv/drivers/do_copyEntriesToVector010075500020550007177000000012520657126731700207070ustar00clevecompmath00000400000006#! /bin/csh -f # # test the Chv_copyEntriesToVector() method # # created -- 98apr22, cca # set msglvl = 4 set msgFile = res set msgFile = stdout set type = 1 set symflag = 0 set nD = 6 set nU = 5 set pivotingflag = 1 set copyflag = 3 set storeflag = 0 set seed = 1 foreach type ( 2 ) foreach symflag ( 2 ) foreach pivotingflag ( 1 ) foreach storeflag ( 1 ) test_copyEntriesToVector \ $msglvl $msgFile $nD $nU $type $symflag \ $pivotingflag $storeflag $seed end end end end Chv/drivers/do_factor010075500020550007177000000011020657354352000161600ustar00clevecompmath00000400000006#! /bin/csh -f # # test the Chv_factor() method # # created -- 98apr22, cca # set msglvl = 4 set msgFile = res set msgFile = stdout set type = 2 set symflag = 0 set nD = 16 set nU = 15 set pivotingflag = 1 set seed = 188291 set tau = 5 foreach type ( 2 ) foreach symflag ( 2 ) foreach pivotingflag ( 1 ) test_factor \ $msglvl $msgFile $nD $nU $type $symflag \ $pivotingflag $seed $tau end end end Chv/drivers/do_findPivot010075500020550007177000000005210657126732000166470ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 1 set msgFile = res set msgFile = stdout set type = 2 set symflag = 2 set nD = 6 set nU = 5 set seed = 77787 set tau = 10 test_findPivot \ $msglvl $msgFile $nD $nU $type $symflag $seed $tau Chv/drivers/do_maxabs010075500020550007177000000004550657126731700161740ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 1 set msgFile = res set msgFile = stdout set type = 2 set symflag = 2 set nD = 6 set nU = 5 set seed = 7777 test_maxabs \ $msglvl $msgFile $nD $nU $type $symflag $seed Chv/drivers/do_r1upd010075500020550007177000000005320657126731700157500ustar00clevecompmath00000400000006#! /bin/csh -f # # test the ZChv_r1upd() method # # created -- 98apr22, cca # set msglvl = 4 set msgFile = res set msgFile = stdout set type = 2 set symflag = 2 set nD = 6 set nU = 5 set seed = 1821 foreach symflag ( 0 ) test_r1upd $msglvl $msgFile $nD $nU $type $symflag $seed end Chv/drivers/do_r2upd010075500020550007177000000005310657126731700157500ustar00clevecompmath00000400000006#! /bin/csh -f # # test the ZChv_r2upd() method # # created -- 98apr22, cca # set msglvl = 4 set msgFile = res set msgFile = stdout set type = 1 set symflag = 0 set nD = 6 set nU = 5 set seed = 18291 foreach symflag ( 0 ) test_r2upd $msglvl $msgFile $nD $nU $type $symflag $seed end Chv/drivers/do_swap010075500020550007177000000004530657126731700156710ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 1 set msgFile = res set msgFile = stdout set type = 2 set symflag = 1 set nD = 6 set nU = 5 set seed = 7777 test_swap \ $msglvl $msgFile $nD $nU $type $symflag $seed Chv/drivers/do_update010075500020550007177000000014220657126731700161760ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = res set msgFile = stdout set type = 1 set symflag = 0 set sparsityflag = 1 set ncolT = 14 set nDT = 5 set ncolU = $ncolT set ncolU = 18 set nrowD = 10 set nentU = 55 set offset = 4 set seed = 66666 # nDT = 5, 6, 7 set nDT = 7 # ncolT = 12, 13, 14 set ncolT = 14 set offset = 4 set nrowD = 10 @ ncolU = $ncolT + $offset foreach type ( 2 ) foreach symflag ( 2 ) foreach sparsityflag ( 1 ) test_update \ $msglvl $msgFile $type $symflag $sparsityflag \ $ncolT $nDT $ncolU $nrowD $nentU $offset $seed end end end Chv/drivers/makefile010064400020550007177000000032500665314237700160040ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = test_addChevron \ test_assmbChv \ test_copyEntriesToVector\ test_copyBigEntriesToVector\ test_factor \ test_findPivot \ test_maxabs \ test_swap \ test_r1upd \ test_r2upd \ test_update drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} test_assmbChv : test_assmbChv.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} test_factor : test_factor.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} test_findPivot : test_findPivot.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} test_maxabs : test_maxabs.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} test_r2upd : test_r2upd.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} test_r1upd : test_r1upd.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} test_addChevron : test_addChevron.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} test_copyBigEntriesToVector : test_copyBigEntriesToVector.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} test_copyEntriesToVector : test_copyEntriesToVector.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} test_swap : test_swap.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} test_update : test_update.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${PURIFY_GCC_VERSION} ${LIBS} Chv/drivers/test_addChevron.c010064400020550007177000000217550657126731700175770ustar00clevecompmath00000400000006/* test_addChevron.c */ #include "../Chv.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------- test the Chv_addChevron() method. created -- 98apr18, cca --------------------------------------- */ { Chv *chv ; double alpha[2] ; double imag, real, t1, t2 ; double *chvent, *entries ; Drand *drand ; FILE *msgFile ; int chvsize, count, ichv, ierr, ii, iloc, irow, jcol, lastcol, msglvl, ncol, nD, nent, nL, nrow, nU, off, seed, symflag, type, upper ; int *chvind, *colind, *keys, *rowind, *temp ; if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nD nU type symflag seed " "\n alphareal alphaimag" "\n msglvl -- message level" "\n msgFile -- message file" "\n nD -- # of rows and columns in the (1,1) block" "\n nU -- # of columns in the (1,2) block" "\n type -- entries type" "\n 1 --> real" "\n 2 --> complex" "\n symflag -- symmetry flag" "\n 0 --> symmetric" "\n 1 --> hermitian" "\n 2 --> nonsymmetric" "\n seed -- random number seed" "\n alpha -- scaling parameter" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } nD = atoi(argv[3]) ; nU = atoi(argv[4]) ; type = atoi(argv[5]) ; symflag = atoi(argv[6]) ; seed = atoi(argv[7]) ; alpha[0] = atof(argv[8]) ; alpha[1] = atof(argv[9]) ; if ( nD <= 0 || nU < 0 || symflag < 0 || symflag > 2 ) { fprintf(stderr, "\n invalid input" "\n nD = %d, nU = %d, symflag = %d\n", nD, nU, symflag) ; exit(-1) ; } fprintf(msgFile, "\n alpha = %12.4e + %12.4e*i ;", alpha[0], alpha[1]) ; nL = nU ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setUniform(drand, -1.0, 1.0) ; /* ---------------------------- initialize the Chv object ---------------------------- */ MARKTIME(t1) ; chv = Chv_new() ; Chv_init(chv, 0, nD, nL, nU, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize chv object", t2 - t1) ; fflush(msgFile) ; Chv_columnIndices(chv, &ncol, &colind) ; temp = IVinit(2*(nD+nU), -1) ; IVramp(2*(nD+nU), temp, 0, 1) ; IVshuffle(2*(nD+nU), temp, ++seed) ; IVcopy(ncol, colind, temp) ; IVqsortUp(ncol, colind) ; if ( CHV_IS_NONSYMMETRIC(chv) ) { Chv_rowIndices(chv, &nrow, &rowind) ; IVcopy(nrow, rowind, colind) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n %% column indices") ; IVfprintf(msgFile, ncol, colind) ; } lastcol = colind[ncol-1] ; nent = Chv_nent(chv) ; entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( CHV_IS_COMPLEX(chv) ) { Drand_fillDvector(drand, 2*nent, entries) ; } if ( CHV_IS_HERMITIAN(chv) ) { /* --------------------------------------------------------- hermitian example, set imaginary part of diagonal to zero --------------------------------------------------------- */ for ( irow = 0 ; irow < nD ; irow++ ) { Chv_complexEntry(chv, irow, irow, &real, &imag) ; Chv_setComplexEntry(chv, irow, irow, real, 0.0) ; } } if ( msglvl > 1 ) { fprintf(msgFile, "\n a = zeros(%d,%d) ;", lastcol+1, lastcol+1) ; Chv_writeForMatlab(chv, "a", msgFile) ; } /* -------------------------------------------------- fill a chevron with random numbers and indices that are a subset of a front's, as in the assembly of original matrix entries. -------------------------------------------------- */ Drand_setUniform(drand, 0, nD) ; iloc = (int) Drand_value(drand) ; ichv = colind[iloc] ; if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { upper = nD - iloc + nU ; } else { upper = 2*(nD - iloc) - 1 + nL + nU ; } Drand_setUniform(drand, 1, upper) ; chvsize = (int) Drand_value(drand) ; fprintf(msgFile, "\n %% iloc = %d, ichv = %d, chvsize = %d", iloc, ichv, chvsize) ; chvind = IVinit(chvsize, -1) ; chvent = DVinit(2*chvsize, 0.0) ; Drand_setNormal(drand, 0.0, 1.0) ; if ( CHV_IS_REAL(chv) ) { Drand_fillDvector(drand, chvsize, chvent) ; } else if ( CHV_IS_COMPLEX(chv) ) { Drand_fillDvector(drand, 2*chvsize, chvent) ; } keys = IVinit(upper+1, -1) ; keys[0] = 0 ; if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { for ( ii = iloc + 1, count = 1 ; ii < nD + nU ; ii++ ) { keys[count++] = colind[ii] - ichv ; } } else { for ( ii = iloc + 1, count = 1 ; ii < nD + nU ; ii++ ) { keys[count++] = colind[ii] - ichv ; keys[count++] = - colind[ii] + ichv ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% iloc = %d, ichv = %d", iloc, ichv) ; fprintf(msgFile, "\n %% upper = %d", upper) ; fprintf(msgFile, "\n %% chvsize = %d", chvsize) ; fprintf(msgFile, "\n %% initial keys") ; IVfprintf(msgFile, count, keys) ; } IVshuffle(count, keys, ++seed) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n %% shuffled keys") ; IVfp80(msgFile, count, keys, 80, &ierr) ; } IVcopy(chvsize, chvind, keys) ; if ( CHV_IS_REAL(chv) ) { IVDVqsortUp(chvsize, chvind, chvent) ; } else if ( CHV_IS_COMPLEX(chv) ) { IVZVqsortUp(chvsize, chvind, chvent) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% chvind") ; IVfprintf(msgFile, chvsize, chvind) ; } if ( CHV_IS_HERMITIAN(chv) ) { for ( ii = 0 ; ii < chvsize ; ii++ ) { if ( chvind[ii] == 0 ) { chvent[2*ii+1] = 0.0 ; } } } if ( msglvl > 1 ) { fprintf(msgFile, "\n b = zeros(%d,%d) ;", lastcol+1, lastcol+1) ; if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_SYMMETRIC(chv) ) { for ( ii = 0 ; ii < chvsize ; ii++ ) { off = chvind[ii] ; fprintf(msgFile, "\n b(%d,%d) = %20.12e ;", colind[iloc]+1, colind[iloc]+off+1, chvent[ii]) ; fprintf(msgFile, "\n b(%d,%d) = %20.12e ;", colind[iloc]+off+1, colind[iloc]+1, chvent[ii]) ; } } else { for ( ii = 0 ; ii < chvsize ; ii++ ) { off = chvind[ii] ; if ( off > 0 ) { fprintf(msgFile, "\n b(%d,%d) = %20.12e ;", colind[iloc]+1, colind[iloc]+off+1, chvent[ii]) ; } else { fprintf(msgFile, "\n b(%d,%d) = %20.12e ;", colind[iloc]-off+1, colind[iloc]+1, chvent[ii]) ; } } } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { for ( ii = 0 ; ii < chvsize ; ii++ ) { off = chvind[ii] ; fprintf(msgFile, "\n b(%d,%d) = %20.12e + %20.12e*i;", colind[iloc]+1, colind[iloc]+off+1, chvent[2*ii], chvent[2*ii+1]) ; if ( CHV_IS_HERMITIAN(chv) ) { fprintf(msgFile, "\n b(%d,%d) = %20.12e + %20.12e*i;", colind[iloc]+off+1, colind[iloc]+1, chvent[2*ii], -chvent[2*ii+1]) ; } else { fprintf(msgFile, "\n b(%d,%d) = %20.12e + %20.12e*i;", colind[iloc]+off+1, colind[iloc]+1, chvent[2*ii], chvent[2*ii+1]) ; } } } else { for ( ii = 0 ; ii < chvsize ; ii++ ) { off = chvind[ii] ; if ( off > 0 ) { fprintf(msgFile, "\n b(%d,%d) = %20.12e + %20.12e*i;", colind[iloc]+1, colind[iloc]+off+1, chvent[2*ii], chvent[2*ii+1]) ; } else { fprintf(msgFile, "\n b(%d,%d) = %20.12e + %20.12e*i;", colind[iloc]-off+1, colind[iloc]+1, chvent[2*ii], chvent[2*ii+1]) ; } } } } } /* ------------------------------------ add the chevron into the Chv object ------------------------------------ */ Chv_addChevron(chv, alpha, ichv, chvsize, chvind, chvent) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %% after adding the chevron") ; fprintf(msgFile, "\n c = zeros(%d,%d) ;", lastcol+1, lastcol+1) ; Chv_writeForMatlab(chv, "c", msgFile) ; } /* ----------------- compute the error ----------------- */ fprintf(msgFile, "\n max(max(abs(c - (a + alpha*b))))") ; /* ------------------------ free the working storage ------------------------ */ Chv_free(chv) ; Drand_free(drand) ; IVfree(temp) ; IVfree(chvind) ; DVfree(chvent) ; IVfree(keys) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Chv/drivers/test_assmbChv.c010064400020550007177000000141530657126732000172540ustar00clevecompmath00000400000006/* test_assmbChv.c */ #include "../Chv.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------ test the Chv_assembleChv() method. created -- 98apr18, cca ------------------------------------ */ { Chv *chvI, *chvJ ; double imag, real, t1, t2 ; double *entriesI, *entriesJ ; Drand *drand ; FILE *msgFile ; int ierr, ii, irow, jcol, lastcol, msglvl, ncolI, ncolJ, nDI, nDJ, nentI, nentJ, nrowI, nrowJ, nUI, nUJ, seed, symflag, type ; int *colindI, *colindJ, *rowindI, *rowindJ, *temp ; if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nDJ nUJ nDI nUI type symflag seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n nDJ -- # of rows and columns in the (1,1) block" "\n nUJ -- # of columns in the (1,2) block" "\n nDI -- # of rows and columns in the (1,1) block" "\n nUI -- # of columns in the (1,2) block" "\n type -- entries type" "\n 1 --> real" "\n 2 --> complex" "\n symflag -- symmetry flag" "\n 0 --> symmetric" "\n 1 --> hermitian" "\n 2 --> nonsymmetric" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } nDJ = atoi(argv[3]) ; nUJ = atoi(argv[4]) ; nDI = atoi(argv[5]) ; nUI = atoi(argv[6]) ; type = atoi(argv[7]) ; symflag = atoi(argv[8]) ; seed = atoi(argv[9]) ; if ( nDJ <= 0 || nUJ < 0 || nDI <= 0 || nUI < 0 || nDI >= nDJ || (nDI + nUI) >= (nDJ + nUJ) || nUI >= (nDJ + nUJ - nDI) || ( symflag != SPOOLES_SYMMETRIC && symflag != SPOOLES_HERMITIAN && symflag != SPOOLES_NONSYMMETRIC) ) { fprintf(stderr, "\n invalid input" "\n nDJ = %d, nUJ = %d, nDI = %d, nUI = %d, symflag = %d\n", nDJ, nUJ, nDI, nUI, symflag) ; exit(-1) ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setUniform(drand, -1.0, 1.0) ; /* ---------------------------- initialize the ChvJ object ---------------------------- */ MARKTIME(t1) ; chvJ = Chv_new() ; Chv_init(chvJ, 0, nDJ, nUJ, nUJ, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize chv object", t2 - t1) ; fflush(msgFile) ; Chv_columnIndices(chvJ, &ncolJ, &colindJ) ; temp = IVinit(2*(nDJ+nUJ), -1) ; IVramp(2*(nDJ+nUJ), temp, 0, 1) ; IVshuffle(2*(nDJ+nUJ), temp, ++seed) ; IVcopy(ncolJ, colindJ, temp) ; IVfree(temp) ; IVqsortUp(ncolJ, colindJ) ; if ( CHV_IS_NONSYMMETRIC(chvJ) ) { Chv_rowIndices(chvJ, &nrowJ, &rowindJ) ; IVcopy(nrowJ, rowindJ, colindJ) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n %% column indices") ; IVfprintf(msgFile, ncolJ, colindJ) ; } lastcol = colindJ[ncolJ-1] ; nentJ = Chv_nent(chvJ) ; entriesJ = Chv_entries(chvJ) ; if ( CHV_IS_REAL(chvJ) ) { Drand_fillDvector(drand, nentJ, entriesJ) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { Drand_fillDvector(drand, 2*nentJ, entriesJ) ; } if ( CHV_IS_HERMITIAN(chvJ) ) { /* --------------------------------------------------------- hermitian example, set imaginary part of diagonal to zero --------------------------------------------------------- */ for ( irow = 0 ; irow < nDJ ; irow++ ) { Chv_complexEntry(chvJ, irow, irow, &real, &imag) ; Chv_setComplexEntry(chvJ, irow, irow, real, 0.0) ; } } /* --------------------------- initialize the ChvI object --------------------------- */ chvI = Chv_new() ; Chv_init(chvI, 0, nDI, nUI, nUI, type, symflag) ; Chv_columnIndices(chvI, &ncolI, &colindI) ; temp = IVinit(ncolJ, -1) ; IVramp(ncolJ, temp, 0, 1) ; while ( 1 ) { IVshuffle(ncolJ, temp, ++seed) ; IVqsortUp(ncolI, temp) ; if ( temp[0] < nDJ ) { break ; } } for ( ii = 0 ; ii < ncolI ; ii++ ) { colindI[ii] = colindJ[temp[ii]] ; } IVfree(temp) ; if ( CHV_IS_NONSYMMETRIC(chvI) ) { Chv_rowIndices(chvI, &nrowI, &rowindI) ; IVcopy(nrowI, rowindI, colindI) ; } nentI = Chv_nent(chvI) ; entriesI = Chv_entries(chvI) ; if ( CHV_IS_REAL(chvI) ) { Drand_fillDvector(drand, nentI, entriesI) ; } else if ( CHV_IS_COMPLEX(chvI) ) { Drand_fillDvector(drand, 2*nentI, entriesI) ; } if ( CHV_IS_HERMITIAN(chvI) ) { /* --------------------------------------------------------- hermitian example, set imaginary part of diagonal to zero --------------------------------------------------------- */ for ( irow = 0 ; irow < nDI ; irow++ ) { Chv_complexEntry(chvI, irow, irow, &real, &imag) ; Chv_setComplexEntry(chvI, irow, irow, real, 0.0) ; } } /* -------------------------------------------------- write out the two chevron objects to a matlab file -------------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n a = zeros(%d,%d) ;", lastcol+1, lastcol+1) ; Chv_writeForMatlab(chvJ, "a", msgFile) ; fprintf(msgFile, "\n b = zeros(%d,%d) ;", lastcol+1, lastcol+1) ; Chv_writeForMatlab(chvI, "b", msgFile) ; } /* --------------------------------------------- assemble the chvI object into the chvJ object --------------------------------------------- */ Chv_assembleChv(chvJ, chvI) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %% after assembly") ; fprintf(msgFile, "\n c = zeros(%d,%d) ;", lastcol+1, lastcol+1) ; Chv_writeForMatlab(chvJ, "c", msgFile) ; } /* ----------------- compute the error ----------------- */ fprintf(msgFile, "\n max(max(abs(c - (b + a))))") ; /* ------------------------ free the working storage ------------------------ */ Chv_free(chvJ) ; Chv_free(chvI) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ nUJ, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize chv object", t2 - t1) ; fflush(msgFile) ; Chv_columnIndices(chvJ, &ncolJ, &colindJ) ; temp = IVinit(2*(nDJ+nUJ), -1) ; IVramp(2*(nDJ+nUJ), temp, 0, 1) ; IVshuffle(2*(nDJ+nUJ), temp, ++seed) ; IVcopy(ncolJ, colindJ, temp) ; IVfree(temp) ; IVqsortUp(ncolJ, colindJ) ; if ( CHV_IS_NONSYMMETRIC(chvJ) ) { Chv_roChv/drivers/test_copyBigEntriesToVector.c010064400020550007177000000541500657126732000221230ustar00clevecompmath00000400000006/* test_copyBigEntriesToVector.c */ #include "../Chv.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------- test the copyBigEntriesToVector routine created -- 98apr18, cca, --------------------------------------- */ { Chv *chvJ, *chvI ; double droptol, imag, real, t1, t2 ; double *dvec, *entries ; Drand *drand ; FILE *msgFile ; int count, first, ierr, ii, iilast, ipivot, irow, jcol, jj, jjlast, maxnent, mm, msglvl, ncol, nD, nent, nentD, nentL, nentL11, nentL21, nentU, nentU11, nentU12, nL, npivot, nrow, nU, pivotingflag, seed, storeflag, symflag, total, type ; int *colind, *ivec, *pivotsizes, *rowind, *sizes ; if ( argc != 11 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nD nU type symflag " "\n pivotingflag storeflag seed droptol" "\n msglvl -- message level" "\n msgFile -- message file" "\n nD -- # of rows and columns in the (1,1) block" "\n nU -- # of columns in the (1,2) block" "\n type -- entries type" "\n 1 --> real" "\n 2 --> complex" "\n symflag -- symmetry flag" "\n 0 --> symmetric" "\n 1 --> nonsymmetric" "\n pivotingflag -- pivoting flag" "\n if symflag = 1 and pivotingflag = 1 then" "\n construct pivotsizes[] vector" "\n endif" "\n storeflag -- flag to denote how to store entries" "\n 0 --> store by rows" "\n 1 --> store by columns" "\n seed -- random number seed" "\n droptol -- entries whose magnitude >= droptol are copied" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } nD = atoi(argv[3]) ; nU = atoi(argv[4]) ; type = atoi(argv[5]) ; symflag = atoi(argv[6]) ; pivotingflag = atoi(argv[7]) ; storeflag = atoi(argv[8]) ; seed = atoi(argv[9]) ; droptol = atof(argv[10]) ; if ( msglvl > 0 ) { switch ( storeflag ) { case 0 : fprintf(msgFile, "\n\n %% STORE BY ROWS") ; break ; case 1 : fprintf(msgFile, "\n\n %% STORE BY COLUMNS") ; break ; default : fprintf(stderr, "\n bad value %d for storeflag", storeflag) ; break ; } } nL = nU ; if ( symflag == SPOOLES_NONSYMMETRIC ) { pivotingflag = 0 ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setNormal(drand, 0.0, 1.0) ; Drand_setSeed(drand, seed) ; /* -------------------------- initialize the chvJ object -------------------------- */ MARKTIME(t1) ; chvJ = Chv_new() ; Chv_init(chvJ, 0, nD, nL, nU, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix objects", t2 - t1) ; nent = Chv_nent(chvJ) ; entries = Chv_entries(chvJ) ; if ( CHV_IS_REAL(chvJ) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { Drand_fillDvector(drand, 2*nent, entries) ; } Chv_columnIndices(chvJ, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; if ( CHV_IS_NONSYMMETRIC(chvJ) ) { Chv_rowIndices(chvJ, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% chevron a") ; Chv_writeForMatlab(chvJ, "a", msgFile) ; fflush(msgFile) ; } /* -------------------------- initialize the chvI object -------------------------- */ MARKTIME(t1) ; chvI = Chv_new() ; Chv_init(chvI, 0, nD, nL, nU, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix objects", t2 - t1) ; Chv_zero(chvI) ; Chv_columnIndices(chvI, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; if ( CHV_IS_NONSYMMETRIC(chvI) ) { Chv_rowIndices(chvI, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; } if ( symflag == 0 && pivotingflag == 1 ) { /* ------------------------------ create the pivotsizes[] vector ------------------------------ */ Drand_setUniform(drand, 1, 2.999) ; pivotsizes = IVinit(nD, 0) ; Drand_fillIvector(drand, nD, pivotsizes) ; /* fprintf(msgFile, "\n initial pivotsizes[] : ") ; IVfp80(msgFile, nD, pivotsizes, 80, &ierr) ; */ for ( npivot = count = 0 ; npivot < nD ; npivot++ ) { count += pivotsizes[npivot] ; if ( count > nD ) { pivotsizes[npivot]-- ; count-- ; } if ( count == nD ) { break ; } } npivot++ ; /* fprintf(msgFile, "\n final pivotsizes[] : ") ; IVfp80(msgFile, npivot, pivotsizes, 80, &ierr) ; */ } else { npivot = 0 ; pivotsizes = NULL ; } /* -------------------------------------------------- first test: copy lower, diagonal and upper entries -------------------------------------------------- */ if ( CHV_IS_NONSYMMETRIC(chvJ) ) { nentL = Chv_countBigEntries(chvJ, npivot, pivotsizes, CHV_STRICT_LOWER, droptol) ; } else { nentL = 0 ; } nentD = Chv_countEntries(chvJ, npivot, pivotsizes, CHV_DIAGONAL) ; nentU = Chv_countBigEntries(chvJ, npivot, pivotsizes, CHV_STRICT_UPPER, droptol) ; maxnent = nentL ; if ( maxnent < nentD ) { maxnent = nentD ; } if ( maxnent < nentU ) { maxnent = nentU ; } fprintf(msgFile, "\n %% nentL = %d, nentD = %d, nentU = %d", nentL, nentD, nentU) ; sizes = IVinit(ncol, 0) ; ivec = IVinit(maxnent, 0) ; if ( CHV_IS_REAL(chvJ) ) { dvec = DVinit(maxnent, 0.0) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { dvec = DVinit(2*maxnent, 0.0) ; } if ( CHV_IS_NONSYMMETRIC(chvJ) ) { /* -------------------------------------- copy the entries in the lower triangle, then move into the chvI object -------------------------------------- */ nent = Chv_copyBigEntriesToVector(chvJ, npivot, pivotsizes, sizes, ivec, dvec, CHV_STRICT_LOWER, storeflag, droptol) ; if ( nent != nentL ) { fprintf(stderr, "\n error: nentL = %d, nent = %d", nentL, nent) ; exit(-1) ; } if ( storeflag == 0 ) { for ( irow = 0, mm = 0 ; irow < nrow ; irow++ ) { if ( sizes[irow] > 0 ) { for ( jj = 0 ; jj < sizes[irow] ; jj++, mm++ ) { jcol = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } else { for ( jcol = 0, mm = 0 ; jcol < nD ; jcol++ ) { if ( sizes[jcol] > 0 ) { for ( ii = 0 ; ii < sizes[jcol] ; ii++, mm++ ) { irow = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } } /* --------------------------------------- copy the entries in the diagonal matrix then move into the chvI object --------------------------------------- */ nent = Chv_copyEntriesToVector(chvJ, npivot, pivotsizes, maxnent, dvec, CHV_DIAGONAL, storeflag) ; if ( nent != nentD ) { fprintf(stderr, "\n error: nentD = %d, nent = %d", nentD, nent) ; exit(-1) ; } if ( pivotsizes == NULL ) { for ( jcol = 0, mm = 0 ; jcol < nD ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, jcol, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, jcol, jcol, real, imag) ; } } } else { for ( ipivot = irow = mm = 0 ; ipivot < npivot ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow, real, imag) ; } mm++ ; irow++ ; } else { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow, real) ; mm++ ; real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow+1, real) ; mm++ ; real = dvec[mm] ; Chv_setRealEntry(chvI, irow+1, irow+1, real) ; mm++ ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow, real, imag) ; mm++ ; real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow+1, real, imag) ; mm++ ; real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow+1, irow+1, real, imag) ; mm++ ; } irow += 2 ; } } } /* -------------------------------------- copy the entries in the upper triangle, then move into the chvI object -------------------------------------- */ nent = Chv_copyBigEntriesToVector(chvJ, npivot, pivotsizes, sizes, ivec, dvec, CHV_STRICT_UPPER, storeflag, droptol) ; if ( nent != nentU ) { fprintf(stderr, "\n error: nentU = %d, nent = %d", nentU, nent) ; exit(-1) ; } if ( storeflag == 1 ) { for ( jcol = mm = 0 ; jcol < ncol ; jcol++ ) { if ( sizes[jcol] > 0 ) { for ( ii = 0 ; ii < sizes[jcol] ; ii++, mm++ ) { irow = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } else { for ( irow = mm = 0 ; irow < nD ; irow++ ) { if ( sizes[irow] > 0 ) { for ( jj = 0 ; jj < sizes[irow] ; jj++, mm++ ) { jcol = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% chevron b") ; Chv_writeForMatlab(chvI, "b", msgFile) ; fprintf(msgFile, "\n\n emtx1 = abs(a - b) ; enorm1 = max(max(emtx1))") ; fflush(msgFile) ; } IVfree(sizes) ; IVfree(ivec) ; DVfree(dvec) ; /* ----------------------------------------------------- second test: copy lower (1,1), lower (2,1), diagonal, upper(1,1) and upper(1,2) blocks ----------------------------------------------------- */ if ( CHV_IS_NONSYMMETRIC(chvJ) ) { nentL11 = Chv_countBigEntries(chvJ, npivot, pivotsizes, CHV_STRICT_LOWER_11, droptol); nentL21 = Chv_countBigEntries(chvJ, npivot, pivotsizes, CHV_LOWER_21, droptol); } else { nentL11 = 0 ; nentL21 = 0 ; } nentD = Chv_countEntries(chvJ, npivot, pivotsizes, CHV_DIAGONAL) ; nentU11 = Chv_countBigEntries(chvJ, npivot, pivotsizes, CHV_STRICT_UPPER_11, droptol) ; nentU12 = Chv_countBigEntries(chvJ, npivot, pivotsizes, CHV_UPPER_12, droptol) ; maxnent = nentL11 ; if ( maxnent < nentL21 ) { maxnent = nentL21 ; } if ( maxnent < nentD ) { maxnent = nentD ; } if ( maxnent < nentU11 ) { maxnent = nentU11 ; } if ( maxnent < nentU12 ) { maxnent = nentU12 ; } fprintf(msgFile, "\n %% nentL11 = %d, nentL21 = %d" "\n %% nentD = %d, nentU11 = %d, nentU12 = %d", nentL11, nentL21, nentD, nentU11, nentU12) ; sizes = IVinit(ncol, 0) ; ivec = IVinit(maxnent, 0) ; if ( CHV_IS_REAL(chvJ) ) { dvec = DVinit(maxnent, 0.0) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { dvec = DVinit(2*maxnent, 0.0) ; } Chv_zero(chvI) ; if ( CHV_IS_NONSYMMETRIC(chvJ) ) { /* ------------------------------------------ copy the entries in the lower (1,1) block, then move into the chvI object ------------------------------------------ */ nent = Chv_copyBigEntriesToVector(chvJ, npivot, pivotsizes, sizes, ivec, dvec, CHV_STRICT_LOWER_11, storeflag, droptol) ; if ( nent != nentL11 ) { fprintf(stderr, "\n error: nentL11 = %d, nent = %d", nentL11, nent) ; exit(-1) ; } if ( storeflag == 0 ) { for ( irow = 0, mm = 0 ; irow < nD ; irow++ ) { if ( sizes[irow] > 0 ) { for ( jj = 0 ; jj < sizes[irow] ; jj++, mm++ ) { jcol = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } else if ( storeflag == 1 ) { for ( jcol = 0, mm = 0 ; jcol < nD ; jcol++ ) { if ( sizes[jcol] > 0 ) { for ( ii = 0 ; ii < sizes[jcol] ; ii++, mm++ ) { irow = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } /* ------------------------------------------ copy the entries in the lower (2,1) block, then move into the chvI object ------------------------------------------ */ nent = Chv_copyBigEntriesToVector(chvJ, npivot, pivotsizes, sizes, ivec, dvec, CHV_LOWER_21, storeflag, droptol) ; if ( nent != nentL21 ) { fprintf(stderr, "\n error: nentL21 = %d, nent = %d", nentL21, nent) ; exit(-1) ; } if ( storeflag == 0 ) { for ( irow = nD, mm = 0 ; irow < nrow ; irow++ ) { if ( sizes[irow-nD] > 0 ) { for ( jj = 0 ; jj < sizes[irow-nD] ; jj++, mm++ ) { jcol = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } else { for ( jcol = mm = 0 ; jcol < nD ; jcol++ ) { if ( sizes[jcol] > 0 ) { for ( ii = 0 ; ii < sizes[jcol] ; ii++, mm++ ) { irow = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } } /* --------------------------------------- copy the entries in the diagonal matrix then move into the chvI object --------------------------------------- */ nent = Chv_copyEntriesToVector(chvJ, npivot, pivotsizes, maxnent, dvec, CHV_DIAGONAL, storeflag) ; /* fprintf(stdout, "\n diagonal dvec") ; DVfprintf(stdout, 2*nent, dvec) ; */ if ( nent != nentD ) { fprintf(stderr, "\n error: nentD = %d, nent = %d", nentD, nent) ; exit(-1) ; } if ( pivotsizes == NULL ) { for ( jcol = 0, mm = 0 ; jcol < nD ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; imag = dvec[2*mm+1] ; Chv_setRealEntry(chvI, jcol, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, jcol, jcol, real, imag) ; } } } else { for ( ipivot = irow = mm = 0 ; ipivot < npivot ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow, real, imag) ; } mm++ ; irow++ ; } else { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow, real) ; mm++ ; real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow+1, real) ; mm++ ; real = dvec[mm] ; Chv_setRealEntry(chvI, irow+1, irow+1, real) ; mm++ ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow, real, imag) ; mm++ ; real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow+1, real, imag) ; mm++ ; real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow+1, irow+1, real, imag) ; mm++ ; } irow += 2 ; } } } /* ----------------------------------------- copy the entries in the upper (1,1) block then move into the chvI object ----------------------------------------- */ nent = Chv_copyBigEntriesToVector(chvJ, npivot, pivotsizes, sizes, ivec, dvec, CHV_STRICT_UPPER_11, storeflag, droptol) ; /* fprintf(stdout, "\n U11 sizes") ; IVfprintf(stdout, nD, sizes) ; fprintf(stdout, "\n U11 ivec") ; IVfprintf(stdout, nent, ivec) ; fprintf(stdout, "\n U11 dvec") ; DVfprintf(stdout, 2*nent, dvec) ; */ if ( nent != nentU11 ) { fprintf(stderr, "\n error: nentU11 = %d, nent = %d", nentU11, nent) ; exit(-1) ; } if ( storeflag == 1 ) { for ( jcol = mm = 0 ; jcol < nD ; jcol++ ) { if ( sizes[jcol] > 0 ) { for ( ii = 0 ; ii < sizes[jcol] ; ii++, mm++ ) { irow = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } else if ( storeflag == 0 ) { for ( irow = mm = 0 ; irow < nD ; irow++ ) { if ( sizes[irow] > 0 ) { for ( jj = 0 ; jj < sizes[irow] ; jj++, mm++ ) { jcol = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } /* ----------------------------------------- copy the entries in the upper (1,2) block then move into the chvI object ----------------------------------------- */ nent = Chv_copyBigEntriesToVector(chvJ, npivot, pivotsizes, sizes, ivec, dvec, CHV_UPPER_12, storeflag, droptol) ; /* fprintf(stdout, "\n U12 sizes") ; if ( storeflag == 1 ) { IVfprintf(stdout, nU, sizes) ; } else { IVfprintf(stdout, nD, sizes) ; } fprintf(stdout, "\n U12 ivec") ; IVfprintf(stdout, nent, ivec) ; fprintf(stdout, "\n U12 dvec") ; DVfprintf(stdout, 2*nent, dvec) ; */ if ( nent != nentU12 ) { fprintf(stderr, "\n error: nentU12 = %d, nent = %d", nentU12, nent) ; exit(-1) ; } if ( storeflag == 1 ) { for ( jcol = nD, mm = 0 ; jcol < ncol ; jcol++ ) { if ( sizes[jcol-nD] > 0 ) { for ( ii = 0 ; ii < sizes[jcol-nD] ; ii++, mm++ ) { irow = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } else if ( storeflag == 0 ) { for ( irow = 0, mm = 0 ; irow < nD ; irow++ ) { if ( sizes[irow] > 0 ) { for ( jj = 0 ; jj < sizes[irow] ; jj++, mm++ ) { jcol = ivec[mm] ; if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% chevron b") ; Chv_writeForMatlab(chvI, "b", msgFile) ; fprintf(msgFile, "\n\n emtx2 = abs(a - b) ; enorm2 = max(max(emtx2))" "\n droptol = %12.4e", droptol) ; fprintf(msgFile, "\n\n [ enorm1 enorm2 droptol ]") ; fflush(msgFile) ; } fprintf(msgFile, "\n") ; Chv_free(chvJ) ; Chv_free(chvI) ; Drand_free(drand) ; IVfree(sizes) ; IVfree(ivec) ; DVfree(dvec) ; if ( pivotsizes != NULL ) { IVfree(pivotsizes) ; } return(1) ; } /*--------------------------------------------------------------------*/ ; } if ( maxnent < nentU11 ) { maxnent = nentU11 ; } if ( maxnent < nentU12 ) { maxnent = nentU12 ; } fprintf(msgFile, "\n %% nentL11 = %d, nentL21 = %d" "\n %% nentD = %d, nentU11 = %d, nentU12 = %d", nentL11, nentL21, nentD, nentU11, nentU12) ; sizes = IVinit(ncol, 0) ; ivec = IVinit(maxnent, 0) ; if ( CHV_IS_REAL(chvJ) ) { dvec = DVinit(maxnent, 0.0) ; } else if ( CHV_IS_CChv/drivers/test_copyEntriesToVector.c010064400020550007177000000624350657126731700215140ustar00clevecompmath00000400000006/* test_copyEntriesToVector.c */ #include "../Chv.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------ test the copyEntriesToVector routine created -- 98may01, cca, ------------------------------------ */ { Chv *chvJ, *chvI ; double imag, real, t1, t2 ; double *dvec, *entries ; Drand *drand ; FILE *msgFile ; int count, first, ierr, ii, iilast, ipivot, irow, jcol, jj, jjlast, maxnent, mm, msglvl, ncol, nD, nent, nentD, nentL, nentL11, nentL21, nentU, nentU11, nentU12, nL, npivot, nrow, nU, pivotingflag, seed, storeflag, symflag, total, type ; int *colind, *pivotsizes, *rowind ; if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nD nU type symflag " "\n pivotingflag storeflag seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n nD -- # of rows and columns in the (1,1) block" "\n nU -- # of columns in the (1,2) block" "\n type -- entries type" "\n 1 --> real" "\n 2 --> complex" "\n symflag -- symmetry flag" "\n 0 --> symmetric" "\n 1 --> nonsymmetric" "\n pivotingflag -- pivoting flag" "\n if symflag = 1 and pivotingflag = 1 then" "\n construct pivotsizes[] vector" "\n endif" "\n storeflag -- flag to denote how to store entries" "\n 0 --> store by rows" "\n 1 --> store by columns" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } nD = atoi(argv[3]) ; nU = atoi(argv[4]) ; type = atoi(argv[5]) ; symflag = atoi(argv[6]) ; pivotingflag = atoi(argv[7]) ; storeflag = atoi(argv[8]) ; seed = atoi(argv[9]) ; if ( msglvl > 0 ) { switch ( storeflag ) { case 0 : fprintf(msgFile, "\n\n %% STORE BY ROWS") ; break ; case 1 : fprintf(msgFile, "\n\n %% STORE BY COLUMNS") ; break ; default : fprintf(stderr, "\n bad value %d for storeflag", storeflag) ; break ; } } nL = nU ; if ( symflag == SPOOLES_NONSYMMETRIC ) { pivotingflag = 0 ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setNormal(drand, 0.0, 1.0) ; Drand_setSeed(drand, seed) ; /* -------------------------- initialize the chvJ object -------------------------- */ MARKTIME(t1) ; chvJ = Chv_new() ; Chv_init(chvJ, 0, nD, nL, nU, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix objects", t2 - t1) ; nent = Chv_nent(chvJ) ; entries = Chv_entries(chvJ) ; if ( CHV_IS_REAL(chvJ) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { Drand_fillDvector(drand, 2*nent, entries) ; } Chv_columnIndices(chvJ, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; if ( CHV_IS_NONSYMMETRIC(chvJ) ) { Chv_rowIndices(chvJ, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% chevron a") ; Chv_writeForMatlab(chvJ, "a", msgFile) ; fflush(msgFile) ; } /* -------------------------- initialize the chvI object -------------------------- */ MARKTIME(t1) ; chvI = Chv_new() ; Chv_init(chvI, 0, nD, nL, nU, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix objects", t2 - t1) ; Chv_zero(chvI) ; Chv_columnIndices(chvI, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; if ( CHV_IS_NONSYMMETRIC(chvI) ) { Chv_rowIndices(chvI, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; } if ( symflag == 0 && pivotingflag == 1 ) { /* ------------------------------ create the pivotsizes[] vector ------------------------------ */ Drand_setUniform(drand, 1, 2.999) ; pivotsizes = IVinit(nD, 0) ; Drand_fillIvector(drand, nD, pivotsizes) ; /* fprintf(msgFile, "\n initial pivotsizes[] : ") ; IVfp80(msgFile, nD, pivotsizes, 80, &ierr) ; */ for ( npivot = count = 0 ; npivot < nD ; npivot++ ) { count += pivotsizes[npivot] ; if ( count > nD ) { pivotsizes[npivot]-- ; count-- ; } if ( count == nD ) { break ; } } npivot++ ; /* fprintf(msgFile, "\n final pivotsizes[] : ") ; IVfp80(msgFile, npivot, pivotsizes, 80, &ierr) ; */ } else { npivot = 0 ; pivotsizes = NULL ; } /* -------------------------------------------------- first test: copy lower, diagonal and upper entries -------------------------------------------------- */ if ( CHV_IS_NONSYMMETRIC(chvJ) ) { nentL = Chv_countEntries(chvJ, npivot, pivotsizes, CHV_STRICT_LOWER); } else { nentL = 0 ; } nentD = Chv_countEntries(chvJ, npivot, pivotsizes, CHV_DIAGONAL) ; nentU = Chv_countEntries(chvJ, npivot, pivotsizes, CHV_STRICT_UPPER) ; maxnent = nentL ; if ( maxnent < nentD ) { maxnent = nentD ; } if ( maxnent < nentU ) { maxnent = nentU ; } if ( CHV_IS_REAL(chvJ) ) { dvec = DVinit(maxnent, 0.0) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { dvec = DVinit(2*maxnent, 0.0) ; } if ( CHV_IS_NONSYMMETRIC(chvJ) ) { /* -------------------------------------- copy the entries in the lower triangle, then move into the chvI object -------------------------------------- */ nent = Chv_copyEntriesToVector(chvJ, npivot, pivotsizes, maxnent, dvec, CHV_STRICT_LOWER, storeflag) ; if ( nent != nentL ) { fprintf(stderr, "\n error: nentL = %d, nent = %d", nentL, nent) ; exit(-1) ; } if ( storeflag == 0 ) { for ( irow = 0, mm = 0 ; irow < nrow ; irow++ ) { jjlast = (irow < nD) ? irow - 1 : nD - 1 ; for ( jj = 0 ; jj <= jjlast ; jj++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jj, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jj, real, imag) ; } } } } else { for ( jcol = 0, mm = 0 ; jcol < nD ; jcol++ ) { for ( irow = jcol + 1 ; irow < nrow ; irow++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; /* fprintf(msgFile, "\n %% mm = %d, a(%d,%d) = %20.12e + %20.12e*i", mm, irow, jcol, real, imag) ; */ Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } /* --------------------------------------- copy the entries in the diagonal matrix then move into the chvI object --------------------------------------- */ nent = Chv_copyEntriesToVector(chvJ, npivot, pivotsizes, maxnent, dvec, CHV_DIAGONAL, storeflag) ; if ( nent != nentD ) { fprintf(stderr, "\n error: nentD = %d, nent = %d", nentD, nent) ; exit(-1) ; } if ( pivotsizes == NULL ) { for ( jcol = 0, mm = 0 ; jcol < nD ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, jcol, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, jcol, jcol, real, imag) ; } } } else { for ( ipivot = irow = mm = 0 ; ipivot < npivot ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow, real, imag) ; } mm++ ; irow++ ; } else { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow, real) ; mm++ ; real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow+1, real) ; mm++ ; real = dvec[mm] ; Chv_setRealEntry(chvI, irow+1, irow+1, real) ; mm++ ; irow += 2 ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow, real, imag) ; mm++ ; real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow+1, real, imag) ; mm++ ; real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow+1, irow+1, real, imag) ; mm++ ; irow += 2 ; } } } } /* -------------------------------------- copy the entries in the upper triangle, then move into the chvI object -------------------------------------- */ nent = Chv_copyEntriesToVector(chvJ, npivot, pivotsizes, maxnent, dvec, CHV_STRICT_UPPER, storeflag) ; if ( nent != nentU ) { fprintf(stderr, "\n error: nentU = %d, nent = %d", nentU, nent) ; exit(-1) ; } if ( storeflag == 1 ) { if ( pivotsizes == NULL ) { for ( jcol = mm = 0 ; jcol < ncol ; jcol++ ) { iilast = (jcol < nD) ? jcol - 1 : nD - 1 ; for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, ii, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, ii, jcol, real, imag) ; } } } } else { for ( ipivot = jcol = mm = 0 ; ipivot < npivot ; ipivot++ ) { iilast = jcol - 1 ; for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, ii, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, ii, jcol, real, imag) ; } } jcol++ ; if ( pivotsizes[ipivot] == 2 ) { for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, ii, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, ii, jcol, real, imag) ; } } jcol++ ; } } for ( jcol = nD ; jcol < ncol ; jcol++ ) { for ( irow = 0 ; irow < nD ; irow++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } else { if ( pivotsizes == NULL ) { for ( irow = mm = 0 ; irow < nD ; irow++ ) { for ( jcol = irow + 1 ; jcol < ncol ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } else { for ( ipivot = irow = mm = 0 ; ipivot < npivot ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { for ( jcol = irow + 1 ; jcol < ncol ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } irow++ ; } else { for ( jcol = irow + 2 ; jcol < ncol ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } for ( jcol = irow + 2 ; jcol < ncol ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow+1, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow+1, jcol, real, imag) ; } } irow += 2 ; } } } } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% chevron b") ; Chv_writeForMatlab(chvI, "b", msgFile) ; fprintf(msgFile, "\n\n emtx1 = abs(a - b) ; enorm1 = max(max(emtx1))") ; fflush(msgFile) ; } DVfree(dvec) ; /* ----------------------------------------------------- second test: copy lower (1,1), lower (2,1), diagonal, upper(1,1) and upper(1,2) blocks ----------------------------------------------------- */ if ( CHV_IS_NONSYMMETRIC(chvJ) ) { nentL11 = Chv_countEntries(chvJ, npivot, pivotsizes, CHV_STRICT_LOWER_11) ; nentL21 = Chv_countEntries(chvJ, npivot, pivotsizes, CHV_LOWER_21) ; } else { nentL11 = 0 ; nentL21 = 0 ; } nentD = Chv_countEntries(chvJ, npivot, pivotsizes, CHV_DIAGONAL) ; nentU11 = Chv_countEntries(chvJ, npivot, pivotsizes, CHV_STRICT_UPPER_11) ; nentU12 = Chv_countEntries(chvJ, npivot, pivotsizes, CHV_UPPER_12) ; maxnent = nentL11 ; if ( maxnent < nentL21 ) { maxnent = nentL21 ; } if ( maxnent < nentD ) { maxnent = nentD ; } if ( maxnent < nentU11 ) { maxnent = nentU11 ; } if ( maxnent < nentU12 ) { maxnent = nentU12 ; } fprintf(msgFile, "\n %% nentL11 = %d, nentL21 = %d" "\n %% nentD = %d, nentU11 = %d, nentU12 = %d", nentL11, nentL21, nentD, nentU11, nentU12) ; if ( CHV_IS_REAL(chvJ) ) { dvec = DVinit(maxnent, 0.0) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { dvec = DVinit(2*maxnent, 0.0) ; } Chv_zero(chvI) ; if ( CHV_IS_NONSYMMETRIC(chvJ) ) { /* ------------------------------------------ copy the entries in the lower (1,1) block, then move into the chvI object ------------------------------------------ */ nent = Chv_copyEntriesToVector(chvJ, npivot, pivotsizes, maxnent, dvec, CHV_STRICT_LOWER_11, storeflag) ; if ( nent != nentL11 ) { fprintf(stderr, "\n error: nentL = %d, nent = %d", nentL, nent) ; exit(-1) ; } if ( storeflag == 0 ) { for ( irow = 0, mm = 0 ; irow < nD ; irow++ ) { jjlast = (irow < nD) ? irow - 1 : nD - 1 ; for ( jj = 0 ; jj <= jjlast ; jj++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jj, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jj, real, imag) ; } } } } else { for ( jcol = 0, mm = 0 ; jcol < nD ; jcol++ ) { for ( irow = jcol + 1 ; irow < nD ; irow++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } /* ------------------------------------------ copy the entries in the lower (2,1) block, then move into the chvI object ------------------------------------------ */ nent = Chv_copyEntriesToVector(chvJ, npivot, pivotsizes, maxnent, dvec, CHV_LOWER_21, storeflag); if ( nent != nentL21 ) { fprintf(stderr, "\n error: nentL21 = %d, nent = %d", nentL21, nent) ; exit(-1) ; } if ( storeflag == 0 ) { for ( irow = nD, mm = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < nD ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } else { for ( jcol = 0, mm = 0 ; jcol < nD ; jcol++ ) { for ( irow = nD ; irow < nrow ; irow++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } } /* --------------------------------------- copy the entries in the diagonal matrix then move into the chvI object --------------------------------------- */ nent = Chv_copyEntriesToVector(chvJ, npivot, pivotsizes, maxnent, dvec, CHV_DIAGONAL, storeflag) ; if ( nent != nentD ) { fprintf(stderr, "\n error: nentD = %d, nent = %d", nentD, nent) ; exit(-1) ; } if ( pivotsizes == NULL ) { for ( jcol = 0, mm = 0 ; jcol < nD ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, jcol, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, jcol, jcol, real, imag) ; } } } else { for ( ipivot = irow = mm = 0 ; ipivot < npivot ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow, real, imag) ; } mm++ ; irow++ ; } else { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow, real) ; mm++ ; real = dvec[mm] ; Chv_setRealEntry(chvI, irow, irow+1, real) ; mm++ ; real = dvec[mm] ; Chv_setRealEntry(chvI, irow+1, irow+1, real) ; mm++ ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow, real, imag) ; mm++ ; real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, irow+1, real, imag) ; mm++ ; real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow+1, irow+1, real, imag) ; mm++ ; } irow += 2 ; } } } /* ----------------------------------------- copy the entries in the upper (1,1) block then move into the chvI object ----------------------------------------- */ nent = Chv_copyEntriesToVector(chvJ, npivot, pivotsizes, maxnent, dvec, CHV_STRICT_UPPER_11, storeflag) ; if ( nent != nentU11 ) { fprintf(stderr, "\n error: nentU11 = %d, nent = %d", nentU11, nent) ; exit(-1) ; } if ( storeflag == 1 ) { if ( pivotsizes == NULL ) { for ( jcol = mm = 0 ; jcol < nD ; jcol++ ) { iilast = (jcol < nD) ? jcol - 1 : nD - 1 ; for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, ii, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, ii, jcol, real, imag) ; } } } } else { for ( ipivot = jcol = mm = 0 ; ipivot < npivot ; ipivot++ ) { iilast = jcol - 1 ; for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, ii, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, ii, jcol, real, imag) ; } } jcol++ ; if ( pivotsizes[ipivot] == 2 ) { for ( ii = 0 ; ii <= iilast ; ii++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, ii, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, ii, jcol, real, imag) ; } } jcol++ ; } } } } else { if ( pivotsizes == NULL ) { for ( irow = mm = 0 ; irow < nD ; irow++ ) { for ( jcol = irow + 1 ; jcol < nD ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } else { for ( ipivot = irow = mm = 0 ; ipivot < npivot ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { for ( jcol = irow + 1 ; jcol < nD ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } irow++ ; } else { for ( jcol = irow + 2 ; jcol < nD ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } for ( jcol = irow + 2 ; jcol < nD ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow+1, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow+1, jcol, real, imag) ; } } irow += 2 ; } } } } /* ----------------------------------------- copy the entries in the upper (1,2) block then move into the chvI object ----------------------------------------- */ nent = Chv_copyEntriesToVector(chvJ, npivot, pivotsizes, maxnent, dvec, CHV_UPPER_12, storeflag) ; if ( nent != nentU12 ) { fprintf(stderr, "\n error: nentU12 = %d, nent = %d", nentU12, nent) ; exit(-1) ; } if ( storeflag == 1 ) { for ( jcol = nD, mm = 0 ; jcol < ncol ; jcol++ ) { for ( irow = 0 ; irow < nD ; irow++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } else { for ( irow = mm = 0 ; irow < nD ; irow++ ) { for ( jcol = nD ; jcol < ncol ; jcol++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv_setRealEntry(chvI, irow, jcol, real) ; } else if ( CHV_IS_COMPLEX(chvJ) ) { real = dvec[2*mm] ; imag = dvec[2*mm+1] ; Chv_setComplexEntry(chvI, irow, jcol, real, imag) ; } } } } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% chevron b") ; Chv_writeForMatlab(chvI, "b", msgFile) ; fprintf(msgFile, "\n\n emtx2 = abs(a - b) ; enorm2 = max(max(emtx2))") ; fprintf(msgFile, "\n\n [ enorm1 enorm2]") ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ if ( pivotsizes != NULL ) { IVfree(pivotsizes) ; } Chv_free(chvJ) ; Chv_free(chvI) ; Drand_free(drand) ; DVfree(dvec) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ for ( irow = 0, mm = 0 ; irow < nD ; irow++ ) { jjlast = (irow < nD) ? irow - 1 : nD - 1 ; for ( jj = 0 ; jj <= jjlast ; jj++, mm++ ) { if ( CHV_IS_REAL(chvJ) ) { real = dvec[mm] ; Chv/drivers/test_factor.c010064400020550007177000000333500657354323400167670ustar00clevecompmath00000400000006/* test_factor.c */ #include "../Chv.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------- test the Chv_factor() method. the program's output is a matlab file to check correctness of the code. created -- 98apr22, cca ------------------------------------- */ { Chv *chv ; double imag, real, tau, t1, t2 ; double *entries ; Drand *drand ; DV *workDV ; FILE *msgFile ; int ii, ipivot, irow, jcol, msglvl, ncol, nD, ndelay, nelim, nent, nL, nrow, npivot, ntest, nU, pivotflag, rc, seed, symflag, tag, type ; int *colind, *pivotsizes, *rowind ; IV *pivotsizesIV ; if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nD nU type symflag pivotflag seed tau " "\n msglvl -- message level" "\n msgFile -- message file" "\n nD -- # of rows and columns in the (1,1) block" "\n nU -- # of columns in the (1,2) block" "\n type -- entries type" "\n 1 --> real" "\n 2 --> complex" "\n symflag -- symmetry flag" "\n 0 --> hermitian" "\n 1 --> symmetric" "\n 2 --> nonsymmetric" "\n pivotflag -- pivoting flag" "\n 0 --> no pivoting" "\n 1 --> pivoting" "\n tau -- bound on magnitude of factor entries" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } nD = atoi(argv[3]) ; nU = atoi(argv[4]) ; type = atoi(argv[5]) ; symflag = atoi(argv[6]) ; pivotflag = atoi(argv[7]) ; seed = atoi(argv[8]) ; tau = atof(argv[9]) ; fprintf(msgFile, "\n %% testChv:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% nD = %d" "\n %% nU = %d" "\n %% type = %d" "\n %% symflag = %d" "\n %% pivotflag = %d" "\n %% seed = %d" "\n %% tau = %f", msglvl, argv[2], nD, nU, type, symflag, pivotflag, seed, tau) ; nL = nU ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nD <= 0 || nL < 0 || nU < 0 || symflag < 0 || symflag > 2 ) { fprintf(stderr, "\n invalid input" "\n nD = %d, nL = %d, nU = %d, symflag = %d\n", nD, nL, nU, symflag) ; exit(-1) ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ---------------------------- initialize the Chv object ---------------------------- */ MARKTIME(t1) ; chv = Chv_new() ; Chv_init(chv, 0, nD, nL, nU, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize chv object", t2 - t1) ; fflush(msgFile) ; Chv_columnIndices(chv, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; if ( CHV_IS_NONSYMMETRIC(chv) ) { Chv_rowIndices(chv, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; } /* ------------------------------------ load the entries with random entries ------------------------------------ */ nent = Chv_nent(chv) ; entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( CHV_IS_COMPLEX(chv) ) { Drand_fillDvector(drand, 2*nent, entries) ; } if ( CHV_IS_HERMITIAN(chv) ) { for ( irow = 0 ; irow < nD ; irow++ ) { Chv_complexEntry(chv, irow, irow, &real, &imag) ; Chv_setComplexEntry(chv, irow, irow, real, 0.0) ; } } fprintf(msgFile, "\n %% matrix entries") ; Chv_writeForMatlab(chv, "A", msgFile) ; if ( pivotflag == 1 ) { pivotsizesIV = IV_new() ; } else { pivotsizesIV = NULL ; } workDV = DV_new() ; /* ----------------- factor the matrix ----------------- */ ndelay = ntest = 0 ; if ( pivotflag == SPOOLES_PIVOTING ) { nelim = Chv_factorWithPivoting(chv, ndelay, pivotflag, pivotsizesIV, workDV, tau, &ntest) ; } else { nelim = Chv_factorWithNoPivoting(chv, NULL) ; } fprintf(msgFile, "\n nD = %d ;\n nelim = %d", nD, nelim) ; /* --------------------- write out the factors --------------------- */ Chv_rowIndices(chv, &nrow, &rowind) ; Chv_columnIndices(chv, &ncol, &colind) ; fprintf(msgFile, "\n\n L = eye(%d,%d); " "\n D = zeros(%d,%d); " "\n T = zeros(%d,%d); " "\n U = eye(%d,%d); ", ncol, ncol, ncol, ncol, ncol, ncol, ncol, ncol) ; if ( pivotflag == 0 ) { if ( CHV_IS_REAL(chv) ) { for ( irow = 0 ; irow < nD ; irow++ ) { Chv_realEntry(chv, irow, irow, &real) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e ;", rowind[irow]+1, colind[irow]+1, real) ; for ( jcol = irow + 1 ; jcol < nD + nU ; jcol++ ) { Chv_realEntry(chv, irow, jcol, &real) ; fprintf(msgFile, "\n U(%d,%d) = %20.12e ;", rowind[irow]+1, colind[jcol]+1, real) ; Chv_realEntry(chv, jcol, irow, &real) ; fprintf(msgFile, "\n L(%d,%d) = %20.12e ;", rowind[jcol]+1, colind[irow]+1, real) ; } } } else if ( CHV_IS_COMPLEX(chv) ) { for ( irow = 0 ; irow < nD ; irow++ ) { Chv_complexEntry(chv, irow, irow, &real, &imag) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow]+1, colind[irow]+1, real, imag) ; for ( jcol = irow + 1 ; jcol < nD + nU ; jcol++ ) { Chv_complexEntry(chv, irow, jcol, &real, &imag) ; fprintf(msgFile, "\n U(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow]+1, colind[jcol]+1, real, imag) ; Chv_complexEntry(chv, jcol, irow, &real, &imag) ; fprintf(msgFile, "\n L(%d,%d) = %20.12e + %20.12e*i ;", rowind[jcol]+1, colind[irow]+1, real, imag) ; } } } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { fprintf(msgFile, "\n colind(%d) = %d;", irow + 1, 1+colind[irow]) ; } if ( CHV_IS_NONSYMMETRIC(chv) ) { for ( irow = 0 ; irow < nrow ; irow++ ) { fprintf(msgFile, "\n rowind(%d) = %d;", irow + 1, 1+rowind[irow]) ; } IV_setSize(pivotsizesIV, nelim) ; IV_fill(pivotsizesIV, 1) ; } else { fprintf(msgFile, "\n rowind = colind ;") ; } fprintf(msgFile, "\n A = A(rowind,colind) ;") ; IVramp(nrow, rowind, 0, 1) ; IVramp(ncol, colind, 0, 1) ; IV_sizeAndEntries(pivotsizesIV, &npivot, &pivotsizes) ; fprintf(msgFile, "\n npivot = %d ;", npivot) ; if ( CHV_IS_REAL(chv) ) { for ( ipivot = irow = 0 ; ipivot < npivot ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { Chv_realEntry(chv, irow, irow, &real) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e ;", rowind[irow]+1, colind[irow]+1, real) ; for ( jcol = irow + 1 ; jcol < nD + nU ; jcol++ ) { Chv_realEntry(chv, irow, jcol, &real) ; fprintf(msgFile, "\n U(%d,%d) = %20.12e ;", rowind[irow]+1, colind[jcol]+1, real) ; Chv_realEntry(chv, jcol, irow, &real) ; fprintf(msgFile, "\n L(%d,%d) = %20.12e ;", rowind[jcol]+1, colind[irow]+1, real) ; } irow += 1 ; } else { Chv_realEntry(chv, irow, irow, &real) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e ;", rowind[irow]+1, colind[irow]+1, real) ; Chv_realEntry(chv, irow, irow+1, &real) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e ;", rowind[irow]+1, colind[irow+1]+1, real) ; Chv_realEntry(chv, irow+1, irow, &real) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e ;", rowind[irow+1]+1, colind[irow]+1, real) ; Chv_realEntry(chv, irow+1, irow+1, &real) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e ;", rowind[irow+1]+1, colind[irow+1]+1, real) ; for ( jcol = irow + 2 ; jcol < nD + nU ; jcol++ ) { Chv_realEntry(chv, irow, jcol, &real) ; fprintf(msgFile, "\n U(%d,%d) = %20.12e ;", rowind[irow]+1, colind[jcol]+1, real) ; Chv_realEntry(chv, jcol, irow, &real) ; fprintf(msgFile, "\n L(%d,%d) = %20.12e ;", rowind[jcol]+1, colind[irow]+1, real) ; Chv_realEntry(chv, irow+1, jcol, &real) ; fprintf(msgFile, "\n U(%d,%d) = %20.12e ;", rowind[irow+1]+1, colind[jcol]+1, real) ; Chv_realEntry(chv, jcol, irow+1, &real) ; fprintf(msgFile, "\n L(%d,%d) = %20.12e ;", rowind[jcol]+1, colind[irow+1]+1, real) ; } irow += 2 ; } } for ( irow = nelim ; irow < nD ; irow++ ) { Chv_realEntry(chv, irow, irow, &real) ; fprintf(msgFile, "\n T(%d,%d) = %20.12e ;", rowind[irow]+1, colind[irow]+1, real) ; for ( jcol = irow + 1 ; jcol < ncol ; jcol++ ) { Chv_realEntry(chv, irow, jcol, &real) ; fprintf(msgFile, "\n T(%d,%d) = %20.12e ;", rowind[irow]+1, colind[jcol]+1, real) ; Chv_realEntry(chv, jcol, irow, &real) ; fprintf(msgFile, "\n T(%d,%d) = %20.12e ;", rowind[jcol]+1, colind[irow]+1, real) ; } } } else if ( CHV_IS_COMPLEX(chv) ) { for ( ipivot = irow = 0 ; ipivot < npivot ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { Chv_complexEntry(chv, irow, irow, &real, &imag) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow]+1, colind[irow]+1, real, imag) ; for ( jcol = irow + 1 ; jcol < nD + nU ; jcol++ ) { Chv_complexEntry(chv, irow, jcol, &real, &imag) ; fprintf(msgFile, "\n U(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow]+1, colind[jcol]+1, real, imag) ; Chv_complexEntry(chv, jcol, irow, &real, &imag) ; fprintf(msgFile, "\n L(%d,%d) = %20.12e + %20.12e*i ;", rowind[jcol]+1, colind[irow]+1, real, imag) ; } irow += 1 ; } else { Chv_complexEntry(chv, irow, irow, &real, &imag) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow]+1, colind[irow]+1, real, imag) ; Chv_complexEntry(chv, irow, irow+1, &real, &imag) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow]+1, colind[irow+1]+1, real, imag) ; Chv_complexEntry(chv, irow+1, irow, &real, &imag) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow+1]+1, colind[irow]+1, real, imag) ; Chv_complexEntry(chv, irow+1, irow+1, &real, &imag) ; fprintf(msgFile, "\n D(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow+1]+1, colind[irow+1]+1, real, imag) ; for ( jcol = irow + 2 ; jcol < nD + nU ; jcol++ ) { Chv_complexEntry(chv, irow, jcol, &real, &imag) ; fprintf(msgFile, "\n U(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow]+1, colind[jcol]+1, real, imag) ; Chv_complexEntry(chv, jcol, irow, &real, &imag) ; fprintf(msgFile, "\n L(%d,%d) = %20.12e + %20.12e*i ;", rowind[jcol]+1, colind[irow]+1, real, imag) ; Chv_complexEntry(chv, irow+1, jcol, &real, &imag) ; fprintf(msgFile, "\n U(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow+1]+1, colind[jcol]+1, real, imag) ; Chv_complexEntry(chv, jcol, irow+1, &real, &imag) ; fprintf(msgFile, "\n L(%d,%d) = %20.12e + %20.12e*i ;", rowind[jcol]+1, colind[irow+1]+1, real, imag) ; } irow += 2 ; } } for ( irow = nelim ; irow < nD ; irow++ ) { Chv_complexEntry(chv, irow, irow, &real, &imag) ; fprintf(msgFile, "\n T(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow]+1, colind[irow]+1, real, imag) ; for ( jcol = irow + 1 ; jcol < ncol ; jcol++ ) { Chv_complexEntry(chv, irow, jcol, &real, &imag) ; fprintf(msgFile, "\n T(%d,%d) = %20.12e + %20.12e*i ;", rowind[irow]+1, colind[jcol]+1, real, imag) ; Chv_complexEntry(chv, jcol, irow, &real, &imag) ; fprintf(msgFile, "\n T(%d,%d) = %20.12e + %20.12e*i ;", rowind[jcol]+1, colind[irow]+1, real, imag) ; } } } } fprintf(msgFile, "\n B = A ;") ; fprintf(msgFile, "\n B = A - T - L(:,1:%d) * D(1:%d,1:%d) * U(1:%d,:) ; ", nelim, nelim, nelim, nelim) ; fprintf(msgFile, "\n B(%d:%d,%d:%d) = 0.0 ; ", nD+1, ncol, nD+1, ncol) ; fprintf(msgFile, "\n maxabsB = max(max(abs(B)))" "\n maxabsL = max(max(abs(L - eye(%d,%d))))" "\n maxabsU = max(max(abs(U - eye(%d,%d))))" "\n [ maxabsB maxabsL maxabsU ]", ncol, ncol, ncol, ncol) ; /* ------------------------ free the working storage ------------------------ */ Chv_free(chv) ; DV_free(workDV) ; if ( pivotsizesIV != NULL ) { IV_free(pivotsizesIV) ; } Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ File, "\n colind(%d) = %d;", irow + 1, 1+colind[irow]) ; } if ( CHV_IS_NONSYMMETRIC(chv) ) { for ( irow = 0 ; irow < nrow ; irow++ ) { fprintf(msgFile, "\n rowind(%d) = %d;", irow + 1, 1+rowind[irow]) ; } IV_setSizChv/drivers/test_findPivot.c010064400020550007177000000224150657126732000174500ustar00clevecompmath00000400000006/* test_findPivot.c */ #include "../Chv.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- test the Chv_findPivot(), swap and update methods. the program's output is a matlab file to check correctness of the code. created -- 98jan24, cca --------------------------------------------------- */ { Chv *chv ; double imag, real, tau, t1, t2 ; double *entries ; Drand *drand ; DV *workDV ; FILE *msgFile ; int icol, ii, ipvt, irow, jcol, jpvt, jrow, msglvl, ncol, nD, ndelay, nent, nL, nrow, ntest, nU, rc, pivotsize, seed, symflag, tag, temp, type ; int *colind, *rowind ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nD nU type symflag seed tau " "\n msglvl -- message level" "\n msgFile -- message file" "\n nD -- # of rows and columns in the (1,1) block" "\n nU -- # of columns in the (1,2) block" "\n type -- entries type" "\n 1 --> real" "\n 2 --> complex" "\n symflag -- symmetry flag" "\n 0 --> symmetric" "\n 1 --> hermitian" "\n 2 --> nonsymmetric" "\n seed -- random number seed" "\n tau -- bound on magnitudes of factor entries" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } nD = atoi(argv[3]) ; nU = atoi(argv[4]) ; type = atoi(argv[5]) ; symflag = atoi(argv[6]) ; seed = atoi(argv[7]) ; tau = atof(argv[8]) ; fprintf(msgFile, "\n %% testChv:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% nD = %d" "\n %% nU = %d" "\n %% type = %d" "\n %% symflag = %d" "\n %% seed = %d" "\n %% tau = %12.4e", msglvl, argv[2], nD, nU, type, symflag, seed, tau) ; nL = nU ; nrow = nD + nL ; ncol = nD + nU ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nD <= 0 || nU < 0 || (symflag != SPOOLES_SYMMETRIC && symflag != SPOOLES_HERMITIAN && symflag != SPOOLES_NONSYMMETRIC) ) { fprintf(stderr, "\n invalid input" "\n nD = %d, nL = %d, nU = %d, symflag = %d\n", nD, nL, nU, symflag) ; exit(-1) ; } if ( (symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN) && nL != nU ) { fprintf(stderr, "\n invalid input" "\n symflag = %d, nL = %d, nU = %d", symflag, nL, nU) ; exit(-1) ; } fprintf(msgFile, "\n nD = %d ;" "\n nL = %d ;" "\n nU = %d ;" "\n nrow = nD + nL ;" "\n ncol = nD + nU ;", nD, nL, nU) ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* -------------------------- initialize the Chv object -------------------------- */ MARKTIME(t1) ; chv = Chv_new() ; Chv_init(chv, 0, nD, nL, nU, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize chv object", t2 - t1) ; fflush(msgFile) ; Chv_columnIndices(chv, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; if ( CHV_IS_NONSYMMETRIC(chv) ) { Chv_rowIndices(chv, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; } /* ------------------------------------ load the entries with random entries ------------------------------------ */ nent = Chv_nent(chv) ; entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( CHV_IS_COMPLEX(chv) ) { Drand_fillDvector(drand, 2*nent, entries) ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n raw entries vector") ; DVfprintf(msgFile, 2*nent, entries) ; fflush(msgFile) ; } if ( CHV_IS_HERMITIAN(chv) ) { /* --------------------------------------------------------- hermitian example, set imaginary part of diagonal to zero --------------------------------------------------------- */ for ( irow = 0 ; irow < nD ; irow++ ) { Chv_complexEntry(chv, irow, irow, &real, &imag) ; Chv_setComplexEntry(chv, irow, irow, real, 0.0) ; } } fprintf(msgFile, "\n %% matrix entries") ; Chv_writeForMatlab(chv, "a", msgFile) ; /* ------------ find a pivot ------------ */ workDV = DV_new() ; ndelay = 0 ; ntest = 0 ; pivotsize = Chv_findPivot(chv, workDV, tau, ndelay, &irow, &jcol, &ntest) ; fprintf(msgFile, "\n\n %% pivotsize = %d", pivotsize) ; ipvt = irow ; jpvt = jcol ; if ( (symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN) && irow > jcol ) { temp = irow ; irow = jcol ; jcol = temp ; } fprintf(msgFile, "\n\n irow = %d ; \n jcol = %d ;", irow+1, jcol+1) ; /* ------------------------- swap the rows and columns ------------------------- */ if ( pivotsize == 0 ) { exit(0) ; } else if ( pivotsize == 1 ) { fprintf(msgFile, "\n b = a ;" "\n xtemp = b(irow,:) ;" "\n b(irow,:) = b(1,:) ;" "\n b(1,:) = xtemp ;" "\n xtemp = b(:,jcol) ;" "\n b(:,jcol) = b(:,1) ;" "\n b(:,1) = xtemp ;") ; if ( CHV_IS_SYMMETRIC(chv) || symflag == CHV_IS_HERMITIAN(chv) ) { Chv_swapRowsAndColumns(chv, 0, irow) ; } else { Chv_swapRows(chv, 0, irow) ; Chv_swapColumns(chv, 0, jcol) ; } } else if ( pivotsize == 2 ) { if ( symflag < 2 ) { fprintf(msgFile, "\n b = a ;" "\n xtemp = b(irow,:) ;" "\n b(irow,:) = b(1,:) ;" "\n b(1,:) = xtemp ;" "\n xtemp = b(:,irow) ;" "\n b(:,irow) = b(:,1) ;" "\n b(:,1) = xtemp ;" "\n xtemp = b(jcol,:) ;" "\n b(jcol,:) = b(2,:) ;" "\n b(2,:) = xtemp ;" "\n xtemp = b(:,jcol) ;" "\n b(:,jcol) = b(:,2) ;" "\n b(:,2) = xtemp ;") ; Chv_swapRowsAndColumns(chv, 0, irow) ; Chv_swapRowsAndColumns(chv, 1, jcol) ; } else { fprintf(stderr, "\n fatal error, symflag = %d, pvtsize = %d", symflag, pivotsize) ; exit(-1) ; } } /* ----------------------------------------- check that the swap was executed properly ----------------------------------------- */ fprintf(msgFile, "\n %% matrix entries") ; Chv_writeForMatlab(chv, "c", msgFile) ; fprintf(msgFile, "\n maxerrswap = norm(c - a)") ; /* --------------------------- ramp the indices once again --------------------------- */ IVramp(ncol, colind, 0, 1) ; if ( CHV_IS_NONSYMMETRIC(chv) ) { Chv_rowIndices(chv, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; } /* ----------------------------------- perform the rank-1 or rank-2 update ----------------------------------- */ fprintf(msgFile, "\n\n ckeep = b ;") ; fprintf(msgFile, "\n\n c = b ;") ; if ( pivotsize == 1 ) { rc = Chv_r1upd(chv) ; fprintf(msgFile, "\n\n d = c(1,1) ;" "\n l = c(2:nrow,1)/d ;" "\n u = c(1,2:ncol) ;") ; if ( nD > 1 ) { fprintf(msgFile, "\n c(2:nrow,2:ncol) = c(2:nrow,2:ncol) - l*u ;") ; } fprintf(msgFile, "\n u = u / d ;" "\n c(1:1,1:1) = d ; " "\n c(1:1,2:ncol) = u ; " "\n c(2:ncol,1:1) = l ; ") ; fprintf(msgFile, "\n c(nD+1:nrow,nD+1:ncol) = 0 ;") ; } else { rc = Chv_r2upd(chv) ; fprintf(msgFile, "\n\n d = c(1:2,1:2) ;" "\n l = c(3:nrow,1:2) / d ;" "\n u = c(1:2,3:ncol) ;") ; if ( nD > 2 ) { fprintf(msgFile, "\n c(3:nrow,3:ncol) = c(3:nrow,3:ncol) - l*u ;") ; } fprintf(msgFile, "\n u = d \\ u ; " "\n c(1:2,1:2) = d ; " "\n c(1:2,3:ncol) = u ; " "\n c(3:ncol,1:2) = l ; ") ; if ( nU > 0 ) { fprintf(msgFile, "\n c(nD+1:nrow,nD+1:ncol) = 0 ;") ; } } fprintf(msgFile, "\n %% matrix entries after update") ; Chv_writeForMatlab(chv, "f", msgFile) ; fprintf(msgFile, "\n maxerrupd = norm(f - c)") ; /* ------------------------------------------------------ check out the maximum magnitude of elements in l and u ------------------------------------------------------ */ fprintf(msgFile, "\n ipvt = %d", ipvt + 1) ; fprintf(msgFile, "\n jpvt = %d", jpvt + 1) ; fprintf(msgFile, "\n pivotsize = %d", pivotsize) ; fprintf(msgFile, "\n tau = %12.4e", tau) ; if ( symflag < 2 ) { fprintf(msgFile, "\n ubound = max(max(abs(u))) ") ; } else { fprintf(msgFile, "\n lbound = max(max(abs(l))) " "\n ubound = max(max(abs(u))) ") ; } /* ------------------------ free the working storage ------------------------ */ Chv_free(chv) ; Drand_free(drand) ; DV_free(workDV) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Chv/drivers/test_maxabs.c010064400020550007177000000172060657126732000167630ustar00clevecompmath00000400000006/* test_maxabs.c */ #include "../Chv.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------------------- test the Chv_maxabsInDiagonal(), Chv_maxabsInRow() and Chv_maxabsInColumn() methods. the program's output is a matlab file to check correctness of the code. created -- 98apr22, cca ---------------------------------------------------- */ { Chv *chv ; double imag, maxval, real, t1, t2 ; double *colmaxes, *entries, *rowmaxes ; Drand *drand ; FILE *msgFile ; int icol, ii, irow, jcol, jrow, msglvl, ncol, nD, nent, nL, nrow, nU, rc, seed, symflag, tag, type ; int *colind, *colmark, *rowind, *rowmark ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nD nU type symflag seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n nD -- # of rows and columns in the (1,1) block" "\n nU -- # of columns in the (1,2) block" "\n type -- entries type" "\n 1 --> real" "\n 2 --> complex" "\n symflag -- symmetry flag" "\n 0 --> symmetric" "\n 1 --> hermitian" "\n 2 --> nonsymmetric " "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } nD = atoi(argv[3]) ; nU = atoi(argv[4]) ; type = atoi(argv[5]) ; symflag = atoi(argv[6]) ; seed = atoi(argv[7]) ; fprintf(msgFile, "\n %% testChv:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% nD = %d" "\n %% nU = %d" "\n %% type = %d" "\n %% symflag = %d" "\n %% seed = %d", msglvl, argv[2], nD, nU, type, symflag, seed) ; nL = nU ; nrow = nD + nL ; ncol = nD + nU ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nD <= 0 || nL < 0 || nU < 0 || symflag < 0 || symflag > 3 ) { fprintf(stderr, "\n invalid input" "\n nD = %d, nL = %d, nU = %d, symflag = %d\n", nD, nL, nU, symflag) ; exit(-1) ; } fprintf(msgFile, "\n nD = %d ;" "\n nL = %d ;" "\n nU = %d ;" "\n nrow = nD + nL ;" "\n ncol = nD + nU ;", nD, nL, nU) ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ---------------------------- initialize the Chv object ---------------------------- */ MARKTIME(t1) ; chv = Chv_new() ; Chv_init(chv, 0, nD, nL, nU, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize chv object", t2 - t1) ; fflush(msgFile) ; Chv_columnIndices(chv, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; if ( CHV_IS_NONSYMMETRIC(chv) ) { Chv_rowIndices(chv, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; } /* ------------------------------------ load the entries with random entries ------------------------------------ */ nent = Chv_nent(chv) ; entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( CHV_IS_COMPLEX(chv) ) { Drand_fillDvector(drand, 2*nent, entries) ; } if ( CHV_IS_HERMITIAN(chv) ) { /* --------------------------------------------------------- hermitian example, set imaginary part of diagonal to zero --------------------------------------------------------- */ for ( irow = 0 ; irow < nD ; irow++ ) { Chv_complexEntry(chv, irow, irow, &real, &imag) ; Chv_setComplexEntry(chv, irow, irow, real, 0.0) ; } } fprintf(msgFile, "\n %% matrix entries") ; Chv_writeForMatlab(chv, "a", msgFile) ; /* ----------------------------- find the row and column maxes ----------------------------- */ rowmaxes = DVinit(nrow, 0.0) ; colmaxes = DVinit(nrow, 0.0) ; for ( irow = 0 ; irow < nD ; irow++ ) { jcol = Chv_maxabsInRow(chv, irow, &maxval) ; rowmaxes[irow] = maxval ; } for ( jcol = 0 ; jcol < nD ; jcol++ ) { irow = Chv_maxabsInColumn(chv, jcol, &maxval) ; colmaxes[jcol] = maxval ; } fprintf(msgFile, "\n\n rowmaxes = [ ...") ; for ( irow = 0 ; irow < nD ; irow++ ) { fprintf(msgFile, "\n %20.12e", rowmaxes[irow]) ; } fprintf(msgFile, " ] ;") ; fprintf(msgFile, "\n\n colmaxes = [ ...") ; for ( jcol = 0 ; jcol < nD ; jcol++ ) { fprintf(msgFile, "\n %20.12e", colmaxes[jcol]) ; } fprintf(msgFile, " ] ;") ; /* ----------------- check with matlab ----------------- */ fprintf(msgFile, "\n\n for irow = 1:nD" "\n maxval = max(abs(a(irow,:))) ;" "\n rmaxes(irow) = maxval ;" "\nend" "\nrowerror = norm(rmaxes' - rowmaxes) " "\nfor jcol = 1:nD" "\n maxval = max(abs(a(:,jcol))) ;" "\n cmaxes(jcol) = maxval ;" "\nend" "\ncolerror = norm(cmaxes' - colmaxes) ") ; /* ----------------------------------------------------- find the row and column maxes of just the (1,1) block ----------------------------------------------------- */ rowmark = IVinit(nD, -1) ; colmark = IVinit(nD, -1) ; tag = -1 ; for ( irow = 0 ; irow < nD ; irow++ ) { jcol = Chv_maxabsInRow11(chv, irow, colmark, tag, &maxval) ; rowmaxes[irow] = maxval ; } for ( jcol = 0 ; jcol < nD ; jcol++ ) { irow = Chv_maxabsInColumn11(chv, jcol, rowmark, tag, &maxval) ; colmaxes[jcol] = maxval ; } fprintf(msgFile, "\n\n rowmaxes = [ ...") ; for ( irow = 0 ; irow < nD ; irow++ ) { fprintf(msgFile, "\n %20.12e", rowmaxes[irow]) ; } fprintf(msgFile, " ] ;") ; fprintf(msgFile, "\n\n colmaxes = [ ...") ; for ( jcol = 0 ; jcol < nD ; jcol++ ) { fprintf(msgFile, "\n %20.12e", colmaxes[jcol]) ; } fprintf(msgFile, " ] ;") ; /* ----------------- check with matlab ----------------- */ fprintf(msgFile, "\n\n for irow = 1:nD" "\n maxval = max(abs(a(irow,1:nD))) ;" "\n rmaxes(irow) = maxval ;" "\nend" "\nrow11error = norm(rmaxes' - rowmaxes) " "\nfor jcol = 1:nD" "\n maxval = max(abs(a(1:nD,jcol))) ;" "\n cmaxes(jcol) = maxval ;" "\nend" "\ncol11error = norm(cmaxes' - colmaxes) ") ; /* --------------------------------------------- find the diagonal max of just the (1,1) block --------------------------------------------- */ jcol = Chv_maxabsInDiagonal11(chv, colmark, tag, &maxval) ; fprintf(msgFile, "\n\n maxval = %20.12e ;", maxval) ; /* ----------------- check with matlab ----------------- */ fprintf(msgFile, "\n\n maxabs = abs(a(1,1)) ;" "\nfor irow = 2:nD" "\n val = abs(a(irow,irow)) ;" "\n if maxabs < val" "\n maxabs = val ;" "\n end " "\nend" "\ndiag11error = abs(maxabs - maxval)") ; fprintf(msgFile, "\n [ rowerror colerror row11error col11error diag11error]") ; /* ------------------------ free the working storage ------------------------ */ Chv_free(chv) ; Drand_free(drand) ; DVfree(rowmaxes) ; DVfree(colmaxes) ; IVfree(rowmark) ; IVfree(colmark) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Chv/drivers/test_r1upd.c010064400020550007177000000121040657126732000165330ustar00clevecompmath00000400000006/* test_r1upd.c */ #include "../Chv.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------- test the Chv_r1upd() method. the program's output is a matlab file to check correctness of the code. created -- 98apr30, cca ------------------------------------- */ { Chv *chv ; double imag, real, t1, t2 ; double *entries ; Drand *drand ; FILE *msgFile ; int ii, irow, jcol, msglvl, ncol, nD, nent, nL, nrow, nU, rc, seed, symflag, tag, type ; int *colind, *rowind ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nD nU type symflag seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n nD -- # of rows and columns in the (1,1) block" "\n nU -- # of columns in the (1,2) block" "\n type -- entries type" "\n 1 --> real" "\n 2 --> complex" "\n symflag -- symmetry flag" "\n 0 --> hermitian" "\n 1 --> symmetric" "\n 2 --> nonsymmetric " "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } nD = atoi(argv[3]) ; nU = atoi(argv[4]) ; type = atoi(argv[5]) ; symflag = atoi(argv[6]) ; seed = atoi(argv[7]) ; fprintf(msgFile, "\n %% testChv:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% nD = %d" "\n %% nU = %d" "\n %% type = %d" "\n %% symflag = %d" "\n %% seed = %d", msglvl, argv[2], nD, nU, type, symflag, seed) ; nL = nU ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nD <= 0 || nL < 0 || nU < 0 || symflag < 0 || symflag > 3 ) { fprintf(stderr, "\n invalid input" "\n nD = %d, nL = %d, nU = %d, symflag = %d\n", nD, nL, nU, symflag) ; exit(-1) ; } if ( symflag <= 2 && nL != nU ) { fprintf(stderr, "\n invalid input" "\n symflag = %d, nL = %d, nU = %d", symflag, nL, nU) ; exit(-1) ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ---------------------------- initialize the Chv object ---------------------------- */ MARKTIME(t1) ; chv = Chv_new() ; Chv_init(chv, 0, nD, nL, nU, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize chv object", t2 - t1) ; fflush(msgFile) ; Chv_columnIndices(chv, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; if ( CHV_IS_NONSYMMETRIC(chv) ) { Chv_rowIndices(chv, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; } /* ------------------------------------ load the entries with random entries ------------------------------------ */ nent = Chv_nent(chv) ; entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( CHV_IS_COMPLEX(chv) ) { Drand_fillDvector(drand, 2*nent, entries) ; } if ( CHV_IS_HERMITIAN(chv) ) { for ( irow = 0 ; irow < nD ; irow++ ) { Chv_complexEntry(chv, irow, irow, &real, &imag) ; Chv_setComplexEntry(chv, irow, irow, real, 0.0) ; } } fprintf(msgFile, "\n %% matrix entries") ; Chv_writeForMatlab(chv, "a", msgFile) ; /* --------------------------------------- write out matlab code for rank-1 update --------------------------------------- */ fprintf(msgFile, "\n nD = %d ;" "\n nL = %d ;" "\n nU = %d ;" "\n nrow = nD + nL ;" "\n ncol = nD + nU ;" "\n b = a ; " "\n d = a(1,1) ;" "\n l = a(2:nrow,1) / d ; " "\n u = a(1,2:ncol) ; " "\n b(2:nrow,2:ncol) = a(2:nrow,2:ncol) - l * u ; " "\n u = u / d ; " "\n b(1,1) = d ; " "\n b(1,2:ncol) = u ; " "\n b(2:nrow,1) = l ; ", nD, nL, nU) ; if ( nL > 0 && nU > 0 ) { fprintf(msgFile, "\n b(nD+1:nrow,nD+1:ncol) = 0.0 ;") ; } /* ------------------------- perform the rank-1 update ------------------------- */ rc = Chv_r1upd(chv) ; /* fprintf(msgFile, "\n raw entries vector") ; DVfprintf(msgFile, 2*nent, entries) ; */ fprintf(msgFile, "\n %% matrix entries after update") ; Chv_writeForMatlab(chv, "c", msgFile) ; fprintf(msgFile, "\n maxerr = max(max(abs(c-b)))") ; /* ------------------------ free the working storage ------------------------ */ Chv_free(chv) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ nt, nL, nrow, nU, rc, seed, symflag, tag, type ; int *colind, *rowind ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nD nU type symflag seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n nD -- # of rows and columns in the (1,1) block" "\n nU -- # of columns in the (1,2) block" "\n type --Chv/drivers/test_r2upd.c010064400020550007177000000122240657126732000165370ustar00clevecompmath00000400000006/* test_r2upd.c */ #include "../Chv.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------- test the Chv_r2upd() method. the program's output is a matlab file to check correctness of the code. created -- 98jan23, cca ------------------------------------- */ { Chv *chv ; double imag, real, t1, t2 ; double *entries ; Drand *drand ; FILE *msgFile ; int ii, irow, jcol, msglvl, ncol, nD, nent, nL, nrow, nU, rc, seed, symflag, tag, type ; int *colind, *rowind ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nD nU symflag seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n nD -- # of rows and columns in the (1,1) block" "\n nU -- # of columns in the (1,2) block" "\n type -- entries type" "\n 1 --> real" "\n 2 --> complex" "\n symflag -- symmetry flag" "\n 0 --> hermitian" "\n 1 --> symmetric" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } nD = atoi(argv[3]) ; nU = atoi(argv[4]) ; type = atoi(argv[5]) ; symflag = atoi(argv[6]) ; seed = atoi(argv[7]) ; fprintf(msgFile, "\n %% testChv:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% nD = %d" "\n %% nU = %d" "\n %% type = %d" "\n %% symflag = %d" "\n %% seed = %d", msglvl, argv[2], nD, nU, type, symflag, seed) ; nL = nU ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nD <= 0 || nL < 0 || nU < 0 || (symflag != SPOOLES_SYMMETRIC && symflag != SPOOLES_HERMITIAN) ) { fprintf(stderr, "\n invalid input" "\n nD = %d, nL = %d, nU = %d, symflag = %d\n", nD, nL, nU, symflag) ; exit(-1) ; } if ( symflag <= 2 && nL != nU ) { fprintf(stderr, "\n invalid input" "\n symflag = %d, nL = %d, nU = %d", symflag, nL, nU) ; exit(-1) ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ---------------------------- initialize the Chv object ---------------------------- */ MARKTIME(t1) ; chv = Chv_new() ; Chv_init(chv, 0, nD, nL, nU, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize chv object", t2 - t1) ; fflush(msgFile) ; Chv_columnIndices(chv, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; if ( CHV_IS_NONSYMMETRIC(chv) ) { Chv_rowIndices(chv, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; } /* ------------------------------------ load the entries with random entries ------------------------------------ */ nent = Chv_nent(chv) ; entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( CHV_IS_COMPLEX(chv) ) { Drand_fillDvector(drand, 2*nent, entries) ; } /* fprintf(msgFile, "\n raw entries vector") ; DVfprintf(msgFile, 2*nent, entries) ; */ if ( CHV_IS_HERMITIAN(chv) ) { for ( irow = 0 ; irow < nD ; irow++ ) { Chv_complexEntry(chv, irow, irow, &real, &imag) ; Chv_setComplexEntry(chv, irow, irow, real, 0.0) ; } } fprintf(msgFile, "\n %% matrix entries") ; Chv_writeForMatlab(chv, "a", msgFile) ; /* --------------------------------------- write out matlab code for rank-2 update --------------------------------------- */ fprintf(msgFile, "\n nD = %d ;" "\n nL = %d ;" "\n nU = %d ;" "\n nrow = nD + nL ;" "\n ncol = nD + nU ;" "\n b = a ; " "\n d = a(1:2,1:2) ;" "\n l = a(3:nrow,1:2) * inv(d) ; " "\n u = inv(d)*a(1:2,3:ncol) ; " "\n b(3:nrow,3:ncol) = a(3:nrow,3:ncol) - l * d * u ; " "\n b(1:2,1:2) = d ; " "\n b(1:2,3:ncol) = u ; " "\n b(3:nrow,1:2) = l ; ", nD, nL, nU) ; if ( nL > 0 && nU > 0 ) { fprintf(msgFile, "\n b(nD+1:nrow,nD+1:ncol) = 0.0 ;") ; } /* ------------------------- perform the rank-2 update ------------------------- */ rc = Chv_r2upd(chv) ; /* fprintf(msgFile, "\n raw entries vector") ; DVfprintf(msgFile, 2*nent, entries) ; */ fprintf(msgFile, "\n %% matrix entries after update") ; Chv_writeForMatlab(chv, "c", msgFile) ; fprintf(msgFile, "\n maxerr = max(max(abs(c-b)))") ; /* ------------------------ free the working storage ------------------------ */ Chv_free(chv) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Chv/drivers/test_swap.c010064400020550007177000000201670657126731700164700ustar00clevecompmath00000400000006/* test_swap.c */ #include "../Chv.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------ test the Chv_swapRows(), Chv_swapColumns() and Chv_swapRowsAndColumns() methods. the program's output is a matlab file to check correctness of the code. created -- 98apr18, cca ------------------------------------------------ */ { Chv *chv ; double imag, real, t1, t2 ; double *entries ; Drand *drand ; FILE *msgFile ; int icol, ii, irow, jcol, jrow, msglvl, ncol, nD, nent, nL, nrow, nU, rc, seed, symflag, tag, type ; int *colind, *rowind ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nD nU type symflag seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n nD -- # of rows and columns in the (1,1) block" "\n nU -- # of columns in the (1,2) block" "\n type -- entries type" "\n 1 --> real" "\n 2 --> complex" "\n symflag -- symmetry flag" "\n 0 --> symmetric" "\n 1 --> hermitian" "\n 2 --> nonsymmetric" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } nD = atoi(argv[3]) ; nU = atoi(argv[4]) ; type = atoi(argv[5]) ; symflag = atoi(argv[6]) ; seed = atoi(argv[7]) ; fprintf(msgFile, "\n %% testChv:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% nD = %d" "\n %% nU = %d" "\n %% type = %d" "\n %% symflag = %d" "\n %% seed = %d", msglvl, argv[2], nD, nU, type, symflag, seed) ; nL = nU ; nrow = nD + nL ; ncol = nD + nU ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nD <= 0 || nL < 0 || nU < 0 || !(type == SPOOLES_REAL || type == SPOOLES_COMPLEX) || !(symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN || symflag == SPOOLES_NONSYMMETRIC) ) { fprintf(stderr, "\n invalid input" "\n nD = %d, nL = %d, nU = %d, type = %d, symflag = %d\n", nD, nL, nU, type, symflag) ; exit(-1) ; } fprintf(msgFile, "\n nD = %d ;" "\n nL = %d ;" "\n nU = %d ;" "\n nrow = nD + nL ;" "\n ncol = nD + nU ;", nD, nL, nU) ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* -------------------------- initialize the Chv object -------------------------- */ MARKTIME(t1) ; chv = Chv_new() ; Chv_init(chv, 0, nD, nL, nU, type, symflag) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize chv object", t2 - t1) ; fflush(msgFile) ; Chv_columnIndices(chv, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; if ( CHV_IS_NONSYMMETRIC(chv) ) { Chv_rowIndices(chv, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; } /* ------------------------------------ load the entries with random entries ------------------------------------ */ nent = Chv_nent(chv) ; entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( CHV_IS_COMPLEX(chv) ) { Drand_fillDvector(drand, 2*nent, entries) ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n raw entries vector") ; if ( CHV_IS_REAL(chv) ) { DVfprintf(msgFile, nent, entries) ; } else if ( CHV_IS_COMPLEX(chv) ) { DVfprintf(msgFile, 2*nent, entries) ; } fflush(msgFile) ; } if ( CHV_IS_COMPLEX(chv) && CHV_IS_HERMITIAN(chv) ) { /* --------------------------------------------------------- hermitian example, set imaginary part of diagonal to zero --------------------------------------------------------- */ for ( irow = 0 ; irow < nD ; irow++ ) { Chv_complexEntry(chv, irow, irow, &real, &imag) ; fprintf(msgFile, "\n %% setting a_{%d,%d} = %20.12e ;", irow, irow, real) ; Chv_setComplexEntry(chv, irow, irow, real, 0.0) ; } } fprintf(msgFile, "\n %% matrix entries") ; Chv_writeForMatlab(chv, "a", msgFile) ; if ( CHV_IS_NONSYMMETRIC(chv) ) { /* --------------------------- choose the two rows to swap --------------------------- */ Drand_setUniform(drand, 0.0, nD) ; irow = Drand_value(drand) ; jrow = Drand_value(drand) ; while ( jrow == irow ) { jrow = Drand_value(drand) ; } if ( irow < 0 || irow >= nD || jrow < 0 || jrow >= nD ) { fprintf(stderr, "\n fatal error, irow = %d, jrow = %d\n", irow, jrow) ; exit(-1) ; } fprintf(msgFile, "\n %% swapping rows %d and %d", irow+1, jrow+1) ; fprintf(msgFile, "\n irow = %d ;" "\n jrow = %d ;" "\n b = a ;" "\n b(irow,:) = a(jrow,:) ;" "\n b(jrow,:) = a(irow,:) ;", irow+1, jrow+1) ; fflush(msgFile) ; Chv_swapRows(chv, irow, jrow) ; fprintf(msgFile, "\n %% matrix entries") ; Chv_writeForMatlab(chv, "c", msgFile) ; fprintf(msgFile, "\n maxerrrowswap1 = norm(c - a)") ; /* ------------------------------ choose the two columns to swap ------------------------------ */ Drand_setUniform(drand, 0.0, nD) ; icol = Drand_value(drand) ; jcol = Drand_value(drand) ; while ( jcol == icol ) { jcol = Drand_value(drand) ; } if ( icol < 0 || icol >= nD || jcol < 0 || jcol >= nD ) { fprintf(stderr, "\n fatal error, icol = %d, jcol = %d\n", icol, jrow) ; exit(-1) ; } fprintf(msgFile, "\n %% swapping columns %d and %d", icol+1, jcol+1) ; fprintf(msgFile, "\n icol = %d ;" "\n jcol = %d ;" "\n c = b ;" "\n c(:,icol) = b(:,jcol) ;" "\n c(:,jcol) = b(:,icol) ;", icol+1, jcol+1) ; fflush(msgFile) ; Chv_swapColumns(chv, icol, jcol) ; fprintf(msgFile, "\n %% matrix entries") ; Chv_writeForMatlab(chv, "d", msgFile) ; fprintf(msgFile, "\n maxerrcolswap1 = norm(d - a)") ; IVramp(ncol, colind, 0, 1) ; IVramp(nrow, rowind, 0, 1) ; Chv_writeForMatlab(chv, "e", msgFile) ; fprintf(msgFile, "\n maxerrswap = norm(e - c)") ; } else { /* --------------------------------------- choose the two rows and columns to swap --------------------------------------- */ Drand_setUniform(drand, 0.0, nD) ; irow = Drand_value(drand) ; jrow = Drand_value(drand) ; while ( jrow == irow ) { jrow = Drand_value(drand) ; } if ( irow < 0 || irow >= nD || jrow < 0 || jrow >= nD ) { fprintf(stderr, "\n fatal error, irow = %d, jrow = %d\n", irow, jrow) ; exit(-1) ; } fprintf(msgFile, "\n %% swapping rows and columns %d and %d", irow+1, jrow+1) ; fprintf(msgFile, "\n irow = %d ;" "\n jrow = %d ;" "\n b = a ;" "\n b(irow,:) = a(jrow,:) ;" "\n b(jrow,:) = a(irow,:) ;" "\n c = b ;" "\n c(:,irow) = b(:,jrow) ;" "\n c(:,jrow) = b(:,irow) ;", irow+1, jrow+1) ; fflush(msgFile) ; Chv_swapRowsAndColumns(chv, irow, jrow) ; fprintf(msgFile, "\n %% matrix entries") ; Chv_writeForMatlab(chv, "d", msgFile) ; fprintf(msgFile, "\n maxerrsymswap1 = norm(d - a)") ; IVramp(ncol, colind, 0, 1) ; Chv_writeForMatlab(chv, "e", msgFile) ; fprintf(msgFile, "\n maxerrsymswap2 = norm(e - c)") ; } /* ------------------------ free the working storage ------------------------ */ Chv_free(chv) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Chv/drivers/test_update.c010064400020550007177000000250700657126731700167760ustar00clevecompmath00000400000006/* test_factorupd.c */ #include "../Chv.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------- test the Chv_update{H,S,N}() methods. T := T - U^T * D * U T := T - U^H * D * U T := T - L * D * U created -- 98apr23, cca ------------------------------------- */ { Chv *chvT ; SubMtx *mtxD, *mtxL, *mtxU ; double imag, ops, real, t1, t2 ; Drand *drand ; DV *tempDV ; FILE *msgFile ; int irow, msglvl, ncolT, nDT, ncolU, nentT, nentU, nrowD, nrowL, nrowT, offset, seed, size, sparsityflag, symflag, type ; int *colindT, *colindU, *ivec, *rowindL, *rowindT ; if ( argc != 13 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type symflag sparsityflag" "\n ncolT ncolU nrowD nentU offset seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- entries type" "\n 1 -- real" "\n 2 -- complex" "\n symflag -- type of matrix U" "\n 0 -- symmetric" "\n 1 -- hermitian" "\n 2 -- nonsymmetric" "\n sparsityflag -- dense or sparse" "\n 0 -- dense" "\n 1 -- sparse" "\n ncolT -- # of rows and columns in matrix T" "\n nDT -- # of internal rows and columns in matrix T" "\n ncolU -- # of rows and columns in matrix U" "\n nrowD -- # of rows and columns in matrix D" "\n nentU -- # of entries in matrix U" "\n offset -- distance between D_I and T" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; symflag = atoi(argv[4]) ; sparsityflag = atoi(argv[5]) ; ncolT = atoi(argv[6]) ; nDT = atoi(argv[7]) ; ncolU = atoi(argv[8]) ; nrowD = atoi(argv[9]) ; nentU = atoi(argv[10]) ; offset = atoi(argv[11]) ; seed = atoi(argv[12]) ; fprintf(msgFile, "\n %% %s:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% symflag = %d" "\n %% sparsityflag = %d" "\n %% ncolT = %d" "\n %% nDT = %d" "\n %% ncolU = %d" "\n %% nrowD = %d" "\n %% nentU = %d" "\n %% offset = %d" "\n %% seed = %d", argv[0], msglvl, argv[2], type, symflag, sparsityflag, ncolT, nDT, ncolU, nrowD, nentU, offset, seed) ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( (type != SPOOLES_REAL && type != SPOOLES_COMPLEX) || (symflag != SPOOLES_SYMMETRIC && symflag != SPOOLES_HERMITIAN && symflag != SPOOLES_NONSYMMETRIC) || (sparsityflag < 0 || sparsityflag > 1) || ncolT <= 0 || ncolU > (ncolT + offset) || nrowD <= 0 ) { fprintf(stderr, "\n invalid input\n") ; exit(-1) ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, ++seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ----------------------- get a vector of indices ----------------------- */ size = nrowD + offset + ncolT ; ivec = IVinit(size, -1) ; IVramp(size, ivec, 0, 1) ; /* ---------------------------- initialize the T Chv object ---------------------------- */ fprintf(msgFile, "\n\n %% symflag = %d", symflag) ; MARKTIME(t1) ; chvT = Chv_new() ; Chv_init(chvT, 0, nDT, ncolT - nDT, ncolT - nDT, type, symflag) ; nentT = Chv_nent(chvT) ; if ( CHV_IS_REAL(chvT) ) { Drand_fillDvector(drand, nentT, Chv_entries(chvT)) ; } else if ( CHV_IS_COMPLEX(chvT) ) { Drand_fillDvector(drand, 2*nentT, Chv_entries(chvT)) ; } Chv_columnIndices(chvT, &ncolT, &colindT) ; IVcopy(ncolT, colindT, ivec + nrowD + offset) ; if ( CHV_IS_NONSYMMETRIC(chvT) ) { Chv_rowIndices(chvT, &nrowT, &rowindT) ; IVcopy(nrowT, rowindT, colindT) ; } IVfree(ivec) ; if ( CHV_IS_HERMITIAN(chvT) ) { fprintf(msgFile, "\n\n %% hermitian\n") ; /* --------------------------------------------------------- hermitian example, set imaginary part of diagonal to zero --------------------------------------------------------- */ for ( irow = 0 ; irow < nDT ; irow++ ) { Chv_complexEntry(chvT, irow, irow, &real, &imag) ; Chv_setComplexEntry(chvT, irow, irow, real, 0.0) ; } } MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize chvT Chv object", t2 - t1) ; fprintf(msgFile, "\n T = zeros(%d,%d); ", size, size) ; Chv_writeForMatlab(chvT, "T", msgFile) ; /* --------------------------- initialize the D Mtx object --------------------------- */ MARKTIME(t1) ; mtxD = SubMtx_new() ; if ( CHV_IS_REAL(chvT) ) { if ( CHV_IS_SYMMETRIC(chvT) ) { SubMtx_initRandom(mtxD, SPOOLES_REAL, SUBMTX_BLOCK_DIAGONAL_SYM, 0, 0, nrowD, nrowD, nrowD*nrowD, ++seed) ; } else { SubMtx_initRandom(mtxD, SPOOLES_REAL, SUBMTX_DIAGONAL, 0, 0, nrowD, nrowD, nrowD*nrowD, ++seed) ; } } else if ( CHV_IS_COMPLEX(chvT) ) { if ( CHV_IS_HERMITIAN(chvT) ) { SubMtx_initRandom(mtxD,SPOOLES_COMPLEX,SUBMTX_BLOCK_DIAGONAL_HERM, 0, 0, nrowD, nrowD, nrowD*nrowD, ++seed) ; } else if ( CHV_IS_SYMMETRIC(chvT) ) { SubMtx_initRandom(mtxD,SPOOLES_COMPLEX, SUBMTX_BLOCK_DIAGONAL_SYM, 0, 0, nrowD, nrowD, nrowD*nrowD, ++seed) ; } else { SubMtx_initRandom(mtxD, SPOOLES_COMPLEX, SUBMTX_DIAGONAL, 0, 0, nrowD, nrowD, nrowD*nrowD, ++seed) ; } } MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize D SubMtx object", t2 - t1) ; fprintf(msgFile, "\n D = zeros(%d,%d) ;", nrowD, nrowD) ; SubMtx_writeForMatlab(mtxD, "D", msgFile) ; /* ---------------------------- initialize the U SubMtx object ---------------------------- */ MARKTIME(t1) ; mtxU = SubMtx_new() ; if ( CHV_IS_REAL(chvT) ) { if ( sparsityflag == 0 ) { SubMtx_initRandom(mtxU, SPOOLES_REAL, SUBMTX_DENSE_COLUMNS, 0, 0, nrowD, ncolU, nentU, ++seed) ; } else { SubMtx_initRandom(mtxU, SPOOLES_REAL, SUBMTX_SPARSE_COLUMNS, 0, 0, nrowD, ncolU, nentU, ++seed) ; } } else if ( CHV_IS_COMPLEX(chvT) ) { if ( sparsityflag == 0 ) { SubMtx_initRandom(mtxU, SPOOLES_COMPLEX, SUBMTX_DENSE_COLUMNS, 0, 0, nrowD, ncolU, nentU, ++seed) ; } else { SubMtx_initRandom(mtxU, SPOOLES_COMPLEX, SUBMTX_SPARSE_COLUMNS, 0, 0, nrowD, ncolU, nentU, ++seed) ; } } ivec = IVinit(offset + ncolT, -1) ; IVramp(offset + ncolT, ivec, nrowD, 1) ; IVshuffle(offset + ncolT, ivec, ++seed) ; SubMtx_columnIndices(mtxU, &ncolU, &colindU) ; IVcopy(ncolU, colindU, ivec) ; IVqsortUp(ncolU, colindU) ; IVfree(ivec) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize U SubMtx object", t2 - t1) ; fprintf(msgFile, "\n U = zeros(%d,%d) ;", nrowD, size) ; SubMtx_writeForMatlab(mtxU, "U", msgFile) ; if ( CHV_IS_NONSYMMETRIC(chvT) ) { /* ---------------------------- initialize the L SubMtx object ---------------------------- */ MARKTIME(t1) ; mtxL = SubMtx_new() ; if ( CHV_IS_REAL(chvT) ) { if ( sparsityflag == 0 ) { SubMtx_initRandom(mtxL, SPOOLES_REAL, SUBMTX_DENSE_ROWS, 0, 0, ncolU, nrowD, nentU, ++seed) ; } else { SubMtx_initRandom(mtxL, SPOOLES_REAL, SUBMTX_SPARSE_ROWS, 0, 0, ncolU, nrowD, nentU, ++seed) ; } } else if ( CHV_IS_COMPLEX(chvT) ) { if ( sparsityflag == 0 ) { SubMtx_initRandom(mtxL, SPOOLES_COMPLEX, SUBMTX_DENSE_ROWS, 0, 0, ncolU, nrowD, nentU, ++seed) ; } else { SubMtx_initRandom(mtxL, SPOOLES_COMPLEX, SUBMTX_SPARSE_ROWS, 0, 0, ncolU, nrowD, nentU, ++seed) ; } } SubMtx_rowIndices(mtxL, &nrowL, &rowindL) ; IVcopy(nrowL, rowindL, colindU) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize L SubMtx object", t2 - t1) ; fprintf(msgFile, "\n L = zeros(%d,%d) ;", size, nrowD) ; SubMtx_writeForMatlab(mtxL, "L", msgFile) ; } else { mtxL = NULL ; } /* -------------------------------- compute the matrix-matrix update -------------------------------- */ tempDV = DV_new() ; ops = 8*nrowD*nrowD*ncolU ; if ( CHV_IS_SYMMETRIC(chvT) ) { Chv_updateS(chvT, mtxD, mtxU, tempDV) ; } else if ( CHV_IS_HERMITIAN(chvT) ) { Chv_updateH(chvT, mtxD, mtxU, tempDV) ; } else if ( CHV_IS_NONSYMMETRIC(chvT) ) { Chv_updateN(chvT, mtxL, mtxD, mtxU, tempDV) ; } MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to compute m-m, %.3f mflops", t2 - t1, ops*1.e-6/(t2 - t1)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Z Chv object") ; fprintf(msgFile, "\n Z = zeros(%d,%d); ", size, size) ; Chv_writeForMatlab(chvT, "Z", msgFile) ; fflush(msgFile) ; } /* ----------------- check with matlab ----------------- */ if ( msglvl > 1 ) { if ( CHV_IS_HERMITIAN(chvT) ) { fprintf(msgFile, "\n\n B = ctranspose(U) * D * U ;") ; } else if ( CHV_IS_SYMMETRIC(chvT) ) { fprintf(msgFile, "\n\n B = transpose(U) * D * U ;") ; } else { fprintf(msgFile, "\n\n B = L * D * U ;") ; } fprintf(msgFile, "\n\n for irow = 1:%d" "\n for jcol = 1:%d" "\n if T(irow,jcol) ~= 0.0" "\n T(irow,jcol) = T(irow,jcol) - B(irow,jcol) ;" "\n end" "\n end" "\n end" "\n emtx = abs(Z - T) ;", size, size) ; fprintf(msgFile, "\n\n maxabs = max(max(emtx)) ") ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ if ( mtxL != NULL ) { SubMtx_free(mtxL) ; } Chv_free(chvT) ; SubMtx_free(mtxD) ; SubMtx_free(mtxU) ; DV_free(tempDV) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Chv/doc/004275500020550007177000000000000665023214400133655ustar00clevecompmath00000400000006Chv/doc/DChv.eps010064400020550007177000000031430657126731500147300ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 500.0 440.0 %%%EndComments /nD 10 def /nL 12 def /nU 15 def /margin 0 def /xscale 500 margin 2 mul sub nD nL add div def /yscale 500 margin 2 mul sub nD nU add div def xscale yscale le { % true action -- if else /yscale xscale def } { % false action -- if else /xscale yscale def } ifelse (xscale) == xscale == (yscale) == yscale == margin margin 500 margin 2 mul sub 440 margin 2 mul sub rectstroke gsave % % translate, scale and rotate % margin margin translate xscale yscale scale 0.05 setlinewidth 0 nD nL add translate -90 rotate % % draw the outlines of the three DA2 objects % 0.0 setgray 0 0 nD nD rectstroke nD 0 nL nD rectstroke 0 nD nD nU rectstroke % % draw the thick edges % 0 1 nD 1 sub { /ix exch def newpath ix 0.5 add ix 0.5 add moveto 0 nD nU add ix sub 1 sub rlineto ix 0.5 add ix 0.5 add moveto nD nL add ix sub 1 sub 0 rlineto stroke } for % % draw the circles that represent entries % /r 0.2 def /x 0.5 def 0 1 nD 1 sub { /y 0.5 def 0 1 nD nU add 1 sub { newpath 1.0 setgray pop x r add y moveto x y r 0 360 arc fill newpath 0.0 setgray x r add y moveto x y r 0 360 arc stroke /y y 1 add def } for /x x 1 add def } for /x nD 0.5 add def 0 1 nL 1 sub { /y 0.5 def 0 1 nD 1 sub { pop newpath 1.0 setgray x r add y moveto x y r 0 360 arc fill newpath 0.0 setgray x r add y moveto x y r 0 360 arc stroke /y y 1 add def } for /x x 1 add def } for stroke grestore showpage U 15 def /margin 0 def /xscale 500 margin 2 mul sub nD nL add div def /yscale 500 margin 2 mul sub nD nU add div def xscale yscale le { % true action -- if else /yscale xscale def } { % false action -- if else /xscale yscale def } ifelse (xscale) == xscale == (yscale) == yscale == margin margin 500 margin 2 mul sub 440 margin 2 mul sub rectstroke gsave % % translate, scale and rotate % margin marginChv/doc/DChvsym.eps010064400020550007177000000032030657126731500154560ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 500.0 200.0 %%%EndComments /nD 10 def /nL 12 def /nL 0 def /nU 15 def /margin 0 def /xscale 500 margin 2 mul sub nD nL add div def /yscale 500 margin 2 mul sub nD nU add div def xscale yscale le { % true action -- if else /yscale xscale def } { % false action -- if else /xscale yscale def } ifelse (xscale) == xscale == (yscale) == yscale == margin margin 500 200 rectstroke gsave % % translate, scale and rotate % margin margin translate xscale yscale scale 0.05 setlinewidth 0 nD nL add translate -90 rotate % % draw the outlines of the three DA2 objects % 0.0 setgray 0 0 nD nD rectstroke % nD 0 nL nD rectstroke 0 nD nD nU rectstroke % % draw the thick edges % 0 1 nD 1 sub { /ix exch def newpath ix 0.5 add ix 0.5 add moveto 0 nD nU add ix sub 1 sub rlineto % ix 0.5 add ix 0.5 add moveto % nD nL add ix sub 1 sub 0 rlineto stroke } for % % draw the circles that represent entries % /r 0.2 def /x 0.5 def 0 1 nD 1 sub { /ix exch def /y x def 0 1 nD nU ix sub add 1 sub { newpath 1.0 setgray pop x r add y moveto x y r 0 360 arc fill newpath 0.0 setgray x r add y moveto x y r 0 360 arc stroke /y y 1 add def } for /x x 1 add def } for % /x nD 0.5 add def % 0 1 nL 1 sub { % /y 0.5 def % 0 1 nD 1 sub { % pop % newpath % 1.0 setgray % x r add y moveto x y r 0 360 arc % fill % newpath % 0.0 setgray % x r add y moveto x y r 0 360 arc % stroke % /y y 1 add def % } for % /x x 1 add def % } for stroke grestore showpage Chv/doc/dataStructure.tex010064400020550007177000000036520657126731500167540ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:Chv:dataStructure} \par \par The {\tt Chv} structure has the following fields. \begin{itemize} \item {\tt int id} : object's id, default value is {\tt -1}. \item {\tt int nD} : number of rows and columns in the (1,1) block \item {\tt int nL} : number of rows in the (2,1) block \item {\tt int nU} : number of columns in the (1,2) block \item {\tt int type} : type of entries \begin{itemize} \item {\tt SPOOLES\_REAL} $\Longrightarrow$ real entries \item {\tt SPOOLES\_COMPLEX} $\Longrightarrow$ complex entries \end{itemize} \item {\tt int symflag} : symmetry flag \begin{itemize} \item {\tt SPOOLES\_SYMMETRIC} $\Longrightarrow$ symmetric entries \item {\tt SPOOLES\_HERMITIAN} $\Longrightarrow$ Hermitian entries \item {\tt SPOOLES\_NONSYMMETRIC} $\Longrightarrow$ nonsymmetric entries \end{itemize} \item {\tt int *rowind} : pointer to the base address of the {\tt int} vector that contains row indices. \item {\tt int *colind} : pointer to the base address of the {\tt int} vector that contains column indices. \item {\tt double *entries} : pointer to the base address of the {\tt double} vector that contains the entries. \item {\tt DV wrkDV} : object that manages the owned working storage. \item {\tt Chv *next} : link to a next object in a singly linked list. \end{itemize} \par One can query the type and symmetry of the object using these simple macros. \begin{itemize} \item {\tt CHV\_IS\_REAL(chv)} is {\tt 1} if {\tt chv} has real entries and {\tt 0} otherwise. \item {\tt CHV\_IS\_COMPLEX(chv)} is {\tt 1} if {\tt chv} has complex entries and {\tt 0} otherwise. \item {\tt CHV\_IS\_SYMMETRIC(chv)} is {\tt 1} if {\tt chv} is symmetric and {\tt 0} otherwise. \item {\tt CHV\_IS\_HERMITIAN(chv)} is {\tt 1} if {\tt chv} is Hermitian and {\tt 0} otherwise. \item {\tt CHV\_IS\_NONSYMMETRIC(chv)} is {\tt 1} if {\tt chv} is nonsymmetric and {\tt 0} otherwise. \end{itemize} Chv/doc/front.eps010064400020550007177000000062510657126731500152370ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 500.0 500.0 %%%EndComments /nD 10 def /nL 15 def /nU 12 def /margin 50 def /xscale 500 margin 2 mul sub nD nL add div def /yscale 500 margin 2 mul sub nD nU add div def xscale yscale le { % true action -- if else /yscale xscale def } { % false action -- if else /xscale yscale def } ifelse (xscale) == xscale == (yscale) == yscale == % 50 50 400 400 rectstroke gsave % % translate, scale and rotate % 50 50 translate xscale yscale scale 0.05 setlinewidth 0 nD nL add translate -90 rotate % % draw the outlines of the three DA2 objects % 0.0 setgray 0 0 nD nD rectstroke nD 0 nL nD rectstroke 0 nD nD nU rectstroke % % draw the pivot elements % /x 0 def /y 0 def 0 1 nD 1 sub { pop x y 1 1 rectstroke /x x 1 add def /y y 1 add def } for % % draw the solid edges for diagonal entries % currentlinewidth 2.0 mul setlinewidth newpath /x 0.5 def /y 0.5 def x y moveto 0 1 nD 2 sub { pop 1 1 rlineto } for stroke % % draw the thick edges for L_{J,J} % 2 1 nD 1 sub { /ix exch def newpath ix 0.5 add 0.5 moveto 0 1 ix 2 sub { /iy exch def 0.0 1.0 rlineto } for stroke } for % % draw the thick edges for L_{bnd{J},J} % nD 1 nD nL add 1 sub { /ix exch def newpath ix 0.5 add 0.5 moveto 0 1 nD 2 sub { /iy exch def 0.0 1.0 rlineto } for stroke } for % % draw the thin edges for L_{J,J} and L_{bnd{J},J} % currentlinewidth 0.5 mul setlinewidth newpath 1.5 0.5 moveto 2 1 nD 1 sub { /ix exch def ix 0.5 add 0.5 lineto ix 0.5 add ix 0.5 sub moveto } for stroke newpath nD 0.5 sub nD 1.5 sub moveto nD 1 nD nL add 1 sub { /ix exch def ix 0.5 add 0.5 lineto ix 0.5 add nD 0.5 sub moveto } for stroke % % draw the thick edges for U_{J,J} % currentlinewidth 2.0 mul setlinewidth 2 1 nD 1 sub { /iy exch def newpath 0.5 iy 0.5 add moveto 0 1 iy 2 sub { /ix exch def 1.0 0.0 rlineto } for stroke } for % % draw the thick edges for U_{bnd{J},J} % nD 1 nD nU add 1 sub { /iy exch def newpath 0.5 iy 0.5 add moveto 0 1 nD 2 sub { /ix exch def 1.0 0.0 rlineto } for stroke } for % % draw the thin edges for U_{J,J} and U_{bnd{J},J} % currentlinewidth 0.5 mul setlinewidth newpath 0.5 1.5 moveto 2 1 nD 1 sub { /iy exch def 0.5 iy 0.5 add lineto iy 0.5 sub iy 0.5 add moveto } for stroke newpath nD 1.5 sub nD 0.5 sub moveto nD 1 nD nU add 1 sub { /iy exch def 0.5 iy 0.5 add lineto nD 0.5 sub iy 0.5 add moveto } for stroke % % draw the circles that represent entries % /r 0.2 def /x 0.5 def 0 1 nD 1 sub { /y 0.5 def 0 1 nD nU add 1 sub { newpath 1.0 setgray pop x r add y moveto x y r 0 360 arc fill newpath 0.0 setgray x r add y moveto x y r 0 360 arc stroke /y y 1 add def } for /x x 1 add def } for /x nD 0.5 add def 0 1 nL 1 sub { /y 0.5 def 0 1 nD 1 sub { pop newpath 1.0 setgray x r add y moveto x y r 0 360 arc fill newpath 0.0 setgray x r add y moveto x y r 0 360 arc stroke /y y 1 add def } for /x x 1 add def } for stroke grestore Chv/doc/frontnonsym.eps010064400020550007177000000062510657126731500165030ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 500.0 500.0 %%%EndComments /nD 10 def /nL 15 def /nU 12 def /margin 50 def /xscale 500 margin 2 mul sub nD nL add div def /yscale 500 margin 2 mul sub nD nU add div def xscale yscale le { % true action -- if else /yscale xscale def } { % false action -- if else /xscale yscale def } ifelse (xscale) == xscale == (yscale) == yscale == % 50 50 400 400 rectstroke gsave % % translate, scale and rotate % 50 50 translate xscale yscale scale 0.05 setlinewidth 0 nD nL add translate -90 rotate % % draw the outlines of the three DA2 objects % 0.0 setgray 0 0 nD nD rectstroke nD 0 nL nD rectstroke 0 nD nD nU rectstroke % % draw the pivot elements % /x 0 def /y 0 def 0 1 nD 1 sub { pop x y 1 1 rectstroke /x x 1 add def /y y 1 add def } for % % draw the solid edges for diagonal entries % currentlinewidth 2.0 mul setlinewidth newpath /x 0.5 def /y 0.5 def x y moveto 0 1 nD 2 sub { pop 1 1 rlineto } for stroke % % draw the thick edges for L_{J,J} % 2 1 nD 1 sub { /ix exch def newpath ix 0.5 add 0.5 moveto 0 1 ix 2 sub { /iy exch def 0.0 1.0 rlineto } for stroke } for % % draw the thick edges for L_{bnd{J},J} % nD 1 nD nL add 1 sub { /ix exch def newpath ix 0.5 add 0.5 moveto 0 1 nD 2 sub { /iy exch def 0.0 1.0 rlineto } for stroke } for % % draw the thin edges for L_{J,J} and L_{bnd{J},J} % currentlinewidth 0.5 mul setlinewidth newpath 1.5 0.5 moveto 2 1 nD 1 sub { /ix exch def ix 0.5 add 0.5 lineto ix 0.5 add ix 0.5 sub moveto } for stroke newpath nD 0.5 sub nD 1.5 sub moveto nD 1 nD nL add 1 sub { /ix exch def ix 0.5 add 0.5 lineto ix 0.5 add nD 0.5 sub moveto } for stroke % % draw the thick edges for U_{J,J} % currentlinewidth 2.0 mul setlinewidth 2 1 nD 1 sub { /iy exch def newpath 0.5 iy 0.5 add moveto 0 1 iy 2 sub { /ix exch def 1.0 0.0 rlineto } for stroke } for % % draw the thick edges for U_{bnd{J},J} % nD 1 nD nU add 1 sub { /iy exch def newpath 0.5 iy 0.5 add moveto 0 1 nD 2 sub { /ix exch def 1.0 0.0 rlineto } for stroke } for % % draw the thin edges for U_{J,J} and U_{bnd{J},J} % currentlinewidth 0.5 mul setlinewidth newpath 0.5 1.5 moveto 2 1 nD 1 sub { /iy exch def 0.5 iy 0.5 add lineto iy 0.5 sub iy 0.5 add moveto } for stroke newpath nD 1.5 sub nD 0.5 sub moveto nD 1 nD nU add 1 sub { /iy exch def 0.5 iy 0.5 add lineto nD 0.5 sub iy 0.5 add moveto } for stroke % % draw the circles that represent entries % /r 0.2 def /x 0.5 def 0 1 nD 1 sub { /y 0.5 def 0 1 nD nU add 1 sub { newpath 1.0 setgray pop x r add y moveto x y r 0 360 arc fill newpath 0.0 setgray x r add y moveto x y r 0 360 arc stroke /y y 1 add def } for /x x 1 add def } for /x nD 0.5 add def 0 1 nL 1 sub { /y 0.5 def 0 1 nD 1 sub { pop newpath 1.0 setgray x r add y moveto x y r 0 360 arc fill newpath 0.0 setgray x r add y moveto x y r 0 360 arc stroke /y y 1 add def } for /x x 1 add def } for stroke grestore Chv/doc/frontnonsymDA2.eps010064400020550007177000000047670657126731600170050ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 500.0 500.0 %%%EndComments /nD 10 def /nL 15 def /nU 12 def /margin 50 def /xscale 500 margin 2 mul sub nD nL add div def /yscale 500 margin 2 mul sub nD nU add div def xscale yscale le { % true action -- if else /yscale xscale def } { % false action -- if else /xscale yscale def } ifelse (xscale) == xscale == (yscale) == yscale == % 50 50 400 400 rectstroke gsave % % translate, scale and rotate % 50 50 translate xscale yscale scale 0.05 setlinewidth 0 nD nL add translate -90 rotate % % draw the outlines of the three DA2 objects % 0.0 setgray 0 0 nD nD rectstroke nD 0 nL nD rectstroke 0 nD nD nU rectstroke % % draw the thick edges for A_{J,J} % 0 1 nD 1 sub { /iy exch def newpath 0.5 iy 0.5 add moveto 0 1 nD 2 sub { /iy exch def 1.0 0.0 rlineto } for stroke } for % % draw the thick edges for A_{bnd{J},J} % nD 1 nD nL add 1 sub { /ix exch def newpath ix 0.5 add 0.5 moveto 0 1 nD 2 sub { /iy exch def 0.0 1.0 rlineto } for stroke } for % % draw the thin edges for A_{J,J} and A_{bnd{J},J} % currentlinewidth 0.5 mul setlinewidth newpath nD 0.5 sub 0.5 moveto 2 1 nD { /iy exch def 0.5 iy 0.5 sub lineto nD 1 sub 0 rmoveto } for stroke newpath nD 0.5 add nD 0.5 sub moveto nD 1 add 1 nD nL add 1 sub { /ix exch def ix 0.5 add 0.5 lineto ix 0.5 add nD 0.5 sub moveto } for stroke % % draw the thick edges for A_{J,bnd{J}} % nD 1 nD nU add 1 sub { /iy exch def newpath 0.5 iy 0.5 add moveto 0 1 nD 2 sub { /ix exch def 1.0 0.0 rlineto } for stroke } for % % draw the thin edges for U_{J,bnd{J}} % currentlinewidth 0.5 mul setlinewidth newpath nD 0.5 sub nD 0.5 add moveto nD 1 add 1 nD nU add 1 sub { /iy exch def 0.5 iy 0.5 add lineto nD 0.5 sub iy 0.5 add moveto } for stroke % % draw the circles that represent entries % /r 0.2 def /x 0.5 def 0 1 nD 1 sub { /y 0.5 def 0 1 nD nU add 1 sub { newpath 1.0 setgray pop x r add y moveto x y r 0 360 arc fill newpath 0.0 setgray x r add y moveto x y r 0 360 arc stroke /y y 1 add def } for /x x 1 add def } for /x nD 0.5 add def 0 1 nL 1 sub { /y 0.5 def 0 1 nD 1 sub { pop newpath 1.0 setgray x r add y moveto x y r 0 360 arc fill newpath 0.0 setgray x r add y moveto x y r 0 360 arc stroke /y y 1 add def } for /x x 1 add def } for stroke grestore Chv/doc/frontsym.eps010064400020550007177000000066760657126731600160040ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 500.0 500.0 %%%EndComments /nD 10 def /nL 15 def /nU 15 def /margin 50 def /xscale 500 margin 2 mul sub nD nL add div def /yscale 500 margin 2 mul sub nD nU add div def xscale yscale le { % true action -- if else /yscale xscale def } { % false action -- if else /xscale yscale def } ifelse (xscale) == xscale == (yscale) == yscale == % 50 50 400 400 rectstroke gsave % % translate, scale and rotate % 50 50 translate xscale yscale scale 0.05 setlinewidth 0 nD nL add translate -90 rotate % % draw the outlines of the three DA2 objects % 0.0 setgray 0 0 nD nD rectstroke nD 0 nL nD rectstroke 0 nD nD nU rectstroke % % draw the pivot elements % 1x1, 2x2, 2x2, 1x1, 1x1, 1x1, 2x2 % /first [ -1 0 0 2 2 4 5 6 7 7 ] def 0 0 1 1 rectstroke 1 1 2 2 rectstroke 3 3 2 2 rectstroke 5 5 1 1 rectstroke 6 6 1 1 rectstroke 7 7 1 1 rectstroke 8 8 2 2 rectstroke % % draw the solid edges for diagonal entries % currentlinewidth 2.0 mul setlinewidth newpath 0.5 0.5 moveto 1 1 rlineto 0 1 rlineto 1 0 rlineto 1 1 rlineto 0 1 rlineto 1 0 rlineto 1 1 rlineto 1 1 rlineto 1 1 rlineto 1 1 rlineto 0 1 rlineto 1 0 rlineto stroke % % draw the thick edges for L_{J,J} % 2 1 nD 1 sub { /ix exch def newpath ix 0.5 add 0.5 moveto 0 1 first ix get 1 sub { /iy exch def 0.0 1.0 rlineto } for stroke } for % % draw the thick edges for L_{bnd{J},J} % nD 1 nD nL add 1 sub { /ix exch def newpath ix 0.5 add 0.5 moveto 0 1 nD 2 sub { /iy exch def 0.0 1.0 rlineto } for stroke } for % % draw the thin edges for L_{J,J} and L_{bnd{J},J} % currentlinewidth 0.5 mul setlinewidth newpath 1.5 0.5 moveto 2 1 nD 1 sub { /ix exch def ix 0.5 add 0.5 lineto ix 0.5 add first ix get 0.5 add moveto } for stroke newpath nD 0.5 sub first nD 1 sub get 0.5 add moveto nD 1 nD nL add 1 sub { /ix exch def ix 0.5 add 0.5 lineto ix 0.5 add nD 0.5 sub moveto } for stroke % % draw the thick edges for U_{J,J} % currentlinewidth 2.0 mul setlinewidth 2 1 nD 1 sub { /iy exch def newpath 0.5 iy 0.5 add moveto 0 1 first iy get 1 sub { /ix exch def 1.0 0.0 rlineto } for stroke } for % % draw the thick edges for U_{bnd{J},J} % nD 1 nD nU add 1 sub { /iy exch def newpath 0.5 iy 0.5 add moveto 0 1 nD 2 sub { /ix exch def 1.0 0.0 rlineto } for stroke } for % % draw the thin edges for U_{J,J} and U_{bnd{J},J} % currentlinewidth 0.5 mul setlinewidth newpath 0.5 1.5 moveto 2 1 nD 1 sub { /iy exch def 0.5 iy 0.5 add lineto first iy get 0.5 add iy 0.5 add moveto } for stroke newpath first nD 1 sub get 0.5 add nD 0.5 sub moveto nD 1 nD nU add 1 sub { /iy exch def 0.5 iy 0.5 add lineto nD 0.5 sub iy 0.5 add moveto } for stroke % % draw the circles that represent entries % /r 0.2 def /x 0.5 def 0 1 nD 1 sub { /y 0.5 def 0 1 nD nU add 1 sub { newpath 1.0 setgray pop x r add y moveto x y r 0 360 arc fill newpath 0.0 setgray x r add y moveto x y r 0 360 arc stroke /y y 1 add def } for /x x 1 add def } for /x nD 0.5 add def 0 1 nL 1 sub { /y 0.5 def 0 1 nD 1 sub { pop newpath 1.0 setgray x r add y moveto x y r 0 360 arc fill newpath 0.0 setgray x r add y moveto x y r 0 360 arc stroke /y y 1 add def } for /x x 1 add def } for stroke grestore d rotate % 50 50 translate xscale yscale scale 0.05 setliChv/doc/intro.tex010064400020550007177000000160210657126731600152500ustar00clevecompmath00000400000006\par \chapter{{\tt Chv}: Block chevron} \par The {\tt Chv} object is used to store and operate on a {\it front} during a sparse factorization. The {\tt Chv} object can contain either double precision real or complex data. A front is a portion of a matrix, shaded grey in the diagram below. \begin{center} \makebox{ % \psfig{file=simple.eps,width=1.0in,height=1.00in} \psfig{file=../../Chv/doc/simple.eps,width=1.0in,height=1.00in} } \end{center} We use the word ``chevron'' to describe the front, because if you rotate the figure $45^\circ$ clockwise the shaded region resembles the chevron insignia of enlisted personnel in the armed forces. Similar matrices are also known as ``arrowhead'' matrices, but we have found the ``chevron'' has a simpler abbreviation. We use the adjective ``block'' to emphasize that the chevron object may have multiple entries of the diagonal of the matrix. A ``single'' chevron (which is one way we assemble entries from a matrix into this data structure) contains a single entry from the diagonal of the matrix. \par The shaded region in the diagram above will normally be sparse, i.e., many of the entries might be zero. There are three logical blocks to the {\tt Chv} object: a nonempty square (1,1) block in the upper left corner, and (possibly empty) (1,2) and (2,1) blocks in the upper right and lower left corners. To conserve space and minimize work on logically zero elements, we store only rows of the lower part and columns of the upper part that have (or may have) nonzero elements. (Note, a particular row or column may have zero elements, but normally there will be nonzeros in each row and column that we store.) \par {\tt Chv} objects come in three types --- symmetric, Hermitian and nonsymmetric. When an object is symmetric or Hermitian, we only store the upper triangle. There is one limitation, perhaps unnecessary, that we put on the {\tt Chv} object --- the number of rows in the (2,1) block and number of columns in the (1,2) block are equal. The {\tt Chv} object is used within the context of a factorization of a sparse matrix that is assumed to have symmetric structure. If we ever extend the code to handle a true nonsymmetric structure factorization (e.g., {\sc umfpack} and {\sc superlu}), then we can modify the {\tt Chv} object to handle unequal rows and columns. \par During a factorization, a front has to take part in four distinct operations. \begin{enumerate} \item Assemble entries from the original matrix (or matrix pencil). (See the {\tt Chv\_addChevron()} method.) \item Accumulate updates from descendant fronts. (See the {\tt Chv\_update\{S,H,N\}()} methods.) \item Assemble any postponed data from its children fronts. (See the {\tt Chv\_assemblePostponedData()} method.) \item Compute the factorization of the completely assembled front. (See the {\tt Chv\_factor()} method.) \end{enumerate} \par The implementor of a front object has a great deal of freedom to design the underlying data structures. We have chosen to store the entries in each single chevron in contiguous memory --- the first entry of a chevron is in the last row of the front, the last entry of a chevron is in the last column of the front. The figure below shows the storage locations for the entries --- on the left is a nonsymmetric chevron, on the right is a symmetric or hermitian chevron. \begin{center} \makebox{ % \psfig{file=simple2.eps,width=2.2in,height=1.00in} \psfig{file=../../Chv/doc/simple2.eps,width=2.2in,height=1.00in} } \end{center} \par Any storage format has advantages and disadvantages. \begin{itemize} \item[{\bf con}] Moving along the diagonal is a nonconstant stride through memory. The same holds for moving along a row in the lower part and along a column in the upper part. While the strides are nonconstant, they are easily determined, particularly when starting in the first chevron. This affects the search methods that look for a pivot in the (1,1) block, the method that evaluates a pivot, the swap methods that swap rows and columns, and the methods that extract the entries from the chevron to be stored in the factor matrix. \item[{{\bf pro}}] Moving along a row in the upper part and along a column in the lower part uses a unit stride. This is useful when performing an update to the remaining part of the front after a pivot element has been selected. \item[{\bf pro}] The assembly of data, be it from the original matrix stored by chevrons, aggregate update fronts from other processes in a parallel factorization, or postponed data when pivoting for stability is used can be done in a straightforward manner. \end{itemize} \par The chevron object exists within the context of a larger global matrix, and so needs indices to define its rows and columns. For a symmetric or Hermitian matrix, we only store the column indices. For a nonsymmetric matrix, we store the both the row and column indices. This second case may seem unnecessary, since we assume that the larger global matrix has symmetric structure. However, during a factorization with pivoting enabled, a pivot element may be chosen from anywhere in the (1,1) block, so the row indices and column indices may no longer be identical. \par A {\tt Chv} object is inherently a serial, single threaded object, meaning it is designed so that only one thread or process ``owns'' or operates on a particular {\tt Chv} object. A {\tt Chv} object is an ``atom'' of communication. It stores postponed rows and columns to be assembled in a parent front. It might have to be written to and read from a file in an out-of-core implementation. In a distributed environment, it is communicated between processes. For these reasons, we designed the object so that its data (the scalars that describe its dimensions, id and type, the row and column indices, and its entries) are found in contiguous storage managed by a {\tt DV} object. A file operation can be done with a single read or write, a message can be sent without packing and unpacking data, or defining a new datatype. Managing working storage for a number of {\tt Chv} objects is now simpler. \par When the {\tt Chv} object contains double precision {\it complex} data, it stores and operates on them as double precision entries. We follow the FORTRAN convention that the real and imaginary part of a complex number are stored consecutively, the real part first followed by the imaginary number. In the above complex nonsymmetric matrix, the third diagonal entry is found at location 38 {\it in terms of the complex numbers}, but its real and imaginary parts are found in locations 2*38 = 76 and 2*38+1 = 77 of the double precision vector that stores the entries. Computations are done in a mix of subroutine calls (see {\tt Utilites/ZV.h}) and by expanding the complex arithmetic into real arithmetic. \par The {\tt Chv} object ``knows'' about the {\tt IV}, {\tt DV} and {\tt ZV} vector objects (for {\tt int}, {\tt double} and {\tt double complex} data types), the {\tt A2} object for dense 2-D arrays, and the {\tt SubMtx} object for dense or sparse 2-D submatrices. These {\tt IV}, {\tt DV}, {\tt ZV}, {\tt A2} and {\tt SubMtx} objects are subordinate to the {\tt Chv} object. Chv/doc/main.aux010064400020550007177000000042720665020172300150270ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt Chv}: Block chevron}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{3}} \newlabel{section:Chv:dataStructure}{{1.1}{3}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt Chv} methods}{4}} \newlabel{section:Chv:proto}{{1.2}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{4}} \newlabel{subsection:Chv:proto:basics}{{1.2.1}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Instance methods}{5}} \newlabel{subsection:Chv:proto:instance}{{1.2.2}{5}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Initialization methods}{7}} \newlabel{subsection:Chv:proto:initial}{{1.2.3}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Search methods}{8}} \newlabel{subsection:Chv:proto:search}{{1.2.4}{8}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Pivot methods}{9}} \newlabel{subsection:Chv:proto:pivot}{{1.2.5}{9}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.6}Update methods}{10}} \newlabel{subsection:Chv:proto:updates}{{1.2.6}{10}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.7}Assembly methods}{10}} \newlabel{subsection:Chv:proto:assembly}{{1.2.7}{10}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.8}Factorization methods}{11}} \newlabel{subsection:Chv:proto:factor}{{1.2.8}{11}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.9}Copy methods}{12}} \newlabel{subsection:Chv:proto:copy}{{1.2.9}{12}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.10}Swap methods}{14}} \newlabel{subsection:Chv:proto:swap}{{1.2.10}{14}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.11}Utility methods}{15}} \newlabel{subsection:Chv:proto:utilities}{{1.2.11}{15}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.12}IO methods}{17}} \newlabel{subsection:Chv:proto:IO}{{1.2.12}{17}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs for the {\tt Chv object}}{17}} \newlabel{section:Chv:drivers}{{1.3}{17}} Chv/doc/main.idx010064400020550007177000000074070665020172300150210ustar00clevecompmath00000400000006\indexentry{Chv_new@{\tt Chv\_new()}}{4} \indexentry{Chv_setDefaultFields@{\tt Chv\_setDefaultFields()}}{4} \indexentry{Chv_clearData@{\tt Chv\_clearData()}}{4} \indexentry{Chv_free@{\tt Chv\_free()}}{4} \indexentry{Chv_id@{\tt Chv\_id()}}{5} \indexentry{Chv_type@{\tt Chv\_type()}}{5} \indexentry{Chv_symmetryFlag@{\tt Chv\_symmetryFlag()}}{5} \indexentry{Chv_dimensions@{\tt Chv\_dimensions()}}{5} \indexentry{Chv_rowIndices@{\tt Chv\_rowIndices()}}{5} \indexentry{Chv_columnIndices@{\tt Chv\_columnIndices()}}{5} \indexentry{Chv_nent@{\tt Chv\_nent()}}{5} \indexentry{Chv_entries@{\tt Chv\_entries()}}{6} \indexentry{Chv_diagLocation@{\tt Chv\_diagLocation()}}{6} \indexentry{Chv_workspace@{\tt Chv\_workspace()}}{6} \indexentry{Chv_realEntry@{\tt Chv\_realEntry()}}{6} \indexentry{Chv_locationOfRealEntry@{\tt Chv\_locationOfRealEntry()}}{6} \indexentry{Chv_setRealEntry@{\tt Chv\_setRealEntry()}}{6} \indexentry{Chv_complexEntry@{\tt Chv\_complexEntry()}}{6} \indexentry{Chv_locationOfComplexEntry@{\tt Chv\_locationOfComplexEntry()}}{7} \indexentry{Chv_setComplexEntry@{\tt Chv\_setComplexEntry()}}{7} \indexentry{Chv_init@{\tt Chv\_init()}}{7} \indexentry{Chv_initWithPointers@{\tt Chv\_initWithPointers()}}{7} \indexentry{Chv_initFromBuffer@{\tt Chv\_initFromBuffer()}}{7} \indexentry{Chv_maxabsInDiagonal11@{\tt Chv\_maxabsInDiagonal11()}}{8} \indexentry{Chv_maxabsInRow11@{\tt Chv\_maxabsInRow11()}}{8} \indexentry{Chv_maxabsInColumn11@{\tt Chv\_maxabsInColumn11()}}{8} \indexentry{Chv_maxabsInRow@{\tt Chv\_maxabsInRow()}}{8} \indexentry{Chv_maxabsInColumn@{\tt Chv\_maxabsInColumn()}}{8} \indexentry{Chv_quasimax@{\tt Chv\_quasimax()}}{9} \indexentry{Chv_fastBunchParlettPivot@{\tt Chv\_fastBunchParlettPivot()}}{9} \indexentry{Chv_findPivot@{\tt Chv\_findPivot()}}{9} \indexentry{Chv_updateS@{\tt Chv\_updateS()}}{10} \indexentry{Chv_updateH@{\tt Chv\_updateH()}}{10} \indexentry{Chv_updateN@{\tt Chv\_updateN()}}{10} \indexentry{Chv_addChevron@{\tt Chv\_addChevron()}}{10} \indexentry{Chv_assembleChv@{\tt Chv\_assembleChv()}}{11} \indexentry{Chv_assemblePostponedData@{\tt Chv\_assemblePostponedData()}}{11} \indexentry{Chv_factorWithPivoting@{\tt Chv\_factorWithPivoting()}}{11} \indexentry{Chv_factorWithNoPivoting@{\tt Chv\_factorWithNoPivoting()}}{11} \indexentry{Chv_r1upd@{\tt Chv\_r1upd()}}{12} \indexentry{Chv_r2upd@{\tt Chv\_r2upd()}}{12} \indexentry{Chv_maxabsInChevron@{\tt Chv\_maxabsInChevron()}}{12} \indexentry{Chv_zeroOffdiagonalOfChevron@{\tt Chv\_zeroOffdiagonalOfChevron()}}{12} \indexentry{Chv_countEntries@{\tt Chv\_countEntries()}}{12} \indexentry{Chv_countBigEntries@{\tt Chv\_countBigEntries()}}{13} \indexentry{Chv_copyEntriesToVector@{\tt Chv\_copyEntriesToVector()}}{13} \indexentry{Chv_copyBigEntriesToVector@{\tt Chv\_copyBigEntriesToVector()}}{14} \indexentry{Chv_copyTrailingPortion@{\tt Chv\_copyTrailingPortion()}}{14} \indexentry{Chv_swapRows@{\tt Chv\_swapRows()}}{14} \indexentry{Chv_swapColumns@{\tt Chv\_swapColumns()}}{15} \indexentry{Chv_swapRowsAndColumns@{\tt Chv\_swapRowsAndColumns()}}{15} \indexentry{Chv_nbytesNeeded@{\tt Chv\_nbytesNeeded()}}{15} \indexentry{Chv_nbytesInWorkspace@{\tt Chv\_nbytesInWorkspace()}}{15} \indexentry{Chv_setNbytesInWorkspace@{\tt Chv\_setNbytesInWorkspace()}}{15} \indexentry{Chv_setFields@{\tt Chv\_setFields()}}{15} \indexentry{Chv_shift@{\tt Chv\_shift()}}{15} \indexentry{Chv_fill11block@{\tt Chv\_fill11block()}}{16} \indexentry{Chv_fill12block@{\tt Chv\_fill12block()}}{16} \indexentry{Chv_fill21block@{\tt Chv\_fill21block()}}{16} \indexentry{Chv_maxabs@{\tt Chv\_maxabs()}}{16} \indexentry{Chv_frobNorm@{\tt Chv\_frobNorm()}}{16} \indexentry{Chv_sub@{\tt Chv\_sub()}}{16} \indexentry{Chv_zero@{\tt Chv\_zero()}}{16} \indexentry{Chv_writeForHumanEye@{\tt Chv\_writeForHumanEye()}}{17} \indexentry{Chv_writeForMatlab@{\tt Chv\_writeForMatlab()}}{17} Chv/doc/main.ilg010064400020550007177000000004570657126731600150220ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (62 entries accepted, 0 rejected). Sorting entries....done (437 comparisons). Generating output file main.ind....done (66 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Chv/doc/main.ind010064400020550007177000000044110657126731600150130ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Chv\_addChevron()}, 10 \item {\tt Chv\_assembleChv()}, 11 \item {\tt Chv\_assemblePostponedData()}, 11 \item {\tt Chv\_clearData()}, 4 \item {\tt Chv\_columnIndices()}, 5 \item {\tt Chv\_complexEntry()}, 6 \item {\tt Chv\_copyBigEntriesToVector()}, 13 \item {\tt Chv\_copyEntriesToVector()}, 13 \item {\tt Chv\_copyTrailingPortion()}, 14 \item {\tt Chv\_countBigEntries()}, 12 \item {\tt Chv\_countEntries()}, 12 \item {\tt Chv\_diagLocation()}, 6 \item {\tt Chv\_dimensions()}, 5 \item {\tt Chv\_entries()}, 6 \item {\tt Chv\_factor()}, 11 \item {\tt Chv\_fastBunchParlettPivot()}, 9 \item {\tt Chv\_fill11block()}, 15 \item {\tt Chv\_fill12block()}, 15 \item {\tt Chv\_fill21block()}, 16 \item {\tt Chv\_findPivot()}, 9 \item {\tt Chv\_free()}, 4 \item {\tt Chv\_frobNorm()}, 16 \item {\tt Chv\_id()}, 5 \item {\tt Chv\_init()}, 7 \item {\tt Chv\_initFromBuffer()}, 7 \item {\tt Chv\_initWithPointers()}, 7 \item {\tt Chv\_locationOfComplexEntry()}, 7 \item {\tt Chv\_locationOfRealEntry()}, 6 \item {\tt Chv\_maxabs()}, 16 \item {\tt Chv\_maxabsInColumn()}, 8 \item {\tt Chv\_maxabsInColumn11()}, 8 \item {\tt Chv\_maxabsInDiagonal11()}, 8 \item {\tt Chv\_maxabsInRow()}, 8 \item {\tt Chv\_maxabsInRow11()}, 8 \item {\tt Chv\_nbytesInWorkspace()}, 15 \item {\tt Chv\_nbytesNeeded()}, 15 \item {\tt Chv\_nent()}, 5 \item {\tt Chv\_new()}, 4 \item {\tt Chv\_quasimax()}, 9 \item {\tt Chv\_r1upd()}, 11 \item {\tt Chv\_r2upd()}, 12 \item {\tt Chv\_realEntry()}, 6 \item {\tt Chv\_rowIndices()}, 5 \item {\tt Chv\_setComplexEntry()}, 7 \item {\tt Chv\_setDefaultFields()}, 4 \item {\tt Chv\_setFields()}, 15 \item {\tt Chv\_setNbytesInWorkspace()}, 15 \item {\tt Chv\_setRealEntry()}, 6 \item {\tt Chv\_shift()}, 15 \item {\tt Chv\_sub()}, 16 \item {\tt Chv\_swapColumns()}, 14 \item {\tt Chv\_swapRows()}, 14 \item {\tt Chv\_swapRowsAndColumns()}, 14 \item {\tt Chv\_symmetryFlag()}, 5 \item {\tt Chv\_type()}, 5 \item {\tt Chv\_updateH()}, 10 \item {\tt Chv\_updateN()}, 10 \item {\tt Chv\_updateS()}, 10 \item {\tt Chv\_workspace()}, 6 \item {\tt Chv\_writeForHumanEye()}, 16 \item {\tt Chv\_writeForMatlab()}, 16 \item {\tt Chv\_zero()}, 16 \end{theindex} Chv/doc/main.log010064400020550007177000000264530665020172300150200ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 16 JAN 1999 13:25 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/latex209.def File: latex209.def 1996/05/21 v0.51 Standard LaTeX file Entering LaTeX 2.09 compatibility mode. \footheight=\dimen102 \@maxsep=\dimen103 \@dblmaxsep=\dimen104 \@cla=\count79 \@clb=\count80 \mscount=\count81 (/home/tex/teTeX/texmf/tex/latex/base/tracefnt.sty Package: tracefnt 1996/07/26 v3.0i Standard LaTeX package (font tracing) \tracingfonts=\count82 LaTeX Info: Redefining \selectfont on input line 139. ) \symbold=\mathgroup4 \symsans=\mathgroup5 \symtypewriter=\mathgroup6 \symitalic=\mathgroup7 \symsmallcaps=\mathgroup8 \symslanted=\mathgroup9 LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 306. LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 307. LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 308. LaTeX Font Info: Redeclaring math alphabet \mathit on input line 314. LaTeX Info: Redefining \em on input line 324. (/home/tex/teTeX/texmf/tex/latex/base/latexsym.sty Package: latexsym 1996/11/20 v2.2d Standard LaTeX package (lasy symbols) \symlasy=\mathgroup10 LaTeX Font Info: Overwriting symbol font `lasy' in version `bold' (Font) U/lasy/m/n --> U/lasy/b/n on input line 85. ) LaTeX Font Info: Redeclaring math delimiter \lgroup on input line 388. LaTeX Font Info: Redeclaring math delimiter \rgroup on input line 390. LaTeX Font Info: Redeclaring math delimiter \bracevert on input line 392. (/home/tex/teTeX/texmf/tex/latex/config/latex209.cfg (/home/tex/teTeX/texmf/tex/latex/tools/rawfonts.sty Compatibility mode: package `' requested, but `rawfonts' provided. Package: rawfonts 1994/05/08 Low-level LaTeX 2.09 font compatibility (/home/tex/teTeX/texmf/tex/latex/tools/somedefs.sty Package: somedefs 1994/06/01 Toolkit for optional definitions ) LaTeX Font Info: Try loading font information for U+lasy on input line 36. (/home/tex/teTeX/texmf/tex/latex/base/ulasy.fd File: ulasy.fd 1996/11/20 v2.2dLaTeX symbol font definitions )))) (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size11.clo File: size11.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count83 \c@chapter=\count84 \c@section=\count85 \c@subsection=\count86 \c@subsubsection=\count87 \c@paragraph=\count88 \c@subparagraph=\count89 \c@figure=\count90 \c@table=\count91 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 Compatibility mode: definition of \rm ignored. Compatibility mode: definition of \sf ignored. Compatibility mode: definition of \tt ignored. Compatibility mode: definition of \bf ignored. Compatibility mode: definition of \it ignored. Compatibility mode: definition of \sl ignored. Compatibility mode: definition of \sc ignored. LaTeX Info: Redefining \cal on input line 622. LaTeX Info: Redefining \mit on input line 623. \bibindent=\dimen105 ) (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen106 \p@intvaluey=\dimen107 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. (intro.tex Chapter 1. psfig: searching ../../Chv/doc/simple.eps for bounding box psfig: including ../../Chv/doc/simple.eps LaTeX Font Info: External font `cmex10' loaded for size (Font) <10.95> on input line 16. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 16. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 16. [1 ] LaTeX Font Info: Try loading font information for OMS+cmtt on input line 61. LaTeX Font Info: No file OMScmtt.fd. on input line 61. LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined (Font) using `OMS/cmsy/m/n' instead (Font) for symbol `textbraceleft' on input line 61. Overfull \hbox (7.47354pt too wide) in paragraph at lines 63--66 []\OT1/cmr/m/n/10.95 Assemble any post-poned data from its chil-dren fronts. (S ee the \OT1/cmtt/m/n/10.95 Chv[]assemblePostponedData() [] Overfull \hbox (1.0263pt too wide) in paragraph at lines 66--68 []\OT1/cmr/m/n/10.95 Compute the fac-tor-iza-tion of the com-pletely as-sem-ble d front. (See the \OT1/cmtt/m/n/10.95 Chv[]factor() \OT1/cmr/m/n/10.95 method.) [] psfig: searching ../../Chv/doc/simple2.eps for bounding box psfig: including ../../Chv/doc/simple2.eps [2]) (dataStructure.tex LaTeX Font Info: Try loading font information for OMS+cmr on input line 9. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10.95> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 9. [3]) (proto.tex [4] [5] [6] Overfull \hbox (29.01247pt too wide) in paragraph at lines 324--324 []\OT1/cmtt/m/n/10.95 void Chv_init( Chv *chv, int id, int nD, int nL, int nU, int type, int symflag ) ;[] [] Overfull \hbox (11.7664pt too wide) in paragraph at lines 347--347 []\OT1/cmtt/m/n/10.95 void Chv_initWithPointers ( Chv *chv, int id, int nD, in t nL, int nU, int type,[] [] Overfull \hbox (52.00722pt too wide) in paragraph at lines 347--347 [] \OT1/cmtt/m/n/10.95 int symflag, int *rowind, in t *colind, double *entries ) ;[] [] Overfull \hbox (11.7664pt too wide) in paragraph at lines 390--390 []\OT1/cmtt/m/n/10.95 int Chv_maxabsInDiagonal11 ( Chv *chv, int mark[], int t ag, double *pmaxval ) ;[] [] [7] [8] [9] [10] Overfull \hbox (0.26903pt too wide) in paragraph at lines 681--681 []\OT1/cmtt/m/n/10.95 int Chv_assemblePostponedData ( Chv *newchv, Chv *oldchv , Chv *firstchild ) ;[] [] [11] [12] Overfull \hbox (8.37198pt too wide) in paragraph at lines 921--925 []\OT1/cmr/m/n/10.95 If \OT1/cmtt/m/n/10.95 storeflag \OT1/cmr/m/n/10.95 is \OT 1/cmtt/m/n/10.95 CHV[]BY[]ROWS\OT1/cmr/m/n/10.95 , the en-tries are stored by r ows and if \OT1/cmtt/m/n/10.95 storeflag \OT1/cmr/m/n/10.95 is \OT1/cmtt/m/n/10 .95 CHV[]BY[]COLUMNS\OT1/cmr/m/n/10.95 , [] [13] Overfull \hbox (8.37198pt too wide) in paragraph at lines 973--977 []\OT1/cmr/m/n/10.95 If \OT1/cmtt/m/n/10.95 storeflag \OT1/cmr/m/n/10.95 is \OT 1/cmtt/m/n/10.95 CHV[]BY[]ROWS\OT1/cmr/m/n/10.95 , the en-tries are stored by r ows and if \OT1/cmtt/m/n/10.95 storeflag \OT1/cmr/m/n/10.95 is \OT1/cmtt/m/n/10 .95 CHV[]BY[]COLUMNS\OT1/cmr/m/n/10.95 , [] [14] [15] [16]) (drivers.tex Overfull \hbox (4.80856pt too wide) in paragraph at lines 36--40 []\OT1/cmr/m/n/10.95 The \OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 pa-ram- e-ter is the sym-me-try flag --- \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr /m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN [] [17] Overfull \hbox (4.80856pt too wide) in paragraph at lines 87--91 []\OT1/cmr/m/n/10.95 The \OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 pa-ram- e-ter is the sym-me-try flag --- \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr /m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN [] Overfull \hbox (4.80856pt too wide) in paragraph at lines 127--131 []\OT1/cmr/m/n/10.95 The \OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 pa-ram- e-ter is the sym-me-try flag --- \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr /m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN [] [18] Overfull \hbox (4.80856pt too wide) in paragraph at lines 177--181 []\OT1/cmr/m/n/10.95 The \OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 pa-ram- e-ter is the sym-me-try flag --- \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr /m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN [] [19] Overfull \hbox (4.80856pt too wide) in paragraph at lines 227--231 []\OT1/cmr/m/n/10.95 The \OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 pa-ram- e-ter is the sym-me-try flag --- \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr /m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN [] Overfull \hbox (4.80856pt too wide) in paragraph at lines 273--277 []\OT1/cmr/m/n/10.95 The \OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 pa-ram- e-ter is the sym-me-try flag --- \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr /m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN [] Overfull \hbox (28.20038pt too wide) in paragraph at lines 287--301 []\OT1/cmr/m/n/10.95 This driver pro-gram tests the \OT1/cmtt/m/n/10.95 Chv[]ma xabsInRow()\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 Chv[]maxabsInRow11()\OT1/cm r/m/n/10.95 , \OT1/cmtt/m/n/10.95 Chv[]maxabsInColumn()\OT1/cmr/m/n/10.95 , [] [20] Overfull \hbox (4.80856pt too wide) in paragraph at lines 321--325 []\OT1/cmr/m/n/10.95 The \OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 pa-ram- e-ter is the sym-me-try flag --- \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr /m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN [] Overfull \hbox (4.80856pt too wide) in paragraph at lines 360--364 []\OT1/cmr/m/n/10.95 The \OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 pa-ram- e-ter is the sym-me-try flag --- \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr /m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN [] Overfull \hbox (4.80856pt too wide) in paragraph at lines 395--399 []\OT1/cmr/m/n/10.95 The \OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 pa-ram- e-ter is the sym-me-try flag --- \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr /m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN [] [21] Overfull \hbox (4.80856pt too wide) in paragraph at lines 435--439 []\OT1/cmr/m/n/10.95 The \OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 pa-ram- e-ter is the sym-me-try flag --- \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr /m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN [] Overfull \hbox (4.80856pt too wide) in paragraph at lines 470--474 []\OT1/cmr/m/n/10.95 The \OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 pa-ram- e-ter is the sym-me-try flag --- \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr /m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN [] [22]) (main.ind [23] [24 ]) (main.aux) LaTeX Font Warning: Some font shapes were not available, defaults substituted. ) Here is how much of TeX's memory you used: 839 strings out of 10908 8656 string characters out of 72189 55441 words of memory out of 262141 3675 multiletter control sequences out of 9500 23452 words of font info for 88 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 22i,7n,21p,313b,388s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (24 pages, 84792 bytes). kage: rawfonts 1994/05/08 Low-level LaTeX 2.09 font compatibility (/home/tex/teTeX/texmf/tex/latex/tools/somedefs.sty Package: somedefs 1994/06/01 Toolkit for optional definitions ) LaTeX Font Info: Try loadinChv/doc/main.tex010064400020550007177000000011510665065617000150350ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \newcommand{\bnd}{{\partial}} \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Chv} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Chv} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} Chv/doc/notes010064400020550007177000000006120657126731600144450ustar00clevecompmath00000400000006(1) DFront's create new DFront objects as the first step of an update, an inter-front computation. (2) The second step is the assembly of one DFront object into another. (3) I.e., DFront objects do not have internal access to others of their own class during the update. (4) Later, we can write the code to perform the update with direct-action-on-storage of the two DFront's. Chv/doc/proto.tex010064400020550007177000001511710665020234200152500ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Chv} methods} \label{section:Chv:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Chv} object. \par \subsection{Basic methods} \label{subsection:Chv:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Chv * Chv_new ( void ) ; \end{verbatim} \index{Chv_new@{\tt Chv\_new()}} This method simply allocates storage for the {\tt Chv} structure and then sets the default fields by a call to {\tt Chv\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_setDefaultFields ( Chv *chv ) ; \end{verbatim} \index{Chv_setDefaultFields@{\tt Chv\_setDefaultFields()}} The structure's fields are set to default values: {\tt id} = {\tt -1}, {\tt nD} = {\tt nL} = {\tt nU} = 0, {\tt type} = {\tt SPOOLES\_REAL}, {\tt symflag} = {\tt SPOOLES\_SYMMETRIC}, and {\tt rowind} = {\tt colind} = {\tt entries} = {\tt next} = {\tt NULL} . The {\tt wrkDV} object has its default fields set via a call to {\tt DV\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_clearData ( Chv *chv ) ; \end{verbatim} \index{Chv_clearData@{\tt Chv\_clearData()}} This method clears the object and free's any owned data by invoking the {\tt \_clearData()} methods for its internal {\tt DV} object. There is a concluding call to {\tt Chv\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_free ( Chv *chv ) ; \end{verbatim} \index{Chv_free@{\tt Chv\_free()}} This method releases any storage by a call to {\tt Chv\_clearData()} and then free the space for {\tt chv}. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:Chv:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_id ( Chv *chv ) ; \end{verbatim} \index{Chv_id@{\tt Chv\_id()}} This method returns the {\it id} of the object. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_type ( Chv *chv ) ; \end{verbatim} \index{Chv_type@{\tt Chv\_type()}} This method returns the {\it type} of the object. \begin{itemize} \item {\tt SPOOLES\_REAL} $\Longrightarrow$ real entries \item {\tt SPOOLES\_COMPLEX} $\Longrightarrow$ complex entries \end{itemize} \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_symmetryFlag ( Chv *chv ) ; \end{verbatim} \index{Chv_symmetryFlag@{\tt Chv\_symmetryFlag()}} This method returns the {\it symmetry flag} of the object. \begin{itemize} \item {\tt SPOOLES\_SYMMETRIC} $\Longrightarrow$ symmetric entries, i.e., $a_{i,j} = a_{j,i}$. \item {\tt SPOOLES\_HERMITIAN} $\Longrightarrow$ hermitian entries, i.e., $a_{i,j} = \overline{a_{j,i}}$. \item {\tt SPOOLES\_NONSYMMETRIC} $\Longrightarrow$ nonsymmetric entries. \end{itemize} \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_dimensions ( Chv *chv, int *pnD, int *pnL, *pnU ) ; \end{verbatim} \index{Chv_dimensions@{\tt Chv\_dimensions()}} This method fills {\tt *pnD}, {\tt *pnL} and {\tt *pnU} with {\tt nD}, {\tt nL} and {\tt nU}. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_rowIndices ( Chv *chv, int *pnrow, **prowind ) ; \end{verbatim} \index{Chv_rowIndices@{\tt Chv\_rowIndices()}} This method fills {\tt *pnrow} with the number of rows ({\tt nD + nL}) and {\tt *prowind} with a pointer to the row indices. \par \noindent {\it Error checking:} If {\tt chv}, {\tt pnrow} or {\tt prowind} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_columnIndices ( Chv *chv, int *pncol, **pcolind ) ; \end{verbatim} \index{Chv_columnIndices@{\tt Chv\_columnIndices()}} This method fills {\tt *pncol} with the number of columns ({\tt nD + nU}) and {\tt *pcolind} with a pointer to the column indices. \par \noindent {\it Error checking:} If {\tt chv}, {\tt pncol} or {\tt pcolind} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_nent ( Chv *chv ) ; \end{verbatim} \index{Chv_nent@{\tt Chv\_nent()}} This method returns number of matrix entries that the object contains. Note, for a complex chevron, this is the number of {\it double precision complex} entries, equal to one half the number of double precision entries that are stored. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} double * Chv_entries ( Chv *chv ) ; \end{verbatim} \index{Chv_entries@{\tt Chv\_entries()}} This method returns the {\it entries} field of the object, a pointer to the base location of the double precision array that stores the complex data. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} double * Chv_diagLocation ( Chv *chv, int ichv ) ; \end{verbatim} \index{Chv_diagLocation@{\tt Chv\_diagLocation()}} This method returns a pointer to the address of the entry in the {\tt ichv}'th diagonal location. For a real chevron, to find the entry {\tt k} places to the right of the diagonal entry, add {\tt k} to the address. To find an entry {\tt k} places below the diagonal entry, subtract {\tt k} from the address. For a complex chevron, to find the entry {\tt k} places to the right of the diagonal entry, add {\tt 2*k} to the address. To find an entry {\tt k} places below the diagonal entry, subtract {\tt 2*k} from the address. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void * Chv_workspace ( Chv *chv ) ; \end{verbatim} \index{Chv_workspace@{\tt Chv\_workspace()}} This method returns a pointer to the base address of the workspace. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_realEntry ( Chv *chv, int irow, int jcol, double *pValue ) ; \end{verbatim} \index{Chv_realEntry@{\tt Chv\_realEntry()}} This method fills {\tt *pValue} with the entry in row {\tt irow} and column {\tt jcol}. Note, {\tt irow} and {\tt jcol} are {\it local} indices, i.e., $0 \le \mbox{\tt irow} < \mbox{\tt nD} + \mbox{\tt nL}$ and $0 \le \mbox{\tt jcol} < \mbox{\tt nD} + \mbox{\tt nU}$. \par \noindent {\it Error checking:} If {\tt chv} or {\tt pValue} is {\tt NULL}, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Chv_locationOfRealEntry ( Chv *chv, int irow, int jcol, double **ppValue ) ; \end{verbatim} \index{Chv_locationOfRealEntry@{\tt Chv\_locationOfRealEntry()}} This method fills {\tt *ppValue} with a pointer to the entry in row {\tt irow} and column {\tt jcol}. Note, {\tt irow} and {\tt jcol} are {\it local} indices, i.e., $0 \le \mbox{\tt irow} < \mbox{\tt nD} + \mbox{\tt nL}$ and $0 \le \mbox{\tt jcol} < \mbox{\tt nD} + \mbox{\tt nU}$. \par \noindent {\it Error checking:} If {\tt chv} or {\tt ppValue} is {\tt NULL}, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_setRealEntry ( Chv *chv, int irow, int jcol, double value ) ; \end{verbatim} \index{Chv_setRealEntry@{\tt Chv\_setRealEntry()}} This method sets the entry in row {\tt irow} and column {\tt jcol} to be {\tt value}. Note, {\tt irow} and {\tt jcol} are {\it local} indices, i.e., $0 \le \mbox{\tt irow} < \mbox{\tt nD} + \mbox{\tt nL}$ and $0 \le \mbox{\tt jcol} < \mbox{\tt nD} + \mbox{\tt nU}$. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_complexEntry ( Chv *chv, int irow, int jcol, double *pReal, double *pImag ) ; \end{verbatim} \index{Chv_complexEntry@{\tt Chv\_complexEntry()}} This method fills {\tt *pReal} with the real part and {\tt *pImag} with the imaginary part of the the entry in row {\tt irow} and column {\tt jcol}. Note, {\tt irow} and {\tt jcol} are {\it local} indices, i.e., $0 \le \mbox{\tt irow} < \mbox{\tt nD} + \mbox{\tt nL}$ and $0 \le \mbox{\tt jcol} < \mbox{\tt nD} + \mbox{\tt nU}$. \par \noindent {\it Error checking:} If {\tt chv}, {\tt pReal} or {\tt pImag} is {\tt NULL}, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Chv_locationOfComplexEntry ( Chv *chv, int irow, int jcol, double **ppReal, double **ppImag ) ; \end{verbatim} \index{Chv_locationOfComplexEntry@{\tt Chv\_locationOfComplexEntry()}} This method fills {\tt *ppReal} with a pointer to the real part and {\tt *ppImag} with a pointer to the imaginary part of the entry in row {\tt irow} and column {\tt jcol}. Note, {\tt irow} and {\tt jcol} are {\it local} indices, i.e., $0 \le \mbox{\tt irow} < \mbox{\tt nD} + \mbox{\tt nL}$ and $0 \le \mbox{\tt jcol} < \mbox{\tt nD} + \mbox{\tt nU}$. \par \noindent {\it Error checking:} If {\tt chv}, {\tt ppReal} or {\tt ppImag} is {\tt NULL}, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_setComplexEntry ( Chv *chv, int irow, int jcol, double real, double imag ) ; \end{verbatim} \index{Chv_setComplexEntry@{\tt Chv\_setComplexEntry()}} This method sets the real and imaginary parts and the entry in row {\tt irow} and column {\tt jcol} to be {\tt real} and {\tt imag}, respectively. Note, {\tt irow} and {\tt jcol} are {\it local} indices, i.e., $0 \le \mbox{\tt irow} < \mbox{\tt nD} + \mbox{\tt nL}$ and $0 \le \mbox{\tt jcol} < \mbox{\tt nD} + \mbox{\tt nU}$. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization methods} \label{subsection:Chv:proto:initial} \par There are three initializer methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_init( Chv *chv, int id, int nD, int nL, int nU, int type, int symflag ) ; \end{verbatim} \index{Chv_init@{\tt Chv\_init()}} This is the initializer method used when the {\tt Chv} object is to use its owned workspace to store indices and entries. The number of indices and entries is computed, the work space is set up via calls to {\tt Chv\_nbytesNeeded()} and {\tt Chv\_setNbytesInWorkspace()}, and the scalars, pointers and buffer are set up via a call to {\tt Chv\_setFields()}. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, or if ${\tt nD} \le 0$, or if {\tt nL} or ${\tt nU} < 0$, or if {\tt type} or if {\tt symflag} is not valid, % or if {\tt type} is not {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, % or if {\tt symflag} is not {\tt SPOOLES\_SYMMETRIC}, % {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_initWithPointers ( Chv *chv, int id, int nD, int nL, int nU, int type, int symflag, int *rowind, int *colind, double *entries ) ; \end{verbatim} \index{Chv_initWithPointers@{\tt Chv\_initWithPointers()}} This initializer method is used when the {\tt Chv} object does not own the storage for its indices and entries, but points into some other storage. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, or if ${\tt nD} \le 0$, or if {\tt nL} or ${\tt nU} < 0$, or if {\tt type} or if {\tt symflag} is not valid, % or if {\tt type} is not {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, % or if {\tt symflag} is not {\tt SPOOLES\_SYMMETRIC}, % {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC} or if {\tt entries} or {\tt colind} is {\tt NULL}, or if {\tt symflag = SPOOLES\_NONSYMMETRIC} and {\tt rowind} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_initFromBuffer ( Chv *chv ) ; \end{verbatim} \index{Chv_initFromBuffer@{\tt Chv\_initFromBuffer()}} This initializer method is used to set the scalar and pointer fields when the object's buffer is already preloaded. This functionality is used in the MPI factorization where a {\tt Chv} object is sent and received, more precisely, the workspace buffer owned by the {\tt Chv} object is sent and received. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Search methods} \label{subsection:Chv:proto:search} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_maxabsInDiagonal11 ( Chv *chv, int mark[], int tag, double *pmaxval ) ; \end{verbatim} \index{Chv_maxabsInDiagonal11@{\tt Chv\_maxabsInDiagonal11()}} This method returns the location of the first tagged element with the largest magnitude in the diagonal of the (1,1) block. Element {\tt jj} must have {\tt mark[jj] = tag} to be eligible. Its magnitude is returned in {\tt *pmaxval}. Note, if the chevron is complex, the location is in terms of the complex entries, not in the real entries, i.e., if {\tt k = Chv\_maxabsDiagonal11(chv,...)}, then the complex entry is found in {\tt chv->entries[2*kk:2*kk+1]}. \par \noindent {\it Error checking:} If {\tt chv}, {\tt mark} or {\tt pmaxval} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_maxabsInRow11 ( Chv *chv, int irow, int colmark[], int tag, double *pmaxval ) ; \end{verbatim} \index{Chv_maxabsInRow11@{\tt Chv\_maxabsInRow11()}} This method returns the location of the first element with the largest magnitude in row {\tt irow} of the (1,1) block. Element {\tt jj} must have {\tt colmark[jj] = tag} to be eligible. Its magnitude is returned in {\tt *pmaxval}. Note, if the chevron is complex, the location is in terms of the complex entries, not in the real entries, i.e., if {\tt k = Chv\_maxabsRow11(chv,...)}, then the complex entry is found in {\tt chv->entries[2*kk:2*kk+1]}. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL} or {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_maxabsInColumn11 ( Chv *chv, int jcol, int rowmark[], int tag, double *pmaxval ) ; \end{verbatim} \index{Chv_maxabsInColumn11@{\tt Chv\_maxabsInColumn11()}} This method returns the location of the first element with the largest magnitude in column {\tt jcol} of the (1,1) block. Element {\tt jj} must have {\tt rowmark[jj] = tag} to be eligible. Its magnitude is returned in {\tt *pmaxval}. Note, if the chevron is complex, the location is in terms of the complex entries, not in the real entries, i.e., if {\tt k = Chv\_maxabsColumn11(chv,...)}, then the complex entry is found in {\tt chv->entries[2*kk:2*kk+1]}. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL} or {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_maxabsInRow ( Chv *chv, int irow, int colmark[], int tag, double *pmaxval ) ; \end{verbatim} \index{Chv_maxabsInRow@{\tt Chv\_maxabsInRow()}} This method returns the location of the first element with the largest magnitude in row {\tt irow}. Element {\tt jj} must have {\tt colmark[jj] = tag} to be eligible. Its magnitude is returned in {\tt *pmaxval}. Note, if the chevron is complex, the location is in terms of the complex entries, not in the real entries, i.e., if {\tt k = Chv\_maxabsRow(chv,...)}, then the complex entry is found in {\tt chv->entries[2*kk:2*kk+1]}. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL} or {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_maxabsInColumn ( Chv *chv, int jcol, int rowmark[], int tag, double *pmaxval ) ; \end{verbatim} \index{Chv_maxabsInColumn@{\tt Chv\_maxabsInColumn()}} This method returns the location of the first element with the largest magnitude in column {\tt jcol}. Element {\tt jj} must have {\tt rowmark[jj] = tag} to be eligible. Its magnitude is returned in {\tt *pmaxval}. Note, if the chevron is complex, the location is in terms of the complex entries, not in the real entries, i.e., if {\tt k = Chv\_maxabsColumn11(chv,...)}, then the complex entry is found in {\tt chv->entries[2*kk:2*kk+1]}. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL} or {\tt irow} is not in {\tt [0,n1-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double Chv_quasimax ( Chv *chv, int rowmark[], int colmark[] int tag, int *pirow, int *pjcol ) ; \end{verbatim} \index{Chv_quasimax@{\tt Chv\_quasimax()}} This method searches for a {\it quasimax} entry in the $(1,1)$ block, an entry $a_{i,j}$ that has largest magnitude of the tagged entries in row $i$ and column $j$. An entry $a_{i,j}$ is {\it tagged} when {\tt rowmark[i] = tag} and {\tt colmark[j] = tag}. On return, {\tt *pirow} is filled with the row id and {\tt *pjcol} is filled with the column id of the quasimax entry. The return value is the magnitude of the entry. \par \noindent {\it Error checking:} If {\tt chv}, {\tt rowmark}, {\tt colmark}, {\tt pirow} or {\tt pjcol} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_fastBunchParlettPivot ( Chv *chv, int mark[], int tag, int *pirow, int *pjcol ) ; \end{verbatim} \index{Chv_fastBunchParlettPivot@{\tt Chv\_fastBunchParlettPivot()}} This method is used only for a symmetric or hermitian object and finds a $1 \times 1$ or $2 \times 2$ pivot that is suitable for elimination. Only pivots from the $(1,1)$ block can be chosen. A diagonal element $a_{r,r}$ with maximum magnitude is first found using the {\tt Chv\_maxabsInDiagonal11()} method. We then find the element $a_{r,k}$ in that row that has a maximum magnitude. If $|a_{r,r}| > 0.6404 |a_{r,k}|$ then we accept the $1 \times 1$ pivot element. Otherwise we look for an offdiagonal element that is largest in its row and column and return it as a $2 \times 2$ pivot. \par \noindent {\it Error checking:} If {\tt chv}, {\tt mark}, {\tt pirow} or {\tt pjcol} is {\tt NULL}, an error message is printed and the method returns. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Pivot methods} \label{subsection:Chv:proto:pivot} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_findPivot ( Chv *chv, DV *workDV, double tau, int ndelay, int *pirow, int *pjcol, int *pntest ) ; \end{verbatim} \index{Chv_findPivot@{\tt Chv\_findPivot()}} This method finds and tests a pivot, where if it were used at the next elimination step, each entry in $L$ and $U$ would have magnitude less than or equal to {\tt tau}. The {\tt workDV} object is used for workspace, it is resized as necessary. The {\tt ndelay} parameter allows one to specify the number of leading rows and columns to ignore, useful when delayed rows and columns have been placed in the leading portion of the chevron. The {\tt pirow}, {\tt pjcol} and {\tt pntest} addresses are filled with the pivot row, pivot column, and number of pivot tests performed to find the pivot. If no pivot was found, {\tt pirow} and {\tt pjcol} are filled with {\tt -1}. The return value is the size of the pivot. If the chevron is symmetric, we can find a $1 \times 1$ or $2 \times 2$ pivot. If the chevron is nonsymmetric, we only find a $1 \times 1$ pivot. A return value of zero means that no pivot was found. \par \noindent {\it Error checking:} If {\tt chv}, {\tt workDV}, {\tt pirow}, {\tt pjcol} or {\tt pntest} is {\tt NULL}, or if ${\tt tau} < 1.0$, or if ${\tt ndelay} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Update methods} \label{subsection:Chv:proto:updates} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_updateS ( Chv *chv, SubMtx *mtxD, SubMtx *mtxU, DV *tempDV ) ; void Chv_updateH ( Chv *chv, SubMtx *mtxD, SubMtx *mtxU, DV *tempDV ) ; void Chv_updateN ( Chv *chv, SubMtx *mtxL, SubMtx *mtxD, SubMtx *mtxU, DV *tempDV ) ; \end{verbatim} \index{Chv_updateS@{\tt Chv\_updateS()}} \index{Chv_updateH@{\tt Chv\_updateH()}} \index{Chv_updateN@{\tt Chv\_updateN()}} These methods perform an update to a chevron during the factorization. For a symmetric chevron, we compute \begin{eqnarray*} T_{J \cap \bnd{I},J \cap \bnd{I}} & := & T_{J \cap \bnd{I},J \cap \bnd{I}} - U_{I,J \cap \bnd{I}}^T D_{I,I} U_{I, J \cap \bnd{I}} \\ T_{J \cap \bnd{I},\bnd{J} \cap \bnd{I}} & := & T_{J \cap \bnd{I},\bnd{J} \cap \bnd{I}} - U_{I,J \cap \bnd{I}}^T D_{I,I} U_{I, \bnd{J} \cap \bnd{I}} \end{eqnarray*} where $D$ is diagonal or block diagonal with $1 \times 1$ and/or symmetric $2 \times 2$ pivots. $U$ is stored by sparse or dense columns. For a Hermitian chevron, we compute \begin{eqnarray*} T_{J \cap \bnd{I},J \cap \bnd{I}} & := & T_{J \cap \bnd{I},J \cap \bnd{I}} - U_{I,J \cap \bnd{I}}^H D_{I,I} U_{I, J \cap \bnd{I}} \\ T_{J \cap \bnd{I},\bnd{J} \cap \bnd{I}} & := & T_{J \cap \bnd{I},\bnd{J} \cap \bnd{I}} - U_{I,J \cap \bnd{I}}^H D_{I,I} U_{I, \bnd{J} \cap \bnd{I}} \end{eqnarray*} where $D$ is diagonal or block diagonal with $1 \times 1$ and/or Hermitian $2 \times 2$ pivots. $U$ is stored by sparse or dense columns. For a nonsymmetric chevron, we compute \begin{eqnarray*} T_{J \cap \bnd{I},J \cap \bnd{I}} & := & T_{J \cap \bnd{I},J \cap \bnd{I}} - L_{J \cap \bnd{I},I} D_{I,I} U_{I, J \cap \bnd{I}} \\ T_{J \cap \bnd{I},\bnd{J} \cap \bnd{I}} & := & T_{J \cap \bnd{I},\bnd{J} \cap \bnd{I}} - L_{J \cap \bnd{I},I} D_{I,I} U_{I, \bnd{J} \cap \bnd{I}} \\ T_{\bnd{J} \cap \bnd{I},J \cap \bnd{I}} & := & T_{\bnd{J} \cap \bnd{I},J \cap \bnd{I}} - L_{\bnd{J} \cap \bnd{I},I} D_{I,I} U_{I, J \cap \bnd{I}} \end{eqnarray*} where $D$ is diagonal, $L$ is stored by sparse or dense rows, and $U$ is stored by sparse or dense columns. {\tt tempDV} is a temporary working vector whose storage is resized as necessary. \par \noindent {\it Error checking:} If {\tt chvT}, {\tt mtxL}, {\tt mtxD}, {\tt mtxU} or {\tt tempDV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Assembly methods} \label{subsection:Chv:proto:assembly} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_addChevron ( Chv *chv, double alpha[], int ichv, int chvsize, int chvind[], double chvent[] ) ; \end{verbatim} \index{Chv_addChevron@{\tt Chv\_addChevron()}} This method is used to assemble entries from the matrix pencil $A + \sigma B$ into the block chevron object. Typically the entries from $A$ or $B$ will come from a {\tt InpMtx} object, one of whose modes of storage is by single {\tt chevrons}. The value {\tt ichv} is the row and column location of the diagonal entry. The indices found in {\tt chvind[]} are {\it offsets}. Let {\tt off = chvind[ii]} be the offset for one of the chevron's entries. If $\mbox{\tt off} \ge 0$, then the entry is found in location {\tt (ichv, ichv+off)} of the matrix. If $\mbox{\tt off} < 0$, then the entry is found in location {\tt (ichv-off, ichv)} of the matrix. The value(s) in {\tt alpha[]} form a scalar used to scale the entire chevron for its assembly. A call to assemble entries in $A$ (from the pencil $A + \sigma B$) would have {\tt alpha[] = (1.0,0.0)}; to assemble entries in $B$ (from the pencil $A + \sigma B$) would have $\mbox{\tt alpha[]} = (Real(\sigma),Imag(\sigma))$. \par \noindent {\it Error checking:} If {\tt chv}, {\tt chvind}, {\tt chvent} or {\tt alpha} is {\tt NULL}, or if {\tt ichv} or {\tt chvsize} are less than zero, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_assembleChv ( Chv *chvJ, Chv *chvI ) ; \end{verbatim} \index{Chv_assembleChv@{\tt Chv\_assembleChv()}} This method is used to assemble entries from one {\tt Chv} object into another. The application is during a factorization with pivoting, postponed entries from the children are stored in the {\tt chvI Chv} object and need to be assembled into the final working front, along with all updates from the descendents (which are stored in the {\tt chvJ Chv} object. Note, the row and column indices of {\tt chvI} {\it must nest} with those of {\tt chvJ}. \par \noindent {\it Error checking:} If {\tt chvI} or {\tt chvJ} is {\tt NULL}, or if their {\tt symflag} fields are not identical, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_assemblePostponedData ( Chv *newchv, Chv *oldchv, Chv *firstchild ) ; \end{verbatim} \index{Chv_assemblePostponedData@{\tt Chv\_assemblePostponedData()}} This method is used to assemble a {\tt Chv} object for a front ({\tt oldchv}) along with any postponed data from the children (objects are held in a list where {\tt firstchild} is the head) into a {\tt Chv} object {\tt newchv}. The return value is the number of delayed rows and columns from the children fronts which are found in the leading rows and columns of the chevron. \par \noindent {\it Error checking:} If {\tt newchv}, {\tt oldchv} or {\tt firstchild} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Factorization methods} \label{subsection:Chv:proto:factor} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_factorWithPivoting ( Chv *chv, int ndelay, int pivotflag, IV *pivotsizesIV, DV *workDV, double tau, int *pntest ) ; \end{verbatim} \index{Chv_factorWithPivoting@{\tt Chv\_factorWithPivoting()}} This method factors a front using pivoting for numerical stability. The number of rows and columns that have been delayed (assembled from the children) is given by {\tt ndelay}, this allows the method that finds the pivots to skip over these rows and columns since no pivot can be found there. When pivoting is enabled ({\tt pivotflag} is {\tt SPOOLES\_PIVOTING}), the {\tt workDV} object used during the search process for pivots must be non-{\tt NULL}, {\tt tau} is the upper bound on factor entries, and {\tt pivotsizesIV} must be non-{\tt NULL} when the front is symmetric or Hermitian. The address {\tt pntest} is incremented with the number of pivot tests by the {\tt Chv\_findPivot()} method. The return value is the number of eliminated rows and columns. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, or if {\tt pivotflag} is not valid, or if {\tt ndelay} is negative, or if {\tt pivotflag == SPOOLES\_PIVOTING} and {\tt workDV} is {\tt NULL} or {\tt tau} is less than {\tt 1.0}, or if the chevron is symmetric or Hermitian, {\tt pivotflag == SPOOLES\_PIVOTING} and {\tt pivotsizesIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_factorWithNoPivoting ( Chv *chv, PatchAndGoInfo *info ) ; \end{verbatim} \index{Chv_factorWithNoPivoting@{\tt Chv\_factorWithNoPivoting()}} This method factors a front without using pivoting for numerical stability. It does support ``patch-and-go'' functionality, where if a small or zero entry is found in the diagonal element that is to be eliminated, some action can be taken. The return value is the number of eliminated rows and columns. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_r1upd ( Chv *chv ) ; \end{verbatim} \index{Chv_r1upd@{\tt Chv\_r1upd()}} This method is used during the factorization of a front, performing a rank-one update of the chevron. The return value is {\tt 1} if the pivot is nonzero, {\tt 0} otherwise. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_r2upd ( Chv *chv ) ; \end{verbatim} \index{Chv_r2upd@{\tt Chv\_r2upd()}} This method is used during the factorization of a front, performing a rank-two update of the chevron. The return value is {\tt 1} if the pivot is nonsingular, {\tt 0} otherwise. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, or if the chevron is nonsymmetric, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_maxabsInChevron ( Chv *chv, int ichv, double *pdiagmaxabs, *prowmaxabs, *pcolmaxabs ) ; \end{verbatim} \index{Chv_maxabsInChevron@{\tt Chv\_maxabsInChevron()}} This method is used during the factorization of a front with a ``patch-and-go'' strategy. On return, {\tt *pdiagmaxabs} contains the magnitude of the diagonal entry for the chevron, {\tt *prowmaxabs} contains the maximum magnitude of the entries in the row of the chevron, and {\tt *pcolmaxabs} contains the maximum magnitude of the entries in the column of the chevron. \par \noindent {\it Error checking:} If {\tt chv}, {\tt pdiagmaxabs}, {\tt prowmaxabs} or {\tt pcolmaxabs} is {\tt NULL}, or if {\tt ichv} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_zeroOffdiagonalOfChevron ( Chv *chv, int ichv ) ; \end{verbatim} \index{Chv_zeroOffdiagonalOfChevron@{\tt Chv\_zeroOffdiagonalOfChevron()}} This method is used during the factorization of a front with a ``patch-and-go'' strategy. On return, the offdiagonal entries of chevron {\tt ichv} have been set to zero. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, or if {\tt ichv} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Copy methods} \label{subsection:Chv:proto:copy} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_countEntries ( Chv *chv, int npivot, int pivotsizes[], int countflag ) ; \end{verbatim} \index{Chv_countEntries@{\tt Chv\_countEntries()}} This method counts the number of entries in the chevron that are larger in magnitude than {\tt droptol}. {\tt countflag} has the following meaning. \begin{itemize} \item {\tt CHV\_STRICT\_LOWER} $\Longrightarrow$ count strict lower entries \item {\tt CHV\_DIAGONAL} $\Longrightarrow$ count diagonal entries \item {\tt CHV\_STRICT\_UPPER} $\Longrightarrow$ count strict upper entries \item {\tt CHV\_STRICT\_LOWER\_11} $\Longrightarrow$ count strict lower entries in the (1,1) block \item {\tt CHV\_LOWER\_21} $\Longrightarrow$ count lower entries in the (2,1) block \item {\tt CHV\_STRICT\_UPPER\_11} $\Longrightarrow$ count strict upper entries in the (1,1) block \item {\tt CHV\_UPPER\_12} $\Longrightarrow$ count upper entries in the (1,2) block \end{itemize} This method is used to compute the necessary storage to store a chevron as a dense front. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL} or if {\tt countflag} is not valid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_countBigEntries ( Chv *chv, int npivot, int pivotsizes[], int countflag, double droptol ) ; \end{verbatim} \index{Chv_countBigEntries@{\tt Chv\_countBigEntries()}} This method counts the number of entries in the chevron that are larger in magnitude than {\tt droptol}. {\tt countflag} has the following meaning. \begin{itemize} \item {\tt CHV\_STRICT\_LOWER} $\Longrightarrow$ count strict lower entries \item {\tt CHV\_STRICT\_UPPER} $\Longrightarrow$ count strict upper entries \item {\tt CHV\_STRICT\_LOWER\_11} $\Longrightarrow$ count strict lower entries in the (1,1) block \item {\tt CHV\_LOWER\_21} $\Longrightarrow$ count lower entries in the (2,1) block \item {\tt CHV\_STRICT\_UPPER\_11} $\Longrightarrow$ count strict upper entries in the (1,1) block \item {\tt CHV\_UPPER\_12} $\Longrightarrow$ count upper entries in the (1,2) block \end{itemize} This method is used to compute the necessary storage to store a chevron as a sparse front. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL} or if {\tt countflag} is not valid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_copyEntriesToVector ( Chv *chv, int npivot, int pivotsizes[], int length, double dvec[], int copyflag, int storeflag) ; \end{verbatim} \index{Chv_copyEntriesToVector@{\tt Chv\_copyEntriesToVector()}} This method copies some entries the chevron object into a double precision vector. This method is called after a front has been factored and is used to store the factor entries into the storage for the factor matrix. If the front is nonsymmetric, the front contains entries of $L$, $D$ and $U$, where $D$ is diagonal. If the front is symmetric or Hermitian, the front contains entries of $D$ and $U$, and $D$ is diagonal if {\tt pivotsizesIV} is {\tt NULL} or may contain a mixture of $1 \times 1$ and $2 \times 2$ pivots otherwise. {\tt copyflag} has the following meaning. \begin{itemize} \item {\tt CHV\_STRICT\_LOWER} $\Longrightarrow$ copy strict lower entries \item {\tt CHV\_DIAGONAL} $\Longrightarrow$ copy diagonal entries \item {\tt CHV\_STRICT\_UPPER} $\Longrightarrow$ copy strict upper entries \item {\tt CHV\_STRICT\_LOWER\_11} $\Longrightarrow$ copy strict lower entries in the (1,1) block \item {\tt CHV\_LOWER\_21} $\Longrightarrow$ copy lower entries in the (2,1) block \item {\tt CHV\_STRICT\_UPPER\_11} $\Longrightarrow$ copy strict upper entries in the (1,1) block \item {\tt CHV\_UPPER\_12} $\Longrightarrow$ copy upper entries in the (1,2) block \end{itemize} \par %% The {\tt DFrontMtx} object presently stores the entries in $U$ %% by columns and the entries in $L$ by rows. %% This allows us to use dot product kernels during the factorization. %% On other architectures it may be more efficient to have {\tt axpy} %% kernels, in which the entries in $U$ would be stored by rows and %% the entries in $L$ stored by columns. %% This method supports both formats, where If {\tt storeflag} is {\tt CHV\_BY\_ROWS}, the entries are stored by rows and if {\tt storeflag} is {\tt CHV\_BY\_COLUMNS}, the entries are stored by columns. \par \noindent {\it Error checking:} If {\tt chv} or {\tt dvec} is {\tt NULL} or if {\tt length} is less than the number of entries to be copied, or if {\tt copyflag} or {\tt storeflag} is valid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_copyBigEntriesToVector ( Chv *chv, int npivot, int pivotsizes[], int sizes[], int ivec[], double dvec[], int copyflag, int storeflag, double droptol ) ; \end{verbatim} \index{Chv_copyBigEntriesToVector@{\tt Chv\_copyBigEntriesToVector()}} This method also copies some entries the chevron object into a double precision vector, but only those entries whose magnitude is greater than or equal to {\tt droptol} are copied. This method is called after a front has been factored and is used to store the factor entries of large magnitude into the storage for the factor matrix. If the front is nonsymmetric, the front contains entries of $L$, $D$ and $U$, where $D$ is diagonal. If the front is symmetric, the front contains entries of $D$ and $U$, and $D$ is diagonal if {\tt pivotsizesIV} is {\tt NULL} or may contain a mixture of $1 \times 1$ and $2 \times 2$ pivots otherwise. {\tt copyflag} has the following meaning. \begin{itemize} \item {\tt CHV\_STRICT\_LOWER} $\Longrightarrow$ copy strict lower entries \item {\tt CHV\_STRICT\_UPPER} $\Longrightarrow$ copy strict upper entries \item {\tt CHV\_STRICT\_LOWER\_11} $\Longrightarrow$ copy strict lower entries in the (1,1) block \item {\tt CHV\_LOWER\_21} $\Longrightarrow$ copy lower entries in the (2,1) block \item {\tt CHV\_STRICT\_UPPER\_11} $\Longrightarrow$ copy strict upper entries in the (1,1) block \item {\tt CHV\_UPPER\_12} $\Longrightarrow$ copy upper entries in the (1,2) block \end{itemize} \par % The {\tt DFrontMtx} object presently stores the entries in $U$ % by columns and the entries in $L$ by rows. % This allows us to use dot product kernels during the factorization. % On other architectures it may be more efficient to have {\tt axpy} % kernels, in which the entries in $U$ would be stored by rows and % the entries in $L$ stored by columns. % This method supports both formats, where If {\tt storeflag} is {\tt CHV\_BY\_ROWS}, the entries are stored by rows and if {\tt storeflag} is {\tt CHV\_BY\_COLUMNS}, the entries are stored by columns. \par When we store the large entries in the columns of $U$, {\tt sizes[jcol]} contains the number of large entries in column {\tt jcol}. The vectors {\tt ivec[]} and {\tt dvec[]} contain the row indices and the entries that are stored. When we store the large entries in the rows of $L$, {\tt sizes[irow]} contains the number of large entries in column {\tt irow}. The vectors {\tt ivec[]} and {\tt dvec[]} contain the column indices and the entries that are stored. Presently there is no checking that {\tt sizes[]}, {\tt ivec[]} and {\tt dvec[]} are large enough to store the sizes, indices and entries. The large entry count can be obtained using the method {\tt Chv\_countBigEntries()}. \par \noindent {\it Error checking:} If {\tt chv} or {\tt dvec} is {\tt NULL} or if {\tt length} is less than the number of entries to be copied, or if {\tt copyflag} or {\tt storeflag} is not valid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_copyTrailingPortion ( Chv *chvI, Chv *chvJ, int offset ) ; \end{verbatim} \index{Chv_copyTrailingPortion@{\tt Chv\_copyTrailingPortion()}} This method copies the trailing portion of {\tt chvJ} into {\tt chvI}. The first {\tt offsets} chevrons are not copied, the remainder are copied. This method is used to extract the delayed entries from a front which has been factored. \par \noindent {\it Error checking:} If {\tt chvI} or {\tt chvJ} is {\tt NULL}, or if ${\tt offset} < 0$ or {\tt offset} is greater than the number of chevrons in {\tt chvJ}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Swap methods} \label{subsection:Chv:proto:swap} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_swapRows ( Chv *chv, int irow, int jrow ) ; \end{verbatim} \index{Chv_swapRows@{\tt Chv\_swapRows()}} This method swaps rows {\tt irow} and {\tt jrow} of the chevron. Both rows must be less than the width {\tt nD} of the chevron. The row ids of the two rows are also swapped. If the chevron is symmetric, then the method {\tt Chv\_swapRowsAndColumns()} is called. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL} or if {\tt irow} or {\tt jrow} are less than 0 or greater than or equal to {\tt nD}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_swapColumns ( Chv *chv, int icol, int jcol ) ; \end{verbatim} \index{Chv_swapColumns@{\tt Chv\_swapColumns()}} This method swaps columns {\tt icol} and {\tt jcol} of the chevron. Both columns must be less than the width {\tt nD} of the chevron. The column ids of the two columns are also swapped. If the chevron is symmetric, then the method {\tt Chv\_swapRowsAndColumns()} is called. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL} or if {\tt icol} or {\tt jcol} are less than 0 or greater than or equal to {\tt nD}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_swapRowsAndColumns ( Chv *chv, int ii, int jj ) ; \end{verbatim} \index{Chv_swapRowsAndColumns@{\tt Chv\_swapRowsAndColumns()}} This method swaps rows and columns {\tt ii} and {\tt jj} of the chevron. Both must be less than the width {\tt nD} of the chevron. The row and/or column ids are also swapped. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL} or if {\tt ii} or {\tt jj} are less than 0 or greater than or equal to {\tt nD}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:Chv:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_nbytesNeeded ( int nD, int nL, int nU, int type, int symflag ) ; \end{verbatim} \index{Chv_nbytesNeeded@{\tt Chv\_nbytesNeeded()}} This method returns the number of bytes necessary to store an object with the given dimensions and type in its workspace. \par \noindent {\it Error checking:} If {\tt nD}, {\tt nL}, or {\tt nU} is less than zero, or if {\tt type} or {\tt symflag} are not valid, % or if {\tt type} is not {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, % or if {\tt symflag} is not {\tt SPOOLES\_SYMMETRIC}, % {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Chv_nbytesInWorkspace ( Chv *chv ) ; \end{verbatim} \index{Chv_nbytesInWorkspace@{\tt Chv\_nbytesInWorkspace()}} This method returns the number of bytes in the workspace. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_setNbytesInWorkspace ( Chv *chv, int nbytes ) ; \end{verbatim} \index{Chv_setNbytesInWorkspace@{\tt Chv\_setNbytesInWorkspace()}} This method sets the number of bytes in the workspace. If {\tt nbytes} is less than the number of present bytes in the workspace, the workspace is not shrunk. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_setFields ( Chv *chv, int id, int nD, int nL, int nU, int type, int symflag ) ; \end{verbatim} \index{Chv_setFields@{\tt Chv\_setFields()}} This method sets the scalar fields and {\tt rowind}, {\tt colind} and {\tt entries} pointers. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, or if ${\tt nD} \le 0$, or if {\tt nL} or {\tt nU} are less than zero, or if {\tt type} or {\tt symflag} are not valid, % or if {\tt type} is not {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, % or if {\tt symflag} is not {\tt SPOOLES\_SYMMETRIC}, % {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_shift ( Chv *chv, int shift ) ; \end{verbatim} \index{Chv_shift@{\tt Chv\_shift()}} This method is used to shift the base of the entries and adjust dimensions of the {\tt Chv} object. If {\tt shift} is positive, the first {\tt shift} chevrons are removed from the chevron. If {\tt shift} is negative, the {\tt shift} previous chevrons are prepended to the chevron. This is a dangerous method as it changes the state of the object. We use it during the factorization of a front, where one {\tt Chv} object points to the entire chevron in order to swap rows and columns, while another chevron points to the uneliminated rows and columns of the front. It is the latter chevron that is shifted during the factorization. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_fill11block ( Chv *chv, A2 *mtx ) ; \end{verbatim} \index{Chv_fill11block@{\tt Chv\_fill11block()}} This method is used to fill a {\tt A2} dense matrix object with the entries in the $(1,1)$ block of the chevron. \par \noindent {\it Error checking:} If {\tt chv} or {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_fill12block ( Chv *chv, A2 *mtx ) ; \end{verbatim} \index{Chv_fill12block@{\tt Chv\_fill12block()}} This method is used to fill a {\tt A2} dense matrix object with the entries in the $(1,2)$ block of the chevron. \par \noindent {\it Error checking:} If {\tt chv} or {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_fill21block ( Chv *chv, A2 *mtx ) ; \end{verbatim} \index{Chv_fill21block@{\tt Chv\_fill21block()}} This method is used to fill a {\tt A2} dense matrix object with the entries in the $(2,1)$ block of the chevron. \par \noindent {\it Error checking:} If {\tt chv} or {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double Chv_maxabs ( Chv *chv ) ; \end{verbatim} \index{Chv_maxabs@{\tt Chv\_maxabs()}} This method returns the magnitude of the entry of largest magnitude in the object. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double Chv_frobNorm ( Chv *chv ) ; \end{verbatim} \index{Chv_frobNorm@{\tt Chv\_frobNorm()}} This method returns the Frobenius norm of the chevron. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_sub ( Chv *chvJ, Chv *chvI ) ; \end{verbatim} \index{Chv_sub@{\tt Chv\_sub()}} This method subtracts {\tt chvI} from {\tt chvJ}. \par \noindent {\it Error checking:} If {\tt chvJ} or {\tt chvI} is {\tt NULL}, or if their dimensions are not the same, or if either of their {\tt entries} fields are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_zero ( Chv *chv ) ; \end{verbatim} \index{Chv_zero@{\tt Chv\_zero()}} This method zeroes the entries in the chevron. \par \noindent {\it Error checking:} If {\tt chv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:Chv:proto:IO} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_writeForHumanEye ( Chv *chv, FILE *fp ) ; \end{verbatim} \index{Chv_writeForHumanEye@{\tt Chv\_writeForHumanEye()}} \par This method writes a {\tt Chv} object to a file in an easily readable format. \par \noindent {\it Error checking:} If {\tt chv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_writeForMatlab ( Chv *chv, char *chvname, FILE *fp ) ; \end{verbatim} \index{Chv_writeForMatlab@{\tt Chv\_writeForMatlab()}} \par This method writes a {\tt Chv} object to a file in a matlab format. For a real chevron, a sample line is \begin{verbatim} a(10,5) = -1.550328201511e-01 ; \end{verbatim} where chvname = {\tt "a"}. For a complex chevron, a sample line is \begin{verbatim} a(10,5) = -1.550328201511e-01 + 1.848033378871e+00*i; \end{verbatim} where chvname = {\tt "a"}. The matrix indices come from the {\tt rowind[]} and {\tt colind[]} vectors, and are incremented by one to follow the Matlab and FORTRAN convention. \par \noindent {\it Error checking:} If {\tt chv}, {\tt chvname} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par label{subsection:Chv:proto:swap} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Chv_swapRows ( Chv *chv, int irow, int jrow ) ; \end{verbatim} \index{Chv_swapRows@{\tt Chv\_swapRows()}} This method swaps rows {\tt irow} and {\tt jrow} of theChv/doc/drivers.tex010064400020550007177000000424010657126731600155740ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt Chv object}} \label{section:Chv:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} test_addChevron msglvl msgFile nD nU type symflag seed alphareal alphaimag \end{verbatim} This driver program tests the {\tt Chv\_addChevron} method. Use the script file {\tt do\_addChevron} for testing. When the output file is loaded into matlab, the last line to the screen is the error of the assembly. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nD} parameter is the number of rows and columns in the (1,1) block. \item The {\tt nU} parameter is the number of columns in the (1,2) block. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt symflag} parameter is the symmetry flag --- {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item The {\tt seed} parameter is a random number seed. \item The {\tt alphareal} and {\tt alphaimag} parameters form a complex number that is a scaling parameter. Normally {\tt alpha} is (1.0,0.0), when we are just loading matrix entries into a front. However, when we factor $A + \alpha B$, the entries of $B$ will be loaded with {\tt alpha} set equal to $\alpha[0:1]$. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_assmbChv msglvl msgFile nDJ nUJ nDI nUI type symflag seed \end{verbatim} This driver program tests the {\tt Chv\_assembleChv} method. It assembles a chevron $T_I$ into $T_J$, as is done during the assembly of postponed rows and columns during the factorization when pivoting is enabled. Use the script file {\tt do\_assmbChv} for testing. When the output file is loaded into matlab, the last line to the screen is the error of the assembly. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nDJ} parameter is the number of rows and columns in the (1,1) block of $T_J$. \item The {\tt nUJ} parameter is the number of columns in the (1,2) block of $T_J$. \item The {\tt nDI} parameter is the number of rows and columns in the (1,1) block of $T_I$. \item The {\tt nUI} parameter is the number of columns in the (1,2) block of $T_I$. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt symflag} parameter is the symmetry flag --- {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_copyEntriesToVector msglvl msgFile nD nU type symflag pivotingflag storeflag seed \end{verbatim} This driver program tests the {\tt Chv\_copyEntriesToVector} method which is used when after a front has been factored to store the entries into dense $L$ and $U$ submatrices. Use the script file {\tt do\_copyEntriesToVector} for testing. When the output file is loaded into matlab, the last line to the screen is a matrix that contains two entries. If the program executes correctly, these two entries should be exactly zero. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nD} parameter is the number of rows and columns in the (1,1) block. \item The {\tt nU} parameter is the number of columns in the (1,2) block. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt symflag} parameter is the symmetry flag --- {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item The {\tt pivotingflag} parameter is the pivoting flag --- {\tt SPOOLES\_NO\_PIVOTING} for no pivoting, {\tt SPOOLES\_PIVOTING} for pivoting. \item The {\tt storeflag} parameter is the storage flag, to store by rows, use {\tt SPOOLES\_BY\_ROWS}, to store by columns, use {\tt SPOOLES\_BY\_COLUMNS}. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_copyBigEntriesToVector msglvl msgFile nD nU type symflag pivotingflag storeflag seed droptol \end{verbatim} This driver program tests the {\tt Chv\_copyBigEntriesToVector} method which is used when after a front has been factored to store the entries into sparse $L$ and $U$ submatrices. Use the script file {\tt do\_copyBigEntriesToVector} for testing. When the output file is loaded into matlab, the last line to the screen is a matrix that contains three entries. The first two are the maximum magnitudes of the entries that were not copied (two different ways), and the third is the drop tolerance. If the program executes correctly, the third term is larger than the first two. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nD} parameter is the number of rows and columns in the (1,1) block. \item The {\tt nU} parameter is the number of columns in the (1,2) block. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt symflag} parameter is the symmetry flag --- {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item The {\tt pivotingflag} parameter is the pivoting flag --- {\tt SPOOLES\_NO\_PIVOTING} for no pivoting, {\tt SPOOLES\_PIVOTING} for pivoting. \item The {\tt storeflag} parameter is the storage flag, to store by rows, use {\tt SPOOLES\_BY\_ROWS}, to store by columns, use {\tt SPOOLES\_BY\_COLUMNS}. \item The {\tt seed} parameter is a random number seed. \item The {\tt droptol} parameter is a drop tolerance parameters, entries whose magnitude is smaller than {\tt droptol} are not copied. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_factor msglvl msgFile nD nU type symflag pivotingflag seed tau \end{verbatim} This driver program tests the {\tt Chv\_factor} method. Use the script file {\tt do\_factor} for testing. When the output file is loaded into matlab, the last line to the screen is a matrix that contains three entries. The first entry is the error in the factorization. The second and third entries are the maximum magnitudes of the entries in $L$ and $U$, respectively. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nD} parameter is the number of rows and columns in the (1,1) block. \item The {\tt nU} parameter is the number of columns in the (1,2) block. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt symflag} parameter is the symmetry flag --- {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item The {\tt pivotingflag} parameter is the pivoting flag --- {\tt SPOOLES\_NO\_PIVOTING} for no pivoting, {\tt SPOOLES\_PIVOTING} for pivoting. \item The {\tt seed} parameter is a random number seed. \item The {\tt tau} parameter is used when pivoting is enabled. All entries in $L$ and $U$ will have magnitudes less than {\tt tau}. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_findPivot msglvl msgFile nD nU type symflag seed tau \end{verbatim} This driver program tests the {\tt Chv\_findPivot} method. Use the script file {\tt do\_findPivot} for testing. When the output file is loaded into matlab, look on the screen for the variables {\tt maxerrupd} (the error in the factor and update), {\tt ubound} (the maximum magnitude of the entries in $U$), and if nonsymmetric {\tt lbound} (the maximum magnitude of the entries in $L$). \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nD} parameter is the number of rows and columns in the (1,1) block. \item The {\tt nU} parameter is the number of columns in the (1,2) block. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt symflag} parameter is the symmetry flag --- {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item The {\tt seed} parameter is a random number seed. \item The {\tt tau} parameter is used when pivoting is enabled. All entries in $L$ and $U$ will have magnitudes less than {\tt tau}. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_maxabs msglvl msgFile nD nU type symflag seed \end{verbatim} This driver program tests the {\tt Chv\_maxabsInRow()}, {\tt Chv\_maxabsInRow11()}, {\tt Chv\_maxabsInColumn()}, {\tt Chv\_maxabsInColumn11()} and {\tt Chv\_maxabsInDiagonal11()} methods. Use the script file {\tt do\_maxabs} for testing. When the output file is loaded into matlab, look on the screen for the variables {\tt rowerror}, {\tt colerror}, {\tt rowerror11}, {\tt colerror11} and {\tt diag11error}. All should be zero. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nD} parameter is the number of rows and columns in the (1,1) block. \item The {\tt nU} parameter is the number of columns in the (1,2) block. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt symflag} parameter is the symmetry flag --- {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item The {\tt pivotingflag} parameter is the pivoting flag --- {\tt SPOOLES\_NO\_PIVOTING} for no pivoting, {\tt SPOOLES\_PIVOTING} for pivoting. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_r1upd msglvl msgFile nD nU type symflag seed \end{verbatim} This driver program tests the {\tt Chv\_r1upd()} method. Use the script file {\tt do\_r1upd} for testing. When the output file is loaded into matlab, the last line is the error of the update. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nD} parameter is the number of rows and columns in the (1,1) block. \item The {\tt nU} parameter is the number of columns in the (1,2) block. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt symflag} parameter is the symmetry flag --- {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_r2upd msglvl msgFile nD nU type symflag seed \end{verbatim} This driver program tests the {\tt Chv\_r2upd()} method. Use the script file {\tt do\_r2upd} for testing. When the output file is loaded into matlab, the last line is the error of the update. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nD} parameter is the number of rows and columns in the (1,1) block. \item The {\tt nU} parameter is the number of columns in the (1,2) block. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt symflag} parameter is the symmetry flag --- {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_swap msglvl msgFile nD nU type symflag seed \end{verbatim} This driver program tests three methods: {\tt Chv\_swapRowsAndColumns()}, {\tt Chv\_swapRows()} and {\tt Chv\_swapColumns()}. Use the script file {\tt do\_swap} for testing. When the output file is loaded into matlab, look for the {\tt maxerrrowswap1}, {\tt maxerrcolswap1}, {\tt maxerrswap}, {\tt maxerrsymswap1} and {\tt maxerrsymswap2} values. All should be zero. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nD} parameter is the number of rows and columns in the (1,1) block. \item The {\tt nU} parameter is the number of columns in the (1,2) block. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt symflag} parameter is the symmetry flag --- {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_update msglvl msgFile type symflag sparsityflag ncolT ncolU nrowD nentU offset seed \end{verbatim} This driver program tests the {\tt Chv\_updateH()}, {\tt Chv\_updateS()} and {\tt Chv\_updateN()} methods. The {\tt Chv} object $T$ is updated by $-U^TDU$, $-U^HDU$ or $-LDU$, depending on whether $T$ is symmetric, hermitian or nonsymmetric. Use the script file {\tt do\_update} for testing. When the output file is loaded into matlab, the last line is the error in the update which should be zero. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter denotes the type of entries --- {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX} \item The {\tt symflag} parameter is the symmetry flag --- {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item The {\tt sparsityflag} parameter should be zero for dense $U$ and $L$, or 1 for sparse $U$ and $L$. \item The {\tt ncolT} parameter is the number of columns in the (1,1) and (1,2) blocks of $T$. \item The {\tt nDT} parameter is the number of rows and columns in the (1,1) block of $T$. \item The {\tt ncolU} parameter is the number of columns in $U$. \item The {\tt nrowD} parameter is the number of rows and columns in $D$. \item The {\tt nentU} parameter is the number entries in $U$, ignored if {\tt sparsityflag = 0}. \item The {\tt offset} parameter is the offset of first index in $T$ from the last index in $D$. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} le {\tt do\_factor} for testing. When the output file is loaded into matlab, the last line to the screen is a matrix that contains three entries. The first entry is the error in the factorization. The second and third entries are the maximum magnitudes ofChv/doc/temp.tex010064400020550007177000000051250657126731600150650ustar00clevecompmath00000400000006% % main TeX file % \documentstyle[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \newcommand{\bnd}{{\partial}} \renewcommand{\Re}{{\mbox{Re}}} \renewcommand{\Im}{{\mbox{Im}}} \input psfig \makeindex \begin{document} $$ \left \lbrack \begin{array}{cc} x & y \\ \overline{y} & z \end{array} \right \rbrack \left \lbrack \begin{array}{c} u_{1,j} \\ u_{2,j} \end{array} \right \rbrack = \left \lbrack \begin{array}{c} a_{1,j} \\ a_{2,j} \end{array} \right \rbrack $$ Multiply on the left by the inverse of the pivot block. $$ \left \lbrack \begin{array}{c} u_{1,j} \\ u_{2,j} \end{array} \right \rbrack = \frac{1}{xz - y\overline{y}} \left \lbrack \begin{array}{cc} z & -y \\ -\overline{y} & x \end{array} \right \rbrack \left \lbrack \begin{array}{c} a_{1,j} \\ a_{2,j} \end{array} \right \rbrack = \frac{1}{xz - y\overline{y}} \left \lbrack \begin{array}{c} z a_{1,j} - y a_{2,j} \\ - \overline{y} a_{1,j} + x a_{2,j} \end{array} \right \rbrack $$ Look at each of the two entries in the rightmost vector. \begin{eqnarray*} z a_{1,j} - y a_{2,j} & = & \Re(z) ( \Re(a_{1,j}) + i\ \Im(a_{1,j}) ) - ( \Re(y) + i\ \Im(y) )( \Re(a_{2,j}) + i\ \Im(a_{2,I}) ) \\ & = & ( \Re(z) \Re(a_{1,j}) - \Re(y) \Re(a_{2,j}) + \Im(y) \Im(a_{2,I}) ) \\ & & \qquad +\ i( \Re(z) \Im(a_{1,j}) - \Re(y) \Im(a_{2,I}) - \Im(y) \Re(a_{2,j}) ) \\ - \overline{y} a_{1,j} + x a_{2,j} & = & -( \Re(y) - i \Im(y) ) ( \Re(a_{1,j}) + i \Im(a_{1,j}) ) + \Re(x) ( \Re(a_{2,j}) + i \Im(a_{2,I}) ) \\ & = & ( -\Re(y) \Re(a_{1,j}) - \Im(y) \Im(a_{1,j}) + x \Re(a_{2,j}) ) \\ & & \qquad + i\ ( -\Re(y) \Im(a_{1,j}) + \Im(y) \Re(a_{1,j}) + x \Im(a_{2,I}) ) \end{eqnarray*} \begin{eqnarray*} \Re(u_{1,j}) & = & \frac{ \Re(z) \Re(a_{1,j}) - \Re(y) \Re(a_{2,j}) + \Im(y) \Im(a_{2,j}) } { xz - y\overline{y} } \\ \Im(u_{1,j}) & = & \frac{ \Re(z) \Im(a_{1,j}) - \Re(y) \Im(a_{2,I}) - \Im(y) \Re(a_{2,j}) } { xz - y\overline{y} } \end{eqnarray*} Taking absolute values and use the triangle inequality. \begin{eqnarray*} \Re(u_{1,j}) & = & \left | \frac{ \Re(z) \Re(a_{1,j}) - \Re(y) \Re(a_{2,j}) + \Im(y) \Im(a_{2,j}) } { xz - y\overline{y} } \right | \\ & \le & \frac{ |\Re(z)|\ |\Re(a_{1,j})| + |\Re(y)|\ |\Re(a_{2,j})| + |\Im(y)|\ |\Im(a_{2,j})| } { \left | xz - y\overline{y} \right | } \\ \max_{j} |\Re(u_{1,j})| & \le & \frac{ |\Re(z)|\ \max_j|\Re(a_{1,j})| + |\Re(y)|\ \max_j|\Re(a_{2,j})| + |\Im(y)|\ \max_j|\Im(a_{2,j})| } { \left | xz - y\overline{y} \right | } \\ \end{eqnarray*} \end{document} Chv/doc/temp.log010064400020550007177000000025120657126731600150430ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 24 JAN 1998 13:38 **temp (temp.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) (/usr/local/lib/texmf/tex/generic/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen100 \p@intvaluey=\dimen101 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file temp.idx (temp.aux) [1 ] (temp.aux) ) Here is how much of TeX's memory you used: 397 strings out of 11977 3945 string characters out of 87269 37241 words of memory out of 262141 2344 multiletter control sequences out of 9500 18996 words of font info for 72 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 12i,9n,17p,149b,94s stack positions out of 300i,40n,60p,3000b,4000s Output written on temp.dvi (1 page, 4344 bytes). Chv/doc/temp.idx010064400020550007177000000000000657126731600150340ustar00clevecompmath00000400000006Chv/doc/temp.aux010064400020550007177000000000100657126731600150460ustar00clevecompmath00000400000006\relax Chv/doc/simple2.eps010064400020550007177000000041460657126731600154640ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 220.0 100.0 %%%EndComments /NumberFont /Helvetica findfont 7 scalefont def NumberFont setfont /CSH { dup stringwidth pop 2 div neg 2 rmoveto show } def gsave % % first chevron % 10 5 moveto (0) CSH 10 15 moveto (1) CSH 10 25 moveto (2) CSH 10 35 moveto (3) CSH 10 45 moveto (4) CSH 10 55 moveto (5) CSH 10 65 moveto (6) CSH 10 75 moveto (7) CSH 10 85 moveto (8) CSH 20 85 moveto (9) CSH 30 85 moveto (10) CSH 40 85 moveto (11) CSH 50 85 moveto (12) CSH 60 85 moveto (13) CSH 70 85 moveto (14) CSH 80 85 moveto (15) CSH 90 85 moveto (16) CSH % % second chevron % 20 5 moveto (17) CSH 20 15 moveto (18) CSH 20 25 moveto (19) CSH 20 35 moveto (20) CSH 20 45 moveto (21) CSH 20 55 moveto (22) CSH 20 65 moveto (23) CSH 20 75 moveto (24) CSH 30 75 moveto (25) CSH 40 75 moveto (26) CSH 50 75 moveto (27) CSH 60 75 moveto (28) CSH 70 75 moveto (29) CSH 80 75 moveto (30) CSH 90 75 moveto (31) CSH % % third chevron % 30 5 moveto (32) CSH 30 15 moveto (33) CSH 30 25 moveto (34) CSH 30 35 moveto (35) CSH 30 45 moveto (36) CSH 30 55 moveto (37) CSH 30 65 moveto (38) CSH 40 65 moveto (39) CSH 50 65 moveto (40) CSH 60 65 moveto (41) CSH 70 65 moveto (42) CSH 80 65 moveto (43) CSH 90 65 moveto (44) CSH 0 0 100 100 rectstroke grestore gsave 120 0 translate % % first chevron % 10 85 moveto (0) CSH 20 85 moveto (1) CSH 30 85 moveto (2) CSH 40 85 moveto (3) CSH 50 85 moveto (4) CSH 60 85 moveto (5) CSH 70 85 moveto (6) CSH 80 85 moveto (7) CSH 90 85 moveto (8) CSH % % second chevron % 20 75 moveto (9) CSH 30 75 moveto (10) CSH 40 75 moveto (11) CSH 50 75 moveto (12) CSH 60 75 moveto (13) CSH 70 75 moveto (14) CSH 80 75 moveto (15) CSH 90 75 moveto (16) CSH % % third chevron % 30 65 moveto (17) CSH 40 65 moveto (18) CSH 50 65 moveto (19) CSH 60 65 moveto (20) CSH 70 65 moveto (21) CSH 80 65 moveto (22) CSH 90 65 moveto (23) CSH 0 0 100 100 rectstroke grestore showpage Chv/doc/simple.eps010064400020550007177000000011030657126731600153700ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 100.0 100.0 %%%EndComments % % center then show a string % /CSH { % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def gsave 0.5 setgray 25 0 75 75 rectfill 1.0 setgray 50 0 50 50 rectfill 0.0 setgray 0 0 100 100 rectstroke 25 50 25 25 rectstroke 25 0 25 75 rectstroke 50 50 50 25 rectstroke /Helvetica findfont 10 scalefont setfont 1.0 setgray 37.5 60 moveto (\(1,1\)) CSH 75 60 moveto (\(1,2\)) CSH 37.5 25 moveto (\(2,1\)) CSH grestore showpage Chv/doc/makefile010064400020550007177000000000270657126731600150720ustar00clevecompmath00000400000006clean : - rm -f *.dvi Chv/doc/simple.eps.bak010064400020550007177000000002700657126731700161310ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 100.0 100.0 %%%EndComments 0.5 setgray 25 0 75 75 rectfill 1.0 setgray 50 0 50 50 rectfill 0.0 setgray 0 0 100 100 rectstroke showpage ChvList.h010064400020550007177000000001100653410641100136060ustar00clevecompmath00000400000006#ifndef _ChvList_ #define _ChvList_ #include "ChvList/ChvList.h" #endif ChvList/ChvList.h010064400020550007177000000133020653624433200152000ustar00clevecompmath00000400000006/* ChvList.h */ #include "../Chv.h" #include "../Lock.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- this object handles a list of lists of Chv objects nlist -- # of lists heads -- heads[ilist] contains a pointer to the first Chv object in list ilist counts -- when not-NULL, counts[ilist] contains the remaining number of objects to be added to list ilist before it is complete lock -- mutex object, can be NULL flags -- when not NULL, a vector to specify when a list needs to be locked before adding an object to it. flags[ilist] = 'N' --> no need to lock flags[ilist] = 'Y' --> must lock nlocks -- number of times the list was locked -------------------------------------------------------------------- */ typedef struct _ChvList ChvList ; struct _ChvList { int nlist ; Chv **heads ; int *counts ; Lock *lock ; char *flags ; int nlocks ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ ChvList * ChvList_new ( void ) ; /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void ChvList_setDefaultFields ( ChvList *chvlist ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void ChvList_clearData ( ChvList *chvlist ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ void ChvList_free ( ChvList *chvlist ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- basic initializer nlist -- number of lists to be held by this object counts -- vector that contains number of items expected for each list. counts == NULL --> unknown number of items expected counts != NULL --> known number of items expected lockflag -- flag to specify lock status lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize only threads in this process. lockflag = 2 --> mutex lock is allocated and it can synchronize threads in this and other processes. flags -- vector to specify whether to lock individual lists flags == NULL --> none or all lists must be locked, use lockflag to determine flags[ilist] = 'N' --> no need to lock list ilist flags[ilist] = 'Y' --> must lock list ilist created -- 98may02, cca ------------------------------------------------------------------ */ void ChvList_init ( ChvList *chvlist, int nlist, int counts[], int lockflag, char flags[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98may02, cca ---------------------------------------- */ void ChvList_writeForHumanEye ( ChvList *chvlist, FILE *fp ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------- return 1 if list ilist is not empty return 0 if list ilist is empty created -- 98may02, cca ----------------------------------- */ int ChvList_isListNonempty ( ChvList *chvlist, int ilist ) ; /* --------------------------------------------------------- return 1 if the count for list ilist is zero return 0 if the count for list ilist is greater than zero created -- 98may02, cca --------------------------------------------------------- */ int ChvList_isCountZero ( ChvList *chvlist, int ilist ) ; /* --------------------------------- if chv is not NULL then add chv to list ilist endif decrement the count of list ilist created -- 98may02, cca --------------------------------- */ void ChvList_addObjectToList ( ChvList *chvlist, Chv *chv, int ilist ) ; /* ------------------------------------ return pointer to head of list ilist and set head to NULL created -- 98may02, cca ------------------------------------ */ Chv * ChvList_getList ( ChvList *chvlist, int ilist ) ; /*--------------------------------------------------------------------*/ ChvList/makefile010064400020550007177000000001410663622355000151500ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean ChvList/src/makefile010064400020550007177000000006740663602152700157520ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = ChvList $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG ChvList/src/makeGlobalLib010064400020550007177000000005750660026075400166600ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = ChvList SRC = basics.c \ init.c \ IO.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a ChvList/src/IO.c010064400020550007177000000032700653410624700147200ustar00clevecompmath00000400000006/* IO.c */ #include "../ChvList.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98may02, cca ---------------------------------------- */ void ChvList_writeForHumanEye ( ChvList *chvlist, FILE *fp ) { Chv *chv ; int ilist ; /* --------------- check the input --------------- */ if ( chvlist == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in ChvList_writeForHumanEye(%p,%p)" "\n bad input\n", chvlist, fp) ; exit(-1) ; } fprintf(fp, "\n ChvList object at address %p" "\n %d lists, %d locks", chvlist, chvlist->nlist, chvlist->nlocks) ; if ( chvlist->lock != NULL ) { fprintf(fp, "\n lock located at %p", chvlist->lock) ; } else { fprintf(fp, "\n lock is NULL") ; } for ( ilist = 0 ; ilist < chvlist->nlist ; ilist++ ) { fprintf(fp, "\n %6d", ilist) ; if ( chvlist->counts != NULL ) { fprintf(fp, " %6d", chvlist->counts[ilist]) ; } else { fprintf(fp, " %6d", 0) ; } if ( chvlist->flags != NULL ) { fprintf(fp, " %6c", chvlist->flags[ilist]) ; } else { fprintf(fp, " %6c", 'N') ; } if ( chvlist->heads != NULL && chvlist->heads[ilist] != NULL ) { fprintf(fp, " %10p", chvlist->heads[ilist]) ; } else { fprintf(fp, " NULL") ; } } /* for ( chv = chvlist->head ; chv != NULL ; chv = chv->next ) { fprintf(fp, "\n chv %d, nbytes %d", chv->id, Chv_nbytesInWorkspace(chv)) ; } */ return ; } /*--------------------------------------------------------------------*/ ChvList/src/basics.c010064400020550007177000000050260653410624700156560ustar00clevecompmath00000400000006/* basics.c */ #include "../ChvList.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ ChvList * ChvList_new ( void ) { ChvList *chvlist ; ALLOCATE(chvlist, struct _ChvList, 1) ; ChvList_setDefaultFields(chvlist) ; return(chvlist) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void ChvList_setDefaultFields ( ChvList *chvlist ) { if ( chvlist == NULL ) { fprintf(stderr, "\n fatal error in ChvList_setDefaultFields(%p)" "\n bad input", chvlist) ; exit(-1) ; } chvlist->nlist = 0 ; chvlist->heads = NULL ; chvlist->counts = NULL ; chvlist->lock = NULL ; chvlist->flags = NULL ; chvlist->nlocks = 0 ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void ChvList_clearData ( ChvList *chvlist ) { /* --------------- check the input --------------- */ if ( chvlist == NULL ) { fprintf(stderr, "\n fatal error in ChvList_clearData(%p)" "\n bad input\n", chvlist) ; exit(-1) ; } /* ------------- free the data ------------- */ if ( chvlist->heads != NULL ) { FREE(chvlist->heads) ; } if ( chvlist->counts != NULL ) { IVfree(chvlist->counts) ; } if ( chvlist->flags != NULL ) { CVfree(chvlist->flags) ; } if ( chvlist->lock != NULL ) { /* ------------------------- destroy and free the lock ------------------------- */ Lock_free(chvlist->lock) ; } /* ---------------------- set the default fields ---------------------- */ ChvList_setDefaultFields(chvlist) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ void ChvList_free ( ChvList *chvlist ) { if ( chvlist == NULL ) { fprintf(stderr, "\n fatal error in ChvList_free(%p)" "\n bad input\n", chvlist) ; exit(-1) ; } ChvList_clearData(chvlist) ; FREE(chvlist) ; return ; } /*--------------------------------------------------------------------*/ ChvList/src/init.c010064400020550007177000000053740653410624700153630ustar00clevecompmath00000400000006/* init.c */ #include "../ChvList.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- basic initializer nlist -- number of lists to be held by this object counts -- vector that contains number of items expected for each list. counts == NULL --> unknown number of items expected counts != NULL --> known number of items expected lockflag -- flag to specify lock status lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize only threads in this process. lockflag = 2 --> mutex lock is allocated and it can synchronize only threads in this and other processes. flags -- vector to specify whether to lock individual lists flags == NULL --> none or all lists must be locked, use lockflag to determine flags[ilist] = 'N' --> no need to lock list ilist flags[ilist] = 'Y' --> must lock list ilist created -- 98may02, cca ------------------------------------------------------------------ */ void ChvList_init ( ChvList *chvlist, int nlist, int counts[], int lockflag, char flags[] ) { int ilist ; /* --------------- check the input --------------- */ if ( chvlist == NULL || nlist <= 0 || lockflag < 0 || lockflag > 1 ) { fprintf(stderr, "\n fatal error in ChvList_init(%p,%d,%p,%d,%p)" "\n bad input\n", chvlist, nlist, counts, lockflag, flags) ; exit(-1) ; } /* -------------- clear all data -------------- */ ChvList_clearData(chvlist) ; /* ------------------------------------------------------- set the number of lists and allocate the heads[] vector ------------------------------------------------------- */ chvlist->nlist = nlist ; ALLOCATE(chvlist->heads, struct _Chv *, nlist) ; for ( ilist = 0 ; ilist < nlist ; ilist++ ) { chvlist->heads[ilist] = NULL ; } if ( counts != NULL ) { /* ------------------------------------- allocate and fill the counts[] vector ------------------------------------- */ chvlist->counts = IVinit(nlist, 0) ; IVcopy(nlist, chvlist->counts, counts) ; } if ( lockflag > 0 ) { /* ----------------- allocate the lock ----------------- */ chvlist->lock = Lock_new() ; Lock_init(chvlist->lock, lockflag) ; } if ( flags != NULL ) { /* ------------------------------------ allocate and fill the flags[] vector ------------------------------------ */ chvlist->flags = CVinit(nlist, 'N') ; CVcopy(nlist, chvlist->flags, flags) ; } return ; } /*--------------------------------------------------------------------*/ ChvList/src/util.c010064400020550007177000000116720653624437300154000ustar00clevecompmath00000400000006/* util.c */ #include "../ChvList.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------- return 1 if list ilist is not empty return 0 if list ilist is empty created -- 98may02, cca ----------------------------------- */ int ChvList_isListNonempty ( ChvList *chvlist, int ilist ) { /* --------------- check the input --------------- */ if ( chvlist == NULL || ilist < 0 || ilist >= chvlist->nlist ) { fprintf(stderr, "\n fatal error in ChvList_isListNonempty(%p,%d)" "\n bad input\n", chvlist, ilist) ; } return(chvlist->heads[ilist] != NULL) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- return 1 if the count for list ilist is zero return 0 if the count for list ilist is greater than zero created -- 98may02, cca --------------------------------------------------------- */ int ChvList_isCountZero ( ChvList *chvlist, int ilist ) { /* --------------- check the input --------------- */ if ( chvlist == NULL || ilist < 0 || ilist >= chvlist->nlist ) { fprintf(stderr, "\n fatal error in ChvList_isCountZero(%p,%d)" "\n bad input\n", chvlist, ilist) ; } if ( chvlist->counts == NULL ) { return(1) ; } else { return(chvlist->counts[ilist] == 0) ; } } /*--------------------------------------------------------------------*/ /* --------------------------------- if chv is not NULL then add chv to list ilist endif decrement the count of list ilist created -- 98may02, cca --------------------------------- */ void ChvList_addObjectToList ( ChvList *chvlist, Chv *chv, int ilist ) { /* --------------- check the input --------------- */ if ( chvlist == NULL || ilist < 0 || ilist >= chvlist->nlist ) { fprintf(stderr, "\n fatal error in ChvList_addObjectToList(%p,%p,%d)" "\n bad input\n", chvlist, chv, ilist) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n ChvList %p : adding chv %p to list %d", chvlist, chv, ilist) ; fflush(stdout) ; #endif if ( chvlist->lock != NULL && (chvlist->flags == NULL || chvlist->flags[ilist] == 'Y' ) ) { /* -------------------------------------------------- we must lock the list to (possibly) add the object and decrement the list's count -------------------------------------------------- */ Lock_lock(chvlist->lock) ; if ( chv != NULL ) { chv->next = chvlist->heads[ilist] ; chvlist->heads[ilist] = chv ; } if ( chvlist->counts != NULL ) { chvlist->counts[ilist]-- ; } chvlist->nlocks++ ; Lock_unlock(chvlist->lock) ; } else { /* --------------------------------------------- no need to lock the list, just (possibly) add the object and decrement the list's count --------------------------------------------- */ if ( chv != NULL ) { chv->next = chvlist->heads[ilist] ; chvlist->heads[ilist] = chv ; } if ( chvlist->counts != NULL ) { chvlist->counts[ilist]-- ; } } #if MYDEBUG > 0 fprintf(stdout, "\n ChvList %p : heads[%d] = %p, counts[%d] = %d", chvlist, ilist, chvlist->heads[ilist], ilist, chvlist->counts[ilist]) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ return pointer to head of list ilist and set head to NULL created -- 98may02, cca ------------------------------------ */ Chv * ChvList_getList ( ChvList *chvlist, int ilist ) { Chv *chv ; /* --------------- check the input --------------- */ if ( chvlist == NULL || ilist < 0 || ilist >= chvlist->nlist ) { fprintf(stderr, "\n fatal error in ChvList_getList(%p,%d)" "\n bad input\n", chvlist, ilist) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n ChvList %p : get list %d", chvlist, ilist) ; fflush(stdout) ; #endif if ( chvlist->heads[ilist] != NULL ) { if ( chvlist->lock == NULL || (chvlist->flags != NULL && chvlist->flags[ilist] == 'N') || (chvlist->counts != NULL && chvlist->counts[ilist] == 0) ) { /* ------------------------ no need to lock the list ------------------------ */ chv = chvlist->heads[ilist] ; chvlist->heads[ilist] = NULL ; } else { /* ---------------------------------------------------- we must lock the list to return the head of the list ---------------------------------------------------- */ Lock_lock(chvlist->lock) ; chv = chvlist->heads[ilist] ; chvlist->heads[ilist] = NULL ; chvlist->nlocks++ ; Lock_unlock(chvlist->lock) ; } } else { chv = NULL ; } #if MYDEBUG > 0 fprintf(stdout, "\n ChvList %p : chv %p", chvlist, chv) ; fflush(stdout) ; #endif return(chv) ; } /*--------------------------------------------------------------------*/ ChvList/doc/004275500020550007177000000000000654276733000142335ustar00clevecompmath00000400000006ChvList/doc/dataStructure.tex010064400020550007177000000013330653624241000175700ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:ChvList:dataStructure} \par \par The {\tt ChvList} structure has the following fields. \begin{itemize} \item {\tt int nlist} : number of lists. \item {\tt Chv **heads} : vector of pointers to the heads of the list of {\tt Chv} objects. \item {\tt int *counts} : vector of incoming counts for the lists. \item {\tt Lock *lock} : mutual exclusion lock. \item {\tt char *flags} : vector of lock flags for the lists. If {\tt flags[ilist] == 'N'}, the list does not need to be locked. If {\tt flags[ilist] == 'Y'}, the list does need to be locked. Used only when {\tt lock} is not {\tt NULL}. \item {\tt int nlocks} : total number of locks made on the mutual exclusion lock. \end{itemize} ChvList/doc/intro.tex010064400020550007177000000053020653624237700161050ustar00clevecompmath00000400000006\par \chapter{{\tt ChvList}: {\tt Chv} list object } \par This object was created to handle a list of lists of {\tt Chv} objects during a matrix factorization. Its form and function is very close to the {\tt SubMtxList} object that handles lists of lists of {\tt SubMtx} objects during the forward and backsolves. \par Here are the main properties. \begin{enumerate} \item There are a fixed number of lists, set when the {\tt ChvList} object is initialized. \item For each list there is an expected count, the number of times an object will be added to the list. (Note, a {\tt NULL} object can be added to the list. In this case, nothing is added to the list, but its count is decremented.) \item There is one lock for all the lists, but each list can be flagged as necessary to lock or not necessary to lock before an insertion, count decrement, or an extraction is made to the list. \end{enumerate} \par The {\tt ChvList} object manages a number of lists that may require handling critical sections of code. For example, one thread may want to add an object to a particular list while another thread is removing objects. The critical sections are hidden inside the {\tt ChvList} object. Our factorization code does not know about any mutual exclusion locks that govern access to the lists. \par There are four functions of the {\tt ChvList} object. \begin{itemize} \item Is the incoming count for a list nonzero? \item Is a list nonempty? \item Add an object to a list (possibly a {\tt NULL} object) and decrement the incoming count. \item Remove a subset of objects from a list. \end{itemize} The first two operations are queries, and can be done without locking the list. The third operation needs a lock only when two or more threads will be inserting objects into the list. The fourth operation requires a lock only when one thread will add an object while another thread removes the object and the incoming count is not yet zero. \par Having a lock associated with a {\tt ChvList} object is optional, for example, it is not needed during a serial factorization nor a MPI factorization. In the latter case there is one {\tt ChvList} per process. For a multithreaded factorization there is one {\tt ChvList} object that is shared by all threads. The mutual exclusion lock that is (optionally) embedded in the {\tt ChvList} object is a {\tt Lock} object from this library. It is inside the {\tt Lock} object that we have a mutual exclusion lock. Presently we support the Solaris and POSIX thread packages. Porting the multithreaded codes to another platform should be simple if the POSIX thread package is present. Another type of thread package will require some modifications to the {\tt Lock} object, but none to the {\tt ChvList} objects. \par e to the {\tt SubMtxList} object that handles lists of lists of {\tt SubMtx} objects during the forward and backsolves. \par Here are the main properties. \begin{enumerate} \item There are a fixed number of lists, set when the {\tt ChvList} object is initialized. \item For each list there is an expected count, the nuChvList/doc/main.aux010064400020550007177000000023730653624243100156670ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space ChvList}: {\string\ptt\space Chv} list object }{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{2}} \newlabel{section:ChvList:dataStructure}{{1.1}{2}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space ChvList} methods}{2}} \newlabel{section:ChvList:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:ChvList:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initialization methods}{3}} \newlabel{subsection:ChvList:proto:initial}{{1.2.2}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{3}} \newlabel{subsection:ChvList:proto:utility}{{1.2.3}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}IO methods}{4}} \newlabel{subsection:ChvList:proto:IO}{{1.2.4}{4}} ChvList/doc/main.idx010064400020550007177000000011640653624243100156530ustar00clevecompmath00000400000006\indexentry{ChvList_new@{\tt ChvList\_new()}}{2} \indexentry{ChvList_setDefaultFields@{\tt ChvList\_setDefaultFields()}}{2} \indexentry{ChvList_clearData@{\tt ChvList\_clearData()}}{3} \indexentry{ChvList_free@{\tt ChvList\_free()}}{3} \indexentry{ChvList_init@{\tt ChvList\_init()}}{3} \indexentry{ChvList_isListNonempty@{\tt ChvList\_isListNonempty()}}{3} \indexentry{ChvList_isCountZero@{\tt ChvList\_isCountZero()}}{3} \indexentry{ChvList_getList@{\tt ChvList\_getList()}}{4} \indexentry{ChvList_addObjectToList@{\tt ChvList\_addObjectToList()}}{4} \indexentry{ChvList_writeForHumanEye@{\tt ChvList\_writeForHumanEye()}}{4} ChvList/doc/main.ilg010064400020550007177000000004560653624242700156520ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (10 entries accepted, 0 rejected). Sorting entries....done (36 comparisons). Generating output file main.ind....done (14 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. ChvList/doc/main.ind010064400020550007177000000006470653624242700156530ustar00clevecompmath00000400000006\begin{theindex} \item {\tt ChvList\_addObjectToList()}, 4 \item {\tt ChvList\_clearData()}, 3 \item {\tt ChvList\_free()}, 3 \item {\tt ChvList\_getList()}, 4 \item {\tt ChvList\_init()}, 3 \item {\tt ChvList\_isCountZero()}, 3 \item {\tt ChvList\_isListNonempty()}, 3 \item {\tt ChvList\_new()}, 2 \item {\tt ChvList\_setDefaultFields()}, 2 \item {\tt ChvList\_writeForHumanEye()}, 4 \end{theindex} ChvList/doc/main.log010064400020550007177000000030620653624243100156470ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 6 JUN 1998 06:33 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) (/usr/local/lib/texmf/tex/generic/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen100 \p@intvaluey=\dimen101 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 2. LaTeX Warning: No \tt typeface in this size, using \rm on input line 2. [1 ]) (dataStructure.tex) (proto.tex [2] [3]) (main.ind [4] [5 ]) (main.aux) ) Here is how much of TeX's memory you used: 421 strings out of 11977 4265 string characters out of 87269 36690 words of memory out of 262141 2356 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,4n,17p,184b,199s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (5 pages, 11544 bytes). ChvList/doc/main.tex010064400020550007177000000011360665065617400157000ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \newcommand{\bnd}{{\partial}} \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt ChvList} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt ChvList} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} ChvList/doc/proto.tex010064400020550007177000000165010653624247100161130ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt ChvList} methods} \label{section:ChvList:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt ChvList} object. \par \subsection{Basic methods} \label{subsection:ChvList:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} ChvList * ChvList_new ( void ) ; \end{verbatim} \index{ChvList_new@{\tt ChvList\_new()}} This method simply allocates storage for the {\tt ChvList} structure and then sets the default fields by a call to {\tt ChvList\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void ChvList_setDefaultFields ( ChvList *list ) ; \end{verbatim} \index{ChvList_setDefaultFields@{\tt ChvList\_setDefaultFields()}} The structure's fields are set to default values: {\tt nlist} and {\tt nlocks} set to zero, and {\tt heads}, {\tt counts}, {\tt lock} and {\tt flags} are set to {\tt NULL} . \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ChvList_clearData ( ChvList *list ) ; \end{verbatim} \index{ChvList_clearData@{\tt ChvList\_clearData()}} This method clears the object and free's any owned data by calling {\tt Chv\_free()} for each object on the free list. If {\tt heads} is not {\tt NULL}, it is free'd. If {\tt counts} is not {\tt NULL}, it is free'd via a call to {\tt IVfree()}. If {\tt flags} is not {\tt NULL}, it is free'd via a call to {\tt CVfree()}. If the lock is not {\tt NULL}, it is destroyed via a call to {\tt Lock\_free()}. There is a concluding call to {\tt ChvList\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ChvList_free ( ChvList *list ) ; \end{verbatim} \index{ChvList_free@{\tt ChvList\_free()}} This method releases any storage by a call to {\tt ChvList\_clearData()} and then free the space for {\tt list}. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization methods} \label{subsection:ChvList:proto:initial} \par There are three initializer methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void ChvList_init( ChvList *list, int nlist, int counts[], int lockflag, char flags[] ) ; \end{verbatim} \index{ChvList_init@{\tt ChvList\_init()}} Any data is cleared via a call to {\tt ChvList\_clearData()}. The number of lists is set and the {\tt heads[]} vector is initialized. If {\tt counts} is not {\tt NULL}, the object's {\tt counts[]} vector is allocated and filled with the incoming entries. If {\tt lockflag} is zero, the lock is not initialized. If {\tt lockflag} is {\tt 1}, the lock is initialized to be able to synchronize threads with the calling process. If {\tt lockflag} is {\tt 2}, the lock is initialized to be able to synchronize threads across processes. If {\tt flags} is not {\tt NULL}, the object's {\tt flags[]} vector is allocated and filled with the incoming entries. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, or if ${\tt nlist} \le 0$, or if {\tt lockflag} is not in {\tt [0,2]}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:ChvList:proto:utility} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ChvList_isListNonempty ( ChvList *list, int ilist ) ; \end{verbatim} \index{ChvList_isListNonempty@{\tt ChvList\_isListNonempty()}} \par If list {\tt ilist} is empty, the method returns 0. Otherwise, the method returns 1. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, or if {\tt ilist} is not in the range {\tt [0,nlist)}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ChvList_isCountZero ( ChvList *list, int ilist ) ; \end{verbatim} \index{ChvList_isCountZero@{\tt ChvList\_isCountZero()}} \par If {\tt counts} is {\tt NULL}, or if {\tt counts[ilist]} equal to zero, the method returns 1. Otherwise, the method returns 0. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, or if {\tt ilist} is not in the range {\tt [0,nlist)}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} Chv * ChvList_getList ( ChvList *list, int ilist ) ; \end{verbatim} \index{ChvList_getList@{\tt ChvList\_getList()}} \par If list {\tt ilist} is empty, the method returns {\tt NULL}. Otherwise, if the list needs to be locked, the lock is locked. The head of the list is saved to a pointer and then the head is set to {\tt NULL}. If the list was locked, the number of locks is incremented and the lock unlocked. The saved pointer is returned. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, or if {\tt ilist} is not in the range {\tt [0,nlist)}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void ChvList_addObjectToList ( ChvList *list, Chv *chv, int ilist ) ; \end{verbatim} \index{ChvList_addObjectToList@{\tt ChvList\_addObjectToList()}} \par If the list needs to be locked, the lock is locked. If {\tt chv} is not {\tt NULL}, it is added to the head of the list. If {\tt counts} is not {\tt NULL}, then {\tt counts[ilist]} is decremented. If the lock was locked, the number of locks is incremented and it is now unlocked. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, or if {\tt ilist} is not in the range {\tt [0,nlist)}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:ChvList:proto:IO} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void ChvList_writeForHumanEye ( ChvList *list, FILE *fp ) ; \end{verbatim} \index{ChvList_writeForHumanEye@{\tt ChvList\_writeForHumanEye()}} \par This method writes the list to a file in user readable form. \par \noindent {\it Error checking:} If {\tt list} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} ChvList/doc/makefile010064400020550007177000000000270654276733000157250ustar00clevecompmath00000400000006clean : - rm -f *.dvi ChvManager.h010064400020550007177000000001240653410641100142520ustar00clevecompmath00000400000006#ifndef _ChvManager_ #define _ChvManager_ #include "ChvManager/ChvManager.h" #endif ChvManager/ChvManager.h010064400020550007177000000112630653625577000163120ustar00clevecompmath00000400000006/* ChvManager.h */ #include "../Chv.h" #include "../Lock.h" /*--------------------------------------------------------------------*/ /* */ typedef struct _ChvManager ChvManager ; struct _ChvManager { Chv *head ; Lock *lock ; int mode ; int nactive ; int nbytesactive ; int nbytesrequested ; int nbytesalloc ; int nrequests ; int nreleases ; int nlocks ; int nunlocks ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ ChvManager * ChvManager_new ( void ) ; /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void ChvManager_setDefaultFields ( ChvManager *manager ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void ChvManager_clearData ( ChvManager *manager ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ void ChvManager_free ( ChvManager *manager ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------------------------------------- simple initializer lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize only threads in this process. lockflag = 2 --> mutex lock is allocated and it can synchronize only threads in this and other processes. mode = 0 --> free object and storage on release mode = 1 --> recycle object and storage on release created -- 98may02, cca --------------------------------------------------------------- */ void ChvManager_init ( ChvManager *manager, int lockflag, int mode ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------ return a pointer to a Chv object that has been initialized with the input parameters created -- 98may02, cca ------------------------------------------ */ Chv * ChvManager_newObject ( ChvManager *manager, int id, int nD, int nL, int nU, int symflag ) ; /* ------------------------------------------ return a pointer to a Chv object that has been initialized with the input parameters created -- 98may02, cca ------------------------------------------ */ Chv * ChvManager_newObjectOfSizeNbytes ( ChvManager *manager, int nbytesNeeded ) ; /* ----------------------- release a Chv instance created -- 98may02, cca ----------------------- */ void ChvManager_releaseObject ( ChvManager *manager, Chv *chv ) ; /* ------------------------------ release a list of Chv objects created -- 98may02, cca ------------------------------ */ void ChvManager_releaseListOfObjects ( ChvManager *manager, Chv *head ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98may02, cca ---------------------------------------- */ void ChvManager_writeForHumanEye ( ChvManager *manager, FILE *fp ) ; /*--------------------------------------------------------------------*/ ChvManager/makefile010064400020550007177000000001410663622355200156110ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean ChvManager/src/makefile010064400020550007177000000006770663602160400164100ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = ChvManager $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : -rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG ChvManager/src/makeGlobalLib010064400020550007177000000006010660026075700173100ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = ChvManager SRC = basics.o \ init.o \ IO.o \ util.o OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a ChvManager/src/IO.c010064400020550007177000000025240653625572000153630ustar00clevecompmath00000400000006/* IO.c */ #include "../ChvManager.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98may02, cca ---------------------------------------- */ void ChvManager_writeForHumanEye ( ChvManager *manager, FILE *fp ) { Chv *chv ; /* --------------- check the input --------------- */ if ( manager == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in ChvManager_writeForHumanEye(%p,%p)" "\n bad input\n", manager, fp) ; exit(-1) ; } fprintf(fp, "\n\n ChvManager object at address %p" "\n %d active objects, %d bytes active" "\n %d total bytes requested, %d total bytes allocated " "\n %d requests, %d releases, %d locks, %d unlocks", manager, manager->nactive, manager->nbytesactive, manager->nbytesrequested, manager->nbytesalloc, manager->nrequests, manager->nreleases, manager->nlocks, manager->nunlocks) ; /* for ( chv = manager->head ; chv != NULL ; chv = chv->next ) { fprintf(fp, "\n chv %d, nbytes %d", chv->id, Chv_nbytesInWorkspace(chv)) ; } */ return ; } /*--------------------------------------------------------------------*/ orHumanEye ( ChvManager *manager, FILE *fp ) { Chv *chv ; /* --------------- check the input --------------- */ if ( manager == NULL || fp == NULChvManager/src/basics.c010064400020550007177000000053730653625474200163300ustar00clevecompmath00000400000006/* basics.c */ #include "../ChvManager.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ ChvManager * ChvManager_new ( void ) { ChvManager *manager ; ALLOCATE(manager, struct _ChvManager, 1) ; ChvManager_setDefaultFields(manager) ; return(manager) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void ChvManager_setDefaultFields ( ChvManager *manager ) { if ( manager == NULL ) { fprintf(stderr, "\n fatal error in ChvManager_setDefaultFields(%p)" "\n bad input", manager) ; exit(-1) ; } manager->head = NULL ; manager->lock = NULL ; manager->mode = 0 ; manager->nactive = 0 ; manager->nbytesactive = 0 ; manager->nbytesrequested = 0 ; manager->nbytesalloc = 0 ; manager->nrequests = 0 ; manager->nreleases = 0 ; manager->nlocks = 0 ; manager->nunlocks = 0 ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void ChvManager_clearData ( ChvManager *manager ) { Chv *chv ; /* --------------- check the input --------------- */ if ( manager == NULL ) { fprintf(stderr, "\n fatal error in ChvManager_clearData(%p)" "\n bad input\n", manager) ; exit(-1) ; } /* ------------------------ free the working storage ------------------------ */ while ( (chv = manager->head) != NULL ) { manager->head = chv->next ; Chv_free(chv) ; } if ( manager->lock != NULL ) { /* ------------------------- destroy and free the lock ------------------------- */ Lock_free(manager->lock) ; } /* ---------------------- set the default fields ---------------------- */ ChvManager_setDefaultFields(manager) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ void ChvManager_free ( ChvManager *manager ) { if ( manager == NULL ) { fprintf(stderr, "\n fatal error in ChvManager_free(%p)" "\n bad input\n", manager) ; exit(-1) ; } ChvManager_clearData(manager) ; FREE(manager) ; return ; } /*--------------------------------------------------------------------*/ ChvManager/src/init.c010064400020550007177000000032370653625504700160230ustar00clevecompmath00000400000006/* init.c */ #include "../ChvManager.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- simple initializer lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize omly threads in this process. lockflag = 2 --> mutex lock is allocated and it can synchronize omly threads in this and other processes. mode = 0 --> free object and storage on release mode = 1 --> recycle object and storage on release created -- 98may02, cca --------------------------------------------------------------- */ void ChvManager_init ( ChvManager *manager, int lockflag, int mode ) { /* --------------- check the input --------------- */ if ( manager == NULL || lockflag < 0 || lockflag > 2 || mode < 0 || mode > 1 ) { fprintf(stderr, "\n fatal error in ChvManager_init(%p,%d,%d)" "\n bad input\n", manager, lockflag, mode) ; exit(-1) ; } /* -------------------------------------------------- clear any previous data and set the default fields -------------------------------------------------- */ ChvManager_clearData(manager) ; if ( lockflag > 0 ) { /* --------------------------- initialize the mutex object --------------------------- */ manager->lock = Lock_new() ; Lock_init(manager->lock, lockflag) ; } /* ------------ set the mode ------------ */ manager->mode = mode ; return ; } /*--------------------------------------------------------------------*/ ChvManager/src/util.c010064400020550007177000000213610653625604700160340ustar00clevecompmath00000400000006/* util.c */ #include "../ChvManager.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------ return a pointer to a Chv object that has been initialized with the input parameters created -- 98may02, cca ------------------------------------------ */ Chv * ChvManager_newObjectOfSizeNbytes ( ChvManager *manager, int nbytesNeeded ) { Chv *chv, *prev ; int nbytesAvailable, newinstance ; /* --------------- check the input --------------- */ if ( manager == NULL || nbytesNeeded <= 0 ) { fprintf(stderr, "\n fatal error in ChvMananger_newObjectOfSizeNbytes(%p,%d)" "\n bad input\n", manager, nbytesNeeded) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n %d bytes needed", nbytesNeeded) ; fflush(stdout) ; #endif if ( manager->lock != NULL ) { /* ----------------------------------------------- lock the lock, get exclusive access to the list ----------------------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n manager: locking") ; fflush(stdout) ; #endif Lock_lock(manager->lock) ; manager->nlocks++ ; #if MYDEBUG > 0 fprintf(stdout, ", %d locks so far", manager->nlocks) ; fflush(stdout) ; #endif } /* ---------------------------------------------------- find a Chv object with the required number of bytes ---------------------------------------------------- */ for ( chv = manager->head, prev = NULL ; chv != NULL ; chv = chv->next ) { nbytesAvailable = Chv_nbytesInWorkspace(chv) ; #if MYDEBUG > 0 fprintf(stdout, "\n free chev %p, nbytes = %d", chv, nbytesAvailable) ; fflush(stdout) ; #endif if ( nbytesNeeded <= nbytesAvailable ) { break ; } prev = chv ; } if ( chv != NULL ) { /* --------------------------------------- suitable object found, remove from list --------------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n chv = %p, %d nbytes available", chv, nbytesAvailable) ; fflush(stdout) ; #endif if ( prev == NULL ) { manager->head = chv->next ; } else { prev->next = chv->next ; } newinstance = 0 ; } else { /* ------------------------------------------------------------------ no suitable object found, create new instance and allocate storage ------------------------------------------------------------------ */ chv = Chv_new() ; #if MYDEBUG > 0 fprintf(stdout, "\n new postponed chv = %p", chv) ; fflush(stdout) ; #endif newinstance = 1 ; DV_setSize(&chv->wrkDV, nbytesNeeded/sizeof(double)) ; } /* ------------------------------- increment the statistics fields ------------------------------- */ if ( newinstance == 1 ) { manager->nbytesalloc += Chv_nbytesInWorkspace(chv) ; } manager->nactive++ ; manager->nbytesactive += Chv_nbytesInWorkspace(chv) ; manager->nbytesrequested += nbytesNeeded ; #if MYDEBUG > 0 fprintf(stdout, "\n %d bytes active, %d bytes requested", manager->nbytesactive, manager->nbytesrequested) ; #endif manager->nrequests++ ; if ( manager->lock != NULL ) { /* ----------------------------------------------------- unlock the lock, release exclusive access to the list ----------------------------------------------------- */ manager->nunlocks++ ; Lock_unlock(manager->lock) ; #if MYDEBUG > 0 fprintf(stdout, "\n manager: unlocking, %d unlocks so far", manager->nunlocks) ; fflush(stdout) ; #endif } return(chv) ; } /*--------------------------------------------------------------------*/ /* ----------------------- release a Chv instance created -- 98may02, cca ----------------------- */ void ChvManager_releaseObject ( ChvManager *manager, Chv *chv1 ) { Chv *chv2, *prev ; int nbytes1, nbytes2 ; /* --------------- check the input --------------- */ if ( manager == NULL || chv1 == NULL ) { fprintf(stderr, "\n fatal error in ChvMananger_releaseObject(%p,%p)" "\n bad input\n", manager, chv1) ; exit(-1) ; } if ( manager->lock != NULL ) { /* ----------------------------------------------- lock the lock, get exclusive access to the list ----------------------------------------------- */ Lock_lock(manager->lock) ; manager->nlocks++ ; } manager->nreleases++ ; manager->nbytesactive -= Chv_nbytesInWorkspace(chv1) ; manager->nactive-- ; if ( manager->mode == 0 ) { /* ------------------- release the storage ------------------- */ Chv_free(chv1) ; } else { /* -------------------------------------------------------- find a place in the list where the Chv objects are sorted in ascending order of the size of their workspace -------------------------------------------------------- */ nbytes1 = Chv_nbytesInWorkspace(chv1) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n trying to release chevron %p with %d bytes", chv1, nbytes1) ; #endif for ( chv2 = manager->head, prev = NULL ; chv2 != NULL ; chv2 = chv2->next ) { nbytes2 = Chv_nbytesInWorkspace(chv2) ; #if MYDEBUG > 0 fprintf(stdout, "\n list chv %p with %d bytes", chv2, nbytes2) ; #endif if ( nbytes2 > nbytes1 ) { break ; } prev = chv2 ; } if ( prev == NULL ) { manager->head = chv1 ; #if MYDEBUG > 0 fprintf(stdout, "\n manager->head = %p", chv1) ; #endif } else { prev->next = chv1 ; #if MYDEBUG > 0 fprintf(stdout, "\n %p->next = %p", prev, chv1) ; #endif } chv1->next = chv2 ; #if MYDEBUG > 0 fprintf(stdout, "\n %p->next = %p", chv1, chv2) ; #endif } if ( manager->lock != NULL ) { /* ----------------------------------------------------- unlock the lock, release exclusive access to the list ----------------------------------------------------- */ manager->nunlocks++ ; Lock_unlock(manager->lock) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------ release a list of Chv objects created -- 98may02, cca ------------------------------ */ void ChvManager_releaseListOfObjects ( ChvManager *manager, Chv *head ) { Chv *chv1, *chv2, *prev ; int nbytes1, nbytes2 ; /* --------------- check the input --------------- */ if ( manager == NULL || head == NULL ) { fprintf(stderr, "\n fatal error in ChvManager_releaseListOfObjects(%p,%p)" "\n bad input\n", manager, head) ; exit(-1) ; } if ( manager->lock != NULL ) { /* ----------------------------------------------- lock the lock, get exclusive access to the list ----------------------------------------------- */ Lock_lock(manager->lock) ; manager->nlocks++ ; } if ( manager->mode == 0 ) { /* --------------- release storage --------------- */ while ( (chv1 = head) != NULL ) { head = head->next ; manager->nbytesactive -= Chv_nbytesInWorkspace(chv1) ; manager->nactive-- ; manager->nreleases++ ; Chv_free(chv1) ; } } else { /* ------------------- recycle the objects ------------------- */ while ( head != NULL ) { chv1 = head ; head = chv1->next ; /* -------------------------------------------------------- find a place in the list where the Chv objects are sorted in ascending order of the size of their workspace -------------------------------------------------------- */ nbytes1 = Chv_nbytesInWorkspace(chv1) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n trying to release chevron %p with %d bytes", chv1, nbytes1) ; #endif for ( chv2 = manager->head, prev = NULL ; chv2 != NULL ; chv2 = chv2->next ) { nbytes2 = Chv_nbytesInWorkspace(chv2) ; #if MYDEBUG > 0 fprintf(stdout, "\n list chevron %p with %d bytes", chv2, nbytes2) ; #endif if ( nbytes2 > nbytes1 ) { break ; } prev = chv2 ; } if ( prev == NULL ) { manager->head = chv1 ; #if MYDEBUG > 0 fprintf(stdout, "\n manager->head = %p", chv1) ; #endif } else { prev->next = chv1 ; #if MYDEBUG > 0 fprintf(stdout, "\n %p->next = %p", prev, chv1) ; #endif } chv1->next = chv2 ; #if MYDEBUG > 0 fprintf(stdout, "\n %p->next = %p", chv1, chv2) ; #endif manager->nbytesactive -= Chv_nbytesInWorkspace(chv1) ; manager->nactive-- ; manager->nreleases++ ; } } if ( manager->lock != NULL ) { /* ----------------------------------------------------- unlock the lock, release exclusive access to the list ----------------------------------------------------- */ manager->nunlocks++ ; Lock_unlock(manager->lock) ; } return ; } /*--------------------------------------------------------------------*/ ChvManager/doc/004275500020550007177000000000000654276733000146725ustar00clevecompmath00000400000006ChvManager/doc/dataStructure.tex010064400020550007177000000020700665020250300202220ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:ChvManager:dataStructure} \par \par The {\tt ChvList} structure has the following fields. \begin{itemize} \item {\tt Chv *head} : vector of pointers to the heads of the list of {\tt Chv} objects. \item {\tt Lock *lock} : mutual exclusion lock. \item {\tt int mode} : behavior mode. When {\tt mode = 0}, the object calls {\tt SubMtx\_new()} and {\tt SubMtx\_free()} to create and release objects. When {\tt mode = 1}, the object recycles the objects. \item {\tt int nactive} : number of active instances. \item {\tt int nbytesactive} : number of bytes that are active. \item {\tt int nbytesrequested} : number of bytes that have been requested. \item {\tt int nbytesalloc} : number of bytes that have been allocated. \item {\tt int nrequests} : number of requests for instances. \item {\tt int releases} : number of instances that have been released. \item {\tt int nlocks} : total number of locks made on the mutual exclusion lock. {\tt int nunlocks} : total number of unlocks made on the mutual exclusion lock. \end{itemize} ChvManager/doc/intro.tex010064400020550007177000000056540653625741400165540ustar00clevecompmath00000400000006\par \chapter{{\tt ChvManager}: {\tt Chv} manager object } \par This object was created to handle a number of instances of {\tt Chv} objects. Our codes are heavily dependent on dynamic memory management. This is partly due to the pivoting capability during the factorization and partly to the nondeterministic nature of parallel computation --- we may not know ahead of time just what data structures will exist during the computations. \par We wanted to be able to generate and re-use {\tt Chv} objects, and we wanted to make the process somewhat transparent to other sections of the code. Towards this aim, there are two simple functions. \begin{itemize} \item Ask the manager object for a {\tt Chv} object that has a certain amount of workspace. \item Return to the manager object a {\tt Chv} object or list of objects that are no longer needed. \end{itemize} Where the manager object gets an instance, or what the manager does with the instance objects when they are returned to it, is of no concern to the user of the manager object --- unless the process takes too much time or storage. We support two {\it modes} of behavior. \begin{itemize} \item {\it catch-and-release} \par In this mode the {\tt ChvManager} object is just a front to {\tt malloc()} and {\tt free()} calls. The user asks for an object of a certain size, and the manager creates one using a call to {\tt malloc()}. When the user returns an object, the manager releases the storage via a call to {\tt free()}. \item {\it recycle} \par In this mode the {\tt ChvManager} object keeps a free pool of {\tt Chv} objects. When the user requests a {\tt Chv} object of a certain size, the manager searches the pool and finds one of that size or larger, removes the object from the pool, and returns the object to the user. (Our implementation finds {\it a} smallest object of that size or larger.) If there is no object on the free pool of sufficient size, one is created and returned. When the user releases an object to the manager, the object is placed on the free pool. \end{itemize} For the factorization, serial, multithreaded or MPI, we recommend using the recycling mode. \par A multithreaded environment creates some difficulties. Should there be one manager object per thread, or should all the threads share one object? We have chosen the latter course, but this requires that a lock be present to guard the critical section of code where one searches or adds an object to the list. The lock we use is a {\tt Lock} object, and so the {\tt ChvManager} code is completely independent of the thread package. Porting to a new system might require some modification to the {\tt Lock}, but none to the manager object. \par Each manager object keeps track of certain statistics, % e.g., the number of active {\tt Chv} objects, the number of bytes in their workspaces, the total number of bytes requested, the number of requests for a {\tt Chv} objects, the number of releases, and the number of locks and unlocks. ChvManager/doc/main.tex010064400020550007177000000011400665065617600163340ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \newcommand{\bnd}{{\partial}} \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt DChvList} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt DChvList} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} ChvManager/doc/proto.tex010064400020550007177000000142040653625722000165460ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt ChvManager} methods} \label{section:ChvManager:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt ChvManager} object. \par \subsection{Basic methods} \label{subsection:ChvManager:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} ChvManager * ChvManager_new ( void ) ; \end{verbatim} \index{ChvManager_new@{\tt ChvManager\_new()}} This method simply allocates storage for the {\tt ChvManager} structure and then sets the default fields by a call to {\tt ChvManager\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void ChvManager_setDefaultFields ( ChvManager *manager ) ; \end{verbatim} \index{ChvManager_setDefaultFields@{\tt ChvManager\_setDefaultFields()}} The structure's fields are set to default values: {\tt mode}, {\tt nactive}, {\tt nbytesactive}, {\tt nbytesrequested}, {\tt nbytesalloc}, {\tt nrequests}, {\tt nreleases}, {\tt nlocks} and {\tt nunlocks} set to zero, and {\tt head} and {\tt lock} are set to {\tt NULL} . \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ChvManager_clearData ( ChvManager *manager ) ; \end{verbatim} \index{ChvManager_clearData@{\tt ChvManager\_clearData()}} This method clears the object and free's any owned data by calling {\tt Chv\_free()} for each object on the free list. If the lock is not {\tt NULL}, it is destroyed via a call to {\tt mutex\_destroy()} and then free'd. There is a concluding call to {\tt ChvManager\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ChvManager_free ( ChvManager *manager ) ; \end{verbatim} \index{ChvManager_free@{\tt ChvManager\_free()}} This method releases any storage by a call to {\tt ChvManager\_clearData()} and then free the space for {\tt manager}. \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization methods} \label{subsection:ChvManager:proto:initial} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void ChvManager_init( ChvManager *manager, int lockflag, int mode ) ; \end{verbatim} \index{ChvManager_init@{\tt ChvManager\_init()}} Any data is cleared via a call to {\tt ChvManager\_clearData()}. If {\tt lockflag} is zero, the lock is not initialized. If {\tt lockflag} is {\tt 1}, the lock is initialized to be able to synchronize threads with the calling process. If {\tt lockflag} is {\tt 2}, the lock is initialized to be able to synchronize threads across processes. The behavior mode is set to {\tt mode}. \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, or if {\tt lockflag} is not in {\tt [0,2]}, or if {\tt mode} is not in {\tt [0,1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:ChvManager:proto:utility} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Chv * ChvManager_newObjectOfSizeNbytes ( ChvManager *manager, int nbytesNeeded ) ; \end{verbatim} \index{ChvManager_newObjectOfSizeNbytes@{\tt ChvManager\_newObjectOfSizeNbytes()}} \par This method returns a {\tt Chv} object whose workspace contains at least {\tt nbytesNeeded} bytes. \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ChvManager_releaseObject ( ChvManager *manager, Chv *chv ) ; \end{verbatim} \index{ChvManager_releaseObject@{\tt ChvManager\_releaseObject()}} \par This method releases the {\tt chv} instance into the free pool of objects. \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void ChvManager_releaseListOfObjects ( ChvManager *manager, Chv *chv ) ; \end{verbatim} \index{ChvManager_releaseListOfObjects@{\tt ChvManager\_releaseListOfObjects()}} \par This method releases a list of {\tt Chv} objects into the free pool of objects. The head of the list is the {\tt chv} instance. \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:ChvManager:proto:IO} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void ChvManager_writeForHumanEye ( ChvManager *manager, FILE *fp ) ; \end{verbatim} \index{ChvManager_writeForHumanEye@{\tt ChvManager\_writeForHumanEye()}} \par This method writes the statistics to a file in user readable form. \par \noindent {\it Error checking:} If {\tt manager} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} rief descriptions including prototypes of all methods that belong to the {\tt ChvManager} object. \par \subsection{Basic methods} \label{subsection:ChvManager:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %===================================================ChvManager/doc/main.log010064400020550007177000000047160653634350700163230ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 6 JUN 1998 15:48 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) (/usr/local/lib/texmf/tex/generic/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen100 \p@intvaluey=\dimen101 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 2. LaTeX Warning: No \tt typeface in this size, using \rm on input line 2. [1 ]) (dataStructure.tex Overfull \hbox (8.41794pt too wide) in paragraph at lines 14--19 [] []\elvtt int mode \elvrm : be-hav-ior mode. When \elvtt mode = 0\elvrm , the ob-ject calls \elvtt SubMtx[]new() \elvrm and \elvtt SubMtx[]free() \hbox(7.60416+2.12917)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(4.86667+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvtt i .etc. ) (proto.tex Overfull \hbox (14.44592pt too wide) in paragraph at lines 33--46 []\elvrm The struc-ture's fields are set to de-fault val-ues: \elvtt mode\elvrm , \elvtt nactive\elvrm , \elvtt nbytesactive\elvrm , \elvtt nbytesrequested\el vrm , \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\elvrm T .\elvrm h .\elvrm e .\glue 3.65 plus 1.825 minus 1.21666 .etc. [2] [3]) (main.ind [4] [5 ]) (main.aux) ) Here is how much of TeX's memory you used: 421 strings out of 11977 4283 string characters out of 87269 38079 words of memory out of 262141 2356 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,5n,17p,187b,258s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (5 pages, 10720 bytes). ChvManager/doc/main.idx010064400020550007177000000012150653634350700163150ustar00clevecompmath00000400000006\indexentry{ChvManager_new@{\tt ChvManager\_new()}}{2} \indexentry{ChvManager_setDefaultFields@{\tt ChvManager\_setDefaultFields()}}{3} \indexentry{ChvManager_clearData@{\tt ChvManager\_clearData()}}{3} \indexentry{ChvManager_free@{\tt ChvManager\_free()}}{3} \indexentry{ChvManager_init@{\tt ChvManager\_init()}}{3} \indexentry{ChvManager_newObjectOfSizeNbytes@{\tt ChvManager\_newObjectOfSizeNbytes()}}{3} \indexentry{ChvManager_releaseObject@{\tt ChvManager\_releaseObject()}}{3} \indexentry{ChvManager_releaseListOfObjects@{\tt ChvManager\_releaseListOfObjects()}}{3} \indexentry{ChvManager_writeForHumanEye@{\tt ChvManager\_writeForHumanEye()}}{4} ChvManager/doc/main.aux010064400020550007177000000024260653634350700163330ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space ChvManager}: {\string\ptt\space Chv} manager object }{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{2}} \newlabel{section:ChvManager:dataStructure}{{1.1}{2}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space ChvManager} methods}{2}} \newlabel{section:ChvManager:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:ChvManager:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initialization methods}{3}} \newlabel{subsection:ChvManager:proto:initial}{{1.2.2}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{3}} \newlabel{subsection:ChvManager:proto:utility}{{1.2.3}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}IO methods}{4}} \newlabel{subsection:ChvManager:proto:IO}{{1.2.4}{4}} ChvManager/doc/main.ind010064400020550007177000000006540653634350400163060ustar00clevecompmath00000400000006\begin{theindex} \item {\tt ChvManager\_clearData()}, 3 \item {\tt ChvManager\_free()}, 3 \item {\tt ChvManager\_init()}, 3 \item {\tt ChvManager\_new()}, 2 \item {\tt ChvManager\_newObjectOfSizeNbytes()}, 3 \item {\tt ChvManager\_releaseListOfObjects()}, 3 \item {\tt ChvManager\_releaseObject()}, 3 \item {\tt ChvManager\_setDefaultFields()}, 3 \item {\tt ChvManager\_writeForHumanEye()}, 4 \end{theindex} ChvManager/doc/main.ilg010064400020550007177000000004550653634350400163060ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (9 entries accepted, 0 rejected). Sorting entries....done (26 comparisons). Generating output file main.ind....done (13 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. ChvManager/doc/makefile010064400020550007177000000000270654276733000163640ustar00clevecompmath00000400000006clean : - rm -f *.dvi Coords.h010064400020550007177000000001040653410637000134720ustar00clevecompmath00000400000006#ifndef _Coords_ #define _Coords_ #include "Coords/Coords.h" #endif Coords/Coords.h010064400020550007177000000207710653503565500147470ustar00clevecompmath00000400000006/* Coords.h */ #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- object to hold coordinates of a graph type -- coordinates type 1 -- use tuple, x(icoor, idim) = coors[idim + ndim*icoor] 2 -- use bycoord, x(icoor, idim) = coors[icoor + ncoor*idim] ndim -- number of dimensions ncoor -- number of coordinates coors -- coordinate array --------------------------------------------------------------- */ typedef struct _Coords Coords ; struct _Coords { int type ; int ndim ; int ncoor ; float *coors ; } ; #define COORDS_BY_TUPLE 1 #define COORDS_BY_COORD 2 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 95dec17, cca ----------------------- */ Coords * Coords_new ( void ) ; /* ----------------------- set the default fields created -- 95dec17, cca ----------------------- */ void Coords_setDefaultFields ( Coords *coords ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 95dec17, cca -------------------------------------------------- */ void Coords_clearData ( Coords *coords ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 95dec17, cca ------------------------------------------ */ Coords * Coords_free ( Coords *coords ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------------------------- initialize the object, storage freed if repeat call created -- 95dec17, cca --------------------------------------------------- */ void Coords_init ( Coords *coords, int type, int ndim, int ncoor ) ; /* ---------------------------------------------------------- purpose -- initialize a 9-point operator on a n1 x n2 grid input -- bbox -- bounding box bbox[0] -- x southwest bbox[1] -- y southwest bbox[2] -- x northeast bbox[3] -- y northeast Type -- type of object n1 -- # of grid points in first direction n2 -- # of grid points in second direction ncomp -- # of components per grid point created -- 95dec17, cca ---------------------------------------------------------- */ void Coords_init9P ( Coords *coords, float bbox[], int type, int n1, int n2, int ncomp ) ; /* ---------------------------------------------------------------- purpose -- initialize a 27-point operator on a n1 x n2 x n3 grid input -- bbox -- bounding box bbox[0] -- x southwest bottom bbox[1] -- y southwest bottom bbox[2] -- z southwest bottom bbox[3] -- x northeast top bbox[4] -- y northeast top bbox[5] -- z northeast top Type -- type of object n1 -- # of grid points in first direction n2 -- # of grid points in second direction n3 -- # of grid points in third direction ncomp -- # of components per grid point created -- 95dec17, cca ---------------------------------------------------------------- */ void Coords_init27P ( Coords *coords, float bbox[], int Type, int n1, int n2, int n3, int ncomp ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95dec17, cca ---------------------------------------------- */ int Coords_sizeOf ( Coords *coords ) ; /* -------------------------------------------------- return the minimum coordinate in the dim-direction created -- 95dec17, cca -------------------------------------------------- */ float Coords_min ( Coords *coords, int dim ) ; /* -------------------------------------------------- return the maximum coordinate in the dim-direction created -- 95dec17, cca -------------------------------------------------- */ float Coords_max ( Coords *coords, int dim ) ; /* ----------------------- 1 <= idim <= ndim 0 <= icoor < ncoor created -- 95dec17, cca ----------------------- */ float Coords_value ( Coords *coords, int idim, int icoor ) ; /* ----------------------- 1 <= idim <= ndim 0 <= icoor < ncoor created -- 95dec17, cca ----------------------- */ void Coords_setValue ( Coords *coords, int idim, int icoor, float val ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------- purpose -- to read in an Coords object from a file input -- fn -- filename, must be *.coordsb or *.coordsf return value -- 1 if success, 0 if failure created -- 95dec19, cca --------------------------------------------------- */ int Coords_readFromFile ( Coords *coords, char *fn ) ; /* --------------------------------------------------------- purpose -- to read an Coords object from a formatted file return value -- 1 if success, 0 if failure created -- 95dec19, cca --------------------------------------------------------- */ int Coords_readFromFormattedFile ( Coords *coords, FILE *fp ) ; /* ------------------------------------------------------ purpose -- to read an Coords object from a binary file return value -- 1 if success, 0 if failure created -- 95dec19, cca ------------------------------------------------------ */ int Coords_readFromBinaryFile ( Coords *coords, FILE *fp ) ; /* ---------------------------------------------- purpose -- to write an Coords object to a file input -- fn -- filename *.coordsb -- binary *.coordsf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95dec19, cca ---------------------------------------------- */ int Coords_writeToFile ( Coords *coords, char *fn ) ; /* -------------------------------------------------------- purpose -- to write an Coords object to a formatted file return value -- 1 if success, 0 otherwise created -- 95dec19, cca -------------------------------------------------------- */ int Coords_writeToFormattedFile ( Coords *coords, FILE *fp ) ; /* ----------------------------------------------------- purpose -- to write an Coords object to a binary file return value -- 1 if success, 0 otherwise created -- 95dec19, cca ----------------------------------------------------- */ int Coords_writeToBinaryFile ( Coords *coords, FILE *fp ) ; /* ---------------------------------------------------- purpose -- to write an Coords object for a human eye return value -- 1 if success, 0 otherwise created -- 95dec19, cca ---------------------------------------------------- */ int Coords_writeForHumanEye ( Coords *coords, FILE *fp ) ; /* ------------------------------------------------------------ purpose -- to write out the statistics for the Coords object return value -- 1 if success, 0 otherwise created -- 95dec19, cca ------------------------------------------------------------ */ int Coords_writeStats ( Coords *coords, FILE *fp ) ; /*--------------------------------------------------------------------*/ Coords/makefile010064400020550007177000000002230663622355300150310ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean Coords/src/makefile010064400020550007177000000006770663602166100156310ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Coords $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG Coords/src/makeGlobalLib010064400020550007177000000005740660026076200165330ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Coords SRC = basics.c \ init.c \ IO.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Coords/src/IO.c010064400020550007177000000310030653503570200145660ustar00clevecompmath00000400000006/* IO.c */ #include "../Coords.h" static const char *suffixb = ".coordsb" ; static const char *suffixf = ".coordsf" ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to read in an Coords object from a file input -- fn -- filename, must be *.coordsb or *.coordsf return value -- 1 if success, 0 if failure created -- 95dec19, cca --------------------------------------------------- */ int Coords_readFromFile ( Coords *coords, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( coords == NULL || fn == NULL ) { fprintf(stderr, "\n error in Coords_readFromFile(%p,%s), file %s, line %d" "\n bad input\n", coords, fn, __FILE__, __LINE__) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in Coords_readFromFile(%p,%s)" "\n unable to open file %s", coords, fn, fn) ; rc = 0 ; } else { rc = Coords_readFromBinaryFile(coords, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in Coords_readFromFile(%p,%s)" "\n unable to open file %s", coords, fn, fn) ; rc = 0 ; } else { rc = Coords_readFromFormattedFile(coords, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in Coords_readFromFile(%p,%s)" "\n bad Coords file name %s," "\n must end in %s (binary) or %s (formatted)\n", coords, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in Coords_readFromFile(%p,%s)" "\n bad Coords file name %s," "\n must end in %s (binary) or %s (formatted)\n", coords, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- to read an Coords object from a formatted file return value -- 1 if success, 0 if failure created -- 95dec19, cca --------------------------------------------------------- */ int Coords_readFromFormattedFile ( Coords *coords, FILE *fp ) { int rc, size ; int itemp[3] ; /* --------------- check the input --------------- */ if ( coords == NULL || fp == NULL ) { fprintf(stderr, "\n error in Coords_readFromFormattedFile(%p,%p)" "\n bad input\n", coords, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ Coords_clearData(coords) ; /* --------------------------------------- read in the three scalar parameters type, # of dimensions, # of coordinates --------------------------------------- */ if ( (rc = IVfscanf(fp, 3, itemp)) != 3 ) { fprintf(stderr, "\n error in Coords_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", coords, fp, rc, 3) ; return(0) ; } /* --------------------- initialize the object --------------------- */ Coords_init(coords, itemp[0], itemp[1], itemp[2]) ; /* -------------------------- read in the coors[] vector -------------------------- */ size = itemp[1]*itemp[2] ; if ( (rc = FVfscanf(fp, size, coords->coors)) != size ) { fprintf(stderr, "\n error in Coords_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", coords, fp, rc, size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to read an Coords object from a binary file return value -- 1 if success, 0 if failure created -- 95dec19, cca ------------------------------------------------------ */ int Coords_readFromBinaryFile ( Coords *coords, FILE *fp ) { int rc, size ; int itemp[3] ; /* --------------- check the input --------------- */ if ( coords == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Coords_readFromBinaryFile(%p,%p)" "\n bad input\n", coords, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ Coords_clearData(coords) ; /* --------------------------------------- read in the three scalar parameters type, # of dimensions, # of coordinates --------------------------------------- */ if ( (rc = fread((void *) itemp, sizeof(int), 3, fp)) != 3 ) { fprintf(stderr, "\n error in Coords_readFromBinaryFile(%p,%p)" "\n itemp(3) : %d items of %d read\n", coords, fp, rc, 3) ; return(0) ; } /* --------------------- initialize the object --------------------- */ Coords_init(coords, itemp[0], itemp[1], itemp[2]) ; /* -------------------------- read in the coors[] vector -------------------------- */ size = itemp[1]*itemp[2] ; if ( (rc = fread((void *) coords->coors, sizeof(float), size, fp)) != size ) { fprintf(stderr, "\n error in Coords_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", coords, fp, rc, size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to write an Coords object to a file input -- fn -- filename *.coordsb -- binary *.coordsf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95dec19, cca ---------------------------------------------- */ int Coords_writeToFile ( Coords *coords, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( coords == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in Coords_writeToFile(%p,%s)" "\n bad input\n", coords, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in Coords_writeToFile(%p,%s)" "\n unable to open file %s", coords, fn, fn) ; rc = 0 ; } else { rc = Coords_writeToBinaryFile(coords, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in Coords_writeToFile(%p,%s)" "\n unable to open file %s", coords, fn, fn) ; rc = 0 ; } else { rc = Coords_writeToFormattedFile(coords, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in Coords_writeToFile(%p,%s)" "\n unable to open file %s", coords, fn, fn) ; rc = 0 ; } else { rc = Coords_writeForHumanEye(coords, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in Coords_writeToFile(%p,%s)" "\n unable to open file %s", coords, fn, fn) ; rc = 0 ; } else { rc = Coords_writeForHumanEye(coords, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to write an Coords object to a formatted file return value -- 1 if success, 0 otherwise created -- 95dec19, cca -------------------------------------------------------- */ int Coords_writeToFormattedFile ( Coords *coords, FILE *fp ) { int rc, size ; /* --------------- check the input --------------- */ if ( coords == NULL || fp == NULL || (size = coords->ndim * coords->ncoor) <= 0 ) { fprintf(stderr, "\n fatal error in Coords_writeToFormattedFile(%p,%p)" "\n bad input\n", coords, fp) ; exit(-1) ; } /* ------------------------------------- write out the three scalar parameters ------------------------------------- */ rc = fprintf(fp, "\n %d %d %d", coords->type, coords->ndim, coords->ncoor) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Coords_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", coords, fp, rc) ; return(0) ; } /* -------------------------------- write out the coordinates vector -------------------------------- */ FVfprintf(fp, size, coords->coors) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to write an Coords object to a binary file return value -- 1 if success, 0 otherwise created -- 95dec19, cca ----------------------------------------------------- */ int Coords_writeToBinaryFile ( Coords *coords, FILE *fp ) { int rc, size ; int itemp[3] ; /* --------------- check the input --------------- */ if ( coords == NULL || fp == NULL || (size = coords->ndim * coords->ncoor) <= 0 ) { fprintf(stderr, "\n fatal error in Coords_writeToBinaryFile(%p,%p)" "\n bad input\n", coords, fp) ; exit(-1) ; } itemp[0] = coords->type ; itemp[1] = coords->ndim ; itemp[2] = coords->ncoor ; rc = fwrite((void *) itemp, sizeof(int), 3, fp) ; if ( rc != 3 ) { fprintf(stderr, "\n error in Coords_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", coords, fp, rc, 3) ; return(0) ; } rc = fwrite((void *) coords->coors, sizeof(float), size, fp) ; if ( rc != size ) { fprintf(stderr, "\n error in Coords_writeToBinaryFile(%p,%p)" "\n coords->coors, %d of %d items written\n", coords, fp, rc, size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to write an Coords object for a human eye return value -- 1 if success, 0 otherwise created -- 95dec19, cca ---------------------------------------------------- */ int Coords_writeForHumanEye ( Coords *coords, FILE *fp ) { int icoor, idim, rc ; if ( coords == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Coords_writeForHumanEye(%p,%p)" "\n bad input\n", coords, fp) ; exit(-1) ; } if ( (rc = Coords_writeStats(coords, fp)) == 0 ) { fprintf(stderr, "\n fatal error in Coords_writeForHumanEye(%p,%p)" "\n rc = %d, return from Coords_writeStats(%p,%p)\n", coords, fp, rc, coords, fp) ; return(0) ; } for ( icoor = 0 ; icoor < coords->ncoor ; icoor++ ) { fprintf(fp, "\n %6d", icoor) ; for ( idim = 1 ; idim <= coords->ndim ; idim++ ) { fprintf(fp, " %12.4g", Coords_value(coords, idim, icoor)) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to write out the statistics for the Coords object return value -- 1 if success, 0 otherwise created -- 95dec19, cca ------------------------------------------------------------ */ int Coords_writeStats ( Coords *coords, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( coords == NULL || fp == NULL ) { fprintf(stderr, "\n error in Coords_writeStats(%p,%p)" "\n bad input\n", coords, fp) ; exit(-1) ; } rc = fprintf(fp, "\n Coords : coordinates object :") ; if ( rc < 0 ) { goto IO_error ; } rc = fprintf(fp, "\n type %d", coords->type) ; if ( rc < 0 ) { goto IO_error ; } switch ( coords->type ) { case 1 : rc = fprintf(fp, ", storage by tuples") ; break ; case 2 : rc = fprintf(fp, ", storage by vectors") ; break ; } if ( rc < 0 ) { goto IO_error ; } rc = fprintf(fp, "\n %d dimensions, %d coordinates, occupies %d bytes", coords->ndim, coords->ncoor, Coords_sizeOf(coords)) ; if ( rc < 0 ) { goto IO_error ; } return(1) ; IO_error : fprintf(stderr, "\n fatal error in Coords_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", coords, fp, rc) ; return(0) ; } /*--------------------------------------------------------------------*/ NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in Coords_writeToFile(%p,%s)" "\n bad input\n", coords, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in Coords_writeToFile(%p,%s)" "\n unable to open file %s", coords, fn, fCoords/src/basics.c010064400020550007177000000042010653503636200155260ustar00clevecompmath00000400000006/* basics.c */ #include "../Coords.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 95dec17, cca ----------------------- */ Coords * Coords_new ( void ) { Coords *coords ; ALLOCATE(coords, struct _Coords, 1) ; Coords_setDefaultFields(coords) ; return(coords) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 95dec17, cca ----------------------- */ void Coords_setDefaultFields ( Coords *coords ) { if ( coords == NULL ) { fprintf(stderr, "\n fatal error in Coords_setDefaultFields(%p)" "\n bad input", coords) ; exit(-1) ; } coords->type = COORDS_BY_TUPLE ; coords->ndim = 0 ; coords->ncoor = 0 ; coords->coors = NULL ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 95dec17, cca -------------------------------------------------- */ void Coords_clearData ( Coords *coords ) { /* --------------- check the input --------------- */ if ( coords == NULL ) { fprintf(stderr, "\n fatal error in Coords_clearData(%p)" "\n bad input\n", coords) ; exit(-1) ; } if ( coords->coors != NULL ) { FVfree(coords->coors) ; } /* ---------------------- set the default fields ---------------------- */ Coords_setDefaultFields(coords) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 95dec17, cca ------------------------------------------ */ Coords * Coords_free ( Coords *coords ) { if ( coords == NULL ) { fprintf(stderr, "\n fatal error in Coords_free(%p)" "\n bad input\n", coords) ; exit(-1) ; } Coords_clearData(coords) ; FREE(coords) ; return(NULL) ; } /*--------------------------------------------------------------------*/ Coords/src/init.c010064400020550007177000000136010653503604700152310ustar00clevecompmath00000400000006/* init.C */ #include "../Coords.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------- initialize the object, storage freed if repeat call created -- 95dec17, cca --------------------------------------------------- */ void Coords_init ( Coords *coords, int type, int ndim, int ncoor ) { /* --------------- check the input --------------- */ if ( coords == NULL || !(type == COORDS_BY_TUPLE || type == COORDS_BY_COORD) || ndim < 1 || ncoor <= 0 ) { fprintf(stderr, "\n fatal error in Coords_init(%p,%d,%d,%d)" "\n bad input\n", coords, type, ndim, ncoor) ; exit(-1) ; } /* -------------- clear the data -------------- */ Coords_clearData(coords) ; /* ------------------- set the data fields ------------------- */ coords->type = type ; coords->ndim = ndim ; coords->ncoor = ncoor ; coords->coors = FVinit(ndim*ncoor, 0.0) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- purpose -- initialize a 9-point operator on a n1 x n2 grid input -- bbox -- bounding box bbox[0] -- x southwest bbox[1] -- y southwest bbox[2] -- x northeast bbox[3] -- y northeast Type -- type of object n1 -- # of grid points in first direction n2 -- # of grid points in second direction ncomp -- # of components per grid point created -- 95dec17, cca ---------------------------------------------------------- */ void Coords_init9P ( Coords *coords, float bbox[], int type, int n1, int n2, int ncomp ) { int i, idof, j, k ; float deltax, deltay ; float *x, *y ; /* --------------- check the input --------------- */ if ( coords == NULL || bbox == NULL || !(type == COORDS_BY_TUPLE || type == COORDS_BY_COORD) || n1 <= 0 || n2 <= 0 || ncomp <= 0 ) { fprintf(stderr, "\n fatal error in Coords_init9P(%p,%p,%d,%d,%d,%d)" "\n bad input\n", coords, bbox, type, n1, n2, ncomp) ; exit(-1) ; } /* --------------------- initialize the object --------------------- */ Coords_init(coords, type, 2, n1*n2) ; /* -------------------- fill the coordinates -------------------- */ deltax = (bbox[2] - bbox[0]) / (n1-1) ; deltay = (bbox[3] - bbox[1]) / (n2-1) ; switch ( type ) { case COORDS_BY_TUPLE : x = coords->coors ; y = coords->coors + 1 ; for ( j = 0, idof = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { for ( k = 0 ; k < ncomp ; k++, idof += 2 ) { x[idof] = bbox[0] + deltax*i ; y[idof] = bbox[1] + deltay*j ; } } } break ; case COORDS_BY_COORD : x = coords->coors ; y = coords->coors + n1*n2 ; for ( j = 0, idof = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { for ( k = 0 ; k < ncomp ; k++, idof++ ) { x[idof] = bbox[0] + deltax*i ; y[idof] = bbox[1] + deltay*j ; } } } break ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- initialize a 27-point operator on a n1 x n2 x n3 grid input -- bbox -- bounding box bbox[0] -- x southwest bottom bbox[1] -- y southwest bottom bbox[2] -- z southwest bottom bbox[3] -- x northeast top bbox[4] -- y northeast top bbox[5] -- z northeast top Type -- type of object n1 -- # of grid points in first direction n2 -- # of grid points in second direction n3 -- # of grid points in third direction ncomp -- # of components per grid point created -- 95dec17, cca ---------------------------------------------------------------- */ void Coords_init27P ( Coords *coords, float bbox[], int type, int n1, int n2, int n3, int ncomp ) { int i, idof, j, k, l ; float deltax, deltay, deltaz ; float *x, *y, *z ; /* --------------- check the input --------------- */ if ( coords == NULL || bbox == NULL || !(type == COORDS_BY_TUPLE || type == COORDS_BY_COORD) || n1 <= 0 || n2 <= 0 || n3 <= 0 || ncomp <= 0 ) { fprintf(stderr, "\n fatal error in Coords_init27P(%p,%p,%d,%d,%d,%d,%d)" "\n bad input\n", coords, bbox, type, n1, n2, n3, ncomp) ; exit(-1) ; } /* --------------------- initialize the object --------------------- */ Coords_init(coords, type, 3, n1*n2*n3) ; /* -------------------- fill the coordinates -------------------- */ deltax = (bbox[3] - bbox[0]) / (n1-1) ; deltay = (bbox[4] - bbox[1]) / (n2-1) ; deltaz = (bbox[5] - bbox[2]) / (n3-1) ; switch ( type ) { case COORDS_BY_TUPLE : x = coords->coors ; y = coords->coors + 1 ; z = coords->coors + 2 ; for ( k = 0, idof = 0 ; k < n3 ; k++ ) { for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { for ( l = 0 ; l < ncomp ; l++, idof += 3 ) { x[idof] = bbox[0] + deltax*i ; y[idof] = bbox[1] + deltay*j ; z[idof] = bbox[2] + deltaz*k ; } } } } break ; case COORDS_BY_COORD : x = coords->coors ; y = coords->coors + coords->ncoor ; z = coords->coors + 2*coords->ncoor ; for ( k = 0, idof = 0 ; k < n3 ; k++ ) { for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { for ( l = 0 ; l < ncomp ; l++, idof++ ) { x[idof] = bbox[0] + deltax*i ; y[idof] = bbox[1] + deltay*j ; z[idof] = bbox[2] + deltaz*k ; } } } } break ; } return ; } /*--------------------------------------------------------------------*/ Coords/src/util.c010064400020550007177000000150530653503640000152370ustar00clevecompmath00000400000006/* basics.C */ #include "../Coords.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95dec17, cca ---------------------------------------------- */ int Coords_sizeOf ( Coords *coords ) { int nbytes ; /* --------------- check the input --------------- */ if ( coords == NULL ) { fprintf(stderr, "\n fatal error in Coords_sizeof(%p)" "\n bad input\n", coords) ; exit(-1) ; } nbytes = sizeof(struct _Coords) ; if ( coords->ndim > 0 && coords->ncoor > 0 ) { nbytes += coords->ndim * coords->ncoor * sizeof(float) ; } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- return the minimum coordinate in the dim-direction created -- 95dec17, cca -------------------------------------------------- */ float Coords_min ( Coords *coords, int dim ) { float minval ; float *coors ; int i, j, ncoor, ndim ; if ( coords == NULL ) { fprintf(stderr, "\n fatal error in Coords_min(%p,%d)" "\n bad input \n", coords, dim) ; exit(-1) ; } else if ( !(coords->type == COORDS_BY_TUPLE || coords->type == COORDS_BY_COORD) ) { fprintf(stderr, "\n fatal error in Coords_min(%p,%d)" "\n coords->type = %d", coords, dim, coords->type) ; exit(-1) ; } else if ( (ndim = coords->ndim) < 1 ) { fprintf(stderr, "\n fatal error in Coords_min(%p,%d)" "\n coords->ndim = %d", coords, dim, coords->ndim) ; exit(-1) ; } else if ( (ncoor = coords->ncoor) < 1 ) { fprintf(stderr, "\n fatal error in Coords_min(%p,%d)" "\n coords->ncoor = %d", coords, dim, coords->ncoor) ; exit(-1) ; } else if ( (coors = coords->coors) == NULL ) { fprintf(stderr, "\n fatal error in Coords_min(%p,%d)" "\n coords->coords = %p", coords, dim, coords->coors) ; exit(-1) ; } else if ( dim <= 0 || dim > coords->ndim ) { fprintf(stderr, "\n fatal error in Coords_min(%p,%d)" "\n bad input value, dim %d, ndim %d", coords, dim, dim, ndim) ; exit(-1) ; } switch ( coords->type ) { case COORDS_BY_TUPLE : i = dim - 1 ; minval = coors[i] ; for ( j = 1, i += ndim ; j < ncoor ; j++, i += ndim ) { if ( coors[i] < minval ) { minval = coors[i] ; } } break ; case COORDS_BY_COORD : i = (dim - 1)*ncoor ; minval = coors[i] ; for ( i++ ; i < ncoor ; i++ ) { if ( coors[i] < minval ) { minval = coors[i] ; } } break ; } return(minval) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- return the maximum coordinate in the dim-direction created -- 95dec17, cca -------------------------------------------------- */ float Coords_max ( Coords *coords, int dim ) { float maxval ; float *coors ; int i, j, ncoor, ndim ; if ( coords == NULL ) { fprintf(stderr, "\n fatal error in Coords_max(%p,%d)" "\n bad input \n", coords, dim) ; exit(-1) ; } else if ( !(coords->type == COORDS_BY_TUPLE || coords->type == COORDS_BY_COORD) ) { fprintf(stderr, "\n fatal error in Coords_max(%p,%d)" "\n coords->type = %d", coords, dim, coords->type) ; exit(-1) ; } else if ( (ndim = coords->ndim) < 1 ) { fprintf(stderr, "\n fatal error in Coords_max(%p,%d)" "\n coords->ndim = %d", coords, dim, coords->ndim) ; exit(-1) ; } else if ( (ncoor = coords->ncoor) < 1 ) { fprintf(stderr, "\n fatal error in Coords_max(%p,%d)" "\n coords->ncoor = %d", coords, dim, coords->ncoor) ; exit(-1) ; } else if ( (coors = coords->coors) == NULL ) { fprintf(stderr, "\n fatal error in Coords_max(%p,%d)" "\n coords->coords = %p", coords, dim, coords->coors) ; exit(-1) ; } else if ( dim <= 0 || dim > coords->ndim ) { fprintf(stderr, "\n fatal error in Coords_max(%p,%d)" "\n bad input value, dim %d, ndim %d", coords, dim, dim, ndim) ; exit(-1) ; } switch ( coords->type ) { case COORDS_BY_TUPLE : i = dim - 1 ; maxval = coors[i] ; for ( j = 1, i += ndim ; j < ncoor ; j++, i += ndim ) { if ( coors[i] > maxval ) { maxval = coors[i] ; } } break ; case COORDS_BY_COORD : i = (dim - 1)*ncoor ; maxval = coors[i] ; for ( i++ ; i < ncoor ; i++ ) { if ( coors[i] > maxval ) { maxval = coors[i] ; } } break ; } return(maxval) ; } /*--------------------------------------------------------------------*/ /* ----------------------- 1 <= idim <= ndim 0 <= icoor < ncoor created -- 95dec17, cca ----------------------- */ float Coords_value ( Coords *coords, int idim, int icoor ) { float val ; /* --------------- check the input --------------- */ if ( coords == NULL || idim <= 0 || !(coords->type == COORDS_BY_TUPLE || coords->type == COORDS_BY_COORD) || icoor < 0 || coords->ncoor <= icoor || coords->coors == NULL ) { fprintf(stderr, "\n fatal error in Coords_value(%p,%d,%d)" "\n bad input or object\n", coords, idim, icoor) ; exit(-1) ; } switch ( coords->type ) { case COORDS_BY_TUPLE : val = coords->coors[idim - 1 + coords->ndim*icoor] ; break ; case COORDS_BY_COORD : val = coords->coors[icoor + coords->ncoor*(idim - 1)] ; break ; } return(val) ; } /*--------------------------------------------------------------------*/ /* ----------------------- 1 <= idim <= ndim 0 <= icoor < ncoor created -- 95dec17, cca ----------------------- */ void Coords_setValue ( Coords *coords, int idim, int icoor, float val ) { /* --------------- check the input --------------- */ if ( coords == NULL || idim <= 0 || !(coords->type == COORDS_BY_TUPLE || coords->type == COORDS_BY_COORD) || icoor < 0 || coords->ncoor <= icoor || coords->coors == NULL ) { fprintf(stderr, "\n fatal error in Coords_setValue(%p,%d,%d,%f)" "\n bad input or object\n", coords, idim, icoor, val) ; exit(-1) ; } switch ( coords->type ) { case COORDS_BY_TUPLE : coords->coors[idim - 1 + coords->ndim*icoor] = val ; break ; case COORDS_BY_COORD : coords->coors[icoor + coords->ncoor*(idim - 1)] = val ; break ; } return ; } /*--------------------------------------------------------------------*/ i, j, ncoor, ndim ; if ( coords == NULL ) { fprintf(stderr, "\n fatal error in Coords_max(%p,%d)" "\n bad input \n", coords, dim) ; exit(-1) ; } else if ( !(coords->type == COORDS_BY_TUPLE || coords->type == COORDS_BY_COORD) ) { fprintf(stderr, "\n fatal error in Coords_max(%p,%d)" "\n coords->type = %d", coords, dim, coords->type) ; exit(-1) ; } else if ( (ndim = coords->ndim) < 1 ) { fprintf(stderr, "\n Coords/drivers/do_mk9PCoords010075500020550007177000000004660653503722200174140ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 3 set msgFile = stdout set n1 = 7 set n2 = 7 set matrices = ../../Matrices set matrix = GRD7x7 set outCoordsFile = $matrices/$matrix/$matrix.coordsf set outCoordsFile = temp.coordsf mk9PCoords $msglvl $msgFile $n1 $n2 $outCoordsFile Coords/drivers/do_testIO010075500020550007177000000007540653410577400166400ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 2 set msgFile = stdout set n1 = 7 set n2 = 7 set matrices = ../../Matrices set matrix = GRD7x7 set inCoordsFile = none set inCoordsFile = $matrices/$matrix/$matrix.coordsb set inCoordsFile = $matrices/$matrix/$matrix.coordsf set outCoordsFile = $matrices/$matrix/$matrix.coordsf set outCoordsFile = $matrices/$matrix/$matrix.coordsb set outCoordsFile = none testIO $msglvl $msgFile $inCoordsFile $outCoordsFile Coords/drivers/makefile010064400020550007177000000006370665314240600165140ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testIO mk9PCoords drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} mk9PCoords : mk9PCoords.o ../../spooles.a ${PURIFY} $(CC) $@.o -o $@ $(PURIFY_GCC_VERSION) $(LIBS) testIO : testIO.o ../../spooles.a ${PURIFY} $(CC) $@.o -o $@ $(PURIFY_GCC_VERSION) $(LIBS) Coords/drivers/mk9PCoords.c010064400020550007177000000041300653503704500171430ustar00clevecompmath00000400000006/* mk9PCoords.c */ #include "../Coords.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------ create a Coords object for a 9P grid created -- 96feb02, cca ------------------------------------ */ { Coords *coords ; double t1, t2 ; FILE *msgFile ; float bbox[4] = { 0.0, 0.0, 1.0, 1.0 } ; int msglvl, n1, n2 ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 outCoordsFile \n" "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- # of grid points in first direction" "\n n2 -- # of grid points in second direction" "\n outCoordsFile -- file to write out Coords object" "\n", argv[0]) ; return(1) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s", argv[0], argv[2]) ; exit(-1) ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; fprintf(msgFile, "\n\n %s %d %s %d %d %s", argv[0], msglvl, argv[2], n1, n2, argv[5]) ; fflush(msgFile) ; /* ------------------------ create the Coords object ------------------------ */ MARKTIME(t1) ; coords = Coords_new() ; Coords_init9P(coords, bbox, COORDS_BY_TUPLE, n1, n2, 1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %.3f : create Coords object", (t2 - t1)) ; if ( msglvl <= 2 ) { Coords_writeStats(coords, msgFile) ; fflush(msgFile) ; } else { Coords_writeForHumanEye(coords, msgFile) ; fflush(msgFile) ; } /* --------------------------- write out the Coords object --------------------------- */ if ( strcmp("none", argv[5]) != 0 ) { MARKTIME(t1) ; Coords_writeToFile(coords, argv[5]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %.3f : write out Coords to file %s", (t2 - t1), argv[5]) ; } fprintf(msgFile, "\n") ; fflush(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Coords/drivers/testIO.c010064400020550007177000000051040653505057700163670ustar00clevecompmath00000400000006/* testIO.c */ #include "../Coords.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------------------------- test Coords_readFromFile and Coords_writeToFile, useful for translating between formatted *.coordsf and binary *.coordsb files. created -- 95dec17, cca -------------------------------------------------- */ { int msglvl, rc ; Coords coords ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : testIO msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.coordsf or *.coordsb" "\n outFile -- output file, must be *.coordsf or *.coordsb" "\n") ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } fprintf(msgFile, "\n testIO " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", msglvl, argv[2], argv[3], argv[4]) ; fflush(msgFile) ; /* ---------------------- set the default fields ---------------------- */ Coords_setDefaultFields(&coords) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after setting default fields") ; Coords_writeForHumanEye(&coords, msgFile) ; fflush(msgFile) ; } /* ------------------------- read in the Coords object ------------------------- */ if ( strcmp(argv[3], "none") == 0 ) { fprintf(msgFile, "\n no file to read from\n") ; exit(0) ; } rc = Coords_readFromFile(&coords, argv[3]) ; fprintf(msgFile, "\n return value %d from Coords_readFromFile(%p,%s)", rc, &coords, argv[3]) ; if ( rc != 1 ) { exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after reading Coords object from file %s", argv[3]) ; Coords_writeForHumanEye(&coords, msgFile) ; fflush(msgFile) ; } /* --------------------------- write out the Coords object --------------------------- */ if ( strcmp(argv[4], "none") != 0 ) { rc = Coords_writeToFile(&coords, argv[4]) ; fprintf(msgFile, "\n return value %d from Coords_writeToFile(%p,%s)", rc, &coords, argv[4]) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Coords/doc/004275500020550007177000000000000654276733000141105ustar00clevecompmath00000400000006Coords/doc/drivers.tex010064400020550007177000000055560653410577500163160ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt Coords} object} \label{section:Coords:drivers} \par This section contains brief descriptions of the driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program reads and write {\tt Coords} files, useful for converting formatted files to binary files and vice versa. One can also read in a {\tt Coords} file and print out just the header information (see the {\tt Coords\_writeStats()} method). \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt Coords} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt Coords} object. It must be of the form {\tt *.coordsf} or {\tt *.coordsb}. The {\tt Coords} object is read from the file via the {\tt Coords\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt Coords} object. If {\tt outFile} is {\tt none} then the {\tt Coords} object is not written to a file. Otherwise, the {\tt Coords\_writeToFile()} method is called to write the object to a formatted file (if {\tt outFile} is of the form {\tt *.coordsf}), or a binary file (if {\tt outFile} is of the form {\tt *.coordsb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} mk9PCoords msglvl msgFile n1 n2 outCoordsFile \end{verbatim} This driver program creates a {\tt Coords} object for 9-point finite difference operator on a $\mbox{\tt n1} \times \mbox{\tt n2}$ grid and optionally writes it to a file. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any message data. \item The {\tt outCoordsFile} parameter is the output file for the {\tt Coords} object. If {\tt outCoordsFile} is {\tt none} then the {\tt Coords} object is not written to a file. Otherwise, the {\tt Coords\_writeToFile()} method is called to write the object to a formatted file (if {\tt outCoordsFile} is of the form {\tt *.coordsf}), or a binary file (if {\tt outCoordsFile} is of the form {\tt *.coordsb}). \end{itemize} %----------------------------------------------------------------------- \end{enumerate} Coords/doc/dataStructure.tex010064000020550007177000000017770653410577500174670ustar00clevecompmath00000400000006\par \section{Data Structure} \par The {\tt Coords} object has four fields. \begin{itemize} \item {\tt int type} : coordinate type. When {\tt type = 1}, coordinates are stored by tuples, $(x_0,y_0,\ldots)$ first, $(x_1,y_1,\ldots)$ next, etc. % \begin{verbatim} % x(icoor, idim) = coors[idim + icoor*ndim] % \end{verbatim} When {\tt type = 2}, coordinates are stored by $x$-coordinates first, $y$-coordinates next, etc. % \begin{verbatim} % x(icoor, idim) = coors[icoor + idim*ncoor] % \end{verbatim} \item {\tt int ndim} : number of dimensions for the coordinates, e.g., for $(x,y)$ coordinates {\tt ndim = 2}, for $(x,y,z)$ coordinates {\tt ndim = 3}. \item {\tt int ncoor} : number of coordinates (i.e., number of grid points). \item {\tt float *coors} : pointer to a {\tt float} vector that holds the coordinates \end{itemize} A correctly initialized and nontrivial {\tt Coords} object will have {\tt type} be {\tt 1} or {\tt 2}, positive {\tt ndim} and {\tt ncoor} values, and a non-{\tt NULL} {\tt coors} field. Coords/doc/intro.tex010064000020550007177000000003100653410577500157460ustar00clevecompmath00000400000006\chapter{{\tt Coords}: Coordinates Object} \par The {\tt Coords} object is used to hold $(x,y)$, $(x,y,z)$ or larger dimensional coordinates. We use it to visualize two- and three-dimensional graphs. Coords/doc/main.tex010064400020550007177000000011020665065620000155340ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Coords} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Coords} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} Coords/doc/proto.tex010064400020550007177000000340130653503742100157620ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Coords} methods} \label{section:Coords:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Coords} object. \par \subsection{Basic methods} \label{subsection:Coords:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Coords * Coords_new ( void ) ; \end{verbatim} \index{Coords_new@{\tt Coords\_new()}} This method simply allocates storage for the {\tt Coords} structure and then sets the default fields by a call to {\tt Coords\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Coords_setDefaultFields ( Coords *coords ) ; \end{verbatim} \index{Coords_setDefaultFields@{\tt Coords\_setDefaultFields()}} This method sets the structure's fields are set to default values: {\tt type = COORDS\_BY\_TUPLE}, {\tt ndim = ncoor = 0} and {\tt coors = NULL}. \par \noindent {\it Error checking:} If {\tt coords} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Coords_clearData ( Coords *coords ) ; \end{verbatim} \index{Coords_clearData@{\tt Coords\_clearData()}} This method clears data and releases any storage allocated by the object. If {\tt coords->coors} is not {\tt NULL}, then {\tt FVfree(coords->coors)} is called to free the {\tt float} vector. It then sets the structure's default fields with a call to {\tt Coords\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt coords} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Coords_free ( Coords *coords ) ; \end{verbatim} \index{Coords_free@{\tt Coords\_free()}} This method releases any storage by a call to {\tt Coords\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt coords} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:Coords:proto:initializers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Coords_init ( Coords *coords, int type, int ndim, int ncoor ) ; \end{verbatim} \index{Coords_init@{\tt Coords\_init()}} This method initializes a {\tt Coords} object given the type, number of dimensions and number of grid points. It clears any previous data with a call to {\tt Coords\_clearData()}. The {\tt float} vector is initialized by a call to {\tt FVinit()}. \par \noindent {\it Error checking:} If {\tt coords} is {\tt NULL} or {\tt type} is not {\tt COORDS\_BY\_TUPLE} or {\tt COORDS\_BY\_COORD}, or if either {\tt ndim} or {\tt ncoor} are nonpositive, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Coords_init9P ( Coords *coords, float bbox[], int type, int n1, int n2, int ncomp ) ; \end{verbatim} \index{Coords_init9P@{\tt Coords\_init9P()}} This method initializes a {\tt Coords} object for a 9-point operator on a $\mbox{\tt n1} \times \mbox{\tt n2}$ grid with {\tt ncomp} degrees of freedom at a grid point. The grid's location is given by the bounding box vector, {\tt bbox[0]} = $x$-coordinate of the southwest point, {\tt bbox[1]} = $y$-coordinate of the southwest point, {\tt bbox[2]} = $x$-coordinate of the northeast point, and {\tt bbox[3]} = $y$-coordinate of the northeast point. \par \noindent {\it Error checking:} If {\tt coords} {\tt bbox} is {\tt NULL}, or if {\tt type} is not {\tt COORDS\_BY\_TUPLE} or {\tt COORDS\_BY\_COORD}, or if any of {\tt n1}, {\tt n2} or {\tt ncomp} are nonpositive, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Coords_init27P ( Coords *coords, float bbox[], int type, int n1, int n2, int n3, int ncomp ) ; \end{verbatim} \index{Coords_init27P@{\tt Coords\_init27P()}} This method initializes a {\tt Coords} object for a 27-point operator on a $\mbox{\tt n1} \times \mbox{\tt n2} \times {\tt n3}$ grid with {\tt ncomp} degrees of freedom at a grid point. The grid's location is given by the bounding box vector, {\tt bbox[0]} = $x$-coordinate of the southwest point, {\tt bbox[1]} = $y$-coordinate of the southwest point, {\tt bbox[2]} = $z$-coordinate of the southwest point, {\tt bbox[3]} = $x$-coordinate of the northeast point, {\tt bbox[4]} = $y$-coordinate of the northeast point, and {\tt bbox[5]} = $z$-coordinate of the northeast point. \par \noindent {\it Error checking:} If {\tt coords} {\tt bbox} is {\tt NULL}, or if {\tt type} is not {\tt COORDS\_BY\_TUPLE} or {\tt COORDS\_BY\_COORD}, or if any of {\tt n1}, {\tt n2}, {\tt n3} or {\tt ncomp} are nonpositive, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:Coords:proto:utilities} \par There are three utility methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Coords_sizeOf ( Coords *coords ) ; \end{verbatim} \index{Coords_sizeOf@{\tt Coords\_sizeOf()}} This method returns the number of bytes that the object occupies. \par \noindent {\it Error checking:} If {\tt coords} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} float Coords_min ( Coords *coords, int dim ) \end{verbatim} \index{Coords_min@{\tt Coords\_min()}} This method returns the minimum coordinate value for the {\tt dim}'th entry in the coordinates. For example, {\tt Coords\_min(coords, 1)} is the minimum $x$-value and {\tt Coords\_min(coords, 2)} is the minimum $y$-value. \par \noindent {\it Error checking:} If {\tt coords} is {\tt NULL}, or if {\tt idim} does not lie in the range {\tt [1,ndim]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} float Coords_max ( Coords *coords, int dim ) \end{verbatim} \index{Coords_max@{\tt Coords\_max()}} This method returns the maximum coordinate value for the {\tt dim}'th entry in the coordinates. For example, {\tt Coords\_max(coords, 1)} is the maximum $x$-value and {\tt Coords\_max(coords, 2)} is the maximum $y$-value. \par \noindent {\it Error checking:} If {\tt coords} is {\tt NULL}, or if {\tt idim} does not lie in the range {\tt [1,ndim]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} float Coords_value ( Coords *coords, int idim, int icoor ) ; \end{verbatim} \index{Coords_value@{\tt Coords\_value()}} This method returns the {\tt float} value of the {\tt idim}-th coordinate of the {\tt icoor}-th grid point. For example, {\tt Coords\_value(coords, 1, 27)} returns $x_{27}$, {\tt Coords\_value(coords, 2, 16)} returns $y_{16}$, and {\tt Coords\_value(coords, 3, 118)} returns $z_{118}$. \par \noindent {\it Error checking:} If {\tt coords} is {\tt NULL}, or if {\tt idim} does not lie in the range {\tt [1,ndim]}, or if {\tt icoor} does not lie in the range {\tt [0,ncoor)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Coords_setValue ( Coords *coords, int idim, int icoor, float val ) ; \end{verbatim} \index{Coords_setValue@{\tt Coords\_setValue()}} This method sets the {\tt float} value of the {\tt idim}-th coordinate of the {\tt icoor}-th grid point. For example, {\tt Coords\_setValue(coords, 1, 27, 1.2)} sets $x_{27} = 1.2$, {\tt Coords\_setValue(coords, 2, 16, 3.3)} sets $y_{16} = 3.3$, and {\tt Coords\_setValue(coords, 3, 118, 0)} sets $z_{118} = 0$. \par \noindent {\it Error checking:} If {\tt coords} is {\tt NULL}, or if {\tt idim} does not lie in the range {\tt [1,ndim]}, or if {\tt icoor} does not lie in the range {\tt [0,ncoor)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:Coords:proto:IO} \par There are the usual eight IO routines. The file structure of a {\tt Coords} object is simple: {\tt type}, {\tt ndim}, {\tt ncoor} followed by the {\tt coors[]} vector. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Coords_readFromFile ( Coords *coords, char *filename ) ; \end{verbatim} \index{Coords_readFromFile@{\tt Coords\_readFromFile()}} \par This method read a {\tt Coords} object from a file. It tries to open the file and if it is successful, it then calls {\tt Coords\_readFromFormattedFile()} or {\tt Coords\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt coords} or {\tt filename} is {\tt NULL}, or if {\tt filename} is not of the form {\tt *.coordsf} (for a formatted file) or {\tt *.coordsb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int Coords_readFromFormattedFile ( Coords *coords, FILE *fp ) ; \end{verbatim} \index{Coords_readFromFormattedFile@{\tt Coords\_readFromFormattedFile()}} \par This method reads in a {\tt Coords} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt coords} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Coords_readFromBinaryFile ( Coords *coords, FILE *fp ) ; \end{verbatim} \index{Coords_readFromBinaryFile@{\tt Coords\_readFromBinaryFile()}} \par This method reads in a {\tt Coords} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt coords} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Coords_writeToFile ( Coords *coords, char *fn ) ; \end{verbatim} \index{Coords_writeToFile@{\tt Coords\_writeToFile()}} \par This method write a {\tt Coords} object to a file. The method tries to open the file and if it is successful, it then calls {\tt Coords\_writeFromFormattedFile()} or {\tt Coords\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt coords} or {\tt fn} is {\tt NULL}, or if {\tt fn} is not of the form {\tt *.coordsf} (for a formatted file) or {\tt *.coordsb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int Coords_writeToFormattedFile ( Coords *coords, FILE *fp ) ; \end{verbatim} \index{Coords_writeToFormattedFile@{\tt Coords\_writeToFormattedFile()}} \par This method writes a {\tt Coords} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt coords} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Coords_writeToBinaryFile ( Coords *coords, FILE *fp ) ; \end{verbatim} \index{Coords_writeToBinaryFile@{\tt Coords\_writeToBinaryFile()}} \par This method writes a {\tt Coords} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt coords} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Coords_writeForHumanEye ( Coords *coords, FILE *fp ) ; \end{verbatim} \index{Coords_writeForHumanEye@{\tt Coords\_writeForHumanEye()}} \par This method write the {\tt Coords} object to a file in an easy to read fashion. The method {\tt Coords\_writeStats()} is called to write out the header and statistics. The {\tt coors[]} vector is then printed out. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt coords} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Coords_writeStats ( Coords *coords, FILE *fp ) ; \end{verbatim} \index{Coords_writeStats@{\tt Coords\_writeStats()}} \par The header and statistics are written. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt coords} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} on{Utility methods} \label{subsection:Coords:proto:utilities} \par There are three utility methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Coords_sizeOf ( Coords *coords ) ; \end{verbatim} \index{Coords_sizeOf@{\tt Coords\_sizeOf()}} This method returns the number of bytes that the object occupies. \par \noindent {\it Error checking:} If {\ttCoords/doc/main.log010064400020550007177000000070510653503744000155270ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 2 JUN 1998 11:06 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. ) (dataStructure.tex) (proto.tex [1 ] Overfull \hbox (2.62105pt too wide) in paragraph at lines 105--113 \elvit Error check-ing: \elvrm If \elvtt coords bbox \elvrm is \elvtt NULL\elvr m , or if \elvtt type \elvrm is not \elvtt COORDS[]BY[]TUPLE \elvrm or \elvtt C OORDS[]BY[]COORD\elvrm , \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\elvit E .\elvit r .\elvit r .\kern-0.55968 .\elvit o .etc. [2] Overfull \hbox (2.62105pt too wide) in paragraph at lines 128--136 \elvit Error check-ing: \elvrm If \elvtt coords bbox \elvrm is \elvtt NULL\elvr m , or if \elvtt type \elvrm is not \elvtt COORDS[]BY[]TUPLE \elvrm or \elvtt C OORDS[]BY[]COORD\elvrm , \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\elvit E .\elvit r .\elvit r .\kern-0.55968 .\elvit o .etc. [3] Overfull \hbox (4.44226pt too wide) in paragraph at lines 283--289 \elvrm cess-ful, it then calls \elvtt Coords[]writeFromFormattedFile() \elvrm o r \elvtt Coords[]writeFromBinaryFile()\elvrm , \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\elvrm c .\elvrm e .\elvrm s .\elvrm s .\discretionary ..\elvrm - .etc. [4]) (drivers.tex Overfull \hbox (42.63402pt too wide) in paragraph at lines 30--35 \elvtt *.coordsf \elvrm or \elvtt *.coordsb\elvrm . The \elvtt Coords \elvrm ob -ject is read from the file via the \elvtt Coords[]readFromFile() \hbox(7.60416+2.12917)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt c .\elvtt o .\elvtt o .etc. Overfull \hbox (1.44826pt too wide) in paragraph at lines 65--74 [] []\elvrm The \elvtt outCoordsFile \elvrm pa-ram-e-ter is the out-put file fo r the \elvtt Coords \elvrm ob-ject. If \elvtt outCoordsFile \hbox(7.60416+2.12917)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm T .etc. Overfull \hbox (18.78839pt too wide) in paragraph at lines 65--74 \elvrm is \elvtt none \elvrm then the \elvtt Coords \elvrm ob-ject is not writ- ten to a file. Oth-er-wise, the \elvtt Coords[]writeToFile() \hbox(7.60416+2.12917)x418.2899, glue set - 1.0 .\elvrm i .\elvrm s .\glue 3.65 plus 1.825 minus 1.21666 .\elvtt n .\elvtt o .etc. [5]) (main.ind [6] [7 ]) (main.aux) ) Here is how much of TeX's memory you used: 207 strings out of 11977 2133 string characters out of 87269 33641 words of memory out of 262141 2141 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 14i,4n,17p,183b,226s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (7 pages, 18624 bytes). 1) (format=lplain 94.11.14) 2 JUN 1998 11:06 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/Coords/doc/main.aux010064400020550007177000000025620653503744000155450ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space Coords}: Coordinates Object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space Coords} methods}{1}} \newlabel{section:Coords:proto}{{1.2}{1}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{1}} \newlabel{subsection:Coords:proto:basics}{{1.2.1}{1}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initializer methods}{2}} \newlabel{subsection:Coords:proto:initializers}{{1.2.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{3}} \newlabel{subsection:Coords:proto:utilities}{{1.2.3}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}IO methods}{4}} \newlabel{subsection:Coords:proto:IO}{{1.2.4}{4}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs for the {\string\ptt\space Coords} object}{5}} \newlabel{section:Coords:drivers}{{1.3}{5}} Coords/doc/main.idx010064400020550007177000000023020653503744000155240ustar00clevecompmath00000400000006\indexentry{Coords_new@{\tt Coords\_new()}}{2} \indexentry{Coords_setDefaultFields@{\tt Coords\_setDefaultFields()}}{2} \indexentry{Coords_clearData@{\tt Coords\_clearData()}}{2} \indexentry{Coords_free@{\tt Coords\_free()}}{2} \indexentry{Coords_init@{\tt Coords\_init()}}{2} \indexentry{Coords_init9P@{\tt Coords\_init9P()}}{2} \indexentry{Coords_init27P@{\tt Coords\_init27P()}}{2} \indexentry{Coords_sizeOf@{\tt Coords\_sizeOf()}}{3} \indexentry{Coords_min@{\tt Coords\_min()}}{3} \indexentry{Coords_max@{\tt Coords\_max()}}{3} \indexentry{Coords_value@{\tt Coords\_value()}}{3} \indexentry{Coords_setValue@{\tt Coords\_setValue()}}{3} \indexentry{Coords_readFromFile@{\tt Coords\_readFromFile()}}{4} \indexentry{Coords_readFromFormattedFile@{\tt Coords\_readFromFormattedFile()}}{4} \indexentry{Coords_readFromBinaryFile@{\tt Coords\_readFromBinaryFile()}}{4} \indexentry{Coords_writeToFile@{\tt Coords\_writeToFile()}}{4} \indexentry{Coords_writeToFormattedFile@{\tt Coords\_writeToFormattedFile()}}{4} \indexentry{Coords_writeToBinaryFile@{\tt Coords\_writeToBinaryFile()}}{4} \indexentry{Coords_writeForHumanEye@{\tt Coords\_writeForHumanEye()}}{5} \indexentry{Coords_writeStats@{\tt Coords\_writeStats()}}{5} Coords/doc/main.ind010064400020550007177000000014310653503743400155170ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Coords\_clearData()}, 2 \item {\tt Coords\_free()}, 2 \item {\tt Coords\_init()}, 2 \item {\tt Coords\_init27P()}, 2 \item {\tt Coords\_init9P()}, 2 \item {\tt Coords\_max()}, 3 \item {\tt Coords\_min()}, 3 \item {\tt Coords\_new()}, 2 \item {\tt Coords\_readFromBinaryFile()}, 4 \item {\tt Coords\_readFromFile()}, 4 \item {\tt Coords\_readFromFormattedFile()}, 4 \item {\tt Coords\_setDefaultFields()}, 2 \item {\tt Coords\_setValue()}, 3 \item {\tt Coords\_sizeOf()}, 3 \item {\tt Coords\_value()}, 3 \item {\tt Coords\_writeForHumanEye()}, 5 \item {\tt Coords\_writeStats()}, 5 \item {\tt Coords\_writeToBinaryFile()}, 4 \item {\tt Coords\_writeToFile()}, 4 \item {\tt Coords\_writeToFormattedFile()}, 4 \end{theindex} Coords/doc/main.ilg010064400020550007177000000004560653503743400155260ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (20 entries accepted, 0 rejected). Sorting entries....done (93 comparisons). Generating output file main.ind....done (24 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Coords/doc/makefile010064400020550007177000000000270654276733000156020ustar00clevecompmath00000400000006clean : - rm -f *.dvi DSTree.h010064400020550007177000000001040653410640100133620ustar00clevecompmath00000400000006#ifndef _DSTree_ #define _DSTree_ #include "DSTree/DSTree.h" #endif DSTree/DSTree.h010064400020550007177000000235410653410606400145270ustar00clevecompmath00000400000006/* DSTree.h */ #include "../cfiles.h" #include "../Tree.h" #include "../IV.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- the DSTree object models a domain/separator tree. it contains a Tree object to represent the connectivity of the domains and separators and an IV object to contain the map from vertices to domains and separators. tree -- pointer to a Tree object that contains the tree adjacency mapIV -- pointer to IV object that contains the map from vertices to domains and separators created -- 96mar10, cca --------------------------------------------------------------------- */ typedef struct _DSTree DSTree ; struct _DSTree { Tree *tree ; IV *mapIV ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in basics.c --------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- purpose -- create and return a new DSTree object created -- 96mar10, cca ----------------------------------------------- */ DSTree * DSTree_new ( void ) ; /* ------------------------------------------------------ purpose -- set the default fields for the DSTree object created -- 96mar10, cca ------------------------------------------------------ */ void DSTree_setDefaultFields ( DSTree *dstree ) ; /* -------------------------------- purpose -- clear the data fields created -- 96mar10, cca -------------------------------- */ void DSTree_clearData ( DSTree *dstree ) ; /* -------------------------------- purpose -- free the DSTree object created -- 96mar10, cca -------------------------------- */ void DSTree_free ( DSTree *dstree ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in instance.c ------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------- return a pointer to the internal Tree object created -- 97jun21, cca -------------------------------------------- */ Tree * DSTree_tree ( DSTree *dstree ) ; /* ------------------------------------- return a pointer to the map IV object created -- 97jun21, cca ------------------------------------- */ IV * DSTree_mapIV ( DSTree *dstree ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in init.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- initialize the object given the number of nodes created -- 96mar10, cca ----------------------------------------------- */ void DSTree_init1 ( DSTree *dstree, int ndomsep, int nvtx ) ; /* ----------------------------------------- initialize the object given a Tree object created -- 96mar10, cca ----------------------------------------- */ void DSTree_init2 ( DSTree *dstree, Tree *tree, IV *mapIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in stages.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------- create a stages vector for a nested dissection ordering created -- 96mar10, cca ------------------------------------------------------- */ IV * DSTree_NDstages ( DSTree *dstree ) ; /* ---------------------------------------------------------------- create a stages vector for a ``half'' nested dissection ordering created -- 96mar10, cca ---------------------------------------------------------------- */ IV * DSTree_ND2stages ( DSTree *dstree ) ; /* ------------------------------------------------------------ create a stages vector for a two-level multisection ordering created -- 96mar10, cca ------------------------------------------------------------ */ IV * DSTree_MS2stages ( DSTree *dstree ) ; /* -------------------------------------------------------------- create a stages vector for a three-level multisection ordering created -- 96mar10, cca -------------------------------------------------------------- */ IV * DSTree_MS3stages ( DSTree *dstree ) ; /* --------------------------------------------------- create a stages vector via cutoff on domain weights created -- 96mar10, cca --------------------------------------------------- */ IV * DSTree_stagesViaDomainWeight ( DSTree *dstree, int *vwghts, DV *cutoffDV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in util.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------- return the number of bytes taken by the object created -- 96mar10, cca ---------------------------------------------- */ int DSTree_sizeOf ( DSTree *dstree ) ; /* --------------------------------------------- renumber the fronts by a post-order traversal created -- 96apr13, cca --------------------------------------------- */ void DSTree_renumberViaPostOT ( DSTree * dstree ) ; /* ----------------------------------------------------------- purpose -- return the weight of the vertices in the domains created -- 97jun21, cca ----------------------------------------------------------- */ int DSTree_domainWeight ( DSTree *dstree, int vwghts[] ) ; /* ----------------------------------------------------------- purpose -- return the weight of the vertices in the domains created -- 97jun21, cca ----------------------------------------------------------- */ int DSTree_domainWeight ( DSTree *dstree, int vwghts[] ) ; /* -------------------------------------------------------------- purpose -- return the weight of the vertices in the separators created -- 97jun21, cca -------------------------------------------------------------- */ int DSTree_separatorWeight ( DSTree *dstree, int vwghts[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in IO.c ------------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------- purpose -- to read in an DSTree object from a file input -- fn -- filename, must be *.dstreeb or *.dstreef return value -- 1 if success, 0 if failure created -- 96mar10, cca -------------------------------------------------- */ int DSTree_readFromFile ( DSTree *dstree, char *fn ) ; /* --------------------------------------------------------- purpose -- to read an DSTree object from a formatted file return value -- 1 if success, 0 if failure created -- 96mar10, cca --------------------------------------------------------- */ int DSTree_readFromFormattedFile ( DSTree *dstree, FILE *fp ) ; /* ------------------------------------------------------ purpose -- to read an DSTree object from a binary file return value -- 1 if success, 0 if failure created -- 96mar10, cca ------------------------------------------------------ */ int DSTree_readFromBinaryFile ( DSTree *dstree, FILE *fp ) ; /* ---------------------------------------------- purpose -- to write an DSTree object to a file input -- fn -- filename *.dstreeb -- binary *.dstreef -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 96mar10, cca ---------------------------------------------- */ int DSTree_writeToFile ( DSTree *dstree, char *fn ) ; /* -------------------------------------------------------- purpose -- to write an DSTree object to a formatted file return value -- 1 if success, 0 otherwise created -- 96mar10, cca -------------------------------------------------------- */ int DSTree_writeToFormattedFile ( DSTree *dstree, FILE *fp ) ; /* ----------------------------------------------------- purpose -- to write an DSTree object to a binary file return value -- 1 if success, 0 otherwise created -- 96mar10, cca ----------------------------------------------------- */ int DSTree_writeToBinaryFile ( DSTree *dstree, FILE *fp ) ; /* ---------------------------------------------------- purpose -- to write an DSTree object for a human eye return value -- 1 if success, 0 otherwise created -- 96mar10, cca ---------------------------------------------------- */ int DSTree_writeForHumanEye ( DSTree *dstree, FILE *fp ) ; /* ------------------------------------------------------------ purpose -- to write out the statistics for the DSTree object return value -- 1 if success, 0 otherwise created -- 96mar10, cca ------------------------------------------------------------ */ int DSTree_writeStats ( DSTree *dstree, FILE *fp ) ; /*--------------------------------------------------------------------*/ DSTree/makefile010064400020550007177000000002230663622355500147300ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean DSTree/src/makefile010064400020550007177000000007410663602205100155100ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = DSTree $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(stages.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG DSTree/src/makeGlobalLib010064400020550007177000000006400660026076500164250ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = DSTree SRC = basics.c \ init.c \ instance.c \ IO.c \ stages.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a DSTree/src/IO.c010064400020550007177000000274110653410606200144700ustar00clevecompmath00000400000006/* IO.c */ #include "../DSTree.h" static const char *suffixb = ".dstreeb" ; static const char *suffixf = ".dstreef" ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to read in an DSTree object from a file input -- fn -- filename, must be *.dstreeb or *.dstreef return value -- 1 if success, 0 if failure created -- 96mar10, cca -------------------------------------------------- */ int DSTree_readFromFile ( DSTree *dstree, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( dstree == NULL || fn == NULL ) { fprintf(stderr, "\n error in DSTree_readFromFile(%p,%s)" "\n bad input\n", dstree, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in DSTree_readFromFile(%p,%s)" "\n unable to open file %s", dstree, fn, fn) ; rc = 0 ; } else { rc = DSTree_readFromBinaryFile(dstree, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in DSTree_readFromFile(%p,%s)" "\n unable to open file %s", dstree, fn, fn) ; rc = 0 ; } else { rc = DSTree_readFromFormattedFile(dstree, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in DSTree_readFromFile(%p,%s)" "\n bad DSTree file name %s," "\n must end in %s (binary) or %s (formatted)\n", dstree, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in DSTree_readFromFile(%p,%s)" "\n bad DSTree file name %s," "\n must end in %s (binary) or %s (formatted)\n", dstree, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- to read an DSTree object from a formatted file return value -- 1 if success, 0 if failure created -- 96mar10, cca --------------------------------------------------------- */ int DSTree_readFromFormattedFile ( DSTree *dstree, FILE *fp ) { IV *mapIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( dstree == NULL || fp == NULL ) { fprintf(stderr, "\n error in DSTree_readFromFormattedFile(%p,%p)" "\n bad input\n", dstree, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ DSTree_clearData(dstree) ; /* ----------------------- read in the Tree object ----------------------- */ tree = Tree_new() ; Tree_readFromFormattedFile(tree, fp) ; /* --------------------- read in the IV object --------------------- */ mapIV = IV_new() ; IV_readFromFormattedFile(mapIV, fp) ; /* ---------------------------- initialize the DSTree object ---------------------------- */ DSTree_init2(dstree, tree, mapIV) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to read an DSTree object from a binary file return value -- 1 if success, 0 if failure created -- 96mar10, cca ------------------------------------------------------ */ int DSTree_readFromBinaryFile ( DSTree *dstree, FILE *fp ) { IV *mapIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( dstree == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in DSTree_readFromBinaryFile(%p,%p)" "\n bad input\n", dstree, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ DSTree_clearData(dstree) ; /* ----------------------- read in the Tree object ----------------------- */ tree = Tree_new() ; Tree_readFromBinaryFile(tree, fp) ; /* --------------------- read in the IV object --------------------- */ mapIV = IV_new() ; IV_readFromBinaryFile(mapIV, fp) ; /* ---------------------------- initialize the DSTree object ---------------------------- */ DSTree_init2(dstree, tree, mapIV) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to write an DSTree object to a file input -- fn -- filename *.dstreeb -- binary *.dstreef -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 96mar10, cca ---------------------------------------------- */ int DSTree_writeToFile ( DSTree *dstree, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( dstree == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in DSTree_writeToFile(%p,%s)" "\n bad input\n", dstree, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in DSTree_writeToFile(%p,%s)" "\n unable to open file %s", dstree, fn, fn) ; rc = 0 ; } else { rc = DSTree_writeToBinaryFile(dstree, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in DSTree_writeToFile(%p,%s)" "\n unable to open file %s", dstree, fn, fn) ; rc = 0 ; } else { rc = DSTree_writeToFormattedFile(dstree, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in DSTree_writeToFile(%p,%s)" "\n unable to open file %s", dstree, fn, fn) ; rc = 0 ; } else { rc = DSTree_writeForHumanEye(dstree, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in DSTree_writeToFile(%p,%s)" "\n unable to open file %s", dstree, fn, fn) ; rc = 0 ; } else { rc = DSTree_writeForHumanEye(dstree, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to write an DSTree object to a formatted file return value -- 1 if success, 0 otherwise created -- 96mar10, cca -------------------------------------------------------- */ int DSTree_writeToFormattedFile ( DSTree *dstree, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( dstree == NULL || fp == NULL || dstree->tree == NULL ) { fprintf(stderr, "\n fatal error in DSTree_writeToFormattedFile(%p,%p)" "\n bad input\n", dstree, fp) ; exit(-1) ; } /* --------------------------------- write the Tree object to the file --------------------------------- */ rc = Tree_writeToFormattedFile(dstree->tree, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in DSTree_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing Tree to file\n", dstree, fp, rc) ; return(0) ; } /* ------------------------------- write the IV object to the file ------------------------------- */ rc = IV_writeToFormattedFile(dstree->mapIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in DSTree_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing IV to file\n", dstree, fp, rc) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to write an DSTree object to a binary file return value -- 1 if success, 0 otherwise created -- 96mar10, cca ----------------------------------------------------- */ int DSTree_writeToBinaryFile ( DSTree *dstree, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( dstree == NULL || fp == NULL || dstree->tree == NULL ) { fprintf(stderr, "\n fatal error in DSTree_writeToBinaryFile(%p,%p)" "\n bad input\n", dstree, fp) ; exit(-1) ; } /* --------------------------------- write the Tree object to the file --------------------------------- */ rc = Tree_writeToBinaryFile(dstree->tree, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in DSTree_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing Tree to file\n", dstree, fp, rc) ; return(0) ; } /* ------------------------------- write the IV object to the file ------------------------------- */ rc = IV_writeToBinaryFile(dstree->mapIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in DSTree_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing IV to file\n", dstree, fp, rc) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to write an DSTree object for a human eye return value -- 1 if success, 0 otherwise created -- 96mar10, cca ---------------------------------------------------- */ int DSTree_writeForHumanEye ( DSTree *dstree, FILE *fp ) { int rc ; if ( dstree == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in DSTree_writeForHumanEye(%p,%p)" "\n bad input\n", dstree, fp) ; exit(-1) ; } if ( (rc = DSTree_writeStats(dstree, fp)) == 0 ) { fprintf(stderr, "\n fatal error in DSTree_writeForHumanEye(%p,%p)" "\n rc = %d, return from DSTree_writeStats(%p,%p)\n", dstree, fp, rc, dstree, fp) ; return(0) ; } fprintf(fp, "\n\n domain/separator tree") ; Tree_writeForHumanEye(dstree->tree, fp) ; fprintf(fp, "\n\n map from vertices to domains and separators") ; IV_writeForHumanEye(dstree->mapIV, fp) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to write out the statistics for the DSTree object return value -- 1 if success, 0 otherwise created -- 96mar10, cca ------------------------------------------------------------ */ int DSTree_writeStats ( DSTree *dstree, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( dstree == NULL || fp == NULL ) { fprintf(stderr, "\n error in DSTree_writeStats(%p,%p)" "\n bad input\n", dstree, fp) ; exit(-1) ; } rc = fprintf(fp, "\n DSTree : dstree object") ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in DSTree_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", dstree, fp, rc) ; return(0) ; } if ( dstree->tree != NULL && dstree->mapIV != NULL ) { rc = fprintf(fp, "\n %d domains and separators, %d vertices, occupies %d bytes", dstree->tree->n, IV_size(dstree->mapIV), DSTree_sizeOf(dstree)) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in DSTree_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", dstree, fp, rc) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ matted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 96mar10, cca ---------------------------------------------- */ int DSTree_writeToFile ( DSTree *dstree, char *fn ) { FILE DSTree/src/basics.c010064400020550007177000000056300653410606200154240ustar00clevecompmath00000400000006/* basics.c */ #include "../DSTree.h" #define MYTRACE 0 #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- create and return a new DSTree object created -- 96mar10, cca ----------------------------------------------- */ DSTree * DSTree_new ( void ) { DSTree *dstree ; #if MYTRACE > 0 fprintf(stdout, "\n just inside DSTree_new()") ; fflush(stdout) ; #endif ALLOCATE(dstree, struct _DSTree, 1) ; DSTree_setDefaultFields(dstree) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving DSTree_new()") ; fflush(stdout) ; #endif return(dstree) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- set the default fields for the DSTree object created -- 96mar10, cca ------------------------------------------------------ */ void DSTree_setDefaultFields ( DSTree *dstree ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside DSTree_setDefaultFields(%)", g) ; fflush(stdout) ; #endif if ( dstree == NULL ) { fprintf(stderr, "\n fatal error in DSTree_setDefaultFields(%p)" "\n dstree is NULL\n", dstree) ; exit(-1) ; } dstree->tree = NULL ; dstree->mapIV = NULL ; #if MYTRACE > 0 fprintf(stdout, "\n leaving DSTree_setDefaultFields(%)", dstree) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- clear the data fields created -- 96mar10, cca -------------------------------- */ void DSTree_clearData ( DSTree *dstree ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside DSTree_clearData(%)", dstree) ; fflush(stdout) ; #endif if ( dstree == NULL ) { fprintf(stderr, "\n fatal error in DSTree_clearData(%p)" "\n dstree is NULL\n", dstree) ; exit(-1) ; } if ( dstree->tree != NULL ) { Tree_clearData(dstree->tree) ; Tree_free(dstree->tree) ; } if ( dstree->mapIV != NULL ) { IV_free(dstree->mapIV) ; } DSTree_setDefaultFields(dstree) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving DSTree_clearData(%)", dstree) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- free the DSTree object created -- 96mar10, cca -------------------------------- */ void DSTree_free ( DSTree *dstree ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside DSTree_free(%)", dstree) ; fflush(stdout) ; #endif if ( dstree == NULL ) { fprintf(stderr, "\n fatal error in DSTree_free(%p)" "\n dstree is NULL\n", dstree) ; exit(-1) ; } DSTree_clearData(dstree) ; FREE(dstree) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving DSTree_free(%)", dstree) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ DSTree/src/init.c010064400020550007177000000031650653410606200151240ustar00clevecompmath00000400000006/* init.c */ #include "../DSTree.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------- initialize the object given the number of nodes created -- 96mar10, cca ----------------------------------------------- */ void DSTree_init1 ( DSTree *dstree, int ndomsep, int nvtx ) { /* --------------- check the input --------------- */ if ( dstree == NULL || ndomsep <= 0 ) { fprintf(stderr, "\n fatal error in DSTree_init1(%p,%d,%d)" "\n bad input\n", dstree, ndomsep, nvtx) ; exit(-1) ; } DSTree_clearData(dstree) ; dstree->tree = Tree_new() ; Tree_init1(dstree->tree, ndomsep) ; dstree->mapIV = IV_new() ; IV_init(dstree->mapIV, nvtx, NULL) ; IV_fill(dstree->mapIV, -1) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- initialize the object given a Tree object and a map IV object created -- 96mar10, cca ------------------------------------------------------------- */ void DSTree_init2 ( DSTree *dstree, Tree *tree, IV *mapIV ) { /* --------------- check the input --------------- */ if ( dstree == NULL || tree == NULL || tree->n < 1 || mapIV == NULL || IV_size(mapIV) < 1 ) { fprintf(stderr, "\n fatal error in DSTree_init2(%p,%p,%p)" "\n bad input\n", dstree, tree, mapIV) ; exit(-1) ; } DSTree_clearData(dstree) ; dstree->tree = tree ; dstree->mapIV = mapIV ; return ; } /*--------------------------------------------------------------------*/ rData(dstree) ; dstree->tree = Tree_new() ; Tree_init1(dstree->tree, ndomsep) ; dstree->mapIV = IV_new() ; IV_init(dstree->mapIV, nvtx, NULL) ; IV_fill(dstree->mapIV, -1) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- initialize the object given a Tree object and a map IV object DSTree/src/instance.c010064400020550007177000000021560653410606300157650ustar00clevecompmath00000400000006/* instance.c */ #include "../DSTree.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------- return a pointer to the internal Tree object created -- 97jun21, cca -------------------------------------------- */ Tree * DSTree_tree ( DSTree *dstree ) { /* --------------- check the input --------------- */ if ( dstree == NULL ) { fprintf(stderr, "\n fatal error in DSTree_tree(%p)" "\n bad input\n", dstree) ; exit(-1) ; } return(dstree->tree) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- return a pointer to the map IV object created -- 97jun21, cca ------------------------------------- */ IV * DSTree_mapIV ( DSTree *dstree ) { /* --------------- check the input --------------- */ if ( dstree == NULL ) { fprintf(stderr, "\n fatal error in DSTree_mapIV(%p)" "\n bad input\n", dstree) ; exit(-1) ; } return(dstree->mapIV) ; } /*--------------------------------------------------------------------*/ DSTree/src/stages.c010064400020550007177000000315230653410606200154460ustar00clevecompmath00000400000006/* stages.c */ #include "../DSTree.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- create a stages vector for a nested dissection ordering created -- 96mar10, cca ------------------------------------------------------- */ IV * DSTree_NDstages ( DSTree *dstree ) { int ndomsep, nvtx, v ; int *hmetric, *map, *stages ; IV *hmetricIV, *mapIV, *stagesIV, *vmetricIV ; Tree *tree ; /* -------------- check the data -------------- */ if ( dstree == NULL || (tree = dstree->tree) == NULL || (ndomsep = tree->n) < 1 || (mapIV = dstree->mapIV) == NULL ) { fprintf(stderr, "\n fatal error in DSTree_NDstages(%p)" "\n bad input\n", dstree) ; exit(-1) ; } IV_sizeAndEntries(mapIV, &nvtx, &map) ; if ( map == NULL || nvtx < 1 ) { fprintf(stderr, "\n fatal error in DSTree_NDstages(%p)" "\n bad mapIV object\n", dstree) ; exit(-1) ; } /* ---------------------------------- get the height metric for the tree ---------------------------------- */ vmetricIV = IV_new() ; IV_init(vmetricIV, ndomsep, NULL) ; IV_fill(vmetricIV, 1) ; hmetricIV = Tree_setHeightImetric(tree, vmetricIV) ; hmetric = IV_entries(hmetricIV) ; /* ------------------------------------ set the stages for nested dissection ------------------------------------ */ stagesIV = IV_new() ; IV_init(stagesIV, nvtx, NULL) ; stages = IV_entries(stagesIV) ; for ( v = 0 ; v < nvtx ; v++ ) { stages[v] = hmetric[map[v]] - 1 ; } /* ------------------------ free the working storage ------------------------ */ IV_free(vmetricIV) ; IV_free(hmetricIV) ; return(stagesIV) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- create a stages vector for a ``half'' nested dissection ordering created -- 96mar10, cca ---------------------------------------------------------------- */ IV * DSTree_ND2stages ( DSTree *dstree ) { int ndomsep, nvtx, v ; int *hmetric, *map, *stages ; IV *hmetricIV, *mapIV, *stagesIV, *vmetricIV ; Tree *tree ; /* -------------- check the data -------------- */ if ( dstree == NULL || (tree = dstree->tree) == NULL || (ndomsep = tree->n) < 1 || (mapIV = dstree->mapIV) == NULL ) { fprintf(stderr, "\n fatal error in DSTree_ND2stages(%p)" "\n bad input\n", dstree) ; exit(-1) ; } IV_sizeAndEntries(mapIV, &nvtx, &map) ; if ( map == NULL || nvtx < 1 ) { fprintf(stderr, "\n fatal error in DSTree_ND2stages(%p)" "\n bad mapIV object\n", dstree) ; exit(-1) ; } /* ---------------------------------- get the height metric for the tree ---------------------------------- */ vmetricIV = IV_new() ; IV_init(vmetricIV, ndomsep, NULL) ; IV_fill(vmetricIV, 1) ; hmetricIV = Tree_setHeightImetric(tree, vmetricIV) ; hmetric = IV_entries(hmetricIV) ; /* ------------------------------------ set the stages for nested dissection ------------------------------------ */ stagesIV = IV_new() ; IV_init(stagesIV, nvtx, NULL) ; stages = IV_entries(stagesIV) ; for ( v = 0 ; v < nvtx ; v++ ) { stages[v] = hmetric[map[v]] - 1 ; if ( stages[v] > 0 ) { stages[v] = (1 + stages[v])/2 ; } } /* ------------------------ free the working storage ------------------------ */ IV_free(vmetricIV) ; IV_free(hmetricIV) ; return(stagesIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ create a stages vector for a two-level multisection ordering created -- 96mar10, cca ------------------------------------------------------------ */ IV * DSTree_MS2stages ( DSTree *dstree ) { int ndomsep, nvtx, v ; int *hmetric, *map, *stages ; IV *hmetricIV, *mapIV, *stagesIV, *vmetricIV ; Tree *tree ; /* -------------- check the data -------------- */ if ( dstree == NULL || (tree = dstree->tree) == NULL || (ndomsep = tree->n) < 1 || (mapIV = dstree->mapIV) == NULL ) { fprintf(stderr, "\n fatal error in DSTree_MS2stages(%p)" "\n bad input\n", dstree) ; exit(-1) ; } IV_sizeAndEntries(mapIV, &nvtx, &map) ; if ( map == NULL || nvtx < 1 ) { fprintf(stderr, "\n fatal error in DSTree_MS2stages(%p)" "\n bad mapIV object\n", dstree) ; exit(-1) ; } /* ---------------------------------- get the height metric for the tree ---------------------------------- */ vmetricIV = IV_new() ; IV_init(vmetricIV, ndomsep, NULL) ; IV_fill(vmetricIV, 1) ; hmetricIV = Tree_setHeightImetric(tree, vmetricIV) ; hmetric = IV_entries(hmetricIV) ; /* ----------------------------------------- set the stages for two-level multisection ----------------------------------------- */ stagesIV = IV_new() ; IV_init(stagesIV, nvtx, NULL) ; stages = IV_entries(stagesIV) ; for ( v = 0 ; v < nvtx ; v++ ) { stages[v] = hmetric[map[v]] - 1 ; if ( stages[v] > 0 ) { stages[v] = 1 ; } } /* ------------------------ free the working storage ------------------------ */ IV_free(vmetricIV) ; IV_free(hmetricIV) ; return(stagesIV) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- create a stages vector for a three-level multisection ordering created -- 96mar10, cca -------------------------------------------------------------- */ IV * DSTree_MS3stages ( DSTree *dstree ) { int ndomsep, nstage, nvtx, v ; int *hmetric, *map, *stages ; IV *hmetricIV, *mapIV, *stagesIV, *vmetricIV ; Tree *tree ; /* -------------- check the data -------------- */ if ( dstree == NULL || (tree = dstree->tree) == NULL || (ndomsep = tree->n) < 1 || (mapIV = dstree->mapIV) == NULL ) { fprintf(stderr, "\n fatal error in DSTree_MS3stages(%p)" "\n bad input\n", dstree) ; exit(-1) ; } IV_sizeAndEntries(mapIV, &nvtx, &map) ; if ( map == NULL || nvtx < 1 ) { fprintf(stderr, "\n fatal error in DSTree_MS3stages(%p)" "\n bad mapIV object\n", dstree) ; exit(-1) ; } /* ---------------------------------- get the height metric for the tree ---------------------------------- */ vmetricIV = IV_new() ; IV_init(vmetricIV, ndomsep, NULL) ; IV_fill(vmetricIV, 1) ; hmetricIV = Tree_setHeightImetric(tree, vmetricIV) ; hmetric = IV_entries(hmetricIV) ; nstage = IV_max(hmetricIV) ; /* ------------------------------------------- set the stages for three-level multisection ------------------------------------------- */ stagesIV = IV_new() ; IV_init(stagesIV, nvtx, NULL) ; stages = IV_entries(stagesIV) ; for ( v = 0 ; v < nvtx ; v++ ) { stages[v] = hmetric[map[v]] - 1 ; if ( stages[v] > 0 ) { if ( 2*stages[v] > nstage ) { stages[v] = 2 ; } else { stages[v] = 1 ; } } } /* ------------------------ free the working storage ------------------------ */ IV_free(vmetricIV) ; IV_free(hmetricIV) ; return(stagesIV) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- create a stages vector via cutoff on domain weights created -- 97jun12, cca --------------------------------------------------- */ IV * DSTree_stagesViaDomainWeight ( DSTree *dstree, int *vwghts, DV *cutoffDV ) { double totvwght ; double *cutoffs, *nodewghts, *subtreewghts ; DV *nodewghtDV, *subtreeDV ; int ireg, istage, jstage, ndomsep, nstage, nvtx, v ; int *map, *mark, *regmap, *stages ; IV *mapIV, *stagesIV ; Tree *tree ; /* -------------- check the data -------------- */ if ( dstree == NULL || (tree = dstree->tree) == NULL || (ndomsep = tree->n) < 1 || (mapIV = dstree->mapIV) == NULL || cutoffDV == NULL ) { fprintf(stderr, "\n fatal error in DSTree_stagesViaDomainWeight(%p,%p,%p)" "\n bad input\n", dstree, vwghts, cutoffDV) ; exit(-1) ; } IV_sizeAndEntries(mapIV, &nvtx, &map) ; if ( map == NULL || nvtx < 1 ) { fprintf(stderr, "\n fatal error in DSTree_stagesViaDomainWeight(%p,%p,%p)" "\n bad mapIV object\n", dstree, vwghts, cutoffDV) ; exit(-1) ; } DV_sizeAndEntries(cutoffDV, &nstage, &cutoffs) ; if ( cutoffs == NULL || nstage < 1 ) { fprintf(stderr, "\n fatal error in DSTree_stagesViaDomainWeight(%p,%p,%p)" "\n bad cutoffDV object\n", dstree, vwghts, cutoffDV) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n %d stages", nstage) ; DVfprintf(stdout, nstage, cutoffs) ; #endif /* -------------------------------- get the node metric for the tree -------------------------------- */ nodewghtDV = DV_new() ; DV_init(nodewghtDV, ndomsep, NULL) ; DV_fill(nodewghtDV, 0.0) ; nodewghts = DV_entries(nodewghtDV) ; totvwght = 0.0 ; if ( vwghts == NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { nodewghts[map[v]]++ ; } totvwght = nvtx ; } else { for ( v = 0 ; v < nvtx ; v++ ) { nodewghts[map[v]] += vwghts[v] ; totvwght += vwghts[v] ; } } #if MYDEBUG > 0 fprintf(stdout, "\n\n node metric") ; DV_writeForHumanEye(nodewghtDV, stdout) ; #endif /* ---------------------------------- get the subtree metric for the tree ---------------------------------- */ subtreeDV = Tree_setSubtreeDmetric(tree, nodewghtDV) ; subtreewghts = DV_entries(subtreeDV) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n subtree metric before scale") ; DV_writeForHumanEye(subtreeDV, stdout) ; #endif for ( ireg = 0 ; ireg < ndomsep ; ireg++ ) { subtreewghts[ireg] /= totvwght ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n subtree metric after scale") ; DV_writeForHumanEye(subtreeDV, stdout) ; #endif /* ---------------------------- mark all stages with support ---------------------------- */ mark = IVinit(nstage, -1) ; for ( ireg = 0 ; ireg < ndomsep ; ireg++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n region %d, subtree weight %.4f", ireg, subtreewghts[ireg]) ; fflush(stdout) ; #endif for ( istage = 0 ; istage < nstage - 1 ; istage++ ) { if ( cutoffs[istage] <= subtreewghts[ireg] && subtreewghts[ireg] < cutoffs[istage+1] ) { mark[istage] = 1 ; #if MYDEBUG > 0 fprintf(stdout, ", found in stage %d", istage) ; fflush(stdout) ; #endif break ; } } if ( istage == nstage - 1 ) { mark[nstage - 1] = 1 ; } } /* ------------------ slide cutoffs down ------------------ */ for ( istage = jstage = 0 ; istage < nstage ; istage++ ) { if ( mark[istage] == 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n stage %d marked", istage) ; fflush(stdout) ; #endif cutoffs[jstage++] = cutoffs[istage] ; } } nstage = jstage ; /* ---------------------------------- get the map from regions to stages ---------------------------------- */ regmap = IVinit(ndomsep, -1) ; for ( ireg = 0 ; ireg < ndomsep ; ireg++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n region %d, subtree weight %.4f", ireg, subtreewghts[ireg]) ; fflush(stdout) ; #endif for ( istage = 0 ; istage < nstage - 1 ; istage++ ) { if ( cutoffs[istage] <= subtreewghts[ireg] && subtreewghts[ireg] < cutoffs[istage+1] ) { #if MYDEBUG > 0 fprintf(stdout, ", found in stage %d", istage) ; fflush(stdout) ; #endif regmap[ireg] = istage ; break ; } } if ( istage == nstage - 1 ) { regmap[ireg] = nstage - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", found in stage %d", nstage - 1) ; fflush(stdout) ; #endif } } #if MYDEBUG > 0 fprintf(stdout, "\n\n region to stage map") ; IVfp80(stdout, ndomsep, regmap, 80, &ierr) ; #endif /* -------------- set the stages -------------- */ stagesIV = IV_new() ; IV_init(stagesIV, nvtx, NULL) ; stages = IV_entries(stagesIV) ; for ( v = 0 ; v < nvtx ; v++ ) { stages[v] = regmap[map[v]] ; } #if MYDEBUG > 0 stageWeights = DVinit(nstage, 0.0) ; for ( ireg = 0 ; ireg < ndomsep ; ireg++ ) { stageWeights[regmap[ireg]] += nodewghts[ireg] ; } fprintf(stdout, "\n\n stageWeights, sum = %.4f", DVsum(nstage, stageWeights)) ; DVfprintf(stdout, nstage, stageWeights) ; for ( istage = nstage - 2 ; istage >= 0 ; istage-- ) { stageWeights[istage] += stageWeights[istage+1] ; } fprintf(stdout, "\n\n stageWeights, sum = %.4f", DVsum(nstage, stageWeights)) ; for ( istage = 0 ; istage < nstage ; istage++ ) { stageWeights[istage] /= totvwght ; } fprintf(stdout, "\n\n stageWeights, sum = %.4f", DVsum(nstage, stageWeights)) ; DVfprintf(stdout, nstage, stageWeights) ; DVfree(stageWeights) ; #endif /* ------------------------ free the working storage ------------------------ */ DV_free(nodewghtDV) ; DV_free(subtreeDV) ; IVfree(regmap) ; IVfree(mark) ; return(stagesIV) ; } /*--------------------------------------------------------------------*/ hmetricIV = Tree_setHeightImetric(tree, vmetricIV) ; hmetric = IV_entries(hmetricIV) ; nstage = IV_max(hmetricIV) ; /* ------------------------------------------- setDSTree/src/util.c010064400020550007177000000116320653410606300151350ustar00clevecompmath00000400000006/* util.c */ #include "../DSTree.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 96mar10, cca ---------------------------------------------- */ int DSTree_sizeOf ( DSTree *dstree ) { int nbytes ; /* --------------- check the input --------------- */ if ( dstree == NULL ) { fprintf(stderr, "\n fatal error in DSTree_sizeOf(%p)" "\n bad input\n", dstree) ; exit(-1) ; } nbytes = sizeof(struct _DSTree) ; if ( dstree->tree != NULL ) { nbytes += Tree_sizeOf(dstree->tree) ; } if ( dstree->mapIV != NULL ) { nbytes += IV_sizeOf(dstree->mapIV) ; } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- renumber the fronts by a post-order traversal created -- 96apr13, cca --------------------------------------------- */ void DSTree_renumberViaPostOT ( DSTree * dstree ) { int count, J, K, n, nvtx, v ; int *map, *oldmap, *temp ; IV *mapIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( dstree == NULL || (tree = dstree->tree) == NULL || (n = tree->n) <= 0 || (mapIV = dstree->mapIV) == NULL || (nvtx = IV_size(mapIV)) <= 0 || (oldmap = IV_entries(mapIV)) == NULL ) { fprintf(stderr, "\n fatal error in DSTree_renumberViaPostOT(%p)" "\n bad input\n", dstree) ; exit(-1) ; } /* --------------------------------- renumber the Tree object but preserve the post-order traversal --------------------------------- */ map = IVinit(n, -1) ; temp = IVinit(n, -1) ; count = 0 ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { map[J] = count++ ; } for ( J = 0 ; J < n ; J++ ) { if ( (K = tree->par[J]) != -1 ) { temp[map[J]] = map[K] ; } else { temp[map[J]] = -1 ; } } IVcopy(n, tree->par, temp) ; for ( J = 0 ; J < n ; J++ ) { if ( (K = tree->fch[J]) != -1 ) { temp[map[J]] = map[K] ; } else { temp[map[J]] = -1 ; } } IVcopy(n, tree->fch, temp) ; for ( J = 0 ; J < n ; J++ ) { if ( (K = tree->sib[J]) != -1 ) { temp[map[J]] = map[K] ; } else { temp[map[J]] = -1 ; } } IVcopy(n, tree->sib, temp) ; if ( tree->root != -1 ) { tree->root = map[tree->root] ; } /* ----------------------------- remap the vertex to front map ----------------------------- */ for ( v = 0 ; v < nvtx ; v++ ) { J = oldmap[v] ; if ( 0 <= J && J < n ) { oldmap[v] = map[J] ; } } IVfree(map) ; IVfree(temp) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- return the weight of the vertices in the domains created -- 97jun21, cca ----------------------------------------------------------- */ int DSTree_domainWeight ( DSTree *dstree, int vwghts[] ) { int domwght, ireg, nvtx, v ; int *fch, *map ; IV *mapIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( dstree == NULL ) { fprintf(stderr, "\n fatal error in DSTree_domainWeight(%p)" "\n bad input\n", dstree) ; exit(-1) ; } tree = DSTree_tree(dstree) ; mapIV = DSTree_mapIV(dstree) ; IV_sizeAndEntries(mapIV, &nvtx, &map) ; fch = tree->fch ; if ( vwghts != NULL ) { for ( v = domwght = 0 ; v < nvtx ; v++ ) { ireg = map[v] ; if ( fch[ireg] == -1 ) { domwght += vwghts[v] ; } } } else { for ( v = domwght = 0 ; v < nvtx ; v++ ) { ireg = map[v] ; if ( fch[ireg] == -1 ) { domwght++ ; } } } return(domwght) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- return the weight of the vertices in the separators created -- 97jun21, cca -------------------------------------------------------------- */ int DSTree_separatorWeight ( DSTree *dstree, int vwghts[] ) { int ireg, nvtx, sepwght, v ; int *fch, *map ; IV *mapIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( dstree == NULL ) { fprintf(stderr, "\n fatal error in DSTree_separatorWeight(%p)" "\n bad input\n", dstree) ; exit(-1) ; } tree = DSTree_tree(dstree) ; mapIV = DSTree_mapIV(dstree) ; IV_sizeAndEntries(mapIV, &nvtx, &map) ; fch = tree->fch ; if ( vwghts != NULL ) { for ( v = sepwght = 0 ; v < nvtx ; v++ ) { ireg = map[v] ; if ( fch[ireg] != -1 ) { sepwght += vwghts[v] ; } } } else { for ( v = sepwght = 0 ; v < nvtx ; v++ ) { ireg = map[v] ; if ( fch[ireg] != -1 ) { sepwght++ ; } } } return(sepwght) ; } /*--------------------------------------------------------------------*/ temp[map[J]] = map[K] ; } else { temp[map[J]] = -1 ; } } IVcopy(n, tree->par, temp) ;DSTree/drivers/do_domWeight010075500020550007177000000006120653410606400172370ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inGraphFile = $matrices/$matrix/orig0.graphf set inDSTreeFile = $matrices/$matrix/nd.dstreef set inCutoffFile = cutoff.dvf set outStagesFile = temp.ivf set msglvl = 1 set msgFile = stdout testDomWeightStages $msglvl $msgFile \ $inDSTreeFile \ $inGraphFile \ $inCutoffFile \ $outStagesFile DSTree/drivers/do_stages010075500020550007177000000005730653410606400166040ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inGraphFile = $matrices/$matrix/orig0.graphf set inDSTreeFile = $matrices/$matrix/nd.dstreef set outStagesFile = temp.ivf set outStagesFile = $matrices/$matrix/ndstages.ivf set msglvl = 1 set msgFile = stdout writeStagesIV $msglvl $msgFile \ $inDSTreeFile \ ND \ $outStagesFile DSTree/drivers/do_testIO010075500020550007177000000004100653410606400165130ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inFile = $matrices/$matrix/nd.dstreef set outFile = $matrices/$matrix/nd.dstreeb set outFile = none set msglvl = 3 set msgFile = stdout testIO $msglvl $msgFile $inFile $outFile DSTree/drivers/makefile010064400020550007177000000010550665314241300164020ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testIO writeStagesIV testDomWeightStages drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testIO : testIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testDomWeightStages : testDomWeightStages.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} writeStagesIV : writeStagesIV.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} DSTree/drivers/testDomWeightStages.c010064400020550007177000000126740654222337000210140ustar00clevecompmath00000400000006/* testDomWeightStages.c */ #include "../../Graph.h" #include "../DSTree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- read in a DSTree object, read in a Graph file, read in a DV cutoffs file, get the stages IV object based on domain weight and write it to a file. created -- 97jun12, cca --------------------------------------------------- */ { char *inCutoffDVfileName, *inDSTreeFileName, *inGraphFileName, *outIVfileName ; double t1, t2 ; DV *cutoffDV ; Graph *graph ; int msglvl, rc ; IV *stagesIV ; DSTree *dstree ; FILE *msgFile ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inDSTreeFile inGraphFile " "\n inCutoffDVfile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inDSTreeFile -- input file, must be *.dstreef or *.dstreeb" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n inCutoffDVfile -- input file, must be *.dvf or *.dvb" "\n outFile -- output file, must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inDSTreeFileName = argv[3] ; inGraphFileName = argv[4] ; inCutoffDVfileName = argv[5] ; outIVfileName = argv[6] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inDSTreeFileName -- %s" "\n inGraphFileName -- %s" "\n inCutoffDVfileName -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inDSTreeFileName, inGraphFileName, inCutoffDVfileName, outIVfileName) ; fflush(msgFile) ; /* ------------------------- read in the DSTree object ------------------------- */ if ( strcmp(inDSTreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } dstree = DSTree_new() ; MARKTIME(t1) ; rc = DSTree_readFromFile(dstree, inDSTreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in dstree from file %s", t2 - t1, inDSTreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from DSTree_readFromFile(%p,%s)", rc, dstree, inDSTreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading DSTree object from file %s", inDSTreeFileName) ; if ( msglvl > 2 ) { DSTree_writeForHumanEye(dstree, msgFile) ; } else { DSTree_writeStats(dstree, msgFile) ; } fflush(msgFile) ; /* ------------------------- read in the Graph object ------------------------- */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* ----------------------------- read in the cutoffs DV object ----------------------------- */ if ( strcmp(inCutoffDVfileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } cutoffDV = DV_new() ; MARKTIME(t1) ; rc = DV_readFromFile(cutoffDV, inCutoffDVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inCutoffDVfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from DV_readFromFile(%p,%s)", rc, cutoffDV, inCutoffDVfileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading DV object from file %s", inCutoffDVfileName) ; if ( msglvl > 0 ) { DV_writeForHumanEye(cutoffDV, msgFile) ; } else { DV_writeStats(cutoffDV, msgFile) ; } fflush(msgFile) ; /* --------------------- get the stages vector --------------------- */ stagesIV = DSTree_stagesViaDomainWeight(dstree, graph->vwghts, cutoffDV) ; if ( msglvl > 2 ) { IV_writeForHumanEye(stagesIV, msgFile) ; } else { IV_writeStats(stagesIV, msgFile) ; } fflush(msgFile) ; /* --------------------------- write out the DSTree object --------------------------- */ if ( stagesIV != NULL && strcmp(outIVfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(stagesIV, outIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write dstree to file %s", t2 - t1, outIVfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_writeToFile(%p,%s)", rc, stagesIV, outIVfileName) ; } } /* ---------------------- free the DSTree object ---------------------- */ DSTree_free(dstree) ; if ( stagesIV != NULL ) { IV_free(stagesIV) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ f ( rc != 1 ) { fprintf(msgFile, "\n return value %d from DSTree_DSTree/drivers/testIO.c010064400020550007177000000057400654222340300162560ustar00clevecompmath00000400000006/* testIO.c */ #include "../DSTree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------------------------- test DSTree_readFromFile and DSTree_writeToFile, useful for translating between formatted *.dstreef and binary *.dstreeb files. created -- 97feb01, cca -------------------------------------------------- */ { char *inDSTreeFileName, *outDSTreeFileName ; double t1, t2 ; int msglvl, rc ; DSTree *dstree ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.dstreef or *.dstreeb" "\n outFile -- output file, must be *.dstreef or *.dstreeb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inDSTreeFileName = argv[3] ; outDSTreeFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inDSTreeFileName, outDSTreeFileName) ; fflush(msgFile) ; /* ------------------------- read in the DSTree object ------------------------- */ if ( strcmp(inDSTreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } dstree = DSTree_new() ; MARKTIME(t1) ; rc = DSTree_readFromFile(dstree, inDSTreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in dstree from file %s", t2 - t1, inDSTreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from DSTree_readFromFile(%p,%s)", rc, dstree, inDSTreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading DSTree object from file %s", inDSTreeFileName) ; if ( msglvl > 2 ) { DSTree_writeForHumanEye(dstree, msgFile) ; } else { DSTree_writeStats(dstree, msgFile) ; } fflush(msgFile) ; /* --------------------------- write out the DSTree object --------------------------- */ if ( strcmp(outDSTreeFileName, "none") != 0 ) { MARKTIME(t1) ; rc = DSTree_writeToFile(dstree, outDSTreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write dstree to file %s", t2 - t1, outDSTreeFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from DSTree_writeToFile(%p,%s)", rc, dstree, outDSTreeFileName) ; } /* ---------------------- free the DSTree object ---------------------- */ DSTree_free(dstree) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ DSTree/drivers/writeStagesIV.c010064400020550007177000000070100654222342100175770ustar00clevecompmath00000400000006/* writeStagesIV.c */ #include "../DSTree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------------------------- read in a DSTree object, create a stagesIV object and write it to a file. created -- 97feb01, cca -------------------------------------------------- */ { char *inDSTreeFileName, *outIVfileName, *type ; double t1, t2 ; int msglvl, rc ; IV *stagesIV ; DSTree *dstree ; FILE *msgFile ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile type outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.dstreef or *.dstreeb" "\n type -- type of stages vector" "\n outFile -- output file, must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inDSTreeFileName = argv[3] ; type = argv[4] ; outIVfileName = argv[5] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inDSTreeFileName, outIVfileName) ; fflush(msgFile) ; /* ------------------------- read in the DSTree object ------------------------- */ if ( strcmp(inDSTreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } dstree = DSTree_new() ; MARKTIME(t1) ; rc = DSTree_readFromFile(dstree, inDSTreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in dstree from file %s", t2 - t1, inDSTreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from DSTree_readFromFile(%p,%s)", rc, dstree, inDSTreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading DSTree object from file %s", inDSTreeFileName) ; if ( msglvl > 2 ) { DSTree_writeForHumanEye(dstree, msgFile) ; } else { DSTree_writeStats(dstree, msgFile) ; } fflush(msgFile) ; /* --------------------- get the stages vector --------------------- */ if ( strcmp(type, "ND") == 0 ) { stagesIV = DSTree_NDstages(dstree) ; } else if ( strcmp(type, "ND2") == 0 ) { stagesIV = DSTree_ND2stages(dstree) ; } else if ( strcmp(type, "MS2") == 0 ) { stagesIV = DSTree_MS2stages(dstree) ; } else if ( strcmp(type, "MS3") == 0 ) { stagesIV = DSTree_MS3stages(dstree) ; } else { stagesIV = NULL ; } /* --------------------------- write out the DSTree object --------------------------- */ if ( stagesIV != NULL && strcmp(outIVfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(stagesIV, outIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write dstree to file %s", t2 - t1, outIVfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_writeToFile(%p,%s)", rc, stagesIV, outIVfileName) ; } } /* ---------------------- free the DSTree object ---------------------- */ DSTree_free(dstree) ; if ( stagesIV != NULL ) { IV_free(stagesIV) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ eStagesIV.c */ #include "../DSTree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------------------------- read in a DSTree object, create a stagesIV object and write it to a file. created -- 97feb01, cca -------------------------------------------------- */ { char *inDSTreeFileName, *outIVfileName, *type ; double t1, t2 ; int msglvl, rc ; IV *sDSTree/drivers/cutoff.dvf010064400020550007177000000001160653410606400166660ustar00clevecompmath0000040000000613 0.00 0.000625 0.00125 0.0025 0.005 0.01 0.02 0.04 0.08 0.16 0.32 0.64 1.00 DSTree/doc/004275500020550007177000000000000654276733100140065ustar00clevecompmath00000400000006DSTree/doc/dataStructure.tex010064000020550007177000000014230653410606300173370ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:DSTree:dataStructure} \par The {\tt DSTree} object has a very simple data structure. It contains a {\tt Tree} object to represent the tree fields of the domains and separators, and an {\tt IV} object to hold the map from the vertices to the domains and separators. \begin{itemize} \item {\tt Tree *tree} : pointer to the {\tt Tree} object \item {\tt IV *mapIV} : pointer to the {\tt IV} object that holds the map from vertices to domains and separators. \end{itemize} % \begin{center} % \begin{tabular}{|l|l|} % \hline % {\tt tree} & pointer to the {\tt Tree} object \\ % {\tt mapIV} & pointer to the {\tt IV} object that holds \\ % & the map from vertices to domains and separators. \\ % \hline % \end{tabular} % \end{center} DSTree/doc/intro.tex010064000020550007177000000031530653410606300156420ustar00clevecompmath00000400000006\chapter{{\tt DSTree}: \break A Domain/Separator Tree Object} \label{chapter:DSTree:intro} \par The {\tt DSTree} object represents a recursive partition of a graph, as is constructed during a nested dissection procedure. The graph is split by a vertex {\it separator} into subgraphs, and this process continues recursively up to some point. A subgraph which is not split is a {\tt domain}. The {\tt DSTree} object is normally created by the {\tt GPart} graph partitioning object and then used to determine the stages vector used as input to the {\tt MSMD} multistage minimum degree object. \par The {\tt DSTree} object contains a {\tt Tree} object that stores the natural tree links between separators and domains. The top level separator has no parent. Once a separator $S$ splits a graph, each subgraph is either split again (in this case $S$ is the parent of the separator that splits the subgraph) or $S$ is the parent of the subgraph (which is a domain). The {\tt DSTree} object also contains an {\tt IV} object that stores a map from the vertices to the domains and separators. \par The {\tt DSTree} object is a natural output from a nested dissection or other graph partitioning algorithm that uses vertex separators. Presently it has only one active function --- it creates a map from the vertices to the {\it stages} needed as input for the multi-stage minimum degree algorithm (see the {\tt MSMD} object). Multisection orders the vertices in two stages: all vertices in the domains first, then the vertices in the separators. Nested dissection orders the vertices in as many stages as there are levels in the {\tt DSTree} object. DSTree/doc/main.tex010064400020550007177000000010760665065620200154450ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Tree} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Tree} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} DSTree/doc/proto.tex010064400020550007177000000430370653410606300156630ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt DSTree} methods} \label{section:DSTree:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt DSTree} object. \par \subsection{Basic methods} \label{subsection:DSTree:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} DSTree * DSTree_new ( void ) ; \end{verbatim} \index{DSTree_new@{\tt DSTree\_new()}} This method allocates storage for an instance of the {\tt DSTree} object. The default fields are set by a call to {\tt DSTree\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void DSTree_setDefaultFields ( DSTree *dstree ) ; \end{verbatim} \index{DSTree_setDefaultFields@{\tt DSTree\_setDefaultFields()}} This method sets the data fields to default values: {\tt tree} and {\tt mapIV} are set to {\tt NULL} ; \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DSTree_clearData ( DSTree *dstree ) ; \end{verbatim} \index{DSTree_clearData@{\tt DSTree\_clearData()}} This method clears the data fields, free'ing storage that has been allocated by the object and free'ing objects that it owns. This method checks to see whether {\tt dstree} is {\tt NULL}. If {\tt tree} is not {\tt NULL}, then {\tt Tree\_free(tree)} is called. If {\tt mapIV} is not {\tt NULL}, then {\tt IV\_free(mapIV)} is called. Then the structure's default fields are set via a call to {\tt DSTree\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DSTree_free ( DSTree *dstree ) ; \end{verbatim} \index{DSTree_free@{\tt DSTree\_free()}} This method checks to see whether {\tt dstree} is {\tt NULL}. If so, an error message is printed and the program exits. Otherwise, it releases any storage by a call to {\tt DSTree\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:DSTree:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Tree * DSTree_tree ( DSTree *dstree ) ; \end{verbatim} \index{DSTree_tree@{\tt DSTree\_tree()}} This method returns a pointer to its {\tt Tree} object. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * DSTree_mapIV ( DSTree *dstree ) ; \end{verbatim} \index{DSTree_mapIV@{\tt DSTree\_mapIV()}} This method returns a pointer to its {\tt IV} object that maps vertices to domains and separators. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:DSTree:proto:initializers} \par There are three initializers and two helper functions to set the dimensions of the dstree, allocate the three vectors, and fill the information. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void DSTree_init1 ( DSTree *dstree, int ndomsep, int nvtx ) ; \end{verbatim} \index{DSTree_init1@{\tt DSTree\_init1()}} This method initializes an object given the number of vertices, (the dimension of {\tt mapIV}) and domains and separators (the number of nodes in {\tt tree}). It then clears any previous data with a call to {\tt DSTree\_clearData()}. The {\tt tree} field is created and initialized via a call to {\tt Tree\_init1()}. The {\tt mapIV} field is created and initialized via a call to {\tt IV\_init1()}. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, or {\tt ndomsep} or {\tt nvtx} are negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DSTree_init2 ( DSTree *dstree, Tree *tree, IV *mapIV) ; \end{verbatim} \index{DSTree_init2@{\tt DSTree\_init2()}} Any previous data is cleared with a call to {\tt DSTree\_clearData()}. Then the {\tt tree} and {\tt mapIV} fields are set to the pointers in the calling sequence. \par \noindent {\it Error checking:} If {\tt dstree}, {\tt tree} or {\tt mapIV} are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Stage methods} \label{subsection:DSTree:proto:stages} \par The only active function of a {\tt DSTree} object is to construct the stages vector needed as input to the multi-stage minimum degree {\tt MSMD} object. Each domain and separator has a particular level associated with it. A domain is a leaf of the domain/separator tree, and has level zero. Each separator has a level that is one greater than the maximum level of its children. \par %======================================================================= \begin{enumerate} \item \begin{verbatim} IV * DSTree_NDstages ( DSTree *dstree ) ; \end{verbatim} \index{DSTree_NDstages@{\tt DSTree\_NDstages()}} This method returns the stages for natural nested dissection. The levels of the domains and separators are obtained via a call to {\tt Tree\_setHeightImetric()}. A {\tt stagesIV} {\tt IV} object is created of size {\tt nvtx = mapIV->size}, filled and then returned. The stage of a vertex is the level of the domain or separator which contains the vertex. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, or if the object has not been initialized, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * DSTree_ND2stages ( DSTree *dstree ) ; \end{verbatim} \index{DSTree_ND2stages@{\tt DSTree\_ND2stages()}} This method returns the stages for a nested dissection variant, separators on two adjacent levels are put into the same stage. The levels of the domains and separators are obtained via a call to {\tt Tree\_setHeightImetric()}. A {\tt stagesIV} {\tt IV} object is created of size {\tt nvtx = mapIV->size}, filled and then returned. If a vertex is found in a domain, its stage is zero. If a vertex is found in a separator at level k, its stage is $\lceil k/2 \rceil$. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, or if the object has not been initialized, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * DSTree_MS2stages ( DSTree *dstree ) ; \end{verbatim} \index{DSTree_MS2stages@{\tt DSTree\_MS2stages()}} This method returns the stages for the standard multisection ordering. The levels of the domains and separators are obtained via a call to {\tt Tree\_setHeightImetric()}. A {\tt stagesIV} {\tt IV} object is created of size {\tt nvtx = mapIV->size}, filled and then returned. If a vertex is found in a domain, its stage is zero. If a vertex is found in a separator, its stage is one. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, or if the object has not been initialized, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * DSTree_MS3stages ( DSTree *dstree ) ; \end{verbatim} \index{DSTree_MS3stages@{\tt DSTree\_MS3stages()}} This method returns the stages for a three-stage variant of the multisection ordering. The levels of the domains and separators are obtained via a call to {\tt Tree\_setHeightImetric()}. A {\tt stagesIV} {\tt IV} object is created of size {\tt nvtx = mapIV->size}, filled and then returned. If a vertex is found in a domain, its stage is zero. The levels of the separators are split into two sets, the lower levels and the upper levels. The stage of a vertex that is found in a separator is either one (if the separator is in the lower levels) or two (if the separator is in the upper levels). \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, or if the object has not been initialized, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * DSTree_stagesViaDomainWeight ( DSTree *dstree, int *vwghts, DV *cutoffDV ) ; \end{verbatim} \index{DSTree_stagesViaDomainWeight@{\tt DSTree\_stagesViaDomainWeight()}} This method sets the stages vector based on subtree (or domain) weights. Each vertex is mapped to a node in the tree. We generate the {\it subtree weights} for each subtree, the fraction of the total vertex weight (based on {\tt vwghts[]}) that is contained in the subtree. For each node in the tree, its fraction of the node weights lies between two consectutive values in the {\tt cutoff[]} vector, and that is the stage for all vertices contained in the node. \par \noindent {\it Error checking:} If {\tt dstree} or {\tt cutoffDV} is {\tt NULL}, or if the object has not been initialized, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \par \subsection{Utility methods} \label{subsection:DSTree:proto:utilities} \par There is one utility method that returns the number of bytes taken by the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int DSTree_sizeOf ( DSTree *dstree ) ; \end{verbatim} \index{DSTree_sizeOf@{\tt DSTree\_sizeOf()}} If {\tt dstree} is {\tt NULL}, an error message is printed and the program exits. Otherwise, the number of bytes taken by this object is returned. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DSTree_renumberViaPostOT ( DSTree *dstree ) ; \end{verbatim} \index{DSTree_renumberViaPostOT@{\tt DSTree\_renumberViaPostOT()}} This method renumbers the fronts in the tree via a post-order traversal. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, or if the object has not been initialized, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DSTree_domainWeight ( DSTree *dstree, int vwghts[] ) ; \end{verbatim} \index{DSTree_domainWeight@{\tt DSTree\_domainWeight()}} This method returns the weight of the vertices in the domains. If {\tt vwghts} is {\tt NULL}, the vertices have unit weight. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DSTree_separatorWeight ( DSTree *dstree, int vwghts[] ) ; \end{verbatim} \index{DSTree_separatorWeight@{\tt DSTree\_separatorWeight()}} This method returns the weight of the vertices in the separators. If {\tt vwghts} is {\tt NULL}, the vertices have unit weight. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:DSTree:proto:IO} \par There are the usual eight IO routines. The file structure of a dstree object is simple: the structure for a {\tt Tree} object followed by the structure for an {\tt IV} object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int DSTree_readFromFile ( DSTree *dstree, char *fn ) ; \end{verbatim} \index{DSTree_readFromFile@{\tt DSTree\_readFromFile()}} \par This method reads a {\tt DSTree} object from a file. It tries to open the file and if it is successful, it then calls {\tt DSTree\_readFromFormattedFile()} or {\tt DSTree\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt dstree} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.dstreef} (for a formatted file) or {\tt *.dstreeb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int DSTree_readFromFormattedFile ( DSTree *dstree, FILE *fp ) ; \end{verbatim} \index{DSTree_readFromFormattedFile@{\tt DSTree\_readFromFormattedFile()}} \par This method reads in a {\tt DSTree} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt dstree} or {\tt fp} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DSTree_readFromBinaryFile ( DSTree *dstree, FILE *fp ) ; \end{verbatim} \index{DSTree_readFromBinaryFile@{\tt DSTree\_readFromBinaryFile()}} \par This method reads in a {\tt DSTree} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt dstree} or {\tt fp} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DSTree_writeToFile ( DSTree *dstree, char *fn ) ; \end{verbatim} \index{DSTree_writeToFile@{\tt DSTree\_writeToFile()}} \par This method writes a {\tt DSTree} object to a file. It tries to open the file and if it is successful, it then calls {\tt DSTree\_writeFromFormattedFile()} or {\tt DSTree\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt dstree} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.dstreef} (for a formatted file) or {\tt *.dstreeb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int DSTree_writeToFormattedFile ( DSTree *dstree, FILE *fp ) ; \end{verbatim} \index{DSTree_writeToFormattedFile@{\tt DSTree\_writeToFormattedFile()}} \par This method writes a {\tt DSTree} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt dstree} or {\tt fp} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DSTree_writeToBinaryFile ( DSTree *dstree, FILE *fp ) ; \end{verbatim} \index{DSTree_writeToBinaryFile@{\tt DSTree\_writeToBinaryFile()}} \par This method writes a {\tt DSTree} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt dstree} or {\tt fp} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DSTree_writeForHumanEye ( DSTree *dstree, FILE *fp ) ; \end{verbatim} \index{DSTree_writeForHumanEye@{\tt DSTree\_writeForHumanEye()}} \par This method writes a {\tt DSTree} object to a file in a human readable format. The method {\tt DSTree\_writeStats()} is called to write out the header and statistics. Then the tree structure is printed via a call to {\tt Tree\_writeForHumanEye}, followed by the map structure via a call to {\tt IV\_writeForHumanEye}. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt dstree} or {\tt fp} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DSTree_writeStats ( DSTree *dstree, FILE *fp ) ; \end{verbatim} \index{DSTree_writeStats@{\tt DSTree\_writeStats()}} \par This method write the header and statistics to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt dstree} or {\tt fp} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \tt DSTree\_MS2stages()}} This method returns the stages for the standard multisection ordering. The levels of the domains and separators are obtained via a call to {\tt Tree\_setHeightImetric()}. A {\tt stagesIV} {\tt IV} object is created of size {\tt nvtx = mapIV->size}, filled and then returned. If a vertex is found in a domain, its stage is zero. If a vertex is found in a separator, its stage is one. \par \noindent {\it Error checking:} If {\tt dstree} is {\tt NULL}, orDSTree/doc/main.log010064400020550007177000000037460653577167000154450ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 5 JUN 1998 06:33 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. ) (dataStructure.tex) (proto.tex [1 ] [2] [3] [4] [5]) (drivers.tex [6] Overfull \hbox (42.63402pt too wide) in paragraph at lines 64--69 \elvtt *.dstreef \elvrm or \elvtt *.dstreeb\elvrm . The \elvtt DSTree \elvrm ob -ject is read from the file via the \elvtt DSTree[]readFromFile() \hbox(7.60416+2.12917)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt d .\elvtt s .\elvtt t .etc. Overfull \hbox (19.63927pt too wide) in paragraph at lines 114--119 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. ) (main.ind [7] [8 ]) (main.aux) ) Here is how much of TeX's memory you used: 211 strings out of 11977 2251 string characters out of 87269 33543 words of memory out of 262141 2145 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,5n,17p,188b,257s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (8 pages, 25216 bytes). DSTree/doc/main.aux010064400020550007177000000034570653577167000154600ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space DSTree}: \penalty -\@M A Domain/Separator Tree Object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \newlabel{chapter:DSTree:intro}{{1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:DSTree:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space DSTree} methods}{2}} \newlabel{section:DSTree:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:DSTree:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Instance methods}{2}} \newlabel{subsection:DSTree:proto:instance}{{1.2.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Initializer methods}{3}} \newlabel{subsection:DSTree:proto:initializers}{{1.2.3}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}Stage methods}{3}} \newlabel{subsection:DSTree:proto:stages}{{1.2.4}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.5}Utility methods}{4}} \newlabel{subsection:DSTree:proto:utilities}{{1.2.5}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.6}IO methods}{5}} \newlabel{subsection:DSTree:proto:IO}{{1.2.6}{5}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs for the {\string\ptt\space DSTree} object}{6}} \newlabel{section:DSTree:drivers}{{1.3}{6}} .1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Instance methods}{2}} \newlabel{subsection:DSTree:proto:instance}{{1.2.2}{2}} \@writefile{toc}{\string\contentslDSTree/doc/main.ind010064400020550007177000000017700653577166600154360ustar00clevecompmath00000400000006\begin{theindex} \item {\tt DSTree\_clearData()}, 2 \item {\tt DSTree\_domainWeight()}, 5 \item {\tt DSTree\_free()}, 2 \item {\tt DSTree\_init1()}, 3 \item {\tt DSTree\_init2()}, 3 \item {\tt DSTree\_mapIV()}, 2 \item {\tt DSTree\_MS2stages()}, 4 \item {\tt DSTree\_MS3stages()}, 4 \item {\tt DSTree\_ND2stages()}, 3 \item {\tt DSTree\_NDstages()}, 3 \item {\tt DSTree\_new()}, 2 \item {\tt DSTree\_readFromBinaryFile()}, 5 \item {\tt DSTree\_readFromFile()}, 5 \item {\tt DSTree\_readFromFormattedFile()}, 5 \item {\tt DSTree\_renumberViaPostOT()}, 4 \item {\tt DSTree\_separatorWeight()}, 5 \item {\tt DSTree\_setDefaultFields()}, 2 \item {\tt DSTree\_sizeOf()}, 4 \item {\tt DSTree\_stagesViaDomainWeight()}, 4 \item {\tt DSTree\_tree()}, 2 \item {\tt DSTree\_writeForHumanEye()}, 6 \item {\tt DSTree\_writeStats()}, 6 \item {\tt DSTree\_writeToBinaryFile()}, 6 \item {\tt DSTree\_writeToFile()}, 5 \item {\tt DSTree\_writeToFormattedFile()}, 6 \end{theindex} DSTree/doc/main.idx010064400020550007177000000030650653577167000154420ustar00clevecompmath00000400000006\indexentry{DSTree_new@{\tt DSTree\_new()}}{2} \indexentry{DSTree_setDefaultFields@{\tt DSTree\_setDefaultFields()}}{2} \indexentry{DSTree_clearData@{\tt DSTree\_clearData()}}{2} \indexentry{DSTree_free@{\tt DSTree\_free()}}{2} \indexentry{DSTree_tree@{\tt DSTree\_tree()}}{2} \indexentry{DSTree_mapIV@{\tt DSTree\_mapIV()}}{2} \indexentry{DSTree_init1@{\tt DSTree\_init1()}}{3} \indexentry{DSTree_init2@{\tt DSTree\_init2()}}{3} \indexentry{DSTree_NDstages@{\tt DSTree\_NDstages()}}{3} \indexentry{DSTree_ND2stages@{\tt DSTree\_ND2stages()}}{3} \indexentry{DSTree_MS2stages@{\tt DSTree\_MS2stages()}}{4} \indexentry{DSTree_MS3stages@{\tt DSTree\_MS3stages()}}{4} \indexentry{DSTree_stagesViaDomainWeight@{\tt DSTree\_stagesViaDomainWeight()}}{4} \indexentry{DSTree_sizeOf@{\tt DSTree\_sizeOf()}}{4} \indexentry{DSTree_renumberViaPostOT@{\tt DSTree\_renumberViaPostOT()}}{4} \indexentry{DSTree_domainWeight@{\tt DSTree\_domainWeight()}}{5} \indexentry{DSTree_separatorWeight@{\tt DSTree\_separatorWeight()}}{5} \indexentry{DSTree_readFromFile@{\tt DSTree\_readFromFile()}}{5} \indexentry{DSTree_readFromFormattedFile@{\tt DSTree\_readFromFormattedFile()}}{5} \indexentry{DSTree_readFromBinaryFile@{\tt DSTree\_readFromBinaryFile()}}{5} \indexentry{DSTree_writeToFile@{\tt DSTree\_writeToFile()}}{5} \indexentry{DSTree_writeToFormattedFile@{\tt DSTree\_writeToFormattedFile()}}{6} \indexentry{DSTree_writeToBinaryFile@{\tt DSTree\_writeToBinaryFile()}}{6} \indexentry{DSTree_writeForHumanEye@{\tt DSTree\_writeForHumanEye()}}{6} \indexentry{DSTree_writeStats@{\tt DSTree\_writeStats()}}{6} DSTree/doc/main.ilg010064400020550007177000000004570653577166600154400ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (25 entries accepted, 0 rejected). Sorting entries....done (118 comparisons). Generating output file main.ind....done (29 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. DSTree/doc/drivers.tex010064400020550007177000000122510653410606300161700ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt DSTree} object} \label{section:DSTree:drivers} \par This section contains brief descriptions of the driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program reads and write {\tt DSTree} files, useful for converting formatted files to binary files and vice versa. One can also read in a {\tt DSTree} file and print out just the header information (see the {\tt DSTree\_writeStats()} method). \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt DSTree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt DSTree} object. It must be of the form {\tt *.dinpmtxf} or {\tt *.dinpmtxb}. The {\tt DSTree} object is read from the file via the {\tt DSTree\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt DSTree} object. If {\tt outFile} is {\tt none} then the {\tt DSTree} object is not written to a file. Otherwise, the {\tt DSTree\_writeToFile()} method is called to write the object to a formatted file (if {\tt outFile} is of the form {\tt *.dinpmtxf}), or a binary file (if {\tt outFile} is of the form {\tt *.dinpmtxb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} writeStagesIV msglvl msgFile inFile type outFile \end{verbatim} This driver program reads in a {\tt DSTree} from a file, creates a stages {\tt IV} object and writes it to a file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt DSTree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt DSTree} object. It must be of the form {\tt *.dstreef} or {\tt *.dstreeb}. The {\tt DSTree} object is read from the file via the {\tt DSTree\_readFromFile()} method. \item The {\tt type} parameter specifies which type of stages vector to create. There are presently four supported types : {\tt ND}, {\tt ND2}, {\tt MS2} and {\tt ND3}. See the stage methods in Section~\ref{subsection:DSTree:proto:stages}. \item The {\tt outFile} parameter is the output file for the stages {\tt IV} object. If {\tt outFile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the object to a formatted file (if {\tt outFile} is of the form {\tt *.ivf}), or a binary file (if {\tt outFile} is of the form {\tt *.ivb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testDomWeightStages msglvl msgFile inDSTreeFile inGraphFile inCutoffDVfile outFile \end{verbatim} This driver program is used to create a stages vector based on subtree weight. It reads in three objects from files: a {\tt DSTree} object, a {\tt Graph} object and a {\tt DV} object that contains the cutoff vector, then creates a stages {\tt IV} object and writes it to a file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt DSTree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inDSTreeFile} parameter is the input file for the {\tt DSTree} object. It must be of the form {\tt *.dstreef} or {\tt *.dstreeb}. The {\tt DSTree} object is read from the file via the {\tt DSTree\_readFromFile()} method. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt inCutoffDVfile} parameter is the input file for the cutoff {\tt DV} object. It must be of the form {\tt *.dvf} or {\tt *.dvb}. The {\tt DV} object is read from the file via the {\tt DV\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the stages {\tt IV} object. If {\tt outFile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the object to a formatted file (if {\tt outFile} is of the form {\tt *.ivf}), or a binary file (if {\tt outFile} is of the form {\tt *.ivb}). \end{itemize} %----------------------------------------------------------------------- \end{enumerate} ------------------------------------------------------------ \item \begin{verbatim} writeStagesIV msglvl msgFile inFile type outFile \end{verbatim} This driver program reads in a {\tt DSTree} from a file, creates a stages {\tt IV} object and writes it to a file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of oDSTree/doc/makefile010064400020550007177000000000270654276733100155000ustar00clevecompmath00000400000006clean : - rm -f *.dvi DV.h010064400020550007177000000000640653410636600125640ustar00clevecompmath00000400000006#ifndef _DV_ #define _DV_ #include "DV/DV.h" #endif DV/DV.h010064400020550007177000000324000653505172000130660ustar00clevecompmath00000400000006/* DV.h */ #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- DV -- double vector object size -- size of the vector maxsize -- maximum size of the vector owned -- owner flag when == 1, storage pointed to by entries has been allocated here and can be free'd. when == 0, storage pointed to by entries has not been allocated here and cannot be free'd. vec -- pointer to base address --------------------------------------------------------- */ typedef struct _DV DV ; struct _DV { int size ; int maxsize ; int owned ; double *vec ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor method created -- 96jun23, cca ----------------------- */ DV * DV_new ( void ) ; /* ----------------------- set the default fields created -- 96jun23, cca ----------------------- */ void DV_setDefaultFields ( DV *dv ) ; /* ----------------------- clear the data fields created -- 96jun23, cca ----------------------- */ void DV_clearData ( DV *dv ) ; /* ----------------------- destructor created -- 96jun23, cca ----------------------- */ void DV_free ( DV *dv ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ---------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------- simplest initialization method if entries != NULL the object does not own the entries, it just points to the entries base address else if size > 0 the object will own the entries, it allocates a vector of size int's. else nothing happens endif created -- 96aug28, cca --------------------------------------------- */ void DV_init ( DV *iv, int size, double *entries ) ; /* ------------------------- basic initializion method created -- 96jun23, cca ------------------------- */ void DV_init1 ( DV *dv, int Maxsize ) ; /* ------------------------- total initializion method created -- 96jun23, cca ------------------------- */ void DV_init2 ( DV *dv, int Size, int Maxsize, int owned, double *Dvec ) ; /* ---------------------------------- set the maximum size of the vector created -- 96dec08, cca ---------------------------------- */ void DV_setMaxsize ( DV *dv, int newmaxsize ) ; /* -------------------------- set the size of the vector created -- 96dec08, cca -------------------------- */ void DV_setSize ( DV *dv, int newsize ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- return 1 if the entries are owned by the object return 0 otherwise created -- 96jun22, cca ----------------------------------------------- */ int DV_owned ( DV *dv ) ; /* ----------------------- return the vector size created -- 95oct06, cca ----------------------- */ int DV_maxsize ( DV *dv ) ; /* ----------------------- return the vector size created -- 95oct06, cca ----------------------- */ int DV_size ( DV *dv ) ; /* ------------------------------------------------- return the loc'th entry of a vector. note: if loc is out of range then 0.0 is returned created -- 96jun29, cca ------------------------------------------------- */ double DV_entry ( DV *dv, int loc ) ; /* ---------------------------------------------- return a pointer to the object's entries array created -- 95oct06, cca ---------------------------------------------- */ double * DV_entries ( DV *dv ) ; /* -------------------------------------------- fill *psize with the vector's size and *pentries with the address of the vector created -- 95oct06, cca -------------------------------------------- */ void DV_sizeAndEntries ( DV *dv, int *psize, double **pentries ) ; /* --------------------------- set and entry in the vector created -- 96jul14, cca --------------------------- */ void DV_setEntry ( DV *dv, int loc, double value ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- shift the base of the entries and adjust the dimensions note: this is a dangerous operation because the dv->vec does not point to the base of the entries any longer, and thus if the object owns its entries and it is called to resize them or to free them, malloc and free will choke. USE WITH CAUTION! created -- 96aug25, cca modified -- 96aug28, cca structure changed ----------------------------------------------------------- */ void DV_shiftBase ( DV *dv, int offset ) ; /* ----------------------- resize the vector created -- 96jun22, cca ----------------------- */ void DV_resize ( DV *dv, int Maxsize ) ; /* ----------------------- set the size to be zero created -- 96jun23, cca ----------------------- */ void DV_clear ( DV *dv ) ; /* --------------------------- push an entry onto the list created -- 96jun23, cca --------------------------- */ void DV_push ( DV *dv, double val ) ; /* ------------------------------------ minimum and maximum entries and sum created -- 96jun23, cca ------------------------------------ */ double DV_min ( DV *dv ) ; double DV_max ( DV *dv ) ; double DV_sum ( DV *dv ) ; /* ------------------------------------------------------- sort each index list into ascending or descending order created -- 96jun23, cca ------------------------------------------------------- */ void DV_sortUp ( DV *dv ) ; void DV_sortDown ( DV *dv ) ; /* ----------------------- ramp the entries created -- 96jun23, cca ----------------------- */ void DV_ramp ( DV *dv, double base, double incr ) ; /* ----------------------- shuffle the list created -- 96jun23, cca ----------------------- */ void DV_shuffle ( DV *dv, int seed ) ; /* ---------------------------------------------- return the number of bytes taken by the object created -- 96jun23, cca ---------------------------------------------- */ int DV_sizeOf ( DV *dv ) ; /* -------------------------------------------- iterator : return the pointer to the head of the vector created -- 96jun23, cca -------------------------------------------- */ double * DV_first ( DV *dv ) ; /* ----------------------------------------------------- iterator : return the pointer to the next location in the vector created -- 96jun23, cca ----------------------------------------------------- */ double * DV_next ( DV *dv, double *pi ) ; /* -------------------------- fill a vector with a value created -- 96jun22, cca -------------------------- */ void DV_fill ( DV *dv, double value ) ; /* -------------------------- fill a vector with zeros created -- 98jun02, cca -------------------------- */ void DV_zero ( DV *dv ) ; /* -------------------------------------- copy entries from dv2 into dv1. note: this is a "mapped" copy, dv1 and dv2 need not be the same size. created -- 96aug31, cca -------------------------------------- */ void DV_copy ( DV *dv1, DV *dv2 ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in profile.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ to fill xDV and yDV with a log10 profile of the magnitudes of the entries in the DV object. tausmall and tau big provide cutoffs within which to examine the entries. pnzero, pnsmall and pnbig are addresses to hold the number of entries zero, smaller than tausmall and larger than taubig, respectively. created -- 97feb14, cca ------------------------------------------------------------------ */ void DV_log10profile ( DV *dv, int npts, DV *xDV, DV *yDV, double tausmall, double taubig, int *pnzero, int *pnsmall, int *pnbig ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------- purpose -- to read in an DV object from a file input -- fn -- filename, must be *.dvb or *.dvf return value -- 1 if success, 0 if failure created -- 96jun23, cca ---------------------------------------------- */ int DV_readFromFile ( DV *dv, char *fn ) ; /* ----------------------------------------------------- purpose -- to read an DV object from a formatted file return value -- 1 if success, 0 if failure created -- 96jun23, cca ----------------------------------------------------- */ int DV_readFromFormattedFile ( DV *dv, FILE *fp ) ; /* --------------------------------------------------- purpose -- to read an DV object from a binary file return value -- 1 if success, 0 if failure created -- 96jun23, cca --------------------------------------------------- */ int DV_readFromBinaryFile ( DV *dv, FILE *fp ) ; /* ------------------------------------------- purpose -- to write an DV object to a file input -- fn -- filename *.dvb -- binary *.dvf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 96jun23, cca ------------------------------------------- */ int DV_writeToFile ( DV *dv, char *fn ) ; /* ----------------------------------------------------- purpose -- to write an DV object to a formatted file return value -- 1 if success, 0 otherwise created -- 96jun23, cca ----------------------------------------------------- */ int DV_writeToFormattedFile ( DV *dv, FILE *fp ) ; /* -------------------------------------------------- purpose -- to write an DV object to a binary file return value -- 1 if success, 0 otherwise created -- 96jun23, cca -------------------------------------------------- */ int DV_writeToBinaryFile ( DV *dv, FILE *fp ) ; /* ------------------------------------------------- purpose -- to write an DV object for a human eye return value -- 1 if success, 0 otherwise created -- 96jun23, cca ------------------------------------------------- */ int DV_writeForHumanEye ( DV *dv, FILE *fp ) ; /* --------------------------------------------------------- purpose -- to write out the statistics for the DV object return value -- 1 if success, 0 otherwise created -- 96jun23, cca --------------------------------------------------------- */ int DV_writeStats ( DV *dv, FILE *fp ) ; /* ------------------------------------------------------------------- purpose -- to write out an integer vector with eighty column lines input -- fp -- file pointer, must be formatted and write access column -- present column pierr -- pointer to int to hold return value, should be 1 if any print was successful, if fprintf() failed, then ierr = -1 return value -- present column created -- 96jun22, cca ------------------------------------------------------------------- */ int DV_fp80 ( DV *dv, FILE *fp, int column, int *pierr ) ; /* --------------------------------------------------- purpose -- to write the DV object for a matlab file return value -- 1 if success, 0 otherwise created -- 98feb07, cca --------------------------------------------------- */ int DV_writeForMatlab ( DV *dv, char *name, FILE *fp ) ; /*--------------------------------------------------------------------*/ DV/makefile010064400020550007177000000002230663622355700141150ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd drivers ; make clean cd src ; make clean cd doc ; make clean DV/src/makefile010064400020550007177000000007600663602222000146720ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = DV $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(profile.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG DV/src/makeGlobalLib010064400020550007177000000006350660026077000156100ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = DV SRC = basics.c \ init.c \ instance.c \ IO.c \ profile.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a DV/src/IO.c010064400020550007177000000273350661365571400136730ustar00clevecompmath00000400000006/* IO.c */ #include "../DV.h" static const char *suffixb = ".dvb" ; static const char *suffixf = ".dvf" ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to read in an DV object from a file input -- fn -- filename, must be *.dvb or *.dvf return value -- 1 if success, 0 if failure created -- 96jun23, cca ---------------------------------------------- */ int DV_readFromFile ( DV *dv, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( dv == NULL || fn == NULL ) { fprintf(stderr, "\n error in DV_readFromFile(%p,%s), file %s, line %d" "\n bad input\n", dv, fn, __FILE__, __LINE__) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in DV_readFromFile(%p,%s)" "\n unable to open file %s", dv, fn, fn) ; rc = 0 ; } else { rc = DV_readFromBinaryFile(dv, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in DV_readFromFile(%p,%s)" "\n unable to open file %s", dv, fn, fn) ; rc = 0 ; } else { rc = DV_readFromFormattedFile(dv, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in DV_readFromFile(%p,%s)" "\n bad DV file name %s," "\n must end in %s (binary) or %s (formatted)\n", dv, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in DV_readFromFile(%p,%s)" "\n bad DV file name %s," "\n must end in %s (binary) or %s (formatted)\n", dv, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to read an DV object from a formatted file return value -- 1 if success, 0 if failure created -- 96jun23, cca ----------------------------------------------------- */ int DV_readFromFormattedFile ( DV *dv, FILE *fp ) { int rc, size ; /* --------------- check the input --------------- */ if ( dv == NULL || fp == NULL ) { fprintf(stderr, "\n error in DV_readFromFormattedFile(%p,%p)" "\n bad input\n", dv, fp) ; return(0) ; } DV_clearData(dv) ; /* ------------------------------ read in the size of the vector ------------------------------ */ if ( (rc = fscanf(fp, "%d", &size)) != 1 ) { fprintf(stderr, "\n error in DV_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", dv, fp, rc, 1) ; return(0) ; } /* --------------------- initialize the object --------------------- */ DV_init(dv, size, NULL) ; /* ------------------------ read in the vec[] vector ------------------------ */ if ( (rc = DVfscanf(fp, size, DV_entries(dv))) != size ) { fprintf(stderr, "\n error in DV_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", dv, fp, rc, size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to read an DV object from a binary file return value -- 1 if success, 0 if failure created -- 96jun23, cca --------------------------------------------------- */ int DV_readFromBinaryFile ( DV *dv, FILE *fp ) { int rc, size ; /* --------------- check the input --------------- */ if ( dv == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in DV_readFromBinaryFile(%p,%p)" "\n bad input\n", dv, fp) ; return(0) ; } DV_clearData(dv) ; /* ------------------------------ read in the size of the vector ------------------------------ */ if ( (rc = fread((void *) &size, sizeof(int), 1, fp)) != 1 ) { fprintf(stderr, "\n error in DV_readFromBinaryFile(%p,%p)" "\n itemp(3) : %d items of %d read\n", dv, fp, rc, 1) ; return(0) ; } /* --------------------- initialize the object --------------------- */ DV_init(dv, size, NULL) ; /* ------------------------ read in the vec[] vector ------------------------ */ if ( (rc = fread((void *) DV_entries(dv), sizeof(double), size, fp)) != size ) { fprintf(stderr, "\n error in DV_readFromBinaryFile(%p,%p)" "\n sizes(%d) : %d items of %d read\n", dv, fp, size, rc, size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to write an DV object to a file input -- fn -- filename *.dvb -- binary *.dvf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 96jun23, cca ------------------------------------------- */ int DV_writeToFile ( DV *dv, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( dv == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in DV_writeToFile(%p,%s)" "\n bad input\n", dv, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in DV_writeToFile(%p,%s)" "\n unable to open file %s", dv, fn, fn) ; rc = 0 ; } else { rc = DV_writeToBinaryFile(dv, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in DV_writeToFile(%p,%s)" "\n unable to open file %s", dv, fn, fn) ; rc = 0 ; } else { rc = DV_writeToFormattedFile(dv, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in DV_writeToFile(%p,%s)" "\n unable to open file %s", dv, fn, fn) ; rc = 0 ; } else { rc = DV_writeForHumanEye(dv, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in DV_writeToFile(%p,%s)" "\n unable to open file %s", dv, fn, fn) ; rc = 0 ; } else { rc = DV_writeForHumanEye(dv, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to write an DV object to a formatted file return value -- 1 if success, 0 otherwise created -- 96jun23, cca ----------------------------------------------------- */ int DV_writeToFormattedFile ( DV *dv, FILE *fp ) { int rc, size ; /* --------------- check the input --------------- */ if ( dv == NULL || fp == NULL || dv->size <= 0 ) { fprintf(stderr, "\n fatal error in DV_writeToFormattedFile(%p,%p)" "\n bad input\n", dv, fp) ; fprintf(stderr, "\n dv->size = %d", dv->size) ; exit(-1) ; } /* ------------------------------------- write out the size of the vector ------------------------------------- */ size = DV_size(dv) ; rc = fprintf(fp, "\n %d", size) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in DV_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", dv, fp, rc) ; return(0) ; } if ( size > 0 ) { DVfprintf(fp, size, DV_entries(dv)) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to write an DV object to a binary file return value -- 1 if success, 0 otherwise created -- 96jun23, cca -------------------------------------------------- */ int DV_writeToBinaryFile ( DV *dv, FILE *fp ) { int rc, size ; /* --------------- check the input --------------- */ if ( dv == NULL || fp == NULL || dv->size <= 0 ) { fprintf(stderr, "\n fatal error in DV_writeToBinaryFile(%p,%p)" "\n bad input\n", dv, fp) ; exit(-1) ; } size = DV_size(dv) ; rc = fwrite((void *) &size, sizeof(int), 1, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n error in DV_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", dv, fp, rc, 1) ; return(0) ; } rc = fwrite((void *) DV_entries(dv), sizeof(double), size, fp) ; if ( rc != size ) { fprintf(stderr, "\n error in DV_writeToBinaryFile(%p,%p)" "\n %d of %d items written\n", dv, fp, rc, size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to write an DV object for a human eye return value -- 1 if success, 0 otherwise created -- 96jun23, cca ------------------------------------------------- */ int DV_writeForHumanEye ( DV *dv, FILE *fp ) { int rc ; if ( dv == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in DV_writeForHumanEye(%p,%p)" "\n bad input\n", dv, fp) ; exit(-1) ; } if ( (rc = DV_writeStats(dv, fp)) == 0 ) { fprintf(stderr, "\n fatal error in DV_writeForHumanEye(%p,%p)" "\n rc = %d, return from DV_writeStats(%p,%p)\n", dv, fp, rc, dv, fp) ; return(0) ; } DVfprintf(fp, DV_size(dv), DV_entries(dv)) ; return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- to write out the statistics for the DV object return value -- 1 if success, 0 otherwise created -- 96jun23, cca --------------------------------------------------------- */ int DV_writeStats ( DV *dv, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( dv == NULL || fp == NULL ) { fprintf(stderr, "\n error in DV_writeStats(%p,%p)" "\n bad input\n", dv, fp) ; exit(-1) ; } rc = fprintf(fp, "\n DV : double vector object : ") ; if ( rc < 0 ) { goto IO_error ; } rc = fprintf(fp, " size = %d, maxsize = %d, owned = %d", dv->size, dv->maxsize, dv->owned) ; if ( rc < 0 ) { goto IO_error ; } return(1) ; IO_error : fprintf(stderr, "\n fatal error in DV_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", dv, fp, rc) ; return(0) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to write the DV object for a matlab file return value -- 1 if success, 0 otherwise created -- 98feb07, cca --------------------------------------------------- */ int DV_writeForMatlab ( DV *dv, char *name, FILE *fp ) { double *entries ; int ii, rc, size ; /* --------------- check the input --------------- */ if ( dv == NULL || fp == NULL ) { fprintf(stderr, "\n error in DV_writeForMatlab(%p,%p,%p)" "\n bad input\n", dv, name, fp) ; exit(-1) ; } DV_sizeAndEntries(dv, &size, &entries) ; fprintf(fp, "\n %s = zeros(%d,%d) ;", name, size, size) ; for ( ii = 0 ; ii < size ; ii++ ) { fprintf(fp, "\n %s(%d) = %24.16e ;", name, ii+1, entries[ii]) ; } return(1) ; } /*--------------------------------------------------------------------*/ fprintf(stderr, "\n error in DV_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", dv, fp, rc, size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- DV/src/basics.c010064400020550007177000000032400653410575700146140ustar00clevecompmath00000400000006/* basics.C */ #include "../DV.h" /*--------------------------------------------------------------------*/ /* ----------------------- constructor method created -- 95oct06, cca ----------------------- */ DV * DV_new ( void ) { DV *dv ; ALLOCATE(dv, struct _DV, 1) ; DV_setDefaultFields(dv) ; return(dv) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 95oct06, cca ----------------------- */ void DV_setDefaultFields ( DV *dv ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_setDefaultFields(%p)" "\n bad input\n", dv) ; exit(-1) ; } dv->size = 0 ; dv->maxsize = 0 ; dv->owned = 0 ; dv->vec = NULL ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields created -- 95oct06, cca ----------------------- */ void DV_clearData ( DV *dv ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_clearData(%p)" "\n bad input\n", dv) ; exit(-1) ; } if ( dv->vec != NULL && dv->owned == 1 ) { DVfree(dv->vec) ; } DV_setDefaultFields(dv) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- destructor created -- 95oct06, cca ----------------------- */ void DV_free ( DV *dv ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_free(%p)" "\n bad input\n", dv) ; exit(-1) ; } DV_clearData(dv) ; FREE(dv) ; return ; } /*--------------------------------------------------------------------*/ DV/src/init.c010064400020550007177000000141760653410575700143250ustar00clevecompmath00000400000006/* init.C */ #include "../DV.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------- simplest initialization method if entries != NULL the object does not own the entries, it just points to the entries base address else if size > 0 the object will own the entries, it allocates a vector of size doubles's. else nothing happens endif created -- 96aug28, cca --------------------------------------------- */ void DV_init ( DV *dv, int size, double *entries ) { if ( dv == NULL || size < 0 ) { fprintf(stderr, "\n fatal error in DV_init(%p,%d,%p)" "\n bad input\n", dv, size, entries) ; exit(-1) ; } /* -------------- clear any data -------------- */ DV_clearData(dv) ; /* ----------------------------- set the size and maximum size ----------------------------- */ dv->maxsize = dv->size = size ; /* ------------------------- set vector and owner flag ------------------------- */ if ( entries != NULL ) { dv->owned = 0 ; dv->vec = entries ; } else if ( size > 0 ) { dv->owned = 1 ; /* dv->vec = DVinit(size, 0.0) ; */ dv->vec = DVinit2(size) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------- basic initializion method created -- 95oct06, cca ------------------------- */ void DV_init1 ( DV *dv, int size ) { DV_init(dv, size, NULL) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------- total initializion method created -- 95oct06, cca ------------------------- */ void DV_init2 ( DV *dv, int size, int maxsize, int owned, double *vec ) { /* --------------- check the input --------------- */ if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_init2(%p,%d,%d,%d,%p)" "\n bad input\n", dv, size, maxsize, owned, vec) ; exit(-1) ; } if ( size < 0 || maxsize < size ) { fprintf(stderr, "\n fatal error in DV_init2(%p,%d,%d,%d,%p)" "\n size = %d, maxsize = %d \n", dv, size, maxsize, owned, vec, size, maxsize) ; exit(-1) ; } if ( owned < 0 || 1 < owned ) { fprintf(stderr, "\n fatal error in DV_init2(%p,%d,%d,%d,%p)" "\n owned = %d\n", dv, size, maxsize, owned, vec, owned) ; exit(-1) ; } if ( owned == 1 && vec == NULL ) { fprintf(stderr, "\n fatal error in DV_init2(%p,%d,%d,%d,%p)" "\n owned = %d and vec = %p", dv, size, maxsize, owned, vec, owned, vec) ; exit(-1) ; } /* -------------- clear any data -------------- */ DV_clearData(dv) ; if ( vec == NULL ) { /* ---------------------------------------------- no entries input, use the simplest initializer ---------------------------------------------- */ DV_init(dv, size, NULL) ; } else { /* --------------------------------- entries are input, set the fields --------------------------------- */ dv->size = size ; dv->maxsize = maxsize ; dv->owned = owned ; dv->vec = vec ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- set the maximum size of the vector created -- 96dec08, cca ---------------------------------- */ void DV_setMaxsize ( DV *dv, int newmaxsize ) { /* --------------- check the input --------------- */ if ( dv == NULL || newmaxsize < 0 ) { fprintf(stderr, "\n fatal error in DV_setMaxsize(%p,%d)" "\n bad input\n", dv, newmaxsize) ; exit(-1) ; } if ( dv->maxsize > 0 && dv->owned == 0 ) { fprintf(stderr, "\n fatal error in DV_setMaxsize(%p,%d)" "\n dv->maxsize = %d, dv->owned = %d\n", dv, newmaxsize, dv->maxsize, dv->owned) ; exit(-1) ; } if ( dv->maxsize != newmaxsize ) { /* ----------------------------------- allocate new storage for the vector ----------------------------------- */ double *vec ; /* vec = DVinit(newmaxsize, 0.0) ; */ vec = DVinit2(newmaxsize) ; if ( dv->size > 0 ) { /* --------------------------------- copy old entries into new entries --------------------------------- */ if ( dv->vec == NULL ) { fprintf(stderr, "\n fatal error in DV_setMaxsize(%p,%d)" "\n dv->size = %d, dv->vec is NULL\n", dv, newmaxsize, dv->size) ; exit(-1) ; } if ( dv->size <= newmaxsize ) { DVcopy(dv->size, vec, dv->vec) ; } else { /* ----------------------- note, data is truncated ----------------------- */ DVcopy(newmaxsize, vec, dv->vec) ; dv->size = newmaxsize ; } } if ( dv->vec != NULL ) { /* ---------------- free old entries ---------------- */ DVfree(dv->vec) ; } /* ---------- set fields ---------- */ dv->maxsize = newmaxsize ; dv->owned = 1 ; dv->vec = vec ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------- set the size of the vector created -- 96dec08, cca -------------------------- */ void DV_setSize ( DV *dv, int newsize ) { /* --------------- check the input --------------- */ if ( dv == NULL || newsize < 0 ) { fprintf(stderr, "\n fatal error in DV_setSize(%p,%d)" "\n bad input\n", dv, newsize) ; exit(-1) ; } if ( 0 < dv->maxsize && dv->maxsize < newsize && dv->owned == 0 ) { fprintf(stderr, "\n fatal error in DV_setSize(%p,%d)" "\n dv->maxsize = %d, newsize = %d, dv->owned = %d\n", dv, newsize, dv->maxsize, newsize, dv->owned) ; exit(-1) ; } if ( dv->maxsize < newsize ) { /* ------------------------------------------------------------- new size requested is more than maxsize, set new maximum size ------------------------------------------------------------- */ DV_setMaxsize(dv, newsize) ; } dv->size = newsize ; return ; } /*--------------------------------------------------------------------*/ wned, vec) ; exit(-1) ; } /* -------------- clear any data -------------- */ DV_clearData(dv) ; if ( vec == NULL ) { /* ---------------------------------------------- no entries input, use the simplest initializer ---------------------------------------------- */ DV_init(dv, size, NULL) ; } else { /* --------------------------------- entries are input,DV/src/instance.c010064400020550007177000000073040653410575700151610ustar00clevecompmath00000400000006/* instance.c */ #include "../DV.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------- return 1 if the entries are owned by the object return 0 otherwise created -- 96jun22, cca ----------------------------------------------- */ int DV_owned ( DV *dv ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_owned(%p)" "\n bad input\n", dv) ; exit(-1) ; } return(dv->owned) ; } /*--------------------------------------------------------------------*/ /* ----------------------- return the vector size created -- 95oct06, cca ----------------------- */ int DV_maxsize ( DV *dv ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_maxsize(%p)" "\n bad input\n", dv) ; exit(-1) ; } return(dv->maxsize) ; } /*--------------------------------------------------------------------*/ /* ----------------------- return the vector size created -- 95oct06, cca ----------------------- */ int DV_size ( DV *dv ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_size(%p)" "\n bad input\n", dv) ; exit(-1) ; } return(dv->size) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- return the loc'th entry of a vector. note: if loc is out of range then 0.0 is returned created -- 96jun29, cca ------------------------------------------------- */ double DV_entry ( DV *dv, int loc ) { if ( dv == NULL || dv->vec == NULL ) { fprintf(stderr, "\n fatal error in DV_entry(%p)" "\n bad input\n", dv) ; exit(-1) ; } if ( loc < 0 || loc >= dv->size ) { return(0.0) ; } else { return(dv->vec[loc]) ; } } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return a pointer to the object's entries array created -- 95oct06, cca ---------------------------------------------- */ double * DV_entries ( DV *dv ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_entries(%p)" "\n bad input\n", dv) ; exit(-1) ; } return(dv->vec) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- fill *psize with the vector's size and *pentries with the address of the vector created -- 95oct06, cca -------------------------------------------- */ void DV_sizeAndEntries ( DV *dv, int *psize, double **pentries ) { if ( dv == NULL || psize == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in DV_sizeAndEntries(%p,%p,%p)" "\n bad input\n", dv, psize, pentries) ; exit(-1) ; } *psize = dv->size ; *pentries = dv->vec ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------- set and entry in the vector created -- 96jul14, cca --------------------------- */ void DV_setEntry ( DV *dv, int loc, double value ) { /* --------------- check the input --------------- */ if ( dv == NULL || loc < 0 ) { fprintf(stderr, "\n fatal error in DV_setEntry(%p,%d,%f)" "\n bad input\n", dv, loc, value) ; exit(-1) ; } if ( loc >= dv->maxsize ) { int newmaxsize = (int) 1.25*dv->maxsize ; if ( newmaxsize < 10 ) { newmaxsize = 10 ; } if ( loc >= newmaxsize ) { newmaxsize = loc + 1 ; } DV_setMaxsize(dv, newmaxsize) ; } if ( loc >= dv->size ) { dv->size = loc + 1 ; } dv->vec[loc] = value ; return ; } /*--------------------------------------------------------------------*/ DV/src/profile.c010064400020550007177000000065740653410575700150250ustar00clevecompmath00000400000006/* profile */ #include "../DV.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ to fill xDV and yDV with a log10 profile of the magnitudes of the entries in the DV object. tausmall and tau big provide cutoffs within which to examine the entries. pnzero, pnsmall and pnbig are addresses to hold the number of entries zero, smaller than tausmall and larger than taubig, respectively. created -- 97feb14, cca ------------------------------------------------------------------ */ void DV_log10profile ( DV *dv, int npts, DV *xDV, DV *yDV, double tausmall, double taubig, int *pnzero, int *pnsmall, int *pnbig ) { double deltaVal, maxval, minval, val ; double *dvec, *sums, *x, *y ; int ii, ipt, nbig, nsmall, nzero, size ; /* --------------- check the input --------------- */ if ( dv == NULL || npts <= 0 || xDV == NULL || yDV == NULL || tausmall < 0.0 || taubig < 0.0 || tausmall > taubig || pnzero == NULL || pnsmall == NULL || pnbig == NULL ) { fprintf(stderr, "\n fatal error in DV_log10profile(%p,%d,%p,%p,%f,%f,%p,%p,%p)" "\n bad input\n", dv, npts, xDV, yDV, tausmall, taubig, pnzero, pnsmall, pnbig) ; exit(-1) ; } /* ------------------------------------- find the largest and smallest entries in the range [tausmall, taubig] ------------------------------------- */ nbig = nsmall = nzero = 0 ; minval = maxval = 0.0 ; DV_sizeAndEntries(dv, &size, &dvec) ; for ( ii = 0 ; ii < size ; ii++ ) { val = fabs(dvec[ii]) ; if ( val == 0.0 ) { nzero++ ; } else if ( val <= tausmall ) { nsmall++ ; } else if ( val >= taubig ) { nbig++ ; } else { if ( minval == 0.0 || minval > val ) { minval = val ; } if ( maxval < val ) { maxval = val ; } } } *pnzero = nzero ; *pnsmall = nsmall ; *pnbig = nbig ; #if MYDEBUG > 0 fprintf(stdout, "\n nzero = %d, minval = %e, nsmall = %d, maxval = %e, nbig = %d", nzero, minval, nsmall, maxval, nbig) ; #endif /* ------------------ set up the buckets ------------------ */ DV_setSize(xDV, npts) ; DV_setSize(yDV, npts) ; x = DV_entries(xDV) ; y = DV_entries(yDV) ; sums = DVinit(npts, 0.0) ; minval = log10(minval) ; maxval = log10(maxval) ; /* minval = log10(tausmall) ; maxval = log10(taubig) ; */ deltaVal = (maxval - minval)/(npts - 1) ; DVfill(npts, x, 0.0) ; DVfill(npts, y, 0.0) ; /* -------------------------------- fill the sums and counts vectors -------------------------------- */ for ( ii = 0 ; ii < size ; ii++ ) { val = fabs(dvec[ii]) ; if ( tausmall < val && val < taubig ) { ipt = (log10(val) - minval) / deltaVal ; sums[ipt] += val ; y[ipt]++ ; } } #if MYDEBUG > 0 fprintf(stdout, "\n sum(y) = %.0f", DV_sum(yDV)) ; #endif /* --------------------------- set the x-coordinate vector --------------------------- */ for ( ipt = 0 ; ipt < npts ; ipt++ ) { if ( sums[ipt] == 0.0 ) { x[ipt] = minval + ipt*deltaVal ; } else { x[ipt] = log10(sums[ipt]/y[ipt]) ; } } /* ------------------------ free the working storage ------------------------ */ DVfree(sums) ; return ; } /*--------------------------------------------------------------------*/ ------------------------ find the largest and smallest entries in the range [tausmall, taubig] ---------------------------DV/src/util.c010064400020550007177000000207340653505176700143360ustar00clevecompmath00000400000006/* basics.C */ #include "../DV.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- shift the base of the entries and adjust the dimensions note: this is a dangerous operation because the dv->vec does not point to the base of the entries any longer, and thus if the object owns its entries and it is called to resize them or to free them, malloc and free will choke. USE WITH CAUTION! created -- 96aug25, cca modified -- 96aug28, cca structure changed ----------------------------------------------------------- */ void DV_shiftBase ( DV *dv, int offset ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_shiftBase(%p,%d)" "\n bad input\n", dv, offset) ; exit(-1) ; } dv->vec += offset ; dv->maxsize -= offset ; dv->size -= offset ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- push an entry onto the list created -- 95oct06, cca -------------------------------------- */ void DV_push ( DV *dv, double val ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_push(%p,%f)" "\n bad input\n", dv, val) ; exit(-1) ; } if ( dv->size == dv->maxsize ) { if ( dv->maxsize > 0 ) { DV_setMaxsize(dv, 2*dv->maxsize) ; } else { DV_setMaxsize(dv, 10) ; } } dv->vec[dv->size++] = val ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- minimum and maximum entries and sum created -- 95oct06, cca ----------------------------------- */ double DV_min ( DV *dv ) { int i ; if ( dv == NULL || dv->size <= 0 || dv->vec == NULL ) { fprintf(stderr, "\n fatal error in DV_min(%p), size = %d, vec = %p", dv, dv->size, dv->vec) ; exit(-1) ; } return(DVmin(dv->size, dv->vec, &i)) ; } double DV_max ( DV *dv ) { int i ; if ( dv == NULL || dv->size <= 0 || dv->vec == NULL ) { fprintf(stderr, "\n fatal error in DV_max(%p), size = %d, vec = %p", dv, dv->size, dv->vec) ; exit(-1) ; } return(DVmax(dv->size, dv->vec, &i)) ; } double DV_sum ( DV *dv ) { if ( dv == NULL || dv->size <= 0 || dv->vec == NULL ) { fprintf(stderr, "\n fatal error in DV_sum(%p), size = %d, vec = %p", dv, dv->size, dv->vec) ; exit(-1) ; } return(DVsum(dv->size, dv->vec)) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- sort each index list into ascending or descending order created -- 95oct06, cca ------------------------------------------------------- */ void DV_sortUp ( DV *dv ) { if ( dv == NULL || dv->size <= 0 || dv->vec == NULL ) { fprintf(stderr, "\n fatal error in DV_sortUp(%p), size = %d, vec = %p", dv, dv->size, dv->vec) ; exit(-1) ; } DVqsortUp(dv->size, dv->vec) ; return ; } void DV_sortDown ( DV *dv ) { if ( dv == NULL || dv->size <= 0 || dv->vec == NULL ) { fprintf(stderr, "\n fatal error in DV_sortDown(%p), size = %d, vec = %p", dv, dv->size, dv->vec) ; exit(-1) ; } DVqsortDown(dv->size, dv->vec) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- ramp the entries created -- 95oct06, cca ----------------------- */ void DV_ramp ( DV *dv, double base, double incr ) { if ( dv == NULL || dv->size <= 0 || dv->vec == NULL ) { fprintf(stderr, "\n fatal error in DV_ramp(%p,%f,%f), size = %d, vec = %p", dv, base, incr, dv->size, dv->vec) ; exit(-1) ; } DVramp(dv->size, dv->vec, base, incr) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- shuffle the list created -- 95oct06, cca ----------------------- */ void DV_shuffle ( DV *dv, int seed ) { if ( dv == NULL || dv->size <= 0 || dv->vec == NULL ) { fprintf(stderr, "\n fatal error in DV_shuffle(%p,%d), size = %d, vec = %p", dv, seed, dv->size, dv->vec) ; exit(-1) ; } DVshuffle(dv->size, dv->vec, seed) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95oct06, cca ---------------------------------------------- */ int DV_sizeOf ( DV *dv ) { int nbytes ; if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_sizeOf(%p)" "\n bad input \n", dv) ; exit(-1) ; } nbytes = sizeof(struct _DV) ; if ( dv->owned == 1 ) { nbytes += + dv->maxsize*sizeof(double) ; } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- iterator : return the pointer to the head of the vector created -- 95oct06, cca -------------------------------------------- */ double * DV_first ( DV *dv ) { double *pd ; /* --------------- check the input --------------- */ if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_first(%p)" "\n bad input", dv) ; exit(-1) ; } if ( dv->size == 0 ) { pd = NULL ; } else { pd = dv->vec ; } return(pd) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- iterator : return the pointer to the next location in the vector created -- 95oct06, cca ----------------------------------------------------- */ double * DV_next ( DV *dv, double *pd ) { int offset ; /* --------------- check the input --------------- */ if ( pd == NULL ) { fprintf(stderr, "\n fatal error in DV_next(%p,%p)" "\n bad input", dv, pd) ; fflush(stderr) ; exit(-1) ; } /* --------------- check the input --------------- */ if ( (offset = pd - dv->vec) < 0 || offset >= dv->size ) { /* ----------------------------- error, offset is out of range ----------------------------- */ fprintf(stderr, "\n fatal error in DV_next(%p,%p)" "\n offset = %d, must be in [0,%d)", dv, pd, offset, dv->size) ; fflush(stderr) ; exit(-1) ; } else if ( offset == dv->size - 1 ) { /* ---------------------------- end of the list, return NULL ---------------------------- */ pd = NULL ; } else { /* ---------------------------------------- middle of the list, return next location ---------------------------------------- */ pd++ ; } return(pd) ; } /*--------------------------------------------------------------------*/ /* -------------------------- fill a vector with a value created -- 96jun22, cca -------------------------- */ void DV_fill ( DV *dv, double value ) { /* --------------- check the input --------------- */ if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_fill(%p,%f)" "\n bad input\n", dv, value) ; exit(-1) ; } if ( dv->size > 0 ) { DVfill(dv->size, dv->vec, value) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------- fill a vector with zeros created -- 98jun02, cca -------------------------- */ void DV_zero ( DV *dv ) { /* --------------- check the input --------------- */ if ( dv == NULL ) { fprintf(stderr, "\n fatal error in DV_zero(%p)" "\n bad input\n", dv) ; exit(-1) ; } if ( dv->size > 0 ) { DVzero(dv->size, dv->vec) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- copy entries from dv2 into dv1. note: this is a "mapped" copy, dv1 and dv2 need not be the same size. created -- 96aug31, cca -------------------------------------- */ void DV_copy ( DV *dv1, DV *dv2 ) { int ii, size ; double *vec1, *vec2 ; /* --------------- check the input --------------- */ if ( dv1 == NULL || dv2 == NULL ) { fprintf(stderr, "\n fatal error in DV_copy(%p,%p)" "\n bad input\n", dv1, dv2) ; exit(-1) ; } size = dv1->size ; if ( size > dv2->size ) { size = dv2->size ; } vec1 = dv1->vec ; vec2 = dv2->vec ; for ( ii = 0 ; ii < size ; ii++ ) { vec1[ii] = vec2[ii] ; } return ; } /*--------------------------------------------------------------------*/ USE WITH CAUTION! created DV/drivers/makefile010064400020550007177000000004510665314241600155670ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testIO drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testIO : testIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} DV/drivers/testIO.c010064400020550007177000000054370653506350200154500ustar00clevecompmath00000400000006/* testIO.c */ #include "../DV.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------------- test DV_readFromFile and DV_writeToFile, useful for translating between formatted *.dvf and binary *.dvb files. created -- 98jun02, cca ---------------------------------------------- */ { char *inDVFileName, *outDVFileName ; double t1, t2 ; int msglvl, rc ; DV *dvobj ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.dvf or *.dvb" "\n outFile -- output file, must be *.dvf or *.dvb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inDVFileName = argv[3] ; outDVFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inDVFileName, outDVFileName) ; fflush(msgFile) ; /* --------------------- read in the DV object --------------------- */ if ( strcmp(inDVFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } dvobj = DV_new() ; MARKTIME(t1) ; rc = DV_readFromFile(dvobj, inDVFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in iv from file %s", t2 - t1, inDVFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from DV_readFromFile(%p,%s)", rc, dvobj, inDVFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading DV object from file %s", inDVFileName) ; if ( msglvl > 2 ) { DV_writeForHumanEye(dvobj, msgFile) ; } else { DV_writeStats(dvobj, msgFile) ; } fflush(msgFile) ; /* ----------------------- write out the DV object ----------------------- */ if ( strcmp(outDVFileName, "none") != 0 ) { MARKTIME(t1) ; rc = DV_writeToFile(dvobj, outDVFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write iv to file %s", t2 - t1, outDVFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from DV_writeToFile(%p,%s)", rc, dvobj, outDVFileName) ; } /* ------------------ free the DV object ------------------ */ DV_free(dvobj) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ DV/doc/004275500020550007177000000000000654276733100131715ustar00clevecompmath00000400000006DV/doc/dataStructure.tex010064400020550007177000000016010653410575700165350ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:DV:dataStructure} \par \par The {\tt DV} structure has three fields. \begin{itemize} \item {\tt int size} : present size of the vector. \item {\tt int maxsize} : maximum size of the vector. \item {\tt int owned} : owner flag for the data. When {\tt owned = 1}, storage for {\tt owned} {\tt double}'s has been allocated by this object and can be free'd by the object. When {\tt owned == 0} but {\tt size > 0 }, this object points to entries that have been allocated elsewhere, and these entries will not be free'd by this object. \item {\tt double *vec} : pointer to the base address of the {\it double} vector \end{itemize} The {\tt size}, {\tt maxsize}, {\tt nowned} and {\tt vec} fields need never be accessed directly --- see the {\tt DV\_size()}, {\tt DV\_maxsize()}, {\tt DV\_owned()}, {\tt DV\_entries()}, {\tt DV\_sizeAndEntries()} methods. DV/doc/intro.tex010064400020550007177000000035550653410575700150500ustar00clevecompmath00000400000006\chapter{{\tt DV}: Double Vector Object} \par The {\tt DV} object is a wrapper around a {\tt double} vector, thus the acronym {\bf D}ouble {\bf V}ector. The driving force for its creation is more convenience than performance. There are three cases that led to its development. \begin{itemize} \item Often a method will create a vector (allocate storage for and fill the entries) whose size is not known before the method call. Instead of having a pointer to {\tt int} and a pointer to {\tt double*} in the calling sequence, we can return a pointer to an {\tt DV} object that contains the newly created vector and its size. \item In many cases we need a persistent {\tt double} vector object, and file IO is simplified if we have an object to deal with. The filename is of the form {\tt *.dvf} for a formatted file or {\tt *.dvb} for a binary file. \item Prototyping can go much faster with this object as opposed to working with an {\tt double} array. Consider the case when one wants to accumulate a list of doubles, but one doesn't know how large the list will be. The method {\tt DV\_setSize()} can be used to set the size of the vector to zero. Another method {\tt DV\_push()} appends an element to the vector, growing the storage if necessary. \item Sometimes an object needs to change its size, i.e., vectors need to grow or shrink. It is easier and more robust to tell an {\tt DV} object to resize itself (see the {\tt DV\_setSize()} and {\tt DV\_setMaxsize()} methods) than it is to duplicate code to work on an {\tt double} vector. \end{itemize} One must choose where to use this object. There is a substantial performance penalty for doing the simplest operations, and so when we need to manipulate an {\tt double} vector inside a loop, we extract out the size and pointer to the base array from the {\tt DV} object. On the other hand, the convenience makes it a widely used object. \par DV/doc/main.tex010064400020550007177000000010720665065620500146270ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt DV} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt DV} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} DV/doc/main.ind010064400020550007177000000025110653506401600145730ustar00clevecompmath00000400000006\begin{theindex} \item {\tt DV\_clearData()}, 2 \item {\tt DV\_copy()}, 6 \item {\tt DV\_entries()}, 3 \item {\tt DV\_entry()}, 3 \item {\tt DV\_fill()}, 6 \item {\tt DV\_first()}, 6 \item {\tt DV\_free()}, 2 \item {\tt DV\_init()}, 4 \item {\tt DV\_init1()}, 4 \item {\tt DV\_init2()}, 4 \item {\tt DV\_log10profile()}, 6 \item {\tt DV\_max()}, 5 \item {\tt DV\_size()}, 3 \item {\tt DV\_min()}, 5 \item {\tt DV\_new()}, 2 \item {\tt DV\_next()}, 6 \item {\tt DV\_owned()}, 3 \item {\tt DV\_push()}, 5 \item {\tt DV\_ramp()}, 5 \item {\tt DV\_readFromBinaryFile()}, 7 \item {\tt DV\_readFromFile()}, 7 \item {\tt DV\_readFromFormattedFile()}, 7 \item {\tt DV\_setDefaultFields()}, 2 \item {\tt DV\_setEntry()}, 3 \item {\tt DV\_setMaxsize()}, 4 \item {\tt DV\_setSize()}, 4 \item {\tt DV\_shiftBase()}, 4 \item {\tt DV\_shuffle()}, 5 \item {\tt DV\_size()}, 3 \item {\tt DV\_sizeAndEntries()}, 3 \item {\tt DV\_sizeOf()}, 5 \item {\tt DV\_sortDown()}, 5 \item {\tt DV\_sortUp()}, 5 \item {\tt DV\_sum()}, 5 \item {\tt DV\_writeForHumanEye()}, 7 \item {\tt DV\_writeForMatlab()}, 8 \item {\tt DV\_writeStats()}, 7 \item {\tt DV\_writeToBinaryFile()}, 7 \item {\tt DV\_writeToFile()}, 7 \item {\tt DV\_writeToFormattedFile()}, 7 \item {\tt DV\_zero()}, 6 \end{theindex} DV/doc/main.log010064400020550007177000000032250653506402100146010ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 2 JUN 1998 14:01 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. ) (dataStructure.tex [1 ]) (proto.tex [2] [3] [4] [5] Overfull \hbox (11.7664pt too wide) in paragraph at lines 413--413 [] \elvtt double taubig, int *pnzero, int *pnsmall, int *pnbig ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\penalty 10000 .\glue 5.74869 .\penalty 10000 .etc. [6] [7]) (drivers.tex) (main.ind [8] [9 ]) (main.aux) ) Here is how much of TeX's memory you used: 209 strings out of 11977 2165 string characters out of 87269 33539 words of memory out of 262141 2143 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 14i,5n,17p,179b,258s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (9 pages, 26652 bytes). DV/doc/main.aux010064400020550007177000000030410653506402100146110ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space DV}: Double Vector Object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:DV:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space DV} methods}{2}} \newlabel{section:DV:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:DV:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Instance methods}{3}} \newlabel{subsection:DV:proto:Instance}{{1.2.2}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Initializer methods}{4}} \newlabel{subsection:DV:proto:initializers}{{1.2.3}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}Utility methods}{4}} \newlabel{subsection:DV:proto:utilities}{{1.2.4}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.5}IO methods}{6}} \newlabel{subsection:DV:proto:IO}{{1.2.5}{6}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs for the {\string\ptt\space DV object}}{8}} \newlabel{section:DV:drivers}{{1.3}{8}} DV/doc/main.idx010064400020550007177000000037520653506402100146110ustar00clevecompmath00000400000006\indexentry{DV_new@{\tt DV\_new()}}{2} \indexentry{DV_setDefaultFields@{\tt DV\_setDefaultFields()}}{2} \indexentry{DV_clearData@{\tt DV\_clearData()}}{2} \indexentry{DV_free@{\tt DV\_free()}}{2} \indexentry{DV_owned@{\tt DV\_owned()}}{3} \indexentry{DV_size@{\tt DV\_size()}}{3} \indexentry{DV_maxsize@{\tt DV\_size()}}{3} \indexentry{DV_entry@{\tt DV\_entry()}}{3} \indexentry{DV_entries@{\tt DV\_entries()}}{3} \indexentry{DV_sizeAndEntries@{\tt DV\_sizeAndEntries()}}{3} \indexentry{DV_setEntry@{\tt DV\_setEntry()}}{3} \indexentry{DV_init@{\tt DV\_init()}}{4} \indexentry{DV_init1@{\tt DV\_init1()}}{4} \indexentry{DV_init2@{\tt DV\_init2()}}{4} \indexentry{DV_setMaxsize@{\tt DV\_setMaxsize()}}{4} \indexentry{DV_setSize@{\tt DV\_setSize()}}{4} \indexentry{DV_shiftBase@{\tt DV\_shiftBase()}}{4} \indexentry{DV_push@{\tt DV\_push()}}{5} \indexentry{DV_min@{\tt DV\_min()}}{5} \indexentry{DV_max@{\tt DV\_max()}}{5} \indexentry{DV_sum@{\tt DV\_sum()}}{5} \indexentry{DV_sortUp@{\tt DV\_sortUp()}}{5} \indexentry{DV_sortDown@{\tt DV\_sortDown()}}{5} \indexentry{DV_ramp@{\tt DV\_ramp()}}{5} \indexentry{DV_shuffle@{\tt DV\_shuffle()}}{5} \indexentry{DV_sizeOf@{\tt DV\_sizeOf()}}{5} \indexentry{DV_first@{\tt DV\_first()}}{6} \indexentry{DV_next@{\tt DV\_next()}}{6} \indexentry{DV_fill@{\tt DV\_fill()}}{6} \indexentry{DV_zero@{\tt DV\_zero()}}{6} \indexentry{DV_copy@{\tt DV\_copy()}}{6} \indexentry{DV_log10profile@{\tt DV\_log10profile()}}{6} \indexentry{DV_readFromFile@{\tt DV\_readFromFile()}}{7} \indexentry{DV_readFromFormattedFile@{\tt DV\_readFromFormattedFile()}}{7} \indexentry{DV_readFromBinaryFile@{\tt DV\_readFromBinaryFile()}}{7} \indexentry{DV_writeToFile@{\tt DV\_writeToFile()}}{7} \indexentry{DV_writeToFormattedFile@{\tt DV\_writeToFormattedFile()}}{7} \indexentry{DV_writeToBinaryFile@{\tt DV\_writeToBinaryFile()}}{7} \indexentry{DV_writeForHumanEye@{\tt DV\_writeForHumanEye()}}{7} \indexentry{DV_writeStats@{\tt DV\_writeStats()}}{7} \indexentry{DV_writeForMatlab@{\tt DV\_writeForMatlab()}}{8} setEntry@{\tt DV\_setEDV/doc/proto.tex010064400020550007177000000540470661364037100150540ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt DV} methods} \label{section:DV:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt DV} object. \par \subsection{Basic methods} \label{subsection:DV:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} DV * DV_new ( void ) ; \end{verbatim} \index{DV_new@{\tt DV\_new()}} This method simply allocates storage for the {\tt DV} structure and then sets the default fields by a call to {\tt DV\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_setDefaultFields ( DV *dv ) ; \end{verbatim} \index{DV_setDefaultFields@{\tt DV\_setDefaultFields()}} This method sets the default fields of the object, {\tt size = maxsize = owned = 0} and {\tt vec = NULL}. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_clearData ( DV *dv ) ; \end{verbatim} \index{DV_clearData@{\tt DV\_clearData()}} This method releases any data owned by the object. If {\tt vec} is not {\tt NULL} and {\tt owned = 1}, then the storage for {\tt vec} is free'd by a call to {\tt DVfree()}. The structure's default fields are then set with a call to {\tt DV\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_free ( DV *dv ) ; \end{verbatim} \index{DV_free@{\tt DV\_free()}} This method releases any storage by a call to {\tt DV\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:DV:proto:Instance} \par These method allow access to information in the data fields without explicitly following pointers. There is overhead involved with these method due to the function call and error checking inside the methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int DV_owned ( DV *dv ) ; \end{verbatim} \index{DV_owned@{\tt DV\_owned()}} This method returns the value of {\tt owned}. If {\tt owned > 0}, then the object owns the data pointed to by {\tt vec} and will free this data with a call to {\tt DVfree()} when its data is cleared by a call to {\tt DV\_free()} or {\tt DV\_clearData()}. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DV_size ( DV *dv ) ; \end{verbatim} \index{DV_size@{\tt DV\_size()}} This method returns the value of {\tt size}, the present size of the vector. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DV_maxsize ( DV *dv ) ; \end{verbatim} \index{DV_maxsize@{\tt DV\_size()}} This method returns the value of {\tt size}, the maximum size of the vector. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double DV_entry ( DV *dv, int loc ) ; \end{verbatim} \index{DV_entry@{\tt DV\_entry()}} This method returns the value of the {\tt loc}'th entry in the vector. If {\tt loc < 0} or {\tt loc >= size}, i.e., if the location is out of range, we return {\tt 0.0}. This design {\tt feature} is handy when a list terminates with a {\tt 0.0} value. \par \noindent {\it Error checking:} If {\tt dv} or {\tt vec} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double * DV_entries ( DV *dv ) ; \end{verbatim} \index{DV_entries@{\tt DV\_entries()}} This method returns {\tt vec}, a pointer to the base address of the vector. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_sizeAndEntries ( DV *dv, int *psize, double **pentries ) ; \end{verbatim} \index{DV_sizeAndEntries@{\tt DV\_sizeAndEntries()}} This method fills {\tt *psize} with the size of the vector and {\tt **pentries} with the base address of the vector. \par \noindent {\it Error checking:} If {\tt dv}, {\tt psize} or {\tt pentries} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_setEntry ( DV *dv, int loc, double value ) ; \end{verbatim} \index{DV_setEntry@{\tt DV\_setEntry()}} This method sets the {\tt loc}'th entry of the vector to {\tt value}. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL} or {\tt loc < 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:DV:proto:initializers} \par There are three initializer methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void DV_init ( DV *dv, int size, double *entries ) ; \end{verbatim} \index{DV_init@{\tt DV\_init()}} This method initializes the object given a size for the vector and a possible pointer to the vectors' storage. Any previous data is cleared with a call to {\tt DV\_clearData()}. If {\tt entries != NULL} then the {\tt vec} field is set to {\tt entries}, the {\tt size} and {\tt maxsize} fields are set to {\tt size}, and {\tt owned} is set to zero because the object does not own the entries. If {\tt entries} is {\tt NULL} and {\tt size > 0} then a vector is allocated by the object, and the object owns this storage. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL} or {\tt size < 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_init1 ( DV *dv, int size ) ; \end{verbatim} \index{DV_init1@{\tt DV\_init1()}} This method initializes the object given a size size for the vector via a call to {\tt DV\_init()}. \par \noindent {\it Error checking:} Error checking is done with the call to {\t DV\_init()}. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_init2 ( DV *dv, int size, int maxsize, int owned, double *vec ) ; \end{verbatim} \index{DV_init2@{\tt DV\_init2()}} This is the total initialization method. The data is cleared with a call to {\tt DV\_clearData()}. If {\tt vec} is {\tt NULL}, the object is initialized via a call to {\tt DV\_init1()}. Otherwise, the objects remaining fields are set to the input parameters. and if {\tt owned} is not {\tt 1}, the data is not owned, so the object cannot grow. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, or if {\tt size < 0}, or if {\tt maxsize < size}, or if {\tt owned} is not equal to {\tt 0} or {\tt 1}, of if { \tt owned = 1} and {\tt vec = NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_setMaxsize ( DV *dv, int newmaxsize ) ; \end{verbatim} \index{DV_setMaxsize@{\tt DV\_setMaxsize()}} This method sets the maximum size of the vector. If {\tt maxsize}, the present maximum size of the vector, is not equal to {\tt newmaxsize}, then new storage is allocated. Only {\tt size} entries of the old data are copied into the new storage, so if {\tt size > newmaxsize} then data will be lost. The {\tt size} field is set to the minimum of {\tt size} and {\tt newmaxsize}. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL} or {\tt newmaxsize < 0}, or if {\tt 0 < maxsize} and {\tt owned == 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_setSize ( DV *dv, int newsize ) ; \end{verbatim} \index{DV_setSize@{\tt DV\_setSize()}} This method sets the size of the vector. If {\tt newsize > maxsize}, the length of the vector is increased with a call to {\tt DV\_setMaxsize()}. The {\tt size} field is set to {\tt newsize}. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, or {\tt newsize < 0}, or if {\tt 0 < maxsize < newsize} and {\tt owned = 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:DV:proto:utilities} \par \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void DV_shiftBase ( DV *dv, int offset ) ; \end{verbatim} \index{DV_shiftBase@{\tt DV\_shiftBase()}} This method shifts the base entries of the vector and decrements the present size and maximum size of the vector by {\tt offset}. This is a dangerous method to use because the state of the vector is lost, namely {\tt vec}, the base of the entries, is corrupted. If the object owns its entries and {\tt DV\_free()}, {\tt DV\_setSize()} or {\tt DV\_setMaxsize()} is called before the base has been shifted back to its original position, a segmentation violation will likely result. This is a very useful method, but use with caution. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_push ( DV *dv, double val ) ; \end{verbatim} \index{DV_push@{\tt DV\_push()}} This method pushes an entry onto the vector. If the vector is full, i.e., if {\tt size == maxsize - 1}, then the size of the vector is doubled if possible. If the storage cannot grow, i.e., if the object does not own its storage, an error message is printed and the program exits. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double DV_min ( DV *dv ) ; double DV_max ( DV *dv ) ; double DV_sun ( DV *dv ) ; \end{verbatim} \index{DV_min@{\tt DV\_min()}} \index{DV_max@{\tt DV\_max()}} \index{DV_sum@{\tt DV\_sum()}} These methods simply return the minimum entry, the maximum entry and the sum of the entries in the vector. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, {\tt size <= 0} or if {\tt vec == NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_sortUp ( DV *dv ) ; void DV_sortDown ( DV *dv ) ; \end{verbatim} \index{DV_sortUp@{\tt DV\_sortUp()}} \index{DV_sortDown@{\tt DV\_sortDown()}} This method sorts the entries in the vector into ascending or descending order via calls to {\tt DVqsortUp()} and {\tt DVqsortDown()}. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, {\tt size <= 0} or if {\tt vec == NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_ramp ( DV *dv, double base, int double ) ; \end{verbatim} \index{DV_ramp@{\tt DV\_ramp()}} This method fills the object with a ramp vector, i.e., entry {\tt i} is {\tt base + i*incr}. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, {\tt size <= 0} or if {\tt vec == NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_shuffle ( DV *dv, int seed ) ; \end{verbatim} \index{DV_shuffle@{\tt DV\_shuffle()}} This method shuffles the entries in the vector using {\tt seed} as a seed to a random number generator. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, {\tt size <= 0} or if {\tt vec == NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DV_sizeOf ( DV *dv ) ; \end{verbatim} \index{DV_sizeOf@{\tt DV\_sizeOf()}} This method returns the number of bytes taken by the object. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double * DV_first ( DV *dv ) ; double * DV_next ( DV *dv, int *pd ) ; \end{verbatim} \index{DV_first@{\tt DV\_first()}} \index{DV_next@{\tt DV\_next()}} These two methods are used as iterators, e.g., \begin{verbatim} for ( pd = DV_first(dv) ; pd != NULL ; pd = DV_next(dv, pd) ) { do something with entry *pd } \end{verbatim} Each method checks to see if {\tt dv} or {\tt pd} is {\tt NULL}, if so an error message is printed and the program exits. In method {\tt DV\_next()}, if {\tt pd} is not in the valid range, an error message is printed and the program exits. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_fill ( DV *dv, double value ) ; \end{verbatim} \index{DV_fill@{\tt DV\_fill()}} This method fills the vector with a scalar value. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_zero ( DV *dv ) ; \end{verbatim} \index{DV_zero@{\tt DV\_zero()}} This method fills the vector with zeros. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_copy ( DV *dv1, DV *dv2 ) ; \end{verbatim} \index{DV_copy@{\tt DV\_copy()}} This method fills the {\tt dv1} object with entries in the {\tt iv2} object. Note, this is a {\it mapped} copy, {\tt dv1} and {\tt dv2} need not have the same size. The number of entries that are copied is the smaller of the two sizes. \par \noindent {\it Error checking:} If {\tt dv1} or {\tt dv2} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DV_log10profile ( DV *dv, int npts, DV *xDV, DV *yDV, double tausmall, double taubig, int *pnzero, int *pnsmall, int *pnbig ) ; \end{verbatim} \index{DV_log10profile@{\tt DV\_log10profile()}} This method scans the entries in the {\tt DV} object and fills {\tt xDV} and {\tt yDV} with data that allows a simple $\log_{10}$ distribution plot. Only entries whose magnitudes lie in the range {\tt [tausmall, taubig]} contribute to the distribution. The number of entries whose magnitudes are zero, smaller than {\tt tausmall}, or larger than {\tt taubig} are placed into {\tt pnzero}, {\tt *pnsmall} and {\tt *pnbig}, respectively. On return, the size of the {\tt xDV} and {\tt yDV} objects is {\tt npts}. \par \noindent {\it Error checking:} If {\tt dv}, {\tt xDV}, {\tt yDV}, {\tt pnsmall} or {\tt pnbig} are {\tt NULL}, or if ${\tt npts} \le 0$, or if ${\tt taubig} < 0.0$ or if ${\tt tausmall} > {\tt taubig}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:DV:proto:IO} \par There are the usual eight IO routines. The file structure of a {\tt DV} object is simple: the first entry is {\tt size}, followed by the {\tt size} entries found in {\tt vec[]}. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int DV_readFromFile ( DV *dv, char *fn ) ; \end{verbatim} \index{DV_readFromFile@{\tt DV\_readFromFile()}} \par This method reads a {\tt DV} object from a file. It tries to open the file and if it is successful, it then calls {\tt DV\_readFromFormattedFile()} or {\tt DV\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt dv} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.dvf} (for a formatted file) or {\tt *.dvb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int DV_readFromFormattedFile ( DV *dv, FILE *fp ) ; \end{verbatim} \index{DV_readFromFormattedFile@{\tt DV\_readFromFormattedFile()}} \par This method reads in a {\tt DV} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt dv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DV_readFromBinaryFile ( DV *dv, FILE *fp ) ; \end{verbatim} \index{DV_readFromBinaryFile@{\tt DV\_readFromBinaryFile()}} \par This method reads in a {\tt DV} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt dv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DV_writeToFile ( DV *dv, char *fn ) ; \end{verbatim} \index{DV_writeToFile@{\tt DV\_writeToFile()}} \par This method writes a {\tt DV} object from a file. It tries to open the file and if it is successful, it then calls {\tt DV\_writeFromFormattedFile()} or {\tt DV\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt dv} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.dvf} (for a formatted file) or {\tt *.dvb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int DV_writeToFormattedFile ( DV *dv, FILE *fp ) ; \end{verbatim} \index{DV_writeToFormattedFile@{\tt DV\_writeToFormattedFile()}} \par This method writes a {\tt DV} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt dv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DV_writeToBinaryFile ( DV *dv, FILE *fp ) ; \end{verbatim} \index{DV_writeToBinaryFile@{\tt DV\_writeToBinaryFile()}} \par This method writes a {\tt DV} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt dv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DV_writeForHumanEye ( DV *dv, FILE *fp ) ; \end{verbatim} \index{DV_writeForHumanEye@{\tt DV\_writeForHumanEye()}} \par This method writes a {\tt DV} object to a file in a human readable format. is called to write out the header and statistics. The entries of the vector then follow in eighty column format using the {\tt DVfprintf()} method. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt dv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DV_writeStats ( DV *dv, FILE *fp ) ; \end{verbatim} \index{DV_writeStats@{\tt DV\_writeStats()}} \par This method writes the header and statistics to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt dv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DV_writeForMatlab ( DV *dv, char *name, FILE *fp ) ; \end{verbatim} \index{DV_writeForMatlab@{\tt DV\_writeForMatlab()}} \par This method writes the entries of the vector to a file suitable to be read by Matlab. The character string {\tt name} is the name of the vector, e.g, if {\tt name = "A"}, then we have lines of the form \begin{verbatim} A(1) = 1.000000000000e0 ; A(2) = 2.000000000000e0 ; ... \end{verbatim} for each entry in the vector. Note, the output indexing is 1-based, not 0-based. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt dv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} --------------------------------------------- \item \begin{verbatim} void DV_ramp ( DV *dv, double base, int double ) ; \end{verbatim} \index{DV_ramp@{\tt DV\_ramp()}} This method fills the object with a ramp vector, i.e., entry {\tt i} is {\tt base + i*incr}. \par \noindent {\it Error checking:} If {\tt dv} is {\tt NULL}, {\tt size <= 0} or if {\tt vec == NULL}, an error message is printed and the program exits. %------------------------------------------------------DV/doc/main.ilg010064400020550007177000000004570653506401600146030ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (41 entries accepted, 0 rejected). Sorting entries....done (231 comparisons). Generating output file main.ind....done (45 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. DV/doc/drivers.tex010064400020550007177000000030270653506375500153670ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt DV object}} \label{section:DV:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program tests the {\tt DV} IO methods, and is useful for translating between the formatted {\tt *.dvf} and binary {\tt *.dvb} files. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the name of the file from which to read in the object. {\tt inFile} must be of the form {\tt *.dvf} for a formatted file or {\tt *.dvb} for a binary file. \item The {\tt outFile} parameter is the name of the file to which to write out the object. If {\tt outfile} is of the form {\tt *.dvf}, the object is written to a formatted file. If {\tt outfile} is of the form {\tt *.dvb}, the object is written to a binary file. When {\tt outFile} is {\it not} {\tt "none"}, the object is written to the file in a human readable format. When {\tt outFile} is {\tt "none"}, the object is not written out. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} DV/doc/makefile010064400020550007177000000000270654276733100146630ustar00clevecompmath00000400000006clean : - rm -f *.dvi DenseMtx.h010064400020550007177000000001140656762734600140120ustar00clevecompmath00000400000006#ifndef _DenseMtx_ #define _DenseMtx_ #include "DenseMtx/DenseMtx.h" #endif DenseMtx/DenseMtx.h010064400020550007177000000462600662234403600155350ustar00clevecompmath00000400000006/* DenseMtx */ #include "../cfiles.h" #include "../Drand.h" #include "../A2.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- this object handles a dense real and complex matrix. type -- type of entries 1 -- real 2 -- complex rowid -- id for the rows in this matrix colid -- id for the columns in this matrix nrow -- # of rows in the matrix ncol -- # of columns in the matrix inc1 -- row increment for the entries inc2 -- column increment for the entries rowind -- pointer to row indices colind -- pointer to column indices entries -- pointer to matrix entries wrkDV -- DV object to manage workspace next -- pointer to next DenseMtx object in a singly linked list ------------------------------------------------------------------- */ typedef struct _DenseMtx DenseMtx ; struct _DenseMtx { int type ; int rowid ; int colid ; int nrow ; int ncol ; int inc1 ; int inc2 ; int *rowind ; int *colind ; double *entries ; DV wrkDV ; DenseMtx *next ; } ; #define DENSEMTX_IS_REAL(mtx) ((mtx)->type == SPOOLES_REAL) #define DENSEMTX_IS_COMPLEX(mtx) ((mtx)->type == SPOOLES_COMPLEX) /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ DenseMtx * DenseMtx_new ( void ) ; /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void DenseMtx_setDefaultFields ( DenseMtx *mtx ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void DenseMtx_clearData ( DenseMtx *mtx ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ void DenseMtx_free ( DenseMtx *mtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------- return the row id of the object created -- 98may02, cca ------------------------------- */ int DenseMtx_rowid ( DenseMtx *mtx ) ; /* ---------------------------------- return the column id of the object created -- 98may02, cca ---------------------------------- */ int DenseMtx_colid ( DenseMtx *mtx ) ; /* ------------------------------------------ fill *pnrow with nrow and *pncol with ncol created -- 98may02, cca ------------------------------------------ */ void DenseMtx_dimensions ( DenseMtx *mtx, int *pnrow, int *pncol ) ; /* ------------------------ return the row increment created -- 98may02, cca ------------------------ */ int DenseMtx_rowIncrement ( DenseMtx *mtx ) ; /* --------------------------- return the column increment created -- 98may02, cca --------------------------- */ int DenseMtx_columnIncrement ( DenseMtx *mtx ) ; /* ------------------------------------------- fill *pnrow with nrow, *prowind with rowind created -- 98may02, cca ------------------------------------------- */ void DenseMtx_rowIndices ( DenseMtx *mtx, int *pnrow, int **prowind ) ; /* ------------------------------------------- fill *pncol with ncol, *pcolind with colind created -- 98may02, cca ------------------------------------------- */ void DenseMtx_columnIndices ( DenseMtx *mtx, int *pncol, int **pcolind ) ; /* -------------------------------------------- fill *pentries with a pointer to the entries created -- 98may02, cca -------------------------------------------- */ double * DenseMtx_entries( DenseMtx *mtx ) ; /* --------------------------------- return a pointer to the workspace created -- 98may02, cca --------------------------------- */ void * DenseMtx_workspace( DenseMtx *mtx ) ; /* ------------------------------------------ fill *pValue with the entry in (irow,jcol) created -- 98jun05, cca ------------------------------------------ */ void DenseMtx_realEntry ( DenseMtx *mtx, int irow, int jcol, double *pValue ) ; /* ---------------------------------------------------- fill *pReal and *pImag with the entry in (irow,jcol) created -- 98jun05, cca ---------------------------------------------------- */ void DenseMtx_complexEntry ( DenseMtx *mtx, int irow, int jcol, double *pReal, double *pImag ) ; /* ------------------------------ set entry (irow,jcol) to value created -- 98jun05, cca ------------------------------ */ void DenseMtx_setRealEntry ( DenseMtx *mtx, int irow, int jcol, double value ) ; /* ------------------------------------ set entry (irow,jcol) to (real,imag) created -- 98jun05, cca ------------------------------------ */ void DenseMtx_setComplexEntry ( DenseMtx *mtx, int irow, int jcol, double real, double imag ) ; /* ---------------------------------------------------------- purpose -- fill *prowent with the base address of row irow return values -- 1 -- normal return -1 -- mtx is NULL -2 -- invalid type for mtx -3 -- irow is invalid -4 -- prowent is NULL created -- 98nov11, cca ---------------------------------------------------------- */ int DenseMtx_row ( DenseMtx *mtx, int irow, double **prowent ) ; /* ------------------------------------------------------------- purpose -- fill *pcolent with the base address of column jcol return values -- 1 -- normal return -1 -- mtx is NULL -2 -- invalid type for mtx -3 -- jcol is invalid -4 -- pcolent is NULL created -- 98nov11, cca ------------------------------------------------------------- */ int DenseMtx_column ( DenseMtx *mtx, int jcol, double **pcolent ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ return the number of bytes needed for an object of this size created -- 98may02, cca ------------------------------------------------------------ */ int DenseMtx_nbytesNeeded ( int type, int nrow, int ncol ) ; /* ---------------------------------------------------------------- return the number of bytes in the workspace owned by this object created -- 98may02, cca ---------------------------------------------------------------- */ int DenseMtx_nbytesInWorkspace ( DenseMtx *mtx ) ; /* ------------------------------------------------------------- set the number of bytes in the workspace owned by this object created -- 98may02, cca ------------------------------------------------------------- */ void DenseMtx_setNbytesInWorkspace ( DenseMtx *mtx, int nbytes ) ; /* --------------------------------------- purpose -- set the fields of the object created -- 98may02, cca --------------------------------------- */ void DenseMtx_setFields ( DenseMtx *mtx, int type, int rowid, int colid, int nrow, int ncol, int inc1, int inc2 ) ; /* ---------------------------- purpose -- basic initializer created -- 98may02, cca ---------------------------- */ void DenseMtx_init ( DenseMtx *mtx, int type, int rowid, int colid, int nrow, int ncol, int inc1, int inc2 ) ; /* --------------------------------------------------------- purpose -- initialize the object from its working storage used when the object is a MPI message created -- 98may02, cca --------------------------------------------------------- */ void DenseMtx_initFromBuffer ( DenseMtx *mtx ) ; /* ------------------------------------ purpose -- initializer with pointers created -- 98may02, cca ------------------------------------ */ void DenseMtx_initWithPointers ( DenseMtx *mtx, int type, int rowid, int colid, int nrow, int ncol, int inc1, int inc2, int *rowind, int *colind, double *entries ) ; /* ----------------------------------- this method initializes a A2 object to point into the entries created -- 98may02, cca ----------------------------------- */ void DenseMtx_setA2 ( DenseMtx *mtx, A2 *a2 ) ; /* ---------------------------------------------------------------- purpose -- initialize as a submatrix of another DenseMtx object. B = A(firstrow:lastrow, firstcol:lastcol) note, B only points into the storage of A. return values -- 1 -- normal return -1 -- B is NULL -2 -- A is NULL -3 -- A has invalid type -4 -- requested rows are invalid -5 -- requested columns are invalid created -- 98nov11, cca ---------------------------------------------------------------- */ int DenseMtx_initAsSubmatrix ( DenseMtx *B, DenseMtx *A, int firstrow, int lastrow, int firstcol, int lastcol ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- purpose -- to read in the object from a file input -- fn -- filename, must be *.densemtxb or *.densemtxf return value -- 1 if success, 0 if failure created -- 98aug13 ----------------------------------------------------------- */ int DenseMtx_readFromFile ( DenseMtx *mtx, char *fn ) ; /* -------------------------------------------------- purpose -- to read an object from a formatted file return value -- 1 if success, 0 if failure created -- 98aug13 -------------------------------------------------- */ int DenseMtx_readFromFormattedFile ( DenseMtx *mtx, FILE *fp ) ; /* ----------------------------------------------- purpose -- to read an object from a binary file return value -- 1 if success, 0 if failure created -- 98aug13 ----------------------------------------------- */ int DenseMtx_readFromBinaryFile ( DenseMtx *mtx, FILE *fp ) ; /* --------------------------------------- purpose -- to write an object to a file input -- fn -- filename *.densemtxb -- binary *.densemtxf -- formatted anything else -- for human eye error return -- 1 -- normal return -1 -- mtx is NULL -2 -- fn is NULL -3 -- unable to open file created -- 98aug13 --------------------------------------- */ int DenseMtx_writeToFile ( DenseMtx *mtx, char *fn ) ; /* ------------------------------------------------- purpose -- to write an object to a formatted file return value -- 1 -- normal return -1 -- mtx is NULL -2 -- fn is NULL created -- 98aug13 ------------------------------------------------- */ int DenseMtx_writeToFormattedFile ( DenseMtx *mtx, FILE *fp ) ; /* -------------------------------------------------------- purpose -- to write an adjacency object to a binary file return value -- 1 -- normal return -1 -- mtx is NULL -2 -- fn is NULL created -- 98aug13 -------------------------------------------------------- */ int DenseMtx_writeToBinaryFile ( DenseMtx *mtx, FILE *fp ) ; /* ----------------------------------------------------- purpose -- to write the object's statistics to a file in human readable form return value -- 1 -- normal return -1 -- mtx is NULL -2 -- fp is NULL created -- 98may02, cca ----------------------------------------------------- */ int DenseMtx_writeStats ( DenseMtx *mtx, FILE *fp ) ; /* ---------------------------------------- purpose -- to write the object to a file in human readable form return value -- 1 -- normal return -1 -- mtx is NULL -2 -- fp is NULL created -- 98may02, cca ---------------------------------------- */ int DenseMtx_writeForHumanEye ( DenseMtx *mtx, FILE *fp ) ; /* ----------------------------------------------- purpose -- to write the object to a matlab file return value -- 1 -- normal return -1 -- mtx is NULL -2 -- mtx is NULL -3 -- fp is NULL created -- 98may02, cca ----------------------------------------------- */ int DenseMtx_writeForMatlab ( DenseMtx *mtx, char *mtxname, FILE *fp ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in permute.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------- purpose -- to permute the rows of an object created -- 98may02, cca ------------------------------------------- */ void DenseMtx_permuteRows ( DenseMtx *mtx, IV *oldToNewIV ) ; /* ---------------------------------------------- purpose -- to permute the columns of an object created -- 98may02, cca ---------------------------------------------- */ void DenseMtx_permuteColumns ( DenseMtx *mtx, IV *oldToNewIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------------------------------- sort the rows so the row ids are in ascending order sort the columns so the column ids are in ascending order created -- 98may02, cca --------------------------------------------------------- */ void DenseMtx_sort ( DenseMtx *mtx ) ; /* ----------------------------------------------- copy row irowA from mtxA into row irowB in mtxB created -- 98may02, cca ----------------------------------------------- */ void DenseMtx_copyRow ( DenseMtx *mtxB, int irowB, DenseMtx *mtxA, int irowA ) ; /* --------------------------------------------------------------- copy row irowA from mtxA into row irowB in mtxB and copy row index irowB from mtxB into row index irowA of mtxA created -- 98aug12, cca --------------------------------------------------------------- */ void DenseMtx_copyRowAndIndex ( DenseMtx *mtxB, int irowB, DenseMtx *mtxA, int irowA ) ; /* ---------------------------------------------- add row irowA from mtxA into row irowB in mtxB created -- 98aug12, cca ---------------------------------------------- */ void DenseMtx_addRow ( DenseMtx *mtxB, int irowB, DenseMtx *mtxA, int irowA ) ; /* ----------------------- zero the entries created -- 98may16, cca ----------------------- */ void DenseMtx_zero ( DenseMtx *mtx ) ; /* ------------------------ fill with random entries created -- 98may16, cca ------------------------ */ void DenseMtx_fillRandomEntries ( DenseMtx *mtx, Drand *drand ) ; /* ----------------------------------- compute three checksums sums[0] = sum of row indices sums[1] = sum of columns indices sums[2] = sum of entry magnitudes created -- 98may16, cca ----------------------------------- */ void DenseMtx_checksums ( DenseMtx *mtx, double sums[] ) ; /* ------------------------------------------- return the maximum magnitude of the entries created -- 98may15, cca ------------------------------------------- */ double DenseMtx_maxabs ( DenseMtx *mtx ) ; /* -------------------------------------------- subtract one matrix from another, B := B - A created -- 98may25, cca -------------------------------------------- */ void DenseMtx_sub ( DenseMtx *mtxB, DenseMtx *mtxA ) ; /* ---------------------------------------------------- purpose -- to copy a row of the matrix into a vector irow -- local row id vec -- double vector to receive the row entries created -- 98jul31, cca ---------------------------------------------------- */ void DenseMtx_copyRowIntoVector ( DenseMtx *mtx, int irow, double *vec ) ; /* ---------------------------------------------------- purpose -- to copy a row of the matrix into a vector irow -- local row id vec -- double vector to supply the row entries created -- 98jul31, cca ---------------------------------------------------- */ void DenseMtx_copyVectorIntoRow ( DenseMtx *mtx, int irow, double *vec ) ; /* ---------------------------------------------------- purpose -- to add a row of the matrix into a vector irow -- local row id vec -- double vector to supply the row entries created -- 98aug12, cca ---------------------------------------------------- */ void DenseMtx_addVectorIntoRow ( DenseMtx *mtx, int irow, double *vec ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in scale.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------- purpose -- to scale a dense matrix object by a scalar A := alpha * A ; return values --- 1 -- normal return -1 -- A is NULL -2 -- A has invalid type -3 -- alpha is NULL created -- 98nov06, cca ----------------------------------------------------- */ int DenseMtx_scale ( DenseMtx *A, double alpha[] ) ; /*--------------------------------------------------------------------*/ int inc2, int *rowind, int *colind, double *entries ) ; /* ----------------------------------- this method initializes a A2 object to point into the entries created -- 98may02, cca ----------------------------------- */ void DenseMtx_setA2 ( DenseMtx *mtx, A2 *a2 ) ; DenseMtx/makefile010064400020550007177000000001410663622356300153270ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean DenseMtx/src/makefile010064400020550007177000000010610663602235500161140ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = DenseMtx $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(initAsSubmtx.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(permute.o) \ $(OBJ).a(scale.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG DenseMtx/src/makeGlobalLib010064400020550007177000000007100662560201100170130ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = DenseMtx SRC = basics.c \ init.c \ initAsSubmtx.c \ instance.c \ IO.c \ permute.c \ scale.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a DenseMtx/src/IO.c010064400020550007177000000431540661671376500151120ustar00clevecompmath00000400000006/* IO.c */ #include "../DenseMtx.h" static const char *suffixb = ".densemtxb" ; static const char *suffixf = ".densemtxf" ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to read in the object from a file input -- fn -- filename, must be *.densemtxb or *.densemtxf return value -- 1 if success, 0 if failure created -- 98aug13 ----------------------------------------------------------- */ int DenseMtx_readFromFile ( DenseMtx *mtx, char *fn ) { FILE *fp ; int fnlength, rc = 0, sulength ; /* --------------- check the input --------------- */ if ( mtx == NULL || fn == NULL ) { fprintf(stderr, "\n error in DenseMtx_readFromFile(%p,%s)" "\n bad input", mtx, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in DenseMtx_readFromFile()" "\n unable to open file %s", fn) ; } else { rc = DenseMtx_readFromBinaryFile(mtx, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in DenseMtx_readFromFile()" "\n unable to open file %s", fn) ; } else { rc = DenseMtx_readFromFormattedFile(mtx, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in DenseMtx_readFromFile()" "\n bad DenseMtx file name %s," "\n must end in %s (binary) or %s (formatted)\n", fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in DenseMtx_readFromFile()" "\n bad DenseMtx file name %s," "\n must end in %s (binary) or %s (formatted)\n", fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to read an object from a formatted file return value -- 1 if success, 0 if failure created -- 98aug13 -------------------------------------------------- */ int DenseMtx_readFromFormattedFile ( DenseMtx *mtx, FILE *fp ) { int rc, size ; int itemp[7] ; /* --------------- check the input --------------- */ if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n error in DenseMtx_readFromFormattedFile(%p,%p)" "\n bad input", mtx, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ DenseMtx_clearData(mtx) ; /* -------------------------------------------- read in the seven scalar parameters: type, rowid, colid, nrow, ncol, inc1, inc2 -------------------------------------------- */ if ( (rc = IVfscanf(fp, 7, itemp)) != 7 ) { fprintf(stderr, "\n error in DenseMtx_readFromFormattedFile()" "\n %d items of %d read\n", rc, 7) ; return(0) ; } /* --------------------- initialize the object --------------------- */ DenseMtx_init(mtx, itemp[0], itemp[1], itemp[2], itemp[3], itemp[4], itemp[5], itemp[6]) ; /* --------------------------- read in the rowind[] vector --------------------------- */ if ( (size = mtx->nrow) > 0 ) { if ( (rc = IVfscanf(fp, size, mtx->rowind)) != size ) { fprintf(stderr, "\n error in DenseMtx_readFromFormattedFile()" "\n %d items of %d read for rowind\n", rc, size) ; return(0) ; } } /* --------------------------- read in the colind[] vector --------------------------- */ if ( (size = mtx->ncol) > 0 ) { if ( (rc = IVfscanf(fp, size, mtx->colind)) != size ) { fprintf(stderr, "\n error in DenseMtx_readFromFormattedFile()" "\n %d items of %d read for colind\n", rc, size) ; return(0) ; } } /* ---------------------------- read in the entries[] vector ---------------------------- */ if ( (size = mtx->nrow*mtx->ncol) > 0 ) { if ( DENSEMTX_IS_REAL(mtx) ) { if ( (rc = DVfscanf(fp, size, mtx->entries)) != size ) { fprintf(stderr, "\n error in DenseMtx_readFromFormattedFile()" "\n %d items of %d read for entries\n", rc, size) ; return(0) ; } } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { if ( (rc = DVfscanf(fp, 2*size, mtx->entries)) != 2*size ) { fprintf(stderr, "\n error in DenseMtx_readFromFormattedFile()" "\n %d items of %d read for entries\n", rc, 2*size) ; return(0) ; } } } return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to read an object from a binary file return value -- 1 if success, 0 if failure created -- 98aug13 ----------------------------------------------- */ int DenseMtx_readFromBinaryFile ( DenseMtx *mtx, FILE *fp ) { int rc, size ; int itemp[7] ; /* --------------- check the input --------------- */ if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_readFromBinaryFile(%p,%p)" "\n bad input", mtx, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ DenseMtx_clearData(mtx) ; /* -------------------------------------------- read in the seven scalar parameters: type, rowid, colid, nrow, ncol, inc1, inc2 -------------------------------------------- */ if ( (rc = fread((char *) itemp, sizeof(int), 7, fp)) != 7 ) { fprintf(stderr, "\n error in DenseMtx_readFromBinaryFile()" "\n %d items of %d read\n", rc, 7) ; return(0) ; } /* --------------------- initialize the object --------------------- */ DenseMtx_init(mtx, itemp[0], itemp[1], itemp[2], itemp[3], itemp[4], itemp[5], itemp[6]) ; /* --------------------------- read in the rowind[] vector --------------------------- */ if ( (size = mtx->nrow) > 0 ) { if ( (rc = fread(mtx->rowind, sizeof(int), size, fp)) != size ) { fprintf(stderr, "\n error in DenseMtx_readFromBinaryFile()" "\n %d items of %d read for rowind[]\n", rc, size) ; return(0) ; } } /* --------------------------- read in the colind[] vector --------------------------- */ if ( (size = mtx->ncol) > 0 ) { if ( (rc = fread(mtx->colind, sizeof(int), size, fp)) != size ) { fprintf(stderr, "\n error in DenseMtx_readFromBinaryFile()" "\n %d items of %d read for colind[]\n", rc, size) ; return(0) ; } } /* ---------------------------- read in the entries[] vector ---------------------------- */ if ( (size = mtx->nrow*mtx->ncol) > 0 ) { if ( DENSEMTX_IS_REAL(mtx) ) { rc = fread(mtx->entries, sizeof(double), size, fp) ; if ( rc != size ) { fprintf(stderr, "\n error in DenseMtx_readFromBinaryFile()" "\n %d items of %d read for entries\n", rc, size) ; return(0) ; } } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { rc = fread(mtx->entries, sizeof(double), 2*size, fp) ; if ( rc != 2*size ) { fprintf(stderr, "\n error in DenseMtx_readFromBinaryFile()" "\n %d items of %d read for entries\n", rc, 2*size) ; return(0) ; } } } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- to write an object to a file input -- fn -- filename *.densemtxb -- binary *.densemtxf -- formatted anything else -- for human eye error return -- 1 -- normal return -1 -- mtx is NULL -2 -- fn is NULL -3 -- unable to open file created -- 98aug13 --------------------------------------- */ int DenseMtx_writeToFile ( DenseMtx *mtx, char *fn ) { FILE *fp ; int fnlength, sulength ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeToFile(%p,%s)" "\n mtx is NULL", mtx, fn) ; return(-1) ; } if ( fn == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeToFile(%p,%s)" "\n fn is NULL", mtx, fn) ; return(-2) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in DenseMtx_writeToFile()" "\n unable to open file %s", fn) ; return(-3) ; } else { DenseMtx_writeToBinaryFile(mtx, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in DenseMtx_writeToFile()" "\n unable to open file %s", fn) ; return(-3) ; } else { DenseMtx_writeToFormattedFile(mtx, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in DenseMtx_writeToFile()" "\n unable to open file %s", fn) ; return(-3) ; } else { DenseMtx_writeForHumanEye(mtx, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in DenseMtx_writeToFile()" "\n unable to open file %s", fn) ; return(-3) ; } else { DenseMtx_writeForHumanEye(mtx, fp) ; fclose(fp) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to write an object to a formatted file return value -- 1 -- normal return -1 -- mtx is NULL -2 -- fn is NULL created -- 98aug13 ------------------------------------------------- */ int DenseMtx_writeToFormattedFile ( DenseMtx *mtx, FILE *fp ) { int size ; if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeToFormattedFile()" "\n mtx is NULL") ; return(-1) ; } if ( fp == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeToFormattedFile()" "\n fp is NULL") ; return(-2) ; } fprintf(fp, "\n %d %d %d %d %d %d %d", mtx->type, mtx->rowid, mtx->colid, mtx->nrow, mtx->ncol, mtx->inc1, mtx->inc2) ; if ( (size = mtx->nrow) > 0 && mtx->rowind != NULL ) { IVfprintf(fp, size, mtx->rowind) ; } if ( (size = mtx->ncol) > 0 && mtx->colind != NULL ) { IVfprintf(fp, size, mtx->colind) ; } if ( (size = mtx->nrow*mtx->ncol) > 0 && mtx->entries != NULL ) { if ( DENSEMTX_IS_REAL(mtx) ) { DVfprintf(fp, size, mtx->entries) ; } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { DVfprintf(fp, 2*size, mtx->entries) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to write an adjacency object to a binary file return value -- 1 -- normal return -1 -- mtx is NULL -2 -- fn is NULL created -- 98aug13 -------------------------------------------------------- */ int DenseMtx_writeToBinaryFile ( DenseMtx *mtx, FILE *fp ) { int size ; if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeToBinaryFile()" "\n mtx is NULL") ; return(-1) ; } if ( fp == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeToBinaryFile()" "\n fp is NULL") ; return(-2) ; } fwrite((void *) &mtx->type, sizeof(int), 1, fp) ; fwrite((void *) &mtx->rowid, sizeof(int), 1, fp) ; fwrite((void *) &mtx->colid, sizeof(int), 1, fp) ; fwrite((void *) &mtx->nrow, sizeof(int), 1, fp) ; fwrite((void *) &mtx->ncol, sizeof(int), 1, fp) ; fwrite((void *) &mtx->inc1, sizeof(int), 1, fp) ; fwrite((void *) &mtx->inc2, sizeof(int), 1, fp) ; if ( (size = mtx->nrow) > 0 && mtx->rowind != NULL ) { fwrite((void *) mtx->rowind, sizeof(int), size, fp) ; } if ( (size = mtx->ncol) > 0 && mtx->colind != NULL ) { fwrite((void *) mtx->colind, sizeof(int), size, fp) ; } if ( (size = mtx->nrow*mtx->ncol) > 0 && mtx->entries != NULL ) { if ( DENSEMTX_IS_REAL(mtx) ) { fwrite((void *) mtx->entries, sizeof(double), size, fp) ; } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { fwrite((void *) mtx->entries, sizeof(double), 2*size, fp) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to write the object's statistics to a file in human readable form return value -- 1 -- normal return -1 -- mtx is NULL -2 -- fp is NULL created -- 98may02, cca ----------------------------------------------------- */ int DenseMtx_writeStats ( DenseMtx *mtx, FILE *fp ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeStats()" "\n mtx is NULL") ; return(-1) ; } if ( fp == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeStats()" "\n fp is NULL") ; return(-2) ; } fprintf(fp, "\n DenseMtx object at address %p", mtx) ; switch ( mtx->type ) { case SPOOLES_REAL : fprintf(fp, ", real entries") ; break ; case SPOOLES_COMPLEX : fprintf(fp, ", complex entries") ; break ; default : fprintf(fp, ", unknown entries type") ; break ; } fprintf(fp, "\n row id = %d, col id = %d" "\n nrow = %d, ncol = %d, inc1 = %d, inc2 = %d", mtx->rowid, mtx->colid, mtx->nrow, mtx->ncol, mtx->inc1, mtx->inc2) ; fprintf(fp, "\n rowind = %p, colind = %p, entries = %p", mtx->rowind, mtx->colind, mtx->entries) ; fprintf(fp, ", base = %p", DV_entries(&mtx->wrkDV)) ; fprintf(fp, "\n rowind - base = %d, colind - base = %d, entries - base = %d", mtx->rowind - (int *) DV_entries(&mtx->wrkDV), mtx->colind - (int *) DV_entries(&mtx->wrkDV), mtx->entries - DV_entries(&mtx->wrkDV)) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to write the object to a file in human readable form return value -- 1 -- normal return -1 -- mtx is NULL -2 -- fp is NULL created -- 98may02, cca ---------------------------------------- */ int DenseMtx_writeForHumanEye ( DenseMtx *mtx, FILE *fp ) { A2 a2 ; int ierr, ncol, nrow ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeForHumanEye()" "\n mtx is NULL\n") ; return(-1) ; } if ( fp == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeForHumanEye()" "\n mtx is NULL\n") ; return(-2) ; } DenseMtx_writeStats(mtx, fp) ; DenseMtx_rowIndices(mtx, &nrow, &rowind) ; if ( nrow > 0 && rowind != NULL ) { fprintf(fp, "\n mtx's row indices at %p", rowind) ; IVfp80(fp, nrow, rowind, 80, &ierr) ; } DenseMtx_columnIndices(mtx, &ncol, &colind) ; if ( ncol > 0 && colind != NULL ) { fprintf(fp, "\n mtx's column indices at %p", colind) ; IVfp80(fp, ncol, colind, 80, &ierr) ; } if ( nrow > 0 && ncol > 0 ) { A2_setDefaultFields(&a2) ; DenseMtx_setA2(mtx, &a2) ; A2_writeForHumanEye(&a2, fp) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to write the object to a matlab file return value -- 1 -- normal return -1 -- mtx is NULL -2 -- mtx is NULL -3 -- fp is NULL created -- 98may02, cca ----------------------------------------------- */ int DenseMtx_writeForMatlab ( DenseMtx *mtx, char *mtxname, FILE *fp ) { double *entries ; int inc1, inc2, irow, jcol, ncol, nrow ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeForMatlab()" "\n mtx is NULL\n") ; return(-1) ; } if ( mtxname == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeForMatlab()" "\n mtxname is NULL\n") ; return(-2) ; } if ( fp == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_writeForMatlab()" "\n fp is NULL\n") ; return(-3) ; } DenseMtx_rowIndices(mtx, &nrow, &rowind) ; DenseMtx_columnIndices(mtx, &ncol, &colind) ; DenseMtx_dimensions(mtx, &nrow, &ncol) ; inc1 = DenseMtx_rowIncrement(mtx) ; inc2 = DenseMtx_columnIncrement(mtx) ; entries = DenseMtx_entries(mtx) ; if ( DENSEMTX_IS_REAL(mtx) ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { for ( irow = 0 ; irow < nrow ; irow++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e ;", mtxname, rowind[irow]+1, colind[jcol]+1, entries[irow*inc1+jcol*inc2]) ; } } } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { for ( irow = 0 ; irow < nrow ; irow++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e + %24.16e*i ;", mtxname, rowind[irow]+1, colind[jcol]+1, entries[2*(irow*inc1+jcol*inc2)], entries[2*(irow*inc1+jcol*inc2)+1]) ; } } } return(1) ; } /*--------------------------------------------------------------------*/ to write an object to a file input -- fn -- filename *.densemtxb -- binary *.densemtxf -- formatted anything else -- for human eye error return -- 1 -- normal return -1 -- mtx is NULL -2 -- fn is NULL -3 -- unable to open file created -- 98aug13 --------------------------------------- */ int DenseMtx_writeToFile ( DenseMtx *mtxDenseMtx/src/basics.c010064400020550007177000000045260656040644300160350ustar00clevecompmath00000400000006/* basics.c */ #include "../DenseMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ DenseMtx * DenseMtx_new ( void ) { DenseMtx *mtx ; ALLOCATE(mtx, struct _DenseMtx, 1) ; DenseMtx_setDefaultFields(mtx) ; return(mtx) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void DenseMtx_setDefaultFields ( DenseMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_setDefaultFields(%p)" "\n bad input", mtx) ; exit(-1) ; } mtx->type = SPOOLES_REAL ; mtx->rowid = -1 ; mtx->colid = -1 ; mtx->nrow = 0 ; mtx->ncol = 0 ; mtx->inc1 = 0 ; mtx->inc2 = 0 ; mtx->rowind = NULL ; mtx->colind = NULL ; mtx->entries = NULL ; DV_setDefaultFields(&mtx->wrkDV) ; mtx->next = NULL ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void DenseMtx_clearData ( DenseMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_clearData(%p)" "\n bad input\n", mtx) ; exit(-1) ; } /* ------------------------ free the working storage ------------------------ */ DV_clearData(&mtx->wrkDV) ; /* ---------------------- set the default fields ---------------------- */ DenseMtx_setDefaultFields(mtx) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ void DenseMtx_free ( DenseMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_free(%p)" "\n bad input\n", mtx) ; exit(-1) ; } DenseMtx_clearData(mtx) ; FREE(mtx) ; return ; } /*--------------------------------------------------------------------*/ DenseMtx/src/init.c010064400020550007177000000224760660471773400155470ustar00clevecompmath00000400000006/* init.c */ #include "../DenseMtx.h" #define MYDEBUG 1 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ return the number of bytes needed for an object of this size created -- 98may02, cca ------------------------------------------------------------ */ int DenseMtx_nbytesNeeded ( int type, int nrow, int ncol ) { int nbytes, ndouble, nint ; /* --------------- check the input --------------- */ if ( nrow < 0 || ncol < 0 ) { fprintf(stderr, "\n fatal error in DenseMtx_nbytesNeeded(%d,%d,%d)" "\n bad input\n", type, nrow, ncol) ; exit(-1) ; } nint = 7 + nrow + ncol ; if ( type == SPOOLES_REAL ) { ndouble = nrow*ncol ; } else if ( type == SPOOLES_COMPLEX ) { ndouble = 2*nrow*ncol ; } else { fprintf(stderr, "\n fatal error in DenseMtx_nbytesNeeded(%d,%d,%d)" "\n bad type %d\n", type, nrow, ncol, type) ; exit(-1) ; } if ( sizeof(int) == sizeof(double) ) { nbytes = nint*sizeof(int) + ndouble*sizeof(double) ; } else if ( 2*sizeof(int) == sizeof(double) ) { nbytes = ((nint + 1)/2 + ndouble)*sizeof(double) ; } else { fprintf(stderr, "\n error in DenseMtx_nbytesNeeded(%d,%d)" "\n sizeof(int) = %d, sizeof(double) = %d", nrow, ncol, sizeof(int), sizeof(double)) ; exit(-1) ; } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- return the number of bytes in the workspace owned by this object created -- 98may02, cca ---------------------------------------------------------------- */ int DenseMtx_nbytesInWorkspace ( DenseMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_nbytesInWorkspace(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(sizeof(double)*DV_maxsize(&mtx->wrkDV)) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- set the number of bytes in the workspace owned by this object created -- 98may02, cca ------------------------------------------------------------- */ void DenseMtx_setNbytesInWorkspace ( DenseMtx *mtx, int nbytes ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_setNbytesInWorkspace(%p)" "\n bad input\n", mtx) ; exit(-1) ; } DV_setSize(&mtx->wrkDV, nbytes/sizeof(double)) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- set the fields of the object created -- 98may02, cca --------------------------------------- */ void DenseMtx_setFields ( DenseMtx *mtx, int type, int rowid, int colid, int nrow, int ncol, int inc1, int inc2 ) { double *dbuffer ; int *ibuffer ; /* --------------- check the input --------------- */ if ( mtx == NULL || nrow < 0 || ncol < 0 || !((inc1 == ncol && inc2 == 1) || (inc1 == 1 && inc2 == nrow)) ) { fprintf(stderr, "\n fatal error in DenseMtx_setFields(%p,%d,%d,%d,%d,%d,%d)" "\n bad input\n", mtx, rowid, colid, nrow, ncol, inc1, inc2) ; exit(-1) ; } dbuffer = DV_entries(&mtx->wrkDV) ; ibuffer = (int *) dbuffer ; /* --------------------- set the scalar fields --------------------- */ mtx->type = ibuffer[0] = type ; mtx->rowid = ibuffer[1] = rowid ; mtx->colid = ibuffer[2] = colid ; mtx->nrow = ibuffer[3] = nrow ; mtx->ncol = ibuffer[4] = ncol ; mtx->inc1 = ibuffer[5] = inc1 ; mtx->inc2 = ibuffer[6] = inc2 ; /* ------------------- set up the pointers ------------------- */ mtx->rowind = ibuffer + 7 ; mtx->colind = mtx->rowind + nrow ; if ( sizeof(int) == sizeof(double) ) { mtx->entries = dbuffer + 7 + nrow + ncol ; } else if ( 2*sizeof(int) == sizeof(double) ) { mtx->entries = dbuffer + (8 + nrow + ncol)/2 ; } /* fprintf(stdout, "\n rowind - ibuffer = %d" "\n colind - rowind = %d" "\n entries - dbuffer = %d", mtx->rowind - ibuffer, mtx->colind - mtx->rowind, mtx->entries - dbuffer) ; */ return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- purpose -- basic initializer created -- 98may02, cca ---------------------------- */ void DenseMtx_init ( DenseMtx *mtx, int type, int rowid, int colid, int nrow, int ncol, int inc1, int inc2 ) { int nbytes ; /* --------------- check the input --------------- */ if ( mtx == NULL || nrow < 0 || ncol < 0 || !((inc1 == ncol && inc2 == 1) || (inc1 == 1 && inc2 == nrow)) ) { fprintf(stderr, "\n fatal error in DenseMtx_init(%p,%d,%d,%d,%d,%d,%d)" "\n bad input\n", mtx, rowid, colid, nrow, ncol, inc1, inc2) ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n fatal error in DenseMtx_init(%p,%d,%d,%d,%d,%d,%d,%d)" "\n bad type %d\n", mtx, type, rowid, colid, nrow, ncol, inc1, inc2, type) ; exit(-1) ; break ; } /* ------------------------------------------------------- get and set the number of bytes needed in the workspace ------------------------------------------------------- */ nbytes = DenseMtx_nbytesNeeded(type, nrow, ncol) ; DenseMtx_setNbytesInWorkspace(mtx, nbytes) ; /* -------------- set the fields -------------- */ DenseMtx_setFields(mtx, type, rowid, colid, nrow, ncol, inc1, inc2) ; if ( nrow > 0 ) { IVramp(nrow, mtx->rowind, 0, 1) ; } if ( ncol > 0 ) { IVramp(ncol, mtx->colind, 0, 1) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- initialize the object from its working storage used when the object is a MPI message created -- 98may02, cca --------------------------------------------------------- */ void DenseMtx_initFromBuffer ( DenseMtx *mtx ) { int *ibuffer ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_initFromBuffer(%p)" "\n bad input\n", mtx) ; exit(-1) ; } ibuffer = (int *) DV_entries(&mtx->wrkDV) ; DenseMtx_setFields(mtx, ibuffer[0], ibuffer[1], ibuffer[2], ibuffer[3], ibuffer[4], ibuffer[5], ibuffer[6]) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ purpose -- initializer with pointers created -- 98may02, cca ------------------------------------ */ void DenseMtx_initWithPointers ( DenseMtx *mtx, int type, int rowid, int colid, int nrow, int ncol, int inc1, int inc2, int *rowind, int *colind, double *entries ) { /* --------------- check the input --------------- */ if ( mtx == NULL || nrow <= 0 || ncol <= 0 || inc1 < 0 || inc2 < 0 || (inc1 != 1 && inc2 != 1) || entries == NULL || colind == NULL || rowind == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_initWithPointers()" "\n mtx = %p, rowid = %d, colid = %d" "\n nrow = %d, ncol = %d, inc1 = %d, inc2 = %d" "\n rowind = %p, colind = %p, entries = %p " "\n bad input\n", mtx, rowid, colid, nrow, ncol, inc1, inc2, rowind, colind, entries) ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n fatal error in DenseMtx_initWithPointers()" "\n bad type %d\n", type) ; break ; } /* --------------------- set the scalar fields --------------------- */ mtx->type = type ; mtx->rowid = rowid ; mtx->colid = colid ; mtx->nrow = nrow ; mtx->ncol = ncol ; mtx->inc1 = inc1 ; mtx->inc2 = inc2 ; /* -------------------------- set up the working storage -------------------------- */ mtx->rowind = rowind ; mtx->colind = colind ; mtx->entries = entries ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- this method initializes a A2 object to point into the entries created -- 98may02, cca ----------------------------------- */ void DenseMtx_setA2 ( DenseMtx *mtx, A2 *a2 ) { /* --------------- check the input --------------- */ if ( mtx == NULL || a2 == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_setZA2(%p,%p)" "\n bad input\n", mtx, a2) ; exit(-1) ; } /* if ( DENSEMTX_IS_REAL(mtx) ) { A2_init(a2, SPOOLES_REAL, mtx->nrow, mtx->ncol, mtx->inc1, mtx->inc2, mtx->entries) ; } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { A2_init(a2, SPOOLES_COMPLEX, mtx->nrow, mtx->ncol, mtx->inc1, mtx->inc2, mtx->entries) ; } */ A2_init(a2, mtx->type, mtx->nrow, mtx->ncol, mtx->inc1, mtx->inc2, mtx->entries) ; return ; } /*--------------------------------------------------------------------*/ --- */ mtx->rowind = ibuffer + 7 ; mtx->colind = mtx->rowind + nrow ; if ( sizeof(int) == sizeof(double) ) { mtx->entries = dbuffer + 7 + nrow + ncol ; } else if ( 2*sizeof(int) == sizeof(douDenseMtx/src/initAsSubmtx.c010064400020550007177000000044620662234363000172170ustar00clevecompmath00000400000006/* initAsSubmtx.c */ #include "../DenseMtx.h" #define MYDEBUG 1 /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- initialize as a submatrix of another DenseMtx object. B = A(firstrow:lastrow, firstcol:lastcol) note, B only points into the storage of A. return values -- 1 -- normal return -1 -- B is NULL -2 -- A is NULL -3 -- A has invalid type -4 -- requested rows are invalid -5 -- requested columns are invalid created -- 98nov11, cca ---------------------------------------------------------------- */ int DenseMtx_initAsSubmatrix ( DenseMtx *B, DenseMtx *A, int firstrow, int lastrow, int firstcol, int lastcol ) { /* --------------- check the input --------------- */ if ( B == NULL ) { fprintf(stderr, "\n error in DenseMtx_initAsSubmatrix()" "\n B is NULL\n") ; return(-1) ; } if ( A == NULL ) { fprintf(stderr, "\n error in DenseMtx_initAsSubmatrix()" "\n A is NULL\n") ; return(-2) ; } if ( A->type != SPOOLES_REAL && A->type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n error in DenseMtx_initAsSubmatrix()" "\n invalid type %d\n", A->type) ; return(-3) ; } if ( firstrow < 0 || lastrow >= A->nrow ) { fprintf(stderr, "\n error in DenseMtx_initAsSubmatrix()" "\n %d rows in A, firstrow is %d\n", A->nrow, firstrow) ; return(-4) ; } if ( firstcol < 0 || lastcol >= A->ncol ) { fprintf(stderr, "\n error in DenseMtx_initAsSubmatrix()" "\n %d columns in A, firstcol is %d\n", A->ncol, firstcol) ; return(-5) ; } /* --------------------- set the scalar fields --------------------- */ B->type = A->type ; B->rowid = A->rowid ; B->colid = A->colid ; B->nrow = lastrow - firstrow + 1 ; B->ncol = lastcol - firstcol + 1 ; B->inc1 = A->inc1 ; B->inc2 = A->inc2 ; B->rowind = A->rowind + firstrow ; B->colind = A->colind + firstcol ; if ( A->type == SPOOLES_REAL ) { B->entries = A->entries + firstrow*A->inc1 + firstcol*A->inc2 ; } else { B->entries = A->entries + 2*(firstrow*A->inc1 + firstcol*A->inc2) ; } return(1) ; } /*--------------------------------------------------------------------*/ DenseMtx/src/instance.c010064400020550007177000000316340662234446300163770ustar00clevecompmath00000400000006/* instance.c */ #include "../DenseMtx.h" /*--------------------------------------------------------------------*/ /* ------------------------------- return the row id of the object created -- 98may02, cca ------------------------------- */ int DenseMtx_rowid ( DenseMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_rowid(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(mtx->rowid) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- return the column id of the object created -- 98may02, cca ---------------------------------- */ int DenseMtx_colid ( DenseMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_colid(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(mtx->colid) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ fill *pnrow with nrow and *pncol with ncol created -- 98may02, cca ------------------------------------------ */ void DenseMtx_dimensions ( DenseMtx *mtx, int *pnrow, int *pncol ) { /* --------------- check the input --------------- */ if ( mtx == NULL || pnrow == NULL || pncol == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_dimensions(%p,%p,%p)" "\n bad input\n", mtx, pnrow, pncol) ; exit(-1) ; } *pnrow = mtx->nrow ; *pncol = mtx->ncol ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------ return the row increment created -- 98may02, cca ------------------------ */ int DenseMtx_rowIncrement ( DenseMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_rowIncrement(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(mtx->inc1) ; } /*--------------------------------------------------------------------*/ /* --------------------------- return the column increment created -- 98may02, cca --------------------------- */ int DenseMtx_columnIncrement ( DenseMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_columnIncrement(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(mtx->inc2) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- fill *pnrow with nrow, *prowind with rowind created -- 98may02, cca ------------------------------------------- */ void DenseMtx_rowIndices ( DenseMtx *mtx, int *pnrow, int **prowind ) { /* --------------- check the input --------------- */ if ( mtx == NULL || pnrow == NULL || prowind == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_rowIndices(%p,%p,%p)" "\n bad input\n", mtx, pnrow, prowind) ; exit(-1) ; } *pnrow = mtx->nrow ; *prowind = mtx->rowind ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- fill *pncol with ncol, *pcolind with colind created -- 98may02, cca ------------------------------------------- */ void DenseMtx_columnIndices ( DenseMtx *mtx, int *pncol, int **pcolind ) { /* --------------- check the input --------------- */ if ( mtx == NULL || pncol == NULL || pcolind == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_columnIndices(%p,%p,%p)" "\n bad input\n", mtx, pncol, pcolind) ; exit(-1) ; } *pncol = mtx->ncol ; *pcolind = mtx->colind ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------- return a pointer to the entries created -- 98may02, cca ------------------------------- */ double * DenseMtx_entries( DenseMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_entries(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(mtx->entries) ; } /*--------------------------------------------------------------------*/ /* --------------------------------- return a pointer to the workspace created -- 98may02, cca --------------------------------- */ void * DenseMtx_workspace( DenseMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_workspace(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(DV_entries(&mtx->wrkDV)) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ fill *pValue with the entry in (irow,jcol) created -- 98jun05, cca ------------------------------------------ */ void DenseMtx_realEntry ( DenseMtx *mtx, int irow, int jcol, double *pValue ) { /* --------------- check the input --------------- */ if ( mtx == NULL || pValue == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_realEntry()" "\n mtx or pValue is NULL\n") ; exit(-1) ; } if ( mtx->type != SPOOLES_REAL ) { fprintf(stderr, "\n fatal error in DenseMtx_realEntry()" "\n mtx type must be SPOOLES_REAL\n") ; exit(-1) ; } if ( irow < 0 || irow >= mtx->nrow ) { fprintf(stderr, "\n fatal error in DenseMtx_realEntry()" "\n irow = %d, mtx->nrow = %d input\n", irow, mtx->nrow) ; exit(-1) ; } if ( jcol < 0 || jcol >= mtx->ncol ) { fprintf(stderr, "\n fatal error in DenseMtx_realEntry()" "\n jcol = %d, mtx->ncol = %d input\n", jcol, mtx->ncol) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_realEntry()" "\n mtx->entries is NULL \n") ; exit(-1) ; } *pValue = mtx->entries[irow*mtx->inc1 + jcol*mtx->inc2] ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- fill *pReal and *pImag with the entry in (irow,jcol) created -- 98jun05, cca ---------------------------------------------------- */ void DenseMtx_complexEntry ( DenseMtx *mtx, int irow, int jcol, double *pReal, double *pImag ) { int loc ; /* --------------- check the input --------------- */ if ( mtx == NULL || pReal == NULL || pImag == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_complexEntry()" "\n mtxm pReal or pImag is NULL\n") ; exit(-1) ; } if ( mtx->type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error in DenseMtx_complexEntry()" "\n mtx type must be SPOOLES_COMPLEX\n") ; exit(-1) ; } if ( irow < 0 || irow >= mtx->nrow ) { fprintf(stderr, "\n fatal error in DenseMtx_complexEntry()" "\n irow = %d, mtx->nrow = %d input\n", irow, mtx->nrow) ; exit(-1) ; } if ( jcol < 0 || jcol >= mtx->ncol ) { fprintf(stderr, "\n fatal error in DenseMtx_complexEntry()" "\n jcol = %d, mtx->ncol = %d input\n", jcol, mtx->ncol) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_complexEntry()" "\n mtx->entries is NULL \n") ; exit(-1) ; } loc = 2*(irow*mtx->inc1 + jcol*mtx->inc2) ; *pReal = mtx->entries[loc] ; *pImag = mtx->entries[loc+1] ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------ set entry (irow,jcol) to value created -- 98jun05, cca ------------------------------ */ void DenseMtx_setRealEntry ( DenseMtx *mtx, int irow, int jcol, double value ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_setRealEntry()" "\n mtx is NULL\n") ; exit(-1) ; } if ( mtx->type != SPOOLES_REAL ) { fprintf(stderr, "\n fatal error in DenseMtx_setRealEntry()" "\n mtx type must be SPOOLES_REAL\n") ; exit(-1) ; } if ( irow < 0 || irow >= mtx->nrow ) { fprintf(stderr, "\n fatal error in DenseMtx_setRealEntry()" "\n irow = %d, mtx->nrow = %d input\n", irow, mtx->nrow) ; exit(-1) ; } if ( jcol < 0 || jcol >= mtx->ncol ) { fprintf(stderr, "\n fatal error in DenseMtx_setRealEntry()" "\n jcol = %d, mtx->ncol = %d input\n", jcol, mtx->ncol) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_setRealEntry()" "\n mtx->entries is NULL \n") ; exit(-1) ; } mtx->entries[irow*mtx->inc1 + jcol*mtx->inc2] = value ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ set entry (irow,jcol) to (real,imag) created -- 98jun05, cca ------------------------------------ */ void DenseMtx_setComplexEntry ( DenseMtx *mtx, int irow, int jcol, double real, double imag ) { int loc ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_setComplexEntry()" "\n mtx is NULL\n") ; exit(-1) ; } if ( mtx->type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error in DenseMtx_setComplexEntry()" "\n mtx type must be SPOOLES_COMPLEX\n") ; exit(-1) ; } if ( irow < 0 || irow >= mtx->nrow ) { fprintf(stderr, "\n fatal error in DenseMtx_setComplexEntry()" "\n irow = %d, mtx->nrow = %d input\n", irow, mtx->nrow) ; exit(-1) ; } if ( jcol < 0 || jcol >= mtx->ncol ) { fprintf(stderr, "\n fatal error in DenseMtx_setComplexEntry()" "\n jcol = %d, mtx->ncol = %d input\n", jcol, mtx->ncol) ; exit(-1) ; } if ( mtx->entries == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_setComplexEntry()" "\n mtx->entries is NULL \n") ; exit(-1) ; } loc = 2*(irow*mtx->inc1 + jcol*mtx->inc2) ; mtx->entries[loc] = real ; mtx->entries[loc+1] = imag ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- purpose -- fill *prowent with the base address of row irow return values -- 1 -- normal return -1 -- mtx is NULL -2 -- invalid type for mtx -3 -- irow is invalid -4 -- prowent is NULL created -- 98nov11, cca ---------------------------------------------------------- */ int DenseMtx_row ( DenseMtx *mtx, int irow, double **prowent ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n error in DenseMtx_row()" "\n mtx is NULL\n") ; return(-1) ; } if ( mtx->type != SPOOLES_REAL && mtx->type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n error in DenseMtx_row()" "\n invalid type %d\n", mtx->type) ; return(-2) ; } if ( irow < 0 || irow >= mtx->nrow ) { fprintf(stderr, "\n error in DenseMtx_row()" "\n %d rows, irow = %d\n", mtx->nrow, irow) ; return(-3) ; } if ( prowent == NULL ) { fprintf(stderr, "\n error in DenseMtx_row()" "\n prowent is NULL\n") ; return(-4) ; } if ( mtx->type == SPOOLES_REAL ) { *prowent = mtx->entries + irow*mtx->inc1 ; } else { *prowent = mtx->entries + 2*irow*mtx->inc1 ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- fill *pcolent with the base address of column jcol return values -- 1 -- normal return -1 -- mtx is NULL -2 -- invalid type for mtx -3 -- jcol is invalid -4 -- pcolent is NULL created -- 98nov11, cca ------------------------------------------------------------- */ int DenseMtx_column ( DenseMtx *mtx, int jcol, double **pcolent ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n error in DenseMtx_column()" "\n mtx is NULL\n") ; return(-1) ; } if ( mtx->type != SPOOLES_REAL && mtx->type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n error in DenseMtx_column()" "\n invalid type %d\n", mtx->type) ; return(-2) ; } if ( jcol < 0 || jcol >= mtx->ncol ) { fprintf(stderr, "\n error in DenseMtx_column()" "\n %d columns, jcol = %d\n", mtx->ncol, jcol) ; return(-3) ; } if ( pcolent == NULL ) { fprintf(stderr, "\n error in DenseMtx_column()" "\n pcolent is NULL\n") ; return(-4) ; } if ( mtx->type == SPOOLES_REAL ) { *pcolent = mtx->entries + jcol*mtx->inc2 ; } else { *pcolent = mtx->entries + 2*jcol*mtx->inc2 ; } return(1) ; } /*--------------------------------------------------------------------*/ heck the input --------------- */ if ( mtx == NULL || pnrow == NULL || prowind == NULL ) { fprDenseMtx/src/permute.c010064400020550007177000000060500656040644400162450ustar00clevecompmath00000400000006/* permute.c */ #include "../DenseMtx.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to permute the rows of an object created -- 98may02, cca ------------------------------------------- */ void DenseMtx_permuteRows ( DenseMtx *mtx, IV *oldToNewIV ) { A2 a2 ; int ii, irow, maxnrow, nrow ; int *oldToNew, *rowind ; /* --------------- check the input --------------- */ if ( mtx == NULL || oldToNewIV == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_permuteRows(%p,%p)" "\n bad input\n", mtx, oldToNewIV) ; exit(-1) ; } DenseMtx_rowIndices(mtx, &nrow, &rowind) ; if ( nrow <= 0 ) { return ; } /* ---------------------------------------------- overwrite the old row ids with the new row ids ---------------------------------------------- */ IV_sizeAndEntries(oldToNewIV, &maxnrow, &oldToNew) ; for ( ii = 0 ; ii < nrow ; ii++ ) { irow = rowind[ii] ; if ( irow < 0 || irow >= maxnrow ) { fprintf(stderr, "\n fatal error in DenseMtx_permuteRows(%p,%p)" "\n irow = %d, maxnrow = %d", mtx, oldToNewIV, irow, maxnrow) ; exit(-1) ; } rowind[ii] = oldToNew[rowind[ii]] ; } /* ------------------------------------ now sort the rows in ascending order ------------------------------------ */ A2_setDefaultFields(&a2) ; DenseMtx_setA2(mtx, &a2) ; A2_sortRowsUp(&a2, nrow, rowind) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to permute the columns of an object created -- 98may02, cca ---------------------------------------------- */ void DenseMtx_permuteColumns ( DenseMtx *mtx, IV *oldToNewIV ) { A2 a2 ; int ii, jcol, maxncol, ncol ; int *oldToNew, *colind ; /* --------------- check the input --------------- */ if ( mtx == NULL || oldToNewIV == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_permuteColumns(%p,%p)" "\n bad input\n", mtx, oldToNewIV) ; exit(-1) ; } DenseMtx_columnIndices(mtx, &ncol, &colind) ; if ( ncol <= 0 ) { return ; } /* ---------------------------------------------------- overwrite the old column ids with the new column ids ---------------------------------------------------- */ IV_sizeAndEntries(oldToNewIV, &maxncol, &oldToNew) ; for ( ii = 0 ; ii < ncol ; ii++ ) { jcol = colind[ii] ; if ( jcol < 0 || jcol >= maxncol ) { fprintf(stderr, "\n fatal error in DenseMtx_permuteColumns(%p,%p)" "\n jcol = %d, maxncol = %d", mtx, oldToNewIV, jcol, maxncol) ; exit(-1) ; } colind[ii] = oldToNew[jcol] ; } /* ------------------------------------ now sort the rows in ascending order ------------------------------------ */ A2_setDefaultFields(&a2) ; DenseMtx_setA2(mtx, &a2) ; A2_sortColumnsUp(&a2, ncol, colind) ; return ; } /*--------------------------------------------------------------------*/ DenseMtx/src/scale.c010064400020550007177000000072100662067743100156550ustar00clevecompmath00000400000006/* scale.c */ #include "../DenseMtx.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to scale a dense matrix object by a scalar A := alpha * A ; return values --- 1 -- normal return -1 -- A is NULL -2 -- A has invalid type -3 -- alpha is NULL created -- 98nov06, cca ----------------------------------------------------- */ int DenseMtx_scale ( DenseMtx *A, double alpha[] ) { /* --------------- check the input --------------- */ if ( A == NULL ) { fprintf(stderr, "\n error in DenseMtx_scale()" "\n A is NULL\n") ; return(-1) ; } if ( A->type != SPOOLES_REAL && A->type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n error in DenseMtx_scale()" "\n A has invalid type\n") ; return(-2) ; } if ( alpha == NULL ) { fprintf(stderr, "\n error in DenseMtx_scale()" "\n alpha is NULL\n") ; return(-3) ; } if ( A->type == SPOOLES_REAL ) { double ralpha = alpha[0] ; if ( ralpha == 1.0 ) { return(1) ; } else { double *entries ; int colinc, ncol, nrow, rowinc ; entries = DenseMtx_entries(A) ; rowinc = DenseMtx_rowIncrement(A) ; colinc = DenseMtx_columnIncrement(A) ; DenseMtx_dimensions(A, &nrow, &ncol) ; if ( (rowinc == 1 && colinc == nrow) || (rowinc == ncol && colinc == 1) ) { if ( ralpha == 0.0 ) { DVzero(nrow*ncol, entries) ; } else { DVscale(nrow*ncol, entries, ralpha) ; } } else { int ii, jj ; if ( ralpha == 0.0 ) { for ( jj = 0 ; jj < ncol ; jj++ ) { for ( ii = 0 ; ii < nrow ; ii++ ) { entries[ii*rowinc + jj*colinc] = 0.0 ; } } } else { for ( jj = 0 ; jj < ncol ; jj++ ) { for ( ii = 0 ; ii < nrow ; ii++ ) { entries[ii*rowinc + jj*colinc] *= ralpha ; } } } } } } else if ( A->type == SPOOLES_COMPLEX ) { double ralpha = alpha[0], ialpha = alpha[1] ; if ( ralpha == 1.0 && ialpha == 0.0 ) { return(1) ; } else { double *entries ; int colinc, ncol, nrow, rowinc ; entries = DenseMtx_entries(A) ; rowinc = DenseMtx_rowIncrement(A) ; colinc = DenseMtx_columnIncrement(A) ; DenseMtx_dimensions(A, &nrow, &ncol) ; if ( (rowinc == 1 && colinc == nrow) || (rowinc == ncol && colinc == 1) ) { if ( ralpha == 0.0 && ialpha == 0.0 ) { ZVzero(nrow*ncol, entries) ; } else { ZVscale(nrow*ncol, entries, ralpha, ialpha) ; } } else { if ( ralpha == 0.0 && ialpha == 0.0 ) { int ii, jj, off ; for ( jj = 0 ; jj < ncol ; jj++ ) { for ( ii = 0 ; ii < nrow ; ii++ ) { off = ii*rowinc + jj*colinc ; entries[2*off] = 0.0 ; entries[2*off+1] = 0.0 ; } } } else { double yi, yr ; int ii, jj, off ; for ( jj = 0 ; jj < ncol ; jj++ ) { for ( ii = 0 ; ii < nrow ; ii++ ) { off = ii*rowinc + jj*colinc ; yr = entries[2*off] ; yi = entries[2*off+1] ; entries[2*off] = yr * ralpha - yi * ialpha ; entries[2*off+1] = yr * ialpha - yi * ralpha ; } } } } } } return(1) ; } /*--------------------------------------------------------------------*/ DenseMtx/src/util.c010064400020550007177000000360170661222234600155420ustar00clevecompmath00000400000006/* util.c */ #include "../DenseMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- sort the rows so the row ids are in ascending order sort the columns so the column ids are in ascending order created -- 98may02, cca --------------------------------------------------------- */ void DenseMtx_sort ( DenseMtx *mtx ) { A2 a2 ; int ii, ncol, nrow, sortColumns, sortRows ; int *colind, *rowind ; /* ---------------- check the output ---------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_sort(%p)" "\n bad input\n", mtx) ; exit(-1) ; } DenseMtx_rowIndices(mtx, &nrow, &rowind) ; DenseMtx_columnIndices(mtx, &ncol, &colind) ; if ( nrow <= 0 || ncol <= 0 ) { return ; } sortRows = sortColumns = 0 ; for ( ii = 1 ; ii < nrow ; ii++ ) { if ( rowind[ii-1] > rowind[ii] ) { sortRows = 1 ; break ; } } for ( ii = 1 ; ii < ncol ; ii++ ) { if ( colind[ii-1] > colind[ii] ) { sortColumns = 1 ; break ; } } if ( sortRows == 0 && sortColumns == 0 ) { return ; } A2_setDefaultFields(&a2) ; DenseMtx_setA2(mtx, &a2) ; if ( sortRows == 1 ) { A2_sortRowsUp(&a2, nrow, rowind) ; } if ( sortColumns == 1 ) { A2_sortColumnsUp(&a2, ncol, colind) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- copy row irowA from mtxA into row irowB in mtxB created -- 98may02, cca ----------------------------------------------- */ void DenseMtx_copyRow ( DenseMtx *mtxB, int irowB, DenseMtx *mtxA, int irowA ) { double *rowA, *rowB ; int ii, inc2A, inc2B, iA, iB, ncol ; /* --------------- check the input --------------- */ if ( mtxB == NULL || irowB < 0 || irowB >= mtxB->nrow || mtxA == NULL || irowA < 0 || irowA >= mtxA->nrow || (ncol = mtxA->ncol) != mtxB->ncol ) { fprintf(stderr, "\n fatal error in DenseMtx_copyRow(%p,%d,%p,%d)" "\n bad input\n", mtxB, irowB, mtxA, irowA) ; exit(-1) ; } inc2A = mtxA->inc2 ; inc2B = mtxB->inc2 ; /* mtxB->rowind[irowB] = mtxA->rowind[irowA] ; */ if ( DENSEMTX_IS_REAL(mtxB) && DENSEMTX_IS_REAL(mtxA) ) { rowA = mtxA->entries + irowA*mtxA->inc1 ; rowB = mtxB->entries + irowB*mtxB->inc1 ; for ( ii = iA = iB = 0 ; ii < ncol ; ii++, iA += inc2A, iB += inc2B){ rowB[iB] = rowA[iA] ; } } else if ( DENSEMTX_IS_COMPLEX(mtxB) && DENSEMTX_IS_COMPLEX(mtxA) ) { rowA = mtxA->entries + 2*irowA*mtxA->inc1 ; rowB = mtxB->entries + 2*irowB*mtxB->inc1 ; for ( ii = iA = iB = 0 ; ii < ncol ; ii++, iA += inc2A, iB += inc2B){ rowB[2*iB] = rowA[2*iA] ; rowB[2*iB+1] = rowA[2*iA+1] ; } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- copy row irowA from mtxA into row irowB in mtxB and copy row index irowB from mtxB into row index irowA of mtxA created -- 98aug12, cca --------------------------------------------------------------- */ void DenseMtx_copyRowAndIndex ( DenseMtx *mtxB, int irowB, DenseMtx *mtxA, int irowA ) { /* --------------- check the input --------------- */ if ( mtxB == NULL || irowB < 0 || irowB >= mtxB->nrow || mtxA == NULL || irowA < 0 || irowA >= mtxA->nrow || mtxA->ncol != mtxB->ncol ) { fprintf(stderr, "\n fatal error in DenseMtx_copyRow(%p,%d,%p,%d)" "\n bad input\n", mtxB, irowB, mtxA, irowA) ; exit(-1) ; } DenseMtx_copyRow(mtxB, irowB, mtxA, irowA) ; mtxB->rowind[irowB] = mtxA->rowind[irowA] ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- add row irowA from mtxA into row irowB in mtxB created -- 98aug12, cca ---------------------------------------------- */ void DenseMtx_addRow ( DenseMtx *mtxB, int irowB, DenseMtx *mtxA, int irowA ) { double *rowA, *rowB ; int ii, inc2A, inc2B, iA, iB, ncol ; /* --------------- check the input --------------- */ if ( mtxB == NULL || irowB < 0 || irowB >= mtxB->nrow || mtxA == NULL || irowA < 0 || irowA >= mtxA->nrow || (ncol = mtxA->ncol) != mtxB->ncol ) { fprintf(stderr, "\n fatal error in DenseMtx_addRow(%p,%d,%p,%d)" "\n bad input\n", mtxB, irowB, mtxA, irowA) ; exit(-1) ; } inc2A = mtxA->inc2 ; inc2B = mtxB->inc2 ; if ( DENSEMTX_IS_REAL(mtxB) && DENSEMTX_IS_REAL(mtxA) ) { rowA = mtxA->entries + irowA*mtxA->inc1 ; rowB = mtxB->entries + irowB*mtxB->inc1 ; for ( ii = iA = iB = 0 ; ii < ncol ; ii++, iA += inc2A, iB += inc2B){ rowB[iB] += rowA[iA] ; } } else if ( DENSEMTX_IS_COMPLEX(mtxB) && DENSEMTX_IS_COMPLEX(mtxA) ) { rowA = mtxA->entries + 2*irowA*mtxA->inc1 ; rowB = mtxB->entries + 2*irowB*mtxB->inc1 ; for ( ii = iA = iB = 0 ; ii < ncol ; ii++, iA += inc2A, iB += inc2B){ rowB[2*iB] += rowA[2*iA] ; rowB[2*iB+1] += rowA[2*iA+1] ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------- zero the entries created -- 98may16, cca ----------------------- */ void DenseMtx_zero ( DenseMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_zero(%p)" "\n bad input\n", mtx) ; exit(-1) ; } if ( DENSEMTX_IS_REAL(mtx) ) { DVzero(mtx->nrow*mtx->ncol, mtx->entries) ; } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { DVzero(2*mtx->nrow*mtx->ncol, mtx->entries) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------ fill with random entries created -- 98may16, cca ------------------------ */ void DenseMtx_fillRandomEntries ( DenseMtx *mtx, Drand *drand ) { /* --------------- check the input --------------- */ if ( mtx == NULL || drand == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_fillRandomEntries(%p,%p)" "\n bad input\n", mtx, drand) ; exit(-1) ; } if ( DENSEMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, mtx->nrow*mtx->ncol, mtx->entries) ; } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*mtx->nrow*mtx->ncol, mtx->entries) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- compute three checksums sums[0] = sum of row indices sums[1] = sum of columns indices sums[2] = sum of entry magnitudes created -- 98may16, cca ----------------------------------- */ void DenseMtx_checksums ( DenseMtx *mtx, double sums[] ) { double *entries ; int ii, ncol, nent, nrow ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( mtx == NULL || sums == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_checksums(%p,%p)" "\n bad input\n", mtx, sums) ; exit(-1) ; } sums[0] = sums[1] = sums[2] = 0.0 ; DenseMtx_rowIndices(mtx, &nrow, &rowind) ; for ( ii = 0 ; ii < nrow ; ii++ ) { sums[0] += rowind[ii] ; } DenseMtx_columnIndices(mtx, &ncol, &colind) ; for ( ii = 0 ; ii < ncol ; ii++ ) { sums[1] += colind[ii] ; } entries = DenseMtx_entries(mtx) ; nent = nrow*ncol ; if ( DENSEMTX_IS_REAL(mtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { sums[2] += fabs(entries[ii]) ; } } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { sums[2] += Zabs(entries[2*ii], entries[2*ii+1]) ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- return the maximum magnitude of the entries created -- 98may15, cca ------------------------------------------- */ double DenseMtx_maxabs ( DenseMtx *mtx ) { double maxabs ; int loc ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_maxabs(%p)" "\n bad input\n", mtx) ; exit(-1) ; } if ( DENSEMTX_IS_REAL(mtx) ) { maxabs = DVmaxabs(mtx->nrow*mtx->ncol, mtx->entries, &loc) ; } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { maxabs = ZVmaxabs(mtx->nrow*mtx->ncol, mtx->entries) ; } else { fprintf(stderr, "\n fatal error in DenseMtx_maxabs(%p)" "\n bad type %d\n", mtx, mtx->type) ; exit(-1) ; } return(maxabs) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- subtract one matrix from another, B := B - A created -- 98may25, cca -------------------------------------------- */ void DenseMtx_sub ( DenseMtx *mtxB, DenseMtx *mtxA ) { /* --------------- check the input --------------- */ if ( mtxB == NULL || mtxA == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_sub(%p,%p)" "\n bad input\n", mtxB, mtxA) ; exit(-1) ; } if ( mtxB->type != mtxA->type ) { fprintf(stderr, "\n fatal error in DenseMtx_sub(%p,%p)" "\n mtxB->type = %d, mtxA->type = %d\n", mtxB, mtxA, mtxB->type, mtxA->type) ; exit(-1) ; } if ( mtxB->nrow != mtxA->nrow ) { fprintf(stderr, "\n fatal error in DenseMtx_sub(%p,%p)" "\n mtxB->nrow = %d, mtxA->nrow = %d\n", mtxB, mtxA, mtxB->nrow, mtxA->nrow) ; exit(-1) ; } if ( mtxB->ncol != mtxA->ncol ) { fprintf(stderr, "\n fatal error in DenseMtx_sub(%p,%p)" "\n mtxB->ncol = %d, mtxA->ncol = %d\n", mtxB, mtxA, mtxB->ncol, mtxA->ncol) ; exit(-1) ; } if ( mtxB->entries == NULL || mtxA->entries == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_sub(%p,%p)" "\n mtxB->entries = %p, mtxA->entries = %p\n", mtxB, mtxA, mtxB->entries, mtxA->entries) ; exit(-1) ; } if ( DENSEMTX_IS_REAL(mtxB) ) { DVsub(mtxB->nrow*mtxB->ncol, mtxB->entries, mtxA->entries) ; } else if ( DENSEMTX_IS_COMPLEX(mtxB) ) { ZVsub(mtxB->nrow*mtxB->ncol, mtxB->entries, mtxA->entries) ; } else { fprintf(stderr, "\n fatal error in DenseMtx_sub(%p,%p)" "\n mtxB->type = %d, mtxA->type = %d\n", mtxB, mtxA, mtxB->type, mtxA->type) ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to copy a row of the matrix into a vector irow -- local row id vec -- double vector to receive the row entries created -- 98jul31, cca ---------------------------------------------------- */ void DenseMtx_copyRowIntoVector ( DenseMtx *mtx, int irow, double *vec ) { double *entries ; int inc1, inc2, jcol, jj, kk, nrow, ncol ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( mtx == NULL || irow < 0 || vec == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_copyRowIntoVector()" "\n bad input\n") ; exit(-1) ; } DenseMtx_rowIndices(mtx, &nrow, &rowind) ; if ( irow >= nrow ) { fprintf(stderr, "\n fatal error in DenseMtx_copyRowIntoVector()" "\n irow = %d, nrow = %d\n", irow, nrow) ; exit(-1) ; } DenseMtx_columnIndices(mtx, &ncol, &colind) ; inc1 = DenseMtx_rowIncrement(mtx) ; inc2 = DenseMtx_columnIncrement(mtx) ; entries = DenseMtx_entries(mtx) ; if ( DENSEMTX_IS_REAL(mtx) ) { for ( jcol = jj = 0, kk = irow*inc1 ; jcol < ncol ; jcol++, jj++, kk += inc2 ) { vec[jj] = entries[kk] ; } } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { for ( jcol = jj = 0, kk = irow*inc1 ; jcol < ncol ; jcol++, jj++, kk += inc2 ) { vec[2*jj] = entries[2*kk] ; vec[2*jj+1] = entries[2*kk+1] ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to copy a row of the matrix into a vector irow -- local row id vec -- double vector to supply the row entries created -- 98jul31, cca ---------------------------------------------------- */ void DenseMtx_copyVectorIntoRow ( DenseMtx *mtx, int irow, double *vec ) { double *entries ; int inc1, inc2, jcol, jj, kk, nrow, ncol ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( mtx == NULL || irow < 0 || vec == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_copyVectorIntoRow()" "\n bad input, mtx %p, irow %d, vec %p\n", mtx, irow, vec) ; exit(-1) ; } DenseMtx_rowIndices(mtx, &nrow, &rowind) ; if ( irow >= nrow ) { fprintf(stderr, "\n fatal error in DenseMtx_copyVectorIntoRow()" "\n irow = %d, nrow = %d\n", irow, nrow) ; exit(-1) ; } DenseMtx_columnIndices(mtx, &ncol, &colind) ; inc1 = DenseMtx_rowIncrement(mtx) ; inc2 = DenseMtx_columnIncrement(mtx) ; entries = DenseMtx_entries(mtx) ; if ( DENSEMTX_IS_REAL(mtx) ) { for ( jcol = jj = 0, kk = irow*inc1 ; jcol < ncol ; jcol++, jj++, kk += inc2 ) { entries[kk] = vec[jj] ; } } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { for ( jcol = jj = 0, kk = irow*inc1 ; jcol < ncol ; jcol++, jj++, kk += inc2 ) { entries[2*kk] = vec[2*jj] ; entries[2*kk+1] = vec[2*jj+1] ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to add a row of the matrix into a vector irow -- local row id vec -- double vector to supply the row entries created -- 98aug12, cca ---------------------------------------------------- */ void DenseMtx_addVectorIntoRow ( DenseMtx *mtx, int irow, double *vec ) { double *entries ; int inc1, inc2, jcol, jj, kk, nrow, ncol ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( mtx == NULL || irow < 0 || vec == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_addVectorIntoRow()" "\n bad input, mtx %p, irow %d, vec %p\n", mtx, irow, vec) ; exit(-1) ; } DenseMtx_rowIndices(mtx, &nrow, &rowind) ; if ( irow >= nrow ) { fprintf(stderr, "\n fatal error in DenseMtx_addVectorIntoRow()" "\n irow = %d, nrow = %d\n", irow, nrow) ; exit(-1) ; } DenseMtx_columnIndices(mtx, &ncol, &colind) ; inc1 = DenseMtx_rowIncrement(mtx) ; inc2 = DenseMtx_columnIncrement(mtx) ; entries = DenseMtx_entries(mtx) ; if ( DENSEMTX_IS_REAL(mtx) ) { for ( jcol = jj = 0, kk = irow*inc1 ; jcol < ncol ; jcol++, jj++, kk += inc2 ) { entries[kk] += vec[jj] ; } } else if ( DENSEMTX_IS_COMPLEX(mtx) ) { for ( jcol = jj = 0, kk = irow*inc1 ; jcol < ncol ; jcol++, jj++, kk += inc2 ) { entries[2*kk] += vec[2*jj] ; entries[2*kk+1] += vec[2*jj+1] ; } } return ; } /*--------------------------------------------------------------------*/ *iB] += rowA[2*iA] ; rowB[2*iB+1] += rowA[2*iA+1] ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------- zero the entries created -- 98may16, cca ----------------------- */ void DenseMtx_zero ( DenseMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_zero(%p)" "\n bad input\n", mtx) ; exit(-1) ; } DenseMtx/doc/004275500020550007177000000000000662342176500144055ustar00clevecompmath00000400000006DenseMtx/doc/dataStructure.tex010064400020550007177000000026610656040644400177560ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:DenseMtx:dataStructure} \par \par The {\tt DenseMtx} structure has the following fields. \begin{itemize} \item {\tt int type} : type of entries, {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. \item {\tt int rowid} : object's row id, default value is {\tt -1}. \item {\tt int colid} : object's column id, default value is {\tt -1}. \item {\tt int nrow} : number of rows \item {\tt int ncol} : number of columns \item {\tt int inc1} : row increment, difference in addresses between entries in the same column \item {\tt int inc2} : column increment, difference in addresses between entries in the same row \item {\tt int *rowind} : pointer to the base address of the {\tt int} vector that contains row indices. \item {\tt int *colind} : pointer to the base address of the {\tt int} vector that contains column indices. \item {\tt double *entries} : pointer to the base address of the {\tt double} vector that contains the entries. \item {\tt DV wrkDV} : object that manages the owned working storage. \item {\tt DenseMtx *next} : link to a next object in a singly linked list. \end{itemize} \par One can query the type of entries via two macros. \begin{itemize} \item {\tt DENSEMTX\_IS\_REAL(mtx)} returns {\tt 1} if the matrix has real entries, and {\tt 0} otherwise. \item {\tt DENSEMTX\_IS\_COMPLEX(mtx)} returns {\tt 1} if the matrix has complex entries, and {\tt 0} otherwise. \end{itemize} DenseMtx/doc/intro.tex010064400020550007177000000016000656040644400162470ustar00clevecompmath00000400000006\par \chapter{{\tt DenseMtx}: Dense matrix object} \par The {\tt DenseMtx} object contains a dense matrix along with row and column indices. The entries in the matrix can be double precision real or double precision complex. It needs to be able to manage its own storage, much like the {\tt Chv} and {\tt SubMtx} objects that are used during the factor and solves, so we include this capability via a contained {\tt DV} object. A {\tt DenseMtx} object may also be found in a list, so there is a {\tt next} field that points to another {\tt DenseMtx} object. \par The {\tt DenseMtx} object also exists in an MPI environment, where it holds the solution and right hand side matrices. Since each of these two matrices is distributed, a processor {\it owns} only part of the global matrix, and so the need for row and column indices to specify which rows and columns are present on which processor. DenseMtx/doc/main.tex010064400020550007177000000011320662233046500160360ustar00clevecompmath00000400000006% % main TeX file % \documentclass[10pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \newcommand{\bnd}{{\partial}} \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt DenseMtx} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt DenseMtx} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} ght 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \newcommand{\bnd}{{\partial}} \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt DenseMtx} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt DenseMtx} : {\it DRAFT} \quad \today \hrulefill} \par \iDenseMtx/doc/proto.tex010064400020550007177000000734170662234570000162720ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt DenseMtx} methods} \label{section:DenseMtx:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt DenseMtx} object. \par \subsection{Basic methods} \label{subsection:DenseMtx:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} DenseMtx * DenseMtx_new ( void ) ; \end{verbatim} \index{DenseMtx_new@{\tt DenseMtx\_new()}} This method simply allocates storage for the {\tt DenseMtx} structure and then sets the default fields by a call to {\tt DenseMtx\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_setDefaultFields ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_setDefaultFields@{\tt DenseMtx\_setDefaultFields()}} The structure's fields are set to default values: {\tt type} = {\tt SPOOLES\_REAL}, {\tt rowid} = {\tt colid} = {\tt -1}, {\tt nrow} = {\tt ncol} = {\tt inc1} = {\tt inc2} = 0 and {\tt rowind} = {\tt colind} = {\tt entries} = {\tt next} = {\tt NULL} . The {\tt wrkDV} object has its default fields set via a call to {\tt DV\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_clearData ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_clearData@{\tt DenseMtx\_clearData()}} This method clears the object and free's any owned data by invoking the {\tt \_clearData()} methods for its internal {\tt DV} object. There is a concluding call to {\tt DenseMtx\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_free ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_free@{\tt DenseMtx\_free()}} This method releases any storage by a call to {\tt DenseMtx\_clearData()} and then free the space for {\tt mtx}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:DenseMtx:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_rowid ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_rowid@{\tt DenseMtx\_rowid()}} This method returns the {\it rowid} field of the object. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_colid ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_colid@{\tt DenseMtx\_colid()}} This method returns the {\it colid} field of the object. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_dimensions ( DenseMtx *mtx, int *pnrow, int *pncol ) ; \end{verbatim} \index{DenseMtx_dimensions@{\tt DenseMtx\_dimensions()}} This method fills {\tt *pnrow} and {\tt *pncol} with {\tt nrow} and {\tt ncol}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_columnIncrement ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_columnIncrement@{\tt DenseMtx\_columnIncrement()}} This method returns the row increment of the object, the difference in memory locations of two entries in consecutive columns in the same row. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_rowIncrement ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_rowIncrement@{\tt DenseMtx\_rowIncrement()}} This method returns the row increment of the object, the difference in memory locations of two entries in consecutive rows in the same column. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_rowIndices ( DenseMtx *mtx, int *pnrow, **prowind ) ; \end{verbatim} \index{DenseMtx_rowIndices@{\tt DenseMtx\_rowIndices()}} This method fills {\tt *pnrow} with {\tt nrow}, the number of rows, and {\tt *prowind} with {\tt rowind}, a pointer to the row indices. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pnrow} or {\tt prowind} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_columnIndices ( DenseMtx *mtx, int *pncol, **colind ) ; \end{verbatim} \index{DenseMtx_columnIndices@{\tt DenseMtx\_columnIndices()}} This method fills {\tt *pncol} with {\tt ncol}, the number of columns, and {\tt *pcolind} with {\tt colind}, a pointer to the column indices. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pncol} or {\tt pcolind} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double * DenseMtx_entries ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_entries@{\tt DenseMtx\_entries()}} This method returns the {\it entries} field of the object. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void * DenseMtx_workspace ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_workspace@{\tt DenseMtx\_workspace()}} This method returns a pointer to the base address of the object's workspace. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_realEntry ( DenseMtx *mtx, int irow, int jcol, double *pValue ) ; \end{verbatim} \index{DenseMtx_realEntry@{\tt DenseMtx\_realEntry()}} This method fills {\tt *pValue} with the entry in row {\tt irow} and column {\tt jcol}. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt pValue} is {\tt NULL}, or if the matrix is not real, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_complexEntry ( DenseMtx *mtx, int irow, int jcol, double *pReal, double *pImag ) ; \end{verbatim} \index{DenseMtx_complexEntry@{\tt DenseMtx\_complexEntry()}} This method fills {\tt *pReal} with the real part and {\tt *pImag} with the imaginary part of the the entry in row {\tt irow} and column {\tt jcol}. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pReal} or {\tt pImag} is {\tt NULL}, or if the matrix is not complex, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_setRealEntry ( DenseMtx *mtx, int irow, int jcol, double value) ; \end{verbatim} \index{DenseMtx_setRealEntry@{\tt DenseMtx\_setRealEntry()}} This method sets the entry in row {\tt irow} and column {\tt jcol} to be {\tt value}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if the matrix is not real, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_setComplexEntry ( DenseMtx *mtx, int irow, int jcol, double real, double imag ) ; \end{verbatim} \index{DenseMtx_setComplexEntry@{\tt DenseMtx\_setComplexEntry()}} This method sets the real and imaginary parts of the entry in row {\tt irow} and column {\tt jcol} to be {\tt (real,imag)}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if the matrix is not complex, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_row ( DenseMtx *mtx, int irow, double **prowent ) ; \end{verbatim} \index{DenseMtx_row@{\tt DenseMtx\_row()}} This method fills {\tt *prowent} with the first location of the entries in row {\tt irow}. \par \noindent {\it Return codes:} {\tt 1} is a normal return, {\tt -1} means {\tt mtx} is {\tt NULL}, {\tt -2} means invalid type for {\tt mtx}, {\tt -3} means {\tt irow} is out-of-range, {\tt -4} means {\tt prowent} is {\tt NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_column ( DenseMtx *mtx, int jcol, double **pcolent ) ; \end{verbatim} \index{DenseMtx_column@{\tt DenseMtx\_column()}} This method fills {\tt *pcolent} with the first location of the entries in column {\tt jcol}. \par \noindent {\it Return codes:} {\tt 1} is a normal return, {\tt -1} means {\tt mtx} is {\tt NULL}, {\tt -2} means invalid type for {\tt mtx}, {\tt -3} means {\tt jcol} is out-of-range, {\tt -4} means {\tt pcolent} is {\tt NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization methods} \label{subsection:DenseMtx:proto:initial} \par There are three initializer methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_init( DenseMtx *mtx, int type, int rowid, int colid, int nrow, int ncol, int inc1, int inc2 ) ; \end{verbatim} \index{DenseMtx_init@{\tt DenseMtx\_init()}} This is the initializer method used when the {\tt DenseMtx} object is to use its workspace to store indices and entries. The number of bytes required in the workspace is computed, the workspace is resized if necessary, and the scalar and pointer fields are set. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if {\tt type} is neither {\tt SPOOLES\_REAL} nor {\tt SPOOLES\_COMPLEX}, or if {\tt nrow}, {\tt ncol}, {\tt inc1} or {\tt inc2} is less than or equal to zero, or if neither {\tt inc1} nor {\tt inc2} are {\tt 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_initWithPointers ( DenseMtx *mtx, int type, int rowid, int colid, int nD, int nL, int nU, int *rowind, int *colind, double *entries ) ; \end{verbatim} \index{DenseMtx_initWithPointers@{\tt DenseMtx\_initWithPointers()}} This is the initializer method used when the {\tt DenseMtx} object does not own the storage for its indices and entries, but points into some other storage. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if {\tt type} is neither {\tt SPOOLES\_REAL} nor {\tt SPOOLES\_COMPLEX}, or if {\tt nrow}, {\tt ncol}, {\tt inc1} or {\tt inc2} is less than or equal to zero, or if neither {\tt inc1} nor {\tt inc2} are {\tt 1}, or if {\tt rowind}, {\tt colind} or {\tt entries} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_initAsSubmatrix ( DenseMtx *B, DenseMtx *A, int firstrow, int lastrow, int firstcol, int lastcol ) ; \end{verbatim} \index{DenseMtx_initAsSubmatrix@{\tt DenseMtx\_initAsSubmatrix()}} This method initializes {\tt B} to contain rows {\tt firstrow:lastrow} and columns {\tt firstcol:lastcol} of {\tt A}. Note, the {\tt rowind}, {\tt colind} and {\tt entries} fields of {\tt B} point into the indices and entries for {\tt A}. \par \noindent {\it Return codes:} {\tt 1} is the normal return, {\tt -1} means {\tt B} is {\tt NULL}, {\tt -2} means {\tt A} is {\tt NULL}, {\tt -3} means {\tt A} has invalid type \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & {\tt B} is {\tt NULL} \\ -2 & {\tt A} is {\tt NULL} \end{tabular} \begin{tabular}{ll} -3 & {\tt A} has invalid type \\ -4 & requested rows are out-of-range \\ -5 & requested columns are out-of-range \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_initFromBuffer ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_initFromBuffer@{\tt DenseMtx\_initFromBuffer()}} This method initializes the object using information present in the workspace buffer. This method is used to initialize the {\tt DenseMtx} object when it has been received as an MPI message. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_setA2 ( DenseMtx *mtx, A2 *a2 ) ; \end{verbatim} \index{DenseMtx_setA2@{\tt DenseMtx\_setA2()}} This method initializes the {\tt a2} object to point into the entries of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt a2} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:DenseMtx:proto:utility} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_nbytesNeeded ( int type, int nrow, int ncol ) ; \end{verbatim} \index{DenseMtx_nbytesNeeded@{\tt DenseMtx\_nbytesNeeded()}} \par This method returns the number of bytes required to store the object's information in its buffer. \par \noindent {\it Error checking:} If {\tt type} is neither {\tt SPOOLES\_REAL} nor {\tt SPOOLES\_COMPLEX}, or if {\tt nrow} or {\tt ncol} is less than zero, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_nbytesInWorkspace ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_nbytesInWorkspace@{\tt DenseMtx\_nbytesInWorkspace()}} \par This method returns the number of bytes in the workspace owned by this object. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_setNbytesInWorkspace ( DenseMtx *mtx, int nbytes ) ; \end{verbatim} \index{DenseMtx_setNbytesInWorkspace@{\tt DenseMtx\_setNbytesInWorkspace()}} \par This method sets the number of bytes in the workspace of this object. If {\tt nbytes} is less than the present number of bytes, the workspace is not resized. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_setFields( DenseMtx *mtx, int type, int rowid, int colid, int nrow, int ncol, int inc1, int inc2 ) ; \end{verbatim} \index{DenseMtx_setFields@{\tt DenseMtx\_setFields()}} This method sets the scalar and pointer fields. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if {\tt type} is neither {\tt SPOOLES\_REAL} nor {\tt SPOOLES\_COMPLEX}, or if {\tt nrow}, {\tt ncol}, {\tt inc1} or {\tt inc2} is less than or equal to zero, or if neither {\tt inc1} nor {\tt inc2} are {\tt 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_permuteRows ( DenseMtx *mtx, IV *oldToNewIV ) ; void DenseMtx_permuteColumns ( DenseMtx *mtx, IV *oldToNewIV ) ; \end{verbatim} \index{DenseMtx_permuteRows@{\tt DenseMtx\_permuteRows()}} \index{DenseMtx_permuteColumns@{\tt DenseMtx\_permuteColumns()}} These methods permute the rows or columns using an old-to-new permutation vector. The row or column ids are overwritten using the permutation vector, and then the rows or columns are sorted into ascending order. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt oldToNewIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_sort ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_sort@{\tt DenseMtx\_sort()}} This method sort the rows so the row ids are in ascending order and sorts the columns so the column ids are in ascending order. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_copyRow ( DenseMtx *mtxB, int irowB, DenseMtx *mtxA, int irowA ) ; \end{verbatim} \index{DenseMtx_copyRow@{\tt DenseMtx\_copyRow()}} This method copies row {\tt irowA} from matrix {\tt mtxA} into row {\tt irowB} of matrix {\tt mtxB}. \par \noindent {\it Error checking:} If {\tt mtxB} is {\tt NULL}, or if {\tt irowB} is out of range, or if {\tt mtxA} is {\tt NULL}, or if {\tt irowA} is out of range, or if the number of columns in {\tt mtxB} and {\tt mtxA} are not the same, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_copyRowAndIndex ( DenseMtx *mtxB, int irowB, DenseMtx *mtxA, int irowA ) ; \end{verbatim} \index{DenseMtx_copyRowAndIndex@{\tt DenseMtx\_copyRowAndIndex()}} This method copies row {\tt irowA} from matrix {\tt mtxA} into row {\tt irowB} of matrix {\tt mtxB}, and copies the index of row {\tt irowA} of {\tt mtxA} into location {\tt irowB} of the row indices for {\tt mtxB}. \par \noindent {\it Error checking:} If {\tt mtxB} is {\tt NULL}, or if {\tt irowB} is out of range, or if {\tt mtxA} is {\tt NULL}, or if {\tt irowA} is out of range, or if the number of columns in {\tt mtxB} and {\tt mtxA} are not the same, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_addRow ( DenseMtx *mtxB, int irowB, DenseMtx *mtxA, int irowA ) ; \end{verbatim} \index{DenseMtx_addRow@{\tt DenseMtx\_addRow()}} This method adds row {\tt irowA} from matrix {\tt mtxA} into row {\tt irowB} of matrix {\tt mtxB}. \par \noindent {\it Error checking:} If {\tt mtxB} is {\tt NULL}, or if {\tt irowB} is out of range, or if {\tt mtxA} is {\tt NULL}, or if {\tt irowA} is out of range, or if the number of columns in {\tt mtxB} and {\tt mtxA} are not the same, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_zero ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_zero@{\tt DenseMtx\_zero()}} This method zeros the entries in the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_fillRandomEntries ( DenseMtx *mtx, Drand *drand ) ; \end{verbatim} \index{DenseMtx_fillRandomEntries@{\tt DenseMtx\_fillRandomEntries()}} This method the entries in the matrix with random numbers using the {\tt drand} object. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt drand} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_checksums ( DenseMtx *mtx, double sums[3] ) ; \end{verbatim} \index{DenseMtx_checksums@{\tt DenseMtx\_checksums()}} This method fills {\tt sums[0]} with the sum of the row indices, {\tt sums[1]} with the sum of the column indices, and {\tt sums[2]} with the sum of the magnitudes of the entries. This method is used to check the MPI method where a distributed matrix is re-distributed. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt sums} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_scale ( DenseMtx *mtx, double alpha[] ) ; \end{verbatim} \index{DenseMtx_scale@{\tt DenseMtx\_scale()}} This method scales the entries in {\tt mtx} by {\tt alpha}. \par \noindent {\it Return values:} 1 for a normal return, -1 if {\tt mtx} is NULL, -2 if {\tt mtx} has an invalid type, -3 if {\tt alpha} is NULL. %----------------------------------------------------------------------- \item \begin{verbatim} double DenseMtx_maxabs ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_maxabs@{\tt DenseMtx\_maxabs()}} This method returns the entry of maximum magnitude of the entries. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double DenseMtx_sub ( DenseMtx *mtxB, *DenseMtx *mtxA ) ; \end{verbatim} \index{DenseMtx_sub@{\tt DenseMtx\_sub()}} This method subtracts matrix {\tt mtxA} from {\tt mtxB} . \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double DenseMtx_copyRowIntoVector ( DenseMtx *mtx, int irow, double vec[] ) ; \end{verbatim} \index{DenseMtx_copyRowIntoVector@{\tt DenseMtx\_copyRowIntoVector()}} This method copies row {\tt irow} of matrix {\tt mtx} into vector {\tt vec[]}. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt vec} is {\tt NULL}, or if ${\tt irow} < 0$ or ${\tt irow} \ge {\tt nrow}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double DenseMtx_copyVectorIntoRow ( DenseMtx *mtx, int irow, double vec[] ) ; \end{verbatim} \index{DenseMtx_copyVectorIntoRow@{\tt DenseMtx\_copyVectorIntoRow()}} This method copies vector {\tt vec[]} into row {\tt irow} of matrix {\tt mtx}. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt vec} is {\tt NULL}, or if ${\tt irow} < 0$ or ${\tt irow} \ge {\tt nrow}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double DenseMtx_addVectorIntoRow ( DenseMtx *mtx, int irow, double vec[] ) ; \end{verbatim} \index{DenseMtx_addVectorIntoRow@{\tt DenseMtx\_addVectorIntoRow()}} This method adds vector {\tt vec[]} into row {\tt irow} of matrix {\tt mtx}. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt vec} is {\tt NULL}, or if ${\tt irow} < 0$ or ${\tt irow} \ge {\tt nrow}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:DenseMtx:proto:IO} \par The file structure of a {\tt DenseMtx} object is simple. First comes seven scalars, {\tt type}, {\tt rowid}, {\tt colid}, {\tt nrow}, {\tt ncol}, {\tt inc1} and {\tt inc2}, followed by the row indices, followed by the column indices, and then followed by the matrix entries. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_readFromFile ( DenseMtx *mtx, char *fn ) ; \end{verbatim} \index{DenseMtx_readFromFile@{\tt DenseMtx\_readFromFile()}} \par This method reads an {\tt DenseMtx} object from a file. If the the file can be opened successfully, the method calls {\tt DenseMtx\_readFromFormattedFile()} or {\tt DenseMtx\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.densemtxf} (for a formatted file) or {\tt *.densemtxb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_readFromFormattedFile ( DenseMtx *mtx, FILE *fp ) ; \end{verbatim} \index{DenseMtx_readFromFormattedFile@{\tt DenseMtx\_readFromFormattedFile()}} \par This method reads an {\tt DenseMtx} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_readFromBinaryFile ( DenseMtx *mtx, FILE *fp ) ; \end{verbatim} \index{DenseMtx_readFromBinaryFile@{\tt DenseMtx\_readFromBinaryFile()}} \par This method reads an {\tt DenseMtx} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_writeToFile ( DenseMtx *mtx, char *fn ) ; \end{verbatim} \index{DenseMtx_writeToFile@{\tt DenseMtx\_writeToFile()}} \par This method writes an {\tt DenseMtx} object to a file. If the the file can be opened successfully, the method calls {\tt DenseMtx\_writeFromFormattedFile()} or {\tt DenseMtx\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.densemtxf} (for a formatted file) or {\tt *.densemtxb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_writeToFormattedFile ( DenseMtx *mtx, FILE *fp ) ; \end{verbatim} \index{DenseMtx_writeToFormattedFile@{\tt DenseMtx\_writeToFormattedFile()}} \par This method writes an {\tt DenseMtx} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_writeToBinaryFile ( DenseMtx *mtx, FILE *fp ) ; \end{verbatim} \index{DenseMtx_writeToBinaryFile@{\tt DenseMtx\_writeToBinaryFile()}} \par This method writes an {\tt DenseMtx} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_writeStats ( DenseMtx *mtx, FILE *fp ) ; \end{verbatim} \index{DenseMtx_writeStats@{\tt DenseMtx\_writeStats()}} \par This method writes out a header and statistics to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_writeForHumanEye ( DenseMtx *mtx, FILE *fp ) ; \end{verbatim} \index{DenseMtx_writeForHumanEye@{\tt DenseMtx\_writeForHumanEye()}} \par This method writes a {\tt DenseMtx} object to a file in an easily readable format. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_writeForMatlab ( DenseMtx *mtx, char *mtxname, FILE *fp ) ; \end{verbatim} \index{DenseMtx_writeForMatlab@{\tt DenseMtx\_writeForMatlab()}} \par This method writes out a {\tt DenseMtx} object to a file in a Matlab format. A sample line is \begin{verbatim} a(10,5) = -1.550328201511e-01 + 1.848033378871e+00*i ; \end{verbatim} for complex matrices, or \begin{verbatim} a(10,5) = -1.550328201511e-01 ; \end{verbatim} for real matrices, where mtxname = {\tt "a"}. The matrix indices come from the {\tt rowind[]} and {\tt colind[]} vectors, and are incremented by one to follow the Matlab and FORTRAN convention. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt mtxname} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} he matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_fillDenseMtx/doc/main.log010064400020550007177000000052510662335732100160260ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 14 NOV 1998 11:49 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. (intro.tex Chapter 1. ) (dataStructure.tex LaTeX Font Info: Try loading font information for OMS+cmr on input line 9. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 9. ) (proto.tex [1 ] [2] [3] LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 325. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 325. [4] [5] [6] [7]) (main.ind [8] [9 ]) (main.aux) ) Here is how much of TeX's memory you used: 512 strings out of 10908 5200 string characters out of 72189 53614 words of memory out of 262141 3436 multiletter control sequences out of 9500 7603 words of font info for 29 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 23i,6n,21p,158b,399s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (9 pages, 30248 bytes). DenseMtx/doc/main.idx010064400020550007177000000066460662335732100160420ustar00clevecompmath00000400000006\indexentry{DenseMtx_new@{\tt DenseMtx\_new()}}{2} \indexentry{DenseMtx_setDefaultFields@{\tt DenseMtx\_setDefaultFields()}}{2} \indexentry{DenseMtx_clearData@{\tt DenseMtx\_clearData()}}{2} \indexentry{DenseMtx_free@{\tt DenseMtx\_free()}}{2} \indexentry{DenseMtx_rowid@{\tt DenseMtx\_rowid()}}{2} \indexentry{DenseMtx_colid@{\tt DenseMtx\_colid()}}{2} \indexentry{DenseMtx_dimensions@{\tt DenseMtx\_dimensions()}}{2} \indexentry{DenseMtx_columnIncrement@{\tt DenseMtx\_columnIncrement()}}{2} \indexentry{DenseMtx_rowIncrement@{\tt DenseMtx\_rowIncrement()}}{3} \indexentry{DenseMtx_rowIndices@{\tt DenseMtx\_rowIndices()}}{3} \indexentry{DenseMtx_columnIndices@{\tt DenseMtx\_columnIndices()}}{3} \indexentry{DenseMtx_entries@{\tt DenseMtx\_entries()}}{3} \indexentry{DenseMtx_workspace@{\tt DenseMtx\_workspace()}}{3} \indexentry{DenseMtx_realEntry@{\tt DenseMtx\_realEntry()}}{3} \indexentry{DenseMtx_complexEntry@{\tt DenseMtx\_complexEntry()}}{3} \indexentry{DenseMtx_setRealEntry@{\tt DenseMtx\_setRealEntry()}}{3} \indexentry{DenseMtx_setComplexEntry@{\tt DenseMtx\_setComplexEntry()}}{3} \indexentry{DenseMtx_row@{\tt DenseMtx\_row()}}{4} \indexentry{DenseMtx_column@{\tt DenseMtx\_column()}}{4} \indexentry{DenseMtx_init@{\tt DenseMtx\_init()}}{4} \indexentry{DenseMtx_initWithPointers@{\tt DenseMtx\_initWithPointers()}}{4} \indexentry{DenseMtx_initAsSubmatrix@{\tt DenseMtx\_initAsSubmatrix()}}{4} \indexentry{DenseMtx_initFromBuffer@{\tt DenseMtx\_initFromBuffer()}}{4} \indexentry{DenseMtx_setA2@{\tt DenseMtx\_setA2()}}{4} \indexentry{DenseMtx_nbytesNeeded@{\tt DenseMtx\_nbytesNeeded()}}{5} \indexentry{DenseMtx_nbytesInWorkspace@{\tt DenseMtx\_nbytesInWorkspace()}}{5} \indexentry{DenseMtx_setNbytesInWorkspace@{\tt DenseMtx\_setNbytesInWorkspace()}}{5} \indexentry{DenseMtx_setFields@{\tt DenseMtx\_setFields()}}{5} \indexentry{DenseMtx_permuteRows@{\tt DenseMtx\_permuteRows()}}{5} \indexentry{DenseMtx_permuteColumns@{\tt DenseMtx\_permuteColumns()}}{5} \indexentry{DenseMtx_sort@{\tt DenseMtx\_sort()}}{5} \indexentry{DenseMtx_copyRow@{\tt DenseMtx\_copyRow()}}{5} \indexentry{DenseMtx_copyRowAndIndex@{\tt DenseMtx\_copyRowAndIndex()}}{5} \indexentry{DenseMtx_addRow@{\tt DenseMtx\_addRow()}}{6} \indexentry{DenseMtx_zero@{\tt DenseMtx\_zero()}}{6} \indexentry{DenseMtx_fillRandomEntries@{\tt DenseMtx\_fillRandomEntries()}}{6} \indexentry{DenseMtx_checksums@{\tt DenseMtx\_checksums()}}{6} \indexentry{DenseMtx_scale@{\tt DenseMtx\_scale()}}{6} \indexentry{DenseMtx_maxabs@{\tt DenseMtx\_maxabs()}}{6} \indexentry{DenseMtx_sub@{\tt DenseMtx\_sub()}}{6} \indexentry{DenseMtx_copyRowIntoVector@{\tt DenseMtx\_copyRowIntoVector()}}{6} \indexentry{DenseMtx_copyVectorIntoRow@{\tt DenseMtx\_copyVectorIntoRow()}}{6} \indexentry{DenseMtx_addVectorIntoRow@{\tt DenseMtx\_addVectorIntoRow()}}{6} \indexentry{DenseMtx_readFromFile@{\tt DenseMtx\_readFromFile()}}{7} \indexentry{DenseMtx_readFromFormattedFile@{\tt DenseMtx\_readFromFormattedFile()}}{7} \indexentry{DenseMtx_readFromBinaryFile@{\tt DenseMtx\_readFromBinaryFile()}}{7} \indexentry{DenseMtx_writeToFile@{\tt DenseMtx\_writeToFile()}}{7} \indexentry{DenseMtx_writeToFormattedFile@{\tt DenseMtx\_writeToFormattedFile()}}{7} \indexentry{DenseMtx_writeToBinaryFile@{\tt DenseMtx\_writeToBinaryFile()}}{7} \indexentry{DenseMtx_writeStats@{\tt DenseMtx\_writeStats()}}{7} \indexentry{DenseMtx_writeForHumanEye@{\tt DenseMtx\_writeForHumanEye()}}{7} \indexentry{DenseMtx_writeForMatlab@{\tt DenseMtx\_writeForMatlab()}}{8} DenseMtx/doc/main.aux010064400020550007177000000022270662335732100160420ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt DenseMtx}: Dense matrix object}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{1}} \newlabel{section:DenseMtx:dataStructure}{{1.1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt DenseMtx} methods}{2}} \newlabel{section:DenseMtx:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{2}} \newlabel{subsection:DenseMtx:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Instance methods}{2}} \newlabel{subsection:DenseMtx:proto:instance}{{1.2.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Initialization methods}{4}} \newlabel{subsection:DenseMtx:proto:initial}{{1.2.3}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Utility methods}{5}} \newlabel{subsection:DenseMtx:proto:utility}{{1.2.4}{5}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}IO methods}{7}} \newlabel{subsection:DenseMtx:proto:IO}{{1.2.5}{7}} file{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{1}} \newlabel{section:DenseMtx:dataStructure}{{1.1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt DenseMtx} methods}{2}} \newlabel{section:DenseMtx:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsecDenseMtx/doc/main.ind010064400020550007177000000041730662234557000160230ustar00clevecompmath00000400000006\begin{theindex} \item {\tt DenseMtx\_addRow()}, 6 \item {\tt DenseMtx\_addVectorIntoRow()}, 6 \item {\tt DenseMtx\_checksums()}, 6 \item {\tt DenseMtx\_clearData()}, 2 \item {\tt DenseMtx\_colid()}, 2 \item {\tt DenseMtx\_column()}, 4 \item {\tt DenseMtx\_columnIncrement()}, 2 \item {\tt DenseMtx\_columnIndices()}, 3 \item {\tt DenseMtx\_complexEntry()}, 3 \item {\tt DenseMtx\_copyRow()}, 5 \item {\tt DenseMtx\_copyRowAndIndex()}, 5 \item {\tt DenseMtx\_copyRowIntoVector()}, 6 \item {\tt DenseMtx\_copyVectorIntoRow()}, 6 \item {\tt DenseMtx\_dimensions()}, 2 \item {\tt DenseMtx\_entries()}, 3 \item {\tt DenseMtx\_fillRandomEntries()}, 6 \item {\tt DenseMtx\_free()}, 2 \item {\tt DenseMtx\_init()}, 4 \item {\tt DenseMtx\_initAsSubmatrix()}, 4 \item {\tt DenseMtx\_initFromBuffer()}, 4 \item {\tt DenseMtx\_initWithPointers()}, 4 \item {\tt DenseMtx\_maxabs()}, 6 \item {\tt DenseMtx\_nbytesInWorkspace()}, 5 \item {\tt DenseMtx\_nbytesNeeded()}, 5 \item {\tt DenseMtx\_new()}, 2 \item {\tt DenseMtx\_permuteColumns()}, 5 \item {\tt DenseMtx\_permuteRows()}, 5 \item {\tt DenseMtx\_readFromBinaryFile()}, 7 \item {\tt DenseMtx\_readFromFile()}, 7 \item {\tt DenseMtx\_readFromFormattedFile()}, 7 \item {\tt DenseMtx\_realEntry()}, 3 \item {\tt DenseMtx\_row()}, 4 \item {\tt DenseMtx\_rowid()}, 2 \item {\tt DenseMtx\_rowIncrement()}, 3 \item {\tt DenseMtx\_rowIndices()}, 3 \item {\tt DenseMtx\_scale()}, 6 \item {\tt DenseMtx\_setA2()}, 4 \item {\tt DenseMtx\_setComplexEntry()}, 3 \item {\tt DenseMtx\_setDefaultFields()}, 2 \item {\tt DenseMtx\_setFields()}, 5 \item {\tt DenseMtx\_setNbytesInWorkspace()}, 5 \item {\tt DenseMtx\_setRealEntry()}, 3 \item {\tt DenseMtx\_sort()}, 5 \item {\tt DenseMtx\_sub()}, 6 \item {\tt DenseMtx\_workspace()}, 3 \item {\tt DenseMtx\_writeForHumanEye()}, 7 \item {\tt DenseMtx\_writeForMatlab()}, 8 \item {\tt DenseMtx\_writeStats()}, 7 \item {\tt DenseMtx\_writeToBinaryFile()}, 7 \item {\tt DenseMtx\_writeToFile()}, 7 \item {\tt DenseMtx\_writeToFormattedFile()}, 7 \item {\tt DenseMtx\_zero()}, 6 \end{theindex} DenseMtx/doc/main.ilg010064400020550007177000000004570662234557000160250ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (52 entries accepted, 0 rejected). Sorting entries....done (300 comparisons). Generating output file main.ind....done (56 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. DenseMtx/doc/makefile010064400020550007177000000000270656040644500160750ustar00clevecompmath00000400000006clean : - rm -f *.dvi Drand.h010064400020550007177000000001000653410636700132730ustar00clevecompmath00000400000006#ifndef _Drand_ #define _Drand_ #include "Drand/Drand.h" #endif Drand/Drand.h010064400020550007177000000106060653505243700143360ustar00clevecompmath00000400000006/* Drand.h */ #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------ Double precision random number generator object there are two modes --- uniform on [lower,upper] and normal(mean, sigma) created -- 96may26, cca ------------------------------------------------ */ typedef struct _Drand { double seed1 ; double seed2 ; double base1 ; double base2 ; double lower ; double upper ; double mean ; double sigma ; int mode ; } Drand ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 96may26, cca ----------------------- */ Drand * Drand_new ( void ) ; /* ----------------------- set the default fields created -- 96may26, cca ----------------------- */ void Drand_setDefaultFields ( Drand *drand ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 96may26, cca -------------------------------------------------- */ void Drand_clearData ( Drand *drand ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 96may26, cca ------------------------------------------ */ Drand * Drand_free ( Drand *drand ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------- initialize the Drand object created -- 96may26, cca --------------------------- */ void Drand_init ( Drand *drand ) ; /* ---------------------------------- set the seeds using one input seed created -- 96may26, cca ---------------------------------- */ void Drand_setSeed ( Drand *drand, int u ) ; /* ----------------------------------- set the seeds using two input seeds created -- 96may26, cca ----------------------------------- */ void Drand_setSeeds ( Drand *drand, int u, int v ) ; /* -------------------------------------------- set the mode to be uniform in [lower, upper] created -- 96may26, cca -------------------------------------------- */ void Drand_setUniform ( Drand *drand, double lower, double upper ) ; /* -------------------------------------- set the mode to be normal(mean, sigma) created -- 96may26, cca -------------------------------------- */ void Drand_setNormal ( Drand *drand, double mean, double sigma ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------------- return a random double precision value created -- 96may26, cca -------------------------------------- */ double Drand_value ( Drand *drand ) ; /* ---------------------------------------------------------- fill a double precision complex vector with random numbers created -- 98jun02, cca ---------------------------------------------------------- */ void Drand_fillZvector ( Drand *drand, int size, double dvec[] ) ; /* -------------------------------------------------- fill a double precision vector with random numbers created -- 96may26, cca -------------------------------------------------- */ void Drand_fillDvector ( Drand *drand, int size, double dvec[] ) ; /* ----------------------------------------- fill a integer vector with random numbers created -- 96may26, cca ----------------------------------------- */ void Drand_fillIvector ( Drand *drand, int size, int ivec[] ) ; /*--------------------------------------------------------------------*/ d_clearData ( Drand *drand ) ; /* ------------------------------------------ destructor, free's the object anDrand/makefile010064400020550007177000000002230663622356500146330ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean Drand/src/makefile010064400020550007177000000006370663602247400154270ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Drand $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG Drand/src/makeGlobalLib010064400020550007177000000005560660026100200163160ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Drand SRC = basics.c \ init.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Drand/src/basics.c010064400020550007177000000042310653410577100153300ustar00clevecompmath00000400000006/* basics.c */ #include "../Drand.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 96may26, cca ----------------------- */ Drand * Drand_new ( void ) { Drand *drand ; ALLOCATE(drand, struct _Drand, 1) ; Drand_setDefaultFields(drand) ; return(drand) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 96may26, cca ----------------------- */ void Drand_setDefaultFields ( Drand *drand ) { if ( drand == NULL ) { fprintf(stderr, "\n fatal error in Drand_setDefaultFields(%p)" "\n bad input", drand) ; exit(-1) ; } drand->seed1 = 123456789.0 ; drand->seed2 = 987654321.0 ; drand->base1 = 2147483563.0 ; drand->base2 = 2147483399.0 ; drand->lower = 0.0 ; drand->upper = 1.0 ; drand->mean = 0.0 ; drand->sigma = 1.0 ; drand->mode = 1 ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 96may26, cca -------------------------------------------------- */ void Drand_clearData ( Drand *drand ) { /* --------------- check the input --------------- */ if ( drand == NULL ) { fprintf(stderr, "\n fatal error in Drand_clearData(%p)" "\n bad input\n", drand) ; exit(-1) ; } /* ---------------------- set the default fields ---------------------- */ Drand_setDefaultFields(drand) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 96may26, cca ------------------------------------------ */ Drand * Drand_free ( Drand *drand ) { if ( drand == NULL ) { fprintf(stderr, "\n fatal error in Drand_free(%p)" "\n bad input\n", drand) ; exit(-1) ; } Drand_clearData(drand) ; FREE(drand) ; return(NULL) ; } /*--------------------------------------------------------------------*/ Drand/src/init.c010064400020550007177000000062030660546737700150440ustar00clevecompmath00000400000006/* init.c */ #include "../Drand.h" /*--------------------------------------------------------------------*/ /* --------------------------- initialize the Drand object created -- 96may26, cca --------------------------- */ void Drand_init ( Drand *drand ) { /* --------------- check the input --------------- */ if ( drand == NULL ) { fprintf(stderr, "\n fatal error in Drand_init(%p)" "\n bad input\n", drand) ; exit(-1) ; } /* ---------------------- set the default fields ---------------------- */ Drand_setDefaultFields(drand) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- set the seeds using one input seed created -- 96may26, cca ---------------------------------- */ void Drand_setSeed ( Drand *drand, int u ) { if ( drand == NULL || u <= 0 || u >= drand->base1 ) { fprintf(stderr, "\n fatal error in Drand_setSeed(%p,%d)" "\n first seed must in in (0,%.0f)", drand, u, drand->base1) ; exit(-1) ; } drand->seed1 = u ; drand->seed2 = fmod(2718.*u, drand->base2) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- set the seeds using two input seeds created -- 96may26, cca ----------------------------------- */ void Drand_setSeeds ( Drand *drand, int u, int v ) { if ( drand == NULL || u <= 0 || u >= drand->base1 || v <= 0 || v >= drand->base2 ) { fprintf(stderr, "\n fatal error in Drand_setSeeds(%p,%d,%d)" "\n first seed must in in (0,%.0f)" "\n second seed must in in (0,%.0f)\n", drand, u, v, drand->base1, drand->base2) ; exit(-1) ; } drand->seed1 = u ; drand->seed2 = v ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- set the mode to be uniform in [lower, upper] created -- 96may26, cca -------------------------------------------- */ void Drand_setUniform ( Drand *drand, double lower, double upper ) { /* --------------- check the input --------------- */ if ( drand == NULL || lower > upper ) { fprintf(stderr, "\n fatal error in Drand_setUniform(%p,%f,%f)" "\n bad input\n", drand, lower, upper) ; exit(-1) ; } drand->mode = 1 ; drand->lower = lower ; drand->upper = upper ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- set the mode to be normal(mean, sigma) created -- 96may26, cca -------------------------------------- */ void Drand_setNormal ( Drand *drand, double mean, double sigma ) { /* --------------- check the input --------------- */ if ( drand == NULL || sigma <= 0 ) { fprintf(stderr, "\n fatal error in Drand_setNormal(%p,%f,%f)" "\n bad input\n", drand, mean, sigma) ; exit(-1) ; } drand->mode = 2 ; drand->mean = mean ; drand->sigma = sigma ; return ; } /*--------------------------------------------------------------------*/ 2) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- set the seeds using two input seeds created -- 96may26, cca ----------------------------------- */ void Drand_setSeeds ( Drand *drand, int u, int v ) { if ( drand == NULL || u <= 0 || u >= drand->base1 || v <= 0Drand/src/util.c010064400020550007177000000101630653505244200150370ustar00clevecompmath00000400000006/* util.c */ #include "../Drand.h" /*--------------------------------------------------------------------*/ /* -------------------------------------- return a random double precision value created -- 96may26, cca -------------------------------------- */ double Drand_value ( Drand *drand ) { double sum, t ; /* --------------- check the input --------------- */ if ( drand == NULL ) { fprintf(stderr, "\n fatal error in Drand_value(%p)" "\n bad input\n", drand) ; exit(-1) ; } /* -------------------- switch over the mode -------------------- */ if ( drand->mode == 1 ) { /* ------------ uniform mode ------------ */ drand->seed1 = fmod(40014*drand->seed1, drand->base1) ; drand->seed2 = fmod(40692*drand->seed2, drand->base2) ; t = drand->seed1 - drand->seed2 ; if ( t <= 0 ) { t = t + (drand->base1 - 1) ; } t = drand->lower + (t/drand->base1)*(drand->upper - drand->lower) ; } else { /* ----------- normal mode ----------- */ drand->seed1 = fmod(40014*drand->seed1, drand->base1) ; drand->seed2 = fmod(40692*drand->seed2, drand->base2) ; t = drand->seed1 - drand->seed2 ; if ( t <= 0 ) { t = t + (drand->base1 - 1) ; } t = t / drand->base1 ; sum = t ; drand->seed1 = fmod(40014*drand->seed1, drand->base1) ; drand->seed2 = fmod(40692*drand->seed2, drand->base2) ; t = drand->seed1 - drand->seed2 ; if ( t <= 0 ) { t = t + (drand->base1 - 1) ; } t = t / drand->base1 ; sum += t ; drand->seed1 = fmod(40014*drand->seed1, drand->base1) ; drand->seed2 = fmod(40692*drand->seed2, drand->base2) ; t = drand->seed1 - drand->seed2 ; if ( t <= 0 ) { t = t + (drand->base1 - 1) ; } t = t / drand->base1 ; sum += t ; t = drand->mean + drand->sigma*(2.*sum - 3.) ; } return(t) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- fill a double precision complex vector with random numbers created -- 98jun02, cca ---------------------------------------------------------- */ void Drand_fillZvector ( Drand *drand, int size, double dvec[] ) { int i ; /* --------------- check the input --------------- */ if ( drand == NULL || size < 0 || dvec == NULL ) { fprintf(stderr, "\n fatal error in Drand_fillZvector(%p,%d,%p)" "\n bad input\n", drand, size, dvec) ; exit(-1) ; } /* --------------- fill the vector --------------- */ for ( i = 0 ; i < 2*size ; i++ ) { dvec[i] = Drand_value(drand) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- fill a double precision vector with random numbers created -- 96may26, cca -------------------------------------------------- */ void Drand_fillDvector ( Drand *drand, int size, double dvec[] ) { int i ; /* --------------- check the input --------------- */ if ( drand == NULL || size < 0 || dvec == NULL ) { fprintf(stderr, "\n fatal error in Drand_fillDvector(%p,%d,%p)" "\n bad input\n", drand, size, dvec) ; exit(-1) ; } /* --------------- fill the vector --------------- */ for ( i = 0 ; i < size ; i++ ) { dvec[i] = Drand_value(drand) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- fill a integer vector with random numbers created -- 96may26, cca ----------------------------------------- */ void Drand_fillIvector ( Drand *drand, int size, int ivec[] ) { int i ; /* --------------- check the input --------------- */ if ( drand == NULL || size < 0 || ivec == NULL ) { fprintf(stderr, "\n fatal error in Drand_fillIvector(%p,%d,%p)" "\n bad input\n", drand, size, ivec) ; exit(-1) ; } /* --------------- fill the vector --------------- */ for ( i = 0 ; i < size ; i++ ) { ivec[i] = (int) Drand_value(drand) ; } return ; } /*--------------------------------------------------------------------*/ Drand/drivers/do_testDrand010075500020550007177000000005510653410577200171510ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 5 set msgFile = stdout set distribution = 2 set param1 = 0 set param2 = 10 set distribution = 1 set param1 = -10 set param2 = 10 set seed1 = 10101 set seed2 = 20304 set n = 100 testDrand $msglvl $msgFile \ $distribution $param1 $param2 $seed1 $seed2 $n Drand/drivers/makefile010064400020550007177000000004670665314242100163110ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testDrand drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testDrand : testDrand.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} Drand/drivers/testDrand.c010064400020550007177000000057250653505401700167110ustar00clevecompmath00000400000006/* testDrand.c */ #include "../Drand.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------- test the Drand random number generator object --------------------------------------------- */ { double ddot, dmean, param1, param2 ; double *dvec ; Drand drand ; FILE *msgFile ; int distribution, ierr, imean, msglvl, n, seed1, seed2 ; int *ivec ; if ( argc != 9 ) { fprintf(stderr, "\n\n usage : testDrand msglvl msgFile " "\n distribution param1 param2 seed1 seed2 n" "\n msglvl -- message level" "\n msgFile -- message file" "\n distribution -- 1 for uniform(param1,param2)" "\n -- 2 for normal(param1,param2)" "\n param1 -- first parameter" "\n param2 -- second parameter" "\n seed1 -- first random number seed" "\n seed2 -- second random number seed" "\n n -- length of the vector" "\n" ) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } distribution = atoi(argv[3]) ; if ( distribution < 1 || distribution > 2 ) { fprintf(stderr, "\n fatal error in testDrand" "\n distribution must be 1 (uniform) or 2 (normal)") ; exit(-1) ; } param1 = atof(argv[4]) ; param2 = atof(argv[5]) ; seed1 = atoi(argv[6]) ; seed2 = atoi(argv[7]) ; n = atoi(argv[8]) ; Drand_init(&drand) ; Drand_setSeeds(&drand, seed1, seed2) ; switch ( distribution ) { case 1 : fprintf(msgFile, "\n uniform in [%f,%f]", param1, param2) ; Drand_setUniform(&drand, param1, param2) ; break ; case 2 : fprintf(msgFile, "\n normal(%f,%f)", param1, param2) ; Drand_setNormal(&drand, param1, param2) ; break ; } /* --------------------------------------------- fill the integer and double precision vectors --------------------------------------------- */ dvec = DVinit(n, 0.0) ; Drand_fillDvector(&drand, n, dvec) ; dmean = DVsum(n, dvec)/n ; ddot = DVdot(n, dvec, dvec) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n dvec mean = %.4f, variance = %.4f", dmean, sqrt(fabs(ddot - n*dmean)/n)) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n dvec") ; DVfprintf(msgFile, n, dvec) ; } DVqsortUp(n, dvec) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted dvec") ; DVfprintf(msgFile, n, dvec) ; } ivec = IVinit(n, 0) ; Drand_fillIvector(&drand, n, ivec) ; imean = IVsum(n, ivec)/n ; if ( msglvl > 1 ) { fprintf(msgFile, "\n ivec") ; IVfp80(msgFile, n, ivec, 80, &ierr) ; } IVqsortUp(n, ivec) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted ivec") ; IVfp80(msgFile, n, ivec, 80, &ierr) ; } fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Drand/doc/004275500020550007177000000000000654276737700137225ustar00clevecompmath00000400000006Drand/doc/drivers.tex010064400020550007177000000030540653410577200161010ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt Drand} object} \label{section:Drand:drivers} \par This section contains brief descriptions of the driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testDrand msglvl msgFile distribution param1 param2 seed1 seed2 n \end{verbatim} This driver program test the {\tt Drand} random number generator. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt distribution} parameter specifies the mode of the object. If {\tt 1}, the distribution is uniform. If {\tt 2}, the distribution is normal. \item When {\tt distribution = 1}, {\tt param1} is the lower bound for the interval. When {\tt distribution = 2}, {\tt param1} is the mean for the normal distribution. \item When {\tt distribution = 1}, {\tt param2} is the upper bound for the interval. When {\tt distribution = 2}, {\tt param2} is the variance for the normal distribution. \item {\tt seed1} is the first random number seed. \item {\tt seed2} is the second random number seed. \item {\tt n} is the length of the vector of random numbers to be generated. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} Drand/doc/dataStructure.tex010064000020550007177000000011750653410577200172530ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:Drand:dataStructure} \par The {\tt Drand} object has nine fields. \begin{itemize} \item {\tt double seed1} : first seed \item {\tt double seed2} : second seed \item {\tt double base1} : first base \item {\tt double base2} : second base \item {\tt double lower} : lower bound for a uniform distribution \item {\tt double upper} : upper bound for a uniform distribution \item {\tt double mean} : mean for a normal distribution \item {\tt double sigma} : variation for a normal distribution \item {\tt int mode}: mode of the object, uniform is {\tt 1}, normal is {\tt 2} \end{itemize} Drand/doc/intro.tex010064000020550007177000000005530653410577200155530ustar00clevecompmath00000400000006\chapter{{\tt Drand}: \break Simple Random Number Generator} \par Finding the same random number generator on a variety of UNIX systems is not guaranteed to be a success. Therefore, we wrote a simple random number generator object taken from \cite{and90-random}. The {\tt Drand} object provides both normally distributed and uniformly distributed random numbers. Drand/doc/main.tex010064400020550007177000000010730665065621500153500ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Drand} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Drand} : {\it DRAFT} \quad \today \hrulefill} \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} Drand/doc/proto.tex010064400020550007177000000163200653505241300155600ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Drand} methods} \label{section:Drand:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Drand} object. \par \subsection{Basic methods} \label{subsection:Drand:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Drand * Drand_new ( void ) ; \end{verbatim} \index{Drand_new@{\tt Drand\_new()}} This method simply allocates storage for the {\tt Drand} structure and then sets the default fields by a call to {\tt Drand\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Drand_setDefaultFields ( Drand *drand ) ; \end{verbatim} \index{Drand_setDefaultFields@{\tt Drand\_setDefaultFields()}} This method sets the structure's fields to default values. \begin{center} \begin{verbatim} drand->seed1 = 123456789.0 ; drand->seed2 = 987654321.0 ; drand->base1 = 2147483563.0 ; drand->base2 = 2147483399.0 ; drand->lower = 0.0 ; drand->upper = 1.0 ; drand->mean = 0.0 ; drand->sigma = 1.0 ; drand->mode = 1 ; \end{verbatim} \end{center} The default mode is a uniform distribution on {\tt [0,1]}. \par \noindent {\it Error checking:} If {\tt drand} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Drand_clearData ( Drand *drand ) ; \end{verbatim} \index{Drand_clearData@{\tt Drand\_clearData()}} This method clears any data owned by the object. It then sets the default fields with a call to {\tt Drand\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt drand} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Drand_free ( Drand *drand ) ; \end{verbatim} \index{Drand_free@{\tt Drand\_free()}} This method frees the object. It releases any storage by a call to {\tt Drand\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt drand} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:Drand:proto:initializers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Drand_init ( Drand *drand ) ; \end{verbatim} \index{Drand_init@{\tt Drand\_init()}} This initializer simply sets the default fields with a call to {\tt Drand\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt drand} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Drand_setSeed ( Drand *drand, int seed1 ) ; \end{verbatim} \index{Drand_setSeed@{\tt Drand\_setSeed()}} This method sets the random number seeds using a single input seed. \par \noindent {\it Error checking:} If {\tt drand} is {\tt NULL}, or if ${\tt seed1} \le 0$, or if ${\tt seed1} \ge 2147483563$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Drand_setSeeds ( Drand *drand, int seed1, int seed2 ) ; \end{verbatim} \index{Drand_setSeeds@{\tt Drand\_setSeeds()}} This method sets the random number seeds using two input seeds. \par \noindent {\it Error checking:} If {\tt drand} is {\tt NULL}, an error message is printed and the program exits. \par \noindent {\it Error checking:} If {\tt drand} is {\tt NULL}, or if ${\tt seed1} \le 0$, or if ${\tt seed1} \ge 2147483563$, or if ${\tt seed2} \le 0$, or if ${\tt seed2} \ge 2147483399$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Drand_setNormal ( Drand *drand, double mean, double sigma ) ; \end{verbatim} \index{Drand_setNormal@{\tt Drand\_setNormal()}} This method sets the mode to be a normal distribution with mean {\tt mean} and variation {\tt sigma}. \par \noindent {\it Error checking:} If {\tt drand} is {\tt NULL}, or if ${\tt sigma} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Drand_setUniform ( Drand *drand, double lower, double upper ) ; \end{verbatim} \index{Drand_setUniform@{\tt Drand\_setUniform()}} This method sets the mode to be a uniform distribution over the interval {\tt [lower,upper]} ; \par \noindent {\it Error checking:} If {\tt drand} is {\tt NULL}, or if ${\tt lower} \ge {\tt upper}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:Drand:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} double Drand_value ( Drand *drand ) ; \end{verbatim} \index{Drand_value@{\tt Drand\_value()}} This method returns a double precision random number. \par \noindent {\it Error checking:} If {\tt drand} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Drand_fillZvector ( Drand *drand, int n, double vec[] ) ; \end{verbatim} \index{Drand_fillZvector@{\tt Drand\_fillZvector()}} This method fills a double precision complex vector {\tt vec[]} with {\tt n} complex random numbers. \par \noindent {\it Error checking:} If {\tt drand} or {\tt vec} are {\tt NULL} or if {\tt n < 0 }, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Drand_fillDvector ( Drand *drand, int n, double vec[] ) ; \end{verbatim} \index{Drand_fillDvector@{\tt Drand\_fillDvector()}} This method fills double precision vector {\tt vec[]} with {\tt n} random numbers. \par \noindent {\it Error checking:} If {\tt drand} or {\tt vec} are {\tt NULL} or if {\tt n < 0 }, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Drand_fillIvector ( Drand *drand, int n, int vec[] ) ; \end{verbatim} \index{Drand_fillIvector@{\tt Drand\_fillIvector()}} This method fills {\tt vec[]} with {\tt n} {\tt int} random numbers. \par \noindent {\it Error checking:} If {\tt drand} or {\tt vec} are {\tt NULL} or if {\tt n < 0 }, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} Drand/doc/main.log010064400020550007177000000047250653505207400153330ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 2 JUN 1998 12:36 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. LaTeX Warning: Citation `and90-random' on page 1 undefined on input line 6. ) (dataStructure.tex) (proto.tex [1 ] [2]) (drivers.tex [3] Overfull \hbox (10.7556pt too wide) in paragraph at lines 29--34 [] []\elvrm When \elvtt distribution = 1\elvrm , \elvtt param1 \elvrm is the lo wer bound for the in-ter-val. When \elvtt distribution \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm W .etc. Overfull \hbox (13.49315pt too wide) in paragraph at lines 34--39 [] []\elvrm When \elvtt distribution = 1\elvrm , \elvtt param2 \elvrm is the up -per bound for the in-ter-val. When \elvtt distribution \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm W .etc. ) (main.ind [4] [5 ]) (main.aux) ) Here is how much of TeX's memory you used: 208 strings out of 11977 2143 string characters out of 87269 33040 words of memory out of 262141 2142 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,4n,17p,187b,254s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (5 pages, 9336 bytes). Drand/doc/main.aux010064400020550007177000000024620653505207400153430ustar00clevecompmath00000400000006\relax \citation{and90-random} \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space Drand}: \penalty -\@M Simple Random Number Generator}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:Drand:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space Drand} methods}{1}} \newlabel{section:Drand:proto}{{1.2}{1}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:Drand:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initializer methods}{2}} \newlabel{subsection:Drand:proto:initializers}{{1.2.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{3}} \newlabel{subsection:Drand:proto:utilities}{{1.2.3}{3}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs for the {\string\ptt\space Drand} object}{3}} \newlabel{section:Drand:drivers}{{1.3}{3}} Drand/doc/main.idx010064400020550007177000000012260653505207400153270ustar00clevecompmath00000400000006\indexentry{Drand_new@{\tt Drand\_new()}}{2} \indexentry{Drand_setDefaultFields@{\tt Drand\_setDefaultFields()}}{2} \indexentry{Drand_clearData@{\tt Drand\_clearData()}}{2} \indexentry{Drand_free@{\tt Drand\_free()}}{2} \indexentry{Drand_init@{\tt Drand\_init()}}{2} \indexentry{Drand_setSeed@{\tt Drand\_setSeed()}}{2} \indexentry{Drand_setSeeds@{\tt Drand\_setSeeds()}}{3} \indexentry{Drand_setNormal@{\tt Drand\_setNormal()}}{3} \indexentry{Drand_setUniform@{\tt Drand\_setUniform()}}{3} \indexentry{Drand_value@{\tt Drand\_value()}}{3} \indexentry{Drand_fillDvector@{\tt Drand\_fillDvector()}}{3} \indexentry{Drand_fillIvector@{\tt Drand\_fillIvector()}}{3} Drand/doc/main.ind010064400020550007177000000007070653505207100153150ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Drand\_clearData()}, 2 \item {\tt Drand\_fillDvector()}, 3 \item {\tt Drand\_fillIvector()}, 3 \item {\tt Drand\_free()}, 2 \item {\tt Drand\_init()}, 2 \item {\tt Drand\_new()}, 2 \item {\tt Drand\_setDefaultFields()}, 2 \item {\tt Drand\_setNormal()}, 3 \item {\tt Drand\_setSeed()}, 2 \item {\tt Drand\_setSeeds()}, 3 \item {\tt Drand\_setUniform()}, 3 \item {\tt Drand\_value()}, 3 \end{theindex} Drand/doc/main.ilg010064400020550007177000000004560653505207100153170ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (12 entries accepted, 0 rejected). Sorting entries....done (46 comparisons). Generating output file main.ind....done (16 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Drand/doc/makefile010064400020550007177000000000270654276737700154140ustar00clevecompmath00000400000006clean : - rm -f *.dvi EGraph.h010064400020550007177000000001040653410640200134030ustar00clevecompmath00000400000006#ifndef _EGraph_ #define _EGraph_ #include "EGraph/EGraph.h" #endif EGraph/EGraph.h010064400020550007177000000170330653410610000145550ustar00clevecompmath00000400000006/* EGraph.h */ #include "../cfiles.h" #include "../Graph.h" #include "../IVL.h" /*====================================================================*/ /* --------------------------------------------------------------- the EGraph object stores an element graph type -- type of element graph 0 --> vertices have unit weight 1 --> vertices are weighted nelem -- # of elements nvtx -- # of vertices adj -- IVL object that holds the lists of elements and their vertices vwghts -- pointer to vector of vertex weights, NULL if type = 0 created -- 95nov03, cca --------------------------------------------------------------- */ typedef struct _EGraph { int type ; int nelem ; int nvtx ; IVL *adjIVL ; int *vwghts ; } EGraph ; /*====================================================================*/ /* ------------------------------------------------------------------------ ------ methods found in basics.c --------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor created -- 95nov03, cca ----------------------- */ EGraph * EGraph_new ( void ) ; /* ----------------------- set the default fields created -- 95nov03, cca ----------------------- */ void EGraph_setDefaultFields ( EGraph *eg ) ;/* ----------------------- clear the data fields created -- 95nov03, cca ----------------------- */ void EGraph_clearData ( EGraph *eg ) ; /* ----------------------- destructor created -- 95nov03, cca ----------------------- */ void EGraph_free ( EGraph *eg ) ; /*====================================================================*/ /* ------------------------------------------------------------------------ ------ methods found in init.c ----------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------- purpose -- initialize the EGraph object created -- 96oct24, cca --------------------------------------- */ void EGraph_init ( EGraph *egraph, int type, int nelem, int nvtx, int IVL_type ) ; /*====================================================================*/ /* ------------------------------------------------------------------------ ------ methods found in mkAdjGraph.c ----------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------- create a Graph object that holds the adjacency graph of the assembled elements. created -- 95nov03, cca ---------------------------------------------------- */ Graph * EGraph_mkAdjGraph ( EGraph *eg ) ; /*====================================================================*/ /* ------------------------------------------------------------------------ ------ methods found in misc.c ----------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- make an element graph for a n1 x n2 grid with ncomp components created -- 95nov03, cca -------------------------------------------------------------- */ EGraph * EGraph_make9P ( int n1, int n2, int ncomp ) ; /* ------------------------------------------------------------------- make an element graph for a n1 x n2 x n3 grid with ncomp components created -- 95nov03, cca ------------------------------------------------------------------- */ EGraph * EGraph_make27P ( int n1, int n2, int n3, int ncomp ) ; /*====================================================================*/ /* ------------------------ IO methods found in IO.c ----------------------- */ /* ------------------------------------------------- purpose -- to read in a EGraph object from a file input -- fn -- filename, must be *.egraphb or *.egraphf return value -- 1 if success, 0 if failure created -- 95nov03, cca ------------------------------------------------- */ int EGraph_readFromFile ( EGraph *egraph, char *fn ) ; /* -------------------------------------------------------- purpose -- to read a EGraph object from a formatted file return value -- 1 if success, 0 if failure created -- 95nov03, cca -------------------------------------------------------- */ int EGraph_readFromFormattedFile ( EGraph *egraph, FILE *fp ) ; /* ---------------------------------------------------- purpose -- to read a EGraph object from a binary file return value -- 1 if success, 0 if failure created -- 95nov03, cca ---------------------------------------------------- */ int EGraph_readFromBinaryFile ( EGraph *egraph, FILE *fp ) ; /* -------------------------------------------- purpose -- to write a EGraph object to a file input -- fn -- filename *.egraphb -- binary *.egraphf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95nov03, cca -------------------------------------------- */ int EGraph_writeToFile ( EGraph *egraph, char *fn ) ; /* ------------------------------------------------------ purpose -- to write a EGraph object to a formatted file return value -- 1 if success, 0 otherwise created -- 95nov03, cca ------------------------------------------------------ */ int EGraph_writeToFormattedFile ( EGraph *egraph, FILE *fp ) ; /* --------------------------------------------------- purpose -- to write a EGraph object to a binary file return value -- 1 if success, 0 otherwise created -- 95nov03, cca --------------------------------------------------- */ int EGraph_writeToBinaryFile ( EGraph *egraph, FILE *fp ) ; /* ------------------------------------------------- purpose -- to write a EGraph object for a human eye return value -- 1 if success, 0 otherwise created -- 95nov03, cca ------------------------------------------------- */ int EGraph_writeForHumanEye ( EGraph *egraph, FILE *fp ) ; /* ----------------------------------------------------------- purpose -- to write out the statistics for the EGraph object return value -- 1 if success, 0 otherwise created -- 95nov03, cca ----------------------------------------------------------- */ int EGraph_writeStats ( EGraph *egraph, FILE *fp ) ; /*====================================================================*/ /* ------------------------------------- miscellaneous methods found in misc.c ------------------------------------- */ /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- return the element graph for a 9 point operator on a n1 x n2 grid with ncomp components at each grid point ----------------------------------------------------- */ EGraph * EGraph_make9P ( int n1, int n2, int ncomp ) ; /* ---------------------------------------------------------- return the element graph for a 27 point operator on a n1 x n2 x n3 grid with ncomp components at each grid point ---------------------------------------------------------- */ EGraph * EGraph_make27P ( int n1, int n2, int n3, int ncomp ) ; /*--------------------------------------------------------------------*/ EGraph/makefile010064400020550007177000000002230663622356700147530ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean EGraph/src/makefile010064400020550007177000000007320663602255200155360ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = EGraph $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(mkAdjGraph.o) \ $(OBJ).a(misc.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG EGraph/src/makeGlobalLib010064400020550007177000000006210660026100600164310ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = EGraph SRC = basics.c \ init.c \ IO.c \ mkAdjGraph.c \ misc.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a EGraph/src/IO.c010064400020550007177000000423250653410610000145020ustar00clevecompmath00000400000006/* IO.c */ #include "../EGraph.h" static const char *suffixb = ".egraphb" ; static const char *suffixf = ".egraphf" ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to read in a EGraph object from a file input -- fn -- filename, must be *.egraphb or *.egraphf return value -- 1 if success, 0 if failure created -- 95nov03, cca ------------------------------------------------- */ int EGraph_readFromFile ( EGraph *egraph, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( egraph == NULL || fn == NULL ) { fprintf(stderr, "\n error in EGraph_readFromFile(%p,%s)" "\n bad input\n", egraph, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in EGraph_readFromFile(%p,%s)" "\n unable to open file %s", egraph, fn, fn) ; rc = 0 ; } else { rc = EGraph_readFromBinaryFile(egraph, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in EGraph_readFromFile(%p,%s)" "\n unable to open file %s", egraph, fn, fn) ; rc = 0 ; } else { rc = EGraph_readFromFormattedFile(egraph, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in EGraph_readFromFile(%p,%s)" "\n bad EGraph file name %s," "\n must end in %s (binary) or %s (formatted)\n", egraph, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in EGraph_readFromFile(%p,%s)" "\n bad EGraph file name %s," "\n must end in %s (binary) or %s (formatted)\n", egraph, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to read a EGraph object from a formatted file return value -- 1 if success, 0 if failure created -- 95nov03, cca -------------------------------------------------------- */ int EGraph_readFromFormattedFile ( EGraph *egraph, FILE *fp ) { int nelem, nvtx, rc, type ; int itemp[6] ; int *vwghts ; IVL *adjIVL ; /* --------------- check the input --------------- */ if ( egraph == NULL || fp == NULL ) { fprintf(stderr, "\n error in EGraph_readFromFormattedFile(%p,%p)" "\n bad input\n", egraph, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ EGraph_clearData(egraph) ; /* ----------------------------------- read in the three scalar parameters type, nelem, nvtx ----------------------------------- */ if ( (rc = IVfscanf(fp, 3, itemp)) != 3 ) { fprintf(stderr, "\n error in EGraph_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", egraph, fp, rc, 3) ; return(0) ; } type = itemp[0] ; nelem = itemp[1] ; nvtx = itemp[2] ; /* ---------------------------- initialize the EGraph object ---------------------------- */ EGraph_init(egraph, type, nelem, nvtx, IVL_CHUNKED) ; /* -------------------------- read in the adj IVL object -------------------------- */ adjIVL = egraph->adjIVL ; rc = IVL_readFromFormattedFile(adjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n error in EGraph_readFromFormattedFile(%p,%p)" "\n trying to read in adjIVL" "\n return code %d from IVL_readFormattedFile(%p,%p)", egraph, fp, rc, adjIVL, fp) ; return(0) ; } if ( type % 2 == 1 ) { /* -------------------------- vertex weights are present -------------------------- */ vwghts = egraph->vwghts ; if ( (rc = IVfscanf(fp, nvtx, vwghts)) != nvtx ) { fprintf(stderr, "\n error in EGraph_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", egraph, fp, rc, nvtx) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to read a EGraph object from a binary file return value -- 1 if success, 0 if failure created -- 95nov03, cca ---------------------------------------------------- */ int EGraph_readFromBinaryFile ( EGraph *egraph, FILE *fp ) { int nelem, nvtx, rc, type ; int itemp[6] ; int *vwghts ; IVL *adjIVL ; /* --------------- check the input --------------- */ if ( egraph == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in EGraph_readFromBinaryFile(%p,%p)" "\n bad input\n", egraph, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ EGraph_clearData(egraph) ; /* ----------------------------------- read in the three scalar parameters type, nelem, nvtx ----------------------------------- */ if ( (rc = fread((void *) itemp, sizeof(int), 3, fp)) != 3 ) { fprintf(stderr, "\n error in EGraph_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", egraph, fp, rc, 3) ; return(0) ; } type = itemp[0] ; nelem = itemp[1] ; nvtx = itemp[2] ; /* ---------------------------- initialize the EGraph object ---------------------------- */ EGraph_init(egraph, type, nelem, nvtx, IVL_CHUNKED) ; /* -------------------------- read in the adj IVL object -------------------------- */ adjIVL = egraph->adjIVL ; rc = IVL_readFromBinaryFile(adjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n error in EGraph_readFromBinaryFile(%p,%p)" "\n trying to read in adjIVL" "\n return code %d from IVL_readBinaryFile(%p,%p)", egraph, fp, rc, adjIVL, fp) ; return(0) ; } if ( type % 2 == 1 ) { /* -------------------------- vertex weights are present -------------------------- */ vwghts = egraph->vwghts ; if ( (rc = fread((void *) vwghts, sizeof(int), nvtx, fp)) != nvtx){ fprintf(stderr, "\n error in EGraph_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", egraph, fp, rc, nvtx) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to write a EGraph object to a file input -- fn -- filename *.egraphb -- binary *.egraphf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95nov03, cca -------------------------------------------- */ int EGraph_writeToFile ( EGraph *egraph, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( egraph == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in EGraph_writeToFile(%p,%s)" "\n bad input\n", egraph, fn) ; return(0) ; } if ( egraph->type < 0 || 3 < egraph->type ) { fprintf(stderr, "\n fatal error in EGraph_writeToFile(%p,%s)" "\n bad type = %d", egraph, fn, egraph->type) ; return(0) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in EGraph_writeToFile(%p,%s)" "\n unable to open file %s", egraph, fn, fn) ; rc = 0 ; } else { rc = EGraph_writeToBinaryFile(egraph, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in EGraph_writeToFile(%p,%s)" "\n unable to open file %s", egraph, fn, fn) ; rc = 0 ; } else { rc = EGraph_writeToFormattedFile(egraph, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in EGraph_writeToFile(%p,%s)" "\n unable to open file %s", egraph, fn, fn) ; rc = 0 ; } else { rc = EGraph_writeForHumanEye(egraph, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in EGraph_writeToFile(%p,%s)" "\n unable to open file %s", egraph, fn, fn) ; rc = 0 ; } else { rc = EGraph_writeForHumanEye(egraph, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to write a EGraph object to a formatted file return value -- 1 if success, 0 otherwise created -- 95nov03, cca ------------------------------------------------------ */ int EGraph_writeToFormattedFile ( EGraph *egraph, FILE *fp ) { int ierr, rc ; /* --------------- check the input --------------- */ if ( egraph == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in EGraph_writeToFormattedFile(%p,%p)" "\n bad input\n", egraph, fp) ; return(0) ; } if ( egraph->type < 0 || 1 < egraph->type ) { fprintf(stderr, "\n fatal error in EGraph_writeToFormattedFile(%p,%p)" "\n bad type = %d", egraph, fp, egraph->type) ; return(0) ; } /* ------------------------------------- write out the three scalar parameters ------------------------------------- */ rc = fprintf(fp, "\n %d %d %d", egraph->type, egraph->nelem, egraph->nvtx) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in EGraph_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", egraph, fp, rc) ; return(0) ; } /* --------------------------------- write out the adjacency structure --------------------------------- */ rc = IVL_writeToFormattedFile(egraph->adjIVL, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in EGraph_writeToFormattedFile(%p,%p)" "\n rc = %d, return from IVL_writeToFormattedFile(%p,%p)" "\n while attempting to write out adjIVL\n", egraph, fp, rc, egraph->adjIVL, fp) ; return(0) ; } /* ----------------------------------------- write out the vwghts[] vector, if present ----------------------------------------- */ if ( egraph->type % 2 == 1 ) { if ( egraph->vwghts == NULL ) { fprintf(stderr, "\n fatal error in EGraph_writeToFormattedFile(%p,%p)" "\n egraph->type = %d, egraph->vwghts == NULL\n", egraph, fp, egraph->type) ; return(0) ; } IVfp80(fp, egraph->nvtx, egraph->vwghts, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in EGraph_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from vwghts[] IVfp80\n", egraph, fp, ierr) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to write a EGraph object to a binary file return value -- 1 if success, 0 otherwise created -- 95nov03, cca --------------------------------------------------- */ int EGraph_writeToBinaryFile ( EGraph *egraph, FILE *fp ) { int rc ; int itemp[6] ; /* --------------- check the input --------------- */ if ( egraph == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in EGraph_writeToBinaryFile(%p,%p)" "\n bad input\n", egraph, fp) ; return(0) ; } if ( egraph->type < 0 || 3 < egraph->type ) { fprintf(stderr, "\n fatal error in EGraph_writeToBinaryFile(%p,%p)" "\n bad type = %d", egraph, fp, egraph->type) ; return(0) ; } /* ------------------------------------- write out the three scalar parameters ------------------------------------- */ itemp[0] = egraph->type ; itemp[1] = egraph->nelem ; itemp[2] = egraph->nvtx ; rc = fwrite((void *) itemp, sizeof(int), 6, fp) ; if ( rc != 6 ) { fprintf(stderr, "\n error in EGraph_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", egraph, fp, rc, 6) ; return(0) ; } /* --------------------------------- write out the adjacency structure --------------------------------- */ rc = IVL_writeToBinaryFile(egraph->adjIVL, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in EGraph_writeToBinaryFile(%p,%p)" "\n rc = %d, return from IVL_writeToBinaryFile(%p,%p)" "\n while attempting to write out adj\n", egraph, fp, rc, egraph->adjIVL, fp) ; return(0) ; } /* ----------------------------------------- write out the vwghts[] vector, if present ----------------------------------------- */ if ( egraph->type % 2 == 1 ) { if ( egraph->vwghts == NULL ) { fprintf(stderr, "\n fatal error in EGraph_writeToBinaryFile(%p,%p)" "\n egraph->type = %d, egraph->vwghts == NULL\n", egraph, fp, egraph->type) ; return(0) ; } rc = fwrite((void *) egraph->vwghts, sizeof(int), egraph->nvtx, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in EGraph_writeToBinaryFile(%p,%p)" "\n rc = %d, return from vwghts[] fwrite\n", egraph, fp, rc) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to write a EGraph object for a human eye return value -- 1 if success, 0 otherwise created -- 95nov03, cca ------------------------------------------------- */ int EGraph_writeForHumanEye ( EGraph *egraph, FILE *fp ) { int ierr, rc ; /* --------------- check the input --------------- */ if ( egraph == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in EGraph_writeForHumanEye(%p,%p)" "\n bad input\n", egraph, fp) ; exit(-1) ; } /* ------------------------ write out the statistics ------------------------ */ if ( (rc = EGraph_writeStats(egraph, fp)) == 0 ) { fprintf(stderr, "\n fatal error in EGraph_writeForHumanEye(%p,%p)" "\n rc = %d, return from EGraph_writeStats(%p,%p)\n", egraph, fp, rc, egraph, fp) ; return(0) ; } if ( egraph->adjIVL != NULL ) { /* ---------------------------------- write out the adjacency IVL object ---------------------------------- */ fprintf(fp, "\n\n adjacency IVL object") ; rc = IVL_writeForHumanEye(egraph->adjIVL, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in EGraph_writeForHumanEye(%p,%p)" "\n rc = %d, return from IVL_writeForHumanEye(%p,%p)" "\n while attempting to write out adjIVL\n", egraph, fp, rc, egraph->adjIVL, fp) ; return(0) ; } } /* ---------------------------------------------- write out the vertex weights vector if present ---------------------------------------------- */ if ( egraph->type % 2 == 1 ) { if ( egraph->vwghts == NULL ) { fprintf(stderr, "\n fatal error in EGraph_writeForHumanEye(%p,%p)" "\n egraph->type = %d, egraph->vwghts == NULL\n", egraph, fp, egraph->type) ; return(0) ; } fprintf(fp, "\n\n vertex weights ") ; IVfp80(fp, egraph->nvtx, egraph->vwghts, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in EGraph_writeForHumanEye(%p,%p)" "\n ierr = %d, return from vwghts[] IVfp80\n", egraph, fp, ierr) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to write out the statistics for the EGraph object return value -- 1 if success, 0 otherwise created -- 95nov03, cca ----------------------------------------------------------- */ int EGraph_writeStats ( EGraph *egraph, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( egraph == NULL || fp == NULL ) { fprintf(stderr, "\n error in EGraph_writeStats(%p,%p)" "\n bad input\n", egraph, fp) ; exit(-1) ; } switch ( egraph->type ) { case 0 : rc = fprintf(fp, "\n EGraph : unweighted egraph object :") ; break ; case 1 : rc = fprintf(fp, "\n EGraph : vertices weighted egraph object :") ; break ; default : fprintf(stderr, "\n fatal error in EGraph_writeStats(%p,%p)" "\n invalid egraph->type = %d\n", egraph, fp, egraph->type) ; return(0) ; } if ( rc < 0 ) { goto IO_error ; } fflush(fp) ; rc = fprintf(fp, " %d elements, %d vertices", egraph->nelem, egraph->nvtx) ; if ( rc < 0 ) { goto IO_error ; } fflush(fp) ; return(1) ; IO_error : fprintf(stderr, "\n fatal error in EGraph_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", egraph, fp, rc) ; return(0) ; } /*--------------------------------------------------------------------*/ or in EGraph_writeToFile(%p,%s)" "\n bad type = %d", egraph, fn, egraph->type) ; return(0) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulengthEGraph/src/basics.c010064400020550007177000000044210653410610000154320ustar00clevecompmath00000400000006/* basics.c */ #include "../EGraph.h" /*--------------------------------------------------------------------*/ /* ----------------------- constructor created -- 95nov03, cca ----------------------- */ EGraph * EGraph_new ( void ) { EGraph *eg ; ALLOCATE(eg, struct _EGraph, 1) ; EGraph_setDefaultFields(eg) ; return(eg) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 95nov03, cca ----------------------- */ void EGraph_setDefaultFields ( EGraph *eg ) { if ( eg == NULL ) { fprintf(stderr, "\n fatal error in Egraph_setDefaultFields(%p)" "\n bad input\n", eg) ; exit(-1) ; } eg->type = 0 ; eg->nelem = 0 ; eg->nvtx = 0 ; eg->adjIVL = NULL ; eg->vwghts = NULL ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields created -- 95nov03, cca ----------------------- */ void EGraph_clearData ( EGraph *eg ) { if ( eg == NULL ) { fprintf(stderr, "\n fatal error in Egraph_clearData(%p)" "\n bad input\n", eg) ; exit(-1) ; } if ( eg->adjIVL != NULL ) { IVL_free(eg->adjIVL) ; } if ( eg->vwghts != NULL ) { IVfree(eg->vwghts) ; } EGraph_setDefaultFields(eg) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- destructor created -- 95nov03, cca ----------------------- */ void EGraph_free ( EGraph *eg ) { if ( eg == NULL ) { fprintf(stderr, "\n fatal error in Egraph_free(%p)" "\n bad input\n", eg) ; exit(-1) ; } EGraph_clearData(eg) ; FREE(eg) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95nov03, cca ---------------------------------------------- */ int EGraph_sizeOf ( EGraph *eg ) { int bytes ; bytes = sizeof(struct _EGraph) ; if ( eg->adjIVL != NULL ) { bytes += IVL_sizeOf(eg->adjIVL) ; } if ( eg->vwghts != NULL ) { bytes += eg->nvtx * sizeof(int) ; } return(bytes) ; } /*--------------------------------------------------------------------*/ EGraph/src/init.c010064400020550007177000000022460653410610000151340ustar00clevecompmath00000400000006/* init.c */ #include "../EGraph.h" /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- initialize the EGraph object created -- 96oct24, cca --------------------------------------- */ void EGraph_init ( EGraph *egraph, int type, int nelem, int nvtx, int IVL_type ) { /* --------------- check the input --------------- */ if ( egraph == NULL || type < 0 || type > 1 || nelem <= 0 || nvtx <= 0 ) { fprintf(stderr, "\n fatal error in EGraph_init(%p,%d,%d,%d,%d)" "\n bad input\n", egraph, type, nelem, nvtx, IVL_type) ; exit(-1) ; } /* ---------------------------- clear the data in the object ---------------------------- */ EGraph_clearData(egraph) ; /* --------------------- initialize the object --------------------- */ egraph->type = type ; egraph->nelem = nelem ; egraph->nvtx = nvtx ; egraph->adjIVL = IVL_new() ; IVL_init1(egraph->adjIVL, IVL_type, nelem) ; if ( type == 1 ) { egraph->vwghts = IVinit(nvtx, 0) ; } return ; } /*--------------------------------------------------------------------*/ EGraph/src/misc.c010064400020550007177000000121070653410610000151210ustar00clevecompmath00000400000006/* misc.C */ #include "../EGraph.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- make an element graph for a n1 x n2 grid with ncomp components created -- 95nov03, cca -------------------------------------------------------------- */ EGraph * EGraph_make9P ( int n1, int n2, int ncomp ) { EGraph *egraph ; int eid, icomp, ij, ielem, jelem, m, nelem, nvtx ; int *list ; #if MYDEBUG > 0 fprintf(stdout, "\n inside EGraph_make9P(%d,%d,%d)", n1, n2, ncomp) ; fflush(stdout) ; #endif /* --------------- check the input --------------- */ if ( n1 <= 0 || n2 <= 0 || ncomp <= 0 ) { fprintf(stderr, "\n fatal error in EGraph_make9P(%d,%d,%d)" "\n bad input\n", n1, n2, ncomp) ; exit(-1) ; } /* ----------------- create the object ----------------- */ nelem = (n1 - 1)*(n2 - 1) ; nvtx = n1*n2*ncomp ; egraph = EGraph_new() ; if ( ncomp == 1 ) { EGraph_init(egraph, 0, nelem, nvtx, IVL_CHUNKED) ; } else { EGraph_init(egraph, 1, nelem, nvtx, IVL_CHUNKED) ; IVfill(nvtx, egraph->vwghts, ncomp) ; } /* ---------------------------- fill the adjacency structure ---------------------------- */ list = IVinit(4*ncomp, -1) ; for ( jelem = 0 ; jelem < n2 - 1 ; jelem++ ) { for ( ielem = 0 ; ielem < n1 - 1 ; ielem++ ) { eid = ielem + jelem * (n1 - 1) ; m = 0 ; ij = ncomp*(ielem + jelem*n1) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ij++ ; } ij = ncomp*(ielem + 1 + jelem*n1) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ij++ ; } ij = ncomp*(ielem + (jelem+1)*n1) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ij++ ; } ij = ncomp*(ielem + 1 + (jelem+1)*n1) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ij++ ; } IVqsortUp(m, list) ; IVL_setList(egraph->adjIVL, eid, m, list) ; } } IVfree(list) ; return(egraph) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- make an element graph for a n1 x n2 x n3 grid with ncomp components created -- 95nov03, cca ------------------------------------------------------------------- */ EGraph * EGraph_make27P ( int n1, int n2, int n3, int ncomp ) { EGraph *egraph ; int eid, icomp, ijk, ielem, jelem, kelem, m, nelem, nvtx ; int *list ; /* --------------- check the input --------------- */ if ( n1 <= 0 || n2 <= 0 || n3 <= 0 || ncomp <= 0 ) { fprintf(stderr, "\n fatal error in EGraph_make27P(%d,%d,%d,%d)" "\n bad input\n", n1, n2, n3, ncomp) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n inside EGraph_make27P(%d,%d,%d,%d)", n1, n2, n3, ncomp) ; fflush(stdout) ; #endif /* ----------------- create the object ----------------- */ nelem = (n1 - 1)*(n2 - 1)*(n3 - 1) ; nvtx = n1*n2*n3*ncomp ; egraph = EGraph_new() ; if ( ncomp == 1 ) { EGraph_init(egraph, 0, nelem, nvtx, IVL_CHUNKED) ; } else { EGraph_init(egraph, 1, nelem, nvtx, IVL_CHUNKED) ; IVfill(nvtx, egraph->vwghts, ncomp) ; } /* ---------------------------- fill the adjacency structure ---------------------------- */ list = IVinit(8*ncomp, -1) ; for ( kelem = 0 ; kelem < n3 - 1 ; kelem++ ) { for ( jelem = 0 ; jelem < n2 - 1 ; jelem++ ) { for ( ielem = 0 ; ielem < n1 - 1 ; ielem++ ) { eid = ielem + jelem*(n1-1) + kelem*(n1-1)*(n2-1); m = 0 ; ijk = ncomp*(ielem + jelem*n1 + kelem*n1*n2) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ijk++ ; } ijk = ncomp*(ielem + 1 + jelem*n1 + kelem*n1*n2) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ijk++ ; } ijk = ncomp*(ielem + (jelem+1)*n1 + kelem*n1*n2) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ijk++ ; } ijk = ncomp*(ielem + 1 + (jelem+1)*n1 + kelem*n1*n2) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ijk++ ; } ijk = ncomp*(ielem + jelem*n1 + (kelem+1)*n1*n2) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ijk++ ; } ijk = ncomp*(ielem + 1 + jelem*n1 + (kelem+1)*n1*n2) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ijk++ ; } ijk = ncomp*(ielem + (jelem+1)*n1 + (kelem+1)*n1*n2) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ijk++ ; } ijk = ncomp*(ielem + 1 + (jelem+1)*n1 + (kelem+1)*n1*n2) ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { list[m++] = ijk++ ; } IVqsortUp(m, list) ; IVL_setList(egraph->adjIVL, eid, m, list) ; } } } IVfree(list) ; return(egraph) ; } /*--------------------------------------------------------------------*/ EGraph/src/mkAdjGraph.c010064400020550007177000000064110653577244000162200ustar00clevecompmath00000400000006/* mkAdjGraph.c.c */ #include "../EGraph.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- create a Graph object that holds the adjacency graph of the assembled elements. created -- 95nov03, cca ---------------------------------------------------- */ Graph * EGraph_mkAdjGraph ( EGraph *egraph ) { int elem, esize, i, nelem, nvtx, v, vsize, w ; int *eind, *head, *link, *marker, *offsets, *vind ; IVL *eadjIVL, *gadjIVL ; Graph *graph ; /* --------------- check the input --------------- */ if ( egraph == NULL || (eadjIVL = egraph->adjIVL) == NULL ) { fprintf(stderr, "\n fatal error in EGraph_mkAdjGraph(%p)" "\n bad input\n", egraph) ; exit(-1) ; } nelem = egraph->nelem ; nvtx = egraph->nvtx ; /* -------------------------------- set up the linked list structure -------------------------------- */ head = IVinit(nvtx, -1) ; link = IVinit(nelem, -1) ; offsets = IVinit(nelem, 0) ; /* ----------------------------------------------------------- sort the vertices in each element list into ascending order and link them into their first vertex ----------------------------------------------------------- */ for ( elem = 0 ; elem < nelem ; elem++ ) { IVL_listAndSize(eadjIVL, elem, &esize, &eind) ; if ( esize > 0 ) { IVqsortUp(esize, eind) ; v = eind[0] ; link[elem] = head[v] ; head[v] = elem ; } } /* --------------------------- create the new Graph object --------------------------- */ graph = Graph_new() ; Graph_init1(graph, egraph->type, nvtx, 0, 0, IVL_CHUNKED, IVL_CHUNKED) ; gadjIVL = graph->adjIVL ; /* ---------------------- loop over the vertices ---------------------- */ vind = IVinit(nvtx, -1) ; marker = IVinit(nvtx, -1) ; for ( v = 0 ; v < nvtx ; v++ ) { /* --------------------------------- loop over the supporting elements --------------------------------- */ vsize = 0 ; vind[vsize++] = v ; marker[v] = v ; while ( (elem = head[v]) != -1 ) { /* fprintf(stdout, "\n checking out element %d :", jelem) ; */ head[v] = link[elem] ; IVL_listAndSize(eadjIVL, elem, &esize, &eind) ; for ( i = 0 ; i < esize ; i++ ) { w = eind[i] ; if ( marker[w] != v ) { marker[w] = v ; vind[vsize++] = w ; } } if ( (i = ++offsets[elem]) < esize ) { w = eind[i] ; link[elem] = head[w] ; head[w] = elem ; } } IVqsortUp(vsize, vind) ; IVL_setList(gadjIVL, v, vsize, vind) ; } graph->nedges = gadjIVL->tsize ; if ( egraph->type == 0 ) { graph->totvwght = nvtx ; } else if ( egraph->type == 1 ) { /* ------------------------------ fill the vertex weights vector ------------------------------ */ IVcopy(nvtx, graph->vwghts, egraph->vwghts) ; graph->totvwght = IVsum(nvtx, graph->vwghts) ; } graph->totewght = graph->nedges ; /* ------------------------ free the working storage ------------------------ */ IVfree(head) ; IVfree(link) ; IVfree(marker) ; IVfree(vind) ; IVfree(offsets) ; return(graph) ; } /*--------------------------------------------------------------------*/ EGraph/drivers/do_mkGraph010075500020550007177000000004230653410607700167250ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inFile = $matrices/$matrix/orig.egraphf set outFile = $matrices/$matrix/orig0.graphf set outFile = temp.graphf set msglvl = 3 set msgFile = stdout mkGraph $msglvl $msgFile $inFile $outFile EGraph/drivers/do_mkGridEGraph010075500020550007177000000003050653410607700176370ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 3 set msgFile = stdout set n1 = 3 set n2 = 3 set n3 = 3 set ncomp = 1 set outFile = temp.egraphf mkGridEGraph $msglvl $msgFile $n1 $n2 $n3 $ncomp $outFile EGraph/drivers/do_testIO010075500020550007177000000004130653410607700165420ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inFile = $matrices/$matrix/orig.egraphf set outFile = $matrices/$matrix/orig.egraphb set outFile = none set msglvl = 3 set msgFile = stdout testIO $msglvl $msgFile $inFile $outFile EGraph/drivers/makefile010064400020550007177000000010360665314242600164250ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testIO \ mkGraph \ mkGridEGraph drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} mkGraph : mkGraph.o ../../spooles.a $(PURIFY) $(CC) $@.o -o $@ $(PURIFY_GCC_VERSION) $(LIBS) mkGridEGraph : mkGridEGraph.o ../../spooles.a $(PURIFY) $(CC) $@.o -o $@ $(PURIFY_GCC_VERSION)$(LIBS) testIO : testIO.o ../../spooles.a $(PURIFY) $(CC) $@.o -o $@ $(PURIFY_GCC_VERSION) $(LIBS) EGraph/drivers/mkGraph.c010064400020550007177000000057670654222402100164660ustar00clevecompmath00000400000006/* mkGraph.c */ #include "../EGraph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------------------------- 1. read in EGraph object 2. convert to Graph object 3. write Graph object to file created -- 96feb09, cca -------------------------------------------------- */ { double t1, t2 ; int msglvl, rc ; EGraph *egraph ; FILE *msgFile ; Graph *graph ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inEGraphFile outGraphFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inEGraphFile -- input file, must be *.egraphf or *.egraphb" "\n outGraphFile -- output file, must be *.graphf or *.graphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], argv[3], argv[4]) ; fflush(msgFile) ; /* ------------------------- read in the EGraph object ------------------------- */ if ( strcmp(argv[3], "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; egraph = EGraph_new() ; EGraph_setDefaultFields(egraph) ; rc = EGraph_readFromFile(egraph, argv[3]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in egraph from file %s", t2 - t1, argv[3]) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from EGraph_readFromFile(%p,%s)", rc, egraph, argv[3]) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading EGraph object from file %s", argv[3]) ; EGraph_writeForHumanEye(egraph, msgFile) ; fflush(msgFile) ; } /* ----------------------- create the Graph object ----------------------- */ MARKTIME(t1) ; graph = EGraph_mkAdjGraph(egraph) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : convert to Graph object", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Graph object") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* -------------------------- write out the Graph object -------------------------- */ if ( strcmp(argv[4], "none") != 0 ) { MARKTIME(t1) ; rc = Graph_writeToFile(graph, argv[4]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write graph to file %s", t2 - t1, argv[4]) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_writeToFile(%p,%s)", rc, graph, argv[4]) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ EGraph/drivers/mkGridEGraph.c010064400020550007177000000053310654222376300174000ustar00clevecompmath00000400000006/* mkGridEgraph.c */ #include "../EGraph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- generate an Egraph object for a 9pt or 27pt grid optionally write out to a file created -- 95nov08, cca ------------------------------------------------- */ { double t1, t2 ; int msglvl, n1, n2, n3, ncomp, rc ; EGraph *eg ; FILE *msgFile ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 ncomp outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- # of points in first grid direction" "\n n2 -- # of points in second grid direction" "\n n3 -- # of points in third grid direction" "\n ncomp -- # of components per grid point" "\n outFile -- output file, must be *.egraphf or *.egraphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; n3 = atoi(argv[5]) ; ncomp = atoi(argv[6]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n n1 -- %d" "\n n2 -- %d" "\n n3 -- %d" "\n ncomp -- %d" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], n1, n2, n3, ncomp, argv[7]) ; fflush(msgFile) ; /* --------------------------- create in the EGraph object --------------------------- */ MARKTIME(t1) ; if ( n3 == 1 ) { eg = EGraph_make9P(n1, n2, ncomp) ; } else { eg = EGraph_make27P(n1, n2, n3, ncomp) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : create the Egraph object", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n EGraph object") ; EGraph_writeForHumanEye(eg, msgFile) ; fflush(msgFile) ; } /* --------------------------- write out the EGraph object --------------------------- */ if ( strcmp(argv[7], "none") != 0 ) { MARKTIME(t1) ; rc = EGraph_writeToFile(eg, argv[7]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write graph to file %s", t2 - t1, argv[7]) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_writeToFile(%p,%s)", rc, eg, argv[7]) ; } } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ EGraph/drivers/testIO.c010064400020550007177000000055650654222377600163200ustar00clevecompmath00000400000006/* testIO.c */ #include "../EGraph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------------------------- test EGraph_readFromFile and EGraph_writeToFile, useful for translating between formatted *.egraphf and binary *.egraphb files. created -- 95nov03, cca -------------------------------------------------- */ { double t1, t2 ; int msglvl, rc ; EGraph egraph ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.egraphf or *.egraphb" "\n outFile -- output file, must be *.egraphf or *.egraphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], argv[3], argv[4]) ; fflush(msgFile) ; /* ---------------------- set the default fields ---------------------- */ EGraph_setDefaultFields(&egraph) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after setting default fields") ; EGraph_writeForHumanEye(&egraph, msgFile) ; fflush(msgFile) ; } /* ------------------------- read in the EGraph object ------------------------- */ if ( strcmp(argv[3], "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; rc = EGraph_readFromFile(&egraph, argv[3]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in egraph from file %s", t2 - t1, argv[3]) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from EGraph_readFromFile(%p,%s)", rc, &egraph, argv[3]) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading EGraph object from file %s", argv[3]) ; EGraph_writeForHumanEye(&egraph, msgFile) ; fflush(msgFile) ; } /* --------------------------- write out the EGraph object --------------------------- */ if ( strcmp(argv[4], "none") != 0 ) { MARKTIME(t1) ; rc = EGraph_writeToFile(&egraph, argv[4]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write egraph to file %s", t2 - t1, argv[4]) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from EGraph_writeToFile(%p,%s)", rc, &egraph, argv[4]) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ EGraph/doc/004275500020550007177000000000000654276737700140405ustar00clevecompmath00000400000006EGraph/doc/dataStructure.tex010064000020550007177000000015440653410610000173530ustar00clevecompmath00000400000006\par \section{Data Structure} \par The {\tt EGraph} object has five fields. \begin{itemize} \item {\tt int type} : type of graph. When {\tt type = 0}, the vertices have unit weight When {\tt type = 1}, the vertices have possibly non-unit weight and the {\tt vwghts} field is not {\tt NULL}. \item {\tt int nelem} : number of elements in the graph \item {\tt int nvtx} : number of vertices in the graph \item {\tt IVL *adjIVL} : pointer to a {\tt IVL} structure that holds the vertex lists for the elements. \item {\tt int *vwghts} : when {\tt type = 1}, {\tt vwghts} points to an {\tt int} vector of size {\tt nvtx} that holds the node weights. \end{itemize} A correctly initialized and nontrivial {\tt EGraph} object will have positive {\tt nelem} and {\tt nvtx} values, a valid {\tt adjIVL} field. If {\tt type = 1}, the {\tt vwghts} will be non-{\tt NULL}. EGraph/doc/intro.tex010064000020550007177000000023710653410610000156530ustar00clevecompmath00000400000006\chapter{{\tt EGraph}: Element Graph Object} \par The {\tt EGraph} object is used to model a graph that has a natural element structure (as from finite elements) or a natural covering clique structure (e.g., the rows of $A$ are natural cliques for the graph of $A^TA$). \par Translating an element graph {\tt EGraph} object into an adjacency list {\tt Graph} object is an easy task --- we provide a method to do so --- but the process in reverse is much more difficult. Given a {\tt Graph} object, it is simple to construct a trivial element graph object, simply take each $(i,j)$ edge to be an element. Constructing an element graph with a smaller number of elements is more difficult. \par Element graphs, when they arise naturally or are constructed from an adjacency graph, have great potential. The element model for sparse elimination {\it appears} to be more powerful than the vertex adjacency list model in the sense that concepts like indistinguishability, outmatching and deficiency are more naturally defined with elements. An element graph might be a more natural vehicle for partitioning graphs, because if one consider elements as the ``nodes'' in a Kernighan-Lin type algorithm, then the ``edge'' separators are formed of vertices of the original graph. EGraph/doc/main.tex010064400020550007177000000011020665065621700154610ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt EGraph} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt EGraph} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} EGraph/doc/main.ind010064400020550007177000000012320653577227700154460ustar00clevecompmath00000400000006\begin{theindex} \item {\tt EGraph\_clearData()}, 2 \item {\tt EGraph\_free()}, 2 \item {\tt EGraph\_init()}, 2 \item {\tt EGraph\_make27P()}, 3 \item {\tt EGraph\_make9P()}, 3 \item {\tt EGraph\_mkAdjGraph()}, 3 \item {\tt EGraph\_new()}, 2 \item {\tt EGraph\_readFromBinaryFile()}, 3 \item {\tt EGraph\_readFromFile()}, 3 \item {\tt EGraph\_readFromFormattedFile()}, 3 \item {\tt EGraph\_setDefaultFields()}, 2 \item {\tt EGraph\_writeForHumanEye()}, 4 \item {\tt EGraph\_writeStats()}, 4 \item {\tt EGraph\_writeToBinaryFile()}, 4 \item {\tt EGraph\_writeToFile()}, 4 \item {\tt EGraph\_writeToFormattedFile()}, 4 \end{theindex} EGraph/doc/main.log010064400020550007177000000062720653577230200154530ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 5 JUN 1998 06:38 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. ) (dataStructure.tex) (proto.tex [1 ] Overfull \hbox (12.76239pt too wide) in paragraph at lines 43--53 \elvrm is not \elvtt NULL\elvrm , then \elvtt IVL[]free(egraph->adjIVL) \elvrm is called to free the \elvtt IVL \elvrm ob-ject. If \elvtt egraph->vwghts \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\elvrm i .\elvrm s .\glue 3.65 plus 1.825 minus 1.21666 .\elvrm n .\elvrm o .etc. [2] Overfull \hbox (3.0602pt too wide) in paragraph at lines 138--145 \elvrm the grid points. The re-sult-ing graph has \elvtt n1*n2*n3*ncomp \elvrm ver-tices and \elvtt (n1-1)*(n2-1)*(n3-1) \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\elvrm t .\elvrm h .\elvrm e .\glue 3.65 plus 1.825 minus 1.21666 .\elvrm g .etc. [3]) (drivers.tex Overfull \hbox (42.63402pt too wide) in paragraph at lines 30--35 \elvtt *.egraphf \elvrm or \elvtt *.egraphb\elvrm . The \elvtt EGraph \elvrm ob -ject is read from the file via the \elvtt EGraph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt e .\elvtt g .\elvtt r .etc. [4] Overfull \hbox (1.44826pt too wide) in paragraph at lines 114--122 [] []\elvrm The \elvtt outEGraphFile \elvrm pa-ram-e-ter is the out-put file fo r the \elvtt EGraph \elvrm ob-ject. If \elvtt outEGraphFile \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm T .etc. Overfull \hbox (18.78839pt too wide) in paragraph at lines 114--122 \elvrm is \elvtt none \elvrm then the \elvtt EGraph \elvrm ob-ject is not writ- ten to a file. Oth-er-wise, the \elvtt EGraph[]writeToFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvrm i .\elvrm s .\glue 3.65 plus 1.825 minus 1.21666 .\elvtt n .\elvtt o .etc. [5]) (main.ind [6] [7 ]) (main.aux) ) Here is how much of TeX's memory you used: 207 strings out of 11977 2133 string characters out of 87269 33495 words of memory out of 262141 2141 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 14i,4n,17p,183b,260s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (7 pages, 18668 bytes). EGraph/doc/main.aux010064400020550007177000000025640653577230200154670ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space EGraph}: Element Graph Object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space EGraph} methods}{2}} \newlabel{section:EGraph:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:EGraph:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initializer methods}{2}} \newlabel{subsection:EGraph:proto:initializers}{{1.2.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{3}} \newlabel{subsection:EGraph:proto:utilities}{{1.2.3}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}IO methods}{3}} \newlabel{subsection:EGraph:proto:IO}{{1.2.4}{3}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs for the {\string\ptt\space EGraph} object}{4}} \newlabel{section:EGraph:drivers}{{1.3}{4}} EGraph/doc/main.idx010064400020550007177000000020000653577230200154370ustar00clevecompmath00000400000006\indexentry{EGraph_new@{\tt EGraph\_new()}}{2} \indexentry{EGraph_setDefaultFields@{\tt EGraph\_setDefaultFields()}}{2} \indexentry{EGraph_clearData@{\tt EGraph\_clearData()}}{2} \indexentry{EGraph_free@{\tt EGraph\_free()}}{2} \indexentry{EGraph_init@{\tt EGraph\_init()}}{2} \indexentry{EGraph_mkAdjGraph@{\tt EGraph\_mkAdjGraph()}}{3} \indexentry{EGraph_make9P@{\tt EGraph\_make9P()}}{3} \indexentry{EGraph_make27P@{\tt EGraph\_make27P()}}{3} \indexentry{EGraph_readFromFile@{\tt EGraph\_readFromFile()}}{3} \indexentry{EGraph_readFromFormattedFile@{\tt EGraph\_readFromFormattedFile()}}{3} \indexentry{EGraph_readFromBinaryFile@{\tt EGraph\_readFromBinaryFile()}}{3} \indexentry{EGraph_writeToFile@{\tt EGraph\_writeToFile()}}{4} \indexentry{EGraph_writeToFormattedFile@{\tt EGraph\_writeToFormattedFile()}}{4} \indexentry{EGraph_writeToBinaryFile@{\tt EGraph\_writeToBinaryFile()}}{4} \indexentry{EGraph_writeForHumanEye@{\tt EGraph\_writeForHumanEye()}}{4} \indexentry{EGraph_writeStats@{\tt EGraph\_writeStats()}}{4} EGraph/doc/proto.tex010064400020550007177000000262500653410610000156710ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt EGraph} methods} \label{section:EGraph:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt EGraph} object. \par \subsection{Basic methods} \label{subsection:EGraph:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} EGraph * EGraph_new ( void ) ; \end{verbatim} \index{EGraph_new@{\tt EGraph\_new()}} This method simply allocates storage for the {\tt EGraph} structure and then sets the default fields by a call to {\tt EGraph\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void EGraph_setDefaultFields ( EGraph *egraph ) ; \end{verbatim} \index{EGraph_setDefaultFields@{\tt EGraph\_setDefaultFields()}} This method sets the structure's fields are set to default values: {\tt type = nelem = nvtx = 0}, {\tt adjIVL = vwghts = NULL}. \par \noindent {\it Error checking:} If {\tt egraph} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void EGraph_clearData ( EGraph *egraph ) ; \end{verbatim} \index{EGraph_clearData@{\tt EGraph\_clearData()}} This method clears data and releases any storage allocated by the object. If {\tt egraph->adjIVL} is not {\tt NULL}, then {\tt IVL\_free(egraph->adjIVL)} is called to free the {\tt IVL} object. If {\tt egraph->vwghts} is not {\tt NULL}, then {\tt IVfree(egraph->vwghts)} is called to free the {\tt int} vector. It then sets the structure's default fields with a call to {\tt EGraph\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt egraph} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void EGraph_free ( EGraph *egraph ) ; \end{verbatim} \index{EGraph_free@{\tt EGraph\_free()}} This method releases any storage by a call to {\tt EGraph\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt egraph} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:EGraph:proto:initializers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void EGraph_init ( EGraph *egraph, int type, int nelem, int nvtx, int IVL_type ) ; \end{verbatim} \index{EGraph_init@{\tt EGraph\_init()}} This method initializes an {\tt EGraph} object given the type of vertices, number of elements, number of vertices, and storage type for the {\tt IVL} element list object. It then clears any previous data with a call to {\tt EGraph\_clearData()}. The {\tt IVL} object is initialized by a call to {\tt IVL\_init1()}. If {\tt type = 1}, the {\tt vwghts} is initialized via a call to {\tt IVinit()}. See the {\tt IVL} object for a description of the {\tt IVL\_type} parameter. \par \noindent {\it Error checking:} If {\tt egraph} is {\tt NULL} or {\tt type} is not zero or one, or if either {\tt nelem} or {\tt nvtx} are nonpositive, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:EGraph:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Graph EGraph_mkAdjGraph ( EGraph *egraph ) ; \end{verbatim} \index{EGraph_mkAdjGraph@{\tt EGraph\_mkAdjGraph()}} This method creates and returns a {\tt Graph} object with vertex adjacency lists from the element graph object. \par \noindent {\it Error checking:} If {\tt egraph} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} EGraph * EGraph_make9P ( int n1, int n2, int ncomp ) ; \end{verbatim} \index{EGraph_make9P@{\tt EGraph\_make9P()}} This method creates and returns a {\tt EGraph} object for a $\mbox{\tt n1} \times \mbox{\tt n2}$ grid for a 9-point operator matrix. Each element is a linear quadrilateral finite element with {\tt ncomp} degrees of freedom at the grid points. The resulting graph has {\tt n1*n2*ncomp} vertices and {\tt (n1-1)*(n2-1)} elements. \par \noindent {\it Error checking:} If {\tt n1}, {\tt n2} or {\tt ncomp} is less than or equal to zero, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} EGraph * EGraph_make27P ( int n1, int n2, int n3, int ncomp ) ; \end{verbatim} \index{EGraph_make27P@{\tt EGraph\_make27P()}} This method creates and returns a {\tt EGraph} object for a $\mbox{\tt n1} \times \mbox{\tt n2} \times \mbox{\tt n3}$ grid for a 27-point operator matrix. Each element is a linear hexahedral finite element with {\tt ncomp} degrees of freedom at the grid points. The resulting graph has {\tt n1*n2*n3*ncomp} vertices and {\tt (n1-1)*(n2-1)*(n3-1)} elements. \par \noindent {\it Error checking:} If {\tt n1}, {\tt n2}, {\tt n3} or {\tt ncomp} is less than or equal to zero, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:EGraph:proto:IO} \par There are the usual eight IO routines. The file structure of a EGraph object is simple: {\tt type}, {\tt nelem}, {\tt nvtx}, an {\tt IVL} object, and an {\tt int} vector if {\tt vwghts} is not {\tt NULL}. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int EGraph_readFromFile ( EGraph *egraph, char *fn ) ; \end{verbatim} \index{EGraph_readFromFile@{\tt EGraph\_readFromFile()}} \par This method reads an {\tt EGraph} object from a file. It tries to open the file and if it is successful, it then calls {\tt EGraph\_readFromFormattedFile()} or {\tt EGraph\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt egraph} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.egraphf} (for a formatted file) or {\tt *.egraphb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int EGraph_readFromFormattedFile ( EGraph *egraph, FILE *fp ) ; \end{verbatim} \index{EGraph_readFromFormattedFile@{\tt EGraph\_readFromFormattedFile()}} \par This method reads in an {\tt EGraph} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt egraph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int EGraph_readFromBinaryFile ( EGraph *egraph, FILE *fp ) ; \end{verbatim} \index{EGraph_readFromBinaryFile@{\tt EGraph\_readFromBinaryFile()}} \par This method reads in an {\tt EGraph} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt egraph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int EGraph_writeToFile ( EGraph *egraph, char *fn ) ; \end{verbatim} \index{EGraph_writeToFile@{\tt EGraph\_writeToFile()}} \par This method writes an {\tt EGraph} object to a file. It tries to open the file and if it is successful, it then calls {\tt EGraph\_writeFromFormattedFile()} or {\tt EGraph\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt egraph} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.egraphf} (for a formatted file) or {\tt *.egraphb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int EGraph_writeToFormattedFile ( EGraph *egraph, FILE *fp ) ; \end{verbatim} \index{EGraph_writeToFormattedFile@{\tt EGraph\_writeToFormattedFile()}} \par This method writes an {\tt EGraph} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt egraph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int EGraph_writeToBinaryFile ( EGraph *egraph, FILE *fp ) ; \end{verbatim} \index{EGraph_writeToBinaryFile@{\tt EGraph\_writeToBinaryFile()}} \par This method writes an {\tt EGraph} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt egraph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int EGraph_writeForHumanEye ( EGraph *egraph, FILE *fp ) ; \end{verbatim} \index{EGraph_writeForHumanEye@{\tt EGraph\_writeForHumanEye()}} \par This method writes an {\tt EGraph} object to a file in a human readable format. The method {\tt EGraph\_writeStats()} is called to write out the header and statistics. Then the {\tt adjIVL} object is written out using {\tt IVL\_writeForHumanEye()}. If the {\tt vwghts} vector is present, the vertex weights are written out. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt egraph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int EGraph_writeStats ( EGraph *egraph, FILE *fp ) ; \end{verbatim} \index{EGraph_writeStats@{\tt EGraph\_writeStats()}} \par This method writes a header and statistics to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt egraph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} us data with a call to {\tt EGraph\_clearData()}. The {\tt IVL} object is initialized by a call to {\tt IVL\_init1()}. If {\tt type = 1}, the {\tt vwghts} is initialized via a call to {\tt IVinit()}. See the {\tt IVL} object for a description of the {\tt IVL\_type} parameter. \par \noindent {\it Error checking:} If {\tt egraph} is {\tt NULLEGraph/doc/main.ilg010064400020550007177000000004560653577227700154560ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (16 entries accepted, 0 rejected). Sorting entries....done (58 comparisons). Generating output file main.ind....done (20 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. EGraph/doc/drivers.tex010064400020550007177000000113250653410610000162010ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt EGraph} object} \label{section:EGraph:drivers} \par This section contains brief descriptions of the driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program reads and writes {\tt EGraph} files, useful for converting formatted files to binary files and vice versa. One can also read in a {\tt EGraph} file and print out just the header information (see the {\tt EGraph\_writeStats()} method). \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt EGraph} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt EGraph} object. It must be of the form {\tt *.egraphf} or {\tt *.egraphb}. The {\tt EGraph} object is read from the file via the {\tt EGraph\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt EGraph} object. If {\tt outFile} is {\tt none} then the {\tt EGraph} object is not written to a file. Otherwise, the {\tt EGraph\_writeToFile()} method is called to write the object to a formatted file (if {\tt outFile} is of the form {\tt *.egraphf}), or a binary file (if {\tt outFile} is of the form {\tt *.egraphb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} mkGraph msglvl msgFile inEGraphFile outGraphFile \end{verbatim} This driver program reads in an {\tt EGraph} object and creates a {\tt Graph} object, which is then optionally written out to a file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt EGraph} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inEGraphFile} parameter is the input file for the {\tt EGraph} object. It must be of the form {\tt *.egraphf} or {\tt *.egraphb}. The {\tt EGraph} object is read from the file via the {\tt EGraph\_readFromFile()} method. \item The {\tt outGraphFile} parameter is the output file for the {\tt Graph} object. If {\tt outGraphFile} is {\tt none} then the {\tt Graph} object is not written to a file. Otherwise, the {\tt Graph\_writeToFile()} method is called to write the object to a formatted file (if {\tt outGraphFile} is of the form {\tt *.graphf}), or a binary file (if {\tt outGraphFile} is of the form {\tt *.graphb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} mkGridEGraph msglvl msgFile n1 n2 n3 ncomp outEGraphFile \end{verbatim} This driver program creates an element graph for linear quadrilateral elements if {\tt n3 = 1} or for linear hexahedral elements if {\tt n3 > 1}. There are {\tt ncomp} degrees of freedom at each grid point. The {\tt EGraph} object is optionally written out to a file. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any message data. \item {\tt n1} is the number of grid points in the first direction, must be greater than one. \item {\tt n2} is the number of grid points in the second direction, must be greater than one. \item {\tt n3} is the number of grid points in the third direction, must be greater than or equal to one. \item {\tt ncomp} is the number of components (i.e., the number of degrees of freedom) at each grid point, must be greater than or equal to one. \item The {\tt outEGraphFile} parameter is the output file for the {\tt EGraph} object. If {\tt outEGraphFile} is {\tt none} then the {\tt EGraph} object is not written to a file. Otherwise, the {\tt EGraph\_writeToFile()} method is called to write the object to a formatted file (if {\tt outEGraphFile} is of the form {\tt *.egraphf}), or a binary file (if {\tt outEGraphFile} is of the form {\tt *.egraphb}). \end{itemize} %----------------------------------------------------------------------- \end{enumerate} EGraph/doc/makefile010064400020550007177000000000270654276737700155320ustar00clevecompmath00000400000006clean : - rm -f *.dvi ETree.h010064400020550007177000000001000653410640100132340ustar00clevecompmath00000400000006#ifndef _ETree_ #define _ETree_ #include "ETree/ETree.h" #endif ETree/ETree.h010064400020550007177000001120530663673505400142720ustar00clevecompmath00000400000006/* ETree.h */ #include "../SPOOLES.h" #include "../cfiles.h" #include "../Graph.h" #include "../Tree.h" #include "../IV.h" #include "../DV.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- the ETree object is a tree that has a weight associated with each node and a weight associated with each node's boundary. it is useful to model: (1) a vertex elimination tree (for a unit weight graph), (2) a compressed vertex elimination tree (for a compressed graph), (3) a front tree (for a factor graph) nfront -- # of fronts nvtx -- # of vertices tree -- pointer to a Tree object, size nfront nodwghtsIV -- IV object of node weights, size nfront bnwwghtsIV -- IV object of node boundary weights, size nfront vtxToFrontIV -- IV object that holds the map from vertices to fronts, size nvtx created -- 96jun23, cca --------------------------------------------------------------------- */ typedef struct _ETree ETree ; struct _ETree { int nfront ; int nvtx ; Tree *tree ; IV *nodwghtsIV ; IV *bndwghtsIV ; IV *vtxToFrontIV ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in basics.c --------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- purpose -- create and return a new ETree object created -- 95nov15, cca ----------------------------------------------- */ ETree * ETree_new ( void ) ; /* ------------------------------------------------------ purpose -- set the default fields for the ETree object created -- 95nov15, cca ------------------------------------------------------ */ void ETree_setDefaultFields ( ETree *etree ) ; /* -------------------------------- purpose -- clear the data fields created -- 95nov15, cca -------------------------------- */ void ETree_clearData ( ETree *etree ) ; /* -------------------------------- purpose -- free the ETree object created -- 95nov15, cca -------------------------------- */ void ETree_free ( ETree *etree ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in instance.c ------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------- return the number of fronts created -- 97feb28, cca --------------------------- */ int ETree_nfront ( ETree *etree ) ; /* ----------------------------- return the number of vertices created -- 97feb28, cca ----------------------------- */ int ETree_nvtx ( ETree *etree ) ; /* ----------------------------------- return a pointer to the Tree object created -- 97feb28, cca ----------------------------------- */ Tree * ETree_tree ( ETree *etree ) ; /* --------------------------- return the root of the tree created -- 97feb28, cca --------------------------- */ int ETree_root ( ETree *etree ) ; /* ------------------------------------- return a pointer to the parent vector created -- 97feb28, cca ------------------------------------- */ int * ETree_par ( ETree *etree ) ; /* ------------------------------------------ return a pointer to the first child vector created -- 97feb28, cca ------------------------------------------ */ int * ETree_fch ( ETree *etree ) ; /* -------------------------------------- return a pointer to the sibling vector created -- 97feb28, cca -------------------------------------- */ int * ETree_sib ( ETree *etree ) ; /* ------------------------------------------ return a pointer to the nodwghts IV object created -- 97feb28, cca ------------------------------------------ */ IV * ETree_nodwghtsIV ( ETree *etree ) ; /* ------------------------------------------- return a pointer to the nodwghts int vector created -- 97feb28, cca ------------------------------------------- */ int * ETree_nodwghts ( ETree *etree ) ; /* ------------------------------------------ return a pointer to the bndwghts IV object created -- 97feb28, cca ------------------------------------------ */ IV * ETree_bndwghtsIV ( ETree *etree ) ; /* ------------------------------------------- return a pointer to the bndwghts int vector created -- 97feb28, cca ------------------------------------------- */ int * ETree_bndwghts ( ETree *etree ) ; /* -------------------------------------------- return a pointer to the vtxToFront IV object created -- 97feb28, cca -------------------------------------------- */ IV * ETree_vtxToFrontIV ( ETree *etree ) ; /* --------------------------------------------- return a pointer to the vtxToFront int vector created -- 97feb28, cca --------------------------------------------- */ int * ETree_vtxToFront ( ETree *etree ) ; /* ------------------------------------------------ purpose -- return the number of internal degrees of freedom in front J created -- 97may23, cca ------------------------------------------------ */ int ETree_frontSize ( ETree *etree, int J ) ; /* ------------------------------------------------ purpose -- return the number of external degrees of freedom in front J created -- 97may23, cca ------------------------------------------------ */ int ETree_frontBoundarySize ( ETree *etree, int J ) ; /* ------------------------------------------------------------ purpose -- compute the maximum number of indices and entries in a front symflag = 1 --> count only column indices count upper entries in (1,1) block and (1,2) block symflag = 2 --> count row and column indices count entries in (1,1), (1,2) and (2,1) blocks created -- 97may23, cca ------------------------------------------------------------ */ void ETree_maxNindAndNent ( ETree *etree, int symflag, int *pmaxnind, int *pmaxnent ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in util.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95nov15, cca ---------------------------------------------- */ int ETree_sizeOf ( ETree *etree ) ; /* ---------------------------------------- return the number of factor indices created -- 95nov15, cca modified -- 96jan11, cca ---------------------------------------- */ int ETree_nFactorIndices ( ETree *etree ) ; /* ------------------------------------------ return the number of factor entries symflag -- symmetry flag 0 (SPOOLES_SYMMETRIC) -- symmetric 1 (SPOOLES_HERMITIAN) -- hermitian 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric created -- 98jun05, cca ------------------------------------------ */ int ETree_nFactorEntries ( ETree *etree, int symflag ) ; /* ------------------------------------------ return the number of factor operations type -- type of matrix entries 1 (SPOOLES_REAL) -- real entries 2 (SPOOLES_COMPLEX) -- complex entries symflag -- symmetry flag 0 (SPOOLES_SYMMETRIC) -- symmetric 1 (SPOOLES_HERMITIAN) -- hermitian 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric created -- 98jun05, cca ------------------------------------------ */ double ETree_nFactorOps ( ETree *etree, int type, int symflag ) ; /* ---------------------------------------- return the number of entries an LU front created -- 96dec04, cca ---------------------------------------- */ double ETree_nFactorEntriesInFront ( ETree *etree, int symflag, int J ) ; /* ------------------------------------------------------- return the number of internal LU operations for a front created -- 96dec04, cca ------------------------------------------------------- */ double ETree_nInternalOpsInFront ( ETree *etree, int type, int symflag, int J ) ; /* ------------------------------------------------------- return the number of external LU operations for a front created -- 96dec04, cca ------------------------------------------------------- */ double ETree_nExternalOpsInFront ( ETree *etree, int type, int symflag, int J ) ; /* ------------------------------------ return an IV object that contains the number of entries for each front created -- 98jan30, cca ------------------------------------ */ IV * ETree_factorEntriesIV ( ETree *etree, int symflag ) ; /* --------------------------------------------------------- return a DV object that contains the number of operations for each front using a backward looking algorithm created -- 96dec04, cca --------------------------------------------------------- */ DV * ETree_backwardOps ( ETree *etree, int type, int symflag, int *vwghts, IVL *symbfacIVL ) ; /* --------------------------------------------------------- return a DV object that contains the number of operations for each front using a forward-looking algorithm created -- 96dec04, cca --------------------------------------------------------- */ DV * ETree_forwardOps ( ETree *etree, int type, int symflag ) ; /* --------------------------------------------------------------- given an IV object that maps uncompressed vertices to vertices, create and return an ETree object that is relative to the uncompressed graph. created -- 97feb13, cca --------------------------------------------------------------- */ ETree * ETree_expand ( ETree *etree, IV *eqmapIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in init.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- initialize the object given the number of nodes created -- 95nov15, cca ----------------------------------------------- */ void ETree_init1 ( ETree *etree, int nfront, int nvtx ) ; /* ---------------------------------------- initialize the ETree object from a graph created -- 95nov15, cca ---------------------------------------- */ void ETree_initFromGraph ( ETree *etree, Graph *g ) ; /* -------------------------------------------------------- initialize the ETree object from a graph and permutation created -- 95nov15, cca -------------------------------------------------------- */ void ETree_initFromGraphWithPerms ( ETree *etree, Graph *g, int newToOld[], int oldToNew[] ) ; /* -------------------------------------------------------------- purpose -- initialize the front tree for a dense matrix n -- size of the matrix option -- mapping option 1 --> have all fronts (save the last) contain the same number of vertices 2 --> have all fronts have roughly equal numbers of entries created -- 96aug19, cca -------------------------------------------------------------- */ void ETree_initFromDenseMatrix ( ETree *etree, int n, int option, int param ) ; /* ------------------------------------- initialize the ETree object (1) read ETree object from file (2) get the old-to-new permutation (3) permute the ETree (4) return the old-to-new permutation created -- 97jul13, cca ------------------------------------- */ IV * ETree_initFromFile ( ETree *frontETree, char *inETreeFileName, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in ms.c ------------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------ returns a compidsIV IV object that maps the vertices to a domain (compids[v] > 1) or to the multisector (compids[v] = 0). the vertices in the multisector is specified by their depth of their front in the tree. created -- 96jan04, cca ------------------------------------------------ */ IV * ETree_msByDepth ( ETree *etree, int depth ) ; /* ---------------------------------------------------------------- construct a multisector based on vertices found in a subtree. created -- 96jan04, cca ---------------------------------------------------------------- */ IV * ETree_msByNvtxCutoff ( ETree *etree, double cutoff ) ; /* -------------------------------------------------- construct a multisector based on the number of factor entries found in a subtree. symflag -- symmetry flag, one of SPOOLES_SYMMETRIC SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 96jan04, cca -------------------------------------------------- */ IV * ETree_msByNentCutoff ( ETree *etree, double cutoff, int symflag ) ; /* -------------------------------------------------- construct a multisector based on the number of factor operations found in a subtree. type -- type of entries, SPOOLES_REAL or SPOOLES_COMPLEX symflag -- symmetry flag, one of SPOOLES_SYMMETRIC SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 96jan04, cca -------------------------------------------------- */ IV * ETree_msByNopsCutoff ( ETree *etree, double cutoff, int type, int symflag ) ; /* -------------------------------------------------------------- purpose -- given a front tree and a multisector map vector, fill the map vector with domain ids and the three statistics arrays with domain and schur complement statistics. frontETree -- front tree object, unchanged on output msIV -- map from fronts to domains or schur complement on input, ms[J] = 0 --> J is in the schur complement ms[J] = 1 --> J is not in the schur complement on output, ms[J] = 0 --> J is in the schur complement ms[J] != 0 --> J is in domain ms[J] on output nvtxIV -- nvtx[ireg] = # of dof in region ireg nzfIV -- nzf[ireg] = # of factor entries in region ireg opsIV -- ops[ireg] = # of factor ops in region ireg type -- type of entries, SPOOLES_REAL or SPOOLES_COMPLEX symflag -- symmetry flag, one of SPOOLES_SYMMETRIC SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 98jan30, cca -------------------------------------------------------------- */ void ETree_msStats ( ETree *frontETree, IV *msIV, IV *nvtxIV, IV *nzfIV, DV *opsDV, int type, int symlag ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in permute.c -------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------- fill the new-to-old permutation vector for the fronts created -- 96jun23, cca ----------------------------------------------------- */ IV * ETree_newToOldFrontPerm ( ETree *etree ) ; /* ----------------------------------------------------- fill the old-to-new permutation vector for the fronts created -- 96jun23, cca ----------------------------------------------------- */ IV * ETree_oldToNewFrontPerm ( ETree *etree ) ; /* ------------------------------------------------------- fill the new-to-old permutation vector for the vertices created -- 96jun23, cca ------------------------------------------------------- */ IV * ETree_newToOldVtxPerm ( ETree *etree ) ; /* ------------------------------------------------------- fill the old-to-new permutation vector for the vertices created -- 96jun23, cca ------------------------------------------------------- */ IV * ETree_oldToNewVtxPerm ( ETree *etree ) ; /* ------------------------------------------------------- purpose -- permute the vertices, overwrite entries in the vertex-to-front map created -- 96oct03, cca ------------------------------------------------------- */ void ETree_permuteVertices ( ETree *etree, IV *vtxOldToNewIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in compress.c ------------------------------------- ------------------------------------------------------------------------ */ /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to create and return an IV object that contains the map from old to new fronts that are fundamental chains. created -- 96jun23, cca ------------------------------------------------------- */ IV * ETree_fundChainMap ( ETree *etree ) ; /* ------------------------------------------------------- purpose -- to create and return an IV object that contains the map from old to new fronts that are fundamental supernodes. created -- 96jun23, cca ------------------------------------------------------- */ IV * ETree_fundSupernodeMap ( ETree *etree ) ; /* ----------------------------------------------------------- compress an ETree object given a map from old to new nodes. note, a new node must be a connected set of the old nodes. return value -- pointer to new ETree object created -- 96jun23, cca. ----------------------------------------------------------- */ ETree * ETree_compress ( ETree *etree, IV *frontmapIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in justify.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ left-justify a tree by subtree size children are linked in ascending order of their subtree size created -- 96jan11, cca ------------------------------------------------------------ */ void ETree_leftJustify ( ETree *etree ) ; /* ------------------------------------------------------ left-justify a etree by a metric children are linked in ascending order of their metric created -- 96jan11, cca ------------------------------------------------------ */ void ETree_leftJustifyI ( ETree *etree, IV *metricIV ) ; /* ------------------------------------------------------ left-justify a etree by a metric children are linked in ascending order of their metric created -- 96jan11, cca ------------------------------------------------------ */ void ETree_leftJustifyD ( ETree *etree, DV *metricDV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in metrics.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------ return an IV object with the weights of the vertices in each front. created -- 96jun23, cca ------------------------------------ */ IV * ETree_nvtxMetric ( ETree *etree ) ; /* --------------------------------------------------------------- return an IV object with the number of factor entries in each front. symflag -- symmetryflag SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 96jun23, cca --------------------------------------------------------------- */ IV * ETree_nentMetric ( ETree *etree, int flag ) ; /* --------------------------------------------------------------- return a DV object with the number of factor operations in each front. type -- type of entries, SPOOLES_REAL or SPOOLES_COMPLEX symflag -- symmetryflag, SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 96jun23, cca --------------------------------------------------------------- */ DV * ETree_nopsMetric ( ETree *etree, int type, int symflag ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in stages.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------- generate a stages vector to be used by the CMD object. (1) if v = par[u] then stages[v] >= stages[u] endif (2) if v is a leaf then stages[v] = 0 endif (3) if u and v belong to the same fundamental supernode then stages[v] = stages[u] endif basically, all nodes in a domain (a subtree) have stage zero, and the stages of all fundamental supernodes ancestor to that subtree are distinct. input -- msIV -- IV object that contains the vertices in the multisector (non-domain vertices) return value -- stagesIV -- an IV object that contains the stage for each vertex created -- 96feb19, cca ------------------------------------------------------------------- */ IV * ETree_stagesViaMS ( ETree *etree, IV *msIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in transform.c ------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------ transform an ETree object by (1) merging small fronts into larger fronts using the ETree_mergeFrontsOne() method (2) merging small fronts into larger fronts using the ETree_mergeFrontsAll() method (3) merging small fronts into larger fronts using the ETree_mergeFrontsAny() method (4) split a large front into a chain of smaller fronts using the ETree_splitFronts() method created -- 96jun27, cca ------------------------------------------------------ */ ETree * ETree_transform ( ETree *etree, int vwghts[], int maxzeros, int maxfrontsize, int seed ) ; /* ------------------------------------------------------ transform an ETree object by (1) merging small fronts into larger fronts using the ETree_mergeFrontsOne() method (2) merging small fronts into larger fronts using the ETree_mergeFrontsAll() method (3) split a large front into a chain of smaller fronts using the ETree_splitFronts() method created -- 96jun27, cca ------------------------------------------------------ */ ETree * ETree_transform2 ( ETree *etree, int vwghts[], int maxzeros, int maxfrontsize, int seed ) ; /* -------------------------------------------------------------------- purpose -- merge the front tree allowing only chains of nodes to merge that create at most maxzeros zero entries inside a front return -- IV object that has the old front to new front map created -- 98jan29, cca -------------------------------------------------------------------- */ ETree * ETree_mergeFrontsOne ( ETree *etree, int maxzeros, IV *nzerosIV ) ; /* ------------------------------------------------------- purpose -- merge the front tree allowing a parent to absorb all children when that creates at most maxzeros zero entries inside a front return -- IV object that has the old front to new front map created -- 98jan29, cca ------------------------------------------------------- */ ETree * ETree_mergeFrontsAll ( ETree *etree, int maxzeros, IV *nzerosIV ) ; /* -------------------------------------------------------------------- purpose -- merge the front tree allowing at most maxzeros zero entries inside a front return -- IV object that has the old front to new front map created -- 96jun23, cca modified -- 97dec18, cca bug fixed that incorrectly counted the number of zeros in a front -------------------------------------------------------------------- */ ETree * ETree_mergeFrontsAny ( ETree *etree, int maxzeros, IV *nzerosIV ) ; /* ------------------------------------------------- expand an ETree object by splitting a large front into a chain of smaller fronts. created -- 96jun27, cca ------------------------------------------------- */ ETree * ETree_splitFronts ( ETree *etree, int vwghts[], int maxfrontsize, int seed ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in maps.c ----------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- this method constructs and returns an IV object that holds the map from fronts to threads for a wrap map of the front tree. created -- 96dec12, cca -------------------------------------------------------------- */ IV * ETree_wrapMap ( ETree *frontTree, int type, int symflag, DV *cumopsDV ) ; /* ---------------------------------------------------------------- this method constructs and returns an IV object that holds the map from fronts to threads for a balanced map of the front tree. the fronts are visited in the post-order traversal. created -- 96dec12, cca ---------------------------------------------------------------- */ IV * ETree_balancedMap ( ETree *frontTree, int type, int symflag, DV *cumopsDV ) ; /* ----------------------------------------------- this method constructs and returns an IV object that holds the map from fronts to threads for a "subtree-subset" map of the front tree. created -- 97jan15, cca ----------------------------------------------- */ IV * ETree_subtreeSubsetMap ( ETree *frontTree, int type, int symflag, DV *cumopsDV ) ; /* ---------------------------------------------------------------- this method constructs and returns an IV object that holds the map from fronts to threads for a domain decomposition balanced map of the front tree. the domains are mapped to threads using a balanced map, and the schur complement fronts are mapped to threads using a balanced map, but the two balanced maps are independent. created -- 97jan17, cca ---------------------------------------------------------------- */ IV * ETree_ddMap ( ETree *frontTree, int type, int symflag, DV *cumopsDV, double cutoff ) ; /* ---------------------------------------------------------------- this method constructs and returns an IV object that holds the map from fronts to threads for a domain decomposition balanced map of the front tree. the domains are mapped to threads using a balanced map, and the schur complement fronts are mapped to threads using a balanced map, but the two balanced maps are independent. created -- 97jan17, cca ---------------------------------------------------------------- */ IV * ETree_ddMapNew ( ETree *frontTree, int type, int symflag, IV *msIV, DV *cumopsDV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in splice.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------- this method is used to splice together two front trees when the domain vertices and schur complement vertices have been ordered separately. etree0 -- the lower front tree is for vertices in the domain. graph0 -- graph for all the vertices mapIV -- IV object that maps vertices to schur complement vertices, if IV_entry(mapIV, v) < 0 then v is a domain vertex. etree1 -- the upper front tree is for vertices in the schur complement. created -- 97feb01, cca ------------------------------------------------------------- */ ETree * ETree_spliceTwoETrees ( ETree *etree0, Graph *graph0, IV *mapIV, ETree *etree1 ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in initFromSubtree.c ------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- purpose -- to initialize subtree with the subtree of the front tree using nodes in nodeidsIV. vtxIV is filled with the vertices in the subtree return values --- 1 -- normal return -1 -- subtree is NULL -2 -- nodeidsIV is NULL -3 -- etree is NULL -4 -- nodeidsIV is invalid -5 -- vtxIV is NULL created -- 98oct15, cca ----------------------------------------------------------- */ int ETree_initFromSubtree ( ETree *subtree, IV *nodeidsIV, ETree *etree, IV *vtxIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in semi.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------- purpose -- to find the optimal domain/schur complement partition for a semi-implict factorization. the gain of a subtree sbt(J) is equal to |L_{bnd{J},sbt{J}}| - |A_{bnd{J},sbt{J}}| - alpha *|L_{sbt{J},sbt{J}}| when alpha = 0 we minimize active storage when alpha = 1 we minimize solve operations *ptotalgain is filled with the total gain the return value is compidsIV, compids[J] = 0 --> J is in the schur complement compids[J] != 0 --> J is in domain compids[J] created -- 98jun20, cca ----------------------------------------------------- */ IV * ETree_optPart ( ETree *etree, Graph *graph, IVL *symbfacIVL, double alpha, int *ptotalgain, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in storage.c -------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------------- purpose -- fill dvec[J] with the active storage to eliminate J using the multifrontal method symflag -- symmetry flag, one of SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 97may21, cca --------------------------------------------------------------- */ void ETree_MFstackProfile ( ETree *etree, int symflag, double dvec[] ) ; /* --------------------------------------------------------------- purpose -- fill dvec[J] with the active storage to eliminate J using the left-looking general sparse method symflag -- symmetry flag, one of SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 97may21, cca --------------------------------------------------------------- */ void ETree_GSstorageProfile ( ETree *etree, int symflag, IVL *symbfacIVL, int *vwghts, double dvec[] ) ; /* --------------------------------------------------------------- purpose -- fill dvec[J] with the active storage to eliminate J using the right-looking general sparse method symflag -- symmetry flag, one of SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 98dec19, cca --------------------------------------------------------------- */ void ETree_FSstorageProfile ( ETree *etree, int symflag, IVL *symbfacIVL, double dvec[] ) ; /* --------------------------------------------------------------- purpose -- fill dvec[J] with the stack storage to solve for J in a forward solve created -- 97nov30, cca --------------------------------------------------------------- */ void ETree_forwSolveProfile ( ETree *etree, double dvec[] ) ; /* --------------------------------------------------------------- purpose -- fill dvec[J] with the stack storage to solve for J in a backward solve created -- 97nov30, cca --------------------------------------------------------------- */ void ETree_backSolveProfile ( ETree *etree, double dvec[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods founds in IO.c ------------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------- purpose -- to read in an ETree object from a file input -- fn -- filename, must be *.etreeb or *.etreef return value -- 1 if success, 0 if failure created -- 95nov15, cca ------------------------------------------------- */ int ETree_readFromFile ( ETree *etree, char *fn ) ; /* -------------------------------------------------------- purpose -- to read an ETree object from a formatted file return value -- 1 if success, 0 if failure created -- 95nov15, cca -------------------------------------------------------- */ int ETree_readFromFormattedFile ( ETree *etree, FILE *fp ) ; /* ---------------------------------------------------- purpose -- to read an ETree object from a binary file return value -- 1 if success, 0 if failure created -- 95nov15, cca ---------------------------------------------------- */ int ETree_readFromBinaryFile ( ETree *etree, FILE *fp ) ; /* -------------------------------------------- purpose -- to write an ETree object to a file input -- fn -- filename *.etreeb -- binary *.etreef -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95nov15, cca -------------------------------------------- */ int ETree_writeToFile ( ETree *etree, char *fn ) ; /* ------------------------------------------------------ purpose -- to write an ETree object to a formatted file return value -- 1 if success, 0 otherwise created -- 95nov15, cca ------------------------------------------------------ */ int ETree_writeToFormattedFile ( ETree *etree, FILE *fp ) ; /* --------------------------------------------------- purpose -- to write an ETree object to a binary file return value -- 1 if success, 0 otherwise created -- 95nov15, cca --------------------------------------------------- */ int ETree_writeToBinaryFile ( ETree *etree, FILE *fp ) ; /* --------------------------------------------------- purpose -- to write an ETree object for a human eye return value -- 1 if success, 0 otherwise created -- 95nov15, cca --------------------------------------------------- */ int ETree_writeForHumanEye ( ETree *etree, FILE *fp ) ; /* ----------------------------------------------------------- purpose -- to write out the statistics for the ETree object return value -- 1 if success, 0 otherwise created -- 95nov15, cca ----------------------------------------------------------- */ int ETree_writeStats ( ETree *etree, FILE *fp ) ; /*--------------------------------------------------------------------*/ ----------------------------- */ IV * ETree_subtreeSubsetMap ( ETree *frontTree, int type, int symflag, DV *cumopsDV ) ; /* ---------------------------------------------------------------- this method constructs and returns an IV object that holds the map from fronts to threads for a domain decomposition balanced map of the front tree. the domains are mapped to threads using a balanced map, and the schur complement fronETree/makefile010064400020550007177000000002230663622357100146040ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean ETree/src/makefile010064400020550007177000000013020663602266000153660ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = ETree $(OBJ).a : \ $(OBJ).a(IO.o) \ $(OBJ).a(basics.o) \ $(OBJ).a(compress.o) \ $(OBJ).a(init.o) \ $(OBJ).a(initFromSubtree.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(justify.o) \ $(OBJ).a(maps.o) \ $(OBJ).a(metrics.o) \ $(OBJ).a(ms.o) \ $(OBJ).a(permute.o) \ $(OBJ).a(semi.o) \ $(OBJ).a(storage.o) \ $(OBJ).a(transform.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG ETree/src/makeGlobalLib010064400020550007177000000010500660026101500162640ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = ETree SRC = IO.c \ basics.c \ compress.c \ init.c \ instance.c \ justify.c \ maps.c \ metrics.c \ ms.c \ permute.c \ semi.c \ storage.c \ transform.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a ETree/src/IO.c010064400020550007177000000365270653410607300143600ustar00clevecompmath00000400000006/* IO.c */ #include "../ETree.h" static const char *suffixb = ".etreeb" ; static const char *suffixf = ".etreef" ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to read in an ETree object from a file input -- fn -- filename, must be *.etreeb or *.etreef return value -- 1 if success, 0 if failure created -- 95nov15, cca ------------------------------------------------- */ int ETree_readFromFile ( ETree *etree, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( etree == NULL || fn == NULL ) { fprintf(stderr, "\n error in ETree_readFromFile(%p,%s)" "\n bad input\n", etree, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in ETree_readFromFile(%p,%s)" "\n unable to open file %s", etree, fn, fn) ; rc = 0 ; } else { rc = ETree_readFromBinaryFile(etree, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in ETree_readFromFile(%p,%s)" "\n unable to open file %s", etree, fn, fn) ; rc = 0 ; } else { rc = ETree_readFromFormattedFile(etree, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in ETree_readFromFile(%p,%s)" "\n bad ETree file name %s," "\n must end in %s (binary) or %s (formatted)\n", etree, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in ETree_readFromFile(%p,%s)" "\n bad ETree file name %s," "\n must end in %s (binary) or %s (formatted)\n", etree, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to read an ETree object from a formatted file return value -- 1 if success, 0 if failure created -- 95nov15, cca -------------------------------------------------------- */ int ETree_readFromFormattedFile ( ETree *etree, FILE *fp ) { int rc ; int itemp[2] ; /* --------------- check the input --------------- */ if ( etree == NULL || fp == NULL ) { fprintf(stderr, "\n error in ETree_readFromFormattedFile(%p,%p)" "\n bad input\n", etree, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ ETree_clearData(etree) ; /* --------------------------- initialize the ETree object --------------------------- */ ETree_init1(etree, 0, 0) ; /* ----------------------------- read in the two scalar fields ----------------------------- */ if ( (rc = IVfscanf(fp, 2, itemp)) != 2 ) { fprintf(stderr, "\n error in ETree_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", etree, fp, rc, 2) ; return(0) ; } etree->nfront = itemp[0] ; etree->nvtx = itemp[1] ; /* ----------------------- read in the Tree object ----------------------- */ Tree_readFromFormattedFile(etree->tree, fp) ; /* ------------------------------ read in the nodwghts IV object ------------------------------ */ IV_readFromFormattedFile(etree->nodwghtsIV, fp) ; /* ------------------------------ read in the bndwghts IV object ------------------------------ */ IV_readFromFormattedFile(etree->bndwghtsIV, fp) ; /* -------------------------------- read in the vtxToFront IV object -------------------------------- */ IV_readFromFormattedFile(etree->vtxToFrontIV, fp) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to read an ETree object from a binary file return value -- 1 if success, 0 if failure created -- 95nov15, cca ---------------------------------------------------- */ int ETree_readFromBinaryFile ( ETree *etree, FILE *fp ) { int rc ; int itemp[2] ; /* --------------- check the input --------------- */ if ( etree == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in ETree_readFromBinaryFile(%p,%p)" "\n bad input\n", etree, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ ETree_clearData(etree) ; /* --------------------------- initialize the ETree object --------------------------- */ ETree_init1(etree, 0, 0) ; /* ----------------------------- read in the two scalar fields ----------------------------- */ if ( (rc = fread((void *) itemp, sizeof(int), 2, fp)) != 2 ) { fprintf(stderr, "\n error in ETree_readFromBinaryFile(%p,%p)" "\n itemp(2) : %d items of %d read\n", etree, fp, rc, 2) ; return(0) ; } etree->nfront = itemp[0] ; etree->nvtx = itemp[1] ; /* ----------------------- read in the Tree object ----------------------- */ Tree_readFromBinaryFile(etree->tree, fp) ; /* ------------------------------ read in the nodwghts IV object ------------------------------ */ IV_readFromBinaryFile(etree->nodwghtsIV, fp) ; /* ------------------------------ read in the bndwghts IV object ------------------------------ */ IV_readFromBinaryFile(etree->bndwghtsIV, fp) ; /* -------------------------------- read in the vtxToFront IV object -------------------------------- */ IV_readFromBinaryFile(etree->vtxToFrontIV, fp) ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to write an ETree object to a file input -- fn -- filename *.etreeb -- binary *.etreef -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95nov15, cca -------------------------------------------- */ int ETree_writeToFile ( ETree *etree, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( etree == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in ETree_writeToFile(%p,%s)" "\n bad input\n", etree, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in ETree_writeToFile(%p,%s)" "\n unable to open file %s", etree, fn, fn) ; rc = 0 ; } else { rc = ETree_writeToBinaryFile(etree, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in ETree_writeToFile(%p,%s)" "\n unable to open file %s", etree, fn, fn) ; rc = 0 ; } else { rc = ETree_writeToFormattedFile(etree, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in ETree_writeToFile(%p,%s)" "\n unable to open file %s", etree, fn, fn) ; rc = 0 ; } else { rc = ETree_writeForHumanEye(etree, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in ETree_writeToFile(%p,%s)" "\n unable to open file %s", etree, fn, fn) ; rc = 0 ; } else { rc = ETree_writeForHumanEye(etree, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to write an ETree object to a formatted file return value -- 1 if success, 0 otherwise created -- 95nov15, cca ------------------------------------------------------ */ int ETree_writeToFormattedFile ( ETree *etree, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( etree == NULL || fp == NULL || etree->tree == NULL ) { fprintf(stderr, "\n fatal error in ETree_writeToFormattedFile(%p,%p)" "\n bad input\n", etree, fp) ; exit(-1) ; } /* --------------------------- write the two scalar fields --------------------------- */ rc = fprintf(fp, "\n %d %d", etree->nfront, etree->nvtx) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in ETree_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", etree, fp, rc) ; return(0) ; } /* --------------------------------- write the Tree object to the file --------------------------------- */ rc = Tree_writeToFormattedFile(etree->tree, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in ETree_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing Tree to file\n", etree, fp, rc) ; return(0) ; } /* ---------------------------------------- write the nodwghts IV object to the file ---------------------------------------- */ rc = IV_writeToFormattedFile(etree->nodwghtsIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in ETree_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing nodwghtsIV to file\n", etree, fp, rc) ; return(0) ; } /* ---------------------------------------- write the bndwghts IV object to the file ---------------------------------------- */ rc = IV_writeToFormattedFile(etree->bndwghtsIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in ETree_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing bndwghtsIV to file\n", etree, fp, rc) ; return(0) ; } /* ------------------------------------------ write the vtxToFront IV object to the file ------------------------------------------ */ rc = IV_writeToFormattedFile(etree->vtxToFrontIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in ETree_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing vtxToFrontIV to file\n", etree, fp, rc) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to write an ETree object to a binary file return value -- 1 if success, 0 otherwise created -- 95nov15, cca --------------------------------------------------- */ int ETree_writeToBinaryFile ( ETree *etree, FILE *fp ) { int rc ; int itemp[2] ; /* --------------- check the input --------------- */ if ( etree == NULL || fp == NULL || etree->tree == NULL ) { fprintf(stderr, "\n fatal error in ETree_writeToBinaryFile(%p,%p)" "\n bad input\n", etree, fp) ; exit(-1) ; } /* --------------------------- write the two scalar fields --------------------------- */ itemp[0] = etree->nfront ; itemp[1] = etree->nvtx ; rc = fwrite((void *) itemp, sizeof(int), 2, fp) ; if ( rc != 2 ) { fprintf(stderr, "\n error in ETree_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", etree, fp, rc, 2) ; return(0) ; } /* --------------------------------- write the Tree object to the file --------------------------------- */ rc = Tree_writeToBinaryFile(etree->tree, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in ETree_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing Tree to file\n", etree, fp, rc) ; return(0) ; } /* ---------------------------------------- write the nodwghts IV object to the file ---------------------------------------- */ rc = IV_writeToBinaryFile(etree->nodwghtsIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in ETree_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing nodwghtsIV to file\n", etree, fp, rc) ; return(0) ; } /* ---------------------------------------- write the bndwghts IV object to the file ---------------------------------------- */ rc = IV_writeToBinaryFile(etree->bndwghtsIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in ETree_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing bndwghtsIV to file\n", etree, fp, rc) ; return(0) ; } /* ------------------------------------------ write the vtxToFront IV object to the file ------------------------------------------ */ rc = IV_writeToBinaryFile(etree->vtxToFrontIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in ETree_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing vtxToFrontIV to file\n", etree, fp, rc) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to write an ETree object for a human eye return value -- 1 if success, 0 otherwise created -- 95nov15, cca --------------------------------------------------- */ int ETree_writeForHumanEye ( ETree *etree, FILE *fp ) { int nfront, rc, v ; int *bndwghts, *fch, *nodwghts, *par, *sib ; if ( etree == NULL || fp == NULL || (nfront = etree->nfront) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_writeForHumanEye(%p,%p)" "\n bad input\n", etree, fp) ; exit(-1) ; } if ( (rc = ETree_writeStats(etree, fp)) == 0 ) { fprintf(stderr, "\n fatal error in ETree_writeForHumanEye(%p,%p)" "\n rc = %d, return from ETree_writeStats(%p,%p)\n", etree, fp, rc, etree, fp) ; return(0) ; } par = etree->tree->par ; fch = etree->tree->fch ; sib = etree->tree->sib ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; fprintf(fp, "\n front parent fchild sibling nodwght bndwght") ; for ( v = 0 ; v < nfront ; v++ ) { fprintf(fp, "\n %5d %9d %9d %9d %9d %9d ", v, par[v], fch[v], sib[v], nodwghts[v], bndwghts[v]) ; } fflush(fp) ; fprintf(fp, "\n\n vtxToFront IV object") ; IV_writeForHumanEye(etree->vtxToFrontIV, fp) ; fflush(fp) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to write out the statistics for the ETree object return value -- 1 if success, 0 otherwise created -- 95nov15, cca ----------------------------------------------------------- */ int ETree_writeStats ( ETree *etree, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( etree == NULL || fp == NULL ) { fprintf(stderr, "\n error in ETree_writeStats(%p,%p)" "\n bad input\n", etree, fp) ; exit(-1) ; } rc = fprintf(fp, "\n ETree : etree object, %d fronts, %d vertices, takes %d bytes", etree->nfront, etree->nvtx, ETree_sizeOf(etree)) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in ETree_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", etree, fp, rc) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ ETree/src/basics.c010064400020550007177000000061270653410607300153060ustar00clevecompmath00000400000006/* basics.c */ #include "../ETree.h" #define MYTRACE 0 #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- create and return a new ETree object created -- 95nov15, cca ----------------------------------------------- */ ETree * ETree_new ( void ) { ETree *etree ; #if MYTRACE > 0 fprintf(stdout, "\n just inside ETree_new()") ; fflush(stdout) ; #endif ALLOCATE(etree, struct _ETree, 1) ; ETree_setDefaultFields(etree) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving ETree_new()") ; fflush(stdout) ; #endif return(etree) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- set the default fields for the ETree object created -- 95nov15, cca ------------------------------------------------------ */ void ETree_setDefaultFields ( ETree *etree ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside ETree_setDefaultFields(%)", g) ; fflush(stdout) ; #endif if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_setDefaultFields(%p)" "\n etree is NULL\n", etree) ; exit(-1) ; } etree->nfront = 0 ; etree->nvtx = 0 ; etree->tree = NULL ; etree->nodwghtsIV = NULL ; etree->bndwghtsIV = NULL ; etree->vtxToFrontIV = NULL ; #if MYTRACE > 0 fprintf(stdout, "\n leaving ETree_setDefaultFields(%)", etree) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- clear the data fields created -- 95nov15, cca -------------------------------- */ void ETree_clearData ( ETree *etree ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside ETree_clearData(%)", etree) ; fflush(stdout) ; #endif if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_clearData(%p)" "\n etree is NULL\n", etree) ; exit(-1) ; } if ( etree->tree != NULL ) { Tree_free(etree->tree) ; } if ( etree->nodwghtsIV != NULL ) { IV_free(etree->nodwghtsIV) ; } if ( etree->bndwghtsIV != NULL ) { IV_free(etree->bndwghtsIV) ; } if ( etree->vtxToFrontIV != NULL ) { IV_free(etree->vtxToFrontIV) ; } ETree_setDefaultFields(etree) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving ETree_clearData(%)", etree) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- free the ETree object created -- 95nov15, cca -------------------------------- */ void ETree_free ( ETree *etree ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside ETree_free(%)", etree) ; fflush(stdout) ; #endif if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_free(%p)" "\n etree is NULL\n", etree) ; exit(-1) ; } ETree_clearData(etree) ; FREE(etree) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving ETree_free(%)", etree) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ ETree/src/compress.c010064400020550007177000000141450653410607400156750ustar00clevecompmath00000400000006/* compress.c */ #include "../ETree.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to create and return an IV object that contains the map from old to new fronts that are fundamental chains. created -- 96jun23, cca ------------------------------------------------------- */ IV * ETree_fundChainMap ( ETree *etree ) { int nfront, nvtx ; IV *frontmapIV ; /* --------------- check the input --------------- */ if ( etree == NULL || etree->tree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_fundChainMap(%p)" "\n bad input\n", etree) ; exit(-1) ; } /* ------------------------------------- call the Tree object's method to get the map from old fronts to new fronts ------------------------------------- */ frontmapIV = Tree_fundChainMap(etree->tree) ; return(frontmapIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to create and return an IV object that contains the map from old to new fronts that are fundamental supernodes created -- 96jun23, cca ------------------------------------------------------- */ IV * ETree_fundSupernodeMap ( ETree *etree ) { int child, front, nfront, nfs, nvtx ; int *bndwghts, *fch, *frontmap, *nodwghts, *par, *sib ; IV *frontmapIV ; /* --------------- check the input --------------- */ if ( etree == NULL || etree->tree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_fundSupernodeMap(%p)" "\n bad input\n", etree) ; exit(-1) ; } par = etree->tree->par ; fch = etree->tree->fch ; sib = etree->tree->sib ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; /* ------------------------------------------ fill the map from old fronts to new fronts ------------------------------------------ */ frontmapIV = IV_new() ; IV_init(frontmapIV, nfront, NULL) ; frontmap = IV_entries(frontmapIV) ; nfs = 0 ; front = etree->tree->root ; while ( front != -1 ) { while ( fch[front] != -1 ) { front = fch[front] ; } frontmap[front] = nfs++ ; while ( sib[front] == -1 && par[front] != -1 ) { front = par[front] ; child = fch[front] ; if ( sib[child] != -1 || (nodwghts[front] + bndwghts[front] != bndwghts[child]) ) { frontmap[front] = nfs++ ; } else { frontmap[front] = frontmap[child] ; } } front = sib[front] ; } return(frontmapIV) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- compress an ETree object given a map from old to new nodes. note, a new node must be a connected set of the old nodes. return value -- pointer to new ETree object created -- 96jun23, cca. ----------------------------------------------------------- */ ETree * ETree_compress ( ETree *etree, IV *frontmapIV ) { ETree *etree2 ; int nfront, newfront, newnfront, newparfront, nvtx, oldfront, parfront, v ; int *bndwghts, *frontmap, *newbndwghts, *newnodwghts, *newpar, *newvtxToFront, *nodwghts, *par, *vtxToFront ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 || frontmapIV == NULL ) { fprintf(stderr, "\n fatal error in ETree_compress(%p,%p)" "\n bad input\n", etree, frontmapIV) ; exit(-1) ; } /* -------------------------------- pull out pointers and dimensions -------------------------------- */ nfront = etree->nfront ; nvtx = etree->nvtx ; par = etree->tree->par ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; vtxToFront = IV_entries(etree->vtxToFrontIV) ; newnfront = 1 + IV_max(frontmapIV) ; frontmap = IV_entries(frontmapIV) ; #if MYDEBUG > 0 fprintf(stdout, "\n newnfront = %d", newnfront) ; #endif /* ------------------------------- initialize the new ETree object ------------------------------- */ etree2 = ETree_new() ; ETree_init1(etree2, newnfront, nvtx) ; newpar = etree2->tree->par ; newnodwghts = IV_entries(etree2->nodwghtsIV) ; newbndwghts = IV_entries(etree2->bndwghtsIV) ; newvtxToFront = IV_entries(etree2->vtxToFrontIV) ; #if MYDEBUG > 0 fprintf(stdout, "\n newnodwghts") ; IV_writeForHumanEye(etree2->nodwghtsIV, stdout) ; #endif /* ------------------------ fill the new tree fields ------------------------ */ for ( oldfront = 0 ; oldfront < nfront ; oldfront++ ) { newfront = frontmap[oldfront] ; parfront = par[oldfront] ; #if MYDEBUG > 0 fprintf(stdout, "\n oldfront = %d, nodwght = %d, parfront = %d, newfront = %d", oldfront, nodwghts[oldfront], parfront, newfront) ; fflush(stdout) ; #endif newnodwghts[newfront] += nodwghts[oldfront] ; #if MYDEBUG > 0 fprintf(stdout, "\n nodwghts[%d] = %d, newnodwghts[%d] = %d", oldfront, nodwghts[oldfront], newfront, newnodwghts[newfront]) ; fflush(stdout) ; #endif if ( parfront != -1 && (newparfront = frontmap[parfront]) != newfront ) { newpar[newfront] = newparfront ; newbndwghts[newfront] = bndwghts[oldfront] ; #if MYDEBUG > 0 fprintf(stdout, "\n newparfront = %d", newparfront) ; fprintf(stdout, "\n setting newpar[%d] = %d, newbndwghts[%d] = %d", newfront, newpar[newfront], newfront, newbndwghts[newfront]) ; fflush(stdout) ; #endif } } Tree_setFchSibRoot(etree2->tree) ; /* --------------------------------------- set the map from vertices to new fronts --------------------------------------- */ for ( v = 0 ; v < nvtx ; v++ ) { newvtxToFront[v] = frontmap[vtxToFront[v]] ; } return(etree2) ; } /*--------------------------------------------------------------------*/ || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_fundChainMap(%p)" "\n bad input\n", etree) ; exit(-1) ; } /* ------------------------------------- call the Tree object's method to get the map from old fronts to new fronts ------------------------------------- */ frontmapIV = Tree_fundChainMap(etree->tree) ; return(frETree/src/init.c010064400020550007177000000310440663603003700150000ustar00clevecompmath00000400000006/* init.c */ #include "../ETree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* ------------------------------- initialize the object given the number of fronts and vertices created -- 96jun23, cca ------------------------------- */ void ETree_init1 ( ETree *etree, int nfront, int nvtx ) { /* --------------- check the input --------------- */ if ( etree == NULL || nfront < 0 || nvtx < nfront ) { fprintf(stderr, "\n fatal error in ETree_init1(%p,%d,%d)" "\n bad input\n", etree, nfront, nvtx) ; exit(-1) ; } ETree_clearData(etree) ; etree->nfront = nfront ; etree->nvtx = nvtx ; etree->tree = Tree_new() ; Tree_init1(etree->tree, nfront) ; etree->nodwghtsIV = IV_new() ; IV_init(etree->nodwghtsIV, nfront, NULL) ; IV_fill(etree->nodwghtsIV, 0) ; etree->bndwghtsIV = IV_new() ; IV_init(etree->bndwghtsIV, nfront, NULL) ; IV_fill(etree->bndwghtsIV, 0) ; etree->vtxToFrontIV = IV_new() ; IV_init(etree->vtxToFrontIV, nvtx, NULL) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- initialize the ETree object from a graph created -- 95nov15, cca ---------------------------------------- */ void ETree_initFromGraph ( ETree *etree, Graph *g ) { int ii, nfront, nvtx, u, v, vsize ; int *bndwghts, *mark, *nodwghts, *par, *vadj ; /* --------------- check the input --------------- */ if ( etree == NULL || g == NULL || (nvtx = g->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_initFromGraph(%p,%p)" "\n bad input\n", etree, g) ; exit(-1) ; } /* ----------------- set up the object ----------------- */ nfront = nvtx ; ETree_init1(etree, nfront, nvtx) ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; par = etree->tree->par ; IV_ramp(etree->vtxToFrontIV, 0, 1) ; /* -------------------------------------------------------- fill the parent, node weight and boundary weight vectors -------------------------------------------------------- */ if ( g->vwghts == NULL ) { IVfill(nvtx, nodwghts, 1) ; } else { IVcopy(nvtx, nodwghts, g->vwghts) ; } mark = IVinit(nvtx, -1) ; IVramp(nvtx, mark, 0, 1) ; for ( v = 0 ; v < nvtx ; v++ ) { Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { u = vadj[ii] ; while ( u < v && mark[u] != v ) { bndwghts[u] += nodwghts[v] ; if ( mark[u] == u ) { par[u] = v ; } mark[u] = v ; u = par[u] ; } } } IVfree(mark) ; /* ------------------------------------ set the fch[], sub[] and root fields ------------------------------------ */ Tree_setFchSibRoot(etree->tree) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- initialize the ETree object from a graph and permutation created -- 95nov15, cca -------------------------------------------------------- */ void ETree_initFromGraphWithPerms ( ETree *etree, Graph *g, int newToOld[], int oldToNew[] ) { int ii, nfront, nvtx, unew, uold, vold, vnew, vsize ; int *bndwghts, *mark, *nodwghts, *par, *vadj ; /* --------------- check the input --------------- */ if ( etree == NULL || g == NULL || (nvtx = g->nvtx) <= 0 || newToOld == NULL || oldToNew == NULL ) { fprintf(stderr, "\n fatal error in ETree_initFromGraph(%p,%p,%p,%p)" "\n bad input\n", etree, g, newToOld, oldToNew) ; exit(-1) ; } nfront = nvtx ; /* -------------------------------------------------- check that the permutation is really a permutation -------------------------------------------------- */ for ( unew = 0 ; unew < nvtx ; unew++ ) { if ( (uold = newToOld[unew]) < 0 || uold >= nvtx || oldToNew[uold] != unew ) { fprintf(stderr, "\n fatal error in ETree_initFromGraphWithPerms(%p,%p,%p,%p)" "\n uold = %d, unew = %d", etree, g, newToOld, oldToNew, uold, unew) ; if ( 0 <= uold && uold < nvtx ) { fprintf(stderr, "\n oldToNew[%d] = %d", uold, oldToNew[uold]) ; } if ( 0 <= unew && unew < nvtx ) { fprintf(stderr, "\n newToOld[%d] = %d", unew, newToOld[unew]) ; } exit(-1) ; } } /* ----------------- set up the object ----------------- */ nfront = nvtx ; ETree_init1(etree, nfront, nvtx) ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; par = etree->tree->par ; IVcopy(nvtx, IV_entries(etree->vtxToFrontIV), oldToNew) ; /* -------------------------------------------------------- fill the parent, node weight and boundary weight vectors -------------------------------------------------------- */ if ( g->vwghts == NULL ) { IVfill(nvtx, nodwghts, 1) ; } else { for ( vold = 0 ; vold < nvtx ; vold++ ) { nodwghts[oldToNew[vold]] = g->vwghts[vold] ; } } mark = IVinit(nvtx, -1) ; IVramp(nvtx, mark, 0, 1) ; for ( vnew = 0 ; vnew < nvtx ; vnew++ ) { vold = newToOld[vnew] ; Graph_adjAndSize(g, vold, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { uold = vadj[ii] ; if ( uold < nvtx ) { unew = oldToNew[uold] ; while ( unew < vnew && mark[unew] != vnew ) { bndwghts[unew] += nodwghts[vnew] ; if ( mark[unew] == unew ) { par[unew] = vnew ; } mark[unew] = vnew ; unew = par[unew] ; } } } } IVfree(mark) ; /* ------------------------------------ set the fch[], sub[] and root fields ------------------------------------ */ Tree_setFchSibRoot(etree->tree) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- initialize the front tree for a dense matrix n -- size of the matrix option -- mapping option 1 --> have all fronts (save the last) contain the same number of vertices 2 --> have all fronts have roughly equal numbers of entries created -- 96aug19, cca -------------------------------------------------------------- */ void ETree_initFromDenseMatrix ( ETree *etree, int n, int option, int param ) { int b, bnd, first, front, ii, last, nent, nfront, target ; int *bndwghts, *nodwghts, *par, *vtxToFront ; /* --------------- check the input --------------- */ if ( etree == NULL || n <= 0 || option < 1 || option > 2 || param <= 0 ) { fprintf(stderr, "\n fatal error in ETree_initFromDenseMatrix(%p,%d,%d,%d)" "\n bad input\n", etree, n, option, param) ; exit(-1) ; } ETree_clearData(etree) ; if ( option == 1 ) { /* ------------------------------------------------------------------ first option, let all front be size b except for possibly the root ------------------------------------------------------------------ */ b = param ; nfront = (n + b - 1)/b ; ETree_init1(etree, nfront, n) ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; vtxToFront = IV_entries(etree->vtxToFrontIV) ; for ( ii = 0 ; ii < n ; ii++ ) { vtxToFront[ii] = ii / b ; } for ( ii = 0, bnd = n ; ii < nfront ; ii++ ) { nodwghts[ii] = (b <= bnd) ? b : bnd ; bnd -= nodwghts[ii] ; bndwghts[ii] = bnd ; } } else if ( option == 2 ) { /* ------------------------------------------------------------ second option, let each front have the same number of entries ------------------------------------------------------------ */ target = param ; first = 0 ; bnd = n - 1 ; nfront = 0 ; while ( first < n ) { nent = 2*(n - first) - 1 ; last = first + 1 ; while ( last < n && (nent + 2*(n - last) - 1) <= target ) { nent += 2*(n - last) - 1 ; last++ ; } first = last ; nfront++ ; } ETree_init1(etree, nfront, n) ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; vtxToFront = IV_entries(etree->vtxToFrontIV) ; first = 0 ; bnd = n - 1 ; front = 0 ; while ( first < n ) { nent = 2*(n - first) - 1 ; vtxToFront[first] = front ; last = first + 1 ; while ( last < n && (nent + 2*(n - last) - 1) <= target ) { vtxToFront[last] = front ; nent += 2*(n - last) - 1 ; last++ ; } last-- ; fprintf(stdout, "\n front = %d, first = %d, last = %d, nent = %d", front, first, last, nent) ; nodwghts[front] = last - first + 1 ; bndwghts[front] = n - last - 1 ; first = last + 1 ; front++ ; } } par = etree->tree->par ; IVramp(nfront, par, 1, 1) ; par[nfront-1] = -1 ; Tree_setFchSibRoot(etree->tree) ; { int bndJ, count, ierr, I, J, sizeI, sizeJ ; int *tmp ; double facops, solops, updops ; facops = solops = updops = 0.0 ; tmp = IVinit((nfront*(nfront+1))/2, -1) ; count = 0 ; for ( J = 0 ; J < nfront ; J++ ) { sizeJ = nodwghts[J] ; bndJ = bndwghts[J] ; facops += 2*(sizeJ * sizeJ * sizeJ)/3 ; solops += 2 * sizeJ * sizeJ * bndJ ; tmp[count++] = facops + solops ; for ( I = 0 ; I < J ; I++ ) { sizeI = nodwghts[I] ; updops += 2 * sizeI * sizeJ * (sizeJ + 2*bndJ) ; tmp[count++] = updops ; } } IVqsortUp(count, tmp) ; /* IVfp80(stdout, count, tmp, 80, &ierr) ; */ IVfree(tmp) ; fprintf(stdout, "\n factor ops = %.0f, %5.1f per cent of total" "\n solve ops = %.0f, %5.1f per cent of total" "\n update ops = %.0f, %5.1f per cent of total", facops, 100.*facops/(facops + solops + updops), solops, 100.*solops/(facops + solops + updops), updops, 100.*updops/(facops + solops + updops)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- initialize the ETree object (1) read ETree object from file (2) get the old-to-new permutation (3) permute the ETree (4) return the old-to-new permutation created -- 97jul13, cca ------------------------------------- */ IV * ETree_initFromFile ( ETree *frontETree, char *inETreeFileName, int msglvl, FILE *msgFile ) { double t1, t2 ; int neqns, rc ; IV *oldToNewIV ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; ETree_setDefaultFields(frontETree) ; rc = ETree_readFromFile(frontETree, inETreeFileName) ; MARKTIME(t2) ; neqns = frontETree->nvtx ; fprintf(msgFile, "\n CPU %8.3f : read in frontETree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, frontETree, inETreeFileName) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl == 2 ) { ETree_writeStats(frontETree, msgFile) ; } else { ETree_writeForHumanEye(frontETree, msgFile) ; } } fflush(msgFile) ; /* ----------------------------- get the permutation IV object ----------------------------- */ MARKTIME(t1) ; oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get permutation", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n vertex old-to-new IV object") ; if ( msglvl == 2 ) { IV_writeStats(oldToNewIV, msgFile) ; } else { IV_writeForHumanEye(oldToNewIV, msgFile) ; } fflush(msgFile) ; } /* ---------------------------------------- permute the vertices in the ETree object ---------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n before permuting the vertex map") ; if ( msglvl == 2 ) { ETree_writeStats(frontETree, msgFile) ; } else { ETree_writeForHumanEye(frontETree, msgFile) ; } fflush(msgFile) ; } MARKTIME(t1) ; ETree_permuteVertices(frontETree, oldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute ETree", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after permuting the vertex map") ; if ( msglvl == 2 ) { ETree_writeStats(frontETree, msgFile) ; } else { ETree_writeForHumanEye(frontETree, msgFile) ; } fflush(msgFile) ; } return(oldToNewIV) ; } /*--------------------------------------------------------------------*/ d = %d, unew = %d", etree, g, newToOld, oldToNew, uold, unew) ; if ( 0 <= uold && uold < nvtx ) { fprintf(stderr, "\n oldToNew[%d] = %d", uold, oldToNew[uold]) ; } if ( 0 <= unew && unew < nvtx ) { fprintf(stderr, "\n newToOld[%d] = %d", unew, newToOld[unew]) ; } exit(-1) ; } } /* ----------------- set up the object ----------------- */ nfront = nvtx ; ETree_init1(etree, nfront, nvtx) ; nodwghts = IV_entETree/src/initFromSubtree.c010064400020550007177000000103460663603003700171600ustar00clevecompmath00000400000006/* initFromSubtree.c */ #include "../ETree.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to initialize subtree with the subtree of the front tree using nodes in nodeidsIV. vtxIV is filled with the vertices in the subtree return values --- 1 -- normal return -1 -- subtree is NULL -2 -- nodeidsIV is NULL -3 -- etree is NULL -4 -- nodeidsIV is invalid -5 -- vtxIV is NULL created -- 98oct15, cca ----------------------------------------------------------- */ int ETree_initFromSubtree ( ETree *subtree, IV *nodeidsIV, ETree *etree, IV *vtxIV ) { int J, Jsub, nfrontInETree, nfrontInSubtree, nvtxInETree, nvtxInSubtree, v, vSub ; int *bndwghts, *bndwghtsSub, *localmap, *nodwghts, *nodwghtsSub, *subtreeNodes, *vtxInSubtree, *vtxToFront, *vtxToFrontSub ; /* --------------- check the input --------------- */ if ( subtree == NULL ) { fprintf(stderr, "\n\n error in ETree_initFromSubtree()" "\n subtree is NULL\n") ; return(-1) ; } if ( nodeidsIV == NULL ) { fprintf(stderr, "\n\n error in ETree_initFromSubtree()" "\n nodeidsIV is NULL\n") ; return(-2) ; } if ( etree == NULL ) { fprintf(stderr, "\n\n error in ETree_initFromSubtree()" "\n etree is NULL\n") ; return(-3) ; } nfrontInETree = ETree_nfront(etree) ; IV_sizeAndEntries(nodeidsIV, &nfrontInSubtree, &subtreeNodes) ; if ( nfrontInSubtree < 0 || nfrontInSubtree >= nfrontInETree ) { fprintf(stderr, "\n\n error in ETree_initFromSubtree()" "\n nfrontInETree = %d, nfrontInSubtree = %d\n", nfrontInETree, nfrontInSubtree) ; return(-4) ; } for ( Jsub = 0 ; Jsub < nfrontInSubtree ; Jsub++ ) { J = subtreeNodes[Jsub] ; if ( J < 0 || J >= nfrontInETree ) { fprintf(stderr, "\n\n error in ETree_initFromSubtree()" "\n nfrontInETree = %d, subtreeNodes[%d] = %d\n", nfrontInETree, Jsub, subtreeNodes[Jsub]) ; return(-4) ; } } if ( vtxIV == NULL ) { fprintf(stderr, "\n\n error in ETree_initFromSubtree()" "\n vtxIV is NULL\n") ; return(-5) ; } nvtxInETree = ETree_nvtx(etree) ; vtxToFront = ETree_vtxToFront(etree) ; /* ---------------------------- create a global-to-local map ---------------------------- */ localmap = IVinit(nfrontInETree, -1) ; for ( Jsub = 0 ; Jsub < nfrontInSubtree ; Jsub++ ) { J = subtreeNodes[Jsub] ; localmap[J] = Jsub ; } /* --------------------------------------------- compute the number of vertices in the subtree --------------------------------------------- */ nvtxInSubtree = 0 ; for ( v = 0 ; v < nvtxInETree ; v++ ) { J = vtxToFront[v] ; if ( (Jsub = localmap[J]) != -1 ) { nvtxInSubtree++ ; } } /* ---------------------- initialize the subtree ---------------------- */ ETree_init1(subtree, nfrontInSubtree, nvtxInSubtree) ; /* ----------------------------- initialize the subtree's tree ----------------------------- */ Tree_initFromSubtree(subtree->tree, nodeidsIV, etree->tree) ; /* ----------------------------------- set the nodwght and bndwght vectors ----------------------------------- */ nodwghts = ETree_nodwghts(etree) ; bndwghts = ETree_bndwghts(etree) ; nodwghtsSub = ETree_nodwghts(subtree) ; bndwghtsSub = ETree_bndwghts(subtree) ; for ( Jsub = 0 ; Jsub < nfrontInSubtree ; Jsub++ ) { J = subtreeNodes[Jsub] ; nodwghtsSub[Jsub] = nodwghts[J] ; bndwghtsSub[Jsub] = bndwghts[J] ; } /* ------------------------------------- set the subtree's vtxToFront[] vector and fill vtxIV with the vertices ------------------------------------- */ IV_init(vtxIV, nvtxInSubtree, NULL) ; vtxInSubtree = IV_entries(vtxIV) ; vtxToFrontSub = ETree_vtxToFront(subtree) ; for ( v = vSub = 0 ; v < nvtxInETree ; v++ ) { J = vtxToFront[v] ; if ( (Jsub = localmap[J]) != -1 ) { vtxInSubtree[vSub] = v ; vtxToFrontSub[vSub] = Jsub ; vSub++ ; } } /* ------------------------ free the working storage ------------------------ */ IVfree(localmap) ; return(1) ; } /*--------------------------------------------------------------------*/ ETree/src/instance.c010064400020550007177000000233620653601654400156530ustar00clevecompmath00000400000006/* instance.c */ #include "../ETree.h" /*--------------------------------------------------------------------*/ /* --------------------------- return the number of fronts created -- 97feb28, cca --------------------------- */ int ETree_nfront ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_nfront(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(etree->nfront) ; } /*--------------------------------------------------------------------*/ /* ----------------------------- return the number of vertices created -- 97feb28, cca ----------------------------- */ int ETree_nvtx ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_nvtx(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(etree->nvtx) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- return a pointer to the Tree object created -- 97feb28, cca ----------------------------------- */ Tree * ETree_tree ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_tree(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(etree->tree) ; } /*--------------------------------------------------------------------*/ /* --------------------------- return the root of the tree created -- 97feb28, cca --------------------------- */ int ETree_root ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL || etree->tree == NULL ) { fprintf(stderr, "\n fatal error in ETree_root(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(etree->tree->root) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- return a pointer to the parent vector created -- 97feb28, cca ------------------------------------- */ int * ETree_par ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL || etree->tree == NULL ) { fprintf(stderr, "\n fatal error in ETree_par(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(etree->tree->par) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ return a pointer to the first child vector created -- 97feb28, cca ------------------------------------------ */ int * ETree_fch ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL || etree->tree == NULL ) { fprintf(stderr, "\n fatal error in ETree_fch(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(etree->tree->fch) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- return a pointer to the sibling vector created -- 97feb28, cca -------------------------------------- */ int * ETree_sib ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL || etree->tree == NULL ) { fprintf(stderr, "\n fatal error in ETree_sib(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(etree->tree->sib) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ return a pointer to the nodwghts IV object created -- 97feb28, cca ------------------------------------------ */ IV * ETree_nodwghtsIV ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_nodwghtsIV(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(etree->nodwghtsIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- return a pointer to the nodwghts int vector created -- 97feb28, cca ------------------------------------------- */ int * ETree_nodwghts ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL || etree->nodwghtsIV == NULL ) { fprintf(stderr, "\n fatal error in ETree_nodwghts(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(IV_entries(etree->nodwghtsIV)) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ return a pointer to the bndwghts IV object created -- 97feb28, cca ------------------------------------------ */ IV * ETree_bndwghtsIV ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_bndwghtsIV(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(etree->bndwghtsIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- return a pointer to the bndwghts int vector created -- 97feb28, cca ------------------------------------------- */ int * ETree_bndwghts ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL || etree->bndwghtsIV == NULL ) { fprintf(stderr, "\n fatal error in ETree_bndwghts(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(IV_entries(etree->bndwghtsIV)) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- return a pointer to the vtxToFront IV object created -- 97feb28, cca -------------------------------------------- */ IV * ETree_vtxToFrontIV ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_vtxToFrontIV(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(etree->vtxToFrontIV) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- return a pointer to the vtxToFront int vector created -- 97feb28, cca --------------------------------------------- */ int * ETree_vtxToFront ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL || etree->vtxToFrontIV == NULL ) { fprintf(stderr, "\n fatal error in ETree_vtxToFront(%p)" "\n bad input\n", etree) ; exit(-1) ; } return(IV_entries(etree->vtxToFrontIV)) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- return the number of internal degrees of freedom in front J created -- 97may23, cca ------------------------------------------------ */ int ETree_frontSize ( ETree *etree, int J ) { /* --------------- check the input --------------- */ if ( etree == NULL || J < 0 || J >= etree->nfront ) { fprintf(stderr, "\n fatal error in ETree_frontSize(%p,%d)" "\n bad input\n", etree, J) ; exit(-1) ; } return(etree->nodwghtsIV->vec[J]) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- return the number of external degrees of freedom in front J created -- 97may23, cca ------------------------------------------------ */ int ETree_frontBoundarySize ( ETree *etree, int J ) { /* --------------- check the input --------------- */ if ( etree == NULL || J < 0 || J >= etree->nfront ) { fprintf(stderr, "\n fatal error in ETree_frontBoundarySize(%p,%d)" "\n bad input\n", etree, J) ; exit(-1) ; } return(etree->bndwghtsIV->vec[J]) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- compute the maximum number of indices and entries in a front symflag = SPOOLES_SYMMETRIC or SPOOLES_HERMITIAN --> count only column indices count upper entries in (1,1) block and (1,2) block symflag = SPOOLES_NONSYMMETRIC --> count row and column indices count entries in (1,1), (1,2) and (2,1) blocks created -- 97may23, cca ------------------------------------------------------------ */ void ETree_maxNindAndNent ( ETree *etree, int symflag, int *pmaxnind, int *pmaxnent ) { int J, maxnent, maxnind, nDJ, nent, nfront, nind, nUJ ; int *nodwghts, *bndwghts ; /* --------------- check the input --------------- */ if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_maxNindAndNent(%p,%d)" "\n bad input\n", etree, symflag) ; exit(-1) ; } nfront = etree->nfront ; nodwghts = ETree_nodwghts(etree) ; bndwghts = ETree_bndwghts(etree) ; for ( J = 0, maxnent = maxnind = 0 ; J < nfront ; J++ ) { nDJ = nodwghts[J] ; nUJ = bndwghts[J] ; switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : nind = nDJ + nUJ ; nent = (nDJ*(nDJ+1))/2 + nDJ*nUJ ; break ; case SPOOLES_NONSYMMETRIC : nind = 2*(nDJ + nUJ) ; nent = nDJ*(nDJ + 2*nUJ) ; break ; default : fprintf(stderr, "\n fatal error in ETree_maxNindAndNent(%p,%d)" "\n bad symflag\n", etree, symflag) ; exit(-1) ; break ; } if ( maxnind < nind ) { maxnind = nind ; } if ( maxnent < nent ) { maxnent = nent ; } } *pmaxnind = maxnind ; *pmaxnent = maxnent ; return ; } /*--------------------------------------------------------------------*/ ETree/src/justify.c010064400020550007177000000045260653410607400155410ustar00clevecompmath00000400000006/* justify.c */ #include "../ETree.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ left-justify a tree by subtree size children are linked in ascending order of their subtree size created -- 96jan11, cca ------------------------------------------------------------ */ void ETree_leftJustify ( ETree *etree ) { /* --------------- check the input --------------- */ if ( etree == NULL || etree->tree == NULL ) { fprintf(stderr, "\n fatal error in ETree_leftJustify(%p)" "\n bad input\n", etree) ; exit(-1) ; } Tree_leftJustify(etree->tree) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ left-justify a etree by a metric children are linked in ascending order of their metric created -- 96jan11, cca ------------------------------------------------------ */ void ETree_leftJustifyI ( ETree *etree, IV *metricIV ) { /* --------------- check the input --------------- */ if ( etree == NULL || etree->nfront <= 0 || etree->nvtx <= 0 || metricIV == NULL || IV_size(metricIV) != etree->nfront || IV_entries(metricIV) == NULL ) { fprintf(stderr, "\n fatal error in ETree_leftJustifyI(%p,%p)" "\n bad input\n", etree, metricIV) ; exit(-1) ; } Tree_leftJustifyI(etree->tree, metricIV) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ left-justify a etree by a metric children are linked in ascending order of their metric created -- 96jan11, cca ------------------------------------------------------ */ void ETree_leftJustifyD ( ETree *etree, DV *metricDV ) { /* --------------- check the input --------------- */ if ( etree == NULL || etree->nfront <= 0 || etree->nvtx <= 0 || metricDV == NULL || DV_size(metricDV) != etree->nfront || DV_entries(metricDV) == NULL ) { fprintf(stderr, "\n fatal error in ETree_leftJustifyD(%p,%p)" "\n bad input\n", etree, metricDV) ; exit(-1) ; } Tree_leftJustifyD(etree->tree, metricDV) ; return ; } /*--------------------------------------------------------------------*/ ETree/src/maps.c010064400020550007177000000553000665117760300150060ustar00clevecompmath00000400000006/* maps.c */ #include "../ETree.h" #define MYDEBUG 0 #define SUBTREE_SIZE 1 #define SUBTREE_OPS 2 #define SUBTREE_DEFINITION SUBTREE_OPS /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- this method constructs and returns an IV object that holds the map from fronts to threads for a wrap map of the front tree. created -- 96dec12, cca -------------------------------------------------------------- */ IV * ETree_wrapMap ( ETree *frontETree, int type, int symflag, DV *cumopsDV ) { double *cumops, *forwardOps ; DV *forwardOpsDV ; int jthread, J, nfront, nthread ; int *owners ; IV *ownersIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( frontETree == NULL || cumopsDV == NULL ) { fprintf(stderr, "\n fatal error in ETree_wrapMap(%p,%p)" "\n bad input\n", frontETree, cumopsDV) ; exit(-1) ; } tree = frontETree->tree ; DV_sizeAndEntries(cumopsDV, &nthread, &cumops) ; DV_zero(cumopsDV) ; /* --------------------------------- get a vector of forward op counts --------------------------------- */ forwardOpsDV = ETree_forwardOps(frontETree, type, symflag) ; DV_sizeAndEntries(forwardOpsDV, &nfront, &forwardOps) ; /* ------------------- load the map vector ------------------- */ ownersIV = IV_new() ; IV_init(ownersIV, nfront, NULL) ; owners = IV_entries(ownersIV) ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { jthread = J % nthread ; owners[J] = jthread ; cumops[jthread] += forwardOps[J] ; } /* ------------------------ free the working storage ------------------------ */ DV_free(forwardOpsDV) ; return(ownersIV) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- this method constructs and returns an IV object that holds the map from fronts to threads for a balanced map of the front tree. the fronts are visited in the post-order traversal. created -- 96dec12, cca ---------------------------------------------------------------- */ IV * ETree_balancedMap ( ETree *frontETree, int type, int symflag, DV *cumopsDV ) { double minops ; double *cumops, *forwardOps ; DV *forwardOpsDV ; int ithread, jthread, J, nfront, nthread ; int *owners ; IV *ownersIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( frontETree == NULL || cumopsDV == NULL ) { fprintf(stderr, "\n fatal error in ETree_balancedMap(%p,%p)" "\n bad input\n", frontETree, cumopsDV) ; exit(-1) ; } tree = frontETree->tree ; DV_sizeAndEntries(cumopsDV, &nthread, &cumops) ; DV_zero(cumopsDV) ; /* --------------------------------- get a vector of forward op counts --------------------------------- */ forwardOpsDV = ETree_forwardOps(frontETree, type, symflag) ; DV_sizeAndEntries(forwardOpsDV, &nfront, &forwardOps) ; /* ------------------- load the map vector ------------------- */ ownersIV = IV_new() ; IV_init(ownersIV, nfront, NULL) ; owners = IV_entries(ownersIV) ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { jthread = 0 ; minops = cumops[0] ; for ( ithread = 1 ; ithread < nthread ; ithread++ ) { if ( minops > cumops[ithread] ) { jthread = ithread ; minops = cumops[ithread] ; } } owners[J] = jthread ; cumops[jthread] += forwardOps[J] ; } /* ------------------------ free the working storage ------------------------ */ DV_free(forwardOpsDV) ; return(ownersIV) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- this method constructs and returns an IV object that holds the map from fronts to threads for a "subtree-subset" map of the front tree. created -- 97jan15, cca ----------------------------------------------- */ IV * ETree_subtreeSubsetMap ( ETree *frontETree, int type, int symflag, DV *cumopsDV ) { double offset, total ; double *cumops, *forwardOps, *tmetric ; DV *forwardOpsDV, *tmetricDV ; int I, J, mthread, nfront, nthread, q, qmin ; int *fch, *firsts, *lasts, *owners, *par, *sib ; IV *ownersIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( frontETree == NULL || cumopsDV == NULL ) { fprintf(stderr, "\n fatal error in ETree_subtreeSubsetMap(%p,%p)" "\n bad input\n", frontETree, cumopsDV) ; exit(-1) ; } tree = frontETree->tree ; fch = tree->fch ; par = tree->par ; sib = tree->sib ; DV_sizeAndEntries(cumopsDV, &nthread, &cumops) ; DV_zero(cumopsDV) ; /* --------------------------------- get a vector of forward op counts --------------------------------- */ forwardOpsDV = ETree_forwardOps(frontETree, type, symflag) ; DV_sizeAndEntries(forwardOpsDV, &nfront, &forwardOps) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n forwardOpsDV") ; DV_writeForHumanEye(forwardOpsDV, stdout) ; fflush(stdout) ; #endif /* -------------------------------- get the subtree metric DV object -------------------------------- */ tmetricDV = Tree_setSubtreeDmetric(tree, forwardOpsDV) ; tmetric = DV_entries(tmetricDV) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n tmetricDV") ; DV_writeForHumanEye(tmetricDV, stdout) ; fflush(stdout) ; #endif /* ----------------------------------- left justify the tree to make the assignment algorithm work correctly ----------------------------------- */ ETree_leftJustifyD(frontETree, tmetricDV) ; /* ----------------------------------------------------- fill two vectors that hold the first and last threads that are eligible to own a front ----------------------------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n\n pre-order traversal to determine eligible sets") ; fflush(stdout) ; #endif firsts = IVinit(nfront, -1) ; lasts = IVinit(nfront, -1) ; for ( J = Tree_preOTfirst(tree) ; J != -1 ; J = Tree_preOTnext(tree, J) ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n visiting front %d", J) ; fflush(stdout) ; #endif if ( par[J] == -1 ) { firsts[J] = 0 ; lasts[J] = nthread - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", root front") ; fflush(stdout) ; #endif } #if MYDEBUG > 0 fprintf(stdout, "\n first = %d, last = %d", firsts[J], lasts[J]) ; fflush(stdout) ; #endif if ( fch[J] != -1 ) { mthread = lasts[J] - firsts[J] + 1 ; total = tmetric[J] - forwardOps[J] ; #if MYDEBUG > 0 fprintf(stdout, "\n mthread = %d, total = %.0f", mthread, total) ; fflush(stdout) ; #endif for ( I = fch[J], offset = 0.0 ; I != -1 ; I = sib[I] ) { firsts[I] = firsts[J] + (int) (mthread*offset/total) ; #if MYDEBUG > 0 fprintf(stdout, "\n child %d, offset = %.0f, firsts[%d] = %d", I, offset, I, firsts[I]) ; fflush(stdout) ; #endif offset += tmetric[I] ; lasts[I] = firsts[J] + (int) (mthread*offset/total) - 1 ; if ( lasts[I] < firsts[I] ) { lasts[I] = firsts[I] ; } #if MYDEBUG > 0 fprintf(stdout, "\n child %d, offset = %.0f, lasts[%d] = %d", I, offset, I, lasts[I]) ; fflush(stdout) ; #endif } } } /* --------------------------------------------------------------- now fill the map IV object and cumops[*] vector with a balanced map using the candidate sets via a postorder traversal --------------------------------------------------------------- */ ownersIV = IV_new() ; IV_init(ownersIV, nfront, NULL) ; owners = IV_entries(ownersIV) ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { #if MYDEBUG > 0 fprintf(stdout, "\n front %d, firsts[%d] = %d, lasts[%d] = %d", J, J, firsts[J], J, lasts[J]) ; fflush(stdout) ; #endif qmin = firsts[J] ; for ( q = firsts[J] + 1 ; q <= lasts[J] ; q++ ) { if ( cumops[qmin] > cumops[q] ) { qmin = q ; } } owners[J] = qmin ; cumops[qmin] += forwardOps[J] ; #if MYDEBUG > 0 fprintf(stdout, ", owners[%d] = %d, cumops[%d] = %.0f", J, owners[J], qmin, cumops[qmin]) ; fflush(stdout) ; #endif } /* ------------------------ free the working storage ------------------------ */ DV_free(forwardOpsDV) ; DV_free(tmetricDV) ; IVfree(firsts) ; IVfree(lasts) ; return(ownersIV) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- this method constructs and returns an IV object that holds the map from fronts to threads for a domain decomposition balanced map of the front tree. the domains are mapped to threads using a balanced map, and the schur complement fronts are mapped to threads using a balanced map, but the two balanced maps are independent. created -- 97jan17, cca ---------------------------------------------------------------- */ IV * ETree_ddMap ( ETree *frontETree, int type, int symflag, DV *cumopsDV, double cutoff ) { double minops ; double *cumops, *domainops, *forwardOps, *schurops, *tmetric ; DV *forwardOpsDV, *tmetricDV ; int ithread, jthread, J, K, ndom, nfront, nthread, root ; int *ms, *owners, *par, *rootAnc ; IV *msIV, *ownersIV, *rootAncIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( frontETree == NULL || cumopsDV == NULL ) { fprintf(stderr, "\n fatal error in ETree_ddMap(%p,%p,%f)" "\n bad input\n", frontETree, cumopsDV, cutoff) ; exit(-1) ; } nfront = frontETree->nfront ; tree = frontETree->tree ; par = tree->par ; DV_sizeAndEntries(cumopsDV, &nthread, &cumops) ; DV_zero(cumopsDV) ; /* --------------------------------- get a vector of forward op counts --------------------------------- */ forwardOpsDV = ETree_forwardOps(frontETree, type, symflag) ; DV_sizeAndEntries(forwardOpsDV, &nfront, &forwardOps) ; #if MYDEBUG > 0 fprintf(stdout, "\n forwardOpsDV") ; DV_writeForHumanEye(forwardOpsDV, stdout) ; fflush(stdout) ; #endif #if SUBTREE_DEFINITION == SUBTREE_SIZE /* ----------------------------- get a vector of subtree sizes ----------------------------- */ { DV *tempDV ; IV *tempIV ; tempIV = ETree_nvtxMetric(frontETree) ; fprintf(stdout, "\n\n nvtx metric") ; IV_writeForHumanEye(tempIV, stdout) ; tempDV = DV_new() ; for ( J = 0 ; J < nfront ; J++ ) { DV_setEntry(tempDV, J, (double) IV_entry(tempIV, J)) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n double nvtx metric") ; DV_writeForHumanEye(tempDV, stdout) ; #endif tmetricDV = Tree_setSubtreeDmetric(tree, tempDV) ; IV_free(tempIV) ; DV_free(tempDV) ; } #endif #if SUBTREE_DEFINITION == SUBTREE_OPS tmetricDV = Tree_setSubtreeDmetric(tree, forwardOpsDV) ; #endif /* ------------------------ get a multisector vector ------------------------ */ msIV = IV_new() ; IV_init(msIV, nfront, NULL) ; IV_fill(msIV, 0) ; ms = IV_entries(msIV) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n double nvtx subtree metric") ; DV_writeForHumanEye(tmetricDV, stdout) ; #endif tmetric = DV_entries(tmetricDV) ; cutoff = cutoff * DV_max(tmetricDV) ; for ( J = 0 ; J < nfront ; J++ ) { if ( tmetric[J] < cutoff ) { ms[J] = 1 ; } } #if MYDEBUG > 0 fprintf(stdout, "\n msIV") ; IV_writeForHumanEye(msIV, stdout) ; fflush(stdout) ; #endif /* -------------------------------------------- create a rootAnc vector, if J is in a domain then rootAnc[J] is the root node of the domain else rootAnc[J] is the root node of the tree endif -------------------------------------------- */ rootAncIV = IV_new() ; IV_init(rootAncIV, nfront, NULL) ; rootAnc = IV_entries(rootAncIV) ; for ( J = nfront - 1 ; J >= 0 ; J-- ) { if ( (K = par[J]) == -1 || ms[J] != ms[K] ) { rootAnc[J] = J ; } else { rootAnc[J] = rootAnc[K] ; } } #if MYDEBUG > 0 fprintf(stdout, "\n rootAncIV") ; IV_writeForHumanEye(rootAncIV, stdout) ; fflush(stdout) ; #endif /* ------------------------------ initialize the ownersIV object ------------------------------ */ ownersIV = IV_new() ; IV_init(ownersIV, nfront, NULL) ; owners = IV_entries(ownersIV) ; /* -------------------------------------------------- assign the domains to threads using a balanced map -------------------------------------------------- */ domainops = DVinit(nthread, 0.0) ; root = -1 ; ndom = 0 ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { if ( ms[J] == 1 ) { if ( root != rootAnc[J] ) { ndom++ ; root = rootAnc[J] ; jthread = 0 ; minops = domainops[0] ; for ( ithread = 1 ; ithread < nthread ; ithread++ ) { if ( minops > domainops[ithread] ) { jthread = ithread ; minops = domainops[ithread] ; } } } owners[J] = jthread ; domainops[jthread] += forwardOps[J] ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %d domains", ndom) ; fprintf(stdout, "\n domainops") ; DVfprintf(stdout, nthread, domainops) ; fflush(stdout) ; #endif /* ------------------------------------------------------------------ assign the schur complement fronts to threads using a balanced map ------------------------------------------------------------------ */ schurops = DVinit(nthread, 0.0) ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { if ( ms[J] == 0 ) { jthread = 0 ; minops = schurops[0] ; for ( ithread = 1 ; ithread < nthread ; ithread++ ) { if ( minops > schurops[ithread] ) { jthread = ithread ; minops = schurops[ithread] ; } } owners[J] = jthread ; schurops[jthread] += forwardOps[J] ; } } #if MYDEBUG > 0 fprintf(stdout, "\n schurops") ; DVfprintf(stdout, nthread, schurops) ; fflush(stdout) ; #endif /* ------------------------------------- fill the cumulative operations vector ------------------------------------- */ for ( jthread = 0 ; jthread < nthread ; jthread++ ) { cumops[jthread] = domainops[jthread] + schurops[jthread] ; } #if MYDEBUG > 0 fprintf(stdout, "\n cumops") ; DVfprintf(stdout, nthread, cumops) ; fflush(stdout) ; #endif /* ------------------------ free the working storage ------------------------ */ DV_free(forwardOpsDV) ; DV_free(tmetricDV) ; IV_free(msIV) ; IV_free(rootAncIV) ; DVfree(domainops) ; DVfree(schurops) ; return(ownersIV) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- this method constructs and returns an IV object that holds the map from fronts to threads for a domain decomposition balanced map of the front tree. the domains are mapped to threads using a balanced map, and the schur complement fronts are mapped to threads using a balanced map, but the two balanced maps are independent. created -- 97jan17, cca ---------------------------------------------------------------- */ IV * ETree_ddMapNew ( ETree *frontETree, int type, int symflag, IV *msIV, DV *cumopsDV ) { double minops ; double *cumops, *domprios, *domops, *forwardOps, *schurprios, *schurops ; DV *forwardOpsDV ; int domid, idom, ireg, ithread, jthread, J, K, nbndJ, ndom, nfront, nJ, nschur, nthread, nvtx, v ; int *bndwghts, *domids, *dommap, *frontToRegion, *ms, *nodwghts, *owners, *par, *schurids, *vtxToFront ; IV *ownersIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( frontETree == NULL || cumopsDV == NULL ) { fprintf(stderr, "\n fatal error in ETree_ddMapNew(%p,%p,%p)" "\n bad input\n", frontETree, msIV, cumopsDV) ; exit(-1) ; } nfront = ETree_nfront(frontETree) ; nvtx = ETree_nvtx(frontETree) ; tree = ETree_tree(frontETree) ; vtxToFront = ETree_vtxToFront(frontETree) ; nodwghts = ETree_nodwghts(frontETree) ; bndwghts = ETree_bndwghts(frontETree) ; par = ETree_par(frontETree) ; DV_sizeAndEntries(cumopsDV, &nthread, &cumops) ; DV_zero(cumopsDV) ; ms = IV_entries(msIV) ; ownersIV = IV_new() ; IV_init(ownersIV, nfront, NULL) ; owners = IV_entries(ownersIV) ; /* -------------------------------------- compute the frontToRegion[] map vector -------------------------------------- */ frontToRegion = IVinit(nfront, -1) ; for ( v = 0 ; v < nvtx ; v++ ) { J = vtxToFront[v] ; frontToRegion[J] = ms[v] ; } #if MYDEBUG > 0 fprintf(stdout, "\n frontToRegion[] from msIV") ; IVfprintf(stdout, nfront, frontToRegion) ; #endif ndom = 0 ; for ( J = Tree_preOTfirst(tree) ; J != -1 ; J = Tree_preOTnext(tree, J) ) { if ( frontToRegion[J] != 0 ) { if ( (K = par[J]) != -1 ) { if ( frontToRegion[K] == 0 ) { frontToRegion[J] = ++ndom ; } else { frontToRegion[J] = frontToRegion[K] ; } } else { frontToRegion[J] = ++ndom ; } } } #if MYDEBUG > 0 fprintf(stdout, "\n frontToRegion[], separate domains") ; IVfprintf(stdout, nfront, frontToRegion) ; #endif /* --------------------------------- get a vector of forward op counts --------------------------------- */ forwardOpsDV = ETree_forwardOps(frontETree, type, symflag) ; forwardOps = DV_entries(forwardOpsDV) ; #if MYDEBUG > 0 fprintf(stdout, "\n forwardOpsDV") ; DV_writeForHumanEye(forwardOpsDV, stdout) ; #endif /* ---------------------------------------- for each domain, compute the forward ops ---------------------------------------- */ domprios = DVinit(ndom+1, 0.0) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (ireg = frontToRegion[J]) > 0 ) { domprios[ireg] += forwardOps[J] ; } } #if MYDEBUG > 0 fprintf(stdout, "\n domprios[], sum = %.0f", DVsum(ndom, domprios+1)) ; DVfprintf(stdout, ndom+1, domprios) ; #endif /* -------------------------------------------------------- sort the domains by descending order of their operations -------------------------------------------------------- */ domids = IVinit(ndom, -1) ; IVramp(ndom, domids, 1, 1) ; #if MYDEBUG > 0 fprintf(stdout, "\n before sort: domids") ; IVfprintf(stdout, ndom, domids) ; fprintf(stdout, "\n before sort: domprios") ; DVfprintf(stdout, ndom, domprios+1) ; #endif DVIVqsortDown(ndom, domprios + 1, domids) ; #if MYDEBUG > 0 fprintf(stdout, "\n after sort: domids") ; IVfprintf(stdout, ndom, domids) ; fprintf(stdout, "\n after sort: domprios") ; DVfprintf(stdout, ndom, domprios+1) ; #endif /* ---------------------------- assign domains to processors ---------------------------- */ dommap = IVinit(ndom+1, -1) ; domops = DVinit(nthread, 0.0) ; for ( idom = 0 ; idom < ndom ; idom++ ) { domid = domids[idom] ; jthread = 0 ; minops = domops[0] ; for ( ithread = 1 ; ithread < nthread ; ithread++ ) { if ( domops[ithread] < minops ) { jthread = ithread ; minops = domops[ithread] ; } } dommap[domid] = jthread ; domops[jthread] += domprios[idom+1] ; #if MYDEBUG > 0 fprintf(stdout, "\n assigning domain %d with ops %.0f to thread %d, new ops = %.0f", domid, domprios[idom+1], jthread, domops[jthread]) ; #endif } #if MYDEBUG > 0 fprintf(stdout, "\n domops[]") ; DVfprintf(stdout, nthread, domops) ; #endif /* ------------------------------------- assign fronts in domains to processes ------------------------------------- */ for ( J = 0 ; J < nfront ; J++ ) { if ( (idom = frontToRegion[J]) > 0 ) { owners[J] = dommap[idom] ; } } /* ----------------------------------------------------- now compute priorities of the schur complement fronts ----------------------------------------------------- */ schurprios = DVinit(nfront, 0.0) ; for ( J = 0 ; J < nfront ; J++ ) { if ( frontToRegion[J] == 0 ) { nJ = nodwghts[J] ; nbndJ = bndwghts[J] ; schurprios[J] = nJ*nJ*(nJ + nbndJ) ; } } #if MYDEBUG > 0 fprintf(stdout, "\n schur front ops") ; DVfprintf(stdout, nfront, schurprios) ; #endif for ( J = Tree_preOTfirst(tree) ; J != -1 ; J = Tree_preOTnext(tree, J) ) { if ( frontToRegion[J] == 0 ) { if ( (K = par[J]) != -1 ) { schurprios[J] += schurprios[K] ; } } } /* -------------------------------------------------- sort the priorities of the schur complement fronts in descending order of their priorities -------------------------------------------------- */ schurids = IVinit(nfront, -1) ; for ( J = nschur = 0 ; J < nfront ; J++ ) { if ( frontToRegion[J] == 0 ) { schurids[nschur] = J ; schurprios[nschur] = schurprios[J] ; nschur++ ; } } #if MYDEBUG > 0 fprintf(stdout, "\n before sort: schurids") ; IVfprintf(stdout, nschur, schurids) ; fprintf(stdout, "\n before sort: schurprios") ; DVfprintf(stdout, nschur, schurprios) ; #endif DVIVqsortDown(nschur, schurprios, schurids) ; #if MYDEBUG > 0 fprintf(stdout, "\n after sort: schurids") ; IVfprintf(stdout, nschur, schurids) ; fprintf(stdout, "\n after sort: schurprios") ; DVfprintf(stdout, nschur, schurprios) ; #endif /* --------------------------------- assign schur fronts to processors --------------------------------- */ schurops = DVinit(nthread, 0.0) ; for ( ireg = 0 ; ireg < nschur ; ireg++ ) { J = schurids[ireg] ; jthread = 0 ; minops = schurops[0] ; for ( ithread = 1 ; ithread < nthread ; ithread++ ) { if ( schurops[ithread] < minops ) { jthread = ithread ; minops = schurops[ithread] ; } } owners[J] = jthread ; schurops[jthread] += forwardOps[J] ; #if MYDEBUG > 0 fprintf(stdout, "\n assigning schur front %d to thread %d, new ops = %.0f", J, jthread, schurops[jthread]) ; #endif } /* ------------------------------ fill the cumulative ops vector ------------------------------ */ for ( jthread = 0 ; jthread < nthread ; jthread++ ) { cumops[jthread] = domops[jthread] + schurops[jthread] ; } #if MYDEBUG > 0 fprintf(stdout, "\n domops[]") ; DVfprintf(stdout, nthread, domops) ; fprintf(stdout, "\n schurops[]") ; DVfprintf(stdout, nthread, schurops) ; fprintf(stdout, "\n sum(domops) = %.0f", DVsum(nthread, domops)) ; fprintf(stdout, "\n sum(schurops) = %.0f", DVsum(nthread, schurops)) ; fprintf(stdout, "\n sum(cumops) = %.0f", DV_sum(cumopsDV)) ; #endif /* ------------------------ free the working storage ------------------------ */ IVfree(frontToRegion) ; IVfree(domids) ; IVfree(dommap) ; IVfree(schurids) ; DV_free(forwardOpsDV) ; DVfree(domprios) ; DVfree(domops) ; DVfree(schurprios) ; DVfree(schurops) ; return(ownersIV) ; } /*--------------------------------------------------------------------*/ ; minops = domainops[0] ; for ( ithread = 1 ; ithread < nthread ; ithread++ ) { if ( minops > domainops[ithread] ) { jthread = ithread ; minops = domainops[ithread] ; } } } owners[J] = jthread ; domainops[jthread] += fETree/src/metrics.c010064400020550007177000000061220653601236100155010ustar00clevecompmath00000400000006/* metrics.c */ #include "../ETree.h" /*--------------------------------------------------------------------*/ /* ------------------------------------ return an IV object with the weights of the vertices in each front. created -- 96jun23, cca ------------------------------------ */ IV * ETree_nvtxMetric ( ETree *etree ) { IV *metricIV ; /* --------------- check the input --------------- */ if ( etree == NULL || etree->nfront <= 0 || etree->nvtx <= 0 ) { fprintf(stderr, "\n fatal error in ETree_nvtxMetric(%p)" "\n bad input\n", etree) ; exit(-1) ; } metricIV = IV_new() ; IV_init(metricIV, etree->nfront, NULL) ; IVcopy(etree->nfront, IV_entries(metricIV), IV_entries(etree->nodwghtsIV)) ; return(metricIV) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- return an IV object with the number of factor entries in each front. symflag -- symmetryflag SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 96jun23, cca --------------------------------------------------------------- */ IV * ETree_nentMetric ( ETree *etree, int flag ) { int front, nfront, nb, nv ; int *bndwghts, *metric, *nodwghts ; IV *metricIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || etree->nvtx <= 0 ) { fprintf(stderr, "\n fatal error in ETree_nentMetric(%p)" "\n bad input\n", etree) ; exit(-1) ; } metricIV = IV_new() ; IV_init(metricIV, nfront, NULL) ; metric = IV_entries(metricIV) ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; if ( flag == 1 ) { for ( front = 0 ; front < nfront ; front++ ) { nv = nodwghts[front] ; nb = bndwghts[front] ; metric[front] = (nv*(nv+1))/2 + nv*nb ; } } else if ( flag == 2 ) { for ( front = 0 ; front < nfront ; front++ ) { nv = nodwghts[front] ; nb = bndwghts[front] ; metric[front] = nv*nv + 2*nv*nb ; } } return(metricIV) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- return a DV object with the number of factor operations in each front. type -- type of entries, SPOOLES_REAL or SPOOLES_COMPLEX symflag -- symmetryflag, SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 96jun23, cca --------------------------------------------------------------- */ DV * ETree_nopsMetric ( ETree *etree, int type, int symflag ) { DV *metricDV ; /* --------------- check the input --------------- */ if ( etree == NULL || etree->nfront <= 0 || etree->nvtx <= 0 ) { fprintf(stderr, "\n fatal error in ETree_nopsMetric(%p)" "\n bad input\n", etree) ; exit(-1) ; } metricDV = ETree_forwardOps(etree, type, symflag) ; return(metricDV) ; } /*--------------------------------------------------------------------*/ ------------------------------*/ /* ------------------------------------ return an IV object with the weights of the vertices in each front. created -- 96jun23, cca ------------------------------------ */ IV * ETree_nvtxMetric ( ETree *etree ) { IV *metricIV ; /* --------------- check the input --------------- */ if ( etree == NULL || etree->nfront <= 0 || etree->nvtx <= 0 ) { fprintf(stderETree/src/ms.c010064400020550007177000000311530653604473000144610ustar00clevecompmath00000400000006/* ms.c */ #include "../ETree.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------ returns a compidsIV IV object that maps the vertices to a domain (compids[v] > 1) or to the multisector (compids[v] = 0). the vertices in the multisector is specified by their depth of their front in the tree. created -- 96jan04, cca ------------------------------------------------ */ IV * ETree_msByDepth ( ETree *etree, int depth ) { int front, nfront, nvtx, v ; int *compids, *dmetric, *vtxToFront ; IV *compidsIV, *vmetricIV, *dmetricIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 || depth <= 0 ) { fprintf(stderr, "\n fatal error in ETree_msByDepth(%p,%d)" "\n bad input\n", etree, depth) ; exit(-1) ; } vtxToFront = IV_entries(etree->vtxToFrontIV) ; /* -------------------- get the depth metric -------------------- */ vmetricIV = IV_new() ; IV_init(vmetricIV, nfront, NULL) ; IV_fill(vmetricIV, 1) ; dmetricIV = Tree_setDepthImetric(etree->tree, vmetricIV) ; dmetric = IV_entries(dmetricIV) ; #if MYDEBUG > 0 { int ierr ; fprintf(stdout, "\n ETree_msByDepth") ; fprintf(stdout, "\n vmetric") ; IV_writeForHumanEye(vmetricIV, stdout) ; fprintf(stdout, "\n dmetric") ; IV_writeForHumanEye(dmetricIV, stdout) ; } #endif IV_free(vmetricIV) ; /* -------------------------------------------------- fill the IV object with the ids in the multisector -------------------------------------------------- */ compidsIV = IV_new() ; IV_init(compidsIV, nvtx, NULL) ; compids = IV_entries(compidsIV) ; for ( v = 0 ; v < nvtx ; v++ ) { front = vtxToFront[v] ; if ( dmetric[front] <= depth ) { compids[v] = 0 ; } else { compids[v] = 1 ; } } IV_free(dmetricIV) ; return(compidsIV) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- construct a multisector based on vertices found in a subtree. created -- 96jan04, cca ---------------------------------------------------------------- */ IV * ETree_msByNvtxCutoff ( ETree *etree, double cutoff ) { int front, nfront, nvtx, v ; int *compids, *tmetric, *vtxToFront ; IV *compidsIV, *tmetricIV, *vmetricIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_msByCutoff(%p,%f)" "\n bad input\n", etree, cutoff) ; exit(-1) ; } vtxToFront = IV_entries(etree->vtxToFrontIV) ; /* ---------------------- get the subtree metric ---------------------- */ vmetricIV = ETree_nvtxMetric(etree) ; tmetricIV = Tree_setSubtreeImetric(etree->tree, vmetricIV) ; #if MYDEBUG > 0 fprintf(stdout, "\n ETree_msByNvtxCutoff") ; fprintf(stdout, "\n vmetric") ; IV_writeForHumanEye(vmetricIV, stdout) ; fprintf(stdout, "\n tmetric") ; IV_writeForHumanEye(tmetricIV, stdout) ; fflush(stdout) ; #endif IV_free(vmetricIV) ; cutoff = cutoff * IV_max(tmetricIV) ; /* -------------------------------------------------- fill the IV object with the ids in the multisector -------------------------------------------------- */ compidsIV = IV_new() ; IV_init(compidsIV, nvtx, NULL) ; compids = IV_entries(compidsIV) ; tmetric = IV_entries(tmetricIV) ; for ( v = 0 ; v < nvtx ; v++ ) { front = vtxToFront[v] ; if ( tmetric[front] >= cutoff ) { compids[v] = 0 ; } else { compids[v] = 1 ; } } IV_free(tmetricIV) ; return(compidsIV) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- construct a multisector based on the number of factor entries found in a subtree. symflag -- symmetry flag, one of SPOOLES_SYMMETRIC SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 96jan04, cca -------------------------------------------------- */ IV * ETree_msByNentCutoff ( ETree *etree, double cutoff, int symflag ) { int front, nfront, nvtx, v ; int *compids, *tmetric, *vtxToFront ; IV *compidsIV, *tmetricIV, *vmetricIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_msByCutoff(%p,%f,%d)" "\n bad input\n", etree, cutoff, symflag) ; exit(-1) ; } vtxToFront = IV_entries(etree->vtxToFrontIV) ; /* ---------------------- get the subtree metric ---------------------- */ vmetricIV = ETree_nentMetric(etree, symflag) ; tmetricIV = Tree_setSubtreeImetric(etree->tree, vmetricIV) ; #if MYDEBUG > 0 fprintf(stdout, "\n ETree_msByNentCutoff") ; fprintf(stdout, "\n vmetric") ; IV_writeForHumanEye(vmetricIV, stdout) ; fprintf(stdout, "\n tmetric") ; IV_writeForHumanEye(tmetricIV, stdout) ; fflush(stdout) ; #endif IV_free(vmetricIV) ; cutoff = cutoff * IV_max(tmetricIV) ; /* -------------------------------------------------- fill the IV object with the ids in the multisector -------------------------------------------------- */ compidsIV = IV_new() ; IV_init(compidsIV, nvtx, NULL) ; compids = IV_entries(compidsIV) ; tmetric = IV_entries(tmetricIV) ; for ( v = 0 ; v < nvtx ; v++ ) { front = vtxToFront[v] ; if ( tmetric[front] >= cutoff ) { compids[v] = 0 ; } else { compids[v] = 1 ; } } IV_free(tmetricIV) ; return(compidsIV) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- construct a multisector based on the number of factor operations found in a subtree. type -- type of entries, SPOOLES_REAL or SPOOLES_COMPLEX symflag -- symmetry flag, one of SPOOLES_SYMMETRIC SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 96jan04, cca -------------------------------------------------- */ IV * ETree_msByNopsCutoff ( ETree *etree, double cutoff, int type, int symflag ) { double *tmetric ; DV *tmetricDV, *vmetricDV ; int front, nfront, nvtx, v ; int *compids, *vtxToFront ; IV *compidsIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_msByCutoff(%p,%f,%d)" "\n bad input\n", etree, cutoff, symflag) ; exit(-1) ; } vtxToFront = IV_entries(etree->vtxToFrontIV) ; /* ---------------------- get the subtree metric ---------------------- */ vmetricDV = ETree_nopsMetric(etree, type, symflag) ; tmetricDV = Tree_setSubtreeDmetric(etree->tree, vmetricDV) ; #if MYDEBUG >= 0 fprintf(stdout, "\n ETree_msByNopsCutoff") ; fprintf(stdout, "\n vmetric") ; DV_writeForHumanEye(vmetricDV, stdout) ; fprintf(stdout, "\n tmetric") ; DV_writeForHumanEye(tmetricDV, stdout) ; fflush(stdout) ; fprintf(stdout, "\n max(tmetricDV) = %.0f, sum(vmetricDV) = %.0f", DV_max(tmetricDV), DV_sum(vmetricDV)) ; fprintf(stdout, "\n cutoff = %.0f", cutoff * DV_max(tmetricDV)) ; #endif cutoff = cutoff * DV_max(tmetricDV) ; /* -------------------------------------------------- fill the IV object with the ids in the multisector -------------------------------------------------- */ compidsIV = IV_new() ; IV_init(compidsIV, nvtx, NULL) ; compids = IV_entries(compidsIV) ; tmetric = DV_entries(tmetricDV) ; for ( v = 0 ; v < nvtx ; v++ ) { front = vtxToFront[v] ; if ( tmetric[front] >= cutoff ) { compids[v] = 0 ; } else { compids[v] = 1 ; } } { double domops, schurops ; double *vmetric ; int J ; vmetric = DV_entries(vmetricDV) ; domops = schurops = 0.0 ; for ( J = 0 ; J < nfront ; J++ ) { if ( tmetric[J] >= cutoff ) { schurops += vmetric[J] ; } else { domops += vmetric[J] ; } } fprintf(stdout, "\n domops = %.0f, schurops = %.0f, total = %.0f", domops, schurops, domops + schurops) ; } /* ------------------------ free the working storage ------------------------ */ DV_free(vmetricDV) ; DV_free(tmetricDV) ; return(compidsIV) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- given a front tree and a multisector map vector, fill the map vector with domain ids and the three statistics arrays with domain and schur complement statistics. frontETree -- front tree object, unchanged on output msIV -- map from fronts to domains or schur complement on input, ms[v] = 0 --> v is in the schur complement ms[v] = 1 --> v is not in the schur complement on output, ms[v] = 0 --> v is in the schur complement ms[v] != 0 --> v is in domain ms[v] on output nvtxIV -- nvtx[ireg] = # of dof in region ireg nzfIV -- nzf[ireg] = # of factor entries in region ireg opsIV -- ops[ireg] = # of factor ops in region ireg type -- type of entries, SPOOLES_REAL or SPOOLES_COMPLEX symflag -- symmetry flag, one of SPOOLES_SYMMETRIC SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 98jan30, cca -------------------------------------------------------------- */ void ETree_msStats ( ETree *frontETree, IV *msIV, IV *nvtxIV, IV *nzfIV, DV *opsDV, int type, int symflag ) { double *opsreg, *opsvec ; DV *opsvecDV ; int J, K, ndom, nfront, nvtx, reg, v ; int *map, *ms, *nodwghts, *nvtxreg, *nzfreg, *nzfvec, *par, *vtxToFront ; IV *nzfvecIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( frontETree == NULL || msIV == NULL || nvtxIV == NULL || nzfIV == NULL || opsDV == NULL ) { fprintf(stderr, "\n fatal error in ETree_msStats()" "\n frontETree = %p, msIV = %p, nvtxIV = %p" "\n nzfIV = %p, opsDV = %p, symflag = %d\n", frontETree, msIV, nvtxIV, nzfIV, opsDV, symflag) ; exit(-1) ; } nfront = ETree_nfront(frontETree) ; nvtx = ETree_nvtx(frontETree) ; tree = ETree_tree(frontETree) ; par = ETree_par(frontETree) ; vtxToFront = ETree_vtxToFront(frontETree) ; ms = IV_entries(msIV) ; /* ---------------------------------------- if J is not in the schur complement then fill ms[J] with its domain id endif ---------------------------------------- */ map = IVinit(nfront, -1) ; for ( v = 0 ; v < nvtx ; v++ ) { J = vtxToFront[v] ; map[J] = ms[v] ; /* fprintf(stdout, "\n vertex %d, front %d, map %d", v, J, map[J]) ; */ } ndom = 0 ; for ( J = Tree_preOTfirst(tree) ; J != -1 ; J = Tree_preOTnext(tree, J) ) { /* fprintf(stdout, "\n J = %d", J) ; */ if ( map[J] != 0 ) { if ( (K = par[J]) != -1 ) { if ( map[K] == 0 ) { map[J] = ++ndom ; } else { map[J] = map[K] ; } } else { map[J] = ++ndom ; } /* fprintf(stdout, ", in domain %d", map[J]) ; } else { fprintf(stdout, ", schur complement front") ; */ } } for ( v = 0 ; v < nvtx ; v++ ) { J = vtxToFront[v] ; ms[v] = map[J] ; /* fprintf(stdout, "\n vertex %d, front %d, region %d", v, J, map[J]) ; */ } /* -------------------------------------------------- set sizes of the nvtxIV, nzfIV and opsV vectors to hold the domain and schur complement statistics -------------------------------------------------- */ IV_setSize(nvtxIV, ndom+1) ; IV_setSize(nzfIV, ndom+1) ; DV_setSize(opsDV, ndom+1) ; nvtxreg = IV_entries(nvtxIV) ; nzfreg = IV_entries(nzfIV) ; opsreg = DV_entries(opsDV) ; IVzero(ndom+1, nvtxreg) ; IVzero(ndom+1, nzfreg) ; DVzero(ndom+1, opsreg) ; /* --------------------------------- get the statistics for the fronts --------------------------------- */ nodwghts = ETree_nodwghts(frontETree) ; nzfvecIV = ETree_factorEntriesIV(frontETree, symflag) ; nzfvec = IV_entries(nzfvecIV) ; opsvecDV = ETree_forwardOps(frontETree, type, symflag) ; opsvec = DV_entries(opsvecDV) ; /* ---------------------------------- fill the region statistics vectors ---------------------------------- */ for ( J = 0 ; J < nfront ; J++ ) { reg = map[J] ; nvtxreg[reg] += nodwghts[J] ; nzfreg[reg] += nzfvec[J] ; opsreg[reg] += opsvec[J] ; } /* ------------------------ free the working storage ------------------------ */ IV_free(nzfvecIV) ; DV_free(opsvecDV) ; IVfree(map) ; return ; } /*--------------------------------------------------------------------*/ = 0 ; } else { compids[v] = 1 ; } } IV_free(tmetricIV) ; return(compidsIV) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- construct a multisector based on the number of factor entries found in a subtree. symflag -- symmetry flag, one of SPOOLES_SYMMETRIC SPOOLES_HERMITIAN or SPOOLES_NONETree/src/permute.c010064400020550007177000000154400653410607400155220ustar00clevecompmath00000400000006/* permute.c */ #include "../ETree.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- fill the new-to-old permutation vector for the fronts created -- 96jun23, cca ----------------------------------------------------- */ IV * ETree_newToOldFrontPerm ( ETree *etree ) { int nfront, nvtx ; IV *newToOldIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_newToOldFrontPerm(%p)" "\n bad input\n", etree) ; exit(-1) ; } newToOldIV = IV_new() ; IV_init(newToOldIV, nfront, NULL) ; /* ------------------------------------------------------ fill the permutation vector by calling the Tree method ------------------------------------------------------ */ Tree_fillNewToOldPerm(etree->tree, IV_entries(newToOldIV)) ; return(newToOldIV) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- fill the old-to-new permutation vector for the fronts created -- 96jun23, cca ----------------------------------------------------- */ IV * ETree_oldToNewFrontPerm ( ETree *etree ) { int nfront, nvtx ; IV *oldToNewIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_oldToNewFrontPerm(%p)" "\n bad input\n", etree) ; exit(-1) ; } oldToNewIV = IV_new() ; IV_init(oldToNewIV, nfront, NULL) ; /* ------------------------------------------------------ fill the permutation vector by calling the Tree method ------------------------------------------------------ */ Tree_fillOldToNewPerm(etree->tree, IV_entries(oldToNewIV)) ; return(oldToNewIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- fill the new-to-old permutation vector for the vertices created -- 96oct05, cca ------------------------------------------------------- */ IV * ETree_newToOldVtxPerm ( ETree *etree ) { int count, front, nfront, nvtx, v ; int *head, *link, *newToOld, *vtxToFront ; IV *newToOldVtxIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_newToOldVtxPerm(%p)" "\n bad input\n", etree) ; exit(-1) ; } vtxToFront = IV_entries(etree->vtxToFrontIV) ; /* ---------------------------------------------------- allocate the old-to-new vertex permutation IV object ---------------------------------------------------- */ newToOldVtxIV = IV_new() ; IV_init(newToOldVtxIV, nvtx, NULL) ; newToOld = IV_entries(newToOldVtxIV) ; /* ------------------------------------------------------- get the head/link structure for the vertices and fronts ------------------------------------------------------- */ head = IVinit(nfront, -1) ; link = IVinit(nvtx, -1) ; for ( v = nvtx - 1 ; v >= 0 ; v-- ) { front = vtxToFront[v] ; link[v] = head[front] ; head[front] = v ; } /* ---------------------------------------------- loop over the fronts in a post-order traversal ---------------------------------------------- */ count = 0 ; for ( front = Tree_postOTfirst(etree->tree) ; front != -1 ; front = Tree_postOTnext(etree->tree, front) ) { for ( v = head[front] ; v != -1 ; v = link[v] ) { newToOld[count++] = v ; } } IVfree(head) ; IVfree(link) ; return(newToOldVtxIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- fill the old-to-new permutation vector for the vertices created -- 96jun23, cca ------------------------------------------------------- */ IV * ETree_oldToNewVtxPerm ( ETree *etree ) { int count, front, nfront, nvtx, v ; int *head, *link, *oldToNew, *vtxToFront ; IV *oldToNewVtxIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_oldToNewVtxPerm(%p)" "\n bad input\n", etree) ; exit(-1) ; } vtxToFront = IV_entries(etree->vtxToFrontIV) ; /* ---------------------------------------------------- allocate the old-to-new vertex permutation IV object ---------------------------------------------------- */ oldToNewVtxIV = IV_new() ; IV_init(oldToNewVtxIV, nvtx, NULL) ; oldToNew = IV_entries(oldToNewVtxIV) ; /* ------------------------------------------------------- get the head/link structure for the vertices and fronts ------------------------------------------------------- */ head = IVinit(nfront, -1) ; link = IVinit(nvtx, -1) ; for ( v = nvtx - 1 ; v >= 0 ; v-- ) { front = vtxToFront[v] ; link[v] = head[front] ; head[front] = v ; } /* ---------------------------------------------- loop over the fronts in a post-order traversal ---------------------------------------------- */ count = 0 ; for ( front = Tree_postOTfirst(etree->tree) ; front != -1 ; front = Tree_postOTnext(etree->tree, front) ) { for ( v = head[front] ; v != -1 ; v = link[v] ) { oldToNew[v] = count++ ; } } IVfree(head) ; IVfree(link) ; return(oldToNewVtxIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- permute the vertices, overwrite entries in the vertex-to-front map created -- 96oct03, cca ------------------------------------------------------- */ void ETree_permuteVertices ( ETree *etree, IV *vtxOldToNewIV ) { int nvtx, v ; int *oldToNew, *temp, *vtxToFront ; /* --------------- check the input --------------- */ if ( etree == NULL || vtxOldToNewIV == NULL || (nvtx = etree->nvtx) <= 0 || nvtx != IV_size(vtxOldToNewIV) ) { fprintf(stderr, "\n fatal error in ETree_permuteVertices(%p,%p)" "\n bad input\n", etree, vtxOldToNewIV) ; if ( etree != NULL && vtxOldToNewIV != NULL ) { fprintf(stderr, "\n etree->nvtx = %d, IV_size(vtxOldToNewIV) = %d\n", etree->nvtx, IV_size(vtxOldToNewIV)) ; } exit(-1) ; } vtxToFront = IV_entries(etree->vtxToFrontIV) ; oldToNew = IV_entries(vtxOldToNewIV) ; temp = IVinit(nvtx, -1) ; for ( v = 0 ; v < nvtx ; v++ ) { temp[oldToNew[v]] = vtxToFront[v] ; } IVcopy(nvtx, vtxToFront, temp) ; IVfree(temp) ; return ; } /*--------------------------------------------------------------------*/ wFrontPerm ( ETree *etree ) { int nfront, nvtx ; IV *oldToNewIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <=ETree/src/semi.c010064400020550007177000000142260654303644300150010ustar00clevecompmath00000400000006/* semi.c */ #include "../ETree.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to find the optimal domain/schur complement partition for a semi-implict factorization. the gain of a subtree sbt(J) is equal to |L_{bnd{J},sbt{J}}| - |A_{bnd{J},sbt{J}}| - alpha *|L_{sbt{J},sbt{J}}| when alpha = 0 we minimize active storage when alpha = 1 we minimize solve operations *ptotalgain is filled with the total gain the return value is compidsIV, compids[J] = 0 --> J is in the schur complement compids[J] != 0 --> J is in domain compids[J] created -- 98jun20, cca ----------------------------------------------------- */ IV * ETree_optPart ( ETree *etree, Graph *graph, IVL *symbfacIVL, double alpha, int *ptotalgain, int msglvl, FILE *msgFile ) { int ii, I, J, K, nfront, nvtx, sizeJ, v, vsize, w, wght, wghtJ ; int *adjJ, *colCountsA, *colCountsL, *colSbtCountsA, *colSbtCountsL, *diagCountsL, *diagSbtCountsL, *fch, *gain, *nodwghts, *rowCountsA, *rowCountsL, *sib, *vadj, *vtxToFront, *vwghts ; IV *compidsIV, *gainIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || graph == NULL || symbfacIVL == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in ETree_optPart()" "\n bad input\n") ; exit(-1) ; } nfront = etree->nfront ; nodwghts = ETree_nodwghts(etree) ; vtxToFront = ETree_vtxToFront(etree) ; tree = etree->tree ; fch = tree->fch ; sib = tree->sib ; if ( (nvtx = graph->nvtx) != etree->nvtx ) { fprintf(stderr, "\n fatal error in ETree_optPart()" "\n etree->nvtx = %d, graph->nvtx = %d\n", etree->nvtx, graph->nvtx) ; exit(-1) ; } vwghts = graph->vwghts ; /* --------------------------------------- compute the # of entries in the offdiagonal front rows and columns of A --------------------------------------- */ rowCountsA = IVinit(nfront, 0) ; colCountsA = IVinit(nfront, 0) ; for ( v = 0 ; v < nvtx ; v++ ) { J = vtxToFront[v] ; Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( (K = vtxToFront[w]) > J ) { wght = (vwghts == NULL) ? 1 : vwghts[v]*vwghts[w] ; colCountsA[J] += wght ; rowCountsA[K] += wght ; } } } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n rowCountsA") ; IVfprintf(msgFile, nfront, rowCountsA) ; fprintf(msgFile, "\n\n colCountsA") ; IVfprintf(msgFile, nfront, colCountsA) ; } /* --------------------------------------------------------- compute colSbtCountsA[J] = # entries in A_{bnd{J},sbt{J}} --------------------------------------------------------- */ colSbtCountsA = IVinit(nfront, 0) ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { colSbtCountsA[J] = colCountsA[J] - rowCountsA[J] ; for ( I = fch[J] ; I != -1 ; I = sib[I] ) { colSbtCountsA[J] += colSbtCountsA[I] ; } } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n colSbtCountsA") ; IVfprintf(msgFile, nfront, colSbtCountsA) ; } /* --------------------------------------- compute the # of entries in the offdiagonal front rows and columns of L --------------------------------------- */ rowCountsL = IVinit(nfront, 0) ; colCountsL = IVinit(nfront, 0) ; diagCountsL = IVinit(nfront, 0) ; for ( J = 0 ; J < nfront ; J++ ) { IVL_listAndSize(symbfacIVL, J, &sizeJ, &adjJ) ; wghtJ = nodwghts[J] ; diagCountsL[J] = (wghtJ*(wghtJ+1))/2 ; for ( ii = 0 ; ii < sizeJ ; ii++ ) { v = adjJ[ii] ; if ( (K = vtxToFront[J]) > J ) { wght = (vwghts == NULL) ? 1 : wghtJ*vwghts[v] ; colCountsL[J] += wght ; rowCountsL[K] += wght ; } } } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n rowCountsL") ; IVfprintf(msgFile, nfront, rowCountsL) ; fprintf(msgFile, "\n\n colCountsL") ; IVfprintf(msgFile, nfront, colCountsL) ; fprintf(msgFile, "\n\n diagCountsL") ; IVfprintf(msgFile, nfront, diagCountsL) ; } /* --------------------------------------------------------- compute colSbtCountsL[J] = # entries in L_{bnd{J},sbt{J}} compute diagSbtCountsL[J] = # entries in L_{sbt{J},sbt{J}} --------------------------------------------------------- */ colSbtCountsL = IVinit(nfront, 0) ; diagSbtCountsL = IVinit(nfront, 0) ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { colSbtCountsL[J] = colCountsL[J] - rowCountsL[J] ; diagSbtCountsL[J] = rowCountsL[J] ; for ( I = fch[J] ; I != -1 ; I = sib[I] ) { colSbtCountsL[J] += colSbtCountsL[I] ; diagSbtCountsL[J] += diagSbtCountsL[I] ; } } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n colSbtCountsL") ; IVfprintf(msgFile, nfront, colSbtCountsL) ; fprintf(msgFile, "\n\n diagSbtCountsL") ; IVfprintf(msgFile, nfront, diagSbtCountsL) ; } /* ----------------------- compute the gain vector ----------------------- */ gainIV = IV_new() ; IV_init(gainIV, nfront, NULL) ; gain = IV_entries(gainIV) ; for ( J = 0 ; J < nfront ; J++ ) { gain[J] = colSbtCountsL[J] - colSbtCountsA[J] - alpha*diagCountsL[J] ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n gain") ; IVfprintf(msgFile, nfront, gain) ; } /* ---------------------------------------------- get the component ids of the optimal partition ---------------------------------------------- */ compidsIV = Tree_maximizeGainIV(tree, gainIV, ptotalgain, msglvl, msgFile) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n total gain = %d", *ptotalgain) ; fprintf(msgFile, "\n\n compidsIV") ; IV_writeForHumanEye(compidsIV, msgFile) ; } /* ------------------------ free the working storage ------------------------ */ IVfree(colCountsA) ; IVfree(rowCountsA) ; IVfree(colSbtCountsA) ; IVfree(colCountsL) ; IVfree(rowCountsL) ; IVfree(diagCountsL) ; IVfree(colSbtCountsL) ; IVfree(diagSbtCountsL) ; IV_free(gainIV) ; return(compidsIV) ; } /*--------------------------------------------------------------------*/ ETree/src/storage.c010064400020550007177000000343010663673513100155070ustar00clevecompmath00000400000006/* storage.c */ #include "../ETree.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- fill dvec[J] with the active storage to eliminate J using the multifrontal method symflag -- symmetry flag, one of SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 97may21, cca --------------------------------------------------------------- */ void ETree_MFstackProfile ( ETree *etree, int symflag, double dvec[] ) { int I, J, nDJ, nUI, nUJ, stack ; int *bndwghts, *fch, *nodwghts, *sib ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in ETree_MFstackProfile(%p,%p)" "\n bad input\n", etree, dvec) ; exit(-1) ; } tree = ETree_tree(etree) ; nodwghts = ETree_nodwghts(etree) ; bndwghts = ETree_bndwghts(etree) ; fch = ETree_fch(etree) ; sib = ETree_sib(etree) ; /* --------------------------------------------- loop over the nodes in a post-order traversal --------------------------------------------- */ stack = 0 ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { nDJ = nodwghts[J] ; nUJ = bndwghts[J] ; #if MYDEBUG > 0 fprintf(stdout, "\n working on front %d, nD = %d, nU = %d, stack = %d", J, nDJ, nUJ, stack) ; #endif if ( (I = fch[J]) != -1 ) { /* -------------------------------- remove last child from the stack -------------------------------- */ while ( sib[I] != -1 ) { I = sib[I] ; } nUI = bndwghts[I] ; if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ) { stack -= (nUI*(nUI+1))/2 ; } else if ( symflag == SPOOLES_NONSYMMETRIC ) { stack -= nUI*nUI ; } #if MYDEBUG > 0 fprintf(stdout, "\n removing last child %d, stack = %d", I, stack) ; #endif } /* --------------------------------- add frontal matrix for J to stack and store as the storage for J --------------------------------- */ dvec[J] = stack + (nDJ + nUJ)*(nDJ + nUJ) ; if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ) { dvec[J] = stack + ((nDJ + nUJ)*(nDJ + nUJ+1))/2 ; } else if ( symflag == SPOOLES_NONSYMMETRIC ) { dvec[J] = stack + (nDJ + nUJ)*(nDJ + nUJ) ; } #if MYDEBUG > 0 fprintf(stdout, "\n working storage = %.0f", dvec[J]) ; #endif if ( (I = fch[J]) != -1 ) { /* ------------------------------------ remove other children from the stack ------------------------------------ */ while ( sib[I] != -1 ) { nUI = bndwghts[I] ; if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ) { stack -= (nUI*(nUI+1))/2 ; } else if ( symflag == SPOOLES_NONSYMMETRIC ) { stack -= nUI*nUI ; } #if MYDEBUG > 0 fprintf(stdout, "\n removing child %d, stack = %d", I, stack) ; #endif I = sib[I] ; } } /* -------------------------------- add update matrix for J to stack -------------------------------- */ if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ) { stack += (nUJ*(nUJ+1))/2 ; } else if ( symflag == SPOOLES_NONSYMMETRIC ) { stack += nUJ*nUJ ; } #if MYDEBUG > 0 fprintf(stdout, "\n adding update matrix, stack = %d", stack) ; #endif } #if MYDEBUG >= 0 fprintf(stdout, "\n MF: final stack = %d", stack) ; #endif return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- fill dvec[J] with the active storage to eliminate J using the left-looking general sparse method symflag -- symmetry flag, one of SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 97may21, cca --------------------------------------------------------------- */ void ETree_GSstorageProfile ( ETree *etree, int symflag, IVL *symbfacIVL, int *vwghts, double dvec[] ) { int count, ii, I, J, K, nDJ, nfront, nUJ, sizeI, sizeJ, storage, v ; int *bndwghts, *head, *indI, *indJ, *link, *nodwghts, *offsets, *vtxToFront ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || symbfacIVL == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in ETree_GSstorageProfile(%p,%p,%p,%p)" "\n bad input\n", etree, symbfacIVL, vwghts, dvec) ; exit(-1) ; } tree = ETree_tree(etree) ; nodwghts = ETree_nodwghts(etree) ; bndwghts = ETree_bndwghts(etree) ; vtxToFront = ETree_vtxToFront(etree) ; nfront = ETree_nfront(etree) ; head = IVinit(nfront, -1) ; link = IVinit(nfront, -1) ; offsets = IVinit(nfront, 0) ; /* --------------------------------------------- loop over the nodes in a post-order traversal --------------------------------------------- */ storage = 0 ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { nDJ = nodwghts[J] ; nUJ = bndwghts[J] ; if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ) { storage += (nDJ*(nDJ + 1))/2 + nDJ*nUJ ; } else if ( symflag == SPOOLES_NONSYMMETRIC ) { storage += nDJ*nDJ + 2*nDJ*nUJ ; } dvec[J] = storage ; #if MYDEBUG > 0 fprintf(stdout, "\n working on front %d, nD = %d, nU = %d, storage = %d", J, nDJ, nUJ, storage) ; #endif /* ----------------------------- loop over the updating fronts ----------------------------- */ while ( (I = head[J]) != -1 ) { head[J] = link[I] ; IVL_listAndSize(symbfacIVL, I, &sizeI, &indI) ; #if MYDEBUG > 0 fprintf(stdout, "\n updating front %d, offset = %d, sizeI = %d", I, offsets[I], sizeI) ; IVfprintf(stdout, sizeI, indI) ; #endif for ( ii = offsets[I], count = 0, K = -1 ; ii < sizeI ; ii++ ) { v = indI[ii] ; #if MYDEBUG > 0 fprintf(stdout, "\n ii = %d, v = %d, K = %d", ii, v, vtxToFront[v]) ; fflush(stdout) ; #endif K = vtxToFront[v] ; if ( K < 0 || K >= nfront ) { fprintf(stderr, "\n\n fatal error" "\n ii = %d, v = %d, K = %d", ii, v, K) ; exit(-1) ; } if ( (K = vtxToFront[v]) != J ) { #if MYDEBUG > 0 fprintf(stdout, "\n linking to next ancestor %d", K) ; #endif link[I] = head[K] ; head[K] = I ; offsets[I] = ii ; break ; } count += (vwghts == NULL) ? 1 : vwghts[v] ; #if MYDEBUG > 0 fprintf(stdout, "\n count = %d", count) ; fflush(stdout) ; #endif } if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ) { storage -= count*nodwghts[I] ; } else if ( symflag == SPOOLES_NONSYMMETRIC ) { storage -= 2*count*nodwghts[I] ; } } if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ) { storage -= (nDJ*(nDJ+1))/2 ; } else if ( symflag == SPOOLES_NONSYMMETRIC ) { storage -= nDJ*nDJ ; } if ( nUJ > 0 ) { IVL_listAndSize(symbfacIVL, J, &sizeJ, &indJ) ; for ( ii = 0 ; ii < sizeJ ; ii++ ) { v = indJ[ii] ; if ( (K = vtxToFront[v]) != J ) { break ; } } offsets[J] = ii ; #if MYDEBUG > 0 fprintf(stdout, "\n linking to next ancestor %d", K) ; #endif IVL_listAndSize(symbfacIVL, J, &sizeJ, &indJ) ; link[J] = head[K] ; head[K] = J ; } #if MYDEBUG > 0 fprintf(stdout, "\n at end of step %d, storage = %d", J, storage) ; #endif } #if MYDEBUG >= 0 fprintf(stdout, "\n GS: final storage = %d", storage) ; #endif IVfree(head) ; IVfree(link) ; IVfree(offsets) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- fill dvec[J] with the active storage to eliminate J using the right-looking general sparse method symflag -- symmetry flag, one of SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC created -- 98dec19, cca --------------------------------------------------------------- */ void ETree_FSstorageProfile ( ETree *etree, int symflag, IVL *symbfacIVL, double dvec[] ) { char *incore ; int ii, J, K, nDJ, nfront, nUJ, sizeJ, storage ; int *bndwghts, *indJ, *mark, *nodwghts, *stor, *vtxToFront ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || symbfacIVL == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in ETree_FSstorageProfile(%p,%p,%p)" "\n bad input\n", etree, symbfacIVL, dvec) ; exit(-1) ; } tree = ETree_tree(etree) ; nodwghts = ETree_nodwghts(etree) ; bndwghts = ETree_bndwghts(etree) ; vtxToFront = ETree_vtxToFront(etree) ; nfront = ETree_nfront(etree) ; incore = CVinit(nfront, 'F') ; stor = IVinit(nfront, 0) ; mark = IVinit(nfront, -1) ; /* -------------------------------------------- compute the storage for each front's chevron -------------------------------------------- */ if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ) { for ( J = 0 ; J < nfront ; J++ ) { nDJ = nodwghts[J] ; nUJ = bndwghts[J] ; stor[J] = (nDJ*(nDJ+1))/2 + nDJ*nUJ ; } } else { for ( J = 0 ; J < nfront ; J++ ) { nDJ = nodwghts[J] ; nUJ = bndwghts[J] ; stor[J] = nDJ*nDJ + 2*nDJ*nUJ ; } } /* --------------------------------------------- loop over the nodes in a post-order traversal --------------------------------------------- */ storage = 0 ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { if ( incore[J] == 'F' ) { storage += stor[J] ; incore[J] = 'T' ; } IVL_listAndSize(symbfacIVL, J, &sizeJ, &indJ) ; mark[J] = J ; for ( ii = 0 ; ii < sizeJ ; ii++ ) { K = vtxToFront[indJ[ii]] ; if ( mark[K] != J ) { mark[K] = J ; if ( incore[K] == 'F' ) { storage += stor[K] ; incore[K] = 'T' ; } } } dvec[J] = storage ; storage -= stor[J] ; } IVfree(mark) ; IVfree(stor) ; CVfree(incore) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- fill dvec[J] with the stack storage to solve for J in a forward solve created -- 97nov30, cca --------------------------------------------------------------- */ void ETree_forwSolveProfile ( ETree *etree, double dvec[] ) { int I, J, maxstack, nDJ, nfront, nUJ, stack ; int *bndwghts, *fch, *nodwghts, *sib ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in ETree_forwSolveProfile(%p,%p)" "\n bad input\n", etree, dvec) ; exit(-1) ; } tree = ETree_tree(etree) ; nodwghts = ETree_nodwghts(etree) ; bndwghts = ETree_bndwghts(etree) ; nfront = ETree_nfront(etree) ; fch = ETree_fch(etree) ; sib = ETree_sib(etree) ; /* --------------------------------------------- loop over the nodes in a post-order traversal --------------------------------------------- */ maxstack = stack = 0 ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { nDJ = nodwghts[J] ; nUJ = bndwghts[J] ; stack += nDJ + nUJ ; dvec[J] = stack ; if ( maxstack < stack ) { maxstack = stack ; } #if MYDEBUG > 0 fprintf(stdout, "\n working on front %d, nD = %d, nU = %d, stack = %d", J, nDJ, nUJ, stack) ; #endif for ( I = fch[J] ; I != -1 ; I = sib[I] ) { stack -= bndwghts[I] ; } stack -= nDJ ; } #if MYDEBUG >= 0 fprintf(stdout, "\n forward solve : final stack = %d, max stack = %d", stack, maxstack) ; #endif return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- fill dvec[J] with the stack storage to solve for J in a backward solve created -- 97nov30, cca --------------------------------------------------------------- */ void ETree_backSolveProfile ( ETree *etree, double dvec[] ) { int J, K, maxstack, nDJ, nfront, nUJ, stack ; int *bndwghts, *fch, *nodwghts, *par, *sib ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in ETree_backSolveProfile(%p,%p)" "\n bad input\n", etree, dvec) ; exit(-1) ; } tree = ETree_tree(etree) ; nodwghts = ETree_nodwghts(etree) ; bndwghts = ETree_bndwghts(etree) ; nfront = ETree_nfront(etree) ; par = ETree_par(etree) ; fch = ETree_fch(etree) ; sib = ETree_sib(etree) ; /* --------------------------------------------- loop over the nodes in a post-order traversal --------------------------------------------- */ maxstack = stack = 0 ; for ( J = Tree_preOTfirst(tree) ; J != -1 ; J = Tree_preOTnext(tree, J) ) { nDJ = nodwghts[J] ; nUJ = bndwghts[J] ; stack += nDJ + nUJ ; dvec[J] = stack ; if ( maxstack < stack ) { maxstack = stack ; } #if MYDEBUG > 0 fprintf(stdout, "\n working on front %d, nD = %d, nU = %d, stack = %d", J, nDJ, nUJ, stack) ; #endif if ( (K = par[J]) != -1 && sib[J] == -1 ) { stack -= nodwghts[K] + bndwghts[K] ; } if ( fch[J] == -1 ) { stack -= nodwghts[J] + bndwghts[J] ; } } #if MYDEBUG >= 0 fprintf(stdout, "\n forward solve : final stack = %d, max stack = %d", stack, maxstack) ; #endif return ; } /*--------------------------------------------------------------------*/ symflag, IVL *symbfacIVL, int *vwghts, double dvec[] ) { int count, ii, I, J, K, nDJ, nfront, nUJ, sizeI, sizeJ, storage, v ; int *bndwghts, *head, *indI, *indJ, *link, *nodwghts, *offsets, *vtxToFront ; Tree *tree ; /* --------------- check the input --------------- */ iETree/src/transform.c010064400020550007177000000642620663302124400160550ustar00clevecompmath00000400000006/* transform.c */ #include "../ETree.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ transform an ETree object by (1) merging small fronts into larger fronts using the ETree_mergeFrontsOne() method (2) merging small fronts into larger fronts using the ETree_mergeFrontsAll() method (3) merging small fronts into larger fronts using the ETree_mergeFrontsAny() method (4) split a large front into a chain of smaller fronts using the ETree_splitFronts() method created -- 96jun27, cca ------------------------------------------------------ */ ETree * ETree_transform ( ETree *etree, int vwghts[], int maxzeros, int maxfrontsize, int seed ) { ETree *etree2 ; int nfront, nvtx ; IV *nzerosIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 || maxfrontsize <= 0 ) { fprintf(stderr, "\n fatal error in ETree_transform(%p,%p,%d,%d,%d)" "\n bad input\n", etree, vwghts, maxzeros, maxfrontsize, seed) ; exit(-1) ; } nzerosIV = IV_new(); IV_init(nzerosIV, nfront, NULL) ; IV_fill(nzerosIV, 0) ; /* -------------------------- first, merge only children -------------------------- */ etree2 = ETree_mergeFrontsOne(etree, maxzeros, nzerosIV) ; ETree_free(etree) ; etree = etree2 ; /* -------------------------- second, merge all children -------------------------- */ etree2 = ETree_mergeFrontsAll(etree, maxzeros, nzerosIV) ; ETree_free(etree) ; etree = etree2 ; /* ------------------------- third, merge any children ------------------------- */ etree2 = ETree_mergeFrontsAny(etree, maxzeros, nzerosIV) ; ETree_free(etree) ; etree = etree2 ; /* ----------------------------------- fourth, split large interior fronts ----------------------------------- */ etree2 = ETree_splitFronts(etree, vwghts, maxfrontsize, seed) ; ETree_free(etree) ; etree = etree2 ; /* ------------------------ free the working storage ------------------------ */ IV_free(nzerosIV) ; return(etree) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ transform an ETree object by (1) merging small fronts into larger fronts using the ETree_mergeFrontsOne() method (2) merging small fronts into larger fronts using the ETree_mergeFrontsAll() method (3) split a large front into a chain of smaller fronts using the ETree_splitFronts() method created -- 96jun27, cca ------------------------------------------------------ */ ETree * ETree_transform2 ( ETree *etree, int vwghts[], int maxzeros, int maxfrontsize, int seed ) { ETree *etree2 ; int nfront, nvtx ; IV *nzerosIV ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 || maxfrontsize <= 0 ) { fprintf(stderr, "\n fatal error in ETree_transform2(%p,%p,%d,%d,%d)" "\n bad input\n", etree, vwghts, maxzeros, maxfrontsize, seed) ; exit(-1) ; } nzerosIV = IV_new(); IV_init(nzerosIV, nfront, NULL) ; IV_fill(nzerosIV, 0) ; /* -------------------------- first, merge only children -------------------------- */ etree2 = ETree_mergeFrontsOne(etree, maxzeros, nzerosIV) ; ETree_free(etree) ; etree = etree2 ; /* -------------------------- second, merge all children -------------------------- */ etree2 = ETree_mergeFrontsAll(etree, maxzeros, nzerosIV) ; ETree_free(etree) ; etree = etree2 ; /* ----------------------------------- fourth, split large interior fronts ----------------------------------- */ etree2 = ETree_splitFronts(etree, vwghts, maxfrontsize, seed) ; ETree_free(etree) ; etree = etree2 ; /* ------------------------ free the working storage ------------------------ */ IV_free(nzerosIV) ; return(etree) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- merge the front tree allowing only chains of nodes to merge that create at most maxzeros zero entries inside a front return -- IV object that has the old front to new front map created -- 98jan29, cca -------------------------------------------------------------------- */ ETree * ETree_mergeFrontsOne ( ETree *etree, int maxzeros, IV *nzerosIV ) { ETree *etree2 ; int costJ, J, K, nfront, nvtx, nnew ; int *bndwghts, *fch, *map, *nodwghts, *nzeros, *rep, *sib, *temp ; IV *mapIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || nzerosIV == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_mergeFrontsOne(%p,%d,%p)" "\n bad input\n", etree, maxzeros, nzerosIV) ; exit(-1) ; } if ( IV_size(nzerosIV) != nfront ) { fprintf(stderr, "\n fatal error in ETree_mergeFrontsOne(%p,%d,%p)" "\n size(nzerosIV) = %d, nfront = %d\n", etree, maxzeros, nzerosIV, IV_size(nzerosIV), nfront) ; exit(-1) ; } nzeros = IV_entries(nzerosIV) ; tree = etree->tree ; fch = ETree_fch(etree) ; sib = ETree_sib(etree) ; /* ---------------------- set up working storage ---------------------- */ nodwghts = IVinit(nfront, 0) ; IVcopy(nfront, nodwghts, ETree_nodwghts(etree)) ; bndwghts = ETree_bndwghts(etree) ; rep = IVinit(nfront, -1) ; IVramp(nfront, rep, 0, 1) ; /* ------------------------------------------ perform a post-order traversal of the tree ------------------------------------------ */ for ( K = Tree_postOTfirst(tree) ; K != -1 ; K = Tree_postOTnext(tree, K) ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n ##### visiting front %d", K) ; fflush(stdout) ; #endif if ( (J = fch[K]) != -1 && sib[J] == -1 ) { costJ = nodwghts[J]*(nodwghts[K] + bndwghts[K] - bndwghts[J]) ; #if MYDEBUG > 0 fprintf(stdout, "\n nzeros[%d] = %d, costJ = %d", J, nzeros[J], costJ) ; fflush(stdout) ; #endif if ( nzeros[J] + costJ <= maxzeros ) { rep[J] = K ; nodwghts[K] += nodwghts[J] ; nzeros[K] = nzeros[J] + costJ ; #if MYDEBUG > 0 fprintf(stdout, "\n merging %d into %d, |%d| = %d, nzeros = %d", J, K, K, nodwghts[K], nzeros[K]) ; fflush(stdout) ; #endif } } } #if MYDEBUG > 0 fprintf(stdout, "\n\n whoa, finished") ; fflush(stdout) ; #endif /* ------------------------------------------------- take the map from fronts to representative fronts and make the map from old fronts to new fronts ------------------------------------------------- */ mapIV = IV_new() ; IV_init(mapIV, nfront, NULL) ; map = IV_entries(mapIV) ; for ( J = 0, nnew = 0 ; J < nfront ; J++ ) { if ( rep[J] == J ) { map[J] = nnew++ ; } else { K = J ; while ( rep[K] != K ) { K = rep[K] ; } rep[J] = K ; } } for ( J = 0 ; J < nfront ; J++ ) { if ( (K = rep[J]) != J ) { map[J] = map[K] ; } } /* ------------------------------- get the compressed ETree object ------------------------------- */ etree2 = ETree_compress(etree, mapIV) ; /* ------------------------- remap the nzeros[] vector ------------------------- */ temp = IVinit(nfront, NULL) ; IVcopy(nfront, temp, nzeros) ; IV_setSize(nzerosIV, nnew) ; nzeros = IV_entries(nzerosIV) ; for ( J = 0 ; J < nfront ; J++ ) { if ( rep[J] == J ) { nzeros[map[J]] = temp[J] ; } } IVfree(temp) ; /* ------------------------ free the working storage ------------------------ */ IVfree(nodwghts) ; IVfree(rep) ; IV_free(mapIV) ; return(etree2) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- merge the front tree allowing a parent to absorb all children when that creates at most maxzeros zero entries inside a front return -- IV object that has the old front to new front map created -- 98jan29, cca ------------------------------------------------------- */ ETree * ETree_mergeFrontsAll ( ETree *etree, int maxzeros, IV *nzerosIV ) { ETree *etree2 ; int cost, J, Jall, K, KandBnd, nfront, nvtx, nnew ; int *bndwghts, *fch, *map, *nodwghts, *nzeros, *rep, *sib, *temp ; IV *mapIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || nzerosIV == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_mergeFrontsAll(%p,%d,%p)" "\n bad input\n", etree, maxzeros, nzerosIV) ; if ( etree != NULL ) { fprintf(stderr, "\n nfront = %d, nvtx = %d", etree->nfront, etree->nvtx) ; } exit(-1) ; } if ( IV_size(nzerosIV) != nfront ) { fprintf(stderr, "\n fatal error in ETree_mergeFrontsAll(%p,%d,%p)" "\n size(nzerosIV) = %d, nfront = %d\n", etree, maxzeros, nzerosIV, IV_size(nzerosIV), nfront) ; exit(-1) ; } nzeros = IV_entries(nzerosIV) ; /* ---------------------- set up working storage ---------------------- */ tree = etree->tree ; fch = ETree_fch(etree) ; sib = ETree_sib(etree) ; nodwghts = IVinit(nfront, 0) ; IVcopy(nfront, nodwghts, ETree_nodwghts(etree)) ; bndwghts = ETree_bndwghts(etree) ; rep = IVinit(nfront, -1) ; IVramp(nfront, rep, 0, 1) ; /* ------------------------------------------ perform a post-order traversal of the tree ------------------------------------------ */ for ( K = Tree_postOTfirst(tree) ; K != -1 ; K = Tree_postOTnext(tree, K) ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n ##### visiting front %d", K) ; fflush(stdout) ; #endif if ( (J = fch[K]) != -1 ) { KandBnd = nodwghts[K] + bndwghts[K] ; Jall = 0 ; cost = 2*nzeros[K] ; for ( J = fch[K] ; J != -1 ; J = sib[J] ) { Jall += nodwghts[J] ; cost -= nodwghts[J]*nodwghts[J] ; cost += 2*nodwghts[J]*(KandBnd - bndwghts[J]) ; cost += 2*nzeros[J] ; } cost += Jall*Jall ; cost = cost/2 ; #if MYDEBUG > 0 fprintf(stdout, "\n cost = %d", cost) ; fflush(stdout) ; #endif if ( cost <= maxzeros ) { for ( J = fch[K] ; J != -1 ; J = sib[J] ) { #if MYDEBUG > 0 fprintf(stdout, "\n merging %d into %d", J, K) ; fflush(stdout) ; #endif rep[J] = K ; nodwghts[K] += nodwghts[J] ; } nzeros[K] = cost ; } } } #if MYDEBUG > 0 fprintf(stdout, "\n\n whoa, finished") ; fflush(stdout) ; #endif /* ------------------------------------------------- take the map from fronts to representative fronts and make the map from old fronts to new fronts ------------------------------------------------- */ mapIV = IV_new() ; IV_init(mapIV, nfront, NULL) ; map = IV_entries(mapIV) ; for ( J = 0, nnew = 0 ; J < nfront ; J++ ) { if ( rep[J] == J ) { map[J] = nnew++ ; } else { K = J ; while ( rep[K] != K ) { K = rep[K] ; } rep[J] = K ; } } for ( J = 0 ; J < nfront ; J++ ) { if ( (K = rep[J]) != J ) { map[J] = map[K] ; } } /* ------------------------------- get the compressed ETree object ------------------------------- */ etree2 = ETree_compress(etree, mapIV) ; /* ------------------------- remap the nzeros[] vector ------------------------- */ temp = IVinit(nfront, NULL) ; IVcopy(nfront, temp, nzeros) ; IV_setSize(nzerosIV, nnew) ; nzeros = IV_entries(nzerosIV) ; for ( J = 0 ; J < nfront ; J++ ) { if ( rep[J] == J ) { nzeros[map[J]] = temp[J] ; } } IVfree(temp) ; /* ------------------------ free the working storage ------------------------ */ IVfree(nodwghts) ; IVfree(rep) ; IV_free(mapIV) ; return(etree2) ; } /*--------------------------------------------------------------------*/ /* --------------------------- static prototype definition --------------------------- */ static void visitAny ( int K, int par[], int fch[], int sib[], int nodwghts[], int bndwghts[], int map[], int cost[], int nzeros[], int maxzeros) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- merge the front tree allowing at most maxzeros zero entries inside a front return -- IV object that has the old front to new front map created -- 96jun23, cca modified -- 97dec18, cca bug fixed that incorrectly counted the number of zeros in a front -------------------------------------------------------------------- */ ETree * ETree_mergeFrontsAny ( ETree *etree, int maxzeros, IV *nzerosIV ) { ETree *etree2 ; int J, K, nfront, nvtx, nnew ; int *bndwghts, *cost, *fch, *map, *nodwghts, *nzeros, *par, *place, *rep, *sib, *temp ; IV *mapIV ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_mergeFrontsAny(%p,%d)" "\n bad input\n", etree, maxzeros) ; exit(-1) ; } if ( IV_size(nzerosIV) != nfront ) { fprintf(stderr, "\n fatal error in ETree_mergeFrontsAny(%p,%d,%p)" "\n size(nzerosIV) = %d, nfront = %d\n", etree, maxzeros, nzerosIV, IV_size(nzerosIV), nfront) ; exit(-1) ; } nzeros = IV_entries(nzerosIV) ; tree = etree->tree ; nodwghts = IVinit(nfront, 0) ; bndwghts = IVinit(nfront, 0) ; par = IVinit(nfront, -1) ; fch = IVinit(nfront, -1) ; sib = IVinit(nfront, -1) ; IVcopy(nfront, par, tree->par) ; IVcopy(nfront, fch, tree->fch) ; IVcopy(nfront, sib, tree->sib) ; IVcopy(nfront, nodwghts, IV_entries(etree->nodwghtsIV)) ; IVcopy(nfront, bndwghts, IV_entries(etree->bndwghtsIV)) ; /* ---------------------- set up working storage ---------------------- */ rep = IVinit(nfront, -1) ; IVramp(nfront, rep, 0, 1) ; cost = IVinit(nfront, 0) ; /* ------------------------------------------ perform a post-order traversal of the tree ------------------------------------------ */ for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n ##### visiting front %d", J) ; fflush(stdout) ; #endif visitAny(J, par, fch, sib, nodwghts, bndwghts, rep, cost, nzeros, maxzeros) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n whoa, finished") ; fflush(stdout) ; #endif /* ------------------------------------------------- take the map from fronts to representative fronts and make the map from old fronts to new fronts ------------------------------------------------- */ mapIV = IV_new() ; IV_init(mapIV, nfront, NULL) ; map = IV_entries(mapIV) ; place = IVinit(nfront, -1) ; for ( J = 0, nnew = 0 ; J < nfront ; J++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n rep[%d] = %d", J, rep[J]) ; fflush(stdout) ; #endif if ( rep[J] != J ) { K = J ; while ( rep[K] != K ) { #if MYDEBUG > 0 fprintf(stdout, "\n rep[%d] = %d", K, rep[K]) ; fflush(stdout) ; #endif K = rep[K] ; } rep[J] = K ; #if MYDEBUG > 0 fprintf(stdout, "\n setting rep[%d] = %d", J, rep[J]) ; fflush(stdout) ; #endif } else { place[J] = nnew++ ; } } for ( J = 0 ; J < nfront ; J++ ) { K = rep[J] ; map[J] = place[K] ; } /* ------------------------------- get the compressed ETree object ------------------------------- */ etree2 = ETree_compress(etree, mapIV) ; /* ------------------------- remap the nzeros[] vector ------------------------- */ temp = IVinit(nfront, NULL) ; IVcopy(nfront, temp, nzeros) ; IV_setSize(nzerosIV, nnew) ; nzeros = IV_entries(nzerosIV) ; for ( J = 0 ; J < nfront ; J++ ) { if ( rep[J] == J ) { nzeros[map[J]] = temp[J] ; } } IVfree(temp) ; /* ------------------------ free the working storage ------------------------ */ IVfree(par) ; IVfree(fch) ; IVfree(sib) ; IVfree(nodwghts) ; IVfree(bndwghts) ; IVfree(rep) ; IVfree(cost) ; IVfree(place) ; IV_free(mapIV) ; return(etree2) ; } /*--------------------------------------------------------------------*/ static void visitAny ( int K, int par[], int fch[], int sib[], int nodwghts[], int bndwghts[], int rep[], int cost[], int nzeros[], int maxzeros ) { int bestJ, firstI, J, lastI, nextJ, prevJ ; if ( fch[K] == -1 ) { return ; } #if MYDEBUG > 0 fprintf(stdout, "\n inside visitAny(%d), nzeros(%d) = %d", K, K, nzeros[K]) ; #endif /* ---------------------------------- find the child with the least cost ---------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n nodwght %d, bndwght %d", nodwghts[K], bndwghts[K]) ; #endif bestJ = -1 ; for ( J = fch[K] ; J != -1 ; J = sib[J] ) { cost[J] = nzeros[J] + nodwghts[J] * (nodwghts[K] + bndwghts[K] - bndwghts[J]) ; #if MYDEBUG > 0 fprintf(stdout, "\n child %d, nodwght %d, bndwght %d, cost %d", J, nodwghts[J], bndwghts[J], cost[J]) ; #endif if ( bestJ == -1 || cost[J] < cost[bestJ] || (cost[J] == cost[bestJ] && nodwghts[J] < nodwghts[bestJ]) ) { bestJ = J ; } } if ( (cost[bestJ] + nzeros[K] > maxzeros) || (sib[fch[K]] != -1 && par[K] == -1) ) { #if MYDEBUG > 0 fprintf(stdout, "\n no merge: cost[%d] + nzeros[%d] = %d + %d > %d", bestJ, K, cost[bestJ], nzeros[K], maxzeros) ; #endif /* -------------------------------- no child can be absorbed, return -------------------------------- */ return ; } #if MYDEBUG > 0 fprintf(stdout, "\n merging child %d into %d", bestJ, K) ; #endif /* ------------------------- absorb child bestJ into K ------------------------- */ for ( J = fch[K], prevJ = -1 ; J != bestJ ; J = sib[J] ) { prevJ = J ; } nextJ = sib[bestJ] ; #if MYDEBUG > 0 fprintf(stdout, "\n previous sibling = %d, next sibling = %d", prevJ, nextJ) ; #endif if ( (firstI = fch[bestJ]) == -1 ) { if ( prevJ == -1 ) { fch[K] = nextJ ; #if MYDEBUG > 0 fprintf(stdout, "\n setting fch[%d] = %d", K, fch[K]) ; #endif } else { sib[prevJ] = nextJ ; #if MYDEBUG > 0 fprintf(stdout, "\n setting sib[%d] = %d", prevJ, sib[prevJ]) ; #endif } } else { firstI = fch[bestJ] ; par[firstI] = K ; #if MYDEBUG > 0 fprintf(stdout, "\n setting par[%d] = %d", firstI, par[firstI]) ; #endif if ( (lastI = sib[firstI]) != -1 ) { while ( sib[lastI] != -1 ) { par[lastI] = K ; #if MYDEBUG > 0 fprintf(stdout, "\n setting par[%d] = %d", lastI, par[lastI]) ; #endif lastI = sib[lastI] ; } par[lastI] = K ; #if MYDEBUG > 0 fprintf(stdout, "\n setting par[%d] = %d", lastI, par[lastI]) ; #endif } if ( prevJ == -1 ) { fch[K] = firstI ; #if MYDEBUG > 0 fprintf(stdout, "\n setting fch[%d] = %d", K, fch[K]) ; #endif } else { sib[prevJ] = firstI ; #if MYDEBUG > 0 fprintf(stdout, "\n setting sib[%d] = %d", prevJ, sib[prevJ]) ; #endif } if ( lastI != -1 ) { sib[lastI] = nextJ ; #if MYDEBUG > 0 fprintf(stdout, "\n setting sib[%d] = %d", lastI, sib[lastI]) ; #endif } } rep[bestJ] = K ; nodwghts[K] += nodwghts[bestJ] ; nzeros[K] += cost[bestJ] ; #if MYDEBUG > 0 fprintf(stdout, "\n setting rep[%d] = %d", bestJ, rep[bestJ]) ; fprintf(stdout, "\n setting nodwghts[%d] = %d", K, nodwghts[K]) ; fprintf(stdout, "\n setting nzeros[%d] = %d", K, nzeros[K]) ; #endif /* ------------- visit K again ------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n\n ### visiting front %d", K) ; fflush(stdout) ; #endif visitAny(K, par, fch, sib, nodwghts, bndwghts, rep, cost, nzeros, maxzeros) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- expand an ETree object by splitting a large front into a chain of smaller fronts. created -- 96jun27, cca ------------------------------------------------- */ ETree * ETree_splitFronts ( ETree *etree, int vwghts[], int maxfrontsize, int seed ) { ETree *etree2 ; int count, front, ii, I, Inew, J, Jnew, nbnd, newsize, nint, nfront, nfront2, nsplit, nvtx, prev, size, sizeJ, v, vwght ; int *bndwghts, *fch, *head, *indices, *link, *newbndwghts, *newmap, *newnodwghts, *newpar, *nodwghts, *roots, *sib, *vtxToFront ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 || maxfrontsize <= 0 ) { fprintf(stderr, "\n fatal error in ETree_splitFronts(%p,%p,%d,%d)" "\n bad input\n", etree, vwghts, maxfrontsize, seed) ; exit(-1) ; } tree = etree->tree ; fch = tree->fch ; sib = tree->sib ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; vtxToFront = IV_entries(etree->vtxToFrontIV) ; /* -------------------------- set up the working storage -------------------------- */ newpar = IVinit(nvtx, -1) ; roots = IVinit(nfront, -1) ; newmap = IVinit(nvtx, -1) ; newnodwghts = IVinit(nvtx, -1) ; newbndwghts = IVinit(nvtx, -1) ; head = IVinit(nfront, -1) ; link = IVinit(nvtx, -1) ; indices = IVinit(nvtx, -1) ; for ( v = 0 ; v < nvtx ; v++ ) { front = vtxToFront[v] ; link[v] = head[front] ; head[front] = v ; } /* ------------------------------------------------ execute a post-order traversal of the front tree ------------------------------------------------ */ nfront2 = 0 ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { sizeJ = 0 ; for ( v = head[J], count = 0 ; v != -1 ; v = link[v] ) { indices[count++] = v ; vwght = (vwghts != NULL) ? vwghts[v] : 1 ; sizeJ += vwght ; } if ( sizeJ != nodwghts[J] ) { fprintf(stderr, "\n fatal error in ETree_splitFronts(%p,%p,%d,%d)" "\n J = %d, sizeJ = %d, nodwght = %d\n", etree, vwghts, maxfrontsize, seed, J, sizeJ, nodwghts[J]) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n checking out front %d, size %d", J, sizeJ) ; #endif if ( sizeJ <= maxfrontsize || fch[J] == -1 ) { /* ------------------------------------------- this front is small enough (or is a domain) ------------------------------------------- */ Jnew = nfront2++ ; for ( ii = 0 ; ii < count ; ii++ ) { v = indices[ii] ; newmap[v] = Jnew ; #if MYDEBUG > 1 fprintf(stdout, "\n mapping vertex %d into new front %d", v, Jnew) ; #endif } for ( I = fch[J] ; I != -1 ; I = sib[I] ) { Inew = roots[I] ; newpar[Inew] = Jnew ; } newnodwghts[Jnew] = nodwghts[J] ; newbndwghts[Jnew] = bndwghts[J] ; roots[J] = Jnew ; #if MYDEBUG > 0 fprintf(stdout, "\n front is small enough, Jnew = %d", Jnew) ; #endif } else { /* ------------------------------------------ this front is too large, split into pieces whose size differs by one vertex ------------------------------------------ */ nsplit = (sizeJ + maxfrontsize - 1)/maxfrontsize ; newsize = sizeJ / nsplit ; if ( sizeJ % nsplit != 0 ) { newsize++ ; } #if MYDEBUG > 0 fprintf(stdout, "\n front is too large, %d target fronts, target size = %d", nsplit, newsize) ; #endif prev = -1 ; nint = nodwghts[J] ; nbnd = nint + bndwghts[J] ; if ( seed > 0 ) { IVshuffle(count, indices, seed) ; } ii = 0 ; while ( ii < count ) { Jnew = nfront2++ ; size = 0 ; while ( ii < count ) { v = indices[ii] ; vwght = (vwghts != NULL) ? vwghts[v] : 1 ; #if MYDEBUG > 0 fprintf(stdout, "\n ii = %d, v = %d, vwght = %d, size = %d", ii, v, vwght, size) ; #endif /* ----------------------------------------------- 97aug28, cca bug fix. front is created even if it is too big ----------------------------------------------- */ if ( newsize >= size + vwght || size == 0 ) { newmap[v] = Jnew ; size += vwght ; #if MYDEBUG > 0 fprintf(stdout, "\n mapping vertex %d into new front %d, size = %d", v, Jnew, size) ; #endif ii++ ; } else { break ; } } if ( prev == -1 ) { for ( I = fch[J] ; I != -1 ; I = sib[I] ) { Inew = roots[I] ; newpar[Inew] = Jnew ; } } else { newpar[prev] = Jnew ; } prev = Jnew ; newnodwghts[Jnew] = size ; nbnd = nbnd - size ; newbndwghts[Jnew] = nbnd ; #if MYDEBUG > 0 fprintf(stdout, "\n new front %d, size %d, bnd %d", Jnew, newnodwghts[Jnew], newbndwghts[Jnew]) ; #endif } roots[J] = Jnew ; } } /* --------------------------- create the new ETree object --------------------------- */ etree2 = ETree_new() ; ETree_init1(etree2, nfront2, nvtx) ; IVcopy(nfront2, etree2->tree->par, newpar) ; Tree_setFchSibRoot(etree2->tree) ; IVcopy(nvtx, IV_entries(etree2->vtxToFrontIV), newmap) ; IVcopy(nfront2, IV_entries(etree2->nodwghtsIV), newnodwghts) ; IVcopy(nfront2, IV_entries(etree2->bndwghtsIV), newbndwghts) ; /* ------------------------ free the working storage ------------------------ */ IVfree(newpar) ; IVfree(roots) ; IVfree(newmap) ; IVfree(newnodwghts) ; IVfree(newbndwghts) ; IVfree(head) ; IVfree(link) ; IVfree(indices) ; return(etree2) ; } /*--------------------------------------------------------------------*/ --------------------- free the working storage ------------------------ */ IVfree(par) ; IVfree(fch) ; IVfree(sib) ; IVfree(nodwghts) ; IVfree(bndwghts) ; IVfree(rep) ; IVfree(cost) ; IVfree(place) ; IV_free(mapIV) ; return(etree2) ; } /*--------------------------------------------------------ETree/src/util.c010064400020550007177000000464300653606201300150150ustar00clevecompmath00000400000006/* util.c */ #include "../ETree.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95nov15, cca ---------------------------------------------- */ int ETree_sizeOf ( ETree *etree ) { int nbytes ; /* --------------- check the input --------------- */ if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_sizeOf(%p)" "\n bad input\n", etree) ; exit(-1) ; } nbytes = sizeof(struct _ETree) ; if ( etree->tree != NULL ) { nbytes += Tree_sizeOf(etree->tree) ; } if ( etree->nodwghtsIV != NULL ) { nbytes += IV_sizeOf(etree->nodwghtsIV) ; } if ( etree->nodwghtsIV != NULL ) { nbytes += IV_sizeOf(etree->bndwghtsIV) ; } if ( etree->vtxToFrontIV != NULL ) { nbytes += IV_sizeOf(etree->vtxToFrontIV) ; } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- return the number of factor indices created -- 95nov15, cca modified -- 96jan11, cca ---------------------------------------- */ int ETree_nFactorIndices ( ETree *etree ) { int nb, nfront, nv, nind, nvtx, v ; int *bndwghts, *nodwghts ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_nFactorIndices(%p)" "\n bad input\n", etree) ; exit(-1) ; } nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; nind = 0 ; for ( v = 0 ; v < nfront ; v++ ) { nv = nodwghts[v] ; nb = bndwghts[v] ; nind += nv + nb ; } return(nind) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ return the number of factor entries symflag -- symmetry flag 0 (SPOOLES_SYMMETRIC) -- symmetric 1 (SPOOLES_HERMITIAN) -- hermitian 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric created -- 98jun05, cca ------------------------------------------ */ int ETree_nFactorEntries ( ETree *etree, int symflag ) { int J, nfront, nvtx, nzf ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_nFactorEntries(%p,%d)" "\n bad input\n", etree, symflag) ; exit(-1) ; } nzf = 0 ; for ( J = 0 ; J < nfront ; J++ ) { nzf += ETree_nFactorEntriesInFront(etree, symflag, J) ; } return(nzf) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ return the number of factor operations type -- type of matrix entries 1 (SPOOLES_REAL) -- real entries 2 (SPOOLES_COMPLEX) -- complex entries symflag -- symmetry flag 0 (SPOOLES_SYMMETRIC) -- symmetric 1 (SPOOLES_HERMITIAN) -- hermitian 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric created -- 98jun05, cca ------------------------------------------ */ double ETree_nFactorOps ( ETree *etree, int type, int symflag ) { double ops ; int J, nfront, nvtx ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in ETree_nFactorOps(%p,%d,%d)" "\n bad input\n", etree, type, symflag) ; exit(-1) ; } ops = 0 ; for ( J = 0 ; J < nfront ; J++ ) { ops += ETree_nInternalOpsInFront(etree, type, symflag, J) + ETree_nExternalOpsInFront(etree, type, symflag, J) ; } return(ops) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- return the number of entries an LU front created -- 96dec04, cca ---------------------------------------- */ double ETree_nFactorEntriesInFront ( ETree *etree, int symflag, int J ) { int b, m, nent ; /* --------------- check the input --------------- */ if ( etree == NULL || etree->nfront <= 0 || J < 0 || J >= etree->nfront ) { fprintf(stderr, "\n fatal error in ETree_nFactorEntriesInFront(%p,%d,%d)" "\n bad input\n", etree, symflag, J) ; exit(-1) ; } b = IV_entry(etree->nodwghtsIV, J) ; m = IV_entry(etree->bndwghtsIV, J) ; switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : nent = (b*(b+1))/2 + b*m ; break ; case SPOOLES_NONSYMMETRIC : nent = b*b + 2*b*m ; break ; default : fprintf(stderr, "\n fatal error in ETree_nFactorEntriesInFront(%p,%d,%d)" "\n bad symflag\n", etree, symflag, J) ; break ; } return(nent) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- return the number of internal LU operations for a front created -- 96dec04, cca ------------------------------------------------------- */ double ETree_nInternalOpsInFront ( ETree *etree, int type, int symflag, int J ) { double b, m, ops ; /* --------------- check the input --------------- */ if ( etree == NULL || etree->nfront <= 0 || J < 0 || J >= etree->nfront ) { fprintf(stderr, "\n fatal error in ETree_nInternalOpsInFront(%p,%d,%d,%d)" "\n bad input\n", etree, type, symflag, J) ; exit(-1) ; } b = ETree_frontSize(etree, J) ; m = ETree_frontBoundarySize(etree, J) ; switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : ops = (b*(b+1)*(2*b+1))/6. + m*b*b ; break ; case SPOOLES_NONSYMMETRIC : ops = b*(2*b*b+1)/3. + 2*m*b*b ; break ; default : fprintf(stderr, "\n fatal error in ETree_nInternalOpsInFront(%p,%d,%d,%d)" "\n bad symflag\n", etree, type, symflag, J) ; break ; } switch ( type ) { case SPOOLES_REAL : break ; case SPOOLES_COMPLEX : ops = 4*ops ; break ; default : fprintf(stderr, "\n fatal error in ETree_nInternalOpsInFront(%p,%d,%d,%d)" "\n bad type\n", etree, type, symflag, J) ; break ; } return(ops) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- return the number of external LU operations for a front created -- 96dec04, cca ------------------------------------------------------- */ double ETree_nExternalOpsInFront ( ETree *etree, int type, int symflag, int J ) { double b, m, ops ; /* --------------- check the input --------------- */ if ( etree == NULL || etree->nfront <= 0 || J < 0 || J >= etree->nfront ) { fprintf(stderr, "\n fatal error in ETree_nExternalOpsInFront(%p,%d,%d,%d)" "\n bad input\n", etree, J, type, symflag) ; exit(-1) ; } b = IV_entry(etree->nodwghtsIV, J) ; m = IV_entry(etree->bndwghtsIV, J) ; switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : ops = m*(m+1)*b ; break ; case SPOOLES_NONSYMMETRIC : ops = 2*b*m*m ; break ; default : break ; } switch ( type ) { case SPOOLES_REAL : break ; case SPOOLES_COMPLEX : ops = 4*ops ; break ; default : fprintf(stderr, "\n fatal error in ETree_nExternalOpsInFront(%p,%d,%d,%d)" "\n bad input\n", etree, J, type, symflag) ; break ; } return(ops) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- return a DV object that contains the number of operations for each front using a backward looking algorithm created -- 96dec04, cca --------------------------------------------------------- */ DV * ETree_backwardOps ( ETree *etree, int type, int symflag, int *vwghts, IVL *symbfacIVL ) { double extops, opsKbndK, opsKK ; double *ops ; DV *opsDV ; int bndwghtJ, ii, J, k, K, kwght, nadj, nfront, size, wghtJ, wghtK ; int *counts, *indices, *list, *mark, *vtxToFront ; /* --------------- check the input --------------- */ if ( etree == NULL || symbfacIVL == NULL ) { fprintf(stderr, "\n fatal error in ETree_backwardOps(%p,%p,%p)" "\n bad input\n", etree, vwghts, symbfacIVL) ; exit(-1) ; } nfront = etree->nfront ; vtxToFront = IV_entries(etree->vtxToFrontIV) ; list = IVinit(nfront, -1) ; mark = IVinit(nfront, -1) ; counts = IVinit(nfront, 0) ; /* ---------------------------- initialize the ops DV object ---------------------------- */ opsDV = DV_new() ; DV_init(opsDV, nfront, NULL) ; ops = DV_entries(opsDV) ; DV_fill(opsDV, 0.0) ; /* ------------------- fill the ops vector ------------------- */ for ( J = 0 ; J < nfront ; J++ ) { ops[J] += ETree_nInternalOpsInFront(etree, type, symflag, J) ; wghtJ = ETree_frontSize(etree, J) ; bndwghtJ = ETree_frontBoundarySize(etree, J) ; IVL_listAndSize(symbfacIVL, J, &size, &indices) ; for ( ii = nadj = 0 ; ii < size ; ii++ ) { k = indices[ii] ; if ( (K = vtxToFront[k]) != J ) { kwght = (vwghts == NULL) ? 1 : vwghts[k] ; if ( mark[K] != J ) { counts[K] = 0 ; mark[K] = J ; list[nadj++] = K ; } counts[K] += kwght ; } } IVqsortUp(nadj, list) ; extops = 0.0 ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = list[ii] ; wghtK = counts[K] ; bndwghtJ -= wghtK ; if ( type == SPOOLES_REAL ) { opsKbndK = 2*wghtJ*wghtK*bndwghtJ ; if ( symflag == SPOOLES_SYMMETRIC ) { opsKK = wghtJ*wghtK*(wghtK+1) ; } else if ( symflag == SPOOLES_NONSYMMETRIC ) { opsKK = 2*wghtJ*wghtK*wghtK ; } } else if ( type == SPOOLES_COMPLEX ) { opsKbndK = 8*wghtJ*wghtK*bndwghtJ ; if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ) { opsKK = 4*wghtJ*wghtK*(wghtK+1) ; } else if ( symflag == SPOOLES_NONSYMMETRIC ) { opsKK = 8*wghtJ*wghtK*wghtK ; } } extops += opsKK + opsKbndK ; ops[K] += opsKK + opsKbndK ; if ( symflag == SPOOLES_NONSYMMETRIC ) { extops += opsKbndK ; ops[K] += opsKbndK ; } } /* fprintf(stdout, "\n front %d, %.0f internal ops, %.0f external ops, %.0f extops", J, ETree_nInternalOpsInFront(etree, type, symflag, J), ETree_nExternalOpsInFront(etree, type, symflag, J), extops) ; */ } IVfree(list) ; IVfree(mark) ; IVfree(counts) ; return(opsDV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ return an IV object that contains the number of entries for each front created -- 98jan30, cca ------------------------------------ */ IV * ETree_factorEntriesIV ( ETree *etree, int symflag ) { int J, nfront ; int *nzf ; IV *nzfIV ; /* --------------- check the input --------------- */ if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_factorEntriesIV(%p,%d)" "\n bad input\n", etree, symflag) ; exit(-1) ; } nfront = ETree_nfront(etree) ; /* ------------------------ initialize the IV object ------------------------ */ nzfIV = IV_new() ; IV_init(nzfIV, nfront, NULL) ; nzf = IV_entries(nzfIV) ; IV_fill(nzfIV, 0) ; /* ------------------- fill the nzf vector ------------------- */ for ( J = 0 ; J < nfront ; J++ ) { nzf[J] = ETree_nFactorEntriesInFront(etree, symflag, J) ; } return(nzfIV) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- return a DV object that contains the number of operations for each front using a forward-looking algorithm created -- 96dec04, cca --------------------------------------------------------- */ DV * ETree_forwardOps ( ETree *etree, int type, int symflag ) { double *ops ; DV *opsDV ; int J, nfront ; /* --------------- check the input --------------- */ if ( etree == NULL ) { fprintf(stderr, "\n fatal error in ETree_forwardOps(%p)" "\n bad input\n", etree) ; exit(-1) ; } nfront = etree->nfront ; opsDV = DV_new() ; DV_init(opsDV, nfront, NULL) ; ops = DV_entries(opsDV) ; DV_fill(opsDV, 0.0) ; for ( J = 0 ; J < nfront ; J++ ) { ops[J] += ETree_nInternalOpsInFront(etree, type, symflag, J) + ETree_nExternalOpsInFront(etree, type, symflag, J) ; } return(opsDV) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- given an IV object that maps uncompressed vertices to vertices, create and return an ETree object that is relative to the uncompressed graph. created -- 97feb13, cca --------------------------------------------------------------- */ ETree * ETree_expand ( ETree *etree, IV *eqmapIV ) { ETree *etree2 ; int ii, ndof, nfront ; int *map, *vtxToFront, *vtxToFront2 ; /* --------------- check the input --------------- */ if ( etree == NULL || eqmapIV == NULL ) { fprintf(stderr, "\n fatal error in ETree_expand(%p,%p)" "\n bad input\n", etree, eqmapIV) ; exit(-1) ; } nfront = etree->nfront ; IV_sizeAndEntries(eqmapIV, &ndof, &map) ; /* --------------------------- create the new ETree object --------------------------- */ etree2 = ETree_new() ; ETree_init1(etree2, nfront, ndof) ; IV_copy(etree2->nodwghtsIV, etree->nodwghtsIV) ; IV_copy(etree2->bndwghtsIV, etree->bndwghtsIV) ; etree2->tree->root = etree->tree->root ; IVcopy(nfront, etree2->tree->par, etree->tree->par) ; IVcopy(nfront, etree2->tree->fch, etree->tree->fch) ; IVcopy(nfront, etree2->tree->sib, etree->tree->sib) ; vtxToFront = IV_entries(etree->vtxToFrontIV) ; vtxToFront2 = IV_entries(etree2->vtxToFrontIV) ; for ( ii = 0 ; ii < ndof ; ii++ ) { vtxToFront2[ii] = vtxToFront[map[ii]] ; } return(etree2) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- this method is used to splice together two front trees when the domain vertices and schur complement vertices have been ordered separately. etree0 -- the lower front tree is for vertices in the domains. graph0 -- graph for all the vertices mapIV -- IV object that maps vertices to schur complement vertices, if IV_entry(mapIV, v) < 0 then v is a domain vertex. etree1 -- the upper front tree is for vertices in the schur complement. created -- 97feb01, cca -------------------------------------------------------------- */ ETree * ETree_spliceTwoETrees ( ETree *etree0, Graph *graph0, IV *mapIV, ETree *etree1 ) { ETree *etree2 ; int *bndwghts0, *bndwghts1, *bndwghts2, *fch0, *head0, *link0, *map, *mark, *nodwghts0, *nodwghts1, *nodwghts2, *par0, *par1, *par2, *sib0, *vadj, *vtxToFront0, *vtxToFront1, *vtxToFront2 ; int ii, J, K, nfront0, nfront1, nfront2, nvtx, phi, v, vsize, w ; /* --------------- check the input --------------- */ if ( etree0 == NULL || graph0 == NULL || mapIV == NULL || etree1 == NULL ) { fprintf(stderr, "\n fatal error in ETree_spliceTwoETrees(%p,%p,%p,%p)" "\n bad input\n", etree0, graph0, mapIV, etree1) ; exit(-1) ; } nfront0 = etree0->nfront ; nvtx = etree0->nvtx ; par0 = etree0->tree->par ; fch0 = etree0->tree->fch ; sib0 = etree0->tree->sib ; nodwghts0 = IV_entries(etree0->nodwghtsIV) ; bndwghts0 = IV_entries(etree0->bndwghtsIV) ; vtxToFront0 = IV_entries(etree0->vtxToFrontIV) ; nfront1 = etree1->nfront ; par1 = etree1->tree->par ; bndwghts1 = IV_entries(etree1->bndwghtsIV) ; nodwghts1 = IV_entries(etree1->nodwghtsIV) ; vtxToFront1 = IV_entries(etree1->vtxToFrontIV) ; map = IV_entries(mapIV) ; /* ------------------------- create the new front tree ------------------------- */ nfront2 = nfront0 + nfront1 ; etree2 = ETree_new() ; ETree_init1(etree2, nfront2, etree0->nvtx) ; par2 = etree2->tree->par ; nodwghts2 = IV_entries(etree2->nodwghtsIV) ; bndwghts2 = IV_entries(etree2->bndwghtsIV) ; vtxToFront2 = IV_entries(etree2->vtxToFrontIV) ; /* -------------------------------------------------- fill the parent fields for fronts in the same tree -------------------------------------------------- */ for ( J = 0 ; J < nfront0 ; J++ ) { par2[J] = par0[J] ; nodwghts2[J] = nodwghts0[J] ; bndwghts2[J] = bndwghts0[J] ; } for ( J = 0 ; J < nfront1 ; J++ ) { par2[J+nfront0] = nfront0 + par1[J] ; nodwghts2[J+nfront0] = nodwghts1[J] ; bndwghts2[J+nfront0] = bndwghts1[J] ; } /* --------------------------- set the vertex to front map --------------------------- */ for ( v = 0 ; v < nvtx ; v++ ) { if ( (J = vtxToFront0[v]) >= 0 ) { vtxToFront2[v] = J ; } else { vtxToFront2[v] = vtxToFront1[map[v]] + nfront0 ; } } /* --------------------------------------------- link the vertices to fronts in the lower tree --------------------------------------------- */ head0 = IVinit(nfront0, -1) ; link0 = IVinit(nvtx, -1) ; for ( v = 0 ; v < nvtx ; v++ ) { if ( (J = vtxToFront0[v]) >= 0 ) { link0[v] = head0[J] ; head0[J] = v ; } } /* ------------------------------------------------------- link roots of the lower tree to nodes in the upper tree ------------------------------------------------------- */ mark = IVinit(nvtx, -1) ; for ( J = etree0->tree->root ; J != -1 ; J = sib0[J] ) { /* --------------------------------------- K is the parent front in the upper tree --------------------------------------- */ K = nfront1 ; /* --------------------------------------- loop over vertices in the lower front J --------------------------------------- */ for ( v = head0[J] ; v != -1 ; v = link0[v] ) { Graph_adjAndSize(graph0, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( vtxToFront0[w] < 0 ) { phi = map[w] ; /* --------------------------------------------------- w is a vertex that belongs to phi in the upper tree --------------------------------------------------- */ if ( mark[phi] != J ) { mark[phi] = J ; if ( K > vtxToFront1[phi] ) { /* ------------------------------------ least numbered adjacent front so far ------------------------------------ */ K = vtxToFront1[phi] ; } } } } } if ( K < nfront1 ) { /* -------------------- set the parent field -------------------- */ par2[J] = nfront0 + K ; } } /* ----------------------------- set the remaining tree fields ----------------------------- */ Tree_setFchSibRoot(etree2->tree) ; /* ------------------------ free the working storage ------------------------ */ IVfree(head0) ; IVfree(link0) ; IVfree(mark) ; return(etree2) ; } /*--------------------------------------------------------------------*/ = J ; list[nadj++] = K ; } counts[K] += kwght ; } } IVqsortUp(nadj, list) ; extops = 0.0 ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = list[ii] ; wghtK = counts[K] ; bndETree/drivers/do_createETree010075500020550007177000000007130654275744500173760ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = GRD7x7 set inGraphFile = $matrices/$matrix/orig0.graphf set inPermFile = $matrices/$matrix/nd.permf set outIVfile = temp.ivf set outIVfile = none set outETreeFile = $matrices/$matrix/nd.etreeb set outETreeFile = temp.etreef set outETreeFile = none set msglvl = 1 set msgFile = stdout createETree $msglvl $msgFile \ $inGraphFile $inPermFile $outIVfile $outETreeFile ETree/drivers/do_expand010075500020550007177000000012130660252644000164430ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set number = 8 set inETreeFile = $matrices/$matrix/nd.etreef set inETreeFile = nd.etreef set inETreeFile = /local1/ARPA/matrices/i4a/best1.etreef set inETreeFile = /local1/ARPA/matrices/SFTC$number/best1.etreef set inEqmapFile = /local1/ARPA/matrices/i4a/map1.ivb set inEqmapFile = /local1/ARPA/matrices/SFTC$number/eqmap.ivb set outETreeFile = $matrices/$matrix/nd.etreeb set outETreeFile = none set outETreeFile = /local1/ARPA/matrices/SFTC$number/best0.etreef set msglvl = 1 set msgFile = stdout testExpand $msglvl $msgFile $inETreeFile $inEqmapFile $outETreeFile ETree/drivers/do_extractTopSep010075500020550007177000000004200653410607000177650ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inETreeFile = $matrices/$matrix/nd.etreef set outIVfile = none set outIVfile = temp.ivf set msglvl = 3 set msgFile = stdout extractTopSep $msglvl $msgFile $inETreeFile $outIVfile ETree/drivers/do_mkNDETree010075500020550007177000000020450665214737300167570ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrices = ../../../matrices set matrix = GRD3x2 set matrix = GRD15x15x15 set matrix = GRD7x7x7 set matrix = GRD31x31x31 set msglvl = 1 set msgFile = nd.res set msgFile = stdout set n1 = 33 set n2 = 33 set n3 = 33 set maxzeros = 16384 set maxzeros = 64 set maxsize = 32 set maxzeros = 0 set maxzeros = 1000 set maxsize = 100000 set maxsize = 64 set outFile = none set outFile = $matrices/$matrix/nd2.etreef set outFile = nd.etreef # foreach n ( 10 12 14 17 20 24 28 34 40 48 56 ) foreach n ( 31 ) set n1 = $n set n2 = $n set n3 = 1 set n3 = $n mkNDETree $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize $outFile end exit # foreach maxzeros ( 0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 ) mkNDETree $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize $outFile # end exit set nmax = 70 set nmin = 66 @ n = $nmin while ( $n <= $nmax ) echo n = $n mkNDETree $msglvl $msgFile $n $n $n $maxzeros $maxsize $outFile @ n = $n + 1 end ETree/drivers/do_mkNDoutput010075500020550007177000000010720654276002200173000ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = GRD3x2 set matrix = GRD15x15 set msglvl = 1 set msgFile = nd.res set msgFile = stdout set n1 = 15 set n2 = 15 set n3 = 15 set maxzeros = 1000 set maxsize = 32 set outETreeFile = none set outETreeFile = $matrices/$matrix/nd.etreef set nthread = 4 set maptype = 4 set cutoff = 0.125 set outOwnersFile = $matrices/$matrix/ndowners.ivf set outOwnersFile = none mkNDoutput $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize \ $nthread $maptype $cutoff $outETreeFile $outOwnersFile ETree/drivers/do_permuteETree010075500020550007177000000005610653410607000175740ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inETreeFile = $matrices/$matrix/nd.etreef set inEqmapFile = none set outETreeFile = $matrices/$matrix/nd.etreeb set outETreeFile = none set outIVfile = none set msglvl = 3 set msgFile = stdout permuteETree $msglvl $msgFile \ $inETreeFile $inEqmapFile $outETreeFile $outIVfile ETree/drivers/do_temp010075500020550007177000000011570664520645500161500ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set msgFile = nd3d.res set n1 = 33 set n2 = 33 set n3 = 33 set maxzeros = 16384 set maxzeros = 64 set maxsize = 32 set maxzeros = 1000 set maxzeros = 0 set maxsize = 64 set maxsize = 100000 # foreach n ( 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 ) # foreach n ( 10 12 14 17 20 24 28 34 40 48 56 ) foreach n ( 31 ) set n1 = $n set n2 = $n # set n3 = 1 set n3 = $n echo $n1 x $n2 x $n3 mkNDETree $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize nd.etreef testHeight $msglvl $msgFile nd.etreef rm nd.etreef end ETree/drivers/do_testFS010075500020550007177000000017540665245673300164220ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inETreeFile = $matrices/$matrix/nd.etreef set inGraphFile = $matrices/$matrix/orig0.graphf set matrices = ../../../matrices set matrix = BCSSTK24 set matrix = GRD15x15x127 set matrix = BCSSTK37 set matrix = BCSSTK30 set matrix = MN12 set matrix = GRD31x31x31 set matrix = GRD7x7 # set matrices = /local1/ARPA/matrices # set matrix = i4a set inETreeFile = $matrices/$matrix/nd2.etreef set inETreeFile = $matrices/$matrix/msmd.etreef set inETreeFile = $matrices/$matrix/best0.etreef set inETreeFile = $matrices/$matrix/ms.etreef set inETreeFile = $matrices/$matrix/mmd.etreef set inETreeFile = $matrices/$matrix/nd.etreef set firstEPSfile = temp1.eps set secondEPSfile = temp2.eps set labelflag = 1 set radius = 10 set msglvl = 1 set msgFile = stdout testFS $msglvl $msgFile $inETreeFile \ $labelflag $radius $firstEPSfile $secondEPSfile ETree/drivers/do_testHeight010075500020550007177000000015170664516225400173110ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inETreeFile = $matrices/$matrix/nd.etreef set inGraphFile = $matrices/$matrix/orig0.graphf set matrices = ../../../matrices set matrix = BCSSTK24 set matrix = GRD15x15x127 set matrix = GRD7x7 set matrix = GRD31x31x31 set matrix = BCSSTK37 set matrix = BCSSTK30 set matrix = MN12 # set matrices = /local1/ARPA/matrices # set matrix = i4a set inETreeFile = $matrices/$matrix/nd2.etreef set inETreeFile = $matrices/$matrix/msmd.etreef set inETreeFile = $matrices/$matrix/best0.etreef set inETreeFile = $matrices/$matrix/mmd.etreef set inETreeFile = $matrices/$matrix/nd.etreef set inETreeFile = $matrices/$matrix/ms.etreef set msglvl = 1 set msgFile = stdout testHeight $msglvl $msgFile $inETreeFile ETree/drivers/do_testIO010075500020550007177000000004340663207461400164030ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inFile = nd.etreef set inFile = $matrices/$matrix/nd.etreef set outFile = $matrices/$matrix/nd.etreeb set outFile = none set msglvl = 3 set msgFile = stdout testIO $msglvl $msgFile $inFile $outFile ETree/drivers/do_testMS010075500020550007177000000010660660523751000164110ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set matrices = ../../../matrices set matrix = R10KV set inFile = $matrices/$matrix/best0.etreef set msglvl = 1 set msgFile = res set msgFile = stdout set outFile = none set outFile = $matrices/$matrix/ndms.ivf set flag = 1 set cutoff = 4 set flag = 2 set cutoff = 0.015625 set cutoff = 0.0625 set cutoff = 0.125 set cutoff = 0.03125 # foreach cutoff ( 0.5 0.25 0.125 0.0625 0.03125 0.015625 0.0078125 ) testMS $msglvl $msgFile $inFile $outFile $flag $cutoff # end ETree/drivers/do_testMaps010075500020550007177000000011510661444375300167750ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D10000 set matrices = ../../../matrices set matrix = GRD7x7 set matrix = R2D100 set matrix = GRD31x31x31 set msglvl = 1 set msgFile = stdout set inFile = nd.etreef set inFile = $matrices/$matrix/nd.1024.64.etreef set inFile = $matrices/$matrix/ndnew.etreef set outFile = temp.ivf set outFile = $matrices/$matrix/nd.1024.64.dd4.ivf set outFile = none set outFile = $matrices/$matrix/ndowners.ivf set nthread = 16 set type = 3 set cutoff = 0.031250 testMaps $msglvl $msgFile $inFile $outFile $nthread $type $cutoff ETree/drivers/do_testStats010075500020550007177000000020560665246112700171750ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set matrices = ../../../matrices set matrix = GRD7x7 set matrix = GRD127x127 set matrix = GRD31x31x31 set matrix = BCSSTK39 set matrix = GRD7x7x7 set inETreeFile = nd.etreef set inETreeFile = $matrices/$matrix/nd.etreef set inGraphFile = $matrices/$matrix/orig0.graphb set inGraphFile = $matrices/$matrix/orig1.graphb set inGraphFile = $matrices/$matrix/orig0.graphf set msglvl = 1 set msgFile = res set msgFile = stdout set outEPSfile = none set outEPSfile = temp.eps # # metricType # 0 -- no metric # 1 -- size of front # 2 -- # original matrix entries in front # 3 -- # factor matrix entries in front # 4 -- # forward factor ops in front # 5 -- # backward factor ops in front # set metricType = 5 set heightflag = D set coordflag = P set rmax = 20 set labelflag = 0 set fontscale = 6 testStats $msglvl $msgFile $inETreeFile $inGraphFile $outEPSfile \ $metricType $heightflag $coordflag $rmax $labelflag $fontscale ETree/drivers/do_testStorage010075500020550007177000000014450664346407700175130ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inETreeFile = $matrices/$matrix/nd.etreef set inGraphFile = $matrices/$matrix/orig0.graphf set matrices = ../../../matrices set matrix = GRD31x31x31 set matrix = BCSSTK24 set matrix = BCSSTK30 set matrix = GRD15x15x127 set inETreeFile = $matrices/$matrix/nd2.etreef set inETreeFile = $matrices/$matrix/best0.etreef set inETreeFile = $matrices/$matrix/msmd.etreef set inETreeFile = $matrices/$matrix/mmd.etreef set inETreeFile = $matrices/$matrix/nd.etreef set inETreeFile = $matrices/$matrix/ms.etreef set inGraphFile = $matrices/$matrix/orig1.graphb set inGraphFile = $matrices/$matrix/orig0.graphb set msglvl = 1 set msgFile = stdout testStorage $msglvl $msgFile $inETreeFile $inGraphFile 30 set matrix = GRD15x15x127 set inETreeFile = $matrices/$matrix/nd2.etreef set inETreeFile = $matrices/$matrix/best0.etreef set inETreeFile = $matrices/$matrix/msmd.etreef set inETreeFile = $matrices/$matrix/mmd.ETree/drivers/do_testTransform010075500020550007177000000016110663303457600200510ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D10000 set matrices = ../../../matrices set matrix = R3D13824 set msglvl = 1 set msgFile = $matrix.mmd.old set msgFile = $matrix.nd.old set msgFile = stdout set inGraphFile = $matrices/$matrix/orig1.graphb set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig0.graphb set inETreeFile = $matrices/$matrix/nd.etreef set outETreeFile = none set maxzeros = 10 set maxsize = 100000 set seed = 10101 set outETreeFile = none set outETreeFile = $matrices/$matrix/nd.$maxzeros.$maxsize.etreef foreach maxzeros ( 0 ) echo maxzeros = $maxzeros foreach maxsize ( 100000 ) echo maxsize = $maxsize set outETreeFile = $matrices/$matrix/nd.$maxzeros.$maxsize.etreef testTransform $msglvl $msgFile $inETreeFile $inGraphFile \ $outETreeFile $maxzeros $maxsize $seed end end ETree/drivers/makefile010064400020550007177000000044050665340425100162630ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = createETree \ extractTopSep \ mkNDETree \ mkNDoutput \ permuteETree \ testExpand \ testFS \ testHeight \ testIO \ testMaps \ testMS \ testStats \ testStorage \ testTransform drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} createETree : createETree.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} extractTopSep : extractTopSep.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} mkNDETree : mkNDETree.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} mkNDoutput : mkNDoutput.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} mkNDoutput2 : mkNDoutput2.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} permuteETree : permuteETree.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testBalance : testBalance.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testBounds : testBounds.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testDense : testDense.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testExpand : testExpand.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testFS : testFS.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testHeight : testHeight.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testIO : testIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testMaps : testMaps.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testMS : testMS.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testStats : testStats.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testStorage : testStorage.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testTransform : testTransform.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} ETree/drivers/createETree.c010064400020550007177000000171600653602206200171150ustar00clevecompmath00000400000006/* createETree.c */ #include "../ETree.h" #include "../../Perm.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------- read in a Graph and a Perm object. create the ETree object and fill an IV object with the compids of the two-set partition created -- 96may02, cca --------------------------------------------- */ { char *inGraphFileName, *inPermFileName, *outETreeFileName, *outIVfileName ; double t1, t2 ; int msglvl, rc ; ETree *etree, *fsETree ; IV *fsMapIV ; FILE *msgFile ; Graph *graph ; Perm *perm ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile inPermFile " "\n outIVfile outETreeFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n inPermFile -- input file, must be *.permf or *.permb" "\n outIVfile -- output file for compids[]" "\n must be *.ivf or *.ivf" "\n outETreeFile -- output file, must be *.etreef or *.etreeb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; inPermFileName = argv[4] ; outIVfileName = argv[5] ; outETreeFileName = argv[6] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n inPermFile -- %s" "\n outIVfile -- %s" "\n outETreeFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, inPermFileName, outIVfileName, outETreeFileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* ------------------------ read in the Perm object ------------------------ */ if ( strcmp(inPermFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; /* exit(0) ; */ perm = NULL ; } else { perm = Perm_new() ; MARKTIME(t1) ; rc = Perm_readFromFile(perm, inPermFileName) ; Perm_fillOldToNew(perm) ; Perm_fillNewToOld(perm) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in perm from file %s", t2 - t1, inPermFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Perm_readFromFile(%p,%s)", rc, perm, inPermFileName) ; exit(-1) ; } rc = Perm_checkPerm(perm) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error, Perm not valid") ; Perm_writeForHumanEye(perm, stderr) ; exit(0) ; } fprintf(msgFile, "\n\n after reading Perm object from file %s", inPermFileName) ; if ( msglvl > 0 ) { Perm_writeForHumanEye(perm, msgFile) ; } else { Perm_writeStats(perm, msgFile) ; } fflush(msgFile) ; } fprintf(msgFile, "\n newToOld") ; IVfprintf(msgFile, perm->size, perm->newToOld) ; fprintf(msgFile, "\n oldToNew") ; IVfprintf(msgFile, perm->size, perm->oldToNew) ; /* ----------------------- create the ETree object ----------------------- */ etree = ETree_new() ; if ( perm == NULL ) { ETree_initFromGraph(etree, graph) ; } else { ETree_initFromGraphWithPerms(etree, graph, perm->newToOld, perm->oldToNew) ; } fprintf(msgFile, "\n\n vertex etree") ; fprintf(msgFile, "\n %d factor indices", ETree_nFactorIndices(etree)) ; fprintf(msgFile, "\n symmetric: %d factor entries", ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC)) ; fprintf(msgFile, "\n nonsymmetric: %d factor entries", ETree_nFactorEntries(etree, SPOOLES_NONSYMMETRIC)) ; fprintf(msgFile, "\n real symmetric : %.0f factor operations", ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; fprintf(msgFile, "\n real nonsymmetric : %.0f factor operations", ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_NONSYMMETRIC)) ; fprintf(msgFile, "\n complex symmetric : %.0f factor operations", ETree_nFactorOps(etree, SPOOLES_COMPLEX, SPOOLES_SYMMETRIC)) ; fprintf(msgFile, "\n complex nonsymmetric : %.0f factor operations", ETree_nFactorOps(etree, SPOOLES_COMPLEX, SPOOLES_NONSYMMETRIC)); fsMapIV = ETree_fundSupernodeMap(etree) ; fsETree = ETree_compress(etree, fsMapIV) ; fprintf(msgFile, "\n\n fundamental supernode etree") ; fprintf(msgFile, "\n %d factor indices", ETree_nFactorIndices(fsETree)) ; fprintf(msgFile, "\n symmetric: %d factor entries", ETree_nFactorEntries(fsETree, SPOOLES_SYMMETRIC)) ; fprintf(msgFile, "\n nonsymmetric: %d factor entries", ETree_nFactorEntries(fsETree, SPOOLES_NONSYMMETRIC)) ; fprintf(msgFile, "\n real symmetric : %.0f factor operations", ETree_nFactorOps(fsETree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; fprintf(msgFile, "\n real nonsymmetric : %.0f factor operations", ETree_nFactorOps(fsETree, SPOOLES_REAL, SPOOLES_NONSYMMETRIC)) ; fprintf(msgFile, "\n complex symmetric : %.0f factor operations", ETree_nFactorOps(fsETree, SPOOLES_COMPLEX, SPOOLES_SYMMETRIC)) ; fprintf(msgFile, "\n complex nonsymmetric : %.0f factor operations", ETree_nFactorOps(fsETree, SPOOLES_COMPLEX, SPOOLES_NONSYMMETRIC)); fprintf(msgFile, "\n %.0f factor operations", ETree_nFactorOps(fsETree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(fsETree, msgFile) ; } else { ETree_writeStats(fsETree, msgFile) ; } fflush(msgFile) ; /* -------------------------- write out the ETree object -------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { MARKTIME(t1) ; rc = ETree_writeToFile(fsETree, outETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write etree to file %s", t2 - t1, outETreeFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_writeToFile(%p,%s)", rc, fsETree, outETreeFileName) ; } /* ------------------------------- write out the compids IV object ------------------------------- */ if ( strcmp(outIVfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(fsETree->vtxToFrontIV, outIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write etree to file %s", t2 - t1, outIVfileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_writeToFile(%p,%s)", rc, fsETree->vtxToFrontIV, outIVfileName) ; } /* ---------------- free the objects ---------------- */ Graph_free(graph) ; Perm_free(perm) ; ETree_free(etree) ; ETree_free(fsETree) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ (perm) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in perm from file %s", t2 - t1, inPermFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Perm_readFromFile(%p,%s)", rc, perm, inPermFileName) ; exit(-1) ; } rc = Perm_checkPerm(perm) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error, Perm noETree/drivers/extractTopSep.c010064400020550007177000000112730653602267200175400ustar00clevecompmath00000400000006/* extractTopSep.c */ #include "../ETree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------------------- read in a ETree object, create an IV object with the same size, mark the vertices in the top level separator(s), write the IV object to a file created -- 96may02, cca --------------------------------------------------------------- */ { char *inETreeFileName, *outIVfileName ; double t1, t2 ; int msglvl, rc, J, K, ncomp, nfront, nvtx, v ; int *bndwghts, *compids, *fch, *map, *nodwghts, *par, *sib, *vtxToFront ; IV *compidsIV, *mapIV ; ETree *etree ; FILE *msgFile ; Tree *tree ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile outIVfile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n outIVfile -- output file, must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; outIVfileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n outIVfile -- %s" "\n", argv[0], msglvl, argv[2], inETreeFileName, outIVfileName) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } fflush(msgFile) ; nfront = ETree_nfront(etree) ; nvtx = ETree_nvtx(etree) ; bndwghts = ETree_bndwghts(etree) ; vtxToFront = ETree_vtxToFront(etree) ; nodwghts = ETree_nodwghts(etree) ; par = ETree_par(etree) ; fch = ETree_fch(etree) ; sib = ETree_sib(etree) ; tree = ETree_tree(etree) ; /* ----------------------------------------- create the map from fronts to components, top level separator(s) are component zero ----------------------------------------- */ mapIV = IV_new() ; IV_init(mapIV, nfront, NULL) ; map = IV_entries(mapIV) ; ncomp = 0 ; for ( J = Tree_preOTfirst(tree) ; J != -1 ; J = Tree_preOTnext(tree, J) ) { if ( (K = par[J]) == -1 ) { map[J] = 0 ; } else if ( map[K] != 0 ) { map[J] = map[K] ; } else if ( J == fch[K] && sib[J] == -1 && bndwghts[J] == nodwghts[K] + bndwghts[K] ) { map[J] = 0 ; } else { map[J] = ++ncomp ; } } fprintf(msgFile, "\n\n mapIV object") ; if ( msglvl > 2 ) { IV_writeForHumanEye(mapIV, msgFile) ; } else { IV_writeStats(mapIV, msgFile) ; } /* ---------------------------------------- fill the map from vertices to components ---------------------------------------- */ compidsIV = IV_new() ; IV_init(compidsIV, nvtx, NULL) ; compids = IV_entries(compidsIV) ; for ( v = 0 ; v < nvtx ; v++ ) { compids[v] = map[vtxToFront[v]] ; } fprintf(msgFile, "\n\n compidsIV object") ; if ( msglvl > 2 ) { IV_writeForHumanEye(compidsIV, msgFile) ; } else { IV_writeStats(compidsIV, msgFile) ; } fflush(msgFile) ; /* ----------------------- write out the IV object ----------------------- */ if ( strcmp(outIVfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(compidsIV, outIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write etree to file %s", t2 - t1, outIVfileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_writeToFile(%p,%s)", rc, compidsIV, outIVfileName) ; } /* ---------------- free the objects ---------------- */ ETree_free(etree) ; IV_free(mapIV) ; IV_free(compidsIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ETree/drivers/mkNDETree.c010064400020550007177000000216730661613607300165160ustar00clevecompmath00000400000006/* mkNDETreeNew.c */ #include "../../ETree.h" #include "../../EGraph.h" #include "../../misc.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------ make ETree objects for nested dissection on a regular grid 1 -- vertex elimination tree 2 -- fundamental supernode front tree 3 -- merge only children if possible 4 -- merge all children if possible 5 -- split large non-leaf fronts created -- 98feb05, cca ------------------------------------------------------------ */ { char *outETreeFileName ; double ops[6] ; double t1, t2 ; EGraph *egraph ; ETree *etree0, *etree1, *etree2, *etree3, *etree4, *etree5 ; FILE *msgFile ; Graph *graph ; int nfronts[6], nfind[6], nzf[6] ; int maxsize, maxzeros, msglvl, n1, n2, n3, nvtx, rc, v ; int *newToOld, *oldToNew ; IV *nzerosIV ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 maxzeros maxsize outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- number of points in the first direction" "\n n2 -- number of points in the second direction" "\n n3 -- number of points in the third direction" "\n maxzeros -- number of points in the third direction" "\n maxsize -- maximum number of vertices in a front" "\n outFile -- output file, must be *.etreef or *.etreeb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; n3 = atoi(argv[5]) ; maxzeros = atoi(argv[6]) ; maxsize = atoi(argv[7]) ; outETreeFileName = argv[8] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n n1 -- %d" "\n n2 -- %d" "\n n3 -- %d" "\n maxzeros -- %d" "\n maxsize -- %d" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], n1, n2, n3, maxzeros, maxsize, outETreeFileName) ; fflush(msgFile) ; /* ---------------------------- create the grid graph object ---------------------------- */ if ( n1 == 1 ) { egraph = EGraph_make9P(n2, n3, 1) ; } else if ( n2 == 1 ) { egraph = EGraph_make9P(n1, n3, 1) ; } else if ( n3 == 1 ) { egraph = EGraph_make9P(n1, n2, 1) ; } else { egraph = EGraph_make27P(n1, n2, n3, 1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n %d x %d x %d grid EGraph", n1, n2, n3) ; EGraph_writeForHumanEye(egraph, msgFile) ; fflush(msgFile) ; } graph = EGraph_mkAdjGraph(egraph) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n %d x %d x %d grid Graph", n1, n2, n3) ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- get the nested dissection ordering ---------------------------------- */ nvtx = n1*n2*n3 ; newToOld = IVinit(nvtx, -1) ; oldToNew = IVinit(nvtx, -1) ; mkNDperm(n1, n2, n3, newToOld, 0, n1-1, 0, n2-1, 0, n3-1) ; for ( v = 0 ; v < nvtx ; v++ ) { oldToNew[newToOld[v]] = v ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n %d x %d x %d nd ordering", n1, n2, n3) ; IVfprintf(msgFile, nvtx, oldToNew) ; fflush(msgFile) ; } /* ------------------------------------------ create the vertex elimination ETree object ------------------------------------------ */ etree0 = ETree_new() ; ETree_initFromGraphWithPerms(etree0, graph, newToOld, oldToNew) ; nfronts[0] = ETree_nfront(etree0) ; nfind[0] = ETree_nFactorIndices(etree0) ; nzf[0] = ETree_nFactorEntries(etree0, SPOOLES_SYMMETRIC) ; ops[0] = ETree_nFactorOps(etree0, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n vtx tree : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[0], nfind[0], nzf[0], ops[0]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n vertex elimination tree") ; ETree_writeForHumanEye(etree0, msgFile) ; fflush(msgFile) ; } /* --------------------------------------------- create the fundamental supernode ETree object --------------------------------------------- */ nzerosIV = IV_new() ; IV_init(nzerosIV, nvtx, NULL) ; IV_fill(nzerosIV, 0) ; etree1 = ETree_mergeFrontsOne(etree0, 0, nzerosIV) ; nfronts[1] = ETree_nfront(etree1) ; nfind[1] = ETree_nFactorIndices(etree1) ; nzf[1] = ETree_nFactorEntries(etree1, SPOOLES_SYMMETRIC) ; ops[1] = ETree_nFactorOps(etree1, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n fs tree : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[1], nfind[1], nzf[1], ops[1]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n fundamental supernode front tree") ; ETree_writeForHumanEye(etree1, msgFile) ; fprintf(msgFile, "\n\n nzerosIV") ; IV_writeForHumanEye(nzerosIV, msgFile) ; fflush(msgFile) ; } /* --------------------------- try to absorb only children --------------------------- */ etree2 = ETree_mergeFrontsOne(etree1, maxzeros, nzerosIV) ; nfronts[2] = ETree_nfront(etree2) ; nfind[2] = ETree_nFactorIndices(etree2) ; nzf[2] = ETree_nFactorEntries(etree2, SPOOLES_SYMMETRIC) ; ops[2] = ETree_nFactorOps(etree2, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n merge one : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[2], nfind[2], nzf[2], ops[2]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after mergeOne") ; ETree_writeForHumanEye(etree2, msgFile) ; fprintf(msgFile, "\n\n nzerosIV") ; IV_writeForHumanEye(nzerosIV, msgFile) ; fflush(msgFile) ; } /* -------------------------- try to absorb all children -------------------------- */ etree3 = ETree_mergeFrontsAll(etree2, maxzeros, nzerosIV) ; nfronts[3] = ETree_nfront(etree3) ; nfind[3] = ETree_nFactorIndices(etree3) ; nzf[3] = ETree_nFactorEntries(etree3, SPOOLES_SYMMETRIC) ; ops[3] = ETree_nFactorOps(etree3, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n merge all : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[3], nfind[3], nzf[3], ops[3]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after mergeAll") ; ETree_writeForHumanEye(etree3, msgFile) ; fprintf(msgFile, "\n\n nzerosIV") ; IV_writeForHumanEye(nzerosIV, msgFile) ; fflush(msgFile) ; } /* -------------------------------- try to absorb any other children -------------------------------- */ etree4 = etree3 ; /* etree4 = ETree_mergeFrontsAny(etree3, maxzeros, nzerosIV) ; nfronts[4] = ETree_nfront(etree4) ; nfind[4] = ETree_nFactorIndices(etree4) ; nzf[4] = ETree_nFactorEntries(etree4, SPOOLES_SYMMETRIC) ; ops[4] = ETree_nFactorOps(etree4, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n merge any : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[4], nfind[4], nzf[4], ops[4]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after mergeAny") ; ETree_writeForHumanEye(etree3, msgFile) ; fprintf(msgFile, "\n\n nzerosIV") ; IV_writeForHumanEye(nzerosIV, msgFile) ; fflush(msgFile) ; } */ /* -------------------- split the front tree -------------------- */ etree5 = ETree_splitFronts(etree4, NULL, maxsize, 0) ; nfronts[5] = ETree_nfront(etree5) ; nfind[5] = ETree_nFactorIndices(etree5) ; nzf[5] = ETree_nFactorEntries(etree5, SPOOLES_SYMMETRIC) ; ops[5] = ETree_nFactorOps(etree5, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n split : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[5], nfind[5], nzf[5], ops[5]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after split") ; ETree_writeForHumanEye(etree4, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n\n complex symmetric ops %.0f", ETree_nFactorOps(etree5, SPOOLES_COMPLEX, SPOOLES_SYMMETRIC)) ; /* -------------------------- write out the ETree object -------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { MARKTIME(t1) ; rc = ETree_writeToFile(etree5, outETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write etree to file %s", t2 - t1, outETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_writeToFile(%p,%s)", rc, etree5, outETreeFileName) ; } } /* ---------------- free the objects ---------------- */ ETree_free(etree0) ; ETree_free(etree1) ; ETree_free(etree2) ; ETree_free(etree3) ; /* ETree_free(etree4) ; */ ETree_free(etree5) ; EGraph_free(egraph) ; Graph_free(graph) ; IVfree(newToOld) ; IVfree(oldToNew) ; IV_free(nzerosIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ETree/drivers/mkNDoutput.c010064400020550007177000000260610654222441200170370ustar00clevecompmath00000400000006/* mkNDoutput.c */ #include "../../ETree.h" #include "../../SymbFac.h" #include "../../EGraph.h" #include "../../misc.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------------------- create (1) an ETree object for nested dissection on a regular grid using a bound on zeros in a front and a bound on front size (2) an IV object that maps fronts to threads using a wrap map, a balanced map, a subtree-subset map, or a domain decomposition map created -- 98feb05, cca --------------------------------------------------------------- */ { char *outETreeFileName, *outMapIVfileName ; double cutoff, t1, t2 ; double ops[5] ; DV *cumopsDV ; int maptype, maxsize, maxzeros, msglvl, n1, n2, n3, nthread, nvtx, rc, v ; int nfind[5], nfronts[5], nzf[5] ; int *newToOld, *oldToNew ; IV *msIV, *nzerosIV, *ownersIV ; IVL *symbfacIVL ; EGraph *egraph ; ETree *etree0, *etree1, *etree2, *etree3, *etree4 ; FILE *msgFile ; Graph *graph ; if ( argc != 13 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 maxzeros maxsize " "\n nthread maptype cutoff etreeFile mapFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- number of points in the first direction" "\n n2 -- number of points in the second direction" "\n n3 -- number of points in the third direction" "\n maxzeros -- number of points in the third direction" "\n maxsize -- maximum number of vertices in a front" "\n nthread -- number of threads" "\n maptype -- map type" "\n 1 -- wrap map" "\n 2 -- balanced map" "\n 3 -- subtree-subset map" "\n 4 -- domain decomposition map" "\n cutoff -- cutoff for domain size w.r.t. # vertices" "\n used only for the domain decomposition map" "\n etreeFile -- output file, must be *.etreef or *.etreeb" "\n mapFile -- output file, must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; n3 = atoi(argv[5]) ; maxzeros = atoi(argv[6]) ; maxsize = atoi(argv[7]) ; nthread = atoi(argv[8]) ; maptype = atof(argv[9]) ; cutoff = atof(argv[10]) ; outETreeFileName = argv[11] ; outMapIVfileName = argv[12] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n n1 -- %d" "\n n2 -- %d" "\n n3 -- %d" "\n maxzeros -- %d" "\n maxsize -- %d" "\n nthread -- %d" "\n maptype -- %d" "\n cutoff -- %f" "\n etreeFile -- %s" "\n mapFile -- %s" "\n", argv[0], msglvl, argv[2], n1, n2, n3, maxzeros, maxsize, nthread, maptype, cutoff, outETreeFileName, outMapIVfileName) ; fflush(msgFile) ; if ( maptype < 0 || maptype > 4 ) { fprintf(stderr, "\n fatal error, maptype = %d, use " "\n 1 -- wrap map" "\n 2 -- balanced map" "\n 3 -- subtree-subset map" "\n 4 -- domain decomposition map\n", maptype) ; exit(-1) ; } /* ---------------------------- create the grid graph object ---------------------------- */ if ( n3 == 1 ) { egraph = EGraph_make9P(n1, n2, 1) ; } else { egraph = EGraph_make27P(n1, n2, n3, 1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n %d x %d x %d grid EGraph", n1, n2, n3) ; EGraph_writeForHumanEye(egraph, msgFile) ; fflush(msgFile) ; } graph = EGraph_mkAdjGraph(egraph) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n %d x %d x %d grid Graph", n1, n2, n3) ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- get the nested dissection ordering ---------------------------------- */ nvtx = n1*n2*n3 ; newToOld = IVinit(nvtx, -1) ; oldToNew = IVinit(nvtx, -1) ; mkNDperm(n1, n2, n3, newToOld, 0, n1-1, 0, n2-1, 0, n3-1) ; for ( v = 0 ; v < nvtx ; v++ ) { oldToNew[newToOld[v]] = v ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n %d x %d x %d nd ordering", n1, n2, n3) ; IVfprintf(msgFile, nvtx, oldToNew) ; fflush(msgFile) ; } /* --------------------------------------------- create the fundamental supernode ETree object --------------------------------------------- */ nzerosIV = IV_new() ; IV_init(nzerosIV, nvtx, NULL) ; IV_fill(nzerosIV, 0) ; etree0 = ETree_new() ; ETree_initFromGraphWithPerms(etree0, graph, newToOld, oldToNew) ; etree1 = ETree_mergeFrontsOne(etree0, 0, nzerosIV) ; nfronts[0] = ETree_nfront(etree1) ; nfind[0] = ETree_nFactorIndices(etree1) ; nzf[0] = ETree_nFactorEntries(etree1, SPOOLES_SYMMETRIC) ; ops[0] = ETree_nFactorOps(etree1, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n\n fs tree : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[0], nfind[0], nzf[0], ops[0]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n fundamental elimination tree") ; ETree_writeForHumanEye(etree1, msgFile) ; fflush(msgFile) ; } /* --------------------------------------- first step: try to absorb an only child --------------------------------------- */ etree2 = ETree_mergeFrontsOne(etree1, maxzeros, nzerosIV) ; nfronts[1] = ETree_nfront(etree2) ; nfind[1] = ETree_nFactorIndices(etree2) ; nzf[1] = ETree_nFactorEntries(etree2, SPOOLES_SYMMETRIC) ; ops[1] = ETree_nFactorOps(etree2, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n merge 1 : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[1], nfind[1], nzf[1], ops[1]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after first merge") ; ETree_writeForHumanEye(etree2, msgFile) ; fflush(msgFile) ; } /* --------------------------------------- second step: try to absorb all children --------------------------------------- */ etree3 = ETree_mergeFrontsAll(etree2, maxzeros, nzerosIV) ; nfronts[2] = ETree_nfront(etree3) ; nfind[2] = ETree_nFactorIndices(etree3) ; nzf[2] = ETree_nFactorEntries(etree3, SPOOLES_SYMMETRIC) ; ops[2] = ETree_nFactorOps(etree3, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n merge 2 : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[2], nfind[2], nzf[2], ops[2]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after second merge") ; ETree_writeForHumanEye(etree3, msgFile) ; fflush(msgFile) ; } /* -------------------------------- third step: split the front tree -------------------------------- */ etree4 = ETree_splitFronts(etree3, NULL, maxsize, 0) ; nfronts[3] = ETree_nfront(etree4) ; nfind[3] = ETree_nFactorIndices(etree4) ; nzf[3] = ETree_nFactorEntries(etree4, SPOOLES_SYMMETRIC) ; ops[3] = ETree_nFactorOps(etree4, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n split : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[3], nfind[3], nzf[3], ops[3]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after split") ; ETree_writeForHumanEye(etree4, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------- create the symbolic factorization object ---------------------------------------- */ symbfacIVL = SymbFac_initFromGraph(etree4, graph) ; nfronts[4] = ETree_nfront(etree4) ; nfind[4] = ETree_nFactorIndices(etree4) ; nzf[4] = ETree_nFactorEntries(etree4, SPOOLES_SYMMETRIC) ; ops[4] = ETree_nFactorOps(etree4, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n final : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[4], nfind[4], nzf[4], ops[4]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after symbolic factorization") ; ETree_writeForHumanEye(etree4, msgFile) ; fprintf(msgFile, "\n\n after symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; } /* -------------------------- write out the ETree object -------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { MARKTIME(t1) ; rc = ETree_writeToFile(etree4, outETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write etree to file %s", t2 - t1, outETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_writeToFile(%p,%s)", rc, etree4, outETreeFileName) ; } } /* ---------------------------- get the owners map IV object ---------------------------- */ cumopsDV = DV_new() ; DV_init(cumopsDV, nthread, NULL) ; DV_fill(cumopsDV, 0.0) ; switch ( maptype ) { case 1 : /* wrap map */ ownersIV = ETree_wrapMap(etree4, SPOOLES_REAL, SPOOLES_SYMMETRIC, cumopsDV) ; break ; case 2 : /* balanced map */ ownersIV = ETree_balancedMap(etree4, SPOOLES_REAL, SPOOLES_SYMMETRIC, cumopsDV) ; break ; case 3 : /* subtree-subset map */ ownersIV = ETree_subtreeSubsetMap(etree4, SPOOLES_REAL, SPOOLES_SYMMETRIC, cumopsDV) ; break ; case 4 : /* dd map */ msIV = ETree_msByNvtxCutoff(etree4, cutoff) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n multisector IV object") ; IV_writeForHumanEye(msIV, msgFile) ; fflush(msgFile) ; } ownersIV = ETree_ddMapNew(etree4, SPOOLES_REAL, SPOOLES_SYMMETRIC, msIV, cumopsDV) ; IV_free(msIV) ; break ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n totalOps = %.0f", DV_sum(cumopsDV)) ; DVscale(DV_size(cumopsDV), DV_entries(cumopsDV), nthread/DV_sum(cumopsDV)) ; fprintf(msgFile, "\n\n cumopsDV") ; DV_writeForHumanEye(cumopsDV, msgFile) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ownersIV") ; IV_writeForHumanEye(ownersIV, msgFile) ; fflush(msgFile) ; } /* --------------------------- write out the map IV object --------------------------- */ if ( strcmp(outMapIVfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(ownersIV, outMapIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write owners map to file %s", t2 - t1, outMapIVfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_writeToFile(%p,%s)", rc, ownersIV, outMapIVfileName) ; } } /* ---------------- free the objects ---------------- */ ETree_free(etree0) ; ETree_free(etree1) ; ETree_free(etree2) ; ETree_free(etree3) ; ETree_free(etree4) ; EGraph_free(egraph) ; Graph_free(graph) ; IVfree(newToOld) ; IVfree(oldToNew) ; IV_free(nzerosIV) ; IV_free(ownersIV) ; IVL_free(symbfacIVL) ; DV_free(cumopsDV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ; ETree *etree0, *etree1, *etree2, *etree3, *etree4 ; FILE *msgFile ; Graph *graph ; if ( argc != 13 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 maxzeros maxsize " "\n nthread maptype cutoff etreeFile mapFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- number of points in the first direction" "\n n2 -- number of points in the secETree/drivers/permuteETree.c010064400020550007177000000142110653603461200173310ustar00clevecompmath00000400000006/* permuteETree.c */ #include "../ETree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------------------- read in an ETree object. if the ETree is defined on a compressed graph read in an equivalence map IV object. expand the ETree to be defined on the unit weight graph. endif get the old-to-new vertex permutation. permute the vtx-to-front map. created -- 97feb28, cca ----------------------------------------------------------- */ { char *inEqmapIVfileName, *inETreeFileName, *outETreeFileName, *outIVfileName ; double t1, t2 ; int msglvl, rc ; IV *eqmapIV, *vtxOldToNewIV ; ETree *etree, *etree2 ; FILE *msgFile ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile inEqmapFile " "\n outETreeFile outIVfile " "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n inEqmapFile -- input file, must be *.ivf or *.ivb" "\n outETreeFile -- output file, must be *.etreef or *.etreeb" "\n outIVfile -- output file for oldToNew vector," "\n must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; inEqmapIVfileName = argv[4] ; outETreeFileName = argv[5] ; outIVfileName = argv[6] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n inEqmapFile -- %s" "\n outETreeFile -- %s" "\n outIVfile -- %s" "\n", argv[0], msglvl, argv[2], inETreeFileName, inEqmapIVfileName, outETreeFileName, outIVfileName) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } ETree_leftJustify(etree) ; fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } fflush(msgFile) ; if ( strcmp(inEqmapIVfileName, "none") != 0 ) { /* ------------------------------------- read in the equivalence map IV object ------------------------------------- */ eqmapIV = IV_new() ; MARKTIME(t1) ; rc = IV_readFromFile(eqmapIV, inEqmapIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in eqmapIV from file %s", t2 - t1, inEqmapIVfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, eqmapIV, inEqmapIVfileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading IV object from file %s", inEqmapIVfileName) ; if ( msglvl > 2 ) { IV_writeForHumanEye(eqmapIV, msgFile) ; } else { IV_writeStats(eqmapIV, msgFile) ; } fflush(msgFile) ; /* --------------------- expand the front tree --------------------- */ MARKTIME(t1) ; etree2 = ETree_expand(etree, eqmapIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.5f : expand the ETree", t2 - t1) ; fprintf(msgFile, "\n\n expanded ETree") ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree2, msgFile) ; } else { ETree_writeStats(etree2, msgFile) ; } /* ------------------------------------------------ free the old ETree object and the eqmapIV object ------------------------------------------------ */ ETree_free(etree) ; etree = etree2 ; etree2 = NULL ; IV_free(eqmapIV) ; } /* ----------------------------- get the permutation IV object ----------------------------- */ MARKTIME(t1) ; vtxOldToNewIV = ETree_oldToNewVtxPerm(etree) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.5f : get the old-to-new permutation", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n vertex old-to-new IV object") ; IV_writeForHumanEye(vtxOldToNewIV, msgFile) ; } else { fprintf(msgFile, "\n\n vertex old-to-new IV object") ; IV_writeStats(vtxOldToNewIV, msgFile) ; } fflush(msgFile) ; /* ------------------------------------------------ overwrite the ETree object with the new ordering ------------------------------------------------ */ ETree_permuteVertices(etree, vtxOldToNewIV) ; fprintf(msgFile, "\n\n after permuting the vertices") ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } /* ------------------------------------- optionally write out the ETree object ------------------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { MARKTIME(t1) ; rc = ETree_writeToFile(etree, outETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write etree to file %s", t2 - t1, outETreeFileName) ; } /* ---------------------------------- optionally write out the IV object ---------------------------------- */ if ( strcmp(outIVfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(vtxOldToNewIV, outIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write vtxOldToNewIV to file %s", t2 - t1, outIVfileName) ; } /* ---------------- free the objects ---------------- */ ETree_free(etree) ; IV_free(vtxOldToNewIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ETree/drivers/testExpand.c010064400020550007177000000104300657427601300170460ustar00clevecompmath00000400000006/* testExpand.c */ #include "../ETree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------- read in an ETree object and an equivalence map, expand the ETree object and optionally write to a file. created -- 98sep05, cca ------------------------------------------------------- */ { char *inEqmapFileName, *inETreeFileName, *outETreeFileName ; double t1, t2 ; ETree *etree, *etree2 ; FILE *msgFile ; int msglvl, rc ; IV *eqmapIV ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile inEqmapFile outETreeFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n inEqmapFile -- input file, must be *.ivf or *.ivb" "\n outETreeFile -- output file, must be *.etreef or *.etreeb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; inEqmapFileName = argv[4] ; outETreeFileName = argv[5] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n inEqmapFile -- %s" "\n outETreeFile -- %s" "\n", argv[0], msglvl, argv[2], inETreeFileName, inEqmapFileName, outETreeFileName) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } fflush(msgFile) ; /* ------------------------------------- read in the equivalence map IV object ------------------------------------- */ if ( strcmp(inEqmapFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } eqmapIV = IV_new() ; MARKTIME(t1) ; rc = IV_readFromFile(eqmapIV, inEqmapFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in eqmapIV from file %s", t2 - t1, inEqmapFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, eqmapIV, inEqmapFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading IV object from file %s", inEqmapFileName) ; if ( msglvl > 2 ) { IV_writeForHumanEye(eqmapIV, msgFile) ; } else { IV_writeStats(eqmapIV, msgFile) ; } fflush(msgFile) ; /* ----------------------- expand the ETree object ----------------------- */ etree2 = ETree_expand(etree, eqmapIV) ; fprintf(msgFile, "\n\n after expanding the ETree object") ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree2, msgFile) ; } else { ETree_writeStats(etree2, msgFile) ; } fflush(msgFile) ; /* -------------------------- write out the ETree object -------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { MARKTIME(t1) ; rc = ETree_writeToFile(etree2, outETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write etree to file %s", t2 - t1, outETreeFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_writeToFile(%p,%s)", rc, etree2, outETreeFileName) ; } /* --------------------- free the ETree object --------------------- */ ETree_free(etree) ; IV_free(eqmapIV) ; ETree_free(etree2) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ETree/drivers/testFS.c010064400020550007177000000174350665245716300161570ustar00clevecompmath00000400000006/* testFS.c */ #include "../../ETree.h" #include "../../SymbFac.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------- read in an ETree object. compute the heights of the nodes in the tree w.r.t. an out-of-core forward sparse factorization. draw the tree. created -- 99jan07, cca ------------------------------------------------------- */ { char *firstEPSfilename, *inETreeFileName, *secondEPSfilename ; double nfops1, radius, t1, t2 ; double *x, *y ; double bbox[4], bounds[4], frame[4] ; DV *xDV, *yDV ; IV *dmetricIV, *hmetricIV, *vmetricIV ; int bndJ, J, K, labelflag, maxdepth, maxnent, msglvl, nfent1, nfind1, nfront, nleaves1, nnode1, rc ; int *bndwghts, *depths, *heights, *nzfs, *par ; ETree *etree ; FILE *msgFile ; Tree *tree ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile labelflag radius" "\n firstEPSfileName secondEPSfileName" "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n labelflag -- flag to draw labels" "\n radius -- radius of node" "\n firstEPSfilename -- EPS file for subtree working storage" "\n secondEPSfilename -- EPS file for node working storage" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; labelflag = atoi(argv[4]) ; radius = atof(argv[5]) ; firstEPSfilename = argv[6] ; secondEPSfilename = argv[7] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n firstEPSfilename -- %s" "\n labelflag -- %d" "\n radius -- %f" "\n", argv[0], msglvl, argv[2], inETreeFileName, firstEPSfilename, labelflag, radius) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } ETree_leftJustify(etree) ; fprintf(msgFile, "\n\n %d LU entries", ETree_nFactorEntries(etree, 2)) ; fflush(msgFile) ; /* ---------------------- compute the statistics ---------------------- */ tree = etree->tree ; nfront = etree->nfront ; nnode1 = etree->tree->n ; nfind1 = ETree_nFactorIndices(etree) ; nfent1 = ETree_nFactorEntries(etree, 1) ; nfops1 = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; nleaves1 = Tree_nleaves(etree->tree) ; fprintf(msgFile, "\n root front %d has %d vertices", etree->tree->root, etree->nodwghtsIV->vec[etree->tree->root]) ; fprintf(msgFile, "\n %d fronts, %d indices, %d entries, %.0f ops", nfront, nfind1, nfent1, nfops1) ; fprintf(msgFile, "\n max front size = %d", IV_max(ETree_nodwghtsIV(etree))) ; fprintf(msgFile, "\n max boundary size = %d", IV_max(ETree_bndwghtsIV(etree))) ; /* ------------------------------ get the # of entries per front ------------------------------ */ vmetricIV = ETree_factorEntriesIV(etree, SPOOLES_SYMMETRIC) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n entries per front") ; IV_writeForHumanEye(vmetricIV, msgFile) ; fflush(msgFile) ; } maxnent = IV_max(vmetricIV) ; fprintf(msgFile, "\n\n max entries per front = %d", maxnent) ; fflush(msgFile) ; /* -------------------------------- get the simple (x,y) coordinates -------------------------------- */ xDV = DV_new() ; yDV = DV_new() ; rc = Tree_getSimpleCoords(tree, 'H', 'C', xDV, yDV) ; if ( rc != 1 ) { fprintf(stderr, "\n error in %s", "\n return value %d from Tree_getSimpleCoords()\n", argv[0], rc) ; exit(-1) ; } x = DV_entries(xDV) ; y = DV_entries(yDV) ; /* ---------------------- get the height profile ---------------------- */ hmetricIV = Tree_setHeightImetric(tree, vmetricIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n entries height per front") ; IV_writeForHumanEye(hmetricIV, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------------- compute y[J] = heights[J] + |bndJ|*(|bndJ|+1)/2 ----------------------------------------------- */ heights = IV_entries(hmetricIV) ; bndwghts = ETree_bndwghts(etree) ; for ( J = 0 ; J < nfront ; J++ ) { bndJ = bndwghts[J] ; y[J] = heights[J] + (bndJ*(bndJ+1))/2 ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n J x y") ; for ( J = 0 ; J < nfront ; J++ ) { fprintf(msgFile, "\n %5d %12.3f %12.0f", J, x[J], y[J]) ; } } /* ------------------ compute the bounds ------------------ */ bounds[0] = 0.0 ; bounds[1] = 0.0 ; bounds[2] = DV_max(xDV) ; bounds[3] = DV_max(yDV) ; fprintf(stdout, "\n\n bounds = [ %.3g %.3g %.3g %.3g ] ", bounds[0], bounds[1], bounds[2], bounds[3]) ; /* ------------- draw the tree ------------- */ bbox[0] = 50.0 ; bbox[1] = 50.0 ; bbox[2] = 500.0 ; bbox[3] = 500.0 ; frame[0] = bbox[0] + 10 ; frame[1] = bbox[1] + 10 ; frame[2] = bbox[2] - 10 ; frame[3] = bbox[3] - 10 ; rc = Tree_drawToEPS(tree, firstEPSfilename, xDV, yDV, radius, NULL, labelflag, radius, NULL, bbox, frame, bounds) ; if ( rc != 1 ) { fprintf(stderr, "\n error in %s" "\n return value %d from Tree_drawToEPS()\n", argv[0], rc) ; exit(-1) ; } /* --------------------- get the depth profile --------------------- */ dmetricIV = Tree_setDepthImetric(tree, vmetricIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n entries depth per front") ; IV_writeForHumanEye(dmetricIV, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------- compute y[J] = depths[par(J)] + nfent[J] ---------------------------------------- */ par = Tree_par(tree) ; depths = IV_entries(dmetricIV) ; nzfs = IV_entries(vmetricIV) ; for ( J = 0 ; J < nfront ; J++ ) { y[J] = nzfs[J] ; if ( (K = par[J]) != -1 ) { y[J] += depths[K] ; } } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n J x y") ; for ( J = 0 ; J < nfront ; J++ ) { fprintf(msgFile, "\n %5d %12.3f %12.0f", J, x[J], y[J]) ; } } /* ------------- draw the tree ------------- */ bbox[0] = 50.0 ; bbox[1] = 50.0 ; bbox[2] = 500.0 ; bbox[3] = 500.0 ; frame[0] = bbox[0] + 10 ; frame[1] = bbox[1] + 10 ; frame[2] = bbox[2] - 10 ; frame[3] = bbox[3] - 10 ; rc = Tree_drawToEPS(tree, secondEPSfilename, xDV, yDV, radius, NULL, labelflag, radius, NULL, bbox, frame, bounds) ; if ( rc != 1 ) { fprintf(stderr, "\n error in %s" "\n return value %d from Tree_drawToEPSfile()\n", argv[0], rc) ; exit(-1) ; } /* ---------------- free the objects ---------------- */ ETree_free(etree) ; IV_free(vmetricIV) ; IV_free(hmetricIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ nfent1, nfind1, nfront, nleaves1, nnode1, rc ; int *bndwghts, *depths, *heights, *nzfs, *par ; ETree *etree ; FILE *msgFile ; Tree *tree ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglETree/drivers/testHeight.c010064400020550007177000000115070664520635500170460ustar00clevecompmath00000400000006/* testHeight.c */ #include "../../ETree.h" #include "../../SymbFac.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------- read in an ETree object. compute the height of the tree w.r.t. an out-of-core forward sparse factorization created -- 99jan07, cca ------------------------------------------------------- */ { char *inETreeFileName ; double nfops1, t1, t2 ; IV *dmetricIV, *vmetricIV ; int maxdepth, maxnent, msglvl, nfent1, nfind1, nfront, nleaves1, nnode1, rc ; ETree *etree ; FILE *msgFile ; Tree *tree ; if ( argc != 4 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n", argv[0], msglvl, argv[2], inETreeFileName) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } ETree_leftJustify(etree) ; fprintf(msgFile, "\n\n %d LU entries", ETree_nFactorEntries(etree, 2)) ; fflush(msgFile) ; /* ---------------------- compute the statistics ---------------------- */ tree = etree->tree ; nfront = etree->nfront ; nnode1 = etree->tree->n ; nfind1 = ETree_nFactorIndices(etree) ; nfent1 = ETree_nFactorEntries(etree, 1) ; nfops1 = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; nleaves1 = Tree_nleaves(etree->tree) ; fprintf(msgFile, "\n root front %d has %d vertices", etree->tree->root, etree->nodwghtsIV->vec[etree->tree->root]) ; fprintf(msgFile, "\n %d fronts, %d indices, %d entries, %.0f ops", nfront, nfind1, nfent1, nfops1) ; fprintf(msgFile, "\n max front size = %d", IV_max(ETree_nodwghtsIV(etree))) ; fprintf(msgFile, "\n max boundary size = %d", IV_max(ETree_bndwghtsIV(etree))) ; /* ------------------------------ get the # of entries per front ------------------------------ */ vmetricIV = ETree_factorEntriesIV(etree, SPOOLES_SYMMETRIC) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n entries per front") ; IV_writeForHumanEye(vmetricIV, msgFile) ; fflush(msgFile) ; } maxnent = IV_max(vmetricIV) ; fprintf(msgFile, "\n\n max entries per front = %d", maxnent) ; fflush(msgFile) ; /* ---------------------- get the height profile ---------------------- */ dmetricIV = Tree_setDepthImetric(tree, vmetricIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n entries depth per front") ; IV_writeForHumanEye(dmetricIV, msgFile) ; fflush(msgFile) ; } maxdepth = IV_max(dmetricIV) ; fprintf(msgFile, "\n\n max depth = %d, fraction of total = %8.3f", maxdepth, ((double) maxdepth)/nfent1) ; fflush(msgFile) ; fprintf(msgFile, "\n\n STATS : %12d %12d %12d %8.3f %8.3f", nfent1, maxnent, maxdepth, ((double) maxdepth)/maxnent, ((double) maxdepth)/nfent1) ; { int J ; int *depth = IV_entries(dmetricIV) ; int *par = Tree_par(tree) ; int *fch = Tree_fch(tree) ; int *sib = Tree_sib(tree) ; int *nodwghts = ETree_nodwghts(etree) ; int *bndwghts = ETree_bndwghts(etree) ; fprintf(msgFile, "\n\n J par fch sib |J| |bndJ| depth/maxdepth") ; for ( J = 0 ; J < nfront ; J++ ) { fprintf(msgFile, "\n %7d %7d %7d %7d %7d %7d %8.3f", J, par[J], fch[J], sib[J], nodwghts[J], bndwghts[J], ((double) depth[J])/maxdepth) ; } } /* ---------------- free the objects ---------------- */ ETree_free(etree) ; IV_free(vmetricIV) ; IV_free(dmetricIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ETree/drivers/testIO.c010064400020550007177000000060120663207450700161360ustar00clevecompmath00000400000006/* testIO.c */ #include "../ETree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- test ETree_readFromFile and ETree_writeToFile, useful for translating between formatted *.etreef and binary *.etreeb files. created -- 96may02, cca ------------------------------------------------- */ { char *inETreeFileName, *outETreeFileName ; double t1, t2 ; int msglvl, rc ; ETree *etree ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.etreef or *.etreeb" "\n outFile -- output file, must be *.etreef or *.etreeb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; outETreeFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inETreeFileName, outETreeFileName) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } fflush(msgFile) ; { IV *oldToNewIV = ETree_oldToNewVtxPerm(etree) ; IV_writeForHumanEye(oldToNewIV, msgFile) ; } /* -------------------------- write out the ETree object -------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { MARKTIME(t1) ; rc = ETree_writeToFile(etree, outETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write etree to file %s", t2 - t1, outETreeFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_writeToFile(%p,%s)", rc, etree, outETreeFileName) ; } /* --------------------- free the ETree object --------------------- */ ETree_free(etree) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ .c */ #include "../ETree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- test ETree_readFromFile and ETree_writeToFile, useful for translating between formatted *.etreef and binary *.etreeb files. created -- 96may02, cca ------------------------------------------------- */ { char *inETreeFileName, *outETreeFileName ; double t1, ETree/drivers/testMS.c010064400020550007177000000144410653605166100161520ustar00clevecompmath00000400000006/* testMS.c */ #include "../ETree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------- generate multisectors created -- 96oct31, cca ----------------------- */ { char *inETreeFileName, *outIVfileName ; double cutoff, domops, totops, t1, t2 ; double *opsreg ; DV *opsDV ; int domnzf, domnvtx, flag, depth, ireg, msglvl, nreg, rc, totnvtx, totnzf ; int *nvtxreg, *nzfreg ; IV *msIV, *nvtxIV, *nzfIV ; ETree *etree ; FILE *msgFile ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile outIVfile flag cutoff" "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n outIVfile -- output file, must be *.ivf or *.ivb" "\n flag -- type of multisector" "\n flag = 1 --> multisector via depth of front" "\n flag = 2 --> multisector via # of vertices in subtree" "\n flag = 3 --> multisector via # of entries in subtree" "\n flag = 4 --> multisector via # of operations in subtree" "\n cutoff -- cutoff point for multisector" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; outIVfileName = argv[4] ; flag = atoi(argv[5]) ; if ( flag == 1 ) { depth = atoi(argv[6]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n outIVfile -- %s" "\n flag -- %d" "\n depth -- %d" "\n", argv[0], msglvl, argv[2], inETreeFileName, outIVfileName, flag, depth) ; fflush(msgFile) ; } else if ( 2 <= flag && flag <= 4 ) { cutoff = atof(argv[6]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n outIVfile -- %s" "\n flag -- %d" "\n cutoff -- %f" "\n", argv[0], msglvl, argv[2], inETreeFileName, outIVfileName, flag, cutoff) ; fflush(msgFile) ; } /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } fflush(msgFile) ; /* -------------------- make the multisector -------------------- */ switch ( flag ) { case 1 : msIV = ETree_msByDepth(etree, depth) ; break ; case 2 : msIV = ETree_msByNvtxCutoff(etree, cutoff) ; break ; case 3 : msIV = ETree_msByNentCutoff(etree, cutoff, SPOOLES_SYMMETRIC) ; break ; case 4 : msIV = ETree_msByNopsCutoff(etree, cutoff, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; break ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n msIV") ; IV_writeForHumanEye(msIV, msgFile) ; } /* ----------------------- generate the statistics ----------------------- */ nvtxIV = IV_new() ; nzfIV = IV_new() ; opsDV = DV_new() ; ETree_msStats(etree, msIV, nvtxIV, nzfIV, opsDV, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; nreg = IV_size(nvtxIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n msIV") ; IV_writeForHumanEye(msIV, msgFile) ; } nvtxreg = IV_entries(nvtxIV) ; nzfreg = IV_entries(nzfIV) ; opsreg = DV_entries(opsDV) ; domnvtx = IVsum(nreg-1, nvtxreg+1) ; domnzf = IVsum(nreg-1, nzfreg+1) ; domops = DVsum(nreg-1, opsreg+1) ; fprintf(msgFile, "\n region vertices entries operations metric/(avg domain)") ; for ( ireg = 0 ; ireg < nreg ; ireg++ ) { fprintf(msgFile, "\n %5d %10d %10d %12.0f %6.3f %6.3f %6.3f", ireg, nvtxreg[ireg], nzfreg[ireg], opsreg[ireg], ((double) nvtxreg[ireg]*(nreg-1))/domnvtx, ((double) nzfreg[ireg]*(nreg-1))/domnzf, opsreg[ireg]*(nreg-1)/domops) ; } totnvtx = IV_sum(nvtxIV) ; totnzf = IV_sum(nzfIV) ; totops = DV_sum(opsDV) ; fprintf(msgFile, "\n\n nvtx %% nzf %% ops %%" "\n domains %6d %5.2f %9d %5.2f %12.0f %5.3f" "\n schur complement %6d %5.2f %9d %5.2f %12.0f %5.3f" "\n total %6d %9d %12.0f ", domnvtx, (100.*domnvtx)/totnvtx, domnzf, (100.*domnzf)/totnzf, domops, (100.*domops)/totops, totnvtx - domnvtx, (100.*(totnvtx - domnvtx))/totnvtx, totnzf - domnzf, (100.*(totnzf - domnzf))/totnzf, totops - domops, (100.*(totops - domops))/totops, totnvtx, totnzf, totops) ; fprintf(msgFile, "\n\n FrontETree : %d entries, %.0f ops", ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC), ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; /* ----------------------- write out the IV object ----------------------- */ if ( strcmp(outIVfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(msIV, outIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write msIV to file %s", t2 - t1, outIVfileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_writeToFile(%p,%s)", rc, msIV, outIVfileName) ; } /* ---------------- free the objects ---------------- */ ETree_free(etree) ; IV_free(msIV) ; IV_free(nvtxIV) ; IV_free(nzfIV) ; DV_free(opsDV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ETree/drivers/testMaps.c010064400020550007177000000123170653605302100165230ustar00clevecompmath00000400000006/* testMaps.c */ #include "../ETree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------- test the map routines created -- 97jan15, cca ----------------------- */ { char *inETreeFileName, *outIVfileName ; double cutoff, t1, t2 ; DV *cumopsDV ; int msglvl, nthread, rc, type ; IV *ownersIV ; ETree *etree ; FILE *msgFile ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile outIVfile " "\n nthread type cutoff" "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n outIVfile -- output file, must be *.ivf or *.ivb" "\n nthread -- number of threads" "\n type -- type of map" "\n 1 -- wrap map" "\n 2 -- balanced map via a post-order traversal" "\n 3 -- subtree-subset map" "\n 4 -- old domain decomposition map" "\n 5 -- new domain decomposition map" "\n cutoff -- cutoff used for the domain decomposition map" "\n 0 <= cutoff <= 1 used to define the multisector" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; outIVfileName = argv[4] ; nthread = atoi(argv[5]) ; type = atoi(argv[6]) ; cutoff = atof(argv[7]) ; if ( type < 1 || type > 5 ) { fprintf(stderr, "\n fatal error in %s" "\n type = %d, must be 1, 2 or 3", argv[0], type) ; exit(-1) ; } fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n outIVfile -- %s" "\n nthread -- %d" "\n type -- %d" "\n cutoff -- %f" "\n", argv[0], msglvl, argv[2], inETreeFileName, outIVfileName, nthread, type, cutoff) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } fflush(msgFile) ; /* -------------------------------------------------- initialize the cumulative operations metric object -------------------------------------------------- */ cumopsDV = DV_new() ; DV_init(cumopsDV, nthread, NULL) ; DV_fill(cumopsDV, 0.0) ; /* ------------------------------- create the owners map IV object ------------------------------- */ switch ( type ) { case 1 : ownersIV = ETree_wrapMap(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC, cumopsDV) ; break ; case 2 : ownersIV = ETree_balancedMap(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC, cumopsDV) ; break ; case 3 : ownersIV = ETree_subtreeSubsetMap(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC, cumopsDV) ; break ; case 4 : ownersIV = ETree_ddMap(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC, cumopsDV, cutoff) ; break ; case 5 : { IV *msIV ; /* msIV = ETree_msByNopsCutoff(etree, cutoff, 1) ; */ msIV = ETree_msByNvtxCutoff(etree, cutoff) ; ownersIV = ETree_ddMapNew(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC, msIV, cumopsDV) ; IV_free(msIV) ; } break ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n totalOps = %.0f", DV_sum(cumopsDV)) ; DVscale(DV_size(cumopsDV), DV_entries(cumopsDV), nthread/DV_sum(cumopsDV)) ; fprintf(msgFile, "\n\n cumopsDV") ; DV_writeForHumanEye(cumopsDV, msgFile) ; fprintf(msgFile, "\n\n ownersIV") ; IV_writeForHumanEye(ownersIV, msgFile) ; fflush(msgFile) ; } /* -------------------------- write out the IV object -------------------------- */ if ( strcmp(outIVfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(ownersIV, outIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write ownersIV to file %s", t2 - t1, outIVfileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_writeToFile(%p,%s)", rc, ownersIV, outIVfileName) ; } /* ---------------- free the objects ---------------- */ ETree_free(etree) ; DV_free(cumopsDV) ; IV_free(ownersIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ETree/drivers/testStats.c010064400020550007177000000230270665340643700167360ustar00clevecompmath00000400000006/* testStats.c */ #include "../../SymbFac.h" #include "../../ETree.h" #include "../../InpMtx.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------- (1) read in an ETree object. (2) read in a Graph object. (3) draw a tree picture of the distribution of some metric across the fronts created -- 99jan22, cca ------------------------------------------- */ { char coordflag, heightflag ; char *inETreeFileName, *inGraphFileName, *outEPSfileName ; double fontscale, rmax, rscale, t1, t2 ; double bbox[4], frame[4] ; double *radius ; DV *radiusDV, *xDV, *yDV ; Graph *graph ; int J, labelflag, metricType, msglvl, nfront, nvtx, rc ; int *metric, *vwghts ; IV *metricIV ; ETree *etree ; FILE *msgFile ; Tree *tree ; if ( argc != 12 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile inGraphFile outEPSfile " "\n metricType heightflag coordflag rscale labelflag fontscale" "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n outEPSfile -- output file for tree picture, must be *.eps" "\n metricType -- metric type" "\n 0 -- no metric" "\n 1 -- # of nodes in front" "\n 2 -- # of original matrix entries in front" "\n 3 -- # of factor matrix entries in front" "\n 4 -- # of forward factor ops in front" "\n 5 -- # of backward factor ops in front" "\n heightflag -- flag for type of height" "\n 'D' -- nodes placed by depth in tree" "\n 'H' -- nodes placed by height in tree" "\n coordflag -- flag for type of coordinate" "\n 'C' -- cartesian (x,y) placement" "\n 'P' -- polar (r,theta) placement" "\n rmax -- maximum radius in pts" "\n labelflag -- flag for type of labels" "\n 1 -- draw labels" "\n otherwise -- do not draw labels" "\n fontscale -- scaling parameter for fonts when labels drawed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; inGraphFileName = argv[4] ; outEPSfileName = argv[5] ; metricType = atoi(argv[6]) ; heightflag = *argv[7] ; coordflag = *argv[8] ; rmax = atof(argv[9]) ; labelflag = atoi(argv[10]) ; fontscale = atof(argv[11]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n inGraphFile -- %s" "\n outEPSfile -- %s" "\n metricType -- %d" "\n heightflag -- %c" "\n coordflag -- %c" "\n rmax -- %f" "\n labelflag -- %d" "\n fontscale -- %f" "\n", argv[0], msglvl, argv[2], inETreeFileName, inGraphFileName, outEPSfileName, metricType, heightflag, coordflag, rmax, labelflag, fontscale) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } ETree_leftJustify(etree) ; fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } fflush(msgFile) ; nfront = ETree_nfront(etree) ; tree = ETree_tree(etree) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; nvtx = graph->nvtx ; vwghts = graph->vwghts ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* ---------------------- compute the statistics ---------------------- */ metricIV = IV_new() ; IV_init(metricIV, nfront, NULL) ; metric = IV_entries(metricIV) ; switch ( metricType ) { case 0 : { /* --------- no metric --------- */ IVfill(nfront, metric, 1) ; } break ; case 1 : { /* ----------- front sizes ----------- */ IVcopy(nfront, metric, ETree_nodwghts(etree)) ; } break ; case 2 : { /* ---------------------------------------------- number of original matrix entries in the front ---------------------------------------------- */ int I, ii, J, v, vsize, w ; int *vadj, *vtxToFront ; vtxToFront = ETree_vtxToFront(etree) ; for ( v = 0 ; v < nvtx ; v++ ) { I = vtxToFront[v] ; Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; J = vtxToFront[w] ; if ( I <= J ) { if ( vwghts == NULL ) { metric[I]++ ; } else { metric[I] += vwghts[v]*vwghts[w] ; } } else { if ( vwghts == NULL ) { metric[J]++ ; } else { metric[J] += vwghts[v]*vwghts[w] ; } } } } } break ; case 3 : { /* -------------------------------------------- number of factor matrix entries in the front -------------------------------------------- */ int *nzf ; IV *nzfIV ; nzfIV = ETree_factorEntriesIV(etree, SPOOLES_SYMMETRIC) ; nzf = IV_entries(nzfIV) ; for ( J = 0 ; J < nfront ; J++ ) { metric[J] = nzf[J] ; } IV_free(nzfIV) ; } break ; case 4 : { /* ------------------------------------------------ number of forward factor operations in the front ------------------------------------------------ */ double *ops ; DV *opsDV ; opsDV = ETree_forwardOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; ops = DV_entries(opsDV) ; for ( J = 0 ; J < nfront ; J++ ) { metric[J] = ops[J] ; } DV_free(opsDV) ; } break ; case 5 : { /* ------------------------------------------------- number of backward factor operations in the front ------------------------------------------------- */ double *ops ; DV *opsDV ; IVL *symbfacIVL ; symbfacIVL = SymbFac_initFromGraph(etree, graph) ; opsDV = ETree_backwardOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC, graph->vwghts, symbfacIVL) ; ops = DV_entries(opsDV) ; for ( J = 0 ; J < nfront ; J++ ) { metric[J] = ops[J] ; } DV_free(opsDV) ; IVL_free(symbfacIVL) ; } break ; default : fprintf(stderr, "\n error in testStats" "\n metricType %d not supported", metricType) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n metric vector") ; IV_writeForHumanEye(metricIV, msgFile) ; fflush(msgFile) ; } /* --------------------- set the radius vector --------------------- */ radiusDV = DV_new() ; DV_init(radiusDV, nfront, NULL) ; radius = DV_entries(radiusDV) ; for ( J = 0 ; J < nfront ; J++ ) { radius[J] = sqrt(0.318309886*metric[J]) ; } rscale = rmax / DVmax(nfront, radius, &J) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n radius vector") ; DV_writeForHumanEye(radiusDV, msgFile) ; fflush(msgFile) ; } /* ------------------------ get the tree coordinates ------------------------ */ xDV = DV_new() ; yDV = DV_new() ; rc = Tree_getSimpleCoords(tree, heightflag, coordflag, xDV, yDV) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from Tree_getSimpleCoords()",rc); exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n x-coordinates") ; DV_writeForHumanEye(xDV, msgFile) ; fprintf(msgFile, "\n\n y-coordinates") ; DV_writeForHumanEye(yDV, msgFile) ; fprintf(msgFile, "\n\n radius") ; DV_writeForHumanEye(radiusDV, msgFile) ; fflush(msgFile) ; } /* ------------- draw the tree ------------- */ bbox[0] = 50 ; bbox[1] = 50 ; bbox[2] = 550 ; bbox[3] = 550 ; frame[0] = 60 ; frame[1] = 60 ; frame[2] = 540 ; frame[3] = 540 ; rc = Tree_drawToEPS(tree, outEPSfileName, xDV, yDV, rscale, radiusDV, labelflag, fontscale, NULL, bbox, frame, NULL) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from Tree_drawToEPSfile()", rc) ; exit(-1) ; } /* ---------------- free the objects ---------------- */ ETree_free(etree) ; Graph_free(graph) ; IV_free(metricIV) ; DV_free(radiusDV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ee = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } ETree_leftJustify(etree) ; fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETrETree/drivers/testStorage.c010064400020550007177000000204440664346325400172430ustar00clevecompmath00000400000006/* testStorage.c */ #include "../../ETree.h" #include "../../SymbFac.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------------------- read in an ETree object. read in a Graph object. get the symbolic factorization IVL object. compute the storage profiles for the general sparse, forward sparse and multifrontal methods. created -- 96oct03, cca ---------------------------------------------------- */ { char *inETreeFileName, *inGraphFileName ; double elapsed, nfops1, t1, t2 ; double *FSvec, *GSvec, *MFvec, *backwardops, *forwardops, *vmetric ; DV *vmetricDV ; Graph *graph ; int J, msglvl, nfent1, nfind1, nfront, nleaves1, nnode1, rc ; IVL *symbfacIVL ; ETree *etree ; FILE *msgFile ; Tree *tree ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile inGraphFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; inGraphFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n inGraphFile -- %s" "\n", argv[0], msglvl, argv[2], inETreeFileName, inGraphFileName) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } ETree_leftJustify(etree) ; fprintf(msgFile, "\n\n %d LU entries", ETree_nFactorEntries(etree, 2)) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* ---------------------- compute the statistics ---------------------- */ tree = etree->tree ; nfront = etree->nfront ; nnode1 = etree->tree->n ; nfind1 = ETree_nFactorIndices(etree) ; nfent1 = ETree_nFactorEntries(etree, 1) ; nfops1 = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; nleaves1 = Tree_nleaves(etree->tree) ; fprintf(msgFile, "\n root front %d has %d vertices", etree->tree->root, etree->nodwghtsIV->vec[etree->tree->root]) ; fprintf(msgFile, "\n %d fronts, %d indices, %d entries, %.0f ops", nfront, nfind1, nfent1, nfops1) ; /* -------------------------------------------- create the symbolic factorization IVL object -------------------------------------------- */ symbfacIVL = SymbFac_initFromGraph(etree, graph) ; fprintf(msgFile, "\n\n symbolic factorization IVL object in old ordering") ; if ( msglvl > 2 ) { IVL_writeForHumanEye(symbfacIVL, msgFile) ; } else { IVL_writeStats(symbfacIVL, msgFile) ; } fflush(msgFile) ; /* -------------------------- get the operations profile -------------------------- */ vmetricDV = ETree_backwardOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC, graph->vwghts, symbfacIVL) ; vmetric = DV_entries(vmetricDV) ; backwardops = DVinit(nfront, 0.0) ; elapsed = 0.0 ; for ( J = Tree_postOTfirst(etree->tree) ; J != -1 ; J = Tree_postOTnext(etree->tree, J) ) { elapsed += vmetric[J] ; backwardops[J] = elapsed ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n sum of backward ops = %.0f", DV_sum(vmetricDV)) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n backward ops") ; DVfprintf(msgFile, nfront, backwardops) ; } DV_free(vmetricDV) ; vmetricDV = ETree_forwardOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; vmetric = DV_entries(vmetricDV) ; forwardops = DVinit(nfront, 0.0) ; elapsed = 0.0 ; for ( J = Tree_postOTfirst(etree->tree) ; J != -1 ; J = Tree_postOTnext(etree->tree, J) ) { elapsed += vmetric[J] ; forwardops[J] = elapsed ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n sum of forward ops = %.0f", DV_sum(vmetricDV)) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n forward ops") ; DVfprintf(msgFile, nfront, forwardops) ; } DV_free(vmetricDV) ; /* -------------------------------------- get the general sparse storage profile -------------------------------------- */ GSvec = DVinit(nfront, 0.0) ; ETree_GSstorageProfile(etree, SPOOLES_SYMMETRIC, symbfacIVL, graph->vwghts, GSvec) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n GSvec storage") ; DVfprintf(msgFile, nfront, GSvec) ; } /* -------------------------------------- get the forward sparse storage profile -------------------------------------- */ FSvec = DVinit(nfront, 0.0) ; ETree_FSstorageProfile(etree, SPOOLES_SYMMETRIC, symbfacIVL, FSvec) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n FSvec storage") ; DVfprintf(msgFile, nfront, FSvec) ; } /* ------------------------------------ get the multifrontal storage profile ------------------------------------ */ MFvec = DVinit(nfront, 0.0) ; ETree_MFstackProfile(etree, SPOOLES_SYMMETRIC, MFvec) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n MFvec storage") ; DVfprintf(msgFile, nfront, MFvec) ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n %% five columns of data" "\n %% backward-ops GS-storage forward-ops FS-storage MF-storage") ; fprintf(msgFile, "\n data = [ ...") ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { /* fprintf(msgFile, "\n %12.0f %12.0f %12.0f %12.0f %12.0f", backwardops[J], FSvec[J], forwardops[J], MGSvec[J], Fvec[J]) ; */ fprintf(msgFile, "\n %12.0f %12.4e %12.0f, %12.4e %12.4e", backwardops[J], GSvec[J]/nfent1, forwardops[J], FSvec[J]/nfent1, MFvec[J]/nfent1) ; } fprintf(msgFile, " ] ;" "\n bops = data(:,1) ;" "\n gs = data(:,2) ;" "\n fops = data(:,3) ;" "\n fs = data(:,4) ;" "\n mf = data(:,5) ;" "\n\n plot( bops, gs, '-o', fops, fs, '-v', fops, mf, '-s') ; " "\n xmax = max(bops) ;" "\n ymax = max( [ max(gs) max(fs) max(mf) ] ) ;" "\n axis([0, xmax, 0, ymax]) ;" "\n xlabel(' elapsed operations') ;" "\n ylabel(' fraction of total factor storage') ;" "\n title(' workspace profile, ""x"" GS, ""o"" FS, ""*"" MF') ;" "\n text( 0.1*xmax, 0.9*ymax, 'circle -- general sparse') ;" "\n text( 0.1*xmax, 0.8*ymax, 'triangle -- forward sparse') ;" "\n text( 0.1*xmax, 0.7*ymax, 'square -- multifrontal') ;" ) ; } /* ---------------- free the objects ---------------- */ ETree_free(etree) ; Graph_free(graph) ; IVL_free(symbfacIVL) ; DVfree(GSvec) ; DVfree(MFvec) ; DVfree(forwardops) ; DVfree(backwardops) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(-1) ; } /*--------------------------------------------------------------------*/ = 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graphETree/drivers/testTransform.c010064400020550007177000000275240663302756100176140ustar00clevecompmath00000400000006/* testTransform.c */ #include "../../ETree.h" #include "../../SymbFac.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------- read in an ETree object and testTransform it by 1 -- merge only children if possible 2 -- merge all children if possible 3 -- split large non-leaf fronts created -- 96jun27, cca ------------------------------------------------------- */ { char *inETreeFileName, *inGraphFileName, *outETreeFileName ; double cpus[6], ops[6], t1, t2 ; ETree *etree0, *etree1, *etree2, *etree3, *etree4, *etree5 ; FILE *msgFile ; Graph *graph ; int maxsize, maxzeros, msglvl, rc, seed ; int nfronts[7], nfind[7], nzf[7] ; IV *nzerosIV ; IVL *symbfacIVL ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile inGraphFile outETreeFile " "\n maxzeros maxsize seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n outETreeFile -- output file, must be *.etreef or *.etreeb" "\n maxzeros -- maximum number of zeros in a front" "\n maxsize -- maximum number of vertices in a front" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; inGraphFileName = argv[4] ; outETreeFileName = argv[5] ; maxzeros = atoi(argv[6]) ; maxsize = atoi(argv[7]) ; seed = atoi(argv[8]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n inGraphFile -- %s" "\n outETreeFile -- %s" "\n maxzeros -- %d" "\n maxsize -- %d" "\n seed -- %d" "\n", argv[0], msglvl, argv[2], inETreeFileName, inGraphFileName, outETreeFileName, maxzeros, maxsize, seed) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree0 = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree0, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree0, inETreeFileName) ; exit(-1) ; } nfronts[0] = ETree_nfront(etree0) ; nfind[0] = ETree_nFactorIndices(etree0) ; nzf[0] = ETree_nFactorEntries(etree0, SPOOLES_SYMMETRIC) ; ops[0] = ETree_nFactorOps(etree0, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n\n original : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[0], nfind[0], nzf[0], ops[0]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n original front tree ") ; ETree_writeForHumanEye(etree0, msgFile) ; fflush(msgFile) ; } fflush(msgFile) ; /* ---------------------------------- get the fundamental supernode tree ---------------------------------- */ nzerosIV = IV_new() ; IV_init(nzerosIV, nfronts[0], NULL) ; IV_fill(nzerosIV, 0) ; MARKTIME(t1) ; etree1 = ETree_mergeFrontsOne(etree0, 0, nzerosIV) ; MARKTIME(t2) ; cpus[1] = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : get fundamental supernode tree", t2 - t1) ; nfronts[1] = ETree_nfront(etree1) ; nfind[1] = ETree_nFactorIndices(etree1) ; nzf[1] = ETree_nFactorEntries(etree1, SPOOLES_SYMMETRIC) ; ops[1] = ETree_nFactorOps(etree1, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n merge one : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[1], nfind[1], nzf[1], ops[1]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after first merge") ; ETree_writeForHumanEye(etree1, msgFile) ; } fprintf(msgFile, "\n IV_sum(nzerosIV) = %d, IV_max(nzerosIV) = %d", IV_sum(nzerosIV), IV_max(nzerosIV)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n nzerosIV") ; IV_writeForHumanEye(nzerosIV, msgFile) ; fflush(msgFile) ; } ETree_writeToFile(etree1, "/local1/cleve/ARPA/matrices/R3D13824/nd1.etreef") ; /* --------------------------- try to absorb only children --------------------------- */ MARKTIME(t1) ; etree2 = ETree_mergeFrontsOne(etree1, maxzeros, nzerosIV) ; MARKTIME(t2) ; cpus[2] = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : merge only single child", t2 - t1) ; nfronts[2] = ETree_nfront(etree2) ; nfind[2] = ETree_nFactorIndices(etree2) ; nzf[2] = ETree_nFactorEntries(etree2, SPOOLES_SYMMETRIC) ; ops[2] = ETree_nFactorOps(etree2, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n merge one : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[2], nfind[2], nzf[2], ops[2]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after first merge") ; ETree_writeForHumanEye(etree2, msgFile) ; } fprintf(msgFile, "\n IV_sum(nzerosIV) = %d, IV_max(nzerosIV) = %d", IV_sum(nzerosIV), IV_max(nzerosIV)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n nzerosIV") ; IV_writeForHumanEye(nzerosIV, msgFile) ; fflush(msgFile) ; } ETree_writeToFile(etree2, "/local1/cleve/ARPA/matrices/R3D13824/nd2.etreef") ; /* -------------------------- try to absorb all children -------------------------- */ MARKTIME(t1) ; etree3 = ETree_mergeFrontsAll(etree2, maxzeros, nzerosIV) ; MARKTIME(t2) ; cpus[3] = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : merge all children", t2 - t1) ; nfronts[3] = ETree_nfront(etree3) ; nfind[3] = ETree_nFactorIndices(etree3) ; nzf[3] = ETree_nFactorEntries(etree3, SPOOLES_SYMMETRIC) ; ops[3] = ETree_nFactorOps(etree3, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n merge all : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[3], nfind[3], nzf[3], ops[3]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after second merge") ; ETree_writeForHumanEye(etree2, msgFile) ; } fprintf(msgFile, "\n IV_sum(nzerosIV) = %d, IV_max(nzerosIV) = %d", IV_sum(nzerosIV), IV_max(nzerosIV)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n nzerosIV") ; IV_writeForHumanEye(nzerosIV, msgFile) ; fflush(msgFile) ; } ETree_writeToFile(etree3, "/local1/cleve/ARPA/matrices/R3D13824/nd3.etreef") ; /* -------------------------- try to absorb any children -------------------------- */ MARKTIME(t1) ; etree4 = ETree_mergeFrontsAny(etree3, maxzeros, nzerosIV) ; MARKTIME(t2) ; cpus[4] = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : merge any child", t2 - t1) ; nfronts[4] = ETree_nfront(etree4) ; nfind[4] = ETree_nFactorIndices(etree4) ; nzf[4] = ETree_nFactorEntries(etree4, SPOOLES_SYMMETRIC) ; ops[4] = ETree_nFactorOps(etree4, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n merge any : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[4], nfind[4], nzf[4], ops[4]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after second merge") ; ETree_writeForHumanEye(etree4, msgFile) ; } fprintf(msgFile, "\n IV_sum(nzerosIV) = %d, IV_max(nzerosIV) = %d", IV_sum(nzerosIV), IV_max(nzerosIV)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n nzerosIV") ; IV_writeForHumanEye(nzerosIV, msgFile) ; fflush(msgFile) ; } ETree_writeToFile(etree4, "/local1/cleve/ARPA/matrices/R3D13824/nd4.etreef") ; /* -------------------- split the front tree -------------------- */ MARKTIME(t1) ; etree5 = ETree_splitFronts(etree4, graph->vwghts, maxsize, 0) ; MARKTIME(t2) ; cpus[5] = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : split fronts", t2 - t1) ; nfronts[5] = ETree_nfront(etree5) ; nfind[5] = ETree_nFactorIndices(etree5) ; nzf[5] = ETree_nFactorEntries(etree5, SPOOLES_SYMMETRIC) ; ops[5] = ETree_nFactorOps(etree5, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n split : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[5], nfind[5], nzf[5], ops[5]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree after split") ; ETree_writeForHumanEye(etree5, msgFile) ; } /* ---------------------------------------- create the symbolic factorization object ---------------------------------------- */ MARKTIME(t1) ; symbfacIVL = SymbFac_initFromGraph(etree5, graph) ; MARKTIME(t2) ; cpus[6] = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : symbolic factorization", t2 - t1) ; nfronts[6] = ETree_nfront(etree5) ; nfind[6] = ETree_nFactorIndices(etree5) ; nzf[6] = ETree_nFactorEntries(etree5, SPOOLES_SYMMETRIC) ; ops[6] = ETree_nFactorOps(etree5, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; fprintf(msgFile, "\n final : %8d fronts, %8d indices, %8d |L|, %12.0f ops", nfronts[6], nfind[6], nzf[6], ops[6]) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after symbolic factorization") ; ETree_writeForHumanEye(etree5, msgFile) ; fprintf(msgFile, "\n\n after symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; } fprintf(msgFile, "\n\n" "\n CPU #fronts #indices #entries #ops" "\n original : %8d %8d %8d %12.0f " "\n fs tree : %8.3f %8d %8d %8d %12.0f " "\n merge one : %8.3f %8d %8d %8d %12.0f " "\n merge all : %8.3f %8d %8d %8d %12.0f " "\n merge any : %8.3f %8d %8d %8d %12.0f " "\n split : %8.3f %8d %8d %8d %12.0f " "\n final : %8.3f %8d %8d %8d %12.0f ", nfronts[0], nfind[0], nzf[0], ops[0], cpus[1], nfronts[1], nfind[1], nzf[1], ops[1], cpus[2], nfronts[2], nfind[2], nzf[2], ops[2], cpus[3], nfronts[3], nfind[3], nzf[3], ops[3], cpus[4], nfronts[4], nfind[4], nzf[4], ops[4], cpus[5], nfronts[5], nfind[5], nzf[5], ops[5], cpus[6], nfronts[6], nfind[6], nzf[6], ops[6]) ; ETree_writeToFile(etree5, "/local1/cleve/ARPA/matrices/R3D13824/nd5.etreef") ; /* -------------------------- write out the ETree object -------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { MARKTIME(t1) ; rc = ETree_writeToFile(etree5, outETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write etree to file %s", t2 - t1, outETreeFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_writeToFile(%p,%s)", rc, etree5, outETreeFileName) ; } /* ---------------------- free the ETree objects ---------------------- */ /* ETree_free(etree0) ; ETree_free(etree1) ; ETree_free(etree2) ; ETree_free(etree3) ; ETree_free(etree4) ; ETree_free(etree5) ; */ Graph_free(graph) ; IVL_free(symbfacIVL) ; IV_free(nzerosIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ RPA/matrices/R3D13824/nd1.etreef") ; /* --------------------------- try to absorb only children --------------------------- */ MARKTIME(t1) ; etree2 = ETree_mergeFETree/doc/004275500020550007177000000000000665315072500136605ustar00clevecompmath00000400000006ETree/doc/dataStructure.tex010064000020550007177000000015140653410607500172210ustar00clevecompmath00000400000006\par \section{Data Structure} \par The {\tt ETree} object has six fields. \begin{itemize} \item {\tt int nfront} : number of fronts in the tree \item {\tt int nvtx} : number of vertices in the tree \item {\tt Tree *tree} : pointer to a {\tt Tree} structure \item {\tt IV *nodwghtsIV} : pointer to an {\tt IV} object to hold front weights, size {\tt nfront} \item {\tt IV *bndwghtsIV} : pointer to an {\tt IV} object to hold the weights of the fronts' boundaries, size {\tt nfront} \item {\tt IV *vtxToFrontIV} : pointer to an {\tt IV} object to hold the map from vertices to fronts, size {\tt nfront} \end{itemize} A correctly initialized and nontrivial {\tt ETree} object will have positive {\tt nfront} and {\tt nvtx} values, a valid {\tt tree} field and non-{\tt NULL} {\tt nodwghtsIV}, {\tt bndwghtsIV} and {\tt vtxToFrontIV} pointers. ETree/doc/intro.tex010064000020550007177000000027710653410607500155300ustar00clevecompmath00000400000006\chapter{{\tt ETree}: Elimination and Front Trees} \label{chapter:ETree} \par The {\tt ETree} object is used to model an elimination tree or a front tree for a sparse factorization with symmetric structure. The tree is defined over a set of vertices in a graph --- the graph can be unit weight or non-unit weight. A ``node'' in the tree can be a single vertex (in the context of an elimination tree) or a group of vertices (as for a front tree). \par The tree information is stored as a {\tt Tree} object. In addition there are three {\tt IV} objects. One stores the total size of the nodes in the fronts, one stores the size of the boundaries of the fronts, and one stores the map from the vertices to the fronts. \par There is a great deal of functionality embodied into the {\tt ETree} object. Given an elimination tree or a front tree, one can extract the permutation vectors (for the fronts or the vertices), extract a multisector based on several criteria, compress the front tree in several ways, justify the tree (order children of a node in meaningful ways), evaluate metric vectors on the tree (heights, depths, subtree accumulators). \par The front tree we obtain from a low-fill matrix ordering is usually not the front tree that drives the factorization. We provide three methods that transform the former into the latter. One method merges the fronts together in a way that adds logical zeros to their structure. One method splits large fronts into smaller fronts. One method combines these two functionalities. ETree/doc/main.aux010064000020550007177000000073210665314225700153160ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt ETree}: Elimination and Front Trees}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:ETree}{{1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt ETree} methods}{2}} \newlabel{section:ETree:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{2}} \newlabel{subsection:ETree:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Instance methods}{2}} \newlabel{subsection:ETree:proto:instance}{{1.2.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Initializer methods}{4}} \newlabel{subsection:ETree:proto:initializers}{{1.2.3}{4}} \citation{liu90-etree} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Utility methods}{6}} \newlabel{subsection:ETree:proto:utilities}{{1.2.4}{6}} \citation{liu91-generalizedEnvelope} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Metrics methods}{8}} \newlabel{subsection:ETree:proto:metrics}{{1.2.5}{8}} \citation{ash89-relaxed} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.6}Compression methods}{9}} \newlabel{subsection:ETree:proto:compression}{{1.2.6}{9}} \citation{liu85-mfstorage} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.7}Justification methods}{10}} \newlabel{subsection:ETree:proto:justify}{{1.2.7}{10}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.8}Permutation methods}{10}} \newlabel{subsection:ETree:proto:permutation}{{1.2.8}{10}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.9}Multisector methods}{11}} \newlabel{subsection:ETree:proto:multisector}{{1.2.9}{11}} \citation{duf83-multifrontal} \citation{ash89-relaxed} \citation{ash89-relaxed} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.10}Transformation methods}{13}} \newlabel{subsection:ETree:proto:transformation}{{1.2.10}{13}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.11}Parallel factorization map methods}{15}} \newlabel{subsection:ETree:proto:map}{{1.2.11}{15}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.12}Storage profile methods}{16}} \newlabel{subsection:ETree:proto:storage}{{1.2.12}{16}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.13}IO methods}{17}} \newlabel{subsection:ETree:proto:IO}{{1.2.13}{17}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs for the {\tt ETree} object}{18}} \newlabel{section:ETree:drivers}{{1.3}{18}} \@writefile{lof}{\contentsline {figure}{\numberline {1.1}{\ignorespaces {\sc GRD7x7}: Working storage for the forward sparse factorization of the nested dissection ordering. On the left is the storage required to factor ${\mathaccent "0362\relax J}$ and its update matrix. On the right is the storage required to factor $J$ and all of its ancestors. Both plots have the same scale.}}{23}} \newlabel{fig-GRD7x7-FStree}{{1.1}{23}} \citation{ash89-relaxed} \citation{duf83-multifrontal} \@writefile{lof}{\contentsline {figure}{\numberline {1.2}{\ignorespaces {\sc GRD7x7x7}: Four tree plots for a $7 \times 7 \times 7$ grid matrix ordered using nested dissection. The top left tree measure number of original matrix entries in a front. The top right tree measure number of factor matrix entries in a front. The bottom left tree measure number of factor operations in a front for a forward looking factorization, e.g., forward sparse. The bottom right tree measure number of factor operations in a front for a backward looking factorization, e.g., general sparse.}}{28}} \newlabel{fig-GRD7x7x7-metrics}{{1.2}{28}} ETree/doc/main.log010064000020550007177000000262770665314225700153150ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 25 JAN 1999 11:23 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size11.clo File: size11.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file main.idx (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. (intro.tex Chapter 1. ) (dataStructure.tex LaTeX Font Info: Try loading font information for OMS+cmr on input line 6. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10.95> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 6. [1 ]) (proto.tex [2] [3] [4] LaTeX Font Info: External font `cmex10' loaded for size (Font) <10.95> on input line 292. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 292. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 292. LaTeX Warning: Citation `liu90-etree' on page 5 undefined on input line 292. Overfull \hbox (11.7664pt too wide) in paragraph at lines 320--320 []\OT1/cmtt/m/n/10.95 void ETree_initFromDenseMatrix ( ETree *etree, int n, in t option, int param ) ;[] [] Overfull \hbox (52.00722pt too wide) in paragraph at lines 354--354 []\OT1/cmtt/m/n/10.95 int ETree_initFromSubtree ( ETree *subtree, IV *nodeidsI V, ETree *etree, IV *vtxIV ) ;[] [] [5] Overfull \hbox (0.18552pt too wide) in paragraph at lines 433--439 \OT1/cmr/m/n/10.95 pa-ram-e-ter can be one of \OT1/cmtt/m/n/10.95 SPOOLES[]SYMM ETRIC\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMITIAN \OT1/cmr/m/n/1 0.95 or \OT1/cmtt/m/n/10.95 SPOOLES[]NONSYMMETRIC\OT1/cmr/m/n/10.95 . [] Overfull \hbox (23.26378pt too wide) in paragraph at lines 466--466 []\OT1/cmtt/m/n/10.95 double ETree_nInternalOpsInFront ( ETree *etree, int typ e, int symflag, int J ) ;[] [] [6] Overfull \hbox (23.26378pt too wide) in paragraph at lines 486--486 []\OT1/cmtt/m/n/10.95 double ETree_nExternalOpsInFront ( ETree *etree, int typ e, int symflag, int J ) ;[] [] Overfull \hbox (69.25328pt too wide) in paragraph at lines 565--565 []\OT1/cmtt/m/n/10.95 ETree * ETree_spliceTwoEtrees ( ETree *etree0, Graph *gr aph, IV *mapIV, ETree *etree1 ) ;[] [] [7] LaTeX Warning: Citation `liu91-generalizedEnvelope' on page 8 undefined on inpu t line 661. [8] LaTeX Warning: Citation `ash89-relaxed' on page 9 undefined on input line 681. Overfull \hbox (0.29208pt too wide) in paragraph at lines 691--695 []\OT1/cmr/m/n/10.95 the struc-tures of $\OML/cmm/m/it/10.95 v[]$ \OT1/cmr/m/n/ 10.95 and $\OML/cmm/m/it/10.95 v[]$ \OT1/cmr/m/n/10.95 are nested, i.e., \OT1/c mtt/m/n/10.95 bndwght[$\OML/cmm/m/it/10.95 v[]$\OT1/cmtt/m/n/10.95 ] = nodwght[ $\OML/cmm/m/it/10.95 v[]$\OT1/cmtt/m/n/10.95 ] + bndwght[$\OML/cmm/m/it/10.95 v []$\OT1/cmtt/m/n/10.95 ] [] [9] LaTeX Warning: Citation `liu85-mfstorage' on page 10 undefined on input line 75 9. [10] [11] Overfull \hbox (29.01247pt too wide) in paragraph at lines 944--944 []\OT1/cmtt/m/n/10.95 IV * ETree_msByNopsCutoff ( ETree *etree, double cutoff, int type, int symflag ) ;[] [] Overfull \hbox (23.26378pt too wide) in paragraph at lines 1000--1000 [] \OT1/cmtt/m/n/10.95 double alpha, int *ptotalgain, int msglvl, FILE *msgFile ) ;[] [] [12] LaTeX Warning: Citation `duf83-multifrontal' on page 13 undefined on input line 1038. LaTeX Warning: Citation `ash89-relaxed' on page 13 undefined on input line 1039 . LaTeX Warning: Citation `ash89-relaxed' on page 13 undefined on input line 1064 . [13] [14] [15] [16] [17]) (drivers.tex Overfull \hbox (19.63927pt too wide) in paragraph at lines 31--36 \OT1/cmtt/m/n/10.95 *.graphf \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.graphb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 Graph \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 Graph[]readFromFile() [] [18] Overfull \hbox (19.63927pt too wide) in paragraph at lines 81--86 \OT1/cmtt/m/n/10.95 *.etreef \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.etreeb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 ETree \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 ETree[]readFromFile() [] [19] [20] Overfull \hbox (19.63927pt too wide) in paragraph at lines 258--263 \OT1/cmtt/m/n/10.95 *.etreef \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.etreeb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 ETree \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 ETree[]readFromFile() [] [21] Overfull \hbox (0.26903pt too wide) in paragraph at lines 333--333 []\OT1/cmtt/m/n/10.95 testFS msglvl msgFile inETreeFile labelflag radius first EPSfile secondEPSfile[] [] Overfull \hbox (19.63927pt too wide) in paragraph at lines 358--363 \OT1/cmtt/m/n/10.95 *.etreef \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.etreeb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 ETree \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 ETree[]readFromFile() [] psfig: searching ../../ETree/doc/FS1.eps for bounding box psfig: including ../../ETree/doc/FS1.eps psfig: searching ../../ETree/doc/FS2.eps for bounding box psfig: including ../../ETree/doc/FS2.eps [22] Overfull \hbox (19.63927pt too wide) in paragraph at lines 411--415 \OT1/cmtt/m/n/10.95 *.etreef \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.etreeb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 ETree \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 ETree[]readFromFile() [] [23] Overfull \hbox (19.63927pt too wide) in paragraph at lines 437--442 \OT1/cmtt/m/n/10.95 *.etreef \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.etreeb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 ETree \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 ETree[]readFromFile() [] Overfull \hbox (19.63927pt too wide) in paragraph at lines 472--477 \OT1/cmtt/m/n/10.95 *.etreef \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.etreeb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 ETree \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 ETree[]readFromFile() [] [24] Overfull \hbox (19.63927pt too wide) in paragraph at lines 573--578 \OT1/cmtt/m/n/10.95 *.etreef \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.etreeb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 ETree \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 ETree[]readFromFile() [] [25] Overfull \hbox (17.51509pt too wide) in paragraph at lines 617--617 []\OT1/cmtt/m/n/10.95 testStats msglvl msgFile inETreeFile labelflag radius fi rstEPSfile secondEPSfile[] [] Overfull \hbox (19.63927pt too wide) in paragraph at lines 653--658 \OT1/cmtt/m/n/10.95 *.etreef \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.etreeb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 ETree \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 ETree[]readFromFile() [] Overfull \hbox (19.63927pt too wide) in paragraph at lines 658--663 \OT1/cmtt/m/n/10.95 *.graphf \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.graphb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 Graph \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 Graph[]readFromFile() [] [26] LaTeX Warning: Reference `subsection:Tree:proto:drawing' on page 27 undefined o n input line 670. psfig: searching ../../ETree/doc/GRD7x7x7_nzA.eps for bounding box psfig: including ../../ETree/doc/GRD7x7x7_nzA.eps psfig: searching ../../ETree/doc/GRD7x7x7_nzF.eps for bounding box psfig: including ../../ETree/doc/GRD7x7x7_nzF.eps psfig: searching ../../ETree/doc/GRD7x7x7_forwops.eps for bounding box psfig: including ../../ETree/doc/GRD7x7x7_forwops.eps psfig: searching ../../ETree/doc/GRD7x7x7_backops.eps for bounding box psfig: including ../../ETree/doc/GRD7x7x7_backops.eps psfig: searching ../../ETree/doc/workingStorage.eps for bounding box psfig: including ../../ETree/doc/workingStorage.eps Overfull \hbox (19.63927pt too wide) in paragraph at lines 732--737 \OT1/cmtt/m/n/10.95 *.etreef \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.etreeb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 ETree \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 ETree[]readFromFile() [] Overfull \hbox (19.63927pt too wide) in paragraph at lines 737--741 \OT1/cmtt/m/n/10.95 *.graphf \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.graphb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 Graph \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 Graph[]readFromFile() [] LaTeX Warning: Citation `ash89-relaxed' on page 27 undefined on input line 752. LaTeX Warning: Citation `duf83-multifrontal' on page 27 undefined on input line 752. [27] [28] Overfull \hbox (19.63927pt too wide) in paragraph at lines 798--803 \OT1/cmtt/m/n/10.95 *.etreef \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.etreeb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 ETree \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 ETree[]readFromFile() [] Overfull \hbox (19.63927pt too wide) in paragraph at lines 803--808 \OT1/cmtt/m/n/10.95 *.graphf \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.graphb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 Graph \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 Graph[]readFromFile() [] ) (main.ind [29] [30 ] [31 ]) (main.aux) LaTeX Warning: There were undefined references. ) Here is how much of TeX's memory you used: 599 strings out of 10908 6400 string characters out of 72189 53984 words of memory out of 262141 3465 multiletter control sequences out of 9500 10951 words of font info for 40 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 23i,6n,22p,612b,426s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (31 pages, 106436 bytes). ETree/doc/main.tex010064400020550007177000000011160665065622100153170ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \input psfig \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt ETree} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt ETree} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} ETree/doc/main.idx010064400020550007177000000120710665314225700153070ustar00clevecompmath00000400000006\indexentry{ETree_new@{\tt ETree\_new()}}{2} \indexentry{ETree_setDefaultFields@{\tt ETree\_setDefaultFields()}}{2} \indexentry{ETree_clearData@{\tt ETree\_clearData()}}{2} \indexentry{ETree_free@{\tt ETree\_free()}}{2} \indexentry{ETree_nfront@{\tt ETree\_nfront()}}{2} \indexentry{ETree_nvtx@{\tt ETree\_nvtx()}}{3} \indexentry{ETree_tree@{\tt ETree\_tree()}}{3} \indexentry{ETree_root@{\tt ETree\_root()}}{3} \indexentry{ETree_par@{\tt ETree\_par()}}{3} \indexentry{ETree_fch@{\tt ETree\_fch()}}{3} \indexentry{ETree_sib@{\tt ETree\_sib()}}{3} \indexentry{ETree_nodwghtsIV@{\tt ETree\_nodwghtsIV()}}{3} \indexentry{ETree_nodwghts@{\tt ETree\_nodwghts()}}{3} \indexentry{ETree_bndwghtsIV@{\tt ETree\_bndwghtsIV()}}{3} \indexentry{ETree_bndwghts@{\tt ETree\_bndwghts()}}{4} \indexentry{ETree_vtxToFrontIV@{\tt ETree\_vtxToFrontIV()}}{4} \indexentry{ETree_vtxToFront@{\tt ETree\_vtxToFront()}}{4} \indexentry{ETree_frontSize@{\tt ETree\_frontSize()}}{4} \indexentry{ETree_frontBoundarySize@{\tt ETree\_frontBoundarySize()}}{4} \indexentry{ETree_maxNindAndNent@{\tt ETree\_maxNindAndNent()}}{4} \indexentry{ETree_init1@{\tt ETree\_init1()}}{4} \indexentry{ETree_initFromGraph@{\tt ETree\_initFromGraph()}}{5} \indexentry{ETree_initFromGraphWithPerms@{\tt ETree\_initFromGraphWithPerms()}}{5} \indexentry{ETree_initFromDenseMatrix@{\tt ETree\_initFromDenseMatrix()}}{5} \indexentry{ETree_initFromFile@{\tt ETree\_initFromFile()}}{5} \indexentry{ETree_initFromSubtree@{\tt ETree\_initFromSubtree()}}{5} \indexentry{ETree_sizeOf@{\tt ETree\_sizeOf()}}{6} \indexentry{ETree_nFactorIndices@{\tt ETree\_nFactorIndices()}}{6} \indexentry{ETree_nFactorEntries@{\tt ETree\_nFactorEntries()}}{6} \indexentry{ETree_nFactorOps@{\tt ETree\_nFactorOps()}}{6} \indexentry{ETree_nFactorEntriesInFront@{\tt ETree\_nFactorEntriesInFront()}}{6} \indexentry{ETree_nInternalOpsInFront@{\tt ETree\_nInternalOpsInFront()}}{7} \indexentry{ETree_nExternalOpsInFront@{\tt ETree\_nExternalOpsInFront()}}{7} \indexentry{ETree_factorEntriesIV@{\tt ETree\_factorEntriesIV()}}{7} \indexentry{ETree_backwardOps@{\tt ETree\_backwardOps()}}{7} \indexentry{ETree_forwardOps@{\tt ETree\_forwardOps()}}{7} \indexentry{ETree_expand@{\tt ETree\_expand()}}{7} \indexentry{ETree_spliceTwoEtrees@{\tt ETree\_spliceTwoEtrees()}}{8} \indexentry{ETree_nvtxMetric@{\tt ETree\_nvtxMetric()}}{8} \indexentry{ETree_nentMetric@{\tt ETree\_nentMetric()}}{8} \indexentry{ETree_nopsMetric@{\tt ETree\_nopsMetric()}}{8} \indexentry{ETree_fundChainMap@{\tt ETree\_fundChainMap()}}{9} \indexentry{ETree_fundSupernodeMap@{\tt ETree\_fundSupernodeMap()}}{9} \indexentry{ETree_compress@{\tt ETree\_compress()}}{10} \indexentry{ETree_leftJustify@{\tt ETree\_leftJustify()}}{10} \indexentry{ETree_leftJustifyI@{\tt ETree\_leftJustifyI()}}{10} \indexentry{ETree_leftJustifyD@{\tt ETree\_leftJustifyD()}}{10} \indexentry{ETree_newToOldFrontPerm@{\tt ETree\_newToOldFrontPerm()}}{10} \indexentry{ETree_oldToNewFrontPerm@{\tt ETree\_oldToNewFrontPerm()}}{10} \indexentry{ETree_newToOldVtxPerm@{\tt ETree\_newToOldVtxPerm()}}{11} \indexentry{ETree_oldToNewVtxPerm@{\tt ETree\_oldToNewVtxPerm()}}{11} \indexentry{ETree_permuteVertices@{\tt ETree\_permuteVertices()}}{11} \indexentry{ETree_msByDepth@{\tt ETree\_msByDepth()}}{11} \indexentry{ETree_msByNvtxCutoff@{\tt ETree\_msByNvtxCutoff()}}{11} \indexentry{ETree_msByNentCutoff@{\tt ETree\_msByNentCutoff()}}{11} \indexentry{ETree_msByNopsCutoff@{\tt ETree\_msByNopsCutoff()}}{12} \indexentry{ETree_msStats@{\tt ETree\_msStats()}}{12} \indexentry{ETree_optPart@{\tt ETree\_optPart()}}{12} \indexentry{ETree_mergeFrontsOne@{\tt ETree\_mergeFrontsOne()}}{14} \indexentry{ETree_mergeFrontsAll@{\tt ETree\_mergeFrontsAll()}}{14} \indexentry{ETree_mergeFrontsAny@{\tt ETree\_mergeFrontsAny()}}{14} \indexentry{ETree_splitFronts@{\tt ETree\_splitFronts()}}{14} \indexentry{ETree_transform@{\tt ETree\_transform()}}{15} \indexentry{ETree_transform2@{\tt ETree\_transform2()}}{15} \indexentry{ETree_wrapMap@{\tt ETree\_wrapMap()}}{15} \indexentry{ETree_balancedMap@{\tt ETree\_balancedMap()}}{15} \indexentry{ETree_subtreeSubsetMap@{\tt ETree\_subtreeSubsetMap()}}{15} \indexentry{ETree_ddMap@{\tt ETree\_ddMap()}}{15} \indexentry{ETree_ddMapNew@{\tt ETree\_ddMapNew()}}{15} \indexentry{ETree_MFstackProfile@{\tt ETree\_MFstackProfile()}}{16} \indexentry{ETree_GSstorageProfile@{\tt ETree\_GSstorageProfile()}}{16} \indexentry{ETree_FSstorageProfile@{\tt ETree\_FSstorageProfile()}}{16} \indexentry{ETree_forwSolveProfile@{\tt ETree\_forwSolveProfile()}}{16} \indexentry{ETree_backSolveProfile@{\tt ETree\_backSolveProfile()}}{17} \indexentry{ETree_readFromFile@{\tt ETree\_readFromFile()}}{17} \indexentry{ETree_readFromFormattedFile@{\tt ETree\_readFromFormattedFile()}}{17} \indexentry{ETree_readFromBinaryFile@{\tt ETree\_readFromBinaryFile()}}{17} \indexentry{ETree_writeToFile@{\tt ETree\_writeToFile()}}{17} \indexentry{ETree_writeToFormattedFile@{\tt ETree\_writeToFormattedFile()}}{17} \indexentry{ETree_writeToBinaryFile@{\tt ETree\_writeToBinaryFile()}}{18} \indexentry{ETree_writeForHumanEye@{\tt ETree\_writeForHumanEye()}}{18} \indexentry{ETree_writeStats@{\tt ETree\_writeStats()}}{18} ETree/doc/drivers.tex010064400020550007177000001017460665314217200160610ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt ETree} object} \label{section:ETree:drivers} \par This section contains brief descriptions of the driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} createETree msglvl msgFile inGraphFile inPermFile outIVfile outETreeFile \end{verbatim} This driver program reads in a {\tt Graph} object and a {\tt Perm} permutation object and creates a front tree {\tt ETree} object. The map from vertices to fronts is optionally written out to {\tt outIVfile}. The {\tt ETree} object is optionally written out to {\tt outETreeFile}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt inPermFile} parameter is the input file for the {\tt Perm} object. It must be of the form {\tt *.permf} or {\tt *.permb}. The {\tt Perm} object is read from the file via the {\tt Perm\_readFromFile()} method. \item The {\tt outIVfile} parameter is the output file for the vertex-to-front map {\tt IV} object. If {\tt outIVfile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the object to a formatted file (if {\tt outIVfile} is of the form {\tt *.ivf}), or a binary file (if {\tt outIVfile} is of the form {\tt *.ivb}). \item The {\tt outETreeFile} parameter is the output file for the {\tt ETree} object. If {\tt outETreeFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt outETreeFile} is of the form {\tt *.etreef}), or a binary file (if {\tt outETreeFile} is of the form {\tt *.etreeb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} extractTopSep msglvl msgFile inETreeFile outIVfile \end{verbatim} This driver program creates an {\tt IV} object that contains a {\tt compids[]} vector, where {\tt compids[v] = 0} if vertex {\tt v} is in the top level separator and {\tt -1} otherwise. The {\tt IV} object is optionally written out to a file. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any message data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt outIVfile} parameter is the output file for the vertex-to-front map {\tt IV} object. If {\tt outIVfile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the object to a formatted file (if {\tt outIVfile} is of the form {\tt *.ivf}), or a binary file (if {\tt outIVfile} is of the form {\tt *.ivb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} mkNDETree msglvl msgFile n1 n2 n3 maxzeros maxsize outFile \end{verbatim} \par This program constructs a front tree for a Laplacian operator on a regular grid ordered using nested dissection. When {\tt n3 = 1}, the problem is two dimensional and a 9-point operator is used. When {\tt n3 > 1}, the problem is three dimensional and a 27-point operator is used. A sequence of five ETree objects are produced: \begin{itemize} \item vertex elimination tree \item fundamental supernode front tree \item front tree after trying to merge with an only child \item front tree after trying to merge with all children \item front tree after splitting large fronts \end{itemize} The merging and splitting process are controlled by the {\tt maxzeros} and {\tt maxsize} parameters. Here is some typical output for a $15 \times 15 \times 15$ grid matrix with {\tt maxzeros = 64} and {\tt maxsize = 32}. \begin{verbatim} vtx tree : 3375 fronts, 367237 indices, 367237 |L|, 63215265 ops fs tree : 1023 fronts, 39661 indices, 367237 |L|, 63215265 ops merge1 : 1023 fronts, 39661 indices, 367237 |L|, 63215265 ops merge2 : 511 fronts, 29525 indices, 373757 |L|, 63590185 ops split : 536 fronts, 34484 indices, 373757 |L|, 63590185 ops \end{verbatim} \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt n1} is the number of grid points in the first direction. \item {\tt n2} is the number of grid points in the second direction. \item {\tt n3} is the number of grid points in the third direction. \item The {\tt maxzeros} parameter is an upper bound on the number of logically zero entries that will be allowed in a new front. \item The {\tt maxsize} parameter is an upper bound on the number of vertices in a front --- any original front that contains more than {\tt maxsize} vertices will be broken up into smaller fronts. \item The {\tt outFile} parameter is the output file for the {\tt ETree} object. If {\tt outFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt outFile} is of the form {\tt *.etreef}), or a binary file (if {\tt outFile} is of the form {\tt *.etreeb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} mkNDoutput msglvl msgFile n1 n2 n3 maxzeros maxsize nthread maptype cutoff outETreeFile outMapFile \end{verbatim} \par This program constructs a front tree for a Laplacian operator on a regular grid ordered using nested dissection. When {\tt n3 = 1}, the problem is two dimensional and a 9-point operator is used. When {\tt n3 > 1}, the problem is three dimensional and a 27-point operator is used. The front tree is generated in the same fashion as done by the {\tt mkNDETree} driver program. Using this front tree, an {\tt IV} object that maps fronts to processors is then created using one of four different kinds of maps. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt n1} is the number of grid points in the first direction. \item {\tt n2} is the number of grid points in the second direction. \item {\tt n3} is the number of grid points in the third direction. \item The {\tt maxzeros} parameter is an upper bound on the number of logically zero entries that will be allowed in a new front. \item The {\tt maxsize} parameter is an upper bound on the number of vertices in a front --- any original front that contains more than {\tt maxsize} vertices will be broken up into smaller fronts. \item The {\tt nthread} parameter is the number of threads. \item The {\tt maptype} parameter is the type of map. \begin{itemize} \item {\tt 1} --- wrap map \item {\tt 2} --- balanced map \item {\tt 3} --- subtree-subset map \item {\tt 4} --- domain decomposition map \end{itemize} \item The {\tt cutoff} parameter is used by the domain decomposition map only. Try setting {\tt cutoff = 1/nthread} or {\tt cutoff = 1/(2*nthread)}. \item The {\tt outETreeFile} parameter is the output file for the {\tt ETree} object. If {\tt outETreeFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt outETreeFile} is of the form {\tt *.etreef}), or a binary file (if {\tt outETreeFile} is of the form {\tt *.etreeb}). \item The {\tt outMapFile} parameter is the output file for the {\tt IV} map object. If {\tt outMapFile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the object to a formatted file (if {\tt outMapFile} is of the form {\tt *.ivf}), or a binary file (if {\tt outMapFile} is of the form {\tt *.ivb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} permuteETree msglvl msgFile inETreeFile inEqmapIVfile outETreeFile outIVfile \end{verbatim} This driver program is used to get an old-to-new permutation vector from an {\tt ETree} object and permute the vertices in the {\tt ETree} object. The program has the ability to handle an {\tt ETree} object that is defined on a compressed graph. If {\tt inEqmapIVfile} is not {\tt none}, the program reads in an {\tt IV} object that contains the equivalence map, i.e., the map from the degrees of freedom to the vertices in the compressed graph. This map is used to expand the {\tt ETree} object. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt inEqmapIVfile} parameter is the input file for the equivalence map {\tt IV} object. It must be of the form {\tt *.ivf}, {\tt *.ivb}, or {\tt none}. If {\tt inEqmapIVfile} is not {\tt none}, the {\tt IV} object is read from the file via the {\tt IV\_readFromFile()} method. \item The {\tt outETreeFile} parameter is the output file for the {\tt ETree} object. If {\tt outETreeFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt outETreeFile} is of the form {\tt *.etreef}), or a binary file (if {\tt outETreeFile} is of the form {\tt *.etreeb}). \item The {\tt outIVFile} parameter is the output file for the old-to-new {\tt IV} object. If {\tt outIVFile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the object to a formatted file (if {\tt outIVFile} is of the form {\tt *.ivf}), or a binary file (if {\tt outIVFile} is of the form {\tt *.ivb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testExpand msglvl msgFile inETreeFile inEqmapFile outETreeFile \end{verbatim} This driver program is used to translate an {\tt ETree} object for a compressed graph into an {\tt ETree} object for the unit weight graph. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object for the compressed graph. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt inEqmapFile} parameter contains the map from vertices in the unit weight graph into vertices in the compressed graph. It must be of the form {\tt *.ivf} or {\tt *.ivb}. The {\tt IV} object is read from the file via the {\tt IV\_readFromFile()} method. \item The {\tt outETreeFile} parameter is the output file for the {\tt ETree} object for the unit weight graph. If {\tt outETreeFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt outETreeFile} is of the form {\tt *.etreef}), or a binary file (if {\tt outETreeFile} is of the form {\tt *.etreeb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testFS msglvl msgFile inETreeFile labelflag radius firstEPSfile secondEPSfile \end{verbatim} This driver program investigates the storage requirements for a limited storage forward sparse factorization. It first reads in a front tree object and for each front $J$, it determines two quantities: (1) the amount of in-core storage necessary to factor ${\widehat J}$ and its boundary, and (2) the amount of in-core storage necessary to factor $J$, $\mbox{par}(J)$, $\mbox{par}^2(J)$, etc. The program then creates two EPS files, written to {\tt firstEPSfile} and {\tt secondEPSfile}. See Figure~\ref{fig-GRD7x7-FStree} for an example. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item If {\tt labelflag = 1}, the node ids are written on the nodes in the two plots. \item Each node will have a circle with radius {\tt radius}. \item The {\tt firstEPSfile} and {\tt secondEPSfile} parameters is the output EPS file for the two plots. \end{itemize} \begin{figure}[htbp] \caption{{\sc GRD7x7}: Working storage for the forward sparse factorization of the nested dissection ordering. On the left is the storage required to factor ${\widehat J}$ and its update matrix. On the right is the storage required to factor $J$ and all of its ancestors. Both plots have the same scale.} \label{fig-GRD7x7-FStree} \begin{center} \fbox{ \psfig{file=../../ETree/doc/FS1.eps,height=3.00in,width=3.00in} } \fbox{ \psfig{file=../../ETree/doc/FS2.eps,height=3.00in,width=3.00in} } \end{center} \end{figure} %----------------------------------------------------------------------- \item \begin{verbatim} testHeight msglvl msgFile inETreeFile \end{verbatim} This driver program computes the height of the front tree with respect to factor storage. This quantity is the minimum amount of working storage for a forward sparse factorization. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program reads and writes {\tt ETree} files, useful for converting formatted files to binary files and vice versa. One can also read in a {\tt ETree} file and print out just the header information (see the {\tt ETree\_writeStats()} method). \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt ETree} object. If {\tt outFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt outFile} is of the form {\tt *.etreef}), or a binary file (if {\tt outFile} is of the form {\tt *.etreeb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testMaps msglvl msgFile inETreeFile outIVfile nthread type cutoff \end{verbatim} This program is used to construct an owners {\tt IV} that maps a front to its owning thread or process. The owners map {\tt IV} object is optionally written to a file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt outIVFile} parameter is the output file for the owners map {\tt IV} object. If {\tt outIVFile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the object to a formatted file (if {\tt outIVFile} is of the form {\tt *.ivf}), or a binary file (if {\tt outIVFile} is of the form {\tt *.ivb}). \item The {\tt nthread} parameter specifies the number of threads or processes to be used. \item The {\tt type} parameter specifies the type of multisector. \begin{itemize} \item {\tt type == 1} --- use {\tt ETree\_wrapMap()} to compute a wrap mapping. \item {\tt type == 2} --- use {\tt ETree\_balancedMap()} to compute a balanced mapping. \item {\tt type == 3} --- use {\tt ETree\_subtreeSubset()} to compute a subtree-subset mapping. \item {\tt type == 4} --- use {\tt ETree\_ddMap()} to compute a domain decomposition map. \end{itemize} \item {\tt cutoff} is a cutoff value for the multisector used only for the domain decomposition map. The cutoff defines the multisector, $0 \le \mbox{\tt cutoff} \le 1$. If front {\tt J} has a subtree metric based on forward operations that is greater than or equalt to {\tt cutoff} times the total number of operations, then front {\tt J} belongs to the multisector. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testMS msglvl msgFile inETreeFile outIVfile flag cutoff \end{verbatim} This program is used to extract a multisector from a front tree {\tt ETree} object. It partitions the vertices into domains and a multisector, where each domain is a subtree of the elimination tree and the multisector is the rest of the vertices. The choice of the subtrees depends on the {\tt flag} and {\tt cutoff} parameters --- it can be based on depth of a subtree or the number of vertices, factor entries or factor operations associated with the subtree. The component ids {\tt IV} object is optionally written to a file. Here is some sample output for {\tt BCSSTK30} ordered by nested dissection, where the multisector is defined by subtree vertex weight ({\tt flag = 2}) with {\tt cutoff = 0.125}. \begin{verbatim} region vertices entries operations metric/(avg domain) 0 1671 597058 255691396 0.797 2.201 3.967 1 3104 255341 33205237 1.481 0.941 0.515 2 3222 457255 116441261 1.537 1.685 1.806 3 1514 194916 41940202 0.722 0.718 0.651 4 2057 333186 100212056 0.981 1.228 1.555 5 77 5040 356454 0.037 0.019 0.006 6 1750 266166 62607526 0.835 0.981 0.971 7 1887 325977 101994905 0.900 1.202 1.582 8 3405 492662 125496320 1.624 1.816 1.947 9 3413 501150 141423868 1.628 1.847 2.194 10 3242 320220 51679456 1.546 1.180 0.802 11 2118 238011 44427959 1.010 0.877 0.689 12 1454 136777 18166107 0.694 0.504 0.282 13 10 106 1168 0.005 0.000 0.000 nvtx % nzf % ops % domains 27253 94.22 3526807 85.52 837952519 76.620 schur complement 1671 5.78 597058 14.48 255691396 23.380 total 28924 4123865 1093643915 \end{verbatim} Region {\tt 0} is the Schur complement, and there are thirteen domains, eleven of good size. A perfectly balanced tree would have eight domains using {\tt cutoff} equal to 1/8. It is interesting to see that the Schur complment contains only six per cent of the vertices but almost one quarter the number of operations. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt outIVFile} parameter is the output file for the {\tt IV} object. If {\tt outIVFile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the object to a formatted file (if {\tt outIVFile} is of the form {\tt *.ivf}), or a binary file (if {\tt outIVFile} is of the form {\tt *.ivb}). \item The {\tt flag} parameter specifies the type of multisector. \begin{itemize} \item {\tt flag == 1} --- the multisector is based on the depth of the front, i.e., if the front is more than {\tt depth} steps removed from the root, it forms the root of a domain. \item {\tt flag == 2} --- the multisector is based on the number of vertices in a subtree, i.e., if the subtree rooted at a front contains more than {\tt cutoff} times the total number of vertices, it is a domain. \item {\tt flag == 3} --- the multisector is based on the number of factor entries in a subtree, i.e., if the subtree rooted at a front contains more than {\tt cutoff} times the total number of factor entries, it is a domain. \item {\tt flag == 4} --- the multisector is based on the number of factor operations in a subtree, i.e., if the subtree rooted at a front contains more than {\tt cutoff} times the total number of factor operations, it is a domain. \end{itemize} \item {\tt cutoff} is a cutoff value for the multisector, see above description when {\tt flag} equals {\tt 1}, {\tt 2} or {\tt 3}. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testStats msglvl msgFile inETreeFile labelflag radius firstEPSfile secondEPSfile \end{verbatim} This driver program computes one of five metrics associated with a front tree and writes an EPS file that illustrates the metric overlaid on the tree structure. It first reads in a front tree object and a graph file. There are six possible plots: \begin{center} \begin{tabular}{c|l} {\tt metricType} & type of metric \\ \hline 0 & no metric, just a tree plot \\ 1 & \# of nodes in a front \\ 2 & \# of original matrix entries in a front \\ 3 & \# of factor matrix entries in a front \\ 4 & \# of forward factor operations in a front \\ 5 & \# of backward factor operations in a front \end{tabular} \end{center} The maximum value of the metric creates a circle with radius {\tt rmax}, and all other nodes have circles with their area relative to this largest circle. See Figure~\ref{fig-GRD7x7x7-metrics} contains four plots, each used {\tt heightflag = 'D'}, {\tt coordflag = 'P'}, {\tt rmax = 20} and {\tt labelflag = 0}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt outEPSfile} parameter is the name of the EPS file to hold the tree. \item The {\tt metricType} parameter defines the type of metric to be illustrated. See above for values. \item For information about the {\tt heightflag} and {\tt coordflag} parameters, see Section~\ref{subsection:Tree:proto:drawing}. \item If {\tt labelflag = 1}, the node ids are written on the nodes in the two plots. \item The {\tt fontscale} parameter is the font size when labels are drawn. \end{itemize} \begin{figure}[htbp] \caption{{\sc GRD7x7x7}: Four tree plots for a $7 \times 7 \times 7$ grid matrix ordered using nested dissection. The top left tree measure number of original matrix entries in a front. The top right tree measure number of factor matrix entries in a front. The bottom left tree measure number of factor operations in a front for a forward looking factorization, e.g., forward sparse. The bottom right tree measure number of factor operations in a front for a backward looking factorization, e.g., general sparse.} \label{fig-GRD7x7x7-metrics} \begin{center} \fbox{ \psfig{file=../../ETree/doc/GRD7x7x7_nzA.eps,height=3.00in,width=3.00in} } \fbox{ \psfig{file=../../ETree/doc/GRD7x7x7_nzF.eps,height=3.00in,width=3.00in} } \par \fbox{ \psfig{file=../../ETree/doc/GRD7x7x7_forwops.eps,height=3.00in,width=3.00in} } \fbox{ \psfig{file=../../ETree/doc/GRD7x7x7_backops.eps,height=3.00in,width=3.00in} } \end{center} \end{figure} %----------------------------------------------------------------------- \item \begin{verbatim} testStorage msglvl msgFile inETreeFile inGraphFile \end{verbatim} This driver program is used to evaluate the working storage for the left-looking general sparse and multifrontal algorithms using the natural post-order traversal of the front tree. The output is in matlab format to produce a plot. An example is found below. \begin{center} \makebox{ % \psfig{file=workingStorage.eps,width=3.0in,height=2.40in} \psfig{file=../../ETree/doc/workingStorage.eps,width=3.0in,height=2.40in} } \end{center} \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testTransform msglvl msgFile inETreeFile inGraphFile outETreeFile maxzeros maxsize seed \end{verbatim} This driver program is used to transform a front tree {\tt ETree} object into a (possibly) merged and (possibly) split front tree. {\it Merging} the front tree means combining fronts together that do not introduce more than {\tt maxzeros} zero entries in a front. (See \cite{ash89-relaxed} and \cite{duf83-multifrontal} for a description of this supernode amalgamation or relaxation.) {\it Splitting} a front means breaking a front up into a chain of smaller fronts; this allows more processors to work on the original front in a straightforward manner. The new front tree is optionally written to a file. Here is some output for the {\tt R3D13824} matrix using {\tt maxzeros = 1000} and {\tt maxsize = 64}. \begin{verbatim} CPU #fronts #indices #entries #ops original : 6001 326858 3459359 1981403337 merge one : 0.209 3477 158834 3497139 2000297117 merge all : 0.136 748 95306 3690546 2021347776 merge any : 0.073 597 85366 3753241 2035158539 split : 0.202 643 115139 3753241 2035158539 final : 3.216 643 115128 3752694 2034396840 \end{verbatim} Note how the number of fronts, front indices, factor entries and factor operations change after each step. Merging chains (the {\tt merge one} line) halves the number of fronts while increasing operations by 1\%. Merging all children when possible (the {\tt merge all} line) reduces the number of fronts by a factor of 5 while increasing operations by another 1\%. Merging any other children (the {\tt merge any} line) has another additional effect. Splitting the fronts increases the number of fronts slightly, but appears not to change the factor entries or operation counts. This is false, as the final step computes the symbolic factorization for the last front tree and updates the boundary sizes of the fronts. We see that the number of indices, entries and factor operations actually decrease slightly due to the split fronts. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt ETree} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt outETreeFile} parameter is the output file for the {\tt ETree} object. If {\tt outETreeFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt outETreeFile} is of the form {\tt *.etreef}), or a binary file (if {\tt outETreeFile} is of the form {\tt *.etreeb}). \item The {\tt maxzeros} parameter is an upper bound on the number of logically zero entries that will be allowed in a new front. \item The {\tt maxsize} parameter is an upper bound on the number of vertices in a front --- any original front that contains more than {\tt maxsize} vertices will be broken up into smaller fronts. \item {\tt seed} is a seed for a random number generator. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} ne} then the {\tt IV} objeETree/doc/proto.tex010064400020550007177000001730740665017451000155470ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt ETree} methods} \label{section:ETree:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt ETree} object. \par \subsection{Basic methods} \label{subsection:ETree:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} ETree * ETree_new ( void ) ; \end{verbatim} \index{ETree_new@{\tt ETree\_new()}} This method simply allocates storage for the {\tt ETree} structure and then sets the default fields by a call to {\tt ETree\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_setDefaultFields ( ETree *etree ) ; \end{verbatim} \index{ETree_setDefaultFields@{\tt ETree\_setDefaultFields()}} This method sets the structure's fields are set to default values: {\tt nfront = nvtx = 0}, {\tt tree = nodwghtsIV = bndwghtsIV = vtxToFrontIV = NULL}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_clearData ( ETree *etree ) ; \end{verbatim} \index{ETree_clearData@{\tt ETree\_clearData()}} This method clears data and releases any storage allocated by the object. If {\tt tree} is not {\tt NULL}, then {\tt Tree\_free(tree)} is called to free the {\tt Tree} object. It releases any storage held by the {\tt nodwghtsIV}, {\tt bndwghtsIV} and {\tt vtxToFrontIV} {\tt IV} objects via calls to {\tt IV\_free()}. It then sets the structure's default fields with a call to {\tt ETree\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_free ( ETree *etree ) ; \end{verbatim} \index{ETree_free@{\tt ETree\_free()}} This method releases any storage by a call to {\tt ETree\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:ETree:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_nfront ( ETree *etree ) ; \end{verbatim} \index{ETree_nfront@{\tt ETree\_nfront()}} This method returns the number of fronts. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_nvtx ( ETree *etree ) ; \end{verbatim} \index{ETree_nvtx@{\tt ETree\_nvtx()}} This method returns the number of vertices. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Tree * ETree_tree ( ETree *etree ) ; \end{verbatim} \index{ETree_tree@{\tt ETree\_tree()}} This method returns a pointer to the {\tt Tree} object. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_root ( ETree *etree ) ; \end{verbatim} \index{ETree_root@{\tt ETree\_root()}} This method returns the id of the root node. \par \noindent {\it Error checking:} If {\tt etree} or {\tt etree->tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * ETree_par ( ETree *etree ) ; \end{verbatim} \index{ETree_par@{\tt ETree\_par()}} This method returns the pointer to the parent vector. \par \noindent {\it Error checking:} If {\tt etree} or {\tt etree->tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * ETree_fch ( ETree *etree ) ; \end{verbatim} \index{ETree_fch@{\tt ETree\_fch()}} This method returns the pointer to the first child vector. \par \noindent {\it Error checking:} If {\tt etree} or {\tt etree->tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * ETree_sib ( ETree *etree ) ; \end{verbatim} \index{ETree_sib@{\tt ETree\_sib()}} This method returns the pointer to the sibling vector. \par \noindent {\it Error checking:} If {\tt etree} or {\tt etree->tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_nodwghtsIV ( ETree *etree ) ; \end{verbatim} \index{ETree_nodwghtsIV@{\tt ETree\_nodwghtsIV()}} This method returns a pointer to the {\tt nodwghtsIV} object. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * ETree_nodwghts ( ETree *etree ) ; \end{verbatim} \index{ETree_nodwghts@{\tt ETree\_nodwghts()}} This method returns a pointer to the {\tt nodwghts} vector. \par \noindent {\it Error checking:} If {\tt etree} or {\tt etree->nodwghtsIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_bndwghtsIV ( ETree *etree ) ; \end{verbatim} \index{ETree_bndwghtsIV@{\tt ETree\_bndwghtsIV()}} This method returns a pointer to the {\tt bndwghtsIV} object. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * ETree_bndwghts ( ETree *etree ) ; \end{verbatim} \index{ETree_bndwghts@{\tt ETree\_bndwghts()}} This method returns a pointer to the {\tt bndwghts} vector. \par \noindent {\it Error checking:} If {\tt etree} or {\tt etree->bndwghtsIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_vtxToFrontIV ( ETree *etree ) ; \end{verbatim} \index{ETree_vtxToFrontIV@{\tt ETree\_vtxToFrontIV()}} This method returns a pointer to the {\tt vtxToFrontIV} object. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * ETree_vtxToFront ( ETree *etree ) ; \end{verbatim} \index{ETree_vtxToFront@{\tt ETree\_vtxToFront()}} This method returns a pointer to the {\tt vtxToFront} vector. \par \noindent {\it Error checking:} If {\tt etree} or {\tt etree->vtxToFrontIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_frontSize ( ETree *etree, int J ) ; \end{verbatim} \index{ETree_frontSize@{\tt ETree\_frontSize()}} This method returns the number of internal degrees of freedom in front {\tt J}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if {\tt J} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_frontBoundarySize ( ETree *etree, int J ) ; \end{verbatim} \index{ETree_frontBoundarySize@{\tt ETree\_frontBoundarySize()}} This method returns the number of external or boundary degrees of freedom in front {\tt J}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if {\tt J} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_maxNindAndNent ( ETree *etree, int symflag, int *pmaxnind, int *pmaxnent ) ; \end{verbatim} \index{ETree_maxNindAndNent@{\tt ETree\_maxNindAndNent()}} This method fills {\tt *pmaxnind} with the maximum number of indices for a front (just column indices if symmetric front, row and column indices if nonsymmetric front) and {\tt *pmaxnent} with the maximum number of entries for a front (just upper entries if symmetric front, all entries if nonsymmetric front). The {\tt symflag} parameter must be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. The entries in the (2,2) block of the front are not counted. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:ETree:proto:initializers} \par There are four initializer methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_init1 ( ETree *etree, int nfront, int nvtx ) ; \end{verbatim} \index{ETree_init1@{\tt ETree\_init1()}} This method initializes an {\tt ETree} object given the number of fronts and number of vertices. Any previous data is cleared with a call to {\tt ETree\_clearData()}, The {\tt Tree} object is initialized with a call to {\tt Tree\_init1()}. The {\tt nodwghtsIV}, {\tt bndwghtsIV} and {\tt vtxToFrontIV} objects are initialized with calls to {\tt IV\_init()}. The entries in {\tt nodwghtsIV} and {\tt bndwghtsIV} are set to {\tt 0}, while the entries in {\tt vtxToFrontIV} are set to {\tt -1}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if {\tt nfront} is negative, or if {\tt nvtx < nfront}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_initFromGraph ( ETree *etree, Graph *g ) ; \end{verbatim} \index{ETree_initFromGraph@{\tt ETree\_initFromGraph()}} This method generates an elimination tree from a graph. The {\tt nodwghtsIV} vector object is filled with the weights of the vertices in the graph. The {\tt tree->par} vector and {\tt bndwghtsIV} vector object are filled using the simple $O(|L|)$ algorithm from \cite{liu90-etree}. The {\tt fch[]}, {\tt sib[]} and {\tt root} fields of the included {\tt Tree} object are then set. {\tt vtxToFrontIV}, the {\tt IV} object that holds the map from vertices to fronts, is set to the identity. \par \noindent {\it Error checking:} If {\tt etree} or {\tt g} is {\tt NULL} or {\tt g->nvtx} is negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_initFromGraphWithPerms ( ETree *etree, Graph *g ) ; int newToOld[], int oldToNew[] ) ; \end{verbatim} \index{ETree_initFromGraphWithPerms@{\tt ETree\_initFromGraphWithPerms()}} This method generates an elimination tree from a graph using two permutation vectors. The behavior of the method is exactly the same as the initializer {\tt ETree\_initFromGraph()}, with the exception that {\tt vtxToFrontIV}, the {\tt IV} object that holds the map from vertices to fronts, is set to the {\tt oldToNew[]} map. \par \noindent {\it Error checking:} If {\tt etree} or {\tt g} is {\tt NULL} or {\tt g->nvtx} is negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_initFromDenseMatrix ( ETree *etree, int n, int option, int param ) ; \end{verbatim} \index{ETree_initFromDenseMatrix@{\tt ETree\_initFromDenseMatrix()}} This method initializes a front tree to factor a {\tt n x n} dense matrix. If {\tt option == 1}, then all fronts (save possibly the last) have the same number of internal vertices, namely {\tt param}. If {\tt option == 2}, then we try to make all fronts have the same number of entries in their (1,1), (1,2) and (2,1) blocks, namely {\tt param} entries. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL} or if ${\tt n} <= 0$, or if ${\tt option} < 1$, or if $2 < {\tt option}$ , or if ${\tt param} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_initFromFile ( ETree *etree, char *inETreeFileName, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{ETree_initFromFile@{\tt ETree\_initFromFile()}} This method reads in an {\tt ETree} object from a file, gets the old-to-new vertex permutation, permutes to vertex-to-front map, and returns an {\tt IV} object that contains the old-to-new permutation. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL} or {\tt inETreeFileName} is ``{\tt none}'', an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_initFromSubtree ( ETree *subtree, IV *nodeidsIV, ETree *etree, IV *vtxIV ) ; \end{verbatim} \index{ETree_initFromSubtree@{\tt ETree\_initFromSubtree()}} This method initializes {\tt subtree} from {\tt tree} using the nodes of {\tt etree} that are found in {\tt nodeidsIV}. The map from nodes in {\tt subtree} to nodes in {\tt etree} is returned in {\tt vtxIV}. \par \noindent {\it Return code: } 1 for a normal return, -1 if {\tt subtree} is {\tt NULL}, -2 if {\tt nodeidsIV} is {\tt NULL}, -3 if {\tt etree} is {\tt NULL}, -4 if {\tt nodeidsIV} is invalid, -5 if {\tt vtxIV} is {\tt NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:ETree:proto:utilities} \par The utility methods return the number of bytes taken by the object, or the number of factor indices, entries or operations required by the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_sizeOf ( ETree *etree ) ; \end{verbatim} \index{ETree_sizeOf@{\tt ETree\_sizeOf()}} This method returns the number of bytes taken by this object (which includes the bytes taken by the internal {\tt Tree} structure). \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_nFactorIndices ( ETree *etree ) ; \end{verbatim} \index{ETree_nFactorIndices@{\tt ETree\_nFactorIndices()}} This method returns the number of indices taken by the factor matrix that the tree represents. Note, if the {\tt ETree} object is a vertex elimination tree, the number of indices is equal to the number of entries. If the number of compressed indices is required, create an {\tt ETree} object to represent the tree of fundamental supernodes and then call this method with this compressed tree. \par \noindent {\it Error checking:} If {\tt etree} or {\tt tree} is {\tt NULL} or if $\mbox{\tt nfront} < 1$, or if $\mbox{\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_nFactorEntries ( ETree *etree, int symflag ) ; \end{verbatim} \index{ETree_nFactorEntries@{\tt ETree\_nFactorEntries()}} This method returns the number of entries taken by the factor matrix that the tree represents. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} or {\tt tree} is {\tt NULL}, or if $\mbox{\tt nfront} < 1$, or if $\mbox{\tt nvtx} < 1$, or if {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double ETree_nFactorOps ( ETree *etree, int type, int symflag ) ; \end{verbatim} \index{ETree_nFactorOps@{\tt ETree\_nFactorOps()}} This method returns the number of operations taken by the factor matrix that the tree represents. The {\tt type} parameter can be one of {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} or {\tt tree} is {\tt NULL}, or if $\mbox{\tt nfront} < 1$, or if $\mbox{\tt nvtx} < 1$, or if {\tt type} or {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double ETree_nFactorEntriesInFront ( ETree *etree, int symflag, int J ) ; \end{verbatim} \index{ETree_nFactorEntriesInFront@{\tt ETree\_nFactorEntriesInFront()}} This method returns the number of entries in front {\tt J} for an $LU$ factorization. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} or {\tt tree} is {\tt NULL}, or if $\mbox{\tt nfront} < 1$, or if {\tt symflag} is invalid, or if ${\tt J} < 0$, or if ${\tt J} \ge {\tt nfront}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double ETree_nInternalOpsInFront ( ETree *etree, int type, int symflag, int J ) ; \end{verbatim} \index{ETree_nInternalOpsInFront@{\tt ETree\_nInternalOpsInFront()}} This method returns the number of internal operations performed by front {\tt J} on its $(1,1)$, $(2,1)$, and $(1,2)$ blocks during a factorization. The {\tt type} parameter can be one of {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. {\tt symflag} must be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} or {\tt tree} is {\tt NULL}, or if $\mbox{\tt nfront} < 1$, or if {\tt type} or {\tt symflag} is invalid, or if ${\tt J} < 0$, or if ${\tt J} \ge {\tt nfront}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double ETree_nExternalOpsInFront ( ETree *etree, int type, int symflag, int J ) ; \end{verbatim} \index{ETree_nExternalOpsInFront@{\tt ETree\_nExternalOpsInFront()}} This method returns the number of operations performed by front {\tt J} on its $(2,2)$ block for an $LU$ factorization. The {\tt type} parameter can be one of {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. {\tt symflag} must be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} or {\tt tree} is {\tt NULL}, or if $\mbox{\tt nfront} < 1$, or if {\tt type} or {\tt symflag} is invalid, or if ${\tt J} < 0$, or if ${\tt J} \ge {\tt nfront}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_factorEntriesIV ( ETree *etree, int symflag ) ; \end{verbatim} \index{ETree_factorEntriesIV@{\tt ETree\_factorEntriesIV()}} This method creates and returns an {\tt IV} object that is filled with the number of entries for the fronts. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} DV * ETree_backwardOps ( ETree *etree, int type, int symflag, int vwghts[], IV *symbfacIVL ) ; \end{verbatim} \index{ETree_backwardOps@{\tt ETree\_backwardOps()}} This method creates and returns a {\tt DV} object that is filled with the backward operations (left-looking) for the fronts. The {\tt type} parameter can be one of {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. {\tt symflag} must be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} or {\tt symbfacIVL} is {\tt NULL}, or if {\tt type} or {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} DV * ETree_forwardOps ( ETree *etree, int type, int symflag ) ; \end{verbatim} \index{ETree_forwardOps@{\tt ETree\_forwardOps()}} This method creates and returns a {\tt DV} object that is filled with the forward operations (right-looking) for the fronts. The {\tt type} parameter can be one of {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. {\tt symflag} must be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if {\tt type} or {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ETree * ETree_expand ( ETree *etree, IV *eqmapIV ) ; \end{verbatim} \index{ETree_expand@{\tt ETree\_expand()}} This method creates and returns an {\tt ETree} object for an uncompressed graph. The map from compressed vertices to uncompressed vertices is found in the {\tt eqmapIV} object. \par \noindent {\it Error checking:} If {\tt etree} or {\tt eqmapIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ETree * ETree_spliceTwoEtrees ( ETree *etree0, Graph *graph, IV *mapIV, ETree *etree1 ) ; \end{verbatim} \index{ETree_spliceTwoEtrees@{\tt ETree\_spliceTwoEtrees()}} This method creates and returns an {\tt ETree} object that is formed by splicing together two front trees, {\tt etree0} for the vertices the eliminated domains, {\tt etree1} for the vertices the Schur complement. The {\tt mapIV} object maps vertices to domains or the Schur complement --- if the entry is {\tt 0}, the vertex is in the Schur complement, otherwise it is in a domain. \par \noindent {\it Error checking:} If {\tt etree0}, {\tt graph}, {\tt mapIV} or {\tt etree1} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \subsection{Metrics methods} \label{subsection:ETree:proto:metrics} \par Many operations need to know some {\it metric} defined on the nodes in a etree. Here are three examples: \begin{itemize} \item the weight of each front in the tree (this is just the {\tt nodwghtsIV} object); \item the number of factor entries in each front \item the number of factor operations associated with each front in a forward looking factorization. \end{itemize} Other metrics based on height, depth or subtree accumulation can be evaluated using the {\tt Tree} metric methods on the {\tt Tree} object contained in the {\tt ETree} object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_nvtxMetric ( ETree *etree ) ; \end{verbatim} \index{ETree_nvtxMetric@{\tt ETree\_nvtxMetric()}} An {\tt IV} object of size {\tt nvtx} is created, filled with the entries from {\tt etree->nodwghtsIV}, and returned. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_nentMetric ( ETree *etree, int symflag ) ; \end{verbatim} \index{ETree_nentMetric@{\tt ETree\_nentMetric()}} An {\tt IV} object of size {\tt nfront} is created and returned. Each entry of the vector is filled with the number of factor entries associated with the corresponding front. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} DV * ETree_nopsMetric ( ETree *etree, int type, int symflag ) ; \end{verbatim} \index{ETree_nopsMetric@{\tt ETree\_nopsMetric()}} An {\tt DV} object of size {\tt nfront} is created and returned. Each entry of the vector is filled with the number of factor operations associated with the corresponding front. The {\tt type} parameter can be one of {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, or if {\tt type} or {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Compression methods} \label{subsection:ETree:proto:compression} \par Frequently an {\tt ETree} object will need to be compressed in some manner. Elimination trees usually have long chains of vertices at the higher levels, where each chain of vertices corresponds to a supernode. Liu's generalized row envelope methods partition the vertices by longest chains \cite{liu91-generalizedEnvelope}. In both cases, we can construct a map from each node to a set of nodes to define a smaller, more compact {\tt ETree} object. Given such a map, we construct the smaller etree. \par A fundamental chain is a set of vertices $v_1, \ldots, v_m$ such that \begin{enumerate} \item $v_1$ is a leaf or has two or more children, \item $v_i$ is the only child of $v_{i+1}$ for $1 \le i < m$, \item $v_m$ is either a root or has a sibling. \end{enumerate} The set of fundamental chains is uniquely defined. In the context of elimination etrees, a fundamental chain is very close to a fundamental supernode, and in many cases, fundamental chains can be used to contruct the fronts with little added fill and factor operations. \par A fundamental supernode \cite{ash89-relaxed} is a set of vertices $v_1, \ldots, v_m$ such that \begin{enumerate} \item $v_1$ is a leaf or has two or more children, \item $v_i$ is the only child of $v_{i+1}$ for $1 \le i < m$, \item $v_m$ is either a root or has a sibling, and \item the structures of $v_i$ and $v_{i+1}$ are nested, i.e., {\tt bndwght[$v_i$] = nodwght[$v_{i+1}$] + bndwght[$v_{i+1}$]} for $1 \le i < m$. \end{enumerate} The set of fundamental supernodes is uniquely defined. \par Once a map from the nodes in a tree to nodes in a compressed tree is known, the compressed tree can be created using the {\tt ETree\_compress()} method. In this way, a vertex elimination tree can be used to generate a front tree. %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_fundChainMap ( ETree *etree ) ; \end{verbatim} \index{ETree_fundChainMap@{\tt ETree\_fundChainMap()}} An {\tt IV} object of size {\tt nfront} is created, filled via a call to {\tt Tree\_fundChainMap}, then returned. \par \noindent {\it Error checking:} If {\tt etree} or {\tt tree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_fundSupernodeMap ( ETree *etree ) ; \end{verbatim} \index{ETree_fundSupernodeMap@{\tt ETree\_fundSupernodeMap()}} An {\tt IV} object of size {\tt nfront} is created, filled with the map from vertices to fundamental supernodes, then returned. \par \noindent {\it Error checking:} If {\tt etree} or {\tt tree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ETree * ETree_compress ( ETree *etree, IV *frontMapIV ) ; \end{verbatim} \index{ETree_compress@{\tt ETree\_compress()}} Using {\tt frontMapIV}, a new {\tt ETree} object is created and returned. If {\tt frontMapIV} does not define each inverse map of a new node to be connected set of nodes in the old {\tt ETree} object, the new {\tt ETree} object will not be well defined. \par \noindent {\it Error checking:} If {\tt etree} or {\tt frontMapIV} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Justification methods} \label{subsection:ETree:proto:justify} \par Given an {\tt ETree} object, how should the children of a node be ordered? This ``justification'' can have a large impact in the working storage for the front etree in the multifrontal algorithm \cite{liu85-mfstorage}. Justification also is useful when displaying trees. These methods simply check for errors and then call the appropriate {\tt Tree} method. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_leftJustify ( ETree *etree ) ; \end{verbatim} \index{ETree_leftJustify@{\tt ETree\_leftJustify()}} If {\tt u} and {\tt v} are siblings, and {\tt u} comes before {\tt v} in a post-order traversal, then the size of the subtree rooted at {\tt u} is as large or larger than the size of the subtree rooted at {\tt v}. \par \noindent {\it Error checking:} If {\tt etree} or {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_leftJustifyI ( ETree *etree, IV *metricIV ) ; void ETree_leftJustifyD ( ETree *etree, DV *metricDV ) ; \end{verbatim} \index{ETree_leftJustifyI@{\tt ETree\_leftJustifyI()}} \index{ETree_leftJustifyD@{\tt ETree\_leftJustifyD()}} Otherwise, if {\tt u} and {\tt v} are siblings, and {\tt u} comes before {\tt v} in a post-order traversal, then the weight of the subtree rooted at {\tt u} is as large or larger than the weight of the subtree rooted at {\tt v}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, or if {\tt metricIV} is {\tt NULL} or invalid (wrong size or {\tt NULL} vector inside), an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Permutation methods} \label{subsection:ETree:proto:permutation} \par Often we need to extract a permutation from an {\tt ETree} object, e.g., a post-order traversal of a front tree gives an ordering of the fronts for a factorization or forward solve, the inverse gives an ordering for a backward solve. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_newToOldFrontPerm ( ETree *etree ) ; IV * ETree_oldToNewFrontPerm ( ETree *etree ) ; \end{verbatim} \index{ETree_newToOldFrontPerm@{\tt ETree\_newToOldFrontPerm()}} \index{ETree_oldToNewFrontPerm@{\tt ETree\_oldToNewFrontPerm()}} An {\tt IV} object is created with size {\tt nfront}. A post-order traversal of the {\tt Tree} object fills the new-to-old permutation. A reversal of the new-to-old permutation gives the old-to-new permutation. Both methods are simply wrappers around the respective {\tt Tree} methods. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_newToOldVtxPerm ( ETree *etree ) ; IV * ETree_oldToNewVtxPerm ( ETree *etree ) ; \end{verbatim} \index{ETree_newToOldVtxPerm@{\tt ETree\_newToOldVtxPerm()}} \index{ETree_oldToNewVtxPerm@{\tt ETree\_oldToNewVtxPerm()}} An {\tt IV} object is created with size {\tt nvtx}. First we find a new-to-old permutation of the fronts. Then we search over the fronts in their new order to fill the vertex new-to-old permutation vector. The old-to-new vertex permutation vector is found by first finding the new-to-old vertex permutation vector, then inverting it. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_permuteVertices ( ETree *etree, IV *vtxOldToNewIV ) ; \end{verbatim} \index{ETree_permuteVertices@{\tt ETree\_permuteVertices()}} This method permutes the vertices --- the {\tt vtxToFrontIV} map is updated to reflect the new vertex numbering. \par \noindent {\it Error checking:} If {\tt etree} or {\tt vtxOldToNewIV} is {\tt NULL}, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Multisector methods} \label{subsection:ETree:proto:multisector} One of our goals is to improve a matrix ordering using the multisection ordering algorithm. To do this, we need to extract a multisector from the vertices, i.e., a set of nodes that when removed from the graph, break the remaining vertices into more than one (typically many) components. The following two methods create and return an {\tt IV} integer vector object that contains the nodes in the multisector. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_msByDepth ( ETree *etree, int depth ) ; \end{verbatim} \index{ETree_msByDepth@{\tt ETree\_msByDepth()}} An {\tt IV} object is created to hold the multisector nodes and returned. Multisector nodes have their component id zero, domain nodes have their component id one. A vertex is in the multisector if the depth of the front to which it belongs is less than or equal to {\tt depth}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, or if ${\tt depth} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_msByNvtxCutoff ( ETree *etree, double cutoff ) ; \end{verbatim} \index{ETree_msByNvtxCutoff@{\tt ETree\_msByNvtxCutoff()}} An {\tt IV} object is created to hold the multisector nodes and returned. Multisector nodes have their component id zero, domain nodes have their component id one. Inclusion in the multisector is based on the number of vertices in the subtree that a vertex belongs, or strictly speaking, the number of vertices in the subtree of the front to which a vertex belongs. If weight of the subtree is more than {\tt cutoff} times the vertex weight, the vertex is in the multisector. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_msByNentCutoff ( ETree *etree, double cutoff, int symflag ) ; \end{verbatim} \index{ETree_msByNentCutoff@{\tt ETree\_msByNentCutoff()}} An {\tt IV} object is created to hold the multisector nodes and returned. Multisector nodes have their component id zero, domain nodes have their component id one. Inclusion in the multisector is based on the number of factor entries in the subtree that a vertex belongs, or strictly speaking, the number of factor entries in the subtree of the front to which a vertex belongs. If weight of the subtree is more than {\tt cutoff} times the number of factor entries, the vertex is in the multisector. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, or if {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_msByNopsCutoff ( ETree *etree, double cutoff, int type, int symflag ) ; \end{verbatim} \index{ETree_msByNopsCutoff@{\tt ETree\_msByNopsCutoff()}} An {\tt IV} object is created to hold the multisector nodes and returned. Multisector nodes have their component id zero, domain nodes have their component id one. Inclusion in the multisector is based on the number of right-looking factor operations in the subtree that a vertex belongs, or strictly speaking, the number of factor operations in the subtree of the front to which a vertex belongs. If weight of the subtree is more than {\tt cutoff} times the number of factor operations, the vertex is in the multisector. The {\tt type} parameter can be one of {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, or if {\tt type} or {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_msStats ( ETree *etree, IV *msIV, IV *nvtxIV, IV *nzfIV, DV *opsDV, int type, int symflag ) ; \end{verbatim} \index{ETree_msStats@{\tt ETree\_msStats()}} This method is used to generate some statistics about a domain decomposition. On input, {\tt msIV} is a flag vector, i.e., {\tt ms[v] = 0} means that {\tt v} is in the Schur complement, otherwise {\tt v} is in domain. On output, {\tt msIV} is a map from nodes to regions, i.e., {\tt ms[v] = 0} means that {\tt v} is in the Schur complement, otherwise {\tt v} is in domain {\tt ms[v]}. On output, {\tt nvtxIV} contains the number of vertices in each of the regions, {\tt nzfIV} contains the number of factor entries in each of the regions, and {\tt opsIV} contains the number of factor operations in each of the regions. The {\tt type} parameter can be one of {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree}, {\tt msIV}, {\tt nvtxIV}, {\tt nzfIV} or {\tt opsIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_optPart ( ETree *etree, Graph *graph, IVL *symbfacIVL, double alpha, int *ptotalgain, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{ETree_optPart@{\tt ETree\_optPart()}} This method is used to find the optimal domain/Schur complement partition for a semi-implicit factorization. The gain of a subtree ${\widehat J}$ is equal to $|L_{\partial{J},{\widehat J}}| - |A_{\partial{J},{\widehat J}}| - \alpha |L_{{\widehat J},{\widehat J}}|$. When $\alpha = 0$, we minimize active storage, when $\alpha = 1$, we minimize solve operations. On return, {\tt *ptotalgain} is filled with the total gain. The return value is a pointer to {\tt compidsIV}, where {\tt compids[J] = 0} means that {\tt J} is in the Schur complement, and {\tt compids[J] != 0} means that {\tt J} is in domain {\tt compids[J]}. \par \noindent {\it Error checking:} If {\tt etree}, {\tt graph} or {\tt symbfacIVL} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Transformation methods} \label{subsection:ETree:proto:transformation} Often the elimination tree or front tree that we obtain from an ordering of the graph is not as appropriate for a factorization as we would like. There are two important cases. \begin{itemize} \item Near the leaves of the tree the fronts are typically small in size. There is an overhead associated with each front, and though the overhead varies with regard to the factorization algorithm, it can be beneficial to group small subtrees together into one front. The expense is added storage for the logically zero entries and the factor operations on them. In this library, the technique we use to merge fronts together is {\it node amalgamation} \cite{duf83-multifrontal}, or more specifically {\it supernode relaxation} \cite{ash89-relaxed}. \item Near the root of the tree the fronts can be very large, large enough that special techniques are necessary to handle the large dense frontal matrices that might not be able to exist in-core. Another consideration is a parallel setting where the design decision is to have each front be factored by a single thread of computation. Large fronts dictate a long critical path in the factorization task graph. We try to split a large front into two or more smaller fronts that form a chain in the front tree. Breaking the front into smaller fronts will reduce core storage requirements and have better cache reuse and reduce the critical path through the task graph. \end{itemize} We provide three methods to merge fronts together and one method to break fronts apart, and one method that is a wrapper around all these. Let us describe the differences between the methods that merge fronts together. Each method performs a post-order traversal of the front tree. They differ on the decision process when visiting a front. \begin{itemize} \item The method {\tt ETree\_mergeFrontsAny()} is taken from \cite{ash89-relaxed}. When visiting a front it tries to merge that front with one of its children if it will not add too many zero entries to that front. If successful, it tries to merge the front with another child. This approach has served well for over a decade in a serial environment, but we discovered that it has a negative effect on nested dissection orderings when we want a parallel factorization. Often it merges the top level separator with {\it one} of its children, and thus reduces parallelism in the front tree. \item The method {\tt ETree\_mergeFrontsOne()} only tries to merge a front when it has only one child. This method is very useful if one has a vertex elimination tree (where the number of fronts is equal to the number of vertices), for the fundamental supernode tree can be created using {\tt maxzeros = 0}. This method has some affect for minimum degree or fill orderings, where chains of nodes can occur in two ways: aggregation (where a vertex is eliminated that is adjacent to only one subtree) or when the indistinguishabilty test fails. In general, this method does not effectively reduce the number of fronts because it has the ``parent-only child'' restriction. \item The method {\tt ETree\_mergeFrontsAll()} tries to merge a front with {\it all} of its children, if the resulting front does not contain too many zero entries. This has the effect of merging small bushy subtrees, but will not merge a top level separator with one of its children. \end{itemize} For a serial application, {\tt ETree\_mergeFrontsAny()} is suitable. For a parallel application, we recommend first using {\tt ETree\_mergeFrontsOne()} followed by {\tt ETree\_mergeFrontsAll()}. See the driver programs {\tt testTransform} and {\tt mkNDETree} for examples of how to call the methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} ETree * ETree_mergeFrontsOne ( ETree *etree, int maxzeros, IV *nzerosIV ) ; \end{verbatim} \index{ETree_mergeFrontsOne@{\tt ETree\_mergeFrontsOne()}} This method only tries to merge a front with its only child. It returns an {\tt ETree} object where one or more subtrees that contain multiple fronts have been merged into single fronts. The parameter that governs the merging process is {\tt maxzeros}, the number of zero entries that can be introduced by merging a child and parent front together. On input, {\tt nzerosIV} contains the number of zeros presently in each front. It is modified on output to correspond with the new front tree. This method only tries to merge a front with its only child. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ETree * ETree_mergeFrontsAll ( ETree *etree, int maxzeros ) ; \end{verbatim} \index{ETree_mergeFrontsAll@{\tt ETree\_mergeFrontsAll()}} This method only tries to merge a front with all of its children. It returns an {\tt ETree} object where a front has either been merged with none or all of its children. The parameter that governs the merging process is {\tt maxzeros}, the number of zero entries that can be introduced by merging the children and parent front together. On input, {\tt nzerosIV} contains the number of zeros presently in each front. It is modified on output to correspond with the new front tree. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ETree * ETree_mergeFrontsAny ( ETree *etree, int maxzeros ) ; \end{verbatim} \index{ETree_mergeFrontsAny@{\tt ETree\_mergeFrontsAny()}} This method only tries to merge a front with any subset of its children. It returns an {\tt ETree} object where a front has possibly merged with any of its children. The parameter that governs the merging process is {\tt maxzeros}, the number of zero entries that can be introduced by merging the children and parent front together. On input, {\tt nzerosIV} contains the number of zeros presently in each front. It is modified on output to correspond with the new front tree. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ETree * ETree_splitFronts ( ETree *etree, int vwghts[], int maxfrontsize, int seed ) ; \end{verbatim} \index{ETree_splitFronts@{\tt ETree\_splitFronts()}} This method returns an {\tt ETree} object where one or more large fronts have been split into smaller fronts. Only an interior front (a front that is not a leaf in the tree) can be split. No front in the returned {\tt ETree} object has more than {\tt maxfrontsize} rows and columns. The {\tt vwghts[]} vector stores the number of degrees of freedom associated with a vertex; if {\tt vwghts} is {\tt NULL}, then the vertices have unit weight. The way the vertices in a front to be split are assigned to smaller fronts is random; the {\tt seed} parameter is a seed to a random number generator that permutes the vertices in a front. \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, or if ${\tt maxfrontsize} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ETree * ETree_transform ( ETree *etree, int vwghts[], int maxzeros, int maxfrontsize, int seed ) ; ETree * ETree_transform2 ( ETree *etree, int vwghts[], int maxzeros, int maxfrontsize, int seed ) ; \end{verbatim} \index{ETree_transform@{\tt ETree\_transform()}} \index{ETree_transform2@{\tt ETree\_transform2()}} These methods returns an {\tt ETree} object where one or more subtrees that contain multiple fronts have been merged into single fronts and where one or more large fronts have been split into smaller fronts. The two methods differ slightly. {\tt ETree\_transform2()} is better suited for parallel computing because it tends to preserve the tree branching properties. (A front is merged with either an only child or all children. {\tt ETree\_transform()} can merge a front with any subset of its children.) \par \noindent {\it Error checking:} If {\tt etree} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, or if ${\tt maxfrontsize} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Parallel factorization map methods} \label{subsection:ETree:proto:map} This family of methods create a map from the fronts to processors or threads, used in a parallel factorization. \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IV * ETree_wrapMap ( ETree *etree, int type, int symflag, DV *cumopsDV ) ; IV * ETree_balancedMap ( ETree *etree, int type, int symflag, DV *cumopsDV ) ; IV * ETree_subtreeSubsetMap ( ETree *etree, int type, int symflag,DV *cumopsDV ) ; IV * ETree_ddMap ( ETree *etree, int type, int symflag, DV *cumopsDV, double cutoff ) ; IV * ETree_ddMapNew ( ETree *etree, int type, int symflag, IV *msIV, DV *cumopsDV ) ; \end{verbatim} \index{ETree_wrapMap@{\tt ETree\_wrapMap()}} \index{ETree_balancedMap@{\tt ETree\_balancedMap()}} \index{ETree_subtreeSubsetMap@{\tt ETree\_subtreeSubsetMap()}} \index{ETree_ddMap@{\tt ETree\_ddMap()}} \index{ETree_ddMapNew@{\tt ETree\_ddMapNew()}} These methods construct and return an {\tt IV} object that contains the map from fronts to threads. The size of the input {\tt cumopsDV} object is the number of threads or processors. On output, {\tt cumopsDV} contains the number of factor operations performed by the threads or processors for a fan-in factorization. The {\tt type} parameter can be one of {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. {\tt symflag} must be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \begin{itemize} \item The simplest map is the {\it wrap map}, where front {\tt J} is assigned to thread or processor {\tt J \% nthread}. \item The {\it balanced map} attempts to balance the computations across the threads or processes, where the fronts are visited in a post-order traversal of the tree and a front is assigned to a thread or processor with the least number of accumulated operations thus far. \item The {\it subtree-subset map} is the most complex, where subsets of threads or processors are assigned to subtrees via a pre-order traversal of the tree. (Each root of the tree can be assigned to all processors.) The tree is then visited in a post-order traversal, and each front is assigned to an eligible thread or processor with the least number of accumulated ops so far. \item The {\it domain decomposition map} is also complex, where domains are mapped to threads, then the fronts in the schur complement are mapped to threads, both using independent balanced maps. The method {\tt ETree\_ddMapNew()} is more robust than {\tt ETree\_ddMap()}, and is more general in the sense that it takes a multisector vector as input. The {\tt msIV} object is a map from the vertices to $\{0,1\}$. A vertex mapped to 0 lies in the Schur complement, a vertex mapped to 1 lies in a domain. \end{itemize} \par \noindent {\it Error checking:} If {\tt etree} or {\tt cumopsDV} is {\tt NULL}, or if {\tt type} or {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Storage profile methods} \label{subsection:ETree:proto:storage} \par These methods fill a vector with the total amount of working storage necessary during the factor and solves. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_MFstackProfile ( ETree *etree, int type, double dvec[] ) ; \end{verbatim} \index{ETree_MFstackProfile@{\tt ETree\_MFstackProfile()}} \par On return, {\tt dvec[J]} contains the amount of active storage to eliminate {\tt J} using the multifrontal method and the natural post-order traversal. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} or {\tt dvec} are {\tt NULL}, or if {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_GSstorageProfile ( ETree *etree, int type, IVL *symbfacIVL, int *vwghts, double dvec[] ) ; \end{verbatim} \index{ETree_GSstorageProfile@{\tt ETree\_GSstorageProfile()}} \par On return, {\tt dvec[J]} contains the amount of active storage to eliminate {\tt J} using the left-looking general sparse method and the natural post-order traversal. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} or {\tt dvec} are {\tt NULL}, or if {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_FSstorageProfile ( ETree *etree, int type, IVL *symbfacIVL, double dvec[] ) ; \end{verbatim} \index{ETree_FSstorageProfile@{\tt ETree\_FSstorageProfile()}} \par On return, {\tt dvec[J]} contains the amount of active storage to eliminate {\tt J} using the right-looking forward sparse method and the natural post-order traversal. The {\tt symflag} parameter can be one of {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \par \noindent {\it Error checking:} If {\tt etree} or {\tt dvec} are {\tt NULL}, or if {\tt symflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_forwSolveProfile ( ETree *etree, double dvec[] ) ; \end{verbatim} \index{ETree_forwSolveProfile@{\tt ETree\_forwSolveProfile()}} \par On return, {\tt dvec[J]} contains the amount of stack storage to solve for {\tt J} using the multifrontal-based forward solve. \par \noindent {\it Error checking:} If {\tt etree} or {\tt dvec} are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ETree_backSolveProfile ( ETree *etree, double dvec[] ) ; \end{verbatim} \index{ETree_backSolveProfile@{\tt ETree\_backSolveProfile()}} \par On return, {\tt dvec[J]} contains the amount of stack storage to solve for {\tt J} using the multifrontal-based backward solve. \par \noindent {\it Error checking:} If {\tt etree} or {\tt dvec} are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:ETree:proto:IO} \par There are the usual eight IO routines. The file structure of a tree object is simple: {\tt nfront}, {\tt nvtx}, a {\tt Tree} object followed by the {\tt nodwghtsIV}, {\tt bndwghtsIV} and {\tt vtxToFrontIV} objects. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_readFromFile ( ETree *etree, char *fn ) ; \end{verbatim} \index{ETree_readFromFile@{\tt ETree\_readFromFile()}} \par This method reads an {\tt ETree} object from a file whose name is stored in {\tt *fn}. It tries to open the file and if it is successful, it then calls {\tt ETree\_readFromFormattedFile()} or {\tt ETree\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt etree} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.etreef} (for a formatted file) or {\tt *.etreeb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_readFromFormattedFile ( ETree *etree, FILE *fp ) ; \end{verbatim} \index{ETree_readFromFormattedFile@{\tt ETree\_readFromFormattedFile()}} \par This method reads an {\tt ETree} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt etree} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_readFromBinaryFile ( ETree *etree, FILE *fp ) ; \end{verbatim} \index{ETree_readFromBinaryFile@{\tt ETree\_readFromBinaryFile()}} \par This method reads an {\tt ETree} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt etree} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_writeToFile ( ETree *etree, char *fn ) ; \end{verbatim} \index{ETree_writeToFile@{\tt ETree\_writeToFile()}} \par This method writes an {\tt ETree} object to a file whose name is stored in {\tt *fn}. An attempt is made to open the file and if successful, it then calls {\tt ETree\_writeFromFormattedFile()} for a formatted file, or {\tt ETree\_writeFromBinaryFile()} for a binary file. The method then closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt etree} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.etreef} (for a formatted file) or {\tt *.etreeb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_writeToFormattedFile ( ETree *etree, FILE *fp ) ; \end{verbatim} \index{ETree_writeToFormattedFile@{\tt ETree\_writeToFormattedFile()}} \par This method writes an {\tt ETree} object to a formatted file. Otherwise, the data is written to the file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt etree} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_writeToBinaryFile ( ETree *etree, FILE *fp ) ; \end{verbatim} \index{ETree_writeToBinaryFile@{\tt ETree\_writeToBinaryFile()}} \par This method writes an {\tt ETree} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt etree} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_writeForHumanEye ( ETree *etree, FILE *fp ) ; \end{verbatim} \index{ETree_writeForHumanEye@{\tt ETree\_writeForHumanEye()}} \par This method writes an {\tt ETree} object to a file in a readable format. Otherwise, the method {\tt ETree\_writeStats()} is called to write out the header and statistics. Then the parent, first child, sibling, node weight and boundary weight values are printed out in five columns. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt etree} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ETree_writeStats ( ETree *etree, FILE *fp ) ; \end{verbatim} \index{ETree_writeStats@{\tt ETree\_writeStats()}} \par This method write a header and some statistics to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt etree} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} r processors are assigned to subtrees via a pre-order traversal of the tree. (Each root of the tree can be assigned to all processors.) The tree is then visited in a post-order traversal, and each front is assigned to an eligible thread or processor with the least number of accumulated ops so far. \item The {\it domain decomposition map} is also complex, where domains are mapped to threads, then the fronts in the schur complement are mapped to thrETree/doc/main.ind010064400020550007177000000062710665314224700153010ustar00clevecompmath00000400000006\begin{theindex} \item {\tt ETree\_backSolveProfile()}, 17 \item {\tt ETree\_backwardOps()}, 7 \item {\tt ETree\_balancedMap()}, 15 \item {\tt ETree\_bndwghts()}, 4 \item {\tt ETree\_bndwghtsIV()}, 3 \item {\tt ETree\_clearData()}, 2 \item {\tt ETree\_compress()}, 10 \item {\tt ETree\_ddMap()}, 15 \item {\tt ETree\_ddMapNew()}, 15 \item {\tt ETree\_expand()}, 7 \item {\tt ETree\_factorEntriesIV()}, 7 \item {\tt ETree\_fch()}, 3 \item {\tt ETree\_forwardOps()}, 7 \item {\tt ETree\_forwSolveProfile()}, 16 \item {\tt ETree\_free()}, 2 \item {\tt ETree\_frontBoundarySize()}, 4 \item {\tt ETree\_frontSize()}, 4 \item {\tt ETree\_FSstorageProfile()}, 16 \item {\tt ETree\_fundChainMap()}, 9 \item {\tt ETree\_fundSupernodeMap()}, 9 \item {\tt ETree\_GSstorageProfile()}, 16 \item {\tt ETree\_init1()}, 4 \item {\tt ETree\_initFromDenseMatrix()}, 5 \item {\tt ETree\_initFromFile()}, 5 \item {\tt ETree\_initFromGraph()}, 5 \item {\tt ETree\_initFromGraphWithPerms()}, 5 \item {\tt ETree\_initFromSubtree()}, 5 \item {\tt ETree\_leftJustify()}, 10 \item {\tt ETree\_leftJustifyD()}, 10 \item {\tt ETree\_leftJustifyI()}, 10 \item {\tt ETree\_maxNindAndNent()}, 4 \item {\tt ETree\_mergeFrontsAll()}, 14 \item {\tt ETree\_mergeFrontsAny()}, 14 \item {\tt ETree\_mergeFrontsOne()}, 14 \item {\tt ETree\_MFstackProfile()}, 16 \item {\tt ETree\_msByDepth()}, 11 \item {\tt ETree\_msByNentCutoff()}, 11 \item {\tt ETree\_msByNopsCutoff()}, 12 \item {\tt ETree\_msByNvtxCutoff()}, 11 \item {\tt ETree\_msStats()}, 12 \item {\tt ETree\_nentMetric()}, 8 \item {\tt ETree\_new()}, 2 \item {\tt ETree\_newToOldFrontPerm()}, 10 \item {\tt ETree\_newToOldVtxPerm()}, 11 \item {\tt ETree\_nExternalOpsInFront()}, 7 \item {\tt ETree\_nFactorEntries()}, 6 \item {\tt ETree\_nFactorEntriesInFront()}, 6 \item {\tt ETree\_nFactorIndices()}, 6 \item {\tt ETree\_nFactorOps()}, 6 \item {\tt ETree\_nfront()}, 2 \item {\tt ETree\_nInternalOpsInFront()}, 7 \item {\tt ETree\_nodwghts()}, 3 \item {\tt ETree\_nodwghtsIV()}, 3 \item {\tt ETree\_nopsMetric()}, 8 \item {\tt ETree\_nvtx()}, 3 \item {\tt ETree\_nvtxMetric()}, 8 \item {\tt ETree\_oldToNewFrontPerm()}, 10 \item {\tt ETree\_oldToNewVtxPerm()}, 11 \item {\tt ETree\_optPart()}, 12 \item {\tt ETree\_par()}, 3 \item {\tt ETree\_permuteVertices()}, 11 \item {\tt ETree\_readFromBinaryFile()}, 17 \item {\tt ETree\_readFromFile()}, 17 \item {\tt ETree\_readFromFormattedFile()}, 17 \item {\tt ETree\_root()}, 3 \item {\tt ETree\_setDefaultFields()}, 2 \item {\tt ETree\_sib()}, 3 \item {\tt ETree\_sizeOf()}, 6 \item {\tt ETree\_spliceTwoEtrees()}, 8 \item {\tt ETree\_splitFronts()}, 14 \item {\tt ETree\_subtreeSubsetMap()}, 15 \item {\tt ETree\_transform()}, 15 \item {\tt ETree\_transform2()}, 15 \item {\tt ETree\_tree()}, 3 \item {\tt ETree\_vtxToFront()}, 4 \item {\tt ETree\_vtxToFrontIV()}, 4 \item {\tt ETree\_wrapMap()}, 15 \item {\tt ETree\_writeForHumanEye()}, 18 \item {\tt ETree\_writeStats()}, 18 \item {\tt ETree\_writeToBinaryFile()}, 18 \item {\tt ETree\_writeToFile()}, 17 \item {\tt ETree\_writeToFormattedFile()}, 17 \end{theindex} ETree/doc/main.ilg010064400020550007177000000004570665314224700153020ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (82 entries accepted, 0 rejected). Sorting entries....done (511 comparisons). Generating output file main.ind....done (86 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. ETree/doc/workingStorage.eps010064400020550007177000001215760653410607500174020ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%Creator: MATLAB, The Mathworks, Inc. %%Title: workingStorage.eps %%CreationDate: 09/05/97 13:55:11 %%DocumentNeededFonts: Helvetica %%DocumentProcessColors: Cyan Magenta Yellow Black %%Pages: 1 %%BoundingBox: 56 201 549 600 %%EndComments %%BeginProlog % MathWorks dictionary /MathWorks 150 dict begin % definition operators /bdef {bind def} bind def /ldef {load def} bind def /xdef {exch def} bdef /xstore {exch store} bdef % operator abbreviations /c /clip ldef /cc /concat ldef /cp /closepath ldef /gr /grestore ldef /gs /gsave ldef /mt /moveto ldef /np /newpath ldef /cm /currentmatrix ldef /sm /setmatrix ldef /rc {rectclip} bdef /rf {rectfill} bdef /rm /rmoveto ldef /rl /rlineto ldef /s /show ldef /sc {setcmykcolor} bdef /sr /setrgbcolor ldef /sg /setgray ldef /w /setlinewidth ldef /j /setlinejoin ldef /cap /setlinecap ldef % page state control /pgsv () def /bpage {/pgsv save def} bdef /epage {pgsv restore} bdef /bplot /gsave ldef /eplot {stroke grestore} bdef % orientation switch /portraitMode 0 def /landscapeMode 1 def % coordinate system mappings /dpi2point 0 def % font control /FontSize 0 def /FMS { /FontSize xstore %save size off stack findfont [FontSize 0 0 FontSize neg 0 0] makefont setfont }bdef /reencode { exch dup where {pop load} {pop StandardEncoding} ifelse exch dup 3 1 roll findfont dup length dict begin { 1 index /FID ne {def}{pop pop} ifelse } forall /Encoding exch def currentdict end definefont pop } bdef /isroman { findfont /CharStrings get /Agrave known } bdef /FMSR { 3 1 roll 1 index dup isroman {reencode} {pop pop} ifelse exch FMS } bdef /csm { 1 dpi2point div -1 dpi2point div scale neg translate landscapeMode eq {90 rotate} if } bdef % line types: solid, dotted, dashed, dotdash /SO { [] 0 setdash } bdef /DO { [.5 dpi2point mul 4 dpi2point mul] 0 setdash } bdef /DA { [6 dpi2point mul] 0 setdash } bdef /DD { [.5 dpi2point mul 4 dpi2point mul 6 dpi2point mul 4 dpi2point mul] 0 setdash } bdef % macros for lines and objects /L { lineto stroke } bdef /MP { 3 1 roll moveto 1 sub {rlineto} repeat } bdef /AP { {rlineto} repeat } bdef /PP { closepath eofill } bdef /DP { closepath stroke } bdef /MR { 4 -2 roll moveto dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath } bdef /FR { MR stroke } bdef /PR { MR fill } bdef /L1i { { currentfile picstr readhexstring pop } image } bdef /tMatrix matrix def /MakeOval { newpath tMatrix currentmatrix pop translate scale 0 0 1 0 360 arc tMatrix setmatrix } bdef /FO { MakeOval stroke } bdef /PO { MakeOval fill } bdef /PD { currentlinecap 1 setlinecap 3 1 roll 2 copy moveto lineto stroke setlinecap } bdef /FA { newpath tMatrix currentmatrix pop translate scale 0 0 1 5 -2 roll arc tMatrix setmatrix stroke } bdef /PA { newpath tMatrix currentmatrix pop translate 0 0 moveto scale 0 0 1 5 -2 roll arc closepath tMatrix setmatrix fill } bdef /FAn { newpath tMatrix currentmatrix pop translate scale 0 0 1 5 -2 roll arcn tMatrix setmatrix stroke } bdef /PAn { newpath tMatrix currentmatrix pop translate 0 0 moveto scale 0 0 1 5 -2 roll arcn closepath tMatrix setmatrix fill } bdef currentdict end def %%EndProlog %%BeginSetup MathWorks begin 0 cap end %%EndSetup %%Page: 1 1 %%BeginPageSetup %%PageBoundingBox: 56 201 549 600 MathWorks begin bpage %%EndPageSetup %%BeginObject: graph1 1 bplot /dpi2point 12 def portraitMode 0216 7344 csm 466 133 5913 4797 MR c np 88 dict begin %Colortable dictionary /c0 { 0 0 0 sr} bdef /c1 { 1 1 1 sr} bdef /c2 { 1 0 0 sr} bdef /c3 { 0 1 0 sr} bdef /c4 { 0 0 1 sr} bdef /c5 { 1 1 0 sr} bdef /c6 { 1 0 1 sr} bdef /c7 { 0 1 1 sr} bdef 1 j 1 sg 0 0 6916 5185 PR 6 w 0 4225 5358 0 0 -4225 899 4613 4 MP PP -5358 0 0 4225 5358 0 0 -4225 899 4613 5 MP stroke DO 4 w SO 6 w 0 sg 899 4613 mt 6257 4613 L 899 388 mt 6257 388 L 899 4613 mt 899 388 L 6257 4613 mt 6257 388 L 899 4613 mt 6257 4613 L 899 4613 mt 899 388 L 899 4613 mt 899 4559 L 899 388 mt 899 442 L %%IncludeResource: font Helvetica /Helvetica /ISOLatin1Encoding 120 FMSR 866 4759 mt (0) s 1435 4613 mt 1435 4559 L 1435 388 mt 1435 442 L 1352 4759 mt (0.1) s 1971 4613 mt 1971 4559 L 1971 388 mt 1971 442 L 1888 4759 mt (0.2) s 2506 4613 mt 2506 4559 L 2506 388 mt 2506 442 L 2423 4759 mt (0.3) s 3042 4613 mt 3042 4559 L 3042 388 mt 3042 442 L 2959 4759 mt (0.4) s 3578 4613 mt 3578 4559 L 3578 388 mt 3578 442 L 3495 4759 mt (0.5) s 4114 4613 mt 4114 4559 L 4114 388 mt 4114 442 L 4031 4759 mt (0.6) s 4650 4613 mt 4650 4559 L 4650 388 mt 4650 442 L 4567 4759 mt (0.7) s 5185 4613 mt 5185 4559 L 5185 388 mt 5185 442 L 5102 4759 mt (0.8) s 5721 4613 mt 5721 4559 L 5721 388 mt 5721 442 L 5638 4759 mt (0.9) s 6257 4613 mt 6257 4559 L 6257 388 mt 6257 442 L 6224 4759 mt (1) s 899 4613 mt 953 4613 L 6257 4613 mt 6203 4613 L 798 4657 mt (0) s 899 4085 mt 953 4085 L 6257 4085 mt 6203 4085 L 631 4129 mt (0.05) s 899 3557 mt 953 3557 L 6257 3557 mt 6203 3557 L 698 3601 mt (0.1) s 899 3029 mt 953 3029 L 6257 3029 mt 6203 3029 L 631 3073 mt (0.15) s 899 2501 mt 953 2501 L 6257 2501 mt 6203 2501 L 698 2545 mt (0.2) s 899 1972 mt 953 1972 L 6257 1972 mt 6203 1972 L 631 2016 mt (0.25) s 899 1444 mt 953 1444 L 6257 1444 mt 6203 1444 L 698 1488 mt (0.3) s 899 916 mt 953 916 L 6257 916 mt 6203 916 L 631 960 mt (0.35) s 899 388 mt 953 388 L 6257 388 mt 6203 388 L 698 432 mt (0.4) s 899 4613 mt 6257 4613 L 899 388 mt 6257 388 L 899 4613 mt 899 388 L 6257 4613 mt 6257 388 L gs 899 388 5359 4226 MR c np 1866 65 577 -501 103 -189 41 -93 10 103 43 -107 9 2 10 -43 1 -7 1 2 2 -18 0 -5 1 -5 0 -5 0 6 2 -2 2 -4 2 -11 0 -7 0 -4 1 -2 0 -2 1 -9 0 -4 1 -7 0 -2 0 -4 0 -3 0 -1 1 -13 0 0 4 14 12 -54 1 -13 0 18 6 -22 2 -4 2 1 1 -8 1 -5 0 -6 1 -2 1 3 2 -17 0 -3 0 -5 0 -6 1 -2 0 0 0 -2 0 2 1 -6 1 4 2 -16 1 -5 0 -5 0 -2 0 -6 0 21 14 -73 1 -16 0 -10 0 -8 2 -17 0 -13 1 -10 0 9 9 -47 1 -13 0 -9 0 11 5 -37 1 -13 0 -10 1 -6 0 -6 0 -9 0 436 259 -140 138 -35 110 -203 25 -35 20 -35 14 -24 8 -31 2 -6 1 4 2 -18 0 -5 0 -4 1 -4 0 -2 0 -3 0 -2 0 13 3 -3 2 -13 1 -8 0 3 2923 2180 100 MP stroke 2 -4 2 1 2 -2 1 2 3 -18 0 -5 1 -7 0 -5 0 -5 0 -1 1 -8 0 -5 0 -3 0 -3 0 -1 1 -13 0 -9 1 -11 0 -2 0 -9 0 2 1 -16 0 -11 1 14 11 -47 1 -13 0 74 25 -77 1 -5 2 -1 2 -2 2 -8 0 -5 1 -6 0 -2 1 5 2 -16 0 -7 0 -4 1 -5 0 -5 0 5 3 2 7 -36 1 10 4 -21 2 -2 2 0 3 -15 0 -7 1 -6 0 -6 0 0 1 -7 0 -6 0 4 1 -6 0 -5 0 -4 0 -3 0 -3 0 -2 1 -5 2 -17 2 -20 1 -13 0 -9 1 -13 0 121 78 -147 5 -37 1 -13 0 -9 0 0 0 -13 1 -9 0 149 80 -200 6 -42 1 -13 0 -8 1 -16 1 -10 0 50 16 -45 4 -5 4 26 10 -43 1 -7 1 5 3 -16 0 -6 0 -5 0 -1 1 -7 0 15 4 -28 0 -1 2 -6 2606 2929 100 MP stroke 1 6 2 -16 1 -4 0 -4 0 -2 0 -2 1 -5 0 -5 0 -2 0 0 0 -7 0 46 14 -59 1 -10 0 2 1 -7 0 4 1 -7 0 -5 0 -5 0 -3 0 -1 0 -1 0 19 6 -33 0 -3 2 8 4 -10 2 -18 0 -5 1 -6 0 -7 0 -1 1 -3 1 -6 0 -5 0 -6 0 -1 0 -3 0 547 507 -626 3 15 15 -56 7 -47 2 -14 0 -13 1 -9 0 1 1 -16 0 -11 0 -2 0 -1 0 -2 0 -2 0 12 6 -37 0 -13 1 -10 0 -13 1 359 287 -382 10 -45 7 -46 1 -11 0 -2 0 -9 0 1 1 -17 1 -10 0 -13 0 0 1 -13 0 -9 0 432 275 -183 105 -93 50 -75 18 -76 0 -8 2 -6 1 2 2 -17 0 -6 0 -5 0 -3 2 -16 0 -4 1 -5 1 -4 1 -7 1 1 0 -7 0 -5 1 -5 0 -1 0 -3 0 -3 0 33 15 -66 1240 3720 100 MP stroke 1 -14 0 -9 0 23 8 -37 0 -13 1 15 5 -26 0 -2 0 0 1 -6 0 -5 0 -6 0 -1 0 0 0 -1 1 16 3 -18 1 -3 1 -7 0 -5 0 -4 0 -2 0 -3 0 9 3 -18 0 -3 1 -5 0 -5 1 -7 0 11 7 19 21 -67 5 -37 1 -13 0 -9 1 -13 0 38 12 -48 2 -4 2 -1 2 -2 1 -9 1 -6 0 5 2 -17 0 -3 1 -6 0 -7 1 -4 0 -5 0 5 2 -13 0 1 2 -18 0 -2 1 -7 0 -4 1 -4 0 -2 0 -3 0 -2 0 130 80 -158 14 -72 2 -18 0 -9 1 -11 0 -2 0 -9 0 2 1 -15 1 -13 0 61 39 -111 1 -17 1 -13 0 -10 0 -1 0 104 45 -117 1 -15 0 -11 0 65 24 -91 2 -18 0 -9 1 -13 0 -9 0 32 7 -9 5 -12 3 -18 0 -3 1 -8 0 -6 0 -5 0 9 3 -20 0 -4 916 4508 100 MP stroke 1 -9 0 -3 0 -5 0 -3 0 -2 0 18 5 -23 1 -1 0 -2 1 -9 0 -4 1 -7 0 -5 0 11 2 -3 1 2 3 -18 0 -5 1 -6 0 -6 0 -5 0 -1 1 -8 0 -5 0 -3 899 4610 26 MP stroke 434 1188 619 -336 211 -94 74 -375 10 214 58 -62 15 5 15 -75 2 -21 1 26 3 -18 1 -16 1 -7 0 -11 1 8 3 -23 2 44 3 -33 1 -9 1 -18 1 3 1 18 1 -18 1 -6 1 -18 0 0 1 -13 0 0 0 8 4 -26 2 -35 5 118 20 -88 3 -26 2 20 9 -57 2 0 2 23 2 -29 1 0 1 -7 1 -8 1 26 3 -18 1 -14 1 -7 1 -9 0 0 0 -4 0 0 0 5 2 -21 2 26 3 -18 1 -7 0 -11 0 2 1 -7 1 187 35 -135 4 -58 3 -41 2 7 6 -67 3 -26 3 -42 2 124 22 -181 3 -28 2 -13 0 66 14 -88 3 -26 2 -46 2 5 2 -26 1 -12 1 620 266 -99 162 211 162 -157 46 -49 31 15 25 1 12 -94 2 -20 1 26 3 -19 1 -16 1 -1 1 -11 0 0 0 -3 0 0 1 8 3 68 4 -62 1 -9 1 -11 3892 2832 100 MP stroke 3 0 3 -21 1 35 2 12 3 -18 1 -15 2 -8 0 -8 1 -10 0 3 2 -9 0 -20 1 0 0 -3 0 8 3 -26 3 -41 2 -5 1 -21 2 -12 0 19 5 -57 2 -42 2 125 22 -182 3 -26 2 141 32 -132 3 -26 2 0 2 23 3 -29 0 0 1 -8 1 -7 1 26 3 -19 1 -7 1 -9 1 -7 0 -10 0 11 6 98 12 -94 2 20 9 -44 3 23 2 -7 3 -10 2 -8 0 -8 1 -9 1 4 1 -15 1 -13 0 17 1 -8 1 -10 0 -13 0 0 1 -3 0 6 2 -32 8 65 8 -109 4 -26 2 -39 3 -26 3 367 91 -243 14 -88 3 -28 2 -12 0 -25 3 -28 2 -12 1 436 118 -170 17 -132 4 -26 2 5 5 -57 2 -42 2 130 27 -222 4 0 4 99 14 -74 2 -21 2 26 3 -18 1 -8 0 -10 0 1 1 -7 1 54 7 -41 2 -25 3 -21 3362 3640 100 MP stroke 1 26 3 -18 1 -7 0 -11 1 0 0 1 1 -7 0 -8 0 0 1 -1 0 -7 1 138 22 -125 2 -4 1 -19 1 -3 0 2 1 -7 1 -11 0 -13 1 -1 0 1 0 -3 0 94 10 -75 2 -39 4 18 5 0 2 -18 1 -15 2 -8 1 -8 0 -6 2 -3 1 -7 0 -10 1 -13 0 -3 0 0 1 1369 607 -947 7 170 46 -154 22 -160 5 -31 3 -28 2 -12 0 -22 5 32 4 -64 0 -7 0 -35 1 0 0 -5 0 68 14 -88 3 -26 2 -39 4 -26 2 975 359 -723 30 7 21 -172 3 -4 0 -21 2 -13 0 39 6 -84 3 -40 3 -33 0 -25 3 -28 2 -12 0 817 347 -220 134 -75 64 -63 27 -109 4 -26 2 -21 1 26 3 -18 1 -7 1 -9 1 34 4 -57 3 -42 2 0 2 -2 1 -15 1 6 1 -7 0 -10 1 -13 0 -3 0 0 0 -3 1 190 28 -156 1504 3732 100 MP stroke 3 -28 2 -12 0 66 14 -88 3 -26 2 17 8 -57 0 3 1 0 1 -8 1 -10 0 -12 0 1 0 -3 0 -2 1 41 5 -23 1 -3 1 -7 1 -10 0 -13 1 0 0 -3 0 36 3 -18 1 -15 1 -9 1 0 1 -7 1 9 11 165 38 -83 14 -88 3 -26 3 -39 3 -26 2 69 19 -88 4 -26 2 0 2 23 2 -29 1 -7 1 25 3 -18 1 -5 1 -8 1 -7 0 -11 1 -10 0 31 4 -26 2 -11 3 -18 1 -15 1 -9 1 -1 0 -10 1 0 0 -4 0 0 0 438 124 -245 35 -75 6 -94 2 -42 3 -4 1 -21 1 -13 1 -22 4 -31 4 -26 2 228 59 -186 6 -68 4 -28 1 -12 1 -28 2 235 52 -136 5 -57 2 -42 2 135 40 -49 6 -93 2 -40 4 -28 1 -12 1 48 10 -30 5 0 3 -19 1 -4 1 -9 1 -17 1 -11 0 47 4 -29 1 3 928 4502 100 MP stroke 1 -19 1 -13 1 -18 0 0 0 -2 1 52 6 -43 1 4 0 18 2 -18 1 -14 1 -7 0 -13 1 6 1 35 3 12 3 -18 0 -15 2 -9 1 -7 0 -10 0 2 2 -8 1 -20 0 0 899 4607 26 MP stroke gr 36 36 899 4610 FO 36 36 899 4607 FO 36 36 899 4602 FO 36 36 900 4594 FO 36 36 900 4593 FO 36 36 900 4588 FO 36 36 900 4582 FO 36 36 901 4576 FO 36 36 901 4571 FO 36 36 904 4553 FO 36 36 905 4555 FO 36 36 907 4552 FO 36 36 907 4563 FO 36 36 907 4558 FO 36 36 908 4551 FO 36 36 908 4547 FO 36 36 909 4538 FO 36 36 909 4536 FO 36 36 910 4535 FO 36 36 915 4512 FO 36 36 915 4530 FO 36 36 915 4528 FO 36 36 915 4525 FO 36 36 915 4520 FO 36 36 915 4517 FO 36 36 916 4508 FO 36 36 916 4504 FO 36 36 919 4484 FO 36 36 919 4493 FO 36 36 919 4488 FO 36 36 919 4482 FO 36 36 920 4474 FO 36 36 920 4471 FO 36 36 923 4453 FO 36 36 928 4441 FO 36 36 935 4432 FO 36 36 935 4464 FO 36 36 935 4455 FO 36 36 936 4442 FO 36 36 936 4433 FO 36 36 938 4415 FO 36 36 962 4324 FO 36 36 962 4389 FO 36 36 962 4378 FO 36 36 963 4363 FO 36 36 1008 4246 FO 36 36 1008 4350 FO 36 36 1008 4349 FO 36 36 1008 4339 FO 36 36 1009 4326 FO 36 36 1010 4309 FO 36 36 1049 4198 FO 36 36 1049 4259 FO 36 36 1050 4246 FO 36 36 1051 4231 FO 36 36 1051 4233 FO 36 36 1051 4224 FO 36 36 1051 4222 FO 36 36 1052 4211 FO 36 36 1052 4202 FO 36 36 1054 4184 FO 36 36 1068 4112 FO 36 36 1148 3954 FO 36 36 1148 4084 FO 36 36 1148 4082 FO 36 36 1148 4079 FO 36 36 1148 4077 FO 36 36 1149 4073 FO 36 36 1149 4069 FO 36 36 1150 4062 FO 36 36 1150 4060 FO 36 36 1152 4042 FO 36 36 1152 4043 FO 36 36 1154 4030 FO 36 36 1154 4035 FO 36 36 1154 4030 FO 36 36 1155 4026 FO 36 36 1155 4019 FO 36 36 1156 4013 FO 36 36 1156 4010 FO 36 36 1158 3993 FO 36 36 1158 3998 FO 36 36 1159 3992 FO 36 36 1160 3983 FO 36 36 1162 3981 FO 36 36 1164 3980 FO 36 36 1166 3976 FO 36 36 1178 3928 FO 36 36 1178 3966 FO 36 36 1179 3953 FO 36 36 1179 3944 FO 36 36 1180 3931 FO 36 36 1185 3894 FO 36 36 1206 3827 FO 36 36 1213 3846 FO 36 36 1213 3857 FO 36 36 1214 3850 FO 36 36 1214 3845 FO 36 36 1215 3840 FO 36 36 1215 3837 FO 36 36 1218 3819 FO 36 36 1218 3828 FO 36 36 1218 3825 FO 36 36 1218 3823 FO 36 36 1218 3819 FO 36 36 1218 3814 FO 36 36 1219 3807 FO 36 36 1220 3804 FO 36 36 1223 3786 FO 36 36 1224 3802 FO 36 36 1224 3801 FO 36 36 1224 3801 FO 36 36 1224 3800 FO 36 36 1224 3794 FO 36 36 1224 3789 FO 36 36 1225 3783 FO 36 36 1225 3783 FO 36 36 1225 3781 FO 36 36 1230 3755 FO 36 36 1231 3770 FO 36 36 1231 3757 FO 36 36 1239 3720 FO 36 36 1239 3743 FO 36 36 1239 3734 FO 36 36 1240 3720 FO 36 36 1255 3654 FO 36 36 1255 3687 FO 36 36 1255 3684 FO 36 36 1255 3681 FO 36 36 1255 3680 FO 36 36 1256 3675 FO 36 36 1256 3670 FO 36 36 1256 3663 FO 36 36 1257 3664 FO 36 36 1258 3657 FO 36 36 1259 3653 FO 36 36 1260 3648 FO 36 36 1260 3644 FO 36 36 1262 3628 FO 36 36 1262 3625 FO 36 36 1262 3620 FO 36 36 1262 3614 FO 36 36 1264 3597 FO 36 36 1265 3599 FO 36 36 1267 3593 FO 36 36 1267 3585 FO 36 36 1285 3509 FO 36 36 1335 3434 FO 36 36 1440 3341 FO 36 36 1715 3158 FO 36 36 1715 3590 FO 36 36 1715 3581 FO 36 36 1716 3568 FO 36 36 1716 3568 FO 36 36 1716 3555 FO 36 36 1717 3545 FO 36 36 1718 3528 FO 36 36 1718 3529 FO 36 36 1718 3520 FO 36 36 1718 3518 FO 36 36 1719 3507 FO 36 36 1726 3461 FO 36 36 1736 3416 FO 36 36 2023 3034 FO 36 36 2024 3393 FO 36 36 2024 3380 FO 36 36 2025 3370 FO 36 36 2025 3357 FO 36 36 2031 3320 FO 36 36 2031 3332 FO 36 36 2031 3330 FO 36 36 2031 3328 FO 36 36 2031 3327 FO 36 36 2031 3325 FO 36 36 2031 3314 FO 36 36 2032 3298 FO 36 36 2032 3299 FO 36 36 2033 3290 FO 36 36 2033 3277 FO 36 36 2035 3263 FO 36 36 2042 3216 FO 36 36 2057 3160 FO 36 36 2060 3175 FO 36 36 2567 2549 FO 36 36 2567 3096 FO 36 36 2567 3093 FO 36 36 2567 3092 FO 36 36 2567 3086 FO 36 36 2567 3081 FO 36 36 2568 3075 FO 36 36 2569 3072 FO 36 36 2569 3071 FO 36 36 2569 3064 FO 36 36 2570 3058 FO 36 36 2570 3053 FO 36 36 2572 3035 FO 36 36 2576 3025 FO 36 36 2578 3033 FO 36 36 2578 3030 FO 36 36 2584 2997 FO 36 36 2584 3016 FO 36 36 2584 3015 FO 36 36 2584 3014 FO 36 36 2584 3011 FO 36 36 2584 3006 FO 36 36 2584 3001 FO 36 36 2585 2994 FO 36 36 2585 2998 FO 36 36 2586 2991 FO 36 36 2586 2993 FO 36 36 2587 2983 FO 36 36 2601 2924 FO 36 36 2601 2970 FO 36 36 2601 2963 FO 36 36 2601 2963 FO 36 36 2601 2961 FO 36 36 2601 2956 FO 36 36 2602 2951 FO 36 36 2602 2949 FO 36 36 2602 2947 FO 36 36 2602 2943 FO 36 36 2603 2939 FO 36 36 2605 2923 FO 36 36 2606 2929 FO 36 36 2608 2923 FO 36 36 2608 2922 FO 36 36 2612 2894 FO 36 36 2612 2909 FO 36 36 2613 2902 FO 36 36 2613 2901 FO 36 36 2613 2896 FO 36 36 2613 2890 FO 36 36 2616 2874 FO 36 36 2617 2879 FO 36 36 2618 2872 FO 36 36 2628 2829 FO 36 36 2632 2855 FO 36 36 2636 2850 FO 36 36 2652 2805 FO 36 36 2652 2855 FO 36 36 2653 2845 FO 36 36 2654 2829 FO 36 36 2654 2821 FO 36 36 2655 2808 FO 36 36 2661 2766 FO 36 36 2741 2566 FO 36 36 2741 2715 FO 36 36 2742 2706 FO 36 36 2742 2693 FO 36 36 2742 2693 FO 36 36 2742 2684 FO 36 36 2743 2671 FO 36 36 2748 2634 FO 36 36 2826 2487 FO 36 36 2826 2608 FO 36 36 2827 2595 FO 36 36 2827 2586 FO 36 36 2828 2573 FO 36 36 2830 2553 FO 36 36 2832 2536 FO 36 36 2833 2531 FO 36 36 2833 2529 FO 36 36 2833 2526 FO 36 36 2833 2523 FO 36 36 2833 2519 FO 36 36 2833 2514 FO 36 36 2834 2508 FO 36 36 2834 2512 FO 36 36 2834 2506 FO 36 36 2835 2499 FO 36 36 2835 2499 FO 36 36 2835 2493 FO 36 36 2836 2487 FO 36 36 2836 2480 FO 36 36 2839 2465 FO 36 36 2841 2465 FO 36 36 2843 2463 FO 36 36 2847 2442 FO 36 36 2848 2452 FO 36 36 2855 2416 FO 36 36 2858 2418 FO 36 36 2858 2423 FO 36 36 2858 2418 FO 36 36 2859 2413 FO 36 36 2859 2409 FO 36 36 2859 2402 FO 36 36 2861 2386 FO 36 36 2862 2391 FO 36 36 2862 2389 FO 36 36 2863 2383 FO 36 36 2863 2378 FO 36 36 2865 2370 FO 36 36 2867 2368 FO 36 36 2869 2367 FO 36 36 2870 2362 FO 36 36 2895 2285 FO 36 36 2895 2359 FO 36 36 2896 2346 FO 36 36 2907 2299 FO 36 36 2908 2313 FO 36 36 2908 2302 FO 36 36 2909 2286 FO 36 36 2909 2288 FO 36 36 2909 2279 FO 36 36 2909 2277 FO 36 36 2910 2266 FO 36 36 2910 2257 FO 36 36 2911 2244 FO 36 36 2911 2243 FO 36 36 2911 2240 FO 36 36 2911 2237 FO 36 36 2911 2232 FO 36 36 2912 2224 FO 36 36 2912 2223 FO 36 36 2912 2218 FO 36 36 2912 2213 FO 36 36 2913 2206 FO 36 36 2913 2201 FO 36 36 2916 2183 FO 36 36 2917 2185 FO 36 36 2919 2183 FO 36 36 2921 2184 FO 36 36 2923 2180 FO 36 36 2923 2183 FO 36 36 2924 2175 FO 36 36 2926 2162 FO 36 36 2929 2159 FO 36 36 2929 2172 FO 36 36 2929 2170 FO 36 36 2929 2167 FO 36 36 2929 2165 FO 36 36 2930 2161 FO 36 36 2930 2157 FO 36 36 2930 2152 FO 36 36 2932 2134 FO 36 36 2933 2138 FO 36 36 2935 2132 FO 36 36 2943 2101 FO 36 36 2957 2077 FO 36 36 2977 2042 FO 36 36 3002 2007 FO 36 36 3112 1804 FO 36 36 3250 1769 FO 36 36 3509 1629 FO 36 36 3509 2065 FO 36 36 3509 2056 FO 36 36 3509 2050 FO 36 36 3510 2044 FO 36 36 3510 2034 FO 36 36 3511 2021 FO 36 36 3516 1984 FO 36 36 3516 1995 FO 36 36 3516 1986 FO 36 36 3517 1973 FO 36 36 3526 1926 FO 36 36 3526 1935 FO 36 36 3527 1925 FO 36 36 3527 1912 FO 36 36 3529 1895 FO 36 36 3529 1887 FO 36 36 3529 1877 FO 36 36 3530 1861 FO 36 36 3544 1788 FO 36 36 3544 1809 FO 36 36 3544 1803 FO 36 36 3544 1801 FO 36 36 3544 1796 FO 36 36 3545 1791 FO 36 36 3547 1775 FO 36 36 3548 1779 FO 36 36 3549 1773 FO 36 36 3549 1775 FO 36 36 3549 1773 FO 36 36 3549 1773 FO 36 36 3550 1771 FO 36 36 3550 1765 FO 36 36 3550 1760 FO 36 36 3550 1757 FO 36 36 3552 1740 FO 36 36 3553 1743 FO 36 36 3554 1741 FO 36 36 3554 1735 FO 36 36 3555 1730 FO 36 36 3556 1722 FO 36 36 3558 1723 FO 36 36 3560 1719 FO 36 36 3566 1697 FO 36 36 3566 1715 FO 36 36 3567 1702 FO 36 36 3579 1648 FO 36 36 3583 1662 FO 36 36 3583 1662 FO 36 36 3584 1649 FO 36 36 3584 1648 FO 36 36 3584 1645 FO 36 36 3584 1641 FO 36 36 3584 1639 FO 36 36 3585 1632 FO 36 36 3585 1628 FO 36 36 3586 1619 FO 36 36 3586 1617 FO 36 36 3587 1615 FO 36 36 3587 1611 FO 36 36 3587 1604 FO 36 36 3589 1593 FO 36 36 3591 1589 FO 36 36 3593 1587 FO 36 36 3593 1593 FO 36 36 3593 1588 FO 36 36 3594 1583 FO 36 36 3594 1578 FO 36 36 3596 1560 FO 36 36 3597 1562 FO 36 36 3598 1555 FO 36 36 3608 1512 FO 36 36 3617 1514 FO 36 36 3660 1407 FO 36 36 3670 1510 FO 36 36 3711 1417 FO 36 36 3814 1228 FO 36 36 4391 727 FO 36 36 6257 792 FO gs 899 388 5359 4226 MR c np gr 874 4582 mt 924 4632 L 924 4582 mt 874 4632 L 874 4582 mt 924 4632 L 924 4582 mt 874 4632 L 875 4562 mt 925 4612 L 925 4562 mt 875 4612 L 877 4554 mt 927 4604 L 927 4554 mt 877 4604 L 877 4556 mt 927 4606 L 927 4556 mt 877 4606 L 877 4546 mt 927 4596 L 927 4546 mt 877 4596 L 878 4539 mt 928 4589 L 928 4539 mt 878 4589 L 880 4530 mt 930 4580 L 930 4530 mt 880 4580 L 880 4515 mt 930 4565 L 930 4515 mt 880 4565 L 883 4497 mt 933 4547 L 933 4497 mt 883 4547 L 886 4509 mt 936 4559 L 936 4509 mt 886 4559 L 887 4544 mt 937 4594 L 937 4544 mt 887 4594 L 888 4550 mt 938 4600 L 938 4550 mt 888 4600 L 888 4537 mt 938 4587 L 938 4537 mt 888 4587 L 889 4530 mt 939 4580 L 939 4530 mt 889 4580 L 890 4516 mt 940 4566 L 940 4516 mt 890 4566 L 892 4498 mt 942 4548 L 942 4498 mt 892 4548 L 892 4516 mt 942 4566 L 942 4516 mt 892 4566 L 893 4520 mt 943 4570 L 943 4520 mt 893 4570 L 899 4477 mt 949 4527 L 949 4477 mt 899 4527 L 900 4529 mt 950 4579 L 950 4529 mt 900 4579 L 900 4527 mt 950 4577 L 950 4527 mt 900 4577 L 900 4527 mt 950 4577 L 950 4527 mt 900 4577 L 901 4509 mt 951 4559 L 951 4509 mt 901 4559 L 902 4496 mt 952 4546 L 952 4496 mt 902 4546 L 903 4477 mt 953 4527 L 953 4477 mt 903 4527 L 904 4480 mt 954 4530 L 954 4480 mt 904 4530 L 908 4451 mt 958 4501 L 958 4451 mt 908 4501 L 908 4498 mt 958 4548 L 958 4498 mt 908 4548 L 909 4487 mt 959 4537 L 959 4487 mt 909 4537 L 910 4470 mt 960 4520 L 960 4470 mt 910 4520 L 911 4461 mt 961 4511 L 961 4461 mt 911 4511 L 912 4457 mt 962 4507 L 962 4457 mt 912 4507 L 915 4438 mt 965 4488 L 965 4438 mt 915 4488 L 920 4438 mt 970 4488 L 970 4438 mt 920 4488 L 930 4408 mt 980 4458 L 980 4408 mt 930 4458 L 931 4456 mt 981 4506 L 981 4456 mt 931 4506 L 932 4444 mt 982 4494 L 982 4444 mt 932 4494 L 936 4416 mt 986 4466 L 986 4416 mt 936 4466 L 938 4376 mt 988 4426 L 988 4376 mt 938 4426 L 944 4283 mt 994 4333 L 994 4283 mt 944 4333 L 984 4234 mt 1034 4284 L 1034 4234 mt 984 4284 L 986 4369 mt 1036 4419 L 1036 4369 mt 986 4419 L 988 4327 mt 1038 4377 L 1038 4327 mt 988 4377 L 993 4270 mt 1043 4320 L 1043 4270 mt 993 4320 L 1045 4134 mt 1095 4184 L 1095 4134 mt 1045 4184 L 1047 4369 mt 1097 4419 L 1097 4369 mt 1047 4419 L 1048 4341 mt 1098 4391 L 1098 4341 mt 1048 4391 L 1049 4329 mt 1099 4379 L 1099 4329 mt 1049 4379 L 1053 4301 mt 1103 4351 L 1103 4301 mt 1053 4351 L 1059 4233 mt 1109 4283 L 1109 4233 mt 1059 4283 L 1118 4047 mt 1168 4097 L 1168 4047 mt 1118 4097 L 1120 4275 mt 1170 4325 L 1170 4275 mt 1120 4325 L 1124 4249 mt 1174 4299 L 1174 4249 mt 1124 4299 L 1128 4218 mt 1178 4268 L 1178 4218 mt 1128 4268 L 1129 4196 mt 1179 4246 L 1179 4196 mt 1129 4246 L 1130 4183 mt 1180 4233 L 1180 4183 mt 1130 4233 L 1131 4162 mt 1181 4212 L 1181 4162 mt 1131 4212 L 1134 4158 mt 1184 4208 L 1184 4158 mt 1134 4208 L 1136 4116 mt 1186 4166 L 1186 4116 mt 1136 4166 L 1142 4022 mt 1192 4072 L 1192 4022 mt 1142 4072 L 1177 3947 mt 1227 3997 L 1227 3947 mt 1177 3997 L 1301 3702 mt 1351 3752 L 1351 3702 mt 1301 3752 L 1301 4140 mt 1351 4190 L 1351 4140 mt 1301 4190 L 1301 4140 mt 1351 4190 L 1351 4140 mt 1301 4190 L 1301 4136 mt 1351 4186 L 1351 4136 mt 1301 4186 L 1302 4136 mt 1352 4186 L 1352 4136 mt 1302 4186 L 1302 4126 mt 1352 4176 L 1352 4126 mt 1302 4176 L 1303 4125 mt 1353 4175 L 1353 4125 mt 1303 4175 L 1304 4116 mt 1354 4166 L 1354 4116 mt 1304 4166 L 1305 4101 mt 1355 4151 L 1355 4101 mt 1305 4151 L 1308 4083 mt 1358 4133 L 1358 4083 mt 1308 4133 L 1310 4072 mt 1360 4122 L 1360 4072 mt 1310 4122 L 1314 4046 mt 1364 4096 L 1364 4046 mt 1314 4096 L 1314 4077 mt 1364 4127 L 1364 4077 mt 1314 4127 L 1315 4067 mt 1365 4117 L 1365 4067 mt 1315 4117 L 1315 4056 mt 1365 4106 L 1365 4056 mt 1315 4106 L 1316 4049 mt 1366 4099 L 1366 4049 mt 1316 4099 L 1317 4041 mt 1367 4091 L 1367 4041 mt 1317 4091 L 1318 4036 mt 1368 4086 L 1368 4036 mt 1318 4086 L 1321 4018 mt 1371 4068 L 1371 4018 mt 1321 4068 L 1322 4043 mt 1372 4093 L 1372 4043 mt 1322 4093 L 1323 4036 mt 1373 4086 L 1373 4036 mt 1323 4086 L 1325 4007 mt 1375 4057 L 1375 4007 mt 1325 4057 L 1327 4030 mt 1377 4080 L 1377 4030 mt 1327 4080 L 1329 4030 mt 1379 4080 L 1379 4030 mt 1329 4080 L 1333 4004 mt 1383 4054 L 1383 4004 mt 1333 4054 L 1352 3916 mt 1402 3966 L 1402 3916 mt 1352 3966 L 1354 3985 mt 1404 4035 L 1404 3985 mt 1354 4035 L 1357 3959 mt 1407 4009 L 1407 3959 mt 1357 4009 L 1360 3920 mt 1410 3970 L 1410 3920 mt 1360 3970 L 1363 3894 mt 1413 3944 L 1413 3894 mt 1363 3944 L 1377 3806 mt 1427 3856 L 1427 3806 mt 1377 3856 L 1415 3723 mt 1465 3773 L 1465 3723 mt 1415 3773 L 1426 3888 mt 1476 3938 L 1476 3888 mt 1426 3938 L 1427 3897 mt 1477 3947 L 1477 3897 mt 1427 3947 L 1428 3890 mt 1478 3940 L 1478 3890 mt 1428 3940 L 1429 3890 mt 1479 3940 L 1479 3890 mt 1429 3940 L 1430 3881 mt 1480 3931 L 1480 3881 mt 1430 3931 L 1431 3866 mt 1481 3916 L 1481 3866 mt 1431 3916 L 1434 3848 mt 1484 3898 L 1484 3848 mt 1434 3898 L 1434 3884 mt 1484 3934 L 1484 3884 mt 1434 3934 L 1434 3881 mt 1484 3931 L 1484 3881 mt 1434 3931 L 1435 3881 mt 1485 3931 L 1485 3881 mt 1435 3931 L 1435 3868 mt 1485 3918 L 1485 3868 mt 1435 3918 L 1436 3858 mt 1486 3908 L 1486 3858 mt 1436 3908 L 1437 3851 mt 1487 3901 L 1487 3851 mt 1437 3901 L 1438 3848 mt 1488 3898 L 1488 3848 mt 1438 3898 L 1443 3825 mt 1493 3875 L 1493 3825 mt 1443 3875 L 1444 3866 mt 1494 3916 L 1494 3866 mt 1444 3916 L 1444 3864 mt 1494 3914 L 1494 3864 mt 1444 3914 L 1444 3861 mt 1494 3911 L 1494 3861 mt 1444 3911 L 1444 3862 mt 1494 3912 L 1494 3862 mt 1444 3912 L 1444 3850 mt 1494 3900 L 1494 3850 mt 1444 3900 L 1445 3840 mt 1495 3890 L 1495 3840 mt 1445 3890 L 1446 3832 mt 1496 3882 L 1496 3832 mt 1446 3882 L 1447 3832 mt 1497 3882 L 1497 3832 mt 1447 3882 L 1447 3835 mt 1497 3885 L 1497 3835 mt 1447 3885 L 1455 3778 mt 1505 3828 L 1505 3778 mt 1455 3828 L 1457 3795 mt 1507 3845 L 1507 3795 mt 1457 3845 L 1460 3769 mt 1510 3819 L 1510 3769 mt 1460 3819 L 1474 3681 mt 1524 3731 L 1524 3681 mt 1474 3731 L 1474 3747 mt 1524 3797 L 1524 3747 mt 1474 3797 L 1476 3735 mt 1526 3785 L 1526 3735 mt 1476 3785 L 1479 3707 mt 1529 3757 L 1529 3707 mt 1479 3757 L 1507 3551 mt 1557 3601 L 1557 3551 mt 1507 3601 L 1508 3741 mt 1558 3791 L 1558 3741 mt 1508 3791 L 1508 3738 mt 1558 3788 L 1558 3738 mt 1508 3788 L 1508 3738 mt 1558 3788 L 1558 3738 mt 1508 3788 L 1508 3735 mt 1558 3785 L 1558 3735 mt 1508 3785 L 1509 3722 mt 1559 3772 L 1559 3722 mt 1509 3772 L 1509 3712 mt 1559 3762 L 1559 3712 mt 1509 3762 L 1510 3705 mt 1560 3755 L 1560 3705 mt 1510 3755 L 1511 3711 mt 1561 3761 L 1561 3711 mt 1511 3761 L 1512 3696 mt 1562 3746 L 1562 3696 mt 1512 3746 L 1514 3694 mt 1564 3744 L 1564 3694 mt 1514 3744 L 1516 3694 mt 1566 3744 L 1566 3694 mt 1516 3744 L 1519 3652 mt 1569 3702 L 1569 3652 mt 1519 3702 L 1523 3595 mt 1573 3645 L 1573 3595 mt 1523 3645 L 1524 3629 mt 1574 3679 L 1574 3629 mt 1524 3679 L 1525 3620 mt 1575 3670 L 1575 3620 mt 1525 3670 L 1526 3613 mt 1576 3663 L 1576 3613 mt 1526 3663 L 1529 3595 mt 1579 3645 L 1579 3595 mt 1529 3645 L 1530 3621 mt 1580 3671 L 1580 3621 mt 1530 3671 L 1532 3600 mt 1582 3650 L 1582 3600 mt 1532 3650 L 1536 3574 mt 1586 3624 L 1586 3574 mt 1536 3624 L 1563 3465 mt 1613 3515 L 1613 3465 mt 1563 3515 L 1627 3402 mt 1677 3452 L 1677 3402 mt 1627 3452 L 1761 3327 mt 1811 3377 L 1811 3327 mt 1761 3377 L 2108 3107 mt 2158 3157 L 2158 3107 mt 2108 3157 L 2108 3924 mt 2158 3974 L 2158 3924 mt 2108 3974 L 2110 3912 mt 2160 3962 L 2160 3912 mt 2110 3962 L 2113 3884 mt 2163 3934 L 2163 3884 mt 2113 3934 L 2113 3859 mt 2163 3909 L 2163 3859 mt 2113 3909 L 2116 3826 mt 2166 3876 L 2166 3826 mt 2116 3876 L 2119 3786 mt 2169 3836 L 2169 3786 mt 2119 3836 L 2125 3702 mt 2175 3752 L 2175 3702 mt 2125 3752 L 2125 3741 mt 2175 3791 L 2175 3741 mt 2125 3791 L 2127 3728 mt 2177 3778 L 2177 3728 mt 2127 3778 L 2127 3707 mt 2177 3757 L 2177 3707 mt 2127 3757 L 2130 3703 mt 2180 3753 L 2180 3703 mt 2130 3753 L 2151 3531 mt 2201 3581 L 2201 3531 mt 2151 3581 L 2181 3538 mt 2231 3588 L 2231 3538 mt 2181 3588 L 2540 2815 mt 2590 2865 L 2590 2815 mt 2540 2865 L 2542 3790 mt 2592 3840 L 2592 3790 mt 2542 3840 L 2546 3764 mt 2596 3814 L 2596 3764 mt 2546 3814 L 2548 3725 mt 2598 3775 L 2598 3725 mt 2548 3775 L 2551 3699 mt 2601 3749 L 2601 3699 mt 2551 3749 L 2565 3611 mt 2615 3661 L 2615 3611 mt 2565 3661 L 2565 3679 mt 2615 3729 L 2615 3679 mt 2565 3729 L 2565 3674 mt 2615 3724 L 2615 3674 mt 2565 3724 L 2566 3674 mt 2616 3724 L 2616 3674 mt 2566 3724 L 2566 3639 mt 2616 3689 L 2616 3639 mt 2566 3689 L 2566 3632 mt 2616 3682 L 2616 3632 mt 2566 3682 L 2570 3568 mt 2620 3618 L 2620 3568 mt 2570 3618 L 2575 3600 mt 2625 3650 L 2625 3600 mt 2575 3650 L 2575 3578 mt 2625 3628 L 2625 3578 mt 2575 3628 L 2577 3566 mt 2627 3616 L 2627 3566 mt 2577 3616 L 2580 3538 mt 2630 3588 L 2630 3538 mt 2580 3588 L 2585 3507 mt 2635 3557 L 2635 3507 mt 2585 3557 L 2607 3347 mt 2657 3397 L 2657 3347 mt 2607 3397 L 2653 3193 mt 2703 3243 L 2703 3193 mt 2653 3243 L 2660 3363 mt 2710 3413 L 2710 3363 mt 2660 3413 L 3267 2416 mt 3317 2466 L 3317 2416 mt 3267 2466 L 3268 3785 mt 3318 3835 L 3318 3785 mt 3268 3835 L 3268 3785 mt 3318 3835 L 3318 3785 mt 3268 3835 L 3268 3782 mt 3318 3832 L 3318 3782 mt 3268 3832 L 3269 3769 mt 3319 3819 L 3319 3769 mt 3269 3819 L 3269 3759 mt 3319 3809 L 3319 3759 mt 3269 3809 L 3270 3752 mt 3320 3802 L 3320 3752 mt 3270 3802 L 3272 3749 mt 3322 3799 L 3322 3749 mt 3272 3799 L 3272 3743 mt 3322 3793 L 3322 3743 mt 3272 3793 L 3273 3735 mt 3323 3785 L 3323 3735 mt 3273 3785 L 3275 3727 mt 3325 3777 L 3325 3727 mt 3275 3777 L 3276 3712 mt 3326 3762 L 3326 3712 mt 3276 3762 L 3278 3694 mt 3328 3744 L 3328 3694 mt 3278 3744 L 3283 3694 mt 3333 3744 L 3333 3694 mt 3283 3744 L 3287 3712 mt 3337 3762 L 3337 3712 mt 3287 3762 L 3289 3673 mt 3339 3723 L 3339 3673 mt 3289 3723 L 3299 3598 mt 3349 3648 L 3349 3598 mt 3299 3648 L 3299 3692 mt 3349 3742 L 3349 3692 mt 3299 3742 L 3299 3689 mt 3349 3739 L 3349 3689 mt 3299 3739 L 3299 3690 mt 3349 3740 L 3349 3690 mt 3299 3740 L 3300 3689 mt 3350 3739 L 3350 3689 mt 3300 3739 L 3300 3676 mt 3350 3726 L 3350 3676 mt 3300 3726 L 3301 3665 mt 3351 3715 L 3351 3665 mt 3301 3715 L 3302 3658 mt 3352 3708 L 3352 3658 mt 3302 3708 L 3302 3660 mt 3352 3710 L 3352 3660 mt 3302 3710 L 3303 3657 mt 3353 3707 L 3353 3657 mt 3303 3707 L 3304 3638 mt 3354 3688 L 3354 3638 mt 3304 3688 L 3306 3634 mt 3356 3684 L 3356 3634 mt 3306 3684 L 3328 3509 mt 3378 3559 L 3378 3509 mt 3328 3559 L 3329 3647 mt 3379 3697 L 3379 3647 mt 3329 3697 L 3329 3640 mt 3379 3690 L 3379 3640 mt 3329 3690 L 3330 3639 mt 3380 3689 L 3380 3639 mt 3330 3689 L 3330 3639 mt 3380 3689 L 3380 3639 mt 3330 3689 L 3330 3631 mt 3380 3681 L 3380 3631 mt 3330 3681 L 3331 3624 mt 3381 3674 L 3381 3624 mt 3331 3674 L 3331 3625 mt 3381 3675 L 3381 3625 mt 3331 3675 L 3332 3625 mt 3382 3675 L 3382 3625 mt 3332 3675 L 3332 3614 mt 3382 3664 L 3382 3614 mt 3332 3664 L 3333 3607 mt 3383 3657 L 3383 3607 mt 3333 3657 L 3336 3589 mt 3386 3639 L 3386 3589 mt 3336 3639 L 3337 3615 mt 3387 3665 L 3387 3615 mt 3337 3665 L 3340 3594 mt 3390 3644 L 3390 3594 mt 3340 3644 L 3342 3569 mt 3392 3619 L 3392 3569 mt 3342 3619 L 3349 3528 mt 3399 3578 L 3399 3528 mt 3349 3578 L 3350 3582 mt 3400 3632 L 3400 3582 mt 3350 3632 L 3351 3575 mt 3401 3625 L 3401 3575 mt 3351 3625 L 3351 3576 mt 3401 3626 L 3401 3576 mt 3351 3626 L 3351 3566 mt 3401 3616 L 3401 3566 mt 3351 3616 L 3352 3558 mt 3402 3608 L 3402 3558 mt 3352 3608 L 3355 3540 mt 3405 3590 L 3405 3540 mt 3355 3590 L 3357 3566 mt 3407 3616 L 3407 3566 mt 3357 3616 L 3359 3545 mt 3409 3595 L 3409 3545 mt 3359 3595 L 3373 3471 mt 3423 3521 L 3423 3471 mt 3373 3521 L 3377 3570 mt 3427 3620 L 3427 3570 mt 3377 3620 L 3381 3570 mt 3431 3620 L 3431 3570 mt 3381 3620 L 3408 3348 mt 3458 3398 L 3458 3348 mt 3408 3398 L 3410 3478 mt 3460 3528 L 3460 3478 mt 3410 3528 L 3412 3436 mt 3462 3486 L 3462 3436 mt 3412 3486 L 3417 3379 mt 3467 3429 L 3467 3379 mt 3417 3429 L 3419 3384 mt 3469 3434 L 3469 3384 mt 3419 3434 L 3423 3358 mt 3473 3408 L 3473 3358 mt 3423 3408 L 3440 3226 mt 3490 3276 L 3490 3226 mt 3440 3276 L 3558 3056 mt 3608 3106 L 3608 3056 mt 3558 3106 L 3559 3492 mt 3609 3542 L 3609 3492 mt 3559 3542 L 3561 3480 mt 3611 3530 L 3611 3480 mt 3561 3530 L 3564 3452 mt 3614 3502 L 3614 3452 mt 3564 3502 L 3564 3427 mt 3614 3477 L 3614 3427 mt 3564 3477 L 3566 3415 mt 3616 3465 L 3616 3415 mt 3566 3465 L 3569 3387 mt 3619 3437 L 3619 3387 mt 3569 3437 L 3583 3299 mt 3633 3349 L 3633 3299 mt 3583 3349 L 3674 3056 mt 3724 3106 L 3724 3056 mt 3674 3106 L 3677 3423 mt 3727 3473 L 3727 3423 mt 3677 3473 L 3680 3397 mt 3730 3447 L 3730 3397 mt 3680 3447 L 3682 3358 mt 3732 3408 L 3732 3358 mt 3682 3408 L 3686 3332 mt 3736 3382 L 3736 3332 mt 3686 3382 L 3694 3223 mt 3744 3273 L 3744 3223 mt 3694 3273 L 3702 3288 mt 3752 3338 L 3752 3288 mt 3702 3338 L 3704 3256 mt 3754 3306 L 3754 3256 mt 3704 3306 L 3704 3262 mt 3754 3312 L 3754 3262 mt 3704 3312 L 3705 3259 mt 3755 3309 L 3755 3259 mt 3705 3309 L 3705 3259 mt 3755 3309 L 3755 3259 mt 3705 3309 L 3705 3246 mt 3755 3296 L 3755 3246 mt 3705 3296 L 3706 3236 mt 3756 3286 L 3756 3236 mt 3706 3286 L 3707 3228 mt 3757 3278 L 3757 3228 mt 3707 3278 L 3707 3245 mt 3757 3295 L 3757 3245 mt 3707 3295 L 3708 3232 mt 3758 3282 L 3758 3232 mt 3708 3282 L 3709 3217 mt 3759 3267 L 3759 3217 mt 3709 3267 L 3710 3221 mt 3760 3271 L 3760 3221 mt 3710 3271 L 3711 3212 mt 3761 3262 L 3761 3212 mt 3711 3262 L 3711 3204 mt 3761 3254 L 3761 3204 mt 3711 3254 L 3713 3196 mt 3763 3246 L 3763 3196 mt 3713 3246 L 3716 3186 mt 3766 3236 L 3766 3186 mt 3716 3236 L 3718 3179 mt 3768 3229 L 3768 3179 mt 3718 3229 L 3721 3202 mt 3771 3252 L 3771 3202 mt 3721 3252 L 3730 3158 mt 3780 3208 L 3780 3158 mt 3730 3208 L 3732 3178 mt 3782 3228 L 3782 3178 mt 3732 3228 L 3744 3084 mt 3794 3134 L 3794 3084 mt 3744 3134 L 3750 3182 mt 3800 3232 L 3800 3182 mt 3750 3232 L 3750 3193 mt 3800 3243 L 3800 3193 mt 3750 3243 L 3750 3183 mt 3800 3233 L 3800 3183 mt 3750 3233 L 3751 3176 mt 3801 3226 L 3801 3176 mt 3751 3226 L 3752 3167 mt 3802 3217 L 3802 3167 mt 3752 3217 L 3753 3160 mt 3803 3210 L 3803 3160 mt 3753 3210 L 3756 3141 mt 3806 3191 L 3806 3141 mt 3756 3191 L 3757 3167 mt 3807 3217 L 3807 3167 mt 3757 3217 L 3758 3160 mt 3808 3210 L 3808 3160 mt 3758 3210 L 3759 3152 mt 3809 3202 L 3809 3152 mt 3759 3202 L 3759 3152 mt 3809 3202 L 3809 3152 mt 3759 3202 L 3762 3123 mt 3812 3173 L 3812 3123 mt 3762 3173 L 3764 3146 mt 3814 3196 L 3814 3146 mt 3764 3196 L 3766 3146 mt 3816 3196 L 3816 3146 mt 3766 3196 L 3769 3120 mt 3819 3170 L 3819 3120 mt 3769 3170 L 3801 2988 mt 3851 3038 L 3851 2988 mt 3801 3038 L 3803 3129 mt 3853 3179 L 3853 3129 mt 3803 3179 L 3806 3103 mt 3856 3153 L 3856 3103 mt 3806 3153 L 3828 2921 mt 3878 2971 L 3878 2921 mt 3828 2971 L 3830 3046 mt 3880 3096 L 3880 3046 mt 3830 3096 L 3832 3004 mt 3882 3054 L 3882 3004 mt 3832 3054 L 3837 2947 mt 3887 2997 L 3887 2947 mt 3837 2997 L 3837 2966 mt 3887 3016 L 3887 2966 mt 3837 3016 L 3839 2954 mt 3889 3004 L 3889 2954 mt 3839 3004 L 3840 2933 mt 3890 2983 L 3890 2933 mt 3840 2983 L 3842 2928 mt 3892 2978 L 3892 2928 mt 3842 2978 L 3845 2887 mt 3895 2937 L 3895 2887 mt 3845 2937 L 3848 2861 mt 3898 2911 L 3898 2861 mt 3848 2911 L 3848 2869 mt 3898 2919 L 3898 2869 mt 3848 2919 L 3848 2866 mt 3898 2916 L 3898 2866 mt 3848 2916 L 3849 2866 mt 3899 2916 L 3899 2866 mt 3849 2916 L 3849 2846 mt 3899 2896 L 3899 2846 mt 3849 2896 L 3851 2837 mt 3901 2887 L 3901 2837 mt 3851 2887 L 3851 2840 mt 3901 2890 L 3901 2840 mt 3851 2890 L 3852 2830 mt 3902 2880 L 3902 2830 mt 3852 2880 L 3852 2822 mt 3902 2872 L 3902 2822 mt 3852 2872 L 3854 2814 mt 3904 2864 L 3904 2814 mt 3854 2864 L 3855 2799 mt 3905 2849 L 3905 2799 mt 3855 2849 L 3858 2781 mt 3908 2831 L 3908 2781 mt 3858 2831 L 3860 2793 mt 3910 2843 L 3910 2793 mt 3860 2843 L 3861 2828 mt 3911 2878 L 3911 2828 mt 3861 2878 L 3864 2807 mt 3914 2857 L 3914 2807 mt 3864 2857 L 3867 2807 mt 3917 2857 L 3917 2807 mt 3867 2857 L 3868 2796 mt 3918 2846 L 3918 2796 mt 3868 2846 L 3869 2787 mt 3919 2837 L 3919 2787 mt 3869 2837 L 3873 2725 mt 3923 2775 L 3923 2725 mt 3873 2775 L 3876 2793 mt 3926 2843 L 3926 2793 mt 3876 2843 L 3877 2801 mt 3927 2851 L 3927 2801 mt 3877 2851 L 3877 2801 mt 3927 2851 L 3927 2801 mt 3877 2851 L 3877 2798 mt 3927 2848 L 3927 2798 mt 3877 2848 L 3877 2798 mt 3927 2848 L 3927 2798 mt 3877 2848 L 3878 2787 mt 3928 2837 L 3928 2787 mt 3878 2837 L 3879 2786 mt 3929 2836 L 3929 2786 mt 3879 2836 L 3880 2770 mt 3930 2820 L 3930 2770 mt 3880 2820 L 3883 2751 mt 3933 2801 L 3933 2751 mt 3883 2801 L 3884 2777 mt 3934 2827 L 3934 2777 mt 3884 2827 L 3886 2757 mt 3936 2807 L 3936 2757 mt 3886 2807 L 3898 2663 mt 3948 2713 L 3948 2663 mt 3898 2713 L 3923 2664 mt 3973 2714 L 3973 2664 mt 3923 2714 L 3954 2679 mt 4004 2729 L 4004 2679 mt 3954 2729 L 4000 2630 mt 4050 2680 L 4050 2630 mt 4000 2680 L 4162 2473 mt 4212 2523 L 4212 2473 mt 4162 2523 L 4324 2684 mt 4374 2734 L 4374 2684 mt 4324 2734 L 4590 2585 mt 4640 2635 L 4640 2585 mt 4590 2635 L 4591 3205 mt 4641 3255 L 4641 3205 mt 4591 3255 L 4592 3193 mt 4642 3243 L 4642 3193 mt 4592 3243 L 4594 3167 mt 4644 3217 L 4644 3167 mt 4594 3217 L 4596 3172 mt 4646 3222 L 4646 3172 mt 4596 3222 L 4598 3126 mt 4648 3176 L 4648 3126 mt 4598 3176 L 4601 3100 mt 4651 3150 L 4651 3100 mt 4601 3150 L 4615 3012 mt 4665 3062 L 4665 3012 mt 4615 3062 L 4615 3078 mt 4665 3128 L 4665 3078 mt 4615 3128 L 4617 3065 mt 4667 3115 L 4667 3065 mt 4617 3115 L 4620 3037 mt 4670 3087 L 4670 3037 mt 4620 3087 L 4642 2856 mt 4692 2906 L 4692 2856 mt 4642 2906 L 4644 2980 mt 4694 3030 L 4694 2980 mt 4644 3030 L 4647 2938 mt 4697 2988 L 4697 2938 mt 4647 2988 L 4650 2912 mt 4700 2962 L 4700 2912 mt 4650 2962 L 4656 2845 mt 4706 2895 L 4706 2845 mt 4656 2895 L 4658 2852 mt 4708 2902 L 4708 2852 mt 4658 2902 L 4661 2811 mt 4711 2861 L 4711 2811 mt 4661 2861 L 4665 2753 mt 4715 2803 L 4715 2753 mt 4665 2803 L 4700 2618 mt 4750 2668 L 4750 2618 mt 4700 2668 L 4701 2805 mt 4751 2855 L 4751 2805 mt 4701 2855 L 4702 2798 mt 4752 2848 L 4752 2798 mt 4702 2848 L 4702 2800 mt 4752 2850 L 4752 2800 mt 4702 2850 L 4702 2789 mt 4752 2839 L 4752 2789 mt 4702 2839 L 4703 2782 mt 4753 2832 L 4753 2782 mt 4703 2832 L 4706 2764 mt 4756 2814 L 4756 2764 mt 4706 2814 L 4708 2790 mt 4758 2840 L 4758 2790 mt 4708 2840 L 4710 2769 mt 4760 2819 L 4760 2769 mt 4710 2819 L 4710 2774 mt 4760 2824 L 4760 2774 mt 4710 2824 L 4710 2774 mt 4760 2824 L 4760 2774 mt 4710 2824 L 4710 2770 mt 4760 2820 L 4760 2770 mt 4710 2820 L 4710 2770 mt 4760 2820 L 4760 2770 mt 4710 2820 L 4711 2761 mt 4761 2811 L 4761 2761 mt 4711 2811 L 4712 2754 mt 4762 2804 L 4762 2754 mt 4712 2804 L 4713 2740 mt 4763 2790 L 4763 2740 mt 4713 2790 L 4716 2722 mt 4766 2772 L 4766 2722 mt 4716 2772 L 4717 2748 mt 4767 2798 L 4767 2748 mt 4717 2798 L 4718 2740 mt 4768 2790 L 4768 2740 mt 4718 2790 L 4719 2733 mt 4769 2783 L 4769 2733 mt 4719 2783 L 4720 2733 mt 4770 2783 L 4770 2733 mt 4720 2783 L 4722 2704 mt 4772 2754 L 4772 2704 mt 4722 2754 L 4724 2727 mt 4774 2777 L 4774 2727 mt 4724 2777 L 4726 2727 mt 4776 2777 L 4776 2727 mt 4726 2777 L 4735 2670 mt 4785 2720 L 4785 2670 mt 4735 2720 L 4737 2690 mt 4787 2740 L 4787 2690 mt 4737 2740 L 4740 2664 mt 4790 2714 L 4790 2664 mt 4740 2714 L 4760 2576 mt 4810 2626 L 4810 2576 mt 4760 2626 L 4765 2694 mt 4815 2744 L 4815 2694 mt 4765 2744 L 4767 2659 mt 4817 2709 L 4817 2659 mt 4767 2709 L 4771 2633 mt 4821 2683 L 4821 2633 mt 4771 2683 L 4771 2641 mt 4821 2691 L 4821 2641 mt 4771 2691 L 4771 2641 mt 4821 2691 L 4821 2641 mt 4771 2691 L 4772 2628 mt 4822 2678 L 4822 2628 mt 4772 2678 L 4772 2628 mt 4822 2678 L 4822 2628 mt 4772 2678 L 4773 2610 mt 4823 2660 L 4823 2610 mt 4773 2660 L 4774 2604 mt 4824 2654 L 4824 2604 mt 4774 2654 L 4775 2586 mt 4825 2636 L 4825 2586 mt 4775 2636 L 4776 2604 mt 4826 2654 L 4826 2604 mt 4776 2654 L 4777 2607 mt 4827 2657 L 4827 2607 mt 4777 2657 L 4778 2589 mt 4828 2639 L 4828 2589 mt 4778 2639 L 4779 2580 mt 4829 2630 L 4829 2580 mt 4779 2630 L 4782 2547 mt 4832 2597 L 4832 2547 mt 4782 2597 L 4784 2591 mt 4834 2641 L 4834 2591 mt 4784 2641 L 4787 2568 mt 4837 2618 L 4837 2568 mt 4787 2618 L 4788 2576 mt 4838 2626 L 4838 2576 mt 4788 2626 L 4788 2565 mt 4838 2615 L 4838 2565 mt 4788 2615 L 4789 2558 mt 4839 2608 L 4839 2558 mt 4789 2608 L 4790 2542 mt 4840 2592 L 4840 2542 mt 4790 2592 L 4793 2524 mt 4843 2574 L 4843 2524 mt 4793 2574 L 4794 2550 mt 4844 2600 L 4844 2550 mt 4794 2600 L 4796 2529 mt 4846 2579 L 4846 2529 mt 4796 2579 L 4811 2454 mt 4861 2504 L 4861 2454 mt 4811 2504 L 4826 2459 mt 4876 2509 L 4876 2459 mt 4826 2509 L 4884 2397 mt 4934 2447 L 4934 2397 mt 4884 2447 L 4894 2611 mt 4944 2661 L 4944 2611 mt 4894 2661 L 4968 2236 mt 5018 2286 L 5018 2236 mt 4968 2286 L 5179 2142 mt 5229 2192 L 5229 2142 mt 5179 2192 L 5798 1806 mt 5848 1856 L 5848 1806 mt 5798 1856 L 6232 2994 mt 6282 3044 L 6282 2994 mt 6232 3044 L gs 899 388 5359 4226 MR c np gr 2879 4901 mt ( fraction of total operations) s 577 3260 mt -90 rotate ( fraction of entries in L and U) s 90 rotate 2065 292 mt ( BCSSTK24, multisection ordering, working storage study) s 3578 3865 mt (multifrontal) s 2506 1488 mt (general sparse) s end eplot %%EndObject graph 1 epage end showpage %%Trailer %%EOF 4 L 3390 3594 mt 3340 3644 L 3342 3569 mt 3392 3619 L 3392 3569 mt 3342 3619 L 3349 3528 mt 3399 3578 L 3399 3528 mt 3349 3578 L 3ETree/doc/makefile010064400020550007177000000000270654276740000153530ustar00clevecompmath00000400000006clean : - rm -f *.dvi ETree/doc/FS1.eps010064400020550007177000000100100665245723700147540ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 50 50 500 500 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def /rscale 10.000 def /fontscale 10.000 def % 60 60 430 430 rectclip newpath 490 103 476 175 ML 461 149 476 175 ML 476 175 447 375 ML 433 149 418 332 ML 404 252 418 332 ML 418 332 447 375 ML 447 375 390 490 ML 375 149 361 175 ML 347 103 361 175 ML 361 175 332 375 ML 318 252 304 332 ML 289 149 304 332 ML 304 332 332 375 ML 332 375 390 490 ML 390 490 275 490 ML 261 149 246 332 ML 232 252 246 332 ML 246 332 218 375 ML 203 103 189 175 ML 175 149 189 175 ML 189 175 218 375 ML 218 375 160 490 ML 146 252 132 332 ML 117 149 132 332 ML 132 332 103 375 ML 88.7 149 74.3 175 ML 60 103 74.3 175 ML 74.3 175 103 375 ML 103 375 160 490 ML 160 490 275 490 ML stroke gsave /Helvetica-Bold findfont fontscale scalefont setfont 1.0 setgray 490 103 10 FC 0.0 setgray 490 103 10 OC 490 97.6 moveto (0) CSH 1.0 setgray 461 149 10 FC 0.0 setgray 461 149 10 OC 461 144 moveto (1) CSH 1.0 setgray 476 175 10 FC 0.0 setgray 476 175 10 OC 476 170 moveto (2) CSH 1.0 setgray 433 149 10 FC 0.0 setgray 433 149 10 OC 433 144 moveto (3) CSH 1.0 setgray 404 252 10 FC 0.0 setgray 404 252 10 OC 404 247 moveto (4) CSH 1.0 setgray 418 332 10 FC 0.0 setgray 418 332 10 OC 418 327 moveto (5) CSH 1.0 setgray 447 375 10 FC 0.0 setgray 447 375 10 OC 447 370 moveto (6) CSH 1.0 setgray 375 149 10 FC 0.0 setgray 375 149 10 OC 375 144 moveto (7) CSH 1.0 setgray 347 103 10 FC 0.0 setgray 347 103 10 OC 347 97.6 moveto (8) CSH 1.0 setgray 361 175 10 FC 0.0 setgray 361 175 10 OC 361 170 moveto (9) CSH 1.0 setgray 318 252 10 FC 0.0 setgray 318 252 10 OC 318 247 moveto (10) CSH 1.0 setgray 289 149 10 FC 0.0 setgray 289 149 10 OC 289 144 moveto (11) CSH 1.0 setgray 304 332 10 FC 0.0 setgray 304 332 10 OC 304 327 moveto (12) CSH 1.0 setgray 332 375 10 FC 0.0 setgray 332 375 10 OC 332 370 moveto (13) CSH 1.0 setgray 390 490 10 FC 0.0 setgray 390 490 10 OC 390 485 moveto (14) CSH 1.0 setgray 261 149 10 FC 0.0 setgray 261 149 10 OC 261 144 moveto (15) CSH 1.0 setgray 232 252 10 FC 0.0 setgray 232 252 10 OC 232 247 moveto (16) CSH 1.0 setgray 246 332 10 FC 0.0 setgray 246 332 10 OC 246 327 moveto (17) CSH 1.0 setgray 203 103 10 FC 0.0 setgray 203 103 10 OC 203 97.6 moveto (18) CSH 1.0 setgray 175 149 10 FC 0.0 setgray 175 149 10 OC 175 144 moveto (19) CSH 1.0 setgray 189 175 10 FC 0.0 setgray 189 175 10 OC 189 170 moveto (20) CSH 1.0 setgray 218 375 10 FC 0.0 setgray 218 375 10 OC 218 370 moveto (21) CSH 1.0 setgray 146 252 10 FC 0.0 setgray 146 252 10 OC 146 247 moveto (22) CSH 1.0 setgray 117 149 10 FC 0.0 setgray 117 149 10 OC 117 144 moveto (23) CSH 1.0 setgray 132 332 10 FC 0.0 setgray 132 332 10 OC 132 327 moveto (24) CSH 1.0 setgray 88.7 149 10 FC 0.0 setgray 88.7 149 10 OC 88.7 144 moveto (25) CSH 1.0 setgray 60 103 10 FC 0.0 setgray 60 103 10 OC 60 97.6 moveto (26) CSH 1.0 setgray 74.3 175 10 FC 0.0 setgray 74.3 175 10 OC 74.3 170 moveto (27) CSH 1.0 setgray 103 375 10 FC 0.0 setgray 103 375 10 OC 103 370 moveto (28) CSH 1.0 setgray 160 490 10 FC 0.0 setgray 160 490 10 OC 160 485 moveto (29) CSH 1.0 setgray 275 490 10 FC 0.0 setgray 275 490 10 OC 275 485 moveto (30) CSH grestore % 60 60 430 430 rectstroke showpage tgray 476 175 10 OC 476 170 moveto (2) CSH 1.0 setgray 433 149 10 FC 0.0 setgray 433 149 10 OC 433 144 moveto (3) CSH 1.0 setgray 404 252 10 FC 0.0 setgray 404 252 10 OC 404 247 moveto (4) CSH 1.0 setgray 418 332 10 FC 0.0 setgray 418 332 10 OC 418 327 moveto (5) CSH 1.0 setgray 447 375 10 FC 0.0 setgray 447 375 10 OC 447 370 moveto (6) CSH 1.0 setgray 375 149 10 FC 0.0 setgray 375 149 10 OC 375 144 moveto (7) CSH 1.0 setgray 347 10ETree/doc/FS2.eps010064400020550007177000000100040665245724700147610ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 50 50 500 500 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def /rscale 10.000 def /fontscale 10.000 def % 60 60 430 430 rectclip newpath 490 452 476 435 ML 461 460 476 435 ML 476 435 447 409 ML 433 477 418 452 ML 404 490 418 452 ML 418 452 447 409 ML 447 409 390 294 ML 375 460 361 435 ML 347 452 361 435 ML 361 435 332 409 ML 318 490 304 452 ML 289 477 304 452 ML 304 452 332 409 ML 332 409 390 294 ML 390 294 275 179 ML 261 477 246 452 ML 232 490 246 452 ML 246 452 218 409 ML 203 452 189 435 ML 175 460 189 435 ML 189 435 218 409 ML 218 409 160 294 ML 146 490 132 452 ML 117 477 132 452 ML 132 452 103 409 ML 88.7 460 74.3 435 ML 60 452 74.3 435 ML 74.3 435 103 409 ML 103 409 160 294 ML 160 294 275 179 ML stroke gsave /Helvetica-Bold findfont fontscale scalefont setfont 1.0 setgray 490 452 10 FC 0.0 setgray 490 452 10 OC 490 447 moveto (0) CSH 1.0 setgray 461 460 10 FC 0.0 setgray 461 460 10 OC 461 455 moveto (1) CSH 1.0 setgray 476 435 10 FC 0.0 setgray 476 435 10 OC 476 430 moveto (2) CSH 1.0 setgray 433 477 10 FC 0.0 setgray 433 477 10 OC 433 472 moveto (3) CSH 1.0 setgray 404 490 10 FC 0.0 setgray 404 490 10 OC 404 485 moveto (4) CSH 1.0 setgray 418 452 10 FC 0.0 setgray 418 452 10 OC 418 447 moveto (5) CSH 1.0 setgray 447 409 10 FC 0.0 setgray 447 409 10 OC 447 404 moveto (6) CSH 1.0 setgray 375 460 10 FC 0.0 setgray 375 460 10 OC 375 455 moveto (7) CSH 1.0 setgray 347 452 10 FC 0.0 setgray 347 452 10 OC 347 447 moveto (8) CSH 1.0 setgray 361 435 10 FC 0.0 setgray 361 435 10 OC 361 430 moveto (9) CSH 1.0 setgray 318 490 10 FC 0.0 setgray 318 490 10 OC 318 485 moveto (10) CSH 1.0 setgray 289 477 10 FC 0.0 setgray 289 477 10 OC 289 472 moveto (11) CSH 1.0 setgray 304 452 10 FC 0.0 setgray 304 452 10 OC 304 447 moveto (12) CSH 1.0 setgray 332 409 10 FC 0.0 setgray 332 409 10 OC 332 404 moveto (13) CSH 1.0 setgray 390 294 10 FC 0.0 setgray 390 294 10 OC 390 289 moveto (14) CSH 1.0 setgray 261 477 10 FC 0.0 setgray 261 477 10 OC 261 472 moveto (15) CSH 1.0 setgray 232 490 10 FC 0.0 setgray 232 490 10 OC 232 485 moveto (16) CSH 1.0 setgray 246 452 10 FC 0.0 setgray 246 452 10 OC 246 447 moveto (17) CSH 1.0 setgray 203 452 10 FC 0.0 setgray 203 452 10 OC 203 447 moveto (18) CSH 1.0 setgray 175 460 10 FC 0.0 setgray 175 460 10 OC 175 455 moveto (19) CSH 1.0 setgray 189 435 10 FC 0.0 setgray 189 435 10 OC 189 430 moveto (20) CSH 1.0 setgray 218 409 10 FC 0.0 setgray 218 409 10 OC 218 404 moveto (21) CSH 1.0 setgray 146 490 10 FC 0.0 setgray 146 490 10 OC 146 485 moveto (22) CSH 1.0 setgray 117 477 10 FC 0.0 setgray 117 477 10 OC 117 472 moveto (23) CSH 1.0 setgray 132 452 10 FC 0.0 setgray 132 452 10 OC 132 447 moveto (24) CSH 1.0 setgray 88.7 460 10 FC 0.0 setgray 88.7 460 10 OC 88.7 455 moveto (25) CSH 1.0 setgray 60 452 10 FC 0.0 setgray 60 452 10 OC 60 447 moveto (26) CSH 1.0 setgray 74.3 435 10 FC 0.0 setgray 74.3 435 10 OC 74.3 430 moveto (27) CSH 1.0 setgray 103 409 10 FC 0.0 setgray 103 409 10 OC 103 404 moveto (28) CSH 1.0 setgray 160 294 10 FC 0.0 setgray 160 294 10 OC 160 289 moveto (29) CSH 1.0 setgray 275 179 10 FC 0.0 setgray 275 179 10 OC 275 174 moveto (30) CSH grestore % 60 60 430 430 rectstroke showpage ETree/doc/GRD7x7x7_nzA.eps010064400020550007177000000427020665246077200164470ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 50 50 550 550 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def /rscale 1.868 def /fontscale 6.000 def 60 60 480 480 rectclip newpath 535 278 495 272 ML 532 255 495 272 ML 495 272 453 263 ML 526 233 485 235 ML 518 211 485 235 ML 485 235 453 263 ML 453 263 407 251 ML 508 190 469 200 ML 496 171 469 200 ML 469 200 427 208 ML 483 152 446 170 ML 467 135 446 170 ML 446 170 427 208 ML 427 208 407 251 ML 407 251 353 243 ML 450 120 417 144 ML 431 106 417 144 ML 417 144 381 167 ML 412 94.1 384 124 ML 391 84.3 384 124 ML 384 124 381 167 ML 381 167 340 190 ML 369 76.6 348 111 ML 346 71 348 111 ML 348 111 324 146 ML 324 67.6 310 106 ML 301 66.5 310 106 ML 310 106 324 146 ML 324 146 340 190 ML 340 190 353 243 ML 353 243 299 262 ML 277 67.6 272 108 ML 255 71 272 108 ML 272 108 262 149 ML 232 76.6 234 117 ML 210 84.3 234 117 ML 234 117 262 149 ML 262 149 250 195 ML 190 94.1 200 133 ML 170 106 200 133 ML 200 133 207 175 ML 151 120 169 156 ML 134 135 169 156 ML 169 156 207 175 ML 207 175 250 195 ML 250 195 242 248 ML 118 152 143 184 ML 105 171 143 184 ML 143 184 166 220 ML 92.8 190 123 217 ML 82.9 211 123 217 ML 123 217 166 220 ML 166 220 190 261 ML 75.2 233 110 253 ML 69.5 255 110 253 ML 110 253 145 278 ML 66.1 278 105 291 ML 65 301 105 291 ML 105 291 145 278 ML 145 278 190 261 ML 190 261 242 248 ML 242 248 299 262 ML 299 262 301 301 ML 66.1 324 106 329 ML 69.5 346 106 329 ML 106 329 148 339 ML 75.2 369 116 366 ML 82.9 390 116 366 ML 116 366 148 339 ML 148 339 194 351 ML 92.8 411 132 401 ML 105 431 132 401 ML 132 401 174 394 ML 118 449 155 432 ML 134 466 155 432 ML 155 432 174 394 ML 174 394 194 351 ML 194 351 248 359 ML 151 482 184 458 ML 170 496 184 458 ML 184 458 220 435 ML 190 507 217 477 ML 210 517 217 477 ML 217 477 220 435 ML 220 435 261 411 ML 232 525 253 490 ML 255 530 253 490 ML 253 490 277 455 ML 277 534 291 496 ML 301 535 291 496 ML 291 496 277 455 ML 277 455 261 411 ML 261 411 248 359 ML 248 359 302 340 ML 324 534 329 494 ML 346 530 329 494 ML 329 494 339 452 ML 369 525 367 485 ML 391 517 367 485 ML 367 485 339 452 ML stroke newpath 339 452 351 407 ML 412 507 401 468 ML 431 496 401 468 ML 401 468 394 426 ML 450 482 432 445 ML 467 466 432 445 ML 432 445 394 426 ML 394 426 351 407 ML 351 407 359 353 ML 483 449 458 417 ML 496 431 458 417 ML 458 417 435 381 ML 508 411 478 384 ML 518 390 478 384 ML 478 384 435 381 ML 435 381 411 340 ML 526 369 491 348 ML 532 346 491 348 ML 491 348 456 324 ML 535 324 497 310 ML 536 301 497 310 ML 497 310 456 324 ML 456 324 411 340 ML 411 340 359 353 ML 359 353 302 340 ML 302 340 301 301 ML stroke gsave 1.0 setgray 535 278 2.11 rscale mul FC 0.0 setgray 535 278 2.11 rscale mul OC 535 278 1.5 sub moveto 1.0 setgray 532 255 2.65 rscale mul FC 0.0 setgray 532 255 2.65 rscale mul OC 532 255 1.5 sub moveto 1.0 setgray 495 272 2.39 rscale mul FC 0.0 setgray 495 272 2.39 rscale mul OC 495 272 1.5 sub moveto 1.0 setgray 526 233 2.65 rscale mul FC 0.0 setgray 526 233 2.65 rscale mul OC 526 233 1.5 sub moveto 1.0 setgray 518 211 3.29 rscale mul FC 0.0 setgray 518 211 3.29 rscale mul OC 518 211 1.5 sub moveto 1.0 setgray 485 235 3.09 rscale mul FC 0.0 setgray 485 235 3.09 rscale mul OC 485 235 1.5 sub moveto 1.0 setgray 453 263 4.37 rscale mul FC 0.0 setgray 453 263 4.37 rscale mul OC 453 263 1.5 sub moveto 1.0 setgray 508 190 2.65 rscale mul FC 0.0 setgray 508 190 2.65 rscale mul OC 508 190 1.5 sub moveto 1.0 setgray 496 171 3.29 rscale mul FC 0.0 setgray 496 171 3.29 rscale mul OC 496 171 1.5 sub moveto 1.0 setgray 469 200 3.09 rscale mul FC 0.0 setgray 469 200 3.09 rscale mul OC 469 200 1.5 sub moveto 1.0 setgray 483 152 3.29 rscale mul FC 0.0 setgray 483 152 3.29 rscale mul OC 483 152 1.5 sub moveto 1.0 setgray 467 135 4.07 rscale mul FC 0.0 setgray 467 135 4.07 rscale mul OC 467 135 1.5 sub moveto 1.0 setgray 446 170 3.91 rscale mul FC 0.0 setgray 446 170 3.91 rscale mul OC 446 170 1.5 sub moveto 1.0 setgray 427 208 5.86 rscale mul FC 0.0 setgray 427 208 5.86 rscale mul OC 427 208 1.5 sub moveto 1.0 setgray 407 251 6.63 rscale mul FC 0.0 setgray 407 251 6.63 rscale mul OC 407 251 1.5 sub moveto 1.0 setgray 450 120 2.65 rscale mul FC 0.0 setgray 450 120 2.65 rscale mul OC 450 120 1.5 sub moveto 1.0 setgray 431 106 2.11 rscale mul FC 0.0 setgray 431 106 2.11 rscale mul OC 431 106 1.5 sub moveto 1.0 setgray 417 144 2.39 rscale mul FC 0.0 setgray 417 144 2.39 rscale mul OC 417 144 1.5 sub moveto 1.0 setgray 412 94.1 3.29 rscale mul FC 0.0 setgray 412 94.1 3.29 rscale mul OC 412 94.1 1.5 sub moveto 1.0 setgray 391 84.3 2.65 rscale mul FC 0.0 setgray 391 84.3 2.65 rscale mul OC 391 84.3 1.5 sub moveto 1.0 setgray 384 124 3.09 rscale mul FC 0.0 setgray 384 124 3.09 rscale mul OC 384 124 1.5 sub moveto 1.0 setgray 381 167 4.37 rscale mul FC 0.0 setgray 381 167 4.37 rscale mul OC 381 167 1.5 sub moveto 1.0 setgray 369 76.6 3.29 rscale mul FC 0.0 setgray 369 76.6 3.29 rscale mul OC 369 76.6 1.5 sub moveto 1.0 setgray 346 71 2.65 rscale mul FC 0.0 setgray 346 71 2.65 rscale mul OC 346 71 1.5 sub moveto 1.0 setgray 348 111 3.09 rscale mul FC 0.0 setgray 348 111 3.09 rscale mul OC 348 111 1.5 sub moveto 1.0 setgray 324 67.6 4.07 rscale mul FC 0.0 setgray 324 67.6 4.07 rscale mul OC 324 67.6 1.5 sub moveto 1.0 setgray 301 66.5 3.29 rscale mul FC 0.0 setgray 301 66.5 3.29 rscale mul OC 301 66.5 1.5 sub moveto 1.0 setgray 310 106 3.91 rscale mul FC 0.0 setgray 310 106 3.91 rscale mul OC 310 106 1.5 sub moveto 1.0 setgray 324 146 5.86 rscale mul FC 0.0 setgray 324 146 5.86 rscale mul OC 324 146 1.5 sub moveto 1.0 setgray 340 190 6.63 rscale mul FC 0.0 setgray 340 190 6.63 rscale mul OC 340 190 1.5 sub moveto 1.0 setgray 353 243 6.63 rscale mul FC 0.0 setgray 353 243 6.63 rscale mul OC 353 243 1.5 sub moveto 1.0 setgray 277 67.6 2.65 rscale mul FC 0.0 setgray 277 67.6 2.65 rscale mul OC 277 67.6 1.5 sub moveto 1.0 setgray 255 71 3.29 rscale mul FC 0.0 setgray 255 71 3.29 rscale mul OC 255 71 1.5 sub moveto 1.0 setgray 272 108 3.09 rscale mul FC 0.0 setgray 272 108 3.09 rscale mul OC 272 108 1.5 sub moveto 1.0 setgray 232 76.6 2.11 rscale mul FC 0.0 setgray 232 76.6 2.11 rscale mul OC 232 76.6 1.5 sub moveto 1.0 setgray 210 84.3 2.65 rscale mul FC 0.0 setgray 210 84.3 2.65 rscale mul OC 210 84.3 1.5 sub moveto 1.0 setgray 234 117 2.39 rscale mul FC 0.0 setgray 234 117 2.39 rscale mul OC 234 117 1.5 sub moveto 1.0 setgray 262 149 4.37 rscale mul FC 0.0 setgray 262 149 4.37 rscale mul OC 262 149 1.5 sub moveto 1.0 setgray 190 94.1 3.29 rscale mul FC 0.0 setgray 190 94.1 3.29 rscale mul OC 190 94.1 1.5 sub moveto 1.0 setgray 170 106 4.07 rscale mul FC 0.0 setgray 170 106 4.07 rscale mul OC 170 106 1.5 sub moveto 1.0 setgray 200 133 3.91 rscale mul FC 0.0 setgray 200 133 3.91 rscale mul OC 200 133 1.5 sub moveto 1.0 setgray 151 120 2.65 rscale mul FC 0.0 setgray 151 120 2.65 rscale mul OC 151 120 1.5 sub moveto 1.0 setgray 134 135 3.29 rscale mul FC 0.0 setgray 134 135 3.29 rscale mul OC 134 135 1.5 sub moveto 1.0 setgray 169 156 3.09 rscale mul FC 0.0 setgray 169 156 3.09 rscale mul OC 169 156 1.5 sub moveto 1.0 setgray 207 175 5.86 rscale mul FC 0.0 setgray 207 175 5.86 rscale mul OC 207 175 1.5 sub moveto 1.0 setgray 250 195 6.63 rscale mul FC 0.0 setgray 250 195 6.63 rscale mul OC 250 195 1.5 sub moveto 1.0 setgray 118 152 3.29 rscale mul FC 0.0 setgray 118 152 3.29 rscale mul OC 118 152 1.5 sub moveto 1.0 setgray 105 171 2.65 rscale mul FC 0.0 setgray 105 171 2.65 rscale mul OC 105 171 1.5 sub moveto 1.0 setgray 143 184 3.09 rscale mul FC 0.0 setgray 143 184 3.09 rscale mul OC 143 184 1.5 sub moveto 1.0 setgray 92.8 190 2.65 rscale mul FC 0.0 setgray 92.8 190 2.65 rscale mul OC 92.8 190 1.5 sub moveto 1.0 setgray 82.9 211 2.11 rscale mul FC 0.0 setgray 82.9 211 2.11 rscale mul OC 82.9 211 1.5 sub moveto 1.0 setgray 123 217 2.39 rscale mul FC 0.0 setgray 123 217 2.39 rscale mul OC 123 217 1.5 sub moveto 1.0 setgray 166 220 4.37 rscale mul FC 0.0 setgray 166 220 4.37 rscale mul OC 166 220 1.5 sub moveto 1.0 setgray 75.2 233 4.07 rscale mul FC 0.0 setgray 75.2 233 4.07 rscale mul OC 75.2 233 1.5 sub moveto 1.0 setgray 69.5 255 3.29 rscale mul FC 0.0 setgray 69.5 255 3.29 rscale mul OC 69.5 255 1.5 sub moveto 1.0 setgray 110 253 3.91 rscale mul FC 0.0 setgray 110 253 3.91 rscale mul OC 110 253 1.5 sub moveto 1.0 setgray 66.1 278 3.29 rscale mul FC 0.0 setgray 66.1 278 3.29 rscale mul OC 66.1 278 1.5 sub moveto 1.0 setgray 65 301 2.65 rscale mul FC 0.0 setgray 65 301 2.65 rscale mul OC 65 301 1.5 sub moveto 1.0 setgray 105 291 3.09 rscale mul FC 0.0 setgray 105 291 3.09 rscale mul OC 105 291 1.5 sub moveto 1.0 setgray 145 278 5.86 rscale mul FC 0.0 setgray 145 278 5.86 rscale mul OC 145 278 1.5 sub moveto 1.0 setgray 190 261 6.63 rscale mul FC 0.0 setgray 190 261 6.63 rscale mul OC 190 261 1.5 sub moveto 1.0 setgray 242 248 6.63 rscale mul FC 0.0 setgray 242 248 6.63 rscale mul OC 242 248 1.5 sub moveto 1.0 setgray 299 262 8.85 rscale mul FC 0.0 setgray 299 262 8.85 rscale mul OC 299 262 1.5 sub moveto 1.0 setgray 66.1 324 2.65 rscale mul FC 0.0 setgray 66.1 324 2.65 rscale mul OC 66.1 324 1.5 sub moveto 1.0 setgray 69.5 346 3.29 rscale mul FC 0.0 setgray 69.5 346 3.29 rscale mul OC 69.5 346 1.5 sub moveto 1.0 setgray 106 329 3.09 rscale mul FC 0.0 setgray 106 329 3.09 rscale mul OC 106 329 1.5 sub moveto 1.0 setgray 75.2 369 3.29 rscale mul FC 0.0 setgray 75.2 369 3.29 rscale mul OC 75.2 369 1.5 sub moveto 1.0 setgray 82.9 390 4.07 rscale mul FC 0.0 setgray 82.9 390 4.07 rscale mul OC 82.9 390 1.5 sub moveto 1.0 setgray 116 366 3.91 rscale mul FC 0.0 setgray 116 366 3.91 rscale mul OC 116 366 1.5 sub moveto 1.0 setgray 148 339 5.86 rscale mul FC 0.0 setgray 148 339 5.86 rscale mul OC 148 339 1.5 sub moveto 1.0 setgray 92.8 411 2.11 rscale mul FC 0.0 setgray 92.8 411 2.11 rscale mul OC 92.8 411 1.5 sub moveto 1.0 setgray 105 431 2.65 rscale mul FC 0.0 setgray 105 431 2.65 rscale mul OC 105 431 1.5 sub moveto 1.0 setgray 132 401 2.39 rscale mul FC 0.0 setgray 132 401 2.39 rscale mul OC 132 401 1.5 sub moveto 1.0 setgray 118 449 2.65 rscale mul FC 0.0 setgray 118 449 2.65 rscale mul OC 118 449 1.5 sub moveto 1.0 setgray 134 466 3.29 rscale mul FC 0.0 setgray 134 466 3.29 rscale mul OC 134 466 1.5 sub moveto 1.0 setgray 155 432 3.09 rscale mul FC 0.0 setgray 155 432 3.09 rscale mul OC 155 432 1.5 sub moveto 1.0 setgray 174 394 4.37 rscale mul FC 0.0 setgray 174 394 4.37 rscale mul OC 174 394 1.5 sub moveto 1.0 setgray 194 351 6.63 rscale mul FC 0.0 setgray 194 351 6.63 rscale mul OC 194 351 1.5 sub moveto 1.0 setgray 151 482 3.29 rscale mul FC 0.0 setgray 151 482 3.29 rscale mul OC 151 482 1.5 sub moveto 1.0 setgray 170 496 2.65 rscale mul FC 0.0 setgray 170 496 2.65 rscale mul OC 170 496 1.5 sub moveto 1.0 setgray 184 458 3.09 rscale mul FC 0.0 setgray 184 458 3.09 rscale mul OC 184 458 1.5 sub moveto 1.0 setgray 190 507 4.07 rscale mul FC 0.0 setgray 190 507 4.07 rscale mul OC 190 507 1.5 sub moveto 1.0 setgray 210 517 3.29 rscale mul FC 0.0 setgray 210 517 3.29 rscale mul OC 210 517 1.5 sub moveto 1.0 setgray 217 477 3.91 rscale mul FC 0.0 setgray 217 477 3.91 rscale mul OC 217 477 1.5 sub moveto 1.0 setgray 220 435 5.86 rscale mul FC 0.0 setgray 220 435 5.86 rscale mul OC 220 435 1.5 sub moveto 1.0 setgray 232 525 2.65 rscale mul FC 0.0 setgray 232 525 2.65 rscale mul OC 232 525 1.5 sub moveto 1.0 setgray 255 530 2.11 rscale mul FC 0.0 setgray 255 530 2.11 rscale mul OC 255 530 1.5 sub moveto 1.0 setgray 253 490 2.39 rscale mul FC 0.0 setgray 253 490 2.39 rscale mul OC 253 490 1.5 sub moveto 1.0 setgray 277 534 3.29 rscale mul FC 0.0 setgray 277 534 3.29 rscale mul OC 277 534 1.5 sub moveto 1.0 setgray 301 535 2.65 rscale mul FC 0.0 setgray 301 535 2.65 rscale mul OC 301 535 1.5 sub moveto 1.0 setgray 291 496 3.09 rscale mul FC 0.0 setgray 291 496 3.09 rscale mul OC 291 496 1.5 sub moveto 1.0 setgray 277 455 4.37 rscale mul FC 0.0 setgray 277 455 4.37 rscale mul OC 277 455 1.5 sub moveto 1.0 setgray 261 411 6.63 rscale mul FC 0.0 setgray 261 411 6.63 rscale mul OC 261 411 1.5 sub moveto 1.0 setgray 248 359 6.63 rscale mul FC 0.0 setgray 248 359 6.63 rscale mul OC 248 359 1.5 sub moveto 1.0 setgray 324 534 3.29 rscale mul FC 0.0 setgray 324 534 3.29 rscale mul OC 324 534 1.5 sub moveto 1.0 setgray 346 530 4.07 rscale mul FC 0.0 setgray 346 530 4.07 rscale mul OC 346 530 1.5 sub moveto 1.0 setgray 329 494 3.91 rscale mul FC 0.0 setgray 329 494 3.91 rscale mul OC 329 494 1.5 sub moveto 1.0 setgray 369 525 2.65 rscale mul FC 0.0 setgray 369 525 2.65 rscale mul OC 369 525 1.5 sub moveto 1.0 setgray 391 517 3.29 rscale mul FC 0.0 setgray 391 517 3.29 rscale mul OC 391 517 1.5 sub moveto 1.0 setgray 367 485 3.09 rscale mul FC 0.0 setgray 367 485 3.09 rscale mul OC 367 485 1.5 sub moveto 1.0 setgray 339 452 5.86 rscale mul FC 0.0 setgray 339 452 5.86 rscale mul OC 339 452 1.5 sub moveto 1.0 setgray 412 507 2.65 rscale mul FC 0.0 setgray 412 507 2.65 rscale mul OC 412 507 1.5 sub moveto 1.0 setgray 431 496 3.29 rscale mul FC 0.0 setgray 431 496 3.29 rscale mul OC 431 496 1.5 sub moveto 1.0 setgray 401 468 3.09 rscale mul FC 0.0 setgray 401 468 3.09 rscale mul OC 401 468 1.5 sub moveto 1.0 setgray 450 482 2.11 rscale mul FC 0.0 setgray 450 482 2.11 rscale mul OC 450 482 1.5 sub moveto 1.0 setgray 467 466 2.65 rscale mul FC 0.0 setgray 467 466 2.65 rscale mul OC 467 466 1.5 sub moveto 1.0 setgray 432 445 2.39 rscale mul FC 0.0 setgray 432 445 2.39 rscale mul OC 432 445 1.5 sub moveto 1.0 setgray 394 426 4.37 rscale mul FC 0.0 setgray 394 426 4.37 rscale mul OC 394 426 1.5 sub moveto 1.0 setgray 351 407 6.63 rscale mul FC 0.0 setgray 351 407 6.63 rscale mul OC 351 407 1.5 sub moveto 1.0 setgray 483 449 4.07 rscale mul FC 0.0 setgray 483 449 4.07 rscale mul OC 483 449 1.5 sub moveto 1.0 setgray 496 431 3.29 rscale mul FC 0.0 setgray 496 431 3.29 rscale mul OC 496 431 1.5 sub moveto 1.0 setgray 458 417 3.91 rscale mul FC 0.0 setgray 458 417 3.91 rscale mul OC 458 417 1.5 sub moveto 1.0 setgray 508 411 3.29 rscale mul FC 0.0 setgray 508 411 3.29 rscale mul OC 508 411 1.5 sub moveto 1.0 setgray 518 390 2.65 rscale mul FC 0.0 setgray 518 390 2.65 rscale mul OC 518 390 1.5 sub moveto 1.0 setgray 478 384 3.09 rscale mul FC 0.0 setgray 478 384 3.09 rscale mul OC 478 384 1.5 sub moveto 1.0 setgray 435 381 5.86 rscale mul FC 0.0 setgray 435 381 5.86 rscale mul OC 435 381 1.5 sub moveto 1.0 setgray 526 369 3.29 rscale mul FC 0.0 setgray 526 369 3.29 rscale mul OC 526 369 1.5 sub moveto 1.0 setgray 532 346 2.65 rscale mul FC 0.0 setgray 532 346 2.65 rscale mul OC 532 346 1.5 sub moveto 1.0 setgray 491 348 3.09 rscale mul FC 0.0 setgray 491 348 3.09 rscale mul OC 491 348 1.5 sub moveto 1.0 setgray 535 324 2.65 rscale mul FC 0.0 setgray 535 324 2.65 rscale mul OC 535 324 1.5 sub moveto 1.0 setgray 536 301 2.11 rscale mul FC 0.0 setgray 536 301 2.11 rscale mul OC 536 301 1.5 sub moveto 1.0 setgray 497 310 2.39 rscale mul FC 0.0 setgray 497 310 2.39 rscale mul OC 497 310 1.5 sub moveto 1.0 setgray 456 324 4.37 rscale mul FC 0.0 setgray 456 324 4.37 rscale mul OC 456 324 1.5 sub moveto 1.0 setgray 411 340 6.63 rscale mul FC 0.0 setgray 411 340 6.63 rscale mul OC 411 340 1.5 sub moveto 1.0 setgray 359 353 6.63 rscale mul FC 0.0 setgray 359 353 6.63 rscale mul OC 359 353 1.5 sub moveto 1.0 setgray 302 340 8.85 rscale mul FC 0.0 setgray 302 340 8.85 rscale mul OC 302 340 1.5 sub moveto 1.0 setgray 301 301 10.7 rscale mul FC 0.0 setgray 301 301 10.7 rscale mul OC 301 301 1.5 sub moveto grestore 60 60 480 480 rectstroke showpage setgray 262 149 4.37 rscale mul FC 0.0 setgray 262 149 4.ETree/doc/GRD7x7x7_nzF.eps010064400020550007177000000426220665246105200164450ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 50 50 550 550 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def /rscale 0.999 def /fontscale 6.000 def 60 60 480 480 rectclip newpath 539 276 498 271 ML 535 253 498 271 ML 498 271 455 261 ML 530 230 488 233 ML 522 208 488 233 ML 488 233 455 261 ML 455 261 408 249 ML 512 187 472 197 ML 500 167 472 197 ML 472 197 429 205 ML 486 148 448 166 ML 470 130 448 166 ML 448 166 429 205 ML 429 205 408 249 ML 408 249 354 241 ML 452 114 419 139 ML 433 100 419 139 ML 419 139 382 163 ML 413 88.3 386 119 ML 392 78.3 386 119 ML 386 119 382 163 ML 382 163 340 187 ML 370 70.3 349 106 ML 347 64.6 349 106 ML 349 106 323 142 ML 324 61.2 310 100 ML 300 60 310 100 ML 310 100 323 142 ML 323 142 340 187 ML 340 187 354 241 ML 354 241 298 260 ML 276 61.2 271 102 ML 253 64.6 271 102 ML 271 102 261 145 ML 230 70.3 233 112 ML 208 78.3 233 112 ML 233 112 261 145 ML 261 145 249 192 ML 187 88.3 197 128 ML 167 100 197 128 ML 197 128 205 171 ML 148 114 166 152 ML 130 130 166 152 ML 166 152 205 171 ML 205 171 249 192 ML 249 192 241 246 ML 114 148 139 181 ML 100 167 139 181 ML 139 181 163 218 ML 88.3 187 119 214 ML 78.3 208 119 214 ML 119 214 163 218 ML 163 218 187 260 ML 70.3 230 106 251 ML 64.6 253 106 251 ML 106 251 142 277 ML 61.2 276 100 290 ML 60 300 100 290 ML 100 290 142 277 ML 142 277 187 260 ML 187 260 241 246 ML 241 246 298 260 ML 298 260 300 300 ML 61.2 324 102 329 ML 64.6 347 102 329 ML 102 329 145 339 ML 70.3 370 112 367 ML 78.3 392 112 367 ML 112 367 145 339 ML 145 339 192 351 ML 88.3 413 128 403 ML 100 433 128 403 ML 128 403 171 395 ML 114 452 152 434 ML 130 470 152 434 ML 152 434 171 395 ML 171 395 192 351 ML 192 351 246 359 ML 148 486 181 461 ML 167 500 181 461 ML 181 461 218 437 ML 187 512 214 481 ML 208 522 214 481 ML 214 481 218 437 ML 218 437 260 413 ML 230 530 251 494 ML 253 535 251 494 ML 251 494 277 458 ML 276 539 290 500 ML 300 540 290 500 ML 290 500 277 458 ML 277 458 260 413 ML 260 413 246 359 ML 246 359 302 340 ML 324 539 329 498 ML 347 535 329 498 ML 329 498 339 455 ML 370 530 367 488 ML 392 522 367 488 ML 367 488 339 455 ML stroke newpath 339 455 351 408 ML 413 512 403 472 ML 433 500 403 472 ML 403 472 395 429 ML 452 486 434 448 ML 470 470 434 448 ML 434 448 395 429 ML 395 429 351 408 ML 351 408 359 354 ML 486 452 461 419 ML 500 433 461 419 ML 461 419 437 382 ML 512 413 481 386 ML 522 392 481 386 ML 481 386 437 382 ML 437 382 413 340 ML 530 370 494 349 ML 535 347 494 349 ML 494 349 458 323 ML 539 324 500 310 ML 540 300 500 310 ML 500 310 458 323 ML 458 323 413 340 ML 413 340 359 354 ML 359 354 302 340 ML 302 340 300 300 ML stroke gsave 1.0 setgray 539 276 1.6 rscale mul FC 0.0 setgray 539 276 1.6 rscale mul OC 539 276 1.5 sub moveto 1.0 setgray 535 253 1.95 rscale mul FC 0.0 setgray 535 253 1.95 rscale mul OC 535 253 1.5 sub moveto 1.0 setgray 498 271 2.11 rscale mul FC 0.0 setgray 498 271 2.11 rscale mul OC 498 271 1.5 sub moveto 1.0 setgray 530 230 1.95 rscale mul FC 0.0 setgray 530 230 1.95 rscale mul OC 530 230 1.5 sub moveto 1.0 setgray 522 208 2.39 rscale mul FC 0.0 setgray 522 208 2.39 rscale mul OC 522 208 1.5 sub moveto 1.0 setgray 488 233 2.65 rscale mul FC 0.0 setgray 488 233 2.65 rscale mul OC 488 233 1.5 sub moveto 1.0 setgray 455 261 4.89 rscale mul FC 0.0 setgray 455 261 4.89 rscale mul OC 455 261 1.5 sub moveto 1.0 setgray 512 187 1.95 rscale mul FC 0.0 setgray 512 187 1.95 rscale mul OC 512 187 1.5 sub moveto 1.0 setgray 500 167 2.39 rscale mul FC 0.0 setgray 500 167 2.39 rscale mul OC 500 167 1.5 sub moveto 1.0 setgray 472 197 2.65 rscale mul FC 0.0 setgray 472 197 2.65 rscale mul OC 472 197 1.5 sub moveto 1.0 setgray 486 148 2.39 rscale mul FC 0.0 setgray 486 148 2.39 rscale mul OC 486 148 1.5 sub moveto 1.0 setgray 470 130 2.93 rscale mul FC 0.0 setgray 470 130 2.93 rscale mul OC 470 130 1.5 sub moveto 1.0 setgray 448 166 3.29 rscale mul FC 0.0 setgray 448 166 3.29 rscale mul OC 448 166 1.5 sub moveto 1.0 setgray 429 205 6.26 rscale mul FC 0.0 setgray 429 205 6.26 rscale mul OC 429 205 1.5 sub moveto 1.0 setgray 408 249 11 rscale mul FC 0.0 setgray 408 249 11 rscale mul OC 408 249 1.5 sub moveto 1.0 setgray 452 114 1.95 rscale mul FC 0.0 setgray 452 114 1.95 rscale mul OC 452 114 1.5 sub moveto 1.0 setgray 433 100 1.6 rscale mul FC 0.0 setgray 433 100 1.6 rscale mul OC 433 100 1.5 sub moveto 1.0 setgray 419 139 2.11 rscale mul FC 0.0 setgray 419 139 2.11 rscale mul OC 419 139 1.5 sub moveto 1.0 setgray 413 88.3 2.39 rscale mul FC 0.0 setgray 413 88.3 2.39 rscale mul OC 413 88.3 1.5 sub moveto 1.0 setgray 392 78.3 1.95 rscale mul FC 0.0 setgray 392 78.3 1.95 rscale mul OC 392 78.3 1.5 sub moveto 1.0 setgray 386 119 2.65 rscale mul FC 0.0 setgray 386 119 2.65 rscale mul OC 386 119 1.5 sub moveto 1.0 setgray 382 163 4.89 rscale mul FC 0.0 setgray 382 163 4.89 rscale mul OC 382 163 1.5 sub moveto 1.0 setgray 370 70.3 2.39 rscale mul FC 0.0 setgray 370 70.3 2.39 rscale mul OC 370 70.3 1.5 sub moveto 1.0 setgray 347 64.6 1.95 rscale mul FC 0.0 setgray 347 64.6 1.95 rscale mul OC 347 64.6 1.5 sub moveto 1.0 setgray 349 106 2.65 rscale mul FC 0.0 setgray 349 106 2.65 rscale mul OC 349 106 1.5 sub moveto 1.0 setgray 324 61.2 2.93 rscale mul FC 0.0 setgray 324 61.2 2.93 rscale mul OC 324 61.2 1.5 sub moveto 1.0 setgray 300 60 2.39 rscale mul FC 0.0 setgray 300 60 2.39 rscale mul OC 300 60 1.5 sub moveto 1.0 setgray 310 100 3.29 rscale mul FC 0.0 setgray 310 100 3.29 rscale mul OC 310 100 1.5 sub moveto 1.0 setgray 323 142 6.26 rscale mul FC 0.0 setgray 323 142 6.26 rscale mul OC 323 142 1.5 sub moveto 1.0 setgray 340 187 11 rscale mul FC 0.0 setgray 340 187 11 rscale mul OC 340 187 1.5 sub moveto 1.0 setgray 354 241 12.4 rscale mul FC 0.0 setgray 354 241 12.4 rscale mul OC 354 241 1.5 sub moveto 1.0 setgray 276 61.2 1.95 rscale mul FC 0.0 setgray 276 61.2 1.95 rscale mul OC 276 61.2 1.5 sub moveto 1.0 setgray 253 64.6 2.39 rscale mul FC 0.0 setgray 253 64.6 2.39 rscale mul OC 253 64.6 1.5 sub moveto 1.0 setgray 271 102 2.65 rscale mul FC 0.0 setgray 271 102 2.65 rscale mul OC 271 102 1.5 sub moveto 1.0 setgray 230 70.3 1.6 rscale mul FC 0.0 setgray 230 70.3 1.6 rscale mul OC 230 70.3 1.5 sub moveto 1.0 setgray 208 78.3 1.95 rscale mul FC 0.0 setgray 208 78.3 1.95 rscale mul OC 208 78.3 1.5 sub moveto 1.0 setgray 233 112 2.11 rscale mul FC 0.0 setgray 233 112 2.11 rscale mul OC 233 112 1.5 sub moveto 1.0 setgray 261 145 4.89 rscale mul FC 0.0 setgray 261 145 4.89 rscale mul OC 261 145 1.5 sub moveto 1.0 setgray 187 88.3 2.39 rscale mul FC 0.0 setgray 187 88.3 2.39 rscale mul OC 187 88.3 1.5 sub moveto 1.0 setgray 167 100 2.93 rscale mul FC 0.0 setgray 167 100 2.93 rscale mul OC 167 100 1.5 sub moveto 1.0 setgray 197 128 3.29 rscale mul FC 0.0 setgray 197 128 3.29 rscale mul OC 197 128 1.5 sub moveto 1.0 setgray 148 114 1.95 rscale mul FC 0.0 setgray 148 114 1.95 rscale mul OC 148 114 1.5 sub moveto 1.0 setgray 130 130 2.39 rscale mul FC 0.0 setgray 130 130 2.39 rscale mul OC 130 130 1.5 sub moveto 1.0 setgray 166 152 2.65 rscale mul FC 0.0 setgray 166 152 2.65 rscale mul OC 166 152 1.5 sub moveto 1.0 setgray 205 171 6.26 rscale mul FC 0.0 setgray 205 171 6.26 rscale mul OC 205 171 1.5 sub moveto 1.0 setgray 249 192 11 rscale mul FC 0.0 setgray 249 192 11 rscale mul OC 249 192 1.5 sub moveto 1.0 setgray 114 148 2.39 rscale mul FC 0.0 setgray 114 148 2.39 rscale mul OC 114 148 1.5 sub moveto 1.0 setgray 100 167 1.95 rscale mul FC 0.0 setgray 100 167 1.95 rscale mul OC 100 167 1.5 sub moveto 1.0 setgray 139 181 2.65 rscale mul FC 0.0 setgray 139 181 2.65 rscale mul OC 139 181 1.5 sub moveto 1.0 setgray 88.3 187 1.95 rscale mul FC 0.0 setgray 88.3 187 1.95 rscale mul OC 88.3 187 1.5 sub moveto 1.0 setgray 78.3 208 1.6 rscale mul FC 0.0 setgray 78.3 208 1.6 rscale mul OC 78.3 208 1.5 sub moveto 1.0 setgray 119 214 2.11 rscale mul FC 0.0 setgray 119 214 2.11 rscale mul OC 119 214 1.5 sub moveto 1.0 setgray 163 218 4.89 rscale mul FC 0.0 setgray 163 218 4.89 rscale mul OC 163 218 1.5 sub moveto 1.0 setgray 70.3 230 2.93 rscale mul FC 0.0 setgray 70.3 230 2.93 rscale mul OC 70.3 230 1.5 sub moveto 1.0 setgray 64.6 253 2.39 rscale mul FC 0.0 setgray 64.6 253 2.39 rscale mul OC 64.6 253 1.5 sub moveto 1.0 setgray 106 251 3.29 rscale mul FC 0.0 setgray 106 251 3.29 rscale mul OC 106 251 1.5 sub moveto 1.0 setgray 61.2 276 2.39 rscale mul FC 0.0 setgray 61.2 276 2.39 rscale mul OC 61.2 276 1.5 sub moveto 1.0 setgray 60 300 1.95 rscale mul FC 0.0 setgray 60 300 1.95 rscale mul OC 60 300 1.5 sub moveto 1.0 setgray 100 290 2.65 rscale mul FC 0.0 setgray 100 290 2.65 rscale mul OC 100 290 1.5 sub moveto 1.0 setgray 142 277 6.26 rscale mul FC 0.0 setgray 142 277 6.26 rscale mul OC 142 277 1.5 sub moveto 1.0 setgray 187 260 11 rscale mul FC 0.0 setgray 187 260 11 rscale mul OC 187 260 1.5 sub moveto 1.0 setgray 241 246 12.4 rscale mul FC 0.0 setgray 241 246 12.4 rscale mul OC 241 246 1.5 sub moveto 1.0 setgray 298 260 20 rscale mul FC 0.0 setgray 298 260 20 rscale mul OC 298 260 1.5 sub moveto 1.0 setgray 61.2 324 1.95 rscale mul FC 0.0 setgray 61.2 324 1.95 rscale mul OC 61.2 324 1.5 sub moveto 1.0 setgray 64.6 347 2.39 rscale mul FC 0.0 setgray 64.6 347 2.39 rscale mul OC 64.6 347 1.5 sub moveto 1.0 setgray 102 329 2.65 rscale mul FC 0.0 setgray 102 329 2.65 rscale mul OC 102 329 1.5 sub moveto 1.0 setgray 70.3 370 2.39 rscale mul FC 0.0 setgray 70.3 370 2.39 rscale mul OC 70.3 370 1.5 sub moveto 1.0 setgray 78.3 392 2.93 rscale mul FC 0.0 setgray 78.3 392 2.93 rscale mul OC 78.3 392 1.5 sub moveto 1.0 setgray 112 367 3.29 rscale mul FC 0.0 setgray 112 367 3.29 rscale mul OC 112 367 1.5 sub moveto 1.0 setgray 145 339 6.26 rscale mul FC 0.0 setgray 145 339 6.26 rscale mul OC 145 339 1.5 sub moveto 1.0 setgray 88.3 413 1.6 rscale mul FC 0.0 setgray 88.3 413 1.6 rscale mul OC 88.3 413 1.5 sub moveto 1.0 setgray 100 433 1.95 rscale mul FC 0.0 setgray 100 433 1.95 rscale mul OC 100 433 1.5 sub moveto 1.0 setgray 128 403 2.11 rscale mul FC 0.0 setgray 128 403 2.11 rscale mul OC 128 403 1.5 sub moveto 1.0 setgray 114 452 1.95 rscale mul FC 0.0 setgray 114 452 1.95 rscale mul OC 114 452 1.5 sub moveto 1.0 setgray 130 470 2.39 rscale mul FC 0.0 setgray 130 470 2.39 rscale mul OC 130 470 1.5 sub moveto 1.0 setgray 152 434 2.65 rscale mul FC 0.0 setgray 152 434 2.65 rscale mul OC 152 434 1.5 sub moveto 1.0 setgray 171 395 4.89 rscale mul FC 0.0 setgray 171 395 4.89 rscale mul OC 171 395 1.5 sub moveto 1.0 setgray 192 351 11 rscale mul FC 0.0 setgray 192 351 11 rscale mul OC 192 351 1.5 sub moveto 1.0 setgray 148 486 2.39 rscale mul FC 0.0 setgray 148 486 2.39 rscale mul OC 148 486 1.5 sub moveto 1.0 setgray 167 500 1.95 rscale mul FC 0.0 setgray 167 500 1.95 rscale mul OC 167 500 1.5 sub moveto 1.0 setgray 181 461 2.65 rscale mul FC 0.0 setgray 181 461 2.65 rscale mul OC 181 461 1.5 sub moveto 1.0 setgray 187 512 2.93 rscale mul FC 0.0 setgray 187 512 2.93 rscale mul OC 187 512 1.5 sub moveto 1.0 setgray 208 522 2.39 rscale mul FC 0.0 setgray 208 522 2.39 rscale mul OC 208 522 1.5 sub moveto 1.0 setgray 214 481 3.29 rscale mul FC 0.0 setgray 214 481 3.29 rscale mul OC 214 481 1.5 sub moveto 1.0 setgray 218 437 6.26 rscale mul FC 0.0 setgray 218 437 6.26 rscale mul OC 218 437 1.5 sub moveto 1.0 setgray 230 530 1.95 rscale mul FC 0.0 setgray 230 530 1.95 rscale mul OC 230 530 1.5 sub moveto 1.0 setgray 253 535 1.6 rscale mul FC 0.0 setgray 253 535 1.6 rscale mul OC 253 535 1.5 sub moveto 1.0 setgray 251 494 2.11 rscale mul FC 0.0 setgray 251 494 2.11 rscale mul OC 251 494 1.5 sub moveto 1.0 setgray 276 539 2.39 rscale mul FC 0.0 setgray 276 539 2.39 rscale mul OC 276 539 1.5 sub moveto 1.0 setgray 300 540 1.95 rscale mul FC 0.0 setgray 300 540 1.95 rscale mul OC 300 540 1.5 sub moveto 1.0 setgray 290 500 2.65 rscale mul FC 0.0 setgray 290 500 2.65 rscale mul OC 290 500 1.5 sub moveto 1.0 setgray 277 458 4.89 rscale mul FC 0.0 setgray 277 458 4.89 rscale mul OC 277 458 1.5 sub moveto 1.0 setgray 260 413 11 rscale mul FC 0.0 setgray 260 413 11 rscale mul OC 260 413 1.5 sub moveto 1.0 setgray 246 359 12.4 rscale mul FC 0.0 setgray 246 359 12.4 rscale mul OC 246 359 1.5 sub moveto 1.0 setgray 324 539 2.39 rscale mul FC 0.0 setgray 324 539 2.39 rscale mul OC 324 539 1.5 sub moveto 1.0 setgray 347 535 2.93 rscale mul FC 0.0 setgray 347 535 2.93 rscale mul OC 347 535 1.5 sub moveto 1.0 setgray 329 498 3.29 rscale mul FC 0.0 setgray 329 498 3.29 rscale mul OC 329 498 1.5 sub moveto 1.0 setgray 370 530 1.95 rscale mul FC 0.0 setgray 370 530 1.95 rscale mul OC 370 530 1.5 sub moveto 1.0 setgray 392 522 2.39 rscale mul FC 0.0 setgray 392 522 2.39 rscale mul OC 392 522 1.5 sub moveto 1.0 setgray 367 488 2.65 rscale mul FC 0.0 setgray 367 488 2.65 rscale mul OC 367 488 1.5 sub moveto 1.0 setgray 339 455 6.26 rscale mul FC 0.0 setgray 339 455 6.26 rscale mul OC 339 455 1.5 sub moveto 1.0 setgray 413 512 1.95 rscale mul FC 0.0 setgray 413 512 1.95 rscale mul OC 413 512 1.5 sub moveto 1.0 setgray 433 500 2.39 rscale mul FC 0.0 setgray 433 500 2.39 rscale mul OC 433 500 1.5 sub moveto 1.0 setgray 403 472 2.65 rscale mul FC 0.0 setgray 403 472 2.65 rscale mul OC 403 472 1.5 sub moveto 1.0 setgray 452 486 1.6 rscale mul FC 0.0 setgray 452 486 1.6 rscale mul OC 452 486 1.5 sub moveto 1.0 setgray 470 470 1.95 rscale mul FC 0.0 setgray 470 470 1.95 rscale mul OC 470 470 1.5 sub moveto 1.0 setgray 434 448 2.11 rscale mul FC 0.0 setgray 434 448 2.11 rscale mul OC 434 448 1.5 sub moveto 1.0 setgray 395 429 4.89 rscale mul FC 0.0 setgray 395 429 4.89 rscale mul OC 395 429 1.5 sub moveto 1.0 setgray 351 408 11 rscale mul FC 0.0 setgray 351 408 11 rscale mul OC 351 408 1.5 sub moveto 1.0 setgray 486 452 2.93 rscale mul FC 0.0 setgray 486 452 2.93 rscale mul OC 486 452 1.5 sub moveto 1.0 setgray 500 433 2.39 rscale mul FC 0.0 setgray 500 433 2.39 rscale mul OC 500 433 1.5 sub moveto 1.0 setgray 461 419 3.29 rscale mul FC 0.0 setgray 461 419 3.29 rscale mul OC 461 419 1.5 sub moveto 1.0 setgray 512 413 2.39 rscale mul FC 0.0 setgray 512 413 2.39 rscale mul OC 512 413 1.5 sub moveto 1.0 setgray 522 392 1.95 rscale mul FC 0.0 setgray 522 392 1.95 rscale mul OC 522 392 1.5 sub moveto 1.0 setgray 481 386 2.65 rscale mul FC 0.0 setgray 481 386 2.65 rscale mul OC 481 386 1.5 sub moveto 1.0 setgray 437 382 6.26 rscale mul FC 0.0 setgray 437 382 6.26 rscale mul OC 437 382 1.5 sub moveto 1.0 setgray 530 370 2.39 rscale mul FC 0.0 setgray 530 370 2.39 rscale mul OC 530 370 1.5 sub moveto 1.0 setgray 535 347 1.95 rscale mul FC 0.0 setgray 535 347 1.95 rscale mul OC 535 347 1.5 sub moveto 1.0 setgray 494 349 2.65 rscale mul FC 0.0 setgray 494 349 2.65 rscale mul OC 494 349 1.5 sub moveto 1.0 setgray 539 324 1.95 rscale mul FC 0.0 setgray 539 324 1.95 rscale mul OC 539 324 1.5 sub moveto 1.0 setgray 540 300 1.6 rscale mul FC 0.0 setgray 540 300 1.6 rscale mul OC 540 300 1.5 sub moveto 1.0 setgray 500 310 2.11 rscale mul FC 0.0 setgray 500 310 2.11 rscale mul OC 500 310 1.5 sub moveto 1.0 setgray 458 323 4.89 rscale mul FC 0.0 setgray 458 323 4.89 rscale mul OC 458 323 1.5 sub moveto 1.0 setgray 413 340 11 rscale mul FC 0.0 setgray 413 340 11 rscale mul OC 413 340 1.5 sub moveto 1.0 setgray 359 354 12.4 rscale mul FC 0.0 setgray 359 354 12.4 rscale mul OC 359 354 1.5 sub moveto 1.0 setgray 302 340 20 rscale mul FC 0.0 setgray 302 340 20 rscale mul OC 302 340 1.5 sub moveto 1.0 setgray 300 300 19.7 rscale mul FC 0.0 setgray 300 300 19.7 rscale mul OC 300 300 1.5 sub moveto grestore 60 60 480 480 rectstroke showpage mul OC 233 112 1.5 sub moveto 1.0 setgray 261 145 4.89 rscale mul FC 0.0 setgray 261 145 4.89 rscETree/doc/GRD7x7x7_forwops.eps010064400020550007177000000426640665246110100174100ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 50 50 550 550 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def /rscale 0.128 def /fontscale 6.000 def 60 60 480 480 rectclip newpath 539 276 498 271 ML 535 253 498 271 ML 498 271 455 261 ML 530 230 488 233 ML 522 208 488 233 ML 488 233 455 261 ML 455 261 408 249 ML 512 187 472 197 ML 500 167 472 197 ML 472 197 429 205 ML 486 148 448 166 ML 470 130 448 166 ML 448 166 429 205 ML 429 205 408 249 ML 408 249 354 241 ML 452 114 419 139 ML 433 100 419 139 ML 419 139 382 163 ML 413 88.3 386 119 ML 392 78.3 386 119 ML 386 119 382 163 ML 382 163 340 187 ML 370 70.3 349 106 ML 347 64.6 349 106 ML 349 106 323 142 ML 324 61.2 310 100 ML 300 60 310 100 ML 310 100 323 142 ML 323 142 340 187 ML 340 187 354 241 ML 354 241 298 260 ML 276 61.2 271 102 ML 253 64.6 271 102 ML 271 102 261 145 ML 230 70.3 233 112 ML 208 78.3 233 112 ML 233 112 261 145 ML 261 145 249 192 ML 187 88.3 197 128 ML 167 100 197 128 ML 197 128 205 171 ML 148 114 166 152 ML 130 130 166 152 ML 166 152 205 171 ML 205 171 249 192 ML 249 192 241 246 ML 114 148 139 181 ML 100 167 139 181 ML 139 181 163 218 ML 88.3 187 119 214 ML 78.3 208 119 214 ML 119 214 163 218 ML 163 218 187 260 ML 70.3 230 106 251 ML 64.6 253 106 251 ML 106 251 142 277 ML 61.2 276 100 290 ML 60 300 100 290 ML 100 290 142 277 ML 142 277 187 260 ML 187 260 241 246 ML 241 246 298 260 ML 298 260 300 300 ML 61.2 324 102 329 ML 64.6 347 102 329 ML 102 329 145 339 ML 70.3 370 112 367 ML 78.3 392 112 367 ML 112 367 145 339 ML 145 339 192 351 ML 88.3 413 128 403 ML 100 433 128 403 ML 128 403 171 395 ML 114 452 152 434 ML 130 470 152 434 ML 152 434 171 395 ML 171 395 192 351 ML 192 351 246 359 ML 148 486 181 461 ML 167 500 181 461 ML 181 461 218 437 ML 187 512 214 481 ML 208 522 214 481 ML 214 481 218 437 ML 218 437 260 413 ML 230 530 251 494 ML 253 535 251 494 ML 251 494 277 458 ML 276 539 290 500 ML 300 540 290 500 ML 290 500 277 458 ML 277 458 260 413 ML 260 413 246 359 ML 246 359 302 340 ML 324 539 329 498 ML 347 535 329 498 ML 329 498 339 455 ML 370 530 367 488 ML 392 522 367 488 ML 367 488 339 455 ML stroke newpath 339 455 351 408 ML 413 512 403 472 ML 433 500 403 472 ML 403 472 395 429 ML 452 486 434 448 ML 470 470 434 448 ML 434 448 395 429 ML 395 429 351 408 ML 351 408 359 354 ML 486 452 461 419 ML 500 433 461 419 ML 461 419 437 382 ML 512 413 481 386 ML 522 392 481 386 ML 481 386 437 382 ML 437 382 413 340 ML 530 370 494 349 ML 535 347 494 349 ML 494 349 458 323 ML 539 324 500 310 ML 540 300 500 310 ML 500 310 458 323 ML 458 323 413 340 ML 413 340 359 354 ML 359 354 302 340 ML 302 340 300 300 ML stroke gsave 1.0 setgray 539 276 4.51 rscale mul FC 0.0 setgray 539 276 4.51 rscale mul OC 539 276 1.5 sub moveto 1.0 setgray 535 253 6.77 rscale mul FC 0.0 setgray 535 253 6.77 rscale mul OC 535 253 1.5 sub moveto 1.0 setgray 498 271 7.9 rscale mul FC 0.0 setgray 498 271 7.9 rscale mul OC 498 271 1.5 sub moveto 1.0 setgray 530 230 6.77 rscale mul FC 0.0 setgray 530 230 6.77 rscale mul OC 530 230 1.5 sub moveto 1.0 setgray 522 208 10.2 rscale mul FC 0.0 setgray 522 208 10.2 rscale mul OC 522 208 1.5 sub moveto 1.0 setgray 488 233 12.4 rscale mul FC 0.0 setgray 488 233 12.4 rscale mul OC 488 233 1.5 sub moveto 1.0 setgray 455 261 24.4 rscale mul FC 0.0 setgray 455 261 24.4 rscale mul OC 455 261 1.5 sub moveto 1.0 setgray 512 187 6.77 rscale mul FC 0.0 setgray 512 187 6.77 rscale mul OC 512 187 1.5 sub moveto 1.0 setgray 500 167 10.2 rscale mul FC 0.0 setgray 500 167 10.2 rscale mul OC 500 167 1.5 sub moveto 1.0 setgray 472 197 12.4 rscale mul FC 0.0 setgray 472 197 12.4 rscale mul OC 472 197 1.5 sub moveto 1.0 setgray 486 148 10.2 rscale mul FC 0.0 setgray 486 148 10.2 rscale mul OC 486 148 1.5 sub moveto 1.0 setgray 470 130 15.2 rscale mul FC 0.0 setgray 470 130 15.2 rscale mul OC 470 130 1.5 sub moveto 1.0 setgray 448 166 19.2 rscale mul FC 0.0 setgray 448 166 19.2 rscale mul OC 448 166 1.5 sub moveto 1.0 setgray 429 205 40.1 rscale mul FC 0.0 setgray 429 205 40.1 rscale mul OC 429 205 1.5 sub moveto 1.0 setgray 408 249 71.2 rscale mul FC 0.0 setgray 408 249 71.2 rscale mul OC 408 249 1.5 sub moveto 1.0 setgray 452 114 6.77 rscale mul FC 0.0 setgray 452 114 6.77 rscale mul OC 452 114 1.5 sub moveto 1.0 setgray 433 100 4.51 rscale mul FC 0.0 setgray 433 100 4.51 rscale mul OC 433 100 1.5 sub moveto 1.0 setgray 419 139 7.9 rscale mul FC 0.0 setgray 419 139 7.9 rscale mul OC 419 139 1.5 sub moveto 1.0 setgray 413 88.3 10.2 rscale mul FC 0.0 setgray 413 88.3 10.2 rscale mul OC 413 88.3 1.5 sub moveto 1.0 setgray 392 78.3 6.77 rscale mul FC 0.0 setgray 392 78.3 6.77 rscale mul OC 392 78.3 1.5 sub moveto 1.0 setgray 386 119 12.4 rscale mul FC 0.0 setgray 386 119 12.4 rscale mul OC 386 119 1.5 sub moveto 1.0 setgray 382 163 24.4 rscale mul FC 0.0 setgray 382 163 24.4 rscale mul OC 382 163 1.5 sub moveto 1.0 setgray 370 70.3 10.2 rscale mul FC 0.0 setgray 370 70.3 10.2 rscale mul OC 370 70.3 1.5 sub moveto 1.0 setgray 347 64.6 6.77 rscale mul FC 0.0 setgray 347 64.6 6.77 rscale mul OC 347 64.6 1.5 sub moveto 1.0 setgray 349 106 12.4 rscale mul FC 0.0 setgray 349 106 12.4 rscale mul OC 349 106 1.5 sub moveto 1.0 setgray 324 61.2 15.2 rscale mul FC 0.0 setgray 324 61.2 15.2 rscale mul OC 324 61.2 1.5 sub moveto 1.0 setgray 300 60 10.2 rscale mul FC 0.0 setgray 300 60 10.2 rscale mul OC 300 60 1.5 sub moveto 1.0 setgray 310 100 19.2 rscale mul FC 0.0 setgray 310 100 19.2 rscale mul OC 310 100 1.5 sub moveto 1.0 setgray 323 142 40.1 rscale mul FC 0.0 setgray 323 142 40.1 rscale mul OC 323 142 1.5 sub moveto 1.0 setgray 340 187 71.2 rscale mul FC 0.0 setgray 340 187 71.2 rscale mul OC 340 187 1.5 sub moveto 1.0 setgray 354 241 91.5 rscale mul FC 0.0 setgray 354 241 91.5 rscale mul OC 354 241 1.5 sub moveto 1.0 setgray 276 61.2 6.77 rscale mul FC 0.0 setgray 276 61.2 6.77 rscale mul OC 276 61.2 1.5 sub moveto 1.0 setgray 253 64.6 10.2 rscale mul FC 0.0 setgray 253 64.6 10.2 rscale mul OC 253 64.6 1.5 sub moveto 1.0 setgray 271 102 12.4 rscale mul FC 0.0 setgray 271 102 12.4 rscale mul OC 271 102 1.5 sub moveto 1.0 setgray 230 70.3 4.51 rscale mul FC 0.0 setgray 230 70.3 4.51 rscale mul OC 230 70.3 1.5 sub moveto 1.0 setgray 208 78.3 6.77 rscale mul FC 0.0 setgray 208 78.3 6.77 rscale mul OC 208 78.3 1.5 sub moveto 1.0 setgray 233 112 7.9 rscale mul FC 0.0 setgray 233 112 7.9 rscale mul OC 233 112 1.5 sub moveto 1.0 setgray 261 145 24.4 rscale mul FC 0.0 setgray 261 145 24.4 rscale mul OC 261 145 1.5 sub moveto 1.0 setgray 187 88.3 10.2 rscale mul FC 0.0 setgray 187 88.3 10.2 rscale mul OC 187 88.3 1.5 sub moveto 1.0 setgray 167 100 15.2 rscale mul FC 0.0 setgray 167 100 15.2 rscale mul OC 167 100 1.5 sub moveto 1.0 setgray 197 128 19.2 rscale mul FC 0.0 setgray 197 128 19.2 rscale mul OC 197 128 1.5 sub moveto 1.0 setgray 148 114 6.77 rscale mul FC 0.0 setgray 148 114 6.77 rscale mul OC 148 114 1.5 sub moveto 1.0 setgray 130 130 10.2 rscale mul FC 0.0 setgray 130 130 10.2 rscale mul OC 130 130 1.5 sub moveto 1.0 setgray 166 152 12.4 rscale mul FC 0.0 setgray 166 152 12.4 rscale mul OC 166 152 1.5 sub moveto 1.0 setgray 205 171 40.1 rscale mul FC 0.0 setgray 205 171 40.1 rscale mul OC 205 171 1.5 sub moveto 1.0 setgray 249 192 71.2 rscale mul FC 0.0 setgray 249 192 71.2 rscale mul OC 249 192 1.5 sub moveto 1.0 setgray 114 148 10.2 rscale mul FC 0.0 setgray 114 148 10.2 rscale mul OC 114 148 1.5 sub moveto 1.0 setgray 100 167 6.77 rscale mul FC 0.0 setgray 100 167 6.77 rscale mul OC 100 167 1.5 sub moveto 1.0 setgray 139 181 12.4 rscale mul FC 0.0 setgray 139 181 12.4 rscale mul OC 139 181 1.5 sub moveto 1.0 setgray 88.3 187 6.77 rscale mul FC 0.0 setgray 88.3 187 6.77 rscale mul OC 88.3 187 1.5 sub moveto 1.0 setgray 78.3 208 4.51 rscale mul FC 0.0 setgray 78.3 208 4.51 rscale mul OC 78.3 208 1.5 sub moveto 1.0 setgray 119 214 7.9 rscale mul FC 0.0 setgray 119 214 7.9 rscale mul OC 119 214 1.5 sub moveto 1.0 setgray 163 218 24.4 rscale mul FC 0.0 setgray 163 218 24.4 rscale mul OC 163 218 1.5 sub moveto 1.0 setgray 70.3 230 15.2 rscale mul FC 0.0 setgray 70.3 230 15.2 rscale mul OC 70.3 230 1.5 sub moveto 1.0 setgray 64.6 253 10.2 rscale mul FC 0.0 setgray 64.6 253 10.2 rscale mul OC 64.6 253 1.5 sub moveto 1.0 setgray 106 251 19.2 rscale mul FC 0.0 setgray 106 251 19.2 rscale mul OC 106 251 1.5 sub moveto 1.0 setgray 61.2 276 10.2 rscale mul FC 0.0 setgray 61.2 276 10.2 rscale mul OC 61.2 276 1.5 sub moveto 1.0 setgray 60 300 6.77 rscale mul FC 0.0 setgray 60 300 6.77 rscale mul OC 60 300 1.5 sub moveto 1.0 setgray 100 290 12.4 rscale mul FC 0.0 setgray 100 290 12.4 rscale mul OC 100 290 1.5 sub moveto 1.0 setgray 142 277 40.1 rscale mul FC 0.0 setgray 142 277 40.1 rscale mul OC 142 277 1.5 sub moveto 1.0 setgray 187 260 71.2 rscale mul FC 0.0 setgray 187 260 71.2 rscale mul OC 187 260 1.5 sub moveto 1.0 setgray 241 246 91.5 rscale mul FC 0.0 setgray 241 246 91.5 rscale mul OC 241 246 1.5 sub moveto 1.0 setgray 298 260 156 rscale mul FC 0.0 setgray 298 260 156 rscale mul OC 298 260 1.5 sub moveto 1.0 setgray 61.2 324 6.77 rscale mul FC 0.0 setgray 61.2 324 6.77 rscale mul OC 61.2 324 1.5 sub moveto 1.0 setgray 64.6 347 10.2 rscale mul FC 0.0 setgray 64.6 347 10.2 rscale mul OC 64.6 347 1.5 sub moveto 1.0 setgray 102 329 12.4 rscale mul FC 0.0 setgray 102 329 12.4 rscale mul OC 102 329 1.5 sub moveto 1.0 setgray 70.3 370 10.2 rscale mul FC 0.0 setgray 70.3 370 10.2 rscale mul OC 70.3 370 1.5 sub moveto 1.0 setgray 78.3 392 15.2 rscale mul FC 0.0 setgray 78.3 392 15.2 rscale mul OC 78.3 392 1.5 sub moveto 1.0 setgray 112 367 19.2 rscale mul FC 0.0 setgray 112 367 19.2 rscale mul OC 112 367 1.5 sub moveto 1.0 setgray 145 339 40.1 rscale mul FC 0.0 setgray 145 339 40.1 rscale mul OC 145 339 1.5 sub moveto 1.0 setgray 88.3 413 4.51 rscale mul FC 0.0 setgray 88.3 413 4.51 rscale mul OC 88.3 413 1.5 sub moveto 1.0 setgray 100 433 6.77 rscale mul FC 0.0 setgray 100 433 6.77 rscale mul OC 100 433 1.5 sub moveto 1.0 setgray 128 403 7.9 rscale mul FC 0.0 setgray 128 403 7.9 rscale mul OC 128 403 1.5 sub moveto 1.0 setgray 114 452 6.77 rscale mul FC 0.0 setgray 114 452 6.77 rscale mul OC 114 452 1.5 sub moveto 1.0 setgray 130 470 10.2 rscale mul FC 0.0 setgray 130 470 10.2 rscale mul OC 130 470 1.5 sub moveto 1.0 setgray 152 434 12.4 rscale mul FC 0.0 setgray 152 434 12.4 rscale mul OC 152 434 1.5 sub moveto 1.0 setgray 171 395 24.4 rscale mul FC 0.0 setgray 171 395 24.4 rscale mul OC 171 395 1.5 sub moveto 1.0 setgray 192 351 71.2 rscale mul FC 0.0 setgray 192 351 71.2 rscale mul OC 192 351 1.5 sub moveto 1.0 setgray 148 486 10.2 rscale mul FC 0.0 setgray 148 486 10.2 rscale mul OC 148 486 1.5 sub moveto 1.0 setgray 167 500 6.77 rscale mul FC 0.0 setgray 167 500 6.77 rscale mul OC 167 500 1.5 sub moveto 1.0 setgray 181 461 12.4 rscale mul FC 0.0 setgray 181 461 12.4 rscale mul OC 181 461 1.5 sub moveto 1.0 setgray 187 512 15.2 rscale mul FC 0.0 setgray 187 512 15.2 rscale mul OC 187 512 1.5 sub moveto 1.0 setgray 208 522 10.2 rscale mul FC 0.0 setgray 208 522 10.2 rscale mul OC 208 522 1.5 sub moveto 1.0 setgray 214 481 19.2 rscale mul FC 0.0 setgray 214 481 19.2 rscale mul OC 214 481 1.5 sub moveto 1.0 setgray 218 437 40.1 rscale mul FC 0.0 setgray 218 437 40.1 rscale mul OC 218 437 1.5 sub moveto 1.0 setgray 230 530 6.77 rscale mul FC 0.0 setgray 230 530 6.77 rscale mul OC 230 530 1.5 sub moveto 1.0 setgray 253 535 4.51 rscale mul FC 0.0 setgray 253 535 4.51 rscale mul OC 253 535 1.5 sub moveto 1.0 setgray 251 494 7.9 rscale mul FC 0.0 setgray 251 494 7.9 rscale mul OC 251 494 1.5 sub moveto 1.0 setgray 276 539 10.2 rscale mul FC 0.0 setgray 276 539 10.2 rscale mul OC 276 539 1.5 sub moveto 1.0 setgray 300 540 6.77 rscale mul FC 0.0 setgray 300 540 6.77 rscale mul OC 300 540 1.5 sub moveto 1.0 setgray 290 500 12.4 rscale mul FC 0.0 setgray 290 500 12.4 rscale mul OC 290 500 1.5 sub moveto 1.0 setgray 277 458 24.4 rscale mul FC 0.0 setgray 277 458 24.4 rscale mul OC 277 458 1.5 sub moveto 1.0 setgray 260 413 71.2 rscale mul FC 0.0 setgray 260 413 71.2 rscale mul OC 260 413 1.5 sub moveto 1.0 setgray 246 359 91.5 rscale mul FC 0.0 setgray 246 359 91.5 rscale mul OC 246 359 1.5 sub moveto 1.0 setgray 324 539 10.2 rscale mul FC 0.0 setgray 324 539 10.2 rscale mul OC 324 539 1.5 sub moveto 1.0 setgray 347 535 15.2 rscale mul FC 0.0 setgray 347 535 15.2 rscale mul OC 347 535 1.5 sub moveto 1.0 setgray 329 498 19.2 rscale mul FC 0.0 setgray 329 498 19.2 rscale mul OC 329 498 1.5 sub moveto 1.0 setgray 370 530 6.77 rscale mul FC 0.0 setgray 370 530 6.77 rscale mul OC 370 530 1.5 sub moveto 1.0 setgray 392 522 10.2 rscale mul FC 0.0 setgray 392 522 10.2 rscale mul OC 392 522 1.5 sub moveto 1.0 setgray 367 488 12.4 rscale mul FC 0.0 setgray 367 488 12.4 rscale mul OC 367 488 1.5 sub moveto 1.0 setgray 339 455 40.1 rscale mul FC 0.0 setgray 339 455 40.1 rscale mul OC 339 455 1.5 sub moveto 1.0 setgray 413 512 6.77 rscale mul FC 0.0 setgray 413 512 6.77 rscale mul OC 413 512 1.5 sub moveto 1.0 setgray 433 500 10.2 rscale mul FC 0.0 setgray 433 500 10.2 rscale mul OC 433 500 1.5 sub moveto 1.0 setgray 403 472 12.4 rscale mul FC 0.0 setgray 403 472 12.4 rscale mul OC 403 472 1.5 sub moveto 1.0 setgray 452 486 4.51 rscale mul FC 0.0 setgray 452 486 4.51 rscale mul OC 452 486 1.5 sub moveto 1.0 setgray 470 470 6.77 rscale mul FC 0.0 setgray 470 470 6.77 rscale mul OC 470 470 1.5 sub moveto 1.0 setgray 434 448 7.9 rscale mul FC 0.0 setgray 434 448 7.9 rscale mul OC 434 448 1.5 sub moveto 1.0 setgray 395 429 24.4 rscale mul FC 0.0 setgray 395 429 24.4 rscale mul OC 395 429 1.5 sub moveto 1.0 setgray 351 408 71.2 rscale mul FC 0.0 setgray 351 408 71.2 rscale mul OC 351 408 1.5 sub moveto 1.0 setgray 486 452 15.2 rscale mul FC 0.0 setgray 486 452 15.2 rscale mul OC 486 452 1.5 sub moveto 1.0 setgray 500 433 10.2 rscale mul FC 0.0 setgray 500 433 10.2 rscale mul OC 500 433 1.5 sub moveto 1.0 setgray 461 419 19.2 rscale mul FC 0.0 setgray 461 419 19.2 rscale mul OC 461 419 1.5 sub moveto 1.0 setgray 512 413 10.2 rscale mul FC 0.0 setgray 512 413 10.2 rscale mul OC 512 413 1.5 sub moveto 1.0 setgray 522 392 6.77 rscale mul FC 0.0 setgray 522 392 6.77 rscale mul OC 522 392 1.5 sub moveto 1.0 setgray 481 386 12.4 rscale mul FC 0.0 setgray 481 386 12.4 rscale mul OC 481 386 1.5 sub moveto 1.0 setgray 437 382 40.1 rscale mul FC 0.0 setgray 437 382 40.1 rscale mul OC 437 382 1.5 sub moveto 1.0 setgray 530 370 10.2 rscale mul FC 0.0 setgray 530 370 10.2 rscale mul OC 530 370 1.5 sub moveto 1.0 setgray 535 347 6.77 rscale mul FC 0.0 setgray 535 347 6.77 rscale mul OC 535 347 1.5 sub moveto 1.0 setgray 494 349 12.4 rscale mul FC 0.0 setgray 494 349 12.4 rscale mul OC 494 349 1.5 sub moveto 1.0 setgray 539 324 6.77 rscale mul FC 0.0 setgray 539 324 6.77 rscale mul OC 539 324 1.5 sub moveto 1.0 setgray 540 300 4.51 rscale mul FC 0.0 setgray 540 300 4.51 rscale mul OC 540 300 1.5 sub moveto 1.0 setgray 500 310 7.9 rscale mul FC 0.0 setgray 500 310 7.9 rscale mul OC 500 310 1.5 sub moveto 1.0 setgray 458 323 24.4 rscale mul FC 0.0 setgray 458 323 24.4 rscale mul OC 458 323 1.5 sub moveto 1.0 setgray 413 340 71.2 rscale mul FC 0.0 setgray 413 340 71.2 rscale mul OC 413 340 1.5 sub moveto 1.0 setgray 359 354 91.5 rscale mul FC 0.0 setgray 359 354 91.5 rscale mul OC 359 354 1.5 sub moveto 1.0 setgray 302 340 156 rscale mul FC 0.0 setgray 302 340 156 rscale mul OC 302 340 1.5 sub moveto 1.0 setgray 300 300 113 rscale mul FC 0.0 setgray 300 300 113 rscale mul OC 300 300 1.5 sub moveto grestore 60 60 480 480 rectstroke showpage moveto 1.0 setgray 261 145 24.4 rscale mul FC 0.0 setgray 261 145 ETree/doc/GRD7x7x7_backops.eps010064400020550007177000000426640665246113300173400ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 50 50 550 550 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def /rscale 0.079 def /fontscale 6.000 def 60 60 480 480 rectclip newpath 539 276 498 271 ML 535 253 498 271 ML 498 271 455 261 ML 530 230 488 233 ML 522 208 488 233 ML 488 233 455 261 ML 455 261 408 249 ML 512 187 472 197 ML 500 167 472 197 ML 472 197 429 205 ML 486 148 448 166 ML 470 130 448 166 ML 448 166 429 205 ML 429 205 408 249 ML 408 249 354 241 ML 452 114 419 139 ML 433 100 419 139 ML 419 139 382 163 ML 413 88.3 386 119 ML 392 78.3 386 119 ML 386 119 382 163 ML 382 163 340 187 ML 370 70.3 349 106 ML 347 64.6 349 106 ML 349 106 323 142 ML 324 61.2 310 100 ML 300 60 310 100 ML 310 100 323 142 ML 323 142 340 187 ML 340 187 354 241 ML 354 241 298 260 ML 276 61.2 271 102 ML 253 64.6 271 102 ML 271 102 261 145 ML 230 70.3 233 112 ML 208 78.3 233 112 ML 233 112 261 145 ML 261 145 249 192 ML 187 88.3 197 128 ML 167 100 197 128 ML 197 128 205 171 ML 148 114 166 152 ML 130 130 166 152 ML 166 152 205 171 ML 205 171 249 192 ML 249 192 241 246 ML 114 148 139 181 ML 100 167 139 181 ML 139 181 163 218 ML 88.3 187 119 214 ML 78.3 208 119 214 ML 119 214 163 218 ML 163 218 187 260 ML 70.3 230 106 251 ML 64.6 253 106 251 ML 106 251 142 277 ML 61.2 276 100 290 ML 60 300 100 290 ML 100 290 142 277 ML 142 277 187 260 ML 187 260 241 246 ML 241 246 298 260 ML 298 260 300 300 ML 61.2 324 102 329 ML 64.6 347 102 329 ML 102 329 145 339 ML 70.3 370 112 367 ML 78.3 392 112 367 ML 112 367 145 339 ML 145 339 192 351 ML 88.3 413 128 403 ML 100 433 128 403 ML 128 403 171 395 ML 114 452 152 434 ML 130 470 152 434 ML 152 434 171 395 ML 171 395 192 351 ML 192 351 246 359 ML 148 486 181 461 ML 167 500 181 461 ML 181 461 218 437 ML 187 512 214 481 ML 208 522 214 481 ML 214 481 218 437 ML 218 437 260 413 ML 230 530 251 494 ML 253 535 251 494 ML 251 494 277 458 ML 276 539 290 500 ML 300 540 290 500 ML 290 500 277 458 ML 277 458 260 413 ML 260 413 246 359 ML 246 359 302 340 ML 324 539 329 498 ML 347 535 329 498 ML 329 498 339 455 ML 370 530 367 488 ML 392 522 367 488 ML 367 488 339 455 ML stroke newpath 339 455 351 408 ML 413 512 403 472 ML 433 500 403 472 ML 403 472 395 429 ML 452 486 434 448 ML 470 470 434 448 ML 434 448 395 429 ML 395 429 351 408 ML 351 408 359 354 ML 486 452 461 419 ML 500 433 461 419 ML 461 419 437 382 ML 512 413 481 386 ML 522 392 481 386 ML 481 386 437 382 ML 437 382 413 340 ML 530 370 494 349 ML 535 347 494 349 ML 494 349 458 323 ML 539 324 500 310 ML 540 300 500 310 ML 500 310 458 323 ML 458 323 413 340 ML 413 340 359 354 ML 359 354 302 340 ML 302 340 300 300 ML stroke gsave 1.0 setgray 539 276 1.6 rscale mul FC 0.0 setgray 539 276 1.6 rscale mul OC 539 276 1.5 sub moveto 1.0 setgray 535 253 1.95 rscale mul FC 0.0 setgray 535 253 1.95 rscale mul OC 535 253 1.5 sub moveto 1.0 setgray 498 271 3.99 rscale mul FC 0.0 setgray 498 271 3.99 rscale mul OC 498 271 1.5 sub moveto 1.0 setgray 530 230 1.95 rscale mul FC 0.0 setgray 530 230 1.95 rscale mul OC 530 230 1.5 sub moveto 1.0 setgray 522 208 2.39 rscale mul FC 0.0 setgray 522 208 2.39 rscale mul OC 522 208 1.5 sub moveto 1.0 setgray 488 233 4.98 rscale mul FC 0.0 setgray 488 233 4.98 rscale mul OC 488 233 1.5 sub moveto 1.0 setgray 455 261 13.5 rscale mul FC 0.0 setgray 455 261 13.5 rscale mul OC 455 261 1.5 sub moveto 1.0 setgray 512 187 1.95 rscale mul FC 0.0 setgray 512 187 1.95 rscale mul OC 512 187 1.5 sub moveto 1.0 setgray 500 167 2.39 rscale mul FC 0.0 setgray 500 167 2.39 rscale mul OC 500 167 1.5 sub moveto 1.0 setgray 472 197 4.98 rscale mul FC 0.0 setgray 472 197 4.98 rscale mul OC 472 197 1.5 sub moveto 1.0 setgray 486 148 2.39 rscale mul FC 0.0 setgray 486 148 2.39 rscale mul OC 486 148 1.5 sub moveto 1.0 setgray 470 130 2.93 rscale mul FC 0.0 setgray 470 130 2.93 rscale mul OC 470 130 1.5 sub moveto 1.0 setgray 448 166 6.18 rscale mul FC 0.0 setgray 448 166 6.18 rscale mul OC 448 166 1.5 sub moveto 1.0 setgray 429 205 17.3 rscale mul FC 0.0 setgray 429 205 17.3 rscale mul OC 429 205 1.5 sub moveto 1.0 setgray 408 249 49.3 rscale mul FC 0.0 setgray 408 249 49.3 rscale mul OC 408 249 1.5 sub moveto 1.0 setgray 452 114 1.95 rscale mul FC 0.0 setgray 452 114 1.95 rscale mul OC 452 114 1.5 sub moveto 1.0 setgray 433 100 1.6 rscale mul FC 0.0 setgray 433 100 1.6 rscale mul OC 433 100 1.5 sub moveto 1.0 setgray 419 139 3.99 rscale mul FC 0.0 setgray 419 139 3.99 rscale mul OC 419 139 1.5 sub moveto 1.0 setgray 413 88.3 2.39 rscale mul FC 0.0 setgray 413 88.3 2.39 rscale mul OC 413 88.3 1.5 sub moveto 1.0 setgray 392 78.3 1.95 rscale mul FC 0.0 setgray 392 78.3 1.95 rscale mul OC 392 78.3 1.5 sub moveto 1.0 setgray 386 119 4.98 rscale mul FC 0.0 setgray 386 119 4.98 rscale mul OC 386 119 1.5 sub moveto 1.0 setgray 382 163 13.5 rscale mul FC 0.0 setgray 382 163 13.5 rscale mul OC 382 163 1.5 sub moveto 1.0 setgray 370 70.3 2.39 rscale mul FC 0.0 setgray 370 70.3 2.39 rscale mul OC 370 70.3 1.5 sub moveto 1.0 setgray 347 64.6 1.95 rscale mul FC 0.0 setgray 347 64.6 1.95 rscale mul OC 347 64.6 1.5 sub moveto 1.0 setgray 349 106 4.98 rscale mul FC 0.0 setgray 349 106 4.98 rscale mul OC 349 106 1.5 sub moveto 1.0 setgray 324 61.2 2.93 rscale mul FC 0.0 setgray 324 61.2 2.93 rscale mul OC 324 61.2 1.5 sub moveto 1.0 setgray 300 60 2.39 rscale mul FC 0.0 setgray 300 60 2.39 rscale mul OC 300 60 1.5 sub moveto 1.0 setgray 310 100 6.18 rscale mul FC 0.0 setgray 310 100 6.18 rscale mul OC 310 100 1.5 sub moveto 1.0 setgray 323 142 17.3 rscale mul FC 0.0 setgray 323 142 17.3 rscale mul OC 323 142 1.5 sub moveto 1.0 setgray 340 187 49.3 rscale mul FC 0.0 setgray 340 187 49.3 rscale mul OC 340 187 1.5 sub moveto 1.0 setgray 354 241 77.9 rscale mul FC 0.0 setgray 354 241 77.9 rscale mul OC 354 241 1.5 sub moveto 1.0 setgray 276 61.2 1.95 rscale mul FC 0.0 setgray 276 61.2 1.95 rscale mul OC 276 61.2 1.5 sub moveto 1.0 setgray 253 64.6 2.39 rscale mul FC 0.0 setgray 253 64.6 2.39 rscale mul OC 253 64.6 1.5 sub moveto 1.0 setgray 271 102 4.98 rscale mul FC 0.0 setgray 271 102 4.98 rscale mul OC 271 102 1.5 sub moveto 1.0 setgray 230 70.3 1.6 rscale mul FC 0.0 setgray 230 70.3 1.6 rscale mul OC 230 70.3 1.5 sub moveto 1.0 setgray 208 78.3 1.95 rscale mul FC 0.0 setgray 208 78.3 1.95 rscale mul OC 208 78.3 1.5 sub moveto 1.0 setgray 233 112 3.99 rscale mul FC 0.0 setgray 233 112 3.99 rscale mul OC 233 112 1.5 sub moveto 1.0 setgray 261 145 13.5 rscale mul FC 0.0 setgray 261 145 13.5 rscale mul OC 261 145 1.5 sub moveto 1.0 setgray 187 88.3 2.39 rscale mul FC 0.0 setgray 187 88.3 2.39 rscale mul OC 187 88.3 1.5 sub moveto 1.0 setgray 167 100 2.93 rscale mul FC 0.0 setgray 167 100 2.93 rscale mul OC 167 100 1.5 sub moveto 1.0 setgray 197 128 6.18 rscale mul FC 0.0 setgray 197 128 6.18 rscale mul OC 197 128 1.5 sub moveto 1.0 setgray 148 114 1.95 rscale mul FC 0.0 setgray 148 114 1.95 rscale mul OC 148 114 1.5 sub moveto 1.0 setgray 130 130 2.39 rscale mul FC 0.0 setgray 130 130 2.39 rscale mul OC 130 130 1.5 sub moveto 1.0 setgray 166 152 4.98 rscale mul FC 0.0 setgray 166 152 4.98 rscale mul OC 166 152 1.5 sub moveto 1.0 setgray 205 171 17.3 rscale mul FC 0.0 setgray 205 171 17.3 rscale mul OC 205 171 1.5 sub moveto 1.0 setgray 249 192 49.3 rscale mul FC 0.0 setgray 249 192 49.3 rscale mul OC 249 192 1.5 sub moveto 1.0 setgray 114 148 2.39 rscale mul FC 0.0 setgray 114 148 2.39 rscale mul OC 114 148 1.5 sub moveto 1.0 setgray 100 167 1.95 rscale mul FC 0.0 setgray 100 167 1.95 rscale mul OC 100 167 1.5 sub moveto 1.0 setgray 139 181 4.98 rscale mul FC 0.0 setgray 139 181 4.98 rscale mul OC 139 181 1.5 sub moveto 1.0 setgray 88.3 187 1.95 rscale mul FC 0.0 setgray 88.3 187 1.95 rscale mul OC 88.3 187 1.5 sub moveto 1.0 setgray 78.3 208 1.6 rscale mul FC 0.0 setgray 78.3 208 1.6 rscale mul OC 78.3 208 1.5 sub moveto 1.0 setgray 119 214 3.99 rscale mul FC 0.0 setgray 119 214 3.99 rscale mul OC 119 214 1.5 sub moveto 1.0 setgray 163 218 13.5 rscale mul FC 0.0 setgray 163 218 13.5 rscale mul OC 163 218 1.5 sub moveto 1.0 setgray 70.3 230 2.93 rscale mul FC 0.0 setgray 70.3 230 2.93 rscale mul OC 70.3 230 1.5 sub moveto 1.0 setgray 64.6 253 2.39 rscale mul FC 0.0 setgray 64.6 253 2.39 rscale mul OC 64.6 253 1.5 sub moveto 1.0 setgray 106 251 6.18 rscale mul FC 0.0 setgray 106 251 6.18 rscale mul OC 106 251 1.5 sub moveto 1.0 setgray 61.2 276 2.39 rscale mul FC 0.0 setgray 61.2 276 2.39 rscale mul OC 61.2 276 1.5 sub moveto 1.0 setgray 60 300 1.95 rscale mul FC 0.0 setgray 60 300 1.95 rscale mul OC 60 300 1.5 sub moveto 1.0 setgray 100 290 4.98 rscale mul FC 0.0 setgray 100 290 4.98 rscale mul OC 100 290 1.5 sub moveto 1.0 setgray 142 277 17.3 rscale mul FC 0.0 setgray 142 277 17.3 rscale mul OC 142 277 1.5 sub moveto 1.0 setgray 187 260 49.3 rscale mul FC 0.0 setgray 187 260 49.3 rscale mul OC 187 260 1.5 sub moveto 1.0 setgray 241 246 77.9 rscale mul FC 0.0 setgray 241 246 77.9 rscale mul OC 241 246 1.5 sub moveto 1.0 setgray 298 260 161 rscale mul FC 0.0 setgray 298 260 161 rscale mul OC 298 260 1.5 sub moveto 1.0 setgray 61.2 324 1.95 rscale mul FC 0.0 setgray 61.2 324 1.95 rscale mul OC 61.2 324 1.5 sub moveto 1.0 setgray 64.6 347 2.39 rscale mul FC 0.0 setgray 64.6 347 2.39 rscale mul OC 64.6 347 1.5 sub moveto 1.0 setgray 102 329 4.98 rscale mul FC 0.0 setgray 102 329 4.98 rscale mul OC 102 329 1.5 sub moveto 1.0 setgray 70.3 370 2.39 rscale mul FC 0.0 setgray 70.3 370 2.39 rscale mul OC 70.3 370 1.5 sub moveto 1.0 setgray 78.3 392 2.93 rscale mul FC 0.0 setgray 78.3 392 2.93 rscale mul OC 78.3 392 1.5 sub moveto 1.0 setgray 112 367 6.18 rscale mul FC 0.0 setgray 112 367 6.18 rscale mul OC 112 367 1.5 sub moveto 1.0 setgray 145 339 17.3 rscale mul FC 0.0 setgray 145 339 17.3 rscale mul OC 145 339 1.5 sub moveto 1.0 setgray 88.3 413 1.6 rscale mul FC 0.0 setgray 88.3 413 1.6 rscale mul OC 88.3 413 1.5 sub moveto 1.0 setgray 100 433 1.95 rscale mul FC 0.0 setgray 100 433 1.95 rscale mul OC 100 433 1.5 sub moveto 1.0 setgray 128 403 3.99 rscale mul FC 0.0 setgray 128 403 3.99 rscale mul OC 128 403 1.5 sub moveto 1.0 setgray 114 452 1.95 rscale mul FC 0.0 setgray 114 452 1.95 rscale mul OC 114 452 1.5 sub moveto 1.0 setgray 130 470 2.39 rscale mul FC 0.0 setgray 130 470 2.39 rscale mul OC 130 470 1.5 sub moveto 1.0 setgray 152 434 4.98 rscale mul FC 0.0 setgray 152 434 4.98 rscale mul OC 152 434 1.5 sub moveto 1.0 setgray 171 395 13.5 rscale mul FC 0.0 setgray 171 395 13.5 rscale mul OC 171 395 1.5 sub moveto 1.0 setgray 192 351 49.3 rscale mul FC 0.0 setgray 192 351 49.3 rscale mul OC 192 351 1.5 sub moveto 1.0 setgray 148 486 2.39 rscale mul FC 0.0 setgray 148 486 2.39 rscale mul OC 148 486 1.5 sub moveto 1.0 setgray 167 500 1.95 rscale mul FC 0.0 setgray 167 500 1.95 rscale mul OC 167 500 1.5 sub moveto 1.0 setgray 181 461 4.98 rscale mul FC 0.0 setgray 181 461 4.98 rscale mul OC 181 461 1.5 sub moveto 1.0 setgray 187 512 2.93 rscale mul FC 0.0 setgray 187 512 2.93 rscale mul OC 187 512 1.5 sub moveto 1.0 setgray 208 522 2.39 rscale mul FC 0.0 setgray 208 522 2.39 rscale mul OC 208 522 1.5 sub moveto 1.0 setgray 214 481 6.18 rscale mul FC 0.0 setgray 214 481 6.18 rscale mul OC 214 481 1.5 sub moveto 1.0 setgray 218 437 17.3 rscale mul FC 0.0 setgray 218 437 17.3 rscale mul OC 218 437 1.5 sub moveto 1.0 setgray 230 530 1.95 rscale mul FC 0.0 setgray 230 530 1.95 rscale mul OC 230 530 1.5 sub moveto 1.0 setgray 253 535 1.6 rscale mul FC 0.0 setgray 253 535 1.6 rscale mul OC 253 535 1.5 sub moveto 1.0 setgray 251 494 3.99 rscale mul FC 0.0 setgray 251 494 3.99 rscale mul OC 251 494 1.5 sub moveto 1.0 setgray 276 539 2.39 rscale mul FC 0.0 setgray 276 539 2.39 rscale mul OC 276 539 1.5 sub moveto 1.0 setgray 300 540 1.95 rscale mul FC 0.0 setgray 300 540 1.95 rscale mul OC 300 540 1.5 sub moveto 1.0 setgray 290 500 4.98 rscale mul FC 0.0 setgray 290 500 4.98 rscale mul OC 290 500 1.5 sub moveto 1.0 setgray 277 458 13.5 rscale mul FC 0.0 setgray 277 458 13.5 rscale mul OC 277 458 1.5 sub moveto 1.0 setgray 260 413 49.3 rscale mul FC 0.0 setgray 260 413 49.3 rscale mul OC 260 413 1.5 sub moveto 1.0 setgray 246 359 77.9 rscale mul FC 0.0 setgray 246 359 77.9 rscale mul OC 246 359 1.5 sub moveto 1.0 setgray 324 539 2.39 rscale mul FC 0.0 setgray 324 539 2.39 rscale mul OC 324 539 1.5 sub moveto 1.0 setgray 347 535 2.93 rscale mul FC 0.0 setgray 347 535 2.93 rscale mul OC 347 535 1.5 sub moveto 1.0 setgray 329 498 6.18 rscale mul FC 0.0 setgray 329 498 6.18 rscale mul OC 329 498 1.5 sub moveto 1.0 setgray 370 530 1.95 rscale mul FC 0.0 setgray 370 530 1.95 rscale mul OC 370 530 1.5 sub moveto 1.0 setgray 392 522 2.39 rscale mul FC 0.0 setgray 392 522 2.39 rscale mul OC 392 522 1.5 sub moveto 1.0 setgray 367 488 4.98 rscale mul FC 0.0 setgray 367 488 4.98 rscale mul OC 367 488 1.5 sub moveto 1.0 setgray 339 455 17.3 rscale mul FC 0.0 setgray 339 455 17.3 rscale mul OC 339 455 1.5 sub moveto 1.0 setgray 413 512 1.95 rscale mul FC 0.0 setgray 413 512 1.95 rscale mul OC 413 512 1.5 sub moveto 1.0 setgray 433 500 2.39 rscale mul FC 0.0 setgray 433 500 2.39 rscale mul OC 433 500 1.5 sub moveto 1.0 setgray 403 472 4.98 rscale mul FC 0.0 setgray 403 472 4.98 rscale mul OC 403 472 1.5 sub moveto 1.0 setgray 452 486 1.6 rscale mul FC 0.0 setgray 452 486 1.6 rscale mul OC 452 486 1.5 sub moveto 1.0 setgray 470 470 1.95 rscale mul FC 0.0 setgray 470 470 1.95 rscale mul OC 470 470 1.5 sub moveto 1.0 setgray 434 448 3.99 rscale mul FC 0.0 setgray 434 448 3.99 rscale mul OC 434 448 1.5 sub moveto 1.0 setgray 395 429 13.5 rscale mul FC 0.0 setgray 395 429 13.5 rscale mul OC 395 429 1.5 sub moveto 1.0 setgray 351 408 49.3 rscale mul FC 0.0 setgray 351 408 49.3 rscale mul OC 351 408 1.5 sub moveto 1.0 setgray 486 452 2.93 rscale mul FC 0.0 setgray 486 452 2.93 rscale mul OC 486 452 1.5 sub moveto 1.0 setgray 500 433 2.39 rscale mul FC 0.0 setgray 500 433 2.39 rscale mul OC 500 433 1.5 sub moveto 1.0 setgray 461 419 6.18 rscale mul FC 0.0 setgray 461 419 6.18 rscale mul OC 461 419 1.5 sub moveto 1.0 setgray 512 413 2.39 rscale mul FC 0.0 setgray 512 413 2.39 rscale mul OC 512 413 1.5 sub moveto 1.0 setgray 522 392 1.95 rscale mul FC 0.0 setgray 522 392 1.95 rscale mul OC 522 392 1.5 sub moveto 1.0 setgray 481 386 4.98 rscale mul FC 0.0 setgray 481 386 4.98 rscale mul OC 481 386 1.5 sub moveto 1.0 setgray 437 382 17.3 rscale mul FC 0.0 setgray 437 382 17.3 rscale mul OC 437 382 1.5 sub moveto 1.0 setgray 530 370 2.39 rscale mul FC 0.0 setgray 530 370 2.39 rscale mul OC 530 370 1.5 sub moveto 1.0 setgray 535 347 1.95 rscale mul FC 0.0 setgray 535 347 1.95 rscale mul OC 535 347 1.5 sub moveto 1.0 setgray 494 349 4.98 rscale mul FC 0.0 setgray 494 349 4.98 rscale mul OC 494 349 1.5 sub moveto 1.0 setgray 539 324 1.95 rscale mul FC 0.0 setgray 539 324 1.95 rscale mul OC 539 324 1.5 sub moveto 1.0 setgray 540 300 1.6 rscale mul FC 0.0 setgray 540 300 1.6 rscale mul OC 540 300 1.5 sub moveto 1.0 setgray 500 310 3.99 rscale mul FC 0.0 setgray 500 310 3.99 rscale mul OC 500 310 1.5 sub moveto 1.0 setgray 458 323 13.5 rscale mul FC 0.0 setgray 458 323 13.5 rscale mul OC 458 323 1.5 sub moveto 1.0 setgray 413 340 49.3 rscale mul FC 0.0 setgray 413 340 49.3 rscale mul OC 413 340 1.5 sub moveto 1.0 setgray 359 354 77.9 rscale mul FC 0.0 setgray 359 354 77.9 rscale mul OC 359 354 1.5 sub moveto 1.0 setgray 302 340 161 rscale mul FC 0.0 setgray 302 340 161 rscale mul OC 302 340 1.5 sub moveto 1.0 setgray 300 300 254 rscale mul FC 0.0 setgray 300 300 254 rscale mul OC 300 300 1.5 sub moveto grestore 60 60 480 480 rectstroke showpageEigen/Bridge.h010075500020550007177000000162640663625432000145070ustar00clevecompmath00000400000006#include "../InpMtx.h" #include "../Pencil.h" #include "../ETree.h" #include "../FrontMtx.h" #include "../SymbFac.h" #include "../misc.h" /* ---------------------------------------------------------------- this object is the bridge between the lanczos and spooles codes. NOTE: serial version neqns -- number of equations prbtype -- problem type 1 -- vibration, multiply with M or B 2 -- buckling, multiply with K or A 3 -- simple mxbsz -- maximum block size seed -- random number seed used in ordering msglvl -- message level for SPOOLES programs set msglvl = 0 for no output set msglvl = 1 for scalar and timing output set msglvl >= 2 for lots of output msgFile -- message file for debug and diagnostic output external objects, not free'd in the cleanup A -- InpMtx object for the first matrix, B -- InpMtx object for the second matrix internal objects, free'd in cleanup pencil -- Pencil object that contains A + sigma B frontETree -- object that contains the front tree information symbfacIVL -- object that contains the symbolic factorization mtxmanager -- SubMtx manager object that handles storage for the submatrices of the factors. frontmtx -- object that contains the factorization oldToNewIV -- object that contains the old-to-new permutation newToOldIV -- object that contains the new-to-old permutation X -- DenseMtx object used in the matrix multiply and solves Y -- DenseMtx object used in the matrix multiply and solves created -- 98aug10, jcp & cca ---------------------------------------------------------------- */ typedef struct bridge_ { int prbtype ; int neqns ; int mxbsz ; InpMtx *A ; InpMtx *B ; Pencil *pencil ; ETree *frontETree ; IVL *symbfacIVL ; SubMtxManager *mtxmanager ; FrontMtx *frontmtx ; IV *oldToNewIV ; IV *newToOldIV ; DenseMtx *X ; DenseMtx *Y ; int seed ; int msglvl ; FILE *msgFile ; } Bridge ; /*--------------------------------------------------------------------*/ #ifndef _TIMINGS_ #define _TIMINGS_ #include static struct timeval TV ; static struct timezone TZ ; #define MARKTIME(t) \ gettimeofday(&TV, &TZ) ; \ t = (TV.tv_sec + 0.000001*TV.tv_usec) #endif /*--------------------------------------------------------------------*/ /* ------------------------------ prototypes for bridge routines ------------------------------ */ /* ---------------------------------------------------------------- purpose -- given InpMtx objects that contain A and B, initialize the bridge data structure for the serial factor's, solve's and mvm's. data -- pointer to a Bridge object pprbtype -- pointer to value containing problem type *prbtype = 1 --> A X = B X Lambda, vibration problem *prbtype = 2 --> A X = B X Lambda, buckling problem *prbtype = 3 --> A X = X Lambda, simple eigenvalue problem pneqns -- pointer to value containing number of equations pmxbsz -- pointer to value containing blocksize A -- pointer to InpMtx object containing A B -- pointer to InpMtx object containing B pseed -- pointer to value containing a random number seed pmsglvl -- pointer to value containing a message level msgFile -- message file pointer return value -- 1 -- normal return -1 -- data is NULL -2 -- pprbtype is NULL -3 -- *pprbtype is invalid -4 -- pneqns is NULL -5 -- *pneqns is invalid -6 -- pmxbsz is NULL -7 -- *pmxbsz is invalid -8 -- A and B are NULL -9 -- pseed is NULL -10 -- pmsglvl is NULL -11 -- *pmsglvl > 0 and msgFile is NULL created -- 98aug10, cca ---------------------------------------------------------------- */ int Setup ( void *data, int *pprbtype, int *pneqns, int *pmxbsz, InpMtx *A, InpMtx *B, int *pseed, int *pmsglvl, FILE *msgFile ) ; /* --------------------------------------------------------------------- purpose -- to compute the factorization of A - sigma * B note: all variables in the calling sequence are references to allow call from fortran. input parameters data -- pointer to bridge data object psigma -- shift for the matrix pencil ppvttol -- pivot tolerance *ppvttol = 0.0 --> no pivoting used *ppvttol != 0.0 --> pivoting used, entries in factor are bounded above by 1/pvttol in magnitude output parameters *pinertia -- on return contains the number of negative eigenvalues *perror -- on return contains an error code 1 -- error found during factorization 0 -- normal return -1 -- psigma is NULL -2 -- ppvttol is NULL -3 -- data is NULL -4 -- pinertia is NULL created -- 98aug10, cca & jcp --------------------------------------------------------------------- */ void Factor ( double *psigma, double *ppvttol, void *data, int *pinertia, int *perror ) ; /* ------------------------------------------------------------- purpose --- to compute a matrix-vector multiply y[] = C * x[] where C is the identity, A or B (depending on *pprbtype). *pnrows -- # of rows in x[] *pncols -- # of columns in x[] *pprbtype -- problem type *pprbtype = 1 --> vibration problem, matrix is A *pprbtype = 2 --> buckling problem, matrix is B *pprbtype = 3 --> matrix is identity, y[] = x[] created -- 98aug11, cca & jcp ------------------------------------------------------------- */ void MatMul ( int *pnrows, int *pncols, double x[], double y[], int *pprbtype, void *data ) ; /* ---------------------------------------------- purpose -- to solve a linear system (A - sigma*B) sol[] = rhs[] data -- pointer to bridge data object *pnrows -- # of rows in x[] and y[] *pncols -- # of columns in x[] and y[] rhs[] -- vector that holds right hand sides sol[] -- vector to hold solutions note: rhs[] and sol[] can be the same array. on return, *perror holds an error code. 1 -- normal return -1 -- pnrows is NULL -2 -- pncols is NULL -3 -- rhs is NULL -4 -- sol is NULL -5 -- data is NULL created -- 98aug10, cca & jcp ---------------------------------------------- */ void Solve ( int *pnrows, int *pncols, double rhs[], double sol[], void *data, int *perror ) ; /* -------------------------------------------- purpose -- to free the owned data structures return values -- 1 -- normal return -1 -- data is NULL created -- 98aug10, cca -------------------------------------------- */ int Cleanup ( void *data ) ; /*--------------------------------------------------------------------*/ Eigen/BridgeMPI.h010075500020550007177000000176050663677251000150630ustar00clevecompmath00000400000006/* BridgeMPI.h */ /* #include */ #include "../MPI.h" #define LOCAL 1 #define GLOBAL 2 /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- this object is the bridge between the lanczos and spooles codes. NOTE: MPI version neqns -- number of equations prbtype -- problem type 1 -- vibration, multiply with M or B 2 -- buckling, multiply with K or A 3 -- simple mxbsz -- maximum block size nproc -- number of processes myid -- id of this process coordFlag -- coordinate flag 1 -- global coordinates for local matrix used in mvm 2 -- local coordinates for local matrix used in mvm seed -- random number seed used in ordering msglvl -- message level for SPOOLES programs set msglvl = 0 for no output set msglvl = 1 for scalar and timing output set msglvl >= 2 for lots of output msgFile -- message file for debug and diagnostic output external objects, not free'd in the cleanup A -- InpMtx object for the first matrix, B -- InpMtx object for the second matrix internal objects, free'd in cleanup pencil -- Pencil object that contains A + sigma B frontETree -- object that contains the front tree information symbfacIVL -- object that contains the symbolic factorization mtxmanager -- SubMtx manager object that handles storage for the submatrices of the factors. frontmtx -- object that contains the factorization oldToNewIV -- object that contains the old-to-new permutation newToOldIV -- object that contains the new-to-old permutation vtxmapIV -- object that contains the map from vertices to processes myownedIV -- object that contains the vertices owned by this processor ownersIV -- object that contains the map from fronts to processes solvemap -- object that contains the map from submatrices to processes rowmapIV -- if pivoting was performed, this object holds the map from rows of the factor to processors. Xloc -- local matrix for X of Y = A*X Yloc -- local matrix for Y of Y = A*X info -- object for distributed matrix-matrix multiply created -- 98aug10, jcp & cca -------------------------------------------------------------------- */ typedef struct bridgeMPI_ { int neqns ; int nproc ; int myid ; int prbtype ; int mxbsz ; int coordFlag ; InpMtx *A ; InpMtx *B ; Pencil *pencil ; ETree *frontETree ; IVL *symbfacIVL ; SubMtxManager *mtxmanager ; FrontMtx *frontmtx ; IV *oldToNewIV ; IV *newToOldIV ; IV *vtxmapIV ; IV *myownedIV ; IV *ownersIV ; IV *rowmapIV ; SolveMap *solvemap ; MatMulInfo *info ; DenseMtx *Xloc ; DenseMtx *Yloc ; int seed ; int msglvl ; FILE *msgFile ; MPI_Comm comm ; } BridgeMPI ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- given InpMtx objects that contain A and B, initialize the bridge data structure for the MPI factor's, solve's and mvm's. NOTE: all the input arguments are pointers to allow calls from Fortran data -- pointer to a Bridge object pprbtype -- pointer to value containing problem type *prbtype = 1 --> A X = B X Lambda, vibration problem *prbtype = 2 --> A X = B X Lambda, buckling problem *prbtype = 3 --> A X = X Lambda, simple eigenvalue problem pneqns -- pointer to value containing number of equations pmxbsz -- pointer to value containing blocksize A -- pointer to InpMtx object containing A B -- pointer to InpMtx object containing B pseed -- pointer to value containing a random number seed pmsglvl -- pointer to value containing a message level msgFile -- message file pointer return value -- 1 -- normal return -1 -- data is NULL -2 -- pprbtype is NULL -3 -- *pprbtype is invalid -4 -- pneqns is NULL -5 -- *pneqns is invalid -6 -- pmxbsz is NULL -7 -- *pmxbsz is invalid -8 -- A and B are NULL -9 -- pseed is NULL -10 -- pmsglvl is NULL -11 -- *pmsglvl > 0 and msgFile is NULL -12 -- comm is NULL created -- 98aug10, cca ---------------------------------------------------------------- */ int SetupMPI ( void *data, int *pprbtype, int *pneqns, int *pmxbsz, InpMtx *A, InpMtx *B, int *pseed, int *pmsglvl, FILE *msgFile, MPI_Comm comm ) ; /* --------------------------------------------------------------------- purpose -- to compute the factorization of A - sigma * B note: all variables in the calling sequence are references to allow call from fortran. input parameters data -- pointer to bridge data object psigma -- shift for the matrix pencil ppvttol -- pivot tolerance *ppvttol = 0.0 --> no pivoting used *ppvttol != 0.0 --> pivoting used, entries in factor are bounded above by 1/pvttol in magnitude output parameters *pinertia -- on return contains the number of negative eigenvalues *perror -- on return contains an error code 1 -- error found during factorization 0 -- normal return -1 -- psigma is NULL -2 -- ppvttol is NULL -3 -- data is NULL -4 -- pinertia is NULL created -- 98aug10, cca & jcp --------------------------------------------------------------------- */ void FactorMPI ( double *psigma, double *ppvttol, void *data, int *pinertia, int *perror ) ; /* ------------------------------------------------------------- purpose --- to compute a matrix-vector multiply y[] = C * x[] where C is the identity, A or B (depending on *pprbtype). *pnrows -- # of rows in x[] *pncols -- # of columns in x[] *pprbtype -- problem type *pprbtype = 1 --> vibration problem, matrix is A *pprbtype = 2 --> buckling problem, matrix is B *pprbtype = 3 --> matrix is identity, y[] = x[] created -- 98aug11, cca & jcp ------------------------------------------------------------- */ void MatMulMPI ( int *pnrows, int *pncols, double x[], double y[], int *pprbtype, void *data ) ; /* ---------------------------------------------- purpose -- to solve a linear system (A - sigma*B) sol[] = rhs[] data -- pointer to bridge data object *pnrows -- # of rows in x[] and y[] *pncols -- # of columns in x[] and y[] rhs[] -- vector that holds right hand sides sol[] -- vector to hold solutions note: rhs[] and sol[] can be the same array. on return, *perror holds an error code. created -- 98aug10, cca & jcp ---------------------------------------------- */ void SolveMPI ( int *pnrows, int *pncols, double rhs[], double sol[], void *data, int *perror ) ; /* -------------------------------------------- purpose -- to free the owned data structures return values -- 1 -- normal return -1 -- data is NULL created -- 98aug10, cca -------------------------------------------- */ int CleanupMPI ( void *data ) ; /*--------------------------------------------------------------------*/ Eigen/BridgeMT.h010075500020550007177000000166440663625534700147640ustar00clevecompmath00000400000006#include "../InpMtx.h" #include "../Pencil.h" #include "../ETree.h" #include "../FrontMtx.h" #include "../SymbFac.h" #include "../MT.h" #include "../misc.h" /* -------------------------------------------------------------------- this object is the bridge between the lanczos and spooles codes. NOTE: POSIX multithreaded version neqns -- number of equations prbtype -- problem type 1 -- vibration, multiply with M or B 2 -- buckling, multiply with K or A 3 -- simple mxbsz -- maximum block size nthread -- number of threads seed -- random number seed used in ordering msglvl -- message level for SPOOLES programs set msglvl = 0 for no output set msglvl = 1 for scalar and timing output set msglvl >= 2 for lots of output msgFile -- message file for debug and diagnostic output external objects, not free'd in the cleanup A -- InpMtx object for the first matrix, B -- InpMtx object for the second matrix internal objects, free'd in cleanup pencil -- Pencil object that contains A + sigma B frontETree -- object that contains the front tree information symbfacIVL -- object that contains the symbolic factorization mtxmanager -- SubMtx manager object that handles storage for the submatrices of the factors. frontmtx -- object that contains the factorization oldToNewIV -- object that contains the old-to-new permutation newToOldIV -- object that contains the new-to-old permutation ownersIV -- object that contains the map from fronts to threads solvemap -- object that contains the map from submatrices to threads created -- 98aug10, jcp & cca -------------------------------------------------------------------- */ typedef struct bridgeMT_ { int prbtype ; int neqns ; int mxbsz ; int nthread ; InpMtx *A ; InpMtx *B ; Pencil *pencil ; ETree *frontETree ; IVL *symbfacIVL ; SubMtxManager *mtxmanager ; FrontMtx *frontmtx ; IV *oldToNewIV ; IV *newToOldIV ; DenseMtx *X ; DenseMtx *Y ; IV *ownersIV ; SolveMap *solvemap ; int seed ; int msglvl ; FILE *msgFile ; } BridgeMT ; /*--------------------------------------------------------------------*/ #ifndef _TIMINGS_ #define _TIMINGS_ #include static struct timeval TV ; static struct timezone TZ ; #define MARKTIME(t) \ gettimeofday(&TV, &TZ) ; \ t = (TV.tv_sec + 0.000001*TV.tv_usec) #endif /*--------------------------------------------------------------------*/ /* ------------------------------ prototypes for bridge routines ------------------------------ */ /* ------------------------------------------------------------------ purpose -- given InpMtx objects that contain A and B, initialize the bridge data structure for the multithreaded factor's, solve's and mvm's. data -- pointer to a Bridge object pprbtype -- pointer to value containing problem type *prbtype = 1 --> A X = B X Lambda, vibration problem *prbtype = 2 --> A X = B X Lambda, buckling problem *prbtype = 3 --> A X = X Lambda, simple eigenvalue problem pneqns -- pointer to value containing number of equations pmxbsz -- pointer to value containing blocksize A -- pointer to InpMtx object containing A B -- pointer to InpMtx object containing B pseed -- pointer to value containing a random number seed pmsglvl -- pointer to value containing a message level msgFile -- message file pointer pnthread -- pointer to value containing # of threads return value -- 1 -- normal return -1 -- data is NULL -2 -- pprbtype is NULL -3 -- *pprbtype is invalid -4 -- pneqns is NULL -5 -- *pneqns is invalid -6 -- pmxbsz is NULL -7 -- *pmxbsz is invalid -8 -- A and B are NULL -9 -- pseed is NULL -10 -- pmsglvl is NULL -11 -- *pmsglvl > 0 and msgFile is NULL created -- 98aug10, cca ------------------------------------------------------------------ */ int SetupMT ( void *data, int *pprbtype, int *pneqns, int *pmxbsz, InpMtx *A, InpMtx *B, int *pseed, int *pnthread, int *pmsglvl, FILE *msgFile ) ; /* --------------------------------------------------------------------- purpose -- to compute the factorization of A - sigma * B note: all variables in the calling sequence are references to allow call from fortran. input parameters data -- pointer to bridge data object psigma -- shift for the matrix pencil ppvttol -- pivot tolerance *ppvttol = 0.0 --> no pivoting used *ppvttol != 0.0 --> pivoting used, entries in factor are bounded above by 1/pvttol in magnitude output parameters *pinertia -- on return contains the number of negative eigenvalues *perror -- on return contains an error code 1 -- error found during factorization 0 -- normal return -1 -- psigma is NULL -2 -- ppvttol is NULL -3 -- data is NULL -4 -- pinertia is NULL created -- 98aug10, cca & jcp --------------------------------------------------------------------- */ void FactorMT ( double *psigma, double *ppvttol, void *data, int *pinertia, int *perror ) ; /* ------------------------------------------------------------- purpose --- to compute a matrix-vector multiply y[] = C * x[] where C is the identity, A or B (depending on *pprbtype). *pprbtype -- problem type *pprbtype = 1 --> vibration problem, matrix is A *pprbtype = 2 --> buckling problem, matrix is B *pprbtype = 3 --> matrix is identity, y[] = x[] *pnrows -- # of rows in x[] *pncols -- # of columns in x[] created -- 98aug11, cca & jcp ------------------------------------------------------------- */ void MatMulMT ( int *pnrows, int *pncols, double x[], double y[], int *pprbtype, void *data ) ; /* ---------------------------------------------- purpose -- to solve a linear system (A - sigma*B) sol[] = rhs[] data -- pointer to bridge data object *pnrows -- # of rows in x[] and y[] *pncols -- # of columns in x[] and y[] rhs[] -- vector that holds right hand sides sol[] -- vector to hold solutions note: rhs[] and sol[] can be the same array. on return, *perror holds an error code. 1 -- normal return -1 -- pnrows is NULL -2 -- pncols is NULL -3 -- rhs is NULL -4 -- sol is NULL -5 -- data is NULL created -- 98aug10, cca & jcp ---------------------------------------------- */ void SolveMT ( int *pnrows, int *pncols, double rhs[], double sol[], void *data, int *perror ) ; /* -------------------------------------------- purpose -- to free the owned data structures return values -- 1 -- normal return -1 -- data is NULL created -- 98aug10, cca -------------------------------------------- */ int CleanupMT ( void *data ) ; /*--------------------------------------------------------------------*/ containing number of equations pmxbsz -- pointer to value containing blocksize A Eigen/makefile010075500020550007177000000004230663677615400146460ustar00clevecompmath00000400000006all_drivers : cd drivers ; make all_drivers lib : cd srcMPI ; make BridgeMPI.a cd srcMT ; make BridgeMT.a cd srcST ; make Bridge.a clean : cd srcMPI ; make clean cd srcMT ; make clean cd srcST ; make clean cd drivers ; make clean cd doc ; make clean Eigen/srcST/makefile010064400020550007177000000005250663625430300156670ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Bridge $(OBJ).a : \ $(OBJ).a(Cleanup.o) \ $(OBJ).a(Factor.o) \ $(OBJ).a(MatMul.o) \ $(OBJ).a(Setup.o) \ $(OBJ).a(Solve.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o Eigen/srcST/Cleanup.c010064400020550007177000000027110663356111600157210ustar00clevecompmath00000400000006/* Cleanup.c */ #include "../Bridge.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Cleanup = 0 ; static double time_Cleanup = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to free the owned data structures return values -- 1 -- normal return -1 -- data is NULL created -- 98aug10, cca -------------------------------------------- */ int Cleanup ( void *data ) { Bridge *bridge = (Bridge *) data ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_Cleanup++ ; fprintf(stdout, "\n (%d) Cleanup()", count_Cleanup) ; fflush(stdout) ; #endif /* --------------- check the input --------------- */ if ( data == NULL ) { fprintf(stderr, "\n error in Cleanup()" "\n data is NULL\n") ; return(-1) ; } bridge->pencil->inpmtxA = NULL ; bridge->pencil->inpmtxB = NULL ; Pencil_free(bridge->pencil) ; IVL_free(bridge->symbfacIVL) ; FrontMtx_free(bridge->frontmtx) ; ETree_free(bridge->frontETree) ; SubMtxManager_free(bridge->mtxmanager) ; IV_free(bridge->oldToNewIV) ; IV_free(bridge->newToOldIV) ; DenseMtx_free(bridge->X) ; DenseMtx_free(bridge->Y) ; #if MYDEBUG > 0 MARKTIME(t2) ; time_Cleanup += t2 - t1 ; fprintf(stdout, ", %8.3f seconds, %8.3f total seconds, ", t2 - t1, time_Cleanup) ; fflush(stdout) ; #endif return(1) ; } /*--------------------------------------------------------------------*/ Eigen/srcST/Factor.c010064400020550007177000000124520663355732600155630ustar00clevecompmath00000400000006/* Factor.c */ #include "../Bridge.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Factor = 0 ; static double time_Factor = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to compute the factorization of A - sigma * B note: all variables in the calling sequence are references to allow call from fortran. input parameters data -- pointer to bridge data object psigma -- shift for the matrix pencil ppvttol -- pivot tolerance *ppvttol = 0.0 --> no pivoting used *ppvttol != 0.0 --> pivoting used, entries in factor are bounded above by 1/pvttol in magnitude output parameters *pinertia -- on return contains the number of negative eigenvalues *perror -- on return contains an error code 1 -- error found during factorization 0 -- normal return -1 -- psigma is NULL -2 -- ppvttol is NULL -3 -- data is NULL -4 -- pinertia is NULL created -- 98aug10, cca & jcp --------------------------------------------------------------------- */ void Factor ( double *psigma, double *ppvttol, void *data, int *pinertia, int *perror ) { Bridge *bridge = (Bridge *) data ; Chv *rootchv ; ChvManager *chvmanager ; double droptol=0.0, tau ; double cpus[10] ; int stats[20] ; int nnegative, nzero, npositive, pivotingflag ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_Factor++ ; fprintf(stdout, "\n (%d) Factor()", count_Factor) ; fflush(stdout) ; #endif /* --------------- check the input --------------- */ if ( psigma == NULL ) { fprintf(stderr, "\n error in Factor()" "\n psigma is NULL\n") ; *perror = -1 ; return ; } if ( ppvttol == NULL ) { fprintf(stderr, "\n error in Factor()" "\n ppvttol is NULL\n") ; *perror = -2 ; return ; } if ( data == NULL ) { fprintf(stderr, "\n error in Factor()" "\n data is NULL\n") ; *perror = -3 ; return ; } if ( pinertia == NULL ) { fprintf(stderr, "\n error in Factor()" "\n pinertia is NULL\n") ; *perror = -4 ; return ; } if ( perror == NULL ) { fprintf(stderr, "\n error in Factor()" "\n perror is NULL\n") ; return ; } /* ---------------------------------- set the shift in the pencil object ---------------------------------- */ bridge->pencil->sigma[0] = -(*psigma) ; bridge->pencil->sigma[1] = 0.0 ; /* ----------------------------------------------------- clear the front matrix and submatrix mananger objects ----------------------------------------------------- */ FrontMtx_clearData(bridge->frontmtx); SubMtxManager_clearData(bridge->mtxmanager); /* ----------------------------------------------------------- set the pivot tolerance. NOTE: spooles's "tau" parameter is a bound on the magnitude of the factor entries, and is the recipricol of that of the pivot tolerance of the lanczos code ----------------------------------------------------------- */ if ( *ppvttol == 0.0 ) { tau = 10.0 ; pivotingflag = SPOOLES_NO_PIVOTING ; } else { tau = (1.0)/(*ppvttol) ; pivotingflag = SPOOLES_PIVOTING ; } /* ---------------------------------- initialize the front matrix object ---------------------------------- */ FrontMtx_init(bridge->frontmtx, bridge->frontETree, bridge->symbfacIVL, SPOOLES_REAL, SPOOLES_SYMMETRIC, FRONTMTX_DENSE_FRONTS, pivotingflag, NO_LOCK, 0, NULL, bridge->mtxmanager, bridge->msglvl, bridge->msgFile) ; /* ------------------------- compute the factorization ------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1); IVfill(20, stats, 0) ; DVfill(10, cpus, 0.0) ; rootchv = FrontMtx_factorPencil(bridge->frontmtx, bridge->pencil, tau, droptol, chvmanager, perror, cpus, stats, bridge->msglvl, bridge->msgFile); ChvManager_free(chvmanager); /* ---------------------------- if matrix is singular then set error flag and return ---------------------------- */ if ( rootchv != NULL ) { *perror = 1 ; return ; } /* ------------------------------------------------------------------ post-process the factor matrix, convert from fronts to submatrices ------------------------------------------------------------------ */ FrontMtx_postProcess(bridge->frontmtx, bridge->msglvl, bridge->msgFile); /* ------------------- compute the inertia ------------------- */ FrontMtx_inertia(bridge->frontmtx, &nnegative, &nzero, &npositive) ; *pinertia = nnegative; /* ------------------------------------------------------------------ set the error. (this is simple since when the spooles codes detect a fatal error, they print out a message to stderr and exit.) ------------------------------------------------------------------ */ *perror = 0 ; #if MYDEBUG > 0 MARKTIME(t2) ; time_Factor += t2 - t1 ; fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Factor) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ Eigen/srcST/MatMul.c010064400020550007177000000056210663653174200155410ustar00clevecompmath00000400000006/* MatMul.c */ #include "../Bridge.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_MatMul = 0 ; static double time_MatMul = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose --- to compute a matrix-vector multiply y[] = C * x[] where C is the identity, A or B (depending on *pprbtype). *pprbtype -- problem type *pprbtype = 1 --> vibration problem, matrix is A *pprbtype = 2 --> buckling problem, matrix is B *pprbtype = 3 --> matrix is identity, y[] = x[] *pnrows -- # of rows in x[] *pncols -- # of columns in x[] created -- 98aug11, cca & jcp ------------------------------------------------------------- */ void MatMul ( int *pnrows, int *pncols, double x[], double y[], int *pprbtype, void *data ) { int ncols, nent, nrows ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_MatMul++ ; fprintf(stdout, "\n (%d) MatMul()", count_MatMul) ; fflush(stdout) ; #endif nrows = *pnrows ; ncols = *pncols ; nent = nrows*ncols ; if ( *pprbtype == 3 ) { /* -------------------------- ... matrix is the identity -------------------------- */ DVcopy(nent, y, x) ; return; } else { Bridge *bridge = (Bridge *) data ; DenseMtx *X, *Y ; double alpha[2] = {1.0, 0.0} ; /* --------------------------------- setup x and y as DenseMtx objects --------------------------------- */ X = bridge->X ; DenseMtx_init(X, SPOOLES_REAL, 0, 0, nrows, ncols, 1, nrows); DVcopy (nent, DenseMtx_entries(X), x); if ( bridge->msglvl > 2 ) { fprintf(bridge->msgFile, "\n inside MatMul, X") ; DenseMtx_writeForHumanEye(X, bridge->msgFile) ; fflush(bridge->msgFile) ; } Y = bridge->Y ; DenseMtx_init(Y, SPOOLES_REAL, 0, 0, nrows, ncols, 1, nrows); DenseMtx_zero(Y); if ( *pprbtype == 1 ) { /* --------------------------------------- ... vibration case matrix is 'm' or 'b' --------------------------------------- */ InpMtx_sym_mmm(bridge->B, Y, alpha, X); } else { /* -------------------------------------- ... buckling case matrix is 'k' or 'a' -------------------------------------- */ InpMtx_sym_mmm(bridge->A, Y, alpha, X); } if ( bridge->msglvl > 2 ) { fprintf(bridge->msgFile, "\n inside MatMul, Y") ; DenseMtx_writeForHumanEye(Y, bridge->msgFile) ; fflush(bridge->msgFile) ; } /* -------------------------------- copy solution into output vector -------------------------------- */ DVcopy (nent, y, DenseMtx_entries(Y) ); } #if MYDEBUG > 0 MARKTIME(t2) ; time_MatMul += t2 - t1 ; fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_MatMul) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ Eigen/srcST/Setup.c010064400020550007177000000222070663355720700154420ustar00clevecompmath00000400000006/* Setup.c */ #include "../Bridge.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Setup = 0 ; static double time_Setup = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- given InpMtx objects that contain A and B, initialize the bridge data structure for the serial factor's, solve's and mvm's. data -- pointer to a Bridge object pprbtype -- pointer to value containing problem type *prbtype = 1 --> A X = B X Lambda, vibration problem *prbtype = 2 --> A X = B X Lambda, buckling problem *prbtype = 3 --> A X = X Lambda, simple eigenvalue problem pneqns -- pointer to value containing number of equations pmxbsz -- pointer to value containing blocksize A -- pointer to InpMtx object containing A B -- pointer to InpMtx object containing B pseed -- pointer to value containing a random number seed pmsglvl -- pointer to value containing a message level msgFile -- message file pointer return value -- 1 -- normal return -1 -- data is NULL -2 -- pprbtype is NULL -3 -- *pprbtype is invalid -4 -- pneqns is NULL -5 -- *pneqns is invalid -6 -- pmxbsz is NULL -7 -- *pmxbsz is invalid -8 -- A and B are NULL -9 -- pseed is NULL -10 -- pmsglvl is NULL -11 -- *pmsglvl > 0 and msgFile is NULL created -- 98aug10, cca ---------------------------------------------------------------- */ int Setup ( void *data, int *pprbtype, int *pneqns, int *pmxbsz, InpMtx *A, InpMtx *B, int *pseed, int *pmsglvl, FILE *msgFile ) { Bridge *bridge = (Bridge *) data ; double sigma[2] ; Graph *graph ; int maxdomainsize, maxsize, maxzeros, msglvl, mxbsz, nedges, neqns, prbtype, seed ; IVL *adjIVL ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_Setup++ ; fprintf(stdout, "\n (%d) Setup()", count_Setup) ; fflush(stdout) ; #endif /* -------------------- check the input data -------------------- */ if ( data == NULL ) { fprintf(stderr, "\n fatal error in Setup()" "\n data is NULL\n") ; return(-1) ; } if ( pprbtype == NULL ) { fprintf(stderr, "\n fatal error in Setup()" "\n prbtype is NULL\n") ; return(-2) ; } prbtype = *pprbtype ; if ( prbtype < 1 || prbtype > 3 ) { fprintf(stderr, "\n fatal error in Setup()" "\n prbtype = %d, is invalid\n", prbtype) ; return(-3) ; } if ( pneqns == NULL ) { fprintf(stderr, "\n fatal error in Setup()" "\n pneqns is NULL\n") ; return(-4) ; } neqns = *pneqns ; if ( neqns <= 0 ) { fprintf(stderr, "\n fatal error in Setup()" "\n neqns = %d, is invalid\n", neqns) ; return(-5) ; } if ( pmxbsz == NULL ) { fprintf(stderr, "\n fatal error in Setup()" "\n pmxbsz is NULL\n") ; return(-6) ; } mxbsz = *pmxbsz ; if ( mxbsz <= 0 ) { fprintf(stderr, "\n fatal error in Setup()" "\n *pmxbsz = %d, is invalid\n", mxbsz) ; return(-7) ; } if ( A == NULL && B == NULL ) { fprintf(stderr, "\n fatal error in Setup()" "\n A and B are NULL\n") ; return(-8) ; } if ( pseed == NULL ) { fprintf(stderr, "\n fatal error in Setup()" "\n pseed is NULL\n") ; return(-9) ; } seed = *pseed ; if ( pmsglvl == NULL ) { fprintf(stderr, "\n fatal error in Setup()" "\n pmsglvl is NULL\n") ; return(-10) ; } msglvl = *pmsglvl ; if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n fatal error in Setup()" "\n msglvl = %d, msgFile = NULL\n", msglvl) ; return(-11) ; } bridge->msglvl = msglvl ; bridge->msgFile = msgFile ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside Setup()" "\n neqns = %d, prbtype = %d, mxbsz = %d, seed = %d", neqns, prbtype, mxbsz, seed) ; if ( A != NULL ) { fprintf(msgFile, "\n\n matrix A") ; InpMtx_writeForHumanEye(A, msgFile) ; } if ( B != NULL ) { fprintf(msgFile, "\n\n matrix B") ; InpMtx_writeForHumanEye(B, msgFile) ; } fflush(msgFile) ; } bridge->prbtype = prbtype ; bridge->neqns = neqns ; bridge->mxbsz = mxbsz ; bridge->A = A ; bridge->B = B ; bridge->seed = seed ; /* ---------------------------- create and initialize pencil ---------------------------- */ sigma[0] = 1.0; sigma[1] = 0.0; bridge->pencil = Pencil_new() ; Pencil_setDefaultFields(bridge->pencil) ; Pencil_init(bridge->pencil, SPOOLES_REAL, SPOOLES_SYMMETRIC, A, sigma, B) ; /* -------------------------------- convert to row or column vectors -------------------------------- */ if ( A != NULL ) { if ( ! INPMTX_IS_BY_ROWS(A) && ! INPMTX_IS_BY_COLUMNS(A) ) { InpMtx_changeCoordType(A, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(A) ) { InpMtx_changeStorageMode(A, INPMTX_BY_VECTORS) ; } } if ( B != NULL ) { if ( ! INPMTX_IS_BY_ROWS(B) && ! INPMTX_IS_BY_COLUMNS(B) ) { InpMtx_changeCoordType(B, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(B) ) { InpMtx_changeStorageMode(B, INPMTX_BY_VECTORS) ; } } /* ------------------------------- create a Graph object for A + B ------------------------------- */ graph = Graph_new() ; adjIVL = Pencil_fullAdjacency(bridge->pencil) ; nedges = IVL_tsize(adjIVL), Graph_init2(graph, 0, bridge->neqns, 0, nedges, bridge->neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* --------------- order the graph --------------- */ maxdomainsize = neqns / 64 ; if ( maxdomainsize == 0 ) { maxdomainsize = 1 ; } maxzeros = (int) (0.01*neqns) ; maxsize = 64 ; bridge->frontETree = orderViaBestOfNDandMS(graph, maxdomainsize, maxzeros, maxsize, bridge->seed, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(bridge->frontETree, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------------- get the old-to-new and new-to-old permutations ---------------------------------------------- */ bridge->oldToNewIV = ETree_oldToNewVtxPerm(bridge->frontETree) ; bridge->newToOldIV = ETree_newToOldVtxPerm(bridge->frontETree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n old-to-new permutation") ; IV_writeForHumanEye(bridge->oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation") ; IV_writeForHumanEye(bridge->newToOldIV, msgFile) ; fflush(msgFile) ; } /* -------------------------------------- permute the vertices in the front tree -------------------------------------- */ ETree_permuteVertices(bridge->frontETree, bridge->oldToNewIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted front etree") ; ETree_writeForHumanEye(bridge->frontETree, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------- permute the entries in the pencil. note, after the permutation the entries are mapped into the upper triangle. ------------------------------------------- */ Pencil_permute(bridge->pencil, bridge->oldToNewIV, bridge->oldToNewIV) ; Pencil_mapToUpperTriangle(bridge->pencil) ; Pencil_changeCoordType(bridge->pencil, INPMTX_BY_CHEVRONS) ; Pencil_changeStorageMode(bridge->pencil, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted pencil") ; Pencil_writeForHumanEye(bridge->pencil, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- compute the symbolic factorization ---------------------------------- */ bridge->symbfacIVL = SymbFac_initFromPencil(bridge->frontETree, bridge->pencil) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(bridge->symbfacIVL, msgFile) ; fflush(msgFile) ; } /* -------------------------------------------------- create a FrontMtx object to hold the factorization -------------------------------------------------- */ bridge->frontmtx = FrontMtx_new() ; /* ------------------------------------------------------------ create a SubMtxManager object to hold the factor submatrices ------------------------------------------------------------ */ bridge->mtxmanager = SubMtxManager_new() ; SubMtxManager_init(bridge->mtxmanager, NO_LOCK, 0) ; /* ------------------------------------------------------------ allocate the working objects X and Y for the matrix multiply ------------------------------------------------------------ */ bridge->X = DenseMtx_new() ; DenseMtx_init(bridge->X, SPOOLES_REAL, 0, 0, neqns, mxbsz, 1, neqns) ; bridge->Y = DenseMtx_new() ; DenseMtx_init(bridge->Y, SPOOLES_REAL, 0, 0, neqns, mxbsz, 1, neqns) ; /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; #if MYDEBUG > 0 MARKTIME(t2) ; time_Setup += t2 - t1 ; fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Setup) ; fflush(stdout) ; #endif return(1) ; } /*--------------------------------------------------------------------*/ Eigen/srcST/Solve.c010064400020550007177000000070550663355726200154370ustar00clevecompmath00000400000006/* Solve.c */ #include "../Bridge.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Solve = 0 ; static double time_Solve = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to solve a linear system (A - sigma*B) sol[] = rhs[] data -- pointer to bridge data object *pnrows -- # of rows in x[] and y[] *pncols -- # of columns in x[] and y[] rhs[] -- vector that holds right hand sides sol[] -- vector to hold solutions note: rhs[] and sol[] can be the same array. on return, *perror holds an error code. 1 -- normal return -1 -- pnrows is NULL -2 -- pncols is NULL -3 -- rhs is NULL -4 -- sol is NULL -5 -- data is NULL created -- 98aug10, cca & jcp ---------------------------------------------- */ void Solve ( int *pnrows, int *pncols, double rhs[], double sol[], void *data, int *perror ) { Bridge *bridge = (Bridge *) data ; DenseMtx *rhsmtx, *solmtx ; double cpus[10] ; int nent, ncols, nrows ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_Solve++ ; fprintf(stdout, "\n (%d) Solve()", count_Solve) ; fflush(stdout) ; #endif /* --------------- check the input --------------- */ if ( perror == NULL ) { fprintf(stderr, "\n error in Solve()" "\n perror == NULL\n") ; return ; } if ( pnrows == NULL ) { fprintf(stderr, "\n error in Solve()" "\n pnrows == NULL\n") ; *perror = -1 ; return ; } if ( pncols == NULL ) { fprintf(stderr, "\n error in Solve()" "\n pncols == NULL\n") ; *perror = -2 ; return ; } if ( rhs == NULL ) { fprintf(stderr, "\n error in Solve()" "\n rhs == NULL\n") ; *perror = -3 ; return ; } if ( sol == NULL ) { fprintf(stderr, "\n error in Solve()" "\n sol == NULL\n") ; *perror = -4 ; return ; } if ( data == NULL ) { fprintf(stderr, "\n error in Solve()" "\n data == NULL\n") ; *perror = -5 ; return ; } /* ---------------------------------- set the number of rows and columns ---------------------------------- */ nrows = *pnrows ; ncols = *pncols ; nent = nrows*ncols ; /* ------------------------------------------- setup rhsmtx and solmtx as DenseMtx objects ------------------------------------------ */ rhsmtx = bridge->Y ; DenseMtx_init(rhsmtx, SPOOLES_REAL, 0, 0, nrows, ncols, 1, nrows) ; DVcopy (nent, DenseMtx_entries(rhsmtx), rhs) ; solmtx = bridge->X ; DenseMtx_init(solmtx, SPOOLES_REAL, 0, 0, nrows, ncols, 1, nrows) ; DenseMtx_zero(solmtx) ; /* ----------------------- solve the linear system ----------------------- */ DVzero(10, cpus) ; FrontMtx_solve(bridge->frontmtx, solmtx, rhsmtx, bridge->mtxmanager, cpus, bridge->msglvl, bridge->msgFile) ; /* ----------------------------------- copy solution into output parameter ----------------------------------- */ DVcopy(nent, sol, DenseMtx_entries(solmtx)) ; /* ------------------------------------------------------------------ set the error. (this is simple since when the spooles codes detect a fatal error, they print out a message to stderr and exit.) ------------------------------------------------------------------ */ *perror = 0 ; #if MYDEBUG > 0 MARKTIME(t2) ; time_Solve += t2 - t1 ; fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Solve) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ ata ; DenseMtx *rhsmtx, *solmtx ; double cpus[10] ; int nent, ncols, nrows ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_Solve++ ; fprintf(stdout, "\n (%d) Solve()", count_Solve) ; fflush(stdout) ; #endif /* --------------- check the input --------------- */ if ( perror == NULL ) { fprintf(stderr, "\n error in Solve()" "\n perror == NULL\n") ; return ; } if ( pnrows == NULL ) { fprintf(stderr, "\n error in SolvEigen/srcMT/makefile010064400020550007177000000005410662557107500156650ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = BridgeMT $(OBJ).a : \ $(OBJ).a(CleanupMT.o) \ $(OBJ).a(FactorMT.o) \ $(OBJ).a(MatMulMT.o) \ $(OBJ).a(SetupMT.o) \ $(OBJ).a(SolveMT.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o Eigen/srcMT/CleanupMT.c010064400020550007177000000024750663356112100161570ustar00clevecompmath00000400000006/* CleanupMT.c */ #include "../BridgeMT.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Cleanup = 0 ; static double time_Cleanup = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to free the owned data structures return values -- 1 -- normal return -1 -- data is NULL created -- 98aug10, cca -------------------------------------------- */ int CleanupMT ( void *data ) { BridgeMT *bridge = (BridgeMT *) data ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_Cleanup++ ; fprintf(stdout, "\n (%d) CleanupMT()", count_Cleanup) ; #endif bridge->pencil->inpmtxA = NULL ; bridge->pencil->inpmtxB = NULL ; Pencil_free(bridge->pencil) ; IVL_free(bridge->symbfacIVL) ; FrontMtx_free(bridge->frontmtx) ; ETree_free(bridge->frontETree) ; SubMtxManager_free(bridge->mtxmanager) ; IV_free(bridge->oldToNewIV) ; IV_free(bridge->newToOldIV) ; IV_free(bridge->ownersIV) ; DenseMtx_free(bridge->X) ; DenseMtx_free(bridge->Y) ; SolveMap_free(bridge->solvemap) ; #if MYDEBUG > 0 MARKTIME(t2) ; time_Cleanup += t2 - t1 ; fprintf(stdout, ", %8.3f seconds, %8.3f total seconds, ", t2 - t1, time_Cleanup) ; #endif return(1) ; } /*--------------------------------------------------------------------*/ Eigen/srcMT/FactorMT.c010064400020550007177000000135220663356117700160140ustar00clevecompmath00000400000006/* FactorMT.c */ #include "../BridgeMT.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Factor = 0 ; static double time_Factor = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to compute the factorization of A - sigma * B note: all variables in the calling sequence are references to allow call from fortran. input parameters data -- pointer to bridge data object psigma -- shift for the matrix pencil ppvttol -- pivot tolerance *ppvttol = 0.0 --> no pivoting used *ppvttol != 0.0 --> pivoting used, entries in factor are bounded above by 1/pvttol in magnitude output parameters *pinertia -- on return contains the number of negative eigenvalues *perror -- on return contains an error code 1 -- error found during factorization 0 -- normal return -1 -- psigma is NULL -2 -- ppvttol is NULL -3 -- data is NULL -4 -- pinertia is NULL created -- 98aug10, cca & jcp --------------------------------------------------------------------- */ void FactorMT ( double *psigma, double *ppvttol, void *data, int *pinertia, int *perror ) { BridgeMT *bridge = (BridgeMT *) data ; Chv *rootchv ; ChvManager *chvmanager ; double droptol=0.0, tau ; double cpus[10] ; int stats[20] ; int nnegative, nzero, npositive, pivotingflag ; int nproc ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_Factor++ ; fprintf(stdout, "\n (%d) FactorMT()", count_Factor) ; fflush(stdout) ; #endif /* --------------- check the input --------------- */ if ( psigma == NULL ) { fprintf(stderr, "\n error in FactorMT()" "\n psigma is NULL\n") ; *perror = -1 ; return ; } if ( ppvttol == NULL ) { fprintf(stderr, "\n error in FactorMT()" "\n ppvttol is NULL\n") ; *perror = -2 ; return ; } if ( data == NULL ) { fprintf(stderr, "\n error in FactorMT()" "\n data is NULL\n") ; *perror = -3 ; return ; } if ( pinertia == NULL ) { fprintf(stderr, "\n error in FactorMT()" "\n pinertia is NULL\n") ; *perror = -4 ; return ; } if ( perror == NULL ) { fprintf(stderr, "\n error in FactorMT()" "\n perror is NULL\n") ; return ; } nproc = bridge->nthread ; /* ---------------------------------- set the shift in the pencil object ---------------------------------- */ bridge->pencil->sigma[0] = -(*psigma) ; bridge->pencil->sigma[1] = 0.0 ; /* ---------------------------------------------------------------- clear the front matrix, submatrix mananger and solve map objects ---------------------------------------------------------------- */ FrontMtx_clearData(bridge->frontmtx); SubMtxManager_clearData(bridge->mtxmanager); SolveMap_clearData(bridge->solvemap) ; /* ----------------------------------------------------------- set the pivot tolerance. NOTE: spooles's "tau" parameter is a bound on the magnitude of the factor entries, and is the recipricol of that of the pivot tolerance of the lanczos code ----------------------------------------------------------- */ if ( *ppvttol == 0.0 ) { tau = 10.0 ; pivotingflag = SPOOLES_NO_PIVOTING ; } else { tau = (1.0)/(*ppvttol) ; pivotingflag = SPOOLES_PIVOTING ; } /* ---------------------------------- initialize the front matrix object ---------------------------------- */ FrontMtx_init(bridge->frontmtx, bridge->frontETree, bridge->symbfacIVL, SPOOLES_REAL, SPOOLES_SYMMETRIC, FRONTMTX_DENSE_FRONTS, pivotingflag, LOCK_IN_PROCESS, 0, NULL, bridge->mtxmanager, bridge->msglvl, bridge->msgFile) ; /* ------------------------- compute the factorization ------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, LOCK_IN_PROCESS, 1); IVfill(20, stats, 0) ; DVfill(10, cpus, 0.0) ; rootchv = FrontMtx_MT_factorPencil(bridge->frontmtx, bridge->pencil, tau, droptol, chvmanager, bridge->ownersIV, 0, perror, cpus, stats, bridge->msglvl, bridge->msgFile) ; ChvManager_free(chvmanager); /* ---------------------------- if matrix is singular then set error flag and return ---------------------------- */ if ( rootchv != NULL ) { *perror = 1 ; return ; } /* ------------------------------------------------------------------ post-process the factor matrix, convert from fronts to submatrices ------------------------------------------------------------------ */ FrontMtx_postProcess(bridge->frontmtx, bridge->msglvl, bridge->msgFile); /* ------------------- compute the inertia ------------------- */ FrontMtx_inertia(bridge->frontmtx, &nnegative, &nzero, &npositive) ; *pinertia = nnegative; /* -------------------------- set up the SolveMap object -------------------------- */ SolveMap_ddMap(bridge->solvemap, SPOOLES_SYMMETRIC, FrontMtx_upperBlockIVL(bridge->frontmtx), FrontMtx_lowerBlockIVL(bridge->frontmtx), nproc, bridge->ownersIV, FrontMtx_frontTree(bridge->frontmtx), bridge->seed, bridge->msglvl, bridge->msgFile ) ; /* ------------------------------------------------------------------ set the error. (this is simple since when the spooles codes detect a fatal error, they print out a message to stderr and exit.) ------------------------------------------------------------------ */ *perror = 0 ; #if MYDEBUG > 0 MARKTIME(t2) ; time_Factor += t2 - t1 ; fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Factor) ; fflush(stdout) ; #endif return; } /*--------------------------------------------------------------------*/ s the number of negative eigenvalues *perror -- on return contains an error code 1 -- error found during factorization 0 -- normal return Eigen/srcMT/MatMulMT.c010064400020550007177000000072210663356125500157710ustar00clevecompmath00000400000006/* MatMulMT.c */ #include "../BridgeMT.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_MatMul = 0 ; static double time_MatMul = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose --- to compute a matrix-vector multiply y[] = C * x[] where C is the identity, A or B (depending on *pprbtype). *pprbtype -- problem type *pprbtype = 1 --> vibration problem, matrix is A *pprbtype = 2 --> buckling problem, matrix is B *pprbtype = 3 --> matrix is identity, y[] = x[] *pnrows -- # of rows in x[] *pncols -- # of columns in x[] created -- 98aug11, cca & jcp ------------------------------------------------------------- */ void MatMulMT ( int *pnrows, int *pncols, double x[], double y[], int *pprbtype, void *data ) { int ncols, nent, nrows ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_MatMul++ ; fprintf(stdout, "\n (%d) MatMulMT()", count_MatMul) ; fflush(stdout) ; #endif nrows = *pnrows ; ncols = *pncols ; nent = nrows*ncols ; if ( *pprbtype == 3 ) { /* -------------------------- ... matrix is the identity -------------------------- */ DVcopy(nent, y, x) ; return; } else { BridgeMT *bridge = (BridgeMT *) data ; DenseMtx *X, *Y ; double alpha[2] = {1.0, 0.0} ; int nthread = bridge->nthread ; /* --------------------------------- setup x and y as DenseMtx objects --------------------------------- */ if ( bridge->msglvl > 2 ) { fprintf(bridge->msgFile, "\n inside MatMulMT, nrows = %d, ncols = %d", nrows, ncols) ; fprintf(bridge->msgFile, "\n x[]") ; DVfprintf(bridge->msgFile, nent, x) ; fflush(bridge->msgFile) ; } X = bridge->X ; DenseMtx_init(X, SPOOLES_REAL, 0, 0, nrows, ncols, 1, nrows); DVcopy(nent, DenseMtx_entries(X), x); if ( bridge->msglvl > 2 ) { fprintf(bridge->msgFile, "\n inside MatMulMT, X") ; DenseMtx_writeForHumanEye(X, bridge->msgFile) ; fflush(bridge->msgFile) ; } Y = bridge->Y ; DenseMtx_init(Y, SPOOLES_REAL, 0, 0, nrows, ncols, 1, nrows); DenseMtx_zero(Y); if ( *pprbtype == 1 ) { if ( bridge->msglvl > 2 ) { fprintf(bridge->msgFile, "\n\n vibration problem") ; fflush(bridge->msgFile) ; } /* --------------------------------------- ... vibration case matrix is 'm' or 'b' --------------------------------------- */ InpMtx_MT_sym_mmm(bridge->B, Y, alpha, X, nthread, bridge->msglvl, bridge->msgFile); } else { if ( bridge->msglvl > 2 ) { fprintf(bridge->msgFile, "\n\n buckling problem") ; fflush(bridge->msgFile) ; } /* -------------------------------------- ... buckling case matrix is 'k' or 'a' -------------------------------------- */ InpMtx_MT_sym_mmm(bridge->A, Y, alpha, X, nthread, bridge->msglvl, bridge->msgFile); } if ( bridge->msglvl > 2 ) { fprintf(bridge->msgFile, "\n inside MatMulMT, Y") ; DenseMtx_writeForHumanEye(Y, bridge->msgFile) ; fflush(bridge->msgFile) ; } /* -------------------------------- copy solution into output vector -------------------------------- */ DVcopy (nent, y, DenseMtx_entries(Y) ); } #if MYDEBUG > 0 MARKTIME(t2) ; MARKTIME(t2) ; time_MatMul += t2 - t1 ; fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_MatMul) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ Eigen/srcMT/SetupMT.c010064400020550007177000000252570663676211200157010ustar00clevecompmath00000400000006/* SetupMT.c */ #include "../BridgeMT.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Setup = 0 ; static double time_Setup = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- given InpMtx objects that contain A and B, initialize the bridge data structure for the multithreaded factor's, solve's and mvm's. data -- pointer to a Bridge object pprbtype -- pointer to value containing problem type *prbtype = 1 --> A X = B X Lambda, vibration problem *prbtype = 2 --> A X = B X Lambda, buckling problem *prbtype = 3 --> A X = X Lambda, simple eigenvalue problem pneqns -- pointer to value containing number of equations pmxbsz -- pointer to value containing blocksize A -- pointer to InpMtx object containing A B -- pointer to InpMtx object containing B pseed -- pointer to value containing a random number seed pmsglvl -- pointer to value containing a message level msgFile -- message file pointer pnthread -- pointer to value containing # of threads return value -- 1 -- normal return -1 -- data is NULL -2 -- pprbtype is NULL -3 -- *pprbtype is invalid -4 -- pneqns is NULL -5 -- *pneqns is invalid -6 -- pmxbsz is NULL -7 -- *pmxbsz is invalid -8 -- A and B are NULL -9 -- pseed is NULL -10 -- pmsglvl is NULL -11 -- *pmsglvl > 0 and msgFile is NULL -12 -- pnthreads is NULL -13 -- *pnthreads is invalid created -- 98aug10, cca ------------------------------------------------------------------ */ int SetupMT ( void *data, int *pprbtype, int *pneqns, int *pmxbsz, InpMtx *A, InpMtx *B, int *pseed, int *pnthread, int *pmsglvl, FILE *msgFile ) { BridgeMT *bridge = (BridgeMT *) data ; double sigma[2] ; DV *cumopsDV ; Graph *graph ; int maxdomainsize, maxsize, maxzeros, msglvl, mxbsz, nedges, neqns, nthread, prbtype, seed ; IVL *adjIVL ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_Setup++ ; fprintf(stdout, "\n (%d) SetupMT()", count_Setup) ; fflush(stdout) ; #endif /* -------------------- check the input data -------------------- */ if ( data == NULL ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n data is NULL\n") ; return(-1) ; } if ( pprbtype == NULL ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n pprbtype is NULL\n") ; return(-2) ; } prbtype = *pprbtype ; if ( prbtype < 1 || prbtype > 3 ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n prbtype = %d, is invalid\n", prbtype) ; return(-3) ; } if ( pneqns == NULL ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n pneqns is NULL\n") ; return(-4) ; } neqns = *pneqns ; if ( neqns <= 0 ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n neqns = %d, is invalid\n", neqns) ; return(-5) ; } if ( pmxbsz == NULL ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n pmxbsz is NULL\n") ; return(-6) ; } mxbsz = *pmxbsz ; if ( mxbsz <= 0 ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n *pmxbsz = %d, is invalid\n", mxbsz) ; return(-7) ; } if ( A == NULL && B == NULL ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n A and B are NULL\n") ; return(-8) ; } if ( pseed == NULL ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n pseed is NULL\n") ; return(-9) ; } seed = *pseed ; if ( pmsglvl == NULL ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n pmsglvl is NULL\n") ; return(-10) ; } msglvl = *pmsglvl ; if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n msglvl = %d, msgFile = NULL\n", msglvl) ; return(-11) ; } if ( pnthread == NULL ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n pnthread is NULL\n") ; return(-12) ; } nthread = *pnthread ; if ( nthread <= 0 ) { fprintf(stderr, "\n fatal error in SetupMT()" "\n nthread = %d, is invalid\n", nthread) ; return(-13) ; } bridge->msglvl = *pmsglvl ; /* bridge->msglvl = 2 ; */ bridge->msgFile = msgFile ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside SetupMT()" "\n neqns = %d, prbtype = %d, mxbsz = %d, seed = %d, nthread = %d", neqns, prbtype, mxbsz, seed, nthread) ; if ( A != NULL ) { fprintf(msgFile, "\n\n matrix A") ; InpMtx_writeForHumanEye(A, msgFile) ; } if ( B != NULL ) { fprintf(msgFile, "\n\n matrix B") ; InpMtx_writeForHumanEye(B, msgFile) ; } fflush(msgFile) ; } bridge->prbtype = prbtype ; bridge->neqns = neqns ; bridge->mxbsz = mxbsz ; bridge->A = A ; bridge->B = B ; bridge->seed = seed ; bridge->nthread = nthread ; /* ---------------------------- create and initialize pencil ---------------------------- */ sigma[0] = 1.0; sigma[1] = 0.0; bridge->pencil = Pencil_new() ; Pencil_setDefaultFields(bridge->pencil) ; Pencil_init(bridge->pencil, SPOOLES_REAL, SPOOLES_SYMMETRIC, A, sigma, B) ; /* -------------------------------- convert to row or column vectors -------------------------------- */ if ( A != NULL ) { if ( ! INPMTX_IS_BY_ROWS(A) && ! INPMTX_IS_BY_COLUMNS(A) ) { InpMtx_changeCoordType(A, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(A) ) { InpMtx_changeStorageMode(A, INPMTX_BY_VECTORS) ; } } if ( B != NULL ) { if ( ! INPMTX_IS_BY_ROWS(B) && ! INPMTX_IS_BY_COLUMNS(B) ) { InpMtx_changeCoordType(B, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(B) ) { InpMtx_changeStorageMode(B, INPMTX_BY_VECTORS) ; } } /* ------------------------------- create a Graph object for A + B ------------------------------- */ graph = Graph_new() ; adjIVL = Pencil_fullAdjacency(bridge->pencil); nedges = IVL_tsize(adjIVL), Graph_init2(graph, 0, bridge->neqns, 0, nedges, bridge->neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* --------------- order the graph --------------- */ maxdomainsize = neqns / 64 ; if ( maxdomainsize == 0 ) { maxdomainsize = 1 ; } maxzeros = (int) (0.01*neqns) ; maxsize = 64 ; bridge->frontETree = orderViaBestOfNDandMS(graph, maxdomainsize, maxzeros, maxsize, bridge->seed, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(bridge->frontETree, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------------- get the old-to-new and new-to-old permutations ---------------------------------------------- */ bridge->oldToNewIV = ETree_oldToNewVtxPerm(bridge->frontETree) ; bridge->newToOldIV = ETree_newToOldVtxPerm(bridge->frontETree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n old-to-new permutation") ; IV_writeForHumanEye(bridge->oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation") ; IV_writeForHumanEye(bridge->newToOldIV, msgFile) ; fflush(msgFile) ; } /* -------------------------------------- permute the vertices in the front tree -------------------------------------- */ ETree_permuteVertices(bridge->frontETree, bridge->oldToNewIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted front etree") ; ETree_writeForHumanEye(bridge->frontETree, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------- permute the entries in the pencil. note, after the permutation the entries are mapped into the upper triangle. ------------------------------------------- */ Pencil_permute(bridge->pencil, bridge->oldToNewIV, bridge->oldToNewIV) ; Pencil_mapToUpperTriangle(bridge->pencil) ; Pencil_changeCoordType(bridge->pencil, INPMTX_BY_CHEVRONS) ; Pencil_changeStorageMode(bridge->pencil, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted pencil") ; Pencil_writeForHumanEye(bridge->pencil, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- compute the symbolic factorization ---------------------------------- */ bridge->symbfacIVL = SymbFac_initFromPencil(bridge->frontETree, bridge->pencil) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(bridge->symbfacIVL, msgFile) ; fflush(msgFile) ; } /* -------------------------------------------------- create a FrontMtx object to hold the factorization -------------------------------------------------- */ bridge->frontmtx = FrontMtx_new() ; /* ------------------------------------------------------------ create a SubMtxManager object to hold the factor submatrices ------------------------------------------------------------ */ bridge->mtxmanager = SubMtxManager_new() ; SubMtxManager_init(bridge->mtxmanager, LOCK_IN_PROCESS, 0) ; /* ------------------------------------------------------------ allocate the working objects X and Y for the matrix multiply ------------------------------------------------------------ */ bridge->X = DenseMtx_new() ; DenseMtx_init(bridge->X, SPOOLES_REAL, 0, 0, neqns, mxbsz, 1, neqns) ; bridge->Y = DenseMtx_new() ; DenseMtx_init(bridge->Y, SPOOLES_REAL, 0, 0, neqns, mxbsz, 1, neqns) ; /* -------------------------------------------------------- setup up ownersIV, the map from fronts to owning threads -------------------------------------------------------- */ cumopsDV = DV_new() ; DV_init(cumopsDV, bridge->nthread, NULL ); bridge->ownersIV = ETree_ddMap(bridge->frontETree, SPOOLES_REAL, SPOOLES_SYMMETRIC, cumopsDV, 1./(2.*bridge->nthread) ); if ( msglvl >= 0 ) { fprintf(msgFile, "\n\n load balance for the processors") ; DV_writeForHumanEye(cumopsDV, msgFile) ; fprintf(msgFile, "\n\n map from fronts to threads") ; IV_writeForHumanEye(bridge->ownersIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------------------- create a SolveMap object, the map from submatries to owning threads ------------------------------------------------------------------- */ bridge->solvemap = SolveMap_new() ; /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; DV_free(cumopsDV); #if MYDEBUG > 0 MARKTIME(t2) ; time_Setup += t2 - t1 ; fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Setup) ; fflush(stdout) ; #endif return(1) ; } /*--------------------------------------------------------------------*/ Eigen/srcMT/SolveMT.c010064400020550007177000000071110663356140500156550ustar00clevecompmath00000400000006/* SolveMT.c */ #include "../BridgeMT.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Solve = 0 ; static double time_Solve = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to solve a linear system (A - sigma*B) sol[] = rhs[] data -- pointer to bridge data object *pnrows -- # of rows in x[] and y[] *pncols -- # of columns in x[] and y[] rhs[] -- vector that holds right hand sides sol[] -- vector to hold solutions note: rhs[] and sol[] can be the same array. on return, *perror holds an error code. 1 -- normal return -1 -- pnrows is NULL -2 -- pncols is NULL -3 -- rhs is NULL -4 -- sol is NULL -5 -- data is NULL created -- 98aug10, cca & jcp ---------------------------------------------- */ void SolveMT ( int *pnrows, int *pncols, double rhs[], double sol[], void *data, int *perror ) { BridgeMT *bridge = (BridgeMT *) data ; DenseMtx *rhsmtx, *solmtx ; double cpus[10] ; int nent, ncols, nrows ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_Solve++ ; fprintf(stdout, "\n (%d) SolveMT()", count_Solve) ; fflush(stdout) ; #endif /* --------------- check the input --------------- */ if ( perror == NULL ) { fprintf(stderr, "\n error in Solve()" "\n perror == NULL\n") ; return ; } if ( pnrows == NULL ) { fprintf(stderr, "\n error in Solve()" "\n pnrows == NULL\n") ; *perror = -1 ; return ; } if ( pncols == NULL ) { fprintf(stderr, "\n error in Solve()" "\n pncols == NULL\n") ; *perror = -2 ; return ; } if ( rhs == NULL ) { fprintf(stderr, "\n error in Solve()" "\n rhs == NULL\n") ; *perror = -3 ; return ; } if ( sol == NULL ) { fprintf(stderr, "\n error in Solve()" "\n sol == NULL\n") ; *perror = -4 ; return ; } if ( data == NULL ) { fprintf(stderr, "\n error in Solve()" "\n data == NULL\n") ; *perror = -5 ; return ; } /* ---------------------------------- set the number of rows and columns ---------------------------------- */ nrows = *pnrows ; ncols = *pncols ; nent = nrows*ncols ; /* ------------------------------------------- setup rhsmtx and solmtx as DenseMtx objects ------------------------------------------ */ rhsmtx = bridge->Y ; DenseMtx_init(rhsmtx, SPOOLES_REAL, 0, 0, nrows, ncols, 1, nrows) ; DVcopy (nent, DenseMtx_entries(rhsmtx), rhs) ; solmtx = bridge->X ; DenseMtx_init(solmtx, SPOOLES_REAL, 0, 0, nrows, ncols, 1, nrows) ; DenseMtx_zero(solmtx) ; /* ----------------------- solve the linear system ----------------------- */ DVzero(10, cpus) ; FrontMtx_MT_solve(bridge->frontmtx, solmtx, rhsmtx, bridge->mtxmanager, bridge->solvemap, cpus, bridge->msglvl, bridge->msgFile) ; /* ----------------------------------- copy solution into output parameter ----------------------------------- */ DVcopy(nent, sol, DenseMtx_entries(solmtx)) ; /* ------------------------------------------------------------------ set the error. (this is simple since when the spooles codes detect a fatal error, they print out a message to stderr and exit.) ------------------------------------------------------------------ */ *perror = 0 ; #if MYDEBUG > 0 MARKTIME(t2) ; time_Solve += t2 - t1 ; fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Solve) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ smtx, *solmtx ; double cpus[10] ; int nent, ncols, nrows ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_Solve++ ; fprintf(stdout, "\n (%d) SolveMT()", count_Solve) ; fflush(stdout) ; #endif /* --------------- check the input --------------- */ if ( perror == NULL ) { fprintf(stderr, "\n error in Solve()" "\n perror == NULL\n") ; return ; } if ( pnrows == NULL ) { fprintf(stderr, "\n errEigen/srcMPI/makefile010064400020550007177000000012040663677213600157720ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- # # set suffix rule *.c --> *.a # .c.a : $(PURIFY) $(CC) -c $(CFLAGS) $(MPI_INCLUDE_DIR) $*.c -o $*.o $(AR) $(ARFLAGS) $(OBJ).a $*.o rm $*.o #----------------------------------------------------------------------- OBJ = BridgeMPI $(OBJ).a : \ $(OBJ).a(JimMatMulMPI.o) \ $(OBJ).a(JimSolveMPI.o) \ $(OBJ).a(CleanupMPI.o) \ $(OBJ).a(FactorMPI.o) \ $(OBJ).a(MatMulMPI.o) \ $(OBJ).a(SetupMPI.o) \ $(OBJ).a(SolveMPI.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o Eigen/srcMPI/CleanupMPI.c010064400020550007177000000036000663672755700164040ustar00clevecompmath00000400000006/* CleanupMPI.c */ #include "../BridgeMPI.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Cleanup = 0 ; static double time_Cleanup = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to free the owned data structures return values -- 1 -- normal return -1 -- data is NULL created -- 98aug10, cca -------------------------------------------- */ int CleanupMPI ( void *data ) { BridgeMPI *bridge = (BridgeMPI *) data ; #if MYDEBUG > 0 double t1, t2 ; MARKTIME(t1) ; count_Cleanup++ ; if ( bridge->myid == 0 ) { fprintf(stdout, "\n (%d) CleanupMPI()", count_Cleanup) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, "\n (%d) CleanupMPI()", count_Cleanup) ; fflush(bridge->msgFile) ; #endif bridge->pencil->inpmtxA = NULL ; bridge->pencil->inpmtxB = NULL ; Pencil_free(bridge->pencil) ; IVL_free(bridge->symbfacIVL) ; FrontMtx_free(bridge->frontmtx) ; ETree_free(bridge->frontETree) ; SubMtxManager_free(bridge->mtxmanager) ; IV_free(bridge->oldToNewIV) ; IV_free(bridge->newToOldIV) ; IV_free(bridge->vtxmapIV) ; IV_free(bridge->ownersIV) ; IV_free(bridge->myownedIV) ; if ( bridge->rowmapIV != NULL ) { IV_free(bridge->rowmapIV) ; } if ( bridge->info != NULL ) { MatMul_cleanup(bridge->info) ; DenseMtx_free(bridge->Xloc) ; DenseMtx_free(bridge->Yloc) ; } SolveMap_free(bridge->solvemap) ; #if MYDEBUG > 0 MARKTIME(t2) ; time_Cleanup += t2 - t1 ; if ( bridge->myid == 0 ) { fprintf(stdout, ", %8.3f seconds, %8.3f total seconds, ", t2 - t1, time_Cleanup) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, ", %8.3f seconds, %8.3f total seconds, ", t2 - t1, time_Cleanup) ; fflush(bridge->msgFile) ; #endif return(1) ; } /*--------------------------------------------------------------------*/ Eigen/srcMPI/FactorMPI.c010064400020550007177000000224750663677145500162420ustar00clevecompmath00000400000006/* FactorMPI.c */ #include "../BridgeMPI.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Factor = 0 ; static double time_Factor = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to compute the factorization of A - sigma * B note: all variables in the calling sequence are references to allow call from fortran. input parameters data -- pointer to bridge data object psigma -- shift for the matrix pencil ppvttol -- pivot tolerance *ppvttol = 0.0 --> no pivoting used *ppvttol != 0.0 --> pivoting used, entries in factor are bounded above by 1/pvttol in magnitude output parameters *pinertia -- on return contains the number of negative eigenvalues *perror -- on return contains an error code 1 -- error found during factorization 0 -- normal return -1 -- psigma is NULL -2 -- ppvttol is NULL -3 -- data is NULL -4 -- pinertia is NULL created -- 98aug10, cca & jcp --------------------------------------------------------------------- */ void FactorMPI ( double *psigma, double *ppvttol, void *data, int *pinertia, int *perror ) { BridgeMPI *bridge = (BridgeMPI *) data ; Chv *rootchv ; ChvManager *chvmanager ; double droptol=0.0, tau ; double cpus[20] ; FILE *msgFile ; int recvtemp[3], sendtemp[3], stats[20] ; int msglvl, nnegative, nzero, npositive, pivotingflag, tag ; MPI_Comm comm ; int nproc ; #if MYDEBUG > 0 double t1, t2 ; count_Factor++ ; MARKTIME(t1) ; if ( bridge->myid == 0 ) { fprintf(stdout, "\n (%d) FactorMPI()", count_Factor) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, "\n (%d) FactorMPI()", count_Factor) ; fflush(bridge->msgFile) ; #endif nproc = bridge->nproc ; /* --------------- check the input --------------- */ if ( psigma == NULL ) { fprintf(stderr, "\n error in FactorMPI()" "\n psigma is NULL\n") ; *perror = -1 ; return ; } if ( ppvttol == NULL ) { fprintf(stderr, "\n error in FactorMPI()" "\n ppvttol is NULL\n") ; *perror = -2 ; return ; } if ( data == NULL ) { fprintf(stderr, "\n error in FactorMPI()" "\n data is NULL\n") ; *perror = -3 ; return ; } if ( pinertia == NULL ) { fprintf(stderr, "\n error in FactorMPI()" "\n pinertia is NULL\n") ; *perror = -4 ; return ; } if ( perror == NULL ) { fprintf(stderr, "\n error in FactorMPI()" "\n perror is NULL\n") ; return ; } comm = bridge->comm ; msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; /* ---------------------------------- set the shift in the pencil object ---------------------------------- */ bridge->pencil->sigma[0] = -(*psigma) ; bridge->pencil->sigma[1] = 0.0 ; /* ----------------------------------------- if the matrices are in local coordinates (i.e., this is the first factorization following a matrix-vector multiply) then map the matrix into global coordinates ----------------------------------------- */ if ( bridge->coordFlag == LOCAL ) { if ( bridge->prbtype == 1 ) { MatMul_setGlobalIndices(bridge->info, bridge->B) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n matrix B in local coordinates") ; InpMtx_writeForHumanEye(bridge->B, msgFile) ; fflush(msgFile) ; } } if ( bridge->prbtype == 2 ) { MatMul_setGlobalIndices(bridge->info, bridge->A) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n matrix A in local coordinates") ; InpMtx_writeForHumanEye(bridge->A, msgFile) ; fflush(msgFile) ; } } bridge->coordFlag = GLOBAL ; } /* ----------------------------------------------------- clear the front matrix and submatrix mananger objects ----------------------------------------------------- */ FrontMtx_clearData(bridge->frontmtx); SubMtxManager_clearData(bridge->mtxmanager); SolveMap_clearData(bridge->solvemap) ; if ( bridge->rowmapIV != NULL ) { IV_free(bridge->rowmapIV) ; bridge->rowmapIV = NULL ; } /* ----------------------------------------------------------- set the pivot tolerance. NOTE: spooles's "tau" parameter is a bound on the magnitude of the factor entries, and is the recipricol of that of the pivot tolerance of the lanczos code ----------------------------------------------------------- */ if ( *ppvttol == 0.0 ) { tau = 10.0 ; pivotingflag = SPOOLES_NO_PIVOTING ; } else { tau = (1.0)/(*ppvttol) ; pivotingflag = SPOOLES_PIVOTING ; } /* ---------------------------------- initialize the front matrix object ---------------------------------- */ FrontMtx_init(bridge->frontmtx, bridge->frontETree, bridge->symbfacIVL, SPOOLES_REAL, SPOOLES_SYMMETRIC, FRONTMTX_DENSE_FRONTS, pivotingflag, NO_LOCK, bridge->myid, bridge->ownersIV, bridge->mtxmanager, bridge->msglvl, bridge->msgFile) ; /* ------------------------- compute the factorization ------------------------- */ tag = 0 ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 0); IVfill(20, stats, 0) ; DVfill(20, cpus, 0.0) ; rootchv = FrontMtx_MPI_factorPencil(bridge->frontmtx, bridge->pencil, tau, droptol, chvmanager, bridge->ownersIV, 0, perror, cpus, stats, bridge->msglvl, bridge->msgFile, tag, comm) ; ChvManager_free(chvmanager); tag += 3*FrontMtx_nfront(bridge->frontmtx) + 2 ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n numeric factorization") ; FrontMtx_writeForHumanEye(bridge->frontmtx, bridge->msgFile) ; fflush(bridge->msgFile) ; } /* ---------------------------- if matrix is singular then set error flag and return ---------------------------- */ if ( rootchv != NULL ) { fprintf(msgFile, "\n WHOA NELLY!, matrix is singular") ; fflush(msgFile) ; *perror = 1 ; return ; } /* ------------------------------------------------------------------ post-process the factor matrix, convert from fronts to submatrices ------------------------------------------------------------------ */ FrontMtx_MPI_postProcess(bridge->frontmtx, bridge->ownersIV, stats, bridge->msglvl, bridge->msgFile, tag, comm); tag += 5*bridge->nproc ; /* ------------------- compute the inertia ------------------- */ FrontMtx_inertia(bridge->frontmtx, &nnegative, &nzero, &npositive) ; sendtemp[0] = nnegative ; sendtemp[1] = nzero ; sendtemp[2] = npositive ; if ( bridge->msglvl > 2 && bridge->msgFile != NULL ) { fprintf(bridge->msgFile, "\n local inertia = < %d, %d, %d >", nnegative, nzero, npositive) ; fflush(bridge->msgFile) ; } MPI_Allreduce((void *) sendtemp, (void *) recvtemp, 3, MPI_INT, MPI_SUM, comm) ; nnegative = recvtemp[0] ; nzero = recvtemp[1] ; npositive = recvtemp[2] ; if ( bridge->msglvl > 2 && bridge->msgFile != NULL ) { fprintf(bridge->msgFile, "\n global inertia = < %d, %d, %d >", nnegative, nzero, npositive) ; fflush(bridge->msgFile) ; } *pinertia = nnegative; /* --------------------------- create the solve map object --------------------------- */ SolveMap_ddMap(bridge->solvemap, SPOOLES_REAL, FrontMtx_upperBlockIVL(bridge->frontmtx), FrontMtx_lowerBlockIVL(bridge->frontmtx), nproc, bridge->ownersIV, FrontMtx_frontTree(bridge->frontmtx), bridge->seed, bridge->msglvl, bridge->msgFile) ; /* ------------------------------- redistribute the front matrices ------------------------------- */ FrontMtx_MPI_split(bridge->frontmtx, bridge->solvemap, stats, bridge->msglvl, bridge->msgFile, tag, comm) ; if ( *ppvttol != 0.0 ) { /* ------------------------------------------------------------- pivoting for stability may have taken place. create rowmapIV, the map from rows in the factorization to processes. ------------------------------------------------------------- */ bridge->rowmapIV = FrontMtx_MPI_rowmapIV(bridge->frontmtx, bridge->ownersIV, bridge->msglvl, bridge->msgFile, bridge->comm) ; if ( bridge->msglvl > 2 && bridge->msgFile != NULL ) { fprintf(bridge->msgFile, "\n\n bridge->rowmapIV") ; IV_writeForHumanEye(bridge->rowmapIV, bridge->msgFile) ; fflush(bridge->msgFile) ; } } else { bridge->rowmapIV = NULL ; } /* ------------------------------------------------------------------ set the error. (this is simple since when the spooles codes detect a fatal error, they print out a message to stderr and exit.) ------------------------------------------------------------------ */ *perror = 0 ; #if MYDEBUG > 0 MARKTIME(t2) ; time_Factor += t2 - t1 ; if ( bridge->myid == 0 ) { fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Factor) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Factor) ; fflush(bridge->msgFile) ; #endif return; } /*--------------------------------------------------------------------*/ Eigen/srcMPI/JimMatMulMPI.c010064400020550007177000000125070663677207700166570ustar00clevecompmath00000400000006/* JimMatMulMPI.c */ #include "../BridgeMPI.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_JimMatMul = 0 ; static double time_JimMatMul = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose --- to compute a matrix-vector multiply y[] = C * x[] where C is the identity, A or B (depending on *pprbtype). *pnrows -- # of rows in x[] *pncols -- # of columns in x[] *pprbtype -- problem type *pprbtype = 1 --> vibration problem, matrix is A *pprbtype = 2 --> buckling problem, matrix is B *pprbtype = 3 --> matrix is identity, y[] = x[] x[] -- vector to be multiplied NOTE: the x[] vector is global, not a portion y[] -- product vector NOTE: the y[] vector is global, not a portion created -- 98aug28, cca & jcp ------------------------------------------------------------- */ void JimMatMulMPI ( int *pnrows, int *pncols, double x[], double y[], int *pprbtype, void *data ) { BridgeMPI *bridge = (BridgeMPI *) data ; int ncols, nent, nrows ; #if MYDEBUG > 0 double t1, t2 ; count_JimMatMul++ ; MARKTIME(t1) ; if ( bridge->myid == 0 ) { fprintf(stdout, "\n (%d) JimMatMulMPI() start", count_JimMatMul) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, "\n (%d) JimMatMulMPI() start", count_JimMatMul) ; fflush(bridge->msgFile) ; #endif nrows = *pnrows ; ncols = *pncols ; nent = nrows*ncols ; if ( *pprbtype == 3 ) { /* -------------------------- ... matrix is the identity -------------------------- */ DVcopy(nent, y, x) ; } else { BridgeMPI *bridge = (BridgeMPI *) data ; DenseMtx *mtx, *newmtx ; int irow, jcol, jj, kk, myid, neqns, nowned, tag = 0 ; int *vtxmap ; int stats[4] ; IV *mapIV ; /* --------------------------------------------- slide the owned rows of x[] down in the array --------------------------------------------- */ vtxmap = IV_entries(bridge->vtxmapIV) ; neqns = bridge->neqns ; myid = bridge->myid ; nowned = IV_size(bridge->myownedIV) ; for ( jcol = jj = kk = 0 ; jcol < ncols ; jcol++ ) { for ( irow = 0 ; irow < neqns ; irow++, jj++ ) { if ( vtxmap[irow] == myid ) { y[kk++] = x[jj] ; } } } if ( kk != nowned * ncols ) { fprintf(stderr, "\n proc %d : kk %d, nowned %d, ncols %d", myid, kk, nowned, ncols) ; exit(-1) ; } /* ---------------------------------------- call the method that assumes local input ---------------------------------------- */ if ( bridge->msglvl > 2 ) { fprintf(bridge->msgFile, "\n inside JimMatMulMPI, calling MatMulMpi" "\n prbtype %d, nrows %d, ncols %d, nowned %d", *pprbtype, *pnrows, *pncols, nowned) ; fflush(bridge->msgFile) ; } MatMulMPI(&nowned, pncols, y, y, pprbtype, data) ; /* ------------------------------------------------- gather all the entries of y[] onto processor zero ------------------------------------------------- */ mtx = DenseMtx_new() ; DenseMtx_init(mtx, SPOOLES_REAL, 0, 0, nowned, ncols, 1, nowned) ; DVcopy (nowned*ncols, DenseMtx_entries(mtx), y) ; IVcopy(nowned, mtx->rowind, IV_entries(bridge->myownedIV)) ; mapIV = IV_new() ; IV_init(mapIV, neqns, NULL) ; IV_fill(mapIV, 0) ; IVfill(4, stats, 0) ; if ( bridge->msglvl > 2 ) { fprintf(bridge->msgFile, "\n mtx: %d rows x %d columns", mtx->nrow, mtx->ncol) ; fflush(bridge->msgFile) ; } newmtx = DenseMtx_MPI_splitByRows(mtx, mapIV, stats, bridge->msglvl, bridge->msgFile, tag, bridge->comm) ; if ( bridge->msglvl > 2 ) { fprintf(bridge->msgFile, "\n newmtx: %d rows x %d columns", newmtx->nrow, newmtx->ncol) ; fflush(bridge->msgFile) ; } DenseMtx_free(mtx) ; mtx = newmtx ; IV_free(mapIV) ; if ( myid == 0 ) { if ( mtx->nrow != neqns || mtx->ncol != ncols ) { fprintf(bridge->msgFile, "\n\n WHOA: mtx->nrows %d, mtx->ncols %d" ", neqns %d, ncols %d", mtx->nrow, mtx->ncol, neqns, ncols) ; exit(-1) ; } DVcopy(neqns*ncols, y, DenseMtx_entries(mtx)) ; } DenseMtx_free(mtx) ; /* --------------------------------------------- broadcast the entries to the other processors --------------------------------------------- */ MPI_Bcast((void *) y, neqns*ncols, MPI_DOUBLE, 0, bridge->comm) ; if ( bridge->msglvl > 2 ) { fprintf(bridge->msgFile, "\n after the broadcast") ; fflush(bridge->msgFile) ; } } MPI_Barrier(bridge->comm) ; #if MYDEBUG > 0 MARKTIME(t2) ; time_JimMatMul += t2 - t1 ; if ( bridge->myid == 0 ) { fprintf(stdout, "\n (%d) JimMatMulMPI() end", count_JimMatMul) ; fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_JimMatMul) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, "\n (%d) JimMatMulMPI() end", count_JimMatMul) ; fprintf(bridge->msgFile, ", %8.3f seconds, %8.3f total time", t2 - t1, time_JimMatMul) ; fflush(bridge->msgFile) ; #endif return ; } /*--------------------------------------------------------------------*/ out) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, "\n (%d) JimMatMulMPI() start", count_JimMatMul) ; fflush(bridge->msgFile) ; #endif nrows = *pnrows ; ncols = *pncols Eigen/srcMPI/JimSolveMPI.c010064400020550007177000000115410663677271200165410ustar00clevecompmath00000400000006/* JimSolveMPI.c */ #include "../BridgeMPI.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_JimSolve = 0 ; static double time_JimSolve = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to solve a linear system (A - sigma*B) sol[] = rhs[] data -- pointer to bridge data object *pnrows -- # of rows in x[] and y[] *pncols -- # of columns in x[] and y[] rhs[] -- vector that holds right hand sides NOTE: the rhs[] vector is global, not a portion sol[] -- vector to hold solutions NOTE: the sol[] vector is global, not a portion note: rhs[] and sol[] can be the same array. on return, *perror holds an error code. created -- 98aug28, cca & jcp -------------------------------------------------- */ void JimSolveMPI ( int *pnrows, int *pncols, double rhs[], double sol[], void *data, int *perror ) { BridgeMPI *bridge = (BridgeMPI *) data ; DenseMtx *mtx, *newmtx ; int irow, jj, jcol, kk, myid, ncols = *pncols, neqns, nowned, tag = 0 ; int *vtxmap ; int stats[4] ; IV *mapIV ; #if MYDEBUG > 0 double t1, t2 ; count_JimSolve++ ; MARKTIME(t1) ; if ( bridge->myid == 0 ) { fprintf(stdout, "\n (%d) JimSolve() start", count_JimSolve) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, "\n (%d) JimSolve() start", count_JimSolve) ; fflush(bridge->msgFile) ; #endif MPI_Barrier(bridge->comm) ; /* --------------------------------------------- slide the owned rows of rhs down in the array --------------------------------------------- */ vtxmap = IV_entries(bridge->vtxmapIV) ; neqns = bridge->neqns ; myid = bridge->myid ; nowned = IV_size(bridge->myownedIV) ; for ( jcol = jj = kk = 0 ; jcol < ncols ; jcol++ ) { for ( irow = 0 ; irow < neqns ; irow++, jj++ ) { if ( vtxmap[irow] == myid ) { sol[kk++] = rhs[jj] ; } } } if ( kk != nowned * ncols ) { fprintf(stderr, "\n proc %d : kk %d, nowned %d, ncols %d", myid, kk, nowned, ncols) ; exit(-1) ; } /* ---------------------------------------- call the method that assumes local input ---------------------------------------- */ if ( bridge->msglvl > 1 ) { fprintf(bridge->msgFile, "\n calling SolveMPI()") ; fflush(bridge->msgFile) ; } SolveMPI(&nowned, pncols, sol, sol, data, perror) ; if ( bridge->msglvl > 1 ) { fprintf(bridge->msgFile, "\n return from SolveMPI()") ; fflush(bridge->msgFile) ; } /* ------------------------------------------ gather all the entries onto processor zero ------------------------------------------ */ mtx = DenseMtx_new() ; DenseMtx_init(mtx, SPOOLES_REAL, 0, 0, nowned, ncols, 1, nowned) ; DVcopy (nowned*ncols, DenseMtx_entries(mtx), sol) ; IVcopy(nowned, mtx->rowind, IV_entries(bridge->myownedIV)) ; mapIV = IV_new() ; IV_init(mapIV, neqns, NULL) ; IV_fill(mapIV, 0) ; IVfill(4, stats, 0) ; if ( bridge->msglvl > 1 ) { fprintf(bridge->msgFile, "\n calling DenseMtx_split()()") ; fflush(bridge->msgFile) ; } newmtx = DenseMtx_MPI_splitByRows(mtx, mapIV, stats, bridge->msglvl, bridge->msgFile, tag, bridge->comm) ; if ( bridge->msglvl > 1 ) { fprintf(bridge->msgFile, "\n return from DenseMtx_split()()") ; fflush(bridge->msgFile) ; } DenseMtx_free(mtx) ; mtx = newmtx ; IV_free(mapIV) ; if ( myid == 0 ) { DVcopy(neqns*ncols, sol, DenseMtx_entries(mtx)) ; } DenseMtx_free(mtx) ; /* --------------------------------------------- broadcast the entries to the other processors --------------------------------------------- */ if ( bridge->msglvl > 1 ) { fprintf(bridge->msgFile, "\n calling MPI_Bcast()()") ; fflush(bridge->msgFile) ; } MPI_Bcast((void *) sol, neqns*ncols, MPI_DOUBLE, 0, bridge->comm) ; if ( bridge->msglvl > 1 ) { fprintf(bridge->msgFile, "\n return from MPI_Bcast()()") ; fflush(bridge->msgFile) ; } MPI_Barrier(bridge->comm) ; /* ------------------------------------------------------------------ set the error. (this is simple since when the spooles codes detect a fatal error, they print out a message to stderr and exit.) ------------------------------------------------------------------ */ *perror = 0 ; #if MYDEBUG > 0 MARKTIME(t2) ; time_JimSolve += t2 - t1 ; if ( bridge->myid == 0 ) { fprintf(stdout, "\n (%d) JimSolve() end", count_JimSolve) ; fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_JimSolve) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, "\n (%d) JimSolve() end", count_JimSolve) ; fprintf(bridge->msgFile, ", %8.3f seconds, %8.3f total time", t2 - t1, time_JimSolve) ; fflush(bridge->msgFile) ; #endif return ; } /*--------------------------------------------------------------------*/ Eigen/srcMPI/MatMulMPI.c010064400020550007177000000140160663677201100162000ustar00clevecompmath00000400000006/* MatMulMPI.c */ #include "../BridgeMPI.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_MatMul = 0 ; static double time_MatMul = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose --- to compute a matrix-vector multiply y[] = C * x[] where C is the identity, A or B (depending on *pprbtype). *pnrows -- # of rows in x[] *pncols -- # of columns in x[] *pprbtype -- problem type *pprbtype = 1 --> vibration problem, matrix is A *pprbtype = 2 --> buckling problem, matrix is B *pprbtype = 3 --> matrix is identity, y[] = x[] created -- 98aug11, cca & jcp ------------------------------------------------------------- */ void MatMulMPI ( int *pnrows, int *pncols, double x[], double y[], int *pprbtype, void *data ) { BridgeMPI *bridge = (BridgeMPI *) data ; int ncols, nent, nrows ; #if MYDEBUG > 0 double t1, t2 ; count_MatMul++ ; MARKTIME(t1) ; if ( bridge->myid == 0 ) { fprintf(stdout, "\n (%d) MatMulMPI()", count_MatMul) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, "\n (%d) MatMulMPI()", count_MatMul) ; fflush(bridge->msgFile) ; #endif nrows = *pnrows ; ncols = *pncols ; nent = nrows*ncols ; if ( *pprbtype == 3 ) { /* -------------------------- ... matrix is the identity -------------------------- */ if ( x == NULL ) { fprintf(stderr, "\n\n fatal error in MatMulMPI, y <-- x, x is NULL") ; exit(-1) ; } if ( y == NULL ) { fprintf(stderr, "\n\n fatal error in MatMulMPI, y <-- x, y is NULL") ; exit(-1) ; } DVcopy(nent, y, x) ; return; } else { DenseMtx *Xloc = bridge->Xloc, *Yloc = bridge->Yloc ; double alpha[2] = {1.0, 0.0} ; FILE *msgFile = bridge->msgFile ; int msglvl = bridge->msglvl, n, nmyowned, tag = 0 ; int *list, *owned ; int stats[4] ; MPI_Comm comm = bridge->comm ; /* ----------------------------------------------- if the matrices are in global coordinates (i.e., this is the first matrix-vector multiply following a factorization) then map the matrix into local coordinates ----------------------------------------------- */ if ( bridge->msglvl > 1 ) { fprintf(bridge->msgFile, "\n\n inside MatMulMPI, nrow = %d, ncol = %d", nrows, ncols) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n bridge->coordFlag = %d", bridge->coordFlag) ; fflush(msgFile) ; } if ( bridge->coordFlag == GLOBAL ) { if ( bridge->prbtype == 1 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ready to permute B") ; fflush(msgFile) ; } MatMul_setLocalIndices(bridge->info, bridge->B) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n matrix B in local coordinates") ; InpMtx_writeForHumanEye(bridge->B, msgFile) ; fflush(msgFile) ; } } else if ( bridge->prbtype == 2 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ready to permute A") ; fflush(msgFile) ; } MatMul_setLocalIndices(bridge->info, bridge->A) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n matrix A in local coordinates") ; InpMtx_writeForHumanEye(bridge->A, msgFile) ; fflush(msgFile) ; } } bridge->coordFlag = LOCAL ; } /* -------------------------------------------------- check to see that Xloc and Yloc are the right size -------------------------------------------------- */ if ( Xloc->nrow != nrows ) { fprintf(stderr, "\n\n fatal error in MatMulMPI, nrows %d, Xloc->nrow %d", nrows, Xloc->nrow) ; exit(-1) ; } if ( Xloc->ncol != ncols ) { IV_sizeAndEntries(bridge->myownedIV, &nmyowned, &owned) ; DenseMtx_clearData(Xloc) ; DenseMtx_init(Xloc, SPOOLES_REAL, 0, 0, nmyowned, ncols, 1, nmyowned) ; DenseMtx_rowIndices(Xloc, &n, &list) ; IVcopy(n, list, owned) ; DenseMtx_clearData(Yloc) ; DenseMtx_init(Yloc, SPOOLES_REAL, 0, 0, nmyowned, ncols, 1, nmyowned) ; DenseMtx_rowIndices(Yloc, &n, &list) ; IVcopy(n, list, owned) ; } /* ------------------ copy x[] into Xloc ------------------ */ DVcopy(nent, DenseMtx_entries(Xloc), x) ; /* --------- zero Yloc --------- */ DenseMtx_zero(Yloc) ; /* ---------------------------------------- compute the local matrix-vector multiply ---------------------------------------- */ if ( *pprbtype == 1 ) { IVzero(4, stats) ; MatMul_MPI_mmm(bridge->info, Yloc, alpha, bridge->B, Xloc, stats, msglvl, msgFile, tag, comm) ; } else if ( *pprbtype == 2 ) { IVzero(4, stats) ; MatMul_MPI_mmm(bridge->info, Yloc, alpha, bridge->A, Xloc, stats, msglvl, msgFile, tag, comm) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after mvm, Yloc") ; DenseMtx_writeForHumanEye(Yloc, msgFile) ; fflush(msgFile) ; } /* ----------------------------- copy entries of Yloc into y[] ----------------------------- */ if ( DenseMtx_entries(Yloc) == NULL ) { fprintf(stderr, "\n\n fatal error in MatMulMPI, y <-- Yloc, Yloc is NULL") ; exit(-1) ; } if ( y == NULL ) { fprintf(stderr, "\n\n fatal error in MatMulMPI, y <-- Yloc, y is NULL") ; exit(-1) ; } DVcopy(nent, y, DenseMtx_entries(Yloc)) ; } #if MYDEBUG > 0 MARKTIME(t2) ; time_MatMul += t2 - t1 ; if ( bridge->myid == 0 ) { fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_MatMul) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, ", %8.3f seconds, %8.3f total time", t2 - t1, time_MatMul) ; fflush(bridge->msgFile) ; #endif return ; } /*--------------------------------------------------------------------*/ Eigen/srcMPI/SetupMPI.c010064400020550007177000000367300663673013000161040ustar00clevecompmath00000400000006/* SetupMPI.c */ #include "../BridgeMPI.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Setup = 0 ; static double time_Setup = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- given InpMtx objects that contain A and B, initialize the bridge data structure for the MPI factor's, solve's and mvm's. NOTE: all the input arguments are pointers to allow calls from Fortran data -- pointer to a Bridge object pprbtype -- pointer to value containing problem type *prbtype = 1 --> A X = B X Lambda, vibration problem *prbtype = 2 --> A X = B X Lambda, buckling problem *prbtype = 3 --> A X = X Lambda, simple eigenvalue problem pneqns -- pointer to value containing number of equations pmxbsz -- pointer to value containing blocksize A -- pointer to InpMtx object containing A B -- pointer to InpMtx object containing B pseed -- pointer to value containing a random number seed pmsglvl -- pointer to value containing a message level msgFile -- message file pointer return value -- 1 -- normal return -1 -- data is NULL -2 -- pprbtype is NULL -3 -- *pprbtype is invalid -4 -- pneqns is NULL -5 -- *pneqns is invalid -6 -- pmxbsz is NULL -7 -- *pmxbsz is invalid -8 -- A and B are NULL -9 -- pseed is NULL -10 -- pmsglvl is NULL -11 -- *pmsglvl > 0 and msgFile is NULL -12 -- comm is NULL created -- 98aug10, cca ---------------------------------------------------------------- */ int SetupMPI ( void *data, int *pprbtype, int *pneqns, int *pmxbsz, InpMtx *A, InpMtx *B, int *pseed, int *pmsglvl, FILE *msgFile, MPI_Comm comm ) { BridgeMPI *bridge = (BridgeMPI *) data ; double cutoff, minops ; double *opcounts ; double sigma[2] ; DV *cumopsDV ; Graph *graph ; int maxdomainsize, maxsize, maxzeros, msglvl, myid, mxbsz, nedges, neqns, nmyowned, nproc, prbtype, root, seed, tag ; int stats[4] ; IVL *adjIVL ; #if MYDEBUG > 0 double t1, t2 ; #endif /* --------------------------------- get number of processors and rank --------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; #if MYDEBUG > 0 count_Setup++ ; MARKTIME(t1) ; if ( myid == 0 ) { fprintf(stdout, "\n (%d) SetupMPI()", count_Setup) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, "\n (%d) SetupMPI()", count_Setup) ; fflush(bridge->msgFile) ; #endif /* -------------------- check the input data -------------------- */ if ( data == NULL ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n data is NULL\n") ; return(-1) ; } if ( pprbtype == NULL ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n prbtype is NULL\n") ; return(-2) ; } prbtype = *pprbtype ; if ( prbtype < 1 || prbtype > 3 ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n prbtype = %d, is invalid\n", prbtype) ; return(-3) ; } if ( pneqns == NULL ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n pneqns is NULL\n") ; return(-4) ; } neqns = *pneqns ; if ( neqns <= 0 ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n neqns = %d, is invalid\n", neqns) ; return(-5) ; } if ( pmxbsz == NULL ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n pmxbsz is NULL\n") ; return(-6) ; } mxbsz = *pmxbsz ; if ( mxbsz <= 0 ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n *pmxbsz = %d, is invalid\n", mxbsz) ; return(-7) ; } if ( A == NULL && B == NULL ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n A and B are NULL\n") ; return(-8) ; } if ( pseed == NULL ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n pseed is NULL\n") ; return(-9) ; } seed = *pseed ; if ( pmsglvl == NULL ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n pmsglvl is NULL\n") ; return(-10) ; } msglvl = *pmsglvl ; if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n msglvl = %d, msgFile = NULL\n", msglvl) ; return(-11) ; } if ( comm == NULL ) { fprintf(stderr, "\n fatal error in SetupMPI()" "\n comm = NULL\n") ; return(-12) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside SetupMPI()" "\n neqns = %d, prbtype = %d, mxbsz = %d, seed = %d", neqns, prbtype, mxbsz, seed) ; if ( A != NULL ) { fprintf(msgFile, "\n\n matrix A") ; InpMtx_writeForHumanEye(A, msgFile) ; } if ( B != NULL ) { fprintf(msgFile, "\n\n matrix B") ; InpMtx_writeForHumanEye(B, msgFile) ; } fflush(msgFile) ; } bridge->myid = myid ; bridge->nproc = nproc ; bridge->prbtype = prbtype ; bridge->neqns = neqns ; bridge->mxbsz = mxbsz ; bridge->A = A ; bridge->B = B ; bridge->seed = seed ; bridge->msglvl = msglvl ; bridge->msgFile = msgFile ; bridge->comm = comm ; /* ------------------------------------ STEP 1: create and initialize pencil ------------------------------------ */ sigma[0] = 1.0; sigma[1] = 0.0; bridge->pencil = Pencil_new() ; Pencil_init(bridge->pencil, SPOOLES_REAL, SPOOLES_SYMMETRIC, A, sigma, B) ; /* ---------------------------------------- STEP 2: convert to row or column vectors ---------------------------------------- */ if ( A != NULL ) { if ( ! INPMTX_IS_BY_ROWS(A) && ! INPMTX_IS_BY_COLUMNS(A) ) { InpMtx_changeCoordType(A, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(A) ) { InpMtx_changeStorageMode(A, INPMTX_BY_VECTORS) ; } } if ( B != NULL ) { if ( ! INPMTX_IS_BY_ROWS(B) && ! INPMTX_IS_BY_COLUMNS(B) ) { InpMtx_changeCoordType(B, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(B) ) { InpMtx_changeStorageMode(B, INPMTX_BY_VECTORS) ; } } /* --------------------------------------- STEP 3: create a Graph object for A + B --------------------------------------- */ graph = Graph_new() ; IVfill(4, stats, 0) ; adjIVL = Pencil_MPI_fullAdjacency(bridge->pencil, stats, msglvl, msgFile, comm); nedges = IVL_tsize(adjIVL), Graph_init2(graph, 0, bridge->neqns, 0, nedges, bridge->neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph of the input pencil") ; fflush(msgFile) ; } /* ------------------------------------------------------------ STEP 4: order the graph. each processor orders the graph independently. then the processors determine who has the best ordering, and that ordering information (contained in the FrontETree object) is broadcast to all processors. ------------------------------------------------------------ */ maxdomainsize = neqns / 64 ; if ( maxdomainsize == 0 ) { maxdomainsize = 1 ; } maxzeros = (int) (0.01*neqns) ; maxsize = 64 ; bridge->frontETree = orderViaBestOfNDandMS(graph, maxdomainsize, maxzeros, maxsize, bridge->seed + myid, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree from ordering") ; fflush(msgFile) ; } Graph_free(graph) ; opcounts = DVinit(nproc, 0.0) ; opcounts[myid] = ETree_nFactorOps(bridge->frontETree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n before gather \n" ); fflush(msgFile) ; } MPI_Allgather((void *) &opcounts[myid], 1, MPI_DOUBLE, (void *) opcounts, 1, MPI_DOUBLE, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n after gather \n" ); fflush(msgFile) ; } minops = DVmin(nproc, opcounts, &root) ; root = 0 ; DVfree(opcounts) ; bridge->frontETree = ETree_MPI_Bcast(bridge->frontETree, root, msglvl, msgFile, comm) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n best front tree") ; ETree_writeForHumanEye(bridge->frontETree, msgFile) ; fflush(msgFile) ; } /* ETree_writeToFile(bridge->frontETree, "stk35.etreef") ; */ /* ------------------------------------------------------ STEP 5: get the old-to-new and new-to-old permutations ------------------------------------------------------ */ bridge->oldToNewIV = ETree_oldToNewVtxPerm(bridge->frontETree) ; bridge->newToOldIV = ETree_newToOldVtxPerm(bridge->frontETree) ; IV_writeToFile(bridge->oldToNewIV, "oldToNew.ivf") ; IV_writeToFile(bridge->newToOldIV, "newToOld.ivf") ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n old-to-new permutation") ; fprintf(msgFile, "\n\n new-to-old permutation") ; fflush(msgFile) ; } /* ---------------------------------------------- STEP 6: permute the vertices in the front tree ---------------------------------------------- */ ETree_permuteVertices(bridge->frontETree, bridge->oldToNewIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted front etree") ; fflush(msgFile) ; } /* ------------------------------------------------------------ STEP 7: generate (1) ownersIV -- the map from fronts to processors (2) vtxmapIV -- the map from vertices to processors (3) myownedIV -- vertices owned by this processor ------------------------------------------------------------ */ cutoff = 1./(2*nproc) ; cumopsDV = DV_new() ; DV_init(cumopsDV, nproc, NULL) ; bridge->ownersIV = ETree_ddMap(bridge->frontETree, SPOOLES_REAL, SPOOLES_SYMMETRIC, cumopsDV, cutoff) ; DV_free(cumopsDV) ; bridge->vtxmapIV = IV_new() ; IV_init(bridge->vtxmapIV, bridge->neqns, NULL) ; IVgather(bridge->neqns, IV_entries(bridge->vtxmapIV), IV_entries(bridge->ownersIV), ETree_vtxToFront(bridge->frontETree)) ; bridge->myownedIV = IV_targetEntries(bridge->vtxmapIV, myid) ; nmyowned = IV_size(bridge->myownedIV) ; bridge->rowmapIV = NULL ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n map from fronts to owning processes") ; IV_writeForHumanEye(bridge->ownersIV, msgFile) ; fprintf(msgFile, "\n\n map from vertices to owning processes") ; IV_writeForHumanEye(bridge->vtxmapIV, msgFile) ; fprintf(msgFile, "\n\n vertices owned by this process") ; IV_writeForHumanEye(bridge->myownedIV, msgFile) ; fflush(msgFile) ; } /* IV_writeToFile(bridge->ownersIV, "owners.ivf") ; Tree_writeToFile(bridge->frontETree->tree, "stk35.treef") ; */ /* --------------------------------------------------- STEP 8: permute the entries in the pencil. note, after the permutation the entries are mapped into the upper triangle. --------------------------------------------------- */ Pencil_permute(bridge->pencil, bridge->oldToNewIV, bridge->oldToNewIV) ; Pencil_mapToUpperTriangle(bridge->pencil) ; Pencil_changeCoordType(bridge->pencil, INPMTX_BY_CHEVRONS) ; Pencil_changeStorageMode(bridge->pencil, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted pencil") ; fflush(msgFile) ; } tag = 0 ; Pencil_MPI_split(bridge->pencil, bridge->vtxmapIV, stats, msglvl, msgFile, tag, comm) ; Pencil_changeCoordType(bridge->pencil, INPMTX_BY_CHEVRONS) ; Pencil_changeStorageMode(bridge->pencil, INPMTX_BY_VECTORS) ; bridge->A = A = bridge->pencil->inpmtxA ; bridge->B = B = bridge->pencil->inpmtxB ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted and split pencil") ; fflush(msgFile) ; } /* ------------------------------------------ STEP 9: compute the symbolic factorization ------------------------------------------ */ bridge->symbfacIVL = SymbFac_MPI_initFromPencil(bridge->frontETree, bridge->ownersIV, bridge->pencil, stats, msglvl, msgFile, tag, comm) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(bridge->symbfacIVL, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------------------------- STEP 10: create a FrontMtx object to hold the factorization ----------------------------------------------------------- */ bridge->frontmtx = FrontMtx_new() ; /* --------------------------------------------------------------------- STEP 11: create a SubMtxManager object to hold the factor submatrices --------------------------------------------------------------------- */ bridge->mtxmanager = SubMtxManager_new() ; SubMtxManager_init(bridge->mtxmanager, NO_LOCK, 0) ; /* --------------------------------------------- STEP 12: create a SolveMap object to hold the map from submatrices to processes --------------------------------------------- */ bridge->solvemap = SolveMap_new() ; /* ----------------------------------- STEP 13: set up the distributed mvm ----------------------------------- */ bridge->coordFlag = GLOBAL ; if ( *pprbtype == 3 ) { /* ---------------------------------- matrix is the identity, do nothing ---------------------------------- */ bridge->info = NULL ; bridge->Xloc = NULL ; bridge->Yloc = NULL ; } else { InpMtx *mtx ; int n ; int *list ; /* ---------------------------------------------- generalized eigenvalue problem, find out which matrix to use with the matrix-vector multiply ---------------------------------------------- */ if ( *pprbtype == 1 ) { mtx = B ; } else if ( *pprbtype == 2 ) { mtx = A ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n before MatMul_MPI_setup \n" ); fflush(msgFile) ; } bridge->info = MatMul_MPI_setup(mtx, SPOOLES_SYMMETRIC, MMM_WITH_A, bridge->vtxmapIV, bridge->vtxmapIV, stats, msglvl, msgFile, tag, comm) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n after MatMul_MPI_setup \n" ); fflush(msgFile) ; } /* --------------------------------- set up the Xloc and Yloc matrices --------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n SPOOLES_REAL = %d", SPOOLES_REAL) ; fprintf(msgFile, "\n bridge->mxbsz = %d", bridge->mxbsz) ; fprintf(msgFile, "\n initializing Xloc") ; fflush(msgFile) ; } bridge->Xloc = DenseMtx_new() ; DenseMtx_init(bridge->Xloc, SPOOLES_REAL, 0, 0, nmyowned, bridge->mxbsz, 1, nmyowned) ; DenseMtx_rowIndices(bridge->Xloc, &n, &list) ; IVcopy(n, list, IV_entries(bridge->myownedIV)) ; bridge->Yloc = DenseMtx_new() ; DenseMtx_zero(bridge->Xloc) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n initializing Yloc") ; fflush(msgFile) ; } DenseMtx_init(bridge->Yloc, SPOOLES_REAL, 0, 0, nmyowned, bridge->mxbsz, 1, nmyowned) ; DenseMtx_rowIndices(bridge->Yloc, &n, &list) ; IVcopy(n, list, IV_entries(bridge->myownedIV)) ; DenseMtx_zero(bridge->Yloc) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n initial Xloc matrix") ; fprintf(msgFile, "\n\n initial Yloc matrix") ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n leaving SetupMPI()\n") ; fflush(msgFile) ; } #if MYDEBUG > 0 MARKTIME(t2) ; time_Setup += t2 - t1 ; if ( bridge->myid == 0 ) { fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Setup) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Setup) ; fflush(bridge->msgFile) ; #endif return(1) ; } /*--------------------------------------------------------------------*/ Eigen/srcMPI/SolveMPI.c010064400020550007177000000144020663677245500161040ustar00clevecompmath00000400000006/* SolveMPI.c */ #include "../BridgeMPI.h" #define MYDEBUG 1 #if MYDEBUG > 0 static int count_Solve = 0 ; static double time_Solve = 0.0 ; #endif /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to solve a linear system (A - sigma*B) sol[] = rhs[] data -- pointer to bridge data object *pnrows -- # of rows in x[] and y[] *pncols -- # of columns in x[] and y[] rhs[] -- vector that holds right hand sides sol[] -- vector to hold solutions note: rhs[] and sol[] can be the same array. on return, *perror holds an error code. 1 -- normal return -1 -- pnrows is NULL -2 -- pncols is NULL -3 -- rhs is NULL -4 -- sol is NULL -5 -- data is NULL created -- 98aug10, cca & jcp ---------------------------------------------- */ void SolveMPI ( int *pnrows, int *pncols, double rhs[], double sol[], void *data, int *perror ) { BridgeMPI *bridge = (BridgeMPI *) data ; DenseMtx *rhsmtx ; double cpus[20] ; int nent, ncols, nrows, tag = 0 ; int stats[8] ; #if MYDEBUG > 0 double t1, t2 ; count_Solve++ ; MARKTIME(t1) ; if ( bridge->myid == 0 ) { fprintf(stdout, "\n (%d) SolveMPI()", count_Solve) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, "\n (%d) SolveMPI()", count_Solve) ; fflush(bridge->msgFile) ; #endif /* --------------- check the input --------------- */ if ( perror == NULL ) { fprintf(stderr, "\n error in Solve()" "\n perror == NULL\n") ; return ; } if ( pnrows == NULL ) { fprintf(stderr, "\n error in Solve()" "\n pnrows == NULL\n") ; *perror = -1 ; return ; } if ( pncols == NULL ) { fprintf(stderr, "\n error in Solve()" "\n pncols == NULL\n") ; *perror = -2 ; return ; } if ( rhs == NULL ) { fprintf(stderr, "\n error in Solve()" "\n rhs == NULL\n") ; *perror = -3 ; return ; } if ( sol == NULL ) { fprintf(stderr, "\n error in Solve()" "\n sol == NULL\n") ; *perror = -4 ; return ; } if ( data == NULL ) { fprintf(stderr, "\n error in Solve()" "\n data == NULL\n") ; *perror = -5 ; return ; } /* ---------------------------------- set the number of rows and columns ---------------------------------- */ nrows = *pnrows ; ncols = *pncols ; nent = nrows*ncols ; /* --------------------------------- setup rhsmtx as a DenseMtx object --------------------------------- */ rhsmtx = DenseMtx_new() ; DenseMtx_init(rhsmtx, SPOOLES_REAL, 0, 0, nrows, ncols, 1, nrows) ; if ( rhs == NULL ) { fprintf(stderr, "\n fatal error in SolveMPI, rhsmtx <-- rhs, rhs is NULL") ; exit(-1) ; } if ( DenseMtx_entries(rhsmtx) == NULL ) { fprintf(stderr, "\n fatal error in SolveMPI, rhsmtx <-- rhs, rhsmtx is NULL") ; exit(-1) ; } DVcopy (nent, DenseMtx_entries(rhsmtx), rhs) ; IVcopy(nrows, rhsmtx->rowind, IV_entries(bridge->myownedIV)) ; if ( bridge->msglvl > 2 && bridge->msgFile != NULL ) { fprintf(bridge->msgFile, "\n\n rhsmtx initialized") ; DenseMtx_writeForHumanEye(rhsmtx, bridge->msgFile) ; fflush(bridge->msgFile) ; } if ( bridge->rowmapIV != NULL ) { DenseMtx *newmtx ; /* -------------------------------- pivoting may have taken place, redistribute the rows of the rhs -------------------------------- */ IVzero(4, stats) ; newmtx = DenseMtx_MPI_splitByRows(rhsmtx, bridge->rowmapIV, stats, bridge->msglvl, bridge->msgFile, tag, bridge->comm) ; DenseMtx_free(rhsmtx) ; rhsmtx = newmtx ; if ( bridge->msglvl > 2 && bridge->msgFile != NULL ) { fprintf(bridge->msgFile, "\n\n rhsmtx after redistribution") ; DenseMtx_writeForHumanEye(rhsmtx, bridge->msgFile) ; fflush(bridge->msgFile) ; } } /* ----------------------- solve the linear system ----------------------- */ IVzero(8, stats) ; DVzero(20, cpus) ; FrontMtx_MPI_solve(bridge->frontmtx, rhsmtx, rhsmtx, bridge->mtxmanager, bridge->solvemap, cpus, stats, bridge->msglvl, bridge->msgFile, tag, bridge->comm) ; if ( bridge->msglvl > 2 && bridge->msgFile != NULL ) { fprintf(bridge->msgFile, "\n\n solution matrix after redistribution") ; DenseMtx_writeForHumanEye(rhsmtx, bridge->msgFile) ; fflush(bridge->msgFile) ; } if ( bridge->rowmapIV != NULL ) { DenseMtx *newmtx ; /* ------------------------------------- pivoting may have taken place, redistribute the rows of the solution ------------------------------------- */ newmtx = DenseMtx_MPI_splitByRows(rhsmtx, bridge->vtxmapIV, stats, bridge->msglvl, bridge->msgFile, tag, bridge->comm) ; DenseMtx_free(rhsmtx) ; rhsmtx = newmtx ; if ( bridge->msglvl > 2 && bridge->msgFile != NULL ) { fprintf(bridge->msgFile, "\n\n solution matrix after redistribution") ; DenseMtx_writeForHumanEye(rhsmtx, bridge->msgFile) ; fflush(bridge->msgFile) ; } } /* ----------------------------------- copy solution into output parameter ----------------------------------- */ if ( DenseMtx_entries(rhsmtx) == NULL ) { fprintf(stderr, "\n fatal error in SolveMPI, sol <-- rhsmtx, rhsmtx is NULL") ; exit(-1) ; } if ( sol == NULL ) { fprintf(stderr, "\n fatal error in SolveMPI, sol <-- rhsmtx, sol is NULL") ; exit(-1) ; } DVcopy(nent, sol, DenseMtx_entries(rhsmtx)) ; /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(rhsmtx) ; /* ------------------------------------------------------------------ set the error. (this is simple since when the spooles codes detect a fatal error, they print out a message to stderr and exit.) ------------------------------------------------------------------ */ *perror = 0 ; #if MYDEBUG > 0 MARKTIME(t2) ; time_Solve += t2 - t1 ; if ( bridge->myid == 0 ) { fprintf(stdout, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Solve) ; fflush(stdout) ; } #endif #if MYDEBUG > 1 fprintf(bridge->msgFile, ", %8.3f seconds, %8.3f total time", t2 - t1, time_Solve) ; fflush(bridge->msgFile) ; #endif return ; } /*--------------------------------------------------------------------*/ Eigen/drivers/do_MPI_fiddle010075500020550007177000000007630663672716100171660ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp set pgFile = spooles.pg echo matrix3fiddle uncompress < $MTX_DIR/matrix.fid.3A.Z > fort.37 uncompress < $MTX_DIR/matrix.fid.3B.Z > fort.38 set msglvl = 0 set msgFile = res.fiddle set parmFile = fiddle.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.fiddle /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testMPI $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* res.9* Eigen/drivers/do_MPI_mtx10010075500020550007177000000007450663672716600167150ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp set pgFile = spooles.pg echo matrix10 uncompress < $MTX_DIR/matrix.10A.Z > fort.37 uncompress < $MTX_DIR/matrix.10B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx10 set parmFile = mtx10.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx10 /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testMPI $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* res.9* Eigen/drivers/do_MPI_mtx3010075500020550007177000000007370663672703300166310ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp set pgFile = spooles.pg echo matrix3 uncompress < $MTX_DIR/matrix.3A.Z > fort.37 uncompress < $MTX_DIR/matrix.3B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx3 set parmFile = mtx3.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx3 /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testMPI $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* res.9* Eigen/drivers/do_MPI_mtx4010075500020550007177000000007370663672717500166410ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp set pgFile = spooles.pg echo matrix4 uncompress < $MTX_DIR/matrix.4A.Z > fort.37 uncompress < $MTX_DIR/matrix.4B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx4 set parmFile = mtx4.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx4 /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testMPI $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* res.9* Eigen/drivers/do_MPI_mtx5010075500020550007177000000007370663672720200166310ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp set pgFile = spooles.pg echo matrix5 uncompress < $MTX_DIR/matrix.5A.Z > fort.37 uncompress < $MTX_DIR/matrix.5B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx5 set parmFile = mtx5.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx5 /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testMPI $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* res.9* Eigen/drivers/do_MPI_mtx6010075500020550007177000000007370663672720700166370ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp set pgFile = spooles.pg echo matrix6 uncompress < $MTX_DIR/matrix.6A.Z > fort.37 uncompress < $MTX_DIR/matrix.6B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx6 set parmFile = mtx6.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx6 /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testMPI $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* res.9* Eigen/drivers/do_MPI_mtx7010075500020550007177000000007370663672721400166360ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp set pgFile = spooles.pg echo matrix7 uncompress < $MTX_DIR/matrix.7A.Z > fort.37 uncompress < $MTX_DIR/matrix.7B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx7 set parmFile = mtx7.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx7 /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testMPI $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* res.9* Eigen/drivers/do_MPI_mtx8010075500020550007177000000007370663672722000166340ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp set pgFile = spooles.pg echo matrix8 uncompress < $MTX_DIR/matrix.8A.Z > fort.37 uncompress < $MTX_DIR/matrix.8B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx8 set parmFile = mtx8.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx8 /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testMPI $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* res.9* Eigen/drivers/do_MPI_mtx9010075500020550007177000000007370663672722600166430ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp set pgFile = spooles.pg echo matrix9 uncompress < $MTX_DIR/matrix.9A.Z > fort.37 uncompress < $MTX_DIR/matrix.9B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx9 set parmFile = mtx9.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx9 /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testMPI $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* res.9* Eigen/drivers/do_MPI_plat362010075500020550007177000000007030663672724100171230ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp set pgFile = spooles.pg echo plat362.mtx uncompress < $MTX_DIR/plat362.mtx.Z > fort.37 set msglvl = 0 set msgFile = res.plat362 set parmFile = plat362.inp set seed = 10 set inFileA = fort.37 set inFileB = none set resFile = res.mtx.plat362 /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testMPI $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* res.9* Eigen/drivers/do_MT_mtx10010075500020550007177000000006650663672626200166050ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix10 uncompress < $MTX_DIR/matrix.10A.Z > fort.37 uncompress < $MTX_DIR/matrix.10B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx10 set parmFile = mtx10.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx10 set nthread = 4 testMT $msglvl $msgFile $parmFile $seed $nthread $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_MT_mtx3010075500020550007177000000006560663672627100165270ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix3 uncompress < $MTX_DIR/matrix.3A.Z > fort.37 uncompress < $MTX_DIR/matrix.3B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx3 set parmFile = mtx3.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx3 set nthread = 4 testMT $msglvl $msgFile $parmFile $seed $nthread $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_MT_mtx4010075500020550007177000000006570663672627600165360ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix4 uncompress < $MTX_DIR/matrix.4A.Z > fort.37 uncompress < $MTX_DIR/matrix.4B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx4 set parmFile = mtx4.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx4 set nthread = 4 testMT $msglvl $msgFile $parmFile $seed $nthread $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_MT_mtx5010075500020550007177000000006570663672630400165270ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix5 uncompress < $MTX_DIR/matrix.5A.Z > fort.37 uncompress < $MTX_DIR/matrix.5B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx5 set parmFile = mtx5.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx5 set nthread = 4 testMT $msglvl $msgFile $parmFile $seed $nthread $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_MT_mtx6010075500020550007177000000006570663672631100165260ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix6 uncompress < $MTX_DIR/matrix.6A.Z > fort.37 uncompress < $MTX_DIR/matrix.6B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx6 set parmFile = mtx6.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx6 set nthread = 4 testMT $msglvl $msgFile $parmFile $seed $nthread $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_MT_mtx7010075500020550007177000000006570663672631700165350ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix7 uncompress < $MTX_DIR/matrix.7A.Z > fort.37 uncompress < $MTX_DIR/matrix.7B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx7 set parmFile = mtx7.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx7 set nthread = 4 testMT $msglvl $msgFile $parmFile $seed $nthread $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_MT_mtx8010075500020550007177000000006570663672632400165340ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix8 uncompress < $MTX_DIR/matrix.8A.Z > fort.37 uncompress < $MTX_DIR/matrix.8B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx8 set parmFile = mtx8.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx8 set nthread = 4 testMT $msglvl $msgFile $parmFile $seed $nthread $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_MT_mtx9010075500020550007177000000006570663672633200165340ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix9 uncompress < $MTX_DIR/matrix.9A.Z > fort.37 uncompress < $MTX_DIR/matrix.9B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx9 set parmFile = mtx9.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx9 set nthread = 4 testMT $msglvl $msgFile $parmFile $seed $nthread $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_MT_plat362010075500020550007177000000006230663672634200170200ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo plat362.mtx uncompress < $MTX_DIR/plat362.mtx.Z > fort.37 set msglvl = 0 set msgFile = res.plat362 set parmFile = plat362.inp set seed = 10 set inFileA = fort.37 set inFileB = none set resFile = res.mtx.plat362 set nthread = 4 testMT $msglvl $msgFile $parmFile $seed $nthread $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_MT_tests010075500020550007177000000046030663202567100167620ustar00clevecompmath00000400000006#! /bin/csh -f set TEST_DIR = ../../../inp echo plat362.mtx rm fort.* uncompress < $TEST_DIR/plat362.mtx.Z > fort.37 cp $TEST_DIR/jcp.plat362.inp input.dat testMT 0 junk stdout 10 3 3 fort.37 > res.mtx.plat362 echo matrices.3 rm fort.* uncompress < $TEST_DIR/matrix.3A.Z > fort.37 uncompress < $TEST_DIR/matrix.3B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.3 input.dat testMT 0 junk stdout 10 1 3 fort.37 fort.38 > res.mtx.3 echo matrices.4 rm fort.* uncompress < $TEST_DIR/matrix.4A.Z > fort.37 uncompress < $TEST_DIR/matrix.4B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.4 input.dat testMT 0 junk stdout 10 1 3 fort.37 fort.38 > res.mtx.4 echo matrices.5 rm fort.* uncompress < $TEST_DIR/matrix.5A.Z > fort.37 uncompress < $TEST_DIR/matrix.5B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.5 input.dat testMT 0 junk stdout 10 1 3 fort.37 fort.38 > res.mtx.5 echo matrices.6 rm fort.* uncompress < $TEST_DIR/matrix.6A.Z > fort.37 uncompress < $TEST_DIR/matrix.6B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.6 input.dat testMT 0 junk stdout 10 1 3 fort.37 fort.38 > res.mtx.6 echo matrices.7 rm fort.* uncompress < $TEST_DIR/matrix.7A.Z > fort.37 uncompress < $TEST_DIR/matrix.7B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.7 input.dat testMT 0 junk stdout 10 1 3 fort.37 fort.38 > res.mtx.7 echo matrices.8 rm fort.* uncompress < $TEST_DIR/matrix.8A.Z > fort.37 uncompress < $TEST_DIR/matrix.8B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.8 input.dat testMT 0 junk stdout 10 1 3 fort.37 fort.38 > res.mtx.8 echo matrices.9 rm fort.* uncompress < $TEST_DIR/matrix.9A.Z > fort.37 uncompress < $TEST_DIR/matrix.9B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.9 input.dat testMT 0 junk stdout 10 1 3 fort.37 fort.38 > res.mtx.9 echo matrices.10 rm fort.* uncompress < $TEST_DIR/matrix.10A.Z > fort.37 uncompress < $TEST_DIR/matrix.10B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.10 input.dat testMT 0 junk stdout 10 1 3 fort.37 fort.38 > res.mtx.10 echo matrices.11 rm fort.* uncompress < $TEST_DIR/matrix.11A.Z > fort.37 uncompress < $TEST_DIR/matrix.11B.Z > fort.38 cp $TEST_DIR/jcp.inp.buck.11 input.dat testMT 0 junk stdout 10 2 3 fort.37 fort.38 > res.mtx.11 echo matrices.3_fiddle #rm fort.* #uncompress < $TEST_DIR/matrix.fid.3A.Z > fort.37 #uncompress < $TEST_DIR/matrix.fid.3B.Z > fort.38 #cp $TEST_DIR/jcp.inp.buck.3fid input.dat #testMT 0 junk stdout 10 2 3 fort.37 fort.38 > res.mtx.3_fiddle quick_diff rm -f fort.* junk* res* *.dat /tmp/*fil* Eigen/drivers/do_ST_35010075000020550007177000000003520663625373100160510ustar00clevecompmath00000400000006#! /bin/csh -f set TEST_DIR = /scratch/pattersn/ echo bcsstk35.mtx rm fort.* cp $TEST_DIR/bcsstk35.mtx.rb fort.37 cp $TEST_DIR/bcsstm35.mtx.rb fort.38 cp input.dat.35 input.dat time testSerial 0 stdout stdout 10 1 fort.37 fort.38 Eigen/drivers/do_ST_fiddle010075500020550007177000000006540663672263500170670ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix3fiddle uncompress < $MTX_DIR/matrix.fid.3A.Z > fort.37 uncompress < $MTX_DIR/matrix.fid.3B.Z > fort.38 set msglvl = 0 set msgFile = res.fiddle set parmFile = fiddle.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.fiddle testSerial $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_ST_mtx10010075500020550007177000000006360663672265100166070ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix10 uncompress < $MTX_DIR/matrix.10A.Z > fort.37 uncompress < $MTX_DIR/matrix.10B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx10 set parmFile = mtx10.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx10 testSerial $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_ST_mtx3010075500020550007177000000006300663672265700165310ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix3 uncompress < $MTX_DIR/matrix.3A.Z > fort.37 uncompress < $MTX_DIR/matrix.3B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx3 set parmFile = mtx3.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx3 testSerial $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_ST_mtx4010075500020550007177000000006300663672266500165310ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix4 uncompress < $MTX_DIR/matrix.4A.Z > fort.37 uncompress < $MTX_DIR/matrix.4B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx4 set parmFile = mtx4.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx4 testSerial $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_ST_mtx5010075500020550007177000000006300663672267400165320ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix5 uncompress < $MTX_DIR/matrix.5A.Z > fort.37 uncompress < $MTX_DIR/matrix.5B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx5 set parmFile = mtx5.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx5 testSerial $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_ST_mtx6010075500020550007177000000006300663672270200165230ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix6 uncompress < $MTX_DIR/matrix.6A.Z > fort.37 uncompress < $MTX_DIR/matrix.6B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx6 set parmFile = mtx6.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx6 testSerial $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_ST_mtx7010075500020550007177000000006300663672271000165230ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix7 uncompress < $MTX_DIR/matrix.7A.Z > fort.37 uncompress < $MTX_DIR/matrix.7B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx7 set parmFile = mtx7.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx7 testSerial $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_ST_mtx8010075500020550007177000000006300663672271500165310ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix8 uncompress < $MTX_DIR/matrix.8A.Z > fort.37 uncompress < $MTX_DIR/matrix.8B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx8 set parmFile = mtx8.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx8 testSerial $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_ST_mtx9010075500020550007177000000006300663672272300165310ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo matrix9 uncompress < $MTX_DIR/matrix.9A.Z > fort.37 uncompress < $MTX_DIR/matrix.9B.Z > fort.38 set msglvl = 0 set msgFile = res.mtx9 set parmFile = mtx9.inp set seed = 10 set inFileA = fort.37 set inFileB = fort.38 set resFile = res.mtx9 testSerial $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_ST_plat362010075500020550007177000000005740663672255500170350ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /home/pattersn/LANCZOS/test/inp echo plat362.mtx uncompress < $MTX_DIR/plat362.mtx.Z > fort.37 set msglvl = 0 set msgFile = res.plat362 set parmFile = plat362.inp set seed = 10 set inFileA = fort.37 set inFileB = none set resFile = res.mtx.plat362 testSerial $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_ST_stk35010075500020550007177000000005660663672273400166130ustar00clevecompmath00000400000006#! /bin/csh -f set MTX_DIR = /local1/cleve/ARPA/matrices/BCSSTK35 echo bcsstk35 set msglvl = 0 set msgFile = res.stk35 set parmFile = stk35.inp set seed = 10 set inFileA = $MTX_DIR/bcsstk35.mtx.rb set inFileB = $MTX_DIR/bcsstm35.mtx.rb set resFile = res.stk35 testSerial $msglvl $msgFile $parmFile $seed $inFileA $inFileB rm fort.* lmq* lq* evc* Eigen/drivers/do_ST_tests010075500020550007177000000047130663625370500167770ustar00clevecompmath00000400000006#! /bin/csh -f set TEST_DIR = ../../../inp echo plat362.mtx rm fort.* uncompress < $TEST_DIR/plat362.mtx.Z > fort.37 cp $TEST_DIR/jcp.plat362.inp input.dat testSerial 0 junk stdout 10 3 fort.37 exit testSerial 0 junk stdout 10 3 fort.37 > res.mtx.plat362 echo matrices.3 rm fort.* uncompress < $TEST_DIR/matrix.3A.Z > fort.37 uncompress < $TEST_DIR/matrix.3B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.3 input.dat testSerial 0 junk stdout 10 1 fort.37 fort.38 > res.mtx.3 echo matrices.4 rm fort.* uncompress < $TEST_DIR/matrix.4A.Z > fort.37 uncompress < $TEST_DIR/matrix.4B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.4 input.dat testSerial 0 junk stdout 10 1 fort.37 fort.38 > res.mtx.4 echo matrices.5 rm fort.* uncompress < $TEST_DIR/matrix.5A.Z > fort.37 uncompress < $TEST_DIR/matrix.5B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.5 input.dat testSerial 0 junk stdout 10 1 fort.37 fort.38 > res.mtx.5 echo matrices.6 rm fort.* uncompress < $TEST_DIR/matrix.6A.Z > fort.37 uncompress < $TEST_DIR/matrix.6B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.6 input.dat testSerial 0 junk stdout 10 1 fort.37 fort.38 > res.mtx.6 echo matrices.7 rm fort.* uncompress < $TEST_DIR/matrix.7A.Z > fort.37 uncompress < $TEST_DIR/matrix.7B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.7 input.dat testSerial 0 junk stdout 10 1 fort.37 fort.38 > res.mtx.7 echo matrices.8 rm fort.* uncompress < $TEST_DIR/matrix.8A.Z > fort.37 uncompress < $TEST_DIR/matrix.8B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.8 input.dat testSerial 0 junk stdout 10 1 fort.37 fort.38 > res.mtx.8 echo matrices.9 rm fort.* uncompress < $TEST_DIR/matrix.9A.Z > fort.37 uncompress < $TEST_DIR/matrix.9B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.9 input.dat testSerial 0 junk stdout 10 1 fort.37 fort.38 > res.mtx.9 echo matrices.10 rm fort.* uncompress < $TEST_DIR/matrix.10A.Z > fort.37 uncompress < $TEST_DIR/matrix.10B.Z > fort.38 cp $TEST_DIR/jcp.inp.vib.10 input.dat testSerial 0 junk stdout 10 1 fort.37 fort.38 > res.mtx.10 echo matrices.11 rm fort.* uncompress < $TEST_DIR/matrix.11A.Z > fort.37 uncompress < $TEST_DIR/matrix.11B.Z > fort.38 cp $TEST_DIR/jcp.inp.buck.11 input.dat testSerial 0 junk stdout 10 2 fort.37 fort.38 > res.mtx.11 echo matrices.3_fiddle #rm fort.* #uncompress < $TEST_DIR/matrix.fid.3A.Z > fort.37 #uncompress < $TEST_DIR/matrix.fid.3B.Z > fort.38 #cp $TEST_DIR/jcp.inp.buck.3fid input.dat #testSerial 0 junk stdout 10 2 fort.37 fort.38 > res.mtx.3_fiddle quick_diff rm -f fort.* junk* stdout /tmp/*fil* res* *.dat Eigen/drivers/makefile010060000020550007177000000040130665314244300162730ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- # # set suffix rule *.c --> *.o # .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $(MPI_INCLUDE_DIR) $< # #----------------------------------------------------------------------- # # redefine CC for mpi on sgi # # CCmpi = /opt/mpi/bin/mpicc # #----------------------------------------------------------------------- F77 = f77 DRIVERS = testSerial testMT testMPI #----------------------------------------------------------------------- # environment on sparcstation 20 # # locations of eigensolver libraries # LANCZOS_ST_LIB = /home/pattersn/LANCZOS/lib/Serial_lncz.a LANCZOS_MT_LIB = /home/pattersn/LANCZOS/lib/MT_lncz.a LANCZOS_MPI_LIB = /home/pattersn/LANCZOS/lib/MPI_lncz.a # # locations of spooles libraries # SPOOLES_DIR = ../.. SPOOLES_LIB = $(SPOOLES_DIR)/spooles.a SPOOLES_MT_LIB = $(SPOOLES_DIR)/MT/src/spoolesMT.a SPOOLES_MPI_LIB = $(SPOOLES_DIR)/MPI/src/spoolesMPI.a # # libraries needed for the eigensolver # LIBS_FOR_ST = $(LANCZOS_ST_LIB) ../srcST/Bridge.a $(SPOOLES_LIB) -lm LIBS_FOR_MT = $(LANCZOS_MT_LIB) ../srcMT/BridgeMT.a \ $(SPOOLES_MT_LIB) $(SPOOLES_LIB) ${THREAD_LIBS} -lm LIBS_FOR_MPI = $(LANCZOS_MPI_LIB) ../srcMPI/BridgeMPI.a \ $(SPOOLES_MPI_LIB) $(SPOOLES_LIB) ${MPI_LIBS} -lm #----------------------------------------------------------------------- # # dependencies for Bridge objects # STlibs : cd ../srcST ; make Bridge.a MTlibs : cd ../srcMT ; make BridgeMT.a MPIlibs : cd ../srcMPI ; make BridgeMPI.a #----------------------------------------------------------------------- all_drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testSerial : testSerial.o STlibs ../../spooles.a ${PURIFY} ${F77} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS_FOR_ST} testMT : testMT.o MTlibs ../../spooles.a ${PURIFY} ${F77} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS_FOR_MT} testMPI : testMPI.o MPIlibs ../../spooles.a ${PURIFY} ${F77} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS_FOR_MPI} Eigen/drivers/testMPI.c010075500020550007177000000270770663677127700163340ustar00clevecompmath00000400000006/* testMPI.c */ #include "../BridgeMPI.h" void JimMatMulMPI ( ) ; void JimSolveMPI ( ) ; /*--------------------------------------------------------------------*/ void main ( int argc, char *argv[] ) /* ----------------------------------------------------------------- MPI environment: read in Harwell-Boeing matrices, using factor, solve, and multiply routines based on spooles, invoke eigensolver created -- 98mar31, jcp modified -- 98dec18, cca ----------------------------------------------------------------- */ { BridgeMPI bridge ; MPI_Comm comm ; char *inFileName_A, *inFileName_B, *parmFileName, *type ; char buffer[20], pbtype[4], which[4] ; int error, fstevl, lfinit, lstevl, msglvl, myid, mxbksz, ncol, ndiscd, neig, neigvl, nfound, nnonzeros, nproc, nrhs, nrow, prbtyp, rc, retc, rfinit, seed, warnng ; int c__5 = 5, output = 6 ; int *lanczos_wksp ; InpMtx *inpmtxA, *inpmtxB ; FILE *msgFile, *parmFile ; double lftend, rhtend, center, shfscl, t1, t2 ; double c__1 = 1.0, c__4 = 4.0, tolact = 2.309970868130169e-11 ; double eigval[1000], sigma[2] ; double *evec; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_dup(MPI_COMM_WORLD, &comm) ; MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; fprintf(stdout, "\n myid = %d", myid) ; fflush(stdout) ; /*--------------------------------------------------------------------*/ /* ----------------------------- decode the command line input ----------------------------- */ if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile parmFile seed inFileA inFileB" "\n msglvl -- message level" "\n msgFile -- message file" "\n parmFile -- input parameters file" "\n seed -- random number seed, used for ordering" "\n inFileA -- stiffness matrix, in Harwell-Boeing format" "\n inFileB -- mass matrix, in Harwell-Boeing format" "\n used for prbtyp = 1 or 2" "\n", argv[0]) ; return ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { int length = strlen(argv[2]) + 1 + 4 ; char *buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], buffer) ; return ; } CVfree(buffer) ; } parmFileName = argv[3] ; seed = atoi(argv[4]) ; inFileName_A = argv[5] ; inFileName_B = argv[6] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n message file -- %s" "\n parameter file -- %s" "\n stiffness matrix file -- %s" "\n mass matrix file -- %s" "\n random number seed -- %d" "\n", argv[0], msglvl, argv[2], parmFileName, inFileName_A, inFileName_B, seed) ; fflush(msgFile) ; if ( strcmp(inFileName_A, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } /*--------------------------------------------------------------------*/ if ( myid == 0 ) { /* ---------------------------------------------- processor zero reads in the matrix header info ---------------------------------------------- */ MARKTIME(t1) ; readHB_info(inFileName_A, &nrow, &ncol, &nnonzeros, &type, &nrhs) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in harwell-boeing header info", t2 - t1) ; fflush(msgFile) ; } MPI_Bcast((void *) &nrow, 1, MPI_INT, 0, MPI_COMM_WORLD) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- read in eigenvalue problem data neigvl -- # of desired eigenvalues which -- which eigenvalues to compute 'l' or 'L' lowest (smallest magnitude) 'h' or 'H' highest (largest magnitude) 'n' or 'N' nearest to central value 'c' or 'C' nearest to central value 'a' or 'A' all eigenvalues in interval pbtype -- type of problem 'v' or 'V' generalized symmetric problem (K,M) with M positive semidefinite (vibration problem) 'b' or 'B' generalized symmetric problem (K,K_s) with K positive semidefinite with K_s posibly indefinite (buckling problem) 'o' or 'O' ordinary symmetric eigenproblem lfinit -- if true, lftend is restriction on lower bound of eigenvalues. if false, no restriction on lower bound lftend -- left endpoint of interval rfinit -- if true, rhtend is restriction on upper bound of eigenvalues. if false, no restriction on upper bound rhtend -- right endpoint of interval center -- center of interval mxbksz -- upper bound on block size for Lanczos recurrence shfscl -- shift scaling parameter, an estimate on the magnitude of the smallest nonzero eigenvalues --------------------------------------------------------------- */ MARKTIME(t1) ; parmFile = fopen(parmFileName, "r"); fscanf(parmFile, "%d %s %s %d %le %d %le %le %d %le", &neigvl, which, pbtype, &lfinit, &lftend, &rfinit, &rhtend, ¢er, &mxbksz, &shfscl) ; fclose(parmFile); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in eigenvalue problem data", t2 - t1) ; fflush(msgFile) ; /* ---------------------------------------- check and set the problem type parameter ---------------------------------------- */ switch ( pbtype[1] ) { case 'v' : case 'V' : prbtyp = 1 ; break ; case 'b' : case 'B' : prbtyp = 2 ; break ; case 'o' : case 'O' : prbtyp = 3 ; break ; default : fprintf(stderr, "\n invalid problem type %s", pbtype) ; exit(-1) ; } /* ---------------------------- Initialize Lanczos workspace ---------------------------- */ MARKTIME(t1) ; lanczos_init_ ( &lanczos_wksp ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize Lanczos workspace", t2 - t1) ; fflush(msgFile) ; /* ---------------------------------- initialize communication structure ---------------------------------- */ MARKTIME(t1) ; lanczos_set_parm( &lanczos_wksp, "order-of-problem", &nrow, &retc ); lanczos_set_parm( &lanczos_wksp, "accuracy-tolerance", &tolact, &retc ); lanczos_set_parm( &lanczos_wksp, "max-block-size", &mxbksz, &retc ); lanczos_set_parm( &lanczos_wksp, "shift-scale", &shfscl, &retc ); lanczos_set_parm( &lanczos_wksp, "message_level", &msglvl, &retc ); lanczos_set_parm( &lanczos_wksp, "mpi-communicator", &comm, &retc ); lanczos_set_parm( &lanczos_wksp, "qfile-pathname", "lqfil", &retc ); lanczos_set_parm( &lanczos_wksp, "mqfil-pathname", "lmqfil", &retc ); lanczos_set_parm( &lanczos_wksp, "evfil-pathname", "evcfil", &retc ); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : init the lanczos communication structure", t2 - t1) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ if ( myid == 0 ) { /* ------------------------------------ processor zero reads in the matrices ------------------------------------ */ MARKTIME(t1) ; inpmtxA = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxA, inFileName_A ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in first matrix", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx A object after loading") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__1, &retc ); if ( prbtyp != 3 ) { if ( strcmp(inFileName_B, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; inpmtxB = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxB, inFileName_B ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in first matrix", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx B object after loading") ; InpMtx_writeForHumanEye(inpmtxB, msgFile) ; fflush(msgFile) ; } } else { inpmtxB = NULL ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__4, &retc ); } } else { /* ------------------------------------------------ other processors initialize their local matrices ------------------------------------------------ */ inpmtxA = InpMtx_new() ; InpMtx_init(inpmtxA, INPMTX_BY_CHEVRONS, SPOOLES_REAL, 0, 0) ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__1, &retc ); if ( prbtyp == 1 || prbtyp == 2 ) { inpmtxB = InpMtx_new() ; InpMtx_init(inpmtxB, INPMTX_BY_CHEVRONS, SPOOLES_REAL, 0, 0) ; } else { inpmtxB = NULL ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__4, &retc ); } } /* ----------------------------- set up the solver environment ----------------------------- */ MARKTIME(t1) ; rc = SetupMPI((void *) &bridge, &prbtyp, &nrow, &mxbksz, inpmtxA, inpmtxB, &seed, &msglvl, msgFile, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set up solver environment", t2 - t1) ; fflush(msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error return %d from SetupMPI()", rc) ; MPI_Finalize() ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- invoke eigensolver nfound -- # of eigenvalues found and kept ndisc -- # of additional eigenvalues discarded ----------------------------------------------- */ MARKTIME(t1) ; lanczos_run ( &neigvl, &which[1] , &pbtype[1], &lfinit, &lftend, &rfinit, &rhtend, ¢er, &lanczos_wksp, &bridge, &nfound, &ndiscd, &warnng, &error, FactorMPI, JimMatMulMPI, JimSolveMPI ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : time for lanczos run", t2 - t1) ; fflush(msgFile) ; if ( myid == 0 ) { /* ---------------------------------------------- processor 0 deals with eigenvalues and vectors ---------------------------------------------- */ MARKTIME(t1) ; neig = nfound + ndiscd ; lstevl = nfound ; lanczos_eigenvalues (&lanczos_wksp, eigval, &neig, &retc); fstevl = 1 ; if ( nfound == 0 ) fstevl = -1 ; if ( ndiscd > 0 ) lstevl = -ndiscd ; hdslp5_ ("computed eigenvalues returned by hdserl", &neig, eigval, &output, 39L ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvalues", t2 - t1) ; fflush(msgFile) ; /* ------------------------- get eigenvectors and print ------------------------- */ /* MARKTIME(t1) ; neig = min ( 50, nrow ); Lncz_ALLOCATE(evec, double, nrow, retc); for (i = 1; i<= nfound; i++) { lanczos_eigenvector(&lanczos_wksp, &i, &i, newToOld, evec, &nrow, &retc) ; hdslp5_("computed eigenvector returned by hdserc", &neig, evec, &output, 39L ) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvectors", t2 - t1) ; fflush(msgFile) ; */ } /* ------------------------ free the working storage ------------------------ */ MARKTIME(t1) ; lanczos_free(&lanczos_wksp) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free lanczos workspace", t2 - t1) ; fflush(msgFile) ; MARKTIME(t1) ; CleanupMPI(&bridge) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free solver workspace", t2 - t1) ; fflush(msgFile) ; MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return ; } Eigen/drivers/testMT.c010064400020550007177000000234350663672621400162050ustar00clevecompmath00000400000006/* testMT.c */ #include "../BridgeMT.h" void FactorMT ( ) ; void MatMulMT ( ) ; void SolveMT ( ) ; /*--------------------------------------------------------------------*/ void main ( int argc, char *argv[] ) /* ---------------------------------------------------------------- read in Harwell-Boeing matrices, using multithreaded factor, solve, and multiply routines based on spooles, invoke eigensolver created -- 98mar31, jcp modified -- 98dec18, cca ---------------------------------------------------------------- */ { BridgeMT bridge ; char *inFileName_A, *inFileName_B, *parmFileName, *type ; char buffer[20], pbtype[4], which[4] ; double lftend, rhtend, center, shfscl, t1, t2 ; double c__1 = 1.0, c__4 = 4.0, tolact = 2.309970868130169e-11 ; double eigval[1000], sigma[2]; double *evec; int error, fstevl, lfinit, lstevl, msglvl, mxbksz, ncol, ndiscd, neig, neigvl, nfound, nnonzeros, nrhs, nrow, nthreads, prbtyp, rc, retc, rfinit, seed, warnng ; int c__5 = 5, output = 6 ; int *lanczos_wksp; InpMtx *inpmtxA, *inpmtxB ; FILE *msgFile, *parmFile ; /*--------------------------------------------------------------------*/ if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile parmFile seed nthread inFileA inFileB" "\n msglvl -- message level" "\n msgFile -- message file" "\n parmFile -- input parameters file" "\n seed -- random number seed, used for ordering" "\n nthreads -- number of threads " "\n inFileA -- stiffness matrix, in Harwell-Boeing format" "\n inFileB -- mass matrix, in Harwell-Boeing format" "\n used for prbtype = 1 or 2" "\n", argv[0]) ; return ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n able to open file %s\n", argv[0], argv[2]) ; exit(-1) ; } parmFileName = argv[3] ; seed = atoi(argv[4]) ; nthreads = atoi(argv[5]) ; inFileName_A = argv[6] ; inFileName_B = argv[7] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n message file -- %s" "\n parameter file -- %s" "\n stiffness matrix file -- %s" "\n mass matrix file -- %s" "\n random number seed -- %d" "\n number of threads -- %d" "\n", argv[0], msglvl, argv[2], parmFileName, inFileName_A, inFileName_B, seed, nthreads) ; fflush(msgFile) ; /* --------------------------------------------- read in the Harwell-Boeing matrix information --------------------------------------------- */ if ( strcmp(inFileName_A, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; readHB_info (inFileName_A, &nrow, &ncol, &nnonzeros, &type, &nrhs) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in harwell-boeing header info", t2 - t1) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- read in eigenvalue problem data neigvl -- # of desired eigenvalues which -- which eigenvalues to compute 'l' or 'L' lowest (smallest magnitude) 'h' or 'H' highest (largest magnitude) 'n' or 'N' nearest to central value 'c' or 'C' nearest to central value 'a' or 'A' all eigenvalues in interval pbtype -- type of problem 'v' or 'V' generalized symmetric problem (K,M) with M positive semidefinite (vibration problem) 'b' or 'B' generalized symmetric problem (K,K_s) with K positive semidefinite with K_s posibly indefinite (buckling problem) 'o' or 'O' ordinary symmetric eigenproblem lfinit -- if true, lftend is restriction on lower bound of eigenvalues. if false, no restriction on lower bound lftend -- left endpoint of interval rfinit -- if true, rhtend is restriction on upper bound of eigenvalues. if false, no restriction on upper bound rhtend -- right endpoint of interval center -- center of interval mxbksz -- upper bound on block size for Lanczos recurrence shfscl -- shift scaling parameter, an estimate on the magnitude of the smallest nonzero eigenvalues --------------------------------------------------------------- */ MARKTIME(t1) ; parmFile = fopen(parmFileName, "r"); fscanf(parmFile, "%d %s %s %d %le %d %le %le %d %le", &neigvl, which, pbtype, &lfinit, &lftend, &rfinit, &rhtend, ¢er, &mxbksz, &shfscl) ; fclose(parmFile); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in eigenvalue problem data", t2 - t1) ; fflush(msgFile) ; /* ---------------------------------------- check and set the problem type parameter ---------------------------------------- */ switch ( pbtype[1] ) { case 'v' : case 'V' : prbtyp = 1 ; break ; case 'b' : case 'B' : prbtyp = 2 ; break ; case 'o' : case 'O' : prbtyp = 3 ; break ; default : fprintf(stderr, "\n invalid problem type %s", pbtype) ; exit(-1) ; } /* ---------------------------- Initialize Lanczos workspace ---------------------------- */ MARKTIME(t1) ; lanczos_init_ ( &lanczos_wksp ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize Lanczos workspace", t2 - t1) ; fflush(msgFile) ; /* ---------------------------------- initialize communication structure ---------------------------------- */ MARKTIME(t1) ; lanczos_set_parm( &lanczos_wksp, "order-of-problem", &nrow, &retc ); lanczos_set_parm( &lanczos_wksp, "accuracy-tolerance", &tolact, &retc); lanczos_set_parm( &lanczos_wksp, "max-block-size", &mxbksz, &retc ); lanczos_set_parm( &lanczos_wksp, "shift-scale", &shfscl, &retc ); lanczos_set_parm( &lanczos_wksp, "message_level", &msglvl, &retc ); lanczos_set_parm( &lanczos_wksp, "number-of-threads", &nthreads, &retc); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : init lanczos communication structure", t2 - t1) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- create the InpMtx objects for matrix A and B --------------------------------------------- */ if ( strcmp(inFileName_A, "none") == 0 ) { fprintf(msgFile, "\n no file to read A from") ; exit(-1) ; } MARKTIME(t1) ; inpmtxA = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxA, inFileName_A ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in A", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx A object after loading") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__1, &retc ); if ( prbtyp != 3 ) { if ( strcmp(inFileName_B, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; inpmtxB = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxB, inFileName_B ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in B", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx B object after loading") ; InpMtx_writeForHumanEye(inpmtxB, msgFile) ; fflush(msgFile) ; } } else { inpmtxB = NULL ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__4, &retc ); } /* ----------------------------- set up the solver environment ----------------------------- */ MARKTIME(t1) ; rc = SetupMT((void *) &bridge, &prbtyp, &nrow, &mxbksz, inpmtxA, inpmtxB, &seed, &nthreads, &msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set up the solver environment", t2 - t1) ; fflush(msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from SetupMT()", rc) ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- invoke eigensolver nfound -- # of eigenvalues found and kept ndisc -- # of additional eigenvalues discarded ----------------------------------------------- */ MARKTIME(t1) ; lanczos_run ( &neigvl, &which[1] , &pbtype[1], &lfinit, &lftend, &rfinit, &rhtend, ¢er, &lanczos_wksp, &bridge, &nfound, &ndiscd, &warnng, &error, FactorMT, MatMulMT, SolveMT ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : time for lanczos_run", t2 - t1) ; fflush(msgFile) ; /* ------------------------- get eigenvalues and print ------------------------- */ MARKTIME(t1) ; neig = nfound + ndiscd ; lstevl = nfound ; lanczos_eigenvalues (&lanczos_wksp, eigval, &neig, &retc); fstevl = 1 ; if ( nfound == 0 ) fstevl = -1 ; if ( ndiscd > 0 ) lstevl = -ndiscd ; hdslp5_ ("computed eigenvalues returned by hdserl", &neig, eigval, &output, 39L ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvalues", t2 - t1) ; fflush(msgFile) ; /* ------------------------- get eigenvectors and print ------------------------- */ /* MARKTIME(t1) ; neig = min ( 50, nrow ); Lncz_ALLOCATE(evec, double, nrow, retc); for (i = 1; i<= nfound; i++) {d lanczos_eigenvector ( &lanczos_wksp, &i, &i, newToOld, evec, &nrow, &retc ) ; hdslp5_ ( "computed eigenvector returned by hdserc", &neig, evec, &output, 39L ) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvectors", t2 - t1) ; fflush(msgFile) ; */ /* ------------------------ free the working storage ------------------------ */ MARKTIME(t1) ; lanczos_free( &lanczos_wksp ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free lanczos workspace", t2 - t1) ; fflush(msgFile) ; MARKTIME(t1) ; CleanupMT(&bridge) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free solver workspace", t2 - t1) ; fflush(msgFile) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return ; } Eigen/drivers/testSerial.c010064400020550007177000000232050663676100100170700ustar00clevecompmath00000400000006/* testSerial.c */ #include "../Bridge.h" void Factor ( ) ; void MatMul ( ) ; void Solve ( ) ; /*--------------------------------------------------------------------*/ void main ( int argc, char *argv[] ) /* ---------------------------------------------------------- read in Harwell-Boeing matrices, use serial factor, solve, and multiply routines based on spooles, invoke eigensolver created -- 98mar31 jcp modified -- 98dec18, cca ---------------------------------------------------------- */ { Bridge bridge ; char *inFileName_A, *inFileName_B, *outFileName, *parmFileName, *type ; char buffer[20], pbtype[4], which[4] ; double lftend, rhtend, center, shfscl, t1, t2 ; double c__1 = 1.0, c__4 = 4.0, tolact = 2.309970868130169e-11 ; double eigval[1000], sigma[2]; double *evec; int error, fstevl, lfinit, lstevl, mxbksz, msglvl, ncol, ndiscd, neig, neigvl, nfound, nnonzeros, nrhs, nrow, prbtyp, rc, retc, rfinit, seed, warnng ; int c__5 = 5, output = 6 ; int *lanczos_wksp; InpMtx *inpmtxA, *inpmtxB ; FILE *msgFile, *parmFile; /*--------------------------------------------------------------------*/ if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile parmFile seed inFileA inFileB" "\n msglvl -- message level" "\n msgFile -- message file" "\n parmFile -- input parameters file" "\n seed -- random number seed, used for ordering" "\n inFileA -- stiffness matrix in Harwell-Boeing format" "\n inFileB -- mass matrix in Harwell-Boeing format" "\n used for prbtyp = 1 or 2" "\n", argv[0]) ; return ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; exit(-1) ; } parmFileName = argv[3] ; seed = atoi(argv[4]) ; inFileName_A = argv[5] ; inFileName_B = argv[6] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n parmFile -- %s" "\n seed -- %d" "\n stiffness file -- %s" "\n mass file -- %s" "\n", argv[0], msglvl, argv[2], parmFileName, seed, inFileName_A, inFileName_B) ; fflush(msgFile) ; /* --------------------------------------------- read in the Harwell-Boeing matrix information --------------------------------------------- */ if ( strcmp(inFileName_A, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; readHB_info (inFileName_A, &nrow, &ncol, &nnonzeros, &type, &nrhs) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in header information for A", t2 - t1) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- read in eigenvalue problem data neigvl -- # of desired eigenvalues which -- which eigenvalues to compute 'l' or 'L' lowest (smallest magnitude) 'h' or 'H' highest (largest magnitude) 'n' or 'N' nearest to central value 'c' or 'C' nearest to central value 'a' or 'A' all eigenvalues in interval pbtype -- type of problem 'v' or 'V' generalized symmetric problem (K,M) with M positive semidefinite (vibration problem) 'b' or 'B' generalized symmetric problem (K,K_s) with K positive semidefinite with K_s posibly indefinite (buckling problem) 'o' or 'O' ordinary symmetric eigenproblem lfinit -- if true, lftend is restriction on lower bound of eigenvalues. if false, no restriction on lower bound lftend -- left endpoint of interval rfinit -- if true, rhtend is restriction on upper bound of eigenvalues. if false, no restriction on upper bound rhtend -- right endpoint of interval center -- center of interval mxbksz -- upper bound on block size for Lanczos recurrence shfscl -- shift scaling parameter, an estimate on the magnitude of the smallest nonzero eigenvalues --------------------------------------------------------------- */ MARKTIME(t1) ; parmFile = fopen(parmFileName, "r"); fscanf(parmFile, "%d %s %s %d %le %d %le %le %d %le", &neigvl, which, pbtype, &lfinit, &lftend, &rfinit, &rhtend, ¢er, &mxbksz, &shfscl) ; fclose(parmFile); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in eigenvalue problem data", t2 - t1) ; /* ---------------------------------------- check and set the problem type parameter ---------------------------------------- */ switch ( pbtype[1] ) { case 'v' : case 'V' : prbtyp = 1 ; break ; case 'b' : case 'B' : prbtyp = 2 ; break ; case 'o' : case 'O' : prbtyp = 3 ; break ; default : fprintf(stderr, "\n invalid problem type %s", pbtype) ; exit(-1) ; } /* ---------------------------- Initialize Lanczos workspace ---------------------------- */ MARKTIME(t1) ; lanczos_init_ ( &lanczos_wksp ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize lanczos workspace", t2 - t1) ; /* ---------------------------------- initialize communication structure ---------------------------------- */ MARKTIME(t1) ; lanczos_set_parm( &lanczos_wksp, "order-of-problem", &nrow, &retc ); lanczos_set_parm( &lanczos_wksp, "accuracy-tolerance", &tolact, &retc ); lanczos_set_parm( &lanczos_wksp, "max-block-size", &mxbksz, &retc ); lanczos_set_parm( &lanczos_wksp, "shift-scale", &shfscl, &retc ); lanczos_set_parm( &lanczos_wksp, "message_level", &msglvl, &retc ); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : init lanczos communication structure", t2 - t1) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- create the InpMtx objects for matrix A and B --------------------------------------------- */ if ( strcmp(inFileName_A, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; inpmtxA = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxA, inFileName_A ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in A", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx A object after loading") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__1, &retc ); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set A's parameters", t2 - t1) ; if ( prbtyp != 3 ) { if ( strcmp(inFileName_B, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; inpmtxB = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxB, inFileName_B ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in B", t2 - t1) ; } else { MARKTIME(t1) ; inpmtxB = NULL ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__4, &retc ); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set B's parameters", t2 - t1) ; } if ( msglvl > 2 && prbtyp != 3 ) { fprintf(msgFile, "\n\n InpMtx B object after loading") ; InpMtx_writeForHumanEye(inpmtxB, msgFile) ; fflush(msgFile) ; } /* ----------------------------- set up the solver environment ----------------------------- */ MARKTIME(t1) ; rc = Setup((void *) &bridge, &prbtyp, &nrow, &mxbksz, inpmtxA, inpmtxB, &seed, &msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set up solver environment", t2 - t1) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error %d from Setup()", rc) ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- invoke eigensolver nfound -- # of eigenvalues found and kept ndisc -- # of additional eigenvalues discarded ----------------------------------------------- */ MARKTIME(t1) ; lanczos_run(&neigvl, &which[1] , &pbtype[1], &lfinit, &lftend, &rfinit, &rhtend, ¢er, &lanczos_wksp, &bridge, &nfound, &ndiscd, &warnng, &error, Factor, MatMul, Solve ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : time for lanczos run", t2 - t1) ; /* ------------------------- get eigenvalues and print ------------------------- */ MARKTIME(t1) ; neig = nfound + ndiscd ; lstevl = nfound ; lanczos_eigenvalues (&lanczos_wksp, eigval, &neig, &retc); fstevl = 1 ; if ( nfound == 0 ) fstevl = -1 ; if ( ndiscd > 0 ) lstevl = -ndiscd ; hdslp5_ ("computed eigenvalues returned by hdserl", &neig, eigval, &output, 39L ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvalues ", t2 - t1) ; /* ------------------------- get eigenvectors and print ------------------------- */ /* MARKTIME(t1) ; neig = min ( 50, nrow ); Lncz_ALLOCATE(evec, double, nrow, retc); for ( i = 1 ; i <= nfound ; i++ ) { lanczos_eigenvector ( &lanczos_wksp, &i, &i, newToOld, evec, &nrow, &retc ) ; hdslp5_ ( "computed eigenvector returned by hdserc", &neig, evec, &output, 39L ) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvectors ", t2 - t1) ; */ /* ------------------------ free the working storage ------------------------ */ MARKTIME(t1) ; lanczos_free( &lanczos_wksp ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free lanczos workspace ", t2 - t1) ; MARKTIME(t1) ; rc = Cleanup(&bridge) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free solver workspace ", t2 - t1) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from Cleanup()", rc) ; exit(-1) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return ; } -------------------------------------*/ void main ( int argc, char *argv[] ) /* ---------------------------------------------------------- read in Harwell-Boeing matrices, use serial factor, solve, and multiply routines based on spooles, invoke eigensolver created -- 98mar31 jcp modified -- 98dec18, cca -----------------------------------------------------Eigen/drivers/fiddle.inp010064400020550007177000000000610663652160400165420ustar00clevecompmath0000040000000610 'l' 'b' 0 0.0e0 0 1.e20 0. 5 0.87332995124806 Eigen/drivers/mtx10.inp010064400020550007177000000000600663652152000162600ustar00clevecompmath0000040000000610 'l' 'v' 0 0.0e0 0 1.e20 0. 5 9.5636564981352 Eigen/drivers/mtx11.inp010064400020550007177000000000600663652154300162660ustar00clevecompmath0000040000000610 'l' 'v' 0 0.0e0 0 1.e20 0. 5 99447.067288973 Eigen/drivers/mtx3.inp010064400020550007177000000000620663652007000162030ustar00clevecompmath0000040000000610 'l' 'v' 0 0.0e0 0 1.e20 0. 5 0.87332995124806 Eigen/drivers/mtx4.inp010064400020550007177000000000660663652072300162150ustar00clevecompmath0000040000000610 'l' 'v' 0 0.0e0 0 1.e20 0. 5 5.3746168051265e-04 Eigen/drivers/mtx5.inp010064400020550007177000000000610663652107500162120ustar00clevecompmath0000040000000610 'l' 'v' 0 0.0e0 0 1.e20 0. 5 387589.03033154 Eigen/drivers/mtx6.inp010064400020550007177000000000600663652125500162120ustar00clevecompmath0000040000000610 'l' 'v' 0 0.0e0 0 1.e20 0. 5 79.625527957362 Eigen/drivers/mtx7.inp010064400020550007177000000000600663652137300162140ustar00clevecompmath0000040000000610 'l' 'v' 0 0.0e0 0 1.e20 0. 5 46.834305149396 Eigen/drivers/mtx8.inp010064400020550007177000000000600663652145400162150ustar00clevecompmath0000040000000610 'l' 'v' 0 0.0e0 0 1.e20 0. 5 4.8004558690386 Eigen/drivers/mtx9.inp010064400020550007177000000000600663652150100162070ustar00clevecompmath0000040000000610 'l' 'v' 0 0.0e0 0 1.e20 0. 5 2.7403158577391 Eigen/drivers/plat362.inp010064400020550007177000000000540663651641400165130ustar00clevecompmath0000040000000610 'l' 'o' 1 2.5e-5 1 2.4e-2 0. 2 2.0364e-5 Eigen/drivers/stk35.inp010064400020550007177000000000500663652232300162610ustar00clevecompmath00000400000006100 'l' 'v' 0 0.0e0 0 1.e20 0. 5 19.349 Eigen/drivers/spooles.pg010075500020550007177000000003740663654754400166440ustar00clevecompmath00000400000006chinacat 0 /local1/cleve/ARPA/release2.1/Eigen/drivers/testMPI chinacat 1 /local1/cleve/ARPA/release2.1/Eigen/drivers/testMPI chinacat 1 /local1/cleve/ARPA/release2.1/Eigen/drivers/testMPI chinacat 1 /local1/cleve/ARPA/release2.1/Eigen/drivers/testMPI Eigen/doc/004275500020550007177000000000000665315072600137045ustar00clevecompmath00000400000006Eigen/doc/MPI.tex010064400020550007177000000474340663677537500151000ustar00clevecompmath00000400000006\chapter{The MPI Bridge Object and Driver} \label{chapter:MPI} \par \section{The \texttt{BridgeMPI} Data Structure} \label{section:BridgeMPI:dataStructure} \par The {\tt BridgeMPI} structure has the following fields. \begin{itemize} % \item {\tt int prbtype} : problem type \begin{itemize} \item {\tt 1} --- vibration, a multiply with $B$ is required. \item {\tt 2} --- buckling, a multiply with $A$ is required. \item {\tt 3} --- simple, no multiply is required. \end{itemize} \item {\tt int neqns} : number of equations, i.e., number of vertices in the graph. \item {\tt int mxbsz} : block size for the Lanczos process. \item {\tt int nproc} : number of processors. \item {\tt int myid} : id (rank) of this processor. \item {\tt int seed} : random number seed used in the ordering. \item {\tt int coordFlag} : coordinate flag for local $A$ and $B$ matrices. \begin{itemize} \item 1 ({\tt LOCAL}) for local indices, needed for matrix-multiplies. \item 2 ({\tt GLOBAL}) for global indices, needed for factorizations. \end{itemize} \item {\tt InpMtx *A} : matrix object for $A$ \item {\tt InpMtx *B} : matrix object for $B$ \item {\tt Pencil *pencil} : object to hold linear combination of $A$ and $B$. \item {\tt ETree *frontETree} : object that defines the factorizations, e.g., the number of fronts, the tree they form, the number of internal and external rows for each front, and the map from vertices to the front where it is contained. \item {\tt IVL *symbfacIVL} : object that contains the symbolic factorization of the matrix. \item {\tt SubMtxManager *mtxmanager} : object that manages the \texttt{SubMtx} objects that store the factor entries and are used in the solves. \item {\tt FrontMtx *frontmtx} : object that stores the $L$, $D$ and $U$ factor matrices. \item {\tt IV *oldToNewIV} : object that stores old-to-new permutation vector. \item {\tt IV *newToOldIV} : object that stores new-to-old permutation vector. \item {\tt DenseMtx *Xloc} : dense {\it local} matrix object that is used during the matrix multiples and solves. \item {\tt DenseMtx *Yloc} : dense {\it local} matrix object that is used during the matrix multiples and solves. \item {\tt IV *vtxmapIV} : object that maps vertices to owning processors for the factorization and matrix-multiplies. \item {\tt IV *myownedIV} : object that contains a list of all vertices owned by this processor. \item {\tt IV *ownersIV} : object that maps fronts to owning processors for the factorization and matrix-multiplies. \item {\tt IV *rowmapIV} : if pivoting was performed for numerical stability, this object maps rows of the factor to processors. \item {\tt SolveMap *solvemap} : object that maps factor submatrices to owning threads for the solve. \item {\tt MatMulInfo *info} : object that holds all the communication information for a distributed matrix-multiply. \item {\tt int msglvl} : message level for output. When 0, no output, When 1, just statistics and cpu times. When greater than 1, more and more output. \item {\tt FILE *msgFile} : message file for output. When \texttt{msglvl} $>$ 0, \texttt{msgFile} must not be \texttt{NULL}. \item {\tt MPI\_Comm comm} : MPI communicator. \end{itemize} \par \section{Prototypes and descriptions of \texttt{BridgeMPI} methods} \label{section:BridgeMPI:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt BridgeMPI} object. \par In contrast to the serial and MT bridge objects, there are seven methods instead of five. In a distributed environment, data structures should be partitioned across processors. On the {\bf SPOOLES} side, the factor entries, and the $X$ and $Y$ matrices that take part in the solves and matrix-multiplies, are partitioned among the processors according to the ``front structure'' and vertex map of the factor matrices. The {\bf SPOOLES} solve and matrix-multiply bridge methods expect the {\it local} $X$ and $Y$ matrices. On the {\bf LANCZOS} side, the Krylov blocks and eigenvectors are partitioned across processors in a simple block manner. (The first of $p$ processors has the first $n/p$ rows, etc.) \par At the present time, the {\bf SPOOLES} and {\bf LANCZOS} software have no agreement on how the data should be partitioned. (For example, {\bf SPOOLES} could tell {\bf LANCZOS} how it wants the data to be partitioned, or {\bf LANCZOS} could tell {\bf SPOOLES} how it wants the data to be partitioned.) Therefore, inside the {\bf LANCZOS} software a global Krylov block is assembled on each processor prior to calling the solve or matrix-multiply methods. To ``translate'' between the global blocks to local blocks, and then back to global blocks, we have written two wrapper methods, {\tt JimMatMulMPI()} and {\tt JimSolveMPI()}. Each takes the global input block, compresses it into a local block, call the bridge matrix-multiply or solve method, then takes the local output blocks and gathers them on all the processors into each of their global output blocks. These operations add a considerable cost to the solve and matrix-multiplies, but the next release of the {\bf LANCZOS} software will remove these steps. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SetupMPI ( void *data, int *pprbtype, int *pneqns, int *pmxbsz, InpMtx *A, InpMtx *B, int *pseed, int *pmsglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{SetupMPI@{\tt SetupMPI()}} \noindent All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt void *data} --- a pointer to the {\tt BridgeMPI} object. \item {\tt int *pprbtype} --- {\tt *pprbtype} holds the problem type. \begin{itemize} \item {\tt 1} --- vibration, a multiply with $B$ is required. \item {\tt 2} --- buckling, a multiply with $A$ is required. \item {\tt 3} --- simple, no multiply is required. \end{itemize} \item {\tt int *pneqns} --- {\tt *pneqns} is the number of equations. \item {\tt int *pmxbsz} --- {\tt *pmxbsz} is an upper bound on the block size. \item {\tt InpMtx *A} --- {\tt A} is a {\bf SPOOLES} object that holds the matrix $A$. \item {\tt InpMtx *B} --- {\tt B} is a {\bf SPOOLES} object that holds the matrix $B$. For an ordinary eigenproblem, $B$ is the identity and {\tt B} is {\tt NULL}. \item {\tt int *pseed} --- {\tt *pseed} is a random number seed. \item {\tt int *pmsglvl} --- {\tt *pmsglvl} is a message level for the bridge methods and the {\bf SPOOLES} methods they call. \item {\tt FILE *pmsglvl} --- {\tt msgFile} is the message file for the bridge methods and the {\bf SPOOLES} methods they call. \item {\tt MPI\_Comm comm} --- MPI communicator. matrix-multiplies. \end{itemize} This method must be called in the driver program prior to invoking the eigensolver via a call to {\tt lanczos\_run()}. It then follows this sequence of action. \begin{itemize} \item The method begins by checking all the input data, and setting the appropriate fields of the {\tt BridgeMPI} object. \item The {\tt pencil} object is initialized with {\tt A} and {\tt B}. \item {\tt A} and {\tt B} are converted to storage by rows and vector mode. \item A {\tt Graph} object is created that contains the sparsity pattern of the union of {\tt A} and {\tt B}. \item The graph is ordered by first finding a recursive dissection partition, and then evaluating the orderings produced by nested dissection and multisection, and choosing the better of the two. The {\tt frontETree} object is produced and placed into the {\tt bridge} object. \item Old-to-new and new-to-old permutations are extracted from the front tree and loaded into the {\tt BridgeMPI} object. \item The vertices in the front tree are permuted, as well as the entries in {\tt A} and {\tt B}. Entries in the lower triangle of {\tt A} and {\tt B} are mapped into the upper triangle, and the storage modes of {\tt A} and {\tt B} are changed to chevrons and vectors, in preparation for the first factorization. \item The {\tt ownersIV}, {\tt vtxmapIV} and {\tt myownedIV} objects are created, that map fronts and vertices to processors. \item The entries in {\tt A} and {\tt B} are permuted. Entries in the permuted lower triangle are mapped into the upper triangle. The storage modes of {\tt A} and {\tt B} are changed to chevrons and vectors, and the entries of {\tt A} and {\tt B} are redistributed to the processors that own them. \item The symbolic factorization is then computed and loaded in the {\tt BridgeMPI} object. \item A {\tt FrontMtx} object is created to hold the factorization and loaded into the {\tt BridgeMPI} object. \item A {\tt SubMtxManager} object is created to hold the factor's submatrices and loaded into the {\tt BridgeMPI} object. \item The map from factor submatrices to their owning threads is computed and stored in the {\tt solvemap} object. \item The distributed matrix-multiplies are set up. \end{itemize} The {\tt A} and {\tt B} matrices are now in their permuted ordering, i.e., $PAP^T$ and $PBP^T$, and all data structures are with respect to this ordering. After the Lanczos run completes, any generated eigenvectors must be permuted back into their original ordering using the {\tt oldToNewIV} and {\tt newToOldIV} objects. \par \noindent {\it Return value:} \begin{center} \begin{tabular}[t]{rl} ~1 & normal return \\ -1 & \texttt{data} is \texttt{NULL} \\ -2 & \texttt{pprbtype} is \texttt{NULL} \\ -3 & \texttt{*pprbtype} is invalid \\ -4 & \texttt{pneqns} is \texttt{NULL} \\ -5 & \texttt{*pneqns} is invalid \\ -6 & \texttt{pmxbsz} is \texttt{NULL} \end{tabular} \begin{tabular}[t]{rl} -7 & \texttt{*pmxbsz} is invalid \\ -8 & \texttt{A} and \texttt{B} are \texttt{NULL} \\ -9 & \texttt{seed} is \texttt{NULL} \\ -10 & \texttt{msglvl} is \texttt{NULL} \\ -11 & $\texttt{msglvl} > 0$ and \texttt{msgFile} is \texttt{NULL} \\ -12 & \texttt{comm} is \texttt{NULL} \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} void FactorMPI ( double *psigma, double *ppvttol, void *data, int *pinertia, int *perror ) ; \end{verbatim} \index{FactorMPI@{\tt FactorMPI()}} This method computes the factorization of $A - \sigma B$. All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt double *psigma} --- the shift parameter $\sigma$ is found in {\tt *psigma}. \item {\tt double *ppvttol} --- the pivot tolerance is found in {\tt *ppvttol}. When ${\tt *ppvttol} = 0.0$, the factorization is computed without pivoting for stability. When ${\tt *ppvttol} > 0.0$, the factorization is computed with pivoting for stability, and all offdiagonal entries have magnitudes bounded above by $1/({\tt *ppvttol})$. \item {\tt void *data} --- a pointer to the {\tt BridgeMPI} object. \item {\tt int *pinertia} --- on return, {\tt *pinertia} holds the number of negative eigenvalues. \item {\tt int *perror} --- on return, {\tt *perror} holds an error code. \begin{center} \begin{tabular}[t]{rl} ~1 & error in the factorization \\ ~0 & normal return \\ -1 & \texttt{psigma} is \texttt{NULL} \end{tabular} \begin{tabular}[t]{rl} -2 & \texttt{ppvttol} is \texttt{NULL} \\ -3 & \texttt{data} is \texttt{NULL} \\ -4 & \texttt{pinertia} is \texttt{NULL} \end{tabular} \end{center} \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} void JimMatMulMPI ( int *pnrows, int *pncols, double X[], double Y[], int *pprbtype, void *data ) ; \end{verbatim} \index{JimMatMulMPI@{\tt JimMatMulMPI()}} This method computes a multiply of the form $Y = I X$, $Y = A X$ or $Y = B X$. All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt int *pnrows} --- {\tt *pnrows} contains the number of {\it global} rows in $X$ and $Y$. \item {\tt int *pncols} --- {\tt *pncols} contains the number of {\it global} columns in $X$ and $Y$. \item {\tt double X[]} --- this is the {\it global} $X$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt double Y[]} --- this is the {\it global} $Y$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt int *pprbtype} --- {\tt *pprbtype} holds the problem type. \begin{itemize} \item {\tt 1} --- vibration, a multiply with $B$ is required. \item {\tt 2} --- buckling, a multiply with $A$ is required. \item {\tt 3} --- simple, no multiply is required. \end{itemize} \item {\tt void *data} --- a pointer to the {\tt BridgeMPI} object. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} void MatMulMPI ( int *pnrows, int *pncols, double X[], double Y[], int *pprbtype, void *data ) ; \end{verbatim} \index{MatMulMPI@{\tt MatMulMPI()}} This method computes a multiply of the form $Y = I X$, $Y = A X$ or $Y = B X$. All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt int *pnrows} --- {\tt *pnrows} contains the number of {\it local} rows in $X$ and $Y$. \item {\tt int *pncols} --- {\tt *pncols} contains the number of {\it local} columns in $X$ and $Y$. \item {\tt double X[]} --- this is the {\it local} $X$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt double Y[]} --- this is the {\it local} $Y$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt int *pprbtype} --- {\tt *pprbtype} holds the problem type. \begin{itemize} \item {\tt 1} --- vibration, a multiply with $B$ is required. \item {\tt 2} --- buckling, a multiply with $A$ is required. \item {\tt 3} --- simple, no multiply is required. \end{itemize} \item {\tt void *data} --- a pointer to the {\tt BridgeMPI} object. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} void JimSolveMPI ( int *pnrows, int *pncols, double X[], double Y[], void *data, int *perror ) ; \end{verbatim} \index{JimSolveMPI@{\tt JimSolveMPI()}} This method solves $(A - \sigma B) X = Y$, where $(A - \sigma B)$ has been factored by a previous call to {\tt Factor()}. All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt int *pnrows} --- {\tt *pnrows} contains the number of {\it global} rows in $X$ and $Y$. \item {\tt int *pncols} --- {\tt *pncols} contains the number of {\it global} columns in $X$ and $Y$. \item {\tt double X[]} --- this is the {\it global} $X$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt double Y[]} --- this is the {\it global} $Y$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt void *data} --- a pointer to the {\tt BridgeMPI} object. \item {\tt int *perror} --- on return, {\tt *perror} holds an error code. \begin{center} \begin{tabular}[t]{rl} ~1 & normal return \\ -1 & \texttt{pnrows} is \texttt{NULL} \\ -2 & \texttt{pncols} is \texttt{NULL} \end{tabular} \begin{tabular}[t]{rl} -3 & \texttt{X} is \texttt{NULL} \\ -4 & \texttt{Y} is \texttt{NULL} \\ -5 & \texttt{data} is \texttt{NULL} \end{tabular} \end{center} \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} void SolveMPI ( int *pnrows, int *pncols, double X[], double Y[], void *data, int *perror ) ; \end{verbatim} \index{SolveMPI@{\tt SolveMPI()}} This method solves $(A - \sigma B) X = Y$, where $(A - \sigma B)$ has been factored by a previous call to {\tt Factor()}. All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt int *pnrows} --- {\tt *pnrows} contains the number of {\it local} rows in $X$ and $Y$. \item {\tt int *pncols} --- {\tt *pncols} contains the number of {\it local} columns in $X$ and $Y$. \item {\tt double X[]} --- this is the {\it local} $X$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt double Y[]} --- this is the {\it local} $Y$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt void *data} --- a pointer to the {\tt BridgeMPI} object. \item {\tt int *perror} --- on return, {\tt *perror} holds an error code. \begin{center} \begin{tabular}[t]{rl} ~1 & normal return \\ -1 & \texttt{pnrows} is \texttt{NULL} \\ -2 & \texttt{pncols} is \texttt{NULL} \end{tabular} \begin{tabular}[t]{rl} -3 & \texttt{X} is \texttt{NULL} \\ -4 & \texttt{Y} is \texttt{NULL} \\ -5 & \texttt{data} is \texttt{NULL} \end{tabular} \end{center} \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} int CleanupMPI ( void *data ) ; \end{verbatim} \index{CleanupMPI@{\tt CleanupMPI()}} This method releases all the storage used by the {\bf SPOOLES} library functions. \par \noindent {\it Return value:} 1 for a normal return, -1 if a {\tt data} is {\tt NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \section{The \texttt{testMPI} Driver Program} \label{section:BridgeMPI:driver} \par A complete listing of the multithreaded driver program is found in chapter~\ref{chapter:MPI_driver}. The program is invoked by this command sequence. \begin{verbatim} testMPI msglvl msgFile parmFile seed inFileA inFileB \end{verbatim} where \begin{itemize} \item {\tt msglvl} is the message level for the {\tt BridgeMPI} methods and the {\bf SPOOLES} software. \item {\tt msgFile} is the message file for the {\tt BridgeMPI} methods and the {\bf SPOOLES} software. \item {\tt parmFile} is the input file for the parameters of the eigensystem to be solved. \item {\tt seed} is a random number seed used by the {\bf SPOOLES} software. \item {\tt inFileA} is the Harwell-Boeing file for the matrix $A$. \item {\tt inFileB} is the Harwell-Boeing file for the matrix $B$. \end{itemize} This program is executed for some sample matrices by the {\tt do\_ST\_*} shell scripts in the {\tt drivers} directory. \par Here is a short description of the steps in the driver program. See Chapter~\ref{chapter:serial_driver} for the listing. \begin{enumerate} \item Each processor determines the number of processors and its rank. \item Each processor decodes the command line inputs. \item Processor {\tt 0} reads the header of the Harwell-Boeing file for $A$ and broadcasts the number of equations to all processors. \item Each processor reads from the {\tt parmFile} file the parameters that define the eigensystem to be solved. \item Each processor initializes its Lanczos eigensolver workspace. \item Each processor fills its Lanczos communication structure with some parameters. \item Processor {\tt 0} reads in the $A$ and possibly $B$ matrices from the Harwell-Boeing files and converts them into {\tt InpMtx} objects from the {\bf SPOOLES} library. The other processors initialize their local {\tt InpMtx} objects. \item Each processor initializes its linear solver environment via a call to {\tt SetupMPI()}. \item Each processor invokes the eigensolver via a call to {\tt lanczos\_run()}. The {\tt FactorMPI()}, {\tt JimSolveMPI()} and {\tt JimMatMulMPI()} methods are passed to this routine. \item Processor zero extracts the eigenvalues via a call to {\tt lanczos\_eigenvalues()} and prints them out. \item Processor zero extracts the eigenvectors via a call to {\tt lanczos\_eigenvectors()} and prints them out. \item Each processor free's the eigensolver working storage via a call to {\tt lanczos\_free()}. \item Each processor free's the linear solver working storage via a call to {\tt CleanupMPI()}. \end{enumerate} d{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} void FactorMPI ( double *psigma, double *ppvttol, void *data, int *pinertia, int *perror ) Eigen/doc/MPI_driver.tex010064400020550007177000000272560663677164000164420ustar00clevecompmath00000400000006\chapter{{\tt testMPI.c} --- A MPI Driver Program} \label{chapter:MPI_driver} \begin{verbatim} /* testMPI.c */ #include "../BridgeMPI.h" void JimMatMulMPI ( ) ; void JimSolveMPI ( ) ; /*--------------------------------------------------------------------*/ void main ( int argc, char *argv[] ) /* ----------------------------------------------------------------- MPI environment: read in Harwell-Boeing matrices, using factor, solve, and multiply routines based on spooles, invoke eigensolver created -- 98mar31, jcp modified -- 98dec18, cca ----------------------------------------------------------------- */ { BridgeMPI bridge ; MPI_Comm comm ; char *inFileName_A, *inFileName_B, *parmFileName, *type ; char buffer[20], pbtype[4], which[4] ; int error, fstevl, lfinit, lstevl, msglvl, myid, mxbksz, ncol, ndiscd, neig, neigvl, nfound, nnonzeros, nproc, nrhs, nrow, prbtyp, rc, retc, rfinit, seed, warnng ; int c__5 = 5, output = 6 ; int *lanczos_wksp ; InpMtx *inpmtxA, *inpmtxB ; FILE *msgFile, *parmFile ; double lftend, rhtend, center, shfscl, t1, t2 ; double c__1 = 1.0, c__4 = 4.0, tolact = 2.309970868130169e-11 ; double eigval[1000], sigma[2] ; double *evec; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_dup(MPI_COMM_WORLD, &comm) ; MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; fprintf(stdout, "\n myid = %d", myid) ; fflush(stdout) ; /*--------------------------------------------------------------------*/ /* ----------------------------- decode the command line input ----------------------------- */ if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile parmFile seed inFileA inFileB" "\n msglvl -- message level" "\n msgFile -- message file" "\n parmFile -- input parameters file" "\n seed -- random number seed, used for ordering" "\n inFileA -- stiffness matrix, in Harwell-Boeing format" "\n inFileB -- mass matrix, in Harwell-Boeing format" "\n used for prbtyp = 1 or 2" "\n", argv[0]) ; return ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { int length = strlen(argv[2]) + 1 + 4 ; char *buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], buffer) ; return ; } CVfree(buffer) ; } parmFileName = argv[3] ; seed = atoi(argv[4]) ; inFileName_A = argv[5] ; inFileName_B = argv[6] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n message file -- %s" "\n parameter file -- %s" "\n stiffness matrix file -- %s" "\n mass matrix file -- %s" "\n random number seed -- %d" "\n", argv[0], msglvl, argv[2], parmFileName, inFileName_A, inFileName_B, seed) ; fflush(msgFile) ; if ( strcmp(inFileName_A, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } /*--------------------------------------------------------------------*/ if ( myid == 0 ) { /* ---------------------------------------------- processor zero reads in the matrix header info ---------------------------------------------- */ MARKTIME(t1) ; readHB_info(inFileName_A, &nrow, &ncol, &nnonzeros, &type, &nrhs) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in harwell-boeing header info", t2 - t1) ; fflush(msgFile) ; } MPI_Bcast((void *) &nrow, 1, MPI_INT, 0, MPI_COMM_WORLD) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- read in eigenvalue problem data neigvl -- # of desired eigenvalues which -- which eigenvalues to compute 'l' or 'L' lowest (smallest magnitude) 'h' or 'H' highest (largest magnitude) 'n' or 'N' nearest to central value 'c' or 'C' nearest to central value 'a' or 'A' all eigenvalues in interval pbtype -- type of problem 'v' or 'V' generalized symmetric problem (K,M) with M positive semidefinite (vibration problem) 'b' or 'B' generalized symmetric problem (K,K_s) with K positive semidefinite with K_s posibly indefinite (buckling problem) 'o' or 'O' ordinary symmetric eigenproblem lfinit -- if true, lftend is restriction on lower bound of eigenvalues. if false, no restriction on lower bound lftend -- left endpoint of interval rfinit -- if true, rhtend is restriction on upper bound of eigenvalues. if false, no restriction on upper bound rhtend -- right endpoint of interval center -- center of interval mxbksz -- upper bound on block size for Lanczos recurrence shfscl -- shift scaling parameter, an estimate on the magnitude of the smallest nonzero eigenvalues --------------------------------------------------------------- */ MARKTIME(t1) ; parmFile = fopen(parmFileName, "r"); fscanf(parmFile, "%d %s %s %d %le %d %le %le %d %le", &neigvl, which, pbtype, &lfinit, &lftend, &rfinit, &rhtend, ¢er, &mxbksz, &shfscl) ; fclose(parmFile); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in eigenvalue problem data", t2 - t1) ; fflush(msgFile) ; /* ---------------------------------------- check and set the problem type parameter ---------------------------------------- */ switch ( pbtype[1] ) { case 'v' : case 'V' : prbtyp = 1 ; break ; case 'b' : case 'B' : prbtyp = 2 ; break ; case 'o' : case 'O' : prbtyp = 3 ; break ; default : fprintf(stderr, "\n invalid problem type %s", pbtype) ; exit(-1) ; } /* ---------------------------- Initialize Lanczos workspace ---------------------------- */ MARKTIME(t1) ; lanczos_init_ ( &lanczos_wksp ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize Lanczos workspace", t2 - t1) ; fflush(msgFile) ; /* ---------------------------------- initialize communication structure ---------------------------------- */ MARKTIME(t1) ; lanczos_set_parm( &lanczos_wksp, "order-of-problem", &nrow, &retc ); lanczos_set_parm( &lanczos_wksp, "accuracy-tolerance", &tolact, &retc ); lanczos_set_parm( &lanczos_wksp, "max-block-size", &mxbksz, &retc ); lanczos_set_parm( &lanczos_wksp, "shift-scale", &shfscl, &retc ); lanczos_set_parm( &lanczos_wksp, "message_level", &msglvl, &retc ); lanczos_set_parm( &lanczos_wksp, "mpi-communicator", &comm, &retc ); lanczos_set_parm( &lanczos_wksp, "qfile-pathname", "lqfil", &retc ); lanczos_set_parm( &lanczos_wksp, "mqfil-pathname", "lmqfil", &retc ); lanczos_set_parm( &lanczos_wksp, "evfil-pathname", "evcfil", &retc ); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : init the lanczos communication structure", t2 - t1) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ if ( myid == 0 ) { /* ------------------------------------ processor zero reads in the matrices ------------------------------------ */ MARKTIME(t1) ; inpmtxA = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxA, inFileName_A ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in first matrix", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx A object after loading") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__1, &retc ); if ( prbtyp != 3 ) { if ( strcmp(inFileName_B, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; inpmtxB = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxB, inFileName_B ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in first matrix", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx B object after loading") ; InpMtx_writeForHumanEye(inpmtxB, msgFile) ; fflush(msgFile) ; } } else { inpmtxB = NULL ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__4, &retc ); } } else { /* ------------------------------------------------ other processors initialize their local matrices ------------------------------------------------ */ inpmtxA = InpMtx_new() ; InpMtx_init(inpmtxA, INPMTX_BY_CHEVRONS, SPOOLES_REAL, 0, 0) ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__1, &retc ); if ( prbtyp == 1 || prbtyp == 2 ) { inpmtxB = InpMtx_new() ; InpMtx_init(inpmtxB, INPMTX_BY_CHEVRONS, SPOOLES_REAL, 0, 0) ; } else { inpmtxB = NULL ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__4, &retc ); } } /* ----------------------------- set up the solver environment ----------------------------- */ MARKTIME(t1) ; rc = SetupMPI((void *) &bridge, &prbtyp, &nrow, &mxbksz, inpmtxA, inpmtxB, &seed, &msglvl, msgFile, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set up solver environment", t2 - t1) ; fflush(msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error return %d from SetupMPI()", rc) ; MPI_Finalize() ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- invoke eigensolver nfound -- # of eigenvalues found and kept ndisc -- # of additional eigenvalues discarded ----------------------------------------------- */ MARKTIME(t1) ; lanczos_run ( &neigvl, &which[1] , &pbtype[1], &lfinit, &lftend, &rfinit, &rhtend, ¢er, &lanczos_wksp, &bridge, &nfound, &ndiscd, &warnng, &error, FactorMPI, JimMatMulMPI, JimSolveMPI ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : time for lanczos run", t2 - t1) ; fflush(msgFile) ; if ( myid == 0 ) { /* ---------------------------------------------- processor 0 deals with eigenvalues and vectors ---------------------------------------------- */ MARKTIME(t1) ; neig = nfound + ndiscd ; lstevl = nfound ; lanczos_eigenvalues (&lanczos_wksp, eigval, &neig, &retc); fstevl = 1 ; if ( nfound == 0 ) fstevl = -1 ; if ( ndiscd > 0 ) lstevl = -ndiscd ; hdslp5_ ("computed eigenvalues returned by hdserl", &neig, eigval, &output, 39L ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvalues", t2 - t1) ; fflush(msgFile) ; /* ------------------------- get eigenvectors and print ------------------------- */ /* MARKTIME(t1) ; neig = min ( 50, nrow ); Lncz_ALLOCATE(evec, double, nrow, retc); for (i = 1; i<= nfound; i++) { lanczos_eigenvector(&lanczos_wksp, &i, &i, newToOld, evec, &nrow, &retc) ; hdslp5_("computed eigenvector returned by hdserc", &neig, evec, &output, 39L ) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvectors", t2 - t1) ; fflush(msgFile) ; */ } /* ------------------------ free the working storage ------------------------ */ MARKTIME(t1) ; lanczos_free(&lanczos_wksp) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free lanczos workspace", t2 - t1) ; fflush(msgFile) ; MARKTIME(t1) ; CleanupMPI(&bridge) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free solver workspace", t2 - t1) ; fflush(msgFile) ; MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return ; } \end{verbatim} Eigen/doc/MT.tex010064400020550007177000000340140663676736500147610ustar00clevecompmath00000400000006\chapter{The Multithreaded Bridge Object and Driver} \label{chapter:MT} \par \section{The \texttt{BridgeMT} Data Structure} \label{section:BridgeMT:dataStructure} \par The {\tt BridgeMT} structure has the following fields. \begin{itemize} % \item {\tt int prbtype} : problem type \begin{itemize} \item {\tt 1} --- vibration, a multiply with $B$ is required. \item {\tt 2} --- buckling, a multiply with $A$ is required. \item {\tt 3} --- simple, no multiply is required. \end{itemize} \item {\tt int neqns} : number of equations, i.e., number of vertices in the graph. \item {\tt int mxbsz} : block size for the Lanczos process. \item {\tt int nthread} : number of threads to use. \item {\tt int seed} : random number seed used in the ordering. \item {\tt InpMtx *A} : matrix object for $A$ \item {\tt InpMtx *B} : matrix object for $B$ \item {\tt Pencil *pencil} : object to hold linear combination of $A$ and $B$. \item {\tt ETree *frontETree} : object that defines the factorizations, e.g., the number of fronts, the tree they form, the number of internal and external rows for each front, and the map from vertices to the front where it is contained. \item {\tt IVL *symbfacIVL} : object that contains the symbolic factorization of the matrix. \item {\tt SubMtxManager *mtxmanager} : object that manages the \texttt{SubMtx} objects that store the factor entries and are used in the solves. \item {\tt FrontMtx *frontmtx} : object that stores the $L$, $D$ and $U$ factor matrices. \item {\tt IV *oldToNewIV} : object that stores old-to-new permutation vector. \item {\tt IV *newToOldIV} : object that stores new-to-old permutation vector. \item {\tt DenseMtx *X} : dense matrix object that is used during the matrix multiples and solves. \item {\tt DenseMtx *Y} : dense matrix object that is used during the matrix multiples and solves. \item {\tt IV *ownersIV} : object that maps fronts to owning threads for the factorization and matrix-multiplies. \item {\tt SolveMap *solvemap} : object that maps factor submatrices to owning threads for the solve. \item {\tt int msglvl} : message level for output. When 0, no output, When 1, just statistics and cpu times. When greater than 1, more and more output. \item {\tt FILE *msgFile} : message file for output. When \texttt{msglvl} $>$ 0, \texttt{msgFile} must not be \texttt{NULL}. \end{itemize} \par \section{Prototypes and descriptions of \texttt{BridgeMT} methods} \label{section:BridgeMT:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt BridgeMT} object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SetupMT ( void *data, int *pprbtype, int *pneqns, int *pmxbsz, InpMtx *A, InpMtx *B, int *pseed, int *pnthread, int *pmsglvl, FILE *msgFile ) ; \end{verbatim} \index{SetupMT@{\tt SetupMT()}} \noindent All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt void *data} --- a pointer to the {\tt BridgeMT} object. \item {\tt int *pprbtype} --- {\tt *pprbtype} holds the problem type. \begin{itemize} \item {\tt 1} --- vibration, a multiply with $B$ is required. \item {\tt 2} --- buckling, a multiply with $A$ is required. \item {\tt 3} --- simple, no multiply is required. \end{itemize} \item {\tt int *pneqns} --- {\tt *pneqns} is the number of equations. \item {\tt int *pmxbsz} --- {\tt *pmxbsz} is an upper bound on the block size. \item {\tt InpMtx *A} --- {\tt A} is a {\bf SPOOLES} object that holds the matrix $A$. \item {\tt InpMtx *B} --- {\tt B} is a {\bf SPOOLES} object that holds the matrix $B$. For an ordinary eigenproblem, $B$ is the identity and {\tt B} is {\tt NULL}. \item {\tt int *pseed} --- {\tt *pseed} is a random number seed. \item {\tt int *pnthread} --- {\tt *pnthread} is the number of threads to use during the factorizations, solves and matrix-multiplies. \item {\tt int *pmsglvl} --- {\tt *pmsglvl} is a message level for the bridge methods and the {\bf SPOOLES} methods they call. \item {\tt FILE *pmsglvl} --- {\tt msgFile} is the message file for the bridge methods and the {\bf SPOOLES} methods they call. \end{itemize} This method must be called in the driver program prior to invoking the eigensolver via a call to {\tt lanczos\_run()}. It then follows this sequence of action. \begin{itemize} \item The method begins by checking all the input data, and setting the appropriate fields of the {\tt BridgeMT} object. \item The {\tt pencil} object is initialized with {\tt A} and {\tt B}. \item {\tt A} and {\tt B} are converted to storage by rows and vector mode. \item A {\tt Graph} object is created that contains the sparsity pattern of the union of {\tt A} and {\tt B}. \item The graph is ordered by first finding a recursive dissection partition, and then evaluating the orderings produced by nested dissection and multisection, and choosing the better of the two. The {\tt frontETree} object is produced and placed into the {\tt bridge} object. \item Old-to-new and new-to-old permutations are extracted from the front tree and loaded into the {\tt BridgeMT} object. \item The vertices in the front tree are permuted, as well as the entries in {\tt A} and {\tt B}. Entries in the lower triangle of {\tt A} and {\tt B} are mapped into the upper triangle, and the storage modes of {\tt A} and {\tt B} are changed to chevrons and vectors, in preparation for the first factorization. \item The symbolic factorization is then computed and loaded in the {\tt BridgeMT} object. \item A {\tt FrontMtx} object is created to hold the factorization and loaded into the {\tt BridgeMT} object. \item A {\tt SubMtxManager} object is created to hold the factor's submatrices and loaded into the {\tt BridgeMT} object. \item Two {\tt DenseMtx} objects are created to be used during the matrix multiplies and solves. \item The map from fronts to their owning threads is computed and stored in the {\tt ownersIV} object. \item The map from factor submatrices to their owning threads is computed and stored in the {\tt solvemap} object. \end{itemize} The {\tt A} and {\tt B} matrices are now in their permuted ordering, i.e., $PAP^T$ and $PBP^T$, and all data structures are with respect to this ordering. After the Lanczos run completes, any generated eigenvectors must be permuted back into their original ordering using the {\tt oldToNewIV} and {\tt newToOldIV} objects. \par \noindent {\it Return value:} \begin{center} \begin{tabular}[t]{rl} ~1 & normal return \\ -1 & \texttt{data} is \texttt{NULL} \\ -2 & \texttt{pprbtype} is \texttt{NULL} \\ -3 & \texttt{*pprbtype} is invalid \\ -4 & \texttt{pneqns} is \texttt{NULL} \\ -5 & \texttt{*pneqns} is invalid \\ -6 & \texttt{pmxbsz} is \texttt{NULL} \end{tabular} \begin{tabular}[t]{rl} -7 & \texttt{*pmxbsz} is invalid \\ -8 & \texttt{A} and \texttt{B} are \texttt{NULL} \\ -9 & \texttt{seed} is \texttt{NULL} \\ -10 & \texttt{msglvl} is \texttt{NULL} \\ -11 & $\texttt{msglvl} > 0$ and \texttt{msgFile} is \texttt{NULL} \\ -12 & \texttt{pnthread} is \texttt{NULL} \\ -13 & \texttt{*pnthread} is invalid \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} void FactorMT ( double *psigma, double *ppvttol, void *data, int *pinertia, int *perror ) ; \end{verbatim} \index{FactorMT@{\tt FactorMT()}} This method computes the factorization of $A - \sigma B$. All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt double *psigma} --- the shift parameter $\sigma$ is found in {\tt *psigma}. \item {\tt double *ppvttol} --- the pivot tolerance is found in {\tt *ppvttol}. When ${\tt *ppvttol} = 0.0$, the factorization is computed without pivoting for stability. When ${\tt *ppvttol} > 0.0$, the factorization is computed with pivoting for stability, and all offdiagonal entries have magnitudes bounded above by $1/({\tt *ppvttol})$. \item {\tt void *data} --- a pointer to the {\tt BridgeMT} object. \item {\tt int *pinertia} --- on return, {\tt *pinertia} holds the number of negative eigenvalues. \item {\tt int *perror} --- on return, {\tt *perror} holds an error code. \begin{center} \begin{tabular}[t]{rl} ~1 & error in the factorization \\ ~0 & normal return \\ -1 & \texttt{psigma} is \texttt{NULL} \end{tabular} \begin{tabular}[t]{rl} -2 & \texttt{ppvttol} is \texttt{NULL} \\ -3 & \texttt{data} is \texttt{NULL} \\ -4 & \texttt{pinertia} is \texttt{NULL} \end{tabular} \end{center} \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} void MatMulMT ( int *pnrows, int *pncols, double X[], double Y[], int *pprbtype, void *data ) ; \end{verbatim} \index{MatMulMT@{\tt MatMulMT()}} This method computes a multiply of the form $Y = I X$, $Y = A X$ or $Y = B X$. All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt int *pnrows} --- {\tt *pnrows} contains the number of rows in $X$ and $Y$. \item {\tt int *pncols} --- {\tt *pncols} contains the number of columns in $X$ and $Y$. \item {\tt double X[]} --- this is the $X$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt double Y[]} --- this is the $Y$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt int *pprbtype} --- {\tt *pprbtype} holds the problem type. \begin{itemize} \item {\tt 1} --- vibration, a multiply with $B$ is required. \item {\tt 2} --- buckling, a multiply with $A$ is required. \item {\tt 3} --- simple, no multiply is required. \end{itemize} \item {\tt void *data} --- a pointer to the {\tt BridgeMT} object. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} void SolveMT ( int *pnrows, int *pncols, double X[], double Y[], void *data, int *perror ) ; \end{verbatim} \index{SolveMT@{\tt SolveMT()}} This method solves $(A - \sigma B) X = Y$, where $(A - \sigma B)$ has been factored by a previous call to {\tt Factor()}. All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt int *pnrows} --- {\tt *pnrows} contains the number of rows in $X$ and $Y$. \item {\tt int *pncols} --- {\tt *pncols} contains the number of columns in $X$ and $Y$. \item {\tt double X[]} --- this is the $X$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt double Y[]} --- this is the $Y$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt void *data} --- a pointer to the {\tt BridgeMT} object. \item {\tt int *perror} --- on return, {\tt *perror} holds an error code. \begin{center} \begin{tabular}[t]{rl} ~1 & normal return \\ -1 & \texttt{pnrows} is \texttt{NULL} \\ -2 & \texttt{pncols} is \texttt{NULL} \end{tabular} \begin{tabular}[t]{rl} -3 & \texttt{X} is \texttt{NULL} \\ -4 & \texttt{Y} is \texttt{NULL} \\ -5 & \texttt{data} is \texttt{NULL} \end{tabular} \end{center} \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} int CleanupMT ( void *data ) ; \end{verbatim} \index{CleanupMT@{\tt CleanupMT()}} This method releases all the storage used by the {\bf SPOOLES} library functions. \par \noindent {\it Return value:} 1 for a normal return, -1 if a {\tt data} is {\tt NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \section{The \texttt{testMT} Driver Program} \label{section:BridgeMT:driver} \par A complete listing of the multithreaded driver program is found in chapter~\ref{chapter:MT_driver}. The program is invoked by this command sequence. \begin{verbatim} testMT msglvl msgFile parmFile seed nthread inFileA inFileB \end{verbatim} where \begin{itemize} \item {\tt msglvl} is the message level for the {\tt BridgeMT} methods and the {\bf SPOOLES} software. \item {\tt msgFile} is the message file for the {\tt BridgeMT} methods and the {\bf SPOOLES} software. \item {\tt parmFile} is the input file for the parameters of the eigensystem to be solved. \item {\tt seed} is a random number seed used by the {\bf SPOOLES} software. \item {\tt nthread} is the number of threads to use in the factors, solves and matrix-multiplies. \item {\tt inFileA} is the Harwell-Boeing file for the matrix $A$. \item {\tt inFileB} is the Harwell-Boeing file for the matrix $B$. \end{itemize} This program is executed for some sample matrices by the {\tt do\_ST\_*} shell scripts in the {\tt drivers} directory. \par Here is a short description of the steps in the driver program. See Chapter~\ref{chapter:serial_driver} for the listing. \begin{enumerate} \item The command line inputs are decoded. \item The header of the Harwell-Boeing file for $A$ is read. This yields the number of equations. \item The parameters that define the eigensystem to be solved are read in from the {\tt parmFile} file. \item The Lanczos eigensolver workspace is initialized. \item The Lanczos communication structure is filled with some parameters. \item The $A$ and possibly $B$ matrices are read in from the Harwell-Boeing files and converted into {\tt InpMtx} objects from the {\bf SPOOLES} library. \item The linear solver environment is then initialized via a call to {\tt SetupMT()}. \item The eigensolver is invoked via a call to {\tt lanczos\_run()}. The {\tt FactorMT()}, {\tt SolveMT()} and {\tt MatMulMT()} methods are passed to this routine. \item The eigenvalues are extracted and printed via a call to {\tt lanczos\_eigenvalues()}. \item The eigenvectors are extracted and printed via calls to {\tt lanczos\_eigenvector()}. \item The eigensolver working storage is free'd via a call to {\tt lanczos\_free()}. \item The linear solver working storage is free'd via a call to {\tt CleanupMT()}. \end{enumerate} } is a message level for the bridge methods and the {\bf SPOOLES} methods they call. \item {\tt FILE *pmsglvl} --- {\tt msgFile} is the message file for the bridge methods and the {\bf SPOOLES} methods they call. \end{itemize} This method must be called in the driver program prior to invoking the eigensolver via a call to {\tt lanczos\_run()}. It then follows this sequence of action. \begin{itemize} \item The method begins by checking all the input data, and setting the appropriate fields of theEigen/doc/MT_driver.tex010064400020550007177000000236240663676227300163320ustar00clevecompmath00000400000006\chapter{{\tt testMT.c} --- A Multithreaded Driver Program} \label{chapter:MT_driver} \begin{verbatim} /* testMT.c */ #include "../BridgeMT.h" void FactorMT ( ) ; void MatMulMT ( ) ; void SolveMT ( ) ; /*--------------------------------------------------------------------*/ void main ( int argc, char *argv[] ) /* ---------------------------------------------------------------- read in Harwell-Boeing matrices, using multithreaded factor, solve, and multiply routines based on spooles, invoke eigensolver created -- 98mar31, jcp modified -- 98dec18, cca ---------------------------------------------------------------- */ { BridgeMT bridge ; char *inFileName_A, *inFileName_B, *parmFileName, *type ; char buffer[20], pbtype[4], which[4] ; double lftend, rhtend, center, shfscl, t1, t2 ; double c__1 = 1.0, c__4 = 4.0, tolact = 2.309970868130169e-11 ; double eigval[1000], sigma[2]; double *evec; int error, fstevl, lfinit, lstevl, msglvl, mxbksz, ncol, ndiscd, neig, neigvl, nfound, nnonzeros, nrhs, nrow, nthreads, prbtyp, rc, retc, rfinit, seed, warnng ; int c__5 = 5, output = 6 ; int *lanczos_wksp; InpMtx *inpmtxA, *inpmtxB ; FILE *msgFile, *parmFile ; /*--------------------------------------------------------------------*/ if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile parmFile seed nthread inFileA inFileB" "\n msglvl -- message level" "\n msgFile -- message file" "\n parmFile -- input parameters file" "\n seed -- random number seed, used for ordering" "\n nthreads -- number of threads " "\n inFileA -- stiffness matrix, in Harwell-Boeing format" "\n inFileB -- mass matrix, in Harwell-Boeing format" "\n used for prbtype = 1 or 2" "\n", argv[0]) ; return ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n able to open file %s\n", argv[0], argv[2]) ; exit(-1) ; } parmFileName = argv[3] ; seed = atoi(argv[4]) ; nthreads = atoi(argv[5]) ; inFileName_A = argv[6] ; inFileName_B = argv[7] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n message file -- %s" "\n parameter file -- %s" "\n stiffness matrix file -- %s" "\n mass matrix file -- %s" "\n random number seed -- %d" "\n number of threads -- %d" "\n", argv[0], msglvl, argv[2], parmFileName, inFileName_A, inFileName_B, seed, nthreads) ; fflush(msgFile) ; /* --------------------------------------------- read in the Harwell-Boeing matrix information --------------------------------------------- */ if ( strcmp(inFileName_A, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; readHB_info (inFileName_A, &nrow, &ncol, &nnonzeros, &type, &nrhs) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in harwell-boeing header info", t2 - t1) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- read in eigenvalue problem data neigvl -- # of desired eigenvalues which -- which eigenvalues to compute 'l' or 'L' lowest (smallest magnitude) 'h' or 'H' highest (largest magnitude) 'n' or 'N' nearest to central value 'c' or 'C' nearest to central value 'a' or 'A' all eigenvalues in interval pbtype -- type of problem 'v' or 'V' generalized symmetric problem (K,M) with M positive semidefinite (vibration problem) 'b' or 'B' generalized symmetric problem (K,K_s) with K positive semidefinite with K_s posibly indefinite (buckling problem) 'o' or 'O' ordinary symmetric eigenproblem lfinit -- if true, lftend is restriction on lower bound of eigenvalues. if false, no restriction on lower bound lftend -- left endpoint of interval rfinit -- if true, rhtend is restriction on upper bound of eigenvalues. if false, no restriction on upper bound rhtend -- right endpoint of interval center -- center of interval mxbksz -- upper bound on block size for Lanczos recurrence shfscl -- shift scaling parameter, an estimate on the magnitude of the smallest nonzero eigenvalues --------------------------------------------------------------- */ MARKTIME(t1) ; parmFile = fopen(parmFileName, "r"); fscanf(parmFile, "%d %s %s %d %le %d %le %le %d %le", &neigvl, which, pbtype, &lfinit, &lftend, &rfinit, &rhtend, ¢er, &mxbksz, &shfscl) ; fclose(parmFile); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in eigenvalue problem data", t2 - t1) ; fflush(msgFile) ; /* ---------------------------------------- check and set the problem type parameter ---------------------------------------- */ switch ( pbtype[1] ) { case 'v' : case 'V' : prbtyp = 1 ; break ; case 'b' : case 'B' : prbtyp = 2 ; break ; case 'o' : case 'O' : prbtyp = 3 ; break ; default : fprintf(stderr, "\n invalid problem type %s", pbtype) ; exit(-1) ; } /* ---------------------------- Initialize Lanczos workspace ---------------------------- */ MARKTIME(t1) ; lanczos_init_ ( &lanczos_wksp ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize Lanczos workspace", t2 - t1) ; fflush(msgFile) ; /* ---------------------------------- initialize communication structure ---------------------------------- */ MARKTIME(t1) ; lanczos_set_parm( &lanczos_wksp, "order-of-problem", &nrow, &retc ); lanczos_set_parm( &lanczos_wksp, "accuracy-tolerance", &tolact, &retc); lanczos_set_parm( &lanczos_wksp, "max-block-size", &mxbksz, &retc ); lanczos_set_parm( &lanczos_wksp, "shift-scale", &shfscl, &retc ); lanczos_set_parm( &lanczos_wksp, "message_level", &msglvl, &retc ); lanczos_set_parm( &lanczos_wksp, "number-of-threads", &nthreads, &retc); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : init lanczos communication structure", t2 - t1) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- create the InpMtx objects for matrix A and B --------------------------------------------- */ if ( strcmp(inFileName_A, "none") == 0 ) { fprintf(msgFile, "\n no file to read A from") ; exit(-1) ; } MARKTIME(t1) ; inpmtxA = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxA, inFileName_A ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in A", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx A object after loading") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__1, &retc ); if ( prbtyp != 3 ) { if ( strcmp(inFileName_B, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; inpmtxB = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxB, inFileName_B ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in B", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx B object after loading") ; InpMtx_writeForHumanEye(inpmtxB, msgFile) ; fflush(msgFile) ; } } else { inpmtxB = NULL ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__4, &retc ); } /* ----------------------------- set up the solver environment ----------------------------- */ MARKTIME(t1) ; rc = SetupMT((void *) &bridge, &prbtyp, &nrow, &mxbksz, inpmtxA, inpmtxB, &seed, &nthreads, &msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set up the solver environment", t2 - t1) ; fflush(msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from SetupMT()", rc) ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- invoke eigensolver nfound -- # of eigenvalues found and kept ndisc -- # of additional eigenvalues discarded ----------------------------------------------- */ MARKTIME(t1) ; lanczos_run ( &neigvl, &which[1] , &pbtype[1], &lfinit, &lftend, &rfinit, &rhtend, ¢er, &lanczos_wksp, &bridge, &nfound, &ndiscd, &warnng, &error, FactorMT, MatMulMT, SolveMT ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : time for lanczos_run", t2 - t1) ; fflush(msgFile) ; /* ------------------------- get eigenvalues and print ------------------------- */ MARKTIME(t1) ; neig = nfound + ndiscd ; lstevl = nfound ; lanczos_eigenvalues (&lanczos_wksp, eigval, &neig, &retc); fstevl = 1 ; if ( nfound == 0 ) fstevl = -1 ; if ( ndiscd > 0 ) lstevl = -ndiscd ; hdslp5_ ("computed eigenvalues returned by hdserl", &neig, eigval, &output, 39L ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvalues", t2 - t1) ; fflush(msgFile) ; /* ------------------------- get eigenvectors and print ------------------------- */ /* MARKTIME(t1) ; neig = min ( 50, nrow ); Lncz_ALLOCATE(evec, double, nrow, retc); for (i = 1; i<= nfound; i++) {d lanczos_eigenvector ( &lanczos_wksp, &i, &i, newToOld, evec, &nrow, &retc ) ; hdslp5_ ( "computed eigenvector returned by hdserc", &neig, evec, &output, 39L ) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvectors", t2 - t1) ; fflush(msgFile) ; */ /* ------------------------ free the working storage ------------------------ */ MARKTIME(t1) ; lanczos_free( &lanczos_wksp ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free lanczos workspace", t2 - t1) ; fflush(msgFile) ; MARKTIME(t1) ; CleanupMT(&bridge) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free solver workspace", t2 - t1) ; fflush(msgFile) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return ; } \end{verbatim} "\n mass matrix file -- %s" "\n random number seed -- %d" "\n number of threads Eigen/doc/abstract.tex010064400020550007177000000022770662505006500162260ustar00clevecompmath00000400000006\begin{abstract} The {\bf SPOOLES} library stands for {\bf SP}arse {\bf O}bject {\bf O}riented {\bf L}inear {\bf E}quation {\bf S}olver. It is written in the C language using object oriented design and can solve real or complex linear systems in serial, multithreaded and MPI environments. It contains three options to order the matrices: minimum degree, generalized nested dissection and multisection. The matrices may be symmetric, Hermitian or nonsymmetric. Pivoting for numerical stability is supported. \par While the functionality of the library is broad, the learning curve can be steep for the initial user. We present in this paper some ``wrapper'' objects in the serial, multithreaded and MPI environments that ease the transition. They were originally written to integrate the {\bf SPOOLES} library into CSAR's Nastran library. \par The wrapper objects are presented as a learning device; anything that reduces the interface between the user and the library also restricts the ability to tune the library to a particular need. This drawback is ameliorated by a number of wrapper methods that allow the user to change default parameters that govern the ordering, factorization and solve. \end{abstract} Eigen/doc/intro.tex010064400020550007177000000072500663675607400155710ustar00clevecompmath00000400000006\chapter{Introduction} \label{chapter:introduction} \par The Lanczos eigensolver finds selected eigenvalues and eigenvectors of % three types of eigenproblems, $AX = B X \Lambda$, where $X$ are eigenvectors and $\Lambda$ is a diagonal matrix whose elements are eigenvalues. Three types of eigenproblems are supported. \begin{itemize} \item An ``ordinary'' eigenvalue problem where $A$ is symmetric and $B = I$. \item An ``vibration'' eigenvalue problem where $A$ is symmetric and $B$ is symmetric positive semidefinite. \item A ``buckling'' eigenvalue problem $A$ is symmetric positive semidefinite and $B$ is symmetric. \end{itemize} For the vibration and buckling problems, there must exist a $\sigma$ that is not an eigenvalue such that $A - \sigma B$ is nonsingular, i.e., $A$ and $B$ cannot share the same null space. \par During the computations, the eigensolver requires the following sparse linear algebra computations. \begin{itemize} \item Sparse factorizations of the form $A - \sigma B$. \item Solves of the form $(A - \sigma B) Z = Y$. \item Multiplies of the form $Z = B Y$ (for the vibration problem) or $Z = A Y$ (for the buckling problem). \end{itemize} The Lanczos eigensolver has defined a specific interface with an external linear algebra package to perform these three operations. The eigensolver currently interfaces with the {\bf BCSLIB-EXT} linear solver in a serial environment and the {\bf SPOOLES} linear solver in serial, multithreaded and MPI environments. \par This paper documents the {\bf SPOOLES} objects and functions that interface with the eigensolver. The three following chapters describe the serial, multithreaded and MPI objects, their data structures, and their methods. The appendix contains listings of three driver programs to exercise the eigensolver using the {\bf SPOOLES} library. \par Symmetric permutations of the eigensystem do not change the eigenvalues, and the eigenvectors can be easily constructed using the permutation matrix. $$ A X = B X \Lambda \longrightarrow {\widehat A} {\widehat X} = {\widehat B} {\widehat X} \Lambda \quad \mbox{where} \quad {\widehat A} = PAP^T, \quad {\widehat B} = PBP^T, \quad \mbox{and} \quad {\widehat X} = PX $$ The linear algebra package is free to use any permutation matrix $P$ to most efficiently perform the factorizations and solves involving ${\widehat A}$ and ${\widehat B}$. This permutation matrix $P$ is typically found by ordering the graph of $A + B$ using a variant of minimum degree or nested dissection. The ordering is performed prior to any action by the eigensolver. This ``setup phase'' includes more than just finding the permutation matrix, e.g., various data structures must be initialized. In a parallel environment, there is even more setup work to do, analyzing the factorization and solves and specifying which threads or processors perform what computations and store what data. In a distributed environment, the entries of $A$ and $B$ must also be distributed among the processors in preparation for the factors and multiplies. \par For each of the three environments --- serial, multithreaded and MPI --- the {\bf SPOOLES} solver has constructed a ``bridge'' object to span the interface between the linear system solver and the eigensolver. Each of the {\tt Bridge}, {\tt BridgeMT} and {\tt BridgeMPI} objects have five methods: set-up, factor, solve, matrix-multiply and cleanup. The factor, solve and matrix-multiply methods follow the calling sequence convention imposed by the eigensolver, and are passed to the eigensolver at the beginning of the Lanczos run. The set-up method is called prior to the eigensolver, and the cleanup method is called after the eigenvalues and eigenvectors have been determined. Eigen/doc/main.aux010064400020550007177000000055420664347214400153500ustar00clevecompmath00000400000006\relax \bibstyle{plain} \@writefile{toc}{\contentsline {chapter}{\numberline {1}Introduction}{2}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:introduction}{{1}{2}} \@writefile{toc}{\contentsline {chapter}{\numberline {2}The Serial Bridge Object and Driver}{4}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:serial}{{2}{4}} \@writefile{toc}{\contentsline {section}{\numberline {2.1}The \texttt {Bridge} Data Structure}{4}} \newlabel{section:Bridge:dataStructure}{{2.1}{4}} \@writefile{toc}{\contentsline {section}{\numberline {2.2}Prototypes and descriptions of \texttt {Bridge} methods}{5}} \newlabel{section:Bridge:proto}{{2.2}{5}} \@writefile{toc}{\contentsline {section}{\numberline {2.3}The \texttt {testSerial} Driver Program}{7}} \newlabel{section:Bridge:driver}{{2.3}{7}} \@writefile{toc}{\contentsline {chapter}{\numberline {3}The Multithreaded Bridge Object and Driver}{9}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:MT}{{3}{9}} \@writefile{toc}{\contentsline {section}{\numberline {3.1}The \texttt {BridgeMT} Data Structure}{9}} \newlabel{section:BridgeMT:dataStructure}{{3.1}{9}} \@writefile{toc}{\contentsline {section}{\numberline {3.2}Prototypes and descriptions of \texttt {BridgeMT} methods}{10}} \newlabel{section:BridgeMT:proto}{{3.2}{10}} \@writefile{toc}{\contentsline {section}{\numberline {3.3}The \texttt {testMT} Driver Program}{12}} \newlabel{section:BridgeMT:driver}{{3.3}{12}} \@writefile{toc}{\contentsline {chapter}{\numberline {4}The MPI Bridge Object and Driver}{14}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:MPI}{{4}{14}} \@writefile{toc}{\contentsline {section}{\numberline {4.1}The \texttt {BridgeMPI} Data Structure}{14}} \newlabel{section:BridgeMPI:dataStructure}{{4.1}{14}} \@writefile{toc}{\contentsline {section}{\numberline {4.2}Prototypes and descriptions of \texttt {BridgeMPI} methods}{15}} \newlabel{section:BridgeMPI:proto}{{4.2}{15}} \@writefile{toc}{\contentsline {section}{\numberline {4.3}The \texttt {testMPI} Driver Program}{19}} \newlabel{section:BridgeMPI:driver}{{4.3}{19}} \@writefile{toc}{\contentsline {chapter}{\numberline {A}{\tt testSerial.c} --- A Serial Driver Program}{20}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:serial_driver}{{A}{20}} \@writefile{toc}{\contentsline {chapter}{\numberline {B}{\tt testMT.c} --- A Multithreaded Driver Program}{27}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:MT_driver}{{B}{27}} \@writefile{toc}{\contentsline {chapter}{\numberline {C}{\tt testMPI.c} --- A MPI Driver Program}{34}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:MPI_driver}{{C}{34}} Eigen/doc/main.idx010064400020550007177000000013240664347214400153310ustar00clevecompmath00000400000006\indexentry{Setup@{\tt Setup()}}{5} \indexentry{Factor@{\tt Factor()}}{6} \indexentry{MatMul@{\tt MatMul()}}{6} \indexentry{Solve@{\tt Solve()}}{7} \indexentry{Cleanup@{\tt Cleanup()}}{7} \indexentry{SetupMT@{\tt SetupMT()}}{10} \indexentry{FactorMT@{\tt FactorMT()}}{11} \indexentry{MatMulMT@{\tt MatMulMT()}}{12} \indexentry{SolveMT@{\tt SolveMT()}}{12} \indexentry{CleanupMT@{\tt CleanupMT()}}{12} \indexentry{SetupMPI@{\tt SetupMPI()}}{16} \indexentry{FactorMPI@{\tt FactorMPI()}}{17} \indexentry{JimMatMulMPI@{\tt JimMatMulMPI()}}{17} \indexentry{MatMulMPI@{\tt MatMulMPI()}}{18} \indexentry{JimSolveMPI@{\tt JimSolveMPI()}}{18} \indexentry{SolveMPI@{\tt SolveMPI()}}{18} \indexentry{CleanupMPI@{\tt CleanupMPI()}}{19} Eigen/doc/main.ilg010064400020550007177000000004560663677431300153320ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (17 entries accepted, 0 rejected). Sorting entries....done (68 comparisons). Generating output file main.ind....done (33 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Eigen/doc/main.ind010064400020550007177000000011110663677431300153160ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Cleanup()}, 7 \item {\tt CleanupMPI()}, 19 \item {\tt CleanupMT()}, 12 \indexspace \item {\tt Factor()}, 6 \item {\tt FactorMPI()}, 17 \item {\tt FactorMT()}, 11 \indexspace \item {\tt JimMatMulMPI()}, 17 \item {\tt JimSolveMPI()}, 18 \indexspace \item {\tt MatMul()}, 6 \item {\tt MatMulMPI()}, 18 \item {\tt MatMulMT()}, 12 \indexspace \item {\tt Setup()}, 5 \item {\tt SetupMPI()}, 16 \item {\tt SetupMT()}, 10 \item {\tt Solve()}, 7 \item {\tt SolveMPI()}, 18 \item {\tt SolveMT()}, 12 \end{theindex} Eigen/doc/main.log010064400020550007177000000076740664347214400153440ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 2 JAN 1999 11:32 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file main.idx (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: External font `cmex10' loaded for size (Font) <12> on input line 52. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 52. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 52. LaTeX Font Info: External font `cmex10' loaded for size (Font) <9> on input line 52. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 52. [1 ] (main.toc LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 3. ) \tf@toc=\write5 (intro.tex [1 ] Chapter 1. LaTeX Font Info: Try loading font information for OMS+cmr on input line 12. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 12. ) (serial.tex [2 ] [3] Chapter 2. LaTeX Font Info: Font shape `OT1/cmtt/bx/n' in size <14.4> not available (Font) Font shape `OT1/cmtt/m/n' tried instead on input line 4. [4 ] [5] Overfull \hbox (22.49097pt too wide) in paragraph at lines 173--173 []\OT1/cmtt/m/n/10 void Factor ( double *psigma, double *ppvttol, void *data, int *pinertia, int *perror ) ;[] [] [6] [7]) (MT.tex [8] Chapter 3. [9 ] [10] [11] [12]) (MPI.tex [13] Chapter 4. [14 ] Overfull \hbox (1.79965pt too wide) in paragraph at lines 72--75 []\OT1/cmtt/m/n/10 IV *ownersIV \OT1/cmr/m/n/10 : ob-ject that maps fronts to o wn-ing pro-ces-sors for the fac-tor-iza-tion and matrix-multiplies. [] [15] [16] [17] [18]) (serial_driver.tex [19] Appendix A. [20 ] [21] [22] [23] [24] [25]) (MT_driver.tex [26] Appendix B. [27 ] [28] [29] [30] [31] [32]) (MPI_driver.tex [33] Appendix C. [34 ] [35] [36] [37] [38] [39] [40]) (main.ind [41] [42 ]) (main.aux) ) Here is how much of TeX's memory you used: 570 strings out of 10908 5786 string characters out of 72189 58833 words of memory out of 262141 3463 multiletter control sequences out of 9500 11727 words of font info for 43 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 25i,11n,21p,152b,396s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (43 pages, 103452 bytes). ng defaults for OML/cmm/m/it on input line 21. LaTeX Font Info: .Eigen/doc/main.tex010064400020550007177000000030340663677012700153510ustar00clevecompmath00000400000006\documentclass[10pt]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \input psfig \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\bf SPOOLES 2.2 Wrapper Objects} : \today \quad \hrulefill} {\quad \hrulefill \quad {\bf SPOOLES 2.2 Wrapper Objects} : \quad \today \hrulefill} \begin{document} \bibliographystyle{plain} \title{Integrating the {\bf SPOOLES} 2.2 Sparse Linear Algebra Library \break into the {\bf LANCZOS} Block-shifted Lanczos Eigensolver } \author{ Cleve Ashcraft\\ Boeing Phantom Works\thanks{ P. O. Box 24346, Mail Stop 7L-22, Seattle, Washington 98124, {\tt cleve.ashcraft@boeing.com}. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} \and Jim Patterson\\ Boeing Phantom Works\thanks{ P. O. Box 24346, Mail Stop 7L-22, Seattle, Washington 98124, {\tt pattersn@redwood.rt.cs.boeing.com}. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} } \date{\today} \maketitle \tableofcontents \input intro.tex \input serial.tex \input MT.tex \input MPI.tex \appendix \input serial_driver.tex \input MT_driver.tex \input MPI_driver.tex \input main.ind \end{document} Eigen/doc/main.toc010064400020550007177000000025410664347214400153340ustar00clevecompmath00000400000006\contentsline {chapter}{\numberline {1}Introduction}{2} \contentsline {chapter}{\numberline {2}The Serial Bridge Object and Driver}{4} \contentsline {section}{\numberline {2.1}The \texttt {Bridge} Data Structure}{4} \contentsline {section}{\numberline {2.2}Prototypes and descriptions of \texttt {Bridge} methods}{5} \contentsline {section}{\numberline {2.3}The \texttt {testSerial} Driver Program}{7} \contentsline {chapter}{\numberline {3}The Multithreaded Bridge Object and Driver}{9} \contentsline {section}{\numberline {3.1}The \texttt {BridgeMT} Data Structure}{9} \contentsline {section}{\numberline {3.2}Prototypes and descriptions of \texttt {BridgeMT} methods}{10} \contentsline {section}{\numberline {3.3}The \texttt {testMT} Driver Program}{12} \contentsline {chapter}{\numberline {4}The MPI Bridge Object and Driver}{14} \contentsline {section}{\numberline {4.1}The \texttt {BridgeMPI} Data Structure}{14} \contentsline {section}{\numberline {4.2}Prototypes and descriptions of \texttt {BridgeMPI} methods}{15} \contentsline {section}{\numberline {4.3}The \texttt {testMPI} Driver Program}{19} \contentsline {chapter}{\numberline {A}{\tt testSerial.c} --- A Serial Driver Program}{20} \contentsline {chapter}{\numberline {B}{\tt testMT.c} --- A Multithreaded Driver Program}{27} \contentsline {chapter}{\numberline {C}{\tt testMPI.c} --- A MPI Driver Program}{34} Eigen/doc/makefile010064400020550007177000000000270662564410500153740ustar00clevecompmath00000400000006clean : - rm -f *.dvi Eigen/doc/serial.tex010064400020550007177000000321460663676736300157220ustar00clevecompmath00000400000006\chapter{The Serial Bridge Object and Driver} \label{chapter:serial} \par \section{The \texttt{Bridge} Data Structure} \label{section:Bridge:dataStructure} \par The {\tt Bridge} structure has the following fields. \begin{itemize} % \item {\tt int prbtype} : problem type \begin{itemize} \item {\tt 1} --- vibration, a multiply with $B$ is required. \item {\tt 2} --- buckling, a multiply with $A$ is required. \item {\tt 3} --- simple, no multiply is required. \end{itemize} \item {\tt int neqns} : number of equations, i.e., number of vertices in the graph. \item {\tt int mxbsz} : block size for the Lanczos process. \item {\tt int seed} : random number seed used in the ordering. \item {\tt InpMtx *A} : matrix object for $A$ \item {\tt InpMtx *B} : matrix object for $B$ \item {\tt Pencil *pencil} : object to hold linear combination of $A$ and $B$. \item {\tt ETree *frontETree} : object that defines the factorizations, e.g., the number of fronts, the tree they form, the number of internal and external rows for each front, and the map from vertices to the front where it is contained. \item {\tt IVL *symbfacIVL} : object that contains the symbolic factorization of the matrix. \item {\tt SubMtxManager *mtxmanager} : object that manages the \texttt{SubMtx} objects that store the factor entries and are used in the solves. \item {\tt FrontMtx *frontmtx} : object that stores the $L$, $D$ and $U$ factor matrices. \item {\tt IV *oldToNewIV} : object that stores old-to-new permutation vector. \item {\tt IV *newToOldIV} : object that stores new-to-old permutation vector. \item {\tt DenseMtx *X} : dense matrix object that is used during the matrix multiples and solves. \item {\tt DenseMtx *Y} : dense matrix object that is used during the matrix multiples and solves. \item {\tt int msglvl} : message level for output. When 0, no output, When 1, just statistics and cpu times. When greater than 1, more and more output. \item {\tt FILE *msgFile} : message file for output. When \texttt{msglvl} $>$ 0, \texttt{msgFile} must not be \texttt{NULL}. \end{itemize} \par \section{Prototypes and descriptions of \texttt{Bridge} methods} \label{section:Bridge:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Bridge} object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Setup ( void *data, int *pprbtype, int *pneqns, int *pmxbsz, InpMtx *A, InpMtx *B, int *pseed, int *pmsglvl, FILE *msgFile ) ; \end{verbatim} \index{Setup@{\tt Setup()}} \noindent All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt void *data} --- a pointer to the {\tt Bridge} object. \item {\tt int *pprbtype} --- {\tt *pprbtype} holds the problem type. \begin{itemize} \item {\tt 1} --- vibration, a multiply with $B$ is required. \item {\tt 2} --- buckling, a multiply with $A$ is required. \item {\tt 3} --- simple, no multiply is required. \end{itemize} \item {\tt int *pneqns} --- {\tt *pneqns} is the number of equations. \item {\tt int *pmxbsz} --- {\tt *pmxbsz} is an upper bound on the block size. \item {\tt InpMtx *A} --- {\tt A} is a {\bf SPOOLES} object that holds the matrix $A$. \item {\tt InpMtx *B} --- {\tt B} is a {\bf SPOOLES} object that holds the matrix $B$. For an ordinary eigenproblem, $B$ is the identity and {\tt B} is {\tt NULL}. \item {\tt int *pseed} --- {\tt *pseed} is a random number seed. \item {\tt int *pmsglvl} --- {\tt *pmsglvl} is a message level for the bridge methods and the {\bf SPOOLES} methods they call. \item {\tt FILE *pmsglvl} --- {\tt msgFile} is the message file for the bridge methods and the {\bf SPOOLES} methods they call. \end{itemize} This method must be called in the driver program prior to invoking the eigensolver via a call to {\tt lanczos\_run()}. It then follows this sequence of action. \begin{itemize} \item The method begins by checking all the input data, and setting the appropriate fields of the {\tt Bridge} object. \item The {\tt pencil} object is initialized with {\tt A} and {\tt B}. \item {\tt A} and {\tt B} are converted to storage by rows and vector mode. \item A {\tt Graph} object is created that contains the sparsity pattern of the union of {\tt A} and {\tt B}. \item The graph is ordered by first finding a recursive dissection partition, and then evaluating the orderings produced by nested dissection and multisection, and choosing the better of the two. The {\tt frontETree} object is produced and placed into the {\tt bridge} object. \item Old-to-new and new-to-old permutations are extracted from the front tree and loaded into the {\tt Bridge} object. \item The vertices in the front tree are permuted, as well as the entries in {\tt A} and {\tt B}. Entries in the lower triangle of {\tt A} and {\tt B} are mapped into the upper triangle, and the storage modes of {\tt A} and {\tt B} are changed to chevrons and vectors, in preparation for the first factorization. \item The symbolic factorization is then computed and loaded in the {\tt Bridge} object. \item A {\tt FrontMtx} object is created to hold the factorization and loaded into the {\tt Bridge} object. \item A {\tt SubMtxManager} object is created to hold the factor's submatrices and loaded into the {\tt Bridge} object. \item Two {\tt DenseMtx} objects are created to be used during the matrix multiplies and solves. \end{itemize} The {\tt A} and {\tt B} matrices are now in their permuted ordering, i.e., $PAP^T$ and $PBP^T$, and all data structures are with respect to this ordering. After the Lanczos run completes, any generated eigenvectors must be permuted back into their original ordering using the {\tt oldToNewIV} and {\tt newToOldIV} objects. \par \noindent {\it Return value:} \begin{center} \begin{tabular}[t]{rl} ~1 & normal return \\ -1 & \texttt{data} is \texttt{NULL} \\ -2 & \texttt{pprbtype} is \texttt{NULL} \\ -3 & \texttt{*pprbtype} is invalid \\ -4 & \texttt{pneqns} is \texttt{NULL} \\ -5 & \texttt{*pneqns} is invalid \end{tabular} \begin{tabular}[t]{rl} -6 & \texttt{pmxbsz} is \texttt{NULL} \\ -7 & \texttt{*pmxbsz} is invalid \\ -8 & \texttt{A} and \texttt{B} are \texttt{NULL} \\ -9 & \texttt{seed} is \texttt{NULL} \\ -10 & \texttt{msglvl} is \texttt{NULL} \\ -11 & $\texttt{msglvl} > 0$ and \texttt{msgFile} is \texttt{NULL} \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} void Factor ( double *psigma, double *ppvttol, void *data, int *pinertia, int *perror ) ; \end{verbatim} \index{Factor@{\tt Factor()}} This method computes the factorization of $A - \sigma B$. All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt double *psigma} --- the shift parameter $\sigma$ is found in {\tt *psigma}. \item {\tt double *ppvttol} --- the pivot tolerance is found in {\tt *ppvttol}. When ${\tt *ppvttol} = 0.0$, the factorization is computed without pivoting for stability. When ${\tt *ppvttol} > 0.0$, the factorization is computed with pivoting for stability, and all offdiagonal entries have magnitudes bounded above by $1/({\tt *ppvttol})$. \item {\tt void *data} --- a pointer to the {\tt Bridge} object. \item {\tt int *pinertia} --- on return, {\tt *pinertia} holds the number of negative eigenvalues. \item {\tt int *perror} --- on return, {\tt *perror} holds an error code. \begin{center} \begin{tabular}[t]{rl} ~1 & error in the factorization \\ ~0 & normal return \\ -1 & \texttt{psigma} is \texttt{NULL} \end{tabular} \begin{tabular}[t]{rl} -2 & \texttt{ppvttol} is \texttt{NULL} \\ -3 & \texttt{data} is \texttt{NULL} \\ -4 & \texttt{pinertia} is \texttt{NULL} \end{tabular} \end{center} \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} void MatMul ( int *pnrows, int *pncols, double X[], double Y[], int *pprbtype, void *data ) ; \end{verbatim} \index{MatMul@{\tt MatMul()}} This method computes a multiply of the form $Y = I X$, $Y = A X$ or $Y = B X$. All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt int *pnrows} --- {\tt *pnrows} contains the number of rows in $X$ and $Y$. \item {\tt int *pncols} --- {\tt *pncols} contains the number of columns in $X$ and $Y$. \item {\tt double X[]} --- this is the $X$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt double Y[]} --- this is the $Y$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt int *pprbtype} --- {\tt *pprbtype} holds the problem type. \begin{itemize} \item {\tt 1} --- vibration, a multiply with $B$ is required. \item {\tt 2} --- buckling, a multiply with $A$ is required. \item {\tt 3} --- simple, no multiply is required. \end{itemize} \item {\tt void *data} --- a pointer to the {\tt Bridge} object. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} void Solve ( int *pnrows, int *pncols, double X[], double Y[], void *data, int *perror ) ; \end{verbatim} \index{Solve@{\tt Solve()}} This method solves $(A - \sigma B) X = Y$, where $(A - \sigma B)$ has been factored by a previous call to {\tt Factor()}. All calling sequence parameters are pointers to more easily allow an interface with Fortran. \begin{itemize} \item {\tt int *pnrows} --- {\tt *pnrows} contains the number of rows in $X$ and $Y$. \item {\tt int *pncols} --- {\tt *pncols} contains the number of columns in $X$ and $Y$. \item {\tt double X[]} --- this is the $X$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt double Y[]} --- this is the $Y$ matrix, stored column major with leading dimension {\tt *pnrows}. \item {\tt void *data} --- a pointer to the {\tt Bridge} object. \item {\tt int *perror} --- on return, {\tt *perror} holds an error code. \begin{center} \begin{tabular}[t]{rl} ~1 & normal return \\ -1 & \texttt{pnrows} is \texttt{NULL} \\ -2 & \texttt{pncols} is \texttt{NULL} \end{tabular} \begin{tabular}[t]{rl} -3 & \texttt{X} is \texttt{NULL} \\ -4 & \texttt{Y} is \texttt{NULL} \\ -5 & \texttt{data} is \texttt{NULL} \end{tabular} \end{center} \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} int Cleanup ( void *data ) ; \end{verbatim} \index{Cleanup@{\tt Cleanup()}} This method releases all the storage used by the {\bf SPOOLES} library functions. \par \noindent {\it Return value:} 1 for a normal return, -1 if a {\tt data} is {\tt NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \section{The \texttt{testSerial} Driver Program} \label{section:Bridge:driver} \par A complete listing of the serial driver program is found in chapter~\ref{chapter:serial_driver}. The program is invoked by this command sequence. \begin{verbatim} testSerial msglvl msgFile parmFile seed inFileA inFileB \end{verbatim} where \begin{itemize} \item {\tt msglvl} is the message level for the {\tt Bridge} methods and the {\bf SPOOLES} software. \item {\tt msgFile} is the message file for the {\tt Bridge} methods and the {\bf SPOOLES} software. \item {\tt parmFile} is the input file for the parameters of the eigensystem to be solved. \item {\tt seed} is a random number seed used by the {\bf SPOOLES} software. \item {\tt inFileA} is the Harwell-Boeing file for the matrix $A$. \item {\tt inFileB} is the Harwell-Boeing file for the matrix $B$. \end{itemize} This program is executed for some sample matrices by the {\tt do\_ST\_*} shell scripts in the {\tt drivers} directory. \par Here is a short description of the steps in the driver program. See Chapter~\ref{chapter:serial_driver} for the listing. \begin{enumerate} \item The command line inputs are decoded. \item The header of the Harwell-Boeing file for $A$ is read. This yields the number of equations. \item The parameters that define the eigensystem to be solved are read in from the {\tt parmFile} file. \item The Lanczos eigensolver workspace is initialized. \item The Lanczos communication structure is filled with some parameters. \item The $A$ and possibly $B$ matrices are read in from the Harwell-Boeing files and converted into {\tt InpMtx} objects from the {\bf SPOOLES} library. \item The linear solver environment is then initialized via a call to {\tt Setup()}. \item The eigensolver is invoked via a call to {\tt lanczos\_run()}. The {\tt FactorMT()}, {\tt SolveMT()} and {\tt MatMulMT()} methods are passed to this routine. \item The eigenvalues are extracted and printed via a call to {\tt lanczos\_eigenvalues()}. \item The eigenvectors are extracted and printed via calls to {\tt lanczos\_eigenvector()}. \item The eigensolver working storage is free'd via a call to {\tt lanczos\_free()}. \item The linear solver working storage is free'd via a call to {\tt Cleanup()}. \end{enumerate} *pneqns} is the number of equations. \item {\tt int *pmxbsz} --- {\tt *pmxbsz} is an upper bound on the block size. \item {\tt InpMtx *A} --- {\tt A} is a {\bf SPOOLES} object that holds the matrix $A$. \item {\tt InpMtx *B} --- {\tt B} is a {\bf SPOOLES} object that holds the matrix $B$. For an ordinary eigenproblem, $B$ is the identity and {\tt B} is {\tt NULL}. \item {\tt int *pseed} --- {\tt *pseed} isEigen/doc/serial_driver.tex010064400020550007177000000233740663675375400172770ustar00clevecompmath00000400000006\chapter{{\tt testSerial.c} --- A Serial Driver Program} \label{chapter:serial_driver} \begin{verbatim} /* testSerial.c */ #include "../Bridge.h" void Factor ( ) ; void MatMul ( ) ; void Solve ( ) ; /*--------------------------------------------------------------------*/ void main ( int argc, char *argv[] ) /* ---------------------------------------------------------- read in Harwell-Boeing matrices, use serial factor, solve, and multiply routines based on spooles, invoke eigensolver created -- 98mar31 jcp modified -- 98dec18, cca ---------------------------------------------------------- */ { Bridge bridge ; char *inFileName_A, *inFileName_B, *outFileName, *parmFileName, *type ; char buffer[20], pbtype[4], which[4] ; double lftend, rhtend, center, shfscl, t1, t2 ; double c__1 = 1.0, c__4 = 4.0, tolact = 2.309970868130169e-11 ; double eigval[1000], sigma[2]; double *evec; int error, fstevl, lfinit, lstevl, mxbksz, msglvl, ncol, ndiscd, neig, neigvl, nfound, nnonzeros, nrhs, nrow, prbtyp, rc, retc, rfinit, seed, warnng ; int c__5 = 5, output = 6 ; int *lanczos_wksp; InpMtx *inpmtxA, *inpmtxB ; FILE *msgFile, *parmFile; /*--------------------------------------------------------------------*/ if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile parmFile seed inFileA inFileB" "\n msglvl -- message level" "\n msgFile -- message file" "\n parmFile -- input parameters file" "\n seed -- random number seed, used for ordering" "\n inFileA -- stiffness matrix in Harwell-Boeing format" "\n inFileB -- mass matrix in Harwell-Boeing format" "\n used for prbtyp = 1 or 2" "\n", argv[0]) ; return ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; exit(-1) ; } parmFileName = argv[3] ; seed = atoi(argv[4]) ; inFileName_A = argv[5] ; inFileName_B = argv[6] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n parmFile -- %s" "\n seed -- %d" "\n stiffness file -- %s" "\n mass file -- %s" "\n", argv[0], msglvl, argv[2], parmFileName, seed, inFileName_A, inFileName_B) ; fflush(msgFile) ; /* --------------------------------------------- read in the Harwell-Boeing matrix information --------------------------------------------- */ if ( strcmp(inFileName_A, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; readHB_info (inFileName_A, &nrow, &ncol, &nnonzeros, &type, &nrhs) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in header information for A", t2 - t1) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- read in eigenvalue problem data neigvl -- # of desired eigenvalues which -- which eigenvalues to compute 'l' or 'L' lowest (smallest magnitude) 'h' or 'H' highest (largest magnitude) 'n' or 'N' nearest to central value 'c' or 'C' nearest to central value 'a' or 'A' all eigenvalues in interval pbtype -- type of problem 'v' or 'V' generalized symmetric problem (K,M) with M positive semidefinite (vibration problem) 'b' or 'B' generalized symmetric problem (K,K_s) with K positive semidefinite with K_s posibly indefinite (buckling problem) 'o' or 'O' ordinary symmetric eigenproblem lfinit -- if true, lftend is restriction on lower bound of eigenvalues. if false, no restriction on lower bound lftend -- left endpoint of interval rfinit -- if true, rhtend is restriction on upper bound of eigenvalues. if false, no restriction on upper bound rhtend -- right endpoint of interval center -- center of interval mxbksz -- upper bound on block size for Lanczos recurrence shfscl -- shift scaling parameter, an estimate on the magnitude of the smallest nonzero eigenvalues --------------------------------------------------------------- */ MARKTIME(t1) ; parmFile = fopen(parmFileName, "r"); fscanf(parmFile, "%d %s %s %d %le %d %le %le %d %le", &neigvl, which, pbtype, &lfinit, &lftend, &rfinit, &rhtend, ¢er, &mxbksz, &shfscl) ; fclose(parmFile); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in eigenvalue problem data", t2 - t1) ; /* ---------------------------------------- check and set the problem type parameter ---------------------------------------- */ switch ( pbtype[1] ) { case 'v' : case 'V' : prbtyp = 1 ; break ; case 'b' : case 'B' : prbtyp = 2 ; break ; case 'o' : case 'O' : prbtyp = 3 ; break ; default : fprintf(stderr, "\n invalid problem type %s", pbtype) ; exit(-1) ; } /* ---------------------------- Initialize Lanczos workspace ---------------------------- */ MARKTIME(t1) ; lanczos_init_ ( &lanczos_wksp ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize lanczos workspace", t2 - t1) ; /* ---------------------------------- initialize communication structure ---------------------------------- */ MARKTIME(t1) ; lanczos_set_parm( &lanczos_wksp, "order-of-problem", &nrow, &retc ); lanczos_set_parm( &lanczos_wksp, "accuracy-tolerance", &tolact, &retc ); lanczos_set_parm( &lanczos_wksp, "max-block-size", &mxbksz, &retc ); lanczos_set_parm( &lanczos_wksp, "shift-scale", &shfscl, &retc ); lanczos_set_parm( &lanczos_wksp, "message_level", &msglvl, &retc ); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : init lanczos communication structure", t2 - t1) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- create the InpMtx objects for matrix A and B --------------------------------------------- */ if ( strcmp(inFileName_A, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; inpmtxA = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxA, inFileName_A ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in A", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx A object after loading") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__1, &retc ); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set A's parameters", t2 - t1) ; if ( prbtyp != 3 ) { if ( strcmp(inFileName_B, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; inpmtxB = InpMtx_new() ; InpMtx_readFromHBfile ( inpmtxB, inFileName_B ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in B", t2 - t1) ; } else { MARKTIME(t1) ; inpmtxB = NULL ; lanczos_set_parm( &lanczos_wksp, "matrix-type", &c__4, &retc ); MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set B's parameters", t2 - t1) ; } if ( msglvl > 2 && prbtyp != 3 ) { fprintf(msgFile, "\n\n InpMtx B object after loading") ; InpMtx_writeForHumanEye(inpmtxB, msgFile) ; fflush(msgFile) ; } /* ----------------------------- set up the solver environment ----------------------------- */ MARKTIME(t1) ; rc = Setup((void *) &bridge, &prbtyp, &nrow, &mxbksz, inpmtxA, inpmtxB, &seed, &msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set up solver environment", t2 - t1) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error %d from Setup()", rc) ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- invoke eigensolver nfound -- # of eigenvalues found and kept ndisc -- # of additional eigenvalues discarded ----------------------------------------------- */ MARKTIME(t1) ; lanczos_run(&neigvl, &which[1] , &pbtype[1], &lfinit, &lftend, &rfinit, &rhtend, ¢er, &lanczos_wksp, &bridge, &nfound, &ndiscd, &warnng, &error, Factor, MatMul, Solve ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : time for lanczos run", t2 - t1) ; /* ------------------------- get eigenvalues and print ------------------------- */ MARKTIME(t1) ; neig = nfound + ndiscd ; lstevl = nfound ; lanczos_eigenvalues (&lanczos_wksp, eigval, &neig, &retc); fstevl = 1 ; if ( nfound == 0 ) fstevl = -1 ; if ( ndiscd > 0 ) lstevl = -ndiscd ; hdslp5_ ("computed eigenvalues returned by hdserl", &neig, eigval, &output, 39L ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvalues ", t2 - t1) ; /* ------------------------- get eigenvectors and print ------------------------- */ /* MARKTIME(t1) ; neig = min ( 50, nrow ); Lncz_ALLOCATE(evec, double, nrow, retc); for ( i = 1 ; i <= nfound ; i++ ) { lanczos_eigenvector ( &lanczos_wksp, &i, &i, newToOld, evec, &nrow, &retc ) ; hdslp5_ ( "computed eigenvector returned by hdserc", &neig, evec, &output, 39L ) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get and print eigenvectors ", t2 - t1) ; */ /* ------------------------ free the working storage ------------------------ */ MARKTIME(t1) ; lanczos_free( &lanczos_wksp ) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free lanczos workspace ", t2 - t1) ; MARKTIME(t1) ; rc = Cleanup(&bridge) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : free solver workspace ", t2 - t1) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from Cleanup()", rc) ; exit(-1) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return ; } \end{verbatim} 4], which[4] ; double lftend, rhtend, center, shfscl, t1, t2 ; double c__1 = 1.0, c__4 = 4.0, tolact = 2.309970868130169e-11 ; double eigval[1000], sigma[2]; double *evec; int error, fstevl, lfinit, lstevl, mxbksz, msglvl, ncol, ndiscd, FrontMtx.h010064400020550007177000000001140657353754400140410ustar00clevecompmath00000400000006#ifndef _FrontMtx_ #define _FrontMtx_ #include "FrontMtx/FrontMtx.h" #endif FrontMtx/FrontMtx.h010064400020550007177000001511140660520203200156020ustar00clevecompmath00000400000006/* FrontMtx.h */ #include "../Pencil.h" #include "../ETree.h" #include "../IVL.h" #include "../PatchAndGoInfo.h" #include "../Chv.h" #include "../ChvManager.h" #include "../ChvList.h" #include "../SubMtx.h" #include "../SubMtxList.h" #include "../SubMtxManager.h" #include "../DenseMtx.h" #include "../Ideq.h" #include "../SolveMap.h" #include "../Lock.h" #include "../I2Ohash.h" #include "../SPOOLES.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- the FrontMtx object is used to compute and store a matrix factorization in serial, multithreaded and MPI modes. there are two data modes: 1 --> data is stored by fronts, a 1-D data decomposition. we use five pointer vectors (p_mtxDJJ[], p_mtxUJJ[], p_mtxUJN[], p_mtxLJJ[] and p_mtxLNJ[]) to store pointers to the factor submatrices 2 --> data is stored by submatrices, a 2-D data decomposition. we use two hash objects (lowerhash and upperhash), a pointer vector p_mtxDJJ[] and two IVL objects (lowerblockIVL and upperblockIVL) to store the structure of the matrix. nfront -- number of fronts in the matrix neqns -- number of rows and columns in the matrix type -- type of entries 1 -- real 2 -- complex symmetryflag -- flag to specify symmetry of the matrix 0 --> symmetric structure, symmetric entries 1 --> symmetric structure, nonsymmetric entries 2 --> nonsymmetric structure, nonsymmetric entries sparsityflag -- flag to specify dense or sparse fronts 0 --> dense fronts 1 --> sparse fronts pivotingflag -- flag to specify pivoting enabled 0 --> pivoting not used 1 --> pivoting used dataMode -- flag to specify storage mode 1 --> 1-dimensional data decomposition, used for factorization 2 --> 2-dimensional data decomposition, used for solves nentD -- number of entries in the diagonal matrix nentL -- number of entries in the lower triangular matrix nentU -- number of entries in the upper triangular matrix tree -- pointer to an Tree object that holds the tree of fronts frontETree -- pointer to an ETree object that holds the front tree symbfacIVL -- pointer to an IVL object that holds the symbolic factorization frontsizesIV -- pointer to an IV object that holds the number of internal rows and columns in each front rowadjIVL -- pointer to an IVL object that holds the row ids of the fronts, used only for nonsymmetric matrices with pivoting coladjIVL -- pointer to an IVL object that holds the column ids of the fronts, used only with pivoting p_mtxDJJ -- vector of pointers to the diagonal D_{J,J} objects p_mtxUJJ -- vector of pointers to the upper U_{J,J} objects p_mtxUJN -- vector of pointers to the upper U_{J,N} objects p_mtxLJJ -- vector of pointers to the lower L_{J,J} objects p_mtxLNJ -- vector of pointers to the lower L_{N,J} objects lowerblockIVL -- pointer to an IVL object that holds the sparsity structure of the block L matrix, i.e., front-front edges, used only for nonsymmetric matrices with pivoting upperblockIVL -- pointer to an IVL object that holds the sparsity structure of the block U matrix, i.e., front-front edges lowerhash -- pointer to a hash table object that holds the submatrices in L, used only for nonsymmetric factorizations upperhash -- pointer to a hash table object that holds the submatrices in U manager -- object to manage instances of Mtx objects lock -- mutex object that controls access to allocating storage in IVL and DVL objects, can be NULL nlocks -- number of times the lock was locked patchinfo -- information object needed for special factorizations created -- 98feb27, cca ------------------------------------------------------------------- */ typedef struct _FrontMtx FrontMtx ; struct _FrontMtx { int nfront ; int neqns ; int type ; int symmetryflag ; int sparsityflag ; int pivotingflag ; int dataMode ; int nentD ; int nentL ; int nentU ; Tree *tree ; ETree *frontETree ; IV *frontsizesIV ; IVL *symbfacIVL ; IVL *rowadjIVL ; IVL *coladjIVL ; IVL *lowerblockIVL ; IVL *upperblockIVL ; SubMtx **p_mtxDJJ ; SubMtx **p_mtxUJJ ; SubMtx **p_mtxUJN ; SubMtx **p_mtxLJJ ; SubMtx **p_mtxLNJ ; I2Ohash *lowerhash ; I2Ohash *upperhash ; SubMtxManager *manager ; Lock *lock ; PatchAndGoInfo *patchinfo ; int nlocks ; } ; #define FRONTMTX_IS_REAL(mtx) ((mtx)->type == SPOOLES_REAL) #define FRONTMTX_IS_COMPLEX(mtx) ((mtx)->type == SPOOLES_COMPLEX) #define FRONTMTX_IS_SYMMETRIC(mtx) \ ((mtx)->symmetryflag == SPOOLES_SYMMETRIC) #define FRONTMTX_IS_HERMITIAN(mtx) \ ((mtx)->symmetryflag == SPOOLES_HERMITIAN) #define FRONTMTX_IS_NONSYMMETRIC(mtx) \ ((mtx)->symmetryflag == SPOOLES_NONSYMMETRIC) #define FRONTMTX_DENSE_FRONTS 0 #define FRONTMTX_SPARSE_FRONTS 1 #define FRONTMTX_IS_DENSE_FRONTS(mtx) \ ((mtx)->sparsityflag == FRONTMTX_DENSE_FRONTS) #define FRONTMTX_IS_SPARSE_FRONTS(mtx) \ ((mtx)->sparsityflag == FRONTMTX_SPARSE_FRONTS) #define FRONTMTX_IS_PIVOTING(mtx) \ ((mtx)->pivotingflag == SPOOLES_PIVOTING) #define FRONTMTX_1D_MODE 1 #define FRONTMTX_2D_MODE 2 #define FRONTMTX_IS_1D_MODE(mtx) \ ((mtx)->dataMode == FRONTMTX_1D_MODE) #define FRONTMTX_IS_2D_MODE(mtx) \ ((mtx)->dataMode == FRONTMTX_2D_MODE) #define NO_LOCK 0 #define LOCK_IN_PROCESS 1 #define LOCK_IN_ALL_PROCESSES 2 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98may04, cca ----------------------- */ FrontMtx * FrontMtx_new ( void ) ; /* ----------------------- set the default fields created -- 98may04, cca ----------------------- */ void FrontMtx_setDefaultFields ( FrontMtx *frontmtx ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may04, cca -------------------------------------------------- */ void FrontMtx_clearData ( FrontMtx *frontmtx ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98may04, cca ------------------------------------------ */ void FrontMtx_free ( FrontMtx *frontmtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------- purpose -- return the number of fronts created -- 98may04, cca -------------------------------------- */ int FrontMtx_nfront ( FrontMtx *frontmtx ) ; /* ----------------------------------------- purpose -- return the number of equations created -- 98may04, cca ----------------------------------------- */ int FrontMtx_neqns ( FrontMtx *frontmtx ) ; /* ---------------------------------------------------- purpose -- return a pointer to the front Tree object created -- 98may04, cca ---------------------------------------------------- */ Tree * FrontMtx_frontTree ( FrontMtx *frontmtx ) ; /* ---------------------------------------------------------------- simple method to return the dimensions of front J and the number of bytes necessary for the Chv object to hold the front. created -- 98may04, cca ---------------------------------------------------------------- */ void FrontMtx_initialFrontDimensions ( FrontMtx *frontmtx, int J, int *pnD, int *pnL, int *pnU, int *pnbytes ) ; /* --------------------------------------------------------- return the number of internal rows and columns in front J created -- 98may04, cca --------------------------------------------------------- */ int FrontMtx_frontSize ( FrontMtx *frontmtx, int J ) ; /* ------------------------------------------------------ set the number of internal rows and columns in front J created -- 98may04, cca ------------------------------------------------------ */ void FrontMtx_setFrontSize ( FrontMtx *frontmtx, int J, int size ) ; /* --------------------------------------------- fill *pncol with the number of columns and *pcolind with a pointer to the column indices created -- 98may04, cca --------------------------------------------- */ void FrontMtx_columnIndices ( FrontMtx *frontmtx, int J, int *pncol, int **pcolind ) ; /* ------------------------------------------- fill *pnrow with the number of rows and *prowind with a pointer to the rows indices created -- 98may04, cca ------------------------------------------- */ void FrontMtx_rowIndices ( FrontMtx *frontmtx, int J, int *pnrow, int **prowind ) ; /* ----------------------------------------------------------- purpose -- return a pointer to the (J,J) diagonal submatrix created -- 98may04, cca ----------------------------------------------------------- */ SubMtx * FrontMtx_diagMtx ( FrontMtx *frontmtx, int J ) ; /* -------------------------------------------------------- purpose -- return a pointer to the (J,K) upper submatrix created -- 98may04, cca -------------------------------------------------------- */ SubMtx * FrontMtx_upperMtx ( FrontMtx *frontmtx, int J, int K ) ; /* -------------------------------------------------------- purpose -- return a pointer to the (K,J) lower submatrix created -- 98may04, cca -------------------------------------------------------- */ SubMtx * FrontMtx_lowerMtx ( FrontMtx *frontmtx, int K, int J ) ; /* -------------------------------------------------- purpose -- fill *pnadj with the number of fronts K such that L_{K,J} != 0 and *padj with a pointer to a list of those fronts created -- 98may04, cca -------------------------------------------------- */ void FrontMtx_lowerAdjFronts ( FrontMtx *frontmtx, int J, int *pnadj, int **padj ) ; /* -------------------------------------------------- purpose -- fill *pnadj with the number of fronts K such that U_{J,K} != 0 and *padj with a pointer to a list of those fronts created -- 98may04, cca -------------------------------------------------- */ void FrontMtx_upperAdjFronts ( FrontMtx *frontmtx, int J, int *pnadj, int **padj ) ; /* ------------------------------------------------------ purpose -- return the number of nonzero L_{K,J} blocks created -- 98may04, cca ------------------------------------------------------ */ int FrontMtx_nLowerBlocks ( FrontMtx *frontmtx ) ; /* ------------------------------------------------------ purpose -- return the number of nonzero U_{K,J} blocks created -- 98may04, cca ------------------------------------------------------ */ int FrontMtx_nUpperBlocks ( FrontMtx *frontmtx ) ; /* --------------------------------------------------------- purpose -- return a pointer to the upper block IVL object created -- 98jun13, cca --------------------------------------------------------- */ IVL * FrontMtx_upperBlockIVL ( FrontMtx *frontmtx ) ; /* --------------------------------------------------------- purpose -- return a pointer to the lower block IVL object created -- 98jun13, cca --------------------------------------------------------- */ IVL * FrontMtx_lowerBlockIVL ( FrontMtx *frontmtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- basic initializer frontETree -- ETree object that stores the front tree symbfacIVL -- IVL object that stores the symbolic factorization manager -- SubMtxManager object to manage SubMtx objects type -- type of entries SPOOLES_REAL --> real SPOOLES_COMPLEX --> complex symmetryflag -- symmetry flag, SPOOLES_SYMMETRIC --> symmetric structure and entries SPOOLES_HERMITIAN --> hermitian (complex only) SPOOLES_NONSYMMETRIC --> nonsymmetric entries sparsityflag -- flag to specify dense or sparse fronts FRONTMTX_DENSE_FRONTS --> dense fronts FRONTMTX_SPARSE_FRONTS --> sparse fronts pivotingflag -- flag to specify pivoting enabled SPOOLES_NO_PIVOTING --> pivoting not used SPOOLES_PIVOTING --> pivoting used in a multithreaded environment, we need to protect the critical section where data is allocated. we use a lockflag to do this. in a serial or distributed environment, use lockflag = 0. lockflag -- flag to specify lock status NO_LOCK --> mutex lock is not allocated or initialized LOCK_IN_PROCESS --> mutex lock is allocated and it can synchronize only threads in this process. LOCK_OVER_ALL_PROCESSES --> mutex lock is allocated and it can synchronize only threads in this and other processes. in a distributed environment we need to specify which process owns each front. when we can preallocate data structures (when there is no pivoting and dense fronts are stored) we need each process to determine what parts of the data it can allocate and set up. in a serial or multithreaded environment, use ownersIV = NULL. ownersIV -- map from fronts to owning processes myid -- id of this process. submatrices (be they lower, diagonal, block diagonal, upper) are stored in SubMtx objects. the management of these objects, (allocation and deallocation) is managed by the SubMtxManager manager object. manager -- SubMtxManager object to handle the submatrices created -- 98may04, cca ------------------------------------------------------------------ */ void FrontMtx_init ( FrontMtx *frontmtx, ETree *frontETree, IVL *symbfacIVL, int type, int symmetryflag, int sparsityflag, int pivotingflag, int lockflag, int myid, IV *ownersIV, SubMtxManager *manager, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in factor.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------- compute an (U^T + I)D(I + U) or (L + I)D(I + L) factorization of A. this is a wrapper method around FrontMtx_factorPencil(). input -- frontmtx -- pointer to the FrontMtx object that will hold the factorization pencil -- pointer to the Pencil object that holds A + sigma*B tau -- upper bound on entries in L and U, used only when pivoting enabled droptol -- lower bound on entries in L and U, used only when sparsity enabled perror -- error flag, on return *perror >= 0 --> factorization failed at front *perror *perror < 0 --> factorization succeeded cpus[] -- timing array cpus[0] -- initialize fronts cpus[1] -- load original entries cpus[2] -- get updates from descendents cpus[3] -- assembled postponed data cpus[4] -- factor the front cpus[5] -- extract postponed data cpus[6] -- store factor entries cpus[7] -- miscellaneous time cpus[8] -- total time stats[] -- statistics array stats[0] -- # of pivots stats[1] -- # of pivot tests stats[2] -- # of delayed rows and columns stats[3] -- # of entries in D stats[4] -- # of entries in L stats[5] -- # of entries in U msglvl -- message level msgFile -- message file created -- 98mar27, cca modified -- 98mar27, cca perror added to argument list ------------------------------------------------------------------- */ Chv * FrontMtx_factorInpMtx ( FrontMtx *frontmtx, InpMtx *inpmtx, double tau, double droptol, ChvManager *chvmanager, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile ) ; /* ------------------------------------------------------------------- compute an (U^T + I)D(I + U) or (L + I)D(I + L) factorization of A + sigma*B. input -- frontmtx -- pointer to the FrontMtx object that will hold the factorization pencil -- pointer to the Pencil object that holds A + sigma*B tau -- upper bound on entries in L and U, used only when pivoting enabled droptol -- lower bound on entries in L and U, used only when sparsity enabled perror -- error flag, on return *perror >= 0 --> factorization failed at front *perror *perror < 0 --> factorization succeeded cpus[] -- timing array cpus[0] -- initialize fronts cpus[1] -- load original entries cpus[2] -- get updates from descendents cpus[3] -- assembled postponed data cpus[4] -- factor the front cpus[5] -- extract postponed data cpus[6] -- store factor entries cpus[7] -- miscellaneous time cpus[8] -- total time stats[] -- statistics array stats[0] -- # of pivots stats[1] -- # of pivot tests stats[2] -- # of delayed rows and columns stats[3] -- # of entries in D stats[4] -- # of entries in L stats[5] -- # of entries in U msglvl -- message level msgFile -- message file created -- 98mar27, cca modified -- 98mar27, cca perror added to argument list ------------------------------------------------------------------- */ Chv * FrontMtx_factorPencil ( FrontMtx *frontmtx, Pencil *pencil, double tau, double droptol, ChvManager *chvmanager, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in factorUtil.c ------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------- purpose -- initialize a front created -- 98may04, cca ----------------------------- */ void FrontMtx_initializeFront ( FrontMtx *frontmtx, Chv *frontJ, int J ) ; /* ------------------------------------------------------------------ purpose -- to visit a front during a factorization. note: this method is called by the serial, multithreaded and MPI factorization codes. frontmtx -- front matrix object pencil -- matrix pencil for A + sigma*B J -- id of front we are working on myid -- id of thread or process owners[] -- map from fronts to owning threads, in a serial environment, owners = NULL fronts[] -- vector of pointers to fronts lookahead -- parameter controls the partial upward visiting of ancestors before returning tau -- used when pivoting enabled, |L_{j,i}| and |U_{i,j}| <= tau droptol -- used for an approximate factorization stored |L_{j,i}| and |U_{i,j}| > droptol status[] -- status vector for the fronts, 'W' -- needs to be woke up 'A' -- active front 'F' -- front is finished heads[] -- vector of pointers to IP objects that store the front-to-front update lists pivotsizesIV -- IV object used during the factorization of a front when pivoting is enabled workDV -- DV object used for working storage parent -- front parent vector aggList -- list object used in parallel environment, used to store aggregate fronts postList -- list object used in pivoting and/or parallel environments, used to stored delayed data and/or to synchronize the factorization chvmanager -- used to manage working storage for Chv objects stats[] -- statistics vector cpus[] -- vector to hold breakdown of cpu times msglvl -- message level msgFil -- message file created -- 98may04, cca ------------------------------------------------------------------ */ char FrontMtx_factorVisit ( FrontMtx *frontmtx, Pencil *pencil, int J, int myid, int owners[], Chv *fronts[], int lookahead, double tau, double droptol, char status[], IP *heads[], IV *pivotsizesIV, DV *workDV, int parent[], ChvList *aggList, ChvList *postList, ChvManager *chvmanager, int stats[], double cpus[], int msglvl, FILE *msgFile ) ; /* -------------------------------------------- purpose -- set up the front's data structure created -- 98mar27, cca -------------------------------------------- */ Chv * FrontMtx_setupFront ( FrontMtx *frontmtx, Pencil *pencil, int J, int myid, int owners[], ChvManager *chvmanager, double cpus[], int msglvl, FILE *msgFile ) ; /* -------------------------------------------------------------------- purpose -- to set up the link data structures for a parallel factorization for process myid return value -- pointer to IP *heads[nfront+2], which contains the beginning of a list of IP objects that store the remaining updates to the fronts. note, heads[nfront] is the first IP object in the free list. heads[nfront+1] is the base address of the allocated IP objects. created -- 98mar07, cca -------------------------------------------------------------------- */ IP ** FrontMtx_factorSetup ( FrontMtx *frontmtx, IV *frontOwnersIV, int myid, int msglvl, FILE *msgFile ) ; /* ----------------------------------------------- create and return the nactiveChild vector. nactiveChild[J] contains the number of children of J that belong to an active path created -- 97jul03, cca ----------------------------------------------- */ int * FrontMtx_nactiveChild ( FrontMtx *frontmtx, char *status, int myid ) ; /* --------------------------------------------------------- create, initialize and return a Ideq object that will be used for a parallel factorization, forward solve, or backward solve. the status[] vector will be set as follows: status[J] = activeflag if J is on an active path status[J] = inactiveflag if J is not on an active path created -- 98mar27, cca --------------------------------------------------------- */ Ideq * FrontMtx_setUpDequeue ( FrontMtx *frontmtx, int owners[], int myid, char status[], IP *heads[], char activeFlag, char inactiveFlag, int msglvl, FILE *msgFile ) ; /* ----------------------------------------------------------------- purpose -- load the dequeue with the leaves of the active subtree used for a factorization and forward solve created -- 98mar27, cca ----------------------------------------------------------------- */ void FrontMtx_loadActiveLeaves ( FrontMtx *frontmtx, char status[], char activeFlag, Ideq *dequeue ) ; /* ----------------------------------------------- create, initialize and return a ChvList object to deal with postponed chevrons created -- 97jul03, cca ----------------------------------------------- */ ChvList * FrontMtx_postList ( FrontMtx *frontmtx, IV *frontOwnersIV, int lockflag ) ; /* ----------------------------------------------- create, initialize and return a ChvList object to deal with aggregate chevrons created -- 97jul03, cca ----------------------------------------------- */ ChvList * FrontMtx_aggregateList ( FrontMtx *frontmtx, IV *frontOwnersIV, int lockflag ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in loadEntries.c ----------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ load entries from sigma*A chv -- pointer to the Chv object that holds the front pencil -- pointer to a Pencil that holds the matrix entries msglvl -- message level msgFile -- message file created -- 97jul18, cca ------------------------------------------------------------ */ void FrontMtx_loadEntries ( Chv *chv, Pencil *pencil, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in update.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ accumulate updates to front J, store them in the Chv object created -- 98may04, cca ------------------------------------------------------------ */ void FrontMtx_update ( FrontMtx *frontmtx, Chv *frontJ, IP *heads[], char status[], DV *tempDV, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in postponed.c ------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- to assemble any postponed data into frontJ frontJ -- pointer to Chv objec that contains current front chvlist -- pointer to a ChvList object that handles the lists of postponed Chv objects chvmanager -- pointer to a ChvManager object for the list of free Chv objects pndelay -- pointer to address to contain the # of delayed rows and columns that were assembled into the front return value -- pointer to Chv object that contains the new front created -- 98may04, cca ------------------------------------------------------------------ */ Chv * FrontMtx_assemblePostponedData ( FrontMtx *frontmtx, Chv *frontJ, ChvList *chvlist, ChvManager *chvmanager, int *pndelay ) ; /* --------------------------------------------------------- purpose -- extract and store the postponed data frontJ -- pointer to present front object npost -- # of postponed rows and columns in frontJ K -- parent of J chvlist -- pointer to a ChvList object that handles the lists of postponed Chv objects a singly linked list to assemble chvmanager -- pointer to a ChvManager object for the list of free Chv objects created -- 98may04, cca --------------------------------------------------------- */ void FrontMtx_storePostponedData ( FrontMtx *frontmtx, Chv *frontJ, int npost, int K, ChvList *chvlist, ChvManager *chvmanager ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in storeFront.c ------------------------------------ ------------------------------------------------------------------------ */ /* ---------------------------------------------------------------- purpose -- to store the factor indicies and entries from front J pivotsizesIV -- used for symmetric or hermitian and pivoting droptol -- used for drop tolerance factorization, an entry is stored if its magnitude > droptol created -- 98may04, cca ---------------------------------------------------------------- */ void FrontMtx_storeFront ( FrontMtx *frontmtx, Chv *frontJ, IV *pivotsizesIV, double droptol, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in postProcess.c ----------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- purpose -- post-process the factorization (1) permute row and column adjacency objects if necessary (2) permute lower and upper matrices if necessary (3) update the block adjacency objects if necessary (4) split the chevron submatrices into submatrices and make the submatrix indices local w.r.t their fronts created -- 98mar05, cca -------------------------------------------------------------- */ void FrontMtx_postProcess ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in permute.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- permute the upper adjacency structure so that the indices in bnd{J} are in ascending order w.r.t. their ancestors created -- 98mar05, cca ------------------------------------------------------------------ */ void FrontMtx_permuteUpperAdj ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; /* ------------------------------------------------------------------ purpose -- permute the lower adjacency structure so that the indices in bnd{J} are in ascending order w.r.t. their ancestors created -- 98mar05, cca ------------------------------------------------------------------ */ void FrontMtx_permuteLowerAdj ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; /* ------------------------------------------------------------ purpose -- if the columns indices of the front matrix are in different order than the column indices of U_{J,bnd{J}}, sort the columns of U_{J,bnd{J}} into ascending order w.r.t the column indices of the front matrix. created -- 98mar05, cca ------------------------------------------------------------ */ void FrontMtx_permuteUpperMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; /* -------------------------------------------------------- purpose -- if the row indices of the front matrix are in different order than the row indices of L_{bnd{J},J}, sort the rows of L_{bnd{J},J} into ascending order w.r.t the row indices of the front matrix. created -- 98mar05, cca -------------------------------------------------------- */ void FrontMtx_permuteLowerMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in split.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------------------- purpose -- for each U_{J,bnd{J}} matrix, remove from hash table, split into their U_{J,K} submatrices and insert into the hash table. created -- 98may04, cca ---------------------------------------------------------------- */ void FrontMtx_splitUpperMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; /* ---------------------------------------------------------------- purpose -- for each L_{bnd{J},J} matrix, remove from hash table, split into their L_{K,J} submatrices and insert into the hash table. created -- 98may04, cca ---------------------------------------------------------------- */ void FrontMtx_splitLowerMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solve.c ----------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- purpose -- to solve a linear system frontmtx -- FrontMtx object that holds the factor matrices solmtx -- DenseMtx that holds the solution rhsmtx -- DenseMtx that holds the right hand side matrix note: right hand side entries are copied from rhsmtx, and solution entries are copied into solmtx. when the row indices of rhsmtx and solmtx are identical, rhsmtx and solmtx can be the same object. cpus -- vector to hold cpu breakdown time cpus[0] -- set up solves cpus[1] -- fetch rhs and store solution cpus[2] -- forward solve cpus[3] -- diagonal solve cpus[4] -- backward solve cpus[5] -- total time mtxmanager -- object that manages working storage msglvl -- message level msgFile -- message file created -- 98may04, cca ------------------------------------------------------------ */ void FrontMtx_solve ( FrontMtx *frontmtx, DenseMtx *solmtx, DenseMtx *rhsmtx, SubMtxManager *mtxmanager, double cpus[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solveUtil.c ------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------- load the right hand side for the owned fronts created -- 98mar19, cca --------------------------------------------- */ SubMtx ** FrontMtx_loadRightHandSide ( FrontMtx *frontmtx, DenseMtx *rhsmtx, int owners[], int myid, SubMtxManager *mtxmanager, int msglvl, FILE *msgFile ) ; /* -------------------------------------- visit front J during the forward solve created -- 98mar27, cca -------------------------------------- */ void FrontMtx_forwardVisit ( FrontMtx *frontmtx, int J, int nrhs, int *owners, int myid, SubMtxManager *mtxmanager, SubMtxList *aggList, SubMtx *p_mtx[], char frontIsDone[], IP *heads[], SubMtx *p_agg[], char status[], int msglvl, FILE *msgFile ) ; /* -------------------------------------------------- purpose -- visit front J during the diagonal solve created -- 98feb20, cca -------------------------------------------------- */ void FrontMtx_diagonalVisit ( FrontMtx *frontmtx, int J, int owners[], int myid, SubMtx *p_mtx[], char frontIsDone[], SubMtx *p_agg[], int msglvl, FILE *msgFile ) ; /* --------------------------------------- visit front J during the backward solve created -- 98mar27, cca --------------------------------------- */ void FrontMtx_backwardVisit ( FrontMtx *frontmtx, int J, int nrhs, int *owners, int myid, SubMtxManager *mtxmanager, SubMtxList *aggList, SubMtx *p_mtx[], char frontIsDone[], IP *heads[], SubMtx *p_agg[], char status[], int msglvl, FILE *msgFile ) ; /* --------------------------------------------------- purpose -- move the solution from the individual SubMtx objects into the global solution SubMtx object created -- 98feb20 --------------------------------------------------- */ void FrontMtx_storeSolution ( FrontMtx *frontmtx, int owners[], int myid, SubMtxManager *manager, SubMtx *p_mtx[], DenseMtx *solmtx, int msglvl, FILE *msgFile ) ; /* --------------------------------------------------- purpose -- load the dequeue with the roots of the active subtree used for a backward solve created -- 98mar27, cca --------------------------------------------------- */ void FrontMtx_loadActiveRoots ( FrontMtx *frontmtx, char status[], char activeFlag, Ideq *dequeue ) ; /* -------------------------------------------------------------------- purpose -- to set up the link data structures for a forward solve return value -- pointer to IP *heads[nfront+2], which contains the beginning of a list of IP objects that store the remaining updates to the fronts. note, heads[nfront] is the first IP object in the free list. heads[nfront+1] is the base address of the allocated IP objects. created -- 98feb20, cca -------------------------------------------------------------------- */ IP ** FrontMtx_forwardSetup ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; /* --------------------------------------------------------- purpose -- set up the linked lists for the backward solve created -- 98feb20, cca --------------------------------------------------------- */ IP ** FrontMtx_backwardSetup ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in QRfactor.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ purpose -- to compute the (U+I)D(I+U) factorization of A^TA, where A = QR, R = (D^{1/2} + D^{1/2}U) cpus[0] -- setup time cpus[1] -- initialize and load staircase matrix cpus[2] -- permute the rows into staircase form cpus[3] -- factor the matrix cpus[4] -- scale and store factor entries cpus[5] -- store update entries cpus[6] -- miscellaneous time created -- 98may28, cca ------------------------------------------------------------ */ void FrontMtx_QR_factor ( FrontMtx *frontmtx, InpMtx *mtxA, ChvManager *chvmanager, double cpus[], double *pfacops, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in QRsolve.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------- minimize ||b - Ax||_2 by solving (U^T + I) * D * (I + U) X = A^T * B where A = QR = QD(I + U) by calling FrontMtx_solve() mtxmanager -- object that manages working storage cpus -- vector of cpu time breakdowns cpus[0] -- set up solves cpus[1] -- fetch rhs and store solution cpus[2] -- forward solve cpus[3] -- diagonal solve cpus[4] -- backward solve cpus[5] -- total solve time cpus[6] -- time to compute A^T * B cpus[7] -- total time created -- 97may27, dkw modified -- 98may28, cca ------------------------------------------------- */ void FrontMtx_QR_solve ( FrontMtx *frontmtx, InpMtx *mtxA, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *manager, double cpus[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in QRutil.c ---------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------------- purpose -- to setup two data structures for a QR serial or multithreaded factorization rowsIVL[J] -- list of rows of A to be assembled into front J firstnz[irow] -- column with location of leading nonzero of row in A created -- 98may29, cca -------------------------------------------------------------------- */ void FrontMtx_QR_setup ( FrontMtx *frontmtx, InpMtx *mtxA, IVL **prowsIVL, int **pfirstnz, int msglvl, FILE *msgFile ) ; /* ----------------------------------------------- purpose -- visit front J during a serial or multithreaded QR factorization cpus[1] -- initialize and load staircase matrix cpus[2] -- factor the matrix cpus[3] -- scale and store factor entries cpus[4] -- store update entries created -- 98may28, cca ----------------------------------------------- */ void FrontMtx_QR_factorVisit ( FrontMtx *frontmtx, int J, InpMtx *mtxA, IVL *rowsIVL, int firstnz[], ChvList *updlist, ChvManager *chvmanager, char status[], int colmap[], DV *workDV, double cpus[], double *pfacops, int msglvl, FILE *msgFile ) ; /* -------------------------------------------------------------- purpose -- create and return an A2 object that contains rows of A and rows from update matrices of the children. the matrix may not be in staircase form created -- 98may25, cca -------------------------------------------------------------- */ A2 * FrontMtx_QR_assembleFront ( FrontMtx *frontmtx, int J, InpMtx *mtxA, IVL *rowsIVL, int firstnz[], int colmap[], Chv *firstchild, DV *workDV, int msglvl, FILE *msgFile ) ; /* ---------------------------------------------------- store the factor entries of the reduced front matrix created -- 98may25, cca ---------------------------------------------------- */ void FrontMtx_QR_storeFront ( FrontMtx *frontmtx, int J, A2 *frontJ, int msglvl, FILE *msgFile ) ; /* ------------------------------------------------- purpose -- to create and return a Chv object that holds the update matrix for front J created -- 98may25, cca ------------------------------------------------- */ Chv * FrontMtx_QR_storeUpdate ( FrontMtx *frontmtx, int J, A2 *frontJ, ChvManager *chvmanager, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------- purpose -- produce a map from each column to the front that contains it created -- 98may04, cca ----------------------------------------- */ IV * FrontMtx_colmapIV ( FrontMtx *frontmtx ) ; /* -------------------------------------------------------------------- purpose -- produce a map from each row to the front that contains it created -- 98may04, cca -------------------------------------------------------------------- */ IV * FrontMtx_rowmapIV ( FrontMtx *frontmtx ) ; /* ------------------------------------------------------------- compute the inertia of a symmetric matrix fill *pnnegative with the number of negative eigenvalues of A fill *pnzero with the number of zero eigenvalues of A fill *pnpositive with the number of positive eigenvalues of A created -- 98may04, cca ------------------------------------------------------------- */ void FrontMtx_inertia ( FrontMtx *frontmtx, int *pnnegative, int *pnzero, int *pnpositive ) ; /* ------------------------------------------------------- purpose -- create and return an IV object that contains all the row ids owned by process myid. created -- 98jun13, cca ------------------------------------------------------- */ IV * FrontMtx_ownedRowsIV ( FrontMtx *frontmtx, int myid, IV *ownersIV, int msglvl, FILE *msgFile ) ; /* ------------------------------------------------------- purpose -- create and return an IV object that contains all the column ids owned by process myid. created -- 98jun13, cca ------------------------------------------------------- */ IV * FrontMtx_ownedColumnsIV ( FrontMtx *frontmtx, int myid, IV *ownersIV, int msglvl, FILE *msgFile ) ; /* ---------------------------------------------------------------- purpose -- to create and return an IVL object that holds the submatrix nonzero pattern for the upper triangular factor. NOTE: this method supercedes calling IVL_mapEntries() on the column adjacency structure. that gave problems when pivoting forced some fronts to have no eliminated columns. in some cases, solve aggregates were expected when none were forthcoming. created -- 98aug20, cca ---------------------------------------------------------------- */ IVL * FrontMtx_makeUpperBlockIVL ( FrontMtx *frontmtx, IV *colmapIV ) ; /* ---------------------------------------------------------------- purpose -- to create and return an IVL object that holds the submatrix nonzero pattern for the lower triangular factor. NOTE: this method supercedes calling IVL_mapEntries() on the row adjacency structure. that gave problems when pivoting forced some fronts to have no eliminated columns. in some cases, solve aggregates were expected when none were forthcoming. created -- 98aug20, cca ---------------------------------------------------------------- */ IVL * FrontMtx_makeLowerBlockIVL ( FrontMtx *frontmtx, IV *rowmapIV ) ; /* --------------------------------------------------------------- purpose -- to compute and return the number of floating point operations to perform a solve with a single right hand side. created -- 98sep26, cca --------------------------------------------------------------- */ int FrontMtx_nSolveOps ( FrontMtx *frontmtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------- purpose -- to read in an FrontMtx object from a file input -- fn -- filename, must be *.frontmtxb or *.frontmtxf return value -- 1 if success, 0 if failure created -- 98may04, cca ----------------------------------------------------- */ int FrontMtx_readFromFile ( FrontMtx *frontmtx, char *fn ) ; /* ------------------------------------------------------------ purpose -- to read an FrontMtx object from a formatted file return value -- 1 if success, 0 if failure created -- 98may04, cca ------------------------------------------------------------ */ int FrontMtx_readFromFormattedFile ( FrontMtx *frontmtx, FILE *fp ) ; /* -------------------------------------------------------- purpose -- to read an FrontMtx object from a binary file return value -- 1 if success, 0 if failure created -- 98may04, cca -------------------------------------------------------- */ int FrontMtx_readFromBinaryFile ( FrontMtx *frontmtx, FILE *fp ) ; /* ------------------------------------------------- purpose -- to write an FrontMtx object to a file input -- fn -- filename *.frontmtxb -- binary *.frontmtxf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 98may04, cca ------------------------------------------------- */ int FrontMtx_writeToFile ( FrontMtx *frontmtx, char *fn ) ; /* ----------------------------------------------------------- purpose -- to write an FrontMtx object to a formatted file return value -- 1 if success, 0 otherwise created -- 98may04, cca ----------------------------------------------------------- */ int FrontMtx_writeToFormattedFile ( FrontMtx *frontmtx, FILE *fp ) ; /* ------------------------------------------------------- purpose -- to write an FrontMtx object to a binary file return value -- 1 if success, 0 otherwise created -- 98may04, cca ------------------------------------------------------- */ int FrontMtx_writeToBinaryFile ( FrontMtx *frontmtx, FILE *fp ) ; /* --------------------------------------------------------------- purpose -- to write out the statistics for the FrontMtx object return value -- 1 if success, 0 otherwise created -- 98may04, cca --------------------------------------------------------------- */ int FrontMtx_writeStats ( FrontMtx *frontmtx, FILE *fp ) ; /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98may04, cca ---------------------------------------- */ int FrontMtx_writeForHumanEye ( FrontMtx *frontmtx, FILE *fp ) ; /* ------------------------------------------------------------- purpose -- to write the factor matrices out for a matlab file Lname -- name for lower triangular matrix Dname -- name for diagonal matrix Uname -- name for upper triangular matrix presently works only with 1-d data decomposition created -- 98sep23, cca ------------------------------------------------------------- */ int FrontMtx_writeForMatlab ( FrontMtx *frontmtx, char *Lname, char *Dname, char *Uname, FILE *fp ) ; /*--------------------------------------------------------------------*/ ing nonzero of row in A created -- 98may29, cca -------------------------------------------------------------------- */ void FrontMtx_QR_setup ( FrontMtx *frontmtx, InpMtx *mtxA, IVL **prowsIVL, int **pfirstnz, int msglvl, FILE *msgFile ) ; /* ----------------------------------------------- purpose -- visit front J during a serial or multithreaded QR fFrontMtx/makefile010064400020550007177000000002230663622357700153670ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean FrontMtx/src/makefile010064400020550007177000000015560663602306500161560ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = FrontMtx $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(factor.o) \ $(OBJ).a(factorUtil.o) \ $(OBJ).a(init.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(loadEntries.o) \ $(OBJ).a(permute.o) \ $(OBJ).a(postponed.o) \ $(OBJ).a(postProcess.o) \ $(OBJ).a(QRfactor.o) \ $(OBJ).a(QRsolve.o) \ $(OBJ).a(QRutil.o) \ $(OBJ).a(solve.o) \ $(OBJ).a(solveUtil.o) \ $(OBJ).a(split.o) \ $(OBJ).a(storeFront.o) \ $(OBJ).a(update.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG FrontMtx/src/makeGlobalLib010064400020550007177000000012310660026102200170400ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = FrontMtx SRC = basics.c \ factor.c \ factorUtil.c \ init.c \ instance.c \ IO.c \ loadEntries.c \ permute.c \ postponed.c \ postProcess.c \ QRfactor.c \ QRsolve.c \ QRutil.c \ solve.c \ solveUtil.c \ split.c \ storeFront.c \ update.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a FrontMtx/src/IO.c010064400020550007177000001732210661222335200151230ustar00clevecompmath00000400000006/* IO.c */ #include "../FrontMtx.h" static const char *suffixb = ".frontmtxb" ; static const char *suffixf = ".frontmtxf" ; #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to read in an FrontMtx object from a file input -- fn -- filename, must be *.frontmtxb or *.frontmtxf return value -- 1 if success, 0 if failure created -- 98may04, cca ----------------------------------------------------- */ int FrontMtx_readFromFile ( FrontMtx *frontmtx, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || fn == NULL ) { fprintf(stderr, "\n error in FrontMtx_readFromFile(%p,%s)" "\n bad input\n", frontmtx, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in FrontMtx_readFromFile(%p,%s)" "\n unable to open file %s", frontmtx, fn, fn) ; rc = 0 ; } else { rc = FrontMtx_readFromBinaryFile(frontmtx, fp) ; #if MYDEBUG > 0 fprintf(stdout, "\n rc = %d from FrontMtx_readFromBinaryFile()", rc) ; fflush(stdout) ; #endif fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in FrontMtx_readFromFile(%p,%s)" "\n unable to open file %s", frontmtx, fn, fn) ; rc = 0 ; } else { rc = FrontMtx_readFromFormattedFile(frontmtx, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in FrontMtx_readFromFile(%p,%s)" "\n bad FrontMtx file name %s," "\n must end in %s (binary) or %s (formatted)\n", frontmtx, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in FrontMtx_readFromFile(%p,%s)" "\n bad FrontMtx file name %s," "\n must end in %s (binary) or %s (formatted)\n", frontmtx, fn, fn, suffixb, suffixf) ; rc = 0 ; } #if MYDEBUG > 0 fprintf(stdout, "\n returning rc = %d from FrontMtx_readFromFile()", rc) ; fflush(stdout) ; #endif return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to read an FrontMtx object from a formatted file return value -- 1 if success, 0 if failure created -- 98may04, cca ------------------------------------------------------------ */ int FrontMtx_readFromFormattedFile ( FrontMtx *frontmtx, FILE *fp ) { SubMtx *mtx ; int imtx, J, JK, KJ, nfront, nmtx, rc ; int itemp[10] ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || fp == NULL ) { fprintf(stderr, "\n error in FrontMtx_readFromFormattedFile(%p,%p)" "\n bad input\n", frontmtx, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ FrontMtx_clearData(frontmtx) ; /* ----------------------------- read in the ten scalar fields ----------------------------- */ if ( (rc = IVfscanf(fp, 10, itemp)) != 10 ) { fprintf(stderr, "\n error in FrontMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", frontmtx, fp, rc, 10) ; return(0) ; } frontmtx->nfront = nfront = itemp[0] ; frontmtx->neqns = itemp[1] ; frontmtx->type = itemp[2] ; frontmtx->symmetryflag = itemp[3] ; frontmtx->pivotingflag = itemp[4] ; frontmtx->sparsityflag = itemp[5] ; frontmtx->dataMode = itemp[6] ; frontmtx->nentD = itemp[7] ; frontmtx->nentL = itemp[8] ; frontmtx->nentU = itemp[9] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n nfront = %d" "\n neqns = %d" "\n type = %d" "\n symmetryflag = %d" "\n pivotingflag = %d" "\n sparsityflag = %d" "\n dataMode = %d" "\n nentD = %d" "\n nentL = %d" "\n nentU = %d", frontmtx->nfront, frontmtx->neqns, frontmtx->type, frontmtx->symmetryflag, frontmtx->pivotingflag, frontmtx->sparsityflag, frontmtx->dataMode, frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ; fflush(stdout) ; #endif /* ------------------------ read in the ETree object ------------------------ */ frontmtx->frontETree = ETree_new() ; rc = ETree_readFromFormattedFile(frontmtx->frontETree, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in frontETree object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->tree = frontmtx->frontETree->tree ; #if MYDEBUG > 0 fprintf(stdout, "\n\n ETree object") ; ETree_writeForHumanEye(frontmtx->frontETree, stdout) ; fflush(stdout) ; #endif /* ----------------------------------------- read in the symbolic factorization object ----------------------------------------- */ frontmtx->symbfacIVL = IVL_new() ; frontmtx->symbfacIVL->type = IVL_CHUNKED ; rc = IVL_readFromFormattedFile(frontmtx->symbfacIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in symbfacIVL object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->frontsizesIV = IV_new() ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { /* --------------------------------- read in the front sizes IV object --------------------------------- */ rc = IV_readFromFormattedFile(frontmtx->frontsizesIV, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in frontsizesIV object\n", frontmtx, fp, rc) ; return(0) ; } } else { /* ---------------------------- create from the ETree object ---------------------------- */ IV_init(frontmtx->frontsizesIV, frontmtx->nfront, NULL) ; IVcopy(nfront, IV_entries(frontmtx->frontsizesIV), ETree_nodwghts(frontmtx->frontETree)) ; } if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { /* ----------------------------------------- read in the rowids and colids IVL objects ----------------------------------------- */ if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { frontmtx->rowadjIVL = IVL_new() ; frontmtx->rowadjIVL->type = IVL_CHUNKED ; rc = IVL_readFromFormattedFile(frontmtx->rowadjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in rowadjIVL object\n", frontmtx, fp, rc) ; return(0) ; } } frontmtx->coladjIVL = IVL_new() ; frontmtx->coladjIVL->type = IVL_CHUNKED ; rc = IVL_readFromFormattedFile(frontmtx->coladjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in coladjIVL object\n", frontmtx, fp, rc) ; return(0) ; } fprintf(stdout, "\n coladjIVL read in") ; fflush(stdout) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { /* ------------------------------- set up the five pointer vectors ------------------------------- */ ALLOCATE(frontmtx->p_mtxDJJ, struct _SubMtx *, nfront) ; ALLOCATE(frontmtx->p_mtxUJJ, struct _SubMtx *, nfront) ; ALLOCATE(frontmtx->p_mtxUJN, struct _SubMtx *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { frontmtx->p_mtxDJJ[J] = NULL ; frontmtx->p_mtxUJJ[J] = NULL ; frontmtx->p_mtxUJN[J] = NULL ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { ALLOCATE(frontmtx->p_mtxLJJ, struct _SubMtx *, nfront) ; ALLOCATE(frontmtx->p_mtxLNJ, struct _SubMtx *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { frontmtx->p_mtxLJJ[J] = NULL ; frontmtx->p_mtxLNJ[J] = NULL ; } } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* ----------------------------- read in the lower matrices ----------------------------- */ fscanf(fp, " %d", &nmtx) ; for ( imtx = 0 ; imtx < nmtx ; imtx++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromFormattedFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxLJJ[mtx->colid] = mtx ; } fscanf(fp, " %d", &nmtx) ; for ( imtx = 0 ; imtx < nmtx ; imtx++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromFormattedFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxLNJ[mtx->colid] = mtx ; } } /* ----------------------------- read in the diagonal matrices ----------------------------- */ fscanf(fp, " %d", &nmtx) ; for ( imtx = 0 ; imtx < nmtx ; imtx++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromFormattedFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxDJJ[mtx->rowid] = mtx ; } /* -------------------------- read in the upper matrices -------------------------- */ fscanf(fp, " %d", &nmtx) ; for ( imtx = 0 ; imtx < nmtx ; imtx++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromFormattedFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxUJJ[mtx->rowid] = mtx ; } fscanf(fp, " %d", &nmtx) ; for ( imtx = 0 ; imtx < nmtx ; imtx++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromFormattedFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxUJN[mtx->rowid] = mtx ; } } else { /* ------------------------------------------------------- read in the lower and upper block adjacency IVL objects ------------------------------------------------------- */ if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { frontmtx->lowerblockIVL = IVL_new() ; frontmtx->lowerblockIVL->type = IVL_CHUNKED ; rc = IVL_readFromFormattedFile(frontmtx->lowerblockIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in lowerblockIVL object\n", frontmtx, fp, rc) ; return(0) ; } } frontmtx->upperblockIVL = IVL_new() ; frontmtx->upperblockIVL->type = IVL_CHUNKED ; rc = IVL_readFromFormattedFile(frontmtx->upperblockIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in upperblockIVL object\n", frontmtx, fp, rc) ; return(0) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* -------------------------------------------------------------- read in the lower submatrices and store them into a hash table -------------------------------------------------------------- */ frontmtx->lowerhash = I2Ohash_new() ; fscanf(fp, " %d", &nmtx) ; I2Ohash_init(frontmtx->lowerhash, nfront - 1, nmtx, 0) ; for ( KJ = 0 ; KJ < nmtx ; KJ++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromFormattedFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in lower SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } I2Ohash_insert(frontmtx->lowerhash, mtx->rowid, mtx->colid, (void *) mtx) ; } } /* ----------------------------------------------------------------- read in the diagonal submatrices and store them into a hash table ----------------------------------------------------------------- */ ALLOCATE(frontmtx->p_mtxDJJ, struct _SubMtx *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { frontmtx->p_mtxDJJ[J] = NULL ; } fscanf(fp, " %d", &nmtx) ; for ( J = 0 ; J < nmtx ; J++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromFormattedFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxDJJ[mtx->rowid] = mtx ; } /* -------------------------------------------------------------- read in the upper submatrices and store them into a hash table -------------------------------------------------------------- */ frontmtx->upperhash = I2Ohash_new() ; fscanf(fp, " %d", &nmtx) ; I2Ohash_init(frontmtx->upperhash, nfront-1, nmtx, 0) ; for ( JK = 0 ; JK < nmtx ; JK++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromFormattedFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromFormattedFile(%p,%p)" "\n error %d reading in upper SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } I2Ohash_insert(frontmtx->upperhash, mtx->rowid, mtx->colid, (void *) mtx) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to read an FrontMtx object from a binary file return value -- 1 if success, 0 if failure created -- 98may04, cca -------------------------------------------------------- */ int FrontMtx_readFromBinaryFile ( FrontMtx *frontmtx, FILE *fp ) { SubMtx *mtx ; int imtx, J, JK, KJ, nfront, nmtx, rc ; int itemp[10] ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || fp == NULL ) { fprintf(stderr, "\n error in FrontMtx_readFromBinaryFile(%p,%p)" "\n bad input\n", frontmtx, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ FrontMtx_clearData(frontmtx) ; /* ----------------------------- read in the ten scalar fields ----------------------------- */ if ( (rc = fread((void *) itemp, sizeof(int), 10, fp)) != 10 ) { fprintf(stderr, "\n error in FrontMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", frontmtx, fp, rc, 10) ; return(0) ; } frontmtx->nfront = nfront = itemp[0] ; frontmtx->neqns = itemp[1] ; frontmtx->type = itemp[2] ; frontmtx->symmetryflag = itemp[3] ; frontmtx->pivotingflag = itemp[4] ; frontmtx->sparsityflag = itemp[5] ; frontmtx->dataMode = itemp[6] ; frontmtx->nentD = itemp[7] ; frontmtx->nentL = itemp[8] ; frontmtx->nentU = itemp[9] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n nfront = %d" "\n neqns = %d" "\n type = %d" "\n symmetryflag = %d" "\n pivotingflag = %d" "\n sparsityflag = %d" "\n dataMode = %d" "\n nentD = %d" "\n nentL = %d" "\n nentU = %d", frontmtx->nfront, frontmtx->neqns, frontmtx->type, frontmtx->symmetryflag, frontmtx->pivotingflag, frontmtx->sparsityflag, frontmtx->dataMode, frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ; fflush(stdout) ; #endif /* ------------------------ read in the ETree object ------------------------ */ frontmtx->frontETree = ETree_new() ; rc = ETree_readFromBinaryFile(frontmtx->frontETree, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in frontETree object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->tree = frontmtx->frontETree->tree ; #if MYDEBUG > 0 fprintf(stdout, "\n\n ETree object") ; ETree_writeForHumanEye(frontmtx->frontETree, stdout) ; fflush(stdout) ; #endif /* ----------------------------------------- read in the symbolic factorization object ----------------------------------------- */ frontmtx->symbfacIVL = IVL_new() ; frontmtx->symbfacIVL->type = IVL_CHUNKED ; rc = IVL_readFromBinaryFile(frontmtx->symbfacIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in symbfacIVL object\n", frontmtx, fp, rc) ; return(0) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n symbfacIVL object") ; IVL_writeForHumanEye(frontmtx->symbfacIVL, stdout) ; fflush(stdout) ; #endif frontmtx->frontsizesIV = IV_new() ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { /* --------------------------------- read in the front sizes IV object --------------------------------- */ rc = IV_readFromBinaryFile(frontmtx->frontsizesIV, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in frontsizesIV object\n", frontmtx, fp, rc) ; return(0) ; } } else { /* ---------------------------- create from the ETree object ---------------------------- */ IV_init(frontmtx->frontsizesIV, frontmtx->nfront, NULL) ; IVcopy(nfront, IV_entries(frontmtx->frontsizesIV), ETree_nodwghts(frontmtx->frontETree)) ; } if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { /* ----------------------------------------- read in the rowids and colids IVL objects ----------------------------------------- */ if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { frontmtx->rowadjIVL = IVL_new() ; frontmtx->rowadjIVL->type = IVL_CHUNKED ; rc = IVL_readFromBinaryFile(frontmtx->rowadjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in rowadjIVL object\n", frontmtx, fp, rc) ; return(0) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n rowadjIVL object") ; IVL_writeForHumanEye(frontmtx->rowadjIVL, stdout) ; fflush(stdout) ; #endif } frontmtx->coladjIVL = IVL_new() ; frontmtx->coladjIVL->type = IVL_CHUNKED ; rc = IVL_readFromBinaryFile(frontmtx->coladjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in coladjIVL object\n", frontmtx, fp, rc) ; return(0) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n coladjIVL object") ; IVL_writeForHumanEye(frontmtx->coladjIVL, stdout) ; fflush(stdout) ; #endif } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { /* ------------------------------- set up the five pointer vectors ------------------------------- */ ALLOCATE(frontmtx->p_mtxDJJ, struct _SubMtx *, nfront) ; ALLOCATE(frontmtx->p_mtxUJJ, struct _SubMtx *, nfront) ; ALLOCATE(frontmtx->p_mtxUJN, struct _SubMtx *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { frontmtx->p_mtxDJJ[J] = NULL ; frontmtx->p_mtxUJJ[J] = NULL ; frontmtx->p_mtxUJN[J] = NULL ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { ALLOCATE(frontmtx->p_mtxLJJ, struct _SubMtx *, nfront) ; ALLOCATE(frontmtx->p_mtxLNJ, struct _SubMtx *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { frontmtx->p_mtxLJJ[J] = NULL ; frontmtx->p_mtxLNJ[J] = NULL ; } } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* ----------------------------- read in the lower matrices ----------------------------- */ if ( (rc = fread((void *) &nmtx, sizeof(int), 1, fp)) != 1 ) { fprintf(stderr, "\n error in FrontMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", frontmtx, fp, rc, 1) ; return(0) ; } for ( imtx = 0 ; imtx < nmtx ; imtx++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromBinaryFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxLJJ[mtx->colid] = mtx ; } if ( (rc = fread((void *) &nmtx, sizeof(int), 1, fp)) != 1 ) { fprintf(stderr, "\n error in FrontMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", frontmtx, fp, rc, 1) ; return(0) ; } for ( imtx = 0 ; imtx < nmtx ; imtx++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromBinaryFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxLNJ[mtx->colid] = mtx ; } } /* ----------------------------- read in the diagonal matrices ----------------------------- */ if ( (rc = fread((void *) &nmtx, sizeof(int), 1, fp)) != 1 ) { fprintf(stderr, "\n error in FrontMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", frontmtx, fp, rc, 1) ; return(0) ; } for ( imtx = 0 ; imtx < nmtx ; imtx++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromBinaryFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxDJJ[mtx->rowid] = mtx ; } /* -------------------------- read in the upper matrices -------------------------- */ if ( (rc = fread((void *) &nmtx, sizeof(int), 1, fp)) != 1 ) { fprintf(stderr, "\n error in FrontMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", frontmtx, fp, rc, 1) ; return(0) ; } for ( imtx = 0 ; imtx < nmtx ; imtx++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromBinaryFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxUJJ[mtx->rowid] = mtx ; } if ( (rc = fread((void *) &nmtx, sizeof(int), 1, fp)) != 1 ) { fprintf(stderr, "\n error in FrontMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", frontmtx, fp, rc, 1) ; return(0) ; } for ( imtx = 0 ; imtx < nmtx ; imtx++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromBinaryFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxUJN[mtx->rowid] = mtx ; } } else { /* ------------------------------------------------------- read in the lower and upper block adjacency IVL objects ------------------------------------------------------- */ if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { frontmtx->lowerblockIVL = IVL_new() ; frontmtx->lowerblockIVL->type = IVL_CHUNKED ; rc = IVL_readFromBinaryFile(frontmtx->lowerblockIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in lowerblockIVL object\n", frontmtx, fp, rc) ; return(0) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n lowerblockIVL object") ; IVL_writeForHumanEye(frontmtx->lowerblockIVL, stdout) ; fflush(stdout) ; #endif } frontmtx->upperblockIVL = IVL_new() ; frontmtx->upperblockIVL->type = IVL_CHUNKED ; rc = IVL_readFromBinaryFile(frontmtx->upperblockIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in upperblockIVL object\n", frontmtx, fp, rc) ; return(0) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n upperblockIVL object") ; IVL_writeForHumanEye(frontmtx->upperblockIVL, stdout) ; fflush(stdout) ; #endif if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* -------------------------------------------------------------- read in the lower submatrices and store them into a hash table -------------------------------------------------------------- */ frontmtx->lowerhash = I2Ohash_new() ; if ( (rc = fread((void *) &nmtx, sizeof(int), 1, fp)) != 1 ) { fprintf(stderr, "\n error in FrontMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", frontmtx, fp, rc, 1) ; return(0) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n nmtx = %d", nmtx) ; fflush(stdout) ; #endif I2Ohash_init(frontmtx->lowerhash, frontmtx->nfront-1, nmtx, 0) ; for ( KJ = 0 ; KJ < nmtx ; KJ++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromBinaryFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in lower SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } I2Ohash_insert(frontmtx->lowerhash, mtx->rowid, mtx->colid, (void *) mtx) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n --- lower SubMtx object") ; SubMtx_writeForHumanEye(mtx, stdout) ; fflush(stdout) ; #endif } } /* ----------------------------------------------------------------- read in the diagonal submatrices and store them into a hash table ----------------------------------------------------------------- */ ALLOCATE(frontmtx->p_mtxDJJ, struct _SubMtx *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { frontmtx->p_mtxDJJ[J] = NULL ; } if ( (rc = fread((void *) &nmtx, sizeof(int), 1, fp)) != 1 ) { fprintf(stderr, "\n error in FrontMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", frontmtx, fp, rc, 1) ; return(0) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n nmtx = %d", nmtx) ; fflush(stdout) ; #endif for ( J = 0 ; J < nmtx ; J++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromBinaryFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in diag SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } frontmtx->p_mtxDJJ[mtx->rowid] = mtx ; #if MYDEBUG > 0 fprintf(stdout, "\n\n --- diagonal SubMtx object") ; SubMtx_writeForHumanEye(mtx, stdout) ; fflush(stdout) ; #endif } /* -------------------------------------------------------------- read in the upper submatrices and store them into a hash table -------------------------------------------------------------- */ frontmtx->upperhash = I2Ohash_new() ; if ( (rc = fread((void *) &nmtx, sizeof(int), 1, fp)) != 1 ) { fprintf(stderr, "\n error in FrontMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", frontmtx, fp, rc, 1) ; return(0) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n nmtx = %d", nmtx) ; fflush(stdout) ; #endif I2Ohash_init(frontmtx->upperhash, nfront-1, nmtx, 0) ; for ( JK = 0 ; JK < nmtx ; JK++ ) { mtx = SubMtx_new() ; rc = SubMtx_readFromBinaryFile(mtx, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_readFromBinaryFile(%p,%p)" "\n error %d reading in upper SubMtx object\n", frontmtx, fp, rc) ; return(0) ; } I2Ohash_insert(frontmtx->upperhash, mtx->rowid, mtx->colid, (void *) mtx) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n --- upper SubMtx object") ; SubMtx_writeForHumanEye(mtx, stdout) ; fflush(stdout) ; #endif } } #if MYDEBUG > 0 fprintf(stdout, "\n\n LEAVING READ_FROM_BINARY_FILE") ; fflush(stdout) ; #endif return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to write an FrontMtx object to a file input -- fn -- filename *.frontmtxb -- binary *.frontmtxf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 98may04, cca ------------------------------------------------- */ int FrontMtx_writeToFile ( FrontMtx *frontmtx, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToFile(%p,%s)" "\n bad input\n", frontmtx, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in FrontMtx_writeToFile(%p,%s)" "\n unable to open file %s", frontmtx, fn, fn) ; rc = 0 ; } else { rc = FrontMtx_writeToBinaryFile(frontmtx, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in FrontMtx_writeToFile(%p,%s)" "\n unable to open file %s", frontmtx, fn, fn) ; rc = 0 ; } else { rc = FrontMtx_writeToFormattedFile(frontmtx, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in FrontMtx_writeToFile(%p,%s)" "\n unable to open file %s", frontmtx, fn, fn) ; rc = 0 ; } else { rc = FrontMtx_writeForHumanEye(frontmtx, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in FrontMtx_writeToFile(%p,%s)" "\n unable to open file %s", frontmtx, fn, fn) ; rc = 0 ; } else { rc = FrontMtx_writeForHumanEye(frontmtx, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to write an FrontMtx object to a formatted file return value -- 1 if success, 0 otherwise created -- 98may04, cca ----------------------------------------------------------- */ int FrontMtx_writeToFormattedFile ( FrontMtx *frontmtx, FILE *fp ) { SubMtx *mtx ; int ii, J, K, nadj, nfront, nmtx, rc ; int *adj ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToFormattedFile(%p,%p)" "\n bad input\n", frontmtx, fp) ; exit(-1) ; } nfront = frontmtx->nfront ; /* --------------------------- write the ten scalar fields --------------------------- */ rc = fprintf(fp, "\n %d %d %d %d %d %d %d %d %d %d", frontmtx->nfront, frontmtx->neqns, frontmtx->type, frontmtx->symmetryflag, frontmtx->pivotingflag, frontmtx->sparsityflag, frontmtx->dataMode, frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", frontmtx, fp, rc) ; return(0) ; } /* -------------------------- write out the ETree object -------------------------- */ rc = ETree_writeToFormattedFile(frontmtx->frontETree, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToFormattedFile(%p,%p)" "\n error %d writing frontETree object\n", frontmtx, fp, rc) ; return(0) ; } /* ------------------------------------------- write out the symbolic factorization object ------------------------------------------- */ rc = IVL_writeToFormattedFile(frontmtx->symbfacIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToFormattedFile(%p,%p)" "\n error %d writing symbfacIVL object\n", frontmtx, fp, rc) ; return(0) ; } if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { /* -------------------------------- write out the front sizes object -------------------------------- */ rc = IV_writeToFormattedFile(frontmtx->frontsizesIV, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToFormattedFile(%p,%p)" "\n error %d writing frontsizesIV object\n", frontmtx, fp, rc) ; return(0) ; } } if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { /* ------------------------------------------- write out the rowids and colids IVL objects ------------------------------------------- */ if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { rc = IVL_writeToFormattedFile(frontmtx->rowadjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToFormattedFile(%p,%p)" "\n error %d writing rowadjIVL object\n", frontmtx, fp, rc) ; return(0) ; } } rc = IVL_writeToFormattedFile(frontmtx->coladjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToFormattedFile(%p,%p)" "\n error %d writing coladjIVL object\n", frontmtx, fp, rc) ; return(0) ; } } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* ------------------------------------------------ count the number of L_{J,J} matrices write out the count, then write out the matrices ------------------------------------------------ */ for ( J = nmtx = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_lowerMtx(frontmtx, J, J)) != NULL ) { nmtx++ ; } } fprintf(fp, "\n %d", nmtx) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_lowerMtx(frontmtx, J, J)) != NULL ) { SubMtx_writeToFormattedFile(mtx, fp) ; } } /* ------------------------------------------------ count the number of L_{*,J} matrices write out the count, then write out the matrices ------------------------------------------------ */ for ( J = nmtx = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_lowerMtx(frontmtx, nfront, J)) != NULL ){ nmtx++ ; } } fprintf(fp, "\n %d", nmtx) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_lowerMtx(frontmtx, nfront, J)) != NULL ){ SubMtx_writeToFormattedFile(mtx, fp) ; } } } /* ------------------------------------------------ count the number of diagonal matrices write out the count, then write out the matrices ------------------------------------------------ */ for ( J = nmtx = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_diagMtx(frontmtx, J)) != NULL ) { nmtx++ ; } } fprintf(fp, "\n %d", nmtx) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_diagMtx(frontmtx, J)) != NULL ) { SubMtx_writeToFormattedFile(mtx, fp) ; } } /* ------------------------------------------------ count the number of U_{J,J} matrices write out the count, then write out the matrices ------------------------------------------------ */ for ( J = nmtx = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_upperMtx(frontmtx, J, J)) != NULL ) { nmtx++ ; } } fprintf(fp, "\n %d", nmtx) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_upperMtx(frontmtx, J, J)) != NULL ) { SubMtx_writeToFormattedFile(mtx, fp) ; } } /* ------------------------------------------------ count the number of U_{J,*} matrices write out the count, then write out the matrices ------------------------------------------------ */ for ( J = nmtx = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_upperMtx(frontmtx, J, nfront)) != NULL ) { nmtx++ ; } } fprintf(fp, "\n %d", nmtx) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_upperMtx(frontmtx, J, nfront)) != NULL ) { SubMtx_writeToFormattedFile(mtx, fp) ; } } } else { /* --------------------------------------------------------- write out the lower and upper block adjacency IVL objects --------------------------------------------------------- */ if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { rc = IVL_writeToFormattedFile(frontmtx->lowerblockIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToFormattedFile(%p,%p)" "\n error %d writing lowerblockIVL object\n", frontmtx, fp, rc) ; return(0) ; } } rc = IVL_writeToFormattedFile(frontmtx->upperblockIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToFormattedFile(%p,%p)" "\n error %d writing upperblockIVL object\n", frontmtx, fp, rc) ; return(0) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* ------------------------------- write out the lower submatrices ------------------------------- */ for ( J = nmtx = 0 ; J < frontmtx->nfront ; J++ ) { IVL_listAndSize(frontmtx->lowerblockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = adj[ii] ; if ( (mtx = FrontMtx_lowerMtx(frontmtx, K, J)) != NULL ) { nmtx++ ; } } } fprintf(fp, "\n %d", nmtx) ; for ( J = 0 ; J < frontmtx->nfront ; J++ ) { IVL_listAndSize(frontmtx->lowerblockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = adj[ii] ; if ( (mtx = FrontMtx_lowerMtx(frontmtx, K, J)) != NULL ) { SubMtx_writeToFormattedFile(mtx, fp) ; } } } } /* ---------------------------------- write out the diagonal submatrices ---------------------------------- */ for ( J = nmtx = 0 ; J < frontmtx->nfront ; J++ ) { if ( (mtx = FrontMtx_diagMtx(frontmtx, J)) != NULL ) { nmtx++ ; } } fprintf(fp, "\n %d", nmtx) ; for ( J = 0 ; J < frontmtx->nfront ; J++ ) { if ( (mtx = FrontMtx_diagMtx(frontmtx, J)) != NULL ) { SubMtx_writeToFormattedFile(mtx, fp) ; } } /* ------------------------------- write out the upper submatrices ------------------------------- */ for ( J = nmtx = 0 ; J < frontmtx->nfront ; J++ ) { IVL_listAndSize(frontmtx->upperblockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = adj[ii] ; if ( (mtx = FrontMtx_upperMtx(frontmtx, J, K)) != NULL ) { nmtx++ ; } } } fprintf(fp, "\n %d", nmtx) ; for ( J = 0 ; J < frontmtx->nfront ; J++ ) { IVL_listAndSize(frontmtx->upperblockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = adj[ii] ; if ( (mtx = FrontMtx_upperMtx(frontmtx, J, K)) != NULL ) { SubMtx_writeToFormattedFile(mtx, fp) ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to write an FrontMtx object to a binary file return value -- 1 if success, 0 otherwise created -- 98may04, cca ------------------------------------------------------- */ int FrontMtx_writeToBinaryFile ( FrontMtx *frontmtx, FILE *fp ) { SubMtx *mtx ; int ii, J, K, nadj, nfront, nmtx, rc ; int *adj ; int itemp[10] ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToBinaryFile(%p,%p)" "\n bad input\n", frontmtx, fp) ; exit(-1) ; } /* --------------------------- write the ten scalar fields --------------------------- */ itemp[0] = nfront = frontmtx->nfront ; itemp[1] = frontmtx->neqns ; itemp[2] = frontmtx->type ; itemp[3] = frontmtx->symmetryflag ; itemp[4] = frontmtx->pivotingflag ; itemp[5] = frontmtx->sparsityflag ; itemp[6] = frontmtx->dataMode ; itemp[7] = frontmtx->nentD ; itemp[8] = frontmtx->nentL ; itemp[9] = frontmtx->nentU ; rc = fwrite((void *) itemp, sizeof(int), 10, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToBinaryFile(%p,%p)" "\n rc = %d, return from first fprintf\n", frontmtx, fp, rc) ; return(0) ; } /* -------------------------- write out the ETree object -------------------------- */ rc = ETree_writeToBinaryFile(frontmtx->frontETree, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToBinaryFile(%p,%p)" "\n error %d writing frontETree object\n", frontmtx, fp, rc) ; return(0) ; } /* ------------------------------------------- write out the symbolic factorization object ------------------------------------------- */ rc = IVL_writeToBinaryFile(frontmtx->symbfacIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToBinaryFile(%p,%p)" "\n error %d writing symbfacIVL object\n", frontmtx, fp, rc) ; return(0) ; } if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { /* -------------------------------- write out the front sizes object -------------------------------- */ rc = IV_writeToBinaryFile(frontmtx->frontsizesIV, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToBinaryFile(%p,%p)" "\n error %d writing frontsizesIV object\n", frontmtx, fp, rc) ; return(0) ; } } if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { /* ------------------------------------------- write out the rowids and colids IVL objects ------------------------------------------- */ if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { rc = IVL_writeToBinaryFile(frontmtx->rowadjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToBinaryFile(%p,%p)" "\n error %d writing rowadjIVL object\n", frontmtx, fp, rc) ; return(0) ; } } rc = IVL_writeToBinaryFile(frontmtx->coladjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToBinaryFile(%p,%p)" "\n error %d writing coladjIVL object\n", frontmtx, fp, rc) ; return(0) ; } } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* ------------------------------------------------ count the number of L_{J,J} matrices write out the count, then write out the matrices ------------------------------------------------ */ for ( J = nmtx = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_lowerMtx(frontmtx, J, J)) != NULL ) { nmtx++ ; } } rc = fwrite((void *) &nmtx, sizeof(int), 1, fp) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_lowerMtx(frontmtx, J, J)) != NULL ) { SubMtx_writeToBinaryFile(mtx, fp) ; } } /* ------------------------------------------------ count the number of L_{*,J} matrices write out the count, then write out the matrices ------------------------------------------------ */ for ( J = nmtx = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_lowerMtx(frontmtx, nfront, J)) != NULL ){ nmtx++ ; } } rc = fwrite((void *) &nmtx, sizeof(int), 1, fp) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_lowerMtx(frontmtx, nfront, J)) != NULL ){ SubMtx_writeToBinaryFile(mtx, fp) ; } } } /* ------------------------------------------------ count the number of diagonal matrices write out the count, then write out the matrices ------------------------------------------------ */ for ( J = nmtx = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_diagMtx(frontmtx, J)) != NULL ) { nmtx++ ; } } rc = fwrite((void *) &nmtx, sizeof(int), 1, fp) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_diagMtx(frontmtx, J)) != NULL ) { SubMtx_writeToBinaryFile(mtx, fp) ; } } /* ------------------------------------------------ count the number of U_{J,J} matrices write out the count, then write out the matrices ------------------------------------------------ */ for ( J = nmtx = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_upperMtx(frontmtx, J, J)) != NULL ) { nmtx++ ; } } rc = fwrite((void *) &nmtx, sizeof(int), 1, fp) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_upperMtx(frontmtx, J, J)) != NULL ) { SubMtx_writeToBinaryFile(mtx, fp) ; } } /* ------------------------------------------------ count the number of U_{J,*} matrices write out the count, then write out the matrices ------------------------------------------------ */ for ( J = nmtx = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_upperMtx(frontmtx, J, nfront)) != NULL ) { nmtx++ ; } } rc = fwrite((void *) &nmtx, sizeof(int), 1, fp) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = FrontMtx_upperMtx(frontmtx, J, nfront)) != NULL ) { SubMtx_writeToBinaryFile(mtx, fp) ; } } } else { /* --------------------------------------------------------- write out the lower and upper block adjacency IVL objects --------------------------------------------------------- */ if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { rc = IVL_writeToBinaryFile(frontmtx->lowerblockIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToBinaryFile(%p,%p)" "\n error %d writing lowerblockIVL object\n", frontmtx, fp, rc) ; return(0) ; } } rc = IVL_writeToBinaryFile(frontmtx->upperblockIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n fatal error in FrontMtx_writeToBinaryFile(%p,%p)" "\n error %d writing upperblockIVL object\n", frontmtx, fp, rc) ; return(0) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* ------------------------------- write out the lower submatrices ------------------------------- */ for ( J = nmtx = 0 ; J < frontmtx->nfront ; J++ ) { IVL_listAndSize(frontmtx->lowerblockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = adj[ii] ; if ( (mtx = FrontMtx_lowerMtx(frontmtx, K, J)) != NULL ) { nmtx++ ; } } } rc = fwrite((void *) &nmtx, sizeof(int), 1, fp) ; for ( J = 0 ; J < frontmtx->nfront ; J++ ) { IVL_listAndSize(frontmtx->lowerblockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = adj[ii] ; if ( (mtx = FrontMtx_lowerMtx(frontmtx, K, J)) != NULL ) { SubMtx_writeToBinaryFile(mtx, fp) ; } } } } /* ---------------------------------- write out the diagonal submatrices ---------------------------------- */ for ( J = nmtx = 0 ; J < frontmtx->nfront ; J++ ) { if ( (mtx = FrontMtx_diagMtx(frontmtx, J)) != NULL ) { nmtx++ ; } } rc = fwrite((void *) &nmtx, sizeof(int), 1, fp) ; for ( J = 0 ; J < frontmtx->nfront ; J++ ) { if ( (mtx = FrontMtx_diagMtx(frontmtx, J)) != NULL ) { SubMtx_writeToBinaryFile(mtx, fp) ; } } /* ------------------------------- write out the upper submatrices ------------------------------- */ for ( J = nmtx = 0 ; J < frontmtx->nfront ; J++ ) { IVL_listAndSize(frontmtx->upperblockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = adj[ii] ; if ( (mtx = FrontMtx_upperMtx(frontmtx, J, K)) != NULL ) { nmtx++ ; } } } rc = fwrite((void *) &nmtx, sizeof(int), 1, fp) ; for ( J = 0 ; J < frontmtx->nfront ; J++ ) { IVL_listAndSize(frontmtx->upperblockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = adj[ii] ; if ( (mtx = FrontMtx_upperMtx(frontmtx, J, K)) != NULL ) { SubMtx_writeToBinaryFile(mtx, fp) ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to write out the statistics for the FrontMtx object return value -- 1 if success, 0 otherwise created -- 98may04, cca --------------------------------------------------------------- */ int FrontMtx_writeStats ( FrontMtx *frontmtx, FILE *fp ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL || fp == NULL ) { fprintf(stderr, "\n error in FrontMtx_writeStats(%p,%p)" "\n bad input\n", frontmtx, fp) ; exit(-1) ; } fprintf(fp, "\n\n FrontMtx object at address %p" "\n nfront = %d", frontmtx, frontmtx->nfront) ; switch ( frontmtx->symmetryflag ) { case SPOOLES_SYMMETRIC : fprintf(fp, "\n symmetric entries") ; break ; case SPOOLES_HERMITIAN : fprintf(fp, "\n Hermitian") ; break ; case SPOOLES_NONSYMMETRIC : fprintf(fp, "\n nonsymmetric structure, nonsymmetric entries") ; break ; default : break ; } switch ( frontmtx->pivotingflag ) { case SPOOLES_NO_PIVOTING : fprintf(fp, "\n pivoting disabled") ; break ; case SPOOLES_PIVOTING : fprintf(fp, "\n pivoting enabled") ; break ; default : break ; } switch ( frontmtx->sparsityflag ) { case FRONTMTX_DENSE_FRONTS : fprintf(fp, "\n dense fronts") ; break ; case FRONTMTX_SPARSE_FRONTS : fprintf(fp, "\n sparse fronts ") ; break ; default : break ; } switch ( frontmtx->dataMode ) { case FRONTMTX_1D_MODE : fprintf(fp, "\n one-dimensional data decomposition") ; break ; case FRONTMTX_2D_MODE : fprintf(fp, "\n two-dimensional data decomposition") ; break ; default : break ; } fprintf(fp, "\n %d entries in D, %d entries in L, %d entries in U", frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98may04, cca ---------------------------------------- */ int FrontMtx_writeForHumanEye ( FrontMtx *frontmtx, FILE *fp ) { SubMtx *mtx ; int ii, J, K, nadj, nfront ; int *adj ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_writeForHumanEye(%p,%p)" "\n bad input\n", frontmtx, fp) ; exit(-1) ; } nfront = frontmtx->nfront ; FrontMtx_writeStats(frontmtx, fp) ; if ( frontmtx->frontETree != NULL ) { fprintf(fp, "\n\n front tree FrontMtx object") ; ETree_writeForHumanEye(frontmtx->frontETree, fp) ; fflush(fp) ; } if ( frontmtx->symbfacIVL != NULL ) { fprintf(fp, "\n\n symbfacIVL IVL object") ; IVL_writeForHumanEye(frontmtx->symbfacIVL, fp) ; fflush(fp) ; } if ( frontmtx->frontsizesIV != NULL ) { fprintf(fp, "\n\n frontsizesIV IV object") ; IV_writeForHumanEye(frontmtx->frontsizesIV, fp) ; fflush(fp) ; } if ( frontmtx->rowadjIVL != NULL ) { fprintf(fp, "\n\n rowids IVL object") ; IVL_writeForHumanEye(frontmtx->rowadjIVL, fp) ; fflush(fp) ; } if ( frontmtx->coladjIVL != NULL ) { fprintf(fp, "\n\n colids IVL object") ; IVL_writeForHumanEye(frontmtx->coladjIVL, fp) ; fflush(fp) ; } if ( frontmtx->lowerblockIVL != NULL ) { fprintf(fp, "\n\n lower block adjacency IVL object") ; IVL_writeForHumanEye(frontmtx->lowerblockIVL, fp) ; fflush(fp) ; } if ( frontmtx->upperblockIVL != NULL ) { fprintf(fp, "\n\n upper block adjacency IVL object") ; IVL_writeForHumanEye(frontmtx->upperblockIVL, fp) ; fflush(fp) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { fprintf(fp, "\n\n lower submatrices") ; for ( J = 0 ; J < nfront ; J++ ) { mtx = FrontMtx_lowerMtx(frontmtx, J, J) ; if ( mtx != NULL ) { fprintf(fp, "\n\n --- lower submatrix -- diagonal") ; SubMtx_writeForHumanEye(mtx, fp) ; fflush(fp) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { mtx = FrontMtx_lowerMtx(frontmtx, nfront, J) ; if ( mtx != NULL ) { fprintf(fp, "\n\n --- lower submatrix") ; SubMtx_writeForHumanEye(mtx, fp) ; fflush(fp) ; } } else { FrontMtx_lowerAdjFronts(frontmtx, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { if ( (K = adj[ii]) > J && (mtx = FrontMtx_lowerMtx(frontmtx, K, J)) != NULL ) { fprintf(fp, "\n\n --- lower submatrix") ; SubMtx_writeForHumanEye(mtx, fp) ; fflush(fp) ; } } } } } fprintf(fp, "\n\n diagonal submatrices") ; for ( J = 0 ; J < nfront ; J++ ) { mtx = FrontMtx_diagMtx(frontmtx, J) ; if ( mtx != NULL ) { fprintf(fp, "\n\n --- diagonal submatrix") ; SubMtx_writeForHumanEye(mtx, fp) ; } fflush(fp) ; } fprintf(fp, "\n\n upper submatrices") ; for ( J = 0 ; J < nfront ; J++ ) { mtx = FrontMtx_upperMtx(frontmtx, J, J) ; if ( mtx != NULL ) { fprintf(fp, "\n\n --- upper submatrix --- diagonal") ; SubMtx_writeForHumanEye(mtx, fp) ; fflush(fp) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { mtx = FrontMtx_upperMtx(frontmtx, J, nfront) ; if ( mtx != NULL ) { fprintf(fp, "\n\n --- upper submatrix") ; SubMtx_writeForHumanEye(mtx, fp) ; fflush(fp) ; } } else { FrontMtx_upperAdjFronts(frontmtx, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { if ( (K = adj[ii]) > J && (mtx = FrontMtx_upperMtx(frontmtx, J, K)) != NULL ) { fprintf(fp, "\n\n --- upper submatrix") ; SubMtx_writeForHumanEye(mtx, fp) ; fflush(fp) ; } } } } fprintf(fp, "\n\n ### leaving FrontMtx_writeForHumanEye") ; fflush(fp) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- to write the factor matrices out for a matlab file Lname -- name for lower triangular matrix Dname -- name for diagonal matrix Uname -- name for upper triangular matrix presently works only with 1-d data decomposition created -- 98sep23, cca ------------------------------------------------------------- */ int FrontMtx_writeForMatlab ( FrontMtx *frontmtx, char *Lname, char *Dname, char *Uname, FILE *fp ) { int J, nfront ; SubMtx *mtx ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || Lname == NULL || Dname == NULL || Uname == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_writeForMatlab()" "\n bad input\n") ; exit(-1) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { nfront = FrontMtx_nfront(frontmtx) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { fprintf(fp, "\n\n %% lower submatrices") ; for ( J = 0 ; J < nfront ; J++ ) { mtx = FrontMtx_lowerMtx(frontmtx, J, J) ; if ( mtx != NULL ) { fprintf(fp, "\n\n %% --- lower submatrix -- diagonal") ; SubMtx_writeForMatlab(mtx, Lname, fp) ; fflush(fp) ; } mtx = FrontMtx_lowerMtx(frontmtx, nfront, J) ; if ( mtx != NULL ) { fprintf(fp, "\n\n %% --- lower submatrix") ; SubMtx_writeForMatlab(mtx, Lname, fp) ; fflush(fp) ; } } } fprintf(fp, "\n\n %% diagonal submatrices") ; for ( J = 0 ; J < nfront ; J++ ) { mtx = FrontMtx_diagMtx(frontmtx, J) ; if ( mtx != NULL ) { fprintf(fp, "\n\n %% --- diagonal submatrix") ; SubMtx_writeForMatlab(mtx, Dname, fp) ; } fflush(fp) ; } fprintf(fp, "\n\n %% upper submatrices") ; for ( J = 0 ; J < nfront ; J++ ) { mtx = FrontMtx_upperMtx(frontmtx, J, J) ; if ( mtx != NULL ) { fprintf(fp, "\n\n %% --- upper submatrix --- diagonal") ; SubMtx_writeForMatlab(mtx, Uname, fp) ; fflush(fp) ; } mtx = FrontMtx_upperMtx(frontmtx, J, nfront) ; if ( mtx != NULL ) { fprintf(fp, "\n\n %% --- upper submatrix") ; SubMtx_writeForMatlab(mtx, Uname, fp) ; fflush(fp) ; } } } else if ( FRONTMTX_IS_2D_MODE(frontmtx) ) { nfront = FrontMtx_nfront(frontmtx) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { int ii, jj, kk, K, nadj, ncolJ, ncolKJ, nrowK, nrowKJ ; int *adj, *colindJ, *colKJ, *rowindK, *rowKJ ; fprintf(fp, "\n\n %% lower submatrices") ; for ( J = 0 ; J < nfront ; J++ ) { mtx = FrontMtx_lowerMtx(frontmtx, J, J) ; if ( mtx != NULL ) { fprintf(fp, "\n\n %% --- lower submatrix -- diagonal") ; SubMtx_writeForMatlab(mtx, Lname, fp) ; fflush(fp) ; } FrontMtx_lowerAdjFronts(frontmtx, J, &nadj, &adj) ; for ( kk = 0 ; kk < nadj ; kk++ ) { if ( (K = adj[kk]) > J && (mtx = FrontMtx_lowerMtx(frontmtx, K, J)) != NULL ) { fprintf(fp, "\n\n %% --- lower submatrix") ; SubMtx_columnIndices(mtx, &ncolKJ, &colKJ) ; FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; for ( ii = 0 ; ii < ncolKJ ; ii++ ) { colKJ[ii] = colindJ[colKJ[ii]] ; } SubMtx_rowIndices(mtx, &nrowKJ, &rowKJ) ; FrontMtx_rowIndices(frontmtx, K, &nrowK, &rowindK) ; for ( ii = 0 ; ii < nrowKJ ; ii++ ) { rowKJ[ii] = rowindK[rowKJ[ii]] ; } SubMtx_writeForMatlab(mtx, Lname, fp) ; for ( ii = jj = 0 ; ii < ncolKJ ; ii++ ) { while ( colKJ[ii] != colindJ[jj] ) { jj++ ; } colKJ[ii] = jj++ ; } for ( ii = jj = 0 ; ii < nrowKJ ; ii++ ) { while ( rowKJ[ii] != rowindK[jj] ) { jj++ ; } rowKJ[ii] = jj++ ; } fflush(fp) ; } } } } fprintf(fp, "\n\n %% diagonal submatrices") ; for ( J = 0 ; J < nfront ; J++ ) { mtx = FrontMtx_diagMtx(frontmtx, J) ; if ( mtx != NULL ) { fprintf(fp, "\n\n %% --- diagonal submatrix") ; SubMtx_writeForMatlab(mtx, Dname, fp) ; } fflush(fp) ; } fprintf(fp, "\n\n %% upper submatrices") ; for ( J = 0 ; J < nfront ; J++ ) { int ii, jj, kk, K, nadj, ncolK, ncolJK, nrowJ, nrowJK ; int *adj, *colindK, *colJK, *rowindJ, *rowJK ; mtx = FrontMtx_upperMtx(frontmtx, J, J) ; if ( mtx != NULL ) { fprintf(fp, "\n\n %% --- upper submatrix --- diagonal") ; SubMtx_writeForMatlab(mtx, Uname, fp) ; fflush(fp) ; } FrontMtx_upperAdjFronts(frontmtx, J, &nadj, &adj) ; for ( kk = 0 ; kk < nadj ; kk++ ) { if ( (K = adj[kk]) > J && (mtx = FrontMtx_upperMtx(frontmtx, J, K)) != NULL ) { fprintf(fp, "\n\n %% --- upper submatrix") ; SubMtx_columnIndices(mtx, &ncolJK, &colJK) ; FrontMtx_columnIndices(frontmtx, K, &ncolK, &colindK) ; for ( ii = 0 ; ii < ncolJK ; ii++ ) { colJK[ii] = colindK[colJK[ii]] ; } SubMtx_rowIndices(mtx, &nrowJK, &rowJK) ; FrontMtx_rowIndices(frontmtx, J, &nrowJ, &rowindJ) ; for ( ii = 0 ; ii < nrowJK ; ii++ ) { rowJK[ii] = rowindJ[rowJK[ii]] ; } SubMtx_writeForMatlab(mtx, Uname, fp) ; for ( ii = jj = 0 ; ii < ncolJK ; ii++ ) { while ( colJK[ii] != colindK[jj] ) { jj++ ; } colJK[ii] = jj++ ; } for ( ii = jj = 0 ; ii < nrowJK ; ii++ ) { while ( rowJK[ii] != rowindJ[jj] ) { jj++ ; } rowJK[ii] = jj++ ; } fflush(fp) ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ ------------------------------------ */ int FrontMtx_writeForHumanEye ( FrontMtx *frontmtx, FILE *fp ) { SubMtx *mtx ; int ii, J, K, nadj, nfront ; int *adj ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_writeForHumanEye(%p,%p)" FrontMtx/src/QRfactor.c010064400020550007177000000057770657126717300163640ustar00clevecompmath00000400000006/* QRfactor.c */ #include "../FrontMtx.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to compute the (U+I)D(I+U) factorization of A^TA, where A = QR, R = (D^{1/2} + D^{1/2}U) cpus[0] -- setup time cpus[1] -- initialize and load staircase matrix cpus[2] -- factor the matrix cpus[3] -- scale and store factor entries cpus[4] -- store update entries cpus[5] -- miscellaneous time cpus[6] -- total time created -- 98may28, cca ------------------------------------------------------------ */ void FrontMtx_QR_factor ( FrontMtx *frontmtx, InpMtx *mtxA, ChvManager *chvmanager, double cpus[], double *pfacops, int msglvl, FILE *msgFile ) { char *status ; ChvList *updlist ; double t0, t1, t2, t3 ; DV workDV ; int J, neqns, nfront ; int *colmap, *firstnz ; IVL *rowsIVL ; Tree *tree ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( frontmtx == NULL || mtxA == NULL || chvmanager == NULL || cpus == NULL || pfacops == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_QR_factor()" "\n bad input\n") ; exit(-1) ; } neqns = frontmtx->neqns ; nfront = frontmtx->nfront ; tree = frontmtx->tree ; /* ---------------------------------------------------------------- create the update list object create the rowsIVL object, where list(J) = list of rows that are assembled in front J firstnz[irowA] = first column with nonzero element in A(irowA,*) colmap[neqns] = work vector for mapping status[neqns] = status vector for fronts ---------------------------------------------------------------- */ MARKTIME(t1) ; updlist = ChvList_new() ; ChvList_init(updlist, nfront+1, NULL, NO_LOCK, NULL) ; FrontMtx_QR_setup(frontmtx, mtxA, &rowsIVL, &firstnz, msglvl, msgFile) ; colmap = IVinit(neqns, -1) ; status = CVinit(nfront, 'W') ; DV_setDefaultFields(&workDV) ; MARKTIME(t2) ; cpus[0] += t2 - t1 ; /* -------------------------------------------- loop over the tree in a post-order traversal -------------------------------------------- */ for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { FrontMtx_QR_factorVisit(frontmtx, J, mtxA, rowsIVL, firstnz, updlist, chvmanager, status, colmap, &workDV, cpus, pfacops, msglvl, msgFile) ; } /* ------------------------ free the working storage ------------------------ */ CVfree(status) ; DV_clearData(&workDV) ; ChvList_free(updlist) ; IVL_free(rowsIVL) ; IVfree(colmap) ; IVfree(firstnz) ; MARKTIME(t3) ; cpus[6] = t3 - t0 ; cpus[5] = t3 - t0 - cpus[0] - cpus[1] - cpus[2] - cpus[3] - cpus[4] - cpus[5] ; return ; } /*--------------------------------------------------------------------*/ FrontMtx/src/QRsolve.c010064400020550007177000000052040657126717300162170ustar00clevecompmath00000400000006/* QRsolve.c */ #include "../FrontMtx.h" #include "../../timings.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- minimize ||b - Ax||_2 by solving (U^T + I) * D * (I + U) X = A^T * B where A = QR = QD(I + U) by calling FrontMtx_solve() note: if A is square, mtxX and mtxB must not be the same mtxmanager -- object that manages working storage cpus -- vector of cpu time breakdowns cpus[0] -- set up solves cpus[1] -- fetch rhs and store solution cpus[2] -- forward solve cpus[3] -- diagonal solve cpus[4] -- backward solve cpus[5] -- total solve time cpus[6] -- time to compute A^T * B cpus[7] -- total time created -- 97may27, dkw modified -- 98may28, cca -------------------------------------------------------- */ void FrontMtx_QR_solve ( FrontMtx *frontmtx, InpMtx *mtxA, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, double cpus[], int msglvl, FILE *msgFile ) { double t0, t1, t2 ; double alpha[2] ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( frontmtx == NULL || mtxA == NULL || mtxX == NULL || mtxB == NULL || cpus == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_QR_solve(%p,%p,%p,%p,%p,%d,%p)" "\n bad input\n", frontmtx, mtxA, mtxX, mtxB, cpus, msglvl, msgFile) ; exit(-1) ; } /* -------------------- compute X := A^T * B -------------------- */ MARKTIME(t1) ; DenseMtx_zero(mtxX) ; alpha[0] = 1.0 ; alpha[1] = 0.0 ; if ( FRONTMTX_IS_REAL(frontmtx) ) { InpMtx_nonsym_mmm_T(mtxA, mtxX, alpha, mtxB) ; } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { InpMtx_nonsym_mmm_H(mtxA, mtxX, alpha, mtxB) ; } MARKTIME(t2) ; cpus[6] = t2 - t1 ; if ( msglvl > 3 ) { fprintf(msgFile, "\n B") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fprintf(msgFile, "\n A^T * B") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /* ----------------------------------- solve (U^T + I) * D * (I + U) Z = X where Z overwrites X ----------------------------------- */ MARKTIME(t1) ; FrontMtx_solve(frontmtx, mtxX, mtxX, mtxmanager, cpus, msglvl, msgFile) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n computed mtxX") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } MARKTIME(t2) ; cpus[7] = t2 - t0 ; return ; } /*--------------------------------------------------------------------*/ FrontMtx/src/QRutil.c010064400020550007177000000463640657126717300160600ustar00clevecompmath00000400000006/* QRutil.c */ #include "../FrontMtx.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- to setup two data structures for a QR serial or multithreaded factorization rowsIVL[J] -- list of rows of A to be assembled into front J firstnz[irow] -- column with location of leading nonzero of row in A created -- 98may29, cca -------------------------------------------------------------------- */ void FrontMtx_QR_setup ( FrontMtx *frontmtx, InpMtx *mtxA, IVL **prowsIVL, int **pfirstnz, int msglvl, FILE *msgFile ) { int count, irow, jcol, J, loc, neqns, nfront, nrowA, rowsize ; int *firstnz, *head, *link, *list, *rowind, *vtxToFront ; IVL *rowsIVL ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || mtxA == NULL || prowsIVL == NULL || pfirstnz == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_QR_setup()" "\n bad input\n") ; exit(-1) ; } neqns = FrontMtx_neqns(frontmtx) ; nfront = FrontMtx_nfront(frontmtx) ; vtxToFront = ETree_vtxToFront(frontmtx->frontETree) ; /* ---------------------------------------------------------------- create the rowsIVL object, list(J) = list of rows that are assembled in front J firstnz[irowA] = first column with nonzero element in A(irowA,*) ---------------------------------------------------------------- */ InpMtx_changeCoordType(mtxA, INPMTX_BY_ROWS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; nrowA = 1 + IVmax(InpMtx_nent(mtxA), InpMtx_ivec1(mtxA), &loc) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n nrowA = %d ", nrowA) ; fflush(msgFile) ; } firstnz = IVinit(nrowA, -1) ; head = IVinit(nfront, -1) ; link = IVinit(nrowA, -1) ; for ( irow = nrowA - 1 ; irow >= 0 ; irow-- ) { InpMtx_vector(mtxA, irow, &rowsize, &rowind) ; if ( rowsize > 0 ) { firstnz[irow] = jcol = rowind[0] ; J = vtxToFront[jcol] ; link[irow] = head[J] ; head[J] = irow ; } } rowsIVL = IVL_new() ; IVL_init2(rowsIVL, IVL_CHUNKED, nfront, nrowA) ; list = IVinit(neqns, -1) ; for ( J = 0 ; J < nfront ; J++ ) { count = 0 ; for ( irow = head[J] ; irow != -1 ; irow = link[irow] ) { list[count++] = irow ; } if ( count > 0 ) { IVL_setList(rowsIVL, J, count, list) ; } } IVfree(head) ; IVfree(link) ; IVfree(list) ; /* --------------------------- set the pointers for return --------------------------- */ *prowsIVL = rowsIVL ; *pfirstnz = firstnz ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- visit front J during a serial or multithreaded QR factorization cpus[1] -- initialize and load staircase matrix cpus[2] -- factor the matrix cpus[3] -- scale and store factor entries cpus[4] -- store update entries created -- 98may28, cca ----------------------------------------------- */ void FrontMtx_QR_factorVisit ( FrontMtx *frontmtx, int J, InpMtx *mtxA, IVL *rowsIVL, int firstnz[], ChvList *updlist, ChvManager *chvmanager, char status[], int colmap[], DV *workDV, double cpus[], double *pfacops, int msglvl, FILE *msgFile ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL || mtxA == NULL || rowsIVL == NULL || firstnz == NULL || updlist == NULL || chvmanager == NULL || status == NULL || colmap == NULL || workDV == NULL || cpus == NULL || pfacops == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(msgFile, "\n fatal error in FrontMtx_QR_factorVisit(%d)" "\n bad input\n", J) ; exit(-1) ; } /* ------------------------------------------------------------ check to see if all incoming updates are present in the list ------------------------------------------------------------ */ if ( ChvList_isCountZero(updlist, J) == 1 ) { A2 *frontJ ; Chv *firstchild, *updchv ; double ops, t1, t2 ; int K ; /* ---------------------------------------- everything is ready to factor this front ---------------------------------------- */ firstchild = ChvList_getList(updlist, J) ; /* ---------------------------------------- initialize and load the staircase matrix ---------------------------------------- */ MARKTIME(t1) ; frontJ = FrontMtx_QR_assembleFront(frontmtx, J, mtxA, rowsIVL, firstnz, colmap, firstchild, workDV, msglvl, msgFile) ; if ( firstchild != NULL ) { ChvManager_releaseListOfObjects(chvmanager, firstchild) ; } MARKTIME(t2) ; cpus[1] += t2 - t1 ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n after assembling front") ; A2_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } /* --------------------------- factor the staircase matrix --------------------------- */ MARKTIME(t1) ; ops = A2_QRreduce(frontJ, workDV, msglvl, msgFile) ; *pfacops += ops ; MARKTIME(t2) ; cpus[2] += t2 - t1 ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n after factoring") ; A2_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- scale and store the factor entries ---------------------------------- */ MARKTIME(t1) ; FrontMtx_QR_storeFront(frontmtx, J, frontJ, msglvl, msgFile) ; MARKTIME(t2) ; cpus[3] += t2 - t1 ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n after storing factor entries") ; A2_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } /* ----------------------- store the update matrix ----------------------- */ if ( (K = frontmtx->tree->par[J]) != -1 ) { MARKTIME(t1) ; updchv = FrontMtx_QR_storeUpdate(frontmtx, J, frontJ, chvmanager, msglvl, msgFile) ; ChvList_addObjectToList(updlist, updchv, K) ; MARKTIME(t2) ; cpus[4] += t2 - t1 ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n after storing update entries") ; A2_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } } /* ------------------------- free the staircase matrix ------------------------- */ A2_free(frontJ) ; /* ------------------------------------- set the status as finished and return ------------------------------------- */ status[J] = 'F' ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- create and return an A2 object that contains rows of A and rows from update matrices of the children. the matrix may not be in staircase form created -- 98may25, cca -------------------------------------------------------------- */ A2 * FrontMtx_QR_assembleFront ( FrontMtx *frontmtx, int J, InpMtx *mtxA, IVL *rowsIVL, int firstnz[], int colmap[], Chv *firstchild, DV *workDV, int msglvl, FILE *msgFile ) { A2 *frontJ ; Chv *chvI ; double *rowI, *rowJ, *rowentA ; int ii, irow, irowA, irowI, jcol, jj, jrow, ncolI, ncolJ, nentA, nrowI, nrowJ, nrowFromA ; int *colindA, *colindI, *colindJ, *map, *rowids, *rowsFromA ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || mtxA == NULL || rowsIVL == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_QR_assembleFront()" "\n bad input\n") ; exit(-1) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n inside FrontMtx_QR_assembleFront(%d)", J) ; fflush(msgFile) ; } /* -------------------------------------------------- set up the map from global to local column indices -------------------------------------------------- */ FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; for ( jcol = 0 ; jcol < ncolJ ; jcol++ ) { colmap[colindJ[jcol]] = jcol ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n front %d's column indices", J) ; IVfprintf(msgFile, ncolJ, colindJ) ; fflush(msgFile) ; } /* ------------------------------------------------- compute the size of the front and map the global indices of the update matrices into local indices ------------------------------------------------- */ IVL_listAndSize(rowsIVL, J, &nrowFromA, &rowsFromA) ; nrowJ = nrowFromA ; if ( msglvl > 3 ) { fprintf(msgFile, "\n %d rows from A", nrowFromA) ; fflush(msgFile) ; } for ( chvI = firstchild ; chvI != NULL ; chvI = chvI->next ) { nrowJ += chvI->nD ; Chv_columnIndices(chvI, &ncolI, &colindI) ; for ( jcol = 0 ; jcol < ncolI ; jcol++ ) { colindI[jcol] = colmap[colindI[jcol]] ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n %d rows from child %d", chvI->nD, chvI->id) ; fflush(msgFile) ; } } /* ---------------------------------------------------------- get workspace for the rowids[nrowJ] and map[nrowJ] vectors ---------------------------------------------------------- */ if ( sizeof(int) == sizeof(double) ) { DV_setSize(workDV, 2*nrowJ) ; } else if ( 2*sizeof(int) == sizeof(double) ) { DV_setSize(workDV, nrowJ) ; } rowids = (int *) DV_entries(workDV) ; map = rowids + nrowJ ; IVramp(nrowJ, rowids, 0, 1) ; IVfill(nrowJ, map, -1) ; /* ----------------------------------------------------------------- get the map from incoming rows to their place in the front matrix ----------------------------------------------------------------- */ for ( irow = jrow = 0 ; irow < nrowFromA ; irow++, jrow++ ) { irowA = rowsFromA[irow] ; map[jrow] = colmap[firstnz[irowA]] ; } for ( chvI = firstchild ; chvI != NULL ; chvI = chvI->next ) { nrowI = chvI->nD ; Chv_columnIndices(chvI, &ncolI, &colindI) ; for ( irow = 0 ; irow < nrowI ; irow++, jrow++ ) { map[jrow] = colindI[irow] ; } } IV2qsortUp(nrowJ, map, rowids) ; for ( irow = 0 ; irow < nrowJ ; irow++ ) { map[rowids[irow]] = irow ; } /* ---------------------------- allocate the A2 front object ---------------------------- */ frontJ = A2_new() ; A2_init(frontJ, frontmtx->type, nrowJ, ncolJ, ncolJ, 1, NULL) ; A2_zero(frontJ) ; /* ------------------------------------ load the original rows of the matrix ------------------------------------ */ for ( jrow = 0 ; jrow < nrowFromA ; jrow++ ) { irowA = rowsFromA[jrow] ; rowJ = A2_row(frontJ, map[jrow]) ; if ( A2_IS_REAL(frontJ) ) { InpMtx_realVector(mtxA, irowA, &nentA, &colindA, &rowentA) ; } else if ( A2_IS_COMPLEX(frontJ) ) { InpMtx_complexVector(mtxA, irowA, &nentA, &colindA, &rowentA) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n loading row %d", irowA) ; fprintf(msgFile, "\n global indices") ; IVfprintf(msgFile, nentA, colindA) ; fflush(msgFile) ; } if ( A2_IS_REAL(frontJ) ) { for ( ii = 0 ; ii < nentA ; ii++ ) { jj = colmap[colindA[ii]] ; rowJ[jj] = rowentA[ii] ; } } else if ( A2_IS_COMPLEX(frontJ) ) { for ( ii = 0 ; ii < nentA ; ii++ ) { jj = colmap[colindA[ii]] ; rowJ[2*jj] = rowentA[2*ii] ; rowJ[2*jj+1] = rowentA[2*ii+1] ; } } } if ( msglvl > 3 ) { fprintf(msgFile, "\n after assembling rows of A") ; A2_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- load the updates from the children ---------------------------------- */ for ( chvI = firstchild ; chvI != NULL ; chvI = chvI->next ) { nrowI = chvI->nD ; Chv_columnIndices(chvI, &ncolI, &colindI) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n loading child %d", chvI->id) ; fprintf(msgFile, "\n child's column indices") ; IVfprintf(msgFile, ncolI, colindI) ; Chv_writeForHumanEye(chvI, msgFile) ; fflush(msgFile) ; } rowI = Chv_entries(chvI) ; for ( irowI = 0 ; irowI < nrowI ; irowI++, jrow++ ) { rowJ = A2_row(frontJ, map[jrow]) ; if ( A2_IS_REAL(frontJ) ) { for ( ii = irowI ; ii < ncolI ; ii++ ) { jj = colindI[ii] ; rowJ[jj] = rowI[ii] ; } rowI += ncolI - irowI - 1 ; } else if ( A2_IS_COMPLEX(frontJ) ) { for ( ii = irowI ; ii < ncolI ; ii++ ) { jj = colindI[ii] ; rowJ[2*jj] = rowI[2*ii] ; rowJ[2*jj+1] = rowI[2*ii+1] ; } rowI += 2*(ncolI - irowI - 1) ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n after assembling child %d", chvI->id) ; A2_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } } return(frontJ) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- store the factor entries of the reduced front matrix created -- 98may25, cca ---------------------------------------------------- */ void FrontMtx_QR_storeFront ( FrontMtx *frontmtx, int J, A2 *frontJ, int msglvl, FILE *msgFile ) { A2 tempA2 ; double fac, ifac, imag, real, rfac ; double *entDJJ, *entUJJ, *entUJN, *row ; int inc1, inc2, irow, jcol, ncol, ncolJ, nD, nentD, nentUJJ, nfront, nrow, nU ; int *colind, *colindJ, *firstlocs, *sizes ; SubMtx *mtx ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || frontJ == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_QR_storeFront()" "\n bad input\n") ; exit(-1) ; } nfront = FrontMtx_nfront(frontmtx) ; FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; nrow = A2_nrow(frontJ) ; ncol = A2_ncol(frontJ) ; A2_setDefaultFields(&tempA2) ; nD = FrontMtx_frontSize(frontmtx, J) ; nU = ncol - nD ; /* -------------------------------------- scale the rows and square the diagonal -------------------------------------- */ row = A2_entries(frontJ) ; if ( A2_IS_REAL(frontJ) ) { for ( irow = 0 ; irow < nD ; irow++ ) { if ( row[irow] != 0.0 ) { fac = 1./row[irow] ; for ( jcol = irow + 1 ; jcol < ncol ; jcol++ ) { row[jcol] *= fac ; } row[irow] = row[irow] * row[irow] ; } row += ncol ; } } else if ( A2_IS_COMPLEX(frontJ) ) { for ( irow = 0 ; irow < nD ; irow++ ) { real = row[2*irow] ; imag = row[2*irow+1] ; if ( real != 0.0 || imag != 0.0 ) { Zrecip(real, imag, &rfac, &ifac) ; ZVscale(ncol - irow - 1, & row[2*irow+2], rfac, ifac) ; row[2*irow] = real*real + imag*imag ; row[2*irow+1] = 0.0 ; } row += 2*ncol ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n after scaling rows of A") ; A2_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } /* ------------------------- copy the diagonal entries ------------------------- */ mtx = FrontMtx_diagMtx(frontmtx, J) ; SubMtx_diagonalInfo(mtx, &nentD, &entDJJ) ; A2_subA2(&tempA2, frontJ, 0, nD-1, 0, nD-1) ; A2_copyEntriesToVector(&tempA2, nentD, entDJJ, A2_DIAGONAL, A2_BY_ROWS) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(nD, colind, colindJ) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n diagonal factor matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } if ( (mtx = FrontMtx_upperMtx(frontmtx, J, J)) != NULL ) { /* ------------------------ copy the U_{J,J} entries ------------------------ */ SubMtx_denseSubcolumnsInfo(mtx, &nD, &nentUJJ, &firstlocs, &sizes, &entUJJ) ; A2_copyEntriesToVector(&tempA2, nentUJJ, entUJJ, A2_STRICT_UPPER, A2_BY_COLUMNS) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(nD, colind, colindJ) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n UJJ factor matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } } if ( ncolJ > nD ) { /* ----------------------------- copy the U_{J,bnd{J}} entries ----------------------------- */ mtx = FrontMtx_upperMtx(frontmtx, J, nfront) ; SubMtx_denseInfo(mtx, &nD, &nU, &inc1, &inc2, &entUJN) ; A2_subA2(&tempA2, frontJ, 0, nD-1, nD, ncolJ-1) ; A2_copyEntriesToVector(&tempA2, nD*nU, entUJN, A2_ALL_ENTRIES, A2_BY_COLUMNS) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(nU, colind, colindJ + nD) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n UJN factor matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to create and return a Chv object that holds the update matrix for front J created -- 98may25, cca ------------------------------------------------- */ Chv * FrontMtx_QR_storeUpdate ( FrontMtx *frontmtx, int J, A2 *frontJ, ChvManager *chvmanager, int msglvl, FILE *msgFile ) { A2 tempJ ; Chv *chvJ ; double *updent ; int nbytes, ncolJ, ncolupd, nD, nent, nrowJ, nrowupd ; int *colindJ, *updind ; /* ----------------------------------------------- compute the number of rows in the update matrix ----------------------------------------------- */ nD = FrontMtx_frontSize(frontmtx, J) ; FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; nrowJ = A2_nrow(frontJ) ; nrowupd = ((nrowJ >= ncolJ) ? ncolJ : nrowJ) - nD ; ncolupd = ncolJ - nD ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n inside FrontMtx_QR_storeUpdate(%d)", J) ; fprintf(msgFile, "\n nD %d, nrowJ %d, nrowupd %d, ncolupd %d", nD, nrowJ, nrowupd, ncolupd) ; fflush(msgFile) ; } if ( nrowupd > 0 && ncolupd > 0 ) { if ( FRONTMTX_IS_REAL(frontmtx) ) { nbytes = Chv_nbytesNeeded(nrowupd, 0, ncolupd - nrowupd, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { nbytes = Chv_nbytesNeeded(nrowupd, 0, ncolupd - nrowupd, SPOOLES_COMPLEX, SPOOLES_HERMITIAN) ; } chvJ = ChvManager_newObjectOfSizeNbytes(chvmanager, nbytes) ; if ( FRONTMTX_IS_REAL(frontmtx) ) { Chv_init(chvJ, J, nrowupd, 0, ncolupd - nrowupd, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { Chv_init(chvJ, J, nrowupd, 0, ncolupd - nrowupd, SPOOLES_COMPLEX, SPOOLES_HERMITIAN) ; } Chv_columnIndices(chvJ, &ncolupd, &updind) ; IVcopy(ncolupd, updind, colindJ + nD) ; nent = Chv_nent(chvJ) ; updent = Chv_entries(chvJ) ; A2_setDefaultFields(&tempJ) ; A2_subA2(&tempJ, frontJ, nD, nrowJ - 1, nD, ncolJ - 1) ; A2_copyEntriesToVector(&tempJ, nent, updent, A2_UPPER, A2_BY_ROWS) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n update matrix %d", J) ; Chv_writeForHumanEye(chvJ, msgFile) ; fflush(msgFile) ; } } else { chvJ = NULL ; } return(chvJ) ; } /*--------------------------------------------------------------------*/ e for the rowids[nrowJ] and map[nrowJ] vectors ---------------------------------------------------------- */ if ( sizeof(int) == sizeof(double) ) { DV_setSize(workDV, 2*nrowJ) ; } else if ( 2*sizeof(int) == sizeof(double) ) { DV_setSize(workDV, nrowJ) ; } rowFrontMtx/src/basics.c010064400020550007177000000136000657126717200160660ustar00clevecompmath00000400000006/* basics.c */ #include "../FrontMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98may04, cca ----------------------- */ FrontMtx * FrontMtx_new ( void ) { FrontMtx *frontmtx ; ALLOCATE(frontmtx, struct _FrontMtx, 1) ; FrontMtx_setDefaultFields(frontmtx) ; return(frontmtx) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98may04, cca ----------------------- */ void FrontMtx_setDefaultFields ( FrontMtx *frontmtx ) { if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_setDefaultFields(%p)" "\n bad input", frontmtx) ; exit(-1) ; } frontmtx->nfront = 0 ; frontmtx->neqns = 0 ; frontmtx->type = SPOOLES_REAL ; frontmtx->symmetryflag = SPOOLES_SYMMETRIC ; frontmtx->sparsityflag = FRONTMTX_DENSE_FRONTS ; frontmtx->pivotingflag = SPOOLES_NO_PIVOTING ; frontmtx->dataMode = FRONTMTX_1D_MODE ; frontmtx->nentD = 0 ; frontmtx->nentL = 0 ; frontmtx->nentU = 0 ; frontmtx->tree = NULL ; frontmtx->frontETree = NULL ; frontmtx->frontsizesIV = NULL ; frontmtx->symbfacIVL = NULL ; frontmtx->rowadjIVL = NULL ; frontmtx->coladjIVL = NULL ; frontmtx->lowerblockIVL = NULL ; frontmtx->upperblockIVL = NULL ; frontmtx->p_mtxDJJ = NULL ; frontmtx->p_mtxUJJ = NULL ; frontmtx->p_mtxUJN = NULL ; frontmtx->p_mtxLJJ = NULL ; frontmtx->p_mtxLNJ = NULL ; frontmtx->lowerhash = NULL ; frontmtx->upperhash = NULL ; frontmtx->lock = NULL ; frontmtx->nlocks = 0 ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may04, cca -------------------------------------------------- */ void FrontMtx_clearData ( FrontMtx *frontmtx ) { SubMtx *mtx ; int ii, J, K, nadj, nfront ; int *adj ; /* --------------- check the input --------------- */ if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_clearData(%p)" "\n bad input\n", frontmtx) ; exit(-1) ; } nfront = frontmtx->nfront ; /* ---------------------- free the owned storage ---------------------- */ if ( frontmtx->frontsizesIV != NULL ) { IV_free(frontmtx->frontsizesIV) ; } if ( frontmtx->rowadjIVL != NULL ) { IVL_free(frontmtx->rowadjIVL) ; } if ( frontmtx->coladjIVL != NULL ) { IVL_free(frontmtx->coladjIVL) ; } if ( frontmtx->p_mtxDJJ != NULL ) { for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = frontmtx->p_mtxDJJ[J]) != NULL ) { SubMtx_free(mtx) ; } } FREE(frontmtx->p_mtxDJJ) ; } if ( frontmtx->tree != NULL ) { if ( frontmtx->frontETree == NULL || frontmtx->frontETree->tree != frontmtx->tree ) { Tree_free(frontmtx->tree) ; } frontmtx->tree = NULL ; } if ( frontmtx->dataMode == FRONTMTX_1D_MODE ) { if ( frontmtx->p_mtxUJJ != NULL ) { for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = frontmtx->p_mtxUJJ[J]) != NULL ) { SubMtx_free(mtx) ; } } FREE(frontmtx->p_mtxUJJ) ; } if ( frontmtx->p_mtxUJN != NULL ) { for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = frontmtx->p_mtxUJN[J]) != NULL ) { SubMtx_free(mtx) ; } } FREE(frontmtx->p_mtxUJN) ; } if ( frontmtx->p_mtxLJJ != NULL ) { for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = frontmtx->p_mtxLJJ[J]) != NULL ) { SubMtx_free(mtx) ; } } FREE(frontmtx->p_mtxLJJ) ; } if ( frontmtx->p_mtxLNJ != NULL ) { for ( J = 0 ; J < nfront ; J++ ) { if ( (mtx = frontmtx->p_mtxLNJ[J]) != NULL ) { SubMtx_free(mtx) ; } } FREE(frontmtx->p_mtxLNJ) ; } } else if ( frontmtx->dataMode == FRONTMTX_2D_MODE ) { for ( J = 0 ; J < nfront ; J++ ) { FrontMtx_upperAdjFronts(frontmtx, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = adj[ii] ; if ( (mtx = FrontMtx_upperMtx(frontmtx, J, K)) != NULL ) { SubMtx_free(mtx) ; } } } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { for ( J = 0 ; J < nfront ; J++ ) { FrontMtx_lowerAdjFronts(frontmtx, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = adj[ii] ; if ( (mtx = FrontMtx_lowerMtx(frontmtx, K, J)) != NULL ) { SubMtx_free(mtx) ; } } } } if ( frontmtx->lowerblockIVL != NULL ) { IVL_free(frontmtx->lowerblockIVL) ; } if ( frontmtx->upperblockIVL != NULL ) { IVL_free(frontmtx->upperblockIVL) ; } if ( frontmtx->lowerhash != NULL ) { I2Ohash_free(frontmtx->lowerhash) ; } if ( frontmtx->upperhash != NULL ) { I2Ohash_free(frontmtx->upperhash) ; } } if ( frontmtx->lock != NULL ) { /* ------------------------- destroy and free the lock ------------------------- */ Lock_free(frontmtx->lock) ; } /* ---------------------- set the default fields ---------------------- */ FrontMtx_setDefaultFields(frontmtx) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98may04, cca ------------------------------------------ */ void FrontMtx_free ( FrontMtx *frontmtx ) { if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_free(%p)" "\n bad input\n", frontmtx) ; exit(-1) ; } FrontMtx_clearData(frontmtx) ; FREE(frontmtx) ; return ; } /*--------------------------------------------------------------------*/ FrontMtx/src/factor.c010064400020550007177000000203000665021723200160610ustar00clevecompmath00000400000006/* factor.c */ #include "../FrontMtx.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- compute an (U^T + I)D(I + U) or (L + I)D(I + L) factorization of A. this is a wrapper method around FrontMtx_factorPencil(). input -- frontmtx -- pointer to the FrontMtx object that will hold the factorization pencil -- pointer to the Pencil object that holds A + sigma*B tau -- upper bound on entries in L and U, used only when pivoting enabled droptol -- lower bound on entries in L and U, used only when sparsity enabled perror -- error flag, on return *perror >= 0 --> factorization failed at front *perror *perror < 0 --> factorization succeeded cpus[] -- timing array cpus[0] -- initialize fronts cpus[1] -- load original entries cpus[2] -- get updates from descendents cpus[3] -- assembled postponed data cpus[4] -- factor the front cpus[5] -- extract postponed data cpus[6] -- store factor entries cpus[7] -- miscellaneous time cpus[8] -- total time stats[] -- statistics array stats[0] -- # of pivots stats[1] -- # of pivot tests stats[2] -- # of delayed rows and columns stats[3] -- # of entries in D stats[4] -- # of entries in L stats[5] -- # of entries in U msglvl -- message level msgFile -- message file created -- 98mar27, cca modified -- 98mar27, cca perror added to argument list ------------------------------------------------------------------- */ Chv * FrontMtx_factorInpMtx ( FrontMtx *frontmtx, InpMtx *inpmtx, double tau, double droptol, ChvManager *chvmanager, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile ) { double zero[2] = {0.0, 0.0} ; Chv *rootchv ; Pencil pencil ; Pencil_setDefaultFields(&pencil) ; Pencil_init(&pencil, frontmtx->type, frontmtx->symmetryflag, inpmtx, zero, NULL) ; rootchv = FrontMtx_factorPencil(frontmtx, &pencil, tau, droptol, chvmanager, perror, cpus, stats, msglvl, msgFile) ; return(rootchv) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- compute an (U^T + I)D(I + U) or (L + I)D(I + L) factorization of A + sigma*B. input -- frontmtx -- pointer to the FrontMtx object that will hold the factorization pencil -- pointer to the Pencil object that holds A + sigma*B tau -- upper bound on entries in L and U, used only when pivoting enabled droptol -- lower bound on entries in L and U, used only when sparsity enabled perror -- error flag, on return *perror >= 0 --> factorization failed at front *perror *perror < 0 --> factorization succeeded cpus[] -- timing array cpus[0] -- initialize fronts cpus[1] -- load original entries cpus[2] -- get updates from descendents cpus[3] -- assembled postponed data cpus[4] -- factor the front cpus[5] -- extract postponed data cpus[6] -- store factor entries cpus[7] -- miscellaneous time cpus[8] -- total time stats[] -- statistics array stats[0] -- # of pivots stats[1] -- # of pivot tests stats[2] -- # of delayed rows and columns stats[3] -- # of entries in D stats[4] -- # of entries in L stats[5] -- # of entries in U msglvl -- message level msgFile -- message file created -- 98mar27, cca modified -- 98mar27, cca perror added to argument list ------------------------------------------------------------------- */ Chv * FrontMtx_factorPencil ( FrontMtx *frontmtx, Pencil *pencil, double tau, double droptol, ChvManager *chvmanager, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile ) { char *status ; ChvList *postList ; Chv *rootchv ; Chv **fronts ; double t0, t3 ; DV tmpDV ; ETree *frontETree ; int J, K, ndelayed, nfront, npivots, ntests ; int *par ; IP **heads ; IV pivotsizesIV ; Tree *tree ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( frontmtx == NULL || pencil == NULL || cpus == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_factorPencil()" "\n frontmtx = %p, pencil = %p" "\n tau = %e, droptol = %e, cpus = %p" "\n msglvl = %d, msgFile = %p" "\n bad input\n", frontmtx, pencil, tau, droptol, cpus, msglvl, msgFile) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n INSIDE FrontMtx_factorPencil()") ; fflush(msgFile) ; } /* ------------------------------- extract pointers and dimensions ------------------------------- */ frontETree = frontmtx->frontETree ; nfront = ETree_nfront(frontETree) ; tree = ETree_tree(frontETree) ; par = ETree_par(frontETree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n got pointers and dimensions") ; fflush(msgFile) ; } /* --------------------------------------- allocate and initialize working storage --------------------------------------- */ heads = FrontMtx_factorSetup(frontmtx, NULL, 0, msglvl, msgFile) ; status = CVinit(nfront, 'W') ; ALLOCATE(fronts, Chv *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { fronts[J] = NULL ; } DV_setDefaultFields(&tmpDV) ; IV_setDefaultFields(&pivotsizesIV) ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { postList = ChvList_new() ; ChvList_init(postList, nfront+1, NULL, 0, NULL) ; } else { postList = NULL ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n allocated working storage") ; fflush(msgFile) ; } /* -------------------------------------------- loop over the tree in a post-order traversal -------------------------------------------- */ *perror = -1 ; npivots = ndelayed = ntests = 0 ; rootchv = NULL ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { K = par[J] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ##### working on front %d, parent %d", J, K) ; fflush(msgFile) ; } FrontMtx_factorVisit(frontmtx, pencil, J, 0, NULL, fronts, 0, tau, droptol, status, heads, &pivotsizesIV, &tmpDV, par, NULL, postList, chvmanager, stats, cpus, msglvl, msgFile) ; if ( status[J] == 'E' ) { /* ------------------------------- error found, unable to continue ------------------------------- */ *perror = J ; break ; } else if ( status[J] != 'F' ) { fprintf(stderr, "\n fatal error, return %c from front %d", status[J], J) ; exit(-1) ; } } /* --------------------------------- get a pointer to the root chevron --------------------------------- */ if ( postList == NULL ) { rootchv = NULL ; } else { rootchv = ChvList_getList(postList, nfront) ; } /* ------------------ set the statistics ------------------ */ stats[3] = frontmtx->nentD ; stats[4] = frontmtx->nentL ; stats[5] = frontmtx->nentU ; /* ------------------------ free the working storage ------------------------ */ IP_free(heads[nfront+1]) ; FREE(heads) ; DV_clearData(&tmpDV) ; IV_clearData(&pivotsizesIV) ; CVfree(status) ; FREE(fronts) ; if ( postList != NULL ) { ChvList_free(postList) ; } /* -------------------------------- set final and miscellaneous time -------------------------------- */ MARKTIME(t3) ; cpus[8] = t3 - t0 ; cpus[7] = cpus[8] - cpus[0] - cpus[1] - cpus[2] - cpus[3] - cpus[4] - cpus[5] - cpus[6] ; return(rootchv) ; } /*--------------------------------------------------------------------*/ FrontMtx/src/factorUtil.c010064400020550007177000001053400657627451000167400ustar00clevecompmath00000400000006/* factorUtil.c */ #include "../FrontMtx.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* ----------------------------- purpose -- initialize a front created -- 98may04, cca ----------------------------- */ void FrontMtx_initializeFront ( FrontMtx *frontmtx, Chv *frontJ, int J ) { int ncolJ, nD, nrowJ ; int *colindJ, *ivec ; /* ----------------------------------- get the number of internal vertices ----------------------------------- */ nD = ETree_frontSize(frontmtx->frontETree, J) ; /* -------------------------------------- get the internal and boundary vertices -------------------------------------- */ IVL_listAndSize(frontmtx->symbfacIVL, J, &ncolJ, &colindJ) ; #if MYDEBUG > 0 fprintf(stdout, "\n front %d, column indices", J) ; IVfprintf(stdout, ncolJ, colindJ) ; fflush(stdout) ; #endif /* ------------------------------------------------------ initialize the front's dimensions, indices and entries ------------------------------------------------------ */ #if MYDEBUG > 0 fprintf(stdout, "\n front %d, nD %d, nU %d", J, nD, ncolJ - nD) ; fflush(stdout) ; #endif Chv_init(frontJ, J, nD, ncolJ - nD, ncolJ - nD, frontmtx->type, frontmtx->symmetryflag) ; /* ----------------------- fill the column indices ----------------------- */ Chv_columnIndices(frontJ, &ncolJ, &ivec) ; IVcopy(ncolJ, ivec, colindJ) ; #if MYDEBUG > 0 fprintf(stdout, "\n front %d, colind = %p", J, ivec) ; IVfprintf(stdout, ncolJ, ivec) ; fflush(stdout) ; #endif if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* -------------------- fill the row indices -------------------- */ Chv_rowIndices(frontJ, &nrowJ, &ivec) ; IVcopy(nrowJ, ivec, colindJ) ; } /* ------------------------ zero the front's entries ------------------------ */ Chv_zero(frontJ) ; #if MYDEBUG > 0 fprintf(stdout, "\n leaving Front_initializeFront()") ; Chv_writeForHumanEye(frontJ, stdout) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* ---------------- static functions ---------------- */ static void assembleAggregates ( Chv *frontJ, ChvList *aggList, ChvManager *chvmanager, double cpus[], int msglvl, FILE *msgFile ) ; static char assemblePostponedData ( FrontMtx *frontmtx, Chv *frontJ, int *pndelay, Chv *fronts[], ChvList *postList, ChvManager *chvmanager, double cpus[], int msglvl, FILE *msgFile ) ; static int factorFront ( FrontMtx *frontmtx, Chv *frontJ, int ndelay, double tau, IV *pivotsizesIV, DV *workDV, int stats[], double cpus[], int msglvl, FILE *msgFile ) ; static void storeEntries ( FrontMtx *frontmtx, Chv *frontJ, int nelim, double droptol, IV *pivotsizesIV, ChvList *postList, ChvManager *chvmanager, int parent[], int stats[], double cpus[], int msglvl, FILE *msgFile ) ; /* ------------------------------------------------------------------ purpose -- to visit a front during a factorization. note: this method is called by the serial, multithreaded and MPI factorization codes. frontmtx -- front matrix object pencil -- matrix pencil for A + sigma*B J -- id of front we are working on myid -- id of thread or process owners[] -- map from fronts to owning threads, in a serial environment, owners = NULL fronts[] -- vector of pointers to fronts lookahead -- parameter controls the partial upward visiting of ancestors before returning tau -- used when pivoting enabled, |L_{j,i}| and |U_{i,j}| <= tau droptol -- used for an approximate factorization stored |L_{j,i}| and |U_{i,j}| > droptol status[] -- status vector for the fronts, 'W' -- needs to be woke up 'A' -- active front 'F' -- front is finished heads[] -- vector of pointers to IP objects that store the front-to-front update lists pivotsizesIV -- IV object used during the factorization of a front when pivoting is enabled workDV -- DV object used for working storage parent -- front parent vector aggList -- list object used in parallel environment, used to store aggregate fronts postList -- list object used in pivoting and/or parallel environments, used to stored delayed data and/or to synchronize the factorization chvmanager -- used to manage working storage for Chv objects stats[] -- statistics vector cpus[] -- vector to hold breakdown of cpu times msglvl -- message level msgFil -- message file created -- 98may04, cca ------------------------------------------------------------------ */ char FrontMtx_factorVisit ( FrontMtx *frontmtx, Pencil *pencil, int J, int myid, int owners[], Chv *fronts[], int lookahead, double tau, double droptol, char status[], IP *heads[], IV *pivotsizesIV, DV *workDV, int parent[], ChvList *aggList, ChvList *postList, ChvManager *chvmanager, int stats[], double cpus[], int msglvl, FILE *msgFile ) { /* --------------- local variables --------------- */ char allAggregatesHere, allPostponedAssmb, allUpdatesDone ; Chv *frontJ ; double t1, t2 ; int K, ndelay, nelim ; if ( status[J] == 'F' ) { return('F') ; } allUpdatesDone = 'N' ; allAggregatesHere = 'N' ; allPostponedAssmb = 'N' ; frontJ = NULL ; if ( heads[J] != NULL ) { /* -------------------------------- internal updates to be performed -------------------------------- */ if ( (frontJ = fronts[J]) == NULL ) { /* -------------------- initialize the front -------------------- */ fronts[J] = FrontMtx_setupFront(frontmtx, pencil, J, myid, owners, chvmanager, cpus, msglvl, msgFile) ; frontJ = fronts[J] ; status[J] = 'A' ; } /* --------------------------------- compute updates from owned fronts --------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n performing updates") ; fflush(msgFile) ; } MARKTIME(t1) ; FrontMtx_update(frontmtx, frontJ, heads, status, workDV, msglvl, msgFile) ; MARKTIME(t2) ; cpus[2] += t2 - t1 ; } if ( heads[J] == NULL ) { allUpdatesDone = 'Y' ; } if ( owners == NULL || owners[J] == myid ) { /* -------------- front is owned -------------- */ if ( (frontJ = fronts[J]) == NULL ) { /* -------------------- initialize the front -------------------- */ fronts[J] = FrontMtx_setupFront(frontmtx, pencil, J, myid, owners, chvmanager, cpus, msglvl, msgFile) ; frontJ = fronts[J] ; status[J] = 'A' ; } if ( aggList != NULL ) { /* ------------------------------------------ we are operating in a parallel environment ------------------------------------------ */ if ( ChvList_isListNonempty(aggList, J) == 1 ) { /* ------------------------------------------------- assemble any aggregate updates from other threads ------------------------------------------------- */ assembleAggregates(frontJ, aggList, chvmanager, cpus, msglvl, msgFile) ; } if ( ChvList_isCountZero(aggList, J) == 1 ) { /* ------------------------------------------------------- all aggregates are assembled or in the list to assemble ------------------------------------------------------- */ if ( ChvList_isListNonempty(aggList, J) == 1 ) { /* ------------------------------------------------- assemble any aggregate updates from other threads ------------------------------------------------- */ assembleAggregates(frontJ, aggList, chvmanager, cpus, msglvl, msgFile) ; } allAggregatesHere = 'Y' ; } } else { allAggregatesHere = 'Y' ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n allUpdatesDone %c, allAggregatesHere %c", allUpdatesDone, allAggregatesHere) ; fflush(msgFile) ; } if ( allUpdatesDone == 'Y' && allAggregatesHere == 'Y' ) { /* ------------------------------------- all internal updates and all external aggregates have been incorporated ------------------------------------- */ if ( postList != NULL ) { /* --------------------------------------------- front is ready to assemble any postponed data --------------------------------------------- */ allPostponedAssmb = assemblePostponedData(frontmtx, frontJ, &ndelay, fronts, postList, chvmanager, cpus, msglvl, msgFile) ; frontJ = fronts[J] ; } else { allPostponedAssmb = 'Y' ; ndelay = 0 ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n allPostponedAssmb %c", allPostponedAssmb) ; fflush(msgFile) ; } if ( allPostponedAssmb == 'Y' ) { /* ----------------------------- front is ready to be factored ----------------------------- */ nelim = factorFront(frontmtx, frontJ, ndelay, tau, pivotsizesIV, workDV, stats, cpus, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n J = %d, nelim = %d", frontJ->id, nelim) ; fflush(msgFile) ; } if ( (! FRONTMTX_IS_PIVOTING(frontmtx)) && nelim < frontJ->nD){ /* ------------------------------------------------ a singular front matrix has been found. release the front and set the status to error ------------------------------------------------ */ ChvManager_releaseObject(chvmanager, frontJ) ; fronts[J] = NULL ; status[J] = 'E' ; } else { /* ------------------------------------------- store any factor entries and postponed data ------------------------------------------- */ storeEntries(frontmtx, frontJ, nelim, droptol, pivotsizesIV, postList, chvmanager, parent, stats, cpus, msglvl, msgFile) ; /* ------------------------------------------------ release the front and set the status to finished ------------------------------------------------ */ ChvManager_releaseObject(chvmanager, frontJ) ; fronts[J] = NULL ; status[J] = 'F' ; } } } } else if ( allUpdatesDone == 'Y' ) { if ( frontJ != NULL ) { /* -------------------------------------------------------- front is not owned and all internal updates are complete put aggregate update front on the aggregate list -------------------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n done with unowned front %3d", J) ; fflush(msgFile) ; } if ( msglvl > 3 ) { Chv_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; ChvList_addObjectToList(aggList, frontJ, J) ; MARKTIME(t2) ; #if MYDEBUG > 0 fprintf(stdout, "\n thread %2d, done with unowned front %3d", myid, J) ; fflush(stdout) ; #endif cpus[7] += t2 - t1 ; } status[J] = 'F' ; } if ( --lookahead >= 0 && (K = parent[J]) != -1 ) { /* ----------------------------- visit parent before returning ----------------------------- */ FrontMtx_factorVisit(frontmtx, pencil, J, myid, owners, fronts, lookahead, tau, droptol, status, heads, pivotsizesIV, workDV, parent, aggList, postList, chvmanager, stats, cpus, msglvl, msgFile) ; } return(status[J]) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- set up the front's data structure created -- 98mar27, cca -------------------------------------------- */ Chv * FrontMtx_setupFront ( FrontMtx *frontmtx, Pencil *pencil, int J, int myid, int owners[], ChvManager *chvmanager, double cpus[], int msglvl, FILE *msgFile ) { Chv *frontJ ; double t1, t2 ; int nbytes, nD, nL, nU ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n inside FrontMtx_setupFront()" "\n frontmtx %p, pencil %p, J %d, myid %d" "\n owners %p, chvmanager %p, cpus %p" "\n msglvl %d, msgFile %p", frontmtx, pencil, J, myid, owners, chvmanager, cpus, msglvl, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; FrontMtx_initialFrontDimensions(frontmtx, J, &nD, &nL, &nU, &nbytes) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n nD %d, nL %d, nU %d, nbytes %d", nD, nL, nU, nbytes) ; fflush(msgFile) ; } frontJ = ChvManager_newObjectOfSizeNbytes(chvmanager, nbytes) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n frontJ = %p", frontJ) ; fflush(msgFile) ; } Chv_init(frontJ, J, nD, nL, nU, frontmtx->type, frontmtx->symmetryflag); FrontMtx_initializeFront(frontmtx, frontJ, J) ; MARKTIME(t2) ; cpus[0] += t2 - t1 ; if ( pencil != NULL && (owners == NULL || owners[J] == myid) ) { /* ------------------------------------------------- thread owns this front, load the original entries ------------------------------------------------- */ MARKTIME(t1) ; FrontMtx_loadEntries(frontJ, pencil, msglvl, msgFile) ; MARKTIME(t2) ; cpus[1] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n original entries loaded") ; fflush(msgFile) ; } /* if ( FRONTMTX_IS_HERMITIAN(frontmtx) && J == frontmtx->nfront - 1 ) { fprintf(msgFile, "\n last front after entries loaded") ; Chv_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } */ } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n front initialized") ; fflush(msgFile) ; } if ( msglvl > 3 ) { Chv_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } return(frontJ) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- assemble any aggregate updates from other threads ------------------------------------------------------------ */ static void assembleAggregates ( Chv *frontJ, ChvList *aggList, ChvManager *chvmanager, double cpus[], int msglvl, FILE *msgFile ) { Chv *chv, *headchv ; double t1, t2 ; MARKTIME(t1) ; headchv = ChvList_getList(aggList, frontJ->id) ; for ( chv = headchv ; chv != NULL ; chv = chv->next ) { Chv_assembleChv(frontJ, chv) ; } MARKTIME(t2) ; cpus[8] += t2 - t1 ; ChvManager_releaseListOfObjects(chvmanager, headchv) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n after assembly") ; Chv_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- assemble any postponed data created -- 98mar27, cca -------------------------------------- */ static char assemblePostponedData ( FrontMtx *frontmtx, Chv *frontJ, int *pndelay, Chv *fronts[], ChvList *postList, ChvManager *chvmanager, double cpus[], int msglvl, FILE *msgFile ) { char rc ; double t1, t2 ; int J ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n frontmtx %p, frontJ %p, pndelay %p" "\n fronts %p, postList %p, chvmanager %p, cpus %p", frontmtx, frontJ, pndelay, fronts, postList, chvmanager, cpus) ; fflush(msgFile) ; } J = frontJ->id ; if ( msglvl > 1 ) { if ( ChvList_isCountZero(postList, J) == 1) { fprintf(msgFile, "\n all postponed data is here") ; fflush(msgFile) ; } else { fprintf(msgFile, "\n still waiting on postponed data") ; fflush(msgFile) ; } } if ( ChvList_isCountZero(postList, J) == 1 ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n assembling postponed data") ; fflush(msgFile) ; } /* --------------------------- assemble any postponed data --------------------------- */ MARKTIME(t1) ; fronts[J] = FrontMtx_assemblePostponedData(frontmtx, frontJ, postList, chvmanager, pndelay) ; if ( frontJ != fronts[J] ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n releasing old front") ; fflush(msgFile) ; } ChvManager_releaseObject(chvmanager, frontJ) ; } MARKTIME(t2) ; cpus[3] += t2 - t1 ; rc = 'Y' ; } else { rc = 'N' ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* --------------------------- purpose -- factor the front created -- 98mar27, cca --------------------------- */ static int factorFront ( FrontMtx *frontmtx, Chv *frontJ, int ndelay, double tau, IV *pivotsizesIV, DV *workDV, int stats[], double cpus[], int msglvl, FILE *msgFile ) { double t1, t2 ; int nelim, npost ; if ( msglvl > 2 ) { fprintf(msgFile, "\n frontJ = %p, ndelay = %d", frontJ, ndelay) ; fprintf(msgFile, "\n tau = %12.4e", tau) ; fprintf(msgFile, "\n stats %p, cpus %p", stats, cpus) ; fflush(msgFile) ; } if ( msglvl > 2 ) { Chv_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { nelim = Chv_factorWithPivoting(frontJ, ndelay, frontmtx->pivotingflag, pivotsizesIV, workDV, tau, &stats[1]) ; } else { nelim = Chv_factorWithNoPivoting(frontJ, frontmtx->patchinfo) ; } npost = frontJ->nD - nelim ; stats[2] += npost ; if ( !(FRONTMTX_IS_PIVOTING(frontmtx)) || FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { stats[0] += nelim ; } else { stats[0] += IV_size(pivotsizesIV) ; } MARKTIME(t2) ; cpus[4] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n front %d, nelim = %d, npost = %d", frontJ->id, nelim, npost) ; fflush(msgFile) ; } if ( msglvl > 2 ) { Chv_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } return(nelim) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- store the factor entries in the front matrix object, and extract any postponed data and put it in the list object created -- 98mar27, cca --------------------------------------------------------------- */ static void storeEntries ( FrontMtx *frontmtx, Chv *frontJ, int nelim, double droptol, IV *pivotsizesIV, ChvList *postList, ChvManager *chvmanager, int parent[], int stats[], double cpus[], int msglvl, FILE *msgFile ) { double t1, t2 ; int npost ; npost = frontJ->nD - nelim ; if ( msglvl > 1 ) { fprintf(msgFile, "\n storing factor data, nelim = %d", nelim) ; fflush(msgFile) ; } MARKTIME(t1) ; frontJ->nD -= npost ; frontJ->nL += npost ; frontJ->nU += npost ; FrontMtx_storeFront(frontmtx, frontJ, pivotsizesIV, droptol, msglvl, msgFile) ; frontJ->nD += npost ; frontJ->nL -= npost ; frontJ->nU -= npost ; MARKTIME(t2) ; cpus[6] += t2 - t1 ; if ( postList != NULL ) { Chv *postponedchv ; if ( npost > 0 ) { /* --------------------------------- there is postponed data, extract and put on postponed list --------------------------------- */ postponedchv = frontJ ; if ( msglvl > 2 ) { fprintf(msgFile, "\n postponed data for front %d", frontJ->id) ; Chv_writeForHumanEye(postponedchv, msgFile) ; fflush(msgFile) ; } } else { postponedchv = NULL ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n storing postponed data %p", postponedchv); fflush(msgFile) ; } MARKTIME(t1) ; FrontMtx_storePostponedData(frontmtx, postponedchv, npost, parent[frontJ->id], postList, chvmanager) ; MARKTIME(t2) ; cpus[5] += t2 - t1 ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- to set up the link data structures for a parallel factorization for process myid return value -- pointer to IP *heads[nfront+2], which contains the beginning of a list of IP objects that store the remaining updates to the fronts. note, heads[nfront] is the first IP object in the free list. heads[nfront+1] is the base address of the allocated IP objects. created -- 98mar07, cca -------------------------------------------------------------------- */ IP ** FrontMtx_factorSetup ( FrontMtx *frontmtx, IV *frontOwnersIV, int myid, int msglvl, FILE *msgFile ) { int count, ii, J, K, nadj, nfront ; int *adj, *mark, *owners, *vtxToFront ; IP *ip ; IP **heads ; IVL *symbfacIVL ; /* --------------------------------------------------- count the number of updates this front will perform --------------------------------------------------- */ nfront = FrontMtx_nfront(frontmtx) ; if ( frontOwnersIV != NULL ) { owners = IV_entries(frontOwnersIV) ; } else { owners = NULL ; } symbfacIVL = frontmtx->symbfacIVL ; vtxToFront = ETree_vtxToFront(frontmtx->frontETree) ; mark = IVinit(nfront, -1) ; for ( J = count = 0 ; J < nfront ; J++ ) { if ( owners == NULL || owners[J] == myid ) { IVL_listAndSize(symbfacIVL, J, &nadj, &adj) ; mark[J] = J ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = vtxToFront[adj[ii]] ; if ( mark[K] != J ) { mark[K] = J ; count++ ; } } } } /* -------------------------------------------------- set up the update head/links for the factorization -------------------------------------------------- */ ALLOCATE(heads, struct _IP *, nfront + 2) ; for ( J = 0 ; J <= nfront + 1 ; J++ ) { heads[J] = NULL ; } heads[nfront] = heads[nfront+1] = IP_init(count, 1) ; IVfill(nfront, mark, -1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( owners == NULL || owners[J] == myid ) { IVL_listAndSize(symbfacIVL, J, &nadj, &adj) ; mark[J] = J ; for ( ii = 0 ; ii < nadj ; ii++ ) { K = vtxToFront[adj[ii]] ; if ( mark[K] != J ) { mark[K] = J ; ip = heads[nfront] ; heads[nfront] = ip->next ; ip->val = J ; ip->next = heads[K] ; heads[K] = ip ; if ( msglvl > 3 ) { fprintf(msgFile, "\n linking L(%d,%d) to L(%d,%d)", K, J, K, (ip->next == NULL) ? -1 : ip->next->val) ; fflush(msgFile) ; } } } } } IVfree(mark) ; return(heads) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- create and return the nactiveChild vector. nactiveChild[J] contains the number of children of J that belong to an active path created -- 97jul03, cca ----------------------------------------------- */ int * FrontMtx_nactiveChild ( FrontMtx *frontmtx, char *status, int myid ) { int J, K, nfront ; int *nactiveChild, *par ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || status == NULL || myid < 0 ) { fprintf(stderr, "\n fatal error in FrontMtx_nativeChild(%p,%p,%d)" "\n bad input\n", frontmtx, status, myid) ; exit(-1) ; } nfront = frontmtx->nfront ; par = ETree_par(frontmtx->frontETree) ; /* --------------------------------------- create and fill the nactiveChild vector --------------------------------------- */ nactiveChild = IVinit(nfront, 0) ; for ( J = 0 ; J < nfront ; J++ ) { if ( status[J] == 'W' && (K = par[J]) != -1 ) { nactiveChild[K]++ ; } } return(nactiveChild) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- create, initialize and return a Ideq object that will be used for a parallel factorization, forward solve, or backward solve. the status[] vector will be set as follows: status[J] = activeflag if J is on an active path status[J] = inactiveflag if J is not on an active path created -- 98mar27, cca --------------------------------------------------------- */ Ideq * FrontMtx_setUpDequeue ( FrontMtx *frontmtx, int owners[], int myid, char status[], IP *heads[], char activeFlag, char inactiveFlag, int msglvl, FILE *msgFile ) { Ideq *dequeue ; int J, K, nfront, npath ; int *par ; Tree *tree ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || owners == NULL || status == NULL || myid < 0 ) { fprintf(stderr, "\n fatal error in FrontMtx_setUpDequeue()" "\n frontmtx %p, owners %p, myid %d, status %p" "\n heads %p, activeFlag %c, inactiveFlag %c" "\n bad input\n", frontmtx, owners, myid, status, heads, activeFlag, inactiveFlag) ; exit(-1) ; } nfront = frontmtx->nfront ; tree = frontmtx->tree ; par = tree->par ; /* ------------------------------------ count the number of active paths in the tree and set the status[] vector ------------------------------------ */ CVfill(nfront, status, inactiveFlag) ; for ( J = npath = 0 ; J < nfront ; J++ ) { if ( status[J] == inactiveFlag ) { if ( owners[J] == myid || (heads != NULL && heads[J] != NULL) ) { npath++ ; for ( K = J ; K != -1 && status[K] != activeFlag ; K = par[K] ) { status[K] = activeFlag ; } } } } dequeue = Ideq_new() ; Ideq_resize(dequeue, npath) ; return(dequeue) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- load the dequeue with the leaves of the active subtree used for a factorization and forward solve created -- 98mar27, cca ----------------------------------------------------------------- */ void FrontMtx_loadActiveLeaves ( FrontMtx *frontmtx, char status[], char activeFlag, Ideq *dequeue ) { int I, J, nactivechild, nfront ; int *fch, *sib ; nfront = frontmtx->nfront ; fch = frontmtx->tree->fch ; sib = frontmtx->tree->sib ; for ( J = 0 ; J < nfront ; J++ ) { if ( status[J] == activeFlag ) { if ( fch[J] == -1 ) { Ideq_insertAtTail(dequeue, J) ; } else { nactivechild = 0 ; for ( I = fch[J] ; I != -1 ; I = sib[I] ) { if ( status[I] == activeFlag ) { nactivechild++ ; break ; } } if ( nactivechild == 0 ) { Ideq_insertAtTail(dequeue, J) ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- create, initialize and return a ChvList object to deal with postponed chevrons created -- 97jul03, cca ----------------------------------------------- */ ChvList * FrontMtx_postList ( FrontMtx *frontmtx, IV *frontOwnersIV, int lockflag ) { char *flags ; ChvList *postList ; int count, I, J, jthread, nchild, nfront, nthread ; int *counts, *fch, *frontOwners, *mark, *sib ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || frontOwnersIV == NULL || lockflag < 0 || lockflag > 2 ) { fprintf(stderr, "\n fatal error in FrontMtx_postList(%p,%p,%d)" "\n bad input\n", frontmtx, frontOwnersIV, lockflag) ; exit(-1) ; } fch = ETree_fch(frontmtx->frontETree) ; sib = ETree_sib(frontmtx->frontETree) ; IV_sizeAndEntries(frontOwnersIV, &nfront, &frontOwners) ; counts = IVinit(nfront+1, 0) ; if ( lockflag > 0 ) { flags = CVinit(nfront+1, 'N') ; } else { flags = NULL ; } nthread = 1 + IV_max(frontOwnersIV) ; mark = IVinit(nthread, -1) ; /* -------------------- loop over the fronts -------------------- */ for ( J = 0 ; J < nfront ; J++ ) { count = nchild = 0 ; for ( I = fch[J] ; I != -1 ; I = sib[I] ) { nchild++ ; jthread = frontOwners[I] ; if ( mark[jthread] != J ) { mark[jthread] = J ; count++ ; } } counts[J] = nchild ; if ( flags != NULL ) { if ( count > 1 ) { flags[J] = 'Y' ; } else { flags[J] = 'N' ; } } } count = nchild = 0 ; for ( J = ETree_root(frontmtx->frontETree) ; J != -1 ; J = sib[J] ) { nchild++ ; jthread = frontOwners[J] ; if ( mark[jthread] != J ) { mark[jthread] = J ; count++ ; } } counts[nfront] = nchild ; if ( flags != NULL ) { if ( count > 1 ) { flags[nfront] = 'Y' ; } else { flags[nfront] = 'N' ; } } /* ----------------------------------------- create and initialize the ChvList object ----------------------------------------- */ postList = ChvList_new() ; ChvList_init(postList, nfront+1, counts, lockflag, flags) ; /* ------------------------ free the working storage ------------------------ */ IVfree(mark) ; IVfree(counts) ; if ( flags != NULL ) { CVfree(flags) ; } return(postList) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- create, initialize and return a ChvList object to deal with aggregate chevrons created -- 97jul03, cca ----------------------------------------------- */ ChvList * FrontMtx_aggregateList ( FrontMtx *frontmtx, IV *frontOwnersIV, int lockflag ) { char *flags ; ChvList *aggList ; int count, ii, I, J, jthread, K, myid, nfront, nthread, size ; int *counts, *frontOwners, *head, *indices, *link, *mark, *offsets, *vtxToFront ; IVL *symbfacIVL ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || frontOwnersIV == NULL || lockflag < 0 || lockflag > 2 ) { fprintf(stderr, "\n fatal error in FrontMtx_aggregateList(%p,%p,%d)" "\n bad input\n", frontmtx, frontOwnersIV, lockflag) ; exit(-1) ; } symbfacIVL = frontmtx->symbfacIVL ; vtxToFront = ETree_vtxToFront(frontmtx->frontETree) ; IV_sizeAndEntries(frontOwnersIV, &nfront, &frontOwners) ; nthread = 1 + IV_max(frontOwnersIV) ; mark = IVinit(nthread, -1) ; head = IVinit(nfront, -1) ; link = IVinit(nfront, -1) ; offsets = IVinit(nfront, 0) ; counts = IVinit(nfront, 0) ; if ( lockflag > 0 ) { flags = CVinit(nfront, 'N') ; } else { flags = NULL ; } /* -------------------- loop over the fronts -------------------- */ for ( J = 0 ; J < nfront ; J++ ) { myid = frontOwners[J] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n front %d, owner %d", J, myid) ; fflush(stdout) ; #endif mark[myid] = J ; count = 0 ; /* --------------------------------------------------- loop over all descendent fronts that might update J --------------------------------------------------- */ while ( (I = head[J]) != -1 ) { head[J] = link[I] ; jthread = frontOwners[I] ; #if MYDEBUG > 0 fprintf(stdout, "\n descendent front %d, owner %d", I, jthread) ; fflush(stdout) ; #endif if ( mark[jthread] != J ) { /* -------------------------------- expect an aggregate from jthread -------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, ", incoming aggregate") ; fflush(stdout) ; #endif mark[jthread] = J ; count++ ; } /* -------------------------------------------------- link front I to next ancestor that it does not own -------------------------------------------------- */ IVL_listAndSize(symbfacIVL, I, &size, &indices) ; for ( ii = offsets[I] ; ii < size ; ii++ ) { if ( (K = vtxToFront[indices[ii]]) > J && frontOwners[K] != jthread ) { #if MYDEBUG > 0 fprintf(stdout, ", link to %d", K) ; fflush(stdout) ; #endif offsets[I] = ii ; link[I] = head[K] ; head[K] = I ; break ; } } } /* ------------------------------------- set the number of incoming aggregates ------------------------------------- */ counts[J] = count ; #if MYDEBUG > 0 fprintf(stdout, "\n counts[%d] = %d", J, counts[J]) ; fflush(stdout) ; #endif /* --------------------------------------------------- set the flags to see if the list needs to be locked --------------------------------------------------- */ if ( flags != NULL ) { if ( count > 1 ) { flags[J] = 'Y' ; } else { flags[J] = 'N' ; } #if MYDEBUG > 0 fprintf(stdout, ", flags[%d] = %c", J, flags[J]) ; fflush(stdout) ; #endif } /* -------------------------------------------------- link front J to next ancestor that it does not own -------------------------------------------------- */ IVL_listAndSize(symbfacIVL, J, &size, &indices) ; for ( ii = 0 ; ii < size ; ii++ ) { if ( (K = vtxToFront[indices[ii]]) > J && frontOwners[K] != myid ) { #if MYDEBUG > 0 fprintf(stdout, ", linking to %d", K) ; fflush(stdout) ; #endif offsets[J] = ii ; link[J] = head[K] ; head[K] = J ; break ; } } } #if MYDEBUG > 0 fprintf(stdout, "\n counts") ; IVfprintf(stdout, nfront, counts) ; fflush(stdout) ; #endif /* ----------------------------------------- create and initialize the ChvList object ----------------------------------------- */ aggList = ChvList_new() ; ChvList_init(aggList, nfront, counts, lockflag, flags) ; /* ------------------------ free the working storage ------------------------ */ IVfree(counts) ; IVfree(head) ; IVfree(link) ; IVfree(offsets) ; IVfree(mark) ; if ( flags != NULL ) { CVfree(flags) ; } return(aggList) ; } /*--------------------------------------------------------------------*/ n, forward solve, or backward solve. the status[] vector will be set as follows: status[J] = activeflag if J is on an active path status[J] = inactiveflag if J is not on an active path created -- 98mar27, cca ---------------------------------------------------FrontMtx/src/init.c010064400020550007177000000322430657132336200155630ustar00clevecompmath00000400000006/* init.c */ #include "../FrontMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- basic initializer frontETree -- ETree object that stores the front tree symbfacIVL -- IVL object that stores the symbolic factorization manager -- SubMtxManager object to manage SubMtx objects type -- type of entries SPOOLES_REAL --> real SPOOLES_COMPLEX --> complex symmetryflag -- symmetry flag, SPOOLES_SYMMETRIC --> symmetric structure and entries SPOOLES_HERMITIAN --> hermitian (complex only) SPOOLES_NONSYMMETRIC --> nonsymmetric entries sparsityflag -- flag to specify dense or sparse fronts FRONTMTX_DENSE_FRONTS --> dense fronts FRONTMTX_SPARSE_FRONTS --> sparse fronts pivotingflag -- flag to specify pivoting enabled SPOOLES_NO_PIVOTING --> pivoting not used SPOOLES_PIVOTING --> pivoting used in a multithreaded environment, we need to protect the critical section where data is allocated. we use a lockflag to do this. in a serial or distributed environment, use lockflag = 0. lockflag -- flag to specify lock status NO_LOCK --> mutex lock is not allocated or initialized LOCK_IN_PROCESS --> mutex lock is allocated and it can synchronize only threads in this process. LOCK_OVER_ALL_PROCESSES --> mutex lock is allocated and it can synchronize only threads in this and other processes. in a distributed environment we need to specify which process owns each front. when we can preallocate data structures (when there is no pivoting and dense fronts are stored) we need each process to determine what parts of the data it can allocate and set up. in a serial or multithreaded environment, use ownersIV = NULL. ownersIV -- map from fronts to owning processes myid -- id of this process. submatrices (be they lower, diagonal, block diagonal, upper) are stored in SubMtx objects. the management of these objects, (allocation and deallocation) is managed by the SubMtxManager manager object. manager -- SubMtxManager object to handle the submatrices created -- 98may04, cca ------------------------------------------------------------------ */ void FrontMtx_init ( FrontMtx *frontmtx, ETree *frontETree, IVL *symbfacIVL, int type, int symmetryflag, int sparsityflag, int pivotingflag, int lockflag, int myid, IV *ownersIV, SubMtxManager *manager, int msglvl, FILE *msgFile ) { SubMtx *mtx ; int J, nbytes, nentD, nentL, nentU, neqns, nD, nent, nfront, nU ; int *bndwghts, *nodwghts, *owners, *vtxToFront ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || frontETree == NULL || symbfacIVL == NULL || (ownersIV != NULL && myid < 0) || manager == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_init()" "\n frontmtx %p, frontETree %p, symbfacIVL %p" "\n myid %d, ownersIV %p, manager %p" "\n bad input\n", frontmtx, frontETree, symbfacIVL, myid, ownersIV, manager) ; exit(-1) ; } if ( type != SPOOLES_REAL && type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error in FrontMtx_init()" "\n type %d must be SPOOLES_REAL or SPOOLES_COMPLEX\n", type) ; exit(-1) ; } if ( type == SPOOLES_REAL && ! (symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_NONSYMMETRIC) ) { fprintf(stderr, "\n fatal error in FrontMtx_init()" "\n type is real" "\n symmetryflag is not SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC") ; exit(-1) ; } if ( type == SPOOLES_COMPLEX && ! (symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN || symmetryflag == SPOOLES_NONSYMMETRIC) ) { fprintf(stderr, "\n fatal error in FrontMtx_init()" "\n type is real, symmetryflag is not SPOOLES_SYMMETRIC," "\n SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC") ; exit(-1) ; } if ( ! ( pivotingflag == SPOOLES_PIVOTING || pivotingflag == SPOOLES_NO_PIVOTING) ) { fprintf(stderr, "\n fatal error in FrontMtx_init()" "\n pivotingflag must be SPOOLES_PIVOTING or SPOOLES_NO_PIVOTING\n") ; exit(-1) ; } if ( ! (lockflag == NO_LOCK || lockflag == LOCK_IN_PROCESS || lockflag == LOCK_OVER_ALL_PROCESSES) ) { fprintf(stderr, "\n fatal error in FrontMtx_init()" "\n invalid lockflag, must be NO_LOCK" "\n LOCK_IN_PROCESS or LOCK_OVER_ALL_PROCESSES") ; exit(-1) ; } nfront = frontETree->nfront ; neqns = frontETree->nvtx ; nodwghts = ETree_nodwghts(frontETree) ; bndwghts = ETree_bndwghts(frontETree) ; vtxToFront = ETree_vtxToFront(frontETree) ; if ( ownersIV != NULL ) { owners = IV_entries(ownersIV) ; } else { owners = NULL ; } /* ---------------------- set the default fields ---------------------- */ FrontMtx_setDefaultFields(frontmtx) ; /* --------------------- set the scalar fields --------------------- */ frontmtx->nfront = nfront ; frontmtx->neqns = neqns ; frontmtx->type = type ; frontmtx->symmetryflag = symmetryflag ; frontmtx->sparsityflag = sparsityflag ; frontmtx->pivotingflag = pivotingflag ; frontmtx->dataMode = FRONTMTX_1D_MODE ; /* --------------------------------------------------------------- set the front tree ETree and symbolic factorization IVL objects --------------------------------------------------------------- */ frontmtx->tree = frontETree->tree ; frontmtx->frontETree = frontETree ; frontmtx->symbfacIVL = symbfacIVL ; /* ---------------------------- set the frontsizes IV object ---------------------------- */ frontmtx->frontsizesIV = IV_new() ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { IV_init(frontmtx->frontsizesIV, nfront, NULL) ; IV_fill(frontmtx->frontsizesIV, 0) ; } else { IV_init(frontmtx->frontsizesIV, nfront, nodwghts) ; } /* ------------------------------------------------------ set the row and column adjacency objects, if necessary ------------------------------------------------------ */ if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { frontmtx->coladjIVL = IVL_new() ; IVL_init1(frontmtx->coladjIVL, IVL_CHUNKED, nfront) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { frontmtx->rowadjIVL = IVL_new() ; IVL_init1(frontmtx->rowadjIVL, IVL_CHUNKED, nfront) ; } } /* --------------------------------- allocate the five pointer vectors --------------------------------- */ ALLOCATE(frontmtx->p_mtxDJJ, struct _SubMtx *, nfront) ; ALLOCATE(frontmtx->p_mtxUJJ, struct _SubMtx *, nfront) ; ALLOCATE(frontmtx->p_mtxUJN, struct _SubMtx *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { frontmtx->p_mtxDJJ[J] = NULL ; frontmtx->p_mtxUJJ[J] = NULL ; frontmtx->p_mtxUJN[J] = NULL ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { ALLOCATE(frontmtx->p_mtxLJJ, struct _SubMtx *, nfront) ; ALLOCATE(frontmtx->p_mtxLNJ, struct _SubMtx *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { frontmtx->p_mtxLJJ[J] = NULL ; frontmtx->p_mtxLNJ[J] = NULL ; } } /* ------------------------------- set the submatrix manager field ------------------------------- */ frontmtx->manager = manager ; /* ------------------------------------- initialize submatrices where possible ------------------------------------- */ if ( ! FRONTMTX_IS_PIVOTING(frontmtx) && FRONTMTX_IS_DENSE_FRONTS(frontmtx) ) { double *entries ; int ii, jj, ncol, nrow ; int *firstlocs, *sizes ; nentD = nentL = nentU = 0 ; for ( J = 0 ; J < nfront ; J++ ) { if ( owners == NULL || owners[J] == myid ) { nD = nodwghts[J] ; nU = bndwghts[J] ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n J %d, nD %d, nU %d", J, nD, nU) ; fflush(msgFile) ; } /* --------------- diagonal matrix --------------- */ nbytes = SubMtx_nbytesNeeded(type, SUBMTX_DIAGONAL, nD, nD, nD) ; mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, type, SUBMTX_DIAGONAL, J, J, nD, nD, nD); SubMtx_diagonalInfo(mtx, &ncol, &entries) ; SubMtx_zero(mtx) ; nentD += nD ; frontmtx->p_mtxDJJ[J] = mtx ; if ( msglvl > 3 ) { fprintf(msgFile, "\n diagonal (%d,%d) matrix %p, %d entries, %d bytes", J, J, mtx, nD, nbytes) ; fflush(msgFile) ; } if ( (nent = (nD*(nD-1))/2) > 0 ) { /* ------------------------------------------- U_{J,J} and possibly lower L_{J,J} matrices ------------------------------------------- */ nbytes = SubMtx_nbytesNeeded(type, SUBMTX_DENSE_SUBCOLUMNS, nD, nD, nent) ; mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, type, SUBMTX_DENSE_SUBCOLUMNS, J, J, nD, nD, nent); SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; for ( jj = 0 ; jj < ncol ; jj++ ) { firstlocs[jj] = 0 ; sizes[jj] = jj ; } SubMtx_zero(mtx) ; nentU += nent ; frontmtx->p_mtxUJJ[J] = mtx ; if ( msglvl > 3 ) { fprintf(msgFile, "\n upper (%d,%d) matrix %p, %d entries, %d bytes", J, J, mtx, nent, nbytes) ; fflush(msgFile) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nbytes = SubMtx_nbytesNeeded(type, SUBMTX_DENSE_SUBROWS, nD, nD, nent) ; mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes); SubMtx_init(mtx, type, SUBMTX_DENSE_SUBROWS, J, J, nD, nD, nent); SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; for ( ii = 0 ; ii < nrow ; ii++ ) { firstlocs[ii] = 0 ; sizes[ii] = ii ; } SubMtx_zero(mtx) ; nentL += nent ; frontmtx->p_mtxLJJ[J] = mtx ; if ( msglvl > 3 ) { fprintf(msgFile, "\n lower (%d,%d) matrix %p, %d entries, %d bytes", J, J, mtx, nent, nbytes) ; fflush(msgFile) ; } } } if ( (nent = nD*nU) > 0 ) { /* ----------------------------------------------- U_{J,bnd{J}} and possibly L_{bnd{J},J} matrices ----------------------------------------------- */ nbytes = SubMtx_nbytesNeeded(type, SUBMTX_DENSE_COLUMNS, nD, nU, nent) ; mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, type, SUBMTX_DENSE_COLUMNS, J, nfront, nD, nU, nent); SubMtx_zero(mtx) ; nentU += nent ; frontmtx->p_mtxUJN[J] = mtx ; if ( msglvl > 3 ) { fprintf(msgFile, "\n upper (%d,%d) matrix %p, %d entries, %d bytes", J, nfront, mtx, nent, nbytes) ; fflush(msgFile) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nbytes = SubMtx_nbytesNeeded(type, SUBMTX_DENSE_ROWS, nU, nD, nent); mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes); SubMtx_init(mtx, type, SUBMTX_DENSE_ROWS, nfront, J, nU, nD, nent); SubMtx_zero(mtx) ; nentL += nent ; frontmtx->p_mtxLNJ[J] = mtx ; if ( msglvl > 3 ) { fprintf(msgFile, "\n lower (%d,%d) matrix %p, %d entries, %d bytes", nfront, J, mtx, nent, nbytes) ; fflush(msgFile) ; } } } } } frontmtx->nentD = nentD ; frontmtx->nentL = nentL ; frontmtx->nentU = nentU ; } if ( lockflag == LOCK_OVER_ALL_PROCESSES || lockflag == LOCK_IN_PROCESS ) { /* ----------------- allocate the lock ----------------- */ frontmtx->lock = Lock_new() ; Lock_init(frontmtx->lock, lockflag) ; } /* -------------------------------------- set the patch-and-go information field -------------------------------------- */ frontmtx->patchinfo = NULL ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n frontmtx->lock = %p", frontmtx->lock) ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ ) { fprintf(stderr, "\n fatal error in FrontMtx_init()" "\n type is real" "\n symmetryflag is not SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC") ; exit(-1) ; } if ( type == SPOOLES_COMPLEX && ! (symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN || symmetryflag == SPOOLES_NONSYMMETRIC) ) { fprintf(FrontMtx/src/instance.c010064400020550007177000000367100657126717200164350ustar00clevecompmath00000400000006/* instance.c */ #include "../FrontMtx.h" /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- return the number of fronts created -- 98may04, cca -------------------------------------- */ int FrontMtx_nfront ( FrontMtx *frontmtx ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_nfront(%p)" "\n bad input\n", frontmtx) ; exit(-1) ; } return(frontmtx->nfront) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- return the number of equations created -- 98may04, cca ----------------------------------------- */ int FrontMtx_neqns ( FrontMtx *frontmtx ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_neqns(%p)" "\n bad input\n", frontmtx) ; exit(-1) ; } return(frontmtx->neqns) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- return a pointer to the front Tree object created -- 98may04, cca ---------------------------------------------------- */ Tree * FrontMtx_frontTree ( FrontMtx *frontmtx ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_frontTree(%p)" "\n bad input\n", frontmtx) ; exit(-1) ; } return(frontmtx->tree) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- simple method to return the dimensions of front J and the number of bytes necessary for the Chv object to hold the front. created -- 98may04, cca ---------------------------------------------------------------- */ void FrontMtx_initialFrontDimensions ( FrontMtx *frontmtx, int J, int *pnD, int *pnL, int *pnU, int *pnbytes ) { int nbytes, nD, nL, nU ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || J < 0 || J >= frontmtx->nfront || pnD == NULL || pnL == NULL || pnU == NULL || pnbytes == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_initialFrontDimensions()" "\n frontmtx = %p, J = %d, pnD = %p, " "pnL = %p, pnU = %p, pnbytes = %p", frontmtx, J, pnD, pnL, pnU, pnbytes) ; exit(-1) ; } switch ( frontmtx->type ) { case SPOOLES_REAL : switch ( frontmtx->symmetryflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in FrontMtx_initialFrontDimensions()" "\n real type, must be symmetric or nonsymmetric\n") ; exit(-1) ; break ; } break ; case SPOOLES_COMPLEX : switch ( frontmtx->symmetryflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; fprintf(stderr, "\n fatal error in FrontMtx_initialFrontDimensions()" "\n complex type, must be symmetric," "\n hermitian or nonsymmetric\n") ; exit(-1) ; break ; } break ; default : fprintf(stderr, "\n fatal error in FrontMtx_initialFrontDimensions()" "\n bad type, must be real or complex") ; exit(-1) ; break ; } nD = frontmtx->frontETree->nodwghtsIV->vec[J] ; nL = nU = frontmtx->frontETree->bndwghtsIV->vec[J] ; nbytes = Chv_nbytesNeeded(nD, nL, nU, frontmtx->type, frontmtx->symmetryflag) ; *pnD = nD ; *pnL = nL ; *pnU = nU ; *pnbytes = nbytes ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- return the number of internal rows and columns in front J created -- 98may04, cca --------------------------------------------------------- */ int FrontMtx_frontSize ( FrontMtx *frontmtx, int J ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL || frontmtx->frontsizesIV == NULL || J < 0 || J >= frontmtx->nfront ) { fprintf(stderr, "\n fatal error in FrontMtx_frontSize(%p,%d)" "\n bad input\n", frontmtx, J) ; exit(-1) ; } return(IV_entry(frontmtx->frontsizesIV, J)) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ set the number of internal rows and columns in front J created -- 98may04, cca ------------------------------------------------------ */ void FrontMtx_setFrontSize ( FrontMtx *frontmtx, int J, int size ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL || frontmtx->frontsizesIV == NULL || J < 0 || J >= frontmtx->nfront || size < 0 ) { fprintf(stderr, "\n fatal error in FrontMtx_setFrontSize(%p,%d,%d)" "\n bad input\n", frontmtx, J, size) ; exit(-1) ; } IV_setEntry(frontmtx->frontsizesIV, J, size) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- fill *pncol with the number of columns and *pcolind with a pointer to the column indices created -- 98may04, cca --------------------------------------------- */ void FrontMtx_columnIndices ( FrontMtx *frontmtx, int J, int *pncol, int **pcolind ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL || J < 0 || J >= frontmtx->nfront || pncol == NULL || pcolind == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_columnIndices(%p,%d,%p,%p)" "\n bad input\n", frontmtx, J, pncol, pcolind) ; exit(-1) ; } if ( ! FRONTMTX_IS_PIVOTING(frontmtx) ) { IVL_listAndSize(frontmtx->symbfacIVL, J, pncol, pcolind) ; } else { IVL_listAndSize(frontmtx->coladjIVL, J, pncol, pcolind) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- fill *pnrow with the number of rows and *prowind with a pointer to the rows indices created -- 98may04, cca ------------------------------------------- */ void FrontMtx_rowIndices ( FrontMtx *frontmtx, int J, int *pnrow, int **prowind ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL || J < 0 || J >= frontmtx->nfront || pnrow == NULL || prowind == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_rowIndices(%p,%d,%p,%p)" "\n bad input\n", frontmtx, J, pnrow, prowind) ; exit(-1) ; } if ( ! FRONTMTX_IS_PIVOTING(frontmtx) ) { IVL_listAndSize(frontmtx->symbfacIVL, J, pnrow, prowind) ; } else if ( FRONTMTX_IS_SYMMETRIC(frontmtx) || FRONTMTX_IS_HERMITIAN(frontmtx) ) { IVL_listAndSize(frontmtx->coladjIVL, J, pnrow, prowind) ; } else if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { IVL_listAndSize(frontmtx->rowadjIVL, J, pnrow, prowind) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- return a pointer to the (J,J) diagonal submatrix created -- 98may04, cca ----------------------------------------------------------- */ SubMtx * FrontMtx_diagMtx ( FrontMtx *frontmtx, int J ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL || J < 0 || J >= frontmtx->nfront ) { fprintf(stderr, "\n fatal error in FrontMtx_diagMtx(%p,%d)" "\n bad input\n", frontmtx, J) ; exit(-1) ; } return(frontmtx->p_mtxDJJ[J]) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- return a pointer to the (J,K) upper submatrix created -- 98may04, cca -------------------------------------------------------- */ SubMtx * FrontMtx_upperMtx ( FrontMtx *frontmtx, int J, int K ) { int rc ; SubMtx *mtx ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || J < 0 || J >= frontmtx->nfront || K < J || K > frontmtx->nfront ) { fprintf(stderr, "\n fatal error in FrontMtx_upperMtx(%p,%d,%d)" "\n bad input\n", frontmtx, J, K) ; exit(-1) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { if ( K == frontmtx->nfront ) { mtx = frontmtx->p_mtxUJN[J] ; } else if ( K == J ) { mtx = frontmtx->p_mtxUJJ[J] ; } } else if ( frontmtx->upperhash == NULL ) { mtx = NULL ; } else { rc = I2Ohash_locate(frontmtx->upperhash, J, K, (void *) &mtx) ; if ( rc == 0 ) { mtx = NULL ; } } return(mtx) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- return a pointer to the (K,J) lower submatrix created -- 98may04, cca -------------------------------------------------------- */ SubMtx * FrontMtx_lowerMtx ( FrontMtx *frontmtx, int K, int J ) { int rc ; SubMtx *mtx ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || J < 0 || J >= frontmtx->nfront || K < J || K > frontmtx->nfront ) { fprintf(stderr, "\n fatal error in FrontMtx_lowerMtx(%p,%d,%d)" "\n bad input\n", frontmtx, K, J) ; exit(-1) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { if ( K == frontmtx->nfront ) { mtx = frontmtx->p_mtxLNJ[J] ; } else if ( K == J ) { mtx = frontmtx->p_mtxLJJ[J] ; } } else if ( frontmtx->lowerhash == NULL ) { mtx = NULL ; } else { rc = I2Ohash_locate(frontmtx->lowerhash, K, J, (void *) &mtx) ; if ( rc == 0 ) { mtx = NULL ; } } return(mtx) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- fill *pnadj with the number of fronts K such that L_{K,J} != 0 and *padj with a pointer to a list of those fronts created -- 98may04, cca -------------------------------------------------- */ void FrontMtx_lowerAdjFronts ( FrontMtx *frontmtx, int J, int *pnadj, int **padj ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL || J < 0 || J >= frontmtx->nfront || pnadj == NULL || padj == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_lowerAdjFronts(%p,%d,%p,%p)" "\n bad input\n", frontmtx, J, pnadj, padj) ; exit(-1) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { fprintf(stderr, "\n fatal error in FrontMtx_lowerAdjFronts()" "\n data mode is 1-D, not 2-D\n") ; exit(-1) ; } else if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { IVL_listAndSize(frontmtx->lowerblockIVL, J, pnadj, padj) ; } else { IVL_listAndSize(frontmtx->upperblockIVL, J, pnadj, padj) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- fill *pnadj with the number of fronts K such that U_{J,K} != 0 and *padj with a pointer to a list of those fronts created -- 98may04, cca -------------------------------------------------- */ void FrontMtx_upperAdjFronts ( FrontMtx *frontmtx, int J, int *pnadj, int **padj ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL || J < 0 || J >= frontmtx->nfront || pnadj == NULL || padj == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_upperAdjFronts(%p,%d,%p,%p)" "\n bad input\n", frontmtx, J, pnadj, padj) ; exit(-1) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { fprintf(stderr, "\n fatal error in FrontMtx_upperAdjFronts()" "\n data mode is 1, not 2\n") ; exit(-1) ; } IVL_listAndSize(frontmtx->upperblockIVL, J, pnadj, padj) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- return the number of nonzero L_{K,J} blocks created -- 98may04, cca ------------------------------------------------------ */ int FrontMtx_nLowerBlocks ( FrontMtx *frontmtx ) { int nblocks ; /* --------------- check the input --------------- */ if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_nLowerBlocks(%p)" "\n bad input\n", frontmtx) ; exit(-1) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { fprintf(stderr, "\n fatal error in FrontMtx_nLowerBlocks()" "\n data mode is 1, not 2\n") ; exit(-1) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nblocks = frontmtx->lowerblockIVL->tsize ; } else { nblocks = frontmtx->upperblockIVL->tsize ; } return(nblocks) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- return the number of nonzero U_{K,J} blocks created -- 98may04, cca ------------------------------------------------------ */ int FrontMtx_nUpperBlocks ( FrontMtx *frontmtx ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_nUpperBlocks(%p)" "\n bad input\n", frontmtx) ; exit(-1) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { fprintf(stderr, "\n fatal error in FrontMtx_nUpperBlocks()" "\n data mode is 1, not 2\n") ; exit(-1) ; } return(frontmtx->upperblockIVL->tsize) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- return a pointer to the upper block IVL object created -- 98jun13, cca --------------------------------------------------------- */ IVL * FrontMtx_upperBlockIVL ( FrontMtx *frontmtx ) { /* --------------- check the input --------------- */ if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_upperBlockIVL(%p)" "\n bad input\n", frontmtx) ; exit(-1) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { fprintf(stderr, "\n fatal error in FrontMtx_upperBlockIVL()" "\n data mode is 1, not 2\n") ; exit(-1) ; } return(frontmtx->upperblockIVL) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- return a pointer to the lower block IVL object created -- 98jun13, cca --------------------------------------------------------- */ IVL * FrontMtx_lowerBlockIVL ( FrontMtx *frontmtx ) { IVL *ivl ; /* --------------- check the input --------------- */ if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_lowerBlockIVL(%p)" "\n bad input\n", frontmtx) ; exit(-1) ; } if ( FRONTMTX_IS_1D_MODE(frontmtx) ) { fprintf(stderr, "\n fatal error in FrontMtx_lowerBlockIVL()" "\n data mode is 1, not 2\n") ; exit(-1) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { ivl = frontmtx->lowerblockIVL ; } else { ivl = frontmtx->upperblockIVL ; } return(ivl) ; } /*--------------------------------------------------------------------*/ FrontMtx/src/loadEntries.c010064400020550007177000000156570657126717200171110ustar00clevecompmath00000400000006/* loadEntries.c */ #include "../FrontMtx.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ load entries from sigma*A chv -- pointer to the Chv object that holds the front pencil -- pointer to a Pencil that holds the matrix entries msglvl -- message level msgFile -- message file created -- 97jul18, cca ------------------------------------------------------------ */ void FrontMtx_loadEntries ( Chv *chv, Pencil *pencil, int msglvl, FILE *msgFile ) { InpMtx *inpmtxA, *inpmtxB ; double one[2] = {1.0,0.0} ; double *sigma ; double *chvent ; int chvsize, ichv, ncol, nD, nL, nU ; int *chvind, *colind ; /* --------------- check the input --------------- */ if ( chv == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_loadEntries(%p,%p,%d,%p)" "\n bad input\n", chv, pencil, msglvl, msgFile) ; exit(-1) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n # inside loadEntries for chv %d" ", sigma = %12.4e + i*%12.4e", chv->id, pencil->sigma[0], pencil->sigma[1]) ; fflush(msgFile) ; } Chv_dimensions(chv, &nD, &nL, &nU) ; Chv_columnIndices(chv, &ncol, &colind) ; /* ---------------------------------------- load the original entries, A + sigma * B ---------------------------------------- */ inpmtxA = pencil->inpmtxA ; sigma = pencil->sigma ; inpmtxB = pencil->inpmtxB ; if ( inpmtxA != NULL ) { int ii ; /* ------------------- load entries from A ------------------- */ for ( ii = 0 ; ii < nD ; ii++ ) { ichv = colind[ii] ; if ( INPMTX_IS_REAL_ENTRIES(inpmtxA) ) { InpMtx_realVector(inpmtxA, ichv, &chvsize, &chvind, &chvent) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtxA) ) { InpMtx_complexVector(inpmtxA, ichv, &chvsize, &chvind, &chvent) ; } if ( chvsize > 0 ) { if ( msglvl > 3 ) { int ierr ; fprintf(msgFile, "\n inpmtxA chevron %d : chvsize = %d", ichv, chvsize) ; fprintf(msgFile, "\n chvind") ; IVfp80(msgFile, chvsize, chvind, 80, &ierr) ; fprintf(msgFile, "\n chvent") ; if ( INPMTX_IS_REAL_ENTRIES(inpmtxA) ) { DVfprintf(msgFile, chvsize, chvent) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtxA) ) { DVfprintf(msgFile, 2*chvsize, chvent) ; } fflush(msgFile) ; } Chv_addChevron(chv, one, ichv, chvsize, chvind, chvent) ; } } } else { double *entries ; int ii, off, stride ; /* ----------------- load the identity ----------------- */ entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { stride = nD + chv->nU ; off = 0 ; for ( ii = 0 ; ii < nD ; ii++ ) { entries[off] += 1.0 ; off += stride ; stride-- ; } } else if ( CHV_IS_NONSYMMETRIC(chv) ) { stride = 2*nD + chv->nL + chv->nU - 2 ; off = nD + chv->nL - 1 ; for ( ii = 0 ; ii < nD ; ii++ ) { entries[off] += 1.0 ; off += stride ; stride -= 2 ; } } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { stride = nD + chv->nU ; off = 0 ; for ( ii = 0 ; ii < nD ; ii++ ) { entries[2*off] += 1.0 ; off += stride ; stride-- ; } } else if ( CHV_IS_NONSYMMETRIC(chv) ) { stride = 2*nD + chv->nL + chv->nU - 2 ; off = nD + chv->nL - 1 ; for ( ii = 0 ; ii < nD ; ii++ ) { entries[2*off] += 1.0 ; off += stride ; stride -= 2 ; } } } } if ( inpmtxB != NULL ) { int ii ; /* ------------------------- load entries from sigma*B ------------------------- */ for ( ii = 0 ; ii < nD ; ii++ ) { ichv = colind[ii] ; if ( INPMTX_IS_REAL_ENTRIES(inpmtxB) ) { InpMtx_realVector(inpmtxB, ichv, &chvsize, &chvind, &chvent) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtxA) ) { InpMtx_complexVector(inpmtxB, ichv, &chvsize, &chvind, &chvent) ; } if ( chvsize > 0 ) { if ( msglvl > 3 ) { int ierr ; fprintf(msgFile, "\n inpmtxB chevron %d : chvsize = %d", ichv, chvsize) ; fprintf(msgFile, "\n chvind") ; IVfp80(msgFile, chvsize, chvind, 80, &ierr) ; fprintf(msgFile, "\n chvent") ; if ( INPMTX_IS_REAL_ENTRIES(inpmtxA) ) { DVfprintf(msgFile, chvsize, chvent) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtxA) ) { DVfprintf(msgFile, 2*chvsize, chvent) ; } } Chv_addChevron(chv, sigma, ichv, chvsize, chvind, chvent) ; } } } else { double *entries ; int ii, off, stride ; /* -------------------------------------- load a scalar multiple of the identity -------------------------------------- */ entries = Chv_entries(chv) ; if ( CHV_IS_REAL(chv) ) { if ( CHV_IS_SYMMETRIC(chv) ) { stride = nD + chv->nU ; off = 0 ; for ( ii = 0 ; ii < nD ; ii++ ) { entries[off] += sigma[0] ; off += stride ; stride-- ; } } else if ( CHV_IS_NONSYMMETRIC(chv) ) { stride = 2*nD + chv->nL + chv->nU - 2 ; off = nD + chv->nL - 1 ; for ( ii = 0 ; ii < nD ; ii++ ) { entries[off] += sigma[0] ; off += stride ; stride -= 2 ; } } } else if ( CHV_IS_COMPLEX(chv) ) { if ( CHV_IS_SYMMETRIC(chv) || CHV_IS_HERMITIAN(chv) ) { if ( CHV_IS_HERMITIAN(chv) && sigma[1] != 0.0 ) { fprintf(stderr, "\n fatal error in FrontMtx_loadEntries()" "\n chevron is hermitian" "\n sigma = %12.4e + %12.4e*i\n", sigma[0], sigma[1]) ; exit(-1) ; } stride = nD + chv->nU ; off = 0 ; for ( ii = 0 ; ii < nD ; ii++ ) { entries[2*off] += sigma[0] ; entries[2*off+1] += sigma[1] ; off += stride ; stride-- ; } } else if ( CHV_IS_NONSYMMETRIC(chv) ) { stride = 2*nD + chv->nL + chv->nU - 2 ; off = nD + chv->nL - 1 ; for ( ii = 0 ; ii < nD ; ii++ ) { entries[2*off] += sigma[0] ; entries[2*off+1] += sigma[1] ; off += stride ; stride -= 2 ; } } } } return ; } /*--------------------------------------------------------------------*/ FrontMtx/src/permute.c010064400020550007177000000246370657126717200163170ustar00clevecompmath00000400000006/* permute.c */ #include "../FrontMtx.h" /*--------------------------------------------------------------------*/ static void FrontMtx_reorderRowIndices ( FrontMtx *frontmtx, int J, int K, int map[], int msglvl, FILE *msgFile ) ; static void FrontMtx_reorderColumnIndices ( FrontMtx *frontmtx, int J, int K, int map[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- permute the upper adjacency structure so that the indices in bnd{J} are in ascending order w.r.t. their ancestors created -- 98mar05, cca ------------------------------------------------------------------ */ void FrontMtx_permuteUpperAdj ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) { int J, K, neqns ; int *map, *par ; Tree *tree ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_permuteUpperAdj(%p,%d,%p)" "\n badn input\n", frontmtx, msglvl, msgFile) ; exit(-1) ; } neqns = FrontMtx_neqns(frontmtx) ; map = IVinit(neqns, -1) ; tree = FrontMtx_frontTree(frontmtx) ; par = tree->par ; for ( J = Tree_preOTfirst(tree) ; J != -1 ; J = Tree_preOTnext(tree, J) ) { if ( (K = par[J]) != -1 ) { FrontMtx_reorderColumnIndices(frontmtx, J, K, map, msglvl, msgFile) ; } } IVfree(map) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- permute the lower adjacency structure so that the indices in bnd{J} are in ascending order w.r.t. their ancestors created -- 98mar05, cca ------------------------------------------------------------------ */ void FrontMtx_permuteLowerAdj ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) { int J, K, neqns ; int *map, *par ; Tree *tree ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_permuteLowerAdj(%p,%d,%p)" "\n badn input\n", frontmtx, msglvl, msgFile) ; exit(-1) ; } neqns = FrontMtx_neqns(frontmtx) ; map = IVinit(neqns, -1) ; tree = FrontMtx_frontTree(frontmtx) ; par = tree->par ; for ( J = Tree_preOTfirst(tree) ; J != -1 ; J = Tree_preOTnext(tree, J) ) { if ( (K = par[J]) != -1 ) { FrontMtx_reorderRowIndices(frontmtx, J, K, map, msglvl, msgFile) ; } } IVfree(map) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- if the columns indices of the front matrix are in different order than the column indices of U_{J,bnd{J}}, sort the columns of U_{J,bnd{J}} into ascending order w.r.t the column indices of the front matrix. created -- 98mar05, cca ------------------------------------------------------------ */ void FrontMtx_permuteUpperMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) { SubMtx *mtxUJ ; int ii, jj, J, mustdo, neqns, nfront, ncolJ, ncolUJ, nJ ; int *map, *colindJ, *colindUJ ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_permuteUpperMatrices(%p,%d,%p)" "\n badn input\n", frontmtx, msglvl, msgFile) ; exit(-1) ; } nfront = FrontMtx_nfront(frontmtx) ; neqns = FrontMtx_neqns(frontmtx) ; map = IVinit(neqns, -1) ; for ( J = 0 ; J < nfront ; J++ ) { mtxUJ = FrontMtx_upperMtx(frontmtx, J, nfront) ; if ( mtxUJ != NULL ) { nJ = FrontMtx_frontSize(frontmtx, J) ; FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; SubMtx_columnIndices(mtxUJ, &ncolUJ, &colindUJ) ; for ( ii = nJ, jj = mustdo = 0 ; ii < ncolJ ; ii++, jj++ ) { if ( colindJ[ii] != colindUJ[jj] ) { mustdo = 1 ; break ; } } if ( mustdo == 1 ) { for ( ii = 0 ; ii < ncolJ ; ii++ ) { map[colindJ[ii]] = ii ; } for ( ii = 0 ; ii < ncolUJ ; ii++ ) { colindUJ[ii] = map[colindUJ[ii]] ; } SubMtx_sortColumnsUp(mtxUJ) ; for ( ii = 0 ; ii < ncolUJ ; ii++ ) { colindUJ[ii] = colindJ[colindUJ[ii]] ; } } } } IVfree(map) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- if the row indices of the front matrix are in different order than the row indices of L_{bnd{J},J}, sort the rows of L_{bnd{J},J} into ascending order w.r.t the row indices of the front matrix. created -- 98mar05, cca -------------------------------------------------------- */ void FrontMtx_permuteLowerMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) { SubMtx *mtxLJ ; int ii, jj, J, mustdo, neqns, nfront, nJ, nrowJ, nrowUJ ; int *map, *rowindJ, *rowindUJ ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_permuteLowerMatrices(%p,%d,%p)" "\n badn input\n", frontmtx, msglvl, msgFile) ; exit(-1) ; } nfront = FrontMtx_nfront(frontmtx) ; neqns = FrontMtx_neqns(frontmtx) ; map = IVinit(neqns, -1) ; for ( J = 0 ; J < nfront ; J++ ) { mtxLJ = FrontMtx_lowerMtx(frontmtx, nfront, J) ; if ( mtxLJ != NULL ) { nJ = FrontMtx_frontSize(frontmtx, J) ; FrontMtx_rowIndices(frontmtx, J, &nrowJ, &rowindJ) ; SubMtx_rowIndices(mtxLJ, &nrowUJ, &rowindUJ) ; for ( ii = nJ, jj = mustdo = 0 ; ii < nrowJ ; ii++, jj++ ) { if ( rowindJ[ii] != rowindUJ[jj] ) { mustdo = 1 ; break ; } } if ( mustdo == 1 ) { for ( ii = 0 ; ii < nrowJ ; ii++ ) { map[rowindJ[ii]] = ii ; } for ( ii = 0 ; ii < nrowUJ ; ii++ ) { rowindUJ[ii] = map[rowindUJ[ii]] ; } SubMtx_sortRowsUp(mtxLJ) ; for ( ii = 0 ; ii < nrowUJ ; ii++ ) { rowindUJ[ii] = rowindJ[rowindUJ[ii]] ; } } } } IVfree(map) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to reorder the column indices in bnd{J} to be ascending order w.r.t. K cup bnd{K} created -- 98mar07, cca -------------------------------------------------- */ static void FrontMtx_reorderColumnIndices ( FrontMtx *frontmtx, int J, int K, int map[], int msglvl, FILE *msgFile ) { int ii, ncolJ, ncolK, nJ ; int *colindJ, *colindK ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside reorderColumnIndices(%d,%d)", J, K) ; fflush(msgFile) ; } nJ = FrontMtx_frontSize(frontmtx, J) ; FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n nJ = %d, ncolJ = %d", nJ, ncolJ) ; fflush(msgFile) ; } if ( ncolJ == 0 ) { return ; } FrontMtx_columnIndices(frontmtx, K, &ncolK, &colindK) ; if ( msglvl > 2 ) { fprintf(msgFile, ", ncolK = %d", ncolK) ; fflush(msgFile) ; } if ( ncolK == 0 ) { fprintf(stderr, "\n fatal error FrontMtx_reorderColumnIndices()" "\n J = %d, K = %d, nJ = %d, ncolJ = %d, ncolK = %d\n", J, K, nJ, ncolJ, ncolK) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n colindJ") ; IVfprintf(msgFile, ncolJ, colindJ) ; fprintf(msgFile, "\n colindK") ; IVfprintf(msgFile, ncolK, colindK) ; fflush(msgFile) ; } for ( ii = 0 ; ii < ncolK ; ii++ ) { map[colindK[ii]] = ii ; } for ( ii = nJ ; ii < ncolJ ; ii++ ) { colindJ[ii] = map[colindJ[ii]] ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n local colindJ") ; IVfprintf(msgFile, ncolJ, colindJ) ; fflush(msgFile) ; } IVqsortUp(ncolJ - nJ, colindJ + nJ) ; for ( ii = nJ ; ii < ncolJ ; ii++ ) { colindJ[ii] = colindK[colindJ[ii]] ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n global colindJ") ; IVfprintf(msgFile, ncolJ, colindJ) ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to reorder the row indices in bnd{J} to be ascending order w.r.t. K cup bnd{K} created -- 98mar07, cca ----------------------------------------------- */ static void FrontMtx_reorderRowIndices ( FrontMtx *frontmtx, int J, int K, int map[], int msglvl, FILE *msgFile ) { int ii, nrowJ, nrowK, nJ ; int *rowindJ, *rowindK ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside reorderRowIndices(%d,%d)", J, K) ; fflush(msgFile) ; } nJ = FrontMtx_frontSize(frontmtx, J) ; FrontMtx_rowIndices(frontmtx, J, &nrowJ, &rowindJ) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n nJ = %d, nrowJ = %d", nJ, nrowJ) ; fflush(msgFile) ; } if ( nrowJ == 0 ) { return ; } FrontMtx_rowIndices(frontmtx, K, &nrowK, &rowindK) ; if ( msglvl > 2 ) { fprintf(msgFile, ", nrowK = %d", nrowK) ; fflush(msgFile) ; } if ( nrowK == 0 ) { fprintf(stderr, "\n fatal error FrontMtx_reorderRowIndices()" "\n J = %d, K = %d, nJ = %d, nrowJ = %d, nrowK = %d\n", J, K, nJ, nrowJ, nrowK) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n rowindJ") ; IVfprintf(msgFile, nrowJ, rowindJ) ; fprintf(msgFile, "\n rowindK") ; IVfprintf(msgFile, nrowK, rowindK) ; fflush(msgFile) ; } for ( ii = 0 ; ii < nrowK ; ii++ ) { map[rowindK[ii]] = ii ; } for ( ii = nJ ; ii < nrowJ ; ii++ ) { rowindJ[ii] = map[rowindJ[ii]] ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n local rowindJ") ; IVfprintf(msgFile, nrowJ, rowindJ) ; fflush(msgFile) ; } IVqsortUp(nrowJ - nJ, rowindJ + nJ) ; for ( ii = nJ ; ii < nrowJ ; ii++ ) { rowindJ[ii] = rowindK[rowindJ[ii]] ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n global rowindJ") ; IVfprintf(msgFile, nrowJ, rowindJ) ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ FrontMtx/src/postProcess.c010064400020550007177000000122450661213037000171330ustar00clevecompmath00000400000006/* postProcess.c */ #include "../FrontMtx.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- post-process the factorization (1) permute row and column adjacency objects if necessary (2) permute lower and upper matrices if necessary (3) update the block adjacency objects if necessary (4) split the chevron submatrices into submatrices and make the submatrix indices local w.r.t their fronts created -- 98mar05, cca -------------------------------------------------------------- */ void FrontMtx_postProcess ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) { int nfront ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_postProcess(%p,%d,%p)" "\n bad input\n", frontmtx, msglvl, msgFile) ; exit(-1) ; } nfront = frontmtx->nfront ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { IV *colmapIV, *rowmapIV ; /* ------------------------------- permute the adjacency object(s) ------------------------------- */ FrontMtx_permuteUpperAdj(frontmtx, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n new column adjacency object") ; IVL_writeForHumanEye(frontmtx->coladjIVL, msgFile) ; fflush(msgFile) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { FrontMtx_permuteLowerAdj(frontmtx, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n new row adjacency object") ; IVL_writeForHumanEye(frontmtx->rowadjIVL, msgFile) ; fflush(msgFile) ; } } /* ------------------------------------------------------------- permute the U_{J,bnd{J}} and L_{bnd{J},J} triangular matrices ------------------------------------------------------------- */ FrontMtx_permuteUpperMatrices(frontmtx, msglvl, msgFile) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { FrontMtx_permuteLowerMatrices(frontmtx, msglvl, msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix after pivoting") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } /* ----------------------------------------------- get the map from columns to owning fronts and create the new upper block adjacency object ----------------------------------------------- */ colmapIV = FrontMtx_colmapIV(frontmtx) ; frontmtx->upperblockIVL = FrontMtx_makeUpperBlockIVL(frontmtx, colmapIV) ; IV_free(colmapIV) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* ------------------------------------------- get the map from rows to owning fronts and create the new lower block adjacency object ------------------------------------------- */ rowmapIV = FrontMtx_rowmapIV(frontmtx) ; frontmtx->lowerblockIVL = FrontMtx_makeLowerBlockIVL(frontmtx, rowmapIV) ; IV_free(rowmapIV) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n new upper block adjacency object") ; IVL_writeForHumanEye(frontmtx->upperblockIVL, msgFile) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { fprintf(msgFile, "\n\n new lower block adjacency object") ; IVL_writeForHumanEye(frontmtx->lowerblockIVL, msgFile) ; } fflush(msgFile) ; } } else { /* --------------------------------------- get the upper block adjacency structure --------------------------------------- */ IV *vtxToFrontIV = ETree_vtxToFrontIV(frontmtx->frontETree) ; frontmtx->upperblockIVL = FrontMtx_makeUpperBlockIVL(frontmtx, vtxToFrontIV) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* --------------------------------------- get the lower block adjacency structure --------------------------------------- */ frontmtx->lowerblockIVL = FrontMtx_makeLowerBlockIVL(frontmtx, vtxToFrontIV) ; } } /* ------------------------ allocate the hash tables ------------------------ */ frontmtx->upperhash = I2Ohash_new() ; I2Ohash_init(frontmtx->upperhash, nfront, nfront, nfront) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { frontmtx->lowerhash = I2Ohash_new() ; I2Ohash_init(frontmtx->lowerhash, nfront, nfront, nfront) ; } else { frontmtx->lowerhash = NULL ; } /* -------------------------------------------------------- split the U_{J,bnd{J}} and L_{bnd{J},J} into submatrices put the U_{J,K} and L_{K,J} matrices into hash tables, free the p_mtx*[] vectors. -------------------------------------------------------- */ FrontMtx_splitUpperMatrices(frontmtx, msglvl, msgFile) ; FREE(frontmtx->p_mtxUJJ) ; frontmtx->p_mtxUJJ = NULL ; FREE(frontmtx->p_mtxUJN) ; frontmtx->p_mtxUJN = NULL ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { FrontMtx_splitLowerMatrices(frontmtx, msglvl, msgFile) ; FREE(frontmtx->p_mtxLJJ) ; frontmtx->p_mtxLJJ = NULL ; FREE(frontmtx->p_mtxLNJ) ; frontmtx->p_mtxLNJ = NULL ; } frontmtx->dataMode = FRONTMTX_2D_MODE ; return ; } /*--------------------------------------------------------------------*/ FrontMtx/src/postponed.c010064400020550007177000000145420657126717200166430ustar00clevecompmath00000400000006/* postponed.c */ #include "../FrontMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- to assemble any postponed data into frontJ frontJ -- pointer to Chv objec that contains current front chvlist -- pointer to a ChvList object that handles the lists of postponed Chv objects chvmanager -- pointer to a ChvManager object for the list of free Chv objects pndelay -- pointer to address to contain the # of delayed rows and columns that were assembled into the front return value -- pointer to Chv object that contains the new front created -- 98may04, cca ------------------------------------------------------------------ */ Chv * FrontMtx_assemblePostponedData ( FrontMtx *frontmtx, Chv *frontJ, ChvList *chvlist, ChvManager *chvmanager, int *pndelay ) { Chv *child, *child2, *firstchild, *newfrontJ, *nextchild, *prev ; int nbytes, nDnew ; if ( (firstchild = ChvList_getList(chvlist, frontJ->id)) == NULL ) { /* ------------------------------------- quick return, no children to assemble ------------------------------------- */ *pndelay = 0 ; return(frontJ) ; } /* ------------------------------------------------------- order the children in ascending order of their front id this is done to ensure that the serial, multithreaded and MPI codes all assemble the same frontal matrix. ------------------------------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n postponed children of %d :", frontJ->id) ; for ( child = firstchild ; child != NULL ; child = child->next ) { fprintf(stdout, " %d", child->id) ; } fflush(stdout) ; #endif for ( child = firstchild, firstchild = NULL ; child != NULL ; child = nextchild ) { nextchild = child->next ; for ( child2 = firstchild, prev = NULL ; child2 != NULL ; child2 = child2->next ) { if ( child2->id > child->id ) { break ; } prev = child2 ; } if ( prev == NULL ) { firstchild = child ; } else { prev->next = child ; } child->next = child2 ; } #if MYDEBUG > 0 fprintf(stdout, "\n front %d, postponed children reordered :", frontJ->id) ; for ( child = firstchild ; child != NULL ; child = child->next ) { fprintf(stdout, " %d", child->id) ; } fflush(stdout) ; #endif /* -------------------------- compute the new dimensions -------------------------- */ nDnew = frontJ->nD ; for ( child = firstchild ; child != NULL ; child = child->next ) { nDnew += child->nD ; } /* ------------------------ get a new chevron object ------------------------ */ nbytes = Chv_nbytesNeeded(nDnew, frontJ->nL, frontJ->nU, frontJ->type, frontJ->symflag) ; newfrontJ = ChvManager_newObjectOfSizeNbytes(chvmanager, nbytes) ; Chv_init(newfrontJ, frontJ->id, nDnew, frontJ->nL, frontJ->nU, frontJ->type, frontJ->symflag) ; /* ---------------------------------------------------------- pivoting has been enabled, assemble any postponed chevrons ---------------------------------------------------------- */ *pndelay = Chv_assemblePostponedData(newfrontJ, frontJ, firstchild) ; /* -------------------------------------------------- now put the postponed chevrons onto the free list. -------------------------------------------------- */ ChvManager_releaseListOfObjects(chvmanager, firstchild) ; /* ------------------------------------- set the delay to zero if a root front ------------------------------------- */ if ( frontJ->nU == 0 ) { *pndelay = 0 ; } return(newfrontJ) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- extract and store the postponed data frontJ -- pointer to present front object npost -- # of postponed rows and columns in frontJ K -- parent of J chvlist -- pointer to a ChvList object that handles the lists of postponed Chv objects a singly linked list to assemble chvmanager -- pointer to a ChvManager object for the list of free Chv objects created -- 98may04, cca --------------------------------------------------------- */ void FrontMtx_storePostponedData ( FrontMtx *frontmtx, Chv *frontJ, int npost, int K, ChvList *chvlist, ChvManager *chvmanager ) { Chv *chv ; int nbytes, nD, nent, nind, nL, nU ; if ( npost <= 0 && chvlist != NULL ) { if ( K == -1 ) { ChvList_addObjectToList(chvlist, NULL, frontmtx->nfront) ; } else { ChvList_addObjectToList(chvlist, NULL, K) ; } return ; } /* -------------------------------------- find the number of indices and entries necessary to store the delayed data -------------------------------------- */ Chv_dimensions(frontJ, &nD, &nL, &nU) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n front %d: npost = %d, nD = %d, nL = %d, nU = %d", frontJ->id, npost, nD, nL, nU) ; fflush(stdout) ; #endif if ( CHV_IS_SYMMETRIC(frontJ) || CHV_IS_HERMITIAN(frontJ) ) { nind = npost + nU ; nent = (npost*(npost+1))/2 + npost*nU ; } else if ( CHV_IS_NONSYMMETRIC(frontJ) ) { nind = 2*(npost + nU) ; nent = npost*(npost + 2*nU) ; } /* ------------------------------------ get a Chv object from the free list ------------------------------------ */ nbytes = Chv_nbytesNeeded(npost, nL, nU, frontJ->type, frontJ->symflag); chv = ChvManager_newObjectOfSizeNbytes(chvmanager, nbytes) ; Chv_init(chv, frontJ->id, npost, nL, nU, frontJ->type, frontJ->symflag); /* ---------------------- store the delayed data ---------------------- */ Chv_copyTrailingPortion(chv, frontJ, nD - npost) ; frontJ->nD -= npost ; frontJ->nL += npost ; frontJ->nU += npost ; #if MYDEBUG > 0 fprintf(stdout, "\n\n postponed chevron %p", chv) ; Chv_writeForHumanEye(chv, stdout) ; fflush(stdout) ; #endif /* ------------------------------ link the postponed Chv object ------------------------------ */ if ( K == -1 ) { ChvList_addObjectToList(chvlist, chv, frontmtx->nfront) ; } else { ChvList_addObjectToList(chvlist, chv, K) ; } return ; } /*--------------------------------------------------------------------*/ ---------------------- order the children in ascending order of their front id this is done to ensure that the serial, multithreaded and MPI codes alFrontMtx/src/solve.c010064400020550007177000000134060657126717100157550ustar00clevecompmath00000400000006/* solve.c */ #include "../FrontMtx.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- to solve a linear system frontmtx -- FrontMtx object that holds the factor matrices solmtx -- DenseMtx that holds the solution rhsmtx -- DenseMtx that holds the right hand side matrix note: right hand side entries are copied from rhsmtx, and solution entries are copied into solmtx. when the row indices of rhsmtx and solmtx are identical, rhsmtx and solmtx can be the same object. cpus -- vector to hold cpu breakdown time cpus[0] -- set up solves cpus[1] -- fetch rhs and store solution cpus[2] -- forward solve cpus[3] -- diagonal solve cpus[4] -- backward solve cpus[5] -- total time mtxmanager -- object that manages working storage msglvl -- message level msgFile -- message file created -- 98may04, cca ------------------------------------------------------------ */ void FrontMtx_solve ( FrontMtx *frontmtx, DenseMtx *solmtx, DenseMtx *rhsmtx, SubMtxManager *mtxmanager, double cpus[], int msglvl, FILE *msgFile ) { char *frontIsDone, *status ; SubMtx **p_mtx ; double t0, t1, t2 ; int J, nfront, nrhs ; IP **heads ; Tree *tree ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( frontmtx == NULL || solmtx == NULL || rhsmtx == NULL || mtxmanager == NULL || cpus == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_solve()" "\n bad input :" "\n frontmtx = %p, solmtx = %p, rhsmtx = %p" "\n mtxmanager = %p, cpus = %p" "\n msglvl = %d, msgFile = %p\n", frontmtx, solmtx, rhsmtx, mtxmanager, cpus, msglvl, msgFile) ; exit(-1) ; } nfront = FrontMtx_nfront(frontmtx) ; tree = FrontMtx_frontTree(frontmtx) ; nrhs = rhsmtx->ncol ; /* -------------------------------------------------- set up the update head/links for the forward solve -------------------------------------------------- */ MARKTIME(t1) ; heads = FrontMtx_forwardSetup(frontmtx, msglvl, msgFile ) ; frontIsDone = CVinit(nfront, 'N') ; status = CVinit(nfront, 'W') ; MARKTIME(t2) ; cpus[0] = t2 - t1 ; /* ---------------------------------------------------- load the right hand side into temporary SubMtx objects ---------------------------------------------------- */ MARKTIME(t1) ; p_mtx = FrontMtx_loadRightHandSide(frontmtx, rhsmtx, NULL, 0, mtxmanager, msglvl, msgFile) ; MARKTIME(t2) ; cpus[1] = t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU : load rhs = %8.3f", t2 - t1) ; } /* ---------------------------- forward solve: (L + I) y = b ---------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ####### starting forward solve") ; fflush(msgFile) ; } MARKTIME(t1) ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n forward visiting front %d", J) ; fflush(msgFile) ; } FrontMtx_forwardVisit(frontmtx, J, nrhs, NULL, 0, mtxmanager, NULL, p_mtx, frontIsDone, heads, p_mtx, status, msglvl, msgFile) ; } IP_free(heads[nfront+1]) ; FREE(heads) ; MARKTIME(t2) ; cpus[2] = t2 - t1 ; /* ----------------- solve D z_J = y_J ----------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ####### starting diagonal solve") ; fflush(msgFile) ; } MARKTIME(t1) ; CVfill(nfront, frontIsDone, 'N') ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n diagonal visiting front %d", J) ; fflush(msgFile) ; } FrontMtx_diagonalVisit(frontmtx, J, NULL, 0, p_mtx, frontIsDone, p_mtx, msglvl, msgFile) ; frontIsDone[J] = 'D' ; } MARKTIME(t2) ; cpus[3] = t2 - t1 ; /* --------------------------------------------------- set up the update head/links for the backward solve --------------------------------------------------- */ MARKTIME(t1) ; heads = FrontMtx_backwardSetup(frontmtx, msglvl, msgFile) ; CVfill(nfront, status, 'W') ; CVfill(nfront, frontIsDone, 'N') ; MARKTIME(t2) ; cpus[0] += t2 - t1 ; /* ----------------------------- backward solve: (I + U) x = z ----------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ####### starting backward solve") ; fflush(msgFile) ; } MARKTIME(t1) ; for ( J = Tree_preOTfirst(tree) ; J != -1 ; J = Tree_preOTnext(tree, J) ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n backward visiting front %d", J) ; fflush(msgFile) ; } FrontMtx_backwardVisit(frontmtx, J, nrhs, NULL, 0, mtxmanager, NULL, p_mtx, frontIsDone, heads, p_mtx, status, msglvl, msgFile) ; } MARKTIME(t2) ; cpus[4] = t2 - t1 ; /* ---------------------------- store the solution in rhsmtx ---------------------------- */ MARKTIME(t1) ; FrontMtx_storeSolution(frontmtx, NULL, 0, mtxmanager, p_mtx, solmtx, msglvl, msgFile) ; MARKTIME(t2) ; cpus[1] += t2 - t1 ; if ( msglvl > 2 ) { fprintf(msgFile, "\n CPU : store solution = %8.3f", t2 - t1) ; } /* ------------------------ free the working storage ------------------------ */ IP_free(heads[nfront+1]) ; FREE(heads) ; FREE(p_mtx) ; CVfree(frontIsDone) ; CVfree(status) ; MARKTIME(t2) ; cpus[5] = t2 - t0 ; return ; } /*--------------------------------------------------------------------*/ FrontMtx/src/solveUtil.c010064400020550007177000000774440661221544700166220ustar00clevecompmath00000400000006/* solveUtil.c */ #include "../FrontMtx.h" #include "../../SubMtxList.h" /*--------------------------------------------------------------------*/ static SubMtx * initBJ ( int type, int J, int nJ, int nrhs, SubMtxManager *mtxmanager, int msglvl, FILE *msgFile ) ; static void computeForwardUpdates ( FrontMtx *frontmtx, SubMtx *BJ, int J, IP *heads[], char frontIsDone[], SubMtx *p_mtx[], int msglvl, FILE *msgFile ) ; static void assembleAggregates ( int J, SubMtx *BJ, SubMtxList *aggList, SubMtxManager *mtxmanager, int msglvl, FILE *msgFile ) ; static void computeBackwardUpdates ( FrontMtx *frontmtx, SubMtx *ZJ, int J, IP *heads[], char frontIsDone[], SubMtx *p_mtx[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- load the right hand side for the owned fronts created -- 98mar19, cca --------------------------------------------- */ SubMtx ** FrontMtx_loadRightHandSide ( FrontMtx *frontmtx, DenseMtx *rhsmtx, int owners[], int myid, SubMtxManager *mtxmanager, int msglvl, FILE *msgFile ) { char localrhs ; SubMtx *BJ ; SubMtx **p_agg ; double *bJ, *rhs ; int inc1, inc2, irow, jrhs, J, kk, nbytes, ncolJ, neqns, nfront, nJ, nrhs, nrowInRhs, nrowJ ; int *rowind, *rowindJ, *rowmap ; nrowInRhs = rhsmtx->nrow ; neqns = frontmtx->neqns ; if ( nrowInRhs != neqns ) { /* ---------------------------------------------------- the rhs matrix is only part of the total rhs matrix. (this happens in an MPI environment where the rhs is partitioned among the processors.) create a map from the global row indices to the indices local to this rhs matrix. ---------------------------------------------------- */ rowmap = IVinit(neqns, -1) ; rowind = rhsmtx->rowind ; if ( msglvl > 2 ) { fprintf(msgFile, "\n rhsmtx->rowind") ; IVfprintf(msgFile, rhsmtx->nrow, rowind) ; fflush(msgFile) ; } for ( irow = 0 ; irow < nrowInRhs ; irow++ ) { rowmap[rowind[irow]] = irow ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n rowmap") ; IVfprintf(msgFile, neqns, rowmap) ; fflush(msgFile) ; } localrhs = 'T' ; } else { localrhs = 'F' ; } /* -------------------------------------- allocate the vector of SubMtx pointers -------------------------------------- */ nfront = FrontMtx_nfront(frontmtx) ; ALLOCATE(p_agg, struct _SubMtx *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { p_agg[J] = NULL ; } DenseMtx_dimensions(rhsmtx, &neqns, &nrhs) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (owners == NULL || owners[J] == myid) && (nJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { FrontMtx_rowIndices(frontmtx, J, &nrowJ, &rowindJ) ; if ( localrhs == 'T' ) { /* ------------------------------------------------------ map the global row indices into the local row indices ------------------------------------------------------ */ for ( irow = 0 ; irow < nJ ; irow++ ) { rowindJ[irow] = rowmap[rowindJ[irow]] ; } } /* ------------------------------------------------ initialize bmtx, a SubMtx object to hold b_{J,*} ------------------------------------------------ */ nbytes = SubMtx_nbytesNeeded(frontmtx->type, SUBMTX_DENSE_COLUMNS, nJ, nrhs, nJ*nrhs); BJ = SubMtxManager_newObjectOfSizeNbytes(mtxmanager, nbytes) ; SubMtx_init(BJ, frontmtx->type, SUBMTX_DENSE_COLUMNS, J, 0, nJ, nrhs, nJ*nrhs) ; p_agg[J] = BJ ; if ( BJ == NULL ) { fprintf(stderr, "\n fatal error in load rhs(%d), BJ = NULL", J) ; exit(-1) ; } /* ----------------------- load BJ with b_{J,*} ----------------------- */ rhs = DenseMtx_entries(rhsmtx) ; SubMtx_denseInfo(BJ, &nrowJ, &ncolJ, &inc1, &inc2, &bJ) ; if ( FRONTMTX_IS_REAL(frontmtx) ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( irow = 0 ; irow < nJ ; irow++ ) { kk = rowindJ[irow] ; bJ[irow] = rhs[kk] ; } bJ += nJ ; rhs += nrowInRhs ; } } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( irow = 0 ; irow < nJ ; irow++ ) { kk = rowindJ[irow] ; bJ[2*irow] = rhs[2*kk] ; bJ[2*irow+1] = rhs[2*kk+1] ; } bJ += 2*nJ ; rhs += 2*nrowInRhs ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n rhs for J = %d, BJ = %p", J, BJ) ; fflush(msgFile) ; SubMtx_writeForHumanEye(BJ, msgFile) ; fflush(msgFile) ; } if ( localrhs == 'T' ) { /* ----------------------------------------------------------- map the local row indices back into the global row indices ----------------------------------------------------------- */ for ( irow = 0 ; irow < nJ ; irow++ ) { rowindJ[irow] = rowind[rowindJ[irow]] ; } } } } if ( localrhs == 'T' ) { IVfree(rowmap) ; } return(p_agg) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- visit front J during the forward solve created -- 98mar27, cca -------------------------------------- */ void FrontMtx_forwardVisit ( FrontMtx *frontmtx, int J, int nrhs, int *owners, int myid, SubMtxManager *mtxmanager, SubMtxList *aggList, SubMtx *p_mtx[], char frontIsDone[], IP *heads[], SubMtx *p_agg[], char status[], int msglvl, FILE *msgFile ) { char aggDone, updDone ; SubMtx *BJ, *LJJ, *UJJ ; int nJ ; if ( (nJ = FrontMtx_frontSize(frontmtx, J)) == 0 ) { /* ----------------------------------------------------- front has no eliminated rows or columns, quick return ----------------------------------------------------- */ if ( owners == NULL || owners[J] == myid ) { frontIsDone[J] = 'Y' ; } status[J] = 'F' ; return ; } if ( heads[J] != NULL ) { /* ------------------------------------- there are internal updates to perform ------------------------------------- */ if ( (BJ = p_agg[J]) == NULL ) { /* --------------------------- create the aggregate object --------------------------- */ BJ = p_agg[J] = initBJ(frontmtx->type, J, nJ, nrhs, mtxmanager, msglvl, msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n BJ = %p", BJ) ; fflush(msgFile) ; SubMtx_writeForHumanEye(BJ, msgFile) ; fflush(msgFile) ; } /* --------------------------- compute any waiting updates --------------------------- */ computeForwardUpdates(frontmtx, BJ, J, heads, frontIsDone, p_mtx, msglvl, msgFile) ; } if ( heads[J] == NULL ) { updDone = 'Y' ; } else { updDone = 'N' ; } if ( aggList != NULL && owners[J] == myid ) { /* ----------------------- assemble any aggregates ----------------------- */ aggDone = 'N' ; if ( (BJ = p_agg[J]) == NULL ) { fprintf(stderr, "\n 2. fatal error in forwardVisit(%d), BJ = NULL", J) ; exit(-1) ; } assembleAggregates(J, BJ, aggList, mtxmanager, msglvl, msgFile) ; if ( SubMtxList_isCountZero(aggList, J) == 1 ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n\n aggregate count is zero") ; fflush(msgFile) ; } assembleAggregates(J, BJ, aggList, mtxmanager, msglvl, msgFile) ; aggDone = 'Y' ; } } else { aggDone = 'Y' ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n updDone = %c, aggDone = %c", updDone, aggDone) ; fflush(msgFile) ; } if ( updDone == 'Y' && aggDone == 'Y' ) { BJ = p_agg[J] ; if ( owners == NULL || owners[J] == myid ) { /* ------------------------------------- owned front, ready for interior solve ------------------------------------- */ if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { LJJ = FrontMtx_lowerMtx(frontmtx, J, J) ; if ( LJJ != NULL ) { SubMtx_solve(LJJ, BJ) ; } } else { UJJ = FrontMtx_upperMtx(frontmtx, J, J) ; if ( UJJ != NULL ) { if ( FRONTMTX_IS_SYMMETRIC(frontmtx) ) { SubMtx_solveT(UJJ, BJ) ; } else if ( FRONTMTX_IS_HERMITIAN(frontmtx) ) { SubMtx_solveH(UJJ, BJ) ; } } } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after forward solve") ; SubMtx_writeForHumanEye(BJ, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------ move YJ (stored in BJ) into p_mtx[], signal front as done, and set status to finished ------------------------------------------------ */ p_agg[J] = NULL ; p_mtx[J] = BJ ; frontIsDone[J] = 'Y' ; } else if ( BJ != NULL ) { /* -------------------------------------- unowned front, put into aggregate list -------------------------------------- */ if ( msglvl > 3 ) { fprintf(msgFile, "\n\n putting BJ into aggregate list") ; fflush(msgFile) ; } SubMtxList_addObjectToList(aggList, BJ, J) ; p_agg[J] = NULL ; } status[J] = 'F' ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- visit front J during the diagonal solve created -- 98feb20, cca -------------------------------------------------- */ void FrontMtx_diagonalVisit ( FrontMtx *frontmtx, int J, int owners[], int myid, SubMtx *p_mtx[], char frontIsDone[], SubMtx *p_agg[], int msglvl, FILE *msgFile ) { if ( owners == NULL || owners[J] == myid ) { SubMtx *BJ, *DJJ ; if ( (BJ = p_mtx[J]) != NULL ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n\n BJ = %p", BJ) ; SubMtx_writeForHumanEye(BJ, msgFile) ; fflush(msgFile) ; } DJJ = FrontMtx_diagMtx(frontmtx, J) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n DJJ = %p", DJJ) ; SubMtx_writeForHumanEye(DJJ, msgFile) ; fflush(msgFile) ; } SubMtx_solve(DJJ, BJ) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n b_{%d,*} after diagonal solve", J) ; SubMtx_writeForHumanEye(BJ, msgFile) ; fflush(msgFile) ; } p_mtx[J] = NULL ; p_agg[J] = BJ ; } frontIsDone[J] = 'Y' ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- visit front J during the backward solve created -- 98mar27, cca --------------------------------------- */ void FrontMtx_backwardVisit ( FrontMtx *frontmtx, int J, int nrhs, int *owners, int myid, SubMtxManager *mtxmanager, SubMtxList *aggList, SubMtx *p_mtx[], char frontIsDone[], IP *heads[], SubMtx *p_agg[], char status[], int msglvl, FILE *msgFile ) { char aggDone, updDone ; SubMtx *UJJ, *ZJ ; int nJ ; if ( msglvl > 1 ) { fprintf(msgFile, "\n inside FrontMtx_backwardVisit(%d), nJ = %d", J, FrontMtx_frontSize(frontmtx, J)) ; fflush(msgFile) ; } if ( (nJ = FrontMtx_frontSize(frontmtx, J)) == 0 ) { /* ----------------------------------------------------- front has no eliminated rows or columns, quick return ----------------------------------------------------- */ if ( owners == NULL || owners[J] == myid ) { frontIsDone[J] = 'Y' ; } status[J] = 'F' ; return ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n heads[%d] = %p", J, heads[J]) ; fflush(msgFile) ; } if ( heads[J] != NULL ) { /* ------------------------------------- there are internal updates to perform ------------------------------------- */ if ( (ZJ = p_agg[J]) == NULL ) { /* --------------------------- create the aggregate object --------------------------- */ ZJ = p_agg[J] = initBJ(frontmtx->type, J, nJ, nrhs, mtxmanager, msglvl, msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n ZJ = %p", ZJ) ; SubMtx_writeForHumanEye(ZJ, msgFile) ; fflush(msgFile) ; } /* --------------------------- compute any waiting updates --------------------------- */ computeBackwardUpdates(frontmtx, ZJ, J, heads, frontIsDone, p_mtx, msglvl, msgFile) ; } if ( heads[J] == NULL ) { updDone = 'Y' ; } else { updDone = 'N' ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n updDone = %c", updDone) ; fflush(msgFile) ; } if ( aggList != NULL && owners[J] == myid ) { /* ----------------------- assemble any aggregates ----------------------- */ aggDone = 'N' ; if ( (ZJ = p_agg[J]) == NULL ) { fprintf(stderr, "\n 2. fatal error in backwardVisit(%d), ZJ = NULL", J) ; exit(-1) ; } assembleAggregates(J, ZJ, aggList, mtxmanager, msglvl, msgFile) ; if ( SubMtxList_isCountZero(aggList, J) == 1 ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n\n aggregate count is zero") ; fflush(msgFile) ; } assembleAggregates(J, ZJ, aggList, mtxmanager, msglvl, msgFile) ; aggDone = 'Y' ; } } else { aggDone = 'Y' ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n aggDone = %c", aggDone) ; fflush(msgFile) ; } if ( updDone == 'Y' && aggDone == 'Y' ) { ZJ = p_agg[J] ; if ( owners == NULL || owners[J] == myid ) { /* ------------------------------------- owned front, ready for interior solve ------------------------------------- */ UJJ = FrontMtx_upperMtx(frontmtx, J, J) ; if ( UJJ != NULL ) { SubMtx_solve(UJJ, ZJ) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after backward solve") ; SubMtx_writeForHumanEye(ZJ, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------ move YJ (stored in BJ) into p_mtx[], signal front as done, and set status to finished ------------------------------------------------ */ p_agg[J] = NULL ; p_mtx[J] = ZJ ; frontIsDone[J] = 'Y' ; } else if ( ZJ != NULL ) { /* -------------------------------------- unowned front, put into aggregate list -------------------------------------- */ SubMtxList_addObjectToList(aggList, ZJ, J) ; p_agg[J] = NULL ; } status[J] = 'F' ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n status[%d] = %c", J, status[J]) ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- move the solution from the individual SubMtx objects into the global solution SubMtx object created -- 98feb20 --------------------------------------------------- */ void FrontMtx_storeSolution ( FrontMtx *frontmtx, int owners[], int myid, SubMtxManager *manager, SubMtx *p_mtx[], DenseMtx *solmtx, int msglvl, FILE *msgFile ) { char localsol ; SubMtx *xmtxJ ; double *sol, *xJ ; int inc1, inc2, irow, jrhs, J, kk, ncolJ, neqns, nfront, nJ, nrhs, nrowInSol, nrowJ ; int *colindJ, *colmap, *rowind ; if ( (nrowInSol = solmtx->nrow) != (neqns = frontmtx->neqns) ) { /* -------------------------------------------------------------- the solution matrix is only part of the total solution matrix. (this happens in an MPI environment where the rhs is partitioned among the processors.) create a map from the global row indices to the indices local to this solution matrix. -------------------------------------------------------------- */ colmap = IVinit(neqns, -1) ; rowind = solmtx->rowind ; if ( msglvl > 1 ) { fprintf(msgFile, "\n solmtx->rowind") ; IVfprintf(msgFile, solmtx->nrow, rowind) ; fflush(msgFile) ; } for ( irow = 0 ; irow < nrowInSol ; irow++ ) { colmap[rowind[irow]] = irow ; } localsol = 'T' ; if ( msglvl > 1 ) { fprintf(msgFile, "\n colmap") ; IVfprintf(msgFile, neqns, colmap) ; fflush(msgFile) ; } } else { localsol = 'F' ; } DenseMtx_dimensions(solmtx, &neqns, &nrhs) ; nfront = FrontMtx_nfront(frontmtx) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (owners == NULL || owners[J] == myid) && (nJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; xmtxJ = p_mtx[J] ; if ( xmtxJ == NULL ) { fprintf(stderr, "\n fatal error in storeSolution(%d)" "\n thread %d, xmtxJ = NULL", J, myid) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n storing solution for front %d", J) ; SubMtx_writeForHumanEye(xmtxJ, msgFile) ; fflush(msgFile) ; } if ( localsol == 'T' ) { /* ------------------------------------------------------ map the global row indices into the local row indices ------------------------------------------------------ */ if ( msglvl > 1 ) { fprintf(msgFile, "\n global row indices") ; IVfprintf(msgFile, nJ, colindJ) ; fflush(msgFile) ; } for ( irow = 0 ; irow < nJ ; irow++ ) { colindJ[irow] = colmap[colindJ[irow]] ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n local row indices") ; IVfprintf(msgFile, nJ, colindJ) ; fflush(msgFile) ; } } /* ---------------------------------- store x_{J,*} into solution matrix ---------------------------------- */ sol = DenseMtx_entries(solmtx) ; SubMtx_denseInfo(xmtxJ, &nrowJ, &ncolJ, &inc1, &inc2, &xJ) ; if ( FRONTMTX_IS_REAL(frontmtx) ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( irow = 0 ; irow < nJ ; irow++ ) { kk = colindJ[irow] ; sol[kk] = xJ[irow] ; } sol += neqns ; xJ += nJ ; } } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( irow = 0 ; irow < nJ ; irow++ ) { kk = colindJ[irow] ; sol[2*kk] = xJ[2*irow] ; sol[2*kk+1] = xJ[2*irow+1] ; } sol += 2*neqns ; xJ += 2*nJ ; } } /* fprintf(msgFile, "\n solution for front %d stored", J) ; */ SubMtxManager_releaseObject(manager, xmtxJ) ; if ( localsol == 'T' ) { /* ----------------------------------------------------------- map the local row indices back into the global row indices ----------------------------------------------------------- */ for ( irow = 0 ; irow < nJ ; irow++ ) { colindJ[irow] = rowind[colindJ[irow]] ; } } } } if ( localsol == 'T' ) { IVfree(colmap) ; } /* fprintf(msgFile, "\n\n SOLUTION") ; DenseMtx_writeForHumanEye(solmtx, msgFile) ; */ return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- initialize an aggregate SubMtx object created -- 98mar27, cca ---------------------------------------------- */ static SubMtx * initBJ ( int type, int J, int nJ, int nrhs, SubMtxManager *mtxmanager, int msglvl, FILE *msgFile ) { SubMtx *BJ ; double *entries ; int inc1, inc2, nbytes ; /* ------------------------------------------ B_J not yet allocated (must not be owned), create and zero the entries ------------------------------------------ */ nbytes = SubMtx_nbytesNeeded(type, SUBMTX_DENSE_COLUMNS, nJ, nrhs, nJ*nrhs); BJ = SubMtxManager_newObjectOfSizeNbytes(mtxmanager, nbytes) ; if ( BJ == NULL ) { fprintf(stderr, "\n 1. fatal error in forwardVisit(%d), BJ = NULL", J) ; exit(-1) ; } SubMtx_init(BJ, type, SUBMTX_DENSE_COLUMNS, J, 0, nJ, nrhs, nJ*nrhs) ; SubMtx_denseInfo(BJ, &nJ, &nrhs, &inc1, &inc2, &entries) ; if ( type == SPOOLES_REAL ) { DVzero(nJ*nrhs, entries) ; } else if ( type == SPOOLES_COMPLEX ) { DVzero(2*nJ*nrhs, entries) ; } return(BJ) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ purpose -- compute any updates to BJ created -- 98mar26, cca ------------------------------------ */ static void computeForwardUpdates ( FrontMtx *frontmtx, SubMtx *BJ, int J, IP *heads[], char frontIsDone[], SubMtx *p_mtx[], int msglvl, FILE *msgFile ) { SubMtx *LJI, *UIJ, *YI ; int I ; IP *ip, *nextip ; /* ------------------------------- loop over the remaining updates ------------------------------- */ for ( ip = heads[J], heads[J] = NULL ; ip != NULL ; ip = nextip ) { I = ip->val ; nextip = ip->next ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n frontIsDone[%d] = %c, p_mtx[%d] = %p", I, frontIsDone[I], I, p_mtx[I]) ; fflush(msgFile) ; } if ( frontIsDone[I] == 'Y' ) { if ( (YI = p_mtx[I]) != NULL ) { /* -------------------------------- Y_I exists and has been computed -------------------------------- */ if ( msglvl > 3 ) { fprintf(msgFile, "\n\n before solve: YI = %p", YI) ; SubMtx_writeForHumanEye(YI, msgFile) ; fflush(msgFile) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { if ( (LJI = FrontMtx_lowerMtx(frontmtx, J, I)) != NULL ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n\n LJI = %p", LJI) ; SubMtx_writeForHumanEye(LJI, msgFile) ; fflush(msgFile) ; } SubMtx_solveupd(BJ, LJI, YI) ; } } else { if ( (UIJ = FrontMtx_upperMtx(frontmtx, I, J)) != NULL ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n\n UIJ = %p", UIJ) ; SubMtx_writeForHumanEye(UIJ, msgFile) ; fflush(msgFile) ; } if ( FRONTMTX_IS_SYMMETRIC(frontmtx) ) { SubMtx_solveupdT(BJ, UIJ, YI) ; } else if ( FRONTMTX_IS_HERMITIAN(frontmtx) ) { SubMtx_solveupdH(BJ, UIJ, YI) ; } } } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n after update: BJ = %p", BJ) ; SubMtx_writeForHumanEye(BJ, msgFile) ; fflush(msgFile) ; } } } else { /* ------------------------ Y_I is not yet available ------------------------ */ ip->next = heads[J] ; heads[J] = ip ; } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- assemble any aggregates in the aggregate list created -- 98mar26, cca -------------------------------------------------------- */ static void assembleAggregates ( int J, SubMtx *BJ, SubMtxList *aggList, SubMtxManager *mtxmanager, int msglvl, FILE *msgFile ) { SubMtx *BJhat, *BJhead ; double *entBJ, *entBJhat ; int inc1, inc1hat, inc2, inc2hat, ncol, ncolhat, nrow, nrowhat ; if ( BJ == NULL || aggList == NULL ) { fprintf(stderr, "\n fatal error in assembleAggregates()" "\n BJ = %p, aggList = %p", BJ, aggList) ; exit(-1) ; } if ( SubMtxList_isListNonempty(aggList, BJ->rowid) ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n\n aggregate list is not-empty") ; fflush(msgFile) ; } SubMtx_denseInfo(BJ, &nrow, &ncol, &inc1, &inc2, &entBJ) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n BJ(%d,%d) : nrow %d, ncol %d, inc1 %d, inc2 %d, ent %p", BJ->rowid, BJ->colid, nrow, ncol, inc1, inc2, entBJ) ; fflush(msgFile) ; } BJhead = SubMtxList_getList(aggList, J) ; for ( BJhat = BJhead ; BJhat != NULL ; BJhat = BJhat->next ) { if ( BJhat == NULL ) { fprintf(stderr, "\n 3. fatal error in forwardVisit(%d)" "\n BJhat = NULL", J) ; exit(-1) ; } SubMtx_denseInfo(BJhat, &nrowhat, &ncolhat, &inc1hat, &inc2hat, &entBJhat) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n BJhat(%d,%d) : nrow %d, ncol %d, inc1 %d, inc2 %d, ent %p", BJhat->rowid, BJhat->colid, nrowhat, ncolhat, inc1hat, inc2hat, entBJhat) ; fflush(msgFile) ; } if ( nrow != nrowhat || ncol != ncolhat || inc1 != inc1hat || inc2 != inc2hat || entBJhat == NULL ) { fprintf(stderr, "\n fatal error") ; exit(-1) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n BJ") ; SubMtx_writeForHumanEye(BJ, msgFile) ; fprintf(msgFile, "\n\n BJhat") ; SubMtx_writeForHumanEye(BJhat, msgFile) ; fflush(msgFile) ; } if ( SUBMTX_IS_REAL(BJhat) ) { DVadd(nrow*ncol, entBJ, entBJhat) ; } else if ( SUBMTX_IS_COMPLEX(BJhat) ) { DVadd(2*nrow*ncol, entBJ, entBJhat) ; } } SubMtxManager_releaseListOfObjects(mtxmanager, BJhead) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n BJ after assembly") ; SubMtx_writeForHumanEye(BJ, msgFile) ; fflush(msgFile) ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ purpose -- compute any updates to ZJ created -- 98mar26, cca ------------------------------------ */ static void computeBackwardUpdates ( FrontMtx *frontmtx, SubMtx *ZJ, int J, IP *heads[], char frontIsDone[], SubMtx *p_mtx[], int msglvl, FILE *msgFile ) { SubMtx *UJK, *XK ; int K ; IP *ip, *nextip ; /* ------------------------------- loop over the remaining updates ------------------------------- */ for ( ip = heads[J], heads[J] = NULL ; ip != NULL ; ip = nextip ) { K = ip->val ; nextip = ip->next ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n frontIsDone[%d] = %c", K, frontIsDone[K]) ; fflush(msgFile) ; } if ( frontIsDone[K] == 'Y' ) { if ( (XK = p_mtx[K]) != NULL ) { /* -------------------------------- X_K exists and has been computed -------------------------------- */ if ( msglvl > 3 ) { fprintf(msgFile, "\n\n before solve: XK = %p", XK) ; SubMtx_writeForHumanEye(XK, msgFile) ; fflush(msgFile) ; } if ( (UJK = FrontMtx_upperMtx(frontmtx, J, K)) != NULL ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n\n UJK = %p", UJK) ; SubMtx_writeForHumanEye(UJK, msgFile) ; fflush(msgFile) ; } SubMtx_solveupd(ZJ, UJK, XK) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n after update: ZJ = %p", ZJ) ; SubMtx_writeForHumanEye(ZJ, msgFile) ; fflush(msgFile) ; } } } else { /* ------------------------ X_K is not yet available ------------------------ */ ip->next = heads[J] ; heads[J] = ip ; } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- load the dequeue with the roots of the active subtree used for a backward solve created -- 98mar27, cca --------------------------------------------------- */ void FrontMtx_loadActiveRoots ( FrontMtx *frontmtx, char status[], char activeFlag, Ideq *dequeue ) { int J ; int *sib ; sib = frontmtx->tree->sib ; for ( J = frontmtx->tree->root ; J != -1 ; J = sib[J] ) { if ( status[J] == activeFlag ) { Ideq_insertAtTail(dequeue, J) ; } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- to set up the link data structures for a forward solve return value -- pointer to IP *heads[nfront+2], which contains the beginning of a list of IP objects that store the remaining updates to the fronts. note, heads[nfront] is the first IP object in the free list. heads[nfront+1] is the base address of the allocated IP objects. created -- 98feb20, cca -------------------------------------------------------------------- */ IP ** FrontMtx_forwardSetup ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) { int ii, J, K, nadj, nblock, nfront ; int *adj ; IP *ip ; IP **heads ; /* -------------------------------------------------- set up the update head/links for the forward solve -------------------------------------------------- */ nblock = FrontMtx_nLowerBlocks(frontmtx) ; nfront = FrontMtx_nfront(frontmtx) ; ALLOCATE(heads, struct _IP *, nfront + 2) ; for ( J = 0 ; J <= nfront + 1 ; J++ ) { heads[J] = NULL ; } heads[nfront] = heads[nfront+1] = IP_init(nblock, 1) ; for ( J = 0 ; J < nfront ; J++ ) { FrontMtx_lowerAdjFronts(frontmtx, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { if ( (K = adj[ii]) > J ) { ip = heads[nfront] ; heads[nfront] = ip->next ; ip->val = J ; ip->next = heads[K] ; heads[K] = ip ; if ( msglvl > 3 ) { fprintf(msgFile, "\n linking L(%d,%d) to L(%d,%d)", K, J, K, (ip->next == NULL) ? -1 : ip->next->val) ; fflush(msgFile) ; } } } } return(heads) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- set up the linked lists for the backward solve created -- 98feb20, cca --------------------------------------------------------- */ IP ** FrontMtx_backwardSetup ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) { IP *ip ; IP **heads ; int ii, J, K, nadj, nblock, nfront ; int *adj ; nfront = FrontMtx_nfront(frontmtx) ; nblock = FrontMtx_nLowerBlocks(frontmtx) ; ALLOCATE(heads, struct _IP *, nfront + 2) ; for ( J = 0 ; J <= nfront + 1 ; J++ ) { heads[J] = NULL ; } heads[nfront] = heads[nfront+1] = IP_init(nblock, 1) ; for ( J = 0 ; J < nfront ; J++ ) { FrontMtx_upperAdjFronts(frontmtx, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { if ( (K = adj[ii]) > J ) { if ( heads[nfront] == NULL ) { fprintf(stderr, "\n WHOA, heads[nfront] = %p", heads[nfront]) ; exit(-1) ; } ip = heads[nfront] ; heads[nfront] = ip->next ; ip->val = K ; ip->next = heads[J] ; heads[J] = ip ; if ( msglvl > 3 ) { fprintf(msgFile, "\n linking U(%d,%d) to U(%d,%d)", J, K, J, (ip->next == NULL) ? -1 : ip->next->val) ; fflush(msgFile) ; } } } } return(heads) ; } /*--------------------------------------------------------------------*/ = p_mtx[I]) != NULL ) { /* -------------------------------- Y_I exists and has been computed -------------------------------- */ if ( msglvl > 3 ) { fprintf(msgFile, "\n\n FrontMtx/src/split.c010064400020550007177000000463120664717354700157710ustar00clevecompmath00000400000006/* split.c */ #include "../FrontMtx.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- for each U_{J,bnd{J}} matrix, remove from hash table, split into their U_{J,K} submatrices and insert into the hash table. created -- 98may04, cca ---------------------------------------------------------------- */ void FrontMtx_splitUpperMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) { SubMtx *mtxUJ, *mtxUJJ, *mtxUJK ; SubMtxManager *manager ; double *entUJ, *entUJK ; int count, first, ii, inc1, inc2, jcol, jj, J, K, nbytes, ncolJ, ncolUJ, ncolUJK, nentUJ, nentUJK, neqns, nfront, nJ, nrowUJ, nrowUJK, offset, v ; int *colindJ, *colindUJ, *colindUJK, *colmap, *indicesUJ, *indicesUJK, *locmap, *rowindUJ, *rowindUJK, *sizesUJ, *sizesUJK ; I2Ohash *upperhash ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_splitUpperMatrices(%p,%d,%p)" "\n bad input\n", frontmtx, msglvl, msgFile) ; exit(-1) ; } nfront = FrontMtx_nfront(frontmtx) ; neqns = FrontMtx_neqns(frontmtx) ; upperhash = frontmtx->upperhash ; manager = frontmtx->manager ; /* ----------------------------------- construct the column and local maps ----------------------------------- */ colmap = IVinit(neqns, -1) ; locmap = IVinit(neqns, -1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (nJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; if ( ncolJ > 0 && colindJ != NULL ) { for ( ii = 0 ; ii < nJ ; ii++ ) { v = colindJ[ii] ; colmap[v] = J ; locmap[v] = ii ; } } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n colmap[]") ; IVfprintf(msgFile, neqns, colmap) ; fprintf(msgFile, "\n\n locmap[]") ; IVfprintf(msgFile, neqns, locmap) ; fflush(msgFile) ; } /* --------------------------------------------- move the U_{J,J} matrices into the hash table --------------------------------------------- */ for ( J = 0 ; J < nfront ; J++ ) { if ( (mtxUJJ = FrontMtx_upperMtx(frontmtx, J, J)) != NULL ) { I2Ohash_insert(frontmtx->upperhash, J, J, mtxUJJ) ; } } /* ------------------------------------------------------------ now split the U_{J,bnd{J}} matrices into U_{J,K} matrices. note: columns of U_{J,bnd{J}} are assumed to be in ascending order with respect to the column ordering of the matrix. ------------------------------------------------------------ */ for ( J = 0 ; J < nfront ; J++ ) { mtxUJ = FrontMtx_upperMtx(frontmtx, J, nfront) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ### J = %d, mtxUJ = %p", J, mtxUJ) ; fflush(msgFile) ; } if ( mtxUJ != NULL ) { if ( msglvl > 2 ) { SubMtx_writeForHumanEye(mtxUJ, msgFile) ; fflush(msgFile) ; } SubMtx_columnIndices(mtxUJ, &ncolUJ, &colindUJ) ; SubMtx_rowIndices(mtxUJ, &nrowUJ, &rowindUJ) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n column indices for J") ; IVfprintf(msgFile, ncolUJ, colindUJ) ; fprintf(msgFile, "\n row indices for UJ") ; IVfprintf(msgFile, nrowUJ, rowindUJ) ; fflush(msgFile) ; } if ( (K = colmap[colindUJ[0]]) == colmap[colindUJ[ncolUJ-1]] ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n front %d supports only %d", J, K) ; fflush(msgFile) ; } /* ------------------------------------------------- U_{J,bnd{J}} is one submatrix, bnd{J} \subseteq K set row and column indices and change column id ------------------------------------------------- */ IVramp(nrowUJ, rowindUJ, 0, 1) ; for ( ii = 0 ; ii < ncolUJ ; ii++ ) { colindUJ[ii] = locmap[colindUJ[ii]] ; } SubMtx_setFields(mtxUJ, mtxUJ->type, mtxUJ->mode, J, K, mtxUJ->nrow, mtxUJ->ncol, mtxUJ->nent) ; /* mtxUJ->colid = K ; */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ## inserting U(%d,%d) ", J, K) ; SubMtx_writeForHumanEye(mtxUJ, msgFile) ; fflush(msgFile) ; } I2Ohash_insert(upperhash, J, K, (void *) mtxUJ) ; } else { /* ----------------------------------- split U_{J,bnd{J}} into submatrices ----------------------------------- */ nJ = FrontMtx_frontSize(frontmtx, J) ; if ( SUBMTX_IS_DENSE_COLUMNS(mtxUJ) ) { SubMtx_denseInfo(mtxUJ, &nrowUJ, &ncolUJ, &inc1, &inc2, &entUJ) ; } else if ( SUBMTX_IS_SPARSE_COLUMNS(mtxUJ) ) { SubMtx_sparseColumnsInfo(mtxUJ, &ncolUJ, &nentUJ, &sizesUJ, &indicesUJ, &entUJ) ; offset = 0 ; count = sizesUJ[0] ; } first = 0 ; K = colmap[colindUJ[0]] ; for ( jcol = 1 ; jcol <= ncolUJ ; jcol++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n jcol = %d", jcol) ; if ( jcol < ncolUJ ) { fprintf(msgFile, ", colmap[%d] = %d", colindUJ[jcol], colmap[colindUJ[jcol]]); } fflush(msgFile) ; } if ( jcol == ncolUJ || K != colmap[colindUJ[jcol]] ) { ncolUJK = jcol - first ; if ( SUBMTX_IS_DENSE_COLUMNS(mtxUJ) ) { nentUJK = nJ*ncolUJK ; } else if ( SUBMTX_IS_SPARSE_COLUMNS(mtxUJ) ) { if ( count == 0 ) { goto no_entries ; } nentUJK = count ; } nbytes = SubMtx_nbytesNeeded(mtxUJ->type, mtxUJ->mode, nJ, ncolUJK, nentUJK) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n ncolUJK %d, nentUJK %d, nbytes %d", ncolUJK, nentUJK, nbytes) ; fflush(msgFile) ; } mtxUJK = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtxUJK, mtxUJ->type, mtxUJ->mode, J, K, nJ, ncolUJK, nentUJK) ; if ( SUBMTX_IS_DENSE_COLUMNS(mtxUJ) ) { SubMtx_denseInfo(mtxUJK, &nrowUJK, &ncolUJK, &inc1, &inc2, &entUJK) ; if ( FRONTMTX_IS_REAL(frontmtx) ) { DVcopy(nentUJK, entUJK, entUJ + first*nJ) ; } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { DVcopy(2*nentUJK, entUJK, entUJ + 2*first*nJ) ; } } else if ( SUBMTX_IS_SPARSE_COLUMNS(mtxUJ) ) { SubMtx_sparseColumnsInfo(mtxUJK, &ncolUJK, &nentUJK, &sizesUJK, &indicesUJK, &entUJK) ; IVcopy(ncolUJK, sizesUJK, sizesUJ + first) ; IVcopy(nentUJK, indicesUJK, indicesUJ + offset) ; if ( FRONTMTX_IS_REAL(frontmtx) ) { DVcopy(nentUJK, entUJK, entUJ + offset) ; } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { DVcopy(2*nentUJK, entUJK, entUJ + 2*offset) ; } count = 0 ; offset += nentUJK ; } /* ------------------------------------- initialize the row and column indices ------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n setting row and column indices"); fflush(msgFile) ; } SubMtx_rowIndices(mtxUJK, &nrowUJK, &rowindUJK) ; IVramp(nJ, rowindUJK, 0, 1) ; SubMtx_columnIndices(mtxUJK, &ncolUJK, &colindUJK) ; for ( ii = 0, jj = first ; ii < ncolUJK ; ii++, jj++ ) { colindUJK[ii] = locmap[colindUJ[jj]] ; } /* ---------------------------------- insert U_{J,K} into the hash table ---------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ## inserting U(%d,%d) ", J, K) ; SubMtx_writeForHumanEye(mtxUJK, msgFile) ; fflush(msgFile) ; } I2Ohash_insert(upperhash, J, K, (void *) mtxUJK) ; /* ----------------------------------- we jump to here if there were no entries to be stored in the matrix. ----------------------------------- */ no_entries : /* ---------------------------------------------------- reset first and K to new first location and front id ---------------------------------------------------- */ first = jcol ; if ( jcol < ncolUJ ) { K = colmap[colindUJ[jcol]] ; } } if ( jcol < ncolUJ && SUBMTX_IS_SPARSE_COLUMNS(mtxUJ) ) { count += sizesUJ[jcol] ; } } /* -------------------------------------------- give U_{J,bnd{J}} back to the matrix manager -------------------------------------------- */ SubMtxManager_releaseObject(manager, mtxUJ) ; } } } /* ------------------------ free the working storage ------------------------ */ IVfree(colmap) ; IVfree(locmap) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- for each L_{bnd{J},J} matrix, remove from hash table, split into their L_{K,J} submatrices and insert into the hash table. created -- 98may04, cca ---------------------------------------------------------------- */ void FrontMtx_splitLowerMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) { SubMtx *mtxLJ, *mtxLJJ, *mtxLKJ ; SubMtxManager *manager ; double *entLJ, *entLKJ ; int count, first, ii, inc1, inc2, irow, jj, J, K, nbytes, ncolLJ, ncolLKJ, nentLJ, nentLKJ, neqns, nfront, nJ, nrowJ, nrowLJ, nrowLKJ, offset, v ; int *colindLJ, *colindLKJ, *rowmap, *indicesLJ, *indicesLKJ, *locmap, *rowindJ, *rowindLJ, *rowindLKJ, *sizesLJ, *sizesLKJ ; I2Ohash *lowerhash ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_splitLowerMatrices(%p,%d,%p)" "\n bad input\n", frontmtx, msglvl, msgFile) ; exit(-1) ; } nfront = FrontMtx_nfront(frontmtx) ; neqns = FrontMtx_neqns(frontmtx) ; lowerhash = frontmtx->lowerhash ; manager = frontmtx->manager ; /* -------------------------------- construct the row and local maps -------------------------------- */ rowmap = IVinit(neqns, -1) ; locmap = IVinit(neqns, -1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (nJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { FrontMtx_rowIndices(frontmtx, J, &nrowJ, &rowindJ) ; if ( nrowJ > 0 && rowindJ != NULL ) { for ( ii = 0 ; ii < nJ ; ii++ ) { v = rowindJ[ii] ; rowmap[v] = J ; locmap[v] = ii ; } } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rowmap[]") ; IVfprintf(msgFile, neqns, rowmap) ; fprintf(msgFile, "\n\n locmap[]") ; IVfprintf(msgFile, neqns, locmap) ; fflush(msgFile) ; } /* --------------------------------------------- move the L_{J,J} matrices into the hash table --------------------------------------------- */ for ( J = 0 ; J < nfront ; J++ ) { if ( (mtxLJJ = FrontMtx_lowerMtx(frontmtx, J, J)) != NULL ) { I2Ohash_insert(frontmtx->lowerhash, J, J, mtxLJJ) ; } } /* ------------------------------------------------------------ now split the L_{bnd{J},J} matrices into L_{K,J} matrices. note: columns of L_{bnd{J},J} are assumed to be in ascending order with respect to the column ordering of the matrix. ------------------------------------------------------------ */ for ( J = 0 ; J < nfront ; J++ ) { mtxLJ = FrontMtx_lowerMtx(frontmtx, nfront, J) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ### J = %d, mtxLJ = %p", J, mtxLJ) ; fflush(msgFile) ; } if ( mtxLJ != NULL ) { if ( msglvl > 2 ) { SubMtx_writeForHumanEye(mtxLJ, msgFile) ; fflush(msgFile) ; } SubMtx_columnIndices(mtxLJ, &ncolLJ, &colindLJ) ; SubMtx_rowIndices(mtxLJ, &nrowLJ, &rowindLJ) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n column indices for J") ; IVfprintf(msgFile, ncolLJ, colindLJ) ; fprintf(msgFile, "\n row indices for LJ") ; IVfprintf(msgFile, nrowLJ, rowindLJ) ; fflush(msgFile) ; } if ( (K = rowmap[rowindLJ[0]]) == rowmap[rowindLJ[nrowLJ-1]] ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n front %d supports only %d", J, K) ; fflush(msgFile) ; } /* ------------------------------------------------- L_{bnd{J},J} is one submatrix, bnd{J} \subseteq K set row and column indices and change column id ------------------------------------------------- */ IVramp(ncolLJ, colindLJ, 0, 1) ; for ( ii = 0 ; ii < nrowLJ ; ii++ ) { rowindLJ[ii] = locmap[rowindLJ[ii]] ; } /* mtxLJ->rowid = K ; */ SubMtx_setFields(mtxLJ, mtxLJ->type, mtxLJ->mode, K, J, mtxLJ->nrow, mtxLJ->ncol, mtxLJ->nent) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ## inserting L(%d,%d) ", K, J) ; SubMtx_writeForHumanEye(mtxLJ, msgFile) ; fflush(msgFile) ; } I2Ohash_insert(lowerhash, K, J, (void *) mtxLJ) ; } else { /* ----------------------------------- split L_{bnd{J},J} into submatrices ----------------------------------- */ nJ = FrontMtx_frontSize(frontmtx, J) ; if ( SUBMTX_IS_DENSE_ROWS(mtxLJ) ) { SubMtx_denseInfo(mtxLJ, &nrowLJ, &ncolLJ, &inc1, &inc2, &entLJ) ; } else if ( SUBMTX_IS_SPARSE_ROWS(mtxLJ) ) { SubMtx_sparseRowsInfo(mtxLJ, &nrowLJ, &nentLJ, &sizesLJ, &indicesLJ, &entLJ) ; offset = 0 ; count = sizesLJ[0] ; } first = 0 ; K = rowmap[rowindLJ[0]] ; for ( irow = 1 ; irow <= nrowLJ ; irow++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n irow = %d", irow) ; if ( irow < nrowLJ ) { fprintf(msgFile, ", rowmap[%d] = %d", rowindLJ[irow], rowmap[rowindLJ[irow]]); } fflush(msgFile) ; } if ( irow == nrowLJ || K != rowmap[rowindLJ[irow]] ) { nrowLKJ = irow - first ; if ( SUBMTX_IS_DENSE_ROWS(mtxLJ) ) { nentLKJ = nJ*nrowLKJ ; } else if ( SUBMTX_IS_SPARSE_ROWS(mtxLJ) ) { if ( count == 0 ) { goto no_entries ; } nentLKJ = count ; } nbytes = SubMtx_nbytesNeeded(mtxLJ->type, mtxLJ->mode, nrowLKJ, nJ, nentLKJ) ; mtxLKJ = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtxLKJ, mtxLJ->type, mtxLJ->mode, K, J, nrowLKJ, nJ, nentLKJ) ; if ( SUBMTX_IS_DENSE_ROWS(mtxLJ) ) { SubMtx_denseInfo(mtxLKJ, &nrowLKJ, &ncolLKJ, &inc1, &inc2, &entLKJ) ; if ( FRONTMTX_IS_REAL(frontmtx) ) { DVcopy(nentLKJ, entLKJ, entLJ + first*nJ) ; } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { DVcopy(2*nentLKJ, entLKJ, entLJ + 2*first*nJ) ; } } else if ( SUBMTX_IS_SPARSE_ROWS(mtxLJ) ) { SubMtx_sparseRowsInfo(mtxLKJ, &nrowLKJ, &nentLKJ, &sizesLKJ, &indicesLKJ, &entLKJ) ; IVcopy(nrowLKJ, sizesLKJ, sizesLJ + first) ; IVcopy(nentLKJ, indicesLKJ, indicesLJ + offset) ; if ( FRONTMTX_IS_REAL(frontmtx) ) { DVcopy(nentLKJ, entLKJ, entLJ + offset) ; } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { DVcopy(2*nentLKJ, entLKJ, entLJ + 2*offset) ; } count = 0 ; offset += nentLKJ ; } /* ------------------------------------- initialize the row and column indices ------------------------------------- */ SubMtx_rowIndices(mtxLKJ, &nrowLKJ, &rowindLKJ) ; for ( ii = 0, jj = first ; ii < nrowLKJ ; ii++, jj++ ) { rowindLKJ[ii] = locmap[rowindLJ[jj]] ; } SubMtx_columnIndices(mtxLKJ, &ncolLKJ, &colindLKJ) ; IVramp(ncolLKJ, colindLKJ, 0, 1) ; /* ---------------------------------- insert L_{K,J} into the hash table ---------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ## inserting L(%d,%d) ", K, J) ; SubMtx_writeForHumanEye(mtxLKJ, msgFile) ; fflush(msgFile) ; } I2Ohash_insert(lowerhash, K, J, (void *) mtxLKJ) ; /* ----------------------------------- we jump to here if there were no entries to be stored in the matrix. ----------------------------------- */ no_entries : /* ---------------------------------------------------- reset first and K to new first location and front id ---------------------------------------------------- */ first = irow ; if ( irow < nrowLJ ) { K = rowmap[rowindLJ[irow]] ; } } if ( irow < nrowLJ && SUBMTX_IS_SPARSE_ROWS(mtxLJ) ) { count += sizesLJ[irow] ; } } /* -------------------------------------------- give L_{bnd{J},J} back to the matrix manager -------------------------------------------- */ SubMtxManager_releaseObject(manager, mtxLJ) ; } } } /* ------------------------ free the working storage ------------------------ */ IVfree(rowmap) ; IVfree(locmap) ; return ; } /*--------------------------------------------------------------------*/ if ( jcol < ncolUJ ) { K = colmap[colindUJ[jcol]] ; } } if ( jcol < ncolUJ && SUBMTX_IS_SPARSE_COLUMNS(mtxUJ) ) { count += sizesUJ[jcol] ; } } /* -------------------------------------------- FrontMtx/src/storeFront.c010064400020550007177000000425320662061746400167730ustar00clevecompmath00000400000006/* storeFront.c */ #include "../FrontMtx.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- to store the factor indicies and entries from front J pivotsizesIV -- used for symmetric or hermitian and pivoting droptol -- used for drop tolerance factorization, an entry is stored if its magnitude > droptol created -- 98may04, cca ---------------------------------------------------------------- */ void FrontMtx_storeFront ( FrontMtx *frontmtx, Chv *frontJ, IV *pivotsizesIV, double droptol, int msglvl, FILE *msgFile ) { SubMtx *mtx ; double *entries ; int inc1, inc2, ipivot, irow, jcol, J, m, nbytes, ncol, nD, nent, nfront, nL, npivot, nrow, nU ; int *colind, *colindJ, *firstlocs, *indices, *pivots, *pivotsizes, *rowind, *rowindJ, *sizes ; SubMtxManager *manager ; /* ------------------------------------- extract information from front matrix ------------------------------------- */ nfront = frontmtx->nfront ; manager = frontmtx->manager ; if ( ( FRONTMTX_IS_SYMMETRIC(frontmtx) || FRONTMTX_IS_HERMITIAN(frontmtx) ) && FRONTMTX_IS_PIVOTING(frontmtx) ) { IV_sizeAndEntries(pivotsizesIV, &npivot, &pivotsizes) ; } else { npivot = 0, pivotsizes = NULL ; } /* -------------------------------- extract information from chevron -------------------------------- */ J = frontJ->id ; Chv_dimensions(frontJ, &nD, &nL, &nU) ; Chv_columnIndices(frontJ, &ncol, &colindJ) ; Chv_rowIndices(frontJ, &nrow, &rowindJ) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n inside FrontMtx_storeFront, J = %d", J) ; fflush(msgFile) ; } if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { if ( frontmtx->lock != NULL ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n locking lock") ; fflush(msgFile) ; } Lock_lock(frontmtx->lock) ; frontmtx->nlocks++ ; } /* -------------------- store the front size -------------------- */ FrontMtx_setFrontSize(frontmtx, J, nD) ; /* ------------------------ store the column indices ------------------------ */ if ( msglvl > 2 ) { fprintf(msgFile, "\n setting column indices, J = %d", J) ; fflush(msgFile) ; } IVL_setList(frontmtx->coladjIVL, J, ncol, colindJ) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* --------------------- store the row indices --------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n setting row indices, J = %d", J) ; fflush(msgFile) ; } IVL_setList(frontmtx->rowadjIVL, J, nrow, rowindJ) ; } if ( frontmtx->lock != NULL ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n unlocking lock") ; fflush(msgFile) ; } Lock_unlock(frontmtx->lock) ; } } if ( nD == 0 ) { return ; } /* ------------------------ store the D_{J,J} matrix ------------------------ */ if ( pivotsizes != NULL ) { /* --------------------------------------------------- symmetric and pivoting, store block diagonal matrix --------------------------------------------------- */ nent = Chv_countEntries(frontJ, npivot, pivotsizes, CHV_DIAGONAL) ; nbytes = SubMtx_nbytesNeeded(frontJ->type, SUBMTX_BLOCK_DIAGONAL_SYM, nD, nD, nent) ; mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; if ( FRONTMTX_IS_SYMMETRIC(frontmtx) ) { SubMtx_init(mtx, frontJ->type, SUBMTX_BLOCK_DIAGONAL_SYM, J, J, nD, nD, nent) ; } else if ( FRONTMTX_IS_HERMITIAN(frontmtx) ) { SubMtx_init(mtx, frontJ->type, SUBMTX_BLOCK_DIAGONAL_HERM, J, J, nD, nD, nent) ; } SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivots, &entries) ; IVzero(nD, pivots) ; IVcopy(npivot, pivots, pivotsizes) ; Chv_copyEntriesToVector(frontJ, npivot, pivotsizes, nent, entries, CHV_DIAGONAL, CHV_BY_ROWS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n block diagonal matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } frontmtx->nentD += nent ; } else { /* --------------- diagonal matrix --------------- */ mtx = frontmtx->p_mtxDJJ[J] ; if ( mtx == NULL ) { nbytes = SubMtx_nbytesNeeded(frontJ->type, SUBMTX_DIAGONAL, nD, nD, nD) ; mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, frontJ->type, SUBMTX_DIAGONAL, J, J, nD, nD, nD); } SubMtx_diagonalInfo(mtx, &nent, &entries) ; Chv_copyEntriesToVector(frontJ, npivot, pivotsizes, nent, entries, CHV_DIAGONAL, CHV_BY_ROWS) ; frontmtx->nentD += nD ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n entries in SubMtx") ; DVfprintf(msgFile, nent, entries) ; fprintf(msgFile, "\n\n block diagonal matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } } frontmtx->p_mtxDJJ[J] = mtx ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(ncol, colind, colindJ) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVcopy(nrow, rowind, rowindJ) ; /* ------------------------------ store the upper U_{J,J} matrix ------------------------------ */ if ( FRONTMTX_IS_DENSE_FRONTS(frontmtx) ) { /* ----------- dense front ----------- */ nent = Chv_countEntries(frontJ, npivot, pivotsizes, CHV_STRICT_UPPER_11) ; if ( nent > 0 ) { mtx = frontmtx->p_mtxUJJ[J] ; if ( mtx == NULL ) { nbytes = SubMtx_nbytesNeeded(frontJ->type, SUBMTX_DENSE_SUBCOLUMNS, nD, nD,nent); mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, frontJ->type, SUBMTX_DENSE_SUBCOLUMNS, J, J, nD, nD, nent) ; } SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; if ( pivotsizes != NULL ) { for ( jcol = ipivot = 0 ; jcol < nD ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { firstlocs[jcol] = 0 ; sizes[jcol] = jcol ; jcol++ ; } else if ( m == 2 ) { firstlocs[jcol] = firstlocs[jcol+1] = 0 ; sizes[jcol] = sizes[jcol+1] = jcol ; jcol += 2 ; } } } else { for ( jcol = 0 ; jcol < nD ; jcol++ ) { firstlocs[jcol] = 0 ; sizes[jcol] = jcol ; } } Chv_copyEntriesToVector(frontJ, npivot, pivotsizes, nent, entries, CHV_STRICT_UPPER_11, CHV_BY_COLUMNS) ; frontmtx->p_mtxUJJ[J] = mtx ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(ncol, colind, colindJ) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVcopy(nrow, rowind, rowindJ) ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { frontmtx->nentU += nent ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n UJJ matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } } } else { /* ------------ sparse front ------------ */ nent = Chv_countBigEntries(frontJ, npivot, pivotsizes, CHV_STRICT_UPPER_11, droptol) ; if ( nent > 0 ) { nbytes = SubMtx_nbytesNeeded(frontJ->type, SUBMTX_SPARSE_COLUMNS, nD, nD, nent) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n U_{%d,%d}, nD %d, nent %d, nbytes %d", J, J, nD, nent, nbytes) ; fflush(msgFile) ; } mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, frontJ->type, SUBMTX_SPARSE_COLUMNS, J, J, nD, nD, nent) ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; Chv_copyBigEntriesToVector(frontJ, npivot, pivotsizes, sizes, indices, entries, CHV_STRICT_UPPER_11, CHV_BY_COLUMNS, droptol) ; frontmtx->p_mtxUJJ[J] = mtx ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(ncol, colind, colindJ) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVcopy(nrow, rowind, rowindJ) ; frontmtx->nentU += nent ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n UJJ matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } } } /* ----------------------------------- store the upper U_{J,bnd{J}} matrix ----------------------------------- */ if ( FRONTMTX_IS_DENSE_FRONTS(frontmtx) ) { /* ----------- dense front ----------- */ nent = Chv_countEntries(frontJ, npivot, pivotsizes, CHV_UPPER_12) ; if ( nent > 0 ) { mtx = frontmtx->p_mtxUJN[J] ; if ( mtx == NULL ) { nbytes = SubMtx_nbytesNeeded(frontJ->type, SUBMTX_DENSE_COLUMNS, nD, nU, nent) ; mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, frontJ->type, SUBMTX_DENSE_COLUMNS, J, nfront, nD, nU, nent) ; } SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; Chv_copyEntriesToVector(frontJ, npivot, pivotsizes, nent, entries, CHV_UPPER_12, CHV_BY_COLUMNS) ; frontmtx->p_mtxUJN[J] = mtx ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(ncol, colind, colindJ + nD) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVcopy(nrow, rowind, rowindJ) ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { frontmtx->nentU += nent ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n UJJN matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } } } else { /* ------------ sparse front ------------ */ nent = Chv_countBigEntries(frontJ, npivot, pivotsizes, CHV_UPPER_12, droptol) ; if ( nent > 0 ) { nbytes = SubMtx_nbytesNeeded(frontJ->type, SUBMTX_SPARSE_COLUMNS, nD, nU, nent) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n U_{%d,%d}, nD %d, nU %d, nent %d, nbytes %d", J, nfront, nD, nU, nent, nbytes) ; fflush(msgFile) ; } mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, frontJ->type, SUBMTX_SPARSE_COLUMNS, J, nfront, nD, nU, nent) ; SubMtx_sparseColumnsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; Chv_copyBigEntriesToVector(frontJ, npivot, pivotsizes, sizes, indices, entries, CHV_UPPER_12, CHV_BY_COLUMNS, droptol) ; frontmtx->p_mtxUJN[J] = mtx ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(ncol, colind, colindJ + nD) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVcopy(nrow, rowind, rowindJ) ; frontmtx->nentU += nent ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n UJJN matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } } } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* ------------------------------ store the lower L_{J,J} matrix ------------------------------ */ if ( FRONTMTX_IS_DENSE_FRONTS(frontmtx) ) { /* ----------- dense front ----------- */ nent = Chv_countEntries(frontJ, npivot, pivotsizes, CHV_STRICT_LOWER_11) ; if ( nent > 0 ) { mtx = frontmtx->p_mtxLJJ[J] ; if ( mtx == NULL ) { nbytes = SubMtx_nbytesNeeded(frontJ->type, SUBMTX_DENSE_SUBROWS, nD, nD,nent); mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, frontJ->type, SUBMTX_DENSE_SUBROWS, J, J, nD, nD, nent) ; } SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; for ( irow = 0 ; irow < nD ; irow++ ) { firstlocs[irow] = 0 ; sizes[irow] = irow ; } Chv_copyEntriesToVector(frontJ, npivot, pivotsizes, nent, entries, CHV_STRICT_LOWER_11, CHV_BY_ROWS) ; frontmtx->p_mtxLJJ[J] = mtx ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(ncol, colind, colindJ) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVcopy(nrow, rowind, rowindJ) ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { frontmtx->nentL += nent ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n LJJ matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } } } else { /* ------------ sparse front ------------ */ nent = Chv_countBigEntries(frontJ, npivot, pivotsizes, CHV_STRICT_LOWER_11, droptol); if ( nent > 0 ) { nbytes = SubMtx_nbytesNeeded(frontJ->type, SUBMTX_SPARSE_ROWS, nD, nD, nent) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n L_{%d,%d}, nD %d, nent %d, nbytes %d", J, J, nD, nent, nbytes) ; fflush(msgFile) ; } mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, frontJ->type, SUBMTX_SPARSE_ROWS, J, J, nD, nD, nent) ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries); Chv_copyBigEntriesToVector(frontJ, npivot, pivotsizes, sizes, indices, entries, CHV_STRICT_LOWER_11, CHV_BY_ROWS, droptol) ; frontmtx->p_mtxLJJ[J] = mtx ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(ncol, colind, colindJ) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVcopy(nrow, rowind, rowindJ) ; frontmtx->nentL += nent ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n LJJ matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } } } /* ----------------------------------- store the lower L_{bnd{J},J} matrix ----------------------------------- */ if ( FRONTMTX_IS_DENSE_FRONTS(frontmtx) ) { /* ----------- dense front ----------- */ nent = Chv_countEntries(frontJ, npivot, pivotsizes, CHV_LOWER_21); if ( nent > 0 ) { mtx = frontmtx->p_mtxLNJ[J] ; if ( mtx == NULL ) { nbytes = SubMtx_nbytesNeeded(frontJ->type, SUBMTX_DENSE_ROWS, nL, nD, nent) ; mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, frontJ->type, SUBMTX_DENSE_ROWS, nfront, J, nL, nD, nent) ; } SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; Chv_copyEntriesToVector(frontJ, npivot, pivotsizes, nent, entries, CHV_LOWER_21, CHV_BY_ROWS) ; frontmtx->p_mtxLNJ[J] = mtx ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(ncol, colind, colindJ) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVcopy(nrow, rowind, rowindJ + nD) ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { frontmtx->nentL += nent ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n LNJ matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } } } else { /* ------------ sparse front ------------ */ nent = Chv_countBigEntries(frontJ, npivot, pivotsizes, CHV_LOWER_21, droptol) ; if ( nent > 0 ) { nbytes = SubMtx_nbytesNeeded(frontJ->type, SUBMTX_SPARSE_ROWS, nL, nD, nent) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n L_{%d,%d}, nL %d, nD %d, nent %d, nbytes %d", nfront, J, nL, nD, nent, nbytes) ; fflush(msgFile) ; } mtx = SubMtxManager_newObjectOfSizeNbytes(manager, nbytes) ; SubMtx_init(mtx, frontJ->type, SUBMTX_SPARSE_ROWS, nfront, J, nL, nD, nent) ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; Chv_copyBigEntriesToVector(frontJ, npivot, pivotsizes, sizes, indices, entries, CHV_LOWER_21, CHV_BY_ROWS, droptol) ; frontmtx->p_mtxLNJ[J] = mtx ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVcopy(ncol, colind, colindJ) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVcopy(nrow, rowind, rowindJ + nD) ; frontmtx->nentL += nent ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n LNJ matrix") ; SubMtx_writeForHumanEye(mtx, msgFile) ; fflush(msgFile) ; } } } } return ; } /*--------------------------------------------------------------------*/ wind) ; IVcopy(nrow, rowind, rowindJ) ; frontmtx->nentU += nent ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n UJJ matrix") ; SubMtxFrontMtx/src/update.c010064400020550007177000000070670657126717200161160ustar00clevecompmath00000400000006/* update.c */ #include "../FrontMtx.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ accumulate updates to front J, store them in the Chv object created -- 98may04, cca ------------------------------------------------------------ */ void FrontMtx_update ( FrontMtx *frontmtx, Chv *frontJ, IP *heads[], char status[], DV *tempDV, int msglvl, FILE *msgFile ) { SubMtx *mtxD, *mtxL, *mtxU ; int I, J, nfront ; IP *first, *ip, *last, *nextip ; /* -------------------------------------- loop over the fronts that may update J -------------------------------------- */ if ( msglvl > 3 ) { fprintf(msgFile, "\n\n inside FrontMtx_update(%d)", frontJ->id) ; fflush(stdout) ; } J = frontJ->id ; nfront = frontmtx->nfront ; for ( ip = heads[J], heads[J] = first = last = NULL ; ip != NULL ; ip = nextip ) { nextip = ip->next ; I = ip->val ; if ( status == NULL || status[I] == 'F' ) { mtxD = FrontMtx_diagMtx(frontmtx, I) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n update from I %d, mtxD = %p", I, mtxD) ; fflush(stdout) ; } if ( mtxD != NULL ) { /* ------------------------------------------------- front I did have some rows and columns eliminated ------------------------------------------------- */ mtxU = FrontMtx_upperMtx(frontmtx, I, nfront) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n mtxU = %p", mtxU) ; fflush(stdout) ; } if ( mtxU != NULL ) { /* ------------------------------ the U_{I,bnd{I}} matrix exists ------------------------------ */ if ( FRONTMTX_IS_SYMMETRIC(frontmtx) ) { Chv_updateS(frontJ, mtxD, mtxU, tempDV) ; } else if ( FRONTMTX_IS_HERMITIAN(frontmtx) ) { Chv_updateH(frontJ, mtxD, mtxU, tempDV) ; /* fprintf(msgFile, "\n after update from front %d", mtxD->rowid) ; Chv_writeForHumanEye(frontJ, msgFile) ; */ } else if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { mtxL = FrontMtx_lowerMtx(frontmtx, nfront, I) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n mtxL = %p", mtxL) ; fflush(stdout) ; } if ( mtxL != NULL ) { /* ------------------------------ the L_{bnd{I},I} matrix exists ------------------------------ */ Chv_updateN(frontJ, mtxL, mtxD, mtxU, tempDV) ; } } } } if ( last == NULL ) { last = ip ; } ip->next = first ; first = ip ; if ( msglvl > 3 ) { fprintf(msgFile, "\n update from I %d is finished", I) ; fflush(stdout) ; } } else { ip->next = heads[J] ; heads[J] = ip ; } } /* if ( frontJ->id == frontmtx->nfront - 1 ) { fprintf(msgFile, "\n\n last front after updates made") ; Chv_writeForHumanEye(frontJ, msgFile) ; fflush(msgFile) ; } */ if ( last != NULL ) { /* ------------------------------------ link the IP objects to the free list ------------------------------------ */ last->next = heads[nfront] ; heads[nfront] = first ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n leaving FrontMtx_update(%d)", frontJ->id) ; fflush(stdout) ; } return ; } /*--------------------------------------------------------------------*/ FrontMtx/src/util.c010064400020550007177000000427770661213040700156020ustar00clevecompmath00000400000006/* util.c */ #include "../FrontMtx.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- produce a map from each column to the front that contains it created -- 98may04, cca ----------------------------------------- */ IV * FrontMtx_colmapIV ( FrontMtx *frontmtx ) { int ii, J, ncolJ, neqns, nfront, nJ ; int *colindJ, *colmap ; IV *colmapIV ; /* ----------------------------------------- get the map from columns to owning fronts ----------------------------------------- */ neqns = FrontMtx_neqns(frontmtx) ; nfront = FrontMtx_nfront(frontmtx) ; colmapIV = IV_new() ; IV_init(colmapIV, neqns, NULL) ; colmap = IV_entries(colmapIV) ; IVfill(neqns, colmap, -1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (nJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; if ( ncolJ > 0 && colindJ != NULL ) { for ( ii = 0 ; ii < nJ ; ii++ ) { colmap[colindJ[ii]] = J ; } } } } return(colmapIV) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- produce a map from each row to the front that contains it created -- 98may04, cca -------------------------------------------------------------------- */ IV * FrontMtx_rowmapIV ( FrontMtx *frontmtx ) { int ii, J, nrowJ, neqns, nfront, nJ ; int *rowindJ, *rowmap ; IV *rowmapIV ; /* -------------------------------------- get the map from rows to owning fronts -------------------------------------- */ neqns = FrontMtx_neqns(frontmtx) ; nfront = FrontMtx_nfront(frontmtx) ; rowmapIV = IV_new() ; IV_init(rowmapIV, neqns, NULL) ; rowmap = IV_entries(rowmapIV) ; IVfill(neqns, rowmap, -1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( (nJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { FrontMtx_rowIndices(frontmtx, J, &nrowJ, &rowindJ) ; if ( nrowJ > 0 && rowindJ != NULL ) { for ( ii = 0 ; ii < nJ ; ii++ ) { rowmap[rowindJ[ii]] = J ; } } } } return(rowmapIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- compute the inertia of a symmetric matrix fill *pnnegative with the number of negative eigenvalues of A fill *pnzero with the number of zero eigenvalues of A fill *pnpositive with the number of positive eigenvalues of A created -- 98may04, cca ------------------------------------------------------------- */ void FrontMtx_inertia ( FrontMtx *frontmtx, int *pnnegative, int *pnzero, int *pnpositive ) { SubMtx *mtx ; double arm, areal, bimag, breal, creal, mid, val ; double *entries ; int ii, ipivot, irow, J, nent, nfront, nJ, nnegative, npositive, nzero ; int *pivotsizes ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || pnnegative == NULL || pnzero == NULL || pnpositive == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_inertia(%p,%p,%p,%p)" "\n bad input\n", frontmtx, pnnegative, pnzero, pnpositive) ; fflush(stdout) ; } if ( FRONTMTX_IS_REAL(frontmtx) && ! FRONTMTX_IS_SYMMETRIC(frontmtx) ) { fprintf(stderr, "\n fatal error in FrontMtx_inertia(%p,%p,%p,%p)" "\n matrix is real and not symmetric \n", frontmtx, pnnegative, pnzero, pnpositive) ; fflush(stdout) ; } else if ( FRONTMTX_IS_COMPLEX(frontmtx) && ! FRONTMTX_IS_HERMITIAN(frontmtx) ) { fprintf(stderr, "\n fatal error in FrontMtx_inertia(%p,%p,%p,%p)" "\n matrix is complex and not hermitian \n", frontmtx, pnnegative, pnzero, pnpositive) ; fflush(stdout) ; } nfront = frontmtx->nfront ; nnegative = nzero = npositive = 0 ; for ( J = 0 ; J < nfront ; J++ ) { mtx = FrontMtx_diagMtx(frontmtx, J) ; if ( mtx != NULL ) { if ( ! FRONTMTX_IS_PIVOTING(frontmtx) ) { /* ----------- no pivoting ----------- */ SubMtx_diagonalInfo(mtx, &nJ, &entries) ; if ( FRONTMTX_IS_REAL(frontmtx) ) { for ( ii = 0 ; ii < nJ ; ii++ ) { if ( entries[ii] < 0.0 ) { nnegative++ ; } else if ( entries[ii] > 0.0 ) { npositive++ ; } else { nzero++ ; } } } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { for ( ii = 0 ; ii < nJ ; ii++ ) { if ( entries[2*ii] < 0.0 ) { nnegative++ ; } else if ( entries[2*ii] > 0.0 ) { npositive++ ; } else { nzero++ ; } } } } else { /* -------- pivoting -------- */ SubMtx_blockDiagonalInfo(mtx, &nJ, &nent, &pivotsizes, &entries) ; if ( FRONTMTX_IS_REAL(frontmtx) ) { for ( irow = ipivot = ii = 0 ; irow < nJ ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { val = entries[ii] ; if ( val < 0.0 ) { nnegative++ ; } else if ( val > 0.0 ) { npositive++ ; } else { nzero++ ; } irow++ ; ii++ ; } else { areal = entries[ii] ; breal = entries[ii+1] ; creal = entries[ii+2] ; mid = 0.5*(areal + creal) ; arm = sqrt(0.25*(areal - creal)*(areal - creal) + breal*breal) ; val = mid + arm ; if ( val < 0.0 ) { nnegative++ ; } else if ( val > 0.0 ) { npositive++ ; } else { nzero++ ; } val = mid - arm ; if ( val < 0.0 ) { nnegative++ ; } else if ( val > 0.0 ) { npositive++ ; } else { nzero++ ; } irow += 2 ; ii += 3 ; } } } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { for ( irow = ipivot = ii = 0 ; irow < nJ ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { val = entries[2*ii] ; if ( val < 0.0 ) { nnegative++ ; } else if ( val > 0.0 ) { npositive++ ; } else { nzero++ ; } irow++ ; ii++ ; } else { areal = entries[2*ii] ; breal = entries[2*ii+2] ; bimag = entries[2*ii+3] ; creal = entries[2*ii+4] ; mid = 0.5*(areal + creal) ; arm = sqrt(0.25*(areal - creal)*(areal - creal) + breal*breal + bimag*bimag) ; val = mid + arm ; if ( val < 0.0 ) { nnegative++ ; } else if ( val > 0.0 ) { npositive++ ; } else { nzero++ ; } val = mid - arm ; if ( val < 0.0 ) { nnegative++ ; } else if ( val > 0.0 ) { npositive++ ; } else { nzero++ ; } irow += 2 ; ii += 3 ; } } } } } } *pnnegative = nnegative ; *pnzero = nzero ; *pnpositive = npositive ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- create and return an IV object that contains all the row ids owned by process myid. created -- 98jun13, cca ------------------------------------------------------- */ IV * FrontMtx_ownedRowsIV ( FrontMtx *frontmtx, int myid, IV *ownersIV, int msglvl, FILE *msgFile ) { int J, neqns, nfront, nJ, nowned, nrowJ, offset ; int *ownedRows, *owners, *rowindJ ; IV *ownedRowsIV ; /* --------------- check the input --------------- */ if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_ownedRowsIV(%p,%d,%p)" "\n bad input\n", frontmtx, myid, ownersIV) ; exit(-1) ; } nfront = frontmtx->nfront ; neqns = frontmtx->neqns ; ownedRowsIV = IV_new() ; if ( ownersIV == NULL ) { IV_init(ownedRowsIV, neqns, NULL) ; IV_ramp(ownedRowsIV, 0, 1) ; } else { owners = IV_entries(ownersIV) ; for ( J = 0, nowned = 0 ; J < nfront ; J++ ) { if ( owners[J] == myid ) { nJ = FrontMtx_frontSize(frontmtx, J) ; nowned += nJ ; } } if ( nowned > 0 ) { IV_init(ownedRowsIV, nowned, NULL) ; ownedRows = IV_entries(ownedRowsIV) ; for ( J = 0, offset = 0 ; J < nfront ; J++ ) { if ( owners[J] == myid ) { nJ = FrontMtx_frontSize(frontmtx, J) ; if ( nJ > 0 ) { FrontMtx_rowIndices(frontmtx, J, &nrowJ, &rowindJ) ; IVcopy(nJ, ownedRows + offset, rowindJ) ; offset += nJ ; } } } } } return(ownedRowsIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- create and return an IV object that contains all the column ids owned by process myid. created -- 98jun13, cca ------------------------------------------------------- */ IV * FrontMtx_ownedColumnsIV ( FrontMtx *frontmtx, int myid, IV *ownersIV, int msglvl, FILE *msgFile ) { int J, neqns, nfront, nJ, nowned, ncolJ, offset ; int *ownedColumns, *owners, *colindJ ; IV *ownedColumnsIV ; /* --------------- check the input --------------- */ if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_ownedColumnsIV(%p,%d,%p)" "\n bad input\n", frontmtx, myid, ownersIV) ; exit(-1) ; } nfront = frontmtx->nfront ; neqns = frontmtx->neqns ; ownedColumnsIV = IV_new() ; if ( ownersIV == NULL ) { IV_init(ownedColumnsIV, neqns, NULL) ; IV_ramp(ownedColumnsIV, 0, 1) ; } else { owners = IV_entries(ownersIV) ; for ( J = 0, nowned = 0 ; J < nfront ; J++ ) { if ( owners[J] == myid ) { nJ = FrontMtx_frontSize(frontmtx, J) ; nowned += nJ ; } } if ( nowned > 0 ) { IV_init(ownedColumnsIV, nowned, NULL) ; ownedColumns = IV_entries(ownedColumnsIV) ; for ( J = 0, offset = 0 ; J < nfront ; J++ ) { if ( owners[J] == myid ) { nJ = FrontMtx_frontSize(frontmtx, J) ; if ( nJ > 0 ) { FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; IVcopy(nJ, ownedColumns + offset, colindJ) ; offset += nJ ; } } } } } return(ownedColumnsIV) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- to create and return an IVL object that holds the submatrix nonzero pattern for the upper triangular factor. NOTE: this method supercedes calling IVL_mapEntries() on the column adjacency structure. that gave problems when pivoting forced some fronts to have no eliminated columns. in some cases, solve aggregates were expected when none were forthcoming. created -- 98aug20, cca ---------------------------------------------------------------- */ IVL * FrontMtx_makeUpperBlockIVL ( FrontMtx *frontmtx, IV *colmapIV ) { int count, ii, J, K, ncol, nfront, nJ ; int *colmap, *colind, *list, *mark ; IVL *upperblockIVL ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || colmapIV == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_makeUpperBlockIVL()" "\n bad input\n") ; exit(-1) ; } nfront = FrontMtx_nfront(frontmtx) ; colmap = IV_entries(colmapIV) ; /* ----------------------------- set up the working storage and initialize the IVL object ----------------------------- */ mark = IVinit(nfront, -1) ; list = IVinit(nfront, -1) ; upperblockIVL = IVL_new() ; IVL_init1(upperblockIVL, IVL_CHUNKED, nfront) ; /* ------------------- fill the IVL object ------------------- */ for ( J = 0 ; J < nfront ; J++ ) { if ( (nJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { FrontMtx_columnIndices(frontmtx, J, &ncol, &colind) ; if ( ncol > 0 ) { mark[J] = J ; count = 0 ; list[count++] = J ; for ( ii = nJ ; ii < ncol ; ii++ ) { K = colmap[colind[ii]] ; if ( mark[K] != J ) { mark[K] = J ; list[count++] = K ; } } IVL_setList(upperblockIVL, J, count, list) ; } } } /* ------------------------ free the working storage ------------------------ */ IVfree(mark) ; IVfree(list) ; return(upperblockIVL) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- to create and return an IVL object that holds the submatrix nonzero pattern for the lower triangular factor. NOTE: this method supercedes calling IVL_mapEntries() on the row adjacency structure. that gave problems when pivoting forced some fronts to have no eliminated columns. in some cases, solve aggregates were expected when none were forthcoming. created -- 98aug20, cca ---------------------------------------------------------------- */ IVL * FrontMtx_makeLowerBlockIVL ( FrontMtx *frontmtx, IV *rowmapIV ) { int count, ii, J, K, nrow, nfront, nJ ; int *rowmap, *rowind, *list, *mark ; IVL *lowerblockIVL ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || rowmapIV == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_makeLowerBlockIVL()" "\n bad input\n") ; exit(-1) ; } nfront = FrontMtx_nfront(frontmtx) ; rowmap = IV_entries(rowmapIV) ; /* ----------------------------- set up the working storage and initialize the IVL object ----------------------------- */ mark = IVinit(nfront, -1) ; list = IVinit(nfront, -1) ; lowerblockIVL = IVL_new() ; IVL_init1(lowerblockIVL, IVL_CHUNKED, nfront) ; /* ------------------- fill the IVL object ------------------- */ for ( J = 0 ; J < nfront ; J++ ) { if ( (nJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { FrontMtx_rowIndices(frontmtx, J, &nrow, &rowind) ; if ( nrow > 0 ) { mark[J] = J ; count = 0 ; list[count++] = J ; for ( ii = nJ ; ii < nrow ; ii++ ) { K = rowmap[rowind[ii]] ; if ( mark[K] != J ) { mark[K] = J ; list[count++] = K ; } } IVL_setList(lowerblockIVL, J, count, list) ; } } } /* ------------------------ free the working storage ------------------------ */ IVfree(mark) ; IVfree(list) ; return(lowerblockIVL) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to compute and return the number of floating point operations to perform a solve with a single right hand side. created -- 98sep26, cca --------------------------------------------------------------- */ int FrontMtx_nSolveOps ( FrontMtx *frontmtx ) { int nsolveops ; /* --------------- check the input --------------- */ if ( frontmtx == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_nSolveOps()" "\n frontmtx is NULL\n") ; exit(-1) ; } switch ( frontmtx->type ) { case SPOOLES_REAL : switch ( frontmtx->symmetryflag ) { case SPOOLES_SYMMETRIC : nsolveops = 4*frontmtx->nentU + frontmtx->nentD ; break ; case SPOOLES_NONSYMMETRIC : nsolveops = 2*frontmtx->nentL + frontmtx->nentD + 2*frontmtx->nentU ; break ; default : fprintf(stderr, "\n fatal error in FrontMtx_nSolveOps()" "\n real type, invalid symmetryflag %d\n", frontmtx->symmetryflag) ; exit(-1) ; break ; } break ; case SPOOLES_COMPLEX : switch ( frontmtx->symmetryflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : nsolveops = 16*frontmtx->nentU + 8*frontmtx->nentD ; break ; case SPOOLES_NONSYMMETRIC : nsolveops = 8*frontmtx->nentL + 8*frontmtx->nentD + 8*frontmtx->nentU ; break ; default : fprintf(stderr, "\n fatal error in FrontMtx_nSolveOps()" "\n complex type, invalid symmetryflag %d\n", frontmtx->symmetryflag) ; exit(-1) ; break ; } break ; default : fprintf(stderr, "\n fatal error in FrontMtx_nSolveOps()" "\n invalid type %d\n", frontmtx->type) ; exit(-1) ; break ; } return(nsolveops) ; } /*--------------------------------------------------------------------*/ FrontMtx/drivers/do_QRgrid010075500020550007177000000005170657354126400171470ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res set msgFile = stdout set n1 = 7 set n2 = 7 set n3 = 7 set seed = 10101 set nrhs = 4 set type = 1 foreach n ( 7 ) set n1 = $n set n2 = $n set n3 = 1 set n3 = $n echo $n1 x $n2 x $n3 grid testQRgrid \ $msglvl $msgFile $n1 $n2 $n3 $seed $nrhs $type end FrontMtx/drivers/do_factor010075500020550007177000000021640663303461200172240ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res3D.64 set msgFile = /local1/ARPA/junk/res.grid set msgFile = res.grid set msgFile = res set msgFile = stdout set mtxFile = ../../../matrices/R2D100/orig.inpmtxb set etreeFile = ../../../matrices/R2D100/nd.etreef set mtxFile = ../../../matrices/R3D13824/orig.inpmtxb set etreeFile = ../../../matrices/R3D13824/nd.0.100000.etreef # set mtxFile = ../../../matrices/R10KV/orig.inpmtxb # set etreeFile = ../../../matrices/R10KV/best0.etreef # set mtxFile = ../../../matrices/R2D100/orig.inpmtxb # set etreeFile = ../../../matrices/R2D100/nd.etreef # set mtxFile = /local1/ARPA/matrices/SFTC$n/SFTC1.inpmtxb # set etreeFile = /local1/ARPA/matrices/SFTC$n/best0.etreef set seed = 10101 set symmetryflag = 0 set sparsityflag = 0 set pivotingflag = 0 set tau = 100 set droptol = 1.e-50 set lookahead = 0 set nrhs = 4 testFactor $msglvl $msgFile $mtxFile $etreeFile \ $seed $symmetryflag $sparsityflag $pivotingflag\ $tau $droptol $lookahead $nrhs FrontMtx/drivers/do_grid010075500020550007177000000025510662060366700167030ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res3D.64 set msgFile = res set msgFile = /local1/ARPA/junk/res.grid set msgFile = res.grid set msgFile = stdout set n1 = 7 set n2 = 7 set n3 = 1 set maxzeros = 1000 set maxzeros = 500 set maxzeros = 250 set maxzeros = 750 set maxzeros = 0 set maxsize = 1000 set maxsize = 64 set seed = 10101 set type = 1 set symmetryflag = 0 set sparsityflag = 0 set pivotingflag = 0 set tau = 5 set droptol = 1.e-50 set lookahead = 0 set nrhs = 4 foreach nrhs ( 1 ) # foreach nrhs ( 1 2 3 4 5 6 8 16 ) echo ' nrhs ' $nrhs # foreach n1 ( 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 ) # foreach maxzeros ( 400 800 1600 ) # foreach maxsize ( 16 32 48 64 80 ) # set msgFile = res3D.$maxsize.$maxzeros echo $maxzeros $maxsize # foreach n1 ( 5 7 9 11 13 15 17 19 21 23 25 27 29 31 ) # set n2 = $n1 # set n3 = $n1 # foreach sparsityflag ( 0 1 ) # foreach pivotingflag ( 0 1 ) # foreach symmetryflag ( 0 2 ) echo $n1 $n2 $n3 testGrid $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize \ $seed $type $symmetryflag $sparsityflag $pivotingflag\ $tau $droptol $lookahead $nrhs # end # end # end # end # end # end end FrontMtx/drivers/makefile010064400020550007177000000012210665314245100170320ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testGrid testQRgrid testFactor drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testQRgrid : testQRgrid.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o \ -o $@ ${LIBS} ${THREAD_LIBS} testGrid : testGrid.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o \ -o $@ ${LIBS} ${THREAD_LIBS} testFactor : testFactor.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o \ -o $@ ${LIBS} ${THREAD_LIBS} FrontMtx/drivers/testFactor.c010064400020550007177000000443260663234502600176310ustar00clevecompmath00000400000006/* testFactor.c */ #include "../FrontMtx.h" #include "../../Drand.h" #include "../../SymbFac.h" #include "../../timings.h" #include "../../misc.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------------- test the factor method for a grid matrix (1) read in an InpMtx object (2) read in an ETree object (3) create a solution matrix object (4) multiply the solution with the matrix to get a right hand side matrix object (5) factor the matrix (6) solve the system created -- 98sep05, cca ----------------------------------------------------- */ { char *etreeFileName, *mtxFileName ; Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxB, *mtxX, *mtxZ ; double one[2] = { 1.0, 0.0 } ; FrontMtx *frontmtx ; InpMtx *mtxA ; SubMtxManager *mtxmanager ; double cputotal, droptol, factorops ; double cpus[9] ; Drand drand ; double nops, tau, t1, t2 ; ETree *frontETree ; FILE *msgFile ; int error, loc, lockflag, msglvl, neqns, nrhs, nzf, pivotingflag, rc, seed, sparsityflag, symmetryflag, type ; int stats[6] ; IV *newToOldIV, *oldToNewIV ; IVL *symbfacIVL ; if ( argc != 13 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile mtxFile etreeFile" "\n seed symmetryflag sparsityflag " "\n pivotingflag tau droptol lockflag nrhs" "\n msglvl -- message level" "\n msgFile -- message file" "\n mtxFile -- file to read in InpMtx matrix object" "\n etreeFile -- file to read in ETree front tree object" "\n seed -- random number seed" "\n symmetryflag -- symmetry flag" "\n 0 --> symmetric " "\n 1 --> hermitian" "\n 2 --> nonsymmetric" "\n sparsityflag -- sparsity flag" "\n 0 --> store dense fronts" "\n 1 --> store sparse fronts, use droptol to drop entries" "\n pivotingflag -- pivoting flag" "\n 0 --> do not pivot" "\n 1 --> enable pivoting" "\n tau -- upper bound on factor entries" "\n used only with pivoting" "\n droptol -- lower bound on factor entries" "\n used only with sparse fronts" "\n lockflag -- flag to specify lock status" "\n 0 --> mutex lock is not allocated or initialized" "\n 1 --> mutex lock is allocated and it can synchronize" "\n only threads in this process." "\n 2 --> mutex lock is allocated and it can synchronize" "\n only threads in this and other processes." "\n nrhs -- # of right hand sides" "\n", argv[0]) ; return(-1) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } mtxFileName = argv[3] ; etreeFileName = argv[4] ; seed = atoi(argv[5]) ; symmetryflag = atoi(argv[6]) ; sparsityflag = atoi(argv[7]) ; pivotingflag = atoi(argv[8]) ; tau = atof(argv[9]) ; droptol = atof(argv[10]) ; lockflag = atoi(argv[11]) ; nrhs = atoi(argv[12]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n mtxFileName -- %s" "\n etreeFileName -- %s" "\n seed -- %d" "\n symmetryflag -- %d" "\n sparsityflag -- %d" "\n pivotingflag -- %d" "\n tau -- %e" "\n droptol -- %e" "\n lockflag -- %d" "\n nrhs -- %d" "\n", argv[0], msglvl, argv[2], mtxFileName, etreeFileName, seed, symmetryflag, sparsityflag, pivotingflag, tau, droptol, lockflag, nrhs) ; fflush(msgFile) ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ Drand_setDefaultFields(&drand) ; Drand_init(&drand) ; Drand_setSeed(&drand, seed) ; /* Drand_setUniform(&drand, 0.0, 1.0) ; */ Drand_setNormal(&drand, 0.0, 1.0) ; /* ------------------------- read in the InpMtx object ------------------------- */ if ( strcmp(mtxFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } mtxA = InpMtx_new() ; MARKTIME(t1) ; rc = InpMtx_readFromFile(mtxA, mtxFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in mtxA from file %s", t2 - t1, mtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from InpMtx_readFromFile(%p,%s)", rc, mtxA, mtxFileName) ; exit(-1) ; } type = mtxA->inputMode ; neqns = 1 + IVmax(mtxA->nent, InpMtx_ivec1(mtxA), &loc) ; if ( INPMTX_IS_BY_ROWS(mtxA) ) { fprintf(msgFile, "\n matrix coordinate type is rows") ; } else if ( INPMTX_IS_BY_COLUMNS(mtxA) ) { fprintf(msgFile, "\n matrix coordinate type is columns") ; } else if ( INPMTX_IS_BY_CHEVRONS(mtxA) ) { fprintf(msgFile, "\n matrix coordinate type is chevrons") ; } else { fprintf(msgFile, "\n\n, error, bad coordinate type") ; exit(-1) ; } if ( INPMTX_IS_RAW_DATA(mtxA) ) { fprintf(msgFile, "\n matrix storage mode is raw data\n") ; } else if ( INPMTX_IS_SORTED(mtxA) ) { fprintf(msgFile, "\n matrix storage mode is sorted\n") ; } else if ( INPMTX_IS_BY_VECTORS(mtxA) ) { fprintf(msgFile, "\n matrix storage mode is by vectors\n") ; } else { fprintf(msgFile, "\n\n, error, bad storage mode") ; exit(-1) ; } { int maxcol, maxrow, mincol, minrow ; InpMtx_range(mtxA, &mincol, &maxcol, &minrow, &maxrow) ; fprintf(msgFile, "\n range of entries = [%d, %d] x [%d,%d]", minrow, maxrow, mincol, maxcol) ; } /* { int nent = InpMtx_nent(mtxA) ; double *dvec = InpMtx_dvec(mtxA) ; Drand *drand ; drand = Drand_new() ; Drand_setUniform(drand, 0., 1.) ; Drand_fillDvector(drand, nent, dvec) ; } */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after reading InpMtx object from file %s", mtxFileName) ; if ( msglvl == 2 ) { InpMtx_writeStats(mtxA, msgFile) ; } else { InpMtx_writeForHumanEye(mtxA, msgFile) ; } fflush(msgFile) ; } /* -------------------------------------------------------- generate the linear system 1. generate solution matrix and fill with random numbers 2. generate rhs matrix and fill with zeros 3. compute matrix-matrix multiply -------------------------------------------------------- */ MARKTIME(t1) ; mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, -1, neqns, nrhs, 1, neqns) ; DenseMtx_fillRandomEntries(mtxX, &drand) ; mtxB = DenseMtx_new() ; DenseMtx_init(mtxB, type, 1, -1, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxB) ; fprintf(msgFile, "\n B and X initialized") ; fflush(msgFile) ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_mmm(mtxA, mtxB, one, mtxX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_mmm(mtxA, mtxB, one, mtxX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_mmm(mtxA, mtxB, one, mtxX) ; break ; default : break ; } fprintf(msgFile, "\n mvm done") ; fflush(msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set up the solution and rhs ", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n original mtxX") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fprintf(msgFile, "\n\n original mtxB") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } DenseMtx_writeToFile(mtxB, "rhs.densemtxb") ; /* InpMtx_writeForMatlab(mtxA, "A", msgFile) ; DenseMtx_writeForMatlab(mtxX, "X", msgFile) ; DenseMtx_writeForMatlab(mtxB, "B", msgFile) ; */ /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(etreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } frontETree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(frontETree, etreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in frontETree from file %s", t2 - t1, etreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, frontETree, etreeFileName) ; exit(-1) ; } ETree_leftJustify(frontETree) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after reading ETree object from file %s", etreeFileName) ; if ( msglvl == 2 ) { ETree_writeStats(frontETree, msgFile) ; } else { ETree_writeForHumanEye(frontETree, msgFile) ; } } fflush(msgFile) ; /* -------------------------------------------------- get the permutations, permute the matrix and the front tree, and compute the symbolic factorization -------------------------------------------------- */ MARKTIME(t1) ; oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get permutations", t2 - t1) ; MARKTIME(t1) ; ETree_permuteVertices(frontETree, oldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute front tree", t2 - t1) ; MARKTIME(t1) ; InpMtx_permute(mtxA, IV_entries(oldToNewIV), IV_entries(oldToNewIV)) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute mtxA", t2 - t1) ; if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { MARKTIME(t1) ; InpMtx_mapToUpperTriangle(mtxA) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : map to upper triangle", t2 - t1) ; } if ( ! INPMTX_IS_BY_CHEVRONS(mtxA) ) { MARKTIME(t1) ; InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : change coordinate type", t2 - t1) ; } if ( INPMTX_IS_RAW_DATA(mtxA) ) { MARKTIME(t1) ; InpMtx_changeStorageMode(mtxA, INPMTX_SORTED) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : sort entries ", t2 - t1) ; } if ( INPMTX_IS_SORTED(mtxA) ) { MARKTIME(t1) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : convert to vectors ", t2 - t1) ; } MARKTIME(t1) ; symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : symbolic factorization", t2 - t1) ; MARKTIME(t1) ; DenseMtx_permuteRows(mtxB, oldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute rhs", t2 - t1) ; /* DenseMtx_writeForMatlab(mtxB, "Bhat", msgFile) ; */ /* ------------------------------ initialize the FrontMtx object ------------------------------ */ MARKTIME(t1) ; frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, lockflag, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, sparsityflag, pivotingflag, lockflag, 0, NULL, mtxmanager, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : initialize the front matrix", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n nendD = %d, nentL = %d, nentU = %d", frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n front matrix initialized") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; /* ----------------- factor the matrix ----------------- */ nzf = ETree_nFactorEntries(frontETree, symmetryflag) ; factorops = ETree_nFactorOps(frontETree, type, symmetryflag) ; fprintf(msgFile, "\n %d factor entries, %.0f factor ops, %8.3f ratio", nzf, factorops, factorops/nzf) ; IVzero(6, stats) ; DVzero(9, cpus) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, lockflag, 1) ; MARKTIME(t1) ; rootchv = FrontMtx_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, &error, cpus, stats, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : factor matrix, %8.3f mflops", t2 - t1, 1.e-6*factorops/(t2-t1)) ; if ( rootchv != NULL ) { fprintf(msgFile, "\n\n factorization did not complete") ; for ( chv = rootchv ; chv != NULL ; chv = chv->next ) { fprintf(stdout, "\n chv %d, nD = %d, nL = %d, nU = %d", chv->id, chv->nD, chv->nL, chv->nU) ; } } if ( error >= 0 ) { fprintf(msgFile, "\n\n error encountered at front %d\n", error) ; exit(-1) ; } fprintf(msgFile, "\n %8d pivots, %8d pivot tests, %8d delayed rows and columns", stats[0], stats[1], stats[2]) ; if ( frontmtx->rowadjIVL != NULL ) { fprintf(msgFile, "\n %d entries in rowadjIVL", frontmtx->rowadjIVL->tsize) ; } if ( frontmtx->coladjIVL != NULL ) { fprintf(msgFile, ", %d entries in coladjIVL", frontmtx->coladjIVL->tsize) ; } if ( frontmtx->upperblockIVL != NULL ) { fprintf(msgFile, "\n %d fronts, %d entries in upperblockIVL", frontmtx->nfront, frontmtx->upperblockIVL->tsize) ; } if ( frontmtx->lowerblockIVL != NULL ) { fprintf(msgFile, ", %d entries in lowerblockIVL", frontmtx->lowerblockIVL->tsize) ; } fprintf(msgFile, "\n %d entries in D, %d entries in L, %d entries in U", stats[3], stats[4], stats[5]) ; fprintf(msgFile, "\n %d locks", frontmtx->nlocks) ; if ( FRONTMTX_IS_SYMMETRIC(frontmtx) || FRONTMTX_IS_HERMITIAN(frontmtx) ) { int nneg, npos, nzero ; FrontMtx_inertia(frontmtx, &nneg, &nzero, &npos) ; fprintf(msgFile, "\n %d negative, %d zero and %d positive eigenvalues", nneg, nzero, npos) ; fflush(msgFile) ; } cputotal = cpus[8] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n initialize fronts %8.3f %6.2f" "\n load original entries %8.3f %6.2f" "\n update fronts %8.3f %6.2f" "\n assemble postponed data %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n extract postponed data %8.3f %6.2f" "\n store factor entries %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[6], 100.*cpus[6]/cputotal, cpus[7], 100.*cpus[7]/cputotal, cputotal) ; } SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; ChvManager_writeForHumanEye(chvmanager, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } /* fprintf(msgFile, "\n L = eye(%d,%d) ;", neqns, neqns) ; fprintf(msgFile, "\n U = eye(%d,%d) ;", neqns, neqns) ; fprintf(msgFile, "\n D = zeros(%d,%d) ;", neqns, neqns) ; FrontMtx_writeForMatlab(frontmtx, "L", "D", "U", msgFile) ; */ /* ------------------------------ post-process the factor matrix ------------------------------ */ MARKTIME(t1) ; FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : post-process the matrix", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } fprintf(msgFile, "\n\n after post-processing") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ---------------- solve the system ---------------- */ neqns = mtxB->nrow ; nrhs = mtxB->ncol ; mtxZ = DenseMtx_new() ; DenseMtx_init(mtxZ, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxZ) ; if ( type == SPOOLES_REAL ) { nops = frontmtx->nentD + 2*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 2*frontmtx->nentL ; } else { nops += 2*frontmtx->nentU ; } } else if ( type == SPOOLES_COMPLEX ) { nops = 8*frontmtx->nentD + 8*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 8*frontmtx->nentL ; } else { nops += 8*frontmtx->nentU ; } } nops *= nrhs ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DVzero(6, cpus) ; MARKTIME(t1) ; FrontMtx_solve(frontmtx, mtxZ, mtxB, mtxmanager, cpus, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : solve the system, %.3f mflops", t2 - t1, 1.e-6*nops/(t2 - t1)) ; cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } /* DenseMtx_writeForMatlab(mtxZ, "Xhat", msgFile) ; */ /* ------------------------------------------------------------- permute the computed solution back into the original ordering ------------------------------------------------------------- */ MARKTIME(t1) ; DenseMtx_permuteRows(mtxZ, newToOldIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute solution", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } /* ----------------- compute the error ----------------- */ DenseMtx_sub(mtxZ, mtxX) ; fprintf(msgFile, "\n\n maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n after solve") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ------------------------ free the working storage ------------------------ */ IV_free(oldToNewIV) ; IV_free(newToOldIV) ; InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxB) ; DenseMtx_free(mtxZ) ; FrontMtx_free(frontmtx) ; ETree_free(frontETree) ; IVL_free(symbfacIVL) ; ChvManager_free(chvmanager) ; SubMtxManager_free(mtxmanager) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ETree_leftJustify(frontETree) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after reading ETree object from file %s", etreeFileName) ; if ( msglvl == 2 ) { ETree_writeStats(frontETree, msgFile) ; } else { ETree_writeForHumanEye(frontETree, msgFile) ; } } fflush(msFrontMtx/drivers/testGrid.c010064400020550007177000000344560665014722500173040ustar00clevecompmath00000400000006/* testGrid.c */ #include "../FrontMtx.h" #include "../../Drand.h" #include "../../SymbFac.h" #include "../../timings.h" #include "../../misc.h" /*--------------------------------------------------------------------*/ void mkNDlinsys ( int n1, int n2, int n3, int maxzeros, int maxsize, int type, int symmetryflag, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB ) ; /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------------- test the factor method for a grid matrix (1) construct a linear system for a nested dissection ordering on a regular grid (2) create a solution matrix object (3) multiply the solution with the matrix to get a right hand side matrix object (4) factor the matrix (5) solve the system created -- 98may16, cca ----------------------------------------------------- */ { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxB, *mtxX, *mtxZ ; FrontMtx *frontmtx ; InpMtx *mtxA ; SubMtxManager *mtxmanager ; double cputotal, droptol, factorops ; double cpus[9] ; Drand drand ; double nops, tau, t1, t2 ; ETree *frontETree ; FILE *msgFile ; int error, lockflag, maxsize, maxzeros, msglvl, neqns, n1, n2, n3, nrhs, nzf, pivotingflag, seed, sparsityflag, symmetryflag, type ; int stats[6] ; IVL *symbfacIVL ; if ( argc != 17 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 maxzeros maxsize" "\n seed type symmetryflag sparsityflag " "\n pivotingflag tau droptol lockflag nrhs" "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- number of grid points in the first direction" "\n n2 -- number of grid points in the second direction" "\n n3 -- number of grid points in the third direction" "\n maxzeros -- max number of zeroes in a front" "\n maxsize -- max number of internal nodes in a front" "\n seed -- random number seed" "\n type -- type of entries" "\n 1 --> real" "\n 2 --> complex" "\n symmetryflag -- symmetry flag" "\n 0 --> symmetric " "\n 1 --> hermitian" "\n 2 --> nonsymmetric" "\n sparsityflag -- sparsity flag" "\n 0 --> store dense fronts" "\n 1 --> store sparse fronts, use droptol to drop entries" "\n pivotingflag -- pivoting flag" "\n 0 --> do not pivot" "\n 1 --> enable pivoting" "\n tau -- upper bound on factor entries" "\n used only with pivoting" "\n droptol -- lower bound on factor entries" "\n used only with sparse fronts" "\n lockflag -- flag to specify lock status" "\n 0 --> mutex lock is not allocated or initialized" "\n 1 --> mutex lock is allocated and it can synchronize" "\n only threads in this process." "\n 2 --> mutex lock is allocated and it can synchronize" "\n only threads in this and other processes." "\n nrhs -- # of right hand sides" "\n", argv[0]) ; return(-1) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; n3 = atoi(argv[5]) ; maxzeros = atoi(argv[6]) ; maxsize = atoi(argv[7]) ; seed = atoi(argv[8]) ; type = atoi(argv[9]) ; symmetryflag = atoi(argv[10]) ; sparsityflag = atoi(argv[11]) ; pivotingflag = atoi(argv[12]) ; tau = atof(argv[13]) ; droptol = atof(argv[14]) ; lockflag = atoi(argv[15]) ; nrhs = atoi(argv[16]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n n1 -- %d" "\n n2 -- %d" "\n n3 -- %d" "\n maxzeros -- %d" "\n maxsize -- %d" "\n seed -- %d" "\n type -- %d" "\n symmetryflag -- %d" "\n sparsityflag -- %d" "\n pivotingflag -- %d" "\n tau -- %e" "\n droptol -- %e" "\n lockflag -- %d" "\n nrhs -- %d" "\n", argv[0], msglvl, argv[2], n1, n2, n3, maxzeros, maxsize, seed, type, symmetryflag, sparsityflag, pivotingflag, tau, droptol, lockflag, nrhs) ; fflush(msgFile) ; neqns = n1 * n2 * n3 ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ Drand_setDefaultFields(&drand) ; Drand_init(&drand) ; Drand_setSeed(&drand, seed) ; /* Drand_setUniform(&drand, 0.0, 1.0) ; */ Drand_setNormal(&drand, 0.0, 1.0) ; /* -------------------------- generate the linear system -------------------------- */ mkNDlinsys(n1, n2, n3, maxzeros, maxsize, type, symmetryflag, nrhs, seed, msglvl, msgFile, &frontETree, &symbfacIVL, &mtxA, &mtxX, &mtxB) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n mtxA") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fprintf(msgFile, "\n mtxX") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fprintf(msgFile, "\n mtxB") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } /* fprintf(msgFile, "\n neqns = %d ;", n1*n2*n3) ; fprintf(msgFile, "\n nrhs = %d ;", nrhs) ; fprintf(msgFile, "\n A = zeros(neqns, neqns) ;") ; fprintf(msgFile, "\n X = zeros(neqns, nrhs) ;") ; fprintf(msgFile, "\n B = zeros(neqns, nrhs) ;") ; InpMtx_writeForMatlab(mtxA, "A", msgFile) ; DenseMtx_writeForMatlab(mtxX, "X", msgFile) ; DenseMtx_writeForMatlab(mtxB, "B", msgFile) ; { int *ivec1 = InpMtx_ivec1(mtxA) ; int *ivec2 = InpMtx_ivec2(mtxA) ; double *dvec = InpMtx_dvec(mtxA) ; int ichv, ii, col, offset, row, nent = InpMtx_nent(mtxA) ; fprintf(msgFile, "\n coordType = %d", mtxA->coordType) ; fprintf(msgFile, "\n start of matrix output file") ; fprintf(msgFile, "\n %d %d %d", n1*n2*n3, n1*n2*n3, nent) ; for ( ii = 0 ; ii < nent ; ii++ ) { ichv = ivec1[ii] ; if ( (offset = ivec2[ii]) >= 0 ) { row = ichv, col = row + offset ; } else { col = ichv, row = col - offset ; } fprintf(msgFile, "\n %d %d %24.16e %24.16e", row, col, dvec[2*ii], dvec[2*ii+1]) ; } } { int ii, jj ; double imag, real ; fprintf(msgFile, "\n start of rhs output file") ; fprintf(msgFile, "\n %d %d", n1*n2*n3, nrhs) ; for ( ii = 0 ; ii < n1*n2*n3 ; ii++ ) { fprintf(msgFile, "\n %d ", ii) ; for ( jj = 0 ; jj < nrhs ; jj++ ) { DenseMtx_complexEntry(mtxB, ii, jj, &real, &imag) ; fprintf(msgFile, " %24.16e %24.16e", real, imag) ; } } } */ /* ------------------------------ initialize the FrontMtx object ------------------------------ */ MARKTIME(t1) ; frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, lockflag, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, sparsityflag, pivotingflag, lockflag, 0, NULL, mtxmanager, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : initialize the front matrix", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n nendD = %d, nentL = %d, nentU = %d", frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n front matrix initialized") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; /* ----------------- factor the matrix ----------------- */ nzf = ETree_nFactorEntries(frontETree, symmetryflag) ; factorops = ETree_nFactorOps(frontETree, type, symmetryflag) ; fprintf(msgFile, "\n %d factor entries, %.0f factor ops, %8.3f ratio", nzf, factorops, factorops/nzf) ; IVzero(6, stats) ; DVzero(9, cpus) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, lockflag, 1) ; MARKTIME(t1) ; rootchv = FrontMtx_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, &error, cpus, stats, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : factor matrix, %8.3f mflops", t2 - t1, 1.e-6*factorops/(t2-t1)) ; if ( rootchv != NULL ) { fprintf(msgFile, "\n\n factorization did not complete") ; for ( chv = rootchv ; chv != NULL ; chv = chv->next ) { fprintf(stdout, "\n chv %d, nD = %d, nL = %d, nU = %d", chv->id, chv->nD, chv->nL, chv->nU) ; } } if ( error >= 0 ) { fprintf(msgFile, "\n\n error encountered at front %d\n", error) ; exit(-1) ; } fprintf(msgFile, "\n %8d pivots, %8d pivot tests, %8d delayed rows and columns", stats[0], stats[1], stats[2]) ; if ( frontmtx->rowadjIVL != NULL ) { fprintf(msgFile, "\n %d entries in rowadjIVL", frontmtx->rowadjIVL->tsize) ; } if ( frontmtx->coladjIVL != NULL ) { fprintf(msgFile, ", %d entries in coladjIVL", frontmtx->coladjIVL->tsize) ; } if ( frontmtx->upperblockIVL != NULL ) { fprintf(msgFile, "\n %d fronts, %d entries in upperblockIVL", frontmtx->nfront, frontmtx->upperblockIVL->tsize) ; } if ( frontmtx->lowerblockIVL != NULL ) { fprintf(msgFile, ", %d entries in lowerblockIVL", frontmtx->lowerblockIVL->tsize) ; } fprintf(msgFile, "\n %d entries in D, %d entries in L, %d entries in U", stats[3], stats[4], stats[5]) ; fprintf(msgFile, "\n %d locks", frontmtx->nlocks) ; cputotal = cpus[8] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n initialize fronts %8.3f %6.2f" "\n load original entries %8.3f %6.2f" "\n update fronts %8.3f %6.2f" "\n assemble postponed data %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n extract postponed data %8.3f %6.2f" "\n store factor entries %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[6], 100.*cpus[6]/cputotal, cpus[7], 100.*cpus[7]/cputotal, cputotal) ; } SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; ChvManager_writeForHumanEye(chvmanager, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n %% MATLAB file: front factor matrix") ; FrontMtx_writeForMatlab(frontmtx, "L", "D", "U", msgFile) ; } /* ------------------------------ post-process the factor matrix ------------------------------ */ MARKTIME(t1) ; FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : post-process the matrix", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } fprintf(msgFile, "\n\n after post-processing") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* code to test out the IO methods. write the matrix to a file, free it, then read it back in. note: formatted files do not have much accuracy. */ /* FrontMtx_writeToFile(frontmtx, "temp.frontmtxb") ; FrontMtx_free(frontmtx) ; frontmtx = FrontMtx_new() ; FrontMtx_readFromFile(frontmtx, "temp.frontmtxb") ; frontmtx->manager = mtxmanager ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; */ /* ---------------- solve the system ---------------- */ neqns = mtxB->nrow ; nrhs = mtxB->ncol ; mtxZ = DenseMtx_new() ; DenseMtx_init(mtxZ, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxZ) ; if ( type == SPOOLES_REAL ) { nops = frontmtx->nentD + 2*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 2*frontmtx->nentL ; } else { nops += 2*frontmtx->nentU ; } } else if ( type == SPOOLES_COMPLEX ) { nops = 8*frontmtx->nentD + 8*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 8*frontmtx->nentL ; } else { nops += 8*frontmtx->nentU ; } } nops *= nrhs ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DVzero(6, cpus) ; MARKTIME(t1) ; FrontMtx_solve(frontmtx, mtxZ, mtxB, mtxmanager, cpus, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : solve the system, %.3f mflops", t2 - t1, 1.e-6*nops/(t2 - t1)) ; cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } /* fprintf(msgFile, "\n Z = zeros(neqns, nrhs) ;") ; DenseMtx_writeForMatlab(mtxZ, "Z", msgFile) ; */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } DenseMtx_sub(mtxZ, mtxX) ; fprintf(msgFile, "\n\n maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n after solve") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ------------------------ free the working storage ------------------------ */ InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxB) ; DenseMtx_free(mtxZ) ; FrontMtx_free(frontmtx) ; ETree_free(frontETree) ; IVL_free(symbfacIVL) ; ChvManager_free(chvmanager) ; SubMtxManager_free(mtxmanager) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ d" "\n symmetryflag -- %d" "\n sparsityflag -- %d" "\n pivotingflag -- %d" "\n tau -- %e" "\n droptol -- %e" "\n lockflag -- %d" FrontMtx/drivers/testQRgrid.c010064400020550007177000000200420657126717400176010ustar00clevecompmath00000400000006/* testQRgrid.c */ #include "../FrontMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ void mkNDlinsysQR ( int n1, int n2, int n3, int type, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB) ; /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- test the QR factor method for a FrontMtx object on an n1 x n2 x n3 grid (1) generate an overdetermined system AX = B (2) factor the matrix (3) solve the systems created -- 97apr11, dkw modified -- 98may28, cca --------------------------------------------------- */ { ChvManager *chvmanager ; DenseMtx *mtxB, *mtxX, *mtxZ ; double cputotal, factorops ; double cpus[9] ; double nops, t1, t2 ; ETree *frontETree ; FILE *msgFile ; FrontMtx *frontmtx ; InpMtx *mtxA ; int msglvl, neqns, nrhs, n1, n2, n3, seed, type ; IVL *symbfacIVL ; SubMtxManager *mtxmanager ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 seed nrhs " "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- # of points in the first direction" "\n n2 -- # of points in the second direction" "\n n3 -- # of points in the third direction" "\n seed -- random number seed" "\n nrhs -- # of right hand sides" "\n type -- type of linear system" "\n 1 -- real" "\n 2 -- complex" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; n3 = atoi(argv[5]) ; seed = atoi(argv[6]) ; nrhs = atoi(argv[7]) ; type = atoi(argv[8]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n n1 -- %d" "\n n2 -- %d" "\n n3 -- %d" "\n seed -- %d" "\n nrhs -- %d" "\n type -- %d" "\n", argv[0], msglvl, argv[2], n1, n2, n3, seed, nrhs, type) ; fflush(msgFile) ; neqns = n1*n2*n3 ; if ( type != SPOOLES_REAL && type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error, type must be real or complex") ; exit(-1) ; } /* ------------------------------------------ generate the A X = B overdetermined system ------------------------------------------ */ mkNDlinsysQR(n1, n2, n3, type, nrhs, seed, msglvl, msgFile, &frontETree, &symbfacIVL, &mtxA, &mtxX, &mtxB) ; /* ------------------------------ initialize the FrontMtx object ------------------------------ */ MARKTIME(t1) ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; frontmtx = FrontMtx_new() ; if ( type == SPOOLES_REAL ) { FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, SPOOLES_SYMMETRIC, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; } else if ( type == SPOOLES_COMPLEX ) { FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, SPOOLES_HERMITIAN, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : FrontMtx initialized", t2 - t1) ; fflush(msgFile) ; /* ----------------- factor the matrix ----------------- */ DVzero(6, cpus) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 0) ; factorops = 0.0 ; MARKTIME(t1) ; FrontMtx_QR_factor(frontmtx, mtxA, chvmanager, cpus, &factorops, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n after QR_factor() call, facops = %8.2f",factorops) ; fprintf(msgFile, "\n CPU %8.3f : FrontMtx_QR_factor, %8.3f mflops", t2 - t1, 1.e-6*factorops/(t2-t1)) ; cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n" "\n setup factorization %8.3f %6.2f" "\n setup fronts %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n store factor %8.3f %6.2f" "\n store update %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cputotal) ; } /* ------------------------------ post-process the factor matrix ------------------------------ */ MARKTIME(t1) ; FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : post-process the matrix", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } fprintf(msgFile, "\n\n after post-processing") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ---------------- solve the system ---------------- */ mtxZ = DenseMtx_new() ; DenseMtx_init(mtxZ, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxZ) ; if ( type == SPOOLES_REAL ) { nops = frontmtx->nentD + 2*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 2*frontmtx->nentL ; } else { nops += 2*frontmtx->nentU ; } } else if ( type == SPOOLES_COMPLEX ) { nops = 8*frontmtx->nentD + 8*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 8*frontmtx->nentL ; } else { nops += 8*frontmtx->nentU ; } } nops *= nrhs ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DVzero(6, cpus) ; MARKTIME(t1) ; FrontMtx_QR_solve(frontmtx, mtxA, mtxZ, mtxB, mtxmanager, cpus, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : solve the system, %.3f mflops", t2 - t1, 1.e-6*nops/(t2 - t1)) ; cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n CPU %%" "\n A^TB matrix-matrix multiply %8.3f %6.2f" "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total solve time %8.3f %6.2f" "\n total QR solve time %8.3f", cpus[6], 100.*cpus[6]/cputotal, cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cputotal) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } /* ----------------- compute the error ----------------- */ DenseMtx_sub(mtxZ, mtxX) ; fprintf(msgFile, "\n\n maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n after solve") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ------------------------ free the working storage ------------------------ */ InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxZ) ; DenseMtx_free(mtxB) ; FrontMtx_free(frontmtx) ; IVL_free(symbfacIVL) ; ETree_free(frontETree) ; SubMtxManager_free(mtxmanager) ; ChvManager_free(chvmanager) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ /FrontMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ void mkNDlinsysQR ( int n1, int n2, int n3, int type, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB) ; /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------FrontMtx/doc/004275500020550007177000000000000665023215700144325ustar00clevecompmath00000400000006FrontMtx/doc/dataStructure.tex010064400020550007177000000131400657206574500200120ustar00clevecompmath00000400000006\par \section{Data Structures} \label{section:FrontMtx:dataStructure} \par The {\tt FrontMtx} structure has the following fields. \begin{itemize} \item {\tt int nfront} : number of fronts. \item {\tt int neqns} : number of rows and columns in the factor matrix. \item {\tt int symmetryflag} : flag to denote the type of symmetry of $A + \sigma B$. \begin{itemize} \item {\tt SPOOLES\_SYMMETRIC} --- $A$ and/or $B$ are symmetric. \item {\tt SPOOLES\_HERMITIAN} --- $A$ and/or $B$ are hermitian. \item {\tt SPOOLES\_NONSYMMETRIC} --- $A$ and/or $B$ are nonsymmetric. \end{itemize} \item {\tt int pivotingflag} : flag to specify pivoting for stability, \begin{itemize} \item {\tt SPOOLES\_NO\_PIVOTING} --- pivoting not used \item {\tt SPOOLES\_PIVOTING} --- pivoting used \end{itemize} \item {\tt int sparsityflag} : flag to specify storage of factors. \begin{itemize} \item {\tt 0} --- each front is dense \item {\tt 1} --- a front may be sparse due to entries dropped because they are below a drop tolerance. \end{itemize} \item {\tt int dataMode} : flag to specify data storage. \begin{itemize} \item {\tt 1} --- one-dimensional, used during the factorization. \item {\tt 2} --- two-dimensional, used during the solves. \end{itemize} \item {\tt int nentD} : number of entries in $D$ \item {\tt int nentL} : number of entries in $L$ \item {\tt int nentU} : number of entries in $U$ \item {\tt Tree *tree} : Tree object that holds the tree of fronts. Note, normally this is {\tt frontETree->tree}, but we leave this here for later enhancements where we change the tree after the factorization, e.g., merge/drop fronts. \item {\tt ETree *frontETree} : elimination tree object that holds the front tree. \item {\tt IVL *symbfacIVL} : {\tt IVL} object that holds the symbolic factorization. \item {\tt IV *frontsizesIV} : {\tt IV} object that holds the vector of front sizes, i.e., the number of internal rows and columns in a front. \item {\tt IVL *rowadjIVL} : {\tt IVL} object that holds the row list for the fronts, used only for a nonsymmetric factorization with pivoting enabled. \item {\tt IVL *coladjIVL} : {\tt IVL} object that holds the column list for the fronts, used only for a symmetric or nonsymmetric factorization with pivoting enabled. \item {\tt IVL *lowerblockIVL} : {\tt IVL} object that holds the front-to-front coupling in $L$, used only for a nonsymmetric factorization. \item {\tt IVL *upperblockIVL} : {\tt IVL} object that holds the front-to-front coupling in $U$. \item {\tt SubMtx **p\_mtxDJJ} : a vector of pointers to diagonal submatrices. \item {\tt SubMtx **p\_mtxUJJ} : a vector of pointers to submatrices in U that are on the block diagonal, used only during the factorization. \item {\tt SubMtx **p\_mtxUJN} : a vector of pointers to submatrices in U that are off the block diagonal, used only during the factorization. \item {\tt SubMtx **p\_mtxLJJ} : a vector of pointers to submatrices in L that are on the block diagonal, used only during a nonsymmetric factorization. \item {\tt SubMtx **p\_mtxLNJ} : a vector of pointers to submatrices in L that are off the block diagonal, used only during a nonsymmetric factorization. \item {\tt I2Ohash *lowerhash} : pointer to a {\tt I2Ohash} hash table for submatrices in $L$, used during the solves. \item {\tt I2Ohash *upperhash} : pointer to a {\tt I2Ohash} hash table for submatrices in $U$, used during the solves. \item {\tt SubMtxManager *manager} : pointer to an object that manages the instances of submatrices during the factors and solves. \item {\tt Lock *lock} : pointer to a {\tt Lock} lock used in a multithreaded environment to ensure exlusive access while allocating storage in the {\tt IV} and {\tt IVL} objects. This is not used in a serial or MPI environment. \item {\tt int nlocks} : number of times the lock has been locked. \item {\tt PatchAndGo *info} : this is a pointer to an object that is used by the {\tt Chv} object during the factorization of a front. \end{itemize} \par One can query the properties of the front matrix object using these simple macros. \begin{itemize} \item {\tt FRONTMTX\_IS\_REAL(frontmtx)} is {\tt 1} if {\tt frontmtx} has real entries and {\tt 0} otherwise. \item {\tt FRONTMTX\_IS\_COMPLEX(frontmtx)} is {\tt 1} if {\tt frontmtx} has complex entries and {\tt 0} otherwise. \item {\tt FRONTMTX\_IS\_SYMMETRIC(frontmtx)} is {\tt 1} if {\tt frontmtx} comes from a symmetric matrix or linear combination of symmetric matrices, and {\tt 0} otherwise. \item {\tt FRONTMTX\_IS\_HERMITIAN(frontmtx)} is {\tt 1} if {\tt frontmtx} comes from a Hermitian matrix or linear combination of Hermitian matrices, and {\tt 0} otherwise. \item {\tt FRONTMTX\_IS\_NONSYMMETRIC(frontmtx)} is {\tt 1} if {\tt frontmtx} comes from a nonsymmetric matrix or linear combination of nonsymmetric matrices, and {\tt 0} otherwise. \item {\tt FRONTMTX\_IS\_DENSE\_FRONTS(frontmtx)} is {\tt 1} if {\tt frontmtx} comes from a direct factorization and so stores dense submatrices, and {\tt 0} otherwise. \item {\tt FRONTMTX\_IS\_SPARSE\_FRONTS(frontmtx)} is {\tt 1} if {\tt frontmtx} comes from an approximate factorization and so stores sparse submatrices, and {\tt 0} otherwise. \item {\tt FRONTMTX\_IS\_PIVOTING(frontmtx)} is {\tt 1} if pivoting was used during the factorization, and {\tt 0} otherwise. \item {\tt FRONTMTX\_IS\_1D\_MODE(frontmtx)} is {\tt 1} if the factor are still stored as a one-dimensional data decomposition (i.e., the matrix has not yet been post-processed), and {\tt 0} otherwise. \item {\tt FRONTMTX\_IS\_2D\_MODE(frontmtx)} is {\tt 1} if the factor are stored as a two-dimensional data decomposition (i.e., the matrix has been post-processed), and {\tt 0} otherwise. \end{itemize} FrontMtx/doc/drivers.tex010064400020550007177000000115570657126717300166460ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt DFrontMtx} object} \label{section:DFrontMtx:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testGrid msglvl msgFile n1 n2 n3 maxzeros maxsize seed type symmetryflag sparsityflag pivotingflag tau droptol lockflag nrhs \end{verbatim} This driver program tests the serial {\tt FrontMtx\_factor()} and {\tt FrontMtx\_solve()} methods for the linear system $AX = B$. Use the script file {\tt do\_grid} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt n1} is the number of points in the first grid direction. \item {\tt n2} is the number of points in the second grid direction. \item {\tt n3} is the number of points in the third grid direction. \item {\tt maxzeros} is used to merge small fronts together into larger fronts. Look at the {\tt ETree} object for the {\tt ETree\_mergeFronts\{One,All,Any\}()} methods. \item {\tt maxsize} is used to split large fronts into smaller fronts. See the {\tt ETree\_splitFronts()} method. \item The {\tt seed} parameter is a random number seed. \item The {\tt type} parameter specifies a real or complex linear system. \begin{itemize} \item {\tt type = 1 (SPOOLES\_REAL)} for real, \item {\tt type = 2 (SPOOLES\_COMPLEX)} for complex. \end{itemize} \item The {\tt symmetryflag} parameter specifies the symmetry of the matrix. \begin{itemize} \item {\tt type = 0 (SPOOLES\_SYMMETRIC)} for $A$ real or complex symmetric, \item {\tt type = 1 (SPOOLES\_HERMITIAN)} for $A$ complex Hermitian, \item {\tt type = 2 (SPOOLES\_NONSYMMETRIC)} \end{itemize} for $A$ real or complex nonsymmetric. \item The {\tt sparsityflag} parameter signals a direct or approximate factorization. \begin{itemize} \item {\tt sparsityflag = 0 (FRONTMTX\_DENSE\_FRONTS)} implies a direct factorization, the fronts will be stored as dense submatrices. \item {\tt sparsityflag = 1 (FRONTMTX\_SPARSE\_FRONTS)} implies an approximate factorization. The fronts will be stored as sparse submatrices, where the entries in the triangular factors will be subjected to a drop tolerance test --- if the magnitude of an entry is {\tt droptol} or larger, it will be stored, otherwise it will be dropped. \end{itemize} \item The {\tt pivotingflag} parameter signals whether pivoting for stability will be enabled or not. \begin{itemize} \item If {\tt pivotingflag = 0 (SPOOLES\_NO\_PIVOTING)}, no pivoting will be done. \item If {\tt pivotingflag = 1 (SPOOLES\_PIVOTING)}, pivoting will be done to ensure that all entries in $U$ and $L$ have magnitude less than {\tt tau}. \end{itemize} \item The {\tt tau} parameter is an upper bound on the magnitude of the entries in $L$ and $U$ when pivoting is enabled. \item The {\tt droptol} parameter is a lower bound on the magnitude of the entries in $L$ and $U$ when the approximate factorization is enabled. \item When {\tt lockflag} is zero, the mutual exclusion lock for the factor matrix is not enabled. When {\tt lockflag} is not zero, the mutual exclusion lock is set. This capability is here to test the overhead for the locks for a serial factorization. \item The {\tt nrhs} parameter is the number of right hand sides to solve as one block. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testQRgrid msglvl msgFile n1 n2 n3 seed nrhs type \end{verbatim} This driver program tests the serial {\tt FrontMtx\_QR\_factor()} and {\tt FrontMtx\_QR\_solve()} methods for the least squares problem $ \min_X \| F - A X \|_F$. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt n1} is the number of points in the first grid direction. \item {\tt n2} is the number of points in the second grid direction. \item {\tt n3} is the number of points in the third grid direction. \item The {\tt seed} parameter is a random number seed. \item The {\tt nrhs} parameter is the number of right hand sides to solve as one block. \item The {\tt type} parameter specifies a real or complex linear system. \begin{itemize} \item {\tt type = 1 (SPOOLES\_REAL)} for real, \item {\tt type = 2 (SPOOLES\_COMPLEX)} for complex. \end{itemize} \end{itemize} %----------------------------------------------------------------------- \end{enumerate} FrontMtx/doc/intro.tex010064400020550007177000000236700657126717300163220ustar00clevecompmath00000400000006\par \chapter{{\tt FrontMtx}: Front matrix} \par The {\tt FrontMtx} object is used to solve linear systems of equations by computing and using an $LU$ or $U^TDU$ factorization of a matrix or matrix pencil. The ``front'' in its name refers to a multifrontal formulation of the factor matrices. We don't actually use the multifrontal factorization method, (rather a left-looking block general sparse algorithm), but the storage of the factors and the computations are based on ``fronts''. \par There are four orthogonal axes that describe a front matrix. \begin{itemize} \item The entries of the matrix can be double precision real or double precision complex. \item The factorization could be from a real or complex symmetric matrix, from a Hermitian matrix, or from a real or complex nonsymmetric matrix. In addition, the matrix can be represented as $A + \sigma B$, a linear combination of two matrices. \item The factorization can be performed with or without pivoting for numerical stability. \item The factorization can be {\it direct} or {\it approximate}. In the former case, the submatrices of the factors are stored as dense matrices. In the latter case, a user supplied drop tolerance is used to decide which entries to keep in the factorization. \end{itemize} The front matrix can exist in three different environments: serial, shared memory with parallelism enabled using Solaris or POSIX threads, and distributed memory using MPI. \par This object computes, stores and solves linear systems using three types of factorizations: \begin{enumerate} \item $(A + \sigma B) = P(U^T + I)D(I + U)P^T$, where $A$ and $B$ are symmetric or Hermitian matrices. If pivoting is not enabled, $D$ is a diagonal matrix. If pivoting is enabled, $D$ has $1 \times 1$ and $2 \times 2$ blocks on its diagonal. $U$ is strictly upper triangular, and the nonzero structures of $U$ and $D$ are disjoint. $P$ is a permutation matrix. If pivoting is not used, $P$ is the identity. \item $(A + \sigma B) = P(L + I)D(I + U)Q^T$ for a square nonsymmetric matrix $A$ with symmetric structure. $D$ is a diagonal matrix. $U$ is strictly upper triangular. $L$ is strictly lower triangular. $P$ and $Q$ are permutation matrices. If pivoting is not used, $P$ and $Q$ are the identity. \item $A = QR$ for square or rectangular $A$. $Q$ is an orthogonal matrix that is not explicitly computed or stored. $R$ is upper triangular. \end{enumerate} \par The factorization is performed using a one dimensional decomposition of the global sparse matrix. A typical {\it front} of the matrix is found the shaded portion of the figure below. \begin{center} \makebox{ % \psfig{file=simple.eps,width=1.0in,height=1.00in} \psfig{file=../../FrontMtx/doc/simple.eps,width=1.0in,height=1.00in} } \end{center} A front is indivisible, it is found on one processor, and one processor or one thread is responsible for its internal computations. This is extremely important if we want to support pivoting for stability, for deciding how to choose the pivot elements in the front requires continuous up-to-date information about all the entries in the front. If a front were partitioned among threads or processors, the cost of the communication to select pivot elements would be intolerable. \par Solving a nonsymmetric linear system $(A + \sigma B)X = B$ is done in the following steps. \begin{itemize} \item Factor $(A + \sigma B) = P(L + I)D(I + U)Q^T$. \item Solve $(L + I) Y = P^T B$ \item Solve $D Z = Y$ \item Solve $(I + U) W = Z$ \item $X = Q W$. \end{itemize} Release 1.0 used a one-dimensional data decomposition for the solves. Release 2.0 has changed to a two-dimensional data decomposition to increase the available parallelism. After the factorization is computed using a one-dimensional data decomposition, we post-process the matrix to obtain the two-dimensional decomposition and then perform the forward and backsolves. \par To use the front matrix object, the user need know about only the initialization, factor, postprocess and solve methods. % Let us take a quick look at the necessary data structures. Here are the objects that a front matrix interacts with from the user's or ``external'' perspective. \begin{itemize} \item A sparse matrix $A$ that is to be factored is contain in a {\tt InpMtx} object. This object has been designed to be easy to use, to assemble and permute matrix entries, and to be put into a convenient form to be assembled into the front matrix. It contains real or complex matrix entries. \item The linear combination $A + \sigma B$ is found in a {\tt Pencil} object. \item The {\tt ETree} object contains the front tree that governs the factorization and solve. Inside this object are the dimensions of each front (the number of internal and external rows and columns), the tree connectivity of the fronts, and a map from each vertex to the front that contains it as an internal row and column. The {\tt FrontMtx} object contains a pointer to an {\tt ETree} object, but it does not modify the object, nor does it own the storage for the {\tt ETree} object. Thus multiple front matrices can all point to the same {\tt ETree} object simultaneously. \item An {\tt IVL} object ({\tt I}nteger {\tt V}ector {\tt L}ist), contains the symbolic factorization. For each front, it gives the list of internal and external rows and columns, used to initialize a front prior to its factorization. For a factorization without pivoting, this object stores the index information for the factors, and so is used during the forward and backsolves. For a factorization with pivoting, the index information for a front may change, so this object is not used during the solves. As for the {\tt ETree} object, the symbolic factorization is neither modified or owned by the front matrix object. \item Working storage is necessary during the factor and solves. Instead of forcing one way of managing working storage, (e.g., simple {\tt malloc} and {\tt free's} or a complex management of one large work array), we have abstracted this behavior into two objects. \begin{itemize} \item The {\tt SubMtxManager} object manages instances of the {\tt SubMtx} object, used to store submatrices of the factors and working storage during the solves. The {\tt FrontMtx} object contains a pointer to this manager object, set upon initialization. \item The {\tt ChvManager} object manages instances of the {\tt Chv} object, used to store fronts during the factorization. This manager object is passed to the front matrix object in a call to the factorization methods. \end{itemize} The user can easily override the behavior of these two manager objects. Our default supplied object are simple in their functionality --- they are either wrappers around {\tt malloc()} and {\tt free()} calls, or they manage a pool of available objects. We measure their overhead and storage requirements during the factorizations and solve. \item The right hand side $B$ and solution $X$ are stored in {\tt DenseMtx} objects. This object is a very simple wrapper around a dense matrix stored either column major or row major. (Our solves presently require the storage to be column major.) The matrices $B$ and $X$ can be either global (as in a serial or shared memory environment) or partitioned into local matrices (as in a distributed implementation). \item A parallel factorization requires a map from fronts to threads or processors, and this functionality is supplied by an {\tt IV} ({\tt I}nteger {\tt V}ector) object. \item The parallel solve requires a map from the submatrices to the threads or processors. This two-dimensional map is embodied in the {\tt SolveMap} object. \end{itemize} \par To see how the front matrix object interacts with the other objects in the {\bf SPOOLES} library, here is a brief description of the objects ``internal'' to the front matrix, its factorization and solve. \par \begin{itemize} \item The {\tt Chv} object stores a front as a block {\it chevron}. Updates to the front, its assembly of postponed data (when pivoting is enabled) or aggregate data (in a parallel factorization), and the factorization of the fully assembled front, take place within the context of this object. \item The {\tt SubMtx} object is used to store a submatrix of the factor matrices $D$, $L$ and $U$. Once a front is factored it is split into one or more of these submatrix objects. After the factorization is complete, the data structures are postprocessed to yield submatrices that contain the coupling between fronts. The working storage during the solves is also managed by {\tt SubMtx} objects. \item Each submatrix represents the coupling between two fronts, $I$ and $J$. To enable rapid random access to these submatrices, we use a {\tt I2Ohash} object that is a hash table whose keys are two integers and whose data is a {\tt void *} pointer. \item The set of nonzero submatrices, i.e., the nonzero couplings between two fronts, is kept in one or two {\tt IVL} objects. This information is necessary for the factorization and forward and backsolves. \item The factorization and solves require {\it lists} of fronts and submatrices to manage assembly of data and synchronization. We encapsulate these functions in the {\tt ChvList} and {\tt SubMtxList} objects that operate in serial, multithreaded and MPI environments. \item For a factorization with pivoting, the composition of a front (its dimensions and the row and column indices) may change, so we need additional data structures to store this information. We use an {\tt IV} object to store the front size --- the number of rows and columns that were eliminated when the front was factored. We use an {\tt IVL} object to store the column indices --- internal and external --- and if the matrix is nonsymmetric, another {\tt IVL} object to store the row indices. \item If we have a multithreaded factorization and use pivoting or an approximate factorization, we need exclusive access to the {\tt IV} object that stores the final front size, and the {\tt IVL} object(s) that store the final row and column indices for the front. Therefore we use a {\tt Lock} object to govern exclusive access to these objects. \end{itemize} end{itemize} Release 1.0 used a one-dimensional data decomposition for tFrontMtx/doc/main.tex010064400020550007177000000011720665065622600161030ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \newcommand{\bnd}[1]{{\partial{#1}}} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt FrontMtx} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt FrontMtx} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} FrontMtx/doc/proto.tex010064400020550007177000001561110665022023100163050ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt FrontMtx} methods} \label{section:FrontMtx:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt FrontMtx} object. \par \subsection{Basic methods} \label{subsection:FrontMtx:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} FrontMtx * FrontMtx_new ( void ) ; \end{verbatim} \index{FrontMtx_new@{\tt FrontMtx\_new()}} This method simply allocates storage for the {\tt FrontMtx} structure and then sets the default fields by a call to {\tt FrontMtx\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_setDefaultFields ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_setDefaultFields@{\tt FrontMtx\_setDefaultFields()}} The structure's fields are set to default values: {\tt nfront}, {\tt neqns}, {\tt nentD}, {\tt nentL}, {\tt nentU} and {\tt nlocks} are set to zero. Five scalars are set to their default values, \begin{center} \begin{tabular}{lcl} {\tt type} & = & {\tt SPOOLES\_REAL} \\ {\tt symmetryflag} & = & {\tt SPOOLES\_SYMMETRIC} \\ {\tt sparsityflag} & = & {\tt FRONTMTX\_DENSE\_FRONTS} \\ {\tt pivotingflag} & = & {\tt SPOOLES\_NO\_PIVOTING} \\ {\tt dataMode} & = & {\tt FRONTMTX\_1D\_MODE} \end{tabular} \end{center} and the structure's pointers are set to {\tt NULL}. % {\tt tree}, % {\tt frontETree}, % {\tt symbfacIVL}, % {\tt frontsizesIV}, % {\tt rowadjIVL}, % {\tt coladjIVL}, % {\tt lowerblockIVL}, % {\tt upperblockIVL}, % {\tt p\_mtxDJJ}, % {\tt p\_mtxUJJ}, % {\tt p\_mtxUJN}, % {\tt p\_mtxLJJ}, % {\tt p\_mtxLNJ}, % {\tt lowerhash}, % {\tt upperhash} and % {\tt lock} % are set to {\tt NULL} . \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_clearData ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_clearData@{\tt FrontMtx\_clearData()}} This method clears the object and free's any owned data by invoking the {\tt \_clearData()} methods for its internal {\tt IV} and {\tt IVL} objects, ({\it not} including the {\tt frontETree} and {\tt symbfacIVL} objects that are not owned by this {\tt FrontMtx} object). If the {\tt lock} pointer is not {\tt NULL}, the lock is destroyed via a call to {\tt Lock\_free()} and its storage is then free'd. There is a concluding call to {\tt FrontMtx\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_free ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_free@{\tt FrontMtx\_free()}} This method releases any storage by a call to {\tt FrontMtx\_clearData()} and then free the space for {\tt frontmtx}. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:FrontMtx:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_nfront ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_nfront@{\tt FrontMtx\_nfront()}} This method returns the number of fronts in the matrix. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_neqns ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_neqns@{\tt FrontMtx\_neqns()}} This method returns the number of equations in the matrix. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Tree * FrontMtx_frontTree ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_frontTree@{\tt FrontMtx\_frontTree()}} This method returns the {\tt Tree} object for the fronts. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_initialFrontDimensions ( FrontMtx *frontmtx, int J, int *pnD, int *pnL, int *pnU, int *pnbytes ) ; \end{verbatim} \index{FrontMtx_initialFrontDimensions@{\tt FrontMtx\_initialFrontDimensions()}} This method fills the four pointer arguments with the number of internal rows and columns, number of rows in the lower block, number of columns in the upper block, and number of bytes for a {\tt Chv} object to hold the front. in front {\tt J}. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, or if {\tt J} is not in {\tt [0,nfront)}, or if any of the four pointer arguments are NULL, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_frontSize ( FrontMtx *frontmtx, int J ) ; \end{verbatim} \index{FrontMtx_frontSize@{\tt FrontMtx\_frontSize()}} This method returns the number of internal rows and columns in front {\tt J}. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt frontsizesIV} is {\tt NULL}, or if {\tt J} is not in {\tt [0,nfront)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_setFrontSize ( FrontMtx *frontmtx, int J, int size ) ; \end{verbatim} \index{FrontMtx_setFrontsize@{\tt FrontMtx\_setFrontSize()}} This method sets the number of internal rows and columns in front {\tt J} to be {\tt size}. This method is used during factorizations with pivoting enabled since we cannot tell ahead of time how many rows and columns in a front will be eliminated. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt frontsizesIV} is {\tt NULL}, or if {\tt J} is not in {\tt [0,nfront)}, or if ${\tt size} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_columnIndices ( FrontMtx *frontmtx, int J, int *pncol, int **pindices ) ; \end{verbatim} \index{FrontMtx_columnIndices@{\tt FrontMtx\_columnIndices()}} This method fills {\tt *pncol} with the number of columns and {\tt *pindices} with a pointer to the column indices for front {\tt J}. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt pncol} or {\tt pindices} is {\tt NULL}, or if {\tt J} is not in {\tt [0,nfront)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_rowIndices ( FrontMtx *frontmtx, int J, int *pnrow, int **pindices ) ; \end{verbatim} \index{FrontMtx_rowIndices@{\tt FrontMtx\_rowIndices()}} This method fills {\tt *pnrow} with the number of rows and {\tt *pindices} with a pointer to the row indices for front {\tt J}. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt pnrow} or {\tt pindices} is {\tt NULL}, or if {\tt J} is not in {\tt [0,nfront)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} SubMtx * FrontMtx_diagMtx ( FrontMtx *frontmtx, int J ) ; \end{verbatim} \index{FrontMtx_diagMtx@{\tt FrontMtx\_diagMtx()}} This method returns a pointer to the object that contains submatrix $D_{J,J}$. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, or if {\tt J} is not in {\tt [0,nfront)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} SubMtx * FrontMtx_upperMtx ( FrontMtx *frontmtx, int J, int K ) ; \end{verbatim} \index{FrontMtx_upperMtx@{\tt FrontMtx\_upperMtx()}} This method returns a pointer to the object that contains submatrix $U_{J,K}$. If $K = nfront$, then the object containing $U_{J,\bnd{J}}$ is returned. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, or if {\tt J} is not in {\tt [0,nfront)}, or if {\tt K} is not in {\tt [0,nfront]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} SubMtx * FrontMtx_lowerMtx ( FrontMtx *frontmtx, int K, int J ) ; \end{verbatim} \index{FrontMtx_lowerMtx@{\tt FrontMtx\_lowerMtx()}} This method returns a pointer to the object that contains submatrix $L_{K,J}$. If $K = nfront$, then the object containing $L_{\bnd{J},J}$ is returned. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, or if {\tt J} is not in {\tt [0,nfront)}, or if {\tt K} is not in {\tt [0,nfront]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_lowerAdjFronts ( FrontMtx *frontmtx, int J, int *pnadj, int **padj ) ; \end{verbatim} \index{FrontMtx_lowerAdjFronts@{\tt FrontMtx\_lowerAdjFronts()}} This method fills {\tt *pnadj} with the number of fronts adjacent to {\tt J} in $L$ and fills {\tt *padj} with a pointer to the first entry of a vector containing the ids of the adjacent fronts. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt pnadj} or {\tt ppadj} is {\tt NULL}, or if {\tt J} is not in {\tt [0,nfront)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_upperAdjFronts ( FrontMtx *frontmtx, int J, int *pnadj, int **padj ) ; \end{verbatim} \index{FrontMtx_upperAdjFronts@{\tt FrontMtx\_upperAdjFronts()}} This method fills {\tt *pnadj} with the number of fronts adjacent to {\tt J} in $U$ and fills {\tt *padj} with a pointer to the first entry of a vector containing the ids of the adjacent fronts. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt pnadj} or {\tt ppadj} is {\tt NULL}, or if {\tt J} is not in {\tt [0,nfront)}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_nLowerBlocks ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_nLowerBlocks@{\tt FrontMtx\_nLowerBlocks()}} This method returns the number of nonzero $L_{K,J}$ submatrices. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_nUpperBlocks ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_nUpperBlocks@{\tt FrontMtx\_nUpperBlocks()}} This method returns the number of nonzero $U_{J,K}$ submatrices. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * FrontMtx_upperBlockIVL ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_upperBlockIVL@{\tt FrontMtx\_upperBlockIVL()}} This method returns a pointer to the {\tt IVL} object that holds the upper blocks. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * FrontMtx_lowerBlockIVL ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_lowerBlockIVL@{\tt FrontMtx\_lowerBlockIVL()}} This method returns a pointer to the {\tt IVL} object that holds the lower blocks. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization methods} \label{subsection:FrontMtx:proto:initialization} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_init ( FrontMtx *frontmtx, ETree *frontETree, IVL *symbfacIVL, int type, int symmetryflag, int sparsityflag, int pivotingflag, int lockflag, int myid, IV *ownersIV, SubMtxManager *manager, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_init@{\tt FrontMtx\_init()}} This method initializes the object, allocating and initializing the internal objects as necessary. See the previous section on data structures for the meanings of the {\tt type}, {\tt symmetryflag}, {\tt sparsityflag} and {\tt pivotingflag} parameters. The {\tt lockflag} parameter has the following meaning. \begin{itemize} \item {\tt 0} --- the {\tt Lock} object is not allocated or initialized. \item {\tt 1} --- the {\tt Lock} object is allocated and initialized to synchronize only threads in this process. \item {\tt 2} --- the {\tt Lock} object is allocated and initialized to synchronize threads in this and other processes. \end{itemize} If {\tt lockflag} is not {\tt 0}, the lock is allocated and initialized. \par This method allocates as much storage as possible. When pivoting is not enabled and dense fronts are stored the structure of the factor matrix is fixed and given by the {\tt frontETree} object. The diagonal $D_{J,J}$, upper triangular $U_{J,J}$ and $U_{J,\bnd{J}}$ matrices, and lower triangular $L_{J,J}$ and $L_{\bnd{J},J}$ matrices are allocated. \par The {\tt myid} and {\tt ownersIV} parameters are used in a distributed environment where we specify which process owns each front. When we can preallocate data structures (when there is no pivoting and dense fronts are stored) we need each process to determine what parts of the data it can allocate and set up. In a serial or multithreaded environment, use {\tt ownersIV = NULL}. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt frontETree} or {\tt symbfacIVL} is {\tt NULL}, or if {\tt type}, {\tt symmetryflag}, {\tt sparsityflag} or {\tt pivotingflag} are not valid, or if {\tt lockflag} is not {\tt 0}, {\tt 1} or {\tt 2}, or if {\tt ownersIV} is not {\tt NULL} and {\tt myid < 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility Factorization methods} \label{subsection:FrontMtx:proto:utility-factor} \par The following methods are called by all the factor methods --- serial, multithreaded and MPI. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_initializeFront ( FrontMtx *frontmtx, Chv *frontJ, int J ) ; \end{verbatim} \index{FrontMtx_initializeFront@{\tt FrontMtx\_initializeFront()}} This method is called to initialize a front. The number of internal rows and columns is found from the front {\tt ETree} object and the row and column indices are obtained from the symbolic factorization {\tt IVL} object. The front {\tt Chv} object is initialized via a call to {\tt Chv\_init()}, and the column indices and row indices (when nonsymemtric) are copied. Finally the front's entries are zeroed via a call to {\tt Chv\_zero()}. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} char FrontMtx_factorVisit ( FrontMtx *frontmtx, Pencil *pencil, int J, int myid, int owners[], Chv *fronts[], int lookahead, double tau, double droptol, char status[], IP *heads[], IV *pivotsizesIV, DV *workDV, int parent[], ChvList *aggList, ChvList *postList, ChvManager *chvmanager, int stats[], double cpus[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_factorVisit@{\tt FrontMtx\_factorVisit()}} This method is called during the serial, multithreaded and MPI factorizations when front {\tt J} is visited during the bottom-up traversal of the tree. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} Chv * FrontMtx_setupFront ( FrontMtx *frontmtx, Pencil *pencil, int J, int myid, int owners[], ChvManager *chvmanager, double cpus[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_setupFront@{\tt FrontMtx\_setupFront()}} This method is called by {\tt FrontMtx\_visitFront()} to initialize the front's {\tt Chv} object and load original entries if applicable. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} IP ** FrontMtx_factorSetup ( FrontMtx *frontmtx, IV *frontOwnersIV, int myid, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_factorSetup@{\tt FrontMtx\_factorSetup()}} This method is called by the serial, multithreaded and MPI factorizations methods to initialize a data structure that contains the front-to-front updates that this thread or processor will perform. The data structure is a vector of pointers to {\tt IP} objects that holds the heads of list of updates for each front. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} int * FrontMtx_nactiveChild ( FrontMtx *frontmtx, char *status, int myid ) ; \end{verbatim} \index{FrontMtx_nactiveChild@{\tt FrontMtx\_nactiveChild()}} This method is called by the multithreaded and MPI factorizations to create an integer vector that contains the number of active children of each front with respect to this thread or processor. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt status} is {\tt NULL}, or if ${\tt myid} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Ideq * FrontMtx_setUpDequeue ( FrontMtx *frontmtx, int owners[], int myid, char status[], IP *heads[], char activeFlag, char inactiveFlag, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_nactiveChild@{\tt FrontMtx\_nactiveChild()}} This method is called by the multithreaded and MPI factorizations to create and return an integer dequeue object to schedule the bottom-up traversal of the front tree. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt owners} or {\tt status} is {\tt NULL}, or if ${\tt myid} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_loadActiveLeaves ( FrontMtx *frontmtx, char status[], char activeFlag, Ideq *dequeue ) ; \end{verbatim} \index{FrontMtx_loadActiveLeaves@{\tt FrontMtx\_loadActiveLeaves()}} This method is called by the multithreaded and MPI factor and solve methods to load the dequeue with the active leaves in the front tree with respect to the thread or processor. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} ChvList * FrontMtx_postList ( FrontMtx *frontmtx, IV *frontOwnersIV, int lockflag ) ; \end{verbatim} \index{FrontMtx_postList@{\tt FrontMtx\_postList()}} This method is called by the multithreaded and MPI factor methods to create and return a list object to hold postponed chevrons and help synchronize the factorization. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} ChvList * FrontMtx_aggregateList ( FrontMtx *frontmtx, IV *frontOwnersIV, int lockflag ) ; \end{verbatim} \index{FrontMtx_aggregateList@{\tt FrontMtx\_aggregateList()}} This method is called by the multithreaded factor methods to create and return a list object to hold aggregate fronts and help synchronize the factorization. There is an analogous {\tt FrontMtx\_MPI\_aggregateList()} method for the MPI environment. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt frontOwnersIV} is {\tt NULL}, or if {\tt lockflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_loadEntries ( Chv *frontJ, DPencil *pencil, int msglvl, FILE *msgFile) ; \end{verbatim} \index{FrontMtx_loadEntries@{\tt FrontMtx\_loadEntries()}} This method is called to load the original entries into a front. \par \noindent {\it Error checking:} If {\tt frontJ} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_update ( FrontMtx *frontmtx, Chv *frontJ, IP *heads[], char status[], DV *tempDV, int msglvl, FILE *msgFile) ; \end{verbatim} \index{FrontMtx_update@{\tt FrontMtx\_update()}} This method is called to update the current front stored in {\tt frontJ} from all descendent fronts. (For the multithreaded and MPI factorizations, updates come from all owned descendent fronts.) The {\tt heads[]} vector maintains the linked list of completed fronts that still have ancestors to update. The {\tt tempDV} object is used as working storage by the {\tt Chv} update methods, its size is automatically resized. When pivoting is disabled, the maximum size of the {\tt tempDV} object is three times the maximum number of internal rows and columns in a front. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} Chv * FrontMtx_assemblePostponedData ( FrontMtx *frontmtx, Chv *frontJ, ChvList *postponedlist, ChvManager *chvmanager, int *pndelay) ; \end{verbatim} \index{FrontMtx_assemblePostponedData@{\tt FrontMtx\_assemblePostponedData()}} This method is called to assemble any postponed data from its children fronts into the current front. {\tt frontJ} contains the updates from the descendents. Any postponed data is found in the list in {\tt postponedlist}. If this list is empty, a new front is created to hold the aggregate updates and the postponed data, and the {\tt chvmanager} object receives the aggregate and postponed {\tt Chv} objects. The number of delayed rows and columns is returned in {\tt *pndelay} --- this is used during the factorization of the front that follows immediately. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} FrontMtx_storePostponedData ( FrontMtx *frontmtx, Chv *frontJ, int npost, int K, ChvList *postponedlist, ChvManager *chvmanager ) ; \end{verbatim} \index{FrontMtx_storePostponedData@{\tt FrontMtx\_storePostponedData()}} This method is used to store any postponed rows and columns from the current front {\tt frontJ} into a {\tt Chv} object obtained from the {\tt chvmanager} object and place it into the list of postponed objects for {\tt K}, its parent, found in the {\tt postponedlist} object. The {\tt frontJ} object is unchanged by this method. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} FrontMtx_storeFront ( FrontMtx *frontmtx, Chv *frontJ, IV *pivotsizesIV, double droptol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_storeFront@{\tt FrontMtx\_storeFront()}} This method is used to store the eliminated rows and columns of the current front {\tt frontJ} into the factor matrix storage. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Serial Factorization method} \label{subsection:FrontMtx:proto:factor} There are two factorization methods: the first is for factoring a matrix $A$ stored in a {\tt DInpMtx} object, the second factors a linear combination $A + \sigma B$ stored in a {\tt DPencil} object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Chv * FrontMtx_factorInpMtx ( FrontMtx *frontmtx, InpMtx *inpmtx, double tau, double droptol, ChvManager *chvmanager, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile ) ; Chv * FrontMtx_factorPencil ( FrontMtx *frontmtx, Pencil *pencil, double tau, double droptol, ChvManager *chvmanager, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_factorInpMtx@{\tt FrontMtx\_factorInpMtx()}} \index{FrontMtx_factorPencil@{\tt FrontMtx\_factorPencil()}} These two serial factorization methods factor a matrix $A$ (stored in {\tt inpmtx}) or a matrix pencil $A + \sigma B$ (stored in {\tt pencil}). The {\tt tau} parameter is used when pivoting is enabled, each entry in $U$ and $L$ (when nonsymmetric) will have magnitude less than or equal to {\tt tau}. The {\tt droptol} parameter is used when the fronts are stored in a sparse format, each entry in $U$ and $L$ (when nonsymmetric) will have magnitude greater than or equal to {\tt droptol}. \par The return value is a pointer to the first element in a list of {\tt Chv} objects that contain the rows and columns that were not able to be eliminated. In all present cases, this should be {\tt NULL}; we have left this return value as a hook to future factorizations via stages. The {\tt perror} parameter is an address that is filled with an error code on return. If the factorization has completed, then {\tt *perror} is a negative number. If {\tt *perror} is in the range {\tt [0,nfront)}, then an error has been detected at front {\tt *perror}. On return, the {\tt cpus[]} vector is filled with the following information. \begin{itemize} \item {\tt cpus[0]} --- time spent initializing the fronts. \item {\tt cpus[1]} --- time spent loading the original entries. \item {\tt cpus[2]} --- time spent accumulating updates from descendents. \item {\tt cpus[3]} --- time spent assembling postponed data. \item {\tt cpus[4]} --- time spent to factor the fronts. \item {\tt cpus[5]} --- time spent to extract postponed data. \item {\tt cpus[6]} --- time spent to store the factor entries. \item {\tt cpus[7]} --- miscellaneous time. \item {\tt cpus[8]} --- total time in the method. \end{itemize} On return, the {\tt stats[]} vector is filled with the following information. \begin{itemize} \item {\tt stats[0]} --- number of pivots. \item {\tt stats[1]} --- number of pivot tests. \item {\tt stats[2]} --- number of delayed rows and columns. \item {\tt stats[3]} --- number of entries in $D$. \item {\tt stats[4]} --- number of entries in $L$. \item {\tt stats[5]} --- number of entries in $U$. \end{itemize} \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt pencil}, {\tt cpus} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{QR factorization utility methods} \label{subsection:FrontMtx:proto:utilityQR} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_QR_setup ( FrontMtx *frontmtx, InpMtx *mtxA, IVL **prowsIVL, int **pfirstnz, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_QR_setup@{\tt FrontMtx\_QR\_setup()}} This method sets up the {\tt rowsIVL} and {\tt firstnz[]} data structures. The address of {\tt rowsIVL} is placed in {\tt *prowsIVL} and the address of {\tt firstnz} is placed in {\tt *pfirstnz}. List {\tt J} of {\tt rowsIVL} contains the rows of $A$ that will be assembled into front {\tt J}. The leading column with a nonzero entry in row {\tt j} is found in {\tt firstnz[j]}. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt mtxA}, {\tt prowsIVL} or {\tt pfirstnz} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_QR_factorVisit ( FrontMtx *frontmtx, int J, InpMtx *mtxA, IVL *rowsIVL, int firstnz[], ChvList *updList, ChvManager *chvmanager, char status[], int colmap[], DV *workDV, double cpus[], double *pfacops, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_QR_factorVisit@{\tt FrontMtx\_QR\_factorVisit()}} This method visits front {\tt J} during the $QR$ factorization. The number of operations to reduce the staircase matrix to upper trapezoidal or triangular form is incremented in {\tt *pfacops}. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt mtxA}, {\tt rowsIVL}, {\tt firstnz}, {\tt updlist}, {\tt chvmanager}, {\tt status}, {\tt colmap}, {\tt workDV}, {\tt cpus} or {\tt pfacops} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} A2 * FrontMtx_QR_assembleFront ( FrontMtx *frontmtx, int J, InpMtx *mtxA, IVL *rowsIVL, int firstnz[], int colmap[], Chv *firstchild, DV *workDV, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_QR_assembleFront@{\tt FrontMtx\_QR\_assembleFront()}} This method creates an {\tt A2} object to hold the front, assembles any original rows of $A$ and any update matrices from the children into the front, and then returns the front. The rows and update matrices are assembled into staircase form, so no subsequent permutations of the rows is necessary. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt mtxA}, {\tt rowsIVL}, {\tt firstnz}, {\tt colmap} or {\tt workDV} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_QR_storeFront ( FrontMtx *frontmtx, int J, A2 *frontJ, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_QR_storeFront@{\tt FrontMtx\_QR\_storeFront()}} This method takes as input {\tt frontJ}, the front in trapezoidal or triangular form. It scales the strict upper triangle or trapezoid by the diagonal entries, then squares the diagonal entries. (This transforms $R^TR$ into $(U^T + I)D(I+U)$ or $R^HR$ into $(U^H + I)D(I+U)$ for our solves.) It then stores the entries into the factor matrix. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt frontJ} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Chv * FrontMtx_QR_storeUpdate ( FrontMtx *frontmtx, int J, A2 *frontJ, ChvManager *chvmanager, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_QR_storeUpdate@{\tt FrontMtx\_QR\_storeUpdate()}} This method takes as input {\tt frontJ}, the front in trapezoidal or triangular form. It extracts the update matrix, stores the entries in a {\tt Chv} object, and returns the {\tt Chv} object. entries, then squares the diagonal entries. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt frontJ} or {\tt chvmanager} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Serial $QR$ Factorization method} \label{subsection:FrontMtx:proto:factorQR} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_QR_factor ( FrontMtx *frontmtx, InpMtx *mtxA, ChvManager *chvmanager, double cpus[], double *pfacops, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_QR_factor@{\tt FrontMtx\_QR\_factor()}} This method computes the $(U^T+I)D(I+U)$ factorization of $A^TA$ if $A$ is real or $(U^H+I)D(I+U)$ factorization of $A^HA$ if $A$ is complex. The {\tt chvmanager} object manages the working storage. On return, the {\tt cpus[]} vector is filled as follows. \begin{itemize} \item {\tt cpus[0]} -- setup time, time to compute the {\tt rowsIVL} and {\tt firstnz[]} objects \item {\tt cpus[1]} -- time to initialize and load the staircase matrices \item {\tt cpus[2]} -- time to factor the matrices \item {\tt cpus[3]} -- time to scale and store the factor entries \item {\tt cpus[4]} -- time to store the update entries \item {\tt cpus[5]} -- miscellaneous time \item {\tt cpus[6]} -- total time \end{itemize} On return, {\tt *pfacops} contains the number of floating point operations done by the factorization. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt frontJ} or {\tt chvmanager} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Postprocessing methods} \label{subsection:FrontMtx:proto:postprocess} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_postProcess ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_postProcess@{\tt FrontMtx\_postProcess()}} This method does post-processing chores after the factorization is complete. If pivoting was enabled, the method permutes the row and column adjacency objects, permutes the lower and upper matrices, and updates the block adjacency objects. The chevron submatrices $L_{\bnd{J},J}$ and $U_{J,\bnd{J}}$ are split into $L_{K,J}$ and $U_{J,K}$ where $K \cap \bnd{J} \ne \emptyset$. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, or if {\tt msglvl} > 0 and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_permuteUpperAdj ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; void FrontMtx_permuteLowerAdj ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_permuteUpperAdj@{\tt FrontMtx\_permuteUpperAdj()}} \index{FrontMtx_permuteLowerAdj@{\tt FrontMtx\_permuteLowerAdj()}} These methods are called during the postprocessing step, where they permute the upper and lower adjacency structures so that vertices in $\bnd{J}$ are in ascending order with respect to the indices in $K \cup \bnd{K}$, where $K$ is the parent of $J$. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, or if {\tt msglvl} > 0 and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_permuteUpperMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; void FrontMtx_permuteLowerMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_permuteUpperMatrices@{\tt FrontMtx\_permuteUpperMatrices()}} \index{FrontMtx_permuteLowerMatrices@{\tt FrontMtx\_permuteLowerMatrices()}} These methods are called during the postprocessing step, where they permute the upper $U_{J,\bnd{J}}$ and lower $L_{\bnd{J},J}$ submatrices so that the columns in $U_{J,\bnd{J}}$ and rows in $L_{\bnd{J},J}$ are in ascending order with the columns and rows of the final matrix. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, or if {\tt msglvl} > 0 and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_splitUpperMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; void FrontMtx_splitLowerMatrices ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_splitUpperMatrices@{\tt FrontMtx\_splitUpperMatrices()}} \index{FrontMtx_splitLowerMatrices@{\tt FrontMtx\_splitLowerMatrices()}} These methods are called during the postprocessing step, where they split the chevron submatrices $L_{\bnd{J},J}$ and $U_{J,\bnd{J}}$ into $L_{K,J}$ and $U_{J,K}$ where $K \cap \bnd{J} \ne \emptyset$. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, or if {\tt msglvl} > 0 and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility Solve methods} \label{subsection:FrontMtx:proto:utility-solve} \par The following methods are called by all the solve methods --- serial, multithreaded and MPI. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} SubMtx ** FrontMtx_loadRightHandSide ( FrontMtx *frontmtx, DenseMtx *mtxB, int owners[], int myid, SubMtxManager *mtxmanager, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_loadRightHandSide@{\tt FrontMtx\_loadRightHandSide()}} This method creates and returns a vector of pointers to {\tt SubMtx} objects that hold pointers to the right hand side submatrices owned by the thread or processor. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_forwardVisit ( FrontMtx *frontmtx, int J, int nrhs, int *owners, int myid, SubMtxManager *mtxmanager, SubMtxList *aggList, SubMtx *p_mtx[], char frontIsDone[], IP *heads[], SubMtx *p_agg[], char status[], int msglvl, FILE *msgFile) ; \end{verbatim} \index{FrontMtx_forwardVisit@{\tt FrontMtx\_forwardVisit()}} This method is used to visit front {\tt J} during the forward solve, $(U^T + I)Y = B$, $(U^H + I)Y = B$ or $(L + I)Y = B$. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_diagonalVisit ( FrontMtx *frontmtx, int J, int owners[], int myid, SubMtx *p_mtx[], char frontIsDone[], SubMtx *p_agg[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_diagonalVisit@{\tt FrontMtx\_diagonalVisit()}} This method is used to visit front {\tt J} during the diagonal solve, $DZ = Y$. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_backwardVisit ( FrontMtx *frontmtx, int J, int nrhs, int *owners, int myid, SubMtxManager *mtxmanager, SubMtxList *aggList, SubMtx *p_mtx[], char frontIsDone[], IP *heads[], SubMtx *p_agg[], char status[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_backwardVisit@{\tt FrontMtx\_backwardVisit()}} This method is used to visit front {\tt J} during the backward solve, $(U + I)Y = B$. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_storeSolution ( FrontMtx *frontmtx, int owners[], int myid, SubMtxManager *mtxmanager, SubMtx *p_mtx[], DenseMtx *mtxX, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_storeSolution@{\tt FrontMtx\_storeSolution()}} This method stores the solution in the {\tt solmtx} dense matrix object. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} IP ** FrontMtx_forwardSetup ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_forwardSetup@{\tt FrontMtx\_forwardSetup()}} This method is used to set up a data structure of {\tt IP} objects that hold the updates of the form $Y_J := Y_J - U_{I,J}^T X_I$, $Y_J := Y_J - U_{I,J}^H X_I$ or $Y_J := Y_J - L_{J,I} X_I$ that will be performed by this thread or processor. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} IP ** FrontMtx_backwardSetup ( FrontMtx *frontmtx, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_backwardSetup@{\tt FrontMtx\_backwardSetup()}} This method is used to set up a data structure of {\tt IP} objects that hold the updates of the form $Z_J := Z_J - U_{J,K} X_K$ that will be performed by this thread or processor. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_loadActiveRoots ( FrontMtx *frontmtx, char status[], char activeFlag, Ideq *dequeue ) ; \end{verbatim} \index{FrontMtx_loadActiveRoots@{\tt FrontMtx\_loadActiveRoots()}} This method loads the active roots for a thread or a processor into the dequeue for the backward solve. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Serial Solve method} \label{subsection:FrontMtx:proto:solve-serial} \par \begin{enumerate} %======================================================================= \item \begin{verbatim} void FrontMtx_solve ( FrontMtx *frontmtx, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, double cpus[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_solve@{\tt FrontMtx\_solve()}} This method is used to solve one of three linear systems of equations --- $(U^T + I)D(I + U) X = B$, $(U^H + I)D(I + U) X = B$ or $(L + I)D(I + U) X = B$. Entries of $B$ are {\it read} from {\tt mtxB} and entries of $X$ are written to {\tt mtxX}. Therefore, {\tt mtxX} and {\tt mtxB} can be the same object. (Note, this does not hold true for an MPI factorization with pivoting.) The {\tt mtxmanager} object manages the working storage using the solve. On return the {\tt cpus[]} vector is filled with the following. \begin{itemize} \item {\tt cpus[0]} --- set up the solves \item {\tt cpus[1]} --- fetch right hand side and store solution \item {\tt cpus[2]} --- forward solve \item {\tt cpus[3]} --- diagonal solve \item {\tt cpus[4]} --- backward solve \item {\tt cpus[5]} --- total time in the method. \end{itemize} \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt mtxB} or {\tt cpus} is {\tt NULL}, or if {\tt msglvl} > 0 and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %======================================================================= \end{enumerate} \par \subsection{Serial $QR$ Solve method} \label{subsection:FrontMtx:proto:QRsolve-serial} \par \begin{enumerate} %======================================================================= \item \begin{verbatim} void FrontMtx_QR_solve ( FrontMtx *frontmtx, InpMtx *mtxA, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, double cpus[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_QR_solve@{\tt FrontMtx\_QR\_solve()}} This method is used to minimize $\|B - AX\|_F$, where $A$ is stored in {\tt mtxA}, $B$ is stored in {\tt mtxB}, and $X$ will be stored in {\tt mtxX}. The {\tt frontmtx} object contains a $(U^T+I)D(I+U)$ factorization of $A^TA$ if $A$ is real or $(U^H+I)D(I+U)$ factorization of $A^HA$ if $A$ is complex. We solve the seminormal equations $(U^T+I)D(I+U)X = A^TB$ or $(U^H+I)D(I+U)X = A^HB$ for $X$. The {\tt mtxmanager} object manages the working storage used in the solves. On return the {\tt cpus[]} vector is filled with the following. \begin{itemize} \item {\tt cpus[0]} --- set up the solves \item {\tt cpus[1]} --- fetch right hand side and store solution \item {\tt cpus[2]} --- forward solve \item {\tt cpus[3]} --- diagonal solve \item {\tt cpus[4]} --- backward solve \item {\tt cpus[5]} --- total time in the solve method. \item {\tt cpus[6]} --- time to compute $A^TB$ or $A^HB$. \item {\tt cpus[7]} --- total time. \end{itemize} \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt mtxA}, {\tt mtxX}, {\tt mtxB} or {\tt cpus} is {\tt NULL}, or if {\tt msglvl} > 0 and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %======================================================================= \end{enumerate} \par \subsection{Utility methods} \label{subsection:FrontMtx:proto:utility} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IV * FrontMtx_colmapIV ( FrontMtx *frontmtx ) ; IV * FrontMtx_rowmapIV ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_colmapIV@{\tt FrontMtx\_colmapIV()}} \index{FrontMtx_rowmapIV@{\tt FrontMtx\_rowmapIV()}} These methods construct and return an {\tt IV} object that map the rows and columns to the fronts that contains them. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} IV * FrontMtx_ownedRowsIV ( FrontMtx *frontmtx, int myid, IV *ownersIV, int msglvl, FILE *msgFile ) ; IV * FrontMtx_ownedColumnsIV ( FrontMtx *frontmtx, int myid, IV *ownersIV, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_ownedColumns@{\tt FrontMtx\_ownedColumns()}} \index{FrontMtx_ownedRows@{\tt FrontMtx\_ownedRows()}} These methods construct and return {\tt IV} objects that contain the ids of the rows and columns that belong to fronts that are owned by processor {\tt myid}. If {\tt ownersIV} is {\tt NULL}, an {\tt IV} object is returned that contains {\tt \{0,1,2,3, ..., nfront-1\}}. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * FrontMtx_makeUpperBlockIVL ( FrontMtx *frontmtx, IV *colmapIV ) ; IVL * FrontMtx_makeLowerBlockIVL ( FrontMtx *frontmtx, IV *rowmapIV ) ; \end{verbatim} \index{FrontMtx_makeUpperBlockIVL@{\tt FrontMtx\_makeUpperBlockIVL()}} \index{FrontMtx_makeLowerBlockIVL@{\tt FrontMtx\_makeLowerBlockIVL()}} These methods construct and return {\tt IVL} objects that contain the submatrix structure of the lower and upper factors. The {\tt IV} objects map the rows and columns of the matrix to the fronts in the factor matrix that contain them. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt colmapIV} or {\tt rowmapIV} are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_inertia ( FrontMtx *frontmtx, int *pnneg, int *pnzero, int *pnpos ) ; \end{verbatim} \index{FrontMtx_inertia@{\tt FrontMtx\_inertia()}} This method determines the inertia of a symmetric matrix based on the $(U^T + I)D(I + U)$ factorization. The number of negative eigenvalues is returned in {\tt *pnneg}, the number of zero eigenvalues is returned in {\tt *pnzero}, and the number of positive eigenvalues is returned in {\tt *pnpos}. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt pnneg}, {\tt pnzero} or {\tt pnpos} is {\tt NULL}, or if ${\tt symmetryflag} \ne 0$ an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_nSolveOps ( FrontMtx *frontmtx ) ; \end{verbatim} \index{FrontMtx_nSolveOps@{\tt FrontMtx\_nSolveOps()}} This method computes and return the number of floating point operations for a solve with a single right hand side. \par \noindent {\it Error checking:} If {\tt frontmtx} is {\tt NULL}, or if {\tt type} or {\tt symmetryflag} are invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:FrontMtx:proto:IO} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_readFromFile ( FrontMtx *frontmtx, char *fn ) ; \end{verbatim} \index{FrontMtx_readFromFile@{\tt FrontMtx\_readFromFile()}} \par This method reads a {\tt FrontMtx object} from a file. It tries to open the file and if it is successful, it then calls {\tt FrontMtx\_readFromFormattedFile()} or {\tt FrontMtx\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.frontmtxf} (for a formatted file) or {\tt *.frontmtxb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_readFromFormattedFile ( FrontMtx *frontmtx, FILE *fp ) ; \end{verbatim} \index{FrontMtx_readFromFormattedFile@{\tt FrontMtx\_readFromFormattedFile()}} \par This method reads a {\tt FrontMtx} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_readFromBinaryFile ( FrontMtx *frontmtx, FILE *fp ) ; \end{verbatim} \index{FrontMtx_readFromBinaryFile@{\tt FrontMtx\_readFromBinaryFile()}} This method reads a {\tt FrontMtx} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_writeToFile ( FrontMtx *frontmtx, char *fn ) ; \end{verbatim} \index{FrontMtx_writeToFile@{\tt FrontMtx\_writeToFile()}} \par This method writes a {\tt FrontMtx object} to a file. It tries to open the file and if it is successful, it then calls {\tt FrontMtx\_writeFromFormattedFile()} or {\tt FrontMtx\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.frontmtxf} (for a formatted file) or {\tt *.frontmtxb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_writeToFormattedFile ( FrontMtx *frontmtx, FILE *fp ) ; \end{verbatim} \index{FrontMtx_writeToFormattedFile@{\tt FrontMtx\_writeToFormattedFile()}} \par This method writes a {\tt FrontMtx} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_writeToBinaryFile ( FrontMtx *frontmtx, FILE *fp ) ; \end{verbatim} \index{FrontMtx_writeToBinaryFile@{\tt FrontMtx\_writeToBinaryFile()}} \par This method writes a {\tt FrontMtx} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_writeForHumanEye ( FrontMtx *frontmtx, FILE *fp ) ; \end{verbatim} \index{FrontMtx_writeForHumanEye@{\tt FrontMtx\_writeForHumanEye()}} \par This method writes a {\tt FrontMtx} object to a file in a human readable format. The method {\tt FrontMtx\_writeStats()} is called to write out the header and statistics. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_writeStats ( FrontMtx *frontmtx, FILE *fp ) ; \end{verbatim} \index{FrontMtx_writeStats@{\tt FrontMtx\_writeStats()}} \par The header and statistics are written to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_writeForMatlab ( FrontMtx *frontmtx, char *Lname, char *Dname, char *Uname, FILE *fp ) ; \end{verbatim} \index{FrontMtx_writeForMatlab@{\tt FrontMtx\_writeForMatlab()}} \par This method writes out the factor matrix entries in a Matlab-readable form. {\tt Lname} is a string for the lower triangular matrix, {\tt Dname} is a string for the diagonal matrix, and {\tt Uname} is a string for the upper triangular matrix. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt Lname}, {\tt Dname}, {\tt Uname} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par --- fetch right hand side and store solution \item {\tt cpus[2]} --- forward solve \item {\tt cpus[3]} --- diagonal solve \item {\tt cpus[4]} --- backward solve \item {\tt cpus[5]} --- total time in the solve method. \item {\tt cpus[6]} --- time to compute $A^TB$ or $A^HB$. \item {\tt cpus[7]} --- total time. \end{itemize} \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt mtxA}, {\tt mtxX}, {\tt mtxB} or {\tt cpus} is {\tt FrontMtx/doc/intro.tex.bak010064400020550007177000000234200657126717300170470ustar00clevecompmath00000400000006\par \chapter{{\tt FrontMtx}: \break Front matrix} \par This object computes, stores and solves linear systems using two types of factorizations: \begin{enumerate} \item $(A + \sigma B) = P(U^T + I)D(I + U)P^T$ for a symmetric matrix $A$. If pivoting is not enabled, $D$ is a diagonal matrix. If pivoting is enabled, $D$ has $1 \times 1$ and $2 \times 2$ blocks on its diagonal. $U$ is strictly upper triangular, and the nonzero structures of $U$ and $D$ are disjoint. $P$ is a permutation matrix. \item $(A + \sigma B) = P(L + I)D(I + U)Q^T$ for a nonsymmetric matrix $A$ with symmetric structure. $D$ is a diagonal matrix. $U$ is strictly upper triangular. $L$ is strictly lower triangular. $P$ and $Q$ are permutation matrices. \end{enumerate} Pivoting for numerical stability is an optional feature, and the storage of the factors $L$ and $U$ may be sparse, i.e., entries of small magnitude can be dropped from the matrix. \par Let us take a quick look at the necessary data structures. \begin{itemize} \item There is a pointer to a {\tt ETree} object that contains the front tree that governs the factorization and solve. Inside this object are the dimensions of each front (the number of internal and external rows and columns), the tree connectivity of the fronts, and a map from each vertex to the front that contains it as an internal row and column. \item There is a pointer to an {\tt IVL} object that contains the symbolic factorization. For each front, it gives the list of internal and external rows and columns, used to initialize a front prior to its factorization. For a factorization without pivoting, this object stores the index information for the factors, and so is used during the forward and backsolves. For a factorization with pivoting, the index information for a front may change, so this object is not used during the solves. \item For a factorization with pivoting, the composition of a front (its dimensions and the row and column indices) may change, so we need additional data structures to store this information. We use an {\tt IV} object to store the front size --- the number of rows and columns that were eliminated when the front was factored. We use an {\tt IVL} object to store the column indices --- internal and external --- and if the matrix is nonsymmetric, another {\tt IVL} object to store the row indices. \item If we have a multithreaded factorization and use pivoting or an approximate factorization, we need exclusive access to the {\tt IV} object that stores the final front size, and the {\tt IVL} object(s) that store the final row and column indices for the front. Therefore we use a {\tt Lock} object to govern exclusive access to these objects. \end{itemize} \par The $(L+I)D(I+U)$ and $(U^T+I)D(I+U)$ factorizations are computed using a {\it 1-dimensional} decomposition of the matrix. Consider a matrix partitioned into eight fronts. \begin{center} \setlength{\unitlength}{0.04in} \begin{picture}(80,80) \put(-10,40){\makebox(0,0){$A = $}} \put(0,0){\framebox(80,80){}} % \put(0,0){\framebox(10,70){}} % \put(10,0){\framebox(10,60){}} % \put(20,0){\framebox(10,50){}} % \put(30,0){\framebox(10,40){}} % \put(40,0){\framebox(10,30){}} % \put(50,0){\framebox(10,20){}} % \put(60,0){\framebox(10,10){}} \put( 0, 70){\line(1,0){80}} \put(10, 60){\line(1,0){70}} \put(20, 50){\line(1,0){60}} \put(30, 40){\line(1,0){50}} \put(40, 30){\line(1,0){40}} \put(50, 20){\line(1,0){30}} \put(60, 10){\line(1,0){20}} \put(10, 80){\line(0,-1){80}} \put(20, 70){\line(0,-1){70}} \put(30, 60){\line(0,-1){60}} \put(40, 50){\line(0,-1){50}} \put(50, 40){\line(0,-1){40}} \put(60, 30){\line(0,-1){30}} \put(70, 20){\line(0,-1){20}} \put( 5, 75){\makebox(0,0){$A_{0,0}$}} \put(15, 65){\makebox(0,0){$A_{1,1}$}} \put(25, 55){\makebox(0,0){$A_{2,2}$}} \put(35, 45){\makebox(0,0){$A_{3,3}$}} \put(45, 35){\makebox(0,0){$A_{4,4}$}} \put(55, 25){\makebox(0,0){$A_{5,5}$}} \put(65, 15){\makebox(0,0){$A_{6,6}$}} \put(75, 5){\makebox(0,0){$A_{7,7}$}} \put( 5, 35){\makebox(0,0){$A_{*,0}$}} \put(15, 30){\makebox(0,0){$A_{*,1}$}} \put(25, 25){\makebox(0,0){$A_{*,2}$}} \put(35, 20){\makebox(0,0){$A_{*,3}$}} \put(45, 15){\makebox(0,0){$A_{*,4}$}} \put(55, 10){\makebox(0,0){$A_{*,5}$}} \put(65, 5){\makebox(0,0){$A_{*,6}$}} \put(45, 75){\makebox(0,0){$A_{0,*}$}} \put(50, 65){\makebox(0,0){$A_{1,*}$}} \put(55, 55){\makebox(0,0){$A_{2,*}$}} \put(60, 45){\makebox(0,0){$A_{3,*}$}} \put(65, 35){\makebox(0,0){$A_{4,*}$}} \put(70, 25){\makebox(0,0){$A_{5,*}$}} \put(75, 15){\makebox(0,0){$A_{6,*}$}} \end{picture} \end{center} The $A_{i,i}$ matrices on the diagonal are square, but they need not be the same size. The off-diagonal matrices $A_{*,i}$ and $A_{i,*}$ use a $*$ notation for their rows and columns, respectively, where $*$ means all indices that follow the $i$'th block. We shall associate with each front a set of row and column indices, so we write $A_{J,J}$ for $A_{i,i}$, where $J$ is the set of row and column indices for front $i$. \par Consider the case where $A$ is structurally symmetric. We factor $A$ into $(L + I)D(I + U)$, where $L$ is strictly lower triangular, $D $ is diagonal, and $U$ is strictly upper triangular. $L$, $D$ and $U$ inherit the block structure of $A$, so we have $L_{*,J}$, $L_{J,J}$, $D_{J,J}$, $U_{J,J}$ and $U_{J,*}$ matrices. \par The off-diagonal matrices of $A$, $L$ and $U$ are usually very sparse. We use special notation to define their nonzero rows and columns. % We write $A_{\bnd{J},J}$ for $A_{*,J}$ and $A_{J,\bnd{J}}$ for % $A_{J,*}$, and similar notation for $L$ and $U$. The set $\bnd{J}$ is the set of indices $k$ such that $l_{k,j} \ne 0$ or $u_{j,k} \ne 0$ for some $j \in J$. $U_{J,*}$ and $U_{J,\bnd{J}}$ are related by some permutation matrix $A$ where $ U_{J,*} Q = \left \lbrack \begin{array}{cc} U_{J,\bnd{J}} & 0 \end{array} \right \rbrack $. Similar relations hold for $A_{J,*}$, $A_{*,J}$ and $L_{*,J}$. We never operate on or store $U_{J,*}$, for this would waste storage and operations. Rather we store and operate on $U_{J,\bnd{J}}$ instead. \par By multiplying the matrices on the right of $A = (L + I)D(I + U)$, we arrive at the three equations that define the factorization. \begin{eqnarray*} A_{J,J} & = & (L_{J,J}+I) D_{J,J} (I+U_{J,J}) + \sum_{I < J} L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap J} \\ A_{J,\bnd{J}} & = & (L_{J,J}+I) D_{J,J} U_{J, \bnd{J}} + \sum_{I < J} L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap \bnd{J}} \\ A_{\bnd{J},J} & = & L_{\bnd{J},J} D_{J,J} (I+U_{J,J}) + \sum_{I < J} L_{\bnd{I} \cap \bnd{J}, I} D_{I, I} U_{I, \bnd{I} \cap J} \end{eqnarray*} Since we are somewhat informal with our notation above, let us take a moment to make it more precise. \begin{itemize} \item In the summation $\sum_{I < J}$, $I$ and $J$ are index sets. We use the convention that $I < J$ when the front that has index set $I$ is numbered before the front that has index set $J$. In the following we will use $I$ to refer to the front with index set $I$, as well as the index set itself. \item The row index set for $L_{\bnd{I} \cap J,I}$ is the intersection of the indices in $\bnd{I}$ with those of $J$. The index set $\bnd{I} \cap \bnd{J}$ is similarly defined. \item The multiplication $L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap J}$ generates a matrix whose rows are $\bnd{I} \cap J$ and whose columns are $\bnd{I} \cap J$, and this matrix is to be added into a matrix whose rows and columns are $J$. If $\bnd{I} \cap J \ne J$, then this operation is not well defined. We use the convention that the entries in $L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap J}$ are {\it scatter/add}'ed into their proper location. This is a generalization of an indexed {\tt axpy} operation applied to matrices. \end{itemize} Just because front $I$ precedes front $J$ does not mean the there is any nonempty intersection between $\bnd{I}$ and $J$. (A sparse matrix should also have a sparse block structure!) If $\bnd{I} \cap J = \emptyset$, then $L_{\bnd{I} \cap J,I}$ and $U_{I,\bnd{I} \cap J}$ are zero matrices. We can rewrite the above equations to take advantage of this ohservation. \begin{eqnarray*} A_{J,J} & = & (L_{J,J}+I) D_{J,J} (I+U_{J,J}) + \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap J} \\ A_{J,\bnd{J}} & = & (L_{J,J}+I) D_{J,J} U_{J, \bnd{J}} + \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap \bnd{J}} \\ A_{\bnd{J},J} & = & L_{\bnd{J},J} D_{J,J} (I+U_{J,J}) + \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap \bnd{J}, I} D_{I, I} U_{I, \bnd{I} \cap J} \end{eqnarray*} These are the defining equations to compute an $A = (L+I)D(I+U)$ factorization without pivoting. We can rearrange the terms and order the steps to give the factorization algorithm. \begin{figure} \caption{Serial factorization without pivoting} \label{figure:serial-factorization} \begin{center} \fbox{ \begin{minipage}{4 in} \begin{tabbing} XXX\=XXX\=XXX\=\kill for $I$ = 0, $\ldots$, \# of fronts \\ \> compute $\displaystyle T_{J,J} = A_{J,J} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap J}$ \\ \> compute $\displaystyle T_{J,\bnd{J}} = A_{J,\bnd{J}} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap \bnd{J}}$ \\ \> compute $\displaystyle T_{\bnd{J},J} = A_{\bnd{J},J} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap \bnd{J}, I} D_{I, I} U_{I, \bnd{I} \cap J}$ \\ \> solve $ \left \lbrack \begin{array}{cc} (L_{J,J}+I) D_{J,J} (I+U_{J,J}) & (L_{J,J}+I) D_{J,J} U_{J, \bnd{J}} \\ L_{\bnd{J},J} D_{J,J} (I+U_{J,J}) & 0 \end{array} \right \rbrack = \left \lbrack \begin{array}{cc} T_{J,J} & T_{J,\bnd{J}} \\ T_{\bnd{J},J} & 0 \\ \end{array} \right \rbrack $ \\ \>\> for $D_{J,J}$, $L_{J,J}$, $L_{\bnd{J},J}$, $U_{J,J}$ and $U_{J,\bnd{J}}$ \end{tabbing} \end{minipage} } \end{center} \end{figure} ertex to the front that contains it as an internal row and column. \item There is a pointer to an {\tt IVL} object that contains the symbolic factorization. For each front, it gives the list of internal and external rows and columns, used tFrontMtx/doc/main.log010064400020550007177000000225510665022024100160500ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 16 JAN 1999 15:28 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/latex209.def File: latex209.def 1996/05/21 v0.51 Standard LaTeX file Entering LaTeX 2.09 compatibility mode. \footheight=\dimen102 \@maxsep=\dimen103 \@dblmaxsep=\dimen104 \@cla=\count79 \@clb=\count80 \mscount=\count81 (/home/tex/teTeX/texmf/tex/latex/base/tracefnt.sty Package: tracefnt 1996/07/26 v3.0i Standard LaTeX package (font tracing) \tracingfonts=\count82 LaTeX Info: Redefining \selectfont on input line 139. ) \symbold=\mathgroup4 \symsans=\mathgroup5 \symtypewriter=\mathgroup6 \symitalic=\mathgroup7 \symsmallcaps=\mathgroup8 \symslanted=\mathgroup9 LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 306. LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 307. LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 308. LaTeX Font Info: Redeclaring math alphabet \mathit on input line 314. LaTeX Info: Redefining \em on input line 324. (/home/tex/teTeX/texmf/tex/latex/base/latexsym.sty Package: latexsym 1996/11/20 v2.2d Standard LaTeX package (lasy symbols) \symlasy=\mathgroup10 LaTeX Font Info: Overwriting symbol font `lasy' in version `bold' (Font) U/lasy/m/n --> U/lasy/b/n on input line 85. ) LaTeX Font Info: Redeclaring math delimiter \lgroup on input line 388. LaTeX Font Info: Redeclaring math delimiter \rgroup on input line 390. LaTeX Font Info: Redeclaring math delimiter \bracevert on input line 392. (/home/tex/teTeX/texmf/tex/latex/config/latex209.cfg (/home/tex/teTeX/texmf/tex/latex/tools/rawfonts.sty Compatibility mode: package `' requested, but `rawfonts' provided. Package: rawfonts 1994/05/08 Low-level LaTeX 2.09 font compatibility (/home/tex/teTeX/texmf/tex/latex/tools/somedefs.sty Package: somedefs 1994/06/01 Toolkit for optional definitions ) LaTeX Font Info: Try loading font information for U+lasy on input line 36. (/home/tex/teTeX/texmf/tex/latex/base/ulasy.fd File: ulasy.fd 1996/11/20 v2.2dLaTeX symbol font definitions )))) (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size11.clo File: size11.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count83 \c@chapter=\count84 \c@section=\count85 \c@subsection=\count86 \c@subsubsection=\count87 \c@paragraph=\count88 \c@subparagraph=\count89 \c@figure=\count90 \c@table=\count91 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 Compatibility mode: definition of \rm ignored. Compatibility mode: definition of \sf ignored. Compatibility mode: definition of \tt ignored. Compatibility mode: definition of \bf ignored. Compatibility mode: definition of \it ignored. Compatibility mode: definition of \sl ignored. Compatibility mode: definition of \sc ignored. LaTeX Info: Redefining \cal on input line 622. LaTeX Info: Redefining \mit on input line 623. \bibindent=\dimen105 ) (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen106 \p@intvaluey=\dimen107 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. (intro.tex Chapter 1. LaTeX Font Info: External font `cmex10' loaded for size (Font) <10.95> on input line 5. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 5. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 5. LaTeX Font Info: Try loading font information for OMS+cmr on input line 16. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10.95> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 16. [1 ] psfig: searching ../../FrontMtx/doc/simple.eps for bounding box psfig: including ../../FrontMtx/doc/simple.eps [2] [3]) (dataStructure.tex [4] Overfull \hbox (12.9766pt too wide) in paragraph at lines 54--59 []\OT1/cmtt/m/n/10.95 Tree *tree \OT1/cmr/m/n/10.95 : Tree ob-ject that holds t he tree of fronts. Note, nor-mally this is \OT1/cmtt/m/n/10.95 frontETree->tree \OT1/cmr/m/n/10.95 , [] [5]) (proto.tex [6] [7] [8] [9] [10] Overfull \hbox (0.26903pt too wide) in paragraph at lines 411--411 [] \OT1/cmtt/m/n/10.95 int parent[], ChvList *aggList, ChvList *postList, Ch vManager *chvmanager,[] [] Overfull \hbox (11.7664pt too wide) in paragraph at lines 463--463 [] \OT1/cmtt/m/n/10.95 char inactiveFlag, int ms glvl, FILE *msgFile ) ;[] [] [11] Overfull \hbox (6.01772pt too wide) in paragraph at lines 529--529 [] \OT1/cmtt/m/n/10.95 char status[], DV *tempDV, int ms glvl, FILE *msgFile) ;[] [] [12] Overfull \hbox (0.26903pt too wide) in paragraph at lines 610--610 []\OT1/cmtt/m/n/10.95 Chv * FrontMtx_factorInpMtx ( FrontMtx *frontmtx, InpMtx *inpmtx, double tau,[] [] Overfull \hbox (0.26903pt too wide) in paragraph at lines 610--610 [] \OT1/cmtt/m/n/10.95 double cpus[], int stats[], int msgl vl, FILE *msgFile ) ;[] [] Overfull \hbox (0.26903pt too wide) in paragraph at lines 610--610 []\OT1/cmtt/m/n/10.95 Chv * FrontMtx_factorPencil ( FrontMtx *frontmtx, Pencil *pencil, double tau,[] [] Overfull \hbox (0.26903pt too wide) in paragraph at lines 610--610 [] \OT1/cmtt/m/n/10.95 double cpus[], int stats[], int msgl vl, FILE *msgFile ) ;[] [] [13] Overfull \hbox (2.58154pt too wide) in paragraph at lines 717--725 \OT1/cmr/m/it/10.95 Error check-ing: \OT1/cmr/m/n/10.95 If \OT1/cmtt/m/n/10.95 frontmtx\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 mtxA\OT1/cmr/m/n/10.95 , \OT1/ cmtt/m/n/10.95 rowsIVL\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 firstnz\OT1/cmr/ m/n/10.95 , \OT1/cmtt/m/n/10.95 updlist\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 chvmanager\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 status\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 colmap\OT1/cmr/m/n/10.95 , [] [14] Overfull \hbox (46.25853pt too wide) in paragraph at lines 765--765 [] \OT1/cmtt/m/n/10.95 ChvManager *chvmanager, int msglvl, FILE *msgFile ) ;[] [] LaTeX Font Info: External font `cmex10' loaded for size (Font) <12> on input line 779. Overfull \hbox (0.26903pt too wide) in paragraph at lines 833--833 []\OT1/cmtt/m/n/10.95 void FrontMtx_postProcess ( FrontMtx *frontmtx, int msgl vl, FILE *msgFile ) ;[] [] [15] Overfull \hbox (40.50984pt too wide) in paragraph at lines 891--891 []\OT1/cmtt/m/n/10.95 void FrontMtx_splitUpperMatrices ( FrontMtx *frontmtx, i nt msglvl, FILE *msgFile ) ;[] [] Overfull \hbox (40.50984pt too wide) in paragraph at lines 891--891 []\OT1/cmtt/m/n/10.95 void FrontMtx_splitLowerMatrices ( FrontMtx *frontmtx, i nt msglvl, FILE *msgFile ) ;[] [] [16] Overfull \hbox (11.7664pt too wide) in paragraph at lines 979--979 []\OT1/cmtt/m/n/10.95 IP ** FrontMtx_forwardSetup ( FrontMtx *frontmtx, int ms glvl, FILE *msgFile ) ;[] [] Overfull \hbox (17.51509pt too wide) in paragraph at lines 993--993 []\OT1/cmtt/m/n/10.95 IP ** FrontMtx_backwardSetup ( FrontMtx *frontmtx, int m sglvl, FILE *msgFile ) ;[] [] [17] Overfull \hbox (17.51509pt too wide) in paragraph at lines 1024--1024 [] \OT1/cmtt/m/n/10.95 SubMtxManager *mtxmanager, double cpus[], int m sglvl, FILE *msgFile ) ;[] [] [18] LaTeX Font Info: Try loading font information for OMS+cmtt on input line 114 2. LaTeX Font Info: No file OMScmtt.fd. on input line 1142. LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined (Font) using `OMS/cmsy/m/n' instead (Font) for symbol `textbraceleft' on input line 1142. Overfull \hbox (34.76115pt too wide) in paragraph at lines 1165--1165 []\OT1/cmtt/m/n/10.95 void FrontMtx_inertia ( FrontMtx *frontmtx, int *pnneg, int *pnzero, int *pnpos ) ;[] [] [19] [20]) (drivers.tex [21] [22]) (main.ind [23] [24 ] [25 ]) (main.aux) LaTeX Font Warning: Some font shapes were not available, defaults substituted. ) Here is how much of TeX's memory you used: 836 strings out of 10908 8802 string characters out of 72189 54462 words of memory out of 262141 3678 multiletter control sequences out of 9500 23753 words of font info for 89 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 22i,7n,21p,313b,426s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (25 pages, 81688 bytes). U/lasy/m/n --> U/lasy/b/n on input line 85. ) LaTeX Font Info: Redeclaring math delimiter \lgroup on input line 388. LaTeX Font Info: RedeclarFrontMtx/doc/main.idx010064400020550007177000000125640665022024100160560ustar00clevecompmath00000400000006\indexentry{FrontMtx_new@{\tt FrontMtx\_new()}}{7} \indexentry{FrontMtx_setDefaultFields@{\tt FrontMtx\_setDefaultFields()}}{7} \indexentry{FrontMtx_clearData@{\tt FrontMtx\_clearData()}}{7} \indexentry{FrontMtx_free@{\tt FrontMtx\_free()}}{7} \indexentry{FrontMtx_nfront@{\tt FrontMtx\_nfront()}}{7} \indexentry{FrontMtx_neqns@{\tt FrontMtx\_neqns()}}{7} \indexentry{FrontMtx_frontTree@{\tt FrontMtx\_frontTree()}}{8} \indexentry{FrontMtx_initialFrontDimensions@{\tt FrontMtx\_initialFrontDimensions()}}{8} \indexentry{FrontMtx_frontSize@{\tt FrontMtx\_frontSize()}}{8} \indexentry{FrontMtx_setFrontsize@{\tt FrontMtx\_setFrontSize()}}{8} \indexentry{FrontMtx_columnIndices@{\tt FrontMtx\_columnIndices()}}{8} \indexentry{FrontMtx_rowIndices@{\tt FrontMtx\_rowIndices()}}{8} \indexentry{FrontMtx_diagMtx@{\tt FrontMtx\_diagMtx()}}{8} \indexentry{FrontMtx_upperMtx@{\tt FrontMtx\_upperMtx()}}{9} \indexentry{FrontMtx_lowerMtx@{\tt FrontMtx\_lowerMtx()}}{9} \indexentry{FrontMtx_lowerAdjFronts@{\tt FrontMtx\_lowerAdjFronts()}}{9} \indexentry{FrontMtx_upperAdjFronts@{\tt FrontMtx\_upperAdjFronts()}}{9} \indexentry{FrontMtx_nLowerBlocks@{\tt FrontMtx\_nLowerBlocks()}}{9} \indexentry{FrontMtx_nUpperBlocks@{\tt FrontMtx\_nUpperBlocks()}}{9} \indexentry{FrontMtx_upperBlockIVL@{\tt FrontMtx\_upperBlockIVL()}}{9} \indexentry{FrontMtx_lowerBlockIVL@{\tt FrontMtx\_lowerBlockIVL()}}{9} \indexentry{FrontMtx_init@{\tt FrontMtx\_init()}}{10} \indexentry{FrontMtx_initializeFront@{\tt FrontMtx\_initializeFront()}}{10} \indexentry{FrontMtx_factorVisit@{\tt FrontMtx\_factorVisit()}}{11} \indexentry{FrontMtx_setupFront@{\tt FrontMtx\_setupFront()}}{11} \indexentry{FrontMtx_factorSetup@{\tt FrontMtx\_factorSetup()}}{11} \indexentry{FrontMtx_nactiveChild@{\tt FrontMtx\_nactiveChild()}}{11} \indexentry{FrontMtx_nactiveChild@{\tt FrontMtx\_nactiveChild()}}{11} \indexentry{FrontMtx_loadActiveLeaves@{\tt FrontMtx\_loadActiveLeaves()}}{11} \indexentry{FrontMtx_postList@{\tt FrontMtx\_postList()}}{12} \indexentry{FrontMtx_aggregateList@{\tt FrontMtx\_aggregateList()}}{12} \indexentry{FrontMtx_loadEntries@{\tt FrontMtx\_loadEntries()}}{12} \indexentry{FrontMtx_update@{\tt FrontMtx\_update()}}{12} \indexentry{FrontMtx_assemblePostponedData@{\tt FrontMtx\_assemblePostponedData()}}{12} \indexentry{FrontMtx_storePostponedData@{\tt FrontMtx\_storePostponedData()}}{12} \indexentry{FrontMtx_storeFront@{\tt FrontMtx\_storeFront()}}{13} \indexentry{FrontMtx_factorInpMtx@{\tt FrontMtx\_factorInpMtx()}}{13} \indexentry{FrontMtx_factorPencil@{\tt FrontMtx\_factorPencil()}}{13} \indexentry{FrontMtx_QR_setup@{\tt FrontMtx\_QR\_setup()}}{14} \indexentry{FrontMtx_QR_factorVisit@{\tt FrontMtx\_QR\_factorVisit()}}{14} \indexentry{FrontMtx_QR_assembleFront@{\tt FrontMtx\_QR\_assembleFront()}}{14} \indexentry{FrontMtx_QR_storeFront@{\tt FrontMtx\_QR\_storeFront()}}{15} \indexentry{FrontMtx_QR_storeUpdate@{\tt FrontMtx\_QR\_storeUpdate()}}{15} \indexentry{FrontMtx_QR_factor@{\tt FrontMtx\_QR\_factor()}}{15} \indexentry{FrontMtx_postProcess@{\tt FrontMtx\_postProcess()}}{16} \indexentry{FrontMtx_permuteUpperAdj@{\tt FrontMtx\_permuteUpperAdj()}}{16} \indexentry{FrontMtx_permuteLowerAdj@{\tt FrontMtx\_permuteLowerAdj()}}{16} \indexentry{FrontMtx_permuteUpperMatrices@{\tt FrontMtx\_permuteUpperMatrices()}}{16} \indexentry{FrontMtx_permuteLowerMatrices@{\tt FrontMtx\_permuteLowerMatrices()}}{16} \indexentry{FrontMtx_splitUpperMatrices@{\tt FrontMtx\_splitUpperMatrices()}}{16} \indexentry{FrontMtx_splitLowerMatrices@{\tt FrontMtx\_splitLowerMatrices()}}{16} \indexentry{FrontMtx_loadRightHandSide@{\tt FrontMtx\_loadRightHandSide()}}{16} \indexentry{FrontMtx_forwardVisit@{\tt FrontMtx\_forwardVisit()}}{17} \indexentry{FrontMtx_diagonalVisit@{\tt FrontMtx\_diagonalVisit()}}{17} \indexentry{FrontMtx_backwardVisit@{\tt FrontMtx\_backwardVisit()}}{17} \indexentry{FrontMtx_storeSolution@{\tt FrontMtx\_storeSolution()}}{17} \indexentry{FrontMtx_forwardSetup@{\tt FrontMtx\_forwardSetup()}}{17} \indexentry{FrontMtx_backwardSetup@{\tt FrontMtx\_backwardSetup()}}{17} \indexentry{FrontMtx_loadActiveRoots@{\tt FrontMtx\_loadActiveRoots()}}{18} \indexentry{FrontMtx_solve@{\tt FrontMtx\_solve()}}{18} \indexentry{FrontMtx_QR_solve@{\tt FrontMtx\_QR\_solve()}}{18} \indexentry{FrontMtx_colmapIV@{\tt FrontMtx\_colmapIV()}}{19} \indexentry{FrontMtx_rowmapIV@{\tt FrontMtx\_rowmapIV()}}{19} \indexentry{FrontMtx_ownedColumns@{\tt FrontMtx\_ownedColumns()}}{19} \indexentry{FrontMtx_ownedRows@{\tt FrontMtx\_ownedRows()}}{19} \indexentry{FrontMtx_makeUpperBlockIVL@{\tt FrontMtx\_makeUpperBlockIVL()}}{19} \indexentry{FrontMtx_makeLowerBlockIVL@{\tt FrontMtx\_makeLowerBlockIVL()}}{19} \indexentry{FrontMtx_inertia@{\tt FrontMtx\_inertia()}}{19} \indexentry{FrontMtx_nSolveOps@{\tt FrontMtx\_nSolveOps()}}{19} \indexentry{FrontMtx_readFromFile@{\tt FrontMtx\_readFromFile()}}{20} \indexentry{FrontMtx_readFromFormattedFile@{\tt FrontMtx\_readFromFormattedFile()}}{20} \indexentry{FrontMtx_readFromBinaryFile@{\tt FrontMtx\_readFromBinaryFile()}}{20} \indexentry{FrontMtx_writeToFile@{\tt FrontMtx\_writeToFile()}}{20} \indexentry{FrontMtx_writeToFormattedFile@{\tt FrontMtx\_writeToFormattedFile()}}{20} \indexentry{FrontMtx_writeToBinaryFile@{\tt FrontMtx\_writeToBinaryFile()}}{20} \indexentry{FrontMtx_writeForHumanEye@{\tt FrontMtx\_writeForHumanEye()}}{21} \indexentry{FrontMtx_writeStats@{\tt FrontMtx\_writeStats()}}{21} \indexentry{FrontMtx_writeForMatlab@{\tt FrontMtx\_writeForMatlab()}}{21} FrontMtx/doc/main.aux010064400020550007177000000050630665022024100160630ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt FrontMtx}: Front matrix}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structures}{4}} \newlabel{section:FrontMtx:dataStructure}{{1.1}{4}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt FrontMtx} methods}{6}} \newlabel{section:FrontMtx:proto}{{1.2}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{7}} \newlabel{subsection:FrontMtx:proto:basics}{{1.2.1}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Instance methods}{7}} \newlabel{subsection:FrontMtx:proto:instance}{{1.2.2}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Initialization methods}{10}} \newlabel{subsection:FrontMtx:proto:initialization}{{1.2.3}{10}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Utility Factorization methods}{10}} \newlabel{subsection:FrontMtx:proto:utility-factor}{{1.2.4}{10}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Serial Factorization method}{13}} \newlabel{subsection:FrontMtx:proto:factor}{{1.2.5}{13}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.6}QR factorization utility methods}{14}} \newlabel{subsection:FrontMtx:proto:utilityQR}{{1.2.6}{14}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.7}Serial $QR$ Factorization method}{15}} \newlabel{subsection:FrontMtx:proto:factorQR}{{1.2.7}{15}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.8}Postprocessing methods}{16}} \newlabel{subsection:FrontMtx:proto:postprocess}{{1.2.8}{16}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.9}Utility Solve methods}{16}} \newlabel{subsection:FrontMtx:proto:utility-solve}{{1.2.9}{16}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.10}Serial Solve method}{18}} \newlabel{subsection:FrontMtx:proto:solve-serial}{{1.2.10}{18}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.11}Serial $QR$ Solve method}{18}} \newlabel{subsection:FrontMtx:proto:QRsolve-serial}{{1.2.11}{18}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.12}Utility methods}{19}} \newlabel{subsection:FrontMtx:proto:utility}{{1.2.12}{19}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.13}IO methods}{20}} \newlabel{subsection:FrontMtx:proto:IO}{{1.2.13}{20}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs for the {\tt DFrontMtx} object}{21}} \newlabel{section:DFrontMtx:drivers}{{1.3}{21}} section:FrontMtx:proto:basics}{{1.2.1}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Instance methods}{7}} \newlabel{subsection:FrontMtx:proto:instance}{{1.2.2}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Initialization methods}{10}} \newlabel{subsection:FrontMtx:proto:initialization}{{1.2.3}{10}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Utility Factorization methods}{10}} \newlabel{subsectioFrontMtx/doc/makefile010064400020550007177000000000270657126717400161350ustar00clevecompmath00000400000006clean : - rm -f *.dvi FrontMtx/doc/main.ind010064400020550007177000000063050657206576100160610ustar00clevecompmath00000400000006\begin{theindex} \item {\tt FrontMtx\_aggregateList()}, 12 \item {\tt FrontMtx\_assemblePostponedData()}, 12 \item {\tt FrontMtx\_backwardSetup()}, 17 \item {\tt FrontMtx\_backwardVisit()}, 17 \item {\tt FrontMtx\_clearData()}, 7 \item {\tt FrontMtx\_colmapIV()}, 19 \item {\tt FrontMtx\_columnIndices()}, 8 \item {\tt FrontMtx\_diagMtx()}, 8 \item {\tt FrontMtx\_diagonalVisit()}, 17 \item {\tt FrontMtx\_factorInpMtx()}, 13 \item {\tt FrontMtx\_factorPencil()}, 13 \item {\tt FrontMtx\_factorSetup()}, 11 \item {\tt FrontMtx\_factorVisit()}, 11 \item {\tt FrontMtx\_forwardSetup()}, 17 \item {\tt FrontMtx\_forwardVisit()}, 17 \item {\tt FrontMtx\_free()}, 7 \item {\tt FrontMtx\_frontSize()}, 8 \item {\tt FrontMtx\_frontTree()}, 8 \item {\tt FrontMtx\_inertia()}, 19 \item {\tt FrontMtx\_init()}, 10 \item {\tt FrontMtx\_initialFrontDimensions()}, 8 \item {\tt FrontMtx\_initializeFront()}, 10 \item {\tt FrontMtx\_loadActiveLeaves()}, 11 \item {\tt FrontMtx\_loadActiveRoots()}, 18 \item {\tt FrontMtx\_loadEntries()}, 12 \item {\tt FrontMtx\_loadRightHandSide()}, 17 \item {\tt FrontMtx\_lowerAdjFronts()}, 9 \item {\tt FrontMtx\_lowerBlockIVL()}, 9 \item {\tt FrontMtx\_lowerMtx()}, 9 \item {\tt FrontMtx\_makeLowerBlockIVL()}, 19 \item {\tt FrontMtx\_makeUpperBlockIVL()}, 19 \item {\tt FrontMtx\_nactiveChild()}, 11 \item {\tt FrontMtx\_neqns()}, 7 \item {\tt FrontMtx\_new()}, 7 \item {\tt FrontMtx\_nfront()}, 7 \item {\tt FrontMtx\_nLowerBlocks()}, 9 \item {\tt FrontMtx\_nUpperBlocks()}, 9 \item {\tt FrontMtx\_ownedColumns()}, 19 \item {\tt FrontMtx\_ownedRows()}, 19 \item {\tt FrontMtx\_permuteLowerAdj()}, 16 \item {\tt FrontMtx\_permuteLowerMatrices()}, 16 \item {\tt FrontMtx\_permuteUpperAdj()}, 16 \item {\tt FrontMtx\_permuteUpperMatrices()}, 16 \item {\tt FrontMtx\_postList()}, 12 \item {\tt FrontMtx\_postProcess()}, 16 \item {\tt FrontMtx\_QR\_assembleFront()}, 14 \item {\tt FrontMtx\_QR\_factor()}, 15 \item {\tt FrontMtx\_QR\_factorVisit()}, 14 \item {\tt FrontMtx\_QR\_setup()}, 14 \item {\tt FrontMtx\_QR\_solve()}, 18 \item {\tt FrontMtx\_QR\_storeFront()}, 15 \item {\tt FrontMtx\_QR\_storeUpdate()}, 15 \item {\tt FrontMtx\_readFromBinaryFile()}, 20 \item {\tt FrontMtx\_readFromFile()}, 20 \item {\tt FrontMtx\_readFromFormattedFile()}, 20 \item {\tt FrontMtx\_rowIndices()}, 8 \item {\tt FrontMtx\_rowmapIV()}, 19 \item {\tt FrontMtx\_setDefaultFields()}, 7 \item {\tt FrontMtx\_setFrontSize()}, 8 \item {\tt FrontMtx\_setupFront()}, 11 \item {\tt FrontMtx\_solve()}, 18 \item {\tt FrontMtx\_splitLowerMatrices()}, 16 \item {\tt FrontMtx\_splitUpperMatrices()}, 16 \item {\tt FrontMtx\_storeFront()}, 13 \item {\tt FrontMtx\_storePostponedData()}, 12 \item {\tt FrontMtx\_storeSolution()}, 17 \item {\tt FrontMtx\_update()}, 12 \item {\tt FrontMtx\_upperAdjFronts()}, 9 \item {\tt FrontMtx\_upperBlockIVL()}, 9 \item {\tt FrontMtx\_upperMtx()}, 9 \item {\tt FrontMtx\_writeForHumanEye()}, 20 \item {\tt FrontMtx\_writeStats()}, 21 \item {\tt FrontMtx\_writeToBinaryFile()}, 20 \item {\tt FrontMtx\_writeToFile()}, 20 \item {\tt FrontMtx\_writeToFormattedFile()}, 20 \end{theindex} FrontMtx/doc/main.ilg010064400020550007177000000004570657206576100160640ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (76 entries accepted, 0 rejected). Sorting entries....done (483 comparisons). Generating output file main.ind....done (79 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. FrontMtx/doc/simple.eps010064400020550007177000000002700657126717400164370ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 100.0 100.0 %%%EndComments 0.5 setgray 25 0 75 75 rectfill 1.0 setgray 50 0 50 50 rectfill 0.0 setgray 0 0 100 100 rectstroke showpage GPart.h010064400020550007177000000001000653410640200132460ustar00clevecompmath00000400000006#ifndef _GPart_ #define _GPart_ #include "GPart/GPart.h" #endif GPart/DDsepInfo.h010064400020550007177000000074210654004360600151010ustar00clevecompmath00000400000006/* DDsepInfo.h */ #ifndef _DDsepInfo_ #define _DDsepInfo_ #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- this structure is used in the GPart_RBviaDDSEP method seed -- random number seed minweight -- minimum weight for any fishnet domain, default value is 50 maxweight -- maximum weight for any fishnet domain, default value is 100 freeze -- multiplier used to freeze nodes in the multisector, default value is 4.0 alpha -- cost function parameter, default value is 1.0 maxcompweight -- any leaf component must have weight less than this value ntreeobj -- accumulator for the number of objects in the domain/separator tree DDoption -- option for finding domain decomposition 1 --> use Fishnet on each subgraph 2 --> use Fishnet on graph, then projection on each subgraph nlayer -- number of layers to be used in the smoothing process 2 --> use two-sided dulmage-mendelsohn smoothing 2k+1 --> use k layers of wide separator smoothing cpuDD -- cpu time for domain decomposition cpuMap -- cpu time to compute the domain/segment maps cpuBPG -- cpu time to create the domain/segment bipartite graphs cpuBKL -- cpu time to find the initial separators using the block kernihan-lin algorithm cpuSmooth -- cpu time to smooth the separators cpuSplit -- cpu time to split the subgraphs cpuTotal -- total cpu time msglvl -- message level, default value is 0 msgFile -- message file, default is stdout --------------------------------------------------------------------- */ typedef struct _DDsepInfo { int seed ; int minweight ; int maxweight ; double freeze ; double alpha ; int maxcompweight ; int ntreeobj ; int DDoption ; int nlayer ; double cpuDD ; double cpuMap ; double cpuBPG ; double cpuBKL ; double cpuSmooth ; double cpuSplit ; double cpuTotal ; int msglvl ; FILE *msgFile ; } DDsepInfo ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in DDsepInfo.c ----------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------ construct a new instance of the DDsepInfo object created -- 96feb24, cca ------------------------------------------------ */ DDsepInfo * DDsepInfo_new ( void ) ; /* --------------------------------------------- set the default fields of the DDsepInfo object created -- 96feb24, cca --------------------------------------------- */ void DDsepInfo_setDefaultFields ( DDsepInfo *info ) ; /* --------------------------------------------- clear the data fields for a DDsepInfo object created -- 96feb24, cca --------------------------------------------- */ void DDsepInfo_clearData ( DDsepInfo *info ) ; /* ------------------------ free the DDsepInfo object created -- 96feb24, cca ------------------------ */ void DDsepInfo_free ( DDsepInfo *info ) ; /* ----------------------- write the CPU times created -- 97nov06, cca ----------------------- */ void DDsepInfo_writeCpuTimes ( DDsepInfo *info, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ #endif GPart/GPart.h010064400020550007177000000372420654004361700143110ustar00clevecompmath00000400000006/* GPart.h */ #include "../Graph.h" #include "../BPG.h" #include "../DSTree.h" #include "../Tree.h" #include "../IV.h" #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- The GPart object is used to generate and store information about a partition of the graph. id -- id for the object g -- pointer to Graph object, not free'd by the destructor nvtx -- # of vertices in the graph, internal vertices only nvbnd -- # of vertices in the boundary of the graph, ncomp -- # of components in the graph compidsIV -- IV object that contains a map from vertices to components, size nvtx compids[v] == 0 --> v is on the interface compids[v] != 0 --> v belongs to domain compids[v] cweightsIV -- IV object that contains the component weights par -- pointer to parent GPart object fch -- pointer to first child GPart object sib -- pointer to sibling GPart object vtxMapIV -- IV object that contains a map map from local vertices to parent's vertices or global vertices msglvl -- message level, default is zero msgFile -- message file pointer, default is stdout created -- 95oct21, cca ---------------------------------------------------------------- */ typedef struct _GPart GPart ; struct _GPart { int id ; Graph *g ; int nvtx ; int nvbnd ; int ncomp ; IV compidsIV ; IV cweightsIV ; GPart *par ; GPart *fch ; GPart *sib ; IV vtxMapIV ; int msglvl ; FILE *msgFile ; } ; /* ------------------------------------------ include the DDsepInfo object's header file ------------------------------------------ */ #include "DDsepInfo.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c -------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------- construct a new instance of the GPart object created -- 95oct05, cca -------------------------------------------- */ GPart * GPart_new ( void ) ; /* --------------------------------------------- set the default fields of the GPart object created -- 95oct05, cca modified -- 95nov29, cca par, fch, sib and vtxMap fields included --------------------------------------------- */ void GPart_setDefaultFields ( GPart *gpart ) ; /* --------------------------------------------- clear the data fields for a GPart object created -- 95oct05, cca modified -- 95nov29, cca par, fch, sib and vtxMap fields included --------------------------------------------- */ void GPart_clearData ( GPart *gpart ) ; /* ------------------------ free the GPart object created -- 95oct05, cca modified -- 95nov29, cca gpart now free'd ------------------------ */ void GPart_free ( GPart *gpart ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in DDviaFishnet.c -------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------------- purpose -- to construct and return a multisector using the fishnet algorithm freeze -- parameter used to keep nodes of high degree in the interface minweight -- minimum weight for a domain maxweight -- maximum weight for a domain seed -- random number seed created -- 96feb16, cca --------------------------------------------------------------- */ void GPart_DDviaFishnet ( GPart *gpart, double freeze, int minweight, int maxweight, int seed ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in DDviaProjection.c ----------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------- set the compids[] vector using a global map from vertices to domains and interface nodes. DDmapIV -- IV object that contains the map from vertices to domains and interface nodes created -- 96mar17, cca --------------------------------------------------------- */ void GPart_DDviaProjection ( GPart *gpart, IV *DDmapIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in DDsepInfo.c ----------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------ construct a new instance of the DDsepInfo object created -- 96feb24, cca ------------------------------------------------ */ DDsepInfo * DDsepInfo_new ( void ) ; /* --------------------------------------------- set the default fields of the DDsepInfo object created -- 96feb24, cca --------------------------------------------- */ void DDsepInfo_setDefaultFields ( DDsepInfo *info ) ; /* --------------------------------------------- clear the data fields for a DDsepInfo object created -- 96feb24, cca --------------------------------------------- */ void DDsepInfo_clearData ( DDsepInfo *info ) ; /* ------------------------ free the DDsepInfo object created -- 96feb24, cca ------------------------ */ void DDsepInfo_free ( DDsepInfo *info ) ; /* ----------------------- write the CPU times created -- 97nov06, cca ----------------------- */ void DDsepInfo_writeCpuTimes ( DDsepInfo *info, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in domSegMap.c ----------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------------- fill *pndom with ndom, the number of domains. fill *pnseg with nseg, the number of segments. domains are numbered in [0, ndom), segments in [ndom,ndom+nseg). return -- an IV object that contains the map from vertices to segments created -- 99feb29, cca -------------------------------------------------------------------- */ IV * GPart_domSegMap ( GPart *gpart, int *pndom, int *pnseg ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in identifyWideSep.c ----------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- identify the wide separator return -- IV object that holds the nodes in the wide separator created -- 96oct21, cca -------------------------------------------------------------- */ IV * GPart_identifyWideSep ( GPart *gpart, int nlevel1, int nlevel2 ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ---------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------- initialize the GPart object created -- 95oct05, cca --------------------------- */ void GPart_init ( GPart *gpart, Graph *g ) ; /* ----------------------- set the message fields created -- 96oct21, cca ----------------------- */ void GPart_setMessageInfo ( GPart *gpart, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in makeYCmap.c ----------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------- make the map from wide separator vertices Y to components {0, 1, 2, 3}. YCmap[y] == 0 --> y is not adjacent to either component YCmap[y] == 1 --> y is adjacent to only component 1 YCmap[y] == 2 --> y is adjacent to only component 2 YCmap[y] == 3 --> y is adjacent to components 1 and 2 created -- 96jun09, cca ------------------------------------------------------- */ IV * GPart_makeYCmap ( GPart *gpart, IV *YVmapIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in RBviaDDsep.c ---------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------- this method constructs recursive partition of a graph. it returns a DSTree object to represent the splitting of the tree into subgraphs. the info object contains the information needed by the DDsep algorithm. created -- 96feb24, cca -------------------------------------------------------- */ DSTree * GPart_RBviaDDsep ( GPart *gpart, DDsepInfo *info ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in smoothBisector.c ------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------------------------------- smooth a wide separator nlevel -- number of levels one each side of the separator to include into the separator alpha -- partition cost function parameter created -- 96jun02, cca --------------------------------------------------------- */ float GPart_smoothBisector ( GPart *gpart, int nlevel, float alpha ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in smoothBy2layers.c ----------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- smooth a bisector using the alternating two-layer algorithm option -- network flag 1 --> make the network bipartite as for the Dulmage-Mendelsohn decomposition otherwise -- use network induced by the wide separator alpha -- cost function parameter created -- 96jun08, cca ----------------------------------------------------------- */ void GPart_smoothBy2layers ( GPart *gpart, int option, float alpha ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in smoothYSep.c ---------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ smooth the wide separator given by YVmapIV by forming the associated network, solving the max flow problem, and examining two min-cuts. YVmapIV -- map from wide vertices Y to vertices V YCmapIV -- map from wide vertices Y to {0,1,2,3} YCmap[y] = 0 --> treat y as an internal node adjacent to neither component YCmap[y] = 1 --> treat y as adjacent only to component 1 YCmap[y] = 2 --> treat y as adjacent only to component 2 YCmap[y] = 3 --> treat y as adjacent to components 1 and 2 alpha -- cost function parameter created -- 96jun08, cca ------------------------------------------------------------ */ float GPart_smoothYSep ( GPart *gpart, IV *YVmapIV, IV *YCmapIV, float alpha ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in split.c --------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------- split the graph partition object into pieces created -- 95nov29, cca -------------------------------------------- */ void GPart_split ( GPart *gpart ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in TwoSetViaBKL.c -------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------------- given a domain decomposition, find a bisector 1. construct the domain/segment graph 2. use block kernihan-lin to get an initial bisector alpha -- cost function parameter for BKL seed -- random number seed cpus -- array to store CPU times cpus[0] -- time to find domain/segment map cpus[1] -- time to find domain/segment bipartite graph cpus[2] -- time to find two-set partition return value -- cost of the partition created -- 96mar09, cca ----------------------------------------------------------------- */ double GPart_TwoSetViaBKL ( GPart *gpart, double alpha, int seed, double cpus[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------- set the component weights from the compids[] vector created -- 95oct05, cca modified -- 95nov29, cca ---------------------------------------------------- */ void GPart_setCweights ( GPart *gpart ) ; /* ---------------------------------------------- return the number of bytes taken by the object created -- 95oct05, cca ---------------------------------------------- */ int GPart_sizeOf ( GPart *gpart ) ; /* ---------------------------------------------------- return 1 if vertex is adjacent to only one domain and fill *pdomid with the domain's id return 0 otherwise created -- 95oct19, cca ------------------------------------------------- */ int GPart_vtxIsAdjToOneDomain ( GPart *gpart, int v, int *pdomid ) ; /* ------------------------------------------------------ return 1 if the partition has a valid vertex separator 0 otherwise created -- 95oct18, cca ------------------------------------------------------ */ int GPart_validVtxSep ( GPart *gpart ) ; /* ------------------------------------- return an IV object filled with the weights of the component's boundaries created -- 96oct21, cca ------------------------------------- */ IV * GPart_bndWeightsIV ( GPart *gpart ) ; /*--------------------------------------------------------------------*/ GPart/makefile010064400020550007177000000002230663622360100146070ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean GPart/src/makefile010064400020550007177000000014460663602323200154040ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = GPart $(OBJ).a : \ $(OBJ).a(DDviaFishnet.o) \ $(OBJ).a(DDviaProjection.o) \ $(OBJ).a(DDsepInfo.o) \ $(OBJ).a(RBviaDDsep.o) \ $(OBJ).a(TwoSetViaBKL.o) \ $(OBJ).a(basics.o) \ $(OBJ).a(domSegMap.o) \ $(OBJ).a(identifyWideSep.o) \ $(OBJ).a(init.o) \ $(OBJ).a(makeYCmap.o) \ $(OBJ).a(smoothBisector.o) \ $(OBJ).a(smoothBy2layers.o) \ $(OBJ).a(smoothYSep.o) \ $(OBJ).a(split.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG GPart/src/makeGlobalLib010064400020550007177000000011720660026102500163030ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = GPart SRC = DDviaFishnet.c \ DDviaProjection.c \ DDsepInfo.c \ RBviaDDsep.c \ TwoSetViaBKL.c \ basics.c \ domSegMap.c \ identifyWideSep.c \ init.c \ makeYCmap.c \ smoothBisector.c \ smoothBy2layers.c \ smoothYSep.c \ split.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a GPart/src/DDsepInfo.c010064400020550007177000000101160653410612000156500ustar00clevecompmath00000400000006/* DDsepInfo.c */ #include "../DDsepInfo.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------ construct a new instance of the DDsepInfo object created -- 96feb24, cca ------------------------------------------------ */ DDsepInfo * DDsepInfo_new ( void ) { DDsepInfo *info ; ALLOCATE(info, struct _DDsepInfo, 1) ; DDsepInfo_setDefaultFields(info) ; return(info) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- set the default fields of the DDsepInfo object created -- 96feb24, cca --------------------------------------------- */ void DDsepInfo_setDefaultFields ( DDsepInfo *info ) { if ( info == NULL ) { fprintf(stderr, "\n fatal error in DDsepInfo_setDefaultFields(%p)" "\n bad input\n", info) ; exit(-1) ; } info->seed = 1 ; info->minweight = 40 ; info->maxweight = 80 ; info->freeze = 4.0 ; info->alpha = 1.0 ; info->maxcompweight = 500 ; info->ntreeobj = 0 ; info->DDoption = 1 ; info->nlayer = 3 ; info->cpuDD = 0.0 ; info->cpuMap = 0.0 ; info->cpuBPG = 0.0 ; info->cpuBKL = 0.0 ; info->cpuSmooth = 0.0 ; info->cpuSplit = 0.0 ; info->cpuTotal = 0.0 ; info->msglvl = 0 ; info->msgFile = stdout ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- clear the data fields for a DDsepInfo object created -- 96feb24, cca --------------------------------------------- */ void DDsepInfo_clearData ( DDsepInfo *info ) { if ( info == NULL ) { fprintf(stderr, "\n fatal error in DDsepInfo_clearData(%p)" "\n bad input\n", info) ; exit(-1) ; } DDsepInfo_setDefaultFields(info) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------ free the DDsepInfo object created -- 96feb24, cca ------------------------ */ void DDsepInfo_free ( DDsepInfo *info ) { if ( info == NULL ) { fprintf(stderr, "\n fatal error in DDsepInfo_free(%p)" "\n bad input\n", info) ; exit(-1) ; } DDsepInfo_clearData(info) ; #if MYDEBUG > 0 fprintf(stdout, "\n trying to free info") ; fflush(stdout) ; #endif FREE(info) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- write the CPU times created -- 97nov06, cca ----------------------- */ void DDsepInfo_writeCpuTimes ( DDsepInfo *info, FILE *msgFile ) { double cpuMisc ; /* --------------- check the input --------------- */ if ( info == NULL || msgFile == NULL ) { fprintf(stderr, "\n fatal error in DDsepInfo_writeCpuTimes(%p,%p)" "\n bad input\n", info, msgFile) ; exit(-1) ; } cpuMisc = info->cpuTotal - info->cpuDD - info->cpuSplit - info->cpuMap - info->cpuBPG - info->cpuBKL - info->cpuSmooth ; if ( info->cpuTotal > 0 ) { fprintf(msgFile, "\n\n CPU breakdown for graph partition" "\n raw CPU per cent" "\n misc : %9.2f %6.1f%%" "\n Split : %9.2f %6.1f%%" "\n find DD : %9.2f %6.1f%%" "\n DomSeg Map : %9.2f %6.1f%%" "\n DomSeg BPG : %9.2f %6.1f%%" "\n BKL : %9.2f %6.1f%%" "\n Smooth : %9.2f %6.1f%%" "\n Total : %9.2f %6.1f%%", cpuMisc, 100.*cpuMisc/info->cpuTotal, info->cpuSplit, 100.*info->cpuSplit/info->cpuTotal, info->cpuDD, 100.*info->cpuDD/info->cpuTotal, info->cpuMap, 100.*info->cpuMap/info->cpuTotal, info->cpuBPG, 100.*info->cpuBPG/info->cpuTotal, info->cpuBKL, 100.*info->cpuBKL/info->cpuTotal, info->cpuSmooth, 100.*info->cpuSmooth/info->cpuTotal, info->cpuTotal, 100.) ; } return ; } /*--------------------------------------------------------------------*/ GPart/src/DDviaFishnet.c010064400020550007177000000420130653410612000163460ustar00clevecompmath00000400000006/* DDviaFishnet.c */ #include "../GPart.h" #include "../../IIheap.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* --------------------------------- declarations for static functions --------------------------------- */ static int GPart_freeze ( GPart *gpart, double freeze, int extdegs[] ) ; static void GPart_indpSetGrowth ( GPart *gpart, int maxWeight, int seed ) ; static void GPart_absDomains ( GPart *gpart, int minweight ) ; static void GPart_absBoundary ( GPart *gpart ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to construct and return a multisector using the fishnet algorithm freeze -- parameter used to keep nodes of high degree in the interface minweight -- minimum weight for a domain maxweight -- maximum weight for a domain seed -- random number seed created -- 96feb16, cca --------------------------------------------------------------- */ void GPart_DDviaFishnet ( GPart *gpart, double freeze, int minweight, int maxweight, int seed ) { double cpus[6], t1, t2 ; int nV, v ; int *extdegs ; /* --------------- check the input --------------- */ if ( gpart == NULL || freeze < 0.0 || minweight < 0 || maxweight < 0 || minweight >= maxweight ) { fprintf(stderr, "\n fatal error in GPart_DDviaFishnet(%p,%f,%d,%d,%d)" "\n bad input\n", gpart, freeze, minweight, maxweight, seed) ; exit(-1) ; } /* ---------------------------- compute the external degrees ---------------------------- */ MARKTIME(t1) ; nV = gpart->g->nvtx ; extdegs = IVinit(nV, 0) ; for ( v = 0 ; v < nV ; v++ ) { extdegs[v] = Graph_externalDegree(gpart->g, v) ; } MARKTIME(t2) ; cpus[0] = t2 - t1 ; /* ------------------- freeze the vertices ------------------- */ MARKTIME(t1) ; GPart_freeze(gpart, freeze, extdegs) ; MARKTIME(t2) ; cpus[1] = t2 - t1 ; /* --------------------------------------------- grow the partition via independent set growth --------------------------------------------- */ MARKTIME(t1) ; GPart_indpSetGrowth(gpart, maxweight, seed) ; IVfree(extdegs) ; MARKTIME(t2) ; cpus[2] = t2 - t1 ; if ( gpart->ncomp == 1 ) { IV_fill(&gpart->compidsIV, 1) ; return ; } /* ------------------------ absorb the small domains ------------------------ */ MARKTIME(t1) ; GPart_absDomains(gpart, minweight) ; MARKTIME(t2) ; cpus[3] = t2 - t1 ; if ( gpart->ncomp <= 1 ) { IV_fill(&gpart->compidsIV, 1) ; return ; } /* -------------------------- absorb the excess boundary -------------------------- */ MARKTIME(t1) ; GPart_absBoundary(gpart) ; MARKTIME(t2) ; cpus[4] = t2 - t1 ; if ( gpart->msglvl > 1 ) { fprintf(gpart->msgFile, "\n FISHNET CPU breakdown" "\n CPU %8.3f : compute external degrees" "\n CPU %8.3f : freeze vertices of high degree" "\n CPU %8.3f : independent set growth" "\n CPU %8.3f : absorb small domains" "\n CPU %8.3f : absorb excess boundary", cpus[0], cpus[1], cpus[2], cpus[3], cpus[4]) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- freeze vertices into the interface that have external degree >= freeze * cutoff return value -- # of frozen vertices created -- 95oct05, cca --------------------------------------- */ static int GPart_freeze ( GPart *gpart, double freeze, int extdegs[] ) { Graph *g ; int cutoff, iv, median, nfrozen, nvtx ; int *compids, *vids ; /* --------------- check the input --------------- */ if ( gpart == NULL || (g = gpart->g) == NULL || extdegs == NULL ) { fprintf(stderr, "\n fatal error in GPart_freeze(%p,%f,%p)" "\n bad input\n", gpart, freeze, extdegs) ; exit(-1) ; } nvtx = gpart->nvtx ; compids = IV_entries(&gpart->compidsIV) ; /* ------------------------------------------------------- sort the vertices in ascending order of external degree ------------------------------------------------------- */ vids = IVinit(nvtx, 0) ; IVramp(nvtx, vids, 0, 1) ; if ( gpart->msglvl > 3 ) { int v ; for ( v = 0 ; v < nvtx ; v++ ) { fprintf(gpart->msgFile, "\n vertex %d, external degree %d", v, extdegs[v]) ; fflush(gpart->msgFile) ; } } IV2qsortUp(nvtx, extdegs, vids) ; /* -------------------------------- get the median and cutoff values -------------------------------- */ median = extdegs[nvtx/2] ; cutoff = (int) (freeze * median) ; if ( gpart->msglvl > 2 ) { fprintf(gpart->msgFile, "\n median = %d, cutoff = %d", median, cutoff) ; fflush(gpart->msgFile) ; } /* ------------------------------------------------------- freeze vertices whose degree is greater than the cutoff ------------------------------------------------------- */ nfrozen = 0 ; for ( iv = nvtx - 1 ; iv >= 0 ; iv-- ) { if ( extdegs[iv] < cutoff ) { break ; } compids[vids[iv]] = 0 ; nfrozen++ ; } /* ------------------------ free the working storage ------------------------ */ IVfree(vids) ; return(nfrozen) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- set up the partition via independent set growth maxWeight -- maximum weight for any domain seed -- random number seed, if seed > 0 then the vertices are visited in some random order, else the vertices are visited 0, 1, ..., nvtx - 1 note : the gpart->compids[] vector is assumed to be initialized outside this method. any vertex v such that compids[v] == -1 is eligible to be put into a domain. this allows the user to pre-specify vertices to be in the separator (by setting compids[v] = -1 prior to calling this method), e.g., vertices of abnormally high degree should be forced to be separator vertices. created -- 95oct05, cca ------------------------------------------------------------------- */ static void GPart_indpSetGrowth ( GPart *gpart, int maxWeight, int seed ) { Graph *g ; int domweight, i, iv, last, ndom, now, nvtx, v, vsize, w ; int *compids, *cweights, *list, *vadj, *vids, *vwghts ; /* --------------- check the input --------------- */ if ( gpart == NULL || (g = gpart->g) == NULL || maxWeight < 0 ) { fprintf(stderr, "\n fatal error in GPart_indpSepGrowth(%p,%d,%d)" "\n bad input\n", gpart, maxWeight, seed) ; exit(-1) ; } vwghts = g->vwghts ; /* -------------------------------- set all component ids != 0 to -1 -------------------------------- */ nvtx = gpart->nvtx ; compids = IV_entries(&gpart->compidsIV) ; for ( v = 0 ; v < nvtx ; v++ ) { if ( compids[v] != 0 ) { compids[v] = -1 ; } } /* ----------------------------------------------------------------- set up the vector that determines the order to visit the vertices ----------------------------------------------------------------- */ vids = IVinit2(nvtx) ; IVramp(nvtx, vids, 0, 1) ; if ( seed > 0 ) { IVshuffle(nvtx, vids, seed) ; } /* ------------------------------ set up the working list vector ------------------------------ */ list = IVinit(nvtx, -1) ; /* ----------------------------------- visit the vertices and grow domains ----------------------------------- */ ndom = 0 ; for ( iv = 0 ; iv < nvtx ; iv++ ) { v = vids[iv] ; if ( gpart->msglvl > 4 ) { fprintf(gpart->msgFile, "\n\n visiting v = %d, compids[%d] = %d", v, v, compids[v]) ; } if ( compids[v] == -1 ) { /* ----------------------------------------- eligible vertex has not yet been visited, create a new domain with v as the seed ----------------------------------------- */ ndom++ ; if ( gpart->msglvl > 3 ) { fprintf(gpart->msgFile, "\n\n domain %d : seed vertex %d", ndom, v) ; fflush(gpart->msgFile) ; } domweight = 0 ; now = last = 0 ; list[0] = v ; while ( now <= last ) { v = list[now++] ; if ( gpart->msglvl > 4 ) { fprintf(gpart->msgFile, "\n adding %d to domain %d, weight %d", v, ndom, ((vwghts != NULL) ? vwghts[v] : 1)) ; fflush(gpart->msgFile) ; } /* --------------------- add v to domain icomp --------------------- */ compids[v] = ndom ; domweight += (vwghts != NULL) ? vwghts[v] : 1 ; Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( i = 0 ; i < vsize ; i++ ) { if ( (w = vadj[i]) < nvtx && compids[w] == -1 ) { /* ----------------------------------------- w has not yet been touched, put on list set compids[w] = -2 to make sure it isn't put on the list twice ----------------------------------------- */ compids[w] = -2 ; list[++last] = w ; } } if ( domweight >= maxWeight ) { /* --------------------------------------------- domain is large enough, mark all the rest of the vertices in the list as boundary vertices --------------------------------------------- */ while ( now <= last ) { w = list[now++] ; if ( gpart->msglvl > 4 ) { fprintf(gpart->msgFile, "\n adding %d to interface, weight %d", w, ((vwghts != NULL) ? vwghts[w] : 1)) ; fflush(gpart->msgFile) ; } compids[w] = 0 ; } } } if ( gpart->msglvl > 2 ) { fprintf(gpart->msgFile, "\n domain %d, weight %d", ndom, domweight) ; fflush(gpart->msgFile) ; } } } /* --------------------------------------------------------------------- set the number of components and resize the component weights vector --------------------------------------------------------------------- */ gpart->ncomp = ndom ; IV_setSize(&gpart->cweightsIV, 1 + ndom) ; IV_fill(&gpart->cweightsIV, 0) ; cweights = IV_entries(&gpart->cweightsIV) ; /* ----------------------------------------------- set the weights of the interface and components ----------------------------------------------- */ if ( vwghts != NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { cweights[compids[v]] += vwghts[v] ; } } else { for ( v = 0 ; v < nvtx ; v++ ) { cweights[compids[v]]++ ; } } /* ------------------------- free the two work vectors ------------------------- */ IVfree(list) ; IVfree(vids) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ absorb small domains into the interface. this method assumes that the component weights vector has been set 95oct05, cca ------------------------------------------------------------------ */ static void GPart_absDomains ( GPart *gpart, int minweight ) { Graph *g ; int c, ierr, ndom, nnewdom, nvtx, v ; int *compids, *cweights, *dmap, *head, *link, *vwghts ; /* --------------- check the input --------------- */ if ( gpart == NULL || (g = gpart->g) == NULL ) { fprintf(stderr, "\n fatal error in GPart_absDomains(%p,%d)" "\n bad input\n", gpart, minweight) ; exit(-1) ; } nvtx = gpart->nvtx ; vwghts = g->vwghts ; ndom = gpart->ncomp ; compids = IV_entries(&gpart->compidsIV) ; cweights = IV_entries(&gpart->cweightsIV) ; /* ---------------------------------------------- get the linked list for vertices and component ---------------------------------------------- */ head = IVinit(ndom+1, -1) ; link = IVinit(nvtx, -1) ; for ( v = 0 ; v < nvtx ; v++ ) { c = compids[v] ; link[v] = head[c] ; head[c] = v ; } dmap = IVinit(ndom+1, -1) ; nnewdom = 0 ; dmap[0] = 0 ; for ( c = 1 ; c <= ndom ; c++ ) { if ( cweights[c] < minweight ) { if ( gpart->msglvl > 2 ) { fprintf(gpart->msgFile, "\n interface absorbs component %d, weight %d", c, cweights[c]) ; fflush(gpart->msgFile) ; } for ( v = head[c] ; v != -1 ; v = link[v] ) { compids[v] = 0 ; } cweights[0] += cweights[c] ; cweights[c] = 0 ; dmap[c] = 0 ; } else { dmap[c] = ++nnewdom ; } if ( gpart->msglvl > 2 ) { fprintf(gpart->msgFile, "\n dmap[%d] = %d", c, dmap[c]) ; fflush(gpart->msgFile) ; } } if ( nnewdom != ndom ) { /* ------------------------ set the new # of domains ------------------------ */ gpart->ncomp = nnewdom ; /* ------------------------- set the new component ids ------------------------- */ if ( gpart->msglvl > 3 ) { fprintf(gpart->msgFile, "\n old component ids") ; IVfp80(gpart->msgFile, nvtx, compids, 80, &ierr) ; fflush(gpart->msgFile) ; } for ( v = 0 ; v < nvtx ; v++ ) { c = compids[v] ; compids[v] = dmap[c] ; } if ( gpart->msglvl > 3 ) { fprintf(gpart->msgFile, "\n new component ids") ; IVfp80(gpart->msgFile, nvtx, compids, 80, &ierr) ; fflush(gpart->msgFile) ; } /* ----------------------------- set the new component weights ----------------------------- */ if ( gpart->msglvl > 2 ) { fprintf(gpart->msgFile, "\n old cweights") ; IVfp80(gpart->msgFile, ndom+1, cweights, 80, &ierr) ; fflush(gpart->msgFile) ; } for ( c = 1 ; c <= ndom ; c++ ) { if ( dmap[c] != 0 ) { cweights[dmap[c]] = cweights[c] ; } } IV_setSize(&gpart->cweightsIV, nnewdom) ; if ( gpart->msglvl > 2 ) { fprintf(gpart->msgFile, "\n new cweights") ; IVfp80(gpart->msgFile, nnewdom+1, cweights, 80, &ierr) ; fflush(gpart->msgFile) ; } } /* ------------------------ free the working storage ------------------------ */ IVfree(head) ; IVfree(link) ; IVfree(dmap) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ absorb the excess boundary created -- 95oct05, cca revised -- 95oct19, cca very simple scheme ------------------------------------------------------------ */ static void GPart_absBoundary ( GPart *gpart ) { Graph *g ; int count, domid, ierr, ii, oldcount, ntest, nvtx, rc, v, vwght ; int *compids, *cweights, *list, *vwghts ; /* --------------- check the input --------------- */ if ( gpart == NULL || (g = gpart->g) == NULL ) { fprintf(stderr, "\n fatal error in GPart_absBoundary(%p)" "\n bad input\n", gpart) ; exit(-1) ; } nvtx = gpart->nvtx ; compids = IV_entries(&gpart->compidsIV) ; cweights = IV_entries(&gpart->cweightsIV) ; vwghts = gpart->g->vwghts ; /* ---------------------- create working storage ---------------------- */ list = IVinit(nvtx, -1) ; /* ----------------------------------------- load all interface vertices into the list ------------------------------------------ */ count = 0 ; for ( v = 0 ; v < nvtx ; v++ ) { if ( compids[v] == 0 ) { list[count++] = v ; } } oldcount = -1 ; while ( count > 0 ) { if ( gpart->msglvl > 2 ) { fprintf(gpart->msgFile, "\n\n new pass, count = %d", count) ; } ntest = count ; count = 0 ; for ( ii = 0 ; ii < ntest ; ii++ ) { v = list[ii] ; rc = GPart_vtxIsAdjToOneDomain(gpart, v, &domid) ; if ( rc == 1 ) { /* ----------------------------------------- transfer interface vertex v into domain c ----------------------------------------- */ compids[v] = domid ; vwght = (vwghts != NULL) ? vwghts[v] : 1 ; cweights[0] -= vwght ; cweights[domid] += vwght ; if ( gpart->msglvl > 3 ) { fprintf(gpart->msgFile, "\n moving vertex %d with weight %d to domain %d" "\n now, cweights[0] = %d, cweights[%d] = %d", v, vwght, domid, cweights[0], domid, cweights[domid]) ; fflush(gpart->msgFile) ; } } else if ( domid == -1 ) { /* ---------------------------------------------------------- vertex v is still not adjacent to any domain, keep on list ---------------------------------------------------------- */ if ( gpart->msglvl > 3 ) { fprintf(gpart->msgFile, "\n keeping vertex %d on list", v) ; } list[count++] = v ; } } if ( count == oldcount ) { break ; } else { oldcount = count ; } } IVfree(list) ; return ; } /*--------------------------------------------------------------------*/ } } /* ----------------------------------------------------------------- set up the vector that determines the order to visit the vertices ----------------------------------------------------------------- */ vids = IVinit2(nvtx) ; IVramp(nvtx, vids, 0, 1) ; if ( seed > 0 ) { IVshuffle(nvtx, vids, seed) ; } /* ------------------------------ set up the working list vector ------------------------------ */ list = IVinit(nvtx, -1) ; /* ----------------------------------- GPart/src/DDviaProjection.c010064400020550007177000000036150653410612000170670ustar00clevecompmath00000400000006/* DDviaProjection.c */ #include"../GPart.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- set the compids[] vector using a global map from vertices to domains and interface nodes. DDmapIV -- IV object that contains the map from vertices to domains and interface nodes created -- 96mar17, cca --------------------------------------------------------- */ void GPart_DDviaProjection ( GPart *gpart, IV *DDmapIV ) { int *compids, *domainMap, *map, *vtxMap ; int dom, domloc, ndom, ndomloc, nvtx, vglob, vloc ; /* --------------- check the input --------------- */ if ( gpart == NULL || DDmapIV == NULL ) { fprintf(stderr, "\n fatal error in GPart_DDviaProjection(%p,%p)" "\n bad input\n", gpart, DDmapIV) ; exit(-1) ; } nvtx = gpart->nvtx ; compids = IV_entries(&gpart->compidsIV) ; /* -------------------------- find the number of domains -------------------------- */ vtxMap = IV_entries(&gpart->vtxMapIV) ; map = IV_entries(DDmapIV) ; ndom = IV_max(DDmapIV) ; /* ------------------------ check for a quick return ------------------------ */ if ( gpart->par == NULL ) { IVcopy(nvtx, compids, map) ; gpart->ncomp = ndom ; return ; } /* ---------------------------------------- fill compids[] with the local domain ids ---------------------------------------- */ domainMap = IVinit(ndom+1, -1) ; ndomloc = 0 ; for ( vloc = 0 ; vloc < nvtx ; vloc++ ) { vglob = vtxMap[vloc] ; if ( (dom = map[vglob]) > 0 ) { if ( (domloc = domainMap[dom]) == -1 ) { domloc = domainMap[dom] = ++ndomloc ; } compids[vloc] = domloc ; } else { compids[vloc] = 0 ; } } gpart->ncomp = ndomloc ; IVfree(domainMap) ; return ; } /*--------------------------------------------------------------------*/ GPart/src/RBviaDDsep.c010064400020550007177000000364120653410612000157670ustar00clevecompmath00000400000006/* RBviaDDsep.c */ #include "../DDsepInfo.h" #include "../GPart.h" #include "../../timings.h" #define NSPLIT 8 #define BE_CAUTIOUS 0 /*--------------------------------------------------------------------*/ /* ----------------------------------- prototype for static visit() method ----------------------------------- */ static void visit ( GPart *gpart, int map[], int vpar[], IV *DDmapIV, DDsepInfo *info) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- this method constructs recursive partition of a graph. it returns a DSTree object to represent the splitting of the tree into subgraphs. the info object contains the information needed by the DDsep algorithm. created -- 96feb24, cca -------------------------------------------------------- */ DSTree * GPart_RBviaDDsep ( GPart *gpart, DDsepInfo *info ) { double t0, t1, t2, t3 ; DSTree *dstree ; FILE *msgFile ; GPart *child ; int ierr, msglvl, nvtx ; int *map, *vpar ; IV *DDmapIV, *DSmapIV ; Tree *tree ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( gpart == NULL || (nvtx = gpart->nvtx) <= 0 || info == NULL ) { fprintf(stderr, "\n fatal error in GPart_RBviaDDsep(%p,%p)" "\n bad input\n", gpart, info) ; exit(-1) ; } msglvl = gpart->msglvl ; msgFile = gpart->msgFile ; /* ------------------------- check that gpart is a root ------------------------- */ if ( gpart->par != NULL ) { fprintf(stderr, "\n fatal error in GPart_RBviaDDsep(%p,%p)" "\n gpart must be a root \n", gpart, info) ; exit(-1) ; } /* ----------------------------- create map and parent vectors ----------------------------- */ vpar = IVinit(nvtx, -1) ; DSmapIV = IV_new() ; IV_init(DSmapIV, nvtx, NULL) ; map = IV_entries(DSmapIV) ; IVfill(nvtx, map, -1) ; info->ntreeobj = 0 ; if ( info->DDoption == 2 ) { /* ------------------------------------------------ get one global domain decomposition via fishnet, then project it on each subgraph ------------------------------------------------ */ MARKTIME(t1) ; GPart_DDviaFishnet(gpart, info->freeze, info->minweight, info->maxweight, info->seed) ; DDmapIV = IV_new() ; IV_init(DDmapIV, nvtx, NULL) ; IV_copy(DDmapIV, &gpart->compidsIV) ; IV_fill(&gpart->compidsIV, 1) ; MARKTIME(t2) ; info->cpuDD += t2 - t1 ; } else { DDmapIV = NULL ; } /* --------------------------------------------- split the graph into its connected components --------------------------------------------- */ MARKTIME(t1) ; GPart_split(gpart) ; MARKTIME(t2) ; info->cpuSplit += t2 - t1 ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n after initial split, ncomp = %d", gpart->ncomp) ; fflush(msgFile) ; } if ( gpart->ncomp > 0 ) { for ( child = gpart->fch ; child != NULL ; child = child->sib ) { child->id = info->ntreeobj++ ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n\n ### component %d", child->id) ; Graph_writeStats(child->g, msgFile) ; if ( msglvl > 3 && msgFile != NULL ) { Graph_writeForHumanEye(child->g, msgFile) ; if ( IV_size(&child->vtxMapIV) > 0 ) { fprintf(msgFile, "\n vtxMap(%d) :", child->nvtx) ; IV_fp80(&child->vtxMapIV, msgFile, 80, &ierr) ; } } } fflush(msgFile) ; } } /* ------------------------------ visit each connected component ------------------------------ */ if ( gpart->fch != NULL ) { while ( (child = gpart->fch) != NULL ) { gpart->fch = child->sib ; visit(child, map, vpar, DDmapIV, info) ; Graph_free(child->g) ; GPart_free(child) ; } } else { gpart->id = info->ntreeobj++ ; visit(gpart, map, vpar, DDmapIV, info) ; } /* ------------------------ create the DSTree object ------------------------ */ tree = Tree_new() ; Tree_init2(tree, info->ntreeobj, vpar) ; dstree = DSTree_new() ; DSTree_init2(dstree, tree, DSmapIV) ; /* ------------------------ free the working storage ------------------------ */ IVfree(vpar) ; MARKTIME(t3) ; info->cpuTotal = t3 - t0 ; return(dstree) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- this method is called for each connected subgraph in the subgraph tree. map -- vector mapping vertices to subgraph number vpar -- vector mapping a subgraph to its parent subgraph info -- information structure for DDsep created -- 96feb24, cca -------------------------------------------------------- */ static void visit ( GPart *gpart, int map[], int vpar[], IV *DDmapIV, DDsepInfo *info ) { double t1, t2 ; double cpus[3] ; FILE *msgFile ; GPart *child, *par ; Graph *g ; int ierr, ii, maxweight, minweight, msglvl, nvbnd, nvtot, nvtx, parnvtot, totvwght, v, vsize, width ; int *compids, *parmap, *vadj, *vtxMap ; /* ------------------------------- extract dimensions and pointers ------------------------------- */ g = gpart->g ; nvtx = g->nvtx ; nvbnd = g->nvbnd ; nvtot = nvtx + nvbnd ; compids = IV_entries(&gpart->compidsIV) ; vtxMap = IV_entries(&gpart->vtxMapIV) ; msgFile = gpart->msgFile ; msglvl = gpart->msglvl ; /* ------------------------------ compute the total graph weight ------------------------------ */ if ( g->type % 2 == 0 ) { totvwght = nvtx ; } else { totvwght = IVsum(nvtx, g->vwghts) ; } /* ----------------- optional messages ----------------- */ if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n\n ### inside visit(%d), parent = %d" "\n nvtx = %d, nvbnd = %d, nvtot = %d, totvwght = %d", gpart->id, (gpart->par != NULL) ? gpart->par->id : -1, nvtx, nvbnd, nvtot, totvwght) ; fflush(msgFile) ; } if ( msglvl > 2 && msgFile != NULL ) { Graph_writeForHumanEye(gpart->g, msgFile) ; fflush(msgFile) ; } /* ------------------------------- set the vertex map to be global ------------------------------- */ if ( (par = gpart->par) != NULL && (parmap = IV_entries(&par->vtxMapIV)) != NULL ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n before changing map") ; fprintf(msgFile, "\n vtxMapIV") ; IV_writeForHumanEye(&gpart->vtxMapIV, msgFile) ; fprintf(msgFile, "\n parVtxMapIV") ; IV_writeForHumanEye(&par->vtxMapIV, msgFile) ; fflush(msgFile) ; IV_fp80(&gpart->vtxMapIV, msgFile, 80, &ierr) ; fflush(msgFile) ; } parnvtot = par->nvtx + par->nvbnd ; for ( v = 0 ; v < nvtot ; v++ ) { #if BE_CAUTIOUS > 0 if ( vtxMap[v] < 0 || vtxMap[v] >= parnvtot ) { fprintf(stderr, "\n error changing map, vtxMap[[%d] = %d, parnvtot = %d", v, vtxMap[v], parnvtot) ; exit(-1) ; } #endif vtxMap[v] = parmap[vtxMap[v]] ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n after changing map") ; IV_fp80(&gpart->vtxMapIV, msgFile, 80, &ierr) ; fflush(msgFile) ; } } if ( totvwght <= info->maxcompweight ) { gpart->ncomp = 1 ; } else { /* ---------------------------------------------- try to find a bisector via the DDsep algorithm ---------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n try to find a bisector") ; fflush(msgFile) ; } MARKTIME(t1) ; switch ( info->DDoption ) { case 1 : /* ---------------------------------------------------------- use the fishnet algorithm to find the domain decomposition ---------------------------------------------------------- */ if ( info->maxweight * NSPLIT <= totvwght ) { minweight = info->minweight ; maxweight = info->maxweight ; } else { maxweight = totvwght / NSPLIT ; if ( maxweight < 2 ) { maxweight = 2 ; } minweight = maxweight / 2 ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n calling DDviaFishnet with minweight = %d, maxweight = %d", minweight, maxweight) ; fflush(msgFile) ; } GPart_DDviaFishnet(gpart, info->freeze, minweight, maxweight, info->seed) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n return from DDviaFishnet") ; fflush(msgFile) ; } break ; case 2 : /* ----------------------------------------------------------------- use projection from a global map to find the domain decomposition ----------------------------------------------------------------- */ GPart_DDviaProjection(gpart, DDmapIV) ; break ; } MARKTIME(t2) ; info->cpuDD += t2 - t1 ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n after DD: %d domains", gpart->ncomp) ; } if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n partition weights :") ; IV_fp80(&gpart->cweightsIV, msgFile, 25, &ierr) ; } #if BE_CAUTIOUS > 0 if ( GPart_validVtxSep(gpart) == 1 ) { if ( msglvl > 2 && msgFile != NULL ) { fprintf(stdout, "\n DD: valid vertex separator ") ; } } else { fprintf(stderr, "\n DD: invalid vertex separator ") ; exit(-1) ; } #endif if ( gpart->ncomp > 1 ) { /* -------------------------------- find an initial bisector via BKL -------------------------------- */ GPart_TwoSetViaBKL(gpart, info->alpha, info->seed, cpus) ; info->cpuMap += cpus[0] ; info->cpuBPG += cpus[1] ; info->cpuBKL += cpus[2] ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n BKL final weights : ") ; IV_fp80(&gpart->cweightsIV, msgFile, 25, &ierr) ; } #if BE_CAUTIOUS > 0 if ( GPart_validVtxSep(gpart) == 1 ) { if ( msglvl > 2 && msgFile != NULL ) { fprintf(stdout, "\n BKL: valid vertex separator ") ; } } else { fprintf(stderr, "\n BKL: invalid vertex separator ") ; exit(-1) ; } #endif } if ( gpart->ncomp > 1 ) { /* --------------------------------------- find an improved bisector via smoothing --------------------------------------- */ MARKTIME(t1) ; if ( info->nlayer <= 2 ) { GPart_smoothBy2layers(gpart, info->nlayer, info->alpha) ; } else if ( (width = info->nlayer/2) > 0 ) { GPart_smoothBisector(gpart, width, info->alpha) ; } MARKTIME(t2) ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n smoothed weights : ") ; IV_fp80(&gpart->cweightsIV, msgFile, 25, &ierr) ; } #if BE_CAUTIOUS > 0 if ( GPart_validVtxSep(gpart) == 1 ) { if ( msglvl > 2 && msgFile != NULL ) { fprintf(stdout, "\n smoothed: valid vertex separator ") ; } } else { fprintf(stderr, "\n smoothed: invalid vertex separator ") ; exit(-1) ; } #endif info->cpuSmooth += t2 - t1 ; } if ( gpart->ncomp > 1 ) { /* ---------------------------------- split the subgraph into components ---------------------------------- */ MARKTIME(t1) ; GPart_split(gpart) ; MARKTIME(t2) ; info->cpuSplit += t2 - t1 ; if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n SPLIT weights : ") ; IV_fp80(&gpart->cweightsIV, msgFile, 20, &ierr) ; fflush(msgFile) ; } if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n compids") ; IV_fp80(&gpart->compidsIV, msgFile, 80, &ierr) ; fflush(msgFile) ; } } } if ( gpart->ncomp > 1 ) { /* --------------------------------------- a separator was found and the graph has been split into connected components --------------------------------------- */ for ( child = gpart->fch ; child != NULL ; child = child->sib) { child->id = info->ntreeobj++ ; vpar[child->id] = gpart->id ; } if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n after initial split, ncomp = %d", gpart->ncomp) ; for ( child = gpart->fch ; child != NULL ; child = child->sib) { fprintf(msgFile, "\n\n ### component %d", child->id) ; Graph_writeStats(child->g, msgFile) ; if ( msglvl > 3 && msgFile != NULL ) { Graph_writeForHumanEye(child->g, msgFile) ; if ( IV_size(&child->vtxMapIV) > 0 ) { fprintf(msgFile, "\n vtxMap(%d) :", child->nvtx) ; IV_fp80(&child->vtxMapIV, msgFile, 80, &ierr) ; } } } fflush(msgFile) ; } /* ------------------------------ visit each connected component ------------------------------ */ while ( (child = gpart->fch) != NULL ) { gpart->fch = child->sib ; visit(child, map, vpar, DDmapIV, info) ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n return from visiting child %d", child->id) ; fflush(msgFile) ; } Graph_free(child->g) ; GPart_free(child) ; } /* ----------------------------------------------------------- map adjacency structure of the separator back to the global numbering and set the map for the separator vertices ----------------------------------------------------------- */ if ( gpart->par != NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { if ( compids[v] == 0 ) { Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { #if BE_CAUTIOUS > 0 if ( vadj[ii] < 0 || vadj[ii] >= nvtot ) { fprintf(stderr, "\n 1.0 whoa, error, vadj[[%d] = %d, nvtot = %d", ii, vadj[ii], nvtot) ; exit(-1) ; } #endif vadj[ii] = vtxMap[vadj[ii]] ; } map[vtxMap[v]] = gpart->id ; } } } else { for ( v = 0 ; v < nvtx ; v++ ) { if ( compids[v] == 0 ) { map[v] = gpart->id ; } } } } else { /* ----------------------------------------------------- the subgraph was not split. map the adjacency back to the global numbering and set the map for the vertices ----------------------------------------------------- */ if ( msglvl > 1 && msgFile != NULL ) { fprintf(msgFile, "\n this subgraph is a domain") ; } if ( gpart->par != NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { #if BE_CAUTIOUS > 0 if ( vadj[ii] < 0 || vadj[ii] >= nvtot ) { fprintf(stderr, "\n 2.0 whoa, error, vadj[[%d] = %d, nvtot = %d", ii, vadj[ii], nvtot) ; exit(-1) ; } #endif vadj[ii] = vtxMap[vadj[ii]] ; } } for ( v = 0 ; v < nvtx ; v++ ) { map[vtxMap[v]] = gpart->id ; } } else { for ( v = 0 ; v < nvtx ; v++ ) { map[v] = gpart->id ; } } } return ; } /*--------------------------------------------------------------------*/ = gpart->g ; nvtx = g->nvtx ; nvbnd = g->nvbnd ; nvtot = nvtx + nvbnd ; compids = IV_entries(&gpart->compidsIV) ; vtxMap = IV_entries(&gpart->vtxMapIV) ; msgFile = gpart->msgFile ; msglvl = gpart->msglvl ; /* ---------------------GPart/src/TwoSetViaBKL.c010064400020550007177000000142300653410612000162540ustar00clevecompmath00000400000006/* TwoSetViaBKL.c */ #include "../GPart.h" #include "../../BKL.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- given a domain decomposition, find a bisector 1. construct the domain/segment graph 2. use block kernihan-lin to get an initial bisector alpha -- cost function parameter for BKL seed -- random number seed cpus -- array to store CPU times cpus[0] -- time to find domain/segment map cpus[1] -- time to find domain/segment bipartite graph cpus[2] -- time to find two-set partition return value -- cost of the partition created -- 96mar09, cca ----------------------------------------------------------------- */ double GPart_TwoSetViaBKL ( GPart *gpart, double alpha, int seed, double cpus[] ) { BKL *bkl ; BPG *bpg ; double t1, t2 ; FILE *msgFile ; float bestcost ; Graph *g, *gc ; int c, flag, ierr, msglvl, ndom, nseg, nvtx, v ; int *compids, *cweights, *dscolors, *dsmap, *vwghts ; IV *dsmapIV ; /* --------------- check the input --------------- */ if ( gpart == NULL || cpus == NULL ) { fprintf(stderr, "\n fatal error in GPart_DDsep(%p,%f,%d,%p)" "\n bad input\n", gpart, alpha, seed, cpus) ; exit(-1) ; } g = gpart->g ; nvtx = gpart->nvtx ; compids = IV_entries(&gpart->compidsIV) ; cweights = IV_entries(&gpart->cweightsIV) ; vwghts = g->vwghts ; msglvl = gpart->msglvl ; msgFile = gpart->msgFile ; /* HARDCODE THE ALPHA PARAMETER. */ alpha = 1.0 ; /* ------------------------------ (1) get the domain/segment map (2) get the compressed graph (3) create the bipartite graph ------------------------------ */ MARKTIME(t1) ; dsmapIV = GPart_domSegMap(gpart, &ndom, &nseg) ; dsmap = IV_entries(dsmapIV) ; MARKTIME(t2) ; cpus[0] = t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %9.5f : generate domain-segment map", t2 - t1) ; fprintf(msgFile, "\n ndom = %d, nseg = %d", ndom, nseg) ; fflush(msgFile) ; } /* ----------------------------------------- create the domain/segment bipartite graph ----------------------------------------- */ MARKTIME(t1) ; gc = Graph_compress(gpart->g, dsmap, 1) ; bpg = BPG_new() ; BPG_init(bpg, ndom, nseg, gc) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %9.5f : create domain-segment graph", t2 - t1) ; fflush(msgFile) ; } cpus[1] = t2 - t1 ; if ( msglvl > 2 ) { if ( bpg->graph->vwghts != NULL ) { fprintf(msgFile, "\n domain weights :") ; IVfp80(msgFile, bpg->nX, bpg->graph->vwghts, 17, &ierr) ; fprintf(msgFile, "\n segment weights :") ; IVfp80(msgFile, bpg->nY, bpg->graph->vwghts+bpg->nX, 18, &ierr) ; fflush(msgFile) ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n dsmapIV ") ; IV_writeForHumanEye(dsmapIV, msgFile) ; fprintf(msgFile, "\n\n domain/segment bipartite graph ") ; BPG_writeForHumanEye(bpg, msgFile) ; fflush(msgFile) ; } /* ------------------------------------ create and initialize the BKL object ------------------------------------ */ MARKTIME(t1) ; flag = 5 ; bkl = BKL_new() ; BKL_init(bkl, bpg, alpha) ; BKL_setInitPart(bkl, flag, seed, NULL) ; bestcost = BKL_evalfcn(bkl) ; gpart->ncomp = 2 ; MARKTIME(t2) ; cpus[2] = t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %9.5f : initialize BKL object", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n BKL : flag = %d, seed = %d", flag, seed) ; fprintf(msgFile, ", initial cost = %.2f", bestcost) ; fflush(msgFile) ; fprintf(msgFile, ", cweights = < %d %d %d >", bkl->cweights[0], bkl->cweights[1], bkl->cweights[2]) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n colors") ; IVfp80(msgFile, bkl->nreg, bkl->colors, 80, &ierr) ; fflush(msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n BKL initial weights : ") ; IVfp80(msgFile, 3, bkl->cweights, 25, &ierr) ; fflush(msgFile) ; } /* -------------------------------- improve the partition via fidmat -------------------------------- */ MARKTIME(t1) ; bestcost = BKL_fidmat(bkl) ; MARKTIME(t2) ; cpus[2] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %9.5f : improve the partition via fidmat", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n BKL : %d passes", bkl->npass) ; fprintf(msgFile, ", %d flips", bkl->nflips) ; fprintf(msgFile, ", %d gainevals", bkl->ngaineval) ; fprintf(msgFile, ", %d improve steps", bkl->nimprove) ; fprintf(msgFile, ", cost = %9.2f", bestcost) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n BKL STATS < %9d %9d %9d > %9.2f < %4d %4d %4d %4d %4d >", bkl->cweights[0], bkl->cweights[1], bkl->cweights[2], bestcost, bkl->npass, bkl->npatch, bkl->nflips, bkl->nimprove, bkl->ngaineval) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n colors") ; IVfp80(msgFile, bkl->nreg, bkl->colors, 80, &ierr) ; fflush(msgFile) ; } /* ---------------------------- set compids[] and cweights[] ---------------------------- */ MARKTIME(t1) ; dscolors = bkl->colors ; gpart->ncomp = 2 ; IV_setSize(&gpart->cweightsIV, 3) ; cweights = IV_entries(&gpart->cweightsIV) ; cweights[0] = cweights[1] = cweights[2] = 0 ; if ( vwghts == NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { compids[v] = c = dscolors[dsmap[v]] ; cweights[c]++ ; } } else { for ( v = 0 ; v < nvtx ; v++ ) { compids[v] = c = dscolors[dsmap[v]] ; cweights[c] += vwghts[v] ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n BKL partition : < %d %d %d >", cweights[0], cweights[1], cweights[2]) ; fflush(msgFile) ; } /* ------------------------------------ free the BKL object, the BPG object and the domain/segment map IV object ------------------------------------ */ BKL_free(bkl) ; IV_free(dsmapIV) ; BPG_free(bpg) ; MARKTIME(t2) ; cpus[2] += t2 - t1 ; return((double) bestcost) ; } /*--------------------------------------------------------------------*/ sgFile) ; } /* ----------------------------------------- create the domain/segment bipartite graph ----------------------------------------- */ MARKTIME(t1) ; gc = Graph_compress(gpart->g, dsmap, 1) ; bpg = BPG_new() ; BPG_init(bpg, ndom, nseg, gc) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %9.5f : create domain-segment graph",GPart/src/basics.c010064400020550007177000000051220653410612000153020ustar00clevecompmath00000400000006/* basics.c */ #include "../GPart.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* -------------------------------------------- construct a new instance of the GPart object created -- 95oct05, cca -------------------------------------------- */ GPart * GPart_new ( void ) { GPart *gpart ; ALLOCATE(gpart, struct _GPart, 1) ; GPart_setDefaultFields(gpart) ; return(gpart) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- set the default fields of the GPart object created -- 95oct05, cca modified -- 95nov29, cca par, fch, sib and vtxMap fields included --------------------------------------------- */ void GPart_setDefaultFields ( GPart *gpart ) { if ( gpart == NULL ) { fprintf(stderr, "\n fatal error in GPart_setDefaultFields(%p)" "\n bad input\n", gpart) ; exit(-1) ; } gpart->id = -1 ; gpart->g = NULL ; gpart->nvtx = 0 ; gpart->nvbnd = 0 ; gpart->ncomp = 0 ; gpart->par = NULL ; gpart->fch = NULL ; gpart->sib = NULL ; IV_setDefaultFields(&gpart->compidsIV) ; IV_setDefaultFields(&gpart->cweightsIV) ; IV_setDefaultFields(&gpart->vtxMapIV) ; gpart->msglvl = 0 ; gpart->msgFile = NULL ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- clear the data fields for a GPart object created -- 95oct05, cca modified -- 95nov29, cca par, fch, sib and vtxMap fields included --------------------------------------------- */ void GPart_clearData ( GPart *gpart ) { if ( gpart == NULL ) { fprintf(stderr, "\n fatal error in GPart_clearData(%p)" "\n bad input\n", gpart) ; exit(-1) ; } IV_clearData(&gpart->compidsIV) ; IV_clearData(&gpart->cweightsIV) ; IV_clearData(&gpart->vtxMapIV) ; GPart_setDefaultFields(gpart) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------ free the GPart object created -- 95oct05, cca modified -- 95nov29, cca gpart now free'd ------------------------ */ void GPart_free ( GPart *gpart ) { if ( gpart == NULL ) { fprintf(stderr, "\n fatal error in GPart_free(%p)" "\n bad input\n", gpart) ; exit(-1) ; } GPart_clearData(gpart) ; #if MYDEBUG > 0 fprintf(stdout, "\n trying to free gpart") ; fflush(stdout) ; #endif FREE(gpart) ; return ; } /*--------------------------------------------------------------------*/ GPart/src/domSegMap.c010064400020550007177000000322340654025207200157230ustar00clevecompmath00000400000006/* domSegMap.c */ #include "../GPart.h" #include "../../timings.h" #define NTIMES 12 static int icputimes ; static double cputimes[NTIMES] ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- fill *pndom with ndom, the number of domains. fill *pnseg with nseg, the number of segments. domains are numbered in [0, ndom), segments in [ndom,ndom+nseg). return -- an IV object that contains the map from vertices to segments created -- 99feb29, cca -------------------------------------------------------------------- */ IV * GPart_domSegMap ( GPart *gpart, int *pndom, int *pnseg ) { FILE *msgFile ; Graph *g ; int adjdom, count, d, first, ierr, ii, jj1, jj2, last, ndom, msglvl, nextphi, nPhi, nPsi, nV, phi, phi0, phi1, phi2, phi3, psi, sigma, size, size0, size1, size2, v, vsize, w ; int *adj, *adj0, *adj1, *adj2, *compids, *dmark, *dsmap, *head, *link, *list, *offsets, *PhiToPsi, *PhiToV, *PsiToSigma, *vadj, *VtoPhi ; IV *dsmapIV ; IVL *PhiByPhi, *PhiByPowD, *PsiByPowD ; /* -------------------- set the initial time -------------------- */ icputimes = 0 ; MARKTIME(cputimes[icputimes]) ; /* --------------- check the input --------------- */ if ( gpart == NULL || (g = gpart->g) == NULL || pndom == NULL || pnseg == NULL ) { fprintf(stderr, "\n fatal error in GPart_domSegMap(%p,%p,%p)" "\n bad input\n", gpart, pndom, pnseg) ; exit(-1) ; } compids = IV_entries(&gpart->compidsIV) ; msglvl = gpart->msglvl ; msgFile = gpart->msgFile ; /* ------------------------ create the map IV object ------------------------ */ nV = g->nvtx ; dsmapIV = IV_new() ; IV_init(dsmapIV, nV, NULL) ; dsmap = IV_entries(dsmapIV) ; /* ---------------------------------- check compids[] and get the number of domains and interface vertices ---------------------------------- */ icputimes++ ; MARKTIME(cputimes[icputimes]) ; ndom = nPhi = 0 ; for ( v = 0 ; v < nV ; v++ ) { if ( (d = compids[v]) < 0 ) { fprintf(stderr, "\n fatal error in GPart_domSegMap(%p,%p,%p)" "\n compids[%d] = %d\n", gpart, pndom, pnseg, v, compids[v]) ; exit(-1) ; } else if ( d == 0 ) { nPhi++ ; } else if ( ndom < d ) { ndom = d ; } } *pndom = ndom ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n Inside GPart_domSegMap") ; fprintf(msgFile, "\n %d domains, %d Phi vertices", ndom, nPhi) ; } if ( ndom == 1 ) { IVfill(nV, dsmap, 0) ; *pndom = 1 ; *pnseg = 0 ; return(dsmapIV) ; } /* -------------------------------- get the maps PhiToV : [0,nPhi) |---> [0,nV) VtoPhi : [0,nV) |---> [0,nPhi) -------------------------------- */ icputimes++ ; MARKTIME(cputimes[icputimes]) ; PhiToV = IVinit(nPhi, -1) ; VtoPhi = IVinit(nV, -1) ; for ( v = 0, phi = 0 ; v < nV ; v++ ) { if ( (d = compids[v]) == 0 ) { PhiToV[phi] = v ; VtoPhi[v] = phi++ ; } } if ( phi != nPhi ) { fprintf(stderr, "\n fatal error in GPart_domSegMap(%p,%p,%p)" "\n phi = %d != %d = nPhi\n", gpart, pndom, pnseg, phi, nPhi) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n PhiToV(%d) :", nPhi) ; IVfp80(msgFile, nPhi, PhiToV, 15, &ierr) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n VtoPhi(%d) :", nV) ; IVfp80(msgFile, nV, VtoPhi, 15, &ierr) ; fflush(msgFile) ; } /* --------------------------------------------------- create an IVL object, PhiByPowD, to hold lists from the interface vertices to their adjacent domains --------------------------------------------------- */ icputimes++ ; MARKTIME(cputimes[icputimes]) ; dmark = IVinit(ndom+1, -1) ; if ( nPhi >= ndom ) { list = IVinit(nPhi, -1) ; } else { list = IVinit(ndom, -1) ; } PhiByPowD = IVL_new() ; IVL_init1(PhiByPowD, IVL_CHUNKED, nPhi) ; for ( phi = 0 ; phi < nPhi ; phi++ ) { v = PhiToV[phi] ; Graph_adjAndSize(g, v, &vsize, &vadj) ; /* if ( phi == 0 ) { int ierr ; fprintf(msgFile, "\n adj(%d,%d) = ", v, phi) ; IVfp80(msgFile, vsize, vadj, 15, &ierr) ; fflush(msgFile) ; } */ count = 0 ; for ( ii = 0 ; ii < vsize ; ii++ ) { if ( (w = vadj[ii]) < nV && (d = compids[w]) > 0 && dmark[d] != phi ) { dmark[d] = phi ; list[count++] = d ; } } if ( count > 0 ) { IVqsortUp(count, list) ; IVL_setList(PhiByPowD, phi, count, list) ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n PhiByPowD : interface x adjacent domains") ; IVL_writeForHumanEye(PhiByPowD, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------- create an IVL object, PhiByPhi to hold lists from the interface vertices to interface vertices. (s,t) are in the list if (s,t) is an edge in the graph and s and t do not share an adjacent domain ------------------------------------------------------- */ icputimes++ ; MARKTIME(cputimes[icputimes]) ; PhiByPhi = IVL_new() ; IVL_init1(PhiByPhi, IVL_CHUNKED, nPhi) ; offsets = IVinit(nPhi, 0) ; head = IVinit(nPhi, -1) ; link = IVinit(nPhi, -1) ; for ( phi1 = 0 ; phi1 < nPhi ; phi1++ ) { count = 0 ; if ( msglvl > 2 ) { v = PhiToV[phi1] ; Graph_adjAndSize(g, v, &vsize, &vadj) ; fprintf(msgFile, "\n checking out phi = %d, v = %d", phi1, v) ; fprintf(msgFile, "\n adj(%d) : ", v) ; IVfp80(msgFile, vsize, vadj, 10, &ierr) ; } /* ------------------------------------------------------------- get (phi1, phi0) edges that were previously put into the list ------------------------------------------------------------- */ if ( msglvl > 3 ) { if ( head[phi1] == -1 ) { fprintf(msgFile, "\n no previous edges") ; } else { fprintf(msgFile, "\n previous edges :") ; } } for ( phi0 = head[phi1] ; phi0 != -1 ; phi0 = nextphi ) { if ( msglvl > 3 ) { fprintf(msgFile, " %d", phi0) ; } nextphi = link[phi0] ; list[count++] = phi0 ; IVL_listAndSize(PhiByPhi, phi0, &size0, &adj0) ; if ( (ii = ++offsets[phi0]) < size0 ) { /* ---------------------------- link phi0 into the next list ---------------------------- */ phi2 = adj0[ii] ; link[phi0] = head[phi2] ; head[phi2] = phi0 ; } } /* -------------------------- get new edges (phi1, phi2) -------------------------- */ IVL_listAndSize(PhiByPowD, phi1, &size1, &adj1) ; v = PhiToV[phi1] ; Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { if ( (w = vadj[ii]) < nV && compids[w] == 0 && (phi2 = VtoPhi[w]) > phi1 ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n checking out phi2 = %d", phi2) ; } /* -------------------------------------------------- see if phi1 and phi2 have a common adjacent domain -------------------------------------------------- */ IVL_listAndSize(PhiByPowD, phi2, &size2, &adj2) ; adjdom = 0 ; jj1 = jj2 = 0 ; while ( jj1 < size1 && jj2 < size2 ) { if ( adj1[jj1] < adj2[jj2] ) { jj1++ ; } else if ( adj1[jj1] > adj2[jj2] ) { jj2++ ; } else { if ( msglvl > 3 ) { fprintf(msgFile, ", common adj domain %d", adj1[jj1]) ; } adjdom = 1 ; break ; } } if ( adjdom == 0 ) { if ( msglvl > 3 ) { fprintf(msgFile, ", no adjacent domain") ; } list[count++] = phi2 ; } } } if ( count > 0 ) { /* --------------------- set the list for phi1 --------------------- */ IVqsortUp(count, list) ; IVL_setList(PhiByPhi, phi1, count, list) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n edge list for %d :", phi1) ; IVfp80(msgFile, count, list, 15, &ierr) ; } for ( ii = 0, phi2 = -1 ; ii < count ; ii++ ) { if ( list[ii] > phi1 ) { offsets[phi1] = ii ; phi2 = list[ii] ; break ; } } if ( phi2 != -1 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n linking %d into list for %d", phi1, phi2) ; } link[phi1] = head[phi2] ; head[phi2] = phi1 ; } /* phi2 = list[0] ; link[phi1] = head[phi2] ; head[phi2] = phi1 ; */ } } if ( msglvl > 2 ) { fprintf(msgFile, "\n PhiByPhi : interface x interface") ; IVL_writeForHumanEye(PhiByPhi, msgFile) ; fflush(msgFile) ; } /* -------------------- get the PhiToPsi map -------------------- */ icputimes++ ; MARKTIME(cputimes[icputimes]) ; PhiToPsi = IVinit(nPhi, -1) ; nPsi = 0 ; for ( phi = 0 ; phi < nPhi ; phi++ ) { if ( PhiToPsi[phi] == -1 ) { /* --------------------------- phi not yet mapped to a psi --------------------------- */ first = last = 0 ; list[0] = phi ; PhiToPsi[phi] = nPsi ; while ( first <= last ) { phi2 = list[first++] ; IVL_listAndSize(PhiByPhi, phi2, &size, &adj) ; for ( ii = 0 ; ii < size ; ii++ ) { phi3 = adj[ii] ; if ( PhiToPsi[phi3] == -1 ) { PhiToPsi[phi3] = nPsi ; list[++last] = phi3 ; } } } nPsi++ ; } } if ( msglvl > 1 ) { fprintf(msgFile, "\n nPsi = %d", nPsi) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n PhiToPsi(%d) :", nPhi) ; IVfp80(msgFile, nPhi, PhiToPsi, 15, &ierr) ; fflush(msgFile) ; } /* --------------------------------- create an IVL object, Psi --> 2^D --------------------------------- */ icputimes++ ; MARKTIME(cputimes[icputimes]) ; IVfill(nPsi, head, -1) ; IVfill(nPhi, link, -1) ; for ( phi = 0 ; phi < nPhi ; phi++ ) { psi = PhiToPsi[phi] ; link[phi] = head[psi] ; head[psi] = phi ; } PsiByPowD = IVL_new() ; IVL_init1(PsiByPowD, IVL_CHUNKED, nPsi) ; IVfill(ndom+1, dmark, -1) ; for ( psi = 0 ; psi < nPsi ; psi++ ) { count = 0 ; for ( phi = head[psi] ; phi != -1 ; phi = link[phi] ) { v = PhiToV[phi] ; Graph_adjAndSize(g, v, &size, &adj) ; for ( ii = 0 ; ii < size ; ii++ ) { if ( (w = adj[ii]) < nV && (d = compids[w]) > 0 && dmark[d] != psi ) { dmark[d] = psi ; list[count++] = d ; } } } if ( count > 0 ) { IVqsortUp(count, list) ; IVL_setList(PsiByPowD, psi, count, list) ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n PsiByPowD(%d) :", nPhi) ; IVL_writeForHumanEye(PsiByPowD, msgFile) ; fflush(msgFile) ; } icputimes++ ; MARKTIME(cputimes[icputimes]) ; /* ------------------------------------- now get the map Psi |---> Sigma that is the equivalence map over PhiByPowD ------------------------------------- */ icputimes++ ; MARKTIME(cputimes[icputimes]) ; PsiToSigma = IVL_equivMap1(PsiByPowD) ; *pnseg = 1 + IVmax(nPsi, PsiToSigma, &ii) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n nSigma = %d", *pnseg) ; fprintf(msgFile, "\n PsiToSigma(%d) :", nPhi) ; IVfp80(msgFile, nPsi, PsiToSigma, 15, &ierr) ; fflush(msgFile) ; } /* -------------------------------------------------------------- now fill the map from the vertices to the domains and segments -------------------------------------------------------------- */ icputimes++ ; MARKTIME(cputimes[icputimes]) ; for ( v = 0 ; v < nV ; v++ ) { if ( (d = compids[v]) > 0 ) { dsmap[v] = d - 1 ; } else { phi = VtoPhi[v] ; psi = PhiToPsi[phi] ; sigma = PsiToSigma[psi] ; dsmap[v] = ndom + sigma ; } } /* ------------------------ free the working storage ------------------------ */ icputimes++ ; MARKTIME(cputimes[icputimes]) ; IVL_free(PhiByPhi) ; IVL_free(PhiByPowD) ; IVL_free(PsiByPowD) ; IVfree(PhiToV) ; IVfree(VtoPhi) ; IVfree(dmark) ; IVfree(list) ; IVfree(PhiToPsi) ; IVfree(head) ; IVfree(link) ; IVfree(offsets) ; IVfree(PsiToSigma) ; icputimes++ ; MARKTIME(cputimes[icputimes]) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n domain/segment map timings split") ; fprintf(msgFile, "\n %9.5f : create the DSmap object" "\n %9.5f : get numbers of domain and interface vertices" "\n %9.5f : generate PhiToV and VtoPhi" "\n %9.5f : generate PhiByPowD" "\n %9.5f : generate PhiByPhi" "\n %9.5f : generate PhiToPsi" "\n %9.5f : generate PsiByPowD" "\n %9.5f : generate PsiToSigma" "\n %9.5f : generate dsmap" "\n %9.5f : free working storage" "\n %9.5f : total time", cputimes[1] - cputimes[0], cputimes[2] - cputimes[1], cputimes[3] - cputimes[2], cputimes[4] - cputimes[3], cputimes[5] - cputimes[4], cputimes[6] - cputimes[5], cputimes[7] - cputimes[6], cputimes[8] - cputimes[7], cputimes[9] - cputimes[8], cputimes[10] - cputimes[9], cputimes[11] - cputimes[0]) ; } return(dsmapIV) ; } /*--------------------------------------------------------------------*/ GPart/src/identifyWideSep.c010064400020550007177000000151150653410612000171350ustar00clevecompmath00000400000006/* identifyWideSep.c */ #include "../GPart.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- identify the wide separator return -- IV object that holds the nodes in the wide separator created -- 96oct21, cca -------------------------------------------------------------- */ IV * GPart_identifyWideSep ( GPart *gpart, int nlevel1, int nlevel2 ) { FILE *msgFile ; Graph *g ; int count, first, ierr, ii, ilevel, last, msglvl, nfirst, now, nsecond, nsep, nvtx, v, vsize, w ; int *compids, *list, *mark, *vadj ; IV *sepIV ; /* --------------- check the input --------------- */ if ( gpart == NULL || (g = gpart->g) == NULL || nlevel1 < 0 || nlevel2 < 0 ) { fprintf(stderr, "\n fatal error in GPart_identifyWideSep(%p,%d,%d)" "\n bad input\n", gpart, nlevel1, nlevel2) ; exit(-1) ; } g = gpart->g ; compids = IV_entries(&gpart->compidsIV) ; nvtx = g->nvtx ; mark = IVinit(nvtx, -1) ; list = IVinit(nvtx, -1) ; msglvl = gpart->msglvl ; msgFile = gpart->msgFile ; /* -------------------------------------- load the separator nodes into the list -------------------------------------- */ nsep = 0 ; for ( v = 0 ; v < nvtx ; v++ ) { if ( compids[v] == 0 ) { list[nsep++] = v ; mark[v] = 0 ; } } count = nsep ; if ( msglvl > 1 ) { fprintf(msgFile, "\n GPart_identifyWideSep : %d separator nodes loaded", count) ; fflush(msgFile) ; } if ( msglvl > 2 ) { IVfp80(msgFile, nsep, list, 80, &ierr) ; fflush(msgFile) ; } /* ---------------------------------------------- loop over the number of levels out that form the wide separator towards the first component ---------------------------------------------- */ if ( nlevel1 >= 1 ) { first = count ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n level = %d, first = %d", 1, first) ; fflush(msgFile) ; } for ( now = 0 ; now < nsep ; now++ ) { v = list[now] ; Graph_adjAndSize(g, v, &vsize, &vadj) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %d : ", v) ; IVfp80(msgFile, vsize, vadj, 80, &ierr) ; fflush(msgFile) ; } for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < nvtx && mark[w] == -1 && compids[w] == 1 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n adding %d to list", w) ; fflush(msgFile) ; } list[count++] = w ; mark[w] = 1 ; } } } now = first ; for ( ilevel = 2 ; ilevel <= nlevel1 ; ilevel++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n level = %d, first = %d", ilevel, first); fflush(msgFile) ; } last = count - 1 ; while ( now <= last ) { v = list[now++] ; Graph_adjAndSize(g, v, &vsize, &vadj) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %d : ", v) ; IVfp80(msgFile, vsize, vadj, 80, &ierr) ; fflush(msgFile) ; } for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < nvtx && mark[w] == -1 && compids[w] == 1 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n adding %d to list", w) ; fflush(msgFile) ; } mark[w] = 1 ; list[count++] = w ; } } } } } nfirst = count - nsep ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %d nodes added from the first component", nfirst) ; fflush(msgFile) ; } if ( msglvl > 3 ) { IVfp80(msgFile, nfirst, &list[nsep], 80, &ierr) ; fflush(msgFile) ; } /* ---------------------------------------------- loop over the number of levels out that form the wide separator towards the second component ---------------------------------------------- */ if ( nlevel2 >= 1 ) { first = count ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n level = %d, first = %d", 1, first) ; fflush(msgFile) ; } for ( now = 0 ; now < nsep ; now++ ) { v = list[now] ; Graph_adjAndSize(g, v, &vsize, &vadj) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %d : ", v) ; IVfp80(msgFile, vsize, vadj, 80, &ierr) ; fflush(msgFile) ; } for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < nvtx && mark[w] == -1 && compids[w] == 2 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n adding %d to list", w) ; fflush(msgFile) ; } list[count++] = w ; mark[w] = 2 ; } } } now = first ; for ( ilevel = 2 ; ilevel <= nlevel2 ; ilevel++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n level = %d, first = %d", ilevel, first); fflush(msgFile) ; } last = count - 1 ; while ( now <= last ) { v = list[now++] ; Graph_adjAndSize(g, v, &vsize, &vadj) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %d : ", v) ; IVfp80(msgFile, vsize, vadj, 80, &ierr) ; fflush(msgFile) ; } for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < nvtx && mark[w] == -1 && compids[w] == 2 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n adding %d to list", w) ; fflush(msgFile) ; } mark[w] = 2 ; list[count++] = w ; } } } } } nsecond = count - nsep - nfirst ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %d nodes added from the second component", nsecond) ; fflush(msgFile) ; } if ( msglvl > 3 ) { IVfp80(msgFile, nsecond, &list[nsep + nfirst], 80, &ierr) ; fflush(msgFile) ; } IVqsortUp(count, list) ; /* -------------------- create the IV object -------------------- */ sepIV = IV_new() ; IV_init(sepIV, count, NULL) ; IVcopy(count, IV_entries(sepIV), list) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n separator has %d nodes", IV_size(sepIV)) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n sepIV") ; IV_writeForHumanEye(sepIV, msgFile) ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ IVfree(mark) ; IVfree(list) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n return from GPart_identifyWideSep") ; fflush(msgFile) ; } return(sepIV) ; } /*--------------------------------------------------------------------*/ GPart/src/init.c010064400020550007177000000024500653410612000150020ustar00clevecompmath00000400000006/* init.c */ #include "../GPart.h" /*--------------------------------------------------------------------*/ /* --------------------------- initialize the GPart object created -- 95oct05, cca --------------------------- */ void GPart_init ( GPart *gpart, Graph *g ) { if ( gpart == NULL || g == NULL || g->nvtx <= 0 ) { fprintf(stderr, "\n fatal error in GPart_init(%p,%p)" "\n bad input\n", gpart, g) ; exit(-1) ; } GPart_clearData(gpart) ; gpart->nvtx = g->nvtx ; gpart->nvbnd = g->nvbnd ; gpart->g = g ; gpart->ncomp = 1 ; IV_setSize(&gpart->compidsIV, g->nvtx) ; IV_fill(&gpart->compidsIV, 1) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the message fields created -- 96oct21, cca ----------------------- */ void GPart_setMessageInfo ( GPart *gpart, int msglvl, FILE *msgFile ) { if ( gpart == NULL ) { fprintf(stderr, "\n fatal error in GPart_setMessageInfo(%p,%d,%p)" "\n bad input\n", gpart, msglvl, msgFile) ; exit(-1) ; } gpart->msglvl = msglvl ; if ( msgFile != NULL ) { gpart->msgFile = msgFile ; } else { gpart->msgFile = stdout ; } return ; } /*--------------------------------------------------------------------*/ GPart/src/makeYCmap.c010064400020550007177000000073110653410612000157070ustar00clevecompmath00000400000006/* makeYCmap.c */ #include "../GPart.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- make the map from wide separator vertices Y to components {0, 1, 2, 3}. YCmap[y] == 0 --> y is not adjacent to either component YCmap[y] == 1 --> y is adjacent to only component 1 YCmap[y] == 2 --> y is adjacent to only component 2 YCmap[y] == 3 --> y is adjacent to components 1 and 2 created -- 96jun09, cca ------------------------------------------------------- */ IV * GPart_makeYCmap ( GPart *gpart, IV *YVmapIV ) { Graph *g ; int ii, nvtx, nY, v, vsize, w, y ; int *compids, *vadj, *VYmap, *YCmap, *YVmap ; IV *YCmapIV ; /* --------------- check the input --------------- */ if ( gpart == NULL || (g = gpart->g) == NULL || (nvtx = gpart->nvtx) <= 0 || YVmapIV == NULL || (nY = IV_size(YVmapIV)) <= 0 || (YVmap = IV_entries(YVmapIV)) == NULL ) { fprintf(stderr, "\n fatal error in GPart_makeYCmap(%p,%p)" "\n bad input\n", gpart, YVmapIV) ; if ( YVmapIV != NULL ) { fprintf(stderr, "\n YVmapIV") ; IV_writeForHumanEye(YVmapIV, stderr) ; } exit(-1) ; } compids = IV_entries(&gpart->compidsIV) ; /* -------------------------------- generate the inverse V --> Y map -------------------------------- */ VYmap = IVinit(nvtx, -1) ; for ( y = 0 ; y < nY ; y++ ) { v = YVmap[y] ; VYmap[v] = y ; } /* ------------------------------------ initialize the Y --> C map IV object ------------------------------------ */ YCmapIV = IV_new(); IV_init(YCmapIV, nY, NULL) ; YCmap = IV_entries(YCmapIV) ; /* --------------- fill the fields --------------- */ for ( y = 0 ; y < nY ; y++ ) { YCmap[y] = 0 ; v = YVmap[y] ; Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < nvtx && VYmap[w] == -1 ) { /* -------------------------------- w is not in the wide separator Y -------------------------------- */ if ( compids[w] == 1 ) { /* --------------------------------------- v is adjacent to component 1 setminus Y --------------------------------------- */ if ( YCmap[y] == 2 ) { /* ------------------------------------ v is already adjacent to component 2 so it is adjacent to both components ------------------------------------ */ YCmap[y] = 3 ; break ; } else { /* ---------------------------------- set map value but keep on checking ---------------------------------- */ YCmap[y] = 1 ; } } else if ( compids[w] == 2 ) { /* --------------------------------------- v is adjacent to component 2 setminus Y --------------------------------------- */ if ( YCmap[y] == 1 ) { /* ------------------------------------ v is already adjacent to component 1 so it is adjacent to both components ------------------------------------ */ YCmap[y] = 3 ; break ; } else { /* ---------------------------------- set map value but keep on checking ---------------------------------- */ YCmap[y] = 2 ; } } } } } /* ------------------------ free the working storage ------------------------ */ IVfree(VYmap) ; return(YCmapIV) ; } /*--------------------------------------------------------------------*/ GPart/src/smoothBisector.c010064400020550007177000000113370653410612100170500ustar00clevecompmath00000400000006/* smoothBisector.c */ #include "../GPart.h" #include "../../Ideq.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------- static definition of evaluation function ---------------------------------------- */ static float eval ( float alpha, float wS, float wB, float wW) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- smooth a wide separator nlevel -- number of levels one each side of the separator to include into the separator alpha -- partition cost function parameter created -- 96jun02, cca --------------------------------------------------------- */ float GPart_smoothBisector ( GPart *gpart, int nlevel, float alpha ) { FILE *msgFile ; float balance, bestcost, cost, newcost ; Graph *g ; int ierr, ipass, msglvl ; int *compids, *cweights, *vwghts ; IV *YCmapIV, *YVmapIV ; /* --------------- check the input --------------- */ if ( gpart == NULL || nlevel < 0 || alpha < 0.0 ) { fprintf(stderr, "\n fatal error in GPart_smoothBisector(%p,%d,%f)" "\n bad input\n", gpart, nlevel, alpha) ; exit(-1) ; } g = gpart->g ; compids = IV_entries(&gpart->compidsIV) ; cweights = IV_entries(&gpart->cweightsIV) ; vwghts = g->vwghts ; msglvl = gpart->msglvl ; msgFile = gpart->msgFile ; bestcost = eval(alpha, cweights[0], cweights[1], cweights[2]) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n smoothBisector : nlevel = %d, alpha = %f", nlevel, alpha) ; fprintf(msgFile, "\n old partition cost %.3f, weights = %5d %5d %5d", bestcost, cweights[0], cweights[1], cweights[2]) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n compids") ; IVfp80(msgFile, g->nvtx, compids, 80, &ierr) ; } /* ------------------------------------ loop while improvement is being made ------------------------------------ */ ipass = 0 ; while ( 1 ) { if ( msglvl > 1 ) { if ( cweights[1] >= cweights[2] ) { balance = ((double) cweights[1]) / cweights[2] ; } else { balance = ((double) cweights[2]) / cweights[1] ; } cost = cweights[0] * (1 + alpha * balance) ; fprintf(msgFile, "\n\n ### pass %d, cweights : %d %d %d, balance = %5.3f, cost = %.1f", ipass, cweights[0], cweights[1], cweights[2], balance, cost) ; fflush(msgFile) ; } /* --------------------------- identify the wide separator --------------------------- */ YVmapIV = GPart_identifyWideSep(gpart, nlevel, nlevel) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n nlevel = %d, |widesep| = %d", nlevel, IV_size(YVmapIV)) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n YVmapIV") ; IV_writeForHumanEye(YVmapIV, msgFile) ; } /* ------------------------------------------------- get the Y = Y_0 cup Y_1 cup Y_2 cup Y_3 partition ------------------------------------------------- */ YCmapIV = GPart_makeYCmap(gpart, YVmapIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n YCmapIV found") ; fflush(msgFile) ; } /* -------------------- smooth the separator -------------------- */ newcost = GPart_smoothYSep(gpart, YVmapIV, YCmapIV, alpha) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n newcost = %.3f", newcost) ; fflush(msgFile) ; } /* ------------------------ free the two map vectors ------------------------ */ IV_free(YVmapIV) ; IV_free(YCmapIV) ; /* ------------------------------- check for an improved partition ------------------------------- */ if ( newcost == bestcost ) { break ; } else { bestcost = newcost ; } ipass++ ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n final partition weights [%d %d %d], cost = %.3f", cweights[0], cweights[1], cweights[2], bestcost) ; fflush(msgFile) ; } return(bestcost) ; } /*--------------------------------------------------------------------*/ /* ----------------------------- partition evaluation function ----------------------------- */ static float eval ( float alpha, float wS, float wB, float wW ) { float cost ; #if MYDEBUG > 2 fprintf(msgFile, "\n alpha = %f, wS = %f, wB = %f, wW = %f", alpha, wS, wB, wW) ; #endif if ( wB == 0 || wW == 0 ) { cost = (wS + wB + wW) * (wS + wB + wW) ; } else if ( wB >= wW ) { cost = wS*(1. + (alpha*wB)/wW) ; } else { cost = wS*(1. + (alpha*wW)/wB) ; } #if MYDEBUG > 2 fprintf(msgFile, ", cost = %f", cost) ; #endif return(cost) ; } /*--------------------------------------------------------------------*/ GPart/src/smoothBy2layers.c010064400020550007177000000117620653410612100171540ustar00clevecompmath00000400000006/* smoothBy2layers.c */ #include "../GPart.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------- static declaration of evaluation function ----------------------------------------- */ static float eval ( float alpha, float wS, float wB, float wW ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- smooth a bisector using the alternating two-layer algorithm option -- network flag 1 --> make the network bipartite as for the Dulmage-Mendelsohn decomposition otherwise -- use network induced by the wide separator alpha -- cost function parameter created -- 96jun08, cca ----------------------------------------------------------- */ void GPart_smoothBy2layers ( GPart *gpart, int option, float alpha ) { FILE *msgFile ; float bestcost, newcost ; int ierr, large, msglvl, nY, pass, small, y ; int *cweights, *YCmap ; IV *YCmapIV, *YVmapIV ; /* --------------- check the input --------------- */ if ( gpart == NULL || alpha < 0.0 ) { fprintf(stderr, "\n fatal error in GPart_smoothBy2layers(%p,%f)" "\n bad input\n", gpart, alpha) ; exit(-1) ; } pass = 1 ; cweights = IV_entries(&gpart->cweightsIV) ; bestcost = eval(alpha, cweights[0], cweights[1], cweights[2]) ; msgFile = gpart->msgFile ; msglvl = gpart->msglvl ; while ( 1 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n PASS %d : attempting a move towards the larger component", pass) ; fflush(msgFile) ; } if ( cweights[1] >= cweights[2] ) { large = 1 ; small = 2 ; YVmapIV = GPart_identifyWideSep(gpart, 1, 0) ; } else { large = 2 ; small = 1 ; YVmapIV = GPart_identifyWideSep(gpart, 0, 1) ; } YCmapIV = GPart_makeYCmap(gpart, YVmapIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n YCmapIV") ; IV_writeForHumanEye(YCmapIV, msgFile) ; fflush(msgFile) ; } IV_sizeAndEntries(YCmapIV, &nY, &YCmap) ; if ( option == 1 ) { /* ---------------------------- generate a bipartite network ---------------------------- */ for ( y = 0 ; y < nY ; y++ ) { if ( YCmap[y] != small ) { YCmap[y] = large ; } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n calling GPartSmoothYSep") ; fflush(msgFile) ; } newcost = GPart_smoothYSep(gpart, YVmapIV, YCmapIV, alpha) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n bestcost = %.2f, newcost = %.2f", bestcost, newcost) ; fflush(msgFile) ; } IV_free(YVmapIV) ; IV_free(YCmapIV) ; if ( newcost == bestcost ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n PASS %d : attempting a move towards the smaller component", pass) ; fflush(msgFile) ; } if ( cweights[1] >= cweights[2] ) { large = 1 ; small = 2 ; YVmapIV = GPart_identifyWideSep(gpart, 0, 1) ; } else { large = 2 ; small = 1 ; YVmapIV = GPart_identifyWideSep(gpart, 1, 0) ; } YCmapIV = GPart_makeYCmap(gpart, YVmapIV) ; IV_sizeAndEntries(YCmapIV, &nY, &YCmap) ; if ( option == 1 ) { /* ---------------------------- generate a bipartite network ---------------------------- */ for ( y = 0 ; y < nY ; y++ ) { if ( YCmap[y] != large ) { YCmap[y] = small ; } } } newcost = GPart_smoothYSep(gpart, YVmapIV, YCmapIV, alpha) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n bestcost = %.2f, newcost = %.2f", bestcost, newcost) ; fflush(msgFile) ; } IV_free(YVmapIV) ; IV_free(YCmapIV) ; } if ( newcost == bestcost ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n no improvement made") ; fflush(msgFile) ; } break ; } else { bestcost = newcost ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n improvement made") ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n compids") ; IVfp80(msgFile, gpart->nvtx, IV_entries(&gpart->compidsIV), 80, &ierr) ; fflush(msgFile) ; } } pass++ ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n leaving smoothBy2layers") ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------- partition evaluation function ----------------------------- */ static float eval ( float alpha, float wS, float wB, float wW ) { float bestcost ; if ( wB == 0 || wW == 0 ) { bestcost = (wS + wB + wW) * (wS + wB + wW) ; } else if ( wB >= wW ) { bestcost = wS*(1. + (alpha*wB)/wW) ; } else { bestcost = wS*(1. + (alpha*wW)/wB) ; } return(bestcost) ; } /*--------------------------------------------------------------------*/ GPart/src/smoothYSep.c010064400020550007177000000471050663354707200161760ustar00clevecompmath00000400000006/* smoothYSep.c */ #include "../GPart.h" #include "../../Network.h" /*--------------------------------------------------------------------*/ /* ----------------- static prototypes ----------------- */ static Network * createNetwork ( Graph *g, int compids[], IV *YVmapIV, IV *YCmapIV, IV *NYmapIV, int msglvl, FILE *msgFile ) ; static void getNewCompids ( int nnode, int NYmap[], int YCmap[], int mark[], int Ycompids[], int msglvl, FILE *msgFile ) ; static float eval ( float alpha, float wS, float wB, float wW) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ smooth the wide separator given by YVmapIV by forming the associated network, solving the max flow problem, and examining two min-cuts. YVmapIV -- map from wide vertices Y to vertices V YCmapIV -- map from wide vertices Y to {0,1,2,3} YCmap[y] = 0 --> treat y as an internal node adjacent to neither component YCmap[y] = 1 --> treat y as adjacent only to component 1 YCmap[y] = 2 --> treat y as adjacent only to component 2 YCmap[y] = 3 --> treat y as adjacent to components 1 and 2 alpha -- cost function parameter created -- 96jun08, cca ------------------------------------------------------------ */ float GPart_smoothYSep ( GPart *gpart, IV *YVmapIV, IV *YCmapIV, float alpha ) { FILE *msgFile ; float bestcost, newcost1, newcost2 ; Graph *g ; Ideq *deq ; int ierr, msglvl, nnode, newcomp, nY, oldcomp, v, vwght, y ; int *compids, *cweights, *mark, *vwghts, *Ycompids1, *Ycompids2, *YCmap, *YVmap ; int deltas[3] ; IV *NYmapIV ; Network *network ; /* --------------- check the input --------------- */ if ( gpart == NULL || (g = gpart->g) == NULL || YVmapIV == NULL || (nY = IV_size(YVmapIV)) <= 0 || (YVmap = IV_entries(YVmapIV)) == NULL || YCmapIV == NULL || IV_size(YCmapIV) != nY || (YCmap = IV_entries(YCmapIV)) == NULL || alpha < 0.0 ) { fprintf(stderr, "\n fatal error in GPart_smoothSep(%p,%p,%p,%f)" "\n bad input\n", gpart, YVmapIV, YCmapIV, alpha) ; exit(-1) ; } compids = IV_entries(&gpart->compidsIV) ; cweights = IV_entries(&gpart->cweightsIV) ; vwghts = g->vwghts ; msgFile = gpart->msgFile ; msglvl = gpart->msglvl ; if ( msglvl > 2 ) { fprintf(msgFile, "\n YVmapIV") ; IV_writeForHumanEye(YVmapIV, msgFile) ; fprintf(msgFile, "\n YCmapIV") ; IV_writeForHumanEye(YCmapIV, msgFile) ; } /* ------------------ create the network ------------------ */ NYmapIV = IV_new() ; network = createNetwork(g, compids, YVmapIV, YCmapIV, NYmapIV, msglvl, msgFile) ; Network_setMessageInfo(network, msglvl, msgFile) ; nnode = network->nnode ; if ( msglvl > 1 ) { fprintf(msgFile, "\n network : %d nodes, %d arcs", nnode, network->narc) ; fflush(msgFile) ; } if ( msglvl > 4 ) { Network_writeForHumanEye(network, msgFile) ; } /* -------------------- solve for a max flow -------------------- */ Network_findMaxFlow(network) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n after max flow solution, %d arc traversals", network->ntrav) ; fflush(msgFile) ; } if ( msglvl > 4 ) { Network_writeForHumanEye(network, msgFile) ; } /* ------------------------------ evaluate the present partition ------------------------------ */ bestcost = eval(alpha, cweights[0], cweights[1], cweights[2]) ; if ( msglvl > 1 ) { int maxval, minval, val1, val2 ; fprintf(msgFile, "\n present partition : < %d, %d, %d >", cweights[0], cweights[1], cweights[2]) ; val1 = cweights[1] ; val2 = cweights[2] ; minval = (val1 <= val2) ? val1 : val2 ; maxval = (val1 > val2) ? val1 : val2 ; if ( minval == 0 ) { fprintf(msgFile, ", imbalance = infinite") ; } else { fprintf(msgFile, ", imbalance = %6.3f", ((double) maxval)/minval) ; } fprintf(msgFile, ", cost = %.2f", bestcost) ; fflush(msgFile) ; } /* --------------------------- set up some working storage --------------------------- */ deq = Ideq_new() ; Ideq_resize(deq, nnode) ; mark = IVinit(nnode, -1) ; Ycompids1 = IVinit(nY, -1) ; Ycompids2 = IVinit(nY, -1) ; /* --------------------------------------- find a min-cut starting from the source and evaluate the partition --------------------------------------- */ Network_findMincutFromSource(network, deq, mark) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n mark starting from source") ; IVfp80(msgFile, nnode, mark, 80, &ierr) ; fflush(msgFile) ; } getNewCompids(nnode, IV_entries(NYmapIV), YCmap, mark, Ycompids1, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n Ycompids1") ; IVfp80(msgFile, nY, Ycompids1, 80, &ierr) ; fflush(msgFile) ; } deltas[0] = deltas[1] = deltas[2] = 0 ; for ( y = 0 ; y < nY ; y++ ) { v = YVmap[y] ; oldcomp = compids[v] ; newcomp = Ycompids1[y] ; if ( msglvl > 5 ) { fprintf(msgFile, "\n y = %d, v = %d, oldcomp = %d, newcomp = %d", y, v, oldcomp, newcomp) ; fflush(msgFile) ; } if ( oldcomp != newcomp ) { vwght = (vwghts != NULL) ? vwghts[v] : 1 ; deltas[oldcomp] -= vwght ; deltas[newcomp] += vwght ; } } newcost1 = eval(alpha, cweights[0] + deltas[0], cweights[1] + deltas[1], cweights[2] + deltas[2]) ; if ( msglvl > 1 ) { int maxval, minval, val1, val2 ; fprintf(msgFile, "\n min-cut from source: < %d, %d, %d >", cweights[0] + deltas[0], cweights[1] + deltas[1], cweights[2] + deltas[2]) ; val1 = cweights[1] + deltas[1] ; val2 = cweights[2] + deltas[2] ; minval = (val1 <= val2) ? val1 : val2 ; maxval = (val1 > val2) ? val1 : val2 ; if ( minval == 0 ) { fprintf(msgFile, ", imbalance = infinite") ; } else { fprintf(msgFile, ", imbalance = %6.3f", ((double) maxval)/minval) ; } fprintf(msgFile, ", newcost1 = %.2f", newcost1) ; fflush(msgFile) ; } /* --------------------------------------- find a min-cut starting from the sink and evaluate the partition --------------------------------------- */ Network_findMincutFromSink(network, deq, mark) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n mark starting from sink") ; IVfp80(msgFile, nnode, mark, 80, &ierr) ; fflush(msgFile) ; } getNewCompids(nnode, IV_entries(NYmapIV), YCmap, mark, Ycompids2, msglvl, msgFile) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n Ycompids2") ; IVfp80(msgFile, nY, Ycompids2, 80, &ierr) ; fflush(msgFile) ; } deltas[0] = deltas[1] = deltas[2] = 0 ; for ( y = 0 ; y < nY ; y++ ) { v = YVmap[y] ; oldcomp = compids[v] ; newcomp = Ycompids2[y] ; if ( oldcomp != newcomp ) { vwght = (vwghts != NULL) ? vwghts[v] : 1 ; deltas[oldcomp] -= vwght ; deltas[newcomp] += vwght ; } } newcost2 = eval(alpha, cweights[0] + deltas[0], cweights[1] + deltas[1], cweights[2] + deltas[2]) ; if ( msglvl > 1 ) { int maxval, minval, val1, val2 ; fprintf(msgFile, "\n min-cut from sink: < %d, %d, %d >", cweights[0] + deltas[0], cweights[1] + deltas[1], cweights[2] + deltas[2]) ; val1 = cweights[1] + deltas[1] ; val2 = cweights[2] + deltas[2] ; minval = (val1 <= val2) ? val1 : val2 ; maxval = (val1 > val2) ? val1 : val2 ; if ( minval == 0 ) { fprintf(msgFile, ", imbalance = infinite") ; } else { fprintf(msgFile, ", imbalance = %6.3f", ((double) maxval)/minval) ; } fprintf(msgFile, ", newcost1 = %.2f", newcost2) ; fflush(msgFile) ; } /* --------------------------------------------- decide whether to accept either new partition --------------------------------------------- */ if ( newcost1 <= newcost2 && newcost1 < bestcost ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n accepting new partition from source min-cut") ; fflush(msgFile) ; } for ( y = 0 ; y < nY ; y++ ) { v = YVmap[y] ; oldcomp = compids[v] ; newcomp = Ycompids1[y] ; if ( oldcomp != newcomp ) { compids[v] = newcomp ; vwght = (vwghts != NULL) ? vwghts[v] : 1 ; cweights[oldcomp] -= vwght ; cweights[newcomp] += vwght ; } } bestcost = newcost1 ; if ( msglvl > 1 ) { fprintf(msgFile, ", cost = %.3f", bestcost) ; fflush(msgFile) ; } } else if ( newcost2 <= newcost1 && newcost2 < bestcost ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n accepting new partition from sink min-cut") ; fflush(msgFile) ; } for ( y = 0 ; y < nY ; y++ ) { v = YVmap[y] ; oldcomp = compids[v] ; newcomp = Ycompids2[y] ; if ( oldcomp != newcomp ) { compids[v] = newcomp ; vwght = (vwghts != NULL) ? vwghts[v] : 1 ; cweights[oldcomp] -= vwght ; cweights[newcomp] += vwght ; } } bestcost = newcost2 ; if ( msglvl > 1 ) { fprintf(msgFile, ", cost = %.3f", bestcost) ; fflush(msgFile) ; } } /* ------------------------ free the working storage ------------------------ */ Network_free(network) ; IV_free(NYmapIV) ; IVfree(mark) ; IVfree(Ycompids1) ; IVfree(Ycompids2) ; Ideq_free(deq) ; return(bestcost) ; } /*--------------------------------------------------------------------*/ /* ------------------ create the network ------------------ */ static Network * createNetwork ( Graph *g, int compids[], IV *YVmapIV, IV *YCmapIV, IV *NYmapIV, int msglvl, FILE *msgFile ) { int first, ierr, ii, i0, i1, i12, i2, maxcap, mnode, n0, n1, n12, n2, nvtx, nY, second, sink, source, v, vnet, vsize, vwght, w, wnet, y, zwid ; int *NYmap, *vadj, *VNmap, *vwghts, *YCmap, *YVmap ; Network *network ; /* --------------- check the input --------------- */ if ( g == NULL || (nvtx = g->nvtx) <= 0 || compids == NULL || YVmapIV == NULL || (nY = IV_size(YVmapIV)) <= 0 || (YVmap = IV_entries(YVmapIV)) == NULL || YCmapIV == NULL || nY != IV_size(YCmapIV) || (YCmap = IV_entries(YCmapIV)) == NULL || NYmapIV == NULL ) { fprintf(stderr, "\n fatal error in createNetwork(%p,%p,%p,%p,%p)" "\n bad input\n", g, compids, YVmapIV, NYmapIV, YCmapIV) ; exit(-1) ; } vwghts = g->vwghts ; if ( vwghts == NULL ) { maxcap = nvtx ; } else { maxcap = IVsum(nvtx, vwghts) ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n maxcap = %d", maxcap) ; fflush(msgFile) ; } /* -------------------------------------------------- count the number of nodes in each of the four sets -------------------------------------------------- */ n1 = n12 = n0 = n2 = 0 ; for ( y = 0 ; y < nY ; y++ ) { switch ( YCmap[y] ) { case 0 : n0++ ; break ; case 1 : n1++ ; break ; case 2 : n2++ ; break ; case 3 : n12++ ; break ; default : fprintf(stderr, "\n fatal error, y = %d, YCmap[%d] = %d", y, y, YCmap[y]) ; exit(-1) ; } } mnode = 1 + n1 + n12 + 2*n0 + n2 + 1 ; if ( msglvl > 2 ) { fprintf(msgFile, "\n n12 = %d, n1 = %d, n0 = %d, n2 = %d", n12, n1, n0, n2) ; fprintf(msgFile, "\n %d nodes in the network", mnode) ; fflush(msgFile) ; } /* ----------------------------------- set up the N --> Y and V --> N maps ----------------------------------- */ IV_init(NYmapIV, mnode, NULL) ; NYmap = IV_entries(NYmapIV) ; VNmap = IVinit(nvtx, -1) ; i12 = 1 ; i1 = 1 + n12 ; i0 = 1 + n12 + n1 ; i2 = 1 + n12 + n1 + 2*n0 ; for ( y = 0 ; y < nY ; y++ ) { v = YVmap[y] ; switch ( YCmap[y] ) { case 0 : NYmap[i0] = y ; NYmap[i0+1] = y ; VNmap[v] = i0 ; if ( msglvl > 4 ) { fprintf(msgFile, "\n comp 0 : y = %d, v = %d, i0 = %d and %d", y, v, i0, i0+1) ; fflush(msgFile) ; } i0 += 2 ; break ; case 1 : NYmap[i1] = y ; VNmap[v] = i1 ; if ( msglvl > 4 ) { fprintf(msgFile, "\n comp 1 : y = %d, v = %d, i1 = %d", y, v, i1) ; fflush(msgFile) ; } i1++ ; break ; case 2 : NYmap[i2] = y ; VNmap[v] = i2 ; if ( msglvl > 4 ) { fprintf(msgFile, "\n comp 2 : y = %d, v = %d, i2 = %d", y, v, i2) ; fflush(msgFile) ; } i2++ ; break ; case 3 : NYmap[i12] = y ; VNmap[v] = i12 ; if ( msglvl > 4 ) { fprintf(msgFile, "\n comp 12 : y = %d, v = %d, i12 = %d", y, v, i12) ; fflush(msgFile) ; } i12++ ; break ; default : fprintf(stderr, "\n fatal error, y = %d, v = %d, YCmap[%d] = %d", y, v, y, YCmap[y]) ; exit(-1) ; } } if ( msglvl > 4 ) { fprintf(msgFile, "\n NYmapIV") ; IV_writeForHumanEye(NYmapIV, msgFile) ; fprintf(msgFile, "\n VNmap") ; IVfp80(msgFile, nvtx, VNmap, 80, &ierr) ; fflush(msgFile) ; } /* ------------------------- create the Network object ------------------------- */ source = 0 ; sink = mnode - 1 ; network = Network_new() ; Network_init(network, mnode, 0) ; /* --------------- insert the arcs --------------- */ for ( y = 0 ; y < nY ; y++ ) { v = YVmap[y] ; vnet = VNmap[v] ; vwght = (vwghts != NULL) ? vwghts[v] : 1 ; if ( msglvl > 4 ) { fprintf(msgFile, "\n checking out y = %d, v = %d, vnet = %d, vwght = %d", y, v, vnet, vwght) ; fflush(msgFile) ; } switch ( YCmap[y] ) { case 0 : first = vnet ; second = first + 1 ; Network_addArc(network, first, second, vwght, 0) ; if ( msglvl > 4 ) { fprintf(msgFile, "\n S: arc (%d, %d) --> (%d,%d)", v, v, first, second) ; fflush(msgFile) ; } Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < nvtx && v != w && (wnet = VNmap[w]) != -1 ) { zwid = NYmap[wnet] ; if ( YCmap[zwid] == 0 ) { first = vnet + 1 ; second = wnet ; if ( msglvl > 4 ) { fprintf(msgFile, "\n S: arc (%d, %d) --> (%d,%d)", v, w, first, second) ; fflush(msgFile) ; } Network_addArc(network, first, second, maxcap, 0) ; } } } break ; case 1 : first = source ; second = vnet ; Network_addArc(network, first, second, vwght, 0) ; if ( msglvl > 4 ) { fprintf(msgFile, "\n B: arc (source, %d) --> (%d,%d)", v, first, second) ; fflush(msgFile) ; } Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( msglvl > 4 ) { fprintf(msgFile, "\n w = %d", w) ; fflush(msgFile) ; } if ( w < nvtx && v != w && (wnet = VNmap[w]) != -1 ) { zwid = NYmap[wnet] ; if ( msglvl > 4 ) { fprintf(msgFile, "\n wnet = %d", wnet) ; fflush(msgFile) ; fprintf(msgFile, "\n zwid = %d", zwid) ; fflush(msgFile) ; } if ( YCmap[zwid] != 1 ) { first = vnet ; second = wnet ; if ( msglvl > 4 ) { fprintf(msgFile, "\n B: arc (%d, %d) --> (%d,%d)", v, w, first, second) ; fflush(msgFile) ; } Network_addArc(network, first, second, maxcap, 0) ; } } } break ; case 2 : first = vnet ; second = sink ; Network_addArc(network, first, second, vwght, 0) ; if ( msglvl > 4 ) { fprintf(msgFile, "\n B: arc (%d, sink) --> (%d,%d)", v, first, second) ; fflush(msgFile) ; } Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < nvtx && v != w && (wnet = VNmap[w]) != -1 ) { zwid = NYmap[wnet] ; if ( YCmap[zwid] == 0 ) { first = wnet + 1 ; second = vnet ; if ( msglvl > 4 ) { fprintf(msgFile, "\n B: arc (%d, %d) --> (%d,%d)", w, v, first, second) ; fflush(msgFile) ; } Network_addArc(network, first, second, maxcap, 0) ; } } } break ; case 3 : first = source ; second = vnet ; Network_addArc(network, first, second, vwght, 0) ; if ( msglvl > 4 ) { fprintf(msgFile, "\n B: arc (source, %d) --> (%d,%d)", v, first, second) ; fflush(msgFile) ; } first = vnet ; second = sink ; Network_addArc(network, first, second, vwght, 0) ; if ( msglvl > 4 ) { fprintf(msgFile, "\n B: arc (%d, sink) --> (%d,%d)", v, first, second) ; fflush(msgFile) ; } break ; default : fprintf(stderr, "\n fatal error, y = %d, v = %d, YCmap[%d] = %d", y, v, y, YCmap[y]) ; exit(-1) ; } } /* ------------------------ free the working storage ------------------------ */ IVfree(VNmap) ; return(network) ; } /*--------------------------------------------------------------------*/ /* ----------------------------- partition evaluation function ----------------------------- */ static float eval ( float alpha, float wS, float wB, float wW ) { float cost ; if ( wB == 0 || wW == 0 ) { cost = (wS + wB + wW) * (wS + wB + wW) ; } else if ( wB >= wW ) { cost = wS*(1. + (alpha*wB)/wW) ; } else { cost = wS*(1. + (alpha*wW)/wB) ; } return(cost) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- given a min-cut via the mark[] vector, get the new component ids created -- 96jun08, cca -------------------------------------- */ static void getNewCompids ( int nnode, int NYmap[], int YCmap[], int mark[], int Ycompids[], int msglvl, FILE *msgFile ) { int sink, y, ynet ; /* ------------------------------------------ decide whether to accept the new separator ------------------------------------------ */ sink = nnode - 1 ; ynet = 1 ; while ( ynet < sink ) { y = NYmap[ynet] ; if ( msglvl > 2 ) { fprintf(msgFile, "\n ynet = %d, y = %d, YCmap[%d] = %d", ynet, y, y, YCmap[y]) ; fflush(msgFile) ; } switch ( YCmap[y] ) { case 0 : if ( mark[ynet] != mark[ynet+1] ) { Ycompids[y] = 0 ; } else { Ycompids[y] = mark[ynet] ; } ynet += 2 ; break ; case 1 : if ( mark[ynet] == 1 ) { Ycompids[y] = 1 ; } else { Ycompids[y] = 0 ; } ynet++ ; break ; case 2 : if ( mark[ynet] == 2 ) { Ycompids[y] = 2 ; } else { Ycompids[y] = 0 ; } ynet++ ; break ; case 3 : Ycompids[y] = 0 ; ynet++ ; break ; default : fprintf(stderr, "\n fatal error in getNewCompids()" "\n ynet = %d, y = %d, YCmap[%d] = %d", ynet, y, y, YCmap[y]) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, ", Ycompids[%d] = %d", y, Ycompids[y]) ; fflush(msgFile) ; } } return ; } /*--------------------------------------------------------------------*/ *YCmapIV, IV *NYmapIV, int msglvl, FILE *msgFile ) { int first, ierr, ii, i0, i1, i12, i2, maxcap, mnode, n0, n1, n12, n2, nvtx, nY, second, sink, source, v, vnet, vsize, vwght, w, wnet, y, zwid ; int *NYmap, *vadj, *VNmap, *vwghts, *YCmap, *YVmap ; Network *network ; /* --------------- check the input --------------- */ if ( g == NULL || (nvtx = g->nvtx) <= 0 || compids =GPart/src/split.c010064400020550007177000000057310653410612100152000ustar00clevecompmath00000400000006/* split.c */ #include "../GPart.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* -------------------------------------------- split the graph partition object into pieces created -- 95nov29, cca -------------------------------------------- */ void GPart_split ( GPart *gpart ) { FILE *msgFile ; GPart *gpartchild ; Graph *g, *gchild ; int domwght, icomp, ierr, msglvl, ncomp, nvtot, nvtx, sepwght ; int *compids, *cweights, *map ; /* --------------- check the input --------------- */ if ( gpart == NULL || (g = gpart->g) == NULL ) { fprintf(stderr, "\n fatal error in GPart_split(%p)" "\n bad input\n", gpart) ; exit(-1) ; } if ( gpart->fch != NULL ) { fprintf(stderr, "\n fatal error in GPart_split(%p)" "\n child(ren) exist, already split\n", gpart) ; exit(-1) ; } msgFile = gpart->msgFile ; msglvl = gpart->msglvl ; /* ------------------------------ count the number of subgraphs and fill the cweights[] vector ------------------------------ */ nvtx = g->nvtx ; GPart_setCweights(gpart) ; ncomp = gpart->ncomp ; cweights = IV_entries(&gpart->cweightsIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n inside GPart_split, %d components, cweights : ", ncomp) ; IV_fp80(&gpart->cweightsIV, msgFile, 25, &ierr) ; } if ( ncomp == 1 ) { return ; } /* ----------------------------------------- compute the weight of the components and count the number of nontrivial components ----------------------------------------- */ sepwght = cweights[0] ; domwght = 0 ; for ( icomp = 1 ; icomp <= ncomp ; icomp++ ) { domwght += cweights[icomp] ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n separator weight = %d, weight of components = %d", sepwght, domwght) ; } /* ------------------------------------------------------ for each component create its subgraph with boundary create a GPart object to contain the subgraph and set as the child of the present GPart object end for ------------------------------------------------------ */ compids = IV_entries(&gpart->compidsIV) ; for ( icomp = 1 ; icomp <= ncomp ; icomp++ ) { gpartchild = GPart_new() ; gchild = Graph_subGraph(g, icomp, compids, &map) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n component %d", icomp) ; fprintf(msgFile, "\n map to parent") ; IVfp80(msgFile, gchild->nvtx + gchild->nvbnd, map, 80, &ierr) ; Graph_writeForHumanEye(gchild, msgFile) ; fflush(msgFile) ; } GPart_init(gpartchild, gchild) ; nvtot = gpartchild->nvtx + gpartchild->nvbnd ; IV_init2(&gpartchild->vtxMapIV, nvtot, nvtot, 1, map) ; gpartchild->par = gpart ; gpartchild->sib = gpart->fch ; gpart->fch = gpartchild ; gpartchild->msglvl = gpart->msglvl ; gpartchild->msgFile = gpart->msgFile ; } return ; } /*--------------------------------------------------------------------*/ GPart/src/util.c010064400020550007177000000165530653410612100150260ustar00clevecompmath00000400000006/* util.c */ #include "../GPart.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- set the component weights from the compids[] vector created -- 95oct05, cca modified -- 95nov29, cca ---------------------------------------------------- */ void GPart_setCweights ( GPart *gpart ) { Graph *g ; int ierr, ii, last, ncomp, now, nvtx, u, usize, v, w ; int *compids, *cweights, *list, *uadj, *vwghts ; /* -------------- check the data -------------- */ if ( gpart == NULL ) { fprintf(stderr, "\n fatal error in GPart_setCweights(%p)" "\n bad input\n", gpart) ; exit(-1) ; } if ( (nvtx = gpart->nvtx) <= 0 || (g = gpart->g) == NULL ) { fprintf(stderr, "\n fatal error in GPart_setCweights(%p)" "\n bad Gpart object\n", gpart) ; exit(-1) ; } /* ---------------------------------------------------------- set the component id of all non-multisector vertices to -1 ---------------------------------------------------------- */ compids = IV_entries(&gpart->compidsIV) ; for ( v = 0 ; v < nvtx ; v++ ) { if ( compids[v] != 0 ) { compids[v] = -1 ; } } /* ---------------------------------------------------------- compute the number of components and set the component ids ---------------------------------------------------------- */ list = IVinit(nvtx, -1) ; ncomp = 0 ; for ( v = 0 ; v < nvtx ; v++ ) { if ( compids[v] == -1 ) { compids[v] = ++ncomp ; now = last = 0 ; list[now] = v ; while ( now <= last ) { u = list[now++] ; Graph_adjAndSize(g, u, &usize, &uadj) ; for ( ii = 0 ; ii < usize ; ii++ ) { if ( (w = uadj[ii]) < nvtx && compids[w] == -1 ) { compids[w] = ncomp ; list[++last] = w ; } } } } } /* ---------------------------- set the number of components ---------------------------- */ gpart->ncomp = ncomp ; /* ------------------------- set the component weights ------------------------- */ IV_setSize(&gpart->cweightsIV, 1 + ncomp) ; cweights = IV_entries(&gpart->cweightsIV) ; IVzero(1 + ncomp, cweights) ; if ( (vwghts = gpart->g->vwghts) != NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { cweights[compids[v]] += vwghts[v] ; } } else { for ( v = 0 ; v < nvtx ; v++ ) { cweights[compids[v]]++ ; } } /* ------------------------ free the working storage ------------------------ */ IVfree(list) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95oct05, cca ---------------------------------------------- */ int GPart_sizeOf ( GPart *gpart ) { int nbytes ; if ( gpart == NULL ) { fprintf(stderr, "\n fatal error in GPart_sizeOf(%p)" "\n bad input\n", gpart) ; exit(-1) ; } nbytes = sizeof(struct _GPart) ; nbytes += IV_size(&gpart->compidsIV) ; nbytes += IV_size(&gpart->cweightsIV) ; nbytes += IV_size(&gpart->vtxMapIV) ; return(nbytes) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- return 1 if vertex is adjacent to only one domain and fill *pdomid with the domain's id return 0 otherwise created -- 95oct19, cca ------------------------------------------------- */ int GPart_vtxIsAdjToOneDomain ( GPart *gpart, int v, int *pdomid ) { Graph *g ; int domid, ii, nvtx, u, Vi, vsize ; int *compids, *vadj ; /* --------------- check the input --------------- */ if ( gpart == NULL || v < 0 || (nvtx = gpart->nvtx) <= v || (g = gpart->g) == NULL || pdomid == NULL ) { fprintf(stderr, "\n fatal error in GPart_vtxIsAdjToOneDomain(%p,%d,%p)" "\n bad input\n", gpart, v, pdomid) ; exit(-1) ; } compids = IV_entries(&gpart->compidsIV) ; /* ------------------------------------------ fill domids[] with ids of adjacent domains ------------------------------------------ */ Graph_adjAndSize(g, v, &vsize, &vadj) ; domid = *pdomid = -1 ; for ( ii = 0 ; ii < vsize ; ii++ ) { if ( (u = vadj[ii]) < nvtx && (Vi = compids[u]) > 0 ) { if ( domid == -1 ) { *pdomid = domid = Vi ; } else if ( Vi != domid ) { return(0) ; } } } if ( domid == -1 ) { return(0) ; } else { return(1) ; } } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ return 1 if the partition has a valid vertex separator 0 otherwise created -- 95oct18, cca ------------------------------------------------------ */ int GPart_validVtxSep ( GPart *gpart ) { Graph *g ; int icomp, ii, nvtx, v, vsize, w ; int *compids, *vadj ; /* --------------- check the input --------------- */ if ( gpart == NULL ) { fprintf(stderr, "\n fatal error in GPart_validVtxSep(%p)" "\n bad input\n", gpart) ; exit(-1) ; } nvtx = gpart->nvtx ; g = gpart->g ; compids = IV_entries(&gpart->compidsIV) ; /* --------------------------------------------------- loop over the vertices check that each non-separator vertex is adjacent to vertices only in its component or in the separator --------------------------------------------------- */ for ( v = 0 ; v < nvtx ; v++ ) { if ( (icomp = compids[v]) != 0 ) { Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { if ( (w = vadj[ii]) < nvtx ) { if ( compids[w] != 0 && compids[w] != icomp ) { fprintf(stderr, "\n vertex %d, component %d, is adjacent to vertex %d, component %d", v, icomp, w, compids[w]) ; return(0) ; } } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- return an IV object filled with the weights of the component's boundaries created -- 96oct21, cca ------------------------------------- */ IV * GPart_bndWeightsIV ( GPart *gpart ) { Graph *graph ; int icomp, ii, ncomp, nvtx, v, vsize, vwght, w ; int *bnd, *compids, *cweights, *mark, *vadj, *vwghts ; IV *bndIV ; /* --------------- check the input --------------- */ if ( gpart == NULL || (graph = gpart->g) == NULL ) { fprintf(stderr, "\n fatal error in GPart_bndWeightsIV(%p)" "\n bad input\n", gpart) ; exit(-1) ; } nvtx = gpart->nvtx ; ncomp = gpart->ncomp ; compids = IV_entries(&gpart->compidsIV) ; cweights = IV_entries(&gpart->cweightsIV) ; vwghts = graph->vwghts ; bndIV = IV_new() ; IV_init(bndIV, 1 + ncomp, NULL) ; IV_fill(bndIV, 0) ; bnd = IV_entries(bndIV) ; mark = IVinit(ncomp+1, -1) ; for ( v = 0 ; v < nvtx ; v++ ) { if ( compids[v] == 0 ) { vwght = (vwghts == NULL) ? 1 : vwghts[v] ; Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( (icomp = compids[w]) != 0 && mark[icomp] != v ) { mark[icomp] = v ; bnd[icomp] += vwght ; } } } } IVfree(mark) ; return(bndIV) ; } /*--------------------------------------------------------------------*/ GPart/drivers/do_DDviaFishnet010075500020550007177000000012220654276041200175070ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = BCSSTK24 set inGraphFile = $matrices/$matrix/orig1.graphf set msglvl = 2 set msgFile = stdout set firstseed = 1 set lastseed = 2 set lastseed = 21 set lastseed = 6 set lastseed = 51 set lastseed = 11 set lastseed = 1 set minweight = 100 set maxweight = 200 set freeze = 4.0 set outIVfile = none set outIVfile = $matrices/$matrix/fishnet.ivf @ seed = $firstseed while ( $seed <= $lastseed ) testDDviaFishnet $msglvl $msgFile $inGraphFile \ $freeze $minweight $maxweight $seed \ $outIVfile @ seed = $seed + 1 end GPart/drivers/do_RBviaDDsep010075500020550007177000000031170654517006100171250ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set matrix = BCSSTK16 set matrix = BCSSTK24 set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig1.graphf set msglvl = 1 set msgFile = stdout set nseed = 1 set nseed = 21 set minweight = 10 set maxweight = 20 set minweight = 50 set maxweight = 100 set minweight = 200 set maxweight = 400 set minweight = 5 set maxweight = 10 set minweight = 100 set maxweight = 200 set alpha = 0.25 set alpha = 1.0 set freeze = 4.0 set maxDomWeight = 200000 set maxDomWeight = 8000 set maxDomWeight = 2000 set maxDomWeight = 4000 set maxDomWeight = 500 set maxDomWeight = 250 set maxDomWeight = 8000 set maxDomWeight = 16000 set maxDomWeight = 9 set maxDomWeight = 200 set maxDomWeight = 500 set maxDomWeight = 10 set maxDomWeight = 100 set DDoption = 1 set ordertype = 1 set outIVfile = $matrices/$matrix/levels50.ivf set outIVfile = none set outDSTreeFile = $matrices/$matrix/ms.dstreef set outDSTreeFile = none set outDSTreeFile = $matrices/$matrix/nd.dstreef set seed = 1 set nlayer = 3 set msgFile = $matrix.res.$nlayer.$alpha set msgFile = res.$matrix set msgFile = stdout set firstseed = 1 set lastseed = 11 set lastseed = 1 @ seed = $firstseed while ( $seed <= $lastseed ) echo 'maxDomWeight = ' $maxDomWeight ' seed = ' $seed testRBviaDDsep $msglvl $msgFile $inGraphFile $seed \ $minweight $maxweight $freeze $alpha \ $maxDomWeight $DDoption $nlayer @ seed = $seed + 1 end 4.0 set maxDomWeight = 200000 set maxDomWeight = 8000 set maxDomWeight = 2000 set maxDomWeight = 4000 set maxDomWeight = 500 set maxDomWeight = 250 set maxDomWeight = 8000 set maxDomWeight = 16000 set maxDomWeight = 9 set maxDomWeight = 200 set maxDomWeight = 500 set maxDomWeight = 10 set maxDomWeight = 100 set DDoption = 1 set ordertype = 1 set outIVfile = $matrices/$matrix/levels50.ivf set outIVfile = none set ouGPart/drivers/do_RBviaDDsep2010075500020550007177000000026520654517006400172150ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set matrix = BCSSTK16 set matrix = BCSSTK24 set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig1.graphf set msglvl = 1 set msgFile = res14 set msgFile = stdout set nseed = 21 set nseed = 1 set minweight = 100 set maxweight = 200 set minweight = 200 set maxweight = 400 set minweight = 10 set maxweight = 20 set minweight = 5 set maxweight = 10 set minweight = 50 set maxweight = 100 set alpha = 0.25 set freeze = 4.0 set alpha = 1.0 set alpha = 0.1 set maxDomWeight = 200000 set maxDomWeight = 8000 set maxDomWeight = 2000 set maxDomWeight = 4000 set maxDomWeight = 500 set maxDomWeight = 250 set maxDomWeight = 8000 set maxDomWeight = 16000 set maxDomWeight = 9 set maxDomWeight = 200 set maxDomWeight = 500 set maxDomWeight = 1 set maxDomWeight = 100 set maxDomWeight = 50 set DDoption = 1 set ordertype = 1 set outIVfile = $matrices/$matrix/levels50.ivf set outIVfile = none set outDSTreeFile = $matrices/$matrix/ms.dstreef set outDSTreeFile = $matrices/$matrix/nd.dstreef set outDSTreeFile = none set nlayer = 3 set ntest = 21 set ntest = 1 echo 'maxDomWeight = ' $maxDomWeight testRBviaDDsep2 $msglvl $msgFile $inGraphFile $ntest \ $minweight $maxweight $freeze $alpha \ $maxDomWeight $DDoption $nlayer GPart/drivers/do_SmoothBisector010075500020550007177000000011100654517010500201340ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = BCSSTK16 set inGraphFile = $matrices/$matrix/orig1.graphb set inIVfile = $matrices/$matrix/bkl.ivf set msglvl = 1 set smoothOption = 2 set smoothOption = 1 set smoothOption = 3 set msgFile = stdout set alpha = 1.0 echo ' inGraphFile = ' $inGraphFile foreach smoothOption ( 1 2 3 4 5 ) set outIVfile = $matrices/$matrix/bkl$smoothOption.ivf set outIVfile = none testSmoothBisector $msglvl $msgFile $inGraphFile $inIVfile \ $smoothOption $alpha $outIVfile end GPart/drivers/do_TwoSetViaBKL010075500020550007177000000014420654276053700174310ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set matrix = BCSSTK16 set matrix = BCSSTK24 set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig1.graphf set msglvl = 2 set msgFile = stdout set firstseed = 1 set lastseed = 2 set lastseed = 21 set lastseed = 6 set lastseed = 51 set lastseed = 11 set lastseed = 1 set alpha = 1.0 echo ' matrix = ' $matrix set inIVfile = $matrices/$matrix/fishnet.ivf set outIVfile = $matrices/$matrix/bkl.ivf set outIVfile = none set msgFile = stdout @ seed = $firstseed while ( $seed <= $lastseed ) testTwoSetViaBKL $msglvl $msgFile $inGraphFile \ $inIVfile $seed $alpha $outIVfile @ seed = $seed + 1 end GPart/drivers/do_mkDSTree010075500020550007177000000032030655375213500166630ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set matrix = BCSSTK16 set matrix = BCSSTK24 set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig1.graphf set matrices = ../../../matrices set matrix = GRD15x15x127 set inGraphFile = $matrices/$matrix/orig0.graphb set msglvl = 1 set msgFile = stdout set nseed = 21 set nseed = 1 set minweight = 10 set maxweight = 20 set minweight = 100 set maxweight = 200 set minweight = 200 set maxweight = 400 set minweight = 50 set maxweight = 100 set minweight = 5 set maxweight = 10 set freeze = 4.0 set alpha = 0.25 set alpha = 0.5 set alpha = 0.75 set alpha = 1.0 set alpha = 0.1 set maxDomWeight = 200000 set maxDomWeight = 8000 set maxDomWeight = 2000 set maxDomWeight = 4000 set maxDomWeight = 500 set maxDomWeight = 250 set maxDomWeight = 8000 set maxDomWeight = 16000 set maxDomWeight = 9 set maxDomWeight = 200 set maxDomWeight = 500 set maxDomWeight = 25 set maxDomWeight = 1 set maxDomWeight = 100 set maxDomWeight = 343 set maxDomWeight = 3375 set DDoption = 1 set ordertype = 1 set outIVfile = $matrices/$matrix/levels50.ivf set outIVfile = $matrices/$matrix/levels.ivf set outIVfile = none set outDSTreeFile = $matrices/$matrix/ms.dstreef set outDSTreeFile = $matrices/$matrix/nd.dstreef set outDSTreeFile = none set outDSTreeFile = $matrices/$matrix/nd2.dstreef set seed = 4 set nlayer = 2 mkDSTree $msglvl $msgFile $inGraphFile $seed \ $minweight $maxweight $freeze $alpha \ $maxDomWeight $DDoption $nlayer $outDSTreeFile GPart/drivers/makefile010064400020550007177000000017620665314246000163000ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testDDviaFishnet \ testTwoSetViaBKL \ testSmoothBisector \ testRBviaDDsep \ mkDSTree \ testRBviaDDsep2 drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} mkDSTree : mkDSTree.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testSmoothBisector : testSmoothBisector.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testTwoSetViaBKL : testTwoSetViaBKL.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testDDviaFishnet : testDDviaFishnet.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testRBviaDDsep2 : testRBviaDDsep2.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testRBviaDDsep : testRBviaDDsep.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} GPart/drivers/mkDSTree.c010064400020550007177000000147640654004703600164260ustar00clevecompmath00000400000006/* mkDSTree.c */ #include "../GPart.h" #include "../../DSTree.h" #include "../../MSMD.h" #include "../../BKL.h" #include "../../ETree.h" #include "../../Perm.h" #include "../../IV.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------------------- test the recursive bisection algorithm that uses (1) fishnet to get the domain decomposition (2) domain/segment BKL to get the two set partition (3) Dulmadge-Mendelsohn decomposition to smooth the bisector the output is a DSTree object to hold the domain/separator tree created -- 96mar09, cca --------------------------------------------------------------- */ { char *inGraphFileName, *msgFileName, *outDSTreeFileName ; DSTree *dstree ; DDsepInfo *info ; double alpha, freeze, msCPU, t1, t2 ; FILE *msgFile ; GPart *gpart ; Graph *gf ; int DDoption, maxdomweight, maxweight, minweight, msglvl, nlayer, nvtx, rc, seed ; if ( argc != 13 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile seed" "\n minweight maxweight freeze alpha maxdomwght " "\n DDoption nlayer outDSTreeFileName" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n seed -- random number seed" "\n minweight -- minimum domain weight" "\n maxweight -- maximum domain weight" "\n freeze -- cutoff multiplier for nodes of high degree" "\n alpha -- cost function parameter" "\n maxdomweight -- maximum subgraph weight" "\n DDoption -- option for domain decomposition" "\n 1 --> fishnet for each subgraph" "\n 2 --> fishnet for graph, projection for each subgraph" "\n nlayer -- number of layers for max flow improvement" "\n outDSTreeFileName -- output file, must be *.dstreef" "\n or *.dstreeb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; msgFileName = argv[2] ; if ( strcmp(msgFileName, "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(msgFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], msgFileName) ; return(-1) ; } inGraphFileName = argv[3] ; seed = atoi(argv[4]) ; minweight = atoi(argv[5]) ; maxweight = atoi(argv[6]) ; freeze = atof(argv[7]) ; alpha = atof(argv[8]) ; maxdomweight = atoi(argv[9]) ; DDoption = atoi(argv[10]) ; nlayer = atoi(argv[11]) ; outDSTreeFileName = argv[12] ; fprintf(msgFile, "\n %s : " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n seed -- %d" "\n minweight -- %d" "\n maxweight -- %d" "\n freeze -- %f" "\n alpha -- %f" "\n maxdomweight -- %d" "\n DDoption -- %d" "\n nlayer -- %d" "\n outDSTreeFile -- %s" "\n", argv[0], msglvl, msgFileName, inGraphFileName, seed, minweight, maxweight, freeze, alpha, maxdomweight, DDoption, nlayer, outDSTreeFileName) ; fflush(msgFile) ; /* --------------------------------------- initialize the DDsep information object --------------------------------------- */ info = DDsepInfo_new() ; info->seed = seed ; info->minweight = minweight ; info->maxweight = maxweight ; info->freeze = freeze ; info->alpha = alpha ; info->DDoption = DDoption ; info->maxcompweight = maxdomweight ; info->nlayer = nlayer ; info->msglvl = msglvl ; info->msgFile = msgFile ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; gf = Graph_new() ; Graph_setDefaultFields(gf) ; if ( (rc = Graph_readFromFile(gf, inGraphFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, gf, inGraphFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = gf->nvtx ; if ( msglvl < 4 ) { Graph_writeStats(gf, msgFile) ; fflush(msgFile) ; } else { Graph_writeForHumanEye(gf, msgFile) ; fflush(msgFile) ; } /* ----------------------- create the GPart object ----------------------- */ MARKTIME(t1) ; gpart = GPart_new() ; GPart_init(gpart, gf) ; GPart_setMessageInfo(gpart, msglvl, msgFile) ; MARKTIME(t2) ; /* ------------------------------------------ get the DSTree object that represents the domain/separator partition of the vertices ------------------------------------------ */ MARKTIME(t1) ; dstree = GPart_RBviaDDsep(gpart, info) ; MARKTIME(t2) ; msCPU = t2 - t1 ; fprintf(msgFile, "\n\n CPU %9.5f : find subgraph tree ", msCPU) ; DDsepInfo_writeCpuTimes(info, msgFile) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n # subgraphs = %d", dstree->tree->n) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n DSTree subgraph tree") ; DSTree_writeForHumanEye(dstree, msgFile) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n map from vertices to subgraphs") ; IV_writeForHumanEye(dstree->mapIV, msgFile) ; fflush(msgFile) ; } DDsepInfo_free(info) ; /* -------------------------------------------- renumber the tree via a post-order traversal -------------------------------------------- */ DSTree_renumberViaPostOT(dstree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n renumbered DSTree subgraph tree") ; DSTree_writeForHumanEye(dstree, msgFile) ; fflush(msgFile) ; } /* -------------------------------------------- optionally write the DSTree object to a file -------------------------------------------- */ if ( strcmp(outDSTreeFileName, "none") != 0 ) { DSTree_writeToFile(dstree, outDSTreeFileName) ; } /* ---------------------------- free all the working storage ---------------------------- */ Graph_free(gpart->g) ; GPart_free(gpart) ; DSTree_free(dstree) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ GPart/drivers/testDDviaFishnet.c010064400020550007177000000120010654004532200201320ustar00clevecompmath00000400000006/* testDDviaFishnet.c */ #include "../GPart.h" #include "../../DSTree.h" #include "../../MSMD.h" #include "../../BKL.h" #include "../../ETree.h" #include "../../Perm.h" #include "../../IV.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------------------- read in a Graph and generate a domain decomposition via fishnet created -- 96oct21, cca --------------------------------------------------------------- */ { char *inGraphFileName, *msgFileName, *outIVfileName ; double t1, t2 ; FILE *msgFile ; float freeze ; GPart *gpart ; Graph *graph ; int maxweight, minweight, msglvl, nvtx, rc, seed ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile " "\n freeze minweight maxweight seed outIVfile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n freeze -- freeze factor, try 4" "\n minweight -- minimum domain weight" "\n maxweight -- maximum domain weight" "\n seed -- random number seed" "\n outIVfile -- output file for vertex component ids," "\n must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; msgFileName = argv[2] ; if ( strcmp(msgFileName, "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(msgFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], msgFileName) ; return(-1) ; } inGraphFileName = argv[3] ; freeze = atof(argv[4]) ; minweight = atoi(argv[5]) ; maxweight = atoi(argv[6]) ; seed = atoi(argv[7]) ; outIVfileName = argv[8] ; fprintf(msgFile, "\n %s : " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n freeze -- %f" "\n minweight -- %d" "\n maxweight -- %d" "\n seed -- %d" "\n outIVfile -- %s" "\n", argv[0], msglvl, msgFileName, inGraphFileName, freeze, minweight, maxweight, seed, outIVfileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; graph = Graph_new() ; Graph_setDefaultFields(graph) ; if ( (rc = Graph_readFromFile(graph, inGraphFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = graph->nvtx ; if ( msglvl < 4 ) { Graph_writeStats(graph, msgFile) ; fflush(msgFile) ; } else { Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ----------------------- create the GPart object ----------------------- */ MARKTIME(t1) ; gpart = GPart_new() ; GPart_init(gpart, graph) ; GPart_setMessageInfo(gpart, msglvl, msgFile) ; MARKTIME(t2) ; /* --------------------------------------------- generate the domain decomposition via Fishnet --------------------------------------------- */ MARKTIME(t1) ; GPart_DDviaFishnet(gpart, freeze, minweight, maxweight, seed) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : generate domain decomposition", t2 - t1) ; /* ------------------------------------------- check that we have a valid vertex separator ------------------------------------------- */ if ( 1 != GPart_validVtxSep(gpart) ) { fprintf(msgFile, "\n\n WHOA : multisector is not valid\n\n") ; fflush(msgFile) ; } /* ---------------------------------- get the boundary weights IV object ---------------------------------- */ if ( msglvl > 1 ) { int icomp, ncomp ; int *bnd, *cweights ; IV *bndIV ; bndIV = GPart_bndWeightsIV(gpart) ; bnd = IV_entries(bndIV) ; ncomp = gpart->ncomp ; cweights = IV_entries(&gpart->cweightsIV) ; fprintf(stdout, "\n %% component id, component weight, boundary weight" "\n data = [ ...") ; for ( icomp = 0 ; icomp <= ncomp ; icomp++ ) { fprintf(stdout, "\n %8d %8d %8d", icomp, cweights[icomp], bnd[icomp]) ; } fprintf(stdout, " ] ") ; IV_free(bndIV) ; } /* ------------------------------------------ optionally write out the compids IV object ------------------------------------------ */ if ( strcmp(outIVfileName, "none") != 0 ) { IV_writeToFile(&gpart->compidsIV, outIVfileName) ; } /* ------------------------ free the data structures ------------------------ */ GPart_free(gpart) ; Graph_free(graph) ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ GPart/drivers/testRBviaDDsep.c010064400020550007177000000270310654004613400175600ustar00clevecompmath00000400000006/* testRBviaDDsep.c */ #include "../GPart.h" #include "../../DSTree.h" #include "../../MSMD.h" #include "../../BKL.h" #include "../../ETree.h" #include "../../Perm.h" #include "../../IV.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------ test the recursive bisection algorithm that uses (1) fishnet to get the domain decomposition (2) domain/segment BKL to get the two set partition (3) Dulmadge-Mendelsohn decomposition to smooth the bisector created -- 96mar09, cca ------------------------------------------------------------ */ { char *inGraphFileName, *msgFileName ; DSTree *dstree ; DDsepInfo *info ; double alpha, freeze, msCPU, msops, ndCPU, ndops, phiFrac, rbCPU, t1, t2 ; ETree *etree ; FILE *msgFile ; GPart *gpart ; Graph *gf ; int DDoption, ierr, maxdomweight, maxweight, minweight, msnfind, msnzf, msglvl, ndnfind, ndnzf, nlayer, nvtx, phiWeight, rc, seed ; int *emap ; IV *stagesIV ; MSMD *msmd ; MSMDinfo *msmdinfo ; if ( argc != 12 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile seed" "\n minweight maxweight freeze alpha maxdomwght " "\n DDoption nlayer" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n seed -- random number seed" "\n minweight -- minimum domain weight" "\n maxweight -- maximum domain weight" "\n freeze -- cutoff multiplier for nodes of high degree" "\n alpha -- cost function parameter" "\n maxdomweight -- maximum subgraph weight" "\n DDoption -- option for domain decomposition" "\n 1 --> fishnet for each subgraph" "\n 2 --> fishnet for graph, projection for each subgraph" "\n nlayer -- number of layers for max flow improvement" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; msgFileName = argv[2] ; if ( strcmp(msgFileName, "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(msgFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], msgFileName) ; return(-1) ; } inGraphFileName = argv[3] ; seed = atoi(argv[4]) ; minweight = atoi(argv[5]) ; maxweight = atoi(argv[6]) ; freeze = atof(argv[7]) ; alpha = atof(argv[8]) ; maxdomweight = atoi(argv[9]) ; DDoption = atoi(argv[10]) ; nlayer = atoi(argv[11]) ; fprintf(msgFile, "\n %s : " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n seed -- %d" "\n minweight -- %d" "\n maxweight -- %d" "\n freeze -- %f" "\n alpha -- %f" "\n maxdomweight -- %d" "\n DDoption -- %d" "\n nlayer -- %d" "\n", argv[0], msglvl, msgFileName, inGraphFileName, seed, minweight, maxweight, freeze, alpha, maxdomweight, DDoption, nlayer) ; fflush(msgFile) ; /* --------------------------------------- initialize the DDsep information object --------------------------------------- */ info = DDsepInfo_new() ; info->seed = seed ; info->minweight = minweight ; info->maxweight = maxweight ; info->freeze = freeze ; info->alpha = alpha ; info->DDoption = DDoption ; info->maxcompweight = maxdomweight ; info->nlayer = nlayer ; info->msglvl = msglvl ; info->msgFile = msgFile ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; gf = Graph_new() ; Graph_setDefaultFields(gf) ; if ( (rc = Graph_readFromFile(gf, inGraphFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, gf, inGraphFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = gf->nvtx ; if ( msglvl > 3 ) { Graph_writeForHumanEye(gf, msgFile) ; fflush(msgFile) ; } else if ( msglvl > 1 ) { Graph_writeStats(gf, msgFile) ; fflush(msgFile) ; } /* ----------------------- create the GPart object ----------------------- */ MARKTIME(t1) ; gpart = GPart_new() ; GPart_init(gpart, gf) ; GPart_setMessageInfo(gpart, msglvl, msgFile) ; MARKTIME(t2) ; /* ------------------------------------------ get the DSTree object that represents the domain/separator partition of the vertices ------------------------------------------ */ MARKTIME(t1) ; dstree = GPart_RBviaDDsep(gpart, info) ; MARKTIME(t2) ; rbCPU = t2 - t1 ; fprintf(msgFile, "\n\n CPU %9.5f : find subgraph tree, %d subgraphs ", rbCPU, dstree->tree->n) ; if ( msglvl > 0 ) { DDsepInfo_writeCpuTimes(info, msgFile) ; } /* -------------------------------------------- compute the weight of the separator vertices -------------------------------------------- */ phiWeight = DSTree_separatorWeight(dstree, gf->vwghts) ; phiFrac = ((double) phiWeight) / gf->totvwght ; if ( msglvl > 1 ) { fprintf(msgFile, "\n # subgraphs = %d", dstree->tree->n) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n DSTree subgraph tree") ; DSTree_writeForHumanEye(dstree, msgFile) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n map from vertices to subgraphs") ; IV_writeForHumanEye(dstree->mapIV, msgFile) ; fflush(msgFile) ; } DDsepInfo_free(info) ; /* ------------------------------------ set the stages for nested dissection ------------------------------------ */ stagesIV = DSTree_NDstages(dstree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n stages for ND") ; IV_writeForHumanEye(stagesIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------------- order as incomplete nested dissection ------------------------------------- */ msmdinfo = MSMDinfo_new() ; msmdinfo->compressFlag = 2 ; msmdinfo->prioType = 1 ; msmdinfo->stepType = 1 ; msmdinfo->seed = seed ; msmdinfo->msglvl = msglvl ; msmdinfo->msgFile = msgFile ; MARKTIME(t1) ; msmd = MSMD_new() ; MSMD_order(msmd, gf, IV_entries(stagesIV), msmdinfo) ; MARKTIME(t2) ; ndCPU = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : order the graph via ND", ndCPU) ; fflush(msgFile) ; if ( msglvl > 1 ) { MSMDinfo_print(msmdinfo, msgFile) ; fflush(msgFile) ; } IV_free(stagesIV) ; /* ---------------------- extract the front tree ---------------------- */ MARKTIME(t1) ; emap = IVinit(nvtx, -1) ; etree = MSMD_frontETree(msmd) ; ndnfind = ETree_nFactorIndices(etree) ; ndnzf = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; ndops = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : make the elimination tree", t2 - t1) ; fprintf(msgFile, "\n ND FACTOR : %9d indices, %9d entries, %9.0f operations", ndnfind, ndnzf, ndops) ; /* ETree_writeToFile(etree, "temp.etreef") ; */ if ( msglvl > 3 ) { ETree_writeForHumanEye(etree, msgFile) ; fflush(msgFile) ; } else if ( msglvl > 1 ) { ETree_writeStats(etree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n STATSND %10d %10.0f %8.3f %8.3f %8.3f", ndnzf, ndops, rbCPU, ndCPU, rbCPU + ndCPU) ; MSMD_free(msmd) ; MSMDinfo_free(msmdinfo) ; ETree_free(etree) ; IVfree(emap) ; /* ----------------------------------------- set the stages for two-stage multisection ----------------------------------------- */ stagesIV = DSTree_MS2stages(dstree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n stages for MS2") ; IV_writeForHumanEye(stagesIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------- order as two-stage multisection ------------------------------- */ msmdinfo = MSMDinfo_new() ; msmdinfo->compressFlag = 2 ; msmdinfo->prioType = 3 ; msmdinfo->stepType = 1 ; msmdinfo->seed = seed ; msmdinfo->msglvl = msglvl ; msmdinfo->msgFile = msgFile ; MARKTIME(t1) ; msmd = MSMD_new() ; MSMD_order(msmd, gf, IV_entries(stagesIV), msmdinfo) ; MARKTIME(t2) ; msCPU = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : order the graph via MS", msCPU) ; fflush(msgFile) ; if ( msglvl > 1 ) { MSMDinfo_print(msmdinfo, msgFile) ; fflush(msgFile) ; } IV_free(stagesIV) ; /* ---------------------- extract the front tree ---------------------- */ MARKTIME(t1) ; emap = IVinit(nvtx, -1) ; etree = MSMD_frontETree(msmd) ; msnfind = ETree_nFactorIndices(etree) ; msnzf = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; msops = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : make the elimination tree", t2 - t1) ; fprintf(msgFile, "\n MS FACTOR : %9d indices, %9d entries, %9.0f operations", msnfind, msnzf, msops) ; if ( msglvl > 3 ) { ETree_writeForHumanEye(etree, msgFile) ; fflush(msgFile) ; } else if ( msglvl > 1 ) { ETree_writeStats(etree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n STATSMS2 %10d %10.0f %8.3f %8.3f %8.3f", msnzf, msops, rbCPU, msCPU, rbCPU + msCPU) ; MSMD_free(msmd) ; MSMDinfo_free(msmdinfo) ; ETree_free(etree) ; IVfree(emap) ; /* ------------------------ print out the statistics ------------------------ */ fprintf(msgFile, "\n ALL %6.3f %8.3f %8d %10.0f %8.3f %8d %10.0f %8.3f", phiFrac, rbCPU, ndnzf, ndops, ndCPU, msnzf, msops, msCPU) ; /* ----------------------- order as minimum degree ----------------------- */ /* msmdinfo = MSMDinfo_new() ; msmdinfo->compressFlag = 2 ; msmdinfo->prioType = 3 ; msmdinfo->stepType = 1 ; msmdinfo->seed = seed ; msmdinfo->msglvl = msglvl ; msmdinfo->msgFile = msgFile ; MARKTIME(t1) ; msmd = MSMD_new() ; MSMD_order(msmd, gf, NULL, msmdinfo) ; MARKTIME(t2) ; orderCPU = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : order the graph", orderCPU) ; fflush(msgFile) ; MSMDinfo_print(msmdinfo, msgFile) ; fflush(msgFile) ; */ /* ---------------------- extract the front tree ---------------------- */ /* MARKTIME(t1) ; emap = IVinit(nvtx, -1) ; etree = MSMD_frontETree(msmd) ; nfind = ETree_nFactorIndices(etree) ; nzf = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; ops = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : make the elimination tree", t2 - t1) ; fprintf(msgFile, "\n FACTOR : %9d indices, %9d entries, %9.0f operations", nfind, nzf, ops) ; if ( msglvl < 3 ) { ETree_writeStats(etree, msgFile) ; fflush(msgFile) ; } else { ETree_writeForHumanEye(etree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n STATSMD %10d %10.0f %8.3f %8.3f %8.3f", nzf, ops, 0.0, orderCPU, 0.0 + orderCPU) ; MSMD_free(msmd) ; MSMDinfo_free(msmdinfo) ; ETree_free(etree) ; IVfree(emap) ; */ /* ---------------------------- free all the working storage ---------------------------- */ Graph_free(gpart->g) ; GPart_free(gpart) ; DSTree_free(dstree) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ intf(msgFile, "\n\n CPU %9.5f : find subgraph tree, %d subgraphs ", rbCPU, dstree->tree->n) ; if ( msglvl > 0 ) { DDsepInfo_writeCpuTimes(info, msgFile) ; } /* -------------------------------------------- compute the weight of the separator vertices -------------------------------------------- */ phiWeight = DSTree_separatorWeight(dstree, gf->vwghts) ; phiFrac = ((double) phiWeight) / gf->totvwght ; if ( msglvl > 1 ) { fprintf(msgFile, "\n # subgraphs = %d",GPart/drivers/testRBviaDDsep2.c010064400020550007177000000313060654004514700176450ustar00clevecompmath00000400000006/* testRBviaDDsep2.c */ #include "../GPart.h" #include "../../DSTree.h" #include "../../MSMD.h" #include "../../BKL.h" #include "../../ETree.h" #include "../../Perm.h" #include "../../IV.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------ test the recursive bisection algorithm that uses (1) fishnet to get the domain decomposition (2) domain/segment BKL to get the two set partition (3) Dulmadge-Mendelsohn decomposition to smooth the bisector created -- 96mar09, cca ------------------------------------------------------------ */ { char *inGraphFileName, *msgFileName ; DSTree *dstree ; DDsepInfo *info ; double alpha, freeze, msCPU, msops, ndCPU, ndops, phiFrac, rbCPU, t1, t2 ; double *fracvec, *mscpuvec, *msopsvec, *ndcpuvec, *ndopsvec, *rbcpuvec ; ETree *etree ; FILE *msgFile ; GPart *gpart ; Graph *gf ; int DDoption, maxdomweight, maxweight, minweight, msnfind, msnzf, msglvl, ndnfind, ndnzf, nlayer, ntest, nvtx, phiWeight, rc, seed ; int *emap, *msnzfvec, *ndnzfvec ; IV *stagesIV ; MSMD *msmd ; MSMDinfo *msmdinfo ; if ( argc != 12 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile ntest" "\n minweight maxweight freeze alpha maxdomwght " "\n DDoption nlayer" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n ntest -- number of tests to make" "\n minweight -- minimum domain weight" "\n maxweight -- maximum domain weight" "\n freeze -- cutoff multiplier for nodes of high degree" "\n alpha -- cost function parameter" "\n maxdomweight -- maximum subgraph weight" "\n DDoption -- option for domain decomposition" "\n 1 --> fishnet for each subgraph" "\n 2 --> fishnet for graph, projection for each subgraph" "\n nlayer -- number of layers for max flow improvement" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; msgFileName = argv[2] ; if ( strcmp(msgFileName, "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(msgFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], msgFileName) ; return(-1) ; } inGraphFileName = argv[3] ; ntest = atoi(argv[4]) ; if ( ntest % 2 == 0 ) { ntest++ ; } minweight = atoi(argv[5]) ; maxweight = atoi(argv[6]) ; freeze = atof(argv[7]) ; alpha = atof(argv[8]) ; maxdomweight = atoi(argv[9]) ; DDoption = atoi(argv[10]) ; nlayer = atoi(argv[11]) ; fprintf(msgFile, "\n %s : " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n ntest -- %d" "\n minweight -- %d" "\n maxweight -- %d" "\n freeze -- %f" "\n alpha -- %f" "\n maxdomweight -- %d" "\n DDoption -- %d" "\n nlayer -- %d" "\n", argv[0], msglvl, msgFileName, inGraphFileName, ntest, minweight, maxweight, freeze, alpha, maxdomweight, DDoption, nlayer) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; gf = Graph_new() ; Graph_setDefaultFields(gf) ; if ( (rc = Graph_readFromFile(gf, inGraphFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, gf, inGraphFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = gf->nvtx ; if ( msglvl > 3 ) { Graph_writeForHumanEye(gf, msgFile) ; fflush(msgFile) ; } else if ( msglvl > 1 ) { Graph_writeStats(gf, msgFile) ; fflush(msgFile) ; } /* ------------------------------- allocate the statistics vectors ------------------------------- */ fracvec = DVinit(ntest, 0.0) ; ndnzfvec = IVinit(ntest, 0) ; msnzfvec = IVinit(ntest, 0) ; ndopsvec = DVinit(ntest, 0.0) ; msopsvec = DVinit(ntest, 0.0) ; rbcpuvec = DVinit(ntest, 0.0) ; ndcpuvec = DVinit(ntest, 0.0) ; mscpuvec = DVinit(ntest, 0.0) ; /* ------------------- loop over the tests ------------------- */ for ( seed = 1 ; seed <= ntest ; seed++ ) { /* --------------------------------------- initialize the DDsep information object --------------------------------------- */ info = DDsepInfo_new() ; info->seed = seed ; info->minweight = minweight ; info->maxweight = maxweight ; info->freeze = freeze ; info->alpha = alpha ; info->DDoption = DDoption ; info->maxcompweight = maxdomweight ; info->nlayer = nlayer ; info->msglvl = msglvl ; info->msgFile = msgFile ; /* ----------------------- create the GPart object ----------------------- */ MARKTIME(t1) ; gpart = GPart_new() ; GPart_init(gpart, gf) ; GPart_setMessageInfo(gpart, msglvl, msgFile) ; MARKTIME(t2) ; /* ------------------------------------------ get the DSTree object that represents the domain/separator partition of the vertices ------------------------------------------ */ MARKTIME(t1) ; dstree = GPart_RBviaDDsep(gpart, info) ; MARKTIME(t2) ; rbCPU = t2 - t1 ; phiWeight = DSTree_separatorWeight(dstree, gf->vwghts) ; fprintf(msgFile, "\n\n CPU %9.5f : find subgraph tree, %d subgraphs, |Phi| = %d ", rbCPU, dstree->tree->n, phiWeight) ; if ( msglvl > 0 ) { DDsepInfo_writeCpuTimes(info, msgFile) ; } /* -------------------------------------------- compute the weight of the separator vertices -------------------------------------------- */ if ( gf->totvwght == 0 ) { if ( gf->vwghts == NULL ) { gf->totvwght = nvtx ; } else { gf->totvwght = IVsum(nvtx, gf->vwghts) ; } } phiFrac = ((double) phiWeight) / gf->totvwght ; if ( msglvl > 1 ) { fprintf(msgFile, "\n # subgraphs = %d", dstree->tree->n) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n DSTree subgraph tree") ; DSTree_writeForHumanEye(dstree, msgFile) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n map from vertices to subgraphs") ; IV_writeForHumanEye(dstree->mapIV, msgFile) ; fflush(msgFile) ; } DDsepInfo_free(info) ; /* ----------------------------------------- set the stages for two-stage multisection ----------------------------------------- */ stagesIV = DSTree_MS2stages(dstree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n stages for MS2") ; IV_writeForHumanEye(stagesIV, msgFile) ; fflush(msgFile) ; } /* ----------------- read in the graph ----------------- Graph_readFromFile(gf, inGraphFileName) ; */ /* ------------------------------- order as two-stage multisection ------------------------------- */ msmdinfo = MSMDinfo_new() ; msmdinfo->compressFlag = 2 ; msmdinfo->prioType = 1 ; msmdinfo->stepType = 1 ; msmdinfo->seed = seed ; msmdinfo->msglvl = msglvl ; msmdinfo->msgFile = msgFile ; MARKTIME(t1) ; msmd = MSMD_new() ; MSMD_order(msmd, gf, IV_entries(stagesIV), msmdinfo) ; MARKTIME(t2) ; msCPU = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : order the graph via MS", msCPU) ; fflush(msgFile) ; if ( msglvl > 1 ) { MSMDinfo_print(msmdinfo, msgFile) ; fflush(msgFile) ; } IV_free(stagesIV) ; /* ---------------------- extract the front tree ---------------------- */ MARKTIME(t1) ; emap = IVinit(nvtx, -1) ; etree = MSMD_frontETree(msmd) ; msnfind = ETree_nFactorIndices(etree) ; msnzf = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; msops = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : make the elimination tree", t2 - t1) ; fprintf(msgFile, "\n MS FACTOR : %9d indices, %9d entries, %9.0f operations", msnfind, msnzf, msops) ; if ( msglvl > 3 ) { ETree_writeForHumanEye(etree, msgFile) ; fflush(msgFile) ; } else if ( msglvl > 1 ) { ETree_writeStats(etree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n STATSMS2 %10d %10.0f %8.3f %8.3f %8.3f", msnzf, msops, rbCPU, msCPU, rbCPU + msCPU) ; MSMD_free(msmd) ; MSMDinfo_free(msmdinfo) ; ETree_free(etree) ; IVfree(emap) ; /* ------------------------------------ set the stages for nested dissection ------------------------------------ */ stagesIV = DSTree_NDstages(dstree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n stages for ND") ; IV_writeForHumanEye(stagesIV, msgFile) ; fflush(msgFile) ; } /* ----------------- read in the graph ----------------- Graph_readFromFile(gf, inGraphFileName) ; */ /* ------------------------------------- order as incomplete nested dissection ------------------------------------- */ msmdinfo = MSMDinfo_new() ; msmdinfo->compressFlag = 2 ; msmdinfo->prioType = 1 ; msmdinfo->stepType = 1 ; msmdinfo->seed = seed ; msmdinfo->msglvl = msglvl ; msmdinfo->msgFile = msgFile ; MARKTIME(t1) ; msmd = MSMD_new() ; MSMD_order(msmd, gf, IV_entries(stagesIV), msmdinfo) ; MARKTIME(t2) ; ndCPU = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : order the graph via ND", ndCPU) ; fflush(msgFile) ; if ( msglvl > 1 ) { MSMDinfo_print(msmdinfo, msgFile) ; fflush(msgFile) ; } IV_free(stagesIV) ; /* ---------------------- extract the front tree ---------------------- */ MARKTIME(t1) ; emap = IVinit(nvtx, -1) ; etree = MSMD_frontETree(msmd) ; ndnfind = ETree_nFactorIndices(etree) ; ndnzf = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; ndops = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : make the elimination tree", t2 - t1) ; fprintf(msgFile, "\n ND FACTOR : %9d indices, %9d entries, %9.0f operations", ndnfind, ndnzf, ndops) ; if ( msglvl > 3 ) { ETree_writeForHumanEye(etree, msgFile) ; fflush(msgFile) ; } else if ( msglvl > 1 ) { ETree_writeStats(etree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n STATSND %10d %10.0f %8.3f %8.3f %8.3f", ndnzf, ndops, rbCPU, ndCPU, rbCPU + ndCPU) ; MSMD_free(msmd) ; MSMDinfo_free(msmdinfo) ; ETree_free(etree) ; IVfree(emap) ; /* ------------------------ print out the statistics ------------------------ */ fprintf(msgFile, "\n ALL %6.3f %8.3f %8d %10.0f %8.3f %8d %10.0f %8.3f", phiFrac, rbCPU, ndnzf, ndops, ndCPU, msnzf, msops, msCPU) ; /* ---------------------------- free all the working storage ---------------------------- */ GPart_free(gpart) ; DSTree_free(dstree) ; /* -------------------- store the statistics -------------------- */ fracvec[seed-1] = phiFrac ; rbcpuvec[seed-1] = rbCPU ; ndcpuvec[seed-1] = ndCPU ; mscpuvec[seed-1] = msCPU ; ndnzfvec[seed-1] = ndnzf ; msnzfvec[seed-1] = msnzf ; ndopsvec[seed-1] = ndops ; msopsvec[seed-1] = msops ; } /* --------------------------- print out the median values --------------------------- */ DVqsortUp(ntest, fracvec) ; DVqsortUp(ntest, rbcpuvec) ; DVqsortUp(ntest, ndcpuvec) ; DVqsortUp(ntest, mscpuvec) ; IVqsortUp(ntest, ndnzfvec) ; IVqsortUp(ntest, msnzfvec) ; DVqsortUp(ntest, ndopsvec) ; DVqsortUp(ntest, msopsvec) ; fprintf(msgFile, "\n MEDIAN %6.3f %8.3f %8d %10.0f %8.3f %8d %10.0f %8.3f", fracvec[ntest/2], rbcpuvec[ntest/2], ndnzfvec[ntest/2], ndopsvec[ntest/2], ndcpuvec[ntest/2], msnzfvec[ntest/2], msopsvec[ntest/2], mscpuvec[ntest/2]) ; /* ---------------------------- free all the working storage ---------------------------- */ Graph_free(gf) ; DVfree(fracvec) ; IVfree(ndnzfvec) ; IVfree(msnzfvec) ; DVfree(ndopsvec) ; DVfree(msopsvec) ; DVfree(rbcpuvec) ; DVfree(ndcpuvec) ; DVfree(mscpuvec) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ GPart/drivers/testSmoothBisector.c010064400020550007177000000161050654004660200206010ustar00clevecompmath00000400000006/* testSmooth4.c */ #include "../GPart.h" #include "../../DSTree.h" #include "../../MSMD.h" #include "../../BKL.h" #include "../../ETree.h" #include "../../Perm.h" #include "../../IV.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------ (1) read in a Graph, (2) read in a 2-set partition (3) smooth the separator (4) optionally write out new partition created -- 96oct21, cca ------------------------------------------ */ { char *inGraphFileName, *inIVfileName, *msgFileName, *outIVfileName ; double alpha, cost, t1, t2 ; FILE *msgFile ; GPart *gpart ; Graph *graph ; int ierr, msglvl, option, nvtx, rc ; IV *tagsIV ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile inIVfile " "\n option alpha outIVfile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n inIVFile -- input file, must be *.ivf or *.ivb" "\n option -- smoothing option" "\n 1 --> bipartite 2-layers" "\n 2 --> non-bipartite 2-layers" "\n k > 2 --> k/2 layers on each side" "\n alpha -- cost function parameter" "\n outIVFile -- output file, must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; msgFileName = argv[2] ; if ( strcmp(msgFileName, "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(msgFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], msgFileName) ; return(-1) ; } inGraphFileName = argv[3] ; inIVfileName = argv[4] ; option = atoi(argv[5]) ; alpha = atof(argv[6]) ; outIVfileName = argv[7] ; fprintf(msgFile, "\n %s : " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n inIVfile -- %s" "\n option -- %d" "\n alpha -- %f" "\n outIVfile -- %s" "\n", argv[0], msglvl, msgFileName, inGraphFileName, inIVfileName, option, alpha, outIVfileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; graph = Graph_new() ; Graph_setDefaultFields(graph) ; if ( (rc = Graph_readFromFile(graph, inGraphFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = graph->nvtx ; if ( msglvl < 4 ) { Graph_writeStats(graph, msgFile) ; fflush(msgFile) ; } else { Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ------------------------ read in the IV object ------------------------ */ if ( strcmp(inIVfileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; tagsIV = IV_new() ; IV_setDefaultFields(tagsIV) ; if ( (rc = IV_readFromFile(tagsIV, inIVfileName)) != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, tagsIV, inIVfileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in tagsIV from file %s", t2 - t1, inIVfileName) ; nvtx = IV_size(tagsIV) ; if ( msglvl < 4 ) { IV_writeStats(tagsIV, msgFile) ; fflush(msgFile) ; } else { IV_writeForHumanEye(tagsIV, msgFile) ; fflush(msgFile) ; } /* ----------------------- create the GPart object ----------------------- */ MARKTIME(t1) ; gpart = GPart_new() ; GPart_init(gpart, graph) ; GPart_setMessageInfo(gpart, msglvl, msgFile) ; IV_copy(&gpart->compidsIV, tagsIV) ; GPart_setCweights(gpart) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : GPart initialized", t2 - t1) ; fprintf(msgFile, "\n cweights : ") ; IVfp80(msgFile, 1 + gpart->ncomp, IV_entries(&gpart->cweightsIV), 30, &ierr) ; fflush(msgFile) ; if ( msglvl > 0 ) { int wB, wS, wW ; int *cweights = IV_entries(&gpart->cweightsIV) ; fprintf(msgFile, "\n initial component weights :") ; IVfp80(msgFile, 1+gpart->ncomp, cweights, 20, &ierr) ; wS = cweights[0] ; wB = cweights[1] ; wW = cweights[2] ; if ( wB < wW ) { wB = wW ; wW = cweights[1] ; } cost = wS*(1. + (alpha*wB)/wW) ; fprintf(msgFile, "\n initial |S| = %d , balance = %6.3f , cpu = %8.3f , cost = %8.1f\n", wS, ((double) wB)/wW, t2 - t1, cost) ; fflush(msgFile) ; } /* ------------------------------------------- check that we have a valid vertex separator ------------------------------------------- */ if ( 1 != GPart_validVtxSep(gpart) ) { fprintf(msgFile, "\n\n WHOA : separator is not valid" "\n\n WHOA : separator is not valid\n\n") ; fflush(msgFile) ; } /* -------------------- smooth the separator -------------------- */ MARKTIME(t1) ; if ( option <= 2 ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n calling GPart_smoothBy2layers with option %d", option) ; fflush(stdout) ; } GPart_smoothBy2layers(gpart, option, alpha) ; } else { if ( msglvl > 1 ) { fprintf(msgFile, "\n calling GPart_smoothBisector with option %d", option/2) ; fflush(stdout) ; } GPart_smoothBisector(gpart, option/2, alpha) ; } MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.5f : improve bisector", t2 - t1) ; if ( msglvl > 0 ) { int wB, wS, wW ; int *cweights = IV_entries(&gpart->cweightsIV) ; fprintf(msgFile, "\n final component weights :") ; IVfp80(msgFile, 1+gpart->ncomp, cweights, 20, &ierr) ; wS = cweights[0] ; wB = cweights[1] ; wW = cweights[2] ; if ( wB < wW ) { wB = wW ; wW = cweights[1] ; } cost = wS*(1. + (alpha*wB)/wW) ; fprintf(msgFile, "\n final |S| = %d , balance = %6.3f , cpu = %8.3f , cost = %8.1f\n", wS, ((double) wB)/wW, t2 - t1, cost) ; fflush(msgFile) ; } /* ------------------------------------------- check that we have a valid vertex separator ------------------------------------------- */ if ( 1 != GPart_validVtxSep(gpart) ) { fprintf(msgFile, "\n\n WHOA : separator is not valid" "\n\n WHOA : separator is not valid\n\n") ; fflush(msgFile) ; } /* ------------------------------------------ optionally write the tags file out to disk ------------------------------------------ */ if ( strcmp(outIVfileName, "none") != 0 ) { IV_writeToFile(&gpart->compidsIV, outIVfileName) ; } /* ------------------------ free the data structures ------------------------ */ GPart_free(gpart) ; Graph_free(graph) ; IV_free(tagsIV) ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ GPart/drivers/testTwoSetViaBKL.c010064400020550007177000000123010654004642100200440ustar00clevecompmath00000400000006/* testTwoSetViaBKL.c */ #include "../GPart.h" #include "../../DSTree.h" #include "../../MSMD.h" #include "../../BKL.h" #include "../../ETree.h" #include "../../Perm.h" #include "../../IV.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------- read in a Graph, read in a components IV object find the two set partition via BKL created -- 96oct21, cca ----------------------------------------------- */ { char *inGraphFileName, *inIVfileName, *msgFileName, *outIVfileName ; double alpha, t1, t2 ; double cpus[3] ; FILE *msgFile ; GPart *gpart ; Graph *graph ; int ierr, msglvl, nvtx, rc, seed ; IV *compidsIV ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile inIVfileName " "\n seed alpha outIVfileName" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n inIVfile -- input file, must be *.ivf or *.ivb" "\n seed -- random number seed" "\n alpha -- partition cost parameter" "\n outIVfile -- output file, must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; msgFileName = argv[2] ; if ( strcmp(msgFileName, "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(msgFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], msgFileName) ; return(-1) ; } inGraphFileName = argv[3] ; inIVfileName = argv[4] ; seed = atoi(argv[5]) ; alpha = atof(argv[6]) ; outIVfileName = argv[7] ; fprintf(msgFile, "\n %s : " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n inIVfile -- %s" "\n seed -- %d" "\n alpha -- %f" "\n outIVfile -- %s" "\n", argv[0], msglvl, msgFileName, inGraphFileName, inIVfileName, seed, alpha, outIVfileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; graph = Graph_new() ; Graph_setDefaultFields(graph) ; if ( (rc = Graph_readFromFile(graph, inGraphFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = graph->nvtx ; if ( msglvl < 4 ) { Graph_writeStats(graph, msgFile) ; fflush(msgFile) ; } else { Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* --------------------- read in the IV object --------------------- */ if ( strcmp(inIVfileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; compidsIV = IV_new() ; IV_setDefaultFields(compidsIV) ; if ( (rc = IV_readFromFile(compidsIV, inIVfileName)) != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, compidsIV, inIVfileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in compidsIV from file %s", t2 - t1, inIVfileName) ; if ( msglvl < 4 ) { IV_writeStats(compidsIV, msgFile) ; fflush(msgFile) ; } else { IV_writeForHumanEye(compidsIV, msgFile) ; fflush(msgFile) ; } /* ----------------------- create the GPart object ----------------------- */ MARKTIME(t1) ; gpart = GPart_new() ; GPart_init(gpart, graph) ; IV_copy(&gpart->compidsIV, compidsIV) ; GPart_setMessageInfo(gpart, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : GPart initialized", t2 - t1) ; /* -------------------------------- find an initial bisector via BKL -------------------------------- */ MARKTIME(t1) ; GPart_TwoSetViaBKL(gpart, alpha, seed, cpus) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : generate bisector", t2 - t1) ; fprintf(msgFile, "\n initial component weights :") ; IVfp80(msgFile, 1+gpart->ncomp, IV_entries(&gpart->cweightsIV), 30, &ierr) ; fflush(msgFile) ; /* ------------------------------------------- check that we have a valid vertex separator ------------------------------------------- */ if ( 1 != GPart_validVtxSep(gpart) ) { fprintf(msgFile, "\n\n WHOA : separator is not valid" "\n\n WHOA : separator is not valid\n\n") ; fflush(msgFile) ; } /* ------------------------------------------------ optionally write the compids IV object to a file ------------------------------------------------ */ if ( strcmp(outIVfileName, "none") != 0 ) { IV_writeToFile(&gpart->compidsIV, outIVfileName) ; } /* ------------------------ free the data structures ------------------------ */ GPart_free(gpart) ; Graph_free(graph) ; IV_free(compidsIV) ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ GPart/doc/004275500020550007177000000000000654276740000136725ustar00clevecompmath00000400000006GPart/doc/dataStructure.tex010064400020550007177000000113150653410612100172260ustar00clevecompmath00000400000006\par \section{Data Structures} \label{section:GPart:dataStructure} \par The {\tt GPart} structure has a pointer to a {\tt Graph} object and other fields that contain information about the partition of the graph. \par The following fields are always active. \begin{itemize} \item {\tt Graph *graph} : pointer to the {\tt Graph} object \item {\tt int nvtx} : number of internal vertices of the graph \item {\tt int nvbnd} : number of boundary vertices of the graph \item {\tt int ncomp} : number of components in the graph \item {\tt IV compidsIV} : an {\tt IV} object that holds the component ids of the internal vertices --- {\tt compids[v] == 0} means that the vertex is in the separator or multisector. \item {\tt IV cweightsIV} : an {\tt IV} object that holds the component weights --- {\tt cweights[icomp]} stores the weight of component {\tt icomp}, {\tt cweights[0]} is the separator or multisector weight. \item {\tt int msglvl} : message level parameter. When {\tt msglvl = 0}, no output is produced. When {\tt msglvl = 1}, only ``scalar'' output is provided, no vectors are printed or any print statements in a loop. When {\tt msglvl > 1}, beware, there can be a fair amount of output. \item {\tt FILE *msgFile} : message file pointer, default value is {\tt stdout}. \end{itemize} The following fields are used when building a domain/separator tree during the recursive dissection process. \begin{itemize} \item {\tt int id} : id of the partition object \item {\tt GPart *par} : pointer to a parent {\tt GPart} object \item {\tt GPart *fch} : pointer to a first child {\tt GPart} object \item {\tt GPart *sib} : pointer to a sibling {\tt GPart} object \item {\tt IV vtxMapIV} : an {\tt IV} object of size {\tt nvtx + nvbnd}, contains a map from the vertices of the graph to either the vertices of its parent or to the vertices of the root graph \end{itemize} \par The {\tt DDsepInfo} {\it helper}-object is used during the {\tt DDSEP} recursive bisection process. It contains input parameters for the different stages of the {\tt DDSEP} algorithm, and collects statistics about the CPU time spent in each stage. \par \begin{itemize} \item These parameters are used to generate the domain decomposition. \begin{itemize} \item {\tt int minweight}: minimum target weight for a domain \item {\tt int maxweight}: maximum target weight for a domain \item {\tt double freeze}: multiplier used to freeze vertices of high degree into the multisector. If the degree of {\tt v} is more than {\tt freeze} times the median degree, {\tt v} is placed into the multisector. \item {\tt int seed}: random number seed \item {\tt int DDoption}: If {\tt 1}, a new domain decomposition is constructed for each subgraph. If {\tt 2}, a domain decomposition is constructed for the original graph, and its projection onto a subgraph is used to define the domain decomposition on the subgraph. \end{itemize} \item These parameters are used to find the initial and final bisectors. \begin{itemize} \item {\tt double alpha}: cost function parameter \item {\tt int seed}: random number seed \item {\tt int nlayer}: number of layers to use to form a wide separator $Y$ from a 2-set partition $[S,B,W]$. If {\tt nlayer = 1} or {\tt 2}, $Y = S \cup (Adj(S) \cap B)$ or $Y = S \cup (Adj(S) \cap W)$. When {\tt nlayer = 1} the network is forced to be bipartite. If {\tt nlayer = 3}, $Y_3 = S \cup Adj(S)$, and for {\tt nlayer = 2k+1}, $Y_{2k+1} = Y_{2k-1} \cup Adj(Y_{2k-1})$. \end{itemize} \item These parameters accumulate CPU times. \begin{itemize} \item {\tt double cpuDD}: time to construct the domain decompositions \item {\tt double cpuMap}: time to construct the maps from vertices to domains and segments \item {\tt double cpuBPG}: time to construct the domain/segment bipartite graphs \item {\tt double cpuBKL}: time to find the initial separators via the Block Kernighan-Lin algorithm on the domain/segment graphs \item {\tt double cpuSmooth}: time to smooth the bisectors \item {\tt double cpuSplit}: time to split the subgraphs \item {\tt double cpuTotal}: total cpu time \end{itemize} \item Miscellaneous parameters. \begin{itemize} \item {\tt int maxcompweight}: an attempt is made to split any subgraph that has weight greater than {\tt maxcompweight}. \item {\tt int ntreeobj}: number of tree objects in the tree, used to set {\tt gpart->id} and used to initialize the {\tt DSTree} object. \item {\tt int msglvl} : message level \item {\tt FILE *msgFile} : message file pointer \end{itemize} \end{itemize} GPart/doc/intro.tex010064400020550007177000000057410665023007400155410ustar00clevecompmath00000400000006\chapter{{\tt GPart}: Graph Partitioning Object} \label{chapter:GPart:intro} \par The {\tt GPart} object is used to create a partition of a graph. We use an explicit vertex separator to split a graph (or a subgraph) into the separator and two or more connected components. This process proceeds recursively until the subgraphs are too small to split (given by some user-supplied parameter). \par At present, there is one path for splitting a graph (or a subgraph). \begin{itemize} \item Find a {\it domain decomposition} of the graph. The graph's vertices $V$ are partitioned into {\it domains}, $\Omega_1, \ldots, \Omega_m$, each a connected component, and the interface vertices $\Phi$. The boundary of a domain $\Omega_i$ (those vertices not in the domain but adjacent to a vertex in the domain), written $\mbox{adj}(\Omega_i)$, are a subset of $\Phi$, the interface vertices. We use the term {\it multisector} for $\Phi$, for it generalizes the notion of bisector. \par We currently find the domain decomposition by growing domains from random seed vertices. Upper and lower bounds are placed on the weights of the domains. \item Given a domain decomposition of the graph $\langle \Phi, \Omega_1, \ldots, \Omega_m \rangle$, we find a {\it 2-set partition} $[S, B, W]$ of the vertices, where $S \subseteq \Phi$, $\mbox{Adj}(B) \subseteq S$ and $\mbox{Adj}(W) \subseteq S$. Note, it may be the case that $B$ and/or $W$ are not connected components. \par We currently find a 2-set partition by forming a {\it domain-segment} bipartite graph where the segments partition the interface nodes $\Phi$. We use a block Kernighan-Lin method to find an edge separator of this domain-segment graph. Since the ``edges'' are segments, an edge separator of the domain-segment graph is truly a vertex separator of the original graph. \item Given a 2-set decomposition $[S,B,W]$ of the graph, we improve the partition by {\it smoothing} $S$. The goal is to decrease the size of $S$, or improve the balance of the two sets (minimize $\left| |B| - |W| \right |$, or both. Our present approach is to generate a {\it wide separator} $Y$ where $S \subseteq Y$ and try to find a separator $\widehat S \subseteq Y$ that induces a better partition $[{\widehat S}, {\widehat B}, {\widehat W}]$. \par To do this, we form a network and solve a max flow problem. The nodes in $B \setminus Y$ are condensed into the {\it source} while the nodes in $W \setminus Y$ are condensed into the {\it sink}. The rest of the network is formed using the structure of the subgraph induced by $Y$. Given a {\it min-cut} of the network we can identify a separator ${\widehat S} \subseteq Y$ that has minimal weight. We examine two (possibly) different min-cuts and evaluate the partitions induced via their minimal weight separators, and accept a better partition if present. \end{itemize} This process we call {\tt DDSEP}, which is short for {\it {\tt D}omain {\tt D}ecomposition {\tt SEP}arator}, explained in more detail in \cite{ash97-DDSEP} and \cite{ash98-maxflow}. \par GPart/doc/main.tex010064400020550007177000000011000665065623000153210ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt GPart} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt GPart} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} GPart/doc/main.ind010064400020550007177000000020140654003365500152760ustar00clevecompmath00000400000006\begin{theindex} \item {\tt DDsepInfo\_clearData()}, 9 \item {\tt DDsepInfo\_free()}, 10 \item {\tt DDsepInfo\_new()}, 9 \item {\tt DDsepInfo\_setDefaultFields()}, 9 \indexspace \item {\tt GPart\_bndWeightsIV()}, 6 \item {\tt GPart\_clearData()}, 4 \item {\tt GPart\_DDviaFishnet()}, 6 \item {\tt GPart\_DDviaProjection()}, 6 \item {\tt GPart\_domSegMap()}, 7 \item {\tt GPart\_free()}, 4 \item {\tt GPart\_identifyWideSep()}, 7 \item {\tt GPart\_init()}, 4 \item {\tt GPart\_makeYCmap()}, 7 \item {\tt GPart\_new()}, 4 \item {\tt GPart\_RBviaDDsep()}, 9 \item {\tt GPart\_setCweights()}, 5 \item {\tt GPart\_setDefaultFields()}, 4 \item {\tt GPart\_setMessageInfo()}, 4 \item {\tt GPart\_sizeOf()}, 5 \item {\tt GPart\_smoothBisector()}, 8 \item {\tt GPart\_smoothBy2layers()}, 8 \item {\tt GPart\_smoothYSep()}, 8 \item {\tt GPart\_split()}, 5 \item {\tt GPart\_TwoSetViaBKL()}, 6 \item {\tt GPart\_validVtxSep()}, 5 \item {\tt GPart\_vtxIsAdjToOneDomain()}, 5 \end{theindex} GPart/doc/main.log010064400020550007177000000075240654003366700153230ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 11 JUN 1998 13:01 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. LaTeX Warning: Citation `ash95-DDSEP' on page 1 undefined on input line 67. LaTeX Warning: Citation `ash96-maxflow' on page 1 undefined on input line 68. [1 ]) (dataStructure.tex Overfull \hbox (10.03406pt too wide) in paragraph at lines 20--24 [] []\elvtt IV compidsIV \elvrm : an \elvtt IV \elvrm ob-ject that holds the co m-po-nent ids of the in-ter-nal ver-tices --- \elvtt compids[v] \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(4.86667+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvtt I .etc. [2]) (proto.tex [3] [4] [5] LaTeX Warning: Citation `ash95-DDSEP' on page 6 undefined on input line 247. [6] [7] [8] [9]) (drivers.tex LaTeX Warning: Citation `ash95-DDSEP' on page 10 undefined on input line 16. Overfull \hbox (19.63927pt too wide) in paragraph at lines 30--35 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. LaTeX Warning: Citation `ash95-DDSEP' on page 10 undefined on input line 59. [10] Overfull \hbox (19.63927pt too wide) in paragraph at lines 76--81 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. Overfull \hbox (19.63927pt too wide) in paragraph at lines 119--124 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. [11] Overfull \hbox (19.63927pt too wide) in paragraph at lines 169--174 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. Overfull \hbox (19.63927pt too wide) in paragraph at lines 230--235 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. [12]) (main.ind [13] [14 ]) (main.aux) ) Here is how much of TeX's memory you used: 215 strings out of 11977 2346 string characters out of 87269 34975 words of memory out of 262141 2149 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,12n,17p,182b,260s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (14 pages, 48468 bytes). 80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/libGPart/doc/main.aux010064400020550007177000000044730654003366700153370ustar00clevecompmath00000400000006\relax \citation{ash95-DDSEP} \citation{ash96-maxflow} \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space GPart}: Graph Partitioning Object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \newlabel{chapter:GPart:intro}{{1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structures}{2}} \newlabel{section:GPart:dataStructure}{{1.1}{2}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space GPart} methods}{3}} \newlabel{section:GPart:proto}{{1.2}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{4}} \newlabel{subsection:GPart:proto:basics}{{1.2.1}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initializer methods}{4}} \newlabel{subsection:GPart:proto:initializers}{{1.2.2}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{5}} \newlabel{subsection:GPart:proto:utilities}{{1.2.3}{5}} \citation{ash95-DDSEP} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}Domain decomposition methods}{6}} \newlabel{subsection:GPart:proto:domain-decomposition}{{1.2.4}{6}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.5}Methods to generate a 2-set partition}{6}} \newlabel{subsection:GPart:proto:2-set}{{1.2.5}{6}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.6}Methods to improve a 2-set partition}{7}} \newlabel{subsection:GPart:proto:improve}{{1.2.6}{7}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.7}Recursive Bisection method}{9}} \newlabel{subsection:GPart:proto:RB}{{1.2.7}{9}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.8}{\string\ptt\space DDsepInfo} methods}{9}} \newlabel{subsection:GPart:proto:DDsepInfo}{{1.2.8}{9}} \citation{ash95-DDSEP} \citation{ash95-DDSEP} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs for the {\string\ptt\space GPart} object}{10}} \newlabel{section:GPart:drivers}{{1.3}{10}} GPart/doc/drivers.tex010064400020550007177000000257120665023015200160610ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt GPart} object} \label{section:GPart:drivers} \par This section contains brief descriptions of four driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testDDviaFishnet msglvl msgFile inGraphFile freeze minweight maxweight seed outIVfile \end{verbatim} This driver program constructs a domain decomposition via the {\it fishnet} algorithm \cite{ash97-DDSEP}. It reads in a {\tt Graph} object from a file, finds the domain decomposition using the four input parameters, then optionally writes out the map from vertices to components to a file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the output file --- if {\tt msgFile} is {\tt stdout}, then the output file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt freeze} parameter is used to place nodes of high degree into the multisector. If the external degree of a vertex is {\tt freeze} times the average degree, then it is placed in the multisector. \item The {\it target} minimum weight for a domain is {\tt minweight}. \item The {\it target} maximum weight for a domain is {\tt maxweight}. \item The {\tt seed} parameter is a random number seed. \item The {\tt outIVfile} parameter is the output file for the {\tt IV} object that contains the map from vertices to components. If {\tt outIVfile} is {\tt "none"}, then there is no output, otherwise {\tt outIVfile} must be of the form {\tt *.ivf} or {\tt *.ivb}. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testTwoSetViaBKL msglvl msgFile inGraphFile inIVfile seed alpha outIVfile \end{verbatim} This driver program constructs a two-set partition via the Block Kernighan-Lin algorithm \cite{ash97-DDSEP}. It reads in a {\tt Graph} object and an {\tt IV} object that holds the map from vertices to components (e.g., the output from the driver program {\tt testDDviaFishet}) from two files, constructs the domain-segment graph and finds an initial separator, then optionally writes out the new map from vertices to components to a file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the output file --- if {\tt msgFile} is {\tt stdout}, then the output file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt inIVfile} parameter is the input file for the {\tt IV} object that contains the map from vertices to domains and multisector. It {\tt inIVfile} must be of the form {\tt *.ivf} or {\tt *.ivb}. \item The {\tt seed} parameter is a random number seed. \item The {\tt alpha} parameter controls the partition evaluation function. \item The {\tt outIVfile} parameter is the output file for the {\tt IV} object that contains the map from vertices to separator and the two components. If {\tt outIVfile} is {\tt "none"}, then there is no output, otherwise {\tt outIVfile} must be of the form {\tt *.ivf} or {\tt *.ivb}. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testSmoothBisector msglvl msgFile inGraphFile inIVfile option alpha outIVfile \end{verbatim} This driver program smooths a bisector of a graph by solving a sequence of max-flow network problems. It reads in a {\tt Graph} object and an {\tt IV} object that holds the map from vertices to components (e.g., the output from the driver program {\tt testTwoSetViaBKL}) from two files, smooths the separator and then optionally writes out the new component ids map to a file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the output file --- if {\tt msgFile} is {\tt stdout}, then the output file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt inIVfile} parameter is the input file for the {\tt IV} object that contains the map from vertices to domains and multisector. It {\tt inIVfile} must be of the form {\tt *.ivf} or {\tt *.ivb}. \item The {\tt option} parameter specifies the type of network optimization problem that will be solved. \begin{itemize} \item {\tt option = 1} --- each network has two layers and is bipartite. \item {\tt option = 2} --- each network has two layers but need not be bipartite. \item {\tt option = 2} --- each network has {\tt option/2} layers on each side of the separator. \end{itemize} \item The {\tt alpha} parameter controls the partition evaluation function. \item The {\tt outIVfile} parameter is the output file for the {\tt IV} object that contains the map from vertices to separator and the two components. If {\tt outIVfile} is {\tt "none"}, then there is no output, otherwise {\tt outIVfile} must be of the form {\tt *.ivf} or {\tt *.ivb}. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testRBviaDDsep msglvl msgFile inGraphFile seed minweight maxweight freeze alpha maxdomweight DDoption nlayer testRBviaDDsep2 msglvl msgFile inGraphFile nruns seed minweight maxweight freeze alpha maxdomweight DDoption nlayer \end{verbatim} These driver programs construct a multisector via recursive bisection and orders the graph using nested dissection and multisection using the multisector. {\tt testRBviaDDsep} executes only one run while {\tt testRBviaDDsep2} executes {\tt nruns} runs with random permutations of the graph. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the output file --- if {\tt msgFile} is {\tt stdout}, then the output file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt nruns} parameter is the number of runs made with the graph randomly permuted. \item The {\tt seed} parameter is a random number seed. \item The {\it target} minimum weight for a domain is {\tt minweight}. \item The {\it target} maximum weight for a domain is {\tt maxweight}. \item The {\tt freeze} parameter is used to place nodes of high degree into the multisector. If the external degree of a vertex is {\tt freeze} times the average degree, then it is placed in the multisector. \item The {\tt alpha} parameter controls the partition evaluation function. \item The {\tt maxdomweight} parameter controls the recursive bisection --- no subgraph with weight less than {\tt maxdomweight} is further split. \item The {\tt DDoption} parameter controls the initial domain/segment partition on each subgraph. When {\tt DDDoption = 1} we use the fishnet algorithm for each subgraph. When {\tt DDDoption = 1} we use the fishnet algorithm once for the entire graph and this is then projected down onto each subgraph. \item The {\tt nlayer} parameter governs the smoothing process by specifying the type of network optimization problem that will be solved. \begin{itemize} \item {\tt nlayer = 1} --- each network has two layers and is bipartite. \item {\tt nlayer = 2} --- each network has two layers but need not be bipartite. \item {\tt nlayer > 2} --- each network has {\tt option/2} layers on each side of the separator. \end{itemize} \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} mkDSTree msglvl msgFile inGraphFile seed minweight maxweight freeze alpha maxdomweight DDoption nlayer outDSTreeFile \end{verbatim} This driver program constructs a domain/separator tree using recursive bisection. The {\tt DSTree} object is optionally written to a file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the output file --- if {\tt msgFile} is {\tt stdout}, then the output file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt seed} parameter is a random number seed. \item The {\it target} minimum weight for a domain is {\tt minweight}. \item The {\it target} maximum weight for a domain is {\tt maxweight}. \item The {\tt freeze} parameter is used to place nodes of high degree into the multisector. If the external degree of a vertex is {\tt freeze} times the average degree, then it is placed in the multisector. \item The {\tt alpha} parameter controls the partition evaluation function. \item The {\tt maxdomweight} parameter controls the recursive bisection --- no subgraph with weight less than {\tt maxdomweight} is further split. \item The {\tt DDoption} parameter controls the initial domain/segment partition on each subgraph. When {\tt DDDoption = 1} we use the fishnet algorithm for each subgraph. When {\tt DDDoption = 1} we use the fishnet algorithm once for the entire graph and this is then projected down onto each subgraph. \item The {\tt nlayer} parameter governs the smoothing process by specifying the type of network optimization problem that will be solved. \begin{itemize} \item {\tt nlayer = 1} --- each network has two layers and is bipartite. \item {\tt nlayer = 2} --- each network has two layers but need not be bipartite. \item {\tt nlayer > 2} --- each network has {\tt option/2} layers on each side of the separator. \end{itemize} \item The {\tt outDSTreeFile} parameter is the output file for the {\tt DSTree} object. It must be of the form {\tt *.dstreef} or {\tt *.dstreeb}. If {\tt outDSTreeFile} is not {\tt "none"}, the {\tt DSTree} object is written to the file via the {\tt DSTree\_writeToFile()} method. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} t {\tt inIVfile} must be of the form {\tt *.ivf} or {\GPart/doc/proto.tex010064400020550007177000000642020665023015500155460ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt GPart} methods} \label{section:GPart:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt GPart} object. % There are four families: % basics, % IO, % initializers % and % utilities. There are no IO methods. \par \subsection{Basic methods} \label{subsection:GPart:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} GPart * GPart_new ( void ) ; \end{verbatim} \index{GPart_new@{\tt GPart\_new()}} This method simply allocates storage for the {\tt GPart} structure and then sets the default fields by a call to {\tt GPart\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void GPart_setDefaultFields ( GPart *gpart ) ; \end{verbatim} \index{GPart_setDefaultFields@{\tt GPart\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt id = -1}, {\tt nvtx = nvbnd = ncomp = 0}, {\tt g} = {\tt par} = {\tt fch} = {\tt sib} = {\tt NULL}, and the default fields for {\tt compidsIV}, {\tt cweightsIV} and {\tt vtxMapIV} are set via calls to {\tt IV\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt gpart} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void GPart_clearData ( GPart *gpart ) ; \end{verbatim} \index{GPart_clearData@{\tt GPart\_clearData()}} The {\tt IV\_clearData()} method is called for the {\tt compidsIV}, {\tt cweightsIV} and {\tt vtxMapIV} objects. The structure's fields are then set with a call to {\tt GPart\_setDefaultFields()}. Note, storage for the {\tt Graph} object {\tt gpart->graph} is {\bf not} free'd. The {\tt GPart} object does not own its {\tt Graph} object, it only uses it. \par \noindent {\it Error checking:} If {\tt gpart} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void GPart_free ( GPart *gpart ) ; \end{verbatim} \index{GPart_free@{\tt GPart\_free()}} This method releases any storage by a call to {\tt GPart\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt gpart} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:GPart:proto:initializers} \par There are two initializer methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void GPart_init ( GPart *gpart, Graph *graph ) ; \end{verbatim} \index{GPart_init@{\tt GPart\_init()}} This method initializes the {\tt Gpart} object given a {\tt Graph} object as input. Any previous data is cleared with a call to {\tt GPart\_clearData()}. The {\tt graph}, {\tt nvtx}, {\tt nvbnd} fields are set. The {\tt compidsIV} and {\tt cweightsIV} {\tt IV} objects are initialized. The remaining fields are not changed from their default values. \par \noindent {\it Error checking:} If {\tt gpart} or {\tt g} is {\tt NULL}, or if $\mbox{\tt g->nvtx} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void GPart_setMessageInfo ( GPart *gpart, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{GPart_setMessageInfo@{\tt GPart\_setMessageInfo()}} This method sets the {\tt msglvl} and {\tt msgFile} fields. \par \noindent {\it Error checking:} If {\tt gpart} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:GPart:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void GPart_setCweights ( GPart *gpart ) ; \end{verbatim} \index{GPart_setCweights@{\tt GPart\_setCweights()}} This method sets the component weights vector {\tt cweightsIV}. We assume that the {\tt compidsIV} vector has been set prior to entering this method. The weight of a component is not simply the sum of the weights of the vertices with that component's id. We accept the separator or multisector vertices (those {\tt v} with {\tt compids[v] == 0}) but then find the connected components of the remaining vertices, renumbering the {\tt compidsIV} vector where necessary. Thus, {\tt ncomp} and {\tt compidsIV} may be updated, and {\tt cweightsIV} is set. \par \noindent {\it Error checking:} If {\tt gpart} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int GPart_sizeOf ( GPart *gpart ) ; \end{verbatim} \index{GPart_sizeOf@{\tt GPart\_sizeOf()}} This method returns the number of bytes owned by the object. This includes the structure itself, the {\tt compidsIV}, {\tt cweightsIV} and {\tt vtxMapIV} arrays (if present), but {\tt not} the {\tt Graph} object. \par \noindent {\it Error checking:} If {\tt gpart} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int GPart_validVtxSep ( GPart *gpart ) ; \end{verbatim} \index{GPart_validVtxSep@{\tt GPart\_validVtxSep()}} This method returns 1 if the partition defined by the {\tt compidsIV} vector has a valid vertex separator and zero otherwise. When there is a valid vertex separator, there are no adjacent vertices not in the multisector that belong to different components (as defined by the {\tt compidsIV} vector). \par \noindent {\it Error checking:} If {\tt gpart} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void GPart_split ( GPart *gpart ) ; \end{verbatim} \index{GPart_split@{\tt GPart\_split()}} This method is used to split a subgraph during the nested dissection process that builds a tree of {\tt GPart} objects. We first generate a valid partition via the {\tt GPart\_setCweights()} method, and then split the graph into its component subgraphs. Each subgraph is assigned to a new child {\tt GPart} object. The {\tt Graph} object for each subgraph is formed from the parent graph using the {\tt Graph\_subGraph()} method. This means that the storage for the adjacency lists of the subgraph is taken from the storage for the parent graph --- the lists are mapped into the local ordering via the {\tt vtxMap} vector. After {\tt GPart\_split(gpart)} is called, the adjacency lists for the vertices in {\tt gpart->g} are no longer valid. \par \noindent {\it Error checking:} If {\tt gpart} or {\tt g} is {\tt NULL}, or if {\tt gpart->fch} is not {\tt NULL} (meaning that the subgraph has already been split), an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int GPart_vtxIsAdjToOneDomain ( GPart *gpart, int v, int *pdomid ) ; \end{verbatim} \index{GPart_vtxIsAdjToOneDomain@{\tt GPart\_vtxIsAdjToOneDomain()}} This method determines whether the vertex {\tt v} is adjacent to just one domain or not. We use this method to make a separator or multisector minimal. If the vertex is adjacent to only one domain, the return value is {\tt 1} and {\tt *pdomid} is set to the domain's id. If a vertex is adjacent to zero or two or more domains, the return value is zero. If a vertex belongs to a domain, it is considered adjacent to that domain. \par \noindent {\it Error checking:} If {\tt gpart}, {\tt g} or {\tt domid} is {\tt NULL}, or if {\tt v} is out of range (i.e., ${\tt v} < 0$ or ${\tt nvtx} \le {\tt v}$), an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * GPart_bndWeightsIV ( GPart *gpart ) ; \end{verbatim} \index{GPart_bndWeightsIV@{\tt GPart\_bndWeightsIV()}} This method returns an {\tt IV} object that contains the weights of the vertices on the boundaries of the components. \par \noindent {\it Error checking:} If {\tt gpart} or {\tt g} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Domain decomposition methods} \label{subsection:GPart:proto:domain-decomposition} \par There are presently two methods that create a domain decomposition of a graph or a subgraph. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void GPart_DDviaFishnet ( GPart *gpart, double frac, int minweight, int maxweight, int seed ) ; \end{verbatim} \index{GPart_DDviaFishnet@{\tt GPart\_DDviaFishnet()}} This method generates a domain decomposition of a graph using the {\it fishnet} algorithm (see \cite{ash97-DDSEP} for details). On return, the {\tt compidsIV} vector is filled with component ids and {\tt ncomp} is set with the number of domains. The {\tt frac} parameter governs the exclusion of nodes of high degree from the domain sets. We have found this to be useful for some graphs. Nodes of very high degree (relative to the average or mean degree) can severely distort a domain decomposition. We have found that setting {\tt frac} to four works well in practice. The {\tt minweight} and {\tt maxweight} parameters are the minimum target weight and maximum target weight for a domain. The {\tt seed} parameter is used to insert a degree of randomness into the algorithm. This allows us to make several runs and take the best partition. \par \noindent {\it Error checking:} If {\tt gpart} or {\tt g} is {\tt NULL}, or if ${\tt freeze} \le 0.0$, or if ${\tt minweight} < 0$, or if ${\tt maxweight} < 0$, or if ${\tt minweight} \ge {\tt maxweight}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void GPart_DDviaProjection ( GPart *gpart, IV *DDmapIV ) ; \end{verbatim} \index{GPart_DDviaProjection@{\tt GPart\_DDviaProjection()}} This method generates a domain decomposition for a subgraph by projecting an existing domain decoposition for the original graph onto the subgraph. Using this method (as opposed to generating a domain decomposition for each subgraph) can typically save 15\% of the overall time to find the graph decomposition, though the resulting partition is usually not as good. \par \noindent {\it Error checking:} If {\tt gpart} or {\tt DDmapIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Methods to generate a 2-set partition} \label{subsection:GPart:proto:2-set} \par These two methods are used to generate a 2-set partition $[S,B,W]$ from a domain decomposition. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} double GPart_TwoSetViaBKL ( GPart *gpart, double alpha, int seed, double cpus[] ) ; \end{verbatim} \index{GPart_TwoSetViaBKL@{\tt GPart\_TwoSetViaBKL()}} This method takes a domain decomposition $\{\Phi, \Omega_1, \ldots, \Omega_m\}$ defined by the {\tt compidsIV} vector and generates a two set partition $[S,B,W]$. We first compute the map from vertices to domains and segments (the segments partition the interface nodes $\Phi$). We then construct the bipartite graph that represents the connectivity of the domains and segments. Each segment is an ``edge'' that connects two ``adjacent'' domains. This allows us to use a variant of the Kernighan-Lin algorithm to find an ``edge'' separator formed of segments, which is really a vertex separator, a subset of $\Phi$. The {\tt alpha} parameter is used in the cost function evaluation for the partition, $\displaystyle \mbox{cost}([S,B,W]) = |S|\left(1 + \alpha \frac{\max\{|B|,|W|\}} {\min\{|B|,|W|\}} \right) $. The {\tt seed} parameter is used to randomize the algorithm. One can make several runs with different seeds and chose the best partition. The {\tt cpus[]} array is used to store execution times for segments of the algorithm: {\tt cpus[0]} stores the time to compute the domain/segment map; {\tt cpus[2]} stores the time to create the domain/segment bipartite graph; {\tt cpus[3]} stores the time to find the bisector using the block Kernighan-Lin algorithm. \par \noindent {\it Error checking:} If {\tt gpart} or {\tt cpus} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * GPart_domSegMap ( GPart *gpart, int *pndom, int *pnseg ) ; \end{verbatim} \index{GPart_domSegMap@{\tt GPart\_domSegMap()}} This method takes a domain decomposition as defined by the {\tt compidsIV} vector and generates the map from the vertices to the domains and segments that are used in the Block Kernighan-Lin procedure to find an initial separator. The map is returned in an {\tt IV} object, and the numbers of domains and segments are set in the {\tt pndom} and {\tt pnseg} addresses. This method is called by {\tt GPart\_TwoSetViaBKL}. \par \noindent {\it Error checking:} If {\tt gpart}, {\tt g}, {\tt pndom} or {\tt pnseg} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Methods to improve a 2-set partition} \label{subsection:GPart:proto:improve} \par These methods are used to improve a 2-set partition $[S,B,W]$. They hinge on finding a {\it wide separator} $Y$ and constructing a better separator ${\widehat S} \subseteq Y$. The {\tt alpha} parameter is used in the cost function $\displaystyle \mbox{cost}([S,B,W]) = |S|\left(1 + \alpha \frac{\max\{|B|,|W|\}} {\min\{|B|,|W|\}} \right) $. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IV * GPart_identifyWideSep ( GPart *gpart, int nlayer1, int nlayer2 ) ; \end{verbatim} \index{GPart_identifyWideSep@{\tt GPart\_identifyWideSep()}} This method takes a 2-set partition $[S,B,W]$ and identifies a {\it wide separator} $Y$ that contains $S$. The portions of $B$ and $W$ that are included in $Y$ are specified using the {\tt nlayer1} and {\tt nlayer2} parameters. If both are zero, then $Y$ is simply $S$. If {\tt nlayer1 > 0}, then $Y$ contains all vertices in the first component whose distance is {\tt nlayer1} or less from $S$, and similarly for {\tt nlayer2 > 0}. The vertices in $Y$ are placed in an {\tt IV} object which is then returned. \par \noindent {\it Error checking:} If {\tt gpart} or {\tt g} is {\tt NULL}, or if ${\tt nlevel1} < 0$ or ${\tt nlevel2} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * GPart_makeYCmap ( GPart *gpart, IV *YVmapIV ) ; \end{verbatim} \index{GPart_makeYCmap@{\tt GPart\_makeYCmap()}} This method contructs and returns an {\tt IV} object that is the blueprint used to form the network. The wide separator $Y$ can be partitioned into four disjoint sets (though some may be empty): \begin{eqnarray*} Y_0 & = & \{y \in Y\ |\ y \notin Adj(B \setminus Y) % y \cap Adj(B \setminus Y) = \emptyset \mbox{\ and\ } y \notin Adj(W \setminus Y) % y \cap Adj(W \setminus Y) = \emptyset \} \\ Y_1 & = & \{y \in Y\ |\ y \in Adj(B \setminus Y) % y \cap Adj(B \setminus Y) \ne \emptyset \mbox{\ and\ } y \notin Adj(W \setminus Y) % y \cap Adj(W \setminus Y) = \emptyset \} \\ Y_2 & = & \{y \in Y\ |\ y \notin Adj(B \setminus Y) % y \cap Adj(B \setminus Y) = \emptyset \mbox{\ and\ } y \in Adj(W \setminus Y) % y \cap Adj(W \setminus Y) \ne \emptyset \} \\ Y_3 & = & \{y \in Y\ |\ y \in Adj(B \setminus Y) % y \cap Adj(B \setminus Y) \ne \emptyset \mbox{\ and\ } y \in Adj(W \setminus Y) % y \cap Adj(W \setminus Y) \ne \emptyset \} \end{eqnarray*} The {\tt YVmapIV} object contains the list of vertices in the wide separator $Y$. The {\tt IV} object that is returned, (called {\tt YCmapIV} in the calling method) contains the subscripts of the $Y_0$, $Y_1$, $Y_2$ or $Y_3$ sets that contains each vertex. \par \noindent {\it Error checking:} If {\tt gpart}, {\tt g} or {\tt YVmapIV} is {\tt NULL}, or if ${\tt nvtx} \le 0$, or if {\tt YVmapIV} is empty, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void * GPart_smoothBy2layers ( GPart *gpart, int bipartite, float alpha ) ; \end{verbatim} \index{GPart_smoothBy2layers@{\tt GPart\_smoothBy2layers()}} This method forms the wide separator $Y$ from two layers of vertices, either $Y_B = S \cup (Adj(S) \cap B)$ or $Y_W = S \cup (Adj(S) \cap W)$. (If $|B| \ge |W|$, we first look at $Y_B$ and if no improvement can be made we look at $Y_W$, and the reverse if $|W| > |B|$.) The {\tt bipartite} parameter defines the type of network problem we solve. The network induced by the wide separator $Y$ need not be bipartite, and will not be bipartite if $Y_0 \ne \emptyset$ or $Y_3 \ne \emptyset$, ($Y_0$ and $Y_3$ are defined immediately above). The $Y_3$ set is not important, since it must be included in any separator ${\widehat S} \subseteq Y$. When $Y_0$ is not empty, it forms a layer {\it between} $Y_1$ and $Y_2$, and so the network is not bipartite. We can force the network to be bipartite (set {\tt bipartite} to {\tt 1}) by moving all nodes in $Y_0$ to the appropriate $Y_1$ or $Y_2$. When the graph is unit-weight and the network is bipartite, we can use the Dulmage-Mendelsohn decomposition to find one or more separators of minimum weight. In general, forcing a non-bipartite network to be bipartite results in possibly a larger separator, so we do not recommend this option. The capability is there to compare the Dulmage-Mendelsohn decomposition smoothers with the more general (and robust) max flow smoothers. \par \noindent {\it Error checking:} If {\tt gpart} is {\tt NULL}, or if ${\tt alpha} < 0.0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} float * GPart_smoothYSep ( GPart *gpart, IV *YVmapIV, IV *YCmapIV, float alpha ) ; \end{verbatim} \index{GPart_smoothYSep@{\tt GPart\_smoothYSep()}} This methods takes as input a 2-set partition $[S,B,W]$ (defined by {\tt gpart->compidsIV}), a wide separator $Y$ (defined by {\tt YVmapIV}) and a $\langle Y_0, Y_1, Y_2, Y_3 \rangle$ partition of $Y$ (defined by {\tt YCmapIV}) and attempts to find a better partition. A max flow problem is solved on a network induced by $\langle Y_0, Y_1, Y_2, Y_3 \rangle$. Two min-cuts and the partitions they induce are examined and the better partition is accepted if better than $[S,B,W]$. The parameter {\tt alpha} is used in the partition's cost function, and the cost of the best partition is returned. \par \noindent {\it Error checking:} If {\tt gpart}, {\tt YVmapIV} or {\tt YCmapIV} is {\tt NULL}, or if ${\tt alpha} < 0.0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} float * GPart_smoothBisector ( GPart *gpart, int nlayer, float alpha ) ; \end{verbatim} \index{GPart_smoothBisector@{\tt GPart\_smoothBisector()}} This method takes a two-set partition $[S,B,W]$ as defined by the {\tt compidsIV} vector and improves it (if possible). The methods returns the cost of a (possibly) new two-set partition $[{\widehat S}, {\widehat B}, {\widehat W}]$ defined by the {\tt compidsIV} vector. The wide separator $Y$ that is constructed is {\it centered} around $S$, i.e., $Y$ includes all nodes in $B$ and $W$ that are {\tt nlayer} distance or less from $S$. This method calls {\tt GPart\_smoothYSep()}. \par \noindent {\it Error checking:} If {\tt gpart} is {\tt NULL}, or if ${\tt nlevel} < 0$, or if ${\tt alpha} < 0.0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Recursive Bisection method} \label{subsection:GPart:proto:RB} \par There is presently one method to construct the domain/separator tree. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} DSTree * GPart_RBviaDDsep ( GPart *gpart, DDsepInfo *info ) ; \end{verbatim} \index{GPart_RBviaDDsep@{\tt GPart\_RBviaDDsep()}} This method performs a recursive bisection of the graph using the {\tt DDSEP} algorithm and returns a {\tt DSTree} object that represents the domain/separator tree and the map from vertices to domains and separators. The {\tt DDsepInfo} structure contains all the parameters to the different steps of the {\tt DDSEP} algorithm (the fishnet method to find the domain decomposition, the Block Kernighan-Lin method to find an initial separator, and solves a max flow problem to improve the separator). An attempt is made to split a subgraph if the weight of the internal vertices of the subgraph exceeds {\tt info->maxcompweight}. The cpu times for the different segments of the algorithm are accumulated in fields of the {\tt DDsepInfo} object. \par \noindent {\it Error checking:} If {\tt gpart} or {\tt info} is {\tt NULL}, or if ${\tt nvtx} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{{\tt DDsepInfo} methods} \label{subsection:GPart:proto:DDsepInfo} \par The {\tt DDsepInfo} {\it helper}-object is used during the {\tt DDSEP} recursive bisection process. It stores the necessary input parameters for the different stages of the {\tt DDSEP} algorithm and collects statistics about the resulting partition. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} DDsepInfo * DDsepInfo_new ( void ) ; \end{verbatim} \index{DDepInfo_new@{\tt DDsepInfo\_new()}} This method simply allocates storage for the {\tt DDsepInfo} structure and then sets the default fields by a call to {\tt DDsepInfo\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void DDsepInfo_setDefaultFields ( DDsepInfo *info ) ; \end{verbatim} \index{DDepInfo_setDefaultFields@{\tt DDsepInfo\_setDefaultFields()}} This method checks to see whether {\tt info} is {\tt NULL}. If so, an error message is printed and the program exits. Otherwise, the structure's fields are set to the following default values. \begin{verbatim} info->seed = 1 ; info->cpuDD = 0.0 ; info->minweight = 40 ; info->cpuMap = 0.0 ; info->maxweight = 80 ; info->cpuBPG = 0.0 ; info->frac = 4.0 ; info->cpuBKL = 0.0 ; info->alpha = 1.0 ; info->cpuSmooth = 0.0 ; info->maxcompweight = 500 ; info->cpuSplit = 0.0 ; info->ntreeobj = 0 ; info->cpuTotal = 0.0 ; info->DDoption = 1 ; info->msglvl = 0 ; info->nlayer = 3 ; info->msgFile = stdout ; \end{verbatim} \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DDsepInfo_clearData ( DDsepInfo *info ) ; \end{verbatim} \index{DDepInfo_clearData@{\tt DDsepInfo\_clearData()}} This method checks to see whether {\tt info} is {\tt NULL}. {\tt DDsepInfo\_setDefaultFields()} is called to set the default values. \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DDsepInfo_free ( DDsepInfo *info ) ; \end{verbatim} \index{DDepInfo_free@{\tt DDsepInfo\_free()}} This method checks to see whether {\tt info} is {\tt NULL}. If so, an error message is printed and the program exits. Otherwise, it releases any storage by a call to {\tt DDsepInfo\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DDsepInfo_writeCpuTimes ( DDsepInfo *info, FILE *msgFile ) ; \end{verbatim} \index{DDepInfo_writeCpuTimes@{\tt DDsepInfo\_writeCpuTimes()}} This method writes a breakdown of the CPU times in a meaningful format. Here is sample output. \begin{verbatim} CPU breakdown for graph partition raw CPU per cent misc : 1.61 1.2% Split : 24.68 17.7% find DD : 12.13 8.7% DomSeg Map : 13.09 9.4% DomSeg BPG : 4.66 3.3% BKL : 5.68 4.1% Smooth : 77.83 55.7% Total : 139.67 100.0% \end{verbatim} \par \noindent {\it Error checking:} If {\tt info} or {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} Y) = \emptyset \} \\ Y_1 & = & \{y \in Y\ |\ y \in Adj(B \setminus Y) % y \cap Adj(B \setminus Y) \ne \emptyset \mbox{\ and\ } y \notin Adj(W \setminus Y) % y \cap Adj(W \setminus Y) = \emptyset \} \\ Y_2 & = & \{y \in Y\ |\ y \notin Adj(B \setminus Y) % y \cap Adj(B \setminus Y) = \emptyset GPart/doc/main.idx010064400020550007177000000030510654003366700153150ustar00clevecompmath00000400000006\indexentry{GPart_new@{\tt GPart\_new()}}{4} \indexentry{GPart_setDefaultFields@{\tt GPart\_setDefaultFields()}}{4} \indexentry{GPart_clearData@{\tt GPart\_clearData()}}{4} \indexentry{GPart_free@{\tt GPart\_free()}}{4} \indexentry{GPart_init@{\tt GPart\_init()}}{4} \indexentry{GPart_setMessageInfo@{\tt GPart\_setMessageInfo()}}{4} \indexentry{GPart_setCweights@{\tt GPart\_setCweights()}}{5} \indexentry{GPart_sizeOf@{\tt GPart\_sizeOf()}}{5} \indexentry{GPart_validVtxSep@{\tt GPart\_validVtxSep()}}{5} \indexentry{GPart_split@{\tt GPart\_split()}}{5} \indexentry{GPart_vtxIsAdjToOneDomain@{\tt GPart\_vtxIsAdjToOneDomain()}}{5} \indexentry{GPart_bndWeightsIV@{\tt GPart\_bndWeightsIV()}}{6} \indexentry{GPart_DDviaFishnet@{\tt GPart\_DDviaFishnet()}}{6} \indexentry{GPart_DDviaProjection@{\tt GPart\_DDviaProjection()}}{6} \indexentry{GPart_TwoSetViaBKL@{\tt GPart\_TwoSetViaBKL()}}{6} \indexentry{GPart_domSegMap@{\tt GPart\_domSegMap()}}{7} \indexentry{GPart_identifyWideSep@{\tt GPart\_identifyWideSep()}}{7} \indexentry{GPart_makeYCmap@{\tt GPart\_makeYCmap()}}{7} \indexentry{GPart_smoothBy2layers@{\tt GPart\_smoothBy2layers()}}{8} \indexentry{GPart_smoothYSep@{\tt GPart\_smoothYSep()}}{8} \indexentry{GPart_smoothBisector@{\tt GPart\_smoothBisector()}}{8} \indexentry{GPart_RBviaDDsep@{\tt GPart\_RBviaDDsep()}}{9} \indexentry{DDepInfo_new@{\tt DDsepInfo\_new()}}{9} \indexentry{DDepInfo_setDefaultFields@{\tt DDsepInfo\_setDefaultFields()}}{9} \indexentry{DDepInfo_clearData@{\tt DDsepInfo\_clearData()}}{9} \indexentry{DDepInfo_free@{\tt DDsepInfo\_free()}}{10} GPart/doc/main.ilg010064400020550007177000000004570654003365500153100ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (26 entries accepted, 0 rejected). Sorting entries....done (126 comparisons). Generating output file main.ind....done (33 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. GPart/doc/makefile010064400020550007177000000000270657627125400153700ustar00clevecompmath00000400000006clean : - rm -f *.dvi Graph.h010064400020550007177000000001000653410640200132720ustar00clevecompmath00000400000006#ifndef _Graph_ #define _Graph_ #include "Graph/Graph.h" #endif Graph/Graph.h010064400020550007177000000562360661665727400144030ustar00clevecompmath00000400000006/* Graph.h */ #include "../IVL.h" #include "../IV.h" #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- The Graph object represents one of three types of graphs, defined by its "type" field. The Graph object uses IVL objects to store the vertex adjacency lists and edge weight lists (for types 2 and 3). The Graph object also supports graphs with "boundaries". This need arose from ordering graphs using constrained minimum degree where boundary vertices contribute to the degree but are not eliminated. created : 95-sep27, cca --------------------------------------------------------------- */ /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- data fields type -- type of graph type vertices weighted? edges weighted? 0 no no 1 yes no 2 no yes 3 yes yes nvtx -- number of vertices, also equals adjIVL->nlist and ewghtIVL->nlist nvbnd -- number of boundary vertices nedges -- number of edges, also equals adjIVL->tsize and ewghtIVL->tsize totvwght -- total vertex weight totewght -- total edge weight adjIVL -- IVL object that holds the adjacency lists vwghts -- int vector that holds the vertex weights, size nvtx + nvbnd, not NULL if type % 2 == 1 ewghtIVL -- IVL object that holds the edge weight lists, not NULL if type >= 2 --------------------------------------------------------- */ typedef struct _Graph Graph ; struct _Graph { int type ; int nvtx ; int nvbnd ; int nedges ; int totvwght ; int totewght ; IVL *adjIVL ; int *vwghts ; IVL *ewghtIVL ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in basics.c ------------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- purpose -- create and return a new Graph object created -- 95sep27, cca ----------------------------------------------- */ Graph * Graph_new ( void ) ; /* ------------------------------------------------------ purpose -- set the default fields for the Graph object created -- 95sep27, cca ------------------------------------------------------ */ void Graph_setDefaultFields ( Graph *g ) ; /* -------------------------------- purpose -- clear the data fields created -- 95sep27, cca -------------------------------- */ void Graph_clearData ( Graph *g ) ; /* -------------------------------- purpose -- free the Graph object created -- 95sep27, cca -------------------------------- */ void Graph_free ( Graph *g ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in compress.c ----------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------------- given a graph g and a fine-to-coarse map vector cmap[], return a compressed graph with type coarseType. note, the compressed graph will have no trivial boundary even if the original graph did have a boundary. created -- 95sep29, cca --------------------------------------------------------------- */ Graph * Graph_compress ( Graph *g, int cmap[], int coarseType ) ; /* --------------------------------------------------------------- given a graph g and a fine-to-coarse map vector *mapIV, return a compressed graph with type coarseType. note, the compressed graph will have no trivial boundary even if the original graph did have a boundary. created -- 96mar02, cca --------------------------------------------------------------- */ Graph * Graph_compress2 ( Graph *g, IV *mapIV, int coarseType ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in equivMap.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- fill an IV object with an equivalence map if ( map[u] == map[v] ) then then u and v are adjacent to the same vertices endif NOTE : each empty list is mapped to a different value return value -- IV object that contains the equivalence map created -- 96feb23, cca ----------------------------------------------------------- */ IV * Graph_equivMap ( Graph *g ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in expand.c ------------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- purpose -- take a Graph object and a map to expand it, create and return a bigger unit weight Graph object. this is useful for expanding a compressed graph into a unit weight graph. created -- 96mar02, cca --------------------------------------------------------------------- */ Graph * Graph_expand ( Graph *g, int nvtxbig, int map[] ) ; /* --------------------------------------------------------------------- purpose -- take a Graph object and a map to expand it, create and return a bigger unit weight Graph object. this is useful for expanding a compressed graph into a unit weight graph. created -- 96mar02, cca --------------------------------------------------------------------- */ Graph * Graph_expand2 ( Graph *g, IV *mapIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in fillFromOffsets.c ---------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------- purpose -- take an adjacency structure in the (offsets[neqns+1], adjncy[*]) form and load the Graph object g -- pointer to Graph object, must be initialized with nvtx = neqns neqns -- # of equations offsets -- offsets vector adjncy -- big adjacency vector note, the adjacency for list v is found in adjncy[offsets[v]:offsets[v+1]-1] also note, offsets[] and adjncy[] must be zero based, if (offsets,adjncy) come from a harwell-boeing file, they use the fortran numbering, so each value must be decremented to conform with C's zero based numbering flag -- task flag flag = 0 --> just set the adjacency list for v to be that found in adjncy[offsets[v]:offsets[v+1]-1] flag = 1 --> the input adjancency is just the upper triangle (or strict upper triangle) as from a harwell-boeing file. fill the Graph object with the full adjacency structure, including (v,v) edges created -- 96mar16, cca ------------------------------------------------------------------- */ void Graph_fillFromOffsets ( Graph *g, int neqns, int offsets[], int adjncy[], int flag ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in init.c --------------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------- basic initializer for the Graph object type -- graph type nvtx -- # of vertices nvbnd -- # of boundary vertices nedges -- # of edges adjType -- IVL type for adjacency object ewghtType -- IVL type for edge weights object created -- 95sep27, cca --------------------------------------------- */ void Graph_init1 ( Graph *g, int type, int nvtx, int nvbnd, int nedges, int adjType, int ewghtType ) ; /* -------------------------------------------------------- second initializer for the Graph object. this function is used in the I/O routines Graph_readFromFormattedFile(Graph *g, FILE *fp) and Graph_readFromBinaryFile(Graph *g, FILE *fp) where the IVL object(s) and vwghts[] vector are created independently. type -- graph type nvtx -- # of vertices nvbnd -- # of boundary vertices nedges -- # of edges totvwght -- total vertex weight totewght -- total edge weight adjIVL -- IVL object for adjacency structure vwghts -- pointer to integer vector for vertex weights ewghtIVL -- IVL object for edge weights created -- 95sep27, cca -------------------------------------------------------- */ void Graph_init2 ( Graph *g, int type, int nvtx, int nvbnd, int nedges, int totvwght, int totewght, IVL *adjIVL, int *vwghts, IVL *ewghtIVL ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in util.c --------------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- return the external degree (in terms of vertex weight) of vertex v created -- 95oct05, cca --------------------------------------------------------------------- */ int Graph_externalDegree ( Graph *g, int v ) ; /* ----------------------------------- method to access the adjacency list created -- 95oct05, cca ----------------------------------- */ void Graph_adjAndSize ( Graph *g, int jvtx, int *psize, int **padj ) ; /* ----------------------------------------------- method to access the adjacency list and possibly the edge weight list for a vertex. created -- 95sep29, cca ----------------------------------------------- */ void Graph_adjAndEweights ( Graph *g, int jvtx, int *psize, int **padj, int **pewghts ) ; /* ---------------------------------------------------- return the number of bytes taken by the Graph object created -- 95oct05, cca ---------------------------------------------------- */ int Graph_sizeOf ( Graph *g ) ; /* -------------------------------------- create and return an IV object filled with a map from vertices to components created -- 96feb25, cca -------------------------------------- */ IV * Graph_componentMap ( Graph *g ) ; /* ----------------------------------------------------------------- given a Graph g and map from vertices to components, fill counts[icomp] with the number of vertices in component icomp and fill weight[icomp] with their weight created -- 96feb25, cca ----------------------------------------------------------------- */ void Graph_componentStats ( Graph *g, int map[], int counts[], int weights[] ) ; /* ------------------------------------------------------------------- create and return a subgraph and a map from its vertices to the vertices of the graph. g -- graph from which to extract the subgraph icomp -- component from which comes the vertices of the subgraph, icomp > 0 compids -- component ids vector of graph pmap -- pointer to hold address of map vector, the map from the subgraph's vertices to the graph's vertices return value -- pointer to subgraph Graph object created -- 95nov10, cca ------------------------------------------------------------------- */ Graph * Graph_subGraph ( Graph *g, int icomp, int compids[], int **pmap ) ; /* ---------------------------------- return 1 if the graph is symmetric return 0 otherwise created -- 96oct31, cca ---------------------------------- */ int Graph_isSymmetric ( Graph *graph ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in polar.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- perform a breadth-first search v -- vertex to check out levelsIV -- IV object that holds the levels vector listIV -- IV object to hold order of search parIV -- IV object to hold parent vector return value -- depth of the search tree created -- 96jul13, cca ----------------------------------------------------------- */ int Graph_BFS ( Graph *graph, int v, IV *levelsIV, IV *listIV, IV *parIV ) ; /* ------------------------------------------------------------ perform a breadth-first search from a list of seed vertices. seedsIV -- IV object that holds the seed vertices levelsIV -- IV object that holds the levels vector listIV -- IV object to hold order of search parIV -- IV object to hold parent vector return value -- depth of the search tree created -- 96jul19, cca ------------------------------------------------------------ */ int Graph_BFS2 ( Graph *graph, IV *seedsIV, IV *levelsIV, IV *listIV, IV *parIV ) ; /* ---------------------------------------------------------- find a pseudodiameter of a graph. fill *pstart and *pend with the endpoint vertices. fill startLevelsIV and endLevelsIV with the level vectors for the BFS from the start and end vertices, respectively. created -- 96jul13, cca ---------------------------------------------------------- */ void Graph_pseudodiameter ( Graph *g, int root, IV *startLevelsIV, IV *endLevelsIV, int *pstart, int *pend ) ; /* ---------------------------------------------------------- create and return an IV object that contains a list of vertices that are in the major axis of the graph. we have dropped two levels structures from end vertices to approximate the diameter of the graph. a vertex v is in the major axis if levels1[v] + levels2[v] - tolerance <= d(s,e) fill *pstart and *pend with the endpoint vertices. created -- 96jul13, cca ---------------------------------------------------------- */ IV * Graph_majorAxis ( Graph *graph, int vstart, int vend, IV *startLevelsIV, IV *endLevelsIV, int tolerance ) ; /* ----------------------------------------------------------- compute and return the polar moment of inertia for a vertex v -- vertex to check out levelsIV -- IV object that holds the levels vector listIV -- IV object for workspace created -- 96jul13, cca ----------------------------------------------------------- */ double Graph_polarMoment ( Graph *graph, int v, IV *levelsIV, IV *listIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in setListsFromOffsets.c ------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------- purpose -- take an adjacency structure in the (offsets[neqns+1], adjncy[*]) form and load the Graph object. note, pointers to the lists are set, no new storage is allocated for the adjacency lists. however, during the ordering process each adjacency lists may be shuffled. g -- pointer to Graph object, must be initialized with nvtx = neqns neqns -- # of equations offsets -- offsets vector adjncy -- big adjacency vector note, the adjacency for list v is found in adjncy[offsets[v]:offsets[v+1]-1] also note, offsets[] and adjncy[] must be zero based, if (offsets,adjncy) come from a harwell-boeing file, they use the fortran numbering, so each value must be decremented to conform with C's zero based numbering created -- 96oct24, cca ------------------------------------------------------------------- */ void Graph_setListsFromOffsets ( Graph *g, int neqns, int offsets[], int adjncy[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in wirebasket.c --------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- on input stages[v] = 0 --> vertex is in a domain stages[v] > 0 --> vertex is in the multisector this remains true on output, but the stage of a multisector vertex is equal to the number of different domains that are found within radius edges from itself created -- 97jul30, cca ----------------------------------------------------------- */ void Graph_wirebasketStages ( Graph *graph, IV *stagesIV, int radius ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in IO.c ----------------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------- purpose -- to read in a Graph object from a file input -- fn -- filename, must be *.graphb or *.graphf return value -- 1 if success, 0 if failure created -- 95sep29, cca ------------------------------------------------- */ int Graph_readFromFile ( Graph *graph, char *fn ) ; /* ------------------------------------------------------- purpose -- to read in a Graph object from a CHACO file input -- fn -- filename return value -- 1 if success, 0 if failure created -- 98sep20, jjs -------------------------------------------------------- */ int Graph_readFromChacoFile ( Graph *graph, char *fn ) ; /* -------------------------------------------------------- purpose -- to read a Graph object from a formatted file return value -- 1 if success, 0 if failure created -- 95sep29, cca -------------------------------------------------------- */ int Graph_readFromFormattedFile ( Graph *graph, FILE *fp ) ; /* ---------------------------------------------------- purpose -- to read a Graph object from a binary file return value -- 1 if success, 0 if failure created -- 95sep29, cca ---------------------------------------------------- */ int Graph_readFromBinaryFile ( Graph *graph, FILE *fp ) ; /* -------------------------------------------- purpose -- to write a Graph object to a file input -- fn -- filename *.graphb -- binary *.graphf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95sep29, cca -------------------------------------------- */ int Graph_writeToFile ( Graph *graph, char *fn ) ; /* ------------------------------------------------------ purpose -- to write a Graph object to a formatted file return value -- 1 if success, 0 otherwise created -- 95sep29, cca ------------------------------------------------------ */ int Graph_writeToFormattedFile ( Graph *graph, FILE *fp ) ; /* --------------------------------------------------- purpose -- to write a Graph object to a binary file return value -- 1 if success, 0 otherwise created -- 95sep29, cca --------------------------------------------------- */ int Graph_writeToBinaryFile ( Graph *graph, FILE *fp ) ; /* ------------------------------------------------- purpose -- to write a Graph object for a human eye return value -- 1 if success, 0 otherwise created -- 95sep29, cca ------------------------------------------------- */ int Graph_writeForHumanEye ( Graph *graph, FILE *fp ) ; /* ----------------------------------------------------------- purpose -- to write out the statistics for the Graph object return value -- 1 if success, 0 otherwise created -- 95sep29, cca ----------------------------------------------------------- */ int Graph_writeStats ( Graph *graph, FILE *fp ) ; /* --------------------------------- write out a graph to a METIS file created -- 95oct18, cca --------------------------------- */ int Graph_writeToMetisFile ( Graph *g, FILE *fp ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- functions in getTree.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------- purpose -- to extract a maximal tree from a graph on input, if mark[v] == 'N' then v is eligible to be placed in the tree endif i.e., mark[] serves as a mask vector on return, if ( mark[v] == 'Y' ) then v is in the tree, parent of v = par[v] else mark[v] = 'N', not in tree endif created -- 98apr10, cca ------------------------------------------------- */ void Graph_getTree ( Graph *graph, int par[], char mark[], int seed, int msglvl, FILE *msgFile ) ; /* -------------------------------------------------------- purpose -- to extract a maximal nlevel-tree from a graph (a vertex v can have an edge in the graph with itself and any ancestor within nlevel levels in the tree.) on input, if mark[v] == 'N' then v is eligible to be placed in the tree endif i.e., mark[] serves as a mask vector on return, if ( mark[v] == 'Y' ) then v is in the tree, parent of v = par[v] else mark[v] = 'N', not in tree endif created -- 98apr10, cca -------------------------------------------------------- */ void Graph_getTree2 ( Graph *graph, int nlevel, int par[], char mark[], int seed, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ tIV -- IV object to hold order of search parIV -- IV object to hold parent vector return value -- depth of the search tree created -- 96jul13, cca ----------------------------------------------------------- */ int Graph_BFS ( Graph *graph, int v, IV *levelsIV, IV *listIV, IV *parIV ) ; /* ----Graph/makefile010064400020550007177000000002230663622360300146350ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean Graph/src/makefile010064400020550007177000000011340663602426600154320ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Graph $(OBJ).a : \ $(OBJ).a(IO.o) \ $(OBJ).a(basics.o) \ $(OBJ).a(compress.o) \ $(OBJ).a(equivMap.o) \ $(OBJ).a(expand.o) \ $(OBJ).a(fillFromOffsets.o) \ $(OBJ).a(init.o) \ $(OBJ).a(setListsFromOffsets.o) \ $(OBJ).a(util.o) \ $(OBJ).a(wirebasket.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG Graph/src/makeGlobalLib010064400020550007177000000007770660026103200163370ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Graph SRC = IO.c \ basics.c \ compress.c \ equivMap.c \ expand.c \ fillFromOffsets.c \ init.c \ setListsFromOffsets.c \ util.c \ wirebasket.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Graph/src/IO.c010064400020550007177000000757660665017540000144240ustar00clevecompmath00000400000006/* IO.c */ #include "../Graph.h" #define BUFLEN 100000 static const char *suffixb = ".graphb" ; static const char *suffixf = ".graphf" ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to read in a Graph object from a file input -- fn -- filename, must be *.graphb or *.graphf return value -- 1 if success, 0 if failure created -- 95sep29, cca ------------------------------------------------- */ int Graph_readFromFile ( Graph *graph, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( graph == NULL || fn == NULL ) { fprintf(stderr, "\n error in Graph_readFromFile(%p,%s)" "\n bad input\n", graph, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in Graph_readFromFile(%p,%s)" "\n unable to open file %s", graph, fn, fn) ; rc = 0 ; } else { rc = Graph_readFromBinaryFile(graph, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in Graph_readFromFile(%p,%s)" "\n unable to open file %s", graph, fn, fn) ; rc = 0 ; } else { rc = Graph_readFromFormattedFile(graph, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in Graph_readFromFile(%p,%s)" "\n bad Graph file name %s," "\n must end in %s (binary) or %s (formatted)\n", graph, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in Graph_readFromFile(%p,%s)" "\n bad Graph file name %s," "\n must end in %s (binary) or %s (formatted)\n", graph, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to read in a Graph object from a CHACO file input -- fn -- filename return value -- 1 if success, 0 if failure created -- 98sep20, jjs -------------------------------------------------------- */ int Graph_readFromChacoFile ( Graph *graph, char *fn ) { char *rc ; FILE *fp; int nvtx, nedges, format; char string[BUFLEN], *s1, *s2; int k, v, vsize, w, vwghts, ewghts; int *adjncy, *weights, *vwghtsINT; IVL *adjIVL, *ewghtIVL; /* --------------- check the input --------------- */ if ((graph == NULL) || (fn == NULL)) { fprintf(stderr, "\n error in Graph_readFromFile(%p,%s)" "\n bad input\n", graph, fn); return(0); } /* --------------------- clear the data fields --------------------- */ Graph_clearData(graph); /* ---------------------------------------------- open file and read in nvtx, nedges, and format ---------------------------------------------- */ if ((fp = fopen(fn, "r")) == (FILE*)NULL) { fprintf(stderr, "\n error in Graph_readFromChacoFile(%p,%s)" "\n unable to open file %s", graph, fn, fn); return(0); } /* ------------- skip comments ------------- */ do { rc = fgets(string, BUFLEN, fp) ; if ( rc == NULL ) { fprintf(stderr, "\n error in Graph_readFromChacoFile()" "\n error skipping comments in file %s\n", fn) ; return(0) ; } } while ( string[0] == '%'); /* ------------------------------------------------- read in # vertices, # edges and (optional) format ------------------------------------------------- */ format = 0; if (sscanf(string, "%d %d %d", &nvtx, &nedges, &format) < 2) { fprintf(stderr, "\n error in Graph_readFromChacoFile(%p,%s)" "\n unable to read header of file %s", graph, fn, fn); return(0); } ewghts = ((format % 10) > 0); vwghts = (((format / 10) % 10) > 0); if (format >= 100) { fprintf(stderr, "\n error in Graph_readFromChacoFile(%p,%s)" "\n unknown format", graph, fn); return(0); } /* ------------------------------------------------------------------ initialize vector(s) to hold adjacency and (optional) edge weights ------------------------------------------------------------------ */ adjncy = IVinit(nvtx, -1) ; if ( ewghts ) { weights = IVinit(nvtx, -1) ; } else { weights = NULL ; } /* --------------------------- initialize the Graph object --------------------------- */ nedges *= 2; nedges += nvtx; Graph_init1(graph, 2*ewghts+vwghts, nvtx, 0, nedges, IVL_CHUNKED, IVL_CHUNKED); adjIVL = graph->adjIVL; if (ewghts) { ewghtIVL = graph->ewghtIVL; weights[0] = 0; /* self loops have no weight */ } if (vwghts) vwghtsINT = graph->vwghts; /* --------------------------- read in all adjacency lists --------------------------- */ k = 0; for (v = 0; v < nvtx; v++) { /* ------------- skip comments ------------- */ do { rc = fgets(string, BUFLEN, fp); if ( rc == NULL ) { fprintf(stderr, "\n error in Graph_readFromChacoFile()" "\n error reading adjacency for vertex %d in file %s\n", v, fn) ; IVfree(adjncy) ; if ( weights != NULL ) { IVfree(weights) ; } return(0) ; } } while ( string[0] == '%'); /* ------------------------- check for buffer overflow ------------------------- */ if (strlen(string) == BUFLEN-1) { fprintf(stderr, "\n error in Graph_readFromChacoFile(%p,%s)" "\n unable to read adjacency lists of file %s (line " "buffer too small)\n", graph, fn, fn); IVfree(adjncy) ; if ( weights != NULL ) { IVfree(weights) ; } return(0); } /* ---------------------------------------------- read in (optional) vertex weight, adjacent vertices, and (optional) edge weights ---------------------------------------------- */ s1 = string; if (vwghts) vwghtsINT[v] = (int)strtol(string, &s1, 10); adjncy[0] = v; /* insert self loop needed by spooles */ if ( ewghts ) { weights[0] = 0; } vsize = 1; while ((w = (int)strtol(s1, &s2, 10)) > 0) { adjncy[vsize] = --w; /* node numbering starts with 0 */ s1 = s2; if (ewghts) { weights[vsize] = (int)strtol(s1, &s2, 10); s1 = s2; } vsize++; } /* --------------------------------- sort the lists in ascending order --------------------------------- */ if ( ewghts ) { IV2qsortUp(vsize, adjncy, weights) ; } else { IVqsortUp(vsize, adjncy) ; } /* -------------------------------- set the lists in the IVL objects -------------------------------- */ IVL_setList(adjIVL, v, vsize, adjncy); if (ewghts) IVL_setList(ewghtIVL, v, vsize, weights); k += vsize; } /* ----------------------------------- close the file and do a final check ----------------------------------- */ fclose(fp); /* ------------------------ free the working storage ------------------------ */ IVfree(adjncy) ; if ( weights != NULL ) { IVfree(weights) ; } /* ---------------- check for errors ---------------- */ if ((k != nedges) || (v != nvtx)) { fprintf(stderr, "\n error in Graph_readFromChacoFile()" "\n number of nodes/edges does not match with header of %s" "\n k %d, nedges %d, v %d, nvtx %d\n", fn, k, nedges, v, nvtx); return(0); } return(1); } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to read a Graph object from a formatted file return value -- 1 if success, 0 if failure created -- 95sep29, cca -------------------------------------------------------- */ int Graph_readFromFormattedFile ( Graph *graph, FILE *fp ) { int nedges, nvbnd, nvtx, rc, totewght, totvwght, type ; int itemp[6] ; int *vwghts ; IVL *adjIVL, *ewghtIVL ; /* --------------- check the input --------------- */ if ( graph == NULL || fp == NULL ) { fprintf(stderr, "\n error in Graph_readFromFormattedFile(%p,%p)" "\n bad input\n", graph, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ Graph_clearData(graph) ; /* --------------------------------------------- read in the six scalar parameters type, nvtx, nvbnd, nedges, totvwght, totewght --------------------------------------------- */ if ( (rc = IVfscanf(fp, 6, itemp)) != 6 ) { fprintf(stderr, "\n error in Graph_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", graph, fp, rc, 6) ; return(0) ; } type = itemp[0] ; nvtx = itemp[1] ; nvbnd = itemp[2] ; nedges = itemp[3] ; totvwght = itemp[4] ; totewght = itemp[5] ; /* -------------------------------------------------- create the adjIVL IVL object, set its type to IVL_CHUNKED, then read in its data -------------------------------------------------- */ adjIVL = IVL_new() ; IVL_setDefaultFields(adjIVL) ; adjIVL->type = IVL_CHUNKED ; rc = IVL_readFromFormattedFile(adjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n error in Graph_readFromFormattedFile(%p,%p)" "\n trying to read in adjIVL" "\n return code %d from IVL_readFormattedFile(%p,%p)", graph, fp, rc, adjIVL, fp) ; return(0) ; } if ( type % 2 == 1 ) { int nvtot, wght ; /* -------------------------- vertex weights are present -------------------------- */ nvtot = nvtx + nvbnd ; vwghts = IVinit2(nvtot) ; if ( (rc = IVfscanf(fp, nvtot, vwghts)) != nvtot ) { fprintf(stderr, "\n error in Graph_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", graph, fp, rc, nvtot) ; return(0) ; } wght = IVsum(nvtot, vwghts) ; if ( wght != totvwght ) { fprintf(stderr, "\n error in Graph_readFromFormattedFile(%p,%p)" "\n totvwght = %d, IVsum(vwghts) = %d\n", graph, fp, totvwght, wght) ; return(0) ; } } else { vwghts = NULL ; } if ( type >= 2 ) { int wght ; /* ----------------------------------------------------- edge weights are present, create the ewghtIVL object, set its type to IVL_CHUNKED, then read in its data ----------------------------------------------------- */ ewghtIVL = IVL_new() ; IVL_setDefaultFields(ewghtIVL) ; ewghtIVL->type = IVL_CHUNKED ; rc = IVL_readFromFormattedFile(ewghtIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n error in Graph_readFromFormattedFile(%p,%p)" "\n trying to read in ewghtIVL" "\n return code %d from IVL_readFormattedFile(%p,%p)", graph, fp, rc, ewghtIVL, fp) ; return(0) ; } wght = IVL_sum(ewghtIVL) ; if ( wght != totewght ) { fprintf(stderr, "\n error in Graph_readFromFormattedFile(%p,%p)" "\n totewght = %d, IVL_sum(ewghtIVL) = %d\n", graph, fp, totewght, wght) ; return(0) ; } } else { ewghtIVL = NULL ; } /* --------------------- initialize the object --------------------- */ Graph_init2(graph, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to read a Graph object from a binary file return value -- 1 if success, 0 if failure created -- 95sep29, cca ---------------------------------------------------- */ int Graph_readFromBinaryFile ( Graph *graph, FILE *fp ) { int nedges, nvbnd, nvtx, rc, totewght, totvwght, type ; int itemp[6] ; int *vwghts ; IVL *adjIVL, *ewghtIVL ; /* --------------- check the input --------------- */ if ( graph == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Graph_readFromBinaryFile(%p,%p)" "\n bad input\n", graph, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ Graph_clearData(graph) ; /* --------------------------------------------- read in the six scalar parameters type, nvtx, nvbnd, nedges, totvwght, totewght --------------------------------------------- */ if ( (rc = fread((void *) itemp, sizeof(int), 6, fp)) != 6 ) { fprintf(stderr, "\n error in Graph_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", graph, fp, rc, 6) ; return(0) ; } type = itemp[0] ; nvtx = itemp[1] ; nvbnd = itemp[2] ; nedges = itemp[3] ; totvwght = itemp[4] ; totewght = itemp[5] ; /* -------------------------------------------------- create the adjIVL IVL object, set its type to IVL_CHUNKED, then read in its data -------------------------------------------------- */ adjIVL = IVL_new() ; IVL_setDefaultFields(adjIVL) ; adjIVL->type = IVL_CHUNKED ; rc = IVL_readFromBinaryFile(adjIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n error in Graph_readFromBinaryFile(%p,%p)" "\n trying to read in adjIVL" "\n return code %d from IVL_readBinaryFile(%p,%p)", graph, fp, rc, adjIVL, fp) ; return(0) ; } if ( type % 2 == 1 ) { int nvtot, wght ; /* -------------------------- vertex weights are present -------------------------- */ nvtot = nvtx + nvbnd ; vwghts = IVinit2(nvtot) ; if ( (rc = fread((void *) vwghts, sizeof(int), nvtot, fp)) != nvtot){ fprintf(stderr, "\n error in Graph_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", graph, fp, rc, nvtx+nvbnd) ; return(0) ; } wght = IVsum(nvtot, vwghts) ; if ( wght != totvwght ) { fprintf(stderr, "\n error in Graph_readFromBinaryFile(%p,%p)" "\n totvwght = %d, IVsum(vwghts) = %d\n", graph, fp, totvwght, wght) ; return(0) ; } } else { vwghts = NULL ; } if ( type > 2 ) { int wght ; /* ----------------------------------------------------- edge weights are present, create the ewghtIVL object, set its type to IVL_CHUNKED, then read in its data ----------------------------------------------------- */ ewghtIVL = IVL_new() ; IVL_setDefaultFields(ewghtIVL) ; ewghtIVL->type = IVL_CHUNKED ; rc = IVL_readFromBinaryFile(ewghtIVL, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n error in Graph_readFromBinaryFile(%p,%p)" "\n trying to read in ewghtIVL" "\n return code %d from IVL_readBinaryFile(%p,%p)", graph, fp, rc, ewghtIVL, fp) ; return(0) ; } wght = IVL_sum(ewghtIVL) ; if ( wght != totewght ) { fprintf(stderr, "\n error in Graph_readFromBinaryFile(%p,%p)" "\n totewght = %d, IVL_sum(ewghtIVL) = %d\n", graph, fp, totewght, wght) ; return(0) ; } } else { ewghtIVL = NULL ; } /* --------------------- initialize the object --------------------- */ Graph_init2(graph, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL) ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to write a Graph object to a file input -- fn -- filename *.graphb -- binary *.graphf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95sep29, cca -------------------------------------------- */ int Graph_writeToFile ( Graph *graph, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( graph == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in Graph_writeToFile(%p,%s)" "\n bad input\n", graph, fn) ; return(0) ; } if ( graph->type < 0 || 3 < graph->type ) { fprintf(stderr, "\n fatal error in Graph_writeToFile(%p,%s)" "\n bad type = %d", graph, fn, graph->type) ; return(0) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in Graph_writeToFile(%p,%s)" "\n unable to open file %s", graph, fn, fn) ; rc = 0 ; } else { rc = Graph_writeToBinaryFile(graph, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in Graph_writeToFile(%p,%s)" "\n unable to open file %s", graph, fn, fn) ; rc = 0 ; } else { rc = Graph_writeToFormattedFile(graph, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in Graph_writeToFile(%p,%s)" "\n unable to open file %s", graph, fn, fn) ; rc = 0 ; } else { rc = Graph_writeForHumanEye(graph, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in Graph_writeToFile(%p,%s)" "\n unable to open file %s", graph, fn, fn) ; rc = 0 ; } else { rc = Graph_writeForHumanEye(graph, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to write a Graph object to a formatted file return value -- 1 if success, 0 otherwise created -- 95sep29, cca ------------------------------------------------------ */ int Graph_writeToFormattedFile ( Graph *graph, FILE *fp ) { int ierr, rc ; /* --------------- check the input --------------- */ if ( graph == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Graph_writeToFormattedFile(%p,%p)" "\n bad input\n", graph, fp) ; return(0) ; } if ( graph->type < 0 || 3 < graph->type ) { fprintf(stderr, "\n fatal error in Graph_writeToFormattedFile(%p,%p)" "\n bad type = %d", graph, fp, graph->type) ; return(0) ; } /* ----------------------------------- write out the six scalar parameters ----------------------------------- */ rc = fprintf(fp, "\n %d %d %d %d %d %d", graph->type, graph->nvtx, graph->nvbnd, graph->nedges, graph->totvwght, graph->totewght) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Graph_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", graph, fp, rc) ; return(0) ; } /* --------------------------------- write out the adjacency structure --------------------------------- */ rc = IVL_writeToFormattedFile(graph->adjIVL, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Graph_writeToFormattedFile(%p,%p)" "\n rc = %d, return from IVL_writeToFormattedFile(%p,%p)" "\n while attempting to write out adjIVL\n", graph, fp, rc, graph->adjIVL, fp) ; return(0) ; } /* ----------------------------------------- write out the vwghts[] vector, if present ----------------------------------------- */ if ( graph->type % 2 == 1 ) { if ( graph->vwghts == NULL ) { fprintf(stderr, "\n fatal error in Graph_writeToFormattedFile(%p,%p)" "\n graph->type = %d, graph->vwghts == NULL\n", graph, fp, graph->type) ; return(0) ; } IVfp80(fp, graph->nvtx+graph->nvbnd, graph->vwghts, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in Graph_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from vwghts[] IVfp80\n", graph, fp, ierr) ; return(0) ; } } /* ------------------------------------- write out the edge weights IVL object ------------------------------------- */ if ( graph->type >= 2 ) { if ( graph->ewghtIVL == NULL ) { fprintf(stderr, "\n fatal error in Graph_writeToFormattedFile(%p,%p)" "\n graph->type = %d, graph->ewghtIVL == NULL\n", graph, fp, graph->type) ; return(0) ; } rc = IVL_writeToFormattedFile(graph->ewghtIVL, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Graph_writeToFormattedFile(%p,%p)" "\n rc = %d, return from IVL_writeToFormattedFile(%p,%p)" "\n while attempting to write out ewghtIVL\n", graph, fp, rc, graph->ewghtIVL, fp) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to write a Graph object to a binary file return value -- 1 if success, 0 otherwise created -- 95sep29, cca --------------------------------------------------- */ int Graph_writeToBinaryFile ( Graph *graph, FILE *fp ) { int rc ; int itemp[6] ; /* --------------- check the input --------------- */ if ( graph == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Graph_writeToBinaryFile(%p,%p)" "\n bad input\n", graph, fp) ; return(0) ; } if ( graph->type < 0 || 3 < graph->type ) { fprintf(stderr, "\n fatal error in Graph_writeToBinaryFile(%p,%p)" "\n bad type = %d", graph, fp, graph->type) ; return(0) ; } /* ----------------------------------- write out the six scalar parameters ----------------------------------- */ itemp[0] = graph->type ; itemp[1] = graph->nvtx ; itemp[2] = graph->nvbnd ; itemp[3] = graph->nedges ; itemp[4] = graph->totvwght ; itemp[5] = graph->totewght ; rc = fwrite((void *) itemp, sizeof(int), 6, fp) ; if ( rc != 6 ) { fprintf(stderr, "\n error in Graph_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", graph, fp, rc, 6) ; return(0) ; } /* --------------------------------- write out the adjacency structure --------------------------------- */ rc = IVL_writeToBinaryFile(graph->adjIVL, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Graph_writeToBinaryFile(%p,%p)" "\n rc = %d, return from IVL_writeToBinaryFile(%p,%p)" "\n while attempting to write out adjIVL\n", graph, fp, rc, graph->adjIVL, fp) ; return(0) ; } /* ----------------------------------------- write out the vwghts[] vector, if present ----------------------------------------- */ if ( graph->type % 2 == 1 ) { if ( graph->vwghts == NULL ) { fprintf(stderr, "\n fatal error in Graph_writeToBinaryFile(%p,%p)" "\n graph->type = %d, graph->vwghts == NULL\n", graph, fp, graph->type) ; return(0) ; } rc = fwrite((void *) graph->vwghts, sizeof(int), graph->nvtx + graph->nvbnd, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Graph_writeToBinaryFile(%p,%p)" "\n rc = %d, return from vwghts[] fwrite\n", graph, fp, rc) ; return(0) ; } } /* ------------------------------------- write out the edge weights IVL object ------------------------------------- */ if ( graph->type >= 2 ) { if ( graph->ewghtIVL == NULL ) { fprintf(stderr, "\n fatal error in Graph_writeToBinaryFile(%p,%p)" "\n graph->type = %d, graph->ewghtIVL == NULL\n", graph, fp, graph->type) ; return(0) ; } rc = IVL_writeToBinaryFile(graph->ewghtIVL, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Graph_writeToBinaryFile(%p,%p)" "\n rc = %d, return from IVL_writeToBinaryFile(%p,%p)" "\n while attempting to write out ewghtIVL\n", graph, fp, rc, graph->ewghtIVL, fp) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to write a Graph object for a human eye return value -- 1 if success, 0 otherwise created -- 95sep29, cca ------------------------------------------------- */ int Graph_writeForHumanEye ( Graph *graph, FILE *fp ) { int ierr, rc ; if ( graph == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Graph_writeForHumanEye(%p,%p)" "\n bad input\n", graph, fp) ; exit(-1) ; } /* ------------------------ write out the statistics ------------------------ */ if ( (rc = Graph_writeStats(graph, fp)) == 0 ) { fprintf(stderr, "\n fatal error in Graph_writeForHumanEye(%p,%p)" "\n rc = %d, return from Graph_writeStats(%p,%p)\n", graph, fp, rc, graph, fp) ; return(0) ; } if ( graph->adjIVL != NULL ) { /* ---------------------------------- write out the adjacency IVL object ---------------------------------- */ fprintf(fp, "\n\n adjacency IVL object") ; rc = IVL_writeForHumanEye(graph->adjIVL, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Graph_writeForHumanEye(%p,%p)" "\n rc = %d, return from IVL_writeForHumanEye(%p,%p)" "\n while attempting to write out adjIVL\n", graph, fp, rc, graph->adjIVL, fp) ; return(0) ; } } /* ---------------------------------------------- write out the vertex weights vector if present ---------------------------------------------- */ if ( graph->type % 2 == 1 ) { if ( graph->vwghts == NULL ) { fprintf(stderr, "\n fatal error in Graph_writeForHumanEye(%p,%p)" "\n graph->type = %d, graph->vwghts == NULL\n", graph, fp, graph->type) ; return(0) ; } fprintf(fp, "\n\n vertex weights ") ; IVfp80(fp, graph->nvtx + graph->nvbnd, graph->vwghts, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in Graph_writeForHumanEye(%p,%p)" "\n ierr = %d, return from vwghts[] IVfp80\n", graph, fp, ierr) ; return(0) ; } } /* ------------------------------------------------ write out the edge weight IVL object, if present ------------------------------------------------ */ if ( graph->type >= 2 ) { if ( graph->ewghtIVL == NULL ) { fprintf(stderr, "\n fatal error in Graph_writeForHumanEye(%p,%p)" "\n graph->type = %d, graph->ewghtIVL == NULL\n", graph, fp, graph->type) ; return(0) ; } fprintf(fp, "\n\n edge weights IVL object") ; rc = IVL_writeForHumanEye(graph->ewghtIVL, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Graph_writeForHumanEye(%p,%p)" "\n rc = %d, return from IVL_writeForHumanEye(%p,%p)" "\n while attempting to write out ewghtIVL\n", graph, fp, rc, graph->ewghtIVL, fp) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to write out the statistics for the Graph object return value -- 1 if success, 0 otherwise created -- 95sep29, cca ----------------------------------------------------------- */ int Graph_writeStats ( Graph *graph, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( graph == NULL || fp == NULL ) { fprintf(stderr, "\n error in Graph_writeStats(%p,%p)" "\n bad input\n", graph, fp) ; exit(-1) ; } switch ( graph->type ) { case 0 : rc = fprintf(fp, "\n Graph : unweighted graph object :") ; break ; case 1 : rc = fprintf(fp, "\n Graph : vertices weighted graph object :") ; break ; case 2 : rc = fprintf(fp, "\n Graph : edges weighted graph object :") ; break ; case 3 : rc = fprintf(fp, "\n Graph : vertices and edges weighted graph object :") ; break ; default : fprintf(stderr, "\n fatal error in Graph_writeStats(%p,%p)" "\n invalid graph->type = %d\n", graph, fp, graph->type) ; return(0) ; } if ( rc < 0 ) { goto IO_error ; } fflush(fp) ; rc = fprintf(fp, "\n %d internal vertices, %d boundary vertices, %d edges", graph->nvtx, graph->nvbnd, graph->nedges) ; if ( rc < 0 ) { goto IO_error ; } fflush(fp) ; rc = fprintf(fp, "\n %d internal vertex weight, %d boundary vertex weight", (graph->vwghts != NULL) ? IVsum(graph->nvtx, graph->vwghts) : graph->nvtx, (graph->vwghts != NULL) ? IVsum(graph->nvbnd, graph->vwghts + graph->nvtx) : graph->nvbnd) ; if ( rc < 0 ) { goto IO_error ; } if ( graph->type >= 2 ) { rc = fprintf(fp, "\n %d total edge weight", graph->totewght) ; } if ( rc < 0 ) { goto IO_error ; } return(1) ; IO_error : fprintf(stderr, "\n fatal error in Graph_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", graph, fp, rc) ; return(0) ; } /*--------------------------------------------------------------------*/ /* --------------------------------- write out a graph to a METIS file created -- 95oct18, cca --------------------------------- */ int Graph_writeToMetisFile ( Graph *g, FILE *fp ) { int ii, nedge, nvtx, v, vsize, w ; int *vewghts, *vadj ; /* --------------- check the input --------------- */ if ( g == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Graph_writeToMetisFile(%p,%p)" "\n bad input\n", g, fp) ; exit(-1) ; } nvtx = g->nvtx ; nedge = (g->nedges - nvtx)/2 ; switch ( g->type ) { case 0 : fprintf(fp, " %d %d ", nvtx, nedge) ; for ( v = 0 ; v < nvtx ; v++ ) { fprintf(fp, "\n ") ; Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w != v && w < nvtx ) { fprintf(fp, " %d", w + 1) ; } } } break ; case 1 : fprintf(fp, " %d %d 10", nvtx, nedge) ; for ( v = 0 ; v < nvtx ; v++ ) { fprintf(fp, "\n %d", g->vwghts[v]) ; Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w != v && w < nvtx ) { fprintf(fp, " %d", w + 1) ; } } } break ; case 2 : fprintf(fp, " %d %d 1", nvtx, nedge) ; for ( v = 0 ; v < nvtx ; v++ ) { fprintf(fp, "\n") ; Graph_adjAndEweights(g, v, &vsize, &vadj, &vewghts) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w != v && w < nvtx ) { fprintf(fp, " %d %d", w + 1, vewghts[ii]) ; } } } break ; case 3 : fprintf(fp, " %d %d 11", nvtx, nedge) ; for ( v = 0 ; v < nvtx ; v++ ) { fprintf(fp, "\n %d", g->vwghts[v]) ; Graph_adjAndEweights(g, v, &vsize, &vadj, &vewghts) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w != v && w < nvtx ) { fprintf(fp, " %d %d", w + 1, vewghts[ii]) ; } } } break ; } return(1) ; } /*--------------------------------------------------------------------*/ raph *gGraph/src/basics.c010064400020550007177000000056560665314274300153570ustar00clevecompmath00000400000006/* basics.c */ #include "../Graph.h" #define MYTRACE 0 #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- create and return a new Graph object created -- 95sep27, cca ----------------------------------------------- */ Graph * Graph_new ( void ) { Graph *g ; #if MYTRACE > 0 fprintf(stdout, "\n just inside Graph_new()") ; fflush(stdout) ; #endif ALLOCATE(g, struct _Graph, 1) ; Graph_setDefaultFields(g) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving Graph_new()") ; fflush(stdout) ; #endif return(g) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- set the default fields for the Graph object created -- 95sep27, cca ------------------------------------------------------ */ void Graph_setDefaultFields ( Graph *g ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside Graph_setDefaultFields(%p)", g) ; fflush(stdout) ; #endif if ( g == NULL ) { fprintf(stderr, "\n fatal error in Graph_setDefaultFields(%p)" "\n graph is NULL\n", g) ; exit(-1) ; } g->type = 0 ; g->nvtx = 0 ; g->nvbnd = 0 ; g->nedges = 0 ; g->totvwght = 0 ; g->totewght = 0 ; g->adjIVL = NULL ; g->vwghts = NULL ; g->ewghtIVL = NULL ; #if MYTRACE > 0 fprintf(stdout, "\n leaving Graph_setDefaultFields(%p)", g) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- clear the data fields created -- 95sep27, cca -------------------------------- */ void Graph_clearData ( Graph *g ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside Graph_clearData(%p)", g) ; fflush(stdout) ; #endif if ( g == NULL ) { fprintf(stderr, "\n fatal error in Graph_clearData(%p)" "\n graph is NULL\n", g) ; exit(-1) ; } if ( g->adjIVL != NULL ) { IVL_free(g->adjIVL) ; } if ( g->vwghts != NULL ) { IVfree(g->vwghts) ; } if ( g->ewghtIVL != NULL ) { IVL_free(g->ewghtIVL) ; } Graph_setDefaultFields(g) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving Graph_clearData(%p)", g) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- free the Graph object created -- 95sep27, cca -------------------------------- */ void Graph_free ( Graph *g ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside Graph_free(%p)", g) ; fflush(stdout) ; #endif if ( g == NULL ) { fprintf(stderr, "\n fatal error in Graph_free(%p)" "\n graph is NULL\n", g) ; exit(-1) ; } Graph_clearData(g) ; FREE(g) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving Graph_free(%p)", g) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ Graph/src/compress.c010064400020550007177000000222510653410610400157210ustar00clevecompmath00000400000006/* compress.c */ #include "../Graph.h" #define MYDEBUG 0 #define MYTRACE 0 /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- given a graph g and a fine-to-coarse map vector *mapIV, return a compressed graph with type coarseType. note, the compressed graph will have no trivial boundary even if the original graph did have a boundary. created -- 96mar02, cca --------------------------------------------------------------- */ Graph * Graph_compress2 ( Graph *g, IV *mapIV, int coarseType ) { /* ------------------------------------------- check input and get dimensions and pointers ------------------------------------------- */ if ( g == NULL || mapIV == NULL || g->nvtx != IV_size(mapIV) || coarseType < 0 || 3 < coarseType ) { fprintf(stderr, "\n fatal error in Graph_compress2(%p,%p,%d)" "\n bad input\n", g, mapIV, coarseType) ; if ( g != NULL ) { Graph_writeStats(g, stderr) ; } if ( mapIV != NULL ) { IV_writeStats(mapIV, stderr) ; } exit(-1) ; } return(Graph_compress(g, IV_entries(mapIV), coarseType)) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- given a graph g and a fine-to-coarse map vector cmap[], return a compressed graph with type coarseType. note, the compressed graph will have no trivial boundary even if the original graph did have a boundary. created -- 95sep29, cca --------------------------------------------------------------- */ Graph * Graph_compress ( Graph *g, int cmap[], int coarseType ) { Graph *g2 ; int ierr, ii, j, jj, jsize, J, Jsize, k, K, ncvtx, nvtx, wght ; int *head, *indices, *jind, *Jind, *jwghts, *Jwghts, *link, *mark, *vwghts, *Vwghts ; IVL *adjIVL, *AdjIVL, *ewghtIVL, *EwghtIVL ; #if MYTRACE > 0 fprintf(stdout, "\n just inside Graph_compress(%p,%p,%d)", g, cmap, coarseType) ; fflush(stdout) ; #endif /* ------------------------------------------- check input and get dimensions and pointers ------------------------------------------- */ if ( g == NULL || cmap == NULL || coarseType < 0 || 3 < coarseType ) { fprintf(stderr, "\n fatal error in Graph_compress(%p,%p,%d)" "\n bad input\n", g, cmap, coarseType) ; exit(-1) ; } if ( (nvtx = g->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in Graph_compress(%p,%p,%d)" "\n nvtx = %d\n", g, cmap, coarseType, nvtx) ; exit(-1) ; } if ( (adjIVL = g->adjIVL) == NULL ) { fprintf(stderr, "\n fatal error in Graph_compress(%p,%p,%d)" "\n adjIVL is NULL\n", g, cmap, coarseType) ; exit(-1) ; } if ( g->type % 2 == 1 && (vwghts = g->vwghts) == NULL ) { fprintf(stderr, "\n fatal error in Graph_compress(%p,%p,%d)" "\n g->type = %d and g->vwghts is NULL\n", g, cmap, coarseType, g->type) ; exit(-1) ; } if ( g->type >= 2 && (ewghtIVL = g->ewghtIVL) == NULL ) { fprintf(stderr, "\n fatal error in Graph_compress(%p,%p,%d)" "\n g->type = %d and g->ewghtIVL is NULL\n", g, cmap, coarseType, g->type) ; exit(-1) ; } if ( IVmin(nvtx, cmap, &j) < 0 ) { fprintf(stderr, "\n fatal error in Graph_compress(%p,%p,%d)" "\n IVmin(cmap) = %d\n", g, cmap, coarseType, IVmin(nvtx, cmap, &j)) ; exit(-1) ; } ncvtx = 1 + IVmax(nvtx, cmap, &j) ; #if MYDEBUG > 0 fprintf(stdout, "\n ncvtx = %d", ncvtx) ; fflush(stdout) ; #endif /* ---------------------------------- initialize the coarse graph object ---------------------------------- */ g2 = Graph_new() ; Graph_init1(g2, coarseType, ncvtx, 0, 0, IVL_CHUNKED, IVL_CHUNKED) ; if ( (AdjIVL = g2->adjIVL) == NULL ) { fprintf(stderr, "\n fatal error in Graph_compress(%p,%p,%d)" "\n AdjIVL is NULL\n", g, cmap, coarseType) ; exit(-1) ; } if ( g2->type % 2 == 1 && (Vwghts = g2->vwghts) == NULL ) { fprintf(stderr, "\n fatal error in Graph_compress(%p,%p,%d)" "\n g2->type = %d and g2->vwghts is NULL\n", g, cmap, coarseType, g2->type) ; exit(-1) ; } if ( g2->type >= 2 && (EwghtIVL = g2->ewghtIVL) == NULL ) { fprintf(stderr, "\n fatal error in Graph_compress(%p,%p,%d)" "\n g2->type = %d and g2->ewghtIVL is NULL\n", g, cmap, coarseType, g2->type) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n after initializing the coarse graph object") ; Graph_writeStats(g2, stdout) ; fflush(stdout) ; #endif /* -------------------------------- set up the head and link vectors -------------------------------- */ head = IVinit(ncvtx, -1) ; link = IVinit(nvtx, -1) ; for ( j = 0 ; j < nvtx ; j++ ) { J = cmap[j] ; link[j] = head[J] ; head[J] = j ; } /* ------------------------------------------------ fill the adjacency structure of the coarse graph ------------------------------------------------ */ indices = IVinit2(ncvtx) ; mark = IVinit(ncvtx, -1) ; for ( J = 0 ; J < ncvtx ; J++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n checking out J = %d", J) ; #endif Jsize = 0 ; for ( j = head[J] ; j != -1 ; j = link[j] ) { IVL_listAndSize(adjIVL, j, &jsize, &jind) ; #if MYDEBUG > 0 fprintf(stdout, "\n adj j = %d : ", j) ; IVfp80(stdout, jsize, jind, 20, &ierr) ; #endif for ( ii = 0 ; ii < jsize ; ii++ ) { if ( (k = jind[ii]) < nvtx ) { K = cmap[k] ; #if MYDEBUG > 0 fprintf(stdout, "\n k = %d, K = %d", k, K) ; #endif if ( mark[K] != J ) { #if MYDEBUG > 0 fprintf(stdout, ", added") ; #endif mark[K] = J ; indices[Jsize++] = K ; } } } } if ( Jsize > 0 ) { IVqsortUp(Jsize, indices) ; } IVL_setList(AdjIVL, J, Jsize, indices) ; #if MYDEBUG > 0 fprintf(stdout, "\n setting list %d :", J) ; IVfp80(stdout, Jsize, indices, 20, &ierr) ; #endif } g2->nedges = AdjIVL->tsize ; IVfree(indices) ; IVfree(mark) ; if ( coarseType % 2 == 1 ) { /* ------------------------------------------- fill the vertex weights of the coarse graph ------------------------------------------- */ for ( J = 0 ; J < ncvtx ; J++ ) { wght = 0 ; for ( j = head[J] ; j != -1 ; j = link[j] ) { if ( g->type % 2 == 1 ) { wght += vwghts[j] ; } else { wght++ ; } } Vwghts[J] = wght ; } g2->totvwght = IVsum(ncvtx, Vwghts) ; #if MYDEBUG > 0 { int ierr ; fprintf(stdout, "\n Vwghts(%d) : ", ncvtx) ; IVfp80(stdout, ncvtx, Vwghts, 80, &ierr) ; fflush(stdout) ; } #endif } else { /* ------------------------------------------------- coarse graph does not have vertex weights, set total vertex weight to the number of vertices ------------------------------------------------- */ g2->totvwght = ncvtx ; } if ( coarseType >= 2 ) { /* ----------------------------------------- fill the edge weights of the coarse graph ----------------------------------------- */ for ( J = 0 ; J < ncvtx ; J++ ) { IVL_listAndSize(AdjIVL, J, &Jsize, &Jind) ; IVL_setList(EwghtIVL, J, Jsize, NULL) ; } if ( g->type >= 2 ) { /* --------------------------- fine graph had edge weights --------------------------- */ for ( j = 0 ; j < nvtx ; j++ ) { J = cmap[j] ; IVL_listAndSize(adjIVL, j, &jsize, &jind) ; IVL_listAndSize(ewghtIVL, j, &jsize, &jwghts) ; IVL_listAndSize(AdjIVL, J, &Jsize, &Jind) ; IVL_listAndSize(EwghtIVL, J, &Jsize, &Jwghts) ; for ( ii = 0 ; ii < jsize ; ii++ ) { k = jind[ii] ; if ( k < nvtx ) { K = cmap[k] ; for ( jj = 0 ; jj < Jsize ; jj++ ) { if ( Jind[jj] == K ) { Jwghts[jj] += jwghts[ii] ; break ; } } } } } } else { /* ------------------------------------ fine graph did not have edge weights ------------------------------------ */ for ( j = 0 ; j < nvtx ; j++ ) { J = cmap[j] ; IVL_listAndSize(adjIVL, j, &jsize, &jind) ; IVL_listAndSize(AdjIVL, J, &Jsize, &Jind) ; IVL_listAndSize(EwghtIVL, J, &Jsize, &Jwghts) ; for ( ii = 0 ; ii < jsize ; ii++ ) { k = jind[ii] ; if ( k < nvtx ) { K = cmap[k] ; for ( jj = 0 ; jj < Jsize ; jj++ ) { if ( Jind[jj] == K ) { Jwghts[jj]++ ; break ; } } } } } } g2->totewght = IVL_sum(EwghtIVL) ; } else { /* -------------------------------------------- coarse graph does not have edge weights, set total edge weight to the number of edges -------------------------------------------- */ g2->totewght = g2->nedges ; } /* ------------------------------ free the head and link vectors ------------------------------ */ IVfree(head) ; IVfree(link) ; return(g2) ; } /*--------------------------------------------------------------------*/ Graph/src/equivMap.c010064400020550007177000000125520653410610400156600ustar00clevecompmath00000400000006/* equivMap.c */ #include "../Graph.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- fill an IV object with an equivalence map if ( map[u] == map[v] ) then then u and v are adjacent to the same vertices endif NOTE : each empty list is mapped to a different value return value -- IV object that contains the equivalence map created -- 96feb23, cca ----------------------------------------------------------- */ IV * Graph_equivMap ( Graph *g ) { int ierr, ii, ismapped, jj, nvtx, nvtx2, u, usize, v, vsize, vsum ; int *chksum, *eqmap, *mark, *uadj, *vadj ; IV *eqmapIV ; /* --------------- check the input --------------- */ if ( g == NULL || (nvtx = g->nvtx) <= 0 ) { fprintf(stderr, "\n fatal error in Graph_equivMap(%p)" "\n bad input\n", g) ; exit(-1) ; } /* ----------------------------------------- initialize map and set up working storage ----------------------------------------- */ eqmapIV = IV_new() ; IV_init(eqmapIV, nvtx, NULL) ; eqmap = IV_entries(eqmapIV) ; IVfill(nvtx, eqmap, -1) ; mark = IVinit(nvtx, -1) ; chksum = IVinit(nvtx, -1) ; /* ----------------------------------------- loop over the vertices in ascending order ----------------------------------------- */ nvtx2 = 0 ; for ( v = 0 ; v < nvtx ; v++ ) { if ( eqmap[v] == -1 ) { Graph_adjAndSize(g, v, &vsize, &vadj) ; if ( vsize == 0 ) { /* ------------------------------ list is empty, map to new list ------------------------------ */ #if MYDEBUG > 1 fprintf(stdout, "\n vertex %d, empty list, map to %d", v, eqmap[v]) ; fflush(stdout) ; #endif eqmap[v] = nvtx2++ ; } else { /* ---------------- compute checksum ---------------- */ vsum = v ; for ( ii = 0 ; ii < vsize ; ii++ ) { if ( vadj[ii] != v ) { vsum += vadj[ii] ; } } chksum[v] = vsum ; #if MYDEBUG > 1 fprintf(stdout, "\n vertex %d, checksum = %d", v, chksum[v]) ; fflush(stdout) ; #endif /* ------------------------------------------------------- look at all adjacent vertices with numbers lower than v ------------------------------------------------------- */ ismapped = 0 ; for ( ii = 0 ; ii < vsize ; ii++ ) { if ( (u = vadj[ii]) < v && chksum[u] == vsum ) { /* ------------------------------ u and v have the same checksum ------------------------------ */ #if MYDEBUG > 1 fprintf(stdout, "\n checking vertex %d, checksum = %d", u, chksum[u]) ; fflush(stdout) ; #endif Graph_adjAndSize(g, u, &usize, &uadj) ; if ( vsize == usize ) { /* ---------------------------------------------- the adjacency lists are the same size, compare ---------------------------------------------- */ if ( ismapped == 0 ) { /* --------------------------- mark all vertices in adj(v) --------------------------- */ mark[v] = v ; for ( jj = 0 ; jj < vsize ; jj++ ) { mark[vadj[jj]] = v ; } ismapped = 1 ; } /* ------------------------------------------------- check to see if all vertices in adj(u) are marked ------------------------------------------------- */ for ( jj = 0 ; jj < usize ; jj++ ) { if ( mark[uadj[jj]] != v ) { #if MYDEBUG > 1 fprintf(stdout, "\n vertex %d is adjacent to %d but not %d", uadj[jj], u, v) ; #endif break ; } } if ( jj == usize ) { /* ---------------------------------- lists are identical, set map for v to be the same as the map for u ---------------------------------- */ #if MYDEBUG > 1 fprintf(stdout, "\n lists are identical, map[%d] = map[%d] = %d", v, u, eqmap[u]) ; fflush(stdout) ; #endif eqmap[v] = eqmap[u] ; break ; } } } } if ( eqmap[v] == -1 ) { /* ------------------------------------------------ v was not found to be indistinguishable from any adjacent vertex with lower number, set map value ------------------------------------------------ */ #if MYDEBUG > 1 fprintf(stdout, "\n mapping %d to %d", v, nvtx2) ; fflush(stdout) ; #endif eqmap[v] = nvtx2++ ; } } } } IVfree(mark) ; IVfree(chksum) ; #if MYDEBUG > 0 fprintf(stdout, "\n final map") ; IVfp80(stdout, nvtx, eqmap, 80, &ierr) ; fflush(stdout) ; #endif return(eqmapIV) ; } /*--------------------------------------------------------------------*/ Graph/src/expand.c010064400020550007177000000103020653410610400153370ustar00clevecompmath00000400000006/* expand.c */ #include "../Graph.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- take a Graph object and a map to expand it, create and return a bigger unit weight Graph object. this is useful for expanding a compressed graph into a unit weight graph. created -- 96mar02, cca --------------------------------------------------------------------- */ Graph * Graph_expand2 ( Graph *g, IV *mapIV ) { /* --------------- check the input --------------- */ if ( g == NULL || g->nvtx <= 0 || mapIV == NULL || IV_entries(mapIV) == NULL ) { fprintf(stderr, "\n fatal error in Graph_expand2(%p,%p)" "\n bad input\n", g, mapIV) ; exit(-1) ; } return(Graph_expand(g, IV_size(mapIV), IV_entries(mapIV))) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- take a Graph object and a map to expand it, create and return a bigger unit weight Graph object. this is useful for expanding a compressed graph into a unit weight graph. created -- 96mar02, cca --------------------------------------------------------------------- */ Graph * Graph_expand ( Graph *g, int nvtxbig, int map[] ) { Graph *gbig ; int count, ii, nedge, nvtx, v, vbig, vsize, w ; int *head, *indices, *link, *mark, *vadj ; IVL *adjIVL, *adjbigIVL ; /* --------------- check the input --------------- */ if ( g == NULL || nvtxbig <= 0 || map == NULL ) { fprintf(stderr, "\n fatal error in Graph_expand(%p,%d,%p)" "\n bad input\n", g, nvtxbig, map) ; exit(-1) ; } nvtx = g->nvtx ; adjIVL = g->adjIVL ; /* ---------------------------------------- set up the linked lists for the vertices ---------------------------------------- */ head = IVinit(nvtx, -1) ; link = IVinit(nvtxbig, -1) ; for ( vbig = 0 ; vbig < nvtxbig ; vbig++ ) { v = map[vbig] ; link[vbig] = head[v] ; head[v] = vbig ; } /* -------------------------------- create the expanded Graph object -------------------------------- */ gbig = Graph_new() ; Graph_init1(gbig, 0, nvtxbig, 0, 0, IVL_CHUNKED, IVL_CHUNKED) ; adjbigIVL = gbig->adjIVL ; /* ------------------------------------------- fill the lists in the expanded Graph object ------------------------------------------- */ indices = IVinit(nvtxbig, -1) ; mark = IVinit(nvtx, -1) ; nedge = 0 ; for ( v = 0 ; v < nvtx ; v++ ) { if ( head[v] != -1 ) { /* ------------------------------ load the indices that map to v ------------------------------ */ mark[v] = v ; count = 0 ; for ( vbig = head[v] ; vbig != -1 ; vbig = link[vbig] ) { indices[count++] = vbig ; } /* --------------------------------------------------- load the indices that map to vertices adjacent to v --------------------------------------------------- */ IVL_listAndSize(adjIVL, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < nvtx && mark[w] != v ) { mark[w] = v ; for ( vbig = head[w] ; vbig != -1 ; vbig = link[vbig] ) { indices[count++] = vbig ; } } } /* -------------------------------------- sort the index list in ascending order -------------------------------------- */ IVqsortUp(count, indices) ; /* ------------------------------------------------------- each vertex in the big IVL object has its own list. ------------------------------------------------------- */ for ( vbig = head[v] ; vbig != -1 ; vbig = link[vbig] ) { IVL_setList(adjbigIVL, vbig, count, indices) ; nedge += count ; } } } gbig->nedges = nedge ; /* ------------------------ free the working storage ------------------------ */ IVfree(head) ; IVfree(link) ; IVfree(indices) ; IVfree(mark) ; return(gbig) ; } /*--------------------------------------------------------------------*/ mapIV) == NULL ) { fprintf(stderr, "\n fatal error in Graph_expand2(%p,%p)" "\n bad input\n", g, mapIV) ; exit(-1) ; } return(Graph_expand(g, IV_size(mapIV), IV_entries(mapIV))) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------Graph/src/fillFromOffsets.c010064400020550007177000000132340654002015700171730ustar00clevecompmath00000400000006/* fillFromOffsets.c */ #include "../Graph.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- take an adjacency structure in the (offsets[neqns+1], adjncy[*]) form and load the Graph object g -- pointer to Graph object, must be initialized with nvtx = neqns neqns -- # of equations offsets -- offsets vector adjncy -- big adjacency vector note, the adjacency for list v is found in adjncy[offsets[v]:offsets[v+1]-1] also note, offsets[] and adjncy[] must be zero based, if (offsets,adjncy) come from a harwell-boeing file, they use the fortran numbering, so each value must be decremented to conform with C's zero based numbering flag -- task flag flag = 0 --> just set the adjacency list for v to be that found in adjncy[offsets[v]:offsets[v+1]-1] flag = 1 --> the input adjancency is just the upper triangle (or strict upper triangle) as from a harwell-boeing file. fill the Graph object with the full adjacency structure, including (v,v) edges created -- 96mar16, cca ------------------------------------------------------------------- */ void Graph_fillFromOffsets ( Graph *g, int neqns, int offsets[], int adjncy[], int flag ) { IVL *adjIVL ; /* --------------- check the input --------------- */ if ( g == NULL || neqns <= 0 || offsets == NULL || adjncy == NULL || flag < 0 || flag > 1 ) { fprintf(stderr, "\n fatal error in Graph_fillFromOffsets(%p,%d,%p,%p,%d)" "\n bad input\n", g, neqns, offsets, adjncy, flag) ; exit(-1) ; } /* --------------------------- initialize the Graph object --------------------------- */ Graph_init1(g, 0, neqns, 0, 0, IVL_CHUNKED, IVL_CHUNKED) ; adjIVL = g->adjIVL ; if ( flag == 0 ) { int count, ii, nedge, v, w ; int *list, *mark ; /* ---------------------------------------------- simple map, do not enforce symmetric structure ---------------------------------------------- */ list = IVinit(neqns, -1) ; mark = IVinit(neqns, -1) ; for ( v = 0, nedge = 0 ; v < neqns ; v++ ) { count = 0 ; for ( ii = offsets[v] ; ii < offsets[v+1] ; ii++ ) { w = adjncy[ii] ; if ( v == neqns ) { fprintf(stdout, "\n hey there!! (v,w) = (%d,%d)", v, w) ; } if ( 0 <= w && w < neqns && mark[w] != v ) { list[count++] = w ; mark[w] = v ; } } if ( mark[v] != v ) { list[count++] = v ; mark[v] = v ; } IVqsortUp(count, list) ; IVL_setList(adjIVL, v, count, list) ; nedge += count ; } g->totvwght = neqns ; g->totewght = g->nedges = nedge ; /* ---------------------------- now free the working storage ---------------------------- */ IVfree(list) ; IVfree(mark) ; } else { int ii, jj, u, v, vsize, w ; int *head, *link, *list, *sizes, *vadj ; int **p_adj ; /* ------------------------------------------- enforce symmetric structure and (v,v) edges make a first pass to check the input ------------------------------------------- */ fprintf(stdout, "\n offsets") ; IVfprintf(stdout, neqns+1, offsets) ; for ( v = 0 ; v < neqns ; v++ ) { fprintf(stdout, "\n v = %d", v) ; for ( ii = offsets[v] ; ii < offsets[v+1] ; ii++ ) { fprintf(stdout, "\n w = %d", adjncy[ii]) ; if ( (w = adjncy[ii]) < v || neqns <= w ) { fprintf(stderr, "\n fatal error in Graph_fillFromOffsets(%p,%d,%p,%p,%d)" "\n list %d, entry %d\n", g, neqns, offsets, adjncy, flag, v, w) ; exit(-1) ; } } } head = IVinit(neqns, -1) ; link = IVinit(neqns, -1) ; list = IVinit(neqns, -1) ; sizes = IVinit(neqns, 0) ; p_adj = PIVinit(neqns) ; for ( v = 0 ; v < neqns ; v++ ) { vsize = 0 ; /* ------------------------- add edges to vertices < v ------------------------- */ while ( (u = head[v]) != -1 ) { head[v] = link[u] ; list[vsize++] = u ; if ( --sizes[u] > 0 ) { w = *(++p_adj[u]) ; link[u] = head[w] ; head[w] = u ; } } /* ----------------- add in edge (v,v) ----------------- */ list[vsize++] = v ; jj = vsize ; /* ------------------------- add edges to vertices > v ------------------------- */ for ( ii = offsets[v] ; ii < offsets[v+1] ; ii++ ) { if ( (w = adjncy[ii]) != v ) { list[vsize++] = w ; } } /* --------------------- sort and set the list --------------------- */ IVqsortUp(vsize, list) ; IVL_setList(adjIVL, v, vsize, list) ; /* -------------------------------------------------- link v to first vertex in its lists greater than v -------------------------------------------------- */ if ( jj < vsize ) { IVL_listAndSize(adjIVL, v, &vsize, &vadj) ; w = vadj[jj] ; link[v] = head[w] ; head[w] = v ; sizes[v] = vsize - jj ; p_adj[v] = &vadj[jj] ; } g->nedges += vsize ; } g->totvwght = neqns ; g->totewght = g->nedges ; /* ---------------------------- now free the working storage ---------------------------- */ IVfree(head) ; IVfree(link) ; IVfree(list) ; IVfree(sizes) ; PIVfree(p_adj) ; } return ; } /*--------------------------------------------------------------------*/ Graph/src/init.c010064400020550007177000000204670653410610400150400ustar00clevecompmath00000400000006/* init.c */ #include "../Graph.h" #define MYTRACE 0 /*--------------------------------------------------------------------*/ /* --------------------------------------------- basic initializer for the Graph object type -- graph type nvtx -- # of vertices nvbnd -- # of boundary vertices nedges -- # of edges adjType -- IVL type for adjacency object ewghtType -- IVL type for edge weights object created -- 95sep27, cca --------------------------------------------- */ void Graph_init1 ( Graph *g, int type, int nvtx, int nvbnd, int nedges, int adjType, int ewghtType ) { int nvtot ; #if MYTRACE > 0 fprintf(stdout, "\n just inside Graph_init1(%p,%d,%d,%d,%d,%d,%d)", g, type, nvtx, nvbnd, nedges, adjType, ewghtType) ; fflush(stdout) ; #endif /* --------------- check the input --------------- */ if ( g == NULL ) { fprintf(stderr, "\n fatal error in Graph_init1(%p,%d,%d,%d,%d,%d,%d)" "\n graph is NULL\n", g, type, nvtx, nvbnd, nedges, adjType, ewghtType) ; exit(-1) ; } if ( type < 0 || type >= 4 ) { fprintf(stderr, "\n fatal error in Graph_init1(%p,%d,%d,%d,%d,%d,%d)" "\n invalid type = %d, must be in [0,3]\n", g, type, nvtx, nvbnd, nedges, adjType, ewghtType, type) ; exit(-1) ; } if ( nvtx <= 0 ) { fprintf(stderr, "\n fatal error in Graph_init1(%p,%d,%d,%d,%d,%d,%d)" "\n nvtx = %d, must be positive\n", g, type, nvtx, nvbnd, nedges, adjType, ewghtType, nvtx) ; exit(-1) ; } if ( nvbnd < 0 ) { fprintf(stderr, "\n fatal error in Graph_init1(%p,%d,%d,%d,%d,%d,%d)" "\n nvbnd = %d, must be nonnegative\n", g, type, nvtx, nvbnd, nedges, adjType, ewghtType, nvbnd) ; exit(-1) ; } if ( nedges < 0 ) { fprintf(stderr, "\n fatal error in Graph_init1(%p,%d,%d,%d,%d,%d,%d)" "\n nedges = %d, must be nonnegative\n", g, type, nvtx, nvbnd, nedges, adjType, ewghtType, nedges) ; exit(-1) ; } #if MYTRACE > 0 fprintf(stdout, "\n input checks out") ; fflush(stdout) ; #endif switch ( adjType ) { case IVL_CHUNKED : case IVL_SOLO : case IVL_UNKNOWN : break ; default : fprintf(stderr, "\n fatal error in Graph_init1(%p,%d,%d,%d,%d,%d,%d)" "\n invalid adjType = %d\n", g, type, nvtx, nvbnd, nedges, adjType, ewghtType, adjType) ; exit(-1) ; } switch ( ewghtType ) { case IVL_CHUNKED : case IVL_SOLO : case IVL_UNKNOWN : break ; default : fprintf(stderr, "\n fatal error in Graph_init1(%p,%d,%d,%d,%d,%d,%d)" "\n invalid ewghtType = %d\n", g, type, nvtx, nvbnd, nedges, adjType, ewghtType, ewghtType) ; exit(-1) ; } /* ------------------------- clear the data structures ------------------------- */ Graph_clearData(g) ; /* --------------------- set the scalar fields --------------------- */ g->type = type ; g->nvtx = nvtx ; g->nvbnd = nvbnd ; g->nedges = nedges ; nvtot = nvtx + nvbnd ; /* ---------------------------- set the adjacency IVL object ---------------------------- */ g->adjIVL = IVL_new() ; if ( nedges == 0 || adjType == IVL_UNKNOWN ) { IVL_init1(g->adjIVL, adjType, nvtot) ; } else { IVL_init2(g->adjIVL, adjType, nvtot, nedges) ; } if ( type % 2 == 1 ) { /* ----------------------------- set the vertex weights vector ----------------------------- */ g->vwghts = IVinit(nvtot, 0) ; } if ( type >= 2 ) { /* ------------------------------- set the edge weights IVL object ------------------------------- */ g->ewghtIVL = IVL_new() ; if ( nedges == 0 || ewghtType == IVL_UNKNOWN ) { IVL_init1(g->ewghtIVL, ewghtType, nvtot) ; } else { IVL_init2(g->ewghtIVL, ewghtType, nvtot, nedges) ; } } #if MYTRACE > 0 fprintf(stdout, "\n leaving Graph_init1(%p,%d,%d,%d,%d,%d,%d)", g, type, nvtx, nvbnd, nedges, adjType, ewghtType) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- second initializer for the Graph object. this function is used in the I/O routines Graph_readFromFormattedFile(Graph *g, FILE *fp) and Graph_readFromBinaryFile(Graph *g, FILE *fp) where the IVL object(s) and vwghts[] vector are created independently. type -- graph type nvtx -- # of vertices nvbnd -- # of boundary vertices nedges -- # of edges totvwght -- total vertex weight totewght -- total edge weight adjIVL -- IVL object for adjacency structure vwghts -- pointer to integer vector for vertex weights ewghtIVL -- IVL object for edge weights created -- 95sep27, cca -------------------------------------------------------- */ void Graph_init2 ( Graph *g, int type, int nvtx, int nvbnd, int nedges, int totvwght, int totewght, IVL *adjIVL, int *vwghts, IVL *ewghtIVL ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside Graph_init2(%p,%d,%d,%d,%d,%d,%d,%p,%p,%p)", g, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL) ; fflush(stdout) ; #endif /* --------------- check the input --------------- */ if ( g == NULL ) { fprintf(stdout, "\n fatal error in Graph_init2(%p,%d,%d,%d,%d,%d,%d,%p,%p,%p)" "\n graph is NULL\n", g, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL) ; exit(-1) ; } if ( type < 0 || type >= 4 ) { fprintf(stdout, "\n fatal error in Graph_init2(%p,%d,%d,%d,%d,%d,%d,%p,%p,%p)" "\n invalid type = %d, must be in [0,3]\n", g, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL, type) ; exit(-1) ; } if ( nvtx <= 0 ) { fprintf(stdout, "\n fatal error in Graph_init2(%p,%d,%d,%d,%d,%d,%d,%p,%p,%p)" "\n nvtx = %d, must be positive\n", g, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL, nvtx) ; exit(-1) ; } if ( nvbnd < 0 ) { fprintf(stdout, "\n fatal error in Graph_init2(%p,%d,%d,%d,%d,%d,%d,%p,%p,%p)" "\n nvbnd = %d, must be nonnegative\n", g, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL, nvbnd) ; exit(-1) ; } if ( nedges < 0 ) { fprintf(stdout, "\n fatal error in Graph_init2(%p,%d,%d,%d,%d,%d,%d,%p,%p,%p)" "\n nedges = %d, must be nonnegative\n", g, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL, nedges) ; exit(-1) ; } if ( adjIVL == NULL ) { fprintf(stdout, "\n fatal error in Graph_init2(%p,%d,%d,%d,%d,%d,%d,%p,%p,%p)" "\n adjIVL is NULL\n", g, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL) ; exit(-1) ; } if ( (type % 2 == 1) && (vwghts == NULL) ) { fprintf(stdout, "\n fatal error in Graph_init2(%p,%d,%d,%d,%d,%d,%d,%p,%p,%p)" "\n type = %d, vwghts is NULL", g, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL, type) ; exit(-1) ; } if ( (type >= 2) && (ewghtIVL == NULL) ) { fprintf(stdout, "\n fatal error in Graph_init2(%p,%d,%d,%d,%d,%d,%d,%p,%p,%p)" "\n type = %d, ewghtIVL is NULL", g, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL, type) ; exit(-1) ; } /* ------------------------- clear the data structures ------------------------- */ Graph_clearData(g) ; /* --------------------- set the scalar fields --------------------- */ g->type = type ; g->nvtx = nvtx ; g->nvbnd = nvbnd ; g->nedges = nedges ; g->totvwght = totvwght ; g->totewght = totewght ; /* --------------------------------------------- set the IVL objects and vertex weights vector --------------------------------------------- */ g->adjIVL = adjIVL ; if ( type % 2 == 1 ) { g->vwghts = vwghts ; } if ( type >= 2 ) { g->ewghtIVL = ewghtIVL ; } #if MYTRACE > 0 fprintf(stdout, "\n leaving Graph_init2(%p,%d,%d,%d,%d,%d,%d,%p,%p,%p)" "\n type = %d, ewghtIVL is NULL", g, type, nvtx, nvbnd, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL, type) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ Graph/src/setListsFromOffsets.c010064400020550007177000000040660653410610400200620ustar00clevecompmath00000400000006/* setListsFromOffsets.c */ #include "../Graph.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- take an adjacency structure in the (offsets[neqns+1], adjncy[*]) form and load the Graph object. note, pointers to the lists are set, no new storage is allocated for the adjacency lists. however, during the ordering process each adjacency lists may be shuffled. g -- pointer to Graph object, must be initialized with nvtx = neqns neqns -- # of equations offsets -- offsets vector adjncy -- big adjacency vector note, the adjacency for list v is found in adjncy[offsets[v]:offsets[v+1]-1] also note, offsets[] and adjncy[] must be zero based, if (offsets,adjncy) come from a harwell-boeing file, they use the fortran numbering, so each value must be decremented to conform with C's zero based numbering created -- 96oct24, cca ------------------------------------------------------------------- */ void Graph_setListsFromOffsets ( Graph *g, int neqns, int offsets[], int adjncy[] ) { int v, vsize ; IVL *adjIVL ; /* --------------- check the input --------------- */ if ( g == NULL || neqns <= 0 || offsets == NULL || adjncy == NULL ) { fprintf(stderr, "\n fatal error in Graph_setListsFromOffsets(%p,%d,%p,%p)" "\n bad input\n", g, neqns, offsets, adjncy) ; exit(-1) ; } /* --------------------------- initialize the Graph object --------------------------- */ Graph_init1(g, 0, neqns, 0, 0, IVL_CHUNKED, IVL_CHUNKED) ; adjIVL = g->adjIVL ; /* ----------------------------- set the pointers to the lists ----------------------------- */ for ( v = 0 ; v < neqns ; v++ ) { if ( (vsize = offsets[v+1] - offsets[v]) > 0 ) { IVL_setPointerToList(adjIVL, v, vsize, &adjncy[offsets[v]]) ; } } return ; } /*--------------------------------------------------------------------*/ Graph/src/util.c010064400020550007177000000311500653410610400150410ustar00clevecompmath00000400000006/* util.c */ #include "../Graph.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- return the external degree (in terms of vertex weight) of vertex v created -- 95oct05, cca --------------------------------------------------------------------- */ int Graph_externalDegree ( Graph *g, int v ) { int ii, vsize, w, weight ; int *vadj, *vwghts ; /* --------------- check the input --------------- */ if ( g == NULL || v < 0 || g->nvtx + g->nvbnd <= v ) { fprintf(stderr, "\n fatal error in Graph_externalDegree(%p,%d)" "\n bad input\n", g, v) ; exit(-1) ; } vwghts = g->vwghts ; Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0, weight = 0 ; ii < vsize ; ii++ ) { if ( (w = vadj[ii]) != v ) { weight += (vwghts != NULL) ? vwghts[w] : 1 ; } } return(weight) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- method to access the adjacency list created -- 95oct05, cca ----------------------------------- */ void Graph_adjAndSize ( Graph *g, int jvtx, int *psize, int **padj ) { /* --------------- check the input --------------- */ if ( g == NULL || jvtx < 0 || g->nvtx + g->nvbnd <= jvtx || psize == NULL || padj == NULL ) { fprintf(stderr, "\n fatal error in Graph_adjAndSize(%p,%d,%p,%p)" "\n bad input\n", g, jvtx, psize, padj) ; exit(-1) ; } if ( g->adjIVL == NULL ) { fprintf(stderr, "\n fatal error in Graph_adjAndSize(%p,%d,%p,%p)" "\n g->adjIVL == NULL\n", g, jvtx, psize, padj) ; exit(-1) ; } IVL_listAndSize(g->adjIVL, jvtx, psize, padj) ; /* here is fast code but not safe code */ /* *psize = g->adjIVL->sizes[jvtx] ; *padj = g->adjIVL->p_vec[jvtx] ; */ return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- method to access the adjacency list and possibly the edge weight list for a vertex. created -- 95sep29, cca ----------------------------------------------- */ void Graph_adjAndEweights ( Graph *g, int jvtx, int *psize, int **padj, int **pewghts ) { /* --------------- check the input --------------- */ if ( g == NULL || jvtx < 0 || g->nvtx + g->nvbnd <= jvtx || psize == NULL || padj == NULL || pewghts == NULL ) { fprintf(stderr, "\n fatal error in Graph_adjAndEwghts(%p,%d,%p,%p,%p)" "\n bad input\n", g, jvtx, psize, padj, pewghts) ; exit(-1) ; } if ( g->adjIVL == NULL ) { fprintf(stderr, "\n fatal error in Graph_adjAndEwghts(%p,%d,%p,%p,%p)" "\n g->adjIVL == NULL\n", g, jvtx, psize, padj, pewghts) ; exit(-1) ; } if ( g->type >= 2 && g->ewghtIVL == NULL ) { fprintf(stderr, "\n fatal error in Graph_adjAndEwghts(%p,%d,%p,%p,%p)" "\n g->type = %d and g->ewghtIVL == NULL\n", g, jvtx, psize, padj, pewghts, g->type) ; exit(-1) ; } IVL_listAndSize(g->adjIVL, jvtx, psize, padj) ; if ( g->type >= 2 ) { IVL_listAndSize(g->ewghtIVL, jvtx, psize, pewghts) ; } else { *pewghts = NULL ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- return the number of bytes taken by the Graph object created -- 95oct05, cca ---------------------------------------------------- */ int Graph_sizeOf ( Graph *g ) { int nbytes ; /* --------------- check the input --------------- */ if ( g == NULL ) { fprintf(stderr, "\n fatal error in Graph_sizeOf(%p)" "\n bad input\n", g) ; exit(-1) ; } nbytes = sizeof(struct _Graph) ; if ( g->vwghts != NULL ) { nbytes += (g->nvtx + g->nvbnd)*sizeof(int) ; } if ( g->adjIVL != NULL ) { nbytes += IVL_sizeOf(g->adjIVL) ; } if ( g->ewghtIVL != NULL ) { nbytes += IVL_sizeOf(g->ewghtIVL) ; } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- create and return an IV object filled with a map from vertices to components created -- 96feb25, cca -------------------------------------- */ IV * Graph_componentMap ( Graph *g ) { int ii, last, ncomp, now, nvtx, u, usize, v, w ; int *list, *map, *uadj ; IV *mapIV ; /* --------------- check the input --------------- */ if ( g == NULL ) { fprintf(stderr, "\n fatal error in Graph_componentMap(%p)" "\n bad input\n", g) ; exit(-1) ; } if ( (nvtx = g->nvtx) <= 0 ) { return(NULL) ; } mapIV = IV_new() ; IV_init(mapIV, nvtx, NULL) ; map = IV_entries(mapIV) ; list = IVinit(nvtx, -1) ; for ( v = 0, ncomp = 0 ; v < nvtx ; v++ ) { if ( map[v] == -1 ) { /* ------------------------------- seed vertex for a new component ------------------------------- */ map[v] = ncomp ; now = last = 0 ; list[0] = v ; while ( now <= last ) { u = list[now++] ; Graph_adjAndSize(g, u, &usize, &uadj) ; for ( ii = 0 ; ii < usize ; ii++ ) { w = uadj[ii] ; if ( map[w] == -1 ) { /* ------------------ add w to component ------------------ */ list[++last] = w ; map[w] = ncomp ; } } } ncomp++ ; } } IVfree(list) ; return(mapIV) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- given a Graph g and map from vertices to components, fill counts[icomp] with the number of vertices in component icomp and fill weight[icomp] with their weight created -- 96feb25, cca ----------------------------------------------------------------- */ void Graph_componentStats ( Graph *g, int map[], int counts[], int weights[] ) { int ncomp, nvtx, v, vcomp ; int *vwghts ; /* --------------- check the input --------------- */ if ( g == NULL || map == NULL || counts == NULL || weights == NULL ) { fprintf(stderr, "\n fatal error in Graph_componentStats(%p,%p,%p,%p)" "\n bad input\n", g, map, counts, weights) ; exit(-1) ; } /* -------------------- fill the two vectors -------------------- */ nvtx = g->nvtx ; ncomp = 1 + IVmax(nvtx, map, &v) ; if ( (vwghts = g->vwghts) != NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { vcomp = map[v] ; counts[vcomp]++ ; weights[vcomp] += vwghts[v] ; } } else { for ( v = 0 ; v < nvtx ; v++ ) { vcomp = map[v] ; counts[vcomp]++ ; } IVcopy(ncomp, weights, counts) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- create and return a subgraph and a map from its vertices to the vertices of the graph. g -- graph from which to extract the subgraph icomp -- component from which comes the vertices of the subgraph, icomp > 0 compids -- component ids vector of graph pmap -- pointer to hold address of map vector, the map from the subgraph's vertices to the graph's vertices return value -- pointer to subgraph Graph object created -- 95nov10, cca ------------------------------------------------------------------- */ Graph * Graph_subGraph ( Graph *g, int icomp, int compids[], int **pmap ) { Graph *gsub ; int count, ii, iv, nvbnd, nvbndsub, nvtx, nvtxsub, nvtot, nvtotsub, v, vsub, vsize, w, wsub ; int *invmap, *map, *vadj ; /* --------------- check the input --------------- */ if ( g == NULL || icomp <= 0 || compids == NULL || pmap == NULL ) { fprintf(stderr, "\n fatal error in Graph_subGraph(%p,%d,%p,%p)" "\n bad input\n", g, icomp, compids, pmap) ; exit(-1) ; } if ( g->type < 0 || g->type >= 2 ) { fprintf(stderr, "\n fatal error in Graph_subGraph(%p,%d,%p,%p)" "\n g->type = 0 or 1 currently supported\n", g, icomp, compids, pmap) ; exit(-1) ; } nvtx = g->nvtx ; nvbnd = g->nvbnd ; nvtot = nvtx + nvbnd ; /* ------------------------------------------------ generate the map vectors map : subgraph's vertices to graph's vertices invmap : graph's vertices to subgraph's vertices ------------------------------------------------ */ map = IVinit(nvtot, -1) ; invmap = IVinit(nvtot, -1) ; for ( v = 0, count = 0 ; v < nvtx ; v++ ) { if ( compids[v] == icomp ) { map[count] = v ; invmap[v] = count++ ; } } nvtxsub = count ; /* ---------------------------------------------- now get the boundary vertices for the subgraph ---------------------------------------------- */ for ( iv = 0 ; iv < nvtxsub ; iv++ ) { v = map[iv] ; Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < nvtx ) { if ( compids[w] == 0 && invmap[w] == -1 ) { map[count] = w ; invmap[w] = count++ ; } } else if ( invmap[w] == -1 ) { map[count] = w ; invmap[w] = count++ ; } } } nvbndsub = count - nvtxsub; nvtotsub = count ; IVqsortUp(nvbndsub, &map[nvtxsub]) ; for ( ii = nvtxsub ; ii < nvtotsub ; ii++ ) { v = map[ii] ; invmap[v] = ii ; } /* ----------------------- initialize the subgraph ----------------------- */ gsub = Graph_new() ; Graph_init1(gsub, g->type, nvtxsub, nvbndsub, 0, IVL_CHUNKED, IVL_UNKNOWN) ; /* --------------------------------------------- fill the adjacency structure of the subgraph note: the pointers of the subgraph point into the adjacency lists of the parent graph and the indices are overwritten. --------------------------------------------- */ for ( vsub = 0 ; vsub < nvtxsub ; vsub++ ) { v = map[vsub] ; Graph_adjAndSize(g, v, &vsize, &vadj) ; IVL_setPointerToList(gsub->adjIVL, vsub, vsize, vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { vadj[ii] = invmap[vadj[ii]] ; } IVqsortUp(vsize, vadj) ; } if ( nvbndsub > 0 ) { int *ind = IVinit(nvtot, -1) ; for ( vsub = nvtxsub ; vsub < nvtotsub ; vsub++ ) { v = map[vsub] ; Graph_adjAndSize(g, v, &vsize, &vadj) ; for ( ii = 0, count = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( (wsub = invmap[w]) != -1 ) { ind[count++] = wsub ; } } IVqsortUp(count, ind) ; IVL_setList(gsub->adjIVL, vsub, count, ind) ; } IVfree(ind) ; } /* --------------------------------- fill vertex weights if applicable --------------------------------- */ if ( gsub->type % 2 == 1 ) { gsub->totvwght = 0 ; for ( vsub = 0 ; vsub < nvtotsub ; vsub++ ) { v = map[vsub] ; gsub->totvwght += g->vwghts[v] ; gsub->vwghts[vsub] = g->vwghts[v] ; } } else { gsub->totvwght = gsub->nvtx ; } /* ---------------------------------------------------------------- free the inverse map, create a new map[] vector the right size, copy the old map vector into the new and free the old map vector ---------------------------------------------------------------- */ IVfree(invmap) ; *pmap = IVinit(nvtotsub, -1) ; IVcopy(nvtotsub, *pmap, map) ; IVfree(map) ; return(gsub) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- return 1 if the graph is symmetric return 0 otherwise created -- 96oct31, cca ---------------------------------- */ int Graph_isSymmetric ( Graph *graph ) { int ii, jj, nvtx, rc, v, vsize, w, wsize ; int *vadj, *wadj ; /* --------------- check the input --------------- */ if ( graph == NULL ) { fprintf(stderr, "\n fatal error in Graph_isSymmetric(%p)" "\n bad input\n", graph) ; exit(-1) ; } /* ---------------------- loop over the vertices ---------------------- */ rc = 1 ; nvtx = graph->nvtx ; for ( v = 0 ; v < nvtx ; v++ ) { Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; Graph_adjAndSize(graph, w, &wsize, &wadj) ; for ( jj = 0 ; jj < wsize ; jj++ ) { if ( wadj[jj] == v ) { break ; } } if ( jj == wsize ) { fprintf(stdout, "\n edge (%d,%d) present, edge (%d,%d) is not", v, w, w, v) ; rc = 0 ; /* return(rc) ; */ } } } return(rc) ; } /*--------------------------------------------------------------------*/ g, jvtx, psize, padj, pewghts) ; exit(-1) ; } if ( g->adjIVL == NULL ) { fprintf(stderr, "\n fatal error in Graph_adjAndEwghts(%p,%d,%p,%p,%p)" "\n g->adjIVL == NULL\n", g, jvtx, psize, padj, pewghts) ; exit(-1) ; } if ( g->type >= 2 && g->ewghtIVL == NULL ) { fprintf(stderr, "\n fatal error in Graph_adjAndEwghts(%p,%d,%p,%p,%p)" Graph/src/wirebasket.c010064400020550007177000000113150660524177100162360ustar00clevecompmath00000400000006/* wirebasket.c */ #include "../Graph.h" #define MYDEBUG 1 /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- on input stages[v] = 0 --> vertex is in a domain stages[v] > 0 --> vertex is in the multisector this remains true on output, but the stage of a multisector vertex is equal to the number of different domains that are found within radius edges from itself created -- 97jul30, cca --------------------------------------------------------------------- */ void Graph_wirebasketStages ( Graph *graph, IV *stagesIV, int radius ) { int count, idom, ierr, ii, last, ndom, now, nvtx, u, v, vsize, w ; int *dist, *dmark, *domids, *list, *stages, *vadj, *vmark ; /* --------------- check the input --------------- */ if ( graph == NULL || stagesIV == NULL || radius < 0 ) { fprintf(stderr, "\n fatal error in Graph_wirebasketStages(%p,%p,%d)" "\n bad input\n", graph, stagesIV, radius) ; exit(-1) ; } IV_sizeAndEntries(stagesIV, &nvtx, &stages) ; if ( nvtx != graph->nvtx || stages == NULL ) { fprintf(stderr, "\n fatal error in Graph_wirebasketStages(%p,%p,%d)" "\n stages->nvtx = %d, graph->nvtx = %d, stages = %p\n", graph, stagesIV, nvtx, radius, graph->nvtx, stages) ; exit(-1) ; } /* ----------------------------------------------- fill domids[] domids[v] = -1 --> v is in the multisector domids[v] != -1 --> v is in domain domids[v] ----------------------------------------------- */ domids = IVinit(nvtx, -1) ; list = IVinit(nvtx, -1) ; for ( u = 0, ndom = 0 ; u < nvtx ; u++ ) { #if MYDEBUG > 1 fprintf(stdout, "\n vertex %d, stage %d, domid %d", u, stages[u], domids[u]) ; #endif if ( stages[u] == 0 && domids[u] == -1 ) { #if MYDEBUG > 1 fprintf(stdout, "\n vertex %d starts domain %d", u, ndom) ; #endif list[now = last = 0] = u ; domids[u] = ndom ; while ( now <= last ) { v = list[now++] ; Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( stages[w] == 0 && domids[w] == -1 ) { #if MYDEBUG > 1 fprintf(stdout, "\n adding vertex %d", w) ; #endif domids[w] = ndom ; list[++last] = w ; } } } ndom++ ; } } #if MYDEBUG > 0 fprintf(stdout, "\n domids") ; fprintf(stdout, "\n %d", nvtx) ; IVfp80(stdout, nvtx, domids, 80, &ierr) ; #endif /* -------------------------------------------------------- fill the stages of the multisector vertices based on the number of different domains that are within radius steps -------------------------------------------------------- */ dmark = IVinit(ndom, -1) ; vmark = IVinit(nvtx, -1) ; dist = IVinit(nvtx, -1) ; for ( u = 0 ; u < nvtx ; u++ ) { if ( stages[u] != 0 ) { #if MYDEBUG > 1 fprintf(stdout, "\n\n checking out schur vertex %d", u) ; #endif list[now = last = 0] = u ; vmark[u] = u ; dist[u] = 0 ; count = 0 ; while ( now <= last ) { v = list[now++] ; Graph_adjAndSize(graph, v, &vsize, &vadj) ; #if MYDEBUG > 1 fprintf(stdout, "\n removing vertex %d from list, dist %d", v, dist[v]) ; #endif for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; #if MYDEBUG > 1 fprintf(stdout, "\n adjacent vertex %d, vmark %d, domids %d", w, vmark[w], domids[w]) ; #endif if ( vmark[w] != u ) { vmark[w] = u ; if ( (idom = domids[w]) != -1 ) { if ( dmark[idom] != u ) { #if MYDEBUG > 1 fprintf(stdout, ", marking domain %d", idom) ; #endif dmark[idom] = u ; count++ ; } } else if ( dist[v] < radius - 1 ) { #if MYDEBUG > 1 fprintf(stdout, ", adding %d to list", w) ; #endif dist[w] = dist[v] + 1 ; list[++last] = w ; } } } } stages[u] = count ; #if MYDEBUG > 1 fprintf(stdout, "\n setting stage of %d to be %d", u, count) ; #endif } } #if MYDEBUG > 0 fprintf(stdout, "\n stages") ; fprintf(stdout, "\n %d", nvtx) ; IVfp80(stdout, nvtx, stages, 80, &ierr) ; #endif /* ------------------------ free the working storage ------------------------ */ IVfree(domids) ; IVfree(list) ; IVfree(dmark) ; IVfree(vmark) ; IVfree(dist) ; return ; } /*--------------------------------------------------------------------*/ Graph/drivers/do_checkComponents010075500020550007177000000004000657427057300203540ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inFile = $matrices/$matrix/orig0.graphf set inFile = /local1/ARPA/matrices/i4a/orig1.graphb set msglvl = 1 set msgFile = stdout checkComponents $msglvl $msgFile $inFile Graph/drivers/do_compressGraph010075500020550007177000000013320657426631200200470ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set matrices = ../../../matrices set matrix = BCELL14 set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig0.graphb set inGraphFile = /local1/ARPA/matrices/i4a/orig0.graphb set coarseType = 1 set outGraphFile = none set outGraphFile = $matrices/$matrix/orig$coarseType.graphb set outGraphFile = /local1/ARPA/matrices/i4a/orig1.graphb set outMapFile = none set outMapFile = $matrices/$matrix/map$coarseType.ivb set outMapFile = /local1/ARPA/matrices/i4a/map$coarseType.ivb set msglvl = 1 set msgFile = stdout compressGraph $msglvl $msgFile \ $inGraphFile $coarseType $outMapFile $outGraphFile Graph/drivers/do_expandGraph010075500020550007177000000005510654276061700174770ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = BCSSTK24 set inGraphFile = $matrices/$matrix/orig1.graphf set outGraphFile = $matrices/$matrix/orig0.graphf set outGraphFile = none set inMapFile = $matrices/$matrix/eqmap.ivf set msglvl = 1 set msgFile = stdout expandGraph $msglvl $msgFile \ $inGraphFile $inMapFile $outGraphFile Graph/drivers/do_mkGridGraph010075500020550007177000000006020663354533100174250ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 3 set msgFile = stdout set stencil = 9 set n1 = 10 set n2 = 1 set n3 = 1 set matrices = ../../Matrices set matrix = GRD15x15x15 set matrix = GRD7x7x7 set matrices = ../../../matrices set matrix = TRI10 set outFile = none set outFile = $matrices/$matrix/orig0.graphf mkGridGraph $msglvl $msgFile $stencil $n1 $n2 $n3 $outFile Graph/drivers/do_testChacoIO010075500020550007177000000006370661666162200174060ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set matrices = ../../../matrices set matrix = metisExample set matrix = kartik set inFile = $matrices/$matrix/graph11.metis set inFile = $matrices/$matrix/kartik.chaco set outFile = $matrices/$matrix/orig0.graphb set outFile = none set msglvl = 5 set msgFile = stdout testChacoIO $msglvl $msgFile $inFile $outFile Graph/drivers/do_testIO010075500020550007177000000006210654517020000164250ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inFile = $matrices/$matrix/orig0.graphf set outFile = $matrices/$matrix/orig0.graphb set outFile = none set matrix = BCSSTK24 set inFile = $matrices/$matrix/orig1.graphb set outFile = $matrices/$matrix/orig1.graphf set outFile = none set msglvl = 1 set msgFile = stdout testIO $msglvl $msgFile $inFile $outFile Graph/drivers/do_testIsSymmetric010075500020550007177000000003140654517020600203730ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = BCSSTK24 set msglvl = 3 set msgFile = stdout set inFile = $matrices/$matrix/orig1.graphf testIsSymmetric $msglvl $msgFile $inFile Graph/drivers/do_testWirebasket010075500020550007177000000013770660524062000202300ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = BCSSTK24 set matrices = ../../../matrices set matrix = R10KV set msglvl = 1 set msgFile = stdout set inGraphFile = $matrices/$matrix/orig1.graphf set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig0.graphb set inStagesFile = $matrices/$matrix/bkl.ivf set inStagesFile = $matrices/$matrix/ddstages0.ivf set inStagesFile = $matrices/$matrix/fishnet.ivf set inStagesFile = $matrices/$matrix/ndms.ivf set outStagesFile = $matrices/$matrix/stages.ivf set outStagesFile = none set radius = 2 set outStagesFile = $matrices/$matrix/wirebasket$radius.ivf testWirebasket $msglvl $msgFile \ $inGraphFile $inStagesFile $outStagesFile $radius Graph/drivers/do_writeMetisFile010075500020550007177000000004550654517023100201630ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inFile = $matrices/$matrix/orig0.graphf set outFile = $matrices/$matrix/metis.graph set outFile = metis.graph set outFile = none set msglvl = 3 set msgFile = stdout writeMetisFile $msglvl $msgFile $inFile $outFile Graph/drivers/makefile010064400020550007177000000026310665314247300163240ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = checkComponents \ compressGraph \ expandGraph \ mkGridGraph \ testIO \ testIsSymmetric \ testWirebasket\ writeMetisFile drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} checkComponents : checkComponents.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} compressGraph : compressGraph.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} expandGraph : expandGraph.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} mkGridGraph : mkGridGraph.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testChacoIO : testChacoIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testIO : testIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testIsSymmetric : testIsSymmetric.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testWirebasket : testWirebasket.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} writeMetisFile : writeMetisFile.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} writeAIJ : writeAIJ.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} ckComponents.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} compressGraphGraph/drivers/checkComponents.c010064400020550007177000000064160654026372200201140ustar00clevecompmath00000400000006/* checkComponents.c */ #include "../Graph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------------------------- read in a Graph and check for connected components created -- 96fmar02, cca -------------------------------------------------- */ { char *inGraphFileName ; double t1, t2 ; int icomp, msglvl, ncomp, rc, v ; int *counts, *weights ; IV *mapIV ; Graph *g ; FILE *msgFile ; if ( argc != 4 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } g = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(g, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, g, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(g, msgFile) ; } else { Graph_writeStats(g, msgFile) ; } fflush(msgFile) ; /* --------------------------------------- get the map from vertices to components --------------------------------------- */ MARKTIME(t1) ; mapIV = Graph_componentMap(g) ; MARKTIME(t2) ; ncomp = 1 + IV_max(mapIV) ; fprintf(msgFile, "\n CPU %9.5f : find %d components", t2 - t1, ncomp) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n component map") ; IV_writeForHumanEye(mapIV, msgFile) ; } /* ------------------------------------ get the statistics on the components ------------------------------------ */ counts = IVinit(ncomp, 0) ; weights = IVinit(ncomp, 0) ; MARKTIME(t1) ; Graph_componentStats(g, IV_entries(mapIV), counts, weights) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : compute component statistics", t2 - t1) ; fprintf(msgFile, "\n\n component # vertices weight") ; for ( icomp = 0 ; icomp < ncomp ; icomp++ ) { fprintf(msgFile, "\n %7d %7d %7d", icomp, counts[icomp], weights[icomp]) ; } /* ---------------- free the storage ---------------- */ Graph_free(g) ; IV_free(mapIV) ; IVfree(counts) ; IVfree(weights) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Graph/drivers/compressGraph.c010064400020550007177000000114610654026410700176000ustar00clevecompmath00000400000006/* compressGraph.c */ #include "../Graph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- 1) read in graph 2) get the equivalence map 3) optionally write out equivalence map 4) get compressed graph 5) optionally write out compressed graph map created -- 95mar02, cca ------------------------------------------------- */ { char *inGraphFileName, *outIVfileName, *outGraphFileName ; double t1, t2 ; int coarseType, msglvl, rc ; Graph *gc, *gf ; FILE *msgFile ; IV *mapIV ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile " "\n coarseType outMapFile outGraphFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file for graph" "\n must be *.graphf or *.graphb" "\n coarseType -- type for compressed graph" "\n outMapFile -- output file for map vector" "\n must be *.ivf or *.ivb" "\n outGraphFile -- output file for compressed graph" "\n must be *.graphf or *.graphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; coarseType = atoi(argv[4]) ; outIVfileName = argv[5] ; outGraphFileName = argv[6] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n coarseType -- %d" "\n outMapFile -- %s" "\n outGraphFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, coarseType, outIVfileName, outGraphFileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; gf = Graph_new() ; rc = Graph_readFromFile(gf, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, gf, inGraphFileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; Graph_writeForHumanEye(gf, msgFile) ; fflush(msgFile) ; } else { Graph_writeStats(gf, msgFile) ; fflush(msgFile) ; } /* ----------------------- get the equivalence map ----------------------- */ MARKTIME(t1) ; mapIV = Graph_equivMap(gf) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : create equivalence map", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n equivalence map IV object") ; IV_writeForHumanEye(mapIV, msgFile) ; fflush(msgFile) ; } /* --------------------------- write out the map IV object --------------------------- */ if ( strcmp(outIVfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(mapIV, outIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write map IV to file %s", t2 - t1, outIVfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_writeToFile(%p,%s)", rc, mapIV, outIVfileName) ; } } /* ------------------------ get the compressed graph ------------------------ */ MARKTIME(t1) ; gc = Graph_compress(gf, IV_entries(mapIV), coarseType) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : compress the graph", t2 - t1) ; fprintf(msgFile, "\n\n compressed graph") ; if ( msglvl > 2 ) { Graph_writeForHumanEye(gc, msgFile) ; fflush(msgFile) ; } else { Graph_writeStats(gc, msgFile) ; fflush(msgFile) ; } /* -------------------------- write out the Graph object -------------------------- */ if ( strcmp(outGraphFileName, "none") != 0 ) { MARKTIME(t1) ; rc = Graph_writeToFile(gc, outGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write compressed graph to file %s", t2 - t1, outGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_writeToFile(%p,%s)", rc, gc, outGraphFileName) ; exit(-1) ; } } /* ---------------- free the objects ---------------- */ Graph_free(gf) ; Graph_free(gc) ; IV_free(mapIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Graph/drivers/expandGraph.c010064400020550007177000000110040654026435600172230ustar00clevecompmath00000400000006/* expandGraph.c */ #include "../Graph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------ 1) read in graph 2) read in the expand map 4) get expanded graph 5) optionally write out expanded graph map created -- 95mar02, cca ------------------------------------------ */ { char *inGraphFileName, *inIVfileName, *outGraphFileName ; double t1, t2 ; int msglvl, rc ; Graph *gc, *gf ; FILE *msgFile ; IV *mapIV ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile " "\n inMapFile outGraphFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file for graph" "\n must be *.graphf or *.graphb" "\n inMapFile -- output file for map vector" "\n must be *.ivf or *.ivb" "\n outGraphFile -- output file for compressed graph" "\n must be *.graphf or *.graphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; inIVfileName = argv[4] ; outGraphFileName = argv[5] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n inMapFile -- %s" "\n outGraphFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, inIVfileName, outGraphFileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; gc = Graph_new() ; rc = Graph_readFromFile(gc, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, gc, inGraphFileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; Graph_writeForHumanEye(gc, msgFile) ; fflush(msgFile) ; } else { Graph_writeStats(gc, msgFile) ; fflush(msgFile) ; } /* --------------------- read in the IV object --------------------- */ if ( strcmp(inIVfileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; mapIV = IV_new() ; rc = IV_readFromFile(mapIV, inIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in IV from file %s", t2 - t1, inIVfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, mapIV, inIVfileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading IV object from file %s", inIVfileName) ; IV_writeForHumanEye(mapIV, msgFile) ; fflush(msgFile) ; } else { IV_writeStats(mapIV, msgFile) ; fflush(msgFile) ; } /* ------------------------- create the expanded graph ------------------------- */ MARKTIME(t1) ; gf = Graph_expand2(gc, mapIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : create expanded graph", t2 - t1) ; fprintf(msgFile, "\n\n expanded Graph object") ; if ( msglvl > 2 ) { Graph_writeForHumanEye(gf, msgFile) ; fflush(msgFile) ; } else { Graph_writeStats(gf, msgFile) ; fflush(msgFile) ; } /* ----------------------------------- write out the expanded Graph object ----------------------------------- */ if ( strcmp(outGraphFileName, "none") != 0 ) { MARKTIME(t1) ; rc = Graph_writeToFile(gf, outGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write expanded graph to file %s", t2 - t1, outGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_writeToFile(%p,%s)", rc, gf, outGraphFileName) ; } } /* ---------------- free the objects ---------------- */ Graph_free(gf) ; Graph_free(gc) ; IV_free(mapIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Graph/drivers/mkGridGraph.c010064400020550007177000000177730654026515200171770ustar00clevecompmath00000400000006/* mkGridGraph.c */ #include "../Graph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- generate a Graph object for a grid created -- 96mar15, cca ------------------------------------------------- */ { char *outFileName ; double t1, t2 ; FILE *msgFile ; Graph *graph ; int count, msglvl, i, ij, ijk, imax, imin, inow, j, jmax, jmin, jnow, k, kmax, kmin, know, nvtx, n1, n2, n3, rc, stencil ; int *list ; IVL *adjIVL ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile stencil n1 n2 n3 outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n stencil -- type of stencil, 5, 9, 27 or 13" "\n n1 -- # of grid points in first dimension" "\n n2 -- # of grid points in second dimension" "\n n3 -- # of grid points in third dimension" "\n outFile -- output file, must be *.graphf or *.graphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } stencil = atoi(argv[3]) ; switch ( stencil ) { case 5 : case 7 : case 9 : case 13 : case 27 : break ; default : fprintf(stderr, "\n fatal error in mkGridGraph" "\n stencil = %d, must be 5, 7, 9, 13 or 27\n", stencil) ; exit(-1) ; } n1 = atoi(argv[4]) ; n2 = atoi(argv[5]) ; n3 = atoi(argv[6]) ; if ( n1 < 1 || n2 < 1 || n3 < 1 ) { fprintf(stderr, "\n fatal error in mkGridGraph" "\n n1 = %d, n2 = %d, n3 = %d, all must be positive\n", n1, n2, n3) ; exit(-1) ; } nvtx = n1 * n2 * n3 ; outFileName = argv[7] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n stencil -- %d" "\n n1 -- %d" "\n n2 -- %d" "\n n3 -- %d" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], stencil, n1, n2, n3, outFileName) ; fflush(msgFile) ; /* ---------------------- set the default fields ---------------------- */ graph = Graph_new() ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after setting default fields") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* --------------------------- initialize the Graph object --------------------------- */ Graph_init1(graph, 0, nvtx, 0, 0, IVL_CHUNKED, IVL_CHUNKED) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } adjIVL = graph->adjIVL ; list = IVinit(nvtx, -1) ; switch ( stencil ) { case 5 : for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { ij = i + j * n1 ; count = 0 ; if ( j >= 1 ) { list[count++] = ij - n1 ; } if ( i >= 1 ) { list[count++] = ij - 1 ; } /* list[count++] = ij ; */ if ( i <= n1 - 2 ) { list[count++] = ij + 1 ; } if ( j <= n2 - 2 ) { list[count++] = ij + n1 ; } IVqsortUp(count, list) ; IVL_setList(adjIVL, ij, count, list) ; } } break ; case 7 : for ( k = 0 ; k < n3 ; k++ ) { for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { ijk = i + j*n1 + k*n1*n2 ; count = 0 ; if ( k >= 1 ) { list[count++] = ijk - n1*n2 ; } if ( j >= 1 ) { list[count++] = ijk - n1 ; } if ( i >= 1 ) { list[count++] = ijk - 1 ; } list[count++] = ijk ; if ( i <= n1 - 2 ) { list[count++] = ijk + 1 ; } if ( j <= n2 - 2 ) { list[count++] = ijk + n1 ; } if ( k <= n3 - 2 ) { list[count++] = ijk + n1*n2 ; } IVqsortUp(count, list) ; IVL_setList(adjIVL, ijk, count, list) ; } } } break ; case 9 : for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { ij = i + j * n1 ; count = 0 ; if ( j >= 1 ) { if ( i >= 1 ) { list[count++] = ij - n1 - 1 ; } list[count++] = ij - n1 ; if ( i <= n1 - 2 ) { list[count++] = ij - n1 + 1 ; } } if ( i >= 1 ) { list[count++] = ij - 1 ; } list[count++] = ij ; if ( i <= n1 - 2 ) { list[count++] = ij + 1 ; } if ( j <= n2 - 2 ) { if ( i >= 1 ) { list[count++] = ij + n1 - 1 ; } list[count++] = ij + n1 ; if ( i <= n1 - 2 ) { list[count++] = ij + n1 + 1 ; } } IVqsortUp(count, list) ; IVL_setList(adjIVL, ij, count, list) ; } } break ; case 13 : for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { ij = i + j * n1 ; count = 0 ; if ( j >= 2 ) { list[count++] = ij - 2*n1 ; } if ( j >= 1 ) { if ( i >= 1 ) { list[count++] = ij - n1 - 1 ; } list[count++] = ij - n1 ; if ( i <= n1 - 2 ) { list[count++] = ij - n1 + 1 ; } } if ( i >= 2 ) { list[count++] = ij - 2 ; } if ( i >= 1 ) { list[count++] = ij - 1 ; } list[count++] = ij ; if ( i <= n1 - 2 ) { list[count++] = ij + 1 ; } if ( i <= n1 - 3 ) { list[count++] = ij + 2 ; } if ( j <= n2 - 2 ) { if ( i >= 1 ) { list[count++] = ij + n1 - 1 ; } list[count++] = ij + n1 ; if ( i <= n1 - 2 ) { list[count++] = ij + n1 + 1 ; } } if ( j <= n2 - 3 ) { list[count++] = ij + 2*n1 ; } IVqsortUp(count, list) ; IVL_setList(adjIVL, ij, count, list) ; } } break ; case 27 : for ( k = 0 ; k < n3 ; k++ ) { kmin = (k > 0) ? k-1 : k ; kmax = (k < n3-1) ? k+1 : k ; for ( j = 0 ; j < n2 ; j++ ) { jmin = (j > 0) ? j-1 : j ; jmax = (j < n2-1) ? j+1 : j ; for ( i = 0 ; i < n1 ; i++ ) { ijk = i + j*n1 + k*n1*n2 ; imin = (i > 0) ? i-1 : i ; imax = (i < n1-1) ? i+1 : i ; for ( know = kmin, count = 0 ; know <= kmax ; know++ ) { for ( jnow = jmin ; jnow <= jmax ; jnow++ ) { for ( inow = imin ; inow <= imax ; inow++ ) { list[count++] = inow + jnow*n1 + know*n1*n2 ; } } } IVqsortUp(count, list) ; IVL_setList(adjIVL, ijk, count, list) ; } } } break ; default : break ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n ") ; Graph_writeForHumanEye(graph, msgFile) ; } /* -------------------------- write out the Graph object -------------------------- */ if ( strcmp(outFileName, "none") != 0 ) { MARKTIME(t1) ; rc = Graph_writeToFile(graph, outFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write graph to file %s", t2 - t1, outFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_writeToFile(%p,%s)", rc, graph, outFileName) ; } } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; IVfree(list) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ist[cGraph/drivers/test1.c010064400020550007177000000016260661665356100160370ustar00clevecompmath00000400000006/* test1.c */ #include /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { char ctemp ; FILE *fp ; int itemp, rc ; if ( argc != 2 ) { fprintf(stdout, "\n usage : filename") ; return(0) ; } if ( (fp = fopen(argv[1], "r")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[1]) ; } /* --------------- check the input --------------- */ while ( 1 ) { rc = fscanf(fp, "%d%c", &itemp, &ctemp) ; if ( rc != 2 ) { fprintf(stdout, "\n error, rc = %d", rc) ; break ; } fprintf(stdout, "\n itemp = '%d', ctemp = '%c'", itemp, ctemp) ; if ( ctemp == '\n' ) { fprintf(stdout, "\n newline") ; } if ( ctemp == EOF ) { fprintf(stdout, "\n end of file") ; break ; } } return(1) ; } /*--------------------------------------------------------------------*/ Graph/drivers/testChacoIO.c010064400020550007177000000057110661665741600171460ustar00clevecompmath00000400000006/* testChacoIO.c */ #include "../Graph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- test Graph_readFromChacoFile, useful for translating between Chaco/Metis files and formatted *.graphf and binary *.graphb files. created -- 98oct31, cca ------------------------------------------------- */ { char *inGraphFileName, *outGraphFileName ; double t1, t2 ; int msglvl, rc ; Graph *graph ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.graphf or *.graphb" "\n outFile -- output file, must be *.graphf or *.graphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; outGraphFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, outGraphFileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromChacoFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromChacoFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* -------------------------- write out the Graph object -------------------------- */ if ( strcmp(outGraphFileName, "none") != 0 ) { MARKTIME(t1) ; rc = Graph_writeToFile(graph, outGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write graph to file %s", t2 - t1, outGraphFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_writeToFile(%p,%s)", rc, graph, outGraphFileName) ; } /* --------------------- free the Graph object --------------------- */ Graph_free(graph) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Graph/drivers/testIO.c010064400020550007177000000056420654026533000161750ustar00clevecompmath00000400000006/* testIO.c */ #include "../Graph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- test Graph_readFromFile and Graph_writeToFile, useful for translating between formatted *.graphf and binary *.graphb files. created -- 96fmar02, cca ------------------------------------------------- */ { char *inGraphFileName, *outGraphFileName ; double t1, t2 ; int msglvl, rc ; Graph *graph ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.graphf or *.graphb" "\n outFile -- output file, must be *.graphf or *.graphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; outGraphFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, outGraphFileName) ; fflush(msgFile) ; /* ---------------------- read in the Graph object ---------------------- */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* ------------------------ write out the Graph object ------------------------ */ if ( strcmp(outGraphFileName, "none") != 0 ) { MARKTIME(t1) ; rc = Graph_writeToFile(graph, outGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write graph to file %s", t2 - t1, outGraphFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_writeToFile(%p,%s)", rc, graph, outGraphFileName) ; } /* --------------------- free the Graph object --------------------- */ Graph_free(graph) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Graph/drivers/testIsSymmetric.c010064400020550007177000000047710654026544100201430ustar00clevecompmath00000400000006/* testIsSymmetric.c */ #include "../Graph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------- check to see whether a graph is symmetric created -- 96oct31, cca ----------------------------------------- */ { char *inGraphFileName ; double t1, t2 ; int msglvl, rc ; Graph *graph ; FILE *msgFile ; if ( argc != 4 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.graphf or *.graphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName) ; fflush(msgFile) ; /* ---------------------- read in the Graph object ---------------------- */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* ------------------------------------------- check to see whether the graph is symmetric ------------------------------------------- */ rc = Graph_isSymmetric(graph) ; if ( rc == 1 ) { fprintf(msgFile, "\n graph is symmetric") ; } else { fprintf(msgFile, "\n graph is not symmetric") ; } /* --------------------- free the Graph object --------------------- */ Graph_free(graph) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Graph/drivers/testWirebasket.c010064400020550007177000000124020660524230300177530ustar00clevecompmath00000400000006/* testWirebasket.c */ #include "../Graph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- read in a Graph and a stages id IV object, replace the stages IV object with wirebasket stages created -- 97jul30, cca --------------------------------------------------- */ { char *inCompidsFileName, *inGraphFileName, *outStagesIVfileName ; double t1, t2 ; Graph *graph ; int msglvl, nvtx, radius, rc, v ; int *compids, *stages ; IV *compidsIV, *stagesIV ; FILE *msgFile ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile inStagesFile " "\n outStagesFile radius" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n inStagesFile -- output file, must be *.ivf or *.ivb" "\n outStagesFile -- output file, must be *.ivf or *.ivb" "\n radius -- radius to set the stage " "\n of a separator vertex" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; inCompidsFileName = argv[4] ; outStagesIVfileName = argv[5] ; radius = atoi(argv[6]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n inStagesFile -- %s" "\n outStagesFile -- %s" "\n radius -- %d" "\n", argv[0], msglvl, argv[2], inGraphFileName, inCompidsFileName, outStagesIVfileName, radius) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* --------------------- read in the IV object --------------------- */ if ( strcmp(inCompidsFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } compidsIV = IV_new() ; MARKTIME(t1) ; rc = IV_readFromFile(compidsIV, inCompidsFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in compidsIV from file %s", t2 - t1, inCompidsFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, compidsIV, inCompidsFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading IV object from file %s", inCompidsFileName) ; if ( msglvl > 2 ) { IV_writeForHumanEye(compidsIV, msgFile) ; } else { IV_writeStats(compidsIV, msgFile) ; } fflush(msgFile) ; IV_sizeAndEntries(compidsIV, &nvtx, &compids) ; /* ---------------------------- convert to the stages vector ---------------------------- */ stagesIV = IV_new() ; IV_init(stagesIV, nvtx, NULL) ; stages = IV_entries(stagesIV) ; for ( v = 0 ; v < nvtx ; v++ ) { if ( compids[v] == 0 ) { stages[v] = 1 ; } else { stages[v] = 0 ; } } /* for ( v = 0 ; v < nvtx ; v++ ) { if ( compids[v] == 0 ) { stages[v] = 0 ; } else { stages[v] = 1 ; } } */ /* ------------------------- get the wirebasket stages ------------------------- */ Graph_wirebasketStages(graph, stagesIV, radius) ; IV_sizeAndEntries(stagesIV, &nvtx, &stages) ; for ( v = 0 ; v < nvtx ; v++ ) { if ( stages[v] == 2 ) { stages[v] = 1 ; } else if ( stages[v] > 2 ) { stages[v] = 2 ; } } fprintf(msgFile, "\n\n new stages IV object") ; if ( msglvl > 2 ) { IV_writeForHumanEye(stagesIV, msgFile) ; } else { IV_writeStats(stagesIV, msgFile) ; } fflush(msgFile) ; /* --------------------------- write out the stages object --------------------------- */ if ( strcmp(outStagesIVfileName, "none") != 0 ) { MARKTIME(t1) ; IV_writeToFile(stagesIV, outStagesIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write stagesIV to file %s", t2 - t1, outStagesIVfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_writeToFile(%p,%s)", rc, stagesIV, outStagesIVfileName) ; } } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; IV_free(stagesIV) ; IV_free(compidsIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ mp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileNGraph/drivers/writeAIJ.c010064400020550007177000000066560663234523700164610ustar00clevecompmath00000400000006/* writeAIJ.c */ #include "../Graph.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- read in a Graph and write out an AIJ file nrow ncol nent row col entry ... created -- 98dec05, cca ------------------------------------------------- */ { char *inGraphFileName, *outFileName ; double t1, t2 ; Drand *drand ; int ii, msglvl, nedges, nvtx, rc, v, vsize, w ; int *vadj ; Graph *graph ; FILE *msgFile, *outFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFileName" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.graphf or *.graphb" "\n outFile -- output file" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; outFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, outFileName) ; fflush(msgFile) ; /* ---------------------- read in the Graph object ---------------------- */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new(); Drand_setSeed(drand, 47) ; Drand_setUniform(drand, -1., 1.) ; /* -------------------------- write out the AIJ entries -------------------------- */ if ( strcmp(outFileName, "stdout") == 0 ) { outFile = stdout ; } else if ( (outFile = fopen(outFileName, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], outFile) ; return(-1) ; } nvtx = graph->nvtx ; nedges = graph->nedges ; fprintf(outFile, "\n %d %d %d", nvtx, nvtx, nvtx + (nedges-nvtx)/2) ; for ( v = 0 ; v < nvtx ; v++ ) { Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( v <= w ) { fprintf(outFile, "\n %8d %8d %20.12e", v, w, Drand_value(drand)) ; } } } fclose(outFile) ; /* --------------------- free the Graph object --------------------- */ Graph_free(graph) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Graph/drivers/writeMetisFile.c010064400020550007177000000061000654026611700177140ustar00clevecompmath00000400000006/* writeMetisFile.c */ #include "../Graph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- read in a graph and write it out as a Metis File created -- 97apr03, cca ------------------------------------------------- */ { char *inGraphFileName, *outGraphFileName ; double t1, t2 ; FILE *fp, *msgFile ; int msglvl, rc ; Graph *graph ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.graphf or *.graphb" "\n outFile -- output file for a metis file" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; outGraphFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, outGraphFileName) ; fflush(msgFile) ; /* ---------------------- read in the Graph object ---------------------- */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* -------------------------- write out the Graph object -------------------------- */ if ( strcmp(outGraphFileName, "none") != 0 ) { if ( (fp = fopen(outGraphFileName, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], outGraphFileName) ; return(-1) ; } MARKTIME(t1) ; rc = Graph_writeToMetisFile(graph, fp) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write graph to file %s", t2 - t1, outGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_writeToMetisFile(%p,%s)", rc, graph, outGraphFileName) ; } } /* --------------------- free the Graph object --------------------- */ Graph_free(graph) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Graph/doc/004275500020550007177000000000000654276740000137165ustar00clevecompmath00000400000006Graph/doc/dataStructure.tex010064400020550007177000000017520653410610500172600ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:Graph:dataStructure} \par The {\tt Graph} structure has nine fields. \begin{itemize} \item {\tt int type} : type of graph \qquad % \begin{center} \begin{tabular}{|c|c|c|} \hline {\tt type} & vertices weighted? & edges weighted? \\ \hline 0 & no & no \\ 1 & yes & no \\ 2 & no & yes \\ 3 & yes & yes \\ \hline \end{tabular} % \end{center} \item {\tt int nvtx } : number of internal vertices \item {\tt int nvbnd } : number of boundary vertices \item {\tt int nedges } : number of edges \item {\tt int totvwght } : total vertex weight \item {\tt int totewght } : total edge weight \item {\tt IVL *adjIVL} : pointer to {\tt IVL} object to hold adjacency lists \item {\tt int *vwghts} : pointer to a vertex to hold vertex weights non-{\tt NULL} if {\tt type \% 2 == 1} \item {\tt IVL *ewghtIVL} : pointer to {\tt IVL} object to hold edge weight lists, non-{\tt NULL} if {\tt type / 2 == 1} \end{itemize} Graph/doc/intro.tex010064400020550007177000000076670665023016100155730ustar00clevecompmath00000400000006\par \chapter{{\tt Graph}: A Graph object} \label{chapter:Graph} \par The {\tt Graph} object is used to represent the graph of a matrix. The representation uses a set of adjacency lists, one edge list for each vertex in the graph, and is implemented using an {\tt IVL} object.\footnote{ The {\tt EGraph} object represents a graph of the matrix, but stores a list of covering cliques in an {\tt IVL} object. } For the {\tt Graph} object, the vertices and the edges can be either unit weight or non-unit weight independently. None of the algorithms in the package {\it at present} use weighted edges, though most use weighted vertices. The weighted edges capability is there, and the weighted edges are also stored using an {\tt IVL} object. \par The {\tt Graph} object is not too sophisticated, i.e., we chose {\bf not} to implement a method to find a separator of a graph inside this object. Such complex functionality is best left to higher level objects, and our method based on domain decomposition \cite{ash97-DDSEP} is found in the {\tt GPart} object. \par A graph can also be a subgraph of another graph --- nested dissection is the natural recursive partition of a graph --- and it pays to use the knowledge of the boundary of a subgraph. We chose not to implement a ``sub''-graph object separately from a graph object, thus our {\tt Graph} object can have a boundary. One specifies {\tt nvtx}, the number of internal vertices, and {\tt nvbnd}, the number of external or boundary vertices. The labels for internal vertices are found in {\tt [0, nvtx)} and those for boundary vertices are found in {\tt [nvtx, nvtx+nvbnd)}. \par It is easy to create a {\tt Graph} object: one specifies the number of internal and boundary vertices, the type of graph (weighted or unit weight vertices and edges), and then uses the methods for the {\tt IVL} object to add adjacency lists and (possibly) lists of edge weights. The {\tt Graph} object relies strongly on the {\tt IVL} object. \par Weighted graphs are commonly used in partitioning and ordering algorithm, and they normally arise from {\it compressing} the graph in some manner. Let us write the unit weight graph as $G(V,E)$ and the weighted graph as ${\bf G}({\bf V}, {\bf E})$, and let $\phi : V \mapsto {\bf V}$ be the map from unit weight vertices to weighted vertices. Let $u$ and $v$ be vertices and $(u,v)$ be an edge in $G(V,E)$, and let ${\bf u}$ and ${\bf v}$ be vertices and $({\bf u},{\bf v})$ be an edge in ${\bf G}({\bf V}, {\bf E})$. The weight of a vertex is $w({\bf u})$, the number of unit weight vertices in the weighted vertex. The weight of an edge is $w({\bf u},{\bf v})$, the number of $(u,v)$ edges in the unit weight graph where $u \in {\bf u}$ and $v \in {\bf v}$. \par The natural compressed graph \cite{ash95-compressed-graphs}, \cite{dam92-compressed} is very important for many matrices from structral analysis and computational fluid mechanics. This type of graph has one special property: $$ w({\bf u}, {\bf v}) = w({\bf u}) \cdot w({\bf v}) $$ and it is the smallest graph with this property. The compression is {\it loss-less}, for given ${\bf G}({\bf V},{\bf E})$ and $\phi$, we can reconstruct the unit weight graph $G(V,E)$. In effect, we can work with the natural compressed graph to find separators and orderings and map back to the unit weight graph. The savings in time and space can be considerable. \par The {\tt Graph} object has a method to find the $\phi$ map for the natural compressed graph; it requires $O(|V|)$ space and $O(|E|)$ time. There is a method to compress a graph (i.e., given $G(V,E)$ and an arbitrary $\phi$, construct ${\bf G}({\bf V}, {\bf E})$) and a method to expand a graph (i.e., given ${\bf G}({\bf V},{\bf E})$ and an arbitrary $\phi$, construct $G(V, E)$). \par There are several utility methods to return information about the memory in use by the {\tt Graph object}, to access adjacency lists and edge weight lists, and to provide information about the connected components of a graph. Graph/doc/main.tex010064400020550007177000000011150665065623200153550ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \input psfig \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Graph} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Graph} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} Graph/doc/proto.tex010064400020550007177000000556200665017540200156010ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Graph} methods} \label{section:Graph:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Graph} object. \par \subsection{Basic methods} \label{subsection:Graph:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Graph * Graph_new ( void ) ; \end{verbatim} \index{Graph_new@{\tt Graph\_new()}} This method simply allocates storage for the {\tt Graph} structure and then sets the default fields by a call to {\tt Graph\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Graph_setDefaultFields ( Graph *graph ) ; \end{verbatim} \index{Graph_setDefaultFields@{\tt Graph\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt type}, {\tt nvtx}, {\tt nvbnd}, {\tt nedges}, {\tt totwght} and {\tt totewght} are all zero, and {\tt adjIVL}, {\tt vwghts} and {\tt ewghtIVL} are all {\tt NULL}. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Graph_clearData ( Graph *graph ) ; \end{verbatim} \index{Graph_clearData@{\tt Graph\_clearData()}} This method clears the data for the object. If {\tt adjIVL} is not {\tt NULL}, then {\tt IVL\_free(adjIVL)} is called to free the {\tt IVL} object. If {\tt ewghtIVL} is not {\tt NULL}, then {\tt IVL\_free(ewghtIVL)} is called to free the {\tt IVL} object. If {\tt vwghts} is not {\tt NULL}, then {\tt IVfree(vwghts)} is called to free the {\tt int} vector. The structure's fields are then set to their default values with a call to {\tt Graph\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Graph_free ( Graph *graph ) ; \end{verbatim} \index{Graph_free@{\tt Graph\_free()}} This method releases any storage by a call to {\tt Graph\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:Graph:proto:initializers} \par There are three initializer methods. The first is most commonly used, the second is used within the IO routines, and the third is used to create a {\tt Graph} object from the {\tt offsets[]/adjncy[]} format for the adjacency structure. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Graph_init1 ( Graph *graph, int type, int nvtx, int nvbnd, int nedges, int adjType, int ewghtType ) ; \end{verbatim} \index{Graph_init1@{\tt Graph\_init1()}} This is the basic initializer method. Any previous data is cleared with a call to {\tt Graph\_clearData()}. Then the scalar fields are set and the {\tt adjIVL} object is initialized. If {\tt type} is {\tt 1} or {\tt 3}, the {\tt vwghts} vector is initialized to zeros. If {\tt type} is {\tt 2} or {\tt 3}, the {\tt ewghtIVL} object is initialized. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, {\tt type} is invalid ({\tt type} must be in {\tt [0,3]}), {\tt nvtx} is non-positive, {\tt nvbnd} or {\tt nedges} is negative, or {\tt adjType} of {\tt ewghtType} is invalid (they must be {\tt IVL\_CHUNKED}, {\tt IVL\_SOLO} or {\tt IVL\_UNKNOWN}). an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Graph_init2 ( Graph *graph, int type, int nvtx, int nvbnd, int nedges, int totvwght, int totewght, IVL *adjIVL, int *vwghts, IVL *ewghtIVL) \end{verbatim} \index{Graph_init2@{\tt Graph\_init2()}} This method is used by the IO read methods. When a {\tt Graph} object is read from a file, the {\tt IVL} object(s) must be initialized and then read in from the file. Therefore, we need an initialization method that allows us to set pointers to the {\tt IVL} objects and the {\tt vwghts} vector. Note, {\tt adjIVL}, {\tt vwghts} and {\tt ewghtIVL} are owned by the {\tt Graph} object and will be free'd when the {\tt Graph} object is free'd. \par \noindent {\it Error checking:} If {\tt graph} or {\tt adjIVL} is {\tt NULL}, {\tt type} is invalid ({\tt type} must be in {\tt [0,3]}), {\tt nvtx} is non-positive, {\tt nvbnd} or {\tt nedges} is negative, or if {\tt type \% 2 = 1} and {\tt vwghts} is {\tt NULL}, or if ${\tt type} \ge 2$ and {\tt ewghtIVL} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Graph_fillFromOffsets ( Graph *graph, int neqns, int offsets[], int adjncy[], int flag ) \end{verbatim} \index{Graph_fillFromOffsets@{\tt Graph\_fillFromOffsets()}} This method initializes the {\tt Graph} object using an adjacency structure, as is the storage format for a Harwell-Boeing matrix. The entries in list {\tt v} are found in {\tt adjncy[i1:i2]}, where {\tt i1 = offsets[v]} and {\tt i2 = offsets[v+1]-1}. The {\tt offsets[]} and {\tt adjncy[]} arrays are assumed to be zero-based (as are C-arrays), not one-based (as are Fortran arrays). If {\tt flag == 0} then the lists are simply loaded into the {\tt Graph} object. If {\tt flag == 1}, the adjacency structure must be upper, meaning that the list for {\tt v} contains entries that are greater than or equal to {\tt v}. The {\tt Graph} will have a full adjacency structure, including the {\tt (v,v)} edges. \par \noindent {\it Error checking:} If {\tt graph}, {\tt offsets} or {\tt adjncy} is {\tt NULL}, or if ${\tt neqns} \le 0$, or if ${\tt flag} < 0$ or if ${\tt flag} > 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Graph_setListsFromOffsets ( Graph *graph, int neqns, int offsets[], int adjncy[] ) ; \end{verbatim} \index{Graph_setListsFromOffsets@{\tt Graph\_setListsFromOffsets()}} This method initializes the {\tt Graph} object using a {\it full} adjacency structure. The entries in list {\tt v} are found in {\tt adjncy[i1:i2]}, where {\tt i1 = offsets[v]} and {\tt i2 = offsets[v+1]-1}. The {\tt offsets[]} and {\tt adjncy[]} arrays are assumed to be zero-based (as are C-arrays), not one-based (as are Fortran arrays). Use this method with caution --- the adjacency list for vertex {\tt v} must contain {\tt v} and {\it all} vertices it is adjacent to. Note, new storage for the adjacency lists is not allocated, the {\tt Graph} object's {\tt IVL} object points into the storage in {\tt adjncy[]}. \par \noindent {\it Error checking:} If {\tt graph}, {\tt offsets} or {\tt adjncy} is {\tt NULL}, or if ${\tt neqns} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Compress and Expand methods} \label{subsection:Graph:proto:compress} \par These three methods find an equivalence map for the natural compressed graph, compress a graph, and expand a graph. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IV * Graph_equivMap ( Graph *graph ) ; \end{verbatim} \index{Graph_equivMap@{\tt Graph\_equivMap()}} This method constructs the equivalence map from the graph to its natural compressed graph. The map $\phi : V \mapsto {\bf V}$ is then constructed (see the Introduction in this section) and put into an {\tt IV} object that is then returned. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL} or {\tt nvtx <= 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Graph * Graph_compress ( Graph *graph, int map[], int coarseType ) ; Graph * Graph_compress2 ( Graph *graph, IV *mapIV, int coarseType ) ; \end{verbatim} \index{Graph_compress@{\tt Graph\_compress()}} \index{Graph_compress2@{\tt Graph\_compress2()}} This {\tt Graph} and map objects ({\tt map[]} or {\tt mapIV}) are checked and if any errors are found, the appropriate message is printed and the program exits. The compressed graph object is constructed and returned. Note, the compressed graph does not have a boundary, even though the original graph may have one. \par \noindent {\it Error checking:} If {\tt graph}, {\tt map} or {\tt mapIV} is {\tt NULL}, or if ${\tt nvtx} \le 0$, or if ${\tt coarseType} < 0$, or if $ 3 < {\tt coarseType}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Graph * Graph_expand ( Graph *graph, int nvtxbig, int map[] ) ; Graph * Graph_expand2 ( Graph *graph, IV *mapIV ) ; \end{verbatim} \index{Graph_expand@{\tt Graph\_expand()}} \index{Graph_expand2@{\tt Graph\_expand2()}} This {\tt Graph} and map objects ({\tt map[]} or {\tt mapIV}) are checked and if any errors are found, the appropriate message is printed and the program exits. The expanded unit weight graph object is constructed and returned. \par \noindent {\it Error checking:} If {\tt graph}, {\tt map} or {\tt mapIV} is {\tt NULL}, or if ${\tt nvtxbig} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Wirebasket domain decomposition ordering} \label{subsection:Graph:proto:wirebasket} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Graph_wirebasketStages ( Graph *graph, IV *stagesIV, int radius ) ; \end{verbatim} \index{Graph_wirebasketStages@{\tt Graph\_wirebasketStages()}} This method is used to group the vertices into stages that is suitable for a wirebasket domain decomposition of a general graph. On input, {\tt stages[v] = 0} means that {\tt v} is in a domain. On output, {\tt stages[v]} contains the stage of elimination --- zero is for all vertices in the domains. If {\tt stages[v] > 0}, then it is the number of domains that are found within {\tt radius} edges of {\tt v}. \par \noindent {\it Error checking:} If {\tt graph} or {\tt stagesIV} is {\tt NULL}, or if {\tt radius < 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:Graph:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_sizeOf ( Graph *graph ) ; \end{verbatim} \index{Graph_sizeOf@{\tt Graph\_sizeOf()}} This method returns the number of bytes taken by this object. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Graph_externalDegree ( Graph *graph, int v ) ; \end{verbatim} \index{Graph_externalDegree@{\tt Graph\_externalDegree()}} This method returns the weight of $\mbox{adj}(\mbox{\tt v})$. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, or {\tt v} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_adjAndSize ( Graph *graph, int u, int *pusize, int **puadj) ; \end{verbatim} \index{Graph_adjAndSize@{\tt Graph\_adjAndSize()}} This method fills {\tt *pusize} with the size of the adjacency list for {\tt u} and {\tt *puadj} points to the start of the list vector. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, or if {\tt u < 0} or {\tt u >= nvtx} or if {\tt pusize} or {\tt puadj} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_adjAndEweights ( Graph *graph, int u, int *pusize, int **puadj, int **puewghts) ; \end{verbatim} \index{Graph_adjAndEweights@{\tt Graph\_adjAndEweights()}} This method fills {\tt *psize} with the size of the adjacency list, {\tt *puadj} points to the start of the list vector and {\tt *puewghts} points to the start of the edge weights vector. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, or if {\tt u < 0} or {\tt u >= nvtx} or if {\tt pusize}, {\tt puadj} or {\tt puewghts} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * Graph_componentMap ( Graph *graph ) ; \end{verbatim} \index{Graph_componentMap@{\tt Graph\_componentMap()}} This method computes and returns an IV object that holds a map from vertices to components. The values of the map vector are in the range {\tt [0, number of components)}. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL} then an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Graph_componentStats ( Graph *graph, int map[], int counts[], int weights[] ) ; \end{verbatim} \index{Graph_componentStats@{\tt Graph\_componentStats()}} This method computes some statistics about the components. The length of {\tt map} is {\tt nvtx}. The number of components is {\tt 1 + max(map)}, and the length of {\tt counts[]} and {\tt weights[]} must be as large as the number of components. On return, {\tt counts[icomp]} and {\tt weights[icomp]} are filled with the number of vertices and weight of the vertices in component {\tt icomp}, respectively. \par \noindent {\it Error checking:} If {\tt graph}, {\tt map}, {\tt counts} or {\tt weights} is {\tt NULL}, then an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Graph * Graph_subGraph ( Graph *graph, int icomp, int compids[], int **pmap ) ; \end{verbatim} \index{Graph_subGraph@{\tt Graph\_subGraph()}} This method is used by the graph partitioning methods. For a graph $G(V,E)$, a vertex separator $S \subset V$ is found which separates the subgraph induced by $V \setminus S$ into two or more connected components. We construct a new graph object for each component using this method. The {\tt compids[]} vector maps the internal vertices of the parent graph into components. This method extracts the subgraph associated with component {\tt icomp}. \par There is one key design feature. {\it Most of the storage for the adjacency lists of the subgraph is the same as its parent graph.} This keeps us from replicating too much storage. The subgraph has internal vertices and boundary vertices (the latter contain at least part of $S$.) Each adjacency list for an internal vertex of the subgraph points to the corresponding adjacency list for the vertex in the parent graph. Each adjacency list for a boundary vertex of the subgraph is new storage, and only these lists are free'd when the subgraph is free'd. A map vector is created that maps the subgraphs's vertices (both internal and boundary) into the parent graph's vertices; the address of the map vector is put into {\tt *pmap}. The adjacency lists for the subgraph are overwritten by the {\tt map[]} vector. This renders the graph object invalid. The graph partitioning methods map the vertices back to their original values. Presently, only graphs with unit edge weights are allowed as input. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL} or {\tt icomp < 0} or {\tt compids} or {\tt pmap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_isSymmetric ( Graph *graph ) ; \end{verbatim} \index{Graph_isSymmetric@{\tt Graph\_isSymmetric()}} This method returns {\tt 1} if the graph is symmetric (i.e., edge {\tt (i,j)} is present if and only if edge {\tt (j,i)} is present) and {\tt 0} otherwise. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:Graph:proto:IO} \par There are the usual eight IO routines. The file structure of a {\tt Graph} object is simple: The six scalar fields come first: {\tt type}, {\tt nvtx}, {\tt nvbnd}, {\tt nedges}, {\tt totvwght} and {\tt totewght}. The adjacency {\tt IVL} structure {\tt adjIVL} follows. If the graph has non-unit vertex weights, i.e., {\tt type \% 2 == 1}, the {\tt vwghts} vector follows. If the graph has non-unit edge weights, i.e., {\tt type / 2 == 1}, the {\tt IVL} structure {\tt ewghtIVL} follows. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_readFromFile ( Graph *graph, char *fn ) ; \end{verbatim} \index{Graph_readFromFile@{\tt Graph\_readFromFile()}} \par This method reads a {\tt Graph object} from a file. It tries to open the file and if it is successful, it then calls {\tt Graph\_readFromFormattedFile()} or {\tt Graph\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt graph} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.graphf} (for a formatted file) or {\tt *.graphb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_readFromFormattedFile ( Graph *graph, FILE *fp ) ; \end{verbatim} \index{Graph_readFromFormattedFile@{\tt Graph\_readFromFormattedFile()}} \par This method reads a {\tt Graph} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt graph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_readFromBinaryFile ( Graph *graph, FILE *fp ) ; \end{verbatim} \index{Graph_readFromBinaryFile@{\tt Graph\_readFromBinaryFile()}} This method reads a {\tt Graph} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt graph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_writeToFile ( Graph *graph, char *fn ) ; \end{verbatim} \index{Graph_writeToFile@{\tt Graph\_writeToFile()}} \par This method writes a {\tt Graph object} to a file. It tries to open the file and if it is successful, it then calls {\tt Graph\_writeFromFormattedFile()} or {\tt Graph\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt graph} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.graphf} (for a formatted file) or {\tt *.graphb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_writeToFormattedFile ( Graph *graph, FILE *fp ) ; \end{verbatim} \index{Graph_writeToFormattedFile@{\tt Graph\_writeToFormattedFile()}} \par This method writes a {\tt Graph} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt graph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_writeToBinaryFile ( Graph *graph, FILE *fp ) ; \end{verbatim} \index{Graph_writeToBinaryFile@{\tt Graph\_writeToBinaryFile()}} \par This method writes a {\tt Graph} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt graph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_writeForHumanEye ( Graph *graph, FILE *fp ) ; \end{verbatim} \index{Graph_writeForHumanEye@{\tt Graph\_writeForHumanEye()}} \par This method writes a {\tt Graph} object to a file in a human readable format. The method {\tt Graph\_writeStats()} is called to write out the header and statistics. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt graph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_writeStats ( Graph *graph, FILE *fp ) ; \end{verbatim} \index{Graph_writeStats@{\tt Graph\_writeStats()}} \par The header and statistics are written to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt graph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Graph_writeToMetisFile ( Graph *graph, FILE *fp ) ; \end{verbatim} \index{Graph_writeToMetisFile@{\tt Graph\_writeToMetisFile()}} \par This method writes a {\tt Graph} object to a file in the format of the {\bf METIS} or {\bf CHACO} packages. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt graph} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} weights()}} This method fills {\tt *psize} with the size of the adjacency list, {\tt *puadj} points to the startGraph/doc/main.log010064400020550007177000000123650654026634000153420ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 12 JUN 1998 11:01 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (/usr/local/lib/texmf/tex/generic/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen100 \p@intvaluey=\dimen101 psfig/tex 1.10-dvips ) (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 2. LaTeX Warning: Citation `ash95-DDSEP' on page 1 undefined on input line 24. LaTeX Warning: Citation `ash95-compressed-graphs' on page 1 undefined on input line 59. LaTeX Warning: Citation `dam92-compressed' on page 1 undefined on input line 60 . [1 ]) (dataStructure.tex) (proto.tex [2] Overfull \hbox (22.0743pt too wide) in paragraph at lines 92--100 []\elvrm This is the ba-sic ini-tial-izer method. Any pre-vi-ous data is cleare d with a call to \elvtt Graph[]clearData()\elvrm . \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\elvrm T .\elvrm h .\elvrm i .\elvrm s .etc. [3] [4] [5] Overfull \hbox (11.7664pt too wide) in paragraph at lines 360--360 [] []\elvtt Graph * Graph_subGraph ( Graph *graph, int icomp, int compids[], i nt **pmap ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. [6] [7]) (drivers.tex Overfull \hbox (19.63927pt too wide) in paragraph at lines 28--32 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. Overfull \hbox (19.63927pt too wide) in paragraph at lines 55--60 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. [8] Overfull \hbox (19.63927pt too wide) in paragraph at lines 105--110 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. [9] Overfull \hbox (19.63927pt too wide) in paragraph at lines 185--190 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. Overfull \hbox (15.38101pt too wide) in paragraph at lines 190--194 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is writ-ten to the file via the \elvtt Graph[]writeToFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. Overfull \hbox (19.63927pt too wide) in paragraph at lines 216--220 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. [10] Overfull \hbox (19.63927pt too wide) in paragraph at lines 247--252 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. psfig: searching ../../Graph/doc/rad1.eps for bounding box psfig: including ../../Graph/doc/rad1.eps psfig: searching ../../Graph/doc/rad2.eps for bounding box psfig: including ../../Graph/doc/rad2.eps [11] Overfull \hbox (19.63927pt too wide) in paragraph at lines 301--306 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. ) (main.ind [12] [13 ]) (main.aux) ) Here is how much of TeX's memory you used: 442 strings out of 11977 4537 string characters out of 87269 37981 words of memory out of 262141 2362 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 14i,6n,17p,182b,260s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (13 pages, 42228 bytes). Graph/doc/main.aux010064400020550007177000000035760654026634000153620ustar00clevecompmath00000400000006\relax \citation{ash95-DDSEP} \citation{ash95-compressed-graphs} \citation{dam92-compressed} \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space Graph}: A Graph object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \newlabel{chapter:Graph}{{1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{2}} \newlabel{section:Graph:dataStructure}{{1.1}{2}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space Graph} methods}{2}} \newlabel{section:Graph:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{3}} \newlabel{subsection:Graph:proto:basics}{{1.2.1}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initializer methods}{3}} \newlabel{subsection:Graph:proto:initializers}{{1.2.2}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Compress and Expand methods}{4}} \newlabel{subsection:Graph:proto:compress}{{1.2.3}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}Wirebasket domain decomposition ordering}{5}} \newlabel{subsection:Graph:proto:wirebasket}{{1.2.4}{5}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.5}Utility methods}{5}} \newlabel{subsection:Graph:proto:utilities}{{1.2.5}{5}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.6}IO methods}{7}} \newlabel{subsection:Graph:proto:IO}{{1.2.6}{7}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs for the {\string\ptt\space Graph} object}{8}} \newlabel{section:Graph:drivers}{{1.3}{8}} Graph/doc/drivers.tex010064400020550007177000000276710654026627600161310ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt Graph} object} \label{section:Graph:drivers} \par This section contains brief descriptions of six driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} checkComponents msglvl msgFile inGraphFile \end{verbatim} This driver program reads in a {\tt Graph} object from a file, and prints out information about the number of vertices and weights of the vertices in the components. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} compressGraph msglvl msgFile inGraphFile coarseType outMapFile outGraphFile \end{verbatim} This driver program reads in a {\tt Graph} object from a file, computes the equivalence map to its natural compressed graph (the first graph need not be unit weight), and constructs the natural compressed graph. The equivalence map and compressed graph are optionally written out to files. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt coarseType} parameter defines the type of compressed graph; valid values are in {\tt [0,3]}. \item The {\tt outMapFile} parameter is the output file for the {\tt IV} object that holds the equivalence map. If {\tt outMapFile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the {\tt IV} object to a formatted file (if {\tt outMapFile} is of the form {\tt *.ivf}), or a binary file (if {\tt outMapFile} is of the form {\tt *.ivb}). \item The {\tt outGraphFile} parameter is the output file for the compressed {\tt Graph} object. If {\tt outGraphFile} is {\tt none} then the {\tt Graph} object is not written to a file. Otherwise, the {\tt Graph\_writeToFile()} method is called to write the graph to a formatted file (if {\tt outGraphFile} is of the form {\tt *.graphf}), or a binary file (if {\tt outGraphFile} is of the form {\tt *.graphb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} expandGraph msglvl msgFile inGraphFile inMapFile outGraphFile \end{verbatim} This driver program reads in a {\tt Graph} object and a map {\tt IV} object from two files. It then creates a new {\tt Graph} object which is the original graph ``expanded'' by the map, and optionally writes this object to a file. The program {\tt expandGraph} is the inverse of {\tt compressGraph}. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt inMapFile} parameter is the input file for the {\tt IV} object that holds the expansion map. The {\tt IV\_readFromFile()} method is called to read the map from a formatted file (if {\tt inMapFile} is of the form {\tt *.ivf}), or a binary file (if {\tt inMapFile} is of the form {\tt *.ivb}). \item The {\tt outGraphFile} parameter is the output file for the compressed {\tt Graph} object. If {\tt outGraphFile} is {\tt none} then the {\tt Graph} object is not written to a file. Otherwise, the {\tt Graph\_writeToFile()} method is called to write the graph to a formatted file (if {\tt outGraphFile} is of the form {\tt *.graphf}), or a binary file (if {\tt outGraphFile} is of the form {\tt *.graphb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} mkGridGraph msglvl msgFile stencil n1 n2 n3 outFile \end{verbatim} This driver program creates a Graph object for a finite difference operator on a ${\tt n1} \times {\tt n2} \times {\tt n3}$ regular grid. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item Valid {\tt stencil} values are {\tt 5} for a 2-D 5-point operator, {\tt 7} for a 3-D 7-point operator, {\tt 9} for a 2-D 9-point operator, {\tt 13} for a 2-D 13-point operator and {\tt 27} for a 3-D 27-point operator. \item {\tt n1} is the number of points in the first direction. \item {\tt n2} is the number of points in the second direction. \item {\tt n3} is the number of points in the third direction, ignored for {\tt stencil} = {\tt 5}, {\tt 9} and {\tt 13}. \item The {\tt Graph} object is written to file {\tt outFile}. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is written to the file via the {\tt Graph\_writeToFile()} method. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program reads in a {\tt Graph} object from {\tt inFile} and writes out the object to {\tt outFile} \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt Graph} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is written to the file via the {\tt Graph\_writeToFile()} method. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testIsSymmetric msglvl msgFile inFile \end{verbatim} This driver program reads in a {\tt Graph} object and tests whether it is symmetric using the {\tt Graph\_isSymmetric()} method. This was useful in one application where the {\tt Graph} object was constructed improperly. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt Graph} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testWirebasket msglvl msgFile inGraphFile inStagesFile outStagesFile radius \end{verbatim} This driver program reads in a {\tt Graph} object and and a file that contains the stages ids of the vertices, (stage equal to zero means the vertex is in the Schur complement), and overwrites the stages vector to specify the stage that the vertex lies for a wirebasket domain decomposition of the graph. For a Schur complement vertex, its stage is precisely the number of domains that lie within {\tt radius} edges of it. The new stages vector is written to the {\tt outStagesFile} file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt Graph} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt inStagesFile} parameter is the input file for the {\tt IV} object that holds the component ids. It must be of the form {\tt *.ivf} or {\tt *.ivb}. The {\tt IV} object is read from the file via the {\tt IV\_readFromFile()} method. \item The {\tt outStagesFile} parameter is the output file for the stages {\tt IV} object. It must be of the form {\tt *.ivf} or {\tt *.ivb}. The {\tt IV} object is written to the file via the {\tt IV\_writeToFile()} method. \item The {\tt radius} parameter is used to define the stage of a Schur complement vertex, namely the stage is the number of domains that are found within {\tt radius} edges of the vertex. \end{itemize} The two plots below illustrate the wirebasket stages for a $15 \times 15$ grid. They show the stages for {\tt radius = 1} on the left and {\tt radius = 2} on the right. The domains are $3 \times 3$ subgrids whose vertices have labels equal to zero. \begin{center} \makebox{ % \psfig{file=rad1.eps,width=2.7in,height=2.70in} \psfig{file=../../Graph/doc/rad1.eps,width=2.7in,height=2.70in} % \psfig{file=rad2.eps,width=2.7in,height=2.70in} \psfig{file=../../Graph/doc/rad2.eps,width=2.7in,height=2.70in} } \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} writeMetisFile msglvl msgFile inGraphFile outMetisFile \end{verbatim} This driver program reads in an {\tt Graph} object and write it out to a file in the format required by the {\bf METIS} software package. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt outMetisFile} parameter is the outfile file for the {\bf METIS} graph object. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} stdout}, otherwise a file is opened with {\it append} status to receiveGraph/doc/main.idx010064400020550007177000000035020654026634000153360ustar00clevecompmath00000400000006\indexentry{Graph_new@{\tt Graph\_new()}}{3} \indexentry{Graph_setDefaultFields@{\tt Graph\_setDefaultFields()}}{3} \indexentry{Graph_clearData@{\tt Graph\_clearData()}}{3} \indexentry{Graph_free@{\tt Graph\_free()}}{3} \indexentry{Graph_init1@{\tt Graph\_init1()}}{3} \indexentry{Graph_init2@{\tt Graph\_init2()}}{4} \indexentry{Graph_fillFromOffsets@{\tt Graph\_fillFromOffsets()}}{4} \indexentry{Graph_setListsFromOffsets@{\tt Graph\_setListsFromOffsets()}}{4} \indexentry{Graph_equivMap@{\tt Graph\_equivMap()}}{4} \indexentry{Graph_compress@{\tt Graph\_compress()}}{5} \indexentry{Graph_compress2@{\tt Graph\_compress2()}}{5} \indexentry{Graph_expand@{\tt Graph\_expand()}}{5} \indexentry{Graph_expand2@{\tt Graph\_expand2()}}{5} \indexentry{Graph_wirebasketStages@{\tt Graph\_wirebasketStages()}}{5} \indexentry{Graph_sizeOf@{\tt Graph\_sizeOf()}}{5} \indexentry{Graph_externalDegree@{\tt Graph\_externalDegree()}}{5} \indexentry{Graph_adjAndSize@{\tt Graph\_adjAndSize()}}{6} \indexentry{Graph_adjAndEweights@{\tt Graph\_adjAndEweights()}}{6} \indexentry{Graph_componentMap@{\tt Graph\_componentMap()}}{6} \indexentry{Graph_componentStats@{\tt Graph\_componentStats()}}{6} \indexentry{Graph_subGraph@{\tt Graph\_subGraph()}}{6} \indexentry{Graph_isSymmetric@{\tt Graph\_isSymmetric()}}{7} \indexentry{Graph_readFromFile@{\tt Graph\_readFromFile()}}{7} \indexentry{Graph_readFromFormattedFile@{\tt Graph\_readFromFormattedFile()}}{7} \indexentry{Graph_readFromBinaryFile@{\tt Graph\_readFromBinaryFile()}}{7} \indexentry{Graph_writeToFile@{\tt Graph\_writeToFile()}}{7} \indexentry{Graph_writeToFormattedFile@{\tt Graph\_writeToFormattedFile()}}{7} \indexentry{Graph_writeToBinaryFile@{\tt Graph\_writeToBinaryFile()}}{8} \indexentry{Graph_writeForHumanEye@{\tt Graph\_writeForHumanEye()}}{8} \indexentry{Graph_writeStats@{\tt Graph\_writeStats()}}{8} Graph/doc/main.ind010064400020550007177000000022440654026630600153300ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Graph\_adjAndEweights()}, 6 \item {\tt Graph\_adjAndSize()}, 6 \item {\tt Graph\_clearData()}, 3 \item {\tt Graph\_componentMap()}, 6 \item {\tt Graph\_componentStats()}, 6 \item {\tt Graph\_compress()}, 5 \item {\tt Graph\_compress2()}, 5 \item {\tt Graph\_equivMap()}, 4 \item {\tt Graph\_expand()}, 5 \item {\tt Graph\_expand2()}, 5 \item {\tt Graph\_externalDegree()}, 5 \item {\tt Graph\_fillFromOffsets()}, 4 \item {\tt Graph\_free()}, 3 \item {\tt Graph\_init1()}, 3 \item {\tt Graph\_init2()}, 4 \item {\tt Graph\_isSymmetric()}, 7 \item {\tt Graph\_new()}, 3 \item {\tt Graph\_readFromBinaryFile()}, 7 \item {\tt Graph\_readFromFile()}, 7 \item {\tt Graph\_readFromFormattedFile()}, 7 \item {\tt Graph\_setDefaultFields()}, 3 \item {\tt Graph\_setListsFromOffsets()}, 4 \item {\tt Graph\_sizeOf()}, 5 \item {\tt Graph\_subGraph()}, 6 \item {\tt Graph\_wirebasketStages()}, 5 \item {\tt Graph\_writeForHumanEye()}, 8 \item {\tt Graph\_writeStats()}, 8 \item {\tt Graph\_writeToBinaryFile()}, 8 \item {\tt Graph\_writeToFile()}, 7 \item {\tt Graph\_writeToFormattedFile()}, 7 \end{theindex} Graph/doc/main.ilg010064400020550007177000000004570654026630600153350ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (30 entries accepted, 0 rejected). Sorting entries....done (141 comparisons). Generating output file main.ind....done (34 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Graph/doc/rad2.eps010064400020550007177000000746150653410610500152550ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 600.0 600.0 /radius 15 def /Helvetica findfont 18.75 scalefont setfont /M {moveto} def /L {lineto} def /ACF { % stack : x y radius newpath 0 360 arc closepath fill } def /str 6 string def /drawLabel { % x y label radius /radius exch def /label exch def /y exch def /x exch def gsave 1.0 setgray x radius add y moveto x y radius 0 360 arc fill 0.0 setgray x radius add y moveto x y radius 0 360 arc stroke x y moveto label stringwidth pop 2 div neg radius 2 div neg rmoveto label show grestore } def gsave 0.001 setlinewidth 0.0 setgray newpath 60 20 M 20 20 L 100 20 M 60 20 L 220 20 M 180 20 L 260 20 M 220 20 L 380 20 M 340 20 L 420 20 M 380 20 L 540 20 M 500 20 L 580 20 M 540 20 L 20 60 M 20 20 L 20 60 M 60 20 L 60 60 M 20 20 L 60 60 M 60 20 L 60 60 M 100 20 L 60 60 M 20 60 L 100 60 M 60 20 L 100 60 M 100 20 L 100 60 M 60 60 L 140 60 M 140 20 L 180 60 M 180 20 L 180 60 M 220 20 L 220 60 M 180 20 L 220 60 M 220 20 L 220 60 M 260 20 L 220 60 M 180 60 L 260 60 M 220 20 L 260 60 M 260 20 L 260 60 M 220 60 L 300 60 M 300 20 L 340 60 M 340 20 L 340 60 M 380 20 L 380 60 M 340 20 L 380 60 M 380 20 L 380 60 M 420 20 L 380 60 M 340 60 L 420 60 M 380 20 L 420 60 M 420 20 L 420 60 M 380 60 L 460 60 M 460 20 L 500 60 M 500 20 L 500 60 M 540 20 L 540 60 M 500 20 L 540 60 M 540 20 L 540 60 M 580 20 L 540 60 M 500 60 L 580 60 M 540 20 L 580 60 M 580 20 L 580 60 M 540 60 L 20 100 M 20 60 L 20 100 M 60 60 L 60 100 M 20 60 L 60 100 M 60 60 L 60 100 M 100 60 L 60 100 M 20 100 L 100 100 M 60 60 L 100 100 M 100 60 L 100 100 M 60 100 L 180 100 M 180 60 L 180 100 M 220 60 L 220 100 M 180 60 L 220 100 M 220 60 L 220 100 M 260 60 L 220 100 M 180 100 L 260 100 M 220 60 L 260 100 M 260 60 L 260 100 M 220 100 L 340 100 M 340 60 L 340 100 M 380 60 L 380 100 M 340 60 L 380 100 M 380 60 L 380 100 M 420 60 L 380 100 M 340 100 L 420 100 M 380 60 L 420 100 M 420 60 L 420 100 M 380 100 L 500 100 M 500 60 L 500 100 M 540 60 L 540 100 M 500 60 L 540 100 M 540 60 L 540 100 M 580 60 L 540 100 M 500 100 L 580 100 M 540 60 L 580 100 M 580 60 L 580 100 M 540 100 L 60 140 M 20 140 L 100 140 M 140 100 L 140 140 M 140 100 L 140 140 M 100 140 L 180 140 M 140 100 L 180 140 M 140 140 L 260 140 M 300 100 L 300 140 M 300 100 L 300 140 M 260 140 L 340 140 M 300 100 L 340 140 M 300 140 L 420 140 M 460 100 L 460 140 M 460 100 L 460 140 M 420 140 L 500 140 M 460 100 L 500 140 M 460 140 L 580 140 M 540 140 L stroke newpath 60 180 M 20 180 L 100 180 M 60 180 L 140 180 M 100 140 L 140 180 M 140 140 L 140 180 M 180 140 L 220 180 M 180 180 L 260 180 M 220 180 L 300 180 M 260 140 L 300 180 M 300 140 L 300 180 M 340 140 L 380 180 M 340 180 L 420 180 M 380 180 L 460 180 M 420 140 L 460 180 M 460 140 L 460 180 M 500 140 L 540 180 M 500 180 L 580 180 M 540 180 L 20 220 M 20 180 L 20 220 M 60 180 L 60 220 M 20 180 L 60 220 M 60 180 L 60 220 M 100 180 L 60 220 M 20 220 L 100 220 M 60 180 L 100 220 M 100 180 L 100 220 M 60 220 L 180 220 M 180 180 L 180 220 M 220 180 L 220 220 M 180 180 L 220 220 M 220 180 L 220 220 M 260 180 L 220 220 M 180 220 L 260 220 M 220 180 L 260 220 M 260 180 L 260 220 M 220 220 L 340 220 M 340 180 L 340 220 M 380 180 L 380 220 M 340 180 L 380 220 M 380 180 L 380 220 M 420 180 L 380 220 M 340 220 L 420 220 M 380 180 L 420 220 M 420 180 L 420 220 M 380 220 L 500 220 M 500 180 L 500 220 M 540 180 L 540 220 M 500 180 L 540 220 M 540 180 L 540 220 M 580 180 L 540 220 M 500 220 L 580 220 M 540 180 L 580 220 M 580 180 L 580 220 M 540 220 L 20 260 M 20 220 L 20 260 M 60 220 L 60 260 M 20 220 L 60 260 M 60 220 L 60 260 M 100 220 L 60 260 M 20 260 L 100 260 M 60 220 L 100 260 M 100 220 L 100 260 M 60 260 L 180 260 M 180 220 L 180 260 M 220 220 L 220 260 M 180 220 L 220 260 M 220 220 L 220 260 M 260 220 L 220 260 M 180 260 L 260 260 M 220 220 L 260 260 M 260 220 L 260 260 M 220 260 L 340 260 M 340 220 L 340 260 M 380 220 L 380 260 M 340 220 L 380 260 M 380 220 L 380 260 M 420 220 L 380 260 M 340 260 L 420 260 M 380 220 L 420 260 M 420 220 L 420 260 M 380 260 L 500 260 M 500 220 L 500 260 M 540 220 L 540 260 M 500 220 L 540 260 M 540 220 L 540 260 M 580 220 L 540 260 M 500 260 L 580 260 M 540 220 L 580 260 M 580 220 L 580 260 M 540 260 L 60 300 M 20 300 L 100 300 M 140 260 L 140 300 M 140 260 L 140 300 M 100 300 L 180 300 M 140 260 L 180 300 M 140 300 L 260 300 M 300 260 L 300 300 M 300 260 L 300 300 M 260 300 L 340 300 M 300 260 L 340 300 M 300 300 L stroke newpath 420 300 M 460 260 L 460 300 M 460 260 L 460 300 M 420 300 L 500 300 M 460 260 L 500 300 M 460 300 L 580 300 M 540 300 L 60 340 M 20 340 L 100 340 M 60 340 L 140 340 M 100 300 L 140 340 M 140 300 L 140 340 M 180 300 L 220 340 M 180 340 L 260 340 M 220 340 L 300 340 M 260 300 L 300 340 M 300 300 L 300 340 M 340 300 L 380 340 M 340 340 L 420 340 M 380 340 L 460 340 M 420 300 L 460 340 M 460 300 L 460 340 M 500 300 L 540 340 M 500 340 L 580 340 M 540 340 L 20 380 M 20 340 L 20 380 M 60 340 L 60 380 M 20 340 L 60 380 M 60 340 L 60 380 M 100 340 L 60 380 M 20 380 L 100 380 M 60 340 L 100 380 M 100 340 L 100 380 M 60 380 L 180 380 M 180 340 L 180 380 M 220 340 L 220 380 M 180 340 L 220 380 M 220 340 L 220 380 M 260 340 L 220 380 M 180 380 L 260 380 M 220 340 L 260 380 M 260 340 L 260 380 M 220 380 L 340 380 M 340 340 L 340 380 M 380 340 L 380 380 M 340 340 L 380 380 M 380 340 L 380 380 M 420 340 L 380 380 M 340 380 L 420 380 M 380 340 L 420 380 M 420 340 L 420 380 M 380 380 L 500 380 M 500 340 L 500 380 M 540 340 L 540 380 M 500 340 L 540 380 M 540 340 L 540 380 M 580 340 L 540 380 M 500 380 L 580 380 M 540 340 L 580 380 M 580 340 L 580 380 M 540 380 L 20 420 M 20 380 L 20 420 M 60 380 L 60 420 M 20 380 L 60 420 M 60 380 L 60 420 M 100 380 L 60 420 M 20 420 L 100 420 M 60 380 L 100 420 M 100 380 L 100 420 M 60 420 L 180 420 M 180 380 L 180 420 M 220 380 L 220 420 M 180 380 L 220 420 M 220 380 L 220 420 M 260 380 L 220 420 M 180 420 L 260 420 M 220 380 L 260 420 M 260 380 L 260 420 M 220 420 L 340 420 M 340 380 L 340 420 M 380 380 L 380 420 M 340 380 L 380 420 M 380 380 L 380 420 M 420 380 L 380 420 M 340 420 L 420 420 M 380 380 L 420 420 M 420 380 L 420 420 M 380 420 L 500 420 M 500 380 L 500 420 M 540 380 L 540 420 M 500 380 L 540 420 M 540 380 L 540 420 M 580 380 L 540 420 M 500 420 L 580 420 M 540 380 L 580 420 M 580 380 L 580 420 M 540 420 L 60 460 M 20 460 L 100 460 M 140 420 L 140 460 M 140 420 L 140 460 M 100 460 L 180 460 M 140 420 L stroke newpath 180 460 M 140 460 L 260 460 M 300 420 L 300 460 M 300 420 L 300 460 M 260 460 L 340 460 M 300 420 L 340 460 M 300 460 L 420 460 M 460 420 L 460 460 M 460 420 L 460 460 M 420 460 L 500 460 M 460 420 L 500 460 M 460 460 L 580 460 M 540 460 L 60 500 M 20 500 L 100 500 M 60 500 L 140 500 M 100 460 L 140 500 M 140 460 L 140 500 M 180 460 L 220 500 M 180 500 L 260 500 M 220 500 L 300 500 M 260 460 L 300 500 M 300 460 L 300 500 M 340 460 L 380 500 M 340 500 L 420 500 M 380 500 L 460 500 M 420 460 L 460 500 M 460 460 L 460 500 M 500 460 L 540 500 M 500 500 L 580 500 M 540 500 L 20 540 M 20 500 L 20 540 M 60 500 L 60 540 M 20 500 L 60 540 M 60 500 L 60 540 M 100 500 L 60 540 M 20 540 L 100 540 M 60 500 L 100 540 M 100 500 L 100 540 M 60 540 L 180 540 M 180 500 L 180 540 M 220 500 L 220 540 M 180 500 L 220 540 M 220 500 L 220 540 M 260 500 L 220 540 M 180 540 L 260 540 M 220 500 L 260 540 M 260 500 L 260 540 M 220 540 L 340 540 M 340 500 L 340 540 M 380 500 L 380 540 M 340 500 L 380 540 M 380 500 L 380 540 M 420 500 L 380 540 M 340 540 L 420 540 M 380 500 L 420 540 M 420 500 L 420 540 M 380 540 L 500 540 M 500 500 L 500 540 M 540 500 L 540 540 M 500 500 L 540 540 M 540 500 L 540 540 M 580 500 L 540 540 M 500 540 L 580 540 M 540 500 L 580 540 M 580 500 L 580 540 M 540 540 L 20 580 M 20 540 L 20 580 M 60 540 L 60 580 M 20 540 L 60 580 M 60 540 L 60 580 M 100 540 L 60 580 M 20 580 L 100 580 M 60 540 L 100 580 M 100 540 L 100 580 M 60 580 L 140 580 M 140 540 L 180 580 M 180 540 L 180 580 M 220 540 L 220 580 M 180 540 L 220 580 M 220 540 L 220 580 M 260 540 L 220 580 M 180 580 L 260 580 M 220 540 L 260 580 M 260 540 L 260 580 M 220 580 L 300 580 M 300 540 L 340 580 M 340 540 L 340 580 M 380 540 L 380 580 M 340 540 L 380 580 M 380 540 L 380 580 M 420 540 L 380 580 M 340 580 L 420 580 M 380 540 L 420 580 M 420 540 L 420 580 M 380 580 L 460 580 M 460 540 L 500 580 M 500 540 L 500 580 M 540 540 L 540 580 M 500 540 L 540 580 M 540 540 L 540 580 M 580 540 L stroke newpath 540 580 M 500 580 L 580 580 M 540 540 L 580 580 M 580 540 L 580 580 M 540 580 L stroke grestore gsave 0.001 setlinewidth 0.0 setgray newpath 140 20 M 100 20 L 180 20 M 140 20 L 300 20 M 260 20 L 340 20 M 300 20 L 460 20 M 420 20 L 500 20 M 460 20 L 100 60 M 140 20 L 140 60 M 100 20 L 140 60 M 180 20 L 140 60 M 100 60 L 180 60 M 140 20 L 180 60 M 140 60 L 260 60 M 300 20 L 300 60 M 260 20 L 300 60 M 340 20 L 300 60 M 260 60 L 340 60 M 300 20 L 340 60 M 300 60 L 420 60 M 460 20 L 460 60 M 420 20 L 460 60 M 500 20 L 460 60 M 420 60 L 500 60 M 460 20 L 500 60 M 460 60 L 100 100 M 140 60 L 140 100 M 100 60 L 140 100 M 140 60 L 140 100 M 180 60 L 140 100 M 100 100 L 180 100 M 140 60 L 180 100 M 140 100 L 260 100 M 300 60 L 300 100 M 260 60 L 300 100 M 300 60 L 300 100 M 340 60 L 300 100 M 260 100 L 340 100 M 300 60 L 340 100 M 300 100 L 420 100 M 460 60 L 460 100 M 420 60 L 460 100 M 460 60 L 460 100 M 500 60 L 460 100 M 420 100 L 500 100 M 460 60 L 500 100 M 460 100 L 20 140 M 20 100 L 20 140 M 60 100 L 60 140 M 20 100 L 60 140 M 60 100 L 60 140 M 100 100 L 100 140 M 60 100 L 100 140 M 100 100 L 100 140 M 60 140 L 140 140 M 100 100 L 140 140 M 180 100 L 180 140 M 180 100 L 180 140 M 220 100 L 220 140 M 180 100 L 220 140 M 220 100 L 220 140 M 260 100 L 220 140 M 180 140 L 260 140 M 220 100 L 260 140 M 260 100 L 260 140 M 220 140 L 300 140 M 260 100 L 300 140 M 340 100 L 340 140 M 340 100 L 340 140 M 380 100 L 380 140 M 340 100 L 380 140 M 380 100 L 380 140 M 420 100 L 380 140 M 340 140 L 420 140 M 380 100 L 420 140 M 420 100 L 420 140 M 380 140 L 460 140 M 420 100 L 460 140 M 500 100 L 500 140 M 500 100 L 500 140 M 540 100 L 540 140 M 500 100 L 540 140 M 540 100 L 540 140 M 580 100 L 540 140 M 500 140 L 580 140 M 540 100 L 580 140 M 580 100 L 20 180 M 20 140 L 20 180 M 60 140 L 60 180 M 20 140 L 60 180 M 60 140 L 60 180 M 100 140 L 100 180 M 60 140 L 100 180 M 100 140 L 100 180 M 140 140 L 140 180 M 100 180 L 180 180 M 140 140 L 180 180 M 180 140 L 180 180 M 220 140 L 180 180 M 140 180 L 220 180 M 180 140 L 220 180 M 220 140 L stroke newpath 220 180 M 260 140 L 260 180 M 220 140 L 260 180 M 260 140 L 260 180 M 300 140 L 300 180 M 260 180 L 340 180 M 300 140 L 340 180 M 340 140 L 340 180 M 380 140 L 340 180 M 300 180 L 380 180 M 340 140 L 380 180 M 380 140 L 380 180 M 420 140 L 420 180 M 380 140 L 420 180 M 420 140 L 420 180 M 460 140 L 460 180 M 420 180 L 500 180 M 460 140 L 500 180 M 500 140 L 500 180 M 540 140 L 500 180 M 460 180 L 540 180 M 500 140 L 540 180 M 540 140 L 540 180 M 580 140 L 580 180 M 540 140 L 580 180 M 580 140 L 100 220 M 140 180 L 140 220 M 100 180 L 140 220 M 140 180 L 140 220 M 180 180 L 140 220 M 100 220 L 180 220 M 140 180 L 180 220 M 140 220 L 260 220 M 300 180 L 300 220 M 260 180 L 300 220 M 300 180 L 300 220 M 340 180 L 300 220 M 260 220 L 340 220 M 300 180 L 340 220 M 300 220 L 420 220 M 460 180 L 460 220 M 420 180 L 460 220 M 460 180 L 460 220 M 500 180 L 460 220 M 420 220 L 500 220 M 460 180 L 500 220 M 460 220 L 100 260 M 140 220 L 140 260 M 100 220 L 140 260 M 140 220 L 140 260 M 180 220 L 140 260 M 100 260 L 180 260 M 140 220 L 180 260 M 140 260 L 260 260 M 300 220 L 300 260 M 260 220 L 300 260 M 300 220 L 300 260 M 340 220 L 300 260 M 260 260 L 340 260 M 300 220 L 340 260 M 300 260 L 420 260 M 460 220 L 460 260 M 420 220 L 460 260 M 460 220 L 460 260 M 500 220 L 460 260 M 420 260 L 500 260 M 460 220 L 500 260 M 460 260 L 20 300 M 20 260 L 20 300 M 60 260 L 60 300 M 20 260 L 60 300 M 60 260 L 60 300 M 100 260 L 100 300 M 60 260 L 100 300 M 100 260 L 100 300 M 60 300 L 140 300 M 100 260 L 140 300 M 180 260 L 180 300 M 180 260 L 180 300 M 220 260 L 220 300 M 180 260 L 220 300 M 220 260 L 220 300 M 260 260 L 220 300 M 180 300 L 260 300 M 220 260 L 260 300 M 260 260 L 260 300 M 220 300 L 300 300 M 260 260 L 300 300 M 340 260 L 340 300 M 340 260 L 340 300 M 380 260 L 380 300 M 340 260 L 380 300 M 380 260 L 380 300 M 420 260 L 380 300 M 340 300 L 420 300 M 380 260 L 420 300 M 420 260 L 420 300 M 380 300 L 460 300 M 420 260 L 460 300 M 500 260 L 500 300 M 500 260 L stroke newpath 500 300 M 540 260 L 540 300 M 500 260 L 540 300 M 540 260 L 540 300 M 580 260 L 540 300 M 500 300 L 580 300 M 540 260 L 580 300 M 580 260 L 20 340 M 20 300 L 20 340 M 60 300 L 60 340 M 20 300 L 60 340 M 60 300 L 60 340 M 100 300 L 100 340 M 60 300 L 100 340 M 100 300 L 100 340 M 140 300 L 140 340 M 100 340 L 180 340 M 140 300 L 180 340 M 180 300 L 180 340 M 220 300 L 180 340 M 140 340 L 220 340 M 180 300 L 220 340 M 220 300 L 220 340 M 260 300 L 260 340 M 220 300 L 260 340 M 260 300 L 260 340 M 300 300 L 300 340 M 260 340 L 340 340 M 300 300 L 340 340 M 340 300 L 340 340 M 380 300 L 340 340 M 300 340 L 380 340 M 340 300 L 380 340 M 380 300 L 380 340 M 420 300 L 420 340 M 380 300 L 420 340 M 420 300 L 420 340 M 460 300 L 460 340 M 420 340 L 500 340 M 460 300 L 500 340 M 500 300 L 500 340 M 540 300 L 500 340 M 460 340 L 540 340 M 500 300 L 540 340 M 540 300 L 540 340 M 580 300 L 580 340 M 540 300 L 580 340 M 580 300 L 100 380 M 140 340 L 140 380 M 100 340 L 140 380 M 140 340 L 140 380 M 180 340 L 140 380 M 100 380 L 180 380 M 140 340 L 180 380 M 140 380 L 260 380 M 300 340 L 300 380 M 260 340 L 300 380 M 300 340 L 300 380 M 340 340 L 300 380 M 260 380 L 340 380 M 300 340 L 340 380 M 300 380 L 420 380 M 460 340 L 460 380 M 420 340 L 460 380 M 460 340 L 460 380 M 500 340 L 460 380 M 420 380 L 500 380 M 460 340 L 500 380 M 460 380 L 100 420 M 140 380 L 140 420 M 100 380 L 140 420 M 140 380 L 140 420 M 180 380 L 140 420 M 100 420 L 180 420 M 140 380 L 180 420 M 140 420 L 260 420 M 300 380 L 300 420 M 260 380 L 300 420 M 300 380 L 300 420 M 340 380 L 300 420 M 260 420 L 340 420 M 300 380 L 340 420 M 300 420 L 420 420 M 460 380 L 460 420 M 420 380 L 460 420 M 460 380 L 460 420 M 500 380 L 460 420 M 420 420 L 500 420 M 460 380 L 500 420 M 460 420 L 20 460 M 20 420 L 20 460 M 60 420 L 60 460 M 20 420 L 60 460 M 60 420 L 60 460 M 100 420 L 100 460 M 60 420 L 100 460 M 100 420 L 100 460 M 60 460 L 140 460 M 100 420 L 140 460 M 180 420 L 180 460 M 180 420 L stroke newpath 180 460 M 220 420 L 220 460 M 180 420 L 220 460 M 220 420 L 220 460 M 260 420 L 220 460 M 180 460 L 260 460 M 220 420 L 260 460 M 260 420 L 260 460 M 220 460 L 300 460 M 260 420 L 300 460 M 340 420 L 340 460 M 340 420 L 340 460 M 380 420 L 380 460 M 340 420 L 380 460 M 380 420 L 380 460 M 420 420 L 380 460 M 340 460 L 420 460 M 380 420 L 420 460 M 420 420 L 420 460 M 380 460 L 460 460 M 420 420 L 460 460 M 500 420 L 500 460 M 500 420 L 500 460 M 540 420 L 540 460 M 500 420 L 540 460 M 540 420 L 540 460 M 580 420 L 540 460 M 500 460 L 580 460 M 540 420 L 580 460 M 580 420 L 20 500 M 20 460 L 20 500 M 60 460 L 60 500 M 20 460 L 60 500 M 60 460 L 60 500 M 100 460 L 100 500 M 60 460 L 100 500 M 100 460 L 100 500 M 140 460 L 140 500 M 100 500 L 180 500 M 140 460 L 180 500 M 180 460 L 180 500 M 220 460 L 180 500 M 140 500 L 220 500 M 180 460 L 220 500 M 220 460 L 220 500 M 260 460 L 260 500 M 220 460 L 260 500 M 260 460 L 260 500 M 300 460 L 300 500 M 260 500 L 340 500 M 300 460 L 340 500 M 340 460 L 340 500 M 380 460 L 340 500 M 300 500 L 380 500 M 340 460 L 380 500 M 380 460 L 380 500 M 420 460 L 420 500 M 380 460 L 420 500 M 420 460 L 420 500 M 460 460 L 460 500 M 420 500 L 500 500 M 460 460 L 500 500 M 500 460 L 500 500 M 540 460 L 500 500 M 460 500 L 540 500 M 500 460 L 540 500 M 540 460 L 540 500 M 580 460 L 580 500 M 540 460 L 580 500 M 580 460 L 100 540 M 140 500 L 140 540 M 100 500 L 140 540 M 140 500 L 140 540 M 180 500 L 140 540 M 100 540 L 180 540 M 140 500 L 180 540 M 140 540 L 260 540 M 300 500 L 300 540 M 260 500 L 300 540 M 300 500 L 300 540 M 340 500 L 300 540 M 260 540 L 340 540 M 300 500 L 340 540 M 300 540 L 420 540 M 460 500 L 460 540 M 420 500 L 460 540 M 460 500 L 460 540 M 500 500 L 460 540 M 420 540 L 500 540 M 460 500 L 500 540 M 460 540 L 100 580 M 140 540 L 140 580 M 100 540 L 140 580 M 180 540 L 140 580 M 100 580 L 180 580 M 140 540 L 180 580 M 140 580 L 260 580 M 300 540 L 300 580 M 260 540 L 300 580 M 340 540 L 300 580 M 260 580 L stroke newpath 340 580 M 300 540 L 340 580 M 300 580 L 420 580 M 460 540 L 460 580 M 420 540 L 460 580 M 500 540 L 460 580 M 420 580 L 500 580 M 460 540 L 500 580 M 460 580 L stroke grestore gsave 0.1 setlinewidth 0.0 setgray 20.000 20.000 (0) radius drawLabel 60.000 20.000 (0) radius drawLabel 100.002 20.000 (0) radius drawLabel 140.002 20.000 (2) radius drawLabel 179.998 20.000 (0) radius drawLabel 219.998 20.000 (0) radius drawLabel 259.999 20.000 (0) radius drawLabel 300.000 20.000 (2) radius drawLabel 340.001 20.000 (0) radius drawLabel 380.002 20.000 (0) radius drawLabel 420.002 20.000 (0) radius drawLabel 459.998 20.000 (2) radius drawLabel 499.998 20.000 (0) radius drawLabel 539.999 20.000 (0) radius drawLabel 580.000 20.000 (0) radius drawLabel 20.000 60.000 (0) radius drawLabel 60.000 60.000 (0) radius drawLabel 100.002 60.000 (0) radius drawLabel 140.002 60.000 (2) radius drawLabel 179.998 60.000 (0) radius drawLabel 219.998 60.000 (0) radius drawLabel 259.999 60.000 (0) radius drawLabel 300.000 60.000 (2) radius drawLabel 340.001 60.000 (0) radius drawLabel 380.002 60.000 (0) radius drawLabel 420.002 60.000 (0) radius drawLabel 459.998 60.000 (2) radius drawLabel 499.998 60.000 (0) radius drawLabel 539.999 60.000 (0) radius drawLabel 580.000 60.000 (0) radius drawLabel 20.000 100.002 (0) radius drawLabel 60.000 100.002 (0) radius drawLabel 100.002 100.002 (0) radius drawLabel 140.002 100.002 (4) radius drawLabel 179.998 100.002 (0) radius drawLabel 219.998 100.002 (0) radius drawLabel 259.999 100.002 (0) radius drawLabel 300.000 100.002 (4) radius drawLabel 340.001 100.002 (0) radius drawLabel 380.002 100.002 (0) radius drawLabel 420.002 100.002 (0) radius drawLabel 459.998 100.002 (4) radius drawLabel 499.998 100.002 (0) radius drawLabel 539.999 100.002 (0) radius drawLabel 580.000 100.002 (0) radius drawLabel 20.000 140.002 (2) radius drawLabel 60.000 140.002 (2) radius drawLabel 100.002 140.002 (4) radius drawLabel 140.002 140.002 (4) radius drawLabel 179.998 140.002 (4) radius drawLabel 219.998 140.002 (2) radius drawLabel 259.999 140.002 (4) radius drawLabel 300.000 140.002 (4) radius drawLabel 340.001 140.002 (4) radius drawLabel 380.002 140.002 (2) radius drawLabel 420.002 140.002 (4) radius drawLabel 459.998 140.002 (4) radius drawLabel 499.998 140.002 (4) radius drawLabel 539.999 140.002 (2) radius drawLabel 580.000 140.002 (2) radius drawLabel 20.000 179.998 (0) radius drawLabel 60.000 179.998 (0) radius drawLabel 100.002 179.998 (0) radius drawLabel 140.002 179.998 (4) radius drawLabel 179.998 179.998 (0) radius drawLabel 219.998 179.998 (0) radius drawLabel 259.999 179.998 (0) radius drawLabel 300.000 179.998 (4) radius drawLabel 340.001 179.998 (0) radius drawLabel 380.002 179.998 (0) radius drawLabel 420.002 179.998 (0) radius drawLabel 459.998 179.998 (4) radius drawLabel 499.998 179.998 (0) radius drawLabel 539.999 179.998 (0) radius drawLabel 580.000 179.998 (0) radius drawLabel 20.000 219.998 (0) radius drawLabel 60.000 219.998 (0) radius drawLabel 100.002 219.998 (0) radius drawLabel 140.002 219.998 (2) radius drawLabel 179.998 219.998 (0) radius drawLabel 219.998 219.998 (0) radius drawLabel 259.999 219.998 (0) radius drawLabel 300.000 219.998 (2) radius drawLabel 340.001 219.998 (0) radius drawLabel 380.002 219.998 (0) radius drawLabel 420.002 219.998 (0) radius drawLabel 459.998 219.998 (2) radius drawLabel 499.998 219.998 (0) radius drawLabel 539.999 219.998 (0) radius drawLabel 580.000 219.998 (0) radius drawLabel 20.000 259.999 (0) radius drawLabel 60.000 259.999 (0) radius drawLabel 100.002 259.999 (0) radius drawLabel 140.002 259.999 (4) radius drawLabel 179.998 259.999 (0) radius drawLabel 219.998 259.999 (0) radius drawLabel 259.999 259.999 (0) radius drawLabel 300.000 259.999 (4) radius drawLabel 340.001 259.999 (0) radius drawLabel 380.002 259.999 (0) radius drawLabel 420.002 259.999 (0) radius drawLabel 459.998 259.999 (4) radius drawLabel 499.998 259.999 (0) radius drawLabel 539.999 259.999 (0) radius drawLabel 580.000 259.999 (0) radius drawLabel 20.000 300.000 (2) radius drawLabel 60.000 300.000 (2) radius drawLabel 100.002 300.000 (4) radius drawLabel 140.002 300.000 (4) radius drawLabel 179.998 300.000 (4) radius drawLabel 219.998 300.000 (2) radius drawLabel 259.999 300.000 (4) radius drawLabel 300.000 300.000 (4) radius drawLabel 340.001 300.000 (4) radius drawLabel 380.002 300.000 (2) radius drawLabel 420.002 300.000 (4) radius drawLabel 459.998 300.000 (4) radius drawLabel 499.998 300.000 (4) radius drawLabel 539.999 300.000 (2) radius drawLabel 580.000 300.000 (2) radius drawLabel 20.000 340.001 (0) radius drawLabel 60.000 340.001 (0) radius drawLabel 100.002 340.001 (0) radius drawLabel 140.002 340.001 (4) radius drawLabel 179.998 340.001 (0) radius drawLabel 219.998 340.001 (0) radius drawLabel 259.999 340.001 (0) radius drawLabel 300.000 340.001 (4) radius drawLabel 340.001 340.001 (0) radius drawLabel 380.002 340.001 (0) radius drawLabel 420.002 340.001 (0) radius drawLabel 459.998 340.001 (4) radius drawLabel 499.998 340.001 (0) radius drawLabel 539.999 340.001 (0) radius drawLabel 580.000 340.001 (0) radius drawLabel 20.000 380.002 (0) radius drawLabel 60.000 380.002 (0) radius drawLabel 100.002 380.002 (0) radius drawLabel 140.002 380.002 (2) radius drawLabel 179.998 380.002 (0) radius drawLabel 219.998 380.002 (0) radius drawLabel 259.999 380.002 (0) radius drawLabel 300.000 380.002 (2) radius drawLabel 340.001 380.002 (0) radius drawLabel 380.002 380.002 (0) radius drawLabel 420.002 380.002 (0) radius drawLabel 459.998 380.002 (2) radius drawLabel 499.998 380.002 (0) radius drawLabel 539.999 380.002 (0) radius drawLabel 580.000 380.002 (0) radius drawLabel 20.000 420.002 (0) radius drawLabel 60.000 420.002 (0) radius drawLabel 100.002 420.002 (0) radius drawLabel 140.002 420.002 (4) radius drawLabel 179.998 420.002 (0) radius drawLabel 219.998 420.002 (0) radius drawLabel 259.999 420.002 (0) radius drawLabel 300.000 420.002 (4) radius drawLabel 340.001 420.002 (0) radius drawLabel 380.002 420.002 (0) radius drawLabel 420.002 420.002 (0) radius drawLabel 459.998 420.002 (4) radius drawLabel 499.998 420.002 (0) radius drawLabel 539.999 420.002 (0) radius drawLabel 580.000 420.002 (0) radius drawLabel 20.000 459.998 (2) radius drawLabel 60.000 459.998 (2) radius drawLabel 100.002 459.998 (4) radius drawLabel 140.002 459.998 (4) radius drawLabel 179.998 459.998 (4) radius drawLabel 219.998 459.998 (2) radius drawLabel 259.999 459.998 (4) radius drawLabel 300.000 459.998 (4) radius drawLabel 340.001 459.998 (4) radius drawLabel 380.002 459.998 (2) radius drawLabel 420.002 459.998 (4) radius drawLabel 459.998 459.998 (4) radius drawLabel 499.998 459.998 (4) radius drawLabel 539.999 459.998 (2) radius drawLabel 580.000 459.998 (2) radius drawLabel 20.000 499.998 (0) radius drawLabel 60.000 499.998 (0) radius drawLabel 100.002 499.998 (0) radius drawLabel 140.002 499.998 (4) radius drawLabel 179.998 499.998 (0) radius drawLabel 219.998 499.998 (0) radius drawLabel 259.999 499.998 (0) radius drawLabel 300.000 499.998 (4) radius drawLabel 340.001 499.998 (0) radius drawLabel 380.002 499.998 (0) radius drawLabel 420.002 499.998 (0) radius drawLabel 459.998 499.998 (4) radius drawLabel 499.998 499.998 (0) radius drawLabel 539.999 499.998 (0) radius drawLabel 580.000 499.998 (0) radius drawLabel 20.000 539.999 (0) radius drawLabel 60.000 539.999 (0) radius drawLabel 100.002 539.999 (0) radius drawLabel 140.002 539.999 (2) radius drawLabel 179.998 539.999 (0) radius drawLabel 219.998 539.999 (0) radius drawLabel 259.999 539.999 (0) radius drawLabel 300.000 539.999 (2) radius drawLabel 340.001 539.999 (0) radius drawLabel 380.002 539.999 (0) radius drawLabel 420.002 539.999 (0) radius drawLabel 459.998 539.999 (2) radius drawLabel 499.998 539.999 (0) radius drawLabel 539.999 539.999 (0) radius drawLabel 580.000 539.999 (0) radius drawLabel 20.000 580.000 (0) radius drawLabel 60.000 580.000 (0) radius drawLabel 100.002 580.000 (0) radius drawLabel 140.002 580.000 (2) radius drawLabel 179.998 580.000 (0) radius drawLabel 219.998 580.000 (0) radius drawLabel 259.999 580.000 (0) radius drawLabel 300.000 580.000 (2) radius drawLabel 340.001 580.000 (0) radius drawLabel 380.002 580.000 (0) radius drawLabel 420.002 580.000 (0) radius drawLabel 459.998 580.000 (2) radius drawLabel 499.998 580.000 (0) radius drawLabel 539.999 580.000 (0) radius drawLabel 580.000 580.000 (0) radius drawLabel grestore showpage 260 500 M 300 460 L 300 500 M 260 500 L 340 500 M 300 460 L 340 500 M 340 460 L 340Graph/doc/rad1.eps010064400020550007177000000746150653410610500152540ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 600.0 600.0 /radius 15 def /Helvetica findfont 18.75 scalefont setfont /M {moveto} def /L {lineto} def /ACF { % stack : x y radius newpath 0 360 arc closepath fill } def /str 6 string def /drawLabel { % x y label radius /radius exch def /label exch def /y exch def /x exch def gsave 1.0 setgray x radius add y moveto x y radius 0 360 arc fill 0.0 setgray x radius add y moveto x y radius 0 360 arc stroke x y moveto label stringwidth pop 2 div neg radius 2 div neg rmoveto label show grestore } def gsave 0.001 setlinewidth 0.0 setgray newpath 60 20 M 20 20 L 100 20 M 60 20 L 220 20 M 180 20 L 260 20 M 220 20 L 380 20 M 340 20 L 420 20 M 380 20 L 540 20 M 500 20 L 580 20 M 540 20 L 20 60 M 20 20 L 20 60 M 60 20 L 60 60 M 20 20 L 60 60 M 60 20 L 60 60 M 100 20 L 60 60 M 20 60 L 100 60 M 60 20 L 100 60 M 100 20 L 100 60 M 60 60 L 140 60 M 140 20 L 180 60 M 180 20 L 180 60 M 220 20 L 220 60 M 180 20 L 220 60 M 220 20 L 220 60 M 260 20 L 220 60 M 180 60 L 260 60 M 220 20 L 260 60 M 260 20 L 260 60 M 220 60 L 300 60 M 300 20 L 340 60 M 340 20 L 340 60 M 380 20 L 380 60 M 340 20 L 380 60 M 380 20 L 380 60 M 420 20 L 380 60 M 340 60 L 420 60 M 380 20 L 420 60 M 420 20 L 420 60 M 380 60 L 460 60 M 460 20 L 500 60 M 500 20 L 500 60 M 540 20 L 540 60 M 500 20 L 540 60 M 540 20 L 540 60 M 580 20 L 540 60 M 500 60 L 580 60 M 540 20 L 580 60 M 580 20 L 580 60 M 540 60 L 20 100 M 20 60 L 20 100 M 60 60 L 60 100 M 20 60 L 60 100 M 60 60 L 60 100 M 100 60 L 60 100 M 20 100 L 100 100 M 60 60 L 100 100 M 100 60 L 100 100 M 60 100 L 140 100 M 140 60 L 180 100 M 180 60 L 180 100 M 220 60 L 220 100 M 180 60 L 220 100 M 220 60 L 220 100 M 260 60 L 220 100 M 180 100 L 260 100 M 220 60 L 260 100 M 260 60 L 260 100 M 220 100 L 300 100 M 300 60 L 340 100 M 340 60 L 340 100 M 380 60 L 380 100 M 340 60 L 380 100 M 380 60 L 380 100 M 420 60 L 380 100 M 340 100 L 420 100 M 380 60 L 420 100 M 420 60 L 420 100 M 380 100 L 460 100 M 460 60 L 500 100 M 500 60 L 500 100 M 540 60 L 540 100 M 500 60 L 540 100 M 540 60 L 540 100 M 580 60 L 540 100 M 500 100 L 580 100 M 540 60 L 580 100 M 580 60 L 580 100 M 540 100 L 60 140 M 20 140 L 100 140 M 140 100 L 100 140 M 60 140 L 180 140 M 140 100 L 220 140 M 180 140 L 260 140 M 300 100 L 260 140 M 220 140 L 340 140 M 300 100 L 380 140 M 340 140 L 420 140 M 460 100 L 420 140 M 380 140 L 500 140 M 460 100 L 540 140 M 500 140 L 580 140 M 540 140 L stroke newpath 60 180 M 20 180 L 100 180 M 60 180 L 140 180 M 100 140 L 140 180 M 180 140 L 220 180 M 180 180 L 260 180 M 220 180 L 300 180 M 260 140 L 300 180 M 340 140 L 380 180 M 340 180 L 420 180 M 380 180 L 460 180 M 420 140 L 460 180 M 500 140 L 540 180 M 500 180 L 580 180 M 540 180 L 20 220 M 20 180 L 20 220 M 60 180 L 60 220 M 20 180 L 60 220 M 60 180 L 60 220 M 100 180 L 60 220 M 20 220 L 100 220 M 60 180 L 100 220 M 100 180 L 100 220 M 60 220 L 140 220 M 140 180 L 180 220 M 180 180 L 180 220 M 220 180 L 220 220 M 180 180 L 220 220 M 220 180 L 220 220 M 260 180 L 220 220 M 180 220 L 260 220 M 220 180 L 260 220 M 260 180 L 260 220 M 220 220 L 300 220 M 300 180 L 340 220 M 340 180 L 340 220 M 380 180 L 380 220 M 340 180 L 380 220 M 380 180 L 380 220 M 420 180 L 380 220 M 340 220 L 420 220 M 380 180 L 420 220 M 420 180 L 420 220 M 380 220 L 460 220 M 460 180 L 500 220 M 500 180 L 500 220 M 540 180 L 540 220 M 500 180 L 540 220 M 540 180 L 540 220 M 580 180 L 540 220 M 500 220 L 580 220 M 540 180 L 580 220 M 580 180 L 580 220 M 540 220 L 20 260 M 20 220 L 20 260 M 60 220 L 60 260 M 20 220 L 60 260 M 60 220 L 60 260 M 100 220 L 60 260 M 20 260 L 100 260 M 60 220 L 100 260 M 100 220 L 100 260 M 60 260 L 140 260 M 140 220 L 180 260 M 180 220 L 180 260 M 220 220 L 220 260 M 180 220 L 220 260 M 220 220 L 220 260 M 260 220 L 220 260 M 180 260 L 260 260 M 220 220 L 260 260 M 260 220 L 260 260 M 220 260 L 300 260 M 300 220 L 340 260 M 340 220 L 340 260 M 380 220 L 380 260 M 340 220 L 380 260 M 380 220 L 380 260 M 420 220 L 380 260 M 340 260 L 420 260 M 380 220 L 420 260 M 420 220 L 420 260 M 380 260 L 460 260 M 460 220 L 500 260 M 500 220 L 500 260 M 540 220 L 540 260 M 500 220 L 540 260 M 540 220 L 540 260 M 580 220 L 540 260 M 500 260 L 580 260 M 540 220 L 580 260 M 580 220 L 580 260 M 540 260 L 60 300 M 20 300 L 100 300 M 140 260 L 100 300 M 60 300 L 180 300 M 140 260 L 220 300 M 180 300 L 260 300 M 300 260 L 260 300 M 220 300 L 340 300 M 300 260 L stroke newpath 380 300 M 340 300 L 420 300 M 460 260 L 420 300 M 380 300 L 500 300 M 460 260 L 540 300 M 500 300 L 580 300 M 540 300 L 60 340 M 20 340 L 100 340 M 60 340 L 140 340 M 100 300 L 140 340 M 180 300 L 220 340 M 180 340 L 260 340 M 220 340 L 300 340 M 260 300 L 300 340 M 340 300 L 380 340 M 340 340 L 420 340 M 380 340 L 460 340 M 420 300 L 460 340 M 500 300 L 540 340 M 500 340 L 580 340 M 540 340 L 20 380 M 20 340 L 20 380 M 60 340 L 60 380 M 20 340 L 60 380 M 60 340 L 60 380 M 100 340 L 60 380 M 20 380 L 100 380 M 60 340 L 100 380 M 100 340 L 100 380 M 60 380 L 140 380 M 140 340 L 180 380 M 180 340 L 180 380 M 220 340 L 220 380 M 180 340 L 220 380 M 220 340 L 220 380 M 260 340 L 220 380 M 180 380 L 260 380 M 220 340 L 260 380 M 260 340 L 260 380 M 220 380 L 300 380 M 300 340 L 340 380 M 340 340 L 340 380 M 380 340 L 380 380 M 340 340 L 380 380 M 380 340 L 380 380 M 420 340 L 380 380 M 340 380 L 420 380 M 380 340 L 420 380 M 420 340 L 420 380 M 380 380 L 460 380 M 460 340 L 500 380 M 500 340 L 500 380 M 540 340 L 540 380 M 500 340 L 540 380 M 540 340 L 540 380 M 580 340 L 540 380 M 500 380 L 580 380 M 540 340 L 580 380 M 580 340 L 580 380 M 540 380 L 20 420 M 20 380 L 20 420 M 60 380 L 60 420 M 20 380 L 60 420 M 60 380 L 60 420 M 100 380 L 60 420 M 20 420 L 100 420 M 60 380 L 100 420 M 100 380 L 100 420 M 60 420 L 140 420 M 140 380 L 180 420 M 180 380 L 180 420 M 220 380 L 220 420 M 180 380 L 220 420 M 220 380 L 220 420 M 260 380 L 220 420 M 180 420 L 260 420 M 220 380 L 260 420 M 260 380 L 260 420 M 220 420 L 300 420 M 300 380 L 340 420 M 340 380 L 340 420 M 380 380 L 380 420 M 340 380 L 380 420 M 380 380 L 380 420 M 420 380 L 380 420 M 340 420 L 420 420 M 380 380 L 420 420 M 420 380 L 420 420 M 380 420 L 460 420 M 460 380 L 500 420 M 500 380 L 500 420 M 540 380 L 540 420 M 500 380 L 540 420 M 540 380 L 540 420 M 580 380 L 540 420 M 500 420 L 580 420 M 540 380 L 580 420 M 580 380 L 580 420 M 540 420 L 60 460 M 20 460 L 100 460 M 140 420 L stroke newpath 100 460 M 60 460 L 180 460 M 140 420 L 220 460 M 180 460 L 260 460 M 300 420 L 260 460 M 220 460 L 340 460 M 300 420 L 380 460 M 340 460 L 420 460 M 460 420 L 420 460 M 380 460 L 500 460 M 460 420 L 540 460 M 500 460 L 580 460 M 540 460 L 60 500 M 20 500 L 100 500 M 60 500 L 140 500 M 100 460 L 140 500 M 180 460 L 220 500 M 180 500 L 260 500 M 220 500 L 300 500 M 260 460 L 300 500 M 340 460 L 380 500 M 340 500 L 420 500 M 380 500 L 460 500 M 420 460 L 460 500 M 500 460 L 540 500 M 500 500 L 580 500 M 540 500 L 20 540 M 20 500 L 20 540 M 60 500 L 60 540 M 20 500 L 60 540 M 60 500 L 60 540 M 100 500 L 60 540 M 20 540 L 100 540 M 60 500 L 100 540 M 100 500 L 100 540 M 60 540 L 140 540 M 140 500 L 180 540 M 180 500 L 180 540 M 220 500 L 220 540 M 180 500 L 220 540 M 220 500 L 220 540 M 260 500 L 220 540 M 180 540 L 260 540 M 220 500 L 260 540 M 260 500 L 260 540 M 220 540 L 300 540 M 300 500 L 340 540 M 340 500 L 340 540 M 380 500 L 380 540 M 340 500 L 380 540 M 380 500 L 380 540 M 420 500 L 380 540 M 340 540 L 420 540 M 380 500 L 420 540 M 420 500 L 420 540 M 380 540 L 460 540 M 460 500 L 500 540 M 500 500 L 500 540 M 540 500 L 540 540 M 500 500 L 540 540 M 540 500 L 540 540 M 580 500 L 540 540 M 500 540 L 580 540 M 540 500 L 580 540 M 580 500 L 580 540 M 540 540 L 20 580 M 20 540 L 20 580 M 60 540 L 60 580 M 20 540 L 60 580 M 60 540 L 60 580 M 100 540 L 60 580 M 20 580 L 100 580 M 60 540 L 100 580 M 100 540 L 100 580 M 60 580 L 140 580 M 140 540 L 180 580 M 180 540 L 180 580 M 220 540 L 220 580 M 180 540 L 220 580 M 220 540 L 220 580 M 260 540 L 220 580 M 180 580 L 260 580 M 220 540 L 260 580 M 260 540 L 260 580 M 220 580 L 300 580 M 300 540 L 340 580 M 340 540 L 340 580 M 380 540 L 380 580 M 340 540 L 380 580 M 380 540 L 380 580 M 420 540 L 380 580 M 340 580 L 420 580 M 380 540 L 420 580 M 420 540 L 420 580 M 380 580 L 460 580 M 460 540 L 500 580 M 500 540 L 500 580 M 540 540 L 540 580 M 500 540 L 540 580 M 540 540 L 540 580 M 580 540 L stroke newpath 540 580 M 500 580 L 580 580 M 540 540 L 580 580 M 580 540 L 580 580 M 540 580 L stroke grestore gsave 0.001 setlinewidth 0.0 setgray newpath 140 20 M 100 20 L 180 20 M 140 20 L 300 20 M 260 20 L 340 20 M 300 20 L 460 20 M 420 20 L 500 20 M 460 20 L 100 60 M 140 20 L 140 60 M 100 20 L 140 60 M 180 20 L 140 60 M 100 60 L 180 60 M 140 20 L 180 60 M 140 60 L 260 60 M 300 20 L 300 60 M 260 20 L 300 60 M 340 20 L 300 60 M 260 60 L 340 60 M 300 20 L 340 60 M 300 60 L 420 60 M 460 20 L 460 60 M 420 20 L 460 60 M 500 20 L 460 60 M 420 60 L 500 60 M 460 20 L 500 60 M 460 60 L 100 100 M 140 60 L 140 100 M 100 60 L 140 100 M 180 60 L 140 100 M 100 100 L 180 100 M 140 60 L 180 100 M 140 100 L 260 100 M 300 60 L 300 100 M 260 60 L 300 100 M 340 60 L 300 100 M 260 100 L 340 100 M 300 60 L 340 100 M 300 100 L 420 100 M 460 60 L 460 100 M 420 60 L 460 100 M 500 60 L 460 100 M 420 100 L 500 100 M 460 60 L 500 100 M 460 100 L 20 140 M 20 100 L 20 140 M 60 100 L 60 140 M 20 100 L 60 140 M 60 100 L 60 140 M 100 100 L 100 140 M 60 100 L 100 140 M 100 100 L 140 140 M 100 100 L 140 140 M 140 100 L 140 140 M 180 100 L 140 140 M 100 140 L 180 140 M 180 100 L 180 140 M 220 100 L 180 140 M 140 140 L 220 140 M 180 100 L 220 140 M 220 100 L 220 140 M 260 100 L 260 140 M 220 100 L 260 140 M 260 100 L 300 140 M 260 100 L 300 140 M 300 100 L 300 140 M 340 100 L 300 140 M 260 140 L 340 140 M 340 100 L 340 140 M 380 100 L 340 140 M 300 140 L 380 140 M 340 100 L 380 140 M 380 100 L 380 140 M 420 100 L 420 140 M 380 100 L 420 140 M 420 100 L 460 140 M 420 100 L 460 140 M 460 100 L 460 140 M 500 100 L 460 140 M 420 140 L 500 140 M 500 100 L 500 140 M 540 100 L 500 140 M 460 140 L 540 140 M 500 100 L 540 140 M 540 100 L 540 140 M 580 100 L 580 140 M 540 100 L 580 140 M 580 100 L 20 180 M 20 140 L 20 180 M 60 140 L 60 180 M 20 140 L 60 180 M 60 140 L 60 180 M 100 140 L 100 180 M 60 140 L 100 180 M 100 140 L 100 180 M 140 140 L 140 180 M 140 140 L 140 180 M 100 180 L 180 180 M 140 140 L 180 180 M 180 140 L 180 180 M 220 140 L 180 180 M 140 180 L 220 180 M 180 140 L stroke newpath 220 180 M 220 140 L 220 180 M 260 140 L 260 180 M 220 140 L 260 180 M 260 140 L 260 180 M 300 140 L 300 180 M 300 140 L 300 180 M 260 180 L 340 180 M 300 140 L 340 180 M 340 140 L 340 180 M 380 140 L 340 180 M 300 180 L 380 180 M 340 140 L 380 180 M 380 140 L 380 180 M 420 140 L 420 180 M 380 140 L 420 180 M 420 140 L 420 180 M 460 140 L 460 180 M 460 140 L 460 180 M 420 180 L 500 180 M 460 140 L 500 180 M 500 140 L 500 180 M 540 140 L 500 180 M 460 180 L 540 180 M 500 140 L 540 180 M 540 140 L 540 180 M 580 140 L 580 180 M 540 140 L 580 180 M 580 140 L 100 220 M 140 180 L 140 220 M 100 180 L 140 220 M 180 180 L 140 220 M 100 220 L 180 220 M 140 180 L 180 220 M 140 220 L 260 220 M 300 180 L 300 220 M 260 180 L 300 220 M 340 180 L 300 220 M 260 220 L 340 220 M 300 180 L 340 220 M 300 220 L 420 220 M 460 180 L 460 220 M 420 180 L 460 220 M 500 180 L 460 220 M 420 220 L 500 220 M 460 180 L 500 220 M 460 220 L 100 260 M 140 220 L 140 260 M 100 220 L 140 260 M 180 220 L 140 260 M 100 260 L 180 260 M 140 220 L 180 260 M 140 260 L 260 260 M 300 220 L 300 260 M 260 220 L 300 260 M 340 220 L 300 260 M 260 260 L 340 260 M 300 220 L 340 260 M 300 260 L 420 260 M 460 220 L 460 260 M 420 220 L 460 260 M 500 220 L 460 260 M 420 260 L 500 260 M 460 220 L 500 260 M 460 260 L 20 300 M 20 260 L 20 300 M 60 260 L 60 300 M 20 260 L 60 300 M 60 260 L 60 300 M 100 260 L 100 300 M 60 260 L 100 300 M 100 260 L 140 300 M 100 260 L 140 300 M 140 260 L 140 300 M 180 260 L 140 300 M 100 300 L 180 300 M 180 260 L 180 300 M 220 260 L 180 300 M 140 300 L 220 300 M 180 260 L 220 300 M 220 260 L 220 300 M 260 260 L 260 300 M 220 260 L 260 300 M 260 260 L 300 300 M 260 260 L 300 300 M 300 260 L 300 300 M 340 260 L 300 300 M 260 300 L 340 300 M 340 260 L 340 300 M 380 260 L 340 300 M 300 300 L 380 300 M 340 260 L 380 300 M 380 260 L 380 300 M 420 260 L 420 300 M 380 260 L 420 300 M 420 260 L 460 300 M 420 260 L 460 300 M 460 260 L 460 300 M 500 260 L 460 300 M 420 300 L 500 300 M 500 260 L stroke newpath 500 300 M 540 260 L 500 300 M 460 300 L 540 300 M 500 260 L 540 300 M 540 260 L 540 300 M 580 260 L 580 300 M 540 260 L 580 300 M 580 260 L 20 340 M 20 300 L 20 340 M 60 300 L 60 340 M 20 300 L 60 340 M 60 300 L 60 340 M 100 300 L 100 340 M 60 300 L 100 340 M 100 300 L 100 340 M 140 300 L 140 340 M 140 300 L 140 340 M 100 340 L 180 340 M 140 300 L 180 340 M 180 300 L 180 340 M 220 300 L 180 340 M 140 340 L 220 340 M 180 300 L 220 340 M 220 300 L 220 340 M 260 300 L 260 340 M 220 300 L 260 340 M 260 300 L 260 340 M 300 300 L 300 340 M 300 300 L 300 340 M 260 340 L 340 340 M 300 300 L 340 340 M 340 300 L 340 340 M 380 300 L 340 340 M 300 340 L 380 340 M 340 300 L 380 340 M 380 300 L 380 340 M 420 300 L 420 340 M 380 300 L 420 340 M 420 300 L 420 340 M 460 300 L 460 340 M 460 300 L 460 340 M 420 340 L 500 340 M 460 300 L 500 340 M 500 300 L 500 340 M 540 300 L 500 340 M 460 340 L 540 340 M 500 300 L 540 340 M 540 300 L 540 340 M 580 300 L 580 340 M 540 300 L 580 340 M 580 300 L 100 380 M 140 340 L 140 380 M 100 340 L 140 380 M 180 340 L 140 380 M 100 380 L 180 380 M 140 340 L 180 380 M 140 380 L 260 380 M 300 340 L 300 380 M 260 340 L 300 380 M 340 340 L 300 380 M 260 380 L 340 380 M 300 340 L 340 380 M 300 380 L 420 380 M 460 340 L 460 380 M 420 340 L 460 380 M 500 340 L 460 380 M 420 380 L 500 380 M 460 340 L 500 380 M 460 380 L 100 420 M 140 380 L 140 420 M 100 380 L 140 420 M 180 380 L 140 420 M 100 420 L 180 420 M 140 380 L 180 420 M 140 420 L 260 420 M 300 380 L 300 420 M 260 380 L 300 420 M 340 380 L 300 420 M 260 420 L 340 420 M 300 380 L 340 420 M 300 420 L 420 420 M 460 380 L 460 420 M 420 380 L 460 420 M 500 380 L 460 420 M 420 420 L 500 420 M 460 380 L 500 420 M 460 420 L 20 460 M 20 420 L 20 460 M 60 420 L 60 460 M 20 420 L 60 460 M 60 420 L 60 460 M 100 420 L 100 460 M 60 420 L 100 460 M 100 420 L 140 460 M 100 420 L 140 460 M 140 420 L 140 460 M 180 420 L 140 460 M 100 460 L 180 460 M 180 420 L 180 460 M 220 420 L 180 460 M 140 460 L stroke newpath 220 460 M 180 420 L 220 460 M 220 420 L 220 460 M 260 420 L 260 460 M 220 420 L 260 460 M 260 420 L 300 460 M 260 420 L 300 460 M 300 420 L 300 460 M 340 420 L 300 460 M 260 460 L 340 460 M 340 420 L 340 460 M 380 420 L 340 460 M 300 460 L 380 460 M 340 420 L 380 460 M 380 420 L 380 460 M 420 420 L 420 460 M 380 420 L 420 460 M 420 420 L 460 460 M 420 420 L 460 460 M 460 420 L 460 460 M 500 420 L 460 460 M 420 460 L 500 460 M 500 420 L 500 460 M 540 420 L 500 460 M 460 460 L 540 460 M 500 420 L 540 460 M 540 420 L 540 460 M 580 420 L 580 460 M 540 420 L 580 460 M 580 420 L 20 500 M 20 460 L 20 500 M 60 460 L 60 500 M 20 460 L 60 500 M 60 460 L 60 500 M 100 460 L 100 500 M 60 460 L 100 500 M 100 460 L 100 500 M 140 460 L 140 500 M 140 460 L 140 500 M 100 500 L 180 500 M 140 460 L 180 500 M 180 460 L 180 500 M 220 460 L 180 500 M 140 500 L 220 500 M 180 460 L 220 500 M 220 460 L 220 500 M 260 460 L 260 500 M 220 460 L 260 500 M 260 460 L 260 500 M 300 460 L 300 500 M 300 460 L 300 500 M 260 500 L 340 500 M 300 460 L 340 500 M 340 460 L 340 500 M 380 460 L 340 500 M 300 500 L 380 500 M 340 460 L 380 500 M 380 460 L 380 500 M 420 460 L 420 500 M 380 460 L 420 500 M 420 460 L 420 500 M 460 460 L 460 500 M 460 460 L 460 500 M 420 500 L 500 500 M 460 460 L 500 500 M 500 460 L 500 500 M 540 460 L 500 500 M 460 500 L 540 500 M 500 460 L 540 500 M 540 460 L 540 500 M 580 460 L 580 500 M 540 460 L 580 500 M 580 460 L 100 540 M 140 500 L 140 540 M 100 500 L 140 540 M 180 500 L 140 540 M 100 540 L 180 540 M 140 500 L 180 540 M 140 540 L 260 540 M 300 500 L 300 540 M 260 500 L 300 540 M 340 500 L 300 540 M 260 540 L 340 540 M 300 500 L 340 540 M 300 540 L 420 540 M 460 500 L 460 540 M 420 500 L 460 540 M 500 500 L 460 540 M 420 540 L 500 540 M 460 500 L 500 540 M 460 540 L 100 580 M 140 540 L 140 580 M 100 540 L 140 580 M 180 540 L 140 580 M 100 580 L 180 580 M 140 540 L 180 580 M 140 580 L 260 580 M 300 540 L 300 580 M 260 540 L 300 580 M 340 540 L 300 580 M 260 580 L stroke newpath 340 580 M 300 540 L 340 580 M 300 580 L 420 580 M 460 540 L 460 580 M 420 540 L 460 580 M 500 540 L 460 580 M 420 580 L 500 580 M 460 540 L 500 580 M 460 580 L stroke grestore gsave 0.1 setlinewidth 0.0 setgray 20.000 20.000 (0) radius drawLabel 60.000 20.000 (0) radius drawLabel 100.002 20.000 (0) radius drawLabel 140.002 20.000 (2) radius drawLabel 179.998 20.000 (0) radius drawLabel 219.998 20.000 (0) radius drawLabel 259.999 20.000 (0) radius drawLabel 300.000 20.000 (2) radius drawLabel 340.001 20.000 (0) radius drawLabel 380.002 20.000 (0) radius drawLabel 420.002 20.000 (0) radius drawLabel 459.998 20.000 (2) radius drawLabel 499.998 20.000 (0) radius drawLabel 539.999 20.000 (0) radius drawLabel 580.000 20.000 (0) radius drawLabel 20.000 60.000 (0) radius drawLabel 60.000 60.000 (0) radius drawLabel 100.002 60.000 (0) radius drawLabel 140.002 60.000 (2) radius drawLabel 179.998 60.000 (0) radius drawLabel 219.998 60.000 (0) radius drawLabel 259.999 60.000 (0) radius drawLabel 300.000 60.000 (2) radius drawLabel 340.001 60.000 (0) radius drawLabel 380.002 60.000 (0) radius drawLabel 420.002 60.000 (0) radius drawLabel 459.998 60.000 (2) radius drawLabel 499.998 60.000 (0) radius drawLabel 539.999 60.000 (0) radius drawLabel 580.000 60.000 (0) radius drawLabel 20.000 100.002 (0) radius drawLabel 60.000 100.002 (0) radius drawLabel 100.002 100.002 (0) radius drawLabel 140.002 100.002 (2) radius drawLabel 179.998 100.002 (0) radius drawLabel 219.998 100.002 (0) radius drawLabel 259.999 100.002 (0) radius drawLabel 300.000 100.002 (2) radius drawLabel 340.001 100.002 (0) radius drawLabel 380.002 100.002 (0) radius drawLabel 420.002 100.002 (0) radius drawLabel 459.998 100.002 (2) radius drawLabel 499.998 100.002 (0) radius drawLabel 539.999 100.002 (0) radius drawLabel 580.000 100.002 (0) radius drawLabel 20.000 140.002 (2) radius drawLabel 60.000 140.002 (2) radius drawLabel 100.002 140.002 (2) radius drawLabel 140.002 140.002 (4) radius drawLabel 179.998 140.002 (2) radius drawLabel 219.998 140.002 (2) radius drawLabel 259.999 140.002 (2) radius drawLabel 300.000 140.002 (4) radius drawLabel 340.001 140.002 (2) radius drawLabel 380.002 140.002 (2) radius drawLabel 420.002 140.002 (2) radius drawLabel 459.998 140.002 (4) radius drawLabel 499.998 140.002 (2) radius drawLabel 539.999 140.002 (2) radius drawLabel 580.000 140.002 (2) radius drawLabel 20.000 179.998 (0) radius drawLabel 60.000 179.998 (0) radius drawLabel 100.002 179.998 (0) radius drawLabel 140.002 179.998 (2) radius drawLabel 179.998 179.998 (0) radius drawLabel 219.998 179.998 (0) radius drawLabel 259.999 179.998 (0) radius drawLabel 300.000 179.998 (2) radius drawLabel 340.001 179.998 (0) radius drawLabel 380.002 179.998 (0) radius drawLabel 420.002 179.998 (0) radius drawLabel 459.998 179.998 (2) radius drawLabel 499.998 179.998 (0) radius drawLabel 539.999 179.998 (0) radius drawLabel 580.000 179.998 (0) radius drawLabel 20.000 219.998 (0) radius drawLabel 60.000 219.998 (0) radius drawLabel 100.002 219.998 (0) radius drawLabel 140.002 219.998 (2) radius drawLabel 179.998 219.998 (0) radius drawLabel 219.998 219.998 (0) radius drawLabel 259.999 219.998 (0) radius drawLabel 300.000 219.998 (2) radius drawLabel 340.001 219.998 (0) radius drawLabel 380.002 219.998 (0) radius drawLabel 420.002 219.998 (0) radius drawLabel 459.998 219.998 (2) radius drawLabel 499.998 219.998 (0) radius drawLabel 539.999 219.998 (0) radius drawLabel 580.000 219.998 (0) radius drawLabel 20.000 259.999 (0) radius drawLabel 60.000 259.999 (0) radius drawLabel 100.002 259.999 (0) radius drawLabel 140.002 259.999 (2) radius drawLabel 179.998 259.999 (0) radius drawLabel 219.998 259.999 (0) radius drawLabel 259.999 259.999 (0) radius drawLabel 300.000 259.999 (2) radius drawLabel 340.001 259.999 (0) radius drawLabel 380.002 259.999 (0) radius drawLabel 420.002 259.999 (0) radius drawLabel 459.998 259.999 (2) radius drawLabel 499.998 259.999 (0) radius drawLabel 539.999 259.999 (0) radius drawLabel 580.000 259.999 (0) radius drawLabel 20.000 300.000 (2) radius drawLabel 60.000 300.000 (2) radius drawLabel 100.002 300.000 (2) radius drawLabel 140.002 300.000 (4) radius drawLabel 179.998 300.000 (2) radius drawLabel 219.998 300.000 (2) radius drawLabel 259.999 300.000 (2) radius drawLabel 300.000 300.000 (4) radius drawLabel 340.001 300.000 (2) radius drawLabel 380.002 300.000 (2) radius drawLabel 420.002 300.000 (2) radius drawLabel 459.998 300.000 (4) radius drawLabel 499.998 300.000 (2) radius drawLabel 539.999 300.000 (2) radius drawLabel 580.000 300.000 (2) radius drawLabel 20.000 340.001 (0) radius drawLabel 60.000 340.001 (0) radius drawLabel 100.002 340.001 (0) radius drawLabel 140.002 340.001 (2) radius drawLabel 179.998 340.001 (0) radius drawLabel 219.998 340.001 (0) radius drawLabel 259.999 340.001 (0) radius drawLabel 300.000 340.001 (2) radius drawLabel 340.001 340.001 (0) radius drawLabel 380.002 340.001 (0) radius drawLabel 420.002 340.001 (0) radius drawLabel 459.998 340.001 (2) radius drawLabel 499.998 340.001 (0) radius drawLabel 539.999 340.001 (0) radius drawLabel 580.000 340.001 (0) radius drawLabel 20.000 380.002 (0) radius drawLabel 60.000 380.002 (0) radius drawLabel 100.002 380.002 (0) radius drawLabel 140.002 380.002 (2) radius drawLabel 179.998 380.002 (0) radius drawLabel 219.998 380.002 (0) radius drawLabel 259.999 380.002 (0) radius drawLabel 300.000 380.002 (2) radius drawLabel 340.001 380.002 (0) radius drawLabel 380.002 380.002 (0) radius drawLabel 420.002 380.002 (0) radius drawLabel 459.998 380.002 (2) radius drawLabel 499.998 380.002 (0) radius drawLabel 539.999 380.002 (0) radius drawLabel 580.000 380.002 (0) radius drawLabel 20.000 420.002 (0) radius drawLabel 60.000 420.002 (0) radius drawLabel 100.002 420.002 (0) radius drawLabel 140.002 420.002 (2) radius drawLabel 179.998 420.002 (0) radius drawLabel 219.998 420.002 (0) radius drawLabel 259.999 420.002 (0) radius drawLabel 300.000 420.002 (2) radius drawLabel 340.001 420.002 (0) radius drawLabel 380.002 420.002 (0) radius drawLabel 420.002 420.002 (0) radius drawLabel 459.998 420.002 (2) radius drawLabel 499.998 420.002 (0) radius drawLabel 539.999 420.002 (0) radius drawLabel 580.000 420.002 (0) radius drawLabel 20.000 459.998 (2) radius drawLabel 60.000 459.998 (2) radius drawLabel 100.002 459.998 (2) radius drawLabel 140.002 459.998 (4) radius drawLabel 179.998 459.998 (2) radius drawLabel 219.998 459.998 (2) radius drawLabel 259.999 459.998 (2) radius drawLabel 300.000 459.998 (4) radius drawLabel 340.001 459.998 (2) radius drawLabel 380.002 459.998 (2) radius drawLabel 420.002 459.998 (2) radius drawLabel 459.998 459.998 (4) radius drawLabel 499.998 459.998 (2) radius drawLabel 539.999 459.998 (2) radius drawLabel 580.000 459.998 (2) radius drawLabel 20.000 499.998 (0) radius drawLabel 60.000 499.998 (0) radius drawLabel 100.002 499.998 (0) radius drawLabel 140.002 499.998 (2) radius drawLabel 179.998 499.998 (0) radius drawLabel 219.998 499.998 (0) radius drawLabel 259.999 499.998 (0) radius drawLabel 300.000 499.998 (2) radius drawLabel 340.001 499.998 (0) radius drawLabel 380.002 499.998 (0) radius drawLabel 420.002 499.998 (0) radius drawLabel 459.998 499.998 (2) radius drawLabel 499.998 499.998 (0) radius drawLabel 539.999 499.998 (0) radius drawLabel 580.000 499.998 (0) radius drawLabel 20.000 539.999 (0) radius drawLabel 60.000 539.999 (0) radius drawLabel 100.002 539.999 (0) radius drawLabel 140.002 539.999 (2) radius drawLabel 179.998 539.999 (0) radius drawLabel 219.998 539.999 (0) radius drawLabel 259.999 539.999 (0) radius drawLabel 300.000 539.999 (2) radius drawLabel 340.001 539.999 (0) radius drawLabel 380.002 539.999 (0) radius drawLabel 420.002 539.999 (0) radius drawLabel 459.998 539.999 (2) radius drawLabel 499.998 539.999 (0) radius drawLabel 539.999 539.999 (0) radius drawLabel 580.000 539.999 (0) radius drawLabel 20.000 580.000 (0) radius drawLabel 60.000 580.000 (0) radius drawLabel 100.002 580.000 (0) radius drawLabel 140.002 580.000 (2) radius drawLabel 179.998 580.000 (0) radius drawLabel 219.998 580.000 (0) radius drawLabel 259.999 580.000 (0) radius drawLabel 300.000 580.000 (2) radius drawLabel 340.001 580.000 (0) radius drawLabel 380.002 580.000 (0) radius drawLabel 420.002 580.000 (0) radius drawLabel 459.998 580.000 (2) radius drawLabel 499.998 580.000 (0) radius drawLabel 539.999 580.000 (0) radius drawLabel 580.000 580.000 (0) radius drawLabel grestore showpage 260 500 M 260 460 L 260 500 M 300 460 L 300 500 M 300 460 L 300 500 M 260 500 L 340Graph/doc/GRD15x15rad2.eps.gz010064400020550007177000000075640653410610500167340ustar00clevecompmath0000040000000685GRD15x15rad2.eps]ݎ ߧ^h/pnA/ @`l/N QC# Ǟs"&A8_}{:M:7^}ۇ{͔NǛwLe?=_ߏMo>ܿ}i:믗O?NÇ̓ojztt}tǻO4%Mwo7O/˳T^>=O|Zw/8K?^~yA]˛W5 1]t{xsé{>&0ߟrVm;<uOE{k9pǧS~?u]o9P%>$W@z2u%D=WZ g!ȝT'elZJ5ג|}1c*㮔(JVK-D}2:Q.I'e(F0I(N|ً?$_/R @-Eb,hyCpqsrTrrŕS%wWwrxCQj*9ʞ\CPNs"7{!\ p8Rɱ+Ǯ(sǩBSO=@ giВT-vuX"t Տ6_KrY6m$xYc!{ lbaVc{Y8=~2@ bl/ǀ ` ),UJ > m,2V+EW!FM 㔜]VVܵ0_/guuxETRvd5K .Zg ׂ:CT,mt@V(2g۾XC&7i9 p= j~s g0yă# #,<7 u-he"Zϻ ɹ'gO^rXYs*_yc)3( bPKrY,߂;[Ќ+R6_{5?Lpm1 ά fHi ` )/A\t%5Gc]SZx5Ĩig:A)9 w= jgrfY<"۴ wA`Qxhk!E#,L /Y6RPXkA!eWAFP"A|WD d_PIxͼ"\B Ϡ;Ds*_[aiiWAeª/ew'[N?_-h[)PEl/@[H+0Ytda3o!. g̐$CӬ 6h B]d`Gc]SZx5Ĩi:A)9 w= jrfY<"۴ wA`Qxhk!E#,L /Yp]PA<8AC,>K ;JF B>FXd'Ȯ`NG#( ;#ElaFA8XlV` k6H Kr{Qz#6f xܵ-(Yp9r$>6kPI*&) "|pgX4*W%I0=KjՈ|eyD"TT˃^"ȣ RE@xe|/p{K+K+zyn;l1.Zx5DI^66b2CB0Y rXxܵ-(Yx{"0ra;*,RM qlV-U'7(SNdhA w )A` Ana7Jo,ayهPx{4ZnAAıT$t60V)n8KU s-x /oK.a`AMÏ%PQƞ;zyL 1C{#3אqdLȩP[ #*&82\Dbdװ] -XF$GƑVEC`Cb]^t4EMAăb(`' CAJfMV\' kxc݀a,b 2vƐf A<n@vE ق FAр.H#-FeݽZ8$ԥm|iaTL(`'@PxX> 7zOa Ij@6KuR!H6A®xW-Ȑκ |uJjN6]d - l$ H\/eAeP.4[C:*X:fK@FNUr8E5HeG%K^z5,.L:`"^C:}(YxA⼺!z5H%` 2Ȼ D3+h%!9F 6H vZlɊA^)h%-A ԉ@C؂ #3Yy6Hs,/i$s:9])adZՂVX :pb]iCR{`Z!`VC#V 3Ue7;)`Yzϯ pFY vvb [!S&AKm.@V nvb - l Hmp\_TXPYx%;}ȃہ!1,Gq^]ѥl R_`-f7~]{~`bT\ ˖,)UȃŐN .Q. ,[wIH_ddwzWe?f 4K_*!vq2b!RmV6Yq;xX n@o0`R; bcH m \ ^U Va7 3WKla il@k !ppb]iC{~!hZ!X#V Xԩױ``adۂl·lVݐ:+k[!1&AKmn3Pjݐ:ak- lL[Djԉ!aT|b#4J؇#$U,^^^WNQHVV=7L'@)W1F)+4UTU9+.X M((V*\N(OO_[VW8\W][\?OPLOU^6?O_[V\W>'E^'JQ8N?[O_\<'/[X=U/]U]^ M6-83=OXWK_S[U?+WA^N;VS\?ET-:;HYO3]__ZWCWZ?AT^^9Z>7O[X>;M_8>G MY5!>?I^6QS?7=\?+]X_'I_.?I^)?EF__OC^5W_]G8[]>OMW=?N@>_/B/GY=O MRXOE\>GZS1_+#\N7Y>OR_,JKY?3KP_'SQ^NG]\NZQ+PNUP]OEC=W]X_'R[.W MMW=WR]52E1Z?'I9\TGDXS6=[=/-P_?GU]>_'N\LKSM)WE^^Z%]3Y';^\>?_, M.C]\+H.'7Y?++_GPR^#AN\?K3\>K9V YG'IY:LB[A^NO]=&7;0#+]WGTXK M]*[J=@^&_/?WGY_[\W!\?+I_.&YK=UI#[MAI5NOA/*^S2RZONAK,=7-%E3]- M)JS++^??3O^\YLZOV_,LGX>P/3\4 %@(E&+9@$@2H"H502K1!J05@"J50"J< MMYR>1'T,<\CCZNQ7'U93)4/C1C+\''5Z@A"B2H#)GCN?1TO "Y!" :# 9,1 M!NO/4AG6?RR5+:F>T4O%VI$(K8JU)6BE!A1MOC&C[#%HX&.6RN#CH10#*"48 M0JJVA*!7J;9$;0D&2&^B,8-V&8/]R%+]<%.QI(HEU3.$?=;+1E#;B9_#[LA& M?=ZK/ZRVT/D+L2^'4@U +4&18L0.4!/#IF#)-03E)$?*<8,(6I>X M/VJG-03FFLCDT 2G>&IBV*F8C8,M+;;E J"('?'\'J98' 15L>>&6]U#D401<^0:IEL^0;KE)*""JU%X-<24U\M<==L9P*YGBY%W&0<<6*\5U.%_*-80 MI29(4HZ8A VX'$C#T X-4G8(P60UR&$%G)84%(,/V1;,MJ!@"<'(?8K8PLB- M4H;M()QR+#:K3+ (YR4%Q> IF((-4H*2)06Y480]3-PHO:4:A%-.9+-HAH7S MDH)B\*G8@L46%"QIMO7B'+TC&<"]E2U&WF4<<#I""\^U8[&&*#5)$G+$)&S M9?OEX49LD-I2(9BL!CFL@-,"03S>6H+9%I0L1&J8W803CE6&Q6 MF6 1S@L$\9AK"#9("0)+"'*C"'N8N%%Z(S8(IYS(9M$,"^<%@GCGC%CV$33RZ"I7 M^"7RC4D9,/(]2[#2:K(2CZX6B=6(?&41T'FV]TL"PBM+Y"N+G/)Z M>;]N.P/8]6PQ\B[C@ ,36GC>'8LU1*E)$EZG-A(VX&*",K1#@Y0=0C!9#7)8 M :<%@GC.%[AB*V,'*CE&$["*<9W#?<*+VE&H133F2S:(:%\P)!/.Y:@L46E"QAMO72*[TC&<"]E2U& MWF4<<#J]%N%Y=RS6$*4F2%*.F(0-.&^_#4*G-$AMJ1!,5H,<5L!I24$Q^)!M MP6P+"I80C-RGB"V,W"BU$3L(IQR+S2H3+,)Y24$Q> JF8(.4H&1)06X480\3 M-TIOQ ;AE!/9+)IAX;RDH!A\*K9@L04%2PB>FU&OK80G8>)[9N/89]#&R*A5 MQEK+M@_XLBA8@<<6L0T-"CCNBX'&K,C#J$72+WQST@;D^Y9@I=5D)1Y&+9*K MP5<6 9V^3O7*DO#*DNJ]1")4D0.^J(-4;T,/"<'0!H&CB#R*@$O<(-7;6'I( M"!(/(^(PB(=!N,0-TKVE'A*"B8>11& M*<-V$$XY%IM5)EBD=IL4Q..N(=@@)0@LO))N+.QAXD;I+=4@G'(BFT4S+)P7 M".)QUQ(LMJ!D";.M%U3O2 9P;V6+D7<9!YR.T,+S[EBL(4I-DH0<,0D;<-E^ M9;@1&Z2V5 @FJT$.*^"T0!"/NY9@M@4E2QQ!N4\16QBY46HC=A!..1:;5298 MI#ZQI" >=PW!!BE!8 E!;A1A#Q,W2F_$!N&4$]DLFF&)>=F'4'@/GH*M]Y3Q M>S2KX!!:I/1_BY)N0<5!Q+%4@"2P!?QT-C!6*8P ;L$XG:E+50JC#M8/R.'L";01Y-D,./JB454%'&GH'WB/$[>@#O$'G4Q!9,# : M,4/!P!O'\!T"P'N<$9XC,XK7D.)Q9+ZH3*3TR,S(J5 ;CUNM#",JNB8X,EQ$ MYHL$8F37L*M=#"U8"$;*)$?&D5;K11*1O>M#8$, &=EBY%V&7N[5XG09-$6B M&0A-TD'%%\2#BL5B*& G( N'IQ%#L$%*L(/4 F:;E4U67"<@':YK$+87!/%X M8[$:A-V C!^>82S!8@LRI'8.Q/_&D&;E&0C;VR"5[P1!/!09K [";D!V$0]% MEB#9@@W"1D'BT8"4Y]>+4;>9>C=O5J,)8T#X+-X9Z3P=A_R!):D V2^_Y=0)2(K=: \TJKR6J03N,V"+L!@N)=9 N2+=@@ M;!0D?PU([:VUY@/5!KI<+_B*94'%9>E0G?$N >DT6QC[D >OMP-#.J'N3Q>C6H^"R\O>P'+LE, M.NI@(@]>KQ=#.GTH67B#V0]!XKRZB"$.H\L1XGHU2"4"@86WF-U@H@J:A;4% M^,8 ,K+%R+L,O>ZKQ>GR@XI$,Q":I8.**V@E$A6+(968E3E&G9P;"S9("7:0 M6L!LL[+)BNL$I.S<0=A>*6@E+16K0=@-F<_4B4!#L-B"#*FM(S.:!J19>0;" M]C9(I7.EH!$5E2SG+VD; YLD70]*O%:8A#4GO^\F 76B%@5D.1(U:#B@FIQ#,(XE5E-^JK!#L(&P4I M8 .R67K/KQ.0"G!&LED-PO9V$'8#!/&J8@D66Y AG5,.)JM!#DMM[BX3[4 ! MYI56D]4@G:1N$'8#!/&J8@F2+=@@;!2DM@U(;:+SR\MPIUP>\%]46%#Q67B+ ML=XEH8([I8Q]R(/7VX$AG3&6++S%[$>=<5Y=D!B'T:6%T6P-4KE?8.$M9C=^ MK)*(7>H5VWM^8 5B&U1R(/7Z\603HX*E@SND?TN 1G) M4=7>+@.*Z]4@E>:4+!GW6\UW24CVL ]?#@%D9(N1=QEZW5>+TV4_%8EF(#1+ M!Q5?$*\J%HLAE7:&L.G$<10RJ&(A@OF>#E+KFFU6-EEQG8"4RSL(NPZ">(.Q M6 W";D"V%F\PEF"Q!1E2.PIBMV-(L_(,A.UMD I<@R!>50Q6!V$W(#.,5Q5+ MD&S!!F&C(&EL0,KS:PLAR]!P!7#@V6+D78;>]*O%:8A#DGM^$2%H!UHA'%@# MK2-6@XH)J5BZ%-2IU[%@@Y1@!V&C9(+;@FR6WMSK!*3"MY%L5H.PO1V$W9"" M.BMK"!9;D"&=,0\FJT$.2VUNRC-0P)#J:K(:E+"]'83=D((Z86L(DBW8(&R4 M3-Q;D-I$ZVK&U(DAM6$;5'P6WF+V(_$T2I'2V(<\>+T=&-+Y<,G"6\Q^3!WG MU87 <1C$@]?Y<(949AM8>(O9C8X3SJM++&-[+P_*>+T:5'P6WF+V@\X$K)85 M5NV-/'B]7@SIU*]D\;N<_ZJ?["%("&^W1G:7>$XZ#,R0"N@""R\WNSEA&DYW M&)S=BH&L4=4S6*KU0F6E"-XA#-*76?7*7Y117>J"*IJKMFI*C.K77U#WK#R3!'[QJ\BJ"+7-ZX6^\:OJKYQJ]@W[KC8 M-[Y6F>D$^\:O2C#'X;C8-ZX6^\:O*C.K77VS+93_>>,6L6_\*H(J__/&U6+? M^%75-VX5^\8=%_O&URHSG6#?^%4)YNA_WKA:[!N_JLRL=CWY'B9\XQ?QV=>O M(JCR3[^N%A]__:IZ_G6K^ #LCHM/P+Y6F>D$GX']J@1S]$_!KA8?@_VJ,K/: MU3=;>-KL6_\JNH;MXI] MXXZ+?>-KE9E.L&_\J@1S=#]O?"WVC5]59E:[^J9,W,/](O:-7T50Y?O&U6+? M^%75-VX5^\8=%_O&URHSG6#?^%4)YNC[QM5BW_A596:U-]_42;B^\8NJ;W:J M"*ID$^\:O2C!']WSC:[%O M_*HRL]K5-Z\F[N%^$?O&KR*H\C]O7"WVC5]5?>-6L6_<<;%O?*TRTPGVC5^5 M8([^YXVKQ;[QJ\K,:F^^J9*N;_RBZIN=*H(JUS>^5O7-3M7F&[^J^L8?5_7- MCE:9Z43US4Y5@CFZOO&U*KI35696N_IF*_9]XQ:Q;_PJ@BK?-ZX6^\:OJKYQ MJ]@W[KC8-[Y6F>D$^\:O2C!'WS>N%OO&KRHSJ]W2%>?_^>W'ZW?'J_\"_89G %!8UY #8 end Graph/doc/GRD15x15rad2.eps.gz.uu010064400020550007177000000125600653410610600173550ustar00clevecompmath00000400000006begin 644 GRD15x15rad2.eps.gz M'XL("/'8.#4 T=21#$U>#$U&&@OXNK3 M8./];"^R]1J[3NP@Z+OW^QE1PT.1(Z -$L>>PW.&(H\F MDD$XK_[RT\]??7O_],OQJ_PZ3?_\Z>?OOSJ\SC>O7GWW]-N'^X;Z>_/=_WMQ-;Q\^W+]]^O!I M.O#KKY?IYOET]^;7Z9OIR_3'='WES73ZZ\/Q\\>[3^^G-,TE37?/;Z8WCT\OQ\NS MMP^/C]/-5)5>/CU/Y:3S?%K/^NC^^>[S#W>_'!\OKSA+/UY^M7E!7=_QRYOW M5];YX34,'OXQ7?[2#[]T'KY[N?O]>',%IL.IEJ>"O'N^^Z,^^K(F,-W=WY]R MNE:H@;4 ;=$5.Z^X_CS]'W5/17OZ];B-U-QK.:ZE_?QP?ZK]QZ>/4Y[N'WX_ M=>A=U=T\Z/+?/WV^UN?Y^/+IZ?FX]N[40ZG8:57I<%[7V2675]UTUKJZHLJ? M%I/3]./YA]/?/TCET_J\Z.'(8#+ MR)W^BU2!_O>EBB>U96REYEJ1&4HUUY*@E1K UGQ]!N\QJ.-CD2K@XZZ4 "BE M&$JJEH2@5DLMB=D2 I#=1'T&[3(Z^U&DMNDN[$FQ)[5E*/NDRT8PVTF>P^XH M3GS9BS\D7^C\$[4ONU(-0"U%T6(L'&AY0W ;Y.QQ&N)S'U<(=\H&@17-[')XGT/X 5%J*CG*GEQ#4$YSE-PB'3=[HR&PHH5<#@UP M.%+3R;$KQZZI[A1"VU/]3Y7V/8U "0799VF(T))4_[NA+9D&H,K7 M=G58&B)T"]6/N#9?&8&PO$MR60 1-I*DD0)MCJOV)'BN[K6_C/WE^EEC["'W M>]@@;-0&8NQA5A!C>UF^.(P]Y'X/!3*-VD"8X L8?<[>$&P@P; MM&"&"RF(L;TL[56%2I<*V3X*@&TL'J/L,@Z8V%8KFQM%5ZPA1DV1M!P+"?O0 M(..4G%U6@P)6QMRUH,HP%U^P^(**I00O9]C<=>4&PG7-[+-X@$68O!94&5)V M!1MD!#5+"2[2?[L#&H3K6LAGT0@+D]>".D/V!=D75"QMFW3Q@-U N!6*!ZC M[#(.N!REA6?;OEA#C)HFX;$WE^Z^:9#9 3F[K 8%K(RY@R"><#W!X@MJ%IY^ M<^GNFPV$ZYK99_$ BS!Y$,2#KB/8(",(+#P$Y]+?-PW"=2WDLVB$9;XB6A#/ MNYX@^X*:!??)N=XG9[Q/7I$#-@A?M($8 M>Y@5A)>@-3],<)8$;0\%FC'##809SJP@O 2M$&9(DJ%IU@;"#!NT8(8+*0@O M0;-<@G2ATB4UVTA6?N.J5!QBDYNZP& M!:R,N8,@GG<]P>(+:A8>A6?NNG(#X;IF]ED\P"*SV[0@GG<=P08906#A47CF M_@YH$*YK(9]%(RQ,'@3QO.L)LB^H6(+,#H,V1=D7U"Q ME."Y__6:27C-O"('Y%P>[$()!;G/\L^@P, [X16:L41S&H J7UO:86D([VE7 MB/"+064$PJHOR64!A'A1?J.J5!QBDYNZP&!:R, MN8,@GG<]P>(+:A8>A1?JNG(#X;IF]ED\P"*SV[0@GG<=P08906#A47BA_@YH M$*YK(9]%(RQ,'@3QO.L)LB^H67"77;BW@03 K5 \1MEE'' Y2@L/O'VQAA@U M35)R)"0LP&4C<7=+-A3W!X@MJECJY2IUF+.$LA3*[ M;0/ADF?V63S (O/MT8)X2G8$&V0$@:4$I5"$-5RD4'8C-@B7O)#/HA&66I=_ M"H7WX+G:>P_WWV-9C"FTP=+_;:!T'5?L##IR!4@#ZYB?G1")\HO07*"*0I207,0..6@5>,_CNV M %XO2J^(;3PQ.P .&RH&WCBZ[U W@P/J5?%.B34Z0@-<#A2\Z;X4$XASG0= MUGF6%9F>I7V.&913:MY$'LHIQ)F4PTZ0K,A,RI5]#@Z]:35GN@[E-*+KO1U3 MZP+(*!ZC[#*L19+'V4S)Q21",SJD!G'/IWN0F=O,V64U*& 9VX$@GE\\P>(+ M:A:A^_NLS? ?[LW-&%\ 835F]ED\P#(^!T$\VCB"FT%#% 26$BP^2R [2II& M(*S&0CZ+1EBX9!#$XXTGR*Y@3IN91^H!N".+QRB[##LCF3Q.0P)2-%B98."H MCKOU6 U"LS3(;#@05%>:[ HV2 OZY^ - XL$$Z$.Y+."B5 SEC>3SVH0EG8# M825 4+V+?4'V!06RTZ?9934H8 4SJV:8;TDNJT%V]S8(EPR"ZEWD"Y(OV""L M!DS5.I#9):D.\YFM<+D)R&W(@P(6AX)V;LX15) SI6I]*.NRVR$-L.R\J1+T M9EN-H(*<>5/C#9)UV7G3,L RDZ-:T)E2M195D#-LYAM#DAUR[ KA'<0%@-F.5U()\5 MS/*:@(GQ!#7$:%'N>H-D7792N RPS,PO".(EQA$$B,$VE+M- M.3_PAF%IA,6AH#=#:P05Y,RUFJ;,LB[;Y33 LA.J2M";AC6""G(F5$U32-9E M)U3+ ,O,FFI!9Z[5"&I(5WX[&MH%D%$\1MEE6+(GQ2 WBGF4[ MT,C,JAFHSME]3X,"EO$D".(%QA,LOJ!FX=W&837(3&AO1F<#"*LQL\_B 9;Q M/PCB!<81W SWHB"P\&[CL02R<]UI!,)J+.2S:(2%2P9!O,1X@NP*YM3&C[5! M*X ;M7B,LLNPX\K)XS0D(!W0+.<'C67'4QU6@] L#3(;3@O:\=2^8(.,X ;" M:N@I; _R63/6<$Y;EAUJ=5@-PAIN(%RR%K1#K8X@^X("V8GO[+(:%+ (:TAE MR[*CL'U6@^PV;1 N60O:45A'D'S!!F$U]"2[!YGMD.H K?'\Y8'\UH('!2R. M!?$2XPEJB' [4-^'LBZ['=( R\YX:T&\Q'B"&B*T*'6]0;(N.^-=!EAF6AL$ M\1+C" )$:!ON-N7R@/M=;A#'++RI[(\X$[#:E+"I_"S)VU8*9.=]-4O>Y1], M-W/%)@4-X;W7F=HE69,= Q;(C.8""Z\BNQ/"U%UN=V1V9V VGX=J4_W77]/? MZA\ *W_>[LWIV+ ?9KK/'L1(/E(#R2-"B5]?-B6X'2K#, R58>*#!*U@&C!+&5*/$0:2#0J.$ M2M4H<=!JE#"H&B7,J1HE5N*!$E2CQ$&+7EUHE%"I&B4.XH$&KT:I?0Z=$@=5 M=">*((HBL\1:U2T[4:M=XJCJESBO:I@=+1ZI1+7,3M0":^SF54T3:U77[$3Q M2+>K;]9V]KU<1H+$-Q0Z@H:BJF_"*/%-F)?X)M02W\11U3=Q%,,:^Q^(/%() M\4T<=3L2);X)\Q+?Q%5=@]9&Q=^;,$A\$T<11,6^";7$-W%4]4T8);X)\Q+? MQ%H\4@GQ31RUP!ICWX1:XILXBD>Z74^^AP'?Q$%R]HVC"*+BTV^H) M?\,H.0"'>'W)M82W\11U3=AE/@FS$M\$VOQ2"7$-W'4 FL,OS>QEO@FCN*1;J^^J64+ MSS=Q4/6-1(7GFYVHU3=Q5/5-G%==?ZQ5T9VHU3<[40QK#,\WL5;US4[4[4A4 M]4V<5_7-3E77H+4@X?'Y)M82W\11U3=AE/@FS$M\ M$VOQ2"7$-W'4 FL,SS>QEO@FCN*1;J^^J8L(?1,'5=_L1!%$A=^;6*OZ9B=J M]4T<57T3YU5]LZ/%(Y6HZ$[4 FL,OS>Q5O7-3A2/=+OZ9HF.ZV4D2'Q3H\+S MS4Y4]4T8);X)\Q+?A%KBFSBJ^B:.8EAC>+Z)M<0W<=3M2)3X)LQ+?!-7=0VZ M';B'QT'BFSB*("KV3:@EOHFCJF_"*/%-F)?X)M;BD4J(;^*H!=88^R;4$M_$ M43S2[=4W53+T31Q4?;,311 5GF]BK>J;G:C5-W%4]4V<5_7-CA:/5*+Z9B=J M@36&YYM8JZ([43S2[>J;-3CV31@DOHFC"*)BWX1:XILXJOHFC!+?A'F);V(M I'JF$^":.6F"-L6]"+?%-',4CW6[3%>?_^>W'NW?'F_\"PE42 8UY ") end ZZ\/Q\\>[3^^G-,TE37?/;Z8WCT\OQ\NS MMP^/C]/-5)5>/CU/Y:3S?%K/^NC^^>[S#W>_'!\OKSA+/UY^M7E!7=_QRYOW M5];YX34,'OXQ7?[2#[]T'KY[N?O]>',%IL.IEJ>"O'N^^Z,Graph/doc/makefile010064400020550007177000000000270654276740000154100ustar00clevecompmath00000400000006clean : - rm -f *.dvi I2Ohash.h010064400020550007177000000001100653410636700135010ustar00clevecompmath00000400000006#ifndef _I2Ohash_ #define _I2Ohash_ #include "I2Ohash/I2Ohash.h" #endif I2Ohash/I2Ohash.h010064400020550007177000000107520653410577100147510ustar00clevecompmath00000400000006/* I2Ohash.h */ #include "../Utilities.h" /*--------------------------------------------------------------------*/ typedef struct _I2Ohash I2Ohash ; struct _I2Ohash { int nlist ; int grow ; int nitem ; I2OP *baseI2OP ; I2OP *freeI2OP ; I2OP **heads ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c --------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------- create and return a new instance of the I2Ohash object created -- 98jan29, cca ----------------------------------------------------- */ I2Ohash * I2Ohash_new ( void ) ; /* ------------------------------------------- set the default fields for an I2Ohash object created -- 98jan29, cca ------------------------------------------- */ void I2Ohash_setDefaultFields ( I2Ohash *hashtbl ) ; /* ----------------------- clear the data fields created -- 98jan29, cca ----------------------- */ void I2Ohash_clearData ( I2Ohash *hashtbl ) ; /* ----------------------- free the I2Ohash object created -- 98jan29, cca ----------------------- */ void I2Ohash_free ( I2Ohash *hashtbl ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------ initializer, (1) set the number of lists to nlist and allocate the heads[] vector (2) initialize nobj I2OP objects (2) set hashtbl item growth factor to grow created -- 98jan29, cca ------------------------------------------ */ void I2Ohash_init ( I2Ohash *hashtbl, int nlist, int nobj, int grow ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ----------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------- insert the (key1, key2, value) triple into the hash table created -- 98jan29, cca --------------------------------------------------------- */ void I2Ohash_insert ( I2Ohash *hashtbl, int key1, int key2, void *value ) ; /* ------------------------------------------------ locate the first (key1,key2,*) in the hash table return value -- 0 -- no (key1,key2,*) value triple 1 -- (key1,key2,value) value triple found, value put into *pvalue created -- 98jan29, cca ------------------------------------------------ */ int I2Ohash_locate ( I2Ohash *hashtbl, int key1, int key2, void **pvalue ) ; /* -------------------------------------------------- remove the first (key1,key2,*) from the hash table return value -- 0 -- no (key1,key2,*) value triple 1 -- (key1,key2,value) value triple found, value put into *pvalue created -- 98jan29, cca -------------------------------------------------- */ int I2Ohash_remove ( I2Ohash *hashtbl, int key1, int key2, void **pvalue ) ; /* --------------------------------------------------------------- return a measure of the nonuniform distribution of the entries. a value of 1.0 is best. created -- 98jan29, cca --------------------------------------------------------------- */ double I2Ohash_measure ( I2Ohash *hashtbl ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c ------------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- purpose -- to write the I2Ohash object to a file created -- 98jan29, cca ----------------------------------------------- */ void I2Ohash_writeForHumanEye ( I2Ohash *hashtbl, FILE *fp ) ; /*--------------------------------------------------------------------*/ I2Ohash/makefile010064400020550007177000000002230663622360500150330ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean cd drivers ; make clean I2Ohash/src/makefile010064400020550007177000000007010663602443700156250ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = I2Ohash $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG I2Ohash/src/makeGlobalLib010064400020550007177000000005750660026103600165330ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = I2Ohash SRC = basics.c \ init.c \ IO.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a I2Ohash/src/IO.c010064400020550007177000000027630653410577000146070ustar00clevecompmath00000400000006/* IO.c */ #include "../I2Ohash.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to write the I2Ohash object to a file created -- 98jan29, cca ------------------------------------------------ */ void I2Ohash_writeForHumanEye ( I2Ohash *hashtable, FILE *fp ) { double measure ; int count, loc, nfull ; I2OP *i2op ; if ( hashtable == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in I2Ohash_writeForHumanEye(%p,%p)" "\n hashtable is NULL or file pointer is NULL", hashtable, fp) ; exit(-1) ; } fprintf(fp, "\n\n I2Ohash : %d lists, %d items", hashtable->nlist, hashtable->nitem) ; nfull = 0 ; measure = 0.0 ; for ( loc = 0 ; loc < hashtable->nlist ; loc++ ) { if ( (i2op = hashtable->heads[loc]) != NULL ) { fprintf(fp, "\n %4d : ", loc) ; count = 0 ; while ( i2op != NULL ) { if ( ++count % 4 == 0 ) { fprintf(fp, "\n") ; } fprintf(fp, " < %6d, %6d, %p >", i2op->value0, i2op->value1, i2op->value2) ; i2op = i2op->next ; } measure += count*count ; nfull++ ; } } measure = sqrt(measure) ; fprintf(fp, "\n %d empty lists, %d items, %.3f ratio", nfull, hashtable->nitem, measure*sqrt((double) hashtable->nlist)/hashtable->nitem) ; return ; } /*--------------------------------------------------------------------*/ I2Ohash/src/basics.c010064400020550007177000000047100653410577000155360ustar00clevecompmath00000400000006/* basics.c */ #include "../I2Ohash.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ create and return a new instance of the I2Ohash object created -- 98jan29, cca ------------------------------------------------------ */ I2Ohash * I2Ohash_new ( void ) { I2Ohash *hashtable ; ALLOCATE(hashtable, struct _I2Ohash, 1) ; I2Ohash_setDefaultFields(hashtable) ; return(hashtable) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- set the default fields for an I2Ohash object created -- 98jan29, cca -------------------------------------------- */ void I2Ohash_setDefaultFields ( I2Ohash *hashtable ) { if ( hashtable == NULL ) { fprintf(stderr, "\n fatal error in I2Ohash_setDefaultFields(%p)" "\n hashtable is NULL\n", hashtable) ; exit(-1) ; } hashtable->nlist = 0 ; hashtable->grow = 0 ; hashtable->nitem = 0 ; hashtable->baseI2OP = NULL ; hashtable->freeI2OP = NULL ; hashtable->heads = NULL ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields created -- 98jan29, cca ----------------------- */ void I2Ohash_clearData ( I2Ohash *hashtable ) { I2OP *i2op ; if ( hashtable == NULL ) { fprintf(stderr, "\n fatal error in I2Ohash_clearData(%p)" "\n hashtable is NULL\n", hashtable) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n I2Ohash_clearData") ; fflush(stdout) ; #endif while ( (i2op = hashtable->baseI2OP) != NULL ) { #if MYDEBUG > 0 fprintf(stdout, "\n baseI2OP = %p", i2op) ; fflush(stdout) ; #endif hashtable->baseI2OP = i2op->next ; I2OP_free(i2op) ; } if ( hashtable->heads != NULL ) { FREE(hashtable->heads) ; } I2Ohash_setDefaultFields(hashtable) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- free the I2Ohash object created -- 98jan29, cca ----------------------- */ void I2Ohash_free ( I2Ohash *hashtable ) { if ( hashtable == NULL ) { fprintf(stderr, "\n fatal error in I2Ohash_free(%p)" "\n hashtable is NULL\n", hashtable) ; exit(-1) ; } I2Ohash_clearData(hashtable) ; FREE(hashtable) ; return ; } /*--------------------------------------------------------------------*/ I2Ohash/src/init.c010064400020550007177000000026300665016332400152320ustar00clevecompmath00000400000006/* init.c */ #include "../I2Ohash.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------ initializer, (1) set hashtable maximum size to nlist and allocate the heads[] vector (2) initialize nobj I2OP objects (2) set item growth factor to grow created -- 98jan29, cca ------------------------------------------ */ void I2Ohash_init ( I2Ohash *hashtable, int nlist, int nobj, int grow ) { int ii ; if ( hashtable == NULL || nlist <= 0 ) { fprintf(stderr, "\n\n error in I2Ohash_init(%p,%d,%d,%d)" "\n hashtable is NULL or nlist = %d is nonpositive\n", hashtable, nlist, nobj, grow, nlist) ; exit(-1) ; } if ( nobj <= 0 && grow <= 0 ) { fprintf(stderr, "\n\n error in I2Ohash_init(%p,%d,%d,%d)" "\n nobj = %d, grow = %d\n", hashtable, nlist, nobj, grow, nobj, grow) ; exit(-1) ; } I2Ohash_clearData(hashtable) ; hashtable->nlist = nlist ; hashtable->grow = grow ; if ( nobj > 0 ) { hashtable->baseI2OP = I2OP_init(nobj+1, I2OP_FORWARD) ; hashtable->freeI2OP = hashtable->baseI2OP + 1 ; hashtable->baseI2OP->next = NULL ; } ALLOCATE(hashtable->heads, struct _I2OP *, nlist) ; for ( ii = 0 ; ii < nlist ; ii++ ) { hashtable->heads[ii] = NULL ; } return ; } /*--------------------------------------------------------------------*/ I2Ohash/src/util.c010064400020550007177000000200760653410577000152520ustar00clevecompmath00000400000006/* util.c */ #include "../I2Ohash.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- insert the (key1, key2, value) triple into the hash table created -- 98jan29, cca --------------------------------------------------------- */ void I2Ohash_insert ( I2Ohash *hashtable, int key1, int key2, void *value ) { int loc, loc1, loc2 ; I2OP *i2op, *j2op, *prev ; if ( hashtable == NULL ) { fprintf(stderr, "\n error in I2Ohash_insert(%p,%d,%d,%p)" "\n hashtable is NULL \n", hashtable, key1, key2, value) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n inside I2Ohash_insert(%p,%d,%d,%p)", hashtable, key1, key2, value) ; fflush(stdout) ; #endif /* --------------------------------------------------- get the list to hold the (key1, key2, value) triple --------------------------------------------------- */ loc1 = (key1 + 1) % hashtable->nlist ; loc2 = (key2 + 1) % hashtable->nlist ; loc = (loc1*loc2) % hashtable->nlist ; #if MYDEBUG > 0 fprintf(stdout, "\n loc1 = %d, loc2 = %d, loc3 = %d", loc1, loc2, loc) ; fflush(stdout) ; #endif /* -------------------------------------------------------- get the list item to hold the (key1, key2, value) triple -------------------------------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n hashtable->freeI2OP = %p", hashtable->freeI2OP) ; fflush(stdout) ; #endif if ( (i2op = hashtable->freeI2OP) == NULL ) { if ( hashtable->grow <= 0 ) { fprintf(stderr, "\n fatal error in I2Ohash_insert(%p,%d,%d,%p)" "\n no free list items, grow = %d", hashtable, key1, key2, value, hashtable->grow) ; exit(-1) ; } i2op = I2OP_init(hashtable->grow, I2OP_FORWARD) ; hashtable->freeI2OP = i2op + 1 ; i2op->next = hashtable->baseI2OP ; hashtable->baseI2OP = i2op ; i2op = hashtable->freeI2OP ; } hashtable->freeI2OP = i2op->next ; #if MYDEBUG > 0 fprintf(stdout, "\n i2op = %p, hashtable->freeI2OP = %p", i2op, hashtable->freeI2OP) ; fflush(stdout) ; #endif i2op->value0 = key1 ; i2op->value1 = key2 ; i2op->value2 = value ; i2op->next = NULL ; #if MYDEBUG > 0 fprintf(stdout, "\n i2op : value0 %d, value1 %d, value2 %p, next %p", i2op->value0, i2op->value1, i2op->value2, i2op->next) ; fflush(stdout) ; #endif /* -------------------------------------------- insert the (key1, key2, value) into its list -------------------------------------------- */ for ( j2op = hashtable->heads[loc], prev = NULL ; j2op != NULL ; j2op = j2op->next ) { #if MYDEBUG > 0 fprintf(stdout, "\n j2op : value0 %d, value1 %d, value2 %p, next %p", j2op->value0, j2op->value1, j2op->value2, j2op->next) ; fflush(stdout) ; #endif if ( j2op->value0 > key1 || (j2op->value0 == key1 && j2op->value1 >= key2 ) ) { break ; } prev = j2op ; } if ( prev == NULL ) { #if MYDEBUG > 0 fprintf(stdout, "\n heads[%d] = %p", loc, i2op) ; #endif hashtable->heads[loc] = i2op ; } else { #if MYDEBUG > 0 fprintf(stdout, "\n %p->next = %p", prev, i2op) ; #endif prev->next = i2op ; } #if MYDEBUG > 0 fprintf(stdout, "\n %p->next = %p", i2op, j2op) ; #endif i2op->next = j2op ; hashtable->nitem++ ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ locate the first (key1,key2,*) in the hash table return value -- 0 -- no (key1,key2,*) value triple 1 -- (key1,key2,value) value triple found, value put into *pvalue created -- 98jan29, cca ------------------------------------------------ */ int I2Ohash_locate ( I2Ohash *hashtable, int key1, int key2, void **pvalue ) { int loc, loc1, loc2, rc ; I2OP *i2op ; /* --------------- check the input --------------- */ if ( hashtable == NULL || pvalue == NULL ) { fprintf(stderr, "\n error in I2Ohash_locate(%p,%d,%d,%p)" "\n hashtable or pvalue is NULL\n", hashtable, key1, key2, pvalue) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n inside I2Ohash_locate(%p,%d,%d,%p)", hashtable, key1, key2, pvalue) ; fflush(stdout) ; #endif loc1 = (key1 + 1) % hashtable->nlist ; loc2 = (key2 + 1) % hashtable->nlist ; loc = (loc1*loc2) % hashtable->nlist ; #if MYDEBUG > 0 fprintf(stdout, "\n loc1 = %d, loc2 = %d, loc3 = %d", loc1, loc2, loc) ; fflush(stdout) ; #endif /* --------------------------------------------- find the location of the first (key,*) triple --------------------------------------------- */ for ( i2op = hashtable->heads[loc] ; i2op != NULL ; i2op = i2op->next ) { #if MYDEBUG > 0 fprintf(stdout, "\n i2op = %p, value0 = %d, value1 = %d, value2 = %p, next = %p", i2op, i2op->value0, i2op->value1, i2op->value2, i2op->next) ; fflush(stdout) ; #endif if ( i2op->value0 > key1 || (i2op->value0 == key1 && i2op->value1 >= key2) ) { break ; } } rc = 0 ; if ( i2op != NULL && i2op->value0 == key1 && i2op->value1 == key2 ) { /* -------------------------- (key,*) found, set *pvalue -------------------------- */ *pvalue = i2op->value2 ; rc = 1 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- remove the first (key1,key2,*) from the hash table return value -- 0 -- no (key1,key2,*) value triple 1 -- (key1,key2,value) value triple found, value put into *pvalue created -- 98jan29, cca -------------------------------------------------- */ int I2Ohash_remove ( I2Ohash *hashtable, int key1, int key2, void **pvalue ) { int loc, loc1, loc2, rc ; I2OP *i2op, *prev ; /* --------------- check the input --------------- */ if ( hashtable == NULL || pvalue == NULL ) { fprintf(stderr, "\n error in I2Ohash_remove(%p,%d,%d,%p)" "\n hashtable or pvalue is NULL\n", hashtable, key1, key2, pvalue) ; exit(-1) ; } loc1 = (key1 + 1) % hashtable->nlist ; loc2 = (key2 + 1) % hashtable->nlist ; loc = (loc1*loc2) % hashtable->nlist ; /* --------------------------------------------------- find the location of the first (key1,key2,*) triple --------------------------------------------------- */ for ( i2op = hashtable->heads[loc], prev = NULL ; i2op != NULL ; i2op = i2op->next ) { if ( i2op->value0 > key1 || (i2op->value0 == key1 && i2op->value1 >= key2) ) { break ; } prev = i2op ; } rc = 0 ; if ( i2op != NULL && i2op->value0 == key1 && i2op->value1 == key2 ) { /* ---------------------------------- (key,*) found, remove, set *pvalue ---------------------------------- */ if ( prev == NULL ) { hashtable->heads[loc] = i2op->next ; } else { prev->next = i2op->next ; } i2op->next = hashtable->freeI2OP ; hashtable->freeI2OP = i2op ; hashtable->nitem-- ; *pvalue = i2op->value2 ; rc = 1 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- return a measure of the nonuniform distribution of the entries. a value of 1.0 is best. created -- 98jan29, cca --------------------------------------------------------------- */ double I2Ohash_measure ( I2Ohash *hashtable ) { double measure ; int count, loc ; I2OP *i2op ; if ( hashtable == NULL ) { fprintf(stderr, "\n fatal error in I2Ohash_measure(%p)" "\n hashtable is NULL\n", hashtable) ; exit(-1) ; } measure = 0.0 ; for ( loc = 0 ; loc < hashtable->nlist ; loc++ ) { if ( (i2op = hashtable->heads[loc]) != NULL ) { count = 0 ; while ( i2op != NULL ) { count++ ; i2op = i2op->next ; } measure += count*count ; } } measure = sqrt(measure) ; measure *= sqrt((double) hashtable->nlist)/hashtable->nitem ; return(measure) ; } /*--------------------------------------------------------------------*/ I2Ohash/drivers/makefile010064400020550007177000000004650665314247600165260ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = test_hash drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} test_hash : test_hash.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} I2Ohash/drivers/test_hash.c010064400020550007177000000055770654222652200171550ustar00clevecompmath00000400000006/* test_hash.c */ #include "../I2Ohash.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------- generate random (key1, key2, value) entries and place them into a hash table. created -- 98jan28, cca ------------------------------------------- */ { Drand *drand ; FILE *msgFile ; I2Ohash *hashtbl ; int grow, ii, key1, key2, maxkey, msglvl, nent, seed, size ; if ( argc != 8 ) { fprintf(stdout, "\n\n %% usage : %s msglvl msgFile size grow maxkey nent seed" "\n %% msglvl -- message level" "\n %% msgFile -- message file" "\n %% size -- number of lists in the hash table" "\n %% grow -- growth for list items" "\n %% maxkey -- maximum key value" "\n %% nent -- number of entries to insert" "\n %% seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } size = atoi(argv[3]) ; grow = atoi(argv[4]) ; maxkey = atoi(argv[5]) ; nent = atoi(argv[6]) ; seed = atoi(argv[7]) ; /* fprintf(msgFile, "\n %% %s " "\n %% msglvl -- %d" "\n %% msgFile -- %s" "\n %% size -- %d" "\n %% grow -- %d" "\n %% maxkey -- %d" "\n %% nent -- %d" "\n", argv[0], msglvl, argv[2], size, grow, maxkey, nent) ; fflush(msgFile) ; */ /* -------------------------------- initialize the hash table object -------------------------------- */ hashtbl = I2Ohash_new() ; I2Ohash_init(hashtbl, size, nent/2, grow) ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; Drand_setUniform(drand, 0, maxkey) ; /* ------------------------------------------------------------ generate (key1, key2, value) pairs and insert into the table ------------------------------------------------------------ */ for ( ii = 0 ; ii < nent ; ii++ ) { key1 = Drand_value(drand) ; key2 = Drand_value(drand) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n inserting <%d,%d,NULL> into hash table", key1, key2) ; } I2Ohash_insert(hashtbl, key1, key2, NULL) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d entries, measure = %.3f", ii+1, I2Ohash_measure(hashtbl)) ; } if ( msglvl > 3 ) { I2Ohash_writeForHumanEye(hashtbl, msgFile) ; } } if ( msglvl > 0 ) { fprintf(msgFile, "\n %12d %12d %12.3f", size, nent, I2Ohash_measure(hashtbl)) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ -- number of entries to insert" "\n %% seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = I2Ohash/doc/004275500020550007177000000000000654276740000141125ustar00clevecompmath00000400000006I2Ohash/doc/dataStructure.tex010064000020550007177000000026660653505565700174750ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:I2Ohash:dataStructure} \par The {\tt I2Ohash} object has a number of lists that contain {\tt } triples. Each % {\tt } triple is stored in an {\tt I2OP} object, a simple structure found in the {\tt Utilities} directory that holds two integer {\it key} fields, a {\tt void *} {\it data} field, and a single {\it pointer} field to allow us to use it in singly linked lists. \par The {\tt I2Ohash} object has six fields. \begin{itemize} \item {\tt int nlist} : number of lists in the hash table \item {\tt int grow} : when no {\tt I2OP} objects are available to insert a new {\tt } triple, the object can allocate {\tt grow} more {\tt I2OP} objects and put them on the free list. \item {\tt nitem} : number of items in the hash table. \item {\tt I2OP *baseI2OP} : pointer to an {\tt I2OP} object that keeps track of all the {\tt I2OP} objects that have been allocated by the hash table. \item {\tt I2OP *freeI2OP} : pointer to the first {\tt I2OP} object on the free list. \item {\tt I2OP **heads} : pointer to a vector of pointers to {\tt I2OP} objects, used to hold a pointer to the first {\tt I2OP} object in each list. \end{itemize} \par A correctly initialized and nontrivial {\tt I2Ohash} object will have {\tt nlist > 0}. If {\tt grow} is zero and a new {\tt } triple is given to the hash table to be inserted, a fatal error occurs. I2Ohash/doc/intro.tex010064000020550007177000000021250653505513600157540ustar00clevecompmath00000400000006\chapter{{\tt I2Ohash}: % \break Integer % (key1, key2, value) Two Key Hash Table} \par The {\tt I2Ohash} is a object that manages a hash table where there are two integer keys and the data to be stored is {\tt void *} pointer. This object was created to support a block sparse matrix, where each block has two keys, a row and column id, and the value is a pointer to a {\tt SubMtx} object. \par This is a very simple implementation. Each {\tt } is mapped to a list. Each list contains {\tt } triples whose keys are mapped to the list, and the triples are in lexicographic order of their {\tt } fields. The size of the hash table (the number of lists) is fixed upon initialization. The number of allowable {\tt } triples can either be fixed (upon initialization) or can grow by a user supplied amount. \par The methods that are supported are \begin{itemize} \item insert a {\tt } triple \item locate a {\tt } triple and return the value \item remove a {\tt } triple and return the value \end{itemize} I2Ohash/doc/main.aux010064400020550007177000000026560653505731200155550ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space I2Ohash}: Two Key Hash Table}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:I2Ohash:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space I2Ohash} methods}{2}} \newlabel{section:I2Ohash:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:I2Ohash:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initializer methods}{2}} \newlabel{subsection:I2Ohash:proto:initializers}{{1.2.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{3}} \newlabel{subsection:I2Ohash:proto:utilities}{{1.2.3}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}IO methods}{3}} \newlabel{subsection:I2Ohash:proto:IO}{{1.2.4}{3}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs for the {\string\ptt\space I2Ohash object}}{4}} \newlabel{section:I2Ohash:drivers}{{1.3}{4}} I2Ohash/doc/main.idx010064400020550007177000000011100653505731200155240ustar00clevecompmath00000400000006\indexentry{I2Ohash_new@{\tt I2Ohash\_new()}}{2} \indexentry{I2Ohash_setDefaultFields@{\tt I2Ohash\_setDefaultFields()}}{2} \indexentry{I2Ohash_clearData@{\tt I2Ohash\_clearData()}}{2} \indexentry{I2Ohash_free@{\tt I2Ohash\_free()}}{2} \indexentry{I2Ohash_init@{\tt I2Ohash\_init()}}{3} \indexentry{I2Ohash_insert@{\tt I2Ohash\_insert()}}{3} \indexentry{I2Ohash_locate@{\tt I2Ohash\_locate()}}{3} \indexentry{I2Ohash_remove@{\tt I2Ohash\_remove()}}{3} \indexentry{I2Ohash_measure@{\tt I2Ohash\_measure()}}{3} \indexentry{I2Ohash_writeForHumanEye@{\tt I2Ohash\_writeForHumanEye()}}{3} I2Ohash/doc/main.ilg010064400020550007177000000004560653505731000155250ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (10 entries accepted, 0 rejected). Sorting entries....done (32 comparisons). Generating output file main.ind....done (14 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. I2Ohash/doc/main.ind010064400020550007177000000006210653505731000155160ustar00clevecompmath00000400000006\begin{theindex} \item {\tt I2Ohash\_clearData()}, 2 \item {\tt I2Ohash\_free()}, 2 \item {\tt I2Ohash\_init()}, 3 \item {\tt I2Ohash\_insert()}, 3 \item {\tt I2Ohash\_locate()}, 3 \item {\tt I2Ohash\_measure()}, 3 \item {\tt I2Ohash\_new()}, 2 \item {\tt I2Ohash\_remove()}, 3 \item {\tt I2Ohash\_setDefaultFields()}, 2 \item {\tt I2Ohash\_writeForHumanEye()}, 3 \end{theindex} I2Ohash/doc/main.log010064400020550007177000000055110653505731200155320ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 2 JUN 1998 13:21 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 4. ) (dataStructure.tex [1 ]) (proto.tex [2] Overfull \hbox (6.01772pt too wide) in paragraph at lines 103--103 [] []\elvtt void I2Ohash_insert ( I2Ohash *hashtable, int key1, int key2, void * value ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. Overfull \hbox (6.01772pt too wide) in paragraph at lines 114--114 [] []\elvtt int I2Ohash_locate ( I2Ohash *hashtable, int key1, int key2, void **pvalue ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. Overfull \hbox (6.01772pt too wide) in paragraph at lines 128--128 [] []\elvtt int I2Ohash_remove ( I2Ohash *hashtable, int key1, int key2, void **pvalue ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. ) (drivers.tex [3]) (main.ind [4] [5 ]) (main.aux) ) Here is how much of TeX's memory you used: 208 strings out of 11977 2170 string characters out of 87269 33690 words of memory out of 262141 2142 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 14i,4n,17p,184b,258s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (5 pages, 12072 bytes). I2Ohash/doc/main.tex010064400020550007177000000011030665065623400155500ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt I2Ohash} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt I2Ohash} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} I2Ohash/doc/proto.tex010064400020550007177000000163660653505546500160110ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt I2Ohash} methods} \label{section:I2Ohash:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt I2Ohash} object. \par \subsection{Basic methods} \label{subsection:I2Ohash:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} I2Ohash * I2Ohash_new ( void ) ; \end{verbatim} \index{I2Ohash_new@{\tt I2Ohash\_new()}} This method simply allocates storage for the {\tt I2Ohash} structure and then sets the default fields by a call to {\tt I2Ohash\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void I2Ohash_setDefaultFields ( I2Ohash *hashtable ) ; \end{verbatim} \index{I2Ohash_setDefaultFields@{\tt I2Ohash\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt nlist}, {\tt grow} and {\tt nitem} are zero, {\tt baseI2OP}, {\tt freeI2OP} and {\tt heads} are {\tt NULL}. \par \noindent {\it Error checking:} If {\tt hashtable} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void I2Ohash_clearData ( I2Ohash *hashtable ) ; \end{verbatim} \index{I2Ohash_clearData@{\tt I2Ohash\_clearData()}} This method clears any data owned by the object. It releases any {\tt I2OP} objects that have been allocated by the hash table, and then free's the {\tt heads[]} vector. It then sets the structure's default fields with a call to {\tt I2Ohash\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt hashtable} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void I2Ohash_free ( I2Ohash *hashtable ) ; \end{verbatim} \index{I2Ohash_free@{\tt I2Ohash\_free()}} This method releases any storage by a call to {\tt I2Ohash\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt hashtable} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:I2Ohash:proto:initializers} \par There is one initializer method. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void I2Ohash_init ( I2Ohash *hashtable, int nlist, int nobj, int grow ) ; \end{verbatim} \index{I2Ohash_init@{\tt I2Ohash\_init()}} This method is the basic initializer method. It clears any previous data with a call to {\tt I2Ohash\_clearData()}. It allocates storage for {\tt nlist} lists and if {\tt nobj} is positive, it loads the free list with {\tt nobj} {\tt I2OP} objects. \par \noindent {\it Error checking:} If {\tt hashtable} is {\tt NULL}, or if ${\tt nlist} \le 0$, or if {\tt nobj} and {\tt grow} are both zero, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:I2Ohash:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void I2Ohash_insert ( I2Ohash *hashtable, int key1, int key2, void * value ) ; \end{verbatim} \index{I2Ohash_insert@{\tt I2Ohash\_insert()}} This method inserts the triple {\tt (key1,key2,value)} into the hash table. \par \noindent {\it Error checking:} If {\tt hashtable} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int I2Ohash_locate ( I2Ohash *hashtable, int key1, int key2, void **pvalue ) ; \end{verbatim} \index{I2Ohash_locate@{\tt I2Ohash\_locate()}} If there is a {\tt } triple in the hash table, {\tt *pvalue} is set to the value, and {\tt 1} is returned. If there is no {\tt } triple in the hash table, {\tt 0} is returned. \par \noindent {\it Error checking:} If {\tt hashtable} or {\tt pvalue} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int I2Ohash_remove ( I2Ohash *hashtable, int key1, int key2, void **pvalue ) ; \end{verbatim} \index{I2Ohash_remove@{\tt I2Ohash\_remove()}} If there is a {\tt } triple in the hash table, {\tt *pvalue} is set to the value, the triple is removed and its {\tt I2OP} structure is placed on the free list, and {\tt 1} is returned. If there is no {\tt } triple in the hash table, {\tt 0} is returned. \par \noindent {\it Error checking:} If {\tt hashtable} or {\tt pvalue} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double I2Ohash_measure ( I2Ohash *hashtable ) ; \end{verbatim} \index{I2Ohash_measure@{\tt I2Ohash\_measure()}} This method returns a floating point number that is some measure of how even a distribution of the {\tt } triples are made to the lists. We measure the imbalance using $\sqrt{\sum_{i} \mbox{\tt count}_i^2}$, where $i$ ranges over the lists and $\mbox{\tt count}_i$ is the number of triples in list $i$. If the triples were perfectly evenly distributed, then each list would have {\tt nitem/nlist} triples, and this value is $\mbox{\tt nitem}/\sqrt{\mbox{\tt nlist}}$. We return the ratio of $\sqrt{\sum_{i} \mbox{\tt count}_i^2}$ over $\mbox{\tt nitem}/\sqrt{\mbox{\tt nlist}}$. A value of 1.0 means that the triples are perfectly distributed. A value of $\sqrt{\mbox{\tt nlist}}$ means that the triples are distributed in the worst possible way (all are found in one list). In general, if the triples are evenly distributed among {\tt nlist/k} lists, the value is $\sqrt{\mbox{\tt k}}$. \par \noindent {\it Error checking:} If {\tt hashtable} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:I2Ohash:proto:IO} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void I2Ohash_writeForHumanEye ( I2Ohash *hashtable, FILE *fp ) ; \end{verbatim} \index{I2Ohash_writeForHumanEye@{\tt I2Ohash\_writeForHumanEye()}} This method prints the hash table in a human-readable format. \par \noindent {\it Error checking:} If {\tt hashtable} or {\tt fp} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} I2Ohash/doc/drivers.tex010064400020550007177000000031140653505725700163100ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt I2Ohash object}} \label{section:I2Ohash:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} test_hash msglvl msgFile size grow maxkey nent seed \end{verbatim} This driver program tests the {\tt I2Ohash} insert method. It inserts a number of triples into a hash table and prints out the ``measure'' of how well distributed the entries are in the hash table. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt size} parameter is the number of lists. \item The {\tt grow} parameter is how much the pool of {\tt I2OP} objects can grow. Setting {\tt grow} to zero is helpful when the number of items that can be placed into the hash table is known a priori. If one tries to insert an items when the free pool is empty and {\tt grow} is zero, an error message is printed and the program exits. \item The {\tt maxkey} parameter an upper bound on key value. \item The {\tt nent} parameter is the number of {\tt } triples to insert. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} I2Ohash/doc/makefile010064400020550007177000000000270654276740000156040ustar00clevecompmath00000400000006clean : - rm -f *.dvi IIheap.h010064400020550007177000000001040653410637000134000ustar00clevecompmath00000400000006#ifndef _IIheap_ #define _IIheap_ #include "IIheap/IIheap.h" #endif IIheap/IIheap.h010064400020550007177000000066250653506102700145550ustar00clevecompmath00000400000006/* IIheap.h */ #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ IIheap -- heap with integer ids, integer values and a map from each integer value to a heap location size -- present size of the heap maxsize -- maximum size of the heap heapLoc -- heap location of each id, size maxsize keys -- object key of each location in the heap, size maxsize values -- object value of each location in the heap, size maxsize created -- 95sep30, cca ------------------------------------------------------------------ */ typedef struct _IIheap IIheap ; struct _IIheap { int size ; int maxsize ; int *heapLoc ; int *keys ; int *values ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ --- methods found in basics.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------------------- create and return a new instance of the IIheap object created -- 95sep30, cca ----------------------------------------------------- */ IIheap * IIheap_new ( void ) ; /* ------------------------------------------- set the default fields for an IIheap object created -- 95sep30, cca ------------------------------------------- */ void IIheap_setDefaultFields ( IIheap *heap ) ; /* ----------------------- clear the data fields created -- 95sep30, cca ----------------------- */ void IIheap_clearData ( IIheap *heap ) ; /* ----------------------- free the IIheap object created -- 95sep30, cca ----------------------- */ void IIheap_free ( IIheap *heap ) ; /* -------------------------------- initializer, set heap maximum size to maxsize and allocate the arrays created -- 95sep30, cca -------------------------------- */ void IIheap_init ( IIheap *heap, int maxsize ) ; /* ------------------------------------------------ fill pkey with the key and pvalue with the value of the minimum (key, value) pair in the heap created -- 95sep30, cca ------------------------------------------------ */ void IIheap_root ( IIheap *heap, int *pkey, int *pvalue ) ; /* ------------------------------------------ insert the (key, value) pair into the heap created -- 95sep30, cca ------------------------------------------ */ void IIheap_insert ( IIheap *heap, int key, int value ) ; /* ---------------------------- remove (key,*) from the heap created -- 95sep30, cca ---------------------------- */ void IIheap_remove ( IIheap *heap, int key ) ; /* ----------------------------------------------- purpose -- to write the IIheap object to a file created -- 95sep30, cca ----------------------------------------------- */ void IIheap_print ( IIheap *heap, FILE *fp ) ; /* ---------------------------------------------- return the number of bytes taken by the object created -- 95sep30, cca ---------------------------------------------- */ int IIheap_sizeOf ( IIheap *heap ) ; /*--------------------------------------------------------------------*/ IIheap/makefile010064400020550007177000000001410663622360700147360ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean IIheap/src/makefile010064400020550007177000000005670663602466400155430ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = IIheap $(OBJ).a : \ $(OBJ).a(basics.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG IIheap/src/makeGlobalLib010064400020550007177000000005210660026104200164210ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = IIheap SRC = basics.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a IIheap/src/basics.c010064400020550007177000000251200653506120200154260ustar00clevecompmath00000400000006/* basics.c */ #include "../IIheap.h" /*--------------------------------------------------------------------*/ static void IIheap_siftUp ( IIheap *heap, int loc ) ; static void IIheap_siftDown ( IIheap *heap, int loc ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- create and return a new instance of the IIheap object created -- 95sep30, cca ----------------------------------------------------- */ IIheap * IIheap_new ( void ) { IIheap *heap ; ALLOCATE(heap, struct _IIheap, 1) ; IIheap_setDefaultFields(heap) ; return(heap) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- set the default fields for an IIheap object created -- 95sep30, cca ------------------------------------------- */ void IIheap_setDefaultFields ( IIheap *heap ) { if ( heap == NULL ) { fprintf(stderr, "\n fatal error in IIheap_setDefaultFields(%p)" "\n heap is NULL\n", heap) ; exit(-1) ; } heap->size = 0 ; heap->maxsize = 0 ; heap->heapLoc = NULL ; heap->keys = NULL ; heap->values = NULL ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields created -- 95sep30, cca ----------------------- */ void IIheap_clearData ( IIheap *heap ) { if ( heap == NULL ) { fprintf(stderr, "\n fatal error in IIheap_clearData(%p)" "\n heap is NULL\n", heap) ; exit(-1) ; } if ( heap->heapLoc != NULL ) { IVfree(heap->heapLoc) ; } if ( heap->keys != NULL ) { IVfree(heap->keys) ; } if ( heap->values != NULL ) { IVfree(heap->values) ; } IIheap_setDefaultFields(heap) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- free the IIheap object created -- 95sep30, cca ----------------------- */ void IIheap_free ( IIheap *heap ) { if ( heap == NULL ) { fprintf(stderr, "\n fatal error in IIheap_free(%p)" "\n heap is NULL\n", heap) ; exit(-1) ; } IIheap_clearData(heap) ; FREE(heap) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- initializer, set heap maximum size to maxsize and allocate the arrays created -- 95sep30, cca -------------------------------- */ void IIheap_init ( IIheap *heap, int maxsize ) { if ( heap == NULL || maxsize <= 0 ) { fprintf(stderr, "\n\n error in IIheap_init(%p,%d)" "\n heap is NULL or size = %d is nonpositive\n", heap, maxsize, maxsize) ; exit(-1) ; } IIheap_clearData(heap) ; heap->maxsize = maxsize ; heap->heapLoc = IVinit(maxsize, -1) ; heap->keys = IVinit(maxsize, -1) ; heap->values = IVinit(maxsize, -1) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ fill pkey with the key and pvalue with the value of the minimum (key, value) pair in the heap created -- 95sep30, cca ------------------------------------------------ */ void IIheap_root ( IIheap *heap, int *pkey, int *pvalue ) { if ( heap == NULL || pkey == NULL || pvalue == NULL ) { fprintf(stderr, "\n\n error in IIheap_root(%p,%p,%p)" "\n heap is NULL or pid is NULL or pkey is NULL\n", heap, pkey, pvalue) ; exit(-1) ; } if ( heap->size > 0 ) { *pkey = heap->keys[0] ; *pvalue = heap->values[0] ; } else { *pkey = *pvalue = -1 ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ insert the (key, value) pair into the heap created -- 95sep30, cca ------------------------------------------ */ void IIheap_insert ( IIheap *heap, int key, int value ) { int loc ; if ( heap == NULL || key < 0 || key >= heap->maxsize ) { fprintf(stderr, "\n error in IIheap_insert(%p,%d,%d)" "\n heap is NULL or pair (%d,%d) is out of bounds\n", heap, key, value, key, value) ; exit(-1) ; } if ( heap->heapLoc[key] != -1 ) { fprintf(stderr, "\n error in IIheap_insert(%p,%d,%d)" "\n object (%d,%d) is already in heap\n", heap, key, value, key, value) ; exit(-1) ; } if ( heap->size == heap->maxsize ) { fprintf(stderr, "\n error in IIheap_insert(%p,%d,%d)" "\n heap size exceeded\n", heap, key, value) ; exit(-1) ; } /* ----------------------------- insert the object and sift up ----------------------------- */ heap->heapLoc[key] = loc = heap->size++ ; heap->keys[loc] = key ; heap->values[loc] = value ; IIheap_siftUp(heap, loc) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- remove (key,*) from the heap created -- 95sep30, cca ---------------------------- */ void IIheap_remove ( IIheap *heap, int key ) { int last, loc, newkey, newVal, oldVal ; /* --------------- check the input --------------- */ if ( heap == NULL || key < 0 || key >= heap->maxsize ) { fprintf(stderr, "\n error in IIheap_remove(%p,%d)" "\n heap is NULL or object (%d) is out of bounds\n", heap, key, key) ; exit(-1) ; } if ( (loc = heap->heapLoc[key]) == -1 ) { fprintf(stderr, "\n error in IIheap_remove(%p,%d)" "\n object %d not in heap", heap, key, key) ; exit(-1) ; } /* ----------------------------------- save the old value at this location and update the three heap vectors ----------------------------------- */ if ( loc == (last = --heap->size) ) { /* ----------------------------------------------------------------- the element occupied the last position in the heap, simple return ----------------------------------------------------------------- */ heap->heapLoc[key] = -1 ; heap->keys[loc] = -1 ; heap->values[loc] = 0 ; } else { /* --------------------------------------------- move the last element to the current location --------------------------------------------- */ heap->heapLoc[key] = -1 ; newkey = heap->keys[last] ; heap->heapLoc[newkey] = loc ; heap->keys[loc] = newkey ; heap->keys[last] = -1 ; oldVal = heap->values[loc] ; heap->values[loc] = newVal = heap->values[last] ; heap->values[last] = 0 ; if ( oldVal > newVal ) { IIheap_siftUp(heap, loc) ; } else if ( oldVal < newVal ) { IIheap_siftDown(heap, loc) ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to write the IIheap object to a file created -- 95sep30, cca ----------------------------------------------- */ void IIheap_print ( IIheap *heap, FILE *fp ) { int ierr, j ; if ( heap == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in IIheap_print(%p,%p)" "\n heap is NULL or file pointer is NULL", heap, fp) ; exit(-1) ; } fprintf(fp, "\n\n IIheap : present size %d, max size %d", heap->size, heap->maxsize) ; if ( heap->size > 0 ) { fprintf(fp, "\n contents of heap : (location id value)") ; for ( j = 0 ; j < heap->size ; j++ ) { fprintf(fp, "\n %8d %8d %8d", j, heap->keys[j], heap->values[j]) ; } fprintf(fp, "\n locations of ids") ; IVfp80(fp, heap->maxsize, heap->heapLoc, 80, &ierr) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95sep30, cca ---------------------------------------------- */ int IIheap_sizeOf ( IIheap *heap ) { return(sizeof(IIheap) + 3*heap->maxsize*sizeof(int)) ; } /*====================================================================*/ /* ----------------------------------------------- purpose -- to sift a heap element down the tree created -- 95sep30, cca ----------------------------------------------- */ static void IIheap_siftDown ( IIheap *heap, int loc ) { int desc, itemp, left, right, size ; int *heapLoc, *keys, *values ; /* --------------- check the input --------------- */ if ( heap == NULL || loc < 0 || loc >= heap->size ) { fprintf(stderr, "\n fatal error in IIheap_siftDown(%p,%d)" "\n heap is NULL or loc = %d out of range\n", heap, loc, loc) ; exit(-1) ; } size = heap->size ; heapLoc = heap->heapLoc ; keys = heap->keys ; values = heap->values ; while ( 1 ) { left = 2 * loc + 1 ; right = left + 1 ; if ( left >= size ) { break ; } else if ( right >= size ) { desc = left ; } else { if ( values[left] <= values[right] ) { desc = left ; } else { desc = right ; } } /* if ( values[desc] < values[loc] ) { */ if ( values[desc] <= values[loc] ) { itemp = values[desc] ; values[desc] = values[loc] ; values[loc] = itemp ; itemp = keys[desc] ; keys[desc] = keys[loc] ; keys[loc] = itemp ; heapLoc[keys[loc]] = loc ; heapLoc[keys[desc]] = desc ; loc = desc ; } else { break ; } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to sift a heap element up the tree created -- 95sep30, cca --------------------------------------------- */ static void IIheap_siftUp ( IIheap *heap, int loc ) { int itemp, par ; int *heapLoc, *keys, *values ; /* --------------- check the input --------------- */ if ( heap == NULL || loc < 0 || loc >= heap->size ) { fprintf(stderr, "\n fatal error in IIheap_siftUp(%p,%d)" "\n heap is NULL or loc = %d out of range\n", heap, loc, loc) ; exit(-1) ; } heapLoc = heap->heapLoc ; keys = heap->keys ; values = heap->values ; while ( loc != 0 ) { par = (loc - 1)/2 ; /* if ( values[par] > values[loc] ) { */ if ( values[par] >= values[loc] ) { itemp = values[par] ; values[par] = values[loc] ; values[loc] = itemp ; itemp = keys[par] ; keys[par] = keys[loc] ; keys[loc] = itemp ; heapLoc[keys[loc]] = loc ; heapLoc[keys[par]] = par ; loc = par ; } else { break ; } } return ; } /*--------------------------------------------------------------------*/ IIheap/doc/004275500020550007177000000000000654276740000140145ustar00clevecompmath00000400000006IIheap/doc/dataStructure.tex010064000020550007177000000016010653506111600173460ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:IIheap:dataStructure} \par The {\tt IIheap} object has five fields. \begin{itemize} \item {\tt int size} : present size of the heap, {\tt 0 <= size < maxsize} \item {\tt int maxsize} : maximum size of the heap, set on initialization \item {\tt int *heapLoc} : pointer to an {\tt int} vector of size {\tt maxsize}, {\tt heapLoc[i]} contains the location of item {\tt i}, {\tt heapLoc[i] = -1} if item {\tt i} is not in the heap \item {\tt int *keys} : pointer to an {\tt int} vector of size {\tt maxsize}, {\tt keys[loc]} contains the key at location {\tt loc} \item {\tt int *values} : pointer to an {\tt int} vector of size {\tt maxsize}, {\tt values[loc]} contains the value at location {\tt loc} \end{itemize} A correctly initialized and nontrivial {\tt IIheap} object will have {\tt maxsize > 0} and {\tt 0 <= size < maxsize}. IIheap/doc/intro.tex010064000020550007177000000011120653505750500156530ustar00clevecompmath00000400000006\chapter{{\tt IIheap}: % \break (Integer Key, Integer Value) Heap} (Key, Value) Heap} \par The {\tt IIheap} is a object that manages a heap of data. Both the {\it key} and the {\it value} are of type {\tt int}. The heap has fixed size, each item must be in {\tt [0,maxsize-1]}, where {\tt maxsize} is set on initialization. The {\tt IIheap} object requires three vectors of size {\tt maxsize}. Three methods are supported: {\it find\_min}, {\it insert} and {\it delete} which take $O(1)$, $O(\log_2 n)$ and $O(\log_2 n)$ time, respectively, where $n$ is the present size of the heap. Value) Heap} \par The {\tt IIheap} is a object that manages a heap of data. Both the {\it key} and the {\it value} are of type {\tt int}. The heap has fixed size, each item must be in {\tt [0,maxsize-1]}, where {\tt maxsize} is set on initialization. The {\tt IIheap} object requires three vectors of size {\tt maxsize}. Three methods are supported: {\it find\_min}, {\it insert} and {\it delete} which take $O(1)$, $O(\log_2 n)$ and $O(\IIheap/doc/main.aux010064400020550007177000000021110653506144200154400ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space IIheap}: (Key, Value) Heap}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:IIheap:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space IIheap} methods}{1}} \newlabel{section:IIheap:proto}{{1.2}{1}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:IIheap:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initializer methods}{2}} \newlabel{subsection:IIheap:proto:initializers}{{1.2.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{2}} \newlabel{subsection:IIheap:proto:utilities}{{1.2.3}{2}} IIheap/doc/main.log010064400020550007177000000025130653506144300154330ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 2 JUN 1998 13:40 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 3. ) (dataStructure.tex) (proto.tex [1 ] [2]) (main.ind [3] [4 ]) (main.aux) ) Here is how much of TeX's memory you used: 203 strings out of 11977 2089 string characters out of 87269 32158 words of memory out of 262141 2140 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,4n,17p,183b,199s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (4 pages, 7400 bytes). IIheap/doc/main.tex010064400020550007177000000010560665065623600154630ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt IIheap} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt IIheap} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} IIheap/doc/proto.tex010064400020550007177000000133740653506144000156750ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt IIheap} methods} \label{section:IIheap:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt IIheap} object. \par \subsection{Basic methods} \label{subsection:IIheap:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IIheap * IIheap_new ( void ) ; \end{verbatim} \index{IIheap_new@{\tt IIheap\_new()}} This method simply allocates storage for the {\tt IIheap} structure and then sets the default fields by a call to {\tt IIheap\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void IIheap_setDefaultFields ( IIheap *heap ) ; \end{verbatim} \index{IIheap_setDefaultFields@{\tt IIheap\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt size} and {\tt maxsize} are zero, {\tt heapLoc}, {\tt keys} and {\tt values} are {\tt NULL}. \par \noindent {\it Error checking:} If {\tt heap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IIheap_clearData ( IIheap *heap ) ; \end{verbatim} \index{IIheap_clearData@{\tt IIheap\_clearData()}} This method clears any data owned by the object. It releases any storage held by the {\tt heap->heapLoc}, {\tt heap->keys} and {\tt heap->values} vectors, then sets the structure's default fields with a call to {\tt IIheap\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt heap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IIheap_free ( IIheap *heap ) ; \end{verbatim} \index{IIheap_free@{\tt IIheap\_free()}} This method releases any storage by a call to {\tt IIheap\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt heap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:IIheap:proto:initializers} \par There is one initializer method. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void IIheap_init ( IIheap *heap, int maxsize ) ; \end{verbatim} \index{IIheap_init@{\tt IIheap\_init()}} This method is the basic initializer method. It clears any previous data with a call to {\tt IIheap\_clearData()}, and allocates storage for the {\tt heapLoc}, {\tt keys} and {\tt values} vectors using {\tt IVinit()}. The entries in the three vectors are set to {\tt -1}. \par \noindent {\it Error checking:} If {\tt heap} is {\tt NULL}, or if ${\tt maxsize} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:IIheap:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int IIheap_sizeOf ( IIheap *heap ) ; \end{verbatim} \index{IIheap_sizeOf@{\tt IIheap\_sizeOf()}} This method returns the number of bytes taken by this object. \par \noindent {\it Error checking:} If {\tt heap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IIheap_root ( IIheap *heap, int *pkey, int *pvalue ) ; \end{verbatim} \index{IIheap_root@{\tt IIheap\_root()}} This method fills {\tt *pid} and {\tt *pkey} with the key and value, respectively, of the root element, an element with minimum value. If {\tt size == 0} then {\tt -1} is returned. \par \noindent {\it Error checking:} If {\tt heap}, {\tt pkey} or {\tt pvalue} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IIheap_insert ( IIheap *heap, int key, int value ) ; \end{verbatim} \index{IIheap_insert@{\tt IIheap\_insert()}} This method inserts the pair {\tt (key,value)} into the heap. \par \noindent {\it Error checking:} If {\tt heap} is {\tt NULL}, of if {\tt key} is out of range, or if {\tt key} is already in the heap, or if the heap is full, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IIheap_remove ( IIheap *heap, int key ) ; \end{verbatim} \index{IIheap_remove@{\tt IIheap\_remove()}} This method removes {\tt (key,*)} from the heap. \par \noindent {\it Error checking:} If {\tt heap} is {\tt NULL}, of if {\tt key} is out of range, or if {\tt key} is not in the heap, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IIheap_print ( IIheap *heap, FILE *fp ) ; \end{verbatim} \index{IIheap_print@{\tt IIheap\_print()}} This method prints the heap in a human-readable format. \par \noindent {\it Error checking:} If {\tt heap} or {\tt fp} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} If {\tt heap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:IIheap:proto:initializers} \par ThIIheap/doc/main.ind010064400020550007177000000005710653506134400154260ustar00clevecompmath00000400000006\begin{theindex} \item {\tt IIheap\_clearData()}, 2 \item {\tt IIheap\_free()}, 2 \item {\tt IIheap\_init()}, 2 \item {\tt IIheap\_insert()}, 3 \item {\tt IIheap\_new()}, 2 \item {\tt IIheap\_print()}, 3 \item {\tt IIheap\_remove()}, 3 \item {\tt IIheap\_root()}, 3 \item {\tt IIheap\_setDefaultFields()}, 2 \item {\tt IIheap\_sizeOf()}, 2 \end{theindex} IIheap/doc/main.idx010064400020550007177000000010300653506144300154270ustar00clevecompmath00000400000006\indexentry{IIheap_new@{\tt IIheap\_new()}}{2} \indexentry{IIheap_setDefaultFields@{\tt IIheap\_setDefaultFields()}}{2} \indexentry{IIheap_clearData@{\tt IIheap\_clearData()}}{2} \indexentry{IIheap_free@{\tt IIheap\_free()}}{2} \indexentry{IIheap_init@{\tt IIheap\_init()}}{2} \indexentry{IIheap_sizeOf@{\tt IIheap\_sizeOf()}}{2} \indexentry{IIheap_root@{\tt IIheap\_root()}}{3} \indexentry{IIheap_insert@{\tt IIheap\_insert()}}{3} \indexentry{IIheap_remove@{\tt IIheap\_remove()}}{3} \indexentry{IIheap_print@{\tt IIheap\_print()}}{3} IIheap/doc/main.ilg010064400020550007177000000004560653506134400154310ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (10 entries accepted, 0 rejected). Sorting entries....done (38 comparisons). Generating output file main.ind....done (14 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. IIheap/doc/makefile010064400020550007177000000000270654276740000155060ustar00clevecompmath00000400000006clean : - rm -f *.dvi ILUMtx.h010064400020550007177000000001040664741056000133670ustar00clevecompmath00000400000006#ifndef _ILUMtx_ #define _ILUMtx_ #include "ILUMtx/ILUMtx.h" #endif ILUMtx/ILUMtx.h010064400020550007177000000242720664720751500145310ustar00clevecompmath00000400000006/* ILUMtx.h */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- the ILUMtx is used to compute, store and solve with a factorization of the form A = (L+I)D(I+U), (U^T+I)D(I+U) or (U^H+I)D(I+U). the factorization is very simple, stored by vectors, and can be exact (up to roundoff) or approximate. it is a less complicated alternative to the FrontMtx object. neqns - # of equations type - SPOOLES_INDICES_ONLY, SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag - SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_COMPLEX UstorageMode -- storage mode for U SPOOLES_BY_ROWS or SPOOLES_BY_COLUMNS LstorageMode -- storage mode for L SPOOLES_BY_ROWS or SPOOLES_BY_COLUMNS sizesL -- vector of sizes of the L vectors sizesU -- vector of sizes of the U vectors p_indL -- vector of pointers to indices of the L vectors p_indU -- vector of pointers to indices of the U vectors entD -- vector of entries in D p_entL -- vector of pointers to entries of the L vectors p_entU -- vector of pointers to entries of the U vectors created -- 98oct03, cca -------------------------------------------------------------------- */ typedef struct _ILUMtx ILUMtx ; struct _ILUMtx { int neqns ; int type ; int symmetryflag ; int UstorageMode ; int LstorageMode ; int *sizesL ; int *sizesU ; int **p_indL ; int **p_indU ; double *entD ; double **p_entL ; double **p_entU ; } ; /*--------------------------------------------------------------------*/ /* ------------ handy macros ------------ */ #define ILUMTX_IS_REAL(mtx) ((mtx)->type == SPOOLES_REAL) #define ILUMTX_IS_COMPLEX(mtx) ((mtx)->type == SPOOLES_COMPLEX) #define ILUMTX_IS_SYMMETRIC(mtx) \ ((mtx)->symmetryflag == SPOOLES_SYMMETRIC) #define ILUMTX_IS_HERMITIAN(mtx) \ ((mtx)->symmetryflag == SPOOLES_HERMITIAN) #define ILUMTX_IS_NONSYMMETRIC(mtx) \ ((mtx)->symmetryflag == SPOOLES_NONSYMMETRIC) #define ILUMTX_IS_L_BY_ROWS(mtx) \ ((mtx)->LstorageMode == SPOOLES_BY_ROWS) #define ILUMTX_IS_L_BY_COLUMNS(mtx) \ ((mtx)->LstorageMode == SPOOLES_BY_COLUMNS) #define ILUMTX_IS_U_BY_ROWS(mtx) \ ((mtx)->UstorageMode == SPOOLES_BY_ROWS) #define ILUMTX_IS_U_BY_COLUMNS(mtx) \ ((mtx)->UstorageMode == SPOOLES_BY_COLUMNS) /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98oct03, cca ----------------------- */ ILUMtx * ILUMtx_new ( void ) ; /* ----------------------- set the default fields return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct03, cca ----------------------- */ int ILUMtx_setDefaultFields ( ILUMtx *mtx ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct03, cca -------------------------------------------------- */ int ILUMtx_clearData ( ILUMtx *mtx ) ; /* ------------------------------------------ destructor, free's the object and its data return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct03, cca ------------------------------------------ */ int ILUMtx_free ( ILUMtx *mtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------------------- purpose -- initialize the ILUMtx object return values --- 1 -- normal return -1 -- mtx is NULL -2 -- neqns <= 0 -3 -- bad type for mtx -4 -- bad symmetryflag for mtx -5 -- storage mode of L is invalid -6 -- storage mode of U is invalid -7 -- matrix is symmetric or hermitian and storage modes are not compatible created -- 98oct03, cca --------------------------------------------- */ int ILUMtx_init ( ILUMtx *mtx, int neqns, int type, int symmetryflag, int LstorageMode, int UstorageMode ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in factor.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------- purpose -- to factor the linear system A = (L + I)D(I + U), A = (U^T + I)D(I + U) or A = (U^H + I)D(I + U). if pops is not NULL, then on return *pops has been incremented by the number of operations performed in the solve. return values --- 1 -- normal return -1 -- mtx is NULL -2 -- neqns <= 0 -3 -- bad type for mtxLDU -4 -- bad symmetryflag for mtxLDU -5 -- storage mode of L is invalid -6 -- storage mode of U is invalid -7 -- sizesL is NULL -8 -- sizesU is NULL -9 -- p_indL is NULL -10 -- p_indU is NULL -11 -- entD is NULL -12 -- p_entL is NULL -13 -- p_entU is NULL -14 -- mtxA is NULL -15 -- types of mtxLDU and mtxA are not the same -16 -- mtxA is not in chevron mode -17 -- droptol < 0.0 -18 -- msglvl > 0 and msgFile is NULL -19 -- singular pivot found created -- 98oct03, cca ------------------------------------------------------------------- */ int ILUMtx_factor ( ILUMtx *mtxLDU, InpMtx *mtxA, double droptol, double *pops, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solve.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------- purpose -- to solve the linear system (L + I)D(I + U) X = B, (U^T + I)D(I + U) X = B or (U^H + I)D(I + U) X = B. X and B are single vectors. workDV is a temporary vector. note, if workDV is different than B, then B is unchanged on return. one can have X, B and workDV all point to the same object. if pops is not NULL, then on return *pops has been incremented by the number of operations performed in the solve. return values --- 1 -- normal return -1 -- LDU is NULL -2 -- neqns <= 0 -3 -- bad type for LDU -4 -- bad symmetryflag for LDU -5 -- storage mode of L is invalid -6 -- storage mode of U is invalid -7 -- sizesL is NULL -8 -- sizesU is NULL -9 -- p_indL is NULL -10 -- p_indU is NULL -11 -- entD is NULL -12 -- p_entL is NULL -13 -- p_entU is NULL -14 -- X is NULL -15 -- size of X is incorrect -16 -- entries of X are NULL -17 -- B is NULL -18 -- size of B is incorrect -19 -- entries of B are NULL -20 -- workDV is NULL -21 -- size of workDV != neqns -22 -- entries of workDV are NULL -23 -- msglvl > 0 and msgFile is NULL created -- 98oct03, cca ------------------------------------------------------------------- */ int ILUMtx_solveVector ( ILUMtx *LDU, DV *X, DV *B, DV *workDV, double *pops, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in misc.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------- purpose -- to fill the indices and entries with random values return values --- 1 -- normal return -1 -- mtx is NULL -2 -- neqns <= 0 -3 -- bad type for mtx -4 -- bad symmetryflag for mtx -5 -- storage mode of L is invalid -6 -- storage mode of U is invalid -7 -- sizesL is NULL -8 -- sizesU is NULL -9 -- p_indL is NULL -10 -- p_indU is NULL -11 -- entD is NULL -12 -- p_entL is NULL -13 -- p_entU is NULL created -- 98oct03, cca ------------------------------------------------------------- */ int ILUMtx_fillRandom ( ILUMtx *mtx, int seed ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------------- purpose -- to write an ILUMtx object to a file in matlab format return values --- 1 -- normal return -1 -- mtx is NULL -2 -- neqns <= 0 -3 -- bad type for LDU -4 -- bad symmetryflag for LDU -5 -- bad LstorageMode for LDU -6 -- bad UstorageMode for LDU -7 -- sizesL is NULL -8 -- sizesU is NULL -9 -- p_indL is NULL -10 -- p_indU is NULL -11 -- entD is NULL -12 -- p_entL is NULL -13 -- p_entU is NULL -14 -- Lname is NULL -15 -- Dname is NULL -16 -- Uname is NULL -17 -- fp is NULL created -- 98oct03, cca --------------------------------------------------------------- */ int ILUMtx_writeForMatlab ( ILUMtx *mtx, char *Lname, char *Dname, char *Uname, FILE *fp ) ; /*--------------------------------------------------------------------*/ ILUMtx/makefile010064400020550007177000000002230664720751500147240ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean ILUMtx/src/makefile010064400020550007177000000005530664720751400155200ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = ILUMtx $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(factor.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(misc.o) \ $(OBJ).a(solve.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o ILUMtx/src/IO.c010064400020550007177000000214630664720751400144760ustar00clevecompmath00000400000006/* IO.c */ #include "../ILUMtx.h" /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* --------------------------------------------------------------- purpose -- to write an ILUMtx object to a file in matlab format return values --- 1 -- normal return -1 -- mtx is NULL -2 -- neqns <= 0 -3 -- bad type for mtx -4 -- bad symmetryflag for mtx -5 -- bad LstorageMode for mtx -6 -- bad UstorageMode for mtx -7 -- sizesL is NULL -8 -- sizesU is NULL -9 -- p_indL is NULL -10 -- p_indU is NULL -11 -- entD is NULL -12 -- p_entL is NULL -13 -- p_entU is NULL -14 -- Lname is NULL -15 -- Dname is NULL -16 -- Uname is NULL -17 -- fp is NULL created -- 98oct03, cca --------------------------------------------------------------- */ int ILUMtx_writeForMatlab ( ILUMtx *mtx, char *Lname, char *Dname, char *Uname, FILE *fp ) { int ieqn, ii, neqns, size ; int *ind, *sizesU, *sizesL ; int **p_indL, **p_indU ; double *ent, *entD ; double **p_entL, **p_entU ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n error in ILUMtx_writeForMatlab(), mtx is NULL\n") ; return(-1) ; } if ( (neqns = mtx->neqns) <= 0 ) { fprintf(stderr, "\n error in ILUM_writeForMatlab()" "\n neqns = %d\n", neqns) ; return(-2) ; } if ( !(ILUMTX_IS_REAL(mtx) || ILUMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n error in ILUM_writeForMatlab()" "\n mtx type = %d\n", mtx->type) ; return(-3) ; } if ( !(ILUMTX_IS_SYMMETRIC(mtx) || ILUMTX_IS_HERMITIAN(mtx) || ILUMTX_IS_NONSYMMETRIC(mtx)) ) { fprintf(stderr, "\n error in ILUM_writeForMatlab()" "\n mtx symmetry = %d\n", mtx->symmetryflag) ; return(-4) ; } if ( !(ILUMTX_IS_L_BY_ROWS(mtx) || ILUMTX_IS_L_BY_COLUMNS(mtx)) ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n LstorageMode = %d\n", mtx->LstorageMode) ; return(-5) ; } if ( !(ILUMTX_IS_U_BY_ROWS(mtx) || ILUMTX_IS_U_BY_COLUMNS(mtx)) ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n UstorageMode = %d\n", mtx->UstorageMode) ; return(-6) ; } sizesU = mtx->sizesU ; entD = mtx->entD ; p_indU = mtx->p_indU ; p_entU = mtx->p_entU ; if ( ILUMTX_IS_SYMMETRIC(mtx) || ILUMTX_IS_HERMITIAN(mtx) ) { sizesL = mtx->sizesU ; p_indL = mtx->p_indU ; p_entL = mtx->p_entU ; } else { sizesL = mtx->sizesL ; p_indL = mtx->p_indL ; p_entL = mtx->p_entL ; } if ( sizesL == NULL ) { fprintf(stderr, "\n error in ILUM_writeForMatlab(), sizesL = NULL\n") ; return(-7) ; } if ( sizesU == NULL ) { fprintf(stderr, "\n error in ILUM_writeForMatlab(), sizesU = NULL\n") ; return(-8) ; } if ( p_indL == NULL ) { fprintf(stderr, "\n error in ILUM_writeForMatlab(), p_indL = NULL\n") ; return(-9) ; } if ( p_indU == NULL ) { fprintf(stderr, "\n error in ILUM_writeForMatlab(), p_indU = NULL\n") ; return(-10) ; } if ( entD == NULL ) { fprintf(stderr, "\n error in ILUM_writeForMatlab(), entD = NULL\n") ; return(-11) ; } if ( p_entL == NULL ) { fprintf(stderr, "\n error in ILUM_writeForMatlab(), p_entL = NULL\n") ; return(-12) ; } if ( p_entU == NULL ) { fprintf(stderr, "\n error in ILUM_writeForMatlab(), p_entU = NULL\n") ; return(-13) ; } if ( Lname == NULL ) { fprintf(stderr, "\n error in ILUMtx_writeForMatlab(), Lname is NULL\n") ; return(-14) ; } if ( Dname == NULL ) { fprintf(stderr, "\n error in ILUMtx_writeForMatlab(), Dname is NULL\n") ; return(-15) ; } if ( Uname == NULL ) { fprintf(stderr, "\n error in ILUMtx_writeForMatlab(), Uname is NULL\n") ; return(-16) ; } if ( fp == NULL ) { fprintf(stderr, "\n error in ILUMtx_writeForMatlab(), fp is NULL\n") ; return(-17) ; } /*--------------------------------------------------------------------*/ /* -------------------------- write out the entries in D -------------------------- */ fprintf(fp, "\n %s = zeros(%d,%d) ;", Dname, neqns, neqns) ; if ( ILUMTX_IS_REAL(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e ;", Dname, ieqn + 1, ieqn + 1, entD[ieqn]) ; } } else if ( ILUMTX_IS_COMPLEX(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e + i*%24.16e ;", Dname, ieqn + 1, ieqn + 1, entD[2*ieqn], entD[2*ieqn+1]) ; } } /* -------------------------- write out the entries in U -------------------------- */ fprintf(fp, "\n %s = eye(%d,%d) ;", Uname, neqns, neqns) ; if ( ILUMTX_IS_REAL(mtx) ) { if ( ILUMTX_IS_U_BY_COLUMNS(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (size = sizesU[ieqn]) > 0 ) { ind = p_indU[ieqn] ; ent = p_entU[ieqn] ; for ( ii = 0 ; ii < size ; ii++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e ;", Uname, ind[ii] + 1, ieqn + 1, ent[ii]) ; } } } } else if ( ILUMTX_IS_U_BY_ROWS(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (size = sizesU[ieqn]) > 0 ) { ind = p_indU[ieqn] ; ent = p_entU[ieqn] ; for ( ii = 0 ; ii < size ; ii++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e ;", Uname, ieqn + 1, ind[ii] + 1, ent[ii]) ; } } } } } else if ( ILUMTX_IS_COMPLEX(mtx) ) { if ( ILUMTX_IS_U_BY_COLUMNS(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (size = sizesU[ieqn]) > 0 ) { ind = p_indU[ieqn] ; ent = p_entU[ieqn] ; for ( ii = 0 ; ii < size ; ii++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e + i*%24.16e ;", Uname, ind[ii] + 1, ieqn + 1, ent[2*ii], ent[2*ii+1]) ; } } } } else if ( ILUMTX_IS_U_BY_ROWS(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (size = sizesU[ieqn]) > 0 ) { ind = p_indU[ieqn] ; ent = p_entU[ieqn] ; for ( ii = 0 ; ii < size ; ii++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e + i*%24.16e ;", Uname, ieqn + 1, ind[ii] + 1, ent[2*ii], ent[2*ii+1]) ; } } } } } if ( ILUMTX_IS_SYMMETRIC(mtx) ) { fprintf(fp, "\n %s = transpose(%s) ;", Lname, Uname) ; } else if ( ILUMTX_IS_HERMITIAN(mtx) ) { fprintf(fp, "\n %s = ctranspose(%s) ;", Lname, Uname) ; } else if ( ILUMTX_IS_NONSYMMETRIC(mtx) ) { /* -------------------------- write out the entries in L -------------------------- */ fprintf(fp, "\n %s = eye(%d,%d) ;", Lname, neqns, neqns) ; if ( ILUMTX_IS_REAL(mtx) ) { if ( ILUMTX_IS_L_BY_COLUMNS(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (size = sizesL[ieqn]) > 0 ) { ind = p_indL[ieqn] ; ent = p_entL[ieqn] ; for ( ii = 0 ; ii < size ; ii++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e ;", Lname, ind[ii] + 1, ieqn + 1, ent[ii]) ; } } } } else if ( ILUMTX_IS_L_BY_ROWS(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (size = sizesL[ieqn]) > 0 ) { ind = p_indL[ieqn] ; ent = p_entL[ieqn] ; for ( ii = 0 ; ii < size ; ii++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e ;", Lname, ieqn + 1, ind[ii] + 1, ent[ii]) ; } } } } } else if ( ILUMTX_IS_COMPLEX(mtx) ) { if ( ILUMTX_IS_L_BY_COLUMNS(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (size = sizesL[ieqn]) > 0 ) { ind = p_indL[ieqn] ; ent = p_entL[ieqn] ; for ( ii = 0 ; ii < size ; ii++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e + i*%24.16e ;", Lname, ind[ii] + 1, ieqn + 1, ent[2*ii], ent[2*ii+1]) ; } } } } else if ( ILUMTX_IS_L_BY_ROWS(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (size = sizesL[ieqn]) > 0 ) { ind = p_indL[ieqn] ; ent = p_entL[ieqn] ; for ( ii = 0 ; ii < size ; ii++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e + i*%24.16e ;", Lname, ieqn + 1, ind[ii] + 1, ent[2*ii], ent[2*ii+1]) ; } } } } } } return(1) ; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ mtx is NULL -2 -- neqns <= 0 -3 -- bad type for mtx -4 -- bad symmetryflag for mtx -5 -- bad LstorageMode for mtx -6 -- bad UstorageMode for mtx -7 -- sizesL is NULL ILUMtx/src/basics.c010064400020550007177000000063310664720751400154300ustar00clevecompmath00000400000006/* basics.c */ #include "../ILUMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98oct03, cca ----------------------- */ ILUMtx * ILUMtx_new ( void ) { ILUMtx *mtx ; ALLOCATE(mtx, struct _ILUMtx, 1) ; ILUMtx_setDefaultFields(mtx) ; return(mtx) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct03, cca ----------------------- */ int ILUMtx_setDefaultFields ( ILUMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in ILUMtx_setDefaultFields(%p)" "\n bad input", mtx) ; return(-1) ; } mtx->neqns = 0 ; mtx->type = SPOOLES_REAL ; mtx->symmetryflag = SPOOLES_SYMMETRIC ; mtx->UstorageMode = SPOOLES_BY_ROWS ; mtx->LstorageMode = SPOOLES_BY_COLUMNS ; mtx->sizesL = NULL ; mtx->sizesU = NULL ; mtx->p_indL = NULL ; mtx->p_indU = NULL ; mtx->entD = NULL ; mtx->p_entU = NULL ; mtx->p_entU = NULL ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct03, cca -------------------------------------------------- */ int ILUMtx_clearData ( ILUMtx *mtx ) { int ieqn, neqns ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in ILUMtx_clearData(%p)" "\n bad input\n", mtx) ; return(-1) ; } if ( (neqns = mtx->neqns) < 0 ) { return(1) ; } if ( mtx->entD != NULL ) { DVfree(mtx->entD) ; } IVfree(mtx->sizesU) ; for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( mtx->p_indU[ieqn] != NULL ) { IVfree(mtx->p_indU[ieqn]) ; } if ( mtx->p_entU[ieqn] != NULL ) { DVfree(mtx->p_entU[ieqn]) ; } } PIVfree(mtx->p_indU) ; PDVfree(mtx->p_entU) ; if ( mtx->symmetryflag == SPOOLES_NONSYMMETRIC ) { IVfree(mtx->sizesL) ; for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( mtx->p_indL[ieqn] != NULL ) { IVfree(mtx->p_indL[ieqn]) ; } if ( mtx->p_entL[ieqn] != NULL ) { DVfree(mtx->p_entL[ieqn]) ; } } PIVfree(mtx->p_indL) ; PDVfree(mtx->p_entL) ; } /* ---------------------- set the default fields ---------------------- */ ILUMtx_setDefaultFields(mtx) ; return(-1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct03, cca ------------------------------------------ */ int ILUMtx_free ( ILUMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in ILUMtx_free(%p)" "\n bad input\n", mtx) ; return(-1) ; } ILUMtx_clearData(mtx) ; FREE(mtx) ; return(1) ; } /*--------------------------------------------------------------------*/ ILUMtx/src/factor.c010064400020550007177000001156140664720751400154470ustar00clevecompmath00000400000006/* factor.c */ #include "../ILUMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ static void loadDiagonal ( int type, int neqns, InpMtx *mtxA, double entD[], int msglvl, FILE *msgFile ) ; static int getRowStructure ( int jeqn, int indicesU[], InpMtx *mtxA, int sizesU[], int *p_indU[], int headL[], int linkL[], int markU[], int msglvl, FILE *msgFile ) ; static void loadOrigRow ( int jeqn, InpMtx *mtxA, int map[], double temp[], int msglvl, FILE *msgFile ) ; static double updateRow ( int type, int symmetryflag, int jeqn, double LJI[], double DII[], int sizeU, int indU[], double entU[], int map[], double temp[], int msglvl, FILE *msgFile ) ; static int storeRow ( int jeqn, int type, double sigma, int countU, int indicesU[], double temp[], double entD[], int sizesU[], int *p_indU[], double *p_entU[], int msglvl, FILE *msgFile ) ; static int getColumnStructure ( int jeqn, int indicesL[], InpMtx *mtxA, int sizesL[], int *p_indL[], int headU[], int linkU[], int markL[], int msglvl, FILE *msgFile ) ; static void loadOrigColumn ( int jeqn, InpMtx *mtxA, int map[], double temp[], int msglvl, FILE *msgFile ) ; static double updateColumn ( int type, int symmetryflag, int jeqn, double DII[], double UIJ[], int sizeL, int indL[], double entL[], int map[], double temp[], int msglvl, FILE *msgFile ) ; static int storeColumn ( int jeqn, int type, double sigma, int countL, int indicesL[], double temp[], double entD[], int sizesL[], int *p_indL[], double *p_entL[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- to factor the linear system A = (L + I)D(I + U), A = (U^T + I)D(I + U) or A = (U^H + I)D(I + U). if pops is not NULL, then on return *pops has been incremented by the number of operations performed in the factorization. return values --- 1 -- normal return -1 -- mtx is NULL -2 -- neqns <= 0 -3 -- bad type for mtxLDU -4 -- bad symmetryflag for mtxLDU -5 -- storage mode of L is invalid -6 -- storage mode of U is invalid -7 -- sizesL is NULL -8 -- sizesU is NULL -9 -- p_indL is NULL -10 -- p_indU is NULL -11 -- entD is NULL -12 -- p_entL is NULL -13 -- p_entU is NULL -14 -- mtxA is NULL -15 -- types of mtxLDU and mtxA are not the same -16 -- mtxA is not in chevron mode -17 -- sigma < 0.0 -18 -- msglvl > 0 and msgFile is NULL -19 -- singular pivot found created -- 98oct03, cca ------------------------------------------------------------------- */ int ILUMtx_factor ( ILUMtx *mtxLDU, InpMtx *mtxA, double sigma, double *pops, int msglvl, FILE *msgFile ) { double ops ; double *entD, *entL, *entU, *pDii, *pLji, *pUij, *temp ; double **p_entL, **p_entU ; int countL, countU, ieqn, ii, ioff, jeqn, keqn, neqns, nexteqn, nkeep, rc, sizeL, sizeU, symmetryflag, type ; int *headL, *headU, *indicesL, *indicesU, *indL, *indU, *linkL, *linkU, *map, *markL, *markU, *offsetsL, *offsetsU, *sizesL, *sizesU ; int **p_indL, **p_indU ; /* --------------- check the input --------------- */ if ( mtxLDU == NULL ) { fprintf(stderr, "\n error in ILUM_factor(), mtxLDU = NULL\n") ; return(-1) ; } if ( (neqns = mtxLDU->neqns) <= 0 ) { fprintf(stderr, "\n error in ILUM_factor()" "\n neqns = %d\n", neqns) ; return(-2) ; } if ( !(ILUMTX_IS_REAL(mtxLDU) || ILUMTX_IS_COMPLEX(mtxLDU)) ) { fprintf(stderr, "\n error in ILUM_factor()" "\n type = %d\n", mtxLDU->type) ; return(-3) ; } if ( !(ILUMTX_IS_SYMMETRIC(mtxLDU) || ILUMTX_IS_HERMITIAN(mtxLDU) || ILUMTX_IS_NONSYMMETRIC(mtxLDU)) ) { fprintf(stderr, "\n error in ILUMfactor()" "\n mtxLDU symmetry = %d\n", mtxLDU->symmetryflag) ; return(-4) ; } if ( !(ILUMTX_IS_L_BY_ROWS(mtxLDU) || ILUMTX_IS_L_BY_COLUMNS(mtxLDU)) ) { fprintf(stderr, "\n error in ILUM_factor()" "\n LstorageMode = %d\n", mtxLDU->LstorageMode) ; return(-5) ; } if ( !(ILUMTX_IS_U_BY_ROWS(mtxLDU) || ILUMTX_IS_U_BY_COLUMNS(mtxLDU)) ) { fprintf(stderr, "\n error in ILUM_factor()" "\n UstorageMode = %d\n", mtxLDU->UstorageMode) ; return(-6) ; } type = mtxLDU->type ; symmetryflag = mtxLDU->symmetryflag ; sizesU = mtxLDU->sizesU ; entD = mtxLDU->entD ; p_indU = mtxLDU->p_indU ; p_entU = mtxLDU->p_entU ; if ( ILUMTX_IS_SYMMETRIC(mtxLDU) || ILUMTX_IS_HERMITIAN(mtxLDU) ) { sizesL = mtxLDU->sizesU ; p_indL = mtxLDU->p_indU ; p_entL = mtxLDU->p_entU ; } else { sizesL = mtxLDU->sizesL ; p_indL = mtxLDU->p_indL ; p_entL = mtxLDU->p_entL ; } if ( sizesL == NULL ) { fprintf(stderr, "\n error in ILUM_factor(), sizesL = NULL\n") ; return(-7) ; } if ( sizesU == NULL ) { fprintf(stderr, "\n error in ILUM_factor(), sizesU = NULL\n") ; return(-8) ; } if ( p_indL == NULL ) { fprintf(stderr, "\n error in ILUM_factor(), p_indL = NULL\n") ; return(-9) ; } if ( p_indU == NULL ) { fprintf(stderr, "\n error in ILUM_factor(), p_indU = NULL\n") ; return(-10) ; } if ( entD == NULL ) { fprintf(stderr, "\n error in ILUM_factor(), entD = NULL\n") ; return(-11) ; } if ( p_entL == NULL ) { fprintf(stderr, "\n error in ILUM_factor(), p_entL = NULL\n") ; return(-12) ; } if ( p_entU == NULL ) { fprintf(stderr, "\n error in ILUM_factor(), p_entU = NULL\n") ; return(-13) ; } if ( mtxA == NULL ) { fprintf(stderr, "\n error in ILUM_factor(), mtxA = NULL\n") ; return(-14) ; } if ( mtxA->inputMode != (type = mtxLDU->type) ) { fprintf(stderr, "\n error in ILUM_factor()" "\n mtxA type = %d, mtxLDU type = %d\n", mtxA->inputMode, mtxLDU->type) ; return(-15) ; } if ( ! INPMTX_IS_BY_CHEVRONS(mtxA) ) { fprintf(stderr, "\n error in ILUM_factor()" "\n mtxA must be in chevron mode\n") ; return(-16) ; } if ( sigma < 0.0 ) { fprintf(stderr, "\n error in ILUM_factor()" "\n sigma = %f\n", sigma) ; return(-17) ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n error in ILUM_factor()" "\n msglvl = %d, msgFile is NULL\n", msglvl) ; return(-18) ; } /*--------------------------------------------------------------------*/ /* -------------------------- allocate temporary storage -------------------------- */ indicesU = IVinit(neqns, -1) ; indicesL = indicesU ; markU = IVinit(neqns, -1) ; headU = IVinit(neqns, -1) ; linkU = IVinit(neqns, -1) ; offsetsU = IVinit(neqns, -1) ; map = IVinit(neqns, -1) ; if ( ILUMTX_IS_SYMMETRIC(mtxLDU) || ILUMTX_IS_HERMITIAN(mtxLDU) ) { headL = headU ; linkL = linkU ; offsetsL = offsetsU ; markL = NULL ; } else { headL = IVinit(neqns, -1) ; linkL = IVinit(neqns, -1) ; offsetsL = IVinit(neqns, -1) ; markL = IVinit(neqns, -1) ; } if ( type == SPOOLES_REAL ) { temp = DVinit(neqns, 0.0) ; } else { temp = DVinit(2*neqns, 0.0) ; } /*--------------------------------------------------------------------*/ /* -------------------------- load diagonal entries of A -------------------------- */ loadDiagonal(type, neqns, mtxA, entD, msglvl, msgFile) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n\n entD after loading diag(A)") ; DVfprintf(msgFile, neqns, entD) ; fflush(msgFile) ; } #endif /*--------------------------------------------------------------------*/ /* ----------------------- loop over the equations ----------------------- */ rc = 1 ; ops = 0.0 ; for ( jeqn = 0 ; jeqn < neqns ; jeqn++ ) { #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ### working on equation %d", jeqn) ; fflush(msgFile) ; } #endif /* -------------------------------------------------- determine the structure of entries in the row of U -------------------------------------------------- */ countU = getRowStructure(jeqn, indicesU, mtxA, sizesU, p_indU, headL, linkL, markU, msglvl, msgFile) ; #if MYDEBUG > 0 if ( msglvl > 1 ) { fprintf(msgFile, "\n\n symbolic row structure") ; IVfprintf(msgFile, countU, indicesU) ; } #endif for ( ii = 0 ; ii < countU ; ii++ ) { map[indicesU[ii]] = ii ; } /* ------------------------------------------------- load original entries of row into the temp vector ------------------------------------------------- */ loadOrigRow(jeqn, mtxA, map, temp, msglvl, msgFile) ; #if MYDEBUG > 0 if ( msglvl > 1 ) { fprintf(msgFile, "\n\n original row entries loaded") ; IVfprintf(msgFile, countU, indicesU) ; if ( type == SPOOLES_REAL ) { DVfprintf(msgFile, countU, temp) ; } else { DVfprintf(msgFile, 2*countU, temp) ; } } #endif /* ------------------ get updates into U ------------------ */ for ( ieqn = headL[jeqn] ; ieqn != -1 ; ieqn = nexteqn ) { sizeL = sizesL[ieqn] ; indL = p_indL[ieqn] ; entL = p_entL[ieqn] ; ioff = offsetsL[ieqn] ; sizeU = sizesU[ieqn] ; indU = p_indU[ieqn] ; entU = p_entU[ieqn] ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ## update from %d, sizeL %d, ioff %d, sizeU %d", ieqn, sizeL, ioff, sizeU) ; fflush(msgFile) ; } #endif /* ------------------------------ update row jeqn using row ieqn ------------------------------ */ if ( type == SPOOLES_REAL ) { pLji = entL + ioff ; pDii = entD + ieqn ; } else { pLji = entL + 2*ioff ; pDii = entD + 2*ieqn ; } ops += updateRow(type, symmetryflag, jeqn, pLji, pDii, sizeU, indU, entU, map, temp, msglvl, msgFile) ; #if MYDEBUG > 0 if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after update from %d", ieqn) ; IVfprintf(msgFile, countU, indicesU) ; if ( type == SPOOLES_REAL ) { DVfprintf(msgFile, countU, temp) ; } else { DVfprintf(msgFile, 2*countU, temp) ; } fflush(msgFile) ; } #endif /* ------------------------------------ link ieqn to the next row it updates ------------------------------------ */ nexteqn = linkL[ieqn] ; linkL[ieqn] = -1 ; if ( ++ioff < sizeL ) { offsetsL[ieqn] = ioff ; keqn = indL[ioff] ; linkL[ieqn] = headL[keqn] ; headL[keqn] = ieqn ; #if MYDEBUG > 0 if ( msglvl > 1 ) { fprintf(msgFile, "\n linking ieqn %d to keqn %d", ieqn, keqn) ; fflush(msgFile) ; } #endif } } /* ---------------------- check for a zero pivot ---------------------- */ if ( type == SPOOLES_REAL ) { if ( temp[0] == 0.0 ) { rc = -19 ; break ; } } else { if ( temp[0] == 0.0 && temp[1] == 0.0 ) { rc = -19 ; break ; } } /* -------------------------- extract row jeqn and store -------------------------- */ nkeep = storeRow(jeqn, type, sigma, countU, indicesU, temp, entD, sizesU, p_indU, p_entU, msglvl, msgFile) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n keep %d entries from row %d", nkeep, jeqn) ; } #endif if ( nkeep > 0 ) { /* ------------------------------------------------- link jeqn to the first column of L it must update ------------------------------------------------- */ keqn = indicesU[0] ; #if MYDEBUG > 0 if ( msglvl > 1 ) { fprintf(msgFile, "\n U linking jeqn %d to keqn %d", jeqn, keqn) ; fflush(msgFile) ; } #endif linkU[jeqn] = headU[keqn] ; headU[keqn] = jeqn ; offsetsU[jeqn] = 0 ; } if ( symmetryflag == SPOOLES_NONSYMMETRIC ) { /* ----------------------------------------------------- determine the structure of entries in the column of U ----------------------------------------------------- */ countL = getColumnStructure(jeqn, indicesL, mtxA, sizesL, p_indL, headU, linkU, markL, msglvl, msgFile); for ( ii = 0 ; ii < countL ; ii++ ) { map[indicesU[ii]] = ii ; } /* ---------------------------------------------------- load original entries of column into the temp vector ---------------------------------------------------- */ loadOrigColumn(jeqn, mtxA, map, temp, msglvl, msgFile) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after loading original entries") ; if ( type == SPOOLES_REAL ) { DVfprintf(msgFile, countL, temp) ; } else { DVfprintf(msgFile, 2*countL, temp) ; } fflush(msgFile) ; } #endif /* ------------------ get updates into L ------------------ */ for ( ieqn = headU[jeqn] ; ieqn != -1 ; ieqn = nexteqn ) { sizeU = sizesU[ieqn] ; indU = p_indU[ieqn] ; entU = p_entU[ieqn] ; ioff = offsetsU[ieqn] ; sizeL = sizesL[ieqn] ; indL = p_indL[ieqn] ; entL = p_entL[ieqn] ; /* ------------------------------------ update column jeqn using column ieqn ------------------------------------ */ if ( type == SPOOLES_REAL ) { pUij = entU + ioff ; pDii = entD + ieqn ; } else { pUij = entU + 2*ioff ; pDii = entD + 2*ieqn ; } ops += updateColumn(type, symmetryflag, jeqn, pUij, pDii, sizeL, indL, entL, map, temp, msglvl, msgFile) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after update from %d", ieqn) ; if ( type == SPOOLES_REAL ) { DVfprintf(msgFile, countL, temp) ; } else { DVfprintf(msgFile, 2*countL, temp) ; } fflush(msgFile) ; } #endif /* --------------------------------------- link ieqn to the next column it updates --------------------------------------- */ nexteqn = linkU[ieqn] ; linkU[ieqn] = -1 ; if ( ++ioff < sizeU ) { offsetsU[ieqn] = ioff ; keqn = indU[ioff] ; linkU[ieqn] = headU[keqn] ; headU[keqn] = ieqn ; } } /* ----------------------------- extract column jeqn and store ----------------------------- */ nkeep = storeColumn(jeqn, type, sigma, countL, indicesL, temp, entD, sizesL, p_indL, p_entL, msglvl, msgFile) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n keep %d entries from column %d", nkeep, jeqn) ; } #endif if ( nkeep > 0 ) { /* ---------------------------------------------- link jeqn to the first row of U it must update ---------------------------------------------- */ keqn = indicesL[0] ; #if MYDEBUG > 0 if ( msglvl > 1 ) { fprintf(msgFile, "\n L linking jeqn %d to keqn %d", jeqn, keqn) ; fflush(msgFile) ; } #endif linkL[jeqn] = headL[keqn] ; headL[keqn] = jeqn ; offsetsL[jeqn] = 0 ; } } } /* ----------------------------------------- increment the operation count if not NULL ----------------------------------------- */ if ( pops != NULL ) { *pops += ops ; } /* ---------------------- free temporary storage ---------------------- */ IVfree(indicesU) ; IVfree(markU) ; IVfree(headU) ; IVfree(linkU) ; IVfree(offsetsU) ; if ( ILUMTX_IS_NONSYMMETRIC(mtxLDU) ) { IVfree(headL) ; IVfree(linkL) ; IVfree(offsetsL) ; IVfree(markL) ; } IVfree(map) ; DVfree(temp) ; return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- copy the diagonal entries of A into entD[] created -- 98oct08, cca ----------------------------------------------------- */ static void loadDiagonal ( int type, int neqns, InpMtx *mtxA, double entD[], int msglvl, FILE *msgFile ) { double *entA ; int ii, jeqn, size ; int *indA ; if ( type == SPOOLES_REAL ) { for ( jeqn = 0 ; jeqn < neqns ; jeqn++ ) { InpMtx_realVector(mtxA, jeqn, &size, &indA, &entA) ; for ( ii = 0 ; ii < size ; ii++ ) { if ( indA[ii] == 0 ) { entD[jeqn] = entA[ii] ; break ; } } } } else { for ( jeqn = 0 ; jeqn < neqns ; jeqn++ ) { InpMtx_complexVector(mtxA, jeqn, &size, &indA, &entA) ; for ( ii = 0 ; ii < size ; ii++ ) { if ( indA[ii] == 0 ) { entD[2*jeqn] = entA[2*ii] ; entD[2*jeqn+1] = entA[2*ii+1] ; break ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- fill the structure of row jeqn of U into indicesU[]. note: includes the diagonal entry. return value is the number of indices in indicesU. created -- 98oct04, cca ---------------------------------------------------- */ static int getRowStructure ( int jeqn, int indicesU[], InpMtx *mtxA, int sizesU[], int *p_indU[], int headL[], int linkL[], int markU[], int msglvl, FILE *msgFile ) { int countU, ieqn, ii, keqn, sizeA, sizeU ; int *indA, *indU ; /* -------------------------------------------------- construct the structure of entries in the row of U -------------------------------------------------- */ InpMtx_vector(mtxA, jeqn, &sizeA, &indA) ; markU[jeqn] = jeqn ; indicesU[0] = jeqn ; countU = 1 ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n indicesU[%d] = %d", countU-1, indicesU[countU-1]) ; fflush(msgFile) ; } #endif for ( ii = sizeA - 1 ; ii >= 0 ; ii-- ) { keqn = jeqn + indA[ii] ; if ( keqn > jeqn ) { markU[keqn] = jeqn ; indicesU[countU++] = keqn ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n 1. indicesU[%d] = %d", countU-1, indicesU[countU-1]) ; fflush(msgFile) ; } #endif } else { break ; } } for ( ieqn = headL[jeqn] ; ieqn != -1 ; ieqn = linkL[ieqn] ) { sizeU = sizesU[ieqn] ; indU = p_indU[ieqn] ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n checking out ieqn %d", ieqn) ; fflush(msgFile) ; } #endif for ( ii = sizeU - 1 ; ii >= 0 ; ii-- ) { #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n indU[%d] = %d", ii, indU[ii]) ; fflush(msgFile) ; } #endif if ( (keqn = indU[ii]) > jeqn ) { if ( markU[keqn] != jeqn ) { markU[keqn] = jeqn ; indicesU[countU++] = keqn ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n 2. indicesU[%d] = %d", countU-1, indicesU[countU-1]) ; fflush(msgFile) ; } #endif } } else { break ; } } } IVqsortUp(countU, indicesU) ; return(countU) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- load entries in upper row jeqn of A into temp vector created -- 98oct04, cca ---------------------------------------------------- */ static void loadOrigRow ( int jeqn, InpMtx *mtxA, int map[], double temp[], int msglvl, FILE *msgFile ) { double *entA ; int ii, keqn, kloc, sizeA ; int *indA ; /* ------------------------------------------------- load original entries of row into the temp vector ------------------------------------------------- */ if ( INPMTX_IS_REAL_ENTRIES(mtxA) ) { InpMtx_realVector(mtxA, jeqn, &sizeA, &indA, &entA) ; for ( ii = sizeA - 1 ; ii >= 0 ; ii-- ) { keqn = jeqn + indA[ii] ; if ( keqn >= jeqn ) { kloc = map[keqn] ; temp[kloc] = entA[ii] ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n temp[%d] = %12.4e", kloc, entA[ii]) ; fflush(msgFile) ; } #endif } else { break ; } } } else { InpMtx_complexVector(mtxA, jeqn, &sizeA, &indA, &entA) ; for ( ii = sizeA - 1 ; ii >= 0 ; ii-- ) { keqn = jeqn + indA[ii] ; if ( keqn >= jeqn ) { kloc = map[keqn] ; temp[2*kloc] = entA[2*ii] ; temp[2*kloc+1] = entA[2*ii+1] ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n temp[%d] = %12.4e + i*%12.4e", kloc, entA[2*ii], entA[2*ii+1]) ; fflush(msgFile) ; } #endif } else { break ; } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- perform an update to row jeqn return value --- # of ops performed created -- 98oct04, cca ---------------------------------------- */ static double updateRow ( int type, int symmetryflag, int jeqn, double LJI[], double DII[], int sizeU, int indU[], double entU[], int map[], double temp[], int msglvl, FILE *msgFile ) { double ops = 0.0 ; int ii, keqn, kloc ; /* ------------------------------------------ compute the multiplier and update row jeqn ------------------------------------------ */ if ( type == SPOOLES_REAL ) { double Lji ; Lji = LJI[0] * DII[0] ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n LJI = %12.4e, DII = %12.4e, Lji = %12.4e", LJI[0], DII[0], Lji) ; fflush(msgFile) ; } #endif for ( ii = sizeU - 1 ; ii >= 0 ; ii-- ) { if ( (keqn = indU[ii]) >= jeqn ) { kloc = map[keqn] ; temp[kloc] -= Lji * entU[ii] ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n temp[%d] -= Lji * %12.4e", kloc, entU[ii]) ; fflush(msgFile) ; } #endif } else { break ; } } ops += 2*(sizeU - ii) ; } else { double LjiI, LjiR, UikI, UikR ; if ( symmetryflag == SPOOLES_HERMITIAN ) { LjiR = LJI[0] * DII[0] + LJI[1] * DII[1] ; LjiI = LJI[0] * DII[1] - LJI[1] * DII[0] ; } else { LjiR = LJI[0] * DII[0] - LJI[1] * DII[1] ; LjiI = LJI[0] * DII[1] + LJI[1] * DII[0] ; } #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n Lji = %12.4e + i*%12.4e", LjiR, LjiI) ; fflush(msgFile) ; } #endif for ( ii = sizeU - 1 ; ii >= 0 ; ii-- ) { if ( (keqn = indU[ii]) >= jeqn ) { kloc = map[keqn] ; UikR = entU[2*ii] ; UikI = entU[2*ii+1] ; temp[2*kloc] -= LjiR*UikR - LjiI*UikI ; temp[2*kloc+1] -= LjiR*UikI + LjiI*UikR ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n temp[%d] -= Lji * (%12.4e + i*%12.4e)", kloc, UikR, UikI) ; fflush(msgFile) ; } #endif } else { break ; } } ops += 8*(sizeU - ii) ; } return(ops) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to extract and store the entries in row jeqn note: indicesU[0] = jeqn. return value -- number of entries kept created -- 98oct04, cca ------------------------------------------------------- */ static int storeRow ( int jeqn, int type, double sigma, int countU, int indicesU[], double temp[], double entD[], int sizesU[], int *p_indU[], double *p_entU[], int msglvl, FILE *msgFile ) { double magDjj, magDkk, magUjk ; int ii, keqn, nkeep ; nkeep = 0 ; if ( type == SPOOLES_REAL ) { /* ------------------------ store the diagonal entry ------------------------ */ entD[jeqn] = temp[0] ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n entD[%d] = %12.4e", jeqn, entD[jeqn]) ; fflush(msgFile) ; } #endif /* -------------------------------------------------- check out the entries, slide down those to be kept -------------------------------------------------- */ magDjj = fabs(entD[jeqn]) ; for ( ii = 1 ; ii < countU ; ii++ ) { keqn = indicesU[ii] ; magUjk = fabs(temp[ii]) ; magDkk = fabs(entD[keqn]) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n keqn %d, magUjk %12.4e, magDkk %12.4e", keqn, magUjk, magDkk) ; fflush(msgFile) ; } #endif if ( magUjk*magUjk > sigma*magDjj*magDkk ) { indicesU[nkeep] = keqn ; temp[nkeep] = temp[ii] / entD[jeqn] ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n temp[%d] = %12.4e", nkeep, temp[nkeep]) ; fflush(msgFile) ; } #endif nkeep++ ; } } if ( nkeep > 0 ) { /* ------------------------------------ store indices and entries to be kept ------------------------------------ */ sizesU[jeqn] = nkeep ; p_indU[jeqn] = IVinit(nkeep, -1) ; IVcopy(nkeep, p_indU[jeqn], indicesU) ; p_entU[jeqn] = DVinit(nkeep, -1) ; DVcopy(nkeep, p_entU[jeqn], temp) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n row %d factor indices", jeqn) ; IVfprintf(msgFile, nkeep, p_indU[jeqn]) ; fprintf(msgFile, "\n row %d factor entries", jeqn) ; DVfprintf(msgFile, nkeep, p_entU[jeqn]) ; fflush(msgFile) ; } #endif } /* -------------------- zero the temp vector -------------------- */ DVzero(countU, temp) ; } else { double rI, rR, tI, tR ; /* ------------------------ store the diagonal entry ------------------------ */ entD[2*jeqn] = temp[0] ; entD[2*jeqn+1] = temp[1] ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n entD[%d] = %12.4e + i*%12.4e", jeqn, entD[2*jeqn], entD[2*jeqn+1]) ; fflush(msgFile) ; } #endif /* -------------------------------------------------- check out the entries, slide down those to be kept -------------------------------------------------- */ magDjj = Zabs(entD[2*jeqn], entD[2*jeqn+1]) ; Zrecip(entD[2*jeqn], entD[2*jeqn+1], &rR, &rI) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n rR = %12.4e, rI = %12.4e", rR, rI) ; fflush(msgFile) ; } #endif for ( ii = 1 ; ii < countU ; ii++ ) { keqn = indicesU[ii] ; magUjk = Zabs(temp[2*ii],temp[2*ii+1]) ; magDkk = Zabs(entD[2*keqn], entD[2*keqn+1]) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n keqn %d, magUjk %12.4e, magDkk %12.4e", keqn, magUjk, magDkk) ; fflush(msgFile) ; } #endif if ( magUjk*magUjk > sigma*magDjj*magDkk ) { indicesU[nkeep] = keqn ; tR = temp[2*ii] ; tI = temp[2*ii+1] ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n tR = %12.4e, tI = %12.4e", tR, tI) ; fflush(msgFile) ; } #endif temp[2*nkeep] = tR*rR - tI*rI ; temp[2*nkeep+1] = tR*rI + tI*rR ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n temp[%d] = %12.4e + i*%12.4e", nkeep, temp[2*nkeep], temp[2*nkeep+1]) ; fflush(msgFile) ; } #endif nkeep++ ; } } if ( nkeep > 0 ) { /* ------------------------------------ store indices and entries to be kept ------------------------------------ */ sizesU[jeqn] = nkeep ; p_indU[jeqn] = IVinit(nkeep, -1) ; IVcopy(nkeep, p_indU[jeqn], indicesU) ; p_entU[jeqn] = DVinit(2*nkeep, -1) ; DVcopy(2*nkeep, p_entU[jeqn], temp) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n row %d factor indices", jeqn) ; IVfprintf(msgFile, nkeep, p_indU[jeqn]) ; fprintf(msgFile, "\n row %d factor entries", jeqn) ; DVfprintf(msgFile, 2*nkeep, p_entU[jeqn]) ; fflush(msgFile) ; } #endif } /* -------------------- zero the temp vector -------------------- */ DVzero(2*countU, temp) ; } return(nkeep) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- fill the structure of column jeqn of L into indicesL[]. note: does not include the diagonal entry. return value is the number of indices in indicesL. created -- 98oct04, cca ------------------------------------------------------- */ static int getColumnStructure ( int jeqn, int indicesL[], InpMtx *mtxA, int sizesL[], int *p_indL[], int headU[], int linkU[], int markL[], int msglvl, FILE *msgFile ) { int countL, ieqn, ii, keqn, sizeA, sizeL ; int *indA, *indL ; /* ----------------------------------------------------- construct the structure of entries in the column of L ----------------------------------------------------- */ InpMtx_vector(mtxA, jeqn, &sizeA, &indA) ; countL = 0 ; for ( ii = 0 ; ii < sizeA ; ii++ ) { keqn = jeqn - indA[ii] ; if ( keqn > jeqn ) { markL[keqn] = jeqn ; indicesL[countL++] = keqn ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n 1. indicesL[%d] = %d", countL-1, indicesL[countL-1]) ; fflush(msgFile) ; } #endif } else { break ; } } for ( ieqn = headU[jeqn] ; ieqn != -1 ; ieqn = linkU[ieqn] ) { sizeL = sizesL[ieqn] ; indL = p_indL[ieqn] ; for ( ii = sizeL - 1 ; ii >= 0 ; ii-- ) { if ( (keqn = indL[ii]) > jeqn ) { if ( markL[keqn] != jeqn ) { markL[keqn] = jeqn ; indicesL[countL++] = keqn ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n 2. indicesL[%d] = %d", countL-1, indicesL[countL-1]) ; fflush(msgFile) ; } #endif } } else { break ; } } } IVqsortUp(countL, indicesL) ; return(countL) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- load entries in upper column jeqn of A into temp vector created -- 98oct04, cca ------------------------------------------------------- */ static void loadOrigColumn ( int jeqn, InpMtx *mtxA, int map[], double temp[], int msglvl, FILE *msgFile ) { double *entA ; int ii, keqn, kloc, sizeA ; int *indA ; /* ---------------------------------------------------- load original entries of column into the temp vector ---------------------------------------------------- */ if ( INPMTX_IS_REAL_ENTRIES(mtxA) ) { InpMtx_realVector(mtxA, jeqn, &sizeA, &indA, &entA) ; for ( ii = 0 ; ii < sizeA ; ii++ ) { keqn = jeqn - indA[ii] ; if ( keqn > jeqn ) { kloc = map[keqn] ; temp[kloc] = entA[ii] ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n temp[%d] = %12.4e", kloc, entA[ii]) ; fflush(msgFile) ; } #endif } else { break ; } } } else { InpMtx_complexVector(mtxA, jeqn, &sizeA, &indA, &entA) ; for ( ii = 0 ; ii < sizeA ; ii++ ) { keqn = jeqn - indA[ii] ; if ( keqn > jeqn ) { kloc = map[keqn] ; temp[2*kloc] = entA[2*ii] ; temp[2*kloc+1] = entA[2*ii+1] ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n temp[%d] = %12.4e + i*%12.4e", kloc, entA[2*ii], entA[2*ii+1]) ; fflush(msgFile) ; } #endif } else { break ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- perform an update to column jeqn return value --- # of ops performed created -- 98oct04, cca ------------------------------------------- */ static double updateColumn ( int type, int symmetryflag, int jeqn, double DII[], double UIJ[], int sizeL, int indL[], double entL[], int map[], double temp[], int msglvl, FILE *msgFile ) { double ops = 0.0 ; int ii, keqn, kloc ; /* ------------------------------------------ compute the multiplier and update row jeqn ------------------------------------------ */ if ( type == SPOOLES_REAL ) { double Uij ; Uij = DII[0] * UIJ[0] ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n Uij = %12.4e", Uij) ; fflush(msgFile) ; } #endif for ( ii = sizeL - 1 ; ii >= 0 ; ii-- ) { if ( (keqn = indL[ii]) > jeqn ) { kloc = map[keqn] ; temp[kloc] -= Uij * entL[ii] ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n temp[%d] -= Uij * %12.4e", kloc, entL[ii]) ; fflush(msgFile) ; } #endif } else { break ; } } ops += 2*(sizeL - ii) ; } else { double LkiI, LkiR, UijI, UijR ; UijR = UIJ[0] * DII[0] - UIJ[1] * DII[1] ; UijI = UIJ[0] * DII[1] + UIJ[1] * DII[0] ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n Uij = %12.4e + i*%12.4e", UijR, UijI) ; fflush(msgFile) ; } #endif for ( ii = sizeL - 1 ; ii >= 0 ; ii-- ) { if ( (keqn = indL[ii]) > jeqn ) { kloc = map[keqn] ; LkiR = entL[2*ii] ; LkiI = entL[2*ii+1] ; temp[2*kloc] -= LkiR*UijR - LkiI*UijI ; temp[2*kloc+1] -= LkiR*UijI + LkiI*UijR ; #if MYDEBUG > 0 if ( msglvl > 3 ) { fprintf(msgFile, "\n temp[%d] -= Uij * (%12.4e + i*%12.4e)", kloc, LkiR, LkiI) ; fflush(msgFile) ; } #endif } else { break ; } } ops += 8*(sizeL - ii) ; } return(ops) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- purpose -- to extract and store the entries in column jeqn return value -- number of entries kept created -- 98oct04, cca ---------------------------------------------------------- */ static int storeColumn ( int jeqn, int type, double sigma, int countL, int indicesL[], double temp[], double entD[], int sizesL[], int *p_indL[], double *p_entL[], int msglvl, FILE *msgFile ) { double magDjj, magDkk, magLkj ; int ii, keqn, nkeep ; nkeep = 0 ; if ( type == SPOOLES_REAL ) { /* -------------------------------------------------- check out the entries, slide down those to be kept -------------------------------------------------- */ magDjj = fabs(entD[jeqn]) ; for ( ii = 0 ; ii < countL ; ii++ ) { keqn = indicesL[ii] ; magLkj = fabs(temp[ii]) ; magDkk = fabs(entD[keqn]) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n keqn %d, magLkj %12.4e, magDkk %12.4e", keqn, magLkj, magDkk) ; fflush(msgFile) ; } #endif if ( magLkj*magLkj > sigma*magDjj*magDkk ) { indicesL[nkeep] = keqn ; temp[nkeep] = temp[ii] / entD[jeqn] ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n temp[%d] = %12.4e", nkeep, temp[nkeep]) ; fflush(msgFile) ; } #endif nkeep++ ; } } if ( nkeep > 0 ) { /* ------------------------------------ store indices and entries to be kept ------------------------------------ */ sizesL[jeqn] = nkeep ; p_indL[jeqn] = IVinit(nkeep, -1) ; IVcopy(nkeep, p_indL[jeqn], indicesL) ; p_entL[jeqn] = DVinit(nkeep, -1) ; DVcopy(nkeep, p_entL[jeqn], temp) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n column %d factor indices", jeqn) ; IVfprintf(msgFile, nkeep, p_indL[jeqn]) ; fprintf(msgFile, "\n column %d factor entries", jeqn) ; DVfprintf(msgFile, nkeep, p_entL[jeqn]) ; fflush(msgFile) ; } #endif } /* -------------------- zero the temp vector -------------------- */ DVzero(countL, temp) ; } else { double rI, rR, tI, tR ; /* -------------------------------------------------- check out the entries, slide down those to be kept -------------------------------------------------- */ magDjj = Zabs(entD[2*jeqn], entD[2*jeqn+1]) ; Zrecip(entD[2*jeqn], entD[2*jeqn+1], &rR, &rI) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n D(%d,%d) = %12.4e + i*%12.4e" "\n 1/(D(%d,%d) = %12.4e + i*%12.4e", jeqn, jeqn, entD[2*jeqn], entD[2*jeqn+1], jeqn, jeqn, rR, rI) ; fflush(msgFile) ; } #endif for ( ii = 0 ; ii < countL ; ii++ ) { keqn = indicesL[ii] ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n A(%d,%d) = %12.4e + i*%12.4e", keqn, jeqn, temp[2*ii], temp[2*ii+1]) ; fflush(msgFile) ; } #endif magLkj = Zabs(temp[2*ii],temp[2*ii+1]) ; magDkk = Zabs(entD[2*keqn], entD[2*keqn+1]) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n keqn %d, magLkj %12.4e, magDkk %12.4e", keqn, magLkj, magDkk) ; fflush(msgFile) ; } #endif if ( magLkj*magLkj > sigma*magDjj*magDkk ) { indicesL[nkeep] = keqn ; tR = temp[2*ii] ; tI = temp[2*ii+1] ; temp[2*nkeep] = tR*rR - tI*rI ; temp[2*nkeep+1] = tR*rI + tI*rR ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n temp[%d] = %12.4e + i*%12.4e", nkeep, temp[2*nkeep], temp[2*nkeep+1]) ; fflush(msgFile) ; } #endif nkeep++ ; } } if ( nkeep > 0 ) { /* ------------------------------------ store indices and entries to be kept ------------------------------------ */ sizesL[jeqn] = nkeep ; p_indL[jeqn] = IVinit(nkeep, -1) ; IVcopy(nkeep, p_indL[jeqn], indicesL) ; p_entL[jeqn] = DVinit(2*nkeep, -1) ; DVcopy(2*nkeep, p_entL[jeqn], temp) ; #if MYDEBUG > 0 if ( msglvl > 2 ) { fprintf(msgFile, "\n column %d factor indices", jeqn) ; IVfprintf(msgFile, nkeep, p_indL[jeqn]) ; fprintf(msgFile, "\n column %d factor entries", jeqn) ; DVfprintf(msgFile, 2*nkeep, p_entL[jeqn]) ; fflush(msgFile) ; } #endif } /* -------------------- zero the temp vector -------------------- */ DVzero(2*countL, temp) ; } return(nkeep) ; } /*--------------------------------------------------------------------*/ *p_indL[], int headU[], int linkU[], int markL[], int msglvl, FILE *msgFile ILUMtx/src/init.c010064400020550007177000000070460664720751400151330ustar00clevecompmath00000400000006/* init.c */ #include "../ILUMtx.h" #define MYDEBUG 0 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* --------------------------------------------- purpose -- initialize the ILUMtx object return values --- 1 -- normal return -1 -- mtx is NULL -2 -- neqns <= 0 -3 -- bad type for mtx -4 -- bad symmetryflag for mtx -5 -- storage mode of L is invalid -6 -- storage mode of U is invalid -7 -- matrix is symmetric or hermitian and storage modes are not compatible created -- 98oct03, cca --------------------------------------------- */ int ILUMtx_init ( ILUMtx *mtx, int neqns, int type, int symmetryflag, int LstorageMode, int UstorageMode ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n error in ILUM_init(), mtx = NULL\n") ; return(-1) ; } if ( neqns <= 0 ) { fprintf(stderr, "\n error in ILUM_init()" "\n neqns = %d\n", neqns) ; return(-2) ; } if ( type != SPOOLES_REAL && type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n error in ILUM_init()" "\n type = %d\n", type) ; return(-3) ; } if ( symmetryflag != SPOOLES_SYMMETRIC && symmetryflag != SPOOLES_HERMITIAN && symmetryflag != SPOOLES_NONSYMMETRIC ) { fprintf(stderr, "\n error in ILUMinit()" "\n symmetry = %d\n", symmetryflag) ; return(-4) ; } if ( LstorageMode != SPOOLES_BY_ROWS && LstorageMode != SPOOLES_BY_COLUMNS ) { fprintf(stderr, "\n error in ILUM_init()" "\n LstorageMode = %d\n", LstorageMode) ; return(-5) ; } if ( UstorageMode != SPOOLES_BY_ROWS && UstorageMode != SPOOLES_BY_COLUMNS ) { fprintf(stderr, "\n error in ILUM_init()" "\n UstorageMode = %d\n", UstorageMode) ; return(-6) ; } if ( ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN) && (LstorageMode == UstorageMode) ) { fprintf(stderr, "\n error in ILUM_init()" "\n symmetryflag %d, LstorageMode %d, UstorageMode %d", symmetryflag, LstorageMode, UstorageMode) ; return(-7) ; } /*--------------------------------------------------------------------*/ /* -------------- clear the data -------------- */ ILUMtx_clearData(mtx) ; /* --------------------- set the scalar fields --------------------- */ mtx->neqns = neqns ; mtx->type = type ; mtx->symmetryflag = symmetryflag ; mtx->LstorageMode = LstorageMode ; mtx->UstorageMode = UstorageMode ; #if MYDEBUG > 0 fprintf(stdout, "\n mtx->neqns = %d" "\n mtx->type = %d" "\n mtx->symmetryflag = %d" "\n mtx->LstorageMode = %d" "\n mtx->UstorageMode = %d", mtx->neqns, mtx->type, mtx->symmetryflag, mtx->LstorageMode, mtx->UstorageMode) ; fflush(stdout) ; #endif /* -------------------- allocate the vectors -------------------- */ mtx->sizesU = IVinit(neqns, 0) ; mtx->p_indU = PIVinit(neqns) ; mtx->p_entU = PDVinit(neqns) ; if ( type == SPOOLES_REAL ) { mtx->entD = DVinit(neqns, 0.0) ; } else { mtx->entD = DVinit(2*neqns, 0.0) ; } if ( symmetryflag == SPOOLES_NONSYMMETRIC ) { mtx->sizesL = IVinit(neqns, 0) ; mtx->p_indL = PIVinit(neqns) ; mtx->p_entL = PDVinit(neqns) ; } else { mtx->sizesL = NULL ; mtx->p_indL = NULL ; mtx->p_entL = NULL ; } /*--------------------------------------------------------------------*/ return(1) ; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ILUMtx/src/misc.c010064400020550007177000000132530664720751400151200ustar00clevecompmath00000400000006/* misc.c */ #include "../ILUMtx.h" /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* ------------------------------------------------------------- purpose -- to fill the indices and entries with random values return values --- 1 -- normal return -1 -- mtx is NULL -2 -- neqns <= 0 -3 -- bad type for mtx -4 -- bad symmetryflag for mtx -5 -- storage mode of L is invalid -6 -- storage mode of U is invalid -7 -- sizesL is NULL -8 -- sizesU is NULL -9 -- p_indL is NULL -10 -- p_indU is NULL -11 -- entD is NULL -12 -- p_entL is NULL -13 -- p_entU is NULL created -- 98oct03, cca ------------------------------------------------------------- */ int ILUMtx_fillRandom ( ILUMtx *mtx, int seed ) { double *entD ; double **p_entL, **p_entU ; Drand *drand ; int ieqn, neqns, size ; int *list, *sizesL, *sizesU ; int **p_indL, **p_indU ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n error in ILUM_fillRandom(), mtx = NULL\n") ; return(-1) ; } if ( (neqns = mtx->neqns) <= 0 ) { fprintf(stderr, "\n error in ILUM_fillRandom()" "\n neqns = %d\n", neqns) ; return(-2) ; } if ( !(ILUMTX_IS_REAL(mtx) || ILUMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n error in ILUM_fillRandom()" "\n type = %d\n", mtx->type) ; return(-3) ; } if ( !(ILUMTX_IS_SYMMETRIC(mtx) || ILUMTX_IS_HERMITIAN(mtx) || ILUMTX_IS_NONSYMMETRIC(mtx)) ) { fprintf(stderr, "\n error in ILUMfillRandom()" "\n mtx symmetry = %d\n", mtx->symmetryflag) ; return(-4) ; } if ( !(ILUMTX_IS_L_BY_ROWS(mtx) || ILUMTX_IS_L_BY_COLUMNS(mtx)) ) { fprintf(stderr, "\n error in ILUM_fillRandom()" "\n LstorageMode = %d\n", mtx->LstorageMode) ; return(-5) ; } if ( !(ILUMTX_IS_U_BY_ROWS(mtx) || ILUMTX_IS_U_BY_COLUMNS(mtx)) ) { fprintf(stderr, "\n error in ILUM_fillRandom()" "\n UstorageMode = %d\n", mtx->UstorageMode) ; return(-6) ; } sizesU = mtx->sizesU ; entD = mtx->entD ; p_indU = mtx->p_indU ; p_entU = mtx->p_entU ; if ( ILUMTX_IS_SYMMETRIC(mtx) || ILUMTX_IS_HERMITIAN(mtx) ) { sizesL = mtx->sizesU ; p_indL = mtx->p_indU ; p_entL = mtx->p_entU ; } else { sizesL = mtx->sizesL ; p_indL = mtx->p_indL ; p_entL = mtx->p_entL ; } if ( sizesL == NULL ) { fprintf(stderr, "\n error in ILUM_fillRandom(), sizesL = NULL\n") ; return(-7) ; } if ( sizesU == NULL ) { fprintf(stderr, "\n error in ILUM_fillRandom(), sizesU = NULL\n") ; return(-8) ; } if ( p_indL == NULL ) { fprintf(stderr, "\n error in ILUM_fillRandom(), p_indL = NULL\n") ; return(-9) ; } if ( p_indU == NULL ) { fprintf(stderr, "\n error in ILUM_fillRandom(), p_indU = NULL\n") ; return(-10) ; } if ( entD == NULL ) { fprintf(stderr, "\n error in ILUM_fillRandom(), entD = NULL\n") ; return(-11) ; } if ( p_entL == NULL ) { fprintf(stderr, "\n error in ILUM_fillRandom(), p_entL = NULL\n") ; return(-12) ; } if ( p_entU == NULL ) { fprintf(stderr, "\n error in ILUM_fillRandom(), p_entU = NULL\n") ; return(-13) ; } /*--------------------------------------------------------------------*/ drand = Drand_new() ; Drand_setSeed(drand, seed) ; /* ----------------- fill entries in D ----------------- */ Drand_setUniform(drand, 0.0, 1.0) ; if ( ILUMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, neqns, entD) ; } else { Drand_fillDvector(drand, 2*neqns, entD) ; } /* ----------------------------- fill indices and entries in U ----------------------------- */ list = IVinit(neqns, -1) ; for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( ILUMTX_IS_U_BY_ROWS(mtx) ) { size = neqns - ieqn - 1 ; } else { size = ieqn ; } Drand_setUniform(drand, 0, size) ; sizesU[ieqn] = (int) Drand_value(drand) ; if ( sizesU[ieqn] > 0 ) { if ( ILUMTX_IS_U_BY_ROWS(mtx) ) { IVramp(size, list, ieqn + 1, 1) ; } else { IVramp(size, list, 0, 1) ; } IVshuffle(size, list, ++seed) ; IVqsortUp(sizesU[ieqn], list) ; p_indU[ieqn] = IVinit(sizesU[ieqn], -1) ; IVcopy(sizesU[ieqn], p_indU[ieqn], list) ; Drand_setUniform(drand, -1.0, 1.0) ; if ( ILUMTX_IS_REAL(mtx) ) { size = sizesU[ieqn] ; } else { size = 2*sizesU[ieqn] ; } p_entU[ieqn] = DVinit(size, 0.0) ; Drand_fillDvector(drand, size, p_entU[ieqn]) ; } } if ( ILUMTX_IS_NONSYMMETRIC(mtx) ) { /* ----------------------------- fill indices and entries in L ----------------------------- */ for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( ILUMTX_IS_L_BY_ROWS(mtx) ) { size = ieqn ; } else { size = neqns - ieqn - 1 ; } Drand_setUniform(drand, 0, size) ; sizesL[ieqn] = (int) Drand_value(drand) ; if ( sizesL[ieqn] > 0 ) { if ( ILUMTX_IS_L_BY_ROWS(mtx) ) { IVramp(size, list, 0, 1) ; } else { IVramp(size, list, ieqn + 1, 1) ; } IVshuffle(size, list, ++seed) ; IVqsortUp(sizesL[ieqn], list) ; p_indL[ieqn] = IVinit(sizesL[ieqn], -1) ; IVcopy(sizesL[ieqn], p_indL[ieqn], list) ; Drand_setUniform(drand, -1.0, 1.0) ; if ( ILUMTX_IS_REAL(mtx) ) { size = sizesL[ieqn] ; } else { size = 2*sizesL[ieqn] ; } p_entL[ieqn] = DVinit(size, 0.0) ; Drand_fillDvector(drand, size, p_entL[ieqn]) ; } } } /*--------------------------------------------------------------------*/ Drand_free(drand) ; IVfree(list) ; return(1) ; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ILUMtx/src/solve.c010064400020550007177000000342620664720751400153200ustar00clevecompmath00000400000006/* solve.c */ #include "../ILUMtx.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- to solve the linear system (L + I)D(I + U) X = B, (U^T + I)D(I + U) X = B or (U^H + I)D(I + U) X = B. X and B are single vectors. workDV is a temporary vector. note, if workDV is different than B, then B is unchanged on return. one can have X, B and workDV all point to the same object. if pops is not NULL, then on return *pops has been incremented by the number of operations performed in the solve. return values --- 1 -- normal return -1 -- mtx is NULL -2 -- neqns <= 0 -3 -- bad type for mtx -4 -- bad symmetryflag for mtx -5 -- storage mode of L is invalid -6 -- storage mode of U is invalid -7 -- sizesL is NULL -8 -- sizesU is NULL -9 -- p_indL is NULL -10 -- p_indU is NULL -11 -- entD is NULL -12 -- p_entL is NULL -13 -- p_entU is NULL -14 -- X is NULL -15 -- size of X is incorrect -16 -- entries of X are NULL -17 -- B is NULL -18 -- size of B is incorrect -19 -- entries of B are NULL -20 -- workDV is NULL -21 -- size of workDV != neqns -22 -- entries of workDV are NULL -23 -- msglvl > 0 and msgFile is NULL created -- 98oct03, cca ------------------------------------------------------------------- */ int ILUMtx_solveVector ( ILUMtx *mtx, DV *X, DV *B, DV *workDV, double *pops, int msglvl, FILE *msgFile ) { double ops ; double *bent, *entD, *work, *xent ; double **p_entL, **p_entU ; int bsize, ieqn, neqns, wsize, xsize ; int *sizesL, *sizesU ; int **p_indL, **p_indU ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector(), mtx = NULL\n") ; return(-1) ; } if ( (neqns = mtx->neqns) <= 0 ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n neqns = %d\n", neqns) ; return(-2) ; } if ( !(ILUMTX_IS_REAL(mtx) || ILUMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n type = %d\n", mtx->type) ; return(-3) ; } if ( !(ILUMTX_IS_SYMMETRIC(mtx) || ILUMTX_IS_HERMITIAN(mtx) || ILUMTX_IS_NONSYMMETRIC(mtx)) ) { fprintf(stderr, "\n error in ILUMsolveVector()" "\n mtx symmetry = %d\n", mtx->symmetryflag) ; return(-4) ; } if ( !(ILUMTX_IS_L_BY_ROWS(mtx) || ILUMTX_IS_L_BY_COLUMNS(mtx)) ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n LstorageMode = %d\n", mtx->LstorageMode) ; return(-5) ; } if ( !(ILUMTX_IS_U_BY_ROWS(mtx) || ILUMTX_IS_U_BY_COLUMNS(mtx)) ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n UstorageMode = %d\n", mtx->UstorageMode) ; return(-6) ; } sizesU = mtx->sizesU ; entD = mtx->entD ; p_indU = mtx->p_indU ; p_entU = mtx->p_entU ; if ( ILUMTX_IS_SYMMETRIC(mtx) || ILUMTX_IS_HERMITIAN(mtx) ) { sizesL = mtx->sizesU ; p_indL = mtx->p_indU ; p_entL = mtx->p_entU ; } else { sizesL = mtx->sizesL ; p_indL = mtx->p_indL ; p_entL = mtx->p_entL ; } if ( sizesL == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector(), sizesL = NULL\n") ; return(-7) ; } if ( sizesU == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector(), sizesU = NULL\n") ; return(-8) ; } if ( p_indL == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector(), p_indL = NULL\n") ; return(-9) ; } if ( p_indU == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector(), p_indU = NULL\n") ; return(-10) ; } if ( entD == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector(), entD = NULL\n") ; return(-11) ; } if ( p_entL == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector(), p_entL = NULL\n") ; return(-12) ; } if ( p_entU == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector(), p_entU = NULL\n") ; return(-13) ; } if ( X == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector(), X = NULL\n") ; return(-14) ; } DV_sizeAndEntries(X, &xsize, &xent) ; if ( (ILUMTX_IS_REAL(mtx) && xsize != neqns) || (ILUMTX_IS_COMPLEX(mtx) && xsize != 2*neqns) ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n neqns = %d, size of X = %d\n", neqns, xsize) ; return(-15) ; } if ( xent == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n entries of X are NULL\n") ; return(-16) ; } if ( B == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector(), B = NULL\n") ; return(-17) ; } DV_sizeAndEntries(B, &bsize, &bent) ; if ( (ILUMTX_IS_REAL(mtx) && bsize != neqns) || (ILUMTX_IS_COMPLEX(mtx) && bsize != 2*neqns) ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n neqns = %d, size of B = %d\n", neqns, bsize) ; return(-18) ; } if ( bent == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n entries of B are NULL\n") ; return(-19) ; } if ( workDV == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector(), workDV = NULL\n") ; return(-20) ; } DV_sizeAndEntries(workDV, &wsize, &work) ; if ( (ILUMTX_IS_REAL(mtx) && wsize != neqns) || (ILUMTX_IS_COMPLEX(mtx) && wsize != 2*neqns) ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n neqns = %d, size of workDV = %d\n", neqns, wsize) ; return(-21) ; } if ( work == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n entries of workDV are NULL\n") ; return(-22) ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n error in ILUM_solveVector()" "\n msglvl = %d, msgFile is NULL\n", msglvl) ; return(-23) ; } /*--------------------------------------------------------------------*/ /* ------------------------- copy B vector into work[] ------------------------- */ if ( msglvl > 4 ) { fprintf(msgFile, "\n bent") ; DVfprintf(msgFile, neqns, bent) ; } if ( bent != work ) { if ( ILUMTX_IS_REAL(mtx) ) { DVcopy(neqns, work, bent) ; } else { DVcopy(2*neqns, work, bent) ; } } /* ------------- solve L Y = B ------------- */ ops = 0.0 ; if ( ILUMTX_IS_REAL(mtx) ) { if ( mtx->LstorageMode == SPOOLES_BY_COLUMNS ) { int ii, Lsize, *ind ; double yi, *ent ; for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (Lsize = sizesL[ieqn]) > 0 ) { yi = work[ieqn] ; ind = p_indL[ieqn] ; ent = p_entL[ieqn] ; for ( ii = 0 ; ii < Lsize ; ii++ ) { work[ind[ii]] -= yi * ent[ii] ; } ops += 2*Lsize ; } } } else { int ii, Lsize, *ind ; double sum, *ent ; for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (Lsize = sizesL[ieqn]) > 0 ) { ind = p_indL[ieqn] ; ent = p_entL[ieqn] ; for ( ii = 0, sum = 0.0 ; ii < Lsize ; ii++ ) { sum += work[ind[ii]] * ent[ii] ; } work[ieqn] -= sum ; ops += 2*Lsize ; } } } } else { if ( mtx->LstorageMode == SPOOLES_BY_COLUMNS ) { int ii, jj, kk, Lsize, *ind ; double LI, LR, yI, yR, *ent ; if ( ILUMTX_IS_HERMITIAN(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (Lsize = sizesL[ieqn]) > 0 ) { yR = work[2*ieqn] ; yI = work[2*ieqn+1] ; ind = p_indL[ieqn] ; ent = p_entL[ieqn] ; for ( ii = kk = 0 ; ii < Lsize ; ii++, kk += 2 ) { LR = ent[kk] ; LI = -ent[kk+1] ; jj = 2*ind[ii] ; work[jj] -= yR*LR - yI*LI ; work[jj+1] -= yR*LI + yI*LR ; } ops += 8*Lsize ; } } } else { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (Lsize = sizesL[ieqn]) > 0 ) { yR = work[2*ieqn] ; yI = work[2*ieqn+1] ; ind = p_indL[ieqn] ; ent = p_entL[ieqn] ; for ( ii = kk = 0 ; ii < Lsize ; ii++, kk += 2 ) { LR = ent[kk] ; LI = ent[kk+1] ; jj = 2*ind[ii] ; work[jj] -= yR*LR - yI*LI ; work[jj+1] -= yR*LI + yI*LR ; } ops += 8*Lsize ; } } } } else { int ii, jj, kk, Lsize, *ind ; double LI, LR, sumI, sumR, yI, yR, *ent ; if ( ILUMTX_IS_HERMITIAN(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (Lsize = sizesL[ieqn]) > 0 ) { ind = p_indL[ieqn] ; ent = p_entL[ieqn] ; sumI = sumR = 0.0 ; for ( ii = kk = 0 ; ii < Lsize ; ii++, kk += 2 ) { jj = 2*ind[ii] ; yR = work[jj] ; yI = work[jj+1] ; LR = ent[kk] ; LI = -ent[kk+1] ; sumR += yR*LR - yI*LI ; sumI += yR*LI + yI*LR ; } work[2*ieqn] -= sumR ; work[2*ieqn+1] -= sumI ; ops += 8*Lsize ; } } } else { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { if ( (Lsize = sizesL[ieqn]) > 0 ) { ind = p_indL[ieqn] ; ent = p_entL[ieqn] ; sumI = sumR = 0.0 ; for ( ii = kk = 0 ; ii < Lsize ; ii++, kk += 2 ) { jj = 2*ind[ii] ; yR = work[jj] ; yI = work[jj+1] ; LR = ent[kk] ; LI = ent[kk+1] ; sumR += yR*LR - yI*LI ; sumI += yR*LI + yI*LR ; } work[2*ieqn] -= sumR ; work[2*ieqn+1] -= sumI ; ops += 8*Lsize ; } } } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n %% after forward solve") ; fprintf(msgFile, "\n Y = zeros(%d,1) ;", neqns) ; if ( ILUMTX_IS_REAL(mtx) ) { DV_writeForMatlab(workDV, "Y", msgFile) ; } else { workDV->size = neqns ; ZV_writeForMatlab((ZV *) workDV, "Y", msgFile) ; workDV->size = 2*neqns ; } fflush(msgFile) ; } /* ------------- solve D Z = Y ------------- */ if ( ILUMTX_IS_REAL(mtx) ) { for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { work[ieqn] = work[ieqn] / entD[ieqn] ; } ops += 2*neqns ; } else { double dI, dR, yI, yR ; int rc ; for ( ieqn = 0 ; ieqn < neqns ; ieqn++ ) { rc = Zrecip(entD[2*ieqn], entD[2*ieqn+1], &dR, &dI) ; if ( rc == 1 ) { yR = work[2*ieqn] ; yI = work[2*ieqn+1] ; work[2*ieqn] = yR*dR - yI*dI ; work[2*ieqn+1] = yR*dI + yI*dR ; } } ops += 11*neqns ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n %% after diagonal solve") ; fprintf(msgFile, "\n Z = zeros(%d,1) ;", neqns) ; if ( ILUMTX_IS_REAL(mtx) ) { DV_writeForMatlab(workDV, "Z", msgFile) ; } else { workDV->size = neqns ; ZV_writeForMatlab((ZV *) workDV, "Z", msgFile) ; workDV->size = 2*neqns ; } fflush(msgFile) ; } /* ------------- solve U X = Z ------------- */ if ( ILUMTX_IS_REAL(mtx) ) { if ( mtx->UstorageMode == SPOOLES_BY_COLUMNS ) { int ii, Usize, *ind ; double xi, *ent ; for ( ieqn = neqns - 1 ; ieqn >= 0 ; ieqn-- ) { if ( (Usize = sizesU[ieqn]) > 0 ) { xi = work[ieqn] ; ind = p_indU[ieqn] ; ent = p_entU[ieqn] ; for ( ii = 0 ; ii < Usize ; ii++ ) { work[ind[ii]] -= xi * ent[ii] ; } ops += 2*Usize ; } } } else { int ii, Usize, *ind ; double sum, *ent ; for ( ieqn = neqns - 1 ; ieqn >= 0 ; ieqn-- ) { if ( (Usize = sizesU[ieqn]) > 0 ) { ind = p_indU[ieqn] ; ent = p_entU[ieqn] ; for ( ii = 0, sum = 0.0 ; ii < Usize ; ii++ ) { sum += work[ind[ii]] * ent[ii] ; } work[ieqn] -= sum ; ops += 2*Usize ; } } } } else { if ( mtx->UstorageMode == SPOOLES_BY_COLUMNS ) { int ii, jj, kk, Usize, *ind ; double UI, UR, xI, xR, *ent ; for ( ieqn = neqns - 1 ; ieqn >= 0 ; ieqn-- ) { if ( (Usize = sizesU[ieqn]) > 0 ) { xR = work[2*ieqn] ; xI = work[2*ieqn+1] ; ind = p_indU[ieqn] ; ent = p_entU[ieqn] ; for ( ii = kk = 0 ; ii < Usize ; ii++, kk += 2 ) { jj = 2*ind[ii] ; UR = ent[kk] ; UI = ent[kk+1] ; work[jj] -= xR*UR - xI*UI ; work[jj+1] -= xR*UI + xI*UR ; } ops += 8*Usize ; } } } else { int ii, jj, kk, Usize, *ind ; double sumI, sumR, UI, UR, xI, xR, *ent ; for ( ieqn = neqns - 1 ; ieqn >= 0 ; ieqn-- ) { if ( (Usize = sizesU[ieqn]) > 0 ) { ind = p_indU[ieqn] ; ent = p_entU[ieqn] ; sumR = sumI = 0.0 ; for ( ii = kk = 0 ; ii < Usize ; ii++, kk += 2 ) { jj = 2*ind[ii] ; xR = work[jj] ; xI = work[jj+1] ; UR = ent[kk] ; UI = ent[kk+1] ; sumR += xR*UR - xI*UI ; sumI += xR*UI + xI*UR ; } work[2*ieqn] -= sumR ; work[2*ieqn+1] -= sumI ; ops += 8*Usize ; } } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n %% after backward solve") ; fprintf(msgFile, "\n W = zeros(%d,1) ;", neqns) ; if ( ILUMTX_IS_REAL(mtx) ) { DV_writeForMatlab(workDV, "W", msgFile) ; } else { workDV->size = neqns ; ZV_writeForMatlab((ZV *) workDV, "W", msgFile) ; workDV->size = 2*neqns ; } fflush(msgFile) ; } /* ----------------------- copy work vector into X ----------------------- */ if ( work != xent ) { if ( ILUMTX_IS_REAL(mtx) ) { DVcopy(neqns, xent, work) ; } else { DVcopy(2*neqns, xent, work) ; } } /* ----------------------------------------- increment the operation count if not NULL ----------------------------------------- */ if ( pops != NULL ) { *pops += ops ; } return(1) ; } /*--------------------------------------------------------------------*/ ILUMtx/drivers/do_factor010075500020550007177000000010230664720751500165670ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res set msgFile = stdout # neqns --> # of equations set neqns = 100 # nitem --> # of entries set nitem = 1000 # type = 1 --> real entries # type = 2 --> complex entries set type = 2 # symflag = 0 --> symmetric # symflag = 1 --> hermitian # symflag = 2 --> nonsymmetric set symflag = 2 set seed = 10223 set droptol = 0.0 set matlabFile = res.m set matlabFile = none testFactor $msglvl $msgFile $type $symflag $neqns $nitem \ $seed $droptol $matlabFile ILUMtx/drivers/do_solve010075500020550007177000000012070664720751400164440ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res set msgFile = stdout # neqns --> # of equations set neqns = 100 # type = 1 --> real entries # type = 2 --> complex entries set type = 1 # symflag = 0 --> symmetric # symflag = 1 --> hermitian # symflag = 2 --> nonsymmetric set symflag = 2 # LstorageMode = 1 --> rows # LstorageMode = 2 --> columns set LstorageMode = 2 # UstorageMode = 1 --> rows # UstorageMode = 2 --> columns set UstorageMode = 1 set seed = 10203 set matlabFile = res.m set matlabFile = none testSolve $msglvl $msgFile $neqns $type $symflag \ $LstorageMode $UstorageMode $seed $matlabFile ILUMtx/drivers/makefile010064400020550007177000000026000665314250400163740ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = \ ../src/ILUMtx.a \ ../../InpMtx/src/InpMtx.a \ ../../DenseMtx/src/DenseMtx.a \ ../../A2/src/A2.a \ ../../EGraph/src/EGraph.a \ ../../ETree/src/ETree.a \ ../../Graph/src/Graph.a \ ../../Tree/src/Tree.a \ ../../Coords/src/Coords.a \ ../../IVL/src/IVL.a \ ../../IV/src/IV.a \ ../../DV/src/DV.a \ ../../ZV/src/ZV.a \ ../../Utilities/src/Utilities.a \ ../../Drand/src/Drand.a DRIVERS = testFactor testSolve libs : cd ../src ; make ILUMtx.a cd ../../InpMtx/src ; make InpMtx.a cd ../../DenseMtx/src ; make DenseMtx.a cd ../../A2/src ; make A2.a cd ../../EGraph/src ; make EGraph.a cd ../../Graph/src ; make Graph.a cd ../../ETree/src ; make ETree.a cd ../../Tree/src ; make Tree.a cd ../../Coords/src ; make Coords.a cd ../../IVL/src ; make IVL.a cd ../../IV/src ; make IV.a cd ../../DV/src ; make DV.a cd ../../ZV/src ; make ZV.a cd ../../Utilities/src ; make Utilities.a cd ../../Drand/src ; make Drand.a drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testFactor : testFactor.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} -lm testSolve : testSolve.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} -lm ILUMtx/drivers/testFactor.c010064400020550007177000000137370664720751400172010ustar00clevecompmath00000400000006/* testFactor.c */ #include "../ILUMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------------- generate a random matrix and test the drop tolerance factorization. the output is a matlab file to test correctness. created -- 98oct08, cca --------------------------------------------------------------------- */ { double droptol, nops, t1, t2 ; Drand *drand ; int msglvl, neqns, nitem, rc, seed, symflag, type ; InpMtx *A ; ILUMtx *mtxLDU ; FILE *matlabFile, *msgFile ; if ( argc != 10 ) { fprintf(stdout, "\n\n %% usage : %s msglvl msgFile type symflag " "\n neqns nitem seed droptol matlabFile" "\n %% msglvl -- message level" "\n %% msgFile -- message file" "\n %% type -- type of matrix entries" "\n %% 1 -- real" "\n %% 2 -- complex" "\n %% symflag -- symmetry flag" "\n %% 0 -- symmetric" "\n %% 1 -- hermitian" "\n %% 2 -- nonsymmetric" "\n %% neqns -- number of equations" "\n %% nitem -- number of items" "\n %% seed -- random number seed" "\n %% droptol -- drop tolerance" "\n %% matlabFile -- matlab file name" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; symflag = atoi(argv[4]) ; neqns = atoi(argv[5]) ; nitem = atoi(argv[6]) ; seed = atoi(argv[7]) ; droptol = atof(argv[8]) ; if ( strcmp(argv[9], "stdout") == 0 ) { matlabFile = stdout ; } else if ( strcmp(argv[2], argv[9]) == 0 ) { matlabFile = msgFile ; } else if ( strcmp("none", argv[9]) != 0 ) { if ( (matlabFile = fopen(argv[9], "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[9]) ; return(-1) ; } } else { matlabFile = NULL ; } fprintf(msgFile, "\n %% %s " "\n %% msglvl -- %d" "\n %% msgFile -- %s" "\n %% type -- %d" "\n %% symflag -- %d" "\n %% neqns -- %d" "\n %% nitem -- %d" "\n %% seed -- %d" "\n %% droptol -- %e" "\n %% matlabFile -- %s" "\n", argv[0], msglvl, argv[2], type, symflag, neqns, nitem, seed, droptol, argv[9]) ; fflush(msgFile) ; if ( type != SPOOLES_REAL && type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n invalid value %d for type\n", type) ; exit(-1) ; } switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n invalid value %d for symflag\n", symflag) ; exit(-1) ; break ; } if ( symflag == SPOOLES_HERMITIAN && type == SPOOLES_REAL ) { fprintf(stderr, "\n symflag is hermitian and type is real") ; exit(-1) ; } if ( neqns <= 0 || nitem <= 0 ) { fprintf(stderr, "\n invalid value: neqns = %d, nitem = %d", neqns, nitem) ; exit(-1) ; } /* ---------------------------- initialize the matrix object ---------------------------- */ A = InpMtx_new() ; InpMtx_randomMatrix(A, type, INPMTX_BY_CHEVRONS, INPMTX_BY_VECTORS, neqns, neqns, symflag, 1, nitem, seed) ; /* ------------------------------------------- write the assembled matrix to a matlab file ------------------------------------------- */ if ( matlabFile != NULL ) { InpMtx_writeForMatlab(A, "A", matlabFile) ; if ( symflag == SPOOLES_SYMMETRIC ) { fprintf(matlabFile, "\n for k = 1:%d" "\n for j = k+1:%d" "\n A(j,k) = A(k,j) ;" "\n end" "\n end", neqns, neqns) ; } else if ( symflag == SPOOLES_HERMITIAN ) { fprintf(matlabFile, "\n for k = 1:%d" "\n for j = k+1:%d" "\n A(j,k) = ctranspose(A(k,j)) ;" "\n end" "\n end", neqns, neqns) ; } InpMtx_changeCoordType(A, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(A, INPMTX_BY_VECTORS) ; /* ----------------------------------------------- compute the incomplete factorization via matlab ----------------------------------------------- */ fprintf(msgFile, "\n\n droptol = %24.16e ;", droptol) ; fprintf(msgFile, "\n\n [ L, D, U ] = ilu(A, droptol) ;") ; } /* ------------------------------------ compute the incomplete factorization ------------------------------------ */ mtxLDU = ILUMtx_new() ; ILUMtx_init(mtxLDU, neqns, type, symflag, SPOOLES_BY_COLUMNS, SPOOLES_BY_ROWS) ; nops = 0.0 ; MARKTIME(t1) ; rc = ILUMtx_factor(mtxLDU, A, droptol, &nops, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU %8.3f : compute ILU, %.0f operations, %.2f mflops\n", t2 - t1, nops, 1.e-6*nops/(t2 - t1)) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from ILUMtx_factor()", rc) ; return(rc) ; } if ( matlabFile != NULL ) { rc = ILUMtx_writeForMatlab(mtxLDU, "Lhat", "Dhat", "Uhat", matlabFile) ; /* ----------------- compute the error ----------------- */ fprintf(matlabFile, "\n\n errorL = max(max(abs(Lhat - L))) ;") ; fprintf(matlabFile, "\n\n errorD = max(max(abs(Dhat - D))) ;") ; fprintf(matlabFile, "\n\n errorU = max(max(abs(Uhat - U))) ;") ; fprintf(matlabFile, "\n\n error = [ errorL errorD errorU ]") ; } /* ------------------------ free the working storage ------------------------ */ InpMtx_free(A) ; ILUMtx_free(mtxLDU) ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ dout") == 0 ) { msgFile = stdoILUMtx/drivers/testSolve.c010064400020550007177000000127570664720751400170540ustar00clevecompmath00000400000006/* testSolve.c */ #include "../../timings.h" #include "../ILUMtx.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------- test the ILUMtx solve methods created -- 98sep04, cca ----------------------------- */ { double ops, t1, t2 ; Drand *drand ; DV *rhsDV, *solDV ; int LstorageMode, msglvl, neqns, rc, seed, symmetryflag, type, UstorageMode ; ILUMtx *mtx ; FILE *matlabFile, *msgFile ; if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile neqns type symmetryflag " "\n LstorageMode UstorageMode seed matlabFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n neqns -- number of equations" "\n type -- type of entries" "\n 1 -- real entries" "\n 2 -- complex entries" "\n symmetryflag -- type of symmetry" "\n 0 -- symmetric" "\n 1 -- hermitian" "\n 2 -- nonsymmetric" "\n LstorageMode -- type of storage for L" "\n 1 -- by rows" "\n 2 -- by columns" "\n UstorageMode -- type of storage for U" "\n 1 -- by rows" "\n 2 -- by columns" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } neqns = atoi(argv[3]) ; type = atoi(argv[4]) ; symmetryflag = atof(argv[5]) ; LstorageMode = atof(argv[6]) ; UstorageMode = atof(argv[7]) ; seed = atoi(argv[8]) ; if ( strcmp(argv[9], "stdout") == 0 ) { matlabFile = stdout ; } else if ( strcmp(argv[2], argv[9]) == 0 ) { matlabFile = msgFile ; } else if ( strcmp("none", argv[9]) != 0 ) { if ( (matlabFile = fopen(argv[9], "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[9]) ; return(-1) ; } } else { matlabFile = NULL ; } fprintf(msgFile, "\n %% %s " "\n %% msglvl -- %d" "\n %% msgFile -- %s" "\n %% neqns -- %d" "\n %% type -- %d" "\n %% symmetryflag -- %d" "\n %% LstorageMode -- %d" "\n %% UstorageMode -- %d" "\n %% seed -- %d" "\n %% matlabFile -- %s" "\n", argv[0], msglvl, argv[2], neqns, type, symmetryflag, LstorageMode, UstorageMode, seed, argv[9]) ; fflush(msgFile) ; /* ---------------------------- initialize the ILUMtx object ---------------------------- */ mtx = ILUMtx_new() ; rc = ILUMtx_init(mtx, neqns, type, symmetryflag, LstorageMode, UstorageMode) ; if ( rc != 1 ) { return(-1) ; } /* -------------------------------------- fill with random structure and entries -------------------------------------- */ rc = ILUMtx_fillRandom(mtx, seed) ; if ( rc != 1 ) { return(-1) ; } if ( matlabFile != NULL ) { /* ---------------------- write to a matlab file ---------------------- */ rc = ILUMtx_writeForMatlab(mtx, "L", "D", "U", matlabFile) ; if ( rc != 1 ) { return(-1) ; } } /* ------------------------------- generate a random rhs DV object ------------------------------- */ drand = Drand_new() ; Drand_setUniform(drand, 0, 1) ; Drand_setSeed(drand, seed + 1) ; rhsDV = DV_new() ; if ( type == SPOOLES_REAL ) { DV_init(rhsDV, neqns, NULL) ; Drand_fillDvector(drand, neqns, DV_entries(rhsDV)) ; } else { DV_init(rhsDV, 2*neqns, NULL) ; Drand_fillDvector(drand, 2*neqns, DV_entries(rhsDV)) ; } if ( matlabFile != NULL ) { fprintf(matlabFile, "\n B = zeros(%d,1) ;", neqns) ; if ( type == SPOOLES_REAL ) { DV_writeForMatlab(rhsDV, "B", matlabFile) ; } else { rhsDV->size = neqns ; ZV_writeForMatlab((ZV *) rhsDV, "B", matlabFile) ; rhsDV->size = 2*neqns ; } } /* ------------------------------------------- get a solution vector by solving the system ------------------------------------------- */ solDV = DV_new() ; if ( type == SPOOLES_REAL ) { DV_init(solDV, neqns, NULL) ; Drand_fillDvector(drand, neqns, DV_entries(solDV)) ; } else { DV_init(solDV, 2*neqns, NULL) ; } DV_zero(solDV) ; ops = 0.0 ; MARKTIME(t1) ; ILUMtx_solveVector(mtx, solDV, rhsDV, rhsDV, &ops, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : solve system, %.0f ops, %.2f mflops\n", t2 - t1, ops, 1.e-6*ops/(t2 - t1)) ; if ( matlabFile != NULL ) { fprintf(matlabFile, "\n X = zeros(%d,1) ;", neqns) ; if ( type == SPOOLES_REAL ) { DV_writeForMatlab(solDV, "X", matlabFile) ; } else { solDV->size = neqns ; ZV_writeForMatlab((ZV *) solDV, "X", matlabFile) ; solDV->size = 2*neqns ; } /* --------------------------------------------- write out the matlab expression for the error --------------------------------------------- */ fprintf(matlabFile, "\n error = max(abs((U\\(D\\(L\\B))) - X))") ; fflush(matlabFile) ; } /* ------------------------ free the working storage ------------------------ */ ILUMtx_free(mtx) ; Drand_free(drand) ; DV_free(rhsDV) ; DV_free(solDV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ILUMtx/doc/004275500020550007177000000000000664720751500140015ustar00clevecompmath00000400000006ILUMtx/doc/dataStructure.tex010064400020550007177000000046020664720751500173520ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:ILUMtx:dataStructure} \par \par The {\tt ILUMtx} structure has the following fields. \begin{itemize} \item {\tt int neqns} : number of equations. \item {\tt int type} : type of entries, {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. \item {\tt int symmetryflag} : type of matrix symmetry, {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item {\tt int UstorageMode} : type of storage for $U$, {\tt SPOOLES\_BY\_ROWS} or {\tt SPOOLES\_BY\_COLUMNS}. \item {\tt int LstorageMode} : type of storage for $L$, {\tt SPOOLES\_BY\_ROWS} or {\tt SPOOLES\_BY\_COLUMNS}. \item {\tt double *entD} : vector of diagonal entries. \item {\tt int *sizesL} : vector of sizes of the off-diagonal vectors of $L$, not used if the matrix is symmetric or Hermitian. \item {\tt int **p\_indL} : vector of pointers to the indicies vectors of $L$, not used if the matrix is symmetric or Hermitian. \item {\tt double **p\_entL} : vector of pointers to the entries vectors of $L$, not used if the matrix is symmetric or Hermitian. \item {\tt int *sizesU} : vector of sizes of the off-diagonal vectors of $U$. \item {\tt int **p\_indU} : vector of pointers to the indicies vectors of $U$. \item {\tt double **p\_entU} : vector of pointers to the entries vectors of $U$. \end{itemize} \par One can query the attributes of the object with the following macros. \begin{itemize} \item {\tt ILUMTX\_IS\_REAL(mtx)} returns {\tt 1} if the entries are real, and {\tt 0} otherwise. \item {\tt ILUMTX\_IS\_COMPLEX(mtx)} returns {\tt 1} if the entries are complex, and {\tt 0} otherwise. \item {\tt ILUMTX\_IS\_SYMMETRIC(mtx)} returns {\tt 1} if the factorization is symmetric, and {\tt 0} otherwise. \item {\tt ILUMTX\_IS\_HERMITIAN(mtx)} returns {\tt 1} if the factorization is Hermitian, and {\tt 0} otherwise. \item {\tt ILUMTX\_IS\_NONSYMMETRIC(mtx)} returns {\tt 1} if the factorization is nonsymmetric, and {\tt 0} otherwise. \item {\tt ILUMTX\_IS\_L\_BY\_ROWS(mtx)} returns {\tt 1} if $L$ is stored by rows, and {\tt 0} otherwise. \item {\tt ILUMTX\_IS\_L\_BY\_COLUMNS(mtx)} returns {\tt 1} if $L$ is stored by columns, and {\tt 0} otherwise. \item {\tt ILUMTX\_IS\_U\_BY\_ROWS(mtx)} returns {\tt 1} if $U$ is stored by rows, and {\tt 0} otherwise. \item {\tt ILUMTX\_IS\_U\_BY\_COLUMNS(mtx)} returns {\tt 1} if $U$ is stored by columns, and {\tt 0} otherwise. \end{itemize} L$, not used if the matrix is symmetric or Hermitian. \item {\tt double **p\_entL} : vector of pointers to the entries vectorsILUMtx/doc/drivers.tex010064400020550007177000000067010664720751500162000ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt ILUMtx} object} \label{section:ILUMtx:drivers} \par This section contains brief descriptions of the driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testFactor msglvl msgFile type symflag neqns nitem seed sigma matlabFile \end{verbatim} This driver program generates a random matrix $A$ stored in an {\tt InpMtx} object. It then factors $A = (L+I)D(I+U)$, $A = (U^T+I)D(I+U)$ or $A = (U^H+I)D(I+U)$ (depending on {\tt type} and {\tt symflag}). If {\tt matlabFile} is not {\tt "none"}, it writes $A$, $L$, $D$ and $U$ to a Matlab file, which can then be run through matlab to compute the error in the factorization. The CPU, number of operations and megaflops for the factorization are printed to {\tt msgFile}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt type} must be either {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. \item {\tt symflag} must be either {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_SYMMETRIC}. \item {\tt neqns} is the number of equations, must be positive. \item {\tt nitem} is the number of off-diagonal entries, must be nonnegative. \item {\tt seed} is a random number seed. \item {\tt sigma} is the drop tolerance. \item {\tt matlabFile} is the name of the Matlab file for the matrices. If {\tt "none"} then no output is written. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testSolve msglvl msgFile neqns type symflag LstorageMode UstorageMode seed matlabFile \end{verbatim} This driver program solve a linear system $(L+I)D(I+U)X = B$, $(U^T+I)D(I+U)X = B$ or $(U^H+I)D(I+U)X = B$, depending on {\tt type} and {\tt symflag}. $L$, $D$ and $L$ are random sparse matrices and $B$ is a random vector. If {\tt matlabFile} is not {\tt "none"}, it writes $L$, $D$, $U$, $B$ and the computed solution $X$ to a Matlab file, which can then be run through matlab to compute the error in the solve. The CPU, number of operations and megaflops for the factorization are printed to {\tt msgFile}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt neqns} is the number of equations, must be positive. \item {\tt type} must be either {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. \item {\tt symflag} must be either {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_SYMMETRIC}. \item {\tt LstorageMode} must be either {\tt SPOOLES\_BY\_ROWS} or {\tt SPOOLES\_BY\_COLUMNS}. \item {\tt UstorageMode} must be either {\tt SPOOLES\_BY\_ROWS} or {\tt SPOOLES\_BY\_COLUMNS}. \item {\tt seed} is a random number seed. \item {\tt matlabFile} is the name of the Matlab file for the matrices. If {\tt "none"} then no output is written. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} ILUMtx/doc/intro.tex010064400020550007177000000026610664720751500156560ustar00clevecompmath00000400000006\chapter{{\tt ILUMtx}: Incomplete $LU$ Matrix Object} \label{chapter:ILUMtx} \par The {\tt ILUMtx} object represents and approximate (incomplete) $(L+I)D(I+U)$, $(U^T+I)D(I+U)$ or $(U^H+I)D(I+U)$ factorization. It is a very simple object, rows and columns of $L$ and $U$ are stored as single vectors. All computations to compute the factorization and to solve linear systems are performed with sparse BLAS1 kernels. Presently, the storage scheme is very simple minded, we use {\tt malloc()} and {\tt free()} to handle the individual vectors of the rows and columns of $L$ and $U$. \par At present we have one factorization method. No pivoting is performed. Rows of $U$ are stored, along with columns of $L$ if the matrix is nonsymmetric. If a zero pivot is encountered on the diagonal during the factorization, the computation stops and returns a nonzero error code. (Presently, there is no ``patch-and-go'' functionality.) An $L_{j,i}$ entry is kept if $ |L_{j,i} D_{i,i}| \ge \sigma \sqrt{|D_{i,i}| \ |A_{j,j}|}, $ where $\sigma$ is a user supplied drop tolerance, and similarly for $U_{i,j}$. Note, if $A_{j,j} = 0$, as is common for KKT matrices, all $L_{j,i}$ and $U_{i,j}$ entries will be kept. It is simple to modify the code to use another drop tolerance criteria, e.g., an absolute tolerance, or one based only on $|D_{i,i}|$. We intend to write other factorization methods that will conform to a user-supplied nonzero structure for the factors. ILUMtx/doc/main.tex010064400020550007177000000011200665065624000154310ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt ILUMtx} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt ILUMtx} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} ILUMtx/doc/proto.tex010064400020550007177000000253120664720751500156640ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt ILUMtx} methods} \label{section:ILUMtx:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt ILUMtx} object. \par \subsection{Basic methods} \label{subsection:ILUMtx:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} ILUMtx * ILUMtx_new ( void ) ; \end{verbatim} \index{ILUMtx_new@{\tt ILUMtx\_new()}} This method simply allocates storage for the {\tt ILUMtx} structure and then sets the default fields by a call to {\tt ILUMtx\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} int ILUMtx_setDefaultFields ( ILUMtx *mtx ) ; \end{verbatim} \index{ILUMtx_setDefaultFields@{\tt ILUMtx\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt neqns = 0}, {\tt type} = {\tt SPOOLES\_REAL}, {\tt symmetryflag} = {\tt SPOOLES\_SYMMETRIC}, {\tt UstorageMode} = {\tt SPOOLES\_BY\_ROWS}, {\tt LstorageMode} = {\tt SPOOLES\_BY\_COLUMNS}, and {\tt entD}, {\tt sizesL}, {\tt p\_indL}, {\tt p\_entL}, {\tt sizesU}, {\tt p\_indU} and {\tt p\_entU} are all set to {\tt NULL}. \par \noindent {\it Return codes:} {\tt 1} means a normal return, {\tt -1} means {\tt mtx} is {\tt NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int ILUMtx_clearData ( ILUMtx *mtx ) ; \end{verbatim} \index{ILUMtx_clearData@{\tt ILUMtx\_clearData()}} This method releases all storage held by the object. \par \noindent {\it Return codes:} {\tt 1} means a normal return, {\tt -1} means {\tt mtx} is {\tt NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int ILUMtx_free ( ILUMtx *mtx ) ; \end{verbatim} \index{ILUMtx_free@{\tt ILUMtx\_free()}} This method releases all storage held by the object via a call to {\tt ILUMtx\_clearData()}, then free'd the storage for the object. \par \noindent {\it Return codes:} {\tt 1} means a normal return, {\tt -1} means {\tt mtx} is {\tt NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization Methods} \label{subsection:ILUMtx:proto:initializers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ILUMtx_init ( ILUMtx *mtx, int neqns, int type, int symmetryflag, int LstorageMode, int UstorageMode ) ; \end{verbatim} \index{ILUMtx_init@{\tt ILUMtx\_init()}} This is the initializer method that should be called immediately after {\tt ILUMtx\_new()}. It first clears any previous data with a call to {\tt ILUMtx\_clearData()}. The object's scalar fields are then set. The {\tt sizesU} (and {\tt sizesL} if nonsymmetric) vector(s) are then initialized and filled with zeros. The {\tt p\_indU}, {\tt p\_entU} (and {\tt p\_indL} and {\tt p\_entL} if nonsymmetric) vectors of pointers are initialized and filled with {\tt NULL} values. The {\tt entD} vector is initialized and filled with zeros. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt mtx} is {\tt NULL} \\ -2 & ${\tt neqns} <= 0$ \\ -3 & {\tt type} is invalid \\ \end{tabular} \quad \begin{tabular}{rl} -4 & {\tt symmetryflag} is invalid \\ -5 & {\tt LstorageMode} is invalid \\ -6 & {\tt UstorageMode} is invalid \\ -7 & {\tt type} and storage modes do not match \end{tabular} \end{center} \end{enumerate} \par %======================================================================= \par \subsection{Factorization Methods} \label{subsection:ILUMtx:proto:factor} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ILUMtx_factor ( ILUMtx *mtx, InpMtx *mtxA, double sigma, double *pops, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{ILUMtx_factor@{\tt ILUMtx\_factor()}} This methods computes a drop tolerance $A = (L + I)D(I + U)$, $A = (U^T + I)D(I + U)$ or $A = (U^H + I)D(I + U)$ factorization. An $L_{j,i}$ entry is kept if $ |L_{j,i} D_{i,i}| \ge \sigma \sqrt{|D_{i,i}| \ |A_{j,j}|}, $ where $\sigma$ is a user supplied drop tolerance, and similarly for $U_{i,j}$. If {\tt pops} is not {\tt NULL}, then on return {\tt *pops} holds the number of floating point operations that was performed during the factorization. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt mtx} is {\tt NULL} \\ -2 & ${\tt neqns} <= 0$ \\ -3 & {\tt type} is invalid \\ -4 & {\tt symmetryflag} is invalid \\ -5 & {\tt LstorageMode} is invalid \\ -6 & {\tt UstorageMode} is invalid \\ -7 & {\tt sizesL} is {\tt NULL} \\ -8 & {\tt sizesU} is {\tt NULL} \\ -9 & {\tt p\_indL} is {\tt NULL} \\ \end{tabular} \quad \begin{tabular}{rl} -10 & {\tt p\_indU} is {\tt NULL} \\ -11 & {\tt entD} is {\tt NULL} \\ -12 & {\tt p\_entL} is {\tt NULL} \\ -13 & {\tt p\_entU} is {\tt NULL} \\ -14 & {\tt mtxA} is {\tt NULL} \\ -15 & types of {\tt mtxLDU} and {\tt mtxA} do not match \\ -16 & {\tt mtxA} is not in chevron mode \\ -17 & $sigma < 0$ \\ -18 & {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL} \\ -19 & singular pivot found \end{tabular} \end{center} \end{enumerate} \par %======================================================================= \par \subsection{Solve Methods} \label{subsection:ILUMtx:proto:solve} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ILUMtx_solveVector ( ILUMtx *mtx, DV *X, DV *B, DV *workDV, double *pops, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{ILUMtx_solveVector@{\tt ILUMtx\_solveVector()}} This methods solves a linear system $(L + I)D(I + U)x = b$, $(U^T + I)D(I + U)x = b$ or $(U^H + I)D(I + U)x = b$. {\tt workDV} is a work vector. If {\tt workDV} is different that {\tt B}, then {\tt B} is unchanged on return. One can have {\tt X}, {\tt B} and {\tt workDV} point to the same object. If {\tt pops} is not {\tt NULL}, then on return {\tt *pops} holds the number of floating point operations that was performed during the solve. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt mtx} is {\tt NULL} \\ -2 & ${\tt neqns} <= 0$ \\ -3 & {\tt type} is invalid \\ -4 & {\tt symmetryflag} is invalid \\ -5 & {\tt LstorageMode} is invalid \\ -6 & {\tt UstorageMode} is invalid \\ -7 & {\tt sizesL} is {\tt NULL} \\ -8 & {\tt sizesU} is {\tt NULL} \\ -9 & {\tt p\_indL} is {\tt NULL} \\ -10 & {\tt p\_indU} is {\tt NULL} \\ -11 & {\tt entD} is {\tt NULL} \\ \end{tabular} \quad \begin{tabular}{rl} -12 & {\tt p\_entL} is {\tt NULL} \\ -13 & {\tt p\_entU} is {\tt NULL} \\ -14 & {\tt X} is {\tt NULL} \\ -15 & size of {\tt X} is incorrect \\ -16 & entries of {\tt X} are {\tt NULL} \\ -17 & {\tt B} is {\tt NULL} \\ -18 & size of {\tt B} is incorrect \\ -19 & entries of {\tt B} are {\tt NULL} \\ -20 & {\tt workDV} is {\tt NULL} \\ -21 & size of {\tt workDV} is incorrect \\ -22 & entries of {\tt workDV} are {\tt NULL} \\ -23 & {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL} \\ \end{tabular} \end{center} \end{enumerate} \par %======================================================================= \subsection{Utility methods} \label{subsection:ILUMtx:proto:utility} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ILUMtx_fillRandom ( ILUMtx *mtx, int seed ) ; \end{verbatim} \index{ILUMtx_fillRandom@{\tt ILUMtx\_fillRandom()}} This method fills the {\tt mtx} object with a random nonzero pattern and random matrix entries. The matrix must have already been initialized using the {\tt ILUMtx\_init()} method. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt mtx} is {\tt NULL} \\ -2 & ${\tt neqns} <= 0$ \\ -3 & {\tt type} is invalid \\ -4 & {\tt symmetryflag} is invalid \\ \end{tabular} \quad \begin{tabular}{rl} -5 & {\tt LstorageMode} is invalid \\ -6 & {\tt UstorageMode} is invalid \\ -7 & {\tt sizesL} is {\tt NULL} \\ -8 & {\tt sizesU} is {\tt NULL} \\ -9 & {\tt p\_indL} is {\tt NULL} \\ \end{tabular} \quad \begin{tabular}{rl} -10 & {\tt p\_indU} is {\tt NULL} \\ -11 & {\tt entD} is {\tt NULL} \\ -12 & {\tt p\_entL} is {\tt NULL} \\ -13 & {\tt p\_entU} is {\tt NULL} \\ \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:ILUMtx:proto:IO} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ILUMtx_writeForMatlab ( ILUMtx *mtx, char *Lname, char *Dname, char *Uname, FILE *fp ) ; \end{verbatim} \index{ILUMtx_writeForMatlab@{\tt ILUMtx\_writeForMatlab()}} \par This method writes out a {\tt ILUMtx} object to a file in a Matlab format. The entries in $L$ use the {\tt Lname} string, the entries in $D$ use the {\tt Dname} string, and the entries in $U$ use the {\tt Uname} string, A sample line is \begin{verbatim} L(10,5) = -1.550328201511e-01 + 1.848033378871e+00*i ; \end{verbatim} for complex matrices, or \begin{verbatim} L(10,5) = -1.550328201511e-01 ; \end{verbatim} for real matrices, where {\tt Lname} = {\tt "L"}. The matrix indices are incremented by one to follow the Matlab and FORTRAN convention. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt mtx} is {\tt NULL} \\ -2 & ${\tt neqns} <= 0$ \\ -3 & {\tt type} is invalid \\ -4 & {\tt symmetryflag} is invalid \\ -5 & {\tt LstorageMode} is invalid \\ \end{tabular} \quad \begin{tabular}{rl} -6 & {\tt UstorageMode} is invalid \\ -7 & {\tt sizesL} is {\tt NULL} \\ -8 & {\tt sizesU} is {\tt NULL} \\ -9 & {\tt p\_indL} is {\tt NULL} \\ -10 & {\tt p\_indU} is {\tt NULL} \\ -11 & {\tt entD} is {\tt NULL} \\ \end{tabular} \quad \begin{tabular}{rl} -12 & {\tt p\_entL} is {\tt NULL} \\ -13 & {\tt p\_entU} is {\tt NULL} \\ -14 & {\tt Lname} is {\tt NULL} \\ -15 & {\tt Dname} is {\tt NULL} \\ -16 & {\tt Uname} is {\tt NULL} \\ -17 & {\tt fp} is {\tt NULL} \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} ILUMtx/doc/main.log010064400020550007177000000143120664720751500154240ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 30 OCT 1998 13:32 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/latex209.def File: latex209.def 1996/05/21 v0.51 Standard LaTeX file Entering LaTeX 2.09 compatibility mode. \footheight=\dimen102 \@maxsep=\dimen103 \@dblmaxsep=\dimen104 \@cla=\count79 \@clb=\count80 \mscount=\count81 (/home/tex/teTeX/texmf/tex/latex/base/tracefnt.sty Package: tracefnt 1996/07/26 v3.0i Standard LaTeX package (font tracing) \tracingfonts=\count82 LaTeX Info: Redefining \selectfont on input line 139. ) \symbold=\mathgroup4 \symsans=\mathgroup5 \symtypewriter=\mathgroup6 \symitalic=\mathgroup7 \symsmallcaps=\mathgroup8 \symslanted=\mathgroup9 LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 306. LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 307. LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 308. LaTeX Font Info: Redeclaring math alphabet \mathit on input line 314. LaTeX Info: Redefining \em on input line 324. (/home/tex/teTeX/texmf/tex/latex/base/latexsym.sty Package: latexsym 1996/11/20 v2.2d Standard LaTeX package (lasy symbols) \symlasy=\mathgroup10 LaTeX Font Info: Overwriting symbol font `lasy' in version `bold' (Font) U/lasy/m/n --> U/lasy/b/n on input line 85. ) LaTeX Font Info: Redeclaring math delimiter \lgroup on input line 388. LaTeX Font Info: Redeclaring math delimiter \rgroup on input line 390. LaTeX Font Info: Redeclaring math delimiter \bracevert on input line 392. (/home/tex/teTeX/texmf/tex/latex/config/latex209.cfg (/home/tex/teTeX/texmf/tex/latex/tools/rawfonts.sty Compatibility mode: package `' requested, but `rawfonts' provided. Package: rawfonts 1994/05/08 Low-level LaTeX 2.09 font compatibility (/home/tex/teTeX/texmf/tex/latex/tools/somedefs.sty Package: somedefs 1994/06/01 Toolkit for optional definitions ) LaTeX Font Info: Try loading font information for U+lasy on input line 36. (/home/tex/teTeX/texmf/tex/latex/base/ulasy.fd File: ulasy.fd 1996/11/20 v2.2dLaTeX symbol font definitions )))) (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size11.clo File: size11.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count83 \c@chapter=\count84 \c@section=\count85 \c@subsection=\count86 \c@subsubsection=\count87 \c@paragraph=\count88 \c@subparagraph=\count89 \c@figure=\count90 \c@table=\count91 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 Compatibility mode: definition of \rm ignored. Compatibility mode: definition of \sf ignored. Compatibility mode: definition of \tt ignored. Compatibility mode: definition of \bf ignored. Compatibility mode: definition of \it ignored. Compatibility mode: definition of \sl ignored. Compatibility mode: definition of \sc ignored. LaTeX Info: Redefining \cal on input line 622. LaTeX Info: Redefining \mit on input line 623. \bibindent=\dimen105 ) (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen106 \p@intvaluey=\dimen107 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. (intro.tex Chapter 1. LaTeX Font Info: External font `cmex10' loaded for size (Font) <24.88> on input line 1. LaTeX Font Info: External font `cmex10' loaded for size (Font) <20.74> on input line 1. LaTeX Font Info: External font `cmex10' loaded for size (Font) <17.28> on input line 1. LaTeX Font Info: External font `cmex10' loaded for size (Font) <10.95> on input line 5. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 5. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 5. ) (dataStructure.tex LaTeX Font Info: Try loading font information for OMS+cmr on input line 9. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10.95> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 9. [1 ]) (proto.tex [2] [3] [4]) (drivers.tex [5] Overfull \hbox (5.32565pt too wide) in paragraph at lines 39--44 []\OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 must be ei-ther \OT1/cmtt/m/n/ 10.95 SPOOLES[]SYMMETRIC\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMI TIAN \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr/m/n/1 0.95 . [] Overfull \hbox (5.32565pt too wide) in paragraph at lines 91--96 []\OT1/cmtt/m/n/10.95 symflag \OT1/cmr/m/n/10.95 must be ei-ther \OT1/cmtt/m/n/ 10.95 SPOOLES[]SYMMETRIC\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 SPOOLES[]HERMI TIAN \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 SPOOLES[]SYMMETRIC\OT1/cmr/m/n/1 0.95 . [] ) (main.ind [6] [7 ]) (main.aux) ) Here is how much of TeX's memory you used: 833 strings out of 10908 8697 string characters out of 72189 57338 words of memory out of 262141 3684 multiletter control sequences out of 9500 28429 words of font info for 105 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 22i,8n,21p,313b,342s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (7 pages, 21420 bytes). ILUMtx/doc/main.idx010064400020550007177000000010130664720751500154210ustar00clevecompmath00000400000006\indexentry{ILUMtx_new@{\tt ILUMtx\_new()}}{2} \indexentry{ILUMtx_setDefaultFields@{\tt ILUMtx\_setDefaultFields()}}{3} \indexentry{ILUMtx_clearData@{\tt ILUMtx\_clearData()}}{3} \indexentry{ILUMtx_free@{\tt ILUMtx\_free()}}{3} \indexentry{ILUMtx_init@{\tt ILUMtx\_init()}}{3} \indexentry{ILUMtx_factor@{\tt ILUMtx\_factor()}}{3} \indexentry{ILUMtx_solveVector@{\tt ILUMtx\_solveVector()}}{4} \indexentry{ILUMtx_fillRandom@{\tt ILUMtx\_fillRandom()}}{4} \indexentry{ILUMtx_writeForMatlab@{\tt ILUMtx\_writeForMatlab()}}{5} ILUMtx/doc/main.aux010064400020550007177000000027300664720751500154410ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt ILUMtx}: Incomplete $LU$ Matrix Object}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:ILUMtx}{{1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{1}} \newlabel{section:ILUMtx:dataStructure}{{1.1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt ILUMtx} methods}{2}} \newlabel{section:ILUMtx:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{2}} \newlabel{subsection:ILUMtx:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Initialization Methods}{3}} \newlabel{subsection:ILUMtx:proto:initializers}{{1.2.2}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Factorization Methods}{3}} \newlabel{subsection:ILUMtx:proto:factor}{{1.2.3}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Solve Methods}{4}} \newlabel{subsection:ILUMtx:proto:solve}{{1.2.4}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Utility methods}{4}} \newlabel{subsection:ILUMtx:proto:utility}{{1.2.5}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.6}IO methods}{5}} \newlabel{subsection:ILUMtx:proto:IO}{{1.2.6}{5}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs for the {\tt ILUMtx} object}{5}} \newlabel{section:ILUMtx:drivers}{{1.3}{5}} label{section:ILUMtx:proto}{{1.2}{2}} \@ILUMtx/doc/main.ind010064400020550007177000000005530664720751500154170ustar00clevecompmath00000400000006\begin{theindex} \item {\tt ILUMtx\_clearData()}, 3 \item {\tt ILUMtx\_factor()}, 3 \item {\tt ILUMtx\_fillRandom()}, 4 \item {\tt ILUMtx\_free()}, 3 \item {\tt ILUMtx\_init()}, 3 \item {\tt ILUMtx\_new()}, 2 \item {\tt ILUMtx\_setDefaultFields()}, 3 \item {\tt ILUMtx\_solveVector()}, 4 \item {\tt ILUMtx\_writeForMatlab()}, 5 \end{theindex} ILUMtx/doc/main.ilg010064400020550007177000000004550664720751500154210ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (9 entries accepted, 0 rejected). Sorting entries....done (30 comparisons). Generating output file main.ind....done (13 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. ILUMtx/doc/makefile010064400020550007177000000000270664720751500154730ustar00clevecompmath00000400000006clean : - rm -f *.dvi IV.h010064400020550007177000000000640653410636600125710ustar00clevecompmath00000400000006#ifndef _IV_ #define _IV_ #include "IV/IV.h" #endif IV/IV.h010064400020550007177000000367020661364027100131130ustar00clevecompmath00000400000006/* IV.h */ #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- IV -- integer vector object size -- size of the vector maxsize -- maximum size of the vector owned -- owner flag when == 1, storage pointed to by entries has been allocated here and can be free'd. when == 0, storage pointed to by entries has not been allocated here and cannot be free'd. vec -- pointer to base address --------------------------------------------------------- */ typedef struct _IV IV ; struct _IV { int size ; int maxsize ; int owned ; int *vec ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor method created -- 95oct06, cca ----------------------- */ IV * IV_new ( void ) ; /* ----------------------- set the default fields created -- 95oct06, cca ----------------------- */ void IV_setDefaultFields ( IV *iv ) ; /* ----------------------- clear the data fields created -- 95oct06, cca ----------------------- */ void IV_clearData ( IV *iv ) ; /* ----------------------- destructor created -- 95oct06, cca ----------------------- */ void IV_free ( IV *iv ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ---------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------- simplest initialization method if entries != NULL the object does not own the entries, it just points to the entries base address else if size > 0 the object will own the entries, it allocates a vector of size int's. else nothing happens endif created -- 96aug28, cca --------------------------------------------- */ void IV_init ( IV *iv, int size, int *entries ) ; /* ------------------------- basic initializion method created -- 95oct06, cca ------------------------- */ void IV_init1 ( IV *iv, int Maxsize ) ; /* ------------------------- total initializion method created -- 95oct06, cca ------------------------- */ void IV_init2 ( IV *iv, int size, int maxsize, int owned, int *vec ) ; /* ---------------------------------- set the maximum size of the vector created -- 96dec08, cca ---------------------------------- */ void IV_setMaxsize ( IV *iv, int newmaxsize ) ; /* -------------------------- set the size of the vector created -- 96dec08, cca -------------------------- */ void IV_setSize ( IV *iv, int newsize ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------------- return value is 0 if the entries are not owned by the object otherwise the return value is the number of entries at the base storage of the vector created -- 96jun22, cca modified -- 96aug28, cca --------------------------------------------------------------- */ int IV_owned ( IV *iv ) ; /* ---------------------------------- return the vector size and entries created -- 95oct06, cca ---------------------------------- */ int IV_size ( IV *iv ) ; /* ------------------------------------- return the maximum size of the vector created -- 95dec08, cca ------------------------------------- */ int IV_maxsize ( IV *iv ) ; /* ------------------------------------------------ return the loc'th entry of a vector. note: if loc is out of range then -1 is returned created -- 96jun29, cca ------------------------------------------------ */ int IV_entry ( IV *iv, int loc ) ; /* ---------------------------------------------- return a pointer to the object's entries array created -- 95oct06, cca ---------------------------------------------- */ int * IV_entries ( IV *iv ) ; /* -------------------------------------------- fill *psize with the vector's size and *pentries with the address of the vector created -- 95oct06, cca -------------------------------------------- */ void IV_sizeAndEntries ( IV *iv, int *psize, int **pentries ) ; /* -------------------------- set the size of the vector created -- 96jun22, cca -------------------------- */ void IV_setSize ( IV *iv, int Size ) ; /* --------------------------- set and entry in the vector created -- 96jul14, cca --------------------------- */ void IV_setEntry ( IV *iv, int location, int value ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- shift the base of the entries and adjust the dimensions note: this is a dangerous operation because the iv->vec does not point to the base of the entries any longer, and thus if the object owns its entries and it is called to resize them or to free them, malloc and free will choke. USE WITH CAUTION! created -- 96aug25, cca modified -- 96aug28, cca structure changed ----------------------------------------------------------- */ void IV_shiftBase ( IV *iv, int offset ) ; /* --------------------------- push an entry onto the list created -- 95oct06, cca modified -- 95aug28, cca structure has changed --------------------------- */ void IV_push ( IV *iv, int val ) ; /* --------------------------- minimum and maximum entries created -- 95oct06, cca --------------------------- */ int IV_min ( IV *iv ) ; int IV_max ( IV *iv ) ; int IV_sum ( IV *iv ) ; /* ------------------------------------------------------- sort each index list into ascending or descending order created -- 95oct06, cca ------------------------------------------------------- */ void IV_sortUp ( IV *iv ) ; void IV_sortDown ( IV *iv ) ; /* ----------------------- ramp the entries created -- 95oct06, cca ----------------------- */ void IV_ramp ( IV *iv, int base, int incr ) ; /* ----------------------- shuffle the list created -- 95oct06, cca ----------------------- */ void IV_shuffle ( IV *iv, int seed ) ; /* ---------------------------------------------- return the number of bytes taken by the object created -- 95oct06, cca ---------------------------------------------- */ int IV_sizeOf ( IV *iv ) ; /* ---------------------------------------------------------------- keep entries that are tagged, move others to end and adjust size created -- 95oct06, cca ---------------------------------------------------------------- */ void IV_filterKeep ( IV *iv, int tags[], int keepTag ) ; /* --------------------------------------------------------- move purge entries that are tagged to end and adjust size created -- 95oct06, cca --------------------------------------------------------- */ void IV_filterPurge ( IV *iv, int tags[], int purgeTag ) ; /* -------------------------------------------- iterator : return the pointer to the head of the vector created -- 95oct06, cca -------------------------------------------- */ int * IV_first ( IV *iv ) ; /* ----------------------------------------------------- iterator : return the pointer to the next location in the vector created -- 95oct06, cca ----------------------------------------------------- */ int * IV_next ( IV *iv, int *pi ) ; /* -------------------------- fill a vector with a value created -- 96jun22, cca -------------------------- */ void IV_fill ( IV *iv, int value ) ; /* -------------------------------------- copy entries from iv2 into iv1. note: this is a "mapped" copy, iv1 and iv2 need not be the same size. created -- 96aug31, cca -------------------------------------- */ void IV_copy ( IV *iv1, IV *iv2 ) ; /* -------------------------------------------------- increment the loc'th location of the vector by one and return the new value created -- 96dec18, cca -------------------------------------------------- */ int IV_increment ( IV *iv, int loc ) ; /* -------------------------------------------------- decrement the loc'th location of the vector by one and return the new value created -- 96dec18, cca -------------------------------------------------- */ int IV_decrement ( IV *iv, int loc ) ; /* ------------------------------------------------------------ return the first location in the vector that contains value. if value is not present, -1 is returned. cost is linear in the size of the vector created -- 96jan15, cca ------------------------------------------------------------ */ int IV_findValue ( IV *iv, int value ) ; /* --------------------------------------------------------------- return a location in the vector that contains value. the entries in the vector are assumed to be in ascending order. if value is not present, -1 is returned. cost is logarithmic in the size of the vector created -- 96jan15, cca --------------------------------------------------------------- */ int IV_findValueAscending ( IV *iv, int value ) ; /* ---------------------------------------------------------------- return a location in the vector that contains value. the entries in the vector are assumed to be in descending order. if value is not present, -1 is returned. cost is logarithmic in the size of the vector created -- 96jan15, cca ---------------------------------------------------------------- */ int IV_findValueDescending ( IV *iv, int value ) ; /* --------------------------------------------------- purpose -- return invlistIV, an IV object that contains the inverse map, i.e., invlist[list[ii]] = ii. other entries of invlist[] are -1. all entris in listIV must be nonnegative created -- 98aug12, cca --------------------------------------------------- */ IV * IV_inverseMap ( IV *listIV ) ; /* ----------------------------------------------------------- purpose -- return an IV object that contains the locations of all instances of target in listIV. this is used when listIV is a map from [0,n) to a finite set (like processors) and we want to find all entries that are mapped to a specific processor. created -- 98aug12, cca ----------------------------------------------------------- */ IV * IV_targetEntries ( IV *listIV, int target ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------- purpose -- to read in an IV object from a file input -- fn -- filename, must be *.ivb or *.ivf return value -- 1 if success, 0 if failure created -- 95oct06, cca ---------------------------------------------- */ int IV_readFromFile ( IV *iv, char *fn ) ; /* ----------------------------------------------------- purpose -- to read an IV object from a formatted file return value -- 1 if success, 0 if failure created -- 95oct06, cca ----------------------------------------------------- */ int IV_readFromFormattedFile ( IV *iv, FILE *fp ) ; /* --------------------------------------------------- purpose -- to read an IV object from a binary file return value -- 1 if success, 0 if failure created -- 95oct06, cca --------------------------------------------------- */ int IV_readFromBinaryFile ( IV *iv, FILE *fp ) ; /* ------------------------------------------- purpose -- to write an IV object to a file input -- fn -- filename *.ivb -- binary *.ivf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95oct06, cca ------------------------------------------- */ int IV_writeToFile ( IV *iv, char *fn ) ; /* ----------------------------------------------------- purpose -- to write an IV object to a formatted file return value -- 1 if success, 0 otherwise created -- 95oct06, cca ----------------------------------------------------- */ int IV_writeToFormattedFile ( IV *iv, FILE *fp ) ; /* -------------------------------------------------- purpose -- to write an IV object to a binary file return value -- 1 if success, 0 otherwise created -- 95oct06, cca -------------------------------------------------- */ int IV_writeToBinaryFile ( IV *iv, FILE *fp ) ; /* ------------------------------------------------- purpose -- to write an IV object for a human eye return value -- 1 if success, 0 otherwise created -- 95oct06, cca ------------------------------------------------- */ int IV_writeForHumanEye ( IV *iv, FILE *fp ) ; /* --------------------------------------------------------- purpose -- to write out the statistics for the IV object return value -- 1 if success, 0 otherwise created -- 95oct06, cca --------------------------------------------------------- */ int IV_writeStats ( IV *iv, FILE *fp ) ; /* ------------------------------------------------------------------- purpose -- to write out an integer vector with eighty column lines input -- fp -- file pointer, must be formatted and write access column -- present column pierr -- pointer to int to hold return value, should be 1 if any print was successful, if fprintf() failed, then ierr = -1 return value -- present column created -- 96jun22, cca ------------------------------------------------------------------- */ int IV_fp80 ( IV *iv, FILE *fp, int column, int *pierr ) ; /* --------------------------------------------------- purpose -- to write the IV object for a matlab file return value -- 1 if success, 0 otherwise created -- 98oct22, cca --------------------------------------------------- */ int IV_writeForMatlab ( IV *iv, char *name, FILE *fp ) ; /*--------------------------------------------------------------------*/ .c ---------------------------------------- ------------------IV/makefile010064400020550007177000000002230663622361400141140ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean IV/src/makefile010064400020550007177000000007220663602473100147060ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = IV $(OBJ).a : \ $(OBJ).a(IO.o) \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG IV/src/makeGlobalLib010064400020550007177000000006130660026104400156040ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = IV SRC = IO.c \ basics.c \ init.c \ instance.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a IV/src/IO.c010064400020550007177000000317250661365567600137050ustar00clevecompmath00000400000006/* IO.c */ #include "../IV.h" static const char *suffixb = ".ivb" ; static const char *suffixf = ".ivf" ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to read in an IV object from a file input -- fn -- filename, must be *.ivb or *.ivf return value -- 1 if success, 0 if failure created -- 95oct06, cca ---------------------------------------------- */ int IV_readFromFile ( IV *iv, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( iv == NULL || fn == NULL ) { fprintf(stderr, "\n error in IV_readFromFile(%p,%s), file %s, line %d" "\n bad input\n", iv, fn, __FILE__, __LINE__) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in IV_readFromFile(%p,%s)" "\n unable to open file %s", iv, fn, fn) ; rc = 0 ; } else { rc = IV_readFromBinaryFile(iv, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in IV_readFromFile(%p,%s)" "\n unable to open file %s", iv, fn, fn) ; rc = 0 ; } else { rc = IV_readFromFormattedFile(iv, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in IV_readFromFile(%p,%s)" "\n bad IV file name %s," "\n must end in %s (binary) or %s (formatted)\n", iv, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in IV_readFromFile(%p,%s)" "\n bad IV file name %s," "\n must end in %s (binary) or %s (formatted)\n", iv, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to read an IV object from a formatted file return value -- 1 if success, 0 if failure created -- 95oct06, cca ----------------------------------------------------- */ int IV_readFromFormattedFile ( IV *iv, FILE *fp ) { int rc, size ; /* --------------- check the input --------------- */ if ( iv == NULL || fp == NULL ) { fprintf(stderr, "\n error in IV_readFromFormattedFile(%p,%p)" "\n bad input\n", iv, fp) ; return(0) ; } IV_clearData(iv) ; /* ------------------------------ read in the size of the vector ------------------------------ */ if ( (rc = fscanf(fp, "%d", &size)) != 1 ) { fprintf(stderr, "\n error in IV_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", iv, fp, rc, 1) ; return(0) ; } /* --------------------- initialize the object --------------------- */ IV_init(iv, size, NULL) ; iv->size = size ; /* ------------------------ read in the vec[] vector ------------------------ */ if ( (rc = IVfscanf(fp, size, iv->vec)) != size ) { fprintf(stderr, "\n error in IV_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", iv, fp, rc, size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to read an IV object from a binary file return value -- 1 if success, 0 if failure created -- 95oct06, cca --------------------------------------------------- */ int IV_readFromBinaryFile ( IV *iv, FILE *fp ) { int rc, size ; /* --------------- check the input --------------- */ if ( iv == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in IV_readFromBinaryFile(%p,%p)" "\n bad input\n", iv, fp) ; return(0) ; } IV_clearData(iv) ; /* ------------------------------ read in the size of the vector ------------------------------ */ if ( (rc = fread((void *) &size, sizeof(int), 1, fp)) != 1 ) { fprintf(stderr, "\n error in IV_readFromBinaryFile(%p,%p)" "\n itemp(3) : %d items of %d read\n", iv, fp, rc, 1) ; return(0) ; } /* --------------------- initialize the object --------------------- */ IV_init(iv, size, NULL) ; iv->size = size ; /* ------------------------ read in the vec[] vector ------------------------ */ if ( (rc = fread((void *) iv->vec, sizeof(int), size, fp)) != size ) { fprintf(stderr, "\n error in IV_readFromBinaryFile(%p,%p)" "\n sizes(%d) : %d items of %d read\n", iv, fp, size, rc, size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to write an IV object to a file input -- fn -- filename *.ivb -- binary *.ivf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95oct06, cca ------------------------------------------- */ int IV_writeToFile ( IV *iv, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( iv == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in IV_writeToFile(%p,%s)" "\n bad input\n", iv, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in IV_writeToFile(%p,%s)" "\n unable to open file %s", iv, fn, fn) ; rc = 0 ; } else { rc = IV_writeToBinaryFile(iv, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in IV_writeToFile(%p,%s)" "\n unable to open file %s", iv, fn, fn) ; rc = 0 ; } else { rc = IV_writeToFormattedFile(iv, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in IV_writeToFile(%p,%s)" "\n unable to open file %s", iv, fn, fn) ; rc = 0 ; } else { rc = IV_writeForHumanEye(iv, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in IV_writeToFile(%p,%s)" "\n unable to open file %s", iv, fn, fn) ; rc = 0 ; } else { rc = IV_writeForHumanEye(iv, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to write an IV object to a formatted file return value -- 1 if success, 0 otherwise created -- 95oct06, cca ----------------------------------------------------- */ int IV_writeToFormattedFile ( IV *iv, FILE *fp ) { int ierr, rc ; /* --------------- check the input --------------- */ if ( iv == NULL || fp == NULL || iv->size <= 0 ) { fprintf(stderr, "\n fatal error in IV_writeToFormattedFile(%p,%p)" "\n bad input\n", iv, fp) ; fprintf(stderr, "\n iv->size = %d", iv->size) ; exit(-1) ; } /* ------------------------------------- write out the size of the vector ------------------------------------- */ rc = fprintf(fp, "\n %d", iv->size) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in IV_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", iv, fp, rc) ; return(0) ; } if ( iv->size > 0 ) { IVfp80(fp, iv->size, iv->vec, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in IV_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from sizes[] IVfp80\n", iv, fp, ierr) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to write an IV object to a binary file return value -- 1 if success, 0 otherwise created -- 95oct06, cca -------------------------------------------------- */ int IV_writeToBinaryFile ( IV *iv, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( iv == NULL || fp == NULL || iv->size <= 0 ) { fprintf(stderr, "\n fatal error in IV_writeToBinaryFile(%p,%p)" "\n bad input\n", iv, fp) ; exit(-1) ; } rc = fwrite((void *) &iv->size, sizeof(int), 1, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n error in IV_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", iv, fp, rc, 1) ; return(0) ; } rc = fwrite((void *) iv->vec, sizeof(int), iv->size, fp) ; if ( rc != iv->size ) { fprintf(stderr, "\n error in IV_writeToBinaryFile(%p,%p)" "\n iv->sizes, %d of %d items written\n", iv, fp, rc, iv->size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to write an IV object for a human eye return value -- 1 if success, 0 otherwise created -- 95oct06, cca ------------------------------------------------- */ int IV_writeForHumanEye ( IV *iv, FILE *fp ) { int ierr, rc ; if ( iv == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in IV_writeForHumanEye(%p,%p)" "\n bad input\n", iv, fp) ; exit(-1) ; } if ( (rc = IV_writeStats(iv, fp)) == 0 ) { fprintf(stderr, "\n fatal error in IV_writeForHumanEye(%p,%p)" "\n rc = %d, return from IV_writeStats(%p,%p)\n", iv, fp, rc, iv, fp) ; return(0) ; } IVfp80(fp, iv->size, iv->vec, 80, &ierr) ; return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- to write out the statistics for the IV object return value -- 1 if success, 0 otherwise created -- 95oct06, cca --------------------------------------------------------- */ int IV_writeStats ( IV *iv, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( iv == NULL || fp == NULL ) { fprintf(stderr, "\n error in IV_writeStats(%p,%p)" "\n bad input\n", iv, fp) ; exit(-1) ; } rc = fprintf(fp, "\n IV : integer vector object : ") ; if ( rc < 0 ) { goto IO_error ; } rc = fprintf(fp, " size = %d, maxsize = %d, owned = %d", iv->size, iv->maxsize, iv->owned) ; if ( rc < 0 ) { goto IO_error ; } return(1) ; IO_error : fprintf(stderr, "\n fatal error in IV_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", iv, fp, rc) ; return(0) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- to write out an integer vector with eighty column lines input -- fp -- file pointer, must be formatted and write access column -- present column pierr -- pointer to int to hold return value, should be 1 if any print was successful, if fprintf() failed, then ierr = -1 return value -- present column created -- 96jun22, cca ------------------------------------------------------------------- */ int IV_fp80 ( IV *iv, FILE *fp, int column, int *pierr ) { /* --------------- check the input --------------- */ if ( iv == NULL || fp == NULL || pierr == NULL ) { fprintf(stderr, "\n fatal error in IV_fp80(%p,%p,%p)" "\n bad input\n", iv, fp, pierr) ; exit(-1) ; } if ( iv->size > 0 && iv->vec != NULL ) { column = IVfp80(fp, iv->size, iv->vec, column, pierr) ; } return(column) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to write the IV object for a matlab file return value -- 1 if success, 0 otherwise created -- 98oct22, cca --------------------------------------------------- */ int IV_writeForMatlab ( IV *iv, char *name, FILE *fp ) { int ii, rc, size ; int *entries ; /* --------------- check the input --------------- */ if ( iv == NULL || fp == NULL ) { fprintf(stderr, "\n error in IV_writeForMatlab(%p,%p,%p)" "\n bad input\n", iv, name, fp) ; exit(-1) ; } IV_sizeAndEntries(iv, &size, &entries) ; fprintf(fp, "\n %s = zeros(%d,%d) ;", name, size, size) ; for ( ii = 0 ; ii < size ; ii++ ) { fprintf(fp, "\n %s(%d) = %d ;", name, ii+1, entries[ii]+1) ; } return(1) ; } /*--------------------------------------------------------------------*/ IV/src/basics.c010064400020550007177000000032400657725423500146240ustar00clevecompmath00000400000006/* basics.C */ #include "../IV.h" /*--------------------------------------------------------------------*/ /* ----------------------- constructor method created -- 95oct06, cca ----------------------- */ IV * IV_new ( void ) { IV *iv ; ALLOCATE(iv, struct _IV, 1) ; IV_setDefaultFields(iv) ; return(iv) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 95oct06, cca ----------------------- */ void IV_setDefaultFields ( IV *iv ) { if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_setDefaultFields(%p)" "\n bad input\n", iv) ; exit(-1) ; } iv->size = 0 ; iv->maxsize = 0 ; iv->owned = 0 ; iv->vec = NULL ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields created -- 95oct06, cca ----------------------- */ void IV_clearData ( IV *iv ) { if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_clearData(%p)" "\n bad input\n", iv) ; exit(-1) ; } if ( iv->vec != NULL && iv->owned == 1 ) { IVfree(iv->vec) ; } IV_setDefaultFields(iv) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- destructor created -- 95oct06, cca ----------------------- */ void IV_free ( IV *iv ) { if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_free(%p)" "\n bad input\n", iv) ; exit(-1) ; } IV_clearData(iv) ; FREE(iv) ; return ; } /*--------------------------------------------------------------------*/ IV/src/init.c010064400020550007177000000152200657725115600143230ustar00clevecompmath00000400000006/* init.C */ #include "../IV.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------- simplest initialization method if entries != NULL the object does not own the entries, it just points to the entries base address else if size > 0 the object will own the entries, it allocates a vector of size int's. else nothing happens endif created -- 96aug28, cca --------------------------------------------- */ void IV_init ( IV *iv, int size, int *entries ) { if ( iv == NULL || size < 0 ) { fprintf(stderr, "\n fatal error in IV_init(%p,%d,%p)" "\n bad input\n", iv, size, entries) ; exit(-1) ; } /* -------------- clear any data -------------- */ IV_clearData(iv) ; /* ----------------------------- set the size and maximum size ----------------------------- */ iv->maxsize = iv->size = size ; /* ------------------------- set vector and owner flag ------------------------- */ if ( entries != NULL ) { iv->owned = 0 ; iv->vec = entries ; } else if ( size > 0 ) { iv->owned = 1 ; iv->vec = IVinit(size, -1) ; } /* fprintf(stdout, "\n %% leaving IV_init, iv %p, size %d, maxsize %d, entries %p", iv, iv->size, iv->maxsize, iv->vec) ; fflush(stdout) ; */ return ; } /*--------------------------------------------------------------------*/ /* ------------------------- basic initializion method created -- 95oct06, cca ------------------------- */ void IV_init1 ( IV *iv, int size ) { IV_init(iv, size, NULL) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------- total initializion method created -- 95oct06, cca ------------------------- */ void IV_init2 ( IV *iv, int size, int maxsize, int owned, int *vec ) { /* --------------- check the input --------------- */ if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_init2(%p,%d,%d,%d,%p)" "\n bad input\n", iv, size, maxsize, owned, vec) ; exit(-1) ; } if ( size < 0 || maxsize < size ) { fprintf(stderr, "\n fatal error in IV_init2(%p,%d,%d,%d,%p)" "\n size = %d, maxsize = %d \n", iv, size, maxsize, owned, vec, size, maxsize) ; exit(-1) ; } if ( owned < 0 || 1 < owned ) { fprintf(stderr, "\n fatal error in IV_init2(%p,%d,%d,%d,%p)" "\n owned = %d\n", iv, size, maxsize, owned, vec, owned) ; exit(-1) ; } if ( owned == 1 && vec == NULL ) { fprintf(stderr, "\n fatal error in IV_init2(%p,%d,%d,%d,%p)" "\n owned = %d and vec = %p", iv, size, maxsize, owned, vec, owned, vec) ; exit(-1) ; } /* -------------- clear any data -------------- */ IV_clearData(iv) ; if ( vec == NULL ) { /* ---------------------------------------------- no entries input, use the simplest initializer ---------------------------------------------- */ IV_init(iv, size, NULL) ; } else { /* --------------------------------- entries are input, set the fields --------------------------------- */ iv->size = size ; iv->maxsize = maxsize ; iv->owned = owned ; iv->vec = vec ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- set the maximum size of the vector created -- 96dec08, cca ---------------------------------- */ void IV_setMaxsize ( IV *iv, int newmaxsize ) { /* --------------- check the input --------------- */ if ( iv == NULL || newmaxsize < 0 ) { fprintf(stderr, "\n fatal error in IV_setMaxsize(%p,%d)" "\n bad input\n", iv, newmaxsize) ; exit(-1) ; } if ( iv->maxsize > 0 && iv->owned == 0 ) { fprintf(stderr, "\n fatal error in IV_setMaxsize(%p,%d)" "\n iv->maxsize = %d, iv->owned = %d\n", iv, newmaxsize, iv->maxsize, iv->owned) ; exit(-1) ; } if ( iv->maxsize != newmaxsize ) { /* ----------------------------------- allocate new storage for the vector ----------------------------------- */ int *vec = IVinit(newmaxsize, -1) ; if ( iv->size > 0 ) { /* --------------------------------- copy old entries into new entries --------------------------------- */ if ( iv->vec == NULL ) { fprintf(stderr, "\n fatal error in IV_setMaxsize(%p,%d)" "\n iv->size = %d, iv->vec is NULL\n", iv, newmaxsize, iv->size) ; exit(-1) ; } if ( iv->size <= newmaxsize ) { /* ----------------------------------------- new maximum size is greater than old size ----------------------------------------- */ IVcopy(iv->size, vec, iv->vec) ; } else { /* ----------------------- note, data is truncated ----------------------- */ IVcopy(newmaxsize, vec, iv->vec) ; iv->size = newmaxsize ; } } if ( iv->vec != NULL ) { /* ---------------- free old entries ---------------- */ IVfree(iv->vec) ; } /* ---------- set fields ---------- */ iv->maxsize = newmaxsize ; iv->owned = 1 ; iv->vec = vec ; } /* fprintf(stdout, "\n %% leaving IV_setMaxsize, iv %p, size %d, maxsize %d, entries %p", iv, iv->size, iv->maxsize, iv->vec) ; fflush(stdout) ; */ return ; } /*--------------------------------------------------------------------*/ /* -------------------------- set the size of the vector created -- 96dec08, cca -------------------------- */ void IV_setSize ( IV *iv, int newsize ) { /* --------------- check the input --------------- */ if ( iv == NULL || newsize < 0 ) { fprintf(stderr, "\n fatal error in IV_setSize(%p,%d)" "\n bad input\n", iv, newsize) ; exit(-1) ; } if ( 0 < iv->maxsize && iv->maxsize < newsize && iv->owned == 0 ) { fprintf(stderr, "\n fatal error in IV_setSize(%p,%d)" "\n iv->maxsize = %d, newsize = %d, iv->owned = %d\n", iv, newsize, iv->maxsize, newsize, iv->owned) ; exit(-1) ; } if ( iv->maxsize < newsize ) { /* ------------------------------------------------------------- new size requested is more than maxsize, set new maximum size ------------------------------------------------------------- */ IV_setMaxsize(iv, newsize) ; } iv->size = newsize ; /* fprintf(stdout, "\n %% leaving IV_setSize, iv %p, size %d, maxsize %d, entries %p", iv, iv->size, iv->maxsize, iv->vec) ; fflush(stdout) ; */ return ; } /*--------------------------------------------------------------------*/ IV/src/instance.c010064400020550007177000000075210657725306300151700ustar00clevecompmath00000400000006/* instance.c */ #include "../IV.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- return value is 0 if the entries are not owned by the object otherwise the return value is the number of entries at the base storage of the vector created -- 96jun22, cca modified -- 96aug28, cca --------------------------------------------------------------- */ int IV_owned ( IV *iv ) { if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_owned(%p)" "\n bad input\n", iv) ; exit(-1) ; } return(iv->owned) ; } /*--------------------------------------------------------------------*/ /* ----------------------- return the vector size created -- 95oct06, cca ----------------------- */ int IV_size ( IV *iv ) { if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_size(%p)" "\n bad input\n", iv) ; exit(-1) ; } return(iv->size) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- return the maximum size of the vector created -- 95dec08, cca ------------------------------------- */ int IV_maxsize ( IV *iv ) { if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_maxsize(%p)" "\n bad input\n", iv) ; exit(-1) ; } return(iv->maxsize) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ return the loc'th entry of a vector. note: if loc is out of range then -1 is returned created -- 96jun29, cca ------------------------------------------------ */ int IV_entry ( IV *iv, int loc ) { if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_entries(%p)" "\n bad input\n", iv) ; exit(-1) ; } if ( loc < 0 || loc >= iv->size ) { return(-1) ; } else { return(iv->vec[loc]) ; } } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return a pointer to the object's entries array created -- 95oct06, cca ---------------------------------------------- */ int * IV_entries ( IV *iv ) { if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_entries(%p)" "\n bad input\n", iv) ; exit(-1) ; } return(iv->vec) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- fill *psize with the vector's size and *pentries with the address of the vector created -- 95oct06, cca -------------------------------------------- */ void IV_sizeAndEntries ( IV *iv, int *psize, int **pentries ) { if ( iv == NULL || psize == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in IV_sizeAndEntries(%p,%p,%p)" "\n bad input\n", iv, psize, pentries) ; exit(-1) ; } *psize = iv->size ; *pentries = iv->vec ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------- set and entry in the vector created -- 96jul14, cca --------------------------- */ void IV_setEntry ( IV *iv, int loc, int value ) { /* --------------- check the input --------------- */ if ( iv == NULL || loc < 0 ) { fprintf(stderr, "\n fatal error in IV_setEntry(%p,%d,%d)" "\n bad input\n", iv, loc, value) ; exit(-1) ; } if ( loc >= iv->maxsize ) { int newmaxsize = (int) 1.25*iv->maxsize ; if ( newmaxsize < 10 ) { newmaxsize = 10 ; } if ( loc >= newmaxsize ) { newmaxsize = loc + 1 ; } IV_setMaxsize(iv, newmaxsize) ; } if ( loc >= iv->size ) { iv->size = loc + 1 ; } iv->vec[loc] = value ; return ; } /*--------------------------------------------------------------------*/ put\n", iv) ; exit(-1) ; } return(iv->maxsize) ; } /*--------------------------------------------------------------------*/ /* -----------------------------------------IV/src/util.c010064400020550007177000000435670656440447500143540ustar00clevecompmath00000400000006/* util.c */ #include "../IV.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- shift the base of the entries and adjust the dimensions note: this is a dangerous operation because the iv->vec does not point to the base of the entries any longer, and thus if the object owns its entries and it is called to resize them or to free them, malloc and free will choke. USE WITH CAUTION! created -- 96aug25, cca modified -- 96aug28, cca structure changed ----------------------------------------------------------- */ void IV_shiftBase ( IV *iv, int offset ) { if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_shiftBase(%p,%d)" "\n bad input\n", iv, offset) ; exit(-1) ; } iv->vec += offset ; iv->size -= offset ; iv->maxsize -= offset ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------- push an entry onto the list created -- 95oct06, cca modified -- 95aug28, cca structure has changed modified -- 96dec08, cca maxsize added to structure ----------------------------- */ void IV_push ( IV *iv, int val ) { if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_push(%p,%d)" "\n bad input\n", iv, val) ; exit(-1) ; } /* fprintf(stdout, "\n %% iv %p, size %d, maxsize %d, entries %p", iv, iv->size, iv->maxsize, iv->vec) ; fflush(stdout) ; */ if ( iv->size == iv->maxsize ) { if ( iv->maxsize == 0 ) { IV_setMaxsize(iv, 10) ; } else { IV_setMaxsize(iv, 2*iv->maxsize) ; } } iv->vec[iv->size++] = val ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------- minimum and maximum entries created -- 95oct06, cca --------------------------- */ int IV_min ( IV *iv ) { int i ; if ( iv == NULL || iv->size <= 0 || iv->vec == NULL ) { fprintf(stderr, "\n fatal error in IV_min(%p), size = %d, vec = %p", iv, iv->size, iv->vec) ; exit(-1) ; } return(IVmin(iv->size, iv->vec, &i)) ; } int IV_max ( IV *iv ) { int i ; if ( iv == NULL || iv->size <= 0 || iv->vec == NULL ) { fprintf(stderr, "\n fatal error in IV_max(%p), size = %d, vec = %p", iv, iv->size, iv->vec) ; exit(-1) ; } return(IVmax(iv->size, iv->vec, &i)) ; } int IV_sum ( IV *iv ) { int i ; if ( iv == NULL || iv->size <= 0 || iv->vec == NULL ) { fprintf(stderr, "\n fatal error in IV_sum(%p), size = %d, vec = %p", iv, iv->size, iv->vec) ; exit(-1) ; } return(IVsum(iv->size, iv->vec)) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- sort each index list into ascending or descending order created -- 95oct06, cca ------------------------------------------------------- */ void IV_sortUp ( IV *iv ) { if ( iv == NULL || iv->size <= 0 || iv->vec == NULL ) { fprintf(stderr, "\n fatal error in IV_sortUp(%p), size = %d, vec = %p", iv, iv->size, iv->vec) ; exit(-1) ; } IVqsortUp(iv->size, iv->vec) ; return ; } void IV_sortDown ( IV *iv ) { if ( iv == NULL || iv->size <= 0 || iv->vec == NULL ) { fprintf(stderr, "\n fatal error in IV_sortDown(%p), size = %d, vec = %p", iv, iv->size, iv->vec) ; exit(-1) ; } IVqsortDown(iv->size, iv->vec) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- ramp the entries created -- 95oct06, cca ----------------------- */ void IV_ramp ( IV *iv, int base, int incr ) { if ( iv == NULL || iv->size <= 0 || iv->vec == NULL ) { fprintf(stderr, "\n fatal error in IV_ramp(%p,%d,%d), size = %d, vec = %p", iv, base, incr, iv->size, iv->vec) ; exit(-1) ; } IVramp(iv->size, iv->vec, base, incr) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- shuffle the list created -- 95oct06, cca ----------------------- */ void IV_shuffle ( IV *iv, int seed ) { if ( iv == NULL || iv->size <= 0 || iv->vec == NULL ) { fprintf(stderr, "\n fatal error in IV_shuffle(%p,%d), size = %d, vec = %p", iv, seed, iv->size, iv->vec) ; exit(-1) ; } IVshuffle(iv->size, iv->vec, seed) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95oct06, cca ---------------------------------------------- */ int IV_sizeOf ( IV *iv ) { int nbytes ; if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_sizeOf(%p)" "\n bad input \n", iv) ; exit(-1) ; } nbytes = sizeof(struct _IV) ; if ( iv->owned == 1 ) { nbytes += iv->maxsize * sizeof(int) ; } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- keep entries that are tagged, move others to end and adjust size created -- 95oct06, cca ---------------------------------------------------------------- */ void IV_filterKeep ( IV *iv, int tags[], int keepTag ) { int i, j, w, size ; int *vec ; /* --------------- check the input --------------- */ if ( iv == NULL || tags == NULL ) { fprintf(stderr, "\n fatal error in IV_filterKeep(%p,%p,%d)" "\n bad input", iv, tags, keepTag) ; exit(-1) ; } size = iv->size ; vec = iv->vec ; /* -------------------------------------------- move untagged entries to the end of the list -------------------------------------------- */ for ( i = 0, j = size ; i < j ; ) { w = vec[i] ; if ( tags[w] != keepTag ) { vec[i] = vec[j-1] ; vec[j-1] = w ; j-- ; } else { i++ ; } } /* ------------------- reset the list size ------------------- */ iv->size = j ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- move purge entries that are tagged to end and adjust size created -- 95oct06, cca --------------------------------------------------------- */ void IV_filterPurge ( IV *iv, int tags[], int purgeTag ) { int i, j, size, w ; int *vec ; /* --------------- check the input --------------- */ if ( iv == NULL || tags == NULL ) { fprintf(stderr, "\n fatal error in IV_filterPurge(%p,%p,%d)" "\n bad input", iv, tags, purgeTag) ; exit(-1) ; } size = iv->size ; vec = iv->vec ; /* -------------------------------------------- move untagged entries to the end of the list -------------------------------------------- */ for ( i = 0, j = size ; i < j ; ) { w = vec[i] ; if ( tags[w] == purgeTag ) { vec[i] = vec[j-1] ; vec[j-1] = w ; j-- ; } else { i++ ; } } /* ------------------- reset the list size ------------------- */ iv->size = j ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- iterator : return the pointer to the head of the vector created -- 95oct06, cca -------------------------------------------- */ int * IV_first ( IV *iv ) { int *pi ; /* --------------- check the input --------------- */ if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_first(%p)" "\n bad input", iv) ; exit(-1) ; } if ( iv->size == 0 ) { pi = NULL ; } else { pi = iv->vec ; } return(pi) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- iterator : return the pointer to the next location in the vector created -- 95oct06, cca ----------------------------------------------------- */ int * IV_next ( IV *iv, int *pi ) { int offset ; /* --------------- check the input --------------- */ if ( iv == NULL || pi == NULL ) { fprintf(stderr, "\n fatal error in IV_next(%p,%p)" "\n bad input", iv, pi) ; fflush(stderr) ; exit(-1) ; } /* --------------- check the input --------------- */ if ( (offset = pi - iv->vec) < 0 || offset >= iv->size ) { /* ----------------------------- error, offset is out of range ----------------------------- */ fprintf(stderr, "\n fatal error in IV_next(%p,%p)" "\n offset = %d, must be in [0,%d)", iv, pi, offset, iv->size) ; fflush(stderr) ; exit(-1) ; } else if ( offset == iv->size - 1 ) { /* ---------------------------- end of the list, return NULL ---------------------------- */ pi = NULL ; } else { /* ---------------------------------------- middle of the list, return next location ---------------------------------------- */ pi++ ; } return(pi) ; } /*--------------------------------------------------------------------*/ /* -------------------------- fill a vector with a value created -- 96jun22, cca -------------------------- */ void IV_fill ( IV *iv, int value ) { /* --------------- check the input --------------- */ if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_fill(%p,%d)" "\n bad input\n", iv, value) ; exit(-1) ; } if ( iv->size > 0 ) { IVfill(iv->size, iv->vec, value) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- copy entries from iv2 into iv1. note: this is a "mapped" copy, iv1 and iv2 need not be the same size. created -- 96aug31, cca -------------------------------------- */ void IV_copy ( IV *iv1, IV *iv2 ) { int ii, size ; int *vec1, *vec2 ; /* --------------- check the input --------------- */ if ( iv1 == NULL || iv2 == NULL ) { fprintf(stderr, "\n fatal error in IV_copy(%p,%p)" "\n bad input\n", iv1, iv2) ; exit(-1) ; } size = iv1->size ; if ( size > iv2->size ) { size = iv2->size ; } vec1 = iv1->vec ; vec2 = iv2->vec ; for ( ii = 0 ; ii < size ; ii++ ) { vec1[ii] = vec2[ii] ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- increment the loc'th location of the vector by one and return the new value created -- 96dec18, cca -------------------------------------------------- */ int IV_increment ( IV *iv, int loc ) { /* --------------- check the input --------------- */ if ( iv == NULL || loc < 0 || loc >= iv->size ) { fprintf(stderr, "\n fatal error in IV_increment(%p,%d)" "\n bad input\n", iv, loc) ; if ( iv != NULL ) { fprintf(stderr, "\n loc = %d, size = %d", loc, iv->size) ; } exit(-1) ; } return(++iv->vec[loc]) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- decrement the loc'th location of the vector by one and return the new value created -- 96dec18, cca -------------------------------------------------- */ int IV_decrement ( IV *iv, int loc ) { /* --------------- check the input --------------- */ if ( iv == NULL || loc < 0 || loc >= iv->size ) { fprintf(stderr, "\n fatal error in IV_decrement(%p,%d)" "\n bad input\n", iv, loc) ; if ( iv != NULL ) { fprintf(stderr, "\n loc = %d, size = %d", loc, iv->size) ; } exit(-1) ; } return(--iv->vec[loc]) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ return the first location in the vector that contains value. if value is not present, -1 is returned. cost is linear in the size of the vector created -- 96jan15, cca ------------------------------------------------------------ */ int IV_findValue ( IV *iv, int value ) { int ii, n ; int *vec ; /* --------------- check the input --------------- */ if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_findValue(%p,%d)" "\n bad input\n", iv, value) ; exit(-1) ; } if ( (n = iv->size) <= 0 || (vec = iv->vec) == NULL ) { return(-1) ; } for ( ii = 0 ; ii < n ; ii++ ) { if ( vec[ii] == value ) { return(ii) ; } } return(-1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- return a location in the vector that contains value. the entries in the vector are assumed to be in ascending order. if value is not present, -1 is returned. cost is logarithmic in the size of the vector created -- 96jan15, cca --------------------------------------------------------------- */ int IV_findValueAscending ( IV *iv, int value ) { int left, mid, n, right ; int *vec ; /* --------------- check the input --------------- */ if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_findValueAscending(%p,%d)" "\n bad input\n", iv, value) ; exit(-1) ; } if ( (n = iv->size) <= 0 || (vec = iv->vec) == NULL ) { return(-1) ; } left = 0 ; right = n - 1 ; if ( vec[left] == value ) { return(left) ; } else if ( vec[right] == value ) { return(right) ; } else { while ( left < right - 1 ) { mid = (left + right)/2 ; if ( vec[mid] == value ) { return(mid) ; } else if ( vec[mid] < value ) { left = mid ; } else { right = mid ; } } } return(-1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- return a location in the vector that contains value. the entries in the vector are assumed to be in descending order. if value is not present, -1 is returned. cost is logarithmic in the size of the vector created -- 96jan15, cca ---------------------------------------------------------------- */ int IV_findValueDescending ( IV *iv, int value ) { int left, mid, n, right ; int *vec ; /* --------------- check the input --------------- */ if ( iv == NULL ) { fprintf(stderr, "\n fatal error in IV_findValueDescending(%p,%d)" "\n bad input\n", iv, value) ; exit(-1) ; } if ( (n = iv->size) <= 0 || (vec = iv->vec) == NULL ) { return(-1) ; } left = 0 ; right = n - 1 ; if ( vec[left] == value ) { return(left) ; } else if ( vec[right] == value ) { return(right) ; } else { while ( left < right - 1 ) { mid = (left + right)/2 ; if ( vec[mid] == value ) { return(mid) ; } else if ( vec[mid] > value ) { left = mid ; } else { right = mid ; } } } return(-1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- return invlistIV, an IV object that contains the inverse map, i.e., invlist[list[ii]] = ii. other entries of invlist[] are -1. all entries in listIV must be nonnegative created -- 98aug12, cca ---------------------------------------------------- */ IV * IV_inverseMap ( IV *listIV ) { int ii, maxval, n ; int *invlist, *list ; IV *invlistIV ; /* --------------- check the input --------------- */ if ( listIV == NULL ) { fprintf(stderr, "\n fatal error in IV_inverseMap()" "\n bad input\n") ; exit(-1) ; } IV_sizeAndEntries(listIV, &n, &list) ; if ( n <= 0 && list == NULL ) { fprintf(stderr, "\n fatal error in IV_inverseMap()" "\n size = %d, list = %p\n", n, list) ; exit(-1) ; } for ( ii = 0, maxval = -1 ; ii < n ; ii++ ) { if ( list[ii] < 0 ) { fprintf(stderr, "\n fatal error in IV_inverseMap()" "\n list[%d] = %d, must be positive\n", ii, list[ii]) ; exit(-1) ; } if ( maxval < list[ii] ) { maxval = list[ii] ; } } invlistIV = IV_new() ; IV_init(invlistIV, 1 + maxval, NULL) ; IV_fill(invlistIV, -1) ; invlist = IV_entries(invlistIV) ; for ( ii = 0 ; ii < n ; ii++ ) { if ( invlist[list[ii]] != -1 ) { fprintf(stderr, "\n fatal error in IV_inverseMap()" "\n repeated list value %d\n", list[ii]) ; exit(-1) ; } invlist[list[ii]] = ii ; } return(invlistIV) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- return an IV object that contains the locations of all instances of target in listIV. this is used when listIV is a map from [0,n) to a finite set (like processors) and we want to find all entries that are mapped to a specific processor. created -- 98aug12, cca ----------------------------------------------------------- */ IV * IV_targetEntries ( IV *listIV, int target ) { int count, ii, n ; int *entries, *list ; IV *entriesIV ; /* --------------- check the input --------------- */ if ( listIV == NULL ) { fprintf(stderr, "\n fatal error in IV_targetEntries()" "\n bad input\n") ; exit(-1) ; } IV_sizeAndEntries(listIV, &n, &list) ; if ( n <= 0 && list == NULL ) { fprintf(stderr, "\n fatal error in IV_targetEntries()" "\n size = %d, list = %p\n", n, list) ; exit(-1) ; } for ( ii = count = 0 ; ii < n ; ii++ ) { if ( list[ii] == target ) { count++ ; } } entriesIV = IV_new() ; if ( count > 0 ) { IV_init(entriesIV, count, NULL) ; entries = IV_entries(entriesIV) ; for ( ii = count = 0 ; ii < n ; ii++ ) { if ( list[ii] == target ) { entries[count++] = ii ; } } } return(entriesIV) ; } /*--------------------------------------------------------------------*/ IV/drivers/makefile010064400020550007177000000004510665314250700155750ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testIO drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testIO : testIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} IV/drivers/testIO.c010064400020550007177000000054370653506335000154560ustar00clevecompmath00000400000006/* testIO.c */ #include "../IV.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------------- test IV_readFromFile and IV_writeToFile, useful for translating between formatted *.ivf and binary *.ivb files. created -- 97dec13, cca ---------------------------------------------- */ { char *inIVFileName, *outIVFileName ; double t1, t2 ; int msglvl, rc ; IV *ivobj ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.ivf or *.ivb" "\n outFile -- output file, must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inIVFileName = argv[3] ; outIVFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inIVFileName, outIVFileName) ; fflush(msgFile) ; /* --------------------- read in the IV object --------------------- */ if ( strcmp(inIVFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } ivobj = IV_new() ; MARKTIME(t1) ; rc = IV_readFromFile(ivobj, inIVFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in iv from file %s", t2 - t1, inIVFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, ivobj, inIVFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading IV object from file %s", inIVFileName) ; if ( msglvl > 2 ) { IV_writeForHumanEye(ivobj, msgFile) ; } else { IV_writeStats(ivobj, msgFile) ; } fflush(msgFile) ; /* ----------------------- write out the IV object ----------------------- */ if ( strcmp(outIVFileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(ivobj, outIVFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write iv to file %s", t2 - t1, outIVFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_writeToFile(%p,%s)", rc, ivobj, outIVFileName) ; } /* ------------------ free the IV object ------------------ */ IV_free(ivobj) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ IV/doc/004275500020550007177000000000000654276740000131735ustar00clevecompmath00000400000006IV/doc/dataStructure.tex010064400020550007177000000015710653410575500165460ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:IV:dataStructure} \par \par The {\tt IV} structure has four fields. \begin{itemize} \item {\tt int size} : present size of the vector. \item {\tt int maxsize} : maximum size of the vector. \item {\tt int owned} : owner flag for the data. When {\tt owned = 1}, storage for {\tt maxsize} {\tt int}'s has been allocated by this object and can be free'd by the object. When {\tt nowned = 0} but {\tt maxsize > 0}, this object points to entries that have been allocated elsewhere, and these entries will not be free'd by this object. \item {\tt int *vec} : pointer to the base address of the {\it int} vector \end{itemize} The {\tt size}, {\tt maxsize}, {\tt owned} and {\tt vec} fields need never be accessed directly --- see the {\tt IV\_size()}, {\tt IV\_maxsize()}, {\tt IV\_owned()}, {\tt IV\_entries()}, {\tt IV\_sizeAndEntries()} methods. IV/doc/intro.tex010064400020550007177000000046210653410575600150470ustar00clevecompmath00000400000006\chapter{{\tt IV}: Integer Vector Object} \par The {\tt IV} object is a wrapper around an {\tt int} vector, thus the acronym {\bf I}nteger {\bf V}ector. The driving force for its creation is more convenience than performance. There are several reasons that led to its development. \begin{itemize} \item Often a method will create a vector (allocate storage for and fill the entries) whose size is not known before the method call. Instead of having a pointer to {\tt int} and a pointer to {\tt int*} in the calling sequence, we can return a pointer to an {\tt IV} object that contains the newly created vector and its size. \item In many cases we need a persistent {\tt int} vector object, and file IO is simplified if we have an object to deal with. The filename is of the form {\tt *.ivf} for a formatted file or {\tt *.ivb} for a binary file. Another case is where an object contains one or more {\tt int} vectors. When they are held as {\tt IV} objects, (e.g., the {\tt ETree} object contains a {\tt Tree} object and three {\tt IV} objects), the method to read and write the object is much cleaner. \item Prototyping can go much faster with this object as opposed to working with an {\tt int} array. Consider the case when one wants to accumulate a list of integers, but one doesn't know how large the list will be. The method {\tt IV\_setSize()} can be used to set the size of the vector to zero. Another method {\tt IV\_push()} appends an element to the vector, growing the storage if necessary. \item Having the size of a vector and a pointer to the base location wrapped together makes it easier to check for valid input inside a method. \item Sometimes an object needs to change its size, i.e., vectors need to grow or shrink. It is easier and more robust to tell an {\tt IV} object to resize itself (see the {\tt IV\_setSize()} and {\tt IV\_setMaxsize()} methods) than it is to duplicate code to work on an {\tt int} vector. \end{itemize} One must choose where to use this object. There is a substantial performance penalty for doing the simplest operations, and so when we need to manipulate an {\tt int} vector inside a loop, we extract out the size and pointer to the base array from the {\tt IV} object. On the other hand, the convenience makes it a widely used object. Originally its use was restricted to reading and writing {\tt *.iv\{f,b\}} files, but now {\tt IV} objects appear much more frequently in new development. \par IV/doc/main.tex010064400020550007177000000010650665065624500146420ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt IV} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt IV} : {\it DRAFT} \quad \today \hrulefill} \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} IV/doc/proto.tex010064400020550007177000000645260665016375100150670ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt IV} methods} \label{section:IV:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt IV} object. \par \subsection{Basic methods} \label{subsection:IV:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IV * IV_new ( void ) ; \end{verbatim} \index{IV_new@{\tt IV\_new()}} This method simply allocates storage for the {\tt IV} structure and then sets the default fields by a call to {\tt IV\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_setDefaultFields ( IV *iv ) ; \end{verbatim} \index{IV_setDefaultFields@{\tt IV\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt size} = {\tt maxsize} = {\tt owned} = 0 and {\tt vec} = {\tt NULL} . \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_clearData ( IV *iv ) ; \end{verbatim} \index{IV_clearData@{\tt IV\_clearData()}} This method clears any data owned by the object. If {\tt vec} is not {\tt NULL} and {\tt owned = 1}, then the storage for {\tt vec} is free'd by a call to {\tt IVfree()}. The structure's default fields are then set with a call to {\tt IV\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_free ( IV *iv ) ; \end{verbatim} \index{IV_free@{\tt IV\_free()}} This method releases any storage by a call to {\tt IV\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:IV:proto:Instance} \par These method allow access to information in the data fields without explicitly following pointers. There is overhead involved with these method due to the function call and error checking inside the methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int IV_owned ( IV *iv ) ; \end{verbatim} \index{IV_owned@{\tt IV\_owned()}} This method returns the value of {\tt owned}. If {\tt owned = 1}, then the object owns the data pointed to by {\tt vec} and will free this data with a call to {\tt IVfree()} when its data is cleared by a call to {\tt IV\_free()} or {\tt IV\_clearData()}. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_size ( IV *iv ) ; \end{verbatim} \index{IV_size@{\tt IV\_size()}} This method returns the value of {\tt size}, the present size of the vector. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_maxsize ( IV *iv ) ; \end{verbatim} \index{IV_maxsize@{\tt IV\_maxsize()}} This method returns the value of {\tt maxsize}, the maximum size of the vector. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_entry ( IV *iv, int loc ) ; \end{verbatim} \index{IV_entry@{\tt IV\_entry()}} This method returns the value of the {\tt loc}'th entry in the vector. If {\tt loc < 0} or {\tt loc >= size}, i.e., if the location is out of range, we return {\tt -1}. This design {\tt feature} is handy when a list terminates with a {\tt -1} value. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * IV_entries ( IV *iv ) ; \end{verbatim} \index{IV_entries@{\tt IV\_entries()}} This method returns {\tt vec}, a pointer to the base address of the vector. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_sizeAndEntries ( IV *iv, int *psize, int **pentries ) ; \end{verbatim} \index{IV_sizeAndEntries@{\tt IV\_sizeAndEntries()}} This method fills {\tt *psize} with the size of the vector and {\tt *pentries} with the base address of the vector. \par \noindent {\it Error checking:} If {\tt iv}, {\tt psize} or {\tt pentries} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_setEntry ( IV *iv, int loc, int value ) ; \end{verbatim} \index{IV_setEntry@{\tt IV\_setEntry()}} This method sets the {\tt loc}'th entry of the vector to {\tt value}. \par \noindent {\it Error checking:} If {\tt iv}, {\tt loc < 0} or {\tt loc >= size}, or if {\tt vec} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:IV:proto:initializers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void IV_init ( IV *iv, int size, int *entries ) ; \end{verbatim} \index{IV_init@{\tt IV\_init()}} This method initializes the object given a size for the vector and a possible pointer to the vectors storage. Any previous data with a call to {\tt IV\_clearData()}. If {\tt entries != NULL} then the {\tt vec} field is set to {\tt entries}, the {\tt size} and {\tt maxsize} fields are set to {\tt size} , and {\tt owned} is set to zero because the object does not own the entries. If {\tt entries} is {\tt NULL} and if {\tt size > 0} then a vector is allocated by the object, and the object owns this storage. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL} or {\tt size < 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_init1 ( IV *iv, int size ) ; \end{verbatim} \index{IV_init1@{\tt IV\_init1()}} This method initializes the object given a size for the vector. Any previous data is cleared with a call to {\tt IV\_clearData()}. Then {\tt size} and {\tt maxsize} are set to {\tt size}. If {\tt size > 0}, then the vector is created via a call to {\tt IVinit()} and {\tt owned} is set to {\tt 1}. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL} or {\tt size < 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_init2 ( IV *iv, int size, int maxsize, int owned, int *vec ) ; \end{verbatim} \index{IV_init2@{\tt IV\_init2()}} This is the total initialization method. Any previous data is cleared with a call to {\tt IV\_clearData()}. If {\tt vec} is {\tt NULL}, the object is initialized via a call to {\tt IV\_init1()}. Otherwise, the object's remaining fields are set to the input parameters. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL} or {\tt maxsize < 0} or {\tt size < 0}, or if {\tt owned} is not equal to {\tt 0} or {\tt 1}, or if {\tt owned = 0} and {\tt vec == NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_setMaxsize ( IV *iv, int newmaxsize ) ; \end{verbatim} \index{IV_setMaxsize@{\tt IV\_setMaxsize()}} This method sets the maximum size of the vector. If {\tt maxsize}, the present maximum size, is not equal to {\tt newmaxsize}, then new storage is allocated. Only {\tt size} entries of the old data are copied into the new storage, so if {\tt size > newmaxsize} then data will be lost. The {\tt size} field is set to the minimum of {\tt size} and {\tt newmaxsize}. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL} or {\tt newmaxsize < 0}, or if {\tt 0 < maxsize} and {\tt owned == 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_setSize ( IV *iv, int newsize ) ; \end{verbatim} \index{IV_setSize@{\tt IV\_setSize()}} This method sets the size of the vector. If {\tt newsize > maxsize}, the length of the vector is increased with a call to {\tt IV\_setMaxsize()}. The {\tt size} field is set to {\tt newsize}. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL} or {\tt newsize < 0}, or if {\tt 0 < maxsize < newsize} and {\tt owned == 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:IV:proto:utilities} \par \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void IV_shiftBase ( IV *iv, int offset ) ; \end{verbatim} \index{IV_shiftBase@{\tt IV\_shiftBase()}} This method shifts the base entries of the vector and decrements the present size and maximum size of the vector by {\tt offset}. This is a dangerous method to use because the state of the vector is lost, namely {\tt vec}, the base of the entries, is corrupted. If the object owns its entries and {\tt IV\_free()}, {\tt IV\_setSize()} or {\tt IV\_setMaxsize()} is called before the base has been shifted back to its original position, a segmentation violation will likely result. This is a very useful method, but use with caution. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_push ( IV *iv, int val ) ; \end{verbatim} \index{IV_push@{\tt IV\_push()}} This method pushes an entry onto the vector. If the vector is full, i.e., if {\tt size = maxsize - 1}, then the size of the vector is doubled if possible. If the storage cannot grow, i.e., if the object does not own its storage, an error message is printed and the program exits. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_min ( IV *iv ) ; int IV_max ( IV *iv ) ; \end{verbatim} \index{IV_min@{\tt IV\_min()}} \index{IV_max@{\tt IV\_max()}} These methods simply return the minimum and maximum entries in the vector. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, {\tt size <= 0} or if {\tt vec == NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_sortUp ( IV *iv ) ; void IV_sortDown ( IV *iv ) ; \end{verbatim} \index{IV_sortUp@{\tt IV\_sortUp()}} \index{IV_sortDown@{\tt IV\_sortDown()}} This method sorts the entries in the vector into ascending or descending order via calls to {\tt IVqsortUp()} and {\tt IVqsortDown()}. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, {\tt size <= 0} or if {\tt vec == NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_ramp ( IV *iv, int base, int incr ) ; \end{verbatim} \index{IV_ramp@{\tt IV\_ramp()}} This method fill the object with a ramp vector, i.e., entry {\tt i} is {\tt base + i*incr}. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, {\tt size <= 0} or if {\tt vec == NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_shuffle ( IV *iv, int seed ) ; \end{verbatim} \index{IV_shuffle@{\tt IV\_shuffle()}} This method shuffles the entries in the vector using {\tt seed} as a seed to a random number generator. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, {\tt size <= 0} or if {\tt vec == NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_sizeOf ( IV *iv ) ; \end{verbatim} \index{IV_sizeOf@{\tt IV\_sizeOf()}} This method returns the number of bytes taken by the object. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_filterKeep ( IV *iv, int tags[], int keepTag ) ; \end{verbatim} \index{IV_filterKeep@{\tt IV\_filterKeep()}} This method examines the entries in the vector. Let {\tt k} be entry {\tt i} in the vector. If {\tt tags[k] != keepTag}, the entry is moved to the end of the vector, otherwise it is moved to the beginning of the vector. The size of the vector is reset to be the number of tagged entries that are now in the leading locations. \par \noindent {\it Error checking:} If {\tt iv} of {\tt tags} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_filterPurge ( IV *iv, int tags[], int purgeTag ) ; \end{verbatim} \index{IV_filterPurge@{\tt IV\_filterPurge()}} This method examines the entries in the vector. Let {\tt k} be entry {\tt i} in the vector. If {\tt tags[k] == purgeTag}, the entry is moved to the end of the vector, otherwise it is moved to the beginning of the vector. The size of the vector is reset to be the number of untagged entries that are now in the leading locations. \par \noindent {\it Error checking:} If {\tt iv} of {\tt tags} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * IV_first ( IV *iv ) ; int * IV_next ( IV *iv, int *pi ) ; \end{verbatim} \index{IV_first@{\tt IV\_first()}} \index{IV_next@{\tt IV\_next()}} These two methods are used as iterators, e.g., \begin{verbatim} for ( pi = IV_first(iv) ; pi != NULL ; pi = IV_next(iv, pi) ) { do something with entry *pi } \end{verbatim} \par \noindent {\it Error checking:} Each method checks to see if {\tt iv} or {\tt pi} is {\tt NULL}. If so an error message is printed and the program exits. In method {\tt IV\_first()}, if {\tt pi} is not in the valid range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_fill ( IV *iv, int value ) ; \end{verbatim} \index{IV_fill@{\tt IV\_fill()}} This method fills the vector with a scalar value. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_copy ( IV *iv1, IV *iv2 ) ; \end{verbatim} \index{IV_copy@{\tt IV\_copy()}} This method fills the {\tt iv1} object with entries in the {\tt iv2} object. Note, this is a {\it mapped} copy, {\tt iv1} and {\tt iv2} need not have the same size. The number of entries that are copied is the smaller of the two sizes. \par \noindent {\it Error checking:} If {\tt iv1} or {\tt iv2} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_increment ( IV *iv, int loc ) ; \end{verbatim} \index{IV_increment@{\tt IV\_increment()}} This method increments the {\tt loc}'th location of the {\tt iv} object by one and returns the new value. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL} or if {\tt loc} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_decrement ( IV *iv, int loc ) ; \end{verbatim} \index{IV_decrement@{\tt IV\_decrement()}} This method decrements the {\tt loc}'th location of the {\tt iv} object by one and returns the new value. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL} or if {\tt loc} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_findValue ( IV *iv, int value ) ; \end{verbatim} \index{IV_findValue@{\tt IV\_findValue()}} This method looks for {\tt value} in its entries. If {\tt value} is present, the first location is returned, otherwise {\tt -1} is returned. The cost is linear in the number of entries. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_findValueAscending ( IV *iv, int value ) ; \end{verbatim} \index{IV_findValueAscending@{\tt IV\_findValueAscending()}} This method looks for {\tt value} in its entries. If {\tt value} is present, a location is returned, otherwise {\tt -1} is returned. This method assumes that the entries are sorted in ascending order. The cost is logarthmic in the number of entries. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_findValueDescending ( IV *iv, int value ) ; \end{verbatim} \index{IV_findValueDescending@{\tt IV\_findValueDescending()}} This method looks for {\tt value} in its entries. If {\tt value} is present, a location is returned, otherwise {\tt -1} is returned. This method assumes that the entries are sorted in descending order. The cost is logarthmic in the number of entries. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * IV_inverseMap ( IV *listIV ) ; \end{verbatim} \index{IV_inverseMap@{\tt IV\_inverseMap()}} This method creates and returns an inverse map for a list of nonnegative integers. This function is used when {\tt listIV} contains a list of global ids and we need a map from the global ids to their location in the list. The size of the returned {\tt IV} object is equal to one plus the largest value found in {\tt listIV}. If {\tt value} is not found in {\tt listIV}, then the corresponding entry in the returned {\tt IV} object is -1. \par \noindent {\it Error checking:} If {\tt listIV} is {\tt NULL}, or if its size if zero or less or if its entries are {\tt NULL}, or if one of its entries is negative, or if any entry in listIV is repeated, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * IV_targetEntries ( IV *listIV ) ; \end{verbatim} \index{IV_targetEntries@{\tt IV\_targetEntries()}} This method creates and returns a list of locations where {\tt target} is found in {\tt listIV} . \par \noindent {\it Error checking:} If {\tt listIV} is {\tt NULL}, or if its size if zero or less or if its entries are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:IV:proto:IO} \par There are the usual eight IO routines. The file structure of an {\tt IV} object is simple: the first entry is {\tt size}, followed by the {\tt size} entries found in {\tt vec[]}. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int IV_readFromFile ( IV *iv, char *fn ) ; \end{verbatim} \index{IV_readFromFile@{\tt IV\_readFromFile()}} \par This method reads an {\tt IV} object from a formatted file. It tries to open the file and if it is successful, it then calls {\tt IV\_readFromFormattedFile()} or {\tt IV\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt iv} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.ivf} (for a formatted file) or {\tt *.ivb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_readFromFormattedFile ( IV *iv, FILE *fp ) ; \end{verbatim} \index{IV_readFromFormattedFile@{\tt IV\_readFromFormattedFile()}} \par This method reads in an {\tt IV} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt iv} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_readFromBinaryFile ( IV *iv, FILE *fp ) ; \end{verbatim} \index{IV_readFromBinaryFile@{\tt IV\_readFromBinaryFile()}} \par This method reads in an {\tt IV} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt iv} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_writeToFile ( IV *iv, char *fn ) ; \end{verbatim} \index{IV_writeToFile@{\tt IV\_writeToFile()}} \par This method writes an {\tt IV} object to a formatted file. It tries to open the file and if it is successful, it then calls {\tt IV\_writeFromFormattedFile()} or {\tt IV\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt iv} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.ivf} (for a formatted file) or {\tt *.ivb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_writeToFormattedFile ( IV *iv, FILE *fp ) ; \end{verbatim} \index{IV_writeToFormattedFile@{\tt IV\_writeToFormattedFile()}} \par This method writes an {\tt IV} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt iv} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_writeToBinaryFile ( IV *iv, FILE *fp ) ; \end{verbatim} \index{IV_writeToBinaryFile@{\tt IV\_writeToBinaryFile()}} \par This method writes an {\tt IV} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt iv} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_writeForHumanEye ( IV *iv, FILE *fp ) ; \end{verbatim} \index{IV_writeForHumanEye@{\tt IV\_writeForHumanEye()}} \par This method writes an {\tt IV} object to a file in a human readable format. The method {\tt IV\_writeStats()} is called to write out the header and statistics. The entries of the vector then follow in eighty column format using the {\tt IVfp80()} method. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt iv} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_writeStats ( IV *iv, FILE *fp ) ; \end{verbatim} \index{IV_writeStats@{\tt IV\_writeStats()}} \par This method writes the header and statistics to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt iv} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_fp80 ( IV *iv, FILE *fp, int column, int *pierr ) ; \end{verbatim} \index{IV_fp80@{\tt IV\_fp80()}} \par This method is just a wrapper around the {\tt IVfp80()} method for an {\tt int} method. The entries in the vector are found on lines with eighty columns and are separated by a whitespace. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt iv} or {\tt fp} or {\tt pierr} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IV_writeForMatlab ( IV *iv, char *name, FILE *fp ) ; \end{verbatim} \index{IV_writeForMatlab@{\tt IV\_writeForMatlab()}} \par This method writes the entries of the vector to a file suitable to be read by Matlab. The character string {\tt name} is the name of the vector, e.g, if {\tt name = "A"}, then we have lines of the form \begin{verbatim} A(1) = 32 ; A(2) = -433 ; ... \end{verbatim} for each entry in the vector. Note, the output indexing is 1-based, not 0-based. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt iv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} tion of the {\tt iv} object by one and returns the new value. \par \noindent {\it Error checking:} If {\tt iv} is {\tt NULL} or if {\tt loc} is out of range, an error meIV/doc/main.log010064400020550007177000000037560653506302400146210ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 2 JUN 1998 13:52 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. ) (dataStructure.tex [1 ]) (proto.tex [2] [3] Overfull \hbox (18.7287pt too wide) in paragraph at lines 208--214 []\elvrm This is the to-tal ini-tial-iza-tion method. Any pre-vi-ous data is cl eared with a call to \elvtt IV[]clearData()\elvrm . \hbox(7.60416+2.12917)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\elvrm T .\elvrm h .\elvrm i .\elvrm s .etc. [4] [5] [6] [7] Overfull \hbox (28.58224pt too wide) in paragraph at lines 600--607 []\elvrm This method writes an \elvtt IV \elvrm ob-ject to a file in a hu-man r ead-able for-mat. The method \elvtt IV[]writeStats() \hbox(7.60416+2.12917)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\elvrm T .\elvrm h .\elvrm i .\elvrm s .etc. ) (drivers.tex [8]) (main.ind [9] [10 ]) (main.aux) ) Here is how much of TeX's memory you used: 209 strings out of 11977 2165 string characters out of 87269 33504 words of memory out of 262141 2143 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 14i,5n,17p,179b,226s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (10 pages, 29420 bytes). (/usr/local/lib/IV/doc/main.aux010064400020550007177000000030420653506302400146210ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space IV}: Integer Vector Object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{2}} \newlabel{section:IV:dataStructure}{{1.1}{2}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space IV} methods}{2}} \newlabel{section:IV:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:IV:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Instance methods}{3}} \newlabel{subsection:IV:proto:Instance}{{1.2.2}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Initializer methods}{4}} \newlabel{subsection:IV:proto:initializers}{{1.2.3}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}Utility methods}{4}} \newlabel{subsection:IV:proto:utilities}{{1.2.4}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.5}IO methods}{7}} \newlabel{subsection:IV:proto:IO}{{1.2.5}{7}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs for the {\string\ptt\space IV object}}{8}} \newlabel{section:IV:drivers}{{1.3}{8}} IV/doc/main.ind010064400020550007177000000027440653506252300146110ustar00clevecompmath00000400000006\begin{theindex} \item {\tt IV\_clearData()}, 2 \item {\tt IV\_copy()}, 6 \item {\tt IV\_decrement()}, 6 \item {\tt IV\_entries()}, 3 \item {\tt IV\_entry()}, 3 \item {\tt IV\_fill()}, 6 \item {\tt IV\_filterKeep()}, 5 \item {\tt IV\_filterPurge()}, 6 \item {\tt IV\_findValue()}, 7 \item {\tt IV\_findValueAscending()}, 7 \item {\tt IV\_findValueDescending()}, 7 \item {\tt IV\_first()}, 6 \item {\tt IV\_fp80()}, 8 \item {\tt IV\_free()}, 2 \item {\tt IV\_increment()}, 6 \item {\tt IV\_init()}, 4 \item {\tt IV\_init1()}, 4 \item {\tt IV\_init2()}, 4 \item {\tt IV\_max()}, 5 \item {\tt IV\_maxsize()}, 3 \item {\tt IV\_min()}, 5 \item {\tt IV\_new()}, 2 \item {\tt IV\_next()}, 6 \item {\tt IV\_owned()}, 3 \item {\tt IV\_push()}, 5 \item {\tt IV\_ramp()}, 5 \item {\tt IV\_readFromBinaryFile()}, 7 \item {\tt IV\_readFromFile()}, 7 \item {\tt IV\_readFromFormattedFile()}, 7 \item {\tt IV\_setDefaultFields()}, 2 \item {\tt IV\_setEntry()}, 3 \item {\tt IV\_setMaxsize()}, 4 \item {\tt IV\_setSize()}, 4 \item {\tt IV\_shiftBase()}, 4 \item {\tt IV\_shuffle()}, 5 \item {\tt IV\_size()}, 3 \item {\tt IV\_sizeAndEntries()}, 3 \item {\tt IV\_sizeOf()}, 5 \item {\tt IV\_sortDown()}, 5 \item {\tt IV\_sortUp()}, 5 \item {\tt IV\_writeForHumanEye()}, 8 \item {\tt IV\_writeStats()}, 8 \item {\tt IV\_writeToBinaryFile()}, 8 \item {\tt IV\_writeToFile()}, 7 \item {\tt IV\_writeToFormattedFile()}, 8 \end{theindex} IV/doc/main.idx010064400020550007177000000043410653506302400146130ustar00clevecompmath00000400000006\indexentry{IV_new@{\tt IV\_new()}}{2} \indexentry{IV_setDefaultFields@{\tt IV\_setDefaultFields()}}{2} \indexentry{IV_clearData@{\tt IV\_clearData()}}{2} \indexentry{IV_free@{\tt IV\_free()}}{2} \indexentry{IV_owned@{\tt IV\_owned()}}{3} \indexentry{IV_size@{\tt IV\_size()}}{3} \indexentry{IV_maxsize@{\tt IV\_maxsize()}}{3} \indexentry{IV_entry@{\tt IV\_entry()}}{3} \indexentry{IV_entries@{\tt IV\_entries()}}{3} \indexentry{IV_sizeAndEntries@{\tt IV\_sizeAndEntries()}}{3} \indexentry{IV_setEntry@{\tt IV\_setEntry()}}{3} \indexentry{IV_init@{\tt IV\_init()}}{4} \indexentry{IV_init1@{\tt IV\_init1()}}{4} \indexentry{IV_init2@{\tt IV\_init2()}}{4} \indexentry{IV_setMaxsize@{\tt IV\_setMaxsize()}}{4} \indexentry{IV_setSize@{\tt IV\_setSize()}}{4} \indexentry{IV_shiftBase@{\tt IV\_shiftBase()}}{4} \indexentry{IV_push@{\tt IV\_push()}}{5} \indexentry{IV_min@{\tt IV\_min()}}{5} \indexentry{IV_max@{\tt IV\_max()}}{5} \indexentry{IV_sortUp@{\tt IV\_sortUp()}}{5} \indexentry{IV_sortDown@{\tt IV\_sortDown()}}{5} \indexentry{IV_ramp@{\tt IV\_ramp()}}{5} \indexentry{IV_shuffle@{\tt IV\_shuffle()}}{5} \indexentry{IV_sizeOf@{\tt IV\_sizeOf()}}{5} \indexentry{IV_filterKeep@{\tt IV\_filterKeep()}}{5} \indexentry{IV_filterPurge@{\tt IV\_filterPurge()}}{6} \indexentry{IV_first@{\tt IV\_first()}}{6} \indexentry{IV_next@{\tt IV\_next()}}{6} \indexentry{IV_fill@{\tt IV\_fill()}}{6} \indexentry{IV_copy@{\tt IV\_copy()}}{6} \indexentry{IV_increment@{\tt IV\_increment()}}{6} \indexentry{IV_decrement@{\tt IV\_decrement()}}{6} \indexentry{IV_findValue@{\tt IV\_findValue()}}{7} \indexentry{IV_findValueAscending@{\tt IV\_findValueAscending()}}{7} \indexentry{IV_findValueDescending@{\tt IV\_findValueDescending()}}{7} \indexentry{IV_readFromFile@{\tt IV\_readFromFile()}}{7} \indexentry{IV_readFromFormattedFile@{\tt IV\_readFromFormattedFile()}}{7} \indexentry{IV_readFromBinaryFile@{\tt IV\_readFromBinaryFile()}}{7} \indexentry{IV_writeToFile@{\tt IV\_writeToFile()}}{7} \indexentry{IV_writeToFormattedFile@{\tt IV\_writeToFormattedFile()}}{8} \indexentry{IV_writeToBinaryFile@{\tt IV\_writeToBinaryFile()}}{8} \indexentry{IV_writeForHumanEye@{\tt IV\_writeForHumanEye()}}{8} \indexentry{IV_writeStats@{\tt IV\_writeStats()}}{8} \indexentry{IV_fp80@{\tt IV\_fp80()}}{8} IV/doc/main.ilg010064400020550007177000000004570653506252300146110ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (45 entries accepted, 0 rejected). Sorting entries....done (259 comparisons). Generating output file main.ind....done (49 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. IV/doc/drivers.tex010064400020550007177000000030270653506264200153660ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt IV object}} \label{section:IV:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program tests the {\tt IV} IO methods, and is useful for translating between the formatted {\tt *.ivf} and binary {\tt *.ivb} files. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the name of the file from which to read in the object. {\tt inFile} must be of the form {\tt *.ivf} for a formatted file or {\tt *.ivb} for a binary file. \item The {\tt outFile} parameter is the name of the file to which to write out the object. If {\tt outfile} is of the form {\tt *.ivf}, the object is written to a formatted file. If {\tt outfile} is of the form {\tt *.ivb}, the object is written to a binary file. When {\tt outFile} is {\it not} {\tt "none"}, the object is written to the file in a human readable format. When {\tt outFile} is {\tt "none"}, the object is not written out. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} IV/doc/makefile010064400020550007177000000000270654276740000146650ustar00clevecompmath00000400000006clean : - rm -f *.dvi IVL.h010064400020550007177000000000700653410636700127030ustar00clevecompmath00000400000006#ifndef _IVL_ #define _IVL_ #include "IVL/IVL.h" #endif IVL/IVL.h010064400020550007177000000537020661166124100133400ustar00clevecompmath00000400000006/* IVL.h */ #include "../IV.h" #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- The IVL object stores and manipulates Lists of Int Vectors, so the acronym for Integer Vector Lists. The most common use of an IVL object is to represent a graph or the adjacency structure of a matrix. The IVL object supports the following functionality. 1. initialization, # of lists must be known. 2. clearing data and free'ing the object 3. set the size of a list and/or its entries 4. un-setting a list or releasing its data 5. returning the min or max entry in all the lists 6. returning the maximum size of a list The number of lists is fixed on initialization, but the number of entries in any list or the total size of the lists need not be known at initialization. Storage for the lists is handled in one of three ways. 1. chunked (IVL_CHUNKED = 1) A chunk of data is allocated by the object and lists point to data in the chunk. When the free space is not large enough to contain a new list, another chunk is allocated. The object keeps track of the chunks and free's all the storage when requested. 2. solo (IVL_SOLO = 2) Each list is allocated separately using the IVinit() or IVinit2() function. When requested, each list is free'd using the IVfree() function. 3. unknown (IVL_UNKNOWN = 3) Each list points to storage somewhere but the object does not keep track of any storage to be free'd. The application that gave rise to this storage mode has a subgraph "share" list storage with the larger graph that contains it. it made no sense to replicate the storage for a very large graph just to instantiate a subgraph. when the subgraph was free'd, it did not release any storage owned by the parent graph. created -- 95sep22, cca --------------------------------------------------------------------- */ /*--------------------------------------------------------------------*/ /* -------------------------------------- typedef for the IVL and Ichunk objects -------------------------------------- */ typedef struct _IVL IVL ; typedef struct _Ichunk Ichunk ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- type -- type of integer vector list IVL_NOTYPE -- no type IVL_CHUNKED -- list are in possibly many chunks of data IVL_SOLO -- each list is created using IVinit() and free'd using IVfree() IVL_UNKNOWN -- storage for lists unknown, it is the user's responsibility maxnlist -- maximum number of lists nlist -- number of lists tsize -- total size of the lists sizes -- vector of list sizes, size nlist p_vec -- vector of list pointers, size nlist incr -- increment for chunks, number of entries allocated when a new chunk is necessary, used only when type = IVL_CHUNKED chunk -- first Ichunk structure, NULL unless type = IVL_CHUNKED ------------------------------------------------------------- */ struct _IVL { int type ; int maxnlist ; int nlist ; int tsize ; int *sizes ; int **p_vec ; int incr ; Ichunk *chunk ; } ; /* ------------------------------------------------------- the Ichunk object is the data structure that handles chunks of storage for mode IVL_CHUNKED size -- number of entries in the chunk, also the dimension of the array base[] inuse -- the number of entries in use, size - inuse is the number of free entries base -- base address for storage used for list entries next -- pointer to the next Ichunk object ------------------------------------------------------- */ struct _Ichunk { int size ; int inuse ; int *base ; Ichunk *next ; } ; /*--------------------------------------------------------------------*/ /* ---------------------------- definitions for storage type ---------------------------- */ #define IVL_NOTYPE (-1) #define IVL_CHUNKED 1 #define IVL_SOLO 2 #define IVL_UNKNOWN 3 #define IVL_INCR 1024 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ --- procedures found in basics.c ----------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 95sep22, cca ----------------------- */ IVL * IVL_new ( void ) ; /* ----------------------- set the default fields created -- 95sep22, cca ----------------------- */ void IVL_setDefaultFields ( IVL *ivl ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 95sep22, cca -------------------------------------------------- */ void IVL_clearData ( IVL *ivl ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 95sep22, cca ------------------------------------------ */ IVL * IVL_free ( IVL *ivl ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ --- procedures found in instance.c --------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------- return the storage type of the object created -- 96dec06, cca ------------------------------------- */ int IVL_type ( IVL *ivl ) ; /* ---------------------------------- return the maximum number of lists created -- 96dec06, cca ---------------------------------- */ int IVL_maxnlist ( IVL *ivl ) ; /* -------------------------- return the number of lists created -- 96dec06, cca -------------------------- */ int IVL_nlist ( IVL *ivl ) ; /* ---------------------------------- return the total size of the lists created -- 96dec06, cca ---------------------------------- */ int IVL_tsize ( IVL *ivl ) ; /* ---------------------------- return the storage increment created -- 96dec06, cca ---------------------------- */ int IVL_incr ( IVL *ivl ) ; /* ------------------------- set the storage increment created -- 96dec06, cca ------------------------- */ void IVL_setincr ( IVL *ivl, int incr ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ --- procedures found in init.c ------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------ initialize given the type and maximum number of lists. used for type IVL_CHUNKED, IVL_SOLO or IVL_UNKNOWN created -- 95sep22, cca ------------------------------------------------------ */ void IVL_init1 ( IVL *ivl, int type, int maxnlist ) ; /* --------------------------------------------------------------- initialize given the type, number of lists and their total size only used when type is IVL_CHUNKED. created -- 95sep22, cca --------------------------------------------------------------- */ void IVL_init2 ( IVL *ivl, int type, int maxnlist, int tsize ) ; /* -------------------------------------- initialize from a vector of list sizes. used with IVL_SOLO or IVL_CHUNKED. created -- 95sep22, cca -------------------------------------- */ void IVL_init3 ( IVL *ivl, int type, int maxnlist, int sizes[] ) ; /* ------------------------------------------------ this method resizes the maximum number of lists, replacing the old sizes[] and p_vec[] vectors as necessary. the nlist value is NOT reset. created -- 96dec05, cca ------------------------------------------------ */ void IVL_setMaxnlist ( IVL *ivl, int newmaxnlist ) ; /* ------------------------------------------------ this method resizes the number of lists, replacing the old sizes[] and p_vec[] vectors as necessary. created -- 96dec05, cca ------------------------------------------------ */ void IVL_setNlist ( IVL *ivl, int newnlist ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ --- procedures found in subIVL.c ----------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------------------- purpose -- initialize subIVL from ivl if keeplistIV is not NULL then keeplistIV contains the lists of ivl to be placed in subIVL else all lists are placed in subIVL endif if keepentriesIV is not NULL then keepentriesIV contains the entries in the lists to be kept else all entries in the kept lists are placed in subIVL endif return value --- 1 -- normal return -1 -- subIVL is NULL -2 -- ivl is NULL -3 -- keeplistIV is invalid created -- 98oct16, cca ---------------------------------------------------------------- */ int IVL_initFromSubIVL ( IVL *subIVL, IVL *ivl, IV *keeplistIV, IV *keepentriesIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ --- procedures found in listmanip.c -------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------------------- fills size of and pointer to the entries of a list set *psize = size of list ilist set *pivec = base address of list ilist use as follows : IVL_listAndSize(ivl, ilist, &isize, &ivec) ; for ( i = 0 ; i < isize ; i++ ) ; do something with ivec[i] ; } created -- 95sep22, cca ---------------------------------------------------------------- */ void IVL_listAndSize ( IVL *ivl, int ilist, int *psize, int **pivec ) ; /* ---------------------------------------------------- returns a pointer to the first element in list ilist to be used as a general iterator, e.g., for ( pi = IVL_firstInList(ivl, ilist) ; pi != NULL ; pi = IVL_nextInList(ivl, ilist, pi) ) ; do something ; } created -- 95sep27, cca ---------------------------------------------------- */ int * IVL_firstInList ( IVL *ivl, int ilist ) ; /* ---------------------------------------------------- returns a pointer to the next element in list ilist to be used as a general iterator, e.g., for ( pi = IVL_firstInList(ivl, ilist) ; pi != NULL ; pi = IVL_nextInList(ivl, ilist, pi) ) ; do something ; } created -- 95sep27, cca ---------------------------------------------------- */ int * IVL_nextInList ( IVL *ivl, int ilist, int *pi ) ; /* ----------------------------------------------------------------- purpose -- to set or reset a list. ilist -- list id to set or reset isize -- size of the list if the present size of list ilist is smaller than isize, the old list is free'd (if ivl->type = IVL_SOLO) or lost (if ivl->type = IVL_CHUNKED) or un-set (if ivl->type = IVL_UNKNOWN) and new storage is allocated (for IVL_SOLO and IVL_CHUNKED) ivec -- list vector if ivl->type is IVL_UNKNOWN then if ivec != NULL then we set the ivl list pointer to be ivec endif else if ivec != NULL we copy ivec[] into ivl's storage for the list endif created -- 95sep27, cca last mods -- 95oct06, cca type = IVL_UNKNOWN, p_vec[ilist] set to ivec only when ivec is not NULL bug fixed, ivl->sizes[ilist] = isize ; ----------------------------------------------------------------- */ void IVL_setList ( IVL *ivl, int ilist, int isize, int ivec[] ) ; /* ---------------------------------------------------------------- set a pointer to a list but don't allocate storage for the list. this method was needed when we form a subgraph with a boundary. lists for the interior vertices point into the parent graph, but lists for the boundary vertices must be allocated and owned. used only for type = IVL_CHUNKED. at some point in the future we should rethink the storage semantics for the IVL object. created -- 95nov11, cca ---------------------------------------------------------------- */ void IVL_setPointerToList ( IVL *ivl, int ilist, int isize, int ivec[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ --- procedures found in misc.c ------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- purpose -- to make and return a 9-point adjacency structure input -- n1 -- # of grid points in first direction n2 -- # of grid points in second direction ncomp -- # of components per grid point ----------------------------------------------------------- */ IVL * IVL_make9P ( int n1, int n2, int ncomp ) ; /* ------------------------------------------------------------ purpose -- to make and return a 27-point adjacency structure input -- n1 -- # of grid points in first direction n2 -- # of grid points in second direction n3 -- # of grid points in second direction ncomp -- # of components per grid point ------------------------------------------------------------ */ IVL * IVL_make27P ( int n1, int n2, int n3, int ncomp ) ; /* ------------------------------------------------------------ purpose -- to make and return a 13-point adjacency structure input -- n1 -- # of grid points in first direction n2 -- # of grid points in second direction created -- 96feb01 ------------------------------------------------------------ */ IVL * IVL_make13P ( int n1, int n2 ) ; /* ----------------------------------------------------------- purpose -- to make and return a 5-point adjacency structure input -- n1 -- # of grid points in first direction n2 -- # of grid points in second direction created -- 96feb02 ----------------------------------------------------------- */ IVL * IVL_make5P ( int n1, int n2 ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ --- procedures found in util.c ------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95sep22, cca ---------------------------------------------- */ int IVL_sizeOf ( IVL *ivl ) ; /* --------------------------------------------------- purpose -- to return the minimum entry in the lists created -- 95sep22, cca --------------------------------------------------- */ int IVL_min ( IVL *ivl ) ; /* --------------------------------------------------- purpose -- to return the maximum entry in the lists created -- 95sep22, cca --------------------------------------------------- */ int IVL_max ( IVL *ivl ) ; /* ---------------------------- return the maximum list size created -- 95sep22, cca ---------------------------- */ int IVL_maxListSize ( IVL *ivl ) ; /* ------------------------------- return the sum of all the lists created -- 95sep29, cca ------------------------------- */ int IVL_sum ( IVL *ivl ) ; /* ------------------------------------------- sort the adjacency lists in ascending order created -- 95sep22, cca ------------------------------------------- */ void IVL_sortUp ( IVL *ivl ) ; /* ----------------------------------------------------- create an equivalence map if ( map[j] == map[k] ) then the lists for j and k are identical endif NOTE : each empty list is mapped to a different value return value -- pointer to map[] vector created -- 95mar15, cca ----------------------------------------------------- */ int * IVL_equivMap1 ( IVL *ivl ) ; /* ----------------------------------------------------- create an equivalence map if ( map[j] == map[k] ) then the lists for j and k are identical endif NOTE : each empty list is mapped to a different value return value -- pointer to map IV object created -- 96mar15, cca ----------------------------------------------------- */ IV * IVL_equivMap2 ( IVL *ivl ) ; /* ------------------------------------ overwrite each list with new entries created -- 96oct03, cca ------------------------------------ */ void IVL_overwrite ( IVL *ivl, IV *oldToNewIV ) ; /* --------------------------------------------------- given an IVL object and a map from old list entries to new list entries, create a new IVL object whose new list entries contain no duplicates. return value -- pointer to new IVL object created -- 96nov07, cca --------------------------------------------------- */ IVL * IVL_mapEntries ( IVL *ivl, IV *mapIV ) ; /* ---------------------------------------------------------------- IVL object ivl1 absorbs the lists and data from IVL object ivl2. the lists in ivl2 are mapped into lists in ivl1 using the mapIV IV object. created -- 96dec06, cca ---------------------------------------------------------------- */ void IVL_absorbIVL ( IVL *ivl1, IVL *ivl2, IV *mapIV ) ; /* ----------------------------------------------------------------- purpose -- expand the lists in an IVL object. this method was created in support of a symbolic factorization. an IVL object is constructed using a compressed graph. it must be expanded to reflect the compressed graph. the number of lists does not change (there is one list per front) but the size of each list may change. so we create a new IVL object that contains entries for the uncompressed graph. created -- 97feb13, cca ----------------------------------------------------------------- */ IVL * IVL_expand ( IVL *ivl, IV *eqmapIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ --- procedures found in IO.c --------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- purpose -- to read in an IVL object from a file input -- fn -- filename, must be *.ivlb or *.ivlf return value -- 1 if success, 0 if failure created -- 95sep29, cca ----------------------------------------------- */ int IVL_readFromFile ( IVL *ivl, char *fn ) ; /* ------------------------------------------------------ purpose -- to read an IVL object from a formatted file return value -- 1 if success, 0 if failure created -- 95sep29, cca ------------------------------------------------------ */ int IVL_readFromFormattedFile ( IVL *ivl, FILE *fp ) ; /* --------------------------------------------------- purpose -- to read an IVL object from a binary file return value -- 1 if success, 0 if failure created -- 95sep29, cca --------------------------------------------------- */ int IVL_readFromBinaryFile ( IVL *ivl, FILE *fp ) ; /* ------------------------------------------- purpose -- to write an IVL object to a file input -- fn -- filename *.ivlb -- binary *.ivlf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95sep29, cca ------------------------------------------- */ int IVL_writeToFile ( IVL *ivl, char *fn ) ; /* ----------------------------------------------------- purpose -- to write an IVL object to a formatted file return value -- 1 if success, 0 otherwise created -- 95sep29, cca ----------------------------------------------------- */ int IVL_writeToFormattedFile ( IVL *ivl, FILE *fp ) ; /* -------------------------------------------------- purpose -- to write an IVL object to a binary file return value -- 1 if success, 0 otherwise created -- 95sep29, cca -------------------------------------------------- */ int IVL_writeToBinaryFile ( IVL *ivl, FILE *fp ) ; /* ------------------------------------------------- purpose -- to write an IVL object for a human eye return value -- 1 if success, 0 otherwise created -- 95sep29, cca ------------------------------------------------- */ int IVL_writeForHumanEye ( IVL *ivl, FILE *fp ) ; /* --------------------------------------------------------- purpose -- to write out the statistics for the IVL object return value -- 1 if success, 0 otherwise created -- 95sep29, cca --------------------------------------------------------- */ int IVL_writeStats ( IVL *ivl, FILE *fp ) ; /*--------------------------------------------------------------------*/ if ivl->type is IVL_UNKNOWN then if ivec != NULL thIVL/makefile010064400020550007177000000001720663622361600142350ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean cd drivers ; make clean IVL/src/makefile010064400020550007177000000010510663602503100150100ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = IVL $(OBJ).a : \ $(OBJ).a(IO.o) \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(listmanip.o) \ $(OBJ).a(misc.o) \ $(OBJ).a(subIVL.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG IVL/src/makeGlobalLib010064400020550007177000000006570660026105200157270ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = IVL SRC = IO.c \ basics.c \ init.c \ instance.c \ listmanip.c \ misc.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a IVL/src/IO.c010064400020550007177000000433130661173013200137700ustar00clevecompmath00000400000006/* IO.c */ #include "../IVL.h" static const char *suffixb = ".ivlb" ; static const char *suffixf = ".ivlf" ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to read in an IVL object from a file input -- fn -- filename, must be *.ivlb or *.ivlf return value -- 1 if success, 0 if failure created -- 95sep29, cca ----------------------------------------------- */ int IVL_readFromFile ( IVL *ivl, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( ivl == NULL || fn == NULL ) { fprintf(stderr, "\n error in IVL_readFromFile(%p,%s), file %s, line %d" "\n bad input\n", ivl, fn, __FILE__, __LINE__) ; return(0) ; } switch ( ivl->type ) { case IVL_CHUNKED : case IVL_SOLO : case IVL_UNKNOWN : break ; default : fprintf(stderr, "\n error in IVL_readFromFile(%p,%s)" "\n bad type = %d", ivl, fn, ivl->type) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in IVL_readFromFile(%p,%s)" "\n unable to open file %s", ivl, fn, fn) ; rc = 0 ; } else { rc = IVL_readFromBinaryFile(ivl, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in IVL_readFromFile(%p,%s)" "\n unable to open file %s", ivl, fn, fn) ; rc = 0 ; } else { rc = IVL_readFromFormattedFile(ivl, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in IVL_readFromFile(%p,%s)" "\n bad IVL file name %s," "\n must end in %s (binary) or %s (formatted)\n", ivl, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in IVL_readFromFile(%p,%s)" "\n bad IVL file name %s," "\n must end in %s (binary) or %s (formatted)\n", ivl, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to read an IVL object from a formatted file return value -- 1 if success, 0 if failure created -- 95sep29, cca ------------------------------------------------------ */ int IVL_readFromFormattedFile ( IVL *ivl, FILE *fp ) { int nlist, rc, type ; int itemp[3] ; int *sizes ; /* --------------- check the input --------------- */ if ( ivl == NULL || fp == NULL ) { fprintf(stderr, "\n error in IVL_readFromFormattedFile(%p,%p)" "\n bad input\n", ivl, fp) ; return(0) ; } switch ( ivl->type ) { case IVL_CHUNKED : case IVL_SOLO : break ; default : fprintf(stderr, "\n error in IVL_readFormattedFile(%p,%p)" "\n bad type = %d", ivl, fp, ivl->type) ; return(0) ; } /* ------------------------------------------- save the ivl type and clear the data fields ------------------------------------------- */ type = ivl->type ; IVL_clearData(ivl) ; /* ----------------------------------- read in the three scalar parameters type, # of lists, # of indices ----------------------------------- */ if ( (rc = IVfscanf(fp, 3, itemp)) != 3 ) { fprintf(stderr, "\n error in IVL_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", ivl, fp, rc, 3) ; return(0) ; } nlist = itemp[1] ; /* fprintf(stdout, "\n itemp = { %d %d %d } ", itemp[0], itemp[1], itemp[2]) ; */ /* -------------------------- read in the sizes[] vector -------------------------- */ sizes = IVinit(nlist, 0) ; if ( (rc = IVfscanf(fp, nlist, sizes)) != nlist ) { fprintf(stderr, "\n error in IVL_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", ivl, fp, rc, nlist) ; return(0) ; } /* --------------------- initialize the object --------------------- */ IVL_init3(ivl, type, nlist, sizes) ; IVfree(sizes) ; /* ----------------------- now read in the indices ----------------------- */ switch ( type ) { case IVL_SOLO : { int ilist, size ; int *ind ; for ( ilist = 0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &ind) ; if ( size > 0 ) { if ( (rc = IVfscanf(fp, size, ind)) != size ) { fprintf(stderr, "\n error in IVL_readFromFormattedFile(%p,%p)" "\n list %d, %d items of %d read\n", ivl, fp, ilist, rc, size) ; return(0) ; } } } } break ; case IVL_CHUNKED : { /* -------------------------------------------------------- read in the indices into the contiguous block of storage -------------------------------------------------------- */ if ( (rc = IVfscanf(fp, ivl->tsize, ivl->chunk->base)) != ivl->tsize ) { fprintf(stderr, "\n error in IVL_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", ivl, fp, rc, ivl->tsize) ; return(0) ; } } break ; } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to read an IVL object from a binary file return value -- 1 if success, 0 if failure created -- 95sep29, cca --------------------------------------------------- */ int IVL_readFromBinaryFile ( IVL *ivl, FILE *fp ) { int nlist, rc, type ; int itemp[3] ; int *sizes ; /* --------------- check the input --------------- */ if ( ivl == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in IVL_readFromBinaryFile(%p,%p)" "\n bad input\n", ivl, fp) ; return(0) ; } switch ( ivl->type ) { case IVL_CHUNKED : case IVL_SOLO : break ; default : fprintf(stderr, "\n error in IVL_readBinaryFile(%p,%p)" "\n bad type = %d", ivl, fp, ivl->type) ; return(0) ; } /* ------------------------------------------- save the ivl type and clear the data fields ------------------------------------------- */ type = ivl->type ; IVL_clearData(ivl) ; /* ----------------------------------- read in the three scalar parameters type, # of lists, # of indices ----------------------------------- */ if ( (rc = fread((void *) itemp, sizeof(int), 3, fp)) != 3 ) { fprintf(stderr, "\n error in IVL_readFromBinaryFile(%p,%p)" "\n itemp(3) : %d items of %d read\n", ivl, fp, rc, 3) ; return(0) ; } nlist = itemp[1] ; /* -------------------------- read in the sizes[] vector -------------------------- */ sizes = IVinit(nlist, 0) ; if ( (rc = fread((void *) sizes, sizeof(int), nlist, fp)) != nlist ) { fprintf(stderr, "\n error in IVL_readFromBinaryFile(%p,%p)" "\n sizes(%d) : %d items of %d read\n", ivl, fp, nlist, rc, nlist) ; return(0) ; } /* --------------------- initialize the object --------------------- */ IVL_init3(ivl, type, nlist, sizes) ; IVfree(sizes) ; /* ------------------- read in the indices ------------------- */ switch ( type ) { case IVL_SOLO : { int ilist, size ; int *ind ; for ( ilist = 0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &ind) ; if ( (rc = fread((void *) ind, sizeof(int), size, fp)) != size ) { fprintf(stderr, "\n error in IVL_readFromBinaryFile(%p,%p)" "\n list %d, %d items of %d read\n", ivl, fp, ilist, rc, size) ; return(0) ; } } } break ; case IVL_CHUNKED : { /* -------------------------------------------------------- read in the indices into the contiguous block of storage -------------------------------------------------------- */ if ( (rc = fread((void *) ivl->chunk->base, sizeof(int), ivl->tsize, fp)) != ivl->tsize ) { fprintf(stderr, "\n error in IVL_readFromBinaryFile(%p,%p)" "\n indices(%d) : %d items of %d read\n", ivl, fp, ivl->tsize, rc, ivl->tsize) ; return(0) ; } } break ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to write an IVL object to a file input -- fn -- filename *.ivlb -- binary *.ivlf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95sep29, cca ------------------------------------------- */ int IVL_writeToFile ( IVL *ivl, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( ivl == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in IVL_writeToFile(%p,%s)" "\n bad input\n", ivl, fn) ; } switch ( ivl->type ) { case IVL_CHUNKED : case IVL_SOLO : case IVL_UNKNOWN : break ; default : fprintf(stderr, "\n fatal error in IVL_writeToFile(%p,%s)" "\n bad type = %d", ivl, fn, ivl->type) ; return(0) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in IVL_writeToFile(%p,%s)" "\n unable to open file %s", ivl, fn, fn) ; rc = 0 ; } else { rc = IVL_writeToBinaryFile(ivl, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in IVL_writeToFile(%p,%s)" "\n unable to open file %s", ivl, fn, fn) ; rc = 0 ; } else { rc = IVL_writeToFormattedFile(ivl, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in IVL_writeToFile(%p,%s)" "\n unable to open file %s", ivl, fn, fn) ; rc = 0 ; } else { rc = IVL_writeForHumanEye(ivl, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in IVL_writeToFile(%p,%s)" "\n unable to open file %s", ivl, fn, fn) ; rc = 0 ; } else { rc = IVL_writeForHumanEye(ivl, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to write an IVL object to a formatted file return value -- 1 if success, 0 otherwise created -- 95sep29, cca ----------------------------------------------------- */ int IVL_writeToFormattedFile ( IVL *ivl, FILE *fp ) { int count, ierr, j, jsize, nlist, rc ; int *jind ; /* --------------- check the input --------------- */ if ( ivl == NULL || fp == NULL || (nlist = ivl->nlist) <= 0 ) { fprintf(stderr, "\n fatal error in IVL_writeToFormattedFile(%p,%p)" "\n bad input\n", ivl, fp) ; exit(-1) ; } /* ------------------------------------- write out the three scalar parameters ------------------------------------- */ rc = fprintf(fp, "\n %d %d %d", ivl->type, ivl->nlist, ivl->tsize) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in IVL_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", ivl, fp, rc) ; return(0) ; } if ( ivl->nlist > 0 ) { IVfp80(fp, ivl->nlist, ivl->sizes, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in IVL_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from sizes[] IVfp80\n", ivl, fp, ierr) ; return(0) ; } } switch ( ivl->type ) { case IVL_NOTYPE : break ; case IVL_UNKNOWN : case IVL_CHUNKED : case IVL_SOLO : for ( j = 0, count = 80 ; j < ivl->nlist ; j++ ) { IVL_listAndSize(ivl, j, &jsize, &jind) ; if ( jsize > 0 ) { count = IVfp80(fp, jsize, jind, count, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in IVL_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from IVfp80, list %d\n", ivl, fp, ierr, j) ; return(0) ; } } } break ; } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to write an IVL object to a binary file return value -- 1 if success, 0 otherwise created -- 95sep29, cca -------------------------------------------------- */ int IVL_writeToBinaryFile ( IVL *ivl, FILE *fp ) { int j, jsize, nlist, rc ; int *jind ; int itemp[3] ; /* --------------- check the input --------------- */ if ( ivl == NULL || fp == NULL || (nlist = ivl->nlist) <= 0 ) { fprintf(stderr, "\n fatal error in IVL_writeToBinaryFile(%p,%p)" "\n bad input\n", ivl, fp) ; exit(-1) ; } itemp[0] = ivl->type ; itemp[1] = ivl->nlist ; itemp[2] = ivl->tsize ; rc = fwrite((void *) itemp, sizeof(int), 3, fp) ; if ( rc != 3 ) { fprintf(stderr, "\n error in IVL_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", ivl, fp, rc, 3) ; return(0) ; } rc = fwrite((void *) ivl->sizes, sizeof(int), ivl->nlist, fp) ; if ( rc != ivl->nlist ) { fprintf(stderr, "\n error in IVL_writeToBinaryFile(%p,%p)" "\n ivl->sizes, %d of %d items written\n", ivl, fp, rc, ivl->nlist) ; return(0) ; } switch ( ivl->type ) { case IVL_NOTYPE : break ; case IVL_CHUNKED : case IVL_SOLO : case IVL_UNKNOWN : for ( j = 0 ; j < ivl->nlist ; j++ ) { IVL_listAndSize(ivl, j, &jsize, &jind) ; if ( jsize > 0 ) { rc = fwrite((void *) jind, sizeof(int), jsize, fp) ; if ( rc != jsize ) { fprintf(stderr, "\n error in IVL_writeToBinaryFile(%p,%p)" "\n list %d, %d of %d items written\n", ivl, fp, j, rc, jsize) ; return(0) ; } } } break ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to write an IVL object for a human eye return value -- 1 if success, 0 otherwise created -- 95sep29, cca ------------------------------------------------- */ int IVL_writeForHumanEye ( IVL *ivl, FILE *fp ) { int ierr, j, size, rc ; int *ind ; if ( ivl == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in IVL_writeForHumanEye(%p,%p)" "\n bad input\n", ivl, fp) ; exit(-1) ; } if ( (rc = IVL_writeStats(ivl, fp)) == 0 ) { fprintf(stderr, "\n fatal error in IVL_writeForHumanEye(%p,%p)" "\n rc = %d, return from IVL_writeStats(%p,%p)\n", ivl, fp, rc, ivl, fp) ; return(0) ; } for ( j = 0 ; j < ivl->nlist ; j++ ) { IVL_listAndSize(ivl, j, &size, &ind) ; if ( size > 0 ) { fprintf(fp, "\n %5d :", j) ; IVfp80(fp, size, ind, 8, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in IVL_writeForHumanEye(%p,%p)" "\n ierr = %d, return from IVfp80, list %d\n", ivl, fp, ierr, j) ; return(0) ; } } } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- to write out the statistics for the IVL object return value -- 1 if success, 0 otherwise created -- 95sep29, cca --------------------------------------------------------- */ int IVL_writeStats ( IVL *ivl, FILE *fp ) { int nactive, rc ; /* --------------- check the input --------------- */ if ( ivl == NULL || fp == NULL ) { fprintf(stderr, "\n error in IVL_writeStats(%p,%p)" "\n bad input\n", ivl, fp) ; exit(-1) ; } nactive = 0 ; if ( ivl->nlist > 0 ) { nactive = IVsum(ivl->nlist, ivl->sizes) ; } rc = fprintf(fp, "\n IVL : integer vector list object :") ; if ( rc < 0 ) { goto IO_error ; } rc = fprintf(fp, "\n type %d", ivl->type) ; if ( rc < 0 ) { goto IO_error ; } switch ( ivl->type ) { case IVL_CHUNKED : rc = fprintf(fp, ", chunked storage") ; break ; case IVL_SOLO : rc = fprintf(fp, ", solo storage") ; break ; case IVL_UNKNOWN : rc = fprintf(fp, ", unknown storage") ; break ; } if ( rc < 0 ) { goto IO_error ; } rc = fprintf(fp, "\n %d lists, %d maximum lists, %d tsize, %d total bytes", ivl->nlist, ivl->maxnlist, ivl->tsize, IVL_sizeOf(ivl)) ; if ( rc < 0 ) { goto IO_error ; } switch ( ivl->type ) { case IVL_CHUNKED : { Ichunk *chunk ; int nalloc, nchunk ; nalloc = nchunk = 0 ; for ( chunk = ivl->chunk ; chunk != NULL ; chunk = chunk->next){ nchunk++ ; nalloc += chunk->size ; } rc = fprintf(fp, "\n %d chunks, %d active entries, %d allocated", nchunk, nactive, nalloc) ; if ( rc < 0 ) { goto IO_error ; } if ( nalloc > 0 ) { rc = fprintf(fp, ", %.2f %% used", (100.*nactive)/nalloc) ; if ( rc < 0 ) { goto IO_error ; } } } break ; case IVL_SOLO : rc = fprintf(fp, "\n %d lists separately allocated, %d active entries", ivl->nlist, nactive) ; if ( rc < 0 ) { goto IO_error ; } break ; } return(1) ; IO_error : fprintf(stderr, "\n fatal error in IVL_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", ivl, fp, rc) ; return(0) ; } /*--------------------------------------------------------------------*/ break ; case IVL_CHUNKED : { /* -------------------------------------------------------- read in the indices into the contiguous block of storage -------------------------------------------------------- */ if ( (rc = fread((void *) ivl->chunk->base, sizeof(int), ivl->tsize, IVL/src/basics.c010064400020550007177000000066010654221705100147270ustar00clevecompmath00000400000006/* basics.c */ #include "../IVL.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 95sep22, cca ----------------------- */ IVL * IVL_new ( void ) { IVL *ivl ; ALLOCATE(ivl, struct _IVL, 1) ; IVL_setDefaultFields(ivl) ; return(ivl) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 95sep22, cca ----------------------- */ void IVL_setDefaultFields ( IVL *ivl ) { if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_setDefaultFields(%p)" "\n bad input", ivl) ; exit(-1) ; } ivl->type = IVL_NOTYPE ; ivl->maxnlist = 0 ; ivl->nlist = 0 ; ivl->tsize = 0 ; ivl->sizes = NULL ; ivl->p_vec = NULL ; ivl->incr = IVL_INCR ; ivl->chunk = NULL ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 95sep22, cca -------------------------------------------------- */ void IVL_clearData ( IVL *ivl ) { /* --------------- check the input --------------- */ if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_clearData(%p)" "\n bad input\n", ivl) ; exit(-1) ; } /* ---------------------------------------------------- switch over the storage type to free list entries. action is taken when type is IVL_SOLO or IVL_CHUNKED ---------------------------------------------------- */ switch ( ivl->type ) { case IVL_SOLO : { int ilist ; for ( ilist = 0 ; ilist < ivl->nlist ; ilist++ ) { if ( ivl->p_vec[ilist] != NULL ) { IVfree(ivl->p_vec[ilist]) ; ivl->p_vec[ilist] = NULL ; ivl->tsize -= ivl->sizes[ilist] ; } } } break ; case IVL_CHUNKED : { Ichunk *chunk ; while ( (chunk = ivl->chunk) != NULL ) { ivl->chunk = chunk->next ; if ( chunk->base != NULL ) { IVfree(chunk->base) ; chunk->base = NULL ; } FREE(chunk) ; } } break ; case IVL_NOTYPE : case IVL_UNKNOWN : break ; default : fprintf(stderr, "\n fatal error in IVL_clearData(%p)" "\n invalid type = %d\n", ivl, ivl->type) ; exit(-1) ; } /* ----------------------------------------------- free storage for the sizes[] and p_vec[] arrays ----------------------------------------------- */ if ( ivl->sizes != NULL ) { IVfree(ivl->sizes) ; ivl->sizes = NULL ; } if ( ivl->p_vec != NULL ) { PIVfree(ivl->p_vec) ; ivl->p_vec = NULL ; } ivl->nlist = ivl->maxnlist = 0 ; /* ---------------------- set the default fields ---------------------- */ IVL_setDefaultFields(ivl) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 95sep22, cca ------------------------------------------ */ IVL * IVL_free ( IVL *ivl ) { if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_free(%p)" "\n bad input\n", ivl) ; exit(-1) ; } IVL_clearData(ivl) ; FREE(ivl) ; return(NULL) ; } /*--------------------------------------------------------------------*/ IVL/src/init.c010064400020550007177000000143220663602770000144310ustar00clevecompmath00000400000006/* init.c */ #include "../IVL.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ initialize given the type and maximum number of lists. used for type IVL_CHUNKED, IVL_SOLO or IVL_UNKNOWN created -- 95sep22, cca ------------------------------------------------------ */ void IVL_init1 ( IVL *ivl, int type, int maxnlist ) { /* ------------------- check for bad input ------------------- */ if ( ivl == NULL || (type != IVL_CHUNKED && type != IVL_SOLO && type != IVL_UNKNOWN) || maxnlist < 0 ) { fprintf(stderr, "\n fatal error in IVL_init1(%p,%d,%d)" "\n bad input", ivl, type, maxnlist) ; exit(-1) ; } /* -------------------------- clear the data, if present -------------------------- */ IVL_clearData(ivl) ; /* ---------- initialize ---------- */ ivl->type = type ; ivl->maxnlist = maxnlist ; ivl->nlist = maxnlist ; if ( maxnlist > 0 ) { ivl->sizes = IVinit(maxnlist, 0) ; ivl->p_vec = PIVinit(maxnlist) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- initialize given the type, number of lists and their total size only used when type is IVL_CHUNKED. created -- 95sep22, cca --------------------------------------------------------------- */ void IVL_init2 ( IVL *ivl, int type, int maxnlist, int tsize ) { /* ------------------- check for bad input ------------------- */ if ( ivl == NULL || type != IVL_CHUNKED || maxnlist < 0 ) { fprintf(stderr, "\n fatal error in IVL_init2(%p,%d,%d,%d)" "\n bad input", ivl, type, maxnlist, tsize) ; exit(-1) ; } /* --------------------------------- initialize via IVL_init1() method --------------------------------- */ IVL_init1(ivl, type, maxnlist) ; /* ---------------------------------- create chunk to hold tsize entries ---------------------------------- */ if ( tsize > 0 ) { ALLOCATE(ivl->chunk, struct _Ichunk, 1) ; ivl->chunk->size = tsize ; ivl->chunk->inuse = 0 ; ivl->chunk->base = IVinit(tsize, -1) ; ivl->chunk->next = NULL ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- initialize from a vector of list sizes. used with IVL_SOLO or IVL_CHUNKED. created -- 95sep22, cca -------------------------------------- */ void IVL_init3 ( IVL *ivl, int type, int maxnlist, int sizes[] ) { int ilist ; /* ------------------- check for bad input ------------------- */ if ( ivl == NULL || (type != IVL_CHUNKED && type != IVL_SOLO) || maxnlist < 0 || sizes == NULL ) { fprintf(stderr, "\n fatal error in IVL_init3(%p,%d,%d,%p)" "\n bad input", ivl, type, maxnlist, sizes) ; exit(-1) ; } switch ( type ) { case IVL_SOLO : /* --------------------------------- initialize via IVL_init1() method --------------------------------- */ IVL_init1(ivl, type, maxnlist) ; break ; case IVL_CHUNKED : /* --------------------------------- initialize via IVL_init2() method --------------------------------- */ IVL_init2(ivl, type, maxnlist, IVsum(maxnlist, sizes)) ; break ; } /* ------------------------- set the size of each list ------------------------- */ for ( ilist = 0 ; ilist < maxnlist ; ilist++ ) { IVL_setList(ivl, ilist, sizes[ilist], NULL) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ this method resizes the maximum number of lists, replacing the old sizes[] and p_vec[] vectors as necessary. the nlist value is NOT reset. created -- 96dec05, cca ------------------------------------------------ */ void IVL_setMaxnlist ( IVL *ivl, int newmaxnlist ) { if ( ivl == NULL || newmaxnlist < 0 ) { fprintf(stderr, "\n fatal error in IVL_setMaxnlist(%p,%d)" "\n bad input\n", ivl, newmaxnlist) ; exit(-1) ; } if ( newmaxnlist != ivl->maxnlist ) { int *ivec, **pivec ; /* -------------------------------------------- allocate (and fill) the new sizes[] array -------------------------------------------- */ ivec = IVinit(newmaxnlist, 0) ; if ( ivl->sizes != NULL ) { if ( ivl->nlist > newmaxnlist ) { IVcopy(newmaxnlist, ivec, ivl->sizes) ; } else if ( ivl->nlist > 0 ) { IVcopy(ivl->nlist, ivec, ivl->sizes) ; } IVfree(ivl->sizes) ; } ivl->sizes = ivec ; /* -------------------------------------------- allocate (and fill) the larger p_vec[] array -------------------------------------------- */ pivec = PIVinit(newmaxnlist) ; if ( ivl->p_vec != NULL ) { if ( ivl->nlist > newmaxnlist ) { PIVcopy(newmaxnlist, pivec, ivl->p_vec) ; } else if ( ivl->nlist > 0 ) { PIVcopy(ivl->nlist, pivec, ivl->p_vec) ; } PIVfree(ivl->p_vec) ; } ivl->p_vec = pivec ; /* ----------------------------------- set the new maximum number of lists ----------------------------------- */ ivl->maxnlist = newmaxnlist ; if ( ivl->nlist > newmaxnlist ) { ivl->nlist = newmaxnlist ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ this method resizes the number of lists, replacing the old sizes[] and p_vec[] vectors as necessary. created -- 96dec05, cca ------------------------------------------------ */ void IVL_setNlist ( IVL *ivl, int newnlist ) { if ( ivl == NULL || newnlist < 0 ) { fprintf(stderr, "\n fatal error in IVL_setNlist(%p,%d)" "\n bad input\n", ivl, newnlist) ; exit(-1) ; } if ( newnlist > ivl->maxnlist ) { /* ------------------------------------ increase the maximum number of lists ------------------------------------ */ IVL_setMaxnlist(ivl, newnlist) ; } /* ------------------- set the nlist field ------------------- */ ivl->nlist = newnlist ; return ; } /*--------------------------------------------------------------------*/ IVL/src/instance.c010064400020550007177000000055420653410576200153000ustar00clevecompmath00000400000006/* instance.c */ #include "../IVL.h" /*--------------------------------------------------------------------*/ /* ------------------------------------- return the storage type of the object created -- 96dec06, cca ------------------------------------- */ int IVL_type ( IVL *ivl ) { /* --------------- check the input --------------- */ if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_type(%p)" "\n bad input\n", ivl) ; exit(-1) ; } return(ivl->type) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- return the maximum number of lists created -- 96dec06, cca ---------------------------------- */ int IVL_maxnlist ( IVL *ivl ) { /* --------------- check the input --------------- */ if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_maxnlist(%p)" "\n bad input\n", ivl) ; exit(-1) ; } return(ivl->maxnlist) ; } /*--------------------------------------------------------------------*/ /* -------------------------- return the number of lists created -- 96dec06, cca -------------------------- */ int IVL_nlist ( IVL *ivl ) { /* --------------- check the input --------------- */ if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_nlist(%p)" "\n bad input\n", ivl) ; exit(-1) ; } return(ivl->nlist) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- return the total size of the lists created -- 96dec06, cca ---------------------------------- */ int IVL_tsize ( IVL *ivl ) { /* --------------- check the input --------------- */ if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_tsize(%p)" "\n bad input\n", ivl) ; exit(-1) ; } return(ivl->tsize) ; } /*--------------------------------------------------------------------*/ /* ---------------------------- return the storage increment created -- 96dec06, cca ---------------------------- */ int IVL_incr ( IVL *ivl ) { /* --------------- check the input --------------- */ if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_incr(%p)" "\n bad input\n", ivl) ; exit(-1) ; } return(ivl->incr) ; } /*--------------------------------------------------------------------*/ /* ------------------------- set the storage increment created -- 96dec06, cca ------------------------- */ void IVL_setincr ( IVL *ivl, int incr ) { /* --------------- check the input --------------- */ if ( ivl == NULL || incr < 0 ) { fprintf(stderr, "\n fatal error in IVL_setincr(%p,%d)" "\n bad input\n", ivl, incr) ; exit(-1) ; } ivl->incr = incr ; return ; } /*--------------------------------------------------------------------*/ IVL/src/listmanip.c010064400020550007177000000246560653410576200155030ustar00clevecompmath00000400000006/* listmanip.c */ #include "../IVL.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- fills size of and pointer to the entries of a list set *psize = size of list ilist set *pivec = base address of list ilist use as follows : IVL_listAndSize(ivl, ilist, &isize, &ivec) ; for ( i = 0 ; i < isize ; i++ ) { do something with ivec[i] ; } created -- 95sep22, cca ---------------------------------------------------------------- */ void IVL_listAndSize ( IVL *ivl, int ilist, int *psize, int **pivec ) { /* --------------- check the input --------------- */ if ( ivl == NULL || ilist < 0 || ilist >= ivl->nlist || psize == NULL || pivec == NULL ) { fprintf(stderr, "\n fatal error in IVL_listAndSize(%p,%d,%p,%p)" "\n bad input\n", ivl, ilist, psize, pivec) ; if ( ivl != NULL ) { fprintf(stderr, "\n ilist = %d, nlist = %d", ilist, ivl->nlist) ; IVL_writeForHumanEye(ivl, stderr) ; } exit(-1) ; } /* -------------------------- set the two pointer fields -------------------------- */ *psize = ivl->sizes[ilist] ; *pivec = ivl->p_vec[ilist] ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- returns a pointer to the first element in list ilist to be used as a general iterator, e.g., for ( pi = IVL_firstInList(ivl, ilist) ; pi != NULL ; pi = IVL_nextInList(ivl, ilist, pi) ) { do something ; } created -- 95sep27, cca ---------------------------------------------------- */ int * IVL_firstInList ( IVL *ivl, int ilist ) { /* --------------- check the input --------------- */ if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_firstInList(%p,%d)" "\n bad input, ivl is NULL\n", ivl, ilist) ; exit(-1) ; } if ( ilist < 0 || ilist >= ivl->nlist ) { fprintf(stderr, "\n fatal error in IVL_firstInList(%p,%d)" "\n bad input, ilist = %d, must be in [0,%d) \n", ivl, ilist, ilist, ivl->nlist) ; exit(-1) ; } if ( ivl->sizes[ilist] == 0 ) { return(NULL) ; } else if ( ivl->p_vec[ilist] != NULL ) { return(ivl->p_vec[ilist]) ; } else { fprintf(stderr, "\n fatal error in IVL_firstInList(%p,%d)" "\n size > 0 but list is NULL\n", ivl, ilist) ; exit(-1) ; } } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- returns a pointer to the next element in list ilist to be used as a general iterator, e.g., for ( pi = IVL_firstInList(ivl, ilist) ; pi != NULL ; pi = IVL_nextInList(ivl, ilist, pi) ) { do something ; } created -- 95sep27, cca ---------------------------------------------------- */ int * IVL_nextInList ( IVL *ivl, int ilist, int *pi ) { int offset ; /* --------------- check the input --------------- */ if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_nextInList(%p,%d,%p)" "\n bad input, ivl is NULL\n", ivl, ilist, pi) ; exit(-1) ; } if ( ilist < 0 || ilist >= ivl->nlist ) { fprintf(stderr, "\n fatal error in IVL_nextInList(%p,%d,%p)" "\n bad input, ilist = %d, must be in [0,%d) \n", ivl, ilist, pi, ilist, ivl->nlist) ; exit(-1) ; } if ( (pi == NULL) || ((offset = pi - ivl->p_vec[ilist]) < 0) || offset >= ivl->sizes[ilist] ) { fprintf(stderr, "\n fatal error in IVL_nextInList(%p,%d,%p)" "\n bad pointer\n", ivl, ilist, pi) ; exit(-1) ; } else if ( offset == ivl->sizes[ilist] - 1 ) { return(NULL) ; } else { return(pi+1) ; } } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- to set or reset a list. ilist -- list id to set or reset isize -- size of the list if the present size of list ilist is smaller than isize, the old list is free'd (if ivl->type = IVL_SOLO) or lost (if ivl->type = IVL_CHUNKED) or un-set (if ivl->type = IVL_UNKNOWN) and new storage is allocated (for IVL_SOLO and IVL_CHUNKED) ivec -- list vector if ivl->type is IVL_UNKNOWN then if ivec != NULL then we set the ivl list pointer to be ivec endif else if ivec != NULL we copy ivec[] into ivl's storage for the list endif created -- 95sep27, cca last mods -- 95oct06, cca type = IVL_UNKNOWN, p_vec[ilist] set to ivec only when ivec is not NULL bug fixed, ivl->sizes[ilist] = isize ; ----------------------------------------------------------------- */ void IVL_setList ( IVL *ivl, int ilist, int isize, int ivec[] ) { /* --------------- check the input --------------- */ if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_setList(%p,%d,%d,%p)" "\n bad input, ivl is NULL\n", ivl, ilist, isize, ivec) ; exit(-1) ; } if ( ilist < 0 ) { fprintf(stderr, "\n fatal error in IVL_setList(%p,%d,%d,%p)" "\n bad input, ilist < 0", ivl, ilist, isize, ivec) ; exit(-1) ; } if ( ilist >= ivl->maxnlist ) { int newmaxnlist = (int) 1.25*ivl->maxnlist ; if ( newmaxnlist < 10 ) { newmaxnlist = 10 ; } if ( ilist >= newmaxnlist ) { newmaxnlist = ilist + 1 ; } IVL_setMaxnlist(ivl, newmaxnlist) ; } if ( ilist >= ivl->nlist ) { ivl->nlist = ilist + 1 ; } if ( isize == 0 ) { /* ------------------------------------------ new list is empty, free storage if present ------------------------------------------ */ if ( ivl->type == IVL_SOLO ) { if ( ivl->p_vec[ilist] != NULL ) { IVfree(ivl->p_vec[ilist]) ; } } ivl->tsize -= ivl->sizes[ilist] ; ivl->sizes[ilist] = 0 ; ivl->p_vec[ilist] = NULL ; } else if ( ivl->type == IVL_UNKNOWN ) { /* ------------------------------- simply set the size and pointer ------------------------------- */ ivl->tsize += isize - ivl->sizes[ilist] ; ivl->sizes[ilist] = isize ; if ( ivec != NULL ) { ivl->p_vec[ilist] = ivec ; } } else { /* -------------------------------------------------- the list entries will be copied into ivl's storage -------------------------------------------------- */ if ( ivl->sizes[ilist] < isize ) { /* -------------------------------------------- old size (might be zero) is not large enough switch over the storage types -------------------------------------------- */ switch ( ivl->type ) { case IVL_SOLO : if ( ivl->p_vec[ilist] != NULL ) { /* --------------------------------------- free old storage before allocating more and decrement the total list size --------------------------------------- */ IVfree(ivl->p_vec[ilist]) ; } ivl->p_vec[ilist] = IVinit(isize, -1) ; break ; case IVL_CHUNKED : { Ichunk *chunk ; if ( (chunk = ivl->chunk) == NULL || (chunk->size - chunk->inuse) < isize ) { /* ------------------------------- allocate a new chunk of storage ------------------------------- */ ALLOCATE(chunk, struct _Ichunk, 1) ; if ( isize < ivl->incr ) { chunk->size = ivl->incr ; } else { chunk->size = isize ; } chunk->inuse = 0 ; chunk->base = IVinit(chunk->size, -1) ; chunk->next = ivl->chunk ; ivl->chunk = chunk ; } /* -------------------------- set pointer for list ilist -------------------------- */ ivl->p_vec[ilist] = chunk->base + chunk->inuse ; chunk->inuse += isize ; } break ; default : fprintf(stderr, "\n fatal error in IVL_setList(%p,%d,%d,%p)" "\n you are trying to grow a list but type = %d" "\n type must be IVL_CHUNKED = 1 or IVL_SOLO = 2\n", ivl, ilist, isize, ivec, ivl->type) ; exit(-1) ; } } ivl->tsize += isize - ivl->sizes[ilist] ; ivl->sizes[ilist] = isize ; if ( ivec != NULL ) { /* -------------------------------- copy the list into ivl's storage -------------------------------- */ IVcopy(isize, ivl->p_vec[ilist], ivec) ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- set a pointer to a list but don't allocate storage for the list. this method was needed when we form a subgraph with a boundary. lists for the interior vertices point into the parent graph, but lists for the boundary vertices must be allocated and owned. used only for type = IVL_CHUNKED. at some point in the future we should rethink the storage semantics for the IVL object. created -- 95nov11, cca ---------------------------------------------------------------- */ void IVL_setPointerToList ( IVL *ivl, int ilist, int isize, int ivec[] ) { /* --------------- check the input --------------- */ if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_setPointerToList(%p,%d,%d,%p)" "\n bad input, ivl is NULL\n", ivl, ilist, isize, ivec) ; exit(-1) ; } if ( ivl->type != IVL_CHUNKED ) { fprintf(stderr, "\n fatal error in IVL_setPointerToList(%p,%d,%d,%p)" "\n this method is only used with type IVL_CHUNKED\n", ivl, ilist, isize, ivec) ; exit(-1) ; } if ( ilist < 0 ) { fprintf(stderr, "\n fatal error in IVL_setPointerToList(%p,%d,%d,%p)" "\n bad input, ilist < 0", ivl, ilist, isize, ivec) ; exit(-1) ; } if ( ilist >= ivl->maxnlist ) { int newmaxnlist = (int) 1.25*ivl->maxnlist ; if ( newmaxnlist < 10 ) { newmaxnlist = 10 ; } if ( ilist >= newmaxnlist ) { newmaxnlist = ilist + 1 ; } IVL_setMaxnlist(ivl, newmaxnlist) ; } if ( ilist >= ivl->nlist ) { ivl->nlist = ilist + 1 ; } if ( ivl->type == IVL_SOLO && ivl->p_vec[ilist] != NULL ) { IVfree(ivl->p_vec[ilist]) ; } ivl->tsize += isize - ivl->sizes[ilist] ; ivl->sizes[ilist] = isize ; ivl->p_vec[ilist] = ivec ; return ; } /*--------------------------------------------------------------------*/ ist, ivl->nlist) ; exit(-1) ; } if ( (pi == NULL) || ((offset = pi - ivl->IVL/src/misc.c010064400020550007177000000216200653410576200144220ustar00clevecompmath00000400000006/* misc.c */ #include "../IVL.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to make and return a 9-point adjacency structure input -- n1 -- # of grid points in first direction n2 -- # of grid points in second direction ncomp -- # of components per grid point ----------------------------------------------------------- */ IVL * IVL_make9P ( int n1, int n2, int ncomp ) { IVL *ivl ; int i, icomp, idof, ij, imax, imin, inow, j, jcomp, jmax, jmin, jnow, k, naind, ndof, nvtx, size ; int *indices ; if ( n1 <= 0 || n2 <= 0 || ncomp <= 0 ) { return(NULL) ; } /* ---------------------------------------- initialize the adjacency graph structure ---------------------------------------- */ nvtx = n1 * n2 ; ndof = nvtx * ncomp ; naind = ncomp*ncomp*((n1-2)*(n2-2)*9 + 2*(n1+n2-4)*6 + 4*4) ; ivl = IVL_new() ; IVL_init2(ivl, IVL_CHUNKED, ndof, naind) ; indices = IVinit(9*ncomp, -1) ; /* ---------------------------- fill the adjacency structure ---------------------------- */ idof = 0 ; k = 0 ; for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { ij = i + j * n1 ; imin = (i > 0) ? i-1 : i ; imax = (i < n1-1) ? i+1 : i ; jmin = (j > 0) ? j-1 : j ; jmax = (j < n2-1) ? j+1 : j ; for ( icomp = 0 ; icomp < ncomp ; icomp++, idof++ ) { size = ncomp*(imax - imin + 1)*(jmax - jmin + 1) ; for ( jnow = jmin, k = 0 ; jnow <= jmax ; jnow++ ) { for ( inow = imin ; inow <= imax ; inow++ ) { for ( jcomp = 0 ; jcomp < ncomp ; jcomp++ ) { indices[k++] = (inow + jnow*n1)*ncomp + jcomp ; } } } IVL_setList(ivl, idof, size, indices) ; } } } IVfree(indices) ; return(ivl) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to make and return a 27-point adjacency structure input -- n1 -- # of grid points in first direction n2 -- # of grid points in second direction n3 -- # of grid points in second direction ncomp -- # of components per grid point ------------------------------------------------------------ */ IVL * IVL_make27P ( int n1, int n2, int n3, int ncomp ) { IVL *ivl ; int i, icomp, idof, imax, imin, inow, j, jcomp, jmax, jmin, jnow, k, kmax, kmin, know, m, naind, ndof, nvtx, size ; int *indices ; if ( n1 <= 0 || n2 <= 0 || n3 <= 0 || ncomp <= 0 ) { return(NULL) ; } /* ---------------------------------------- initialize the adjacency graph structure ---------------------------------------- */ nvtx = n1 * n2 * n3 ; ndof = nvtx * ncomp ; naind = ncomp*ncomp*ncomp*( 27*(n1-2)*(n2-2)*(n3-2) + 2*18*(n1-2)*(n2-2) + 2*18*(n1-2)*(n3-2) + 2*18*(n2-2)*(n3-2) + 4*12*(n1-2) + 4*12*(n2-2) + 4*12*(n3-2) + 8*8) ; ivl = IVL_new() ; IVL_init2(ivl, IVL_CHUNKED, ndof, naind) ; indices = IVinit(27*ncomp, -1) ; /* ---------------------------- fill the adjacency structure ---------------------------- */ idof = 0 ; m = 0 ; for ( k = 0 ; k < n3 ; k++ ) { kmin = (k > 0) ? k-1 : k ; kmax = (k < n3-1) ? k+1 : k ; for ( j = 0 ; j < n2 ; j++ ) { jmin = (j > 0) ? j-1 : j ; jmax = (j < n2-1) ? j+1 : j ; for ( i = 0 ; i < n1 ; i++ ) { imin = (i > 0) ? i-1 : i ; imax = (i < n1-1) ? i+1 : i ; for ( icomp = 0 ; icomp < ncomp ; icomp++, idof++ ) { size = ncomp*(imax - imin + 1) *(jmax - jmin + 1)*(kmax - kmin + 1) ; /* fprintf(stdout, "\n k = %d, j = %d, i = %d, icomp = %d, size = %d", k, j, i, icomp, size) ; fflush(stdout) ; fprintf(stdout, "\n dof %d : m %d :", idof, m) ; */ for ( know = kmin, m = 0 ; know <= kmax ; know++ ) { for ( jnow = jmin ; jnow <= jmax ; jnow++ ) { for ( inow = imin ; inow <= imax ; inow++ ) { for ( jcomp = 0 ; jcomp < ncomp ; jcomp++ ) { if ( m == naind ) { fprintf(stderr, "\n error in IVL::IVLmake27P(%d,%d,%d,%d)" "\n naind = %d, m = %d" "\n (i,j,k) = (%d,%d,%d)," " (inow,jnow,know) = (%d,%d,%d)", n1, n2, n3, ncomp, naind, m, i, j, k, inow, jnow, know) ; exit(-1) ; } indices[m++] = jcomp + (inow + jnow*n1 + know*n1*n2)*ncomp ; /* fprintf(stdout, " %d", indices[m - 1]) ; */ } } } } IVL_setList(ivl, idof, size, indices) ; } } } } IVfree(indices) ; return(ivl) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to make and return a 13-point adjacency structure input -- n1 -- # of grid points in first direction n2 -- # of grid points in second direction created -- 96feb01 ------------------------------------------------------------ */ IVL * IVL_make13P ( int n1, int n2 ) { IVL *ivl ; int count, i, ij, j, nvtx ; int list[13] ; if ( n1 <= 0 || n2 <= 0 ) { return(NULL) ; } /* ---------------------------------------- initialize the adjacency graph structure ---------------------------------------- */ nvtx = n1 * n2 ; ivl = IVL_new() ; IVL_init1(ivl, IVL_CHUNKED, nvtx) ; /* ---------------------------- fill the adjacency structure ---------------------------- */ for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { ij = i + j * n1 ; count = 0 ; if ( j >= 2 ) { list[count++] = ij - 2*n1 ; } if ( j >= 1 ) { if ( i >= 1 ) { list[count++] = ij - n1 - 1 ; } list[count++] = ij - n1 ; if ( i <= n1 - 2 ) { list[count++] = ij - n1 + 1 ; } } if ( i >= 2 ) { list[count++] = ij - 2 ; } if ( i >= 1 ) { list[count++] = ij - 1 ; } list[count++] = ij ; if ( i <= n1 - 2 ) { list[count++] = ij + 1 ; } if ( i <= n1 - 3 ) { list[count++] = ij + 2 ; } if ( j <= n2 - 2 ) { if ( i >= 1 ) { list[count++] = ij + n1 - 1 ; } list[count++] = ij + n1 ; if ( i <= n1 - 2 ) { list[count++] = ij + n1 + 1 ; } } if ( j <= n2 - 3 ) { list[count++] = ij + 2*n1 ; } IVL_setList(ivl, ij, count, list) ; } } return(ivl) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to make and return a 5-point adjacency structure input -- n1 -- # of grid points in first direction n2 -- # of grid points in second direction created -- 96feb02 ----------------------------------------------------------- */ IVL * IVL_make5P ( int n1, int n2 ) { IVL *ivl ; int count, i, ij, j, nvtx ; int list[5] ; if ( n1 <= 0 || n2 <= 0 ) { return(NULL) ; } /* ---------------------------------------- initialize the adjacency graph structure ---------------------------------------- */ nvtx = n1 * n2 ; ivl = IVL_new() ; IVL_init1(ivl, IVL_CHUNKED, nvtx) ; /* ---------------------------- fill the adjacency structure ---------------------------- */ for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { ij = i + j * n1 ; count = 0 ; if ( j >= 1 ) { list[count++] = ij - n1 ; } if ( i >= 1 ) { list[count++] = ij - 1 ; } list[count++] = ij ; if ( i <= n1 - 2 ) { list[count++] = ij + 1 ; } if ( j <= n2 - 2 ) { list[count++] = ij + n1 ; } /* if ( j >= 1 ) { list[count++] = ij - n1 ; } else { list[count++] = i + n1 * (n2 - 1) ; } if ( i >= 1 ) { list[count++] = ij - 1 ; } else { list[count++] = ij + n1 - 1 ; } list[count++] = ij ; if ( i <= n1 - 2 ) { list[count++] = ij + 1 ; } else { list[count++] = ij - n1 + 1 ; } if ( j <= n2 - 2 ) { list[count++] = ij + n1 ; } else { list[count++] = i ; } */ IVqsortUp(count, list) ; IVL_setList(ivl, ij, count, list) ; } } return(ivl) ; } /*--------------------------------------------------------------------*/ 27*(n1-2)*(n2-2)*(n3-2) + 2*18*(n1-2)*(n2-2) + 2*18*(n1-2)*(n3-2) + 2*18*(n2-2IVL/src/subIVL.c010064400020550007177000000066720663603011000146300ustar00clevecompmath00000400000006/* subIVL.c */ #include "../IVL.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- initialize subIVL from ivl if keeplistIV is not NULL then keeplistIV contains the lists of ivl to be placed in subIVL else all lists are placed in subIVL endif if keepentriesIV is not NULL then keepentriesIV contains the entries in the lists to be kept else all entries in the kept lists are placed in subIVL endif return value --- 1 -- normal return -1 -- subIVL is NULL -2 -- ivl is NULL -3 -- keeplistIV is invalid created -- 98oct16, cca ---------------------------------------------------------------- */ int IVL_initFromSubIVL ( IVL *subIVL, IVL *ivl, IV *keeplistIV, IV *keepentriesIV ) { int count, ii, ikeep, ilist, maxlistsize, maxval, nkeep, nkeepent, nlist, size, val ; int *keepent, *keeplist, *list, *map, *temp ; /* --------------- check the input --------------- */ if ( subIVL == NULL ) { fprintf(stderr, "\n error in IVL_initFromSubIVL()" "\n subIVL is NULL\n") ; return(-1) ; } if ( ivl == NULL ) { fprintf(stderr, "\n error in IVL_initFromSubIVL()" "\n ivl is NULL\n") ; return(-2) ; } nlist = ivl->nlist ; if ( keeplistIV != NULL ) { IV_sizeAndEntries(keeplistIV, &nkeep, &keeplist) ; if ( nkeep < 0 || keeplist == NULL ) { fprintf(stderr, "\n error in IVL_initFromSubIVL()" "\n invalid keeplistIV, nkeep %d, keeplist %p\n", nkeep, keeplist) ; return(-3) ; } for ( ii = 0 ; ii < nkeep ; ii++ ) { if ( (val = keeplist[ii]) < 0 || val >= nlist ) { fprintf(stderr, "\n error in IVL_initFromSubIVL()" "\n invalid keeplistIV, keeplist[%d] = %d, nlist %d\n", ii, val, nlist) ; return(-3) ; } } } else { nkeep = nlist ; keeplist = IVinit(nkeep, -1) ; IVramp(nkeep, keeplist, 0, 1) ; } if ( keepentriesIV != NULL ) { IV_sizeAndEntries(keepentriesIV, &nkeepent, &keepent) ; maxval = IVL_max(ivl) ; if ( maxval >= 0 ) { map = IVinit(1 + maxval, -1) ; for ( ii = 0 ; ii < nkeepent ; ii++ ) { if ( (val = keepent[ii]) >= 0 ) { map[val] = ii ; } } maxlistsize = IVL_maxListSize(ivl) ; temp = IVinit(maxlistsize, -1) ; } else { map = NULL ; } } else { map = NULL ; } /* ---------------------------- initialize the subIVL object ---------------------------- */ IVL_init1(subIVL, IVL_CHUNKED, nkeep) ; /* ----------------------------------- fill the lists of the subIVL object ----------------------------------- */ for ( ikeep = 0 ; ikeep < nkeep ; ikeep++ ) { ilist = keeplist[ikeep] ; IVL_listAndSize(ivl, ilist, &size, &list) ; if ( map == NULL ) { IVL_setList(subIVL, ikeep, size, list) ; } else { for ( ii = count = 0 ; ii < size ; ii++ ) { if ( (val = map[list[ii]]) != -1 ) { temp[count++] = val ; } } IVL_setList(subIVL, ikeep, count, temp) ; } } /* ------------------------ free the working storage ------------------------ */ if ( keeplistIV == NULL ) { IVfree(keeplist) ; } if ( map != NULL ) { IVfree(map) ; IVfree(temp) ; } return(1) ; } /*--------------------------------------------------------------------*/ IVL/src/util.c010064400020550007177000000476740657430071700144660ustar00clevecompmath00000400000006/* util.c */ #include "../IVL.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95sep22, cca ---------------------------------------------- */ int IVL_sizeOf ( IVL *ivl ) { int nbytes ; /* --------------- check the input --------------- */ if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_sizeOf(%p)" "\n bad input\n", ivl) ; exit(-1) ; } nbytes = sizeof(struct _IVL) ; if ( ivl->nlist > 0 ) { nbytes += ivl->nlist * (sizeof(int) + sizeof(int *)) ; if ( ivl->type == IVL_SOLO ) { nbytes += IVsum(ivl->nlist, ivl->sizes) * sizeof(int) ; } else { Ichunk *chunk ; for ( chunk = ivl->chunk ; chunk != NULL ; chunk = chunk->next ) { nbytes += sizeof(Ichunk) + chunk->size * sizeof(int) ; } } } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to return the minimum entry in the lists created -- 95sep22, cca --------------------------------------------------- */ int IVL_min ( IVL *ivl ) { int first, i, ilist, minval, nlist, size, val ; int *ent ; /* --------------- check the input --------------- */ if ( ivl == NULL || (nlist = ivl->nlist) <= 0 ) { fprintf(stderr, "\n fatal error in IVL_min(%p)" "\n bad input\n", ivl) ; exit(-1) ; } first = 1 ; minval = -1 ; for ( ilist = 0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &ent) ; if ( size > 0 ) { val = IVmin(size, ent, &i) ; if ( first == 1 ) { minval = val ; first = 0 ; } else if ( minval > val ) { minval = val ; } } } return(minval) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to return the maximum entry in the lists created -- 95sep22, cca --------------------------------------------------- */ int IVL_max ( IVL *ivl ) { int first, i, ilist, maxval, nlist, size, val ; int *ent ; /* --------------- check the input --------------- */ if ( ivl == NULL || (nlist = ivl->nlist) <= 0 ) { fprintf(stderr, "\n fatal error in IVL_max(%p)" "\n bad input\n", ivl) ; exit(-1) ; } first = 1 ; maxval = -1 ; for ( ilist = 0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &ent) ; if ( size > 0 ) { val = IVmax(size, ent, &i) ; if ( first == 1 ) { maxval = val ; first = 0 ; } else if ( maxval < val ) { maxval = val ; } } } return(maxval) ; } /*--------------------------------------------------------------------*/ /* ---------------------------- return the maximum list size created -- 95sep22, cca ---------------------------- */ int IVL_maxListSize ( IVL *ivl ) { int ilist, maxsize, nlist, size ; int *ent ; /* ------------------- check for bad input ------------------- */ if ( ivl == NULL || (nlist = ivl->nlist) <= 0 ) { fprintf(stderr, "\n fatal error in IVL_maxListSize(%p)" "\n bad input", ivl) ; exit(-1) ; } for ( ilist = 0, maxsize = 0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &ent) ; if ( maxsize < size ) { maxsize = size ; } } return(maxsize) ; } /*--------------------------------------------------------------------*/ /* ------------------------------- return the sum of all the lists created -- 95sep29, cca ------------------------------- */ int IVL_sum ( IVL *ivl ) { int j, jsize, sum ; int *jind ; if ( ivl == NULL ) { fprintf(stderr, "\n fatal error in IVL_sum(%p)" "\n bad input\n", ivl) ; exit(-1) ; } sum = 0 ; for ( j = 0 ; j < ivl->nlist ; j++ ) { IVL_listAndSize(ivl, j, &jsize, &jind) ; if ( jsize > 0 ) { sum = sum + IVsum(jsize, jind) ; } } return(sum) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- sort the adjacency lists in ascending order created -- 95sep22, cca ------------------------------------------- */ void IVL_sortUp ( IVL *ivl ) { int ilist, nlist, size ; int *ent ; /* --------------- check the input --------------- */ if ( ivl == NULL || (nlist = ivl->nlist) < 0 ) { fprintf(stderr, "\n fatal error in IVL_sortUp(%p)" "\n bad input\n", ivl) ; exit(-1) ; } for ( ilist = 0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &ent) ; if ( size > 0 ) { IVqsortUp(size, ent) ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- create an equivalence map if ( map[j] == map[k] ) then the lists for j and k are identical endif NOTE : each empty list is mapped to a different value return value -- pointer to map[] vector created -- 95mar15, cca ----------------------------------------------------- */ int * IVL_equivMap1 ( IVL *ivl ) { int first, ierr, ii, itest, jtest, nlist, nlist2, ntest, nv2, sum, v, v2, vsize, w, wsize ; int *chksum, *issorted, *map, *mark, *vadj, *vids, *wadj ; /* --------------- check the input --------------- */ if ( ivl == NULL || (nlist = ivl->nlist) < 0 ) { fprintf(stderr, "\n fatal error in IVL_equivMap(%p)" "\n bad input\n", ivl) ; exit(-1) ; } if ( nlist == 0 ) { return(NULL) ; } /* -------------- initialize map -------------- */ map = IVinit(nlist, -1) ; nlist2 = 0 ; /* --------------------------------- sort the lists by their checksums --------------------------------- */ vids = IVinit(nlist, -1) ; chksum = IVinit(nlist, -1) ; for ( v = 0, ntest = 0 ; v < nlist ; v++ ) { IVL_listAndSize(ivl, v, &vsize, &vadj) ; if ( vsize > 0 ) { /* --------------------------------------------- list is not empty, store list id and checksum --------------------------------------------- */ for ( ii = 0, sum = 0 ; ii < vsize ; ii++ ) { sum += vadj[ii] ; } vids[ntest] = v ; chksum[ntest] = sum ; ntest++ ; } else { /* ------------------------------ list is empty, map to new list ------------------------------ */ map[v] = nlist2++ ; } } #if MYDEBUG > 0 fprintf(stdout, "\n before sort, vids") ; IVfp80(stdout, ntest, vids, 80, &ierr) ; fprintf(stdout, "\n before sort, chksum") ; IVfp80(stdout, ntest, chksum, 80, &ierr) ; fflush(stdout) ; #endif IV2qsortUp(ntest, chksum, vids) ; #if MYDEBUG > 0 fprintf(stdout, "\n after sort, vids") ; IVfp80(stdout, ntest, vids, 80, &ierr) ; fprintf(stdout, "\n after sort, chksum") ; IVfp80(stdout, ntest, chksum, 80, &ierr) ; fflush(stdout) ; #endif /* ----------------------------------------------------------------- loop over the nonempty lists in the order of increasing checksums ----------------------------------------------------------------- */ issorted = IVinit(nlist, -1) ; for ( itest = 0 ; itest < ntest ; itest++ ) { v = vids[itest] ; if ( map[v] == -1 ) { /* ------------------------------------------------- list v has not been found to be indistinguishable to any other list, map it to a new list ------------------------------------------------- */ map[v] = nlist2++ ; #if MYDEBUG > 0 fprintf(stdout, "\n setting map[%d] = %d, chksum[%d] = %d", v, map[v], itest, chksum[itest]) ; fflush(stdout) ; #endif /* -------------------------------------- loop over lists with the same checksum -------------------------------------- */ IVL_listAndSize(ivl, v, &vsize, &vadj) ; first = 1 ; for ( jtest = itest + 1 ; jtest < ntest ; jtest++ ) { w = vids[jtest] ; #if MYDEBUG > 0 fprintf(stdout, "\n comparing with %d, chksum[%d] = %d", w, jtest, chksum[jtest]) ; fflush(stdout) ; #endif if ( chksum[itest] != chksum[jtest] ) { /* -------------------------------------------------- checksums are not equal, list v cannot be the same as any following list, break out of test loop -------------------------------------------------- */ break ; } else { /* ----------------------------------------------------- lists v and w have the same checksum if the list sizes are the same then compare the lists ----------------------------------------------------- */ IVL_listAndSize(ivl, w, &wsize, &wadj) ; #if MYDEBUG > 0 fprintf(stdout, "\n vsize = %d, wsize = %d", vsize, wsize) ; fflush(stdout) ; #endif if ( vsize == wsize ) { if ( issorted[v] != 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n sorting list for %d", v) ; fflush(stdout) ; #endif issorted[v] = 1 ; IVqsortUp(vsize, vadj) ; } if ( issorted[w] != 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n sorting list for %d", w) ; fflush(stdout) ; #endif issorted[w] = 1 ; IVqsortUp(wsize, wadj) ; } for ( ii = 0 ; ii < vsize ; ii++ ) { if ( vadj[ii] != wadj[ii] ) { break ; } } if ( ii == vsize ) { /* ---------------------------------- lists are identical, set map for w ---------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n lists are identical") ; fflush(stdout) ; #endif map[w] = map[v] ; } } } } } } IVfree(issorted) ; IVfree(chksum) ; IVfree(vids) ; #if MYDEBUG > 0 fprintf(stdout, "\n initial map") ; IVfp80(stdout, nlist, map, 80, &ierr) ; fflush(stdout) ; #endif /* ---------------------------------------------------- now modify the map to ensure if v2 < w2 then min { v | map[v] = v2 } < min { w | map[w] = w2 } endif ---------------------------------------------------- */ mark = IVinit(nlist2, -1) ; for ( v = 0, nv2 = 0 ; v < nlist ; v++ ) { v2 = map[v] ; if ( mark[v2] == -1 ) { mark[v2] = nv2++ ; } map[v] = mark[v2] ; } IVfree(mark) ; #if MYDEBUG > 0 fprintf(stdout, "\n final map") ; IVfp80(stdout, nlist, map, 80, &ierr) ; fflush(stdout) ; #endif return(map) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- create an equivalence map if ( map[j] == map[k] ) then the lists for j and k are identical endif NOTE : each empty list is mapped to a different value return value -- pointer to map IV object created -- 96mar15, cca ----------------------------------------------------- */ IV * IVL_equivMap2 ( IVL *ivl ) { int *map ; IV *mapIV ; if ( (map = IVL_equivMap1(ivl)) == NULL ) { mapIV = NULL ; } else { mapIV = IV_new() ; IV_init2(mapIV, ivl->nlist, ivl->nlist, 1, map) ; } return(mapIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ overwrite each list with new entries created -- 96oct03, cca ------------------------------------ */ void IVL_overwrite ( IVL *ivl, IV *oldToNewIV ) { int ii, ilist, nlist, range, size ; int *list, *oldToNew ; /* --------------- check the input --------------- */ if ( ivl == NULL || oldToNewIV == NULL ) { fprintf(stderr, "\n fatal error in IVL_overwrite(%p,%p)" "\n bad input\n", ivl, oldToNewIV) ; exit(-1) ; } oldToNew = IV_entries(oldToNewIV) ; range = IV_size(oldToNewIV) ; nlist = ivl->nlist ; for ( ilist = 0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &list) ; for ( ii = 0 ; ii < size ; ii++ ) { if ( 0 <= list[ii] && list[ii] < range ) { list[ii] = oldToNew[list[ii]] ; } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- given an IVL object and a map from old list entries to new list entries, create a new IVL object whose new list entries contain no duplicates. return value -- pointer to new IVL object created -- 96nov07, cca --------------------------------------------------- */ IVL * IVL_mapEntries ( IVL *ivl, IV *mapIV ) { int count, ierr, ii, ilist, maxsize, nlist, range, size, value ; int *list, *map, *newlist ; IVL *newIVL ; /* --------------- check the input --------------- */ if ( ivl == NULL || mapIV == NULL ) { fprintf(stderr, "\n fatal error in IVL_mapEntries(%p,%p)" "\n bad input\n", ivl, mapIV) ; exit(-1) ; } nlist = ivl->nlist ; range = IV_size(mapIV) ; map = IV_entries(mapIV) ; #if MYDEBUG > 0 fprintf(stdout, "\n nlist = %d, range = %d, map = %p", nlist, range, map) ; #endif if ( nlist <= 0 || range < 0 || map == NULL ) { return(NULL) ; } /* ------------------------- create the new IVL object ------------------------- */ newIVL = IVL_new(); IVL_init1(newIVL, IVL_CHUNKED, nlist) ; /* ------------------- loop over the lists ------------------- */ maxsize = IVL_maxListSize(ivl) ; newlist = IVinit(maxsize, -1) ; for ( ilist = 0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &list) ; #if MYDEBUG > 0 fprintf(stdout, "\n list %d :", ilist) ; IVfp80(stdout, size, list, 10, &ierr) ; #endif for ( ii = 0, count = 0 ; ii < size ; ii++ ) { if ( 0 <= list[ii] && list[ii] < range ) { /* ----------------------------------------- old entry is in range, store mapped value ----------------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n newlist[%d] = map[%d] = %d", count, list[ii], map[list[ii]]) ; #endif newlist[count++] = map[list[ii]] ; } } if ( count > 0 ) { /* ------------------------------------ sort the new list in ascending order ------------------------------------ */ #if MYDEBUG > 0 fprintf(stdout, "\n unsorted list %d :", ilist) ; IVfp80(stdout, count, newlist, 10, &ierr) ; #endif IVqsortUp(count, newlist) ; #if MYDEBUG > 0 fprintf(stdout, "\n sorted list %d :", ilist) ; IVfp80(stdout, count, newlist, 10, &ierr) ; #endif /* ----------------------- purge duplicate entries ----------------------- */ size = count ; value = -1 ; for ( ii = count = 0 ; ii < size ; ii++ ) { if ( newlist[ii] != value ) { #if MYDEBUG > 0 fprintf(stdout, "\n keeping entry %d", newlist[ii]) ; #endif newlist[count++] = newlist[ii] ; value = newlist[ii] ; } } } /* ---------------------------------- set the list in the new IVL object ---------------------------------- */ IVL_setList(newIVL, ilist, count, newlist) ; } IVfree(newlist) ; return(newIVL) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- IVL object ivl1 absorbs the lists and data from IVL object ivl2. the lists in ivl2 are mapped into lists in ivl1 using the mapIV IV object. created -- 96dec06, cca ---------------------------------------------------------------- */ void IVL_absorbIVL ( IVL *ivl1, IVL *ivl2, IV *mapIV ) { Ichunk *chunk ; int ilist, jlist, nlist2, size ; int *ivec, *map ; /* --------------- check the input --------------- */ if ( ivl1 == NULL || ivl2 == NULL || mapIV == NULL ) { fprintf(stderr, "\n fatal error in IVL_absorbIVL(%p,%p,%p)" "\n bad input\n", ivl1, ivl2, mapIV) ; exit(-1) ; } if ( (map = IV_entries(mapIV)) == NULL ) { fprintf(stderr, "\n fatal error in IVL_absorbIVL(%p,%p,%p)" "\n IV_entries(mapIV) is NULL\n", ivl1, ivl2, mapIV) ; exit(-1) ; } /* -------------------------------------------- check that the sizes of ivl2 and mapIV agree -------------------------------------------- */ if ( IV_size(mapIV) != (nlist2 = ivl2->nlist) ) { fprintf(stderr, "\n fatal error in IVL_absorbIVL(%p,%p,%p)" "\n ivl2->nlist = %d, IV_size(mapIV) = %d\n", ivl1, ivl2, mapIV, nlist2, IV_size(mapIV)) ; exit(-1) ; } /* ------------------------------- for each list in ivl2 get size and pointer get mapped list in ivl1 set size and pointer in ivl1 ------------------------------- */ for ( ilist = 0 ; ilist < nlist2 ; ilist++ ) { IVL_listAndSize(ivl2, ilist, &size, &ivec) ; if ( (jlist = map[ilist]) >= 0 ) { IVL_setPointerToList(ivl1, jlist, size, ivec) ; } } if ( (chunk = ivl2->chunk) != NULL ) { /* ------------------------------------------- move the chunks of memory from ivl2 to ivl1 ------------------------------------------- */ while ( chunk->next != NULL ) { chunk = chunk->next ; } chunk->next = ivl1->chunk ; ivl1->chunk = ivl2->chunk ; ivl2->chunk = NULL ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- expand the lists in an IVL object. this method was created in support of a symbolic factorization. an IVL object is constructed using a compressed graph. it must be expanded to reflect the compressed graph. the number of lists does not change (there is one list per front) but the size of each list may change. so we create a new IVL object that contains entries for the uncompressed graph. created -- 97feb13, cca ----------------------------------------------------------------- */ IVL * IVL_expand ( IVL *ivl, IV *eqmapIV ) { int count, ii, ilist, jj, kk, nlist1, nlist2, nvtx, size ; int *head, *link, *list, *map, *temp ; IVL *ivl2 ; /* --------------- check the input --------------- */ if ( ivl == NULL || eqmapIV == NULL ) { fprintf(stderr, "\n fatal error in IVL_expand(%p,%p)" "\n bad input\n", ivl, eqmapIV) ; exit(-1) ; } nlist1 = ivl->nlist ; /* ------------------------------- get the head[]/link[] structure ------------------------------- */ IV_sizeAndEntries(eqmapIV, &nlist2, &map) ; nvtx = 1 + IV_max(eqmapIV) ; #if MYDEBUG > 0 fprintf(stdout, "\n nlist1 = %d, nlist2 = %d", nlist1, nlist2) ; fflush(stdout) ; #endif head = IVinit(nvtx, -1) ; link = IVinit(nlist2, -1) ; for ( ii = nlist2 - 1 ; ii >= 0 ; ii-- ) { if ( (jj = map[ii]) < 0 || jj >= nvtx ) { fprintf(stderr, "\n fatal error in IVL_expand(%p,%p)" "\n nlist1 = %d, nvtx = %d, map[%d] = %d\n", ivl, eqmapIV, nlist1, nvtx, ii, jj) ; exit(-1) ; } link[ii] = head[jj] ; head[jj] = ii ; } #if MYDEBUG > 0 fprintf(stdout, "\n head/link structure created") ; fflush(stdout) ; #endif /* --------------------------- allocate the new IVL object --------------------------- */ ivl2 = IVL_new() ; IVL_init1(ivl2, IVL_CHUNKED, nlist1) ; temp = IVinit(nlist2, -1) ; for ( ilist = 0 ; ilist < nlist1 ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &list) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n working on list %d", ilist) ; IVfprintf(stdout, size, list) ; fflush(stdout) ; #endif for ( ii = 0, count = 0 ; ii < size ; ii++ ) { jj = list[ii] ; for ( kk = head[jj] ; kk != -1 ; kk = link[kk] ) { temp[count++] = kk ; } } IVL_setList(ivl2, ilist, count, temp) ; } /* ------------------------ free the working storage ------------------------ */ IVfree(head) ; IVfree(link) ; IVfree(temp) ; return(ivl2) ; } /*--------------------------------------------------------------------*/ } } } IVfree(issorted) ; IVfree(chksum) ; IVfree(vids) IVL/doc/004275500020550007177000000000000665023216500133025ustar00clevecompmath00000400000006IVL/doc/dataStructure.tex010064400020550007177000000064550653410576200166660ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:IVL:dataStructure} \par The {\tt IVL} structure has seven fields. \begin{itemize} \item {\tt int type} : storage type, one of {\tt IVL\_CHUNKED}, {\tt IVL\_SOLO}, {\tt IVL\_UNKNOWN}, and {\tt IVL\_NOTYPE} (which means the object has not yet been initialized.) Here is a description of the three types of storage management. \begin{itemize} \item {\tt IVL\_CHUNKED} \par A chunk of data is allocated by the object and each list occupies contiguous entries in a chunk. More than one chunk may exist at one time, but only one contains free entries to be used for a new list. If there is not enough space in the chunk to contain the entries in a new list, another chunk is allocated to hold the list. When the {\tt IVL} object is free'd, all the chunks of data are free'd. The number of entries in a chunk can be set by the user by changing the {\tt incr} field, whose default value is 1024. This type of storage is used most often. \item {\tt IVL\_SOLO} \par Each list is allocated separately using the {\tt IVinit()} function. When the {\tt IVL} object is free'd, each list is free'd separately using the {\tt IVfree()} function. \item {\tt IVL\_UNKNOWN} \par This storage mode is available for the cases where storage for a list is aliased to another location. Absolutely no free'ing of data is done when the {\tt IVL} object is free'd. \end{itemize} The storage management is handled by {\tt IVL\_setList()} and {\tt IVL\_setPointerToList()}. \item {\tt int maxnlist} : maximum number of lists. \par {\tt int nlist} : number of lists. \par We may not know how many lists we will need for the object --- {\tt maxnlist} is the dimension of the {\tt sizes[]} and {\tt p\_vec[]} arrays and {\tt nlist} is the present number of active lists. When we initialize the object using one of the {\tt IVL\_init\{1,2,3\}()} methods, we set {\tt nlist} equal to {\tt maxnlist}. We resize the object using {\tt IVL\_setMaxnlist()}. \item {\tt int tsize} : total number of list entries. \item {\tt int *sizes} : pointer to an {\tt int} vector of size {\tt maxnlist}. \par {\tt int **p\_vec} : pointer to an {\tt int*} vector of size {\tt maxnlist}. \par The size of list {\tt ilist} is found in {\tt sizes[ilist]} and {\tt p\_vec[ilist]} points to the start of the list. The {\tt sizes} and {\tt p\_vec} fields need never be accessed directly --- see the {\tt IVL\_listAndSize()}, {\tt IVL\_setList()} and {\tt IVL\_setPointerToList()} methods. \item {\tt int incr} : increment for a new chunk of data, used for type {\tt IVL\_CHUNKED} \item {\tt Ichunk *chunk} : pointer to the active {\tt Ichunk} structure, a helper object to manage the allocated storage. It has the following fields. \begin{itemize} \item {\tt int size} : number of entries in the chunk, also the dimension of the array {\tt base[]}. \item {\tt int inuse} : number of entries in use from this chunk, the number of available entries in {\tt size - inuse}. \item {\tt int *base} : base address of the {\tt int} vector of size {\tt size} from which we find storage for the individual lists. \item {\tt Ichunk *next} : pointer to the next {\tt Ichunk} object in the list of active {\tt Ichunk} objects. \end{itemize} \end{itemize} IVL/doc/intro.tex010064400020550007177000000010000653410576200151440ustar00clevecompmath00000400000006\chapter{{\tt IVL}: Integer Vector List Object} \par The {\tt IVL} object is used to handle a list of {\tt int} vectors, thus the acronym {\bf I}nteger {\bf V}ector {\bf L}ist. The most common use is to represent a graph or the adjacency structure of a matrix. We have tried to make this object easy to use, and much hinges on the ability to create new lists or change the size of a list. In the interests of efficiency, this object is not a general purpose storage object, i.e., free'd data is not reused. \par IVL/doc/main.aux010064400020550007177000000031420665016464000147420ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt IVL}: Integer Vector List Object}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{1}} \newlabel{section:IVL:dataStructure}{{1.1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt IVL} methods}{2}} \newlabel{section:IVL:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{2}} \newlabel{subsection:IVL:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Instance methods}{3}} \newlabel{subsection:IVL:proto:instance}{{1.2.2}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Initialization and resizing methods}{4}} \newlabel{subsection:IVL:proto:initializers}{{1.2.3}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}List manipulation methods}{5}} \newlabel{subsection:IVL:proto:listmanip}{{1.2.4}{5}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Utility methods}{6}} \newlabel{subsection:IVL:proto:utilities}{{1.2.5}{6}} \citation{ash95-compressed-graphs} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.6}Miscellaneous methods}{8}} \newlabel{subsection:IVL:proto:miscellaneous}{{1.2.6}{8}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.7}IO methods}{8}} \newlabel{subsection:IVL:proto:IO}{{1.2.7}{8}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs for the {\tt IVL} object}{9}} \newlabel{section:IVL:drivers}{{1.3}{9}} IVL/doc/main.log010064400020550007177000000150630665016464000147330ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 16 JAN 1999 11:33 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/latex209.def File: latex209.def 1996/05/21 v0.51 Standard LaTeX file Entering LaTeX 2.09 compatibility mode. \footheight=\dimen102 \@maxsep=\dimen103 \@dblmaxsep=\dimen104 \@cla=\count79 \@clb=\count80 \mscount=\count81 (/home/tex/teTeX/texmf/tex/latex/base/tracefnt.sty Package: tracefnt 1996/07/26 v3.0i Standard LaTeX package (font tracing) \tracingfonts=\count82 LaTeX Info: Redefining \selectfont on input line 139. ) \symbold=\mathgroup4 \symsans=\mathgroup5 \symtypewriter=\mathgroup6 \symitalic=\mathgroup7 \symsmallcaps=\mathgroup8 \symslanted=\mathgroup9 LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 306. LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 307. LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 308. LaTeX Font Info: Redeclaring math alphabet \mathit on input line 314. LaTeX Info: Redefining \em on input line 324. (/home/tex/teTeX/texmf/tex/latex/base/latexsym.sty Package: latexsym 1996/11/20 v2.2d Standard LaTeX package (lasy symbols) \symlasy=\mathgroup10 LaTeX Font Info: Overwriting symbol font `lasy' in version `bold' (Font) U/lasy/m/n --> U/lasy/b/n on input line 85. ) LaTeX Font Info: Redeclaring math delimiter \lgroup on input line 388. LaTeX Font Info: Redeclaring math delimiter \rgroup on input line 390. LaTeX Font Info: Redeclaring math delimiter \bracevert on input line 392. (/home/tex/teTeX/texmf/tex/latex/config/latex209.cfg (/home/tex/teTeX/texmf/tex/latex/tools/rawfonts.sty Compatibility mode: package `' requested, but `rawfonts' provided. Package: rawfonts 1994/05/08 Low-level LaTeX 2.09 font compatibility (/home/tex/teTeX/texmf/tex/latex/tools/somedefs.sty Package: somedefs 1994/06/01 Toolkit for optional definitions ) LaTeX Font Info: Try loading font information for U+lasy on input line 36. (/home/tex/teTeX/texmf/tex/latex/base/ulasy.fd File: ulasy.fd 1996/11/20 v2.2dLaTeX symbol font definitions )))) (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size11.clo File: size11.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count83 \c@chapter=\count84 \c@section=\count85 \c@subsection=\count86 \c@subsubsection=\count87 \c@paragraph=\count88 \c@subparagraph=\count89 \c@figure=\count90 \c@table=\count91 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 Compatibility mode: definition of \rm ignored. Compatibility mode: definition of \sf ignored. Compatibility mode: definition of \tt ignored. Compatibility mode: definition of \bf ignored. Compatibility mode: definition of \it ignored. Compatibility mode: definition of \sl ignored. Compatibility mode: definition of \sc ignored. LaTeX Info: Redefining \cal on input line 622. LaTeX Info: Redefining \mit on input line 623. \bibindent=\dimen105 ) \@indexfile=\write3 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. (intro.tex Chapter 1. ) (dataStructure.tex LaTeX Font Info: Try loading font information for OMS+cmr on input line 8. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10.95> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 8. [1 ] LaTeX Font Info: Try loading font information for OMS+cmtt on input line 51. LaTeX Font Info: No file OMScmtt.fd. on input line 51. LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined (Font) using `OMS/cmsy/m/n' instead (Font) for symbol `textbraceleft' on input line 51. Overfull \hbox (2.18349pt too wide) in paragraph at lines 63--69 \OT1/cmr/m/n/10.95 list. The \OT1/cmtt/m/n/10.95 sizes \OT1/cmr/m/n/10.95 and \ OT1/cmtt/m/n/10.95 p[]vec \OT1/cmr/m/n/10.95 fields need never be ac-cessed di- rectly --- see the \OT1/cmtt/m/n/10.95 IVL[]listAndSize()\OT1/cmr/m/n/10.95 , [] ) (proto.tex [2] [3] Overfull \hbox (46.25853pt too wide) in paragraph at lines 199--199 []\OT1/cmtt/m/n/10.95 int IVL_initFromSubIVL ( IVL *subIVL, IVL *ivl, IV *keep listIV, IV *keepentriesIV ) ;[] [] Overfull \hbox (2.9712pt too wide) in paragraph at lines 220--229 \OT1/cmtt/m/n/10.95 newmaxnlist == maxnlist\OT1/cmr/m/n/10.95 , noth-ing is don e. Oth-er-wise, new stor-age for \OT1/cmtt/m/n/10.95 sizes[] \OT1/cmr/m/n/10.95 and \OT1/cmtt/m/n/10.95 p[]vec[] [] [4] LaTeX Font Info: External font `cmex10' loaded for size (Font) <10.95> on input line 329. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 329. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 329. Underfull \vbox (badness 10000) has occurred while \output is active [] [5] [6] LaTeX Warning: Citation `ash95-compressed-graphs' on page 7 undefined on input line 404. [7] [8]) (drivers.tex [9]) (main.ind [10] [11 ]) (main.aux) LaTeX Font Warning: Some font shapes were not available, defaults substituted. LaTeX Warning: There were undefined references. LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right. ) Here is how much of TeX's memory you used: 606 strings out of 10908 6292 string characters out of 72189 50903 words of memory out of 262141 3456 multiletter control sequences out of 9500 23452 words of font info for 88 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 23i,5n,21p,313b,385s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (11 pages, 32580 bytes). 84 \c@section=\count85 \c@subsection=\count86 \c@subsubsection=\count87 \c@paragraph=\count88 \c@subparagraph=\count89 \c@figure=\count90 \c@table=\count91 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 Compatibility mode: definition of \rm ignored. Compatibility mode: definition of \sf ignored. Compatibility mode: definition of \tt ignored. Compatibility mode: definition of \bf ignored. Compatibility mode: definition of \it ignored. Compatibility modeIVL/doc/main.tex010064400020550007177000000010730665065624700147570ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt IVL} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt IVL} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} IVL/doc/proto.tex010064400020550007177000000623250665016463200151750ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt IVL} methods} \label{section:IVL:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt IVL} object. \par \subsection{Basic methods} \label{subsection:IVL:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IVL * IVL_new ( void ) ; \end{verbatim} \index{IVL_new@{\tt IVL\_new()}} This method simply allocates storage for the {\tt IVL} structure and then sets the default fields by a call to {\tt IVL\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_setDefaultFields ( IVL *ivl ) ; \end{verbatim} \index{IVL_setDefaultFields@{\tt IVL\_setDefaultFields()}} This method sets the default fields of the object --- {\tt type = IVL\_NOTYPE}, {\tt maxnlist}, {\tt nlist} and {\tt tsize} are zero, {\tt incr} is {\tt 1024}, and {\tt sizes}, {\tt p\_vec} and {\tt chunk} are {\tt NULL}. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_clearData ( IVL *ivl ) ; \end{verbatim} \index{IVL_clearData@{\tt IVL\_clearData()}} This method clears any data allocated by this object and then sets the default fields with a call to {\tt IVL\_setDefaultFields()}. Any storage held by the {\tt Ichunk} structures is free'd, and if {\tt sizes} or {\tt p\_vec} are not {\tt NULL}, they are free'd. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_free ( IVL *ivl ) ; \end{verbatim} \index{IVL_free@{\tt IVL\_free()}} This method releases any storage by a call to {\tt IVL\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \par \subsection{Instance methods} \label{subsection:IVL:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_type ( IVL *ivl ) ; \end{verbatim} \index{IVL_type@{\tt IVL\_type()}} This method returns {\tt type}, the storage type. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_maxnlist ( IVL *ivl ) ; \end{verbatim} \index{IVL_maxnlist@{\tt IVL\_maxnlist()}} This method returns {\tt maxnlist}, the maximum number of lists. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_nlist ( IVL *ivl ) ; \end{verbatim} \index{IVL_nlist@{\tt IVL\_nlist()}} This method returns {\tt nlist}, the present number of lists. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_tsize ( IVL *ivl ) ; \end{verbatim} \index{IVL_tsize@{\tt IVL\_tsize()}} This method returns {\tt tsize}, the present number of list entries. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_incr ( IVL *ivl ) ; \end{verbatim} \index{IVL_incr@{\tt IVL\_incr()}} This method returns {\tt incr}, the storage increment. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_setincr ( IVL *ivl, int incr ) ; \end{verbatim} \index{IVL_setincr@{\tt IVL\_setincr()}} This method sets the storage increment to {\tt incr}. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL} or {\tt incr} is negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization and resizing methods} \label{subsection:IVL:proto:initializers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_init1 ( IVL *ivl, int type, int maxnlist ) ; \end{verbatim} \index{IVL_init@{\tt IVL\_init()}} This method is used when only the number of lists is known. Any previous data is cleared with a call to {\tt IVL\_clearData()}. The {\tt type} field is set. If {\tt maxnlist > 0}, storage is allocated for the {\tt sizes[]} and {\tt p\_vec[]} arrays and {\tt nlist} is set to {\tt maxnlist}. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL} or {\tt type} is invalid or {\tt maxnlist} is negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_init2 ( IVL *ivl, int type, int nlist, int tsize ) ; \end{verbatim} \index{IVL_init2@{\tt IVL\_init2()}} This method is used when the number of lists and their total size is known --- {\tt type} must be {\tt IVL\_CHUNKED}. The {\tt IVL\_init1()} initializer method is called. If {\tt tsize > 0} an {\tt Ichunk} object with {\tt tsize} entries is allocated. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL} or {\tt type} is not {\tt IVL\_CHUNKED} or if {\tt nlist} or {\tt tsize} are negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_init3 ( IVL *ivl, int type, int nlist, int sizes[] ) ; \end{verbatim} \index{IVL_init3@{\tt IVL\_init3()}} This method is used when the number of lists and the size of each list is known --- {\tt type} must be {\tt IVL\_CHUNKED} or {\tt IVL\_SOLO}. If {\tt type} is {\tt IVL\_CHUNKED}, then {\tt IVL\_init2()} is called to initialize the object, else {\tt type} is {\tt IVL\_SOLO} and {\tt IVL\_init1()} is called. The size and pointer for each list is then set using the value from the {\tt sizes[]} array. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, or if {\tt type} is not {\tt IVL\_CHUNKED} or {\tt IVL\_SOLO}, or if {\tt nlist} is nonpositive, or if {\tt sizes[]} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_initFromSubIVL ( IVL *subIVL, IVL *ivl, IV *keeplistIV, IV *keepentriesIV ) ; \end{verbatim} \index{IVL_initFromSubIVL@{\tt IVL\_initFromSubIVL()}} This method initializes the {\tt subIVL} object from the {\tt ivl} object. The lists found in {\tt keeplistIV} are placed into the {\tt subIVL} object; if {\tt keeplistIV} is {\tt NULL}, all lists are included. The list entries found in {\tt keepentriesIV} are placed into lists in the the {\tt subIVL} object; if {\tt keepentriesIV} is {\tt NULL}, all entries are included. \par \noindent {\it Return values:} 1 is a normal return, -1 means {\tt subIVL} is {\tt NULL}, -2 means {\tt ivl} is {\tt NULL}, -3 means {\tt keeplistIV} is invalid. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_setMaxnlist ( IVL *ivl, int newmaxnlist ) ; \end{verbatim} \index{IVL_setMaxnlist@{\tt IVL\_setMaxnlist()}} This method is used to resize the object by changing the maximum number of lists. If {\tt newmaxnlist == maxnlist}, nothing is done. Otherwise, new storage for {\tt sizes[]} and {\tt p\_vec[]} is allocated, the information for the first {\tt nlist} lists is copied over, and the old storage free'd. Note, {\tt maxnlist} is set to {\tt newmaxnlist} and {\tt nlist} is set to the minimum of {\tt nlist} and {\tt newmaxnlist}. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL} or if {\tt newmaxnlist} is negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_setNlist ( IVL *ivl, int newnlist ) ; \end{verbatim} \index{IVL_setNlist@{\tt IVL\_setNlist()}} This method is used to change the number of lists. If {\tt newnlist > maxnlist}, storage for the lists is increased via a call to the {\tt IVL\_setMaxnlist()} method. Then {\tt nlist} is set to {\tt newnlist}. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, or if {\tt newnlist} is negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{List manipulation methods} \label{subsection:IVL:proto:listmanip} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_listAndSize ( IVL *ivl, int ilist, int *psize, int **pivec) ; \end{verbatim} \index{IVL_listAndSize@{\tt IVL\_listAndSize()}} This method fills {\tt *psize} with {\tt sizes[ilist]} and {\tt *pivec} with {\tt p\_vec[ilist]}. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, or if {\tt ilist < 0} or {\tt ilist >= nlist} or if {\tt psize} or {\tt pivec} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * IVL_firstInList ( IVL *ivl, int ilist ) ; int * IVL_nextInList ( IVL *ivl, int ilist, int *pi ) ; \end{verbatim} \index{IVL_firstInList@{\tt IVL\_firstInList()}} \index{IVL_nextInList@{\tt IVL\_nextInList()}} These two methods are used as iterators, e.g., \begin{verbatim} for ( pi = IVL_firstInList(ivl, ilist) ; pi != NULL ; pi = IVL_nextInList(ivl, ilist, pi) ) { do something with entry *pi } \end{verbatim} \par \noindent {\it Error checking:} Each method checks to see if {\tt ivl} is {\tt NULL} or {\tt ilist < 0} or {\tt ilist >= nlist}, if so an error message is printed and the program exits. In method {\tt IVL\_firstInList()}, if {\tt sizes[ilist] > 0} and {\tt p\_vec[ilist] = NULL}, an error message is printed and the program exits. In method {\tt IVL\_nextInList()}, if {\tt pi} is not in the valid range for list {\tt ilist}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_setList ( IVL *ivl, int ilist, int isize, int ivec[] ) ; \end{verbatim} \index{IVL_setList@{\tt IVL\_setList()}} This method sets the size and (possibly) pointer to a list of entries. The behavior of the method depends on the type of the {\tt ivl} object. Here is the flow chart: \begin{center} \fbox{ \begin{minipage}{4 in} \begin{tabbing} XXX \= XXX \= XXX \= \kill if {\tt ilist >= maxnlist} then \\ \> the number of lists is increased via a call to {\tt IVL\_setMaxnlist()} \\ endif \\ if {\tt ilist >= nlist} then \\ \> {\tt nlist} is increased \\ endif \\ if {\tt isize = 0} then \\ \> release the storage for that list, reclaim storage if possible\\ else if {\tt type} is {\tt IVL\_UNKNOWN} then\\ \> set the pointer\\ else\\ \> if the present size of list {\tt ilist} is smaller than {\tt isize} then\\ \> \> get new storage for a new larger list\\ \> endif\\ \> set the size \\ \> if {\tt ivec} is not {\tt NULL} then \\ \>\> copy the entries \\ \> endif \\ endif \end{tabbing} \end{minipage} } \end{center} \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL} or {\tt ilist < 0} then an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_setPointerToList ( IVL *ivl, int ilist, int size, int ivec[] ) ; \end{verbatim} \index{IVL_setPointerToList@{\tt IVL\_setPointerToList()}} This method is similar to {\tt IVL\_setList()} but is used only with {\tt type = IVL\_CHUNKED}. It simply sets a size and pointer. The maximum number of lists and the number of lists are resized as necessary. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL} or {\tt type != IVL\_CHUNKED}. or {\tt ilist < 0} then an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:IVL:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_sizeOf ( IVL *ivl ) ; \end{verbatim} \index{IVL_sizeOf@{\tt IVL\_sizeOf()}} This method returns the number of bytes taken by this object. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_min ( IVL *ivl ) ; int IVL_max ( IVL *ivl ) ; int IVL_maxListSize ( IVL *ivl ) ; int IVL_sum ( IVL *ivl ) ; \end{verbatim} \index{IVL_min@{\tt IVL\_min()}} \index{IVL_max@{\tt IVL\_max()}} \index{IVL_maxListSize@{\tt IVL\_maxListSize()}} \index{IVL_sum@{\tt IVL\_sum()}} These methods return some simple information about the object. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL} then an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_sortUp ( IVL *ivl ) ; \end{verbatim} \index{IVL_sortUp@{\tt IVL\_sortUp()}} This method sorts each list into ascending order. \par \noindent {\it Error checking:} If {\tt ivl} is {\tt NULL} or {\tt nlist < 0} then an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * IVL_equivMap1 ( IVL *ivl ) ; IV * IVL_equivMap2 ( IVL *ivl ) ; \end{verbatim} \index{IVL_equivMap1@{\tt IVL\_equivMap1()}} \index{IVL_equivMap2@{\tt IVL\_equivMap2()}} Two lists are equivalent if their contents are identical. These methods are used to find the natural compressed graph of a matrix \cite{ash95-compressed-graphs}. The returned {\tt int} vector or {\tt IV} object has size {\tt ivl->nlist} and contains a map from the lists in {\tt ivl} to the lists in the new {\tt IVL} object. If {\tt nlist} is zero, {\tt NULL} is returned. \par \noindent {\it Error checking:} As usual, if {\tt ivl} is {\tt NULL} or {\tt nlist < 0} then an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_overwrite ( IVL *ivl, IV *oldToNewIV ) ; \end{verbatim} \index{IVL_overwrite@{\tt IVL\_overwrite()}} This method overwrite the entries in each list using an old-to-new vector. If an entry in a list is out of range, i.e., it is not in {\tt [0,size-1]} where {\tt size} is the size of {\tt oldToNewIV}, the entry is not changed. \par \noindent {\it Error checking:} If {\tt ivl} or {\tt oldToNewIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * IVL_mapEntries ( IVL *ivl, IV *mapIV ) ; \end{verbatim} \index{IVL_mapEntries@{\tt IVL\_mapEntries()}} This method creates and returns a new {\tt IVL} object. List {\tt ilist} in the new {\tt IVL} object contains the image of the entries in list {\tt ilist} of the old {\tt IVL} object, i.e., the old entries are mapped using the {\tt mapIV} map vector and duplicates are purged. \par \noindent {\it Error checking:} If {\tt ivl} or {\tt mapIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_absorbIVL ( IVL *ivl1, IVL *ivl2, IV *mapIV ) ; \end{verbatim} \index{IVL_absorbIVL@{\tt IVL\_absorbIVL()}} In this method, object {\tt ivl1} absorbs the lists and entries of object {\tt ivl2}. List {\tt ilist} of object {\tt ivl1} is mapped into list {\tt map[ilist]} of object {\tt ivl2}, where {\tt map[]} is the vector from the {\tt mapIV} object. All {\tt Ichunk} objects once owned by {\tt ivl2} are now owned by {\tt ivl1}. \par \noindent {\it Error checking:} If {\tt ivl1}, {\tt ivl2} or {\tt mapIV} is {\tt NULL}, or if the size pf {\tt mapIV} is not equal to the number of lists in {\tt ivl2}, or if the vector in {\tt mapIV} is {\tt NULL}, then an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * IVL_expand ( IVL *ivl, IV *eqmapIV ) ; \end{verbatim} \index{IVL_expand@{\tt IVL\_expand()}} This method was created in support of a symbolic factorization. An {\tt IVL} object is constructed using a compressed graph. it must be expanded to reflect the compressed graph. The number of lists does not change (there is one list per front) but the size of each list may change. so we create and return a new {\tt IVL} object that contains entries for the uncompressed graph. \par \noindent {\it Error checking:} If {\tt ivl} or {\tt eqmapIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Miscellaneous methods} \label{subsection:IVL:proto:miscellaneous} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IVL * IVL_make9P ( int n1, int n2, int ncomp ) ; \end{verbatim} \index{IVL_make9P@{\tt IVL\_make9P()}} This method returns an {\tt IVL} object that contains the full adjacency structure for a 9-point operator on a ${\tt n1} \times {\tt n2}$ grid with {\tt ncomp} components at each grid point. \par \noindent {\it Error checking:} If {\tt n1}, {\tt n2} or {\tt ncomp} is less than or equal to zero, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * IVL_make13P ( int n1, int n2 ) ; \end{verbatim} \index{IVL_make13P@{\tt IVL\_make13P()}} This method returns an {\tt IVL} object that contains the full adjacency structure for a 13-point two dimensional operator on a ${\tt n1} \times {\tt n2}$ grid. \par \noindent {\it Error checking:} If {\tt n1} or {\tt n2} is less than or equal to zero, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * IVL_make5P ( int n1, int n2 ) ; \end{verbatim} \index{IVL_make5P@{\tt IVL\_make5P()}} This method returns an {\tt IVL} object that contains the full adjacency structure for a 5-point two dimensional operator on a ${\tt n1} \times {\tt n2}$ grid. \par \noindent {\it Error checking:} If {\tt n1} or {\tt n2} is less than or equal to zero, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * IVL_make27P ( int n1, int n2, int ncomp ) ; \end{verbatim} \index{IVL_make27P@{\tt IVL\_make27P()}} This method returns an {\tt IVL} object that contains the full adjacency structure for a 27-point operator on a ${\tt n1} \times {\tt n2} \times {\tt n3}$ grid with {\tt ncomp} components at each grid point. \par \noindent {\it Error checking:} If {\tt n1}, {\tt n2}, {\tt n3} or {\tt ncomp} is less than or equal to zero, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:IVL:proto:IO} \par There are the usual eight IO routines. The file structure of a {\tt IVL} object is simple: {\tt type}, {\tt nlist} and {\tt tsize}, followed by {\tt sizes[nlist]}, followed by the lists pointed to by {\tt p\_vec[]}. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_readFromFile ( IVL *ivl, char *fn ) ; \end{verbatim} \index{IVL_readFromFile@{\tt IVL\_readFromFile()}} \par This method reads an {\tt IVL} object from a file. If the the file can be opened successfully, the method calls {\tt IVL\_readFromFormattedFile()} or {\tt IVL\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt ivl} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.ivlf} (for a formatted file) or {\tt *.ivlb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_readFromFormattedFile ( IVL *ivl, FILE *fp ) ; \end{verbatim} \index{IVL_readFromFormattedFile@{\tt IVL\_readFromFormattedFile()}} \par This method reads an {\tt IVL} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt ivl} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_readFromBinaryFile ( IVL *ivl, FILE *fp ) ; \end{verbatim} \index{IVL_readFromBinaryFile@{\tt IVL\_readFromBinaryFile()}} \par This method reads an {\tt IVL} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt ivl} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_writeToFile ( IVL *ivl, char *fn ) ; \end{verbatim} \index{IVL_writeToFile@{\tt IVL\_writeToFile()}} \par This method writes an {\tt IVL} object to a file. If the the file can be opened successfully, the method calls {\tt IVL\_writeFromFormattedFile()} or {\tt IVL\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt ivl} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.ivlf} (for a formatted file) or {\tt *.ivlb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_writeToFormattedFile ( IVL *ivl, FILE *fp ) ; \end{verbatim} \index{IVL_writeToFormattedFile@{\tt IVL\_writeToFormattedFile()}} \par This method writes an {\tt IVL} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt ivl} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_writeToBinaryFile ( IVL *ivl, FILE *fp ) ; \end{verbatim} \index{IVL_writeToBinaryFile@{\tt IVL\_writeToBinaryFile()}} \par This method writes an {\tt IVL} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt ivl} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_writeForHumanEye ( IVL *ivl, FILE *fp ) ; \end{verbatim} \index{IVL_writeForHumanEye@{\tt IVL\_writeForHumanEye()}} \par This method writes an {\tt IVL} object to a file in an easily readable format. The method {\tt IVL\_writeStats()} is called to write out the header and statistics. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt ivl} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IVL_writeStats ( IVL *ivl, FILE *fp ) ; \end{verbatim} \index{IVL_writeStats@{\tt IVL\_writeStats()}} \par This method writes some statistics about an {\tt IVL} object to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt ivl} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} -- \item \begin{verbatim} void IVL_overwrite ( IVL *ivl, IV *oldToNewIV ) ; \end{verbatim} \index{IVL_overwrite@{\tt IVL\_overwrite()}} This method overwrite the entries in each list using an old-to-new vector. If an entry in a list is out of range, i.e., it is not in {\tt [0,size-1]} where {\tt sIVL/doc/main.idx010064400020550007177000000045130665016464000147340ustar00clevecompmath00000400000006\indexentry{IVL_new@{\tt IVL\_new()}}{2} \indexentry{IVL_setDefaultFields@{\tt IVL\_setDefaultFields()}}{2} \indexentry{IVL_clearData@{\tt IVL\_clearData()}}{3} \indexentry{IVL_free@{\tt IVL\_free()}}{3} \indexentry{IVL_type@{\tt IVL\_type()}}{3} \indexentry{IVL_maxnlist@{\tt IVL\_maxnlist()}}{3} \indexentry{IVL_nlist@{\tt IVL\_nlist()}}{3} \indexentry{IVL_tsize@{\tt IVL\_tsize()}}{3} \indexentry{IVL_incr@{\tt IVL\_incr()}}{3} \indexentry{IVL_setincr@{\tt IVL\_setincr()}}{3} \indexentry{IVL_init@{\tt IVL\_init()}}{4} \indexentry{IVL_init2@{\tt IVL\_init2()}}{4} \indexentry{IVL_init3@{\tt IVL\_init3()}}{4} \indexentry{IVL_initFromSubIVL@{\tt IVL\_initFromSubIVL()}}{4} \indexentry{IVL_setMaxnlist@{\tt IVL\_setMaxnlist()}}{4} \indexentry{IVL_setNlist@{\tt IVL\_setNlist()}}{4} \indexentry{IVL_listAndSize@{\tt IVL\_listAndSize()}}{5} \indexentry{IVL_firstInList@{\tt IVL\_firstInList()}}{5} \indexentry{IVL_nextInList@{\tt IVL\_nextInList()}}{5} \indexentry{IVL_setList@{\tt IVL\_setList()}}{5} \indexentry{IVL_setPointerToList@{\tt IVL\_setPointerToList()}}{6} \indexentry{IVL_sizeOf@{\tt IVL\_sizeOf()}}{6} \indexentry{IVL_min@{\tt IVL\_min()}}{6} \indexentry{IVL_max@{\tt IVL\_max()}}{6} \indexentry{IVL_maxListSize@{\tt IVL\_maxListSize()}}{6} \indexentry{IVL_sum@{\tt IVL\_sum()}}{6} \indexentry{IVL_sortUp@{\tt IVL\_sortUp()}}{7} \indexentry{IVL_equivMap1@{\tt IVL\_equivMap1()}}{7} \indexentry{IVL_equivMap2@{\tt IVL\_equivMap2()}}{7} \indexentry{IVL_overwrite@{\tt IVL\_overwrite()}}{7} \indexentry{IVL_mapEntries@{\tt IVL\_mapEntries()}}{7} \indexentry{IVL_absorbIVL@{\tt IVL\_absorbIVL()}}{7} \indexentry{IVL_expand@{\tt IVL\_expand()}}{7} \indexentry{IVL_make9P@{\tt IVL\_make9P()}}{8} \indexentry{IVL_make13P@{\tt IVL\_make13P()}}{8} \indexentry{IVL_make5P@{\tt IVL\_make5P()}}{8} \indexentry{IVL_make27P@{\tt IVL\_make27P()}}{8} \indexentry{IVL_readFromFile@{\tt IVL\_readFromFile()}}{8} \indexentry{IVL_readFromFormattedFile@{\tt IVL\_readFromFormattedFile()}}{8} \indexentry{IVL_readFromBinaryFile@{\tt IVL\_readFromBinaryFile()}}{9} \indexentry{IVL_writeToFile@{\tt IVL\_writeToFile()}}{9} \indexentry{IVL_writeToFormattedFile@{\tt IVL\_writeToFormattedFile()}}{9} \indexentry{IVL_writeToBinaryFile@{\tt IVL\_writeToBinaryFile()}}{9} \indexentry{IVL_writeForHumanEye@{\tt IVL\_writeForHumanEye()}}{9} \indexentry{IVL_writeStats@{\tt IVL\_writeStats()}}{9} IVL/doc/main.ind010064400020550007177000000027620653511015200147150ustar00clevecompmath00000400000006\begin{theindex} \item {\tt IVL\_absorbIVL()}, 7 \item {\tt IVL\_clearData()}, 3 \item {\tt IVL\_equivMap1()}, 6 \item {\tt IVL\_equivMap2()}, 6 \item {\tt IVL\_expand()}, 7 \item {\tt IVL\_firstInList()}, 5 \item {\tt IVL\_free()}, 3 \item {\tt IVL\_incr()}, 3 \item {\tt IVL\_init()}, 4 \item {\tt IVL\_init2()}, 4 \item {\tt IVL\_init3()}, 4 \item {\tt IVL\_listAndSize()}, 4 \item {\tt IVL\_make13P()}, 7 \item {\tt IVL\_make27P()}, 8 \item {\tt IVL\_make5P()}, 7 \item {\tt IVL\_make9P()}, 7 \item {\tt IVL\_mapEntries()}, 7 \item {\tt IVL\_max()}, 6 \item {\tt IVL\_maxListSize()}, 6 \item {\tt IVL\_maxnlist()}, 3 \item {\tt IVL\_min()}, 6 \item {\tt IVL\_new()}, 2 \item {\tt IVL\_nextInList()}, 5 \item {\tt IVL\_nlist()}, 3 \item {\tt IVL\_overwrite()}, 6 \item {\tt IVL\_readFromBinaryFile()}, 8 \item {\tt IVL\_readFromFile()}, 8 \item {\tt IVL\_readFromFormattedFile()}, 8 \item {\tt IVL\_setDefaultFields()}, 2 \item {\tt IVL\_setincr()}, 3 \item {\tt IVL\_setList()}, 5 \item {\tt IVL\_setMaxnlist()}, 4 \item {\tt IVL\_setNlist()}, 4 \item {\tt IVL\_setPointerToList()}, 6 \item {\tt IVL\_sizeOf()}, 6 \item {\tt IVL\_sortUp()}, 6 \item {\tt IVL\_sum()}, 6 \item {\tt IVL\_tsize()}, 3 \item {\tt IVL\_type()}, 3 \item {\tt IVL\_writeForHumanEye()}, 9 \item {\tt IVL\_writeStats()}, 9 \item {\tt IVL\_writeToBinaryFile()}, 8 \item {\tt IVL\_writeToFile()}, 8 \item {\tt IVL\_writeToFormattedFile()}, 8 \end{theindex} IVL/doc/main.ilg010064400020550007177000000004570653511015200147150ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (44 entries accepted, 0 rejected). Sorting entries....done (250 comparisons). Generating output file main.ind....done (48 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. IVL/doc/makefile010064400020550007177000000000270654276745100150070ustar00clevecompmath00000400000006clean : - rm -f *.dvi IVL/doc/drivers.tex010064400020550007177000000060400657600425200154760ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt IVL} object} \label{section:IVL:drivers} \par This section contains brief descriptions of six driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program reads in a {\tt IVL} object from {\tt inFile} and writes out the object to {\tt outFile} \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt IVL} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt IVL} object. It must be of the form {\tt *.ivlf} or {\tt *.ivlb}. The {\tt IVL} object is read from the file via the {\tt IVL\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt IVL} object. It must be of the form {\tt *.ivlf} or {\tt *.ivlb}. The {\tt IVL} object is written to the file via the {\tt IVL\_writeToFile()} method. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testExpand msglvl msgFile inIVLfile inEqmapFile outIVLfile \end{verbatim} This program is used to test the expand function. One application is the symbolic factorization. We need the adjacency structure of the factor matrix. We could compute it directly from the original graph, or we could compute the adjacency structure of the compressed graph and then expand it into the full adjacency structure. The second method is usually faster. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt IVL} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inIVLfile} parameter is the input file for the first, unexpanded {\tt IVL} object. It must be of the form {\tt *.ivlf} or {\tt *.ivlb}. The {\tt IVL} object is read from the file via the {\tt IVL\_readFromFile()} method. \item The {\tt inEqmapFile} parameter is the input file for the map from uncompressed vertices to compressed vertices. It must be of the form {\tt *.ivf} or {\tt *.ivb}. The {\tt IV} object is read from the file via the {\tt IV\_readFromFile()} method. \item The {\tt outIVLfile} parameter is the output file for the second, expanded {\tt IVL} object. It must be of the form {\tt *.ivlf} or {\tt *.ivlb}. The {\tt IVL} object is read from the file via the {\tt IVL\_readFromFile()} method. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} ad from the file via the {\tt IVL\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt IVL} object. It must be of the form {\tt *.ivlf} or {\tt *.ivlb}. The {\tt IVL} object is written to the file via the {\tt IVL\_writeToFile()} method. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testExpand msglvl msgFile inIVLfile inEqmapFile outIVLfile \end{verbatim} This program is usedIVL/drivers/do_expand010075500020550007177000000007600657427725300161140ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inETreeFile = $matrices/$matrix/nd.etreef set inETreeFile = nd.etreef set inETreeFile = /local1/ARPA/matrices/i4a/symb1.ivlb set inEqmapFile = /local1/ARPA/matrices/i4a/map1.ivb set outETreeFile = $matrices/$matrix/nd.etreeb set outETreeFile = /local1/ARPA/matrices/i4a/symb0.ivlf set outETreeFile = none set msglvl = 1 set msgFile = stdout testExpand $msglvl $msgFile $inETreeFile $inEqmapFile $outETreeFile IVL/drivers/do_testIO010075500020550007177000000005160657427737100160440ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inFile = $matrices/$matrix/symb.ivlf set inFile = symb.ivlf set inFile = /local1/ARPA/matrices/i4a/symb0.ivlb set outFile = $matrices/$matrix/symb.ivlb set outFile = none set msglvl = 3 set msgFile = stdout testIO $msglvl $msgFile $inFile $outFile IVL/drivers/makefile010064400020550007177000000006450665314251400157140ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testExpand \ testIO drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testExpand : testExpand.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testIO : testIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} IVL/drivers/testExpand.c010064400020550007177000000104200657430076600164760ustar00clevecompmath00000400000006/* testExpand.c */ #include "../IVL.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------- read in an IVL object and an equivalence map, expand the IVL object and optionally write to a file. created -- 98sep05, cca ------------------------------------------------------- */ { char *inEqmapFileName, *inIVLfileName, *outIVLfileName ; double t1, t2 ; IVL *ivl, *ivl2 ; FILE *msgFile ; int msglvl, rc ; IV *eqmapIV ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inIVLfile inEqmapFile outIVLfile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inIVLfile -- input file, must be *.ivlf or *.ivlb" "\n inEqmapFile -- input file, must be *.ivf or *.ivb" "\n outIVLfile -- output file, must be *.ivlf or *.ivlb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inIVLfileName = argv[3] ; inEqmapFileName = argv[4] ; outIVLfileName = argv[5] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inIVLfile -- %s" "\n inEqmapFile -- %s" "\n outIVLfile -- %s" "\n", argv[0], msglvl, argv[2], inIVLfileName, inEqmapFileName, outIVLfileName) ; fflush(msgFile) ; /* ---------------------- read in the IVL object ---------------------- */ if ( strcmp(inIVLfileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } ivl = IVL_new() ; IVL_init1(ivl, IVL_CHUNKED, 0) ; MARKTIME(t1) ; rc = IVL_readFromFile(ivl, inIVLfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in ivl from file %s", t2 - t1, inIVLfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IVL_readFromFile(%p,%s)", rc, ivl, inIVLfileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading IVL object from file %s", inIVLfileName) ; if ( msglvl > 2 ) { IVL_writeForHumanEye(ivl, msgFile) ; } else { IVL_writeStats(ivl, msgFile) ; } fflush(msgFile) ; /* ------------------------------------- read in the equivalence map IV object ------------------------------------- */ if ( strcmp(inEqmapFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } eqmapIV = IV_new() ; MARKTIME(t1) ; rc = IV_readFromFile(eqmapIV, inEqmapFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in eqmapIV from file %s", t2 - t1, inEqmapFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, eqmapIV, inEqmapFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading IV object from file %s", inEqmapFileName) ; if ( msglvl > 2 ) { IV_writeForHumanEye(eqmapIV, msgFile) ; } else { IV_writeStats(eqmapIV, msgFile) ; } fflush(msgFile) ; /* --------------------- expand the IVL object --------------------- */ MARKTIME(t1) ; ivl2 = IVL_expand(ivl, eqmapIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : expand the IVL object", t2 - t1) ; fprintf(msgFile, "\n\n after expanding the IVL object") ; if ( msglvl > 2 ) { IVL_writeForHumanEye(ivl2, msgFile) ; } else { IVL_writeStats(ivl2, msgFile) ; } fflush(msgFile) ; /* ------------------------ write out the IVL object ------------------------ */ if ( strcmp(outIVLfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IVL_writeToFile(ivl2, outIVLfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write ivl to file %s", t2 - t1, outIVLfileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IVL_writeToFile(%p,%s)", rc, ivl2, outIVLfileName) ; } /* --------------------- free the IVL object --------------------- */ IVL_free(ivl) ; IV_free(eqmapIV) ; IVL_free(ivl2) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ IVL/drivers/testIO.c010064400020550007177000000055360657427764200156100ustar00clevecompmath00000400000006/* testIO.c */ #include "../IVL.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- test IVL_readFromFile and IVL_writeToFile, useful for translating between formatted *.ivlf and binary *.ivlb files. created -- 98sep05, cca ------------------------------------------------- */ { char *inIVLfileName, *outIVLfileName ; double t1, t2 ; int msglvl, rc ; IVL *ivl ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.ivlf or *.ivlb" "\n outFile -- output file, must be *.ivlf or *.ivlb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inIVLfileName = argv[3] ; outIVLfileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inIVLfileName, outIVLfileName) ; fflush(msgFile) ; /* ---------------------- read in the IVL object ---------------------- */ if ( strcmp(inIVLfileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } ivl = IVL_new() ; IVL_init1(ivl, IVL_CHUNKED, 0) ; MARKTIME(t1) ; rc = IVL_readFromFile(ivl, inIVLfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in ivl from file %s", t2 - t1, inIVLfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IVL_readFromFile(%p,%s)", rc, ivl, inIVLfileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading IVL object from file %s", inIVLfileName) ; if ( msglvl > 2 ) { IVL_writeForHumanEye(ivl, msgFile) ; } else { IVL_writeStats(ivl, msgFile) ; } fflush(msgFile) ; /* ------------------------ write out the IVL object ------------------------ */ if ( strcmp(outIVLfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IVL_writeToFile(ivl, outIVLfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write ivl to file %s", t2 - t1, outIVLfileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IVL_writeToFile(%p,%s)", rc, ivl, outIVLfileName) ; } /* ------------------- free the IVL object ------------------- */ IVL_free(ivl) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Ideq.h010064400020550007177000000000740653561656500131460ustar00clevecompmath00000400000006#ifndef _Ideq_ #define _Ideq_ #include "Ideq/Ideq.h" #endif Ideq/Ideq.h010064400020550007177000000115330653410710300140100ustar00clevecompmath00000400000006/* Ideq.h */ #include "../IV.h" #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ Ideq -- dequeue with integer ids maxsize -- maxmimum size of the deq head -- head of the list tail -- tail of the list iv -- IV object to manage dequeue created -- 96jun06, cca ------------------------------------------------------------------ */ typedef struct _Ideq Ideq ; struct _Ideq { int maxsize ; int head ; int tail ; IV iv ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ------ methods found in basics.c -------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------- create and return a new instance of the Ideq object created -- 96jun06, cca ----------------------------------------------------- */ Ideq * Ideq_new ( void ) ; /* ------------------------------------------- set the default fields for an Ideq object created -- 96jun06, cca ------------------------------------------- */ void Ideq_setDefaultFields ( Ideq *deq ) ; /* ----------------------- clear the data fields created -- 96jun06, cca ----------------------- */ void Ideq_clearData ( Ideq *deq ) ; /* ----------------------- free the Ideq object created -- 96jun06, cca ----------------------- */ void Ideq_free ( Ideq *deq ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ------ methods found in resize.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------ resize the deque if the new size is large enough then copy the old data return 1 else error, return -1 endif created -- 96jun06, cca ------------------------------------ */ int Ideq_resize ( Ideq *deq, int newsize ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ------ methods found in util.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- clear the dequeue, created -- 96jun06, cca ----------------------- */ void Ideq_clear ( Ideq *deq ) ; /* --------------------------------- return the head of the dequeue, return -1 if the dequeue is empty created -- 96jun06, cca --------------------------------- */ int Ideq_head ( Ideq *deq ) ; /* ------------------------------------------ return and remove the head of the dequeue, return -1 if the dequeue is empty created -- 96jun06, cca ------------------------------------------ */ int Ideq_removeFromHead ( Ideq *deq ) ; /* --------------------------------------- insert value at head of dequeue return value 1 --> value inserted -1 --> no room in dequeue, must resize created -- 96jun06, cca --------------------------------------- */ int Ideq_insertAtHead ( Ideq *deq, int val ) ; /* --------------------------------- return the tail of the dequeue, return -1 if the dequeue is empty created -- 96jun06, cca --------------------------------- */ int Ideq_tail ( Ideq *deq ) ; /* ------------------------------------------ return and remove the tail of the dequeue, return -1 if the dequeue is empty created -- 96jun06, cca ------------------------------------------ */ int Ideq_removeFromTail ( Ideq *deq ) ; /* --------------------------------------- insert value at tail of dequeue return value 1 --> value inserted -1 --> no room in dequeue, must resize created -- 96jun06, cca --------------------------------------- */ int Ideq_insertAtTail ( Ideq *deq, int val ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ------ methods found in IO.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------ purpose -- write the contents of the dequeue to a file in a human readable format created -- 98feb11, cca ------------------------------------------------------ */ void Ideq_writeForHumanEye ( Ideq *dequeue, FILE *fp ) ; /*--------------------------------------------------------------------*/ Ideq/makefile010064400020550007177000000001410663622362000144540ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean Ideq/src/makefile010064400020550007177000000006760663602513000152540ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Ideq $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(resize.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG Ideq/src/makeGlobalLib010064400020550007177000000005740660026105400161570ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Ideq SRC = basics.c \ IO.c \ resize.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Ideq/src/IO.c010064400020550007177000000025260662033637100142300ustar00clevecompmath00000400000006/* IO.c */ #include "../Ideq.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- write the contents of the dequeue to a file in a human readable format created -- 98feb11, cca ------------------------------------------------------ */ void Ideq_writeForHumanEye ( Ideq *dequeue, FILE *fp ) { int ii ; /* --------------- check the input --------------- */ if ( dequeue == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Ideq_writeForHumanEye(%p,%p)" "\n bad input\n", dequeue, fp) ; exit(-1) ; } fprintf(fp, "\n\n Ideq : maxsize = %d, head = %d, tail = %d\n", dequeue->maxsize, dequeue->head, dequeue->tail) ; if ( dequeue->head != -1 && dequeue->tail != -1) { if ( dequeue->head <= dequeue->tail ) { for ( ii = dequeue->head ; ii <= dequeue->tail ; ii++ ) { fprintf(fp, " %d", IV_entry(&dequeue->iv, ii)) ; } } else { for ( ii = dequeue->head ; ii < dequeue->maxsize ; ii++ ) { fprintf(fp, " %d", IV_entry(&dequeue->iv, ii)) ; } for ( ii = 0 ; ii <= dequeue->tail ; ii++ ) { fprintf(fp, " %d", IV_entry(&dequeue->iv, ii)) ; } } } return ; } /*--------------------------------------------------------------------*/ Ideq/src/basics.c010064400020550007177000000035250653410710200151550ustar00clevecompmath00000400000006/* basics.c */ #include "../Ideq.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- create and return a new instance of the Ideq object created -- 96jun06, cca ----------------------------------------------------- */ Ideq * Ideq_new ( void ) { Ideq *deq ; ALLOCATE(deq, struct _Ideq, 1) ; Ideq_setDefaultFields(deq) ; return(deq) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- set the default fields for an Ideq object created -- 96jun06, cca ------------------------------------------- */ void Ideq_setDefaultFields ( Ideq *deq ) { if ( deq == NULL ) { fprintf(stderr, "\n fatal error in Ideq_setDefaultFields(%p)" "\n deq is NULL\n", deq) ; exit(-1) ; } deq->maxsize = 0 ; deq->head = -1 ; deq->tail = -1 ; IV_setDefaultFields(&deq->iv) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields created -- 96jun06, cca ----------------------- */ void Ideq_clearData ( Ideq *deq ) { if ( deq == NULL ) { fprintf(stderr, "\n fatal error in Ideq_clearData(%p)" "\n deq is NULL\n", deq) ; exit(-1) ; } IV_clearData(&deq->iv) ; Ideq_setDefaultFields(deq) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- free the Ideq object created -- 96jun06, cca ----------------------- */ void Ideq_free ( Ideq *deq ) { if ( deq == NULL ) { fprintf(stderr, "\n fatal error in Ideq_free(%p)" "\n deq is NULL\n", deq) ; exit(-1) ; } Ideq_clearData(deq) ; FREE(deq) ; return ; } /*--------------------------------------------------------------------*/ Ideq/src/resize.c010064400020550007177000000032620653410710300152110ustar00clevecompmath00000400000006/* resize.c */ #include "../Ideq.h" /*--------------------------------------------------------------------*/ /* ------------------------------------ resize the deque if the new size is large enough then copy the old data return 1 else error, return -1 endif created -- 96jun06, cca ------------------------------------ */ int Ideq_resize ( Ideq *deq, int newsize ) { int count, head, j, size, tail ; int *ivec, *tmp ; /* --------------- check the input --------------- */ if ( deq == NULL || newsize < 0 ) { fprintf(stderr, "\n fatal error in Ideq_resize(%p,%d)" "\n bad input\n", deq, newsize) ; exit(-1) ; } /* --------------------------------------- check that the new size is large enough --------------------------------------- */ if ( deq->tail >= deq->head ) { size = deq->tail - deq->head + 1 ; } else { size = deq->tail + deq->iv.size - deq->head + 1 ; } if ( size > newsize ) { return(-1) ; } /* --------------------- create the new vector --------------------- */ tmp = IVinit(size, -1) ; if ( (j = deq->head) != -1 ) { ivec = deq->iv.vec ; count = 0 ; while ( j != deq->tail ) { tmp[count++] = ivec[j] ; if ( j == size - 1 ) { j = 0 ; } else { j++ ; } } tmp[count++] = ivec[j] ; head = 0 ; tail = count - 1 ; } else { head = tail = -1 ; } Ideq_clearData(deq) ; IV_init(&deq->iv, newsize, NULL) ; if ( size > 0 ) { IVcopy(size, deq->iv.vec, tmp) ; } IVfree(tmp) ; deq->head = head ; deq->tail = tail ; deq->maxsize = newsize ; return(1) ; } /*--------------------------------------------------------------------*/ Ideq/src/util.c010064400020550007177000000126140653410710300146660ustar00clevecompmath00000400000006/* util.c */ #include "../Ideq.h" /*--------------------------------------------------------------------*/ /* ----------------------- clear the dequeue, created -- 96jun06, cca ----------------------- */ void Ideq_clear ( Ideq *deq ) { /* --------------- check the input --------------- */ if ( deq == NULL ) { fprintf(stderr, "\n fatal error in Ideq_clear(%p)" "\n bad input\n", deq) ; exit(-1) ; } deq->head = deq->tail = -1 ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------- return the head of the dequeue, return -1 if the dequeue is empty created -- 96jun06, cca --------------------------------- */ int Ideq_head ( Ideq *deq ) { int val ; /* --------------- check the input --------------- */ if ( deq == NULL ) { fprintf(stderr, "\n fatal error in Ideq_head(%p)" "\n bad input\n", deq) ; exit(-1) ; } if ( deq->head == -1 ) { val = -1 ; } else { val = deq->iv.vec[deq->head] ; } return(val) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ return and remove the head of the dequeue, return -1 if the dequeue is empty created -- 96jun06, cca ------------------------------------------ */ int Ideq_removeFromHead ( Ideq *deq ) { int val ; /* --------------- check the input --------------- */ if ( deq == NULL ) { fprintf(stderr, "\n fatal error in Ideq_removeFromHead(%p)" "\n bad input\n", deq) ; exit(-1) ; } if ( deq->head == -1 ) { val = -1 ; } else { val = deq->iv.vec[deq->head] ; if ( deq->head == deq->tail ) { deq->head = deq->tail = -1 ; } else if ( deq->head == deq->iv.size - 1 ) { deq->head = 0 ; } else { deq->head++ ; } } return(val) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- insert value at head of dequeue return value 1 --> value inserted -1 --> no room in dequeue, must resize created -- 96jun06, cca --------------------------------------- */ int Ideq_insertAtHead ( Ideq *deq, int val ) { int rc, size ; int *ivec ; /* --------------- check the input --------------- */ if ( deq == NULL ) { fprintf(stderr, "\n fatal error in Ideq_insertAtHead(%p,%d)" "\n bad input\n", deq, val) ; exit(-1) ; } ivec = deq->iv.vec ; size = deq->iv.size ; if ( deq->head == -1 ) { ivec[0] = val ; deq->head = deq->tail = 0 ; rc = 1 ; } else { if ( deq->head == 0 ) { if ( deq->tail == size - 1 ) { rc = -1 ; } else { ivec[(deq->head = size - 1)] = val ; rc = 1 ; } } else if ( deq->tail == deq->head - 1 ) { rc = -1 ; } else { ivec[--deq->head] = val ; rc = 1 ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* --------------------------------- return the tail of the dequeue, return -1 if the dequeue is empty created -- 96jun06, cca --------------------------------- */ int Ideq_tail ( Ideq *deq ) { int val ; /* --------------- check the input --------------- */ if ( deq == NULL ) { fprintf(stderr, "\n fatal error in Ideq_tail(%p)" "\n bad input\n", deq) ; exit(-1) ; } if ( deq->tail == -1 ) { val = -1 ; } else { val = deq->iv.vec[deq->tail] ; } return(val) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ return and remove the tail of the dequeue, return -1 if the dequeue is empty created -- 96jun06, cca ------------------------------------------ */ int Ideq_removeFromTail ( Ideq *deq ) { int val ; /* --------------- check the input --------------- */ if ( deq == NULL ) { fprintf(stderr, "\n fatal error in Ideq_removeFromTail(%p)" "\n bad input\n", deq) ; exit(-1) ; } if ( deq->tail == -1 ) { val = -1 ; } else { val = deq->iv.vec[deq->tail] ; if ( deq->head == deq->tail ) { deq->head = deq->tail = -1 ; } else if ( deq->tail == 0 ) { deq->tail = deq->iv.size - 1 ; } else { deq->tail-- ; } } return(val) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- insert value at tail of dequeue return value 1 --> value inserted -1 --> no room in dequeue, must resize created -- 96jun06, cca --------------------------------------- */ int Ideq_insertAtTail ( Ideq *deq, int val ) { int rc, size ; int *ivec ; /* --------------- check the input --------------- */ if ( deq == NULL ) { fprintf(stderr, "\n fatal error in Ideq_insertAtTail(%p,%d)" "\n bad input\n", deq, val) ; exit(-1) ; } ivec = deq->iv.vec ; size = deq->iv.size ; if ( deq->tail == -1 ) { ivec[0] = val ; deq->head = deq->tail = 0 ; rc = 1 ; } else { if ( deq->tail == size - 1 ) { if ( deq->head == 0 ) { rc = -1 ; } else { ivec[(deq->tail = 0)] = val ; rc = 1 ; } } else if ( deq->tail + 1 == deq->head ) { rc = -1 ; } else { ivec[++deq->tail] = val ; rc = 1 ; } } return(rc) ; } /*--------------------------------------------------------------------*/ Ideq/doc/004275500020550007177000000000000654276745100135455ustar00clevecompmath00000400000006Ideq/doc/dataStructure.tex010064000020550007177000000007500653410710300170710ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:Ideq:dataStructure} \par The {\tt Ideq} object has four fields. \begin{itemize} \item {\tt int maxsize} : maximum size of the dequeue. \item {\tt int head} : head of the list. \item {\tt int tail} : tail of the list. \item {\tt IV iv} : an {\tt IV} object to hold the list vector. \end{itemize} A correctly initialized and nontrivial {\tt Ideq} object will have {\tt maxsize > 0}. When the dequeue is empty, {\tt head = tail = -1}. Ideq/doc/intro.tex010064000020550007177000000014730653552761400154130ustar00clevecompmath00000400000006\chapter{{\tt Ideq}: Integer Dequeue} \par The {\tt Ideq} is a object that manages a {\it dequeue}, a list data structure that supports inserts and deletes at both the head and the tail of the list. We wrote this application in support of a max flow code where visiting an out-edge put a vertex on the head of the list and visiting an in-edge put a vertex on the tail of the list. The goal was to be close to a depth first traversal of the network. This object is also used in multithreaded and MPI factorizations and forward and back solves, where each process must perform a bottom-up or top-down traversal of a tree. The {\tt Ideq} object is used to specify which nodes of the tree to visit (possibly repeatedly) in which order. \par The dequeue has fixed size though it can grow using the {\tt Ideq\_resize()} method. \par Ideq/doc/main.aux010064400020550007177000000023220653552761700152020ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space Ideq}: Integer Dequeue}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:Ideq:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space Ideq} methods}{1}} \newlabel{section:Ideq:proto}{{1.2}{1}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:Ideq:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initializer methods}{2}} \newlabel{subsection:Ideq:proto:initializers}{{1.2.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{3}} \newlabel{subsection:Ideq:proto:utilities}{{1.2.3}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}IO methods}{4}} \newlabel{subsection:Ideq:proto:IO}{{1.2.4}{4}} ng\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:Ideq:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\striIdeq/doc/main.log010064400020550007177000000025170653552761700151740ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 4 JUN 1998 07:30 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. ) (dataStructure.tex) (proto.tex [1 ] [2] [3]) (main.ind [4] [5 ]) (main.aux) ) Here is how much of TeX's memory you used: 204 strings out of 11977 2105 string characters out of 87269 33311 words of memory out of 262141 2141 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,5n,17p,181b,262s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (5 pages, 9880 bytes). Ideq/doc/main.tex010064400020550007177000000011230665065625100151760ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Ideq} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Ideq} : {\it DRAFT} \quad \today \hrulefill} % \section{{\tt Ideq}: Integer Dequeue} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} Ideq/doc/proto.tex010064400020550007177000000205050653552754500154270ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Ideq} methods} \label{section:Ideq:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Ideq} object. \par \subsection{Basic methods} \label{subsection:Ideq:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Ideq * Ideq_new ( void ) ; \end{verbatim} \index{Ideq_new@{\tt Ideq\_new()}} This method simply allocates storage for the {\tt Ideq} structure and then sets the default fields by a call to {\tt Ideq\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Ideq_setDefaultFields ( Ideq *deq ) ; \end{verbatim} \index{Ideq_setDefaultFields@{\tt Ideq\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt head} and {\tt tail} are set to {\tt -1}, {\tt maxsize} is set to zero, and the fields for {\tt iv} are set via a call to {\tt IV\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt deq} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Ideq_clearData ( Ideq *deq ) ; \end{verbatim} \index{Ideq_clearData@{\tt Ideq\_clearData()}} This method clears any data owned by the object. It releases any storage held by the {\tt deq->iv} object with a call to {\tt IV\_clearData()}. It then calls {\tt Ideq\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt deq} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Ideq_free ( Ideq *deq ) ; \end{verbatim} \index{Ideq_free@{\tt Ideq\_free()}} This method releases any storage by a call to {\tt Ideq\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt deq} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:Ideq:proto:initializers} \par There is one initializer method. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Ideq_resize ( Ideq *deq, int newsize ) ; \end{verbatim} \index{Ideq_resize@{\tt Ideq\_resize()}} This method resizes the dequeue list, either increasing the size or decreasing the size (if possible). Since after {\tt Ideq\_new()} the size of the list is zero, this method also serves as an initializer. \par If the present size of the list (the number of entries between {\tt head} and {\tt tail} inclusive) is larger than {\tt newsize}, the method returns {\tt -1}. Otherwise, a new {\tt int} vector is allocated and filled with the entries in the list. The old {\tt int} vector is free'd, the new vector is spliced into the {\tt IV} object, and the {\tt head}, {\tt tail} and {\tt maxsize} fields are set. The method then returns {\tt 1}. \par \noindent {\it Error checking:} If {\tt deq} is {\tt NULL}, or if ${\tt newsize} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:Ideq:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Ideq_clear ( Ideq *deq ) ; \end{verbatim} \index{Ideq_clear@{\tt Ideq\_clear()}} This method clears the dequeue. The {\tt head} and {\tt tail} fields are set to {\tt -1}. \par \noindent {\it Error checking:} If {\tt deq} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Ideq_head ( Ideq *deq ) ; \end{verbatim} \index{Ideq_head@{\tt Ideq\_head()}} This method returns the value at the head of the list without removing that value. If {\tt head == -1} then {\tt -1} is returned. Note, the list may be nonempty and the first value may be {\tt -1}, so {\tt -1} may signal an empty list or a terminating element. \par \noindent {\it Error checking:} If {\tt deq} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Ideq_removeFromHead ( Ideq *deq ) ; \end{verbatim} \index{Ideq_removeFromHead@{\tt Ideq\_removeFromHead()}} This method returns the value at the head of the list and removes that value. If {\tt head == -1} then {\tt -1} is returned. Note, the list may be nonempty and the first value may be {\tt -1}, so {\tt -1} may signal an empty list or a terminating element. \par \noindent {\it Error checking:} If {\tt deq} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Ideq_insertAtHead ( Ideq *deq, int val ) ; \end{verbatim} \index{Ideq_insertAtHead@{\tt Ideq\_insertAtHead()}} This method inserts a value {\tt val} into the list at the head of the list. If there is no room in the list, {\tt -1} is returned and the dequeue must be resized using the {\tt Ideq\_resize()} method. Otherwise, the item is placed into the list and {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt deq} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Ideq_tail ( Ideq *deq ) ; \end{verbatim} \index{Ideq_tail@{\tt Ideq\_tail()}} This method returns the value at the tail of the list without removing that value. If {\tt tail == -1} then {\tt -1} is returned. Note, the list may be nonempty and the first value may be {\tt -1}, so {\tt -1} may signal an empty list or a terminating element. \par \noindent {\it Error checking:} If {\tt deq} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Ideq_removeFromTail ( Ideq *deq ) ; \end{verbatim} \index{Ideq_removeFromTail@{\tt Ideq\_removeFromTail()}} This method returns the value at the tail of the list and removes that value. If {\tt tail == -1} then {\tt -1} is returned. Note, the list may be nonempty and the first value may be {\tt -1}, so {\tt -1} may signal an empty list or a terminating element. \par \noindent {\it Error checking:} If {\tt deq} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Ideq_insertAtTail ( Ideq *deq, int val ) ; \end{verbatim} \index{Ideq_insertAtTail@{\tt Ideq\_insertAtTail()}} This method inserts a value {\tt val} into the list at the tail of the list. If there is no room in the list, {\tt -1} is returned and the dequeue must be resized using the {\tt Ideq\_resize()} method. Otherwise, the item is placed into the list and {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt deq} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:Ideq:proto:IO} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Ideq_writeForHumanEye ( Ideq *deq ) ; \end{verbatim} \index{Ideq_writeForHumanEye@{\tt Ideq\_writeForHumanEye()}} This method write the state of the object, (the size, head and tail) and the list of entries to a file. \par \noindent {\it Error checking:} If {\tt deq} or {\tt fp} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} ng the size or decreasing the size (if possible). Since after {\tt Ideq\_new()} the size of the list is zero, this method also serves as an initializer. \par If the present size of the liIdeq/doc/main.idx010064400020550007177000000013170653552761700151740ustar00clevecompmath00000400000006\indexentry{Ideq_new@{\tt Ideq\_new()}}{2} \indexentry{Ideq_setDefaultFields@{\tt Ideq\_setDefaultFields()}}{2} \indexentry{Ideq_clearData@{\tt Ideq\_clearData()}}{2} \indexentry{Ideq_free@{\tt Ideq\_free()}}{2} \indexentry{Ideq_resize@{\tt Ideq\_resize()}}{2} \indexentry{Ideq_clear@{\tt Ideq\_clear()}}{3} \indexentry{Ideq_head@{\tt Ideq\_head()}}{3} \indexentry{Ideq_removeFromHead@{\tt Ideq\_removeFromHead()}}{3} \indexentry{Ideq_insertAtHead@{\tt Ideq\_insertAtHead()}}{3} \indexentry{Ideq_tail@{\tt Ideq\_tail()}}{3} \indexentry{Ideq_removeFromTail@{\tt Ideq\_removeFromTail()}}{3} \indexentry{Ideq_insertAtTail@{\tt Ideq\_insertAtTail()}}{3} \indexentry{Ideq_writeForHumanEye@{\tt Ideq\_writeForHumanEye()}}{4} Ideq/doc/main.ind010064400020550007177000000007530653552755300151640ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Ideq\_clear()}, 3 \item {\tt Ideq\_clearData()}, 2 \item {\tt Ideq\_free()}, 2 \item {\tt Ideq\_head()}, 3 \item {\tt Ideq\_insertAtHead()}, 3 \item {\tt Ideq\_insertAtTail()}, 3 \item {\tt Ideq\_new()}, 2 \item {\tt Ideq\_removeFromHead()}, 3 \item {\tt Ideq\_removeFromTail()}, 3 \item {\tt Ideq\_resize()}, 2 \item {\tt Ideq\_setDefaultFields()}, 2 \item {\tt Ideq\_tail()}, 3 \item {\tt Ideq\_writeForHumanEye()}, 4 \end{theindex} Ideq/doc/main.ilg010064400020550007177000000004560653552755300151650ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (13 entries accepted, 0 rejected). Sorting entries....done (50 comparisons). Generating output file main.ind....done (17 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Ideq/doc/makefile010064400020550007177000000000270654276745100152370ustar00clevecompmath00000400000006clean : - rm -f *.dvi InpMtx.h010064400020550007177000000001040653410641000134530ustar00clevecompmath00000400000006#ifndef _InpMtx_ #define _InpMtx_ #include "InpMtx/InpMtx.h" #endif InpMtx/InpMtx.h010064400020550007177000001342400662340504100147040ustar00clevecompmath00000400000006/* InpMtx.h */ #include "../DenseMtx.h" #include "../IV.h" #include "../IVL.h" #include "../DV.h" #include "../ZV.h" #include "../cfiles.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ coordType -- coordinate type 0 -- no type specified 1 -- row triples (i, j, a_{i,j}) 2 -- column triples (i, j, a_{j,i}) 3 -- chevron triples (i, k, a_{i,i+k}) if k >= 0 (i, k, a_{i-k,i}) if k < 0 i is the chevron, k is the offset 4 -- custom coordinate, e.g., one could store (I, k, a_{i,j}) where I is the front where a_{i,j} will be assembled and k is the offset into the vector that holds the entries in the front storageMode -- storage mode 0 -- no mode specified 1 -- filled with raw triples 2 -- filled with sorted and distinct triples 3 -- vectors by the first coordinate, ivec1[*] ignored inputMode -- input mode 0 -- no input allowed 1 -- indices only 2 -- indices and real entries 3 -- indices and complex entries maxnent -- present maximum number of entries nent -- present number of entries resizeMultiple -- when resizing is done, new maxnent = old maxnent * resizeMultiple ivec1IV -- IV object that holds the first coordinates ivec2IV -- IV object that holds the second coordinates dvecDV -- DV object that holds the entries maxnvector -- present number of vectors nvector -- present number of vectors vecidsIV -- IV object that holds vector ids sizesIV -- IV object that holds vector sizes offsetsIV -- IV object that holds vector offsets created -- 98jan28, cca ------------------------------------------------------------------ */ typedef struct _InpMtx InpMtx ; struct _InpMtx { int coordType ; int storageMode ; int inputMode ; int maxnent ; int nent ; double resizeMultiple ; IV ivec1IV ; IV ivec2IV ; DV dvecDV ; int maxnvector ; int nvector ; IV vecidsIV ; IV sizesIV ; IV offsetsIV ; } ; #define INPMTX_NO_TYPE 0 #define INPMTX_BY_ROWS 1 #define INPMTX_BY_COLUMNS 2 #define INPMTX_BY_CHEVRONS 3 #define INPMTX_CUSTOM 4 #define INPMTX_IS_BY_ROWS(inpmtx) \ ((inpmtx)->coordType == INPMTX_BY_ROWS) #define INPMTX_IS_BY_COLUMNS(inpmtx) \ ((inpmtx)->coordType == INPMTX_BY_COLUMNS) #define INPMTX_IS_BY_CHEVRONS(inpmtx) \ ((inpmtx)->coordType == INPMTX_BY_CHEVRONS) #define INPMTX_IS_CUSTOM(inpmtx) \ ((inpmtx)->coordType == INPMTX_CUSTOM) #define INPMTX_NO_MODE 0 #define INPMTX_RAW_DATA 1 #define INPMTX_SORTED 2 #define INPMTX_BY_VECTORS 3 #define INPMTX_IS_RAW_DATA(inpmtx) \ ((inpmtx)->storageMode == INPMTX_RAW_DATA) #define INPMTX_IS_SORTED(inpmtx) \ ((inpmtx)->storageMode == INPMTX_SORTED) #define INPMTX_IS_BY_VECTORS(inpmtx) \ ((inpmtx)->storageMode == INPMTX_BY_VECTORS) #define INPMTX_INDICES_ONLY 0 #define INPMTX_REAL_ENTRIES 1 #define INPMTX_COMPLEX_ENTRIES 2 #define INPMTX_IS_INDICES_ONLY(inpmtx) \ ((inpmtx)->inputMode == INPMTX_INDICES_ONLY) #define INPMTX_IS_REAL_ENTRIES(inpmtx) \ ((inpmtx)->inputMode == SPOOLES_REAL) #define INPMTX_IS_COMPLEX_ENTRIES(inpmtx) \ ((inpmtx)->inputMode == SPOOLES_COMPLEX) /* #define INPMTX_IS_REAL_ENTRIES(inpmtx) \ ((inpmtx)->inputMode == INPMTX_REAL_ENTRIES) #define INPMTX_IS_COMPLEX_ENTRIES(inpmtx) \ ((inpmtx)->inputMode == INPMTX_COMPLEX_ENTRIES) */ /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98jan28, cca ----------------------- */ InpMtx * InpMtx_new ( void ) ; /* ----------------------- set the default fields created -- 98jan28, cca ----------------------- */ void InpMtx_setDefaultFields ( InpMtx *inpmtx ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98jan28, cca -------------------------------------------------- */ void InpMtx_clearData ( InpMtx *inpmtx ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98jan28, cca ------------------------------------------ */ InpMtx * InpMtx_free ( InpMtx *inpmtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- returns coordinate type created -- 98jan28, cca ----------------------- */ int InpMtx_coordType ( InpMtx *inpmtx ) ; /* ----------------------- returns storage mode created -- 98jan28, cca ---------------------- */ int InpMtx_storageMode ( InpMtx *inpmtx ) ; /* ----------------------- returns input mode created -- 98jan28, cca ----------------------- */ int InpMtx_inputMode ( InpMtx *inpmtx ) ; /* ----------------------- returns inpmtx->mxnent created -- 98jan28, cca ----------------------- */ int InpMtx_maxnent ( InpMtx *inpmtx ) ; /* ----------------------- returns inpmtx->nent created -- 98jan28, cca ----------------------- */ int InpMtx_nent ( InpMtx *inpmtx ) ; /* ------------------------- returns inpmtx->mxnvector created -- 98jan28, cca ------------------------- */ int InpMtx_maxnvector ( InpMtx *inpmtx ) ; /* ----------------------- returns inpmtx->nvector created -- 98jan28, cca ----------------------- */ int InpMtx_nvector ( InpMtx *inpmtx ) ; /* ------------------------------ returns inpmtx->resizeMultiple created -- 98jan28, cca ------------------------------ */ double InpMtx_resizeMultiple ( InpMtx *inpmtx ) ; /* --------------------------------- returns pointer to ivec1[] vector created -- 98jan28, cca --------------------------------- */ int * InpMtx_ivec1 ( InpMtx *inpmtx ) ; /* --------------------------------- returns pointer to ivec2[] vector created -- 98jan28, cca --------------------------------- */ int * InpMtx_ivec2 ( InpMtx *inpmtx ) ; /* -------------------------------- returns pointer to dvec[] vector created -- 98jan28, cca -------------------------------- */ double * InpMtx_dvec ( InpMtx *inpmtx ) ; /* --------------------------------- returns pointer to sizes[] vector created -- 98jan28, cca --------------------------------- */ int * InpMtx_sizes ( InpMtx *inpmtx ) ; /* ---------------------------------- returns pointer to vecids[] vector created -- 98jan28, cca ---------------------------------- */ int * InpMtx_vecids ( InpMtx *inpmtx ) ; /* ----------------------------------- returns pointer to offsets[] vector created -- 98jan28, cca ----------------------------------- */ int * InpMtx_offsets ( InpMtx *inpmtx ) ; /* --------------------------------------- retrieve requested vector set *pnent to # of entries *pindices to address of first index created -- 98jan28, cca --------------------------------------- */ void InpMtx_vector ( InpMtx *inpmtx, int id, int *pnent, int **pindices ) ; /* --------------------------------------- retrieve requested vector set *pnent to # of entries *pindices to address of first index *pentries to address of first entry created -- 98jan28, cca --------------------------------------- */ void InpMtx_realVector ( InpMtx *inpmtx, int id, int *pnent, int **pindices, double **pentries ) ; /* --------------------------------------- retrieve requested vector set *pnent to # of entries *pindices to address of first index *pentries to address of first entry created -- 98jan28, cca --------------------------------------- */ void InpMtx_complexVector ( InpMtx *inpmtx, int id, int *pnent, int **pindices, double **pentries ) ; /* -------------------------------------------------------------- sets the maximum numnber of entries. this methods resizes the ivec1[], ivece2[] and dvec[] vectors if newmaxnent != maxnent created -- 98jan28, cca -------------------------------------------------------------- */ void InpMtx_setMaxnent ( InpMtx *inpmtx, int newmaxnent ) ; /* --------------------------------- set the present number of entries created -- 98jan28, cca -------------------------------- */ void InpMtx_setNent ( InpMtx *inpmtx, int newnent ) ; /* -------------------------------------------------- sets the maximum number of vectors. if newmaxnent != maxnent then this methods resizes the vecids[], sizes[] and offsets[] vectors created -- 98jan28, cca -------------------------------------------------- */ void InpMtx_setMaxnvector ( InpMtx *inpmtx, int newmaxnvector ) ; /* --------------------------------- set the present number of vectors created -- 98jan28, cca --------------------------------- */ void InpMtx_setNvector ( InpMtx *inpmtx, int newnvector ) ; /* --------------------------- sets inpmtx->resizeMultiple created -- 98jan28, cca --------------------------- */ void InpMtx_setResizeMultiple ( InpMtx *inpmtx, double resizeMultiple ) ; /* -------------------------------------------- sets coordType of InpMtx structure to allow user to define custom coordinate type. Note, new type must be > 3. created -- 98jan28, cca -------------------------------------------- */ void InpMtx_setCoordType ( InpMtx *inpmtx, int type ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ initialize the object coordType -- coordinate type, input supported for types 1, 2 and 3 1 -- row triples (i, j, a_{i,j}) 2 -- column triples (i, j, a_{j,i}) 3 -- chevron triples (i, k, a_{i,i+k}) if k >= 0 (i, k, a_{i-k,i}) if k < 0 i is the chevron, k is the offset 4 -- custom coordinate, e.g., one could store (I, k, a_{i,j}) where I is the front where a_{i,j} will be assembled and k is the offset into the vector that holds the entries in the front inputMode -- mode for input 1 --> indices only 2 --> indices and entries maxnent -- upper bound on the number of entries, also equal to the workspace, so if the assembly includes overlapping data, give enough elbow room for efficiency. maxnvector -- upper bound on the number of vectors to be supported. this may not be known ahead of time (e.g., the number of vectors may be the number of fronts which is not known before the ordering is done and front tree constructed). created -- 98jan28, cca ------------------------------------------------------------------ */ void InpMtx_init ( InpMtx *inpmtx, int coordType, int inputMode, int maxnent, int maxnvector ) ; /* -------------------------- change the coordinate type created -- 98jan28, cca -------------------------- */ void InpMtx_changeCoordType ( InpMtx *inpmtx, int newType ) ; /* ----------------------- change the storage mode created -- 98jan28, cca ----------------------- */ void InpMtx_changeStorageMode ( InpMtx *inpmtx, int newMode ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in input.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------- input a single entry in the matrix created -- 98jan28, cca ---------------------------------- */ void InpMtx_inputEntry ( InpMtx *inpmtx, int row, int col ) ; /* --------------------------------------- input a single real entry in the matrix created -- 98jan28, cca --------------------------------------- */ void InpMtx_inputRealEntry ( InpMtx *inpmtx, int row, int col, double value ) ; /* ------------------------------------------ input a single complex entry in the matrix created -- 98jan28, cca ------------------------------------------ */ void InpMtx_inputComplexEntry ( InpMtx *inpmtx, int row, int col, double real, double imag ) ; /* ------------------------------ input a real row in the matrix created -- 98jan28, cca ------------------------------ */ void InpMtx_inputRow ( InpMtx *inpmtx, int row, int rowsize, int rowind[] ) ; /* ------------------------------ input a real row in the matrix created -- 98jan28, cca ------------------------------ */ void InpMtx_inputRealRow ( InpMtx *inpmtx, int row, int rowsize, int rowind[], double rowent[] ) ; /* --------------------------------- input a complex row in the matrix created -- 98jan28, cca --------------------------------- */ void InpMtx_inputComplexRow ( InpMtx *inpmtx, int row, int rowsize, int rowind[], double rowent[] ) ; /* ---------------------------- input a column in the matrix created -- 98jan28, cca ---------------------------- */ void InpMtx_inputColumn ( InpMtx *inpmtx, int col, int colsize, int colind[] ) ; /* --------------------------------- input a real column in the matrix created -- 98jan28, cca --------------------------------- */ void InpMtx_inputRealColumn ( InpMtx *inpmtx, int col, int colsize, int colind[], double colent[] ) ; /* ------------------------------------ input a complex column in the matrix created -- 98jan28, cca ------------------------------------ */ void InpMtx_inputComplexColumn ( InpMtx *inpmtx, int col, int colsize, int colind[], double colent[] ) ; /* ----------------------------- input a chevron in the matrix created -- 98jan28, cca ----------------------------- */ void InpMtx_inputChevron ( InpMtx *inpmtx, int chv, int chvsize, int chvind[] ) ; /* ----------------------------- input a chevron in the matrix created -- 98jan28, cca ----------------------------- */ void InpMtx_inputRealChevron ( InpMtx *inpmtx, int chv, int chvsize, int chvind[], double chvent[] ) ; /* ----------------------------- input a chevron in the matrix created -- 98jan28, cca ----------------------------- */ void InpMtx_inputComplexChevron ( InpMtx *inpmtx, int chv, int chvsize, int chvind[], double chvent[] ) ; /* ----------------------- input a matrix created -- 98jan28, cca ----------------------- */ void InpMtx_inputMatrix ( InpMtx *inpmtx, int nrow, int ncol, int rowstride, int colstride, int rowind[], int colind[] ) ; /* ----------------------- input a matrix created -- 98jan28, cca ----------------------- */ void InpMtx_inputRealMatrix ( InpMtx *inpmtx, int nrow, int ncol, int rowstride, int colstride, int rowind[], int colind[], double mtxent[] ) ; /* ----------------------- input a matrix created -- 98jan28, cca ----------------------- */ void InpMtx_inputComplexMatrix ( InpMtx *inpmtx, int nrow, int ncol, int rowstride, int colstride, int rowind[], int colind[], double mtxent[] ) ; /* ------------------------------------------------------------- input a number of (row,column, entry) triples into the matrix created -- 98jan28, cca ------------------------------------------------------------- */ void InpMtx_inputTriples ( InpMtx *inpmtx, int ntriples, int rowids[], int colids[] ) ; /* ------------------------------------------------------------- input a number of (row,column, entry) triples into the matrix created -- 98jan28, cca ------------------------------------------------------------- */ void InpMtx_inputRealTriples ( InpMtx *inpmtx, int ntriples, int rowids[], int colids[], double entries[] ) ; /* ------------------------------------------------------------- input a number of (row,column, entry) triples into the matrix created -- 98jan28, cca ------------------------------------------------------------- */ void InpMtx_inputComplexTriples ( InpMtx *inpmtx, int ntriples, int rowids[], int colids[], double entries[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in permute.c --------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- permute the entries created -- 96jul05, cca ----------------------- */ void InpMtx_permute ( InpMtx *inpmtx, int rowOldToNew[], int colOldToNew[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in extract.c --------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------------- purpose -- to extract a submatrix, B = A(BrowsIV, BcolsIV) return values --- 1 -- normal return -1 -- B is NULL -2 -- BcolsIV is NULL -3 -- BrowsIV is NULL -4 -- B is NULL -5 -- invalid input mode for A -6 -- invalid coordinate type for A -7 -- invalid symmetryflag -8 -- hermitian flag but not complex -9 -- msglvl > 0 and msgFile = NULL created -- 98oct15, cca ---------------------------------------------------------- */ int InpMtx_initFromSubmatrix ( InpMtx *B, InpMtx *A, IV *BrowsIV, IV *BcolsIV, int symmetryflag, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------- given the data is in raw triples, sort and compress the data created -- 98jan28, cca --------------------------------- */ void InpMtx_sortAndCompress ( InpMtx *inpmtx ) ; /* ---------------------------------------------------- convert from sorted and compressed triples to vector created -- 98jan28, cca ---------------------------------------------------- */ void InpMtx_convertToVectors ( InpMtx *inpmtx ) ; /* ------------------------- drop off-diagonal entries created -- 98jan28, cca ------------------------- */ void InpMtx_dropOffdiagonalEntries ( InpMtx *inpmtx ) ; /* ---------------------------------- drop entries in the lower triangle created -- 98jan28, cca ---------------------------------- */ void InpMtx_dropLowerTriangle ( InpMtx *inpmtx ) ; /* ---------------------------------- drop entries in the upper triangle created -- 98jan28, cca ---------------------------------- */ void InpMtx_dropUpperTriangle ( InpMtx *inpmtx ) ; /* ----------------------------------- map entries into the lower triangle created -- 98jan28, cca ----------------------------------- */ void InpMtx_mapToLowerTriangle ( InpMtx *inpmtx ) ; /* ----------------------------------- map entries into the upper triangle created -- 98jan28, cca ----------------------------------- */ void InpMtx_mapToUpperTriangle ( InpMtx *inpmtx ) ; /* ----------------------------------- map entries into the upper triangle for a hermitian matrix created -- 98may15, cca ----------------------------------- */ void InpMtx_mapToUpperTriangleH ( InpMtx *inpmtx ) ; /* ----------------------------------------------------------- purpose -- compute the checksums of the indices and entries sums[0] = sum_{ii=0}^{nent} abs(ivec1[ii]) sums[1] = sum_{ii=0}^{nent} abs(ivec2[ii]) if real or complex entries then sums[2] = sum_{ii=0}^{nent} magnitudes of entries endif created -- 98may16, cca ----------------------------------------------------------- */ void InpMtx_checksums ( InpMtx *inpmtx, double sums[] ) ; /* ---------------------------------------------------------------- purpose -- to create an InpMtx object filled with random entries input -- mtx -- matrix object, if NULL, it is created inputMode -- input mode for the object, indices only, real or complex entries coordType -- coordinate type for the object, by rows, by columns or by chevrons storageMode -- storage mode for the object, raw data, sorted or by vectors nrow -- # of rows ncol -- # of columns symflag -- symmetry flag for the matrix, symmetric, hermitian or nonsymmetric nonzerodiag -- if 1, entries are placed on the diagonal nitem -- # of items to be placed into the matrix seed -- random number seed return value --- 1 -- normal return -1 -- mtx is NULL -2 -- bad input mode -3 -- bad coordinate type -4 -- bad storage mode -5 -- nrow or ncol <= 0 -6 -- bad symmetry flag -7 -- hermitian matrix but not complex -8 -- symmetric or hermitian matrix but nrow != ncol -9 -- nitem < 0 ---------------------------------------------------------------- */ int InpMtx_randomMatrix ( InpMtx *mtx, int inputMode, int coordType, int storageMode, int nrow, int ncol, int symflag, int nonzerodiag, int nitem, int seed ) ; /* ---------------------------------------------------- determine the range of the matrix, i.e., the minimum and maximum rows and columns if pmincol != NULL then *pmincol = minimum column id if pmaxcol != NULL then *pmaxcol = maximum column id if pminrow != NULL then *pminrow = minimum row id if pmaxrow != NULL then *pmaxrow = maximum row id return value --- 1 -- normal return -1 -- mtx is NULL -2 -- no entries in the matrix -3 -- invalid coordinate type created -- 98oct15, cca ---------------------------------------------------- */ int InpMtx_range ( InpMtx *mtx, int *pmincol, int *pmaxcol, int *pminrow, int *pmaxrow ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in fullAdj.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------- purpose -- to return the full, symmetric adjacency IVL object for the graph of A + A^T created -- 98jan28, cca ------------------------------------------------------------- */ IVL * InpMtx_fullAdjacency ( InpMtx *inpmtx ) ; /* ------------------------------------------------------------- purpose -- to return the full, symmetric adjacency IVL object for the graph of (A + B) + (A + B)^T created -- 97nov05, cca ------------------------------------------------------------- */ IVL * InpMtx_fullAdjacency2 ( InpMtx *inpmtxA, InpMtx *inpmtxB ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in adjForATA.c ------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------- return an IVL object that contains the adjacency structure of A^TA. created -- 98jan28, cca ---------------------------------- */ IVL * InpMtx_adjForATA ( InpMtx *inpmtxA ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in profile.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ to fill xDV and yDV with a log10 profile of the magnitudes of the entries in the InpMtx object. tausmall and tau big provide cutoffs within which to examine the entries. pnsmall and pnbig are address to hold the number of entries smaller than tausmall, and larger than taubig, respectively. created -- 97feb14, cca ------------------------------------------------------------------ */ void InpMtx_log10profile ( InpMtx *inpmtx, int npts, DV *xDV, DV *yDV, double tausmall, double taubig, int *pnzero, int *pnsmall, int *pnbig ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in gmmm.c ------------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A*X where X and Y are DenseMtx objects, and X and Y must be column major. return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- Y is NULL -6 -- type of Y is invalid -7 -- dimensions and strides of Y do not line up -8 -- entries of Y are NULL -9 -- beta is NULL -10 -- X is NULL -11 -- type of X is invalid -12 -- dimensions and strides of X do not line up -13 -- entries of X are NULL -14 -- types of A, X and Y are not identical -15 -- # of columns of X and Y are not equal created -- 98may02, cca -------------------------------------------------- */ int InpMtx_nonsym_gmmm ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) ; /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A^T*X return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- Y is NULL -6 -- type of Y is invalid -7 -- dimensions and strides of Y do not line up -8 -- entries of Y are NULL -9 -- beta is NULL -10 -- X is NULL -11 -- type of X is invalid -12 -- dimensions and strides of X do not line up -13 -- entries of X are NULL -14 -- types of A, X and Y are not identical -15 -- # of columns of X and Y are not equal created -- 98may02, cca -------------------------------------------------- */ int InpMtx_nonsym_gmmm_T ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) ; /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A^H*X return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- Y is NULL -6 -- type of Y is invalid -7 -- dimensions and strides of Y do not line up -8 -- entries of Y are NULL -9 -- beta is NULL -10 -- X is NULL -11 -- type of X is invalid -12 -- dimensions and strides of X do not line up -13 -- entries of X are NULL -14 -- types of A, X and Y are not identical -15 -- # of columns of X and Y are not equal -16 -- A, X and Y are real created -- 98may02, cca -------------------------------------------------- */ int InpMtx_nonsym_gmmm_H ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) ; /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A*X where A is symmetric return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- Y is NULL -6 -- type of Y is invalid -7 -- dimensions and strides of Y do not line up -8 -- entries of Y are NULL -9 -- beta is NULL -10 -- X is NULL -11 -- type of X is invalid -12 -- dimensions and strides of X do not line up -13 -- entries of X are NULL -14 -- types of A, X and Y are not identical -15 -- # of columns of X and Y are not equal created -- 98nov06, cca -------------------------------------------------- */ int InpMtx_sym_gmmm ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) ; /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A*X where A is hermitian return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- Y is NULL -6 -- type of Y is invalid -7 -- dimensions and strides of Y do not line up -8 -- entries of Y are NULL -9 -- beta is NULL -10 -- X is NULL -11 -- type of X is invalid -12 -- dimensions and strides of X do not line up -13 -- entries of X are NULL -14 -- types of A, X and Y are not identical -15 -- # of columns of X and Y are not equal -16 -- A, X and Y are real created -- 98nov06, cca -------------------------------------------------- */ int InpMtx_herm_gmmm ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in gmvm.c ------------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------------------------- purpose -- to compute y := beta*y + alpha*A*x where x and y are double vectors. return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 -9 -- x is NULL created -- 98nov14, cca -------------------------------------------------- */ int InpMtx_nonsym_gmvm ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) ; /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A^T*X return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 -9 -- x is NULL created -- 98may02, cca -------------------------------------------------- */ int InpMtx_nonsym_gmvm_T ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) ; /* --------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A^H*X return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 -9 -- x is NULL -10 -- A is real created -- 98may02, cca --------------------------------------------------- */ int InpMtx_nonsym_gmvm_H ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) ; /* ---------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A*X where A is symmetric return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 -9 -- x is NULL created -- 98nov06, cca ---------------------------------------------------- */ int InpMtx_sym_gmvm ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) ; /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A*X where A is hermitian return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 -9 -- x is NULL -10 -- A, X and Y are real created -- 98nov06, cca -------------------------------------------------- */ int InpMtx_herm_gmvm ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in mmm.c ------------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98may02, cca ---------------------------------------- */ void InpMtx_nonsym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; /* ------------------------------------------ purpose -- to compute Y := Y + alpha*A^T*X created -- 98may28, cca ------------------------------------------ */ void InpMtx_nonsym_mmm_T ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; /* ------------------------------------------ purpose -- to compute Y := Y + alpha*A^H*X created -- 98may28, cca ------------------------------------------ */ void InpMtx_nonsym_mmm_H ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X where A is symmetric created -- 98may02, cca ---------------------------------------- */ void InpMtx_sym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X where A is hermitian created -- 98may02, cca ---------------------------------------- */ void InpMtx_herm_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in mvmVector.c ------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98may02, cca ---------------------------------------- */ void InpMtx_nonsym_mmmVector ( InpMtx *A, double y[], double alpha[], double x[] ) ; /* ------------------------------------------ purpose -- to compute Y := Y + alpha*A^T*X created -- 98may28, cca ------------------------------------------ */ void InpMtx_nonsym_mmmVector_T ( InpMtx *A, double y[], double alpha[], double x[] ) ; /* ------------------------------------------ purpose -- to compute Y := Y + alpha*A^H*X created -- 98may28, cca ------------------------------------------ */ void InpMtx_nonsym_mmmVector_H ( InpMtx *A, double y[], double alpha[], double x[] ) ; /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X where A is symmetric created -- 98may02, cca ---------------------------------------- */ void InpMtx_sym_mmmVector ( InpMtx *A, double y[], double alpha[], double x[] ) ; /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X where A is hermitian created -- 98may02, cca ---------------------------------------- */ void InpMtx_herm_mmmVector ( InpMtx *A, double y[], double alpha[], double x[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in support.c --------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------------- purpose -- this method is used to determine the support of this matrix for a matrix-vector multiply y[] = A * x[] when A is a nonsymmetric matrix. rowsupIV -- filled with row indices of y[] which will be updated. colsupIV -- filled with row indices of x[] which will be used. created -- 98aug01, cca -------------------------------------------------------------------- */ void InpMtx_supportNonsym ( InpMtx *A, IV *rowsupIV, IV *colsupIV ) ; /* -------------------------------------------------------------------- purpose -- this method is used to determine the support of this matrix for a matrix-vector multiply y[] = A * x[] when A is a nonsymmetric matrix. rowsupIV -- filled with row indices of y[] which will be updated. colsupIV -- filled with row indices of x[] which will be used. created -- 98aug01, cca -------------------------------------------------------------------- */ void InpMtx_supportNonsymT ( InpMtx *A, IV *rowsupIV, IV *colsupIV ) ; /* -------------------------------------------------------------------- purpose -- this method is used to determine the support of this matrix for a matrix-vector multiply y[] = A * x[] when A is a nonsymmetric matrix. rowsupIV -- filled with row indices of y[] which will be updated. colsupIV -- filled with row indices of x[] which will be used. created -- 98aug01, cca -------------------------------------------------------------------- */ void InpMtx_supportNonsymH ( InpMtx *A, IV *rowsupIV, IV *colsupIV ) ; /* -------------------------------------------------------------------- purpose -- this method is used to determine the support of this matrix for a matrix-vector multiply y[] = A * x[] when A is a symmetric matrix. supIV -- filled with row indices of y[] which will be updated and row indices of x[] which will be used. created -- 98aug01, cca -------------------------------------------------------------------- */ void InpMtx_supportSym ( InpMtx *A, IV *supIV ) ; /* -------------------------------------------------------------------- purpose -- this method is used to determine the support of this matrix for a matrix-vector multiply y[] = A * x[] when A is a Hermitian matrix. supIV -- filled with row indices of y[] which will be updated and row indices of x[] which will be used. created -- 98aug01, cca -------------------------------------------------------------------- */ void InpMtx_supportHerm ( InpMtx *A, IV *supIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in map.c ------------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------------- purpose -- to map the coordinates of the entries of the matrix into new coordinates. this method is used during the distributed matrix-vector multiply where a matrix local to a processor is mapped into a local coordinate system. (row,col) --> (rowmap[row],colmap[col]) we check that row is in [0,nrow) and col is in [0,ncol), where nrow is the size of rowmapIV and ncol is the size of colmapIV. note, the storage mode is not changed. i.e., if the data is stored by vectors, it may be invalid after the indices have been mapped. on the other hand, it may not, so it is the user's responsibility to reset the storage mode if necessary. created -- 98aug02, cca -------------------------------------------------------------------- */ void InpMtx_mapEntries ( InpMtx *inpmtx, IV *rowmapIV, IV *colmapIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------- purpose -- to read in a InpMtx object from a file input -- fn -- filename, must be *.inpmtxb or *.inpmtxf return value -- 1 if success, 0 if failure created -- 98jan28, cca -------------------------------------------------- */ int InpMtx_readFromFile ( InpMtx *inpmtx, char *fn ) ; /* -------------------------------------------------------- purpose -- to read a InpMtx object from a formatted file return value -- 1 if success, 0 if failure created -- 98jan28, cca -------------------------------------------------------- */ int InpMtx_readFromFormattedFile ( InpMtx *inpmtx, FILE *fp ) ; /* ------------------------------------------------------ purpose -- to read a InpMtx object from a binary file return value -- 1 if success, 0 if failure created -- 98jan28, cca ------------------------------------------------------ */ int InpMtx_readFromBinaryFile ( InpMtx *inpmtx, FILE *fp ) ; /* ---------------------------------------------- purpose -- to write a InpMtx object to a file input -- fn -- filename *.inpmtxb -- binary *.inpmtxf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 98jan28, cca ---------------------------------------------- */ int InpMtx_writeToFile ( InpMtx *inpmtx, char *fn ) ; /* ------------------------------------------------------ purpose -- to write a InpMtx object to a formatted file return value -- 1 if success, 0 otherwise created -- 98jan28, cca ------------------------------------------------------ */ int InpMtx_writeToFormattedFile ( InpMtx *inpmtx, FILE *fp ) ; /* --------------------------------------------------- purpose -- to write a InpMtx object to a binary file return value -- 1 if success, 0 otherwise created -- 98jan28, cca --------------------------------------------------- */ int InpMtx_writeToBinaryFile ( InpMtx *inpmtx, FILE *fp ) ; /* ---------------------------------------------------- purpose -- to write a InpMtx object for a human eye return value -- 1 if success, 0 otherwise created -- 98jan28, cca ---------------------------------------------------- */ int InpMtx_writeForHumanEye ( InpMtx *inpmtx, FILE *fp ) ; /* ----------------------------------------------------------- purpose -- to write out the statistics for the InpMtx object return value -- 1 if success, 0 otherwise created -- 98jan28, cca ----------------------------------------------------------- */ int InpMtx_writeStats ( InpMtx *inpmtx, FILE *fp ) ; /* ---------------------------------------------------- purpose -- to write a InpMtx object to a matlab file return value -- 1 if success, 0 otherwise created -- 98jan28, cca ---------------------------------------------------- */ int InpMtx_writeForMatlab ( InpMtx *inpmtx, char *mtxname, FILE *fp ) ; /* ---------------------------------------------------------------- purpose -- to read in a InpMtx object from a Harwell-Boeing file input -- fn -- filename return value -- 1 if success, 0 if failure created -- 98sep11, cca --------------------------------------------------------------- */ int InpMtx_readFromHBfile ( InpMtx *inpmtx, char *fn ) ; /*--------------------------------------------------------------------*/ + alpha*A*X where A is hermitian created -- 98may02, cca ---------------------------------------- */ void InpMtx_herm_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------InpMtx/makefile010064400020550007177000000002230663622362200150140ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean InpMtx/src/makefile010064400020550007177000000014370663602515500156140ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = InpMtx $(OBJ).a : \ $(OBJ).a(adjForATA.o) \ $(OBJ).a(basics.o) \ $(OBJ).a(extract.o) \ $(OBJ).a(fullAdj.o) \ $(OBJ).a(gmmm.o) \ $(OBJ).a(gmvm.o) \ $(OBJ).a(init.o) \ $(OBJ).a(input.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(map.o) \ $(OBJ).a(mvm.o) \ $(OBJ).a(mvmVector.o) \ $(OBJ).a(permute.o) \ $(OBJ).a(profile.o) \ $(OBJ).a(support.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG InpMtx/src/makeGlobalLib010064400020550007177000000011310662560176100165140ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = InpMtx SRC = adjForATA.c \ basics.c \ extract.c \ fullAdj.c \ gmmm.c \ gmvm.c \ init.c \ input.c \ instance.c \ IO.c \ map.c \ mvm.c \ mvmVector.c \ permute.c \ profile.c \ support.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a InpMtx/src/IO.c010064400020550007177000000631400661364364100145670ustar00clevecompmath00000400000006/* IO.c */ #include "../../InpMtx.h" static const char *suffixb = ".inpmtxb" ; static const char *suffixf = ".inpmtxf" ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to read in a InpMtx object from a file input -- fn -- filename, must be *.inpmtxb or *.inpmtxf return value -- 1 if success, 0 if failure created -- 98jan28, cca -------------------------------------------------- */ int InpMtx_readFromFile ( InpMtx *inpmtx, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( inpmtx == NULL || fn == NULL ) { fprintf(stderr, "\n error in InpMtx_readFromFile(%p,%s)" "\n bad input\n", inpmtx, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in InpMtx_readFromFile(%p,%s)" "\n unable to open file %s", inpmtx, fn, fn) ; rc = 0 ; } else { rc = InpMtx_readFromBinaryFile(inpmtx, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in InpMtx_readFromFile(%p,%s)" "\n unable to open file %s", inpmtx, fn, fn) ; rc = 0 ; } else { rc = InpMtx_readFromFormattedFile(inpmtx, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in InpMtx_readFromFile(%p,%s)" "\n bad InpMtx file name %s," "\n must end in %s (binary) or %s (formatted)\n", inpmtx, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in InpMtx_readFromFile(%p,%s)" "\n bad InpMtx file name %s," "\n must end in %s (binary) or %s (formatted)\n", inpmtx, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to read a InpMtx object from a formatted file return value -- 1 if success, 0 if failure created -- 98jan28, cca -------------------------------------------------------- */ int InpMtx_readFromFormattedFile ( InpMtx *inpmtx, FILE *fp ) { int rc ; int itemp[5] ; /* --------------- check the input --------------- */ if ( inpmtx == NULL || fp == NULL ) { fprintf(stderr, "\n error in InpMtx_readFromFormattedFile(%p,%p)" "\n bad input\n", inpmtx, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ InpMtx_clearData(inpmtx) ; /* -------------------------------------------------------- read in the five scalar parameters coordinate type, storage mode, input mode, nent, nvector -------------------------------------------------------- */ if ( (rc = IVfscanf(fp, 5, itemp)) != 5 ) { fprintf(stderr, "\n error in InpMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", inpmtx, fp, rc, 5) ; return(0) ; } inpmtx->coordType = itemp[0] ; inpmtx->storageMode = itemp[1] ; inpmtx->inputMode = itemp[2] ; inpmtx->nent = itemp[3] ; inpmtx->nvector = itemp[4] ; if ( inpmtx->nent > 0 ) { IV_readFromFormattedFile(&inpmtx->ivec1IV, fp) ; IV_readFromFormattedFile(&inpmtx->ivec2IV, fp) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) || INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { DV_readFromFormattedFile(&inpmtx->dvecDV, fp) ; } } if ( inpmtx->nvector > 0 ) { IV_readFromFormattedFile(&inpmtx->vecidsIV, fp) ; IV_readFromFormattedFile(&inpmtx->sizesIV, fp) ; IV_readFromFormattedFile(&inpmtx->offsetsIV, fp) ; } inpmtx->maxnent = inpmtx->nent ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to read a InpMtx object from a binary file return value -- 1 if success, 0 if failure created -- 98jan28, cca ------------------------------------------------------ */ int InpMtx_readFromBinaryFile ( InpMtx *inpmtx, FILE *fp ) { int rc ; int itemp[5] ; /* --------------- check the input --------------- */ if ( inpmtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_readFromBinaryFile(%p,%p)" "\n bad input\n", inpmtx, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ InpMtx_clearData(inpmtx) ; /* --------------------------------------------- read in the five scalar parameters coordType storageMode inputMode nent nvector --------------------------------------------- */ if ( (rc = fread((void *) itemp, sizeof(int), 5, fp)) != 5 ) { fprintf(stderr, "\n error in InpMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", inpmtx, fp, rc, 5) ; return(0) ; } inpmtx->coordType = itemp[0] ; inpmtx->storageMode = itemp[1] ; inpmtx->inputMode = itemp[2] ; inpmtx->nent = itemp[3] ; inpmtx->nvector = itemp[4] ; if ( inpmtx->nent > 0 ) { IV_readFromBinaryFile(&inpmtx->ivec1IV, fp) ; IV_readFromBinaryFile(&inpmtx->ivec2IV, fp) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) || INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { DV_readFromBinaryFile(&inpmtx->dvecDV, fp) ; } } if ( inpmtx->nvector > 0 ) { IV_readFromBinaryFile(&inpmtx->vecidsIV, fp) ; IV_readFromBinaryFile(&inpmtx->sizesIV, fp) ; IV_readFromBinaryFile(&inpmtx->offsetsIV, fp) ; } inpmtx->maxnent = inpmtx->nent ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to write a InpMtx object to a file input -- fn -- filename *.inpmtxb -- binary *.inpmtxf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 98jan28, cca ---------------------------------------------- */ int InpMtx_writeToFile ( InpMtx *inpmtx, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( inpmtx == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_writeToFile(%p,%s)" "\n bad input\n", inpmtx, fn) ; return(0) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in InpMtx_writeToFile(%p,%s)" "\n unable to open file %s", inpmtx, fn, fn) ; rc = 0 ; } else { rc = InpMtx_writeToBinaryFile(inpmtx, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in InpMtx_writeToFile(%p,%s)" "\n unable to open file %s", inpmtx, fn, fn) ; rc = 0 ; } else { rc = InpMtx_writeToFormattedFile(inpmtx, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in InpMtx_writeToFile(%p,%s)" "\n unable to open file %s", inpmtx, fn, fn) ; rc = 0 ; } else { rc = InpMtx_writeForHumanEye(inpmtx, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in InpMtx_writeToFile(%p,%s)" "\n unable to open file %s", inpmtx, fn, fn) ; rc = 0 ; } else { rc = InpMtx_writeForHumanEye(inpmtx, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to write a InpMtx object to a formatted file return value -- 1 if success, 0 otherwise created -- 98jan28, cca ------------------------------------------------------ */ int InpMtx_writeToFormattedFile ( InpMtx *inpmtx, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( inpmtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_writeToFormattedFile(%p,%p)" "\n bad input\n", inpmtx, fp) ; return(0) ; } /* ------------------------------------ write out the five scalar parameters ------------------------------------ */ rc = fprintf(fp, "\n %d %d %d %d %d", inpmtx->coordType, inpmtx->storageMode, inpmtx->inputMode, inpmtx->nent, inpmtx->nvector) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", inpmtx, fp, rc) ; return(0) ; } /* --------------------- write out the vectors --------------------- */ if ( inpmtx->nent > 0 ) { IV_setSize(&inpmtx->ivec1IV, inpmtx->nent) ; rc = IV_writeToFormattedFile(&inpmtx->ivec1IV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing ivec1\n", inpmtx, fp, rc) ; return(0) ; } IV_setSize(&inpmtx->ivec2IV, inpmtx->nent) ; rc = IV_writeToFormattedFile(&inpmtx->ivec2IV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing ivec2\n", inpmtx, fp, rc) ; return(0) ; } if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { DV_setSize(&inpmtx->dvecDV, inpmtx->nent) ; rc = DV_writeToFormattedFile(&inpmtx->dvecDV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing dvec\n", inpmtx, fp, rc) ; return(0) ; } } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { DV_setSize(&inpmtx->dvecDV, 2*inpmtx->nent) ; rc = DV_writeToFormattedFile(&inpmtx->dvecDV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing dvec\n", inpmtx, fp, rc) ; return(0) ; } } } if ( inpmtx->nvector > 0 ) { rc = IV_writeToFormattedFile(&inpmtx->vecidsIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing vecids\n", inpmtx, fp, rc) ; return(0) ; } rc = IV_writeToFormattedFile(&inpmtx->sizesIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing sizes\n", inpmtx, fp, rc) ; return(0) ; } rc = IV_writeToFormattedFile(&inpmtx->offsetsIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToFormattedFile(%p,%p)" "\n rc = %d, return from writing offsets\n", inpmtx, fp, rc) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to write a InpMtx object to a binary file return value -- 1 if success, 0 otherwise created -- 98jan28, cca --------------------------------------------------- */ int InpMtx_writeToBinaryFile ( InpMtx *inpmtx, FILE *fp ) { int rc ; int itemp[6] ; /* --------------- check the input --------------- */ if ( inpmtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_writeToBinaryFile(%p,%p)" "\n bad input\n", inpmtx, fp) ; return(0) ; } /* ------------------------------------ write out the five scalar parameters ------------------------------------ */ itemp[0] = inpmtx->coordType ; itemp[1] = inpmtx->storageMode ; itemp[2] = inpmtx->inputMode ; itemp[3] = inpmtx->nent ; itemp[4] = inpmtx->nvector ; rc = fwrite((void *) itemp, sizeof(int), 5, fp) ; if ( rc != 5 ) { fprintf(stderr, "\n error in InpMtx_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", inpmtx, fp, rc, 5) ; return(0) ; } /* --------------------- write out the vectors --------------------- */ if ( inpmtx->nent > 0 ) { IV_setSize(&inpmtx->ivec1IV, inpmtx->nent) ; rc = IV_writeToBinaryFile(&inpmtx->ivec1IV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing ivec1\n", inpmtx, fp, rc) ; return(0) ; } IV_setSize(&inpmtx->ivec2IV, inpmtx->nent) ; rc = IV_writeToBinaryFile(&inpmtx->ivec2IV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing ivec2\n", inpmtx, fp, rc) ; return(0) ; } if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { DV_setSize(&inpmtx->dvecDV, inpmtx->nent) ; rc = DV_writeToBinaryFile(&inpmtx->dvecDV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing dvec\n", inpmtx, fp, rc) ; return(0) ; } } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { DV_setSize(&inpmtx->dvecDV, 2*inpmtx->nent) ; rc = DV_writeToBinaryFile(&inpmtx->dvecDV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing dvec\n", inpmtx, fp, rc) ; return(0) ; } } } if ( inpmtx->nvector > 0 ) { rc = IV_writeToBinaryFile(&inpmtx->vecidsIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing vecids\n", inpmtx, fp, rc) ; return(0) ; } rc = IV_writeToBinaryFile(&inpmtx->sizesIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing sizes\n", inpmtx, fp, rc) ; return(0) ; } rc = IV_writeToBinaryFile(&inpmtx->offsetsIV, fp) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeToBinaryFile(%p,%p)" "\n rc = %d, return from writing offsets\n", inpmtx, fp, rc) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to write a InpMtx object for a human eye return value -- 1 if success, 0 otherwise created -- 98jan28, cca ---------------------------------------------------- */ int InpMtx_writeForHumanEye ( InpMtx *inpmtx, FILE *fp ) { double *entries ; int ierr, ii, iv, rc, size, vecid ; int *indices ; if ( inpmtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_writeForHumanEye(%p,%p)" "\n bad input\n", inpmtx, fp) ; exit(-1) ; } /* ------------------------ write out the statistics ------------------------ */ if ( (rc = InpMtx_writeStats(inpmtx, fp)) == 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeForHumanEye(%p,%p)" "\n rc = %d, return from InpMtx_writeStats(%p,%p)\n", inpmtx, fp, rc, inpmtx, fp) ; return(0) ; } if ( inpmtx->nent > 0 ) { if ( INPMTX_IS_RAW_DATA(inpmtx) || INPMTX_IS_SORTED(inpmtx) ) { int *ivec1 = InpMtx_ivec1(inpmtx) ; int *ivec2 = InpMtx_ivec2(inpmtx) ; fprintf(fp, "\n data via triples") ; if ( INPMTX_IS_INDICES_ONLY(inpmtx) ) { for ( ii = 0 ; ii < inpmtx->nent ; ii++ ) { if ( ii % 4 == 0 ) { fprintf(fp, "\n") ; } fprintf(fp, " <%6d,%6d>", ivec1[ii], ivec2[ii]) ; } } else if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { double *dvec = InpMtx_dvec(inpmtx) ; for ( ii = 0 ; ii < inpmtx->nent ; ii++ ) { if ( ii % 2 == 0 ) { fprintf(fp, "\n") ; } fprintf(fp, " <%6d,%6d,%20.12e>", ivec1[ii], ivec2[ii], dvec[ii]) ; } } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { double *dvec = InpMtx_dvec(inpmtx) ; for ( ii = 0 ; ii < inpmtx->nent ; ii++ ) { fprintf(fp, "\n <%6d,%6d,%20.12e,%20.12e>", ivec1[ii], ivec2[ii], dvec[2*ii], dvec[2*ii+1]) ; } } } else if ( INPMTX_IS_BY_VECTORS(inpmtx) && inpmtx->nvector > 0 ) { int *vecids = InpMtx_vecids(inpmtx) ; fprintf(fp, "\n data via vectors") ; if ( INPMTX_IS_INDICES_ONLY(inpmtx) ) { for ( iv = 0 ; iv < inpmtx->nvector ; iv++ ) { vecid = vecids[iv] ; InpMtx_vector(inpmtx, vecid, &size, &indices) ; if ( size > 0 ) { fprintf(fp, "\n %6d : ", vecids[iv]) ; IVfp80(fp, size, indices, 10, &ierr) ; } } } else if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { for ( iv = 0 ; iv < inpmtx->nvector ; iv++ ) { vecid = vecids[iv] ; InpMtx_realVector(inpmtx, vecid, &size, &indices, &entries); fprintf(fp, "\n %6d : ", vecids[iv]) ; IVfp80(fp, size, indices, 10, &ierr) ; DVfprintf(fp, size, entries) ; } } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { for ( iv = 0 ; iv < inpmtx->nvector ; iv++ ) { vecid = vecids[iv] ; InpMtx_complexVector(inpmtx, vecid, &size, &indices, &entries); fprintf(fp, "\n %6d : ", vecids[iv]) ; IVfp80(fp, size, indices, 10, &ierr) ; ZVfprintf(fp, size, entries) ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to write out the statistics for the InpMtx object return value -- 1 if success, 0 otherwise created -- 98jan28, cca ----------------------------------------------------------- */ int InpMtx_writeStats ( InpMtx *inpmtx, FILE *fp ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL || fp == NULL ) { fprintf(stderr, "\n error in InpMtx_writeStats(%p,%p)" "\n bad input\n", inpmtx, fp) ; exit(-1) ; } fprintf(fp, "\n InpMtx : double precision input matrix object :") ; if ( INPMTX_IS_BY_ROWS(inpmtx) ) { fprintf(fp, "\n coordType --> row triples") ; } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { fprintf(fp, "\n coordType --> column triples") ; } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { fprintf(fp, "\n coordType --> chevron triples") ; } else if ( INPMTX_IS_CUSTOM(inpmtx) ) { fprintf(fp, "\n coordType --> custom triples") ; } else { fprintf(stderr, "\n fatal error in InpMtx_writeStats(%p,%p)" "\n invalid inpmtx->coordType = %d\n", inpmtx, fp, inpmtx->coordType) ; return(0) ; } if ( INPMTX_IS_RAW_DATA(inpmtx) ) { fprintf(fp, "\n storageMode --> raw triples") ; } else if ( INPMTX_IS_SORTED(inpmtx) ) { fprintf(fp, "\n storageMode --> sorted and distinct triples") ; } else if ( INPMTX_IS_BY_VECTORS(inpmtx) ) { fprintf(fp, "\n storageMode --> vectors by first coordinate") ; } else { fprintf(stderr, "\n fatal error in InpMtx_writeStats(%p,%p)" "\n invalid inpmtx->storageMode = %d\n", inpmtx, fp, inpmtx->storageMode) ; return(0) ; } if ( INPMTX_IS_INDICES_ONLY(inpmtx) ) { fprintf(fp, "\n inputMode --> indices only") ; } else if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { fprintf(fp, "\n inputMode --> real entries") ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { fprintf(fp, "\n inputMode --> complex entries") ; } else { fprintf(stderr, "\n fatal error in InpMtx_writeStats(%p,%p)" "\n invalid inpmtx->inputMode = %d\n", inpmtx, fp, inpmtx->inputMode) ; return(0) ; } fprintf(fp, "\n maxnent = %d --> maximum number of entries", inpmtx->maxnent) ; fprintf(fp, "\n nent = %d --> present number of entries", inpmtx->nent) ; fprintf(fp, "\n resizeMultiple = %.4g --> resize multiple", inpmtx->resizeMultiple) ; fprintf(fp, "\n maxnvector = %d --> maximum number of vectors", inpmtx->maxnvector) ; fprintf(fp, "\n nvector = %d --> present number of vectors", inpmtx->nvector) ; fflush(fp) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to write a InpMtx object to a matlab file return value -- 1 if success, 0 otherwise created -- 98jan28, cca ---------------------------------------------------- */ int InpMtx_writeForMatlab ( InpMtx *inpmtx, char *mtxname, FILE *fp ) { int ii, oldCoordType, oldStorageMode ; if ( inpmtx == NULL || mtxname == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_writeForMatlab(%p,%p,%p)" "\n bad input\n", inpmtx, mtxname, fp) ; exit(-1) ; } /* fprintf(fp, "\n before changing") ; InpMtx_writeForHumanEye(inpmtx, fp) ; */ oldCoordType = inpmtx->coordType ; oldStorageMode = inpmtx->storageMode ; if ( oldCoordType != INPMTX_BY_ROWS ) { InpMtx_changeCoordType(inpmtx, INPMTX_BY_ROWS) ; } /* fprintf(fp, "\n after changing") ; InpMtx_writeForHumanEye(inpmtx, fp) ; */ if ( inpmtx->nent > 0 ) { int *ivec1 = InpMtx_ivec1(inpmtx) ; int *ivec2 = InpMtx_ivec2(inpmtx) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { double *dvec = InpMtx_dvec(inpmtx) ; for ( ii = 0 ; ii < inpmtx->nent ; ii++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e ;", mtxname, 1+ivec1[ii], 1+ivec2[ii], dvec[ii]) ; } } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { double *dvec = InpMtx_dvec(inpmtx) ; for ( ii = 0 ; ii < inpmtx->nent ; ii++ ) { fprintf(fp, "\n %s(%d,%d) = %24.16e + %24.16e*i;", mtxname, 1+ivec1[ii], 1+ivec2[ii], dvec[2*ii], dvec[2*ii+1]) ; } } } if ( oldCoordType != INPMTX_BY_ROWS ) { InpMtx_changeCoordType(inpmtx, oldCoordType) ; } InpMtx_changeStorageMode(inpmtx, oldStorageMode) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- to read in a InpMtx object from a Harwell-Boeing file input -- fn -- filename return value -- 1 if success, 0 if failure created -- 98sep11, cca --------------------------------------------------------------- */ int InpMtx_readFromHBfile ( InpMtx *inpmtx, char *fn ) { char *type ; double *values ; int ii, iiend, iistart, inputMode, jcol, ncol, nnonzeros, nrhs, nrow, rc ; int *colind, *colptr, *rowind ; /* --------------- check the input --------------- */ if ( inpmtx == NULL || fn == NULL ) { fprintf(stderr, "\n error in InpMtx_readFromFile(%p,%s)" "\n bad input\n", inpmtx, fn) ; return(0) ; } /* --------------------------------------------- read in the Harwell-Boeing matrix information --------------------------------------------- */ if ( strcmp(fn, "none") == 0 ) { fprintf(stderr, "\n no file to read from") ; exit(0) ; } rc = readHB_info(fn, &nrow, &ncol, &nnonzeros, &type, &nrhs) ; if ( rc != 1 ) { return(rc) ; } switch ( type[0] ) { case 'P' : inputMode = INPMTX_INDICES_ONLY ; break ; case 'R' : inputMode = SPOOLES_REAL ; break ; case 'C' : inputMode = SPOOLES_COMPLEX ; break ; default : fprintf(stderr, "\n fatal error in InpMtx_readFromHBfile" "\n type = %s, first character must be 'P', 'R' or 'C'", type) ; exit(-1) ; break ; } /* ----------------------------- initialize the InpMtx object ----------------------------- */ InpMtx_init(inpmtx, INPMTX_BY_COLUMNS, inputMode, nnonzeros, 0) ; colptr = IVinit(ncol+1, -1) ; colind = InpMtx_ivec1(inpmtx) ; rowind = InpMtx_ivec2(inpmtx) ; values = InpMtx_dvec(inpmtx) ; InpMtx_setNent(inpmtx, nnonzeros) ; /* ------------------------------- read in the indices and entries ------------------------------- */ rc = readHB_mat_double(fn, colptr, rowind, values) ; if ( rc != 1 ) { return(rc) ; } /* -------------------------------------------- decrement the column offsets and row indices -------------------------------------------- */ for ( jcol = 0 ; jcol <= ncol ; jcol++ ) { colptr[jcol]-- ; } for ( ii = 0 ; ii < nnonzeros ; ii++ ) { rowind[ii]-- ; } /* ------------------------------------------- fill the ivec1[] vector with column indices ------------------------------------------- */ for ( jcol = 0 ; jcol < ncol ; jcol++ ) { iistart = colptr[jcol] ; iiend = colptr[jcol+1] - 1 ; for ( ii = iistart ; ii <= iiend ; ii++ ) { colind[ii] = jcol ; } } /* ------------------------ free the working storage ------------------------ */ IVfree(colptr) ; CVfree(type) ; return(1) ; } /*--------------------------------------------------------------------*/ ------------------ write out the statistics ------------------------ */ if ( (rc = InpMtx_writeStats(inpmtx, fp)) == 0 ) { fprintf(stderr, "\n fatal error in InpMtx_writeForHumanEye(%p,%p)" "\n rc = %d, return from InpMtx_writeStats(%p,%p)\n", inpmtx, fp, rc, inpmtx, fp) ; return(0) ; } if ( inpmtx->nent > 0 ) { if ( INPMTX_IS_RAW_DATA(inpmtx) || INPMTX_IS_SORTED(inpmtx) ) { InpMtx/src/adjForATA.c010064400020550007177000000051260653410623500160060ustar00clevecompmath00000400000006/* adjForATA.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ /* ---------------------------------- return an IVL object that contains the adjacency structure of A^TA. created -- 98jan28, cca ---------------------------------- */ IVL * InpMtx_adjForATA ( InpMtx *inpmtxA ) { InpMtx *inpmtxATA ; int firstcol, firstrow, irow, jvtx, lastcol, lastrow, loc, ncol, nent, nrow, size ; int *ind, *ivec1, *ivec2 ; IVL *adjIVL ; /* --------------- check the input --------------- */ if ( inpmtxA == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_adjForATA(%p)" "\n NULL input\n", inpmtxA) ; exit(-1) ; } /* ---------------------------------------------------------- change the coordinate type and storage mode to row vectors ---------------------------------------------------------- */ InpMtx_changeCoordType(inpmtxA, INPMTX_BY_ROWS) ; InpMtx_changeStorageMode(inpmtxA, INPMTX_BY_VECTORS) ; nent = InpMtx_nent(inpmtxA) ; ivec1 = InpMtx_ivec1(inpmtxA) ; ivec2 = InpMtx_ivec2(inpmtxA) ; firstrow = IVmin(nent, ivec1, &loc) ; lastrow = IVmax(nent, ivec1, &loc) ; firstcol = IVmin(nent, ivec2, &loc) ; lastcol = IVmax(nent, ivec2, &loc) ; if ( firstrow < 0 || firstcol < 0 ) { fprintf(stderr, "\n fatal error" "\n firstrow = %d, firstcol = %d" "\n lastrow = %d, lastcol = %d", firstrow, firstcol, lastrow, lastcol) ; exit(-1) ; } nrow = 1 + lastrow ; ncol = 1 + lastcol ; /* ----------------------------------------------------------- create the new InpMtx object to hold the structure of A^TA ----------------------------------------------------------- */ inpmtxATA = InpMtx_new() ; InpMtx_init(inpmtxATA, INPMTX_BY_ROWS, INPMTX_INDICES_ONLY, 0, 0) ; for ( irow = 0 ; irow < nrow ; irow++ ) { InpMtx_vector(inpmtxA, irow, &size, &ind) ; InpMtx_inputMatrix(inpmtxATA, size, size, 1, size, ind, ind) ; } for ( jvtx = 0 ; jvtx < nrow ; jvtx++ ) { InpMtx_inputEntry(inpmtxATA, jvtx, jvtx) ; } InpMtx_changeStorageMode(inpmtxATA, INPMTX_BY_VECTORS) ; /* ------------------- fill the IVL object ------------------- */ adjIVL = IVL_new() ; IVL_init1(adjIVL, IVL_CHUNKED, nrow) ; for ( jvtx = 0 ; jvtx < ncol ; jvtx++ ) { InpMtx_vector(inpmtxATA, jvtx, &size, &ind) ; IVL_setList(adjIVL, jvtx, size, ind) ; } /* ------------------------------ free the working InpMtx object ------------------------------ */ InpMtx_free(inpmtxATA) ; return(adjIVL) ; } /*--------------------------------------------------------------------*/ InpMtx/src/basics.c010064400020550007177000000056000653410623400155130ustar00clevecompmath00000400000006/* basics.c */ #include "../InpMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98jan28, cca ----------------------- */ InpMtx * InpMtx_new ( void ) { InpMtx *inpmtx ; ALLOCATE(inpmtx, struct _InpMtx, 1) ; InpMtx_setDefaultFields(inpmtx) ; return(inpmtx) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98jan28, cca ----------------------- */ void InpMtx_setDefaultFields ( InpMtx *inpmtx ) { if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_setDefaultFields(%p)" "\n bad input", inpmtx) ; exit(-1) ; } inpmtx->coordType = INPMTX_BY_ROWS ; inpmtx->storageMode = INPMTX_RAW_DATA ; inpmtx->inputMode = SPOOLES_REAL ; inpmtx->maxnent = 0 ; inpmtx->nent = 0 ; inpmtx->resizeMultiple = 1.25 ; inpmtx->maxnvector = 0 ; inpmtx->nvector = 0 ; IV_setDefaultFields(&inpmtx->ivec1IV) ; IV_setDefaultFields(&inpmtx->ivec2IV) ; DV_setDefaultFields(&inpmtx->dvecDV) ; IV_setDefaultFields(&inpmtx->vecidsIV) ; IV_setDefaultFields(&inpmtx->sizesIV) ; IV_setDefaultFields(&inpmtx->offsetsIV) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98jan28, cca -------------------------------------------------- */ void InpMtx_clearData ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_clearData(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } /* ----------------------------------------------------- free any storage held in the IV and DV vector objects ----------------------------------------------------- */ IV_clearData(&inpmtx->ivec1IV) ; IV_clearData(&inpmtx->ivec2IV) ; DV_clearData(&inpmtx->dvecDV) ; IV_clearData(&inpmtx->vecidsIV) ; IV_clearData(&inpmtx->sizesIV) ; IV_clearData(&inpmtx->offsetsIV) ; /* ---------------------- set the default fields ---------------------- */ InpMtx_setDefaultFields(inpmtx) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98jan28, cca ------------------------------------------ */ InpMtx * InpMtx_free ( InpMtx *inpmtx ) { if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_free(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } InpMtx_clearData(inpmtx) ; FREE(inpmtx) ; return(NULL) ; } /*--------------------------------------------------------------------*/ InpMtx/src/extract.c010064400020550007177000000242220665022102700157170ustar00clevecompmath00000400000006/* extract.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- purpose -- to extract a submatrix, B = A(BrowsIV, BcolsIV) return values --- 1 -- normal return -1 -- B is NULL -2 -- BcolsIV is NULL -3 -- BrowsIV is NULL -4 -- B is NULL -5 -- invalid input mode for A -6 -- invalid coordinate type for A -7 -- invalid symmetryflag -8 -- hermitian flag but not complex -9 -- msglvl > 0 and msgFile = NULL created -- 98oct15, cca ---------------------------------------------------------- */ int InpMtx_initFromSubmatrix ( InpMtx *B, InpMtx *A, IV *BrowsIV, IV *BcolsIV, int symmetryflag, int msglvl, FILE *msgFile ) { double *dbuf, *entA ; int colA, colB, ii, jj, jjfirst, jjlast, kk, maxcolA, maxn, maxrowA, nbuf, ncolB, nent, nrowB, nvector, rowA, rowB, oldCoordType, oldStorageMode, rowsAndColumnsAreIdentical ; int *colmap, *colsA, *colsB, *ibuf1, *ibuf2, *offsets, *rowmap, *rowsB, *sizes, *vecids ; /* --------------- check the input --------------- */ if ( B == NULL ) { fprintf(stderr, "\n error in InpMtx_initFromSubmatrix()" "\n B is NULL\n") ; return(-1) ; } if ( BrowsIV == NULL ) { fprintf(stderr, "\n error in InpMtx_initFromSubmatrix()" "\n BrowsIV is NULL\n") ; return(-2) ; } if ( BcolsIV == NULL ) { fprintf(stderr, "\n error in InpMtx_initFromSubmatrix()" "\n BcolsIV is NULL\n") ; return(-3) ; } if ( A == NULL ) { fprintf(stderr, "\n error in InpMtx_initFromSubmatrix()" "\n A is NULL\n") ; return(-4) ; } switch ( A->inputMode ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : case INPMTX_INDICES_ONLY : break ; default : fprintf(stderr, "\n error in InpMtx_initFromSubmatrix()" "\n invalid inputMode %d for A\n", A->inputMode) ; return(-5) ; break ; } switch ( A->coordType ) { case INPMTX_BY_ROWS : case INPMTX_BY_COLUMNS : case INPMTX_BY_CHEVRONS : break ; default : fprintf(stderr, "\n error in InpMtx_initFromSubmatrix()" "\n invalid coordType %d for A\n", A->coordType) ; return(-6) ; break ; } switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n error in InpMtx_initFromSubmatrix()" "\n invalid symmetryflag %d \n", symmetryflag) ; return(-7) ; break ; } if ( A->inputMode != SPOOLES_COMPLEX && symmetryflag == SPOOLES_HERMITIAN ) { fprintf(stderr, "\n error in InpMtx_initFromSubmatrix()" "\n Hermitian symmetry flag but A is not complex\n") ; return(-8) ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n error in InpMtx_initFromSubmatrix()" "\n msglvl = %d, msgFile = NULL\n", msglvl) ; return(-9) ; } /*--------------------------------------------------------------------*/ /* ------------ initialize B ------------ */ InpMtx_init(B, INPMTX_BY_ROWS, A->inputMode, 0, 0) ; /* ----------------------------- get the range of entries in A ----------------------------- */ InpMtx_range(A, NULL, &maxcolA, NULL, &maxrowA) ; maxn = (maxcolA >= maxrowA) ? maxcolA : maxrowA ; /* -------------------------------------------------- get the # and indices of the rows and columns of B -------------------------------------------------- */ IV_sizeAndEntries(BrowsIV, &nrowB, &rowsB) ; IV_sizeAndEntries(BcolsIV, &ncolB, &colsB) ; if ( nrowB != ncolB ) { rowsAndColumnsAreIdentical = 0 ; } else { rowsAndColumnsAreIdentical = 1 ; for ( ii = 0 ; ii < nrowB ; ii++ ) { if ( rowsB[ii] != colsB[ii] ) { rowsAndColumnsAreIdentical = 0 ; break ; } } } /* --------------------------- set up the local column map --------------------------- */ colmap = IVinit(1+maxn, -1) ; for ( ii = 0 ; ii < ncolB ; ii++ ) { colmap[colsB[ii]] = ii ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n colmap") ; IVfprintf(msgFile, 1+maxn, colmap) ; fflush(msgFile) ; } /* --------------------------------------- change the coordinate type of A to rows and storage mode to vectors --------------------------------------- */ if ( (oldCoordType = A->coordType) != INPMTX_BY_ROWS ) { InpMtx_changeCoordType(A, INPMTX_BY_ROWS) ; } if ( (oldStorageMode = A->storageMode) != INPMTX_BY_VECTORS ) { InpMtx_changeStorageMode(A, INPMTX_BY_VECTORS) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n A") ; InpMtx_writeForHumanEye(A, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------------------------- switch over the input mode. search the rows of A that will belong to B, load into the buffer all entries that belong in columns of B. when the buffer is full, add to B matrix. ----------------------------------------------------------- */ nbuf = 100 ; ibuf1 = IVinit(nbuf, -1) ; ibuf2 = IVinit(nbuf, -1) ; kk = 0 ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { dbuf = DVinit(nbuf, 0.0) ; for ( rowB = 0 ; rowB < nrowB ; rowB++ ) { rowA = rowsB[rowB] ; InpMtx_realVector(A, rowA, &nent, &colsA, &entA) ; for ( jj = 0 ; jj < nent ; jj++ ) { if ( (colB = colmap[colsA[jj]]) != -1 ) { ibuf1[kk] = rowB ; ibuf2[kk] = colB ; dbuf[kk] = entA[jj] ; if ( ++kk == nbuf ) { InpMtx_inputRealTriples(B, kk, ibuf1, ibuf2, dbuf) ; kk = 0 ; } } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { dbuf = DVinit(2*nbuf, 0.0) ; for ( rowB = 0 ; rowB < nrowB ; rowB++ ) { rowA = rowsB[rowB] ; InpMtx_complexVector(A, rowA, &nent, &colsA, &entA) ; for ( jj = 0 ; jj < nent ; jj++ ) { if ( (colB = colmap[colsA[jj]]) != -1 ) { ibuf1[kk] = rowB ; ibuf2[kk] = colB ; dbuf[2*kk] = entA[2*jj] ; dbuf[2*kk+1] = entA[2*jj+1] ; if ( ++kk == nbuf ) { InpMtx_inputComplexTriples(B, kk, ibuf1, ibuf2, dbuf) ; kk = 0 ; } } } } } else if ( INPMTX_IS_INDICES_ONLY(A) ) { dbuf = NULL ; for ( rowB = 0 ; rowB < nrowB ; rowB++ ) { rowA = rowsB[rowB] ; InpMtx_vector(A, rowA, &nent, &colsA) ; for ( jj = 0 ; jj < nent ; jj++ ) { if ( (colB = colmap[colsA[jj]]) != -1 ) { ibuf1[kk] = rowB ; ibuf2[kk] = colB ; if ( ++kk == nbuf ) { InpMtx_inputTriples(B, kk, ibuf1, ibuf2) ; kk = 0 ; } } } } } if ( ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN) && !rowsAndColumnsAreIdentical ) { /* ---------------------------------------------- matrix is symmetric or hermitian, search lower triangle of A for entries that belong to B. ---------------------------------------------- */ rowmap = IVinit(1+maxn, -1) ; for ( ii = 0 ; ii < nrowB ; ii++ ) { rowmap[rowsB[ii]] = ii ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n rowmap") ; IVfprintf(msgFile, 1+maxn, rowmap) ; fflush(msgFile) ; } if ( INPMTX_IS_REAL_ENTRIES(A) ) { for ( colB = 0 ; colB < ncolB ; colB++ ) { colA = colsB[colB] ; InpMtx_realVector(A, colA, &nent, &colsA, &entA) ; for ( jj = 0 ; jj < nent ; jj++ ) { if ( (rowB = rowmap[colsA[jj]]) != -1 ) { ibuf1[kk] = rowB ; ibuf2[kk] = colB ; dbuf[kk] = entA[jj] ; if ( ++kk == nbuf ) { InpMtx_inputRealTriples(B, kk, ibuf1, ibuf2, dbuf) ; kk = 0 ; } } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { for ( colB = 0 ; colB < ncolB ; colB++ ) { colA = colsB[colB] ; InpMtx_complexVector(A, colA, &nent, &colsA, &entA) ; for ( jj = 0 ; jj < nent ; jj++ ) { if ( (rowB = rowmap[colsA[jj]]) != -1 ) { ibuf1[kk] = rowB ; ibuf2[kk] = colB ; dbuf[2*kk] = entA[2*jj] ; dbuf[2*kk+1] = -entA[2*jj+1] ; if ( ++kk == nbuf ) { InpMtx_inputComplexTriples(B, kk, ibuf1, ibuf2, dbuf); kk = 0 ; } } } } } else if ( INPMTX_IS_INDICES_ONLY(A) ) { for ( colB = 0 ; colB < ncolB ; colB++ ) { colA = colsB[colB] ; InpMtx_vector(A, colA, &nent, &colsA) ; for ( jj = 0 ; jj < nent ; jj++ ) { if ( (rowB = rowmap[colsA[jj]]) != -1 ) { ibuf1[kk] = rowB ; ibuf2[kk] = colB ; if ( ++kk == nbuf ) { InpMtx_inputTriples(B, kk, ibuf1, ibuf2) ; kk = 0 ; } } } } } IVfree(rowmap) ; } if ( kk > 0 ) { /* ------------------------------------------- load remaining entries in the buffer into B ------------------------------------------- */ if ( INPMTX_IS_REAL_ENTRIES(A) ) { InpMtx_inputRealTriples(B, kk, ibuf1, ibuf2, dbuf) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { InpMtx_inputComplexTriples(B, kk, ibuf1, ibuf2, dbuf) ; } else { InpMtx_inputTriples(B, kk, ibuf1, ibuf2) ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n B") ; InpMtx_writeForHumanEye(B, msgFile) ; fflush(msgFile) ; } /* ----------------------------------- set B's coordinate type and storage mode to be the same as A's on input ----------------------------------- */ InpMtx_changeCoordType(B, oldCoordType) ; InpMtx_changeStorageMode(B, oldStorageMode) ; /* ------------------------------------------- change back to the old coordinate type of A ------------------------------------------- */ if ( (oldCoordType = A->coordType) != INPMTX_BY_ROWS ) { InpMtx_changeCoordType(A, oldCoordType) ; } if ( oldStorageMode != A->storageMode ) { InpMtx_changeStorageMode(A, oldStorageMode) ; } /* ------------------------ free the working storage ------------------------ */ IVfree(colmap) ; IVfree(ibuf1) ; IVfree(ibuf2) ; if ( dbuf != NULL ) { DVfree(dbuf) ; } return(1) ; } /*--------------------------------------------------------------------*/ ntical = 1 ; for ( ii = 0 ; ii < nrowB ; ii++ ) { if ( rowsB[ii] != colsB[ii] ) { rowsAndColumnsAreIdentical = 0 ; break ; } } } /* --------------------------- set up the local column map --------------------------- */ colmap = IVinit(1+maxn, -1) ; for ( ii = 0 ; ii < ncolB ; ii++ ) { colmap[colsB[ii]] = ii ; } if ( InpMtx/src/fullAdj.c010064400020550007177000000326520665022104300156320ustar00clevecompmath00000400000006/* fullAdj.c */ #include "../InpMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- to return the full, symmetric adjacency IVL object for the graph of A + A^T created -- 98jan28, cca ------------------------------------------------------------- */ IVL * InpMtx_fullAdjacency ( InpMtx *inpmtx ) { int count, ii, jvtx, jsize, kvtx, nvtx ; int *jind, *list, *mark ; IP *baseIP, *freeIP, *ip ; IP **head ; IVL *adjIVL ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_fullAdjacency(%p)" "\n NULL input\n", inpmtx) ; exit(-1) ; } /* ---------------------- check for empty matrix ---------------------- */ if ( inpmtx->nent == 0 ) { return(NULL) ; } /* ------------------------------------------------- check for invalid coordinate type or storage mode ------------------------------------------------- */ if ( ! (INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx)) ) { InpMtx_changeCoordType(inpmtx, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(inpmtx) ) { InpMtx_changeStorageMode(inpmtx, INPMTX_BY_VECTORS) ; } nvtx = 1 + IV_max(&inpmtx->ivec1IV) ; if ( nvtx < (count = 1 + IV_max(&inpmtx->ivec2IV)) ) { nvtx = count ; } /* ------------------------- initialize the IVL object ------------------------- */ adjIVL = IVL_new() ; IVL_init1(adjIVL, IVL_CHUNKED, nvtx) ; list = IVinit(nvtx, -1) ; mark = IVinit(nvtx, -1) ; ALLOCATE(head, struct _IP *, nvtx) ; baseIP = freeIP = NULL ; /* --------------------------- initially link the vertices --------------------------- */ for ( jvtx = 0 ; jvtx < nvtx ; jvtx++ ) { head[jvtx] = NULL ; } for ( jvtx = 0 ; jvtx < nvtx ; jvtx++ ) { InpMtx_vector(inpmtx, jvtx, &jsize, &jind) ; if ( jsize > 0 ) { for ( ii = 0 ; ii < jsize ; ii++ ) { if ( (kvtx = jind[ii]) < jvtx ) { /* ----------------- link jvtx to kvtx ----------------- */ if ( (ip = freeIP) == NULL ) { ip = IP_init(nvtx+1, IP_FORWARD) ; ip->next = baseIP ; baseIP = ip ; freeIP = baseIP + 1 ; ip = freeIP ; } freeIP = ip->next ; ip->val = jvtx ; ip->next = head[kvtx] ; head[kvtx] = ip ; #if MYDEBUG > 0 fprintf(stdout, "\n linking %d to %d, %p to %p", jvtx, kvtx, ip, ip->next) ; fflush(stdout) ; #endif } } } } for ( jvtx = 0 ; jvtx < nvtx ; jvtx++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n working on vertex %d :", jvtx) ; fflush(stdout) ; #endif list[0] = jvtx ; #if MYDEBUG > 0 fprintf(stdout, "\n 0. adding %d", jvtx) ; fflush(stdout) ; #endif mark[jvtx] = jvtx ; count = 1 ; /* ------------------------------------- check previous rows that contain jvtx ------------------------------------- */ while ( (ip = head[jvtx]) != NULL ) { kvtx = ip->val ; #if MYDEBUG > 0 fprintf(stdout, "\n 1. kvtx %d", kvtx) ; fflush(stdout) ; #endif if ( mark[kvtx] != jvtx ) { mark[kvtx] = jvtx ; list[count++] = kvtx ; #if MYDEBUG > 0 fprintf(stdout, ", adding") ; fflush(stdout) ; #endif } head[jvtx] = ip->next ; ip->next = freeIP ; freeIP = ip ; } /* ---------------------------- get the indices for row jvtx ---------------------------- */ InpMtx_vector(inpmtx, jvtx, &jsize, &jind) ; if ( jsize > 0 ) { /* ---------------------------- add row indices for row jvtx ---------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n InpMtx row %d :", jvtx) ; IVfprintf(stdout, jsize, jind) ; fflush(stdout) ; #endif for ( ii = 0 ; ii < jsize ; ii++ ) { kvtx = jind[ii] ; if ( mark[kvtx] != jvtx ) { mark[kvtx] = jvtx ; list[count++] = kvtx ; #if MYDEBUG > 0 fprintf(stdout, "\n 2. adding %d", kvtx) ; fflush(stdout) ; #endif } if ( kvtx > jvtx ) { /* ----------------- link jvtx to kvtx ----------------- */ if ( (ip = freeIP) == NULL ) { ip = IP_init(nvtx+1, IP_FORWARD) ; ip->next = baseIP ; baseIP = ip ; freeIP = baseIP + 1 ; ip = freeIP ; } freeIP = ip->next ; ip->val = jvtx ; ip->next = head[kvtx] ; head[kvtx] = ip ; #if MYDEBUG > 0 fprintf(stdout, "\n linking %d to %d, %p to %p", jvtx, kvtx, ip, ip->next) ; fflush(stdout) ; #endif } } } /* ------------------------------------------------ list is complete, sort and insert into adjacency ------------------------------------------------ */ IVqsortUp(count, list) ; IVL_setList(adjIVL, jvtx, count, list) ; } /* ------------------------ free the working storage ------------------------ */ IVfree(list) ; IVfree(mark) ; FREE(head) ; while ( (ip = baseIP) != NULL ) { baseIP = baseIP->next ; IP_free(ip) ; } return(adjIVL) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- to return the full, symmetric adjacency IVL object for the graph of (A + B) + (A + B)^T created -- 97nov05, cca ------------------------------------------------------------- */ IVL * InpMtx_fullAdjacency2 ( InpMtx *inpmtxA, InpMtx *inpmtxB ) { int count, ierr, ii, jvtx, jsize, kvtx, nvtx ; int *jind, *list, *mark ; IP *baseIP, *freeIP, *ip ; IP **head ; IVL *adjIVL ; /* --------------- check the input --------------- */ if ( inpmtxA == NULL && inpmtxB == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_fullAdjacency2(%p,%p)" "\n both input matrices are NULL\n", inpmtxA, inpmtxB) ; exit(-1) ; } /* ------------------------------ cases where one matrix is NULL ------------------------------ */ if ( inpmtxA == NULL ) { adjIVL = InpMtx_fullAdjacency(inpmtxB) ; return(adjIVL) ; } else if ( inpmtxB == NULL ) { adjIVL = InpMtx_fullAdjacency(inpmtxA) ; return(adjIVL) ; } /* ------------------------------------------------- check for invalid coordinate type or storage mode ------------------------------------------------- */ if ( ! (INPMTX_IS_BY_ROWS(inpmtxA) || INPMTX_IS_BY_COLUMNS(inpmtxA)) ) { InpMtx_changeCoordType(inpmtxA, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(inpmtxA) ) { InpMtx_changeStorageMode(inpmtxA, INPMTX_BY_VECTORS) ; } if ( ! (INPMTX_IS_BY_ROWS(inpmtxB) || INPMTX_IS_BY_COLUMNS(inpmtxB)) ) { InpMtx_changeCoordType(inpmtxB, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(inpmtxB) ) { InpMtx_changeStorageMode(inpmtxB, INPMTX_BY_VECTORS) ; } nvtx = 1 + IV_max(&inpmtxA->ivec1IV) ; if ( nvtx < (count = 1 + IV_max(&inpmtxA->ivec2IV)) ) { nvtx = count ; } if ( nvtx < (count = 1 + IV_max(&inpmtxB->ivec1IV)) ) { nvtx = count ; } if ( nvtx < (count = 1 + IV_max(&inpmtxB->ivec2IV)) ) { nvtx = count ; } /* ------------------------- initialize the IVL object ------------------------- */ adjIVL = IVL_new() ; IVL_init1(adjIVL, IVL_CHUNKED, nvtx) ; /* ------------------------------ initialize the working storage ------------------------------ */ list = IVinit(nvtx, -1) ; mark = IVinit(nvtx, -1) ; ALLOCATE(head, struct _IP *, nvtx) ; baseIP = freeIP = NULL ; /* --------------------------- initially link the vertices --------------------------- */ for ( jvtx = 0 ; jvtx < nvtx ; jvtx++ ) { head[jvtx] = NULL ; } for ( jvtx = 0 ; jvtx < nvtx ; jvtx++ ) { InpMtx_vector(inpmtxA, jvtx, &jsize, &jind) ; if ( jsize > 0 ) { for ( ii = 0 ; ii < jsize ; ii++ ) { if ( (kvtx = jind[ii]) < jvtx ) { /* ----------------- link jvtx to kvtx ----------------- */ if ( (ip = freeIP) == NULL ) { ip = IP_init(nvtx+1, IP_FORWARD) ; ip->next = baseIP ; baseIP = ip ; freeIP = baseIP + 1 ; ip = freeIP ; } freeIP = ip->next ; ip->val = jvtx ; ip->next = head[kvtx] ; head[kvtx] = ip ; #if MYDEBUG > 0 fprintf(stdout, "\n linking %d to %d, %p to %p", jvtx, kvtx, ip, ip->next) ; fflush(stdout) ; #endif } } } InpMtx_vector(inpmtxB, jvtx, &jsize, &jind) ; if ( jsize > 0 ) { for ( ii = 0 ; ii < jsize ; ii++ ) { if ( (kvtx = jind[ii]) < jvtx ) { /* ----------------- link jvtx to kvtx ----------------- */ if ( (ip = freeIP) == NULL ) { ip = IP_init(nvtx+1, IP_FORWARD) ; ip->next = baseIP ; baseIP = ip ; freeIP = baseIP + 1 ; ip = freeIP ; } freeIP = ip->next ; ip->val = jvtx ; ip->next = head[kvtx] ; head[kvtx] = ip ; #if MYDEBUG > 0 fprintf(stdout, "\n linking %d to %d, %p to %p", jvtx, kvtx, ip, ip->next) ; fflush(stdout) ; #endif } } } } for ( jvtx = 0 ; jvtx < nvtx ; jvtx++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n vertex %d :", jvtx) ; fflush(stdout) ; #endif list[0] = jvtx ; #if MYDEBUG > 0 fprintf(stdout, "\n 0. adding %d", jvtx) ; fflush(stdout) ; #endif mark[jvtx] = jvtx ; count = 1 ; /* ------------------------------------- check previous rows that contain jvtx ------------------------------------- */ while ( (ip = head[jvtx]) != NULL ) { kvtx = ip->val ; #if MYDEBUG > 0 fprintf(stdout, "\n 1. kvtx %d", kvtx) ; fflush(stdout) ; #endif if ( mark[kvtx] != jvtx ) { mark[kvtx] = jvtx ; list[count++] = kvtx ; #if MYDEBUG > 0 fprintf(stdout, ", adding") ; fflush(stdout) ; #endif } head[jvtx] = ip->next ; ip->next = freeIP ; freeIP = ip ; } /* ---------------------------- get the indices for row jvtx ---------------------------- */ InpMtx_vector(inpmtxA, jvtx, &jsize, &jind) ; if ( jsize > 0 ) { /* ---------------------------- add row indices for row jvtx ---------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n InpMtx row %d :", jvtx) ; IVfprintf(stdout, jsize, jind) ; fflush(stdout) ; #endif for ( ii = 0 ; ii < jsize ; ii++ ) { kvtx = jind[ii] ; if ( mark[kvtx] != jvtx ) { mark[kvtx] = jvtx ; list[count++] = kvtx ; #if MYDEBUG > 0 fprintf(stdout, "\n 2. adding %d", kvtx) ; fflush(stdout) ; #endif } if ( kvtx > jvtx ) { /* ----------------- link jvtx to kvtx ----------------- */ if ( (ip = freeIP) == NULL ) { ip = IP_init(nvtx+1, IP_FORWARD) ; ip->next = baseIP ; baseIP = ip ; freeIP = baseIP + 1 ; ip = freeIP ; } freeIP = ip->next ; ip->val = jvtx ; ip->next = head[kvtx] ; head[kvtx] = ip ; #if MYDEBUG > 0 fprintf(stdout, "\n linking %d to %d, %p to %p", jvtx, kvtx, ip, ip->next) ; fflush(stdout) ; #endif } } } InpMtx_vector(inpmtxB, jvtx, &jsize, &jind) ; if ( jsize > 0 ) { /* ---------------------------- add row indices for row jvtx ---------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n InpMtx row %d :", jvtx) ; IVfprintf(stdout, jsize, jind) ; fflush(stdout) ; #endif for ( ii = 0 ; ii < jsize ; ii++ ) { kvtx = jind[ii] ; if ( mark[kvtx] != jvtx ) { mark[kvtx] = jvtx ; list[count++] = kvtx ; #if MYDEBUG > 0 fprintf(stdout, "\n 2. adding %d", kvtx) ; fflush(stdout) ; #endif } if ( kvtx > jvtx ) { /* ----------------- link jvtx to kvtx ----------------- */ if ( (ip = freeIP) == NULL ) { ip = IP_init(nvtx+1, IP_FORWARD) ; ip->next = baseIP ; baseIP = ip ; freeIP = baseIP + 1 ; ip = freeIP ; } freeIP = ip->next ; ip->val = jvtx ; ip->next = head[kvtx] ; head[kvtx] = ip ; #if MYDEBUG > 0 fprintf(stdout, "\n linking %d to %d, %p to %p", jvtx, kvtx, ip, ip->next) ; fflush(stdout) ; #endif } } } /* ------------------------------------------------ list is complete, sort and insert into adjacency ------------------------------------------------ */ IVqsortUp(count, list) ; IVL_setList(adjIVL, jvtx, count, list) ; } /* ------------------------ free the working storage ------------------------ */ IVfree(list) ; IVfree(mark) ; FREE(head) ; while ( (ip = baseIP) != NULL ) { baseIP = baseIP->next ; IP_free(ip) ; } return(adjIVL) ; } /*--------------------------------------------------------------------*/ InpMtx/src/gmmm.c010064400020550007177000001477330662341011100152110ustar00clevecompmath00000400000006/* gmmm.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ static int checkInput ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X, char *methodname ) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A*X where X and Y are DenseMtx objects, and X and Y must be column major. return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- Y is NULL -6 -- type of Y is invalid -7 -- dimensions and strides of Y do not line up -8 -- entries of Y are NULL -9 -- alpha is NULL -10 -- X is NULL -11 -- type of X is invalid -12 -- dimensions and strides of X do not line up -13 -- entries of X are NULL -14 -- types of A, X and Y are not identical -15 -- # of columns of X and Y are not equal created -- 98may02, cca -------------------------------------------------- */ int InpMtx_nonsym_gmmm ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) { int incX, incY, ncolX, ncolY, nent, nrhs, nrowX, nrowY, rc ; int *ivec1, *ivec2 ; double *dvec, *x, *y ; /* --------------- check the input --------------- */ rc = checkInput(A, beta, Y, alpha, X, "InpMtx_nonsym_gmmm") ; if ( rc != 1 ) { return(rc) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; incY = Y->inc2 ; y = Y->entries ; nrhs = Y->ncol ; incX = X->inc2 ; x = X->entries ; /* ---------------- scale Y by beta ---------------- */ DenseMtx_scale(Y, beta) ; /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, jrhs, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A^T*X return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- Y is NULL -6 -- type of Y is invalid -7 -- dimensions and strides of Y do not line up -8 -- entries of Y are NULL -9 -- alpha is NULL -10 -- X is NULL -11 -- type of X is invalid -12 -- dimensions and strides of X do not line up -13 -- entries of X are NULL -14 -- types of A, X and Y are not identical -15 -- # of columns of X and Y are not equal created -- 98may02, cca -------------------------------------------------- */ int InpMtx_nonsym_gmmm_T ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) { int incX, incY, ncolX, ncolY, nent, nrhs, nrowX, nrowY, rc ; int *ivec1, *ivec2 ; double *dvec, *x, *y ; /* --------------- check the input --------------- */ rc = checkInput(A, beta, Y, alpha, X, "InpMtx_nonsym_gmmm_T") ; if ( rc != 1 ) { return(rc) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; incY = Y->inc2 ; y = Y->entries ; nrhs = Y->ncol ; incX = X->inc2 ; x = X->entries ; /* ---------------- scale Y by beta ---------------- */ DenseMtx_scale(Y, beta) ; /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, jrhs, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec2[ii] ; row = ivec1[ii] ; y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec2[ii] ; row = ivec1[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A^H*X return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- Y is NULL -6 -- type of Y is invalid -7 -- dimensions and strides of Y do not line up -8 -- entries of Y are NULL -9 -- alpha is NULL -10 -- X is NULL -11 -- type of X is invalid -12 -- dimensions and strides of X do not line up -13 -- entries of X are NULL -14 -- types of A, X and Y are not identical -15 -- # of columns of X and Y are not equal -16 -- A, X and Y are real created -- 98may02, cca --------------------------------------------------- */ int InpMtx_nonsym_gmmm_H ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) { int incX, incY, ncolX, ncolY, nent, nrhs, nrowX, nrowY, rc ; int *ivec1, *ivec2 ; double *dvec, *x, *y ; /* --------------- check the input --------------- */ rc = checkInput(A, beta, Y, alpha, X, "InpMtx_nonsym_gmmm_H") ; if ( rc != 1 ) { return(rc) ; } if ( INPMTX_IS_REAL_ENTRIES(A) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_gmmm_H()" "\n A, X and Y are real\n") ; return(-16) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; incY = Y->inc2 ; y = Y->entries ; nrhs = Y->ncol ; incX = X->inc2 ; x = X->entries ; /* ---------------- scale Y by beta ---------------- */ DenseMtx_scale(Y, beta) ; /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ nent = A->nent ; if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A*X where A is symmetric return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- Y is NULL -6 -- type of Y is invalid -7 -- dimensions and strides of Y do not line up -8 -- entries of Y are NULL -9 -- alpha is NULL -10 -- X is NULL -11 -- type of X is invalid -12 -- dimensions and strides of X do not line up -13 -- entries of X are NULL -14 -- types of A, X and Y are not identical -15 -- # of columns of X and Y are not equal created -- 98nov06, cca ---------------------------------------------------- */ int InpMtx_sym_gmmm ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) { int incX, incY, ncolX, ncolY, nent, nrhs, nrowX, nrowY, rc ; int *ivec1, *ivec2 ; double *dvec, *x, *y ; /* --------------- check the input --------------- */ rc = checkInput(A, beta, Y, alpha, X, "InpMtx_sym_gmmm") ; if ( rc != 1 ) { return(rc) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; incY = Y->inc2 ; y = Y->entries ; nrhs = Y->ncol ; incX = X->inc2 ; x = X->entries ; /* ---------------- scale Y by beta ---------------- */ DenseMtx_scale(Y, beta) ; /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, jrhs, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A*X where A is hermitian return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- Y is NULL -6 -- type of Y is invalid -7 -- dimensions and strides of Y do not line up -8 -- entries of Y are NULL -9 -- alpha is NULL -10 -- X is NULL -11 -- type of X is invalid -12 -- dimensions and strides of X do not line up -13 -- entries of X are NULL -14 -- types of A, X and Y are not identical -15 -- # of columns of X and Y are not equal -16 -- A, X and Y are real created -- 98nov06, cca -------------------------------------------------- */ int InpMtx_herm_gmmm ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) { int incX, incY, ncolX, ncolY, nent, nrhs, nrowX, nrowY, rc ; int *ivec1, *ivec2 ; double *dvec, *x, *y ; /* --------------- check the input --------------- */ rc = checkInput(A, beta, Y, alpha, X, "InpMtx_herm_gmmm") ; if ( rc != 1 ) { return(rc) ; } if ( INPMTX_IS_REAL_ENTRIES(A) ) { fprintf(stderr, "\n fatal error in InpMtx_herm_gmmm()" "\n A, X and Y are real\n") ; return(-16) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; incY = Y->inc2 ; y = Y->entries ; nrhs = Y->ncol ; incX = X->inc2 ; x = X->entries ; /* ---------------- scale Y by beta ---------------- */ DenseMtx_scale(Y, beta) ; /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ nent = A->nent ; if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to check the input return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- Y is NULL -6 -- type of Y is invalid -7 -- dimensions and strides of Y do not line up -8 -- entries of Y are NULL -9 -- alpha is NULL -10 -- X is NULL -11 -- type of X is invalid -12 -- dimensions and strides of X do not line up -13 -- entries of X are NULL -14 -- types of A, X and Y are not identical -15 -- # of columns of X and Y are not equal created -- 98may02, cca -------------------------------------------------- */ static int checkInput ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X, char *methodname ) { double *dvec, *x, *y ; int colincX, colincY, rowincX, rowincY, ncolX, ncolY, nrowX, nrowY, typeA, typeX, typeY ; int *ivec1, *ivec2 ; if ( A == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n A is NULL\n", methodname) ; return(-1) ; } typeA = A->inputMode ; if ( typeA != SPOOLES_REAL && typeA != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error in %s()" "\n type of A is %d, invalid\n", methodname, typeA) ; return(-2) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n ivec1 %p, ivec2 %p, dvec %p\n", methodname, ivec1, ivec2, dvec) ; return(-3) ; } if ( beta == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n beta is NULL\n", methodname) ; return(-4) ; } if ( Y == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n Y is NULL\n", methodname) ; return(-5) ; } typeY = Y->type ; if ( typeY != SPOOLES_REAL && typeY != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error in %s()" "\n type of Y is %d, invalid\n", methodname, typeY) ; return(-6) ; } DenseMtx_dimensions(Y, &nrowY, &ncolY) ; colincY = DenseMtx_columnIncrement(Y) ; rowincY = DenseMtx_rowIncrement(Y) ; if ( nrowY <= 0 || ncolY <= 0 || rowincY != 1 || colincY != nrowY ) { fprintf(stderr, "\n fatal error in %s()" "\n nrowY %d, ncolY %d, rowincY %d, colincY %d\n", methodname, nrowY, ncolY, rowincY, colincY) ; return(-7) ; } y = DenseMtx_entries(Y) ; if ( y == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n Y's entries are NULL\n", methodname) ; return(-8) ; } if ( alpha == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n alpha is NULL\n", methodname) ; return(-9) ; } if ( X == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n X is NULL\n", methodname) ; return(-10) ; } typeX = X->type ; if ( typeX != SPOOLES_REAL && typeX != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error in %s()" "\n type of X is %d, invalid\n", methodname, typeX) ; return(-11) ; } DenseMtx_dimensions(X, &nrowX, &ncolX) ; colincX = DenseMtx_columnIncrement(X) ; rowincX = DenseMtx_rowIncrement(X) ; if ( nrowX <= 0 || ncolX <= 0 || rowincX != 1 || colincX != nrowX ) { fprintf(stderr, "\n fatal error in %s()" "\n nrowX %d, ncolX %d, rowincX %d, colincX %d\n", methodname, nrowX, ncolX, rowincX, colincX) ; return(-12) ; } x = DenseMtx_entries(X) ; if ( x == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n entries of X are NULL\n", methodname) ; return(-13) ; } if ( typeA != typeX || typeA != typeY || typeX != typeY ) { fprintf(stderr, "\n fatal error in %s()" "\n types do not match, typeA %d, typeX %d, typeY %d\n", methodname, typeA, typeX, typeY) ; return(-14) ; } if ( ncolY != ncolX ) { fprintf(stderr, "\n fatal error in %s()" "\n ncolY %d, ncolX %d\n", methodname, ncolY, ncolX) ; return(-15) ; } return(1) ; } /*--------------------------------------------------------------------*/ ivec2[ii] ; areal = dInpMtx/src/gmvm.c010064400020550007177000001226310665341063500152260ustar00clevecompmath00000400000006/* gmvm.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ static int checkInput ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[], char *methodname ) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to compute y := beta*y + alpha*A*x where x and y are double vectors. return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 -9 -- x is NULL created -- 98nov14, cca -------------------------------------------------- */ int InpMtx_nonsym_gmvm ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) { int nent, rc ; int *ivec1, *ivec2 ; double *dvec ; /* --------------- check the input --------------- */ rc = checkInput(A, beta, ny, y, alpha, nx, x, "InpMtx_nonsym_gmvm") ; if ( rc != 1 ) { return(rc) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; /* ---------------- scale y by beta ---------------- */ if ( INPMTX_IS_REAL_ENTRIES(A) ) { if ( beta[0] == 0.0 ) { DVzero(ny, y) ; } else if ( beta[0] != 0.0 ) { DVscale(ny, y, beta[0]) ; } } else { if ( beta[0] == 0.0 && beta[1] == 0.0 ) { ZVzero(ny, y) ; } else if ( beta[0] != 1.0 || beta[1] != 0.0 ) { ZVscale(ny, y, beta[0], beta[1]) ; } } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A^T*X return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 -9 -- x is NULL created -- 98may02, cca -------------------------------------------------- */ int InpMtx_nonsym_gmvm_T ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) { int nent, rc ; int *ivec1, *ivec2 ; double *dvec ; /* --------------- check the input --------------- */ rc = checkInput(A, beta, ny, y, alpha, nx, x, "InpMtx_nonsym_gmvm_T") ; if ( rc != 1 ) { return(rc) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; /* ---------------- scale y by beta ---------------- */ if ( INPMTX_IS_REAL_ENTRIES(A) ) { if ( beta[0] == 0.0 ) { DVzero(ny, y) ; } else if ( beta[0] != 0.0 ) { DVscale(ny, y, beta[0]) ; } } else { if ( beta[0] == 0.0 && beta[1] == 0.0 ) { ZVzero(ny, y) ; } else if ( beta[0] != 1.0 || beta[1] != 0.0 ) { ZVscale(ny, y, beta[0], beta[1]) ; } } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, jrhs, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec2[ii] ; row = ivec1[ii] ; y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec2[ii] ; row = ivec1[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A^H*X return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 -9 -- x is NULL -10 -- A is real created -- 98may02, cca --------------------------------------------------- */ int InpMtx_nonsym_gmvm_H ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) { int nent, rc ; int *ivec1, *ivec2 ; double *dvec ; /* --------------- check the input --------------- */ rc = checkInput(A, beta, ny, y, alpha, nx, x, "InpMtx_nonsym_gmvm_H") ; if ( rc != 1 ) { return(rc) ; } if ( INPMTX_IS_REAL_ENTRIES(A) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_gmvm_H()" "\n A, X and Y are real\n") ; return(-10) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; /* ---------------- scale y by beta ---------------- */ if ( INPMTX_IS_REAL_ENTRIES(A) ) { if ( beta[0] == 0.0 ) { DVzero(ny, y) ; } else if ( beta[0] != 0.0 ) { DVscale(ny, y, beta[0]) ; } } else { if ( beta[0] == 0.0 && beta[1] == 0.0 ) { ZVzero(ny, y) ; } else if ( beta[0] != 1.0 || beta[1] != 0.0 ) { ZVscale(ny, y, beta[0], beta[1]) ; } } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ nent = A->nent ; if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A*X where A is symmetric return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 -9 -- x is NULL created -- 98nov06, cca ---------------------------------------------------- */ int InpMtx_sym_gmvm ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) { int nent, rc ; int *ivec1, *ivec2 ; double *dvec ; /* --------------- check the input --------------- */ rc = checkInput(A, beta, ny, y, alpha, nx, x, "InpMtx_sym_gmvm") ; if ( rc != 1 ) { return(rc) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; /* ---------------- scale y by beta ---------------- */ if ( INPMTX_IS_REAL_ENTRIES(A) ) { if ( beta[0] == 0.0 ) { DVzero(ny, y) ; } else if ( beta[0] != 0.0 ) { DVscale(ny, y, beta[0]) ; } } else { if ( beta[0] == 0.0 && beta[1] == 0.0 ) { ZVzero(ny, y) ; } else if ( beta[0] != 1.0 || beta[1] != 0.0 ) { ZVscale(ny, y, beta[0], beta[1]) ; } } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, jrhs, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } } else { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } } else { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } } else { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to compute Y := beta*Y + alpha*A*X where A is hermitian return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 -9 -- x is NULL -10 -- A, X and Y are real created -- 98nov06, cca -------------------------------------------------- */ int InpMtx_herm_gmvm ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) { int nent, rc ; int *ivec1, *ivec2 ; double *dvec ; /* --------------- check the input --------------- */ rc = checkInput(A, beta, ny, y, alpha, nx, x, "InpMtx_herm_gmvm") ; if ( rc != 1 ) { return(rc) ; } if ( INPMTX_IS_REAL_ENTRIES(A) ) { fprintf(stderr, "\n fatal error in InpMtx_herm_gmvm()" "\n A, X and Y are real\n") ; return(-10) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; /* ---------------- scale y by beta ---------------- */ if ( INPMTX_IS_REAL_ENTRIES(A) ) { if ( beta[0] == 0.0 ) { DVzero(ny, y) ; } else if ( beta[0] != 0.0 ) { DVscale(ny, y, beta[0]) ; } } else { if ( beta[0] == 0.0 && beta[1] == 0.0 ) { ZVzero(ny, y) ; } else if ( beta[0] != 1.0 || beta[1] != 0.0 ) { ZVscale(ny, y, beta[0], beta[1]) ; } } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ nent = A->nent ; if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to check the input return values --- 1 -- normal return -1 -- A is NULL -2 -- type of A is invalid -3 -- indices or entries of A are NULL -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 -9 -- x is NULL created -- 98may02, cca -------------------------------------------------- */ static int checkInput ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[], char *methodname ) { double *dvec ; int typeX, typeY ; int *ivec1, *ivec2 ; if ( A == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n A is NULL\n", methodname) ; return(-1) ; } if ( ! INPMTX_IS_REAL_ENTRIES(A) && ! INPMTX_IS_COMPLEX_ENTRIES(A) ) { fprintf(stderr, "\n fatal error in %s()" "\n type of A is %d, invalid\n", methodname, A->inputMode) ; return(-2) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n ivec1 %p, ivec2 %p, dvec %p\n", methodname, ivec1, ivec2, dvec) ; return(-3) ; } if ( beta == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n beta is NULL\n", methodname) ; return(-4) ; } if ( ny <= 0 ) { fprintf(stderr, "\n fatal error in %s()" "\n ny = %d\n", methodname, ny) ; return(-5) ; } if ( y == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n y is NULL\n", methodname) ; return(-6) ; } if ( alpha == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n alpha is NULL\n", methodname) ; return(-7) ; } if ( nx <= 0 ) { fprintf(stderr, "\n fatal error in %s()" "\n nx = %d\n", methodname, nx) ; return(-8) ; } if ( x == NULL ) { fprintf(stderr, "\n fatal error in %s()" "\n x is NULL\n", methodname) ; return(-9) ; } return(1) ; } /*--------------------------------------------------------------------*/ -4 -- beta is NULL -5 -- ny <= 0 -6 -- y is NULL -7 -- alpha is NULL -8 -- nx <= 0 InpMtx/src/init.c010064400020550007177000000245540653410623500152240ustar00clevecompmath00000400000006/* init.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ initialize the object coordType -- coordinate type, input supported for types 1, 2 and 3 1 -- row triples (i, j, a_{i,j}) 2 -- column triples (i, j, a_{j,i}) 3 -- chevron triples (i, k, a_{i,i+k}) if k >= 0 (i, k, a_{i-k,i}) if k < 0 i is the chevron, k is the offset 4 -- custom coordinate, e.g., one could store (I, k, a_{i,j}) where I is the front where a_{i,j} will be assembled and k is the offset into the vector that holds the entries in the front inputMode -- mode for input 0 --> indices only 1 --> indices and real entries 2 --> indices and complex entries maxnent -- upper bound on the number of entries, also equal to the workspace, so if the assembly includes overlapping data, give enough elbow room for efficiency. maxnvector -- upper bound on the number of vectors to be supported. this may not be known ahead of time (e.g., the number of vectors may be the number of fronts which is not known before the ordering is done and front tree constructed). created -- 98jan28, cca ------------------------------------------------------------------ */ void InpMtx_init ( InpMtx *inpmtx, int coordType, int inputMode, int maxnent, int maxnvector ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_init(%p,%d,%d,%d,%d)" "\n inpmtx is NULL \n", inpmtx, coordType, inputMode, maxnent, maxnvector) ; exit(-1) ; } if ( ! ( INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_init(%p,%d,%d,%d,%d)" "\n bad coordType \n", inpmtx, coordType, inputMode, maxnent, maxnvector) ; exit(-1) ; } if ( ! (INPMTX_IS_INDICES_ONLY(inpmtx) || INPMTX_IS_REAL_ENTRIES(inpmtx) || INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_init(%p,%d,%d,%d,%d)" "\n bad inputMode \n", inpmtx, coordType, inputMode, maxnent, maxnvector) ; exit(-1) ; } if ( maxnent < 0 || maxnvector < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_init(%p,%d,%d,%d,%d)" "\n maxnent = %d, maxnvector = %d \n", inpmtx, coordType, inputMode, maxnent, maxnvector, maxnent, maxnvector) ; exit(-1) ; } /* ------------------------ clear the data structure ------------------------ */ InpMtx_clearData(inpmtx) ; /* ------------------------------------------------------------------- if maxnent > 0 then allocate the ivec1[], ivec2[] and dvec[] vectors ------------------------------------------------------------------- */ inpmtx->coordType = coordType ; inpmtx->inputMode = inputMode ; if ( maxnent > 0 ) { InpMtx_setMaxnent(inpmtx, maxnent) ; } /* --------------------------------------- if nvector > 0 initialize the vecids[], sizes[] and offsets[] vectors. --------------------------------------- */ if ( maxnvector > 0 ) { InpMtx_setMaxnvector(inpmtx, maxnvector) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------- change the coordinate type created -- 98jan28, cca -------------------------- */ void InpMtx_changeCoordType ( InpMtx *inpmtx, int newType ) { int chev, col, i, nent, off, oldType, row, temp ; int *ivec1, *ivec2 ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_changeCoordType(%p,%d)" "\n bad input\n", inpmtx, newType) ; exit(-1) ; } if ( newType != INPMTX_BY_ROWS && newType != INPMTX_BY_COLUMNS && newType != INPMTX_BY_CHEVRONS && newType != INPMTX_CUSTOM ) { fprintf(stderr, "\n fatal error in InpMtx_changeCoordType(%p,%d)" "\n bad new coordType\n", inpmtx, newType) ; exit(-1) ; } if ( ! ( INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_changeCoordType(%p,%d)" "\n bad existing coordType\n", inpmtx, newType) ; exit(-1) ; } oldType = inpmtx->coordType ; if ( oldType == newType ) { return ; } if ( newType == INPMTX_CUSTOM ) { /* ---------------------------------------------------- custom type, just set the coordType field and return ---------------------------------------------------- */ inpmtx->coordType = INPMTX_CUSTOM ; return ; } nent = inpmtx->nent ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; if ( oldType == INPMTX_BY_ROWS ) { if ( newType == INPMTX_BY_COLUMNS ) { /* ---------------------------------- row coordType --> column coordType ---------------------------------- */ for ( i = 0 ; i < nent ; i++ ) { temp = ivec1[i] ; ivec1[i] = ivec2[i] ; ivec2[i] = temp ; } inpmtx->coordType = INPMTX_BY_COLUMNS ; inpmtx->storageMode = INPMTX_RAW_DATA ; } else if ( newType == INPMTX_BY_CHEVRONS ) { /* ----------------------------------- row coordType --> chevron coordType ----------------------------------- */ for ( i = 0 ; i < nent ; i++ ) { row = ivec1[i] ; col = ivec2[i] ; if ( row <= col ) { ivec1[i] = row ; ivec2[i] = col - row ; } else { ivec1[i] = col ; ivec2[i] = col - row ; } } inpmtx->coordType = INPMTX_BY_CHEVRONS ; inpmtx->storageMode = INPMTX_RAW_DATA ; } } else if ( oldType == INPMTX_BY_COLUMNS ) { if ( newType == INPMTX_BY_ROWS ) { /* ---------------------------------- column coordType --> row coordType ---------------------------------- */ for ( i = 0 ; i < nent ; i++ ) { temp = ivec1[i] ; ivec1[i] = ivec2[i] ; ivec2[i] = temp ; } inpmtx->coordType = INPMTX_BY_ROWS ; inpmtx->storageMode = INPMTX_RAW_DATA ; } else if ( newType == INPMTX_BY_CHEVRONS ) { /* -------------------------------------- column coordType --> chevron coordType -------------------------------------- */ for ( i = 0 ; i < nent ; i++ ) { col = ivec1[i] ; row = ivec2[i] ; if ( row <= col ) { ivec1[i] = row ; ivec2[i] = col - row ; } else { ivec1[i] = col ; ivec2[i] = col - row ; } } inpmtx->coordType = INPMTX_BY_CHEVRONS ; inpmtx->storageMode = INPMTX_RAW_DATA ; } } else if ( oldType == INPMTX_BY_CHEVRONS ) { if ( newType == INPMTX_BY_ROWS ) { /* ----------------------------------- chevron coordType --> row coordType ----------------------------------- */ for ( i = 0 ; i < nent ; i++ ) { chev = ivec1[i] ; off = ivec2[i] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } ivec1[i] = row ; ivec2[i] = col ; } inpmtx->coordType = INPMTX_BY_ROWS ; inpmtx->storageMode = INPMTX_RAW_DATA ; } else if ( newType == INPMTX_BY_COLUMNS ) { /* -------------------------------------- chevron coordType --> column coordType -------------------------------------- */ for ( i = 0 ; i < nent ; i++ ) { chev = ivec1[i] ; off = ivec2[i] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } ivec1[i] = col ; ivec2[i] = row ; } inpmtx->coordType = INPMTX_BY_COLUMNS ; inpmtx->storageMode = INPMTX_RAW_DATA ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------- change the storage mode created -- 98jan28, cca ----------------------- */ void InpMtx_changeStorageMode ( InpMtx *inpmtx, int newMode ) { int oldMode ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_changeStorageMode(%p,%d)" "\n inpmtx is NULL\n", inpmtx, newMode) ; exit(-1) ; } if ( newMode != INPMTX_RAW_DATA && newMode != INPMTX_SORTED && newMode != INPMTX_BY_VECTORS ) { fprintf(stderr, "\n fatal error in InpMtx_changeStorageMode(%p,%d)" "\n bad new storage mode\n", inpmtx, newMode) ; exit(-1) ; } oldMode = inpmtx->storageMode ; if ( oldMode == newMode ) { return ; } if ( oldMode == INPMTX_RAW_DATA ) { if ( newMode == INPMTX_SORTED ) { /* ------------------------------------- raw triples --> sorted and compressed ------------------------------------- */ InpMtx_sortAndCompress(inpmtx) ; inpmtx->storageMode = INPMTX_SORTED ; } else if ( newMode == INPMTX_BY_VECTORS ) { /* ----------------------- raw triples --> vectors ----------------------- */ InpMtx_sortAndCompress(inpmtx) ; InpMtx_convertToVectors(inpmtx) ; inpmtx->storageMode = INPMTX_BY_VECTORS ; } } else if ( oldMode == INPMTX_SORTED ) { if ( newMode == INPMTX_RAW_DATA ) { /* -------------------------------------- sorted and compressed --> raw triples, simply set the storageMode field -------------------------------------- */ inpmtx->storageMode = INPMTX_RAW_DATA ; } else if ( newMode == INPMTX_BY_VECTORS ) { /* --------------------------------- sorted and compressed --> vectors --------------------------------- */ InpMtx_convertToVectors(inpmtx) ; inpmtx->storageMode = INPMTX_BY_VECTORS ; } } else if ( oldMode == INPMTX_BY_VECTORS ) { if ( newMode == INPMTX_RAW_DATA || newMode == INPMTX_SORTED ) { /* -------------------------------- vectors --> triples, simply set the storageMode field -------------------------------- */ inpmtx->storageMode = newMode ; } } return ; } /*--------------------------------------------------------------------*/ ------------------------------------------*/ /* -------------------------- change the coordinate type created -- 98jan28, cca ---------InpMtx/src/input.c010064400020550007177000000736500660767666200154420ustar00clevecompmath00000400000006/* input.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ /* --------------------------------- prepare to add more entries, sort/compress and possible resize created -- 98apr25, cca --------------------------------- */ static void prepareToAddNewEntries ( InpMtx *inpmtx, int nnewent ) { if ( inpmtx->nent + nnewent > inpmtx->maxnent ) { /* ----------------------------------- vectors are full, sort and compress ----------------------------------- */ InpMtx_sortAndCompress(inpmtx) ; inpmtx->storageMode = INPMTX_SORTED ; } if ( inpmtx->nent + nnewent > inpmtx->maxnent ) { /* ------------------------------ vectors are still full, resize ------------------------------ */ int newmaxnent = inpmtx->maxnent * inpmtx->resizeMultiple ; if ( newmaxnent < inpmtx->nent + nnewent ) { newmaxnent = inpmtx->nent + nnewent ; } InpMtx_setMaxnent(inpmtx, newmaxnent) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- input a single entry in the matrix created -- 98jan28, cca ---------------------------------- */ static void inputEntry ( InpMtx *inpmtx, int row, int col, double real, double imag ) { int nent ; int *ivec1, *ivec2 ; prepareToAddNewEntries(inpmtx, 1) ; nent = inpmtx->nent ; ivec1 = IV_entries(&inpmtx->ivec1IV) ; ivec2 = IV_entries(&inpmtx->ivec2IV) ; if ( INPMTX_IS_BY_ROWS(inpmtx) ) { ivec1[nent] = row ; ivec2[nent] = col ; } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { ivec1[nent] = col ; ivec2[nent] = row ; } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { if ( row <= col ) { ivec1[nent] = row ; ivec2[nent] = col - row ; } else { ivec1[nent] = col ; ivec2[nent] = col - row ; } } IV_setSize(&inpmtx->ivec1IV, nent + 1) ; IV_setSize(&inpmtx->ivec2IV, nent + 1) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) ; dvec[nent] = real ; DV_setSize(&inpmtx->dvecDV, nent + 1) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) ; dvec[2*nent] = real ; dvec[2*nent+1] = imag ; DV_setSize(&inpmtx->dvecDV, 2*(nent + 1)) ; } inpmtx->nent++ ; inpmtx->storageMode = INPMTX_RAW_DATA ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- input a single entry in the matrix created -- 98jan28, cca ---------------------------------- */ void InpMtx_inputEntry ( InpMtx *inpmtx, int row, int col ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || row < 0 || col < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_inputEntry(%p,%d,%d)" "\n bad input\n", inpmtx, row, col) ; exit(-1) ; } if ( !( INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_inputEntry(%p,%d,%d)" "\n bad coordType = %d\n", inpmtx, row, col, inpmtx->coordType) ; exit(-1) ; } if ( ! INPMTX_IS_INDICES_ONLY(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputEntry(%p,%d,%d)" "\n inputMode is not INPMTX_INDICES_ONLY\n", inpmtx, row, col) ; exit(-1) ; } inputEntry(inpmtx, row, col, 0.0, 0.0) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- input a single real entry in the matrix created -- 98jan28, cca --------------------------------------- */ void InpMtx_inputRealEntry ( InpMtx *inpmtx, int row, int col, double value ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || row < 0 || col < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealEntry(%p,%d,%d,%e)" "\n bad inputReal\n", inpmtx, row, col, value) ; exit(-1) ; } if ( !( INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealEntry(%p,%d,%d,%e)" "\n bad coordType = %d\n", inpmtx, row, col, value, inpmtx->coordType) ; exit(-1) ; } if ( ! INPMTX_IS_REAL_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealEntry(%p,%d,%d,%e)" "\n inputMode is not SPOOLES_REAL\n", inpmtx, row, col, value) ; exit(-1) ; } inputEntry(inpmtx, row, col, value, 0.0) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ input a single complex entry in the matrix created -- 98jan28, cca ------------------------------------------ */ void InpMtx_inputComplexEntry ( InpMtx *inpmtx, int row, int col, double real, double imag ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || row < 0 || col < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexEntry(%p,%d,%d,%e,%e)" "\n bad inputComplex\n", inpmtx, row, col, real, imag) ; exit(-1) ; } if ( !( INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexEntry(%p,%d,%d,%e,%e)" "\n bad coordType = %d\n", inpmtx, row, col, real, imag, inpmtx->coordType) ; exit(-1) ; } if ( ! INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexEntry(%p,%d,%d,%e,%e)" "\n inputMode is not SPOOLES_COMPLEX\n", inpmtx, row, col, real, imag) ; exit(-1) ; } inputEntry(inpmtx, row, col, real, imag) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------- input a row in the matrix created -- 98jan28, cca --------------------------------- */ static void inputRow ( InpMtx *inpmtx, int row, int rowsize, int rowind[], double rowent[] ) { int col, ii, jj, nent ; int *ivec1, *ivec2 ; prepareToAddNewEntries(inpmtx, rowsize) ; nent = inpmtx->nent ; ivec1 = IV_entries(&inpmtx->ivec1IV) ; ivec2 = IV_entries(&inpmtx->ivec2IV) ; if ( INPMTX_IS_BY_ROWS(inpmtx) ) { /* row coordinates */ IVfill(rowsize, ivec1 + nent, row) ; IVcopy(rowsize, ivec2 + nent, rowind) ; } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { /* column coordinates */ IVfill(rowsize, ivec2 + nent, row) ; IVcopy(rowsize, ivec1 + nent, rowind) ; } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { /* chevron coordinates */ for ( ii = 0, jj = nent ; ii < rowsize ; ii++, jj++ ) { col = rowind[ii] ; ivec1[ii] = (row <= col) ? row : col ; ivec2[ii] = col - row ; } } IV_setSize(&inpmtx->ivec1IV, nent + rowsize) ; IV_setSize(&inpmtx->ivec2IV, nent + rowsize) ; /* ----------------- input the entries ----------------- */ if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) ; DVcopy(rowsize, dvec + nent, rowent) ; DV_setSize(&inpmtx->dvecDV, nent + rowsize) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) ; ZVcopy(rowsize, dvec + 2*nent, rowent) ; DV_setSize(&inpmtx->dvecDV, 2*(nent + rowsize)) ; } inpmtx->storageMode = INPMTX_RAW_DATA ; inpmtx->nent += rowsize ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------ input a real row in the matrix created -- 98jan28, cca ------------------------------ */ void InpMtx_inputRow ( InpMtx *inpmtx, int row, int rowsize, int rowind[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || row < 0 || rowsize < 0 || rowind == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputRow(%p,%d,%d,%p)" "\n bad input\n", inpmtx, row, rowsize, rowind) ; exit(-1) ; } if ( ! INPMTX_IS_INDICES_ONLY(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputRow(%p,%d,%d,%p)" "\n inputMode is not INPMTX_INDICES_ONLY\n", inpmtx, row, rowsize, rowind) ; exit(-1) ; } inputRow(inpmtx, row, rowsize, rowind, NULL) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------ input a real row in the matrix created -- 98jan28, cca ------------------------------ */ void InpMtx_inputRealRow ( InpMtx *inpmtx, int row, int rowsize, int rowind[], double rowent[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || row < 0 || rowsize < 0 || rowind == NULL || rowent == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealRow(%p,%d,%d,%p,%p)" "\n bad input\n", inpmtx, row, rowsize, rowind, rowent) ; exit(-1) ; } if ( ! INPMTX_IS_REAL_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealRow(%p,%d,%d,%p,%p)" "\n inputMode is not SPOOLES_REAL\n", inpmtx, row, rowsize, rowind, rowent) ; exit(-1) ; } inputRow(inpmtx, row, rowsize, rowind, rowent) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------- input a complex row in the matrix created -- 98jan28, cca --------------------------------- */ void InpMtx_inputComplexRow ( InpMtx *inpmtx, int row, int rowsize, int rowind[], double rowent[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || row < 0 || rowsize < 0 || rowind == NULL || rowent == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexRow(%p,%d,%d,%p,%p)" "\n bad input\n", inpmtx, row, rowsize, rowind, rowent) ; exit(-1) ; } if ( ! INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexRow(%p,%d,%d,%p,%p)" "\n inputMode is not SPOOLES_COMPLEX\n", inpmtx, row, rowsize, rowind, rowent) ; exit(-1) ; } inputRow(inpmtx, row, rowsize, rowind, rowent) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ input a complex column in the matrix created -- 98jan28, cca ------------------------------------ */ static void inputColumn ( InpMtx *inpmtx, int col, int colsize, int colind[], double colent[] ) { int ii, jj, nent, row ; int *ivec1, *ivec2 ; prepareToAddNewEntries(inpmtx, colsize) ; nent = inpmtx->nent ; ivec1 = IV_entries(&inpmtx->ivec1IV) ; ivec2 = IV_entries(&inpmtx->ivec2IV) ; if ( INPMTX_IS_BY_ROWS(inpmtx) ) { IVcopy(colsize, ivec1 + nent, colind) ; IVfill(colsize, ivec2 + nent, col) ; } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { IVfill(colsize, ivec1 + nent, col) ; IVcopy(colsize, ivec2 + nent, colind) ; } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { for ( ii = 0, jj = nent ; ii < colsize ; ii++, jj++ ) { row = colind[jj] ; ivec1[jj] = (row <= col) ? row : col ; ivec2[jj] = col - row ; } } IV_setSize(&inpmtx->ivec1IV, nent + colsize) ; IV_setSize(&inpmtx->ivec2IV, nent + colsize) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) + nent ; DVcopy(colsize, dvec, colent) ; DV_setSize(&inpmtx->dvecDV, nent + colsize) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) + 2*nent ; ZVcopy(colsize, dvec, colent) ; DV_setSize(&inpmtx->dvecDV, 2*(nent + colsize)) ; } inpmtx->nent = nent + colsize ; inpmtx->storageMode = INPMTX_RAW_DATA ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- input a column in the matrix created -- 98jan28, cca ---------------------------- */ void InpMtx_inputColumn ( InpMtx *inpmtx, int col, int colsize, int colind[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || col < 0 || colsize < 0 || colind == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealColumn(%p,%d,%d,%p)" "\n bad input\n", inpmtx, col, colsize, colind) ; exit(-1) ; } if ( ! INPMTX_IS_INDICES_ONLY(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputColumn(%p,%d,%d,%p)" "\n inputMode must be INPMTX_INDICES_ONLY\n", inpmtx, col, colsize, colind) ; exit(-1) ; } inputColumn(inpmtx, col, colsize, colind, NULL) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------- input a real column in the matrix created -- 98jan28, cca --------------------------------- */ void InpMtx_inputRealColumn ( InpMtx *inpmtx, int col, int colsize, int colind[], double colent[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || col < 0 || colsize < 0 || colind == NULL || colent == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealColumn(%p,%d,%d,%p,%p)" "\n bad input\n", inpmtx, col, colsize, colind, colent) ; exit(-1) ; } if ( ! INPMTX_IS_REAL_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealColumn(%p,%d,%d,%p,%p)" "\n inputMode must be SPOOLES_REAL\n", inpmtx, col, colsize, colind, colent) ; exit(-1) ; } inputColumn(inpmtx, col, colsize, colind, colent) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ input a complex column in the matrix created -- 98jan28, cca ------------------------------------ */ void InpMtx_inputComplexColumn ( InpMtx *inpmtx, int col, int colsize, int colind[], double colent[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || col < 0 || colsize < 0 || colind == NULL || colent == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexColumn(%p,%d,%d,%p,%p)" "\n bad input\n", inpmtx, col, colsize, colind, colent) ; exit(-1) ; } if ( ! INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexColumn(%p,%d,%d,%p,%p)" "\n inputMode must be SPOOLES_COMPLEX\n", inpmtx, col, colsize, colind, colent) ; exit(-1) ; } inputColumn(inpmtx, col, colsize, colind, colent) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------- input a chevron in the matrix created -- 98jan28, cca ----------------------------- */ static void inputChevron ( InpMtx *inpmtx, int chv, int chvsize, int chvind[], double chvent[] ) { int col, ii, jj, nent, offset, row ; int *ivec1, *ivec2 ; prepareToAddNewEntries(inpmtx, chvsize) ; nent = inpmtx->nent ; ivec1 = IV_entries(&inpmtx->ivec1IV) ; ivec2 = IV_entries(&inpmtx->ivec2IV) ; if ( INPMTX_IS_BY_ROWS(inpmtx) ) { for ( ii = 0, jj = nent ; ii < chvsize ; ii++, jj++ ) { if ( (offset = chvind[ii]) >= 0 ) { row = chv ; col = chv + offset ; } else { col = chv ; row = chv - offset ; } ivec1[jj] = row ; ivec2[jj] = col ; } } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { for ( ii = 0, jj = nent ; ii < chvsize ; ii++, jj++ ) { if ( (offset = chvind[ii]) >= 0 ) { row = chv ; col = chv + offset ; } else { col = chv ; row = chv - offset ; } ivec1[jj] = col ; ivec2[jj] = row ; } } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { IVfill(chvsize, ivec1 + nent, chv) ; IVcopy(chvsize, ivec2 + nent, chvind) ; } IV_setSize(&inpmtx->ivec1IV, nent + chvsize) ; IV_setSize(&inpmtx->ivec2IV, nent + chvsize) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) + nent ; DVcopy(chvsize, dvec, chvent) ; DV_setSize(&inpmtx->dvecDV, nent + chvsize) ; } else if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) + 2*nent ; ZVcopy(chvsize, dvec, chvent) ; DV_setSize(&inpmtx->dvecDV, 2*(nent + chvsize)) ; } inpmtx->nent += chvsize ; inpmtx->storageMode = INPMTX_RAW_DATA ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------- input a chevron in the matrix created -- 98jan28, cca ----------------------------- */ void InpMtx_inputChevron ( InpMtx *inpmtx, int chv, int chvsize, int chvind[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || chv < 0 || chvsize < 0 || chvind == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputChevron(%p,%d,%d,%p)" "\n bad input\n", inpmtx, chv, chvsize, chvind) ; exit(-1) ; } if ( ! INPMTX_IS_INDICES_ONLY(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputChevron(%p,%d,%d,%p)" "\n inputMode must be INPMTX_INDICES_ONLY\n", inpmtx, chv, chvsize, chvind) ; exit(-1) ; } inputChevron(inpmtx, chv, chvsize, chvind, NULL) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------- input a chevron in the matrix created -- 98jan28, cca ----------------------------- */ void InpMtx_inputRealChevron ( InpMtx *inpmtx, int chv, int chvsize, int chvind[], double chvent[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || chv < 0 || chvsize < 0 || chvind == NULL || chvent == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealChevron(%p,%d,%d,%p,%p)" "\n bad input\n", inpmtx, chv, chvsize, chvind, chvent) ; exit(-1) ; } if ( ! INPMTX_IS_REAL_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealChevron(%p,%d,%d,%p,%p)" "\n inputMode must be SPOOLES_REAL\n", inpmtx, chv, chvsize, chvind, chvent) ; exit(-1) ; } inputChevron(inpmtx, chv, chvsize, chvind, chvent) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------- input a chevron in the matrix created -- 98jan28, cca ----------------------------- */ void InpMtx_inputComplexChevron ( InpMtx *inpmtx, int chv, int chvsize, int chvind[], double chvent[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || chv < 0 || chvsize < 0 || chvind == NULL || chvent == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexChevron(%p,%d,%d,%p,%p)" "\n bad input\n", inpmtx, chv, chvsize, chvind, chvent) ; exit(-1) ; } if ( ! INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexChevron(%p,%d,%d,%p,%p)" "\n inputMode must be SPOOLES_COMPLEX\n", inpmtx, chv, chvsize, chvind, chvent) ; exit(-1) ; } inputChevron(inpmtx, chv, chvsize, chvind, chvent) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- input a matrix created -- 98jan28, cca ----------------------- */ static void inputMatrix ( InpMtx *inpmtx, int nrow, int ncol, int rowstride, int colstride, int rowind[], int colind[], double mtxent[] ) { int col, ii, jj, kk, nent, row ; int *ivec1, *ivec2 ; prepareToAddNewEntries(inpmtx, nrow*ncol) ; nent = inpmtx->nent ; ivec1 = IV_entries(&inpmtx->ivec1IV) ; ivec2 = IV_entries(&inpmtx->ivec2IV) ; if ( INPMTX_IS_BY_ROWS(inpmtx) ) { for ( jj = 0, kk = nent ; jj < ncol ; jj++ ) { col = colind[jj] ; for ( ii = 0 ; ii < nrow ; ii++, kk++ ) { row = rowind[ii] ; ivec1[kk] = row ; ivec2[kk] = col ; } } } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { for ( jj = 0, kk = nent ; jj < ncol ; jj++ ) { col = colind[jj] ; for ( ii = 0 ; ii < nrow ; ii++, kk++ ) { row = rowind[ii] ; ivec1[kk] = col ; ivec2[kk] = row ; } } } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { for ( jj = 0, kk = nent ; jj < ncol ; jj++ ) { col = colind[jj] ; for ( ii = 0 ; ii < nrow ; ii++, kk++ ) { row = rowind[ii] ; if ( row <= col ) { ivec1[kk] = row ; } else { ivec1[kk] = col ; } ivec2[kk] = col - row ; } } } IV_setSize(&inpmtx->ivec1IV, nent + nrow*ncol) ; IV_setSize(&inpmtx->ivec2IV, nent + nrow*ncol) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) ; int ij ; for ( jj = 0, kk = nent ; jj < ncol ; jj++ ) { for ( ii = 0 ; ii < nrow ; ii++, kk++ ) { ij = ii*rowstride + jj*colstride ; dvec[kk] = mtxent[ij] ; } } DV_setSize(&inpmtx->dvecDV, nent + nrow*ncol) ; } if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) ; int ij ; for ( jj = 0, kk = nent ; jj < ncol ; jj++ ) { for ( ii = 0 ; ii < nrow ; ii++, kk++ ) { ij = ii*rowstride + jj*colstride ; dvec[2*kk] = mtxent[2*ij] ; dvec[2*kk+1] = mtxent[2*ij+1] ; } } DV_setSize(&inpmtx->dvecDV, 2*(nent + nrow*ncol)) ; } inpmtx->nent += nrow*ncol ; inpmtx->storageMode = INPMTX_RAW_DATA ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- input a matrix created -- 98jan28, cca ----------------------- */ void InpMtx_inputMatrix ( InpMtx *inpmtx, int nrow, int ncol, int rowstride, int colstride, int rowind[], int colind[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || nrow < 0 || ncol < 0 || rowstride < 1 || colstride < 1 || rowind == NULL || colind == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputMatrix(%p,%d,%d,%d,%d,%p,%p)" "\n bad input\n", inpmtx, nrow, ncol, rowstride, colstride, rowind, colind) ; exit(-1) ; } if ( ! INPMTX_IS_INDICES_ONLY(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputMatrix(%p,%d,%d,%d,%d,%p,%p)" "\n inputComplexMode must be INPMTX_INDICES_ONLY\n", inpmtx, nrow, ncol, rowstride, colstride, rowind, colind) ; exit(-1) ; } if ( nrow == 0 || ncol == 0 ) { return ; } inputMatrix(inpmtx, nrow, ncol, rowstride, colstride, rowind, colind, NULL) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- input a matrix created -- 98jan28, cca ----------------------- */ void InpMtx_inputRealMatrix ( InpMtx *inpmtx, int nrow, int ncol, int rowstride, int colstride, int rowind[], int colind[], double mtxent[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || nrow < 0 || ncol < 0 || rowstride < 1 || colstride < 1 || rowind == NULL || colind == NULL || mtxent == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealMatrix(%p,%d,%d,%d,%d,%p,%p,%p)" "\n bad input\n", inpmtx, nrow, ncol, rowstride, colstride, rowind, colind, mtxent) ; exit(-1) ; } if ( ! INPMTX_IS_REAL_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealMatrix(%p,%d,%d,%d,%d,%p,%p,%p)" "\n inputMode must be SPOOLES_REAL\n", inpmtx, nrow, ncol, rowstride, colstride, rowind, colind, mtxent) ; exit(-1) ; } if ( nrow == 0 || ncol == 0 ) { return ; } inputMatrix(inpmtx, nrow, ncol, rowstride, colstride, rowind, colind, mtxent) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- input a matrix created -- 98jan28, cca ----------------------- */ void InpMtx_inputComplexMatrix ( InpMtx *inpmtx, int nrow, int ncol, int rowstride, int colstride, int rowind[], int colind[], double mtxent[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || nrow < 0 || ncol < 0 || rowstride < 1 || colstride < 1 || rowind == NULL || colind == NULL || mtxent == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexMatrix(%p,%d,%d,%d,%d,%p,%p,%p)" "\n bad input\n", inpmtx, nrow, ncol, rowstride, colstride, rowind, colind, mtxent) ; exit(-1) ; } if ( ! INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexMatrix(%p,%d,%d,%d,%d,%p,%p,%p)" "\n inputMode must be SPOOLES_COMPLEX\n", inpmtx, nrow, ncol, rowstride, colstride, rowind, colind, mtxent) ; exit(-1) ; } if ( nrow == 0 || ncol == 0 ) { return ; } inputMatrix(inpmtx, nrow, ncol, rowstride, colstride, rowind, colind, mtxent) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- inputComplex a number of (row,column, entry) triples into the matrix created -- 98jan28, cca -------------------------------------------------------------------- */ static void inputTriples ( InpMtx *inpmtx, int ntriples, int rowids[], int colids[], double entries[] ) { int nent ; int *ivec1, *ivec2 ; prepareToAddNewEntries(inpmtx, ntriples) ; nent = inpmtx->nent ; ivec1 = IV_entries(&inpmtx->ivec1IV) ; ivec2 = IV_entries(&inpmtx->ivec2IV) ; IVcopy(ntriples, ivec1 + nent, rowids) ; IVcopy(ntriples, ivec2 + nent, colids) ; IV_setSize(&inpmtx->ivec1IV, nent + ntriples) ; IV_setSize(&inpmtx->ivec2IV, nent + ntriples) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) ; DVcopy(ntriples, dvec + nent, entries) ; DV_setSize(&inpmtx->dvecDV, nent + ntriples) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { double *dvec = DV_entries(&inpmtx->dvecDV) ; ZVcopy(ntriples, dvec + 2*nent, entries) ; DV_setSize(&inpmtx->dvecDV, 2*(nent + ntriples)) ; } inpmtx->nent += ntriples ; inpmtx->storageMode = INPMTX_RAW_DATA ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- input a number of (row,column, entry) triples into the matrix created -- 98jan28, cca ------------------------------------------------------------- */ void InpMtx_inputTriples ( InpMtx *inpmtx, int ntriples, int rowids[], int colids[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || ntriples < 0 || rowids == NULL || colids == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputTriples(%p,%d,%p,%p)" "\n bad inputComplex\n", inpmtx, ntriples, rowids, colids) ; exit(-1) ; } if ( ! INPMTX_IS_INDICES_ONLY(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputEntry(%p,%d,%p,%p)" "\n coordType must be INPMTX_INDICES_ONLY\n", inpmtx, ntriples, rowids, colids) ; exit(-1) ; } inputTriples(inpmtx, ntriples, rowids, colids, NULL) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- input a number of (row,column, entry) triples into the matrix created -- 98jan28, cca ------------------------------------------------------------- */ void InpMtx_inputRealTriples ( InpMtx *inpmtx, int ntriples, int rowids[], int colids[], double entries[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || ntriples < 0 || rowids == NULL || colids == NULL || entries == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealTriples(%p,%d,%p,%p,%p)" "\n bad input\n", inpmtx, ntriples, rowids, colids, entries) ; exit(-1) ; } if ( ! INPMTX_IS_REAL_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputRealEntry(%p,%d,%p,%p,%p)" "\n coordType must be COMPLEX_REAL_ENTRIES\n", inpmtx, ntriples, rowids, colids, entries) ; exit(-1) ; } inputTriples(inpmtx, ntriples, rowids, colids, entries) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- input a number of (row,column, entry) triples into the matrix created -- 98jan28, cca ------------------------------------------------------------- */ void InpMtx_inputComplexTriples ( InpMtx *inpmtx, int ntriples, int rowids[], int colids[], double entries[] ) { /* -------------- check the data -------------- */ if ( inpmtx == NULL || ntriples < 0 || rowids == NULL || colids == NULL || entries == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexTriples(%p,%d,%p,%p,%p)" "\n bad inputComplex\n", inpmtx, ntriples, rowids, colids, entries) ; exit(-1) ; } if ( ! INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_inputComplexEntry(%p,%d,%p,%p,%p)" "\n inputMode must be SPOOLES_COMPLEX\n", inpmtx, ntriples, rowids, colids, entries) ; exit(-1) ; } inputTriples(inpmtx, ntriples, rowids, colids, entries) ; return ; } /*--------------------------------------------------------------------*/ (inpmtx, nrow*ncol) ; nent = inpmtx->nent ; ivec1 = IV_entries(&inpmtx->ivec1IV) ; ivecInpMtx/src/instance.c010064400020550007177000000444330653777611100160740ustar00clevecompmath00000400000006/* instanceRead.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ /* ----------------------- returns coordinate type created -- 98jan28, cca ----------------------- */ int InpMtx_coordType ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_coordType(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(inpmtx->coordType) ; } /*--------------------------------------------------------------------*/ /* ----------------------- returns storage mode created -- 98jan28, cca ---------------------- */ int InpMtx_storageMode ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_storageMode(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(inpmtx->storageMode) ; } /*--------------------------------------------------------------------*/ /* ----------------------- returns input mode created -- 98jan28, cca ----------------------- */ int InpMtx_inputMode ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_inputMode(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(inpmtx->inputMode) ; } /*--------------------------------------------------------------------*/ /* ----------------------- returns inpmtx->mxnent created -- 98jan28, cca ----------------------- */ int InpMtx_maxnent ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_maxnent(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(inpmtx->maxnent) ; } /*--------------------------------------------------------------------*/ /* ----------------------- returns inpmtx->nent created -- 98jan28, cca ----------------------- */ int InpMtx_nent ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nent(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(inpmtx->nent) ; } /*--------------------------------------------------------------------*/ /* ------------------------- returns inpmtx->mxnvector created -- 98jan28, cca ------------------------- */ int InpMtx_maxnvector ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_maxnvector(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(inpmtx->maxnvector) ; } /*--------------------------------------------------------------------*/ /* ----------------------- returns inpmtx->nvector created -- 98jan28, cca ----------------------- */ int InpMtx_nvector ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nvector(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(inpmtx->nvector) ; } /*--------------------------------------------------------------------*/ /* ------------------------------ returns inpmtx->resizeMultiple created -- 98jan28, cca ------------------------------ */ double InpMtx_resizeMultiple ( InpMtx *inpmtx ) { if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_resizeMultiple(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(inpmtx->resizeMultiple) ; } /*--------------------------------------------------------------------*/ /* --------------------------------- returns pointer to ivec1[] vector created -- 98jan28, cca --------------------------------- */ int * InpMtx_ivec1 ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_ivec1(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(IV_entries(&inpmtx->ivec1IV)) ; } /*--------------------------------------------------------------------*/ /* --------------------------------- returns pointer to ivec2[] vector created -- 98jan28, cca --------------------------------- */ int * InpMtx_ivec2 ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_ivec2(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(IV_entries(&inpmtx->ivec2IV)) ; } /*--------------------------------------------------------------------*/ /* -------------------------------- returns pointer to dvec[] vector created -- 98jan28, cca -------------------------------- */ double * InpMtx_dvec ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_dvec(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(DV_entries(&inpmtx->dvecDV)) ; } /*--------------------------------------------------------------------*/ /* --------------------------------- returns pointer to sizes[] vector created -- 98jan28, cca --------------------------------- */ int * InpMtx_sizes ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_sizes(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(IV_entries(&inpmtx->sizesIV)) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- returns pointer to vecids[] vector created -- 98jan28, cca ---------------------------------- */ int * InpMtx_vecids ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_vecids(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(IV_entries(&inpmtx->vecidsIV)) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- returns pointer to offsets[] vector created -- 98jan28, cca ----------------------------------- */ int * InpMtx_offsets ( InpMtx *inpmtx ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_offsets(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } return(IV_entries(&inpmtx->offsetsIV)) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- retrieve requested vector set *pnent to # of entries *pindices to address of first index created -- 98jan28, cca --------------------------------------- */ void InpMtx_vector ( InpMtx *inpmtx, int id, int *pnent, int **pindices ) { int loc, off ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_vector(%p,%d,%p,%p)" "\n bad input\n", inpmtx, id, pnent, pindices) ; exit(-1) ; } if ( ! INPMTX_IS_BY_VECTORS(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_vector(%p,%d,%p,%p)" "\n bad input\n", inpmtx, id, pnent, pindices) ; exit(-1) ; } if ( pnent == NULL || pindices == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_vector(%p,%d,%p,%p)" "\n NULL input, pnent = %p, pindices = %p", inpmtx, id, pnent, pindices, pnent, pindices) ; exit(-1) ; } /* ------------------------------- find the location of the vector ------------------------------- */ loc = IV_findValueAscending(&inpmtx->vecidsIV, id) ; if ( loc == -1 ) { /* ------------------------------------------------------------ vector is not present, set size to zero and pointers to NULL ------------------------------------------------------------ */ *pnent = 0 ; *pindices = NULL ; } else { /* -------------------------------------------------------------- fill *pnent with the number of entries in vector id. fill *pindices with the pointer to the first index in vector id. fill *pentries with the pointer to the first entry in vector id. -------------------------------------------------------------- */ *pnent = inpmtx->sizesIV.vec[loc] ; off = inpmtx->offsetsIV.vec[loc] ; *pindices = inpmtx->ivec2IV.vec + off ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- retrieve requested vector set *pnent to # of entries *pindices to address of first index *pentries to address of first entry created -- 98jan28, cca --------------------------------------- */ void InpMtx_realVector ( InpMtx *inpmtx, int id, int *pnent, int **pindices, double **pentries ) { int loc, off ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_realVector(%p,%d,%p,%p,%p)" "\n bad input\n", inpmtx, id, pnent, pindices, pentries) ; exit(-1) ; } if ( !INPMTX_IS_BY_VECTORS(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_realVector(%p,%d,%p,%p,%p)" "\n storageMode must be INPMTX_BY_VECTORS\n", inpmtx, id, pnent, pindices, pentries) ; exit(-1) ; } if ( pnent == NULL || pindices == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_realVector(%p,%d,%p,%p,%p)" "\n NULL input, pnent = %p, pindices = %p, pentries = %p", inpmtx, id, pnent, pindices, pentries, pnent, pindices, pentries) ; exit(-1) ; } /* ------------------------------- find the location of the vector ------------------------------- */ loc = IV_findValueAscending(&inpmtx->vecidsIV, id) ; if ( loc == -1 ) { /* ------------------------------------------------------------ vector is not present, set size to zero and pointers to NULL ------------------------------------------------------------ */ *pnent = 0 ; *pindices = NULL ; *pentries = NULL ; } else { /* -------------------------------------------------------------- fill *pnent with the number of entries in vector id. fill *pindices with the pointer to the first index in vector id. fill *pentries with the pointer to the first entry in vector id. -------------------------------------------------------------- */ *pnent = inpmtx->sizesIV.vec[loc] ; off = inpmtx->offsetsIV.vec[loc] ; *pindices = inpmtx->ivec2IV.vec + off ; *pentries = inpmtx->dvecDV.vec + off ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- retrieve requested vector set *pnent to # of entries *pindices to address of first index *pentries to address of first entry created -- 98jan28, cca --------------------------------------- */ void InpMtx_complexVector ( InpMtx *inpmtx, int id, int *pnent, int **pindices, double **pentries ) { int loc, off ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_complexVector(%p,%d,%p,%p,%p)" "\n bad input\n", inpmtx, id, pnent, pindices, pentries) ; exit(-1) ; } if ( !INPMTX_IS_BY_VECTORS(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_complexVector(%p,%d,%p,%p,%p)" "\n storage mode muse be INPMTX_BY_VECTORS\n", inpmtx, id, pnent, pindices, pentries) ; exit(-1) ; } if ( pnent == NULL || pindices == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_complexVector(%p,%d,%p,%p,%p)" "\n NULL input, pnent = %p, pindices = %p, pentries = %p", inpmtx, id, pnent, pindices, pentries, pnent, pindices, pentries) ; exit(-1) ; } /* ------------------------------- find the location of the vector ------------------------------- */ loc = IV_findValueAscending(&inpmtx->vecidsIV, id) ; if ( loc == -1 ) { /* ------------------------------------------------------------ vector is not present, set size to zero and pointers to NULL ------------------------------------------------------------ */ *pnent = 0 ; *pindices = NULL ; *pentries = NULL ; } else { /* -------------------------------------------------------------- fill *pnent with the number of entries in vector id. fill *pindices with the pointer to the first index in vector id. fill *pentries with the pointer to the first entry in vector id. -------------------------------------------------------------- */ *pnent = inpmtx->sizesIV.vec[loc] ; off = inpmtx->offsetsIV.vec[loc] ; *pindices = inpmtx->ivec2IV.vec + off ; *pentries = inpmtx->dvecDV.vec + 2*off ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- sets the maximum numnber of entries. this methods resizes the ivec1[], ivece2[] and dvec[] vectors if newmaxnent != maxnent created -- 98jan28, cca -------------------------------------------------------------- */ void InpMtx_setMaxnent ( InpMtx *inpmtx, int newmaxnent ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL || newmaxnent < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_setMaxnent(%p, %d)" "\n bad input\n", inpmtx, newmaxnent) ; exit(-1) ; } if ( newmaxnent != inpmtx->maxnent ) { IV_setMaxsize(&(inpmtx->ivec1IV), newmaxnent) ; IV_setMaxsize(&(inpmtx->ivec2IV), newmaxnent) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { DV_setMaxsize(&(inpmtx->dvecDV), newmaxnent) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { DV_setMaxsize(&(inpmtx->dvecDV), 2*newmaxnent) ; } } inpmtx->maxnent = newmaxnent ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------- set the present number of entries created -- 98jan28, cca -------------------------------- */ void InpMtx_setNent ( InpMtx *inpmtx, int newnent ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL || newnent < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_setNent(%p,%d)" "\n bad input\n", inpmtx, newnent) ; exit(-1) ; } if ( inpmtx->maxnent < newnent ) { /* ------------------------------------------------------- newnent requested is more than maxnent, set new maxnent ------------------------------------------------------- */ InpMtx_setMaxnent(inpmtx, newnent) ; } inpmtx->nent = newnent ; IV_setSize(&inpmtx->ivec1IV, newnent) ; IV_setSize(&inpmtx->ivec2IV, newnent) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { DV_setSize(&(inpmtx->dvecDV), newnent) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { DV_setSize(&inpmtx->dvecDV, 2*newnent) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- sets the maximum number of vectors. if newmaxnent != maxnent then this methods resizes the vecids[], sizes[] and offsets[] vectors created -- 98jan28, cca -------------------------------------------------- */ void InpMtx_setMaxnvector ( InpMtx *inpmtx, int newmaxnvector ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL || newmaxnvector < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_Maxnvector(%p, %d)" "\n bad input\n", inpmtx, newmaxnvector) ; exit(-1) ; } if ( newmaxnvector != inpmtx->maxnvector ) { IV_setMaxsize(&(inpmtx->vecidsIV), newmaxnvector) ; IV_setMaxsize(&(inpmtx->sizesIV), newmaxnvector) ; IV_setMaxsize(&(inpmtx->offsetsIV), newmaxnvector) ; } inpmtx->maxnvector = newmaxnvector ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------- set the present number of vectors created -- 98jan28, cca --------------------------------- */ void InpMtx_setNvector ( InpMtx *inpmtx, int newnvector ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL || newnvector < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_setNvector(%p, %d)" "\n bad input\n", inpmtx, newnvector) ; exit(-1) ; } if ( newnvector > inpmtx->maxnvector ) { InpMtx_setMaxnvector(inpmtx, newnvector) ; } inpmtx->nvector = newnvector ; IV_setSize(&inpmtx->vecidsIV, newnvector) ; IV_setSize(&inpmtx->sizesIV, newnvector) ; IV_setSize(&inpmtx->offsetsIV, newnvector) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------- sets inpmtx->resizeMultiple created -- 98jan28, cca --------------------------- */ void InpMtx_setResizeMultiple ( InpMtx *inpmtx, double resizeMultiple ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL || resizeMultiple < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_setResizeMultiple(%p,%f)" "\n bad input\n", inpmtx, resizeMultiple) ; exit(-1) ; } inpmtx->resizeMultiple = resizeMultiple ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- sets coordType of InpMtx structure to allow user to define custom coordinate type. Note, new type must be > 3. created -- 98jan28, cca -------------------------------------------- */ void InpMtx_setCoordType ( InpMtx *inpmtx, int type ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL || type <= 3 ) { fprintf(stderr, "\n fatal error in InpMtx_setCoordType(%p,%d)" "\n bad input\n", inpmtx, type) ; if ( type <= 3 ) fprintf(stderr, "\n fatal error in InpMtx_setCoordType" "\n reserved coordinate type %d \n", type) ; exit(-1) ; } inpmtx->coordType = type ; return ; } /*--------------------------------------------------------------------*/ dex in vector id. fill *pentries with the pointer to the first entry in vector id. -------------------------------------------------------------- */ *pnent = inpmtx->sizesIV.vec[loc] ; off = inpmtx->offsetsIVInpMtx/src/map.c010064400020550007177000000100170656106626500150330ustar00clevecompmath00000400000006/* map.c */ #include "../../InpMtx.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- to map the coordinates of the entries of the matrix into new coordinates. this method is used during the distributed matrix-vector multiply where a matrix local to a processor is mapped into a local coordinate system. (row,col) --> (rowmap[row],colmap[col]) we check that row is in [0,nrow) and col is in [0,ncol), where nrow is the size of rowmapIV and ncol is the size of colmapIV. note, the storage mode is not changed. i.e., if the data is stored by vectors, it may be invalid after the indices have been mapped. on the other hand, it may not, so it is the user's responsibility to reset the storage mode if necessary. created -- 98aug02, cca -------------------------------------------------------------------- */ void InpMtx_mapEntries ( InpMtx *inpmtx, IV *rowmapIV, IV *colmapIV ) { int chv, col, ii, ncol, nent, nrow, off, row ; int *colmap, *ivec1, *ivec2, *rowmap ; /* --------------- check the input --------------- */ if ( inpmtx == NULL || rowmapIV == NULL || colmapIV == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_mapEntries()" "\n bad input\n") ; exit(-1) ; } if ( !(INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx)) ) { fprintf(stderr, "\n fatal error in InpMtx_mapEntries()" "\n bad coordinate type\n") ; exit(-1) ; } IV_sizeAndEntries(rowmapIV, &nrow, &rowmap) ; if ( rowmap == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_mapEntries()" "\n rowmap is NULL\n") ; exit(-1) ; } IV_sizeAndEntries(colmapIV, &ncol, &colmap) ; if ( colmap == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_mapEntries()" "\n colmap is NULL\n") ; exit(-1) ; } nent = inpmtx->nent ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; if ( INPMTX_IS_BY_ROWS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; if ( row < 0 || row >= nrow ) { fprintf(stderr, "\n fatal error in InpMtx_mapEntries()" "\n entry (%d,%d), nrow = %d\n", row, col, nrow) ; exit(-1) ; } ivec1[ii] = rowmap[row] ; if ( col < 0 || col >= ncol ) { fprintf(stderr, "\n fatal error in InpMtx_mapEntries()" "\n entry (%d,%d), ncol = %d\n", row, col, ncol) ; exit(-1) ; } ivec2[ii] = colmap[col] ; } } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; if ( row < 0 || row >= nrow ) { fprintf(stderr, "\n fatal error in InpMtx_mapEntries()" "\n entry (%d,%d), nrow = %d\n", row, col, nrow) ; exit(-1) ; } ivec2[ii] = rowmap[row] ; if ( col < 0 || col >= ncol ) { fprintf(stderr, "\n fatal error in InpMtx_mapEntries()" "\n entry (%d,%d), ncol = %d\n", row, col, ncol) ; exit(-1) ; } ivec1[ii] = colmap[col] ; } } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { chv = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chv ; col = chv + off ; } else { row = chv - off ; col = chv ; } if ( row < 0 || row >= nrow ) { fprintf(stderr, "\n fatal error in InpMtx_mapEntries()" "\n entry (%d,%d), nrow = %d\n", row, col, nrow) ; exit(-1) ; } row = rowmap[row] ; if ( col < 0 || col >= ncol ) { fprintf(stderr, "\n fatal error in InpMtx_mapEntries()" "\n entry (%d,%d), ncol = %d\n", row, col, ncol) ; exit(-1) ; } col = colmap[col] ; ivec1[ii] = (row >= col) ? col : row ; ivec2[ii] = col - row ; } } return ; } /*--------------------------------------------------------------------*/ InpMtx/src/mvm.c010064400020550007177000001533260656416103200150570ustar00clevecompmath00000400000006/* mvm.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98may02, cca ---------------------------------------- */ void InpMtx_nonsym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) { int incX, incY, ncolX, ncolY, nent, nrhs, nrowX, nrowY ; int *ivec1, *ivec2 ; double *dvec, *x, *y ; /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm(%p,%p,%p,%p)" "\n bad input\n", A, Y, alpha, X) ; exit(-1) ; } if ( ! (INPMTX_IS_REAL_ENTRIES(A) || INPMTX_IS_COMPLEX_ENTRIES(A)) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm(%p,%p,%p,%p)" "\n bad inputMode %d for A\n", A, Y, alpha, X, A->inputMode) ; exit(-1) ; } if ( ! (DENSEMTX_IS_REAL(Y) || DENSEMTX_IS_COMPLEX(Y)) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm(%p,%p,%p,%p)" "\n bad type %d for Y\n", A, Y, alpha, X, Y->type) ; exit(-1) ; } if ( ! (DENSEMTX_IS_REAL(X) || DENSEMTX_IS_COMPLEX(X)) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm(%p,%p,%p,%p)" "\n bad type %d for X\n", A, Y, alpha, X, X->type) ; exit(-1) ; } if ( DENSEMTX_IS_REAL(Y) != DENSEMTX_IS_REAL(X) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm(%p,%p,%p,%p)" "\n X's type %d, Y's type %d \n", A, Y, alpha, X, X->type, Y->type) ; exit(-1) ; } if ( (INPMTX_IS_REAL_ENTRIES(A) && !DENSEMTX_IS_REAL(Y)) || (INPMTX_IS_COMPLEX_ENTRIES(A) && !DENSEMTX_IS_COMPLEX(Y)) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm(%p,%p,%p,%p)" "\n A's inputMode %d, Y's type %d \n", A, Y, alpha, X, A->inputMode, Y->type) ; exit(-1) ; } if ( DenseMtx_rowIncrement(Y) != 1 ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm(%p,%p,%p,%p)" "\n Y's row increment = %d\n", A, Y, alpha, X, DenseMtx_rowIncrement(Y)) ; exit(-1) ; } incY = DenseMtx_columnIncrement(Y) ; if ( DenseMtx_rowIncrement(X) != 1 ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm(%p,%p,%p,%p)" "\n X's row increment = %d\n", A, Y, alpha, X, DenseMtx_rowIncrement(X)) ; exit(-1) ; } incX = DenseMtx_columnIncrement(X) ; x = DenseMtx_entries(X) ; y = DenseMtx_entries(Y) ; DenseMtx_dimensions(Y, &nrowY, &ncolY) ; DenseMtx_dimensions(X, &nrowX, &ncolX) ; if ( (nrhs = ncolY) != ncolX ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm(%p,%p,%p,%p)" "\n Y's nrhs = %d, X's nrhs = %d", A, Y, alpha, X, nrhs, ncolX) ; exit(-1) ; } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm(%p,%p,%p,%p)" "\n ivec1 %p, ivec2 %p, dvec %p\n", A, Y, alpha, X, ivec1, ivec2, dvec) ; exit(-1) ; } nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, jrhs, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ purpose -- to compute Y := Y + alpha*A^T*X created -- 98may28, cca ------------------------------------------ */ void InpMtx_nonsym_mmm_T ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) { int incX, incY, ncolX, ncolY, nent, nrhs, nrowX, nrowY ; int *ivec1, *ivec2 ; double *dvec, *x, *y ; /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_T(%p,%p,%p,%p)" "\n bad input\n", A, Y, alpha, X) ; exit(-1) ; } if ( ! (INPMTX_IS_REAL_ENTRIES(A) || INPMTX_IS_COMPLEX_ENTRIES(A)) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_T(%p,%p,%p,%p)" "\n bad inputMode %d for A\n", A, Y, alpha, X, A->inputMode) ; exit(-1) ; } if ( ! (DENSEMTX_IS_REAL(Y) || DENSEMTX_IS_COMPLEX(Y)) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_T(%p,%p,%p,%p)" "\n bad type %d for Y\n", A, Y, alpha, X, Y->type) ; exit(-1) ; } if ( ! (DENSEMTX_IS_REAL(X) || DENSEMTX_IS_COMPLEX(X)) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_T(%p,%p,%p,%p)" "\n bad type %d for X\n", A, Y, alpha, X, X->type) ; exit(-1) ; } if ( DENSEMTX_IS_REAL(Y) != DENSEMTX_IS_REAL(X) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_T(%p,%p,%p,%p)" "\n X's type %d, Y's type %d \n", A, Y, alpha, X, X->type, Y->type) ; exit(-1) ; } if ( (INPMTX_IS_REAL_ENTRIES(A) && !DENSEMTX_IS_REAL(Y)) || (INPMTX_IS_COMPLEX_ENTRIES(A) && !DENSEMTX_IS_COMPLEX(Y)) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_T(%p,%p,%p,%p)" "\n A's inputMode %d, Y's type %d \n", A, Y, alpha, X, A->inputMode, Y->type) ; exit(-1) ; } if ( DenseMtx_rowIncrement(Y) != 1 ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_T(%p,%p,%p,%p)" "\n Y's row increment = %d\n", A, Y, alpha, X, DenseMtx_rowIncrement(Y)) ; exit(-1) ; } incY = DenseMtx_columnIncrement(Y) ; if ( DenseMtx_rowIncrement(X) != 1 ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_T(%p,%p,%p,%p)" "\n X's row increment = %d\n", A, Y, alpha, X, DenseMtx_rowIncrement(X)) ; exit(-1) ; } incX = DenseMtx_columnIncrement(X) ; x = DenseMtx_entries(X) ; y = DenseMtx_entries(Y) ; DenseMtx_dimensions(Y, &nrowY, &ncolY) ; DenseMtx_dimensions(X, &nrowX, &ncolX) ; if ( (nrhs = ncolY) != ncolX ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_T(%p,%p,%p,%p)" "\n Y's nrhs = %d, X's nrhs = %d", A, Y, alpha, X, nrhs, ncolX) ; exit(-1) ; } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_T(%p,%p,%p,%p)" "\n ivec1 %p, ivec2 %p, dvec %p\n", A, Y, alpha, X, ivec1, ivec2, dvec) ; exit(-1) ; } nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, jrhs, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec2[ii] ; row = ivec1[ii] ; y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec2[ii] ; row = ivec1[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } y[row] += dvec[ii]*x[col] ; } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; } x += incX ; y += incY ; } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ purpose -- to compute Y := Y + alpha*A^H*X created -- 98may28, cca ------------------------------------------ */ void InpMtx_nonsym_mmm_H ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) { int incX, incY, ncolX, ncolY, nent, nrhs, nrowX, nrowY ; int *ivec1, *ivec2 ; double *dvec, *x, *y ; /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_H(%p,%p,%p,%p)" "\n bad input\n", A, Y, alpha, X) ; exit(-1) ; } if ( ! INPMTX_IS_COMPLEX_ENTRIES(A) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_H(%p,%p,%p,%p)" "\n bad inputMode %d for A\n", A, Y, alpha, X, A->inputMode) ; exit(-1) ; } if ( ! DENSEMTX_IS_COMPLEX(Y) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_H(%p,%p,%p,%p)" "\n bad type %d for Y\n", A, Y, alpha, X, Y->type) ; exit(-1) ; } if ( ! DENSEMTX_IS_COMPLEX(X) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_H(%p,%p,%p,%p)" "\n bad type %d for X\n", A, Y, alpha, X, X->type) ; exit(-1) ; } if ( DenseMtx_rowIncrement(Y) != 1 ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_H(%p,%p,%p,%p)" "\n Y's row increment = %d\n", A, Y, alpha, X, DenseMtx_rowIncrement(Y)) ; exit(-1) ; } incY = DenseMtx_columnIncrement(Y) ; if ( DenseMtx_rowIncrement(X) != 1 ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_H(%p,%p,%p,%p)" "\n X's row increment = %d\n", A, Y, alpha, X, DenseMtx_rowIncrement(X)) ; exit(-1) ; } incX = DenseMtx_columnIncrement(X) ; x = DenseMtx_entries(X) ; y = DenseMtx_entries(Y) ; DenseMtx_dimensions(Y, &nrowY, &ncolY) ; DenseMtx_dimensions(X, &nrowX, &ncolX) ; if ( (nrhs = ncolY) != ncolX ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_H(%p,%p,%p,%p)" "\n Y's nrhs = %d, X's nrhs = %d", A, Y, alpha, X, nrhs, ncolX) ; exit(-1) ; } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmm_H(%p,%p,%p,%p)" "\n ivec1 %p, ivec2 %p, dvec %p\n", A, Y, alpha, X, ivec1, ivec2, dvec) ; exit(-1) ; } nent = A->nent ; if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } x += 2*incX ; y += 2*incY ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X where A is symmetric created -- 98may02, cca ---------------------------------------- */ void InpMtx_sym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) { int incX, incY, ncolX, ncolY, nent, nrhs, nrowX, nrowY ; int *ivec1, *ivec2 ; double *dvec, *x, *y ; /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmm(%p,%p,%p,%p)" "\n bad input\n", A, Y, alpha, X) ; exit(-1) ; } if ( ! (INPMTX_IS_REAL_ENTRIES(A) || INPMTX_IS_COMPLEX_ENTRIES(A)) ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmm(%p,%p,%p,%p)" "\n bad inputMode %d for A\n", A, Y, alpha, X, A->inputMode) ; exit(-1) ; } if ( ! (DENSEMTX_IS_REAL(Y) || DENSEMTX_IS_COMPLEX(Y)) ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmm(%p,%p,%p,%p)" "\n bad type %d for Y\n", A, Y, alpha, X, Y->type) ; exit(-1) ; } if ( ! (DENSEMTX_IS_REAL(X) || DENSEMTX_IS_COMPLEX(X)) ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmm(%p,%p,%p,%p)" "\n bad type %d for X\n", A, Y, alpha, X, X->type) ; exit(-1) ; } if ( DENSEMTX_IS_REAL(Y) != DENSEMTX_IS_REAL(X) ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmm(%p,%p,%p,%p)" "\n X's type %d, Y's type %d \n", A, Y, alpha, X, X->type, Y->type) ; exit(-1) ; } if ( (INPMTX_IS_REAL_ENTRIES(A) && !DENSEMTX_IS_REAL(Y)) || (INPMTX_IS_COMPLEX_ENTRIES(A) && !DENSEMTX_IS_COMPLEX(Y)) ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmm(%p,%p,%p,%p)" "\n A's inputMode %d, Y's type %d \n", A, Y, alpha, X, A->inputMode, Y->type) ; exit(-1) ; } if ( DenseMtx_rowIncrement(Y) != 1 ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmm(%p,%p,%p,%p)" "\n Y's row increment = %d\n", A, Y, alpha, X, DenseMtx_rowIncrement(Y)) ; exit(-1) ; } incY = DenseMtx_columnIncrement(Y) ; if ( DenseMtx_rowIncrement(X) != 1 ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmm(%p,%p,%p,%p)" "\n X's row increment = %d\n", A, Y, alpha, X, DenseMtx_rowIncrement(X)) ; exit(-1) ; } incX = DenseMtx_columnIncrement(X) ; x = DenseMtx_entries(X) ; y = DenseMtx_entries(Y) ; DenseMtx_dimensions(Y, &nrowY, &ncolY) ; DenseMtx_dimensions(X, &nrowX, &ncolX) ; if ( (nrhs = ncolY) != ncolX ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmm(%p,%p,%p,%p)" "\n Y's nrhs = %d, X's nrhs = %d", A, Y, alpha, X, nrhs, ncolX) ; exit(-1) ; } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmm(%p,%p,%p,%p)" "\n ivec1 %p, ivec2 %p, dvec %p\n", A, Y, alpha, X, ivec1, ivec2, dvec) ; exit(-1) ; } nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, jrhs, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } x += incX ; y += incY ; } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X where A is hermitian created -- 98may02, cca ---------------------------------------- */ void InpMtx_herm_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) { int incX, incY, ncolX, ncolY, nent, nrhs, nrowX, nrowY ; int *ivec1, *ivec2 ; double *dvec, *x, *y ; /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_herm_mmm(%p,%p,%p,%p)" "\n bad input\n", A, Y, alpha, X) ; exit(-1) ; } if ( ! INPMTX_IS_COMPLEX_ENTRIES(A) ) { fprintf(stderr, "\n fatal error in InpMtx_herm_mmm(%p,%p,%p,%p)" "\n bad inputMode %d for A\n", A, Y, alpha, X, A->inputMode) ; exit(-1) ; } if ( ! DENSEMTX_IS_COMPLEX(Y) ) { fprintf(stderr, "\n fatal error in InpMtx_herm_mmm(%p,%p,%p,%p)" "\n bad type %d for Y\n", A, Y, alpha, X, Y->type) ; exit(-1) ; } if ( ! DENSEMTX_IS_COMPLEX(X) ) { fprintf(stderr, "\n fatal error in InpMtx_herm_mmm(%p,%p,%p,%p)" "\n bad type %d for X\n", A, Y, alpha, X, X->type) ; exit(-1) ; } if ( DenseMtx_rowIncrement(Y) != 1 ) { fprintf(stderr, "\n fatal error in InpMtx_herm_mmm(%p,%p,%p,%p)" "\n Y's row increment = %d\n", A, Y, alpha, X, DenseMtx_rowIncrement(Y)) ; exit(-1) ; } incY = DenseMtx_columnIncrement(Y) ; if ( DenseMtx_rowIncrement(X) != 1 ) { fprintf(stderr, "\n fatal error in InpMtx_herm_mmm(%p,%p,%p,%p)" "\n X's row increment = %d\n", A, Y, alpha, X, DenseMtx_rowIncrement(X)) ; exit(-1) ; } incX = DenseMtx_columnIncrement(X) ; x = DenseMtx_entries(X) ; y = DenseMtx_entries(Y) ; DenseMtx_dimensions(Y, &nrowY, &ncolY) ; DenseMtx_dimensions(X, &nrowX, &ncolX) ; if ( (nrhs = ncolY) != ncolX ) { fprintf(stderr, "\n fatal error in InpMtx_herm_mmm(%p,%p,%p,%p)" "\n Y's nrhs = %d, X's nrhs = %d", A, Y, alpha, X, nrhs, ncolX) ; exit(-1) ; } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_herm_mmm(%p,%p,%p,%p)" "\n ivec1 %p, ivec2 %p, dvec %p\n", A, Y, alpha, X, ivec1, ivec2, dvec) ; exit(-1) ; } nent = A->nent ; if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } x += 2*incX ; y += 2*incY ; } } else if ( ifac == 0.0 ) { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } x += 2*incX ; y += 2*incY ; } } else { for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } x += 2*incX ; y += 2*incY ; } } } } return ; } /*--------------------------------------------------------------------*/ eMtx *X ) { int incX, incY, ncolX, ncolY, nent, nrhs, nrowX, nrowY ; int *ivec1, *ivec2 ; double *dvec, *x, *y ; /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_hInpMtx/src/mvmVector.c010064400020550007177000001136040660773502400162430ustar00clevecompmath00000400000006/* mvm.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98may02, cca ---------------------------------------- */ void InpMtx_nonsym_mmmVector ( InpMtx *A, double y[], double alpha[], double x[] ) { int nent ; int *ivec1, *ivec2 ; double *dvec ; /* --------------- check the input --------------- */ if ( A == NULL || y == NULL || alpha == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmmVector(%p,%p,%p,%p)" "\n bad input\n", A, y, alpha, x) ; exit(-1) ; } if ( ! (INPMTX_IS_REAL_ENTRIES(A) || INPMTX_IS_COMPLEX_ENTRIES(A)) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmmVector(%p,%p,%p,%p)" "\n bad inputMode %d for A\n", A, y, alpha, x, A->inputMode) ; exit(-1) ; } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmmVector(%p,%p,%p,%p)" "\n ivec1 %p, ivec2 %p, dvec %p\n", A, y, alpha, x, ivec1, ivec2, dvec) ; exit(-1) ; } nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, jrhs, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ purpose -- to compute Y := Y + alpha*A^T*X created -- 98may28, cca ------------------------------------------ */ void InpMtx_nonsym_mmmVector_T ( InpMtx *A, double y[], double alpha[], double x[] ) { int nent ; int *ivec1, *ivec2 ; double *dvec ; /* --------------- check the input --------------- */ if ( A == NULL || y == NULL || alpha == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmmVector_T(%p,%p,%p,%p)" "\n bad input\n", A, y, alpha, x) ; exit(-1) ; } if ( ! (INPMTX_IS_REAL_ENTRIES(A) || INPMTX_IS_COMPLEX_ENTRIES(A)) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmmVector_T(%p,%p,%p,%p)" "\n bad inputMode %d for A\n", A, y, alpha, x, A->inputMode) ; exit(-1) ; } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmmVector_T(%p,%p,%p,%p)" "\n ivec1 %p, ivec2 %p, dvec %p\n", A, y, alpha, x, ivec1, ivec2, dvec) ; exit(-1) ; } nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, jrhs, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec2[ii] ; row = ivec1[ii] ; y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec2[ii] ; row = ivec1[ii] ; y[row] += rfac * dvec[ii]*x[col] ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } y[row] += dvec[ii]*x[col] ; } } else { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ purpose -- to compute Y := Y + alpha*A^H*X created -- 98may28, cca ------------------------------------------ */ void InpMtx_nonsym_mmmVector_H ( InpMtx *A, double y[], double alpha[], double x[] ) { int nent ; int *ivec1, *ivec2 ; double *dvec ; /* --------------- check the input --------------- */ if ( A == NULL || y == NULL || alpha == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmmVector_H(%p,%p,%p,%p)" "\n bad input\n", A, y, alpha, x) ; exit(-1) ; } if ( ! INPMTX_IS_COMPLEX_ENTRIES(A) ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmmVector_H(%p,%p,%p,%p)" "\n bad inputMode %d for A\n", A, y, alpha, x, A->inputMode) ; exit(-1) ; } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_nonsym_mmmVector_H(%p,%p,%p,%p)" "\n ivec1 %p, ivec2 %p, dvec %p\n", A, y, alpha, x, ivec1, ivec2, dvec) ; exit(-1) ; } nent = A->nent ; if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec2[ii] ; col = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec2[ii] ; row = ivec1[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal + aimag*ximag ; y[2*row+1] += areal*ximag - aimag*xreal ; } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal + aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag - aimag*xreal) ; } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { col = chev ; row = chev + off ; } else { row = chev ; col = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X where A is symmetric created -- 98may02, cca ---------------------------------------- */ void InpMtx_sym_mmmVector ( InpMtx *A, double y[], double alpha[], double x[] ) { int nent ; int *ivec1, *ivec2 ; double *dvec ; /* --------------- check the input --------------- */ if ( A == NULL || y == NULL || alpha == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmmVector(%p,%p,%p,%p)" "\n bad input\n", A, y, alpha, x) ; exit(-1) ; } if ( ! (INPMTX_IS_REAL_ENTRIES(A) || INPMTX_IS_COMPLEX_ENTRIES(A)) ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmmVector(%p,%p,%p,%p)" "\n bad inputMode %d for A\n", A, y, alpha, x, A->inputMode) ; exit(-1) ; } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_sym_mmmVector(%p,%p,%p,%p)" "\n ivec1 %p, ivec2 %p, dvec %p\n", A, y, alpha, x, ivec1, ivec2, dvec) ; exit(-1) ; } nent = A->nent ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { double rfac ; int chev, col, ii, jrhs, off, row ; rfac = alpha[0] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } } else { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } } else { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 ) { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += dvec[ii]*x[col] ; if ( row != col ) { y[col] += dvec[ii]*x[row] ; } } } else { for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } y[row] += rfac * dvec[ii]*x[col] ; if ( row != col ) { y[col] += rfac * dvec[ii]*x[row] ; } } } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal - aimag*ximag ; y[2*col+1] += areal*ximag + aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal - aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag + aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X where A is hermitian created -- 98may02, cca ---------------------------------------- */ void InpMtx_herm_mmmVector ( InpMtx *A, double y[], double alpha[], double x[] ) { int nent ; int *ivec1, *ivec2 ; double *dvec ; /* --------------- check the input --------------- */ if ( A == NULL || y == NULL || alpha == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_herm_mmmVector(%p,%p,%p,%p)" "\n bad input\n", A, y, alpha, x) ; exit(-1) ; } if ( ! INPMTX_IS_COMPLEX_ENTRIES(A) ) { fprintf(stderr, "\n fatal error in InpMtx_herm_mmmVector(%p,%p,%p,%p)" "\n bad inputMode %d for A\n", A, y, alpha, x, A->inputMode) ; exit(-1) ; } /* -------------------------------- data is stored as triples (deal with vector storage later) -------------------------------- */ ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; dvec = InpMtx_dvec(A) ; if ( ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_herm_mmmVector(%p,%p,%p,%p)" "\n ivec1 %p, ivec2 %p, dvec %p\n", A, y, alpha, x, ivec1, ivec2, dvec) ; exit(-1) ; } nent = A->nent ; if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { double aimag, areal, ifac, rfac, t1, t2, ximag, xreal ; int chev, col, ii, jj, jrhs, off, row ; rfac = alpha[0] ; ifac = alpha[1] ; if ( INPMTX_IS_BY_ROWS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { row = ivec1[ii] ; col = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { col = ivec1[ii] ; row = ivec2[ii] ; areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { if ( rfac == 1.0 && ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += areal*xreal - aimag*ximag ; y[2*row+1] += areal*ximag + aimag*xreal ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += areal*xreal + aimag*ximag ; y[2*col+1] += areal*ximag - aimag*xreal ; } } } else if ( ifac == 0.0 ) { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; y[2*row] += rfac*(areal*xreal - aimag*ximag) ; y[2*row+1] += rfac*(areal*ximag + aimag*xreal) ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; y[2*col] += rfac*(areal*xreal + aimag*ximag) ; y[2*col+1] += rfac*(areal*ximag - aimag*xreal) ; } } } else { for ( ii = jj = 0 ; ii < nent ; ii++, jj += 2 ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; xreal = x[2*col] ; ximag = x[2*col+1] ; t1 = areal*xreal - aimag*ximag ; t2 = areal*ximag + aimag*xreal ; y[2*row] += rfac*t1 - ifac*t2 ; y[2*row+1] += rfac*t2 + ifac*t1 ; if ( row != col ) { xreal = x[2*row] ; ximag = x[2*row+1] ; t1 = areal*xreal + aimag*ximag ; t2 = areal*ximag - aimag*xreal ; y[2*col] += rfac*t1 - ifac*t2 ; y[2*col+1] += rfac*t2 + ifac*t1 ; } } } } } return ; } /*--------------------------------------------------------------------*/ col = chev ; row = chev - off ; } areal = dvec[jj] ; aimag = dvec[jj+1] ; InpMtx/src/permute.c010064400020550007177000000056450657431447100157510ustar00clevecompmath00000400000006/* permute.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ /* ----------------------- permute the entries created -- 96jul05, cca ----------------------- */ void InpMtx_permute ( InpMtx *inpmtx, int rowOldToNew[], int colOldToNew[] ) { int col, ii, nent, row ; int *ivec1, *ivec2 ; /* -------------- check the data -------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_permute(%p,%p,%p)" "\n bad input\n", inpmtx, rowOldToNew, colOldToNew); exit(-1) ; } if ( inpmtx->coordType <= 0 || inpmtx->coordType >= 4 ) { fprintf(stderr, "\n fatal error in InpMtx_permute(%p,%p,%p)" "\n coordType = %d, must be 1, 2 or 3\n", inpmtx, rowOldToNew, colOldToNew, inpmtx->coordType); exit(-1) ; } /* ---------------------- check for quick return ---------------------- */ if ( rowOldToNew == NULL && colOldToNew == NULL ) { return ; } if ( (nent = inpmtx->nent) == 0 ) { return ; } ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; if ( ivec1 == NULL || ivec2 == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_permute(%p,%p,%p)" "\n nent = %d, ivec1 = %p, ivec2 = %p", inpmtx, rowOldToNew, colOldToNew, nent, ivec1, ivec2) ; exit(-1) ; } /* -------------------------------------- convert coordinates to new permutation -------------------------------------- */ if ( INPMTX_IS_BY_ROWS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; if ( 0 <= row && rowOldToNew != NULL ) { row = rowOldToNew[row] ; } if ( 0 <= col && colOldToNew != NULL ) { col = colOldToNew[col] ; } ivec1[ii] = row ; ivec2[ii] = col ; } } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { col = ivec1[ii] ; row = ivec2[ii] ; if ( 0 <= row && rowOldToNew != NULL ) { row = rowOldToNew[row] ; } if ( 0 <= col && colOldToNew != NULL ) { col = colOldToNew[col] ; } ivec1[ii] = col ; ivec2[ii] = row ; } } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { int chv, off ; for ( ii = 0 ; ii < nent ; ii++ ) { chv = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chv ; col = chv + off ; } else { col = chv ; row = chv - off ; } if ( 0 <= row && rowOldToNew != NULL ) { row = rowOldToNew[row] ; } if ( 0 <= col && colOldToNew != NULL ) { col = colOldToNew[col] ; } ivec1[ii] = (col <= row) ? col : row ; ivec2[ii] = col - row ; } } /* ----------------------------------- set the storage mode to raw triples ----------------------------------- */ inpmtx->storageMode = INPMTX_RAW_DATA ; return ; } /*--------------------------------------------------------------------*/ InpMtx/src/profile.c010064400020550007177000000035030653410623500157100ustar00clevecompmath00000400000006/* profile */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ to fill xDV and yDV with a log10 profile of the magnitudes of the entries in the InpMtx object. tausmall and tau big provide cutoffs within which to examine the entries. pnsmall and pnbig are address to hold the number of entries smaller than tausmall, and larger than taubig, respectively. created -- 97feb14, cca ------------------------------------------------------------------ */ void InpMtx_log10profile ( InpMtx *inpmtx, int npts, DV *xDV, DV *yDV, double tausmall, double taubig, int *pnzero, int *pnsmall, int *pnbig ) { /* --------------- check the input --------------- */ if ( inpmtx == NULL || npts <= 0 || xDV == NULL || yDV == NULL || tausmall < 0.0 || taubig < 0.0 || tausmall > taubig || pnzero == NULL || pnsmall == NULL || pnbig == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_log10profile(%p,%d,%p,%p,%f,%f,%p,%p,%p)" "\n bad input\n", inpmtx, npts, xDV, yDV, tausmall, taubig, pnzero, pnsmall, pnbig) ; exit(-1) ; } if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { DV *dv = DV_new(); DV_init(dv, inpmtx->nent, InpMtx_dvec(inpmtx)) ; DV_log10profile(dv, npts, xDV, yDV, tausmall, taubig, pnzero, pnsmall, pnbig) ; DV_free(dv) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { ZV *zv = ZV_new(); ZV_init(zv, inpmtx->nent, InpMtx_dvec(inpmtx)) ; ZV_log10profile(zv, npts, xDV, yDV, tausmall, taubig, pnzero, pnsmall, pnbig) ; ZV_free(zv) ; } return ; } /*--------------------------------------------------------------------*/ InpMtx/src/support.c010064400020550007177000000334270656416204300157760ustar00clevecompmath00000400000006/* support.c */ #include "../../InpMtx.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- this method is used to determine the support of this matrix for a matrix-vector multiply y[] = A * x[] when A is a nonsymmetric matrix. rowsupIV -- filled with row indices of y[] which will be updated. colsupIV -- filled with row indices of x[] which will be used. created -- 98aug01, cca -------------------------------------------------------------------- */ void InpMtx_supportNonsym ( InpMtx *A, IV *rowsupIV, IV *colsupIV ) { char *colmark, *rowmark ; int chev, col, colcount, ii, loc, maxcol, maxrow, nent, off, row, rowcount ; int *colsup, *ivec1, *ivec2, *rowsup ; /* --------------- check the input --------------- */ if ( A == NULL || rowsupIV == NULL || colsupIV == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_supportNonsym(%p,%p,%p)" "\n bad input\n", A, rowsupIV, colsupIV) ; exit(-1) ; } if ( !INPMTX_IS_BY_ROWS(A) && !INPMTX_IS_BY_COLUMNS(A) && !INPMTX_IS_BY_CHEVRONS(A) ) { fprintf(stderr, "\n fatal error in InpMtx_supportNonsym(%p,%p,%p)" "\n coordinate type\n", A, rowsupIV, colsupIV) ; exit(-1) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; nent = A->nent ; /* ----------------------------------------------------------------- (1) determine the maximum row and column numbers in these entries (2) allocate marking vectors for rows and columns (3) fill marking vectors for rows and columns (4) fill support vectors ----------------------------------------------------------------- */ if ( INPMTX_IS_BY_ROWS(A) ) { maxrow = IVmax(nent, ivec1, &loc) ; maxcol = IVmax(nent, ivec2, &loc) ; rowmark = CVinit(1+maxrow, 'O') ; colmark = CVinit(1+maxcol, 'O') ; rowcount = colcount = 0 ; for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; if ( rowmark[row] == 'O' ) { rowcount++ ; } rowmark[row] = 'X' ; if ( colmark[col] == 'O' ) { colcount++ ; } colmark[col] = 'X' ; } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { maxrow = IVmax(nent, ivec2, &loc) ; maxcol = IVmax(nent, ivec1, &loc) ; rowmark = CVinit(1+maxrow, 'O') ; colmark = CVinit(1+maxcol, 'O') ; rowcount = colcount = 0 ; for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; if ( rowmark[row] == 'O' ) { rowcount++ ; } rowmark[row] = 'X' ; if ( colmark[col] == 'O' ) { colcount++ ; } colmark[col] = 'X' ; } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { maxrow = maxcol = -1 ; for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } if ( maxrow < row ) { maxrow = row ; } if ( maxcol < col ) { maxcol = col ; } } rowmark = CVinit(1+maxrow, 'O') ; colmark = CVinit(1+maxcol, 'O') ; rowcount = colcount = 0 ; for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } if ( rowmark[row] == 'O' ) { rowcount++ ; } rowmark[row] = 'X' ; if ( colmark[col] == 'O' ) { colcount++ ; } colmark[col] = 'X' ; } } IV_setSize(rowsupIV, rowcount) ; rowsup = IV_entries(rowsupIV) ; for ( row = rowcount = 0 ; row <= maxrow ; row++ ) { if ( rowmark[row] == 'X' ) { rowsup[rowcount++] = row ; } } IV_setSize(colsupIV, colcount) ; colsup = IV_entries(colsupIV) ; for ( col = colcount = 0 ; col <= maxcol ; col++ ) { if ( colmark[col] == 'X' ) { colsup[colcount++] = col ; } } CVfree(colmark) ; CVfree(rowmark) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- this method is used to determine the support of this matrix for a matrix-vector multiply y[] = A * x[] when A is a nonsymmetric matrix. rowsupIV -- filled with row indices of y[] which will be updated. colsupIV -- filled with row indices of x[] which will be used. created -- 98aug01, cca -------------------------------------------------------------------- */ void InpMtx_supportNonsymT ( InpMtx *A, IV *rowsupIV, IV *colsupIV ) { char *colmark, *rowmark ; int chev, col, colcount, ii, loc, maxcol, maxrow, nent, off, row, rowcount ; int *colsup, *ivec1, *ivec2, *rowsup ; /* --------------- check the input --------------- */ if ( A == NULL || rowsupIV == NULL || colsupIV == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_supportNonsymT(%p,%p,%p)" "\n bad input\n", A, rowsupIV, colsupIV) ; exit(-1) ; } if ( !INPMTX_IS_BY_ROWS(A) && !INPMTX_IS_BY_COLUMNS(A) && !INPMTX_IS_BY_CHEVRONS(A) ) { fprintf(stderr, "\n fatal error in InpMtx_supportNonsymT(%p,%p,%p)" "\n coordinate type\n", A, rowsupIV, colsupIV) ; exit(-1) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; nent = A->nent ; /* ----------------------------------------------------------------- (1) determine the maximum row and column numbers in these entries (2) allocate marking vectors for rows and columns (3) fill marking vectors for rows and columns (4) fill support vectors ----------------------------------------------------------------- */ if ( INPMTX_IS_BY_ROWS(A) ) { maxrow = IVmax(nent, ivec1, &loc) ; maxcol = IVmax(nent, ivec2, &loc) ; rowmark = CVinit(1+maxcol, 'O') ; colmark = CVinit(1+maxrow, 'O') ; rowcount = colcount = 0 ; for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; if ( colmark[row] == 'O' ) { colcount++ ; } colmark[row] = 'X' ; if ( rowmark[col] == 'O' ) { rowcount++ ; } rowmark[col] = 'X' ; } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { maxrow = IVmax(nent, ivec2, &loc) ; maxcol = IVmax(nent, ivec1, &loc) ; rowmark = CVinit(1+maxcol, 'O') ; colmark = CVinit(1+maxrow, 'O') ; rowcount = colcount = 0 ; for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; if ( colmark[row] == 'O' ) { colcount++ ; } colmark[row] = 'X' ; if ( rowmark[col] == 'O' ) { rowcount++ ; } rowmark[col] = 'X' ; } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { maxrow = maxcol = -1 ; for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } if ( maxrow < row ) { maxrow = row ; } if ( maxcol < col ) { maxcol = col ; } } rowmark = CVinit(1+maxcol, 'O') ; colmark = CVinit(1+maxrow, 'O') ; rowcount = colcount = 0 ; for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } if ( colmark[row] == 'O' ) { colcount++ ; } colmark[row] = 'X' ; if ( rowmark[col] == 'O' ) { rowcount++ ; } rowmark[col] = 'X' ; } } IV_setSize(rowsupIV, rowcount) ; rowsup = IV_entries(rowsupIV) ; for ( col = rowcount = 0 ; col <= maxcol ; col++ ) { if ( rowmark[col] == 'X' ) { rowsup[rowcount++] = col ; } } IV_setSize(colsupIV, colcount) ; colsup = IV_entries(colsupIV) ; for ( row = colcount = 0 ; row <= maxrow ; row++ ) { if ( colmark[row] == 'X' ) { colsup[colcount++] = row ; } } CVfree(colmark) ; CVfree(rowmark) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- this method is used to determine the support of this matrix for a matrix-vector multiply y[] = A * x[] when A is a nonsymmetric matrix. rowsupIV -- filled with row indices of y[] which will be updated. colsupIV -- filled with row indices of x[] which will be used. created -- 98aug01, cca -------------------------------------------------------------------- */ void InpMtx_supportNonsymH ( InpMtx *A, IV *rowsupIV, IV *colsupIV ) { /* --------------- check the input --------------- */ if ( A == NULL || rowsupIV == NULL || colsupIV == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_supportNonsymH(%p,%p,%p)" "\n bad input\n", A, rowsupIV, colsupIV) ; exit(-1) ; } if ( !INPMTX_IS_BY_ROWS(A) && !INPMTX_IS_BY_COLUMNS(A) && !INPMTX_IS_BY_CHEVRONS(A) ) { fprintf(stderr, "\n fatal error in InpMtx_supportNonsymH(%p,%p,%p)" "\n coordinate type\n", A, rowsupIV, colsupIV) ; exit(-1) ; } InpMtx_supportNonsymT(A, rowsupIV, colsupIV) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- this method is used to determine the support of this matrix for a matrix-vector multiply y[] = A * x[] when A is a symmetric matrix. supIV -- filled with row indices of y[] which will be updated and row indices of x[] which will be used. created -- 98aug01, cca -------------------------------------------------------------------- */ void InpMtx_supportSym ( InpMtx *A, IV *supIV ) { char *mark ; int chev, col, count, ii, loc, maxcol, maxrow, maxv, nent, off, row ; int *ivec1, *ivec2, *sup ; /* --------------- check the input --------------- */ if ( A == NULL || supIV == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_supportSym(%p,%p)" "\n bad input\n", A, supIV) ; exit(-1) ; } if ( !INPMTX_IS_BY_ROWS(A) && !INPMTX_IS_BY_COLUMNS(A) && !INPMTX_IS_BY_CHEVRONS(A) ) { fprintf(stderr, "\n fatal error in InpMtx_supportSym(%p,%p)" "\n coordinate type\n", A, supIV) ; exit(-1) ; } ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; nent = A->nent ; /* ----------------------------------------------------------------- (1) determine the maximum row and column numbers in these entries (2) allocate marking vectors for rows and columns (3) fill marking vectors for rows and columns (4) fill support vectors ----------------------------------------------------------------- */ if ( INPMTX_IS_BY_ROWS(A) ) { maxrow = IVmax(nent, ivec1, &loc) ; maxcol = IVmax(nent, ivec2, &loc) ; maxv = (maxrow >= maxcol) ? maxrow : maxcol ; mark = CVinit(1+maxv, 'O') ; count = 0 ; for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec1[ii] ; col = ivec2[ii] ; if ( mark[row] == 'O' ) { count++ ; } mark[row] = 'X' ; if ( mark[col] == 'O' ) { count++ ; } mark[col] = 'X' ; } } else if ( INPMTX_IS_BY_COLUMNS(A) ) { maxrow = IVmax(nent, ivec2, &loc) ; maxcol = IVmax(nent, ivec1, &loc) ; maxv = (maxrow >= maxcol) ? maxrow : maxcol ; mark = CVinit(1+maxv, 'O') ; count = 0 ; for ( ii = 0 ; ii < nent ; ii++ ) { row = ivec2[ii] ; col = ivec1[ii] ; if ( mark[row] == 'O' ) { count++ ; } mark[row] = 'X' ; if ( mark[col] == 'O' ) { count++ ; } mark[col] = 'X' ; } } else if ( INPMTX_IS_BY_CHEVRONS(A) ) { maxv = -1 ; for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; if ( maxv < col ) { maxv = col ; } } else { col = chev ; row = chev - off ; if ( maxv < row ) { maxv = row ; } } } mark = CVinit(1+maxv, 'O') ; count = 0 ; for ( ii = 0 ; ii < nent ; ii++ ) { chev = ivec1[ii] ; off = ivec2[ii] ; if ( off >= 0 ) { row = chev ; col = chev + off ; } else { col = chev ; row = chev - off ; } if ( mark[row] == 'O' ) { count++ ; } mark[row] = 'X' ; if ( mark[col] == 'O' ) { count++ ; } mark[col] = 'X' ; } } IV_setSize(supIV, count) ; sup = IV_entries(supIV) ; for ( row = count = 0 ; row <= maxv ; row++ ) { if ( mark[row] == 'X' ) { sup[count++] = row ; } } CVfree(mark) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- this method is used to determine the support of this matrix for a matrix-vector multiply y[] = A * x[] when A is a Hermitian matrix. supIV -- filled with row indices of y[] which will be updated and row indices of x[] which will be used. created -- 98aug01, cca -------------------------------------------------------------------- */ void InpMtx_supportHerm ( InpMtx *A, IV *supIV ) { /* --------------- check the input --------------- */ if ( A == NULL || supIV == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_supportHerm(%p,%p)" "\n bad input\n", A, supIV) ; exit(-1) ; } if ( !INPMTX_IS_BY_ROWS(A) && !INPMTX_IS_BY_COLUMNS(A) && !INPMTX_IS_BY_CHEVRONS(A) ) { fprintf(stderr, "\n fatal error in InpMtx_supportHerm(%p,%p)" "\n coordinate type\n", A, supIV) ; exit(-1) ; } InpMtx_supportSym(A, supIV) ; return ; } /*--------------------------------------------------------------------*/ _setSize(colsupIV, colcount) ; colsup = IV_entries(colsupIV) ; for ( col = colcount = 0 ; col <= maxcol ; col++ ) { if ( colmark[col] == 'X' ) { colsup[colcount++] = col ; } } CVfree(colmark) ; CVfree(rowmark) ; return ;InpMtx/src/util.c010064400020550007177000000722260661365231500152400ustar00clevecompmath00000400000006/* util.c */ #include "../InpMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* --------------------------------------- given the data is in raw triples, sort and compress the data created -- 98jan28, cca modified -- 98sep04, cca test to see if the sort is necessary --------------------------------------- */ void InpMtx_sortAndCompress ( InpMtx *inpmtx ) { int ient, nent, sortMustBeDone ; int *ivec1, *ivec2 ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_sortAndCompress(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } if ( INPMTX_IS_SORTED(inpmtx) || INPMTX_IS_BY_VECTORS(inpmtx) || (nent = inpmtx->nent) == 0 ) { inpmtx->storageMode = INPMTX_SORTED ; return ; } ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; sortMustBeDone = 0 ; for ( ient = 1 ; ient < nent ; ient++ ) { if ( ivec1[ient-1] > ivec1[ient] || ( ivec1[ient-1] == ivec1[ient] && ivec2[ient-1] > ivec2[ient] ) ) { sortMustBeDone = 1 ; break ; } } if ( sortMustBeDone == 1 ) { if ( INPMTX_IS_INDICES_ONLY(inpmtx) ) { inpmtx->nent = IV2sortUpAndCompress(nent, ivec1, ivec2) ; } else if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { double *dvec = InpMtx_dvec(inpmtx) ; inpmtx->nent = IV2DVsortUpAndCompress(nent, ivec1, ivec2, dvec) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { double *dvec = InpMtx_dvec(inpmtx) ; inpmtx->nent = IV2ZVsortUpAndCompress(nent, ivec1, ivec2, dvec) ; } } inpmtx->storageMode = INPMTX_SORTED ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- convert from sorted and compressed triples to vector created -- 98jan28, cca ---------------------------------------------------- */ void InpMtx_convertToVectors ( InpMtx *inpmtx ) { int *ivec1, *ivec2, *offsets, *sizes, *vecids ; int first, id, ient, jj, nent, nvector, value ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_convertToVectors(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } if ( INPMTX_IS_BY_VECTORS(inpmtx) || (nent = inpmtx->nent) == 0 ) { inpmtx->storageMode = INPMTX_BY_VECTORS ; return ; } if ( INPMTX_IS_RAW_DATA(inpmtx) ) { InpMtx_sortAndCompress(inpmtx) ; } ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; /* ----------------------------------- find the number of distinct vectors ----------------------------------- */ value = -1 ; nvector = 0 ; for ( ient = 0 ; ient < nent ; ient++ ) { if ( ivec1[ient] >= 0 && value != ivec1[ient] ) { value = ivec1[ient] ; nvector++ ; #if MYDEBUG > 0 fprintf(stdout, "\n ient %d, value %d, nvector %d", ient, value, nvector) ; fflush(stdout) ; #endif } } #if MYDEBUG > 0 fprintf(stdout, "\n %d vectors", nvector) ; fflush(stdout) ; #endif /* ----------------------------------------------------------------- adjust the sizes of the sizes[] and offsets[] arrays if necessary ----------------------------------------------------------------- */ InpMtx_setNvector(inpmtx, nvector) ; if ( nvector <= 0 ) { /* ----------------------------- matrix has no entries, return ----------------------------- */ inpmtx->storageMode = INPMTX_RAW_DATA ; InpMtx_setNent(inpmtx, 0) ; return ; } vecids = InpMtx_vecids(inpmtx) ; sizes = InpMtx_sizes(inpmtx) ; offsets = InpMtx_offsets(inpmtx) ; /* ------------------------------------------------------------ set the vector sizes and offsets note: we skip all entries whose first coordinate is negative ------------------------------------------------------------ */ for ( first = 0 ; first < nent ; first++ ) { if ( ivec1[first] >= 0 ) { break ; } } id = 0 ; if ( first < nent ) { value = ivec1[first] ; for ( jj = first + 1 ; jj < nent ; jj++ ) { if ( ivec1[jj] != value ) { vecids[id] = value ; sizes[id] = jj - first ; offsets[id] = first ; #if MYDEBUG > 0 fprintf(stdout, "\n vecids[%d] = %d, sizes[%d] = %d, offsets[%d] = %d", id, vecids[id], id, sizes[id], id, offsets[id]) ; fflush(stdout) ; #endif first = jj ; value = ivec1[jj] ; id++ ; } } vecids[id] = value ; sizes[id] = jj - first ; offsets[id] = first ; #if MYDEBUG > 0 fprintf(stdout, "\n vecids[%d] = %d, sizes[%d] = %d, offsets[%d] = %d", id, vecids[id], id, sizes[id], id, offsets[id]) ; fflush(stdout) ; #endif } inpmtx->storageMode = INPMTX_BY_VECTORS ; #if MYDEBUG > 0 fprintf(stdout, "\n vecidsIV") ; IV_writeForHumanEye(&inpmtx->vecidsIV, stdout) ; fprintf(stdout, "\n sizesIV") ; IV_writeForHumanEye(&inpmtx->sizesIV, stdout) ; fprintf(stdout, "\n offsetsIV") ; IV_writeForHumanEye(&inpmtx->offsetsIV, stdout) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* ------------------------- drop off-diagonal entries created -- 98jan28, cca ------------------------- */ void InpMtx_dropOffdiagonalEntries ( InpMtx *inpmtx ) { double *dvec ; int count, ii, nent ; int *ivec1, *ivec2 ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_dropOffdiagonalEntries(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } if ( !( INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_dropOffdiagonalEntries(%p)" "\n bad coordType = %d\n", inpmtx, inpmtx->coordType) ; exit(-1) ; } nent = inpmtx->nent ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; count = 0 ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) || INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec = InpMtx_dvec(inpmtx) ; } if ( INPMTX_IS_BY_ROWS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec1[ii] == ivec2[ii] ) { ivec1[count] = ivec1[ii] ; ivec2[count] = ivec2[ii] ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { dvec[count] = dvec[ii] ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec[2*count] = dvec[2*ii] ; dvec[2*count+1] = dvec[2*ii+1] ; } count++ ; } } } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec1[ii] == ivec2[ii] ) { ivec1[count] = ivec1[ii] ; ivec2[count] = ivec2[ii] ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { dvec[count] = dvec[ii] ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec[2*count] = dvec[2*ii] ; dvec[2*count+1] = dvec[2*ii+1] ; } count++ ; } } } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec2[ii] == 0 ) { ivec1[count] = ivec1[ii] ; ivec2[count] = ivec2[ii] ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { dvec[count] = dvec[ii] ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec[2*count] = dvec[2*ii] ; dvec[2*count+1] = dvec[2*ii+1] ; } count++ ; } } } inpmtx->nent = count ; IV_setSize(&inpmtx->ivec1IV, count) ; IV_setSize(&inpmtx->ivec2IV, count) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) || INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { DV_setSize(&inpmtx->dvecDV, count) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- drop entries in the lower triangle created -- 98jan28, cca ---------------------------------- */ void InpMtx_dropLowerTriangle ( InpMtx *inpmtx ) { double *dvec ; int count, ii, nent ; int *ivec1, *ivec2 ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_dropLowerTriangle(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } if ( !( INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_dropLowerTriangle(%p)" "\n bad coordType \n", inpmtx) ; exit(-1) ; } nent = inpmtx->nent ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; count = 0 ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) || INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec = InpMtx_dvec(inpmtx) ; } if ( INPMTX_IS_BY_ROWS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { /* fprintf(stdout, "\n ii = %d, (%d,%d)", ii, ivec1[ii], ivec2[ii]) ; */ if ( ivec1[ii] <= ivec2[ii] ) { ivec1[count] = ivec1[ii] ; ivec2[count] = ivec2[ii] ; /* fprintf(stdout, "\n ivec1[%d] = %d, ivec2[%d] = %d", count, ivec1[count], count, ivec2[count]) ; */ if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { dvec[count] = dvec[ii] ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec[2*count] = dvec[2*ii] ; dvec[2*count+1] = dvec[2*ii+1] ; } count++ ; } } } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec1[ii] >= ivec2[ii] ) { ivec1[count] = ivec1[ii] ; ivec2[count] = ivec2[ii] ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { dvec[count] = dvec[ii] ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec[2*count] = dvec[2*ii] ; dvec[2*count+1] = dvec[2*ii+1] ; } count++ ; } } } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec2[ii] >= 0 ) { ivec1[count] = ivec1[ii] ; ivec2[count] = ivec2[ii] ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { dvec[count] = dvec[ii] ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec[2*count] = dvec[2*ii] ; dvec[2*count+1] = dvec[2*ii+1] ; } count++ ; } } } inpmtx->nent = count ; IV_setSize(&inpmtx->ivec1IV, count) ; IV_setSize(&inpmtx->ivec2IV, count) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { DV_setSize(&inpmtx->dvecDV, count) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { DV_setSize(&inpmtx->dvecDV, 2*count) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- drop entries in the upper triangle created -- 98jan28, cca ---------------------------------- */ void InpMtx_dropUpperTriangle ( InpMtx *inpmtx ) { double *dvec ; int count, ii, nent ; int *ivec1, *ivec2 ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_dropUpperTriangle(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } if ( !( INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_dropUpperTriangle(%p)" "\n bad coordType \n", inpmtx) ; exit(-1) ; } nent = inpmtx->nent ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; count = 0 ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) || INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec = InpMtx_dvec(inpmtx) ; } if ( INPMTX_IS_BY_ROWS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec1[ii] >= ivec2[ii] ) { ivec1[count] = ivec1[ii] ; ivec2[count] = ivec2[ii] ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { dvec[count] = dvec[ii] ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec[2*count] = dvec[2*ii] ; dvec[2*count+1] = dvec[2*ii+1] ; } count++ ; } } } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec1[ii] <= ivec2[ii] ) { ivec1[count] = ivec1[ii] ; ivec2[count] = ivec2[ii] ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { dvec[count] = dvec[ii] ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec[2*count] = dvec[2*ii] ; dvec[2*count+1] = dvec[2*ii+1] ; } count++ ; } } } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec2[ii] <= 0 ) { ivec1[count] = ivec1[ii] ; ivec2[count] = ivec2[ii] ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { dvec[count] = dvec[ii] ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { dvec[2*count] = dvec[2*ii] ; dvec[2*count+1] = dvec[2*ii+1] ; } count++ ; } } } inpmtx->nent = count ; IV_setSize(&inpmtx->ivec1IV, count) ; IV_setSize(&inpmtx->ivec2IV, count) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtx) || INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { DV_setSize(&inpmtx->dvecDV, count) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- map entries into the lower triangle created -- 98jan28, cca ----------------------------------- */ void InpMtx_mapToLowerTriangle ( InpMtx *inpmtx ) { int col, ii, nent, row ; int *ivec1, *ivec2 ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_mapToLowerTriangle(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } if ( !( INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_mapToLowerTriangle(%p)" "\n bad coordType\n", inpmtx) ; exit(-1) ; } nent = inpmtx->nent ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; if ( INPMTX_IS_BY_ROWS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( (row = ivec1[ii]) < (col = ivec2[ii]) ) { ivec1[ii] = col ; ivec2[ii] = row ; } } } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( (row = ivec2[ii]) < (col = ivec1[ii]) ) { ivec1[ii] = row ; ivec2[ii] = col ; } } } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec2[ii] > 0 ) { ivec2[ii] = -ivec2[ii] ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- map entries into the upper triangle created -- 98jan28, cca ----------------------------------- */ void InpMtx_mapToUpperTriangle ( InpMtx *inpmtx ) { int col, ii, nent, row ; int *ivec1, *ivec2 ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_mapToUpperTriangle(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } if ( !( INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_mapToUpperTriangle(%p)" "\n bad coordType = %d, must be 1, 2, or 3\n", inpmtx, inpmtx->coordType) ; exit(-1) ; } nent = inpmtx->nent ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; if ( INPMTX_IS_BY_ROWS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( (row = ivec1[ii]) > (col = ivec2[ii]) ) { ivec1[ii] = col ; ivec2[ii] = row ; } } } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( (row = ivec2[ii]) > (col = ivec1[ii]) ) { ivec1[ii] = row ; ivec2[ii] = col ; } } } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec2[ii] < 0 ) { ivec2[ii] = -ivec2[ii] ; } } } inpmtx->storageMode = INPMTX_RAW_DATA ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- map entries into the upper triangle for a hermitian matrix created -- 98jan28, cca ----------------------------------- */ void InpMtx_mapToUpperTriangleH ( InpMtx *inpmtx ) { double *dvec ; int col, ii, nent, row ; int *ivec1, *ivec2 ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_mapToUpperTriangle(%p)" "\n bad input\n", inpmtx) ; exit(-1) ; } if ( !( INPMTX_IS_BY_ROWS(inpmtx) || INPMTX_IS_BY_COLUMNS(inpmtx) || INPMTX_IS_BY_CHEVRONS(inpmtx) ) ) { fprintf(stderr, "\n fatal error in InpMtx_mapToUpperTriangle(%p)" "\n bad coordType = %d, must be 1, 2, or 3\n", inpmtx, inpmtx->coordType) ; exit(-1) ; } if ( ! INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { fprintf(stderr, "\n fatal error in InpMtx_mapToUpperTriangleH(%p)" "\n input mode is not complex\n", inpmtx) ; exit(-1) ; } nent = inpmtx->nent ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; dvec = InpMtx_dvec(inpmtx) ; if ( INPMTX_IS_BY_ROWS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( (row = ivec1[ii]) > (col = ivec2[ii]) ) { ivec1[ii] = col ; ivec2[ii] = row ; dvec[2*ii+1] = -dvec[2*ii+1] ; } } } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( (row = ivec2[ii]) > (col = ivec1[ii]) ) { ivec1[ii] = row ; ivec2[ii] = col ; dvec[2*ii+1] = -dvec[2*ii+1] ; } } } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec2[ii] < 0 ) { ivec2[ii] = -ivec2[ii] ; dvec[2*ii+1] = -dvec[2*ii+1] ; } } } inpmtx->storageMode = INPMTX_RAW_DATA ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- compute the checksums of the indices and entries sums[0] = sum_{ii=0}^{nent} abs(ivec1[ii]) sums[1] = sum_{ii=0}^{nent} abs(ivec2[ii]) if real or complex entries then sums[2] = sum_{ii=0}^{nent} magnitudes of entries endif created -- 98may16, cca ----------------------------------------------------------- */ void InpMtx_checksums ( InpMtx *inpmtx, double sums[] ) { int ient, nent ; int *ivec1, *ivec2 ; /* --------------- check the input --------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_checksums(%p,%p)" "\n bad input\n", inpmtx, sums) ; exit(-1) ; } switch ( inpmtx->inputMode ) { case INPMTX_INDICES_ONLY : case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n fatal error in InpMtx_checksums(%p,%p)" "\n bad inputMode\n", inpmtx, sums) ; exit(-1) ; } sums[0] = sums[1] = sums[2] = 0.0 ; if ( (nent = InpMtx_nent(inpmtx)) <= 0 ) { return ; } ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; for ( ient = 0 ; ient < nent ; ient++ ) { sums[0] += abs(ivec1[ient]) ; sums[1] += abs(ivec2[ient]) ; } switch ( inpmtx->inputMode ) { case INPMTX_INDICES_ONLY : break ; case SPOOLES_REAL : { double *dvec = InpMtx_dvec(inpmtx) ; for ( ient = 0 ; ient < nent ; ient++ ) { sums[2] += fabs(dvec[ient]) ; } } break ; case SPOOLES_COMPLEX : { double *dvec = InpMtx_dvec(inpmtx) ; for ( ient = 0 ; ient < nent ; ient++ ) { sums[2] += Zabs(dvec[2*ient], dvec[2*ient+1]) ; } } break ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- to create an InpMtx object filled with random entries input -- mtx -- matrix object, if NULL, it is created inputMode -- input mode for the object, indices only, real or complex entries coordType -- coordinate type for the object, by rows, by columns or by chevrons storageMode -- storage mode for the object, raw data, sorted or by vectors nrow -- # of rows ncol -- # of columns symflag -- symmetry flag for the matrix, symmetric, hermitian or nonsymmetric nonzerodiag -- if 1, entries are placed on the diagonal nitem -- # of items to be placed into the matrix seed -- random number seed return value --- 1 -- normal return -1 -- mtx is NULL -2 -- bad input mode -3 -- bad coordinate type -4 -- bad storage mode -5 -- nrow or ncol <= 0 -6 -- bad symmetry flag -7 -- hermitian matrix but not complex -8 -- symmetric or hermitian matrix but nrow != ncol -9 -- nitem < 0 ---------------------------------------------------------------- */ int InpMtx_randomMatrix ( InpMtx *mtx, int inputMode, int coordType, int storageMode, int nrow, int ncol, int symflag, int nonzerodiag, int nitem, int seed ) { double *dvec ; Drand *drand ; int col, ii, neqns, row ; int *colids, *rowids ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_randomMatrix" "\n mtx is NULL\n") ; return(-1) ; } switch ( inputMode ) { case INPMTX_INDICES_ONLY : case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n fatal error in InpMtx_randomMatrix" "\n bad input mode %d\n", inputMode) ; return(-2) ; break ; } switch ( coordType ) { case INPMTX_BY_ROWS : case INPMTX_BY_COLUMNS : case INPMTX_BY_CHEVRONS : break ; default : fprintf(stderr, "\n fatal error in InpMtx_randomMatrix" "\n bad coordinate type %d\n", coordType) ; return(-3) ; break ; } switch ( storageMode ) { case INPMTX_RAW_DATA : case INPMTX_SORTED : case INPMTX_BY_VECTORS : break ; default : fprintf(stderr, "\n fatal error in InpMtx_randomMatrix" "\n bad storage mode%d\n", storageMode) ; return(-4) ; break ; } if ( nrow <= 0 || ncol <= 0 ) { fprintf(stderr, "\n fatal error in InpMtx_randomMatrix" "\n nrow = %d, ncol = %d\n", nrow, ncol) ; return(-5) ; } switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in InpMtx_randomMatrix" "\n bad symmetry flag%d\n", symflag) ; return(-6) ; break ; } if ( symflag == SPOOLES_HERMITIAN && inputMode != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error in InpMtx_randomMatrix" "\n symmetryflag is Hermitian, requires complex type\n") ; return(-7) ; } if ( (symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN) && nrow != ncol ) { fprintf(stderr, "\n fatal error in InpMtx_randomMatrix" "\n symmetric or hermitian matrix, nrow %d, ncol%d\n", nrow, ncol) ; return(-8) ; } if ( nitem < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_randomMatrix" "\n nitem = %d\n", nitem) ; return(-9) ; } /*--------------------------------------------------------------------*/ neqns = (nrow <= ncol) ? nrow : ncol ; if ( nonzerodiag == 1 ) { nitem += neqns ; } /* --------------------- initialize the object --------------------- */ InpMtx_init(mtx, INPMTX_BY_ROWS, inputMode, nitem, 0) ; /* ---------------- fill the triples ---------------- */ drand = Drand_new() ; Drand_setSeed(drand, seed) ; rowids = IVinit(nitem, -1) ; colids = IVinit(nitem, -1) ; if ( nonzerodiag == 1 ) { IVramp(neqns, rowids, 0, 1) ; Drand_setUniform(drand, 0, nrow) ; Drand_fillIvector(drand, nitem - neqns, rowids + neqns) ; Drand_setUniform(drand, 0, ncol) ; IVramp(neqns, colids, 0, 1) ; Drand_fillIvector(drand, nitem - neqns, colids + neqns) ; } else { Drand_setUniform(drand, 0, nrow) ; Drand_fillIvector(drand, nitem, rowids) ; Drand_setUniform(drand, 0, ncol) ; Drand_fillIvector(drand, nitem, colids) ; } if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ) { for ( ii = 0 ; ii < nitem ; ii++ ) { if ( (row = rowids[ii]) > (col = colids[ii]) ) { rowids[ii] = col ; colids[ii] = row ; } } } if ( inputMode == SPOOLES_REAL ) { dvec = DVinit(nitem, 0.0) ; Drand_setUniform(drand, 0.0, 1.0) ; Drand_fillDvector(drand, nitem, dvec) ; } else if ( inputMode == SPOOLES_COMPLEX ) { dvec = DVinit(2*nitem, 0.0) ; Drand_setUniform(drand, 0.0, 1.0) ; Drand_fillDvector(drand, 2*nitem, dvec) ; if ( symflag == SPOOLES_HERMITIAN ) { for ( ii = 0 ; ii < nitem ; ii++ ) { if ( rowids[ii] == colids[ii] ) { dvec[2*ii+1] = 0.0 ; } } } } else { dvec = NULL ; } /* ---------------- load the triples ---------------- */ switch ( inputMode ) { case INPMTX_INDICES_ONLY : InpMtx_inputTriples(mtx, nitem, rowids, colids) ; break ; case SPOOLES_REAL : InpMtx_inputRealTriples(mtx, nitem, rowids, colids, dvec) ; break ; case SPOOLES_COMPLEX : InpMtx_inputComplexTriples(mtx, nitem, rowids, colids, dvec) ; break ; } /* ---------------------------------------- set the coordinate type and storage mode ---------------------------------------- */ InpMtx_changeCoordType(mtx, coordType) ; InpMtx_changeStorageMode(mtx, storageMode) ; /* ------------------------ free the working storage ------------------------ */ Drand_free(drand) ; IVfree(rowids) ; IVfree(colids) ; if ( dvec != NULL ) { DVfree(dvec) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- determine the range of the matrix, i.e., the minimum and maximum rows and columns if pmincol != NULL then *pmincol = minimum column id if pmaxcol != NULL then *pmaxcol = maximum column id if pminrow != NULL then *pminrow = minimum row id if pmaxrow != NULL then *pmaxrow = maximum row id return value --- 1 -- normal return -1 -- mtx is NULL -2 -- no entries in the matrix -3 -- invalid coordinate type created -- 98oct15, cca ---------------------------------------------------- */ int InpMtx_range ( InpMtx *mtx, int *pmincol, int *pmaxcol, int *pminrow, int *pmaxrow ) { int maxcol, maxrow, mincol, minrow, nent ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_range()" "\n mtx is NULL\n") ; return(-1) ; } if ( (nent = mtx->nent) <= 0 ) { fprintf(stderr, "\n fatal error in InpMtx_range()" "\n %d entries\n", nent) ; return(-2) ; } if ( INPMTX_IS_BY_ROWS(mtx) ) { int *rowind = InpMtx_ivec1(mtx) ; int *colind = InpMtx_ivec2(mtx) ; int col, ii, row ; minrow = maxrow = rowind[0] ; mincol = maxcol = colind[0] ; for ( ii = 1 ; ii < nent ; ii++ ) { row = rowind[ii] ; col = colind[ii] ; if ( minrow > row ) { minrow = row ; } else if ( maxrow < row ) { maxrow = row ; } if ( mincol > col ) { mincol = col ; } else if ( maxcol < col ) { maxcol = col ; } } } else if ( INPMTX_IS_BY_COLUMNS(mtx) ) { int *rowind = InpMtx_ivec2(mtx) ; int *colind = InpMtx_ivec1(mtx) ; int col, ii, row ; minrow = maxrow = rowind[0] ; mincol = maxcol = colind[0] ; for ( ii = 1 ; ii < nent ; ii++ ) { row = rowind[ii] ; col = colind[ii] ; if ( minrow > row ) { minrow = row ; } else if ( maxrow < row ) { maxrow = row ; } if ( mincol > col ) { mincol = col ; } else if ( maxcol < col ) { maxcol = col ; } } } else if ( INPMTX_IS_BY_CHEVRONS(mtx) ) { int *chvind = InpMtx_ivec1(mtx) ; int *offsets = InpMtx_ivec2(mtx) ; int col, ii, off, row ; if ( (off = offsets[0]) >= 0 ) { row = chvind[0], col = row + off ; } else { col = chvind[0], row = col - off ; } minrow = maxrow = row ; mincol = maxcol = col ; for ( ii = 1 ; ii < nent ; ii++ ) { if ( (off = offsets[ii]) >= 0 ) { row = chvind[ii], col = row + off ; } else { col = chvind[ii], row = col - off ; } if ( minrow > row ) { minrow = row ; } else if ( maxrow < row ) { maxrow = row ; } if ( mincol > col ) { mincol = col ; } else if ( maxcol < col ) { maxcol = col ; } } } else { fprintf(stderr, "\n fatal error in InpMtx_range()" "\n invalid coordType %d\n", mtx->coordType) ; return(-3) ; } if ( pmincol != NULL ) { *pmincol = mincol ; } if ( pmaxcol != NULL ) { *pmaxcol = maxcol ; } if ( pminrow != NULL ) { *pminrow = minrow ; } if ( pmaxrow != NULL ) { *pmaxrow = maxrow ; } return(1) ; } /*--------------------------------------------------------------------*/ = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; for ( ient = 0 ; ient < nent ; ient++ ) { sums[0] += abs(ivec1[ient]) ; sums[1] += abs(ivec2[ient]) ; } switch ( inpmtx->inputMode ) { case INPMTX_INDICES_ONLY : break ; case SPOOLES_REAL : { double *dvec = InpMtx_dvec(inpmtx) ; for ( ient = 0 ; ient < nent ; ient++ ) { sums[2] += InpMtx/drivers/do_adjToGraph010075500020550007177000000004730654275671100174420ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = almond.9 set inAdjFile = $matrices/$matrix/orig0.adj set outGraphFile = temp.graphf set flag = 1 set msglvl = 5 set msgFile = res.$matrix set msgFile = res set msgFile = stdout adjToGraph $msglvl $msgFile $inAdjFile $outGraphFile $flag InpMtx/drivers/do_createGraph010075500020550007177000000011470660521066700176360ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inInpMtxFile = $matrices/$matrix/orig.inpmtxb set inInpMtxFile = $matrices/$matrix/orig.inpmtxf set inInpMtxFile = temp.inpmtxb set inInpMtxFile = /local1/ARPA/matrices/i4a/i4a.inpmtxb set inInpMtxFile = ../../../matrices/R10KV/orig.inpmtxb set outGraphFile = $matrices/$matrix/orig0.graphf set outGraphFile = temp.graphf set outGraphFile = /local1/ARPA/matrices/i4a/orig0.graphb set outGraphFile = ../../../matrices/R10KV/orig0.graphb set msglvl = 1 set msgFile = stdout createGraph $msglvl $msgFile $inInpMtxFile $outGraphFile InpMtx/drivers/do_createGraphForATA010075500020550007177000000004730654275677700206550ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inDInpMtxFile = $matrices/$matrix/orig.inpmtxb set inDInpMtxFile = $matrices/$matrix/orig.inpmtxf set outGraphFile = temp.graphf set msglvl = 3 set msgFile = stdout createGraphForATA $msglvl $msgFile $inDInpMtxFile $outGraphFile InpMtx/drivers/do_extract010075500020550007177000000014610661365266000170640ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res set msgFile = stdout # dataType = 1 --> real entries # dataType = 2 --> complex entries set dataType = 1 # symmetryflag = 0 --> symmetric # symmetryflag = 1 --> hermitian # symmetryflag = 2 --> nonsymmetric set symmetryflag = 2 # coordType = 1 --> rows # coordType = 2 --> columns # coordType = 3 --> chevrons set coordType = 1 set nrowA = 20 set ncolA = 30 set nitem = 100 set nrow1 = 5 set nrow2 = 15 set ncol1 = 10 set ncol2 = 20 set seed = 10203 foreach symmetryflag ( 2 ) foreach dataType ( 2 ) foreach storageMode ( 3 ) testExtract $msglvl $msgFile $dataType $symmetryflag \ $coordType $nrowA $ncolA $nitem \ $nrow1 $nrow2 $ncol1 $ncol2 $seed end end end InpMtx/drivers/do_fullAdj010075500020550007177000000002260653410623000167560ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set nvtx = 10 set nent = 50 set seed = 10101 testFullAdj $msglvl $msgFile $nvtx $nent $seed InpMtx/drivers/do_fullAdj2010075500020550007177000000002620653410623000170400ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set nvtx = 10 set nentA = 20 set nentB = 20 set seed = 10101 testFullAdj2 $msglvl $msgFile $nvtx $nentA $nentB $seed InpMtx/drivers/do_gmmm010075500020550007177000000022410662340002100163230ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 5 set msgFile = res set msgFile = stdout # dataType = 0 --> indices only # dataType = 1 --> real entries # dataType = 2 --> complex entries set dataType = 2 # symflag = 0 --> symmetric # symflag = 1 --> hermitian # symflag = 2 --> nonsymmetric set symflag = 0 # storageMode = 1 --> rows # storageMode = 2 --> columns # storageMode = 3 --> chevrons set storageMode = 1 # transposeflag = 0 --> Y := Y + alpha * A * X # transposeflag = 1 --> Y := Y + alpha * A^H * X, nonsymmetric only # transposeflag = 2 --> Y := Y + alpha * A^T * X, nonsymmetric only set transposeflag = 0 set nrow = 20 set ncol = 30 set nitem = 200 set nrhs = 3 set seed = 10203 set alphaReal = 2.0 set alphaImag = 3.0 set betaReal = 1.0 set betaImag = 5.0 foreach transposeflag ( 2 ) foreach symflag ( 2 ) foreach dataType ( 2 ) foreach storageMode ( 1 ) testGMMM $msglvl $msgFile $dataType $symflag $storageMode \ $transposeflag $nrow $ncol $nitem $nrhs $seed \ $alphaReal $alphaImag $betaReal $betaImag end end end end ex entries set dataType = 2 # symflag = 0 --> symmetric # symflag = 1 --> hermitian # symflag = 2 --> nonsymmetric set symflag = 0 # storageMode = 1 --> rows # storageMode = 2 --> columns # storageMode = 3 --> chevrons set storageMode = 1 # transposeflag = 0 --> Y := Y + alpha * A * X # transposeflag = 1 --> Y := Y + alpha * A^H * X, nonsymmetricInpMtx/drivers/do_gmvm010075500020550007177000000022070662340736000163530ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 5 set msgFile = res set msgFile = stdout # dataType = 0 --> indices only # dataType = 1 --> real entries # dataType = 2 --> complex entries set dataType = 2 # symflag = 0 --> symmetric # symflag = 1 --> hermitian # symflag = 2 --> nonsymmetric set symflag = 0 # storageMode = 1 --> rows # storageMode = 2 --> columns # storageMode = 3 --> chevrons set storageMode = 1 # transposeflag = 0 --> Y := Y + alpha * A * X # transposeflag = 1 --> Y := Y + alpha * A^H * X, nonsymmetric only # transposeflag = 2 --> Y := Y + alpha * A^T * X, nonsymmetric only set transposeflag = 0 set nrow = 20 set ncol = 30 set nitem = 200 set seed = 10203 set alphaReal = 0.0 set alphaImag = 0.0 set betaReal = 0.0 set betaImag = 0.0 foreach transposeflag ( 0 ) foreach symflag ( 0 ) foreach dataType ( 1 ) foreach storageMode ( 1 ) testGMVM $msglvl $msgFile $dataType $symflag $storageMode \ $transposeflag $nrow $ncol $nitem $seed \ $alphaReal $alphaImag $betaReal $betaImag end end end end InpMtx/drivers/do_mkLaplacianMtx010075500020550007177000000003200662061172200203000ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 5 set msgFile = stdout set n1 = 7 set n2 = 7 set n3 = 7 set outFile = ../../../matrices/GRD7x7x7/laplacian.inpmtxb mkLaplacianMtx $msglvl $msgFile $n1 $n2 $n3 $outFile InpMtx/drivers/do_mkNaturalFactorMtx010075500020550007177000000003250654002571000211630ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 5 set msgFile = stdout set n1 = 3 set n2 = 3 set n3 = 1 set seed = 1 set outFile = natfac.$n1.$n2.$n3.inpmtxf mkNaturalFactorMtx $msglvl $msgFile $n1 $n2 $n3 $seed $outFile InpMtx/drivers/do_mmm010075500020550007177000000021410654002644300161650ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 5 set msgFile = res set msgFile = stdout # dataType = 0 --> indices only # dataType = 1 --> real entries # dataType = 2 --> complex entries set dataType = 2 # symflag = 0 --> symmetric # symflag = 1 --> hermitian # symflag = 2 --> nonsymmetric set symflag = 0 # storageMode = 1 --> rows # storageMode = 2 --> columns # storageMode = 3 --> chevrons set storageMode = 1 # transposeflag = 0 --> Y := Y + alpha * A * X # transposeflag = 1 --> Y := Y + alpha * A^H * X, nonsymmetric only # transposeflag = 2 --> Y := Y + alpha * A^T * X, nonsymmetric only set transposeflag = 0 set nrow = 30 set ncol = 30 set nitem = 2000 set nrhs = 3 set seed = 10203 set alphaReal = 4.0 set alphaImag = 0.0 foreach transposeflag ( 0 ) foreach symflag ( 0 ) foreach dataType ( 2 ) foreach storageMode ( 1 ) testMMM $msglvl $msgFile $dataType $symflag $storageMode \ $transposeflag $nrow $ncol $nitem $nrhs $seed \ $alphaReal $alphaImag end end end end InpMtx/drivers/do_profile010075500020550007177000000010470662066635400170550ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set msglvl = 1 set msgFile = stdout set inFile = $matrices/$matrix/orig.inpmtxb set inFile = $matrices/$matrix/orig.inpmtxf set inFile = /local1/ARPA/matrices/i4a/i4a.inpmtxb set n = 5 set inFile = /local1/ARPA/matrices/SFTC$n/SFTC$n.inpmtxb set inFile = ../../../matrices/R10KV/orig.inpmtxb set inFile = /local1/ARPA/matrices/SFTC8/SFTC8.inpmtxb set npts = 100 set tausmall = 1.e-20 set taubig = 1.e+21 getProfile $msglvl $msgFile $inFile $npts $tausmall $taubig InpMtx/drivers/do_readAIJ010075500020550007177000000017230663234535000166460ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = GRD7x7 set msglvl = 1 set msgFile = stdout set dataType = 1 set flag = 0 set matrices = /local1/DATA set matrix = MAT_1 set matrices = ../../../matrices set matrix = R3D13824 set inFile = $matrices/$matrix/AIJ$dataType.raw set inFile = $matrices/$matrix.DAT set inFile = $matrices/$matrix/aij.raw set outFile = $matrices/$matrix/AIJ$dataType.inpmtxf set outFile = $matrices/$matrix/AIJ$dataType.inpmtxb set outFile = /local1/ARPA/matrices/SFTC1/SFTC1.inpmtxb set outFile = $matrices/$matrix/orig.inpmtxb time readAIJ $msglvl $msgFile $dataType $inFile $outFile $flag exit # set inFile = temp # set outFile = temp.inpmtxb foreach n ( 2 3 4 5 6 7 8 ) set inFile = /local1/DATA/MAT_$n.DAT set outFile = /local1/ARPA/matrices/SFTC$n/SFTC$n.inpmtxb echo inFile $inFile echo outFile $outFile time readAIJ $msglvl $msgFile $dataType $inFile $outFile $flag end InpMtx/drivers/do_readAIJ2010075500020550007177000000013200660520754300167220ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = GRD7x7 set msglvl = 1 set msgFile = stdout set dataType = 1 set flag = 0 set matrices = /local1/DATA set matrix = MAT_1 set inFile = $matrices/$matrix/AIJ$dataType.raw set inFile = $matrices/$matrix.DAT set outFile = $matrices/$matrix/AIJ$dataType.inpmtxf set outFile = $matrices/$matrix/AIJ$dataType.inpmtxb set outFile = /local1/ARPA/matrices/SFTC1/SFTC1.inpmtxb set inFile = /local/cleve/ARPA/matrices/R10KV/r10kv.jacdata set outFile = /local/cleve/ARPA/matrices/R10KV/orig.inpmtxb # set inFile = temp # set outFile = temp.inpmtxb echo inFile $inFile echo outFile $outFile time readAIJ2 $msglvl $msgFile $inFile $outFile InpMtx/drivers/do_testHBIO010075500020550007177000000020400662456730700170320ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = /local/cleve/ARPA/matrices set matrix = BCELL14 set matrices = ../../Matrices set matrix = BCSSTK23 set matrix = PLAT362 set matrix = BCSSTK03 set matrix = BCSSTK04 set matrix = BCSSTM04 set matrix = BCSSTK17 set matrices = /local/cleve/ARPA/matrices set inHBfile = $matrices/$matrix/$matrix.hbmat # set inHBfile = $matrices/$matrix/bcell14.rb.mtx # set matrices = /local/cleve/ARPA/release2.1/iohb1.0/data # set inHBfile = $matrices/abb313.pra # set inHBfile = $matrices/add20.rua # set inHBfile = $matrices/dwg961a.cua # set inHBfile = $matrices/illc1033.rra # set inHBfile = $matrices/mahindas.rua # set inHBfile = $matrices/mhd1280b.cua # set matrices = /local/cleve/ARPA/release1.0/Matrices/ # set inHBfile = $matrices/BCSSTK23/BCSSTK23.hbmat set outInpMtxFile = $matrices/$matrix/orig.inpmtxf set outInpMtxFile = $matrices/$matrix/orig.inpmtxb set outInpMtxFile = none set msglvl = 1 set msgFile = stdout testHBIO2 $msglvl $msgFile $inHBfile $outInpMtxFile InpMtx/drivers/do_testIO010075500020550007177000000007440660773732100166250ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrices = ../../../matrices set matrix = GRD7x7 set inInpMtxFile = $matrices/$matrix/AIJ0.inpmtxf set inInpMtxFile = $matrices/$matrix/AIJ0.inpmtxb set inInpMtxFile = $matrices/$matrix/AIJ2.inpmtxb set inInpMtxFile = $matrices/$matrix/AIJ1.inpmtxb set outInpMtxFile = $matrices/$matrix/AIJ0.inpmtxf set outInpMtxFile = none set msglvl = 3 set msgFile = stdout testIO $msglvl $msgFile $inInpMtxFile $outInpMtxFile InpMtx/drivers/do_testInput010075500020550007177000000004000657730446600174100ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set type = 2 set n1 = 31 set n2 = 31 set n3 = 31 set estpar = 0.95 set estpar = 1.00 set growth = 2.00 set growth = 1.25 testInput $msglvl $msgFile $type $n1 $n2 $n3 $estpar $growth InpMtx/drivers/do_testR2D010075500020550007177000000010350654275715600167050ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inEGraphFile = $matrices/$matrix/orig.egraphf set inCoordsFile = $matrices/$matrix/grid.coordsf set coordType = 1 set seed = 1 set outDInpMtxFile = temp.inpmtxf set outDInpMtxFile = $matrices/$matrix/orig.inpmtxb set outDInpMtxFile = $matrices/$matrix/orig.inpmtxf set msglvl = 1 set msgFile = res.$matrix set msgFile = res set msgFile = stdout testR2D $msglvl $msgFile $inEGraphFile $inCoordsFile \ $coordType $seed $outDInpMtxFile InpMtx/drivers/do_weightedAdjToGraph010075500020550007177000000004630654275721400211210ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = almond.9 set flag = 0 set flag = 1 set inAdjFile = $matrices/$matrix/orig1.adj set outGraphFile = temp.graphf set msglvl = 5 set msgFile = stdout weightedAdjToGraph $msglvl $msgFile $inAdjFile $outGraphFile $flag InpMtx/drivers/makefile010064400020550007177000000052040665314253700165020ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = adjToGraph \ createGraph \ createGraphForATA \ getProfile \ mkLaplacianMtx \ mkNaturalFactorMtx \ readAIJ \ readAIJ2 \ testExtract \ testFullAdj \ testFullAdj2 \ testGMMM \ testGMVM \ testHBIO \ testHBIO2 \ testInput \ testIO \ testMMM \ testR2D \ weightedAdjToGraph drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} adjToGraph : adjToGraph.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} createGraph : createGraph.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} createGraphForATA : createGraphForATA.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} getProfile : getProfile.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} mkLaplacianMtx : mkLaplacianMtx.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} mkNaturalFactorMtx : mkNaturalFactorMtx.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} readAIJ : readAIJ.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} readAIJ2 : readAIJ2.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testExtract : testExtract.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testFullAdj : testFullAdj.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testFullAdj2 : testFullAdj2.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testGMMM : testGMMM.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testGMVM : testGMVM.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testHBIO : testHBIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testHBIO2 : testHBIO2.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testInput : testInput.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testIO : testIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testMMM : testMMM.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testR2D : testR2D.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} weightedAdjToGraph : weightedAdjToGraph.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} {DRIVERS} adjToGraph : adjToGraph.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} createGraph : createGraph.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} createGraphForATA : createGraphForATA.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} getProfile : getProfile.o ../../spooles.a ${PURIFInpMtx/drivers/adjToGraph.c010064400020550007177000000160450654001765700171750ustar00clevecompmath00000400000006/* makeGraph.c */ #include "../InpMtx.h" #include "../../Graph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------- read in an adjacency structure file and create a unit weight Graph object nvtx nadj offsets[nvtx+1] indices[nadj] created -- 96nov15, cca ------------------------------------- */ { InpMtx *inpmtx ; double t1, t2 ; int flag, ierr, ii, msglvl, nadj, nvtx, rc, v, vsize ; int *adjncy, *offsets, *vadj ; Graph *graph ; FILE *fp, *msgFile ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inAdjacencyFile outGraphFile flag" "\n msglvl -- message level" "\n msgFile -- message file" "\n inAdjacencyFile -- input file" "\n outGraphFile -- output file, must be *.graphf or *.graphb" "\n flag -- flag for 0-based or 1-based addressing" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } flag = atoi(argv[5]) ; if ( flag < 0 || flag > 1 ) { fprintf(stderr, "\n fatal error in makeGraph %d %s %s %s %d" "\n flag must be 0 if indices and offsets are zero-based like C" "\n flag must be 1 if indices and offsets are one-based like Fortran" "\n", msglvl, argv[2], argv[3], argv[4], flag) ; exit(-1) ; } fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n flag -- %d" "\n", argv[0], msglvl, argv[2], argv[3], argv[4], flag) ; fflush(msgFile) ; /* ------------------- open the input file ------------------- */ if ( (fp = fopen(argv[3], "r")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[3]) ; return(-1) ; } /* ------------------------------------------------- read in the number of vertices and adjacency size ------------------------------------------------- */ if ( (rc = fscanf(fp, " %d %d", &nvtx, &nadj)) != 2 ) { fprintf(stderr, "\n fatal error in %s" "\n %d of %d items read\n", argv[0], rc, 2) ; exit(-1) ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n adjacency file has %d vertices and %d indices", nvtx, nadj) ; fflush(msgFile) ; } /* ------------------- read in the offsets ------------------- */ offsets = IVinit(nvtx + 1, -1) ; rc = IVfscanf(fp, nvtx + 1, offsets) ; if ( rc != nvtx + 1 ) { fprintf(stderr, "\n fatal error in %s reading offsets" "\n %d of %d items read\n", argv[0], rc, nvtx + 1) ; exit(-1) ; } if ( flag == 1 ) { /* --------------------------------------------- decrement the offsets by one for C addressing --------------------------------------------- */ for ( ii = 0 ; ii < nvtx + 1 ; ii++ ) { offsets[ii]-- ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n offsets") ; IVfp80(msgFile, nvtx+1, offsets, 80, &ierr) ; fflush(msgFile) ; } /* --------------------- read in the adjacency --------------------- */ adjncy = IVinit(nadj, -1) ; rc = IVfscanf(fp, nadj, adjncy) ; if ( rc != nadj ) { fprintf(stderr, "\n fatal error in %s reading adjncy" "\n %d of %d items read\n", argv[0], rc, nadj) ; exit(-1) ; } if ( flag == 1 ) { /* --------------------------------------------- decrement the offsets by one for C addressing --------------------------------------------- */ for ( ii = 0 ; ii < nadj ; ii++ ) { adjncy[ii]-- ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n adjncy") ; IVfp80(msgFile, nadj, adjncy, 80, &ierr) ; fflush(msgFile) ; } /* ----------------------------------------------- check the adjacency structure for valid entries ----------------------------------------------- */ for ( ii = 0 ; ii < nadj ; ii++ ) { v = adjncy[ii] ; if ( v < 0 || v >= nvtx ) { fprintf(stderr, "\n fatal error in mkGraph" "\n adjncy[%d] = %d, out of range in [0,%d]" "\n ", ii, v, nvtx-1) ; exit(-1) ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n adjncy") ; IVfp80(msgFile, nadj, adjncy, 80, &ierr) ; fflush(msgFile) ; } /* ------------------------- set up the InpMtx object ------------------------- */ inpmtx = InpMtx_new() ; InpMtx_init(inpmtx, INPMTX_BY_ROWS, INPMTX_INDICES_ONLY, nvtx + 2*nadj, nvtx) ; for ( v = 0 ; v < nvtx ; v++ ) { InpMtx_inputEntry(inpmtx, v, v) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n inputting entry (%d,%d)", v, v) ; fflush(msgFile) ; } vsize = offsets[v+1] - offsets[v] ; vadj = &adjncy[offsets[v]] ; if ( msglvl > 3 ) { fprintf(msgFile, "\n inputting row %d :", v) ; IVfp80(msgFile, vsize, vadj, 22, &ierr) ; fflush(msgFile) ; } InpMtx_inputRow(inpmtx, v, vsize, vadj) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n inputting column %d :", v) ; IVfp80(msgFile, vsize, vadj, 22, &ierr) ; fflush(msgFile) ; } InpMtx_inputColumn(inpmtx, v, vsize, vadj) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n raw data") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; } InpMtx_changeStorageMode(inpmtx, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n after changing to vector storage mode") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; } /* ----------------------------------- free the offsets and adjncy vectors ----------------------------------- */ IVfree(offsets) ; IVfree(adjncy) ; /* --------------------------- initialize the Graph object --------------------------- */ offsets = IVinit(nvtx + 1, -1) ; IVcopy(nvtx, offsets, IV_entries(&inpmtx->offsetsIV)) ; offsets[nvtx] = inpmtx->nent ; adjncy = IV_entries(&inpmtx->ivec2IV) ; graph = Graph_new() ; Graph_fillFromOffsets(graph, nvtx, offsets, adjncy, 0) ; graph->type = 0 ; graph->totvwght = nvtx ; if ( msglvl > 0 ) { fprintf(msgFile, "\n graph has %d vertices and %d edges", graph->nvtx, graph->nedges) ; fflush(msgFile) ; } if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } /* -------------------------- write out the Graph object -------------------------- */ if ( strcmp(argv[4], "none") != 0 ) { MARKTIME(t1) ; rc = Graph_writeToFile(graph, argv[4]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write graph to file %s", t2 - t1, argv[4]) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_writeToFile(%p,%s)", rc, graph, argv[4]) ; } /* --------------------------------- free the Graph and InpMtx object --------------------------------- */ Graph_free(graph) ; InpMtx_free(inpmtx) ; IVfree(offsets) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/createGraph.c010064400020550007177000000065610657352113700174000ustar00clevecompmath00000400000006/* createGraph.c */ #include "../InpMtx.h" #include "../../Graph.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------------------- read in a InpMtx object and create the Graph object created -- 97feb14, cca ---------------------------------------------------- */ { InpMtx *inpmtx ; FILE *msgFile ; Graph *graph ; int count, msglvl, nvtx, rc ; IVL *adjIVL ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.inpmtxf or *.inpmtxb" "\n outFile -- output file, must be *.graphf or *.graphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], argv[3], argv[4]) ; fflush(msgFile) ; /* -------------------------- read in the InpMtx object -------------------------- */ inpmtx = InpMtx_new() ; if ( strcmp(argv[3], "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } rc = InpMtx_readFromFile(inpmtx, argv[3]) ; fprintf(msgFile, "\n return value %d from InpMtx_readFromFile(%p,%s)", rc, inpmtx, argv[3]) ; if ( rc != 1 ) { exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading InpMtx object from file %s", argv[3]) ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; fflush(msgFile) ; } InpMtx_changeStorageMode(inpmtx, 3) ; nvtx = 1 + IV_max(&inpmtx->ivec1IV) ; count = 1 + IV_max(&inpmtx->ivec2IV) ; if ( nvtx < count ) { nvtx = count ; } /* ------------------------------------ create the full adjacency IVL object ------------------------------------ */ adjIVL = InpMtx_fullAdjacency(inpmtx) ; /* --------------------- fill the Graph object --------------------- */ graph = Graph_new() ; Graph_init2(graph, 0, nvtx, 0, adjIVL->tsize, nvtx, adjIVL->tsize, adjIVL, NULL, NULL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Graph object") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* --------------------------------- check that the graph is symmetric --------------------------------- */ if ( (rc = Graph_isSymmetric(graph)) == 1 ) { fprintf(msgFile, "\n\n graph is symmetric\n") ; } else { fprintf(msgFile, "\n\n graph is not symmetric\n") ; } /* --------------------------- write out the Graph object --------------------------- */ if ( strcmp(argv[4], "none") != 0 ) { rc = Graph_writeToFile(graph, argv[4]) ; fprintf(msgFile, "\n return value %d from Graph_writeToFile(%p,%s)", rc, graph, argv[4]) ; } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; InpMtx_free(inpmtx) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/createGraphForATA.c010064400020550007177000000060370654001646600203710ustar00clevecompmath00000400000006/* createGraphForATA.c */ #include "../InpMtx.h" #include "../../Graph.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------- read in a InpMtx object for a matrix A and create the Graph object for A^T A created -- 97mar12, cca --------------------------------------- */ { InpMtx *inpmtxA ; FILE *msgFile ; Graph *graph ; int msglvl, nvtx, rc ; IVL *adjIVL ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.dinpmtxf or *.dinpmtxb" "\n outFile -- output file, must be *.graphf or *.graphb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], argv[3], argv[4]) ; fflush(msgFile) ; /* -------------------------- read in the InpMtx object -------------------------- */ inpmtxA = InpMtx_new() ; if ( strcmp(argv[3], "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } rc = InpMtx_readFromFile(inpmtxA, argv[3]) ; fprintf(msgFile, "\n return value %d from InpMtx_readFromFile(%p,%s)", rc, inpmtxA, argv[3]) ; if ( rc != 1 ) { exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading InpMtx object from file %s", argv[3]) ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } /* -------------------------------------------------------- get the IVL object with the adjacency structure of A^T*A -------------------------------------------------------- */ adjIVL = InpMtx_adjForATA(inpmtxA) ; nvtx = IVL_nlist(adjIVL) ; /* --------------------- fill the Graph object --------------------- */ graph = Graph_new() ; Graph_init2(graph, 0, nvtx, 0, adjIVL->tsize, nvtx, adjIVL->tsize, adjIVL, NULL, NULL) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n graph of A^T A") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* --------------------------- write out the Graph object --------------------------- */ if ( strcmp(argv[4], "none") != 0 ) { rc = Graph_writeToFile(graph, argv[4]) ; fprintf(msgFile, "\n return value %d from Graph_writeToFile(%p,%s)", rc, graph, argv[4]) ; } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; InpMtx_free(inpmtxA) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/getProfile.c010064400020550007177000000057460657426655300172700ustar00clevecompmath00000400000006/* getProfile.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------- get a log10 profile of the matrix entries created -- 97feb14, cca ----------------------------------------- */ { int ii, msglvl, nbig, npts, nsmall, nzero, rc, size ; InpMtx *inpmtx ; double taubig, tausmall ; double *xvec, *yvec ; DV *xDV, *yDV ; FILE *msgFile ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile npts tausmall taubig" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.dinpmtxf or *.dinpmtxb" "\n npts -- number of points in the profile curve" "\n tausmall -- lower cutoff" "\n taubig -- upper cutoff" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } npts = atoi(argv[4]) ; tausmall = atof(argv[5]) ; taubig = atof(argv[6]) ; fprintf(msgFile, "\n %% %s " "\n %% msglvl -- %d" "\n %% msgFile -- %s" "\n %% inFile -- %s" "\n %% npts -- %d" "\n %% tausmall -- %e" "\n %% taubig -- %e" "\n", argv[0], msglvl, argv[2], argv[3], npts, tausmall, taubig) ; fflush(msgFile) ; /* -------------------------- read in the InpMtx object -------------------------- */ if ( strcmp(argv[3], "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } inpmtx = InpMtx_new() ; rc = InpMtx_readFromFile(inpmtx, argv[3]) ; fprintf(msgFile, "\n %% return value %d from InpMtx_readFromFile(%p,%s)", rc, inpmtx, argv[3]) ; if ( rc != 1 ) { exit(-1) ; } fprintf(msgFile, "\n\n %d entries", inpmtx->nent) ; /* --------------- get the profile --------------- */ xDV = DV_new() ; yDV = DV_new() ; InpMtx_log10profile(inpmtx, npts, xDV, yDV, tausmall, taubig, &nzero, &nsmall, &nbig) ; fprintf(msgFile, "\n %% %8d zero entries " "\n %% %8d entries smaller than %20.12e in magnitude" "\n %% %8d entries larger than %20.12e in magnitude", nzero, nsmall, tausmall, nbig, taubig) ; DV_sizeAndEntries(xDV, &size, &xvec) ; DV_sizeAndEntries(yDV, &size, &yvec) ; fprintf(msgFile, "\n data = [ ...") ; for ( ii = 0 ; ii < size ; ii++ ) { fprintf(msgFile, "\n %20.12e %20.12e", xvec[ii], yvec[ii]) ; } fprintf(msgFile, " ] ; ") ; /* ------------------------ free the working storage ------------------------ */ DV_free(xDV) ; DV_free(yDV) ; InpMtx_free(inpmtx) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ *msgFile ; if ( argInpMtx/drivers/mkLaplacianMtx.c010064400020550007177000000115130662060742500200470ustar00clevecompmath00000400000006/* mkLaplacianMtx.c */ #include "../InpMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- create a laplacian matrix for a regular grid for a n1 x n2 grid we use the following stencil [ -1 -1 -1 ] [ -1 8 -1 ] [ -1 -1 -1 ] for a n1 x n2 x n3 grid we use the following stencil [ -1 -1 -1 ] [ -1 -1 -1 ] [ -1 -1 -1 ] [ -1 -1 -1 ] [ -1 27 -1 ] [ -1 -1 -1 ] [ -1 -1 -1 ] [ -1 -1 -1 ] [ -1 -1 -1 ] created -- 98nov06, cca --------------------------------------------------------------- */ void main ( int argc, char *argv[] ) { char *outFileName ; double *dvec ; double t1, t2 ; FILE *msgFile ; InpMtx *inpmtx ; int ient, ii, msglvl, nent, nvtx, n1, n2, n3, size, stencil, v, vsize, w ; int *ivec1, *ivec2, *vadj ; IVL *adjIVL ; /* --------------- check the input --------------- */ if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 outFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- number of grid points in the first direction" "\n n2 -- number of grid points in the second direction" "\n n3 -- number of grid points in the third direction" "\n outFile -- file to contain the InpMtx object" "\n must be *.inpmtxb or *.inpmtxf" "\n", argv[0]) ; return ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; n3 = atoi(argv[5]) ; outFileName = argv[6] ; /* -------------- echo the input -------------- */ fprintf(msgFile, "\n input to %s" "\n msglvl = %d" "\n msgFile = %s" "\n n1 = %d" "\n n2 = %d" "\n n3 = %d" "\n outFile = %s" "\n", argv[0], msglvl, argv[2], n1, n2, n3, outFileName) ; fflush(msgFile) ; nvtx = n1 * n2 * n3 ; /* ---------------------------------------- create the grid graph's adjacency object ---------------------------------------- */ if ( n1 == 1 ) { adjIVL = IVL_make9P(n2, n3, 1) ; stencil = 9 ; } else if ( n2 == 1 ) { adjIVL = IVL_make9P(n1, n3, 1) ; stencil = 9 ; } else if ( n3 == 1 ) { adjIVL = IVL_make9P(n1, n2, 1) ; stencil = 9 ; } else { adjIVL = IVL_make27P(n1, n2, n3, 1) ; stencil = 27 ; } nent = adjIVL->tsize ; /* ------------------------- create the InpMtx object ------------------------- */ MARKTIME(t1) ; inpmtx = InpMtx_new() ; InpMtx_init(inpmtx, INPMTX_BY_ROWS, SPOOLES_REAL, nent, 0) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : initialize the InpMtx object", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n InpMtx after initialization") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; } ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; dvec = InpMtx_dvec(inpmtx) ; if ( stencil == 9 ) { for ( v = ient = 0 ; v < nvtx ; v++ ) { IVL_listAndSize(adjIVL, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { if ( (w = vadj[ii]) == v ) { ivec1[ient] = v ; ivec2[ient] = w ; dvec[ient] = 8.0 ; ient++ ; } else if ( w > v ) { ivec1[ient] = v ; ivec2[ient] = w ; dvec[ient] = -1.0 ; ient++ ; } } } } else { for ( v = ient = 0 ; v < nvtx ; v++ ) { IVL_listAndSize(adjIVL, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { if ( (w = vadj[ii]) == v ) { ivec1[ient] = v ; ivec2[ient] = w ; dvec[ient] = 27.0 ; ient++ ; } else if ( w > v ) { ivec1[ient] = v ; ivec2[ient] = w ; dvec[ient] = -1.0 ; ient++ ; } } } } inpmtx->nent = ient ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx object for a %d x %d x %d grid", n1, n2, n3) ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------- optionally write out the InpMtx object to a file ------------------------------------------------- */ if ( strcmp(outFileName, "none") != 0 ) { InpMtx_writeToFile(inpmtx, outFileName) ; } /* ---------------- free the objects ---------------- */ IVL_free(adjIVL) ; InpMtx_free(inpmtx) ; fprintf(msgFile, "\n") ; return ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/mkNaturalFactorMtx.c010064400020550007177000000112550654002600600207220ustar00clevecompmath00000400000006/* mkNaturalFactorMtx.c */ #include "../InpMtx.h" #include "../../EGraph.h" #include "../../Coords.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- create a natural factor matrix. for a n1 x n2 grid there are (n1-1)*(n2-1) elements and four rows per element, so the matrix is 4*(n1-1)*(n2-1) x n1*n2 for a n1 x n2 x n3 grid there are (n1-1)*(n2-1)*(n3-1) elements and eight rows per element, so the matrix is 8*(n1-1)*(n2-1)*(n3-1) x n1*n2*n3 created -- 97sep19, cca --------------------------------------------------------------- */ void main ( int argc, char *argv[] ) { char *outFileName ; InpMtx *inpmtx ; double *entries ; double t1, t2 ; Drand *drand ; EGraph *egraph ; FILE *msgFile ; int ielem, irow, jrow, msglvl, nelem, nvtx, n1, n2, n3, seed, size ; int *indices ; /* --------------- check the input --------------- */ if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 seed outFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- number of grid points in the first direction" "\n n2 -- number of grid points in the second direction" "\n n3 -- number of grid points in the third direction" "\n seed -- random number seed" "\n outFile -- file to contain the InpMtx object" "\n must be *.dinpmtxb or *.dinpmtxf" "\n", argv[0]) ; return ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; n3 = atoi(argv[5]) ; seed = atoi(argv[6]) ; outFileName = argv[7] ; /* -------------- echo the input -------------- */ fprintf(msgFile, "\n input to %s" "\n msglvl = %d" "\n msgFile = %s" "\n n1 = %d" "\n n2 = %d" "\n n3 = %d" "\n seed = %d" "\n outFile = %s" "\n", argv[0], msglvl, argv[2], n1, n2, n3, seed, outFileName) ; fflush(msgFile) ; /* ------------------------ create the EGraph object ------------------------ */ MARKTIME(t1) ; if ( n3 == 1 ) { egraph = EGraph_make9P(n1, n2, 1) ; entries = DVinit(4, 0.0) ; } else { egraph = EGraph_make27P(n1, n2, n3, 1) ; entries = DVinit(8, 0.0) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : create egraph ", t2 - t1) ; if ( msglvl > 2 ) { EGraph_writeForHumanEye(egraph, msgFile) ; fflush(msgFile) ; } nvtx = egraph->nvtx ; nelem = egraph->nelem ; /* ------------------------------- create the random number object ------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setUniform(drand, -1.0, 1.0) ; Drand_setSeed(drand, seed) ; /* ------------------------- create the InpMtx object ------------------------- */ MARKTIME(t1) ; inpmtx = InpMtx_new() ; InpMtx_init(inpmtx, INPMTX_BY_ROWS, SPOOLES_REAL, 0, 0) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : initialize the InpMtx object", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n InpMtx after initialization") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; } for ( ielem = 0, jrow = 0 ; ielem < nelem ; ielem++ ) { IVL_listAndSize(egraph->adjIVL, ielem, &size, &indices) ; if ( n3 == 1 ) { for ( irow = 0 ; irow < 4 ; irow++, jrow++ ) { Drand_fillDvector(drand, size, entries) ; InpMtx_inputRealRow(inpmtx, jrow, size, indices, entries) ; } } else { for ( irow = 0 ; irow < 8 ; irow++, jrow++ ) { Drand_fillDvector(drand, size, entries) ; InpMtx_inputRealRow(inpmtx, jrow, size, indices, entries) ; } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx object for a %d x %d x %d grid", n1, n2, n3) ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------- optionally write out the InpMtx object to a file ------------------------------------------------- */ if ( strcmp(outFileName, "none") != 0 ) { InpMtx_writeToFile(inpmtx, outFileName) ; } /* ---------------- free the objects ---------------- */ EGraph_free(egraph) ; InpMtx_free(inpmtx) ; Drand_free(drand) ; DVfree(entries) ; fprintf(msgFile, "\n") ; return ; } /*--------------------------------------------------------------------*/ msglvl -- message level" "\n msgFile -- message file" "\n n1 -- number of grid points in the first direction" "\n n2 -- number of grid points in the second direction" "\n n3 -- number of grid points in the third direction" "\n seed -- random number seed" "\InpMtx/drivers/readAIJ.c010064400020550007177000000144600657352117500164110ustar00clevecompmath00000400000006/* readAIJ.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- read in (i, j, a(i,j)) triples, construct a InpMtx object and write it out to a file created -- 97oct17, cca --------------------------------------------------- */ { char *inFileName, *outFileName ; InpMtx *inpmtx ; FILE *inputFile, *msgFile ; int dataType, flag, ient, msglvl, ncol, nent, nrow, rc ; int *ivec1, *ivec2 ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : readAIJ msglvl msgFile dataType inputFile outFile flag" "\n msglvl -- message level" "\n msgFile -- message file" "\n dataType -- 0 for indices only, 1 for double, 2 for complex" "\n inputFile -- input file for a(i,j) entries" "\n the first line must be \"nrow ncol nentries\"" "\n if dataType == 0 then" "\n next lines are \"irow jcol\"" "\n else if dataType == 1 then" "\n next lines are \"irow jcol entry\"" "\n else if dataType == 2 then" "\n next lines are \"irow jcol realEntry imagEntry\"" "\n endif" "\n outFile -- output file, must be *.inpmtxf or *.inpmtxb" "\n flag -- flag for 0-based or 1-based addressing" "\n") ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } dataType = atoi(argv[3]) ; inFileName = argv[4] ; outFileName = argv[5] ; flag = atoi(argv[6]) ; fprintf(msgFile, "\n readAIJ " "\n msglvl -- %d" "\n msgFile -- %s" "\n dataType -- %d" "\n inputFile -- %s" "\n outFile -- %s" "\n flag -- %d" "\n", msglvl, argv[2], dataType, inFileName, outFileName, flag) ; fflush(msgFile) ; /* ---------------------------- open the input file and read #rows #columns #entries ---------------------------- */ if ( (inputFile = fopen(inFileName, "r")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], inFileName) ; return(-1) ; } rc = fscanf(inputFile, "%d %d %d", &nrow, &ncol, &nent) ; if ( rc != 3 ) { fprintf(stderr, "\n fatal error in %s" "\n %d of 3 fields read on first line of file %s", argv[0], rc, inFileName) ; return(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n read in nrow = %d, ncol = %d, nent = %d", nrow, ncol, nent) ; fflush(msgFile) ; } /* -------------------------------------------------- initialize the object set coordType = INPMTX_BY_ROWS --> row coordinates set inputMode = dataType -------------------------------------------------- */ inpmtx = InpMtx_new() ; InpMtx_init(inpmtx, INPMTX_BY_ROWS, dataType, nent, 0) ; /* ------------------------------------------------- read in the entries and load them into the object ------------------------------------------------- */ ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; if ( INPMTX_IS_INDICES_ONLY(inpmtx) ) { for ( ient = 0 ; ient < nent ; ient++ ) { rc = fscanf(inputFile, "%d %d", ivec1 + ient, ivec2 + ient) ; if ( rc != 2 ) { fprintf(stderr, "\n fatal error in %s" "\n %d of 2 fields read on entry %d of file %s", argv[0], rc, ient, inFileName) ; return(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n entry %d, row %d, column %d", ient, ivec1[ient], ivec2[ient]) ; fflush(msgFile) ; } } } else if ( INPMTX_IS_REAL_ENTRIES(inpmtx) ) { double *dvec = InpMtx_dvec(inpmtx) ; for ( ient = 0 ; ient < nent ; ient++ ) { rc = fscanf(inputFile, "%d %d %le", ivec1 + ient, ivec2 + ient, dvec + ient) ; if ( rc != 3 ) { fprintf(stderr, "\n fatal error in %s" "\n %d of 3 fields read on entry %d of file %s", argv[0], rc, ient, argv[3]) ; return(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n entry %d, row %d, column %d, value %e", ient, ivec1[ient], ivec2[ient], dvec[ient]) ; fflush(msgFile) ; } } } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtx) ) { double *dvec = InpMtx_dvec(inpmtx) ; for ( ient = 0 ; ient < nent ; ient++ ) { rc = fscanf(inputFile, "%d %d %le %le", ivec1 + ient, ivec2 + ient, dvec + 2*ient, dvec + 2*ient+1) ; if ( rc != 4 ) { fprintf(stderr, "\n fatal error in %s" "\n %d of 4 fields read on entry %d of file %s", argv[0], rc, ient, argv[3]) ; return(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n entry %d, row %d, column %d, value %12.4e + %12.4e*i", ient, ivec1[ient], ivec2[ient], dvec[2*ient], dvec[2*ient+1]) ; fflush(msgFile) ; } } } inpmtx->nent = nent ; if ( flag == 1 ) { /* -------------------------------------------------- indices were in FORTRAN mode, decrement for C mode -------------------------------------------------- */ for ( ient = 0 ; ient < nent ; ient++ ) { ivec1[ient]-- ; ivec2[ient]-- ; } } /* ----------------------------- sort and compress the entries ----------------------------- */ InpMtx_changeStorageMode(inpmtx, 3) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n sorted, compressed and vector form") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; fflush(msgFile) ; } /* --------------------------- write out the InpMtx object --------------------------- */ if ( strcmp(outFileName, "none") != 0 ) { rc = InpMtx_writeToFile(inpmtx, outFileName) ; fprintf(msgFile, "\n return value %d from InpMtx_writeToFile(%p,%s)", rc, inpmtx, outFileName) ; } /* --------------------- free the working data --------------------- */ InpMtx_free(inpmtx) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/readAIJ2.c010064400020550007177000000103740665341252300164660ustar00clevecompmath00000400000006/* readAIJ.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------- read in Dave Young format construct a InpMtx object and write it out to a file created -- 97oct17, cca ------------------------------- */ { char *inFileName, *outFileName ; double ent ; InpMtx *inpmtx ; FILE *inputFile, *msgFile ; int icol, irow, jcol, jrow, msglvl, ncol, nentInRow, nrow, rc ; int *ivec1, *ivec2 ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : readAIJ2 msglvl msgFile inputFile outFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n inputFile -- input file for a(i,j) entries" "\n the first line must be \"nrow ncol \"" "\n next lines are \"irow nentInRow\"" "\n \"jcol entry \"" "\n ..." "\n \"jcol entry \"" "\n ..." "\n endif" "\n outFile -- output file, must be *.inpmtxf or *.inpmtxb" "\n") ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inFileName = argv[3] ; outFileName = argv[4] ; fprintf(msgFile, "\n readAIJ " "\n msglvl -- %d" "\n msgFile -- %s" "\n inputFile -- %s" "\n outFile -- %s" "\n", msglvl, argv[2], inFileName, outFileName ) ; fflush(msgFile) ; /* ---------------------------- open the input file and read #rows #columns ---------------------------- */ if ( (inputFile = fopen(inFileName, "r")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], inFileName) ; return(-1) ; } rc = fscanf(inputFile, "%d %d", &nrow, &ncol) ; if ( rc != 2 ) { fprintf(stderr, "\n fatal error in %s" "\n %d of 2 fields read on first line of file %s", argv[0], rc, inFileName) ; return(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n read in nrow = %d, ncol = %d", nrow, ncol) ; fflush(msgFile) ; } /* -------------------------------------------------- initialize the object set coordType = INPMTX_BY_ROWS --> row coordinates -------------------------------------------------- */ inpmtx = InpMtx_new() ; InpMtx_init(inpmtx, INPMTX_BY_ROWS, SPOOLES_REAL, 10*nrow, 0) ; /* ------------------------------------------------- read in the entries and load them into the object ------------------------------------------------- */ for ( irow = 0 ; irow < nrow ; irow++ ) { rc = fscanf(inputFile, "%d %d", &jrow, &nentInRow) ; if ( rc != 2 ) { fprintf(stderr, "\n fatal error in %s" "\n %d of 2 fields read on entry %d of file %s", argv[0], rc, irow, inFileName) ; return(-1) ; } for ( icol = 0 ; icol < nentInRow ; icol++ ) { rc = fscanf(inputFile, "%d %lf", &jcol, &ent) ; if ( rc != 2 ) { fprintf(stderr, "\n fatal error in %s" "\n %d of 2 fields read on entry %d of file %s", argv[0], rc, irow, inFileName) ; return(-1) ; } InpMtx_inputRealEntry(inpmtx, jrow-1, jcol-1, ent) ; } } /* ----------------------------- sort and compress the entries ----------------------------- */ InpMtx_changeStorageMode(inpmtx, 3) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n sorted, compressed and vector form") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; fflush(msgFile) ; } /* --------------------------- write out the InpMtx object --------------------------- */ if ( strcmp(outFileName, "none") != 0 ) { rc = InpMtx_writeToFile(inpmtx, outFileName) ; fprintf(msgFile, "\n return value %d from InpMtx_writeToFile(%p,%s)", rc, inpmtx, outFileName) ; } /* --------------------- free the working data --------------------- */ InpMtx_free(inpmtx) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/testExtract.c010064400020550007177000000263370661364753000174710ustar00clevecompmath00000400000006/* testExtract.c */ #include "../InpMtx.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------------ generate a random matrix and test the submatrix extraction method. the output is a matlab file to test correctness. created -- 98oct15, cca -------------------------------------------------------------------- */ { int coordType, dataType, ii, msglvl, ncolA, ncol1, ncol2, nitem, nrowA, nrow1, nrow2, rc, seed, symmetryflag ; int *colids, *rowids, *temp ; InpMtx *A ; IV *cols1IV, *cols2IV, *rows1IV, *rows2IV ; FILE *msgFile ; if ( argc != 14 ) { fprintf(stdout, "\n\n %% usage : %s msglvl msgFile dataType symmetryflag coordType " "\n %% nrowA ncolA nitem nrow1 nrow2 ncol1 ncol2 seed" "\n %% msglvl -- message level" "\n %% msgFile -- message file" "\n %% dataType -- type of matrix entries" "\n %% 1 -- real" "\n %% 2 -- complex" "\n %% symmetryflag -- type of matrix symmetry" "\n %% 0 -- symmetric" "\n %% 1 -- hermitian" "\n %% 2 -- nonsymmetric" "\n %% coordType -- coordinate Type" "\n %% 1 -- by rows" "\n %% 2 -- by columns" "\n %% 3 -- by chevrons" "\n %% nrowA -- number of rows in A" "\n %% ncolA -- number of columns in A" "\n %% nitem -- number of items to be loaded into A" "\n %% nrow1 -- number of rows in the first block" "\n %% nrow2 -- number of rows in the second block" "\n %% ncol1 -- number of columns in the first block" "\n %% ncol2 -- number of columns in the second block" "\n %% seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } dataType = atoi(argv[3]) ; symmetryflag = atoi(argv[4]) ; coordType = atoi(argv[5]) ; nrowA = atoi(argv[6]) ; ncolA = atoi(argv[7]) ; nitem = atoi(argv[8]) ; nrow1 = atoi(argv[9]) ; nrow2 = atoi(argv[10]) ; ncol1 = atoi(argv[11]) ; ncol2 = atoi(argv[12]) ; seed = atoi(argv[13]) ; fprintf(msgFile, "\n %% %s " "\n %% msglvl -- %d" "\n %% msgFile -- %s" "\n %% dataType -- %d" "\n %% symmetryflag -- %d" "\n %% coordType -- %d" "\n %% nrowA -- %d" "\n %% ncolA -- %d" "\n %% nitem -- %d" "\n %% nrow1 -- %d" "\n %% nrow2 -- %d" "\n %% ncol1 -- %d" "\n %% ncol2 -- %d" "\n %% seed -- %d" "\n", argv[0], msglvl, argv[2], dataType, symmetryflag, coordType, nrowA, ncolA, nitem, nrow1, nrow2, ncol1, ncol2, seed) ; fflush(msgFile) ; if ( dataType != SPOOLES_REAL && dataType != SPOOLES_COMPLEX ) { fprintf(stderr, "\n invalid value %d for dataType\n", dataType) ; exit(-1) ; } if ( symmetryflag != SPOOLES_SYMMETRIC && symmetryflag != SPOOLES_HERMITIAN && symmetryflag != SPOOLES_NONSYMMETRIC ) { fprintf(stderr, "\n invalid value %d for symmetryflag\n", symmetryflag) ; exit(-1) ; } if ( symmetryflag == SPOOLES_HERMITIAN && dataType != SPOOLES_COMPLEX ){ fprintf(stderr, "\n symmetryflag is hermitian, data type is not complex\n") ; exit(-1) ; } if ( coordType != INPMTX_BY_ROWS && coordType != INPMTX_BY_COLUMNS && coordType != INPMTX_BY_CHEVRONS ) { fprintf(stderr, "\n invalid value %d for coordType\n", coordType) ; exit(-1) ; } if ( nrowA <= 0 || ncolA <= 0 || nitem <= 0 ) { fprintf(stderr, "\n invalid value: nrow = %d, ncol = %d, nitem = %d", nrowA, ncolA, nitem) ; exit(-1) ; } fprintf(msgFile, "\n %% symmetryflag %d, nrowA %d, ncolA %d\n", symmetryflag, nrowA, ncolA) ; if ( ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN) && nrowA != ncolA ) { fprintf(stderr, "\n symmetric matrix, nrowA %d, ncolA %d\n", nrowA, ncolA) ; exit(-1) ; } if ( nrow1 < 0 || nrow2 < 0 || (nrow1 + nrow2 != nrowA) ) { fprintf(stderr, "\n invalid value: nrow = %d, nrow1 = %d, nrow2 = %d", nrowA, nrow1, nrow2) ; exit(-1) ; } if ( ncol1 < 0 || ncol2 < 0 || (ncol1 + ncol2 != ncolA) ) { fprintf(stderr, "\n invalid value: ncol = %d, ncol1 = %d, ncol2 = %d", ncolA, ncol1, ncol2) ; exit(-1) ; } /* ---------------------------- initialize the matrix object ---------------------------- */ A = InpMtx_new() ; rc = InpMtx_randomMatrix(A, dataType, coordType, INPMTX_BY_VECTORS, nrowA, ncolA, symmetryflag, 0, nitem, seed) ; /* ------------------------------------------- write the assembled matrix to a matlab file ------------------------------------------- */ fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowA, ncolA) ; InpMtx_writeForMatlab(A, "A", msgFile) ; if ( symmetryflag == SPOOLES_SYMMETRIC ) { fprintf(msgFile, "\n A = diag(diag(A)) + triu(A,1) + transpose(triu(A,1)) ;") ; } else if ( symmetryflag == SPOOLES_HERMITIAN ) { fprintf(msgFile, "\n A = diag(diag(A)) + triu(A,1) + ctranspose(triu(A,1)) ;") ; } /* ---------------------------------- generate row and column id vectors ---------------------------------- */ temp = IVinit(nrowA, -1) ; IVramp(nrowA, temp, 0, 1) ; IVshuffle(nrowA, temp, ++seed) ; if ( nrow1 > 0 ) { rows1IV = IV_new() ; IV_init(rows1IV, nrow1, NULL) ; IVqsortUp(nrow1, temp) ; IVcopy(nrow1, IV_entries(rows1IV), temp) ; } else { rows1IV = NULL ; } if ( nrow2 > 0 ) { rows2IV = IV_new() ; IV_init(rows2IV, nrow2, NULL) ; IVqsortUp(nrow2, temp + nrow1) ; IVcopy(nrow2, IV_entries(rows2IV), temp + nrow1) ; } else { rows2IV = NULL ; } IVfree(temp) ; if ( symmetryflag == SPOOLES_NONSYMMETRIC ) { temp = IVinit(ncolA, -1) ; IVramp(ncolA, temp, 0, 1) ; IVshuffle(ncolA, temp, ++seed) ; if ( ncol1 > 0 ) { cols1IV = IV_new() ; IV_init(cols1IV, ncol1, NULL) ; IVqsortUp(ncol1, temp) ; IVcopy(ncol1, IV_entries(cols1IV), temp) ; } else { cols1IV = NULL ; } if ( ncol2 > 0 ) { cols2IV = IV_new() ; IV_init(cols2IV, ncol2, NULL) ; IVqsortUp(ncol2, temp + ncol1) ; IVcopy(ncol2, IV_entries(cols2IV), temp + ncol1) ; } else { cols2IV = NULL ; } IVfree(temp) ; } else { if ( ncol1 > 0 ) { cols1IV = IV_new() ; IV_init(cols1IV, ncol1, NULL) ; IV_copy(cols1IV, rows1IV) ; } else { cols1IV = NULL ; } if ( ncol2 > 0 ) { cols2IV = IV_new() ; IV_init(cols2IV, ncol2, NULL) ; IV_copy(cols2IV, rows2IV) ; } else { cols2IV = NULL ; } } if ( nrow1 > 0 ) { fprintf(msgFile, "\n rows1 = zeros(%d,1) ;", nrow1) ; IV_writeForMatlab(rows1IV, "rows1", msgFile) ; } if ( nrow2 > 0 ) { fprintf(msgFile, "\n rows2 = zeros(%d,1) ;", nrow2) ; IV_writeForMatlab(rows2IV, "rows2", msgFile) ; } if ( ncol1 > 0 ) { fprintf(msgFile, "\n cols1 = zeros(%d,1) ;", ncol1) ; IV_writeForMatlab(cols1IV, "cols1", msgFile) ; } if ( ncol2 > 0 ) { fprintf(msgFile, "\n cols2 = zeros(%d,1) ;", ncol2) ; IV_writeForMatlab(cols2IV, "cols2", msgFile) ; } /* ----------------------- extract the submatrices ----------------------- */ if ( nrow1 > 0 ) { if ( ncol1 > 0 ) { InpMtx *A11 = InpMtx_new() ; rc = InpMtx_initFromSubmatrix(A11, A, rows1IV, cols1IV, symmetryflag, msglvl, msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d for A11\n", rc) ; exit(-1) ; } fprintf(msgFile, "\n A11 = zeros(%d,%d) ;", nrow1, ncol1) ; InpMtx_writeForMatlab(A11, "A11", msgFile) ; if ( symmetryflag == SPOOLES_SYMMETRIC ) { fprintf(msgFile, "\n A11 = diag(diag(A11)) + triu(A11,1) + transpose(triu(A11,1)) ;") ; } else if ( symmetryflag == SPOOLES_HERMITIAN ) { fprintf(msgFile, "\n A11 = diag(diag(A11)) + triu(A11,1) + ctranspose(triu(A11,1)) ;") ; } fprintf(msgFile, "\n err11 = max(max(abs(A11 - A(rows1,cols1)))) ;") ; InpMtx_free(A11) ; } else { fprintf(msgFile, "\n err11 = 0 ;") ; } if ( ncol2 > 0 ) { InpMtx *A12 = InpMtx_new() ; rc = InpMtx_initFromSubmatrix(A12, A, rows1IV, cols2IV, symmetryflag, msglvl, msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d for A12\n", rc) ; exit(-1) ; } fprintf(msgFile, "\n A12 = zeros(%d,%d) ;", nrow1, ncol2) ; InpMtx_writeForMatlab(A12, "A12", msgFile) ; fprintf(msgFile, "\n err12 = max(max(abs(A12 - A(rows1,cols2)))) ;") ; InpMtx_free(A12) ; } else { fprintf(msgFile, "\n err12 = 0 ;") ; } } else { fprintf(msgFile, "\n err11 = 0 ;") ; fprintf(msgFile, "\n err12 = 0 ;") ; } if ( nrow2 > 0 ) { if ( ncol1 > 0 ) { InpMtx *A21 = InpMtx_new() ; rc = InpMtx_initFromSubmatrix(A21, A, rows2IV, cols1IV, symmetryflag, msglvl, msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d for A21\n", rc) ; exit(-1) ; } fprintf(msgFile, "\n A21 = zeros(%d,%d) ;", nrow2, ncol1) ; InpMtx_writeForMatlab(A21, "A21", msgFile) ; fprintf(msgFile, "\n err21 = max(max(abs(A21 - A(rows2,cols1)))) ;") ; InpMtx_free(A21) ; } else { fprintf(msgFile, "\n err21 = 0 ;") ; } if ( ncol2 > 0 ) { InpMtx *A22 = InpMtx_new() ; rc = InpMtx_initFromSubmatrix(A22, A, rows2IV, cols2IV, symmetryflag, msglvl, msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d for A22\n", rc) ; exit(-1) ; } fprintf(msgFile, "\n A22 = zeros(%d,%d) ;", nrow2, ncol2) ; InpMtx_writeForMatlab(A22, "A22", msgFile) ; if ( symmetryflag == SPOOLES_SYMMETRIC ) { fprintf(msgFile, "\n A22 = diag(diag(A22)) + triu(A22,1) + transpose(triu(A22,1)) ;") ; } else if ( symmetryflag == SPOOLES_HERMITIAN ) { fprintf(msgFile, "\n A22 = diag(diag(A22)) + triu(A22,1) + ctranspose(triu(A22,1)) ;") ; } fprintf(msgFile, "\n err22 = max(max(abs(A22 - A(rows2,cols2)))) ;") ; InpMtx_free(A22) ; } else { fprintf(msgFile, "\n err22 = 0 ;") ; } } else { fprintf(msgFile, "\n err21 = 0 ;") ; fprintf(msgFile, "\n err22 = 0 ;") ; } fprintf(msgFile, "\n error = [ err11 err12 ; err21 err22 ] ") ; /* ------------------------ free the working storage ------------------------ */ InpMtx_free(A) ; if ( rows1IV != NULL ) { IV_free(rows1IV) ; } if ( rows2IV != NULL ) { IV_free(rows2IV) ; } if ( cols1IV != NULL ) { IV_free(cols1IV) ; } if ( cols2IV != NULL ) { IV_free(cols2IV) ; } fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ riteForMatlab(A, "A", msgFile) ; if ( symmetryflag == SPOOLES_SYMMETRIC ) { fprintf(msgFile, "\n A = diag(diag(A)) + triu(A,1) + transpose(triu(A,1)) ;") ; } else if ( symmetryflag == SPOOLES_HERMITIAN ) { fprintf(msgFile, "\n A = diag(diag(A)) + triu(A,1) + ctrInpMtx/drivers/testFullAdj.c010064400020550007177000000112610662263576000173700ustar00clevecompmath00000400000006/* testFullAdj.c */ #include "../InpMtx.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- generate a random InpMtx object for a matrix A and return an IVL object with the structure of A + A^T created -- 97nov05, cca --------------------------------------------------- */ { Drand *drand ; int msglvl, ient, ii, irow, isHere, jcol, nent, nedgesMissing, nvtx, seed, size ; int *colids, *list, *rowids ; InpMtx *inpmtxA ; FILE *msgFile ; IVL *adjIVL ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : testFullAdj msglvl msgFile nvtx nent seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n nvtx -- number of rows and columns" "\n nent -- bound on number of entries" "\n seed -- random number seed" "\n") ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } nvtx = atoi(argv[3]) ; nent = atoi(argv[4]) ; seed = atoi(argv[5]) ; fprintf(msgFile, "\n testIO " "\n msglvl -- %d" "\n msgFile -- %s" "\n nvtx -- %d" "\n nent -- %d" "\n seed -- %d" "\n", msglvl, argv[2], nvtx, nent, seed) ; fflush(msgFile) ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_setSeed(drand, seed) ; Drand_setUniform(drand, 0, nvtx) ; /* ----------------------------------- initialize the InpMtx object for A ----------------------------------- */ inpmtxA = InpMtx_new() ; InpMtx_init(inpmtxA, INPMTX_BY_ROWS, INPMTX_INDICES_ONLY, nent, nvtx) ; /* ---------------------- load with random edges ---------------------- */ rowids = IVinit(nent, -1) ; colids = IVinit(nent, -1) ; Drand_fillIvector(drand, nent, rowids) ; Drand_fillIvector(drand, nent, colids) ; for ( ient = 0 ; ient < nent ; ient++ ) { irow = rowids[ient] ; jcol = colids[ient] ; if ( msglvl > 0 ) { fprintf(msgFile, "\n loading (%5d,%5d)", irow, jcol) ; fflush(msgFile) ; } InpMtx_inputEntry(inpmtxA, irow, jcol) ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n after loading raw data") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------- sort, compress and change to vector form ---------------------------------------- */ InpMtx_sortAndCompress(inpmtxA) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n after sort and compress") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } InpMtx_convertToVectors(inpmtxA) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n after convert to vectors") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------- get the full adjacency structure of A + A^T ------------------------------------------- */ adjIVL = InpMtx_fullAdjacency(inpmtxA) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n full adjacency IVL object") ; IVL_writeForHumanEye(adjIVL, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------------------- check that each (irow,jcol) is in the full adjacency ---------------------------------------------------- */ for ( ient = 0, nedgesMissing = 0 ; ient < nent ; ient++ ) { irow = rowids[ient] ; jcol = colids[ient] ; IVL_listAndSize(adjIVL, irow, &size, &list) ; for ( ii = 0, isHere = 0 ; ii < size ; ii++ ) { if ( list[ii] == jcol ) { isHere = 1 ; break ; } } if ( isHere != 1 ) { fprintf(stderr, "\n fatal error, (%d,%d) not in adjIVL", irow, jcol) ; nedgesMissing++ ; } IVL_listAndSize(adjIVL, jcol, &size, &list) ; for ( ii = 0, isHere = 0 ; ii < size ; ii++ ) { if ( list[ii] == irow ) { isHere = 1 ; break ; } } if ( isHere != 1 ) { fprintf(stderr, "\n fatal error, (%d,%d) not in adjIVL", irow, jcol) ; nedgesMissing++ ; } } fprintf(msgFile, "\n %d edges missing from adjIVL", nedgesMissing) ; /* ------------- free the data ------------- */ IVfree(colids) ; IVfree(rowids) ; InpMtx_free(inpmtxA) ; IVL_free(adjIVL) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ "\n\n usage : testFullAdj msglvl msgFile nvtx nent seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n nvtx -- number of rows and columns" "\n nent -- bound on number of entries" "\n seed -- random number seed" "\n") ; return(0) ; } msglvl = atoi(argv[1])InpMtx/drivers/testFullAdj2.c010064400020550007177000000166460657403461500174640ustar00clevecompmath00000400000006/* testFullAdj2.c */ #include "../InpMtx.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------------------------- generate random InpMtx object for matrices A and B return an IVL object with the structure of (A+B) + (A+B)^T created -- 97nov05, cca ---------------------------------------------------------- */ { Drand *drand ; int msglvl, ient, ii, irow, isHere, jcol, nedgesMissing, nentA, nentB, nvtx, seed, size ; int *colidsA, *colidsB, *list, *rowidsA, *rowidsB ; InpMtx *inpmtxA, *inpmtxB ; FILE *msgFile ; IVL *adjIVL ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : testFullAdj2 msglvl msgFile nvtx nentA nentB seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n nvtx -- number of rows and columns" "\n nentA -- bound on number of entries in A" "\n nentB -- bound on number of entries in B" "\n seed -- random number seed" "\n") ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } nvtx = atoi(argv[3]) ; nentA = atoi(argv[4]) ; nentB = atoi(argv[5]) ; seed = atoi(argv[6]) ; fprintf(msgFile, "\n testIO " "\n msglvl -- %d" "\n msgFile -- %s" "\n nvtx -- %d" "\n nentA -- %d" "\n nentB -- %d" "\n seed -- %d" "\n", msglvl, argv[2], nvtx, nentA, nentB, seed) ; fflush(msgFile) ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_setSeed(drand, seed) ; Drand_setUniform(drand, 0, nvtx) ; /* ----------------------------------- initialize the InpMtx object for A ----------------------------------- */ inpmtxA = InpMtx_new() ; InpMtx_init(inpmtxA, INPMTX_BY_ROWS, INPMTX_INDICES_ONLY, nentA, nvtx) ; /* ---------------------- load with random edges ---------------------- */ rowidsA = IVinit(nentA, -1) ; colidsA = IVinit(nentA, -1) ; Drand_fillIvector(drand, nentA, rowidsA) ; Drand_fillIvector(drand, nentA, colidsA) ; for ( ient = 0 ; ient < nentA ; ient++ ) { irow = rowidsA[ient] ; jcol = colidsA[ient] ; if ( msglvl > 0 ) { fprintf(msgFile, "\n loading (%5d,%5d)", irow, jcol) ; fflush(msgFile) ; } InpMtx_inputEntry(inpmtxA, irow, jcol) ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n after loading raw data") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------- sort, compress and change to vector form ---------------------------------------- */ InpMtx_sortAndCompress(inpmtxA) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n after sort and compress") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } InpMtx_convertToVectors(inpmtxA) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n after convert to vectors") ; InpMtx_writeForHumanEye(inpmtxA, msgFile) ; fflush(msgFile) ; } /* ----------------------------------- initialize the InpMtx object for B ----------------------------------- */ inpmtxB = InpMtx_new() ; InpMtx_init(inpmtxB, INPMTX_BY_ROWS, INPMTX_INDICES_ONLY, nentB, nvtx) ; /* ---------------------- load with random edges ---------------------- */ rowidsB = IVinit(nentB, -1) ; colidsB = IVinit(nentB, -1) ; Drand_fillIvector(drand, nentB, rowidsB) ; Drand_fillIvector(drand, nentB, colidsB) ; for ( ient = 0 ; ient < nentB ; ient++ ) { irow = rowidsB[ient] ; jcol = colidsB[ient] ; if ( msglvl > 0 ) { fprintf(msgFile, "\n loading (%5d,%5d)", irow, jcol) ; fflush(msgFile) ; } InpMtx_inputEntry(inpmtxB, irow, jcol) ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n after loading raw data") ; InpMtx_writeForHumanEye(inpmtxB, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------- sort, compress and change to vector form ---------------------------------------- */ InpMtx_sortAndCompress(inpmtxB) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n after sort and compress") ; InpMtx_writeForHumanEye(inpmtxB, msgFile) ; fflush(msgFile) ; } InpMtx_convertToVectors(inpmtxB) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n after convert to vectors") ; InpMtx_writeForHumanEye(inpmtxB, msgFile) ; fflush(msgFile) ; } /* --------------------------------------------------- get the full adjacency structure of (A+B) + (A+B)^T --------------------------------------------------- */ fprintf(msgFile, "\n inpmtxA = %p, inpmtxB = %p", inpmtxA, inpmtxB) ; adjIVL = InpMtx_fullAdjacency2(inpmtxA, inpmtxB) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n full adjacency IVL object") ; IVL_writeForHumanEye(adjIVL, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------------------------- check that each (irow,jcol) from A is in the full adjacency ----------------------------------------------------------- */ for ( ient = 0, nedgesMissing = 0 ; ient < nentA ; ient++ ) { irow = rowidsA[ient] ; jcol = colidsA[ient] ; IVL_listAndSize(adjIVL, irow, &size, &list) ; for ( ii = 0, isHere = 0 ; ii < size ; ii++ ) { if ( list[ii] == jcol ) { isHere = 1 ; break ; } } if ( isHere != 1 ) { fprintf(stderr, "\n fatal error, (%d,%d) not in adjIVL", irow, jcol) ; nedgesMissing++ ; } IVL_listAndSize(adjIVL, jcol, &size, &list) ; for ( ii = 0, isHere = 0 ; ii < size ; ii++ ) { if ( list[ii] == irow ) { isHere = 1 ; break ; } } if ( isHere != 1 ) { fprintf(stderr, "\n fatal error, (%d,%d) not in adjIVL", irow, jcol) ; nedgesMissing++ ; } } fprintf(msgFile, "\n %d edges of A missing from adjIVL", nedgesMissing) ; /* ----------------------------------------------------------- check that each (irow,jcol) from B is in the full adjacency ----------------------------------------------------------- */ for ( ient = 0, nedgesMissing = 0 ; ient < nentB ; ient++ ) { irow = rowidsB[ient] ; jcol = colidsB[ient] ; IVL_listAndSize(adjIVL, irow, &size, &list) ; for ( ii = 0, isHere = 0 ; ii < size ; ii++ ) { if ( list[ii] == jcol ) { isHere = 1 ; break ; } } if ( isHere != 1 ) { fprintf(stderr, "\n fatal error, (%d,%d) not in adjIVL", irow, jcol) ; nedgesMissing++ ; } IVL_listAndSize(adjIVL, jcol, &size, &list) ; for ( ii = 0, isHere = 0 ; ii < size ; ii++ ) { if ( list[ii] == irow ) { isHere = 1 ; break ; } } if ( isHere != 1 ) { fprintf(stderr, "\n fatal error, (%d,%d) not in adjIVL", irow, jcol) ; nedgesMissing++ ; } } fprintf(msgFile, "\n %d edges of B missing from adjIVL", nedgesMissing) ; /* ------------- free the data ------------- */ IVfree(colidsA) ; IVfree(rowidsA) ; InpMtx_free(inpmtxA) ; IVfree(colidsB) ; IVfree(rowidsB) ; InpMtx_free(inpmtxB) ; IVL_free(adjIVL) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/testGMMM.c010064400020550007177000000205240665341614200166010ustar00clevecompmath00000400000006/* testGMMM.c */ #include "../InpMtx.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------ generate a random matrix and test the InpMtx_*_gmmm*() matrix-matrix multiply methods. the output is a matlab file to test correctness. created -- 98nov14, cca ------------------------------------------------------ */ { DenseMtx *X, *Y ; double alpha[2], beta[2] ; double alphaImag, alphaReal, betaImag, betaReal ; Drand *drand ; int dataType, msglvl, ncolA, nitem, nrhs, nrowA, nrowX, nrowY, seed, coordType, rc, symflag, transposeflag ; InpMtx *A ; FILE *msgFile ; if ( argc != 16 ) { fprintf(stdout, "\n\n %% usage : %s msglvl msgFile symflag coordType transpose" "\n %% nrow ncol nent nrhs seed " "\n %% alphaReal alphaImag betaReal betaImag" "\n %% msglvl -- message level" "\n %% msgFile -- message file" "\n %% dataType -- type of matrix entries" "\n %% 1 -- real" "\n %% 2 -- complex" "\n %% symflag -- symmetry flag" "\n %% 0 -- symmetric" "\n %% 1 -- hermitian" "\n %% 2 -- nonsymmetric" "\n %% coordType -- storage mode" "\n %% 1 -- by rows" "\n %% 2 -- by columns" "\n %% 3 -- by chevrons, (requires nrow = ncol)" "\n %% transpose -- transpose flag" "\n %% 0 -- Y := beta * Y + alpha * A * X" "\n %% 1 -- Y := beta * Y + alpha * A^H * X, nonsymmetric only" "\n %% 2 -- Y := beta * Y + alpha * A^T * X, nonsymmetric only" "\n %% nrowA -- number of rows in A" "\n %% ncolA -- number of columns in A" "\n %% nitem -- number of items" "\n %% nrhs -- number of right hand sides" "\n %% seed -- random number seed" "\n %% alphaReal -- y := beta*y + alpha*A*x" "\n %% alphaImag -- y := beta*y + alpha*A*x" "\n %% betaReal -- y := beta*y + alpha*A*x" "\n %% betaImag -- y := beta*y + alpha*A*x" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } dataType = atoi(argv[3]) ; symflag = atoi(argv[4]) ; coordType = atoi(argv[5]) ; transposeflag = atoi(argv[6]) ; nrowA = atoi(argv[7]) ; ncolA = atoi(argv[8]) ; nitem = atoi(argv[9]) ; nrhs = atoi(argv[10]) ; seed = atoi(argv[11]) ; alphaReal = atof(argv[12]) ; alphaImag = atof(argv[13]) ; betaReal = atof(argv[14]) ; betaImag = atof(argv[15]) ; fprintf(msgFile, "\n %% %s " "\n %% msglvl -- %d" "\n %% msgFile -- %s" "\n %% dataType -- %d" "\n %% symflag -- %d" "\n %% coordType -- %d" "\n %% transposeflag -- %d" "\n %% nrowA -- %d" "\n %% ncolA -- %d" "\n %% nitem -- %d" "\n %% nrhs -- %d" "\n %% seed -- %d" "\n %% alphaReal -- %e" "\n %% alphaImag -- %e" "\n %% betaReal -- %e" "\n %% betaImag -- %e" "\n", argv[0], msglvl, argv[2], dataType, symflag, coordType, transposeflag, nrowA, ncolA, nitem, nrhs, seed, alphaReal, alphaImag, betaReal, betaImag) ; fflush(msgFile) ; if ( dataType != 1 && dataType != 2 ) { fprintf(stderr, "\n invalid value %d for dataType\n", dataType) ; exit(-1) ; } if ( symflag != 0 && symflag != 1 && symflag != 2 ) { fprintf(stderr, "\n invalid value %d for symflag\n", symflag) ; exit(-1) ; } if ( coordType != 1 && coordType != 2 && coordType != 3 ) { fprintf(stderr, "\n invalid value %d for coordType\n", coordType) ; exit(-1) ; } if ( transposeflag < 0 || transposeflag > 2 ) { fprintf(stderr, "\n error, transposeflag = %d, must be 0, 1 or 2", transposeflag) ; exit(-1) ; } if ( (transposeflag == 1 && symflag != 2) || (transposeflag == 2 && symflag != 2) ) { fprintf(stderr, "\n error, transposeflag = %d, symflag = %d", transposeflag, symflag) ; exit(-1) ; } if ( transposeflag == 1 && dataType != 2 ) { fprintf(stderr, "\n error, transposeflag = %d, dataType = %d", transposeflag, dataType) ; exit(-1) ; } if ( symflag == 1 && dataType != 2 ) { fprintf(stderr, "\n symflag = 1 (hermitian), dataType != 2 (complex)") ; exit(-1) ; } if ( nrowA <= 0 || ncolA <= 0 || nitem <= 0 ) { fprintf(stderr, "\n invalid value: nrow = %d, ncol = %d, nitem = %d", nrowA, ncolA, nitem) ; exit(-1) ; } if ( symflag < 2 && nrowA != ncolA ) { fprintf(stderr, "\n invalid data: symflag = %d, nrow = %d, ncol = %d", symflag, nrowA, ncolA) ; exit(-1) ; } alpha[0] = alphaReal ; alpha[1] = alphaImag ; beta[0] = betaReal ; beta[1] = betaImag ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; Drand_setUniform(drand, -1.0, 1.0) ; /* ---------------------------- initialize the matrix object and fill with random entries ---------------------------- */ A = InpMtx_new() ; InpMtx_init(A, coordType, dataType, 0, 0) ; rc = InpMtx_randomMatrix(A, dataType, coordType, INPMTX_BY_VECTORS, nrowA, ncolA, symflag, 1, nitem, seed) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from InpMtx_randomMatrix()", rc); exit(-1) ; } /* ------------------------------------------- write the assembled matrix to a matlab file ------------------------------------------- */ InpMtx_writeForMatlab(A, "A", msgFile) ; if ( symflag == 0 ) { fprintf(msgFile, "\n for k = 1:%d" "\n for j = k+1:%d" "\n A(j,k) = A(k,j) ;" "\n end" "\n end", nrowA, ncolA) ; } else if ( symflag == 1 ) { fprintf(msgFile, "\n for k = 1:%d" "\n for j = k+1:%d" "\n A(j,k) = ctranspose(A(k,j)) ;" "\n end" "\n end", nrowA, ncolA) ; } /* ------------------------------- generate dense matrices X and Y ------------------------------- */ if ( transposeflag == 0 ) { nrowX = ncolA ; nrowY = nrowA ; } else { nrowX = nrowA ; nrowY = ncolA ; } X = DenseMtx_new() ; Y = DenseMtx_new() ; DenseMtx_init(X, dataType, 0, 0, nrowX, nrhs, 1, nrowX) ; DenseMtx_fillRandomEntries(X, drand) ; DenseMtx_init(Y, dataType, 0, 0, nrowY, nrhs, 1, nrowY) ; DenseMtx_fillRandomEntries(Y, drand) ; fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, nrhs) ; DenseMtx_writeForMatlab(X, "X", msgFile) ; fprintf(msgFile, "\n Y = zeros(%d,%d) ;", nrowY, nrhs) ; DenseMtx_writeForMatlab(Y, "Y", msgFile) ; /* ---------------------------------- perform the matrix-matrix multiply ---------------------------------- */ fprintf(msgFile, "\n beta = %20.12e + %20.2e*i;", beta[0], beta[1]); fprintf(msgFile, "\n alpha = %20.12e + %20.2e*i;", alpha[0], alpha[1]); fprintf(msgFile, "\n Z = zeros(%d,1) ;", nrowY) ; if ( transposeflag == 0 ) { if ( symflag == 0 ) { InpMtx_sym_gmmm(A, beta, Y, alpha, X) ; } else if ( symflag == 1 ) { InpMtx_herm_gmmm(A, beta, Y, alpha, X) ; } else if ( symflag == 2 ) { InpMtx_nonsym_gmmm(A, beta, Y, alpha, X) ; } DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - beta*Y - alpha*A*X) ") ; fprintf(msgFile, "\n") ; } else if ( transposeflag == 1 ) { InpMtx_nonsym_gmmm_H(A, beta, Y, alpha, X) ; DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - beta*Y - alpha*ctranspose(A)*X) ") ; fprintf(msgFile, "\n") ; } else if ( transposeflag == 2 ) { InpMtx_nonsym_gmmm_T(A, beta, Y, alpha, X) ; DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - beta*Y - alpha*transpose(A)*X) ") ; fprintf(msgFile, "\n") ; } /* ------------------------ free the working storage ------------------------ */ InpMtx_free(A) ; DenseMtx_free(X) ; DenseMtx_free(Y) ; Drand_free(drand) ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/testGMVM.c010064400020550007177000000205000665341614700166110ustar00clevecompmath00000400000006/* testGMVM.c */ #include "../InpMtx.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------ generate a random matrix and test the InpMtx_*_gmvm*() matrix-matrix multiply methods. the output is a matlab file to test correctness. created -- 98nov14, cca ------------------------------------------------------ */ { DenseMtx *X, *Y ; double alpha[2], beta[2] ; double alphaImag, alphaReal, betaImag, betaReal ; double *x, *y ; Drand *drand ; int dataType, msglvl, ncolA, nitem, nrowA, nrowX, nrowY, seed, coordType, rc, symflag, transposeflag ; InpMtx *A ; FILE *msgFile ; if ( argc != 15 ) { fprintf(stdout, "\n\n %% usage : %s msglvl msgFile symflag coordType " "\n %% nrow ncol nent seed " "\n %% alphaReal alphaImag betaReal betaImag" "\n %% msglvl -- message level" "\n %% msgFile -- message file" "\n %% dataType -- type of matrix entries" "\n %% 1 -- real" "\n %% 2 -- complex" "\n %% symflag -- symmetry flag" "\n %% 0 -- symmetric" "\n %% 1 -- hermitian" "\n %% 2 -- nonsymmetric" "\n %% coordType -- storage mode" "\n %% 1 -- by rows" "\n %% 2 -- by columns" "\n %% 3 -- by chevrons, (requires nrow = ncol)" "\n %% transpose -- transpose flag" "\n %% 0 -- Y := beta * Y + alpha * A * X" "\n %% 1 -- Y := beta * Y + alpha * A^H * X, nonsymmetric only" "\n %% 2 -- Y := beta * Y + alpha * A^T * X, nonsymmetric only" "\n %% nrowA -- number of rows in A" "\n %% ncolA -- number of columns in A" "\n %% nitem -- number of items" "\n %% seed -- random number seed" "\n %% alphaReal -- y := beta*y + alpha*A*x" "\n %% alphaImag -- y := beta*y + alpha*A*x" "\n %% betaReal -- y := beta*y + alpha*A*x" "\n %% betaImag -- y := beta*y + alpha*A*x" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } dataType = atoi(argv[3]) ; symflag = atoi(argv[4]) ; coordType = atoi(argv[5]) ; transposeflag = atoi(argv[6]) ; nrowA = atoi(argv[7]) ; ncolA = atoi(argv[8]) ; nitem = atoi(argv[9]) ; seed = atoi(argv[10]) ; alphaReal = atof(argv[11]) ; alphaImag = atof(argv[12]) ; betaReal = atof(argv[13]) ; betaImag = atof(argv[14]) ; fprintf(msgFile, "\n %% %s " "\n %% msglvl -- %d" "\n %% msgFile -- %s" "\n %% dataType -- %d" "\n %% symflag -- %d" "\n %% coordType -- %d" "\n %% transposeflag -- %d" "\n %% nrowA -- %d" "\n %% ncolA -- %d" "\n %% nitem -- %d" "\n %% seed -- %d" "\n %% alphaReal -- %e" "\n %% alphaImag -- %e" "\n %% betaReal -- %e" "\n %% betaImag -- %e" "\n", argv[0], msglvl, argv[2], dataType, symflag, coordType, transposeflag, nrowA, ncolA, nitem, seed, alphaReal, alphaImag, betaReal, betaImag) ; fflush(msgFile) ; if ( dataType != 1 && dataType != 2 ) { fprintf(stderr, "\n invalid value %d for dataType\n", dataType) ; exit(-1) ; } if ( symflag != 0 && symflag != 1 && symflag != 2 ) { fprintf(stderr, "\n invalid value %d for symflag\n", symflag) ; exit(-1) ; } if ( coordType != 1 && coordType != 2 && coordType != 3 ) { fprintf(stderr, "\n invalid value %d for coordType\n", coordType) ; exit(-1) ; } if ( transposeflag < 0 || transposeflag > 2 ) { fprintf(stderr, "\n error, transposeflag = %d, must be 0, 1 or 2", transposeflag) ; exit(-1) ; } if ( (transposeflag == 1 && symflag != 2) || (transposeflag == 2 && symflag != 2) ) { fprintf(stderr, "\n error, transposeflag = %d, symflag = %d", transposeflag, symflag) ; exit(-1) ; } if ( transposeflag == 1 && dataType != 2 ) { fprintf(stderr, "\n error, transposeflag = %d, dataType = %d", transposeflag, dataType) ; exit(-1) ; } if ( symflag == 1 && dataType != 2 ) { fprintf(stderr, "\n symflag = 1 (hermitian), dataType != 2 (complex)") ; exit(-1) ; } if ( nrowA <= 0 || ncolA <= 0 || nitem <= 0 ) { fprintf(stderr, "\n invalid value: nrow = %d, ncol = %d, nitem = %d", nrowA, ncolA, nitem) ; exit(-1) ; } if ( symflag < 2 && nrowA != ncolA ) { fprintf(stderr, "\n invalid data: symflag = %d, nrow = %d, ncol = %d", symflag, nrowA, ncolA) ; exit(-1) ; } alpha[0] = alphaReal ; alpha[1] = alphaImag ; beta[0] = betaReal ; beta[1] = betaImag ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; Drand_setUniform(drand, -1.0, 1.0) ; /* ---------------------------- initialize the matrix object and fill with random entries ---------------------------- */ A = InpMtx_new() ; InpMtx_init(A, coordType, dataType, 0, 0) ; rc = InpMtx_randomMatrix(A, dataType, coordType, INPMTX_BY_VECTORS, nrowA, ncolA, symflag, 1, nitem, seed) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from InpMtx_randomMatrix()", rc); exit(-1) ; } /* ------------------------------------------- write the assembled matrix to a matlab file ------------------------------------------- */ InpMtx_writeForMatlab(A, "A", msgFile) ; if ( symflag == 0 ) { fprintf(msgFile, "\n for k = 1:%d" "\n for j = k+1:%d" "\n A(j,k) = A(k,j) ;" "\n end" "\n end", nrowA, ncolA) ; } else if ( symflag == 1 ) { fprintf(msgFile, "\n for k = 1:%d" "\n for j = k+1:%d" "\n A(j,k) = ctranspose(A(k,j)) ;" "\n end" "\n end", nrowA, ncolA) ; } /* ------------------------------- generate dense matrices X and Y ------------------------------- */ if ( transposeflag == 0 ) { nrowX = ncolA ; nrowY = nrowA ; } else { nrowX = nrowA ; nrowY = ncolA ; } X = DenseMtx_new() ; Y = DenseMtx_new() ; DenseMtx_init(X, dataType, 0, 0, nrowX, 1, 1, nrowX) ; DenseMtx_fillRandomEntries(X, drand) ; DenseMtx_init(Y, dataType, 0, 0, nrowY, 1, 1, nrowY) ; DenseMtx_fillRandomEntries(Y, drand) ; fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, 1) ; DenseMtx_writeForMatlab(X, "X", msgFile) ; fprintf(msgFile, "\n Y = zeros(%d,%d) ;", nrowY, 1) ; DenseMtx_writeForMatlab(Y, "Y", msgFile) ; x = DenseMtx_entries(X) ; y = DenseMtx_entries(Y) ; /* ---------------------------------- perform the matrix-matrix multiply ---------------------------------- */ fprintf(msgFile, "\n beta = %20.12e + %20.2e*i;", beta[0], beta[1]); fprintf(msgFile, "\n alpha = %20.12e + %20.2e*i;", alpha[0], alpha[1]); fprintf(msgFile, "\n Z = zeros(%d,1) ;", nrowY) ; if ( transposeflag == 0 ) { if ( symflag == 0 ) { InpMtx_sym_gmvm(A, beta, nrowY, y, alpha, nrowX, x) ; } else if ( symflag == 1 ) { InpMtx_herm_gmvm(A, beta, nrowY, y, alpha, nrowX, x) ; } else if ( symflag == 2 ) { InpMtx_nonsym_gmvm(A, beta, nrowY, y, alpha, nrowX, x) ; } DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - beta*Y - alpha*A*X) ") ; fprintf(msgFile, "\n") ; } else if ( transposeflag == 1 ) { InpMtx_nonsym_gmvm_H(A, beta, nrowY, y, alpha, nrowX, x) ; DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - beta*Y - alpha*ctranspose(A)*X) ") ; fprintf(msgFile, "\n") ; } else if ( transposeflag == 2 ) { InpMtx_nonsym_gmvm_T(A, beta, nrowY, y, alpha, nrowX, x) ; DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - beta*Y - alpha*transpose(A)*X) ") ; fprintf(msgFile, "\n") ; } /* ------------------------ free the working storage ------------------------ */ InpMtx_free(A) ; DenseMtx_free(X) ; DenseMtx_free(Y) ; Drand_free(drand) ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/testHBIO.c010064400020550007177000000126110657623276200165730ustar00clevecompmath00000400000006/* testHBIO.c */ #include "../../misc.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- read in a Harwell-Boeing matrix, convert to a InpMtx object and write to a file. created -- 98sep11, cca --------------------------------------------------- */ { char *inFileName, *outFileName, *type ; double t1, t2 ; double *values ; int ierr, ii, iiend, iistart, inputMode, jcol, msglvl, ncol, nnonzeros, nrhs, nrow, rc ; int *colptr, *colind, *rowind ; InpMtx *inpmtx ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be Harwell-Boeing format" "\n outFile -- output file, must be *.inpmtxf or *.inpmtxb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inFileName = argv[3] ; outFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inFileName, outFileName) ; fflush(msgFile) ; /* --------------------------------------------- read in the Harwell-Boeing matrix information --------------------------------------------- */ if ( strcmp(inFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; readHB_info(inFileName, &nrow, &ncol, &nnonzeros, &type, &nrhs) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in information", t2 - t1) ; fprintf(msgFile, "\n matrix is %d x %d with %d entries, type = %s, nrhs = %d", nrow, ncol, nnonzeros, type, nrhs) ; fflush(msgFile) ; switch ( type[0] ) { case 'P' : inputMode = INPMTX_INDICES_ONLY ; break ; case 'R' : inputMode = SPOOLES_REAL ; break ; case 'C' : inputMode = SPOOLES_COMPLEX ; break ; default : fprintf(stderr, "\n fatal error in %s, type = %s" "\n first character must be 'P', 'R' or 'C'", argv[0], type) ; exit(-1) ; break ; } FREE(type) ; /* ----------------------------- initialize the InpMtx object ----------------------------- */ MARKTIME(t1) ; inpmtx = InpMtx_new() ; InpMtx_init(inpmtx, INPMTX_BY_COLUMNS, inputMode, nnonzeros, 0) ; colptr = IVinit(ncol+1, -1) ; colind = InpMtx_ivec1(inpmtx) ; rowind = InpMtx_ivec2(inpmtx) ; values = InpMtx_dvec(inpmtx) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize InpMtx object", t2 - t1) ; /* ------------------------------- read in the indices and entries ------------------------------- */ MARKTIME(t1) ; readHB_mat_double(inFileName, colptr, rowind, values) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in matrix entries", t2 - t1) ; /* -------------------------------------------- decrement the column offsets and row indices -------------------------------------------- */ MARKTIME(t1) ; for ( jcol = 0 ; jcol <= ncol ; jcol++ ) { colptr[jcol]-- ; } for ( ii = 0 ; ii < nnonzeros ; ii++ ) { rowind[ii]-- ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : decrement indices", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n colptr") ; IVfp80(msgFile, ncol+1, colptr, 80, &ierr) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n rowind") ; IVfp80(msgFile, nnonzeros, rowind, 80, &ierr) ; } if ( values != NULL && msglvl > 3 ) { fprintf(msgFile, "\n\n values") ; DVfprintf(msgFile, nnonzeros, values) ; } /* ------------------------------------------- fill the ivec1[] vector with column indices ------------------------------------------- */ MARKTIME(t1) ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { iistart = colptr[jcol] ; iiend = colptr[jcol+1] - 1 ; for ( ii = iistart ; ii <= iiend ; ii++ ) { colind[ii] = jcol ; } } InpMtx_setNent(inpmtx, nnonzeros) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : fill column indices", t2 - t1) ; /* --------------------------- sort and convert to vectors --------------------------- */ MARKTIME(t1) ; InpMtx_changeStorageMode(inpmtx, INPMTX_SORTED) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : sort entries", t2 - t1) ; MARKTIME(t1) ; InpMtx_changeStorageMode(inpmtx, INPMTX_BY_VECTORS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : convert to vectors", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n InpMtx object ") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; fflush(msgFile) ; } /* ---------------------------- write out the InpMtx object ---------------------------- */ if ( strcmp(outFileName, "none") != 0 ) { rc = InpMtx_writeToFile(inpmtx, outFileName) ; fprintf(msgFile, "\n return value %d from InpMtx_writeToFile(%p,%s)", rc, inpmtx, outFileName) ; } /* ------------------------ free the working storage ------------------------ */ InpMtx_free(inpmtx) ; IVfree(colptr) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/testHBIO2.c010064400020550007177000000052300660030006100166240ustar00clevecompmath00000400000006/* testHBIO2.c */ #include "../../misc.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- read in a Harwell-Boeing matrix, convert to a InpMtx object and write to a file. created -- 98sep11, cca --------------------------------------------------- */ { char *inFileName, *outFileName ; double t1, t2 ; int msglvl, rc ; InpMtx *inpmtx ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be Harwell-Boeing format" "\n outFile -- output file, must be *.inpmtxf or *.inpmtxb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inFileName = argv[3] ; outFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inFileName, outFileName) ; fflush(msgFile) ; /* --------------------------------------------- read in the Harwell-Boeing matrix information --------------------------------------------- */ if ( strcmp(inFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; inpmtx = InpMtx_new() ; fprintf(msgFile, "\n 1. inpmtx = %p", inpmtx) ; rc = InpMtx_readFromHBfile(inpmtx, inFileName) ; fprintf(msgFile, "\n 2. inpmtx = %p", inpmtx) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in matrix", t2 - t1) ; if ( rc != 1 ) { fprintf(msgFile, "\n error reading in matrix") ; return(1) ; } if ( msglvl > 2 ) { InpMtx_writeForHumanEye(inpmtx, msgFile) ; fflush(msgFile) ; } /* ---------------------------- write out the InpMtx object ---------------------------- */ if ( strcmp(outFileName, "none") != 0 ) { rc = InpMtx_writeToFile(inpmtx, outFileName) ; fprintf(msgFile, "\n return value %d from InpMtx_writeToFile(%p,%s)", rc, inpmtx, outFileName) ; } /* ------------------------ free the working storage ------------------------ */ InpMtx_free(inpmtx) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/testIO.c010064400020550007177000000057560654000516100163530ustar00clevecompmath00000400000006/* testIO.c */ #include "../InpMtx.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- test InpMtx_readFromFile and InpMtx_writeToFile, useful for translating between formatted *.inpmtxf and binary *.inpmtxb files. created -- 95dec17, cca --------------------------------------------------- */ { int msglvl, rc ; InpMtx *inpmtx ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : testIO msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.inpmtxf or *.inpmtxb" "\n outFile -- output file, must be *.inpmtxf or *.inpmtxb" "\n") ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } fprintf(msgFile, "\n testIO " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", msglvl, argv[2], argv[3], argv[4]) ; fflush(msgFile) ; /* ---------------------- set the default fields ---------------------- */ inpmtx = InpMtx_new() ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n after setting default fields") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; fflush(msgFile) ; } /* -------------------------- read in the InpMtx object -------------------------- */ if ( strcmp(argv[3], "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } rc = InpMtx_readFromFile(inpmtx, argv[3]) ; fprintf(msgFile, "\n return value %d from InpMtx_readFromFile(%p,%s)", rc, inpmtx, argv[3]) ; if ( rc != 1 ) { exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading InpMtx object from file %s", argv[3]) ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- change the storage mode to vectors ---------------------------------- */ InpMtx_changeCoordType(inpmtx, INPMTX_BY_ROWS) ; InpMtx_changeStorageMode(inpmtx, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after changing storage mode") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; fflush(msgFile) ; } /* --------------------------- write out the InpMtx object --------------------------- */ if ( strcmp(argv[4], "none") != 0 ) { rc = InpMtx_writeToFile(inpmtx, argv[4]) ; fprintf(msgFile, "\n return value %d from InpMtx_writeToFile(%p,%s)", rc, inpmtx, argv[4]) ; } /* --------------- free the object --------------- */ InpMtx_free(inpmtx) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/testInput.c010064400020550007177000000156570657730430700171620ustar00clevecompmath00000400000006/* testInput.c */ #include "../../timings.h" #include "../InpMtx.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------- test the InpMtx input methods for Peter Schartz created -- 98sep04, cca ----------------------------------------------- */ { double estpar, growth, t1, t2 ; double *entries ; FILE *msgFile ; int count, ii, irow, maxsize, msglvl, nent, neqns, n1, n2, n3, size, size1, size2, type ; int *indices, *indices1, *indices2, *list ; InpMtx *mtxA ; IVL *adjIVL, *fullIVL, *lowerIVL ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 estpar growth" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 0 -- indices only" "\n 1 -- real entries" "\n 2 -- complex entries" "\n n1 -- # of grid points in first direction" "\n n2 -- # of grid points in second direction" "\n n3 -- # of grid points in third direction" "\n estpar -- estimation for nent" "\n growth -- growth factor" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; n1 = atoi(argv[4]) ; n2 = atoi(argv[5]) ; n3 = atoi(argv[6]) ; estpar = atof(argv[7]) ; growth = atof(argv[8]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n type -- %d" "\n n1 -- %d" "\n n2 -- %d" "\n n3 -- %d" "\n estpar -- %f" "\n growth -- %f" "\n", argv[0], msglvl, argv[2], type, n1, n2, n3, estpar, growth) ; fflush(msgFile) ; if ( n1 <= 0 || n2 <= 0 || n3 <= 0 || estpar < 0.0 || growth <= 1.0 ) { fprintf(stderr, "\n fatal error in testInput, bad input\n") ; exit(-1) ; } /* ----------------------------------- set up the grid adjacency structure ----------------------------------- */ neqns = n1 * n2 * n3 ; MARKTIME(t1) ; if ( n1 == 1 ) { adjIVL = IVL_make9P(n2, n3, 1) ; } else if ( n2 == 1 ) { adjIVL = IVL_make9P(n1, n3, 1) ; } else if ( n3 == 1 ) { adjIVL = IVL_make9P(n1, n2, 1) ; } else { adjIVL = IVL_make27P(n1, n2, n3, 1) ; } nent = IVL_tsize(adjIVL) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : make full adjacency, %d entries", t2 - t1, nent) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n full adjacency structure, %d entries", nent) ; IVL_writeForHumanEye(adjIVL, msgFile) ; } /* ---------------------------------- make the lower adjacency structure ---------------------------------- */ MARKTIME(t1) ; lowerIVL = IVL_new() ; IVL_init1(lowerIVL, IVL_CHUNKED, neqns) ; list = IVinit(neqns, -1) ; for ( irow = 0 ; irow < neqns ; irow++ ) { IVL_listAndSize(adjIVL, irow, &size, &indices) ; for ( ii = count = 0 ; ii < size ; ii++ ) { if ( indices[ii] >= irow ) { list[count++] = indices[ii] ; } } IVL_setList(lowerIVL, irow, count, list) ; } nent = IVL_tsize(lowerIVL) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : make lower adjacency, %d entries", t2 - t1, nent) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n lower adjacency structure, %d entries", nent); IVL_writeForHumanEye(adjIVL, msgFile) ; } /* --------------------------------------------------- create a vector to hold entries, its size is the maximum size of the lower adjacency --------------------------------------------------- */ maxsize = IVL_maxListSize(adjIVL) ; entries = DVinit(2*maxsize, 0.0) ; /* ---------------------------- initialize the InpMtx object ---------------------------- */ MARKTIME(t1) ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_COLUMNS, type, estpar*nent, 0) ; InpMtx_setResizeMultiple(mtxA, growth) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : initialize InpMtx", t2 - t1) ; /* ---------------- load the columns ---------------- */ MARKTIME(t1) ; if ( INPMTX_IS_INDICES_ONLY(mtxA) ) { for ( irow = 0 ; irow < neqns ; irow++ ) { IVL_listAndSize(lowerIVL, irow, &size, &indices) ; InpMtx_inputColumn(mtxA, irow, size, indices) ; } } else if ( INPMTX_IS_REAL_ENTRIES(mtxA) ) { for ( irow = 0 ; irow < neqns ; irow++ ) { IVL_listAndSize(lowerIVL, irow, &size, &indices) ; InpMtx_inputRealColumn(mtxA, irow, size, indices, entries) ; } } else if ( INPMTX_IS_COMPLEX_ENTRIES(mtxA) ) { for ( irow = 0 ; irow < neqns ; irow++ ) { IVL_listAndSize(lowerIVL, irow, &size, &indices) ; InpMtx_inputComplexColumn(mtxA, irow, size, indices, entries) ; } } MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : load entries by columns", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n mtxA") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; } /* ----------------------------- sort and compress the entries ----------------------------- */ MARKTIME(t1) ; InpMtx_sortAndCompress(mtxA) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : sort and compress", t2 - t1) ; /* ------------------- set the vector mode ------------------- */ MARKTIME(t1) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : convert to vectors", t2 - t1) ; /* -------------------------------------- construct the full adjacency structure -------------------------------------- */ MARKTIME(t1) ; fullIVL = InpMtx_fullAdjacency(mtxA) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : construct the full adjacency", t2 - t1) ; /* ----------------------------------------- compare the two full adjacency structures ----------------------------------------- */ for ( irow = 0 ; irow < neqns ; irow++ ) { IVL_listAndSize(adjIVL, irow, &size1, &indices1) ; IVL_listAndSize(fullIVL, irow, &size2, &indices2) ; if ( size1 != size2 ) { fprintf(msgFile, "\n\n error, irow %d, size1 %d, size2 %d", irow, size1, size2) ; exit(-1) ; } for ( ii = 0 ; ii < size1 ; ii++ ) { if ( indices1[ii] != indices2[ii] ) { fprintf(msgFile, "\n\n error, irow %d", irow) ; fprintf(msgFile, "\n indices1") ; IVfprintf(msgFile, size1, indices1) ; fprintf(msgFile, "\n indices2") ; IVfprintf(msgFile, size1, indices2) ; exit(-1) ; } } } /* ------------------------ free the working storage ------------------------ */ IVL_free(adjIVL) ; IVL_free(lowerIVL) ; IVL_free(fullIVL) ; InpMtx_free(mtxA) ; DVfree(entries) ; IVfree(list) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/testMMM.c010064400020550007177000000250670654002623000164670ustar00clevecompmath00000400000006/* testMMM.c */ #include "../InpMtx.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------------ generate a random matrix and test a matrix-matrix multiply method. the output is a matlab file to test correctness. created -- 98jan29, cca -------------------------------------------------------------------- */ { DenseMtx *X, *Y ; double alpha[2] ; double alphaImag, alphaReal ; double *zvec ; Drand *drand ; int col, dataType, ii, msglvl, ncolA, nitem, nrhs, nrowA, nrowX, nrowY, row, seed, storageMode, symflag, transposeflag ; int *colids, *rowids ; InpMtx *A ; FILE *msgFile ; if ( argc != 14 ) { fprintf(stdout, "\n\n %% usage : %s msglvl msgFile symflag storageMode " "\n %% nrow ncol nent nrhs seed alphaReal alphaImag" "\n %% msglvl -- message level" "\n %% msgFile -- message file" "\n %% dataType -- type of matrix entries" "\n %% 1 -- real" "\n %% 2 -- complex" "\n %% symflag -- symmetry flag" "\n %% 0 -- symmetric" "\n %% 1 -- hermitian" "\n %% 2 -- nonsymmetric" "\n %% storageMode -- storage mode" "\n %% 1 -- by rows" "\n %% 2 -- by columns" "\n %% 3 -- by chevrons, (requires nrow = ncol)" "\n %% transpose -- transpose flag" "\n %% 0 -- Y := Y + alpha * A * X" "\n %% 1 -- Y := Y + alpha * A^H * X, nonsymmetric only" "\n %% 2 -- Y := Y + alpha * A^T * X, nonsymmetric only" "\n %% nrowA -- number of rows in A" "\n %% ncolA -- number of columns in A" "\n %% nitem -- number of items" "\n %% nrhs -- number of right hand sides" "\n %% seed -- random number seed" "\n %% alphaReal -- y := y + alpha*A*x" "\n %% alphaImag -- y := y + alpha*A*x" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } dataType = atoi(argv[3]) ; symflag = atoi(argv[4]) ; storageMode = atoi(argv[5]) ; transposeflag = atoi(argv[6]) ; nrowA = atoi(argv[7]) ; ncolA = atoi(argv[8]) ; nitem = atoi(argv[9]) ; nrhs = atoi(argv[10]) ; seed = atoi(argv[11]) ; alphaReal = atof(argv[12]) ; alphaImag = atof(argv[13]) ; fprintf(msgFile, "\n %% %s " "\n %% msglvl -- %d" "\n %% msgFile -- %s" "\n %% dataType -- %d" "\n %% symflag -- %d" "\n %% storageMode -- %d" "\n %% transposeflag -- %d" "\n %% nrowA -- %d" "\n %% ncolA -- %d" "\n %% nitem -- %d" "\n %% nrhs -- %d" "\n %% seed -- %d" "\n %% alphaReal -- %e" "\n %% alphaImag -- %e" "\n", argv[0], msglvl, argv[2], dataType, symflag, storageMode, transposeflag, nrowA, ncolA, nitem, nrhs, seed, alphaReal, alphaImag) ; fflush(msgFile) ; if ( dataType != 1 && dataType != 2 ) { fprintf(stderr, "\n invalid value %d for dataType\n", dataType) ; exit(-1) ; } if ( symflag != 0 && symflag != 1 && symflag != 2 ) { fprintf(stderr, "\n invalid value %d for symflag\n", symflag) ; exit(-1) ; } if ( storageMode != 1 && storageMode != 2 && storageMode != 3 ) { fprintf(stderr, "\n invalid value %d for storageMode\n", storageMode) ; exit(-1) ; } if ( transposeflag < 0 || transposeflag > 2 ) { fprintf(stderr, "\n error, transposeflag = %d, must be 0, 1 or 2", transposeflag) ; exit(-1) ; } if ( (transposeflag == 1 && symflag != 2) || (transposeflag == 2 && symflag != 2) ) { fprintf(stderr, "\n error, transposeflag = %d, symflag = %d", transposeflag, symflag) ; exit(-1) ; } if ( transposeflag == 1 && dataType != 2 ) { fprintf(stderr, "\n error, transposeflag = %d, dataType = %d", transposeflag, dataType) ; exit(-1) ; } if ( symflag == 1 && dataType != 2 ) { fprintf(stderr, "\n symflag = 1 (hermitian), dataType != 2 (complex)") ; exit(-1) ; } if ( nrowA <= 0 || ncolA <= 0 || nitem <= 0 ) { fprintf(stderr, "\n invalid value: nrow = %d, ncol = %d, nitem = %d", nrowA, ncolA, nitem) ; exit(-1) ; } if ( symflag < 2 && nrowA != ncolA ) { fprintf(stderr, "\n invalid data: symflag = %d, nrow = %d, ncol = %d", symflag, nrowA, ncolA) ; exit(-1) ; } alpha[0] = alphaReal ; alpha[1] = alphaImag ; /* ---------------------------- initialize the matrix object ---------------------------- */ A = InpMtx_new() ; InpMtx_init(A, storageMode, dataType, 0, 0) ; drand = Drand_new() ; /* ---------------------------------- generate a vector of nitem triples ---------------------------------- */ rowids = IVinit(nitem, -1) ; Drand_setUniform(drand, 0, nrowA) ; Drand_fillIvector(drand, nitem, rowids) ; colids = IVinit(nitem, -1) ; Drand_setUniform(drand, 0, ncolA) ; Drand_fillIvector(drand, nitem, colids) ; Drand_setUniform(drand, 0.0, 1.0) ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { zvec = DVinit(nitem, 0.0) ; Drand_fillDvector(drand, nitem, zvec) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { zvec = ZVinit(nitem, 0.0, 0.0) ; Drand_fillDvector(drand, 2*nitem, zvec) ; } /* ----------------------------------- assemble the entries entry by entry ----------------------------------- */ fprintf(msgFile, "\n\n A = zeros(%d,%d) ;", nrowA, ncolA) ; if ( symflag == 1 ) { /* ---------------- hermitian matrix ---------------- */ for ( ii = 0 ; ii < nitem ; ii++ ) { if ( rowids[ii] == colids[ii] ) { zvec[2*ii+1] = 0.0 ; } if ( rowids[ii] <= colids[ii] ) { row = rowids[ii] ; col = colids[ii] ; } else { row = colids[ii] ; col = rowids[ii] ; } InpMtx_inputComplexEntry(A, row, col, zvec[2*ii], zvec[2*ii+1]) ; } } else if ( symflag == 0 ) { /* ---------------- symmetric matrix ---------------- */ if ( INPMTX_IS_REAL_ENTRIES(A) ) { for ( ii = 0 ; ii < nitem ; ii++ ) { if ( rowids[ii] <= colids[ii] ) { row = rowids[ii] ; col = colids[ii] ; } else { row = colids[ii] ; col = rowids[ii] ; } InpMtx_inputRealEntry(A, row, col, zvec[ii]) ; } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { for ( ii = 0 ; ii < nitem ; ii++ ) { if ( rowids[ii] <= colids[ii] ) { row = rowids[ii] ; col = colids[ii] ; } else { row = colids[ii] ; col = rowids[ii] ; } InpMtx_inputComplexEntry(A, row, col, zvec[2*ii], zvec[2*ii+1]) ; } } } else { /* ------------------- nonsymmetric matrix ------------------- */ if ( INPMTX_IS_REAL_ENTRIES(A) ) { for ( ii = 0 ; ii < nitem ; ii++ ) { InpMtx_inputRealEntry(A, rowids[ii], colids[ii], zvec[ii]) ; } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { for ( ii = 0 ; ii < nitem ; ii++ ) { InpMtx_inputComplexEntry(A, rowids[ii], colids[ii], zvec[2*ii], zvec[2*ii+1]) ; } } } InpMtx_changeStorageMode(A, INPMTX_BY_VECTORS) ; DVfree(zvec) ; /* ------------------------------------------- write the assembled matrix to a matlab file ------------------------------------------- */ InpMtx_writeForMatlab(A, "A", msgFile) ; if ( symflag == 0 ) { fprintf(msgFile, "\n for k = 1:%d" "\n for j = k+1:%d" "\n A(j,k) = A(k,j) ;" "\n end" "\n end", nrowA, ncolA) ; } else if ( symflag == 1 ) { fprintf(msgFile, "\n for k = 1:%d" "\n for j = k+1:%d" "\n A(j,k) = ctranspose(A(k,j)) ;" "\n end" "\n end", nrowA, ncolA) ; } /* ------------------------------- generate dense matrices X and Y ------------------------------- */ if ( transposeflag == 0 ) { nrowX = ncolA ; nrowY = nrowA ; } else { nrowX = nrowA ; nrowY = ncolA ; } X = DenseMtx_new() ; Y = DenseMtx_new() ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { DenseMtx_init(X, SPOOLES_REAL, 0, 0, nrowX, nrhs, 1, nrowX) ; Drand_fillDvector(drand, nrowX*nrhs, DenseMtx_entries(X)) ; DenseMtx_init(Y, SPOOLES_REAL, 0, 0, nrowY, nrhs, 1, nrowY) ; Drand_fillDvector(drand, nrowY*nrhs, DenseMtx_entries(Y)) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { DenseMtx_init(X, SPOOLES_COMPLEX, 0, 0, nrowX, nrhs, 1, nrowX) ; Drand_fillDvector(drand, 2*nrowX*nrhs, DenseMtx_entries(X)) ; DenseMtx_init(Y, SPOOLES_COMPLEX, 0, 0, nrowY, nrhs, 1, nrowY) ; Drand_fillDvector(drand, 2*nrowY*nrhs, DenseMtx_entries(Y)) ; } fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, nrhs) ; DenseMtx_writeForMatlab(X, "X", msgFile) ; fprintf(msgFile, "\n Y = zeros(%d,%d) ;", nrowY, nrhs) ; DenseMtx_writeForMatlab(Y, "Y", msgFile) ; /* ---------------------------------- perform the matrix-matrix multiply ---------------------------------- */ fprintf(msgFile, "\n alpha = %20.12e + %20.2e*i;", alpha[0], alpha[1]); fprintf(msgFile, "\n Z = zeros(%d,1) ;", nrowY) ; if ( transposeflag == 0 ) { if ( symflag == 0 ) { InpMtx_sym_mmm(A, Y, alpha, X) ; } else if ( symflag == 1 ) { InpMtx_herm_mmm(A, Y, alpha, X) ; } else if ( symflag == 2 ) { InpMtx_nonsym_mmm(A, Y, alpha, X) ; } DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - Y - alpha*A*X) ") ; fprintf(msgFile, "\n") ; } else if ( transposeflag == 1 ) { InpMtx_nonsym_mmm_H(A, Y, alpha, X) ; DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - Y - alpha*ctranspose(A)*X) ") ; fprintf(msgFile, "\n") ; } else if ( transposeflag == 2 ) { InpMtx_nonsym_mmm_T(A, Y, alpha, X) ; DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - Y - alpha*transpose(A)*X) ") ; fprintf(msgFile, "\n") ; } /* ------------------------ free the working storage ------------------------ */ InpMtx_free(A) ; DenseMtx_free(X) ; DenseMtx_free(Y) ; IVfree(rowids) ; IVfree(colids) ; Drand_free(drand) ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ InpMtx/drivers/testR2D.c010064400020550007177000000376030654000235000164240ustar00clevecompmath00000400000006/* testR2D.c */ #include "../InpMtx.h" #include "../../EGraph.h" #include "../../Coords.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ void generateMatrix ( int eadj[], Coords *coords, double mtxent[], int msglvl, FILE *msgFile ) ; void loadMatrices ( EGraph *egraph, Coords *coords, InpMtx *inpmtx, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- test the InpMtx object (1) read in an EGraph file that contains the vertex lists for triangular element (2) read in a Coords file that contains the vertex coordinates (3) for each element (4) create an elemental matrix and insert into InpMtx (5) assemble the matrix created -- 96jul05, cca -------------------------------------------------------------- */ int main ( int argc, char *argv[] ) { char *CoordsFileName, *EGraphFileName, *outFileName ; Coords *coords ; DenseMtx *X, *Y, *Y2 ; double alpha[2] = {1.0, 0.0} ; double *x, *y ; double *mtxent ; double t1, t2 ; Drand *drand ; EGraph *egraph ; FILE *msgFile ; int coordType, esize, ielem, msglvl, nelem, nvtx, rc, seed ; int *colOldToNew, *eadj, *rowOldToNew ; InpMtx *inpmtx ; IV *colOldToNewIV, *rowOldToNewIV ; /* --------------- check the input --------------- */ if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile EGraphFile CoordsFile " "\n coordType seed outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n EGraphFile -- file that contains the element graph" "\n must be *.egraphf or *.egraphb" "\n CoordsFile -- file that contains the coordinates object" "\n must be *.coordsf or *.coordsb" "\n coordType -- coordinate type" "\n 1 --> by rows" "\n 2 --> by columns" "\n 3 --> by chevrons" "\n seed -- random number seed" "\n outFile -- file to contain the InpMtx object" "\n must be *.inpmtxb or *.inpmtxf" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } EGraphFileName = argv[3] ; CoordsFileName = argv[4] ; coordType = atoi(argv[5]) ; seed = atoi(argv[6]) ; outFileName = argv[7] ; /* -------------- echo the input -------------- */ fprintf(msgFile, "\n input to %s" "\n msglvl = %d" "\n msgFile = %s" "\n EGraphFile = %s" "\n CoordsFile = %s" "\n coordType = %d" "\n seed = %d" "\n", argv[0], msglvl, argv[2], EGraphFileName, CoordsFileName, coordType, seed) ; fflush(msgFile) ; /* ------------------------- read in the EGraph object ------------------------- */ egraph = EGraph_new() ; MARKTIME(t1) ; rc = EGraph_readFromFile(egraph, EGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in egraph from file %s", t2 - t1, EGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from EGraph_readFromFile(%p,%s)", rc, egraph, EGraphFileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading EGraph object from file %s", EGraphFileName) ; EGraph_writeForHumanEye(egraph, msgFile) ; fflush(msgFile) ; } nvtx = egraph->nvtx ; nelem = egraph->nelem ; /* ------------------------- read in the Coords object ------------------------- */ coords = Coords_new() ; MARKTIME(t1) ; rc = Coords_readFromFile(coords, CoordsFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in egraph from file %s", t2 - t1, CoordsFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Coords_readFromFile(%p,%s)", rc, coords, CoordsFileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading Coords object from file %s", CoordsFileName) ; Coords_writeForHumanEye(coords, msgFile) ; fflush(msgFile) ; } /* ------------------------------- create the random number object ------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setUniform(drand, -1.0, 1.0) ; Drand_setSeed(drand, seed) ; /* ------------------------- create the InpMtx object ------------------------- */ MARKTIME(t1) ; inpmtx = InpMtx_new() ; InpMtx_init(inpmtx, coordType, INPMTX_REAL_ENTRIES, egraph->adjIVL->tsize, 0) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : initialize the InpMtx object", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n InpMtx after initialization") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; } /* -------------------------- fill X with random numbers -------------------------- */ nvtx = egraph->nvtx ; X = DenseMtx_new() ; DenseMtx_init(X, SPOOLES_REAL, 0, 0, nvtx, 1, 1, nvtx) ; DenseMtx_fillRandomEntries(X, drand) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n solution vector") ; DenseMtx_writeForHumanEye(X, msgFile) ; } x = DenseMtx_entries(X) ; /* ----------------- fill Y with zeros ----------------- */ Y = DenseMtx_new() ; DenseMtx_init(Y, SPOOLES_REAL, 0, 0, nvtx, 1, 1, nvtx) ; DenseMtx_zero(Y) ; y = DenseMtx_entries(Y) ; /* --------------------------------- load the matrices and compute y[] --------------------------------- */ MARKTIME(t1) ; mtxent = DVinit(9, 0.0) ; for ( ielem = 0 ; ielem < nelem ; ielem++ ) { IVL_listAndSize(egraph->adjIVL, ielem, &esize, &eadj) ; if ( msglvl > 3 && msgFile != NULL ) { fprintf(msgFile, "\n\n elemental matrix %d", ielem) ; } generateMatrix(eadj, coords, mtxent, msglvl, msgFile) ; InpMtx_inputRealMatrix(inpmtx, 3, 3, 1, 3, eadj, eadj, mtxent) ; if ( msglvl > 3 && msgFile != NULL ) { InpMtx_writeForHumanEye(inpmtx, stdout) ; } y[eadj[0]] += mtxent[0] * x[eadj[0]] + mtxent[3] * x[eadj[1]] + mtxent[6] * x[eadj[2]] ; y[eadj[1]] += mtxent[1] * x[eadj[0]] + mtxent[4] * x[eadj[1]] + mtxent[7] * x[eadj[2]] ; y[eadj[2]] += mtxent[2] * x[eadj[0]] + mtxent[5] * x[eadj[1]] + mtxent[8] * x[eadj[2]] ; } /* ----------------------------- change to packed storage mode ----------------------------- */ InpMtx_changeStorageMode(inpmtx, INPMTX_SORTED) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n InpMtx after matrices loaded") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n right hand side vector via elemental mvm") ; DVfprintf(msgFile, nvtx, y) ; } /* --------------------------------------------------- the matrix as constructed is singular, uncomment this code to make node 0 a dirichlet node and so make the matrix nonsingular --------------------------------------------------- */ /* { double *dvec ; int ii, nent ; int *ivec1, *ivec2 ; nent = inpmtx->nent ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; dvec = InpMtx_dvec(inpmtx) ; for ( ii = 0 ; ii < nent ; ii++ ) { if ( ivec1[ii] == 0 ) { if ( ivec2[ii] == 0 ) { dvec[ii] = 1.0 ; } else { dvec[ii] = 0.0 ; } } } } */ /* ------------------------------------------------- optionally write out the InpMtx object to a file ------------------------------------------------- */ if ( strcmp(outFileName, "none") != 0 ) { InpMtx_writeToFile(inpmtx, outFileName) ; } /* --------------------- change to vector mode --------------------- */ InpMtx_changeStorageMode(inpmtx, INPMTX_BY_VECTORS) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n InpMtx in vector mode") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; } /* --------------------- compute y[] = A * x[] --------------------- */ Y2 = DenseMtx_new() ; DenseMtx_init(Y2, SPOOLES_REAL, 0, 0, nvtx, 1, 1, nvtx) ; DenseMtx_zero(Y2) ; MARKTIME(t1) ; InpMtx_nonsym_mmm(inpmtx, Y2, alpha, X) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : compute matrix-vector multiply, %.3f mflops", t2 - t1, 2*inpmtx->nent*1.e-6/(t2 - t1)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n right hand side vector via assembled mvm") ; DenseMtx_writeForHumanEye(Y2, msgFile) ; } /* ---------------- compare Y and Y2 ---------------- */ DenseMtx_sub(Y2, Y) ; fprintf(msgFile, "\n ||error||_max = %12.4e", DenseMtx_maxabs(Y2)) ; /* -------------------------------------- get random row and column permutations -------------------------------------- */ rowOldToNewIV = IV_new() ; IV_init(rowOldToNewIV, nvtx, NULL) ; IV_ramp(rowOldToNewIV, 0, 1) ; IV_shuffle(rowOldToNewIV, seed + 1) ; rowOldToNew = IV_entries(rowOldToNewIV) ; colOldToNewIV = IV_new() ; IV_init(colOldToNewIV, nvtx, NULL) ; IV_ramp(colOldToNewIV, 0, 1) ; IV_shuffle(colOldToNewIV, seed + 2) ; colOldToNew = IV_entries(colOldToNewIV) ; /* ---------------------------------- permute the InpMtx object, X and Y ---------------------------------- */ MARKTIME(t1) ; InpMtx_permute(inpmtx, rowOldToNew, colOldToNew) ; DenseMtx_permuteRows(X, colOldToNewIV) ; DenseMtx_permuteRows(Y, rowOldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute matrix", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n permuted matrix") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; fprintf(msgFile, "\n permuted solution") ; DenseMtx_writeForHumanEye(X, msgFile) ; fprintf(msgFile, "\n permuted right hand side") ; DenseMtx_writeForHumanEye(Y, msgFile) ; } /* ------------------------------------------------------- compute the matrix-vector product with permuted vectors ------------------------------------------------------- */ DenseMtx_zero(Y2) ; MARKTIME(t1) ; InpMtx_nonsym_mmm(inpmtx, Y2, alpha, X) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : compute matrix-vector multiply, %.3f mflops", t2 - t1, 2*inpmtx->nent*1.e-6/(t2 - t1)) ; DenseMtx_sub(Y2, Y) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n error") ; DenseMtx_writeForHumanEye(Y2, msgFile) ; } fprintf(msgFile, "\n ||error||_max = %12.4e", DenseMtx_maxabs(Y2)) ; /* ---------------- free the objects ---------------- */ EGraph_free(egraph) ; Coords_free(coords) ; InpMtx_free(inpmtx) ; Drand_free(drand) ; DenseMtx_free(X) ; DenseMtx_free(Y) ; DenseMtx_free(Y2) ; DVfree(mtxent) ; IV_free(rowOldToNewIV) ; IV_free(colOldToNewIV) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------- generate a matrix ----------------- */ void generateMatrix ( int eadj[], Coords *coords, double mtxent[], int msglvl, FILE *msgFile ) { double area, dx10, dx20, dx21, dy10, dy20, dy21 ; double x0, x1, x2, y0, y1, y2 ; int i, v0, v1, v2 ; v0 = eadj[0] ; v1 = eadj[1] ; v2 = eadj[2] ; x0 = Coords_value(coords, 1, v0) ; x1 = Coords_value(coords, 1, v1) ; x2 = Coords_value(coords, 1, v2) ; y0 = Coords_value(coords, 2, v0) ; y1 = Coords_value(coords, 2, v1) ; y2 = Coords_value(coords, 2, v2) ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n vertex %d at (%6.3f, %6.3f)", v0, x0, y0) ; fprintf(msgFile, "\n vertex %d at (%6.3f, %6.3f)", v1, x1, y1) ; fprintf(msgFile, "\n vertex %d at (%6.3f, %6.3f)", v2, x2, y2) ; fflush(msgFile) ; } dx10 = x1 - x0 ; dx20 = x2 - x0 ; dx21 = x2 - x1 ; dy10 = y1 - y0 ; dy20 = y2 - y0 ; dy21 = y2 - y1 ; area = 0.5*(dx10*dy20 - dx20*dy10) ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n area = %20.12e", area) ; fflush(msgFile) ; } if ( area > 1.e-12 ) { mtxent[0] = dx21*dx21 + dy21*dy21 ; mtxent[1] = - dx21*dx20 - dy21*dy20 ; mtxent[2] = dx21*dx10 + dy21*dy10 ; mtxent[3] = mtxent[1] ; mtxent[4] = dx20*dx20 + dy20*dy20 ; mtxent[5] = - dx20*dx10 - dy20*dy10 ; mtxent[6] = mtxent[2] ; mtxent[7] = mtxent[5] ; mtxent[8] = dx10*dx10 + dy10*dy10 ; for ( i = 0 ; i < 9 ; i++ ) { mtxent[i] /= (4.*area) ; } if ( msglvl > 3 && msgFile != NULL ) { fprintf(msgFile, "\n matrix " "\n [ %20.12e %20.12e %20.12e ] " "\n [ %20.12e %20.12e %20.12e ] " "\n [ %20.12e %20.12e %20.12e ] ", mtxent[0], mtxent[3], mtxent[6], mtxent[1], mtxent[4], mtxent[7], mtxent[2], mtxent[5], mtxent[8]) ; fprintf(msgFile, "\n rowsums = [ %13.5e %13.5e %13.5e ]", mtxent[0] + mtxent[3] + mtxent[6], mtxent[1] + mtxent[4] + mtxent[7], mtxent[2] + mtxent[5] + mtxent[8]) ; fprintf(msgFile, "\n loading matrix into bag") ; fflush(msgFile) ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------ load the matrices into the bag ------------------------------ */ void loadMatrices ( EGraph *egraph, Coords *coords, InpMtx *inpmtx, int msglvl, FILE *msgFile ) { double area, dx10, dx20, dx21, dy10, dy20, dy21 ; double mtxent[9] ; double x0, x1, x2, y0, y1, y2 ; int esize, i, ielem, nelem, nvtx, v0, v1, v2 ; int *eadj ; IVL *adj ; nvtx = egraph->nvtx ; nelem = egraph->nelem ; adj = egraph->adjIVL ; /* for ( ielem = 0 ; ielem < 10 ; ielem++ ) { */ for ( ielem = 0 ; ielem < nelem ; ielem++ ) { IVL_listAndSize(adj, ielem, &esize, &eadj) ; v0 = eadj[0] ; v1 = eadj[1] ; v2 = eadj[2] ; x0 = Coords_value(coords, 1, v0) ; x1 = Coords_value(coords, 1, v1) ; x2 = Coords_value(coords, 1, v2) ; y0 = Coords_value(coords, 2, v0) ; y1 = Coords_value(coords, 2, v1) ; y2 = Coords_value(coords, 2, v2) ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n vertex %d at (%6.3f, %6.3f)", v0, x0, y0) ; fprintf(msgFile, "\n vertex %d at (%6.3f, %6.3f)", v1, x1, y1) ; fprintf(msgFile, "\n vertex %d at (%6.3f, %6.3f)", v2, x2, y2) ; fflush(msgFile) ; } dx10 = x1 - x0 ; dx20 = x2 - x0 ; dx21 = x2 - x1 ; dy10 = y1 - y0 ; dy20 = y2 - y0 ; dy21 = y2 - y1 ; area = 0.5*(dx10*dy20 - dx20*dy10) ; if ( msglvl > 2 && msgFile != NULL ) { fprintf(msgFile, "\n area = %20.12e", area) ; fflush(msgFile) ; } if ( area > 1.e-12 ) { mtxent[0] = dx21*dx21 + dy21*dy21 ; mtxent[1] = - dx21*dx20 - dy21*dy20 ; mtxent[2] = dx21*dx10 + dy21*dy10 ; mtxent[3] = mtxent[1] ; mtxent[4] = dx20*dx20 + dy20*dy20 ; mtxent[5] = - dx20*dx10 - dy20*dy10 ; mtxent[6] = mtxent[2] ; mtxent[7] = mtxent[5] ; mtxent[8] = dx10*dx10 + dy10*dy10 ; for ( i = 0 ; i < 9 ; i++ ) { mtxent[i] /= (4.*area) ; } if ( msglvl > 3 && msgFile != NULL ) { fprintf(msgFile, "\n matrix %d" "\n [ %20.12e %20.12e %20.12e ] " "\n [ %20.12e %20.12e %20.12e ] " "\n [ %20.12e %20.12e %20.12e ] ", ielem, mtxent[0], mtxent[3], mtxent[6], mtxent[1], mtxent[4], mtxent[7], mtxent[2], mtxent[5], mtxent[8]) ; fprintf(msgFile, "\n rowsums = [ %13.5e %13.5e %13.5e ]", mtxent[0] + mtxent[3] + mtxent[6], mtxent[1] + mtxent[4] + mtxent[7], mtxent[2] + mtxent[5] + mtxent[8]) ; fprintf(msgFile, "\n loading matrix into bag") ; fflush(msgFile) ; } InpMtx_inputRealMatrix(inpmtx, 3, 3, 1, 3, eadj, eadj, mtxent) ; if ( msglvl > 3 && msgFile != NULL ) { InpMtx_writeForHumanEye(inpmtx, stdout) ; } } } return ; } /*--------------------------------------------------------------------*/ egraph->adjIVL, ielem, &esize, &eadj) ; if ( msglvl > 3 && msgFile != NULL ) { fprintf(msgFile, "\n\n elemental matrInpMtx/drivers/weightedAdjToGraph.c010064400020550007177000000172150654002055300206430ustar00clevecompmath00000400000006/* makeGraph.c */ #include "../InpMtx.h" #include "../../Graph.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------- read in an adjacency structure file and create a Graph object nvtx nadj vwghts[nvtx] offsets[nvtx+1] indices[nadj] created -- 96oct31, cca ------------------------------------------------------------- */ { InpMtx *inpmtx ; double t1, t2 ; int flag, ierr, ii, msglvl, nadj, nvtx, rc, v, vsize ; int *adjncy, *offsets, *vadj, *vwghts ; Graph *graph ; FILE *fp, *msgFile ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inAdjacencyFile outGraphFile flag" "\n msglvl -- message level" "\n msgFile -- message file" "\n inAdjacencyFile -- input file" "\n outGraphFile -- output file, must be *.graphf or *.graphb" "\n flag -- flag for 0-based or 1-based addressing" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } flag = atoi(argv[5]) ; if ( flag < 0 || flag > 1 ) { fprintf(stderr, "\n fatal error in makeGraph %d %s %s %s %d" "\n flag must be 0 if indices and offsets are zero-based like C" "\n flag must be 1 if indices and offsets are one-based like Fortran" "\n", msglvl, argv[2], argv[3], argv[4], flag) ; exit(-1) ; } fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n flag -- %d" "\n", argv[0], msglvl, argv[2], argv[3], argv[4], flag) ; fflush(msgFile) ; /* ------------------- open the input file ------------------- */ if ( (fp = fopen(argv[3], "r")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[3]) ; return(-1) ; } /* ------------------------------------------------- read in the number of vertices and adjacency size ------------------------------------------------- */ if ( (rc = fscanf(fp, " %d %d", &nvtx, &nadj)) != 2 ) { fprintf(stderr, "\n fatal error in %s" "\n %d of %d items read\n", argv[0], rc, 2) ; exit(-1) ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n adjacency file has %d vertices and %d indices", nvtx, nadj) ; fflush(msgFile) ; } /* -------------------------- read in the vertex weights -------------------------- */ vwghts = IVinit(nvtx, 0) ; rc = IVfscanf(fp, nvtx, vwghts) ; if ( rc != nvtx ) { fprintf(stderr, "\n fatal error in %s reading vertex weights" "\n %d of %d items read\n", argv[0], rc, nvtx) ; exit(-1) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n vertex weights") ; IVfp80(msgFile, nvtx, vwghts, 80, &ierr) ; fflush(msgFile) ; } /* ------------------- read in the offsets ------------------- */ offsets = IVinit(nvtx + 1, -1) ; rc = IVfscanf(fp, nvtx + 1, offsets) ; if ( rc != nvtx + 1 ) { fprintf(stderr, "\n fatal error in %s reading offsets" "\n %d of %d items read\n", argv[0], rc, nvtx + 1) ; exit(-1) ; } if ( flag == 1 ) { /* --------------------------------------------- decrement the offsets by one for C addressing --------------------------------------------- */ for ( ii = 0 ; ii < nvtx + 1 ; ii++ ) { offsets[ii]-- ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n offsets") ; IVfp80(msgFile, nvtx+1, offsets, 80, &ierr) ; fflush(msgFile) ; } /* --------------------- read in the adjacency --------------------- */ adjncy = IVinit(nadj, -1) ; rc = IVfscanf(fp, nadj, adjncy) ; if ( rc != nadj ) { fprintf(stderr, "\n fatal error in %s reading adjncy" "\n %d of %d items read\n", argv[0], rc, nadj) ; exit(-1) ; } if ( flag == 1 ) { /* --------------------------------------------- decrement the offsets by one for C addressing --------------------------------------------- */ for ( ii = 0 ; ii < nadj ; ii++ ) { adjncy[ii]-- ; } } /* ----------------------------------------------- check the adjacency structure for valid entries ----------------------------------------------- */ for ( ii = 0 ; ii < nadj ; ii++ ) { v = adjncy[ii] ; if ( v < 0 || v >= nvtx ) { fprintf(stderr, "\n fatal error in mkGraph" "\n adjncy[%d] = %d, out of range in [0,%d]" "\n ", ii, v, nvtx-1) ; exit(-1) ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n adjncy") ; IVfp80(msgFile, nadj, adjncy, 80, &ierr) ; fflush(msgFile) ; } /* ------------------------- set up the InpMtx object ------------------------- */ inpmtx = InpMtx_new() ; InpMtx_init(inpmtx, INPMTX_BY_ROWS, INPMTX_INDICES_ONLY, nvtx + 2*nadj, nvtx) ; for ( v = 0 ; v < nvtx ; v++ ) { InpMtx_inputEntry(inpmtx, v, v) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n inputting entry (%d,%d)", v, v) ; fflush(msgFile) ; } vsize = offsets[v+1] - offsets[v] ; vadj = &adjncy[offsets[v]] ; if ( msglvl > 3 ) { fprintf(msgFile, "\n inputting row %d :", v) ; IVfp80(msgFile, vsize, vadj, 22, &ierr) ; fflush(msgFile) ; } InpMtx_inputRow(inpmtx, v, vsize, vadj) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n inputting column %d :", v) ; IVfp80(msgFile, vsize, vadj, 22, &ierr) ; fflush(msgFile) ; } InpMtx_inputColumn(inpmtx, v, vsize, vadj) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n raw data") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; } InpMtx_changeStorageMode(inpmtx, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n after changing to vector storage mode") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; } /* ----------------------------------- free the offsets and adjncy vectors ----------------------------------- */ IVfree(offsets) ; IVfree(adjncy) ; /* --------------------------- initialize the Graph object --------------------------- */ offsets = IVinit(nvtx + 1, -1) ; IVcopy(nvtx, offsets, IV_entries(&inpmtx->offsetsIV)) ; offsets[nvtx] = inpmtx->nent ; adjncy = IV_entries(&inpmtx->ivec2IV) ; graph = Graph_new() ; Graph_fillFromOffsets(graph, nvtx, offsets, adjncy, 0) ; graph->type = 1 ; graph->totvwght = IVsum(nvtx, vwghts) ; graph->vwghts = vwghts ; if ( msglvl > 0 ) { fprintf(msgFile, "\n graph has %d vertices and %d edges", graph->nvtx, graph->nedges) ; fflush(msgFile) ; } if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } /* -------------------------- write out the Graph object -------------------------- */ if ( strcmp(argv[4], "none") != 0 ) { MARKTIME(t1) ; rc = Graph_writeToFile(graph, argv[4]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write graph to file %s", t2 - t1, argv[4]) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_writeToFile(%p,%s)", rc, graph, argv[4]) ; } if ( msglvl > 0 ) { int ierr ; fprintf(msgFile, "\n vertex weights in ascending order") ; IVqsortUp(nvtx, vwghts) ; IVfp80(msgFile, nvtx, vwghts, 80, &ierr) ; } /* --------------------------------- free the Graph and InpMtx object --------------------------------- */ Graph_free(graph) ; InpMtx_free(inpmtx) ; IVfree(offsets) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ - ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n offsets") ; IVfp80(msgFile, nvtx+1, offsets, 80, &ierr) ; fflush(msgFile) ; } /* --------------------- read in the adjacency --------------------- */ adjncy = IVinit(nadj, -1) ; rc = IVfscanf(fp, nadj, adjncy) ; if ( rc != nadj ) { fprintf(stderr, "\n fatal error in %s reading adjncy" "InpMtx/doc/004275500020550007177000000000000665023217000140635ustar00clevecompmath00000400000006InpMtx/doc/dataStructure.tex010064400020550007177000000117230655115111000174300ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:InpMtx:dataStructure} \par \par The {\tt InpMtx} structure has the following fields. \begin{itemize} \item {\tt int coordType} : coordinate type. The following types are supported. \begin{itemize} \item {\tt INPMTX\_BY\_ROWS} --- row triples, the coordinates for $a_{i,j}$ is $(i,j)$. \item {\tt INPMTX\_BY\_COLUMNS} --- column triples, the coordinates for $a_{i,j}$ is $(j,i)$. \item {\tt INPMTX\_BY\_CHEVRONS} --- chevron triples, the coordinates for $a_{i,j}$ is $(\min(i,j), j-i)$. (Chevron $j$ contains $a_{j,j}$, $a_{j,k} \ne 0$ and $a_{k,j} \ne 0$ for $k > j$.) \item {\tt INPMTX\_CUSTOM} --- custom coordinates. \end{itemize} \item {\tt int storageMode} : mode of storage \begin{itemize} \item {\tt INPMTX\_RAW\_DATA} --- data is raw pairs or triples, two coordinates and (optionally) one or two double precision values. \item {\tt INPMTX\_SORTED} --- data is sorted and distinct triples, the primary key is the first coordinate, the secondary key is the second coordinate. \item {\tt INPMTX\_BY\_VECTORS} --- data is sorted and distinct vectors. All entries in a vector share something in common. For example, when {\tt coordType} is {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}, row vectors, column vectors, or chevron vectors are stored, respectively. When {\tt coordType} is {\tt INPMTX\_CUSTOM}, a custom type, entries in the same vector have something in common but it need not be a common row, column or chevron coordinate. \end{itemize} \item {\tt int inputMode} : mode of data input \begin{itemize} \item {\tt INPMTX\_INDICES\_ONLY} --- only indices are stored, not entries. \item {\tt SPOOLES\_REAL} --- indices and real entries are stored. \item {\tt SPOOLES\_COMPLEX} --- indices and complex entries are stored. \end{itemize} \item {\tt int maxnent} -- present maximum number of entries in the object. This quantity is initialized by the {\tt InpMtx\_init()} method, but will be changed as the object resizes itself as necessary. \item {\tt int nent} -- present number of entries in the object. This quantity changes as data is input or when the raw triples are sorted and compressed. \item {\tt double resizeMultiple} -- governs how the workspace grows as necessary. The default value is 1.25. \item {\tt IV ivec1IV} -- an {\tt IV} vector object of size {\tt mxnent} that holds first coordinates. \item {\tt IV ivec2IV} -- an {\tt IV} vector object of size {\tt mxnent} that holds second coordinates. \item {\tt DV dvecDV} -- a {\tt DV} vector object of size {\tt mxnent} that holds double precision entries. Used only when {\tt inputMode} is {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. \item {\tt int maxnvector} -- present maximum number of vectors. This quantity is initialized by the {\tt InpMtx\_init()} method, but will be changed as the object resizes itself as necessary. Used only when {\tt storageMode} is {\tt INPMTX\_BY\_VECTORS}. \item {\tt int nvector} -- present number of vectors. Used only when {\tt storageMode} is {\tt INPMTX\_BY\_VECTORS}. \item {\tt IV vecidsIV} -- an {\tt IV} vector object of size {\tt nvector} to hold the id of each vector. Used only when {\tt storageMode} is {\tt INPMTX\_BY\_VECTORS}. \item {\tt IV sizesIV} -- an {\tt IV} vector object of size {\tt nvector} to hold the size of each vector. Used only when {\tt storageMode} is {\tt INPMTX\_BY\_VECTORS}. \item {\tt IV offsetsIV} -- an {\tt IV} vector object of size {\tt nvector} to hold the offset of each vector into the {\tt ivec1IV}, {\tt ivec2IV} and {\tt dvecDV} vector objects. Used only when {\tt storageMode} is {\tt INPMTX\_BY\_VECTORS}. \end{itemize} \par One can query the attributes of the object with the following macros. \begin{itemize} \item {\tt INPMTX\_IS\_BY\_ROWS(mtx)} returns {\tt 1} if the entries are stored by rows, and {\tt 0} otherwise. \item {\tt INPMTX\_IS\_BY\_COLUMNS(mtx)} returns {\tt 1} if the entries are stored by columns, and {\tt 0} otherwise. \item {\tt INPMTX\_IS\_BY\_CHEVRONS(mtx)} returns {\tt 1} if the entries are stored by chevrons, and {\tt 0} otherwise. \item {\tt INPMTX\_IS\_BY\_CUSTOM(mtx)} returns {\tt 1} if the entries are stored by some custom coordinate, and {\tt 0} otherwise. \item {\tt INPMTX\_IS\_RAW\_DATA(mtx)} returns {\tt 1} if the entries are stored as unsorted pairs or triples, and {\tt 0} otherwise. \item {\tt INPMTX\_IS\_SORTED(mtx)} returns {\tt 1} if the entries are stored as sorted pairs or triples, and {\tt 0} otherwise. \item {\tt INPMTX\_IS\_BY\_VECTORS(mtx)} returns {\tt 1} if the entries are stored as vectors, and {\tt 0} otherwise. \item {\tt INPMTX\_IS\_INDICES\_ONLY(mtx)} returns {\tt 1} if the entries are not stored, and {\tt 0} otherwise. \item {\tt INPMTX\_IS\_REAL\_ENTRIES(mtx)} returns {\tt 1} if the entries are real, and {\tt 0} otherwise. \item {\tt INPMTX\_IS\_COMPLEX\_ENTRIES(mtx)} returns {\tt 1} if the entries are complex, and {\tt 0} otherwise. \end{itemize} InpMtx/doc/drivers.tex010064400020550007177000000665110662341676300163030ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt InpMtx} object} \label{section:InpMtx:drivers} \par This section contains brief descriptions of the driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program reads and write {\tt InpMtx} files, useful for converting formatted files to binary files and vice versa. One can also read in a {\tt InpMtx} file and print out just the header information (see the {\tt InpMtx\_writeStats()} method). \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt InpMtx} object. It must be of the form {\tt *.inpmtxf} or {\tt *.inpmtxb}. The {\tt InpMtx} object is read from the file via the {\tt InpMtx\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt InpMtx} object. If {\tt outFile} is {\tt none} then the {\tt InpMtx} object is not written to a file. Otherwise, the {\tt InpMtx\_writeToFile()} method is called to write the object to a formatted file (if {\tt outFile} is of the form {\tt *.inpmtxf}), or a binary file (if {\tt outFile} is of the form {\tt *.inpmtxb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testFullAdj msglvl msgFile nvtx nent seed \end{verbatim} This driver program tests the {\tt InpMtx\_fullAdjacency()} method. If first generates a {\tt InpMtx} object filled with random entries of a matrix $A$ and then constructs an {\tt IVL} object that contains the full adjacency structure of $A + A^T$, diagonal edges included. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nvtx} parameter is the number of rows and columns in $A$. \item The {\tt nent} parameter is an upper bound on the number of entries in $A$. (Since the locations of the entries are generated via random numbers, there may be duplicate entries.) \item The {\tt seed} parameter is random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testFullAdj2 msglvl msgFile nvtx nentA nentB seed \end{verbatim} This driver program tests the {\tt InpMtx\_fullAdjacency2()} method. If first generates two {\tt InpMtx} object filled with random entries --- one for a matrix $A$ and one for a matrix $B$. It then constructs an {\tt IVL} object that contains the full adjacency structure of $(A+B) + (A+B)^T$, diagonal edges included. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nvtx} parameter is the number of rows and columns in $A$. \item The {\tt nentA} parameter is an upper bound on the number of entries in $A$. (Since the locations of the entries are generated via random numbers, there may be duplicate entries.) \item The {\tt nentB} parameter is an upper bound on the number of entries in $B$. (Since the locations of the entries are generated via random numbers, there may be duplicate entries.) \item The {\tt seed} parameter is random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} createGraph msglvl msgFile inFile outFile \end{verbatim} This driver program reads in {\tt InpMtx} object from the file {\tt inFile} that holds a matrix $A$. It then creates a {\tt Graph} object for $B = A + A^T$ and writes it to the file {\tt outFile}. Recall, a {\tt Graph} object must be symmetric, so if the {\tt InpMtx} object only holds the lower or upper triangular part of the matrix, the other portion will be added. Also, a {\tt Graph} object has edges of the form {\tt (v,v)}, and if these entries are missing from the {\tt InpMtx} object, they will be added. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt InpMtx} object. It must be of the form {\tt *.inpmtxf} or {\tt *.inpmtxb}. The {\tt InpMtx} object is read from the file via the {\tt InpMtx\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt InpMtx} object. If {\tt outFile} is {\tt none} then the {\tt InpMtx} object is not written to a file. Otherwise, the {\tt InpMtx\_writeToFile()} method is called to write the object to a formatted file (if {\tt outFile} is of the form {\tt *.inpmtxf}), or a binary file (if {\tt outFile} is of the form {\tt *.inpmtxb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} createGraphForATA msglvl msgFile inFile outFile \end{verbatim} This driver program reads in {\tt InpMtx} object from the file {\tt inFile} that holds a matrix $A$. It then creates a {\tt Graph} object for $B = A^TA$ and writes it to the file {\tt outFile}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt InpMtx} object. It must be of the form {\tt *.inpmtxf} or {\tt *.inpmtxb}. The {\tt InpMtx} object is read from the file via the {\tt InpMtx\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt InpMtx} object. If {\tt outFile} is {\tt none} then the {\tt InpMtx} object is not written to a file. Otherwise, the {\tt InpMtx\_writeToFile()} method is called to write the object to a formatted file (if {\tt outFile} is of the form {\tt *.inpmtxf}), or a binary file (if {\tt outFile} is of the form {\tt *.inpmtxb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} adjToGraph msglvl msgFile inAdjacencyFile outGraphFile flag \end{verbatim} This driver program was used to generate a {\tt type 0} {\tt Graph} object (unit weight vertices and edges) from a file that contained the adjacency structure of a matrix in the following form. \begin{verbatim} nvtx nadj offsets[nvtx+1] indices[nadj] \end{verbatim} There are {\tt nvtx} vertices in the graph and the adjacency vector has {\tt nadj} entries. It was not known whether the adjacency structure contained {\tt (v,v)} entries or if it was only the upper or lower triangle. Our {\tt Graph} object is symmetric with loops, i.e., {\tt (u,v)} is present if and only if {\tt (v,u)} is present, and {\tt (v,v)} is present. \par This program reads in the adjacency structure, decrements the offsets and indices by one if specified by the flag parameter (our application came from a Fortran code with 1-indexing), then loads the entries into a {\tt InpMtx} object where they are assembled and sorted by rows. The $(v,v)$ entries are loaded, and each vector of the adjacency structure is loaded as both a column and as a row, so in effect we are constructing the graph of $(A+A^T)$. Recall, multiple entries are collapsed during the sort and merge step. \par A {\tt Graph} object is then created using the {\tt Graph\_fillFromOffsets()} method using the vectors in the {\tt InpMtx} object. The {\tt Graph} object is then optionally written to a file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inAdjacencyFile} parameter is the input file for the adjacency structure as defined above. It must be a formatted file. \item The {\tt outGraphFile} parameter is the output file for the {\tt Graph} object. If {\tt outGraphFile} is {\tt none} then the {\tt Graph} object is not written to a file. Otherwise, the {\tt Graph\_writeToFile()} method is called to write the object to a formatted file (if {\tt outGraphFile} is of the form {\tt *.graphf}), or a binary file (if {\tt outGraphFile} is of the form {\tt *.graphb}). \item The {\tt flag} parameter is used to specify whether the offsets and indices are 0-indexed (as in C) or 1-indexed (as in Fortran). If they are 1-indexed, the offsets and indices are decremented prior to loading into the {\tt InpMtx} object. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} weightedAdjToGraph msglvl msgFile inAdjacencyFile outGraphFile flag \end{verbatim} This driver program was used to generate a {\tt type 1} {\tt Graph} object (weighted vertices, unit weight edges) from a file that contained the adjacency structure of a matrix in the following form. \begin{verbatim} nvtx nadj vwghts[nvtx] offsets[nvtx+1] indices[nadj] \end{verbatim} There are {\tt nvtx} vertices in the graph and the adjacency vector has {\tt nadj} entries. It was not known whether the adjacency structure contained {\tt (v,v)} entries or if it was only the upper or lower triangle. Our {\tt Graph} object is symmetric with loops, i.e., {\tt (u,v)} is present if and only if {\tt (v,u)} is present, and {\tt (v,v)} is present. \par This program reads in the adjacency structure, decrements the offsets and indices by one if specified by the flag parameter (our application came from a Fortran code with 1-indexing), then loads the entries into a {\tt InpMtx} object where they are assembled and sorted by rows. The $(v,v)$ entries are loaded, and each vector of the adjacency structure is loaded as both a column and as a row, so in effect we are constructing the graph of $(A+A^T)$. Recall, multiple entries are collapsed during the sort and merge step. \par A {\tt Graph} object is then created using the {\tt Graph\_fillFromOffsets()} method using the vectors in the {\tt InpMtx} object. The {\tt Graph} object is then optionally written to a file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inAdjacencyFile} parameter is the input file for the adjacency structure as defined above. It must be a formatted file. \item The {\tt outGraphFile} parameter is the output file for the {\tt Graph} object. If {\tt outGraphFile} is {\tt none} then the {\tt Graph} object is not written to a file. Otherwise, the {\tt Graph\_writeToFile()} method is called to write the object to a formatted file (if {\tt outGraphFile} is of the form {\tt *.graphf}), or a binary file (if {\tt outGraphFile} is of the form {\tt *.graphb}). \item The {\tt flag} parameter is used to specify whether the offsets and indices are 0-indexed (as in C) or 1-indexed (as in Fortran). If they are 1-indexed, the offsets and indices are decremented prior to loading into the {\tt InpMtx} object. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testR2D msglvl msgFile EGraphFile CoordsFile coordType seed outInpMtxFile \end{verbatim} This driver program reads in an {\tt EGraph} element graph and a {\tt Coords} grid point coordinate object for one of the {\tt R2D*} randomly triangulated 2-D grids. It then generates the finite element matrices for each of the triangular elements and assembles the matrices into a {\tt InpMtx} object, which is then optionally written out to a file. A matrix-vector product is computed using the unassembled matrix and the assembled matrix and compared to detect errors. The {\tt InpMtx} object is then permuted and a matrix-vector multiply again computed and checked for errors. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any message data. \item The {\tt EGraphFile} is the file that holds the {\tt EGraph} object --- must be of the form {\tt *.egraphf} or {\tt *.egraphb}. \item The {\tt CoordsFile} is the file that holds the {\tt Coords} object --- must be of the form {\tt *.coordsf} or {\tt *.coordsb}. \item The {\tt coordType} determines the coordinate type for the {\tt InpMtx} object. \begin{itemize} \item {\tt 1} --- storage of entries by rows \item {\tt 2} --- storage of entries by columns \item {\tt 3} --- storage of entries by chevrons \end{itemize} \item The {\tt seed} parameter is used as a random number seed to determine the row and column permutations for the matrix-vector multiply. \item The {\tt outInpMtxFile} parameter is the output file for the {\tt InpMtx} object. If {\tt outInpMtxFile} is {\tt none} then the {\tt InpMtx} object is not written to a file. Otherwise, the {\tt InpMtx\_writeToFile()} method is called to write the object to a formatted file (if {\tt outInpMtxFile} is of the form {\tt *.inpmtxf}), or a binary file (if {\tt outInpMtxFile} is of the form {\tt *.inpmtxb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} readAIJ msglvl msgFile inputFile outInpMtxFile flag \end{verbatim} This driver program reads $(i,j,a_{i,j})$ triples from a file, loads them into a {\tt InpMtx} object, and optionally writes the object out to a file. The input file has the form: \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any message data. \item The {\tt inputFile} is the file that holds the triples. It has the following form. \begin{verbatim} nrow ncol nentries irow jcol value ... irow jcol value \end{verbatim} Note, {\tt nrow} and {\tt ncol} are not used by the {\tt InpMtx} object --- each (irow, jcol, value) triple is loaded. \item The {\tt outInpMtxFile} parameter is the output file for the {\tt InpMtx} object. If {\tt outInpMtxFile} is {\tt none} then the {\tt InpMtx} object is not written to a file. Otherwise, the {\tt InpMtx\_writeToFile()} method is called to write the object to a formatted file (if {\tt outInpMtxFile} is of the form {\tt *.inpmtxf}), or a binary file (if {\tt outInpMtxFile} is of the form {\tt *.inpmtxb}). \item The {\tt flag} parameter is used to specify whether the indices are 0-indexed (as in C) or 1-indexed (as in Fortran). If they are 1-indexed, the indices are decremented prior to loading into the {\tt InpMtx} object. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} getProfile msglvl msgFile inInpMtxFile npts tausmall taubig \end{verbatim} This driver program produces a profile of the magnitudes of the matrix entries in a format that is suitable for plotting by Matlab. The {\tt npts} parameter specifies how many points to be used in the profile plot. The message file will contain line of the form. \begin{verbatim} data = [ ... x1 y1 ... xnpts ynpts ] ; \end{verbatim} which can be used to generate the following matlab plot. An example is given below for the {\sc bcsstk23} matrix, where {\tt npts = 200}, {\tt tausmall = 1.e-10} and {\tt taubig = 1.e100}. \begin{center} \makebox{ % \psfig{file=BCSSTK23.eps,width=3.0in,height=2.40in} \psfig{file=../../InpMtx/doc/BCSSTK23.eps,width=3.0in,height=2.40in} } \end{center} The number of entries that are zero, the number whose magnitude is less than {\tt tausmall}, and the number whose magnitude is larger than {\tt taubig} are printed to {\tt msgFile}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inInpMtxFile} parameter is the input file for the {\tt InpMtx} object that holds the matrix. It must be of the form {\tt *.inpmtxf} or {\tt *.inpmtxb}. The {\tt InpMtx} object is read from the file via the {\tt InpMtx\_readFromFile()} method. \item The {\tt npts} parameter determines the number of points to use in the plot. \item The {\tt tausmall} parameter is a lower cutoff for putting entries in the profile plot. \item The {\tt taubig} parameter is an upper cutoff for putting entries in the profile plot. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} mkNaturalFactorMtx msglvl msgFile n1 n2 n3 seed outFile \end{verbatim} This driver program generates rectangular matrix that would arise from a natural factor representation of the Laplacian operator on a regular grid. If {\tt n3 = 1}, we have a ${\tt n1} \times {\tt n2}$ grid. There are {\tt (n1-1)*(n2-1)} elements and each element gives rise to four equations, so the resulting matrix has {\tt 4(n1-1)*(n2-1)} rows and {\tt n1*n2} columns. If {\tt n3 > 1}, we have a ${\tt n1} \times {\tt n2} \times {\tt n3}$ grid. There are {\tt (n1-1)*(n2-1)*(n3-1)} elements and each element gives rise to eight equations, so the resulting matrix has {\tt 8(n1-1)*(n2-1)*(n3-1)} rows and {\tt n1*n2*n3} columns. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt n1} is the number of points in the first direction. \item {\tt n2} is the number of points in the second direction. \item {\tt n3} is the number of points in the third direction. \item The {\tt seed} parameter is a random number seed used to fill the matrix entries with random numbers. \item The {\tt outFile} parameter is the output file for the {\tt InpMtx} object that holds the matrix. It must be of the form {\tt *.inpmtxf} or {\tt *.inpmtxb}. The {\tt InpMtx} object is written to the file via the {\tt InpMtx\_writeToFile()} method. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testMMM msglvl msgFile dataType symflag coordType transpose nrow ncol nitem nrhs seed alphaReal alphaImag \end{verbatim} This driver program tests the matrix-matrix multiply methods. This driver program generates $A$, a ${\tt nrow} \times {\tt ncol}$ matrix using {\tt nitem} input entries, $X$ and $Y$, ${\tt nrow} \times {\tt nrhs}$ matrices, and all are filled with random numbers. It then computes $Y := Y + \alpha A X$, $Y := Y + \alpha A^T X$ or $Y := Y + \alpha A^H X$. The program's output is a file which when sent into Matlab, outputs the error in the computation. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt dataType} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item {\tt symflag} is the symmetry flag, {\tt 0} for symmetric, {\tt 1} for Hermitian, {\tt 2} for nonsymmetric. \item {\tt coordType} is the storage mode for the entries, {\tt 1} for by rows, {\tt 2} for by columns, {\tt 3} for by chevrons. \item {\tt transpose} determines the equation, {\tt 0} for $Y := Y + \alpha A X$, {\tt 1} for $Y := Y + \alpha A^H X$ or {\tt 2} for $Y := Y + \alpha A^T X$. \item {\tt nrowA} is the number of rows in $A$ \item {\tt ncolA} is the number of columns in $A$ \item {\tt nitem} is the number of matrix entries that are assembled into the matrix. \item {\tt nrhs} is the number of columns in $X$ and $Y$. \item The {\tt seed} parameter is a random number seed used to fill the matrix entries with random numbers. \item {\tt alphaReal} and {\tt alphaImag} form the scalar in the multiply. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testGMMM msglvl msgFile dataType symflag coordType transpose nrow ncol nitem nrhs seed alphaReal alphaImag betaReal betaImag \end{verbatim} This driver program tests the generalized matrix-matrix multiply methods. It generates $A$, a ${\tt nrow} \times {\tt ncol}$ matrix using {\tt nitem} input entries, $X$ and $Y$, ${\tt nrow} \times {\tt nrhs}$ matrices, and all are filled with random numbers. It then computes $Y := \beta Y + \alpha A X$, $Y := \beta Y + \alpha A^T X$ or $Y := \beta Y + \alpha A^H X$. The program's output is a file which when sent into Matlab, outputs the error in the computation. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt dataType} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item {\tt symflag} is the symmetry flag, {\tt 0} for symmetric, {\tt 1} for Hermitian, {\tt 2} for nonsymmetric. \item {\tt coordType} is the storage mode for the entries, {\tt 1} for by rows, {\tt 2} for by columns, {\tt 3} for by chevrons. \item {\tt transpose} determines the equation, {\tt 0} for $Y := \beta Y + \alpha A X$, {\tt 1} for $Y := \beta Y + \alpha A^H X$ or {\tt 2} for $Y := \beta Y + \alpha A^T X$. \item {\tt nrowA} is the number of rows in $A$ \item {\tt ncolA} is the number of columns in $A$ \item {\tt nitem} is the number of matrix entries that are assembled into the matrix. \item {\tt nrhs} is the number of columns in $X$ and $Y$. \item The {\tt seed} parameter is a random number seed used to fill the matrix entries with random numbers. \item {\tt alphaReal} and {\tt alphaImag} form the $\alpha$ scalar in the multiply. \item {\tt betaReal} and {\tt betaImag} form the $\beta$ scalar in the multiply. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testGMVM msglvl msgFile dataType symflag coordType transpose nrow ncol nitem seed alphaReal alphaImag betaReal betaImag \end{verbatim} This driver program tests the generalized matrix-vector multiply methods. It generates $A$, a ${\tt nrow} \times {\tt ncol}$ matrix using {\tt nitem} input entries, $x$ and $y$, and fills the matrices with random numbers. It then computes $y := \beta y + \alpha A x$, $y := \beta y + \alpha A^T x$ or $y := \beta y + \alpha A^H x$. The program's output is a file which when sent into Matlab, outputs the error in the computation. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt dataType} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item {\tt symflag} is the symmetry flag, {\tt 0} for symmetric, {\tt 1} for Hermitian, {\tt 2} for nonsymmetric. \item {\tt coordType} is the storage mode for the entries, {\tt 1} for by rows, {\tt 2} for by columns, {\tt 3} for by chevrons. \item {\tt transpose} determines the equation, {\tt 0} for $y := \beta y + \alpha A x$, {\tt 1} for $y := \beta y + \alpha A^T x$ or {\tt 2} for $y := \beta y + \alpha A^H x$. \item {\tt nrowA} is the number of rows in $A$ \item {\tt ncolA} is the number of columns in $A$ \item {\tt nitem} is the number of matrix entries that are assembled into the matrix. \item The {\tt seed} parameter is a random number seed used to fill the matrix entries with random numbers. \item {\tt alphaReal} and {\tt alphaImag} form the $\alpha$ scalar in the multiply. \item {\tt betaReal} and {\tt betaImag} form the $\beta$ scalar in the multiply. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testHBIO msglvl msgFile inFile outFile \end{verbatim} This driver program read in a matrix from a Harwell-Boeing file, and optionally writes it to a formatted or binary {\tt InpMtx} file. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the Harwell-Boeing file. \item The {\tt outFile} parameter is the output file for the {\tt InpMtx} object. If {\tt outFile} is {\tt none} then the {\tt InpMtx} object is not written to a file. Otherwise, the {\tt InpMtx\_writeToFile()} method is called to write the object to a formatted file (if {\tt outFile} is of the form {\tt *.inpmtxf}), or a binary file (if {\tt outFile} is of the form {\tt *.inpmtxb}). \end{itemize} %----------------------------------------------------------------------- \end{enumerate} }, and the number whose magnitude is larger than {\tt taubig} are printed to {\tt msgFile}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- tInpMtx/doc/intro.tex010064400020550007177000000117720657603055700157570ustar00clevecompmath00000400000006\chapter{{\tt InpMtx}: Input Matrix Object} \label{chapter:InpMtx} \par The {\tt InpMtx} object has two functions: \begin{itemize} \item It is used to assemble a sparse matrix (or just its structure) from individual entries, rows, columns or dense submatrices (or any combination of these) that may overlap. \item It is used to communicate entries of a matrix into a front during the factorization. \end{itemize} We have designed this object to be easy to use, but it has one significant drawback --- it is an in-core implementation, and this is a disadvantage in situations where memory is limited. Extending this object to work out-of-core is not difficult, but we leave that {\it value-added} function to others in the future. \par The {\tt InpMtx} object has three faces. It can just manipulate $(i,j)$ pairs, where it assembles just the nonzero structure of a matrix. We use this functionality to generate a {\tt Graph} object that is needed as input to the ordering software. Alternatively, it can assemble and manipulate $(i,j,a_{i,j}$ triples where $a_{i,j}$ is either a real or complex number. (At any one time, the object works with either no numbers, real numbers or complex numbers but not mixtures of the three.) The normal input to the {\tt InpMtx} object is a collection of matrix entries in some form, e.g., single entries, (partial) rows or columns, or dense submatrices. \par Here is a common sequence of events to use this object when we want to build the structure of a sparse matrix. \begin{enumerate} \item Create an instance of a {\tt InpMtx} object using the {\tt InpMtx\_new()} method. \item Initialize the {\tt InpMtx} object using the {\tt InpMtx\_init()} method; set the input mode to indices only, maximum number of entries for the workspace, and the number of vectors. (The latter two quantities may be zero, for the object resizes its storage as required.) \item Call the method {\tt InpMtx\_changeCoordType()} to set the coordinate type to rows. \item Load data into the object using one or more of the five input methods: {\tt InpMtx\_inputEntry()}, {\tt InpMtx\_inputRow()}, {\tt InpMtx\_inputColumn()}, {\tt InpMtx\_inputMatrix()} and {\tt InpMtx\_inputTriples()} methods. Each time the workspace fills up, the raw data is sorted and compressed and then the workspace is resized. If the input data overlaps, e.g., elemental matrices are being assembled, it would be efficient to have sufficient elbow room to minimize the number of sorts and compressions. In this case, a tight upper bound on the necessary storage is the sum of the sizes of the elemental matrices. The entries are assembled by a call to {\tt InpMtx\_changeStorageMode()}. \item Create an {\tt IVL} object that contains the full adjacency of $A + A^T$ by calling the {\tt InpMtx\_fullAdjacency()} method. \item Create a {\tt Graph} object using the {\tt Graph\_init2()} method and the {\tt IVL} object as an input argument. \end{enumerate} A similar functionality exists for creating a {\tt Graph} object from a linear combination of two {\tt InpMtx} objects that contains the matrices $A$ and $B$. The {\tt InpMtx\_fullAdjacency2()} method returns an {\tt IVL} object with the full adjacency of $(A+B) + (A+B)^T$. These two methods are called by the {\tt DPencil\_fullAdjacency()} methods to return the full adjacency of a matrix pencil. \par Here is a common sequence of events to use this object when we want to assemble the entries of a sparse matrix. \begin{enumerate} \item Create an instance of a {\tt InpMtx} object using the {\tt InpMtx\_new()} method. \item Initialize the {\tt InpMtx} object using the {\tt InpMtx\_init()} method; set the input mode to real or complex entries, maximum number of entries for the workspace, and the number of vectors. (The latter two quantities may be zero, for the object resizes its storage as required.) \item Call the method {\tt InpMtx\_changeCoordType()} to set the coordinate type to rows. \item Load data into the object using one or more of the five input methods: {\tt InpMtx\_inputEntry()}, {\tt InpMtx\_inputRow()}, {\tt InpMtx\_inputColumn()}, {\tt InpMtx\_inputMatrix()} and {\tt InpMtx\_inputTriples()} methods. Each time the workspace fills up, the raw data is sorted and compressed and then the workspace is resized. If the input data overlaps, e.g., elemental matrices are being assembled, it would be efficient to have sufficient elbow room to minimize the number of sorts and compressions. In this case, a tight upper bound on the necessary storage is the sum of the sizes of the elemental matrices. The entries are assembled by a call to {\tt InpMtx\_changeStorageMode()}. \end{enumerate} The {\tt InpMtx} object is now ready to be permuted, take part in a matrix-vector multiply, become part of a {\tt Pencil} matrix pencil object, or serve as input to a numeric factorization. \par {\bf NOTE:} to improve performance we have changed the {\tt InpMtx\_fullAdjacency()} method. The {\tt InpMtx} object must be in the chevron coordinate type and have its storage mode be by vectors. Previously, this was done if necessary inside the method. InpMtx/doc/main.tex010064400020550007177000000011750665065625400155450ustar00clevecompmath00000400000006% % main TeX file % % \documentstyle[leqno,11pt,twoside]{report} \documentclass[leqno,10pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt InpMtx} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt InpMtx} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} InpMtx/doc/proto.tex010064400020550007177000001665440665022214300157620ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt InpMtx} methods} \label{section:InpMtx:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt InpMtx} object. \par \subsection{Basic methods} \label{subsection:InpMtx:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} InpMtx * InpMtx_new ( void ) ; \end{verbatim} \index{InpMtx_new@{\tt InpMtx\_new()}} This method simply allocates storage for the {\tt InpMtx} structure and then sets the default fields by a call to {\tt InpMtx\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_setDefaultFields ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_setDefaultFields@{\tt InpMtx\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt coordType} = {\tt INPMTX\_BY\_ROWS}, {\tt storageMode} = {\tt INPMTX\_RAW\_DATA}, {\tt inputMode} = {\tt SPOOLES\_REAL}, {\tt resizeMultiple} = 1.25, and {\tt maxnent} = {\tt nent} = {\tt maxnvector} = {\tt nvector} = 0. The {\tt IV} and {\tt DV} objects have their fields set to their default values via calls to {\tt IV\_setDefaultFields()} and {\tt DV\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_clearData ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_clearData@{\tt InpMtx\_clearData()}} This method releases all storage held by the object. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_free ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_free@{\tt InpMtx\_free()}} This method releases all storage held by the object via a call to {\tt InpMtx\_clearData()}, then free'd the storage for the object. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance Methods} \label{subsection:InpMtx:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_coordType ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_coordType@{\tt InpMtx\_coordType()}} This method returns the coordinate type. \begin{itemize} \item {\tt INPMTX\_NO\_TYPE} -- none specified \item {\tt INPMTX\_BY\_ROWS} -- storage by row triples \item {\tt INPMTX\_BY\_COLUMNS} -- storage by column triples \item {\tt INPMTX\_BY\_CHEVRONS} -- storage by chevron triples \item {\tt INPMTX\_CUSTOM} -- custom type \end{itemize} \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_storageMode ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_storageMode@{\tt InpMtx\_storageMode()}} This method returns the storage mode. \begin{itemize} \item {\tt INPMTX\_NO\_MODE} -- none specified \item {\tt INPMTX\_RAW\_DATA} -- raw triples \item {\tt INPMTX\_SORTED} -- sorted and distinct triples \item {\tt INPMTX\_BY\_VECTORS} -- vectors by the first coordinate \end{itemize} \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_inputMode ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_inputMode@{\tt InpMtx\_inputMode()}} This method returns the input mode. \begin{itemize} \item {\tt INPMTX\_INDICES\_ONLY} -- indices only \item {\tt SPOOLES\_REAL} -- indices and real entries \item {\tt SPOOLES\_COMPLEX} -- indices and complex entries \end{itemize} \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_maxnent ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_maxnent@{\tt InpMtx\_maxnent()}} This method returns the maximum number of entries. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_nent ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_nent@{\tt InpMtx\_nent()}} This method returns the present number of entries. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_maxnvector ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_maxnvector@{\tt InpMtx\_maxnvector()}} This method returns the maximum number of vectors. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_nvector ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_nvector@{\tt InpMtx\_nvector()}} This method returns the present number of vectors. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double InpMtx_resizeMultiple ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_resizeMultiple@{\tt InpMtx\_resizeMultiple()}} This method returns the present resize multiple for the storage of entries. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * InpMtx_ivec1 ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_ivec1@{\tt InpMtx\_ivec1()}} This method returns the base address of the {\tt ivec1[]} vector. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * InpMtx_ivec2 ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_ivec2@{\tt InpMtx\_ivec2()}} This method returns the base address of the {\tt ivec2[]} vector. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double * InpMtx_dvec ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_dvec@{\tt InpMtx\_dvec()}} This method returns the base address of the {\tt dvec[]} vector. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * InpMtx_vecids ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_vecids@{\tt InpMtx\_vecids()}} This method returns the base address of the {\tt vecids[]} vector. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * InpMtx_sizes ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_sizes@{\tt InpMtx\_sizes()}} This method returns the base address of the {\tt sizes[]} vector. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * InpMtx_offsets ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_offsets@{\tt InpMtx\_offsets()}} This method returns the base address of the {\tt offsets[]} vector. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_vector ( InpMtx *inpmtx, int id, int *pnent, int **pindices ) ; void InpMtx_realVector ( InpMtx *inpmtx, int id, int *pnent, int **pindices, double **pentries ) ; void InpMtx_complexVector ( InpMtx *inpmtx, int id, int *pnent, int **pindices, double **pentries ) ; \end{verbatim} \index{InpMtx_vector@{\tt InpMtx\_vector()}} \index{InpMtx_realVector@{\tt InpMtx\_realVector()}} \index{InpMtx_complexVector@{\tt InpMtx\_complexVector()}} This methods fills {\tt *pnent} with the number of entries in vector {\tt id} and sets {\tt *pindices} to the base address of the indices. When the object stores real or complex matrix entries, the methods sets {\tt *pentries} to the base address of the entries. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if ${\tt storageMode} \ne {\tt INPMTX\_BY\_VECTORS}$, or if {\tt id} is out of range, or if {\tt pnent}, {\tt pindices} or {\tt pentries} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_range ( InpMtx *inpmtx, int *pmincol, int *pmaxcol, int *pminrow, int *pmaxrow ) ; \end{verbatim} \index{InpMtx_range@{\tt InpMtx\_range()}} This method computes and returns the minimum and maximum rows and columns in the matrix. If {\tt pmincol} is not {\tt NULL}, on return {\tt *pmincol} is filled with the minimum column id. If {\tt pmaxcol} is not {\tt NULL}, on return {\tt *pmaxcol} is filled with the maximum column id. If {\tt pminrow} is not {\tt NULL}, on return {\tt *pminrow} is filled with the minimum row id. If {\tt pmaxrow} is not {\tt NULL}, on return {\tt *pmaxrow} is filled with the maximum row id. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt mtx} is {\tt NULL} \\ \end{tabular} \quad \begin{tabular}{rl} -2 & no entries in the matrix \\ -3 & invalid coordinate type \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_setMaxnent ( InpMtx *inpmtx, int newmaxnent ) ; \end{verbatim} \index{InpMtx_setMaxnent@{\tt InpMtx\_setMaxnent()}} This method sets the maxinum number of entries in the indices and entries vectors. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if ${\tt newmaxnent} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_setNent ( InpMtx *inpmtx, int newnent ) ; \end{verbatim} \index{InpMtx_setNent@{\tt InpMtx\_setNent()}} This method sets the present number of entries in the indices and entries vectors. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if ${\tt newnent} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_setMaxnvector ( InpMtx *inpmtx, int newmaxnvector ) ; \end{verbatim} \index{InpMtx_setMaxnvector@{\tt InpMtx\_setMaxnvector()}} This method sets the maxinum number of vectors. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if ${\tt newmaxnvector} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_setNvector ( InpMtx *inpmtx, int newnvector ) ; \end{verbatim} \index{InpMtx_setNvector@{\tt InpMtx\_setNvector()}} This method sets the present number of vectors. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if ${\tt newnvector} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_setResizeMultiple ( InpMtx *inpmtx, double resizeMultiple ) ; \end{verbatim} \index{InpMtx_setResizeMultiple@{\tt InpMtx\_setResizeMultiple()}} This method sets the present number of vectors. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if ${\tt resizeMultiple} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_setCoordType ( InpMtx *inpmtx, int type ) ; \end{verbatim} \index{InpMtx_setCoordType@{\tt InpMtx\_setCoordType()}} This method sets a custom coordinate type, so type must be greater than or equal to {\tt 4}. To change from one of the three supported types to another, use {\tt InpMtx\_changeCoordType()}. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if ${\tt coordType} <= 3$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Methods to initialize and change state} \label{subsection:InpMtx:proto:initializers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_init ( InpMtx *inpmtx, int coordType, int inputMode, int maxnent, int maxnvector) ; \end{verbatim} \index{InpMtx_init@{\tt InpMtx\_init()}} This is the initializer method that should be called immediately after {\tt InpMtx\_new()}. It first clears any previous data with a call to {\tt InpMtx\_clearData()}. The {\tt coordType} and {\tt inputMode} fields are set. If {\tt maxnent > 0} then the {\tt ivec1IV} and {\tt ivec2IV} objects are initialized to have size {\tt maxnent}. If {\tt maxnent > 0} and {\tt inputMode = SPOOLES\_REAL} or {\tt inputMode = SPOOLES\_COMPLEX} , then the {\tt dvecDV} object is initialized to have size {\tt maxnent}. If {\tt maxnvector > 0} then the {\tt sizesIV} and {\tt offsetsIV} objects are initialized to have size {\tt maxnvector}. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL} or if {\tt coordType} or {\tt inputMode} is invalid, or if {\tt maxnent} or {\tt maxnvector} are less than zero, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_changeCoordType ( InpMtx *inpmtx, int newType ) ; \end{verbatim} \index{InpMtx_changeCoordType@{\tt InpMtx\_changeCoordType()}} This method changes the coordinate type. If ${\tt coordType} = {\tt newType}$, the program returns. If ${\tt coordType} \ge 4$, then the triples are held in some unknown custom type and cannot be translated, so an error message is printed and the program exits. If ${\tt newType} \ge 4$, then some custom coordinate type is now present; the {\tt coordType} field is set and the method returns. If {\tt newType} is one of {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}, a translation is made from the old coordinate type to the new type. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL} or {\tt newType} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_changeStorageMode ( InpMtx *inpmtx, int newMode ) ; \end{verbatim} \index{InpMtx_changeStorageMode@{\tt InpMtx\_changeStorageMode()}} If {\tt storageMode} = {\tt newMode}, the method returns. Otherwise, a translation between the three valid modes is made by calling {\tt InpMtx\_sortAndCompress()} and {\tt InpMtx\_convertToVectors()}, as appropriate. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL} or {\tt newMode} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Input methods} \label{subsection:InpMtx:proto:input} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_inputEntry ( InpMtx *inpmtx, int row, int col ) ; void InpMtx_inputRealEntry ( InpMtx *inpmtx, int row, int col, double value ) ; void InpMtx_inputComplexEntry ( InpMtx *inpmtx, int row, int col, double real, double imag ) ; \end{verbatim} \index{InpMtx_inputEntry@{\tt InpMtx\_inputEntry()}} \index{InpMtx_inputRealEntry@{\tt InpMtx\_inputRealEntry()}} \index{InpMtx_inputComplexEntry@{\tt InpMtx\_inputComplexEntry()}} This method places a single entry into the matrix object. The coordinate type of the object must be {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}. The triple is formed and inserted into the vectors, which are resized if necessary. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL} or {\tt row} or {\tt col} are negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_inputRow ( InpMtx *inpmtx, int row, int rowsize, int rowind[] ) ; void InpMtx_inputRealRow ( InpMtx *inpmtx, int row, int rowsize, int rowind[], double rowent[] ) ; void InpMtx_inputComplexRow ( InpMtx *inpmtx, int row, int rowsize, int rowind[], double rowent[] ) ; \end{verbatim} \index{InpMtx_inputRow@{\tt InpMtx\_inputRow()}} \index{InpMtx_inputRealRow@{\tt InpMtx\_inputRealRow()}} \index{InpMtx_inputComplexRow@{\tt InpMtx\_inputComplexRow()}} This method places a row or row fragment into the matrix object. The coordinate type of the object must be {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}. The individual entries of the row are placed into the vector storage as triples, and the vectors are resized if necessary. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or {\tt row} or {\tt rowsize} are negative, or {\tt rowind} or {\tt rowent} are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_inputColumn ( InpMtx *inpmtx, int col, int colsize, int colind[] ) ; void InpMtx_inputRealColumn ( InpMtx *inpmtx, int col, int colsize, int colind[], double colent[] ) ; void InpMtx_inputComplexColumn ( InpMtx *inpmtx, int col, int colsize, int colind[], double colent[] ) ; \end{verbatim} \index{InpMtx_inputColumn@{\tt InpMtx\_inputColumn()}} \index{InpMtx_inputRealColumn@{\tt InpMtx\_inputRealColumn()}} \index{InpMtx_inputComplexColumn@{\tt InpMtx\_inputComplexColumn()}} This method places a column or column fragment into the matrix object. The coordinate type of the object must be {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}. The individual entries of the column are placed into the vector storage as triples, and the vectors are resized if necessary. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or {\tt col} or {\tt colsize} are negative, or {\tt colind} or {\tt colent} are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_inputChevron ( InpMtx *inpmtx, int chv, int chvsize, int chvind[] ) ; void InpMtx_inputRealChevron ( InpMtx *inpmtx, int chv, int chvsize, int chvind[], double chvent[] ) ; void InpMtx_inputComplexChevron ( InpMtx *inpmtx, int chv, int chvsize, int chvind[], double chvent[] ) ; \end{verbatim} \index{InpMtx_inputChevron@{\tt InpMtx\_inputChevron()}} \index{InpMtx_inputRealChevron@{\tt InpMtx\_inputRealChevron()}} \index{InpMtx_inputComplexChevron@{\tt InpMtx\_inputComplexChevron()}} This method places a chevron or chevron fragment into the matrix object. The coordinate type of the object must be {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}. The individual entries of the chevron are placed into the vector storage as triples, and the vectors are resized if necessary. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or {\tt chv} or {\tt chvsize} are negative, or {\tt chvind} or {\tt chvent} are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_inputMatrix ( InpMtx *inpmtx, int nrow, int col, int rowstride, int colstride, int rowind[], int colind[] ) ; void InpMtx_inputRealMatrix ( InpMtx *inpmtx, int nrow, int col, int rowstride, int colstride, int rowind[], int colind[], double mtxent[] ) ; void InpMtx_inputComplexMatrix ( InpMtx *inpmtx, int nrow, int col, int rowstride, int colstride, int rowind[], int colind[], double mtxent[] ) ; \end{verbatim} \index{InpMtx_inputMatrix@{\tt InpMtx\_inputMatrix()}} \index{InpMtx_inputRealMatrix@{\tt InpMtx\_inputRealMatrix()}} \index{InpMtx_inputComplexMatrix@{\tt InpMtx\_inputComplexMatrix()}} This method places a dense submatrix into the matrix object. The coordinate type of the object must be {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}. The individual entries of the matrix are placed into the vector storage as triples, and the vectors are resized if necessary. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or {\tt col} or {\tt row} are negative, or {\tt rowstride} or {\tt colstride} are less than {\tt 1}, or {\tt rowind}, {\tt colind} or {\tt mtxent} are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_inputTriples ( InpMtx *inpmtx, int ntriples, int rowids[], int colids[]) ; void InpMtx_inputRealTriples ( InpMtx *inpmtx, int ntriples, int rowids[], int colids[], double entries[] ) ; void InpMtx_inputComplexTriples ( InpMtx *inpmtx, int ntriples, int rowids[], int colids[], double entries[] ) ; \end{verbatim} \index{InpMtx_inputTriples@{\tt InpMtx\_inputTriples()}} \index{InpMtx_inputRealTriples@{\tt InpMtx\_inputRealTriples()}} \index{InpMtx_inputComplexTriples@{\tt InpMtx\_inputComplexTriples()}} This method places a vector of (row,column,entry) triples into the matrix object. The coordinate type of the object must be {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}. \par \noindent {\it Error checking:} If {\tt inpmtx}, {\tt rowids}, {\tt colids} is {\tt NULL}, or {\tt ntriples} are negative, or if {\tt inputMode = 2} and {\tt entries} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Permutation, map and support methods} \label{subsection:InpMtx:proto:permute} \par These methods find the {\it support} of a matrix, map the indices from one numbering to another, and permute the rows and/or columns of the matrix. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_supportNonsym ( InpMtx *A, IV *rowsupIV, IV *colsupIV ) ; void InpMtx_supportNonsymT ( InpMtx *A, IV *rowsupIV, IV *colsupIV ) ; void InpMtx_supportNonsymH ( InpMtx *A, IV *rowsupIV, IV *colsupIV ) ; \end{verbatim} \index{InpMtx_supportNonsym@{\tt InpMtx\_supportNonsym()}} \index{InpMtx_supportNonsymT@{\tt InpMtx\_supportNonsymT()}} \index{InpMtx_supportNonsymH@{\tt InpMtx\_supportNonsymH()}} These methods are used to set up sparse matrix-matrix multiplies of the form $Y := Y + \alpha A X$, $Y := Y + \alpha A^T X$ or $Y := Y + \alpha A^H X$, where $A$ is a nonsymmetric matrix. These methods fill {\tt rowsupIV} with the rows of $Y$ that will be updated, and {\tt colsupIV} with the rows of $X$ that will be accessed. In a distributed environment, $A$, $X$ and $Y$ will be distributed, and {\tt A} will contain only part of the larger global matrix $A$. Finding the row an column support enables one to construct local data structures for $X$ and the product $\alpha A X$. \par \noindent {\it Error checking:} If {\tt A}, {\tt rowsupIV} or {\tt colsupIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_supportSym ( InpMtx *A, IV *supIV ) ; void InpMtx_supportSymH ( InpMtx *A, IV *supIV ) ; \end{verbatim} \index{InpMtx_supportSym@{\tt InpMtx\_supportSym()}} \index{InpMtx_supportSymH@{\tt InpMtx\_supportSymH()}} These methods are used to set up sparse matrix-matrix multiplies of the form $Y := Y + \alpha A X$ where $A$ is a symmetric or Hermitian matrix. These methods fill {\tt supIV} with the rows of $Y$ that will be updated. Since $A$ has symmetric nonzero structure, the rows of $Y$ that will be updated are exactly the same as the rows of $X$ that will be accessed. In a distributed environment, $A$, $X$ and $Y$ will be distributed, and {\tt A} will contain only part of the larger global matrix $A$. Finding the row an column support enables one to construct local data structures for $X$ and the product $\alpha A X$. \par \noindent {\it Error checking:} If {\tt A} or {\tt supIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_mapEntries ( InpMtx *A, IV *rowmapIV, IV *colmapIV ) ; \end{verbatim} \index{InpMtx_mapEntries@{\tt InpMtx\_mapEntries()}} These methods are used to map a matrix from one numbering system to another. The primary use of this method is to map a part of a distributed matrix between the global and local numberings. \par \noindent {\it Error checking:} If {\tt A}, {\tt rowmapIV} or {\tt colmapIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_permute ( InpMtx *inpmtx, int rowOldToNew[], int colOldToNew[] ) ; \end{verbatim} \index{InpMtx_permute@{\tt InpMtx\_permute()}} This method permutes the rows and or columns of the matrix. If {\tt rowOldToNew} and {\tt colOldToNew} are both {\tt NULL}, or if there are no entries in the matrix, the method returns. Note, either {\tt rowOldToNew} or {\tt colOldToNew} can be {\tt NULL}. If {\tt coordType == INPMTX\_BY\_CHEVRONS}, then the coordinates are changed to row coordinates. The coordinates are then mapped to their new values. The {\tt storageMode} is set to {\tt 1}, (raw triples). \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Matrix-matrix multiply methods} \label{subsection:InpMtx:proto:mvm} \par There are four families of matrix-vector and matrix-matrix multiply methods. The {\tt InpMtx\_*\_mmm*()} methods compute $$ Y := Y + \alpha A X, \qquad Y := Y + \alpha A^T X \qquad \mbox{\ and\ } \qquad Y := Y + \alpha A^H X, $$ where $A$ is an {\tt InpMtx} object, and $X$ and $Y$ are column major {\tt DenseMtx} objects. The {\tt InpMtx\_*\_mmmVector*()} methods compute $$ y := y + \alpha A x, \qquad y := y + \alpha A^T x \qquad \mbox{\ and\ } \qquad y := y + \alpha A^H x, $$ where $A$ is an {\tt InpMtx} object, and $x$ and $y$ are vectors. The {\tt InpMtx\_*\_gmmm*()} methods compute $$ Y := \beta Y + \alpha A X, \qquad Y := \beta Y + \alpha A^T X \qquad \mbox{\ and\ } \qquad Y := \beta Y + \alpha A^H X, $$ where $A$ is an {\tt InpMtx} object, and $X$ and $Y$ are column major {\tt DenseMtx} objects. The {\tt InpMtx\_*\_gmvm*()} methods compute $$ y := \beta y + \alpha A x, \qquad y := \beta y + \alpha A^T x \qquad \mbox{\ and\ } \qquad y := \beta y + \alpha A^H x, $$ where $A$ is an {\tt InpMtx} object, and $x$ and $y$ are {\tt double} vectors. The code notices if $\alpha$ and/or $\beta$ are zero or 1 and takes special action. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_nonsym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; void InpMtx_sym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; void InpMtx_herm_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; void InpMtx_nonsym_mmm_T ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; void InpMtx_nonsym_mmm_H ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; \end{verbatim} \index{InpMtx_nonsym_mmm@{\tt InpMtx\_nonsym\_mmm()}} \index{InpMtx_sym_mmm@{\tt InpMtx\_sym\_mmm()}} \index{InpMtx_herm_mmm@{\tt InpMtx\_herm\_mmm()}} \index{InpMtx_nonsym_mmm_T@{\tt InpMtx\_nonsym\_mmm\_T()}} \index{InpMtx_nonsym_mmm_H@{\tt InpMtx\_nonsym\_mmm\_H()}} These five methods perform the following computations. \begin{center} \begin{tabular}{llll} {\tt InpMtx\_nonsym\_mmm()} & $Y := Y + \alpha A X$ & nonsymmetric & real or complex \\ {\tt InpMtx\_sym\_mmm()} & $Y := Y + \alpha A X$ & symmetric & real or complex \\ {\tt InpMtx\_herm\_mmm()} & $Y := Y + \alpha A X$ & Hermitian & complex \\ {\tt InpMtx\_nonsym\_mmm\_T()} & $Y := Y + \alpha A^T X$ & nonsymmetric & real or complex \\ {\tt InpMtx\_nonsym\_mmm\_H()} & $Y := Y + \alpha A^H X$ & nonsymmetric & complex \end{tabular} \end{center} {\tt A}, {\tt X} and {\tt Y} must all be real or all be complex. When {\tt A} is real, then $\alpha$ = {\tt alpha[0]}. When {\tt A} is complex, then $\alpha$ = {\tt alpha[0]} + i* {\tt alpha[1]}. The values of $\alpha$ must be loaded into an array of length 1 or 2. \par \noindent {\it Error checking:} If {\tt A}, {\tt Y} or {\tt X} are {\tt NULL}, or if {\tt coordType} is not {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}, or if {\tt storageMode} is not one of {\tt INPMTX\_RAW\_DATA}, {\tt INPMTX\_SORTED} or {\tt INPMTX\_BY\_VECTORS}, or if {\tt inputMode} is not {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_nonsym_mmmVector ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; void InpMtx_sym_mmmVector ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; void InpMtx_herm_mmmVector ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; void InpMtx_nonsym_mmmVector_T ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; void InpMtx_nonsym_mmmVector_H ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X ) ; \end{verbatim} \index{InpMtx_nonsym_mmmVector@{\tt InpMtx\_nonsym\_mmmVector()}} \index{InpMtx_sym_mmmVector@{\tt InpMtx\_sym\_mmmVector()}} \index{InpMtx_herm_mmmVector@{\tt InpMtx\_herm\_mmmVector()}} \index{InpMtx_nonsym_mmmVector_T@{\tt InpMtx\_nonsym\_mmmVector\_T()}} \index{InpMtx_nonsym_mmmVector_H@{\tt InpMtx\_nonsym\_mmmVector\_H()}} These five methods perform the following computations. \begin{center} \begin{tabular}{llll} {\tt InpMtx\_nonsym\_mmm()} & $y := y + \alpha A x$ & nonsymmetric & real or complex \\ {\tt InpMtx\_sym\_mmm()} & $y := y + \alpha A x$ & symmetric & real or complex \\ {\tt InpMtx\_herm\_mmm()} & $y := y + \alpha A x$ & Hermitian & complex \\ {\tt InpMtx\_nonsym\_mmm\_T()} & $y := y + \alpha A^T x$ & nonsymmetric & real or complex \\ {\tt InpMtx\_nonsym\_mmm\_H()} & $y := y + \alpha A^H x$ & nonsymmetric & complex \end{tabular} \end{center} {\tt A}, {\tt x} and {\tt y} must all be real or all be complex. When {\tt A} is real, then $\alpha$ = {\tt alpha[0]}. When {\tt A} is complex, then $\alpha$ = {\tt alpha[0]} + i* {\tt alpha[1]}. The values of $\alpha$ must be loaded into an array of length 1 or 2. \par \noindent {\it Error checking:} If {\tt A}, {\tt x} or {\tt x} are {\tt NULL}, or if {\tt coordType} is not {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}, or if {\tt storageMode} is not one of {\tt INPMTX\_RAW\_DATA}, {\tt INPMTX\_SORTED} or {\tt INPMTX\_BY\_VECTORS}, or if {\tt inputMode} is not {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_nonsym_gmmm ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) ; int InpMtx_sym_gmmm ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) ; int InpMtx_herm_gmmm ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) ; int InpMtx_nonsym_gmmm_T ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) ; int InpMtx_nonsym_gmmm_H ( InpMtx *A, double beta[], DenseMtx *Y, double alpha[], DenseMtx *X ) ; \end{verbatim} \index{InpMtx_nonsym_gmmm@{\tt InpMtx\_nonsym\_gmmm()}} \index{InpMtx_sym_gmmm@{\tt InpMtx\_sym\_gmmm()}} \index{InpMtx_herm_gmmm@{\tt InpMtx\_herm\_gmmm()}} \index{InpMtx_nonsym_gmmm_T@{\tt InpMtx\_nonsym\_gmmm\_T()}} \index{InpMtx_nonsym_gmmm_H@{\tt InpMtx\_nonsym\_gmmm\_H()}} These five methods perform the following computations. \begin{center} \begin{tabular}{llll} {\tt InpMtx\_nonsym\_gmmm()} & $Y := \beta Y + \alpha A X$ & nonsymmetric & real or complex \\ {\tt InpMtx\_sym\_gmmm()} & $Y := \beta Y + \alpha A X$ & symmetric & real or complex \\ {\tt InpMtx\_herm\_gmmm()} & $Y := \beta Y + \alpha A X$ & Hermitian & complex \\ {\tt InpMtx\_nonsym\_gmmm\_T()} & $Y := \beta Y + \alpha A^T X$ & nonsymmetric & real or complex \\ {\tt InpMtx\_nonsym\_gmmm\_H()} & $Y := \beta Y + \alpha A^H X$ & nonsymmetric & complex \end{tabular} \end{center} {\tt A}, {\tt X} and {\tt Y} must all be real or all be complex. When {\tt A} is real, then $\beta$ = {\tt beta[0]} and $\alpha$ = {\tt alpha[0]}. When {\tt A} is complex, then $\beta$ = {\tt beta[0]} + i*{\tt beta[1]} and $\alpha$ = {\tt alpha[0]} + i*{\tt alpha[1]}. The values of $\beta$ and $\alpha$ must be loaded into an array of length 1 or 2. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}[t]{rl} ~1 & normal return \\ -1 & {\tt A} is {\tt NULL} \\ -2 & type of {\tt A} is invalid \\ -3 & indices of entries of {\tt A} are {\tt NULL} \\ -4 & {\tt beta} is {\tt NULL} \\ -5 & {\tt Y} is {\tt NULL} \\ -6 & type of {\tt Y} is invalid \\ -7 & bad dimensions and strides for {\tt Y} \\ \end{tabular} \begin{tabular}[t]{rl} ~-8 & entries of {\tt Y} are {\tt NULL} \\ ~-9 & {\tt alpha} is {\tt NULL} \\ -10 & {\tt X} is {\tt NULL} \\ -11 & type of {\tt X} is invalid \\ -12 & bad dimensions and strides for {\tt X} \\ -13 & entries of {\tt X} are {\tt NULL} \\ -14 & types of {\tt A}, {\tt X} and {\tt Y} are not identical \\ -15 & number of columns in {\tt X} and {\tt Y} are not equal \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_nonsym_gmvm ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) ; int InpMtx_sym_gmvm ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) ; int InpMtx_herm_gmvm ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) ; int InpMtx_nonsym_gmvm_T ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) ; int InpMtx_nonsym_gmvm_H ( InpMtx *A, double beta[], int ny, double y[], double alpha[], int nx, double x[] ) ; \end{verbatim} \index{InpMtx_nonsym_gmvm@{\tt InpMtx\_nonsym\_gmvm()}} \index{InpMtx_sym_gmvm@{\tt InpMtx\_sym\_gmvm()}} \index{InpMtx_herm_gmvm@{\tt InpMtx\_herm\_gmvm()}} \index{InpMtx_nonsym_gmvm_T@{\tt InpMtx\_nonsym\_gmvm\_T()}} \index{InpMtx_nonsym_gmvm_H@{\tt InpMtx\_nonsym\_gmvm\_H()}} These five methods perform the following computations. \begin{center} \begin{tabular}{llll} {\tt InpMtx\_nonsym\_gmvm()} & $y := \beta y + \alpha A x$ & nonsymmetric & real or complex \\ {\tt InpMtx\_sym\_gmvm()} & $y := \beta y + \alpha A x$ & symmetric & real or complex \\ {\tt InpMtx\_herm\_gmvm()} & $y := \beta y + \alpha A x$ & Hermitian & complex \\ {\tt InpMtx\_nonsym\_gmvm\_T()} & $y := \beta y + \alpha A^T x$ & nonsymmetric & real or complex \\ {\tt InpMtx\_nonsym\_gmvm\_H()} & $y := \beta y + \alpha A^H x$ & nonsymmetric & complex \end{tabular} \end{center} When {\tt A} is real, then $\beta$ = {\tt beta[0]} and $\alpha$ = {\tt alpha[0]}. When {\tt A} is complex, then $\beta$ = {\tt beta[0]} + i*{\tt beta[1]} and $\alpha$ = {\tt alpha[0]} + i*{\tt alpha[1]}. The values of $\beta$ and $\alpha$ must be loaded into an array of length 1 or 2. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}[t]{rl} ~1 & normal return \\ -1 & {\tt A} is {\tt NULL} \\ -2 & type of {\tt A} is invalid \\ -3 & indices of entries of {\tt A} are {\tt NULL} \\ -4 & {\tt beta} is {\tt NULL} \\ \end{tabular} \begin{tabular}[t]{rl} -5 & ${\tt ny} \le 0$ \\ -6 & {\tt y} is {\tt NULL} \\ -7 & {\tt alpha} is {\tt NULL} \\ -8 & ${\tt nx} \le 0$ \\ -9 & {\tt x} is {\tt NULL} \\ \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Graph construction methods} \label{subsection:InpMtx:proto:construct} \par Often we need to construct a graph object from a matrix, e.g., when we need to find an ordering of the rows and columns. We don't construct a {\tt Graph} object directly, but create a full adjacency structure that is stored in an {\tt IVL} object, a lower level object than the {\tt Graph} object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IVL * InpMtx_fullAdjacency ( InpMtx *inpmtxA ) ; \end{verbatim} \index{InpMtx_fullAdjacency@{\tt InpMtx\_fullAdjacency()}} This method creates and returns an {\tt IVL} object that holds the full adjacency structure of $A + A^T$, where {\tt inpmtxA} contains the entries in $A$. \par \noindent {\it Error checking:} If {\tt inpmtxA} is {\tt NULL}, or if the coordinate type is not {\tt INPMTX\_BY\_ROWS} or {\tt INPMTX\_BY\_COLUMNS}, or if the storage mode is not {\tt INPMTX\_BY\_VECTORS}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * InpMtx_fullAdjacency2 ( InpMtx *inpmtxA, InpMtx *inpmtxB ) ; \end{verbatim} \index{InpMtx_fullAdjacency2@{\tt InpMtx\_fullAdjacency2()}} This method creates and returns an {\tt IVL} object that holds the full adjacency structure of $(A + B) + (A + B)^T$, where {\tt inpmtxA} contains the entries in $A$ and {\tt inpmtxB} contains the entries in $B$. \par \noindent {\it Error checking:} If {\tt inpmtxA} is {\tt NULL}, or if the coordinate type is not {\tt INPMTX\_BY\_ROWS} or {\tt INPMTX\_BY\_COLUMNS}, or if the storage mode is not {\tt INPMTX\_BY\_VECTORS}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * InpMtx_adjForATA ( InpMtx *inpmtxA ) ; \end{verbatim} \index{InpMtx_adjForATA@{\tt InpMtx\_adjForATA()}} This method creates and returns an {\tt IVL} object that holds the full adjacency structure of $A^T A$, where {\tt inpmtxA} contains the entries in $A$. \par \noindent {\it Error checking:} If {\tt inpmtxA} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \par %======================================================================= % \subsection{Custom coordinate mapping methods} % \label{subsection:InpMtx:proto:custom} % \par % There is one method to map the entries into custom coordinates. % We want to be able to load entries of the matrix into the front % structures in as rapid and efficient manner as possible. % Towards this goal, this custom coordinate map has % {\tt ivec1[ient]} equal to the front that will assemble entry % {\tt ient}, % {\tt ivec2[ient]} is the offset into the data array for the front % where the entry will be assembled. % \par % \begin{enumerate} %----------------------------------------------------------------------- % \item % \begin{verbatim} % void InpMtx_mapToFronts ( InpMtx *inpmtx, IV *vtxToFrontIV, % IVL *frontIndicesIVL ) ; % \end{verbatim} % \index{InpMtx_mapToFronts@{\tt InpMtx\_mapToFronts()}} % We are given two input parameters: an {\tt IV} object that contains % the map from the vertices to the fronts, % and an {\tt IVL} object that holds the indices for each of the fronts. % {\it For this method,}\footnote{ % There are other ways to map entries into frontal matrices. % For example, if the full frontal matrix is stored, (as for the % classical multifrontal method), we could map entry $a_{i,j}$ to the % first numbered front that contains both $i$ and $j$ in its rows and % columns.} % the front contains three matrices --- $A_{1,1}$, $A_{1,2}$ and % $A_{2,1}$. % The mode of storage is column-major for $A_{1,1}$ and $A_{1,2}$ % and row-major for $A_{2,1}$. % The storage for the three matrices is contiguous, that of $A_{1,1}$ % first, followed by that for $A_{1,2}$, followed by that for $A_{2,1}$. % \par % We first convert the coordinate mode to chevrons, sort and compress. % (This allows the mapping to be executed in an efficient manner.) % The {\tt ivec1[]} and {\tt ivec2[]} vectors are filled with the % fronts and offsets for the entries, respectively. % The coordinate type is set to {\tt 4} (custom) and the storage mode % is then converted to {\tt 3}, distinct vectors. % \par \noindent {\it Error checking:} % If {\tt inpmtx}, {\tt vtxToFrontIV} or {\tt frontIndicesIVL} % are {\tt NULL}, % an error message is printed and the program exits. %----------------------------------------------------------------------- % \end{enumerate} \par %======================================================================= \subsection{Submatrix extraction method} \label{subsection:InpMtx:proto:extract} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_initFromSubmatrix ( InpMtx *B, InpMtx *A, IV *BrowsIV, IV *BcolsIV, int symmetryflag, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{InpMtx_initFromSubmatrix@{\tt InpMtx\_initFromSubmatrix()}} This method fills {\tt B} with the submatrix formed from the rows and columns of {\tt A} found in {\tt BrowsIV} and {\tt BcolsIV}. The row and column indices in {\tt B} are local with respect to {\tt BrowsIV} and {\tt BcolsIV}. \par When {\tt symmetryflag} is {\tt SPOOLES\_SYMMETRIC} or {\tt SPOOLES\_HERMITIAN}, then we assume that when $i \ne j$, $A_{i,j}$ or $A_{j,i}$ is stored, but not both. ($A$ could be stored by rows of its upper triangle, or by columns of its lower triangle, or a mixture.) In this case, if {\tt BrowsIV} and {\tt BcolsIV} are identical, then just the upper triangular part of {\tt B} is stored. Otherwise {\tt B} contains all entries of $A$ for rows in {\tt rowsIV} and columns in {\tt colsIV}. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt B} is {\tt NULL} \\ -2 & {\tt BcolsIV} is {\tt NULL} \\ -3 & {\tt BrowsIV} is {\tt NULL} \\ -4 & {\tt A} is {\tt NULL} \\ \end{tabular} \quad \begin{tabular}{rl} -5 & invalid input mode for {\tt A} \\ -6 & invalid coordinate type for {\tt A} \\ -7 & invalid {\tt symmetryflag} \\ -8 & Hermitian {\tt symmetryflag} but not complex \\ -9 & ${\tt msglvl} > 0$ and {\tt msgFile} is {\tt NULL} \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} \par %======================================================================= \subsection{Utility methods} \label{subsection:InpMtx:proto:utility} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_sortAndCompress ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_sortAndCompress@{\tt InpMtx\_sortAndCompress()}} This method sorts the triples first by their primary key and next by their secondary key. At this point any two triples with identical first and second coordinates lie in consecutive locations, so it is easy to add all entries together that are associated with a triple and thus compress the vectors. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if {\tt storageMode} is not 1, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_convertToVectors ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_convertToVectors@{\tt InpMtx\_convertToVectors()}} This method fills the {\tt sizes[]} and {\tt offsets[]} arrays to generate a set of vectors of triples whose first coordinate is identical. The method requires that {\tt storageMode = INPMTX\_SORTED}, i.e., that the triples have been sorted and compressed. The sizes of the two arrays are changed as necessary. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if {\tt storageMode} is not 2, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_dropOffDiagonalEntries ( InpMtx *inpmtx ) ; void InpMtx_dropLowerTriangle ( InpMtx *inpmtx ) ; void InpMtx_dropUpperTriangle ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_dropOffDiagonalEntries@{\tt InpMtx\_dropOffDiagonalEntries()}} \index{InpMtx_dropLowerTriangle@{\tt InpMtx\_dropLowerTriangle()}} \index{InpMtx_dropUpperTriangle@{\tt InpMtx\_dropUpperTriangle()}} These methods purge entries based on structure. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if {\tt coordType} is not {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_mapToLowerTriangle ( InpMtx *inpmtx ) ; void InpMtx_mapToUpperTriangle ( InpMtx *inpmtx ) ; void InpMtx_mapToUpperTriangleH ( InpMtx *inpmtx ) ; \end{verbatim} \index{InpMtx_mapToLowerTriangle@{\tt InpMtx\_mapToLowerTriangle()}} \index{InpMtx_mapToUpperTriangle@{\tt InpMtx\_mapToUpperTriangle()}} \index{InpMtx_mapToUpperTriangleH@{\tt InpMtx\_mapToUpperTriangleH()}} If the {\tt InpMtx} object holds only the lower or upper triangle of a matrix (as when the matrix is symmetric or Hermitian), and is then permuted, it is not likely that the permuted object will only have entries in the lower or upper triangle. The first method moves $a_{i,j}$ for $i < j$ to $a_{j,i}$. The second method moves $a_{i,j}$ for $i > j$ to $a_{j,i}$, (If the matrix is Hermitian, the sign of the imaginary part of an entry is dealt with in the correct fashion.) In other words, using these methods will restore the lower or upper triangular structure after a permutation. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if {\tt coordType} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_log10profile ( InpMtx *inpmtx, int npts, DV *xDV, DV *yDV, double tausmall, double taubig, int *pnzero, int *pnsmall, int *pnbig ) ; \end{verbatim} \index{InpMtx_log10profile@{\tt InpMtx\_log10profile()}} This method fills the {\tt xDV} and {\tt yDV} objects with with an approximate density profile of the magnitudes of the entries in the matrix. Only values whose $\log10(a_{i,j})$ is in the range {\tt [tausmall, taubig]} contribute to the profile. The range is divided up into {\tt npts} buckets. The {\tt x} value is the $\log10$ of a average magnitude of a bucket, and the {\tt y} value is the number of entries found in that bucket. On return, {\tt *pnzero} returns the number of zero entries in the matrix, {\tt *pnsmall} returns the number of entries whose $\log10$ magnitude is smaller than {\tt tausmall}, and {\tt *pnbig} returns the number of entries whose $\log10$ magnitude is larger than {\tt taubig}. The {\tt DVL\_log10profile()} method is used to find the profile. \par \noindent {\it Error checking:} If {\tt inpmtx}, {\tt xDV}, {\tt yDV}, {\tt pnzero}, {\tt pnsmall} or {\tt pnbig} is {\tt NULL}, or if {\tt inputMode} is not {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, or if {\tt npts}, {\tt taubig} or {\tt tausmall} $\le 0$, or if {\tt tausmall > taubig}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_checksums ( InpMtx *inpmtx, double sums[] ) ; \end{verbatim} \index{InpMtx_checksums@{\tt InpMtx\_checksums()}} This method fills {\tt sums[0]} with the sum of the absolute values of the first coordinates, {\tt sums[1]} with the sum of the absolute values of the second coordinates, and if entries are present, it fills {\tt sums[2]} with the sum of the magnitudes of the entries. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, or if {\tt inputMode} is not valid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_randomMatrix ( InpMtx *inpmtx, int inputMode, int coordType, int storageMode, int nrow, int ncol, int symflag, int nonzerodiag, int nitem, int seed ) ; \end{verbatim} \index{InpMtx_randomMatrix@{\tt InpMtx\_randomMatrix()}} This methods fills {\tt mtx} with random entries. {\tt inputMode} can be indices only, real or complex. {\tt coordType} can be rows, columns or chevrons. {\tt storageMode} can be raw, sorted or vectors. {\tt nrow} and {\tt ncol} must be positive. {\tt symflag} can be symmetric, Hermitian or nonsymmetric. if {\tt nonzerodiag} is {\tt 1}, the diagonal of the matrix is filled with nonzeros. {\tt nitem} numbers (or {\tt nitem + min(nrow,ncol)} if {\tt nonzerodiag = 1}) are placed into the matrix. {\tt seed} is used for the random number generator. \par \noindent {\it Error checking:} If {\tt inpmtx} is {\tt NULL}, {\tt -1} is returned. If {\tt inputMode} is invalid, {\tt -2} is returned. If {\tt coordType} is invalid, {\tt -3} is returned. If {\tt storageMode} is invalid, {\tt -4} is returned. If {\tt nrow} or {\tt ncol} is not positive, {\tt -5} is returned. If {\tt symflag} is invalid, {\tt -5} is returned. If {\tt symflag} is Hermitian but {\tt inputMode} is not complex, {\tt -7} is returned. If {\tt symflag} is symmetric or Hermitian but {\tt nrow} is not equal to {\tt ncol}, {\tt -8} is returned. If {\tt nitem} is not positive, {\tt -9} is returned. Otherwise, {\tt 1} is returned. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt inpmtx} is {\tt NULL} \\ -2 & {\tt inputMode} invalid \\ -3 & {\tt coordType} invalid \\ -4 & {\tt storageMode} invalid \\ \end{tabular} \quad \begin{tabular}{rl} -5 & {\tt nrow} or {\tt ncol} negative \\ -6 & {\tt symflag} is invalid \\ -7 & {\tt (symflag,inputMode)} invalid \\ -8 & {\tt (symflag,nrow,ncol)} invalid \\ -9 & {\tt nitem} negative \\ \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:InpMtx:proto:IO} \par There are the usual eight IO routines. The file structure of a {\tt InpMtx} object is simple: The first entries in the file are {\tt coordType}, {\tt storageMode}, {\tt inputMode}, {\tt nent} and {\tt nvector}. If {\tt nent > 0}, then the {\tt ivec1IV} and {\tt ivec2IV} vectors follow, If {\tt nent > 0} and {\tt inputMode = SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, the {\tt dvecDV} vector follows. If {\tt storageMode = INPMTX\_BY\_VECTORS} and {\tt nvector > 0}, the {\tt vecidsIV}, {\tt sizesIV} and {\tt offsetsIV} vectors follow. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_readFromFile ( InpMtx *inpmtx, char *fn ) ; \end{verbatim} \index{InpMtx_readFromFile@{\tt InpMtx\_readFromFile()}} \par This method reads the object from a formatted or binary file. It tries to open the file and if successful, it then calls {\tt InpMtx\_readFromBinaryFile()} or {\tt InpMtx\_readFromFormattedFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt inpmtx} or {\tt fn} is {\tt NULL}, or if {\tt fn} is not of the form {\tt *.inpmtxf} (for a formatted file) or {\tt *.inpmtxb} (for a binary file), or if the file cannot be opened, an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_readFromFormattedFile ( InpMtx *inpmtx, FILE *fp ) ; \end{verbatim} \index{InpMtx_readFromFormattedFile@{\tt InpMtx\_readFromFormattedFile()}} \par This method reads in the object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt inpmtx} or {\tt fp} is {\tt NULL}, an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_readFromBinaryFile ( InpMtx *inpmtx, FILE *fp ) ; \end{verbatim} \index{InpMtx_readFromBinaryFile@{\tt InpMtx\_readFromBinaryFile()}} \par This method reads in the object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt inpmtx} or {\tt fp} is {\tt NULL}, an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_writeToFile ( InpMtx *inpmtx, char *fn ) ; \end{verbatim} \index{InpMtx_writeToFile@{\tt InpMtx\_writeToFile()}} \par This method writes the object to a formatted or binary file. It tries to open the file and if successful, it then calls {\tt InpMtx\_writeToBinaryFile()} or {\tt InpMtx\_writeToFormattedFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt inpmtx} of {\tt fn} is {\tt NULL}, or if {\tt fn} is not of the form {\tt *.inpmtxf} (for a formatted file) or {\tt *.inpmtxb} (for a binary file), or if the file cannot be opened, an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_writeToFormattedFile ( InpMtx *inpmtx, FILE *fp ) ; \end{verbatim} \index{InpMtx_writeToFormattedFile@{\tt InpMtx\_writeToFormattedFile()}} \par This method writes the object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt inpmtx} or {\tt fp} is {\tt NULL}, an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_writeToBinaryFile ( InpMtx *inpmtx, FILE *fp ) ; \end{verbatim} \index{InpMtx_writeToBinaryFile@{\tt InpMtx\_writeToBinaryFile()}} \par This method writes the object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt inpmtx} or {\tt fp} is {\tt NULL}, an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_writeForHumanEye ( InpMtx *inpmtx, FILE *fp ) ; \end{verbatim} \index{InpMtx_writeForHumanEye@{\tt InpMtx\_writeForHumanEye()}} \par This method writes the object to a file suitable for reading by a human. The method {\tt InpMtx\_writeStats()} is called to write out the header and statistics. The data is written out in the appropriate way, e.g., if the storage mode is by triples, triples are written out. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt inpmtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_writeStats ( InpMtx *inpmtx, FILE *fp ) ; \end{verbatim} \index{InpMtx_writeStats@{\tt InpMtx\_writeStats()}} \par This method writes the statistics about the object to a file. human. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt inpmtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_writeForMatlab ( InpMtx *mtx, char *mtxname, FILE *fp ) ; \end{verbatim} \index{InpMtx_writeForMatlab@{\tt InpMtx\_writeForMatlab()}} \par This method writes out a {\tt InpMtx} object to a file in a Matlab format. A sample line is \begin{verbatim} a(10,5) = -1.550328201511e-01 + 1.848033378871e+00*i ; \end{verbatim} for complex matrices, or \begin{verbatim} a(10,5) = -1.550328201511e-01 ; \end{verbatim} for real matrices, where mtxname = {\tt "a"}. The matrix indices come from the {\tt rowind[]} and {\tt colind[]} vectors, and are incremented by one to follow the Matlab and FORTRAN convention. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt mtxname} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int InpMtx_readFromHBFile ( InpMtx *inpmtx, char *fn ) ; \end{verbatim} \index{InpMtx_readFromHBFile@{\tt InpMtx\_readFromHBFile()}} \par This method reads the object from a Harwell-Boeing file. This method calls {\tt readHB\_info()} and {\tt readHB\_mat\_double()} from the Harwell-Boeing C IO routines from NIST\footnote{\tt http://math.nist.gov/mcsd/Staff/KRemington/harwell\_io/harwell\_io.html}, found in the {\tt misc/src/iohb.c} file. \par \noindent {\it Error checking:} If {\tt inpmtx} or {\tt fn} is {\tt NULL}, or if the file cannot be opened, an error message is printed and the method returns zero. %----------------------------------------------------------------------- \end{enumerate} l > taubig}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatInpMtx/doc/main.log010064400020550007177000000141040665022215000155020ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 16 JAN 1999 15:44 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 19. LaTeX Font Info: ... okay on input line 19. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 19. LaTeX Font Info: ... okay on input line 19. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 19. LaTeX Font Info: ... okay on input line 19. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 19. LaTeX Font Info: ... okay on input line 19. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 19. LaTeX Font Info: ... okay on input line 19. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 19. LaTeX Font Info: ... okay on input line 19. (intro.tex Chapter 1. LaTeX Font Info: Try loading font information for OMS+cmr on input line 7. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 7. LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 22. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 22. [1 ]) (dataStructure.tex [2] Overfull \hbox (10.7373pt too wide) in paragraph at lines 74--79 []\OT1/cmtt/m/n/10 int maxnvector \OT1/cmr/m/n/10 -- present max-i-mum num-ber of vec-tors. This quan-tity is ini-tial-ized by the \OT1/cmtt/m/n/10 InpMtx[]in it() [] [3]) (proto.tex [4] [5] [6] Overfull \hbox (9.61465pt too wide) in paragraph at lines 390--400 []\OT1/cmr/m/n/10 This method changes the co-or-di-nate type. If $[] = []$, the pro-gram re-turns. If $[] \OMS/cmsy/m/n/10 ^^U [] [7] [8] [9] Overfull \hbox (34.11732pt too wide) in paragraph at lines 734--745 \OT1/cmtt/m/n/10 INPMTX[]BY[]CHEVRONS\OT1/cmr/m/n/10 , or if \OT1/cmtt/m/n/10 s torageMode \OT1/cmr/m/n/10 is not one of \OT1/cmtt/m/n/10 INPMTX[]RAW[]DATA\OT1 /cmr/m/n/10 , \OT1/cmtt/m/n/10 INPMTX[]SORTED \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/ 10 INPMTX[]BY[]VECTORS\OT1/cmr/m/n/10 , [] Overfull \hbox (6.7411pt too wide) in paragraph at lines 751--751 []\OT1/cmtt/m/n/10 void InpMtx_nonsym_mmmVector ( InpMtx *A, DenseMtx *Y, doub le alpha[], DenseMtx *X ) ;[] [] Overfull \hbox (17.24101pt too wide) in paragraph at lines 751--751 []\OT1/cmtt/m/n/10 void InpMtx_nonsym_mmmVector_T ( InpMtx *A, DenseMtx *Y, do uble alpha[], DenseMtx *X ) ;[] [] Overfull \hbox (17.24101pt too wide) in paragraph at lines 751--751 []\OT1/cmtt/m/n/10 void InpMtx_nonsym_mmmVector_H ( InpMtx *A, DenseMtx *Y, do uble alpha[], DenseMtx *X ) ;[] [] [10] Overfull \hbox (34.11732pt too wide) in paragraph at lines 787--798 \OT1/cmtt/m/n/10 INPMTX[]BY[]CHEVRONS\OT1/cmr/m/n/10 , or if \OT1/cmtt/m/n/10 s torageMode \OT1/cmr/m/n/10 is not one of \OT1/cmtt/m/n/10 INPMTX[]RAW[]DATA\OT1 /cmr/m/n/10 , \OT1/cmtt/m/n/10 INPMTX[]SORTED \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/ 10 INPMTX[]BY[]VECTORS\OT1/cmr/m/n/10 , [] [11] Overfull \hbox (11.27731pt too wide) in paragraph at lines 964--972 \OT1/cmr/m/it/10 Error check-ing: \OT1/cmr/m/n/10 If \OT1/cmtt/m/n/10 inpmtxA \ OT1/cmr/m/n/10 is \OT1/cmtt/m/n/10 NULL\OT1/cmr/m/n/10 , or if the co-or-di-nat e type is not \OT1/cmtt/m/n/10 INPMTX[]BY[]ROWS \OT1/cmr/m/n/10 or \OT1/cmtt/m/ n/10 INPMTX[]BY[]COLUMNS\OT1/cmr/m/n/10 , [] Overfull \hbox (11.27731pt too wide) in paragraph at lines 980--988 \OT1/cmr/m/it/10 Error check-ing: \OT1/cmr/m/n/10 If \OT1/cmtt/m/n/10 inpmtxA \ OT1/cmr/m/n/10 is \OT1/cmtt/m/n/10 NULL\OT1/cmr/m/n/10 , or if the co-or-di-nat e type is not \OT1/cmtt/m/n/10 INPMTX[]BY[]ROWS \OT1/cmr/m/n/10 or \OT1/cmtt/m/ n/10 INPMTX[]BY[]COLUMNS\OT1/cmr/m/n/10 , [] [12] [13] [14] Overfull \hbox (13.68219pt too wide) in paragraph at lines 1411--1418 []\OT1/cmr/m/n/10 This method writes the ob-ject to a file suit-able for read-i ng by a hu-man. The method \OT1/cmtt/m/n/10 InpMtx[]writeStats() [] [15] LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 1469. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 1469. Overfull \hbox (10.59344pt too wide) in paragraph at lines 1465--1471 \OT1/cmtt/m/n/10 readHB[]mat[]double() \OT1/cmr/m/n/10 from the Harwell-Boeing C IO rou-tines from NIST[], found in the \OT1/cmtt/m/n/10 misc/src/iohb.c [] ) (drivers.tex [16] [17] [18] [19] psfig: searching ../../InpMtx/doc/BCSSTK23.eps for bounding box psfig: including ../../InpMtx/doc/BCSSTK23.eps [20] [21] [22]) (main.ind [23] [24 ] [25 ]) (main.aux) LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right. ) Here is how much of TeX's memory you used: 553 strings out of 10908 5755 string characters out of 72189 55796 words of memory out of 262141 3455 multiletter control sequences out of 9500 10371 words of font info for 39 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 24i,8n,21p,159b,425s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (25 pages, 104472 bytes). e 19. LaTeX Font Info: ... okay on input line 19. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 19. LaTeX Font Info: ... okay on input line 19. (intro.tex Chapter 1. LaTeX Font Info: Try loading font information for OMS+cmr on input line 7. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> InpMtx/doc/main.idx010064400020550007177000000150170665022215000155110ustar00clevecompmath00000400000006\indexentry{InpMtx_new@{\tt InpMtx\_new()}}{4} \indexentry{InpMtx_setDefaultFields@{\tt InpMtx\_setDefaultFields()}}{4} \indexentry{InpMtx_clearData@{\tt InpMtx\_clearData()}}{4} \indexentry{InpMtx_free@{\tt InpMtx\_free()}}{4} \indexentry{InpMtx_coordType@{\tt InpMtx\_coordType()}}{4} \indexentry{InpMtx_storageMode@{\tt InpMtx\_storageMode()}}{5} \indexentry{InpMtx_inputMode@{\tt InpMtx\_inputMode()}}{5} \indexentry{InpMtx_maxnent@{\tt InpMtx\_maxnent()}}{5} \indexentry{InpMtx_nent@{\tt InpMtx\_nent()}}{5} \indexentry{InpMtx_maxnvector@{\tt InpMtx\_maxnvector()}}{5} \indexentry{InpMtx_nvector@{\tt InpMtx\_nvector()}}{5} \indexentry{InpMtx_resizeMultiple@{\tt InpMtx\_resizeMultiple()}}{5} \indexentry{InpMtx_ivec1@{\tt InpMtx\_ivec1()}}{5} \indexentry{InpMtx_ivec2@{\tt InpMtx\_ivec2()}}{5} \indexentry{InpMtx_dvec@{\tt InpMtx\_dvec()}}{6} \indexentry{InpMtx_vecids@{\tt InpMtx\_vecids()}}{6} \indexentry{InpMtx_sizes@{\tt InpMtx\_sizes()}}{6} \indexentry{InpMtx_offsets@{\tt InpMtx\_offsets()}}{6} \indexentry{InpMtx_vector@{\tt InpMtx\_vector()}}{6} \indexentry{InpMtx_realVector@{\tt InpMtx\_realVector()}}{6} \indexentry{InpMtx_complexVector@{\tt InpMtx\_complexVector()}}{6} \indexentry{InpMtx_range@{\tt InpMtx\_range()}}{6} \indexentry{InpMtx_setMaxnent@{\tt InpMtx\_setMaxnent()}}{6} \indexentry{InpMtx_setNent@{\tt InpMtx\_setNent()}}{6} \indexentry{InpMtx_setMaxnvector@{\tt InpMtx\_setMaxnvector()}}{7} \indexentry{InpMtx_setNvector@{\tt InpMtx\_setNvector()}}{7} \indexentry{InpMtx_setResizeMultiple@{\tt InpMtx\_setResizeMultiple()}}{7} \indexentry{InpMtx_setCoordType@{\tt InpMtx\_setCoordType()}}{7} \indexentry{InpMtx_init@{\tt InpMtx\_init()}}{7} \indexentry{InpMtx_changeCoordType@{\tt InpMtx\_changeCoordType()}}{7} \indexentry{InpMtx_changeStorageMode@{\tt InpMtx\_changeStorageMode()}}{7} \indexentry{InpMtx_inputEntry@{\tt InpMtx\_inputEntry()}}{8} \indexentry{InpMtx_inputRealEntry@{\tt InpMtx\_inputRealEntry()}}{8} \indexentry{InpMtx_inputComplexEntry@{\tt InpMtx\_inputComplexEntry()}}{8} \indexentry{InpMtx_inputRow@{\tt InpMtx\_inputRow()}}{8} \indexentry{InpMtx_inputRealRow@{\tt InpMtx\_inputRealRow()}}{8} \indexentry{InpMtx_inputComplexRow@{\tt InpMtx\_inputComplexRow()}}{8} \indexentry{InpMtx_inputColumn@{\tt InpMtx\_inputColumn()}}{8} \indexentry{InpMtx_inputRealColumn@{\tt InpMtx\_inputRealColumn()}}{8} \indexentry{InpMtx_inputComplexColumn@{\tt InpMtx\_inputComplexColumn()}}{8} \indexentry{InpMtx_inputChevron@{\tt InpMtx\_inputChevron()}}{8} \indexentry{InpMtx_inputRealChevron@{\tt InpMtx\_inputRealChevron()}}{8} \indexentry{InpMtx_inputComplexChevron@{\tt InpMtx\_inputComplexChevron()}}{8} \indexentry{InpMtx_inputMatrix@{\tt InpMtx\_inputMatrix()}}{9} \indexentry{InpMtx_inputRealMatrix@{\tt InpMtx\_inputRealMatrix()}}{9} \indexentry{InpMtx_inputComplexMatrix@{\tt InpMtx\_inputComplexMatrix()}}{9} \indexentry{InpMtx_inputTriples@{\tt InpMtx\_inputTriples()}}{9} \indexentry{InpMtx_inputRealTriples@{\tt InpMtx\_inputRealTriples()}}{9} \indexentry{InpMtx_inputComplexTriples@{\tt InpMtx\_inputComplexTriples()}}{9} \indexentry{InpMtx_supportNonsym@{\tt InpMtx\_supportNonsym()}}{9} \indexentry{InpMtx_supportNonsymT@{\tt InpMtx\_supportNonsymT()}}{9} \indexentry{InpMtx_supportNonsymH@{\tt InpMtx\_supportNonsymH()}}{9} \indexentry{InpMtx_supportSym@{\tt InpMtx\_supportSym()}}{9} \indexentry{InpMtx_supportSymH@{\tt InpMtx\_supportSymH()}}{9} \indexentry{InpMtx_mapEntries@{\tt InpMtx\_mapEntries()}}{9} \indexentry{InpMtx_permute@{\tt InpMtx\_permute()}}{10} \indexentry{InpMtx_nonsym_mmm@{\tt InpMtx\_nonsym\_mmm()}}{10} \indexentry{InpMtx_sym_mmm@{\tt InpMtx\_sym\_mmm()}}{10} \indexentry{InpMtx_herm_mmm@{\tt InpMtx\_herm\_mmm()}}{10} \indexentry{InpMtx_nonsym_mmm_T@{\tt InpMtx\_nonsym\_mmm\_T()}}{10} \indexentry{InpMtx_nonsym_mmm_H@{\tt InpMtx\_nonsym\_mmm\_H()}}{10} \indexentry{InpMtx_nonsym_mmmVector@{\tt InpMtx\_nonsym\_mmmVector()}}{11} \indexentry{InpMtx_sym_mmmVector@{\tt InpMtx\_sym\_mmmVector()}}{11} \indexentry{InpMtx_herm_mmmVector@{\tt InpMtx\_herm\_mmmVector()}}{11} \indexentry{InpMtx_nonsym_mmmVector_T@{\tt InpMtx\_nonsym\_mmmVector\_T()}}{11} \indexentry{InpMtx_nonsym_mmmVector_H@{\tt InpMtx\_nonsym\_mmmVector\_H()}}{11} \indexentry{InpMtx_nonsym_gmmm@{\tt InpMtx\_nonsym\_gmmm()}}{11} \indexentry{InpMtx_sym_gmmm@{\tt InpMtx\_sym\_gmmm()}}{11} \indexentry{InpMtx_herm_gmmm@{\tt InpMtx\_herm\_gmmm()}}{11} \indexentry{InpMtx_nonsym_gmmm_T@{\tt InpMtx\_nonsym\_gmmm\_T()}}{11} \indexentry{InpMtx_nonsym_gmmm_H@{\tt InpMtx\_nonsym\_gmmm\_H()}}{11} \indexentry{InpMtx_nonsym_gmvm@{\tt InpMtx\_nonsym\_gmvm()}}{12} \indexentry{InpMtx_sym_gmvm@{\tt InpMtx\_sym\_gmvm()}}{12} \indexentry{InpMtx_herm_gmvm@{\tt InpMtx\_herm\_gmvm()}}{12} \indexentry{InpMtx_nonsym_gmvm_T@{\tt InpMtx\_nonsym\_gmvm\_T()}}{12} \indexentry{InpMtx_nonsym_gmvm_H@{\tt InpMtx\_nonsym\_gmvm\_H()}}{12} \indexentry{InpMtx_fullAdjacency@{\tt InpMtx\_fullAdjacency()}}{12} \indexentry{InpMtx_fullAdjacency2@{\tt InpMtx\_fullAdjacency2()}}{12} \indexentry{InpMtx_adjForATA@{\tt InpMtx\_adjForATA()}}{12} \indexentry{InpMtx_initFromSubmatrix@{\tt InpMtx\_initFromSubmatrix()}}{13} \indexentry{InpMtx_sortAndCompress@{\tt InpMtx\_sortAndCompress()}}{13} \indexentry{InpMtx_convertToVectors@{\tt InpMtx\_convertToVectors()}}{13} \indexentry{InpMtx_dropOffDiagonalEntries@{\tt InpMtx\_dropOffDiagonalEntries()}}{13} \indexentry{InpMtx_dropLowerTriangle@{\tt InpMtx\_dropLowerTriangle()}}{13} \indexentry{InpMtx_dropUpperTriangle@{\tt InpMtx\_dropUpperTriangle()}}{13} \indexentry{InpMtx_mapToLowerTriangle@{\tt InpMtx\_mapToLowerTriangle()}}{13} \indexentry{InpMtx_mapToUpperTriangle@{\tt InpMtx\_mapToUpperTriangle()}}{13} \indexentry{InpMtx_mapToUpperTriangleH@{\tt InpMtx\_mapToUpperTriangleH()}}{13} \indexentry{InpMtx_log10profile@{\tt InpMtx\_log10profile()}}{14} \indexentry{InpMtx_checksums@{\tt InpMtx\_checksums()}}{14} \indexentry{InpMtx_randomMatrix@{\tt InpMtx\_randomMatrix()}}{14} \indexentry{InpMtx_readFromFile@{\tt InpMtx\_readFromFile()}}{15} \indexentry{InpMtx_readFromFormattedFile@{\tt InpMtx\_readFromFormattedFile()}}{15} \indexentry{InpMtx_readFromBinaryFile@{\tt InpMtx\_readFromBinaryFile()}}{15} \indexentry{InpMtx_writeToFile@{\tt InpMtx\_writeToFile()}}{15} \indexentry{InpMtx_writeToFormattedFile@{\tt InpMtx\_writeToFormattedFile()}}{15} \indexentry{InpMtx_writeToBinaryFile@{\tt InpMtx\_writeToBinaryFile()}}{15} \indexentry{InpMtx_writeForHumanEye@{\tt InpMtx\_writeForHumanEye()}}{15} \indexentry{InpMtx_writeStats@{\tt InpMtx\_writeStats()}}{16} \indexentry{InpMtx_writeForMatlab@{\tt InpMtx\_writeForMatlab()}}{16} \indexentry{InpMtx_readFromHBFile@{\tt InpMtx\_readFromHBFile()}}{16} InpMtx/doc/main.aux010064400020550007177000000041160665022215000155200ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt InpMtx}: Input Matrix Object}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:InpMtx}{{1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{2}} \newlabel{section:InpMtx:dataStructure}{{1.1}{2}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt InpMtx} methods}{4}} \newlabel{section:InpMtx:proto}{{1.2}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{4}} \newlabel{subsection:InpMtx:proto:basics}{{1.2.1}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Instance Methods}{4}} \newlabel{subsection:InpMtx:proto:instance}{{1.2.2}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Methods to initialize and change state}{7}} \newlabel{subsection:InpMtx:proto:initializers}{{1.2.3}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Input methods}{8}} \newlabel{subsection:InpMtx:proto:input}{{1.2.4}{8}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Permutation, map and support methods}{9}} \newlabel{subsection:InpMtx:proto:permute}{{1.2.5}{9}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.6}Matrix-matrix multiply methods}{10}} \newlabel{subsection:InpMtx:proto:mvm}{{1.2.6}{10}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.7}Graph construction methods}{12}} \newlabel{subsection:InpMtx:proto:construct}{{1.2.7}{12}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.8}Submatrix extraction method}{13}} \newlabel{subsection:InpMtx:proto:extract}{{1.2.8}{13}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.9}Utility methods}{13}} \newlabel{subsection:InpMtx:proto:utility}{{1.2.9}{13}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.10}IO methods}{15}} \newlabel{subsection:InpMtx:proto:IO}{{1.2.10}{15}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs for the {\tt InpMtx} object}{16}} \newlabel{section:InpMtx:drivers}{{1.3}{16}} InpMtx/doc/main.ind010064400020550007177000000075350662341362600155170ustar00clevecompmath00000400000006\begin{theindex} \item {\tt InpMtx\_adjForATA()}, 12 \item {\tt InpMtx\_changeCoordType()}, 7 \item {\tt InpMtx\_changeStorageMode()}, 7 \item {\tt InpMtx\_checksums()}, 14 \item {\tt InpMtx\_clearData()}, 4 \item {\tt InpMtx\_complexVector()}, 6 \item {\tt InpMtx\_convertToVectors()}, 13 \item {\tt InpMtx\_coordType()}, 4 \item {\tt InpMtx\_dropLowerTriangle()}, 13 \item {\tt InpMtx\_dropOffDiagonalEntries()}, 13 \item {\tt InpMtx\_dropUpperTriangle()}, 13 \item {\tt InpMtx\_dvec()}, 6 \item {\tt InpMtx\_free()}, 4 \item {\tt InpMtx\_fullAdjacency()}, 12 \item {\tt InpMtx\_fullAdjacency2()}, 12 \item {\tt InpMtx\_herm\_gmmm()}, 11 \item {\tt InpMtx\_herm\_gmvm()}, 11 \item {\tt InpMtx\_herm\_mmm()}, 10 \item {\tt InpMtx\_init()}, 7 \item {\tt InpMtx\_initFromSubmatrix()}, 12 \item {\tt InpMtx\_inputChevron()}, 8 \item {\tt InpMtx\_inputColumn()}, 8 \item {\tt InpMtx\_inputComplexChevron()}, 8 \item {\tt InpMtx\_inputComplexColumn()}, 8 \item {\tt InpMtx\_inputComplexEntry()}, 8 \item {\tt InpMtx\_inputComplexMatrix()}, 9 \item {\tt InpMtx\_inputComplexRow()}, 8 \item {\tt InpMtx\_inputComplexTriples()}, 9 \item {\tt InpMtx\_inputEntry()}, 8 \item {\tt InpMtx\_inputMatrix()}, 9 \item {\tt InpMtx\_inputMode()}, 5 \item {\tt InpMtx\_inputRealChevron()}, 8 \item {\tt InpMtx\_inputRealColumn()}, 8 \item {\tt InpMtx\_inputRealEntry()}, 8 \item {\tt InpMtx\_inputRealMatrix()}, 9 \item {\tt InpMtx\_inputRealRow()}, 8 \item {\tt InpMtx\_inputRealTriples()}, 9 \item {\tt InpMtx\_inputRow()}, 8 \item {\tt InpMtx\_inputTriples()}, 9 \item {\tt InpMtx\_ivec1()}, 5 \item {\tt InpMtx\_ivec2()}, 5 \item {\tt InpMtx\_log10profile()}, 13 \item {\tt InpMtx\_mapEntries()}, 9 \item {\tt InpMtx\_mapToLowerTriangle()}, 13 \item {\tt InpMtx\_mapToUpperTriangle()}, 13 \item {\tt InpMtx\_mapToUpperTriangleH()}, 13 \item {\tt InpMtx\_maxnent()}, 5 \item {\tt InpMtx\_maxnvector()}, 5 \item {\tt InpMtx\_nent()}, 5 \item {\tt InpMtx\_new()}, 4 \item {\tt InpMtx\_nonsym\_gmmm()}, 11 \item {\tt InpMtx\_nonsym\_gmmm\_H()}, 11 \item {\tt InpMtx\_nonsym\_gmmm\_T()}, 11 \item {\tt InpMtx\_nonsym\_gmvm()}, 11 \item {\tt InpMtx\_nonsym\_gmvm\_H()}, 11 \item {\tt InpMtx\_nonsym\_gmvm\_T()}, 11 \item {\tt InpMtx\_nonsym\_mmm()}, 10 \item {\tt InpMtx\_nonsym\_mmm\_H()}, 10 \item {\tt InpMtx\_nonsym\_mmm\_T()}, 10 \item {\tt InpMtx\_nvector()}, 5 \item {\tt InpMtx\_offsets()}, 6 \item {\tt InpMtx\_permute()}, 10 \item {\tt InpMtx\_randomMatrix()}, 14 \item {\tt InpMtx\_range()}, 6 \item {\tt InpMtx\_readFromBinaryFile()}, 15 \item {\tt InpMtx\_readFromFile()}, 14 \item {\tt InpMtx\_readFromFormattedFile()}, 14 \item {\tt InpMtx\_readFromHBFile()}, 16 \item {\tt InpMtx\_realVector()}, 6 \item {\tt InpMtx\_resizeMultiple()}, 5 \item {\tt InpMtx\_setCoordType()}, 7 \item {\tt InpMtx\_setDefaultFields()}, 4 \item {\tt InpMtx\_setMaxnent()}, 6 \item {\tt InpMtx\_setMaxnvector()}, 7 \item {\tt InpMtx\_setNent()}, 6 \item {\tt InpMtx\_setNvector()}, 7 \item {\tt InpMtx\_setResizeMultiple()}, 7 \item {\tt InpMtx\_sizes()}, 6 \item {\tt InpMtx\_sortAndCompress()}, 13 \item {\tt InpMtx\_storageMode()}, 5 \item {\tt InpMtx\_supportNonsym()}, 9 \item {\tt InpMtx\_supportNonsymH()}, 9 \item {\tt InpMtx\_supportNonsymT()}, 9 \item {\tt InpMtx\_supportSym()}, 9 \item {\tt InpMtx\_supportSymH()}, 9 \item {\tt InpMtx\_sym\_gmmm()}, 11 \item {\tt InpMtx\_sym\_gmvm()}, 11 \item {\tt InpMtx\_sym\_mmm()}, 10 \item {\tt InpMtx\_vecids()}, 6 \item {\tt InpMtx\_vector()}, 6 \item {\tt InpMtx\_writeForHumanEye()}, 15 \item {\tt InpMtx\_writeForMatlab()}, 15 \item {\tt InpMtx\_writeStats()}, 15 \item {\tt InpMtx\_writeToBinaryFile()}, 15 \item {\tt InpMtx\_writeToFile()}, 15 \item {\tt InpMtx\_writeToFormattedFile()}, 15 \end{theindex} InpMtx/doc/main.ilg010064400020550007177000000004600662341362600155060ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (96 entries accepted, 0 rejected). Sorting entries....done (617 comparisons). Generating output file main.ind....done (100 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. InpMtx/doc/BCSSTK23.eps010064400020550007177000000144030653410622600157320ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%Creator: MATLAB, The Mathworks, Inc. %%Title: profile.eps %%CreationDate: 03/13/97 09:20:11 %%DocumentNeededFonts: Helvetica %%DocumentProcessColors: Cyan Magenta Yellow Black %%Pages: 1 %%BoundingBox: 47 197 550 604 %%EndComments %%BeginProlog % MathWorks dictionary /MathWorks 150 dict begin % definition operators /bdef {bind def} bind def /ldef {load def} bind def /xdef {exch def} bdef /xstore {exch store} bdef % operator abbreviations /c /clip ldef /cc /concat ldef /cp /closepath ldef /gr /grestore ldef /gs /gsave ldef /mt /moveto ldef /np /newpath ldef /cm /currentmatrix ldef /sm /setmatrix ldef /rc {rectclip} bdef /rf {rectfill} bdef /rm /rmoveto ldef /rl /rlineto ldef /s /show ldef /sc {setcmykcolor} bdef /sr /setrgbcolor ldef /w /setlinewidth ldef /j /setlinejoin ldef /cap /setlinecap ldef % page state control /pgsv () def /bpage {/pgsv save def} bdef /epage {pgsv restore} bdef /bplot /gsave ldef /eplot {stroke grestore} bdef % orientation switch /portraitMode 0 def /landscapeMode 1 def % coordinate system mappings /dpi2point 0 def % font control /FontSize 0 def /FMS { /FontSize xstore %save size off stack findfont [FontSize 0 0 FontSize neg 0 0] makefont setfont }bdef /reencode { exch dup where {pop load} {pop StandardEncoding} ifelse exch dup 3 1 roll findfont dup length dict begin { 1 index /FID ne {def}{pop pop} ifelse } forall /Encoding exch def currentdict end definefont pop } bdef /isroman { findfont /CharStrings get /Agrave known } bdef /FMSR { 3 1 roll 1 index dup isroman {reencode} {pop pop} ifelse exch FMS } bdef /csm { 1 dpi2point div -1 dpi2point div scale neg translate landscapeMode eq {90 rotate} if } bdef % line types: solid, dotted, dashed, dotdash /SO { [] 0 setdash } bdef /DO { [.5 dpi2point mul 4 dpi2point mul] 0 setdash } bdef /DA { [6 dpi2point mul] 0 setdash } bdef /DD { [.5 dpi2point mul 4 dpi2point mul 6 dpi2point mul 4 dpi2point mul] 0 setdash } bdef % macros for lines and objects /L { lineto stroke } bdef /MP { 3 1 roll moveto 1 sub {rlineto} repeat } bdef /AP { {rlineto} repeat } bdef /PP { closepath fill } bdef /DP { closepath stroke } bdef /MR { 4 -2 roll moveto dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath } bdef /FR { MR stroke } bdef /PR { MR fill } bdef /L1i { { currentfile picstr readhexstring pop } image } bdef /tMatrix matrix def /MakeOval { newpath tMatrix currentmatrix pop translate scale 0 0 1 0 360 arc tMatrix setmatrix } bdef /FO { MakeOval stroke } bdef /PO { MakeOval fill } bdef /PD { 2 copy moveto lineto stroke } bdef currentdict end def %%EndProlog %%BeginSetup MathWorks begin 0 cap end %%EndSetup %%Page: 1 1 %%BeginPageSetup %%PageBoundingBox: 47 197 550 604 MathWorks begin bpage %%EndPageSetup %%BeginObject: graph1 1 bplot /dpi2point 12 def portraitMode 0216 7344 csm 355 91 6030 4882 MR c np 76 dict begin %Colortable dictionary /c0 { 0 0 0 sr} bdef /c1 { 1 1 1 sr} bdef /c2 { 1 0 0 sr} bdef /c3 { 0 1 0 sr} bdef /c4 { 0 0 1 sr} bdef /c5 { 1 1 0 sr} bdef /c6 { 1 0 1 sr} bdef /c7 { 0 1 1 sr} bdef %%IncludeResource: font Helvetica /Helvetica /ISOLatin1Encoding 144 FMSR 1 j c1 0 0 6914 5184 PR 6 w DO 4 w SO 6 w c0 898 4612 mt 6256 4612 L 898 388 mt 6256 388 L 898 4612 mt 898 388 L 6256 4612 mt 6256 388 L 898 4612 mt 898 4612 L 6256 4612 mt 6256 4612 L 898 4612 mt 6256 4612 L 898 4612 mt 898 388 L 898 4612 mt 898 4612 L 898 4612 mt 898 4558 L 898 388 mt 898 442 L 734 4781 mt (-10) s 1791 4612 mt 1791 4558 L 1791 388 mt 1791 442 L 1667 4781 mt (-5) s 2684 4612 mt 2684 4558 L 2684 388 mt 2684 442 L 2644 4781 mt (0) s 3577 4612 mt 3577 4558 L 3577 388 mt 3577 442 L 3537 4781 mt (5) s 4470 4612 mt 4470 4558 L 4470 388 mt 4470 442 L 4390 4781 mt (10) s 5363 4612 mt 5363 4558 L 5363 388 mt 5363 442 L 5283 4781 mt (15) s 6256 4612 mt 6256 4558 L 6256 388 mt 6256 442 L 6176 4781 mt (20) s 898 4612 mt 952 4612 L 6256 4612 mt 6202 4612 L 783 4665 mt (0) s 898 4084 mt 952 4084 L 6256 4084 mt 6202 4084 L 623 4137 mt (200) s 898 3556 mt 952 3556 L 6256 3556 mt 6202 3556 L 623 3609 mt (400) s 898 3028 mt 952 3028 L 6256 3028 mt 6202 3028 L 623 3081 mt (600) s 898 2500 mt 952 2500 L 6256 2500 mt 6202 2500 L 623 2553 mt (800) s 898 1972 mt 952 1972 L 6256 1972 mt 6202 1972 L 543 2025 mt (1000) s 898 1444 mt 952 1444 L 6256 1444 mt 6202 1444 L 543 1497 mt (1200) s 898 916 mt 952 916 L 6256 916 mt 6202 916 L 543 969 mt (1400) s 898 388 mt 952 388 L 6256 388 mt 6202 388 L 543 441 mt (1600) s 898 4612 mt 6256 4612 L 898 388 mt 6256 388 L 898 4612 mt 898 388 L 6256 4612 mt 6256 388 L 898 388 mt 898 388 L 6256 388 mt 6256 388 L gs 898 388 5359 4225 MR c np 16 18 28 -21 23 0 18 11 20 97 16 159 25 -32 27 82 18 -193 22 19 24 108 19 -71 28 488 16 -459 30 269 15 -367 23 -5 23 26 23 -71 21 23 30 -31 10 -21 30 -11 18 21 27 130 26 -161 21 34 24 644 21 388 20 -256 18 -211 24 290 24 -681 21 8 25 3 25 -66 20 -11 24 -34 23 61 20 -69 25 32 27 84 14 187 24 -81 21 786 27 -625 23 913 19 -578 28 330 18 -143 26 -42 18 -32 24 -227 21 -73 21 118 27 11 19 779 24 -1014 21 538 22 779 26 -174 21 -465 22 251 22 -515 24 344 23 -233 22 -319 22 148 22 253 21 2862 25 -2920 22 13 19 277 26 -718 24 293 22 560 22 623 20 -583 23 -66 22 -439 23 82 23 -610 24 -92 27 660 18 -869 24 103 20 98 22 -16 22 -60 27 -183 19 180 24 -13 18 303 24 -140 25 101 23 -404 19 -156 23 34 24 -60 3384 4609 100 MP stroke 28 2 15 0 36 -5 18 3 10 0 39 -3 22 0 23 0 22 0 23 0 22 0 22 21 23 -21 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 22 0 23 0 22 0 23 0 20 3 25 -3 22 0 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 23 0 22 0 22 0 23 0 22 0 23 0 22 0 23 0 2 32 43 -32 22 0 23 0 22 0 23 0 18 169 27 -169 22 0 3 169 26 -166 32 2 29 -5 23 0 22 0 23 0 20 32 23 2 20 225 21 97 28 -356 6 496 36 -459 18 372 30 -409 22 0 1 5 44 -5 10 13 35 -13 19 11 26 -11 23 0 22 0 22 3 14 63 28 -63 1151 4609 100 MP stroke 26 282 1125 4327 2 MP stroke gr 3116 4941 mt ( log10\(|a_{i,j}|\)) s 489 2877 mt -90 rotate ( # of entries) s 90 rotate 1950 273 mt ( BCSSTK23: profile of magnitudes of matrix entries) s end eplot %%EndObject graph 1 epage end showpage %%Trailer %%EOF InpMtx/doc/makefile010064400020550007177000000000270654276745100155740ustar00clevecompmath00000400000006clean : - rm -f *.dvi Iter/Iter.h010064400020550007177000000234470664026447000140720ustar00clevecompmath00000400000006#include "../A2.h" #include "../FrontMtx.h" #include "../Drand.h" #include "../SymbFac.h" #include "../timings.h" #include "../misc.h" #include "../DenseMtx.h" #include "../InpMtx.h" #include "../Utilities.h" #define CONVER_TOL 1.0e-6 #define BiCGStabR 0 #define BiCGStabL 1 #define MLBiCGStabR 2 #define MLBiCGStabL 3 #define TFQMRR 4 #define TFQMRL 5 #define PCGR 6 #define PCGL 7 #define BGMRESR 8 #define BGMRESL 9 int bicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int bicgstabl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int tfqmrr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int tfqmrl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int pcgr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int pcgl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int mlbicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxQ, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int mlbicgstabl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxQ, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int bgmresr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int maxnouter, int maxninner, int *pnouter, int *pninner, double convergetol, int msglvl, FILE *msgFile ); int bgmresl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int maxnouter, int maxninner, int *pnouter, int *pninner, double convergetol, int msglvl, FILE *msgFile ); int zbicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int zbicgstabl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int ztfqmrr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int ztfqmrl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int zpcgr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int zpcgl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int zmlbicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxQ, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); int zmlbicgstabl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxQ, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ); /*************************** NEW UTILITY ROUTINES ********************/ double DenseMtx_frobNorm ( DenseMtx *mtx ); double DenseMtx_twoNormOfColumn ( DenseMtx *mtx, int jcol ); /* ------------------------------------------------------ copy column icol of a Dense matrix A to column jcol of a Dense matrix B. Ai->Bj. ------------------------------------------------------ */ void DenseMtx_colCopy ( DenseMtx *mtxB, int jcol, DenseMtx *mtxA, int icol ); /* ------------------------------------------------------ compute dot product of column icol of a Dense matrix A and column jcol of a Dense matrix B prod=Ai^H * Bj. ------------------------------------------------------ */ void DenseMtx_colDotProduct ( DenseMtx *mtxA, int icol, DenseMtx *mtxB, int jcol, double *prod ); /* ------------------------------------------------------ compute a general axpy with column icol of a Dense matrix A and column jcol of a Dense matrix B. Ai=alpha*Ai+beta*Bj. ------------------------------------------------------ */ void DenseMtx_colGenAxpy ( double *alpha, DenseMtx *mtxA, int icol, double *beta, DenseMtx *mtxB, int jcol ); /* ----------------------------------------------- copy col icolA from mtxA into col icolB in mtxB ----------------------------------------------- */ void DenseMtx_copyCoulmn ( DenseMtx *mtxB, int icolB, DenseMtx *mtxA, int icolA ); /* ----------------------------------------------- FrontMtx_solve with column icol of rhsmtx as right-hand-side. ----------------------------------------------- */ void FrontMtx_solveOneColumn ( FrontMtx *frontmtx, DenseMtx *solmtx, int jcol, DenseMtx *rhsmtx, int icol, SubMtxManager *mtxmanager, double cpus[], int msglvl, FILE *msgFile ); /* ------------------------------------------- performs the matrix-matrix operations C = beta*C + alpha*(A)*(B) A, B and C must be column major. */ int DenseMtx_mmm( char *A_opt, char *B_opt, double *beta, DenseMtx *mtxC, double *alpha, DenseMtx *mtxA, DenseMtx *mtxB ); /* ---------------------------------------------- return the absolute value of a complex number ---------------------------------------------- */ double zabs(double *x); /* ------------------------------------------- compute the sum of two complex numbers ------------------------------------------- */ void zadd (double *x, double *y, double *u ); /* ------------------------------------------- divide two complex numbers ------------------------------------------- */ void zdiv (double *x, double *y, double *u ); /* ------------------------------------------- multiply two complex numbers ------------------------------------------- */ void zmul(double *x, double *y, double *u ); /* --------------------------------------------- compute the difference of two complex numbers --------------------------------------------- */ void zsub (double *x, double *y, double *u ); Iter/src/makefile010075500020550007177000000014540664344665100153100ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Iter $(OBJ).a : \ $(OBJ).a(bicgstabr.o) \ $(OBJ).a(bicgstabl.o) \ $(OBJ).a(mlbicgstabr.o) \ $(OBJ).a(mlbicgstabl.o) \ $(OBJ).a(pcgr.o)\ $(OBJ).a(pcgl.o)\ $(OBJ).a(tfqmrr.o)\ $(OBJ).a(tfqmrl.o)\ $(OBJ).a(zbicgstabr.o) \ $(OBJ).a(zbicgstabl.o) \ $(OBJ).a(zmlbicgstabr.o) \ $(OBJ).a(zmlbicgstabl.o) \ $(OBJ).a(zpcgl.o)\ $(OBJ).a(zpcgr.o)\ $(OBJ).a(bgmresl.o)\ $(OBJ).a(bgmresr.o)\ $(OBJ).a(ztfqmrr.o)\ $(OBJ).a(ztfqmrl.o)\ $(OBJ).a(DenseMtx_mmm.o) \ $(OBJ).a(util.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG Iter/src/makeGlobalLib010064400020550007177000000011330664026467200162050ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Iter SRC = bicgstabl.c \ bicgstabr.c \ mlbicgstabl.c \ mlbicgstabr.c \ pcgl.c \ pcgr.c \ bgmresr.c \ bgmresl.c \ tfqmrl.c \ tfqmrr.c \ zbicgstabl.c \ zbicgstabr.c \ zmlbicgstabl.c \ zmlbicgstabr.c \ zpcgl.c \ zpcgr.c \ ztfqmrl.c \ ztfqmrr.c \ DenseMtx_mmm.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Iter/src/DenseMtx_mmm.c010064400020550007177000000273270664345020100163370ustar00clevecompmath00000400000006/* DenseMtx_mmm.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------- performs the matrix-matrix operations C = beta*C + alpha*(A)*(B) A, B and C must be column major. Parameters --- A_opt -- form of op( A ) to be used = 'N' or 'n', op( A ) = A. = 'T' or 't', op( A ) = A'. = 'C' or 'c', op( A ) = A*. B_opt -- form of op( B ) to be used = 'N' or 'n', op( B ) = B. = 'T' or 't', op( B ) = B'. = 'C' or 'c', op( B ) = B*. return values --- 1 -- normal return -1 -- C, A, B, alpha or beta is NULL -2 -- type of A, B or C are invalid -3 -- row or column of A and B is not match -4 -- invalid option for A or B created -- 98dec11, ycp ------------------------------------------- */ int DenseMtx_mmm( char *A_opt, char *B_opt, double *beta, DenseMtx *mtxC, double *alpha, DenseMtx *mtxA, DenseMtx *mtxB ) { int nrowA, ncolA, rowincA, colincA; int nrowB, ncolB, rowincB, colincB; int nrowC, ncolC, rowincC, colincC; int ierr, i, k, j, l; double *Ai, *Bj, *Ci, r_alpha, r_beta, r_temp, im_temp, im_alpha, im_beta; double one[2]={1.0, 0.0}, zero[2]={0.0, 0.0}, aconj[2], bconj[2] ; double temp[2]={0.0, 0.0}, result[2]={1.0, 0.0} ; if ( beta == NULL || alpha == NULL || mtxC == NULL || mtxA == NULL || mtxB == NULL ){ fprintf(stderr, "\n fatal error in Input" "\n one or more of beta, alpha, mtxC, mtxB and" " mtxA is NULL\n") ; return(-1) ; } if ( (DENSEMTX_IS_REAL(mtxA) != DENSEMTX_IS_REAL(mtxB)) || (DENSEMTX_IS_REAL(mtxA) != DENSEMTX_IS_REAL(mtxC)) ){ fprintf(stderr,"mtxA, mtxB and mtxC do not have the same data type\n"); return(-2); } DenseMtx_dimensions(mtxA, &nrowA, &ncolA); DenseMtx_dimensions(mtxB, &nrowB, &ncolB); DenseMtx_dimensions(mtxC, &nrowC, &ncolC); rowincA=DenseMtx_rowIncrement(mtxA); colincA=DenseMtx_columnIncrement(mtxA); rowincB=DenseMtx_rowIncrement(mtxB); colincB=DenseMtx_columnIncrement(mtxB); rowincC=DenseMtx_rowIncrement(mtxC); colincC=DenseMtx_columnIncrement(mtxC); r_alpha=*alpha; r_beta =*beta; r_temp =*temp; if ( B_opt[0] == 'N' || B_opt[0] == 'n' ){ if (A_opt[0] == 'N' || A_opt[0] == 'n'){/*Form C := beta*c+alpha*A*B*/ if (ncolA != nrowB || nrowC != nrowA || ncolC != ncolB) { fprintf(stderr,"Error in Input DenseMtx_mmm\n"); return(-3); } } else if ( (A_opt[0] == 'T' || A_opt[0] == 't') || (A_opt[0] == 'C' || A_opt[0] == 'c') ){ if (nrowA != nrowB || nrowC != ncolA || ncolC != ncolB) { fprintf(stderr,"Error in Input DenseMtx_mmm\n"); exit(-3); } } else { fprintf(stderr,"Invalid option for mtxA\n"); return(-4); } } else if ( (B_opt[0] == 'T' || B_opt[0] == 't') || (B_opt[0] == 'C' || B_opt[0] == 'c') ){ if (A_opt[0] == 'N' || A_opt[0] == 'n'){ if (ncolA != ncolB || nrowC != nrowA || ncolC != nrowB) { fprintf(stderr,"Error in Input DenseMtx_mmm\n"); return(-3); } } else if ( (A_opt[0] == 'T' || A_opt[0] == 't') || (A_opt[0] == 'C' || A_opt[0] == 'c') ){ if (nrowA != ncolB || nrowC != ncolA || ncolC != nrowB) { fprintf(stderr,"Error in Input DenseMtx_mmm\n"); return(-3); } } else { fprintf(stderr,"Invalid option for mtxA\n"); return(-4); } } else { fprintf(stderr,"Invalid option for mtxB\n"); return(-4); } if (DENSEMTX_IS_REAL(mtxA)) { if ( r_alpha == *zero ) { if( r_beta == *zero ) { DenseMtx_zero (mtxC); } else { DenseMtx_scale(mtxC,&r_beta); } return(1); } if ( B_opt[0] == 'N' || B_opt[0] == 'n' ){ if (A_opt[0] == 'N' || A_opt[0] == 'n'){/*Form C := beta*c+alpha*A*B*/ for (i=0; i 0 and msgFile = NULL created -- 98dec03, dkw --------------------------------------------------------------------- */ int bgmresl ( int neqns, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *mtxM, DenseMtx *mtxX, DenseMtx *mtxB, int maxnouter, int maxninner, int *pnouter, int *pninner, double convergetol, int msglvl, FILE *msgFile ) { A2 *A2G, *A2Gi, *A2Gj, *A2H, *A2Hij, *A2Hkj, *A2H11, *A2H12, *A2Vj, *A2Vk, *A2Z ; DenseMtx *G, *Gj, *H, *Hij, *Hkj, *V, *Vi, *Vj, *Vk, *Z; double Hkk, Hik, initResNorm, ops, resnorm, t0, t1 ; double cpus[9], minusone[2] = {-1.0, 0.0}, one[2] = {1.0, 0.0}, zero[2] = {0.0, 0.0} ; double *col, *val, *Y ; DV workDV ; int converged, i, ii, iinner, jinner, jouter, kinner, nrhs, nstep, hijfrow, hijlrow, hijfcol, hijlcol, hkjfcol, hkjlcol, iend, inc1, inc2, irow, istart, jcol, ncol, ndiag, nrow, rc, vifcol, vilcol, vjfcol, vjlcol, vkfcol, vklcol ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( neqns <= 0 ) { fprintf(stderr, "\n error in bgmresl()" "\n neqns = %d\n", neqns) ; return(-1) ; } if ( type != SPOOLES_REAL ) { fprintf(stderr, "\n error in bgmresl()" "\n type = %d, must be SPOOLES_REAL\n", type) ; return(-2) ; } if ( symmetryflag != SPOOLES_SYMMETRIC && symmetryflag != SPOOLES_NONSYMMETRIC ) { fprintf(stderr, "\n error in bgmresl()" "\n symmetryflag = %d" "\n must be SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC\n", symmetryflag) ; return(-3) ; } if ( mtxA == NULL ) { fprintf(stderr, "\n error in bgmresl()" "\n mtxA is NULL\n") ; return(-4) ; } if ( mtxX == NULL ) { fprintf(stderr, "\n error in bgmresl()" "\n mtxX is NULL\n") ; return(-5) ; } if ( mtxB == NULL ) { fprintf(stderr, "\n error in bgmresl()" "\n mtxB is NULL\n") ; return(-6) ; } if ( convergetol < 0.0 ) { fprintf(stderr, "\n error in bgmresl()" "\n convergetol is %e\n", convergetol) ; return(-7) ; } if ( maxnouter <= 0 || maxninner <= 0 ) { fprintf(stderr, "\n error in bgmresl()" "\n maxnouter %d, maxninner %d\n", maxnouter, maxninner) ; return(-8) ; } if ( pnouter == NULL ) { fprintf(stderr, "\n error in bgmresl()" "\n pnouter is NULL\n") ; return(-9) ; } if ( pninner == NULL ) { fprintf(stderr, "\n error in bgmresl()" "\n pninner is NULL\n") ; return(-10) ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n error in bgmresl()" "\n msglvl = %d and msgFile is NULL\n", msglvl) ; return(-11) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n maximum # of outer iterations = %d" "\n maximum # of inner iterations = %d", maxnouter, maxninner) ; fflush(msgFile) ; } /* ------------------------------------------------- check for zero rhs (if B is zero, then X is zero) ------------------------------------------------- */ initResNorm = DenseMtx_frobNorm(mtxB) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n initial residual = %12.4e", initResNorm) ; fflush(msgFile) ; } if ( initResNorm == 0.0 ) { *pnouter = *pninner = 0 ; return(1) ; } /* --------------------------- initialize the working data --------------------------- */ nrhs = mtxB->ncol ; Y = DVinit(maxninner+1, 0.0) ; DV_setDefaultFields(&workDV) ; H = DenseMtx_new() ; DenseMtx_init(H, SPOOLES_REAL, 0, 0, (maxninner+1)*nrhs, maxninner*nrhs, 1, (maxninner+1)*nrhs) ; DenseMtx_zero(H) ; V = DenseMtx_new() ; DenseMtx_init(V, SPOOLES_REAL, 0, 0, neqns, nrhs*(maxninner+1), 1, neqns) ; DenseMtx_zero(V) ; G = DenseMtx_new() ; DenseMtx_init(G, SPOOLES_REAL, 0, 0, (maxninner+1)*nrhs, nrhs, 1, (maxninner+1)*nrhs) ; DenseMtx_zero(G) ; Z = DenseMtx_new() ; DenseMtx_init(Z, SPOOLES_REAL, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(Z) ; Vi = DenseMtx_new() ; Vj = DenseMtx_new() ; Vk = DenseMtx_new() ; Gj = DenseMtx_new() ; Hij = DenseMtx_new() ; Hkj = DenseMtx_new() ; A2G = A2_new() ; A2H = A2_new() ; A2Z = A2_new() ; DenseMtx_setA2(Z, A2Z) ; /* --------------------------- main loop of the iterations --------------------------- */ converged = 0 ; for ( jouter = 0 ; jouter < maxnouter ; jouter++ ) { A2Gi = A2_new() ; A2Vj = A2_new() ; DenseMtx_zero(H) ; DenseMtx_zero(V) ; DenseMtx_zero(G) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n outer iteration %d", jouter) ; fflush(msgFile) ; } /* ----------------------------------------------------- compute the preconditioned residual and load into V_0 1. compute W = B - A*X 2. solve M Z = W 3. set W = Z ----------------------------------------------------- */ if ( msglvl > 3 ) { fprintf(msgFile, "\n\n B") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } for ( i = 0 ; i < nrhs ; i++ ) DenseMtx_colCopy(Z, i, mtxB, i) ; if ( symmetryflag == SPOOLES_SYMMETRIC ) { InpMtx_sym_mmm(mtxA, Z, minusone, mtxX) ; } else { InpMtx_nonsym_mmm(mtxA, Z, minusone, mtxX) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ||B - A*X||_f = %12.4e", DenseMtx_frobNorm(Z)) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n B - A*X") ; DenseMtx_writeForHumanEye(Z, msgFile) ; fflush(msgFile) ; } if ( mtxM != NULL ) { FrontMtx_solve(mtxM, Z, Z, mtxM->manager, cpus, 0, msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ||M^{-1}(B - A*X)||_f = %12.4e", DenseMtx_frobNorm(Z)) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n M^{-1}(B - A*X)") ; DenseMtx_writeForHumanEye(Z, msgFile) ; fflush(msgFile) ; } /* --------------------------------------------------- Compute the QR factorization of the initial residual to get our starting orthogonal vectors V_0 and our top block in G --------------------------------------------------- */ ops = A2_QRreduce(A2Z, &workDV, msglvl, msgFile) ; rc = DenseMtx_initAsSubmatrix(Vj, V, 0, neqns-1, 0, nrhs-1) ; DenseMtx_setA2(Vj, A2Vj) ; A2_computeQ(A2Vj, A2Z, &workDV, msglvl, msgFile) ; DenseMtx_initAsSubmatrix(Gj, G, 0, 2*nrhs-1, 0, nrhs-1) ; DenseMtx_setA2(Gj, A2Gi) ; nrow = A2Z->n1 ; ncol = A2Z->n2 ; inc1 = A2Z->inc1 ; inc2 = A2Z->inc2 ; if ( nrow >= ncol ) { ndiag = ncol ; } else { ndiag = nrow ; } for ( jcol = 0, col = A2Z->entries, val = A2Gi->entries ; jcol < ncol ; jcol++, col += inc2, val += inc2 ) { istart = 0 ; iend = (jcol < ndiag) ? jcol : ndiag - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1 ) { val[ii] = col[ii] ; } } resnorm = DenseMtx_frobNorm(G) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n V_%d = ", jouter) ; A2_writeForHumanEye(A2Vj, msgFile) ; fprintf(msgFile, "\n\n G_%d%d = ", jouter, jouter) ; A2_writeForHumanEye(A2Gi, msgFile) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ||G||_f = %12.4e", resnorm) ; fflush(msgFile) ; } if ( resnorm == 0.0 ) { break ; } if ( jouter == 0 ) { initResNorm = resnorm ; } /* ------------------------------------------------------------ loop over the inner gmres iterations using Arnoldi iteration ------------------------------------------------------------ */ nstep = maxninner - 1 ; for ( jinner = 0 ; jinner < maxninner ; jinner++ ) { A2Gj = A2_new() ; A2Hij = A2_new() ; A2Hkj = A2_new() ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inner iteration %d", jinner) ; fflush(msgFile) ; } /* ---------------------------- compute W = M^{-1} * A * V_j ---------------------------- */ DenseMtx_zero(Z) ; vjfcol = jinner*nrhs ; vjlcol = vjfcol+nrhs-1 ; DenseMtx_initAsSubmatrix(Vj, V, 0, neqns-1, vjfcol, vjlcol) ; if ( symmetryflag == SPOOLES_SYMMETRIC ) { InpMtx_sym_mmm(mtxA, Z, one, Vj) ; } else { InpMtx_nonsym_mmm(mtxA, Z, one, Vj) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ||A*V_%d||_f = %12.4e", jinner, DenseMtx_frobNorm(Z)) ; fflush(msgFile) ; } if ( mtxM != NULL ) { FrontMtx_solve(mtxM, Z, Z, mtxM->manager, cpus, 0, msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ||M^{-1}*A*V_%d||_f = %12.4e", jinner, DenseMtx_frobNorm(Z)) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n M^{-1}*A*V_%d", jinner) ; DenseMtx_writeForHumanEye(Z, msgFile) ; fflush(msgFile) ; } for ( iinner = 0 ; iinner <= jinner ; iinner++ ) { vifcol = iinner*nrhs ; vilcol = vifcol+nrhs-1 ; DenseMtx_initAsSubmatrix(Vi, V, 0, neqns-1, vifcol, vilcol) ; hijfrow = vifcol ; hijlrow = vilcol ; hijfcol = jinner*nrhs ; hijlcol = hijfcol+nrhs-1 ; DenseMtx_initAsSubmatrix(Hij, H, hijfrow, hijlrow, hijfcol, hijlcol) ; DenseMtx_mmm("t", "n", zero, Hij, one, Vi, Z) ; DenseMtx_mmm("n", "n", one, Z, minusone, Vi, Hij) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n H_%d%d = ", iinner, jinner) ; DenseMtx_writeForHumanEye(Hij, msgFile) ; fflush(msgFile) ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n Wj after Arnoldi iteration") ; DenseMtx_writeForHumanEye(Z, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------------- compute V_jinner+1 and H_jinner+1,jinner blocks using QR decomposition of W_j then copy R from A2Z(1:ncolA,1:ncolA) into H_jinner+1,jinner ----------------------------------------------- */ ops = A2_QRreduce(A2Z, &workDV, msglvl, msgFile) ; vkfcol = vjlcol+1 ; vklcol = vkfcol+nrhs-1 ; DenseMtx_initAsSubmatrix(Vk, V, 0, neqns-1, vkfcol, vklcol) ; A2Vk = A2_new() ; DenseMtx_setA2(Vk, A2Vk) ; A2_computeQ(A2Vk, A2Z, &workDV, msglvl, msgFile) ; A2_free(A2Vk) ; hijfrow = hijlrow+1 ; hijlrow = hijfrow+nrhs-1 ; DenseMtx_initAsSubmatrix(Hkj, H, hijfrow, hijlrow, hijfcol, hijlcol) ; DenseMtx_setA2(Hkj, A2Hkj) ; nrow = A2Z->n1 ; ncol = A2Z->n2 ; inc1 = A2Z->inc1 ; inc2 = A2Z->inc2 ; if ( nrow >= ncol ) { ndiag = ncol ; } else { ndiag = nrow ; } for ( jcol = 0, col = A2Z->entries, val = A2Hkj->entries ; jcol < ncol ; jcol++, col += inc2, val += inc2 ) { istart = 0 ; iend = (jcol < ndiag) ? jcol : ndiag - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1 ) { val[ii] = col[ii] ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n V_%d = ", jinner+1) ; DenseMtx_writeForHumanEye(Vk, msgFile) ; fprintf(msgFile, "\n\n H_%d%d = ", jinner+1, jinner) ; DenseMtx_writeForHumanEye(Hij, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------- Before starting the next iteration, triangulate the Hessenberg matrix. To do this we must first apply the previous triangulating transformations to the newly constructed columns and then triangulate the new portion of the Hessenberg matrix. When we compute these new transformations we need to also apply them to the corresponding portion of G to keep track of the norm of the current residual. First apply the previous transformations ------------------------------------------------- */ hijfrow = 0 ; hijlrow = 2*nrhs-1 ; hkjfcol = 0 ; hkjlcol = nrhs-1 ; for ( iinner = 0 ; iinner <= jinner-1 ; iinner++ ) { A2H11 = A2_new() ; A2H12 = A2_new() ; DenseMtx_initAsSubmatrix(Hij, H, hijfrow, hijlrow, hkjfcol, hkjlcol) ; DenseMtx_setA2(Hij, A2H11) ; DenseMtx_initAsSubmatrix(Hkj, H, hijfrow, hijlrow, hijfcol, hijlcol) ; DenseMtx_setA2(Hkj, A2H12) ; A2_applyQT(A2H12, A2H11, A2H12, &workDV, msglvl, msgFile) ; hijfrow += nrhs ; hijlrow += nrhs ; hkjfcol += nrhs ; hkjlcol += nrhs ; A2_free(A2H11) ; A2_free(A2H12) ; } /* ------------------------------------------------- Compute the QR factorization of the diagonal and subdiagonal blocks of the block Hessenberg matrix ------------------------------------------------- */ DenseMtx_initAsSubmatrix(Hij, H, hijfrow, hijlrow, hijfcol, hijlcol) ; DenseMtx_setA2(Hij, A2Hij) ; ops = A2_QRreduce(A2Hij, &workDV, msglvl, msgFile) ; /* ---------------------------------------------------------- apply the transformation to the corresponding section of G ---------------------------------------------------------- */ DenseMtx_initAsSubmatrix(Gj, G, hijfrow, hijlrow, 0, nrhs-1) ; DenseMtx_setA2(Gj, A2Gj) ; A2_applyQT(A2Gj, A2Hij, A2Gj, &workDV, msglvl, msgFile) ; DenseMtx_initAsSubmatrix(Gj, G, hijfrow+nrhs, hijlrow, 0, nrhs-1) ; resnorm = DenseMtx_frobNorm(Gj) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n outer %d, inner %d, res = %24.16e", jouter, jinner, resnorm) ; fflush(msgFile) ; } /* ----------------- check convergence ----------------- */ if ( resnorm <= convergetol * initResNorm ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n BGMRESL convergence has been achieved") ; fprintf(msgFile, "\n ***convergetol = %24.16e", convergetol) ; fprintf(msgFile, "\n ***initResNorm = %24.16e", initResNorm) ; fflush(msgFile) ; } /* ------------------------------------------------ convergence has been achieved, break out of loop ------------------------------------------------ */ nstep = jinner ; converged = 1 ; A2_free(A2Gj) ; A2_free(A2Hij) ; A2_free(A2Hkj) ; break ; } A2_free(A2Gj) ; A2_free(A2Hij) ; A2_free(A2Hkj) ; } /* ---------------------------------- for each rhs copy Gi into vector Y solve Y := H^{-1} Y and store Y back into Gi ---------------------------------- */ DenseMtx_setA2(H, A2H) ; DenseMtx_setA2(G, A2G) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n H") ; A2H->n1 = nstep+1 ; A2H->n2 = nstep+1 ; A2_writeForHumanEye(A2H, msgFile) ; A2G->n1 = nstep+1 ; fprintf(msgFile, "\n\n G") ; A2_writeForHumanEye(A2G, msgFile) ; A2H->n1 = maxninner+1 ; A2H->n2 = maxninner+1 ; fprintf(msgFile, "\n\n before solve, Y") ; fprintf(msgFile, "\n\n before solve ykinner = %24.16e ",Y[7]) ; DVfprintf(msgFile, nstep+1, Y) ; fflush(msgFile) ; } for ( i = 0 ; i < nrhs ; i++ ) { A2_extractColumn(A2G, Y, i) ; for ( kinner = nstep ; kinner >= 0 ; kinner-- ) { A2_realEntry(A2H, kinner, kinner, &Hkk) ; Y[kinner] = Y[kinner] / Hkk ; for ( iinner = 0 ; iinner < kinner ; iinner++ ) { A2_realEntry(A2H, iinner, kinner, &Hik) ; Y[iinner] -= Y[kinner] * Hik ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after solve, Y") ; DVfprintf(msgFile, nstep+1, Y) ; fflush(msgFile) ; } A2_setColumn(A2G, Y, i) ; } /* ------------------------------------- compute the new solution X := X + V*Y ------------------------------------- */ DenseMtx_mmm("n", "n", one, mtxX, one, V, G) ; if ( msglvl > 2 ) { resnorm = DenseMtx_frobNorm(mtxX) ; fprintf(msgFile, "\n ||X||_f = %24.16e", resnorm) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n X") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } if ( converged == 1 ) { break ; } A2_free(A2Gi) ; A2_free(A2Vj) ; } /* ----------- return info ----------- */ *pnouter = jouter + 1 ; *pninner = jinner + 1 ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n before leaving, *pnouter = %d, *pinner = %d", *pnouter, *pninner) ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ A2_free(A2G) ; A2_free(A2H) ; A2_free(A2Z) ; A2_free(A2Gi) ; A2_free(A2Vj) ; DenseMtx_free(Gj) ; DenseMtx_free(G) ; DenseMtx_free(Hij) ; DenseMtx_free(Hkj) ; DenseMtx_free(H) ; DenseMtx_free(Vi) ; DenseMtx_free(Vj) ; DenseMtx_free(Vk) ; DenseMtx_free(V) ; DenseMtx_free(Z) ; DV_clearData(&workDV) ; DVfree(Y) ; return(1) ; } /*--------------------------------------------------------------------*/ ile, "\n\n G_%d%d = ", jouter, jouter) ; A2_writeForHumanEye(A2Gi, msgFile) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ||G||_f = %12.4e", resnorm) ; fflush(msgFile) ; } if ( resnorm == 0.0 ) { break ; } if ( jouter == 0 ) { initResNorm = resnorm ; } /* ------------------------------------------------------------ loop over the inner gmres iterationIter/src/bgmresr.c010064400020550007177000000451520664345020100153770ustar00clevecompmath00000400000006/* bgmresr.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve the system A X = B using the block GMRES Arnoldi iteration method with right preconditioning neqns -- # of equations type -- must be SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- must be SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC mtxA -- pointer to object for A mtxM -- pointer to object for M, may be NULL mtxX -- pointer to object for X, zero on input mtxB -- pointer to object for B maxnouter -- maximum number of outer iterations maxninner -- maximum number of inner iterations pninner -- the last # of inner iterations executed pnouter -- the last # of outer iterations executed convergetol -- tolerance for convergence convergence achieved when ||r||_f <= convergetol * ||r_0||_f msglvl -- message level 1 -- no output 2 -- iteration #, residual, ratio 3 -- scalar information 4 -- scalar and vector information msgFile -- message file return value --- 1 -- normal return -1 -- neqns <= 0 -2 -- type invalid -3 -- symmetryflag invalid -4 -- mtxA NULL -5 -- mtxX NULL -6 -- mtxB NULL -7 -- convergetol invalid -8 -- maxnouter and/or maxninner invalid -9 -- pnouter NULL -10 -- pninner NULL -11 -- msglvl > 0 and msgFile = NULL created -- 98dec03, dkw --------------------------------------------------------------------- */ int bgmresr ( int neqns, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *mtxM, DenseMtx *mtxX, DenseMtx *mtxB, int maxnouter, int maxninner, int *pnouter, int *pninner, double convergetol, int msglvl, FILE *msgFile ) { A2 *A2G, *A2Gi, *A2Gj, *A2H, *A2Hij, *A2Hkj, *A2H11, *A2H12, *A2Vj, *A2Vk, *A2Z ; DenseMtx *G, *Gj, *H, *Hij, *Hkj, *V, *Vi, *Vj, *Vk, *W, *Z; double Hkk, Hik, initResNorm, ops, resnorm, t0, t1 ; double cpus[9], minusone[2] = {-1.0, 0.0}, one[2] = {1.0, 0.0}, zero[2] = {0.0, 0.0} ; double *col, *val, *Y ; DV workDV ; int converged, i, ii, iinner, jinner, jouter, kinner, nrhs, nstep, hijfrow, hijlrow, hijfcol, hijlcol, hkjfcol, hkjlcol, iend, inc1, inc2, irow, istart, jcol, ncol, ndiag, nrow, rc, vifcol, vilcol, vjfcol, vjlcol, vkfcol, vklcol ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( neqns <= 0 ) { fprintf(stderr, "\n error in bgmresr()" "\n neqns = %d\n", neqns) ; return(-1) ; } if ( type != SPOOLES_REAL ) { fprintf(stderr, "\n error in bgmresr()" "\n type = %d, must be SPOOLES_REAL\n", type) ; return(-2) ; } if ( symmetryflag != SPOOLES_SYMMETRIC && symmetryflag != SPOOLES_NONSYMMETRIC ) { fprintf(stderr, "\n error in bgmresr()" "\n symmetryflag = %d" "\n must be SPOOLES_SYMMETRIC or SPOOLES_NONSYMMETRIC\n", symmetryflag) ; return(-3) ; } if ( mtxA == NULL ) { fprintf(stderr, "\n error in bgmresr()" "\n mtxA is NULL\n") ; return(-4) ; } if ( mtxX == NULL ) { fprintf(stderr, "\n error in bgmresr()" "\n mtxX is NULL\n") ; return(-5) ; } if ( mtxB == NULL ) { fprintf(stderr, "\n error in bgmresr()" "\n mtxB is NULL\n") ; return(-6) ; } if ( convergetol < 0.0 ) { fprintf(stderr, "\n error in bgmresr()" "\n convergetol is %e\n", convergetol) ; return(-7) ; } if ( maxnouter <= 0 || maxninner <= 0 ) { fprintf(stderr, "\n error in bgmresr()" "\n maxnouter %d, maxninner %d\n", maxnouter, maxninner) ; return(-8) ; } if ( pnouter == NULL ) { fprintf(stderr, "\n error in bgmresr()" "\n pnouter is NULL\n") ; return(-9) ; } if ( pninner == NULL ) { fprintf(stderr, "\n error in bgmresr()" "\n pninner is NULL\n") ; return(-10) ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n error in bgmresr()" "\n msglvl = %d and msgFile is NULL\n", msglvl) ; return(-11) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n maximum # of outer iterations = %d" "\n maximum # of inner iterations = %d", maxnouter, maxninner) ; fflush(msgFile) ; } /* ------------------------------------------------- check for zero rhs (if B is zero, then X is zero) ------------------------------------------------- */ initResNorm = DenseMtx_frobNorm(mtxB) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n initial residual = %12.4e", initResNorm) ; fflush(msgFile) ; } if ( initResNorm == 0.0 ) { *pnouter = *pninner = 0 ; return(1) ; } /* --------------------------- initialize the working data --------------------------- */ nrhs = mtxB->ncol ; Y = DVinit(maxninner+1, 0.0) ; DV_setDefaultFields(&workDV) ; H = DenseMtx_new() ; DenseMtx_init(H, SPOOLES_REAL, 0, 0, (maxninner+1)*nrhs, maxninner*nrhs, 1, (maxninner+1)*nrhs) ; DenseMtx_zero(H) ; V = DenseMtx_new() ; DenseMtx_init(V, SPOOLES_REAL, 0, 0, neqns, nrhs*(maxninner+1), 1, neqns) ; DenseMtx_zero(V) ; G = DenseMtx_new() ; DenseMtx_init(G, SPOOLES_REAL, 0, 0, (maxninner+1)*nrhs, nrhs, 1, (maxninner+1)*nrhs) ; DenseMtx_zero(G) ; Z = DenseMtx_new() ; DenseMtx_init(Z, SPOOLES_REAL, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(Z) ; W = DenseMtx_new() ; DenseMtx_init(W, SPOOLES_REAL, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(W) ; Vi = DenseMtx_new() ; Vj = DenseMtx_new() ; Vk = DenseMtx_new() ; Gj = DenseMtx_new() ; Hij = DenseMtx_new() ; Hkj = DenseMtx_new() ; A2G = A2_new() ; A2H = A2_new() ; A2Z = A2_new() ; DenseMtx_setA2(Z, A2Z) ; /* --------------------------- main loop of the iterations --------------------------- */ converged = 0 ; for ( jouter = 0 ; jouter < maxnouter ; jouter++ ) { A2Gi = A2_new() ; A2Vj = A2_new() ; DenseMtx_zero(H) ; DenseMtx_zero(V) ; DenseMtx_zero(G) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n outer iteration %d", jouter) ; fflush(msgFile) ; } /* ----------------------------------------------------- compute the preconditioned residual and load into V_0 1. solve M Z = X 2. compute Z = A*Z ----------------------------------------------------- */ if ( msglvl > 3 ) { fprintf(msgFile, "\n\n B") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } if ( jouter == 0 ) { for ( i = 0 ; i < nrhs ; i++ ) DenseMtx_colCopy(Z, i, mtxB, i) ; }else{ if ( mtxM != NULL ) { FrontMtx_solve(mtxM, W, mtxX, mtxM->manager, cpus, 0, msgFile) ; } for ( i = 0 ; i < nrhs ; i++ ) DenseMtx_colCopy(Z, i, mtxB, i) ; if ( symmetryflag == SPOOLES_SYMMETRIC ) { InpMtx_sym_mmm(mtxA, Z, minusone, W) ; } else { InpMtx_nonsym_mmm(mtxA, Z, minusone, W) ; } } /* --------------------------------------------------- Compute the QR factorization of the initial residual to get our starting orthogonal vectors V_0 and our top block in G --------------------------------------------------- */ ops = A2_QRreduce(A2Z, &workDV, msglvl, msgFile) ; rc = DenseMtx_initAsSubmatrix(Vj, V, 0, neqns-1, 0, nrhs-1) ; DenseMtx_setA2(Vj, A2Vj) ; A2_computeQ(A2Vj, A2Z, &workDV, msglvl, msgFile) ; DenseMtx_initAsSubmatrix(Gj, G, 0, 2*nrhs-1, 0, nrhs-1) ; DenseMtx_setA2(Gj, A2Gi) ; nrow = A2Z->n1 ; ncol = A2Z->n2 ; inc1 = A2Z->inc1 ; inc2 = A2Z->inc2 ; if ( nrow >= ncol ) { ndiag = ncol ; } else { ndiag = nrow ; } for ( jcol = 0, col = A2Z->entries, val = A2Gi->entries ; jcol < ncol ; jcol++, col += inc2, val += inc2 ) { istart = 0 ; iend = (jcol < ndiag) ? jcol : ndiag - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1 ) { val[ii] = col[ii] ; } } resnorm = DenseMtx_frobNorm(G) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after QRreduce A2Vj =") ; fprintf(msgFile, "\n\n V_%d = ", jouter) ; A2_writeForHumanEye(A2Vj, msgFile) ; fprintf(msgFile, "\n\n G_%d%d = ", jouter, jouter) ; A2_writeForHumanEye(A2Gi, msgFile) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ||G||_f = %12.4e", resnorm) ; fflush(msgFile) ; } if ( resnorm == 0.0 ) { break ; } if ( jouter == 0 ) { initResNorm = resnorm ; } /* ------------------------------------------------------------ loop over the inner gmres iterations using Arnoldi iteration ------------------------------------------------------------ */ nstep = maxninner - 1 ; for ( jinner = 0 ; jinner < maxninner ; jinner++ ) { A2Gj = A2_new() ; A2Hij = A2_new() ; A2Hkj = A2_new() ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inner iteration %d", jinner) ; fflush(msgFile) ; } /* ---------------------------- compute W = A * M^{-1} * V_j ---------------------------- */ DenseMtx_zero(Z) ; vjfcol = jinner*nrhs ; vjlcol = vjfcol+nrhs-1 ; DenseMtx_initAsSubmatrix(Vj, V, 0, neqns-1, vjfcol, vjlcol) ; if ( mtxM != NULL ) { FrontMtx_solve(mtxM, W, Vj, mtxM->manager, cpus, 0, msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ||M^{-1}*V_%d||_f = %12.4e", jinner, DenseMtx_frobNorm(W)) ; fflush(msgFile) ; } if ( symmetryflag == SPOOLES_SYMMETRIC ) { InpMtx_sym_mmm(mtxA, Z, one, W) ; } else { InpMtx_nonsym_mmm(mtxA, Z, one, W) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ||A*M^{-1}V_%d||_f = %12.4e", jinner, DenseMtx_frobNorm(Z)) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n A*M^{-1}*V_%d", jinner) ; DenseMtx_writeForHumanEye(Z, msgFile) ; fflush(msgFile) ; } for ( iinner = 0 ; iinner <= jinner ; iinner++ ) { vifcol = iinner*nrhs ; vilcol = vifcol+nrhs-1 ; DenseMtx_initAsSubmatrix(Vi, V, 0, neqns-1, vifcol, vilcol) ; hijfrow = vifcol ; hijlrow = vilcol ; hijfcol = jinner*nrhs ; hijlcol = hijfcol+nrhs-1 ; DenseMtx_initAsSubmatrix(Hij, H, hijfrow, hijlrow, hijfcol, hijlcol) ; DenseMtx_mmm("t", "n", zero, Hij, one, Vi, Z) ; DenseMtx_mmm("n", "n", one, Z, minusone, Vi, Hij) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n H_%d%d = ", iinner, jinner) ; DenseMtx_writeForHumanEye(Hij, msgFile) ; fflush(msgFile) ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n Wj after Arnoldi iteration") ; DenseMtx_writeForHumanEye(Z, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------------- compute V_jinner+1 and H_jinner+1,jinner blocks using QR decomposition of W_j then copy R from A2Z(1:ncolA,1:ncolA) into H_jinner+1,jinner ----------------------------------------------- */ ops = A2_QRreduce(A2Z, &workDV, msglvl, msgFile) ; vkfcol = vjlcol+1 ; vklcol = vkfcol+nrhs-1 ; DenseMtx_initAsSubmatrix(Vk, V, 0, neqns-1, vkfcol, vklcol) ; A2Vk = A2_new() ; DenseMtx_setA2(Vk, A2Vk) ; A2_computeQ(A2Vk, A2Z, &workDV, msglvl, msgFile) ; A2_free(A2Vk) ; hijfrow = hijlrow+1 ; hijlrow = hijfrow+nrhs-1 ; DenseMtx_initAsSubmatrix(Hkj, H, hijfrow, hijlrow, hijfcol, hijlcol) ; DenseMtx_setA2(Hkj, A2Hkj) ; nrow = A2Z->n1 ; ncol = A2Z->n2 ; inc1 = A2Z->inc1 ; inc2 = A2Z->inc2 ; if ( nrow >= ncol ) { ndiag = ncol ; } else { ndiag = nrow ; } for ( jcol = 0, col = A2Z->entries, val = A2Hkj->entries ; jcol < ncol ; jcol++, col += inc2, val += inc2 ) { istart = 0 ; iend = (jcol < ndiag) ? jcol : ndiag - 1 ; for ( irow = istart, ii = irow*inc1 ; irow <= iend ; irow++, ii += inc1 ) { val[ii] = col[ii] ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n V_%d = ", jinner+1) ; DenseMtx_writeForHumanEye(Vk, msgFile) ; fprintf(msgFile, "\n\n H_%d%d = ", jinner+1, jinner) ; DenseMtx_writeForHumanEye(Hij, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------- Before starting the next iteration, triangulate the Hessenberg matrix. To do this we must first apply the previous triangulating transformations to the newly constructed columns and then triangulate the new portion of the Hessenberg matrix. When we compute these new transformations we need to also apply them to the corresponding portion of G to keep track of the norm of the current residual. First apply the previous transformations ------------------------------------------------- */ hijfrow = 0 ; hijlrow = 2*nrhs-1 ; hkjfcol = 0 ; hkjlcol = nrhs-1 ; for ( iinner = 0 ; iinner <= jinner-1 ; iinner++ ) { A2H11 = A2_new() ; A2H12 = A2_new() ; DenseMtx_initAsSubmatrix(Hij, H, hijfrow, hijlrow, hkjfcol, hkjlcol) ; DenseMtx_setA2(Hij, A2H11) ; DenseMtx_initAsSubmatrix(Hkj, H, hijfrow, hijlrow, hijfcol, hijlcol) ; DenseMtx_setA2(Hkj, A2H12) ; A2_applyQT(A2H12, A2H11, A2H12, &workDV, msglvl, msgFile) ; hijfrow += nrhs ; hijlrow += nrhs ; hkjfcol += nrhs ; hkjlcol += nrhs ; A2_free(A2H11) ; A2_free(A2H12) ; } /* ------------------------------------------------- Compute the QR factorization of the diagonal and subdiagonal blocks of the block Hessenberg matrix ------------------------------------------------- */ DenseMtx_initAsSubmatrix(Hij, H, hijfrow, hijlrow, hijfcol, hijlcol) ; DenseMtx_setA2(Hij, A2Hij) ; ops = A2_QRreduce(A2Hij, &workDV, msglvl, msgFile) ; /* ---------------------------------------------------------- apply the transformation to the corresponding section of G ---------------------------------------------------------- */ DenseMtx_initAsSubmatrix(Gj, G, hijfrow, hijlrow, 0, nrhs-1) ; DenseMtx_setA2(Gj, A2Gj) ; A2_applyQT(A2Gj, A2Hij, A2Gj, &workDV, msglvl, msgFile) ; DenseMtx_initAsSubmatrix(Gj, G, hijfrow+nrhs, hijlrow, 0, nrhs-1) ; resnorm = DenseMtx_frobNorm(Gj) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n outer %d, inner %d, res = %24.16e", jouter, jinner, resnorm) ; fflush(msgFile) ; } /* ----------------- check convergence ----------------- */ if ( resnorm <= convergetol * initResNorm ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n BGMRESR convergence has been achieved") ; fprintf(msgFile, "\n ***convergetol = %24.16e", convergetol) ; fprintf(msgFile, "\n ***initResNorm = %24.16e", initResNorm) ; fflush(msgFile) ; } /* ------------------------------------------------ convergence has been achieved, break out of loop ------------------------------------------------ */ nstep = jinner ; converged = 1 ; A2_free(A2Gj) ; A2_free(A2Hij) ; A2_free(A2Hkj) ; break ; } A2_free(A2Gj) ; A2_free(A2Hij) ; A2_free(A2Hkj) ; } /* ---------------------------------- for each rhs copy Gi into vector Y solve Y := H^{-1} Y and store Y back into Gi ---------------------------------- */ DenseMtx_setA2(H, A2H) ; DenseMtx_setA2(G, A2G) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n H") ; A2H->n1 = nstep+1 ; A2H->n2 = nstep+1 ; A2_writeForHumanEye(A2H, msgFile) ; A2G->n1 = nstep+1 ; fprintf(msgFile, "\n\n G") ; A2_writeForHumanEye(A2G, msgFile) ; A2H->n1 = maxninner+1 ; A2H->n2 = maxninner+1 ; fprintf(msgFile, "\n\n before solve, Y") ; fprintf(msgFile, "\n\n before solve ykinner = %24.16e ",Y[7]) ; DVfprintf(msgFile, nstep+1, Y) ; fflush(msgFile) ; } for ( i = 0 ; i < nrhs ; i++ ) { A2_extractColumn(A2G, Y, i) ; for ( kinner = nstep ; kinner >= 0 ; kinner-- ) { A2_realEntry(A2H, kinner, kinner, &Hkk) ; Y[kinner] = Y[kinner] / Hkk ; for ( iinner = 0 ; iinner < kinner ; iinner++ ) { A2_realEntry(A2H, iinner, kinner, &Hik) ; Y[iinner] -= Y[kinner] * Hik ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after solve, Y") ; DVfprintf(msgFile, nstep+1, Y) ; fflush(msgFile) ; } A2_setColumn(A2G, Y, i) ; } /* ------------------------------------- compute the new solution X := X + V*Y ------------------------------------- */ DenseMtx_mmm("n", "n", one, mtxX, one, V, G) ; if ( msglvl > 2 ) { resnorm = DenseMtx_frobNorm(mtxX) ; fprintf(msgFile, "\n ||X||_f = %24.16e", resnorm) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n X") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; } if ( converged == 1 ) { break ; } A2_free(A2Gi) ; A2_free(A2Vj) ; } /* ------------------ final solve MX = Y ------------------ */ if ( mtxM != NULL ) { FrontMtx_solve(mtxM, mtxX, mtxX, mtxM->manager, cpus, 0, msgFile) ; } if ( msglvl > 2 ) { resnorm = DenseMtx_frobNorm(mtxX) ; fprintf(msgFile, "\n ***after solve ||X||_f = %24.16e", resnorm) ; } /* ----------- return info ----------- */ *pnouter = jouter + 1 ; *pninner = jinner + 1 ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n before leaving, *pnouter = %d, *pinner = %d", *pnouter, *pninner) ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ A2_free(A2G) ; A2_free(A2H) ; A2_free(A2Z) ; A2_free(A2Gi) ; A2_free(A2Vj) ; DenseMtx_free(Gj) ; DenseMtx_free(G) ; DenseMtx_free(Hij) ; DenseMtx_free(Hkj) ; DenseMtx_free(H) ; DenseMtx_free(Vi) ; DenseMtx_free(Vj) ; DenseMtx_free(Vk) ; DenseMtx_free(V) ; DenseMtx_free(Z) ; DenseMtx_free(W) ; DV_clearData(&workDV) ; DVfree(Y) ; return(1) ; } /*--------------------------------------------------------------------*/ orm ; } /* ------------------------------------------------------------ loop over the inner gmres iterations using Arnoldi iteration ------------------------------------------------------------ */ nstep = maxninner - 1 ; for ( jinner = 0 ; jinner < maxninner ; jinner++ ) { A2Gj = A2_new() ; A2Hij = A2_new() ; A2Hkj = A2_new() ; if ( msglvl > 2 ) { fpriIter/src/bicgstabl.c010064400020550007177000000160060664345020100156640ustar00clevecompmath00000400000006/* bicgstabl.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a unsymmetric real matrix equation Ax=b using left preconditioned BiCGSTAB x -- Initial guess A -- Input matrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- 98spe10 wpt --------------------------------------------------------------------- */ int bicgstabl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxZ ; DenseMtx *vecP, *vecR, *vecR0, *vecT, *vecV, *vecW; DenseMtx *vecX, *vecY, *vecZ ; double Alpha, Beta, Init_norm, Omega, ratio, Res_norm, Rho, Rho_new, Rtmp, Rtmp2; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0}, zero[2]={0.0, 0.0} ; double Tiny = 0.1e-28; int Iter, Imv, neqns; int stats[6] ; neqns = n_matrixSize; /* -------------------- init the vectors in bicgstab -------------------- */ vecP = DenseMtx_new() ; DenseMtx_init(vecP, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecR0 = DenseMtx_new() ; DenseMtx_init(vecR0, type, 0, 0, neqns, 1, 1, neqns) ; vecT = DenseMtx_new() ; DenseMtx_init(vecT, type, 0, 0, neqns, 1, 1, neqns) ; vecV = DenseMtx_new() ; DenseMtx_init(vecV, type, 0, 0, neqns, 1, 1, neqns) ; vecW = DenseMtx_new() ; DenseMtx_init(vecW, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecY = DenseMtx_new() ; DenseMtx_init(vecY, type, 0, 0, neqns, 1, 1, neqns) ; vecZ = DenseMtx_new() ; DenseMtx_init(vecZ, type, 0, 0, neqns, 1, 1, neqns) ; /* -------------------------- Initialize the iterations -------------------------- */ /* ---- Set initial guess as zero ---- */ DenseMtx_zero(vecX) ; DenseMtx_colCopy(vecT, 0, mtxB, 0); /* */ FrontMtx_solve(Precond, vecR, vecT, Precond->manager, cpus, msglvl, msgFile) ; /* */ Init_norm = DenseMtx_twoNormOfColumn(vecR,0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; ratio = 1.0; DenseMtx_colCopy(vecR0, 0, vecR, 0); fprintf(msgFile, "\n BiCGSTAB Initial norm: %6.2e ", Init_norm ) ; fprintf(msgFile, "\n BiCGSTAB Conveg. Control: %6.2e ", convergetol ) ; /* */ Rho = 1.0; Alpha = 1.0; Omega = 1.0; DenseMtx_zero(vecV) ; DenseMtx_zero(vecP) ; /* ------------------------------ ------------------------------ */ MARKTIME(t1) ; Iter = 0; Imv = 0; /* ----------------- factor the matrix ----------------- */ while ( ratio > convergetol && Iter <= itermax ) { Iter++; DenseMtx_colDotProduct(vecR0, 0, vecR, 0, &Rho_new); Beta = (Rho_new / (Rho+Tiny)) * (Alpha / (Omega+Tiny)); Rho = Rho_new; /* DenseMtx_axpy(vecP, vecV, -Omega); */ Rtmp=-Omega; DenseMtx_colGenAxpy(one, vecP, 0, &Rtmp, vecV, 0); /* DenseMtx_aypx(vecP, vecR, Beta); */ DenseMtx_colGenAxpy(&Beta, vecP, 0, one, vecR, 0); /* DenseMtx_zero(vecY) ; InpMtx_nonsym_mmm(mtxA, vecY, one, vecP) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecY, one, vecP) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n BiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecY, one, vecP) ; break ; default : fprintf(msgFile, "\n BiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } /* */ FrontMtx_solve(Precond, vecV, vecY, Precond->manager, cpus, msglvl, msgFile) ; Imv++; /* */ DenseMtx_colDotProduct(vecR0, 0, vecV, 0, &Rtmp); Alpha = Rho / (Rtmp+Tiny); /* */ Rtmp=-Alpha; DenseMtx_colGenAxpy(one, vecR, 0, &Rtmp, vecV, 0); /* DenseMtx_zero(vecZ) ; InpMtx_nonsym_mmm(mtxA, vecZ, one, vecR) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecZ, one, vecR) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n BiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecZ, one, vecR) ; break ; default : fprintf(msgFile, "\n BiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } /* */ FrontMtx_solve(Precond, vecT, vecZ, Precond->manager, cpus, msglvl, msgFile) ; Imv++; /* */ DenseMtx_colDotProduct(vecT, 0, vecR, 0, &Rtmp); DenseMtx_colDotProduct(vecT, 0, vecT, 0, &Rtmp2); Omega = Rtmp/(Rtmp2+Tiny); DenseMtx_colGenAxpy(one, vecX, 0, &Alpha, vecP, 0); DenseMtx_colGenAxpy(one, vecX, 0, &Omega, vecR, 0); /* */ Rtmp=-Omega; DenseMtx_colGenAxpy(one, vecR, 0, &Rtmp, vecT, 0); Res_norm = DenseMtx_twoNormOfColumn(vecR,0); ratio = Res_norm/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e" "\n Residual norm is %6.2e", Imv, ratio, Res_norm) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after BICGSTABL") ; DenseMtx_colCopy(mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: DenseMtx_free(vecP) ; DenseMtx_free(vecR) ; DenseMtx_free(vecR0) ; DenseMtx_free(vecT) ; DenseMtx_free(vecV) ; DenseMtx_free(vecW) ; DenseMtx_free(vecX) ; DenseMtx_free(vecY) ; DenseMtx_free(vecZ) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/src/bicgstabr.c010064400020550007177000000147510664345020100156770ustar00clevecompmath00000400000006/* bicgstab.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a unsymmetric real matrix equation Ax=b using right preconditioned BiCGSTAB x -- Initial guess A -- Input matrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- 98spe10 wpt --------------------------------------------------------------------- */ int bicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxZ ; DenseMtx *vecP, *vecR, *vecR0, *vecT, *vecV, *vecW; DenseMtx *vecX, *vecY, *vecZ ; double Alpha, Beta, Init_norm, Omega, ratio, Res_norm, Rho, Rho_new, Rtmp, Rtmp2; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0}, zero[2]={0.0, 0.0} ; double Tiny = 0.1e-28; int Iter, Imv, neqns; int stats[6] ; neqns = n_matrixSize; /* -------------------- init the vectors in bicgstab -------------------- */ vecP = DenseMtx_new() ; DenseMtx_init(vecP, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecR0 = DenseMtx_new() ; DenseMtx_init(vecR0, type, 0, 0, neqns, 1, 1, neqns) ; vecT = DenseMtx_new() ; DenseMtx_init(vecT, type, 0, 0, neqns, 1, 1, neqns) ; vecV = DenseMtx_new() ; DenseMtx_init(vecV, type, 0, 0, neqns, 1, 1, neqns) ; vecW = DenseMtx_new() ; DenseMtx_init(vecW, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecY = DenseMtx_new() ; DenseMtx_init(vecY, type, 0, 0, neqns, 1, 1, neqns) ; vecZ = DenseMtx_new() ; DenseMtx_init(vecZ, type, 0, 0, neqns, 1, 1, neqns) ; /* -------------------------- Initialize the iterations -------------------------- */ Init_norm = DenseMtx_twoNormOfColumn(mtxB, 0); ratio = 1.0; DenseMtx_zero(vecX) ; DenseMtx_colCopy (vecR0, 0, mtxB, 0); DenseMtx_colCopy (vecR, 0, vecR0, 0); Iter = 0; Imv = 0; fprintf(msgFile, "\n BiCGSTAB Initial norml: %6.2ef ", Init_norm ) ; fprintf(msgFile, "\n BiCGSTAB Conveg. Control: %12.8f ", convergetol ) ; /* */ Rho = 1.0; Alpha = 1.0; Omega = 1.0; DenseMtx_zero(vecV) ; DenseMtx_zero(vecP) ; /* ------------------------------ ------------------------------ */ MARKTIME(t1) ; /* ----------------- factor the matrix ----------------- */ while ( ratio > convergetol && Iter <= itermax ) { Iter++; DenseMtx_colDotProduct(vecR0, 0, vecR, 0, &Rho_new); Beta = (Rho_new / (Rho+Tiny)) * (Alpha / (Omega+Tiny)); Rho = Rho_new; Rtmp=-Omega; DenseMtx_colGenAxpy(one, vecP, 0, &Rtmp, vecV, 0); DenseMtx_colGenAxpy(&Beta, vecP, 0, one, vecR, 0); /* */ FrontMtx_solve(Precond, vecY, vecP, Precond->manager, cpus, msglvl, msgFile) ; /* DenseMtx_zero(vecV) ; InpMtx_nonsym_mmm(mtxA, vecV, one, vecY) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecV, one, vecY) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n BiCGSTAB Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecV, one, vecY) ; break ; default : fprintf(msgFile, "\n BiCGSTAB Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; /* */ DenseMtx_colDotProduct(vecR0, 0, vecV, 0, &Rtmp); Alpha = Rho / (Rtmp+Tiny); /* */ Rtmp=-Alpha; DenseMtx_colGenAxpy(one, vecR, 0, &Rtmp, vecV, 0); /* */ FrontMtx_solve(Precond, vecZ, vecR, Precond->manager, cpus, msglvl, msgFile) ; /* DenseMtx_zero(vecT) ; InpMtx_nonsym_mmm(mtxA, vecT, one, vecZ) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecZ) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n BiCGSTAB Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecZ) ; break ; default : fprintf(msgFile, "\n BiCGSTAB Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; DenseMtx_colDotProduct(vecT, 0, vecR, 0, &Rtmp); DenseMtx_colDotProduct(vecT, 0, vecT, 0, &Rtmp2); Omega = Rtmp/(Rtmp2+Tiny); DenseMtx_colGenAxpy(one, vecX, 0, &Alpha, vecY, 0); DenseMtx_colGenAxpy(one, vecX, 0, &Omega, vecZ, 0); /* */ Rtmp=-Omega; DenseMtx_colGenAxpy(one, vecR, 0, &Rtmp, vecT, 0); Res_norm = DenseMtx_twoNormOfColumn(vecR,0); ratio = Res_norm/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e" "\n Residual norm is %6.2e", Imv, ratio, Res_norm) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after BICGSTABR") ; DenseMtx_colCopy (mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: DenseMtx_free(vecP) ; DenseMtx_free(vecR) ; DenseMtx_free(vecR0) ; DenseMtx_free(vecT) ; DenseMtx_free(vecV) ; DenseMtx_free(vecW) ; DenseMtx_free(vecX) ; DenseMtx_free(vecY) ; DenseMtx_free(vecZ) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/src/mlbicgstabl.c010064400020550007177000000337230664345020100162220ustar00clevecompmath00000400000006/* MLBiCGSTABL.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a unsymmetric real matrix equation Ax=b using left preconditioned ML(k)BiCGSTAB method by M-C Yeung and T. Chan x -- Initial guess as zeros A -- Input matrix Precond -- Front Matrix as the preconditioner Q -- Starting vectors b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- Nov. 28, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int mlbicgstabl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxQ, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxD, *mtxG, *mtxU, *mtxW; DenseMtx *vecGt, *vecR, *vecT, *vecT1; DenseMtx *vecX, *vecZD, *vecZG, *vecZW ; double Alpha, Beta, Rho ; double c[100] ; double Init_norm, ratio, Res_norm; double error_trol, m, Rtmp; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0} ; double zero[2] = {0.0, 0.0} ; double minusone[2] = {-1.0, 0.0}; double Tiny = 0.1e-28; int Iter, Imv, neqns, Ik, ii, is; int stats[6] ; int return_flag; neqns = n_matrixSize; Ik = mtxQ->ncol; if (Ik > 100){ fprintf(msgFile, "\n\n Fatal Error, \n" " Too many starting vectors in Q !!") ; return_flag = -1; return (return_flag); }; return_flag = 1; /* -------------------- init the vectors in MLBiCGSTABL -------------------- */ mtxD = DenseMtx_new() ; DenseMtx_init(mtxD, type, 0, 0, neqns, Ik, 1, neqns) ; mtxG = DenseMtx_new() ; DenseMtx_init(mtxG, type, 0, 0, neqns, Ik, 1, neqns) ; mtxU = DenseMtx_new() ; DenseMtx_init(mtxU, type, 0, 0, neqns, 2, 1, neqns) ; mtxW = DenseMtx_new() ; DenseMtx_init(mtxW, type, 0, 0, neqns, Ik, 1, neqns) ; vecGt = DenseMtx_new() ; DenseMtx_init(vecGt, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecT = DenseMtx_new() ; DenseMtx_init(vecT, type, 0, 0, neqns, 1, 1, neqns) ; vecT1 = DenseMtx_new() ; DenseMtx_init(vecT1, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecZD = DenseMtx_new() ; DenseMtx_init(vecZD, type, 0, 0, neqns, 1, 1, neqns) ; vecZG = DenseMtx_new() ; DenseMtx_init(vecZG, type, 0, 0, neqns, 1, 1, neqns) ; vecZW = DenseMtx_new() ; DenseMtx_init(vecZW, type, 0, 0, neqns, 1, 1, neqns) ; /* c = DV_new(); DV_init(c, Ik, NULL); */ for ( ii = 0; ii <100; ii++){ c[ii] = 0; } /* -------------------------- Initialize the iterations -------------------------- */ /* ---- Set initial guess as zero ---- */ DenseMtx_zero(vecX) ; /* ---- If x_0 is not zero ---- */ /* DenseMtx_colCopy(vecX, 0, mtxX, 0); */ /* InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecX) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n MLBiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; default : fprintf(msgFile, "\n MLBiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; } DenseMtx_colCopy(vecR, 0, mtxB, 0); DenseMtx_sub(vecR, vecT) ; FrontMtx_solve(Precond, vecT, vecR, Precond->manager, cpus, msglvl, msgFile) ; DenseMtx_colCopy(vecR, 0, vecT, 0); Init_norm = DenseMtx_twoNormOfColumn(vecR, 0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; error_trol = Init_norm * convergetol ; fprintf(msgFile, "\n MLBiCGSTABL Initial norml: %6.2e ", Init_norm ) ; fprintf(msgFile, "\n MLBiCGSTABL Conveg. Control: %7.3e ", convergetol ) ; fprintf(msgFile, "\n MLBiCGSTABL Convergen Control: %7.3e ",error_trol ) ; DenseMtx_zero(mtxG) ; DenseMtx_zero(mtxD) ; DenseMtx_zero(mtxW) ; Iter = 0; Imv = 0; DenseMtx_colCopy (mtxG, Ik-1, vecR, 0); /* ------------------------------ MLBiCGSTABL Iteration start ------------------------------ */ MARKTIME(t1) ; while ( Iter <= itermax ){ Iter++; /* g_tld = G(:,k); W(:,k) = U\(L\( A*g_tld)); */ DenseMtx_colCopy (vecGt, 0, mtxG, Ik-1); /* InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n MLBiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; default : fprintf(msgFile, "\n MLBiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; } FrontMtx_solveOneColumn(Precond, mtxW, Ik-1, vecT, 0, Precond->manager, cpus, msglvl, msgFile) ; Imv++; /* c[Ik] = *DenseMtx_colDotProduct (mtxQ, 0, mtxG, Ik-1); */ DenseMtx_colDotProduct (mtxQ, 0, mtxG, Ik-1, c+Ik); if (c[Ik] == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " MLBiCGSTABL Breakdown, c[k] = 0 !!") ; return_flag = -1; goto end; }; /* Alpha = Q(:,1)'*r/c(k); ; */ DenseMtx_colDotProduct (mtxQ,0, vecR, 0, &Rtmp); Alpha = Rtmp/c[Ik]; DenseMtx_colCopy (mtxU, 0, vecR, 0); Rtmp = -Alpha; DenseMtx_colGenAxpy (one, mtxU, 0, &Rtmp, mtxW, Ik-1); /* u = r - alpha*W(:,k); u_tld = u; temp = U\(L\(A*u_tld)); rho =temp'*temp; */ DenseMtx_colCopy (mtxU, 1, mtxU, 0); DenseMtx_colCopy (vecT, 0, mtxU, 0); /* InpMtx_nonsym_gmmm(mtxA, zero, vecT1, one, vecT) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT1, one, vecT) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n MLBiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT1, one, vecT) ; break ; default : fprintf(msgFile, "\n MLBiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; } FrontMtx_solveOneColumn(Precond, vecT, 0, vecT1, 0, Precond->manager, cpus, msglvl, msgFile) ; Imv++; /* Rho = temp'*temp; */ DenseMtx_colDotProduct (vecT, 0, vecT, 0, &Rho); if (Rho == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " MLBiCGSTABL Breakdown, Rho = 0 !!") ; return_flag = -1; goto end; }; /* Rho = -(*DenseMtx_colDotProduct (mtxU, 0, vecT, 0))/Rho; */ DenseMtx_colDotProduct (mtxU, 0, vecT, 0, &Rtmp); Rho = -Rtmp/Rho; DenseMtx_colGenAxpy(one, vecX, 0, &Alpha, vecGt, 0); Rtmp = -Rho; DenseMtx_colGenAxpy (one, vecX, 0, &Rtmp, mtxU, 1) ; DenseMtx_colCopy (vecR, 0, mtxU, 0); DenseMtx_colGenAxpy (one, vecR, 0, &Rho, vecT, 0) ; /* Iter++; */ /* ---------------- Convergence Test --------------- */ Rtmp = DenseMtx_twoNormOfColumn ( vecR, 0); ratio = Rtmp/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e" "\n Residual norm is %6.2ee", Imv, ratio, Rtmp) ; fflush(msgFile) ; if ( Rtmp <= error_trol ) { fprintf(msgFile, "\n # iterations = %d", Imv) ; return_flag = Imv; goto end; }; for (ii = 1; ii < Ik+1; ii++ ){ if (Iter > itermax ){ fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n MLBiCGSTABL did not Converge !") ; return_flag = Imv; goto end; }; DenseMtx_colCopy (vecZD,0, mtxU, 0); DenseMtx_colCopy (vecZG,0, vecR, 0); DenseMtx_zero(vecZW) ; if ( Iter > 1 ){ for ( is = ii ; is < Ik ; is++ ){ /* Beta =-( *(DenseMtx_colDotProduct(mtxQ, is, vecZD, 0)))/c[is]; */ DenseMtx_colDotProduct(mtxQ, is, vecZD, 0, &Rtmp); Beta = -Rtmp/c[is]; DenseMtx_colGenAxpy (one, vecZD, 0, &Beta, mtxD, is-1); DenseMtx_colGenAxpy (one, vecZG, 0, &Beta, mtxG, is-1); DenseMtx_colGenAxpy (one, vecZW, 0, &Beta, mtxW, is-1); }; }; Beta = Rho * c[Ik]; if (Beta == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " MLBiCGSTABL Breakdown, Beta = 0 !!") ; return_flag = -1; goto end; }; /* Beta = - Q(:,1)'* (r + Rho* zw )/ Beta; */ DenseMtx_colCopy (vecT, 0, vecR, 0); DenseMtx_colGenAxpy (one, vecT, 0, &Rho, vecZW, 0); /* Beta = - (*DenseMtx_colDotProduct(mtxQ, 0, vecT, 0))/Beta; */ DenseMtx_colDotProduct(mtxQ, 0, vecT, 0, &Rtmp); Beta = - Rtmp/Beta; /* zg = zg + beta*G(:,k); zw = rho*(zw + beta*W(:,k)); zd = r + zw; */ DenseMtx_colGenAxpy (one, vecZG, 0, &Beta, mtxG, Ik-1); Rtmp = Rho*Beta; DenseMtx_colGenAxpy (&Rho, vecZW, 0, &Rtmp, mtxW, Ik-1); DenseMtx_colCopy (vecZD, 0, vecR, 0); DenseMtx_colGenAxpy (one, vecZD, 0, one, vecZW, 0); /* for s = 1:i-1 beta = -Q(:,s+1)'*zd/c(s); zd = zd + beta*D(:,s); zg = zg + beta*G(:,s); end */ for ( is = 1; is < ii - 1; is ++){ /* Beta = -(*DenseMtx_colDotProduct(mtxQ, is, vecZD, 0))/c[is] ; */ DenseMtx_colDotProduct(mtxQ, is, vecZD, 0, &Rtmp); Beta = - Rtmp/c[is]; DenseMtx_colGenAxpy (one, vecZD, 0, &Beta, mtxD, is-1); DenseMtx_colGenAxpy (one, vecZG, 0, &Beta, mtxG, is-1); }; /* D(:,i) = zd - u; G(:,i) = zg + zw; */ DenseMtx_colCopy (mtxD, ii-1, vecZD, 0); DenseMtx_colGenAxpy (one, mtxD, ii-1, minusone, mtxU, 0); DenseMtx_colCopy (mtxG, ii-1, vecZG, 0); DenseMtx_colGenAxpy (one, mtxG, ii-1, one, vecZW, 0); /* if i < k c(i) = Q(:,i+1)'*D(:,i); */ if ( ii < Ik ){ /* c[ii] = *DenseMtx_colDotProduct(mtxQ, ii, mtxD, ii-1); */ DenseMtx_colDotProduct(mtxQ, ii, mtxD, ii-1, c+ii); /* If breakdown ? */ if (c[ii] == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " MLBiCGSTABL Breakdown, c[ii] = 0 !!") ; return_flag = -1; goto end; }; /* alpha = Q(:,i+1)'*u/c(i); u = u - alpha*D(:,i); g_tld = G(:,i); */ DenseMtx_colDotProduct(mtxQ, ii, mtxU, 0, &Rtmp); Alpha = Rtmp/c[ii]; Rtmp = -Alpha; DenseMtx_colGenAxpy (one, mtxU, 0, &Rtmp, mtxD, ii-1); DenseMtx_colCopy (vecGt, 0, mtxG, ii-1); /* x = x + rho*alpha*g_tld; W(:,i) = U\(L\(A*g_tld)); r = r - rho*alpha*W(:,i); */ Rtmp = Rho * Alpha; DenseMtx_colGenAxpy (one, vecX, 0, &Rtmp, vecGt, 0); /* InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n MLBiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; default : fprintf(msgFile, "\n MLBiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; } FrontMtx_solveOneColumn(Precond, mtxW, ii-1, vecT, 0, Precond->manager, cpus, msglvl, msgFile) ; Imv++; Rtmp = -Rtmp; DenseMtx_colGenAxpy (one, vecR, 0, &Rtmp, mtxW, ii-1); /* ---------------- Convergence Test --------------- */ Rtmp = DenseMtx_twoNormOfColumn ( vecR, 0); if ( Rtmp <= error_trol ) { fprintf(msgFile, "\n # iterations = %d", Imv) ; return_flag = Imv; goto end; }; }; }; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n MLBiCGSTABL did not Converge !") ; DenseMtx_colCopy(mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; DenseMtx_colCopy(mtxX, 0, vecX, 0); /* InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n MLBiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n MLBiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp = DenseMtx_twoNormOfColumn(vecT, 0); fprintf(msgFile, "\n MLBiCGSTABL True Residual norm: %6.2e ", Rtmp) ; fprintf(msgFile, "\n\n after MLBiCGSTABL") ; DenseMtx_free(mtxD) ; DenseMtx_free(mtxG) ; DenseMtx_free(mtxU) ; DenseMtx_free(mtxW) ; DenseMtx_free(vecGt) ; DenseMtx_free(vecR) ; DenseMtx_free(vecT) ; DenseMtx_free(vecT1) ; DenseMtx_free(vecX) ; DenseMtx_free(vecZD) ; DenseMtx_free(vecZG) ; DenseMtx_free(vecZW) ; fprintf(msgFile, "\n") ; return(return_flag) ; } /*--------------------------------------------------------------------*/ ); return_flag = -1; goto end; case SIter/src/mlbicgstabr.c010064400020550007177000000344430664345020100162300ustar00clevecompmath00000400000006/* MLBiCGSTAB.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a unsymmetric real matrix equation Ax=b using right preconditioned ML(k)BiCGSTAB method by M-C Yeung and T. Chan x -- Initial guess as zeros A -- Input matrix Precond -- Front Matrix as the preconditioner Q -- Starting vectors b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- Nov. 28, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int mlbicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxQ, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxD, *mtxG, *mtxU, *mtxW; DenseMtx *vecGt, *vecR, *vecT, *vecT1; DenseMtx *vecX, *vecZD, *vecZG, *vecZW ; double Alpha, Beta, Rho ; double c[100] ; double Init_norm, ratio, Res_norm; double error_trol, m, Rtmp; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0} ; double zero[2] = {0.0, 0.0} ; double minusone[2] = {-1.0, 0.0}; double Tiny = 0.1e-28; int Iter, Imv, neqns, Ik, ii, is; int stats[6] ; int return_flag; neqns = n_matrixSize; Ik = mtxQ->ncol; if (Ik > 100){ fprintf(msgFile, "\n\n Fatal Error, \n" " Too many starting vectors in Q !!") ; return_flag = -1; return (return_flag); }; return_flag = 1; /* -------------------- init the vectors in MLBiCGSTAB -------------------- */ mtxD = DenseMtx_new() ; DenseMtx_init(mtxD, type, 0, 0, neqns, Ik, 1, neqns) ; mtxG = DenseMtx_new() ; DenseMtx_init(mtxG, type, 0, 0, neqns, Ik, 1, neqns) ; mtxU = DenseMtx_new() ; DenseMtx_init(mtxU, type, 0, 0, neqns, 2, 1, neqns) ; mtxW = DenseMtx_new() ; DenseMtx_init(mtxW, type, 0, 0, neqns, Ik, 1, neqns) ; vecGt = DenseMtx_new() ; DenseMtx_init(vecGt, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecT = DenseMtx_new() ; DenseMtx_init(vecT, type, 0, 0, neqns, 1, 1, neqns) ; vecT1 = DenseMtx_new() ; DenseMtx_init(vecT1, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecZD = DenseMtx_new() ; DenseMtx_init(vecZD, type, 0, 0, neqns, 1, 1, neqns) ; vecZG = DenseMtx_new() ; DenseMtx_init(vecZG, type, 0, 0, neqns, 1, 1, neqns) ; vecZW = DenseMtx_new() ; DenseMtx_init(vecZW, type, 0, 0, neqns, 1, 1, neqns) ; /* c = DV_new(); DV_init(c, Ik, NULL); */ for ( ii = 0; ii <100; ii++){ c[ii] = 0; } /* -------------------------- Initialize the iterations -------------------------- */ /* ---- Set initial guess as zero ---- */ DenseMtx_zero(vecX) ; /* ---- If x_0 is not zero ---- */ /* DenseMtx_copy(vecX, mtxX); */ /* InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecX) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n MLBiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; default : fprintf(msgFile, "\n MLBiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; } DenseMtx_colCopy(vecR, 0, mtxB, 0); DenseMtx_sub(vecR, vecT) ; Init_norm = DenseMtx_twoNormOfColumn(vecR, 0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; error_trol = Init_norm * convergetol ; fprintf(msgFile, "\n MLBiCGSTAB Initial norml: %6.2e ", Init_norm ) ; fprintf(msgFile, "\n MLBiCGSTAB Conveg. Control: %7.3e ", convergetol ) ; fprintf(msgFile, "\n MLBiCGSTAB Convergen Control: %7.3e ",error_trol ) ; DenseMtx_zero(mtxG) ; DenseMtx_zero(mtxD) ; DenseMtx_zero(mtxW) ; Iter = 0; Imv = 0; DenseMtx_colCopy (mtxG, Ik-1, vecR, 0); /* ------------------------------ MLBiCGSTAB Iteration start ------------------------------ */ MARKTIME(t1) ; while ( Iter <= itermax ){ Iter++; /* DenseMtx_colCopy (vecT,0, mtxG,Ik-1); FrontMtx_solve(Precond, vecGt, vecT, Precond->manager, cpus, msglvl, msgFile) ; */ FrontMtx_solveOneColumn(Precond, vecGt, 0, mtxG, Ik-1, Precond->manager, cpus, msglvl, msgFile) ; /* InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n MLBiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; default : fprintf(msgFile, "\n MLBiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; } DenseMtx_colCopy (mtxW, Ik-1, vecT, 0); Imv++; /* c[Ik] = *DenseMtx_colDotProduct (mtxQ, 0, mtxG, Ik-1); */ DenseMtx_colDotProduct (mtxQ, 0, mtxG, Ik-1, c+Ik); if (c[Ik] == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " MLBiCGSTAB Breakdown, c[k] = 0 !!") ; return_flag = -1; goto end; }; /* Alpha =( *DenseMtx_colDotProduct (mtxQ,0, vecR, 0))/c[Ik] ; */ DenseMtx_colDotProduct (mtxQ,0, vecR, 0, &Rtmp); Alpha = Rtmp/c[Ik]; DenseMtx_colCopy (mtxU, 0, vecR, 0); Rtmp = -Alpha; DenseMtx_colGenAxpy (one, mtxU, 0, &Rtmp, mtxW, Ik-1); /* DenseMtx_colCopy (vecT, 0, mtxU, 0); FrontMtx_solve(Precond, vecT1, vecT, Precond->manager, cpus, msglvl, msgFile) ; DenseMtx_colCopy (mtxU, 1, vecT1, 0); InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecT1) ; */ FrontMtx_solveOneColumn(Precond, vecT1, 0, mtxU, 0, Precond->manager, cpus, msglvl, msgFile) ; DenseMtx_colCopy (mtxU, 1, vecT1, 0); /* InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecT1) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecT1) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n MLBiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecT1) ; break ; default : fprintf(msgFile, "\n MLBiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; } Imv++; /* Rho = *DenseMtx_colDotProduct (vecT, 0, vecT, 0); */ DenseMtx_colDotProduct (vecT, 0, vecT, 0, &Rho); if (Rho == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " MLBiCGSTAB Breakdown, Rho = 0 !!") ; return_flag = -1; goto end; }; /* Rho = -(*DenseMtx_colDotProduct (mtxU, 0, vecT, 0))/Rho; */ DenseMtx_colDotProduct (mtxU, 0, vecT, 0, &Rtmp); Rho = -Rtmp/Rho; DenseMtx_colGenAxpy(one, vecX, 0, &Alpha, vecGt, 0); Rtmp = -Rho; DenseMtx_colGenAxpy (one, vecX, 0, &Rtmp, mtxU, 1) ; DenseMtx_colCopy (vecR, 0, mtxU, 0); DenseMtx_colGenAxpy (one, vecR, 0, &Rho, vecT, 0) ; /* Iter++; */ /* ---------------- Convergence Test --------------- */ Rtmp = DenseMtx_twoNormOfColumn (vecR, 0); ratio = Rtmp/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e" "\n Residual norm is %6.2ee", Imv, ratio, Rtmp) ; fflush(msgFile) ; if ( Rtmp <= error_trol ) { fprintf(msgFile, "\n # iterations = %d", Imv) ; return_flag = Imv; goto end; }; for (ii = 1; ii < Ik+1; ii++ ){ if (Iter > itermax ){ fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n MLBiCGSTAB did not Converge !") ; return_flag = Imv; goto end; }; DenseMtx_colCopy (vecZD,0, mtxU, 0); DenseMtx_colCopy (vecZG,0, vecR, 0); DenseMtx_zero(vecZW) ; if ( Iter > 1 ){ for ( is = ii ; is < Ik ; is++ ){ /* Beta =-( *(DenseMtx_colDotProduct(mtxQ, is, vecZD, 0)))/c[is]; */ DenseMtx_colDotProduct(mtxQ, is, vecZD, 0, &Rtmp); Beta = -Rtmp/c[is]; DenseMtx_colGenAxpy (one, vecZD, 0, &Beta, mtxD, is-1); DenseMtx_colGenAxpy (one, vecZG, 0, &Beta, mtxG, is-1); DenseMtx_colGenAxpy (one, vecZW, 0, &Beta, mtxW, is-1); }; }; Beta = Rho * c[Ik]; if (Beta == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " MLBiCGSTAB Breakdown, Beta = 0 !!") ; return_flag = -1; goto end; }; /* Beta = - Q(:,1)'* (r + Rho* zw )/ Beta; */ DenseMtx_colCopy (vecT, 0, vecR, 0); DenseMtx_colGenAxpy (one, vecT, 0, &Rho, vecZW, 0); /* Beta = - (*DenseMtx_colDotProduct(mtxQ, 0, vecT, 0))/Beta; */ DenseMtx_colDotProduct(mtxQ, 0, vecT, 0, &Rtmp); Beta = - Rtmp/Beta; /* zg = zg + beta*G(:,k); zw = rho*(zw + beta*W(:,k)); zd = r + zw; */ DenseMtx_colGenAxpy (one, vecZG, 0, &Beta, mtxG, Ik-1); Rtmp = Rho*Beta; DenseMtx_colGenAxpy (&Rho, vecZW, 0, &Rtmp, mtxW, Ik-1); DenseMtx_colCopy (vecZD, 0, vecR, 0); DenseMtx_colGenAxpy (one, vecZD, 0, one, vecZW, 0); /* for s = 1:i-1 beta = -Q(:,s+1)'*zd/c(s); zd = zd + beta*D(:,s); zg = zg + beta*G(:,s); end */ for ( is = 1; is < ii - 1; is ++){ /* Beta = -(*DenseMtx_colDotProduct(mtxQ, is, vecZD, 0))/c[is] ; */ DenseMtx_colDotProduct(mtxQ, is, vecZD, 0, &Rtmp); Beta = - Rtmp/c[is]; DenseMtx_colGenAxpy (one, vecZD, 0, &Beta, mtxD, is-1); DenseMtx_colGenAxpy (one, vecZG, 0, &Beta, mtxG, is-1); }; /* D(:,i) = zd - u; G(:,i) = zg + zw; */ DenseMtx_colCopy (mtxD, ii-1, vecZD, 0); DenseMtx_colGenAxpy (one, mtxD, ii-1, minusone, mtxU, 0); DenseMtx_colCopy (mtxG, ii-1, vecZG, 0); DenseMtx_colGenAxpy (one, mtxG, ii-1, one, vecZW, 0); /* if i < k c(i) = Q(:,i+1)'*D(:,i); */ if ( ii < Ik ){ /* c[ii] = *DenseMtx_colDotProduct(mtxQ, ii, mtxD, ii-1); */ DenseMtx_colDotProduct(mtxQ, ii, mtxD, ii-1, c+ii); /* If breakdown ? */ if (c[ii] == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " MLBiCGSTAB Breakdown, c[ii] = 0 !!") ; return_flag = -1; goto end; }; /* alpha = Q(:,i+1)'*u/c(i); u = u - alpha*D(:,i); g_tld = U\(L\G(:,i)); */ /* Alpha = (*DenseMtx_colDotProduct(mtxQ, ii, mtxU, 0))/c[ii]; */ DenseMtx_colDotProduct(mtxQ, ii, mtxU, 0, &Rtmp); Alpha = Rtmp/c[ii]; Rtmp = -Alpha; DenseMtx_colGenAxpy (one, mtxU, 0, &Rtmp, mtxD, ii-1); /* DenseMtx_colCopy (vecT, 0, mtxG, ii-1); FrontMtx_solve(Precond, vecGt, vecT, Precond->manager, cpus, msglvl, msgFile) ; */ FrontMtx_solveOneColumn(Precond, vecGt, 0, mtxG, ii-1, Precond->manager, cpus, msglvl, msgFile) ; /* x = x + rho*alpha*g_tld; W(:,i) = A*g_tld; r = r - rho*alpha*W(:,i); */ Rtmp = Rho * Alpha; DenseMtx_colGenAxpy (one, vecX, 0, &Rtmp, vecGt, 0); /* InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n MLBiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; default : fprintf(msgFile, "\n MLBiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; } Imv++; DenseMtx_colCopy (mtxW, ii-1, vecT, 0); Rtmp = -Rtmp; DenseMtx_colGenAxpy (one, vecR, 0, &Rtmp, mtxW, ii-1); /* ---------------- Convergence Test --------------- */ Rtmp = DenseMtx_twoNormOfColumn (vecR, 0); if ( Rtmp <= error_trol ) { fprintf(msgFile, "\n # iterations = %d", Imv) ; return_flag = Imv; goto end; }; }; }; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n MLBiCGSTAB did not Converge !") ; DenseMtx_colCopy(mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; /* DenseMtx_copy(mtxX, vecX); */ DenseMtx_colCopy(mtxX, 0, vecX, 0); /* InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n MLBiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n MLBiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp = DenseMtx_twoNormOfColumn(vecT, 0); fprintf(msgFile, "\n MLBiCGSTAB True Residual norm: %6.2e ", Rtmp) ; fprintf(msgFile, "\n\n after MLBiCGSTABR") ; DenseMtx_free(mtxD) ; DenseMtx_free(mtxG) ; DenseMtx_free(mtxU) ; DenseMtx_free(mtxW) ; DenseMtx_free(vecGt) ; DenseMtx_free(vecR) ; DenseMtx_free(vecT) ; DenseMtx_free(vecT1) ; DenseMtx_free(vecX) ; DenseMtx_free(vecZD) ; DenseMtx_free(vecZG) ; DenseMtx_free(vecZW) ; fprintf(msgFile, "\n") ; return(return_flag) ; } /*--------------------------------------------------------------------*/ npMtx_sym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n MLBiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); return_flag = -1; goto end; case SIter/src/pcgl.c010064400020550007177000000106000664345020100146510ustar00clevecompmath00000400000006/* pcgl.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a symmetric nonnegative matrix equation Ax=b using left preconditioned conjugate gradient method x -- Initial guess A -- Input matrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file created -- Oct. 27, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int pcgl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxZ ; DenseMtx *vecP, *vecR, *vecQ ; DenseMtx *vecX, *vecZ ; double Alpha, Beta, Rho, Rho0, Init_norm, ratio, Res_norm, Rtmp ; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0}, zero[2] = {0.0, 0.0} ; double Tiny = 0.1e-28; int Iter, neqns; int stats[6] ; if (symmetryflag != SPOOLES_SYMMETRIC){ fprintf(msgFile, "\n\n Fatal Error, \n" " Matrix is not symmetric in PCGL !!") ; return (-1); }; neqns = n_matrixSize; /* -------------------- init the vectors in bicgstab -------------------- */ vecP = DenseMtx_new() ; DenseMtx_init(vecP, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecQ = DenseMtx_new() ; DenseMtx_init(vecQ, type, 0, 0, neqns, 1, 1, neqns) ; vecZ = DenseMtx_new() ; DenseMtx_init(vecZ, type, 0, 0, neqns, 1, 1, neqns) ; /* -------------------------- Initialize the iterations -------------------------- */ FrontMtx_solve(Precond, vecR, mtxB, Precond->manager, cpus, msglvl, msgFile) ; Init_norm = DenseMtx_twoNormOfColumn(vecR,0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; ratio = 1.0; DenseMtx_zero(vecX) ; /* DenseMtx_copy(vecR, mtxB); */ MARKTIME(t1) ; Iter = 0; /* ------------------------------ Main Loop of the iterations ------------------------------ */ while ( ratio > convergetol && Iter <= itermax ) { Iter++; /* */ DenseMtx_colDotProduct(vecR, 0, vecR, 0, &Rho); /* */ if ( Iter == 1 ) { DenseMtx_colCopy(vecP, 0, vecR, 0); } else { Beta = Rho /(Rho0 + Tiny); DenseMtx_colGenAxpy(&Beta, vecP, 0, one, vecR, 0); }; InpMtx_sym_gmmm(mtxA, zero, vecZ, one, vecP) ; FrontMtx_solve(Precond, vecQ, vecZ, Precond->manager, cpus, msglvl, msgFile) ; DenseMtx_colDotProduct(vecP, 0, vecQ, 0, &Rtmp); Alpha = Rho/(Rtmp+Tiny); DenseMtx_colGenAxpy(one, vecX, 0, &Alpha, vecP, 0); Rtmp=-Alpha; DenseMtx_colGenAxpy(one, vecR, 0, &Rtmp, vecQ, 0); Rho0 = Rho; /* */ Res_norm = DenseMtx_twoNormOfColumn(vecR,0); ratio = Res_norm/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e", Iter, ratio) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Iter) ; fprintf(msgFile, "\n\n after PCGL") ; DenseMtx_colCopy(mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: DenseMtx_free(vecP) ; DenseMtx_free(vecR) ; DenseMtx_free(vecX) ; DenseMtx_free(vecQ) ; DenseMtx_free(vecZ) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ atrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerancIter/src/pcgr.c010064400020550007177000000104670664345020100146720ustar00clevecompmath00000400000006/* pcgr.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a symmetric nonnegative matrix equation Ax=b using right preconditioned conjugate gradient method x -- Initial guess A -- Input matrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- final residual norm created -- Oct. 27, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int pcgr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxZ ; DenseMtx *vecP, *vecR, *vecQ ; DenseMtx *vecX, *vecZ ; double Alpha, Beta, Rho, Rho0, Init_norm, ratio, Res_norm, Rtmp ; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0} ; double Tiny = 0.1e-28; int Iter, neqns; int stats[6] ; if (symmetryflag != SPOOLES_SYMMETRIC){ fprintf(msgFile, "\n\n Fatal Error, \n" " Matrix is not symmetric in PCGR !!") ; return(-1); }; neqns = n_matrixSize; /* -------------------- init the vectors in bicgstab -------------------- */ vecP = DenseMtx_new() ; DenseMtx_init(vecP, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecQ = DenseMtx_new() ; DenseMtx_init(vecQ, type, 0, 0, neqns, 1, 1, neqns) ; vecZ = DenseMtx_new() ; DenseMtx_init(vecZ, type, 0, 0, neqns, 1, 1, neqns) ; /* -------------------------- Initialize the iterations -------------------------- */ Init_norm = DenseMtx_twoNormOfColumn(mtxB,0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; ratio = 1.0; DenseMtx_zero(vecX) ; DenseMtx_colCopy(vecR, 0, mtxB, 0); MARKTIME(t1) ; Iter = 0; /* ------------------------------ Main Loop of the iterations ------------------------------ */ while ( ratio > convergetol && Iter <= itermax ) { Iter++; /* */ FrontMtx_solve(Precond, vecZ, vecR, Precond->manager, cpus, msglvl, msgFile) ; DenseMtx_colDotProduct(vecR, 0, vecZ, 0, &Rho); /* */ if ( Iter == 1 ) { DenseMtx_colCopy(vecP, 0, vecZ, 0); } else { Beta = Rho /(Rho0 + Tiny); DenseMtx_colGenAxpy(&Beta, vecP, 0, one, vecZ, 0); }; DenseMtx_zero(vecQ); InpMtx_sym_mmm(mtxA, vecQ, one, vecP) ; DenseMtx_colDotProduct(vecP, 0, vecQ, 0, &Rtmp); Alpha = Rho/(Rtmp+Tiny); DenseMtx_colGenAxpy(one, vecX, 0, &Alpha, vecP, 0); Rtmp=-Alpha; DenseMtx_colGenAxpy(one, vecR, 0, &Rtmp, vecQ, 0); Rho0 = Rho; /* */ Res_norm = DenseMtx_twoNormOfColumn(vecR,0); ratio = Res_norm/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e", Iter, ratio) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Iter) ; fprintf(msgFile, "\n\n after PCGR") ; DenseMtx_colCopy(mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(vecP) ; DenseMtx_free(vecR) ; DenseMtx_free(vecX) ; DenseMtx_free(vecQ) ; DenseMtx_free(vecZ) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/src/tfqmrl.c010064400020550007177000000264370664345020100152500ustar00clevecompmath00000400000006/* TFQMRL.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a unsymmetric real matrix equation Ax=b using Left preconditioned TFQMR method without lookahead x -- Initial guess as zeros A -- Input matrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- Oct. 28, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int tfqmrl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *vecD, *vecR, *vecT, *vecU1, *vecU2, *vecV, *vecW; DenseMtx *vecX, *vecY1, *vecY2 ; double Alpha, Beta, Cee, Eta, Rho, Rho_new ; double Sigma, Tau, Theta; double Init_norm, ratio, Res_norm; double error_trol, m, Rtmp; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0}, zero[2] ={0.0, 0.0} ; double Tiny = 0.1e-28; int Iter, Imv, neqns; int stats[6] ; neqns = n_matrixSize; /* -------------------- init the vectors in TFQMRL -------------------- */ vecD = DenseMtx_new() ; DenseMtx_init(vecD, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecT = DenseMtx_new() ; DenseMtx_init(vecT, type, 0, 0, neqns, 1, 1, neqns) ; vecU1 = DenseMtx_new() ; DenseMtx_init(vecU1, type, 0, 0, neqns, 1, 1, neqns) ; vecU2 = DenseMtx_new() ; DenseMtx_init(vecU2, type, 0, 0, neqns, 1, 1, neqns) ; vecV = DenseMtx_new() ; DenseMtx_init(vecV, type, 0, 0, neqns, 1, 1, neqns) ; vecW = DenseMtx_new() ; DenseMtx_init(vecW, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecY1 = DenseMtx_new() ; DenseMtx_init(vecY1, type, 0, 0, neqns, 1, 1, neqns) ; vecY2 = DenseMtx_new() ; DenseMtx_init(vecY2, type, 0, 0, neqns, 1, 1, neqns) ; /* -------------------------- Initialize the iterations -------------------------- */ /* ---- Set initial guess as zero ---- */ DenseMtx_zero(vecX) ; DenseMtx_colCopy(vecT, 0, mtxB, 0); /* */ FrontMtx_solve(Precond, vecR, vecT, Precond->manager, cpus, msglvl, msgFile) ; /* */ Init_norm = DenseMtx_twoNormOfColumn(vecR,0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; error_trol = Init_norm * convergetol ; fprintf(msgFile, "\n TFQMRL Initial norml: %6.2e ", Init_norm ) ; fprintf(msgFile, "\n TFQMRL Conveg. Control: %7.3e ", convergetol ) ; fprintf(msgFile, "\n TFQMRL Convergen Control: %7.3e ",error_trol ) ; DenseMtx_zero(vecD) ; DenseMtx_zero(vecU1) ; DenseMtx_zero(vecU2) ; DenseMtx_zero(vecY2) ; /* DenseMtx_copy(vecR, mtxB); */ DenseMtx_colCopy(vecW, 0, vecR, 0); DenseMtx_colCopy(vecY1, 0, vecR, 0); Iter = 0; Imv = 0; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecY1) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n TFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecY1) ; break ; default : fprintf(msgFile, "\n TFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } /* */ FrontMtx_solve(Precond, vecV, vecT, Precond->manager, cpus, msglvl, msgFile) ; /* */ Imv++; DenseMtx_colCopy(vecU1, 0, vecV, 0); /* */ Theta = 0.0; Eta = 0.0; Tau = Init_norm ; Rho = Tau * Tau ; /* ------------------------------ TFQMRL Iteration start ------------------------------ */ MARKTIME(t1) ; while ( Iter <= itermax ) { Iter++; DenseMtx_colDotProduct(vecV, 0, vecR, 0, &Sigma); if (Sigma == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " TFQMRL Breakdown, Sigma = 0 !!") ; Imv = -1; goto end; }; Alpha = Rho/Sigma; /* ---------------- Odd step --------------- */ m = 2 * Iter - 1; Rtmp=-Alpha; DenseMtx_colGenAxpy(one, vecW, 0, &Rtmp, vecU1, 0); Rtmp = Theta * Theta * Eta / Alpha ; DenseMtx_colGenAxpy(&Rtmp, vecD, 0, one, vecY1, 0); Theta = DenseMtx_twoNormOfColumn(vecW,0)/Tau; Cee = 1.0/sqrt(1.0 + Theta*Theta); Tau = Tau * Theta * Cee ; Eta = Cee * Cee * Alpha ; DenseMtx_colGenAxpy(one, vecX, 0, &Eta, vecD, 0); fprintf(msgFile, "\n\n Odd step at %d", Imv); fprintf(msgFile, " \n Tau is : %7.3e", Tau) ; /* Debug purpose: Check the convergence history for the true residual norm */ /* DenseMtx_zero(vecT) ; InpMtx_nonsym_mmm(mtxA, vecT, one, vecX) ; DenseMtx_sub(vecT, mtxB) ; Rtmp = DenseMtx_twoNormOfColumn(vecT,0); fprintf(msgFile, "\n TFQMRL Residual norm: %6.2e ", Rtmp) ; */ /* ---------------- Convergence Test --------------- */ if (Tau * sqrt(m + 1) <= error_trol ) { /* */ DenseMtx_colCopy(mtxX, 0, vecX, 0); /* DenseMtx_zero(vecT) ; InpMtx_nonsym_mmm(mtxA, vecT, one, mtxX) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n TFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n TFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp = DenseMtx_twoNormOfColumn(vecT,0); fprintf(msgFile, "\n TFQMRL Residual norm: %6.2e ", Rtmp) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after TFQMRL") ; goto end; }; /* ---------------- Even step --------------- */ DenseMtx_colCopy(vecY2, 0, vecY1, 0); Rtmp=-Alpha; DenseMtx_colGenAxpy(one, vecY2, 0, &Rtmp, vecV, 0); /* DenseMtx_zero(vecT) ; InpMtx_nonsym_mmm(mtxA, vecT, one, vecY2) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecY2) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n TFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecY2) ; break ; default : fprintf(msgFile, "\n TFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } FrontMtx_solve(Precond, vecU2, vecT, Precond->manager, cpus, msglvl, msgFile) ; Imv++; m = 2 * Iter ; Rtmp = -Alpha; DenseMtx_colGenAxpy(one, vecW, 0, &Rtmp, vecU2, 0); Rtmp = Theta * Theta * Eta / Alpha ; DenseMtx_colGenAxpy(&Rtmp, vecD, 0, one, vecY2, 0); Theta = DenseMtx_twoNormOfColumn(vecW,0)/Tau; Cee = 1.0/sqrt(1.0 + Theta*Theta); Tau = Tau * Theta * Cee ; Eta = Cee * Cee * Alpha ; DenseMtx_colGenAxpy(one, vecX, 0, &Eta, vecD, 0); fprintf(msgFile, "\n\n Even step at %d", Imv) ; /* ---------------- Convergence Test for even step --------------- */ if (Tau * sqrt(m + 1) <= error_trol ) { DenseMtx_colCopy(mtxX, 0, vecX, 0); /* DenseMtx_zero(vecT) ; InpMtx_nonsym_mmm(mtxA, vecT, one, mtxX) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n TFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n TFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp = DenseMtx_twoNormOfColumn(vecT,0); fprintf(msgFile, "\n TFQMRL Residual norm: %6.2e ", Rtmp) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after TFQMRL") ; goto end; }; if (Rho == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " TFQMRL Breakdown, Rho = 0 !!") ; Imv = -1; goto end; }; DenseMtx_colDotProduct(vecW, 0, vecR, 0, &Rho_new); Beta = Rho_new / Rho; Rho = Rho_new ; DenseMtx_colCopy(vecY1, 0, vecY2, 0); DenseMtx_colGenAxpy(&Beta, vecY1, 0, one, vecW, 0); /* DenseMtx_zero(vecT) ; InpMtx_nonsym_mmm(mtxA, vecT, one, vecY1) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecY1) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n TFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecY1) ; break ; default : fprintf(msgFile, "\n TFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } FrontMtx_solve(Precond, vecU1, vecT, Precond->manager, cpus, msglvl, msgFile) ; Imv++; /* */ DenseMtx_colCopy(vecT, 0, vecU2, 0); DenseMtx_colGenAxpy(one, vecT, 0, &Beta, vecV, 0); DenseMtx_colCopy(vecV, 0, vecT, 0); DenseMtx_colGenAxpy(&Beta, vecV, 0, one, vecU1, 0); Rtmp = Tau*sqrt(m + 1)/Init_norm ; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e", Imv, Rtmp) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n TFQMRL did not Converge !") ; fprintf(msgFile, "\n\n after TFQMRL") ; DenseMtx_colCopy(mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: DenseMtx_free(vecD) ; DenseMtx_free(vecR) ; DenseMtx_free(vecT) ; DenseMtx_free(vecU1) ; DenseMtx_free(vecU2) ; DenseMtx_free(vecV) ; DenseMtx_free(vecW) ; DenseMtx_free(vecX) ; DenseMtx_free(vecY1) ; DenseMtx_free(vecY2) ; fprintf(msgFile, "\n") ; return(Imv) ; } Iter/src/tfqmrr.c010064400020550007177000000305210664345020100152430ustar00clevecompmath00000400000006/* TMQMRR.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a unsymmetric real matrix equation Ax=b using right preconditioned TMQMRR method without lookahead x -- Initial guess as zeros A -- Input matrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- Oct. 28, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int tfqmrr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *vecD, *vecR, *vecT, *vecU1, *vecU2, *vecV, *vecW; DenseMtx *vecX, *vecY1, *vecY2 ; double Alpha, Beta, Cee, Eta, Rho, Rho_new ; double Sigma, Tau, Theta; double Init_norm, ratio, Res_norm; double error_trol, m, Rtmp; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0}, zero[2]={0.0, 0.0} ; double Tiny = 0.1e-28; int Iter, Imv, neqns; int stats[6] ; neqns = n_matrixSize; /* -------------------- init the vectors in TMQMRR -------------------- */ vecD = DenseMtx_new() ; DenseMtx_init(vecD, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecT = DenseMtx_new() ; DenseMtx_init(vecT, type, 0, 0, neqns, 1, 1, neqns) ; vecU1 = DenseMtx_new() ; DenseMtx_init(vecU1, type, 0, 0, neqns, 1, 1, neqns) ; vecU2 = DenseMtx_new() ; DenseMtx_init(vecU2, type, 0, 0, neqns, 1, 1, neqns) ; vecV = DenseMtx_new() ; DenseMtx_init(vecV, type, 0, 0, neqns, 1, 1, neqns) ; vecW = DenseMtx_new() ; DenseMtx_init(vecW, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecY1 = DenseMtx_new() ; DenseMtx_init(vecY1, type, 0, 0, neqns, 1, 1, neqns) ; vecY2 = DenseMtx_new() ; DenseMtx_init(vecY2, type, 0, 0, neqns, 1, 1, neqns) ; /* -------------------------- Initialize the iterations -------------------------- */ /* ---- Set initial guess as zero ---- */ DenseMtx_zero(vecX) ; Init_norm = DenseMtx_twoNormOfColumn(mtxB,0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; error_trol = Init_norm * convergetol ; fprintf(msgFile, "\n TMQMRR Initial norml: %6.2e ", Init_norm ) ; fprintf(msgFile, "\n TMQMRR Conveg. Control: %6.2e ", convergetol ) ; fprintf(msgFile, "\n TMQMRR Convergen Control: %6.2e ",error_trol ) ; DenseMtx_zero(vecD) ; DenseMtx_zero(vecU1) ; DenseMtx_zero(vecU2) ; DenseMtx_zero(vecY2) ; Iter = 0; Imv = 0; DenseMtx_colCopy(vecR, 0, mtxB, 0); DenseMtx_colCopy(vecW, 0, vecR, 0); DenseMtx_colCopy(vecY1, 0, vecR, 0); /* */ FrontMtx_solve(Precond, vecT, vecY1, Precond->manager, cpus, msglvl, msgFile) ; /* */ /* DenseMtx_zero(vecV) ; InpMtx_nonsym_mmm(mtxA, vecV, one, vecT) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecV, one, vecT) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecV, one, vecT) ; break ; default : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; DenseMtx_colCopy(vecU1, 0, vecV, 0); /* */ Theta = 0.0; Eta = 0.0; Tau = Init_norm ; Rho = Tau * Tau ; /* ------------------------------ TFQMRR Iteration start ------------------------------ */ MARKTIME(t1) ; while ( Iter <= itermax ) { Iter++; DenseMtx_colDotProduct(vecV, 0, vecR, 0, &Sigma); if (Sigma == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " TFQMRR Breakdown, Sigma = 0 !!") ; Imv = -1; goto end; }; Alpha = Rho/Sigma; /* ---------------- Odd step --------------- */ m = 2 * Iter - 1; Rtmp=-Alpha; DenseMtx_colGenAxpy(one, vecW, 0, &Rtmp, vecU1, 0); Rtmp = Theta * Theta * Eta / Alpha ; DenseMtx_colGenAxpy(&Rtmp, vecD, 0, one, vecY1, 0); Theta = DenseMtx_twoNormOfColumn(vecW,0)/Tau; Cee = 1.0/sqrt(1.0 + Theta*Theta); Tau = Tau * Theta * Cee ; Eta = Cee * Cee * Alpha ; DenseMtx_colGenAxpy(one, vecX, 0, &Eta, vecD, 0); fprintf(msgFile, "\n\n Odd step at %d", Imv); fprintf(msgFile, " \n Tau is : %6.2e", Tau) ; /* ------------------ For debug purpose: Check the true residual ------------------ */ /* --------------- DenseMtx_colCopy(vecT, 0, vecX, 0); FrontMtx_solve(Precond, mtxX, vecT, Precond->manager, cpus, msglvl, msgFile) ; DenseMtx_zero(vecT) ; InpMtx_nonsym_mmm(mtxA, vecT, one, mtxX) ; Imv++; DenseMtx_sub(vecT, mtxB) ; Rtmp = DenseMtx_twoNormOfColumn(vecT,0); fprintf(msgFile, "\n TFQMR Residual norm: %6.2e ", Rtmp) ; --------------- */ /* ---------------- Convergence Test --------------- */ if (Tau * sqrt(m + 1) <= error_trol ) { /* */ FrontMtx_solve(Precond, mtxX, vecX, Precond->manager, cpus, msglvl, msgFile) ; /* */ /* DenseMtx_zero(vecT) ; InpMtx_nonsym_mmm(mtxA, vecT, one, mtxX) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; DenseMtx_sub(vecT, mtxB) ; Rtmp = DenseMtx_twoNormOfColumn(vecT,0); fprintf(msgFile, "\n TFQMRR Residual norm: %6.2e ", Rtmp) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after TFQMRR") ; goto end; }; /* ---------------- Even step --------------- */ DenseMtx_colCopy(vecY2, 0, vecY1 , 0); Rtmp=-Alpha; DenseMtx_colGenAxpy(one, vecY2, 0, &Rtmp, vecV, 0); FrontMtx_solve(Precond, vecT, vecY2, Precond->manager, cpus, msglvl, msgFile) ; /* DenseMtx_zero(vecU2) ; InpMtx_nonsym_mmm(mtxA, vecU2, one, vecT) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecU2, one, vecT) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecU2, one, vecT) ; break ; default : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } m = 2 * Iter ; Rtmp=-Alpha; DenseMtx_colGenAxpy(one, vecW, 0, &Rtmp, vecU2, 0); Rtmp = Theta * Theta * Eta / Alpha ; DenseMtx_colGenAxpy(&Rtmp, vecD, 0, one, vecY2, 0); Theta = DenseMtx_twoNormOfColumn(vecW,0)/Tau; Cee = 1.0/sqrt(1.0 + Theta*Theta); Tau = Tau * Theta * Cee ; Eta = Cee * Cee * Alpha ; DenseMtx_colGenAxpy(one, vecX, 0, &Eta, vecD, 0); fprintf(msgFile, "\n\n Even step at %d", Imv) ; /* ---------------- Convergence Test for even step --------------- */ if (Tau * sqrt(m + 1) <= error_trol ) { /* */ FrontMtx_solve(Precond, mtxX, vecX, Precond->manager, cpus, msglvl, msgFile) ; /* */ /* DenseMtx_zero(vecT) ; InpMtx_nonsym_mmm(mtxA, vecT, one, mtxX) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; DenseMtx_sub(vecT, mtxB) ; Rtmp = DenseMtx_twoNormOfColumn(vecT,0); fprintf(msgFile, "\n TFQMRR Residual norm: %6.2e ", Rtmp) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after TFQMRR") ; goto end; }; if (Rho == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " TFQMRR Breakdown, Rho = 0 !!") ; Imv = -1; goto end; }; DenseMtx_colDotProduct(vecW, 0, vecR, 0, &Rho_new); Beta = Rho_new / Rho; Rho = Rho_new ; DenseMtx_colCopy(vecY1, 0, vecY2, 0); DenseMtx_colGenAxpy(&Beta, vecY1, 0, one, vecW, 0); /* */ FrontMtx_solve(Precond, vecT, vecY1, Precond->manager, cpus, msglvl, msgFile) ; /* DenseMtx_zero(vecU1) ; InpMtx_nonsym_mmm(mtxA, vecU1, one, vecT) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecU1, one, vecT) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecU1, one, vecT) ; break ; default : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; /* */ DenseMtx_colCopy(vecT, 0, vecU2, 0); DenseMtx_colGenAxpy(one, vecT, 0, &Beta, vecV, 0); DenseMtx_colCopy(vecV, 0, vecT, 0); DenseMtx_colGenAxpy(&Beta, vecV, 0, one, vecU1, 0); Rtmp = Tau*sqrt(m + 1)/Init_norm ; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e", Imv, Rtmp) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n TFQMRR did not Converge !") ; /* DenseMtx_zero(vecT) ; InpMtx_nonsym_mmm(mtxA, vecT, one, vecX) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; case SPOOLES_HERMITIAN : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; default : fprintf(msgFile, "\n TFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; DenseMtx_sub(vecT, mtxB) ; Rtmp = DenseMtx_twoNormOfColumn(vecT,0); fprintf(msgFile, "\n TFQMRR Residual norm: %6.2e ", Rtmp) ; fprintf(msgFile, "\n\n after TFQMRR") ; DenseMtx_colCopy(mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: DenseMtx_free(vecD) ; DenseMtx_free(vecR) ; DenseMtx_free(vecT) ; DenseMtx_free(vecU1) ; DenseMtx_free(vecU2) ; DenseMtx_free(vecV) ; DenseMtx_free(vecW) ; DenseMtx_free(vecX) ; DenseMtx_free(vecY1) ; DenseMtx_free(vecY2) ; fprintf(msgFile, "\n") ; return(1) ; } Mtx_init(vecV, type, 0, 0, neqns, 1, 1, neqns) ; vecW = DenseMtx_new() ; DenseMtx_init(vecW, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, tyIter/src/util.c010064400020550007177000000361070665022243100147130ustar00clevecompmath00000400000006#include "../Iter.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------- return the frobenius norm of a Dense matrix created -- 98nov11, dkw ------------------------------------------- */ double DenseMtx_frobNorm ( DenseMtx *mtx ) { double fnorm; A2 a2; A2_setDefaultFields(&a2) ; DenseMtx_setA2(mtx, &a2); fnorm = A2_frobNorm(&a2) ; return (fnorm); } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ return the two-norm of column jcol from a Dense matrix created -- 98nov11, dkw ------------------------------------------------------ */ double DenseMtx_twoNormOfColumn ( DenseMtx *mtx, int jcol ) { double norm; A2 a2; A2_setDefaultFields(&a2) ; DenseMtx_setA2(mtx, &a2); norm = A2_twoNormOfColumn(&a2, jcol) ; return (norm); } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ copy column icol of a Dense matrix A to column jcol of a Dense matrix B. Ai->Bj. created -- 98nov12, jwu ------------------------------------------------------ */ void DenseMtx_colCopy ( DenseMtx *mtxB, int jcol, DenseMtx *mtxA, int icol ) { int nrowA, ncolA, rowincA; int nrowB, ncolB, rowincB; double *Ai, *Bj; int ierr, k; if (mtxA == NULL || mtxB == NULL) { fprintf(stderr,"mtxA and/or mtxB are NULL\n"); return; } if (DENSEMTX_IS_REAL(mtxA) != DENSEMTX_IS_REAL(mtxB)) { fprintf(stderr,"mtxA and mtxB do not have the same data type\n"); return; } DenseMtx_dimensions(mtxA, &nrowA, &ncolA); DenseMtx_dimensions(mtxB, &nrowB, &ncolB); if (nrowA != nrowB) { fprintf(stderr,"Error in DenseMtx_colCopy: nrowA != nrowB\n"); return; } if (icol > ncolA-1 || icol < 0 ) { fprintf(stderr,"Error in DenseMtx_colCopy: icol is not in [0,ncolA-1]\n"); return; } else if (jcol > ncolB-1 || jcol < 0 ) { fprintf(stderr,"Error in DenseMtx_colCopy: jcol is not in [0,ncolB-1]\n"); return; } ierr=DenseMtx_column(mtxA, icol, &Ai); ierr=DenseMtx_column(mtxB, jcol, &Bj); if (ierr != 1) { fprintf(stderr,"Error in DenseMtx_colCopy: ierr!=1 after DenseMtx_column\n"); return; } rowincA=DenseMtx_rowIncrement(mtxA); rowincB=DenseMtx_rowIncrement(mtxB); /* copying... */ if (DENSEMTX_IS_COMPLEX(mtxA)) { rowincA *= 2; rowincB *= 2; } for (k=0; k ncolA-1 || icol < 0 ) { fprintf(stderr,"Error in DenseMtx_colDotProduct: " "icol is not in [0,ncolA-1]\n"); return; } else if (jcol > ncolB-1 || jcol < 0 ) { fprintf(stderr,"Error in DenseMtx_colDotProduct: " "jcol is not in [0,ncolB-1]\n"); return; } ierr=DenseMtx_column(mtxA, icol, &Ai); ierr=DenseMtx_column(mtxB, jcol, &Bj); if (ierr != 1) { fprintf(stderr,"Error in DenseMtx_colDotProduct: " "ierr!=1 after DenseMtx_column\n"); return; } rowincA=DenseMtx_rowIncrement(mtxA); rowincB=DenseMtx_rowIncrement(mtxB); /* inner product */ if (DENSEMTX_IS_COMPLEX(mtxA)) { rowincA *= 2; rowincB *= 2; } for (k=0; k ncolA-1 || icol < 0 ) { fprintf(stderr,"Error in DenseMtx_colGenAxpy: " "icol is not in [0,ncolA-1]\n"); return; } else if (jcol > ncolB-1 || jcol < 0 ) { fprintf(stderr,"Error in DenseMtx_colGenAxpy: " "jcol is not in [0,ncolB-1]\n"); return; } ierr=DenseMtx_column(mtxA, icol, &Ai); ierr=DenseMtx_column(mtxB, jcol, &Bj); if (ierr != 1) { fprintf(stderr,"Error in DenseMtx_colGenAxpy: " "error after DenseMtx_column\n"); return; } rowincA=DenseMtx_rowIncrement(mtxA); rowincB=DenseMtx_rowIncrement(mtxB); areal=*alpha; breal=*beta; /* general saxp */ if (DENSEMTX_IS_REAL(mtxA)) { if (areal == 0.0) for (k=0; k= mtxB->nrow || mtxA == NULL || icolA < 0 || icolA >= mtxA->nrow || (nrow = mtxA->nrow) != mtxB->nrow ) { fprintf(stderr, "\n fatal error in DenseMtx_copyRow(%p,%d,%p,%d)" "\n bad input\n", mtxB, icolB, mtxA, icolA) ; exit(-1) ; } inc1A = mtxA->inc1 ; inc1B = mtxB->inc1 ; /* mtxB->colind[icolB] = mtxA->colind[icolA] ; */ if ( DENSEMTX_IS_REAL(mtxB) && DENSEMTX_IS_REAL(mtxA) ) { colA = mtxA->entries + icolA*mtxA->inc2 ; colB = mtxB->entries + icolB*mtxB->inc2 ; for ( ii = iA = iB = 0 ; ii < nrow ; ii++, iA += inc1A, iB += inc1B){ colB[iB] = colA[iA] ; } } else if ( DENSEMTX_IS_COMPLEX(mtxB) && DENSEMTX_IS_COMPLEX(mtxA) ) { colA = mtxA->entries + 2*icolA*mtxA->inc2 ; colB = mtxB->entries + 2*icolB*mtxB->inc2 ; for ( ii = iA = iB = 0 ; ii < nrow ; ii++, iA += inc1A, iB += inc1B){ colB[2*iB] = colA[2*iA] ; colB[2*iB+1] = colA[2*iA+1] ; } } else { fprintf(stderr, "\n fatal error in DenseMtx_copyColumn(%p,%d,%p,%d)" "\n mixing real and complex datatype\n", mtxB, icolB, mtxA, icolA); exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- FrontMtx_solve with column icol of a DenseMtx rhsmtx as right-hand-side. created -- 98nov24, jwu ----------------------------------------------- */ void FrontMtx_solveOneColumn ( FrontMtx *frontmtx, DenseMtx *solmtx, int jcol, DenseMtx *rhsmtx, int icol, SubMtxManager *mtxmanager, double cpus[], int msglvl, FILE *msgFile ) { DenseMtx rhsV, solV; int nrowr, nrows, ncol, ierr; DenseMtx_dimensions (rhsmtx, &nrowr, &ncol); DenseMtx_dimensions (solmtx, &nrows, &ncol); /*rhsV = DenseMtx_new() ;*/ DenseMtx_setDefaultFields(&rhsV); ierr=DenseMtx_initAsSubmatrix (&rhsV, rhsmtx, 0, nrowr-1, icol, icol); if (ierr < 0) { fprintf(stderr, "\n fatal error in FrontMtx_solveOneColumn: "); fprintf(stderr, "cannot assign rhsmtx(:,icol) as a sub-DenseMtx"); exit(-1) ; } /*solV = DenseMtx_new() ;*/ DenseMtx_setDefaultFields(&solV); ierr=DenseMtx_initAsSubmatrix (&solV, solmtx, 0, nrows-1, jcol, jcol); if (ierr < 0) { fprintf(stderr, "\n fatal error in FrontMtx_solveOneColumn: "); fprintf(stderr, "cannot assign solmtx(:,jcol) as a sub-DenseMtx"); exit(-1) ; } FrontMtx_solve (frontmtx,&solV,&rhsV,mtxmanager,cpus,msglvl,msgFile); return; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the absolute value of a complex number created -- 98dec07, ycp ---------------------------------------------- */ double zabs(double *x) { double v; if( fabs(x[0]) > fabs(x[1]) ) { v = fabs(x[1])/fabs(x[0]); return ( fabs(x[0])*sqrt(1. + v*v) ); } else { if(x[1] == 0.) return( fabs(x[0]) ); else { v = fabs(x[0])/fabs(x[1]); return ( fabs(x[1])*sqrt(1. + v*v) ); } } } /*--------------------------------------------------------------------*/ /* ------------------------------------------- compute the sum of two complex numbers created -- 98dec07, ycp ------------------------------------------- */ void zadd (double *x, double *y, double *u ) { u[0] = x[0] + y[0]; u[1] = x[1] + y[1]; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- divide two complex numbers created -- 98dec07, ycp ------------------------------------------- */ void zdiv (double *x, double *y, double *u ) { int flip; double hold, s, t; double x_re, x_im, y_re, y_im; x_re = x[0]; x_im = x[1]; y_re = y[0]; y_im = y[1]; if ( y_im == 0. ){ u[0] = x_re/y_re; u[1] = x_im/y_re; return; } if ( y_re == 0. ){ u[0] = x_im/y_im; u[1] = -x_re/y_im; return; } flip = 0; if ( fabs(y_re) >= fabs(y_im) ) { hold = y_re; y_re = y_im; y_im = hold; hold = x_re; x_re = x_im; x_im = hold; flip = 1; } s = 1.0/y_re; t = 1.0/(y_re+ y_im*(y_im*s) ); if ( fabs(y_im) >= fabs(s) ) { hold = y_im; y_im = s; s = hold; } if ( fabs(x_im) >= fabs(s) ) u[0] = t*(x_re+ s*(x_im*y_im) ); else { if ( fabs (x_im) >= fabs(y_im) ) u[0] = t*( x_re + x_im*(s*y_im) ); else u[0] = t*( x_re + y_im*(s*x_im) ); } if ( fabs(x_re) >= fabs(s) ) u[1] = t*( x_im - s*(x_re*y_im) ); else { if ( fabs (x_re) >= fabs(y_im) ) u[1] = t*(x_im- x_re*(s*y_im) ); else u[1] = t*(x_im- y_im*(s*x_re) ); } if ( flip ) u[1] = -u[1] ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- multiply two complex numbers created -- 98dec07, ycp ------------------------------------------- */ void zmul(double *x, double *y, double *u) { double Re, Im; Re = x[0]*y[0] - x[1]*y[1] ; Im = x[0]*y[1] + x[1]*y[0] ; u[0] = Re; u[1] = Im; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- compute the difference of two complex numbers created -- 98dec07, ycp --------------------------------------------- */ void zsub (double *x, double *y, double *u ) { u[0] = x[0] - y[0]; u[1] = x[1] - y[1]; return ; } in DenseMtx_colGenAxpy: " "error after DenseMtx_column\n"); return; } rowincA=DenseMtx_rowIncrement(mtxA); rowincB=DenseMtx_rowIncrement(mtxB); areal=*alpha; breal=*beta; /* general saxp */ if (DENSEMTX_IS_REAL(mtxA)) { if (areal == 0.0) for (k=0; kmanager, cpus, msglvl, msgFile) ; /* */ Init_norm = DenseMtx_twoNormOfColumn(vecR, 0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; ratio = 1.0; DenseMtx_colCopy (vecR0, 0, vecR, 0); fprintf(msgFile, "\n ZBiCGSTABL Initial norm: %6.2e ", Init_norm ) ; fprintf(msgFile, "\n ZBiCGSTABL Conveg. Control: %6.2e ", convergetol ) ; /* */ Rho[0] = 1.0; Alpha[0] = 1.0; Omega[0] = 1.0; Rho[1] = 0.0; Alpha[1] = 0.0; Omega[1] = 0.0; DenseMtx_zero(vecV) ; DenseMtx_zero(vecP) ; /* ------------------------------ ------------------------------ */ MARKTIME(t1) ; Iter = 0; Imv = 0; /* ----------------- factor the matrix ----------------- */ while ( ratio > convergetol && Iter <= itermax ) { Iter++; DenseMtx_colDotProduct (vecR0, 0, vecR,0, Rho_new); if ( zabs(Rho_new) == 0.0 || zabs(Omega)== 0.0 ){ fprintf(stderr, "\n breakdown in ZBiCGSTABL !! " "\n Fatal error \n"); exit(-1) ; } /* Beta = (Rho_new / (Rho+Tiny)) * (Alpha / (Omega+Tiny)); */ zdiv(Rho_new, Rho, Beta); zmul(Beta, Alpha, Rtmp); zdiv(Rtmp, Omega, Beta); Rho[0] = Rho_new[0]; Rho[1] = Rho_new[1]; /* DenseMtx_axpy(vecP, vecV, -Omega); DenseMtx_aypx(vecP, vecR, Beta); */ zsub(zero, Omega, Rtmp); DenseMtx_colGenAxpy (one, vecP, 0, Rtmp, vecV, 0 ); DenseMtx_colGenAxpy (Beta, vecP, 0, one, vecR, 0 ); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecY, one, vecP) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecY, one, vecP) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecY, one, vecP) ; break ; default : fprintf(msgFile, "\n BiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } /* */ FrontMtx_solve(Precond, vecV, vecY, Precond->manager, cpus, msglvl, msgFile) ; Imv++; /* */ /* Alpha = Rho / (DenseMtx_dot(vecR0, vecV)+Tiny); */ DenseMtx_colDotProduct (vecR0, 0, vecV,0, Rtmp); if ( zabs(Rtmp) == 0.0 ){ fprintf(stderr, "\n breakdown in ZBiCGSTABL !! " "\n Fatal error \n"); exit(-1) ; } zdiv(Rho, Rtmp, Alpha); /* */ /* DenseMtx_axpy(vecR, vecV, -Alpha); */ zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, vecR, 0, Rtmp, vecV, 0 ); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecZ, one, vecR) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecZ, one, vecR) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecZ, one, vecR) ; break ; default : fprintf(msgFile, "\n BiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } /* */ FrontMtx_solve(Precond, vecT, vecZ, Precond->manager, cpus, msglvl, msgFile) ; Imv++; /* */ /* Omega = DenseMtx_dot(vecT, vecR)/(DenseMtx_dot(vecT, vecT)+Tiny); */ DenseMtx_colDotProduct (vecT, 0, vecT,0, Ttmp); if ( zabs(Ttmp) == 0.0 ){ fprintf(stderr, "\n breakdown in ZBiCGSTABL !! " "\n Fatal error \n"); exit(-1) ; }; DenseMtx_colDotProduct (vecT, 0, vecR, 0, Rtmp); zdiv(Rtmp, Ttmp, Omega); DenseMtx_colGenAxpy (one, vecX, 0, Alpha, vecP, 0); DenseMtx_colGenAxpy (one, vecX, 0, Omega, vecR, 0); /* */ /* DenseMtx_axpy(vecR, vecT, -Omega); */ zsub(zero, Omega, Rtmp); DenseMtx_colGenAxpy (one, vecR, 0, Rtmp, vecT, 0); Res_norm = DenseMtx_twoNormOfColumn (vecR, 0); ratio = Res_norm/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e" "\n Residual norm is %6.2e", Imv, ratio, Res_norm) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after ZBICGSTABL") ; /* DenseMtx_copy(mtxX, vecX); */ DenseMtx_colCopy (mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: DenseMtx_free(vecP) ; DenseMtx_free(vecR) ; DenseMtx_free(vecR0) ; DenseMtx_free(vecT) ; DenseMtx_free(vecV) ; DenseMtx_free(vecW) ; DenseMtx_free(vecX) ; DenseMtx_free(vecY) ; DenseMtx_free(vecZ) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/src/zbicgstabr.c010064400020550007177000000167370664345020100160770ustar00clevecompmath00000400000006/* zbicgstabr.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a complex matrix equation Ax=b using right preconditioned BiCGSTABR x -- Initial guess A -- Input matrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- Dec. 10, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int zbicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxZ ; DenseMtx *vecP, *vecR, *vecR0, *vecT, *vecV, *vecW; DenseMtx *vecX, *vecY, *vecZ ; double Alpha[2], Beta[2], Init_norm, Omega[2], Rtmp[2]; double ratio, Res_norm, Rho[2], Rho_new[2], Ttmp[2]; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0}, zero[2] = {0.0, 0.0} ; double Tiny = 0.1e-28; int Iter, Imv, neqns; int stats[6] ; neqns = n_matrixSize; /* -------------------- init the vectors in bicgstab -------------------- */ vecP = DenseMtx_new() ; DenseMtx_init(vecP, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecR0 = DenseMtx_new() ; DenseMtx_init(vecR0, type, 0, 0, neqns, 1, 1, neqns) ; vecT = DenseMtx_new() ; DenseMtx_init(vecT, type, 0, 0, neqns, 1, 1, neqns) ; vecV = DenseMtx_new() ; DenseMtx_init(vecV, type, 0, 0, neqns, 1, 1, neqns) ; vecW = DenseMtx_new() ; DenseMtx_init(vecW, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecY = DenseMtx_new() ; DenseMtx_init(vecY, type, 0, 0, neqns, 1, 1, neqns) ; vecZ = DenseMtx_new() ; DenseMtx_init(vecZ, type, 0, 0, neqns, 1, 1, neqns) ; /* -------------------------- Initialize the iterations -------------------------- */ Init_norm = DenseMtx_twoNormOfColumn(mtxB, 0); ratio = 1.0; DenseMtx_zero(vecX) ; DenseMtx_colCopy (vecR0, 0, mtxB, 0); DenseMtx_colCopy (vecR, 0, vecR0, 0); Iter = 0; Imv = 0; fprintf(msgFile, "\n ZBiCGSTABR Initial norml: %6.2ef ", Init_norm ) ; fprintf(msgFile, "\n ZBiCGSTABR Conveg. Control: %12.8f ", convergetol ) ; /* */ Rho[0] = 1.0; Alpha[0] = 1.0; Omega[0] = 1.0; Rho[1] = 0.0; Alpha[1] = 0.0; Omega[1] = 0.0; DenseMtx_zero(vecV) ; DenseMtx_zero(vecP) ; /* ------------------------------ ------------------------------ */ MARKTIME(t1) ; /* ----------------- factor the matrix ----------------- */ while ( ratio > convergetol && Iter <= itermax ) { Iter++; /* Rho_new = DenseMtx_dot(vecR0, vecR); */ DenseMtx_colDotProduct (vecR0, 0, vecR,0, Rho_new); if ( zabs(Rho_new) == 0.0 || zabs(Omega)== 0.0 ){ fprintf(stderr, "\n breakdown in ZBiCGSTABR !! " "\n Fatal error \n"); exit(-1) ; } /* Beta = (Rho_new / (Rho+Tiny)) * (Alpha / (Omega+Tiny)); */ zdiv(Rho_new, Rho, Beta); zmul(Beta, Alpha, Rtmp); zdiv(Rtmp, Omega, Beta); Rho[0] = Rho_new[0]; Rho[1] = Rho_new[1]; /* DenseMtx_axpy(vecP, vecV, -Omega); */ /* DenseMtx_aypx(vecP, vecR, Beta); */ zsub(zero, Omega, Rtmp); DenseMtx_colGenAxpy (one, vecP, 0, Rtmp, vecV, 0 ); DenseMtx_colGenAxpy (Beta, vecP, 0, one, vecR, 0 ); /* */ FrontMtx_solve(Precond, vecY, vecP, Precond->manager, cpus, msglvl, msgFile) ; /* */ /* InpMtx_nonsym_gmmm(mtxA, zero, vecV, one, vecY) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecV, one, vecY) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecV, one, vecY) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecV, one, vecY) ; break ; default : fprintf(msgFile, "\n BiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; /* Alpha = Rho / (DenseMtx_dot(vecR0, vecV)+Tiny); */ DenseMtx_colDotProduct (vecR0, 0, vecV,0, Rtmp); if ( zabs(Rtmp) == 0.0 ){ fprintf(stderr, "\n breakdown in ZBiCGSTABR !! " "\n Fatal error \n"); exit(-1) ; } zdiv(Rho, Rtmp, Alpha); /* */ /* DenseMtx_axpy(vecR, vecV, -Alpha); */ zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, vecR, 0, Rtmp, vecV, 0 ); /* */ FrontMtx_solve(Precond, vecZ, vecR, Precond->manager, cpus, msglvl, msgFile) ; /* InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecZ) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecZ) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecZ) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecZ) ; break ; default : fprintf(msgFile, "\n BiCGSTABR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; /* Omega = DenseMtx_dot(vecT, vecR)/(DenseMtx_dot(vecT, vecT)+Tiny); */ DenseMtx_colDotProduct (vecT, 0, vecT,0, Ttmp); if ( zabs(Ttmp) == 0.0 ){ fprintf(stderr, "\n breakdown in ZBiCGSTABR !! " "\n Fatal error \n"); exit(-1) ; }; DenseMtx_colDotProduct (vecT, 0, vecR, 0, Rtmp); zdiv(Rtmp, Ttmp, Omega); DenseMtx_colGenAxpy (one, vecX, 0, Alpha, vecY, 0); DenseMtx_colGenAxpy (one, vecX, 0, Omega, vecZ, 0); /* DenseMtx_axpy(vecR, vecT, -Omega); */ zsub(zero, Omega, Rtmp); DenseMtx_colGenAxpy (one, vecR, 0, Rtmp, vecT, 0); Res_norm = DenseMtx_twoNormOfColumn (vecR, 0); ratio = Res_norm/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e" "\n Residual norm is %6.2e", Imv, ratio, Res_norm) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after ZBICGSTABR") ; /* DenseMtx_copy(mtxX, vecX); */ DenseMtx_colCopy (mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: DenseMtx_free(vecP) ; DenseMtx_free(vecR) ; DenseMtx_free(vecR0) ; DenseMtx_free(vecT) ; DenseMtx_free(vecV) ; DenseMtx_free(vecW) ; DenseMtx_free(vecX) ; DenseMtx_free(vecY) ; DenseMtx_free(vecZ) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ / Rho[0] = 1.0; Alpha[0] Iter/src/zmlbicgstabl.c010064400020550007177000000337740664345020100164220ustar00clevecompmath00000400000006/* ZMLBiCGSTABL.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a complex matrix equation Ax=b using left preconditioned ML(k)BiCGSTABL method by M-C Yeung and T. Chan x -- Initial guess as zeros A -- Input matrix Precond -- Front Matrix as the preconditioner Q -- Starting vectors b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- Dec. 10, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int zmlbicgstabl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxQ, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxD, *mtxG, *mtxU, *mtxW; DenseMtx *vecGt, *vecR, *vecT, *vecT1; DenseMtx *vecX, *vecZD, *vecZG, *vecZW ; double Alpha[2], Beta[2], Rho[2] ; double c[200] ; double Init_norm, ratio, Res_norm; double error_trol, m, Rtmp[2], Ttmp[2]; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0} ; double zero[2] = {0.0, 0.0} ; double minusone[2] = {-1.0, 0.0}; double Tiny = 0.1e-28; int Iter, Imv, neqns, Ik, ii, is; int stats[6] ; int return_flag; neqns = n_matrixSize; Ik = mtxQ->ncol; if (Ik > 99){ fprintf(msgFile, "\n\n Fatal Error, \n" " Too many starting vectors in Q !!") ; return(-1); }; return_flag = 1; /* -------------------- init the vectors in ZMLBiCGSTABL -------------------- */ mtxD = DenseMtx_new() ; DenseMtx_init(mtxD, type, 0, 0, neqns, Ik, 1, neqns) ; mtxG = DenseMtx_new() ; DenseMtx_init(mtxG, type, 0, 0, neqns, Ik, 1, neqns) ; mtxU = DenseMtx_new() ; DenseMtx_init(mtxU, type, 0, 0, neqns, 2, 1, neqns) ; mtxW = DenseMtx_new() ; DenseMtx_init(mtxW, type, 0, 0, neqns, Ik, 1, neqns) ; vecGt = DenseMtx_new() ; DenseMtx_init(vecGt, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecT = DenseMtx_new() ; DenseMtx_init(vecT, type, 0, 0, neqns, 1, 1, neqns) ; vecT1 = DenseMtx_new() ; DenseMtx_init(vecT1, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecZD = DenseMtx_new() ; DenseMtx_init(vecZD, type, 0, 0, neqns, 1, 1, neqns) ; vecZG = DenseMtx_new() ; DenseMtx_init(vecZG, type, 0, 0, neqns, 1, 1, neqns) ; vecZW = DenseMtx_new() ; DenseMtx_init(vecZW, type, 0, 0, neqns, 1, 1, neqns) ; for ( ii = 0; ii <200; ii++){ c[ii] = 0; } /* -------------------------- Initialize the iterations -------------------------- */ /* ---- Set initial guess as zero ---- */ DenseMtx_zero(vecX) ; /* ---- If x_0 is not zero ---- */ /* DenseMtx_colCopy(vecX, 0, mtxX, 0); */ /* InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecX) ; */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; default : fprintf(msgFile, "\n ZTFQMR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_colCopy(vecR, 0, mtxB, 0); DenseMtx_sub(vecR, vecT) ; FrontMtx_solve(Precond, vecT, vecR, Precond->manager, cpus, msglvl, msgFile) ; DenseMtx_colCopy(vecR, 0, vecT, 0); Init_norm = DenseMtx_twoNormOfColumn(vecR, 0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; error_trol = Init_norm * convergetol ; fprintf(msgFile, "\n ZMLBiCGSTABL Initial norm : %6.2e ", Init_norm ) ; fprintf(msgFile, "\n ZMLBiCGSTABL Conveg. Control: %7.3e ", convergetol ) ; fprintf(msgFile, "\n ZMLBiCGSTABL Convergen Control: %7.3e ",error_trol ) ; DenseMtx_zero(mtxG) ; DenseMtx_zero(mtxD) ; DenseMtx_zero(mtxW) ; Iter = 0; Imv = 0; DenseMtx_colCopy (mtxG, Ik-1, vecR, 0); /* ------------------------------ ZMLBiCGSTABL Iteration start ------------------------------ */ MARKTIME(t1) ; while ( Iter <= itermax ){ Iter++; /* g_tld = G(:,k); W(:,k) = U\(L\( A*g_tld)); */ DenseMtx_colCopy (vecGt, 0, mtxG, Ik-1); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; default : fprintf(msgFile, "\n ZTFQMR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } FrontMtx_solveOneColumn(Precond, mtxW, Ik-1, vecT, 0, Precond->manager, cpus, msglvl, msgFile) ; Imv++; /* c[Ik] = *DenseMtx_colDotProduct (mtxQ, 0, mtxG, Ik-1); */ DenseMtx_colDotProduct (mtxQ, 0, mtxG, Ik-1, Rtmp); c[2*Ik] = Rtmp[0]; c[2*Ik+1]= Rtmp[1]; if (zabs(Rtmp) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZMLBiCGSTABL Breakdown, c[k] = 0 !!") ; return_flag = -1; goto end; }; /* Alpha = Q(:,1)'*r/c(k); ; */ DenseMtx_colDotProduct (mtxQ,0, vecR, 0, Rtmp); /* Alpha = Rtmp/c[Ik]; */ zdiv(Rtmp, c+(2*Ik), Alpha); DenseMtx_colCopy (mtxU, 0, vecR, 0); /* Rtmp = -Alpha; */ zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, mtxU, 0, Rtmp, mtxW, Ik-1); /* u = r - alpha*W(:,k); u_tld = u; temp = U\(L\(A*u_tld)); rho =temp'*temp; */ DenseMtx_colCopy (mtxU, 1, mtxU, 0); DenseMtx_colCopy (vecT, 0, mtxU, 0); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT1, one, vecT) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT1, one, vecT) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT1, one, vecT) ; break ; default : fprintf(msgFile, "\n ZTFQMR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } FrontMtx_solveOneColumn(Precond, vecT, 0, vecT1, 0, Precond->manager, cpus, msglvl, msgFile) ; Imv++; /* Rho = temp'*temp; */ DenseMtx_colDotProduct (vecT, 0, vecT, 0, Rho); if (zabs(Rho) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZMLBiCGSTABL Breakdown, Rho = 0 !!") ; return_flag = -1; goto end; }; /* Rho = -(*DenseMtx_colDotProduct (mtxU, 0, vecT, 0))/Rho; */ DenseMtx_colDotProduct (mtxU, 0, vecT, 0, Rtmp); /* Rho = -Rtmp/Rho; */ zdiv(Rtmp, Rho, Ttmp); zsub(zero, Ttmp, Rho); DenseMtx_colGenAxpy(one, vecX, 0, Alpha, vecGt, 0); /* Rtmp = -Rho; */ zsub(zero, Rho, Rtmp); DenseMtx_colGenAxpy (one, vecX, 0, Rtmp, mtxU, 1) ; DenseMtx_colCopy (vecR, 0, mtxU, 0); DenseMtx_colGenAxpy (one, vecR, 0, Rho, vecT, 0) ; /* Iter++; */ /* ---------------- Convergence Test --------------- */ Rtmp[0] = DenseMtx_twoNormOfColumn ( vecR, 0); ratio = Rtmp[0]/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e" "\n Residual norm is %6.2ee", Imv, ratio, Rtmp[0]) ; fflush(msgFile) ; if ( Rtmp[0] <= error_trol ) { fprintf(msgFile, "\n # iterations = %d", Imv) ; return_flag = Imv; goto end; }; for (ii = 1; ii < Ik+1; ii++ ){ if (Iter > itermax ){ fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n ZMLBiCGSTABL did not Converge !") ; return_flag = Imv; goto end; }; DenseMtx_colCopy (vecZD,0, mtxU, 0); DenseMtx_colCopy (vecZG,0, vecR, 0); DenseMtx_zero(vecZW) ; if ( Iter > 1 ){ for ( is = ii ; is < Ik ; is++ ){ /* Beta =-( *(DenseMtx_colDotProduct(mtxQ, is, vecZD, 0)))/c[is]; */ DenseMtx_colDotProduct(mtxQ, is, vecZD, 0, Rtmp); /* Beta = -Rtmp/c[is]; */ zdiv(Rtmp, c+(2*is), Ttmp); zsub(zero, Ttmp, Beta); DenseMtx_colGenAxpy (one, vecZD, 0, Beta, mtxD, is-1); DenseMtx_colGenAxpy (one, vecZG, 0, Beta, mtxG, is-1); DenseMtx_colGenAxpy (one, vecZW, 0, Beta, mtxW, is-1); }; }; /* Beta = Rho * c[Ik]; */ zmul(Rho, c+(2*Ik), Beta); if (zabs(Beta) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZMLBiCGSTABL Breakdown, Beta = 0 !!") ; return_flag = -1; goto end; }; /* Beta = - Q(:,1)'* (r + Rho* zw )/ Beta; */ DenseMtx_colCopy (vecT, 0, vecR, 0); DenseMtx_colGenAxpy (one, vecT, 0, Rho, vecZW, 0); /* Beta = - (*DenseMtx_colDotProduct(mtxQ, 0, vecT, 0))/Beta; */ DenseMtx_colDotProduct(mtxQ, 0, vecT, 0, Rtmp); /* Beta = - Rtmp/Beta; */ zdiv(Rtmp, Beta, Ttmp); zsub(zero, Ttmp, Beta); /* zg = zg + beta*G(:,k); zw = rho*(zw + beta*W(:,k)); zd = r + zw; */ DenseMtx_colGenAxpy (one, vecZG, 0, Beta, mtxG, Ik-1); /* Rtmp = Rho*Beta; */ zmul(Rho, Beta, Rtmp); DenseMtx_colGenAxpy (Rho, vecZW, 0, Rtmp, mtxW, Ik-1); DenseMtx_colCopy (vecZD, 0, vecR, 0); DenseMtx_colGenAxpy (one, vecZD, 0, one, vecZW, 0); /* for s = 1:i-1 beta = -Q(:,s+1)'*zd/c(s); zd = zd + beta*D(:,s); zg = zg + beta*G(:,s); end */ for ( is = 1; is < ii - 1; is ++){ /* Beta = -(*DenseMtx_colDotProduct(mtxQ, is, vecZD, 0))/c[is] ; */ DenseMtx_colDotProduct(mtxQ, is, vecZD, 0, Rtmp); /* Beta = - Rtmp/c[is]; */ zdiv(Rtmp, c+(2*is), Ttmp); zsub(zero, Ttmp, Beta); DenseMtx_colGenAxpy (one, vecZD, 0, Beta, mtxD, is-1); DenseMtx_colGenAxpy (one, vecZG, 0, Beta, mtxG, is-1); }; /* D(:,i) = zd - u; G(:,i) = zg + zw; */ DenseMtx_colCopy (mtxD, ii-1, vecZD, 0); DenseMtx_colGenAxpy (one, mtxD, ii-1, minusone, mtxU, 0); DenseMtx_colCopy (mtxG, ii-1, vecZG, 0); DenseMtx_colGenAxpy (one, mtxG, ii-1, one, vecZW, 0); /* if i < k c(i) = Q(:,i+1)'*D(:,i); */ if ( ii < Ik ){ /* c[ii] = *DenseMtx_colDotProduct(mtxQ, ii, mtxD, ii-1); */ DenseMtx_colDotProduct(mtxQ, ii, mtxD, ii-1, Rtmp); c[2*ii] = Rtmp[0]; c[2*ii+1] = Rtmp[1]; /* If breakdown ? */ if (zabs(Rtmp) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZMLBiCGSTABL Breakdown, c[ii] = 0 !!") ; return_flag = -1; goto end; }; /* alpha = Q(:,i+1)'*u/c(i); u = u - alpha*D(:,i); g_tld = G(:,i); */ DenseMtx_colDotProduct(mtxQ, ii, mtxU, 0, Rtmp); /* Alpha = Rtmp/c[ii]; */ zdiv(Rtmp, c+(2*ii), Alpha); /* Rtmp = -Alpha; */ zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, mtxU, 0, Rtmp, mtxD, ii-1); DenseMtx_colCopy (vecGt, 0, mtxG, ii-1); /* x = x + rho*alpha*g_tld; W(:,i) = U\(L\(A*g_tld)); r = r - rho*alpha*W(:,i); */ /* Rtmp = Rho * Alpha; */ zmul(Rho, Alpha, Rtmp); DenseMtx_colGenAxpy (one, vecX, 0, Rtmp, vecGt, 0); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; default : fprintf(msgFile, "\n ZTFQMR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } FrontMtx_solveOneColumn(Precond, mtxW, ii-1, vecT, 0, Precond->manager, cpus, msglvl, msgFile) ; Imv++; /* Rtmp = -Rtmp; */ zsub(zero, Rtmp, Rtmp); DenseMtx_colGenAxpy (one, vecR, 0, Rtmp, mtxW, ii-1); /* ---------------- Convergence Test --------------- */ Rtmp[0] = DenseMtx_twoNormOfColumn ( vecR, 0); if ( Rtmp[0] <= error_trol ) { fprintf(msgFile, "\n # iterations = %d", Imv) ; return_flag = Imv; goto end; }; }; }; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n ZMLBiCGSTABL did not Converge !") ; DenseMtx_colCopy(mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; DenseMtx_colCopy(mtxX, 0, vecX, 0); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n ZTFQMR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp[0] = DenseMtx_twoNormOfColumn(vecT, 0); fprintf(msgFile, "\n ZMLBiCGSTABL True Residual norm: %6.2e ", Rtmp[0]) ; fprintf(msgFile, "\n\n after ZMLBiCGSTABL") ; DenseMtx_free(mtxD) ; DenseMtx_free(mtxG) ; DenseMtx_free(mtxU) ; DenseMtx_free(mtxW) ; DenseMtx_free(vecGt) ; DenseMtx_free(vecR) ; DenseMtx_free(vecT) ; DenseMtx_free(vecT1) ; DenseMtx_free(vecX) ; DenseMtx_free(vecZD) ; DenseMtx_free(vecZG) ; DenseMtx_free(vecZW) ; fprintf(msgFile, "\n") ; return(return_flag) ; } /*--------------------------------------------------------------------*/ Iter/src/zmlbicgstabr.c010064400020550007177000000336250664345020100164230ustar00clevecompmath00000400000006/* ZMLBiCGSTABRg.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a complex matrix equation Ax=b using right preconditioned ML(k)BiCGSTABR method by M-C Yeung and T. Chan x -- Initial guess as zeros A -- Input matrix Precond -- Front Matrix as the preconditioner Q -- Starting vectors b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- Dec. 10, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int zmlbicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxQ, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxD, *mtxG, *mtxU, *mtxW; DenseMtx *vecGt, *vecR, *vecT, *vecT1; DenseMtx *vecX, *vecZD, *vecZG, *vecZW ; double Alpha[2], Beta[2], Rho[2] ; double c[200] ; double Init_norm, ratio, Res_norm; double error_trol, m, Rtmp[2], Ttmp[2]; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0} ; double zero[2] = {0.0, 0.0} ; double minusone[2] = {-1.0, 0.0}; double Tiny = 0.1e-28; int Iter, Imv, neqns, Ik, ii, is; int stats[6] ; int return_flag; neqns = n_matrixSize; Ik = mtxQ->ncol; if (Ik > 99){ fprintf(msgFile, "\n\n Fatal Error, \n" " Too many starting vectors in Q !!") ; return(-1); }; return_flag = 1; /* -------------------- init the vectors in ZMLBiCGSTABR -------------------- */ mtxD = DenseMtx_new() ; DenseMtx_init(mtxD, type, 0, 0, neqns, Ik, 1, neqns) ; mtxG = DenseMtx_new() ; DenseMtx_init(mtxG, type, 0, 0, neqns, Ik, 1, neqns) ; mtxU = DenseMtx_new() ; DenseMtx_init(mtxU, type, 0, 0, neqns, 2, 1, neqns) ; mtxW = DenseMtx_new() ; DenseMtx_init(mtxW, type, 0, 0, neqns, Ik, 1, neqns) ; vecGt = DenseMtx_new() ; DenseMtx_init(vecGt, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecT = DenseMtx_new() ; DenseMtx_init(vecT, type, 0, 0, neqns, 1, 1, neqns) ; vecT1 = DenseMtx_new() ; DenseMtx_init(vecT1, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecZD = DenseMtx_new() ; DenseMtx_init(vecZD, type, 0, 0, neqns, 1, 1, neqns) ; vecZG = DenseMtx_new() ; DenseMtx_init(vecZG, type, 0, 0, neqns, 1, 1, neqns) ; vecZW = DenseMtx_new() ; DenseMtx_init(vecZW, type, 0, 0, neqns, 1, 1, neqns) ; for ( ii = 0; ii <200; ii++){ c[ii] = 0; } /* -------------------------- Initialize the iterations -------------------------- */ /* ---- Set initial guess as zero ---- */ DenseMtx_zero(vecX) ; /* ---- If x_0 is not zero ---- */ /* DenseMtx_colCopy (vecX, 0, mtxX, 0); */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; default : fprintf(msgFile, "\n ZTFQMR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_colCopy(vecR, 0, mtxB, 0); DenseMtx_sub(vecR, vecT) ; Init_norm = DenseMtx_twoNormOfColumn(vecR, 0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; error_trol = Init_norm * convergetol ; fprintf(msgFile, "\n ZMLBiCGSTABR Initial norml: %6.2e ", Init_norm ) ; fprintf(msgFile, "\n ZMLBiCGSTABR Conveg. Control: %7.3e ", convergetol ) ; fprintf(msgFile, "\n ZMLBiCGSTABR Convergen Control: %7.3e ",error_trol ) ; DenseMtx_zero(mtxG) ; DenseMtx_zero(mtxD) ; DenseMtx_zero(mtxW) ; Iter = 0; Imv = 0; DenseMtx_colCopy (mtxG, Ik-1, vecR, 0); /* ------------------------------ ZMLBiCGSTABR Iteration start ------------------------------ */ MARKTIME(t1) ; while ( Iter <= itermax ){ Iter++; FrontMtx_solveOneColumn(Precond, vecGt, 0, mtxG, Ik-1, Precond->manager, cpus, msglvl, msgFile) ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; default : fprintf(msgFile, "\n ZTFQMR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_colCopy (mtxW, Ik-1, vecT, 0); Imv++; /* c[Ik] = *DenseMtx_colDotProduct (mtxQ, 0, mtxG, Ik-1); */ DenseMtx_colDotProduct (mtxQ, 0, mtxG, Ik-1, Rtmp); c[2*Ik] = Rtmp[0]; c[2*Ik+1]= Rtmp[1]; if (zabs(Rtmp) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZMLBiCGSTABR Breakdown, c[k] = 0 !!") ; return_flag = -1; goto end; }; /* Alpha =( *DenseMtx_colDotProduct (mtxQ,0, vecR, 0))/c[Ik] ; */ DenseMtx_colDotProduct (mtxQ,0, vecR, 0, Rtmp); /* Alpha = Rtmp/c[Ik]; */ zdiv(Rtmp, c+(2*Ik), Alpha); DenseMtx_colCopy (mtxU, 0, vecR, 0); /* Rtmp = -Alpha; */ zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, mtxU, 0, Rtmp, mtxW, Ik-1); FrontMtx_solveOneColumn(Precond, vecT1, 0, mtxU, 0, Precond->manager, cpus, msglvl, msgFile) ; DenseMtx_colCopy (mtxU, 1, vecT1, 0); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecT1) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecT1) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecT1) ; break ; default : fprintf(msgFile, "\n ZTFQMR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; /* Rho = *DenseMtx_colDotProduct (vecT, 0, vecT, 0); */ DenseMtx_colDotProduct (vecT, 0, vecT, 0, Rho); if (zabs(Rho) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZMLBiCGSTABR Breakdown, Rho = 0 !!") ; return_flag = -1; goto end; }; /* Rho = -(*DenseMtx_colDotProduct (mtxU, 0, vecT, 0))/Rho; */ DenseMtx_colDotProduct (mtxU, 0, vecT, 0, Rtmp); /* Rho = -Rtmp/Rho; */ zdiv(Rtmp, Rho, Ttmp); zsub(zero, Ttmp, Rho); DenseMtx_colGenAxpy(one, vecX, 0, Alpha, vecGt, 0); /* Rtmp = -Rho; */ zsub(zero, Rho, Rtmp); DenseMtx_colGenAxpy (one, vecX, 0, Rtmp, mtxU, 1) ; DenseMtx_colCopy (vecR, 0, mtxU, 0); DenseMtx_colGenAxpy (one, vecR, 0, Rho, vecT, 0) ; /* Iter++; */ /* ---------------- Convergence Test --------------- */ Rtmp[0] = DenseMtx_twoNormOfColumn ( vecR, 0); ratio = Rtmp[0]/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e" "\n Residual norm is %6.2ee", Imv, ratio, Rtmp[0]) ; fflush(msgFile) ; if ( Rtmp[0] <= error_trol ) { fprintf(msgFile, "\n # iterations = %d", Imv) ; return_flag = Imv; goto end; }; for (ii = 1; ii < Ik+1; ii++ ){ if (Iter > itermax ){ fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n ZMLBiCGSTABR did not Converge !") ; return_flag = Imv; goto end; }; DenseMtx_colCopy (vecZD,0, mtxU, 0); DenseMtx_colCopy (vecZG,0, vecR, 0); DenseMtx_zero(vecZW) ; if ( Iter > 1 ){ for ( is = ii ; is < Ik ; is++ ){ /* Beta =-( *(DenseMtx_colDotProduct(mtxQ, is, vecZD, 0)))/c[is]; */ DenseMtx_colDotProduct(mtxQ, is, vecZD, 0, Rtmp); /* Beta = -Rtmp/c[is]; */ zdiv(Rtmp, c+(2*is), Ttmp); zsub(zero, Ttmp, Beta); DenseMtx_colGenAxpy (one, vecZD, 0, Beta, mtxD, is-1); DenseMtx_colGenAxpy (one, vecZG, 0, Beta, mtxG, is-1); DenseMtx_colGenAxpy (one, vecZW, 0, Beta, mtxW, is-1); }; }; /* Beta = Rho * c[Ik]; */ zmul(Rho, c+(2*Ik), Beta); if (zabs(Beta) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZMLBiCGSTABR Breakdown, Beta = 0 !!") ; return_flag = -1; goto end; }; /* Beta = - Q(:,1)'* (r + Rho* zw )/ Beta; */ DenseMtx_colCopy (vecT, 0, vecR, 0); DenseMtx_colGenAxpy (one, vecT, 0, Rho, vecZW, 0); /* Beta = - (*DenseMtx_colDotProduct(mtxQ, 0, vecT, 0))/Beta; */ DenseMtx_colDotProduct(mtxQ, 0, vecT, 0, Rtmp); /* Beta = - Rtmp/Beta; */ zdiv(Rtmp, Beta, Ttmp); zsub(zero, Ttmp, Beta); /* zg = zg + beta*G(:,k); zw = rho*(zw + beta*W(:,k)); zd = r + zw; */ DenseMtx_colGenAxpy (one, vecZG, 0, Beta, mtxG, Ik-1); /* Rtmp = Rho*Beta; */ zmul(Rho, Beta, Rtmp); DenseMtx_colGenAxpy (Rho, vecZW, 0, Rtmp, mtxW, Ik-1); DenseMtx_colCopy (vecZD, 0, vecR, 0); DenseMtx_colGenAxpy (one, vecZD, 0, one, vecZW, 0); /* for s = 1:i-1 beta = -Q(:,s+1)'*zd/c(s); zd = zd + beta*D(:,s); zg = zg + beta*G(:,s); end */ for ( is = 1; is < ii - 1; is ++){ /* Beta = -(*DenseMtx_colDotProduct(mtxQ, is, vecZD, 0))/c[is] ; */ DenseMtx_colDotProduct(mtxQ, is, vecZD, 0, Rtmp); /* Beta = - Rtmp/c[is]; */ zdiv(Rtmp, c+(2*is), Ttmp); zsub(zero, Ttmp, Beta); DenseMtx_colGenAxpy (one, vecZD, 0, Beta, mtxD, is-1); DenseMtx_colGenAxpy (one, vecZG, 0, Beta, mtxG, is-1); }; /* D(:,i) = zd - u; G(:,i) = zg + zw; */ DenseMtx_colCopy (mtxD, ii-1, vecZD, 0); DenseMtx_colGenAxpy (one, mtxD, ii-1, minusone, mtxU, 0); DenseMtx_colCopy (mtxG, ii-1, vecZG, 0); DenseMtx_colGenAxpy (one, mtxG, ii-1, one, vecZW, 0); /* if i < k c(i) = Q(:,i+1)'*D(:,i); */ if ( ii < Ik ){ /* c[ii] = *DenseMtx_colDotProduct(mtxQ, ii, mtxD, ii-1); */ DenseMtx_colDotProduct(mtxQ, ii, mtxD, ii-1, Rtmp); c[2*ii] = Rtmp[0]; c[2*ii+1] = Rtmp[1]; /* If breakdown ? */ if (zabs(Rtmp) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZMLBiCGSTABR Breakdown, c[ii] = 0 !!") ; return_flag = -1; goto end; }; /* alpha = Q(:,i+1)'*u/c(i); u = u - alpha*D(:,i); g_tld = U\(L\G(:,i)); */ /* Alpha = (*DenseMtx_colDotProduct(mtxQ, ii, mtxU, 0))/c[ii]; */ DenseMtx_colDotProduct(mtxQ, ii, mtxU, 0, Rtmp); /* Alpha = Rtmp/c[ii]; */ zdiv(Rtmp, c+(2*ii), Alpha); /* Rtmp = -Alpha; */ zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, mtxU, 0, Rtmp, mtxD, ii-1); /* DenseMtx_colCopy (vecT, 0, mtxG, ii-1); FrontMtx_solve(Precond, vecGt, vecT, Precond->manager, cpus, msglvl, msgFile) ; */ FrontMtx_solveOneColumn(Precond, vecGt, 0, mtxG, ii-1, Precond->manager, cpus, msglvl, msgFile) ; /* x = x + rho*alpha*g_tld; W(:,i) = A*g_tld; r = r - rho*alpha*W(:,i); */ /* Rtmp = Rho * Alpha; */ zmul(Rho, Alpha, Rtmp); DenseMtx_colGenAxpy (one, vecX, 0, Rtmp, vecGt, 0); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecGt) ; break ; default : fprintf(msgFile, "\n ZTFQMR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; DenseMtx_colCopy (mtxW, ii-1, vecT, 0); /* Rtmp = -Rtmp; */ zsub(zero, Rtmp, Rtmp); DenseMtx_colGenAxpy (one, vecR, 0, Rtmp, mtxW, ii-1); /* ---------------- Convergence Test --------------- */ Rtmp[0] = DenseMtx_twoNormOfColumn ( vecR, 0); if ( Rtmp[0] <= error_trol ) { fprintf(msgFile, "\n # iterations = %d", Imv) ; return_flag = Imv; goto end; }; }; }; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n ZMLBiCGSTABR did not Converge !") ; DenseMtx_colCopy(mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; DenseMtx_colCopy(mtxX, 0, vecX, 0); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n ZTFQMR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp[0] = DenseMtx_twoNormOfColumn(vecT, 0); fprintf(msgFile, "\n ZMLBiCGSTABR True Residual norm: %6.2e ", Rtmp[0]) ; fprintf(msgFile, "\n\n after ZMLBiCGSTABR") ; DenseMtx_free(mtxD) ; DenseMtx_free(mtxG) ; DenseMtx_free(mtxU) ; DenseMtx_free(mtxW) ; DenseMtx_free(vecGt) ; DenseMtx_free(vecR) ; DenseMtx_free(vecT) ; DenseMtx_free(vecT1) ; DenseMtx_free(vecX) ; DenseMtx_free(vecZD) ; DenseMtx_free(vecZG) ; DenseMtx_free(vecZW) ; fprintf(msgFile, "\n") ; return(return_flag) ; } /*--------------------------------------------------------------------*/ fprintf(msgFile, "\n ZTFQMR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; }Iter/src/zpcgl.c010064400020550007177000000111650664345020100150520ustar00clevecompmath00000400000006/* zpcgl.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a symmetric nonnegative matrix equation Ax=b using right preconditioned conjugate gradient method x -- Initial guess A -- Input matrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- Oct. 27, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int zpcgl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxZ ; DenseMtx *vecP, *vecR, *vecQ ; DenseMtx *vecX, *vecZ ; double Alpha[2], Beta[2], Rho[2], Rho0[2], Rtmp[2]; double Init_norm, ratio, Res_norm ; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0}, zero[2] = {0.0, 0.0} ; double Tiny[2] = {0.1e-28, 0.0}; int Iter, neqns; int stats[6] ; if (symmetryflag != SPOOLES_HERMITIAN){ fprintf(msgFile, "\n\n Fatal Error, \n" " Matrix is not Hermitian in ZPCGL !!") ; exit(-1); }; neqns = n_matrixSize; /* -------------------- init the vectors in ZPCGL -------------------- */ vecP = DenseMtx_new() ; DenseMtx_init(vecP, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecQ = DenseMtx_new() ; DenseMtx_init(vecQ, type, 0, 0, neqns, 1, 1, neqns) ; vecZ = DenseMtx_new() ; DenseMtx_init(vecZ, type, 0, 0, neqns, 1, 1, neqns) ; /* -------------------------- Initialize the iterations -------------------------- */ FrontMtx_solve(Precond, vecR, mtxB, Precond->manager, cpus, msglvl, msgFile) ; Init_norm = DenseMtx_twoNormOfColumn (vecR, 0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; ratio = 1.0; DenseMtx_zero(vecX) ; MARKTIME(t1) ; Iter = 0; /* ------------------------------ Main Loop of the iterations ------------------------------ */ while ( ratio > convergetol && Iter <= itermax ) { Iter++; /* */ DenseMtx_colDotProduct(vecR, 0, vecR, 0, Rho); if ( Rho[0] == 0.0 & Rho[1] == 0.0){ fprintf(stderr, "\n breakdown in ZPCGL !! " "\n Fatal error \n"); exit(-1) ; } /* */ if ( Iter == 1 ) { DenseMtx_colCopy (vecP, 0, vecR, 0); } else { zdiv(Rho, Rho0, Beta); DenseMtx_colGenAxpy (Beta, vecP, 0, one, vecR, 0); }; InpMtx_herm_gmmm(mtxA, zero, vecZ, one, vecP) ; FrontMtx_solve(Precond, vecQ, vecZ, Precond->manager, cpus, msglvl, msgFile) ; DenseMtx_colDotProduct (vecP, 0, vecQ,0, Rtmp); zdiv(Rho, Rtmp, Alpha); DenseMtx_colGenAxpy (one, vecX, 0, Alpha, vecP, 0); Rtmp[0] = -Alpha[0]; Rtmp[1] = -Alpha[1]; DenseMtx_colGenAxpy (one, vecR, 0, Rtmp, vecQ, 0); Rho0[0] = Rho[0]; Rho0[1] = Rho[1]; /* */ Res_norm = DenseMtx_twoNormOfColumn (vecR, 0); ratio = Res_norm/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e", Iter, ratio) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Iter) ; fprintf(msgFile, "\n\n after ZPCGL") ; DenseMtx_colCopy (mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(vecP) ; DenseMtx_free(vecR) ; DenseMtx_free(vecX) ; DenseMtx_free(vecQ) ; DenseMtx_free(vecZ) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/src/zpcgr.c010064400020550007177000000110610664345020100150530ustar00clevecompmath00000400000006/* zpcgr.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a symmetric nonnegative matrix equation Ax=b using right preconditioned conjugate gradient method x -- Initial guess A -- Input matrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- Oct. 27, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int zpcgr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxZ ; DenseMtx *vecP, *vecR, *vecQ ; DenseMtx *vecX, *vecZ ; double Alpha[2], Beta[2], Rho[2], Rho0[2], Rtmp[2]; double Init_norm, ratio, Res_norm ; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0}, zero[2] = {0.0, 0.0} ; double Tiny[2] = {0.1e-28, 0.0}; int Iter, neqns; int stats[6] ; if (symmetryflag != SPOOLES_HERMITIAN){ fprintf(msgFile, "\n\n Fatal Error, \n" " Matrix is not Hermitian in ZPCGR !!") ; exit(-1); }; neqns = n_matrixSize; /* -------------------- init the vectors in ZPCGR -------------------- */ vecP = DenseMtx_new() ; DenseMtx_init(vecP, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecQ = DenseMtx_new() ; DenseMtx_init(vecQ, type, 0, 0, neqns, 1, 1, neqns) ; vecZ = DenseMtx_new() ; DenseMtx_init(vecZ, type, 0, 0, neqns, 1, 1, neqns) ; /* -------------------------- Initialize the iterations -------------------------- */ Init_norm = DenseMtx_twoNormOfColumn (mtxB, 0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; ratio = 1.0; DenseMtx_zero(vecX) ; DenseMtx_colCopy (vecR, 0, mtxB, 0); MARKTIME(t1) ; Iter = 0; /* ------------------------------ Main Loop of the iterations ------------------------------ */ while ( ratio > convergetol && Iter <= itermax ) { Iter++; /* */ FrontMtx_solve(Precond, vecZ, vecR, Precond->manager, cpus, msglvl, msgFile) ; DenseMtx_colDotProduct(vecR, 0, vecZ, 0, Rho); if ( Rho[0] == 0.0 & Rho[1] == 0.0){ fprintf(stderr, "\n breakdown in ZPCGR !! " "\n Fatal error \n"); exit(-1) ; } /* */ if ( Iter == 1 ) { DenseMtx_colCopy (vecP, 0, vecZ, 0); } else { zdiv(Rho, Rho0, Beta); DenseMtx_colGenAxpy (Beta, vecP, 0, one, vecZ, 0); }; InpMtx_herm_gmmm(mtxA, zero, vecQ, one, vecP) ; DenseMtx_colDotProduct (vecP, 0, vecQ,0, Rtmp); zdiv(Rho, Rtmp, Alpha); DenseMtx_colGenAxpy (one, vecX, 0, Alpha, vecP, 0); Rtmp[0] = -Alpha[0]; Rtmp[1] = -Alpha[1]; DenseMtx_colGenAxpy (one, vecR, 0, Rtmp, vecQ, 0); Rho0[0] = Rho[0]; Rho0[1] = Rho[1]; /* */ Res_norm = DenseMtx_twoNormOfColumn (vecR, 0); ratio = Res_norm/Init_norm; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e", Iter, ratio) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Iter) ; fprintf(msgFile, "\n\n after ZPCGR") ; DenseMtx_colCopy (mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(vecP) ; DenseMtx_free(vecR) ; DenseMtx_free(vecX) ; DenseMtx_free(vecQ) ; DenseMtx_free(vecZ) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/src/ztfqmrl.c010064400020550007177000000301450664345020100154310ustar00clevecompmath00000400000006/* ZTFQMRL.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a complex matrix equation Ax=b using Left preconditioned TFQMR method without lookahead x -- Initial guess as zeros A -- Input matrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- Dec. 10, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int ztfqmrl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *vecD, *vecR, *vecT, *vecU1, *vecU2, *vecV, *vecW; DenseMtx *vecX, *vecY1, *vecY2 ; double Alpha[2], Beta[2], Cee, Eta[2], Rho[2], Rho_new[2] ; double Sigma[2], Tau, Theta, Rtmp[2], Ttmp[2]; double Init_norm, ratio, Res_norm; double error_trol, m; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0}, zero[2] = {0.0, 0.0} ; double Tiny = 0.1e-28; int Iter, Imv, neqns; int stats[6] ; neqns = n_matrixSize; /* -------------------- init the vectors in ZTFQMRL -------------------- */ vecD = DenseMtx_new() ; DenseMtx_init(vecD, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecT = DenseMtx_new() ; DenseMtx_init(vecT, type, 0, 0, neqns, 1, 1, neqns) ; vecU1 = DenseMtx_new() ; DenseMtx_init(vecU1, type, 0, 0, neqns, 1, 1, neqns) ; vecU2 = DenseMtx_new() ; DenseMtx_init(vecU2, type, 0, 0, neqns, 1, 1, neqns) ; vecV = DenseMtx_new() ; DenseMtx_init(vecV, type, 0, 0, neqns, 1, 1, neqns) ; vecW = DenseMtx_new() ; DenseMtx_init(vecW, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecY1 = DenseMtx_new() ; DenseMtx_init(vecY1, type, 0, 0, neqns, 1, 1, neqns) ; vecY2 = DenseMtx_new() ; DenseMtx_init(vecY2, type, 0, 0, neqns, 1, 1, neqns) ; /* -------------------------- Initialize the iterations -------------------------- */ /* ---- Set initial guess as zero ---- */ DenseMtx_zero(vecX) ; DenseMtx_colCopy (vecT, 0, mtxB, 0); /* */ FrontMtx_solve(Precond, vecR, vecT, Precond->manager, cpus, msglvl, msgFile) ; /* */ Init_norm = DenseMtx_twoNormOfColumn(vecR, 0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; error_trol = Init_norm * convergetol ; fprintf(msgFile, "\n ZTFQMRL Initial norml: %6.2e ", Init_norm ) ; fprintf(msgFile, "\n ZTFQMRL Conveg. Control: %7.3e ", convergetol ) ; fprintf(msgFile, "\n ZTFQMRL Convergen Control: %7.3e ",error_trol ) ; DenseMtx_zero(vecD) ; DenseMtx_zero(vecU1) ; DenseMtx_zero(vecU2) ; DenseMtx_zero(vecY2) ; DenseMtx_colCopy (vecW, 0, vecR, 0); DenseMtx_colCopy (vecY1, 0, vecR, 0); Iter = 0; Imv = 0; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecY1) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecY1) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecY1) ; break ; default : fprintf(msgFile, "\n BiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } /* */ FrontMtx_solve(Precond, vecV, vecT, Precond->manager, cpus, msglvl, msgFile) ; /* */ Imv++; DenseMtx_colCopy (vecU1, 0, vecV, 0); Eta[0] = 0.0; Eta[1] = 0.0; Theta = 0.0; Tau = Init_norm ; /* Rho = Tau * Tau ; */ Rho[0] = Tau * Tau; Rho[1] = 0.0; /* ------------------------------ ZTFQMRL Iteration start ------------------------------ */ MARKTIME(t1) ; while ( Iter <= itermax ) { Iter++; DenseMtx_colDotProduct (vecV, 0, vecR,0, Sigma); if (zabs(Sigma) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZTFQMRL Breakdown, Sigma = 0 !!") ; Imv = -1; goto end; }; /* Alpha = Rho/Sigma; */ zdiv(Rho, Sigma, Alpha); /* ---------------- Odd step --------------- */ m = 2 * Iter - 1; /* DenseMtx_axpy(vecW, vecU1, -Alpha); */ zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, vecW, 0, Rtmp, vecU1, 0 ); /* Rtmp = Theta * Theta * Eta / Alpha ; */ Rtmp[0] = Theta * Theta; Rtmp[1] = 0.0; zmul(Rtmp, Eta, Ttmp); zdiv(Ttmp, Alpha, Rtmp); DenseMtx_colGenAxpy (Rtmp, vecD, 0, one, vecY1, 0 ); /* Theta = DenseMtx_fnorm(vecW)/Tau; */ Theta = DenseMtx_twoNormOfColumn(vecW, 0)/Tau; Cee = 1.0/sqrt(1.0 + Theta*Theta); Tau = Tau * Theta * Cee ; /* Eta = Cee * Cee * Alpha ; */ Rtmp[0] = Cee * Cee; Rtmp[1] = 0.0; zmul(Rtmp, Alpha, Eta); DenseMtx_colGenAxpy (one, vecX, 0, Eta, vecD, 0 ); fprintf(msgFile, "\n\n Odd step at %d", Imv); fprintf(msgFile, " \n Tau is : %7.3e", Tau) ; /* Debug purpose: Check the convergence history for the true residual norm */ /* switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; default : fprintf(msgFile, "\n ZTFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp = DenseMtx_fnorm(vecT); fprintf(msgFile, "\n ZTFQMRL Residual norm: %6.2e ", Rtmp) ; */ /* ---------------- Convergence Test --------------- */ if (Tau * sqrt(m + 1) <= error_trol ) { /* */ DenseMtx_colCopy (mtxX, 0, vecX, 0); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n ZTFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp[0] = DenseMtx_twoNormOfColumn(vecT, 0); fprintf(msgFile, "\n ZTFQMRL Residual norm: %6.2e ", Rtmp[0]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after ZTFQMRL") ; goto end; }; /* ---------------- Even step --------------- */ DenseMtx_colCopy (vecY2, 0, vecY1, 0); zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, vecY2, 0, Rtmp, vecV, 0 ); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecY2) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecY2) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecY2) ; break ; default : fprintf(msgFile, "\n ZTFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } FrontMtx_solve(Precond, vecU2, vecT, Precond->manager, cpus, msglvl, msgFile) ; Imv++; m = 2 * Iter ; /* DenseMtx_axpy(vecW, vecU2, -Alpha); */ zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, vecW, 0, Rtmp, vecU2, 0 ); /* Rtmp = Theta * Theta * Eta / Alpha ; */ Rtmp[0] = Theta * Theta; Rtmp[1] = 0.0; zmul(Rtmp, Eta, Ttmp); zdiv(Ttmp, Alpha, Rtmp); DenseMtx_colGenAxpy (Rtmp, vecD, 0, one, vecY2, 0 ); /* Theta = DenseMtx_fnorm(vecW)/Tau; */ Theta = DenseMtx_twoNormOfColumn(vecW, 0)/Tau; Cee = 1.0/sqrt(1.0 + Theta*Theta); Tau = Tau * Theta * Cee ; /* Eta = Cee * Cee * Alpha ; */ Rtmp[0] = Cee * Cee; Rtmp[1] = 0.0; zmul(Rtmp, Alpha, Eta); DenseMtx_colGenAxpy (one, vecX, 0, Eta, vecD, 0 ); fprintf(msgFile, "\n\n Even step at %d", Imv) ; /* ---------------- Convergence Test for even step --------------- */ if (Tau * sqrt(m + 1) <= error_trol ) { DenseMtx_colCopy (mtxX, 0, vecX, 0); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n ZTFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp[0] = DenseMtx_twoNormOfColumn(vecT, 0); fprintf(msgFile, "\n ZTFQMRL Residual norm: %6.2e ", Rtmp[0]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after ZTFQMRL") ; goto end; }; if (zabs(Rho) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZTFQMRL Breakdown, Rho = 0 !!") ; Imv = -1; goto end; }; /* Rho_new = DenseMtx_dot(vecW, vecR); Beta = Rho_new / Rho; Rho = Rho_new ; */ DenseMtx_colDotProduct (vecW, 0, vecR,0, Rho_new); zdiv(Rho_new, Rho, Beta); Rho[0]= Rho_new[0]; Rho[1]= Rho_new[1]; DenseMtx_colCopy (vecY1, 0, vecY2, 0); DenseMtx_colGenAxpy (Beta, vecY1, 0, one, vecW, 0 ); switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecY1) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecY1) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecY1) ; break ; default : fprintf(msgFile, "\n ZTFQMRL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } FrontMtx_solve(Precond, vecU1, vecT, Precond->manager, cpus, msglvl, msgFile) ; Imv++; /* */ DenseMtx_colCopy (vecT, 0, vecU2, 0); DenseMtx_colGenAxpy (one, vecT, 0, Beta, vecV, 0 ); DenseMtx_colCopy (vecV, 0, vecT, 0); DenseMtx_colGenAxpy (Beta, vecV, 0, one, vecU1, 0 ); Rtmp[0] = Tau*sqrt(m + 1)/Init_norm ; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e", Imv, Rtmp[0]) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n ZTFQMRL did not Converge !") ; fprintf(msgFile, "\n\n after ZTFQMRL") ; DenseMtx_colCopy (mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: DenseMtx_free(vecD) ; DenseMtx_free(vecR) ; DenseMtx_free(vecT) ; DenseMtx_free(vecU1) ; DenseMtx_free(vecU2) ; DenseMtx_free(vecV) ; DenseMtx_free(vecW) ; DenseMtx_free(vecX) ; DenseMtx_free(vecY1) ; DenseMtx_free(vecY2) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ */ Rtmp[0] = Cee * Cee; Rtmp[1] = 0.0; zmul(Rtmp, Alpha, Eta); DenseMtx_colGenAxpy (one, vecX, 0, Eta, vecD, 0 ); fprintf(msgFile, "\n\n Odd step at %d", Imv); fprintf(msgFile, " \n Tau is : %7.3e", Tau) ; /* Debug purpose: Check the convergence history for the true residual norm */ /* switch ( symmetryflag ) { case SPOOLES_SYMMETRIC Iter/src/ztfqmrr.c010064400020550007177000000313630664345020100154420ustar00clevecompmath00000400000006/* ZTFQMRR.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to solve a complex matrix equation Ax=b using right preconditioned TFQMR method without lookahead x -- Initial guess as zeros A -- Input matrix M -- Front Matrix as the preconditioner b -- Right-hand side tol -- Convergence tolerance type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides msglvl -- message level msgFile -- message file return value -- error flag created -- Dec. 10, 1998 Wei-Pai Tang --------------------------------------------------------------------- */ int ztfqmrr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *vecD, *vecR, *vecT, *vecU1, *vecU2, *vecV, *vecW; DenseMtx *vecX, *vecY1, *vecY2 ; double Alpha[2], Beta[2], Cee, Eta[2], Rho[2], Rho_new[2] ; double Sigma[2], Tau, Theta, Rtmp[2], Ttmp[2]; double Init_norm, ratio, Res_norm; double error_trol, m ; double t1, t2, cpus[9] ; double one[2] = {1.0, 0.0}, zero[2] = {0.0, 0.0} ; double Tiny = 0.1e-28; int Iter, Imv, neqns; int stats[6] ; neqns = n_matrixSize; /* -------------------- init the vectors in ZTFQMRR -------------------- */ vecD = DenseMtx_new() ; DenseMtx_init(vecD, type, 0, 0, neqns, 1, 1, neqns) ; vecR = DenseMtx_new() ; DenseMtx_init(vecR, type, 0, 0, neqns, 1, 1, neqns) ; vecT = DenseMtx_new() ; DenseMtx_init(vecT, type, 0, 0, neqns, 1, 1, neqns) ; vecU1 = DenseMtx_new() ; DenseMtx_init(vecU1, type, 0, 0, neqns, 1, 1, neqns) ; vecU2 = DenseMtx_new() ; DenseMtx_init(vecU2, type, 0, 0, neqns, 1, 1, neqns) ; vecV = DenseMtx_new() ; DenseMtx_init(vecV, type, 0, 0, neqns, 1, 1, neqns) ; vecW = DenseMtx_new() ; DenseMtx_init(vecW, type, 0, 0, neqns, 1, 1, neqns) ; vecX = DenseMtx_new() ; DenseMtx_init(vecX, type, 0, 0, neqns, 1, 1, neqns) ; vecY1 = DenseMtx_new() ; DenseMtx_init(vecY1, type, 0, 0, neqns, 1, 1, neqns) ; vecY2 = DenseMtx_new() ; DenseMtx_init(vecY2, type, 0, 0, neqns, 1, 1, neqns) ; /* -------------------------- Initialize the iterations -------------------------- */ /* ---- Set initial guess as zero ---- */ DenseMtx_zero(vecX) ; Init_norm = DenseMtx_twoNormOfColumn(mtxB, 0); if ( Init_norm == 0.0 ){ Init_norm = 1.0; }; error_trol = Init_norm * convergetol ; fprintf(msgFile, "\n ZTFQMRR Initial norml: %6.2e ", Init_norm ) ; fprintf(msgFile, "\n ZTFQMRR Conveg. Control: %6.2e ", convergetol ) ; fprintf(msgFile, "\n ZTFQMRR Convergen Control: %6.2e ",error_trol ) ; DenseMtx_zero(vecD) ; DenseMtx_zero(vecU1) ; DenseMtx_zero(vecU2) ; DenseMtx_zero(vecY2) ; Iter = 0; Imv = 0; DenseMtx_colCopy (vecR, 0, mtxB, 0); DenseMtx_colCopy (vecW, 0, vecR, 0); DenseMtx_colCopy (vecY1, 0, vecR, 0); /* */ FrontMtx_solve(Precond, vecT, vecY1, Precond->manager, cpus, msglvl, msgFile) ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecV, one, vecT) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecV, one, vecT) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecV, one, vecT) ; break ; default : fprintf(msgFile, "\n BiCGSTABL Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; DenseMtx_colCopy (vecU1, 0, vecV, 0); /* */ Eta[0] = 0.0; Eta[1] = 0.0; Tau = Init_norm ; Theta = 0.0; /* Rho = Tau * Tau ; */ Rho[0] = Tau * Tau; Rho[1] = 0.0; /* ------------------------------ ZTFQMRR Iteration start ------------------------------ */ MARKTIME(t1) ; while ( Iter <= itermax ) { Iter++; /* Sigma = DenseMtx_dot(vecV, vecR); */ DenseMtx_colDotProduct (vecV, 0, vecR,0, Sigma); if (zabs(Sigma) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZTFQMRR Breakdown, Sigma = 0 !!") ; Imv = -1; goto end; }; /* Alpha = Rho/Sigma; */ zdiv(Rho, Sigma, Alpha); /* ---------------- Odd step --------------- */ m = 2 * Iter - 1; zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, vecW, 0, Rtmp, vecU1, 0 ); /* Rtmp = Theta * Theta * Eta / Alpha ; */ Rtmp[0] = Theta * Theta; Rtmp[1] = 0.0; zmul(Rtmp, Eta, Ttmp); zdiv(Ttmp, Alpha, Rtmp); DenseMtx_colGenAxpy (Rtmp, vecD, 0, one, vecY1, 0 ); /* Theta = DenseMtx_fnorm(vecW)/Tau; */ Theta = DenseMtx_twoNormOfColumn(vecW, 0)/Tau; Cee = 1.0/sqrt(1.0 + Theta*Theta); Tau = Tau * Theta * Cee ; /* Eta = Cee * Cee * Alpha ; */ Rtmp[0] = Cee * Cee; Rtmp[1] = 0.0; zmul(Rtmp, Alpha, Eta); DenseMtx_colGenAxpy (one, vecX, 0, Eta, vecD, 0 ); fprintf(msgFile, "\n\n Odd step at %d", Imv); fprintf(msgFile, " \n Tau is : %6.2e", Tau) ; /* ------------------ For debug purpose: Check the true residual ------------------ */ /* --------------- DenseMtx_colCopy (vecT, 0, vecX, 0); FrontMtx_solve(Precond, mtxX, vecT, Precond->manager, cpus, msglvl, msgFile) ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n ZTFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp[0] = DenseMtx_fnorm(vecT); fprintf(msgFile, "\n ZTFQMRR Residual norm: %6.2e ", Rtmp[0]) ; --------------- */ /* ---------------- Convergence Test --------------- */ if (Tau * sqrt(m + 1) <= error_trol ) { /* */ FrontMtx_solve(Precond, mtxX, vecX, Precond->manager, cpus, msglvl, msgFile) ; /* */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n ZTFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp[0] = DenseMtx_twoNormOfColumn(vecT, 0); fprintf(msgFile, "\n ZTFQMRR Residual norm: %6.2e ", Rtmp[0]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after ZTFQMRR") ; goto end; }; /* ---------------- Even step --------------- */ DenseMtx_colCopy (vecY2, 0, vecY1, 0); zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, vecY2, 0, Rtmp, vecV, 0 ); FrontMtx_solve(Precond, vecT, vecY2, Precond->manager, cpus, msglvl, msgFile) ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecU2, one, vecT) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecU2, one, vecT) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecU2, one, vecT) ; break ; default : fprintf(msgFile, "\n ZTFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } m = 2 * Iter ; zsub(zero, Alpha, Rtmp); DenseMtx_colGenAxpy (one, vecW, 0, Rtmp, vecU2, 0 ); /* Rtmp = Theta * Theta * Eta / Alpha ; */ Rtmp[0] = Theta * Theta; Rtmp[1] = 0.0; zmul(Rtmp, Eta, Ttmp); zdiv(Ttmp, Alpha, Rtmp); DenseMtx_colGenAxpy (Rtmp, vecD, 0, one, vecY2, 0 ); /* Theta = DenseMtx_fnorm(vecW)/Tau; */ Theta = DenseMtx_twoNormOfColumn(vecW, 0)/Tau; Cee = 1.0/sqrt(1.0 + Theta*Theta); Tau = Tau * Theta * Cee ; /* Eta = Cee * Cee * Alpha ; */ Rtmp[0] = Cee * Cee; Rtmp[1] = 0.0; zmul(Rtmp, Alpha, Eta); DenseMtx_colGenAxpy (one, vecX, 0, Eta, vecD, 0 ); fprintf(msgFile, "\n\n Even step at %d", Imv) ; /* ---------------- Convergence Test for even step --------------- */ if (Tau * sqrt(m + 1) <= error_trol ) { /* */ FrontMtx_solve(Precond, mtxX, vecX, Precond->manager, cpus, msglvl, msgFile) ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, mtxX) ; break ; default : fprintf(msgFile, "\n ZTFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } DenseMtx_sub(vecT, mtxB) ; Rtmp[0] = DenseMtx_twoNormOfColumn(vecT, 0); fprintf(msgFile, "\n ZTFQMRR Residual norm: %6.2e ", Rtmp[0]) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Converges in time: %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n after ZTFQMRR") ; goto end; }; if (zabs(Rho) == 0){ fprintf(msgFile, "\n\n Fatal Error, \n" " ZTFQMRR Breakdown, Rho = 0 !!") ; Imv = -1; goto end; }; /* Rho_new = DenseMtx_dot(vecW, vecR); Beta = Rho_new / Rho; Rho = Rho_new ; */ DenseMtx_colDotProduct (vecW, 0, vecR,0, Rho_new); zdiv(Rho_new, Rho, Beta); Rho[0]= Rho_new[0]; Rho[1]= Rho_new[1]; DenseMtx_colCopy (vecY1, 0, vecY2, 0); DenseMtx_colGenAxpy (Beta, vecY1, 0, one, vecW, 0 ); /* */ FrontMtx_solve(Precond, vecT, vecY1, Precond->manager, cpus, msglvl, msgFile) ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecU1, one, vecT) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecU1, one, vecT) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecU1, one, vecT) ; break ; default : fprintf(msgFile, "\n ZTFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; DenseMtx_colCopy (vecT, 0, vecU2, 0); DenseMtx_colGenAxpy (one, vecT, 0, Beta, vecV, 0 ); DenseMtx_colCopy (vecV, 0, vecT, 0); DenseMtx_colGenAxpy (Beta, vecV, 0, one, vecU1, 0 ); Rtmp[0] = Tau*sqrt(m + 1)/Init_norm ; fprintf(msgFile, "\n\n At iteration %d" " the convergence ratio is %12.4e", Imv, Rtmp[0]) ; } /* End of while loop */ MARKTIME(t2) ; fprintf(msgFile, "\n CPU : Total iteration time is : %8.3f ", t2 - t1) ; fprintf(msgFile, "\n # iterations = %d", Imv) ; fprintf(msgFile, "\n\n ZTFQMRR did not Converge !") ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_gmmm(mtxA, zero, vecT, one, vecX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_gmmm(mtxA, zero, vecT, one, vecX) ; break ; default : fprintf(msgFile, "\n ZTFQMRR Matrix type wrong"); fprintf(msgFile, "\n Fatal error"); goto end; } Imv++; DenseMtx_sub(vecT, mtxB) ; Rtmp[0] = DenseMtx_twoNormOfColumn(vecT, 0); fprintf(msgFile, "\n ZTFQMRR Residual norm: %6.2e ", Rtmp[0] ) ; fprintf(msgFile, "\n\n after ZTFQMRR") ; DenseMtx_colCopy (mtxX, 0, vecX, 0); /* ------------------------ free the working storage ------------------------ */ end: DenseMtx_free(vecD) ; DenseMtx_free(vecR) ; DenseMtx_free(vecT) ; DenseMtx_free(vecU1) ; DenseMtx_free(vecU2) ; DenseMtx_free(vecV) ; DenseMtx_free(vecW) ; DenseMtx_free(vecX) ; DenseMtx_free(vecY1) ; DenseMtx_free(vecY2) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/drivers/do_colCopy010075500020550007177000000004330663306504100164750ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = stdout set type = 2 set nrow = 4 set ncol = 2 set inc1 = 1 set inc2 = $nrow set icol = 0 set jcol = 1 set seed = 10101 test_colCopy $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 \ $icol $jcol $seed Iter/drivers/do_colDotProduct010075500020550007177000000004410663156452100176560ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = stdout set type = 2 set nrow = 4 set ncol = 2 set inc1 = 1 set inc2 = $nrow set icol = 0 set jcol = 1 set seed = 10101 test_colDotProduct $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 \ $icol $jcol $seed Iter/drivers/do_colGenAxpy010075500020550007177000000005740663157234100171500ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = stdout set type = 2 set nrow = 3 set ncol = 2 set inc1 = $ncol set inc2 = 1 set icol = 0 set jcol = 1 set ralpha = 1 set ialpha = 2 set rbeta = 3 set ibeta = 1 set seed = 10101 test_colGenAxpy $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 \ $icol $jcol $ralpha $ialpha $rbeta $ibeta $seed Iter/drivers/do_frobNorm010075500020550007177000000003570663204741000166550ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = stdout set type = 2 set nrow = 4 set ncol = 2 set inc1 = 1 set inc2 = $nrow set seed = 10101 test_frobNorm $msglvl $msgFile $type $nrow $ncol $inc1 \ $inc2 $seed Iter/drivers/do_iter010075500020550007177000000025530664026133000160320ustar00clevecompmath00000400000006#! /bin/csh -f ## method: 0)BiCGStabR 1)BiCGStabL 2)MLBiCGStabR 3)MLBiCGStabL ## 4)TFQMRR 5)TFQMRL 6)PCGR 7)PCGL ## 8)GMRESR 9)GMRESL set input = in2 set srcformat = 0 set srcFile = ../../Matrices/COMPLEX/zherm.inpmtxb set inpmtxFile = none set etreesrc = 0 set etreeFile = ../../Matrices/COMPLEX/zherm.etreef set rhsFile = none set slnFile = none set msgFile = stdout set msglvl = 1 set seed = 10101 set nrhs = 4 set Ik = 5 set itermax = 100 set iterout = 10 set symmetryflag = 1 set sparsityflag = 1 set pivotingflag = 1 set tau = 100 set droptol = 1.0e-4 set convergece = 1.0e-8 set method = 6/7 #use "/" to separate method number echo $srcformat > $input echo $srcFile >> $input echo $inpmtxFile >> $input echo $etreesrc >> $input echo $etreeFile >> $input echo $rhsFile >> $input echo $slnFile >> $input echo $msgFile >> $input echo $msglvl $seed $nrhs $Ik $itermax $iterout >> $input echo $symmetryflag $sparsityflag $pivotingflag >> $input echo $tau $droptol $convergece >> $input set tmp = `echo $method | /bin/sed s/"\/"/" "/g` echo $tmp >> $input echo " " >> $input iter $input #/bin/rm -f $input Iter/drivers/do_mmm010075500020550007177000000010220664026412700156520ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = stdout set type = 2 set nrow = 2 set nk = 3 set ncol = 2 set ainc1 = 1 set ainc2 = $nrow set binc1 = 1 set binc2 = $nk set cinc1 = 1 set cinc2 = $ncol set a_opt = "n" set b_opt = "n" set ralpha = 1.0 set ialpha = 2.0 set rbeta = 1.0 set ibeta = -1.0 set seed = 10101 test_DenseMtx_mmm $msglvl $msgFile $type $nrow $nk $ncol $ainc1 \ $ainc2 $binc1 $binc2 $cinc1 $cinc2 $a_opt $b_opt $ralpha \ $ialpha $rbeta $ibeta $seed Iter/drivers/do_twoNormOfColumn010075500020550007177000000004160663204737100202030ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = stdout set type = 2 set nrow = 4 set ncol = 2 set inc1 = 1 set inc2 = $nrow set jcol = 1 set seed = 10101 test_twoNormOfColumn $msglvl $msgFile $type $nrow $ncol \ $inc1 $inc2 $jcol $seed Iter/drivers/makefile010064400020550007177000000024750665314256100161720ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../src/Iter.a ${THREAD_LIBS} ../../spooles.a -lm LIBS = ${THREAD_LIBS} ../../spooles.a -lm DRIVERS = iter test_colDotProduct test_colGenAxpy test_frobNorm\ test_twoNormOfColumn test_colCopy test_mmm drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} clean_test: - rm -f test_colDotProduct test_colGenAxpy test_frobNorm\ test_twoNormOfColumn test_colCopy \ test_colDotProduct.o test_colGenAxpy.o test_frobNorm.o\ test_twoNormOfColumn.o test_colCopy.o iter : iter.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} test_colDotProduct: test_colDotProduct.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} test_colGenAxpy: test_colGenAxpy.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} test_frobNorm: test_frobNorm.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} test_twoNormOfColumn: test_twoNormOfColumn.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} test_colCopy: test_colCopy.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} test_mmm: test_mmm.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} Iter/drivers/iter.c010064400020550007177000000675340664026067600156140ustar00clevecompmath00000400000006/* iter.c */ #include "../Iter.h" #include "../../Graph.h" #include #define METHODS 10 int InpMtx_readFromAIJ2file(InpMtx *mtxA, char *srcFileName); int InpMtx_createGraph(InpMtx *mtxA, Graph *graph); /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------------- test the factor method for a grid matrix (0) read in matrix from source file (1) conver data matrix to InpMtx object if necessary (2) create Graph and ETree object if necessary (3) read in/create an ETree object (4) create a solution matrix object (5) multiply the solution with the matrix to get a right hand side matrix object (6) factor the matrix (7) solve the system created -- 98dec30, jwu ----------------------------------------------------- */ { char etreeFileName[80], mtxFileName[80], *cpt, rhsFileName[80], srcFileName[80], ctemp[81], msgFileName[80], slnFileName[80] ; Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxB, *mtxQ, *mtxX, *mtxZ ; double one[2] = { 1.0, 0.0 } ; FrontMtx *frontmtx ; InpMtx *mtxA ; SubMtxManager *mtxmanager ; double cputotal, droptol, conv_tol, factorops ; double cpus[9] ; Drand drand ; double nops, tau, t1, t2 ; ETree *frontETree ; Graph *graph ; FILE *msgFile, *inFile ; int error, loc, msglvl, neqns, nzf, iformat, pivotingflag, rc, seed, sparsityflag, symmetryflag, method[METHODS], type, nrhs, etreeflag ; int stats[6] ; int nnzA, Ik, itermax, zversion, iterout ; IV *newToOldIV, *oldToNewIV ; IVL *symbfacIVL ; int i, j, k, m, n, imethod, maxdomainsize, maxzeros, maxsize; int nouter,ninner ; if ( argc != 2 ) { fprintf(stdout, "\n\n usage : %s inFile" "\n inFile -- input filename" "\n", argv[0]) ; return(-1) ; } /* read input file */ inFile = fopen(argv[1], "r"); if (inFile == (FILE *)NULL) { fprintf(stderr, "\n fatal error in %s: unable to open file %s\n", argv[0], argv[1]) ; return(-1) ; } for (i=0; i 2) { fprintf(stderr, "\n fatal error in %s: " "invalid source matrix format\n",argv[0]) ; return(-1) ; } } else if (k==1) sscanf(ctemp, "%s", srcFileName); else if (k==2) sscanf(ctemp, "%s", mtxFileName); else if (k==3) { sscanf(ctemp, "%d", &etreeflag); if (etreeflag < 0 || etreeflag > 4) { fprintf(stderr, "\n fatal error in %s: " "invalid etree file status\n",argv[0]) ; return(-1) ; } } else if (k==4) sscanf(ctemp, "%s", etreeFileName); else if (k==5) sscanf(ctemp, "%s", rhsFileName); else if (k==6) sscanf(ctemp, "%s", slnFileName); else if (k==7){ sscanf(ctemp, "%s", msgFileName); if ( strcmp(msgFileName, "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(msgFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], ctemp) ; return(-1) ; } } else if (k==8) sscanf(ctemp, "%d %d %d %d %d %d", &msglvl, &seed, &nrhs, &Ik, &itermax, &iterout); else if (k==9) sscanf(ctemp, "%d %d %d", &symmetryflag, &sparsityflag, &pivotingflag); else if (k==10) sscanf(ctemp, "%lf %lf %lf", &tau, &droptol, &conv_tol); else if (k==11) { /* for (j=0; j 1) { fprintf(msgFile,"*** Multiple right-hand-side vectors is not allowed yet.\n"); fprintf(msgFile,"*** nrhs is reset to 1.\n"); nrhs =1; } fprintf(msgFile, "\n %s " "\n srcFileName -- %s" "\n mtxFileName -- %s" "\n etreeFileName -- %s" "\n rhsFileName -- %s" "\n msglvl -- %d" "\n seed -- %d" "\n symmetryflag -- %d" "\n sparsityflag -- %d" "\n pivotingflag -- %d" "\n tau -- %e" "\n droptol -- %e" "\n conv_tol -- %e" "\n method -- ", argv[0], srcFileName, mtxFileName, etreeFileName, rhsFileName, msglvl, seed, symmetryflag, sparsityflag, pivotingflag, tau, droptol, conv_tol) ; for (k=0; k0 && strcmp(mtxFileName, "none") != 0 ) { rc = InpMtx_writeToFile(mtxA, mtxFileName) ; if ( rc != 1 ) fprintf(msgFile, "\n return value %d from InpMtx_writeToFile(%p,%s)", rc, mtxA, mtxFileName) ; } fprintf(msgFile, "\n CPU %8.3f : read in (+ convert to) mtxA from file %s", t2 - t1, mtxFileName) ; if (rc != 1) { goto end_read; } type = mtxA->inputMode ; neqns = 1 + IVmax(mtxA->nent, InpMtx_ivec1(mtxA), &loc) ; if ( INPMTX_IS_BY_ROWS(mtxA) ) { fprintf(msgFile, "\n matrix coordinate type is rows") ; } else if ( INPMTX_IS_BY_COLUMNS(mtxA) ) { fprintf(msgFile, "\n matrix coordinate type is columns") ; } else if ( INPMTX_IS_BY_CHEVRONS(mtxA) ) { fprintf(msgFile, "\n matrix coordinate type is chevrons") ; } else { fprintf(msgFile, "\n\n, error, bad coordinate type") ; rc=-1; goto end_read; } if ( INPMTX_IS_RAW_DATA(mtxA) ) { fprintf(msgFile, "\n matrix storage mode is raw data\n") ; } else if ( INPMTX_IS_SORTED(mtxA) ) { fprintf(msgFile, "\n matrix storage mode is sorted\n") ; } else if ( INPMTX_IS_BY_VECTORS(mtxA) ) { fprintf(msgFile, "\n matrix storage mode is by vectors\n") ; } else { fprintf(msgFile, "\n\n, error, bad storage mode") ; rc=-1; goto end_read; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after reading InpMtx object from file %s", mtxFileName) ; if ( msglvl == 2 ) { InpMtx_writeStats(mtxA, msgFile) ; } else { InpMtx_writeForHumanEye(mtxA, msgFile) ; } fflush(msgFile) ; } /* Get the nonzeros in matrix A and print it */ nnzA = InpMtx_nent( mtxA ); fprintf(msgFile, "\n\n Input matrix size %d NNZ %d", neqns, nnzA) ; /* -------------------------------------------------------- generate the linear system 1. generate solution matrix and fill with random numbers 2. generate rhs matrix and fill with zeros 3. compute matrix-matrix multiply -------------------------------------------------------- */ MARKTIME(t1) ; mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, -1, neqns, nrhs, 1, neqns) ; mtxB = DenseMtx_new() ; if (strcmp(rhsFileName, "none")) { rc = DenseMtx_readFromFile(mtxB, rhsFileName) ; if ( rc != 1 ) fprintf(msgFile, "\n return value %d from DenseMtx_readFromFile(%p,%s)", rc, mtxB, rhsFileName) ; DenseMtx_zero(mtxX) ; } else { DenseMtx_init(mtxB, type, 1, -1, neqns, nrhs, 1, neqns) ; DenseMtx_fillRandomEntries(mtxX, &drand) ; DenseMtx_zero(mtxB) ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_mmm(mtxA, mtxB, one, mtxX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_mmm(mtxA, mtxB, one, mtxX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_mmm(mtxA, mtxB, one, mtxX) ; break ; default : break ; } } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set up the solution and rhs ", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n original mtxX") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fprintf(msgFile, "\n\n original mtxB") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } if (rc != 1) { InpMtx_free(mtxA); DenseMtx_free(mtxX); DenseMtx_free(mtxB); goto end_init; } /* ------------------------ read in/create the ETree object ------------------------ */ MARKTIME(t1) ; if (etreeflag == 0) { /* read in ETree from file */ if ( strcmp(etreeFileName, "none") == 0 ) fprintf(msgFile, "\n no file to read from") ; frontETree = ETree_new() ; rc = ETree_readFromFile(frontETree, etreeFileName) ; if (rc!=1) fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, frontETree, etreeFileName) ; } else { graph = Graph_new() ; rc = InpMtx_createGraph(mtxA, graph); if (rc!=1) { fprintf(msgFile, "\n return value %d from InpMtx_createGraph(%p,%p)", rc, mtxA, graph) ; Graph_free(graph); goto end_tree; } if (etreeflag == 1) { /* Via BestOfNDandMS */ maxdomainsize = 500; maxzeros = 1000; maxsize = 64 ; frontETree = orderViaBestOfNDandMS(graph, maxdomainsize, maxzeros, maxsize, seed, msglvl, msgFile) ; } else if (etreeflag == 2) { /* Via MMD */ frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; } else if (etreeflag == 3) { /* Via MS */ maxdomainsize = 500; frontETree = orderViaMS(graph, maxdomainsize, seed, msglvl, msgFile) ; } else if (etreeflag == 4) { /* Via ND */ maxdomainsize = 500; frontETree = orderViaND(graph, maxdomainsize, seed, msglvl, msgFile) ; } Graph_free(graph); /* optionally write out the ETree object */ if ( strcmp(etreeFileName, "none") != 0 ) { fprintf(msgFile, "\n\n writing out ETree to file %s", etreeFileName) ; ETree_writeToFile(frontETree, etreeFileName) ; } } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in/create frontETree from file %s", t2 - t1, etreeFileName) ; if ( rc != 1 ) { ETree_free(frontETree); goto end_tree; } ETree_leftJustify(frontETree) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after reading ETree object from file %s", etreeFileName) ; if ( msglvl == 2 ) { ETree_writeStats(frontETree, msgFile) ; } else { ETree_writeForHumanEye(frontETree, msgFile) ; } } fflush(msgFile) ; /* -------------------------------------------------- get the permutations, permute the matrix and the front tree, and compute the symbolic factorization -------------------------------------------------- */ MARKTIME(t1) ; oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get permutations", t2 - t1) ; MARKTIME(t1) ; ETree_permuteVertices(frontETree, oldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute front tree", t2 - t1) ; MARKTIME(t1) ; InpMtx_permute(mtxA, IV_entries(oldToNewIV), IV_entries(oldToNewIV)) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute mtxA", t2 - t1) ; if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { MARKTIME(t1) ; InpMtx_mapToUpperTriangle(mtxA) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : map to upper triangle", t2 - t1) ; } if ( ! INPMTX_IS_BY_CHEVRONS(mtxA) ) { MARKTIME(t1) ; InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : change coordinate type", t2 - t1) ; } if ( INPMTX_IS_RAW_DATA(mtxA) ) { MARKTIME(t1) ; InpMtx_changeStorageMode(mtxA, INPMTX_SORTED) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : sort entries ", t2 - t1) ; } if ( INPMTX_IS_SORTED(mtxA) ) { MARKTIME(t1) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : convert to vectors ", t2 - t1) ; } MARKTIME(t1) ; symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : symbolic factorization", t2 - t1) ; MARKTIME(t1) ; DenseMtx_permuteRows(mtxB, oldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute rhs", t2 - t1) ; /* ------------------------------ initialize the FrontMtx object ------------------------------ */ MARKTIME(t1) ; frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, sparsityflag, pivotingflag, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : initialize the front matrix", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n nendD = %d, nentL = %d, nentU = %d", frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ; SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n front matrix initialized") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /* ----------------- factor the matrix ----------------- */ nzf = ETree_nFactorEntries(frontETree, symmetryflag) ; factorops = ETree_nFactorOps(frontETree, type, symmetryflag) ; fprintf(msgFile, "\n %d factor entries, %.0f factor ops, %8.3f ratio", nzf, factorops, factorops/nzf) ; IVzero(6, stats) ; DVzero(9, cpus) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1) ; MARKTIME(t1) ; rootchv = FrontMtx_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, &error, cpus, stats, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : factor matrix, %8.3f mflops", t2 - t1, 1.e-6*factorops/(t2-t1)) ; if ( rootchv != NULL ) { fprintf(msgFile, "\n\n factorization did not complete") ; for ( chv = rootchv ; chv != NULL ; chv = chv->next ) { fprintf(stdout, "\n chv %d, nD = %d, nL = %d, nU = %d", chv->id, chv->nD, chv->nL, chv->nU) ; } } if ( error >= 0 ) { fprintf(msgFile, "\n\n error encountered at front %d\n", error) ; rc=error ; goto end_front; } fprintf(msgFile, "\n %8d pivots, %8d pivot tests, %8d delayed rows and columns", stats[0], stats[1], stats[2]) ; if ( frontmtx->rowadjIVL != NULL ) { fprintf(msgFile, "\n %d entries in rowadjIVL", frontmtx->rowadjIVL->tsize) ; } if ( frontmtx->coladjIVL != NULL ) { fprintf(msgFile, ", %d entries in coladjIVL", frontmtx->coladjIVL->tsize) ; } if ( frontmtx->upperblockIVL != NULL ) { fprintf(msgFile, "\n %d fronts, %d entries in upperblockIVL", frontmtx->nfront, frontmtx->upperblockIVL->tsize) ; } if ( frontmtx->lowerblockIVL != NULL ) { fprintf(msgFile, ", %d entries in lowerblockIVL", frontmtx->lowerblockIVL->tsize) ; } fprintf(msgFile, "\n %d entries in D, %d entries in L, %d entries in U", stats[3], stats[4], stats[5]) ; fprintf(msgFile, "\n %d locks", frontmtx->nlocks) ; if ( FRONTMTX_IS_SYMMETRIC(frontmtx) || FRONTMTX_IS_HERMITIAN(frontmtx) ) { int nneg, npos, nzero ; FrontMtx_inertia(frontmtx, &nneg, &nzero, &npos) ; fprintf(msgFile, "\n %d negative, %d zero and %d positive eigenvalues", nneg, nzero, npos) ; fflush(msgFile) ; } cputotal = cpus[8] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n initialize fronts %8.3f %6.2f" "\n load original entries %8.3f %6.2f" "\n update fronts %8.3f %6.2f" "\n assemble postponed data %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n extract postponed data %8.3f %6.2f" "\n store factor entries %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[6], 100.*cpus[6]/cputotal, cpus[7], 100.*cpus[7]/cputotal, cputotal) ; } if ( msglvl > 1 ) { SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; ChvManager_writeForHumanEye(chvmanager, msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } /* ------------------------------ post-process the factor matrix ------------------------------ */ MARKTIME(t1) ; FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : post-process the matrix", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } fprintf(msgFile, "\n\n after post-processing") ; if ( msglvl > 1 ) SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ---------------- solve the system ---------------- */ neqns = mtxB->nrow ; mtxZ = DenseMtx_new() ; DenseMtx_init(mtxZ, type, 0, 0, neqns, nrhs, 1, neqns) ; zversion=INPMTX_IS_COMPLEX_ENTRIES(mtxA); for (k=0; k 2 ) { fprintf(msgFile, "\n\n rhs") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n itemax %d", itermax) ; DVzero(6, cpus) ; MARKTIME(t1) ; switch ( method[k] ) { case BiCGStabR : if (zversion) rc=zbicgstabr(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); else rc=bicgstabr(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); break; case BiCGStabL : if (zversion) rc=zbicgstabl(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); else rc=bicgstabl(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); break; case TFQMRR : if (zversion) rc=ztfqmrr(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); else rc=tfqmrr(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); break; case TFQMRL : if (zversion) rc=ztfqmrl(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); else rc=tfqmrl(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); break; case PCGR : if (zversion) rc=zpcgr(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); else rc=pcgr(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); break; case PCGL : if (zversion) rc=zpcgl(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); else rc=pcgl(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); break; case MLBiCGStabR : mtxQ = DenseMtx_new() ; DenseMtx_init(mtxQ, type, 0, -1, neqns, Ik, 1, neqns) ; Drand_setUniform(&drand, 0.0, 1.0) ; DenseMtx_fillRandomEntries(mtxQ, &drand) ; if (zversion) rc=zmlbicgstabr(neqns, type, symmetryflag, mtxA, frontmtx, mtxQ, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); else rc=mlbicgstabr(neqns, type, symmetryflag, mtxA, frontmtx, mtxQ, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); DenseMtx_free(mtxQ) ; break; case MLBiCGStabL : mtxQ = DenseMtx_new() ; DenseMtx_init(mtxQ, type, 0, -1, neqns, Ik, 1, neqns) ; Drand_setUniform(&drand, 0.0, 1.0) ; DenseMtx_fillRandomEntries(mtxQ, &drand) ; if (zversion) rc=zmlbicgstabl(neqns, type, symmetryflag, mtxA, frontmtx, mtxQ, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); else rc=mlbicgstabl(neqns, type, symmetryflag, mtxA, frontmtx, mtxQ, mtxZ, mtxB, itermax, conv_tol, msglvl, msgFile); DenseMtx_free(mtxQ) ; break; case BGMRESR: if (zversion) fprintf(msgFile, "\n\n *** BGMRESR complex version is not available " "at this moment. ") ; else rc=bgmresr(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, iterout, itermax, &nouter, &ninner, conv_tol, msglvl, msgFile); break; case BGMRESL: if (zversion) fprintf(msgFile, "\n\n *** BGMRESR complex version is not available " "at this moment. ") ; else rc=bgmresl(neqns, type, symmetryflag, mtxA, frontmtx, mtxZ, mtxB, iterout, itermax, &nouter, &ninner, conv_tol, msglvl, msgFile); break; default: fprintf(msgFile, "\n\n *** Invalid method number ") ; } MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : solve the system", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } /* ------------------------------------------------------------- permute the computed solution back into the original ordering ------------------------------------------------------------- */ MARKTIME(t1) ; DenseMtx_permuteRows(mtxZ, newToOldIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute solution", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } /* ------------- save solution ------------- */ if ( strcmp(slnFileName, "none") != 0 ) { DenseMtx_writeToFile(mtxZ, slnFileName) ; } /* ----------------- compute the error ----------------- */ if (!strcmp(rhsFileName, "none")) { DenseMtx_sub(mtxZ, mtxX) ; if (method[k] <8) { mtxQ = DenseMtx_new() ; DenseMtx_init(mtxQ, type, 0, -1, neqns, 1, 1, neqns) ; rc=DenseMtx_initAsSubmatrix (mtxQ, mtxZ, 0, neqns-1, 0, 0); fprintf(msgFile, "\n\n maxabs error = %12.4e", DenseMtx_maxabs(mtxQ)) ; DenseMtx_free(mtxQ) ; } else fprintf(msgFile, "\n\n maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } if ( msglvl > 1 ) SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; } fprintf(msgFile, "\n--------- End of Method %d -------\n",method[k]) ; } /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(mtxZ) ; end_front: ChvManager_free(chvmanager) ; SubMtxManager_free(mtxmanager) ; FrontMtx_free(frontmtx) ; IVL_free(symbfacIVL) ; IV_free(oldToNewIV) ; IV_free(newToOldIV) ; end_tree: ETree_free(frontETree) ; end_init: DenseMtx_free(mtxB) ; DenseMtx_free(mtxX) ; end_read: InpMtx_free(mtxA) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- InpMtx_readFromAIJ2file reads in an AIJ2 matrix from file and converts to InpMtx object. created -- 98dec01, jwu ------------------------------------------------------------------- */ int InpMtx_readFromAIJ2file(InpMtx *mtxA, char *srcFileName) { FILE *srcFile; int rc, nrow, ncol, irow, icol, jrow, jcol, ient, nentInRow; double ent; /* ---------------------------- open the input file and read #rows #columns ---------------------------- */ if ( (srcFile = fopen(srcFileName, "r")) == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_readFromAIJ2file" "\n unable to open file %s\n", srcFileName) ; return(-1) ; } rc = fscanf(srcFile, "%d %d", &nrow, &ncol) ; if ( rc != 2 ) { fprintf(stderr, "\n fatal error in InpMtx_readFromAIJ2file" "\n %d of 2 fields read on first line of file %s", rc, srcFileName) ; return(-1) ; } /* -------------------------------------------------- initialize the object set coordType = INPMTX_BY_ROWS --> row coordinates -------------------------------------------------- */ InpMtx_init(mtxA, INPMTX_BY_ROWS, SPOOLES_REAL, 10*nrow, 0) ; /* ------------------------------------------------- read in the entries and load them into the object ------------------------------------------------- */ ient=0; for ( irow = 0 ; irow < nrow ; irow++ ) { rc = fscanf(srcFile, "%d %d", &jrow, &nentInRow) ; if ( rc != 2 ) { fprintf(stderr, "\n fatal error in InpMtx_readFromAIJ2file" "\n %d of 2 fields read on entry %d of file %s", rc, ient, srcFileName) ; return(-1) ; } for ( icol = 0 ; icol < nentInRow ; icol++ ) { rc = fscanf(srcFile, "%d %lf", &jcol, &ent) ; if ( rc != 2 ) { fprintf(stderr, "\n fatal error in InpMtx_readFromAIJ2file" "\n %d of 2 fields read on entry %d of file %s", rc, ient, srcFileName) ; return(-1) ; } InpMtx_inputRealEntry(mtxA, jrow-1, jcol-1, ent) ; ient++; } } /* ----------------------------- sort and compress the entries ----------------------------- */ InpMtx_changeStorageMode(mtxA, 3) ; fclose(srcFile); return(1) ; } /*--------------------------------------------------------------------*/ /* createGraph.c */ /*--------------------------------------------------------------------*/ int InpMtx_createGraph (InpMtx *mtxA, Graph *graph) /* ---------------------------------------------------- read in a InpMtx object and create the Graph object created -- 97feb14, cca ---------------------------------------------------- */ { int count, msglvl, nvtx, rc ; IVL *adjIVL ; InpMtx_changeStorageMode(mtxA, 3) ; nvtx = 1 + IV_max(&mtxA->ivec1IV) ; count = 1 + IV_max(&mtxA->ivec2IV) ; if ( nvtx < count ) { nvtx = count ; } /* ------------------------------------ create the full adjacency IVL object ------------------------------------ */ adjIVL = InpMtx_fullAdjacency(mtxA) ; /* --------------------- fill the Graph object --------------------- */ Graph_init2(graph, 0, nvtx, 0, adjIVL->tsize, nvtx, adjIVL->tsize, adjIVL, NULL, NULL) ; return(1) ; } /*--------------------------------------------------------------------*/ l > 2 ) { fprintf(msgFile, "\n\n front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } /* ------------------------------ post-procesIter/drivers/test_colCopy.c010064400020550007177000000074050663576537200173160ustar00clevecompmath00000400000006/* test_colCopy.c */ #include "../Iter.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------- test the DenseMtx_colCopy routine. copy column icol of a DenseMtx A to column jcol of a DenseMtx A. Ai->Aj. (Aj could be replaced by Bj, j-th column of another DenseMtx B.) when msglvl > 1, the output of this program can be fed into Matlab to check for errors created -- 98dec07, jwu ----------------------------------------------- */ { DenseMtx *A ; double t1, t2; Drand *drand ; FILE *msgFile ; int inc1, inc2, icol, jcol, msglvl, nrow, ncol, rc, seed, type ; if ( argc != 11 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow ncol inc1 inc2 " "\n icol, jcol, seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- entries type" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- # of rows " "\n ncol -- # of columns " "\n inc1 -- row increment " "\n inc2 -- column increment " "\n icol -- i-th column of A " "\n jcol -- j-th column of A " "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; nrow = atoi(argv[4]) ; ncol = atoi(argv[5]) ; inc1 = atoi(argv[6]) ; inc2 = atoi(argv[7]) ; if ( type < 1 || type > 2 || nrow < 0 || ncol < 0 || inc1 < 1 || inc2 < 1 ) { fprintf(stderr, "\n fatal error, type %d, nrow %d, ncol %d, inc1 %d, inc2 %d", type, nrow, ncol, inc1, inc2) ; exit(-1) ; } icol = atoi(argv[8]) ; jcol = atoi(argv[9]) ; seed = atoi(argv[10]) ; fprintf(msgFile, "\n\n %% %s :" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% nrow = %d" "\n %% ncol = %d" "\n %% inc1 = %d" "\n %% inc2 = %d" "\n %% icol = %d" "\n %% jcol = %d" "\n %% seed = %d" "\n", argv[0], msglvl, argv[2], type, nrow, ncol, inc1, inc2, icol, jcol, seed) ; /* ---------------------------- initialize the matrix object ---------------------------- */ MARKTIME(t1) ; A = DenseMtx_new() ; DenseMtx_init(A, type, 0, 0, nrow, ncol, inc1, inc2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; MARKTIME(t1) ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; seed++ ; Drand_setUniform(drand, -1.0, 1.0) ; DenseMtx_fillRandomEntries(A, drand) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to fill matrix with random numbers", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n matrix A") ; DenseMtx_writeForHumanEye(A, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n %% matrix A") ; fprintf(msgFile, "\n nrow = %d ;", nrow) ; fprintf(msgFile, "\n ncol = %d ;", ncol) ; fprintf(msgFile, "\n"); DenseMtx_writeForMatlab(A, "A", msgFile) ; } /* ---------------- copying ... ---------------- */ DenseMtx_colCopy(A, jcol, A, icol); if ( msglvl > 1 ) { fprintf(msgFile, "\n\nAfter copying A(:,%d) to A(:,%d):",icol+1,jcol+1); DenseMtx_writeForMatlab(A, "A", msgFile) ; fprintf(msgFile, "\n\n"); fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(A) ; Drand_free(drand) ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/drivers/test_colDotProduct.c010064400020550007177000000076410663576537200204750ustar00clevecompmath00000400000006/* test_colDotProduct.c */ #include "../Iter.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------- test the DenseMtx_colDotProduct routine. value = x^H * y, where x and y are i-th and j-th columns of a DenseMtx A respectively. (In real application, y could be from another DenseMtx.) when msglvl > 1, the output of this program can be fed into Matlab to check for errors created -- 98dec03, jwu ----------------------------------------------- */ { DenseMtx *A ; double t1, t2, value[2] ; Drand *drand ; FILE *msgFile ; int inc1, inc2, icol, jcol, msglvl, nrow, ncol, rc, seed, type ; if ( argc != 11 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow ncol inc1 inc2 " "\n icol, jcol, seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- entries type" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- # of rows " "\n ncol -- # of columns " "\n inc1 -- row increment " "\n inc2 -- column increment " "\n icol -- vector x: i-th column of A " "\n jcol -- vector y: j-th column of A " "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; nrow = atoi(argv[4]) ; ncol = atoi(argv[5]) ; inc1 = atoi(argv[6]) ; inc2 = atoi(argv[7]) ; if ( type < 1 || type > 2 || nrow < 0 || ncol < 0 || inc1 < 1 || inc2 < 1 ) { fprintf(stderr, "\n fatal error, type %d, nrow %d, ncol %d, inc1 %d, inc2 %d", type, nrow, ncol, inc1, inc2) ; exit(-1) ; } icol = atoi(argv[8]) ; jcol = atoi(argv[9]) ; seed = atoi(argv[10]) ; fprintf(msgFile, "\n\n %% %s :" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% nrow = %d" "\n %% ncol = %d" "\n %% inc1 = %d" "\n %% inc2 = %d" "\n %% icol = %d" "\n %% jcol = %d" "\n %% seed = %d" "\n", argv[0], msglvl, argv[2], type, nrow, ncol, inc1, inc2, icol, jcol, seed) ; /* ---------------------------- initialize the matrix object ---------------------------- */ MARKTIME(t1) ; A = DenseMtx_new() ; DenseMtx_init(A, type, 0, 0, nrow, ncol, inc1, inc2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; MARKTIME(t1) ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; seed++ ; Drand_setUniform(drand, -1.0, 1.0) ; DenseMtx_fillRandomEntries(A, drand) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to fill matrix with random numbers", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n matrix A") ; DenseMtx_writeForHumanEye(A, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n %% matrix A") ; fprintf(msgFile, "\n nrow = %d ;", nrow) ; fprintf(msgFile, "\n ncol = %d ;", ncol) ; fprintf(msgFile, "\n"); DenseMtx_writeForMatlab(A, "A", msgFile) ; } /* ---------------- compute the inner product ---------------- */ DenseMtx_colDotProduct(A, icol, A, jcol, value); if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Dot product A(:,%d)^H * A(:,%d):",icol+1, jcol+1) ; fprintf(msgFile, "\n real = %e", value[0]) ; if (DENSEMTX_IS_COMPLEX(A)) fprintf(msgFile, "\n imag = %e", value[1]); fprintf(msgFile, "\n"); fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(A) ; Drand_free(drand) ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/drivers/test_colGenAxpy.c010064400020550007177000000103770663576537200177610ustar00clevecompmath00000400000006/* test_colGenAxpy.c */ #include "../Iter.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------- test the DenseMtx_colGenAxpy routine. x = alpha*x + beta*y, where x and y are i-th and j-th columns of a DenseMtx A respectively, and alpha and beta are scalars. (In real application, y could be from another DenseMtx.) when msglvl > 1, the output of this program can be fed into Matlab to check for errors created -- 98dec03, jwu ----------------------------------------------- */ { DenseMtx *A ; double t1, t2; double alpha[2], beta[2]; Drand *drand ; FILE *msgFile ; int inc1, inc2, icol, jcol, msglvl, nrow, ncol, rc, seed, type ; if ( argc != 15 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow ncol inc1 inc2 icol jcol" "\n ralpha ialpha rbeta ibeta seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- entries type" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- # of rows " "\n ncol -- # of columns " "\n inc1 -- row increment " "\n inc2 -- column increment " "\n icol -- vector x: i-th column of A " "\n jcol -- vector y: j-th column of A " "\n ralpha -- real(alpha)" "\n ialpha -- imag(alpha)" "\n rbeta -- real(beta)" "\n ibeta -- imag(beta)" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; nrow = atoi(argv[4]) ; ncol = atoi(argv[5]) ; inc1 = atoi(argv[6]) ; inc2 = atoi(argv[7]) ; if ( type < 1 || type > 2 || nrow < 0 || ncol < 0 || inc1 < 1 || inc2 < 1 ) { fprintf(stderr, "\n fatal error, type %d, nrow %d, ncol %d, inc1 %d, inc2 %d", type, nrow, ncol, inc1, inc2) ; exit(-1) ; } icol = atoi(argv[8]) ; jcol = atoi(argv[9]) ; alpha[0] = atof (argv[10]); alpha[1] = atof (argv[11]); beta[0] = atof (argv[12]); beta[1] = atof (argv[13]); seed = atoi(argv[14]) ; fprintf(msgFile, "\n\n %% %s :" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% nrow = %d" "\n %% ncol = %d" "\n %% inc1 = %d" "\n %% inc2 = %d" "\n %% icol = %d" "\n %% jcol = %d" "\n %% ralpha = %e" "\n %% ialpha = %e" "\n %% rbeta = %e" "\n %% ibeta = %e" "\n %% seed = %d" "\n", argv[0], msglvl, argv[2], type, nrow, ncol, inc1, inc2, icol, jcol, alpha[0], alpha[1], beta[0], beta[1], seed) ; /* ---------------------------- initialize the matrix object ---------------------------- */ MARKTIME(t1) ; A = DenseMtx_new() ; DenseMtx_init(A, type, 0, 0, nrow, ncol, inc1, inc2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; MARKTIME(t1) ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; seed++ ; Drand_setUniform(drand, -1.0, 1.0) ; DenseMtx_fillRandomEntries(A, drand) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to fill matrix with random numbers", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n matrix A") ; DenseMtx_writeForHumanEye(A, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n %% matrix A") ; fprintf(msgFile, "\n nrow = %d ;", nrow) ; fprintf(msgFile, "\n ncol = %d ;", ncol) ; fprintf(msgFile, "\n"); DenseMtx_writeForMatlab(A, "A", msgFile) ; } /* ---------------- compute the inner product ---------------- */ DenseMtx_colGenAxpy(alpha, A, icol, beta, A, jcol); if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% A(:,%d)=alpha*A(:,%d)+beta*A(:,%d):", icol+1,icol+1,jcol+1) ; DenseMtx_writeForMatlab(A, "A", msgFile) ; fprintf(msgFile, "\n"); } /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(A) ; Drand_free(drand) ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/drivers/test_frobNorm.c010064400020550007177000000065650663576537200175000ustar00clevecompmath00000400000006/* test_frobNorm.c */ #include "../Iter.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------- test the DenseMtx_frobNorm routine. when msglvl > 1, the output of this program can be fed into Matlab to check for errors created -- 98dec03, ycp ----------------------------------------------- */ { DenseMtx *A ; double t1, t2, value ; Drand *drand ; FILE *msgFile ; int inc1, inc2, msglvl, nrow, ncol, seed, type ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow ncol inc1 inc2 " "\n , seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- entries type" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- # of rows " "\n ncol -- # of columns " "\n inc1 -- row increment " "\n inc2 -- column increment " "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; nrow = atoi(argv[4]) ; ncol = atoi(argv[5]) ; inc1 = atoi(argv[6]) ; inc2 = atoi(argv[7]) ; if ( type < 1 || type > 2 || nrow < 0 || ncol < 0 || inc1 < 1 || inc2 < 1 ) { fprintf(stderr, "\n fatal error, type %d, nrow %d, ncol %d, inc1 %d, inc2 %d", type, nrow, ncol, inc1, inc2) ; exit(-1) ; } seed = atoi(argv[8]) ; fprintf(msgFile, "\n\n %% %s :" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% nrow = %d" "\n %% ncol = %d" "\n %% inc1 = %d" "\n %% inc2 = %d" "\n %% seed = %d" "\n", argv[0], msglvl, argv[2], type, nrow, ncol, inc1, inc2, seed) ; /* ---------------------------- initialize the matrix object ---------------------------- */ MARKTIME(t1) ; A = DenseMtx_new() ; DenseMtx_init(A, type, 0, 0, nrow, ncol, inc1, inc2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; MARKTIME(t1) ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; seed++ ; Drand_setUniform(drand, -1.0, 1.0) ; DenseMtx_fillRandomEntries(A, drand) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to fill matrix with random numbers", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n matrix A") ; DenseMtx_writeForHumanEye(A, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n %% matrix A") ; fprintf(msgFile, "\n nrow = %d ;", nrow) ; fprintf(msgFile, "\n ncol = %d ;", ncol) ; fprintf(msgFile, "\n"); DenseMtx_writeForMatlab(A, "A", msgFile) ; } /* -------------------------- compute the frobenius norm -------------------------- */ value = DenseMtx_frobNorm(A); if ( msglvl > 1 ) { fprintf(msgFile, "\n %% Frobenius Norm = %e", value) ; fprintf(msgFile, "\n"); fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(A) ; Drand_free(drand) ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/drivers/test_mmm.c010064400020550007177000000161340664026433100164540ustar00clevecompmath00000400000006/* test_DenseMtx_mmm.c */ #include "../Iter.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------- test the DenseMtx_mmm routine. C = alpha*A*B + beta*C, where A, B and C are DenseMtx. alpha and beta are scalars. when msglvl > 1, the output of this program can be fed into Matlab to check for errors created -- 98dec14, ycp ------------------------------------------------------- */ { DenseMtx *mtxA, *mtxB, *mtxC; double t1, t2, value[2] = {1.0, 1.0} ; Drand *drand ; FILE *msgFile ; int i, j, k, msglvl, nrow, nk, ncol, cnrow, cncol, seed, type ; int ainc1, ainc2, binc1, binc2, cinc1, cinc2; double alpha[2], beta[2], one[2] = {1.0, 0.0}, rvalue; char A_opt[1]=" ", B_opt[1]=" "; if ( argc != 20 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow nk ncol ainc1 ainc2 binc1 " "\n binc2 cinc1 cinc2 A_opt B_opt ralpha ialpha rbeta ibeta seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- entries type" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- # of rows of mtxA " "\n nk -- # of columns of mtxA " "\n ncol -- # of columns of mtxB " "\n ainc1 -- A row increment " "\n ainc2 -- A column increment " "\n binc1 -- B row increment " "\n binc2 -- B column increment " "\n binc1 -- C row increment " "\n binc2 -- C column increment " "\n A_opt -- A option " "\n B_opt -- B option " "\n ralpha -- real(alpha)" "\n ialpha -- imag(alpha)" "\n rbeta -- real(beta)" "\n ibeta -- imag(beta)" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; nrow = atoi(argv[4]) ; nk = atoi(argv[5]) ; ncol = atoi(argv[6]) ; ainc1= atoi(argv[7]) ; ainc2= atoi(argv[8]) ; binc1= atoi(argv[9]) ; binc2= atoi(argv[10]) ; cinc1= atoi(argv[11]) ; cinc2= atoi(argv[12]) ; if ( type < 1 || type > 2 || nrow < 0 || ncol < 0 || ainc1 < 1 || ainc2 < 1 || binc1 < 1 || binc2 < 1 ) { fprintf(stderr, "\n fatal error, type %d, nrow %d, ncol %d, ainc1 %d, ainc2 %d" ", binc1 %d, binc2 %d", type, nrow, ncol, ainc1, ainc2, binc1, binc2) ; exit(-1) ; } A_opt[0] = *argv[13] ; B_opt[0] = *argv[14] ; alpha[0]= atof (argv[15]); alpha[1]= atof (argv[16]); beta[0] = atof (argv[17]); beta[1] = atof (argv[18]); seed = atoi (argv[19]) ; fprintf(msgFile, "\n\n %% %s :" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% nrow = %d" "\n %% nk = %d" "\n %% ncol = %d" "\n %% ainc1 = %d" "\n %% ainc2 = %d" "\n %% binc1 = %d" "\n %% binc2 = %d" "\n %% cinc1 = %d" "\n %% cinc2 = %d" "\n %% a_opt = %c" "\n %% b_opt = %c" "\n %% ralpha = %e" "\n %% ialpha = %e" "\n %% rbeta = %e" "\n %% ibeta = %e" "\n %% seed = %d" "\n", argv[0], msglvl, argv[2], type, nrow, nk, ncol, ainc1, ainc2, binc1, binc2, cinc1, cinc2, A_opt[0], B_opt[0], alpha[0], alpha[1], beta[0], beta[1], seed) ; /* ---------------------------- initialize the matrix object ---------------------------- */ MARKTIME(t1) ; mtxA = DenseMtx_new() ; DenseMtx_init(mtxA, type, 0, 0, nrow, nk, ainc1, ainc2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; MARKTIME(t1) ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; seed++ ; Drand_setUniform(drand, -1.0, 1.0) ; DenseMtx_fillRandomEntries(mtxA, drand) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to fill matrix A with random numbers", t2 - t1) ; MARKTIME(t1) ; mtxB = DenseMtx_new() ; DenseMtx_init(mtxB, type, 0, 0, nk, ncol, binc1, binc2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; MARKTIME(t1) ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; seed++ ; Drand_setUniform(drand, -1.0, 1.0) ; DenseMtx_fillRandomEntries(mtxB, drand) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to fill matrix B with random numbers", t2 - t1) ; cnrow = nrow; cncol = ncol; MARKTIME(t1) ; mtxC = DenseMtx_new() ; if ( A_opt[0] == 't' || A_opt[0] == 'T' || A_opt[0] == 'c' || A_opt[0] == 'C') { cnrow = nk; } if ( B_opt[0] == 't' || B_opt[0] == 'T' || B_opt[0] == 'c' || B_opt[0] == 'C') { cncol = nk; } if ( cinc1 == 1 && cinc2 == nrow ){ /* stored by column */ cinc1 = 1; cinc2 = cnrow; } else { /* stored by row */ cinc1 = cncol; cinc2 = 1; } DenseMtx_init(mtxC, type, 0, 0, cnrow, cncol, cinc1, cinc2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; MARKTIME(t1) ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; seed++ ; Drand_setUniform(drand, -1.0, 1.0) ; DenseMtx_fillRandomEntries(mtxC, drand) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to fill matrix C with random numbers", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n matrix A") ; DenseMtx_writeForHumanEye(mtxA, msgFile) ; fprintf(msgFile, "\n matrix B") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fprintf(msgFile, "\n matrix C") ; DenseMtx_writeForHumanEye(mtxC, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% beta = (%f, %f)", beta[0], beta[1]) ; fprintf(msgFile, "\n %% alpha = (%f, %f)\n", alpha[0], alpha[1]) ; fprintf(msgFile, "\n %% matrix A") ; fprintf(msgFile, "\n nrow = %d ;", nrow) ; fprintf(msgFile, "\n ncol = %d ;", nk) ; DenseMtx_writeForMatlab(mtxA, "A", msgFile) ; fprintf(msgFile, "\n"); fprintf(msgFile, "\n %% matrix B") ; fprintf(msgFile, "\n nrow = %d ;", nk) ; fprintf(msgFile, "\n ncol = %d ;", ncol) ; DenseMtx_writeForMatlab(mtxB, "B", msgFile) ; fprintf(msgFile, "\n"); fprintf(msgFile, "\n %% matrix C") ; fprintf(msgFile, "\n nrow = %d ;", cnrow) ; fprintf(msgFile, "\n ncol = %d ;", cncol) ; DenseMtx_writeForMatlab(mtxC, "C", msgFile) ; } /* -------------------------- performs the matrix-matrix operations C = alpha*(A)*(B) + beta*C -------------------------- */ DenseMtx_mmm(A_opt, B_opt, &beta, mtxC, &alpha, mtxA, mtxB); if ( msglvl > 1 ) { fprintf(msgFile, "\n"); fprintf(msgFile, "\n %% *** Output matrix C ***") ; fprintf(msgFile, "\n nrow = %d ;", cnrow) ; fprintf(msgFile, "\n ncol = %d ;", cncol) ; DenseMtx_writeForMatlab(mtxC, "C", msgFile) ; fprintf(msgFile, "\n"); fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(mtxA) ; DenseMtx_free(mtxB) ; DenseMtx_free(mtxC) ; Drand_free(drand) ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/drivers/test_twoNormOfColumn.c010064400020550007177000000067760663576537200210300ustar00clevecompmath00000400000006/* test__twoNormOfColumn.c */ #include "../Iter.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------- test the DenseMtx_twoNormOfColumn routine. when msglvl > 1, the output of this program can be fed into Matlab to check for errors created -- 98dec03, ycp ----------------------------------------------- */ { DenseMtx *A ; double t1, t2, value ; Drand *drand ; FILE *msgFile ; int inc1, inc2, jcol, msglvl, nrow, ncol, seed, type ; if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow ncol inc1 inc2 " "\n , jcol, seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- entries type" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- # of rows " "\n ncol -- # of columns " "\n inc1 -- row increment " "\n inc2 -- column increment " "\n jcol -- vector x: j-th column of A " "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; nrow = atoi(argv[4]) ; ncol = atoi(argv[5]) ; inc1 = atoi(argv[6]) ; inc2 = atoi(argv[7]) ; if ( type < 1 || type > 2 || nrow < 0 || ncol < 0 || inc1 < 1 || inc2 < 1 ) { fprintf(stderr, "\n fatal error, type %d, nrow %d, ncol %d, inc1 %d, inc2 %d", type, nrow, ncol, inc1, inc2) ; exit(-1) ; } jcol = atoi(argv[8]) ; seed = atoi(argv[9]) ; fprintf(msgFile, "\n\n %% %s :" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% nrow = %d" "\n %% ncol = %d" "\n %% inc1 = %d" "\n %% inc2 = %d" "\n %% jcol = %d" "\n %% seed = %d" "\n", argv[0], msglvl, argv[2], type, nrow, ncol, inc1, inc2, jcol, seed) ; /* ---------------------------- initialize the matrix object ---------------------------- */ MARKTIME(t1) ; A = DenseMtx_new() ; DenseMtx_init(A, type, 0, 0, nrow, ncol, inc1, inc2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize matrix object", t2 - t1) ; MARKTIME(t1) ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; seed++ ; Drand_setUniform(drand, -1.0, 1.0) ; DenseMtx_fillRandomEntries(A, drand) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to fill matrix with random numbers", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n matrix A") ; DenseMtx_writeForHumanEye(A, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n %% matrix A") ; fprintf(msgFile, "\n nrow = %d ;", nrow) ; fprintf(msgFile, "\n ncol = %d ;", ncol) ; fprintf(msgFile, "\n"); DenseMtx_writeForMatlab(A, "A", msgFile) ; } /* -------------------------- compute the frobenius norm -------------------------- */ value = DenseMtx_twoNormOfColumn(A,jcol); if ( msglvl > 1 ) { fprintf(msgFile, "\n %% Two Norm = %e", value) ; fprintf(msgFile, "\n"); fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(A) ; Drand_free(drand) ; return(1) ; } /*--------------------------------------------------------------------*/ Iter/doc/004275500020550007177000000000000665315072600135605ustar00clevecompmath00000400000006Iter/doc/proto.tex010064400020550007177000000447650664025526500154600ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Iter} methods} \label{section:Iter:proto} \par This section contains brief descriptions including prototypes of all methods found in the {\tt Iter} source directory. \par % % in util.c % \subsection{Utility methods} \label{subsection:Iter:proto:utility} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} double DenseMtx_frobNorm ( DenseMtx *mtx ) ; \end{verbatim} \index{DenseMtx_frobNorm@{\tt DenseMtx\_frobNorm()}} \par This method returns the Frobenius norm of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double DenseMtx_twoNormOfColumn ( DenseMtx *mtx, int jcol ) ; \end{verbatim} \index{DenseMtx_twoNormOfColumn@{\tt DenseMtx\_twoNormOfColumn()}} \par This method returns the two-norm of column {\tt jcol} of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or {\tt jcol} is not in {\tt [0,ncol-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_colCopy ( DenseMtx *mtxB, int jcol, DenseMtx *mtxA, int icol ) ; \end{verbatim} \index{DenseMtx_colCopy@{\tt DenseMtx\_colCopy()}} \par This method copies the column {\tt icol} of the matrix {\tt mtxA} to the column {\tt jcol} of the matrix {\tt mtxB}. \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} is {\tt NULL}, {\tt jcol} is not in {\tt [0,ncolB-1]}, or {\tt icol} is not in {\tt [0,ncolA-1]} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_colDotProduct ( DenseMtx *mtxA, int icol, DenseMtx *mtxB, int jcol, double *prod ) ; \end{verbatim} \index{DenseMtx_colDotProduct@{\tt DenseMtx\_colDotProduct()}} \par This method computes dot product of column {\tt icol} of the matrix {\tt mtxA} and column {\tt jcol} of the matrix {\tt mtxB}. Note that the column {\tt icol} of the matrix {\tt mtxA} will be transported and conjugated for complex entries. \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} is {\tt NULL}, {\tt jcol} is not in {\tt [0,ncolB-1]}, or {\tt icol} is not in {\tt [0,ncolA-1]} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_colGenAxpy ( double *alpha, DenseMtx *mtxA, int icol, double *beta, DenseMtx *mtxB, int jcol ) ; \end{verbatim} \index{DenseMtx_colGenAxpy@{\tt DenseMtx\_colGenAxpy()}} \par This method replaces column {\tt icol} of the matrix {\tt mtxA} by {\tt alpha} times itself plus {\tt beta} times column {\tt jcol} of {\tt mtxB}. \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} is {\tt NULL}, {\tt jcol} is not in {\tt [0,ncolB-1]}, or {\tt icol} is not in {\tt [0,ncolA-1]} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int DenseMtx_mmm ( char *A_opt, char *B_opt, double *beta, DenseMtx *mtxC, double *alpha, DenseMtx *mtxA, DenseMtx *mtxB ); \end{verbatim} \index{DenseMtx_mmm@{\tt DenseMtx\_mmm()}} This method computes the matrix-matrix multiplication $C := \beta C + \alpha AB$, where $A$, $B$ and $C$ are found in the {\tt C DenseMtx} object, $\beta$ and $\alpha$ are real or complex in {\tt beta[]} and {\tt alpha[]}. If any of the input objects are {\tt NULL}, an error message is printed and the program exits. {\tt A}, {\tt B} and {\tt C} must all be real or all be complex. When {\tt A and \tt B} are real, then $\alpha$ = {\tt alpha[0]}. When {\tt A and \tt B} are complex, then $\alpha$ = {\tt alpha[0]} + i* {\tt alpha[1]}. When {\tt C} is real, then $\beta$ = {\tt beta[0]}. When {\tt C} is complex, then $\beta$ = {\tt beta[0]} + i* {\tt beta[1]}. This means that one cannot call the method with a constant as the third and fifth parameter, e.g., {\tt DenseMtx\_mmm(a\_opt, b\_opt, beta, C, alpha, A, B)}, for this may result in a segmentation violation. The values of $\alpha$ and $\beta$ must be loaded into an array of length 1 or 2 . \par \noindent {\it Error checking:} If {\tt beta}, {\tt alpha}, {\tt C}, {\tt A}, {\tt B} are {\tt NULL}, or if {\tt C}, {\tt A} and {\tt B} do not have the same data type ({\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}), or if {\tt A\_opt} or {\tt B\_opt} is invalid, or the number of column of {\tt A} and the number of row of {\tt B} is not match, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_solveOneColumn ( FrontMtx *frontmtx, DenseMtx *solmtx, int jcol, DenseMtx *rhsmtx, int icol, SubMtxManager *mtxmanager, double cpus[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_solveOneColumn@{\tt FrontMtx\_solveOneColumn()}} \par This method is used to solve one of three linear systems of equations --- $(U^T + I)D(I + U) X = B$, $(U^H + I)D(I + U) X = B$ or $(L + I)D(I + U) X = B$. Entries of $B$ are read from column {\tt icol} of {\tt rhsmtx} and entries of $X$ are written to column {\tt jcol} of {\tt solmtx}. Therefore, {\tt rhsmtx} and {\tt solmtx} can be the same object. (Note, this does not hold true for an MPI factorization with pivoting.) The {\tt mtxmanager} object manages the working storage using the solve. On return the {\tt cpus[]} vector is filled with the following. \begin{itemize} \item {\tt cpus[0]} --- set up the solves \item {\tt cpus[1]} --- fetch right hand side and store solution \item {\tt cpus[2]} --- forward solve \item {\tt cpus[3]} --- diagonal solve \item {\tt cpus[4]} --- backward solve \item {\tt cpus[5]} --- total time in the method. \end{itemize} \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt rhsmtx} or {\tt cpus} is {\tt NULL}, or if {\tt msglvl} $>$ 0 and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %======================================================================== \end{enumerate} % % iterative methods % \subsection{Iterative methods} A collection of iterative methods is provided to solve a sparse linear system $AX=B$, where $A$ is an {\tt InpMtx} object and $X$ and $B$ are {\tt DenseMtx} objects. This includes left and right preconditioning BiCGStab, MLBiCGStab, TFQMR, PCG, and BGMRES. All methods have similar input arguments: \par \begin{itemize} \item {\tt n\_matrixSize} is order of the matrix $A$. \item {\tt type} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item The {\tt symmetryflag} parameter specifies the symmetry of the matrix $A$. \begin{itemize} \item {\tt type = 0 (SPOOLES\_SYMMETRIC)} for $A$ real or complex symmetric, \item {\tt type = 1 (SPOOLES\_HERMITIAN)} for $A$ complex Hermitian, \item {\tt type = 2 (SPOOLES\_NONSYMMETRIC)} for $A$ real or complex nonsymmetric. \end{itemize} \item {\tt mtxA} is the matrix $A$. \item {\tt Precond} is the preconditioner. \item {\tt mtxX} is the solution vectors $X$ saved as a {\tt DenseMtx} object. \item {\tt mtxB} is the right-hand-side vectors $B$ saved as a {\tt DenseMtx} object. \item {\tt itermax} is the maximum iterations number. \item {\tt convergetol} parameter is a stop criterion for iterative algorithms. \item {\tt maxninner} is the maximum number of inner iterations in BGMRES method. \item {\tt maxnouter} is the maximum number of outer iterations in BGMRES method. \item {\tt pninner} is last number of inner iterations executed in BGMRES method. \item {\tt pnouter} is last number of outer iterations executed in BGMRES method. \item {\tt mtxQ} is the starting vectors saved as a {\tt DenseMtx} object for MLBiCGStab method. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means most of the objects are written to the message file. \end{itemize} \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int bicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{bicgstabr@{\tt bicgstabr()}} \par This method solves a real linear system using BiCGStab algorithm with right preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int bicgstabl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{bicgstabl@{\tt bicgstabl()}} \par This method solves a real linear system using BiCGStab algorithm with left preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int mlbicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxQ, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{mlbicgstabr@{\tt mlbicgstabr()}} \par This method solves a real linear system using MLBiCGStab algorithm with right preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int mlbicgstabl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxQ, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{mlbicgstabl@{\tt mlbicgstabl()}} \par This method solves a real linear system using MLBiCGStab algorithm with left preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int tfqmrr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{tfqmrr@{\tt tfqmrr()}} \par This method solves a real linear system using TFQMR algorithm with right preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int tfqmrl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{tfqmrl@{\tt tfqmrl()}} \par This method solves a real linear system using TFQMR algorithm with left preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int pcgr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{pcgr@{\tt pcgr()}} \par This method solves a real symmetric position definite linear system using PCG algorithm with right preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int pcgl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{pcgl@{\tt pcgl()}} \par This method solves a real symmetric position definite linear system using PCG algorithm with left preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int bgmresr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int maxnouter, int maxninner, int *pnouter, int *pninner, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{pcgl@{\tt pcgl()}} \par This method solves a real linear system using BGMRES algorithm with right preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int bgmresl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int maxnouter, int maxninner, int *pnouter, int *pninner, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{pcgl@{\tt pcgl()}} \par This method solves a real linear system using BGMRES algorithm with left preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int zbicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{zbicgstabr@{\tt zbicgstabr()}} \par This method solves a complex linear system using BiCGStab algorithm with right preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int zbicgstabl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{zbicgstabl@{\tt zbicgstabl()}} \par This method solves a complex linear system using BiCGStab algorithm with left preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int zmlbicgstabr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxQ, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{zmlbicgstabr@{\tt zmlbicgstabr()}} \par This method solves a complex linear system using MLBiCGStab algorithm with right preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int zmlbicgstabl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxQ, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{zmlbicgstabl@{\tt zmlbicgstabl()}} \par This method solves a complex linear system using MLBiCGStab algorithm with left preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ztfqmrr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{ztfqmrr@{\tt ztfqmrr()}} \par This method solves a complex linear system using TFQMR algorithm with right preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ztfqmrl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{ztfqmrl@{\tt ztfqmrl()}} \par This method solves a complex linear system using TFQMR algorithm with left preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int zpcgr ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{zpcgr@{\tt zpcgr()}} \par This method solves a complex hermitian position definite linear system using PCG algorithm with right preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int zpcgl ( int n_matrixSize, int type, int symmetryflag, InpMtx *mtxA, FrontMtx *Precond, DenseMtx *mtxX, DenseMtx *mtxB, int itermax, double convergetol, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{zpcgl@{\tt zpcgl()}} \par This method solves a complex hermitian position definite linear system using PCG algorithm with left preconditioner. \par \noindent {\it Return codes:} {\tt 1} is a normal return. Otherwise, an error message is printed and the program exits. \end{enumerate} termax, Iter/doc/intro.tex010064400020550007177000000032600664343372000154260ustar00clevecompmath00000400000006\par \chapter{{\tt Iter}: Iterative Methods} \par {\tt Iter} is composed of 5 Krylov space iterative methods, PCG (Preconditioned Conjugate Gradients), BiCGStab, TFQMR, and BGMRES (Block GMRES), and MLBiCGStab. (For references, see top comments in codes.) The intent of these methods is to provide the user of {\bf SPOOLES} with an easy way to evaluate the effectiveness of the approximate factorizations belonging to the {\tt FrontMtx} object. To further facilitate the evaluation we have included a single call {\tt driver} that can run anyone of the methods we have provided with the type of preconditioner desired. For each iterative method we allow for left and right preconditioning. Also, for each method, except BGMRES, we allow for real or complex matrices. \par Because our intent was to provide a simple means to test the effectiveness of the preconditioners, these implementations are not parallel (neither shared or distributed memory). However, they were intentionally written to be consistent in style and form so that they could be easily adapted to exploit the parallelism that is in {\bf SPOOLES}. All iterative methods use the basic structure {\tt DenseMtx} for handling the intermediate vectors and performing the matrix multiplications and system solves. By doing this we have also anticipated the eventual movement to block iterative methods and the {\tt DenseMtx} structure can remain the basic structure. There are a few basic utilities that have been added, which are discribed in this section, upon which the iterative methods were built. These are provided to aid the experienced {\bf SPOOLES} user with an ability to develop additional iterative methods, as seen fit. GMRES (Block GMRES), and MLBiCGStab. (For references, see top comments in codes.) The intent of these methods is to provide the user of {\bf SPOOLES} with an easy way to evaluate the effectiveness of the approximate factorizations belonging to the {\tt FrontMtx} object. To further facilitate the evaluation we have included a singlIter/doc/main.tex010064400020550007177000000012360665065625600152310ustar00clevecompmath00000400000006% % main TeX file % % \documentstyle[leqno,11pt,twoside]{report} \documentclass[leqno,10pt,twoside]{report} \newcommand{\bnd}[1]{{\partial{#1}}} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Iter} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Iter} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} Iter/doc/makefile010064400020550007177000000000270663625707100152540ustar00clevecompmath00000400000006clean : - rm -f *.dvi Iter/doc/main.log010064400020550007177000000060420664343372400152050ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 2 JAN 1999 07:14 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. (intro.tex Chapter 1. Overfull \hbox (5.20291pt too wide) in paragraph at lines 4--15 \OT1/cmtt/m/n/10 Iter \OT1/cmr/m/n/10 is com-posed of 5 Krylov space it-er-a-ti ve meth-ods, PCG (Pre-con-di-tioned Con-ju-gate Gra-di-ents), BiCGStab, [] ) (dataStructure.tex LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 6. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 6. ) (proto.tex [1 ] LaTeX Font Info: Try loading font information for OMS+cmr on input line 143. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 143. [2] [3] [4] [5]) (drivers.tex [6] [7] [8] [9]) (main.ind [10] [11 ]) (main.aux) ) Here is how much of TeX's memory you used: 516 strings out of 10908 5150 string characters out of 72189 53681 words of memory out of 262141 3432 multiletter control sequences out of 9500 7575 words of font info for 28 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 23i,5n,21p,142b,427s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (11 pages, 37080 bytes). Iter/doc/main.idx010064400020550007177000000022530664343372400152100ustar00clevecompmath00000400000006\indexentry{DenseMtx_frobNorm@{\tt DenseMtx\_frobNorm()}}{1} \indexentry{DenseMtx_twoNormOfColumn@{\tt DenseMtx\_twoNormOfColumn()}}{2} \indexentry{DenseMtx_colCopy@{\tt DenseMtx\_colCopy()}}{2} \indexentry{DenseMtx_colDotProduct@{\tt DenseMtx\_colDotProduct()}}{2} \indexentry{DenseMtx_colGenAxpy@{\tt DenseMtx\_colGenAxpy()}}{2} \indexentry{DenseMtx_mmm@{\tt DenseMtx\_mmm()}}{2} \indexentry{FrontMtx_solveOneColumn@{\tt FrontMtx\_solveOneColumn()}}{2} \indexentry{bicgstabr@{\tt bicgstabr()}}{4} \indexentry{bicgstabl@{\tt bicgstabl()}}{4} \indexentry{mlbicgstabr@{\tt mlbicgstabr()}}{4} \indexentry{mlbicgstabl@{\tt mlbicgstabl()}}{4} \indexentry{tfqmrr@{\tt tfqmrr()}}{4} \indexentry{tfqmrl@{\tt tfqmrl()}}{4} \indexentry{pcgr@{\tt pcgr()}}{4} \indexentry{pcgl@{\tt pcgl()}}{4} \indexentry{pcgl@{\tt pcgl()}}{5} \indexentry{pcgl@{\tt pcgl()}}{5} \indexentry{zbicgstabr@{\tt zbicgstabr()}}{5} \indexentry{zbicgstabl@{\tt zbicgstabl()}}{5} \indexentry{zmlbicgstabr@{\tt zmlbicgstabr()}}{5} \indexentry{zmlbicgstabl@{\tt zmlbicgstabl()}}{5} \indexentry{ztfqmrr@{\tt ztfqmrr()}}{5} \indexentry{ztfqmrl@{\tt ztfqmrl()}}{5} \indexentry{zpcgr@{\tt zpcgr()}}{6} \indexentry{zpcgl@{\tt zpcgl()}}{6} Iter/doc/main.aux010064400020550007177000000014400664343372400152160ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt Iter}: Iterative Methods}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{1}} \newlabel{section:Iter:dataStructure}{{1.1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt Iter} methods}{1}} \newlabel{section:Iter:proto}{{1.2}{1}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Utility methods}{1}} \newlabel{subsection:Iter:proto:utility}{{1.2.1}{1}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Iterative methods}{3}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs}{6}} \newlabel{section:Iter:drivers}{{1.3}{6}} re}{{1.1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt Iter} methods}{1}} \newlabel{section:Iter:proto}{{1.2}{1}} \@writefile{toc}{\contentsline {subsection}{\numberline Iter/doc/drivers.tex010064400020550007177000000330440664026104100157440ustar00clevecompmath00000400000006\par \section{Driver programs} \label{section:Iter:drivers} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} test_colCopy msglvl msgFile type n1 n2 inc1 inc2 icol jcol seed \end{verbatim} This driver program generates a {\tt DenseMtx} object whose column {\tt icol} is copied to column {\tt jcol}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt DenseMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt type} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item {\tt n1} is the row dimension of the test matrix. \item {\tt n2} is the column dimension of the test matrix. \item {\tt inc1} is the row increment. \item {\tt inc2} is the column increment. \item {\tt icol} is the column number to be copied. $0\leq${\tt icol}$<${\tt n2}. \item {\tt jcol} is the column number to be replaced. $0\leq${\tt jcol}$<${\tt n2}. \item {\tt seed} parameter is random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_colDotProduct msglvl msgFile type n1 n2 inc1 inc2 icol jcol seed \end{verbatim} This driver program generates a {\tt DenseMtx} object object, and computes the dot product of column {\tt icol} and column {\tt jcol} of the matrix. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt DenseMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt type} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item {\tt n1} is the row dimension of the test matrix. \item {\tt n2} is the column dimension of the test matrix. \item {\tt inc1} is the row increment. \item {\tt inc2} is the column increment. \item {\tt icol} is the first column number. $0\leq${\tt icol}$<${\tt n2}. \item {\tt jcol} is the second column number. $0\leq${\tt jcol}$<${\tt n2}. \item {\tt seed} parameter is random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_colGenAxpy msglvl msgFile type n1 n2 inc1 inc2 icol jcol ralpha, ialpha, rbeta, ibeta, seed \end{verbatim} This driver program generates a {\tt DenseMtx} object whose column {\tt icol} is replaced by $\alpha$ times column {\tt icol} plus $\beta$ times column {\tt jcol}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt DenseMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt type} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item {\tt n1} is the row dimension of the test matrix. \item {\tt n2} is the column dimension of the test matrix. \item {\tt inc1} is the row increment. \item {\tt inc2} is the column increment. \item {\tt icol} is the column number to be replaced. $0\leq${\tt icol}$<${\tt n2}. \item {\tt jcol} is the column number to be added. $0\leq${\tt jcol}$<${\tt n2}. \item {\tt ralpha} is the real part of the scalar $\alpha$. \item {\tt ialpha} is the imaginary part of the scalar $\alpha$. \item {\tt rbeta} is the real part of the scalar $\beta$. \item {\tt ibeta} is the imaginary part of the scalar $\beta$. \item {\tt seed} parameter is random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_frobNorm msglvl msgFile type n1 n2 inc1 inc2 seed \end{verbatim} This driver program generates a {\tt DenseMtx} object and computes the Frobenius norm of this matrix. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt DenseMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt type} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item {\tt n1} is the row dimension of the test matrix. \item {\tt n2} is the column dimension of the test matrix. \item {\tt inc1} is the row increment. \item {\tt inc2} is the column increment. \item {\tt seed} parameter is random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_frobNorm msglvl msgFile type n1 n2 inc1 inc2 jcol seed \end{verbatim} This driver program generates a {\tt DenseMtx} object and computes two norm of column {\tt jcol} of this matrix. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt DenseMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt type} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item {\tt n1} is the row dimension of the test matrix. \item {\tt n2} is the column dimension of the test matrix. \item {\tt inc1} is the row increment. \item {\tt inc2} is the column increment. \item {\tt jcol} is the column number whose two norm is required. $0\leq${\tt jcol}$<${\tt n2}. \item {\tt seed} parameter is random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_DenseMtx_mmm msglvl msgFile type nrow nk ncol ainc1 ainc2 binc1 binc2 cinc1 cinc2 a_opt b_opt ralpha ialpha rbeta ibeta seed \end{verbatim} This driver program tests the matrix-matrix multiply method. The program generates {\tt DenseMtx} objects $A$, ,$B$ and $C$. It returns the matrix {\tt C} whose elements are replaced by $\beta$ times matrix {\tt C} plus $\alpha$ times matrix {\tt A} times matrix {\tt B}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt DenseMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt type} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item {\tt nrow} is the row dimension of the test matrix {\tt A}. \item {\tt nk} is the column dimension of the test matrix {\tt A} and the row dimension of the test matrix {\tt B}. \item {\tt ncol} is the column dimension of the test matrix {\tt B}. \item {\tt ainc1} is the row increment for the test matrix {\tt A}. \item {\tt ainc2} is the column increment for the test matrix {\tt A}. \item {\tt binc1} is the row increment for the test matrix {\tt B}. \item {\tt binc2} is the column increment for the test matrix {\tt B}. \item {\tt cinc1} is the row increment for the test matrix {\tt C}. \item {\tt cinc2} is the column increment for the test matrix {\tt C}. \item {\tt a\_opt} specifies the computation of the test matrix {\tt A} to be performed. {\tt "n"} or {\tt "N"} is No transpose. {\tt "t"} or {\tt "T"} is Transpose. {\tt "c"} or {\tt "C"} is Conjugate transpose. \item {\tt b\_opt} specifies the computation of the test matrix {\tt B} to be performed. {\tt "n"} or {\tt "N"} is No transpose. {\tt "t"} or {\tt "T"} is Transpose. {\tt "c"} or {\tt "C"} is Conjugate transpose. \item {\tt ralpha} is the real part of the scalar $\alpha$. \item {\tt ialpha} is the imaginary part of the scalar $\alpha$. \item {\tt rbeta} is the real part of the scalar $\beta$. \item {\tt ibeta} is the imaginary part of the scalar $\beta$. \item {\tt seed} parameter is random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} iter inFile \end{verbatim} This driver program reads required parameters from the {\tt inFile} to solve a sparse linear system $AX=B$, where $A$ is an {\tt InpMtx} object and $X$ and $B$ are {\tt DenseMtx} objects, using selected methods with left or right preconditioner. The preconditioner is obtained via applying frontal method to the matrix $A$. In the {\tt inFile}, the required parameters are in a layout as \begin{verbatim} srcMtxFormat srcMtxFile InpMtxFile ETreeFormat ETreeFile rhsFile slnFile msgFile msglvl seed nrhs Ik itermax iterout symmetryflag sparsityflag pivotingflag tau droptol convtol methods \end{verbatim} All comment lins should start with a start ({\tt *}) and the lines order of the required parameters should not be changed. \par \begin{itemize} \item {\tt srcMtxFormat} is the file format of source matrix $A$, {\tt 0} for InpMtx, {\tt 1} for HBF, and {\tt 2} for AIJ2. \item {\tt srcMtxFile} is the file name saved the source matrix $A$. \item {\tt InpMtxFile} is the file name to save InpMtx object if the original input matrix is in HBF or AIJ2 format. It should be with extension {\tt .inpmtxb} or {\tt .inpmtxf}. If {\tt InpMtxFile} is {\tt none}, the converted InpMtx object will not be written to file. \item {\tt ETreeFormat} is the source format for ETree object. {\tt 0} for reading from file, {\tt 1} for obtaining via the best of a nested dissection and a multisection ordering, {\tt 2} for obtaining via a multiple minimum degree ordering, {\tt 3} for obtaining via a multisection ordering, and {\tt 4} for obtaining via a nested dissection ordering. \item {\tt ETreeFile} is the name of file from which ETree object is read if {\tt ETreeFormat} is {\tt 0}. Otherwise, it is the file name to save the computed ETree object. It should be with extension {\tt .etreeb} or {\tt .etreef}. If {\tt ETreeFile} is {\tt none}, the computed ETree object will not be written to file. \item {\tt rhsFile} is the name of file from which right-hand-side vectors $B$ is read. It should be with extension {\tt .densemtxb} or {\tt .densemtxf}. If {\tt rhsFile} is {\tt none}, the right-hand-side $B$ is generated by random numbers. \item {\tt slnFile} is the name of file from which solution vectors $X$ is saved. It should be with extension {\tt .densemtxb} or {\tt .densemtxf}. If {\tt rhsFile} is {\tt none}, the solution $X$ is not saved. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means most of the objects are written to the message file. \item {\tt seed} parameter is random number seed. \item {\tt nrhs} is the number of columns of right-hand-side $B$. \item {\tt Ik} is a block parameter for MLBiCGStab method. \item {\tt itermax} is the maximum iterations number. (inner iterations number for GMRES method) \item {\tt iterout} is the maximum outer number of iterations for GMRES method. \item The {\tt symmetryflag} parameter specifies the symmetry of the matrix $A$. \begin{itemize} \item {\tt type = 0 (SPOOLES\_SYMMETRIC)} for $A$ real or complex symmetric, \item {\tt type = 1 (SPOOLES\_HERMITIAN)} for $A$ complex Hermitian, \item {\tt type = 2 (SPOOLES\_NONSYMMETRIC)} \end{itemize} for $A$ real or complex nonsymmetric. \item The {\tt sparsityflag} parameter signals a direct or approximate factorization. \begin{itemize} \item {\tt sparsityflag = 0 (FRONTMTX\_DENSE\_FRONTS)} implies a direct factorization, the fronts will be stored as dense submatrices. \item {\tt sparsityflag = 1 (FRONTMTX\_SPARSE\_FRONTS)} implies an approximate factorization. The fronts will be stored as sparse submatrices, where the entries in the triangular factors will be subjected to a drop tolerance test --- if the magnitude of an entry is {\tt droptol} or larger, it will be stored, otherwise it will be dropped. \end{itemize} \item The {\tt pivotingflag} parameter signals whether pivoting for stability will be enabled or not. \begin{itemize} \item If {\tt pivotingflag = 0 (SPOOLES\_NO\_PIVOTING)}, no pivoting will be done. \item If {\tt pivotingflag = 1 (SPOOLES\_PIVOTING)}, pivoting will be done to ensure that all entries in $U$ and $L$ have magnitude less than {\tt tau}. \end{itemize} \item The {\tt tau} parameter is an upper bound on the magnitude of the entries in $L$ and $U$ when pivoting is enabled. \item The {\tt droptol} parameter is a lower bound on the magnitude of the entries in $L$ and $U$ when the approximate factorization is enabled. \item {\tt convtol} parameter is a stop criterion for iterative algorithms. \item {\tt methods} parameters are choices of iterative algorithms, {\tt 0} for BiCGStabR, {\tt 1} for BiCGStabL, {\tt 2} for MLBiCGStabR, {\tt 3} for MLBiCGStabL, {\tt 4} for TFQMRR, {\tt 5} for TFQMRL, {\tt 6} for PCGR {\tt 7}, for PCGL {\tt 8} for BGMRESR, and {\tt 9} for BGMRESL. \end{itemize} \end{enumerate} pened with {\it append} status to receive any output data. \item {\tt type} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item {\tt n1} is the row dimension of the test matrix. \item {\tt n2} is the column dimension of the test matrix. \item {\tt inc1} is the row increment. \item {\tt inc2} is the column increment. \item {\tt seed} parameter is random number seed. \end{itemize} %----------------------------------------------------------------------- \itIter/doc/main.ind010064400020550007177000000015350664343366200152010ustar00clevecompmath00000400000006\begin{theindex} \item {\tt bicgstabl()}, 4 \item {\tt bicgstabr()}, 4 \indexspace \item {\tt DenseMtx\_colCopy()}, 2 \item {\tt DenseMtx\_colDotProduct()}, 2 \item {\tt DenseMtx\_colGenAxpy()}, 2 \item {\tt DenseMtx\_frobNorm()}, 1 \item {\tt DenseMtx\_mmm()}, 2 \item {\tt DenseMtx\_twoNormOfColumn()}, 2 \indexspace \item {\tt FrontMtx\_solveOneColumn()}, 2 \indexspace \item {\tt mlbicgstabl()}, 4 \item {\tt mlbicgstabr()}, 4 \indexspace \item {\tt pcgl()}, 4, 5 \item {\tt pcgr()}, 4 \indexspace \item {\tt tfqmrl()}, 4 \item {\tt tfqmrr()}, 4 \indexspace \item {\tt zbicgstabl()}, 5 \item {\tt zbicgstabr()}, 5 \item {\tt zmlbicgstabl()}, 5 \item {\tt zmlbicgstabr()}, 5 \item {\tt zpcgl()}, 6 \item {\tt zpcgr()}, 6 \item {\tt ztfqmrl()}, 5 \item {\tt ztfqmrr()}, 5 \end{theindex} Iter/doc/main.ilg010064400020550007177000000004570664343366200152040ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (25 entries accepted, 0 rejected). Sorting entries....done (105 comparisons). Generating output file main.ind....done (45 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Iter/doc/dataStructure.tex010064400020550007177000000005710664025727400171340ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:Iter:dataStructure} \par \par The methods in {\tt Iter} solve a linear system $AX=B$, where $A$ is an {\tt InpMtx} object and $X$ and $B$ are {\tt DenseMtx} objects. The preconditioner is a {\tt FrontMtx} object obtained via frontal method which uses several other objects. See header file {\tt Iter.h} for further information. LinSol/Bridge.h010060000020550007177000000354630662007037100146420ustar00clevecompmath00000400000006#include "../InpMtx.h" #include "../ETree.h" #include "../FrontMtx.h" #include "../SymbFac.h" #include "../misc.h" #include "../PatchAndGoInfo.h" #include "../timings.h" /* ---------------------------------------------------------------- this object is the bridge between the lanczos and spooles codes. NOTE: serial version graph statistics neqns -- number of vertices in the uncompressed graph nedges -- number of edges in the uncompressed graph Neqns -- number of vertices in the compressed graph Nedges -- number of edges in the compressed graph ordering parameters maxdomainsize -- maximum domain size for recursive dissection maxnzeros -- maximum number of zeros in a front maxsize -- maximum size of a front seed -- random number seed compressCutoff -- cutoff for graph compression, if Neqns <= compressCutoff * neqns then the compressed graph is created, ordered and used to create the symbolic factorization matrix parameters neqns -- number of equations type -- SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC factorization parameters sparsityflag -- FRONTMTX_DENSE_FRONTS or FRONTMTX_SPARSE_FRONTS pivotingflag -- SPOOLES_PIVOTING or SPOOLES_NO_PIVOTING tau -- upper bound on magnitude of factor entries when pivoting is used droptol -- lower bound on magnitude of factor entries when sparse fronts are stored patchinfo -- pointer to PatchAndGoInfo object, can be NULL message info msglvl -- message level for SPOOLES programs set msglvl = 0 for no output set msglvl = 1 for scalar and timing output set msglvl >= 2 for lots of output msgFile -- message file for debug and diagnostic output internal objects, free'd in cleanup frontETree -- object that contains the front tree information symbfacIVL -- object that contains the symbolic factorization mtxmanager -- SubMtx manager object that handles storage for the submatrices of the factors. frontmtx -- object that contains the factorization oldToNewIV -- object that contains the old-to-new permutation newToOldIV -- object that contains the new-to-old permutation statistics stats[ 0] -- # of pivots stats[ 1] -- # of pivot tests stats[ 2] -- # of delayed rows and columns stats[ 3] -- # of entries in D stats[ 4] -- # of entries in L stats[ 5] -- # of entries in U timings cpus[ 0] -- time to construct Graph cpus[ 1] -- time to compress Graph cpus[ 2] -- time to order Graph cpus[ 3] -- time for symbolic factorization cpus[ 4] -- total setup time cpus[ 5] -- time to permute original matrix cpus[ 6] -- time to initialize the front matrix cpus[ 7] -- time to factor the front matrix cpus[ 8] -- time to post-process the front matrix cpus[ 9] -- total factor time cpus[10] -- permute rhs cpus[11] -- solve time cpus[12] -- permute solution cpus[13] -- total solve time created -- 98sep17, cca ---------------------------------------------------------------- */ typedef struct _Bridge Bridge ; struct _Bridge { /* ---------------- graph parameters ---------------- */ int neqns ; int nedges ; int Neqns ; int Nedges ; /* ------------------- ordering parameters ------------------- */ int maxdomainsize ; int maxnzeros ; int maxsize ; int seed ; double compressCutoff ; /* ----------------- matrix parameters ----------------- */ int type ; int symmetryflag ; /* ------------------------ factorization parameters ------------------------ */ int sparsityflag ; int pivotingflag ; double tau ; double droptol ; PatchAndGoInfo *patchinfo ; /* ------------------- pointers to objects ------------------- */ ETree *frontETree ; IVL *symbfacIVL ; SubMtxManager *mtxmanager ; FrontMtx *frontmtx ; IV *oldToNewIV ; IV *newToOldIV ; /* --------------------------------- message info, statistics and cpus --------------------------------- */ int msglvl ; FILE *msgFile ; int stats[6] ; double cpus[14] ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor method created -- 98sep18, cca ----------------------- */ Bridge * Bridge_new ( void ) ; /* ----------------------- set the default fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int Bridge_setDefaultFields ( Bridge *bridge ) ; /* ----------------------- clear the data fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int Bridge_clearData ( Bridge *bridge ) ; /* ----------------------- destructor return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int Bridge_free ( Bridge *bridge ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in setparams.c ------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------- purpose -- to set the matrix parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- neqns <= 0 -3 -- type is invalid -4 -- symmetryflag is invalid -5 -- matrix is hermitian but type is real created -- 98sep25, cca ------------------------------------------- */ int Bridge_setMatrixParams ( Bridge *bridge, int neqns, int type, int symmetryflag ) ; /* ------------------------------------------- purpose -- to set the ordering parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- maxdomainsize <= 0 -3 -- maxsize <= 0 -4 -- compressCutoff > 1.0 created -- 98sep25, cca ------------------------------------------- */ int Bridge_setOrderingParams ( Bridge *bridge, int maxdomainsize, int maxnzeros, int maxsize, int seed, double compressCutoff ) ; /* ---------------------------------------------- purpose -- to set the factorization parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- sparsityflag is invalid -3 -- pivotingflag is invalid -4 -- tau < 2.0 -5 -- droptol < 0.0 created -- 98sep25, cca ---------------------------------------------- */ int Bridge_setFactorParams ( Bridge *bridge, int sparsityflag, int pivotingflag, double tau, double droptol, PatchAndGoInfo *patchinfo ) ; /* ------------------------------------- purpose -- to set the message info return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- msglvl > 0 and msgFile is NULL created -- 98sep18, cca ------------------------------------- */ int Bridge_setMessageInfo ( Bridge *bridge, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------- purpose -- load *pobj with the address of the old-to-new permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int Bridge_oldToNewIV ( Bridge *bridge, IV **pobj ) ; /* --------------------------------------------- purpose -- load *pobj with the address of the new-to-old permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int Bridge_newToOldIV ( Bridge *bridge, IV **pobj ) ; /* -------------------------------------- purpose -- load *pobj with the address of the front ETree object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int Bridge_frontETree ( Bridge *bridge, ETree **pobj ) ; /* --------------------------------------------- purpose -- load *pobj with the address of the symbolic factorization IVL object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int Bridge_symbfacIVL ( Bridge *bridge, IVL **pobj ) ; /* ----------------------------------------- purpose -- load *pobj with the address of the submatrix manager object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca ----------------------------------------- */ int Bridge_mtxmanager ( Bridge *bridge, SubMtxManager **pobj ) ; /* -------------------------------------- purpose -- load *pobj with the address of the front matrix object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int Bridge_frontmtx ( Bridge *bridge, FrontMtx **pobj ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in info.c ------------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- purpose -- generate and return some statistics about the factor and solve type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry type SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC on return --- *pnfront -- # of fronts *pnfactorind -- # of factor indices *pnfactorent -- # of factor entries *pnsolveops -- # of solve operations *pnfactorops -- # of factor operations return values -- 1 -- normal return -1 -- bridge is NULL -2 -- type is bad, must be SPOOLES_REAL or SPOOLES_COMPLEX -3 -- symmetryflag is bad, must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC -4 -- type and symmetryflag mismatch -5 -- front tree is not present -6 -- pnfront is NULL -7 -- pnfactorind is NULL -8 -- pnfactorent is NULL -9 -- pnsolveops is NULL -10 -- pnfactorops is NULL created -- 98oct01, cca -------------------------------------------------------------- */ int Bridge_factorStats ( Bridge *bridge, int type, int symmetryflag, int *pnfront, int *pnfactorind, int *pnfactorent, int *pnsolveops, double *pnfactorops ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in setup.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------- purpose -- given an InpMtx object that contains the structure of A, initialize the bridge data structure for the serial factor's and solve's. return value -- 1 -- normal return -1 -- bridge is NULL -2 -- mtxA is NULL created -- 98sep17, cca ------------------------------------------------------------------- */ int Bridge_setup ( Bridge *bridge, InpMtx *mtxA ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in factor.c ---------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- purpose -- to permute (if necessary) the original matrix, and to initialize, factor and postprocess the factor matrix if permuteflag == 1 then matrix is permuted into new ordering endif return value --- 1 -- normal return, factorization complete 0 -- factorization did not complete, see error flag -1 -- bridge is NULL -2 -- mtxA is NULL -3 -- perror is NULL created -- 98sep18, cca -------------------------------------------------------------- */ int Bridge_factor ( Bridge *bridge, InpMtx *mtxA, int permuteflag, int *perror ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solve.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------- purpose -- to solve the linear system return value --- 1 -- normal return -1 -- bridge is NULL -2 -- X is NULL -3 -- Y is NULL -4 -- frontmtx is NULL -5 -- mtxmanager is NULL -6 -- oldToNewIV not available -7 -- newToOldIV not available created -- 98sep18, cca ------------------------------------- */ int Bridge_solve ( Bridge *bridge, int permuteflag, DenseMtx *X, DenseMtx *Y ) ; /*--------------------------------------------------------------------*/ -------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ----------------------------------------------LinSol/BridgeMPI.h010060000020550007177000000560620662014067600152140ustar00clevecompmath00000400000006/* BridgeMPI.h */ #include "../MPI.h" #include "../InpMtx.h" #include "../ETree.h" #include "../FrontMtx.h" #include "../SymbFac.h" #include "../misc.h" #include "../timings.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- this object is the bridge between the nastran and spooles codes. NOTE: MPI version graph statistics neqns -- number of vertices in the uncompressed graph nedges -- number of edges in the uncompressed graph Neqns -- number of vertices in the compressed graph Nedges -- number of edges in the compressed graph ordering parameters maxdomainsize -- maximum domain size for recursive dissection maxnzeros -- maximum number of zeros in a front maxsize -- maximum size of a front seed -- random number seed compressCutoff -- cutoff for graph compression, if Neqns <= compressCutoff * neqns then the compressed graph is created, ordered and used to create the symbolic factorization matrix parameters neqns -- number of equations type -- SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC factorization parameters sparsityflag -- FRONTMTX_DENSE_FRONTS or FRONTMTX_SPARSE_FRONTS pivotingflag -- SPOOLES_PIVOTING or SPOOLES_NO_PIVOTING tau -- upper bound on magnitude of factor entries when pivoting is used droptol -- lower bound on magnitude of factor entries when sparse fronts are stored patchinfo -- pointer to PatchAndGoInfo object, can be NULL lookahead -- lookahead parameter for factorization recommended value = nthread message info msglvl -- message level for SPOOLES programs set msglvl = 0 for no output set msglvl = 1 for scalar and timing output set msglvl >= 2 for lots of output msgFile -- message file for debug and diagnostic output internal objects, free'd in cleanup frontETree -- object that contains the front tree information symbfacIVL -- object that contains the symbolic factorization mtxmanager -- SubMtx manager object that handles storage for the submatrices of the factors. frontmtx -- object that contains the factorization oldToNewIV -- object that contains the old-to-new permutation newToOldIV -- object that contains the new-to-old permutation vtxmapIV -- object that contains the map from vertices to processors rowmapIV -- object that contains the map from rows to processors in the solve ownedColumnsIV -- object that contains the owned columns during the solve Aloc -- InpMtx object to hold local owned matrix Xloc -- DenseMtx object to hold local solution Yloc -- DenseMtx object to hold local right hand side MPI information nproc -- # of processors myid -- rank of this processors comm -- MPI communicator ownersIV -- map from fronts to owning threads solvemap -- map from submatrices to owning threads cumopsDV -- vector that holds operations for each thread statistics stats[ 0] -- # of pivots stats[ 1] -- # of pivot tests stats[ 2] -- # of delayed rows and columns stats[ 3] -- # of entries in D stats[ 4] -- # of entries in L stats[ 5] -- # of entries in U timings cpus[ 0] -- time to construct Graph cpus[ 1] -- time to compress Graph cpus[ 2] -- time to order Graph cpus[ 3] -- time for symbolic factorization cpus[ 4] -- time to broadcast the front tree cpus[ 5] -- time to broadcast the symbolic factorization cpus[ 6] -- total setup time cpus[ 7] -- parallel factor setup time cpus[ 8] -- time to permute original matrix cpus[ 9] -- time to distribute the original matrix cpus[10] -- time to initialize the front matrix cpus[11] -- time to factor the front matrix cpus[12] -- time to post-process the front matrix cpus[13] -- total factor time cpus[14] -- parallel solve setup time cpus[15] -- time to permute rhs cpus[16] -- time to distribute rhs cpus[17] -- time to create the solution matrix cpus[18] -- time to solve the linear system cpus[19] -- time to gather solution on processor zero cpus[20] -- time to permute solution cpus[21] -- total solve time created -- 98sep17, cca ---------------------------------------------------------------- */ typedef struct _BridgeMPI BridgeMPI ; struct _BridgeMPI { /* ---------------- graph parameters ---------------- */ int neqns ; int nedges ; int Neqns ; int Nedges ; /* ------------------- ordering parameters ------------------- */ double compressCutoff ; int maxdomainsize ; int maxnzeros ; int maxsize ; int seed ; /* ----------------- matrix parameters ----------------- */ int type ; int symmetryflag ; /* ------------------------ factorization parameters ------------------------ */ int sparsityflag ; int pivotingflag ; double tau ; double droptol ; int lookahead ; PatchAndGoInfo *patchinfo ; /* ------------------- pointers to objects ------------------- */ ETree *frontETree ; IVL *symbfacIVL ; SubMtxManager *mtxmanager ; FrontMtx *frontmtx ; IV *oldToNewIV ; IV *newToOldIV ; /* ----------------------- pointers to MPI objects ----------------------- */ IV *ownersIV ; SolveMap *solvemap ; DV *cumopsDV ; IV *vtxmapIV ; IV *rowmapIV ; IV *ownedColumnsIV ; InpMtx *Aloc ; DenseMtx *Xloc ; DenseMtx *Yloc ; /* -------------- MPI parameters -------------- */ int nproc ; int myid ; MPI_Comm comm ; /* --------------------------------- message info, statistics and cpus --------------------------------- */ int msglvl ; FILE *msgFile ; int stats[6] ; double cpus[22] ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor method created -- 98sep25, cca ----------------------- */ BridgeMPI * BridgeMPI_new ( void ) ; /* ----------------------- set the default fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep25, cca ----------------------- */ int BridgeMPI_setDefaultFields ( BridgeMPI *bridge ) ; /* ----------------------- clear the data fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep25, cca ----------------------- */ int BridgeMPI_clearData ( BridgeMPI *bridge ) ; /* ----------------------- destructor return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep25, cca ----------------------- */ int BridgeMPI_free ( BridgeMPI *bridge ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in setparams.c ------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------- purpose -- to set the matrix parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- neqns <= 0 -3 -- type is invalid -4 -- symmetryflag is invalid -5 -- matrix is hermitian but type is real created -- 98sep25, cca ------------------------------------------- */ int BridgeMPI_setMatrixParams ( BridgeMPI *bridge, int neqns, int type, int symmetryflag ) ; /* ------------------------------------------- purpose -- to set the MPI parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- nproc <= 0 -3 -- myid < 0 or myid >= nproc created -- 98sep25, cca ------------------------------------------- */ int BridgeMPI_setMPIparams ( BridgeMPI *bridge, int nproc, int myid, MPI_Comm comm ) ; /* ------------------------------------------- purpose -- to set the ordering parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- maxdomainsize <= 0 -3 -- maxsize <= 0 -4 -- compressCutoff > 1.0 created -- 98sep25, cca ------------------------------------------- */ int BridgeMPI_setOrderingParams ( BridgeMPI *bridge, int maxdomainsize, int maxnzeros, int maxsize, int seed, int compressCutoff ) ; /* ------------------------------------- purpose -- to set the message info return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- msglvl > 0 and msgFile is NULL created -- 98sep25, cca ------------------------------------- */ int BridgeMPI_setMessageInfo ( BridgeMPI *bridge, int msglvl, FILE *msgFile ) ; /* ---------------------------------------------- purpose -- to set the factorization parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- sparsityflag is invalid -3 -- pivotingflag is invalid -4 -- tau < 2.0 -5 -- droptol < 0.0 -6 -- lookahead < 0 created -- 98sep25, cca ---------------------------------------------- */ int BridgeMPI_setFactorParams ( BridgeMPI *bridge, int sparsityflag, int pivotingflag, double tau, double droptol, int lookahead, PatchAndGoInfo *patchinfo ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------- purpose -- load *pobj with the address of the old-to-new permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMPI_oldToNewIV ( BridgeMPI *bridge, IV **pobj ) ; /* --------------------------------------------- purpose -- load *pobj with the address of the new-to-old permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMPI_newToOldIV ( BridgeMPI *bridge, IV **pobj ) ; /* -------------------------------------- purpose -- load *pobj with the address of the front ETree object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int BridgeMPI_frontETree ( BridgeMPI *bridge, ETree **pobj ) ; /* --------------------------------------------- purpose -- load *pobj with the address of the symbolic factorization IVL object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMPI_symbfacIVL ( BridgeMPI *bridge, IVL **pobj ) ; /* ----------------------------------------- purpose -- load *pobj with the address of the submatrix manager object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca ----------------------------------------- */ int BridgeMPI_mtxmanager ( BridgeMPI *bridge, SubMtxManager **pobj ) ; /* -------------------------------------- purpose -- load *pobj with the address of the front matrix object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int BridgeMPI_frontmtx ( BridgeMPI *bridge, FrontMtx **pobj ) ; /* -------------------------------------- purpose -- load *pobj with the address of the owners IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep25, cca -------------------------------------- */ int BridgeMPI_ownersIV ( BridgeMPI *bridge, IV **pobj ) ; /* ----------------------------------------- purpose -- load *pobj with the address of the solve map SolveMap object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep25, cca ----------------------------------------- */ int BridgeMPI_solvemap ( BridgeMPI *bridge, SolveMap **pobj ) ; /* -------------------------------------- purpose -- load *pobj with the address of the vtxmap IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98oct01, cca -------------------------------------- */ int BridgeMPI_vtxmapIV ( BridgeMPI *bridge, IV **pobj ) ; /* -------------------------------------- purpose -- load *pobj with the address of the rowmap IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98oct01, cca -------------------------------------- */ int BridgeMPI_rowmapIV ( BridgeMPI *bridge, IV **pobj ) ; /* ---------------------------------------- purpose -- load *pobj with the address of the ownedColumns IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98oct01, cca ---------------------------------------- */ int BridgeMPI_ownedColumns ( BridgeMPI *bridge, IV **pobj ) ; /* ---------------------------------------- purpose -- load *pobj with the address of the Xloc DenseMtx object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98oct01, cca ---------------------------------------- */ int BridgeMPI_Xloc ( BridgeMPI *bridge, DenseMtx **pobj ) ; /* ---------------------------------------- purpose -- load *pobj with the address of the Yloc DenseMtx object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98oct01, cca ---------------------------------------- */ int BridgeMPI_Yloc ( BridgeMPI *bridge, DenseMtx **pobj ) ; /* ----------------------------------------------------- purpose -- load *pnproc with the number of processors return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pnproc is NULL created -- 98sep18, cca ----------------------------------------------------- */ int BridgeMPI_nproc ( BridgeMPI *bridge, int *pnproc ) ; /* ---------------------------------------------------- purpose -- load *pmyid with the id of this processor return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pmyid is NULL created -- 98sep18, cca ---------------------------------------------------- */ int BridgeMPI_myid ( BridgeMPI *bridge, int *pmyid ) ; /* ---------------------------------------------------- purpose -- load *plookahead with the lookahead value for the factorization return value -- 1 -- normal return -1 -- bridge is NULL -2 -- plookahead is NULL created -- 98sep18, cca ---------------------------------------------------- */ int BridgeMPI_lookahead ( BridgeMPI *bridge, int *plookahead ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in info.c ------------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- purpose -- generate and return some statistics about the factor and solve type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry type SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC on return --- *pnfront -- # of fronts *pnfactorind -- # of factor indices *pnfactorent -- # of factor entries *pnsolveops -- # of solve operations *pnfactorops -- # of factor operations return values -- 1 -- normal return -1 -- bridge is NULL -2 -- type is bad, must be SPOOLES_REAL or SPOOLES_COMPLEX -3 -- symmetryflag is bad, must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC -4 -- type and symmetryflag mismatch -5 -- front tree is not present -6 -- pnfront is NULL -7 -- pnfactorind is NULL -8 -- pnfactorent is NULL -9 -- pnsolveops is NULL -10 -- pnfactorops is NULL created -- 98oct01, cca -------------------------------------------------------------- */ int BridgeMPI_factorStats ( BridgeMPI *bridge, int type, int symmetryflag, int *pnfront, int *pnfactorind, int *pnfactorent, int *pnsolveops, double *pnfactorops ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in setup.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------- purpose -- given an InpMtx object that contains the structure of A, initialize the bridge data structure for the serial factor's and solve's. note: all parameters are pointers to be compatible with fortran's call by reference. return value -- 1 -- normal return -1 -- bridge is NULL -2 -- myid is zero and mtxA is NULL created -- 98sep25, cca ------------------------------------------------------------------- */ int BridgeMPI_setup ( BridgeMPI *bridge, InpMtx *mtxA ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in factorSetup.c ----------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------------- purpose -- to construct the map from fronts to processors, and compute operations for each processor. maptype -- type of map for parallel factorization maptype = 1 --> wrap map maptype = 2 --> balanced map maptype = 3 --> subtree-subset map maptype = 4 --> domain decomposition map cutoff -- used when maptype = 4 as upper bound on relative domain size return value -- 1 -- success -1 -- bridge is NULL -2 -- front tree is NULL created -- 98sep25, cca ---------------------------------------------------------- */ int BridgeMPI_factorSetup ( BridgeMPI *bridge, int maptype, double cutoff ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in factor.c ---------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- purpose -- to permute (if necessary) the original matrix, and to initialize, factor and postprocess the factor matrix if permuteflag == 1 then matrix is permuted into new ordering endif return value --- 1 -- normal return, factorization complete 0 -- factorization did not complete, see error flag -1 -- bridge is NULL -2 -- perror is NULL created -- 98sep18, cca -------------------------------------------------------------- */ int BridgeMPI_factor ( BridgeMPI *bridge, InpMtx *mtxA, int permuteflag, int *perror ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solveSetup.c ------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------------- purpose -- to setup for the parallel solve return value --- 1 -- normal return -1 -- bridge is NULL -2 -- frontmtx is NULL -3 -- frontmtx has not yet been postprocessed created -- 98sep24, cca ----------------------------------------------- */ int BridgeMPI_solveSetup ( BridgeMPI *bridge ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solve.c ----------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------- purpose -- to solve the linear system MPI version if permuteflag is 1 then rhs is permuted into new ordering solution is permuted into old ordering return value --- 1 -- normal return -1 -- bridge is NULL -2 -- X is NULL -3 -- Y is NULL -4 -- frontmtx is NULL -5 -- mtxmanager is NULL -6 -- oldToNewIV not available -7 -- newToOldIV not available created -- 98sep18, cca -------------------------------------------- */ int BridgeMPI_solve ( BridgeMPI *bridge, int permuteflag, DenseMtx *X, DenseMtx *Y ) ; /*--------------------------------------------------------------------*/ geMPI_frontmtx ( BridgeMPI *bridge, FrontMtx **pobj ) ; /* -------------------------------------- purpose -- load *pobj with the address of the owners IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep25, cca -------------------------------------- */ int BridgeMPI_ownersIV ( BridgeMPI *bridge, IV **pobj ) ; /* -------------------LinSol/BridgeMT.h010060000020550007177000000456040662007073200151020ustar00clevecompmath00000400000006#include "../MT.h" #include "../InpMtx.h" #include "../ETree.h" #include "../FrontMtx.h" #include "../SymbFac.h" #include "../misc.h" #include "../timings.h" /* ---------------------------------------------------------------- this object is the bridge between the lanczos and spooles codes. NOTE: multithreaded version graph statistics neqns -- number of vertices in the uncompressed graph nedges -- number of edges in the uncompressed graph Neqns -- number of vertices in the compressed graph Nedges -- number of edges in the compressed graph ordering parameters maxdomainsize -- maximum domain size for recursive dissection maxnzeros -- maximum number of zeros in a front maxsize -- maximum size of a front seed -- random number seed compressCutoff -- cutoff for graph compression, if Neqns <= compressCutoff * neqns then the compressed graph is created, ordered and used to create the symbolic factorization matrix parameters neqns -- number of equations type -- SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC factorization parameters sparsityflag -- FRONTMTX_DENSE_FRONTS or FRONTMTX_SPARSE_FRONTS pivotingflag -- SPOOLES_PIVOTING or SPOOLES_NO_PIVOTING tau -- upper bound on magnitude of factor entries when pivoting is used droptol -- lower bound on magnitude of factor entries when sparse fronts are stored lookahead -- lookahead parameter for factorization recommended value = nthread message info msglvl -- message level for SPOOLES programs set msglvl = 0 for no output set msglvl = 1 for scalar and timing output set msglvl >= 2 for lots of output msgFile -- message file for debug and diagnostic output internal objects, free'd in cleanup frontETree -- object that contains the front tree information symbfacIVL -- object that contains the symbolic factorization mtxmanager -- SubMtx manager object that handles storage for the submatrices of the factors. frontmtx -- object that contains the factorization oldToNewIV -- object that contains the old-to-new permutation newToOldIV -- object that contains the new-to-old permutation multithreaded information nthread -- # of threads ownersIV -- map from fronts to owning threads solvemap -- map from submatrices to owning threads cumopsDV -- vector that holds operations for each thread statistics stats[ 0] -- # of pivots stats[ 1] -- # of pivot tests stats[ 2] -- # of delayed rows and columns stats[ 3] -- # of entries in D stats[ 4] -- # of entries in L stats[ 5] -- # of entries in U timings cpus[ 0] -- time to construct Graph cpus[ 1] -- time to compress Graph cpus[ 2] -- time to order Graph cpus[ 3] -- time for symbolic factorization cpus[ 4] -- total setup time cpus[ 5] -- parallel factor setup time cpus[ 6] -- time to permute original matrix cpus[ 7] -- time to initialize the front matrix cpus[ 8] -- time to factor the front matrix cpus[ 9] -- time to post-process the front matrix cpus[10] -- total factor time cpus[11] -- parallel solve setup time cpus[12] -- permute rhs cpus[13] -- solve time cpus[14] -- permute solution cpus[15] -- total solve time created -- 98sep17, cca ---------------------------------------------------------------- */ typedef struct _BridgeMT BridgeMT ; struct _BridgeMT { /* ---------------- graph parameters ---------------- */ int neqns ; int nedges ; int Neqns ; int Nedges ; /* ------------------- ordering parameters ------------------- */ int maxdomainsize ; int maxnzeros ; int maxsize ; int seed ; double compressCutoff ; /* ----------------- matrix parameters ----------------- */ int type ; int symmetryflag ; /* ------------------------ factorization parameters ------------------------ */ int sparsityflag ; int pivotingflag ; double tau ; double droptol ; int lookahead ; PatchAndGoInfo *patchinfo ; /* ------------------- pointers to objects ------------------- */ ETree *frontETree ; IVL *symbfacIVL ; SubMtxManager *mtxmanager ; FrontMtx *frontmtx ; IV *oldToNewIV ; IV *newToOldIV ; /* ------------------------ multithreaded parameters ------------------------ */ int nthread ; IV *ownersIV ; SolveMap *solvemap ; DV *cumopsDV ; /* --------------------------------- message info, statistics and cpus --------------------------------- */ int msglvl ; FILE *msgFile ; int stats[6] ; double cpus[16] ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor method created -- 98sep18, cca ----------------------- */ BridgeMT * BridgeMT_new ( void ) ; /* ----------------------- set the default fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int BridgeMT_setDefaultFields ( BridgeMT *bridge ) ; /* ----------------------- clear the data fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int BridgeMT_clearData ( BridgeMT *bridge ) ; /* ----------------------- destructor return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int BridgeMT_free ( BridgeMT *bridge ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in setparams.c ------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------- purpose -- to set the matrix parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- neqns <= 0 -3 -- type is invalid -4 -- symmetryflag is invalid -5 -- matrix is hermitian but type is real created -- 98sep25, cca ------------------------------------------- */ int BridgeMT_setMatrixParams ( BridgeMT *bridge, int neqns, int type, int symmetryflag ) ; /* ------------------------------------------- purpose -- to set the ordering parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- maxdomainsize <= 0 -3 -- maxsize <= 0 -4 -- compressCutoff > 1.0 created -- 98sep25, cca ------------------------------------------- */ int BridgeMT_setOrderingParams ( BridgeMT *bridge, int maxdomainsize, int maxnzeros, int maxsize, int seed, int compressCutoff ) ; /* ------------------------------------- purpose -- to set the message info return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- msglvl > 0 and msgFile is NULL created -- 98sep18, cca ------------------------------------- */ int BridgeMT_setMessageInfo ( BridgeMT *bridge, int msglvl, FILE *msgFile ) ; /* ---------------------------------------------- purpose -- to set the factorization parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- sparsityflag is invalid -3 -- pivotingflag is invalid -4 -- tau < 2.0 -5 -- droptol < 0.0 -6 -- lookahead < 0 created -- 98sep25, cca ---------------------------------------------- */ int BridgeMT_setFactorParams ( BridgeMT *bridge, int sparsityflag, int pivotingflag, double tau, double droptol, int lookahead, PatchAndGoInfo *patchinfo ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------- purpose -- load *pobj with the address of the old-to-new permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMT_oldToNewIV ( BridgeMT *bridge, IV **pobj ) ; /* --------------------------------------------- purpose -- load *pobj with the address of the new-to-old permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMT_newToOldIV ( BridgeMT *bridge, IV **pobj ) ; /* -------------------------------------- purpose -- load *pobj with the address of the front ETree object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int BridgeMT_frontETree ( BridgeMT *bridge, ETree **pobj ) ; /* --------------------------------------------- purpose -- load *pobj with the address of the symbolic factorization IVL object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMT_symbfacIVL ( BridgeMT *bridge, IVL **pobj ) ; /* ----------------------------------------- purpose -- load *pobj with the address of the submatrix manager object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca ----------------------------------------- */ int BridgeMT_mtxmanager ( BridgeMT *bridge, SubMtxManager **pobj ) ; /* -------------------------------------- purpose -- load *pobj with the address of the front matrix object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int BridgeMT_frontmtx ( BridgeMT *bridge, FrontMtx **pobj ) ; /* -------------------------------------- purpose -- load *pobj with the address of the owners IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep24, cca -------------------------------------- */ int BridgeMT_ownersIV ( BridgeMT *bridge, IV **pobj ) ; /* ----------------------------------------- purpose -- load *pobj with the address of the solve map SolveMap object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep24, cca ----------------------------------------- */ int BridgeMT_solvemap ( BridgeMT *bridge, SolveMap **pobj ) ; /* ---------------------------------------------------- purpose -- load *pnthread with the number of threads return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pnthread is NULL created -- 98sep24, cca ---------------------------------------------------- */ int BridgeMT_nthread ( BridgeMT *bridge, int *pnthread ) ; /* -------------------------------------------------------- purpose -- load *plookahead with the lookahead parameter return value -- 1 -- normal return -1 -- bridge is NULL -2 -- plookahead is NULL created -- 98sep24, cca -------------------------------------------------------- */ int BridgeMT_lookahead ( BridgeMT *bridge, int *plookahead ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in info.c ------------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- purpose -- generate and return some statistics about the factor and solve type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry type SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC on return --- *pnfront -- # of fronts *pnfactorind -- # of factor indices *pnfactorent -- # of factor entries *pnsolveops -- # of solve operations *pnfactorops -- # of factor operations return values -- 1 -- normal return -1 -- bridge is NULL -2 -- type is bad, must be SPOOLES_REAL or SPOOLES_COMPLEX -3 -- symmetryflag is bad, must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC -4 -- type and symmetryflag mismatch -5 -- front tree is not present -6 -- pnfront is NULL -7 -- pnfactorind is NULL -8 -- pnfactorent is NULL -9 -- pnsolveops is NULL -10 -- pnfactorops is NULL created -- 98oct01, cca -------------------------------------------------------------- */ int BridgeMT_factorStats ( BridgeMT *bridge, int type, int symmetryflag, int *pnfront, int *pnfactorind, int *pnfactorent, int *pnsolveops, double *pnfactorops ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in setup.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------- purpose -- given an InpMtx object that contains the structure of A, initialize the bridge data structure for the serial factor's and solve's. note: all parameters are pointers to be compatible with fortran's call by reference. return value -- 1 -- normal return -1 -- bridge is NULL -2 -- mtxA is NULL created -- 98sep17, cca ------------------------------------------------------------------- */ int BridgeMT_setup ( BridgeMT *bridge, InpMtx *mtxA ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in factorSetup.c ----------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------- purpose -- to construct the map from fronts to threads, and compute operations for each thread. nthread -- number of threads maptype -- type of map for parallel factorization maptype = 1 --> wrap map maptype = 2 --> balanced map maptype = 3 --> subtree-subset map maptype = 4 --> domain decomposition map cutoff -- used when maptype = 4 as upper bound on relative domain size default is maptype = 4 and cutoff = 1/(2*nthread) return value -- 1 -- success -1 -- bridge is NULL -2 -- nthread is invalid, must be > 0 -3 -- front tree is NULL created -- 98sep24, cca ------------------------------------------------------- */ int BridgeMT_factorSetup ( BridgeMT *bridge, int nthread, int maptype, double cutoff ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in factor.c ---------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- purpose -- to permute (if necessary) the original matrix, and to initialize, factor and postprocess the factor matrix return value --- 1 -- normal return, factorization complete 0 -- factorization did not complete, see error flag -1 -- bridge is NULL -2 -- mtxA is NULL -3 -- perror is NULL created -- 98sep18, cca -------------------------------------------------------------- */ int BridgeMT_factor ( BridgeMT *bridge, InpMtx *mtxA, int permuteflag, int *perror ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solveSetup.c ------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------------- purpose -- to setup for the parallel solve return value --- 1 -- normal return -1 -- bridge is NULL -2 -- frontmtx is NULL -3 -- frontmtx has not yet been postprocessed created -- 98sep24, cca ----------------------------------------------- */ int BridgeMT_solveSetup ( BridgeMT *bridge ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solve.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------- purpose -- to solve the linear system return value --- 1 -- normal return -1 -- bridge is NULL -2 -- X is NULL -3 -- Y is NULL -4 -- frontmtx is NULL -5 -- mtxmanager is NULL -6 -- oldToNewIV not available -7 -- newToOldIV not available created -- 98sep18, cca ------------------------------------- */ int BridgeMT_solve ( BridgeMT *bridge, int permuteflag, DenseMtx *X, DenseMtx *Y ) ; /*--------------------------------------------------------------------*/ ------------ ----- methods found in instance.c -------------------------------------- --------------------------------------LinSol/makefile010064400020550007177000000003630663622363400150050ustar00clevecompmath00000400000006all_drivers : lib : cd srcST ; make Bridge.a cd srcMT ; make BridgeMT.a cd srcMPI ; make BridgeMPI.a clean : cd srcST ; make clean cd srcMT ; make clean cd srcMPI ; make clean cd doc ; make clean cd drivers ; make clean LinSol/srcST/makefile010060000020550007177000000006130661671126700160330ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Bridge $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(factor.o) \ $(OBJ).a(info.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(setparams.o) \ $(OBJ).a(setup.o) \ $(OBJ).a(solve.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o LinSol/srcST/basics.c010060000020550007177000000070160661736365600157550ustar00clevecompmath00000400000006/* basics.C */ #include "../Bridge.h" /*--------------------------------------------------------------------*/ /* ----------------------- constructor method created -- 98sep18, cca ----------------------- */ Bridge * Bridge_new ( void ) { Bridge *bridge ; ALLOCATE(bridge, struct _Bridge, 1) ; Bridge_setDefaultFields(bridge) ; return(bridge) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int Bridge_setDefaultFields ( Bridge *bridge ) { if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in Bridge_setDefaultFields(%p)" "\n bad input\n", bridge) ; return(-1) ; } /* ---------------- graph statistics ---------------- */ bridge->neqns = 0 ; bridge->nedges = 0 ; bridge->Neqns = 0 ; bridge->Nedges = 0 ; /* ------------------- ordering parameters ------------------- */ bridge->compressCutoff = 0.0 ; bridge->maxdomainsize = -1 ; bridge->maxnzeros = -1 ; bridge->maxsize = -1 ; bridge->seed = -1 ; /* ------------------------------- matrix/factorization parameters ------------------------------- */ bridge->type = SPOOLES_REAL ; bridge->symmetryflag = SPOOLES_SYMMETRIC ; bridge->sparsityflag = FRONTMTX_DENSE_FRONTS ; bridge->pivotingflag = SPOOLES_NO_PIVOTING ; bridge->tau = 100.0 ; bridge->droptol = 1.e-3 ; bridge->patchinfo = NULL ; /* ------------------------------------ message info, statistics and timings ------------------------------------ */ IVzero(6, bridge->stats) ; DVzero(14, bridge->cpus) ; bridge->msglvl = 0 ; bridge->msgFile = stdout ; /* ------------------- pointers to objects ------------------- */ bridge->frontETree = NULL ; bridge->symbfacIVL = NULL ; bridge->mtxmanager = NULL ; bridge->frontmtx = NULL ; bridge->oldToNewIV = NULL ; bridge->newToOldIV = NULL ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int Bridge_clearData ( Bridge *bridge ) { if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in Bridge_clearData(%p)" "\n bad input\n", bridge) ; return(-1) ; } if ( bridge->frontmtx != NULL ) { FrontMtx_free(bridge->frontmtx) ; } if ( bridge->frontETree != NULL ) { ETree_free(bridge->frontETree) ; } if ( bridge->symbfacIVL != NULL ) { IVL_free(bridge->symbfacIVL) ; } if ( bridge->mtxmanager != NULL ) { SubMtxManager_free(bridge->mtxmanager) ; } if ( bridge->oldToNewIV != NULL ) { IV_free(bridge->oldToNewIV) ; } if ( bridge->newToOldIV != NULL ) { IV_free(bridge->newToOldIV) ; } Bridge_setDefaultFields(bridge) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------- destructor return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int Bridge_free ( Bridge *bridge ) { if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in Bridge_free(%p)" "\n bad input\n", bridge) ; return(-1) ; } Bridge_clearData(bridge) ; FREE(bridge) ; return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcST/factor.c010060000020550007177000000160020661671126700157540ustar00clevecompmath00000400000006/* factor.c */ #include "../Bridge.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- to permute (if necessary) the original matrix, and to initialize, factor and postprocess the factor matrix if permuteflag == 1 then matrix is permuted into new ordering endif return value --- 1 -- normal return, factorization complete 0 -- factorization did not complete, see error flag -1 -- bridge is NULL -2 -- mtxA is NULL -3 -- perror is NULL created -- 98sep18, cca -------------------------------------------------------------- */ int Bridge_factor ( Bridge *bridge, InpMtx *mtxA, int permuteflag, int *perror ) { Chv *rootchv ; ChvManager *chvmanager ; double cputotal, nfops, t0, t1, t2 ; double cpus[9] ; int msglvl, nzf ; int stats[6] ; FILE *msgFile ; FrontMtx *frontmtx ; SubMtxManager *mtxmanager ; /*--------------------------------------------------------------------*/ MARKTIME(t0) ; /* --------------- check the input --------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in Bridge_factor()" "\n bridge is NULL\n") ; return(-1) ; } if ( mtxA == NULL ) { fprintf(stderr, "\n error in Bridge_factor()" "\n mtxA is NULL\n") ; return(-2) ; } if ( perror == NULL ) { fprintf(stderr, "\n error in Bridge_factor()" "\n perror is NULL\n") ; return(-3) ; } msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; /*--------------------------------------------------------------------*/ MARKTIME(t1) ; if ( permuteflag == 1 ) { int *oldToNew = IV_entries(bridge->oldToNewIV) ; /* ------------------------------------------------ permute the input matrix and convert to chevrons ------------------------------------------------ */ InpMtx_permute(mtxA, oldToNew, oldToNew) ; if ( bridge->symmetryflag == SPOOLES_SYMMETRIC || bridge->symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } } if ( ! INPMTX_IS_BY_CHEVRONS(mtxA) ) { InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; } if ( ! INPMTX_IS_BY_VECTORS(mtxA) ) { InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; } MARKTIME(t2) ; bridge->cpus[5] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : permute and format A", t2 - t1) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* --------------------------- initialize the front matrix --------------------------- */ MARKTIME(t1) ; if ( (mtxmanager = bridge->mtxmanager) == NULL ) { mtxmanager = bridge->mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; } if ( (frontmtx = bridge->frontmtx) == NULL ) { frontmtx = bridge->frontmtx = FrontMtx_new() ; } else { FrontMtx_clearData(frontmtx) ; } FrontMtx_init(frontmtx, bridge->frontETree, bridge->symbfacIVL, bridge->type, bridge->symmetryflag, bridge->sparsityflag, bridge->pivotingflag, NO_LOCK, -1, NULL, mtxmanager, bridge->msglvl, bridge->msgFile) ; frontmtx->patchinfo = bridge->patchinfo ; MARKTIME(t2) ; bridge->cpus[6] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : initialize front matrix", t2 - t1) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------- factor the matrix ----------------- */ nzf = ETree_nFactorEntries(bridge->frontETree, bridge->symmetryflag) ; nfops = ETree_nFactorOps(bridge->frontETree, bridge->type, bridge->symmetryflag) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d factor entries, %.0f factor ops, %8.3f ratio", nzf, nfops, nfops/nzf) ; fflush(msgFile) ; } IVzero(6, stats) ; DVzero(9, cpus) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1) ; MARKTIME(t1) ; rootchv = FrontMtx_factorInpMtx(frontmtx, mtxA, bridge->tau, bridge->droptol, chvmanager, perror, cpus, stats, bridge->msglvl, bridge->msgFile) ; MARKTIME(t2) ; IVcopy(6, bridge->stats, stats) ; bridge->cpus[7] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : factor matrix, %8.3f mflops", t2 - t1, 1.e-6*nfops/(t2-t1)) ; fprintf(msgFile, "\n %8d pivots, %8d pivot tests, %8d delayed vertices" "\n %d entries in D, %d entries in L, %d entries in U", stats[0], stats[1], stats[2], stats[3], stats[4], stats[5]) ; cputotal = cpus[8] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n initialize fronts %8.3f %6.2f" "\n load original entries %8.3f %6.2f" "\n update fronts %8.3f %6.2f" "\n assemble postponed data %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n extract postponed data %8.3f %6.2f" "\n store factor entries %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[6], 100.*cpus[6]/cputotal, cpus[7], 100.*cpus[7]/cputotal, cputotal) ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n submatrix mananger after factorization") ; SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; fprintf(msgFile, "\n\n chevron mananger after factorization") ; ChvManager_writeForHumanEye(chvmanager, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } ChvManager_free(chvmanager) ; if ( *perror >= 0 ) { return(0) ; } /*--------------------------------------------------------------------*/ /* ----------------------------- post-process the front matrix ----------------------------- */ MARKTIME(t1) ; FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; MARKTIME(t2) ; bridge->cpus[8] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : post-process the matrix", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n submatrix mananger after post-processing") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ MARKTIME(t2) ; bridge->cpus[9] += t2 - t0 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : total factor time", t2 - t0) ; fflush(msgFile) ; } return(1) ; } /*--------------------------------------------------------------------*/ r in Bridge_factor()" "\n perror is NULL\n") ; return(-3) ; } msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; /*--------------------------------------------------------------------*/ MARKTIME(t1) ; if ( permuteflag == 1 ) { int *oldToNew = IV_entries(bridge->oldToNewIV) ; /* ------------------------------------------------ permute the input matrix and convert to chevrons ------------------------------------------------ */ InpMtx_permute(mtxA, oldToNew, oldToNew) ; LinSol/srcST/info.c010060000020550007177000000072540661671126700154420ustar00clevecompmath00000400000006/* info.c */ #include "../Bridge.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- generate and return some statistics about the factor and solve type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry type SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC on return --- *pnfront -- # of fronts *pnfactorind -- # of factor indices *pnfactorent -- # of factor entries *pnsolveops -- # of solve operations *pnfactorops -- # of factor operations return values -- 1 -- normal return -1 -- bridge is NULL -2 -- type is bad, must be SPOOLES_REAL or SPOOLES_COMPLEX -3 -- symmetryflag is bad, must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC -4 -- type and symmetryflag mismatch -5 -- front tree is not present -6 -- pnfront is NULL -7 -- pnfactorind is NULL -8 -- pnfactorent is NULL -9 -- pnsolveops is NULL -10 -- pnfactorops is NULL created -- 98oct01, cca -------------------------------------------------------------- */ int Bridge_factorStats ( Bridge *bridge, int type, int symmetryflag, int *pnfront, int *pnfactorind, int *pnfactorent, int *pnsolveops, double *pnfactorops ) { ETree *etree ; int nentD, nentU ; /* --------------- check the input --------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n bridge is NULL\n") ; return(-1) ; } switch ( type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n error in Bridge_factorStats()" "\n bad type %d\n", type) ; return(-3) ; break ; } switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n error in Bridge_factorStats()" "\n bad symmetryflag %d\n", symmetryflag) ; return(-3) ; break ; } if ( type == SPOOLES_REAL && symmetryflag == SPOOLES_HERMITIAN ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n type %d, symmetryflag %d, mismatch\n", type, symmetryflag) ; return(-4) ; } if ( (etree = bridge->frontETree) == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n front tree is not present\n") ; return(-5) ; } if ( pnfront == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n pnfront is NULL\n") ; return(-6) ; } if ( pnfactorind == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n pnfactorind is NULL\n") ; return(-7) ; } if ( pnfactorent == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n pnfactorent is NULL\n") ; return(-8) ; } if ( pnsolveops == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n pnsolveops is NULL\n") ; return(-9) ; } if ( pnfactorops == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n pnfactorops is NULL\n") ; return(-10) ; } *pnfront = ETree_nfront(etree) ; *pnfactorind = ETree_nFactorIndices(etree) ; *pnfactorent = ETree_nFactorEntries(etree, symmetryflag) ; *pnfactorops = ETree_nFactorOps(etree, type, symmetryflag) ; nentD = etree->nvtx ; nentU = *pnfactorent - nentD ; switch ( type ) { case SPOOLES_REAL : *pnsolveops = 4*nentU + nentD ; break ; case SPOOLES_COMPLEX : *pnsolveops = 16*nentU + 8*nentD ; break ; } return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcST/instance.c010060000020550007177000000116500661671126700163060ustar00clevecompmath00000400000006/* instance.c */ #include "../Bridge.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- load *pobj with the address of the old-to-new permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int Bridge_oldToNewIV ( Bridge *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in Bridge_oldToNewIV" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in Bridge_oldToNewIV" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->oldToNewIV ; return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- load *pobj with the address of the new-to-old permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int Bridge_newToOldIV ( Bridge *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in Bridge_newToOldIV" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in Bridge_newToOldIV" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->newToOldIV ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- load *pobj with the address of the front ETree object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int Bridge_frontETree ( Bridge *bridge, ETree **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in Bridge_frontETree" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in Bridge_frontETree" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->frontETree ; return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- load *pobj with the address of the symbolic factorization IVL object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int Bridge_symbfacIVL ( Bridge *bridge, IVL **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in Bridge_symbfacIVL" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in Bridge_symbfacIVL" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->symbfacIVL ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- load *pobj with the address of the submatrix manager object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca ----------------------------------------- */ int Bridge_mtxmanager ( Bridge *bridge, SubMtxManager **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in Bridge_mtxmanager" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in Bridge_mtxmanager" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->mtxmanager ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- load *pobj with the address of the front matrix object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int Bridge_frontmtx ( Bridge *bridge, FrontMtx **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in Bridge_frontmtx" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in Bridge_frontmtx" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->frontmtx ; return(1) ; } /*--------------------------------------------------------------------*/ idge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------LinSol/srcST/setparams.c010060000020550007177000000132020662007040700164610ustar00clevecompmath00000400000006/* setparams.c */ #include "../Bridge.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to set the matrix parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- neqns <= 0 -3 -- type is invalid -4 -- symmetryflag is invalid -5 -- matrix is hermitian but type is real created -- 98sep25, cca ------------------------------------------- */ int Bridge_setMatrixParams ( Bridge *bridge, int neqns, int type, int symmetryflag ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in Bridge_setMatrixParams()" "\n bridge is NULL\n") ; return(-1) ; } if ( neqns <= 0 ) { fprintf(stderr, "\n\n error in Bridge_setMatrixParams()" "\n neqns = %d\n", neqns) ; return(-2) ; } if ( type != SPOOLES_REAL && type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n\n error in Bridge_setMatrixParams()" "\n type = %d\n", type) ; return(-3) ; } switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : break ; case SPOOLES_HERMITIAN : if ( type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n\n error in Bridge_setMatrixParams()" "\n type = %d\n", type) ; return(-5) ; } break ; case SPOOLES_NONSYMMETRIC : break ; default : if ( type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n\n error in Bridge_setMatrixParams()" "\n symmetryflag = %d\n", symmetryflag) ; return(-4) ; } break ; } bridge->neqns = neqns ; bridge->type = type ; bridge->symmetryflag = symmetryflag ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to set the ordering parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- maxdomainsize <= 0 -3 -- maxsize <= 0 -4 -- compressCutoff > 1.0 created -- 98sep25, cca ------------------------------------------- */ int Bridge_setOrderingParams ( Bridge *bridge, int maxdomainsize, int maxnzeros, int maxsize, int seed, double compressCutoff ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in Bridge_setOrderingParams()" "\n bridge is NULL\n") ; return(-1) ; } if ( maxdomainsize <= 0 ) { fprintf(stderr, "\n\n error in Bridge_setOrderingParams()" "\n maxdomainsize = %d\n", maxdomainsize) ; return(-2) ; } if ( maxsize <= 0 ) { fprintf(stderr, "\n\n error in Bridge_setOrderingParams()" "\n maxsize = %d\n", maxsize) ; return(-3) ; } if ( compressCutoff > 1.0 ) { fprintf(stderr, "\n\n error in Bridge_setOrderingParams()" "\n compressCutoff = %f\n", compressCutoff) ; return(-4) ; } bridge->maxdomainsize = maxdomainsize ; bridge->maxnzeros = maxnzeros ; bridge->maxsize = maxsize ; bridge->seed = seed ; bridge->compressCutoff = compressCutoff ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to set the factorization parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- sparsityflag is invalid -3 -- pivotingflag is invalid -4 -- tau < 2.0 -5 -- droptol < 0.0 created -- 98sep25, cca ---------------------------------------------- */ int Bridge_setFactorParams ( Bridge *bridge, int sparsityflag, int pivotingflag, double tau, double droptol, PatchAndGoInfo *patchinfo ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in Bridge_setFactorParams()" "\n bridge is NULL\n") ; return(-1) ; } if ( sparsityflag != FRONTMTX_DENSE_FRONTS && sparsityflag != FRONTMTX_SPARSE_FRONTS ) { fprintf(stderr, "\n\n error in Bridge_setFactorParams()" "\n sparsityflag = %d\n", sparsityflag) ; return(-2) ; } if ( pivotingflag != SPOOLES_PIVOTING && pivotingflag != SPOOLES_NO_PIVOTING ) { fprintf(stderr, "\n\n error in Bridge_setFactorParams()" "\n pivotingflag = %d\n", pivotingflag) ; return(-3) ; } if ( tau < 2.0 ) { fprintf(stderr, "\n\n error in Bridge_setFactorParams()" "\n invalid value %f for tau", tau) ; return(-4) ; } if ( droptol < 0.0 ) { fprintf(stderr, "\n\n error in Bridge_setFactorParams()" "\n invalid value %f for droptol", droptol) ; return(-5) ; } bridge->sparsityflag = sparsityflag ; bridge->pivotingflag = pivotingflag ; bridge->tau = tau ; bridge->droptol = droptol ; bridge->patchinfo = patchinfo ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to set the message info return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- msglvl > 0 and msgFile is NULL created -- 98sep18, cca ------------------------------------- */ int Bridge_setMessageInfo ( Bridge *bridge, int msglvl, FILE *msgFile ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in Bridge_setMessageInfo()" "\n bridge is NULL\n") ; return(-1) ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n\n error in Bridge_setMessageInfo()" "\n msglvl is > 0 and msgFile is NULL\n") ; return(-2) ; } bridge->msglvl = msglvl ; bridge->msgFile = msgFile ; return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcST/setup.c010060000020550007177000000154640662007156300156420ustar00clevecompmath00000400000006/* Setup.c */ #include "../Bridge.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- given an InpMtx object that contains the structure of A, initialize the bridge data structure for the serial factor's and solve's. return value -- 1 -- normal return -1 -- bridge is NULL -2 -- mtxA is NULL created -- 98sep17, cca ------------------------------------------------------------------- */ int Bridge_setup ( Bridge *bridge, InpMtx *mtxA ) { double t0, t1, t2 ; ETree *frontETree ; FILE *msgFile ; Graph *graph ; int compressed, msglvl, nedges, neqns, Neqns ; IV *eqmapIV ; IVL *adjIVL, *symbfacIVL ; MARKTIME(t0) ; /* -------------------- check the input data -------------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in Bridge_setup()" "\n data is NULL\n") ; return(-1) ; } if ( mtxA == NULL ) { fprintf(stderr, "\n fatal error in Bridge_setup()" "\n A is NULL\n") ; return(-2) ; } msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; neqns = bridge->neqns ; if ( ! (INPMTX_IS_BY_ROWS(mtxA) || INPMTX_IS_BY_COLUMNS(mtxA)) ) { /* ------------------------------ change coordinate type to rows ------------------------------ */ InpMtx_changeCoordType(mtxA, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(mtxA) ) { /* ------------------------------ change storage mode to vectors ------------------------------ */ InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; } /* --------------------------- create a Graph object for A --------------------------- */ MARKTIME(t1) ; graph = Graph_new() ; adjIVL = InpMtx_fullAdjacency(mtxA); nedges = bridge->nedges = IVL_tsize(adjIVL), Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; MARKTIME(t2) ; bridge->cpus[0] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time to create Graph", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ----------------------- get the equivalence map ----------------------- */ MARKTIME(t1) ; eqmapIV = Graph_equivMap(graph) ; Neqns = bridge->Neqns = 1 + IV_max(eqmapIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph's equivalence map") ; IV_writeForHumanEye(eqmapIV, msgFile) ; fflush(msgFile) ; } if ( Neqns < bridge->compressCutoff * neqns ) { Graph *cgraph ; /* ------------------ compress the graph ------------------ */ cgraph = Graph_compress2(graph, eqmapIV, 1) ; Graph_free(graph) ; graph = cgraph ; compressed = 1 ; bridge->Nedges = graph->nedges ; } else { compressed = 0 ; } MARKTIME(t2) ; bridge->cpus[1] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time to create compressed graph", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n graph to order") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* --------------- order the graph --------------- */ MARKTIME(t1) ; if ( bridge->maxdomainsize <= 0 ) { bridge->maxdomainsize = neqns/32 ; } if ( bridge->maxdomainsize <= 0 ) { bridge->maxdomainsize = 1 ; } if ( bridge->maxnzeros < 0 ) { bridge->maxnzeros = 0.01*neqns ; } if ( bridge->maxsize < 0 ) { bridge->maxsize = neqns ; } frontETree = orderViaBestOfNDandMS(graph, bridge->maxdomainsize, bridge->maxnzeros, bridge->maxsize, bridge->seed, msglvl, msgFile) ; bridge->frontETree = frontETree ; MARKTIME(t2) ; bridge->cpus[2] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time to order graph", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(bridge->frontETree, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; if ( compressed == 1 ) { ETree *etree ; IVL *tempIVL ; /* ---------------------------------------------------------- compute the symbolic factorization of the compressed graph ---------------------------------------------------------- */ tempIVL = SymbFac_initFromGraph(frontETree, graph) ; /* ------------------------------------------------------- expand the symbolic factorization to the original graph ------------------------------------------------------- */ symbfacIVL = IVL_expand(tempIVL, eqmapIV) ; IVL_free(tempIVL) ; /* --------------------- expand the front tree --------------------- */ etree = ETree_expand(frontETree, eqmapIV) ; ETree_free(frontETree) ; frontETree = etree ; } else { /* -------------------------------------------------------- compute the symbolic factorization of the original graph -------------------------------------------------------- */ symbfacIVL = SymbFac_initFromGraph(frontETree, graph) ; } MARKTIME(t2) ; bridge->frontETree = frontETree ; bridge->symbfacIVL = symbfacIVL ; /* ---------------------------------------------- get the old-to-new and new-to-old permutations ---------------------------------------------- */ bridge->oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; bridge->newToOldIV = ETree_newToOldVtxPerm(frontETree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n old-to-new permutation") ; IV_writeForHumanEye(bridge->oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation") ; IV_writeForHumanEye(bridge->newToOldIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------ overwrite the symbolic factorization with the permuted indices and sort the lists into ascending order ------------------------------------------------------ */ IVL_overwrite(symbfacIVL, bridge->oldToNewIV) ; IVL_sortUp(symbfacIVL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /* -------------------------------------- permute the vertices in the front tree -------------------------------------- */ ETree_permuteVertices(frontETree, bridge->oldToNewIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted front etree") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } MARKTIME(t2) ; bridge->cpus[3] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time for symbolic factorization", t2 - t1) ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; IV_free(eqmapIV) ; MARKTIME(t2) ; bridge->cpus[4] += t2 - t0 ; return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcST/solve.c010060000020550007177000000074430661671126700156370ustar00clevecompmath00000400000006/* solve.c */ #include "../Bridge.h" /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to solve the linear system return value --- 1 -- normal return -1 -- bridge is NULL -2 -- X is NULL -3 -- Y is NULL -4 -- frontmtx is NULL -5 -- mtxmanager is NULL -6 -- oldToNewIV not available -7 -- newToOldIV not available created -- 98sep18, cca ------------------------------------- */ int Bridge_solve ( Bridge *bridge, int permuteflag, DenseMtx *X, DenseMtx *Y ) { double cputotal, nops, t0, t1, t2 ; double cpus[6] ; FILE *msgFile ; FrontMtx *frontmtx ; int msglvl ; SubMtxManager *mtxmanager ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( bridge == NULL ) { fprintf(stderr, "\n error in Bridge_solve" "\n bridge is NULL\n") ; return(-1) ; } if ( X == NULL ) { fprintf(stderr, "\n error in Bridge_solve" "\n X is NULL\n") ; return(-2) ; } if ( Y == NULL ) { fprintf(stderr, "\n error in Bridge_solve" "\n Y is NULL\n") ; return(-3) ; } if ( (frontmtx = bridge->frontmtx) == NULL ) { fprintf(stderr, "\n error in Bridge_solve" "\n frontmtx is NULL\n") ; return(-4) ; } if ( (mtxmanager = bridge->mtxmanager) == NULL ) { fprintf(stderr, "\n error in Bridge_solve" "\n mtxmanager is NULL\n") ; return(-5) ; } msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; /* -------------------------- optionally permute the rhs -------------------------- */ if ( permuteflag == 1 ) { int rc ; IV *oldToNewIV ; MARKTIME(t1) ; rc = Bridge_oldToNewIV(bridge, &oldToNewIV) ; if (rc != 1) { fprintf(stderr, "\n error in Bridge_solve()" "\n rc = %d from Bridge_oldToNewIV()\n", rc) ; return(-6) ; } DenseMtx_permuteRows(Y, oldToNewIV) ; MARKTIME(t2) ; bridge->cpus[10] += t2 - t1 ; } /* ---------------- solve the system ---------------- */ nops = ETree_nFactorEntries(bridge->frontETree, bridge->symmetryflag) ; nops *= 2 * X->ncol ; if ( bridge->type == SPOOLES_COMPLEX ) { nops *= 4 ; } MARKTIME(t1) ; DVzero(6, cpus) ; FrontMtx_solve(frontmtx, X, Y, mtxmanager, cpus, msglvl, msgFile) ; MARKTIME(t2) ; bridge->cpus[11] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : solve the system, %.3f mflops", t2 - t1, 1.e-6*nops/(t2 - t1)) ; } cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(X, msgFile) ; fflush(stdout) ; } /* ------------------------------- optionally permute the solution ------------------------------- */ if ( permuteflag == 1 ) { int rc ; IV *newToOldIV ; MARKTIME(t1) ; rc = Bridge_newToOldIV(bridge, &newToOldIV) ; if (rc != 1) { fprintf(stderr, "\n error in Bridge_solve()" "\n rc = %d from Bridge_newToOldIV()\n", rc) ; return(-7) ; } DenseMtx_permuteRows(X, newToOldIV) ; MARKTIME(t2) ; bridge->cpus[12] += t2 - t1 ; } MARKTIME(t2) ; bridge->cpus[13] += t2 - t0 ; return(1) ; } /*--------------------------------------------------------------------*/ -3 -- Y is NULL -4 -- frontmtx is NULL -5 -- mtxmanager is NULL -6 -- oldToNewIV not available -7 -- newToOldIV not available created -- 98sep18, cca ------------------------------------- LinSol/srcMT/makefile010060000020550007177000000007140661671126700160270ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = BridgeMT $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(factor.o) \ $(OBJ).a(factorSetup.o) \ $(OBJ).a(info.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(setparams.o) \ $(OBJ).a(setup.o) \ $(OBJ).a(solve.o) \ $(OBJ).a(solveSetup.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o LinSol/srcMT/basics.c010060000020550007177000000077240662007067100157370ustar00clevecompmath00000400000006/* basics.C */ #include "../BridgeMT.h" /*--------------------------------------------------------------------*/ /* ----------------------- constructor method created -- 98sep18, cca ----------------------- */ BridgeMT * BridgeMT_new ( void ) { BridgeMT *bridge ; ALLOCATE(bridge, struct _BridgeMT, 1) ; BridgeMT_setDefaultFields(bridge) ; return(bridge) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int BridgeMT_setDefaultFields ( BridgeMT *bridge ) { if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in BridgeMT_setDefaultFields(%p)" "\n bad input\n", bridge) ; return(-1) ; } /* ---------------- graph statistics ---------------- */ bridge->neqns = 0 ; bridge->nedges = 0 ; bridge->Neqns = 0 ; bridge->Nedges = 0 ; /* ------------------- ordering parameters ------------------- */ bridge->compressCutoff = 0.0 ; bridge->maxdomainsize = -1 ; bridge->maxnzeros = -1 ; bridge->maxsize = -1 ; bridge->seed = -1 ; /* ------------------------------- matrix/factorization parameters ------------------------------- */ bridge->type = SPOOLES_REAL ; bridge->symmetryflag = SPOOLES_SYMMETRIC ; bridge->sparsityflag = FRONTMTX_DENSE_FRONTS ; bridge->pivotingflag = SPOOLES_NO_PIVOTING ; bridge->tau = 100.0 ; bridge->droptol = 1.e-3 ; bridge->lookahead = 0 ; bridge->patchinfo = NULL ; /* ------------------------ multithreaded parameters ------------------------ */ bridge->nthread = 0 ; bridge->ownersIV = NULL ; bridge->solvemap = NULL ; bridge->cumopsDV = NULL ; /* ------------------------------------ message info, statistics and timings ------------------------------------ */ IVzero(6, bridge->stats) ; DVzero(16, bridge->cpus) ; bridge->msglvl = 0 ; bridge->msgFile = stdout ; /* ------------------- pointers to objects ------------------- */ bridge->frontETree = NULL ; bridge->symbfacIVL = NULL ; bridge->mtxmanager = NULL ; bridge->frontmtx = NULL ; bridge->oldToNewIV = NULL ; bridge->newToOldIV = NULL ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int BridgeMT_clearData ( BridgeMT *bridge ) { if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in BridgeMT_clearData(%p)" "\n bad input\n", bridge) ; return(-1) ; } if ( bridge->frontmtx != NULL ) { FrontMtx_free(bridge->frontmtx) ; } if ( bridge->frontETree != NULL ) { ETree_free(bridge->frontETree) ; } if ( bridge->symbfacIVL != NULL ) { IVL_free(bridge->symbfacIVL) ; } if ( bridge->mtxmanager != NULL ) { SubMtxManager_free(bridge->mtxmanager) ; } if ( bridge->oldToNewIV != NULL ) { IV_free(bridge->oldToNewIV) ; } if ( bridge->newToOldIV != NULL ) { IV_free(bridge->newToOldIV) ; } if ( bridge->ownersIV != NULL ) { IV_free(bridge->ownersIV) ; } if ( bridge->solvemap != NULL ) { SolveMap_free(bridge->solvemap) ; } if ( bridge->cumopsDV != NULL ) { DV_free(bridge->cumopsDV) ; } BridgeMT_setDefaultFields(bridge) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------- destructor return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep18, cca ----------------------- */ int BridgeMT_free ( BridgeMT *bridge ) { if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in BridgeMT_free(%p)" "\n bad input\n", bridge) ; return(-1) ; } BridgeMT_clearData(bridge) ; FREE(bridge) ; return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMT/factor.c010060000020550007177000000153430662007071600157450ustar00clevecompmath00000400000006/* factor.c */ #include "../BridgeMT.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- to permute (if necessary) the original matrix, and to initialize, factor and postprocess the factor matrix return value --- 1 -- normal return, factorization complete 0 -- factorization did not complete, see error flag -1 -- bridge is NULL -2 -- mtxA is NULL -3 -- perror is NULL created -- 98sep18, cca -------------------------------------------------------------- */ int BridgeMT_factor ( BridgeMT *bridge, InpMtx *mtxA, int permuteflag, int *perror ) { Chv *rootchv ; ChvManager *chvmanager ; double cputotal, nfops, t0, t1, t2 ; double cpus[11] ; int msglvl, nzf ; int stats[16] ; FILE *msgFile ; FrontMtx *frontmtx ; SubMtxManager *mtxmanager ; /*--------------------------------------------------------------------*/ MARKTIME(t0) ; /* --------------- check the input --------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_factor()" "\n bridge is NULL\n") ; return(-1) ; } if ( mtxA == NULL ) { fprintf(stderr, "\n error in BridgeMT_factor()" "\n mtxA is NULL\n") ; return(-2) ; } if ( perror == NULL ) { fprintf(stderr, "\n error in BridgeMT_factor()" "\n perror is NULL\n") ; return(-3) ; } msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; /*--------------------------------------------------------------------*/ MARKTIME(t1) ; if ( permuteflag == 1 ) { int *oldToNew = IV_entries(bridge->oldToNewIV) ; /* ------------------------------------------------ permute the input matrix and convert to chevrons ------------------------------------------------ */ InpMtx_permute(mtxA, oldToNew, oldToNew) ; if ( bridge->symmetryflag == SPOOLES_SYMMETRIC || bridge->symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } } if ( ! INPMTX_IS_BY_CHEVRONS(mtxA) ) { InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; } if ( ! INPMTX_IS_BY_VECTORS(mtxA) ) { InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; } MARKTIME(t2) ; bridge->cpus[6] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : permute and format A", t2 - t1) ; fflush(msgFile) ; } /* --------------------------- initialize the front matrix --------------------------- */ MARKTIME(t1) ; if ( (mtxmanager = bridge->mtxmanager) == NULL ) { mtxmanager = bridge->mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, LOCK_IN_PROCESS, 0) ; } if ( (frontmtx = bridge->frontmtx) == NULL ) { frontmtx = bridge->frontmtx = FrontMtx_new() ; } else { FrontMtx_clearData(frontmtx) ; } FrontMtx_init(frontmtx, bridge->frontETree, bridge->symbfacIVL, bridge->type, bridge->symmetryflag, bridge->sparsityflag, bridge->pivotingflag, LOCK_IN_PROCESS, 0, NULL, mtxmanager, msglvl, msgFile) ; frontmtx->patchinfo = bridge->patchinfo ; MARKTIME(t2) ; bridge->cpus[7] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : initialize front matrix", t2 - t1) ; fflush(msgFile) ; } /* ----------------- factor the matrix ----------------- */ nzf = ETree_nFactorEntries(bridge->frontETree, bridge->symmetryflag) ; nfops = ETree_nFactorOps(bridge->frontETree, bridge->type, bridge->symmetryflag) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d factor entries, %.0f factor ops, %8.3f ratio", nzf, nfops, nfops/nzf) ; fflush(msgFile) ; } IVzero(16, stats) ; DVzero(11, cpus) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, LOCK_IN_PROCESS, 1) ; MARKTIME(t1) ; rootchv = FrontMtx_MT_factorInpMtx(frontmtx, mtxA, bridge->tau, bridge->droptol, chvmanager, bridge->ownersIV, bridge->lookahead, perror, cpus, stats, msglvl, msgFile) ; MARKTIME(t2) ; IVcopy(6, bridge->stats, stats) ; bridge->cpus[8] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : factor matrix, %8.3f mflops", t2 - t1, 1.e-6*nfops/(t2-t1)) ; fprintf(msgFile, "\n %8d pivots, %8d pivot tests, %8d delayed vertices" "\n %d entries in D, %d entries in L, %d entries in U", stats[0], stats[1], stats[2], stats[3], stats[4], stats[5]) ; cputotal = cpus[8] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n initialize fronts %8.3f %6.2f" "\n load original entries %8.3f %6.2f" "\n update fronts %8.3f %6.2f" "\n assemble postponed data %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n extract postponed data %8.3f %6.2f" "\n store factor entries %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[6], 100.*cpus[6]/cputotal, cpus[7], 100.*cpus[7]/cputotal, cputotal) ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n submatrix mananger after factorization") ; SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; fprintf(msgFile, "\n\n chevron mananger after factorization") ; ChvManager_writeForHumanEye(chvmanager, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } ChvManager_free(chvmanager) ; if ( *perror >= 0 ) { return(0) ; } /* ----------------------------- post-process the front matrix ----------------------------- */ MARKTIME(t1) ; FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; MARKTIME(t2) ; bridge->cpus[9] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : post-process the matrix", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n submatrix mananger after post-processing") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ MARKTIME(t2) ; bridge->cpus[10] += t2 - t0 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : total factor time", t2 - t0) ; fflush(msgFile) ; } return(1) ; } /*--------------------------------------------------------------------*/ ront matrix", t2 - t1) ; fflush(msgFile) ; } /* ----------------- factor the matrix ----------------- */ nzf = ETree_nFactorEntries(bridge->frontETree, bridge->symmetryflag) ; nfops = ETree_nFactorOps(bridge->frontETree, bridge->type, bridge->syLinSol/srcMT/factorSetup.c010060000020550007177000000071730661741101300167630ustar00clevecompmath00000400000006/* factorSetup.c */ #include "../BridgeMT.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to construct the map from fronts to threads, and compute operations for each thread. nthread -- number of threads maptype -- type of map for parallel factorization maptype = 1 --> wrap map maptype = 2 --> balanced map maptype = 3 --> subtree-subset map maptype = 4 --> domain decomposition map cutoff -- used when maptype = 4 as upper bound on relative domain size default is maptype = 4 and cutoff = 1/(2*nthread) return value -- 1 -- success -1 -- bridge is NULL -2 -- nthread is invalid, must be > 0 -3 -- front tree is NULL created -- 98sep24, cca ------------------------------------------------------- */ int BridgeMT_factorSetup ( BridgeMT *bridge, int nthread, int maptype, double cutoff ) { double t1, t2 ; DV *cumopsDV ; ETree *frontETree ; FILE *msgFile ; int msglvl ; /* --------------- check the input --------------- */ MARKTIME(t1) ; if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_factorSetup()" "\n bridge is NULL") ; return(-1) ; } if ( nthread < 1 ) { fprintf(stderr, "\n error in BridgeMT_factorSetup()" "\n nthread = %d, is invalid", nthread) ; return(-2) ; } if ( (frontETree = bridge->frontETree) == NULL ) { fprintf(stderr, "\n error in BridgeMT_factorSetup()" "\n frontETree is NULL") ; return(-5) ; } bridge->nthread = nthread ; /* ------------------------------------------- allocate and initialize the cumopsDV object ------------------------------------------- */ if ( (cumopsDV = bridge->cumopsDV) == NULL ) { cumopsDV = bridge->cumopsDV = DV_new() ; } DV_setSize(cumopsDV, nthread) ; DV_zero(cumopsDV) ; /* ---------------------------- create the owners map object ---------------------------- */ switch ( maptype ) { case 1 : bridge->ownersIV = ETree_wrapMap(frontETree, bridge->type, bridge->symmetryflag, cumopsDV) ; break ; case 2 : bridge->ownersIV = ETree_balancedMap(frontETree, bridge->type, bridge->symmetryflag, cumopsDV) ; break ; case 3 : bridge->ownersIV = ETree_subtreeSubsetMap(frontETree, bridge->type, bridge->symmetryflag, cumopsDV) ; break ; case 4 : bridge->ownersIV = ETree_ddMap(frontETree, bridge->type, bridge->symmetryflag, cumopsDV, cutoff) ; break ; default : bridge->ownersIV = ETree_ddMap(frontETree, bridge->type, bridge->symmetryflag, cumopsDV, 1./(2*nthread)) ; break ; } MARKTIME(t2) ; bridge->cpus[5] = t2 - t1 ; msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n parallel factor setup") ; fprintf(msgFile, "\n type = %d, symmetryflag = %d", bridge->type, bridge->symmetryflag) ; fprintf(msgFile, "\n total factor operations = %.0f", DV_sum(cumopsDV)) ; fprintf(msgFile, "\n upper bound on speedup due to load balance = %.2f", DV_max(cumopsDV)/DV_sum(cumopsDV)) ; fprintf(msgFile, "\n operations distributions over threads") ; DV_writeForHumanEye(cumopsDV, msgFile) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n owners map IV object") ; IV_writeForHumanEye(bridge->ownersIV, msgFile) ; fflush(msgFile) ; } return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMT/info.c010060000020550007177000000073000661671126700154240ustar00clevecompmath00000400000006/* info.c */ #include "../BridgeMT.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- generate and return some statistics about the factor and solve type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry type SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC on return --- *pnfront -- # of fronts *pnfactorind -- # of factor indices *pnfactorent -- # of factor entries *pnsolveops -- # of solve operations *pnfactorops -- # of factor operations return values -- 1 -- normal return -1 -- bridge is NULL -2 -- type is bad, must be SPOOLES_REAL or SPOOLES_COMPLEX -3 -- symmetryflag is bad, must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC -4 -- type and symmetryflag mismatch -5 -- front tree is not present -6 -- pnfront is NULL -7 -- pnfactorind is NULL -8 -- pnfactorent is NULL -9 -- pnsolveops is NULL -10 -- pnfactorops is NULL created -- 98oct01, cca -------------------------------------------------------------- */ int BridgeMT_factorStats ( BridgeMT *bridge, int type, int symmetryflag, int *pnfront, int *pnfactorind, int *pnfactorent, int *pnsolveops, double *pnfactorops ) { ETree *etree ; int nentD, nentU ; /* --------------- check the input --------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n bridge is NULL\n") ; return(-1) ; } switch ( type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n error in Bridge_factorStats()" "\n bad type %d\n", type) ; return(-3) ; break ; } switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n error in Bridge_factorStats()" "\n bad symmetryflag %d\n", symmetryflag) ; return(-3) ; break ; } if ( type == SPOOLES_REAL && symmetryflag == SPOOLES_HERMITIAN ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n type %d, symmetryflag %d, mismatch\n", type, symmetryflag) ; return(-4) ; } if ( (etree = bridge->frontETree) == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n front tree is not present\n") ; return(-5) ; } if ( pnfront == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n pnfront is NULL\n") ; return(-6) ; } if ( pnfactorind == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n pnfactorind is NULL\n") ; return(-7) ; } if ( pnfactorent == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n pnfactorent is NULL\n") ; return(-8) ; } if ( pnsolveops == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n pnsolveops is NULL\n") ; return(-9) ; } if ( pnfactorops == NULL ) { fprintf(stderr, "\n error in Bridge_factorStats()" "\n pnfactorops is NULL\n") ; return(-10) ; } *pnfront = ETree_nfront(etree) ; *pnfactorind = ETree_nFactorIndices(etree) ; *pnfactorent = ETree_nFactorEntries(etree, symmetryflag) ; *pnfactorops = ETree_nFactorOps(etree, type, symmetryflag) ; nentD = etree->nvtx ; nentU = *pnfactorent - nentD ; switch ( type ) { case SPOOLES_REAL : *pnsolveops = 4*nentU + nentD ; break ; case SPOOLES_COMPLEX : *pnsolveops = 16*nentU + 8*nentD ; break ; } return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMT/instance.c010060000020550007177000000202650661671126700163020ustar00clevecompmath00000400000006/* instance.c */ #include "../BridgeMT.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- load *pobj with the address of the old-to-new permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMT_oldToNewIV ( BridgeMT *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_oldToNewIV" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMT_oldToNewIV" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->oldToNewIV ; return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- load *pobj with the address of the new-to-old permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMT_newToOldIV ( BridgeMT *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_newToOldIV" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMT_newToOldIV" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->newToOldIV ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- load *pobj with the address of the front ETree object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int BridgeMT_frontETree ( BridgeMT *bridge, ETree **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_frontETree" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMT_frontETree" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->frontETree ; return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- load *pobj with the address of the symbolic factorization IVL object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMT_symbfacIVL ( BridgeMT *bridge, IVL **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_symbfacIVL" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMT_symbfacIVL" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->symbfacIVL ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- load *pobj with the address of the submatrix manager object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca ----------------------------------------- */ int BridgeMT_mtxmanager ( BridgeMT *bridge, SubMtxManager **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_mtxmanager" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMT_mtxmanager" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->mtxmanager ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- load *pobj with the address of the front matrix object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int BridgeMT_frontmtx ( BridgeMT *bridge, FrontMtx **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_frontmtx" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMT_frontmtx" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->frontmtx ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- load *pobj with the address of the owners IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep24, cca -------------------------------------- */ int BridgeMT_ownersIV ( BridgeMT *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_ownersIV" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMT_ownersIV" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->ownersIV ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- load *pobj with the address of the solve map SolveMap object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep24, cca ----------------------------------------- */ int BridgeMT_solvemap ( BridgeMT *bridge, SolveMap **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_solvemap" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMT_solvemap" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->solvemap ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- load *pnthread with the number of threads return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pnthread is NULL created -- 98sep24, cca ---------------------------------------------------- */ int BridgeMT_nthread ( BridgeMT *bridge, int *pnthread ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_nthread" "\n bridge is NULL\n") ; return(-1) ; } if ( pnthread == NULL ) { fprintf(stderr, "\n error in BridgeMT_nthread" "\n pnthread is NULL\n") ; return(-2) ; } *pnthread = bridge->nthread ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- load *plookahead with the lookahead parameter return value -- 1 -- normal return -1 -- bridge is NULL -2 -- plookahead is NULL created -- 98sep24, cca -------------------------------------------------------- */ int BridgeMT_lookahead ( BridgeMT *bridge, int *plookahead ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_lookahead" "\n bridge is NULL\n") ; return(-1) ; } if ( plookahead == NULL ) { fprintf(stderr, "\n error in BridgeMT_lookahead" "\n plookahead is NULL\n") ; return(-2) ; } *plookahead = bridge->lookahead ; return(1) ; } /*--------------------------------------------------------------------*/ created -- 98sep18, cca --------------------------------------------- */ int BridgeMT_newToOldIV ( BridgeMT *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_newToOldIV" "\n bridge is NULL\n") ; LinSol/srcMT/setparams.c010060000020550007177000000137250661736605700165040ustar00clevecompmath00000400000006/* setparams.c */ #include "../BridgeMT.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to set the matrix parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- neqns <= 0 -3 -- type is invalid -4 -- symmetryflag is invalid -5 -- matrix is hermitian but type is real created -- 98sep25, cca ------------------------------------------- */ int BridgeMT_setMatrixParams ( BridgeMT *bridge, int neqns, int type, int symmetryflag ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in BridgeMT_setMatrixParams()" "\n bridge is NULL\n") ; return(-1) ; } if ( neqns <= 0 ) { fprintf(stderr, "\n\n error in BridgeMT_setMatrixParams()" "\n neqns = %d\n", neqns) ; return(-2) ; } if ( type != SPOOLES_REAL && type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n\n error in BridgeMT_setMatrixParams()" "\n type = %d\n", type) ; return(-3) ; } switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : break ; case SPOOLES_HERMITIAN : if ( type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n\n error in BridgeMT_setMatrixParams()" "\n type = %d\n", type) ; return(-5) ; } break ; case SPOOLES_NONSYMMETRIC : break ; default : if ( type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n\n error in BridgeMT_setMatrixParams()" "\n symmetryflag = %d\n", symmetryflag) ; return(-4) ; } break ; } bridge->neqns = neqns ; bridge->type = type ; bridge->symmetryflag = symmetryflag ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to set the ordering parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- maxdomainsize <= 0 -3 -- maxsize <= 0 -4 -- compressCutoff > 1.0 created -- 98sep25, cca ------------------------------------------- */ int BridgeMT_setOrderingParams ( BridgeMT *bridge, int maxdomainsize, int maxnzeros, int maxsize, int seed, int compressCutoff ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in BridgeMT_setOrderingParams()" "\n bridge is NULL\n") ; return(-1) ; } if ( maxdomainsize <= 0 ) { fprintf(stderr, "\n\n error in BridgeMT_setOrderingParams()" "\n maxdomainsize = %d\n", maxdomainsize) ; return(-2) ; } if ( maxsize <= 0 ) { fprintf(stderr, "\n\n error in BridgeMT_setOrderingParams()" "\n maxsize = %d\n", maxsize) ; return(-2) ; } if ( compressCutoff > 1.0 ) { fprintf(stderr, "\n\n error in BridgeMT_setOrderingParams()" "\n compressCutoff = %d\n", compressCutoff) ; return(-2) ; } bridge->maxdomainsize = maxdomainsize ; bridge->maxnzeros = maxnzeros ; bridge->maxsize = maxsize ; bridge->seed = seed ; bridge->compressCutoff = compressCutoff ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to set the message info return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- msglvl > 0 and msgFile is NULL created -- 98sep18, cca ------------------------------------- */ int BridgeMT_setMessageInfo ( BridgeMT *bridge, int msglvl, FILE *msgFile ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in BridgeMT_setMessageInfo()" "\n bridge is NULL\n") ; return(-1) ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n\n error in BridgeMT_setMessageInfo()" "\n msglvl is > 0 and msgFile is NULL\n") ; return(-2) ; } bridge->msglvl = msglvl ; bridge->msgFile = msgFile ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to set the factorization parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- sparsityflag is invalid -3 -- pivotingflag is invalid -4 -- tau < 2.0 -5 -- droptol < 0.0 -6 -- lookahead < 0 created -- 98sep25, cca ---------------------------------------------- */ int BridgeMT_setFactorParams ( BridgeMT *bridge, int sparsityflag, int pivotingflag, double tau, double droptol, int lookahead, PatchAndGoInfo *patchinfo ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in BridgeMT_setFactorParams()" "\n bridge is NULL\n") ; return(-1) ; } if ( sparsityflag != FRONTMTX_DENSE_FRONTS && sparsityflag != FRONTMTX_SPARSE_FRONTS ) { fprintf(stderr, "\n\n error in BridgeMT_setFactorParams()" "\n sparsityflag = %d\n", sparsityflag) ; return(-2) ; } if ( pivotingflag != SPOOLES_PIVOTING && pivotingflag != SPOOLES_NO_PIVOTING ) { fprintf(stderr, "\n\n error in BridgeMT_setFactorParams()" "\n pivotingflag = %d\n", pivotingflag) ; return(-3) ; } if ( tau < 2.0 ) { fprintf(stderr, "\n\n error in BridgeMT_setFactorParams()" "\n invalid value %f for tau", tau) ; return(-4) ; } if ( droptol < 0.0 ) { fprintf(stderr, "\n\n error in BridgeMT_setFactorParams()" "\n invalid value %f for droptol", droptol) ; return(-5) ; } if ( lookahead < 0 ) { fprintf(stderr, "\n\n error in BridgeMT_setFactorParams()" "\n invalid value %d for lookahead", lookahead) ; return(-6) ; } bridge->sparsityflag = sparsityflag ; bridge->pivotingflag = pivotingflag ; bridge->tau = tau ; bridge->droptol = droptol ; bridge->lookahead = lookahead ; bridge->patchinfo = patchinfo ; return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMT/setup.c010060000020550007177000000155540662007156100156320ustar00clevecompmath00000400000006/* Setup.c */ #include "../BridgeMT.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- given an InpMtx object that contains the structure of A, initialize the bridge data structure for the serial factor's and solve's. note: all parameters are pointers to be compatible with fortran's call by reference. return value -- 1 -- normal return -1 -- bridge is NULL -2 -- mtxA is NULL created -- 98sep17, cca ------------------------------------------------------------------- */ int BridgeMT_setup ( BridgeMT *bridge, InpMtx *mtxA ) { double t0, t1, t2 ; ETree *frontETree ; FILE *msgFile ; Graph *graph ; int compressed, msglvl, nedges, neqns, Neqns ; IV *eqmapIV ; IVL *adjIVL, *symbfacIVL ; MARKTIME(t0) ; /* -------------------- check the input data -------------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in BridgeMT_setup()" "\n data is NULL\n") ; return(-1) ; } if ( mtxA == NULL ) { fprintf(stderr, "\n fatal error in BridgeMT_setup()" "\n A is NULL\n") ; return(-2) ; } msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; neqns = bridge->neqns ; if ( ! (INPMTX_IS_BY_ROWS(mtxA) || INPMTX_IS_BY_COLUMNS(mtxA)) ) { /* ------------------------------ change coordinate type to rows ------------------------------ */ InpMtx_changeCoordType(mtxA, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(mtxA) ) { /* ------------------------------ change storage mode to vectors ------------------------------ */ InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; } /* --------------------------- create a Graph object for A --------------------------- */ MARKTIME(t1) ; graph = Graph_new() ; adjIVL = InpMtx_fullAdjacency(mtxA); nedges = bridge->nedges = IVL_tsize(adjIVL), Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; MARKTIME(t2) ; bridge->cpus[0] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time to create Graph", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ------------------ compress the graph ------------------ */ MARKTIME(t1) ; eqmapIV = Graph_equivMap(graph) ; Neqns = bridge->Neqns = 1 + IV_max(eqmapIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph's equivalence map") ; IV_writeForHumanEye(eqmapIV, msgFile) ; fflush(msgFile) ; } if ( Neqns < bridge->compressCutoff * neqns ) { Graph *cgraph ; /* ------------------ compress the graph ------------------ */ cgraph = Graph_compress2(graph, eqmapIV, 1) ; Graph_free(graph) ; graph = cgraph ; compressed = 1 ; bridge->Nedges = graph->nedges ; } else { compressed = 0 ; } MARKTIME(t2) ; bridge->cpus[1] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time to create compressed graph", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n graph to order") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* --------------- order the graph --------------- */ MARKTIME(t1) ; if ( bridge->maxdomainsize <= 0 ) { bridge->maxdomainsize = neqns/32 ; } if ( bridge->maxdomainsize <= 0 ) { bridge->maxdomainsize = 1 ; } if ( bridge->maxnzeros < 0 ) { bridge->maxnzeros = 0.01*neqns ; } if ( bridge->maxsize < 0 ) { bridge->maxsize = neqns ; } frontETree = orderViaBestOfNDandMS(graph, bridge->maxdomainsize, bridge->maxnzeros, bridge->maxsize, bridge->seed, msglvl, msgFile) ; MARKTIME(t2) ; bridge->cpus[2] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time to order graph", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; if ( compressed == 1 ) { ETree *etree ; IVL *tempIVL ; /* ---------------------------------------------------------- compute the symbolic factorization of the compressed graph ---------------------------------------------------------- */ tempIVL = SymbFac_initFromGraph(frontETree, graph) ; /* ------------------------------------------------------- expand the symbolic factorization to the original graph ------------------------------------------------------- */ symbfacIVL = IVL_expand(tempIVL, eqmapIV) ; IVL_free(tempIVL) ; /* --------------------- expand the front tree --------------------- */ etree = ETree_expand(frontETree, eqmapIV) ; ETree_free(frontETree) ; frontETree = etree ; } else { /* -------------------------------------------------------- compute the symbolic factorization of the original graph -------------------------------------------------------- */ symbfacIVL = SymbFac_initFromGraph(frontETree, graph) ; } MARKTIME(t2) ; bridge->frontETree = frontETree ; bridge->symbfacIVL = symbfacIVL ; /* ---------------------------------------------- get the old-to-new and new-to-old permutations ---------------------------------------------- */ bridge->oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; bridge->newToOldIV = ETree_newToOldVtxPerm(frontETree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n old-to-new permutation") ; IV_writeForHumanEye(bridge->oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation") ; IV_writeForHumanEye(bridge->newToOldIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------ overwrite the symbolic factorization with the permuted indices and sort the lists into ascending order ------------------------------------------------------ */ IVL_overwrite(symbfacIVL, bridge->oldToNewIV) ; IVL_sortUp(symbfacIVL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /* -------------------------------------- permute the vertices in the front tree -------------------------------------- */ ETree_permuteVertices(frontETree, bridge->oldToNewIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted front etree") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } MARKTIME(t2) ; bridge->cpus[3] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time for symbolic factorization", t2 - t1) ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; IV_free(eqmapIV) ; MARKTIME(t2) ; bridge->cpus[4] += t2 - t0 ; return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMT/solve.c010060000020550007177000000075450661737116200156310ustar00clevecompmath00000400000006/* solve.c */ #include "../BridgeMT.h" /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to solve the linear system return value --- 1 -- normal return -1 -- bridge is NULL -2 -- X is NULL -3 -- Y is NULL -4 -- frontmtx is NULL -5 -- mtxmanager is NULL -6 -- oldToNewIV not available -7 -- newToOldIV not available created -- 98sep18, cca ------------------------------------- */ int BridgeMT_solve ( BridgeMT *bridge, int permuteflag, DenseMtx *X, DenseMtx *Y ) { double cputotal, nops, t0, t1, t2 ; double cpus[6] ; FILE *msgFile ; FrontMtx *frontmtx ; int msglvl ; SubMtxManager *mtxmanager ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMT_solve" "\n bridge is NULL\n") ; return(-1) ; } if ( X == NULL ) { fprintf(stderr, "\n error in BridgeMT_solve" "\n X is NULL\n") ; return(-2) ; } if ( Y == NULL ) { fprintf(stderr, "\n error in BridgeMT_solve" "\n Y is NULL\n") ; return(-3) ; } if ( (frontmtx = bridge->frontmtx) == NULL ) { fprintf(stderr, "\n error in BridgeMT_solve" "\n frontmtx is NULL\n") ; return(-4) ; } if ( (mtxmanager = bridge->mtxmanager) == NULL ) { fprintf(stderr, "\n error in BridgeMT_solve" "\n mtxmanager is NULL\n") ; return(-5) ; } msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; /* -------------------------- optionally permute the rhs -------------------------- */ if ( permuteflag == 1 ) { int rc ; IV *oldToNewIV ; MARKTIME(t1) ; rc = BridgeMT_oldToNewIV(bridge, &oldToNewIV) ; if (rc != 1) { fprintf(stderr, "\n error in BridgeMT_solve()" "\n rc = %d from BridgeMT_oldToNewIV()\n", rc) ; return(-6) ; } DenseMtx_permuteRows(Y, oldToNewIV) ; MARKTIME(t2) ; bridge->cpus[12] += t2 - t1 ; } /* ---------------- solve the system ---------------- */ nops = ETree_nFactorEntries(bridge->frontETree, bridge->symmetryflag) ; nops *= 2 * X->ncol ; if ( bridge->type == SPOOLES_COMPLEX ) { nops *= 4 ; } MARKTIME(t1) ; DVzero(6, cpus) ; FrontMtx_MT_solve(frontmtx, X, Y, mtxmanager, bridge->solvemap, cpus, msglvl, msgFile) ; MARKTIME(t2) ; bridge->cpus[13] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : solve the system, %.3f mflops", t2 - t1, 1.e-6*nops/(t2 - t1)) ; } cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(X, msgFile) ; fflush(stdout) ; } /* ------------------------------- optionally permute the solution ------------------------------- */ if ( permuteflag == 1 ) { int rc ; IV *newToOldIV ; MARKTIME(t1) ; rc = BridgeMT_newToOldIV(bridge, &newToOldIV) ; if (rc != 1) { fprintf(stderr, "\n error in BridgeMT_solve()" "\n rc = %d from BridgeMT_newToOldIV()\n", rc) ; return(-7) ; } DenseMtx_permuteRows(X, newToOldIV) ; MARKTIME(t2) ; bridge->cpus[14] += t2 - t1 ; } MARKTIME(t2) ; bridge->cpus[15] += t2 - t0 ; return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMT/solveSetup.c010060000020550007177000000043230662007103000166220ustar00clevecompmath00000400000006/* solveSetup.c */ #include "../BridgeMT.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to setup for the parallel solve return value --- 1 -- normal return -1 -- bridge is NULL -2 -- frontmtx is NULL -3 -- frontmtx has not yet been postprocessed created -- 98sep24, cca ----------------------------------------------- */ int BridgeMT_solveSetup ( BridgeMT *bridge ) { double t1, t2 ; FILE *msgFile ; FrontMtx *frontmtx ; int msglvl ; SolveMap *solvemap ; /* --------------- check the input --------------- */ MARKTIME(t1) ; if ( bridge == NULL ) { fprintf(stderr, "\n\n error in BridgeMT_solveSetup()" "\n bridge is NULL\n") ; return(-1) ; } if ( (frontmtx = bridge->frontmtx) == NULL ) { fprintf(stderr, "\n\n error in BridgeMT_solveSetup()" "\n frontmtx is NULL\n") ; return(-2) ; } if ( ! FRONTMTX_IS_2D_MODE(frontmtx) ) { fprintf(stderr, "\n\n error in BridgeMT_solveSetup()" "\n frontmtx must be in 2-D mode\n") ; return(-2) ; } msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; if ( (solvemap = bridge->solvemap) == NULL ) { solvemap = bridge->solvemap = SolveMap_new() ; } else { SolveMap_clearData(solvemap) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) && FRONTMTX_IS_PIVOTING(frontmtx) ) { SolveMap_ddMap(solvemap, SPOOLES_NONSYMMETRIC, frontmtx->upperblockIVL, frontmtx->lowerblockIVL, bridge->nthread, bridge->ownersIV, frontmtx->tree, bridge->seed, msglvl, msgFile) ; } else { SolveMap_ddMap(solvemap, SPOOLES_SYMMETRIC, frontmtx->upperblockIVL, NULL, bridge->nthread, bridge->ownersIV, frontmtx->tree, bridge->seed, msglvl, msgFile) ; } MARKTIME(t2) ; bridge->cpus[11] = t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n solve map created") ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n SolveMap") ; SolveMap_writeForHumanEye(solvemap, msgFile) ; fflush(msgFile) ; } return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMPI/makefile010060000020550007177000000012520661671126600161310ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- # # set suffix rule *.c --> *.a # .c.a : $(PURIFY) $(CC) -c $(CFLAGS) $(MPI_INCLUDE_DIR) $*.c -o $*.o $(AR) $(ARFLAGS) $(OBJ).a $*.o rm $*.o # #----------------------------------------------------------------------- OBJ = BridgeMPI $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(factor.o) \ $(OBJ).a(factorSetup.o) \ $(OBJ).a(info.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(setparams.o) \ $(OBJ).a(setup.o) \ $(OBJ).a(solve.o) \ $(OBJ).a(solveSetup.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o LinSol/srcMPI/basics.c010060000020550007177000000115760662013335000160360ustar00clevecompmath00000400000006/* basics.C */ #include "../BridgeMPI.h" /*--------------------------------------------------------------------*/ /* ----------------------- constructor method created -- 98sep25, cca ----------------------- */ BridgeMPI * BridgeMPI_new ( void ) { BridgeMPI *bridge ; ALLOCATE(bridge, struct _BridgeMPI, 1) ; BridgeMPI_setDefaultFields(bridge) ; return(bridge) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep25, cca ----------------------- */ int BridgeMPI_setDefaultFields ( BridgeMPI *bridge ) { if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in BridgeMPI_setDefaultFields(%p)" "\n bad input\n", bridge) ; return(-1) ; } /* ---------------- graph statistics ---------------- */ bridge->neqns = 0 ; bridge->nedges = 0 ; bridge->Neqns = 0 ; bridge->Nedges = 0 ; /* ------------------- ordering parameters ------------------- */ bridge->compressCutoff = 0.0 ; bridge->maxdomainsize = -1 ; bridge->maxnzeros = -1 ; bridge->maxsize = -1 ; bridge->seed = -1 ; /* ------------------------------- matrix/factorization parameters ------------------------------- */ bridge->type = SPOOLES_REAL ; bridge->symmetryflag = SPOOLES_SYMMETRIC ; bridge->sparsityflag = FRONTMTX_DENSE_FRONTS ; bridge->pivotingflag = SPOOLES_NO_PIVOTING ; bridge->tau = 100.0 ; bridge->droptol = 1.e-3 ; bridge->patchinfo = NULL ; bridge->lookahead = 0 ; /* --------------------------- MPI information and objects --------------------------- */ bridge->nproc = 0 ; bridge->myid = -1 ; bridge->comm = NULL ; bridge->ownersIV = NULL ; bridge->solvemap = NULL ; bridge->cumopsDV = NULL ; bridge->vtxmapIV = NULL ; bridge->rowmapIV = NULL ; bridge->ownedColumnsIV = NULL ; bridge->Aloc = NULL ; bridge->Xloc = NULL ; bridge->Yloc = NULL ; /* ------------------------------------ message info, statistics and timings ------------------------------------ */ IVzero(6, bridge->stats) ; DVzero(22, bridge->cpus) ; bridge->msglvl = 0 ; bridge->msgFile = stdout ; /* ------------------- pointers to objects ------------------- */ bridge->frontETree = NULL ; bridge->symbfacIVL = NULL ; bridge->mtxmanager = NULL ; bridge->frontmtx = NULL ; bridge->oldToNewIV = NULL ; bridge->newToOldIV = NULL ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep25, cca ----------------------- */ int BridgeMPI_clearData ( BridgeMPI *bridge ) { if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in BridgeMPI_clearData(%p)" "\n bad input\n", bridge) ; return(-1) ; } /* ------------ free objects ------------ */ if ( bridge->frontmtx != NULL ) { FrontMtx_free(bridge->frontmtx) ; } if ( bridge->frontETree != NULL ) { ETree_free(bridge->frontETree) ; } if ( bridge->symbfacIVL != NULL ) { IVL_free(bridge->symbfacIVL) ; } if ( bridge->mtxmanager != NULL ) { SubMtxManager_free(bridge->mtxmanager) ; } if ( bridge->oldToNewIV != NULL ) { IV_free(bridge->oldToNewIV) ; } if ( bridge->newToOldIV != NULL ) { IV_free(bridge->newToOldIV) ; } /* ---------------- free MPI objects ---------------- */ if ( bridge->ownersIV != NULL ) { IV_free(bridge->ownersIV) ; } if ( bridge->solvemap != NULL ) { SolveMap_free(bridge->solvemap) ; } if ( bridge->cumopsDV != NULL ) { DV_free(bridge->cumopsDV) ; } if ( bridge->rowmapIV != bridge->vtxmapIV ) { IV_free(bridge->rowmapIV) ; } if ( bridge->vtxmapIV != NULL ) { IV_free(bridge->vtxmapIV) ; } if ( bridge->ownedColumnsIV != NULL ) { IV_free(bridge->ownedColumnsIV) ; } if ( bridge->Aloc != NULL ) { InpMtx_free(bridge->Aloc) ; } if ( bridge->Xloc != NULL ) { DenseMtx_free(bridge->Xloc) ; } if ( bridge->Yloc != NULL ) { DenseMtx_free(bridge->Yloc) ; } /* ------------------ set default fields ------------------ */ BridgeMPI_setDefaultFields(bridge) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------- destructor return value --- 1 -- normal return -1 -- bridge is NULL created -- 98sep25, cca ----------------------- */ int BridgeMPI_free ( BridgeMPI *bridge ) { if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in BridgeMPI_free(%p)" "\n bad input\n", bridge) ; return(-1) ; } BridgeMPI_clearData(bridge) ; FREE(bridge) ; return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMPI/factor.c010060000020550007177000000207550661671126600160640ustar00clevecompmath00000400000006/* factor.c */ #include "../BridgeMPI.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- to permute (if necessary) the original matrix, and to initialize, factor and postprocess the factor matrix if permuteflag == 1 then matrix is permuted into new ordering endif return value --- 1 -- normal return, factorization complete 0 -- factorization did not complete, see error flag -1 -- bridge is NULL -2 -- perror is NULL created -- 98sep18, cca -------------------------------------------------------------- */ int BridgeMPI_factor ( BridgeMPI *bridge, InpMtx *mtxA, int permuteflag, int *perror ) { Chv *rootchv ; ChvManager *chvmanager ; double cputotal, nfops, t0, t1, t2 ; double cpus[20] ; int firsttag, msglvl, myid, neqns, nproc, nzf ; int stats[20] ; InpMtx *Aloc ; FILE *msgFile ; FrontMtx *frontmtx ; SubMtxManager *mtxmanager ; /*--------------------------------------------------------------------*/ MARKTIME(t0) ; /* --------------- check the input --------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_factor()" "\n bridge is NULL\n") ; return(-1) ; } if ( perror == NULL ) { fprintf(stderr, "\n error in BridgeMPI_factor()" "\n perror is NULL\n") ; return(-2) ; } msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; neqns = bridge->neqns ; myid = bridge->myid ; nproc = bridge->nproc ; if ( msglvl > 1 ) { fprintf(msgFile, "\n all set in BridgeMPI_factor()") ; fprintf(msgFile, "\n myid = %d", myid) ; fprintf(msgFile, "\n permuteflag = %d", permuteflag) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ MARKTIME(t1) ; if ( myid == 0 ) { if ( permuteflag == 1 ) { int *oldToNew = IV_entries(bridge->oldToNewIV) ; /* ------------------------------------------------ permute the input matrix and convert to chevrons ------------------------------------------------ */ InpMtx_permute(mtxA, oldToNew, oldToNew) ; if ( bridge->symmetryflag == SPOOLES_SYMMETRIC || bridge->symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } } if ( ! INPMTX_IS_BY_CHEVRONS(mtxA) ) { InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; } if ( ! INPMTX_IS_BY_VECTORS(mtxA) ) { InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; } MARKTIME(t2) ; bridge->cpus[8] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : permute and format A", t2 - t1) ; fflush(msgFile) ; } } /*--------------------------------------------------------------------*/ /* --------------------------------- distribute the front matrix. processor 0 scatters the entries to all the other processors. -------------------------------- */ MARKTIME(t1) ; if ( myid != 0 ) { mtxA = NULL ; } firsttag = 0 ; IVzero(4, stats) ; Aloc = bridge->Aloc = InpMtx_MPI_splitFromGlobal(mtxA, NULL, bridge->vtxmapIV, 0, stats, msglvl, msgFile, firsttag, bridge->comm) ; if ( Aloc != NULL ) { InpMtx_changeStorageMode(Aloc, INPMTX_BY_VECTORS) ; } MARKTIME(t2) ; bridge->cpus[9] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : distribute A", t2 - t1) ; fflush(msgFile) ; } if ( Aloc != NULL && msglvl > 1 ) { fprintf(msgFile, "\n\n permuted and split InpMtx") ; InpMtx_writeForHumanEye(Aloc, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* --------------------------- initialize the front matrix --------------------------- */ MARKTIME(t1) ; if ( (mtxmanager = bridge->mtxmanager) == NULL ) { mtxmanager = bridge->mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; } if ( (frontmtx = bridge->frontmtx) == NULL ) { frontmtx = bridge->frontmtx = FrontMtx_new() ; } else { FrontMtx_clearData(frontmtx) ; } FrontMtx_init(frontmtx, bridge->frontETree, bridge->symbfacIVL, bridge->type, bridge->symmetryflag, bridge->sparsityflag, bridge->pivotingflag, NO_LOCK, myid, bridge->ownersIV, mtxmanager, bridge->msglvl, bridge->msgFile) ; frontmtx->patchinfo = bridge->patchinfo ; MARKTIME(t2) ; bridge->cpus[10] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : initialize front matrix", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n bridge ownersIV") ; IV_writeForHumanEye(bridge->ownersIV, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------- factor the matrix ----------------- */ nzf = ETree_nFactorEntries(bridge->frontETree, bridge->symmetryflag) ; nfops = ETree_nFactorOps(bridge->frontETree, bridge->type, bridge->symmetryflag) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d factor entries, %.0f factor ops, %8.3f ratio", nzf, nfops, nfops/nzf) ; fflush(msgFile) ; } IVzero(20, stats) ; DVzero(20, cpus) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1) ; MARKTIME(t1) ; rootchv = FrontMtx_MPI_factorInpMtx(frontmtx, Aloc, bridge->tau, bridge->droptol, chvmanager, bridge->ownersIV, bridge->lookahead, perror, cpus, stats, bridge->msglvl, bridge->msgFile, firsttag, bridge->comm) ; MARKTIME(t2) ; firsttag += 4*bridge->frontmtx->nfront ; IVcopy(6, bridge->stats, stats) ; bridge->cpus[11] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : factor matrix, %8.3f mflops", t2 - t1, 1.e-6*nfops/(t2-t1)) ; fprintf(msgFile, "\n %8d pivots, %8d pivot tests, %8d delayed vertices" "\n %d entries in D, %d entries in L, %d entries in U", stats[0], stats[1], stats[2], stats[3], stats[4], stats[5]) ; cputotal = cpus[8] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n initialize fronts %8.3f %6.2f" "\n load original entries %8.3f %6.2f" "\n update fronts %8.3f %6.2f" "\n assemble postponed data %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n extract postponed data %8.3f %6.2f" "\n store factor entries %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[6], 100.*cpus[6]/cputotal, cpus[7], 100.*cpus[7]/cputotal, cputotal) ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n submatrix mananger after factorization") ; SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; fprintf(msgFile, "\n\n chevron mananger after factorization") ; ChvManager_writeForHumanEye(chvmanager, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } ChvManager_free(chvmanager) ; if ( *perror >= 0 ) { return(0) ; } /* ----------------------------- post-process the front matrix ----------------------------- */ MARKTIME(t1) ; IVzero(4, stats) ; FrontMtx_MPI_postProcess(frontmtx, bridge->ownersIV, stats, msglvl, msgFile, firsttag, bridge->comm) ; MARKTIME(t2) ; bridge->cpus[12] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : post-process the matrix", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n submatrix mananger after post-processing") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ MARKTIME(t2) ; bridge->cpus[13] += t2 - t0 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : total factor time", t2 - t0) ; fflush(msgFile) ; } return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMPI/factorSetup.c010060000020550007177000000074750662013366600171060ustar00clevecompmath00000400000006/* factorSetup.c */ #include "../BridgeMPI.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- purpose -- to construct the map from fronts to processors, and compute operations for each processor. maptype -- type of map for parallel factorization maptype = 1 --> wrap map maptype = 2 --> balanced map maptype = 3 --> subtree-subset map maptype = 4 --> domain decomposition map cutoff -- used when maptype = 4 as upper bound on relative domain size return value -- 1 -- success -1 -- bridge is NULL -2 -- front tree is NULL created -- 98sep25, cca ---------------------------------------------------------- */ int BridgeMPI_factorSetup ( BridgeMPI *bridge, int maptype, double cutoff ) { double t1, t2 ; DV *cumopsDV ; ETree *frontETree ; FILE *msgFile ; int msglvl, nproc ; /* --------------- check the input --------------- */ MARKTIME(t1) ; if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_factorSetup()" "\n bridge is NULL") ; return(-1) ; } if ( (frontETree = bridge->frontETree) == NULL ) { fprintf(stderr, "\n error in BridgeMPI_factorSetup()" "\n frontETree is NULL") ; return(-2) ; } nproc = bridge->nproc ; msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; /* ------------------------------------------- allocate and initialize the cumopsDV object ------------------------------------------- */ if ( (cumopsDV = bridge->cumopsDV) == NULL ) { cumopsDV = bridge->cumopsDV = DV_new() ; } DV_setSize(cumopsDV, nproc) ; DV_zero(cumopsDV) ; /* ---------------------------- create the owners map object ---------------------------- */ switch ( maptype ) { case 1 : bridge->ownersIV = ETree_wrapMap(frontETree, bridge->type, bridge->symmetryflag, cumopsDV) ; break ; case 2 : bridge->ownersIV = ETree_balancedMap(frontETree, bridge->type, bridge->symmetryflag, cumopsDV) ; break ; case 3 : bridge->ownersIV = ETree_subtreeSubsetMap(frontETree, bridge->type, bridge->symmetryflag, cumopsDV) ; break ; case 4 : bridge->ownersIV = ETree_ddMap(frontETree, bridge->type, bridge->symmetryflag, cumopsDV, cutoff) ; break ; default : bridge->ownersIV = ETree_ddMap(frontETree, bridge->type, bridge->symmetryflag, cumopsDV, 1./(2*nproc)) ; break ; } MARKTIME(t2) ; bridge->cpus[7] = t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n parallel factor setup") ; fprintf(msgFile, "\n type = %d, symmetryflag = %d", bridge->type, bridge->symmetryflag) ; fprintf(msgFile, "\n total factor operations = %.0f", DV_sum(cumopsDV)) ; fprintf(msgFile, "\n upper bound on speedup due to load balance = %.2f", DV_max(cumopsDV)/DV_sum(cumopsDV)) ; fprintf(msgFile, "\n operations distributions over threads") ; DV_writeForHumanEye(cumopsDV, msgFile) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n owners map IV object") ; IV_writeForHumanEye(bridge->ownersIV, msgFile) ; fflush(msgFile) ; } /* ---------------------------- create the vertex map object ---------------------------- */ bridge->vtxmapIV = IV_new() ; IV_init(bridge->vtxmapIV, bridge->neqns, NULL) ; IVgather(bridge->neqns, IV_entries(bridge->vtxmapIV), IV_entries(bridge->ownersIV), ETree_vtxToFront(bridge->frontETree)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n vertex map IV object") ; IV_writeForHumanEye(bridge->vtxmapIV, msgFile) ; fflush(msgFile) ; } return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMPI/info.c010060000020550007177000000073500661671126600155350ustar00clevecompmath00000400000006/* info.c */ #include "../BridgeMPI.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- generate and return some statistics about the factor and solve type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry type SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC on return --- *pnfront -- # of fronts *pnfactorind -- # of factor indices *pnfactorent -- # of factor entries *pnsolveops -- # of solve operations *pnfactorops -- # of factor operations return values -- 1 -- normal return -1 -- bridge is NULL -2 -- type is bad, must be SPOOLES_REAL or SPOOLES_COMPLEX -3 -- symmetryflag is bad, must be SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC -4 -- type and symmetryflag mismatch -5 -- front tree is not present -6 -- pnfront is NULL -7 -- pnfactorind is NULL -8 -- pnfactorent is NULL -9 -- pnsolveops is NULL -10 -- pnfactorops is NULL created -- 98oct01, cca -------------------------------------------------------------- */ int BridgeMPI_factorStats ( BridgeMPI *bridge, int type, int symmetryflag, int *pnfront, int *pnfactorind, int *pnfactorent, int *pnsolveops, double *pnfactorops ) { ETree *etree ; int nentD, nentU ; /* --------------- check the input --------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_factorStats()" "\n bridge is NULL\n") ; return(-1) ; } switch ( type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n error in BridgeMPI_factorStats()" "\n bad type %d\n", type) ; return(-3) ; break ; } switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n error in BridgeMPI_factorStats()" "\n bad symmetryflag %d\n", symmetryflag) ; return(-3) ; break ; } if ( type == SPOOLES_REAL && symmetryflag == SPOOLES_HERMITIAN ) { fprintf(stderr, "\n error in BridgeMPI_factorStats()" "\n type %d, symmetryflag %d, mismatch\n", type, symmetryflag) ; return(-4) ; } if ( (etree = bridge->frontETree) == NULL ) { fprintf(stderr, "\n error in BridgeMPI_factorStats()" "\n front tree is not present\n") ; return(-5) ; } if ( pnfront == NULL ) { fprintf(stderr, "\n error in BridgeMPI_factorStats()" "\n pnfront is NULL\n") ; return(-6) ; } if ( pnfactorind == NULL ) { fprintf(stderr, "\n error in BridgeMPI_factorStats()" "\n pnfactorind is NULL\n") ; return(-7) ; } if ( pnfactorent == NULL ) { fprintf(stderr, "\n error in BridgeMPI_factorStats()" "\n pnfactorent is NULL\n") ; return(-8) ; } if ( pnsolveops == NULL ) { fprintf(stderr, "\n error in BridgeMPI_factorStats()" "\n pnsolveops is NULL\n") ; return(-9) ; } if ( pnfactorops == NULL ) { fprintf(stderr, "\n error in BridgeMPI_factorStats()" "\n pnfactorops is NULL\n") ; return(-10) ; } *pnfront = ETree_nfront(etree) ; *pnfactorind = ETree_nFactorIndices(etree) ; *pnfactorent = ETree_nFactorEntries(etree, symmetryflag) ; *pnfactorops = ETree_nFactorOps(etree, type, symmetryflag) ; nentD = etree->nvtx ; nentU = *pnfactorent - nentD ; switch ( type ) { case SPOOLES_REAL : *pnsolveops = 4*nentU + nentD ; break ; case SPOOLES_COMPLEX : *pnsolveops = 16*nentU + 8*nentD ; break ; } return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMPI/instance.c010060000020550007177000000317770662014046200164050ustar00clevecompmath00000400000006/* instance.c */ #include "../BridgeMPI.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- load *pobj with the address of the old-to-new permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMPI_oldToNewIV ( BridgeMPI *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_oldToNewIV" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_oldToNewIV" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->oldToNewIV ; return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- load *pobj with the address of the new-to-old permutation IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMPI_newToOldIV ( BridgeMPI *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_newToOldIV" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_newToOldIV" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->newToOldIV ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- load *pobj with the address of the front ETree object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int BridgeMPI_frontETree ( BridgeMPI *bridge, ETree **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_frontETree" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_frontETree" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->frontETree ; return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- load *pobj with the address of the symbolic factorization IVL object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca --------------------------------------------- */ int BridgeMPI_symbfacIVL ( BridgeMPI *bridge, IVL **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_symbfacIVL" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_symbfacIVL" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->symbfacIVL ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- load *pobj with the address of the submatrix manager object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca ----------------------------------------- */ int BridgeMPI_mtxmanager ( BridgeMPI *bridge, SubMtxManager **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_mtxmanager" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_mtxmanager" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->mtxmanager ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- load *pobj with the address of the front matrix object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep18, cca -------------------------------------- */ int BridgeMPI_frontmtx ( BridgeMPI *bridge, FrontMtx **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_frontmtx" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_frontmtx" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->frontmtx ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- load *pobj with the address of the owners IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep25, cca -------------------------------------- */ int BridgeMPI_ownersIV ( BridgeMPI *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_ownersIV" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_ownersIV" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->ownersIV ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- load *pobj with the address of the solve map SolveMap object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98sep25, cca ----------------------------------------- */ int BridgeMPI_solvemap ( BridgeMPI *bridge, SolveMap **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_solvemap" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_solvemap" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->solvemap ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- load *pobj with the address of the vtxmap IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98oct01, cca -------------------------------------- */ int BridgeMPI_vtxmapIV ( BridgeMPI *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_vtxmapIV" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_vtxmapIV" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->vtxmapIV ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- load *pobj with the address of the rowmap IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98oct01, cca -------------------------------------- */ int BridgeMPI_rowmapIV ( BridgeMPI *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_rowmapIV" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_rowmapIV" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->rowmapIV ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- load *pobj with the address of the ownedColumns IV object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98oct01, cca ---------------------------------------- */ int BridgeMPI_ownedColumns ( BridgeMPI *bridge, IV **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_ownedColumns" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_ownedColumns" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->ownedColumnsIV ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- load *pobj with the address of the Xloc DenseMtx object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98oct01, cca ---------------------------------------- */ int BridgeMPI_Xloc ( BridgeMPI *bridge, DenseMtx **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_Xloc" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_Xloc" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->Xloc ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- load *pobj with the address of the Yloc DenseMtx object return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pobj is NULL created -- 98oct01, cca ---------------------------------------- */ int BridgeMPI_Yloc ( BridgeMPI *bridge, DenseMtx **pobj ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_Yloc" "\n bridge is NULL\n") ; return(-1) ; } if ( pobj == NULL ) { fprintf(stderr, "\n error in BridgeMPI_Yloc" "\n pobj is NULL\n") ; return(-2) ; } *pobj = bridge->Yloc ; return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- load *pnproc with the number of processors return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pnproc is NULL created -- 98sep18, cca ----------------------------------------------------- */ int BridgeMPI_nproc ( BridgeMPI *bridge, int *pnproc ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_nproc()" "\n bridge is NULL\n") ; return(-1) ; } if ( pnproc == NULL ) { fprintf(stderr, "\n error in BridgeMPI_nproc()" "\n pnproc is NULL\n") ; return(-2) ; } *pnproc = bridge->nproc ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- load *pmyid with the id of this processor return value -- 1 -- normal return -1 -- bridge is NULL -2 -- pmyid is NULL created -- 98sep18, cca ---------------------------------------------------- */ int BridgeMPI_myid ( BridgeMPI *bridge, int *pmyid ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_myid()" "\n bridge is NULL\n") ; return(-1) ; } if ( pmyid == NULL ) { fprintf(stderr, "\n error in BridgeMPI_myid()" "\n pmyid is NULL\n") ; return(-2) ; } *pmyid = bridge->myid ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- load *plookahead with the lookahead value for the factorization return value -- 1 -- normal return -1 -- bridge is NULL -2 -- plookahead is NULL created -- 98sep18, cca ---------------------------------------------------- */ int BridgeMPI_lookahead ( BridgeMPI *bridge, int *plookahead ) { /* ---------------- check the output ---------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_lookahead()" "\n bridge is NULL\n") ; return(-1) ; } if ( plookahead == NULL ) { fprintf(stderr, "\n error in BridgeMPI_lookahead()" "\n plookahead is NULL\n") ; return(-2) ; } *plookahead = bridge->lookahead ; return(1) ; } /*--------------------------------------------------------------------*/ -LinSol/srcMPI/setparams.c010060000020550007177000000160000662014065600165630ustar00clevecompmath00000400000006/* setparams.c */ #include "../BridgeMPI.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to set the matrix parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- neqns <= 0 -3 -- type is invalid -4 -- symmetryflag is invalid -5 -- matrix is hermitian but type is real created -- 98sep25, cca ------------------------------------------- */ int BridgeMPI_setMatrixParams ( BridgeMPI *bridge, int neqns, int type, int symmetryflag ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in BridgeMPI_setMatrixParams()" "\n bridge is NULL\n") ; return(-1) ; } if ( neqns <= 0 ) { fprintf(stderr, "\n\n error in BridgeMPI_setMatrixParams()" "\n neqns = %d\n", neqns) ; return(-2) ; } if ( type != SPOOLES_REAL && type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n\n error in BridgeMPI_setMatrixParams()" "\n type = %d\n", type) ; return(-3) ; } switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : break ; case SPOOLES_HERMITIAN : if ( type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n\n error in BridgeMPI_setMatrixParams()" "\n type = %d\n", type) ; return(-5) ; } break ; case SPOOLES_NONSYMMETRIC : break ; default : if ( type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n\n error in BridgeMPI_setMatrixParams()" "\n symmetryflag = %d\n", symmetryflag) ; return(-4) ; } break ; } bridge->neqns = neqns ; bridge->type = type ; bridge->symmetryflag = symmetryflag ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to set the MPI parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- nproc <= 0 -3 -- myid < 0 or myid >= nproc created -- 98sep25, cca ------------------------------------------- */ int BridgeMPI_setMPIparams ( BridgeMPI *bridge, int nproc, int myid, MPI_Comm comm ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in BridgeMPI_setMPIparams()" "\n bridge is NULL\n") ; return(-1) ; } if ( nproc <= 0 ) { fprintf(stderr, "\n\n error in BridgeMPI_setMPIparams()" "\n nproc = %d\n", nproc) ; return(-2) ; } if ( myid < 0 || myid >= nproc ) { fprintf(stderr, "\n\n error in BridgeMPI_setMPIparams()" "\n myid = %d, nproc = %d\n", myid, nproc) ; return(-3) ; } bridge->nproc = nproc ; bridge->myid = myid ; bridge->comm = comm ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to set the ordering parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- maxdomainsize <= 0 -3 -- maxsize <= 0 -4 -- compressCutoff > 1.0 created -- 98sep25, cca ------------------------------------------- */ int BridgeMPI_setOrderingParams ( BridgeMPI *bridge, int maxdomainsize, int maxnzeros, int maxsize, int seed, int compressCutoff ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in BridgeMPI_setOrderingParams()" "\n bridge is NULL\n") ; return(-1) ; } if ( maxdomainsize <= 0 ) { fprintf(stderr, "\n\n error in BridgeMPI_setOrderingParams()" "\n maxdomainsize = %d\n", maxdomainsize) ; return(-2) ; } if ( maxsize <= 0 ) { fprintf(stderr, "\n\n error in BridgeMPI_setOrderingParams()" "\n maxsize = %d\n", maxsize) ; return(-2) ; } if ( compressCutoff > 1.0 ) { fprintf(stderr, "\n\n error in BridgeMPI_setOrderingParams()" "\n compressCutoff = %d\n", compressCutoff) ; return(-2) ; } bridge->maxdomainsize = maxdomainsize ; bridge->maxnzeros = maxnzeros ; bridge->maxsize = maxsize ; bridge->seed = seed ; bridge->compressCutoff = compressCutoff ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to set the message info return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- msglvl > 0 and msgFile is NULL created -- 98sep25, cca ------------------------------------- */ int BridgeMPI_setMessageInfo ( BridgeMPI *bridge, int msglvl, FILE *msgFile ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in BridgeMPI_setMessageInfo()" "\n bridge is NULL\n") ; return(-1) ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n\n error in BridgeMPI_setMessageInfo()" "\n msglvl is > 0 and msgFile is NULL\n") ; return(-2) ; } bridge->msglvl = msglvl ; bridge->msgFile = msgFile ; return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to set the factorization parameters return value -- 1 -- normal return -1 -- bridge object is NULL -2 -- sparsityflag is invalid -3 -- pivotingflag is invalid -4 -- tau < 2.0 -5 -- droptol < 0.0 -6 -- lookahead < 0 created -- 98sep25, cca ---------------------------------------------- */ int BridgeMPI_setFactorParams ( BridgeMPI *bridge, int sparsityflag, int pivotingflag, double tau, double droptol, int lookahead, PatchAndGoInfo *patchinfo ) { if ( bridge == NULL ) { fprintf(stderr, "\n\n error in BridgeMPI_setFactorParams()" "\n bridge is NULL\n") ; return(-1) ; } if ( sparsityflag != FRONTMTX_DENSE_FRONTS && sparsityflag != FRONTMTX_SPARSE_FRONTS ) { fprintf(stderr, "\n\n error in BridgeMPI_setFactorParams()" "\n sparsityflag = %d\n", sparsityflag) ; return(-2) ; } if ( pivotingflag != SPOOLES_PIVOTING && pivotingflag != SPOOLES_NO_PIVOTING ) { fprintf(stderr, "\n\n error in BridgeMPI_setFactorParams()" "\n pivotingflag = %d\n", pivotingflag) ; return(-3) ; } if ( tau < 2.0 ) { fprintf(stderr, "\n\n error in BridgeMPI_setFactorParams()" "\n invalid value %f for tau", tau) ; return(-4) ; } if ( droptol < 0.0 ) { fprintf(stderr, "\n\n error in BridgeMPI_setFactorParams()" "\n invalid value %f for droptol", droptol) ; return(-5) ; } if ( lookahead < 0 ) { fprintf(stderr, "\n\n error in BridgeMPI_setFactorParams()" "\n invalid value %d for lookahead", lookahead) ; return(-6) ; } bridge->sparsityflag = sparsityflag ; bridge->pivotingflag = pivotingflag ; bridge->tau = tau ; bridge->droptol = droptol ; bridge->lookahead = lookahead ; bridge->patchinfo = patchinfo ; return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMPI/setup.c010060000020550007177000000226350662013523700157360ustar00clevecompmath00000400000006/* Setup.c */ #include "../BridgeMPI.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- given an InpMtx object that contains the structure of A, initialize the bridge data structure for the serial factor's and solve's. return value -- 1 -- normal return -1 -- bridge is NULL -2 -- myid is zero and mtxA is NULL created -- 98sep25, cca ------------------------------------------------------------------- */ int BridgeMPI_setup ( BridgeMPI *bridge, InpMtx *mtxA ) { double t0, t1, t2 ; FILE *msgFile ; int msglvl, myid, neqns, nproc, rc ; MPI_Comm comm ; /*--------------------------------------------------------------------*/ MARKTIME(t0) ; /* -------------------- check the input data -------------------- */ if ( bridge == NULL ) { fprintf(stderr, "\n fatal error in BridgeMPI_setup()" "\n data is NULL\n") ; return(-1) ; } nproc = bridge->nproc ; myid = bridge->myid ; comm = bridge->comm ; msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; neqns = bridge->neqns ; if ( myid == 0 ) { /* ------------------------------------------------ processor 0 does some error checking and broadcasts neqns to the other processors ------------------------------------------------ */ rc = 1 ; if ( mtxA == NULL ) { fprintf(stderr, "\n fatal error in BridgeMPI_setup()" "\n A is NULL\n") ; rc = -2 ; } /* ------------------------ broadcast the error flag ------------------------ */ MPI_Bcast((void *) &rc, 1, MPI_INT, 0, bridge->comm) ; } else { /* --------------------------------------- other processors receive the error flag --------------------------------------- */ MPI_Bcast((void *) &rc, 1, MPI_INT, 0, bridge->comm) ; } if ( rc != 1 ) { /* ---------------------- error detected, return ---------------------- */ return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ processor 0 does all the non-numeric computation (1) orders the graph (2) creates the front tree (3) creates the symbolic factorization ------------------------------------------------ */ if ( myid == 0 ) { ETree *frontETree ; Graph *graph ; int compressed, nedges, Neqns ; IV *eqmapIV ; IVL *adjIVL, *symbfacIVL ; if ( ! (INPMTX_IS_BY_ROWS(mtxA) || INPMTX_IS_BY_COLUMNS(mtxA)) ) { /* ------------------------------ change coordinate type to rows ------------------------------ */ InpMtx_changeCoordType(mtxA, INPMTX_BY_ROWS) ; } if ( ! INPMTX_IS_BY_VECTORS(mtxA) ) { /* ------------------------------ change storage mode to vectors ------------------------------ */ InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; } /* --------------------------- create a Graph object for A --------------------------- */ MARKTIME(t1) ; graph = Graph_new() ; adjIVL = InpMtx_fullAdjacency(mtxA); nedges = bridge->nedges = IVL_tsize(adjIVL), Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; MARKTIME(t2) ; bridge->cpus[0] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time to create Graph", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ----------------------- get the equivalence map ----------------------- */ MARKTIME(t1) ; eqmapIV = Graph_equivMap(graph) ; Neqns = bridge->Neqns = 1 + IV_max(eqmapIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph's equivalence map") ; IV_writeForHumanEye(eqmapIV, msgFile) ; fflush(msgFile) ; } if ( Neqns < bridge->compressCutoff * neqns ) { Graph *cgraph ; /* ------------------ compress the graph ------------------ */ cgraph = Graph_compress2(graph, eqmapIV, 1) ; Graph_free(graph) ; graph = cgraph ; compressed = 1 ; bridge->Nedges = graph->nedges ; } else { compressed = 0 ; } MARKTIME(t2) ; bridge->cpus[1] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time to create compressed graph", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n graph to order") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* --------------- order the graph --------------- */ MARKTIME(t1) ; if ( bridge->maxdomainsize <= 0 ) { bridge->maxdomainsize = neqns/32 ; } if ( bridge->maxdomainsize <= 0 ) { bridge->maxdomainsize = 1 ; } if ( bridge->maxnzeros < 0 ) { bridge->maxnzeros = 0.01*neqns ; } if ( bridge->maxsize < 0 ) { bridge->maxsize = 64 ; } frontETree = orderViaBestOfNDandMS(graph, bridge->maxdomainsize, bridge->maxnzeros, bridge->maxsize, bridge->seed, msglvl, msgFile) ; MARKTIME(t2) ; bridge->cpus[2] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time to order graph", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; if ( compressed == 1 ) { ETree *etree ; IVL *tempIVL ; /* ---------------------------------------------------------- compute the symbolic factorization of the compressed graph ---------------------------------------------------------- */ tempIVL = SymbFac_initFromGraph(frontETree, graph) ; /* ------------------------------------------------------- expand the symbolic factorization to the original graph ------------------------------------------------------- */ symbfacIVL = IVL_expand(tempIVL, eqmapIV) ; IVL_free(tempIVL) ; /* --------------------- expand the front tree --------------------- */ etree = ETree_expand(frontETree, eqmapIV) ; ETree_free(frontETree) ; frontETree = etree ; } else { /* -------------------------------------------------------- compute the symbolic factorization of the original graph -------------------------------------------------------- */ symbfacIVL = SymbFac_initFromGraph(frontETree, graph) ; } MARKTIME(t2) ; bridge->frontETree = frontETree ; bridge->symbfacIVL = symbfacIVL ; /* ---------------------------------------------- get the old-to-new and new-to-old permutations ---------------------------------------------- */ bridge->oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; bridge->newToOldIV = ETree_newToOldVtxPerm(frontETree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n old-to-new permutation") ; IV_writeForHumanEye(bridge->oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation") ; IV_writeForHumanEye(bridge->newToOldIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------ overwrite the symbolic factorization with the permuted indices and sort the lists into ascending order ------------------------------------------------------ */ IVL_overwrite(symbfacIVL, bridge->oldToNewIV) ; IVL_sortUp(symbfacIVL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /* -------------------------------------- permute the vertices in the front tree -------------------------------------- */ ETree_permuteVertices(frontETree, bridge->oldToNewIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted front etree") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } MARKTIME(t2) ; bridge->cpus[3] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : time for symbolic factorization", t2 - t1) ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; IV_free(eqmapIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- processor 0 broadcasts the ETree and the symbolic factorization IVL ------------------------------------------------------------------- */ MPI_Barrier(comm) ; if ( myid == 0 ) { MARKTIME(t1) ; ETree_MPI_Bcast(bridge->frontETree, 0, msglvl, msgFile, comm) ; MARKTIME(t2) ; bridge->cpus[4] += t2 - t1 ; t1 = t2 ; IVL_MPI_Bcast(bridge->symbfacIVL, 0, msglvl, msgFile, comm) ; MARKTIME(t2) ; bridge->cpus[5] += t2 - t1 ; } else { MARKTIME(t1) ; bridge->frontETree = ETree_MPI_Bcast(NULL, 0, msglvl, msgFile, comm); MARKTIME(t2) ; bridge->cpus[4] += t2 - t1 ; t1 = t2 ; bridge->symbfacIVL = IVL_MPI_Bcast(NULL, 0, msglvl, msgFile, comm) ; MARKTIME(t2) ; bridge->cpus[5] += t2 - t1 ; } MARKTIME(t2) ; bridge->cpus[6] += t2 - t0 ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMPI/solve.c010060000020550007177000000164010661671126600157270ustar00clevecompmath00000400000006/* solve.c */ #include "../BridgeMPI.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to solve the linear system MPI version if permuteflag is 1 then rhs is permuted into new ordering solution is permuted into old ordering return value --- 1 -- normal return -1 -- bridge is NULL -2 -- X is NULL -3 -- Y is NULL -4 -- frontmtx is NULL -5 -- mtxmanager is NULL -6 -- oldToNewIV not available -7 -- newToOldIV not available created -- 98sep18, cca -------------------------------------------- */ int BridgeMPI_solve ( BridgeMPI *bridge, int permuteflag, DenseMtx *X, DenseMtx *Y ) { DenseMtx *Xloc, *Yloc ; double cputotal, t0, t1, t2 ; double cpus[6] ; FILE *msgFile ; FrontMtx *frontmtx ; int firsttag, msglvl, myid, nmycol, nrhs, nrow ; int *mycolind, *rowind ; int stats[4] ; IV *mapIV, *ownersIV ; MPI_Comm comm ; SubMtxManager *mtxmanager ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( bridge == NULL ) { fprintf(stderr, "\n error in BridgeMPI_solve" "\n bridge is NULL\n") ; return(-1) ; } if ( (frontmtx = bridge->frontmtx) == NULL ) { fprintf(stderr, "\n error in BridgeMPI_solve" "\n frontmtx is NULL\n") ; return(-4) ; } if ( (mtxmanager = bridge->mtxmanager) == NULL ) { fprintf(stderr, "\n error in BridgeMPI_solve" "\n mtxmanager is NULL\n") ; return(-5) ; } myid = bridge->myid ; comm = bridge->comm ; msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; frontmtx = bridge->frontmtx ; ownersIV = bridge->ownersIV ; Xloc = bridge->Xloc ; Yloc = bridge->Yloc ; if ( myid != 0 ) { X = Y = NULL ; } else { if ( X == NULL ) { fprintf(stderr, "\n error in BridgeMPI_solve" "\n myid 0, X is NULL\n") ; return(-2) ; } if ( Y == NULL ) { fprintf(stderr, "\n error in BridgeMPI_solve" "\n myid 0, Y is NULL\n") ; return(-3) ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside BridgeMPI_solve()") ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile , "\n\n Xloc") ; DenseMtx_writeForHumanEye(Xloc, msgFile) ; fprintf(msgFile , "\n\n Yloc") ; DenseMtx_writeForHumanEye(Yloc, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ if ( myid == 0 ) { /* -------------------------- optionally permute the rhs -------------------------- */ if ( permuteflag == 1 ) { int rc ; IV *oldToNewIV ; MARKTIME(t1) ; rc = BridgeMPI_oldToNewIV(bridge, &oldToNewIV) ; if (rc != 1) { fprintf(stderr, "\n error in BridgeMPI_solve()" "\n rc = %d from BridgeMPI_oldToNewIV()\n", rc) ; return(-6) ; } DenseMtx_permuteRows(Y, oldToNewIV) ; MARKTIME(t2) ; bridge->cpus[15] += t2 - t1 ; if ( msglvl > 2 ) { fprintf(msgFile , "\n\n permuted Y") ; DenseMtx_writeForHumanEye(Y, msgFile) ; fflush(msgFile) ; } } } /*--------------------------------------------------------------------*/ /* ------------------------------------- distribute the right hand side matrix ------------------------------------- */ MARKTIME(t1) ; mapIV = bridge->rowmapIV ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n row map IV object") ; IV_writeForHumanEye(mapIV, msgFile) ; fflush(msgFile) ; } if ( myid == 0 ) { nrhs = Y->ncol ; } else { nrhs = 0 ; } MPI_Bcast((void *) &nrhs, 1, MPI_INT, 0, comm) ; firsttag = 0 ; IVfill(4, stats, 0) ; DenseMtx_MPI_splitFromGlobalByRows(Y, Yloc, mapIV, 0, stats, msglvl, msgFile, firsttag, comm) ; MARKTIME(t2) ; bridge->cpus[16] += t2 - t1 ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n local matrix Y after the split") ; DenseMtx_writeForHumanEye(Yloc, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- initialize the local solution X object -------------------------------------- */ MARKTIME(t1) ; IV_sizeAndEntries(bridge->ownedColumnsIV, &nmycol, &mycolind) ; DenseMtx_init(Xloc, bridge->type, -1, -1, nmycol, nrhs, 1, nmycol) ; if ( nmycol > 0 ) { DenseMtx_rowIndices(Xloc, &nrow, &rowind) ; IVcopy(nmycol, rowind, mycolind) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n local matrix X") ; DenseMtx_writeForHumanEye(Xloc, msgFile) ; fflush(msgFile) ; } } MARKTIME(t2) ; bridge->cpus[17] += t2 - t1 ; /*--------------------------------------------------------------------*/ /* ---------------- solve the system ---------------- */ MARKTIME(t1) ; DVzero(6, cpus) ; FrontMtx_MPI_solve(frontmtx, Xloc, Yloc, mtxmanager, bridge->solvemap, cpus, stats, msglvl, msgFile, firsttag, comm) ; MARKTIME(t2) ; bridge->cpus[18] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : solve the system", t2 - t1) ; } cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(Xloc, msgFile) ; fflush(stdout) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- gather the solution on processor zero ------------------------------------- */ MARKTIME(t1) ; DenseMtx_MPI_mergeToGlobalByRows(X, Xloc, 0, stats, msglvl, msgFile, firsttag, comm) ; MARKTIME(t2) ; bridge->cpus[19] += t2 - t1 ; if ( myid == 0 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n global matrix X in new ordering") ; DenseMtx_writeForHumanEye(X, msgFile) ; fflush(msgFile) ; } } /*--------------------------------------------------------------------*/ /* ------------------------------- optionally permute the solution ------------------------------- */ if ( myid == 0 ) { if ( permuteflag == 1 ) { int rc ; IV *newToOldIV ; rc = BridgeMPI_newToOldIV(bridge, &newToOldIV) ; if (rc != 1) { fprintf(stderr, "\n error in BridgeMPI_solve()" "\n rc = %d from BridgeMPI_newToOldIV()\n", rc) ; return(-7) ; } DenseMtx_permuteRows(X, newToOldIV) ; } MARKTIME(t2) ; bridge->cpus[20] += t2 - t1 ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n global matrix X in old ordering") ; DenseMtx_writeForHumanEye(X, msgFile) ; fflush(msgFile) ; } } MARKTIME(t2) ; bridge->cpus[21] += t2 - t0 ; return(1) ; } /*--------------------------------------------------------------------*/ LinSol/srcMPI/solveSetup.c010060000020550007177000000115600661671126600167510ustar00clevecompmath00000400000006/* solveSetup.c */ #include "../BridgeMPI.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to setup for the parallel solve return value --- 1 -- normal return -1 -- bridge is NULL -2 -- frontmtx is NULL -3 -- frontmtx has not yet been postprocessed created -- 98sep24, cca ----------------------------------------------- */ int BridgeMPI_solveSetup ( BridgeMPI *bridge ) { double t0, t1, t2 ; FILE *msgFile ; FrontMtx *frontmtx ; int firsttag, msglvl, myid, nproc ; int stats[4] ; IV *ownersIV ; MPI_Comm comm ; SolveMap *solvemap ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( bridge == NULL ) { fprintf(stderr, "\n\n error in BridgeMPI_solveSetup()" "\n bridge is NULL\n") ; return(-1) ; } if ( (frontmtx = bridge->frontmtx) == NULL ) { fprintf(stderr, "\n\n error in BridgeMPI_solveSetup()" "\n frontmtx is NULL\n") ; return(-2) ; } if ( ! FRONTMTX_IS_2D_MODE(frontmtx) ) { fprintf(stderr, "\n\n error in BridgeMPI_solveSetup()" "\n frontmtx must be in 2-D mode\n") ; return(-2) ; } msglvl = bridge->msglvl ; msgFile = bridge->msgFile ; myid = bridge->myid ; comm = bridge->comm ; nproc = bridge->nproc ; ownersIV = bridge->ownersIV ; if ( (solvemap = bridge->solvemap) == NULL ) { solvemap = bridge->solvemap = SolveMap_new() ; } else { SolveMap_clearData(solvemap) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) && FRONTMTX_IS_PIVOTING(frontmtx) ) { SolveMap_ddMap(solvemap, SPOOLES_NONSYMMETRIC, frontmtx->upperblockIVL, frontmtx->lowerblockIVL, nproc, ownersIV, frontmtx->tree, bridge->seed, msglvl, msgFile) ; } else { SolveMap_ddMap(solvemap, SPOOLES_SYMMETRIC, frontmtx->upperblockIVL, NULL, nproc, ownersIV, frontmtx->tree, bridge->seed, msglvl, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n solve map created") ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n SolveMap") ; SolveMap_writeForHumanEye(solvemap, msgFile) ; fflush(msgFile) ; } /* ---------------------- split the front matrix ---------------------- */ IVzero(4, stats) ; firsttag = 0 ; MARKTIME(t1) ; FrontMtx_MPI_split(frontmtx, solvemap, stats, msglvl, msgFile, firsttag, comm) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n CPU %8.3f : split the matrix", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n submatrix manager after split") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n frontmtx after split") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /* --------------------------------------- generate bridge->rowmapIV, the map from rows of the factor to owning processors --------------------------------------- */ if ( FRONTMTX_IS_PIVOTING(bridge->frontmtx) ) { /* ----------------------------------------- factorization done with pivoting, row map is different than for the original matrix ----------------------------------------- */ if ( bridge->rowmapIV == NULL ) { /* ------------------------------------------------ this is the first solve since the factorization, create the rowmap IV object ------------------------------------------------ */ bridge->rowmapIV = FrontMtx_MPI_rowmapIV(frontmtx, ownersIV, msglvl, msgFile, comm) ; } } else { /* ------------------------------------------- no pivoting, map is simply the original map ------------------------------------------- */ bridge->rowmapIV = bridge->vtxmapIV ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n row map IV object") ; IV_writeForHumanEye(bridge->rowmapIV, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------- create ownedColumnsIV, a vector of column ids that are owned by this processor. ----------------------------------------- */ bridge->ownedColumnsIV = FrontMtx_ownedColumnsIV(frontmtx, myid, ownersIV, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ownedColumns IV object") ; IV_writeForHumanEye(bridge->ownedColumnsIV, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------- create DenseMtx objects to hold the local solution and right hand side matrices ----------------------------------------- */ bridge->Xloc = DenseMtx_new() ; bridge->Yloc = DenseMtx_new() ; MARKTIME(t2) ; bridge->cpus[14] += t2 - t0 ; return(1) ; } /*--------------------------------------------------------------------*/ tag = 0 ; MARKTIME(t1) ; FrontMtx_MPI_split(frontmtx, solvemap, stats, msglvl, msgFile, firsttag, comm) ; MARKTIME(t2) ; if (LinSol/drivers/do_wrapper010070000020550007177000000007120662007144400170300ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set seed = 10101 set matrices = ../../Matrices/ set matrix = GRD7x7 set neqns = 49 set type = 1 set symmetryflag = 0 set mtxFile = $matrices/$matrix/realsym.inpmtxb set rhsFile = $matrices/$matrix/realrhs.densemtxb set solFile = none testWrapper $msglvl $msgFile \ $neqns $type $symmetryflag \ $mtxFile $rhsFile $solFile $seed LinSol/drivers/do_wrapperMPI010070000020550007177000000016630662013504200173770ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res set seed = 10101 set matrices = ../../Matrices/ set matrix = GRD7x7 set neqns = 49 set type = 1 set symmetryflag = 0 set mtxFile = $matrices/$matrix/realsym.inpmtxb set rhsFile = $matrices/$matrix/realrhs.densemtxb set solFile = none set nproc = 4 # # for solaris with mpich # set pgFile = wrapperMPI.$nproc.pg /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testWrapperMPI $msglvl $msgFile \ $neqns $type $symmetryflag \ $mtxFile $rhsFile $solFile $seed # # for sgi # # mpirun -np $nproc \ # testWrapperMPI $msglvl $msgFile \ # $neqns $type $symmetryflag \ # $mtxFile $rhsFile $solFile $seed # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testWrapperMPI $msglvl $msgFile \ # $neqns $type $symmetryflag \ # $mtxFile $rhsFile $solFile $seed LinSol/drivers/do_wrapperMT010070000020550007177000000007520662013500700172710ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set seed = 10101 set matrices = ../../Matrices/ set matrix = GRD7x7 set neqns = 49 set type = 1 set symmetryflag = 0 set mtxFile = $matrices/$matrix/realsym.inpmtxb set rhsFile = $matrices/$matrix/realrhs.densemtxb set solFile = none set nthread = 2 testWrapperMT $msglvl $msgFile \ $neqns $type $symmetryflag \ $mtxFile $rhsFile $solFile $seed $nthread LinSol/drivers/makefile010060000020550007177000000025000665314257500164510ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- # # set suffix rule *.c --> *.o # .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $(MPI_INCLUDE_DIR) $< # #----------------------------------------------------------------------- # # redefine CC for mpi # # CCmpi = /opt/mpi/bin/mpicc # #----------------------------------------------------------------------- DRIVERS = testWrapper testWrapperMT testWrapperMPI STlib : cd ../srcST ; make Bridge.a MTlib : cd ../srcMT ; make BridgeMT.a cd ../../MT/src ; make spoolesMT.a MPIlib : cd ../srcMPI ; make BridgeMPI.a cd ../../MPI/src ; make spoolesMPI.a LIBS_FOR_ST = ../srcST/Bridge.a ../../spooles.a -lm LIBS_FOR_MT = ../srcMT/BridgeMT.a ../../MT/src/spoolesMT.a \ ../../spooles.a ${THREAD_LIBS} -lm LIBS_FOR_MPI = ../srcMPI/BridgeMPI.a ../../MPI/src/spoolesMPI.a \ ../../spooles.a ${MPI_LIBS} -lm drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testWrapper : STlib testWrapper.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS_FOR_ST} testWrapperMT : MTlib testWrapperMT.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS_FOR_MT} testWrapperMPI : MPIlib testWrapperMPI.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS_FOR_MPI} LinSol/drivers/testWrapper.c010060000020550007177000000215140662007167500174370ustar00clevecompmath00000400000006/* testWrapper.c */ #include "../Bridge.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ----------------------------------------------------------- purpose -- main driver program to solve a linear system where the matrix and rhs are read in from files and the solution is written to a file. created -- 98oct31, cca ----------------------------------------------------------- */ Bridge *bridge ; char *mtxFileName, *rhsFileName, *solFileName ; double nfactorops ; FILE *msgFile ; InpMtx *mtxA ; int error, msglvl, neqns, nfent, nfind, nfront, nrhs, nrow, nsolveops, permuteflag, rc, seed, symmetryflag, type ; DenseMtx *mtxX, *mtxY ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile neqns type symmetryflag" "\n mtxFile rhsFile seed" "\n msglvl -- message level" "\n 0 -- no output" "\n 1 -- timings and statistics" "\n 2 and greater -- lots of output" "\n msgFile -- message file" "\n neqns -- # of equations" "\n type -- type of entries" "\n 1 -- real" "\n 2 -- complex" "\n symmetryflag -- symmetry flag" "\n 0 -- symmetric" "\n 1 -- hermitian" "\n 2 -- nonsymmetric" "\n neqns -- # of equations" "\n mtxFile -- input file for A matrix InpMtx object" "\n must be *.inpmtxf or *.inpmtxb" "\n rhsFile -- input file for Y DenseMtx object" "\n must be *.densemtxf or *.densemtxb" "\n solFile -- output file for X DenseMtx object" "\n must be none, *.densemtxf or *.densemtxb" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } neqns = atoi(argv[3]) ; type = atoi(argv[4]) ; symmetryflag = atoi(argv[5]) ; mtxFileName = argv[6] ; rhsFileName = argv[7] ; solFileName = argv[8] ; seed = atoi(argv[9]) ; fprintf(msgFile, "\n\n %s input :" "\n msglvl = %d" "\n msgFile = %s" "\n neqns = %d" "\n type = %d" "\n symmetryflag = %d" "\n mtxFile = %s" "\n rhsFile = %s" "\n solFile = %s" "\n seed = %d" "\n", argv[0], msglvl, argv[2], neqns, type, symmetryflag, mtxFileName, rhsFileName, solFileName, seed) ; /*--------------------------------------------------------------------*/ /* ------------------ read in the matrix ------------------ */ mtxA = InpMtx_new() ; rc = InpMtx_readFromFile(mtxA, mtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxA from file %s, rc = %d", mtxFileName, rc) ; fflush(msgFile) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n InpMtx object ") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- read in the right hand side matrix ---------------------------------- */ mtxY = DenseMtx_new() ; rc = DenseMtx_readFromFile(mtxY, rhsFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxY from file %s, rc = %d", rhsFileName, rc) ; fflush(msgFile) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n DenseMtx object for right hand side") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } DenseMtx_dimensions(mtxY, &nrow, &nrhs) ; /*--------------------------------------------------------------------*/ /* -------------------------------- create and setup a Bridge object -------------------------------- */ bridge = Bridge_new() ; Bridge_setMatrixParams(bridge, neqns, type, symmetryflag) ; Bridge_setMessageInfo(bridge, msglvl, msgFile) ; rc = Bridge_setup(bridge, mtxA) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from Bridge_setup()", rc) ; exit(-1) ; } fprintf(msgFile, "\n\n ----- SETUP -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to construct Graph" "\n CPU %8.3f : time to compress Graph" "\n CPU %8.3f : time to order Graph" "\n CPU %8.3f : time for symbolic factorization" "\n CPU %8.3f : total setup time\n", bridge->cpus[0], bridge->cpus[1], bridge->cpus[2], bridge->cpus[3], bridge->cpus[4]) ; rc = Bridge_factorStats(bridge, type, symmetryflag, &nfront, &nfind, &nfent, &nsolveops, &nfactorops) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from Bridge_factorStats()", rc) ; exit(-1) ; } fprintf(msgFile, "\n\n factor matrix statistics" "\n %d fronts, %d indices, %d entries" "\n %d solve operations, %12.4e factor operations", nfront, nfind, nfent, nsolveops, nfactorops) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* ----------------- factor the matrix ----------------- */ permuteflag = 1 ; rc = Bridge_factor(bridge, mtxA, permuteflag, &error) ; if ( rc == 1 ) { fprintf(msgFile, "\n\n factorization completed successfully\n") ; } else { fprintf(msgFile, "\n return code from factorization = %d" "\n error code = %d", rc, error) ; exit(-1) ; } fprintf(msgFile, "\n\n ----- FACTORIZATION -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to permute original matrix" "\n CPU %8.3f : time to initialize factor matrix" "\n CPU %8.3f : time to compute factorization" "\n CPU %8.3f : time to post-process factorization" "\n CPU %8.3f : total factorization time\n", bridge->cpus[5], bridge->cpus[6], bridge->cpus[7], bridge->cpus[8], bridge->cpus[9]) ; fprintf(msgFile, "\n\n factorization statistics" "\n %d pivots, %d pivot tests, %d delayed vertices" "\n %d entries in D, %d entries in L, %d entries in U", bridge->stats[0], bridge->stats[1], bridge->stats[2], bridge->stats[3], bridge->stats[4], bridge->stats[5]) ; fprintf(msgFile, "\n\n factorization: raw mflops %8.3f, overall mflops %8.3f", 1.e-6*nfactorops/bridge->cpus[7], 1.e-6*nfactorops/bridge->cpus[9]) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* ---------------- solve the system ---------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; rc = Bridge_solve(bridge, permuteflag, mtxX, mtxY) ; if ( rc == 1 ) { fprintf(msgFile, "\n\n solve completed successfully\n") ; } else { fprintf(msgFile, "\n" " return code from solve = %d\n", rc) ; exit(-1) ; } fprintf(msgFile, "\n\n ----- SOLVE -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to permute rhs into new ordering" "\n CPU %8.3f : time to solve linear system" "\n CPU %8.3f : time to permute solution into old ordering" "\n CPU %8.3f : total solve time\n", bridge->cpus[10], bridge->cpus[11], bridge->cpus[12], bridge->cpus[13]) ; fprintf(msgFile, "\n\n solve: raw mflops %8.3f, overall mflops %8.3f", 1.e-6*nsolveops/bridge->cpus[11], 1.e-6*nsolveops/bridge->cpus[13]) ; fflush(msgFile) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ if ( strcmp(solFileName, "none") != 0 ) { /* ----------------------------------- write the solution matrix to a file ----------------------------------- */ rc = DenseMtx_writeToFile(mtxX, solFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error writing mtxX to file %s, rc = %d", solFileName, rc) ; fflush(msgFile) ; exit(-1) ; } } /*--------------------------------------------------------------------*/ /* --------------------- free the working data --------------------- */ InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxY) ; Bridge_free(bridge) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ LinSol/drivers/testWrapperMPI.c010060000020550007177000000310470662013703300177760ustar00clevecompmath00000400000006/* testWrapperMPI.c */ #include "../BridgeMPI.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ----------------------------------------------------------- purpose -- main driver program to solve a linear system where the matrix and rhs are read in from files and the solution is written to a file. NOTE: MPI version created -- 98sep25, cca and pjs ----------------------------------------------------------- */ BridgeMPI *bridge ; char *mtxFileName, *rhsFileName, *solFileName ; double nfactorops ; FILE *msgFile ; InpMtx *mtxA ; int error, msglvl, myid, neqns, nfent, nfind, nfront, nproc, nrhs, nrow, nsolveops, permuteflag, rc, seed, symmetryflag, type ; int tstats[6] ; DenseMtx *mtxX, *mtxY ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile neqns type symmetryflag" "\n mtxFile rhsFile solFile seed" "\n msglvl -- message level" "\n 0 -- no output" "\n 1 -- timings and statistics" "\n 2 and greater -- lots of output" "\n msgFile -- message file" "\n neqns -- # of equations" "\n type -- type of entries" "\n 1 -- real" "\n 2 -- complex" "\n symmetryflag -- symmetry flag" "\n 0 -- symmetric" "\n 1 -- hermitian" "\n 2 -- nonsymmetric" "\n mtxFile -- input file for A matrix InpMtx object" "\n must be *.inpmtxf or *.inpmtxb" "\n rhsFile -- input file for Y DenseMtx object" "\n must be *.densemtxf or *.densemtxb" "\n solFile -- output file for X DenseMtx object" "\n must be none, *.densemtxf or *.densemtxb" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { int length = strlen(argv[2]) + 1 + 4 ; char *buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; MPI_Finalize() ; return(0) ; } CVfree(buffer) ; } neqns = atoi(argv[3]) ; type = atoi(argv[4]) ; symmetryflag = atoi(argv[5]) ; mtxFileName = argv[6] ; rhsFileName = argv[7] ; solFileName = argv[8] ; seed = atoi(argv[9]) ; fprintf(msgFile, "\n\n %s input :" "\n msglvl = %d" "\n msgFile = %s" "\n neqns = %d" "\n type = %d" "\n symmetryflag = %d" "\n mtxFile = %s" "\n rhsFile = %s" "\n solFile = %s" "\n", argv[0], msglvl, argv[2], neqns, type, symmetryflag, mtxFileName, rhsFileName, solFileName) ; /*--------------------------------------------------------------------*/ /* ----------------------------------- processor zero reads in the matrix. if an error is found, all processors exit cleanly ----------------------------------- */ if ( myid != 0 ) { mtxA = NULL ; } else { /* ---------------------------------------------------- open the file, read in the matrix and close the file ---------------------------------------------------- */ mtxA = InpMtx_new() ; rc = InpMtx_readFromFile(mtxA, mtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxA from file %s, rc = %d", mtxFileName, rc) ; fflush(msgFile) ; } } /* --------------------------------------------------------------- processor 0 broadcasts the error return to the other processors --------------------------------------------------------------- */ MPI_Bcast((void *) &rc, 1, MPI_INT, 0, MPI_COMM_WORLD) ; if ( rc != 1 ) { MPI_Finalize() ; return(-1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- processor zero reads in the right hand side matrix. if an error is found, all processors exit cleanly --------------------------------------------------- */ if ( myid != 0 ) { mtxY = NULL ; } else { /* ---------------------------------- read in the right hand side matrix ---------------------------------- */ mtxY = DenseMtx_new() ; rc = DenseMtx_readFromFile(mtxY, rhsFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxY from file %s, rc = %d", rhsFileName, rc) ; fflush(msgFile) ; } else { DenseMtx_dimensions(mtxY, &nrow, &nrhs) ; } } /* --------------------------------------------------------------- processor 0 broadcasts the error return to the other processors --------------------------------------------------------------- */ MPI_Bcast((void *) &rc, 1, MPI_INT, 0, MPI_COMM_WORLD) ; if ( rc != 1 ) { MPI_Finalize() ; return(-1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ create and setup a BridgeMPI object set the MPI, matrix and message parameters ------------------------------------------ */ bridge = BridgeMPI_new() ; BridgeMPI_setMPIparams(bridge, nproc, myid, MPI_COMM_WORLD) ; BridgeMPI_setMatrixParams(bridge, neqns, type, symmetryflag) ; BridgeMPI_setMessageInfo(bridge, msglvl, msgFile) ; /* ----------------- setup the problem ----------------- */ rc = BridgeMPI_setup(bridge, mtxA) ; fprintf(msgFile, "\n\n ----- SETUP -----\n" "\n CPU %8.3f : time to construct Graph" "\n CPU %8.3f : time to compress Graph" "\n CPU %8.3f : time to order Graph" "\n CPU %8.3f : time for symbolic factorization" "\n CPU %8.3f : time to broadcast front tree" "\n CPU %8.3f : time to broadcast symbolic factorization" "\n CPU %8.3f : total setup time\n", bridge->cpus[0], bridge->cpus[1], bridge->cpus[2], bridge->cpus[3], bridge->cpus[4], bridge->cpus[5], bridge->cpus[6]) ; rc = BridgeMPI_factorStats(bridge, type, symmetryflag, &nfront, &nfind, &nfent, &nsolveops, &nfactorops) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from BridgeMPI_factorStats()", rc) ; MPI_Finalize() ; exit(-1) ; } fprintf(msgFile, "\n\n factor matrix statistics" "\n %d fronts, %d indices, %d entries" "\n %d solve operations, %12.4e factor operations", nfront, nfind, nfent, nsolveops, nfactorops) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* -------------------------------- setup the parallel factorization -------------------------------- */ rc = BridgeMPI_factorSetup(bridge, 0, 0.0) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from BridgeMPI_factorSetup()", rc) ; MPI_Finalize() ; exit(-1) ; } fprintf(msgFile, "\n\n ----- PARALLEL FACTOR SETUP -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to setup parallel factorization", bridge->cpus[7]) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n total factor operations = %.0f" "\n upper bound on speedup due to load balance = %.2f", DV_sum(bridge->cumopsDV), DV_sum(bridge->cumopsDV)/DV_max(bridge->cumopsDV)) ; fprintf(msgFile, "\n operations distributions over processors") ; DV_writeForHumanEye(bridge->cumopsDV, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ set the factorization parameters and factor the matrix ------------------------------------------------------ */ permuteflag = 1 ; rc = BridgeMPI_factor(bridge, mtxA, permuteflag, &error) ; fprintf(msgFile, "\n\n ----- FACTORIZATION -----\n") ; if ( rc == 1 ) { fprintf(msgFile, "\n\n factorization completed successfully\n") ; } else { fprintf(msgFile, "\n" "\n return code from factorization = %d\n" "\n error code = %d\n", rc, error) ; MPI_Finalize() ; exit(-1) ; } fprintf(msgFile, "\n CPU %8.3f : time to permute original matrix" "\n CPU %8.3f : time to distribute original matrix" "\n CPU %8.3f : time to initialize factor matrix" "\n CPU %8.3f : time to compute factorization" "\n CPU %8.3f : time to post-process factorization" "\n CPU %8.3f : total factorization time\n", bridge->cpus[8], bridge->cpus[9], bridge->cpus[10], bridge->cpus[11], bridge->cpus[12], bridge->cpus[13]) ; IVzero(6, tstats) ; MPI_Reduce((void *) bridge->stats, (void *) tstats, 6, MPI_INT, MPI_SUM, 0, bridge->comm) ; fprintf(msgFile, "\n\n factorization statistics" "\n %d pivots, %d pivot tests, %d delayed vertices" "\n %d entries in D, %d entries in L, %d entries in U", tstats[0], tstats[1], tstats[2], tstats[3], tstats[4], tstats[5]) ; fprintf(msgFile, "\n\n factorization: raw mflops %8.3f, overall mflops %8.3f", 1.e-6*nfactorops/bridge->cpus[11], 1.e-6*nfactorops/bridge->cpus[13]) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* ------------------------ setup the parallel solve ------------------------ */ rc = BridgeMPI_solveSetup(bridge) ; fprintf(msgFile, "\n\n ----- PARALLEL SOLVE SETUP -----\n" "\n CPU %8.3f : time to setup parallel solve", bridge->cpus[14]) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from BridgeMPI_solveSetup()", rc) ; MPI_Finalize() ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- processor 0 initializes a DenseMtx object to hold the global solution matrix ----------------------------------------- */ if ( myid == 0 ) { mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; } else { mtxX = NULL ; } /* --------------------------------------------- the processors solve the system cooperatively --------------------------------------------- */ permuteflag = 1 ; rc = BridgeMPI_solve(bridge, permuteflag, mtxX, mtxY) ; if ( rc == 1 ) { fprintf(msgFile, "\n\n solve complete successfully\n") ; } else { fprintf(msgFile, "\n" " return code from solve = %d\n", rc) ; } fprintf(msgFile, "\n\n ----- SOLVE -----\n" "\n CPU %8.3f : time to permute rhs into new ordering" "\n CPU %8.3f : time to distribute rhs " "\n CPU %8.3f : time to initialize solution matrix " "\n CPU %8.3f : time to solve linear system" "\n CPU %8.3f : time to gather solution " "\n CPU %8.3f : time to permute solution into old ordering" "\n CPU %8.3f : total solve time" "\n\n solve: raw mflops %8.3f, overall mflops %8.3f", bridge->cpus[15], bridge->cpus[16], bridge->cpus[17], bridge->cpus[18], bridge->cpus[19], bridge->cpus[20], bridge->cpus[21], 1.e-6*nsolveops/bridge->cpus[18], 1.e-6*nsolveops/bridge->cpus[21]) ; fflush(msgFile) ; if ( myid == 0 ) { if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } } /*--------------------------------------------------------------------*/ /* --------------------- free the working data --------------------- */ if ( myid == 0 ) { InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxY) ; } BridgeMPI_free(bridge) ; /*--------------------------------------------------------------------*/ MPI_Finalize() ; return(1) ; } /*--------------------------------------------------------------------*/ cmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { int length = strlen(argv[2]) + 1 + 4 ; char *buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; MPI_Finalize() ; return(0) ; } CVfree(buffer) ; } neqns = atoi(argv[3]) ; typLinSol/drivers/testWrapperMT.c010060000020550007177000000242570662007126100176760ustar00clevecompmath00000400000006/* testWrapperMT.c */ #include "../BridgeMT.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ----------------------------------------------------------- purpose -- main driver program to solve a linear system where the matrix and rhs are read in from files and the solution is written to a file. NOTE: multithreaded version created -- 98sep24, cca ----------------------------------------------------------- */ BridgeMT *bridge ; char *mtxFileName, *rhsFileName, *solFileName ; double nfactorops ; FILE *msgFile ; InpMtx *mtxA ; int error, msglvl, neqns, nfent, nfind, nfront, nrhs, nrow, nsolveops, nthread, permuteflag, rc, seed, symmetryflag, type ; DenseMtx *mtxX, *mtxY ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 11 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile neqns type symmetryflag " "\n mtxFile rhsFile solFile seed nthread\n" "\n msglvl -- message level" "\n 0 -- no output" "\n 1 -- timings and statistics" "\n 2 and greater -- lots of output" "\n msgFile -- message file" "\n neqns -- # of equations" "\n type -- type of entries" "\n 1 -- real" "\n 2 -- complex" "\n symmetryflag -- symmetry flag" "\n 0 -- symmetric" "\n 1 -- hermitian" "\n 2 -- nonsymmetric" "\n neqns -- # of equations" "\n mtxFile -- input file for A matrix InpMtx object" "\n must be *.inpmtxf or *.inpmtxb" "\n rhsFile -- input file for Y DenseMtx object" "\n must be *.densemtxf or *.densemtxb" "\n solFile -- output file for X DenseMtx object" "\n must be none, *.densemtxf or *.densemtxb" "\n seed -- random number seed" "\n nthread -- number of threads" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } neqns = atoi(argv[3]) ; type = atoi(argv[4]) ; symmetryflag = atoi(argv[5]) ; mtxFileName = argv[6] ; rhsFileName = argv[7] ; solFileName = argv[8] ; seed = atoi(argv[9]) ; nthread = atoi(argv[10]) ; fprintf(msgFile, "\n\n %s input :" "\n msglvl = %d" "\n msgFile = %s" "\n neqns = %d" "\n type = %d" "\n symmetryflag = %d" "\n mtxFile = %s" "\n rhsFile = %s" "\n solFile = %s" "\n nthread = %d" "\n", argv[0], msglvl, argv[2], neqns, type, symmetryflag, mtxFileName, rhsFileName, solFileName, nthread) ; /*--------------------------------------------------------------------*/ /* ------------------ read in the matrix ------------------ */ mtxA = InpMtx_new() ; rc = InpMtx_readFromFile(mtxA, mtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxA from file %s, rc = %d", mtxFileName, rc) ; fflush(msgFile) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n InpMtx object ") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- read in the right hand side matrix ---------------------------------- */ mtxY = DenseMtx_new() ; rc = DenseMtx_readFromFile(mtxY, rhsFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxY from file %s, rc = %d", rhsFileName, rc) ; fflush(msgFile) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n DenseMtx object for right hand side") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } DenseMtx_dimensions(mtxY, &nrow, &nrhs) ; /*--------------------------------------------------------------------*/ /* ---------------------------------- create and setup a BridgeMT object ---------------------------------- */ bridge = BridgeMT_new() ; BridgeMT_setMatrixParams(bridge, neqns, type, symmetryflag) ; BridgeMT_setMessageInfo(bridge, msglvl, msgFile) ; rc = BridgeMT_setup(bridge, mtxA) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from BridgeMT_setup()", rc) ; exit(-1) ; } fprintf(msgFile, "\n\n ----- SETUP -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to construct Graph" "\n CPU %8.3f : time to compress Graph" "\n CPU %8.3f : time to order Graph" "\n CPU %8.3f : time for symbolic factorization" "\n CPU %8.3f : total setup time\n", bridge->cpus[0], bridge->cpus[1], bridge->cpus[2], bridge->cpus[3], bridge->cpus[4]) ; rc = BridgeMT_factorStats(bridge, type, symmetryflag, &nfront, &nfind, &nfent, &nsolveops, &nfactorops) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from BridgeMT_factorStats()", rc) ; exit(-1) ; } fprintf(msgFile, "\n\n factor matrix statistics" "\n %d fronts, %d indices, %d entries" "\n %d solve operations, %12.4e factor operations", nfront, nfind, nfent, nsolveops, nfactorops) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* -------------------------------- setup the parallel factorization -------------------------------- */ rc = BridgeMT_factorSetup(bridge, nthread, 0, 0.0) ; fprintf(msgFile, "\n\n ----- PARALLEL FACTOR SETUP -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to setup parallel factorization", bridge->cpus[5]) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n total factor operations = %.0f", DV_sum(bridge->cumopsDV)) ; fprintf(msgFile, "\n upper bound on speedup due to load balance = %.2f", DV_sum(bridge->cumopsDV)/DV_max(bridge->cumopsDV)) ; fprintf(msgFile, "\n operations distributions over threads") ; DV_writeForHumanEye(bridge->cumopsDV, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------- factor the matrix ----------------- */ permuteflag = 1 ; rc = BridgeMT_factor(bridge, mtxA, permuteflag, &error) ; if ( rc == 1 ) { fprintf(msgFile, "\n\n factorization completed successfully\n") ; } else { fprintf(msgFile, "\n return code from factorization = %d\n" "\n error code = %d\n", rc, error) ; exit(-1) ; } fprintf(msgFile, "\n\n ----- FACTORIZATION -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to permute original matrix" "\n CPU %8.3f : time to initialize factor matrix" "\n CPU %8.3f : time to compute factorization" "\n CPU %8.3f : time to post-process factorization" "\n CPU %8.3f : total factorization time\n", bridge->cpus[6], bridge->cpus[7], bridge->cpus[8], bridge->cpus[9], bridge->cpus[10]) ; fprintf(msgFile, "\n\n factorization statistics" "\n %d pivots, %d pivot tests, %d delayed vertices" "\n %d entries in D, %d entries in L, %d entries in U", bridge->stats[0], bridge->stats[1], bridge->stats[2], bridge->stats[3], bridge->stats[4], bridge->stats[5]) ; fprintf(msgFile, "\n\n factorization: raw mflops %8.3f, overall mflops %8.3f", 1.e-6*nfactorops/bridge->cpus[8], 1.e-6*nfactorops/bridge->cpus[10]) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* ------------------------ setup the parallel solve ------------------------ */ rc = BridgeMT_solveSetup(bridge) ; fprintf(msgFile, "\n\n ----- PARALLEL SOLVE SETUP -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to setup parallel solve", bridge->cpus[11]) ; /*--------------------------------------------------------------------*/ /* ---------------- solve the system ---------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; rc = BridgeMT_solve(bridge, permuteflag, mtxX, mtxY) ; if (rc == 1) { fprintf(msgFile, "\n\n solve complete successfully\n") ; } else { fprintf(msgFile, "\n" " return code from solve = %d\n", rc) ; } fprintf(msgFile, "\n\n ----- SOLVE -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to permute rhs into new ordering" "\n CPU %8.3f : time to solve linear system" "\n CPU %8.3f : time to permute solution into old ordering" "\n CPU %8.3f : total solve time\n", bridge->cpus[12], bridge->cpus[13], bridge->cpus[14], bridge->cpus[15]) ; fprintf(msgFile, "\n\n solve: raw mflops %8.3f, overall mflops %8.3f", 1.e-6*nsolveops/bridge->cpus[13], 1.e-6*nsolveops/bridge->cpus[15]) ; fflush(msgFile) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ if ( strcmp(solFileName, "none") != 0 ) { /* ----------------------------------- write the solution matrix to a file ----------------------------------- */ rc = DenseMtx_writeToFile(mtxX, solFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error writing mtxX to file %s, rc = %d", solFileName, rc) ; fflush(msgFile) ; exit(-1) ; } } /*--------------------------------------------------------------------*/ /* --------------------- free the working data --------------------- */ InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxY) ; BridgeMT_free(bridge) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ "\n mtxFile -- input file for A matrix InpMtx object" "\n must be *.inpmtxf or *.inpmtxb" "\n rhsFile -- input file for Y DenseMtx object" "\n must be *.densemtxf or *.densemtxb" "\n solFile -- output file for X DenseMtx object" "\n must be none, *.densemtxf or *LinSol/drivers/wrapperMPI.4.pg010064400020550007177000000004310663625332600175000ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.1/LinSol/drivers/testWrapperMPI chinacat 1 /local/cleve/ARPA/release2.1/LinSol/drivers/testWrapperMPI chinacat 1 /local/cleve/ARPA/release2.1/LinSol/drivers/testWrapperMPI chinacat 1 /local/cleve/ARPA/release2.1/LinSol/drivers/testWrapperMPI LinSol/doc/004275500020550007177000000000000665315072600140555ustar00clevecompmath00000400000006LinSol/doc/makefile010060000020550007177000000000270661671124200155320ustar00clevecompmath00000400000006clean : - rm -f *.dvi LinSol/doc/main.tex010064400020550007177000000027040664347130600155200ustar00clevecompmath00000400000006\documentclass[10pt]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \input psfig \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\bf SPOOLES 2.2 Wrapper Objects} : \today \quad \hrulefill} {\quad \hrulefill \quad {\bf SPOOLES 2.2 Wrapper Objects} : \quad \today \hrulefill} \begin{document} \bibliographystyle{plain} \title{Wrapper Objects for Solving \break a Linear System of Equations\break using {\bf SPOOLES} 2.2} \author{ Cleve Ashcraft\\ Boeing Shared Services Group\thanks{ P. O. Box 24346, Mail Stop 7L-21, Seattle, Washington 98124. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} \and Peter Schartz \\ CSAR Corporation\thanks{ 28035 Dorothy Drive, Agoura Hills, CA 91301. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} } \date{\today} \maketitle \input abstract.tex \tableofcontents \input intro.tex \input setup.tex \input serial.tex \input MT.tex \input MPI.tex \appendix \input serial_driver.tex \input MT_driver.tex \input MPI_driver.tex \input main.ind \end{document} LinSol/doc/serial_driver.tex010060000020550007177000000217050661672330500174170ustar00clevecompmath00000400000006\chapter{{\tt testWrapper.c} --- A Serial Driver Program} \label{chapter:serial_driver} \begin{verbatim} /* testWrapper.c */ #include "../Bridge.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ----------------------------------------------------------- purpose -- main driver program to solve a linear system where the matrix and rhs are read in from files and the solution is written to a file. created -- 98oct31, cca ----------------------------------------------------------- */ Bridge *bridge ; char *mtxFileName, *rhsFileName, *solFileName ; double nfactorops ; FILE *msgFile ; InpMtx *mtxA ; int error, msglvl, neqns, nfent, nfind, nfront, nrhs, nrow, nsolveops, permuteflag, rc, seed, symmetryflag, type ; DenseMtx *mtxX, *mtxY ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile neqns type symmetryflag" "\n mtxFile rhsFile seed" "\n msglvl -- message level" "\n 0 -- no output" "\n 1 -- timings and statistics" "\n 2 and greater -- lots of output" "\n msgFile -- message file" "\n neqns -- # of equations" "\n type -- type of entries" "\n 1 -- real" "\n 2 -- complex" "\n symmetryflag -- symmetry flag" "\n 0 -- symmetric" "\n 1 -- hermitian" "\n 2 -- nonsymmetric" "\n neqns -- # of equations" "\n mtxFile -- input file for A matrix InpMtx object" "\n must be *.inpmtxf or *.inpmtxb" "\n rhsFile -- input file for Y DenseMtx object" "\n must be *.densemtxf or *.densemtxb" "\n solFile -- output file for X DenseMtx object" "\n must be none, *.densemtxf or *.densemtxb" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } neqns = atoi(argv[3]) ; type = atoi(argv[4]) ; symmetryflag = atoi(argv[5]) ; mtxFileName = argv[6] ; rhsFileName = argv[7] ; solFileName = argv[8] ; seed = atoi(argv[9]) ; fprintf(msgFile, "\n\n %s input :" "\n msglvl = %d" "\n msgFile = %s" "\n neqns = %d" "\n type = %d" "\n symmetryflag = %d" "\n mtxFile = %s" "\n rhsFile = %s" "\n solFile = %s" "\n seed = %d" "\n", argv[0], msglvl, argv[2], neqns, type, symmetryflag, mtxFileName, rhsFileName, solFileName, seed) ; /*--------------------------------------------------------------------*/ /* ------------------ read in the matrix ------------------ */ mtxA = InpMtx_new() ; rc = InpMtx_readFromFile(mtxA, mtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxA from file %s, rc = %d", mtxFileName, rc) ; fflush(msgFile) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n InpMtx object ") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- read in the right hand side matrix ---------------------------------- */ mtxY = DenseMtx_new() ; rc = DenseMtx_readFromFile(mtxY, rhsFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxY from file %s, rc = %d", rhsFileName, rc) ; fflush(msgFile) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n DenseMtx object for right hand side") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } DenseMtx_dimensions(mtxY, &nrow, &nrhs) ; /*--------------------------------------------------------------------*/ /* -------------------------------- create and setup a Bridge object -------------------------------- */ bridge = Bridge_new() ; Bridge_setMatrixParams(bridge, neqns, type, symmetryflag) ; Bridge_setMessageInfo(bridge, msglvl, msgFile) ; rc = Bridge_setup(bridge, mtxA) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from Bridge_setup()", rc) ; exit(-1) ; } fprintf(msgFile, "\n\n ----- SETUP -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to construct Graph" "\n CPU %8.3f : time to compress Graph" "\n CPU %8.3f : time to order Graph" "\n CPU %8.3f : time for symbolic factorization" "\n CPU %8.3f : total setup time\n", bridge->cpus[0], bridge->cpus[1], bridge->cpus[2], bridge->cpus[3], bridge->cpus[4]) ; rc = Bridge_factorStats(bridge, type, symmetryflag, &nfront, &nfind, &nfent, &nsolveops, &nfactorops) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from Bridge_factorStats()", rc) ; exit(-1) ; } fprintf(msgFile, "\n\n factor matrix statistics" "\n %d fronts, %d indices, %d entries" "\n %d solve operations, %12.4e factor operations", nfront, nfind, nfent, nsolveops, nfactorops) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* ----------------- factor the matrix ----------------- */ permuteflag = 1 ; rc = Bridge_factor(bridge, mtxA, permuteflag, &error) ; if ( rc == 1 ) { fprintf(msgFile, "\n\n factorization completed successfully\n") ; } else { fprintf(msgFile, "\n return code from factorization = %d" "\n error code = %d", rc, error) ; exit(-1) ; } fprintf(msgFile, "\n\n ----- FACTORIZATION -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to permute original matrix" "\n CPU %8.3f : time to initialize factor matrix" "\n CPU %8.3f : time to compute factorization" "\n CPU %8.3f : time to post-process factorization" "\n CPU %8.3f : total factorization time\n", bridge->cpus[5], bridge->cpus[6], bridge->cpus[7], bridge->cpus[8], bridge->cpus[9]) ; fprintf(msgFile, "\n\n factorization statistics" "\n %d pivots, %d pivot tests, %d delayed vertices" "\n %d entries in D, %d entries in L, %d entries in U", bridge->stats[0], bridge->stats[1], bridge->stats[2], bridge->stats[3], bridge->stats[4], bridge->stats[5]) ; fprintf(msgFile, "\n\n factorization: raw mflops %8.3f, overall mflops %8.3f", 1.e-6*nfactorops/bridge->cpus[7], 1.e-6*nfactorops/bridge->cpus[9]) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* ---------------- solve the system ---------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; rc = Bridge_solve(bridge, permuteflag, mtxX, mtxY) ; if ( rc == 1 ) { fprintf(msgFile, "\n\n solve completed successfully\n") ; } else { fprintf(msgFile, "\n" " return code from solve = %d\n", rc) ; exit(-1) ; } fprintf(msgFile, "\n\n ----- SOLVE -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to permute rhs into new ordering" "\n CPU %8.3f : time to solve linear system" "\n CPU %8.3f : time to permute solution into old ordering" "\n CPU %8.3f : total solve time\n", bridge->cpus[10], bridge->cpus[11], bridge->cpus[12], bridge->cpus[13]) ; fprintf(msgFile, "\n\n solve: raw mflops %8.3f, overall mflops %8.3f", 1.e-6*nsolveops/bridge->cpus[11], 1.e-6*nsolveops/bridge->cpus[13]) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ if ( strcmp(solFileName, "none") != 0 ) { /* ----------------------------------- write the solution matrix to a file ----------------------------------- */ rc = DenseMtx_writeToFile(mtxX, solFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error writing mtxX to file %s, rc = %d", solFileName, rc) ; fflush(msgFile) ; exit(-1) ; } } /*--------------------------------------------------------------------*/ /* --------------------- free the working data --------------------- */ InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxY) ; Bridge_free(bridge) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ \end{verbatim} LinSol/doc/intro.tex010064400020550007177000000112420663604577200157320ustar00clevecompmath00000400000006\chapter{Introduction} \label{chapter:introduction} \par One common task for the {\bf SPOOLES} library is to solve a linear system of equations $AX = Y$. The matrix $A$ is large and sparse, and the right hand side $Y$ and solution $X$ will have one or more columns. The matrices may be real or complex. We will consider the case where $A$ is square, and could be symmetric, Hermitian, or nonsymmetric. \par The first step is the find a permutation matrix $P$ such that $\widehat A = PAP^T$ has a \textit{low-fill} factorization, i.e., after $\widehat A$ has been factored into $(U^T+I)D(I+U)$ (if $\widehat A$ is symmetric), $(U^H+I)D(I+U)$ (if $\widehat A$ is Hermitian), or $(L+I)D(I+U)$ (if $\widehat A$ is nonsymmetric), the factor matrices $L$ and $U$ have relatively few entries. The {\bf SPOOLES} library can compute three types of low-fill orderings: minimum degree, generalized nested dissection, and multisection. \par The second step is to permute $A$ into $\widehat A$ and compute the factorization. The {\bf SPOOLES} library has a great deal of flexiblity in this step. The \textit{choreography}, (what data structures exist, what block computations take place), can be specified and tuned by the knowledgeable user. Pivoting for numerical stability is supported, i.e., the user can specify an upper bound on the magnitudes of the entries in $L$ and $U$. The factorization can be exact (up to roundoff) or approximate, where entries that are small in magnitude are dropped, neither stored nor used in computations. \par The last step is to solve $\widehat A \widehat X = \widehat Y$, where $\widehat Y = P Y$, and $X = P \widehat X$. The matrix $Y$ needs to be permuted to form $\widehat Y$, and $X$ is obtained from $\widehat X$ by a permutation. \par Needless to say, the complex process outlined above can be intimidating to the first time user. The complete step-by-step process for serial, multithreaded and MPI environments is described at length in the {\bf SPOOLES} User's Manual. The purpose of this document is to present a {\it vastly} simplified approach for the first-time user. We describe three \textit{wrapper} objects that we wrote for the integration of the {\bf SPOOLES} library into CSAR-Nastran. Bewarned, while the wrapper objects insulate the user from many of the details, they also restrict the ability of the user to tune the code to the particular linear system. We hope that these wrapper methods will provide a gentle introduction to the library, and be a good example from which the user can tune as necessary. \par The user's application program must interface with the {\bf SPOOLES} library in some manner. The serial, multithreaded and MPI wrapper objects we describe in sections~\ref{section:serial}, ~\ref{section:MT} and~\ref{section:MPI}. But first the user must communicate the matrix $A$ and right hand side $Y$ to the library, and receive back the solution $X$. To do this the user must generate two {\bf SPOOLES} objects --- a {\tt InpMtx} object for $A$ and {\tt DenseMtx} objects for $Y$ and $X$. This process is described in section~\ref{section:setup-linear-system}. \par Serial code has one process and one address space. Multithreaded code can have multiple threads sharing one address space. The {\bf SPOOLES} library utilizes multiple threads only in the factorization and solve steps. All other operations act on the global data structures using serial methods. In the MPI environment, the data structures for $A$, $X$ and $Y$ may be distributed, and all working data structures that contain the factor matrices and their supporting information are distributed. The MPI code is much more complex than the serial or multithreaded codes, for not only are the factor and solves parallel and distributed (as is the symbolic factorization), but there is a great deal of support code necessary because of the distributed data structures. \par The wrapper methods described in this paper do not exercise all the functionality of the MPI environment. This is due to the present state of the CSAR-Nastran code from CSAR, where the matrix $A$ and right hand side $Y$ are generated on one processor. We chose to do all the serial preprocessing \begin{itemize} \item generate a graph of the matrix, \item order the graph, \item compute the symbolic factorization, \item and construct the permutations \end{itemize} on processor 0 that reads in $A$ and $Y$ from the CSAR-Nastran files. Since the bulk of the overall time for a CSAR-Nastran run is dominated by the factor and solves, this approach was considered acceptable. For the user who is interested in using the MPI environment for the entire process, e.g., when $A$ and $Y$ cannot fit on one processor, see the {\bf SPOOLES} User Manual for driver programs. ecified and tuned by the knowledgeable user. Pivoting for numerical stability is supported, i.e., the user can specify an upper bound on the magnitudes of the entries in $L$ and $U$. The factorization can be exact (up to roundoff) or approximate, where entries that are small in magnitude are dropped, neither stored nor used in computations. \par ThLinSol/doc/serial.tex010064400020550007177000000563010663604600100160450ustar00clevecompmath00000400000006\chapter{The Serial Wrapper Object and Driver} \label{section:serial} \par The goal is to solve $AX = Y$ in a serial environment. Section 1 of the User's Manual presents a listing of the {\tt AllInOne.c} driver program for solving $AX =Y$. There are nine steps, and each requires ``mid-level'' knowledge of several objects of the {\bf SPOOLES} library. To reduce the complexity of using the library, (and the complexity rises dramatically in the multithreaded and MPI environments), we created the {\tt Bridge} object. The term ``bridge'' symbolizes spanning the distance between the {\bf SPOOLES} library and the CSAR-Nastran application code. The nine steps of the {\tt allInOne.c} driver program is reduced to three using the {\tt Bridge} object. \begin{itemize} \item Initialization and setup step. \par Here the {\tt Bridge} object is allocated via a call to {\tt Bridge\_new()}. Parameters are set using {\tt Bridge\_set*()} methods. The setup phase orders the matrix and prepares all the necessary {\bf SPOOLES} data structures for the factorization and solve that follows. \item Factorization step. \par The matrix is factored via a call to {\tt Bridge\_factor()}. \item Solution step. \par The linear system is solved via a call to {\tt Bridge\_solve()}. \end{itemize} \par The {\tt Bridge} object has many parameters that control the ordering of the matrix, the pivoting tolerance (if pivoting is requested), the drop tolerance (for an approximate factorization), and so on. Rather than burden the user with the knowledge of and setting these parameters, there are decent default values built into the object. There are also methods to set various parameters to allow the user some control over the ordering, factor and solve processes. \par Section~\ref{section:Bridge:quick-look-serial-driver} takes a quick look at the {\tt Bridge} driver program (whose complete listing is found in Appendix~\ref{chapter:serial_driver}). Section~\ref{section:Bridge:dataStructure} describes the internal data fields of the {\tt Bridge} object. Section~\ref{section:Bridge:proto} contains the prototypes and descriptions of all {\tt Bridge} methods. \par \section{A quick look at serial driver program} \label{section:Bridge:quick-look-serial-driver} \par The entire listing of this serial driver is found in Appendix~\ref{chapter:serial_driver}. We now extract parts of the code. \begin{itemize} \item Decode the input. \par \begin{verbatim} msglvl = atoi(argv[1]) ; msgFileName = argv[6] ; neqns = atoi(argv[3]) ; type = atoi(argv[4]) ; symmetryflag = atoi(argv[5]) ; mtxFileName = argv[6] ; rhsFileName = argv[7] ; solFileName = argv[8] ; seed = atoi(argv[9]) ; \end{verbatim} Here is a description of the input parameters. \begin{itemize} \item {\tt msglvl} is the message level. \item {\tt msgFile} is the message file name \item {\tt neqns} is the number of equations. \item {\tt type} is the type of entries: 1 ({\tt SPOOLES\_REAL}) or 2 ({\tt SPOOLES\_COMPLEX}). \item {\tt symmetryflag} is the type of matrix symmetry: 0 ({\tt SPOOLES\_SYMMETRIC}), 1 ({\tt SPOOLES\_HERMITIAN}) or 2 ({\tt SPOOLES\_NONSYMMETRIC}). \item {\tt mtxFile} is the name of the file from which to read the {\tt InpMtx} object for $A$. The file name must have the form {\tt *.inpmtxb} for a binary file or {\tt *.inpmtxf} for a formatted file. \item {\tt rhsFile} is the name of the file from which to read the {\tt DenseMtx} object for the right hand side $Y$. The file name must have the form {\tt *.densemtxb} for a binary file or {\tt *.densemtxf} for a formatted file. \item {\tt solFile} is the name of the file to write the {\tt DenseMtx} object for the solution $X$. The file name must have the form {\tt *.densemtxb} for a binary file or {\tt *.densemtxf} for a formatted file, {\tt "none"} for no output, or any other name for a human-readable listing. \item {\tt seed} is a random number seed used in the ordering process. \end{itemize} % \item Read in the {\tt InpMtx} object for $A$. \begin{verbatim} mtxA = InpMtx_new() ; rc = InpMtx_readFromFile(mtxA, mtxFileName) ; \end{verbatim} The {\tt rc} parameter is the error return. In the driver it is tested for an error, but we omit this from the present discussion. % \item Read in the {\tt DenseMtx} object for $Y$. \begin{verbatim} mtxY = DenseMtx_new() ; rc = DenseMtx_readFromFile(mtxY, mtxFileName) ; DenseMtx_dimensions(mtxY, &nrow, &nrhs) ; \end{verbatim} The {\tt nrhs} parameter contains the number of right hand sides, or equivalently, the number of columns in $Y$. % \item Create and setup the {\tt Bridge} object. \begin{verbatim} bridge = Bridge_new() ; Bridge_setMatrixParams(bridge, neqns, type, symmetryflag) ; Bridge_setMessageInfo(bridge, msglvl, msgFile) ; rc = Bridge_setup(bridge, mtxA) ; \end{verbatim} The {\tt Bridge} object is allocated by {\tt Bridge\_new()}, and various parameters are set. The actual ordering of the matrix, symbolic factorization, and permutation creation are performed inside the {\tt Bridge\_setup()} method. % \item Compute the matrix factorization. \begin{verbatim} permuteflag = 1 ; rc = Bridge_factor(bridge, mtxA, permuteflag, &error) ; \end{verbatim} When {\tt permuteflag} is {\tt 1}, it means that the matrix in {\tt mtxA} has not yet been permuted into the new ordering and so is done inside the method. The {\tt error} flag is filled with an error code that tells how far the factorization was able to proceed. If {\tt rc = 1}, the factorization completed without any error. % \item Solve the linear system. \begin{verbatim} mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; rc = Bridge_solve(bridge, permuteflag, mtxX, mtxY) ; \end{verbatim} The {\tt DenseMtx} object {\tt mtxX} is created and initialized to be the same type and size as {\tt mtxY}. Its entries are explicitly zeroed (this is not necessary but is a good idea in general). The solution is then solved. Again, note the presence of {\tt permuteflag}. When {\tt 1}, \texttt{mtxY} needs to be permuted into the new ordering, and \texttt{mtxX} is returned in the original ordering. \end{itemize} \par \section{The \texttt{Bridge} Data Structure} \label{section:Bridge:dataStructure} \par The {\tt Bridge} structure has the following fields. \begin{itemize} % \item Graph parameters: \begin{itemize} \item {\tt int neqns} : number of equations, i.e., number of vertices in the graph. \item {\tt int nedges} : number of edges (includes $(u,v)$, $(v,u)$ and $(u,u)$). \item {\tt int Neqns} : number of equations in the compressed graph. \item {\tt int Nedges} : number of edges in the compressed graph. \end{itemize} % \item Ordering parameters: \begin{itemize} \item {\tt int maxdomainsize} : maximum size of a subgraph to not split any further during the nested dissection process. \item {\tt int maxnzeros} : maximum number of zeros to allow in a front during the supernode amalgamation process. \item {\tt int maxsize} : maximum size of a front when the fronts are split. \item {\tt int seed} : random number seed. \item {\tt double compressCutoff} : if the \texttt{Neqns} $<$ \texttt{compressCutoff} $*$ \texttt{neqns}, then the compressed graph is formed, ordered and used to create the symbolic factorization. \end{itemize} % \item Matrix parameters: \begin{itemize} \item {\tt int type} : type of entries, {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, default value is {\tt SPOOLES\_REAL}. \item {\tt int symmetryflag} : type of symmetry for the matrix, {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}, default value is {\tt SPOOLES\_SYMMETRIC}. \end{itemize} % \item Factorization parameters: \begin{itemize} \item {\tt int sparsityflag} : {\tt SPOOLES\_DENSE\_FRONTS} for a direct factorization, or {\tt SPOOLES\_SPARSE\_FRONTS} for an approximate factorization, default value is {\tt SPOOLES\_DENSE\_FRONTS}. \item {\tt int pivotingflag} : {\tt SPOOLES\_PIVOTING} for pivoting enabled, or {\tt SPOOLES\_NO\_PIVOTING} for no pivoting, default value is {\tt SPOOLES\_NO\_PIVOTING}. \item {\tt double tau} : used when pivoting is enabled, all entries in $L$ and $U$ have magnitude less than or equal to \texttt{tau}, default value is 100. \item {\tt double droptol} : used for an approximation, all entries in $L$ and $U$ that are kept have magnitude greater than or equal to \texttt{droptol}. default value is 0.001. \item {\tt PatchAndGoInfo *patchinfo} : pointer to an object that controls special factorizations for optimization matrices and singular matrices from structural analysis, default value is \texttt{NULL} which means no special action is taken. See the Reference Manual for more information. \end{itemize} % \item Pointers to objects: \begin{itemize} \item {\tt ETree *frontETree} : object that defines the factorizations, e.g., the number of fronts, the tree they form, the number of internal and external rows for each front, and the map from vertices to the front where it is contained. \item {\tt IVL *symbfacIVL} : object that contains the symbolic factorization of the matrix. \item {\tt SubMtxManager *mtxmanager} : object that manages the \texttt{SubMtx} objects that store the factor entries and are used in the solves. \item {\tt FrontMtx *frontmtx} : object that stores the $L$, $D$ and $U$ factor matrices. \item {\tt IV *oldToNewIV} : object that stores old-to-new permutation vector. \item {\tt IV *newToOldIV} : object that stores new-to-old permutation vector. \end{itemize} % \item Message information, statistics and cpu times: \begin{itemize} \item {\tt int msglvl} : message level for output. When 0, no output, When 1, just statistics and cpu times. When greater than 1, more and more output. \item {\tt FILE *msgFile} : message file for output. When \texttt{msglvl} $>$ 0, \texttt{msgFile} must not be \texttt{NULL}. \item {\tt int stats[6]} : statistics for the factorization. \begin{center} \begin{tabular}{ll} \texttt{stats[0]} : & \# of pivots \\ \texttt{stats[1]} : & \# of pivot tests \\ \texttt{stats[2]} : & \# of delayed rows and columns \end{tabular} \begin{tabular}{ll} \texttt{stats[3]} : & \# of entries in $D$ \\ \texttt{stats[4]} : & \# of entries in $L$ \\ \texttt{stats[5]} : & \# of entries in $U$ \end{tabular} \end{center} \item {\tt double cpus[14]} : cpus for the different functions. \begin{center} \begin{tabular}{ll} \texttt{cpus[0]} : & time to construct \texttt{Graph} \\ \texttt{cpus[1]} : & time to compress \texttt{Graph} \\ \texttt{cpus[2]} : & time to order \texttt{Graph} \\ \texttt{cpus[3]} : & time for symbolic factorization \\ \texttt{cpus[4]} : & total setup time \\ \texttt{cpus[5]} : & time to permute matrix \\ \texttt{cpus[6]} : & time to initialize front matrix \end{tabular} \begin{tabular}{ll} \texttt{cpus[7]} : & time to factor matrix \\ \texttt{cpus[8]} : & time to post-process matrix \\ \texttt{cpus[9]} : & total factor time \\ \texttt{cpus[10]} : & time to permute rhs \\ \texttt{cpus[11]} : & time to solve \\ \texttt{cpus[12]} : & time to permute solution \\ \texttt{cpus[13]} : & total solve time \end{tabular} \end{center} \end{itemize} \end{itemize} \par \section{Prototypes and descriptions of \texttt{Bridge} methods} \label{section:Bridge:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Bridge} object. \par \subsection{Basic methods} \label{subsection:Bridge:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Bridge * Bridge_new ( void ) ; \end{verbatim} \index{Bridge_new@{\tt Bridge\_new()}} This method simply allocates storage for the {\tt Bridge} structure and then sets the default fields by a call to {\tt Bridge\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_setDefaultFields ( Bridge *bridge ) ; \end{verbatim} \index{Bridge_setDefaultFields@{\tt Bridge\_setDefaultFields()}} The structure's fields are set to default values: \begin{itemize} \item \texttt{neqns} = \texttt{nedges} = \texttt{Neqns} = \texttt{Nedges} = 0. \item \texttt{maxdomainsize} = \texttt{maxnzeros} = \texttt{maxsize} = \texttt{seed} = -1. \texttt{compressCutoff} = 0. \item \texttt{type} = \texttt{SPOOLES\_REAL}. \item \texttt{symmetryflag} = \texttt{SPOOLES\_SYMMETRIC}. \item \texttt{sparsityflag} = \texttt{SPOOLES\_DENSE\_FRONTS}. \item \texttt{pivotingflag} = \texttt{SPOOLES\_NO\_PIVOTING}. \item \texttt{tau} = 100., \texttt{droptol} = 0.001. \item \texttt{patchinfo} = \texttt{frontETree} = \texttt{symbfacIVL} = \texttt{mtxmanager} = \texttt{frontmtx} = \texttt{oldToNewIV} = \texttt{newToOldIV} = \texttt{NULL}. \end{itemize} The \texttt{stats[6]} and \texttt{cpus[14]} vectors are filled with zeros. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_clearData ( Bridge *bridge ) ; \end{verbatim} \index{Bridge_clearData@{\tt Bridge\_clearData()}} This method clears the object and free's any owned data. It then calls {\tt Bridge\_setDefaultFields()}. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_free ( Bridge *bridge ) ; \end{verbatim} \index{Bridge_free@{\tt Bridge\_free()}} This method releases any storage by a call to {\tt Bridge\_clearData()} and then free the space for {\tt bridge}. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:Bridge:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_oldToNewIV ( Bridge *bridge, IV **pobj ) ; \end{verbatim} \index{Bridge_oldToNewIV@{\tt Bridge\_oldToNewIV()}} This method fills \texttt{*pobj} with its \texttt{oldToNewIV} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_newToOldIV ( Bridge *bridge, IV **pobj ) ; \end{verbatim} \index{Bridge_newToOldIV@{\tt Bridge\_newToOldIV()}} This method fills \texttt{*pobj} with its \texttt{newToOldIV} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_frontETree ( Bridge *bridge, ETree **pobj ) ; \end{verbatim} \index{Bridge_frontETree@{\tt Bridge\_frontETree()}} This method fills \texttt{*pobj} with its \texttt{frontETree} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_symbfacIVL ( Bridge *bridge, IVL **pobj ) ; \end{verbatim} \index{Bridge_symbfacIVL@{\tt Bridge\_symbfacIVL()}} This method fills \texttt{*pobj} with its \texttt{symbfacIVL} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_mtxmanager ( Bridge *bridge, SubMtxManager **pobj ) ; \end{verbatim} \index{Bridge_mtxmanager@{\tt Bridge\_mtxmanager()}} This method fills \texttt{*pobj} with its \texttt{mtxmanager} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_frontmtx ( Bridge *bridge, FrontMtx **pobj ) ; \end{verbatim} \index{Bridge_frontmtx@{\tt Bridge\_frontmtx()}} This method fills \texttt{*pobj} with its \texttt{frontmtx} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Parameter methods} \label{subsection:Bridge:proto:parameters} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_setMatrixParams ( Bridge *bridge, int neqns, int type, int symmetryflag ) ; \end{verbatim} \index{Bridge_setMatrixParams@{\tt Bridge\_setMatrixParams()}} This method sets the number of equations, type of entries, and symmetry type of the matrix. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{neqns} $\le$ 0 \end{tabular} \begin{tabular}{ll} -3 & \texttt{type} is invalid \\ -4 & \texttt{symmetryflag} is invalid \\ -5 & symmetry flag is Hermitian but type is real \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_setOrderingParams ( Bridge *bridge, int maxdomainsize, int maxnzeros, int maxsize, int seed, double compressCutoff ) ; \end{verbatim} \index{Bridge_setOrderingParams@{\tt Bridge\_setOrderingParams()}} This method sets parameters needed for the ordering. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{maxdomainsize} $\le$ 0 \end{tabular} \begin{tabular}{ll} -3 & \texttt{maxsize} $\le$ 0 \\ -4 & \texttt{compressCutoff} $>$ 1 \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_setFactorParams ( Bridge *bridge, int sparsityflag, int pivotingflag, double tau, double droptol, PatchAndGoInfo *patchinfo ) ; \end{verbatim} \index{Bridge_setFactorParams@{\tt Bridge\_setFactorParams()}} This method sets parameters needed for the factorization. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{sparsityflag} is invalid \end{tabular} \begin{tabular}{ll} -3 & \texttt{pivotingflag} is invalid \\ -4 & \texttt{tau} $<$ 2.0 \\ -5 & \texttt{droptol} $<$ 0.0 \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_setMessagesInfo ( Bridge *bridge, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{Bridge_setMessagesInfo@{\tt Bridge\_setMessagesInfo()}} This method sets the message level and file. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}, -2 if \texttt{msglvl} $>$ 0 and \texttt{msgFile} is \texttt{NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Setup methods} \label{subsection:Bridge:proto:setup} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_setup ( Bridge *bridge, InpMtx *mtxA ) ; \end{verbatim} \index{Bridge_setup@{\tt Bridge\_setup()}} This method orders the graph, generates the front tree, computes the symbolic factorization, and creates the two permutation vectors. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}, -2 if \texttt{mtxA} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_factorStats ( Bridge *bridge, int type, int symmetryflag, int *pnfront, int *pnfactorind, int *pnfactorent, int *pnsolveops, double *pnfactorops ) ; \end{verbatim} \index{Bridge_factorStats@{\tt Bridge\_factorStats()}} This method takes as input the type and symmetry of the matrix, and fills the pointer fields with the number of fronts, factor indices, factor entries, forward and back solve operations, and factor operations. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{type} is invalid \\ -3 & \texttt{symmetryflag} is invalid \\ -4 & \texttt{type} is real but \texttt{symmetryflag} is Hermitian \\ -5 & front tree is not present \end{tabular} \begin{tabular}{ll} ~-6 & \texttt{pnfront} is \texttt{NULL} \\ ~-7 & \texttt{pnfactorind} is \texttt{NULL} \\ ~-8 & \texttt{pnfactorent} is \texttt{NULL} \\ ~-9 & \texttt{pnsolveops} is \texttt{NULL} \\ -10 & \texttt{pnfactorops} is \texttt{NULL} \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Factor method} \label{subsection:Bridge:proto:factor} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_factor ( Bridge *bridge, InpMtx *mtxA, int permuteflag, int *perror ) ; \end{verbatim} \index{Bridge_factor@{\tt Bridge\_factor()}} This method permutes the matrix into the new ordering (if \texttt{permuteflag} is 1), factors the matrix, and then post-processes the factors. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return, factorization did complete \\ ~0 & factorization did not complete \\ \end{tabular} \begin{tabular}{ll} -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{mtxA} is \texttt{NULL} \\ -3 & \texttt{perror} is \texttt{NULL} \\ \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Solve method} \label{subsection:Bridge:proto:solve} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_solve ( Bridge *bridge, int permuteflag, DenseMtx *mtxX, DenseMtx *mtxY ) ; \end{verbatim} \index{Bridge_solve@{\tt Bridge\_solve()}} If \texttt{permuteflag} is 1, then \texttt{mtxY} is permuted into the new ordering. The linear system $AX = Y$ is solved. If \texttt{permuteflag} is 1, then \texttt{mtxX} is permuted into the old ordering. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{X} is \texttt{NULL} \\ -3 & \texttt{Y} is \texttt{NULL} \\ \end{tabular} \begin{tabular}{ll} -4 & \texttt{frontmtx} is \texttt{NULL} \\ -5 & \texttt{mtxmanager} is \texttt{NULL} \\ -6 & \texttt{oldToNewIV} needed, but not available \\ -7 & \texttt{newToOldIV} needed, but not available \\ \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} normal return, -1 if \texttt{bridge} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int Bridge_free ( Bridge *bridge ) ; \end{verbatim} \index{Bridge_free@{\tt Bridge\_free()}} This method releases any storage by a call to {\tt Bridge\_clearData()} andLinSol/doc/abstract.tex010064400020550007177000000023040663604574700164030ustar00clevecompmath00000400000006\begin{abstract} The {\bf SPOOLES} library stands for {\bf SP}arse {\bf O}bject {\bf O}riented {\bf L}inear {\bf E}quation {\bf S}olver. It is written in the C language using object oriented design and can solve real or complex linear systems in serial, multithreaded and MPI environments. It contains three options to order the matrices: minimum degree, generalized nested dissection and multisection. The matrices may be symmetric, Hermitian or nonsymmetric. Pivoting for numerical stability is supported. \par While the functionality of the library is broad, the learning curve can be steep for the initial user. We present in this paper some ``wrapper'' objects in the serial, multithreaded and MPI environments that ease the transition. They were originally written to integrate the {\bf SPOOLES} library into CSAR's CSAR-Nastran library. \par The wrapper objects are presented as a learning device; anything that reduces the interface between the user and the library also restricts the ability to tune the library to a particular need. This drawback is ameliorated by a number of wrapper methods that allow the user to change default parameters that govern the ordering, factorization and solve. \end{abstract} LinSol/doc/main.log010064400020550007177000000222370664347136600155120ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 2 JAN 1999 11:26 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file main.idx (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 21. LaTeX Font Info: ... okay on input line 21. LaTeX Font Info: External font `cmex10' loaded for size (Font) <12> on input line 48. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 48. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 48. LaTeX Font Info: External font `cmex10' loaded for size (Font) <9> on input line 48. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 48. [1 ] (abstract.tex [1]) (main.toc LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 3. [1 ]) \tf@toc=\write5 (intro.tex [2] Chapter 1. [3 ] LaTeX Font Info: Try loading font information for OMS+cmr on input line 92. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 92. ) (setup.tex [4] Chapter 2. [5 ] [6] [7] [8] [9]) (serial.tex [10] Chapter 3. [11 ] [12] LaTeX Font Info: Font shape `OT1/cmtt/bx/n' in size <14.4> not available (Font) Font shape `OT1/cmtt/m/n' tried instead on input line 160. [13] Overfull \hbox (1.50043pt too wide) in paragraph at lines 215--220 []\OT1/cmtt/m/n/10 int sparsityflag \OT1/cmr/m/n/10 : \OT1/cmtt/m/n/10 SPOOLES[ ]DENSE[]FRONTS \OT1/cmr/m/n/10 for a di-rect fac-tor-iza-tion, or \OT1/cmtt/m/n /10 SPOOLES[]SPARSE[]FRONTS [] [14] Overfull \hbox (2.32315pt too wide) in paragraph at lines 363--370 []\OT1/cmtt/m/n/10 patchinfo \OT1/cmr/m/n/10 = \OT1/cmtt/m/n/10 frontETree \OT1 /cmr/m/n/10 = \OT1/cmtt/m/n/10 symbfacIVL \OT1/cmr/m/n/10 = \OT1/cmtt/m/n/10 mt xmanager \OT1/cmr/m/n/10 = \OT1/cmtt/m/n/10 frontmtx \OT1/cmr/m/n/10 = \OT1/cmt t/m/n/10 oldToNewIV \OT1/cmr/m/n/10 = \OT1/cmtt/m/n/10 newToOldIV [] [15] Overfull \hbox (6.7411pt too wide) in paragraph at lines 481--481 []\OT1/cmtt/m/n/10 int Bridge_setMatrixParams ( Bridge *bridge, int neqns, int type, int symmetryflag ) ;[] [] Overfull \hbox (6.7411pt too wide) in paragraph at lines 523--523 [] \OT1/cmtt/m/n/10 double tau, double droptol, Pa tchAndGoInfo *patchinfo ) ;[] [] [16] Overfull \hbox (6.7411pt too wide) in paragraph at lines 640--640 []\OT1/cmtt/m/n/10 int Bridge_solve ( Bridge *bridge, int permuteflag, DenseMt x *mtxX, DenseMtx *mtxY ) ;[] [] ) (MT.tex [17] Chapter 4. Overfull \hbox (8.70973pt too wide) in paragraph at lines 18--24 \OT1/cmtt/m/n/10 BridgeMT[]set*() \OT1/cmr/m/n/10 meth-ods. The setup phase or- ders the ma-trix and pre-pares all the nec-es-sary \OT1/cmr/bx/n/10 SPOOLES [] [18 ] [19] [20] Overfull \hbox (1.50043pt too wide) in paragraph at lines 244--249 []\OT1/cmtt/m/n/10 int sparsityflag \OT1/cmr/m/n/10 : \OT1/cmtt/m/n/10 SPOOLES[ ]DENSE[]FRONTS \OT1/cmr/m/n/10 for a di-rect fac-tor-iza-tion, or \OT1/cmtt/m/n /10 SPOOLES[]SPARSE[]FRONTS [] [21] [22] Overfull \hbox (9.65831pt too wide) in paragraph at lines 422--433 []\OT1/cmtt/m/n/10 patchinfo\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 frontETree\OT1/c mr/m/n/10 , \OT1/cmtt/m/n/10 symbfacIVL\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 mtxma nager\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 frontmtx\OT1/cmr/m/n/10 , \OT1/cmtt/m/n /10 oldToNewIV\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 newToOldIV\OT1/cmr/m/n/10 , \O T1/cmtt/m/n/10 ownersIV\OT1/cmr/m/n/10 , [] [23] Overfull \hbox (27.74092pt too wide) in paragraph at lines 588--588 []\OT1/cmtt/m/n/10 int BridgeMT_setMatrixParams ( BridgeMT *bridge, int neqns, int type, int symmetryflag ) ;[] [] Overfull \hbox (6.7411pt too wide) in paragraph at lines 630--630 [] \OT1/cmtt/m/n/10 double tau, double droptol, int lookahead, Pa tchAndGoInfo *patchinfo ) ;[] [] [24] Overfull \hbox (6.7411pt too wide) in paragraph at lines 683--683 []\OT1/cmtt/m/n/10 int BridgeMT_factorStats ( BridgeMT *bridge, int type, int symmetryflag, int *pnfront,[] [] Overfull \hbox (17.24101pt too wide) in paragraph at lines 719--719 []\OT1/cmtt/m/n/10 int BridgeMT_factorSetup ( BridgeMT *bridge, int nthread, i nt maptype, double cutoff ) ;[] [] Overfull \hbox (6.7411pt too wide) in paragraph at lines 756--756 []\OT1/cmtt/m/n/10 int BridgeMT_factor ( BridgeMT *bridge, InpMtx *mtxA, int p ermuteflag, int *perror ) ;[] [] [25] Overfull \hbox (27.74092pt too wide) in paragraph at lines 804--804 []\OT1/cmtt/m/n/10 int BridgeMT_solve ( BridgeMT *bridge, int permuteflag, Den seMtx *mtxX, DenseMtx *mtxY ) ;[] [] ) (MPI.tex [26] Chapter 5. [27 ] [28] [29] Overfull \hbox (1.50043pt too wide) in paragraph at lines 252--257 []\OT1/cmtt/m/n/10 int sparsityflag \OT1/cmr/m/n/10 : \OT1/cmtt/m/n/10 SPOOLES[ ]DENSE[]FRONTS \OT1/cmr/m/n/10 for a di-rect fac-tor-iza-tion, or \OT1/cmtt/m/n /10 SPOOLES[]SPARSE[]FRONTS [] [30] [31] Overfull \hbox (9.65831pt too wide) in paragraph at lines 460--478 []\OT1/cmtt/m/n/10 patchinfo\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 frontETree\OT1/c mr/m/n/10 , \OT1/cmtt/m/n/10 symbfacIVL\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 mtxma nager\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 frontmtx\OT1/cmr/m/n/10 , \OT1/cmtt/m/n /10 oldToNewIV\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 newToOldIV\OT1/cmr/m/n/10 , \O T1/cmtt/m/n/10 ownersIV\OT1/cmr/m/n/10 , [] Overfull \hbox (2.07051pt too wide) in paragraph at lines 489--491 []\OT1/cmr/m/n/10 This method clears the ob-ject and free's any owned data. It then calls \OT1/cmtt/m/n/10 BridgeMPI[]setDefaultFields()\OT1/cmr/m/n/10 . [] [32] [33] Overfull \hbox (38.24083pt too wide) in paragraph at lines 700--700 []\OT1/cmtt/m/n/10 int BridgeMPI_setMatrixParams ( BridgeMPI *bridge, int neqn s, int type, int symmetryflag ) ;[] [] Overfull \hbox (6.7411pt too wide) in paragraph at lines 721--721 []\OT1/cmtt/m/n/10 int BridgeMPI_setMPIparams ( BridgeMPI *bridge, int nproc, int myid, MPI_Comm comm ) ;[] [] Overfull \hbox (6.7411pt too wide) in paragraph at lines 740--740 []\OT1/cmtt/m/n/10 int BridgeMPI_setOrderingParams ( BridgeMPI *bridge, int ma xdomainsize, int maxnzeros,[] [] Overfull \hbox (6.7411pt too wide) in paragraph at lines 760--760 []\OT1/cmtt/m/n/10 int BridgeMPI_setFactorParams ( BridgeMPI *bridge, int spar sityflag, int pivotingflag,[] [] Overfull \hbox (6.7411pt too wide) in paragraph at lines 760--760 [] \OT1/cmtt/m/n/10 double tau, double droptol, int lookahead, Pa tchAndGoInfo *patchinfo ) ;[] [] [34] Overfull \hbox (17.24101pt too wide) in paragraph at lines 813--813 []\OT1/cmtt/m/n/10 int BridgeMPI_factorStats ( BridgeMPI *bridge, int type, in t symmetryflag, int *pnfront,[] [] [35] Overfull \hbox (17.24101pt too wide) in paragraph at lines 879--879 []\OT1/cmtt/m/n/10 int BridgeMPI_factor ( BridgeMPI *bridge, InpMtx *mtxA, int permuteflag, int *perror ) ;[] [] Overfull \hbox (38.24083pt too wide) in paragraph at lines 927--927 []\OT1/cmtt/m/n/10 int BridgeMPI_solve ( BridgeMPI *bridge, int permuteflag, D enseMtx *mtxX, DenseMtx *mtxY ) ;[] [] ) (serial_driver.tex [36] Appendix A. [37 ] [38] [39] [40] [41]) (MT_driver.tex [42] Appendix B. [43 ] [44] [45] [46] [47] [48]) (MPI_driver.tex [49] Appendix C. [50 ] [51] [52] [53] [54] [55] [56]) (main.ind [57] [58 ]) (main.aux) ) Here is how much of TeX's memory you used: 597 strings out of 10908 6593 string characters out of 72189 59047 words of memory out of 262141 3485 multiletter control sequences out of 9500 11867 words of font info for 43 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 25i,11n,21p,152b,402s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (60 pages, 170020 bytes). LinSol/doc/main.idx010064400020550007177000000111760664347136600155150ustar00clevecompmath00000400000006\indexentry{Bridge_new@{\tt Bridge\_new()}}{15} \indexentry{Bridge_setDefaultFields@{\tt Bridge\_setDefaultFields()}}{15} \indexentry{Bridge_clearData@{\tt Bridge\_clearData()}}{15} \indexentry{Bridge_free@{\tt Bridge\_free()}}{15} \indexentry{Bridge_oldToNewIV@{\tt Bridge\_oldToNewIV()}}{15} \indexentry{Bridge_newToOldIV@{\tt Bridge\_newToOldIV()}}{15} \indexentry{Bridge_frontETree@{\tt Bridge\_frontETree()}}{16} \indexentry{Bridge_symbfacIVL@{\tt Bridge\_symbfacIVL()}}{16} \indexentry{Bridge_mtxmanager@{\tt Bridge\_mtxmanager()}}{16} \indexentry{Bridge_frontmtx@{\tt Bridge\_frontmtx()}}{16} \indexentry{Bridge_setMatrixParams@{\tt Bridge\_setMatrixParams()}}{16} \indexentry{Bridge_setOrderingParams@{\tt Bridge\_setOrderingParams()}}{16} \indexentry{Bridge_setFactorParams@{\tt Bridge\_setFactorParams()}}{16} \indexentry{Bridge_setMessagesInfo@{\tt Bridge\_setMessagesInfo()}}{16} \indexentry{Bridge_setup@{\tt Bridge\_setup()}}{17} \indexentry{Bridge_factorStats@{\tt Bridge\_factorStats()}}{17} \indexentry{Bridge_factor@{\tt Bridge\_factor()}}{17} \indexentry{Bridge_solve@{\tt Bridge\_solve()}}{17} \indexentry{BridgeMT_new@{\tt BridgeMT\_new()}}{23} \indexentry{BridgeMT_setDefaultFields@{\tt BridgeMT\_setDefaultFields()}}{23} \indexentry{BridgeMT_clearData@{\tt BridgeMT\_clearData()}}{23} \indexentry{BridgeMT_free@{\tt BridgeMT\_free()}}{23} \indexentry{BridgeMT_oldToNewIV@{\tt BridgeMT\_oldToNewIV()}}{23} \indexentry{BridgeMT_newToOldIV@{\tt BridgeMT\_newToOldIV()}}{23} \indexentry{BridgeMT_frontETree@{\tt BridgeMT\_frontETree()}}{23} \indexentry{BridgeMT_symbfacIVL@{\tt BridgeMT\_symbfacIVL()}}{23} \indexentry{BridgeMT_mtxmanager@{\tt BridgeMT\_mtxmanager()}}{24} \indexentry{BridgeMT_frontmtx@{\tt BridgeMT\_frontmtx()}}{24} \indexentry{BridgeMT_ownersIV@{\tt BridgeMT\_ownersIV()}}{24} \indexentry{BridgeMT_solvemap@{\tt BridgeMT\_solvemap()}}{24} \indexentry{BridgeMT_nthread@{\tt BridgeMT\_nthread()}}{24} \indexentry{BridgeMT_lookahead@{\tt BridgeMT\_lookahead()}}{24} \indexentry{BridgeMT_setMatrixParams@{\tt BridgeMT\_setMatrixParams()}}{24} \indexentry{BridgeMT_setOrderingParams@{\tt BridgeMT\_setOrderingParams()}}{24} \indexentry{BridgeMT_setFactorParams@{\tt BridgeMT\_setFactorParams()}}{24} \indexentry{BridgeMT_setMessagesInfo@{\tt BridgeMT\_setMessagesInfo()}}{25} \indexentry{BridgeMT_setup@{\tt BridgeMT\_setup()}}{25} \indexentry{BridgeMT_factorStats@{\tt BridgeMT\_factorStats()}}{25} \indexentry{BridgeMT_factorSetup@{\tt BridgeMT\_factorSetup()}}{25} \indexentry{BridgeMT_factor@{\tt BridgeMT\_factor()}}{26} \indexentry{BridgeMT_solveSetup@{\tt BridgeMT\_solveSetup()}}{26} \indexentry{BridgeMT_solve@{\tt BridgeMT\_solve()}}{26} \indexentry{BridgeMPI_new@{\tt BridgeMPI\_new()}}{32} \indexentry{BridgeMPI_setDefaultFields@{\tt BridgeMPI\_setDefaultFields()}}{32} \indexentry{BridgeMPI_clearData@{\tt BridgeMPI\_clearData()}}{32} \indexentry{BridgeMPI_free@{\tt BridgeMPI\_free()}}{32} \indexentry{BridgeMPI_oldToNewIV@{\tt BridgeMPI\_oldToNewIV()}}{33} \indexentry{BridgeMPI_newToOldIV@{\tt BridgeMPI\_newToOldIV()}}{33} \indexentry{BridgeMPI_frontETree@{\tt BridgeMPI\_frontETree()}}{33} \indexentry{BridgeMPI_symbfacIVL@{\tt BridgeMPI\_symbfacIVL()}}{33} \indexentry{BridgeMPI_mtxmanager@{\tt BridgeMPI\_mtxmanager()}}{33} \indexentry{BridgeMPI_frontmtx@{\tt BridgeMPI\_frontmtx()}}{33} \indexentry{BridgeMPI_ownersIV@{\tt BridgeMPI\_ownersIV()}}{33} \indexentry{BridgeMPI_solvemap@{\tt BridgeMPI\_solvemap()}}{33} \indexentry{BridgeMPI_vtxmapIV@{\tt BridgeMPI\_vtxmapIV()}}{33} \indexentry{BridgeMPI_rowmapIV@{\tt BridgeMPI\_rowmapIV()}}{33} \indexentry{BridgeMPI_ownedColumns@{\tt BridgeMPI\_ownedColumns()}}{33} \indexentry{BridgeMPI_Xloc@{\tt BridgeMPI\_Xloc()}}{34} \indexentry{BridgeMPI_Yloc@{\tt BridgeMPI\_Yloc()}}{34} \indexentry{BridgeMPI_nproc@{\tt BridgeMPI\_nproc()}}{34} \indexentry{BridgeMPI_myid@{\tt BridgeMPI\_myid()}}{34} \indexentry{BridgeMPI_lookahead@{\tt BridgeMPI\_lookahead()}}{34} \indexentry{BridgeMPI_setMatrixParams@{\tt BridgeMPI\_setMatrixParams()}}{34} \indexentry{BridgeMPI_setMPIparams@{\tt BridgeMPI\_setMPIparams()}}{34} \indexentry{BridgeMPI_setOrderingParams@{\tt BridgeMPI\_setOrderingParams()}}{34} \indexentry{BridgeMPI_setFactorParams@{\tt BridgeMPI\_setFactorParams()}}{35} \indexentry{BridgeMPI_setMessagesInfo@{\tt BridgeMPI\_setMessagesInfo()}}{35} \indexentry{BridgeMPI_setup@{\tt BridgeMPI\_setup()}}{35} \indexentry{BridgeMPI_factorStats@{\tt BridgeMPI\_factorStats()}}{35} \indexentry{BridgeMPI_factorSetup@{\tt BridgeMPI\_factorSetup()}}{35} \indexentry{BridgeMPI_factor@{\tt BridgeMPI\_factor()}}{36} \indexentry{BridgeMPI_solveSetup@{\tt BridgeMPI\_solveSetup()}}{36} \indexentry{BridgeMPI_solve@{\tt BridgeMPI\_solve()}}{36} LinSol/doc/main.aux010064400020550007177000000141070664347136600155230ustar00clevecompmath00000400000006\relax \bibstyle{plain} \@writefile{toc}{\contentsline {chapter}{\numberline {1}Introduction}{3}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:introduction}{{1}{3}} \@writefile{toc}{\contentsline {chapter}{\numberline {2}Setting up the linear system}{5}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{section:setup-linear-system}{{2}{5}} \@writefile{toc}{\contentsline {section}{\numberline {2.1}Constructing an {\tt InpMtx} object}{5}} \newlabel{subsection:construct-InpMtx}{{2.1}{5}} \@writefile{toc}{\contentsline {section}{\numberline {2.2}Constructing an {\tt DenseMtx} object}{8}} \newlabel{subsection:construct-DenseMtx}{{2.2}{8}} \@writefile{toc}{\contentsline {section}{\numberline {2.3}IO for the {\tt InpMtx} and {\tt DenseMtx} objects}{9}} \newlabel{subsection:IO}{{2.3}{9}} \@writefile{toc}{\contentsline {chapter}{\numberline {3}The Serial Wrapper Object and Driver}{11}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{section:serial}{{3}{11}} \@writefile{toc}{\contentsline {section}{\numberline {3.1}A quick look at serial driver program}{11}} \newlabel{section:Bridge:quick-look-serial-driver}{{3.1}{11}} \@writefile{toc}{\contentsline {section}{\numberline {3.2}The \texttt {Bridge} Data Structure}{13}} \newlabel{section:Bridge:dataStructure}{{3.2}{13}} \@writefile{toc}{\contentsline {section}{\numberline {3.3}Prototypes and descriptions of \texttt {Bridge} methods}{15}} \newlabel{section:Bridge:proto}{{3.3}{15}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.3.1}Basic methods}{15}} \newlabel{subsection:Bridge:proto:basics}{{3.3.1}{15}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.3.2}Instance methods}{15}} \newlabel{subsection:Bridge:proto:instance}{{3.3.2}{15}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.3.3}Parameter methods}{16}} \newlabel{subsection:Bridge:proto:parameters}{{3.3.3}{16}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.3.4}Setup methods}{17}} \newlabel{subsection:Bridge:proto:setup}{{3.3.4}{17}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.3.5}Factor method}{17}} \newlabel{subsection:Bridge:proto:factor}{{3.3.5}{17}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.3.6}Solve method}{17}} \newlabel{subsection:Bridge:proto:solve}{{3.3.6}{17}} \@writefile{toc}{\contentsline {chapter}{\numberline {4}The Multithreaded Wrapper Object and Driver}{18}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{section:MT}{{4}{18}} \@writefile{toc}{\contentsline {section}{\numberline {4.1}A quick look at the multithreaded driver program}{19}} \newlabel{section:BridgeMT:quick-look-MT-driver}{{4.1}{19}} \@writefile{toc}{\contentsline {section}{\numberline {4.2}The \texttt {BridgeMT} Data Structure}{21}} \newlabel{section:BridgeMT:dataStructure}{{4.2}{21}} \@writefile{toc}{\contentsline {section}{\numberline {4.3}Prototypes and descriptions of \texttt {BridgeMT} methods}{22}} \newlabel{section:BridgeMT:proto}{{4.3}{22}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.3.1}Basic methods}{22}} \newlabel{subsection:BridgeMT:proto:basics}{{4.3.1}{22}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.3.2}Instance methods}{23}} \newlabel{subsection:BridgeMT:proto:instance}{{4.3.2}{23}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.3.3}Parameter methods}{24}} \newlabel{subsection:BridgeMT:proto:parameters}{{4.3.3}{24}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.3.4}Setup methods}{25}} \newlabel{subsection:BridgeMT:proto:setup}{{4.3.4}{25}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.3.5}Factor methods}{25}} \newlabel{subsection:BridgeMT:proto:factor}{{4.3.5}{25}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.3.6}Solve methods}{26}} \newlabel{subsection:BridgeMT:proto:solve}{{4.3.6}{26}} \@writefile{toc}{\contentsline {chapter}{\numberline {5}The MPI Wrapper Object and Driver}{27}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{section:MPI}{{5}{27}} \@writefile{toc}{\contentsline {section}{\numberline {5.1}A quick look at the MPI driver program}{28}} \newlabel{section:BridgeMPI:quick-look-MPI-driver}{{5.1}{28}} \@writefile{toc}{\contentsline {section}{\numberline {5.2}The \texttt {BridgeMPI} Data Structure}{30}} \newlabel{section:BridgeMPI:dataStructure}{{5.2}{30}} \@writefile{toc}{\contentsline {section}{\numberline {5.3}Prototypes and descriptions of \texttt {BridgeMPI} methods}{32}} \newlabel{section:BridgeMPI:proto}{{5.3}{32}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.3.1}Basic methods}{32}} \newlabel{subsection:BridgeMPI:proto:basics}{{5.3.1}{32}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.3.2}Instance methods}{33}} \newlabel{subsection:BridgeMPI:proto:instance}{{5.3.2}{33}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.3.3}Parameter methods}{34}} \newlabel{subsection:BridgeMPI:proto:parameters}{{5.3.3}{34}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.3.4}Setup methods}{35}} \newlabel{subsection:BridgeMPI:proto:setup}{{5.3.4}{35}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.3.5}Factor methods}{35}} \newlabel{subsection:BridgeMPI:proto:factor}{{5.3.5}{35}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.3.6}Solve methods}{36}} \newlabel{subsection:BridgeMPI:proto:solve}{{5.3.6}{36}} \@writefile{toc}{\contentsline {chapter}{\numberline {A}{\tt testWrapper.c} --- A Serial Driver Program}{37}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:serial_driver}{{A}{37}} \@writefile{toc}{\contentsline {chapter}{\numberline {B}{\tt testWrapperMT.c} --- A Multithreaded Driver Program}{43}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:MT_driver}{{B}{43}} \@writefile{toc}{\contentsline {chapter}{\numberline {C}{\tt testWrapperMPI.c} --- A MPI Driver Program}{50}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:MPI_driver}{{C}{50}} LinSol/doc/main.ind010064400020550007177000000056510662432750500154760ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Bridge\_clearData()}, 15 \item {\tt Bridge\_factor()}, 17 \item {\tt Bridge\_factorStats()}, 17 \item {\tt Bridge\_free()}, 15 \item {\tt Bridge\_frontETree()}, 16 \item {\tt Bridge\_frontmtx()}, 16 \item {\tt Bridge\_mtxmanager()}, 16 \item {\tt Bridge\_new()}, 15 \item {\tt Bridge\_newToOldIV()}, 15 \item {\tt Bridge\_oldToNewIV()}, 15 \item {\tt Bridge\_setDefaultFields()}, 15 \item {\tt Bridge\_setFactorParams()}, 16 \item {\tt Bridge\_setMatrixParams()}, 16 \item {\tt Bridge\_setMessagesInfo()}, 16 \item {\tt Bridge\_setOrderingParams()}, 16 \item {\tt Bridge\_setup()}, 17 \item {\tt Bridge\_solve()}, 17 \item {\tt Bridge\_symbfacIVL()}, 16 \item {\tt BridgeMPI\_clearData()}, 32 \item {\tt BridgeMPI\_factor()}, 36 \item {\tt BridgeMPI\_factorSetup()}, 35 \item {\tt BridgeMPI\_factorStats()}, 35 \item {\tt BridgeMPI\_free()}, 32 \item {\tt BridgeMPI\_frontETree()}, 33 \item {\tt BridgeMPI\_frontmtx()}, 33 \item {\tt BridgeMPI\_lookahead()}, 34 \item {\tt BridgeMPI\_mtxmanager()}, 33 \item {\tt BridgeMPI\_myid()}, 34 \item {\tt BridgeMPI\_new()}, 32 \item {\tt BridgeMPI\_newToOldIV()}, 33 \item {\tt BridgeMPI\_nproc()}, 34 \item {\tt BridgeMPI\_oldToNewIV()}, 33 \item {\tt BridgeMPI\_ownedColumns()}, 33 \item {\tt BridgeMPI\_ownersIV()}, 33 \item {\tt BridgeMPI\_rowmapIV()}, 33 \item {\tt BridgeMPI\_setDefaultFields()}, 32 \item {\tt BridgeMPI\_setFactorParams()}, 35 \item {\tt BridgeMPI\_setMatrixParams()}, 34 \item {\tt BridgeMPI\_setMessagesInfo()}, 35 \item {\tt BridgeMPI\_setMPIparams()}, 34 \item {\tt BridgeMPI\_setOrderingParams()}, 34 \item {\tt BridgeMPI\_setup()}, 35 \item {\tt BridgeMPI\_solve()}, 36 \item {\tt BridgeMPI\_solvemap()}, 33 \item {\tt BridgeMPI\_solveSetup()}, 36 \item {\tt BridgeMPI\_symbfacIVL()}, 33 \item {\tt BridgeMPI\_vtxmapIV()}, 33 \item {\tt BridgeMPI\_Xloc()}, 34 \item {\tt BridgeMPI\_Yloc()}, 34 \item {\tt BridgeMT\_clearData()}, 23 \item {\tt BridgeMT\_factor()}, 26 \item {\tt BridgeMT\_factorSetup()}, 25 \item {\tt BridgeMT\_factorStats()}, 25 \item {\tt BridgeMT\_free()}, 23 \item {\tt BridgeMT\_frontETree()}, 23 \item {\tt BridgeMT\_frontmtx()}, 24 \item {\tt BridgeMT\_lookahead()}, 24 \item {\tt BridgeMT\_mtxmanager()}, 24 \item {\tt BridgeMT\_new()}, 23 \item {\tt BridgeMT\_newToOldIV()}, 23 \item {\tt BridgeMT\_nthread()}, 24 \item {\tt BridgeMT\_oldToNewIV()}, 23 \item {\tt BridgeMT\_ownersIV()}, 24 \item {\tt BridgeMT\_setDefaultFields()}, 23 \item {\tt BridgeMT\_setFactorParams()}, 24 \item {\tt BridgeMT\_setMatrixParams()}, 24 \item {\tt BridgeMT\_setMessagesInfo()}, 25 \item {\tt BridgeMT\_setOrderingParams()}, 24 \item {\tt BridgeMT\_setup()}, 25 \item {\tt BridgeMT\_solve()}, 26 \item {\tt BridgeMT\_solvemap()}, 24 \item {\tt BridgeMT\_solveSetup()}, 26 \item {\tt BridgeMT\_symbfacIVL()}, 23 \end{theindex} LinSol/doc/main.ilg010064400020550007177000000004570662432750500154760ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (73 entries accepted, 0 rejected). Sorting entries....done (478 comparisons). Generating output file main.ind....done (77 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. LinSol/doc/MT.tex010064400020550007177000000725530663604574100151270ustar00clevecompmath00000400000006\chapter{The Multithreaded Wrapper Object and Driver} \label{section:MT} The goal is to solve $AX = Y$ in a multithreaded environment. Section 8 of the User's Manual presents a listing of the {\tt AllInOneMT.c} driver program for solving $AX =Y$. There are ten steps, and each requires ``mid-level'' knowledge of several objects of the {\bf SPOOLES} library. To reduce the complexity of using the library, (and the complexity rises dramatically in the MPI environments), we created the {\tt BridgeMT} object. The term ``bridge'' symbolizes spanning the distance between the {\bf SPOOLES} library and the CSAR Nastran application code. The ten steps of the {\tt allInOneMT.c} driver program is reduced to five using the {\tt BridgeMT} object. \begin{itemize} \item Initialization and setup step. \par Here the {\tt BridgeMT} object is allocated via a call to {\tt BridgeMT\_new()}. Parameters are set using {\tt BridgeMT\_set*()} methods. The setup phase orders the matrix and prepares all the necessary {\bf SPOOLES} data structures for the factorization and solve that follow \item Setup the numerical factorization. \par In this step, {\tt BridgeMT\_factorSetup()} is called to define the parallelism for the factorization, and all data structures for the parallel execution are created. \item Factorization step. \par The matrix is factored via a call to {\tt BridgeMT\_factor()}. \item Setup the numerical solves. \par {\tt BridgeMT\_solveSetup()} is called to set up the parallel solves. This must be called {\it once} after a factorization, one or more solves may follow. \item Solution step. \par The linear system is solved via a call to {\tt BridgeMT\_solve()}. \end{itemize} \par The {\tt BridgeMT} object has many parameters that control the ordering of the matrix, the pivoting tolerance (if pivoting is requested), the drop tolerance (for an approximate factorization), and so on. Rather than burden the user with the knowledge of and setting these parameters, there are decent default values built into the object. \par Section~\ref{section:BridgeMT:quick-look-MT-driver} takes a quick look at the {\tt BridgeMT} driver program (whose complete listing is found in Appendix~\ref{chapter:MT_driver}). Section~\ref{section:BridgeMT:dataStructure} describes the internal data fields of the {\tt BridgeMT} object. Section~\ref{section:Bridge:proto} contains the prototypes and descriptions of all {\tt Bridge} methods. \par \section{A quick look at the multithreaded driver program} \label{section:BridgeMT:quick-look-MT-driver} \par The entire listing of this multithreaded driver is found in Appendix~\ref{chapter:MT_driver}. We now extract parts of the code. \begin{itemize} \item Decode the input. \par \begin{verbatim} msglvl = atoi(argv[1]) ; msgFileName = argv[6] ; neqns = atoi(argv[3]) ; type = atoi(argv[4]) ; symmetryflag = atoi(argv[5]) ; mtxFileName = argv[6] ; rhsFileName = argv[7] ; solFileName = argv[8] ; seed = atoi(argv[9]) ; nthread = atoi(argv[10]) ; \end{verbatim} Here is a description of the input parameters. \begin{itemize} \item {\tt msglvl} is the message level. \item {\tt msgFile} is the message file name \item {\tt neqns} is the number of equations. \item {\tt type} is the type of entries: 1 ({\tt SPOOLES\_REAL}) or 2 ({\tt SPOOLES\_COMPLEX}). \item {\tt symmetryflag} is the type of matrix symmetry: 0 ({\tt SPOOLES\_SYMMETRIC}), 1 ({\tt SPOOLES\_HERMITIAN}) or 2 ({\tt SPOOLES\_NONSYMMETRIC}). \item {\tt mtxFile} is the name of the file from which to read the {\tt InpMtx} object for $A$. The file name must have the form {\tt *.inpmtxb} for a binary file or {\tt *.inpmtxf} for a formatted file. \item {\tt rhsFile} is the name of the file from which to read the {\tt DenseMtx} object for the right hand side $Y$. The file name must have the form {\tt *.densemtxb} for a binary file or {\tt *.densemtxf} for a formatted file. \item {\tt solFile} is the name of the file to write the {\tt DenseMtx} object for the solution $X$. The file name must have the form {\tt *.densemtxb} for a binary file or {\tt *.densemtxf} for a formatted file, {\tt "none"} for no output, or any other name for a human-readable listing. \item {\tt seed} is a random number seed used in the ordering process. \item {\tt nthread} is the number of threads to be used in the factorization and solve. \end{itemize} % \item Read in the {\tt InpMtx} object for $A$. \begin{verbatim} mtxA = InpMtx_new() ; rc = InpMtx_readFromFile(mtxA, mtxFileName) ; \end{verbatim} The {\tt rc} parameter is the error return. In the driver it is tested for an error, but we omit this from the present discussion. % \item Read in the {\tt DenseMtx} object for $Y$. \begin{verbatim} mtxY = DenseMtx_new() ; rc = DenseMtx_readFromFile(mtxY, mtxFileName) ; DenseMtx_dimensions(mtxY, &nrow, &nrhs) ; \end{verbatim} The {\tt nrhs} parameter contains the number of right hand sides, or equivalently, the number of columns in $Y$. % \item Create and setup the {\tt BridgeMT} object. \begin{verbatim} bridge = BridgeMT_new() ; BridgeMT_setMatrixParams(bridge, neqns, type, symmetryflag) ; BridgeMT_setMessageInfo(bridge, msglvl, msgFile) ; rc = BridgeMT_setup(bridge, mtxA) ; \end{verbatim} The {\tt BridgeMT} object is allocated by {\tt BridgeMT\_new()}, and various parameters are set. The actual ordering of the matrix, symbolic factorization, and permutation creation are performed inside the {\tt BridgeMT\_setup()} method. % \item Setup the numerical factorization. \begin{verbatim} rc = BridgeMT_factorSetup(bridge, nthread, 0, 0.0) ; \end{verbatim} This step tells the \texttt{BridgeMT} object the number of threads to be used in the factorization and solve. The third and fourth parameters define the particular type of map of the computations to processors. When the third parameter is zero, the defaults map is used. If {\tt rc = 1}, the setup completed without any error. % \item Compute the matrix factorization. \begin{verbatim} permuteflag = 1 ; rc = BridgeMT_factor(bridge, mtxA, permuteflag, &error) ; \end{verbatim} When {\tt permuteflag} is {\tt 1}, it means that the matrix in {\tt mtxA} has not yet been permuted into the new ordering and so is done inside the method. The {\tt error} flag is filled with an error code that tells how far the factorization was able to proceed. If {\tt rc = 1}, the factorization completed without any error. % \item Setup the solve. \begin{verbatim} rc = BridgeMT_solveSetup(bridge) ; \end{verbatim} This method sets up the environment for a parallel solve. If {\tt rc = 1}, the setup completed without any error. % \item Solve the linear system. \begin{verbatim} mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; rc = BridgeMT_solve(bridge, permuteflag, mtxX, mtxY) ; \end{verbatim} The {\tt DenseMtx} object {\tt mtxX} is created and initialized to be the same type and size as {\tt mtxY}. Its entries are explicitly zeroed (this is not necessary but is a good idea in general). The solution is then solved. Again, note the presence of {\tt permuteflag}. When {\tt 1}, \texttt{mtxY} needs to be permuted into the new ordering, and \texttt{mtxX} is returned in the original ordering. \end{itemize} \par \section{The \texttt{BridgeMT} Data Structure} \label{section:BridgeMT:dataStructure} \par The {\tt BridgeMT} structure has the following fields. \begin{itemize} % \item Graph parameters: \begin{itemize} \item {\tt int neqns} : number of equations, i.e., number of vertices in the graph. \item {\tt int nedges} : number of edges (includes $(u,v)$, $(v,u)$ and $(u,u)$). \item {\tt int Neqns} : number of equations in the compressed graph. \item {\tt int Nedges} : number of edges in the compressed graph. \end{itemize} % \item Ordering parameters: \begin{itemize} \item {\tt int maxdomainsize} : maximum size of a subgraph to not split any further during the nested dissection process. \item {\tt int maxnzeros} : maximum number of zeros to allow in a front during the supernode amalgamation process. \item {\tt int maxsize} : maximum size of a front when the fronts are split. \item {\tt int seed} : random number seed. \item {\tt double compressCutoff} : if the \texttt{Neqns} $<$ \texttt{compressCutoff} $*$ \texttt{neqns}, then the compressed graph is formed, ordered and used to create the symbolic factorization. \end{itemize} % \item Matrix parameters: \begin{itemize} \item {\tt int type} : type of entries, {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, default value is {\tt SPOOLES\_REAL}. \item {\tt int symmetryflag} : type of symmetry for the matrix, {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}, default value is {\tt SPOOLES\_SYMMETRIC}. \end{itemize} % \item Factorization parameters: \begin{itemize} \item {\tt int sparsityflag} : {\tt SPOOLES\_DENSE\_FRONTS} for a direct factorization, or {\tt SPOOLES\_SPARSE\_FRONTS} for an approximate factorization, default value is {\tt SPOOLES\_DENSE\_FRONTS}. \item {\tt int pivotingflag} : {\tt SPOOLES\_PIVOTING} for pivoting enabled, or {\tt SPOOLES\_NO\_PIVOTING} for no pivoting, default value is {\tt SPOOLES\_NO\_PIVOTING}. \item {\tt double tau} : used when pivoting is enabled, all entries in $L$ and $U$ have magnitude less than or equal to \texttt{tau}, default value is 100. \item {\tt double droptol} : used for an approximation, all entries in $L$ and $U$ that are kept have magnitude greater than or equal to \texttt{droptol}. default value is 0.001. \item {\tt PatchAndGoInfo *patchinfo} : pointer to an object that controls special factorizations for optimization matrices and singular matrices from structural analysis, default value is \texttt{NULL} which means no special action is taken. See the Reference Manual for more information. \end{itemize} % \item Pointers to objects: \begin{itemize} \item {\tt ETree *frontETree} : object that defines the factorizations, e.g., the number of fronts, the tree they form, the number of internal and external rows for each front, and the map from vertices to the front where it is contained. \item {\tt IVL *symbfacIVL} : object that contains the symbolic factorization of the matrix. \item {\tt SubMtxManager *mtxmanager} : object that manages the \texttt{SubMtx} objects that store the factor entries and are used in the solves. \item {\tt FrontMtx *frontmtx} : object that stores the $L$, $D$ and $U$ factor matrices. \item {\tt IV *oldToNewIV} : object that stores old-to-new permutation vector. \item {\tt IV *newToOldIV} : object that stores new-to-old permutation vector. \end{itemize} % \item Multithreaded information: \begin{itemize} \item {\tt int nthread} : number of threads to be used during the factor and solve. \item {\tt int lookahead} : this parameter is used to possibly reduce the idle time of threads during the factorization. When {\tt lookahead} is 0, the factorization uses the least amount of working storage but threads can be idle. Larger values of {\tt lookahead} tend to increase the working storage but may decrease the execution time. Values of {\tt lookahead} greater than {\tt nthread} are not useful. \item {\tt IV *ownersIV} : this object contains the map from fronts to their owning processors. \item {\tt SolveMap *solvemap} : this object contains the map from factor submatrices to their owning processors. \item {\tt DV *cumopsDV} : this object is formed when the map from fronts to owning processors is created. Its size is {\tt nthread} and contains the operations that each thread will perform during a direct factorization without pivoting. \end{itemize} % \item Message information, statistics and cpu times: \begin{itemize} \item {\tt int msglvl} : message level for output. When 0, no output, When 1, just statistics and cpu times. When greater than 1, more and more output. \item {\tt FILE *msgFile} : message file for output. When \texttt{msglvl} $>$ 0, \texttt{msgFile} must not be \texttt{NULL}. \item {\tt int stats[6]} : statistics for the factorization. \begin{center} \begin{tabular}{ll} \texttt{stats[0]} : & \# of pivots \\ \texttt{stats[1]} : & \# of pivot tests \\ \texttt{stats[2]} : & \# of delayed rows and columns \end{tabular} \begin{tabular}{ll} \texttt{stats[3]} : & \# of entries in $D$ \\ \texttt{stats[4]} : & \# of entries in $L$ \\ \texttt{stats[5]} : & \# of entries in $U$ \end{tabular} \end{center} \item {\tt double cpus[16]} : cpus for the different functions. \begin{center} \begin{tabular}{ll} \texttt{cpus[0]} : & time to construct \texttt{Graph} \\ \texttt{cpus[1]} : & time to compress \texttt{Graph} \\ \texttt{cpus[2]} : & time to order \texttt{Graph} \\ \texttt{cpus[3]} : & time for symbolic factorization \\ \texttt{cpus[4]} : & total setup time \\ \texttt{cpus[5]} : & time to setup the factorization \\ \texttt{cpus[6]} : & time to permute matrix \\ \texttt{cpus[7]} : & time to initialize front matrix \end{tabular} \begin{tabular}{ll} \texttt{cpus[8]} : & time to factor matrix \\ \texttt{cpus[9]} : & time to post-process matrix \\ \texttt{cpus[10]} : & total factor time \\ \texttt{cpus[11]} : & time to setup the parallel solve \\ \texttt{cpus[12]} : & time to permute rhs \\ \texttt{cpus[13]} : & time to solve \\ \texttt{cpus[14]} : & time to permute solution \\ \texttt{cpus[15]} : & total solve time \end{tabular} \end{center} \end{itemize} \end{itemize} \par \section{Prototypes and descriptions of \texttt{BridgeMT} methods} \label{section:BridgeMT:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt BridgeMT} object. \par \subsection{Basic methods} \label{subsection:BridgeMT:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} BridgeMT * BridgeMT_new ( void ) ; \end{verbatim} \index{BridgeMT_new@{\tt BridgeMT\_new()}} This method simply allocates storage for the {\tt BridgeMT} structure and then sets the default fields by a call to {\tt BridgeMT\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_setDefaultFields ( BridgeMT *bridge ) ; \end{verbatim} \index{BridgeMT_setDefaultFields@{\tt BridgeMT\_setDefaultFields()}} The structure's fields are set to default values: \begin{itemize} \item \texttt{neqns} = \texttt{nedges} = \texttt{Neqns} = \texttt{Nedges} = 0. \item \texttt{maxdomainsize} = \texttt{maxnzeros} = \texttt{maxsize} = \texttt{seed} = -1. \texttt{compressCutoff} = 0. \item \texttt{type} = \texttt{SPOOLES\_REAL}. \item \texttt{symmetryflag} = \texttt{SPOOLES\_SYMMETRIC}. \item \texttt{sparsityflag} = \texttt{SPOOLES\_DENSE\_FRONTS}. \item \texttt{pivotingflag} = \texttt{SPOOLES\_NO\_PIVOTING}. \item \texttt{tau} = 100., \texttt{droptol} = 0.001. \item \texttt{lookahead} = \texttt{nthread} = 0. \item \texttt{patchinfo}, \texttt{frontETree}, \texttt{symbfacIVL}, \texttt{mtxmanager}, \texttt{frontmtx}, \texttt{oldToNewIV}, \texttt{newToOldIV}, \texttt{ownersIV}, \texttt{solvemap} and \texttt{cumopsDV} are all set to \texttt{NULL}. \end{itemize} The \texttt{stats[6]} and \texttt{cpus[16]} vectors are filled with zeros. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_clearData ( BridgeMT *bridge ) ; \end{verbatim} \index{BridgeMT_clearData@{\tt BridgeMT\_clearData()}} This method clears the object and free's any owned data. It then calls {\tt BridgeMT\_setDefaultFields()}. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_free ( BridgeMT *bridge ) ; \end{verbatim} \index{BridgeMT_free@{\tt BridgeMT\_free()}} This method releases any storage by a call to {\tt BridgeMT\_clearData()} and then free the space for {\tt bridge}. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:BridgeMT:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_oldToNewIV ( BridgeMT *bridge, IV **pobj ) ; \end{verbatim} \index{BridgeMT_oldToNewIV@{\tt BridgeMT\_oldToNewIV()}} This method fills \texttt{*pobj} with its \texttt{oldToNewIV} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_newToOldIV ( BridgeMT *bridge, IV **pobj ) ; \end{verbatim} \index{BridgeMT_newToOldIV@{\tt BridgeMT\_newToOldIV()}} This method fills \texttt{*pobj} with its \texttt{newToOldIV} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_frontETree ( BridgeMT *bridge, ETree **pobj ) ; \end{verbatim} \index{BridgeMT_frontETree@{\tt BridgeMT\_frontETree()}} This method fills \texttt{*pobj} with its \texttt{frontETree} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_symbfacIVL ( BridgeMT *bridge, IVL **pobj ) ; \end{verbatim} \index{BridgeMT_symbfacIVL@{\tt BridgeMT\_symbfacIVL()}} This method fills \texttt{*pobj} with its \texttt{symbfacIVL} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_mtxmanager ( BridgeMT *bridge, SubMtxManager **pobj ) ; \end{verbatim} \index{BridgeMT_mtxmanager@{\tt BridgeMT\_mtxmanager()}} This method fills \texttt{*pobj} with its \texttt{mtxmanager} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_frontmtx ( BridgeMT *bridge, FrontMtx **pobj ) ; \end{verbatim} \index{BridgeMT_frontmtx@{\tt BridgeMT\_frontmtx()}} This method fills \texttt{*pobj} with its \texttt{frontmtx} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_ownersIV ( BridgeMT *bridge, IV **pobj ) ; \end{verbatim} \index{BridgeMT_ownersIV@{\tt BridgeMT\_ownersIV()}} This method fills \texttt{*pobj} with its \texttt{ownersIV} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_solvemap ( BridgeMT *bridge, SolveMap **pobj ) ; \end{verbatim} \index{BridgeMT_solvemap@{\tt BridgeMT\_solvemap()}} This method fills \texttt{*pobj} with its \texttt{solvemap} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_nthread ( BridgeMT *bridge, int *pnthread ) ; \end{verbatim} \index{BridgeMT_nthread@{\tt BridgeMT\_nthread()}} This method fills \texttt{*pobj} with the number of threads. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pnthread} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_lookahead ( BridgeMT *bridge, int *plookahead ) ; \end{verbatim} \index{BridgeMT_lookahead@{\tt BridgeMT\_lookahead()}} This method fills \texttt{*pobj} with the lookahead parameter. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{plookahead} is \texttt{NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Parameter methods} \label{subsection:BridgeMT:proto:parameters} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_setMatrixParams ( BridgeMT *bridge, int neqns, int type, int symmetryflag ) ; \end{verbatim} \index{BridgeMT_setMatrixParams@{\tt BridgeMT\_setMatrixParams()}} This method sets the number of equations, type of entries, and symmetry type of the matrix. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{neqns} $\le$ 0 \end{tabular} \begin{tabular}{ll} -3 & \texttt{type} is invalid \\ -4 & \texttt{symmetryflag} is invalid \\ -5 & symmetry flag is Hermitian but type is real \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_setOrderingParams ( BridgeMT *bridge, int maxdomainsize, int maxnzeros, int maxsize, int seed, double compressCutoff ) ; \end{verbatim} \index{BridgeMT_setOrderingParams@{\tt BridgeMT\_setOrderingParams()}} This method sets parameters needed for the ordering. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{maxdomainsize} $\le$ 0 \end{tabular} \begin{tabular}{ll} -3 & \texttt{maxsize} $\le$ 0 \\ -4 & \texttt{compressCutoff} $>$ 1 \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_setFactorParams ( BridgeMT *bridge, int sparsityflag, int pivotingflag, double tau, double droptol, int lookahead, PatchAndGoInfo *patchinfo ) ; \end{verbatim} \index{BridgeMT_setFactorParams@{\tt BridgeMT\_setFactorParams()}} This method sets parameters needed for the factorization. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{sparsityflag} is invalid \\ -3 & \texttt{pivotingflag} is invalid \end{tabular} \begin{tabular}{ll} -4 & \texttt{tau} $<$ 2.0 \\ -5 & \texttt{droptol} $<$ 0.0 \\ -6 & \texttt{lookahead} $<$ 0 \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_setMessagesInfo ( BridgeMT *bridge, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{BridgeMT_setMessagesInfo@{\tt BridgeMT\_setMessagesInfo()}} This method sets the message level and file. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}, -2 if \texttt{msglvl} $>$ 0 and \texttt{msgFile} is \texttt{NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Setup methods} \label{subsection:BridgeMT:proto:setup} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_setup ( BridgeMT *bridge, InpMtx *mtxA ) ; \end{verbatim} \index{BridgeMT_setup@{\tt BridgeMT\_setup()}} This method orders the graph, generates the front tree, computes the symbolic factorization, and creates the two permutation vectors. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}, -2 if \texttt{mtxA} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_factorStats ( BridgeMT *bridge, int type, int symmetryflag, int *pnfront, int *pnfactorind, int *pnfactorent, int *pnsolveops, double *pnfactorops ) ; \end{verbatim} \index{BridgeMT_factorStats@{\tt BridgeMT\_factorStats()}} This method takes as input the type and symmetry of the matrix, and fills the pointer fields with the number of fronts, factor indices, factor entries, forward and back solve operations, and factor operations. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{type} is invalid \\ -3 & \texttt{symmetryflag} is invalid \\ -4 & \texttt{type} is real but \texttt{symmetryflag} is Hermitian \\ -5 & front tree is not present \end{tabular} \begin{tabular}{ll} ~-6 & \texttt{pnfront} is \texttt{NULL} \\ ~-7 & \texttt{pnfactorind} is \texttt{NULL} \\ ~-8 & \texttt{pnfactorent} is \texttt{NULL} \\ ~-9 & \texttt{pnsolveops} is \texttt{NULL} \\ -10 & \texttt{pnfactorops} is \texttt{NULL} \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Factor methods} \label{subsection:BridgeMT:proto:factor} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_factorSetup ( BridgeMT *bridge, int nthread, int maptype, double cutoff ) ; \end{verbatim} \index{BridgeMT_factorSetup@{\tt BridgeMT\_factorSetup()}} This method constructs the map from fronts to owning threads, and computes the number of factor operations that each thread will execute. The \texttt{maptype} parameter can be one of four values: \begin{itemize} \item 1 --- wrap map \item 2 --- balanced map \item 3 --- subtree-subset map \item 4 --- domain decomposition map \end{itemize} The wrap map and balanced map are not recommended. The subtree-subset map is a good map with a very well balanced nested dissection ordering. The domain decomposition map is recommended when the nested dissection tree is imbalanced or for the multisection ordering. The domain decomposition map requires a \texttt{cutoff} parameter in $\left \lbrack0,1\right \rbrack$ which specifies the relative size of a subtree that forms a domain. If \texttt{maptype} is not one of 1, 2, 3 or 4, the default map is used: domain decomposition with \texttt{cutoff} = 1/(2*\texttt{nthread}). \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return, factorization did complete \\ -1 & \texttt{bridge} is \texttt{NULL} \\ \end{tabular} \begin{tabular}{ll} -2 & \texttt{nthread} $<$ 1 \\ -5 & \texttt{frontETree} is not present \\ \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_factor ( BridgeMT *bridge, InpMtx *mtxA, int permuteflag, int *perror ) ; \end{verbatim} \index{BridgeMT_factor@{\tt BridgeMT\_factor()}} This method permutes the matrix into the new ordering (if \texttt{permuteflag} is 1), factors the matrix, and then post-processes the factors. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return, factorization did complete \\ ~0 & factorization did not complete \\ \end{tabular} \begin{tabular}{ll} -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{mtxA} is \texttt{NULL} \\ -3 & \texttt{perror} is \texttt{NULL} \\ \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Solve methods} \label{subsection:BridgeMT:proto:solve} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_solveSetup ( BridgeMT *bridge ) ; \end{verbatim} \index{BridgeMT_solveSetup@{\tt BridgeMT\_solveSetup()}} This method creates the {\tt SolveMap} object that governs the parallel solve. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \end{tabular} \begin{tabular}{ll} -2 & \texttt{frontMtx} is \texttt{NULL} \\ -3 & \texttt{frontMtx} needs to be postprocessed \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMT_solve ( BridgeMT *bridge, int permuteflag, DenseMtx *mtxX, DenseMtx *mtxY ) ; \end{verbatim} \index{BridgeMT_solve@{\tt BridgeMT\_solve()}} If \texttt{permuteflag} is 1, then \texttt{mtxY} is permuted into the new ordering. The linear system $AX = Y$ is solved. If \texttt{permuteflag} is 1, then \texttt{mtxX} is permuted into the old ordering. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{X} is \texttt{NULL} \\ -3 & \texttt{Y} is \texttt{NULL} \\ \end{tabular} \begin{tabular}{ll} -4 & \texttt{frontmtx} is \texttt{NULL} \\ -5 & \texttt{mtxmanager} is \texttt{NULL} \\ -6 & \texttt{oldToNewIV} needed, but not available \\ -7 & \texttt{newToOldIV} needed, but not available \\ \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} nd{verbatim} \index{BridgeMT_solvemap@{\tt BridgeMT\_solvemap()}} This method fills \texttt{*pobj} with its \texttt{solvemap} pointer. \par \noindentLinSol/doc/main.toc010064400020550007177000000055720664347136600155210ustar00clevecompmath00000400000006\contentsline {chapter}{\numberline {1}Introduction}{3} \contentsline {chapter}{\numberline {2}Setting up the linear system}{5} \contentsline {section}{\numberline {2.1}Constructing an {\tt InpMtx} object}{5} \contentsline {section}{\numberline {2.2}Constructing an {\tt DenseMtx} object}{8} \contentsline {section}{\numberline {2.3}IO for the {\tt InpMtx} and {\tt DenseMtx} objects}{9} \contentsline {chapter}{\numberline {3}The Serial Wrapper Object and Driver}{11} \contentsline {section}{\numberline {3.1}A quick look at serial driver program}{11} \contentsline {section}{\numberline {3.2}The \texttt {Bridge} Data Structure}{13} \contentsline {section}{\numberline {3.3}Prototypes and descriptions of \texttt {Bridge} methods}{15} \contentsline {subsection}{\numberline {3.3.1}Basic methods}{15} \contentsline {subsection}{\numberline {3.3.2}Instance methods}{15} \contentsline {subsection}{\numberline {3.3.3}Parameter methods}{16} \contentsline {subsection}{\numberline {3.3.4}Setup methods}{17} \contentsline {subsection}{\numberline {3.3.5}Factor method}{17} \contentsline {subsection}{\numberline {3.3.6}Solve method}{17} \contentsline {chapter}{\numberline {4}The Multithreaded Wrapper Object and Driver}{18} \contentsline {section}{\numberline {4.1}A quick look at the multithreaded driver program}{19} \contentsline {section}{\numberline {4.2}The \texttt {BridgeMT} Data Structure}{21} \contentsline {section}{\numberline {4.3}Prototypes and descriptions of \texttt {BridgeMT} methods}{22} \contentsline {subsection}{\numberline {4.3.1}Basic methods}{22} \contentsline {subsection}{\numberline {4.3.2}Instance methods}{23} \contentsline {subsection}{\numberline {4.3.3}Parameter methods}{24} \contentsline {subsection}{\numberline {4.3.4}Setup methods}{25} \contentsline {subsection}{\numberline {4.3.5}Factor methods}{25} \contentsline {subsection}{\numberline {4.3.6}Solve methods}{26} \contentsline {chapter}{\numberline {5}The MPI Wrapper Object and Driver}{27} \contentsline {section}{\numberline {5.1}A quick look at the MPI driver program}{28} \contentsline {section}{\numberline {5.2}The \texttt {BridgeMPI} Data Structure}{30} \contentsline {section}{\numberline {5.3}Prototypes and descriptions of \texttt {BridgeMPI} methods}{32} \contentsline {subsection}{\numberline {5.3.1}Basic methods}{32} \contentsline {subsection}{\numberline {5.3.2}Instance methods}{33} \contentsline {subsection}{\numberline {5.3.3}Parameter methods}{34} \contentsline {subsection}{\numberline {5.3.4}Setup methods}{35} \contentsline {subsection}{\numberline {5.3.5}Factor methods}{35} \contentsline {subsection}{\numberline {5.3.6}Solve methods}{36} \contentsline {chapter}{\numberline {A}{\tt testWrapper.c} --- A Serial Driver Program}{37} \contentsline {chapter}{\numberline {B}{\tt testWrapperMT.c} --- A Multithreaded Driver Program}{43} \contentsline {chapter}{\numberline {C}{\tt testWrapperMPI.c} --- A MPI Driver Program}{50} LinSol/doc/MT_driver.tex010060000020550007177000000244550662007202000164470ustar00clevecompmath00000400000006\chapter{{\tt testWrapperMT.c} --- A Multithreaded Driver Program} \label{chapter:MT_driver} \begin{verbatim} /* testWrapperMT.c */ #include "../BridgeMT.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ----------------------------------------------------------- purpose -- main driver program to solve a linear system where the matrix and rhs are read in from files and the solution is written to a file. NOTE: multithreaded version created -- 98sep24, cca ----------------------------------------------------------- */ BridgeMT *bridge ; char *mtxFileName, *rhsFileName, *solFileName ; double nfactorops ; FILE *msgFile ; InpMtx *mtxA ; int error, msglvl, neqns, nfent, nfind, nfront, nrhs, nrow, nsolveops, nthread, permuteflag, rc, seed, symmetryflag, type ; DenseMtx *mtxX, *mtxY ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 11 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile neqns type symmetryflag " "\n mtxFile rhsFile solFile seed nthread\n" "\n msglvl -- message level" "\n 0 -- no output" "\n 1 -- timings and statistics" "\n 2 and greater -- lots of output" "\n msgFile -- message file" "\n neqns -- # of equations" "\n type -- type of entries" "\n 1 -- real" "\n 2 -- complex" "\n symmetryflag -- symmetry flag" "\n 0 -- symmetric" "\n 1 -- hermitian" "\n 2 -- nonsymmetric" "\n neqns -- # of equations" "\n mtxFile -- input file for A matrix InpMtx object" "\n must be *.inpmtxf or *.inpmtxb" "\n rhsFile -- input file for Y DenseMtx object" "\n must be *.densemtxf or *.densemtxb" "\n solFile -- output file for X DenseMtx object" "\n must be none, *.densemtxf or *.densemtxb" "\n seed -- random number seed" "\n nthread -- number of threads" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } neqns = atoi(argv[3]) ; type = atoi(argv[4]) ; symmetryflag = atoi(argv[5]) ; mtxFileName = argv[6] ; rhsFileName = argv[7] ; solFileName = argv[8] ; seed = atoi(argv[9]) ; nthread = atoi(argv[10]) ; fprintf(msgFile, "\n\n %s input :" "\n msglvl = %d" "\n msgFile = %s" "\n neqns = %d" "\n type = %d" "\n symmetryflag = %d" "\n mtxFile = %s" "\n rhsFile = %s" "\n solFile = %s" "\n nthread = %d" "\n", argv[0], msglvl, argv[2], neqns, type, symmetryflag, mtxFileName, rhsFileName, solFileName, nthread) ; /*--------------------------------------------------------------------*/ /* ------------------ read in the matrix ------------------ */ mtxA = InpMtx_new() ; rc = InpMtx_readFromFile(mtxA, mtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxA from file %s, rc = %d", mtxFileName, rc) ; fflush(msgFile) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n InpMtx object ") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- read in the right hand side matrix ---------------------------------- */ mtxY = DenseMtx_new() ; rc = DenseMtx_readFromFile(mtxY, rhsFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxY from file %s, rc = %d", rhsFileName, rc) ; fflush(msgFile) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n DenseMtx object for right hand side") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } DenseMtx_dimensions(mtxY, &nrow, &nrhs) ; /*--------------------------------------------------------------------*/ /* ---------------------------------- create and setup a BridgeMT object ---------------------------------- */ bridge = BridgeMT_new() ; BridgeMT_setMatrixParams(bridge, neqns, type, symmetryflag) ; BridgeMT_setMessageInfo(bridge, msglvl, msgFile) ; rc = BridgeMT_setup(bridge, mtxA) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from BridgeMT_setup()", rc) ; exit(-1) ; } fprintf(msgFile, "\n\n ----- SETUP -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to construct Graph" "\n CPU %8.3f : time to compress Graph" "\n CPU %8.3f : time to order Graph" "\n CPU %8.3f : time for symbolic factorization" "\n CPU %8.3f : total setup time\n", bridge->cpus[0], bridge->cpus[1], bridge->cpus[2], bridge->cpus[3], bridge->cpus[4]) ; rc = BridgeMT_factorStats(bridge, type, symmetryflag, &nfront, &nfind, &nfent, &nsolveops, &nfactorops) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from BridgeMT_factorStats()", rc) ; exit(-1) ; } fprintf(msgFile, "\n\n factor matrix statistics" "\n %d fronts, %d indices, %d entries" "\n %d solve operations, %12.4e factor operations", nfront, nfind, nfent, nsolveops, nfactorops) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* -------------------------------- setup the parallel factorization -------------------------------- */ rc = BridgeMT_factorSetup(bridge, nthread, 0, 0.0) ; fprintf(msgFile, "\n\n ----- PARALLEL FACTOR SETUP -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to setup parallel factorization", bridge->cpus[5]) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n total factor operations = %.0f", DV_sum(bridge->cumopsDV)) ; fprintf(msgFile, "\n upper bound on speedup due to load balance = %.2f", DV_sum(bridge->cumopsDV)/DV_max(bridge->cumopsDV)) ; fprintf(msgFile, "\n operations distributions over threads") ; DV_writeForHumanEye(bridge->cumopsDV, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------- factor the matrix ----------------- */ permuteflag = 1 ; rc = BridgeMT_factor(bridge, mtxA, permuteflag, &error) ; if ( rc == 1 ) { fprintf(msgFile, "\n\n factorization completed successfully\n") ; } else { fprintf(msgFile, "\n return code from factorization = %d\n" "\n error code = %d\n", rc, error) ; exit(-1) ; } fprintf(msgFile, "\n\n ----- FACTORIZATION -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to permute original matrix" "\n CPU %8.3f : time to initialize factor matrix" "\n CPU %8.3f : time to compute factorization" "\n CPU %8.3f : time to post-process factorization" "\n CPU %8.3f : total factorization time\n", bridge->cpus[6], bridge->cpus[7], bridge->cpus[8], bridge->cpus[9], bridge->cpus[10]) ; fprintf(msgFile, "\n\n factorization statistics" "\n %d pivots, %d pivot tests, %d delayed vertices" "\n %d entries in D, %d entries in L, %d entries in U", bridge->stats[0], bridge->stats[1], bridge->stats[2], bridge->stats[3], bridge->stats[4], bridge->stats[5]) ; fprintf(msgFile, "\n\n factorization: raw mflops %8.3f, overall mflops %8.3f", 1.e-6*nfactorops/bridge->cpus[8], 1.e-6*nfactorops/bridge->cpus[10]) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* ------------------------ setup the parallel solve ------------------------ */ rc = BridgeMT_solveSetup(bridge) ; fprintf(msgFile, "\n\n ----- PARALLEL SOLVE SETUP -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to setup parallel solve", bridge->cpus[11]) ; /*--------------------------------------------------------------------*/ /* ---------------- solve the system ---------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; rc = BridgeMT_solve(bridge, permuteflag, mtxX, mtxY) ; if (rc == 1) { fprintf(msgFile, "\n\n solve complete successfully\n") ; } else { fprintf(msgFile, "\n" " return code from solve = %d\n", rc) ; } fprintf(msgFile, "\n\n ----- SOLVE -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to permute rhs into new ordering" "\n CPU %8.3f : time to solve linear system" "\n CPU %8.3f : time to permute solution into old ordering" "\n CPU %8.3f : total solve time\n", bridge->cpus[12], bridge->cpus[13], bridge->cpus[14], bridge->cpus[15]) ; fprintf(msgFile, "\n\n solve: raw mflops %8.3f, overall mflops %8.3f", 1.e-6*nsolveops/bridge->cpus[13], 1.e-6*nsolveops/bridge->cpus[15]) ; fflush(msgFile) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ if ( strcmp(solFileName, "none") != 0 ) { /* ----------------------------------- write the solution matrix to a file ----------------------------------- */ rc = DenseMtx_writeToFile(mtxX, solFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error writing mtxX to file %s, rc = %d", solFileName, rc) ; fflush(msgFile) ; exit(-1) ; } } /*--------------------------------------------------------------------*/ /* --------------------- free the working data --------------------- */ InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxY) ; BridgeMT_free(bridge) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ \end{verbatim} LinSol/doc/MPI.tex010064400020550007177000001035140662432775200152260ustar00clevecompmath00000400000006\chapter{The MPI Wrapper Object and Driver} \label{section:MPI} \par The goal is to solve $AX = Y$ in a distributed environment using MPI. Section 9 of the User's Manual presents a listing of the {\tt AllInOneMPI} driver program for solving $AX =Y$. There are thirteen steps, and each requires ``mid-level'' knowledge of several objects of the {\bf SPOOLES} library. To reduce the complexity of using the library, we created the {\tt BridgeMPI} object. The term ``bridge'' symbolizes spanning the distance between the {\bf SPOOLES} library and the CSAR Nastran application code. The ten steps of the {\tt allInOneMPI} driver program is reduced to five using the {\tt BridgeMPI} object. \begin{itemize} \item Initialization and setup step. \par Here the {\tt BridgeMPI} object is allocated via a call to {\tt BridgeMPI\_new()}. Parameters are set using {\tt BridgeMPI\_set*()} methods. The setup phase orders the matrix and prepares all the necessary {\bf SPOOLES} data structures for the factorization and solve that follows. \item Setup the numerical factorization. \par In this step, {\tt BridgeMPI\_factorSetup()} is called to define the parallelism for the factorization, and all data structures for the parallel execution are created. \item Factorization step. \par The matrix is factored via a call to {\tt BridgeMPI\_factor()}. \item Setup the numerical solves. \par {\tt BridgeMPI\_solveSetup()} is called to set up the parallel solves. This must be called {\it once} after a factorization, one or more solves may follow. \item Solution step. \par The linear system is solved via a call to {\tt BridgeMPI\_solve()}. \end{itemize} \par The {\tt BridgeMPI} object has many parameters that control the ordering of the matrix, the pivoting tolerance (if pivoting is requested), the drop tolerance (for an approximate factorization), and so on. Rather than burden the user with the knowledge of and setting these parameters, there are decent default values built into the object. Using the {\tt BridgeMPI} object to solve a linear system of equations can be broken down into three steps. \par Section~\ref{section:BridgeMPI:quick-look-MPI-driver} takes a quick look at the {\tt BridgeMPI} driver program (whose complete listing is found in Appendix~\ref{chapter:MPI_driver}). Section~\ref{section:BridgeMPI:dataStructure} describes the internal data fields of the {\tt BridgeMPI} object. Section~\ref{section:Bridge:proto} contains the prototypes and descriptions of all {\tt Bridge} methods. \par \section{A quick look at the MPI driver program} \label{section:BridgeMPI:quick-look-MPI-driver} \par The entire listing of this MPI driver is found in Appendix~\ref{chapter:MPI_driver}. We now extract parts of the code. \begin{itemize} \item Decode the input. \par \begin{verbatim} msglvl = atoi(argv[1]) ; msgFileName = argv[6] ; neqns = atoi(argv[3]) ; type = atoi(argv[4]) ; symmetryflag = atoi(argv[5]) ; mtxFileName = argv[6] ; rhsFileName = argv[7] ; solFileName = argv[8] ; seed = atoi(argv[9]) ; \end{verbatim} Here is a description of the input parameters. \begin{itemize} \item {\tt msglvl} is the message level. \item {\tt msgFile} is the message file name \item {\tt neqns} is the number of equations. \item {\tt type} is the type of entries: 1 ({\tt SPOOLES\_REAL}) or 2 ({\tt SPOOLES\_COMPLEX}). \item {\tt symmetryflag} is the type of matrix symmetry: 0 ({\tt SPOOLES\_SYMMETRIC}), 1 ({\tt SPOOLES\_HERMITIAN}) or 2 ({\tt SPOOLES\_NONSYMMETRIC}). \item {\tt mtxFile} is the name of the file from which to read the {\tt InpMtx} object for $A$. The file name must have the form {\tt *.inpmtxb} for a binary file or {\tt *.inpmtxf} for a formatted file. \item {\tt rhsFile} is the name of the file from which to read the {\tt DenseMtx} object for the right hand side $Y$. The file name must have the form {\tt *.densemtxb} for a binary file or {\tt *.densemtxf} for a formatted file. \item {\tt solFile} is the name of the file to write the {\tt DenseMtx} object for the solution $X$. The file name must have the form {\tt *.densemtxb} for a binary file or {\tt *.densemtxf} for a formatted file, {\tt "none"} for no output, or any other name for a human-readable listing. \item {\tt seed} is a random number seed used in the ordering process. \end{itemize} % \item Processor 0 reads in the {\tt InpMtx} object for $A$. \begin{verbatim} mtxA = InpMtx_new() ; rc = InpMtx_readFromFile(mtxA, mtxFileName) ; \end{verbatim} The {\tt rc} parameter is the error return. Processor 0 then broadcasts the error return to the other processors. If an error occured reading in the matrix, all processors call \texttt{MPI\_Finalize()} and exit. % \item Processor 0 reads in the {\tt DenseMtx} object for $Y$. \begin{verbatim} mtxY = DenseMtx_new() ; rc = DenseMtx_readFromFile(mtxY, mtxFileName) ; DenseMtx_dimensions(mtxY, &nrow, &nrhs) ; \end{verbatim} The {\tt nrhs} parameter contains the number of right hand sides, or equivalently, the number of columns in $Y$. Processor 0 then broadcasts the error return to the other processors. If an error occured reading in the matrix, all processors call \texttt{MPI\_Finalize()} and exit. % \item Create and setup the {\tt BridgeMPI} object. \begin{verbatim} bridge = BridgeMPI_new() ; BridgeMPI_setMPIparams(bridge, nproc, myid, MPI_COMM_WORLD) ; BridgeMPI_setMatrixParams(bridge, neqns, type, symmetryflag) ; BridgeMPI_setMessageInfo(bridge, msglvl, msgFile) ; rc = BridgeMPI_setup(bridge, mtxA) ; \end{verbatim} The {\tt BridgeMPI} object is allocated by {\tt BridgeMPI\_new()}, and various parameters are set. The actual ordering of the matrix, symbolic factorization, and permutation creation are performed inside the {\tt BridgeMPI\_setup()} method. % \item Setup the numerical factorization. \begin{verbatim} rc = BridgeMPI_factorSetup(bridge, 0, 0.0) ; \end{verbatim} This step tells the \texttt{BridgeMPI} object the number of threads to be used in the factorization and solve. The second and third parameters define the particular type of map of the computations to processors. When the second parameter is zero, the defaults map is used. If {\tt rc = 1}, the setup completed without any error. % \item Compute the matrix factorization. \begin{verbatim} permuteflag = 1 ; rc = BridgeMPI_factor(bridge, mtxA, permuteflag, &error) ; \end{verbatim} When {\tt permuteflag} is {\tt 1}, it means that the matrix in {\tt mtxA} has not yet been permuted into the new ordering and so is done inside the method. The {\tt error} flag is filled with an error code that tells how far the factorization was able to proceed. If {\tt rc = 1}, the factorization completed without any error. % \item Setup the solve. \begin{verbatim} rc = BridgeMPI_solveSetup(bridge) ; \end{verbatim} This method sets up the environment for a parallel solve. It is called once per factorization, not once per solve. If {\tt rc = 1}, the setup completed without any error. % \item Solve the linear system. Processor 0 initializes the \texttt{DenseMtx} object {\tt mtxX} to hold the global solution $X$. Its entries are explicitly zeroed (this is not necessary but is a good idea in general). The solution is then solved. \begin{verbatim} mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; \end{verbatim} All processors then cooperate to compute the solution $X$. \begin{verbatim} rc = BridgeMPI_solve(bridge, permuteflag, mtxX, mtxY) ; \end{verbatim} Again, note the presence of {\tt permuteflag}. When {\tt 1}, \texttt{mtxY} needs to be permuted into the new ordering, and \texttt{mtxX} is returned in the original ordering. \end{itemize} \par \section{The \texttt{BridgeMPI} Data Structure} \label{section:BridgeMPI:dataStructure} \par The {\tt BridgeMPI} structure has the following fields. \begin{itemize} % \item Graph parameters: \begin{itemize} \item {\tt int neqns} : number of equations, i.e., number of vertices in the graph. \item {\tt int nedges} : number of edges (includes $(u,v)$, $(v,u)$ and $(u,u)$). \item {\tt int Neqns} : number of equations in the compressed graph. \item {\tt int Nedges} : number of edges in the compressed graph. \end{itemize} % \item Ordering parameters: \begin{itemize} \item {\tt int maxdomainsize} : maximum size of a subgraph to not split any further during the nested dissection process. \item {\tt int maxnzeros} : maximum number of zeros to allow in a front during the supernode amalgamation process. \item {\tt int maxsize} : maximum size of a front when the fronts are split. \item {\tt int seed} : random number seed. \item {\tt double compressCutoff} : if the \texttt{Neqns} $<$ \texttt{compressCutoff} $*$ \texttt{neqns}, then the compressed graph is formed, ordered and used to create the symbolic factorization. \end{itemize} % \item Matrix parameters: \begin{itemize} \item {\tt int type} : type of entries, {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, default value is {\tt SPOOLES\_REAL}. \item {\tt int symmetryflag} : type of symmetry for the matrix, {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}, default value is {\tt SPOOLES\_SYMMETRIC}. \end{itemize} % \item Factorization parameters: \begin{itemize} \item {\tt int sparsityflag} : {\tt SPOOLES\_DENSE\_FRONTS} for a direct factorization, or {\tt SPOOLES\_SPARSE\_FRONTS} for an approximate factorization, default value is {\tt SPOOLES\_DENSE\_FRONTS}. \item {\tt int pivotingflag} : {\tt SPOOLES\_PIVOTING} for pivoting enabled, or {\tt SPOOLES\_NO\_PIVOTING} for no pivoting, default value is {\tt SPOOLES\_NO\_PIVOTING}. \item {\tt double tau} : used when pivoting is enabled, all entries in $L$ and $U$ have magnitude less than or equal to \texttt{tau}, default value is 100. \item {\tt double droptol} : used for an approximation, all entries in $L$ and $U$ that are kept have magnitude greater than or equal to \texttt{droptol}. default value is 0.001. \item {\tt PatchAndGoInfo *patchinfo} : pointer to an object that controls special factorizations for optimization matrices and singular matrices from structural analysis, default value is \texttt{NULL} which means no special action is taken. See the Reference Manual for more information. \item {\tt int lookahead} : this parameter is used to possibly reduce the idle time of threads during the factorization. When {\tt lookahead} is 0, the factorization uses the least amount of working storage but threads can be idle. Larger values of {\tt lookahead} tend to increase the working storage but may decrease the execution time. Values of {\tt lookahead} greater than {\tt nthread} are not useful. \end{itemize} % \item Pointers to objects: \begin{itemize} \item {\tt ETree *frontETree} : object that defines the factorizations, e.g., the number of fronts, the tree they form, the number of internal and external rows for each front, and the map from vertices to the front where it is contained. \item {\tt IVL *symbfacIVL} : object that contains the symbolic factorization of the matrix. \item {\tt SubMtxManager *mtxmanager} : object that manages the \texttt{SubMtx} objects that store the factor entries and are used in the solves. \item {\tt FrontMtx *frontmtx} : object that stores the $L$, $D$ and $U$ factor matrices. \item {\tt IV *oldToNewIV} : object that stores old-to-new permutation vector. \item {\tt IV *newToOldIV} : object that stores new-to-old permutation vector. \end{itemize} % \item MPI information: \begin{itemize} \item {\tt int nproc} : number of processors. \item {\tt int myid} : id of this processor. \item {\tt MPI\_Comm} : MPI communicator. \item {\tt IV *ownersIV} : this object contains the map from fronts to their owning processors. \item {\tt SolveMap *solvemap} : this object contains the map from factor submatrices to their owning processors. \item {\tt DV *cumopsDV} : this object is formed when the map from fronts to owning processors is created. Its size is {\tt nthread} and contains the operations that each thread will perform during a direct factorization without pivoting. \item {\tt IV *vtxmapIV} : this object contains the map from vertices to their owning processors. \item {\tt IV *rowmapIV} : this object contains the map from rows to their owning processors during the solve. This may be different from {\tt vtxmapIV} if pivoting is enabled. \item {\tt IV *ownedColumnsIV} : this object contains the columns of the matrix that are owned by this processor during the solve. \item {\tt InpMtx *Aloc} : this object contains the entries of $A$ that are local to this processor during the factorization. \item {\tt DenseMtx *Xloc} : this object contains the local solution during the solve. \item {\tt DenseMtx *Yloc} : this object contains the local right hand side during the solve. \end{itemize} % \item Message information, statistics and cpu times: \begin{itemize} \item {\tt int msglvl} : message level for output. When 0, no output, When 1, just statistics and cpu times. When greater than 1, more and more output. \item {\tt FILE *msgFile} : message file for output. When \texttt{msglvl} $>$ 0, \texttt{msgFile} must not be \texttt{NULL}. \item {\tt int stats[6]} : statistics for the factorization. \begin{center} \begin{tabular}{ll} \texttt{stats[0]} : & \# of pivots \\ \texttt{stats[1]} : & \# of pivot tests \\ \texttt{stats[2]} : & \# of delayed rows and columns \end{tabular} \begin{tabular}{ll} \texttt{stats[3]} : & \# of entries in $D$ \\ \texttt{stats[4]} : & \# of entries in $L$ \\ \texttt{stats[5]} : & \# of entries in $U$ \end{tabular} \end{center} \item {\tt double cpus[22]} : cpus for the different functions. \begin{center} \begin{tabular}{ll} \texttt{cpus[0]} : & construct \texttt{Graph} \\ \texttt{cpus[1]} : & compress \texttt{Graph} \\ \texttt{cpus[2]} : & order \texttt{Graph} \\ \texttt{cpus[3]} : & symbolic factorization \\ \texttt{cpus[4]} : & broadcast the front tree \\ \texttt{cpus[5]} : & broadcast symbolic factor \\ \texttt{cpus[6]} : & total setup time \\ \texttt{cpus[7]} : & setup the factorization \\ \texttt{cpus[8]} : & permute matrix \\ \texttt{cpus[9]} : & distribute matrix \\ \texttt{cpus[10]} : & initialize front matrix \end{tabular} \begin{tabular}{ll} \texttt{cpus[11]} : & factor matrix \\ \texttt{cpus[12]} : & post-process matrix \\ \texttt{cpus[13]} : & total factor time \\ \texttt{cpus[14]} : & setup the parallel solve \\ \texttt{cpus[15]} : & permute rhs \\ \texttt{cpus[16]} : & distribute rhs \\ \texttt{cpus[17]} : & create solution matrix \\ \texttt{cpus[18]} : & solve \\ \texttt{cpus[19]} : & gather solution \\ \texttt{cpus[20]} : & permute solution \\ \texttt{cpus[21]} : & total solve time \end{tabular} \end{center} \end{itemize} \end{itemize} \par \section{Prototypes and descriptions of \texttt{BridgeMPI} methods} \label{section:BridgeMPI:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt BridgeMPI} object. \par \subsection{Basic methods} \label{subsection:BridgeMPI:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} BridgeMPI * BridgeMPI_new ( void ) ; \end{verbatim} \index{BridgeMPI_new@{\tt BridgeMPI\_new()}} This method simply allocates storage for the {\tt BridgeMPI} structure and then sets the default fields by a call to {\tt BridgeMPI\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_setDefaultFields ( BridgeMPI *bridge ) ; \end{verbatim} \index{BridgeMPI_setDefaultFields@{\tt BridgeMPI\_setDefaultFields()}} The structure's fields are set to default values: \begin{itemize} \item \texttt{neqns} = \texttt{nedges} = \texttt{Neqns} = \texttt{Nedges} = 0. \item \texttt{maxdomainsize} = \texttt{maxnzeros} = \texttt{maxsize} = \texttt{seed} = -1. \texttt{compressCutoff} = 0. \item \texttt{type} = \texttt{SPOOLES\_REAL}. \item \texttt{symmetryflag} = \texttt{SPOOLES\_SYMMETRIC}. \item \texttt{sparsityflag} = \texttt{SPOOLES\_DENSE\_FRONTS}. \item \texttt{pivotingflag} = \texttt{SPOOLES\_NO\_PIVOTING}. \item \texttt{tau} = 100., \texttt{droptol} = 0.001. \item \texttt{lookahead} = \texttt{nproc} = 0. \item \texttt{myid} = -1. \item \texttt{patchinfo}, \texttt{frontETree}, \texttt{symbfacIVL}, \texttt{mtxmanager}, \texttt{frontmtx}, \texttt{oldToNewIV}, \texttt{newToOldIV}, \texttt{ownersIV}, \texttt{solvemap}, \texttt{cumopsDV}, \texttt{vtxmapIV}, \texttt{rowmapIV}, \texttt{ownedColumnsIV}, \texttt{Aloc}, \texttt{Xloc}, \texttt{Yloc} and \texttt{comm} are all set to \texttt{NULL}. \end{itemize} The \texttt{stats[6]} and \texttt{cpus[22]} vectors are filled with zeros. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_clearData ( BridgeMPI *bridge ) ; \end{verbatim} \index{BridgeMPI_clearData@{\tt BridgeMPI\_clearData()}} This method clears the object and free's any owned data. It then calls {\tt BridgeMPI\_setDefaultFields()}. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_free ( BridgeMPI *bridge ) ; \end{verbatim} \index{BridgeMPI_free@{\tt BridgeMPI\_free()}} This method releases any storage by a call to {\tt BridgeMPI\_clearData()} and then free the space for {\tt bridge}. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:BridgeMPI:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_oldToNewIV ( BridgeMPI *bridge, IV **pobj ) ; \end{verbatim} \index{BridgeMPI_oldToNewIV@{\tt BridgeMPI\_oldToNewIV()}} This method fills \texttt{*pobj} with its \texttt{oldToNewIV} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_newToOldIV ( BridgeMPI *bridge, IV **pobj ) ; \end{verbatim} \index{BridgeMPI_newToOldIV@{\tt BridgeMPI\_newToOldIV()}} This method fills \texttt{*pobj} with its \texttt{newToOldIV} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_frontETree ( BridgeMPI *bridge, ETree **pobj ) ; \end{verbatim} \index{BridgeMPI_frontETree@{\tt BridgeMPI\_frontETree()}} This method fills \texttt{*pobj} with its \texttt{frontETree} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_symbfacIVL ( BridgeMPI *bridge, IVL **pobj ) ; \end{verbatim} \index{BridgeMPI_symbfacIVL@{\tt BridgeMPI\_symbfacIVL()}} This method fills \texttt{*pobj} with its \texttt{symbfacIVL} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_mtxmanager ( BridgeMPI *bridge, SubMtxManager **pobj ) ; \end{verbatim} \index{BridgeMPI_mtxmanager@{\tt BridgeMPI\_mtxmanager()}} This method fills \texttt{*pobj} with its \texttt{mtxmanager} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_frontmtx ( BridgeMPI *bridge, FrontMtx **pobj ) ; \end{verbatim} \index{BridgeMPI_frontmtx@{\tt BridgeMPI\_frontmtx()}} This method fills \texttt{*pobj} with its \texttt{frontmtx} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_ownersIV ( BridgeMPI *bridge, IV **pobj ) ; \end{verbatim} \index{BridgeMPI_ownersIV@{\tt BridgeMPI\_ownersIV()}} This method fills \texttt{*pobj} with its \texttt{ownersIV} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_solvemap ( BridgeMPI *bridge, SolveMap **pobj ) ; \end{verbatim} \index{BridgeMPI_solvemap@{\tt BridgeMPI\_solvemap()}} This method fills \texttt{*pobj} with its \texttt{solvemap} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_vtxmapIV ( BridgeMPI *bridge, IV **pobj ) ; \end{verbatim} \index{BridgeMPI_vtxmapIV@{\tt BridgeMPI\_vtxmapIV()}} This method fills \texttt{*pobj} with its \texttt{vtxmapIV} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_rowmapIV ( BridgeMPI *bridge, IV **pobj ) ; \end{verbatim} \index{BridgeMPI_rowmapIV@{\tt BridgeMPI\_rowmapIV()}} This method fills \texttt{*pobj} with its \texttt{rowmapIV} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_ownedColumns ( BridgeMPI *bridge, IV **pobj ) ; \end{verbatim} \index{BridgeMPI_ownedColumns@{\tt BridgeMPI\_ownedColumns()}} This method fills \texttt{*pobj} with its \texttt{ownedColumnsIV} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_Xloc ( BridgeMPI *bridge, DenseMtx **pobj ) ; \end{verbatim} \index{BridgeMPI_Xloc@{\tt BridgeMPI\_Xloc()}} This method fills \texttt{*pobj} with its \texttt{Xloc} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_Yloc ( BridgeMPI *bridge, DenseMtx **pobj ) ; \end{verbatim} \index{BridgeMPI_Yloc@{\tt BridgeMPI\_Yloc()}} This method fills \texttt{*pobj} with its \texttt{Yloc} pointer. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pobj} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_nproc ( BridgeMPI *bridge, int *pnproc ) ; \end{verbatim} \index{BridgeMPI_nproc@{\tt BridgeMPI\_nproc()}} This method fills \texttt{*pobj} with the number of processors. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pnproc} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_myid ( BridgeMPI *bridge, int *pmyid ) ; \end{verbatim} \index{BridgeMPI_myid@{\tt BridgeMPI\_myid()}} This method fills \texttt{*pobj} with the id of this processor. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{pmyid} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_lookahead ( BridgeMPI *bridge, int *plookahead ) ; \end{verbatim} \index{BridgeMPI_lookahead@{\tt BridgeMPI\_lookahead()}} This method fills \texttt{*pobj} with the lookahead parameter. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2 if \texttt{plookahead} is \texttt{NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Parameter methods} \label{subsection:BridgeMPI:proto:parameters} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_setMatrixParams ( BridgeMPI *bridge, int neqns, int type, int symmetryflag ) ; \end{verbatim} \index{BridgeMPI_setMatrixParams@{\tt BridgeMPI\_setMatrixParams()}} This method sets the number of equations, type of entries, and symmetry type of the matrix. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{neqns} $\le$ 0 \end{tabular} \begin{tabular}{ll} -3 & \texttt{type} is invalid \\ -4 & \texttt{symmetryflag} is invalid \\ -5 & symmetry flag is Hermitian but type is real \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_setMPIparams ( BridgeMPI *bridge, int nproc, int myid, MPI_Comm comm ) ; \end{verbatim} \index{BridgeMPI_setMPIparams@{\tt BridgeMPI\_setMPIparams()}} This method sets the MPI environment parameters. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \end{tabular} \begin{tabular}{ll} -2 & \texttt{nproc} $\le$ 0 \\ -3 & \texttt{myid} $<$ 0 or $>=$ \texttt{nproc} \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_setOrderingParams ( BridgeMPI *bridge, int maxdomainsize, int maxnzeros, int maxsize, int seed, double compressCutoff ) ; \end{verbatim} \index{BridgeMPI_setOrderingParams@{\tt BridgeMPI\_setOrderingParams()}} This method sets parameters needed for the ordering. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{maxdomainsize} $\le$ 0 \end{tabular} \begin{tabular}{ll} -3 & \texttt{maxsize} $\le$ 0 \\ -4 & \texttt{compressCutoff} $>$ 1 \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_setFactorParams ( BridgeMPI *bridge, int sparsityflag, int pivotingflag, double tau, double droptol, int lookahead, PatchAndGoInfo *patchinfo ) ; \end{verbatim} \index{BridgeMPI_setFactorParams@{\tt BridgeMPI\_setFactorParams()}} This method sets parameters needed for the factorization. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{sparsityflag} is invalid \\ -3 & \texttt{pivotingflag} is invalid \end{tabular} \begin{tabular}{ll} -4 & \texttt{tau} $<$ 2.0 \\ -5 & \texttt{droptol} $<$ 0.0 \\ -6 & \texttt{lookahead} $<$ 0 \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_setMessagesInfo ( BridgeMPI *bridge, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{BridgeMPI_setMessagesInfo@{\tt BridgeMPI\_setMessagesInfo()}} This method sets the message level and file. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}, -2 if \texttt{msglvl} $>$ 0 and \texttt{msgFile} is \texttt{NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Setup methods} \label{subsection:BridgeMPI:proto:setup} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_setup ( BridgeMPI *bridge, InpMtx *mtxA ) ; \end{verbatim} \index{BridgeMPI_setup@{\tt BridgeMPI\_setup()}} This method orders the graph, generates the front tree, computes the symbolic factorization, and creates the two permutation vectors. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}, -2 if \texttt{mtxA} is \texttt{NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_factorStats ( BridgeMPI *bridge, int type, int symmetryflag, int *pnfront, int *pnfactorind, int *pnfactorent, int *pnsolveops, double *pnfactorops ) ; \end{verbatim} \index{BridgeMPI_factorStats@{\tt BridgeMPI\_factorStats()}} This method takes as input the type and symmetry of the matrix, and fills the pointer fields with the number of fronts, factor indices, factor entries, forward and back solve operations, and factor operations. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{type} is invalid \\ -3 & \texttt{symmetryflag} is invalid \\ -4 & \texttt{type} is real but \texttt{symmetryflag} is Hermitian \\ -5 & front tree is not present \end{tabular} \begin{tabular}{ll} ~-6 & \texttt{pnfront} is \texttt{NULL} \\ ~-7 & \texttt{pnfactorind} is \texttt{NULL} \\ ~-8 & \texttt{pnfactorent} is \texttt{NULL} \\ ~-9 & \texttt{pnsolveops} is \texttt{NULL} \\ -10 & \texttt{pnfactorops} is \texttt{NULL} \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Factor methods} \label{subsection:BridgeMPI:proto:factor} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_factorSetup ( BridgeMPI *bridge, int maptype, double cutoff ) ; \end{verbatim} \index{BridgeMPI_factorSetup@{\tt BridgeMPI\_factorSetup()}} This method constructs the map from fronts to owning processors, and computes the number of factor operations that each thread will execute. The \texttt{maptype} parameter can be one of four values: \begin{itemize} \item 1 --- wrap map \item 2 --- balanced map \item 3 --- subtree-subset map \item 4 --- domain decomposition map \end{itemize} The wrap map and balanced map are not recommended. The subtree-subset map is a good map with a very well balanced nested dissection ordering. The domain decomposition map is recommended when the nested dissection tree is imbalanced or for the multisection ordering. The domain decomposition map requires a \texttt{cutoff} parameter in $\left \lbrack0,1\right \rbrack$ which specifies the relative size of a subtree that forms a domain. If \texttt{maptype} is not one of 1, 2, 3 or 4, the default map is used: domain decomposition with \texttt{cutoff} = 1/(2*\texttt{nthread}). \par \noindent {\it Return value:} 1 normal return, factorization did complete, -1 \texttt{bridge} is \texttt{NULL}, -2 \texttt{frontETree} is not present. %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_factor ( BridgeMPI *bridge, InpMtx *mtxA, int permuteflag, int *perror ) ; \end{verbatim} \index{BridgeMPI_factor@{\tt BridgeMPI\_factor()}} This method permutes the matrix into the new ordering (if \texttt{permuteflag} is 1), factors the matrix, and then post-processes the factors. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return, factorization did complete \\ ~0 & factorization did not complete \\ \end{tabular} \begin{tabular}{ll} -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{mtxA} is \texttt{NULL} \\ -3 & \texttt{perror} is \texttt{NULL} \\ \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Solve methods} \label{subsection:BridgeMPI:proto:solve} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_solveSetup ( BridgeMPI *bridge ) ; \end{verbatim} \index{BridgeMPI_solveSetup@{\tt BridgeMPI\_solveSetup()}} This method creates the {\tt SolveMap} object that governs the parallel solve. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \end{tabular} \begin{tabular}{ll} -2 & \texttt{frontMtx} is \texttt{NULL} \\ -3 & \texttt{frontMtx} needs to be postprocessed \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int BridgeMPI_solve ( BridgeMPI *bridge, int permuteflag, DenseMtx *mtxX, DenseMtx *mtxY ) ; \end{verbatim} \index{BridgeMPI_solve@{\tt BridgeMPI\_solve()}} If \texttt{permuteflag} is 1, then \texttt{mtxY} is permuted into the new ordering. The linear system $AX = Y$ is solved. If \texttt{permuteflag} is 1, then \texttt{mtxX} is permuted into the old ordering. \par \noindent {\it Return value:} \begin{center} \begin{tabular}{ll} ~1 & normal return \\ -1 & \texttt{bridge} is \texttt{NULL} \\ -2 & \texttt{X} is \texttt{NULL} \\ -3 & \texttt{Y} is \texttt{NULL} \\ \end{tabular} \begin{tabular}{ll} -4 & \texttt{frontmtx} is \texttt{NULL} \\ -5 & \texttt{mtxmanager} is \texttt{NULL} \\ -6 & \texttt{oldToNewIV} needed, but not available \\ -7 & \texttt{newToOldIV} needed, but not available \\ \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} eMPI\_myid()}} This method fills \texttt{*pobj} with the id of this processor. \par \noindent {\it Return value:} 1 for a normal return, -1 if \texttt{bridge} is \texttt{NULL}. -2LinSol/doc/MPI_driver.tex010060000020550007177000000312350662014142100165500ustar00clevecompmath00000400000006\chapter{{\tt testWrapperMPI.c} --- A MPI Driver Program} \label{chapter:MPI_driver} \begin{verbatim} /* testWrapperMPI.c */ #include "../BridgeMPI.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ----------------------------------------------------------- purpose -- main driver program to solve a linear system where the matrix and rhs are read in from files and the solution is written to a file. NOTE: MPI version created -- 98sep25, cca and pjs ----------------------------------------------------------- */ BridgeMPI *bridge ; char *mtxFileName, *rhsFileName, *solFileName ; double nfactorops ; FILE *msgFile ; InpMtx *mtxA ; int error, msglvl, myid, neqns, nfent, nfind, nfront, nproc, nrhs, nrow, nsolveops, permuteflag, rc, seed, symmetryflag, type ; int tstats[6] ; DenseMtx *mtxX, *mtxY ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile neqns type symmetryflag" "\n mtxFile rhsFile solFile seed" "\n msglvl -- message level" "\n 0 -- no output" "\n 1 -- timings and statistics" "\n 2 and greater -- lots of output" "\n msgFile -- message file" "\n neqns -- # of equations" "\n type -- type of entries" "\n 1 -- real" "\n 2 -- complex" "\n symmetryflag -- symmetry flag" "\n 0 -- symmetric" "\n 1 -- hermitian" "\n 2 -- nonsymmetric" "\n mtxFile -- input file for A matrix InpMtx object" "\n must be *.inpmtxf or *.inpmtxb" "\n rhsFile -- input file for Y DenseMtx object" "\n must be *.densemtxf or *.densemtxb" "\n solFile -- output file for X DenseMtx object" "\n must be none, *.densemtxf or *.densemtxb" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { int length = strlen(argv[2]) + 1 + 4 ; char *buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; MPI_Finalize() ; return(0) ; } CVfree(buffer) ; } neqns = atoi(argv[3]) ; type = atoi(argv[4]) ; symmetryflag = atoi(argv[5]) ; mtxFileName = argv[6] ; rhsFileName = argv[7] ; solFileName = argv[8] ; seed = atoi(argv[9]) ; fprintf(msgFile, "\n\n %s input :" "\n msglvl = %d" "\n msgFile = %s" "\n neqns = %d" "\n type = %d" "\n symmetryflag = %d" "\n mtxFile = %s" "\n rhsFile = %s" "\n solFile = %s" "\n", argv[0], msglvl, argv[2], neqns, type, symmetryflag, mtxFileName, rhsFileName, solFileName) ; /*--------------------------------------------------------------------*/ /* ----------------------------------- processor zero reads in the matrix. if an error is found, all processors exit cleanly ----------------------------------- */ if ( myid != 0 ) { mtxA = NULL ; } else { /* ---------------------------------------------------- open the file, read in the matrix and close the file ---------------------------------------------------- */ mtxA = InpMtx_new() ; rc = InpMtx_readFromFile(mtxA, mtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxA from file %s, rc = %d", mtxFileName, rc) ; fflush(msgFile) ; } } /* --------------------------------------------------------------- processor 0 broadcasts the error return to the other processors --------------------------------------------------------------- */ MPI_Bcast((void *) &rc, 1, MPI_INT, 0, MPI_COMM_WORLD) ; if ( rc != 1 ) { MPI_Finalize() ; return(-1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- processor zero reads in the right hand side matrix. if an error is found, all processors exit cleanly --------------------------------------------------- */ if ( myid != 0 ) { mtxY = NULL ; } else { /* ---------------------------------- read in the right hand side matrix ---------------------------------- */ mtxY = DenseMtx_new() ; rc = DenseMtx_readFromFile(mtxY, rhsFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n fatal error reading mtxY from file %s, rc = %d", rhsFileName, rc) ; fflush(msgFile) ; } else { DenseMtx_dimensions(mtxY, &nrow, &nrhs) ; } } /* --------------------------------------------------------------- processor 0 broadcasts the error return to the other processors --------------------------------------------------------------- */ MPI_Bcast((void *) &rc, 1, MPI_INT, 0, MPI_COMM_WORLD) ; if ( rc != 1 ) { MPI_Finalize() ; return(-1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ create and setup a BridgeMPI object set the MPI, matrix and message parameters ------------------------------------------ */ bridge = BridgeMPI_new() ; BridgeMPI_setMPIparams(bridge, nproc, myid, MPI_COMM_WORLD) ; BridgeMPI_setMatrixParams(bridge, neqns, type, symmetryflag) ; BridgeMPI_setMessageInfo(bridge, msglvl, msgFile) ; /* ----------------- setup the problem ----------------- */ rc = BridgeMPI_setup(bridge, mtxA) ; fprintf(msgFile, "\n\n ----- SETUP -----\n" "\n CPU %8.3f : time to construct Graph" "\n CPU %8.3f : time to compress Graph" "\n CPU %8.3f : time to order Graph" "\n CPU %8.3f : time for symbolic factorization" "\n CPU %8.3f : time to broadcast front tree" "\n CPU %8.3f : time to broadcast symbolic factorization" "\n CPU %8.3f : total setup time\n", bridge->cpus[0], bridge->cpus[1], bridge->cpus[2], bridge->cpus[3], bridge->cpus[4], bridge->cpus[5], bridge->cpus[6]) ; rc = BridgeMPI_factorStats(bridge, type, symmetryflag, &nfront, &nfind, &nfent, &nsolveops, &nfactorops) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from BridgeMPI_factorStats()", rc) ; MPI_Finalize() ; exit(-1) ; } fprintf(msgFile, "\n\n factor matrix statistics" "\n %d fronts, %d indices, %d entries" "\n %d solve operations, %12.4e factor operations", nfront, nfind, nfent, nsolveops, nfactorops) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* -------------------------------- setup the parallel factorization -------------------------------- */ rc = BridgeMPI_factorSetup(bridge, 0, 0.0) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from BridgeMPI_factorSetup()", rc) ; MPI_Finalize() ; exit(-1) ; } fprintf(msgFile, "\n\n ----- PARALLEL FACTOR SETUP -----\n") ; fprintf(msgFile, "\n CPU %8.3f : time to setup parallel factorization", bridge->cpus[7]) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n total factor operations = %.0f" "\n upper bound on speedup due to load balance = %.2f", DV_sum(bridge->cumopsDV), DV_sum(bridge->cumopsDV)/DV_max(bridge->cumopsDV)) ; fprintf(msgFile, "\n operations distributions over processors") ; DV_writeForHumanEye(bridge->cumopsDV, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ set the factorization parameters and factor the matrix ------------------------------------------------------ */ permuteflag = 1 ; rc = BridgeMPI_factor(bridge, mtxA, permuteflag, &error) ; fprintf(msgFile, "\n\n ----- FACTORIZATION -----\n") ; if ( rc == 1 ) { fprintf(msgFile, "\n\n factorization completed successfully\n") ; } else { fprintf(msgFile, "\n" "\n return code from factorization = %d\n" "\n error code = %d\n", rc, error) ; MPI_Finalize() ; exit(-1) ; } fprintf(msgFile, "\n CPU %8.3f : time to permute original matrix" "\n CPU %8.3f : time to distribute original matrix" "\n CPU %8.3f : time to initialize factor matrix" "\n CPU %8.3f : time to compute factorization" "\n CPU %8.3f : time to post-process factorization" "\n CPU %8.3f : total factorization time\n", bridge->cpus[8], bridge->cpus[9], bridge->cpus[10], bridge->cpus[11], bridge->cpus[12], bridge->cpus[13]) ; IVzero(6, tstats) ; MPI_Reduce((void *) bridge->stats, (void *) tstats, 6, MPI_INT, MPI_SUM, 0, bridge->comm) ; fprintf(msgFile, "\n\n factorization statistics" "\n %d pivots, %d pivot tests, %d delayed vertices" "\n %d entries in D, %d entries in L, %d entries in U", tstats[0], tstats[1], tstats[2], tstats[3], tstats[4], tstats[5]) ; fprintf(msgFile, "\n\n factorization: raw mflops %8.3f, overall mflops %8.3f", 1.e-6*nfactorops/bridge->cpus[11], 1.e-6*nfactorops/bridge->cpus[13]) ; fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* ------------------------ setup the parallel solve ------------------------ */ rc = BridgeMPI_solveSetup(bridge) ; fprintf(msgFile, "\n\n ----- PARALLEL SOLVE SETUP -----\n" "\n CPU %8.3f : time to setup parallel solve", bridge->cpus[14]) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from BridgeMPI_solveSetup()", rc) ; MPI_Finalize() ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- processor 0 initializes a DenseMtx object to hold the global solution matrix ----------------------------------------- */ if ( myid == 0 ) { mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; } else { mtxX = NULL ; } /* --------------------------------------------- the processors solve the system cooperatively --------------------------------------------- */ permuteflag = 1 ; rc = BridgeMPI_solve(bridge, permuteflag, mtxX, mtxY) ; if ( rc == 1 ) { fprintf(msgFile, "\n\n solve complete successfully\n") ; } else { fprintf(msgFile, "\n" " return code from solve = %d\n", rc) ; } fprintf(msgFile, "\n\n ----- SOLVE -----\n" "\n CPU %8.3f : time to permute rhs into new ordering" "\n CPU %8.3f : time to distribute rhs " "\n CPU %8.3f : time to initialize solution matrix " "\n CPU %8.3f : time to solve linear system" "\n CPU %8.3f : time to gather solution " "\n CPU %8.3f : time to permute solution into old ordering" "\n CPU %8.3f : total solve time" "\n\n solve: raw mflops %8.3f, overall mflops %8.3f", bridge->cpus[15], bridge->cpus[16], bridge->cpus[17], bridge->cpus[18], bridge->cpus[19], bridge->cpus[20], bridge->cpus[21], 1.e-6*nsolveops/bridge->cpus[18], 1.e-6*nsolveops/bridge->cpus[21]) ; fflush(msgFile) ; if ( myid == 0 ) { if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } } /*--------------------------------------------------------------------*/ /* --------------------- free the working data --------------------- */ if ( myid == 0 ) { InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxY) ; } BridgeMPI_free(bridge) ; /*--------------------------------------------------------------------*/ MPI_Finalize() ; return(1) ; } /*--------------------------------------------------------------------*/ \end{verbatim} LinSol/doc/setup.tex010064400020550007177000000414130663604603100157270ustar00clevecompmath00000400000006\chapter{Setting up the linear system} \label{section:setup-linear-system} \par Our typical user is interested in solving $A X = Y$, where $A$ is square, large and sparse, and $X$ and $Y$ are dense matrices with one or more columns. {\bf SPOOLES} is a very large sophisticated library with a commensurate learning curve to master its functionality. But what is the bare minimum a user has to know to obtain a solution to their linear system? \begin{itemize} \item They need to construct an {\tt InpMtx} object that holds the entries of $A$. ({\tt InpMtx} stands for {\tt Inp}ut {\tt m}a{\tt t}ri{\tt x}, for it is an easy to use object that one uses to input, assemble, sort and manipulate entries in a sparse matrix.) \item They need to construct a {\tt DenseMtx} object that holds the entries of $Y$. \item They need to construct a {\tt DenseMtx} object to hold the entries of $X$. \end{itemize} These two objects encapsulate the minimal interface to the {\bf SPOOLES} library. the application program needs to know how to construct the {\tt InpMtx} and {\tt DenseMtx} objects, either directly inside an application program, or by reading in a custom matrix file. This is what we now describe. \par \section{Constructing an {\tt InpMtx} object} \label{subsection:construct-InpMtx} \par The {\tt InpMtx} object is more of an ``Input'' object than a ``Matrix'' object. It descended from an out-of-core assembly code that assembled and sorted entries of a sparse matrix. Simplicity and functionality are its goals, at some expense of efficiency in storage and computation. {\it Note: all indices are zero-based as in C, not 1-based as in FORTRAN.} \par The {\tt InpMtx} object is simplest understood as a ``bag'' of triples $\langle r(i,j),c(i,j),a_{i,j}\rangle$, where $r()$ and $c()$ are some functions that define the first and second coordinates. Each {\tt InpMtx} object has a ``coordinate type'', one of \begin{itemize} \item {\tt INPMTX\_BY\_ROWS}, where $r(i,j) = i$, $c(i,j) = j$. \item {\tt INPMTX\_BY\_COLUMNS}, where $r(i,j) = j$, $c(i,j) = i$. \item {\tt INPMTX\_BY\_CHEVRONS}, where $r(i,j) = \min(i,j)$, $c(i,j) = j - i$. \end{itemize} Rows and columns are self-explanatory, the first coordinate $r(i,j)$ is either the row or column of $a_{i,j}$. The $j$-th ``chevron'' is composed of the diagonal entry $a_{j,j}$, entries in the $j$-th row of the upper triangle, and entries in the $j$-th column of the lower triangle. It is the natural data structure for the assembly of the matrix entries into the ``fronts'' used to factor the matrix. \par % ``Entries'' of the {\tt InpMtx} object can be one of three types. The {\tt InpMtx} object can hold one of three types of entries as ``indices only'' (no entries are present), real entries, or complex entries. The type is specified by the {\tt inputMode} parameter to the {\tt InpMtx\_init()} method. \begin{itemize} \item {\tt INPMTX\_INDICES\_ONLY} where the triples $langle r(i,j),c(i,j),-\rangle$ are really only pairs, i.e., no numerical values are present. This mode is useful for assembling graphs. \item {\tt SPOOLES\_REAL} where $a_{i,j}$ is a real number, a {\tt double} value. \item {\tt SPOOLES\_COMPLEX} where $a_{i,j}$ is a complex number, really two consecutive {\tt double} values. \end{itemize} ``Coodinate type'' and ``input mode'' (equivalently, the type of entries) are the two parameters that must be specified when initializing an {\tt InpMtx} object. \begin{verbatim} InpMtx *mtxA = InpMtx_new() ; InpMtx_init(mtxA, coordType, inputMode, 0, 0) ; \end{verbatim} Every object in the {\bf SPOOLES} library is initialized via an {\tt {\it ObjectName}\_new()} method, which allocates space for the object and sets its fields to default values. If you wish to use an {\it automatic} variable, then one must explicitly set the default fields, as follows. \begin{verbatim} InpMtx mtxA ; InpMtx_setDefaultFields(&mtxA) ; InpMtx_init(&mtxA, coordType, inputMode, 0, 0) ; \end{verbatim} Only the coordinate type and input mode are necessary. The fourth and fifth arguments are upper bounds on the number of entries and vectors for the object. (More on vectors in just a moment.) The user does not need to know values for the number of entries or vectors, for the object resizes itself as necessary as information is placed into it. \par ``Vectors'' is one way that the entries can be stored. There are actually three ways, specified by the {\tt storageMode} field of the {\tt InpMtx} object. \begin{itemize} \item {\tt INPMTX\_RAW\_DATA}, where the pairs or triples are stored in unordered form. \item {\tt INPMTX\_SORTED}, where the pairs or triples are stored in ascending lexicographic order of the first two coordinates. \item {\tt INPMTX\_BY\_VECTORS}, where the pairs or triples are sorted and stored in vectors defined by their first coordinate. \end{itemize} The storage mode can be changed via a call to {\tt InpMtx\_changeStorageMode()}. \par The user does not really need to know about this ``storage mode''. Fill the {\tt InpMtx} object with data in any way at all (we will describe this shortly). The wrapper method will check that the data is in the form it needs. If is isn't, the object will be transformed as necessary. The ``sort'' operation is really ``sort-and-compress'', the pairs or triples are sorted into ascending order, and then the list is scanned duplicates are ``merged'' together, i.e., if real or complex entries are present, they are added together. (This allows us to assemble finite element matrices.) The knowledgeable user can change the storage mode as necessary, and thus avoiding expensive sorts when possible. For example, after reading in the matrix data from the CSAR-Nastran file, the entries are already in sorted form, and the explicit sort can be avoided. \par Now let us see how we ``input'' information into the {\tt InpMtx} object. There are several input methods, e.g., single entries, rows, columns, and submatrices, and each input method has three types of input, e.g, indices only, real entries, or complex entries. Here are the prototypes below. \begin{itemize} \item Input methods for ``indices only'' mode. \begin{verbatim} void InpMtx_inputEntry ( InpMtx *mtxA, int row, int col ) ; void InpMtx_inputRow ( InpMtx *mtxA, int row, int rowsize, int rowind[] ) ; void InpMtx_inputColumn ( InpMtx *mtxA, int col, int colsize, int colind[] ) ; void InpMtx_inputMatrix ( InpMtx *mtxA, int nrow, int ncol, int rowstride, int colstride, int rowind[], colind[] ) ; \end{verbatim} \item Input methods for real entries. \begin{verbatim} void InpMtx_inputRealEntry ( InpMtx *mtxA, int row, int col, double value ) ; void InpMtx_inputRealRow ( InpMtx *mtxA, int row, int rowsize, int rowind[], double rowent[] ) ; void InpMtx_inputRealColumn ( InpMtx *mtxA, int col, int colsize, int colind[], double colent[] ) ; void InpMtx_inputRealMatrix ( InpMtx *mtxA, int nrow, int ncol, int rowstride, int colstride, int rowind[], colind[], double mtxent[] ) ; \end{verbatim} \item Input methods for complex entries. \begin{verbatim} void InpMtx_inputComplexEntry ( InpMtx *mtxA, int row, int col, double real, double imag ) ; void InpMtx_inputComplexRow ( InpMtx *mtxA, int row, int rowsize, int rowind[], double rowent[] ) ; void InpMtx_inputComplexColumn ( InpMtx *mtxA, int col, int colsize, int colind[], double colent[] ) ; void InpMtx_inputComplexMatrix ( InpMtx *mtxA, int nrow, int ncol, int rowstride, int colstride, int rowind[], colind[], double mtxent[] ) ; \end{verbatim} \end{itemize} The {\tt rowind[]} row indices and {\tt colind[]} column indices are precisely that. Don't worry about what coordinate type the {\tt InpMtx} object has, the translation from row and column indices into the particular coordinate is done inside the input methods. \par Let us look at a particular example, where we have a ${\tt n1} \times {\tt n2}$ grid and we want to have a $\left \lbrack \begin{array}{ccc} & -1 & \\ -1 & 4 & -1 \\ & -1 & \end{array} \right \rbrack$ 5-point operator at each grid point. Note, this matrix is symmetric, so we need input only the upper triangle (or the lower triangle) of the matrix. \begin{verbatim} mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, SPOOLES_REAL, 0, 0) ; for ( ii = 0 ; ii < n1 ; ii++ ) { for ( jj = 0 ; jj < n2 ; jj++ ) { ij = ii + jj*n1 ; indices[0] = ij ; entries[0] = 4.0 ; count = 1 ; if ( ii < n1 ) { indices[count] = ij + 1 ; entries[count] = -1.0 ; count++ ; } if ( jj < n2 ) { indices[count] = ij + n1 ; entries[count] = -1.0 ; count++ ; } InpMtx_inputRealRow(mtxA, ij, count, indices, entries) ; } } InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; \end{verbatim} The process begins by allocating an {\tt InpMtx} object {\tt mtxA} using the {\tt InpMtx\_new()} method, initializing it with the {\tt InpMtx\_init()} method, and filling it with matrix entries with the {\tt InpMtx\_inputRealRow()} method. The last method, {\tt InpMtx\_changeStorageMode()}, ``assembles'' the data (not really necessary because the entries are disjoint, ``sorts'' the data (again not necessary since the entries were input in ascending order, and creates a vector structure inside the {\tt InpMtx} object that allows easy access to each individual row. \par We could have input all the entries and treated it as a nonsymmetric matrix, but that would not be efficient with respect to storage or factorization cost. Alternatively, we could have input all the entries and called the {\tt InpMtx\_dropLowerTriangle()} method to drop the lower triangular entries. \par \section{Constructing an {\tt DenseMtx} object} \label{subsection:construct-DenseMtx} \par The {\tt DenseMtx} stores a real or complex dense matrix. It is not just an array of numbers, it also has row indices and column indices. This allows it to exist in a distributed MPI environment where each processors has only a submatrix of the matrix. Here is how to initialize a {\tt DenseMtx} object. \begin{verbatim} int type, rowid, colid, nrow, ncol, inc1, inc2 ; DenseMtx *mtx = DenseMtx_new() ; DenseMtx_init(mtx, type, rowid, colid, nrow, ncol, inc1, inc2) ; \end{verbatim} \begin{itemize} \item The {\tt type} is either {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. \item The {\tt rowid} and {\tt colid} values are used to identify a {\tt DenseMtx} as a submatrix of a larger matrix. Any values are suitable. \item {\tt nrow} and {\tt ncol} are the number of rows and columns in the matrix, respectively. \item The entries of the matrix can be stored in either row major or column major form. For row major, use {\tt inc1 = ncol} and {\tt inc2 = 1}. For column major, use {\tt inc1 = 1} and {\tt inc2 = nrow}. Note, all solve and matrix-matrix multiply methods require that the {\tt DenseMtx} object be column major. \end{itemize} For example, here is the call to initialize a {\tt DenseMtx} object to have real entries, 100 rows and 5 columns, entries column major. \begin{verbatim} DenseMtx_init(mtx, SPOOLES_REAL, 0, 0, 100, 5, 1, 100) ; \end{verbatim} During the initialization, the row indices are set to $0, 1, \dots, \mathtt{nrow - 1}$ and the column indices are set to $0, 1, \dots, \mathtt{ncol - 1}$. The entries are {\bf not} initialized. Zero the entries with a call to {\tt DenseMtx\_zero()}. (This is crucial when loading a sparse right hand side into the {\tt DenseMtx} object.) \par Once we have the {\tt DenseMtx} object initialized, we want to be able to access the row indices, the column indices and the entries. We do this through instance methods. \begin{verbatim} void DenseMtx_rowIndices ( DenseMtx *mtx, int *pnrow, int *prowind ) ; void DenseMtx_columnIndices ( DenseMtx *mtx, int *pncol, int *pcolind ) ; double * DenseMtx_entries ( DenseMtx *mtx ) ; \end{verbatim} We would use them as follows. \begin{verbatim} double *entries ; int ncol, nrow, *colind, *rowind ; DenseMtx_rowIndices(mtx, &nrow, &rowind) ; DenseMtx_columnIndices(mtx, &ncol, &colind) ; entries = DenseMtx_entries(mtx) ; \end{verbatim} We can now fill the indices or the entries. The location of the {\tt (irow,jcol)} entry is found at {\tt offset = irow*inc1 + jcol*inc2}. The row and column increments can be found as follows. \begin{verbatim} int inc1 = DenseMtx_rowIncrement(mtx) ; int inc2 = DenseMtx_columnIncrement(mtx) ; \end{verbatim} \par To avoid dealing with row and column increments, we can retrieve and set values of a particular entry. \begin{verbatim} double value, real, imag ; int irow, jcol ; DenseMtx_realEntry(mtx, irow, jcol, &value) ; DenseMtx_complexEntry(mtx, irow, jcol, &real, &imag) ; DenseMtx_setRealEntry(mtx, irow, jcol, value + 10.) ; DenseMtx_setComplexEntry(mtx, irow, jcol, real + 1., imag + 2.) ; \end{verbatim} As a real example, consider the ${\tt n1} \times {\tt n2}$ grid from the previous subsection, where we assembled a finite difference matrix. Assume that the right hand side is zero except for points where {\tt (n1-1,0:n2-1)}, where a unit load is applied. Here is the code to generate the {\tt DenseMtx} object. \begin{verbatim} mtxY = DenseMtx_new(); DenseMtx_init(mtxY, SPOOLES_REAL, 0, 0, n1*n2, 1, 1, n1*n2) ; DenseMtx_zero(mtxY) ; ii = n1 - 1 ; for ( jj = 0 ; jj < n2 ; jj++ ) { ij = ii + jj*n1 ; DenseMtx_setRealEntry(mtxY, ij, 1, 1.0) ; } \end{verbatim} Do not forget to zero the entries in {\tt mtxY} before setting any entries. \par \section{IO for the {\tt InpMtx} and {\tt DenseMtx} objects} \label{subsection:IO} \par The three driver programs that we describe in the next sections read $A$ and $Y$ from files and write $X$ to a file. So the first thing we know is that the {\tt InpMtx} and {\tt DenseMtx} objects can read and write themselves from and to files. This convention is supported by most of the objects in the {\bf SPOOLES} library. In fact, there is a common {\it protocol} that is followed. Let us take a look at the common IO methods for the {\tt InpMtx}. \begin{itemize} \item {\tt int InpMtx\_readFromFile ( InpMtx *obj, char *filename ) ;} \item {\tt int InpMtx\_readFromFormattedFile ( InpMtx *obj, FILE *fp ) ;} \item {\tt int InpMtx\_readFromBinaryFile ( InpMtx *obj, FILE *fp ) ;} \item {\tt int InpMtx\_writeToFile ( InpMtx *obj, char *filename ) ;} \item {\tt int InpMtx\_writeToFormattedFile ( InpMtx *obj, FILE *fp ) ;} \item {\tt int InpMtx\_writeToBinaryFile ( InpMtx *obj, FILE *fp ) ;} \item {\tt int InpMtx\_writeForHumanEye ( InpMtx *obj, FILE *fp ) ;} \end{itemize} There are corresponding methods for the {\tt DenseMtx} object, just replace ``{\tt Inp}'' by ``{\tt Dense}'' in the above prototypes. \par Two methods take as input {\tt char *} file names. Each object can be archived in its own file with a particular suffix. For example, {\tt InpMtx} objects can be read from and written to files of the form {\tt *.inpmtxf} for a formatted file and {\tt *.inpmtxb} for a binary file. For a {\tt DenseMtx} object, the file names are {\tt *.densemtxf} and {\tt *.densemtxb}. The {\tt InpMtx\_readFromFile()} method looks at the {\tt filename} argument, and calls the binary or formatted read methods, depending on the suffix of {\tt filename}. A normal return code is {\tt 1}. If the suffix does not match either {\tt *.inpmtxf} or {\tt *.inpmtxb}, an error message is printed and the return code is {\tt 0}. Something similar works for writing an {\tt InpMtx} object to a file using {\tt InpMtx\_writeToFile()}, except if {\tt filename}'s suffix does not match, the {\tt InpMtx\_writeForHumanEye()} method is called. \par Here are three approaches to link $A$ and $Y$ from an application code to the {\tt InpMtx} and {\tt DenseMtx} objects demanded by the {\bf SPOOLES} application. \begin{itemize} \item An application could take the simple approach of creating an {\tt InpMtx} and {\tt DenseMtx} object to hold $A$ and $Y$, write them to a file, and then call a totally separate code that functions much like our drivers, reading in $A$ and $Y$, computing $X$ and writing $X$ to a file, which is then read in by the application code. \item A second approach, one that was taken during the first integration of the {\bf SPOOLES} library into CSAR-Nastran, was to have the CSAR-Nastran code generate two files for $A$ and $Y$ in CSAR-Nastran format. (This way CSAR-Nastran did not need to know any of the {\bf SPOOLES} interface.) Two custom routines were written to read in the entries of $A$ and $Y$ from the CSAR-Nastran files and construct {\tt InpMtx} and {\tt DenseMtx} objects. The wrapper routines we describe in the next three chapters were called to solve for $X$ which was then written to a CSAR-Nastran file. \item A third approach would be to generate the {\tt InpMtx} and {\tt DenseMtx} objects in the application program, and then call the wrapper methods to solve for $X$, i.e., no IO would be necessary. \end{itemize} ent[] ) ; void InpMtx_inputRealMatrix ( InpMtx *mtxA, int nrow, int ncol, int rowstride, int colstride, int rowind[], colind[], double mtxent[] ) ; \end{verbatim} \item Input methods for complex entries. \begin{verbatim} voiLinSol/doc/wrappers.ps.gz.uu010064400020550007177000025117350663201521500173320ustar00clevecompmath00000400000006begin 644 wrappers.ps.gz M'XL("&8::#8 W=R87!P97)S+G!S .S]88\EN96F"7ZW7^ '5V)&21M+, MR (6:)H9.5,S7>IJJ;I:LX7^$(KPS(RIR(BLB$B5U G]]WT>1J3<(Z5=8+#? M%EO=BO1[_?J]O.3A.>]+GO.>O_F?_O$WOVBOWOWN\1?QEV'YF[^YWC^^^/CN M_=\]O/K]Z^\__.O#]LNM?/UPO?O^C^]??_/MQX>UEOU_YM^:'W[]XM7KER_> M//0_/C[\YMW7'__]Q?M'WN&?7G]\\_AW#]^]>/WVE[P)S_SCBV\>/_S=PQX^ M__R?W[]ZY!/:AY>/;U_QW/GNA[>O7K_]YGSWA[]["/R_?8T/1XW\ZG[W\H?O M'M]^'._>?N0MKG_X]7KP[_E;7N&#^6_QG]U_ZJ??A?D[__VG?UK]U/\[/_[F M/\UG_N'OYW_Z;S\_\NW^Z=-SO_D_?OJ;YQ_]CR^^?WS_F]?_PZ_PGQX_?GQ\ MSR_[VU?7N^_\]8?E;^Y__OM__(T/7[Q]]9]>OWW\/'ES"AY^\>[S"_[QQ?L7 MWSWRY[S/J^]?_S_V$/[GAY>?W^3A_>-W[W[_^.KS:W_S[H?W+WF?AW]Z_.W# MNQ\^?O^#,U_++]?UE^OQ=Z&NQ7E[_.;UVW]\_^[E;QX__MW#Q\<__/+[]^^6 MK_B;^_7+CP]Q"P^O_.'5X]^Z$^_ M>OCJ-S\^_N'EMW_ZU?+5;W_\S<.O_G0^?/5/O_[QX_L7;S^\>?'QT9>\_O#F MP\/7+]Y\>'S@T>\_,#4/Z_IPQ(?O?GCC4]_.I\HO-YY;/C_WAKGY_LT/'VKX M/:B]>$7ZY]^_,7ZL/YI>?WUHQ^F983__O+= MVY\DU_[S/__+.GWCY^\_ !*WU87GUZT?/OTHC]]'MD__=KQ/'OM\_?^]*:?__IA M?7CQZI5_O?S3K__ENQ\^/(1?!OYO?7CS\//F\RL=\+,?__N'Q\_OZ)K]1[\X M\_#]XX^?UN_C^Q\>7=[EJ_^(V?[PXLW7CX^O?OSP\<7''SY,H_GJZ>E/+\8& MM8;_^/+=]Z\?/_SXU?_MTP\/O_5-QC^\^/@OZURB7\S__'<^=)SGOX3/R\;# MMV_YB?_^??_TWY^/FSL;KY_^F/WS\^ M)%_MHW_X-'%?O_WX_@\_/7?B/A[XR(=?+1_X[=MO'K[ZW0L6Y[V_"T__O#ZS:OKVQ?O?_2?^>CQO?/4W[Y\IRMZ8)"_6A[=%S]\_^-7 M7[][]\!\?LW'_"E^?C^^/O_\WL]_\^[%*[X*(W:C_O3%_L7I>O4U7^O#UZP[ M[_YIO,X5CSY_ZT\O^O"CQN$+?_OY9?_"STX=_]&&GSUK_[PUUZ]_FP8K[\CE/STPL47?M1&OOJT^//GM_R>M? 3YJ+XOT\;\%?N M'][G]:M/)OC^W_WO\M7[EY\>?_/]9QO]_-__Y=-_YIKPWV=6\^.'%[_7,E?V M'GOQ-W../UF>GQL?<*Z/?Y@__^;)!C\]_#2PSU_UMP^NYY]WQ9R')3Q\GO"' MS_/X\.>EFM/Q[+=SI>>7^_S2!4MX^>+EMX^O'G__^N7CTVN>WL*-_;1M?_'+ M]<]O^/G-Y_O\/'T +CT[E_>-7+U_R+?[?K<1_ MUY%KKT^3P^O]NFX:G_]R]_7/CH3T_?/!^/?O'MNW?_^O"O;]_]^]L? M?WKH.W[UF[]_F O^JX=/L6MQ[@S=']\]?/7/#W_-H\]AKG-X_F3DF+XZ/']J M<2R_K%4'_]5_^><__?C5K__YI_ RW8OQ4@/A?SJJ1T;,6#[/_\-/@U_\Q?/! M/SX;_(=OW_W[]ZZ? 0%7__[CLR\]'\^7+I_^\NF).97:YO.PAI_ZXM%*>)IS M_Q4(!OMX^.VBIX_;_ME?_HHOO/)X^Y&G?^,*?O+23D!@ WU:1I?LY>^G(_T3 MX6W9MZ.LOSSV3V_]*9;^]N'+9S]%Y-_ZM;[_T2_I3[_^,B(M,P2=]SNVY!Y^ M^FQW_@]O^-CPTX]__/3C[W_\_.BW/[WBMP__K*7\\_*C__GU/S\\BY6?XQ3H MZ]4///SW;Q_?/T[O_-,SS]S8P:K_&!X._=[KM\#!WP.A^?W?WJ\_?/_FQ1__ MP^.__60>^>'9:_[V5X^__2=_^>[]G^9[?X)1G\'1GSZCJL\60^#Z\<=OIJ'^ MTZ_GON;_\]/JM(N&'CY]J4_?=Q,I/_Y9\_O_/;1XR3"9I8DZ7_;OFKN.;A]9]?\-.^^VD)W[\A M!O(X?!X2<7/YZ;E/K_D427]Z[NO7..QOGKFP%S]^>L<9DQ_?X)2G,1AQE^F! M/C_[6]_DZ:7_ %(V!/LKM_%/$?IW\_F?'KW\\1?YX1_^M/C>/_XB\2,_/?[X MB_CIIZ\%N_.G;S"/^<.W/WY^YO6/GU_T?_[X^>_^]<>)KF3Z0/!O69NOS$ M9 1QGRG>\C=_YJ4^^PM8ST_D;WVBJ3B>&T[R=U*C]:']\,U#Q,7L?Y?*W\6\ M+'_SC+;^[?4??-7QT+Y[? ]K??N >7Z+57Z<%/8W[UZ^?OSXQU\^/#2^RJ_] MDP_B>7;>XZM?+@OTYFFC+Q-N_OW;K]^QF3\1+$SC\Z]^#[_3(?XMX_P/?.D7 MK]Z]??-'O??RU:_>?30._^W_]6']E5']_,W'#V_>_ J"R7LZ3W_QZQ??O7[S MQ\\O>/<=[O7Q_<,_O / O/WY2__;)VSPM__P^.KU#]_]_+=___'%F]?UG(^^8^PY$_P/CR] M:CY>GQY_!OS_(@WZY-3__--__]F'_!G"_SGT+)\#SP/[Z5.4F8[DJU^^??=Q MAE5BS8/!9@;J?07NO8#,^_SGIR)1;6[OIZ<2Q/C;QR^>R@]?_:<7W_WNU?/G MMH>O?OOZV>/]X:M_?/[X %*\_N:+#RL/7_W7[S^\?O/N[;,G*W_W[;,_/ )/ M?'C^! /ZS]\]?O/LG0X&]/77SQXSF*^?_PF#^?K-L\>'KW_^@N(3SU_!,%Z] M^_CF\91Z_>:\;>'J*>7SQ$M-[]A3#?OGB_?/O6ACV[]X_ M?O&'FWSTY9L7)I7"%Q:5UK\PJ!3_BCTE MAHQ/>_/BNZ>G&/2__?#NXR/C^Q1L_OP;AO[VA^]^9Z3ZYNEKISGW?,?W3T\Q M_.\?W[^$RCP]QW=X\1W/?N"K/SU;/W_:EQ^5^3K?OX *O7G\^MFSZ^=G?_9B MO<,'WP*H^.V#T]X6*\>[Y+,M_GVS]^_^WCTW?)^QSXZW=/(\Q\ER]G M,O--_L?C^W=/3_ EWKU]6JZ-T7_\]Z??;XS[X[?O'Y^]0FM_]\/3C&W:^^MG M]K4QW ^O__#T6'> 3Z-E2CUU>,7$[$QU+>OGP^D^)V?[]*M^C;?O?[R68C- M9S-X!8-[>IIQ/_[;#R^>]ID![=]^ )$!5;Y\:7KZQ=.3?(<73\,SIK6G1PS_ M?'K$T*^G1XS[?GK$F)],VP VGAX9=)\>,;S_]>D18_K[IT<,YG][>L18_O>G M1XSE/ST]8BS_\/2(L?SJZ1%C^<]//L]@^O2(L?R7IT>,Y==/CQC+;YX>,99_ M>GK$6/[KTZ/=\X _/V(L_^WI$6/Y[=,CQO)_/#EXR-KU\_?[E#]]]_>;QR1X-3SC7%R^_V.2&I_GV7[XW M7^)IVU6^Q.^>'O$E7CX+$T*"9P^UP&[90T;U_;.';H5G#QG5^V,JH?GCUD5+]_]I!1_?NSB,FH_O#L(:/ZX[.'C.I_/'NHIW_[Z@N( M87QZ_.YGS^D4?WC[S8OW/WSWYL4/S\9FB/KHT>6SIXZ_@D8\X/TKR$4?\^'[ M%R\__?E?XGN/X:&W";:)_ZPXYR/7/WWYNO_Z]C5.YN]O/&P(!R;HLY_/S":A MDB)^?@Q)?WQX?/S#X\MEJ6>]UFVO8=U&O-8[GF/;P\A7N+<8M^-LUWWOO&D[ M[[;UNY:TC;V%=;_&548(YWZ%+?;[V-M2CK+MY\:?WR7=6U\R@4G:/M^G>>UG3TN8TNMW>7N1[QO3.?9XME"8J!;#WSR?8^XYQ:.?(2SC_7:(L:QG/LX[^TZCG[R M'7C!M;5XGOVJ=SE3SZ5UWBN$U/9T;WD[CGS6&,]Z;V/L_&+?^]5SVO/6EC6! MB^L94ES3<>]WB2F5;?1M&RF'>&_;,?B..9?][&G;KUBOU/BLE0$=8[L3YIO. ME8^MRUA'V[;*-Z^),=XAWWD.?K/*ZKK>G.K=6KGRFW(Y0V8NQ[O:X^ M0M]"OA*$-QS;$G/:"JLT=M8EY^,J=UBO,QKBK%A M+;W>M3)YV\Y;C^V*9]J6$M86SG"4(W:QT[W_FZ4TB'QC.6[5[WQGTA9Y/X'W$U'I*!^97XTWE L+8L*PB.U>@E/;&/0Q]L0>..Z35]5^8=0, M=1LEE!"/T)FV+?<& ;W/ZPK[VN/(Q\!X1V#^8[OJTO926V3,,9QU/;AAS6V&]/,(04^B&5HRY$&^W@[CQ;[ MQE"8\L*(^>U]L$LCZPY//D(\^\HR[ 'CVIFA$=K=X*-W9%++A2$=8^&3ZKEC M37WT4'L)M?$*=OR6]OTF1J1PI[Z7BR=Z/N(ZQA:9OH1C.4IFEB,[ B\2:UM2 MONN-)[D[*]@9,RX"[W#>?,M:ZD@;&_;DJ:,?93W.$C9\0,%M#;Q(/]D,."-, M?C_W)=8M#QQ0O,#A/,<%YOX6..)!V+2 M+P9]K^T>K,RR9QQ6OV,]Q\G&WQA&B.OAML<)C:/$>P^YA_O R-8C'5?=CQ7# M;Q7CYDNQFD??:JUG6U@V_PY^SUJ/L?)]K-/Q6;P.G-.*!4:?S/K?]QK(' MB\^L\ 4#KV-G9^QYKY4930OK?(;U'!@\KXG,S8XCW*#&+19>G<3RPK,@U,]Y('N_3$LFM><43KL;$"E5W(VZVI5W9)W+;0 M,/@80QDCYWW4@WF.%_O\SAW?EG*\VI477I13OQLN?]\N_K0?%SNX8_OYOG!) M!QYP8R('5EGX+OC+E8EF/Y]A;W'TE D9.>-O%S;HNEUI9VZ:'T\48D4QS\*^ M/@@J!UL%%][X)]Z8\];N-;'K*P9>MDB88LT&*UC*-I6.BU,'B" M7>>IA-\JA)BZX>@W!A9&2VF[KW.LV\8*E;H3SP@_G4\>R[W'_4Z1M]N(%UCM M5MCN3 P!"=^XX3IQ6Q&_-#2S"R<8SWCX7?#?&[/+R'._.W%@P:=COE?0-]Q\ M."]K#+D1H&*(_+LSXJWW0C0+>XQ;^%PFS5B32JL%S/"DN,96'(^AVD[\=]X#3;@>MTQ MZEH81DDKVTZSRV[ND#<^/U>=W9T&NXCW*3>1&!^Y;Q'KC(25ON:,W2P;JQ+Q MI:LQ^1KG2HS"%8,O]MKULXW-/H -QQAU9) #'W_WLF:L&)?%JXFVJT D+)G0 MF/%R>SNVAH,TMA$1+ "8=5R[2](UL0- L0UL*(>V MK66YVUCSU8^&.63"A5-US"W0P5+,!AY_"^"%"!RY]Q-'FYF,ABO EQ/W<*DW MT3T?I2^:$H:."\/5G\1!WAW?=3*U6^4K,S<%R]E97CQASV/&KLSV!7=T(! M[6)4.>Q J77T)>P]\&.[F/1SI#8(2EM=RYYJ8QVQ8"#5S1OPX+Y+.0808,-K M% ROX^T[P(3]B[WWA<4^"\B5-[A/T2 SC^43WOW0BX7;@9PL?U\+OF=VR\I;8-PR B%6:&0'CD-;1XK(!7IAW4, MR66ZZQXV/&7&"0#:B*ZLQ(;C)"[$>SG+J#A+X$0 G_ 7D25(X-J['0"IABG-<"K9@(,.L8>&)"<+@QT=('<]B78R^\T=D#>_5BR'A/(EM@R@B8 M#1"5)2+@R3 C"K$3YQH)F&P1G% Y\/=$4VG-OHP"2@-*#8,B6WUCE MB@MA5\+%"*0%CPW":F4IF\&//[_/L@LT @QR%T6!X59LB$4FW&#J(2X%]U0AJ(2] MA$O!\3")!V]P.OM,2VP!WG&,N 8,OC%C.3J]I>(K(2Q LFL#,A66NE5 IJA0672"]&&%AO;+),A[X8NQW9UW!^Y 6'!EXH@+G, VV+T#D MP/^Q=_9"6,$V\7[GCAO$D//:<5X .ETX6Q675Q*+MXE7L+>$"2< +LI+.O5 ML0T8F^A\7_FYXRCXB!;P@RT1VG5O.&C]0B9X5R*;OI2@LM[,:&;/PB:9DZ4) M-TL"[6#LA$[<$JYR6S%BF#5KE/<)=%90F6A8G\84I$,XQQB'K))Y/<#!"_SD MQDD9ZL:<#J9J8 X8?L8Y[0X$=,!XFYL*CZ1+Y" YXRH$ ] 7T0@. B0?\VB+EPG&[W@=!.6Q>+PC<*YX Z9 M:*D%M/0\CSHV 4$O!$I8(KBL>F+ >R:P<4P9!]DWT ?1HER)V0 J\"8PK;80 MDT$@$&!VX,KLK#C_ &1G2C54$2'>BUF V#96,[%S >H$@94(LQ%+81,Y85;E MPFTWWN4F#(2+P E6.6_@'@P?C(.C$GZQT^(\9.#C =1@G!J!$M@<'G(0=WC8DF= :LL+D)^0HGM*-AKX1BR 8$$IN$R@/4H/_X M5BP73'@M!3)^ !QR%N1BZ?G8^QWDVN'<,4#B)W!.0D8,V_C2$ V#/LO#TF4 M$G#FQ@'6E2#<,"A0G 64*#^$C<-R8#D_$LHX(!,$9@Z;WR M^;BSDFM:TW4N%X$3QX;1[ 9QW)0P$$(Y1F\7&P@_RNZ?)T$>Z; I\'7,$KP& M_\PJ50DEQA4!+N+2,3!SZP5S@G:P/\[<10[X8!8C,M+18D>S#! X$5H^2"ZP (A$14 "Z$X)G4^ >^ MJ%V_P@9.*V QK..[3H6WKMD @H?SI+7U$'6.R0-, F=.\Z=+0*78P<'W&UK MG:6>UK'B%CSS8))BT!?4<^D8,NX%!Z]KN&,C:NV-Z +YK/#8>82 [;&)RBVF MG YACQ#M*!07DM8P:#,$+A<@$%(*]L-).?/;E@RG#VX<!702$ K^)@ MP>C0WA:V"U?;(_QI$'H".,!(;.1C$1"0P]"IX$VS+8#0AL]! 9&_YTQ%/ M^5>3A&(2YZUW97H'8:( 3@&*#.7,[#S\TK(%@J1G9(DOSD2Q&.W$/S$J(C80 M]()=-A@:KNQ(=Q\R/'#&);7L/KNN8GP,Z5KXVG!6UQ P/LH1/:Z^@2@8 B = MJ!0]0614F#@N:C^'(0A+ R1$[ C(?^\CLP_RTN-V3+)(',.]0HG!1(-E82<> MX <0/$%KAYG#0_ #6SJ863Z6S4(,8M<#+O*%=S^(Z,31/9[@.V: -ZEL$5AD M7:MGQ&#_=@KXX"_8;S0,.9QKTSKV@CS["%G4,@$W@>&%8++ D$O)XQY*Z#%PJMP M>IYPP&R#.U78'_"(Q!HP*#$"@R!DG<48C%\)'OT!W? "UP*<2)Y1X?:PU@2; M6XL;B%?S 6O:O>9862(X< 7UPOT:X9%10R3OPE<@/#",M2?<]C#"'K!.@M2) MCQEZ9^$6Q"9Y-+ "S%A-@AEN@RB2(-/GSB:Y831-M@:0;^#1=2%R$VD@@/"6 MJ)GQCA?1#W(_<,%' H=%X$*!CQ&BO3]9I1:;I_!M0,4VT RSCV=:>+XT3YU! MA3,&@E:Z[S!.H-?)KXE/F%J'#K1AOU^SH.?1>+NB0@; MEW@/MKZ.+&Q)GHVW??4TKZ;(%FSX;;AQ!!B!26\)'0R@ FB2!\8>WQSS+'H% M !'E4Q(48 6 #^:?;W+VSKL'"*X7-'BZ>GB$CX>Y!_3T3!E[J>?*;*9S81YA M?@<#W(P[8G'"%>Z:%Z^$.;[*O;+Y;]#Q#FD X*2-S;LEO@E$ -"-ISXBW^!8 M*N"9K='@B&M@Q

3#[$AHE:)TV$A\$A#EQI+''SGDH8O'.MV>E)> M%[X@J&08@L&M0,L#@L/.%3)@]\S1V;TPP>-"O\';Q("&CX'&9'S!\%@K 517 M")F7"UG^ETLOA,3=@Q(=/+8=B0." ,!" AMUQG8SZ(:EX!$3'L3SEPZ]Q6IV M..?2QKA6H6@'FA"IO:43GX)&"8I;(.:QO&7 RP$DJ6Q29_8SZ ^8/3T6GP&M M@G8L23XW"H&!*S%NN^0E"8:54F:G-J@X*,E3)MX31KN!,-<1(9N\ M,UCA6."DQ"J>A)HQQ8-BZQ HAWJ->4;7#MXI>Y0'AEGC/M\>H):\ V!UTY4\\#5(!1B-!\R7 M!#0R#WM>^"1B<6./A"#9.M 'R\/$YR# M!NCD \^E!2@B VG$)GR%EX[0IJU WSSS[3>LA#TA??;6">I2P4!,%.P,6,W, M$\+9GRM\ ; 'E-I@2Z?_"2"$OO-YA'4OPP"7!>C)5U\]SQG& M!^ .P- $VH#78&":#GR>/V8I\"R7D9@^886Q[S?O)CBJ&T1U;7I/NBM70@!B=1!L3W.1?-][B MU']XZ)#9$4M-,L5 OX'V! C MA7GNV #:UL.*;QJ#@K9A'TF2H(=0:@\ M@8D0P>!(T,O;P X&U#EBZ=']R"[SS/"X1::>:N(G<(];VTZ/4 .\/+UXB?72'@"6?A/0_/@N^N#<"(RTT$*D+' M.AH\9;B.8+S>\1S@' CH@H$7(,KJS1=0$S*6XKSOW"#6]X[C@++O1!M"@&<7 M& ,S4591T'Y[GHB[7XGGS.2R9RC%@0 N0K]!9G-^\#$-_"D&4B?\+2@)2"R0$PODS7FB/GB*XLY 7@Z JJ74R E M=C-1EE=TV &A^:AS V/K>.2P\)("):S>R*V\/7.RKWMD[S T,#\KB*,C^C-" MW"A3GRZVP$9@W^&HN%8F$!/%WYT+L##"JXQ%D=BEP05B8AA8Y8!K[&8Z[. D M)M/ =D-@KMU< @ T1@D8XMO+'F'")U8)$QC#8XQFE(XK[L]$?65\\%"O0PJ5A 676:[UZ+YXQ0#C/!=_)K'?P3!4.2Y#8,<0O&!F;J!.@ M+_8Y=@D[P^/QISD3L9E(D%OW6 3.7K&NDQW@62ES"Y]9MWT3=<+-L3X8(9YV<$@T[O(9N'DN&=<.C!NA E) !IITEMM,58:S[B;>[\5+@9C TP X <>^P M:4_:($-0C\O[Y5BV>9^_XL&25S%X%R)?W,/.CTMNF&V59DFN,0-\>2&T!7DB M;L.?QN;_^:QY]P*!-",!SB/BALX?\%::M;V83\9[$ (()L1>,@5, 8L**H/9I MAVV-=K*/,27H_):]F2_>&['X^"Q/#W#%QSSK.[%M=L>Q>%&_7D3&S*;#;[#B M_)YI,/F_2*=ZD86OP&CP?\V2H]R6=/<3&Q>M>![OC7$ 7R6.Z!N $*< 2 M" "\U%"VP3TVUK$ >; )F#^O*@F0CJ%ZI;[#L$X!Y.8=XVW&$H1#\)UWHSIK MR?[' Z#R+P#L"0 M,$\95SBSZ4G>7>*P<#*M>0*]>_"R00M7-G;IGH+%XX!F$=6\T5LP<.%TZ!T" M'7/>C8P>G0,MV(*7P16,G@#R3>N!3^5V>)6-Z\<-GKA*-M6.SV\+@9D-E+R[ MV@*$DTF"ME>\?@?8\!LX,[P$2$L\.',0X$@M )O#:YUX3H(.7=K+PF+@3"$G M':[/%X9RAIWO*F/?^$B0]^&.9Y!F6A'F"3_%D]BPGS'#M!M0+ "@"<)AA4VO MS3P4F 4X9\6;=+\ 6 +?(ZXJ&;L!#.R["1UX:;S5>L%#@C>4[ 1<+L\FTY\: M%'H'7PUV\[$80]&_"S-P&T0*A#_X*'!Y^! M W"3["YY=)MY,X1OS^EOWDTZ"F\G5#;/??# A)*=/<%([G!"/<:]L4LW;'EA MS@'MQ&WPQZB>P U"'V_**TZ6UTLJSVG B@!?2/[FU,+&O'K+0!M +>B.O0_? MW*.GXSG#+?C3%=QJ$"]$_[%Y5^55,1XG2NK#BE/9O70 !"K3@^,S=6Y.QX> MM,T(H[E4#!>Z[+FS-X9,W@9; URP*B>$@-]#5 \#-E[]W!PJ;J:"'?'(# \ MM2TX\>FWLVC4%(J=R3MN\1(F?!!!,- ![HJ#]0-4KIXN,?MMX$/8)Q7D=E:) MS5C8J1M4YR1BB@B@QYO0D[]F%*7>?)\=RLC6W^2;VXQ=T>-5\1>PFYF!Q$"H M3&;;Q.T@METSW[<=O-A U^ YZ%%FVCQ?)$+CB]GN:[E-W&'8-U..ZQY ]QQD MU?E:O$ $VLBMHZ#GN@P H G -\053$00R@?P^?"4%PP+QTQ@M;)Y9)V\ &!] M@N%G6:5&^6Q>$F2\@2@$LB FV8?\^S!HGNZ0434$OB18#$^RYID'0GSD_0&9 M+2QF(9B6LQ]W<3"@E3Y@6&8%M0%>*H2RRXP/0)WIJH (?%W=>=,Z,^"\DCV. MZ^QE2<8-N$L$YK&.8][AL"WS/:)Y@WP/,2H&44TL!5%=8@X\5/=<%7B$!1.4 MV"[[ OC%W03^;H8;YNL"4!,(3K27;9XE5OG*18!:S9P$L8.F M,PB@]64N*C!CYP%(VX U M0'XWBVDI "]O2 ?\#JB%^R$G4DT@UW"GCK //,. 4?7YGD];K3M"7*G];/A M;YT)-)P@W/ -5:@%4_*>&8LE!%=F80OF-.!(L:Y&$*ZG"9#!BRG& B^ZF%_,YN/-P"8>RP! ME,*3!EZ_PM86Z-O-Z.%Y>>]\>TR"<)^K&105Y\3RP /7U.=U B$:7!?"1J#! M"KJ[Q'O'@%L]BFEVA:W.[O;.\S#;%]OT<-LC-/Z :'[*>@!Y!F=1/F/N42P) MHH!6"AU'TFTG?)"P#] %:6@UG;7BL-C8ZSE39I@+YAEWQ:QXG(2G+=%\FB[Y M %($^2. ";"7]GMENV#SD#9"COF[X!?8&RM'?&7-07OS4K'?'N7.*]\5(G,$ M5J<138[B\/#A"]'@SI?6&KU8)' &J!2X@$T)B[R2R69\4]P4-!!OLJ?[8+0F MIWJ(GWFSP\L:['*I)F/AJ4/$GQW8R&DN$W$4_Z\CQ_EL\FBO! &@3/[*'(;) M,@$::5W-BS[9<$=<,LCVK.=F*J1YA)MGZ#V#]39K!LQ6%IS?HWB693K3;N8/ MS!\K\N#U:JL7&;@)F/"!S\%VDJ=.^[IVRPIVBP#P34?WFCJS]<'28$K0!3[A MPF<0WO'+N+C;"\@L!K_7A9@)/V14\.I5:VCNI[W-9&T0,\X_GJN _[[9NBOT M[UJ!!?B0T\5E8ON( $AVXC),^')[$8H(E\=A9E8VC123!Y>R4&*1DU P6"& M\, KX,$L^X9)$%E;Q4.FF7TS!"8@ +8B]G1+8G?V[P6R:1YA78WH!$+BJ^U& MA Y1A!8EW@"^ 5-DI$(HR>T>AK; MF0OH7?&8-&Y'<_?B.+5)K.2Z "[>WUMK;"CS9B+=+MA%HV?4P90 S M6-]+OW7S'3)OK$T!]MF4? M0#C$ XE%,+8.E)WXB@N?;1-\+'Y)9JRI(VL_+ MP@O ]%6+Z2%,H:F0 X"PS1R93GC;%OXBB$EJ]>0G0+=:&,?=3&_V_)EW GL2 MELW[XGL&5MR[(U.J\2?,\6TF'RMXW(O5-96)81V+]"IG8 Y\L\PR&\@4;N'J M3/I^5!PEN.-B=R=0(QXW>4^]SX.?[J%OV#>/6;!(2'"&V0#G",S.1TTC1_.< MV&[LHQV4;TY)8#L/>0M;M<'>H!HL'GYQ7?9@YC..O(=B]B@4<-^ '6<[A^-@L66H&ZLX3.\K.-:[ M1,\<@;@@E'X#?-C"@*5"!)J'0_O,(AE0TA)QCAV[AZ7/>A(+#& 2N.AL4IY) M;=O:B\QSQSS9+'C+P\.:N@, 0>X;4WBWL]W&ZH58VF[<"6>.62UE@2 /CX;B;=:-K$=?@PD' MW%,>.+SSSI&MR1-\J[W![KW3#IY=,$'>#X+_"?'+[=6BN<_IF 4@^[KQ]2QT M\@P#1%(Y],,?A7C)@)&'-^Y \%CT3S"&+ M'0L[!*=HNA3\$:_""\T<^1QJ0CM 7/>!K0S> 8"PW,1 %A%'+IB3FF*_@!OG MJ=S%:=UZM6Y*)0;".]WL/2(O6V$1,+;#^T4SIHYN_CVV MNWE@^.)+E'X-*XPVD& &.1*G/7O+.@-ZNI-HQAD!A2T/GX=1:P$;UK*; M<,M?S1,?L+SGBVP&ZWT8)!;)?.)WNX45$(33BKJ-]\[W8O%;(OP?WD3S00-; M !9[VIYN(08>M0YVP[Z9!60YP%6VZ^1[ALB\9*GT9>D8'!UP=%R8'+ )I /N M8@2B#@"&^9B794Y8Z.')7X%T7_ :MI\\)=\L.7 X,Y7 CY/H!-PMPN'-_,4= M&L'VC@E*G<"B\01W0TK@,IUI#%#7(Q1\@*=5<,7-:L.#.&T*Q5A*BYZEL\H& MY>:ERV74E',RB$U_"]_-R?+ _B _$8CZ9C19N4P9WCW?8(6=;>KDLL*H1 ML./A2"9"W(8C5MC(9X6ER5_LZ6*J$UYDJH'[99I,"[50LW\!-8C \,'<=H7O(.7]4)L7YCX?/ +^;V MX=E,2(7DS'15$+^%O"%:ILC^NJ(9!B9[)?P 4&^L7C"?Y[@!'WOC4Y8,=MTC M<-R$3&$F<^*I4?:8<9XME6TP%5CB8#X:P! \12S.$8L!3)HA RG #.^E\>TN MD>2Z7BNDS5N^;H3<0 D1""]B[EZ)@JFQ([!W%H[N-\ >L$UX("X27HT!^._# M8J'&DB1KDK&^9@:'I9J@ 3X8E@WKPB^:%.?A[,PNW#W%A5Y>5I1$K[+B(I;8 M9AV4Q'U4BQ3KN>JXAZ5W8B/S&UA26*.4#[;"YFL>./>=L(O+6H.EHNNR$9" MSI",,.])S'*X("&GB7>GQ_G!I!9"]F;A$.]ME<[.$"Y/L3# X$[%3F\WNM"5 MD-TJYC,\2L0-X$"JVB/@6D\NS%-=4ZGXME_@& M7($I5@_D,D F>S>1 ]H%GN0-BZ6?L(T#V\.6;OXHPE)2Q4=FW.=^+V*& M.S$U6V3((!!,@*VHLX@6(()6&]EUN0UX=#EK>5>=) [RXR)K'WFY!"W6*TX;K[M M@B/!LN[ >F/#7BIYQYW-B@1L%V_KG'?\%WB-SS%,#1AVP*[8-D0+BX]9Y&3E M@HCNME(-6SU&CW5M421Y>X ^M.T5#V]:<0#A@2^\^0>4X$3O>NPX"B!5]EZI M+6YGC#R!9I/77FEFOQS)?',!(!SUUBA@!\.B2 S?,]=F5D**JQGG'@>Q7E=> M)K9G"?@B-SQ>-U3 />!YT4EJB;B[ [2!'=E$%NBS%UV;191[\ @;)'![O'@= M"]X,Z,F&&"98,('X6?"9A: &H&WSD '[ TX":8!\JY3KP.-"UN&4. //.$YK M@99FSAP4TGJ.E*K9K;B0YCU3Q4E7J46((!.6+7G]!CS&>QRGN<-FZNUQU4*! ME2!'C-34[5BA5VPS K>G5]YOU/8\] +\U5P8>O$M)NU]/!3%@MBOF6^+=R2 MN-;+@NN"A][9T_'A&2I O0'Y5KP>>"X*E4X3_3R2TRM::QXGVF>[[P A1E.M M CQ/4V"O00PHF/C>O*N]9%ZF4HF#;N#[4(; ^]=M/PA9,CZFS31'HIZKUW8L M4;?M-2L&)KAO!=MBBVSRZ\.)P"696$=DN$ A[M.Z$R']T&8RQ0KN)W835+O7 M O(E+6(ISXP!POK<#[-^T&F^5P]NU-$ !@$XK(\;D1+?'90,"%FMWX."($9 M 8,\U]B**4R CLUC]&O;QS!&YIQ],V MNQ:4=E>F,[&3/<>[0ZXU>AYD5DRZ M]J.D>S'YTPD"-%J3#D,D (AFV1#S?MO2?E.B04L@3WE_K;)H Z))D,S5O%L% MFB[UTY4X8R*DP/L\QF.G&DA7ZQLL>PK,.\ /Z'YXD'Z")MDNK#B[10)63KW^ MWA8"$D$V-^O@SEJD,I8801^;4//6'B" G>-4U)!(,,9M'GMV M(CI[GJB-*P.' Y=PKM5,PP+@Q\=$Z^XLB-@K]H<,RN>3=PXON/ ML(#7K-BO!;I65RB/A>:[:17@Y)'8ON9%XZ9BD6%=?8W?@!4 M9V-)G,#YMS TX>LS(+B4@:AZ^P>@4=K=/%!E@HR]F0)]]E#.LVV M-0ED<9> LO!S429J]4#&P5I)#Y["M5JA#4YUD2QR)?[VF6\*FV8)5F2[Q M>N5K&J/-$<)HV.E6$!P=CHV)0N3Y-JLG5^R\E6AD*-PTVZ,8Y2$1K I?@?VY M @_D96H# (D4FY!L8X&FB+ 2@["Q'3,2 ,D9)M;L&?F8&'PC/NXCF]-F77?? M%O@S>RQ@"+=\ :10B-1#%X&],\9MG5EQN.T=3'I8CW"%R(ZR3#?J1>,X3:V. M85'UY?":?GX:$(/54PL$KVQ. GQU %UG&E.:13T!P I^MJRJ 9)G*J$Y=KQ@ MX8\WYI#9'<8^W%8Y<;C R!4\QB>5#H#=@$Y=5X8-))!?FI5/42QNW2F.PY+E M!<^XFB3;F\<%'0)=+?H^K<8V\EZ>J>/;QPZ6O0 0@!LX!F9#V*ZG%ILW+[*8 MC\6DMWMF'H/H//#GOP$#)=)Z:7OB:QGF[2414:"J[& )$M3;DS^K$$S9BE:+ MW$O-&_Z+3X>YI.Z5+:S $BSI'G;!;C$5O+)1@/9@!>P5;'#"*DPIN68%#E\K M@=,62PWN678IZR*H K4NR_R!DU;43#P=<,7EKBR7#SJR MB<6)(,SL>QAN0BH0I,RE O#-Q(XND]=IPQK-7(V>G_$\1LZS0(D!U/3( +/+ M:<&QU!M$-@NEO$@-5D7#>($DK%>]YW';L+(@;D+!M(O08CC@:6OO'@.4TRR; M5A?H^VG^^N6IHG(HH/$;7]OP&F%X-6SJVJS5QDB!!VP$4QE9+9']!8WVI"*K M/X/1GFRQP/8>7O\1-#N^=\?&<1VWB*F>)G%"<%3%,8T/'$BD)<2P*\.J5 (1 M>\5<%P(Q \S]]#[/*A6/MH'_#$'!&6NAK+_8@-P0WGRPWNM),,)1!!$%%+VL M,O<(WP3(>^_*T&#*Q%9/'GBGTVRWVC$WWA5^;/ZF)[W5&Q)([>ZV!%+!%B-N M>(@XMP7O"\ #2%F>?'N8I\[-88GO/JMD8TTK *$5\#G+DV9V5H?->L!_WUOB M>V'8V[U)$0D;YM!O6U9D@U7@-5Y.7TS4EGFFS&N7<]5IF$SHYQ5/>P<+9X4L M%D?4VR]<4#'M/7;P"03"FVRS9[REPP'-L\-&[+'X5()8\>=\7;;P.@BMP5H9 M8"N@FV<7 Q91%JL @1(/SW!YO .-\_X:BE^ 6==)5*^[&0)%*@+$2Y9+5_65 M/&IN^2RFI[>C$@XOUMF;*ZL0S"T_A'"8SBUS AHEK_Z#!WC%XU,BT"42QK&P M0%:=;\!8[ P" #H-F)#@_JI6GU9+&KV&M](+(S!LEH$/'7!NMG0F'LWW;]XS M6<,+$R2@7$"Z8E;^:G&7)UP>_7M+3H1E<(=2&?+^^_:>/(6=@/@W3+F:37[5X"2"XBQ:8*UTOS?. M:;^$MD"LO@ O5@,K6'H%T7O9[(6[2A8XE3 K:3JD0FOW(RPT 3V=^02E'\': M88S$T\!R+GX. <3"F8E! $=X*]PGO@27[Y&;Z!X'WNKPXLIS;V\WB&]L3+PP M7SOVYG79XA';!%IX*>\1^61V2H L05A-'4],RQTQ*2B!1QPB#@N(P=NX#.?@ M[%Y)X"@74/_!Q]?N7;H7)/>LTH.R1#'6?2GF 15DB>X[L&8LTR=R9QY573U+ MR4#9%=Z[8# ]="O[V/A@#C-"H-1U4V0KJXV569$*Z/ 2&BYXM'MFR-01BR5O M-_B86#@3LW"XD%:FH4Z^=2M(8-I[@K'SZ4"1CE_#[?"W0KFH, 'LG9D$H]Z^ MF)TL!I*JOWX);Y MW3I2W"UH?:G,G6EANZMI12.1U5/ODT7JX,A(F#(5"FBCV,)1(/F$/IVIY8\Q M@6$(,:F"$9:M=,L5U5$ ]\). )&Y7AZCLI\RX?CV0+BH. ;HVOOJS:F38\;- M/>65HH>& ,MEPYD1OTTCGQ58:P8H'-YKQ.OR7 VL9%8HN_ T)S9ZVAU@8+N9 M*R7>A&I/7*WBAZ'AMYIFQYY4'N)7@VWK+QMYUS1:- M6?^1S&6OH42XKLWG@T -PO*E;0ZSVS QOR@Y5IZ"9+4GL/H$CN$F3\?O$ M)18.@>&P%_CJN64"RDRCQ!=@%&'%;8&=LI@%7#):-',?A\G7CE";2JAB1\,' MRN>K_\W$JZ.H[K3#T=G1BE$1I$V_A$%[O*TWY$.]C.IUP K7"(N&;T"!@>_0 M%G9VOM3_:>=Q60G.UUM"3^9D86"P,1 W@0+4L'G>9.)P\2:\ 9J NF ;>0FA M&P_I>OR,SW2W M5 03J[K9OLJEL/>"5=[J[,U4*4^:-D\66=HDT&2[J?8TKGF0T'C1G3QSWYH7 MY/HO15M/'S0(,YBL> X/NRB4>D#\-U(NT= XKH3PU M4QV0-9I>M11K/38KF-;%U,,&^L<1F,0[ZY557EL]0IZB;E;X>=RW;GW,G +/ M7P_AZ2TIX%M,B4IPU5),]-=OZ H"C < ,6;5E#F]/0!(&>W*5]^]KUW'4KD %*&9 ZV[U^]M95 MJ0>KE_CE<>FTF:)[4?WQMHC$R_ #*D[< I59,<1@SZRJXV:5D)IWE_?O*D;P M0C9Q .>Q^[ULLYQRP(0E:*P-.[5C\)X$6541[L:V. /@VB*1,>/A-'N+?T]H M/F3$\D6@H.4FK9^\V7: D*+GI8:,55V44T9CZ<3N3?9^W\1'LRA!15/E_Y.G#:XA5_B.YBT,!/$(>S[#>>1KC++4W MW]^$,+X$?\[2-+ &7C+@616IV;#%Z%+>BG_HV,.M>(1"FO 32X99/\]P8-6X MV0H'9+N99@0KCF4I8$[\="4.XY4@/I?J(%&A.K:8.1^$1J^<\;06K%G2:O&P M=V"7Y9,P=N(' !HFC)%=WJZSICTH807I-&W(5&HOXG?/0UCLBYDY,3,F%Q_= MX !8Q58;MI\S?)$YY,U***]"A:@<[ M*:V-^3B'IY+=PC!ON-6^85L&[\%6]3_9R&(Q_F/=PMUQODD)*+X)I#M&K]& M"9;'ML8T\JV8C:@\:,D+[A8O [B$,&+&_3;/^3BN>8KH,:",&W!4MCKEX*ID MH%N*L]X ACVJUG*KM[EO"Y9C)BJ0P7,X?)SGPQY7J.!V6=9@/J-22SK$V_): MP.1V PO8;9ZF8.(6^:W8600K>.V#>.M.D#I/R# 8B T,2E;&$^[9 /:F MX()0"1F A)E@A@<"L77,:6>?;LNIQ6V8RBV:OG>5(-1M8&,"B[S9NY6O.^-D M8KLRL9B7A_/S6(BP.KR].RY0]6(6MLB0&*J2#"[H+,1;"[4(BY5E]O*)>-7O MR!Y3H\D:2I!0QU]ZB0_CPZF42S$UW%\#Z#$LAI=4LX+]XG="M=36J]!B.3^6 M(((FD..!/-UL#*]Y].!A)!Z>\+N(AN:5CE6+MYF0YO[>IL)$\*V_(_0"#]26 M LUFE4T#"#EN236 W?-OI98 V$JO "4N$V^(@Y\JJ@GJ*L_BOK;-,^-AA<=] MSRH6.+G$\5"11(AS=C8J^XI9R\MQFK2V67,"@EH[;Z,4G#71+&=5$<1\CP9C M$NK!( B;185<7B$!2U.WB!B:CV6W0J0VEQQ'#PH'V]Z:0,&YG6 UCN2QP+2W9DC+AO4?W *Y8TYTWQDJKB#6VHCQ=E#JR@,5LT74J7UX)2'3,VC60 MQLQ)4$CGA)%%BX9,[3RGL 2AFCE:8+J>')R#,!Y.-@>AXV!+A^PD'0% 6ZW_ M("ZS :R1K+NI-&R-R_J+6OGND!LLYU[B",P6S)F9!)VNT=R$K%+%>982=HN) MLB7LS5Q_9LXC',!T'/-6%7_'PF.[[*9U48N.K MA^HIUS0Q0BV@/6&9JFVLIX+4.]L8#U#:,E/" ,LP]F,0]', AKK]F/1RG MXH;RDWQ'[+YM1 L6D=T*.RIY9ZD ]JI+QL74TMUK#R>V@#0PRR MBAZWT!TS!;1ABS5_DC!T]E1-!5V:V4^P6,[F*8F5A-:NFJL@"E+VSM+9Q+Q9 MWW'.1(W+]"G8"G$?\+.:S'4H=RLRU.@7=@O[:WC[J4H:UY1C+);IGRRM6N"+5\"I$.MV^)>:?BJ)=2,N*#\E:S?S M9KJI1>F]1""ATDJ0 IP,M#+-A%4A^I$6+-IR5!;0!!6X>FAF)V!(%W"52;-2 MJ#3I0JO%_5GD5R>> T-H-2DHJ0?$'WA0GJ8V#28#GB;*2#$--KMBRW?P3GI3 M"4<1=.;:TYO3+$BC?>]U:K:M7@4>"[2,;6$IYJGL#W:,H49AY GX31XPBB_2 MT Q6)9FASNP[L2.SRQH#N@C!%6SI B0+F*(83-#;NOHE0L;BK;6Y20=[W'-V MAA&!.]5#LG.2:C8.@UDOQ?[2ON"?-#E9&4'Z'G>"P("S# .;.7YL%7TW\Z7 M-,11< /.-9,^6#@,\P E2#,6KPAX=PCMEJ9BJUJ@5XZ?LH"L%ZOF?T7P\6T* M02_L\@MC->]B]_C9L[I;2<=]";" W%1X9%-8#FU=U5"G-VPFY\4K 5\4=!96 M88'GQH3E3;E9X"3!P 2YZQ16+ +CH/+'(18&IIC5E(U\\/4;6()S2&46X./: M97S".V+E98)V9LZ@?UB Y>>F#2>^"_L'^I02_@52&L ?4L\*^;?B%FJ(8P3= M*MJ$'JQF%;(-(,6ZS A"7M7I3>W^X9)$;#OA/?U7/NN MU@5?*H*F% '>JIW/G'X6JGDIO0A!0> JG1;KAT.>E:867*GU#2G9AH=>$@/) MZ['/0P^^<+-D[DI60>U-2$4$U77P#@@(?G&;7<-W+MX\G)8. M8,B$.R603R!_+DVBCY7BX,STM'QP7D*:Y))FJ8052\5R[S'5^A7@\604(E%, M@.^FXZO #D^^+F_[-V_/.M%],0L2JC8\,C$_VV0[:.(M ['H&-Y"Y$B[E=1I M:U-TUO.'TRS-RMY?+X0(S7JWK-K8:'1=T80O8:XD[12J8+F&915Z^] ML9A ^].K+$4& TX#IS6BYQ2 P86=JIXGR(:Y]=S=TTS/0& ">(L+Y";3QN9Q M9%4-O60J3\%_J%166C)A];"2$TQKS,.YP835H\I0'/ ?%!)TTP#Y'9C"3B(P M +BR/U% M@*FXKLL^X1YLKI^T&@^+;U6BOVI9 CY9_C'\OG4FI>5A80[ U@O4<<[^#H Y M<,Y0#=,KTLU<#>71E>JTD-3IRDIS,T^G*F%V89!"XI;[ MY&Z&WS")&!/&5P$(T?,= ME0Q2V%7@.KM"#EW- 7:#M\!!=8%FY5#8A4P@?").'ZSC;IF04N-5X>!H5H7" M6DDK=O;4Z@62 "B[*@*[QPRWZ>G "! $(JWP^IJ10W+9ETBQ,#3/C-%U=3U MF& ?:H_M)R$*I^[U@BP=5DN07J+R=Z>ZL*HGX15M=. T@4TO7-50L5;Y^--U M,GJW!W='7]6>O3SG6;S(5X^0WU6=.7M0 :\HXH.JSBJJR:W+>6]L M^'4_TCP,OSS/A>."\DP_![^U9=NFSA1<0(&B/+219N$R.-0+PS+KNY*? ESB M1:SDL#1/C\A768FE%A<.['-1\8+) 4E:"X<->NMS@Y9E/-[U0 J,"%;4XZR" MY](LO_51:M98N%P8$"X3H_4.:Q:T='Q@5QF_FBYJ7Q#SAO+,BVN$ONO*PW+= M34USHQ8\1O4=2"+!U5QXBT%3;+BV[(TH<06L9:%;Z1"WP],W<,Q]*8YB6AOX MLD_W@S_$GOC(:HFU$:U"\^\ MGG%= =(F*F%UWLJI-!;.<2FB &>I\XBG*6RLHIY%!=SO[,MJ4RC0++:Y74O*N)-RG66];;ICX;H.&;('2 ME/E7Z"?#^GF_S4Q3EF$S<92 N4!%80+5RT\F^5CGR:\7HD<_*V@I1>0%V+!P,& A,B=)TQ39%.]4X7XL04Q5+A[YJ]#[*[W;$Q>$ U/MYC415% M[LU4%!Q\G=(XK:[JZBLE#^@?EG6ISJ20D/< "D-Z*Q:4FJJ6[,_KFZ-X,+2I M8 _E,#VJY]VT Q_M1@Z3;6I!]+B MNWXI+6(JT0ZM21X_Y@:7T[D"7*88>^)/NRT.IFKM8=K;.*M76]9'1W6JO*:Q M*@/.@\'XY4$%<4^B $P-RKM8!^AU/.#?D[5HBHV].:+S9KFG*\VK87UMYBB: MS32\7B3$!8^JLBH_U>VXN&UF6L1J=E;9W/:;U3"6RV;SR8:G<:H5,NOG:GWN M:K:_YY/!!+7CFOZ2\$= @5W-:@OO1#"OC6"4F!SE.Z^SVW=G$[-VY27DB$Q0 M+Q,M>6H)%M^:?1V HPLNN0=EGKU,M[YE!?8I4C=8"&:@MJ[@30'8KN<\TMS@ M=,=ECCR;GN_%)\^JXI()*%CM:EX[[O, TN <%!DW'YI][A5R71=Z2_PHZ?-]DMAQ^-8 M$D#6U#FE[EOW0AK_92NH15FJ!"%835(#4N$?;.$3 *1]/W%;R0US'<:A=R_>SLOXV"VH!&JM2T,"(W11.\Q'5P;L-I%=3%@SOE_>]B[F] M\@-];PJCE<1@:RSJ1ZP[2#T?@D-09&.#8(#K3(H;'FEIHJM,8MZ(R:^! M/U*CK2HHCZ]0(PW7+H>Z@ <$RW$1_2S5">$R[#3Y+IX%9]^4UW#J-@\Z+,F< M0IF7F>(P()"2_1"8. +5$J:8;%(^RQIJ-BR8B M8I^[FK6;"4C*,=_$2-#-(L->%;@]U;Y2$QK\8ADO] #&5)D64\)%;''S@D(> M"J#=9&/!M,>AE)G7KXK"8%?V';%12PJP[WJ!0O4.-_L8ZJX,7?1@ HS ML+I.A2D#4U<+?F")35AV\"63/[N"0-X8F\1%')B]WS$Q<&0"WF;LV,[+8Y*D MLGLAUKC?RU2PR;+^16=V6>9@OZ&FJ\[ 9T#5!3(T-E/2NF=N43F$DKL:ZL4+AV'5J]DSG[("B"RVHI"? M7QXH%.>:R*J*GRH6IDH.!?Y;5'$Z=4\K3K/BNQHG^'M3[VP]8^RS=M6XN7NI M:7<.LQ)4'+!UQ&*-K#FD'FRJ.F.."?8-/%CYA[&;7**B.93IL*$!]!^PE-SZ MUG?>H&W(2U;X=A$9V0WH5*L_*?.=K"^08I]F[0&=#[,:!\B*?>]YPGEX)A7: M7*\KYJEB80N2Q>SVXC477T39WZ X*O2/+7*SZD%5/=4@)%H):#R]3F>$R0+N M+=1KZJVIR=*6$E6Z@['/:^Y>["> 9;=FWX$3UFK)O>J&PY06O<[-0JJ<<);* M0&]UC#NX MZ_=/&W;W;G@@5J8G5RT5=X-C@XB )[; MKLP"O,R\GNR0!:QJ/Z+- ]KB(97]%+H:GMERZH/!R5P:\$KE M_52D)G@O>S97VQ<4AJA&6&=Z%5.WYLD^;N8/&?\4!2M16=/]L(3 ,S"[ ^W0 M< /UMBYJXYJF#9L^<6Q]%)75P)RL)5X#+]SB461Z8RAM>#J/MK/AI4>SK2'\ MKAQ#5+& H7'7(D:S5=RU4F#1<['!VMW:#?LW/:^JIZ?:G+=3.:U^F*)3W:/6 M4QF095@IC]?QDE?=!B*?"J- ).7 HA6S'?QUJ-L=35/LUHQE((9N\>Q\H,)0 ME3U8EZAZ_ J574NZ@!L .,9'@-^]'@Q>-K.;O,:!*2OUEZMRHL0!>.B1U9:, MQ-5=2>VE\%'XRP'H\U;?G.9@TM> U=HS99VZ@^S9Q"SGJ6%PKJIMK<>XC2%L9?/F=B;< MNIHMQA.ZMYR>+ZU6GQ6/D,Y-$:-#,GBP&Y-B?%.7I1]32@8G8]VP!9HEF.E\ MF6FP=\6TDZK6+"BVH' U@V#[8 1CA\#&[H5ZM3*+@(QI64=V>[=BKR(<'-3Y MM.0R,D] F+*PAS1Z6)\5-M6:HJFY;:TSSIMILQ^A!TS)%'H%)'>"+$A7%=L* MC+L5E[;>;EL\Y3$:VNUJ3[QS3OP97+!,XP#.M)8/KWQW)>$O J+GL%Y!6$ \ M<[+8$E&=O.56L%Q_8ZW0 2JT/-I3)?O"F-*1RCA5M#.Y1&[ (B;(6[#H3"&< M>VVX6S7 -Y"CZ$=0.>"S,\T@KDH*KUZA=MMT3,&6>0E\>^/C%B FFKG8K;>S M<,$\\'PM2G0RL4!VF!QSI-A:Z""$&A4G4[BWQ$\:EI#Q"S2^F@&!=083;-=S MJO>:)A/.!=)V'J8PWYXI%_YP/[+]&I5.GE)O_$%;U\+0TJE0&B;;G?2Z,=^* MR%PVRO+J:3F]DC:S"\>/HS%?J$H$^,[-%.X;A'5Z7WZK^VHA;;=GC3T+FRXB[<0<&6(YFI OI6 ;L4":5$EDYS",&GF)OI[T#"N MMBF+F!6E [H3J:2\S>8'H!EV.@YNF(=99"F"=\.GJ3C%2TY>9O/2I$ZJ*LW M4EC %L:Y+]L%:[2XP&(IH%["M]NU+W;QDO6I>U1/PV0M8I#2][8@MD@?.\0> MB#'89M!U URF(-^Y>5E^>3/B/K5Z(*O4/PNLX5Z6\4LA 8/!,Q:%F';6/JVU M=WN"$7'NY0[6/N]V3#0?;C03LM:F)#OP-!B"^V:/BY'UYA;N186RBA4>^S6+ MH:#P$)60@0MS96C#;7EA'AK9\S,URWQ;RR\RR^H(V;O; M[#=7;%]N+[4MK;%S7W33>W191(?N6""5JLW53M>J11$?S)/J5YEM&G%['J=[ MI-\/(CJ(\"#\UTO]>#:WK:@45B8P':8BM-.:YFX_Q>&]MR4Q9=ZXV__GX(OE M<"D%7,_%Q@@2.N<%OVY/;8_I/-CR<"I8F^$A;P\G!'UXD^I=G#?5*]0ZZRUL M6)YP@::\9(HJ.3D_L#$% M0''EQV+#W6"#,)SD):!6>N53L;W2",/V6M%$'\S*,\G&&ARN-K8($\"F5F^M MSN$[N#R;SN[)3LS6DBP MVFX:M)W@,+=GQW!KHMEZ>+^) P(/V736.L7LV2:?8J$8D/R\E)%0CVTSJ^D, M9M[N;*D%^%2$#MFR,;OUK6:^9^1D'@DXV:;CN5KVG<.4 M%+5/&?CLG!59=BXRED\(E:#T*$G?GJZJ&A^@K!DRM=E>>F MX'CXIEJ(+)[]2"_+>W=[2YQB]TN)Y&!A ?%)E3)KL-=LRV^;I'M*Q*:V<#IY M7HCS6':0)%'>!AB&%-V%(K@B*3C^9H[]<.DL#[[K Y;>F<4H3NT73./A[V7,@8.YZ^>QPZ5DBY[6EG#08!E?CN M*)9WP M>N1>5L].NEGMTGJ+J_F*4570JE(\W[1>MMJQY(L@KIM2]=M6RY]X>WKPF6[O&.)5TL#\[-"ET ZNQ9=?AF%3;LWW':%YF>Z.E*K4ZQI8CE^'I M6TL+#B'9%3:8*U/WS2(?.]@JP+IYS;+9$B5Y!*ZGP%]DZZI"-O6/_:ULG9': M>V(HHFU^IWK0<=6LY*="9QU =)H2 '>L4PX2NS]JL!$R?ENQ%+X?<*)9',0P M><]K45I$#73@);S%ZBQH7["QEK6[,J=YZ'_AFBW7\;J8"87?@!%8!$]-[N$] M9TYC,2_9I/&R6^-G:7E7N&3VL4JO?)8 @; MZQ(AEMF'+1R5-5NM%3[X !;) M+[^O"U.+=[MCM2"+.;7P-"EJ"/8_/3;T#0 9P<,(U!!,&O)G_I 'M%6* M C;;;#UY3'N?[-R,8 "/FG2 KO*Q^SHA'?T&!O1!JIZ*[/\9K(:N'9>(C9\MP; MI]"7V2)JM>$Z,<,^T^PH8"TPY9[M:FU["U/RAMP:+J6V1 MUMB;5_:2-4=KB$\6&:=XVAWP-C'Q&J4IY^NZ@2WL)6=TT)?;J?O>;)*'W[(] M?8@)PG_8@'(G9'5;H"K[Y,G"<;8V4VN8%Z]S,$Z\PX"G86)0ITLU_'O267M1 M6HC%G)D5:?L#!F>S<*NFS"J4'EJ=RS#$!6/,C)Y3&>V.T>&_9TJZ'7P^2U 1 MT8&NF_V[NL5D>NC9Q'K8B0!>E[N)RL-1W?8"GKK.MEMN=;^\+$O*;UR>:T 9 M6(#3EI3*E7H@;&L/@LUJKL3.GIYBM2$IOY2FYA,4&4:"75]6/ZC<4TT<7%G% M"-:X7'4^85O>$?$M9[.$V,WOLU2&OU7D!'>[ Z*5JP/+[Q!E)L'[,Z\N MTZ+XO\6.1&A[AT.C]N;>O%2?*Z'8P'DFB%[FL7M2Z<8'314US, CATQ%-8,Z MV)L3L;&WQ)W':@*X5<"[8C-6Q$LV;+>V6H-6O9"T.B_#LV;1ZB@K#M\KF[,L M*7LO)[.P;[%M(S!]T(5"/CA1NQA*2E8S)4QO*?!3K^_,0#J[K=QYZTK6#X>A");T:6 M[1P_E8!7%[A4^Z+MWJR98 8BC>;-K*P&CW:32*K"O(K[*H*MF$RUFVX :SA^ M_T;9&< R#$LDPL!M37&+&F;:'+R/0(*E:W>$_LU407V9!\D9N!DM.HYL/R.A M&YM/\)C>*BUU\-0:LZ_Y-17:U*6%@ES$8!B$M2278 L#B-ZZMQ&7.V-TJS(* M8PI.E'W-P+W(=N'+)M6;MTQL;SG+88^@K+*2S<7;?=AHW:#U?/"^.K*FQ.], MFE*CW3,A,W7G[1!CC::4>(!H0 8%>:UL)>1E^V=/UXH%6EL$VMF%G/A8:H]* MI\+V9,*6*>(W4HU LPHBL,O$.3NX;ZZ7!_F@.]#\VKHR\ ?34%,&.:J2?C4; M=B>[C7L#)BMKGK>H[F6K:P6GB'<$GME0R]P)Q6)4.0)N>9D.)!\+A,^^+A[O M2KBBJM'QLB"UJ'QSHPVK!@A_%0OE.9 M=B^8!T.\@J<3QZ%@F#=2UG+CP\R2@?-=GJYN'4PE#IW$#!AU\C791&4'-,1] M2 W777EQNU")/(UHRI?9D,)V?O<]TP7QHNGP<.!2IZU,F1D[+!:000&9+]W^4YGMQ ^&*%T2]$6IRGQX-K';$/:4D/+Q-*@I SSJ;1UL%2=Q(!&%BL,W4K-^' MG8)H9P[H;E\I&+HZ>C:=)*PD3TJDUUWQ$,4"U#I0KY)@KR([Y!68HT9]!XU MS--N(MJI<'C1[YR*Q0%%-@5K\)B\JN02A1-6I13>M9A+ZWU= &TSA^&:ZKF* MG8FC@'HJQGO.CSUU>[Z99#L\OST+BT!8YB6G[>:N8%&.#M3DW) MX0M8&* P MS?P'"&'M"I-'\UQ5TV7N-J)UQJUG1=5OCSZ2)S0X3YLGAK*:Y:6Z485(&=<) M=6?%)WKT[WVM?8)PWT2[BFMBR/9=\U;?C"L/XC'*R_OO83%/L:X.@&%'I0LL M&CT )3PKVV.Z1\TR@._$62Z;/+* MRMI.Y>L\51M\X)UT51XW@%X)2R;(>Z9; $U!=HO-JAU*N 3&+RI&;W;C7OLY M>]*P$]*&N39"Y&5"][!?ZU TQ=PYC\0.B^'&5,"SDMB<3LAC$KAX;;\R[ZEY MYH7?Z-D.[Y--, HO$?65$S^*W7A7QJ;4U#!K"7 :[:V;;1-+A+AW7-F]8+W57CO'Q8L$ MO6Q\-Z1IN=F:,ENN,Q-Z5%/=@.WKL$A"%1M@TK$1,N7!>,XE>E*_6P8&.L[@ M6SOP3JFN(\Q3X.%MLQJFJMO"&:,MAO+N/6!4Z\L4.[7[ -R+]C9C8B%,TU*Y-!"YH TF C,(HE8'LEZF?=NDI*A]-?N0!D8&(+(1D?(-@5VX MVS$8>^_J0*B% (?:NN(ZV?XGURR-FC65$MK=1J=*A_;;)MC$$2L=%1H"IEY> MF.!L%- W^H.XH4VU#1M'GEN+JE^LQ*JX5FC9!D^!!-M,AM58NH68\H=H]97M M^&9_W:1ZOXK1, @%H/KML:\G_?8'LAN;'4&@CRSCK7GQ1=/"[E^5.]E//Z-F M'!88(>_X2S,7;EM_VSBI-)SV;O$.*/783)2S"QU,1F$VD\+6NJ@U8:;2;9,A MV[4HW!Q!;B-:ZKN;4VLSJ,ON':N%-19GX*E9$[,$1[(7&]_TK!"Q:*]9DU4\ MB;%0':0_^?MNC>A@B!;)Q&SR0/4?0"T ?<7-.J.'R;'@U[/L>;%#HNHT,"A; MP?)Y25D>\*3BC$H8@$1VSY>JIT.F(T%VV',6D(K%O5],+$P_[L43Z@U>9 Q2 M,+!U.]FJ\X!3O*JZY))J3"'#VKV[L\>M:N'>MBK0(PNR:AH[NVT($M0?AYH$ M&($88?,69 I7$X$()KB "Q)J7394QIC?5L5J8@8)TLT>Z72'V(FRP,9^YH1[668.%*X7$ MS9I<<]S-2S7GIG@&R:=?!X:^\>V*[;=Z-X,JT@'UHOVN+@\==P$!Z ^_N >ZN3%K3"DQMLLM(O-D' [ %U*".4)J\,=Z\K*JI)?'4P?)Z ML&@WA4OX/_3F-N#)T -E7X4!]G;RP,M.BP"E=:8ISHO=W=*132&(LMZ:NDV_ MB/;0.ON+B)A.-=@C?+C\=% .IEUMNF4_))RE.S'8I MR?S!BA%.YP^1\22:.*1 A9=BYD\3T^:%YVD!R3S,3O>I"[*I'Y$M@W\8P528 MW(3F'>^P'FP_:V'LR@(\*LDL'T:F"EVM!'R[X]D/A%BRL*N5Z*\^.E4:"R9Q M6@6T7IX>EEIU$KV:7PT8"8?,NW#Q\%CM: M^F46!O&7>.X!HD+=)KD!,:--=^%EV-8>@FJP^$<(H?5+"P1>!<%L^UU7O19+1EL\*-"U0.0@Q4S]YOGG>80DG<[* MLIJM/N;E_F[S9B)&S?9ESU+G[0!7@T1V)69N^W-:N2"G4#7@ZM))L'334;2A MQ/>FEDLWRQEVL%NWT6E. 0 5PY%47U@8( MJQN&,JQFM9(AJ5W49V4-VV18U6:,*%,R"X/N=UTN3>.\-?%H[[_=0]MQ$3J: MR?1\Z@38;&'8W&7"FY>+E[4VU9RWR*?A^+IUY0O1CW&ORI?9*F&SPJ?: 64< M(#'XPVZ%/X9A]4;9H2.$%AUOYN>QVUEAV(C$'L<+IE]F@@5&H^I0,F_6\[W5 M)&DPPU;L(J@TI,H)RA]U#^Z9:ABCM3*666&,5X^+1=+'I&_)UN.P8\]E>YS: M]0H'M-ZW9-/7"2ZF7K>Z8!;\>TO(9,1[=JSOZV*_/6S;$^(]>Y?&5[&]#""& M"*6R%1%BRM^TF?.V;J:6J^#B=;!*P^"3V:WZ/!;>!!QG.LFM\F\Y5*5R*V8; M$@++]F1/A&L%&M5URE=%KRBEG.X: &,S! M'-6=N*W-WM[P_)IF4;\JK[\M5P 2C!7[5.D_MIM\;U)+V3N MN'^P4O8T6AG3HWR2@[Q-QC,>C+U9AZP/&;VJ![[BRWO,9*'.^;EM72+UMB*JQEP4$MDG#W1+*_5*"_8IU\N_+3'#FN3-]:[<9!@#Y5C91Z0,BLX!TM2WG.9)? MRZ*D-%MR8,A-399YKD%T2++Z# M#AX;:#:L9G]%OC&[[C;K(1)Q/&$#OI5X6[2^G+9Z--65&>#K$A:SES >;Q"9 MLO+ C:Y(UZ8P(=3PX<2&B,^REP1FSF6M)CY6TRTXF/,Y;$A5[!WG0TD.X:J M1+]U#C:-Z+9-L#ETM)>K1:?$Z$/EBHA-@[:'[;QPF3:ER1;LQ^"MBA<@AY>' M90/ 7N;-JN>6UU W^^&%31F;7:FY8#VGRH*+"71#E'FR8"J&G" 2MD-J##@I M"H>7VS.3V.W.R;9/J! MO&V*8&?+YVX%'AI>!P=034A2SQZ4-HZI*E 799(N$SJZ)VEX?6C)[<&'/;QA M%BI*F7]VF:]KKJ\ZZ&9+VPC^ZIL9NP',[)=>O# !O)@BTU4DN#WWG8<(28F- MC:]AU2@P4KD0PMWLOL+0;[%)D5%#F.Z;W7[,;A#8.>_;9Y])\(,W*L1QV=+QVJ=$L]MJHBHVCLO#]08MO_@V0#9K,FQX,C-]561EMV\VE?QL!?@;#>P MSB9*$K"KPC'Q!ZI/V$;9G&%3T($,FTT5-\6A%ZDL6SF9;.31,9,#"IF[%ZF>JMX=.6UI,NK7EQ69Y=+=EM.)I;7H6VUF; M8P28LL=3,DKF!N)/*]Q"@:K[4,NP66Y6][!8.U]F"%B5& #>AUIUU;KVG?% MCEEGWEF-XXV5#=(OW_KSWSU<_W#^=HW+W_Q/__B;7[17[W[WZ-._6'^Y_O2KA_67@3^Y MWC^^^/CZW=O[Q_2_GO !?+WSQ<[[[_X_O7WWS[ M\>%OK__@JXZ']MWC^]?GBS<-OWKU\_?CQC[]\>&AO MWCS\VC_Y\/#KQP^/[W__^.J7"R3BX=7KEQ\??N=(EZ\'5X]?+5[]ZQZ<],I;_R\/Z*Z/Z M^9N/']Z\^=6+[WS[.5%_\?L7W[U^\\?/KWCWW?<_?'Q\__ /[UX]OG_[\Y?^ MM\=/@SO?O?F+C_G[CR_>O'[9WG[SYO$A?'KJ]8?Q^@^/K_[Q]<>7WSY\_>+- MA\?Y_./;5S\? M,V!_#5Y[6' M?PF_!-#P0O[?3S_]]Y]]2G_[\MVKUV\QAFU_>/'^_8L_+E@%C[:'']>'UV]? M/?[AX?$/#/6K7[Y]]Y$_>6 N_O3P];OWB^L(U7SXZG]Y\=UW+WS^\U/QX:O[ M\[5\^>VAZ]^^_K9X_WAJW]\_OAX^.HW MK[_YXL/*PU?_]?L/K]]@14]/5O[NVV=_> 2>^/#\"0;TG[][_.;9.QT,Z.NO MGSUF,%\__Q,&\_6;9X\/7__\!<4GGK^"8;QZ]_'-XX?G'UW"GY_]/Y\]RSQ^ M\_[%[Q^?/<4\OGB)Y3U[BF&_?/'^^7 MO/CP[;/G&'_KSQX[Y\\?,_+__/._8>@??OC^^_?,SK-G&?RKUX\\^?KIV? 7 MAO=SLXL_-[KT%R:7OS"X[0MSVW]N;,=?FEKYTM#JS\PL_(65K5\:6?S2QM*7 M)I9_9F';SPQL_VOV=?Q5\_H+ZZH_-RZBP<]L*ZX_-ZT8_\*R8OJ98<7\EW85 MM[]J5G'_PJKB\851Q?(7-A7K%R:5PA<6E=:_,*@4_XH])8:,3WOSXKNGIQCT MO_WP[N,CX_L4;/[\&X;^]H?O?F>D^N;I:ZGW&^/^^.W[QV>OT-K?_? T8YOV_OJ9?6T,]P.1 MZ\^/=0<8X--8B5)?/7XQ$1M#??OZ^4"*W_GY+MVJ;_/=ZR^?W<-/9O#JW;\_ M>YIQ/_[;#R^>]ID![=]^>/P@A/KRI>GI%T]/\AU>/ W/F-:>'C'\\^D10[^> M'C'N^^D18WXR;0/8>'IDT'UZQ/#^UZ='C.GOGQXQF/_MZ1%C^=^?'C&6__3T MB+'\P],CQO*KIT>,Y3\_^3R#Z=,CQO)?GAXQEE\_/6(LOWEZQ%C^Z>D18_FO M3X\8RS\_/6(L_^WI$6/Y[=,CQO)_/#EXR-KU\_?[E#]]]_>;QR1X-3SC7%R^_V.2&I_GV7[XW7^)IVU6^ MQ.^>'O$E7CX+$T*"9P^UP&[90T;U_;.';H5G#QG5^V M,JH?GCUD5+]_]I!1_?NSB,FH_O#L(:/ZX[.'C.I_/'NHIW_[Z@N(87QZ_.YG MS^D4?WC[S8OW/WSWYL4/S\9FB/KX^LVK9^MAF/H+-+(:K?X2N>AC/GS_XN6G M/_]+@'^>[_[PXR_P@[^(^$LSY-FDX4]?OO"_OGV-E_G[&Q<;O/N;S[[\X3TQ MX>-D5'S%GQY__1JJ\?CXA\>7RU+/>IEQ'M9M>#09S[%Y&'*%>XO1C([KOG<[ MXIYWVQ1=35.8:;4);ADAG/L5+%0X]K84):S.C3^_9Q.-SL_%?.02BWIOQ;YV M?28QA:IQ%;R_W7K8S(P8-B U^53-_?6R(T9=SGV<=AD]^MEM>]^NS5;CW<2U M*>[5NJJP(9E]MN7M./)9HPD#VQ@[O]@M!U';>6N+1=9'/4.*:SKNW2;1J5AX MLUFE&&\;EUBEE\MNU53PZ)&A*A%TK2,?BM@-KVR8[N5BEN)>Z\;'_ M,T\T8V9@6_30_6HL2U:5+7F7K0;566NUM9KM#BWKW<]%G<68AO=KGDOF:(JS M"5G[I5132=7SW:I+Z<3JR*>1K[TKI74U>_[+93 MU'#VHF$=>[ ;T.Y!;]T]CZ];7\^SV"0Y>$C=+$:M[+3MB*&P#\*Y,+S>AZ:Y M6>E4;+*6:KZ/&NON"?UYFS1W[LRM-Z&UVK>@;_G:K"$_W1Q*>WI5LQS3($TT M.THY%&WRG+WONSU 1IPM/W_/$93^3?5%[[/14 M7$7Z153W0F[^J\24UA%-4=6"&;)>^6"#.O=DBH3'NR@05>8[4U MR1F#Y3*#60G>FIL/>;"[O:QE8L:4LCPR[Y7VU(HGPU MS:NDLZY%S8-XA&O+=EXR6RG:=<\.EV;TQ7V-I_J05RGSH';P6@(QVU_5RFWQ M]LEN9^VLQWYL%GN:Z!1W2^_XP7*%*T9U.]P!>:;\F5*>!IYF\Z[+FH45P\F+ MI^/US.RGJ.;M?:5<]['?MH3/>;5XI:PJ5YYL\RTZ6X<-PXZLG.88Q[!RCC=A M&9?F,?HY9@=&$Q\2'Z-ZCIJE<:A0:]._9$/!,+NYFO/;QUE'.>RQ&^MB']W>?!AQO;M-+V\+4(?Y<7BN3776;NF]R<.VD;)[3#QO M97V8T;80P KH9E\5U\9T!I$4+VSM4.U*S>)K9Y']P438*0D+(KJ="K+UV.JZ M6[15S8=K2V)UB4PQ'MB@:6+XO6HOFLO,(V5'MWHUI577T.RL@*]8&2B?L,T* M)KPW1K::6;ED&\WGW+#N$FJT>OXD\':,;>"YL;"[G>Q\E5[=ID MR^O&C)]&5%L3\4[;;7>K[5(28R5.YVCKJ:;1'*?F,JI=,G:K15AJC"&9*1^2 MG6KNR!ZPRQ"^=;F=)0P1-]I,9U0<<5/D3=V3;#&GBA!YMY%4W4T0B?L9+_52 M6!O5S0E(LR[]ZHLJ65>R0#3:@8576YBKY(!U>GMF_J)Z*+8W/*V'5#+JNF_)?@ZE-:NKO4P9D ML\&WFG;92ZN9JU330K1-O*%-$T^LS?O^>+=D:5,PQ_:X+/8P:21D6P_GRW[? MN1#EBGTY; #,;/!-UG.Y9I^.TSI?&P@5Y<9M#[9/20& *"X4Z'36?0HD*FLU M\QO*V!J!1TD&KW\C4.M8_#Q5FXK#/%9[D MUY>=MF8)><[89$\9_+:TTNPYK9+HOO&\&?:EQF-VRJN*>-WVN68]XW6S67TE MT>$8\UHW%'PBWMT2W?N:$K[>0U=%(-@*P!4K8.QK8045((:)[FNXS( ZIB*< M63W7.4!5Q(L!V5+AJ)73WITXIA%9%;6T,&Q^)IJUL:]'&.8UJ_F8KAIG+.K" MNFPA=5=3_M= MFO5EF7C )]F#H.!(C&TXR:6?C$>IA<9<;\KWY:/= "^"XF$3S9[M18"CWF9= M;S/K7@R6;PL]:E3]Q>"$NU_:&FX;3]NBZC[541MXVDW)YRUC@+:;6.$6O?=B MG=GL6<[6W+>,';KP^\,;J_+Q94I#X(R( MR[NJ>.;' +PD+(KM;;,_8V83!I@P^WY*T:ELIF C; +W;#-K^L[E$<1+?? MXA16;*?]#&-3!Y3="4%K%MV>O!GCA&[M]J'!7/'1>57,VQK()'/W3D M4T]_528:I+-O"JL23Y=N,G:<^31 2TLCSC&[[JJFZ[[&T>(2JPKR M%9LES@\5J7!4MP4BN"X\\:FBFBI:0E3S^X@D)DD&.W7PUA8> MB8>9L4UY/3RIZI%V\60=TFX=^B(ZS(K9$0$AS-46 0H>GJJAAF,F+O)IE\K5 MT6S4DW?9CF$K;$B*F A;.6Q%(Q'+BA"X*=?1;_LR*)M<#_%IR# M;478'&?WR <+=@&8IC=V>0Y:P\A4^"2P"*3<5)X@PM\ZVZ<*$ MT]6.(M<^3M.?+I&GB7:8"DS8_LC5:B/UO3$"E83<@ 7 .#7UV>3-8H <[+!( MV+6?ZV:?PQ/B:;8;/DKNO52@V4)W%(O?=]L?L "=-Z^J8]2LQAEX^[0Q-[#-WB40 M79MQPJC,_>RN+CRD#2N*V37+9@=)%LVB&)55^VF+SY/@K>(4O.PBJH7-M%;> M&KPCZ\)6P3V$JV!;^=N*^GQ/MXU3N"$P.)9N>G&4SV)LC;=4B3:Q!X;8+R)$3+$-I!?P.-DLD-LG+ M @==G2IQN(1#Z6%5E^0A_$%F LU1I(6WWB9G;% 50PR29; A(8S[BW M:_:;A^>ID7\5HSY^ECAQ\MZCM65E65N?_;*FG0G\0V!!-;%>QVKPQ%I/U M8$-]&C8^&G]8+?/(MAS,%E]:*:)TS^R_#498DQFS)Y")Z%& I;:7GQNDU0'A M]R32)M15=2>&DEBR&]^K3 W.A-4$Q!:[X-JQR2X;3;&\9$86$2_;,7!LG@EF M>1PC9>EA>:SK:OJ9$K;KL=Y*U)D^:^(E1#'JTB'$,1^?BCJBG4^(F-(0P;&G M90?T<.N7DK3%U.7438LC ,!U^V*,/F[KAIA5W(*"_%#9NV73#)E[AI^F#S,ZI M[F@@Y%3[,6KL58-;/=^RS\PVEF2;!LO7]J$&&0 77V%';Z#Q;)K")]NDHJO] MI!:W!<:LYU"*:+/FTZ.-=1\]9)BPI[T62&_8DBMVDCAO2$^R"@*(G QA+!_1EB!,9 XVHU/73MP-B&)MF+G#PHJI/:53AQ6X M7\LE]+BV78WGT^X9Q6,BM7CVY3+;EW4$H6HV0!C&H$($P)F]:.FD;;&9!-5L M&C2F*\[659G=;3:G KAJ"YDWLRV7Z<;\U>814$D@^=T]<=E0\E#WM@/$S@;[ MNE69=/9-XKRL-]L]&+8-+GPTF'"Y$Y@WZQ?9@\5D8[M$@KY43NP$!/E[S;NM MYJ*!;#-A\09=S(*S "S7J@)O=IKVR\J8FPYLG;4P; 18MMKW9GG#KP/0=C:B MX)VJ'<]G!_6Y^U0X =X<6-:Y$%9-* ZS3Z='X_@63+,0)V*Z;734+?[TTB!8 M.]_Z;.9]L V&U9&'O32V;CWIM:BWCW%@B<1H.##LO.+= >&[.-R2Z83-S)Q/ M_GNYK?*TY,-$?IM2X0[A=#"_A94+ZH#4F8.KT!=[&$R4UD+TU_=<:JMC_&PT M9:%VQI=LM<8@K, %JC-!4&0)_Z&Z457O'(\!^ ?%XS#*JB:JXJNX:>L8@[J- M=N+&;*O9V.;ZV_(>HP0'L4=[77BGJ*TJ4&*Q3[*8J8H8+!8*RI^ONV?-RGV> MPV.F"\AFHC!<*V<%>]8;P>4INW6AUJIBF)9K MLSQ<$FBBV9=LMX%9DY#YOQZ9\9H P= MU&$&/=S.4TL)QZSE(7Y!$;>I[8TT:LH MJ#D!>!VSJ\X6\Z")3S@]WH =&U*[@T)OQ99CP;)W]T95S:)T+S=L M[[(&#V44(IHUOL'3^)4WVQ-_>31@(SM*A9$I[I2RES&JK[$^X'^V.SX:!!KL MF'99+1MMYPFCN90CLC"N+HI;VXP[W87]FG8?WA[V'_8(OB5,!_QH:U@B_,K^ MQ$4IMZ*>-3;OK67F?PK,<#A M#2L'DX*!K6*(&&R96H3K[%ZK>J[2IZHL5SNKIGDQ=*@YMHK$;-WMK4EG4=5I MM^>3QQ:GGV6SJ'L*N^_KH@A\3P-\ 17?;6 $1)T=16T9;$42"-)3#>,D88FA ML*;>R4#M0,KMGM!"<;YCL:$>@QHV-2?*)Q.N51*]8.B>T++5E$'.MKDSZU_A M0BQSQT2:8G)#A1H\ETU/EU0LE .@*H=Y$7?R*#-='1^N[=F8:U5"%]I_WAXV M*9.?@:WK3'T/MM0";&&6<1XL>4!GYT1V+&[7QCY$3U/$>[PU&%LM@/N#6@)$ M9+8:!!=/;Z-FG?#9Y=];7FS#LC2%H@?+ 3+8'1H MSEJV-H)U9. W&Y:_;!7NE&7L:FTVU:"K(A9,[^84MZX:GNUK+]C#H?\8;"J@ M;/'8M5;OHXR!2L,7Z,[ '*=F_-HZC GI.XVF*DRZ>:S)P,3V^+3+:Q7J"/> M:F4IHE:*K6CQZA9\++-#N(?GGBJD;@ 5JM"=]L\&/Y]3C%9Y5_XVGDEBJHU MRA+;=59)K"QD+6&_EZ%:J&IA++T>]6R< CVA5* :<5(>77:+HM6+$UB,-YDWO#N MRV;M0&'+C*Q\@M2O?5&?=;53#V%- 8UM:V/-Q#);!MA3#N@<[(#%"JG1+%I_:S) M92UPEU94,6%$@DZX'?=8U/*J^&.;D*D40N 'V!2B@F?:0R4J E#W)/,LL[<(GA9P M:.4R?V])+H^"MZ[>N*]IP01XEN7;UTF4O&*8?38E#J%;L .?9WA!R5K;WT+\ M;3B:9[-TB\AN=5MO]N-B&\X#1ZV754_!-MN7;4_M0]R]M8"X8- 8%+;9IZ.S M,SS.#P<"(X1YV+E'S;L%/NMWLNV+UT<@5L]5IC"TETR8;K(2DIT!@YWM=H?N M)P(&E5MC.6UR"# Z^[VH;;V[FZ)JE^L-B5-S7$G[9N..%<9UX\\W>(,]'@ED MA]TT\ X!JB&05UG)GN9]R4K[LQ65-/) !K?^M3(HW&\T]8)<2 MMQRLQ!9"@-JNXU647)$;N[S8O[?W>-EU T=H,],S3CTL?%WV/,>38L_OLA"G M[V4'1P!06=QW5)CH,&>X)84U51='#/A,)OXPC MLJ^I[>O97/56A?:ZS'@!T.)STKTH)^3W(:X&-BC(V]YGLPK-!I,GL0L7I[H5 M#-3C^#%F:P=^:^PA@/TPYOUO62Q>0#P4D@%J1$,Y<;P1_7HDW)MAY8S65 M"%0BP2!FA6,UUV>H'K4#/L2.Y[&P,(3DU4Z6UK >L!Z]YECY>JS>:2M&&X8E MVZ)Y,1KG_4X('N]ZLST4/+,5F.1UFWJ3-CYSV0'5IV?.A\H]:KPPC\=!.%7K M)PAR/"0NJ[=.0AP @-?NP^8Z'F F[X@\!@^V1?>JCF"(F0'M<$FJ/9D\9:7S M[CFK- $:! KT0!389%:&VOHL@%I MDBN]Y39EC';=!Z YC%SMPXXV581ZQA@ MQ-OK=B!R;\JI@X0 MU I)797Z\L4V?5.0O$F\-!,C<''V<:UG*N]B)G!,D6Z M]U,[]ES8-([3;C6G5?NW1[5W6]B JOO9;CCA"8,=E]9Y2L.F.17:\!C>8 I< M7XORZ4'!WVHO&SMU51M_V%^B;@M0 7='G+GM2 I(O4'X@:'C;CS_.A0GNKWG MM+<'@W8/>?\&&U'-*P%@"ZY_-"UW%B:#)MC)G3G8\)?X9 MOF(W=!O.0"_O8C?):D^;Y+%M4!5UWQ=E;\:8G8OQR;UZA* 3G&6F5_1$;71( MDM1U'0H\@G_/S$^X;HS* MJN':/9H/$%B00(._-#4< )O6JB>CY,+'$^K7Q">9=E%!2(D0KGA%5E/^VJ_A M!=A)]/&<_0[@'K.<5+=5L.=4G70>),.$+_/0#E<8IG9*<*&"MIJ7X]R>=E=E M0%>[AJ^ZI!S-AU"%R):G4\B:3\$&YT;7J.TO'D'GQ[@\G03LDNL^:%:%[ZC> S;I<:;FJ0A MSL;TX5,7UG%!'.R7O'I3!+%5P':YO(=B$O5U\$#;R63U9Y-R^@=Z^^]WACUG.OJ*=%X+*\-GFWH/@[8=',R>P] M=CYO:^L5%K)9#LS-<_ID32ES;CLGU;J+ H!5M;],",52E*#B(=#:$OFUJW./ MNV^SY\!IC7KPF!X,;G['876^F7%$WAG^/.&RM> U54B5:)I'?2?<%@AR6Q); M<*-1T:Z0/(;QW$#/NYD'062TM[IM+;-ZX[88/TSVL._=Y4TB4;P"K)3&LA&J M/>@(5TTQJ]%"GJH3V6ZQ]J-FSG!)F(.=IA0H,B*HA145X@,6'C8N[%5]?Y,' MV4TV55J+;>H @<;C[ETH>R%<<2$B*%) B.L5N(4!*AFRJ^Y!H/9,&T;9%4;8 MNU?C98HY>\6?3V;"6^MB!A#(DHU^1U4,,64B2R"@\C(/2X.->.Z$-[SM==U$ M"!;CPRB(2KBJ>5R.%S!3@F$J1[^8"Z"VU^SR!)O/U0N--CRSTN<&Y=G:O./' M^B 0%MP-M:R\DW,*HB'EP)8T[[8U68H?HDAX,V\\6;3!^5(FCF4]OMF@%9Z MFZ>JW&1I)C=<@X]7DH"/T7Y*)VY>BKR:Q\?:>\7)]@P8;1JYFC_6 M9_7VI2*BV4. BJZ$1/**VC/8L"XWG#*HTVR**-Y]M16$UW2A 3X3J#]Y@0Q@ MN=2)2#!SX!]0;U?B694)Q>C7V7%M88 8]WEX/W<%E:UL5,12,E_F>9[VGSJ4 M@P5Q[VKPABF-MB6[502\ @[?&T%(A$K%'@L!)3;_-MD%\O08U528P"AL3@CE M$)39O,_K4HDU*,&S=8*:O7+!.3C0I?%UB*>V[LFAJ-[I(3/?A6^G0&X"0QY5 M]?S+3G:KFCOF/@V[,+$^U4RSZIECQ 4-$Q@QRAMBSX16A8BJ*3][Z?8[5D!3 M_H!=XU8 E#68SF2CLM6S>>CK9>OKS01 _[UFEZ:,C5\>SJYXL+JK)&!&(_') M/$3[&4RE\F(').!=%!@"$80/W0.1LGA)""B[P^6YOJUOQ-5VDL3OZXIN #P8 M!T"B\B6,Z3)J9%.<"':8V.Z)1;+C\^*54_ FN*GL$IMGLKM7%7SI--B=:76W MM[H-MV7L^^5KL\G13/XA\VP%1@(P6(*GW;9?\C *K!5L\P&R!-WE^S;SIJBN M9+P9-L@+XS+9X$K""HP&]B'#M%%-7^Q.>7JVF"\;FP).QNZ!%J$#1E.N.JE_ M43, _VIV$'\-3;Z!,C8$O93^V%@RO"$\H*K2('YF+B4AQ4W 8@S8F]>F.M=J MNHOF&[WDSH*0H#X6!%'I N\::[]L!CUL6W0["P5DQ MLUDU=J#>-97^7<7"A"B!9\O'HEX;8,^F@Q5'),6?FJ4K5.PB?,#@"4W56ZE[ M;:"= E]31&;UBL/F"]7V'C C6Y(S*>>2=]OQ3,EZ]J!IJ3:^W&>FSA5,N;Y, M]"G0,7RVLG9\>Z\5?,&% M.*6\3FXR#UM4MFN&>%L],U++$#P?+'51C+6*+VSHP6Z#$T6[*#4UJ[)-W=?= M&[D;CQI,UNMC]GBT:Y59IZ!MV^)[] P&5G(G7>3[1/\A$WE MF>MZ>4%Q7HJHJHK:B&Z0$5MJXJB!O39/6#:Y.D26B#Z/!.QB=]C^S)M;15+M M9@SHO8/*P&![0F-17-)D5M"D"K8XH:I:W'+6%$"J^FN347!V!%!%]$ ((!KF MS1.!766AK$B0^ Y38S1V?)>=#-4]<=&7ZC1X%2;)?"4K16Y;.>-BBDW0UO58 MP2H1!+=BLU: L.)>.9HRP-XY#,RGBF2,>%OL0I)/7,K,I[#)6DM,2U< ";14 MS;K;JL*34]1;>:%ZV*@1V^<= /,[))+G]ZWQ9B45<]*:F9D]FSYYSO;7#'86 M+[!#U($VFMMK*,MZ+MG6;) Z)?6 P6R*?)!P^SO3>O(\[[$:5Q#/# MU@*0M& BHCD$V7H";3]OBJ0SO3&IZ0T>WAED05;=AJV4#!V'^ M5@H8/PD>-\M, 6T[/UL=8/\J8IIJ4:?7U(M'%K"VC8B,I0+W;1YHEXP\;[7T M0P,#L#Y(W=_#CI;#O+QZ.>]$)<&\*:SGL>"R3W/5H#H!NSI5T[++TF8:Y+'[ MV?- E1W)8/E$8SOODPB0=D@!XUA2.TP;!B&7A>B:J03Q6,VH4 M2F?96"WO@)E7D]Q7U0K-BF:S:]'BD6,4VU2#8'GQN2N[&?3$5@!X0:?O5^5R MX OLQMZ]WCT5:_4DSB8 >'Q\(>]V1J+$_VQ&;G8VYK':E7K5;YRV]X:N MK1;)V-$BF%8ZM:TPS]E=+GB+:WLP$YJM%/ T,W6S-O$*!RPRG.9#[H>=YC:^ M]W:HI5JLO#)IRDP5T + "VX7B8S1^JLTFUH*Y&J?7:#4^9?QV&,2;W!-)F9* MI-JS@^!N>DXZ8FV>=-DP9Y.>>R?/>RSQ+.9 !^]M32ZRE&/'4B=XN C9%^2" MT!O9$[!*<+0GTRSB./IAT-GM=6Z_3:*3M4+VOMOLL@<4K,$VA0S^ 6 MP&G<]E);"9\9#\?K9[L*4T*"TH8V]2C#5AYGW?+,89BJU* PO%JX5-*R+3I^ M+ZL_JJ9MT8_VE?4*!IA]8#>093P@IC& GA9!@'^O.NLT]NO360C3,8N>;&!^ MXVQ/,P>83J-GJ'>=/6/-M[9:BA4->=EODT),,Y\;G?@8[0WDO2T4%S@6; D* MC7>DM^5%9@!80N$9>56]=P"Z#ICIOMC$PZQ,\\,/587-40*&;LH"6T. ^V=I M[YXG'07!XKD.;TO3)Z*,RV2;>$^_+B-U.(0WNB:%W][,,H7W#:U9X;X>^[!B MER>PWDLQ6[99NA7@RWX M>?&L'$2R>?Z(/UMM7#V++()72^KBFE'.0 EN-Q/=Q-U7MGVJ-ZRK3:+8G, U MS,IS)R(TGV0-"A0$!@S3LPW"J(25K!ZPB8OVC#R$3-$S4?N-F;[GG>SJF1UH MNM]@*#O2,J+I)YO%2:K/-6\\V^UMU+5X_'4K2>QAKZDSMA'%MF!:MOCA=\G+ M,$+5]BESA9& Q@BB'H]5$YX "U@V4&=9;2";/)W%)[$#@9_V0Y)S9OWU(20X M5-O&!ECV@:/>;3UT;@QJ%Q8!+LV>V(Y%&?YC5OA(4G'YA\V+0.4 K),]Z;7# M4&G>GF[8N=G#S&&Q\ GD;(\!"&&]#]4#/6DT/L&+/]4E!%7O3&WV7G"[@<&[ MBJQWA--"R&]S\3RJLLI3WE*E;O#WDVRD#'<'Y(=O6'H>'YP&H$&K, MR<.55%4R1\1'@$=L(V&A#:M)$)<7"^O#XOE\4XB<&!\4U?5@<8OV0L)[0GA$ MZ#8=/F;?X3R"[;-M?='V("%E:N]D[<=%#"A6?7JU:$F.)^KFXIPF>?#N8DA; M2+G_H<$;@ O"8<4K&VR7*RIFV-(?&AIJ]DBK!ZDD"K3V7 M8;P-*[9&3TE-3,1WJGIR;)]PLUIBN=S>%%2]&'3I, /5$^S:X1510NRY&O, MI[&>P.1;C8(=S?J&/2@@7OFN39G$17G^51'\75>/U_*;VOD12-V )!8%@*?% M+CO[GOFYHNK9-I"^IXJHU6 >%S.$FWV8K\?*W!)0-OP1.#&X\&,VP2;SM2U=GNK>0!B5"4R M!@_>6Q8,@7]PW-'ZGLM2 _R9C;(/YKXLAZ+NBGC6XC6$V^Z871ML"VF7579R MKJMG3.=A;K>V*ZDZ9G-5B1;1GM9:XXK\=!? MPX][- 7<+CEG;NI.$W(-85 ;3]OW>_%D1YUI0+:)ZZN=PF=G*!Z6FYE8#,1+C9CL7>T\49=_7127<>_:,MZDS@?.T(18>%JYMF_%H$WF\ MUKZS!ZU;Q\BQ9HORS1I?X;%]PP_ 48Y%M%ALRKM[4W";3-2K1SBV!KF9-X5< M]9.GS15A:H2'RU:NJL'J1Q4Y!8$DH-$"G_:0,:DYFC<+W$]EK0G%Q#>P/Y$ 8.6;P#T6J)UM-JM7V*#5EIL5M<0^17MMCM7@ M^J-+.$ZEBT_;W35S'O/G=&"6?#9ZJ68LP0:P_=V;]>P%BS':NV)6UH6EFH. >[$H^K!/BH7/LXFZI;UL3SZI MU(*K/\8NGNK&4ZA+/XFB4.[69Q-&N\ O\'9<%8LB]K(/T&'O0 9HWSS@SVW* M"!P W[$9?&P?I$XVG+-VN0N82:5A/&EE!^!7<&$8$5O1%$9KICS1$1K"S-SV>1YA;18^3#S-';[8@=PS(;) MMK3#A%7&[HKRVV@\-GMSGJO=1[P?,X<+![I4 \5VRSV('&RJ9-=[8OB>-Q7< MK5:H9C]:.:;G <%NUI-G"-UZF@()ZQCBL+I@;,-FP98J#)MH7LZ)[8:[:6G6 M,F R^+C;ZD.!PF61_Z52@EVS<)95R6,&8 KL '^P,91C ,2.<'X>!TV:VD> M:&!LL[D-J!+(YI7G5!_@RWJ.8"[K%NR!M<_N: 5L:EF1V>_F&]P6=S/1, K, MR^!O"\D]3< UE)' I9L3%]ENJ]T//'G:N_UG5,@&KHCOSZOLN!N\?L+[JKK: M34,CUBN-+T^RDZ]IKRZ"K-/J3V6X\4CKMJRFO-HF))O1"BE@*'9_QW]Y"N5) M7B$RJD=^F_->5;TWGM_!R1Z\6N]TV5M\(; WF8FAS;N%:Z_>Y@E;(Q!R6%KE M=?A(?#_@U(VKM$#2U!8I+@9LLA??:$\+IF\B>U& H-I\RU,=VR[@?S6TY(D4 ML0U(BP^_!R9V)P\)XV9+)^RVV'?G$LTLJK0?YP5-P5]ZP0VF96N.#1/O.-P M:A<20'V+=69$ [,>)>/1:,X.L"?2;6WQXID@;#MEW0;A?&,*F'OKZHGOUM3/ M/!3BX>51,B9FTYC#O61-TVD6$O18KC063='^F,0^]A?VSN;)]G3:8#^FPEQ0 M!/LPX'V[JO.KM=GRN8;IL6MO+<:Z ]RVYPKP=W,TK$0L\'7(*"B1;[*I1("Q MGM9^$R=QKK/;,,N1K6EG!UB1RS* ,#_B_+X0PF)F+;">=8M$]YM]H $72Y3@"UVY"HNHP&WMB*#>&UBY>FF53'X& M7"2^>B6R=9-&$^3B%?%G<,2/0Z,WH^MIVW\C&X6X0:X-J[+1$4/ M*0B4R60M9F\V-[!J,\>""[5/%V!H'A,V.V1:;[.::S9%([8X^WL;B.0,A$"H MNIS;!I!FQD.O"R_T;M[]6,BX (]!\[4J:6Z%)EX#M,R?U<8>,W')HT_U=_@ZX#L+S9E0 M.] 1T.RF;&+]]:E51Q0]XH"<,:+.N33K#$U\84/9VWF7=-Z6F6XMV^.D% B0 MT]V*6;,-^@LNM3WXO>;K*A-1X9UMFF1.+-8S;-I,O-S 79A4%'2RITU5/'!Q M&@T4P-[V=O.R [KMC @1]N@"[%H]M"T0\+&S:0 !S3#!?C[L^N81!*A)70(_ MRCRF:M=@9KH<:NE#,O%A&L.AE(^+M_3++JV[-T 7+A+T#@H%GU@%Q%X(]JDR M5<^"7!O">ML_>)@ &VHH@922) @8.>\W:U>SRYQ1;8YA+_/5 M23T$9Q'.?-XKGKH!"]D'@"9 O%DIO.D"$K$1 'Y"990#U#3+);P8LEA_GA1L MXH'@G6NWT_#I42'F9:WDP<:]P? L&YGR;HIG\?'8\IG#"K*X@3'P6ZC:JQ*&;SJ>%I33-)%#@*+K9V=!9\KDJ8 M6\YY,ODF72D!#[4ZO)CJ:_%0XB0%L<9WC$W* M@F^>^D=F=PQBX+B5E3_A8QG6E1UPM4":R.P$NXN#?+Q/QREV9W1POV M=Q'UL,8!NP;BS#/K9,,QVTP46P78G)(G@#7,X;N[=!7SILPP:B\=YA9 !/9O%L M^*(H%A&B>L9?U(/G$>&4/4)8NBS2E>F'=;%%O5UTNBUE@GA=]?K;]E7-_6B[ M.*MSL8=\>Y.2&+SIH!Y<>G^N)2G'@G=?%/W*WO)>W=[,A/ ^RR4[([QM7=^L MDER!-831+DXK-_RAC0P>*1[H^H$@X=.$9C7\F<7;+A\CFOEF:8R$(]9MS)Y2 M^Q:!U83RE85I\[IRLR\P:-M-@S7DAM/ES6!01RJW=8L9Z$@XLJP?%L;^6L>] M6\*:O0,_S9]G'@&EE@5B$KM-P/V_F8MUC64XPP2K=1C//92%HMY@R/VP5@A7 M.J77-OLI@>;Y]M_="79?37N6S\MO;*:MWX&BVZ\6!#2O' M3#3*)O196!)L:#AP"7;8O@,OL$%/Q >RP?N2@+K@O6);,?:!(+A[22K$B)N< MRU&"YN'5,>WVM/5X*[&5K$ L(5QG.3T:LB6Z M*P:V(##9B5%M&N/H9G5T2)X0L+ VSH8U+38)M62)>;( %>LT!2(#DZSY)IBH M/V-Q=^,W6[%5%U3#DU/O#:>\A!WDF-PM2JL]"8LV0SG U;>";":_V2W"-N_7 M>=CP[62SZWP/=KRER\2\8)L=V(1-*"HN*R^$R15#Z5:GF@UVFTK1;&@L',39 M>;#M#=KL[UUY>_LL=KLH;+9'@78SDHFLIC M-LZTWLC3_&VS")OPEK/)TT4I%S4@*J9S+LJLV1DG3],NEH![([S+5C9!&2@. MW'K7NYF5).B)+IVGLQZV\;[;&M(!\\YX6C84?E%5-R"]^=J';3C8P.?:1.RX MF*)GA:P)RX)]6H2&Y<07U-.T_2.M=DQ;<-@SJ]\T\MD=XY[=2DRD8!"S:3/A MY,#=*HEG"]#8=$,5(\I6"XG/=W'Y=B\7GF$0<%*P "T 48&'V:R-!M:R$+ZI M8L?75,D&[]ZA*L3ES?)E90SQ&O$RF\J.99M1?5.BFV@2?8 MNW(R8^1T- 5H9L-22Z2]&FW"5YMY@[;9:M@6YL2$Y&"5VN%1A9HZ,'0 MQ1.X:AKPS8Q'\3_C51COT*6F:/_#.A;^6+=O10< ,MK(M]G01G^#I9F2S03% M&U)/0"YF<^L!BX5V^W:H)*)."?'N*(M'JOE2DP)/U1CWJ=3 FF;>T#'OK9D> M(;W=93'-'G@S,#VT;?/VX;*_ZX7S;=X[;2?\"=ZTE[)N=IY?#[#@I4JG0."$ M[8@EV=O9XBB(]-B>^%(/<9G/0'6IQ+GQK;#$!((;463V(H9>\!!]*)"H5 M!H=4_.3*&U:9K"R!P7HTL>IK@3.F^Y]Y.:ZI06 5Z0;JM'PASDRMQ 1%[Y?, M\['V^K3&$O9^79(?,'4TI\A\8=L$@1'Z0I3%'IJAQMM!3//NPTY%5F"IXI+: M81!A$DSJP1-U;]Z[7"R7'#UO CX0I>*ZX#!.TYDM>.FVT&GV;2+@P0C5L=H\ M974==N4TZBSV4R5'M4'S?O %1^_LEG6$A7@9[(K)BYI9"[OWK7:!4O/"C [O M$%:F7,])1$AW-M[:GK%,]8BTVI]040_0MHFD4H960.SVU,+UFSHYUKYV8I( MQ*L3<[!ML@H$,I')U,LF,H8.6,^3"4*+E?"PS*UZ_C9/%ZYCP[>PGG^"+\X^FW4E,PXA/$K.P8ILS0T1(\"M>U.:Q08Y4#_^#/Q=;!7$$'9# MSE^MYG:5D>:9QO18\68EM/.0$GM4)OHVM(S@.:\*/$&ZHA* M-6SV.4KV)I+9V_:F6_<5@'PKL>P^A@LSNW2S MO9NQJBE/>F(*N(E;5G7#DQNQZ8JS2GOOFTTWV>C-K#,/O*PQ)[[CX-M0!P]2 MLGE4L]\JA_+O%JV=C,%U.CW=916QHU)A/L&ZDL7:-U,[+P]OB/\LSK:NG6VR MC3VD65A_9GMO>N&=@1NJR^+JB&CG5(\]9UT?4V\CT"XNJW;\PC79B75*LS39 M@$5/,#PV,;C:)$^P!HODI>>5DN7$(!;]:L3#6"2]MF?":&%KQ"=U0QGN/GO;LF.#4CHVP@-_ MJ#,*P#2%;1.DW 4_;.[ M.5K/J#))ODQY*;PVW/!9 MU*V.!TBLJ=,WK.HR0TLO$] M7C>[^)X50-"I'>IO'7B=#8V)"(J;P9/L8)S3,IO;P3:=YZB^:A1<71)0//1I M9"II-GSDNS9 V[PF5$<%WW[7B\%L/5FWQW:R.:X2#L,]/%T$:*-4&;K0KA6/=*G9VAGGM[\4 DV[#]U+L[HION(!G MA(H&QTOX\_O>VWH1K#;O.B-#\$I:3]E/.W3BMOGVL3?/A @35LD01@%PS>:Q M*O1@?V)!XJDI57$VU]N]FL\8-7SKG.W.WK8KB796_X"'^@.U.%0R<)LD1U'(=97+$"1UMD/)LA0\)X]:TP4&LO 6"L"(.J$' M'TP<+O ^0&Y>*V (6_1L.C$T NIIQG&>H5DFEQY:4TDA4!P?M>8O^19M/>2P 8KB68E+L::WDI.P'HY=&C M/0P;@+*HW3V".5R$)%[ ;H21QF(*(=@'_]Q42-W.43I!V&Z!WI:IJCP;BQO+ M@*IXF\A(O*S/<[LH_YT$\DP K19?HO!05I8#[1 R$X*9+M21O?H : M6=WTLM>ILV>VC,U;C"+F:@V>_ M1&+VU6?JMA)E.(T@.LNRN'A$=+MUAO;5.X?CE-4ZD9#A"/Z,U2A[]!I:)T M"ZA'1"VVH\9Y*5MWV6#0<-7M>&G7VRLK6%0UQN7P3- J,<\ #]/O+[.\O1RV M_$2=E*FKEXD*V+Z)3!$7R/CP/3C(:L4D_HD7U^7J9FN \TSDB!#"VLR')NBR M+5AO?.^A%"L!Z_;T3&7N;FCLL^?EK;B$MZ\7EKZDT54 P RJ94C\:[Y*+HD) MQ#M7TPN!'O82L)*T#AVRQU 63# ($*H9#:M9G0M\4&Q[V/E\5J7W;B+\,/T2 M_H/?27;>]!091$I$59R93X;.Y\OX3H12UQ);6Y1S:V/ED; ZDR*LU7TF;.*0+Q;LS:A>.#+ MHC/ Z+5*\LQ=>0Z%294M[4#76!)-@-^(\CZ5/L+J)AJ BW*UGZ>L%I\,57]B!<.!/Y+; DBK@G*WR?-KF1=[ M;(E#-SUN SC;=GBL# H2+MLD%9BR*W>T>.4&_6P>5-DYW>2:.HO(1:75T@ S M-'9U%C7'>3[19UN*W:3>F XC* &L6"4YL$L"Y\JXU1SQO@.7$:T LM #E[YY MDD84-6_%&(U?(IQ5?0*N1M+3"-PUV7-AY5,2'-F$1(O*-F*?P1@(OE[*@00+ MO@Y+8MF(U=*TT$Q-4,OQ%O/O\Y*^X()@P01-.)(ZSN[M=5VGBHF:R0-*P[R9 M?0DY5D%*P9C=TY(^;YWS87UGG'INR^4MO/HGIH0!E>P'H3#AO##+7B;N03UA MMK*'\8=M#)(';DK;,3W1FC'+#R]JSJ] P<;*'TDI6H%62_$*S/ )V]U>8KD[J ' '$P#3QDMG0 #7+ M7M5C<%@6.J6C>+>XS@./556K@Z\);%G#$ ^67IH"VG3BWH"QN&# M9@&KNMF!7;Q5SZOL:;ZJ6F4R%=Y_*:H4[&",C'&O%WAFG46(T42S8GJCLBAL M['990]F4_L3+X=VG$A<3G9F9K-8//QNM*2;&E,14SQA*4;_&&4$D3^+A<\U#*IM]J0P0O<%3J!'6L M5J[=*FUYGQ&KHK<#9@IU%?-9"#B=S@-N =EQ M6UKAW95H@E_WP\8Z-HD'MQQLS:QJT)+5A,MFSYJPS/MOU1[8&S.IL#;OAL^) M:P=&0_N.V\OU;;'L9]IME, 4F$N M+$(Q3 )B6-,\4R1!-@K>%P6Y+\,M<[=454*@]\I%$12A+Z9.#@4GO,7S_EHM M 2S7*G?(C$GA9M^JAB8?:Q MB3>'BHK!U$(\F.=?^ M8T_"@@4VW=:LDI49Y][S8Q'JBQN%5/O;!#E3 92# MG7E0 W>9,A(5CI#,&P6+; I+>C1D2:=ZCH2;P'*?1\ K --.SYW.>=Q"L!+E MFKK$R ^OP$605]G'OV1HQNT H15CA!NP4(H(GS(ROJJAL]VOS MA+PV/+U\"D0!+"$JB6WR1U&6NED\@)DL!.FI/[5[8Z0\BQG;R132&ZZ,-18U M_T5#785,0J\*?+82P6T2:I)58N!\CR47Q=SYBRH=L:^.M<< ECP.VUOPA6]O MFE;E&9CNKOQ-"6Y@$RQN"!A?P0[O-T!U\2Z837;JQ\/X*ZL?LQJS5LJ0+9PFMTHB [$APP/9.ECU?"4QQJ:II4 MXQ46$7E')@O56CM)J)#;)<5BI97U:&OF57%B MH)M]6C9&Q>8U"0,'$@[V%J,!-;AW9XY\.Q=L\]SPJVS>"BUE)ID\Q=15GK#; M5[NOPY.^C0$0SR[UV3'NTS.,TWOL];#0"L!8%XW:4H:HD ]S4RPU8#E5E8A% M(KP%>(=]L(9' SA,4*K--J 6?*SEKYC6:K;3D@'$0B/%GRRZFZ'VNBV%)V(4 MP[^GD/RA"03MFFFG%!%L0J<*MP"'3E?9H35N9_:G<,S!A[W.\ M[E+HS;9.9L"PB-9[%'7H[$^O=,?:K%CM!!1@)+9@2Y$[JN[ WK22]K#0$):- M#U;,!.(&ZOX$ZTVZ)IR%F?BSL2*(Q@^5;L-%PS( CS MP<$Z5K?"V!U"G"0%]C<(K)9%J./,UI!GGHOG5;VRRSPZV65'H"/UWA1&\!2\ M2._,X.<=04N$5/ -@V;AS)G#V2A(M#6&O*P"16_^.ZP4/VOYL:4[!]03.&3) MH%K(\+Z*_\ANIGCB(E2MD9RU:SV'8B*0V07BKI!.^8,[N"O*;"JXJ]JC-MA&V\9#;,JDV$,8$R*K-%S.7/"8)IIUG MVQ9DO 0AI*EGR >4U!6ZQ_\'MNU] NXMLH*(=>]?8,B7>O,F%NVS2Q;L2IF] M4XE)DWHW^Z=8C@6:PH_F&WOU/QHD$52N4R "&K@0<@J^J% M><=QRRHCPZ9,P82D LF@Q[9EV&#>!W;=>K_!@,X9;GXUS+$KM@,[&H<\6M+!UT"^.SBE5H##S/W@&YFVP-#)7?9UF:+ M5*\8V"';/!&Q7]X^P&Y\<&,?>)8,0HI'5)EDR;L>2-7$"(S#315>RJ=N5-;T-MP/"39G M$O'%(GJY%V&T5LKOP)+5$\"BD=?KA/-T;?N&VBFVVE2NZ>_T<^O4'&A?K5 M_0OG]=0%3^*FS-=A]91YSQ6<$#P_+#)&E?3RPHO8Y^:H8;X N6*S&CAOWX:M MSS8E([V,U7^KK[AB/_OF,2S1@H .7/#T.ZL. WDE7$E>/7!O;@1E0XO:(7BF MU?)%WE&K#.;UI;"J.^TEPA[MUA>D1"!O^=]"$&I>6R96LRO?, OI;QCK;B[A ME/&!;:VI[P?H5PY >%Y-Y08HV<&P3IF->NW 4&_#36[%CV-+8/=H HXB-.H MS20G!4?3":Y<3<2U@Z:Z<$-U,/S*;-=FZ[BQG'KGR1I +(>]$54A:7>R/-YS M064V06.7C-8"NN(A5U<#.=L*+4Q!.S/#-^_1KTK CY?)?E9MFZ0*6[7N'$QG MFY;- P[ ($%KE[!/-NSK%'-0+QMT'KT^ +@$*:6=0FV2I;0B '5@'TVE U5Z MD@IH-G@9UAV>%@%Y'5'%8%4U MV+%W((@U&W:Q\XH#U@K9A?RH1671FQE\JJC#>QW;/J\,PLV&. MY*$MJ-J.K[8[Y17)?"N/5;$WNRBJG\6.7J:X,A"*C:@@XJH4C.Q*E7O"6/.6 MF^4_53P&D!<[S\"\5 :#_Q,39I&^"D>U+"HE,\W)]&*6#ZY#W"+22+BL:K8P MEB^L0A^1.$E7^%))#ZNYG5Y%IOW 4M*^["9A;PKZ*"=[Y[1NM@G%KF8!\V[5 M*_C7!%^KA.S91:@"\K19.":"LQ#4&VBB4P:( E/9!:"@]?(^#?\RY5/Z?L&J M#-S*<^,=BRJ .>VJ_'J]R19.M_+#F\O?(?QP.].N_E_L_4NS)4=VI@?/XU?D M-Z!9]X!$^-V#LW"/"(E2LYOB1=V23(,L(*LJQ40F.@&PJ[JM__OW/)Y%GI, M)S+-9*IB@=C[G+-WA(?[6N^ZO6^2#8#3 S8%Z#=CKNAD EB1+5X4$92/039! MHW?VZ3&PP%5YH$=*V9BW4^[C;._4P&[B*#$#(+KCMFIQ+$&'U;M_1>?^I?>L MMWHU0"VPEX0OT@2 Q$"XFY/&MU-ZG!^>05XCQX<#1ZN3KA)C\RFEFPFM9]6H<2DJ!C?";!L$R78SK+U MX6"^_*;.M7,_F*>R6K@W1:"D\Q80!&DV^$R[E3GQQ8Y"605NPQ6G@_&1O(MM M!K_GO2P";L %'W?*JKJQCD]2,,5HA.BL^!2=8Z_EX\!(GCP\\(O41 "24 M+V&#U*5\C9ITAX0$Q)O.9JS^=/:R%$%Z69R:-!]7<@ )6U5/EN(J45J<@W58 M@I><_6"X>:V1H#U;JW-PXC[42QO2(NXE >Z,I.0LDHIGGI<]1K;*XPL< 0A^ MLZH.U>J;0N+0!0(\N!U>0_$I:;L[:1U'PG[PL%ZLIP<-4U/%R'B6O<,F-Z7 9 <'2#E-(-DCR A, MT[$4MT(_[5%@BQ.6&R@MC/1X&VR$W"12&W8A.8?0+.:H'$*,PV+*L8!-!;HH ML=HM7<1N>7N[!ZY;VHH0"3%%RG87F0K==0'\RQ=N@T@HQ>=SVXZ"P[Z7 M:A/6+:M9;$&"78/EJ"D1)RCEO MZ6XD#RT\ZRTI0]+FTNRT96M*B\^]-$\ $9J#Y%:V;3XN\50>.DI>64SG!\MO M0U"C",Z^J0SD(QLCF;IB_PGF8R3<])K!/2"H9N90LB.P;5*6;%^#<[;C=%/N M5N'80)L4I@&PX%!15=*0[_&0E*Z4S"*5;<5)D9$<^DPRJG$0 M/3G[OA7+]3[KD:V+=NNL)]M-X2O@)!8I2?ND1@&VSO/*)NX.,@,0; (^W/#S M6'S;K/!CUX_Q956I>76[ A9NY='VW9:Y8Y$>Z!ELWB#J <"58;/4(7$PVS'< M228C@B+ -6]EQZ>/BBM;NN#3\HF VCUV*/&*EXV!@SJU?.PO&6S:J7 C,6.R MN6]S9$5QS?B,NNH.IC;L+.+/9!4!_5VK#;Q=M\SIU9E5S@R66LKY!R-!J,+5 M<\8)JP_.U>4(6K0OFO,@/\9T(1H&1^;GO:M&#DRN75)BT VAEW.R.^:<)V!& M*]EDI$"D@1\>K$D*/)Q+,4:0G@ES[FSP3J1^[818.C.-O/N?%_3H(H3 HM[_S1,U0$/-^ M823H<;/S%K/H; 2?ZI S3XRS-!V_(K -MV#/0A"7XZ07J&I5[@$[??6[1DF! MN8DP5F:/C<\5<[5V3[*;E<^TVT!'P@&8EQRM<[=C"(LMSS@6W1ZO0X$GY]9O M=F CJE.PQNE$I[=M&I$'**A]"2@$(W0E28&ZW2 H\,4 M&(%#) KEQ?^)AJA M L+KMD>>-_^Y5TX.3R9[4)=A<)%;V\1JH S>(VQ1'VVWQUXHJH.[I]D2^]FY M^+3UV_$JJUJW??P.ZJD.@367[D_2N37%9<)?N>N.]>I6[.\\55$EC 347UBO M7O/&4['32E*0?8D )28 I^4K[QX867Q896J0HQ2>*JC:TOE5"_7G,+) M$G2,(X:(7>Y,^NT@?0&WS,6-*-@%"3M88JJXW_93=<7*V5TV0:H _2BN>4L, MC:N+)H+8BE)D1<6TK@<;T'QTJF5SBF0\?(@?.)[WS;5'!ROYZ&LUBTM!5&P\ M)2K<[/^6]S&=68ZK1_V!@FGQM!:IN,&PXE4%!^Q!7U.QMZ#:QWWH\VRNLU6M M;#ALHQ5"MEUIX*5A0D0\TM7M-R$^/2_IB?MJ70%-.PE%?+=(X(!CLE]8F)+3 M9+.-KDD-#2HH<^=4JL%3IMDO)D0:*L6:6 MHAT!3;<$,!R1Q;ETK!F_7;*%R&,'&+?=_&#H:VP )&TP6U5NM6_)66'0PN9' M@V>7ZBH+,NTY8H7909PN0@/55(K4"XX3X09X6L-2X3 . _(Y[R)YL/V+$IX? M4Y[5??6YG0(6D)E*B>>3EQP$VU9NWHL-:YV'J" H.D$(4DWF.$4N&^$UMJH& M4E]#H[*!XXXE,^A+/6QO6>I'<-G./["(=S?VDVC%'N@(O@.GF18.T^G$C8]T M\M\ZDY$8+DT>A?;()F/*4I;]IKV]+N(U0A4KJL6A0VE2@!.'JI]#36.9P,5Z MH=[V,!/WRPQ8E?7$FXT0%O^.QOQF=06-U 49$?D(E^UL$%]'-5F).TR,5@52<#_;]T^+AN3 M!=.7]1%.Z&W\95=-E+V?S=?.2T5(5U3>L*S5;56G@*2@$:O*:-IY';C6?J/)/S M6N?64?1@6D9"H#. >H'\7WBVKD=>:[&.\6$.4^[^JH,JW3RBC#8-XUID2LQ;U:RNA.8X,#$FBCK M2G@G5=]4ET26B>! ORG$TZ04#U]"'WD3.09<_&Y6UZF5S7,[);4^[97GWP@5 M'ENOK$Q) FE::PG$4!LEF(U9@KL :_R8DL7 M%1PF%U7!6#-*"H,>;&1+?9Q0N?D<=N84$5#)X*$BPR8EJ]2 ZC3;J6;&M#O% M]229.# <5U:RITB]AR&3&W)-:)E!Y^3YW!I;S,:SJ-:2=. .Z?#L!@Z94 CLL3N0,Q0+.@D1W4QL!?G""<;T[-+16\7D M/@^C$=Q&QDFN1P>68Y,YKEFEMC=W7NM*5+9SFVE>S@:X(50H6,4)\T[ 05EA M@CHW*V.-*3V4D>2(2MDJ_0E0@SW&&DGN5.I65932@2?B_4K@KOB.U.@$^[)0 MV6KI=A:!$5_TC!N0SL$DJV7D =":ME '[:R=+0.-7ZG=,K'04P+'+;$C3/# MWX+L=WD5B/+Y=ZYFETLU'?9DR0@H+6M1X.3F 4C6ON0])>Z5M%UL8[I/AC9; MFDTW7.,PYQ5NV9J6!*YM%,]AP0= N$A]SDV)!F7HG/1X;+I24L->V7H^BRK5 M7&W)3J(F*8D!T89%A(7VB]U.?8"F TC^XBB-;L LAEE%%D[KF*.,QM]EXB1VYPANSJ/R*V3;4S;']DBL: .T5QV M4QNYK%K><(?X!R#D_;)G[UH"OQBGZS*U*CW!<-(F^V2&I/PG8(>_4$AA3=<7 M^RL=1EG8=ZJHU]AN19#AS/)M!Q..<]OS8R_/#CP[@C)/SOL [Z+$X":U&N8< MG'E+)J:J\\G2[O+6>:/EZ*T= MBJ&Z&R^:>)@6C:*V7\KC*$[/&U;Y5#34"FAR J#;6]""&1()1[BAI&"19!*< M=VGXKT*\<^KBBWU#9BA[DH1QJQ@O(D@N9+];<2ZAJ4C<%L.E&J-K+E$M@VMO MCLXV?X=C?RC9*UMZM1.8TQ@CP:M*ENHF7*8 P!]J+:^AMV)C=%WRF5+^$V8< MV*/(7CQ6KW1S]ET%WNNR]4.>O="<>)%*G;A0;6GY_*POW+;29_D@%,H;N[/2 M4Y;S;SI-4Y)BGBQ6[F-@^E0@YM*4'[/M(7#9PBS<3EB(<)#ZX'YP"J M)!(!2JF=_/ ['&X\[)!L9$FI;(M>0RW"INZ]O$J<2=5)'^"HLEMY,2!8CE S M"M.3K=L0*7L:\75*)'39X1X3Y1@XV^6<[&UJ ;$WIOJHQ0:3+HNITEVGK51- MFOFAPI!468XE5&L_I^EFW.]VIIZ)U.3PJH$Y82:1$@12"%%:+*#4V6#:W4Z3.G&"4"=)"F2;V&N3O;FM11@W4M=B?2' M*P9X@P< 6H28$J&H$KLH%\JVKX%U"3MXR_"RJLUX8 RJU:8J_Z7J]%+^X8WN M&^A5",. #Y)3CZH/B*N-4AYDPMV+^$-T[XS!$Q0T-*549'E4U4@: IF.=R5. MKD="Q%25VU6+2(T@!4!B/8C1 <'1D>.2Y6<\4WH>3$Q;U*?L5ODWSK;N3BEN$E@P+6JG38$2X$OG+SD(\#8 MG$--GQ6Z*CNT[[*>FI TM7J:/6EQGF:W#.J"42O*%$,$&M52C>@>J0@)#G;K#\BX4 MFZ3GX&%8 BI?>&\!(EO6Y46 6;;#60;;+*58M3Q^5/RWA4"V4K<_#PB%RR+$ MO8>;Y5H4])<>F+NK?0E3)LV-^LKVWPU'#C6Q]Z.4XZ78E=7A54M\+-R[]254 M]=&D&9L&M-FKM44U14]]/[&.:F7E,"/C0-2E%UEM"RTU6#^)+"ZU<0%,KV*FFQN-V".F4R"%BGT&E;!D][ZZDK",X M3N&>3A:F0W@SXS:,4(L3NC)A.'4*1!OV6RW5<"Y20G55".ZJIHMYY)"L$4Q) M(H&-V0Q@<2R7L'JJE$0 R#TV0A69OL>]X"KQM2*/X'!VZV&[XE#DP09*UMOI M<8<"K1=..>EPPOW6[H/ZY<#,40,_I>C,B]FAJ .?E08)JIQE<_%V:MEMY7SN M(2P'J&G MTW=6,^SUW @+#H'!(V6S! /J07/OM@H><\B6W:PC.BBN*;*\_%QVF,J=PH,] M>7Z*R;(=-DS%D100M'D94)[EV"-HNYI,?)8 /:V/U6WE% :'UPVDZQ4LB"0CQ)3:J-P7+#?4=4&((51Y)>JVN%X43QL M*5=_MD> 2^9$ -ZGM>DX#$3N1;1(C+3H'2_U<\"D> &U&$(5$CC_YQ2T-,B[ M0H>&,9LS88[QMC2_M)6?? @0%WAY2<*LQK5IC7WRCP(G3 M4AVG:I-0R))?=9R[*0$8]B'O*E8)K');;\*DN"VVN.TR M/&T3VH@UQE)B<0:EV662!R?5<;KR -AYTJI /T C,WHWVQC$SMH6M;=8FD4, MY71LNC8G3F2WP.W(W5+$#$J#;;SU!'E9A$L'B&EC8I=-F5Q.ZF9B3OT%6!%; [IIEOL'I M/,>MMU6N+-B4243XL#\&!JB9:.)VG:Z<5L,6$9H#]DDQ:5P?>\'.#4)"V\0O M=>@WQTAY)UK"E?[0N1G[7;!U1) 8>OM=.1U8ND>M*\ES3AN)P4)9AKA;>FLO!2J%:C5;"IH*OE)LFJUQ OQZAD^1P* M3MAFDR5]=-[ 9P[DTFE,A.*'HO1522D/.7:/\ZG4BA3\Q4&5:&$E*L=^2=8: M-GE2K(!4$T2*0!*9X3()1[Q&D\E$V 0D'9/,?@3G/[(A7.HP2HBB4!">%.?P M/)LGNYP&1;Y5Y%]3R8=HORC&=C@UQ6XSL.@FPC@=%BO*3++R+H-033)QIW%C MA79C"D5N%2D=RN:N%I1%;F);E>0>]0$4PZ91BV'<3799FM6:^,@ MK>D04V8JRW=V"CC4 M!]V,57(]J=XJ,/L)VMYP\^H=C8 \;ABBPWI'EL=%/H3:%DZT7P!#M@'<,I4HNSSB6&)$BI$B:C9 M_#8M2V2[6\B?VT4GP>1W)'BSGD7%^8" K>5556;;K,!901;$D)4+E9#PV MM0JC"JJ/H5.U96]7Q8P'N!-!']BU\\8C[6 AB]-R)&>)_&S-8_FQ5$N :";P MF=UR.JQH.X13?Y?,F^:;'X>%V'<'1O_1=IQF8*;=1.%8:1#U5_#:CN*Z><_M MD&.BKUR.8TO]B$N[LDL7%,PJ.PJXRS%^J/#&W@^2$#DI=_W+;MS_[L_OC=\^GC3_S;>/>[]Q_]][]\,__Z;T/<_NS_]S=_]^?G=Y]^ M\\YW_SS\1?C33]Z$O]CY@_GYW=N?WG_Z>+W]Z=U?OI%)_,WY\^_>Q/U-J'^9 M^E\2C&]_]F9^^N&/G]__[O<_O?DW\]_Z6^W-^?V[S^^_??OQS5^__>GW[[[G M0[Y]^^'-WWWZ]OV[G_[X%V_>G!\^O/E;_^3'-W_[[L=WG__IW7=_L6TAO/GN M_;<_O?F-U[E]XS7]U-:_F]?UK]R5;_\\.?G#Q_^_=OO_7C7Z5<_?OO] M^P]__-,O?/K^AY]_>O?YS5]_^N[=YX^__-7_^.[+M?WUN^_>__S]+W_Z5S^] M_?#^V_/C[SZ\>[-_>>O]C\_[/[S[[F_>__3M[]_\]NV'']^M]]]]_.Z7%\&Z MK4OXYLNS7&_^S=OW'W_Z^S_^\"\?YV^MU^'E-^ 7^>\_ M_]O_^8LON3]^^^F[]Q_9#*6^>?OY\]L_;NP*7I4W_RV\>?_QNW=_>//N#USI M-W_Q\=-/_,D;%N._O_GMI\^;SS'4\.:;_^'M]]^_]?T_O17??'.]^_#3Z[?2 MFV_^_O?OOGHKO_GFW[W]_C??O7ZOO/GF/[U_];J^^>9O7K]N;[[YN_>_^^K+ M^IMO_N&'']]_8!>]O'GP=[]_]8=MYXT?7[_!!?V'[]_][M4G-2[HM[]]]9J+ M^>WK/^%B?OOAU>OF[[_^A>X;KW^#R_CNTT\?WOWX^JO[_B_O_E^OWF4=?_?Y M[3^]>_46Z_CV6[;>J[>X[&_??GY]KYW+_LWG=U_](5?^_=MOO_XUKOZSS_GE M':[_6S;MAP^O%J%S#[][]_G[MQ^_^\V''U^]SZV\??45!S?QZ?5K+O_3CQ_> M_OC[5^]Q_>?]ZK5K_OHU5_X??ODW7/J//__PPV=6Y]6[7/QW[]_QYON7=_=? M;;Q?;KOXRTV7?K7E\E<;KGRUW>HO-UO[]5;K7V^TXQ?;;/_5+@M?;[+X]1Y+ M7V^Q_(L=5GZQP>J_MK_:O[J]?K6[CE]N+KS!+_96#+_<6C'^:F?%](N-%?.O M]U4L_^JVBO6K717;5YLJ]E_MJ7A\M:72_M6.2N%7&RK%?V4_)2X9F_;A[?7M[C\']Y]_O;= MQU=_S3V\_9YW?^367]X]_O1M7W]5YG9^>/OYW<5-[NR'#S^_W&KV87QZ?4HR]_/[/_[P^WX"8^?7QY7(6K_^F_O/R\<-T__?[SNU>_X6[_]//+BA7W^_M7 M^ZMPN3_BN?[EM>: #?ARK7BI;]Y]M1"%2_WX_O6%=._Y]2DMAQ_S_?NOWZW[ M/V^#[S[]EU=O<]WO_O//;U_.F0[M/__\[D_FEY^\/(F]_#VY?+T:>?+ M*RY_O+SBTN?+*Z[[>GG%-;]L;1W8\_)*I_ORBLO['U]><4U_]?**B_F?7EYQ M+?_SRRNNY=^]O.):_OKE%=?R[U]><2W_X<7FZ4Q?7G$M_\O+*Z[E;U]><2U_ M]_**:_G[EU=75US+?WQYQ;7\IY=77,O_]F)PN9;__>75,EAO MO_W'=S]]=82.^'*ZO_Y!^I<_^/ITZ9N^??_YVY^__^V'=R_[4?>$<7W[[5>' M7/>T/O[KS^8F7H[=P4W\YN45-_'M*SN5.=J[JQ20&O=>HY?O>2J?GKUDJOZ^=5+KNJ?7KWDJO[+*X_)5?WAU4NNZH^O7G)5 M__752RW]Q^^^@ACZIW??_^(]C>+/'W_W]O//WW]X^_.K:]-%_?3^PW>OGH=N MZE=H).BM?HU?;MMQSA4ZCCV M4&21O*(\WZJ^[U=9[,"G_!ZR'(]+ I>C)P5=]U"5AGCV?=2YEWA?K9Z;66N9 M.QY)SZ[G=+"U+WEH!\'3TU7:N_.5Y"+85W]Q:D<[S/=?TW;!JH;9M'5N4V_" MQ.+=XG6Q=8:\03$^X[GO*K/249PE3NH(V[=6;)1\KNN)-9][LP?V?H+S[>'8 M%JFA#4.WI$'\PBQG'$O4LX\D4?7-9^T.@UMP7A-HIH<..]"KL@-*0EBL+.<6 MDMR(PT)%:E=U##'U\MRE6&!665"ICY$5*UF\IWEPZ7/&.XPGW]%)B+LY.)WF MEIS(4<9W+HW@,]FO-N6V/26M'*Q9<4)5S94]1YG(*C=RYA0/2=WZTH&SZ;'% M18 WG=88]>8&=SOM))#W-CJ#*(US"B?:7RZ)6#]4?924U>YLR*W9?3G)=2ZI*(;WSE$)M6A#I M&\_CBJ=ZE*>EE'Q(>,\MVJC+TY=5/<:^<)VW9YRKAKCERJ MP&T\A\0>NW+ED37.4M!R@A\[2,*QI#(BRRM[N'P,''W^=-J%4L*M N(EK?M4 MN7%S\O=QXCIV!3?WDE;S>%)@5FF8Q>XTLU3_[8H^F-L>XVGE:; IV8LM).ER M<]ID,*H\8'.OLHBHZVBO&4]*DIVGL:F":>=PG1'#UY/]J_(#N7*<@C1LT!YJ MP&Y*A\W%+LO.8-'OYJ3X[ECY?.[HE$R*[;0;PK)E5^NR>=-.5O95,7=D]):* M8[,>Y^QRE6BKJ_]PJGVP]FFYN J.:$S-N;)13/\>3LNI!>:P^>)Z<\29 ]?; MQCVVPP:?JRW>_3-;ZY,A1&G8:F_)W520D=II]!@UL)CV>K3]]43PY7]24(UV/#!U[).NZW MG("SI5B3$S0GC[=+?M_ME.D'YL\>^9M?=D0[7-?PHP8K=<_%H=..MHTS\)E]=,DL_#AIHHB()5:VZ&0#89CJL*G#(41[=R5M M.]NF2F2;M>$9GN@CEA#SCO=DX>U9/<=N=Y+&#IMB 7I8&UZ$:*JV6=$,(SHQ M$S<6\98X$XL86RD8/0Z0&MP!=\/!/'C W(E-M1*D-:=+99J3 MN-F>=#U!@?O)N[-8.G+X6\DQA]*J\85;M%UC\17:Y_D\"K>H03=.^]BR=2VY^7LG2)'V3P[)VZKB4 (H M@CBD3G;,OK&0PSXO@ I6[;+EA)U7DL*GRDO'>:SATUT:4@#E==ER^@@K=YER ML4LU2Y7@H(:4%H/OPU'62ZZ]*@?&<\OXUVMNDK=@5U5N<1+P4+=D'+?LX'BB M=NV\OK;]V,^3=;1ER&81&V:ED#E2=F,<[00YV6N@]IM-LT=@8]Q!BD@.9'9* M&%]VV/.\ 5RY8F>@(Y\C\RXW=MHR+__Y9/M*%!L?&4TQR4\-DCPT-42X!K"( MC<(@#]!(VK"%P5T^-3!R4*D'=4M^>-B,4)P=;^Q,7$/&Z0_)ZH(,&T&)0IGO M<+""^?*$S;Y[?@8:F#;B.H*4\/SJR=WWXVA^4-HTV*3(";3/S\GZ7;DK;"46 M5 JP?=@RO)W)X7KVK?ZER4/3I50!$['T0"=)B;.5S]/.HV:;%!!%WR#MZ90X MMLN-@R^Y-OQ$&+8;7'B0-<,LY]1]-RCQ4Q@+9GLU]2&+!061# MXE*"HN_/25#QQ,63K99G#?H3">.M_G<%=FY >>4D9MDP.2R[TQ6L%$^P2FZ= MG."^N25@F/I2U6$"SZW<-))O*DA7LN.HI;HS+R<04D^*]U16C(\&&W%=WN2U M)F5S54ALLQZ>G&,[;2W'KBAW* NT4C5*-ZA-RXKSR)U/O\4SGO0J;5ZZ,INS MZYY$PEO8<8NV6S@=<2I%XRQ%9*O>^+Y@ZQ#(D&"N.1%ZB^G!,I@S'\KJ;>QK M$(QE"5L'G/$0"#7ME3BD9JNS!5Q\*(\577(A0XY^IYP,DI]\Q9 M#7;I5U 0]UP-6"[;TZL'4_S$/CZ>3F3*)RY=0AR-,0OV8\U$Q>QTDC$G!TV= M!=7JY>('CF. Y<$ @+*NPY$"!U_&D+FIR;':V>6&N6&*L#&3Q;CY[)P. M8DJ>9@?KJUQDQY3ZSH=PA7#\>8C207@@7!4M^8ANET^+E6=8_F2P5Z+1_WYD+!T$DYL'@&$W.2X8Z/.&S M9&ZD2EB\7CA$0OPIH_:T*<6A-0*W![#2!M$O>^T@'ASJ0YRV)R4A;)7E51HQ MMOH@('@VZ32(H3EBW(O/+&OI],(,$6COXF]^U Y9X,VBY7$ 5 MJ1TE!:INZL\:.F 9./-#EDI.,6%S<+1"Q3$61?9A3PT?B$-,"V7R3?IDT#CA M10+"I;(YK@<2O+!P4X$9KD51H9H3<$\!(BVO+G .PY@=PO,0PJPF]&I*? M:K'8^KV%IQIUGR$D;(I]@@VCC@N_%#1^)"R2FES>:I66'109\L[BT*Y8%WO] M8[.GXNM;P3;(7-DY$ H+2TB+S<# G-P2B(# AX@B+KIE^\]PU8W0#3 (7I5 MPD"'(QP5^ *R+)$8O@9P5*5$J7$T520))YV[\B-F_C*#DCB)MUH+/"1@E)*\ M[&?.K_J(6S6.CQ@#M>UD;I4F21U6.PT)65GF1?=(W''/>8&2, DR8SLEVM@X MEWU"06*[L7'C!QCY<( ;4\[95[%\RCK+4=Z+@[*LZ#ULQ\OQEG""$$)5@FCF M 2>.Y[SYJF-L7:6XXRDM2V$WETD8(/QAYHD5P\L]TFW6?CS*6I[[O8(&/C8Y MY':H(CB,V*_F"+L-09?>&H M8"D/"G\&HCHWNWX!S6Q2FXH/U;NZS?IAS;0J*]DEL7-8L8=^*9>$8>?#9$7N M/1\X(">1V"R@(((IH/(IY=33[0Q.1(]2 XCI<8,&U2-7IS]YCLE9?/,%//LU MW4107V4N)DB,F_I.0SFEPU2,PO-\73004*AC*HMX[([L<"2/+'DHH;DPQ*$_ MISP$KW5WUN;8L/(.*@]Y$,Y]<65GHUS[WG N\I;(V#0D)DC2?:IE@N\5T=F$ MV#R7QITXR%G_IT++V]JS:P'DY:AC=JB#)W99* M#+5>][SSICXSGJ?8! J,(E!1&J#>7$V5V%4C#K;!ZH()=@Z&*;PF1;=SG:TJ M7(A+N*6X5SD>,"[7L)R_N_.4=@^Z;8C,%%XG0I1 R5'0+WW7+($SBE$Z#D.4 MIB".@X*<37-N=]=]BF"A5JDGA8_+=K))) MV8?[Q6]BX^U] T/U_"QN-1:*4[IT9]*29'@D:CTK7F#77CRRH0*@S06%F0D& M%0634$AMWJ,U98SQY,1':=<<3:?6YE*FE5ZM&XSM=D8K5LI.PKC8KWI+0F+3 M@94 *<2@YKE4[*!$X*134-+=K=FT76;R'3,?QK'&]A1P2:+S M)%V[;7X@ <<\% Q2$1Q60G7UIZVC6@>%M?##'G>A%.G['-5A,+$_#M$8E M(?&/1,*+3];^9E#)0J8=9!QE.W*D:H7E:@'*WG(>+"N ? ES/W89JN^PP)RS M]743WM4$>'0P2=T(-A#H+.LV'5[#)A#\F=J2G E'H;CK-.6^%/ID,^_.FK?P MS,W#C7THCLA&I\MJ50MC]=@^TN^#I7N6XZPM<;R!P.,JE+[Z G'KDH9P]>"BK][L$.:X%.5+Z:/;&E M/Q40! M8F#"JXBJ*0C@C=]X5]!E+L[L.$W6";CGQ[)+^**_@.?;5Q/Y***2J92%!9&M-//] M<3\KYR*ITW'B\F"[4&04WJXL,%!\0(<$='%=JK2 M&!W,8Y^>4@FLT1EM]@6$B-G9%I# [6#T(W-05O?DG,(6P-"9E*9CC3C^V\!> M$+^S91])M5A?OFI(\80#4=?C-@MN/@.@VX@!"!QX,M@Y<&90I/Q0T5:VP[P1 M;>,-=CG;"#+$A;O$[U)WC0&2OM6:D@Z+$\YS IH $>6GV@\):G6DDBIU=DC: M3/@I92$6D3$3UZ-T%Z!K=P307#M62%,]355>,JV"_[%LE5\E=LOLJ, CVD&. M8-G.DDI::D;#X4[^/JEH1]@R%LO55(K2Q..5,Y$'<>A4@M<(H'%"/5^!S3HW MO)>S*,A$%X;T(=&1YZHY>R:*/L<:KL1QR MHIRN<7. KN-.XU!?_5+B5GY6R<)Q>MF,##=*"'M(W\'J$\B>YS75;K;FP:[9 MA/>27H%!+]-_X!C,J(W,469 *?2$M: 4V]CWQ5G*CL1;X,6J$HE!A3GS2JH& M8[4F:()C03 RK]J3@WOXE(H#'6M&S;$D0(O"T6T&OJHH+&AR])'(6&#!O@UN MV@HJ+"RC8:;Z8S)+)M90T=:C%1%+-0-ICJRLU/872D-B"XS#FB=54J*/K9B@ M6)P!W?I>?.1I"QJ\@,UNELZ2K,X9-I4IC;)6(E-L%>$A(J2 /8D@,5F MR2.#B8H= \7Q#D2VTI8KG)!W9?."#W)W],_:AF0I0._=>7$,I/Q]][ZQ$0CV M.*_R3QH2WZ94.2EU_U)8.4R]$,,HL,PR2QT?>],5WZ:^B6?9V'E-0VT.TBAG M6YS G/KN:\$8 F@K@29.?+CXIF@U@;L]%7]HTZ'E"*Q4M)#/2M--RPE]%+XW MR0L>O)H0*3@MAD,QP],EM8W.":J"QQ,"^V9E7B10,[?!@NJFV6>R1!&O/6Z: MI1(1U5Y6=8,--SX^[!+H>31\K> MR=^3TZ7(@65#:3&,>JY&Y&5QMQ_9\LMS-\!A4?"R8-'QR\XE;T6]*=!U @[@ MF6[):TZ,BF$ M[U(WE2P 5)I 9GL\\K4WK+VAV:4P9,*B%:G!;4B0/U?2\R0!GLXAI:CHH9H* M(?'\#A=5.@!<-C&&1#'.N660W0Y.XW!']1:RDY;1\6;"-CY->:.)*;U!!YXE M,]A 3/F<9$+B -QJT%[*S5[F0U?P-8.3\_@JO'LV(ZAH%V$#)^"0ANL827=Z MYQT8A8?#1W&V+R?]GAV[3$27+$_WFZ?1*B@^R[2Y!E_T]CRMN&]$+.$Q&.8Q MRSL".+*&4^1,&=*[*ITA'_)88X6WC&A19$5T$<2N@97=A 4Z 'WGH09RK#KJ:/60OD=]T,2],GN-O(W&<",9E;7:PHS[C66ORVRI:I,"W&)G*Y< M7['+HLJ;_9@_M!;OP#KG@PMT,/?@MG&_H-]F\T< ]D<,Y2:KS6[N-+.%HJ)N MUK@)]9LB!& 6[&/E^-F0@0%YSGWINA XJ$@(?F.?#F6WE =/BNEPR+I3\+90 MW,X.WE/J^ )X[MHW@,"9S\$%\7LL MZ;4&Z$RHWV ?@*34%ESE8G,8#H%EW(_IABC+M[J[QY7E/,AAPUNQ- HI=.D$ MC^AL]%#Y2C)4.Z%\KRH>+#=,U9IK$,_YP+ ML4L"H)8Z")V'9ZE<*5E9S4('\JV* Y:@J/Z5%)A26F\\^$TVYV4:)OJ@@1-# MR[([,:LJK>2G.Q!# :RC9@];GC=[DG5@@[$GB<2)[A(K=Q MMV)@^:\H+LUA'5*K6[N0T;!(LFA:=^G?2;,K?6YV[*UM;=4A"6-E2YS:!/40 M>81&TI="?![0QI91#MD&$J/Y:[&-*C0!J'6@_,&:WUM_IBQ&0)JISKIJ7""G M8BZH2X8*N#NLY\PE30F"FX]R"[MR=?8 !1_"+D*\\W:DIL()'_$HBST5*ZI# MU6;'C8<5HP/GP58[Y3A\#I"X"C#1/"^W5:QI:IOYSV;H3@S/]X.0V?,7C\"\ M:%F1R9#G+ ',L!*+"A:PM(F*;Y:D])+=F"K#AFP MO"\1VZN8L.!L8XZ!)^7$%=^<%1RVE31 IV4=W)?$G_)[*">+.ZK3IBT923E0 M2O,2$/-P.:K A,,:LKR DZE2">"KTORVT6@ZM_CM,< M2CD4*)A2.#]J7K#%QI2>:>8&F@0( ,_KQ'W>4E&.'2$D>6%[8 QFD:[IN%@B/MV5<%H_>[DB5>;G0*#9K M1SB,!F]U9XAE*@]*3B&'X4$5^&M[W-BU)\=B:4C4,C99E(B#QQ>]TD<>-N&T MFJ=.]1;#?]!>4_LDL*P&[T-"(;P>#Q4W^\@.2_ [^L:VY(7).P7Q^.YVF99Q MU+VJ7E&+]"#UE/E7GDZ7C=A'"8M%WB6;N-Q[;,1GZW("&"XV\"]X4,I A7") M"E3L+7+?!,7,LTRD$BG=>Y3PA+#4:H^5CV0]),R.$R:$8@5O^<@5*^(DGL:P M1&QN*X=GE>4#^5J]GDL^B8A8$>LAN^!%Z(D'%0=OURX&: MS//9TPO$ Q])S<@&-F8_B&*?9(FDRASK?+I?70F*34>7 X< @R-BJ9+AN(#+A!.I? \G;\)K\I![^$!<;&YJTYQ@99*M-) MJCFQ3L1,6B,E50D@E)0[\/"J9@$=]RA_R:X) H\VGBO1:S%[IRQ/69K5MT0\ M8%G;D< TE7]: %!6C>C^!NG9:X&5YZ9E0^O$Z,$87#H8;EW^DE,Q44G#)?.6 M\03+6F13PY9**(SM7/)"<[?!3GF^I?O"I6R@R%)X>+8$ JJL2.?[LMFR%.GC MKW,I#A+CR+:,\^U#>8&P$GX1I]8OAO*SJ2'MNZP>8RXIJ M,/_6+^*@MM+UDE.;SLMF SGTN@J<07Y2W22@4($M$CKKTIH\P%((8F257,". M'*FJX'Y*:Q+4NU/%X;YD<-(%@]3 1C$L-D956M7@D6"L!G9;?:!*#935:O. MYI5#)*[HV!\BTJ;:FH2"5BI!R/'XPO'2L!HM6-54:!$OF9XBE8GT#^S78^4C M9 N2=TEN1J6]V'?2W\D ?$VQ +\'U@(=\32EJ,''L%S:;&*YTVH= ;Z)8:?T ML5"$BJF!EWBB-35B(;7S/6.M&_I&9$3@NW1.>^R2E=+/?9WL*I! M^L=%-EMZXE 2 [JY2K:#E_CX5@DK$5')A ;6X/CIEA4 D@)BV&SZ&!2H*K&S M462 ,$PJ9S"!OE*'W YV1,D_X)*A): X;&I:8:PX4-POHT;=E M4KP:,0G'2:)!);]N+D!!**,[^["C=%OMV1(8M$1^1QFT %(G6% G:=2ZVN2; MVMBXP!*(2(:D0BZ_Y*()I*9$D'WG\2C5(&@^"[3H'22W"D' MF&C@O%SB4XZZ1:[:W!EVAG'ZHH+3N.N+@\X9674[=?#LE\ /V1N=;5VRZ:M; MO"R&^F&7%IC@:&?UP6[@IMMD,#$[M[8;5L= L*#V:53BNMKH4]@K_&(6QQ@= M<4AMI3P5MB,RO@\,#(%!BZK(7/9Q&R2.8UODY_M5I*?".WN9Q'3EDO-B2E-Y M6W$&.1WFY2RS*"=S\Z%9;HLA<3/XKMBMM]W][H&;?SS(H.='AF%[%$YKZ#I* M@2C>X^*T55G)I;YR!$(E:ZN;>P]6"',Z-X)25>;.;CF'8(. V2/:;"%Z\(^8 M:+>%G3-8ZGOQH;4AO]Y0" =K#QX$WG*'2A!;^.)@!%NS<#E\AD35(.)H(^\5 M%4##_Q<5L?8@D7T&1_!YSH T93ILGI_G]6R&6W-I(>+RBE,'MR5^-E]0"873 M]4B ;5FV2?P6^B%Q2K^+E88LO:12LG::/%N,S])4DS!S$:_IJ))=SL#!W8/' MEJT7IS&K&[Z;Q;SMI#"FD\#;8OW!80 Q;SS4ZHA$%%P^*A1B"G9PR_'L=HKC M+0!Z8%:V1IS8.?V1TP. %S=0]5N)5, B=>-F&S9>@9-B88 SKM@4QCA4RR/E M7-SCK+E=IQJR,^!4).9E6SL.$*W A4M!:4E.+CL>S%)F=:,OG"P^'5MX'9+L MF*7T&X\O-3C6%V.N1R(ZK6:0"!HB ;9<[4>*FDUS>X<:LRVXM.WWEMD MZ=GM=>8NAZ3+Q% 74=,303M\76F'[8!/W^P3-6"/LG3BNU6Q!))A4@(!U"-Q ME3T?['$%0:),NYEE.E)V0(5[*+?=\78"'MNMB"B8ZY$+'NRCCVE"K@;X+[D[IUV,+7<_ M)MH=P&D8Z9&FM1\$'6J<8X)4OY1K$8N^?>E+-S$NAE"M=6#3[3:79K>>2D:[ MV;( 7A9(TZO[H4GL=FU&-4S- =]GWI1WCJ5,3*5\L??N.-%-L"5UO(V#1P-/ M1_EX&MY6]6),TF5N3J%H-ZR<;P]GNN/JB >)_<[+$8 39^%_+!Q/L/2TL&T+>\[R8=H&:OL2,W,D_(TY[8ITL#AF'X+DWG9] MX6K,'$X,.):\$["#C]@ JM@#S8-L6-MJS^EJ#';?,Y&B!#)F(DK)#-K";>9+ M-D.VPC.5,3:_-L:LF4M\PNDTCPW_8:NJMEAX4U?+KCV>Y[5$&C')8 >+UYCV M9!3#T700V_!4!T#&*%P\9$0.88[#-YUG8 /<$-)XT@,YGG:OERUT6<^Q.:DTB"R"@*-;-+LP5;8+KVB\V0;MY9QC^#_7U!E DJ%*Z^01=8'W&H2B'A'N[B?Z\8\A4@06U83F/ M9TFJ@CN2'&H'-U+0.XLP^11 MCHL;C5;LU8\7T3MZIIS?D"R."][L>E4ZGO.-Q;LE@L9R.;8=EV.!]>&$V6) MNCTFA%S#DK@=UT0LQH2@[=WT V=L.!JF!HW->:;(6GND27[V<=I *']S\DQ; M;>.^HTD9HXTE[\&5$%9L!,(I<>P $G'9("GT+UR868 K]XC=5\*AVQ[E(\?CK5:?HP%D--008X%[4>2,N,R$0+MRR#8C.MZS. M:=56KB4_$P'.I; U>*CV!6 GEDPG8)O' :[J8C5,-8J MU'"TF\274C+B%Y]SJU?I*V66=@ZNHK;&*X1ZD@BS+Y*0<$E5OA*4Q4ZPADV MXB-,:O+!KE8G(F?":FL/A I2>:[=V)QZ. BP#HX.KO)02=+9H]-R)]Y"+>OA MB,QCJY0S>Q)1]N/ ,E1D>Y,.$$(+)36[A2I(_]PNO+:1B^]? M$JYVC@AZE02^-TG-C7()2 _I[O.BHL1;JX5,E%:J8[47>+RMQI;AQ\US=Y($ M_+!TN:)LA?L1'3JNX$2/I=Y?T0-'^*[#<8]NZTX%]S_+R[(__*<11UFH!I'[%G)U$L"6+M#=\T.L/AQETA6?H+<'19F MBQ\J<\VR"LR7>6QV!6AJI'LXCX?=,86/;U(66CV+_BP;=,N;RG:I1KR\.H_; MQ,33RBKU8AQW4T=XJOFL%#2@'G2W+QF=QF&-(#20YX'W)*P;&0\4JGU5MUJ0 MM@NOZ5M";N !MBT)%==)43R4D+,--99,YH> 7SJS5 )O1NP)%:E\:,^QV MT2I3.8%C,VVVMV*YV$$I\73,HT[;10]E-I5OXONURSM.%\C$H71SWP MT78T/-N^&8]TBU0LS>7=#![V*1113MO"JSH(?:@T'C%@SESA]RV3@R-*=0R' M98R<'8DGAGV%7=FH8B;=T1ZN2?4/VP*Y8I=E2:4GFU8Q!Q@<8/Y81+Q1,69A M,&>6V.F1BC4\2O!:RM^5&I:T 20#CGRR57\%BZ+Q>8I+/1CHP^*5SE7Q;9<: M4IRR#6>E4%S6*=0U:H5WW)M3XKO)_G8K%H:-*!P,;I!=S\/O1I7$\,5 *;6J MM+"36'M2XU+1G"S(=)JM*\/H0B;!@YV[^;%O3+)535\9EY2 MAAO'0O*%0Y_X?!FR,VN$W2,BL8%K@K0:+I9[W8TA'NG03Z#^Q7-V5OLFW,%. M6=TAO%=J1O5XI>_U!:Q/W([\RDN^Z0:"9J7!I.8>]J6&=-\V@LE0&U67 MFGWSHSBN3D/W$9? M[0#32M;-\0Y&!I?9OKY/1WM/B_BW2+VJD N$#QQY95640LG/.%6S;/8,79:P M M[=#N\%FZ\LXXGBZQLEICDI)S:MS%3R?"XC(OAT"&7 N8*R)B MD.,NI0D1H<+)=C>!7$5-F4L]'$UM]UR[WLG>1T6O:O>,\MPB47L63M6-V-=Y M&U84E1[-C%K?H,GB*%P5RB)U=5E XIC@<(!&"%$ MU!FTQR0'WM$67[R]!+%AL[%#'U%O%#63H2#AT - D= MMT=A[&)_S>@6-9U&=#DR$>2N/'BQHQ[K[O1*&0T>T!\>3;7_"[&PA M+5;JKMB%CPS[V\$HN,V1L$4FXEFM*SHO>#JS?C7'<\'F=]8K[$NBZ6DFYC<\ M _'"/09H4]X2^Y)RR*#)/4]G"V2!#LK^E&!"[FI& RR.FIC/<%$)9@"N>,!- M3HM@7[?)<(#TM0A(%!)W/(:G$T2D;(,'U^AGRL)C]EIS7*>JD?GB!*EOL=EN MA*^[LGTS7]A='.6J"F&/Q9^P2_&SE^8@+MOWE ;;'#/1HWE+#H+]>*P ,+07 MPGLQG*/DYKN2W,\LPBYG=Q\\(9NW#NF5["A4[RNVE>I4/@*8TE>! ^_N;=HT MR85P>5C98N7D7%'NO):B.A"U$%%%+87"HJ&[@_-L- MO=L04Y0=M_2 94V]G+O*ZL!JMG 6^N!#QT&P>X""Q-!) M%(T;PC 2/ _0;C=5>DOXG2S1KXJUM!4L+P@U*PR4,B8\!:>X'/%3.FU3O5,) MYN7(L:.6H IA(I&RDTY@29LK\?N'@TRS[\T8=R@.47E*15HFL(-8+^+J'@UG MEKYA5XJI.:K)M,)=CX%O/U M,D.94WP\"^KB 9.&IW-.N0#*>:G\TVUR[]E!9)/FI>&8.Z8[\O" #!L(: #L M&C:>6!_LKB9YJ(*'9G[0G(\J\V 7 %7DSY)G[=F55?=9),>43?'O!V@[+ MM938+6A?PF@? MIWZZJ/M3;&>8UKK5?S_*DKU0M\[XVQXH3HQ%?O[(DM=C@C%M! ]GJ;>#E2S( M':R_!$<#"8&6S$T_=[^AKQR"4:,RAL^2V=^<6:).&%L_O9_!E6&\A3[*CT MYQ(#7#MF #\BTT_G&FB5G(&[7N(AEU5$XB,/7W>O7,6Z MJ#)]@!.#@9,H5^'&CVVU^SWML5P_>PS4)&..) MN;%">:EC%('7VYRFL-D>^> 9G_@4E68(^,7<>(C+,5* M#8YS F//<9J.PV?BGGU\'$7WMLU/#D=4=7^!,(Y^80^J=<80C0-._0'A-Z;( MRA1^.AF(5K#E]AA2SP>)V$X%GXH^\KS4Q5-=1C;,EO8DLQ;S43UT\N2 M6SV>:1==(AX>U^K_4@,,;YL$- I$*X9*B!15]#@YX>.,"C/C Z*\2'?_(A5T M[43/N&[I1PYOT=.E@OAN1ZP!=C=2-5-;/#&.?ZQ,0>H$7=N=L*I=!?L0JV-: MRI&VK.N.'=!YF.1+*?@8-G4]<;$5.'++ @;,P'GB;BZ].&=_(\W8,B!5+NRG6*3.+=(PFYX#*ESI AP]6H:RM3@(8GN10/C=):J8_ M!Q:?[31E:+I@CYOZ=7CEQSXTR0-V>Y-S MD>H.@,]W[I;F^*Z.&==6VUMDM[ZGM:O.?BG[0HR3L&=784UMRBJ*K#9JGK;/\5@*X'P809 /K-ND?CF= M\1"<@7X(EW'G@:!"WD#L)"81H'#==DF?-G![C@F;]WLS]R/=9[?&U[LD96Q[ MBR7V!4W_)CLVD"X@)@LER!V*]H;GO?3 M@?MK39LD=S6@(MFD=!_)B2[+!F,N$H FOXJKY!SA%B>[R4[SF*TR'S:18$)- M%^",EKJL *U;/[N!359R_I((%_286_9W5,W7Z%T[X2U&U$ [K,1BQ[RU#A6,OYA1\G MQM6D97\!N-3ZYK!RUFM8%%I)^LN5-I?V4F7@;8G&8O:)@0V2PNP86*PR6'$X MRWLJYGI[-+ T217=)*D<$%@9=REGDL4R0NS:-AO3NY1XG.Q+UA"W.)O!@&AB M"^,"34#6(_$T\+?L>K/3 ?Q?5U&\2X56E;O&N2VT,;WXJ M(]AWBV,$SH%HF/>N*#^3PZ@WD2;V^"2T+?.T''J> M6(''6+@YVPM:']-@R48A*[>#,[RFO9+#,YO)TP//T)02!!>9UW.+31;$;I%Q MSC8Q=4Y+2>#V2+HJ#JH-A#[\BMM6/0(QX@#=KTR7X&\V@IL!\'@-5ZJ@25.\[&& =PP\=C2**Y MFP; O/&911E' K4XG1S;)/JUIV#("6196K$LGD]6[O(84K[B MPIWE4,K[$@G@+1]COV0<.]=8VB/VG%OD&H_8;#R_B=D!V!9Y.0(8-3]W)E:R MV]PN\18FU6JN!$^ &_>;*5+.B31;]]9:E&333C]'-Z0"BTX5* T.%@*'VK+> MU)Q693>J_,8C.E88)RD3YO^P9Q:K:R<)0!UO>7&YQ&(LO7WUQ52CQ&Y/XV![ M#^RP?CJNSH[#>DK:2Z2XI+9W^\Q$03)?KW-1VL+B!81RF:XR/<6QR[YCC['AH%6Q7D4)#D) R%HA43M><7 M&VD3QX'5LNXBK#6_K7([*\)';&")U2[.T=W5+%:"4(ZGP^%-94-WT/,%[I(O M[0;R+!JZ$>U$<'X5I[SHOJ6=VKY0F^+D8UHBAH[4RW;4,?LF6S'\LG,.R0,' MB$2,;N^'A&(@YJE?)43D5;XV1Y8#B)%QQ&N^4$RGM=R9J(P&;9!?W/C,6,_\'!$1GK=LMMWH^H\^T$6-#,5&32?909O M4HUC^4U3)4W88HU(3B-R)#83V*# ;D\*P:ZIH;Q+]-* C?@P"PS#H>^G++;" MC%FX#X\DR%/F0# WBSXU]JQ%_ +N)= MK0+6M\I["7:)$I%J%/8C[9N9;"%0M#L_RO@X..8FCHLE?7//3GT"B+% %;2A MS96:C74(4KX90TJWBO/>6*@GNTT>_B+:5+F%G.A5QIAPFV_% M??&8.'=LU,%3F$YEV<,1TW-L=N1Q4#C4Q%LE6S$\FLG";->E2MU8HZ!?)]I[ MAHSOMGI(-S9X$D7YXK2Z L^X^2 >A:HQ)I=3;H]E?>)9V2] IPJA@V=L=.:@ M2\A%G#BR(KDR@>-VP\E.M(P8-A"(W=(@!&T+SU/:0=;49E$3NK<-L\^,BWBO MRD)#M'$61[RPO1*5VQX]FRT+VC.B7/ER@H4,FSDN+J!V;B;O=O\":2([689> MI0,DKU 2DC6JLR@J?759&%D_Z02#PO.7Q4_AT^58Q"S@JS5SYCY07AU_FVQ* M)LX"('!@\#[=*81LI]7A=,@#"@)I*]\I5>*9[)*3'&*L4I?Q@)K"A]%;TC8H M%1%JMZS&IJLK&"Y7#-BY^S#@=];-3A>' 9V-D+$XV*9@6>R4GQ.<9$F>EKU*>[G:\#;;T'"U,KO) F5)7*9,@K@L 1A;CA@\CYL%J\;$ M'(6$\;!!EI 3GRVO#?$V06_=YHU?=A*_R4IEIE=!@Z5+7YRCTFR#CQ9C@"^8X>C20BSC$HL$S:R>CA(5Y$PLLH& M9EW)M9+>*#G0L6:S*S&+I'V@W5J('HV8,/#RK5;ST&>R? 0ZXV8ECE*+N)EE MJLZ[."(=C$()K.4#Y"LS@9BUN/N2#[4[OBF?O/D'Z9J>A,M-=E:I8, ' PX> M< \'9K?+_\#DQ;F_/6%N3501>0^Z6* LCCOR\S;3*DL7& MXBJ(\$+ !^QV)WZE6<[2.V)K914P M;)OAL= J(>D^LZP?*@O+(.GHR.F89YM#7C&"1'N*L\0K-B>.58[IDC?*L;;$ MAY-<*QX^!X8)$<.:=L"U;,[@CCHN\W?"7&_CYB38QXM#6KHA5M#8RYP!R==- M)>(U[-90E2/LCL.(%JP[1>>V!#FN7D+Y1*)L0=&P97RDF>C>," *XJ>RY.@L/=I*&,AKY5D7!]/]@M8\UM MU;-F0M%I&<(K?3*7%F@(ZVQ=_>#HYU[(3#FCNZE MF]R4LI8>CL#.J)CT+)N;9I^%"H[E/MTV M%UGXGB7U;7+D2 3\ICE+U*MC_@_0 D\=-S"FL? -*GOD?1KWKCJ]XMD\FID- M17PVN_T&54:A^"CVO@.AHB3/1S8]TIV")EICA\KAOCLD>%TV6SE6^-R2H)DZ M?8Y C"2#U;5"O%/AW?H.%H52G<&&I1DJ6JT=9Q E79U MV)MK1RC8CBV@S,.V+_F64NS(6E-A3I>94C@G%L&A6\NVT?'@T\I0$Q[779+X M\S17Y/RFG/^@CXTC8BKV20YO1Z**S!.W?\O\I[/W*=C6$IP'O>4R2![]%I4 MKX_ENQ,'0P >Q[E-#"J'(!()C-TTC,-'[ X"E&GF1H9O_F&Q'8Q+@",/AR-J M5@2#IHG'P;Z(;*3-8>4"9I,O2Y,CL3@!46GLUW3&@9^1P7BN[+1]@?*O.S]P MV4!C%Z6$$)94V[!2D0XG"0C$6?.,+<.TG4FF78'$J=*V_!#>L:D;B2C8-,G6 M\Q(D]K27FJV5\Y84@S@DJ9-WJ^->\4S$Y4I*V-V!V^7?HX3-EN4PG"=W 73! MUYSR?)ZU@.\P2OG9U'N)5J_832 R.8>(4XQ]L8<2U=GJFF0$+';7.5G7+3V8 MJ%U35\H\.1!W% M$WO:#;1"J-VL#"? M*<,HQ.G#%2L32K8*$>,F6!SO?8#7L9">P:^ X]/694( M%:W:6[FKF!H"S0T8.#E;Z;"F&MWH2- K! M'SM^KVM*37>Q_V'W'@5 MJ'*"1TN6VISHW!@=MV7;F/Y%XC80(8MHE81G4#BQ@'^-_VF]P^RV' !F(IVK MPL1(F&I&+=U]2P7GES3*UC[%T66J,C&5;@(R[5955XV!N^;O#BO@"AB9'Y6& MN%JG9AEO [&H7YM62620WS&*6(/+7]_M&9@[8)H8W0-S+KD3&]]64W+A?(S[ MG%)D)SN;-AO_VP.PRC)"[5K!/6!&37-/H!80'H0M$X)=ZL/)/D<0JX1C=@;; M/@Z8/&W_)!(&!G((;('AX\$$A>O*$GLWY]< &<0H]Q4(M<2(G$!=WS.LL=HY8$+;A>=J9@&M(S4=* MW),<-E.WQ![D& 6TJ?,!TMWHQV]=AT$ M]%$Q&AQN'AM'3XT]8?O#"5/X(LFU\5R2;^+KKS7:>RGNHGA6D5-0W@U,"/=[ MK ZQB.G"N&QR,TL#B^DY,6=\%#9X9Q%FJUV5"'GGCHGKJ(IO\) !W3O!/K S M 6QE&I7E7KZS#6AKWW@#;?"UM>71%[GHV0RX5.EL,.V2NLS& MB9.<5BK6)8X3+DP0L1M^N:B*H*8"%^WL?I+MP(@T.)[LR)BMP_@Z)PZ,JP*W MM$J,^$^)%A^N!WM6DXP'!%"[/ &[(8@MA=QYO]JIBM$56:7S:N+J[!0<>VBP MK;OPIQ$Z'<[QJ08!5K\Q5%G2,-85]SV)4#"FPP.Z4C%\9I"W_IR+I?!V]N)F MASM:>M[5!'?1_6WY7D);&2@-5$XVG(+/SK@D?.RFM&L$D[H;9%Y#9 J\Y8-X M.("911!BA+'O<]^,:XA6/4T$4]+0#%N?60;.F&VQH\;%=\>'R9-D$6COILV/ M2WY%0!J!]\G&CL?&-WF"I&@1C'/05<*+5G6O<\A,E2T(%^=T>,]DK1P+?.#M M=&F2PT3:8,Q )]RQ<8SLU5^6#Y3B[R4^'"H9AR=YZ'F 7AXYM&W!Z M'^C)Q5J!3&;*9>EG*[I?0;\/.X>P#^OI>/0T&ZAS="Y>VVO?!=&4]#YUB;AP MB=@)^]H$:^+ED;<<6X)WL[.'"^J*LM0=6#M&KI17Z$W*=F3VJA);#SZ<,/X_,/(1ZV7." M6ZF*UME#O.VW&A#.8P4S_[<=DD^[%SJ1P X0;)-XDWB3V*'5537FQ*ASP8G# MG.#>L[I\YR:OVN4XLF(1]@2I7@+HD0&KJ)3169D+D%JD(>MF'7*1>3HFI7G MUBPNV,>^G,V&+.R+^IV'87P.NSQ*DL+:T2_SN8@B.4CCR56#4,HXC/BI1A5[ MFZ5HJ@+)2+"&O>FKW:Y. FZ#,1 M:DBA(L7VJ*65I##46=KGT(5]CALZ!H:+4A=-'3L.;KX4X(M2_#;00U 90*X6 M0D6%MC8[?N^[6T#%"'([-@;=8C;L["WA2P(O'5*33Z?_KGZX?74X1,RG6.?& MDRJX1,#_I;WZPBU)K;D55[4\#I6-!NYED!SU,AN"8G"1]X.+AK MQ=K>SDU#8MLSD?JC.VN6;&^['W"Q6>H 7*9-HA.?$WG$A[)>SEH^(*Y%!'3= M:R#Z/K9':19V$7%-KB;MI*6:=AY>0 HVE,2ALSL>&23"J19@B^0W3;'.PQXO MT^=MGY+VX??.4^K8EK3<( Y59_& 53(*_HZ(7-$*839A'QY/ S/4I MR(C/.@@1";KVHKW&X9V/G99YD<]>T]$!E._@P+5^:ZM,BR '( M.#[/>K9MSU&&=1PB/O6Q<&3]WF%AY3L)VCE 1-N+77CUHLS5A^)8Z0/.E!KS M @/G?FJV3\=1(FBX.$UTX%N?-1UCG7Q(8XX)*.XKK"^@,X_54XQ+"K:8+:/= M#&^;]4VVJH(-ECLR*.":6@I'HO7UXSH."<%D6!W'=#[X;ETNXF1\8V=?0AS3MEVY,8H@H!JP4&*,X,V0A$, MS[-ODP/^R*N6NG5# '@O=N "LL\E/$N@(^G_;;^S79+J#'&+MC%P_O$?;)8Y M"'/8M&V,<=OMG=0+PCE+CC8E5@,L[*ZWL^)L2U,(IT4QX/ ^Y&%X9&5.(B+E M$/NU.Z(DL:<]OAA';#S@D/BU%CET,!;@E6*JV";*/,:/B6GND[B[4G];L MN58@E21>)W8^:4XRL*D 4("?QR3"$U@7W!'??X_%P<+=J4X5DD$V,=7^I3YB M6[LZ8EF&7TEL@4]*H.&K13O25\N<(S.R7(O[D$!JS)05)@!-.3?EG#CGQ0 > M>*!T7)!3X39_:':PQ3JGE()RBLS=L8RW]5GN(/:M_;K['*%5N#>L&PWZLW>3Q9X%#=A M 39<&:Y7D30LJ"4[VZ2E)B/^4@\+AWQA.*-4I,IKL7@ *HQ2=&%YZFIEXD1D MC-IZ;_9!=!4\3.\Z?8!#M?4(UR?WAF-S9@3P,)HB' 8GOH)I M)8P;EK>!?+6NCH*LE(I1J7.>K ];LILKE2;LP&;QR)-62]T'%3PL81)^;P0A MU4E3_RD7DS+<3;&680:..R!>","=,.0BCZRG8ELK+RE=R=[T'E%=D(@3+B#[ ML@8@I+SA.#6>R:*@24L7*BH-^2ADHO(\CX-X4H]%G!+Z(;6!I"_:2]4'EP"G MK'\\K3TM6MR5LHE\KZVK65W YF 3\",X7FDI8F*2=]9O+^8\;5^><^Q MU,&>K;1;QL0<@HMY]E:-K\6G)B$!#V!4=_JN^)3:0FQ/=@*UP&=LP6>)H:^B MG=[;0;5^+AK,'1=4',&[V+]%;@?B\97=:@#TKL$]"3MZD[I,P4!LE&4JP\^A M&JLDO4D1#?NSN3P"O&!((]5!OKE?K')J4N^:6+XPZVPRF2GR:0*S'X]*T7)< MVH7 GJG#J/3\T@NP:\/Z&MKF5^^]R_5^2!5!8*8[/U1B[S0]LITE(.E4J)J#+VL[\9Y4(3C9[6B'LJ#%O'>6D-81 MX6'_D01MQ.W63#C6PWE.Q<(<2@[7L[S\*6&+G =V I6+0.P\S!";8,EWMNN: MZ)#3'( 0:_SIEGW9IK'5R1ILESY54+0)4/FR;)>RK#CGEKY0"3I39BH8,_C, M@S@DK 08"&\-?9@H$]H&A3B2J3> @".[^$\;6L%!!."@;6=09>WF?/ CX2K6 MI*C5>VO/F^2*H%]7:P?Q$FW6)OV -,[2B>":;B68B\UV.Y32P$PE7F-,E $E MH'"2)*QU5_+X=.;=8:1#%57"3Y!5DIDW,12UVV9JR-%I)C@>>LXDG+I$?VI%^EB:I,IX1G*V G7=O2@2, MSR$%WP)FY*:V,R?9.4JL@F0+V4L;8<1QD\F2Q'4CF M)#NX8\^G@P6.9$=5I2EO*&X:_L^%2#MB]VT7V:_2K)4I'9UG+F+(OG_5@(,I.' M?H*IY9V&BWB80U\3[2QGT!KZ+-;9?5N<6:YJ;% MP0$D;U-P?!1AEC5^0A5[-(OJK(I1LN5E70NV[UY@#3:"C&)WY%V3W(=5>&SX MM34 MJ@S2%@1O7=ZV8-$D[)),W2<65B637<4"91(PW YA;K9IF -HMV/DZ;:SUZGE MO"2*G+7@9.<+&Z,&V%E8!>,%3NNU"HN8OD?>X/LAK$Z%0ZQ/"11A =PX&^,@([/MDVTDM_XVM1F11^2,W.[$.BMLEB%4-1K6CU*MM85]C\W?#P/SJ)NIYWVW5@'#/ND8P;K75@B MU67C\D5XC, O8">Q@HYXVDW/8G*0"R#VV=EZTPZMS;[8P]&[86$U9AM)'_D$ M;G.UP4F0X!2QRNI$EEE M@+:PORLB:-\-3VFQ21!W@< U"C=K9 ][ IGPT,MV""T)/'CY+$;/IHE^[*4$ M3,@Q7"1,8;='O"KQDE+4FJG3% +@ZW;H%OY"8CJ+7R<8YR/AL[C+V]TM2$23RAI^;5+MJ: M#1!#@BOU!65GN*>\O]4)O>K,R+ )F; _6D2_KG-[++9G+LS9*EO%L(($)Q=> M==K3R*V;J7<&YVY2)7#JB:4,K=6(LYG-28^NSM&F,[5-=VG!\' .H[J0ZA)O M4H!8U;+[,DQ335;*5UOR[+.-2KW*07 MWXVC,83_6'/BY/WJ:P;[D36,\S75@+PEO;1K:Y.I*)^8Q%L*?6(0M>,\7H>D M:]-QLH[MDAF : ?(:%)3!ATKT<3 'IS!Z3CO=7'X78';6^I3#5\-D:#"0;_CF65 M&-?]PU])S ]&AX=CR/=@*Z59B5. MRKCT#H;<3^/%6=\^^0I%[=-D=^+F?'FTK00![P#Q'I:1\AV\ 1EACG9H?H10!K6Y?]9*KGX<&+ YT2 M3623:6K"XN_.51UUKIZEEW?7XA*!B\02>3QA _013R0)BME2 &G[=QTBD*!3 MAC+P&G^AR!H1I.H3&>J1H\5U:CEXBC;TZU?N$99!DPMGE*D&$2"4R& M,>2.=H!9-JQO:]Y,OG\9J )+X8*+@#5>6U!P$&G+?)FGW*8_X-)FJ MJ"?81X('\^\\5\E!'J)*[GWE3S#Z(Q 5QXM$A1ZR/IVW.N-$^XK8ZI5)O4UVZ'%):$B%>R1 E2M)WHM@G=6I@Y8&E? M@5LV(IME.@^@E1/S1#?QD8U)CJA\M4?CQ0;;^(6FCI_ZY4X/WX?=6]GZ P8S M7/:,=8NX)7-TOS0%@MHDTE7-LLVM./2N8N9N^Y]CO,XB9Q"XW;E+ M-^@PXR%=B#.G6:IFVT]D71Y$%41K4B433-+%A?G2Z.>CB6>B;6 M]#FD$;]Y7%,%GW!*8_M(7B#1W!?59L>_TN:PS9 P5Z58*=$O3GUI7"8')\IU M;*\YYV*YP[K7B1US+W;:F$^M$4+9AG28#S-@LP@'IP96J MS%U:\"P$/G< MPW1 ]' 4VPPG,%'.P]+#XNF,3S0#DP%&VV$87B6ICTLPRR%X>=0J1F<\PR3*[6QM.]84H,+/ M-*4T;>["9//K?7&.@M%/8$5U[N!H;8W<;1PY##?N4#&P_4KV(!"$$4.*7^P7 MLY/-.O/.?BJ2LD:5>SG,N#A5,VT65S#U/CR*;(AI.,MP"=1V+VC6][E# P!W/B'0*^ MS6@0+%H=@"':D[@Z&2BTQ4E?V* 249O6OA2R.!QJF])-[4KC<%J7 *'&$H<7 M+"#Q #CRZI. (NU^4-MPMZJK.H(Y;^TVT\TCU\V!B MHHT)MU5'R^!9&JQ<5D>:@X6M;K)U-K5+"*XX42 @OD:)"PS8#LY4\%PYI*./ M.R8 I^0%@+K=IKG5:6.[I7W#9]^"[2U9R:7I@66'25SL!)]LZD1!CD;8'\@] M30?7LWU5*G*F0Z7!:,-3,&'SF6+Z:HJR$]F M=#(YZG;6+ TL9<;$K3A1ARB.K1-LE$4'7,T@G*Q)9N6'O Q$3(>4^02'67)% M0@9%A2Z.DT5:Z3XNQ74DAXE(Q?6)-C& M*373,%5FN6M)>^%/61F;4G@T6P*H+QEW8%=5/J]&Z27MDKO,;X,WSFO)C>/U MOQ AW,1CM:[$7FF _&H&P/AIDUK(<7?\["Z7J(T\YE4<3R6^QS04]CS?H794 MS 2X1T]141D@HY>'%P56JT]J,XU MS?[N4I55]_XTI6L&M1(($@3.8[/[2UW>RP82)TJE>CHKZVK34N23NV.4#D1* MWCF!TP3"A^?#J4:G8L7$;KQKPZC;"U&5-#G%8ODT[>5QN2U:U47)OT:&):!I MJO!."Y^7J<=GE=ADTJMK#B4>EZ+:1*H*7['P0:E+Y9&D,<6-"Z>J>8Q332ZG M/%I<]FXCN,W 29X^.W?U3C;.G$6FE"%D*CA&4[>Y24PA MU:6C9QA##ZTA:,=JL+SYZ,7Y9V+5FV\XI(F4EL2W5(QR J&PP/J9FR8P M!WQ:9U#K9[*+GFZK-4'-XX"UK7IL/[D]3S_PT4T/P)/<')F5D61/2:E8/'=_H M;+:S$^O"'$JUZK#=H"]'G#AZX!XPX2.#IN0!F:^^Y/F_3Q-9^ MY).5!LN$>9:*/2WEP$>1GW2RJ!Y&+Z@!!OGVV MF20"Z="XU,&J;58_DPD\U]DA!QL^9&XOEF#,OK+CHIH?/!69GI7'L408J@5P MPC0%Z+#DX3ZV2,Q%L)&--J6!3L\A?>^PD<%I+)G9-;[,EHJ[3FS&V(CQO$K!C9>0:.!4RP.G5.T[SM8L[&5<'_C#M+SL8 M6W<N);3I*5RW*%CNQH\HF*73'ZORT'IK=2$'>I=TN[>SD%QNN@KPOVY&S MS&^WY(6$+&U4S#;+9(@7Y&2Z;G.F68J)HO0LV^I4Y5=%UHS)5L0"1VW]B2"1 M1\&VX,DHBF-UQQ[#,&V;,RLXKR42SQX%\>'RGE.6IR:!)FAAB:4IS72FX[FM MC1SJAMGK4&STWO)P%D/QW-O\F.RF/,V WX]J2SA.G1Y"Q*0415 OY&K+U7%* M>$ZKO7*_U'&;$D]@1'83!@\8')Y2/V,P937M'^ M1L,&X@HGU%6@V%:F>'\I-@WBN>6 MP7T'V%=+'IBGJVT/L V'9@NC,K]JLSC+!,QUS"F8YJH@(F[7(O-4,>F4I_/: M)=7/CA5C]G0D.F'"?>4^S+5GB8,)JQWEV!V3*#+4.)TQ2]X7$2:NXFRL&O&7 MVI 8CZ! D$_]!@5UB;KPK)?]0/@Z#$'7,=T2E85=S?2"79N6KR7&#HN$Z=R# M)4HG^HX ?K@Q@W6K2M_B>Z,>\K 352JW@^"@A8N/'4/=M?U\B"U,F_!M>S=1 M,J+EX\ 7FS U! H;QICW<&T/'E\IA%5SF*?D+TH&ZK\=%N AA'DZ1HXK=.0, M<(S%8Q-Q_B4)D0=9[1<>B[6)("515.= MO>[HH%0E]EXI+9$59%WC)]/'!P("&7)E1@5-]MBL[;=&Q][(S\0V)77:1*\J M-129=9;?E*(%$Z!@ 7$&#E2BO>$,$_!Y.CABQR2O#E8H$)5$/=8VN/HZYA948ERT-R(D_PV%/;QE#G,S-8GO3 MQA6I'F3+(H<.E(9EX(5+$'5D;/ MS3(:J&,L%%HJ=ME(3:0F0=S^__ _V__W ?^O^(!O/[Q[^_FG3]^__?R/V[;] MV9_='[][/GW\B7\;[W[W_J/__I=OYE__;=_^[/_W-W_WY^=WGW[SSC?_//Q% M^/*#-^$O=GY]?G[W]J?WGSY>;W]Z]Y=OPG&$-^?/OWL3]S>A_F4Z_C+O?/R; M^>F'/WY^_[O?__3FW\Q_ZV^U-^?W[SZ___;MQS=__?:GW[_[G@_Y]NV'-W_W MZ=OW[W[ZXU^\>7-^^/#F;_V3']_\[;L?WWW^IW??_<4&+'_SW?MO?WKS&Z]R M^\9+^JN/O_WTIGUY^[N??_CG'_W3N\\_'/SQ\^_/NWW_OQ+-.O?OKV^_??WKW^>/O_S5__CNRZ7]];OOWO_\_2]_^E<_O?WP_MOSX^\^ MO'NS?WGK_8_/^S^\^^YOWO_T[>_?_/;MAQ_?K?????SNEQ?!LJU+^&8]R?7> MW[Q]__&GO__C#__R:?[2>AU>7K,HG]__X_^1K5#JF[>?/[_]X\:>X%5Y\]_"F_?O_]6]__TUOQS3?7NP\_O7XKO?GF[W__[JNW M\IMO_MW;[W_SW>OWRIMO_M/[5Z_KFV_^YO7K]N:;OWO_NZ^^K+_YYA]^^/'] M!_;0RYL'?_?[5W_8=M[X\?4;7-!_^/[=[UY]4N."?OO;5Z^YF-^^_A,NYK?W_[3NU=OL8YO MOV7GO7J+R_[V[>?7]]JY[-]\?O?5'W+EW[_]]NM?X^H_^YQ?WN'ZOV7/?OCP M:A$Z]_"[=Y^_?_OQN]]\^/'5^]S*VU=?<7 3GUZ_YO(__?CA[8^_?_4>UW_> MKUZ[YJ]?<^7_X9=_PZ7_^/,//WQF=5Z]R\5_]_X=;[Y_>7?_U<;[Y;:+O]QT MZ5=;+G^UX47 M&ZS^:_NK_:O;ZU>[Z_CEYL(7_&)OQ?#+K17CKW963+_86#'_>E_%\J]NJUB_ MVE6Q?;6I8O_5GHK'5ULJ[5_MJ!1^M:%2_%?V4^*2L6D?WG[_\A87_9]__O33 M.Z[OBZOYEY]PZ1]__OXW^JG?O=QV6FO//7Y^>8O+_^'=YV_??7SUU]S#V^]Y M]T=N_>7=XT_?]O5796[GA[>?WWW\\.ZWK]X-?WKW%[^L=?C1C_CQ'U_>Y,Y^ M^/#SRZUF'\:GUZ7QU6X^I_^R\O/"]?]T^\_OWOU&^[V3S^_K%AQO[]_M;\*E_LCGNM? M7FL.V( OUXJ7^N;=5PM1N-2/[U]?2/>>7Y_245U_(_O[SB6O[= MRRNNY:]?7G$M__[E%=?R'UYLGL[TY177\K^\O.):_O;E%=?R=R^ON):_?WG% MM?S#RRNNY7]]><6U_,>75US+?WIYQ;7\;R\&EVOYWU]>+8/U]MM_?/?35T?H MB"^G^^L?I'_Y@Z]/E[[IV_>?O_WY^]]^>/>R'W5/&->WWWYUR'5/Z^.__FQN MXN78'=S$;UY><1/?OG(30H)7+]V!KUYZ;%Z]Y)I?N?&=*WWE0'>N\+4#XM)> MN8&=:_K'5R^YJ%?N9.>J7DQBT'N]0A"ZKD^O7G)5/[QZZ5%X]9*K^OSJI>?X MU4NNZJ=7+[FJGU^]Y*K^Z=5+KNJ_O/*87-4?7KWDJO[XZB57]5]?O=32?_SN M*XBA?WKW_2_>TRC^_/%W;S___/V'MS^_NC9=U$_O/WSWZGGHIGZ%1H+>ZM?( M11OSXP]OO_WRY[^&]V-\^L-_^W.0[O_]ZU_\AX_OL3)_=6%B M][T=7X#^MS]_QB?\M.(I;O&?7__V/8'&NW=_>/?MMAWCF XS[J$\<=HG(D_J MDZ<#6+&T81FJ\J'GN,ZBYEN2MWY7Z6QV9W>J>;W[:O7<>NNEFA*Q-\XAL\6Q M?2ARW=7[Z'T$51N2Q.+[4\MM,[)T/WS+=&:B6ER>9=QQ>Q27N[I4P-?%WAG% M.50E<>Z[%JF[BTR2*0YE1YI->U:GE4G+YRY+ZI"T0N)'E4T?!WR;G(.7=)^J M.(XA&4T?Z7:DWDRB&BZ2I=M9:IU_'#:9U>$@VVW>62*3S;JIE$DI2E%2KQ[3 MJ@Z7\LAS?972U-N3S%2ARKA*L4X:W2J#WKP^=WD=8MV;Y-6EE];T6$;528J;;S5N7XD&VZ.'*Y)""?OENBREO<[S5V)P7#2-?* MGIU6R6VB.4N]]B:=WWY'ECR:[\[[J307CSC?=^H\S)1;>$;IVV-MY509*P[R/PEYZ[MK2L8]MEQSQ.NY+ M.8)\UI9S>HH)VM"^:#39'7+OT?ZY<@8VRRT!PWXHF=K\\-$K&[O-:UN]X*J? MW"H\RKOPV$Y:5*5SD+1?DL;R1/(1FH1BY:YYS*2DV=-8/B=&FK6]>XV <,'RNFS\WSTTN416UW5D.:Z'BKR<)2#OE/MM$5OPLS MLE$#^R;&,WZ9G+/VM;/*$W-RQ".=N_PJQ4I1[$H1'GL)RL\?G)K.=F@6R+L# MR3*TGVSJ$:,=HCWN4ZHFSD-^YG'<=5@#'(H=SG2,6SV5RR&5QZECCUFM6V"/ MQ!JP"\HD%.696Y74*9T.?]^J ,R1G%K&A&K7K6*"=1'%FGV?R@O?VYE5 M7PW#:7OFW,S]$L=SA1&UKB+JP2#T7H9%5ABTBKB%&<&$=' M)[@)A8^.(@G4H:P@)LB>5)]T6$U<;J>T#Y;TO@\)A6*P"'2I!/(L'A:GHG8> MN[(L,RD7_+"HUQ*@?Z0M:V)8C>FQ&D[JCJ=S_)YE3;(*>H1.3$M39O5Q2Z7 MOS1WJJYV)\"[<@D.; 2L3EX#&/JCVPZ!WK(67]T[]7-&F;USE9BCU!5;ZE?9 ME+RTR_%1$593*FV!DLZ'NM6U/9@BI5!PN%EZ^#L]JU*C6F%W=5XI2NZ7DL"&>M&%W8[_BCK^7%4:FC2(-EEKR MF^VR7&5FV9*#^O@03GU4 _'<'9UDN>39X9@6/AL#(K'W*"VQZ:P?<_RP6%*8 METT^O3TIX*VNFL,E+2CTU,]K6#_*^Z[\&\XD5*G=;U8-"P! MR[%-&81O_-U>;%S9>[_R8;'6 V135%2V<'?8_F!'6E2\'^_-]D];SL8HM4E* MHC1&]+!$C#.?EZ+C5A5[>H$^<.S-::I%"L5]WW+)5+:X)1U,>+NC-D/F\G/- M*F_ "353P"^[M>QZXMP?AY/UD\I'2^LA(0J/-^&#X\)U*)!7[^2J[RVDSQ]&EWY&*782C:1EN?ER233G7 MQCFH5G@ES9*PUJD,K.=AT5O.V:4>-RV'RY&2I>MM34AX/+BHQZ^VRY*CV_?M M4K+W<;:V<)C8N%G2K+,D3*O[I+8JM_JTN"A;;Y1J:LA46YK]X5>5NJO(7U05 MBW>0@^MT6I[K4U@+YY8X?NE92DHR];+Y@8WC65J1N_/("L 7YUGP&1;T\-O; MX-A7Q5\!'1,_(QH%=]G;>GOLIMV!'J21)"@"2/' )<(/*D8=IU2D'*#K:4_= M#I5TEZ3R63GYN&P>Q.K7PA*5YZR.)H&J#_"'2B!LK@(.3$JTE@8&.4#^#I/L MF.UF.^;H.2HO!I@6NV _PL3%WSZ<):>+3;Y4W)!;JDL+.9P$X:>VF6/R6&"W?%.#E:8U^JI=%3_Z<_-G6@6=]FY+GL)@E@^9OND51_$KNK&NF2? M&UN[J!%6Y40JEB[[^D?6)(7G^!5"/'[KC+WS^[/>[*OL)E%)KPO*O;(E9$-J ,.9:Y.X 35%GLJEGN]G _U2:J0[ZQ\ER+C#Z-4;$HP-]+ M&IAU L#.*@NFU;8QLIKU*(+P>[BS4]"%O "V/NQK1*(\E@(YL[8 M*9OZ65,T#U8HAR/1IU(]ZCPI \?6"$O4 [3,.DL8!USELX-L-QP3O',OH 4? M_#99 5MJ;B,/>Y>G;4_JP^^D>"07<$BO)W5*D+2- MI\;9E(%=)?!L?UB,-KFP21J10-J#MC+*$X&- Z%$OHA=7RX ]N%(Y:UXMA5U MT/6]32G'+L( MF(]N_]R0/EOZ5_YF#+UMQZ<' [ZH_XGIS+(T)>48L3M^.SL$? HRR!E$P_FGQTH M",*CVVI_##M!1__3T"P@%O\L/]>*H:Q-=/63BK@2KF M.&V2HY\*U]]AV1]9E^3-!KMV)E9L1?89L/-DUB_2S1%*8\Z<"Y(V5")V923< MDQO7)"-YR^8&JGH/!^;#SE>E" E.,S&*PFN$?^R;H73CP98FQ'.VQP%^T"1! M5>AE"R)D8.EB'AN[LQDVL.V CC'"B)K;-M9G,4]\50* MSJ38-IGL) -!=803;_MG&0W7-_3H" M7ZV.UC9/66NN;#^@U+LM$M>X[8T<)213HO)IBZBE+KZT9YA]<=2\J^'T**8 MML=4;ZM)5NHG; &(3L)"6QQM8)2*8-LUX,Y2N668!M? 2>RI*" A&E,E :CAP='WD>[GCW>1TC<>,BW(JJ5_B MD'P$ALJD\D@OY:"1LX"F+\LP# ?4#^5]7FNPX8JS)_4:83PAAXA MVQQ'N*-S2WO9E#)(*@QY-G'V9U Z2Q4<9(/"W785U^PFY5(YJ$!**8EWN>HN6_B'4.^^ M59Y791C''W>7%NC%Q=J ]YSV6P-895LCGB'>8Q5#E&_E<8*B?Y%QNY1/92NE M:[O/2Y)*?/#D28$=P(TG(8R6E;!*"BJ[/%E?:='YKLL1'TSXK@8F$5#">;$1 M%=[:EHDP^^?<5<> V9M+]*'8IQ,(PVG4(@& NEY*NZA[,!SM5<<'=4DO,1$;!A*0T.;'MD768NBRD%+LG4GY_QX8M(8SF:K[3JMGJR '5.6:J:(F*QJZ\]$2M[X89&2 M4*I1HI75=8NQ/ DM;F4_$ZBYRUZG:(,G2&'(KO9A5W85MW0^YR-UDQP$<2D3 MJ:$2);Y6>)BC(?,'NQ1O:BOK<.#.*?]C)? E&71V@-T^B(S;O0#7X&GN,@YD ML!J@/IAA3N%4Z*U+1,V"G=C=76G'$>WP3G9_@^_D$'^Y7GJ MXA:PGW< MP1*>7Z<)_%->V]OY4JY!$1-G3W )4>] M9N N]]?;N(S$L\S.13\]"AA(4:VLPO$7*2Z/[-6N& 1'7)+ZL(9IHVP4SL!SL04 /(&(A]0ANS1N>5%Z5&EE+&6( MCA[#Y'/13\CQX$$/3HTD(DRP\6(,KB?I]9&6FC3H(C@M>FPFQH@!"% M&)2V4YE=#4O'Y<,NT;\<>[IYD/))E,5>.+/<7,?E20S*I.&(9,@)16]QB=HQ MUD&9*$MLLN\0_F7I=W1U4.\+S_+( MKW=QH#&TJBB:_:]C:; !'DU-'C*-2)G9KMTV]QA5F.;'6RO8X*?7W:P)QP*_ MIHKLC97L.W[,B0KS#YAU_ECB^_I4Z4,ODQ## \QC,ZEYE"V;SI3F/:C+AW,< MV(LOVBZ8>_:^V43QGV* CUI71#OX(/G(,!85'\""S^3PQD8 )L\FWFI%Z*87 M#'[!-Z=G.<@DF<4&:O+*?!;#DG^0T"L?ZF@EH#T'!I.WR?;X182*"+4EJZR% M,S*'8]:-O3<)U+D+)RN[W$53A@/6^+9;WJ#XCCJ<#.C9V#B7;>-$#09!0!6@ MK7-W=J]/P4M6IK%9*@,=EVK$'U@NJ66C)*'2M>'>,8)@6FF;))0$[[,:4BJK M,&>E03IA#EF5FSED1_>BF3YB9\+7X6#RKAZV-E#^IK)]8:N2E(@[E+@GRN47 MI5:;^QK9SY+?J8HB":A58(&S+-N.R1- JHAT.61Q;X]9YL/"A:=,(O#;7%-[ M;/YO:JQ$%04SS^:4GLL;$Z2"KASF>_"<&6.G^+-ECST[LDS\N#B*^/W&OR2' M*HQ>V0"8-J ZX2C45S1I->0 9_UY12KURPU(Y$P_U":$-2JXY9;,YP-.C((P8,OK88DB5OZTW6##S>]JG +T4S2%5:PCXZ75 M@U2,<)A,(2C %CK$#9(-2M3RRPHK.+0H6X50.3L7&)]%B2>W G&S''C3F%0E MS6#=@Z-]R60# E( #1R784.5\Y^EC-4(L3/*;>+5'@ MVW=998I3L[A%X#AP$ 3FQ+,EB7-Q %K .94DC%L[L,%*W3GI.-Y=J3 TC6 M.&(L E:>7S;&53Y5KA(>:B)25"TH#"O=1QE-A0]04)&O6KRO!CL6#\-\VU5" M'.?$T6(A/BU+&'#R2$V<76OX%]?/2H'=V/8J3D?M31WQ\,?X /G%>SH/'V4:>Z(2ZN<1;W.MDD-DU(RK12(.I50C82^ M"L4 L77D0:%:Z;TP1QQ\F9Z(W>XQKJK(M#0G("%PT[Y)Q(;]N8EYW/T9B&M$ M/@-!-\=:HT[(D):N4'-3WZJ":LU,\>!4+U85?(4=W#?S:6K8JZNACWM8=<=5L4Z(;BY0EC7@Z6G1B2Y+]!!L>#["?C>+DZ)-!1&98 M"Q=<3C&GHM(]1G;*6Q"D> @6+Z6=,FE]6 JLYE/W30F^7=;OA^T:S7-=JY\C M5:6O>-!\+'& ]9M7^6&N;,8^&7I#O=#:YM5$!O7L7'.%\VOXLUJ!ZMLH>:: M#/!CT8&KM6 )[Y0[6O%QCMPM:8PJ#3P_0G@Y%^,8H" S##4X<*WP/+N)HSM6 M.C)2\(5D M9I 5Q/+CFJV)LJDK?I60+SII>U7KSK?%>+66.N$Z6Z.LW+.S]AP##I AUQ-6 MX?;1"!?E!=A%( M=V?2>SK[8=*HYO(3;5)X&?-8>XF"L$+9^,55>3>(#>5%5 M&,>/-$<]07@8%4XOD:*\L29]HO$V[K4/<([Y^+*I^:26&*MR8 _DEEB:J=@' M SK[@4["8VO?F'FP$7#MB[JU:NI[0% ER/),3R ]-65Q=[4Q[6'HLC^XXOTA&1GF5/< M92G[!8D69=4E^NJRUWL8)"!LN\"JE$=M2A0G5;QPHV&3)@\RY@.X(:0 S@N^3:V"+WQL\X&T 9M9(YIV71!['U,'2< M"UW6(56#?2Z$[7,)>!R!-..&2C5H2-.P)3IC]+UTY!SSI#J,Z;69D@NU2 MPYU=>&Y779D8+,5S*=W)L9[2,I]/!.6Q#7 ":N!(N\OGY^-FUW85)Y;"+M:W MZ4 W/R*(_V'DB:QM*87!JTHJ@MPME(@W4+/6SSRTVSU(VKG !1YP4$6,HE( M?=2J _W$BE4!(N[O6&R67 *V\; O")QFV1%+/)2MD37J7O/QCZ) 0.Y[*M?9 MAHDH566.&HUI#K7(<:B\VC%\BY9&%CL5_*XJ?YN1X+&R<=7,5>34@+VME1)N M2NX5>!H[7EF="= IMH"-FEVW7([%W^4HL,]L4W@ 'R-!IX7KI!ZXYY$HE'6PVQ$DC2\X(VQ])( R >1L#I?=EA8;CX%K( @27GE)0X8 M*\T"B&BQSRC&%'%M3;YYPR@O34:\3 3=]V>SE$#4?ATL^,G_R=US*3=\RJ&G M5=I7=I3XZY*3DJUXR=#,GCOP/4,%VX2KX;$!D"V3]$-&7EE FT/%>/$=KX[[ M]DPJ/QZ"^J? &VD&)7K@BS#PM]*/Q 0-,$L4 PHR$X(_J_F6VU#U!7;7=)_671KS^61J)%+MU\WF5:V9&2HO?5&;@G+=I_^?GS!,NI# .UO MB;FP\%T)'"P=,;=B2QQ-/!!8SJZA((62C4[[$I7$!\3!#; H5M7Z?Y-M: Q^DJ]5 MZB908=G+:N/AK^V"&G;;")ZK1,:VR$I?M@CP-^6/ =4\NB2S&?#<#U%$.>"K M]@/_8*_;)2S 2GK4DFQWCR0'651?",R3A9*XF?BI4U[2YO7C-(*Y[PRPV6T& MD/-R:3-(_ (F4!]:%L/TI6>W6"<%,)YLE'NKJAKBK#%6(*Y3)0"5L^U8*I*9 MX3HE^HU*!F6)I3$Q,KYR]]-Z%0]GQ$Q@= VLQK2O\EE=07+I*?URAP@*/E;I M]^9&];;@O\ ZSU,-H<7%>,F@I- 2C[+O/-=C QC?2K$JL2&+![LU@5>:719 MIID.V>^Q2]'%/A7&OMFH61!ZF-R_5:'UK(>YI_B?>,T9I] M SM.0UE[0]N[GK*+J@>-QP$YWX\!D3N,%3<94+=[/6FU^_AN2;4>70EN2&B- MN2Y*9A.Q /)D#?W>]@)-F< MF_?8E70\"-,.FR& 7"J5#K 7QH$-DLBT:TGUV7R.-4 MS:2:E.*F,*-"7FP8>Q+T<1&M847L5YTQQZ-/H+N9#K7['FD);5;9U>GC\,RD MO[T6P7,=JZ=\)E$J^V9(M[>X-ANHO7#WQ#M;DF^FGFHT$GQ,=CVHREHW@J"G7+>R2:\Q8!9UP!9U)0V])&ND;]5E>=R M7D$Q!3#(,1<%;.2Y]ZQ$ D?8S.'.PQ2(<<^;S-*2@1/LI<*9YP'(%Z=6O& 6 M2V>K_9%MEK #'#O@894>6J5$(F*5[A\!Q[G92%0+GMD^$VX1Y#!7XYX4,TES MH12"6< 3KY."_5'2\1/:S7.-JG!.U+PEG-@D?)..C9VK'*AZ&3@"_!-Q3F6+ M@Z<>N_H-@VSZEUX?IVC-)LKI!RJ,DNI=YSDWFY%Y"ULOCQ6HEYCY-L>M9OSQ M7')W$L7C# ]V4/_"$0@DKS/P*6XZ[!+1RY7KOA6-=0*^XX )^*-JDH=JA_+: M*;;5) ^RCU39;()Y8I?$/E+=NB90M:2@G2@W)!R*.4/;$XT"<&S2^0==C:1D MN_H@EQ(=1.?V-(,M,#/N2X[ZHD(T?7Y,PNYTG5N6^/I2SE4HGZ2&J1+$)S&$ MC2Q.JQQ "(/MO14@).]XW7*.21S#E$7:*37MMGH7"RU'>S=8HVQ*:#15SY4 MB61\M S;N[4GMY6*A_+N/M/T/"8;YRRE;^]I2^I.[2?A8 ' )>P\(-7#3\3K MO$RN5NJ6UI_"AJ?TE1KY(B'C899>Y>OF9!D >=AK=-J[,:(\.1)8@I^*1E%0 MKK8OSPTTGNLE;5HXNS&K2N#UL)5NJLEH(]%F?V$T>9Y5M0[P^4.YPK8DR]CKJD2=DI6!K;AMF;,(.#830S:@VER'P\'$S34LX>B+JMGW M7+F*WI5%5K>'(#>YL-J:0"PLS1.'#*"Q M'6,W=85G5,@\G I_#TZ)G=:$<'9''MNPC/JHO32LE.4GL$V/LH3;39KEH0JJ M+;U2JTG"J^$\GW39\"ZO:N:Y7@#8\]@"ZPH:X(ZR-.Y+4ZL^-VZBV[!\J>I3 M,?.GU?3=MORT)GB:#+O*0&+6 /7S2:JF%$!+4-BO6W15IAI?G^WD?N3J#VK_ MJ%?A=G.LR>:K)YL=DGSJT4K)*I5ZW=@5)C9P$B9TK>H;M!_851OH+YN 'Y75 MKJQ2LQ5]+)B%[9FP ZI13*,-#$"[MB5QH4U.$W6)=&R!Q8Q9JV;[G8;V0*FLFB;G?K")VFKE#.<29K%Y M3> ;@W-OX503BS#4^2(^&6)78W"K#9H*VUA$%I^IU%SD\"3P M<8;DU.>K'O^HS%"4.^!A;':%1Z"X,J+=,0(SXLRDYI7F,H.C(X"$\S]87_226T0ZY4\2KEL>#,5 :JX1FAGCQ+Q M%H.J4I<[C.&+V)T:K/>SA66N5B\;Z)8]7=04EXR[?#D-YC^4ZQ#T*OT +'R M?+"C3@_':?-KJ3N'>5N[<[V'Z6 PZOXXA&.'/F8>'QR=_'F4F0N.%)SX M!2WX;6I::D$WZ':O5$5=6293N"K%J[1Q$00>D$N\/R6U&1 M>[$&EC0,B?>R>5W54JO"#XG8)N.01;Q3+9/B]*R:5XJO!(>P;K7SV "@&)L( M""*:K65#R9\-],GILOSX:*RC1893-0:6"KN7U4^[ ,2G&9PJW#>%R)9VTIFG MJ*P76^TD9$D;T5$1:9A/QI>-1_9*7!=FXY81TV09YU#;WV6G[X]DP,54YY=Y M"A"V,\A'==..C/LDCF5?G_R[#+B*3]ZFX4[/VJDVHIJA[%9%&0(!R66VPOYY M/+CAF@T;F4@X.,FE\..E>OD5'2Y^'#OJN,U%3'D$0&('PBJ0G!4&"^)< %I2 MMU-5GZ6925 !^,&^='.PN-"D\KG"[( G#ESMMBT>-W'4N!U&KGT-*U_FB-A[ MC[D7GHVRWK8_X>=F%K)E-J^]1KBR!_SF>'AP?YHE D&"78Y'VD\B% [3L7II M,+VVZY^[FL(G !D/,?-2>.&T%!1O@ G@"(+MB\NM).=Q_.RKHC[9DL30SBOMD05 M'OOIE :_R]:,E55='9R\_)@HF]EJ#^"G-% ROP@^MHU.V=_;AO)YL*1K!\AW M:L,,6XLCO_%SARF2U1%YA]=MJN>%;?5T[D #D>QB;1^F9MRI([@D30?AW.:P%FZZJG K OT"0[ M%P-DOFY3N%N-OWXZK6WX$A1%Y2X,R[N=;@ =2YS-'/D(K'P>("XI79O--H^S M93CBV'RR$JMMV-)NDWRE8 MF1TL^[[Q06=.!UCF#$!LPO$PP!@V3XC!YKSTQ:#M.[(.# MD,&=\W2KG,5./PWY>E,*P:S8XUZ(_$@1'>(C M!E#)-*J[M5U$=(0*'<0$1NWJ1S=QC)UZJ@2?%K'5$^)L8/G#4QS(S,5)L%-P M9J,?\1/ /FZFM?OD"@S=8UA@W^KQ&J@\Y8.V8O>%^]]B%9:0AUD=SCUM7\=- M@M,N'L4@J#B%P^9'A55.2@552H+*]G*S:!ZM,!'R\R1.ZS72M9N1Y#/8,!:1 MLL-;_=AL5<.CV=>'[P01V8(X'5E0+)V5#4/5]5/QS#LLFA&NE?\1>+#YL7>' M# =.?MZ;+-W@-:5GG,[2)3E1=S^6T>=J0@S&,^D6R MBKE7OZ:HMJ7MCE:?,N>3)XYR$K4U),5;S-200VKX(B6YVH$EW8G1DZP\"4. FL $XZ=R74[P)%P32X4WY2II2TOG: MJDDLFSBK37S9]LE]M[0*FK4;,\H#[\@9L6.TZMRZRPLJ568++'#>3GIQVJ=I MPJB4#B&_S< J ]B9FIVL).K&!(XJV9.PW8GB2,R!O1T+!'G*,V$3;_; M&;0G_A+Q]2/72FA),936!-MU\D$WFU:6)TV3Q:?7T:2H8GBSQKJQ9W(BR M[5!G+ZEL#KQF"6XYOB\'T51. ?3C'APY96%KYM0U0,+%C6)[),%8$N/$DT0H MC;W;3X#V82BP1(8 EI:N 2A=W+3XV)7.LO 65%=9E-1 M0OH,KA:KFB1_$9424S@2O71_)$*R"<^6WUW0+$$!FQAL'1R&(H@;$3L?MDLF M")ZP?3U5E;-"G'UV@)+1;[+7 ,.-->&QAM.JI,J]4I"]?<<43I" M! 0=1UOT3MWY5Z(Z:]\2Z>N[U(*;'AWGYM6KO]3.8&'5@U:T3L4JK)S#!FJ9 M[V:8LR1.]V%P6I<*ISI1@RL$E=BU:/G!YR+30R(,2KJ%756)=BN4(-A3SV,X MX99,9NT.Z)RBGMUR$&=S)>XL#IVVW32;112EPDBRS8:T 7T0CG"F"5ZC!#[5 ME+7SISM.M-@6NTI)K 5@Q7'_I1?=;KM>$ENC377?)"T)UW4"7(#> )>@B6<"(G4BCOVM7H]5E8U0KP9]OP-= M)X\O6BI@_Q3G%Y57/TRN@" >Y:W-R0 @]Z)NP&$;'N&R8>8#4M@PD,4A22*D MZV;='#&[SK1:V\!W3JJ5J;PL/NN69N=4>$W)E2Y8K.$4Y9LQW943L1OUDK0B MXA>4QTARK-CFQ$T1"CU5U4E;OW3A9>*&E((Y5I-",H-E0T-\2M[*#2R0,*S: MHTO$P_:R(J6JL=-%B@W<HUI+U?S. MT=5K7VJ\G"0V;W/0"G,>)72[.; KJILRTP[K([ MP ^&QFMQHP3%NW)[MFMP)AX3R98+V1L*31N9L%QQ-=\U#@;K$U3HB-M@9S6; M54Q:<%MAJK:%$2P.RA,7+XXX; ML/, YR1]F1B2 ^&HN$H4%_^/7;VX21SB9HUOS5=7Z(XS-R).V[;!_=C8ZE)! M@?4."V.VC@D?[3IQ4IB-<[]#58V5G8[99]&ZM M*GKV."=RCN-Q&"#I.,%J%F,/12M:L?%H3+"6M4B[QXNBR'E*&$+D&S>UHJQX M+OW31\4_S$Y-]2!BZAJ.2_Z%OO1!V;@U$TO>RTKOE1#/N)F6TZ[:P.1@)IX.F&_'WVX XEQ,.^L?F< M?<7*L$D%2H04SRF+UR'U"G;;5L=LX\Q0GQI R88&E=BQE)U)J+:U@-]"WJSH M[^-6I)&'("G*:50 ^J]F6PZ%K1VB=)B!L,0D#\]FF*9@X4'D=AEG$#1H99/0 MA@>H]IMK/@=XT!'!PQ0JH,,$NS,-TVE&_'&QC)-Y6)8PSC2ZO(Z7XJCAWJ9T M545=K\1'W=)='/(M8:D.];$QT&$_;4JR+J9'O:^.*^RGVI'7>H7S2I94-ES6 M$Y]\F 8H(E] MW/%'&<>!JO:]P#:OZ-ICDMI-S[:CC8.ZFS8S?N2T4>USK*I MD[O8T=B*#K[B,KI.U.J!\Y!$0M+& ?MGPZ)TM8\?1P0.J^XR(BS%)^<5XG80 MA41[H$YUI8&ZC2TY;J<,C1&[0HA NBM_46)W5-\V\]6^?4RP2+,,:E7A3%M: MQ66O2O%+LS/FGW(75V4Q#/!W,0 F"4# Q[=,I0X'S:"V'O#V4B6N1,5A[E6! MP?:S.+94=%!7R,41#=THBZ&.':%4=E+V=J0BRPZBRFSOG,8R%*!N1%G X*5 M=MJ0(%^C6I61;YE@BMN(2>:_50N2@>B\".RG;8YM2IXQCJ"MDC? @M.,CXRWT[ MUJPA@6FP;=G>9 6,51X_3YXI)MPDOS+&VN['H7R@!!>0S/ZPD7%=BGS%!^1X ML0,Q5L-NXC'L6,ZF+([. N'AA\*21$$E/H>_N/K?^U!;MSGWE;Z0!"J=>9Z; M@W.@>G8!MUCQ:-?BI62AFO?@_#B[CN";;W_LGE7);5=(MP9U:-EO:8V5 5B$ M[NJ*XJV=P 3.<_T/<6J1J(Q5MADJ=[DAQNU/ +X.:69EK8+MO<9841%WI;*! M>?;N1L<^>/+$SMWR$9O"!2 ,XZI M@@PT6AYQR_AUOUBK"C[E\QSR+?=PL-\,]RV<$[8W.^\#6]5!G":I!LN[15# M:0+)PF78;5#&2EI!<1#8X!',<72C8>W&[6%@7];%?#GM37;!@@.%YT9@M+,' MG*N]E>R23=FFH0@R;J*1X/92H.SQZ4L10Y3A<]E-#^)<3M-5S3K AELDO"5F MJ%*"(*^.14WX3:)9D"I5#3=VK_('6%!R4SQZ,R_+_X30Q_UT)A MYS'>C[;@ED)1[4V\/Y8'6+.:K50]]F#NJVL&3$.DM**Y<9\[\6;>) UASQ6C M*YM-O1-"'P=.Y&ULP.W#N7<<->'8;8\X[A6PS(DX'(:405.F7).^\E$-R7]E M-I190A=@X<..7NRG7!BX$%# 4\HB'+ \OEOWKMK(+@\%(.S"D +VBNKQ4I(4 M3-\$"9FS9S M7]Q;(/VT5%OWQ15T<82S0TE7W>TT!\05<*9O/NK1SN2^!$++O+?=,A#(Y")W MJ@USIOZX$0.M;MN&LX.$X$0G]W[A],,2E0?7U(?0C- /IV@/$T@$&.I1(]8. MDB4Z*Z3K=-[)?A\[.2SALZ'X)K8OEHX(:$IL&@3==H!-0V*[&=BTF)SH.+=" M[[M3I;,Y..JPO?0A/$?.VV';/GMO50,NY:7'&J\+7%^31AB8?&_@2*R"\^EW M/VV=!)H!7, 0#B(JL$DD$)T;)"OU@U]5,O?HX7YP1T51RM^Q9S M;F=3AEMG,LV>NI1 ;XS5655*MR]3\BB\\.YADI'40?LLKZ@T;]4>K.86Z_LM M4T^Q0VL_[K :K);<=;ZR\YP+"'++O8ER#CU'CNLAV"?0 MM<-7UD,K?B9\[1*V8F(CC^T?E_.TNZ2^A[/RSW'+A%U-;C]A8S=$ &Y=!)W) M-/("AZ-(P&BW@=UZ!-L" ,P7#K KFQH]2,Y7-/LKJD1)J0'VM ,6%3#+ $7" M%7"0]BG+,AZCLZ"XW>,Z6"HBN.9<$>ONU#1Q@Y1X+B>OVQ;O-=PJ8?;/BR],$8S;@Y2+2U$; V4&K* M1V[M+JE]YFG&["S#L#F50X^1*K)T24MNI\ONM)T9:SD,MR%T D Y,.@,IHR/ M6(L&E,#49:X!_+@K3 ^ZD7T)N\&>6XU?UG .B2J[5/"C;%>U'UZ-YG/5ET ] M>GBB745MN4.VR7Y7B1< D%5RY(-[(3I(=Y:JQPP1 , \W6;?37.FRE993G61 MQZ79+KT&"Z2-S1+Q[O99.'FT!%Y/,XJ617#:I^S(N&=04+&?HR9G+R18>\3; MGGIN$60A(VLCB LLG>P==DRG8'_9Z7[B(.9%UA380ZD(W6_CYR,$K[TZ7>_0 MDD0=HA5[]GC>7.#@(BSB\-YM=9_X1IKC2&A_8J:;V5 \6-&L5%;8=NO;L149 MQG&/AEAXMCW:!1$=\^61LHN!%Q*3R>8[.6E[E!8IU.W!$EKQ* X6DPF7FW.Y%8VR>XI2\:EB-[=+0.8B]'Q@P"5KPLMO5U&Z];)0 J'*\Y>!S M /"P+,,&4I==JMVC2NPN)]4N7N+0.--E3P-8-ZNE?F\C'HI)GQ::L'1QSYG\.Q-G&E2Y]&=+D3[M@#3[S2QHZ%/I=. MMU_=[-RT^0*386N(,SR*O]HIB:TSR6RSD(+T//>F(/@JKQ M%#QOSD(%P)G4.4!T !V;))P+DQ0(7Y)EG[H%_@=A/#;TVFYQ9 BVGS691R\! MB:4WGHQL(TX^AOC*#G^?=G8D?2#IE@ M(E(@3YR!).Q%*O63_4F(D,&F3?JZ+EO:),0Y.R+0@N0V65/D)TG^D>/-0%I^O M&[CEC*'-Z<#(TFJ( MUHO MG#;(9^GA/;9)Z>P>9)R^Y+H4*60GWF1QZ!UTV)MK.!SK2M9+\"M*M_A[!DNULX/^QUW4!O7F@\@\Z<+2HE3#"['.$]]A'C,XMS3$1D,&H/9M'X1!=<)X#B?]J^J61]\XY;V#-_H21>I7=S!%>P].*6%Q0-@GN\UUJ-C M O%COA-QI8/,%FIP$7;R8COD.DIV;UMS9,_6 M L?)*A+-8G3#I58[#QY#AI_!. UIB;%'2X $^^W89MFZ\O:8"G,S]5$-I"Y[ M$L8J-#59Z*K'E^,6,5-= 6WOXJP"J6EO=3BT>3V#'%EY[ 9G9F=/=M=UVQ$*$4^_BF[\V[90U6#B)5@J]S[+7OR$1US MM^6*"#B"&K722&<=3XQG5FNUH$!2(%,&.P@55V<;NJ+YL9+EQ.VFSCM8;F&"3.,^*K5IEE MX+T)(TQE6V2L!>LDI MV>S)S+JF_S][?]*L69)=Y\'S\ROB&\",' #IW?$&,S^=!(D@(30B)9D&49E1 M52%$1B0C,\$JTOC?O^?Q*.#>R,1$IIE,8(-\;]SF-.Y[K[U][;52GR+RO+=! M1+I9]DO0UM%4Y=)NV=.*;&^7Z4I: _5 ]<@U;SR X&O34^./,0C58:N^$VP MUZL&(*#2,:G]EDSB:$C>';MWPG>$VR4,=H@$(HH4*@^BT:'H&XC"F0PVHMP) MH "!B>3&AK='O/?HRP-+3-"V-5RT2VL/QB&#J?*0[6A""87UHUQPG Z^/M7> MJ)&9-<;O;L\%T-ZCZD>@2L*V^26JA:'?_1HB'3J@ASA;UASTB("I8^K"I6I5T:3+9?EM M?HD\CWK6[5!V1!$\C]K/OI$CI?93)GG&R;/.EB>)AW>HAN=L$H_8N9O9=6ZX M)2L13)=J9[3(VNT$FT">S7UC,7T:"G:V@#GRTNQ!/7WK**+-XFZ>SNTZ0KJ. M2::R*LWAXD?*D )QE-4:0(P&_']8:VJ%V6SF#^O9T5FPJW>E)Q,X5<7VEN5E MY6.-7W19FJQS(.$\RW;K;M3TYRHV;%DNFK0H,JB@:29@4#N4)4FF&G,U?^HC MIR2ZL-:^_U05BFBQ\1BXVO1X;L'Z/]554QY;!57E)/EJ=82X.[[D.1*%]6/W M^'"F.MO(X[Y8C62%33EI4! O;2H05-U'38<#]0ZS8E*D2ADD,1U!$>I69#NJ M-TDAGIN- 6J;0$0D;/-,/5KUB/\>S@-U^^R'0<]I RG["D]-N^:4@L-1\,W$R M17.]R/WR7S=(ISH?OE$L1?Z8<-A?RR,^95^PN!Y/<:(J[)WJB2(C>.BO;E5< M+H3&)MXN*""H\<,JV=*95\./&!?5 HO@^>E,'??\V.CT2$=U"96(#-7W4!3\ M-@*K5,0_@2^T?I!]0^AQTN]4'E<%-B"E\W5J+1X^?R*NQ@EL1/:UTK(>Q6H: M!-"Z'8\"$)%F>6&DNB63?YDJ=@HH+OA0SO:1*_=%!8=@2DGB0>4E. _0 @N=3]@R92V+2 I6W MZ%&9FJN!L^K\E(4U-@%,+S&QMIBB386;/&P3 \#P(6M M&VJTO"2T'-?Q3)@XKVXN\1.\<"WK0;:??%*>]V$C0C<##_/VAPR\5%P DC,M M;BPOPUER[=6BBW;(MSN22(RZE1I$%3BNVATJI//(MV;*_!12MN3-NZS;QX$\ M B#;46<1K3[RIHB_,C'UDMVAT8\GB25<5(U1599G>DIGNY-G: -0'@PI>.FN MLOO!X (6 .SIW#QNXF'I[A0EQ$66?G#(71N'1TX0:>%:5F%RB2;A'.1L*"A< M&0 !/"I?)IWGIX+*?*KAEJ&7(9/0IA4_?5(5(3M"O]*CR@J3V*2B/<"%4D^T,5V#/H+J/QV:&5VSF5SG,6,RJ%H&PJ MRQV!3B&4M5K4F]9 AHB\/Y\.VWBX$ M2 *;80DUG%55'E:99SE@<+VUOAA]*(=%D76%/9QWVHL#)M8/JNONQ^*R:(4$ M9%\V.DJH458?"F2IT&6*BY(P><2'?0[023^RR@-*FRBO"4R1.^3SI4"[I^T+ M1TY],+:3-U7+':902L3Q=M6N9.K5&9UEVXV3E<5Y.5U '4&APPZE\DVDI7/? M%:*GGORBKQ$],B 7DK/X(]6.\Y=YW;!F[J5'J*7+KN-VM?Y0[S0LX[V[*>'K M<).TP/-4'-)6[.AW5OS^"\>" N#8#U7_9W:2@9)M$(TUX&#YSZ&XC]=\JD,( MB'2_-FJI[3I!UBRF9K>GB#?8MF(.5@(/,5V/@W>VOG?/#YSR(P$\%EMUU_Y' M>FY:\KU7'_I#YHMBFH$LE M%$>7GVW:&_ $7CF4YH$FF?!9!Y'@#5&XS5+]&CO+*ZOF((L;%*B 3'0ZR>ID M/GVDC?!ITSA,B:^'XXLI@T>K7D+R =.2F-R3#A^'C 3*FN89CH1N.]ED)D?= M-5+[K9RR6==PW=S#]PZ%=T \Q?>_W#01B5NXEZVJYK5D97BEX<&2@\% M,4F)14O=7>[%C> .LSTK-DE7$D6WOCBEA[9L ^WQ[(^P> F#:K6J%'-=3?GA MHJ;O?BJZV(9J]8&LEI1'OSV )&\/!_KD;RA1R5)TSIY_(-)589.RD=$!& \K MCK'L'[V!U:FG>G+\-EG\-O+MS)H.46_K)WPD"1:56N94(FC-&VA#0 %+BE$. M?,MJK>M\T^:^#&@HFBX#_TYBL-O4EO_Q8DTD7=&]?6 MQQ(MR=(.<[#DYTW%IO!: MS[$W[DXC:6ZW/1XW43H82^7-@RN)$?8))YF/JNDB:*MX ]YGVX+#Y3D2-6P# M@^G2FENR(:3+;:_\5=5"1,^%\B4^(>M%0DH@YBP9#O!XT_^/)[&JDC#9Z!=P MDL*&4$.E1S' \V"KDM2M+A_]+I3*LORV%U^-%X^>"O)2;F(D&X6L"*PK6[\; M!;E38D?6?\E2R7RH\AGEH?.2>C(N$DR(ZL(N9JYN$/1:G8K2W>GK3."E4"8:4-QK">&S3?4<293P7>J1$+K-USVDE MW"@29.PFA',O)PQ,VC:K8% 0*!W: M%;&8I_)<61>T+ MMI;S;ICEYB?JI!Q66#Y;UI4-VE/%! 2W[K6E*I[M-?3PK MO@F^AZ;2Y--'B#?4^+W5!-/Z&+C-Z[WUGPC:&,^L5%&7 TCZHR+7-WY[]E/? M5L4VG/8ZP[+D!FFG8\F1&K,I4/F@9(4>9\IJW?:J*0YL'12'WM78:NIM&WTU MD+YT.K?]/;LZNB MUK.R;1K"5@U>@VUHF_R][Q*E;R73B+X7=2D/N2AI0$0[%\+9+8""$WD0CK7+H)9P0X-8> )7>DL1%HNTU,2B-@ K4!N%V821K2BI[0X?P^I8"M3UD5TVDWB].=M>30A([3VUR@617, M)A59=R)/D]WG9.6QV\ CL +1>%6E$ZR^*/?7I5[I>.J8A+5@ ;IY#)Y/DRWW M[S36[&*Q@T),?L>MQ(0'CJ#WU3'9M3 4+W@(SLO8=5IS.B&,>RLI/T#@Y(@S M /()01F^(*_@2 MH^C[X$U%H%$EB53(Z>=;FC>)&:6J?3535GKMJ_UW*+,5< MPAWT+V15^Y<%Y.&97K(Q?'59MG59VAU!B?U5\!YJ@/I*ZC8E;%*4#@].2#T" M?XT.6=1D[ZAV_>3";I7"N-.J>P"A,K B@II&[#P6H;'UZFIYL91(,O&6D!0* M,4(F*84<'Q2->_0.^Z*ZX,#"?@*M6Y71H9VK1JG/X;P&,'3H@$EI;0A.RCR6$(#GWJ.GY5^6679YM2XQ]F:U993Z38* MX6680R1R-6BMT\^R&-D::[DG3^=BEV2H6I-.J))W2'5WI?YXG"U_U*(JECO[ M(2B@ #JHS_JICW-.X&'>%DF0XA7E5(Q/*G:*1O&,.53&X&FQW M:G>^6[4X#3BUA1%&CLE.]%R,*%7M._=S!'6' 1K7V!_6&1?J/S0*"R44VBD9 MBARC!)/1_F2)\U9U%>(+22,5T9*]?@I(^Y,: FG5\#P;J:IGU7L4%-*TMR_- M&6=1KZBFX".RI'8GPEIOTMP(( ZD.NU4$&A9V.:3K\KSS M4>ZB\^,=*56DEM[**"P[6D^U@X=%E^/??96#ET/!-\4KZ]W@+R$8 ,_&N7@@ MD42G*I5JS<;$I3"9N]'6N7B-?<&&Q#WI?DO3VC'OO+7%+>?ED4U+9'FHPU'5 M%5+8TF^^?)WZIG>#?3S!=7)%*,L':9_%NGM8$;W-J&W4T0H[X& 59&U3ZN%B M:(Y;L=(];W?)/DOTP(DI5BB/*CD8Q?.]G8[.!="U$9UE<6AJ/:0=W!JZ6?KR MO8_>@XNT2]TBL 1]5@?29/1,U5^G*MS&4/)C9)U]Z=NX1-ERQ/^H*1,;I1+=>- $M9V5YU'HY7C+\]2E?*!\Q$WQ:OF\DZKD)7U1#M.HM!T: M8K7FR=.CC=ZS^H2>E&DF?EO;5<6D^7\'NUDMZ@V$1T$ %JZ:H9- @0VK[]P5 MS%7@!/1X'<0:$.41#X7.J$J;/467K MS^6&)A-C>K!+H+H",2,I#5%)+O2GU-;.ZV0!^5424 MJ>19Z\9V7?8Y!HE"%R2%]"D=#UT:=J"'4^&.$.UC(X8J6 +.(;G9G1)J! _E M:YYLVSOD)4U0E7A4BOG4&/I(A[0PP+M-#^O("+K9"(0* NV6AYI(\2S *+PV M#7;W=:A\L=YSL3@KU;$#\.Q:XF.=O3FO;(F3[;@\8-)*9J5$W/OR=",)A>GL MO"(-T]E-9_\=QE L2;W:(JNGR7OO5CK :'6;^Y:D0BN9V6U]%FVSE%\KSZD8 M$-E8[Q%;="Q+._N\N'.V/E6[/MWWBB&>%(,\Y>W.52M:5IMO&J6Z[A] M)8N9'S3G +0*A9:#)FO_N"Y%C+268PT/D)6R2+)/M*B_ (?J*D*6SL@ 8UBB2CS-K5=(0%<,58ED6: MB@P.@9,$NM4AMJ*%YO@)&BE]5:V][Z M(EKDNIJ-Q>U,':'U9<^2]ZMMXF2[S49WJ-MJ32LUIP^,3Z];5DV;W%5A=0H^ ME^CI&,8YL@1GC2@]JCZ^L !+&/8QVQ78Z&J,:X3#B^MUJ#P]CS6\>RM8*.D@ M6VE=BU!VVJP'5^VV'^U96< MHTJ ]V9%%V,+3Q4U)LG#U+ND9N)Q'0O6*3I<9'ET@^>N M ?%M4-1@2]]GR6F>G&8[#URE_#,-/CR:T( JB2^B?>P654V^=P^3=6S=U055 M[:^'KN)Q%I"1B-JSYFP=$R5?;$1#:?M4^$?1^W!U,#MHXE#(R5*,-'S(V%7Z MHNM$K3=WM7,M_?4ZN=IJN&Y@VLO-9^[7%T .OS57SHXA!G?SE**OEJ>&4F.2 M,T%H/(MKR'JZ%$_4/(_B[-BXS(:5-?6(<=I5$?F2'9-9)VS6@ -EQ*DZ(/.+>GD-1 MB7$U<\YBU0,RXGF32B/9R5%C"@YR!I'7TBKJ\&[5?C@;/R\EG(5Z"N/74S,4 MK7*B?(8PV]0+J8"5-8@DTDH67%?,?=GG>12'BP+.HI[9"5!O-G" <-<1/-Q5 M7_NQ\VV_TBCA":4L?++*L@EJCI/NA ZQ<@'?!H]'YRD;3^,,98D<&FA*/O$_ MDHYW8GSFA\4JMK4WY7]OV7RZJA3/M6R5'G>ZEFR3%O(BCTD@5Q=I-=2.W8&< M@\*(RV0K 9J(JD-"QM<52]"A:A85R$AX(;4[#S?.66C,L.BTB[E/'U#T).J[E M0R3$M82F,-P=#]FD5&M8H"FJBKM=!06^4\.9X"%0$$_H3'U%DK^& =R<%MQC MU*0.O?4ZV*GK4Z'5 6;1J& ZBHU.\Y0]93-#]'7^1_VJ(?0C24K\UJ"IXG/ ML9NJC@Q;1D^I;9<0U!3MN@9]Z)NNT!I0WO.:F^*2O+X[1*QZ%W#^D4$]>#D: MPY.<)[=9%,%K>]X4YCX%+Q[NEN5YY Q_5_JV%;MO!2IEH^).^:-AE625/I6_^FL7JSY;B[KJ @3:+4L[2.549;AH2.A%!^UZ:E M+DN?5$P)-57@W/0CLB="ZA0[LRF+)VU.8=N!U U-B!%=2F3EK'B7'@6[*\># M4PH?2B>=""? I=G]2%VKPQP=99Z>C/,^=\GSRK@?V0%K,CXU9M= Z%H*?F6Y MRQ':]RFUYG9YK4VJG5A33$+A.2TZ9)*SLH2 9R42%&+;] M=5&1R57._.^-^GZJ"+DFZX_G])"4C.1Q,T4O:^,Y=%\YN 3>TH- ]^>)E72T14 M1WUVW:/X2S<0[FZ7HGW2,H0OP1)%?8&:RG".U-D)!\VT"V6_--^G$O*L4,UQ MI9B3(;[@)V*U@@"71^M.D4T' N08+@92[X5J^!0@YR\ZV30G*S5O&=$EFZ=O.U5/OD'*'N 3GJY M7R13K=U57=N6@-LWZQ'EE-N@ ^Y03AU@(Z.'=BNG).'W*?ZLA1TJS*1Q48D MTP\@D=B(&L%3O6>=DX]X9\MU%;RT7SENM52[0@&>T,XO+LC=-C2EKGRX.\N4 M7Z8+^9B6"JQ2#\ A/!:(.5)ULZDG5HQP0CY+"3/,,=<%4 MBP+_4V#RR^PM2MWN'H 2!<9IP74 U#17462=^A-(I!RH_3M/)]D]3FHY5:<_ M:,@>&3T;@0YDVK7;BK)^HL(-K+W].F7:A(=;[/J$Z-;J^'.2[Z,YCV]I3 M.A)(C-=6]>/@27NP#$+I*D/R'H>VX2H/D_PHIZ11=@U:E9Q3];/8%]%Z4&9# M5-O.I2'77"YU&M2I'J)JR+G.HI4UV]FIGOQ=MI:R1YQM*4",VZ$MF=(*%^OM MJVSW)B6.8-R7!R*)P.Z&@"E&!3@59B6*EH?J%_SO,"0!Y@9$-WU%-'-M"M55 M=G9Z-NU>)6@_>M"N>0=BGIS/@[]6KR7;5LSXP'$58,[$WVW.("U_!79G.ZBG M-%XJ=ES ;/QN8$96_Y0:*! \GC6=21G+?EN2UI<^Z)>\@+94X0"@(*KT.+2PN\ )8/D-SC1S"P?3O#I4;ONBK8H^;F+FY-11TRJ22@, /W,7(_G":T MS#J4.MB$G9<1X^1I%/Y1IT&P8[RU;Y8O)1OB.:;J$\J@Q6+-Y?"; QY%)Q?R MN";E&CKS'AW"T# N5IMYW'G2*.V(HGFJ\:R6.W_D4):.E<'OC ZC:F@L*:4J M3,SRWB2.4C1DO7ORDN8:0(T2J[K^TTXW*)9HTV/+2N)W&YDRF2_Y;CP&\C'I MCYT9*"KZZ=$9D#L3Z?9G94Q[.,F9S\8GX]TNZB#N@3B#WJ:2F8A]RS:BJB?^4)(]JWS:R MM6F=46<#$-;Z^Z;RJ/WTH$4\QI0T@57W5C&0)H%HMB+]':2@8/S[RHI%/SWK5=]MR;R+3X M8835S5I$R6T@+-5O.A3FOY6 =[*=5PM*B7(@'F>Y*C_-SE&B:OG*GW8Y']TR M*/E(*-JCWTJ6.J1##KDM46+VL.MQ8B&<2R6E@5<20=)#=[EV]A6[CIQ4;J<8 M8EQ'WSSIHF12,^!(GFDZNOYT_WZ1!\VK&I&W9S/'PQ -78ECV8$2F3(G24K" MBM.(FT<]QFAJBRX7>NI31T;)TIFIMDR_PV:CX.BJBTH>0&'-\4K'DHD.RD4Y M0[9Q7W:?M0J@6M.JF!U]6>R6$)W[2XX&:,Q&<-4+ET5$;$TZ5VN>-9.%:&_. M%FZAL"8.B^6A4J7ZY2QO8@*U1-8CQ/Y>TO2X2:UV/C!9X1'Y/:MVV@STN-L= M)=)>,H@DUTG,5G\EQ'UW#%9IQT&L/>QRZYI6LJ5MM47:SFS'E_6QRVG(I/GV MA$U#)38(<:7R#G5MJ-*5;=AT-KH:P_R0"-6#BD%%\01RI:Y1YSI1S.Q4'5NM M4)2H.GA"!DZ/]/5B4E*!5PKH/@ ^R)[->6Y7).Z"?./SLWP*[4GI%*QABZ7 M#F>'Q)7#*5'+N%*;-$V!;>D*[._LEUN QY>6J*UN1*Q1OJ8L^EC&*D/SZ(TL M?34VC;8WIZ?/+)MG.1LE1_4U+C!]4_7U?1TT.4@G!W>W#0QVY>WH'55] >+? M1)JY/*#XPM/[DL9NM38.W0<>9[L(,Q>)[/&T[?"P'TP5AP-!9#+]B(LV\)2. M:C.P6(5]X%V0&HLIZPQ-S:@I9VCN@**KU]T\OIG\D&Y6K-JDQO&I%@20:JZ7 MQTMW*.JPTTERK(J6VQOMGJ0J2^?YO)Q6SWI(M4!>)V.>;E.ULU((W^>ESVM0 M2'&U.BE[56OB1E6L+*0OR102%_F*HODWZ-,\2JE 4!N$%G5#BHK+\AQ/Y0R5 M!W_4OEXR,LX\6(031%OH9]0_8GF-9L7J2E47?C^7G+(SV,"2%G4MT3A\G?IH M4GDJRVTI>@'VO:6H(=A^ KU$J9=F!:"P-MGFQ2$)X"48U8['!0IG:7APXE29 MR@1&:$7$V,H\$C$ J"BL$1S]O#POMN*E1%@Z+IXM:EJV;%+86H<")SK:4"''#2V(K4IL]R6/3PIC6QFJ 60F!+A;I:[Q9Q00K(EN031U4"\K[D M3(+'4.R^L)PY+Z"V0^K\J%HA2P[W49G0Z-ZX^A M&;MJVCEUGE1.W-HEX7[Y(/4#X(XE;FJU>*N[$6A0P!0' M99NQ1[6'6UXAUY1F2HL:Q,LDRYWU(<>84]DJ7,[%XTYA:TL.A)_OB_+C0)DJ ML9>")JI&RF:))R%J2NYM>B_8%")7.V74KH[O$*WZIV,1O; M84*G 'FU/5UJ42^6B2&\*5!R[Q))@8N!%:$95_@B$KK=:EB4SB_1/T0Q6X'_ M[51"*1X<4 V<.E>MZ9:\MA+9M,@$C#;&IBY3LLV/MC7I+]VS)P&5I,>JNLV, M2:FCZ4R HE3&X4/C8[#5KA_6&H^5[W6<4;\RGE;;U )5!A, ?ZO^(ETYZ>R[ MI/VUSE*7VN*W.^^FJM'=FN.'.DRKHN'1I\1L];:)-*JA5!5LJ0W)Z8YV\Z?+ M&G7C0O1LF:2D3ES4-/_-?Q[G?O/_K??_GF_.N_K=N?_?_^YN_^ M?'[WZ3?O_.*?Q[^(7_[A3?R+P+>?G]^]_>G]IX_7VY_>_>6;.$9\,W_^W9L4 MWL3ZEWG\)=E]^[,WYZ]^_].;?W/^6[^KO9G?O_O\_MNW']_\]=N? M?O_N>W[)MV\_O/F[3]^^?_?3'__BS9OYX<.;O_5'?GSSM^]^?/?YG]Y]]Q?; M%N.;[]Y_^].;WWB5VS=>TE]]_.VG-^W+E[_[^8=__J=_>O?Y1Z[KS;_A.O_M M&Z[RNT\?/_SQS7?O?KM]\^\_\=?><2W_MR_K7[FJ7_[RY^YOO8W;]]__.GO__C#O_PVOVE]CB^?>2B?W__AS?\1_B*$ MR#?R?_[YO_[/7_R-^^.WG[Y[_Y&EL-9Z M]^&GUU_*;[[Y^]^_^^I+YO/[_??69B_GMZQ_A8G[[X=7GYO>__H;N%UY_!Y?QW:>?/KS[\?6?[N%?OOI_ MO?HJS_%WG]_^T[M77^(YOOV6E??J2USVMV\_O[[7SF7_YO.[KWZ0*__^[;=? M?QM7_]GW_/(5KO];UNR'#Z\>0N<>?O?N\_=O/W[WFP\_OOHZM_+VU9\8W,2G MUY^Y_$\_?GC[X^]??8WKG_>KSS[SUY^Y\O_PRY_ATG_\^8JGUKQ?:^,4R"[]: M9?'K19:^7F/YZR56?K'"]E\LL/JOK:_VKRZO7ZVN\?O_R)2[Z/__\Z:=W7-^75/,O_\*E?_SY^]^8IW[W/?;5U^- M?_KJ+[[9Z/"CO^+'?WSY(G?VPX>?7VZU^#(^O=XEA?OY_1]_^/V[EWLI=5WX M^T\O5UBXEZ^?9.%._NN[SY]>OL!-?/KX\KIVKOZG__+R[SO7_=/O/[][]1VN M]D\_OSRQW?7^_M7ZVKG<'\E<__+9<, "?+E6LM0W[[YZ$#N7^O']ZPOIWO/K M7;H/?\WW[[_^:@W_O R^^_1?7GV9ZW[WGW]^^[+/3&C_^>=W/PJ@OO[6_/(/ M+U_D'MZ^7)XY;;Y\XO*/ET]<^OGRB>N^7CYQS2]+VP3VO'PRZ;Y\XO+^QY=/ M7--?O7SB8OZGET](EY)M.73US+ M__+RB6OYVY=/7,O?O7SB6O[^Y1/7\@\OG[B6__7E$]?R'U\^<2W_Z>43U_*_ MO01N]%4"#5SAZP3$I;U* X%K^L=7'[FH5^DD<%4O(3&:O5XA"%/7 MIU94RN MZ@^O/G)5?WSUD:OZKZ\^&ND_?O<5Q# _O?O^%U\S*/[\\7=O/__\_8>W/[^Z M-E/43^\_?/?J?9BF?H5&HMGJU\C%&//C#V^__?+COX;WQ_'I#__MS[FG/T_$ M3_WWV*3AOW_]C?_P\3U1YJ\N0FP(C0W@5[_]^3,YX:=53W&+__SYM^\I--Z] M^\.[;[=M*->V*^.A DF\]&/40^ITJ#+M3=7!-=SKL?Y^.]*^/W5*&'X\'I-[ MI!BP(Z*;XG[UV/GQJP=UV/EO&>I2G>,C]?6([=;G;,B(JYI>M:$0^W2(N]J$ MEOV['W?:GMVYPR[17J9OEMRNUM+QW+?G92H5[\>1TZ$C4#OV.T@IIYM53SGU_;MG))6@IT)Y+#Q\9Y/U88P8SG#+( M#OOYFL_>DB9Z/I5Y>/9+ 04NM3H7K.CR/)LTRZQ=ZK$[C1B5 RNZ*@35MQWI M6F12>2&WY):CI6U>MJU&[$>];>L[&=CNH%+*F4+1I(C7<%:UU]MEK[3-47B M4=Z0!V[7DE)VD'*[G!@-Q5Z]HU2ARR')6;>SXI3:H43SX:S [I27(\^/(^52 MWHK#OL[B24G?8][.0_4I)3Y2'7//+0ZEK;C,7.L:H&[]Y#K\M8>JE/JUUT/F M0QY3@2K1CY/DNIIW8E8>/>5(7F_Q_:3:F24SP?^*(2-D?28+-K1MC4/SV^C!G< MNR:P>RIJ,-V[9G2]WYLRXS6,Y5A\2=52.FH^'KXDUO$NX4C9=4VULX-_<^\. M3:EEZ#SET>^@.QKO*V[I'HV5<:B26F\'(&8Y94*'D2OK9OEQEQBXC&L?Z58* MH,AW7BIQPZ$;QT_87575E&AS\HB>FDAJ80T[,"\'3#6JZNDY%$W2.;&O>T/?YPERP]4QY%2N+(NBB5=C4L+X^*=W@XA]\M_\;BG M*9-1=!+B[9#AI.)=1+6MCS8?R8(S.@,9=.Y3R)/ME_7WU.HHG%IF%2TL\Z, M4"[.+JIV=WL6>,NN)^QMR0$U59YV)4YJ],CKF0[XYJ!NZZF6?6Y-G?:@VJ>. MZPHTC=U1GJGIA%8EI$(P4;[I#&(Q=:"06U"UUM3FQS[]TS&9FL MOK"A/>1D64OG*664?>.))%[-.&\?W>EX"?NDL7!E0JNTHTA:>]ND?.\=QU3X6HL*12N4V([\ MM4?%(Q7ZT]6;0FI: O16-\G0Y+,]]'13AWE9K$E9X:MMNE++KIB'VG$^WV@"WE=B9&GU>Z6QKOTN[\<=QQ^? MX+-)GBU#"=.K.:7X$(*<*S+JD9"JO$;5RRXI@(3NTK3SZ$L=D#U->#JGS,QZ M*_.N((C<0"7(*W_TEFJAT-&4(W&PNW<9$$JS$MPJL>9AT]Y?U+T O'HJK*13B %\>EDS^M_0HAT@&6*I&9Y",I57>BN MEX#>242%G?]Q7O.X-N6O;U.KKF'!0/OH3+$#P*+J7,3IPL*)[6@7N;;RGV(5 M)YYNE1_S3<9B^TLDV\!&K+*DM13!+ <]A4FLA50QG1CJS^ ;R=XU.O04'V<' M=H+C.)\E200F*V">LG-EU7&JEB5T]2+?3P6=ZW2 ).MV_["M#^>+E][=+M^& ML)#72$/K%[\RZ^-P>W2VA:4MQU(U=7H6J0ZYUD8'ZY[OEN3H(#W/1O[-<,3, MB3UEYXH7I_EHY//',*2:^+>GJ25\GP)RFK*1O MU]D\@ \'UR7)$TCV#*22V,S&5"UD*4UJ9NRL]_,^OQCHL&-^:4 M;/A5>0X0X 'ATJF>O$TGIC75]+A2KUM206I*?B1'2T_5E35P!%^OY'[6>O#4 M+PGX75>CJO%W!F6.Y]F62,WMJU\:=>J9/))"^P M4D^]E+MCE\U1LT28VX[KEKK8G0F<)"&#M//+*G, T[FV=+&W GC4P-HRWO;F2:]*"C?/.97&!3 !56;1J%$K >Z$G]/"Q?%)$,7!JB1TB/).N>I1 M@F'1\J:K4DY2O]FV=6-):3I4PJX,$Z]3)=%C%U3GH;)H""!!*1:G].8A0T[U M>4.F0E<4$6S!*"^('*#J4'6H"IQ[+;J%K.%N_)RJFTO[E3+)7R%PG4,SU%$> M'7X*L/G1)8?GE8 Y6] ;;7<45T,=,GN:B_7AD)NR.V>6 'ITS:B>2YM[Z@GG M)*4X$#S8![T!*!VQVE1E;$Z01_TU^%]2E%79(0H*.)[%^#FLN.::2Z"8.+M\ MI+V2DWP*7 M9/-'M8 ^9>4]R^6 0HS?H7AV3H!"\%ILJJ0?FID]@\SQS&5B-PB-NZH]UIE< M69SR(O1R T\^?J1 M@3I'O"2B7UKIJOQ_DFOO+8\8-5HU492NDD77A;IJ]*#" M)&EI3$!9!RHK'Y)O_>O[=@R-+X^:R=)$:QY@.([JK'Q>HQCMR-DE_5!KWA&8 M1-8^HF1B16).(JAB%^U1XX#@6+O:@9*EYI%TA"H (S*GR?!1L-!Y8<-QE=,Z MB!C2%=063+)F*>,4\^A-QY8.NGEJ4S_G4E:4U%@TM^M#1!W.J(1\6Q8K)%B^ MQ?#[\"!8O&$N@@]X.-HD/3!-Q_=W M)2X/2WKEH !,CQ[*["*]HBG$9'JNYZ$N!.N1<-,HK;+KOA;5$7?5OTD1-2F3 M:1RG")%QH_:$8H,J9H9C I"=AC[:("T]^[DF'+*>:E8S% :DU4E8[-+=%4,A M !<=U;@DB9I58G#J_LW,=@*%6.A&9XS4QBWA<1>II??H/TX>7BH":^Y%#[#] M43LCJ3J365Y5)W5 -2AD>]3:KN[Y _@<'WLEC5H$W'UK+#!.YSTU>I:O\TA@ M>EC(4B@)W]6Y;JJ7KJT/J2X[E>YX6W#43A[=,2G7P& ZQK;L\&TEQ86F88Y* MVLN=6Z:NQJ(2QR[I3,#%3;UIQZQJ7?-\87?*;,V)' KY3W%3"HM,N33X*V4' M!<3ET+_JT)2.;%/I:H%UEBRKR-9[VC5 M/\H615:<;F^!2C?J;#9/'8^[]C!D7X7B(/DQ_?'((P_\>A=S1%80JJWIZ ;FJU?2JWW1V$LVVW^PR:L<:\ZG' MC\T)7G(N/!^Q<0&R4V"H:L@Z4V%+5SN Q;C]*R[X!"H6+VN2HD&LVXA?MT)A M77IPRCD+M1V*5 R'2HY4UQ2LWC7T>TX'@;67Y-E4-NF,K67'E$Q=>0];2^5$S2+"@9+O^GWMEQ(BK"-[ M'R3%Z243D4\BPF4G%6RQ:?&E??O);2Q-QV'_CGJ'T&SWLU[MN2G>;W;XK2>= MJ$R)$FNA\K": :071]4R'X1NXJ%-B/XU$T$DHER+;3=WR,P,0M")Y[4RBTHVRE0?=2.%46]6RPM^Y2-2*1%(KZ_/=QZTZ"+V0"(Y@4ZU$^$S*?O!BE=X8 MCJCQ&"3X-XH =4B5&]2,13?1NCGI0B(/]^B4-0=7XE@>;_L(ZAS$Y;4EA]\I M0C+0&Z4"KL$V:5D5&_*F:3^+L53]Y(G(%;1Z"K0 MY5HZ2=2D*5N:("R17L+ER2HC.%I0.D=D=U)/OV-M; G<15WB[LP^?T?Z-7F> M^JY3DB22R3/K(1ETJKPE^_KVRH!0YVI^J"OB,/OMZ842P^.ALB1![.##3$') MX@Y-M>%P[EIW HA,E%B7N]M'[>A1._^RG)RC4H\4&CXCL MTG")U:#:KVJ9ZV#!9@4/-8:P-67/'D#:[3BQRGRJ@:H)>%CIGNJ1[PHY7FI, MW2$I_I5U#8URS$7-AXOAZ?KO[ Z!*-*5G&P'O*C*K[/ZT*>K:64TK?IV7H#V MPIF-JG2CS>98%WY1.X587K8,#*HLDCVHS0*XW_6YT.WDUC34^11VCMN]+)<8 MFS>7)BPGCS=^8=3S>IUT7H<+SQIL("8'A1^L19Y+P08#H&H-WC)ELUFB?8\4R-KQU^B'@1\(_M8;Q=EO)7H MI+(\/),BP1X\>^6?274.Q;!;KVQW9"BRFC2]U8JGD6+43+ 7!4"PT48V(.HI M4\,K8#=3^3R.,_DGCW-KF1K@ %BDLU4-MS40#TWG&"UA-!\ QX-Q*=)RD+U- MDEQG%L]2=25='PH21,J*[5"&N7S1M59)E-+R[(_5'[EL6#I.DF?7JR=1UB?G M0:M:I0M3J5MQD;""':NX.<&4Q8*W'8'TG);<*F9&0'MC)0 3/+C*M>OF3>K2 M_Y?@0%XA2^LUI#".RE<\,^VZQ6,F5!Y@4%OL=$@!2"O"N7Q M\%6%I>K)43MD8]>CW.L6U -?A$?9)0I@@477B.<1PWRSSI;BO6J X(Z5Z[VTZPM0+T4UW[ M!)PX0*,8IC(2BBMG3SP!"106AWY[GMLFREX-C=NMTN-C*_%Y@.V[7N7$L*+( MGX+<^I@1N0G@GBIL'A>VJ<;D<5E#4B85XJRR75=OX*=\@#F2!TV*(Q LW%*Q M*)J2!.&^W\!BI53R!S:UJ\B#G66S#*B<)'=4RO>K^J%*(XX.6G'4[FBSBO^ M>.Y+/1^PB\A&!]:+MSD40R@K#6N3J*P#VS(NV9<[*!#4+H]AE;Y,( NNNX.2:MQ($'PG4(!W!"@1JO HUF#];575FP+"Q'-N^[7J?#8[K4 MV#U18(,%PE[E%K9)'/04WLP'\'%BNSD3V@F"G6BFG9)V+4L9FLJ*VU6^GC!> M&I4.P8(W8>4(<-HZN$DY1]&QSC6G*GJ>&%WJ/!5U%G5#L=V750MF4ZWF7EE' M\]W3:-6->/+WL:G_RI[3[;GI,'YTNVR%&QAZKWENS493H*Z8D0^+?G 2VWYD MOP^+&X$G>H'KY[NLC6H.P97-I#D>G..)TN M;EIQ@\RBP@G6(IL-,Q8[,7:W>44\!D>5+$[G!>[R*7BD3]P5"KH4^#S(5KRH MISNPH]0"D"<='K)L#@D*5DG8V?*A6>VI :',75%3K&DK2!%8A5@ 5NLBL@=H M[]; B^3JJU58;%/(T'GE4I7!Y%Y!%F$W6TF2>=C3T]69):9X.G!P14FS$Z<[ MS66WBK&C7X:@J"?7:A\2FQ1Q5GN0" XVJLK(FPM8-;Z7=<07PJX'/!FJ9- H M#X5([W0F==FFS6?S\)C'K.Q54MQQV0(ER_5L&X2:D+BK9IEZ"[%YV%X *T"O MS$^QUW>]38=%!7"$FQ(ZNV%LU9-4R3(4\X>.>2H, BN31DQ@-]8K&,H^8\C) M;9G!;RJ.Z<-Y:XX,7 HV+X%B0"H2&MDZ!YU>HTT@@O#YJ%!&7KRZN&(=2-S. MCP(7D\>23]NZQF:@G:C$8M556:2IDO.E+&992D!JHG(_STKBF9 F/"?QZ(BL M]8GR*5?NE-5Q5N4A)"P<2<=#T(L>*I5#9\S2,QX.] M=\XO4\-QTY'N#/O4\.$FKAV>YP[=SA1#)?$9:[T>==HD0_E>B?_6>1J8L#YIAK3 MZ>CEL>FXK;Q<5]];+4@5*H_2EKKD&+*G=E:I*$R&@MY_D?)4_IGJ\0H'!I)[ ME'*Q%9>$$@DAB1[4^=$SMKFH+*FLGANO7UL1/3P]QW'H_G$65>7;?K%PE%5G M;^:2\[+)2UIQ\3]LG*.7Q?-2A9K*27%C]1ITW]IYG60=+A(@X/5[WD MM5-F M ZE.:@-E/TC]5,1%I:_AB0*UC(&$)%14;BZE[7LGT//ZGE,YDJRCU.,1%\]& MP8Q[T^4M79G7 =)1F4#C96K*ZZT=9 M%".59SBT28_5 5.*LK#.^@5&&GI(>;NX3AZ!P\V\50(_\6GM*I=0MPM_V==8 MWO*G:@QV-;0U38<2*X3^4I-X;9T9&\ 2D:T\16>P](58HM(,M[)X2<%9[JW* M0:@L;3)U7H2J('CG"T7E+-L&%+74_OIV9*OB1^^(H?(OP*X0Z-13<,N?BG8H M.,OK?4B\9 8)=$UY3#'88;KGD@!HE^T1<(SRGKM(B5U[:4\Q;FW2/!]0FT2X M07;D;_%X6"?6T?)>E(=]DK:W$@4.):&'UH\4,<:/PS.Z$9NZZA1%:SF\:T38((%<90S5@M.VH7( =A;9*#18MN<6^;TH&2<>Q4*.=I>F=3 M*OM%.=C7Z?%\EE R^T*! OEEJ1!\R;<$EZCE#>G^F(]JH6SE6/0\W#RI^\*5 M(',2^KMJB@=12 G_QPYTI.Y=PI"AZ)RM09+^%&SRK27[FMKV M@%*6\@ IR=.8:!$+'-!/1:\9A:#OPV, '16E0NYWML*WS-/5E$BKFUEQ!O^P M07FN"6> _@]:RT_/!B[U ?Q=$@%)E5$2;S:FP]]L:9^A=KAY&MK.RC%\[JE M@R4(-1\OJ=.36]S'D@9EV=@N)+EFR3IFP3L)*9O.9KNR!UTQA77:3]Q;@O@7 M^V)O-KH?3Z,:BW8]H@W'_Y6 M)9D\EE^J=L;E!Z?H[3Q!5%'G4FVNR7.[^1[P4<1(/ ]QWW;6]9@]UEOVO \MA9M8!=OI]8#1"TR>89M;["E1@L25C'-=UUEVY_ M#%3A*AYZEEQ!(E.1 HL(0%_:R3=ST8?E\*C>URMA=R^;*B2%-+H,>:?:;$%# M79[Y;N=?#[[#:&B#:^@NWZ;&$ IO>%B5-:Z6 7OA MS"TN"ZJ^O)@J<>A;!J@@+7(I._5BVUB<94D>7+/+G.C+D*TF M3=C8-L2+_60;LT^ Y^!7I1.FW@&$=IL@Q.S3LE+C'JV RX^*STR%Q@PZ.R41 M5U;U)2#S:Z[!;E"J1H>*1P_QZU9N$J%X>*>F,X\RL1'(VD1C601V_[@RJR7P[:YG.?^FO4$C)K!8 M%VG'YCMOS%9>\OWEY4JBDLPX ,U%IAQ?.!<,S4/)$4TJ_6G0E08TDI84,R60 M:WJ9>AX"\:'%MSJ>MZ\U+*^<=&D5O?1/KZTK#-',2 8-#9'YO7S+J41@^(*< M* @UP 3P*RAW45!?BB>ZORDLIBHF)(*9-HK^!=AE#1]>WVG>K]+FKEMWE%/S M2JG\F;=,"6;)OP!"J131%&8U"UX?0L^F:S:5G]Y;L1_\99EZZNI1BI&?]^XQ M-"A:3YJN# ZI[]1Z(&H)P24VQ<;*I BLFTB I>&YAG6 TA1*]K/O4_*F3C(M M62L8RC5<"0XT*%YW[*IA"S=.Y4N5K]](SZ9X*D$*^:+9.-7O_")O :A\M%8E M^7OJL&OFVR45#5M^W,W)3665Z6RC'&,+D@B .G/J"W.XEL >/!90BVPIBE=6 M00(KZ#&<)(N-*N2B^CJ!N%''/BI:,-C8Q-,..#3)G>0KU6G%!N0DUA^(/RU7 MZ2)=$;R[Y#M9)UJ(A'FFH&D B%<:_MQ:(A\I,JS\C*YAK.=3B;IA!\I6]6T? M$&0K)I^V;R@F)!GJ$*:#WC%W5>)Y0$=:6F7+:XAG M="C2I*;1!=ZN/$I"6+Q4:=&)]-9RB[S)O=X+,X/ZY'=<2_.&34@^Y%=(F U4 MY*J/$3J(!WH+\)"$K)&U*.Y*2P4^;,2^Y@B*>CYZ3DRRBL4;$4RQ%H4J%4T7 M,S>R)%5U+4M;_DF>1X-0^$.=)_\.OBC06MPE>D%,D0PK?EL MV/-R'*20Z+8#-RE=@ >K?S+5;V*=+0'2KJQ/T.V)AVFQ+LA0\_(.4_6N0-5A M9VSP<78/>=E]#2P&V.ON/=L),I:6CRP8D#*:+4)"JHLG3" 9 Y/!7@^2^"> M!5FUK:Z/?7:BKB5T\NSN!A_8IP7F::/#$V>3'8K7NCWSDXV?;#:^$3PO+_$V MPKCI-80\/8XYYZ5:87^:AO(;<25J/FS5EJ('*XVB0!GOZKG'-/2 \>).UB/= M\QK+=/R)Q%"RY_I<+V#=X9D!# 4W2-/PJ$SYG*:<_MWXHSJ**'PVM)(G:B5J M_DN?*Z6\['<7?0%X(9IT!-[=EC749O?FT0';\[@4"$Q$_SBUAV$ML31DVECU M@*\T<3W5QE:=.0531LX*5!(EML F5^-SK(/.6\V_PU-+:@'/VCW,OZG)>G*2 MI*^SXS<_OW*8.QDFRE^"/8B.3[_EV?BFA4;93U^^;[=;M M^@-NY7>H6D^.V_4]4#KT!-/U;4CS],2R\&2U:B#/%=(/CUZ9U+9DE_A5I).@ M@; 3!U&U=P#G*3&!G;O4J^((&X\'<%-/K:EWTCQ!H#E+<[#3M;B8+ 3*!U6N M@*JZ54Q)IM22IE6;K& =E63!NMNDV&V:PG1"-G<++*>R(?%4.^+W);V_JP(+ MJ%1 [>%RQ\%+4@+\LG4#LF&)".651WH(0URXV4]CP7(G!5)5DJ5>#IU[[@ZU MC5O/@Z426:N]"!8FP)8??CPMWN4%-9LD_/JH3"4H(&@S$.27EZS \!?O<%ET ME?KOZ7VN5C^AV:-]3>BH7R+E31<%-W#ABJJZD=_NC+1DSP_.;6>H6% MJ5(B*];1F,,Z P 0;;51N*GO&S9"D[\ S,\%7?G6N)5B@85WVE1DI2D*'CTO M+[='MZ E-4;97IXR:V]PV99).1].%=T\JH=4LSI2SJLWLBF4S% M!V6[[9##32R]KP:=-K)L6NI% S%:R"<@NTCN3,FW.I^B"+(7 MJP#DE1_M*52([RQTVY%1^NQJLCV;;?E=FR7PA-2GNRM:6;7/"8\V36HH]@H6 M.C0HID[0\8H*A/"["_Z E%G7/F#-MD\YQ,1MY;(2N^:2VW-+< ?/*HM(TG6& M\:3:[*>\E6AZLR*[=6 ER%+=$%?GL5T W:"+I.U.!V/J.M&@6KQ84_=2]J)2 MCMWI)WL1Y-5HM-LM-RA%HN)Y!PAFNFA5H-N/^P!^4TH$C^N3,W"'0XX$,;ET M*KD:FZU+G4CR37AFJQ^EYO!AR-G9W!UJWWOW5.IIS:6,Y8JVSDA%RHH:VT,2 MXP-@\K0YP=_PS-#CV:S1>S[:1FQS/(\]P6:LFG9>>P#&DIK,D [UD28Z6?60 MG*FLMR'3TXM+,M1%S=D&=T"&DY;RK,'*::,\!*WL^_"D7!K>0U2X582OPY&Z M1UU_$N_N"=>AO-G9Y5'<2D+WKF;0OM(9\#!C:-5RC8R#04P40+?F,GR3]9DYO%^,XR>;65 MZ$Y@#0D]IQQ7L S X_ P6LULU6!U/;DT#!O:X^E%,(N7/6R"S[U[:L?J !)> ME>4).).-UE6Q.WC8W6[@$GIGB6X'Q9O.$>!I9TQYS-0/'D)+]2)&\S+XY5DI M/QV98M5$L$WJEOBC5,9 MSA*#@>9%_2^/Y(Q"=^6E"1AAVY>UKF%13;_5-+-B)RN UAP6OA7'5)18?V@' ML2*[]&X:G^>DE9?=Z<9?>^Z-M243]?90[UFSG)KY-!UAG/34;4&=[<2-[4[+ M#5:I:P&D-X[.Y[4=+SV.J3?/2P++G7G^6D!/1\[*FNP])9P![.N2FSRDCD2B MP. .V4_=YC'_479*8ZI3MOZF/1#!M.N#8OOGML%WK4/,;G]2LC)IKBF4+0LK M4YH3!Y4VS#I)+N+J ;QKI6]'XF\LB4BG#.(ZE6H.4_HN394'D- ")DDHY5]E M[!F_3R)Y678FC07 GVZ-LGJU]DDT/N6[GWY2I/N:$/K.17;34 V#R^ MFWTN4^F10Z\M(Z^0,E^1R)MKOC3WTC)L"%AMO1!B+3T?RZ[/=3G7,IW*/X*E9%V#?IF%^,CG MD(9#B*3L97/LTIP5ZJ4.W, LW0-0B[U5,SCPPZ41>ZBV3^O *^_K6,[#6:TY MDB[V!(8C$I.'(K)5.G1=8Q# 1:W6'EL?FB@"'EW]4M MSR>01?ZGQY9L3UY(ESJ^.0 L'SS9#EXF F?1EHZ[5M!<_6H=^:8#9VQ4=IL MAN"W[X8V-4 S8;6R%.:6.WM+Y83LD9\&]LY,KH@$QA.L]^:9$HLJ6\7I [)3 M+86I?^,Z$SW=-L>:+*U)JF.9J^T/RF&[$6F)U$XXRM+B=\A+B%6P_->Q(,52=TAV6%_?T]+"=TI+Q)GH)_-UA M0(KJB94DWR;7+91M")G=AFQK6^\*3#N-<3N=+A?']VC5DOC.O;ZFY$L*< M,F!>?6D6QG-S!:N$/EU]]C2J:KQ:907VNE+- MQ"T1C;K(>5=>8*.LU_R=%[Q[1FEE?:UI#^5(/ ?*.I]4M:*%KV$DL=RRBM$9 MH'@-6I/<@.5-\A^+FVI 9F_K@$! 9?_H1M0N8,,2]FX;5[H9 MZSLK!TRA:(IGJCIGW718\:1#J?RFW^NM/O4NX2'Y-/.BBQSZ=A_2&Z9?)@<# MQKHSKPYL''O=;-3U(;F]'II@39V+R,F:'OO\]&(%9A/@>+".DH(G+4VX0%&. M_IA!']Y3KS_B(.^; FE2V;!V\W,&X(=^&X7U<6G-2XK2+R;*T07*D.MO$3^E M%\]Z:"DHX>),6U7X5S)]Y7])>MO5RR5.)OULJ?F*GJE'5G?ENG6Y!0!+^I:R M[NY5UA=XY7S_1@H['$L6G@,CLN2]D<0'>HQ$J7KKQ;#@NSH7U1.>2].$NB3Q MU42OY[3)1R6L':XS:#Q%L/9F%M1S8H^(S8?NU#$A6 ZI[W M/)[++IK%_'X_6QR/DZ7\<-])X/:\GD?_.V)9-9;U&S#*ZG1BRL-2O:/802SZ MD72$OY<9&/&GC427K" M\EB&IP#-XZ96CIN&!UT7ZD.3 //)ZJ>WXOAHNG6EV[WC;)Y@@>QURM< M2U)E=S5R>+I;56WDM@S)]TWUHO/5&0A8O![]7.7+%NGS5"WV+W/7>-V(8=^W MJ1>A"YEDOK#)XU#86)YN_W%XT?VY>-DD*?UAY5"LC1)1>[I M=:_#>@\7+XI7UB>@=K^IWH*M3.N:XXOM\YI(L@) 48UPW]3=UP-UU;I#FG'NR"#E,;8W4K\O.8(^#2XB#VM%.[GS,)>F1) UF MIQ@Z[U[?[F?3VW"9O,CN(*:W-0/,7HZ'ZO0 LFC=NER3IH4_V?J2F N*U\'A MI/(A=\DO*1O;PVCB=/!%D@<&A#7#"'[D[H+40=#3H8*WM+_FX!S:9!+(%_=N7C.9H>[%K;@?:C+I1 MVD/BH12G<97W=Y;:<,G# <(XE5OU:=NB_8! M3D>3V&";KL,]%7T7 *I( MA4$PO(."V.3^V&U!):E'K98*2)9F9!O5[K"&JD7BJ>:IU#N2G HOC04M9=>S M^*AM&C%7V\M$=A1T7*=C\)<4,$U?9&I>FC!Z[+/,RF4>[V">+!'CBM?0/*)> MLG8]8$[EUB>F.=]5U:RX>-X A$[9N\>#'7X# \"+4AA4ZS'1%I91X+M)7])J MP(K5EM>URY>1_RGY-<3S 2TL/3O^@[>R^-/[KWG_YI%*K]! ;LD[T\M3ZGX63-) M/:FM>E>:FJB2,;N;TH-YI<3FY01S]O#8"8KKR6#21^XXY9&J,CUT:Q"M4H=T MZ*VKW%]!UUQ<7+-,W3-.R0%4ZWOS@,!]X?.23WIJ&@[Y/TXC#WU@M4U?9#,E^J,B>?BD;-/VK)84LV&Y]NX^W::D*E$[ M=0DC#^FI2;FR,BF7ZC>%1?;HK>?!,.4L@+-\5$HID MB[HLDXKF#OJ82QCQ;%;'+&U/R[Z4VG;@5F6'Z+%*.E,W@:0*&GGD*Q.3*,0H M)V]MQ4_?5W*866JV9%#VW'E[@8.(JK'8 ?R)JPOZ&!FSO290>*LCL-\4'P)T M4-E-8'!0O0&X1ZKV9$,216#E-%LZ9)R1"'WVR8N\_>[QUK3)%7?YX53!6W5B M[P(IRDY-2?TPX@?97JFXAXA)[>OK.:(_UN\ M"6!*XCLFCV#-1A/6=WT\-< L:W3CWL6'CX1J/0YO515F3YIE*O#4MS/:BDZG M&@FAK%V^['ZK9R-5[HB&+TG90% OI:.G*2R0T/)9=^<[97!3!9S/R48?%DB* MXQ&\3MF;DM;(8_MYJN9#0F+E4PO<6F8 934TE=/$^@+Y$-P6[=D$LI74%N-" M"%X=O'?0G@54'1MWD*,,ZG\5%XH3]I?FVAX,/L,62DB%35^5>J* W/@T' Y[ MR-;'7'97=0Y'_O2JYAF9A6_'3IT1,4V"2T!':S^79S*U?%&- R!T.5S#0HRZ; .#IHUT*>6\,(45R5XL-5E-6UOF+1%4 MXOA/"EI4:T<>FYQS1TSE;-R>P\?H1.EH>F?ONV.=J9U+V\;>*>MWVY_=44+U M'"6# =0NZ7# J!F=^:8FCA)XKCS9; 368A>2 B'9S@:W.%G%:E(N8V.W[N R MU@MQGJTF6V8219<=Z>-ZB$N5B')7:1*V2P4;C( M@6G'J4P=0.)VT(U2@6J8RC=20/N3=IR260C(K&6J*^B1CI[\A^C+"7*$<'\H ;0.X9;YJ^H-W8?GFP'7D#< MDUV*)@N%W:[1TIF4.-S!),5PIL-PM>OB.&U;0SWMD&!/K*>J+I=F8=0.J1// MBGCV4'5P?=JMJA-56[6F7H \U$MU $U J+G"GLE!K+7@&G+NSX#-MNE?R9!\"8[ M>:I#">.,V.4(G7Z[ER?=U)*7Y5'7D*Q?2>V%'I5"8L]3=IP.ZU)]JT'&ZS[J M1K'B%"1Y17IB-MJ>ML\L#8=67RH2Z=/I!-K>]$ G>FJW/4P3ZAIDV64#X+,1 M8-Q[K*^B0D*K=])MC97I>GJHG.HL3E9(9W8N4\J(I#5> LN.3%!4!3P/2M,M M';PU\C](WT61X'$KYM,5-SW*YP&>\ M#W*J*S!)7ZN.I^CK+?M$(K1D>\H4VPN'A\JKTE#EE,<2VARLK4M+H9GNC=U7 M631/6^ZB>[/=LB]+US#MB3RADT"Y#]['X6K2X[6XH5G!#B@<4HUO^Z\Z ^56 MG15J.O?R<@[O1@6,4(9+UU!O@S;SV(XL<:@KLC^W MW;15X^Z+W$49TA5P>1*IDEK/Z"!XFV?ERIVAD]3ER(=GB0H59)[6O@$E]ZD9 MZT7&5PKR<#(P.F=#N"53\.CXE<3XG6U"&4*9 ML*HD"S]'5-OKU)QS4NC9!VM2E C5P'OJ(?+)R:_3;5B&IP>^;$YM[:F=2@A+ M]<>Q91+N%.GNQ1H"5)8C*%O-!S E!:[SN[=J6QXN#>(<>%QAN\N3>.HM,WJI M:[KPK,=.U"^^;L*1+5W6SAYD$CBA[(R8I(UA?@Y:#5/3G%'7:95P;^FD:CF9H-G>G>/>"Y/P/?0[":9=J3E MOIJE%VCSN&BT]]6,"&3VNZE&Y]G+.(PZ:^;%\1)'8"\UEL%;LN\W(&CR<#9+ MS]!CE#>PRX7FO5K1@S[D>R;+.#+TN=M3S&/)^!S+3+=\2>?4C9ML..D@M\(Y MDSJ,WRI#*BN%_%CR+_=IBFA/FUB1W($<$6U[/6F1$96TKR3 ;.+.6S-4BQR/ MFFT^!P_=JY-)88F*1L=K;YD M"%9)UY23@.['N)@(%^ 5@"II(QY)KSEE06R0'HO8) E4![W':0]9)$K:40JG M-4*OLS@E&9%^C?EDWAY%P&/'7FZ,7#RE/C(+],FB>_[ 716YZ^;WH>J]]C)XF_S M=KJBU]0UGO4NJ<,BF>)22R.Q%X8E_*JMI\Q7U9=;:#[:N9W:MA,Y@8M+78W0 M31%"YHI+1<2>#Z%ZJ%YE5%2WK-M59"6VP\;P( RP M YEF4M:GT J6 UJD<$V+FR?U7\8BTD0)!O%:279<6$X)JLA)$PJ;N;6>#L0*"_8&+ MD%.-5T<$(FH&UC5Z=AHJ6;M5 4F M"HXXF7 :=2AOY5A0!B45B;-J.Z?&?(#\PT8-(7R_'':1MSV()S<[DW_=77O* M!]:F[7)E@7.G%J;.O52B.O.MO=LQ(@IG/-TEE59!^[@RIRJ2Y>:-.C5(6T4)]-P/6 M-#+3<,JO+Z4)I5!WZB9 )9]1);)XBAQU,OPL- MB0XGJ[^(!';MF0M[DWUTY-7J\0!='=M93?@:M._J$HUM38BR/*C;KS7<+\7' M32,5.BR#8_5]E8VA5'PN;I05\@SBFB$MJ,)IY<2#"9OZ&/Q5Y<^JDE;EG\^1 MSM-*>E=/F;#[J$^?'+'WE A8Q!H$J@B3@LI(R8'[S4$$\(;TQWNH75$D'_!? MY!G RG*:)\:0BZAPUYRC8\%4?+()=NO3J0\C=]QU;@Q.W>FI.6]%<)Q/7O63 M![C/KN!H!#5W9SB V6OVP[@E."6D%"4[U[ 52R,K^7,H/#+57ZBR8)-Z06QC MU9UNAV+3(;;F_P!2K+&3X\F*0H*GHTKA!+S8[XT%07F[NEN$C=PEH9ZV]Q5^ M(9%-27"@$O8#B.UP D$>QW0Z5<@!K(@E9$]<\J8LJ4=?Z@SF94G,QB_JVE&N M'*2DMLX)0?G[TZ@4>.,>3IF6E-G)0==K932GV6E)'%^J3ZF-K3\Z/^,('Z"E M/TJO5B5PE?FX)%]$C^75Y9=_GNR#%A8SP)2HT?,)AA1X!4<\]N@4,95H\)2# MT!Z2!Y]-218G?UAA;'." P!0'5B6\PR\]-VR:M/)4ZM;]8H.1T= ,IYSL'/< M*KS%2FJZUHRG_$" E"K*1QW%6;>X-&V21?_!TG"@XI:D:7;U]'[N9NP+8#0' MJ\Z13W9<4(+K4F]46VR^O3K)$IS5.$Z'^%D>FPQ8(#&+A23O..NA4ZF^PZM? M\?"W"8<4= \1HH Y*K^8_3+42EOC^L#82\2X9R)MFIT ;[?(3AZ)7=89,#&2 MZ98P)8%)506SIQOR4(B2@":PX-^_?C>< D6ETLS4N,-[32T"A76_=9 M- UOVI9W99G)(I>3B=P]R&MO7;Y.,3MYO.0T+@%&MC517O/2[ 2CD\D$;,"# M^^^RF">J2IE63@KHG?;E^^VN][ D.9/">[\DFIZ>WB?J[>20-LE7<3YU*APO M=I9=SPS>QYJFB\J%&M>R/ D0*B"3Y[G.>ME.'B(R>*T\D?["$^SD!FWH0% M!"4_93&0UXD#)W"EXMO6)2Z $T#VC^-O2B)NSGBS?$Z%+.[#D]=L/R>JZ4SQ M?)"Z_05%DX3 CG<&.3J;0>)SQ)F2BEKJ=)"];G;C>5G3!E+K9Y-V[%LS@J$MNPY7D M-W,;59UI]A3E!A'POHC1MGMX*W9_,LG00Y;B%$39NI8*Y!T*V0@6/(5H3EF,1SUM#NSZ;CP;@:&L/A4AYS[LDE \DBJ/ ML;369Q(O4&83713 GCX29V)&+563\Y#*<2N[5*Z^L3#C9=UR4](I&UQ.YT6C)%!YCR\5CQ M'@K(0UNJ56S %-2RIZ?(?((C8!J^ MLRFC1P,$-S#$ ]2DAITJ.4:=OZ=S=RP=/<9K,I=LI--=QP6Q# &/0*C8T\%N M(F%4J07"1E;//$!T/5.>%8)V8T4J9,C+5(E.N6/MX-5/"VO667X9.RO7I3>0 MB >33:@\Z'X+>UF+-Z])%5:/ -4( !40O,ETF@(=&QMX$I"H$QPHFUW:+/5C M2*HJ ;$;R"CR=I8P#QE&"X'@6"LO@!"SRP[4WB<./1>(#!)G23^ZIROZ^[@, M+X^7([7"E(O 4_"(0\$D-NQ>'IVLB?K4S6V!)PU#[@W :!A0<BD8#T/C43D23S7XKI3^5_Y4H?G]!!.A1WN M-M2\LVUDW5>+\E+^A M7'PF,%33G,0KD@>ESV8FWK3;7I],=V9UZIZAQN=R,&Z MTS)\5UE\]T\LW'G6(8RDPJ[R*[+E%1F5 O(Z-@41NS,(AZJ#!M%3Y2<6K(>% M#J7;\>8J>.UL-)LAU20WGN2<&P@4!L8V?9(L]R0>(Q 38I@'8W MJO^^NXK.%7TTZNP-. 3!7V9Y&TJ5&5Y3F<$B7EU8GMO5YZ;.NGE,32'H MM!,WS J_LM&)IWP(7$9A%K^A.T@*21QRS3F6)L>W!!O-IHG M/J>-MZ.5E&0P=^)QCV;NY^X#J!?DLL;+Y*G5HRL='PU;J--EX2R))W MIFB0HMM6Z8=*'JI:.WU+M"@KO"L4ZE'$=M4OS$OA+D5*(X5K2S$D@GJT=ZE: MDTW54]G1W8HKRF1:UA-G3:HHY::6 MU>Y*4*Q.30KU EG^Y[C%+%*&U$HC;P[)U$X)LC6)'4-Y<'#-0MU@EAL2...-JI6Q @:JLG$AOOZBGB/;708'RV!E>LOKD MR\<)_JG8' F,4/A$HC&;;E)@FNV7!9-#>NJ_W1YJ+%TDOF=EX!,8I'34$%N+ M"UGQ<4_[+3F/;9-DC2WFXS"TZB>Q3L#,B2[@N*P&>($M[!Y>EF9V8-IX7,Y;DJ&3*NZ']!#*5Z*5K-"H-P\%GJ+. MSEM%C[;M#R2+XDLZ?[A/MI,DO/=.6C225I38G W!*%$E%-GU5H(SG M#T;RR$R%?.H3+50*CW^-<%[^RIPW@+C^3=9E^B?,>)<0@7H*XGN^0$B1P\T2 M=ZIY7U8G<9?.KQ(Z.=.9VWMW\O_: INQR>3D+I+22T6*:_-S\TS-$B0YX'N\F UY>(Z=R*VJ]B]L2M5@!,Z3G0IHPO(XF$#Y(M* M16=V6"QT9P,(>01YH#)K^Q03WCKI7534;#D*&R"80Y"L3RJ)FJC.V^4RG=CEX$Z"4Z2/L0QQ :M#ZD_5B1L;)PK>FZ6 M!;_Z*2DN T#? 74AZ\5Y/FD#4*HLD16^ LH^NU+6-N[DII[\XU*%H7)=VD]" M!FF$HU"F)'*M[$3RTW ,J6R@0" C&<1TZQB2IE>VL;4^J_U>_H&'-A5+W(ZG MLX@*\MA(N2H Y7U7H:)35E/?Z1U)VB02G1[$D/4DM9$JFG!N=RJ$Q5.2G!Q#K6X7F]%"\E!67RC $!6O,2>P2T]>XAM+I.E<4AX MIQD8SV(.<4+UJ."^-P61 25K94<--KCG^U2M4\M3C2!.!9SM?)"#I/4058S& MI=[*U;!B]2:)297^0=@\"*8>I04QXZEV8U$5L"IX8=*;$^P1.?7I:SD5W=V0H;= MI:)H2C:(R&CD^2>-3463ZU$M@F>J+*G3:6>?65>KQ@;M,L&I_?-Q.I*2%'(5 M)AUZR7*OT:N*LIY9&J>+BU0#D.E*LK*8E'NCNB3CGUU%J)1]FV1[0/@N#\[1 MB6NR)\@&_0%2ZROZA&T$S>':[BBABXYV%[AKF\Y 7;D'976YB]Y M.C@\\*5XT M#0]5-SIQRO0!&( ]H5Z>B>"QS+/N5!$>2C0/"CR5CLTT 0#V= M<".^@I]E6NQV':G1:RCL6"([Z7P7$QB/M(BD@@?8$FPL)?5;FU0DCL+MB0)7 M:]$EA% BO\;1. G-NR&)OT(QH@TJ@.?2%/9V7ETCI"&+BHRISX.BCDK%[#MQ M@@U5NT-GV4GSPW$;?7=/N]:$[YVE=*W)HT>/#25\#SL9RIXOGJ8RG>PQUDHD MWW>YA+:<;4Q0U?2-;!&>2RU%PI9>OA0CFICF99"V4CPX/:HUSIJWLYV_&.=H MFMQ9XX1'ZF/*R="WPWQVI*JL(5'ZU)(K'UE >1^>+I$\],X;0.Z001VW3B'7 MJ/;.;4GOPVEXR_M]$V)4J)Y$$XU?%M<:['2] C ME( >M2KTA;#Q6-Y;UIE6]NMU7E0(VE(8/VW\?WD>CFPLHM*W+9#BA['0Y$+[1-X M.JWK%CO5;&IEW\1U*9LH/)QU >LQHR[#;H&V/I.T.D= (@0^O9+G*$M0$ &=*_D55?VW=$P>![P"@4!?' M)@ =6,4>EFW!*7_+_-EM5#U?GB603J\#27)CM1VUU];<%=!#B/1X2PV7-"3Z ML8^K/FY]:X[W"V-(A4HEW]3C>ATXF3'MYJD)HB J!>RAL*Y3%CVKTJU8EPX. M#IM,E\?F'$;1"$1D<7A$&A7YNY94:I#58??>"')2YSN4JK,D%S;.)2](_9*4 MXP-_/YMEB(Z1V8. H3U/I@X_E2^0M32:X[Z+H'P4K=U(>@2"HX?F$E.XAB!8 MV*1D@HW,^DC>.G0?ZYH,9@K#?CG#)!"WM8P$I4+,+6TXGD(_%#J6@X!ME MY/NBMWL),]MFW>U#' MWG<,<%-_@"*-O?94#:B"HA]Z%A(*M-*D3+M4MEVMP$H\G$''=(,D6^P@$NK_ M_)!41]EV"<6.$]UG6Z)L+.'=[O4I\0\4"+M;HZ7ID M3/0Q+:MYRL7CDZ3X(EO60Q2']$J6Z:]PV2%+EXRV^@9!(5@EB@2?R@60M!X' MD,G^P=/J8ZS!U_SHCD0TL-KJ/""*Z_QE3NBZG ;)%]C2PQ_'J[_,3;+@@?2[ MQCY.8JET325M^=Y5Y&-)3_N/[ A-#CV@71(64W5.8]+R]O!&KIYO81OC\>E:9]'Y(TX/1S5Y[V=^>ZGC+/;,OG\HE9D ME_( TP9/YL"D";CM:+L-U^@0E-T0UM1BK>AOZ$#"WDDII'H]H*BXJHPPA:O2^J M-?B9J&$ +:I UFHE!&(*JLX]<^Y6 0?85,)>,;0II+@[Q3D= K.L7$.O!&_N MFHU^GE=54U"^25$+N=L5&XH1QW(<6FJ!WH>S.^OL<++T%1@2L)//JPE=>@+A M63 CEQ.)X_9/NEPQ%(.XZGV(T$SV;N^ MCF-;H[6]J0$HW=+=R:LA>UY+$ZD4A68??@/;QCE^"<>ZUZEZ=-F>;"1B0M3^ MA9;B@)=+)SH7X&BQ+!_JV*AL:'2P ^C1+?YX;M?!OI44JC@4*5TA#D&4]-FX M1>.;TZC=UG&K69J[G<)PLD]ZE#T;=DU^=\K.;@^;^E*]!;UK]Q5LB"0@QOIL M%BKCC(G@-/FMDKBK<$1KC %FV#T58RTJL^/<+9AKWLNA0#FFJH!5E!^EO\I6 M#)QS7/-6?-P!2OL)(K!3)8OE@! H.[/B;ZX+*K&Y!F,\4W?TTX%E)RBNN0T% M67N>EI0[/VY8![^MUSQ\NQVA<3R_WHF. \B@,MN1; M=L0E.MC+FYO+V&L^-5O4RVK8G6G6549'3R"-O#G/8$$;3U6TC!A2=+C;'.K0 MB]KVC=4;B)\K4BY*IJ(:KC>U5= _Z7#=^I\4(U0:W;+4?IVZ32SH/K>LBW0 M5\W%GCNB;H[-(EC^N\*XRSG^3#>!*H'Y>>:DW%N]&&<7;JI!8H/#P?:V3R(I M>T^J2^,F@R/TC8SA< QUA=(X&JV-LF07[31.O7D+MQ##!4ZUTTFX:@=[4W1< M@J9:75^G8[+<+ $55%*&N)MMJ8_9.!XJ7*).36&S<@.U:M]4=VT@>)O!D\7= MCJ\VU>L4G+C/2B!..I@S/8K+:R<3/QKEW4,<[*KF3<5VKJ*UO;D/@*SRSZFR MX7DX*B!A"DQD\P]X7KM!]!0I*>/GQ"&;4)+CF@C=);G-+"("1>^;8I4WN$YP MQX^"$VT^[0[5\"B*O*"0[+4H&.3\2EE;+.I/SYH[=1?)5>O JWX1.K2_8,-6 MQU#'6UK1;O16JZ2M\K,M6A/EAN^]?QD:*PZ-KM-=@LC.KBBLLT'-P'9MRXX7 M/'8]*ZIZ3NL%DT#@D@^Y 8>:EYWK?9=#_^XIFLX[6!W/=MSE4CEIG48F*H.' M%]C;K:V'MHN1W*2_,\@*)"T/[)E%/Y1KM7O)KD/&&Q$HGIO$K3CTG@%5.,_' MMBB>35.FKK.+TN4]$ASTD >(LKMO$YXP=I>Q=.6LG0TK5Q78@X*3ESJK_?.] M$.R/0]XWO[(LHKK%9VJ2Q[+C3SD=8GF/&%G@8_?A'XJ\;':K%(5NGBJ0'R7 M->!:*0I%>B!XZJV7G">UX[&&7J> H"UQFN+!L;/O1ES^9*W%; MB4KN)%]"P&,'9P$C'3P^-'>J!"%3- &$_T\9I4LR2]_82%R$'FT#/'9'FY6" MJ.P -K5'5$C7+J03/3SVH2-*TZKC4(-6V$(]2=%/5-GN"?@FD3D=H>9U58-5 M!1C5=J.->'9]H+RAE&JW@O!]*@%Y.$')HYZ$%Z5HW>%;3N-2H?@\017+)\31 MPO,>:A-0S_"T=6&6A5OTISWM>-=ZF$4U*R8F*_% "M&>>R'J@^=F >NS4*X% MT $.!=%)[3]U%)<:N'R#,C7/$24>4":5Q%H4WY7SN<]-/11 =O6 7]LU,F52 MKD)UQ*$Z6-;5Q@-XTF=:2DSL$=7=E[4P%^%TB];85'6[UD\.5A'T\[WXK[?" M'I+G>D4 MV/Q2246V=%_GGB>!=BGH*7NU@Z2G)H]!*7JVDYT2;>,I+C1F!AR<=@*:\@1@ ME30E$)?E<2K];#U+9Q[ D?9>\@Q(:11E:?@WI29.)76+74&) M_TFCKO1E;LV'VEOM]M/"O,1&(6OFI%K\=6^ZERXQ A5H[74%'>".H2]X]W E M+LDZOJ(Z)9Z+^K7>K6H/U9(5QURG/@XF*F J W/-A2499,OBS:$V#U-WJ8!JD^K#7IM' M,53B)G\%.4#(/#V;/-G+DI?1-U+"4%>,M #*CE^R;II+=S3J9+=[TLE_DAN> M9ZFZWTZ,GY:H1!-%U'9[W'FBM#CG9MMPR9T"B4W5? [\'-!=%0:1^ M/3P;.+3<&_JF:,;F!@&G^C]G!H;/; ? <8A0ET?N6,2PO6G3 M0_2WWZ';NH*"RV<3 )[T%T_J($_'D0"OI$\+!NF,ES)DMC":/!E6S0%X+,Y$ M75(^JFZ/1#.;PR L$J&]KUTB SE_JC4K49SJU0,L3VG;LF%YM$VUZ[9[5G\0 M@,@)R[[H.E1DTXZ>*U3)LH_ME P!TIU'8,^IFJ::):5XT.7K)EZOP5D9/M>] MSJS8;7*A;:A=MZKX9 WVHJ<[CPPAR7[L%'*EE;TVX+>G!#P' A:A?\E*=DD' M;CR0.1O;$3S0@Z(WV")W?-02:_4Q\0U-L@IHX6R+I/\ J^T!3GE M63]FRLYP.ED-\%=M,O@Z0*Q'3^,784 TI:B&/4\K7<\ M%^M$"XDZTXG%D)0+\Z 7! [6\ GIF=JB;%EE70%Y(+!3\U[2*/GZH7:[LKS; M9PTD.*30SDC*N*O 1@@-O5.I<4Z)V?&R) MLI";4B&J98^H!%[QJ)*=?S0J&.V%G ("E%;M;W3[;[[+EM))J MCT?N!(-BO\!6G81MR@0R \BIDX0?7C.5S%@FI:"[2YFWHM*Q>BU-0M#0MQN\ M3PB50I9XSA*?>1PGE4%8L=O1Y$U7OWBI^JUC;BTVW]:)2R:@*SQ*N:%7GR8+ M4>-79?"X MPRW'/.566K[X(&-?YO!;V0U203>BF[J+G4W8FL%9CONT3/$0V*#H\' M%K!LM+60C:G\^)Q.K-2UA<"TRPI5Z;$12-D4C@^!R!$*Z@6U@:DT'#,"WK # MHV'3\TY](94%I[X M)A2EW&4UJX'2%)V5 )45FJ&X)J0'N1*:)M9#:0@] M]K1R(#6#F'GA[)\+2%I43U>IU+2B5P<+_&')*4(''E+4QB$0,L^C.UC1#.;) MI/['%FA6$'FVU6#T[&!LE]4\0"NHE6.CUR"=7*Q46OS*E(IGB&PP_9%E"=I= M?.3IWF&U.RAV#_E>LO!OIX@2X%N92Y:2)Z4424'.@UV%XU&QM:MR0E*A_-*, MT2;Q6.^3]'SQ"*7%')M'2P!9WJ'$S9! W?.J^W%/-EKU*S$O"HK9YKHL@?A) M30JDIP4H.%\!(]P%=N5:?/N@0:_,,$ M<;V-JG:_T4D9QW+2INC;DD!HW6%S$-,>0SO66%>S?2%W.5SV>9VJJL58)_GU M/I90%?#S=.Y2.5L)S8>.?&L4>E*W.>FNJ*[#E,">94>QZQUCL='/&B(ES$7) M1MU=2:HL[NHH/'OC"\4"['2I//+TR2X@_ \SRZ5,@7J9RF6HE[?../0#\ICQ M43I'6 2:)YOI,[0!,VYM='NUH&5I*VAAE9HEASU1GRD;/H6H2X#5\(/(78MJ M\&KN\K9)]>/4?FFK1<9Z5E^>7-;+,G2)9CM6IB7EJ?)^DN:8)2A=I!JVNWL] M29,FKPT2T2TMCRL[]+$0_QY?6K(\/T^)3_6/'?8;TO8>YU15W1T>M+(T[1-V MQ5$)-$X<5G#DUFU/V,,]=$?2)%U;\O,8,KYN@,!CX1^K_E&-O)397G=3>%.5 MF)V]/F3%4[-?F3I FZ@8M0-,BJS67D0]29$%HW1VN>OD% 7WZO+O=GO:6OX$ MT6$-<-K_%NPI4'9=)E>*=IISD M)5>\14[Z2V-L%\9#6IB$O#\SQ2/%'= MUJ6;+4Z*5VVZ#E4\%0FFBOR3#M3U+ =)/;+U) -U$[7.*8E)5OH^Y8&3/!YN M/SJ+2?6W\>;TU[H(#>HX*7>@NSK58?/#&4Y'XWFM:^FS#$,$(!7^2E;H'#A) MBIG=&9.R10<.'\+!:6!T6'@G"-ZD/FOI?0&/S)MT[# [247BHE+;N=RXQ"_T MW!12VS^;.Q4[2;'IF)1TY-%EC&^):[_I]^S9PL[.!O:(,_6_=?;(H4Y+J)24 M*@&2ABW8Q//HYCZ!JS)F-?VU1,^.E"NNW:GB;>),0E8.'D6!<%F,8Y+ MWK>2E-NN. EQO,7KB:".J=>G4W)/V N6T:&.G M6P>HX?]=Q^J$N@_,9("S>3C>E15>DY'1\*:X5"H_@1393==U5ZG!ZO.1.QXG8CSW9XEIU2B9@:6I-KB2L+4N^F-Q1&$H0JCV M)"6W G26(WK[%*7]Y3/Q;JRTEI9A(%O+V/%!G.HR+[9A=5#A ='IG@K\R[;) M'ED1:IN8<9:&BRQ-\S< M@U2G? X%AE%"JXJJ]X3]%;4A'^?%S"546(^DEIHDLNECI?"%>,.#BRK=N/1- M39:P_$YU[:"2!PE3J$AK8Z%2,"M&K5J;>FU:6N!.L M09GINCZ7FO?CO6N)H>=U(5Q1T; C>7D>9DIROU3"<1[0,ZQ=#[YN5P7L4;:@ MU#5/>2PY4/T^E_RTMJ#/2:SU*)6""D"A!K2"&\-CZU-YFBG_.H/'V.0/:'E3 M>)P+XFH+D0UTA4BJ K UY#RS46X'V8AJ3S^W MJTM'+TNV09< ;2+U,E,*TPQU@'356F9ER?_FIJZ=8*1#X3HTYG>K!E>M;S8E MH<#TU#F]ZRKB>WEC7$:[6$T?E;FQNJ%[YOFW)P M5+^@]%4&3X\!Q3&2UCI$H. +D_?E/(DG0RGJO<7]DLRP7 M1.&3+KLL(,_ZFR%N/M3\E-# G7@I4:2#C;,,Y'.UD0X+PT->Z[,&"ZB$TSF< MTE3 5JZ+>EUJE+N1 ?>.0SEAI*+"$"U_,17G.Y,#%E2\Z]"5NVG#[<2E@92. M?;,2I\PJ_C'2EG_&N ML3LE*J!!#_1\V$#U=/9V.) TWCUNM>)EA>JH>CLWTE>.8S<]CFILHADC/EM/ M5UO6IS'0N[A$--P;935!7PYYT-),7G)B7WO"Z#PY[U*Q;PJC4R.W9!_OUO": MT')\F?!EG>UK.C$ZZO.D2]H&,2TEW2@#5?H>M&LCR#C!OO,NGGNK8)4LW<(5 M[DG6L&,&U<*42HV_3&Z#)-UGCNT+KCIJ*T;95EE&OYK9O4O;B! M!Z $<*A\:%+,9SK,>O]I3"YZB%951%/Z0.>IL9@&D6VGVD'=*#?U:%F&-*=R M0B-(SWX2*T,\QM'YR5,\>HNKK15VMR[ERBJEE]U836_7>M*$'SUXV3(=M MC:4;,IP'8^LVHI3>;T[8G!ZRZHY-J!OJPK.4R:I<*:OY5D9\"SQ?PMQQ?Y' M^V+5LI-N!^6A'0F%LVT_1WL$6;9^EDJX-.82[]OY[FM4S"G8];1[] MYHAEP<+O3QNF>V2E$28(QLGT6X,8 &!][ V#,94U5]"^[&6[;'&H7W?I*TSP M4D:4IZN]X^2W:#U3 Z]I&O5U::6(5R/N\$PL2.H\)&C9^=\HX.1A27->\_J[ MD((-?,A X^SGA?I@54QEF_A0@>H[*0ISF7N?_W';MC_[L_OC=\^GCS_Q7\>[W[W_Z'__Y9OSK_]V;'_V M__N;O_OS^=VGW[SSBW\>_R)^^8?/EYO?WKWEV_B&/'- M_/EW;U)X$^M?YO&7^^#7OSD__?#'S^]_]_N?WOR;\]_Z7>W-_/[=Y_??OOWX MYJ_?_O3[=]_S2[Y]^^'-WWWZ]OV[G_[X%V_>S \?WORM/_+CF[]]]^.[S__T M[KN_V-@,;[Y[_^U/;W[C56[?>$E_]?&WG]ZT+U_^[N\>U_-^^K'_EJG[YRY^?/WSX]V^_ M]]?SF'[UKV^_?__ACW_Z]T_?__#S3^\^O_GK3]^]^_SQE]_Z']]]N;2_?O?= M^Y^__^6__M5/;S^\_W9^_-V'=V_"ER^]__%Y_X=WW_W-^Y^^_?V;W[[]\..[ M]?5W'[_[Y47PV-8E?+/>Y/K:W[Q]__&GO__C#__RV_RF]3F^?.:A?'[_AS?_ M1_@+RA^^D?_SS__U?_[B;]P?O_WTW?N/+(6]OGG[^?/;/VZL"3[M;_Y;?//^ MXW?O_O#FW1^XT&_^XN.GG_B1-SR+__[FMY\^;[Y%(,*;;_Z'M]]__]:O_^E+ MZOO[:_^>8_O7_UN;[YYF]> M?VYOOOF[][_[ZH_U-]_\PP\_OO_ &GKYXN#G?O_J!UO@"S^^_@(7]!^^?_>[ M5[^I<4&__>VKSUS,;U__"!?SVP^O/C>___4W=+_P^CNXC.\^_?3AW8^O_W0/ M__+5_^O55WF.O_O\]I_>O?H2S_'MMZR\5U_BLK]]^_GUO78N^S>?WWWU@USY M]V^__?K;N/K/ON>7KW#]W[)F/WQX]1 Z]_"[=Y^_?_OQN]]\^/'5U[F5MZ_^ MQ. F/KW^S.5_^O'#VQ]__^IK7/^\7WWVF;_^S)7_AU_^#)?^X\\__/"9I_/J MJUS\=^_?\<7W+U\-OUIXOUQVZ9>++O]JR96O%MS^U7*KOUQL[==+K7^]T,8O MEEGXU2J+7R^R]/4:RU\OL?*+%;;_8H'5?VU]M7]U>?UJ=8U?+BYRP2_65HJ_ M7%HI_6IEI?R+A97*K]=5VO_5997J5ZLJM:\65>J_6E-I?+6D7XJP65 MT[^RGC*73$S[\/;[ER]QT?_YYT\_O>/ZOJ2:?_D7+OWCS]__QCSUNY?;SNO9 MWW?/5';OWEJ^-/?^WK/U6XG1_>?G[W\<.[ MW[[Z:OS35W_QS4:''_T5/_[CRQ>YLQ\^_/QRJ\67\>GU+BGKG"PKU\_20+=_)?WWW^]/(%;N+3QY?7M7/U/_V7EW_?N>Z??O_Y MW:OO<+5_^OGEB>VN]_>OUM?.Y?Y(YOJ7SX8#%N#+M9*EOGGWU8/8N=2/[U]? M2/>>7^_2??AKOG__]5=K^.=E\-VG__+JRUSWN__\\]N7?69"^\\_O_M1 /7U MM^:7?WCY(O?P]N7RS&GSY1.7?[Q\XM+/ET]<]_7RB6M^6=HFL.?EDTGWY1.7 M]S^^?.*:_NKE$Q?S/[U\XEK^YY=/7,N_>_G$M?SURR>NY=^_?.):_L-+S#.9 MOGSB6OZ7ET]/G$M?RO+Y^XEO_X\HEK^4\O MG[B6_^TEX'(M__O+IQ6PWG[[C^]^^FH+C?2RN[_^A_PO/_#U[C(W??O^\[<_ M?__;#^]>UJ/IB>#Z]MNO-KGI:?WZKW\W-_&R[08W\9N73]S$MZ_2A)#@U4=7 MX*N/;IM7'[GF5VD\<*6O$FC@"E\G("[M51H(7-,_OOK(1;U*)X&K>@F)T>SU M"D&8NCZ]^LA5_?#JHUOAU4>NZO.KC^[C5Q^YJI]>?>2J?G[UD:OZIU/61J_KCJX]G=][_XFD'QYX^_>_OYY^\_ MO/WYU;69HGYZ_^&[5^_#-/4K-!+-5K]&+L:8'W]X^^V7'_\UO#^.3W_X;W]. M/OCS1/SDW58V:?CO7W_C/WQ\3Y3YJ^N-QI*-Q>Q7O_WY,SGAIU5/<8O__/FW M[RDTWKW[P[MOMVT&DO+4#AAJS1&K M#:DGA*.>85%]ZMP<:JF' ]Q7#]V-:Q9DG;[<:?MT5_\6C,(U\7:6=HX:;DG:<=R'DYM:OEZ3/T6E_%6>*[K M2?:IF\>"MRI^B=6Q'?613=ML;UZ#;SCWJ5'P*<\EWZ5/S8N6JG*^=MDH:K G M7= >22.A5O4?I&O,+6;M+(Z0T](8O_28Z;NG@:KD2"#6L]BY@=KWX[J4QP_Z MAC6I:37F=.>LNTB+;9.L<:DYU>*T Y?7P$=3M"TY!NBA<5$U<&C)PU<+^_>) ME6<^9DZTO/;>=[<6)<0=#H6DZINV?-0:WDZ MW?^,/![/J!X5J';MO2;/3,VO='1G>!T_M= M#NJ6-M5<%]:9#$Z4]1?J4XRPC7SSL5O MU?&OJ2/RT>XU(Z7MMI,LK*+[V)8#'P]\:+&]AG(4=]^G+4\':V4_I22-3>Z] MG.29E%;?N7\=3ZKZ/K3SY.)W#4 1*KPZU@(X8U>%7U')6I?"#JG=9 M%H?<@G;P$O:2^:+,Q3&U\JKEV/0'Y-G/6Z\BI4'VL8<4TGTZ[\E2=!2E:IB> M-/.4HI'OZU&HTQ'RHAU)8 7O>WJVIY1UX.;9VB.'T.F^L@8C)\SD]K8WQ\O":'U13-;$T.VM_ M3,\69ZE\#-E3006*O+JC)C;[W@=O4S7R.YR>[]P.K!V&@BN4JN'\/A_52HI^ MNDJ>2ZPX=)K/BK]E18L4C.V'=-Y>-]4%M"4)'IB MGDLJTOHH(AD\N& O:9ZQ6&5!5OI)NEW$J1+4OV1MCAC[/@;C$ MPDVM/-?9-:Z2?<2KKZ=JGVMHIW8=![?3UN^YU\1W2AQLM:JGQD/R&($5G^HL MSL*4Y\R:G-F-EHO6"&)C2I3.&KNGI' 3?]CHQ:7J5(PD[4]5 EP\'LZ M&ZM)B@/L4X>VLA\."*L&$#V*CIIIQ:V?1>)Y?*)F>DFU>$VD^1WC>L;M&+\D M#/6KV)(DQ$KT=4R-S;][LA*&FTB]Y6=KNP)=MT9CI\;IJ3NOOZ>+*#_6A''? MR2FY-V6EB +1D?ENO)3E?7S=Y]VHAK98V!I'DFEHF[CY^H+=S+E/%0 M+,N#N)[+HP%6+A[0YDE$<$;MY(M+P:,>UZ;\S-[T!GVT3>Q1J;G+N9*;EU]" MU@M94N!2OO1Q<,-ML0P-VKM^-7(_>2)E>W+O=QX7&U/Q8=8^64&[=T+%J886 M&T(_)J6X2]*6<&DG\1*Y-"YX=_8ND5?.Q@NX5,CS?,T9PV-H.T5.4B5-S0RG MR)18(E,X#"/!EK7CT9.CGE=QHDJ-$0V06+1$ZZ1%:3URY.4Y'!;N?GC^G?O% MU8\N[]WSF:I8]$T>4RW'"1T-Y=E6^ZV+>;HWO4.'I(K!%BKG,5MP*"N'NSB7 M&GO1L"7SIQ]6?/64JJY1I')(SN[F1?[?JT#F7: \'_4*;O>E0 :8JP+4US^0*'AWU5@5#5 M(D@VRI,F&:].82]K I)B44B)E7NK-Z@2\ZENS]AT5_&0\6X.:9<1V#E1->PD MI4?SRJC7Z'@(4XOY*4.3==XUEU!\P)-ME;T/26UI:@M$KKYRJ1WZ[: M9#_MI_[VG1VJKL^]]XMP1"[*EQ$%H*%22_.(O[^5>+QV1557&GEG\9U&HTNF<:CR:"NQS%S??Q0T6+BBP"XC$4K8< M)0U9RP6 %@ A&)!#T?ES' KO2W/DUSD3'*5?;;.3_=8YG!ZP6@([%]Z7Y^P* MNZ3":WK.STT/]M49IRQ$$KS"!4/>^W1VO"@M>T5EH+5B(&X<,U=2Q:W)5.<=J^) MOQWX7H>";N6F2ED2KU$R$70Q"U_4XJ_IS MY$.!E*,-S7_C?$9RCCGJ5QH/I:^D2,]>]+E1)C7KJYS#H3SM%77!R2[:PIZY M'#L^/85<]\'&.ZL<%>7KSZKVGAI:MZ/74Z,?4)!B'B-:FU?U!,-4UU*=C66^ MF-VL/(!6U+4TG^?U9=]+RQSZT20I ME@HJ2]5KN?.JOJ"#9%U3!H_DK[V"\1^6X+4KG*=A",NB*&A&RM5L3D&/HD]P M U?OU&[LV9@]P0_/+KJ;DZ#4C"=.]M:_7KVD +7 MS?"L+*/.?YI6QZJ5TG6S3'7=$HQ>FD?MOJ)XR(1)FP/)DTW"4I%,P(9CQRL] M3W"]5:^[@6)M9HABN9 MA8"C^,(AD)EA:E3DG.+4?)LX/35E/:QZB^'U$&'GK6N2/"]"?RX: YT#?%L5 MEY$X6/DMA("B.GT:SON=($,]CF1"UGW9N6LQ%*8C<:'P'"I);]>IY;H785": ME-*9![4;J)^7X @B02TNA:*3IV;H O7EN)-_'2\B/X&VR1 $%RY\Z&N9-9F] M]0%A>5+^4>).O:UUSE,UQ5GY0C5@?"=5J/\DI@(]$!P);WEQ9_8F&YCE(:2C M4"2BD<"58B2MDX"U]@0\4]8YKMK)!6LH,EUW=EZXM2OP L 3RN@?"[!*2IJE63G1L:\NM+5K"BRN>JG MKE-= X,RD$DZ8G&4@_ I,;<_RUJ"IUXU\ CZ3D\>*5%+ZTSID1?I+O7+M4^0 MTJ.82^ R!ONC.F&E+W*4F+M7(P^H7PZKL)W*#Z2BE/UF.;]4A 0'UE;22&0R M\TAVL!N+95)KAH<-IV:N)+QJ\?O(!DRRG]B5C:V:]DTOUD%)[V +ET MPB/U MVV^1D\3XP"H(1F%R[5-9MUK.D1YYP2'-V\%:'R$5Y*;2 F]_5RKNT"GF4)*] MZPB?3Y/1TDL'/SQJSQ-Z6:8UDPO871;KU'R["E$._6]IO]HT0(^#K.@NF(D( MSZ*7/^94:[B<\SI/N3HJJFIAHGL8F)SE8MD .*J.HFV',CV1$,IS40QW.H)] M7,^>3H?I " WJEW[:/DD%ZO@"%'\75'?"A%@CY@A+3SV<[EG-O5YY<=OZ]I MZ9ID\CBAEI5)(":J0:\:ZCVDEDF-[%6?7X+MI520@O/."]\+GR?9_P[@@4 . M%8VGX5H!0(DY"@1&J>514IP:V(9&W0%8[BK;1[,?2\.A9*I2)Z: OB06+N6W-J,]^6FJS<*>?-Z6)D/;U-DTI-,/"<\%4H-76T8 M=B,(OVM4.X?SU_0A)2]B TR1:B<.E/K;63J6D M3@<2SZQ^H[4^7RG:;]W*F-U@^E/+!+GK]@X4VB;E3>K-I;W3G$1?&B?' *?9 M;0 ^R4O6YJ"0K?>EC]C5?=KW1S1<&!6 MNV51X% )7I9\%MHT:/0$= M1;7/8U)4]H,5XZSV[#9IC[3KLZF4R,GSN[6DYU%N7958"P=@T:6-9S0P]%M) ML&,/0?=@=F)15UQ36*%VWO7E?1RRV:TD04AZC>FFM*NIGA7058Y%J2:+7C7" MHCJO2O\29JRA=/9\^%T @VJ6$S6#[YGSVFS0U.6OY;34($< _C>5VL8 M?.HH]B@RI"GS'8VIE-Y:JI:DA)/U"OMPUWN4E[H=T^DJ[>G 'C=ES$'5JQE' M(&U2B5)MLQ T0B5K= 6(KDN6N:E:M[-T*JTE86^?6[D)WH9KWE77O^VY0!VD M@SR5H\O+:_-> 4L]_4N%0W[$3B51Z6%94'REK714&/J,[V*_;A@0@;2(0TJU6U+F\CMB*(W979 M5K+!24D :S8%@V-4LFKB>GL<*??8V1P L:(1X;V-JOZ'8T&@Z"63S,N9>?7W M6%Y4.867U>W:@%P4AV+M+>-GA<:)Y W<3VJ38+H5KI&-'(LJ$V1L#>JRZGZ@ M ]#IY%)LW%#V/D[P=-#QJ<<&<0XD4LF^-EP*>>(.F[S@YEB,AH-E. @/*BQK M/&C7YY-]8/'&6R0*@J75VGU4"R92I$54'NHNVMG=AOSOD4\>%EG'?:K&WYIV MRFK57D-WQ8?(/13BUAKX473UE&A\V/?:99@_BGU2\._+O&5&K<$G(3JN$D]Y M 24/FY.J44.K3"D>%7(G"%PV]ZXZU1Q1V\7>2IQ;U\ )P'$K,%1TM*?,GX]T MX4>1'_[H /J%*LF>WT=:SXYU$LVI7X V,H;.J#MN/3:-6HNU.'/NBD-3L214% MG@#J#;R]Y"O23(2>($P%\9/8VU,5,M$ H=[*>[")-C7\Q$WK)6LZWJB^=6Q1 MKHYM3\U*N5"HJ[(">U,MJ*1(\"@:H!?^:! [ <=5!.=^(VFX4Y.?NKV:6@81 MR!FT(^=55QN=;M:Q5L7:M-W\;1[ $@>M?.&=3#B-N.QM-8=7F)MGT36FV!% MX:9Y]@5\ESN]$SM(#."]0P_X6P]=SI(V[37$CK)*[GY39:11\P:EE M%IN9$-AXB7E<"VS-(?U8S1WJ] JB>CRQ"&K\V*TV<&V' P@'FTYI,L&94[MU M)1D ZZZE5G)@\EJRRQU4W;:@/'DQ5KDE_1!Z% L]. MK)P*=38@R6W+3F'@7:DKC6PGT:8MWT02GM40]S\W>W')]N:@P'>6$2QQVQ8& M3@W)]<6!4>Z'H+ZFQ%DO!%L I.XI*NIRM[K]1S52X$D1Z8CBFBCC_P,+B>\$VC=P+0MGLS% 6/#$A)076^@3G#'G1ME!B&K6$<<6GXX M@4X=?LQE>./VH.)3_XA=P+<%_O?0J->CCKZ4'+:N4XA.>TUUOKQ>_V.?VX$Q M;7DN[?24GC@]\1P@^TC4!CK8EM;^Y;F7D"+!3E$U$^?M=$4:S9>LP?"E\T[P M=,83(NKRP$;3,X,83ED(XM;?:F);P7?>AGVVD&AH+R@\.ES:V5R:2VF"!F5 1F*$MH3J5!E MX*NR:$AF*:OR&H!T4W5X7;Z5(/)I$^*OP(9/&R#%T\Q]G2_J4JSYDN;9XPQ" M'<=A3G_^^**0JD*'#@W-^IA=*' M?@=ZT5)PIJE!&256=CY2NYQP#(H IU@28';?JBK]/-/!OY_+= 'X1;AVY!&8 M#%91ZU.7PGCK6:?_V9E=EY0+O&=;SCGOEAF[LQ7W\CJL/I,Y5%W0/"F2%]1S M69+"6;=2+CHZ89B[J&.%U-J$SZ88!*,GF3"DX%']8?N0-XZ0&QJMLV%\ * M.P_O\4B!%PB /CQNV>9O)-R.P.;%$PH/+OGV,#XJHT"@Y93D(?)E F>G9+H M(^E:XT,=>X(*PBFLE%- UUVI!)'K:CM[_D'Q2IG_Y; XGDLJEPJ.AUZG@L=$ M_J@PP57T5E-P\"1.A,L3:D>26)T$$^J^T\GS9]-'6FU(7RZ[=YFR%X7)+9@. MVTBZ51*4P(]4Q)YV'-I%G"QH!U,%=]%]].G>7)-I-[#I8T,;]V)KD<#5FJ-L#QW^Q;808>G&N980J=50+:*5'9J M-2&FDT!*]6H5Z_3H?3E'_9!1%,ZR*M$7C'>[A:60H]J5LS)LK5V5+)$@:8;B M0F"J%)PF*4#VF9R-4A5:_>59''=.2]D2G+:IZ@J0) P16;B$N4XA*!O 0[7X MK"AA'+"66Z-9DLK[11FTYO0S:^Q46>$I-DE*IES5\A.\QN^=Y02GL\3(DQ0S M?74<*:#XAV1#Z+QM[H MDX--[ 4E/KA-2KPEFYS#\:3-QT]*'+752X*L'H1/@K3W'Y=&3 MK8;;1*I*!.]89'PI!G+J(>N1"R ]]2QYY5:T@V<-DIO3J3[2J]N<5:R'BTTK M"C]S9M=J*VL@Q)L@(;>EA!I8V,31?JN7P>LCU1F!G7MGB7ALG:-X@R>P:^E# ML4' 8UE>[)KNN4UM@M23BH>D O!J3>8)O[X.Q?OD=F3-3\,>6,K\6_7,V)99 M:U5%94=_N\06)I _*@C4:YVI# 3[73^56;,J_ MV.]US)5=0* PUX'4"T7 ;M8\(4>SE$S>=+$ CI=(&0MJ/9KL>"N+E MY-!RW M$%9X]FG@T@.32OMK5PRS236:)?A$[;#N_>U.GD M?L 3-?"M]3FI$;![JJ,Z%#)Q+JWS5VZN2V70]%U\=S*$Y- M2-]5E #D'K[ZT[9\L6*D_EO6Z(06-M3&/W1U3$@JIZ?ZKMH#O'/N!I>C A7U MN+L.\N+%>X^=BA!$K&B%(O,4P/G7\B9MTSET*]4C5*FK9K50=E M'0;A4#C/>GJB263))>M*J3IL?F1B2-Q*>7-W48LJ4G!1Z@Q/&SV+93'V*0]$ M8E%E'[+?#YX[5SV(.5'USUO]1F+Z(&DW7NP&Z@A2$A^P55MZ@:JF +)\?6H M>)H.$*'.2#PI]ER4Q2'W)#OK/U0$UE!#(P?/CM@90]D_'PKXQ*,I#VFI4GF8 M; &%@X_12B2QMT1<5M-2 _60=&1;$W0J.AW<<#) M'ZV9)YP#"+ IVG'IS-!6D.GL');/H (Q+/,"!D']5,=!H=+=QCP96-TE@&/R M(J@8XO))OMM-3"$[K E=9\R%4E4PW)6P4D5=EPBVP[0'0_&CB=!#]#CNF/7I MRU8;1[('?S_^4+,;"X0CH?"MY[) 4J(0M#UF6>8>+7ND1#36/QC\&A6M(/Q2 MCTQ)/VI.-55)BRU0-?R&0LC.J@][65-?E RXX!N @6$.\!-YR@-K$-N([(S= M25Q]?2H(09/*=5BGJJ(Z(-2._ AKIU/R@<_FX;FN&HB]DI6),41S\(7MA5OK MDKE,.(7]]R[_*>AS"R)21TY_UK$*:'9*W>P.^:S ^CK;ZS1?]$34/-IJ0,,H MWN*A3'U>D#%>:T?E^=@9]KQ! @)+O&XZ_1CI#HE4VM422_Q1?]73; MCBW.H0/[[%)-V5TV_/!/?]ZDH= M" @O1;:*C*0Y*19*4PE%A=ZKJKS)"F3BD7QK:/PA&L<^$XST:/"]LY#S$"L#<*,\GA9!N3U^JC]6&\MS,B& M]TYNB5).01VJ^P==)EGT7)PAC>)_]KS%+&&M201MR@)?'LTKMTRA[X$Z(8&Z M)-E8N12,.@%;3Y0%ICB0W./,D^JV"FY@:/2PGR!>XB)C3GE.?5A^J0%K]=@O MF\)+3N/2M(0'M^1)+M^&\J*4J:RC>]/$(HLC*$8D?XWIV1,9H ,&R7@:\E+> MZ5I,6.?!U2^>4COO7DW.*CLM"%CJ5 \Y49F!N%G%6DKZH%GWI-9]LI#WJH"7 M __-,Q:*,U;!HXK9T!%,J,S;O%3+GY0[!!P]Z(1OI"""F4A-Y]/+,X"TNG3B MY4=GY::S]>/YJ1Y:>1TX 3GU-]V;YA<'&X4Z\E:_8@@"C7>6S>.U#H87L^>-89^67:CU7[-LI25-S,\T6 =4L@EN2(%]M@SORL+RP M-R76:3Q*8:?C^$A@;3<&>#PMIA"A9>.W$*\B'W:R]&/O":#0BA8UYZ-6.&_( M!O%:'U)N*CA<]HAM_S$7K2=I=W6QT8%B R1./%1QA?),$S%NZI$-4UEIA^?J MA!V>Z"*GJ^21HVESTIY7[Q M/''JNOED%:R&YR$YDPFU+.N>P?!DV &$3"F 38E,\ $A;]_!4+;]1I?!^5PY M#G8;"X@@1D%+5N;'F*W:<*E>J'$EX 7I[?/Y(#MFI#0RKEHXLY!1FX.+/-K=UZTRGSV5O7 MG%PK)IV?]-X^]_AT#;,NHFXR%O''EW\U>P34PM\'K5Q:=+"4YOE0T'JO$I=U M\CHDLI)@KH- GG68R-H340P3\IXE$+0!KJ39\1<\1"8&@U$>?42K%9FD9O(Y M6P6 37R\U$C2>\E6I4HCU @:" ,QB+O;/"2QUK,_M^80;%SJ1'LOMR*TW,PR MO%/.K"D>+5U5<:BOT4LC_H!S#4T2\G@43Y+GK#N][#_- M02ZSXJE ?"*P4ZA>=]9D65N@:]=7V-.,QRBD'*''#T/7!-V_*3ILW!Z6OLYJ M@,D G!9>NVQJ=K,:?^M\F3J%8F:3(K\W=H?+?BJ7S$IIS3=GZ_;RG/#4+TL? MYDA\54O[T4MYU ?D?3_#W-D\! 12Q445GEF:S*XC""$MIJ6HRG\565:: Q 3 MU9^YI")0TMCFR]3/H$?_>-E[+AL@YBFJ?5+J\N2SCN?\U_XHA+<#!QMYCC1< MG9:).IA3V5D9Z]83$K_GUL5Z*$^_G2Z876X./ZQW0@)'4L,G?9AOZO73N*+ M55#3V6A.M%FR2;IO+$8@E41/<<9-FQ.5>4#6(_ >2UM:]M:-S63#'R@2Q9YE MOT.Q1KU]<>GG,B)/7]KJJB%.(FU2J[0I455M,4X39]"KA^3_*WO4[&8XHG117_#0=,AUIB>I-\4F 4%HM&B/_SC5DRX4 MYSH&'6QKW82&OK]',V.+8F;>D@;26@_>I_3MR]X\_\\PH8$'UP(P ACWTR[) M(9= '_@(4IN:><2B>30HBC)T PIX*-(D'5+D%,7$]9T2;ZEOU57>C?;6NX>T M^K2PDY223'+(P,+=PS=E[6[;T<25V B@U##6[[XM@BY/B_7.+E4 E)NC%'RD M/NY.ZNA%MLNHK=SX,ZF2@2-U ]RGN ]I[QKN?5#"T>.TT91 M[Y2_M]RXH1IB6R^2TDDJJ,+OT)3:)O\' M&XS[.N.-VKY0Q0Q6,*E'\Y:Z41=YSLU?B&MXK=K277I,%F37\CDH M$O_VD$94O*SF.<^Z>Y5OPQOLVP"?L7N6X?-!;*LZ(^G/!,0-57,6*VVB.KE:9DB@E.Y?( M3Q'GA(T*FV&YY\IHWSVY':T#J33"J"&%#A)1\;: _BFM5=U/5=F]@]O3K8G$ M(ZU^*1 JS$A K5P;E4$85!E'W^[DK$7M3H(T;<^EZ;"@R^I3>^C TJ4,44I: M*2N/JSU(K&#]0L#K:=D6\." 5!:5A!E/T*I^:&S:"<2I41?<4BB=;8@L"OTM M$SXEOVQB*/)%6#74(13*'NK+6.(1)?*!4R^@D5LZ;U=&L*OU1>D#Q%-13>7' MDU^MEV+T? P@4"E'1!*CR$W>),[NYW)?!@W: N5%J+^KA<<>J6-XV!8Z1%,V M7-+L_'[TITJB(TUJU$W'V_(:=]ETGE[].-^H@Z@R;'CGX$OMG"B7GD;,LA]TNYJH MQZD:QLAQ; M@OI*&]K". F@DZ]&6<#88^-WV6W0'UI5L2&74 >DWD!YY&[YTKQULO_C2\J9 M;$EN#==.!:J;04J7] 1'4#?2U_(0I;JY/"]C]>FLEJFH]',06\24'0MCKS;I MX[Y/:EB>9&C+#W'8?P';Q8VT3>D9E_X\F-/IUDLW*NKU[M@G&-A1LXO\R"_@ MJK2WU.0M@[+E+/!(A?8@I;SE+Q/!>9]4L[8H%=8'7WFN=3KF1]P'N-X43\(P MFRL NWA-:Z^21=V2T 4@(+M6@J/VATUU_2M=\M3'(":V3&/IYWL^IBB_K^L M3V)H&X,2/_%&^TUQS;;(U'6/E+'K\F"?WUE)(WHGQ]S9/549T>5V+H.BJFA( M'"1Y>S4.AV6$:@1 MBG,,NV*^ M0_CB3"'&"LM^YR,1OFB'+F,_B2PCQ2L943\RH&'H4H%/0A3(EY0:^.&J?F?H MZ@>G;;1S%#H%!_V^+\6"K=$#0(:OL2AOY4 MCP>45', R4NWD\=!Z$L$Z3$NX$\G.@_)+L\4M$\ZG.$3 5\W^+H^DC8\R.7% MWDKO2LX ?E =LA!37*F:]Z++S0C5B2V]3<,RTW/DE_!='+QI:H6?3]92H,@ ML% 1,B9 WZG5'$M)S>U;8E:3W?WLZIT7C_RKL\$:+W*)6=G2L6HRTL>I)T+< M=3V3KT\)3%8\G/N[(L_PT4!9ZXR.:>P;9G+';F\KWIEV0DN"DJKHNRC)*!F$!]2> CI :G"+*V(2;I MHTG<(7V#C>5<3GV(YW+YB9$24=:A5G-:!J5Z& MRS)H;JO<^4FP/&N4 K%VR,9VI4C7O$$.4%FS6AF(1>0#90S2,@%Z2A5-RT6= M-Z"ADA8-JCOH1UW$VUHK;KMF06HA!*+DGHE7\*JA3]=P.5[ < M6*-A33A[INHQ%U TBZX?,&UY/,]VX$R]D&YG]]!X"7 %CE!U8CC5(K7ZO"0E M4"-1% )BB[S5[$D*ETC559X-H*I' NY)DG0@=)#ZD>I&KA- M*E,%Q+L6AAIX9!=F%=X#7:B$I3!Q=Y6M0'FX#P<66"^[!(2ISYOC)[RP!WBQ MIRPUXRR>G;&UJV@N.AW8V<4@QU,1?I !H%:6A?,][&W;UUKC[@)DJDO&6'X]57="Y'9F,W7^W"%^E ,D#!$"QCEHF# M,P1%VXB#L' Z+FGC[\YW:AOK0;!J7C@1 D5R(K@Y+,VO'M+#>)H/:Y0%K$-24L1# MFEOQ$-U.?2OZ?2;/3A]^&4GH=G;@LH7-D^(UK.)DNBSG(\^3H&9#]'9@? TJ M%DV#0M&2*'GTI].J,X';13W[W(IS>(IHF]NQ^RM2:O&XFJ8\8ZK,J\E.4(+\ MF=)#!NB"&H$0-.6ZG_((N3+6#%6EG1I2=Y.S0)(F*.J,,AQ&C!+, M=U5ZW( M5@^K4K:X"L"BW;>70#E>"&4^+#:=&NZG2Q6\Q*VPD<9';/L(K?U<=P M!EPL206AO/VI1]E!K;G-Q[ZSMNV2C#SA.Z)F=9IOJKL06"Y46_/A>3W)XS;W M*4\Z*M]>]9@BV9XLIS$WF6^ .%,N7]7C$I!'%I*VKVMW]91P&-S6^Z5HIP@\ M@ZQ1IW\GHS)4QM;*8[9ND3>FW/3NXQ$YPYO $($N:KB M3OKJ60,!#U@;+-@&U6Z-$I%+4=GN7-JU90_7$@%A' MW%(E@?>@C88$/Z+,IE]&HY2QH3DU(CM=09>",H C=A)E09)PZ"CAG4LB8FU1^*%A=2O<#"D=1TFZ!42S! M2.R73BJ%I>E8VEWC1H'L \R>F5:1B1F8TA\T*[WK7E-9U9!Y[BX,)S\UW]9? ME94Y>6>7U @;)EMR*JIJ 2@&JRKMNU^BSDT\2J VA5:JBBX,QS%IZYP&527QZ>KX+#G8R=@!#\#IUQR#W>R 7BD7L M[@GS38U,43E#O;8@09@*^Z'B=)R.!VSI=LC38KGQMEEWSV,S;;AJ M].XKB_) D&;G7*2ZE)T!1]',[L M#GD:(+ZD"<.D0M@*52?A&"C>;UG0['I]XA_=X305+$I]F(2P%>1G#:#W+))_ M0-UL?Y(8:?MX %F;OHV>146=$"2UY%(6'TA3"@I[6S.U 2:B(P7D)S*1VNE% MD:YV<64\3,TP+!'/PP'S0ZT:FQ.!8EBKI6+_4>F2X60FNW'YF#3])?G59EEGD3D4ZV\J.&@B<74W-UMI\72#(=[/;1V1"@ M\ZLL/X]'HT?>1JP;^X^'-C-8@K)7SW?]CR6-4)P"#X)SW^1E#2Y>];N 1^RR,GVE*^DFV<>-@ H_SW JIJD.Z"TBO^0 M#AUSN@.+4H,=9]Z46SA ?/-BB[#/'15P)KQ[/GR>OH-C<=R#D#[K>>=II2N& M'$.P5TO&4'[W<^M4D("%>\V<])JT:=??YSB*XZ!VQOC7N!RYV:/%@1&U(O2[ M!C@%"2+D:FFC]Z9A@-H;ZM$5W06GDV(2BLY])_F=RSB)9.RLXVY?6=OMR@"C'B#&QS_HTDY(BX;3 )> #&H9LRUUHUM/9< M6C^,D-K-;5Y)OMF1M'(JN^HCHF*2*J4^D.&IAZ8\SNP;U<_ ?R9MV"/Q1*]> M,7E4M>+8S+'+,X603J5QZQ%SIY,0&U5]Z3QP)P))RJQEH,RUC.8LQS3DUCS& M0IV;?70?B5JMD8!4GG(DY%AS+.Z&2ZN28D%/&#PU+G(,N!'87"AZ; WJQIN* M)FHZ,O;M(1T.CTXL+.Q^Z_&H%T^^J)=9GB/(1%=])GU!U12-Q&6;2VYTB..LPG+77*#(BNNYWSU,DOE.*<+NG(@\\1Z<7 MI9JJ"%#!UIU>@1EP1-(%PH Q3$/,H=R?GJ. M[PZ4;(64,-A>SC,!546IERZ E J3E[4X\$WKJC5:11Z=LDD <\3YIJ@!I9/4 M6( ZA5AUD/4Y+28HA?B+>Q.X\0>)GDE_424#R#MN>"I'212&DH,B,2?'AV0U M$(199ZL4"<\:!=T]8-+"^?#D*@'PB&B$DRS%:<:H/%WHR\@\>TYCK^H2-D\Y M'M)23IU'>%U.)! R1]+3";%E6GO$][V%E^D8(9^@?;QIR.DX5[ MI2ZD+-NG!/!7Z)07( J* M"BHJ13#333U^"3,D=4?"/;CC 8<^%,#9<34@NZ0_?KNG"TM 9Q8>?MT]B)2) MQZ(E/O"K"'ZD,1"N'HRV__6?O4FSNDV;F:YXZ8(6A[]B M&]D,KJTA#PM@KR.,D$5@#ZI+2.$HF5B1P'0XMN3V&IGJR>*)]0/;C MQO906VMY=DTMII$S;BQ09H!1VJ\S:T^ENHCX5'A",.P0Q.X[H.+]'; "G M33_99&F^G/#F 3X@;=[3F>KJ^JNR3),\Z:H4:SO(G=E>)P7% 3;:%=<,O1>= M@4[[T$5*P%1QUBE\:NXS*$IV:=PVI,'8M@'DGVC.)1Q9 ]'DJN5W(DO:K54$1WCP04 M=D!<%G5[HFX:\0S =*(!E71RLEE=G1M@2D!7=\FI 0)BN57E\6"/"@OT)MV. M'^P;E0%)\92/0=UOA]4^H0*O/._F..,.6NG=LTD'#BAV6U[*K25UH@1IN^G$ MSKL]-G(^@27G$IP?N"41W<5Q-N"DHI27QH'@O(>/'D,E%MR(NJ4Z]'U/Z8 J MI%(-G%O)JI=,97-MCLL:XUV"' "-90'".@)NP,=5LVN]HK^GL]QF.>Y M(*)''MLC#COR6IX>AJT3;9"RPDJ>>O.J% ;R3.(NRYM/^6'6!34MV)I:T8DQ M(L,D!RS[+YLD=W.V,GMO2YVM-TV7];%7&LXV85+H:K=49MW__^S]2YF9QH:::EOI#I'NZOVP4X9Y^# M??8^@%G!&5,C+8B!?*WB6%6LSI/'QR&1G+B6HY@ O-OA7VH$_M- MY"YKW(CR=B0=1Z.9:%"R)0?$E57RS=X\T*'BTL.]9'Y:(=6+RJ=R9;L#KLEJ MC9M\R#YUVLI_NJ0%P##P)I_.="O:U>*R+54F<0E'V.-D=<@5!$(##SQTL#O3 M"(0"K[1$.)K'7P?53CX]LN/O3%4C/&4J2;VW^[#1,A[UC)44J@#DL*SX@.8F MYI[<0)3168/PPX/*?BKIY6*ZG2$A09R"-R68R8(Z05*M'.544GH#T1NN=@^& MA4R7?75Y^HHI\%OD]J+^LXI@-F5LQ5DX7KV,_>;2J%6U%+]9>YM'$]1K!S#% MM>U9&H]/7<<=.)'T;@Y.VJH]JMRM?N$$,<*Z R@R@X@$MU5?O;="\2-=DL3% M^B#T$9\H6>Y'WI.,;DKD0S\[*B=B)!F3)0K:/3U<5:&#',8V"4M*2HTZ=C?) MM^[N$1!'L=(CC)#/HFH3SFP!V&Q^*T6M1YT'0S*H]J ;Y*$"4)O9 5J);>>\ M6'!CR=6$9]M0Y([R?BG\'$X';;?B=%0F-JMW M#Z? 2'>U=IZ4K&Q\\H*: NIG\VR5?>WJH_#FP7GD3>V9Y5L Q&3&D6$I-!20 MEDY1E1?W^(:/3%3$:>K$&DG;@*%FN(G:)3?/@%0$E278'<.6ZZYND))MU3GI MJ<%S(F76$IQ&4;^"/]E28J;D M3 U;7E=RU3()Z?>U[/:63@W!6I?3::/$QM=H^D!V JNT-9X\5V:+P]$6CW:) M$9?V=_J6$TD]<5.&T7$:69&\LE.*T:ZAK&=ZET<"N\B:PC%O/$CJ7U9LT:O\ M IH#WH?3D1:XGEY.9=@4)I/3-8UM]0"+[Z@D@(7'JXK]_!L=?+Z@U/P)-I# MFU.(ZIVOLY3=+-]IF#N_51?>+029'Y)'K?&+HSM['WM1&JAPP_+!6<#=\0MI$_>^.=P@4*RVB]D- M8C.>\HAU[:5 N>:Q^+B:&@;3-KI,1"O-)(6-5S_77#B7L#V/ZAC.5FDL[N'> M;3)@(T=AMZ<@["D^7)_Y0IW.Y:KNXDA%8F^IBUD\T1X7Q:O4'UE\/#RG;BG) M,C%=ZM+">)ZK)N"^PTN5,*+J+UDE\CZ3+*-KR &[I:'K$MU)WE.=SR*O8ZKL M?M_<-K"%:BHAZ2 .]3?GF3$V9-%=1.?%9A?_$V#Q\I8?24^A:F$M( MG)NG5#VZBU,@&IW^(UB!$JL"K$! ^\Y.P*KNK=P<:7C3,%[5J-O6WY!UPO:_ M'SXB6!6NUH:JP+I2*QZ@,B&WE6[P3)=-%WNWMZ5D JGN8J6>BFEUAZ)5[1Z= M!:,*5'-(XRE5=G^234H2.$Y5]$GJ64?MI^U75O+[*./86A*%#C7?P+GLLD?[ M "(^N+6Z KUK_YY:K@[J.%?/RN+:64-1]6@612 [E;3U16UE1Y+_29;DPJ@F M6:+4.4I&[MA.'YX%NDK?%#O'I\, MJ0XEVSX\SZ28#&''$[*A\\,2!R9.V8:AJK'_?TU@*'N#E\'*S(X"/\ *-@?O M8DT5/S+5'W/=J5/VZ2"H:"]0Z%^7PN-=+6=U>%6+VH@ 3K"J5\ =9Z?42*// MK9"Q1>68F/,H[.]>VR?2=;XU!5VM 7LH/:B=NT33VZLZ#O\B.,FQ=1_8K:\5PA?^B;_>U,#6=J?1A?\7'3PG>U' MZ#18 X95C*I=3J/UP>U4HA(:3H5IS,X%\V@]&FUU RC5D)P?D-VXQ 7!T\NT MI2KWHPPY]0Z(HQ ?19]+V!?<[;C*H*9_W)J[ISY ]Q0H#Z^\A@IW0/H2 M7. M^Q)'5E<;&_/QX*0^RDSM2JX03AL_8RSD(,*<:3$#-HD*$'7+R< MWYD.W) %)"$Y=J8\#-.9M=_6ZN3,U;G4P-OLXGGSNO2$:.Z% #O"2C' MY5*>7\/24"WPQ6G5DIH:4S<:M8H\0!A<)A?@;/4@+>L( Y;W0,$ .X,]5,;@,3*]/W.(U>Z] MUSMW0J@X<,)O1K&OXHJR-(:D@CGQW(-SD/I@*UU'>:,"_"8;4[&@0NY/,M9L#BF# 0"1?WLK M:P$L69-M<_%JV/:$<"D3+%)P[DDE0>ZYHJ[W*L$[Q]#E;K('M*B1<:-(F5PG M*A??AGIWH)KL6#OY,&=*S!$)#N1I)NKL1[S3JS?IUYM0]&+F,A.<%O M8:R[R-/8>Y[[$&12UOS RE76MF<(_/V-7#H%*I+XER+753RA/)5..K,]/,\R M>:9\/OBO4-GE.UYU23%3-TZE8-6 *?78G)(_-= ,CGNY#.52L6&J_<)$,B/ MTDX>'8XE04R( S6 DNY[>8@X&,\BX1*?35U%JCD2Q].F$^&%;),73XN8>F:> M#2%&<:TEK,.?=0".?:!-4>PJ"ZO PJ^":;7UYK!]DM+!(=!:)6*L"!Z-]FAXVY MM-7DRR5[K>Q,10/5Y(A@;>"#].,QA!14&#S'3!M8L>#0V2?G?I86&U*N 9@G?86.\C\ M4:O:<]LNAK@!"#Y?RR8RB>+X@\TZHP9;U!%!>?ZBG-BM7C-0 M.'2GC.QR/,X "$%XN-(7J:?8LUQ3&=NAFX65L=--*HSTK( QQ4#KEW(LO,_= M"44N+; 8;\]DS%';X5S&L6PH@&913H B)D$.VNXQ M4"44"*Q9RY-,6]3X=21"PBCX"UR4PT:.Z91-)#4I![?3=&LV;LV\2&@-=FFE MSSFA7MW[33:GYYZ4-L\A3YL0IA+P%F0OJ4 FYZ_:JPDZ\SB+_7CP2!AF*1(R M9*P3GE0PNGIWL-96?CYL#0>ID935Q\6.\Q370[_H?*9G](5ZGZ3G'P82V2YX M+'(.T0PP:.H_1#8A.K)7>!4L.'+H1I4J)<_&ZRFE,U..EX%\ MXTWU3>0&&:LSGNYI4]>=?,GX G [N; 'L 0H1O93$>2QVFOILK3+7-8"ZH"W MHICZLT99[2CMU(#ZY-CT,#C6^]FD"5%)=_(;FT:1.A9TL=%EIRJ3 G:G2;3% MD#"HK"8IA%"75(\&BNYVFBBN2\J;I+SY*$7#NRO1(WT[RL[U.+5ONUL9#" B MNT^"9?<0YN@ R>X(E]94Y]%'7EY%I.R6=""A7LBR;M01G\N/R4,-8.DPNI*% M[">N4YO;^R3Q%E"OU&KG("62;_&X+"=<#JT2!T';/=E+!L8-R<-@FAW\)S> M5491\8BCR_1.2+Y+/9;?J@0(2'S->Q&OHIJ'S\ ME/L@79.-%,SWH\#6PBFKG^.)&^GZX;W):*:"I:@]7:U'=.TN:P/^@]#9NTXM M49EN*CUN23\\/L-IHZK$_Z1HW^9MM:W'!2B4.$S,L5&ADN]HTNR<3DG$QNOQ M+1UY*)-PE67B<$I^OI1TX^9@U.@PX4_>6I^ 0CQ*^ MU*R/P[@.@#N1DH;E-4%9\*#/L\KH=$*].*X-OLA;65%BGKAFK^ M*K>.NB@,[+U].#\!,FU+ *A(,M)8ITP>$.CB*LX_-R(Y*]':- A-#-#=MH-R MD)?G5N?ZLTT=%\"Z'5BMR,HF,=G\130 #D9/XV7S/XHK9_LRU-V>&(N@P)L4 MH)0(]T6B/YU8O2AN-(_4KZ1N$EZ"=3)%8>1CW.AN/]X'B:"HFF3RN7(2NRAB M=-HE"U2.CP%?=NC=0@?D/1N+L0)$I%YZ6$%FX&''ISE!'I5\[>!Y=3 !1-.# M'2=D8_:4CL*#(K<[GT3&)JEMD6TC_)&)E:RL M!$X>5\I$'[4'QVVC)MW%J966%%7F2UZ]*F02.0DM;9VCQ'OYOIU%,33]3,S> MVFM*]FL/ZY1(?2ND2-2TJ+TWW@( <,K9!'$N*J]%Y)#>I(PG\=UQ=DK:ZCE\?R5*Q,:'3_E31.^B\>2ML(@^/$NF*1W:Y#E9< %J M03,6S5V+JX6?R*55ZZ]QIVL+SE%0 ZK+;POSFI^%(3N529#?%754744Y?YSB MC?_V;-+30%)J*ZK'D?EYJVVCHO$(7>I?-@M'V5[95OXQ/+Q;\[?KM$GA7<]X MG5JBMF$7DK*B2C%R0_/E;3H9G12:2/>2! !'[H-JXB:1D7L<:62G:2KH&ITV M1QPGY1.6 J"!-"SM^SBWA4AU+9"9)GGI] !"P3YJ:- U?S=81).PNR?MGL> MSP#[4]&Z#+9VM#%3?K:-YR&CB4P!?&W+[@2DP/N3VPK$O1U]?LKIV9+*&Y<^ M>8X274H)$-:OG:TGO,P6_-9[ET8:9M:3-4Y([OICV5!RL)"U?B\9SJ8G9-XU ME +-9&5%56\;UI]J%6Z\UJZJ(J!$(TVKUD%%ERXU&#S*!3,$=@/OEQ UG?X% MM5"CW4\"/P HG 75_\]%R^,EC\ADVYT<)2>*0RD1"%C//O7M5#7!HSEJH-%D MX3RZ]B4[81HY'3[VDV6YG8Z4JG^CO1*EL&]ANLYN,FO4"HGR2+WHJ4R!1'Q; M75W%8=65*6Z?XF&=^MX;<008$2EA50GF9[2"FP?[O1S]L->95/%64FC-*[#8 M '::?8;5EB/;UB6RU8]C _E?"DL3LE?W9]>:HXG/4ETX1UBXT'?\_/\QWI>-0R.HW,?-)CX9B:!]QN$$E0)#DV M?PU/UY!,YTT2JVJ4[/^Z27U4BV_<2JTY$Z]R@?LZB[*;+7+"TPI#5]"C6,:W MI=LDB"RJG%0^TV39A!0 ;5"ZP=QCU4GQ/@\)0S0U+&J>:L+9RI$>=J&42I2[M"2I$R4ACL_%*06'A8,!S%1.:6'@.' MR,E=%,=SQ;%SLVD5E5,\!4[ M IQ.=;EKGN1<'<_N4=PFA^,>4D2UOB)D4#([H$3AW#46D;*FC$G0 4V90^4L M;[;MKMJA*E ;Y61)BKQ-E<=R5-48X*EX6*$&&UH -JI+8@=O2LL_1SR\N]0$?$RG+/TV M<)+V>?O80V)O%BJVM,H74IAM?_T$U((GU35/!1VI?T@%K$NG=S3JK1X!=;$X M66,NV^'(.NMC'?L;P\#EA"-@M"O\\+#59R=24R%.^+]3Q=F)U21*G#R6U-:0 MJ$E(3IO,H5JB0@5]20&*B8G8%.CIN!UAR\N2=3'-^WD7,I$C6.><^L_J?P-D M61Z0^Q8UL*.^[-+?>[9FNG6[Y[L'&OONMI>>JR\/AZ:(AWK/BB M:?DA S,J5W7:0M S0)@#%' PS>'PHG:"._$VJ O#>>]3"S*"*F7L[O%==YKJ M,]C3%N#:[3TOB4O9NQZR-7,"P7F:B0_=WD 2)UF2",A5+^6D,T8'7YN&P+5M ME'./?Z0?@"49-8Z]J9"<%3)W K>JJ"!7VG$/JE?*^.Z:E>8A]_Y0N>=JX)>M M>VS.$^:N]131Y;$#BT\#X:6PQ>6I*>D@*VTH>$ND),\CNX>M(RN7D59ODF>V MQ'"+DW#&1^(38>@@0 V@59&&VI1USQZK5%@5X#HW)1S MU,R:15&4N%O=//Y7=V06X!]4O&0])SU=B:8*I[#'J0,4N.P:U75G]RC:ZZ;R M3&-![+&K]1-895,F@N9Y%"P\''VXV#P6:A1(&JL?#L2H/SYD6ATR5#VD/C;- M?>9M?T9-W4 :!. T/:6[.J/2RM4>%G\&2W"-)ZEN920Y;1@USM0Z4S6?35-- MEHT/4&I^SEV'E4>A.I4)R>=1!@P!6P;94,!K:;=I1^#0A)/7O#R/\:YM>;8K M(J\E<;Q6T^ ,-J35O93W/:8^\)XMSUL^O23GHR[2IN.2AA1/5%F/5"CV*X_+ MJ;3;V36-P-A_1W=V41*)!_6[<^S*ZROB+J9YE!12[/:PS7QX>'&=&P&%$@@P M(G&RZN<^]1OF@:2DB-@977NGAO=! SIB) FJ2)0F3CJIS+9@^_&O8?-0CWM3 MA8RJTY8W8$L+/-6E6[&NUJ&:(\M%6[]Y;\00AA1V5) M,4KRUL?Q*BK7@^";G;=1']DF!4'ZH)(.P22L\"N?%FP8\S*6YLC8]"F?CUI] M/)4E'Z/R"0&^>VQ"R*-X'3?_T9>'?/>40X>@EP*T%[OJ,,C--/!+/$.KL75(B@(DH.]F8 X3GPJD+# M&%/+#5O2Y-I+C75@?KRD8 /93KM;N@(#;&RI1D/O!#ZIX#3F .Q1MBD,K6WV MM8"M#O=/V3W"T,R!BU1%HK&D15ZG8Z#E,Q,YJH6ED5I2,2#,S9;[%!K)+G1" MG_A"_J%D)F]>2D"!T0GL[2F)3>30QV4%42KE@":;$B$UP4ASWUC09Z1:U5%! M]TEJ'X# (/S96:P>$3Q=RJ4-%R 4&]T#./UN>%.Z[Q#6 7#R)#9BIEI;%A:^ M'?U/PS 62"K-5,#4^MI>:@.W1F;YJP[3 OUV%RS_I-;75[:JLJS^49. &"G!B*3AQ>;&DZP['.Y.IEQ;HH .V> M4G0H+%JDONE//1Y2&>B'\I4M]6#)15.P ML:Q G1=P((Q:,SVKZRDM3O>BSSG.#F*UJ_#9%34=:@["R]"59,UG0;6T,:U.LAHFY^%.AWP M].) G(\>);KW.L6>])S2VYDW$80JI[(,IR>)P%W5I[?'>9K%G6XZ;WZNXIK2 M\V==I.1+6R:VDDN_D'./97RP_"O-'*PO9V&UVGNVE@6$>D>Q"?<,;AA$]2K> M>#P1.,4+)%-BUC*NOM1=Z^NA'&$IM>]Y\"KC+IS_L-/7"29YZ6&!DW9 U;-O&F,'79)-CP1,:;1%Q59G MA<.1JOPGQ9RI4:DU,Z&*QZ#9T.&HNI79U%IUEK,HC9>:5<0EO8;@F$:SFCF3C7JB'@HLNC,/*K@ZL>0.SO@?JY50)!_0(SCIM!A9E;!?>C69P;(FND-E>0SX0VH<(8M@-F+D3FP$A]P_B7;]O*4 M%S3%6A_&[:Y!GX8U?)+=:Q:TP\X\2$T?#/UJBFPJ=^U+VX%7H)$;:^W<':9V M$K91Y3LIDNQ%F7NZVCT^<3FV'M#,2 5FO"+_*U]_R1!IRX?F5DLJK3R>25,Z MI8,; '/)(S:%H^MR3HAVB<9^Z536%%8)/,1(/'. #*P'BGND ]F4$\0-H#GX M?B]KSOXFPRN4:L7._LX.V\@9>#SLY*7*3CXV\LO%A>[1 XWQV>N'X':K>+XM4ZZC35+>8EG5_][7&H?=G$ )/55ZN:ONZ&S_TU-P5 M)7'T01\2*="[?G(4?_<@J?.WJ3[F?);1,L6I+N0[/V_%KA-3U^JQ4;*%QT%P MF?LRV>R9:1//[4R@D'-[;>'OSE_FO\# %();F&'1/8M2+9XQB6N:LNMJ,'(% M-53IC!=%H.*VB]TM (L: 9()*"<5*Z$FH=[4@SPY42$]P(+5ULM35.Q7*>WD M>0IJ5FGIM#9;PSE1><]10OGMO$81YX[-5GY]Y'DE7A'U]$H9IR5!?9H>5W)( M"/G!:]9P]G(L0D=S6YQ:MK/*-7V[G@T$H)(;65*K,;)=BK(HCUU:7M1TX>$C M5$'Q&D\[0E.%R,QZ=H[_E#_%0_6H:VM ?E)HT?Y2MDZYBC!*SDW=FQ5ZU[S!$NT4W(1"%&2K@Q] K>F(,KQ MF,<]US^68/I^%7ETE#./E3WHJR,E MJ.OVNA^JT0T[0+,\CD(Z(DFEOBDN>SCT0V)KGJ$80YKG#K?T 0#>BD]4*;SM M)"D- -L<]^1G[Z>8%[AIKIX<0$0:$IQ/M99XV41F>2&ZPE\>+3]&.!XI_S\H MXIJ3PB#41."8)4GR7(H2G945M^G3)DY/2AMD;5B<''Q.^>0G8>2@NM8:B"TC MY_?1;E1^9CM](E,N):_2A[2G;=?,]L[+*4\R+^_-4PNY*??##W:/9-5T$U]2 M5['#=\=+/=AR9Y">J;- ?N>\-P^H-9ADLWFF4C1EDCY4HA(31.3A=-^M*%V5 MA=_L\77*/>6D>(@S5W5V;SG_FS.A2I Y,=VK%'K5'10-4S;I '<17[CC&K M_:$YT*F)@@>5\EU4Z,C'70?X;*UH+B&"_QJY2?U\!6;MZ $+#-Y0S640USZ:,-Z*7KF M1F8[VL)J04Y[4!K3 ]'MTFB9NO@J10^)Z)2'IP/@HG[??)KM>PF9MN&3WC>L M_ BDE\ T58 E#;.MC5OL3?6"[)M)-R#81D\T1[:U34KU_%XGO35$=(]@$?KP M\AQ_S,^*R\J7&%#/:[N/>[DNNNYEDXO#E$)=VAIL&,*3LXWW81N)#0O@L!!7 M*;8HT'G.ICPA &VG$..^B8[1T3&JL^<%/;DO9>0A8>/\4 M05RVDT7L%M&4SBN*#Y'.^&=5\Y;D!OLY3BIU5KY>G0107:GJKB*=U!>/"$>T MPA,J.YCOT$GT*'USM*0=6G8EESEQ>9TU&_8 G3,X.%;/[ M ) IP5^37<)QWSP+T@1++#LUQAQ7A! M-REE%0\SH;!H\]2Y\V85J6#7R""ZE.)5=\)6E+LI@G&'3*;50%L&-DI(WE0B M%!@17+'<7LZ-$E?3 HT5KUOS&DI9J9&.%;(E%,DEN %68PZ6O9(RJ]/ORNE= MIV?J"IC)SNN;XJ3-H0 "S])_X[43"BF'-"R5O]_4\P0($:.,W,E)K*1H-)DG M+\_5\ZX/0+"YT7GW0_$;7HLFX/J#-*TBR=+/3M3D(:MXP6>;3\9489Z<*2EK M=P:IBNJHLS6_XY%W !R%Z6@ZLGM,85>WK)S@-&]WJE3_NZ18"=!0SILZ]U-* M'R"&D.2,Z=(] !/K.G,TV;QDUM[/UY7J"@ MCY[E,C]/BRY*M*M-FP58J8 ME=OYU/W8J$B4=>/3'XV?RE/U-4S XNLD(P)]EI;Z'9T3H-X'#W7AU<$+)9$_ MNM7GJP6'%[>+?74HO]"?DB]P7",7 BW'F@:(^Y/UMM#&T.GR73MV&YV^ZFO> M^73@^ 9TL/?&QN;KH(]"16.VJI/M]9!1/9C/%*+WD'##;\5%M!81++?*:A62 MI+XHENP)[VC;\N*X[07MBA?(;]+AA"APZNH!TN/=* H.'%/ V2%KF;Y+5EP, M2 %T$Z,?WM(V'-NR4:C9(1EG*';M&5.X"Z4!+V(N-S @1)Y$<7F\IV"(#&]C MA;*2X++8\<]V?M80N:?G"R+3H"BH79'=:D*E+\(&FW_56#HQVPS:#]OM\7(( M6P_ JK/I[=*@-+M$LKP^31$/'5%V9/1>S4Z1!^B MW%WED]7"IV#5/C F_2Z4T"8SJ8JI;G@%RAZ>\*COJUOCF-041.P#.* '%XB( M:+A$L:A @*%L!LJ2H!'6Z"J\4UU*?J[7WD#.V5HR/TLCD'_2>(CTW)/3U+N# ME<4V/DB DFU;9A^1,/WX-X2O@/@NP:Y0?>:B-J^*#4]TH%E=S%U'9\JHYIB: M#E=GB55AF+I1PNN?T%6$Y&$L+WL[MT 0#;_)DT5=^4$D5:HZM=6D5*,L?AYN M#83W@Y\B+6WR6XCQPH9!?DW'24R] 4P2M\-0VV#H7K \*\C4CCO>]IZ$D7$- MVFBND*H;F@.TZ5BM]WIWB[E&N5;DG-8JHAPG2 M1$CNC3J $/16NGGY;!:"B>Z&9*FV M".A*=4VPQT:1U*JDX1,$;IAB\2CIN]NFJ5285E7LXRBI,7@HI0=A=DZXN;A; M9%4K=#<=MSGJTF=0EYOD0);-'ID2'>4=[EHR$)"S)&_%664FL#-UEE,5I+%U MYW4K),%+V&P'2D0 4 %D 7W[8D8VI7N)C$Y1)V&09,@"LF8QWE*4R4)+V8^J M6!JT'2-U0^VK)>D=R_CF*4$;":#H?3WEX*4H7DN<<>86_*JF:7W",B7K\U([ MT;)7ZM8C8_?NB2&5*JI"?BS*SRMR?EC4QF"MLSK MR16NIKSMT_BM@4WWI+NI7$5@3PYF:C5$G,E4.]-*Q\)P3<@$J4K$#5VLB'58;/L&IB+RR:@UA"G0== MNJCJHB6B*?)TFYL5". ML1$M2'PZ$?>ANI(JG?)\J.4#\=*! (T3'EL9!#2/P S9M^VF7(OLK ZP=?0B M;_HI29PF%1#)=WU.Y8#9GV\L&NZ= Q@E)8- 0D?WCMCE=S,T%: MRK03%*TDY(MGY3><"E<=19'P6X$;K?#*>GM=PX2NQY)JK\O(*PX>G4/TUT8> M8 'JQZ76,H[S2@ K8>FNV1,H,*!QJ6*7VAWFSS%*)7&5(M'JRS MU$T2VESY#B_;^P2)0TIM7=JX,C\\3)/30I32Y/YTLO=2!E\^!%\NPI_"K99; M5)H.;Q*(*+X/]>T.767NJE:Y^BOL\9T+T0-2+[IA2V9XWA:5<=B[-['9S#SU M,WV<^!71$L8HF0AZ44,"0%"M6E.M1H>4)]:>8IH@.F+IX\ M1W_G2ZS",(D56Q7CCLLBMM1\%/Z).16U*3>-(U,"-FFQG3)@-T5S5Y MMPP^N-Y+P[I^. 6B\Y/&5R>P>S\/]2,50/#3AY+2Q'Q'-:S3EV/-.^#5U MZAY5@2YUK+6^U'[MR(K@//J)1KM!SZAL([NO@)IHQ"+GLBP'U K:F,>/5<7'=F#F!K:'6/9@>D^J=&FZH_$+@I^G9X (8T5 MY98FT,XS.L!YV>=\O!GVLGUQS[*(((N&*=B7U^>QQ>>A078;^(R*3BI)'OK1 M74[+L^JI5MPU%X_OECI.:?YH.5RL0/3-HIR=H,UR$NM(IDOL<7/T7TJP+8^L MH52Z]4D_;=TIST^2'N9+'@]_C I5HQ[^3-!'-,L+VOE4:Y$YE\H3O#T>UB1E,2=D!/U[P5AL[_ 4#7*:?>DO60GMJEQMW*%W$G3JAU+ M.%8AM&7U*VSC5Z<3"(075V%+H:FZ[< &250E7:>S?Q3K('I51;)H/2*E4S G+\;(Y5PHC^0DZ][N1;5:=@4DCT$NJ'; G->)ZB#OZ[A9UG^2^D>Z M++M#_NP5&S2\NQ(LV_-5U2.6U*4#VIS['@@#3]H]EXP6K.3-6%0!*5&N>?>' MN0L'U/8UZSA8_23 \[0AL5P<]U)58P+$D;2ID7;EI3.XF1Q @:X"!* >-!JT M+__,A5)\RQF0*W,;];RHQ;6:X$%[K*Z@_1.61/U4&Y-R;LRP$=F>DPP?/?-5 M$YO;X &F7-'^-(8O 5?J*S3B^//5%L NA M6*LSTV?>FRNAJ!.O+->3N!9,]^0(JGFJ=#,?&>KR5(ZE08$S\F-. C/R MS(>N:DJM'-10_!$**-XN034JJ$(FYREX\_O*)M3*#AM2"; LMWW9*X$M9_/, M5(UG?E966+:5.]=4EF)RE+V'^N9AS95J_*'$Z"XS3JZA)M:;AWKQ&&;%\W"( MR%(2('>[CP3LJM80/?KB91(]9, [%OHGKX]UP*C0(;ER\]V*!.--F@Q@ARD@ MS#.JO;5&1"MX29D0)\@ TY6:LDL;BT.7L%TS;DVBJ*J/0X6 ;O[XI%E^7^J\S2,^BYQ&3 MEJF\AQ9DNI@,EUK>FKR'+6C>.,MSN:^+"*_#5W)M(,18=V-4Y/:JC/ST.=-^*$\4;' M$ US^(OG(R#63=,Z+ZK_\NBCP;:R)+TLZ,\H5XZ%ORV]>]XGP"\NJ=*=VM%F MR9-OGB,;*&@ F9/3]?O262"<.L\!+NDJ:SCRY_E%3!NAWND#@O9-673JP %P M)"K*+,Z34-856D^.:VO:&[+=)""M%?P>FCQ.MR8;=ZH=[;'G_Z/_L_U_'_#_ MB@_X^MN7]Y]^^OC=^T__N&W;G_W9^/Z;^?'[G_BO^^5W'[[WO__R7?_K^S_M M8?NS_]_?_-V?MV\^_N;%;__Y_A?[/__3N_TO0KCYI?[IY?U/'SY^_[S_Z>4O MW^W7%=_-E]_P'_R_O\SI+\/)'WG7/_[PQT\??O?[G][]F_YO_:GRKGWW\NG# MU^^_?_?7[W_Z__\5JWK[RLO_K^MQ_?E<_?_N;G'_[YG_[IY=./ M7->[?[.N]-^^XSJ_^?C]MW]\]\W+;[>O_OU'_MX+5_-_^\+^E>OZY8?/G[_] M]M^__\Z/7P_K5__^_KL/W_[Q3S_Q\;L??O[IY=.[O_[XSOV_>^^?7D7/G_KPX_SPQ]>OOF;#S]]_?MWOWW_[8\O MZ_LOWW_SRTO@P:T+^.I/[W-]]V_>?_C^I[__XP__\GG^V/IZ?_V:Q_+IPQ_> M_1^!Y[KS@_S??_ZO__,7?V5\__7';SY\_[MWA/QW[S]]>O_'C97#5_G=?]O? M??C^FY<_O'OY Y?ZU5]\__$G?N4=S^*_O_OMQT^;;W(_]W=?_0_OO_ONO=__ MT[?BNZ^>EV]_>ONMX]U7?__[ER^^E=Y]]>_>?_>;;]Y^+[_[ZC]]>//U^>ZK MOWG[=7GWU=]]^-T7?ZR^^^H??OCQP[>LH]=O7OS>[]_\8@E\X\>WW^""_L-W M+[][\TF%"_KM;]]\S<7\]NVO<#&__?;-U\6??_L#U6^\_0DNXYN//WW[\N/; M/UW#OWSW_WKS79[C[SZ]_Z>7-]_B.;[_FI7WYEM<]M?O/[V]U\IE_^;3RQ>_ MR)5_]_[K+W^,J__D>W[]#M?_]?-=+OZ;#R]\\\/K=\.O%MXOEUW\Y:([?K7DTA<++G^QW,Y?+K;RZZ56 MOUQHUR^66?C5*MN_7&3QRS5V?+G$TB]66/[% CO_M?55_M7E]:O5=?UR<<7P MR[45]U\NK1A_M;+B\8N%%=.OUU7,_^JRBN<7JRJ6+Q95K+]:4_'Z8DD=X8L5 M=>R_6E!'_%?6T\$E$].^??_=Z[>XZ/_\\\>?7KB^S\GF7_Z%2__^Y^]^8Z[Z MW>MM'^O9M/?^W+/Y6XG1_> M?WKY_MN7W[[Y[OZG[_[BAXT./_H1/_[CZS>YLQ^^_?GU5I,OX^/;79*XG]__ M\8??O[S>2SK7A7_X^'J%B7OY\DDF[N2_OGSZ^/H-;N+C]Z^O*W/U/_V7UW_/ M7/=/O__T\N8G7.T??WY]8MGU_N'-^LI<[H]DKG_YVG# GR]5K+45R]?/(C, MI7[_X>V%5._Y[2[-EQ_SW8?W[_N,Q/:?_[Y MY4=!U)<_>KS^P^LWN8?WKY=G3FNO7W'Y]^M77'I__8KK?EZ_XII?E[8);+Y^ M9=)]_8K+^Q]?O^*:_NKU*R[F?WK]BFOYGU^_XEK^W>M77,M?OW[%M?S[UZ^X MEO_P&O-,IJ]?<2W_R^M77,O?OG[%M?S=ZU=?_V/+S]]L86N^+J[O_R'XU]^X-UV%S?QF]>ON(FO MWZ0)(<&;+UV!;[YTV[SYDFM^D\8#5_HF@0:N\&T"XM+>I(' -?WCFR^YJ#?I M)'!5KR%Q-WN]01"FKH]OON2J?GCSI5OAS9=^)]' N@N++[2^=^__,E_^/X#8>:OGG?*1Q3BA-_]^N=/ M)(6?5E'%/?[SU[_]0*WQ\O*'EZ^WK89\Y#T]L0XU[)MBU4LD\8XV'^-S>'Q; MM6&.1\_9PUMI!.K7.2WCS$)1;[TLY6P5@^Y\WDZNQ^QAWA[OG*>"QZU[UME[ MF4E.[Z//7%>IZ2B/M-)TZ5;4VQ5KT@+8A9>20O8HC9J_T[,:%2.,6;,.#--C IM9_8AIY'WV.W)K];89FO:CT YL X[D3-H:5U"-L!SJV6^1Z\M%8L33NAK=O"#EVT;4 6B")S5S#77FFI/4SCOR3]SCJ?K[C-NL/1TQ#W[FY'>36L6R5>16*NX\ MEHG[GO9YEQKLNG)[=BT5I*GE/CS ?CR\.=?I+N]0TJ>VN@Y,=26)3R7_6@]7 MX-ZZ5QK&4\\IV>50KD_#L7&D>C@2ZO3\,\[MNA)W[E%FBU(K5-MD$3NS$>?5 M;];7Z4PJ-/3M9TQ:%^C<*>H)&C*A6GTLC[D- 2)QEY?_5H[-'J0: B?Z=< M"\55'Q[J>?&W[-KJ=*HY9'P4I';,>L^!;6<'F/_>9)^J]YSO<3TCSUL",@N] M>S"UCHW/TW.OO=P.!S5=M4[NQAN-_V MWN_&_ELG_&QB6?794QXGECS#3%V/F:HM@]9#^]GNL6_UFH>RUDIXZ@C+BLB> ML#BJD4\GO3_SYX_KN'H.3C#>=]SSW;HN" H9=.?BG4/<](SV7V47'!Z6[\[W MCA)D@M5S[*WM604?W@GQZ>(%]N4KD1U&/LY=Y8PZ3C4+MU.7%39?/[@'EN%I M:[I-#0QZ57BMW-J_LH?XJ+TL1KNKS\/.TI-:?D3D?6FU;TKIQMA3*_NT!WOH MK\/]:IZ76RJRCF4@.#R;NIJ-RF=J/TPT719+\=)&\1SWV)2^83L1/KV[74DY M'9!D_X4J>TWQ-+UO/*<@!#JI2T%LI646_]3.-O-< M0,LB'IY$KN2T'$O.^:C>5)2[5:\;H35BG;;T@\>2>!6=[93CK$_DYX['PTB- MC.2!J NS'P[_)44!Y/\]MP&4O:'X@]HUB].A84[KI^)3O #-P0,Q-'BX34P\ MIQJOC7C:E.8)[%H<)L22P^/4@^])JOF$&EOAZK1^[X=:2U3KJ]I%*0+ MA]Q4+4V2&GX[T>3@O6N.[L%@5W-%J?ZQ=P_E/%;/;!8^)&YQ.&LO8UPZ86:# M$II(3%6Q2![;E3]W\=6A6[[ ,95,W#M&8 5=@8C?R85J9)3-A=%X[7%(GYF/ MVE<[P3?HR*V6=-4O2ACD[%/W0GW'YN)1':QE!;$NTG39[_5V)5+( M8%=AFB1RG)Z_Z$SB3,BA+&LGE=5;RY53"N!2KK[U]".AYTW=!M[7Y*;(?!XO M]T.&D'I\#V_)C9YULXMZANG-=+"KJUHRSF<<"I@&63Q99Q/R-TO$*$KR"/8A?U(+$9(%%5]ZT21!=3 M8>5ZG?%XYBJ^2]NZM$V*O![-N[B=T!T%'_I:+KV0FVBRL<"4KJK+>^M0M97G M=2C%D!W4XY6SJL?%/5T@OL,@K>"?M(513Q^_A#[1E0P?GC*;A+L_1..YC0]3<W2@%* Y M,=-45EUNL50V_GL2GUX:'WK==?N>\E5 M[E)"^<54+F?M.BN59S^5/6QG4H1$=HVGR*1'YYL)ZQL7[\B2!#\E#/0<.)^+ M]+J/L.!I6?,S^0!T\<<(;\/1>[UY55!A\[''03<$Q+SI[GWU,X+8/-9<\Y?# MR0?5BXZQ+*#!!%.E$$T&QB)X:4K7+IY_D\W(CLB=M[01/Y1TD:T R"1?2YJ5 MQ*?>6/]G-DAQR#HEI6<<='#D9C%X!QCVU$P=E#+W+7@D3YY56BTK+V).5@F* M5-YDGAHREQ6\3B;.^)7>?+M1*\>3].=CV_7_F1NA-Y;#U?+HV0NXT-?%"?=; M<85=8B8O67.E:\E,$E", @-,H]Y Z/]H=KBF' MA2=\1]T02,8K%[GIBVXY:5G+J$4E!5FN$R!S$V4;^4^'F;/DCZ*(?@>R=S,Z MF%\LK93RZ3#XH^4A+\=C[BC/GF0+E)!O -B+JL/NBBQU)^?5D%?H/"0>G@+Q M0:%Y4)@37R+&16Y>@J87@(L2PR$?'B\?N'G<3?%W*_=[7^QD8H,^!VFY]O)! M3;L$L/GMJ#(8_@2QG$:XKD[5I8"U6H3$R[&5J,-BTIQ;")V:\FK6 MG%C3DEQNMM9'G=5'K4#!5EMQ#;.Q;Y;,V PMO+@J(_%NBP">U^R#**,9GY]S M8=MP*!!BD:M)&VCU5Z(#Z=#_F#H*]"B9OVTY.95W\,NG:?-1I60WQ017-9'FYK?, MOY3MRG:R[PC+1W-:ME%?I4"&5\N-XF++.IC6RN\Z_'& !>;)K>E:%@[EGXZ@ MEW:/CKUI&L%KM0VBA;C" ?8[EH,"Q<>V$\M#T$EQ[KR?R3+K>J%QUQ0F;"K0 M%9CE:>"H7:D @,5(8%#V;E3,5#=NE7J(2V"-1 $23XO))GJ:?-"AF*@;N#O] M1F /%A3+1H1P+^]/>C )3VT()>"4VPN?R:RL0*4G8S?WDM2:)GL)J)K4N-)( MW-@Y>#0$2M[,49< I>I)5<] *6?:;VR7,_'5.5_6O9\P^DZ% 2QUR*M0G1!N M]+HCIBI34GDJ@*5E RX)S[EZ$S+52-A"4QV)ZD8U+?<3!6L,@$20EU;V>14* M]F&RHDQC:#A:N#R^0WY_=+Y=X?VZPB;S#WC/32A!SM+1E>L:1,)K7Q&>7,3G M#G72EN>@GE[4D\X@4V81F\];&0I@_J7SG!;-.YF;"LT .1\--;7Y B(T\M!3 M5.\F\5!\J8O/)M;B8VH8H/8H0?KI[NYT[*?8S7^;B%M@X. M2)8ETQS*_"D5IVHN>30J/E^YG=,,#BUTF9#J]\J5 M/8DJ^5;.22.TL0HM,_^L;"1Q^%-63;D1UFQY4!U2N'/%>2DDJYC%QHCJG"BN MWBLQN#35;!1R:I2]TI2UFI@/VUW-,J [W^.%V3!2=Y+U.H"S#J,!IWD<9@I0 MF9X8<^$"+IPZS\;4^H- .Q)4K=2S0PG6-4JY=4V?6\.U=P>U A8Y'6Q M:"[]><2=0ROV(B>.[$A]#G(,EW3;6Q%T#8>-3,DB*[!HVD%;31P'%TME-/3U&-:(33,;*0SRA!N6@RY*!&8TFZ M<%4LNPE@SM=>(@#;&@=O7),/N?J$;4)O6$J1;+G3JH\"AQ#;"UA;(Q[@Q>&3 MOP[U/-*A?5>CB P[A0K=U;H'_!X[8-GI@KT5$3*H?&J9VY6+)QE07S6YD+Z MO'Z33E5UX*_Q@)![RJG;0;A[?I8![1&W)ZEL>K$I_T36"RH6=4UT4CV([^>4 MU5S[*B,= MF6\_BB)%ZVD*)6)3 1QHI*1^33B'$@^@(*.5;G3)P=?G<8\/I[9))0^12Z5K M!9E&8#E2>CD+2?('*9+=#:05^)!./=DIQ)Q?SGK/*7#)$EH"[P2/K!\P;]?A M'])=:?K;JV!P6WH##M3;/U4X()GST?>Q:6=[4+V,1T?F>Q]+M)@7300INV96 MF?5<-<6>YS6.H14J (!,-_A[H\K_MO'%H]S8/\[2DG?.J>AE=<,7N]P\YUU] M9>HL!R\[V[N&OK1!HGHJA2PI\9IEGHG-Y22AQ .8WN?2Z6D$3O:?9I3#Q]O[ MH_URT#;'5$\$#<[LZU)Z:2?$3_'G-/2^ES%MYT4]CP*S:MOH_:/>\ER#&Q,\ MD#2NW$EEQ C'OF8X-0$BP2RD31@@\%"@ZB,8VZ5@89$"*JW<#I =^:2&_N#9 M1_600"GE "P2 -A2LFNI:W>E&I5??"* E(6V-06]3E^O0\C.BC?MERJE(N] MTYQRZ[91E9V]J*>NL&* M->N*ZK"?<43'.C7:N+9E+-N=6M8.@Q1UZ'5$:T<-;R;/FVATLZEB.4 M\WK$8[":>FEORCIO8*"M[<:NK'RB=H_Y<$:QW;"K?G$]20%,QK=")BR,J M4TIQ"S21MYRS,?SR6-5!%1R09#8BT;4&796,ZO;OBG+*E(94 M&#I6D*5Y 00EO<7Y=M%9?@>BJM6@PR]_2IT[:I9MG,VNTG749SGH!'4ZW&+6 M;.JA4H7+AL9&C %=V5*LX-&4!"S [64G4.YNPM $C/7^9+'H" \^)0EA7 MG5WM/8>N+A8B*0T$8BE)G+G"=+# 9E_C H'\5'#43JP&#X>$>SS.)<,)_#F" M8[%3Y:I;VV.*TW+9=%7<2R$O2H2F:Q*[ZI0W_Y!0$@^0-5J>91%<3_6W":!Y MD!8T8;0F6+-WA-R+G09XTYWVLLM,3+U59M-9@TU,B5B7)F TZTJ?!WB10Y]; MZ^ZB'(6CM&ZOJ659=A*EJB-.>$P:)!#[BQ.\)'+VIKY70_LURA3J!$![$+7T M*+CE_JG9P8,$PIN%#LP<"O$,2>OLXGD]BH(47B Q:+LTT-3"AE H-B*H48IW MC;ALNJB8J&Q\(:SL^BI6/RFN?EBR6_>41)#E;Q+HB6?3KM4DJNV>-:_M;+D2 M'=O-T7,$=R5[X#'50 MD>FL2!2DM K.8UQ4W-TQC%O5\-U3=C:]0@S&&M+&9I^.?ED,' K:[TGOIJ"2$-M,B2]"HR_8T6)=7!]/\:HS^&=3 M+R\KCL*2JF(3N+:%I16+#:R]^-9 ,H4%SQ R$G% MJ;BK"72O$Y9LL#X.13:JYE-SC;K:2( M;G1>4E7OKF+E?5.L<^N@ 0"M@*#7!EZ:Q\H!G4>EH>2H1 M(!(HAW+:.3< QC-"8KM?*B2 #I1?I5KFXO,,U^;Q(J#TT#KF\QAI!* K$ZH6 M^[,TGKD9P,/.5J-RN(?R4WL5>39;A(Z2#?8 (X5 BD'PU8]*CC#P-E":ZGUILW7,[;?13+CH6V>QWZN-XGJH^ M\-CXLU.;H98] Z2:=4*=;[#H>>E*=E6C.>]N'J%OI]A2BVY-E):<35K=2U/B MT%IBRE9H%76 *<(,Q;L=8IPZ)OI#,>; 5PJ4&8R2F'1_-D MID"6Y66HDF^: $GI;F@++1:--4[5>YMJWH07Y81.Z\UI&R-H.9*T1E:B-9 \ MSB4)Z)2D$F$/#ZGHLYEM!9C[I ;<9$H@.>6H0^.;_\-R;1=8*R8S^P72L-)) M(&8[,<9, H$']'>PU[I3I:E$IWB]YCJ!,'3ROK8[6^B?NX$@: M0 5:6=&S;E+542YU#9-N/8)TA0(\@:0\QSDW9Z.;NO('=E[==!W-=GE56V"C*C=!EUF1-DJ2(Y; GN(#>[MN!0.SFH<42"Q$ MWK[$"LL>EMM03:FH.^!!] GH]P/=_*7D:RND#;U%[R6W;09U34E+ZD@11?E=S=FB M\WL>0/>H[>Q@O1'8V\-;YFKGFD/G(@B7(6Q=''X857@ARS2X=184T(.8="]- M'WT\+MD9;"#MW\>I@7%5F93U[(";ZSK;/=#D7*$&0K8&ST!%U_VN(Z!J)VSF M1LVG+9 G#=H")M7]QMBU!]8A)[.OIZ)VFR=+5Q.E[4K"L7Q.4,Q].!'*0FA< MLQ4%B)59:B+?13>+;H&4W'5T^48 9'W0NQZ2P]'@-?*=/#J2$T4V(:8H M>,35@'R#])O:;;TK/DY=0Q C=W,3H(;BD21AL3S&SX/\14FN+2M5F8=X9Y-U M ?0VO^2JIKAE]!BKH7AZZ&"OS890 \1OZ;JI_97\UL /U'FQ\7E(E>7^J!XD MNTK+$7(T=5.057:0OV_C-]O4JH_PLVM6M^EQHP%28C-IWD;<8WVS"XD05R?3 M]26+I-ZHX]&4TCNEVJY#^!BWB"3H/E5IQ+[S/#, G\V;AF*IXHB61O3:FJ2HU0/,B:VB\[ M%)YL4<]<>%'+"%@8S OFW6HI25G15)X.33?E1X$__OI)93$US;RH7SPWNBMX M23_:)AG-8PC6T5H@/ 7;RDK.%L\^5%*+=5/R+4WUC]BJ366DH.@V>7YZ J97 MC5[@W>IKLDED)1#I"7+VXIRWO_5E(4N2ZEA+@5PQ%,65I%$U(^>W&@" ZEGK M>MY44PD?&'VJ)%+DW#2%#&X]KU5%4I/V&5N,5I%4P(UXQA._M$$82L@KF[B& M>G69'HKMRQ?AQO1<+$J\:BN_#I%XPA,4$^&1B^VVS"@3_$(FT M>-?4?0;EL8^N,0K]['4\58,#0H*>N&VI[) M+WH\WY9E[&4-T9,*F$%2ZW3A1J+=TAK6J#8K:C)%EJM&58I? M5P_9ANJXIW5>.&3D2C96,/FQV"9';H#QR];#4#45X)*5+N0N1]?.B7U-]GP\ MJ$PS=H\U'G>^GMQ''UHJ7.HOG7I\7!M7JR'C5!RYJ2\7/7^C6MY3[K8^!L\_ M*XA1=YV$KL6 J=0CSQQ 97##\GZM//+M5KK5BI]5%P?]C9%@5 *8=@F7_,8^>.>*9;E^"K:$7AWRX55X)^U/+"LKI3A.N+ M3!HH1'E5N_JF[-6L%8]Z<\DH<@*$@5"MAN,HBXVWGWK4.4SO40TY"7QAP5]7CX3*/'0WKO@.4%/L[FE[J9 0 MNX\Z')!$6) ADKHF39_Y./N:K2?O4@=HAW#+6EK68T:^1X:G)S?LS$HED]0# M3:1IBGD6,M6WIK9:!8[!!I:TH%2O.T#?YUW]Q9- =,DUJ$M.N,SEM1 MKH,U?.^/GH;9UBD7F;N]UJ&>J_Q,Y:I.0$6IE>=3/>8X9EWBYI%@FH'4ALPE MNQ=MKY=E(M7U#$F/!@ !5$G4TA:3&MTV_;P4*;H:$5\]F6.)X*F^Y?XHON7D M1>WL$C8DV]UFJY&,D"/%KVLJV\&2JV1Q*-C2BPG^5 MB[!QJL*R0E'S7OYI43]+@JEM0GYRA*)0X:$&':".5ZY=A#KG:XFJUD-LWZ-: M"G%754.Q'%:<"5LS,BZ9-+\EX 7AGL6V.*JJO$=7F3Y4<\438#5_."T819TN M;=03@*"]MX;=6JQ) RYJ^9TZ2&H#=J[=ERV1T_38ID02-N@DZ<]T9Q*9O16N M51,'FS%9(1#R'ZN$4F]NQ&9MF4AH)F$PXZ.RV:U,IL?6*KP#;5RO'L!6/T - MUJ[--4C;AFQ: BT@D&U.A<2)@:"<25K/-B%3D6>2W()S64[Q!$G60WH\^?"0 MP*-48I-H>$OH*$HI;TUQ+#4A 5A2>Z<<-)(L[\@GUH.\,"[B_M.)AU(;X91P MU( _ODP2#AD)1)ZW4__Z,_&3J5+#Q<7NTQ1""K!25U:41$O/^0OE3!"KH:6EFTDE(MOJIR5\1CS0@GT)*B_I)RNLN0V\&?G\6"I@YL23OE M.B])B0_1N=[$W[P! K0UNE6X);T5$S5UF\12LAD!3 ICOZ@PJ+X(WN0J/V:P M\YXS<57'[2C(368MH.UZ>)#(5G$P8YFFS!LDM;!3](%FJGO>/;VF,FY]4;3?VPL.F MKB&TJPM+[?(< >B;VBUM6)F:IJ3Q+?6.HR.! M:&7#VUYET#:>5'A2P%.A7)?DXF1#K,JA 1T1LD!BCQ9%7!IXQ@-SO=J>M#QB MBX:GVH!E_?^"QG 'M\/2:!<[RG/>A["CF)J'FXX3! M5P*].> Q?2?RS/<1GLT@ +:Y*)BMA\_N,3E_UCN681*'AU?!41&7_B6AY#Y) M^=)Y%.KA-0-%53T[-[ODTO.(,Y[QG.<-@B0PVGZ[4M1V+F4M14QG0;VVJ8ED MX?T87Y1DE3>,S*"@I5-3KS2K7 M.F^D?P9U0+"8I#S='A7PCMI'4=:K&S?D*5G]\I%L1F6BN8R[#196DGZS[WHE M HD!B]I"'I][KYK>M*%[-YMA:K7PV3P7#+DXS:=>K.#R0WOGX>%F,:GR)%A@ M(M363:U$YBF3&GA0"W=/V;GP69@I4[X/(5+EAP F:I&R\ZF.= E2=EIMW" G MD&BRVT$ 'VI8NBF0W:>*?1.PQ#MJ8U@!*_)+.)4H5B4=4,ZYB1V/D7*CZPBA MJ8WH^A4B'CSFG+1=3;INJL%%K,J)9>,Q[^T) M'8F-.BGK<4M@V3RVZ$&5:=^3AQ*\>K8K,?YH9U,8^)"\TV]^)GE<2"")LD0I M41Z28;Y/:=Z>&&S X*P''BO/1MFE8?BN4):QZ[A9[CRN>#BH):%^O_E%74+9 M-Q+791=J#:[-:=[T)SF=\=AEOWLT[1',KBCLT&]*V@$5):F-@O(!4,@FIJR2 MA'29)"D5KZ$O$<^,G[STE/)DU6-5C6,\Z:8LTAN7B;2/=/NK:R.@%,3 MIJ&4],HL9]B+LXCD2A:1:S!$VQ@:G&LN??A0#] :E_;(7@\-(&]+!$1%0&VZ MD3E)J;%]50,Q'[P ZJNFD2![Z)#',B@>/1O4A0304$)/JG.ZZC4,7&?HDUU% M.-%]*Q1-)FX2#XM6NMGC.;=VALZ-\)"[ FT2+IQ*VEF=.A9QZ2T(:R7#ZUA/ MM 8B@%EEV9!+@.Z[BJ&A@^!XZW$Q 6]#(U74&DM)^HX![&\7KYJ5VHB[0GBZ M6DY9F37USYYSXT5XB'ET_:@J87-TZRLV?Y0. !*L2\W/=R(+187>431L+)1R MP(E3,SI=@9ZV+;5F4A'@DC3,#T@5 :@!I-4]X[%S?1[^DYZC Q*E:L>HLPO5 M0XOGSIOMDP75HKV@M*S7=!QZ'(6QQ![.EE$@F,"JQAG .*$VCX9_8\.?'B=< MU^D13M!2U]6WZ9)M0_=19]73I^HH'B%R$H]'^3Q! ?2@;"&)R(2=\B2K%P$6 MF6 K@#.[=M'3%>RC6"UJ;3H*15ZA>->0CKA/$O1DC9O*84GSBBQWFP4*\EM1 M.UAQ2%6C6M3&#FR@DI< O2N_DF M.^44\VF>OI$>3F4%B1H:BC4'$9O;[M@[NTM=QWF4\QI6,"61T/3OM?+WB$[^ M9- 6)TO$V=B0IXY\8("31\H38MU;YO-[T4/;U84G3]D"/#(@0???%JSPW1PUSN9HU^7#V>\T4:1C=/(&\-%M?!F9:(<>ZT $8=.J8J7 U M90=5N>!*$R\=-0!W818IO9H_C:)";R"#6M2JSCS.5=A&19$)TG&);\I=J)K_ MD4H.7;7R!MKB8XNM)$OX^H"@P?1VWY\=>;IX;.Q=CO!+W?)6JL=Z_F.2GWX.)S.>1W[,$YO#)(IFJY'^09 M9V=EV+,6M@*4NEBFVH.#)<9R.:QU+TZ1 ?&HTQ[5US,;[;Z6A8F,]$4*(&5K MZYP $X0AZ@!=EZQ_"$,*Q%9K[>M1ZO'4C%F7;@F.C\.XRI/.XFQIE -/:+B* M;#ZE6T& ]Z8[GFK5W "QJGG"%Z6H1^#?Z39(>NMX10ZWGW+)26>K =N=J[IL M6I-3.V]ZT_R'?4.&>FR\7_8='R7BJQ:Y8UE*E[[KV"*3AG5DC-$D6P/SRO^\ M=7*UF7^!M@E;4DUB?_2+\3"9Y4]1_0 [!6C-F>PB3DLR):1'><#0"9CI7!M! M\I_)<-NSLQ5@[^@L@W'KLKS.#AI=A[J:DH( 1^.00M>I#DUQNZ.]U+!D_D'- M_*@\>VUC.;T2\]ET0]LPNSZJ#NI\ M@?;/>].2FACNF1-17D5>!0::@XK$=HW2HJZF+!UG3H#W+#TML VP%(XA+.?D M-9\\-[W&@S+3E]8^SH,*7*;#SP!_?4YO??T*C%EKI[:'\B9U=9?/>;C,JN4<,5V+ MG+!I\N:*Z]JJ@M$HYFW^L9V2QYJ/KD2Z4'(O-G^>,_!:K*)8I_V29..ZIJHA M0VPGN:OI:N/>I#"T#O+%3D!&]U'5F>VNMI'G4DC4XB]9A>LJQHJ5S M/I3Q #E9\%)4B60]^9\][85JAMOP;9'H]7 <_$G@4J20U8T'E*]A*D"F :! MCOQ&T 3.UA K45-C1V"+EFWQ4($ZE<<9&F"Q+GG*%_"&3F?K;ST:G,Y]QN(Y M N6;7"R*)8(P7X$I+ITX>:-J1VA/?>H5-H$8.W=(3KLT@*ZGV)V5NWKBW,E^ M;9I_7OJ&DX(5V_=,S9+NDHE?]$F^!^EZ>+"C->'.KF.U*F1[R P*3F'P?+07 MV#S@'PL@4'/,DPVUCK?O&P#JI%^V-TJJ L>2)5EE^MF?]L*61*Z#Q(WW84^B M;")T!Q6"$Y0%#%9)U#S>78D)W4 \_AQ:NBJ?[(1;5C;CUCN:7R5.7JO[J^_E MIJ4?NX"2- 6/@1Q^:%)STLH51/*Q++]YV7Q# W9;/YK4:B5;HUUS$M79CSK5 MI][-L%UN9/7P\N)=5LWBV"1#CWG]RQ[0FJZ%SZ7?"H%LEQQMN:WWLX*ZI=P; M\7@W?Z^6$,58=]PX Y4\[]^3+0DRPW592KF-GF67U-3]ID+>=0L_]*8:+>[; M,W9MO]@HJK^P'+-@Q5=%_0"^D68E3!=>N6T&6P* :WDNK6WF MADL'&@_U>1%RV1R2I,T*SKN\@%W-&ZH@YMD@FS'NV>;RF@+_,Z+9&>H 4)\8RTQZXE M-QGXK76#J[0='DWL5RC+IU=G.&48TM0SC^1&[4!83QZI@\*Z[8M+XS,+!EY MUC:(>U6*Q %73]*;#@N.U;750M+86=X/(:!]5NH.UAI'EH#L,-*V7FJV.-!- MK@\R'E'@UM5),N0M1?MR'O3QK&M7E$?'HSBX1?XF$7 F)WFFY-CUENT-J'C!7NNNFA#!2+/6NUL<6G5WTE-'\" MU62I\+-7R?=W=NB]GE==!D[%46;RN(3L"A2ZEEF$OIE#[Q&N;S.M>])W3;U0 MVFK[W@[Y7(>2_/T.4K,)P[;X/%K<)2K4*!7.DXA&4(RR3('/6]'A3P 6Y4UT MK7RH@1CSSJ0,D<%AM$O*1RB7K?#W>NO2?;H'@P#\9 M@]RH*@>?8QU59.(##KJ*\,3VLP99MX_]O;L-;^'2';X4 MEVU:FTR$+/X&^V M-J67ZBQL+N*\_N:6B%I)"O".R6L4Y%!A38?NJ@8O,R]'\:WK3A0<(9>FY]H M:0 %4Z.L+40Q!7=((*-&33S&+C3746"H< .P!/M2Y)*'/6#6D!$(I_.JYCOR M(K-V88$[VC.)C\?(*I$;\.AZP>/BG4E9MG_E8)#<87TK]HU$MSNW[=G._@2" M/*\K >VBG,NNL_3E(7IF@VH''/;%<_"(O-OC U@2@A1W"0"7J5U)BD#9^4S/ M;QP:]'V?LC9W)0<(YH0XQ5Q8;J=J4D_3Z/&A,HZ:+ '."(5Q*VG)93A\8N>\ MRQMFY14'-^SV.E7E@)@C[=HG@N&S[3#>IZI'%TA$$CO;G:K.1H=3TF1[6>!W M>W@\]H@5-++XN=JCI<#A"90*7(_>U(\!05PVV$>7HA=R_3Q%='P5J"N7>O!F M5#"[;NV>[<;N#@(N=S,"'W&V:5["]M>E]')3ID,B/9CWV3>]D^S>\OAO9Y5/ M*>^WC&5UN2+AG'6U.S%.7;4O.VQ7R5-T:%*U3%(;&$=QFRU6"IFAM:)T+0*\ M(*(HB:&\%1?J)$=2-Z2=,9(&I.G=8%M9-3PU9SKL/%-ABHEU SME(J0G$AL)VZ U&[(Z@$B^ M<=RP/HT8YOBU_LF:!Y&_@-S7 "+9Q4E.'4B:5=*+TBFJWP/NV(BS4WBC&!9Y M>(J:#KU2Q"3GD)(/UE<;3JT,<(GFAV!K74!T<@*<-X%INW?9-TL.Y)%3'_B@ MG$[*IB.(JZMR%=/Z1Z,QQ1QD%&JK[>D8[Y5E$H@L#9!-]5J !V!ZSU/BFC,R M)"1Q#T6 ?44V06>;JFIX3Z6 2E/7A6V3A6J29@#0=3;Q9)R"<9EC7H M/5I[-ZWMA^=LWK>'UA0*?/:]> ;9UFZR*^6932(J3<>AC^O1E\M.-"',DWO' M??CS3E4LCYC'YAFP&@@_2-1L3$4=P8'[\/]/IZYX,%R9@EIUG:S+VY/F&W=Z(QYK$0:%U!:!U'\E;VFNA%UE:V4J?'8 ]!H6:_# M =;=))\O)Q[6AV2U02N^1QDO 156SBQHE!!-:3![N# M!_F[H"NM:IQ042OR9,6GVV.$76-;LY?]YJ[ M24,*SP-H:ZECF M]=)AZJ7FA_Q-EIPS!KLMUL>,\;0X%+(CTARL:CE_G0JE''*M,EB!+1DT+3W$ M\_F\DM/V-@E(34GZ-_=-YMLG!7[IC MLH;!DV=;GDYV$:=AO?)$Y&V#R5E%CAAF0)31WMG4S/X?AP[69D M=P;W(0/#DKT3>86:COD3>(]#7UCB17DD@O;2G#K8])($W0#-Y6""Q;BJK.I8 MD9',(SFL?$!X^C&"WA7I(;P\CM>3^%<6BF*\7+@RI^*!J*P$788]NRZRDVZ; M$).=,)5'L'G)'W5.)"G<8^[:*;:+;H0R8]CP^=B<=.&&E=3,^BL[4/#H;.6) MMX19J<&WW5#[ZRJI%O!$=NY($GQAKX_Z *EP);A:=QEA(@ M"+L0/ ;O0\+\\OM26('*C0_SD.YYU&?J%"8^L^QLI54!94^XEB^9TZVIWGIM M%14]94(_\AED]O!MQ>X46",):Q)-L@-Z)ZVRR-IKQG:H6%4IR3T9((U[-#^7 MG-2]E&.E;P'5^$-3_KF\@YPT9&75/)Y;SRUZUG&R O,]-0@^00W:2$5Y!NQ\ M'1>KU!+>X#Z=D=8\CDH31*BB"&6*3G9K2G=CPTK\=JBAKYE."H-E>&EK'MBH M+.E1Q0V2KK0#!GQ)\+B6O+%B01>\@I:XXG6+I=6 T$T?L<@2 M#)*05.B=>[5=$W?J:SM<3W:G5+N&9D7@L9)BF7*& M#4K&+/JX>Q<\3(](W*=C36B22S>%%R@%*#2(5EQ!FHIS^-P."M8&G)&HZTFJ MIYUC^AX&J5,6++7)3>T>Y.-(1N%MJB_J>14?DR6Q>]C<)>:Q@W15=()A*<^T M0I50Q(3LG1O\/56W-O$V->[LN/!$;P]G-$(E0"E)7==686.QEY5T506[4X:9 MOR]*Z)E\;7S_U'^-/^V\7CX#4<,)&X_(U)T+2PG[%,4\,N95-GN"Y?C(RA=4 MP@9I3C6!BT\BUPW[]%>CK#J[1T4>U%V:I2DG=3ECRX_G>FE\2%5W\MN.PK(% MB)Z:'C]JFBEW==QJ<6L@N1_ JDUG:-P6>-@OJ MXVCQ_:@%$H+"3\"W78V*9*I,07F'D)>\G4+E"JQ15H+L>)]75JR[*N%&0ARL M9MFBR;YD.+65)<2>KM;I[$:(F1K=P1.=XLG]SBOE8I^ W=>L "K;4M*&ZMS% MJ6J) ]1V 'L':,2 M3M$I GGI5?MZ:@+"X#U\>:F"=+=B<.YRHB4TJK=-O\ M&LV6=]LF>3B2ZXE8]VQ?%;]P\,R41E!UFRO-CAM3>%09*CQH4=#M@%APPH_: M%G3Z4,6K6$2.NPVEGDXJM\U_;;U95:;NPB;HL9B&!!D[%%D^AL@Q:![;%2YT M$9Y*T:3F(-1J#^0H;!E4&)[^$)N6=WI(O'TII[5XAJ\Z22+R M@'I9T$2=8Q5O776 PY872,5=6AR_;T2N4V?'PTD@0GDY\_(VOQ0L>A[ -GGD MB9% [BSNY1P> 9B(H4EZWQY]1M4+EW@#J N\;>V*[9MJH7WI5*D3ZK)./G>@ M4U/6 -0-+):LGNT9*V%M:S4>36=DE:2!]%XOZ5SM8:7:+&O9'DZ'38GUSAX2 M1;E\X[BNDXHHAGU_"+$;V(K'X'E^[6OVA#4>= B/!VLAM+3K\AAXC532,P/[GLD-, @8I0\1M M-H%E%IG 64#;C.R<3 [30<*LE),*(Z'=V4ABMJC;&=S<;8'P3O9G\^G/N8I'K.K\EE]\@D. ML#(O=GDUH=[;QF9;^LHD2FK5115),XVH5J;:J$KK5/(&JUD6Q-W[N!QIY8.O MK'S9&A?,RG'T[?9D[!PFMJ:N/:#EVH%K)\]?=GI0&=A,)$,S 5]<&H'Z1.JI MW,Q+EL3U2$7>6-&5]$;)0B5QL>C8L"JK1,?UBPN=H+I8H/DL/#H'?(M.J8!N M]@7([C H4?YWE7.!0PHEN*SE'NHCGYU@K LC="DNY\Y?(*$ <.75J\1$K2 , M=]&P.UMB"Q[;[-0,57?GVM8!M2DES2KUKWDZ8'YPK)6@3VEP>,X:Y^+I41E= MI,Y6?.)%D:M;(65%C>/2:RN2CBL+@&2W PZ5\ZYEC?)H?LXS +S[E!W@(4,$ M5KCCOQ1=(VU*YA'AC0T4MBQ5UF!3)N(\V0Q$-,*N?K[MLQNL7%H7-*^Y*#7& M_] _>I=.]&S:19LTP=DU=2]:*_H1=IX:KZP+]-*N2;T*@$NSS+E=JEW^HOK' M0_T54KO#[005+HX'%:8T![7E@@J&K2YWXM-^%%'5<]?N;+-F!Q9857IS.9:] M,G'FX^)BDA9!@/Z%,KGX6;9^-5S3D6Q%/OB+Y8HK4.\ MISSJC8!Z!:+_T9 ME?<_-KGD]G,>SU*KLO6V;1[V-T^!I\KM21\(@R4U1 E+%_$0NSF&[*R@:E(> M=1Z;+NNL$W8!5ZU .JB7=0R0\0R\AL5)E9=K%:8T@*F,*H28-9T.NA6@%TP3 M#%EGE.)D4<51ACU6Z]S@?3NMKVJSVXQ='LD30?$ZPANHF235U.]26#E**E#7 MG1@NZ_X&)5 ->'S+U7%G\SJ6XE%3E^)6Q)LTP:N:)T%ZT>X]'Y:9JLA(4;$L M;"$Z%^"LB/ $0%,>$>;.$D]1;848CR4GX@ 0#[-6QV0BH.M9#B- KIT:ZB94 M4J,#(P;!RE&X3.PYY/9(2"5R$!:*S>*HB*QGCC)\NS.O_-^D^/82>Y:Y:@_C MWMA#K'OVVQ&5.B3AE>H@WEG6?]_1"0MMCMO-4^DA.Q%V 0&B1C/B06+?TL D MHU/MDM-;/27$IB2=P4H>+* V7]XI<\I2B&)+L5N)YYX4*U1Q6/9=JO7SJE6N M/3?[ZKO,)"UW"&4\'MFNC^5;H42L)#;>Z/[Y#)0LHE0 F:JK4.OY$(_A44Y' MD?BF5C.83.7K-= CE>!2_%N(1@8( $TE'2][[G:@#CL9A AI$E%+'8\;^=_$*C4,]0%X M3MN$*>M:[:'RH_M%,?7KYJ%\4^>SSVBWVMFX9SG*>S 95)(\EO":XA.R.Z>: MOI>Z3Z"Q5!:35@(BT$;'ANBD7581Y#Y5X6&P,6@HRUZEQMV'.'>S M*E:2XSZIX<&/Q6$IUAX[5=K9_1SVS*ZT1I^G0V! <'))4$M!"O39%S-+XZZ- M7*JV0'(Y/%TNE)+%41^':]XD<>6#^8RL> NOE;0H$Y)K41=Y>83EV\8$>%V' M,XJ3?)D[]#,KZ X,C'90>N$!"&"E [CXK" M>),3?Y_,^@%.+&,40&/O4RLT7"K[$NY."H$4P#KRWE^-R/? 2R1 M-V)5/?BW+=QZ$:R*D!VC4=78?';);!2,5 HDY%X.2I\4EP1;NS' MJ0'+RDW%[F!^4C_PH*8]J"ID;DD:LU NP:FUQ!*_U[G,)859SRBB MX#;59J*>K/(=K,^BPG#R(&S54YJPO"@JGW,'R*C,0- F-1H?'CZ=EQY. AX) M0>%6Q[4)?EKE$+LSY3D%@(/^"J@7QT'EF))4&]7'.)0#8>.I":0FO_H#5!O: MQ*6AXKQLK]NYB4B8"&15?B=*K:)P]?Q>HOQ0ON+S-]>!C=V6>S36C!I$=:HA MR6URBSY2\3CA^W"(R$I .NZY#W9!&"I5>'2EPHJLYEL%7K#P&F.B^B8RY!J< M]H@42F!LTHWTZ4XT1U40*[=1A<)XF2G$XQ%.VF3 M=^',A,EVY2XMJ_6VWE)6R8!R?EV".VP*E%#(B9E^O=;)C+%:[[L M>H!G[!HJO: :EXF?.B>HW#[WTVPBI'(R^O/AP5A-&V?!!+ MTCIB&@].+1*)Z=P/)2U !G0(_LLN?&4D-..0?N[(D4*&22EY E.PY96=S?9< MS;<&?@+Q[M4^F>JSN]KX?3E1D$ 3L2LJ6VW]9:-N+MJZI=.42-LWL_CHU2BB7#\V@9+^J!RL4T=GCOTY0(/63C'GW3K .PT:/"E_TZ>C(37KA?T[[8A>K M3PGG.J6YG(ZFW?,"N;-_-(,$DH0]R&IVL.H$[H.3^UQ>-:-NC26\)HF)TO;E M.C^0/ RUZ@2GKGM_1 &9P\&]U'K5-V>4&BT?043Y\G]0$ M6/'(PI+>G7IT).CVC>R5>W000P7$HI_@H5(U%TH=I*CTV)J'4\^N:9YP3VNS MDJG4RSJ/.L:2*! 6J2K#5@N^T*&X+B&@>N8/&% Z^FJ-$+2O6466TZ/R_5BJ MFI*U$R5;.]GUE&4@,Y(2:/^*TN)4.9I*;Y_L<$]J1,\S;\85HAP;^2&F/ZH" M.+E_R,V559K,[7J]*=P12"\@@TM;*=,"*/DM6.+0Y]7I*'I3+]J&-= M1%6Q^Z@;Q,W2%5$XWR<5E;^R4X591R5IU5-YN&N-5 '=3_!DHT+R0)/%[)@: MK](F[S)L^U.?MV6GL3D#>BF">NH6Z'%J MN-3]5#16_7L A3Q$+L')2HKBK/$F3TGO&$GORA:O,X%Q;K:+DR<@C1@D:BO+ MEL##? J/2SE*C0**0Y@U9]4S#X)%4U+JI";8?3!.@LL-57NZ\X?EFB=%N(T@ MRZ8EK!%1E9RYE;/(XE'>GG\MSM55N S?7[-D!$K"Q34+:RE,[J&3@E M6?)L65>R:%I7)4:C&UZQGI9$UCBG= 6"H5I>)/'-DDH/C6>LN:ONQ&XI>W:/ M@3+VUD!^+&6*-DLI10)2I'RR Y6:ZM#6XL;]4C9BYAG2U705UO^$70^J.EAE M6@M*WP!QY4#LWI;$IE"]EDSR*L5^W_'6X M$=5G2+;.67A 3S3S@#XMCC+8C_=T*,^OK#G%5^J;$1*L-3,W7]5++,2:1Z Q M](;(XM17%LH!XE5V:V4<^'A$N' M-2^I1RU;3/.JRC(WF$Y27;.#I'E'DR"B&O*51MZH7:<3E)J,E6!K7AU@[ML6 MGIKPP&-J@*(SI\JIFAI4J2?NV)FN1; #.\N4V*H>)3Q6E3G5_J^:<*EJ)W%6 M5E$'M/1J?US'T.&CYV?!H??QN5G8M:QE$=T.G%UD:G^!)79+OJ5@!T2"SYLV MKT!0$(BUP+D],O8/:"440_<)<8V MT>OI-* F@#I6!.E2Z2;T*=G'RZ/D8&-K*R)OF_PY=;UF/[*V6?N[$ADQZ&Y' M_K<_YWANU.SVSJ+(Y[.E%L!0]("@=IUUDY\G3+H(&NKT\]J4<.R>;.VJ M/SX>_X-N)O]/?0B6HKPRO4S)EEH$.+M&8+_&QAY4&Q#8&XP[ZF4VE7T?YW%8 MIY>DJV#\=V9'?QO*"L!N?:)=E$?=3^J]Z+'!9R\878C7^[L !2O9E^@P4F<=^[BX"G;/HN)RMNN M7U1<3/6GU6%0!U?VKDTS[8@DP!U6:+R26Q,?7JIZ8 HXUG5;)0&O+1XPBY5*46[\H'GT%^Y+UZN*L:H0M M5%073J+U/O*JN4]K9(>=3ET='H(7")JE 03VR4C^%;P1@%BCX'N^PQ;7[BQW2T%I=;5_" 1W$5O*%/$42%=Z5WDPI2C MJ]@DWO+XLZFN:G368BFR^4A]-:SS384C>4)G\-=U!9962SUI37=2HR]S>:Z< M;7FTKM\3T$9!K"8_[+%,4)T2[-"H4!Q-NN(ZQW&1&TD%AM)A4G8H'[[&L=9.3>9EO M?E.3NN3 .=O*<5Y'3HZXA*#VDTHXV#6N!A0; NK!K4>_( 7Y.Y#K ORTU.HL>D ME.HJ13@=1#&:[Z>H=K$\J,(=-HH2H$V:'F6!@%BNT@";]E&\\%-\[=]AL^KQ M3BJ5^V73(ZN7(UDK*]SB+/_8J@.4V9HU\[B;.J" O"7&M]_7<'Y1;C0)(*M# M5\!>+,2G@HSOVD?;>6EIZ=OV8RN.J5% *@IQE;8,)F5&!8F %#I]!O;,116= MU1C/7ENP77X'IVHOP42LP>D0+8!#ZCQ?LKUKF0!HN9^S@D<.19G.R+_@GKTJ M^24U!3QV3HJ_6IQ98 &K[4A H7BU89-8,#4E#0[Y:=ZYI;EZ:8YY5!LE>F<1 M#,^EV:*G>+OGL+:A]M_:Z-8 F$^.;9LPJ$:KL0P#3F QVS M?*)D&\GZEBXC[MJ 7PK%'2SB33\+"Q;0?'76F,=FV$AJ>$;9-6KA4==)\637 MWVQ,_:CF&AM(.H*YW8A',[4M6G7U5>9J3PD$)W\J53N7"_V]G"R[I8U2?>K8 M*V$MV[OT)7A9;P4+X^AU;)0&RJ,OS41IX_QYRDOK!C*]Y"=+40?"SY,2J"AS MI&PF1;KJ6H?U43GG4AP;E-64&M1 -#/CGR7DU% 0D(K6X,]K@3&[>EZ#$KD M7%<2MCWZ*>J#E!3QV!V(4U(6;-ET7R5Z5ZU5U7SB88#5IEO?!:&9V*&.O(W" MZ!R1M#C=0&7T"W-4WQ@@ R&IF*T';3P7( C-9;D5PR=7NUF"HNBQ]&\ M?:I/RM6N7Y@,%RZEZO7MZ)I5PN'HB"-Q#3T# &-BOE8V I&F#7H1%">2X* NV)[L*Q[X%_?M8^@#;P_)+>70; MHE)DE+6I]0-?>FJ746R,5!8]'G(%-Z7 M6@5A727+Y":.I)<-O*N3I,9WQS*:)J$D%JS4:GNH:MP#+ .HSK2C8Z.ZO$5\ MJ?!((G%M4YZSI)J0_KJXFMR[R!/]IOYDPDYP*F8DUJ),7,#DIH>,0 M3%;$:/= E83(#MS(%\6'-J->Y!Z$2=-=W9+5^EY6PUBW#OOM M2^@=S))5&QW;,)D,,L1C$:*;Z:6IG^9!%$F@PTHH:,J">Q1".9,4A:O[XNH% M<@L;4\*4>WAKU/W:*Q%TYFV_$=C (CZ=OF2[VRH8Q+Q=42= N&RX-97,TM%6 MI6C%T$ 0O*Z\>>YP'$L\0P5@00?%O1]9IJ*5% _- 5:%AEFJSDY3%)G^#-H* M.$E9<58P4PD3#8GPXRH>;(=>0 >&:$6U#A7LBJ;F!&\%U))DB>%FKQXQ/$K@ ML T/D$(D;V^V,R8A>^RW-E5R9FL@YI@[J+!9DO(>^I* =NS;OCUQD]^W8V+? MBRHOIL6%T?X1+%YT4VE9*$=\G9KD[>6B$@58L]A[JUHR[?&4JC=$H,W ^>@/ MIH=8<,XM;"4N8;[03]3HU9JF(.5Q,7PE%2W5E-CJC8YU"Q,3P3; MUGAYVA5B;)MVY$2*:_F^\O]7$TT].NH'M3IF6D:Q_(;J@R3L]NA&R2)EE]_: M)^C'N$1E*,1N17O(9@<)"T!7##A)Q@F7O*I9#P]&>C2L.JMR'/+HLJQLJI&23:>GW!?,>)JH1N7#R]9E-[X]@\3,EKRCKE-$Z,NA6KTXUU%9F%)' M]<:)1.$-#%Q4"]$BA45EX]G: >QN:SID\O@D#%29)H2)H3L2<:PX5#V4>2,A M>,[#=??M4=\+Q*I7%37J-6QM*8.9W=G#6^#T9-+DY\-\KH]D>@I+TF/T M5$U-%0L*."7BLDQ2SR&RD],1C%VJ$X!'!NI8M5%S6@CS6HM".;OV;23#9RD M4;%I0@L*JKP>5K"G:(T[IY.F1RWBV M/DPR_*8NS@,H -\"_1_Q/.!^GY:%68[KK>B#RZ@2=NU;\Q!D,3S4I!I,\G0H M5U2TZELL6AZH):AV@[.@S1D^L$_VF$T')MF?>E=H_%=EF1Q=!:\&K'L\61T" MI)-ML1'-;P<6"1QLY#TJJW0X/:',HZ+JZ@@[6OD,"N\JYE/=*+&T''U4Q8:E MJ4?6/C<6MU(@TP]URN>!%D 7*O0E/S3<#M$TS)]--IZ6 MM$KM1RC67/*WQ405]=TX''62[V]6S<,A7P MG.#'#5C.15%: &=LC]I >.SK:T/(\KAU7^-J"DE0DPZBA(HSR@JN"7 "R;!/ MRI6DC=U].[+?F\/FIP4-"8;U7'D RN_+,FQTO65;6B6]= G;0>F1&[=L/.^GF&Z) O^:4/'SOX M,4ID(&:I&W\KK 5*FBK5/Y^EQZO'4Y:@1#ER>"$*L;?M&5TJ-7E6V&VT._W) M>Y6%G[06LEG'G[HG]<3EP':QZB+%.<8(3'S4<>8/'U/W*%DZ6G(NZCQ_ M>*,RN<(2M@""/+HR-.Z1E<9B/=68D>9)<5:*9UJJQX'QV2A\)$""*I/_OLV3PD&K&+$Q[^WTL+@M*Q2%!ZDFY_*29A57*4BL&N7P'/T?2LH;-9.\ M1[+V%FZJ]-N3#4![(GQ0#VO&Y3@%P;P3ZHBVUWD/S8KE^?->P'IKRL_#8)[< MZJ/$63:%H#V5U HC2#[36\5G7Z7E@I/57C)#48=0J"A\_'0[;BVU(@N7/6V# M_]P=4^7+J&"R9Y%EVMP'3#RR?.VBY(=?VZ\N]>P H*@?4?364<8HR"#IUZX M"Z6G6 /$187DJ=]NJ?80?U'>@I2EL$TSZRI)Q(MFIPDIP@BKIV291U8:ER7@N7!(?E* MRG[BMAC:IY(D0 L>':_=#N$Q;W56LW8V&(9_UL1]S3>%5!99T?"$[9,^H M)<"#MA/[#8BO@K-IU_E!1RJTAK7ZUDKS[!)YB-C@8@TF'&)XJE91R>1A#.W$ MXLT1/)5XP$T@.IFSY +)HT (9VE)]Y[ #,4PG9_V 'Q0]T1EYY+2O"?O/7L< M4*C118&&^EUEQMLI= KI4W.,4T]!%FOSH#>OM*EC@:(-_.QCTUBA8P*TPHKI MVK@@IV[9 W4Q^RQD610R?-IEY<-#97OE3)RTZ1P\/8-;-TN M3S2J[8>I=<#4)$I4QB8B&-\"$W;0KD'*.NA0R)K,]:CUN%/K5SO.O(;N&8HB M:P3*FC7@42+J-#G;U(CJ%9'PUV3+?M[YDF8K!5$&N+/BRVCPE$)WR;<[*PC^S IB"/9XOF.B(1-&F-SB;G.?A69LP]G;8]_$P)EEGM[ZI]GRK M"@?*H9H'5*M0*S#EV?EN#QE/CB[FH0KU14VF[@[@%MAU.3HF#+)1P7;B+0\9 M*@2F0=FFP#;(T!,<4NHRW)2?JX.)11%!S7-ZW04N57F?94NA1 PO='LD,3D> MX8A^C-HU)\<'(^^M:\3)*]8#E6(Q@C[YTYZ3Z?$ HE;,BI"@A(#(GAPPE[#- MHQ59J,@P MEZ;1G.!LRKY\[BD=5K].[II>J,@K^%D]$4(DK[0L)Y^@$!H;Z/!':QAN7 H4[NS6,% M89"JY=5K< $0FQ(BDM-L\A_Z>(!>K/!++>3AD9V3D\[E@#+:=LH'ZIJAUU.! M12*AXB&[GCN.>MSG52GISN&,*K?CZ+CZ9K8#E,.\-'FX'>._TL;&OG5A3@"C M:LBQL\&2HJ(A$JH$"P*6Y)\O\IHQI'2/$BD@=3T,MC;)W0=+;FZGM"K[/:<]*M,:P M;Q_)02QPRK6B*'.6)WWH0L_MA(4@I3M+6FHZV5/VS@LT0YES;T$O6E[U4).3 M&G&7^4FE0N"3\;3SHD/AG5&[J9ZO^0+13[%A(NS3?1AVBS*1;6Q::]X>EVBZ MR1N_%J5"AE?IC:RG. "I=RHZ\_#=:S6$B=T$366RHQW]MKC'YZ:W#U6N[W%I M%W2/7$E8^51PQ8GQI/"YM0DOE/TE!J9DM$FG=U;D_3NZ0,@!. M:V?E1CMKTYDE'K 53G&^2=5B"4V@:RU;B\Z%8P0;T7(18ZR/6E_]/ M"Q;V.YC(YH;"G:<2CF09Y_.(CK:MG=8_TJ6XX+4FEN.C"SDU\7F8RI:5=^3B M;"@\)$0VF1W>)GE*T6*+2+)>4!6!6)KTH:)<8A$%#1CV30F( GPCGW$3?*48 MF).51;VDX<$G=P#Z43;+Z?^+[ NN.HM>UVKS2_R2F7PX6VU.4@/N!I%4QR4F M05+!(5#H7*X625(_&(LV=;'%UF7F[(V@X?MT7!TJSN(-3#J M*&*IB;&G3LV3-YX\-?0M>'Y.AX]7>F=Y2SW1BV)S9#+?7.E4AV8H4LK*)AY:3@.9%J-!7B=?D,D8HC28FQ.Z5U M>AI:F@/5RC*N>JQC64'3[7![DJ//7%#Z?UOT$H?\J'[&\]D8]5RJ*@#DH^F% MX?$*N%KK>2U^>:7%P973T0+M(&I0%#*"TN#0'EY@E5ZEY]G$;40G72B&&94R0+Y52 M4PMS)@"['E,E.+]Z/UR]I'Q]1FI5.X5O;Q*Y=2G/%B^$FY \$/240%4!?N>I MZA8'-5@U_M73\G+@4?EESPE95;;_-9[;6$_6'TU#\-V]*)\[K8G2I)&J4VLV M=MP"G?BIBM6N[\'2!98NU)<%J'3)S7M,\A:+0A.7#K2J#2=*Q=T6@G,].Y%S M:>\5!PMV%YXB0EP.=6SVH,9SLG%LA\HOJZI[%(MY'+DLGGBQ04A-MNYX0;+G M;0;%DV@95!XAL%^+]6C=T-><$77 216_+X=S-I$T2Z,]]^G)<9 _?JAEM7OV MK,^)9Q_.3-Z3-WQ88/+GJ*"JVC0KK.%H#V:TF(MR[X ZCA6P M4X&[7)1ZD+MF).F,FK&5"=BV[4D _5ZRLGS](.:7.T=Q=OUGZ+>HC:) M33;4+"9Y!7^>>TA35R:Z$8E]DD19GMF^ZZN@.JFSF]+.59I>,K2L7MWO^$O# M,_!Q6Q8#J37F(/U1JQ9JOT?C7*Z,@I]]94I2]+&#J$D'7#K0E[6G7^@$$ZPQ MEO3<2TTL1"FFUJ+*$5IV49P-YV^>3:W3H8>S0P$\DM3A6 M*760WV\/C&]U>W\C2@EM?8:3DEV0-?G0'M?AY;H326;0-VP*#:7D.NGX*9N/J7H@.AYECDA(4RV(Z+ 3B^8!"Q/1 MSJ!-$6B<,I1%"P#3>9G]GHNG>\>1-&K>6$\J *GI$VX/O\ 2^L><4CZU*?1X MH5:G=Z<:"+*K9?)K:J8RA,ZO#N:7JG\ 8<%'3>&E;8>L,5U*ATT.87E4/W'O MUIS%0V0BCD\5-!_/JI0AZ$(F\;[@#(EC]-=)P-^U MN-7IZ;KD09!7P>UJTX-:W$B.7N6=@I\@?EJ#:[OIC5-[6ANFL#]OCG'W59FQ: M4JLI04][!/8"@X:]8F3YXU2)"NEDT6:0Q*&EB,V=0XVH:-7L0 ]WP[)R/C-J M;WAK3,(SZ:O<[/SJQ3BJ7_VY*F1O9)\]DNW9M$@=>/C8:3' M:N)312Q)FOIKR?I51CT!#X@U)MV2B(7320/*-5!L=C#;;H8\X271<^O_% 4] M3WMXZDU;W'GIJZC*2;K&YL0O<>^QVC5"B+O8Q9?J94?6J%W5>R6>[.Y?ZM>J MH^K@&H&.!$!PD&G)1G@V);AYQJ3QJ48$U:SI0OA4I++!1C?M^E=L6,IOCLAF5( M$6@H)X%^TN#/1TW.7=*K:DG M#[M5]?.B#88^W/.QD/(';MU4[1PY5SO7KK3,RNCZEG]P:C%3PGC/\)'!_0*M$HG@W(>;>@XKL-G,5X=5&^;2;EMBE?85. M^YHS^<;M -J>H "*FW9/CWZ!^U(WM+@!,JN]>JCC/TBG%C=):-U#M5"C\+RFLSR0]%H?9A$A[B%J&L]JBUZP0'K?O::SGRK-GH 9_ M#IRXFZ'WJ5P!.\#U#$SMGP'TX7!!V <%N8;9A\LK$]"!W(WUP^-2F#RHG6HY M)FOO?#;>!XA$%P3>*>7H M[MYDNVY DT I1[1G&4X'3M2M"\)61W!TI5F2WCOO6/MH_O=,#GMER*(9+*%)'>LBS-<_P=5N5=3.483VH\&J36I66L_":.%'I3ND@@04US6G_3>^>9P\>25Z2 M'<=F?XOT!/1QLDQ2%%F2Y_F00966>I)J!6;11GK2#7N7CB1?4[R_:!MJXLC/ MW\A)"@,F%3>MK"IO:#W="JRT37H%=T4?9Z[#1U-]F),5F> C^@M01I>&A;0KS; MEDI)I!*Y]%$$4 $"I+XOUV4@RZ$HG09Y:@1K%,D/6 =4NO&DO6U&H^1BFPS MQTJSMW4T52?B-M,2IU4*TE/4JOFA?-O+5UB4Q Q*YPZ]Y.;9V2U*O==V<&5L M)*7OJ'?/W<%/ E[/&="S.]5[D"R#+HC]ENDK/68'>4GR+36QU__KODVJ04CL->_Z8; M,-'( 0++#X4*IUQ-HBQ/ 8"I@6:8,3P2[65B6XHZ^5>$*('/OFU,VD#;)%HL M>V!+EW%*:B=E-!)N&*<6E(_F9A+.=%#+6L-KEEJU@36V'(JG\P+8K]4:_;HT ML@6'\EZ.N;R'G$VZ9)%0^'FTJ=@:CQS@2![>964'5EV2O#R5_[]LHI#J@$K2 M8'BWGEQR?Y/-8=MDZN@6&D_%846P>W5(@USFC-KN]'0G6_-Z6-+/21&:-KXG M)=PB3RTE(A7%PT-IN-87:X#=EA2-7=)VCK(Y?+:D/Z=32+531:J$SK+<6/)= MZILJ [*N K%-@HWV=O(=AG3D(1M-)W4O3+=R([ M"KZ72!T?#J![I#/SD(^X=]L(UOHCZS4U5$;P")VXRU^/YZ-@S^O6T#?/G[W_M,_;MOV9W\VOO]F?OS^)_[K?OG=A^_][[]\U__Z;_>P_=G_[V_^ M[L_;-Q]_\^)W_WS_B_U/__)N_PMV'[_2/[V\_^G#Q^^?]S^]_.4[BL_X;K[\ MAO_@__UE3G_)XM_^[%W_^,,?/WWXW>]_>O=O^K_UI\J[]MW+IP]?O__^W5^_ M_^GW+]_Q(5^___;=WWW\^L/+3W_\BW?OVK??OOM;?^7'=W_[\N/+IW]Z^>8O MMFW?WWWSX>N?WOW&*]V^\JK^ZOO??GQ7/G_[FY]_^.=_^J>73S]R7>_^S;K2 M?_N.Z_SFX_??_O'=-R^_W;[Z]Q_Y>R] M9_6K?W[_W8=O__BG'_CXW0\___3RZ=U??_SFY=/WO_S1__CR^=K^^N6;#S]_ M]\M__:N?WG_[X>OV_>^^?7D7/G_KPX_SPQ]>OOF;#S]]_?MWOWW_[8\OZ_LO MWW_SRXO@R:U+^.KS^US?_)OW'[[_Z>__^,._?)P_M;[>7[_FL7SZ\(=W_T?@ MN>[\(/_WG__K__S%'QG??_WQFP_?_^X=1>2[]Y\^O?_CQLKAJ_SNO^WO/GS_ MSZKO__]RQ??2N^^^G?OO_O--V^_E]]]]9\^O/GZ?/?5W[S] MNKS[ZN\^_.Z+/U;???4//_SXX5O6T>LW+W[O]V]^L02^\>/;;W!!_^&[E]^] M^:3"!?WVMV^^YF)^^_97N)C??OOFZ^+/O_V!ZC?>_@27\_]/+FV_Q'-]_S=)[\RTN^^OWG][>:^6R?_/IY8M?Y,J_ M>__UES_&U7_R/;]^A^O_FD7[[;=O'D+E'G[W\NF[]]]_\YMO?WSS?6[E_9L_ M<7$3']]^S>5__/';]S_^_LWWN/XVWGSM,W_[-5?^'W[Y.USZCS__\,,GGLZ; M[W+QWWQXX9L?7K\;?K7P?KGLXB\7W?&K)9>^6'#YB^5V_G*QE5\OM?KE0KM^ ML/+)99^L<+R+Q;8^:^MK_*O+J]?K:[KEXLKAE^NK;C_ M]>;_M8 MSYY[_/3Z+2[_AY=/7[]\_^:WN8?WW_'='[GUU^]>?_IK7_ZIQ.W\\/[3R_?? MOOSVS7?W/WWW%S]L=/C1C_CQ'U^_R9W]\.W/K[>:?!D?W^Z2Q/W\_H\__/[E M]5[2N2[\P\?7*TS^:Z?_K] MIY& Q;@Z[62I;YZ^>)!9"[U^P]O M+Z1ZSV]W:;[\F.\^?/G=,_SS,OCFXW]Y\VVN^^4___S^=9^9T/[SSR\_"J*^ M_-'C]1]>O\D]O'^]/'-:>_V*R[]?O^+2^^M77/?S^A77_+JT36#S]2N3[NM7 M7-[_^/H5U_17KU]Q,?_3ZU=O^):_OKU*Z[EW[]^Q;7\A]>8 M9S)]_8IK^5]>O^):_O;U*Z[E[UZ_XEK^_O4KKN4?7K_B6O[7UZ^XEO_X^A77 M\I]>O^):_K?7@,NU_.^O7ZV ]?[K?WSYZ8LM=,77W?WE/QS_\@M?[BYST]__?;E=3V:G@BN[[_^8I.;GM;'?_G9W,3KMKNXB=^\?L5-?/TF30@) MWGSI"GSSI=OFS9=<\YLT'KC2-PDT<(5O$Q"7]B8-!*[I']]\R46]22>!JWH- MB;O9ZPV",'5]?/,E5_7#FR_="F^^Y*H^O?G2??SF2Z[JIS=?B97\C^!*N%A.UW__\B?_X?L/A)F_>M[9("@L6K_[]<^?2 H_K:** M>_SGKW_[@5+CY>4/+U]O*G/JCF&+M<>ZV$5A24?8$JH*,VI;7NLB,.L&7N8X MNX:9=8Q\UZN,O?0[Q#+SULNAB5L^[[ X?TMS+]Y9420E$^8]9^]E)ITJ]*]< MML;/49ZCC\5*O76^B76=4@29-_8L9V'MI#O,XUFZHM/^^CJ,CV'?E^-*5^S.WUCL\X.J-;M3TFZ3U]7>!+7:6.- M"[\4E8Q.32P'J2>E\WGN?F^/I(;[XF;X%'6GJ_VGN>0AG$N0BA9D7V0EZJ9UA MKX^>T(K(SO.*:WXBZ/7>PSC/[7&>H.:^I[G/FM2W*$(8DXL]J3X\3/+L,ERQ'WW7*6^< M6GJI_C5;C+F[5)U83S9DYE#\Y/=25-' M3VQ*ZWM^GPK0.('AM/Y5\[.T)(>N[=( E35H\M$R=U;CZ+SYH4O4(-AJ '$D MOBV19CI8)A6O:E>9Y9[466]E_+C-W4._H J!'5&E_!QH.!V,"D>/+=5EMG$] M9XQ^C,-_YW*AUC#^NILC[;D/S?"V^"PE)X]B]BY[NYSW'>>A$N]QGLX+CZ3W MGH2PLPR%C#T7.;1\5?3ET2%TM(/]M25=\$*WP3]4YVWWV1++5>^E>FCN-SUR4?NZ:)SGEY/JOB;4GP'G_4H#SLT M$CSFSFMZ_*8GJ XRQ=1RCH?Q("OR7O/V2 MI:M.&2T?@DVA60]33*2H=-%18 M"BGU@Q=,!. ]+5N?G,9P!D0WG)S2KJ[8UN.ER&KN2\3Q;-4&O\H.P\,2)5K8 MKMQ=+9-=HP,D*X5KT0H]^"6TGD,]]QF>PZ)JV_\Z;Q=99@V_H5IL/NRH>.7>L95JBZ ME\X9N?27A_7>JY9/@?>IY\#CZ;VFDK/TMK%I]C40UQO+PT.4O>LEKQ&]ZL%$ MJM/-HVS6N.[H(+?/(WIBI^[6K4JX GKQWHB*O2X7I^[1CP..S[F7V^%3O>"K M<\':^!!9YI"QP,,^?0W\Y^5HK].[#E;5(%=CF=1R M284'7T]9CT52@M:WE<#MN2J9\"*.9"V9QG8F PI[7Q,0F_8\.CT]S\=1I6W>J8E+Q+2%2X]+Z0!J6EX=(]L M>+=:$5[S40U]E4:8"\R:(YE!16>/'*77J=/"D- MIQX',4DHCI!KF94DIBC--&;LH[ YP6S;O6K1\U#+TX&TJU.Z<@]SN%G6/ M.Y[J:-IZX#QZ D=CCSN;3\BLXVS$NU8O$^.8QS;;<-"+_'(/N;N[1,N@Z\WE M.&K,*UXJZ:4LG"I+X"*PC9Z4_=1D/.E/K(+DN3DHR7=DV#M31Q!0]]5YDY[B MU!*ZEB8SWKF+^]0TJ"0I?H\V0\7=6T]6R:7O6KN6G&941/Q0YM=)('GHC]'D M=!Y;XZGN:!=+6%S3#83@FM"S+IE3355US2ZM;*N^+C%5IX=ZD<7)OT/S.T]B;"NE=>P5I'F/346XLB]+0]=92#.Q076-7MX5;VTFY MB\B1"$BC*W0@[4^&KFHDZN#E>=[7\]1-1X1].O\(V#PD2(W=L]NF\GIU@%PW M[=T!M?,$V.YDJRC MQ.%8TZF'RU"^7%>T$LR:015)>31NMX59-_TS2;!*I U0E<-^4VW_2E I$WCZ M]$L]DZ%I0GZ:F/-WM!GIP7'H0S)* MKB1 G0-W]?,/K:?E9AY31]"3/PEPD '5SXUU*NE+[>DU.). X(YQ.&](XE-;$%V+YKR MM>ELTN<)5^&1H\%\T .B3!0JE"%=TT/9:'-CJY&?^),ZM:8);I":I3(A\-"! MJT,/6>4S#FU3XI3]Q.>&1]9@YY8TX0'87(>*/ [M#:=:2.E >Z".#\2)Z+A& M@!,QXF*C7]*B^+L.KYZ18$<0N=P%K(7C<$QSTW"&YUY+UX&+:XN:JE?Y.8KK MS*202V$SY"Q)&D2N!.DYAJX1W;EE/7%B)-,H7:^#RK'F2(B$IP/DV=41>/OC M.2AR^+#,9UFZ!2+\FK_R'%]L#'+I_#0?6T/;=!"023&D/TMR28=&:D[[':!Z MMGW01?TAJ(.BM&A:HR >X/>E^:(6..@J@FXVEEM8USETX3@H$\ZN:E8#;SU* M9R7UEG)_QJV]V2YT #9RQS.?<2F1L$>53KKR1MTEI9>?O;5"R0]92;/H\SP! M;)-F.42>2/?5UE#!EW48\ M(-,__.W=:1[EX"B3EY,JVT-)ZU.#P5T'=6K/+,EN4XN/>YP24YP1YKZDSW:% M2XOFOWM5)YB5?DJ(./-</X)\V$)*T(5T3"ABIZ7)F;B%J M 1H<66'M4SB&!I943&2NZD?5U:RC(%D^:(ZK<^)&Y?08+&_=JZ8V?"W*#[UT M^:Z@@]F70Z^X(A(&B_8LSA1F5D]1.>4H$NA9XO=V+++4Q\2CE*Q&]IOQ7&$H(0HHLJ]K)EYBZZV]2V<^X_4)]JIYFD0JLP&A7^ M'(!GJ?D4A$E/)RH1]=@^V];?2FD]&HP30:C6GLT:^>RG^SFK4'-8FHQ\J*A. MQF49IN6\LTO1))KKE.0 &NM?$:ERZH=N<& /D.I 'D=2W(O%IQ].M-<# KAO M_MV5E;0**97%)[2^?5)%BT#+%$ 'V(RU2([XTXSPLM$%5<9Q QQ FUWM(DJU M2N%/_JU"L!,((TO7[D_HH@M%#F_EAS0BW?N2WDK9^9>A>2 ;F&@(K+;54/6[ M,BZ0 WD,[$;^V)>U1@F<35= JY?=SU1O9V]>"H7N*O3KOI@T#1 V:?!LJ5*.,SS1 MZ8KETJR4"R6Y*BHJ.H(B)2T1_ZD2G?IONL[DII=PH^8.IU4.:% 7PZ'/]'Q< M#"2J8EUX*A!,!>--*^0B,=VQ()TFJNI]*A\96LI:1LQ MEL3S3F7*$QS:; /G9?%2BEU)) % I *MDMLH=^P#D?P3F4B&(MN'2GJ(5HDA M\[8/<3IP*Y>*CW-JZ>G/JC 4R=>5" M-XY[JD3G?(9V@XI7N(6#$>1FR[.IQ37AH"8@.ZDJ::-.EEO7_JS?NYG)P4B0 M%*6V?A5:3Y]MU,J*\DPQN%4.,"F(\*4$0(BHL:J1&) MPU3Y4?GII##M;5F@0@BI,1WY65)D.WN.O)RO]>S@2NWHOA",8*SPR@)CW2H;]PM M899R\5"*F$58"$:/=0JY;6?K$>.(M$E1G?P$53;(3O)3TY6.I*U)":Q0=9NH M+N_#&0AAAISZ0*H!)9^:'[/FEE,I2[3S,"3,NJ^"6MM-:F(".ZP>I<[>ER7B MP_^4K\DV);O4R0_Q)().8$+2I" 0/Y%G^2 48JB[)94'80&XLE.YF(]9J M/E/8CT]P#HJ'3_Y="FIGK=2M($/2!85@TJ(\Z_T2MV#]N?R%<^7]7 (U&RQ! M?[ZFUQ>YTFDF5G_/BF,3C/49Y,VS4$E[JG-7GF0F!X"EK*!WS7Z"$MU)6F"^ MV*/-&<;*T.;W?'\4;8C#F:7,RQO(3&FC;HI',? MG'9Y1+ZB;C_5G,+.:G6P$06B4[L"JEA>JM;2B1#TD+ZHX!\EC-I!5B'QL"H$ MB&>ZR*]I:.":4H[Z)U'+9IV:.L4YT;U74P\HD5KMV9*.E#H&4](N$3/*G2R5 M5'D.?JRE9>)K^T5EN27=J.5'L?O8W9&1!!LS(:#:OCGT<");BIG:0TX3@@$Z MAGSH;I-<^SY9U> UM@X9TOZ$G6U)VH9>NXC7Y#;O228#5-K4V;G^JF:72V&7 M\FLYF\"#S16GS4DG:G>B98R7DHF7?':=*WBQV\'.B'>X#BG(]GF#56O.X^HD MN6,EQ6<<2[[OOB77%K+;TA7-(.CC\NE3P"U_/UY"UG?,^G"MS@JE$Y%IHR4RT_) M6#U8-*"B/@VWPSC%F=_ZS$!%V"7[1H?OP+B@( \VG!M7VXZM3(G6#827]0G8 M'-PFA!39=0^9W(;I9F&RO'5QOJH*!6SUM[PKC.<MU=_) M_I!0WP&[R5=._9)57S^HF"^5\=4R%X7>&[CE=OQ.Z79/S\YEKY!4[,O61$HR M7R5*D6:A6&5HTF6OFB+YT8^O54I59>_*IO&@NFSC2L^I9*A[0U&AVTZ7C2!- M6C2/Z\0Q.]Y#?3G5/GECCF)SMWN/!VAR"_9:&B\AW(K0$W]*6YZJA ,/:P L ME$E<%L6C\IA5-K]F-VLH_=)3LNC+[%$@\>S1OH9"7&$K>>/4J_ROW6/3TP#Q M@(8]MJH:2Q'/DOY8P6!*R697N:XA&5#3YDQ[TFCULPD[>+B&0TE4ED\Y;ZH7 MB?O7**R=L08%9K \N768.H2)18/=72G=+3NS'*+Z0@J>1+7?DN-U_/*I(O?> ME)QI=JAN)81.)P)V5E97LCG:3./5=7+QN45= ;E,$)3-3^H2Q<9W\I["9)1\ MZFAPJ>=0$17\K1F9 VEW3BJSC_UT'$WCE[2E^RF4<,KQQ4:Z>VX;QTY #>+/ M.)1N4F:=4%97F /=5#:EYY^JP^=B'YT RB;>&D^45:JWM)9$(L-JN>6,_R,T M2-QFN-?,J^JC'H10 %B_9H(WM;_BJ^I3.%=M+DM*T%? >5/8DF0"D#'R10_& M6 6J("G--V(]M.,$H[%']V'=.N)L/MN5:J3JJ\\Y#17"%7[@K59&#8JSL02=I-3-?MBZ[._(&,GMB%\OF@/]0KT?]HGHN8Z5S=ZH_G488TSRQ MR#+88]+@T7^R%:IY1VWJC/.*=$9FT>ZJ5FMQ8A=-6Z##J>:HJM^MY4*+G7H MB'RHP=*MT&RBW9;^M^(QMGB5AZ#>WKAAQ_!XE-X*]TIUJ26*_LML[MLQJ 1P MF5K;GT&[='*2!TG*]BKL[U;QO^>U/?J#3P\G3OZ(MJ[D?\\C><2!VU3:5[W( M6^?5O'NXI:UNKK527C\$)W-V=B![%],JJIYT/DI580 %FB@I-*26J7(<2T-< M"QM-8D[56T*X[#%G*1(ZJHV]&OBV,9VZ/MG-':SJ&*?C@7WI55[JVX#L*&?% MQBK-+[<=3=B5Q>QW!"8Y-JQ5P,5V C(#C5GP_=JKS2L"KQIR?)LMFC6^SL7' MT*K99C<4@655SU/VS88G911YOIWX7-GLHXUM9M3[4)<% M:^[*'TP+["LQW;2@TK?T7,?U M/#,%)$&<^Y#K0/QIYTC3HS]*YBT>^H-?R_V!HM13C:I$X>DP),F,NE/KM*0T MJF_>*6NE"@"M'A9:M0#(AHX,$AD(\9UTHG$B2*:W)6KU2'D@.-M^47#7#E>^ ME\S9ZF3)TDDJ)VH:!3A-A<"\U:;IT2#>20H[PO=M.S7*)25U+0OA@_/9YND,C$ M6;%&9A>K2*X$&9OBT;&1Q,0ZNQ3%UL#WD7EUZDW6"'=:\?'6*<&5"KNG2_AD MX!<&Q MY7WK:;IRJ#5X\(>"P@8.B/(0J9T*EZN% M4M76XA)QFQCNJD9^;AZQ<(3\S M7#Y/,T.RA'4.UYM]7RXXFRXV8GZ=8&T C8.0[)D4H7L'-"M!,@"-C;C@;#=7 M/J5VZ L**!^3!0)).&3[03\47.-XNJ1%4#N/2T$)N51\=;9*X&+)0&Q9>JE M .5ALX8:RX:4M"EV8M!G92/K'A35E*&4.GMPIX.LN(@*3M<^C,+V<>I>N2-R MOQ+T42X,:%2W0L(0:)AHL3]Q(SK7QW%K*:PJRP?"PZ9%\)!4J>COD'6@S+1'L8?&,)>GUUV56R7. M5>8!I.I.=NG_L *(:MR/)(*P)>, +USO8'D#*I=8!P^1#(GC2'?7H 2()QGA MOL\]*3=S4KB [<\,!@LJ[VIA)=K.]= $GGJ3S:8J +B(2]6*IJNMIS[+KC\0 M"$>EBEV=&PK^X]:[@7B[CC98&B3"Y7._G"EV<>0@2!P*0"12K8+KA-^HO3=; MZQ[+5-0XWS4#/+5#L/URF!HVZ_MKYY*BW=]:%6BGTNO..P/'@.]*'H^L!(5% M&_NYJSM$VM'7T0-9\ML(=@%USR =+#-4XJ(>C^?Z#B 8L%-EUHVLP1A1\M9] M1V*=B1SLUFW$'8I>YZ4OLZE#" B;UQ$]B506*"A%+"G7PP!!E1IR&BU$*<76 M=\WK8E\(%#7%E>.3SVL#Q2MR,Y>0.IO*F??Y'("'QV]1)ROR^+#VA4O@=.I@ M3:QU'?<>%5LZ]QF4!-@.VS,$0G4$TK(T Y>KI-,7[)^<*TLN0A OI100!I;0(O7R\*'U<)G M!77DJ=6F/4W%$KNT,8"+!?(M/55E8&H/>5;*'I'5B]B3= EF?JCC)8!I54#= M.I1)5ELK+ :*HF.];S?%'[AO]P3T/(A&]]1+4:]8CY,F*/7)]N5LTAR*;*5E MUW!0J0$66#4D-U8CB;IM_/O0)HWB@S*(=^9>;NKCLF;!@!(-;&:O/@QXBNHR MZKZKQ EW3-7MLGR46R@;&WPL0O8J&:[+7H[25H\F2:[ 8N5KT:PS.V6SDH[E MD4X>@/>)=SX.8O[JNL]#F]7*VNG C?VBWFA2_;CNP((]FB"?2E7S$WV!CT9Z M+MIV4U '(1MABOJ! J5MZFZP;"A7KC,IY[F>MXZ !%V5*<$M+%8/WI0R)"4+ MV);>'/M.5G7670N0]U"\3E4G2/!+C0Y,+54I@PX\4>."QJTBIRIY!)39IT87 M0VL]>[*\3CGSC0Q]YZR1YTT@4$J ;ZDS!\(UR\GR9B--&^MR]J9V*OPCZ18( M8?]^!M[SWDG-H[E!I)>-,[(;J4>#_7ZA'M3=O*K/9" M4G:!&.NIK[(;)V$ 2H?I8UD0]R9W#R"BGJ#S*1=[V M0\'BJO:0U:EEJ,VW6X_Y[+LD'3X$8WN>5?ZBBS0HZLL%^>;MH0+\Y9;K+T#T M(7Q3O2B,G#2:VK=#I*'"_1,MQ+JQ];!1*+V.VGLH4*FXL";)G=@LDR'+6M&R MV:*F>5I$<6O[1I*HW9ZQ![5"+K7.M ?F.@IK_SA=DC:-EPOJ)>9Q'("_K3C2 MM6G)E4@:K*= '-% 1L-O?U#B%Y7$/3[)]RYKU*H^S MR^,DM"[V:=[(Y8K/MSF5$AU4 H2(P]I/22W@E SLKOD$<*))N9VV_&\U_7I1 MWUTA0^5J \C1HY,DX5U;-8\YR557UHT6"*?4%$5 OPGVIT09FP/L:<+T>!:IE%V3M4FL":#+ M,[AV;6-X9OUVT('L0AD=NRP*8%P%G+*/@=Q#C]:IH9GV>+MC^[U'2;.;OAL<;UX%6D@S9]>PD-HF,2L$F-L=N""2P'E%%44J/ MJY/H 5 ;=]TT72UA%*,EX'@9IZ@Y#BYAG9*^.G4MH9MRK&E,2HY73].;#^I7 M!L\-U'+D0]7Q!@)FU?RIGMV//&\>!FL/*"4+P@Z=+3\W"$%2;R-#I;?B:=EN M;37J=E2]8%HNU@CKT_RAJ3A(-@!%5O3/V%+GC6:T%R8A5_S9V=@8( MR6)NU %9\X?$5J72!+:(Y-7OO)8HMC^0E((=BWN2T=;7K:DP>> M27^*62G4)'TK*PQ\:[)D@YA]*#Z?>F83 HLB?H3J!S#@",E!O2@1+4B9S%*) M8]Y2EAU#MIF$G7M>E"F[= M%A:G*>(2J-'O62M(9&O(=REAI'Z=\V#X@L:Y\GHBH$:&;7U'?K%:T6DW[*\/3:BGFTZTQTJ9&HX1MA)^Y%OAX'(DI=8 M#*R1JPJQA/U+U%!J4[P.7!_M=%%<"_1D8))RN.);#3KAJ.(^E)$Z"%$:W-I2 M/4#WEK3TC0HH@)P(XRQ))5N;3A-@]] MF)Y3EY932PU)3ER)827H_/A$U6E)(0\5]B6NN*1E\N6291_Z1$F+4@J.^H*- M<5;!'ANW:O3DYFF&[$Q1H?"=?>X*8FW>'$^<2)1MNB7;_4&!94'!%.\"2"ZR MD_0W_3%8YH OW7G4NI0H1V7]@/W):->8,AMGEQ5=B H-M'E)4M2250E\&0O[ M!C*2*6@Y)KP(3O^06@\3GF02O>[5"O9X7=?O@\\Z&^%4SUM5UZG2/*Y306[C M_6L+<4H9#S*C]<]F\2[G=!9+&V"O8021]'6J^69$WV4ZL,DIB*I@7@@]-JJ< MH.2N-MU!VE6OTG/I+Z)9-&I/-FL>3!)NG;MZ;NL1D9;IR6) A?0VE;O<]WDL9>G#WFR:2^[\5$VS;FL^ M3*/6"EARN,3&GK-2>NCMGHJ'NRAU9^Q]!)!\91UA].P@/PILX5 WXF")"; W'*#H8#8J&:) MF+S/PS/V/_C M]1_<_%"[D%5P)^U,%+'T(V5[.S/&VYWGH3&6)M- "4\@=,U]LN-:>]PHAVW6 M$*F/?<@]&YY*7"<19%=&,FDG-U1LRQK G"JU+]][:A UX11.9*EJXIRVVV<_ MI2)6+:(!/E&):^ET$W1,5:X+(GLW2-#GH60UT+*:_)Z9!CT15]%+%;OI:T(B M[!+J%0Q4<1CTK)@L5:]&I&2M'#3Q?%2N78YA_.2MC^-#!%TF;%R_DN)#AT!' MY,*Q:+6R]0QOROZ3'W:"=[8*5O:S^X=O,@2Q%4"@+JXZ>]-D2P!HFW[@RNW6 M+EO/^5$=:51ZMZU*/N3I^G%5A6=)0,ZBZ;BKNU@B)?$\NU6:1@15L-0D6-M# M4$W/7W'=T!A5#24#CP "ZB$B %MVZ6$]7&5[ MN'&3/)EY+9*7=4E*F56C_KN_#S>E5BI3'+O<\[>$0A@K;F N>8< MI#YPB"T\E(TD'^TJ)*1GG:.H.*L[I[+H92S9R7O:)D,.(S9HV+9HLDQU)LDM MBI(+SR5;.;60: 4\$B@AIGK& (LM(',=_TCSFBN(#/?CW:*%7RC1XEG M3/?0@J:NC0*YQ 1V2B-6/%#A)GR$8_7)Y+Y1]OBL;6[0G2,F&9+A>MPXKJU< M]]-9PR3$71E88@B9BZ+;_Z^:ORYAZ:(9:@"Z5VM&_M-:1M4D;QX(.'DG:)G1#B%*7;7+;Z4HK^7MO%V$$PV&*WFDJ_Y+%B!QRJWC_S7Q M=:O!F-;OQ>EA(8'*YG:2&!O0)UV$=/)&F_P6I0C18$]- M-J6>WE96S!\R4"4?N=69].C.6EB$ZO;!/ I%Q#J+1JT!59. MWB3X<[O%_5;K2X8\Z'GE_]V /[VT*=S'N:>YN?UEOX=H6@N1("N[26TCZD@8 M9VB5/":V'*#WB5&<.5!=;L?-Z4LS-IL2H!J+CX (5FXU\ M'@_U<6.!.MO>FVRES12B]*38O2(3,I.";51I^^8N#BDD>]#/<[MU=!4/ZD4I M!I$Z#"KC80R;*O2>]0!()X+3[:*AX:QJME>J&X&OZ7$>55\'^:R.TVGCR.). ML5#/M!A3LE-U7>,9[&K_@^:TR!UV4'HVSN]NFBVID7!0P+CCIA%\DS$NG(\Z M*EX>7SPL=&T,;GM;R$7D8[)YMAF"$CKP!V>I5 *O) MIRNUW#QU:D%" 'X\P)<955A :DCOS5A.0L@;DP_,?^MZ;K;77UO;LN==LL8J/,I->HA+C:E,+7G1"P)G\C MB83!H%R*_&CBY.WAAMJP]B>2L0P0)SEI;$NR^[)[/%;"&)-6%^]33M!#PM5U MF&5+1#LPU^O@&[G\6;UI,#D,?'G3Q6ZI )+-,U MCZ59W!IB<*P8@UR"QZ#1 4/7;<=OSK5?S[/%8!?+WEFV#SDWZ3]*(."BE[7? M+8WGMNZW')B/+O"77:4\8$)J(5ZI3IH\XBI;IPRW=7I(A]9805MEAN#6&,+# M%X]S@J9<'E_HD>KA9I%T>(@N 9.DCJ:C7-]L]JO9YJ2J"OYI]YMGF_9T4BP# ML(9+>53[]BLPQ;-I^Y0(Y%PFD$KQATJIRMJ44+(>HB9(U1Y\*T#M!.SNT@R" MDOPAGN@;FC4%52O@)+APT4ME@H)UU^_F.;;*F@]BQG.RV*K1P#RHY>NX%)PE MJJPNSM7T^3R>: 2;-8?^ "M@IPL(%%C'6_1$G=9K+2O?19J_3 \=^:>;>-/+<=2,!6QZV[I+SB2>=3'>&9=$:UGXX M!8B^2\$V@N'I8=AYR/@DU+!Q**GL* M6Y0?D*5C$@J;EHB= 6P>AO=V#1LV-,!VPZ NH$H]D^P?#T':<9>;$JG3B7.: M[^ZV&5U\>#3G [-3N.4*C,=6*+_I;RU\8.3G0L?.]Q1M#YNJUNA7$#T8 MDZ,*9++6'GH;I:'';]?*PQ/#R*(&'I@@@GO3N1L.J"M2LGL),":7GJ6R:R) M3M':V6W2B_%[B+0@G)WI=24R$1 C;4/7\H>ZANN4?7#K1,!H\#>=V*C&]QV( MKN3W%MV>%M%3+TGTH=(&:56^UM:8:VZ,#Y.6BTAR?77>=MM?BQ)";M"2O8 0 M2])^0"P]9SE!)$7/::M]"0$U9B6UVQ:&'D*E %I(/&?L0R,M=0^,'*+A4_F& M3A9,FI7L\G1)[AJ/WJTM'O:\+S!F\]Q)G10MCX>LY9-ZJZ@%8)MVYA;E^'O4 MOMJ9 2^V\FM"E(!TP_TI'@]%J VH?0.04%H.]]:>1QF)(,5D%75'4R.(V=]D M[7B:P$)A#K/TBRR&6\F0:3GA$[L4.Y>12<(@R?*AC//P?(!,8CK!Q:UKYS"!/3N4@IN,E$^'21Y@E MXL -4AEP:6<\]]5XH,:)2><&PO-XJ>KDBYP _F*+_.TYW.,$.#SV&?:1W+=2 M[5.36 KOP?RQ2!^'[!"%75@[TSU^^YUFTF=]X=Y;$0&04U]Z1(29)EM;X]O2 M/.)0:P%D*,K5L]B=@!$^^DU2II1#D:>@A M>]\Y6(VSB_,>E,4X)ZOQUC+-#N:KRQ](*LB[_P.*S;J4*OC2/7HVGU$I\8D: MNFAU:L7D;@S03/^,RPT6=P^HSL(P':K&\)F:RF=VBEC0^ZUO FAA(=J?R^V M)=O;<9"8IWMZE,;3U$_.?>X"$FW79+N[;KJ;>[ M4]T\*V=T+A"%NS2L7W;XJ')QWZ>^RGM.DSKKW*@SH['T4->LM=L3_ +.=[.W>$FM(9')$ M%FN7TLL0WV1\C1(/34-)!C?3+*K(H$V+"@2/1@!@%,"&C>\@Q"0\8?25'#I) MIU21M\;P=IQV MUP;!RK%<68(N0]3\-L=3>)T,PP:^.CY;Y/*XDFU6I%D6*M=!9B BI2:=0E_9 MZG9VEB]?M1#2.."R2SI>XG?+ZCT,2W=0K0Y2S\72THAU1M;#T63O/:>TQ&DA-ZH+[5T,-#8P%4U1N,A79>!Z%(IHT<%BZ28 MD6*)_"?A(U)84H=E5KB]X+,Q,9ZVZ?A"+"(X-1LA^:V##V"(RBHG%7NKB6MG M1M\'%ZX]=-#K5'=.AIB2[63^/D2^?5N6F(R2R;7H_#4M2PE5NB(#<#N%W#J= M(T, H9EQ[O]J^DM>3<,")*G4QU2[MNLATEC$D.2*;H4><$S;59YZQ%U]ED>K M-9;>#B)EH16M+4$E*CR!^%AGTC1N3UY)"MH+N ,S \CY'*8)SR\HL+UF%K<* M:,DNO]LGNDATE;4YE1%I]A0"M2E&XP:JUL!%,YT^(Y,Z&:4)4<14][;.764? MZYZ3OVC&6)*^\DUZU1/Z1&6PY)1M0GE]N>41KRW+NK!B/X,33BX\*X.ZFC*KR!@]"#55 M4Q,;&T/7EWNR7-64 DU/Y;,L82*K=-,N::Z- N;:'#E2A^U/%WFTDPC<3I9QCV9'B3 \IA]P90GD'3HV.IGV55@C)@CF1T/^7*$NO< MEN'#=N5X;F8"%<"Y2W97UY"9XCDZ<4&&6FJ 5<;5K@C65! MRLWQ%('+4HBZS.%0^=DI96>/]Z80#S!! SG;M9X4EMD4L)')>I(*2"[NM7"[ M@!>"JWT'(;2Z7$XIXH)"73M+@(*?%$(>NSQM+G*MSR&Q-4=/\T\>>&I+/%,# M.YXW5]>)4M4K3TD_.V N0! @FSUWZI=DPP>4L>M7-X^AX@?I6J-@;6IT2=+< MF+#)''UXFX^J@C)M7?BX6T4G>TLV;:XD#[!(Q) + K*@*# E[#T*V&0]=NLR MW0'S#F43%@62'$GMEU6A.J>GIN1-VPJ)$40L7='+BJ_#6*G_%@G(+7&>&_!A MR5H8ZE@;Q$+9U39CZPP[R%]I(^"E=91WVBW251B1,A[UOTM PUSB-03.ZFC:8#$1#LF=O:Q[6C1MO0Q"*DQ@3\1)L\DTSF MP&Y9#81V^\$$;M*6FP>7G"30MNQ-=63T5#3-'-3=MAT?^J81&;.'3<>9"%_1 MG'C(T5#/0$Q%MF)VNH@['\"57;L&2U3.[H%6K>"8>#O@R!Z99L<1E;MB7Q1@ M8%!RKIZ_E\WS5F2L7FUX27ZJUZ^*C,$-K7=_3T^U>HA? JI Y=P4.RG&J M'*H)F8IS01H\0=4.JLN>YU3;5N7@O2"L[O936^J;Q+PN1*2 C!IDSA Y-%H-,EL:)HS,W?L4)Y+:FBX/7#:0RE+ M@V]FCDM-T>'1[9'+AM:I&>;:/P/[2-+*3N)BK_/""00%*E9YEYX5J?G;I31[ M.'0K!#<5.R;B/[8F XZ:5JT;2X604]W%49I(01C@-D"0[PCR"RDZ#QYF7WI[ M4@;DO_- KJ@B(D&-ZDZS5O4U6%J/!^R/WF @40(%V$+>>%Y$-,7$9,Z02@\% M>&QDE?T"ZIQN%:3H$=E4#2ANRMU(!;[F+3MI$JW= 4QJK %A=VUP*:!N#]\# M$45=Y6<2ISNIP:,1?H-?W&T?V #A21$R\I^HG4-T=,QJEGV7:IJ:;NX=\0-25CXOK;CNK"\J2+Z!==FXE+0QX5T05/&WHEPG#SEKL\Q23?*SZJ%S;JCN63Z: M;A-4GM,N%S=5=?>EL*+L$RIOUU@'[CQK3\D>]]]-5""PQ_TD @T38;>+A6I9 M9JT$-SV"\Y*4)4RZ'SYD/*?M\CSBT+S<;9DSJ#4X*":E)).<:4\O&BMA4U?(//U2Q(B7Z[@U&V["DNN) ,[[9?/U55;KIWLPQR5]AZK(.D&*Z\ M3#=W4N[A03]S,S\^F[PX\2UO9U&4P >WG]TP]GBVM%R*[1=C]?2#8;45R8X3 M5MAELX5D-":R;>8;E3=8/>A:W?A"MR4J^>ZTEQ!(=U43!-E Q2$W M&"Z)?'$O&G:F5.T$*EKHUJ0YO>(++M#(P,N7.C^S;U:+%W@:Y-.%9T0:P)IW M=[1;HV]"RN4F6K0;E+$@3VY@+"H7*8A$4(4EI.&"*TA\IS[.MTQVDG>XE":T M]ET/U4F_EZ7^/($$!3*9RDX M:J?T6QXO@T'68)HW;66I0"4R3#55GDO!$KLJ+ZUG6:(5P MI;:W*88ZZKX!RJ0300$0;]L+-0,!EJS]*%&0%=TD#1* +UG:#]NQ>)%$UZC&;C$'7E62VW7-0>F5;S=478^8P".66Y7*34>Q;S?;74QCP MW,SP;N(?]EDESZ_/BS2M2,)>SVVN[EQ!';]#/BO0Y'YG-O@I0 MP!^*^&AC M7&/0U&G4@-(9HDZ0G81$;8]6LKT[D7@B&];JLCX>11]*MD0J@;T0Z2X=1L&' MNLJJ4B3UHXXGV4?7;-85G,\]2WG00)3)]+\)M/ "'M<^DH*EYW*>%QR>:F M0+J'89/918D4B.9,NJC_LSO*>EWOFXH&CW1BD .?;F]=XA%:Y5S$N>QII8=] MM9P*D9$',B7LZ2@/W1C(2DMMU^"Z*?O:;ZD]UU(6#CSTQ<&0&,#LI8P9U'64 MFQY>L>C ME"GX*BE,06)4W-,RG36XVM!8LAJ6;HDGV?0QM@M'G9'=+J/'IF7P>2/(%"?> MN"W+&;K[D:Q44/2;99;*5 B$;G8;@AFEIM:0Q:$"L=!09>^ M3D9/)G?:/9FVTRH^8NJ4W$4'.8Q$I#5\4<_7W;\.]I;$*D=6ONIMCZB9CEH' M#$"&9 7GQ94$Y%-5,3Q)+Q#[VT+>1)+J&D\%?:E'K$Y78KS5&7)ZEP" *0H[ MFUA&MQN';Q[3]K-+=H6J;MFN;Z74J9)4&JQZCGB&=#'?;(A@ @V;&N36>4(_ MP2O1YE8;917/.MQ3IOQ\;%,;E=K)9:O^E J([@E0_YY9=_)N/Q_%D@>-*GO9 M=>R)^931Q$)VHU!A@"S"4IAOH]*[I&Y%Q<6U.=;7^R ;5YG=.H:3VB@L +L^ MOL!S[3&QV DUC%!Y6&Y973"/OAE@4C@1\%+1U -DQLH#SK5=ZY$.0.;>F9]$ MH<4#/]VZ/?444/&]/B$S^9D:GE3<>W\*HS85!3Z.=7S#IN^ 13RA0Q(L+*T 2UN#P4;H0542#P7 *$(WD&K_7.3)[JFD)XW,%5QAE)XK)"4HS^-Z MK 55)*9,X,E-@FA+2:W[P8.8Q&#OBP'04$EAB^:0$.PM^!%",WL) FW#=C+OS XS&\NY1#8;'/D+P?56; MNMI%?J2I_W)6HX8,1\!6]E":,/ B;![C[#R66\*/L5S=UJR7,9G^>'0 .N>Q M?$F85D'-2HU-'I?9KD ]X="#&[-/:K>%].P@O"@#1,8_R:?)-*+B+-0]%#X* M]-GA9=ODWJG>> F"D1L [B'=;#R/?G?%_8I5>5D<(!5AE=%VR\0."]LA#!3J M3,B^L<(OC,;-G#P#F5!] "(M@90EHFHX13F13?G" *H8*4LSVSTN)*Z+NTX7 M+C "I)E W8I=4R%9..^-)0NF)>+.RN.WF5[K'05R$C6WAO"=NJ)0O&KM8H.[ MFA!)51,E.3T/M8/GT,^;H0 6;3P68"\H4$T[ !5P.1Q11P2FAFK>\NG$"8^A M2_V3L>PNW#>OJO$0U_8]2?$Y-WEWHT@,6MV8"K+XZQG(>=@\I3P<<%B"VZ-L M<1R2+4'SMAEY5!=U9E&HM+;-8W').VJ;]:1+RI&5K^+R0US]CJJB,4^B$T)2 MN:X1 &CP-V,PS>UW4?/M2%M^ $YDCJ@H\>WYH\E1)"BW),ANTC1AQ?MPJ562 MLGJ@1,$@,"N*/7L#QQ,V]QNJ[+?$WQ9E#-U7KZ=H=G=O@)GO^4+9N0Z4]&BM?F9:4G_5L>0E@E&/I=I^4=$3GY;&E\/NU M#H35?4Y/G]2VU:/R8UAZ@&Z-.\9FF[TJRN.E/)=W5 T,ZL^W4G7E)I^ M<9I"Y0LX8>6VJM*-*-WW05'(YU'44#_:=DD%SL4050 (NVW+(#_@,R%^Z5=X MPG@KN*9,VNZA5Y4XNDGW(V<.-0:-_(0&8, A%9.%4$SS3@X&FL>UN[<+]E,3 M/ZE$D=WB[4/R66ASTXC,RDV#),F[85HY%BYJ=6_VPQ,840E!,7@NR?Q2F?M0 M7CK*A*-HKFMC646&J4)3L?E:@NL MM@>2UHR 3>[-*5=J+$+$;JP*(T7Z7)0U,8A50R670?PI,==CFJFQ5";>3 MO9U5GJI-SG?;Y$@1OXI($#R5/7C>;:_H@)5*;CAY?$D!S%V-[J:JKVN?B5^6 MIH[M*,RBNU*A@ U_E@O)S2W]>W59%2^.*4E5:B^9K O/>,*,0(1[ M\%-"[%U5UZ_V(JH<<:7F#B^U,:N_.F/#L*]+;E*RB:V(PH!Q(*,0;C49JAU9 M;LC9W0K&):&1A!NEPUB+JI"#/,>-)G82,RF 1U$]F[/_+*CM3QY3P(\Y"1:; MBDC:.<14(;QM[A8)FMT8LR>:.)>OI%QO<#5H^E:#1X(*$P <02D\A?MN"N+9 MK*1N1U8!C'@F.7*Q/^JX;'3B]Y7@E%T'=%FV=;:V4?<^ZWSL64H(=ML&N:\\ MK[!3N9$/GKE9'BIS;\L%P(58,/5R(Q:I=RVEXK'G])8M,IREP+RHRHX'JRK0 M$I)&UBCKR-M]9)4!DDIS108W>6BY.A6%6]WNBKH/'9+ 24K23[+N;78H<"&L M'8;)T_$D:Y5RBW3Q=/7AK1@>?25XW@RB.N_J/60@AFJP6<'>>:IIF8A//%8B M&NM *-);WC_3L\ M.%! XSY%CE2AAWNZ/M'K$G>J/4<%J4ZA^M"-:9GW%8KE6V4+%.86TY.D/C15 M">+H:".0<"@P_,<2T 4P=.O-;I@(4:[$DKZ4ZV)G\:4W#'@V2JOE*9]@7A[O MH=_6SM.TR;OL,@+)X)=U\J59 >M4IO15]OIHOZ ^]ZU8U>1=A57E- SU;V9X M\LX/64ZG6G#2Z.R893*4OBS*5A'74E-JBKLRP9:U%=Z6&XQNC,NL1&60 M4]VU;8+ CJC0G&J-ZC@&ZAE"$F,@K9_\I([XZD.ECF->*^<$<([VYMWN#163 M'GGJWJKZ6P]9,RPEVUNYH:-:E%4OJ?2' -@!0-P/J(XZ*A'ZDM4QL)743;SA MA@'?3]HDF]Q%C*@=DHQ)":U, ;(2*P9,6(D8U-',9)LNB+):.@4 !.G"FASH MRWW;5;M)"RRD66K0(5V,? $^W54C!#0I_G%12C$CE=HCD;GMH !*HD**ZJS* MSS2,$OPW/8"ZO6E)!GV3/-"B+-6]/6X^D#59^GNSP&\ IKW@(,29!XDGSR8S1*\/'XXLRNR'#[/5&0Z MWL#7YWZV4V[_M.GJ4@BE,0=S\ZA6=*O('I7 (!#)#RJZSUU*8LF3/@XJ\$A> M-DGMPHE-4E-4UC0H:2AE^9)HD]V_5=,BI$MI&#D C\(DS=:C%;GV&R'+, L3\!5N!?CZ&E!B!O%BIUBH^E]5*PA*]9;1U)RWV)E= ,XV,GT )1>/9 TFRH&B R)#5Y!,,]:Q%,GO(P4PNX^_3@ MCWN9NYX@9-N@HJ"'5$1W%G\Y//3(:TZ D>89 5"']!#J;,N_9)=Z7Q&Q#16: MV\D'Z#=$BCWC88-!-.)0,EP2Q3RQ/:ADER3J,'?;)B [HRG1M=_@/SO[^;5[ M"\H] )W QL0\Y525&&7ZAM->QR2W5RGN:+NT)T&$Q<3:4&> FK-3%7"1Q\X/ M&R$HB/R6&1MQD4 M[%R0(0G0Z6I42,O20_"PA[2Y:P$BV:VWS_,.#/RES:>;+HK&'>/0VR0;>4!N MFV<&KS:E20S0 'BK'1KM,D&3#ZT>SEUF6&TI^><0^\U M)7UO^_:DNB_I8C4:).,1UM6LNJS)+GT-[Q&/4V+;<:T=UZS>N%K86ARR H[- M]EVP! MW#EK&S<3PKW=H!P?@P@FG6K3VC>Y'RKN 61N[<489;+X[7%]M!Q,X%4PW76= MVSB[97Y7R6#)T%U+:V_VX69V5)?A($U:&VN!;3-]YA8)/-EV*B#(66SB="]1 M^I-' ^KX#;OL)W_=5)>5>NXB/Y>0@#L^%O!N4"D2L5RWK*MY<'V(R49(&R 0 ME"5WA?#_B%;OG6BXR-HG5:WC(MO)1A!97H!+<)OB\0F8U^S890UY%,JD!6$^ M#'IEWKL'8R.)\E@[ER^M")QY>+; ]"09763H><*>^63EX(H[R20:&9'WEGE8 M*2\=AV,JO'9>?M304+O9SR13]]JY&,"3VVF\E^2X$7($AOJ*ZUMRIGMN'J@- MF4.J^CV,]_V $'4K?]3LLF,Q2<6./ ^>)M_I:=02GF&RV)>@"=)3;3[;CFY+ M471G:CYNT!$G%\"3ATQLH:BTC_6QY&5"ZA/1J=R&5J^R%7H.'JV2)(^%SZ:' M)@NO\4U@SK[XI=2Q29N0DC48W"W7F0R1JB'8W4_Q.H-=PR1/T;_1=N,OY925 M<:I]R(174EG1_RIMA@=?2C^T"5*0BT4JK3LK*W14&\+CI+!SV]Z+W<1++C,I>U[M(!:0,4\P\U?$1T M'K5(FJ2"!-,W12QOT@M1)&JSE%7?]71+JXW@Z,N%TGUC:8AMBBL1JR9SEYI& M786HM2=0E;$"!ZIX\R3R3-4H=P1WEFQ27KIC-.N\V )ZVG0),C7)]\V^UMV^^*)RF#N] M8(&UY>$9GPH5%$KVIA!T>SAL'I$7JX!1(2\H]I8O$ 6(KV_)'A<]R3J%0%;# M6:69:C*B8&ZKOUVJB0U"1O/D 10?)TK6%O[Q..'QQ'SL&PA S,8#M]M0+@H9IN#<4%W)0(+H^HQHDQ?JQ*I*#PKU0-[T&20 M,LV%;#>1;0%)9^/50,]MA3-*]TK+-T3IH*/HJ]<7 U.?O&;#8+7-H?NWX_2@ M4<;%D9F![S+%'M6P>MM7G&$[0KQ=ZB94\[36XJ18Z1QF8GWZ[JBCM(:KC,*J,V$85[ M(8 D(.D9U 'R3"OH3>!YGD^>:?JH<[J#&LB J6\:B-IT;I]L(^NX_9A;6/"* MJ"%N5Z'7B@B<006E:S5)O B9SW0ZO??GYO(]7B/25(5])&A&MRU5265V@HH5:"E:2,]5,V09N>/NM?HY$VE3U(D>2['3(>#C7Z7,-NJ>E($Y7$(\@M M51\_$5P$!KZ6DA3A$A C226P"D'>8"./8IVT(+-E)RY6)$S./08&Q583=V;< MJSG=$&-P9BJ>+S-%#6LRT:;=434HH:R2D0=Z[OUH)VN7&*.P?,V7T@W+W2VB M2'3TG+>[\T>HM1]E2&M7AK8N&:MF8_%F*:HZA(I^>O*2^I?-2C>GW46)?K < M!1\)T[--6T07P W,%JY'7N"A$@D/=9- G=4RU)3;PJ'ZK6[0<2O*%O6Y#^4G MI6(U=V&/6]ZB%A'VJXNB=XN9>)2-4:^*>EO0%OT7AW[#0L7#ZL#](A*'Y[E= M=\+FKVC 20J\P4%)T5,"SZYG&,"%)]WW8/_G5%N=?);4SWNNJ@PU:P[H/?9Z MJY!^-C1-U MR6I<[D4L\/0U:2-#-J,ZK7H?U UX=R2W8 D9;BX#Z:E.GF?69ECO/7@%Z MIUX./)@#!F#*NGON:YMM5UTJ_CC7'O??;D=$PG.$7M:,J@$ZZQX M=@" )I"2MH\.CG ,]? MNF=R.>(N]X,.!5.(#_KX-!#2S%OR7$3H3$S#?KR<4W$Y#/;2]+]X'%(<'&W1I/RXKR^BHN4?)3@Y%^I)F< M1;VC.^PZ6VE3:3]96CTEY=EW&4N/9B;73MV\+XE,-V[LMS H'C;KD+DX9112%6C+MI\\C:J]C*@[NIA(:CEORYY!6;,,[:>:P M?8^WF73'^6@#/XM.](?: ^ 914B)L,]JKL]B>WOH%"E\[.:27<'JXH^5I1F2 M7BYS^\'CMG"=C)U$Q4?F59V;YH4,HB=/P##%BGCF>LGOE%+]G/(VM&W<'WT1 M;#^[M)YPGRU#(K1)F/1"3J2:W='DML22G M/ED4':4N:6/RM >_2H3W?F_/4L&9X8I=?EOM'FR:M56JX!N)O&H%VX[GI%Z[ M;LVBF&4GA\^63^8I/SK&5K2ITT8$^!ZU;R *2K(<6C=85G<]H+-M*PR-=,M' MI0C=Y8+NJ(11AC?D\;S1;9IZN*GPUDLDNY)NIF*_1HHR"U MQ=2C]; L&';DQH>I<L9 M*P/*P[7P*-7)"#+/6F!Y$J%OUPB/D3\XBCTV-F LXUZN0U5O<9SVJ,R@IM44 M?U66V^ UM%_I.NG)\F.(U9N>FI@LX10%*"B!@#0 8+ZXFCIVZI!#7=+LL:>F M5OD!X;J71*0!96S'4CN:4]D@QQ: H@Y!4>4WV_@'I 8T"E6B5NFL%)4/2:TG MCYY_R@53[I,[W,91AHYW,4CM4%^!_'C9!BNT(MU%E2;"71[;57:=7Y:MS6$Q MJX:@!BR@0OM:-H+1L+?!?B6%&%CT.I#I-* M,W#?_<9#\Q PJ-S+J$DCH8&: M(0+SY;'+\]#C[U**O^D"SE^"AK/5ODLK3C6E983E*^F*8T>A+I=+_>>H"G[M M.L<*/SS5N<*FA(7\6?=2"4YRHPB(_*A3W("4JY*VQ(<4P4V4?\!7V]$/E8IZ M5JA<4M.NE;G!%/6#U'=$B?7%-E:;A#00N) M(0S?O&U!]%1J.^T%7;K7AVDR5&2_[,^3 M_-NC9P/$Q+M?&VF,;",Y^[%E6B-O&>I"WR+]KI65?'23O+0YZB10PA5U8]$4 MK*W$5!>K]-CFDUD"32H/JXR*O9V>*2D0+S'(7=W ,$6]EH%7741F*07:3>[P M7ZOKGXH-($)PU%I.(_B["V%.H/>S6KL>06M0@.B2(<$: U"0AA)XCWM^EINU MIP6 )6GO+'1GH>[5D]YK+8^]40U&BHRJ*\E=]OM0=#[,^KX MO0-U0'#@?!**KN$:,3R2$GH1XMY+T>GVS+9)OB6A+-E5%0 ?@+:F2,WN!Y,R MSSF+' Z%J'=+Q-QLW3@7]?"6)J/&-E5*4+M)PHRWJ39)J"KLD#58#4/:":]9 M@E2_E:K.]D^Y!1HL *:E0I+YN1&NG-0T+VD,M[NNMI?S7#0>GFU9MG=IT?.2 M4T-"I]S1B6W((F864<[9BGYQVUV2\C7LO4L>_#RV,1R4&\ZWKHJM?H.7.^@N MDP0^;]LNZ:1/77!JA+[/+2#/>PQ5G$^NB:$ZG:/8%/#6!42WBN3S&X%]X M1P?,37);W35L?9;YR_Z9!E&T)B7PD,P)&< 4+C%6M?*>55D_(0LS]*3UU'3O M3#!"D$9=6O)D49=5M5M>^@#;MZ<].L R2G\8E9?LQJ%3(E_<%(H1;JBX01UPR,N^B@>QQ"G-9RKE;M!# MQO9 X&49)%JFGVQ3&T#\3>72R7-#7S:/!HBO"214F5ZGG5@E*R&_-XJ**ZCG MH>E]40,7%T]!T2]Q0;%>PWE&%8O*4@)ZE?%LF:WYQ#6I'XE)9FYF4V;>M[$,]D'1X M)GQJCQ&SSI]#L#*G6T3' MYJ/C4N;:A+W<5K+=*!02&XNZYVG3\%0&%!1%[A^DF&D?/<^,#WRBV[LN,R;5 MYI$:]>8EZTX.E!M*YZ/.1I/Q>H%!_7-6]6TM0"&C0=%MOZE) NS\U.67UY)= MDB%&.R>B7NRGM_*ANE @D47JA-SKRBF4URQ7ZMZBWR9S0(&CJSZW2IU/ MWC1*N@BBE =D@<,=DQPDF!6MN(ZRNV]"9>\ )=E9R0!O9TAO;8EK*$'#W[%^ M-G?QF"?BF:JZ2?'<23:H_5)2(A8+Z@9)Z%O" $X&8JQ=#7MPAY3)*JVP@[9) M+*J_N4F<*HA)S44)^_GTF+EKT6>0Z3-X]%0TRM0 \VCV]ATV$RF:E&^E7399 M>5V3';VC]8^K3^[N3LMVEY>O/0"W ]:5#2Z@:L%M%\H>^U?422E'8U&=9 M-_>;7TC*@!J^;!5FRC]SR<43%:RY>5-OC,NZF4RQ;+$T@9%E0)C.2J]M!$\] M260SV@&1]1^6"P!B)2 U3_0IB]4R\F#??IGS4'RN/)2)LC=-'D;<_0>.Q[=.<"-%E9NE:DGXL:4:OMM]=DTUP8%<@MMHR:R MHBDV0HD)648@9%*%*C>:2Y7P'$.WP0(X:52(5?--$F-YK,+F$N)5_/52$,#] MHC'USE#@8Z38LI9N#*0&3U5BET;4NW3LPR*%U7$IRAU,E0]8'\:%K.W@]J=KL*3P<&KL%D+I.?T\$;:>U M'C0!]-S))M[+9$N@MRKF602/] $)(9,2E;2XJX8X//3.=]G2J,"PCLN;+78@ MZN"V@;KX?(Z8?E)S$UR=F_MI=ZN'_*R#N%/6NI0%"F1B#V<9U(S<)^XIH6N$Q7EJWJ0-'[@3>$(+MGRG;08BP MT4/7FZQ,/BL#/)&3%?0N.UK-K)(OFYPS:=6\U1XJ4:ENW3Z0U*GKUEWX";XNYU MDSHNR5A1!LUM S?E"GC"(Y&'N##MH+:U^E[<2MB2]:3T,S?VQ+$ M'U4UHOG(724KX9HZG/P!V;IX(%:%]+H6G)'T@% UD8"_?;CL8?W5CT'L&?]D%)3/U=_ M:AN.U/(E8U^KG4VE3A(LH4 W7\L9_=ND8U>W.XJ9.5ICK7(WL1*71W78:ACX]H,D!*I8IR,WP=AO[ M[PAHVKN*4UFY4MEB_4Z+ )+D&-6D;K(]98(QN?W7$NYM@[*:Z.D6ML=CGC]- MG@BU@W*O+D$^S',L3W7RD9;@Q?*>50Q0%<;.ATF1'HK0&X* V)+CSZ1@!Q=8 M=8 9=CIGW2.])G6G-;J)GML*3N0&*PT.DKK+DH0$KS)IS[[8;RPE6 Y@XF*4&_=TTY^:5@C4>HMS%&L:HE=D;YM6E:#')4 R!Z\*9D TF4 M)^Q!7XR*;2I2T%<'=/-[%:1A_2B3PZBI)741)K(U.H$SV9D[%--]3CW@*)KD MRDKB9[:6,.PCXE^71QQ9^1'I$;B.I*'<6$7B8D7H;C,=$:#=V2B8N.E@#Y^' M1&I N/7"].DL.AM(FF40(4[>D^IA2<)+9M (K)NT^(62U-(\[8JSD[68=U@' MQ[%$B$?K&B7DQ0?ANA4DDYS?W2RW(8!L3"X@"N+6H&B6% MG&Z^GII*F0>1*F+3A:VDOZ&Q$EC+,YK-WBK;>BU#"A<@(4'EGC(.H/.\=]44 M&H'7=L);/1:6G>)@X.UBO6=DDJI'0MNX58I#AH%H5[5#NZP5E'<&K2E/G\HE M&5Z>:1,H%>G_Y1*,NV^HBVP(@[#X[%H9EMVS6G$SD2@=,@B!%J<= DL!A[*/ M7Y6A5#U.+TQH5;%VB6D\-;TN:U2;=9N>J_+0P[VG)697# ]<*1BX)?V/I#W( MP'3OC62D-OE#F:?:K!M8>G;*'0S3=AN>6K4?S[XJSYQ-MIY4!\4M[U4&J#\7 M,CB I+#OBD-JP2"W<)$*Y1YY;D3M%.^DOS/ 1M4!K0:G,%7A-;?\HD1V('*Z M+#0HFB3'[[=^KR O]\6B+J;U9IX!E?0BO@E?]C-R41K3D!ZE:*I+U?578+P& M\WP9+:DG72Z]TN1*V]'8J&N(Z7DC]_G!W:8,^0%/DKU>I=CM[I/8BM]9W[VJ M_I- "%=QPX3'4O.2 M&UCXIQ&5,J< JHT^V-42<$$L/(??R!/3\:)*JW[@ZQ M/BTDA^7MT!2GU=CM<)-8'F:/<6,JD8'53,\7">:P)5Y69YN/().02$5CG[V] M]=T-AWS48W5)22@%6$G$OU63N3?M_HCBT:X:P(J$#L7NB&YK.>EA:/^$+G8Z MVQ,=NL53N^ZF9/^N"JAC2U1,F_N3$G-N=Y!!9A1JH-#(5]VVWQ5+S%,OEN"A M#^A(77 M= R79*<#]#+<9XYWWA2) 312:)!B6<$GD3ZQ*$&&LCK4KKN]:),= M;]X6*?*B[:W(:O7J)K_=RE.]R6QKFA56<.S62LS+;G02UL&S=$^2_>Z']C,GL7=C-X%@'8F M39Y3U+Z0)1USA/#]ME1Q8&,&H4DH9GYAI& M#U2XLJH)&&9UX60VXL,@_)=TEL M387%X%:)GPEH=I-KUNS5$XLZWF:LL]MQ:B>7$9JUH)AHT-6/&KX$SZ"R^]QU ME#0M=ZV0 .&@Y-G!Z'L)]^;JUQ%0BV?WU(DPE-+Z-E>M,624LTZI=^YNS:?! MJ[YOISY.?+1=QP8O30] \C20^ER M@'( 47FJ+QE$ V=7$^0AE)4 .O5)=]5'FD"LFFY MPH^)I^0I991.+8G(HL]&]9.Y,X41 ;J"M]XT2U6N:??TH'KLN%^#NEC$,^WCE);>W2"M4O)8IR\V'7B4-U<[RM@>_S<'DO,8+:!KT4> MS+WP9*'[+A5.L4-]A[=!_+2M1Q)LU?Q%T]:%<]F?:P&D#)@>9_?H\ATN35$T M&.?[=3+WA)(+X<-(?8=<()[PD16A5VB'ND_)=K[#LTB"O9$K,IO 4R,]0U$- MNY-#N?@8!:X^:V .<_*N&9PZ-+8)<^6, \O30@T":6] M7,]J#&5P)*G>.\'1VN5A&&Q"DW/"1?$D.F4%2ZAW>V66E!^/G:EW6*OFQ:"9 M^J?':]>!4;<9%KJ'A4D1_>0>\DWVW^W<3O*]D[L3YP+,'EW'BS5[*PQPZU]( M^DEV*ZGKKPK/W&HN/A5K$A#_Y5GQ*7VX,=OL0U9HVF-M3;HII:_B(1N%A)21 M6$8J^C@1\'4@=#F!K=U 89"2.Q=.FJ4*I".(G-61.VOJ4!.$V3LH('HC4=9$ M_99T)%^RATS*;7]$]B 0^T\#$T$>;N^J'=>V5#VTS@,GLX!5@'.O(!$:&1,C MK)*3JB!4P'O8LK02I:RT=*BK1;-0"DOFU1Z.]:A;[]"@3&N?2,Q6U7B?-\!/ MP3F;NRU$W,#LWE67[.21[[0CZ\F+/ 7(/Y?P<%[M>Y*F^"HE?A=;;NJ0(^N@ M'\0I2Y"Q$7@4B";[SGT21L%,39&8QP5@CSKX3^ZYT([X.$ UNSJWIU+*U7$@ M\]LV!X#>NMWON[.:8GA?0J8$]3AYJ,IDCZOH: 6PF],:7ZOS:LV:%%6SYI$9- M_A,)>387DY88NCO]R4",Z/C<(G_)VI^2Q)[[X#*))Y[<:>%-1 J";P7O5,\* M[9Y2I(,L+QO4W4&362YB.:U/I J<4U$QA4$/(]QT%Y45KR032>54-49;+O'M M[J;CL8%3>> Y2\+G-Z5Z9=]Y*(,(-3/HVEH5S[G+$ND@S5+G5*,?]:"U!M,[ MV0$9-EG\S+L3$*ZSN6<;X)L#O,(@)/,.2(YZ5I$VOK_J!R5K>GAH(R'#4Y2F MT/O9MF+#Y*6S$L7JK0_C=;NUO78U'S&W-(-K67KNBXXE'7S:&Z&&O^$(]"<2 M263T;#NO=I'!->X9VQFUI2A+K:=JRC-OH[P03YI:=L6I'BJ3(YY+UFFX \5R M6J9C@DE"J:KT<:?$DSSE=M]RL!,>\]T>M13E>'B,E+9&Y6C?!.#,[%*U&053 M:6L]=TG9AZ+J4G@5'E5::5&+F/=R;B;I9F=4 :JLY$>U9R8)BXK15]5<*4"7WEGQ6SQLH*:Q-V7JTG$4PME)!M5CA0K% M?@G-J8]GB9-VC[-.147D0;GM0@0(DJJD-9-%E:>NFO[>NR:[SQUL *%X(3NI M^23#45T_DH@>"_TSJ_80V<3@CK$T+_ H-\[@=3N;*>68]VK$V/&P+,5[WB@I M&=G'WG.I4LH82PY,:MJ>ROA&-W=9-JQ40/%#1%$'S7X+^\955#A8R$P(I\;0 MJQ7TGH(\76;4D.4=5:=@*L?'$R-5IU-^)H6W1F5D[\*TYZ^(R7HH:JQ]['F; M9TO6G#PTDML.A!*-ZW@UDH%;Q;H[N%F MF9BGYTP@KL>K3\6>O7K(J)P:()#2Y(XPP13[S3JU40;HBZ.U#P7\MHCT@.;( M9(I,H@=3H,^J%S5%J &_;)2ZKF,>_$TL?VUF-80I-?X]GFOITC'-:I MNE.J%VXE ,8H1-?$PS2VV]5EQZKY5F8XP)6X7S4;B3I5_+_ZO^W__X#_3WS MEU^_O/_TP\=OWG_ZIVW;_NS/QK=?S8_?_L"_72^__?"M__X7[^Z_^H=_H%S\ ML__N;__^S_M7'W_]XMM_'GX5_O5'[\*O=HK3/_NS^]/+^Q\^?/SV>?_#RU^\ M"V3W=_V[3^]B>1?VO\B1_^=+WMT?O_O#IP^__=T/[_[=_>_]K?JN?_/RZ<.7 M[[]]]U?O?_C=RS=\R)?OOW[W]Q^__/#RPQ]^]>Y=__KK=W_GGWS_[N]>OG_Y M],\O7_UJVT)X]]6'+W]X]VNO=?O"R_K+;W_S\5W]_/97/W[WKS_ZYY=/WW-= M[_[=NM)__X[K_.KCMU__X=U7+[_9OOCKCWS?"U?S__C"_L1U_?S#YX]??_W7 M[[_QX]=@_>+G[[_Y\/4?_O@;'[_Y[L_>_?#IQ]? MUMLOWW[U\VM@Y-85?/''![K>_=OW'[[]X1_^\-V_?9R_MEZ'U]>,RZZ_AG??'?O__FF_>^_\>W MXKLOGI>O?WC[5GKWQ3_\[N4G;^5W7_R']]_\^JNW[QWOOOA/']Z\+N^^^-NW MK^N[+_[^PV]_\F7GNR_^\;OO/WS-1'I]L_%WOWOSAW7GC>_?OL$%_O_/;[[P9+#? M?\G\?/,6]_;E^T]O!^3DWG[]Z>4G?\B=??/^RY_^&K?URK77W__YGUNY?V;KVCWK[G\C]]__?[[W[UYC^OO MX\UK'\S;UUSYW_S\;[CT?_[P_8=?,SS?O?_R[3=P U]]>/G$?QD7I:?S\KZRSEY_G1&MI_-Q_T7TS'\B=D8_^1D3/\W M/=[ M[OSUW?;'+_J<)?]MPG(WW[W_]/+MUR^_>?-N^..[/_ME9];W?L3W__3Z)C?U MW=<_O@YP]EE\?+N2,O?SNS]\][N7UWO)95WXAX^O5YBYEY\.9.9._LO+IX^O M;W 3'[]]'="#J__A7UY_?G#=/_SNT\N;W^"2?_/QQ]<1.[C9BOV?^O5XK*>^+EY\,Q,&E?OOA[86_*U@[.7UHDMZ78VO;YJ)7J_)K-A?7W'-U^LKKO=^?<7% M/J^ON-#7Z6P*G*^O3-NOK[BR_^'U%=?TEZ^ON)C_\?45U_(_O;[B6O[#ZRNN MY:]>7W$M?_WZBFOYF]=@:#I^?<6U_,^OK[B6OWM]Q;7\_>LKKN4?7E]Q+?_X M^HIK^5]>7W$M__'U%=?RGUY?<2W_ZVLDYEK^M]=7*TB]__*?7G[XR;HQ3?V: MMW\ZC4U6?_SMGZXGL];[[[_\\.'+#Y^^_/$U*)BY?@13??K^RX^?7B=9^UEUKC'G[]^HI[^/)-^A NO'GIW'OSTJ7RYB57_2;%[USKF^2Z8E5_5ZL\&L]B:_F-(^OGG)5;W);2N-O7G)57UZ M\]*U^^8E5_7#FY=G7;Z)U,"6MW_OI/ @K)SD1?OCP]5=O'HG)Z1= )9BC_C2P,;R\ MOO7+0N&Z/O[^O_YY?O?GD11325WGOO^WG_[:/W[[@4CSEP^Q==>.;+W[Y8^? M2 8_K-*,$N1?7__F T#BY>7W+U]NV[DKH:#UUKC=9P?,[R#UV2_5VDZ;:N]> M3RFW'@BI,C[*G23KCJ$[DJ23^]K=]=ONFO1]/>3FU#MZ_'0$;?>F[:;]GM>< M]ZTTL(*$*M9X5+2L$N_1/2>SIZ/%,]>^S5UCA+SG,172S]>NMT!KBHBU1P_) MLKOO>S4^5Y&E:/^L8IN'RCT:";@G_]A^N-5\UK;H5T=0WI=;L]-$/T:<]7*XI&N($I8^2T,[IH3B ' M?E>^(,O7&;V.M.M<7HMM/LPM,W)-I6.&(G3[>4_-C>[S MSJ=>FTW;F'[OGAGG,;2:UN97L3BUGWH?FPJMRZW,=N7@MEP^)-MTY<_M/9!G M=A]GU*5$0DVI2PNE3UL7&X])#GUXAK0@FZEX1'E/Z5;Q/1;E?G(^QEU2YVN+ M/85J1VJNG+/\9-VI'3:[-Z2T:-1>QG-OVIL_^]/+W7C,+)ZV <]C1&G/6ZNRI !)?]W@(EZ3GGUL*(X4[[K>]5F6IL=P:]WA,VY2> M\=CTD+0T:U3$>!PII%N5YW$W.P/'+7-D]#UM_;AKSI\MI#W1MH_FEI!\5KN, MI:$I290\(FF'#>^GC.Y'NS65F_=SO]HCZRV%+<5&C*D>7YV=VU\NO$R5HBU= M3YXS'\S(<"B:WN^N9KP^2'D_&:CS6@TPK%%;&K:#/[%I@*%:JH8:H;(*/*!M MI9_GW8XG!1OAGI27OHO=&TST4VU0-_Z5MP\$GZRN_GVK4L!RS$%AL"IS7XJZ M>_-W2E67=NFLE]($N&N]I1S*"(T]&OK2?48 M^QD#MT)HF^48\V)F[>HRJ#8;U9!*>>][3=R%IW.G(A:S*3#IL5#R#( U>.F< M<>YMG'W:BWM'CQVO-@.#G7A$K*IF/YJ4QJ?_JYACZ9)6^=#H)K5RS"W>L]B% M]Q0B7S^F'T?@5@)!DSRFYJ/CDWK:AYZJLUR2O>+43KCR27/)S&O='0>/=H:D M5T%NZOD?NR)/-NG5WL)R.N=_]A2:/@M'FM+1[8:^T]SF<]@MW8_GB<1Z.ZITQ&R):IP=AC/9)G=0FDJ;B7UXH&732!/WG7!>VS 9D8JH'?H0JRE:50?H01FSD:,(A*L1U927-'B MR<2;1K \:K"EV/YU;6#VMCJW=UW$F-6QDBK3Y\6I,%*^MO-^^/"A?0+S?L^J M^RH=95=&5PUP\K598]!>%!/MIX:"73LZA9B".LE$.QGC<6N*+JDB-">1[RP\ M::Y!>^O[NG4,U*Y'US_/HV42$EFZ9JV'BF8[4W0NY6*)8)M"K^OT\RIC]Q0L M)2(42=F3*=*:C:)R[B3C,&T;ST]"[7A*+&78"DN4D(67E%@B5-_[?:M/:@=/ M,C#.,ICEGB$IBW+>Y)]*JAD$GTNM3\EG65&6-+3HDYU5N!-N<_DE2FB=GO+W MYYY!"VC-1\-EZOBC8($2T@("5N>^SI\]C#:.%Y;RJ=_:-CN+0O43E2NGCK%V M#^@%KIKT3NBY-,LX9*''='I0YF&H@LD29TO5R_8()+M:-X#*D2X'("F%F:[K MY D:PZ?"L!ZF,9'M?K*#X(I#7CX P0[N4S'G>6A^9@O#N?&853&)ZCW4?>GU M9^7_IL)PK*\<"TGWEN,X=24*$B94,^6ZNPJO/>YRZQ/388L@N19M< Z:P-XN M )TL+DG@04,)LA'HPG;<9W@PUY>Z4"2]9:ZL78JAM*I\^L;P4@.04O)^J>9J MA^B0)VP#UJZ14RFJA>H_SF?+BI^>R\X]J&R<)VE)!QS;(;;!A(MR%G?9)5*! M^54]U_NM]_M!J#B!G390Z'],3 K/(^67E,$:57O.J<5\//(VI:%J= YFD#@Y MP:W+9,;#\:!2YQZ?Y;Q+%E@"!%+TYW*6(0&H>'MJ4I<)=MM#X$NWWN?[D]JR M@+*#PC[_,4[)661>1::?^[!C9_5*RS4]Y"OL'406Y9%I8+OI? -B(ZB:?Y,& MQ$ KN]6P,0>Z9UE<4DHNO4U39]=PZ-N9?9C*O8LO2KE96PP+U(7OZ!1\MX] M][X/D+']/_8XRCO*34&PUKE;/9>U--T/3?'4HK4YYU9PY]B40YJ/$+;9]+?\ M<$ $Z;1CE]$DDDV6<0:L*(ET[1*<0+^R$T^>O<*>ZG2$JKV3)HJ$5>"R'$)^ M2U4=!D*REV9;.2MNMLO@ 3I(J+S$)(X! 9TEOB7H/?+N8$9]V*[([AH:E34 M+$Z26M::GFO:PWI0) U0HA.*8GPLCT[X2,XV902BXO:U;8_D#QUWE"!7MT1= M#J(?B%4S0+46[")=?A]1VOHI[1.$H:80X8PD"O3GV9+WMTMB'&-@C7$-NYQ8 M(G; )>S1^*/HHVA,'9+_W+H,#1TN&_JIQTD:CZ>!%1:VDZK&1FTO%-+KK9B M4DCF0_O6"E#;B:?JP-G0-,,9I"W9 3.6*+!M^9(VM (JV\XC(9^2=5TX/GMA MPGE;#NV+!6B11F*VW'B.KK%BL&])'?"+HJ,3TQNAG^)8":D-,W)22?E><)45$)Z$NV MM5T'-=KR%R2"W%H/W.!"T*5-ZE)D)$9TM06<1?JE'DR-10#C%_50Y6D(&>V3 MC38::ANBSL@>U$=JO3!S];92 X;Y1K4" J&6R_:^V8J<6:&S$62/S[ *7M38T'6%HNRZ,<U#>Y#'7@J>*7-& M&7RYJ9UB&N13] O**L\S\Y=_FI;W*C[;W9A4K][;)@JL3;I9MX=FM1,!+_7] ME>DRF,^M1.$WKFDGR-/<;= 2BFF N%9R21"8E%R^M MO6VH5CY0$C^/^334<]UJ;YI$59G9"]?7Y7,7:G0%?$ES6(;-[B,!+P9(&$GIBECZ5?49V-]2*AD[2=%^=0FT[ECR@;2ON2J MFL/=DD8?"P*2$.N>OU*X2:OL&+8=(%DZE'W6]?K-QW53?;Y'.HV M!XE&]HT=&C-IO?CLA?#*;!/!,+>/!*XF20;;A'4"BL!>3$E^++N*E"12,<9A4S+M#RPQ%70D0HEV* -(F"4J$%L;C];.'1ZFCI7 MD:/XE8/ H+:%[H<6Y;&H8FX+T;(L/32RM*_QW!4UCLN-6B=C36.CQ?$A,Q^X MI%[JS6K14XX*KV6AT)&,] 25L_?:U">6H'M06UBS\U)L0"XW MLYZ2:@I@0=.Y2Q%*O>[@5NNN!&W5TBDY5I+[V2J;@<<&Q; M)(DO(? FY@NI"9 B [9K5@.BM9V+04MJ8FS7Z=,(-A8?X798[:"1BM[<;VE: M;38*'D!-FTMN2Z$ -:^+(401"KL* HEJ)SCJDJY"YM1)F,G!AX*S6=RGLF*: M0TF:)!!57< I*9J=(KJZ'#JQZE=,C>_^S::;NSJKBO.[I6)PR(K [H4+UIN% M9:CH2549E?C&1S:;N9(,9LI676XR=2F%\0;4X-=L+1HJ@$R8GG6BR9 M"7(V?\CA+STJDD,T/94)<)TP^%6-2#[XV @(CYQMH(G^3:H.++-Q2G >!+7T M;M*X;,O=J6^KXK>!^I/"*BC.QN)*1$K"HN(")$)NBX3^\!6'.R2Z$ ]=IE2< MI+"Z2NG]6!V-"E%7BX1R$'BHI\-@#1"E*< /SS+:_UNUK6L4!_Z*BN3NY1I6R MEF>,3W7#O^JU(UBEQC3 KR2V.CGJ8"@W^^^8>+=5[=3)HTW*0\>UJULQ+;Q6"U>/T M*BK$W&[Q,,'-9:32VTFGC K":FFND1=6Y\B+KGUT0AV:]YWT&Y" 9GS M9OCT%&ZGS'LM EWST>TA=3G=_&AWWI9CL@W3#^M,#F@%;RMH=SY1QQXRC(JW M2DT^8I?2/?1PPZ+?>M6.IX M":"@$0]'E,N_;!Q27YD8*: GF>G#M%%9L33L"%M:< = V98Z]3.H8P 8N\(" MJ\>>7S%75GZA Z7E1MNZK*#<^6A0M@T[G9D2E"*W?5%\C2W3!_"/2Y"22TJ@ MUJK%GF4MTDC2<9F%/'=P/T,X>TGQCYNJNBHGZ ^4;#:\%974@>;9'V5\\F%W M:2((=B N2- &=I+DJ=Q+!M!;8#)5P06;C'C]QO1XO0BU1FB6/#EW5WV/@HH/ M<6*KCT?V'[>>-RH0,O_#TE9;0JX/SV(C4#/VP1:1(--7%]UL^W,"6I#?4VFW MNCQ[^D>K!1O(& NBAAOZU*"W&H+Y'B+_SI MV"F3]1DM87E9Z[_#=%9"ZC[;HC\KF#FIT5OK9NNL4V4]A>NLKGBJ<)GM5ZFV M@M_ZY8H?YUF#FZ4M2_:W,MZ'SJ^[N^\;^-VX2#26FQ]Y2ER:$N6RJ:E1U^EG53F&[![*:]72L33G?I' ?>\5 8]C>/7FCID)%*-*58G M#I#JT M67<9#',%(,W5YY(#RF M*#E93Z(HVZ:6LCZ?>ZM ?JK5SZ3DROICP4Y=FU:I?[DA-96"5HLC9VI$331O M9:?UECC61NA4J^4@>U%\>QP!<#Z>9_,7E6;3ZH,(J^7(0ZULVO-LQA5,PCF? M[!&-<"&IT,_Z9Z';5#L+,8RUJL+P1@Y\;+!MAO:F:0NA7M6+1BE5M 35C9-R MUMZVEHX)!C4I)ZU#EV@@-T)ZWF>Y-A8>$(65M5.%[YH+12(1EW:ZM[SZJU@# M]K 3^(GZ'F=UQOG6UU,E%6.T,(>QW<8([K,QG5B3YCEC0--U%7P JCK U " M-76SBX6W%1E5+!0DUUA8:E/8<46DW?G[=*J49M7"/ZP>#YU*"]@X*S2]1Z>+ M^N'.=_'EJ(GZG2N**D[J-U]9"&!:GB]13BEW>[E.]Q/)P22R7?UPHD=4AYX: MC/Q,:*3.!9JPPH# X=)\++@CP[\T5H"6-4UKU\H45%>C:0"AISK71-A70?9\ MW-%I =Q%-M!7:31UD%7_4*I ]$ @Y,.B:"K-SN4 TVNVI9P1GV[5Z_ZL^&,A M8($_=,G,6LYJQ:O#0 ]:N2;,O3)^OC #!A1:X>4\]: MW2U89V:GO=_I8DPN&S04./&PX#ZWZ;XX:R=;;O6@I.R^:OI#!:,+&-5C6=)@ MPR:9%6-Z:PVA<]_>0_O%>SRN>TH M3^UV'_?%ZMJ2(!'?JJ(/!?F!65OEJ;$H/>7N23E+:OU6U3D$ _?[\E!OM_LY M99T&!X4>107/+I;5[DBQZDD;8WS/K025LHOT 0\0#GTF->O.R\+9;C^/ZMPO M2+:*/6):UH.H2V%67:@(3*2/KHF2:B >'2?F;.:Q\8.IE==R_/#H1#^. EYY MF#OGT'6-Q]KLS0%7%U5H@0XG*X0'4"R4-(^<4=UP:F!SF66%5 MZ7EXC'O:6WU<*A(](#'[]8O)^0'?;O[-PVC>^Z7J"+")826[@F?T"0=%*E8U MM8-FQ.TL?A[JIJ,I/T!143RO5+*2V]LK3^2M27TFOM\Z0NF9 MI1*9$E)GIFA2OVM*86"]"S>3U0#U)M'GT,ML5;8+A=HVG1+0; JJF>_-]L"E MI*4F'U4<""P1.2/8A7RE3S3#0$$=49*9?;5LG=TU/'HJ=5M2?_)8RX@0#!K@;RIQY/R3H"<>[/YU^T^6]74#5(9?9$4XJ,3*5.-A.T^ M1-6X3Y6C.(H;?5F;.G-MHT)H))!T;I;&;F&I3)I)-;F2VK+27@83S6@(? 4T M ):RBSTWEB0Y^>.!OC(=\EGXK0@)U.E19O+2ZM IBX7;N6 MI(8)7^%$?TZ%SMT&$/\!S6SC]2S"7?=9#\:"%7?JC.=) '.SZU7&XU(Z"[0" MU.*1LW09?.*>6P,G9=U5B(!QIY;6^/793DH<*GU2&X':)*M_.5B9E:2AB&<- M2P/QH,8[]<$&]TSY0SPVRK'=;3\KO > MYW9_=+[,=SHDF%?*7/(=/$L RQ6 M5+C5JV%M'FZ_ R:30BR,&6F&^\E)IYK6[HW?=R4K/%5[$].JEL1H9!!=%UMN:AJT(4Y>O4 M)8L"3F0A#$IS/><\ZCNUD,RV 3+.*K;5M@57<+2T\-QL[EJL.,*>G5TD6OY) MQI;CH4R/JMCJL!5E"CR>ZN8BM! 95U461 M\\&X79X %AL;BUO3J@2U#J#BTL_EH[.!=VJO3YLJ&_$TJ/JI,;+4I<,F1M4! M_/YGJEF1[7;>U1A[U.YM^I]I!4*68C V*E4W04^6)^&#;&!_^CKFZX\MP#I; M<4GNA;2L,+5E,(C 8W8SI@I<8!4B*<6KS8Y ["@%3E]?Y?H%CZHU-JJ FMWY M+01,3WF9AJ 'H:ABK/?:1]#LS&[F^]H\;2I:+W*QP:(51E3?+S6YWMSC) B/* M#GK2T-E4=TYK"3NV[Z/RGS)TJ+D\$>NJ\=SZQT:A+,NE6BB$Q^,L@AYE 3#L MX1=8=]H5=:L;-SQV#[XTH666YPP.V%3:B,. '*/W=-BJK\U>6\M";5\8.8J6\AEPM^-:1M-5$5H% ME6YW\V\J,&U% @.V;/2(6H"M(?DQ;O(BM44-2R)NZ",3P3 @S3U2@39/V6-J MLEJYQ:[(E@01'MA-NJJV91,FJ$[NP?P[EA+" M#I!GA"2ISJ;,[1X1&*F#0PY T"1@SXK*P^>]=N9'" M>B,@>' @A6VX!:'G(@EKRFBPU#L.GJ9N(+KGEEVAX*-<4>]892RT?0%H[S.S M%@^KDU,#EB15KX]#8?Q"/"O)8T(/;N>FD(*'1]WG= SRQC6MFUMW)^G1+N-1 M=.*1^@-*)$#>'I7R0%QE^^?@.BNK+VQ\@#Z<-2DL![K1@X6*ZZE:F@!H]$I3 MOS.K):8-X*4H1=8@1W)2_2S8?VM%PCP3E:F>*M0F2Q;NEF5UM% \@*(JW=7^ MDRS053 TB*H+G-8.$+&4N1RT2@)\42*ZK\NC<9]E,K AW'H9%.*#@R6!3]^' MW-99>5=VC204-(49X%<*"%;^ <8[,Y"*9[,&L%/7325R0A[R/P*K@:7!3 (R M,P&U6PI\]US*>FD^GG5&53'4'N*&]XU_DDZN[K.7E0(V(3%V[R3_#\F"0_V$&33(!$=5)>2 M$6= MPBQ"UR===ZN6FGR7<#Z:BRO!%,DW][&IDT_E^Y#XJ3RXD*,:$WC(9)^#^R.E M,G;DSU,)Q'V15U5DU@RIB#0 )KI_4<9N"HE2#_GPGX.AXVXR29#QF6"]"711 M37775?ZYJ5?<%ZJ4#D.M+L"5O"ZB@^(_YY:=X\Y5JNS%][Q R0I\ ]N7M:CJ M.4GU%!'^I10EA1ZK3\K?*?]][D97DJV"E >Y+;E^Y&81;ZMN M?5R/VP;.VDEJ5-1?$F-_3"J4ID2*WT2$K29MQX#LZ*(:5$9 MK"PF5: E*$S.](M#75VW4-WTS9W'LQ&2W"V:%G\E$>1BY9'I3:K$%*7-E#^D M'JW6D^!9 NNMSJH&[;-3=/OL@KKY85,;!0BDD7PI6G;9=\Y#2J3^:RHGTGJC MYF/2.&N*R2%0U5AIA,4P9EE<0LA2T5_>,SY>:LG4*%RA*16(J%M,;: MI,-1&1*JHP),JOIX\D[E$M3BO*GY9B)L%VI>Q7G!.+(U'F#4_CS:QZKFOLAPSWMC%9A\^L4 *!)>M .2@^S:J8\JD'*- MHV=9XR3$7> >GUCVW(PD$*A>*01;4K%,5MUR6'0'#(2]5E5J']\C%WCUF"FWPI3<1S=G2+[*8)'1BH^><) N"H,MWM' M]TKFNR*-2?6W3")7!%P]MN#>"-\&.#!F&@+= U"$(7Z MHZ_]K=:UQ"_@N\=0##V%X;!R&^$GWCQ]Y]=8%0.$>@\ZJA1UIYR](! M+"+/RJB5FM*Y7.>=W41\EG(P4UI>D6X<^NU*]N9Q'DH$WFZ2)."6;LED]Z3@ M6?8(]"H5K %./1[EFDZ@#?.5!ZJF&RELT^K YRR]P#-_">V5(',(-CP63>D2 M^CV:RTX-Z_GG+E%407:@.,D7*%:(QFU3PTH+4K(&#V9D'H:>=''RA&,\N<5 M,#_5C&;M6[]0[3 4X5*)3,$OIJA2T$22C1EI^>'^YK*()!@N;[Y#E4[_RA-[ M@"%I!UQZ*(.:;N5MGD/?[+V+^%4K291&0=5HE:.L=IQV&2Y3":+M5>#J7RJ\<*@H>R!L4\T_FH*V]=BE02^-/L6>^TC$U;@(Q.IE M4SCHH!,U=*ZD%Z42&0ZJO.S1#QD]$>();MV6'&#_K<8[Q17IY4E4/UKO,A.L MIM2_WW51(\D>/#/YU"0'E>6E*O TW>",+/JHQTE?'AO LWKH_W;IVL/29CII M!<:CY-.26PCS./4BDS#@GCY5;[O;L:F&S%A92$MF$(\UHQ+Q12:$Q!\"B824 MVTTXUZB;CKM'^*2H1T.SL:Q$KKIY-*"?D]K(*L2Y,7;<:Q=B610I]LA#5+)7 M4*5#,"LR%,]$[(/A#[G*KC\1]:9V"40VGK9F*]0P;F^L:FK9#LDW\ !L:6KI M 6>1"WKN_RX2$\6.O49E&W49NY@'$UVI9#MI?FS#*O M5L)Z+;'RNCT6Q9,MBQ6;G_(FHY? YG;8,S01IT8C BT'T]V2MC95>56JBEEG MLWL)$Z[M4>7$TZ7J(Q@R<67W87]#U5,I^(NG+JZAJ<).(:M/,YE)5^OSIH+4 M6(,UH6HZ<>M,#?1YU: 10^]SFYHJ\2287H3Z6P?J2&[:M4JX](:ONVKCP!ER MOJPYSU^;/J:JLU';/^[WJ1%49,5> MMKV G>3L-ME3/:P.CLNP#AH@V&\J,I/(B[ILMT>*^>F0G"WU%4]STJ) M;H7>7!$#'#P"SQIY/3P>N1CY9FKL\M=W:MX=;"\6/BFGKN=2YE8S3Q+&5--5 M&\PX;9\IPANU$Z?UCUK3ND"%XFV2,?=%.^&S0-G*T6M2\2P%>GW*<@3M\/R; MS23M:%I$W)=HAJ2\5ZJ]6+4U>S:F(X'%!".T.[13IMXKASXMTAJZU4UB(W74^B[J#HB=(]-TO3XG**8TW;F&ZR\'C-Q'RE58D5IA%N$L>5A[&7S0=?-L=@5[VXW/UWVYT+RT4U0:"5WO&&X%TS'Y#?!7*X37^$&>+@(D<%>S*H"*FD M*!K7SG8P(9;B/@[7N,QMRI(/UU:)QZBY4]2#S!-L_IG9];+)$LFM96HV&8@>MMH1S,SQ^V>0H$%.$PA$A>XJ$/_Q M %.P12D5O4W0-^5JV=R@M1N2B4UA;^E0!;0$L.=4W%WZKZ44.8'LK+:R:98% M1E6BN#HY;3BLLE$!R/V:W)@?(G-Q1/7&K?;MH).2XI[C\$3I<5\>W$#5PXP- MUW!?S>/U8]F55>*9&-#-++4B(QAF@$Z,2[+_+TI;)EM1++Y0X_&N_9TD\*FN M*5-#*X5EA,8D;UL+%P^-:2E]EYSGL8\5$\N8&%U!UY2 2GFS-#3ZTW9^A(,J MP)^1230PI4!E#MJY$-UR+DO[.I,P6\E4R("A(!V %Y1'_ Q/V1V_83X +/ M"1BDHJL0'B#41]WL7#IULR2\ #//W>IE4@=,TN=&J+P_;98;)0=ZK MW395X?CE7$0EK WBL5\V<1G)[#*61:7'FFR>=%[F>B::_/(,]J"><.]6@5M] MSDAT2T]>_YOM(._?T6U*XA\0\M2@=^PV&6F"QDPY]&ES"5:W5H:%3+QXOM/] ME@(T70^A6CMUONKVD/+H(.&I.15?-X_[(57*7CRHY MG])S>@@LTS5=7%FPF77W7/&B3+A9X>"*P\W=IS>4?2"_V$LGCE]1&Q#];0E:]=1[IMX: MXDZ#OT8<)?.@+WMWDC:')%JGVY[<;2=K$-:LV^/R/M(9!]!+="0@LN[U_W9K M5@%1\(NBM]1J)%]JIUUJ?*NAKF+3W6KYO)/ 1:5,3#IU.&R:$AT:@^S'T%_S M6!;#?+_DO,FM,#:;4I5/U16(R7+K$'SR7/C>+JUR!^B(GLB.+ ?%6UT/3[*_ M&H!Z+57V9(7.?#@W2C:+$F;.TAVW*=B]SV<2N+.58'RJ.S'[JU!B[8EUB ZN_6R[N] MXS;=9GD7@+==.N?4",V?,DZS:3CXV'%8@(Y6[S9>J_!)0%2Y=U^>C5-VU" E M++O$RN_I8QRVVTVGX?$ 68:*@M)0??>;\9Z+9)7=Y=4ORN/I>BN";C@B:TV M&F 9 &A5RX!NU#TWTU,F&&M1V_:\=WV;;^L?-]$H^(K>TCDK"4 )S9UDC;R4 MN=A#6SXBMA(?6LK/[=7(SDT2*?"RG]S, M[2Z.4LVGM70LD1"DUCA7M5-_/SL%=Z[-';$&BB2OJ<_.@FO[5-%6D^,CG1*0 M*13T+-1P4BEK\J#RM+8(MV931Y2H$#Q(H[H!-5!5NH=\!VOH)-.:TE?C$;>< M3A?DFLE-Y K /BD1\^J"TT/#$S5EBJ5P[LI@2U5Y%%'N4JUVF>" ::Z]AN/6 MX-RGJO_IO3P)-ZE&@>DP2[ZZU.U*\7,95EJ M)5,.CU. F5ML=6WNE.6K)5]\5XU!:ZQ!O\#0?36$D52^-"R[8AFCWK[70 ..1U_CBX/[K;ADLA54*2>M'M.5FW8!DQ#97U0=FC)KJZ M!,_:6],X7'V3Q3JNBNGHT,S< 2O<[LK5J(WRZM6SD=Y& MINUP+Z2I:C,]=]>A$^!J(PMXGG*-%:)_V F88#&!TOA#D\/R'WHL1]P!,QD5 M]S7TTS@$5?E@D%CH3QF9\4@=S9-,E,RK1*T#OTL9;MD^S(UG11(ZIP@%^8?/L& M5@'9/1X*)BT%0!+ 2 5_@-IN%BM5'CV6+VXC4S$>7!H/YO*4-2U*ZDX @"0 MA \KOM4JF*?9.)N@ MYU'H@OJ5(K;K 4O<4[,(7*C#B*U$X7&7[;"-F&5]R(:=I]NXQ^K%4?:E@QP/ MC;W4J (YZ'J6F+7]X/ZEM89IZY9F2BN8V!UF'*5769LJ>( M,C"G[&6**T*M7131L?.,*\ZL$P_?K8827\:J4G2%\&*>JXWR^7&S.KKG)*0* M9$+/J9L-Y N6%?+L?-8NASI+Z6 5N(=]Y+4=DF[SI89/8 IW)[5*X,,WMX5" MUMFT7\6^<96A;/4[W9:,:_+:'UT_M]F0^MR3LAQR1L79S/E%S"3 1.RVED/HTKH 1N7;5)W=KUA M"P/$2B/J5\_H4V+MG;%K(4@TLUU1VA*E?)0)ZG91BZ[4OGN2>MD?ONB0$D]"%L$RAYA*1YHPGMNBYDV'PDAN M&)MI%1!CEC;/_GF U%Z:(@S)=^.TJUT.J@<_G0EK+SYIS@8;P![#'X/$+M:# M[?5@C]9SKI(TJ>DI6T[+5ING8VA)4S)&/ =Y\833-=O3)#MZ]!W E&I>P!C M=6]XOUC%>8G-\)A7F[CQ/%'YDBL9*-;BH&CWU,]&X5L*KB32&4EUQ7*M'S;E M)\U127G2VJ4\A!FD"%6Q/XMQ*A*0;"W27\ ^EOWDDNL;A*PN+.P-\!;_=S*N1J3 M"!K)@XSS87T=DL?T5927T ^+@'8R:Q9$R-G@WK MRE64IEU!)Q(MPZA^\N0(;TT'E:GE'#B2@;UM83CTY)D$>.K+[8Z+W7_ILW!0 M;9='JMF'&-6-T;-[*'ATL&QK74O (&-R#/>DP?,WT#U(REP/AL^: M3]*)6E\,T!PI=ER2$.(-+ -O\50/=^)>[(+/ M0[_02BHBM?)G7?DTX/E.;)@VV_.+06FT8,<90:-JY 0U,J'A;,=4@2NY\S4 M#W?0(I1R@;+^UL7[%'1>=O^L"]FU5 /@+*!.ZICIT,E.\W:/%^NF=!KPC#Q'"QG(*G6$XJN>!7#UA\]?*0SV@5.1@(^ ML3"Y.#T("\M RY/;'F:;0A5@X[\QN?G*/ZA6F\1( [B^/W8P [.CF^"3/%$> MT"Q0?NJ)9MN'Y*ECM>2Z[UNM:]=19])NA;'O,M49 -;I=#D-[=IM>PGDZ."& M7,P\TJ&&6P7_VO<#CF58"7CD[>O4:*HU!I[9PATN_Z.@_?9V,P>U?+=YX'%; MU 8SN^F8B.!OOB-ZSN,ACDY:AYWX%/1K]ZXH'U*U,-;I^O1X;=BYZ&$V*^G0 M;9EU,J2_GV2O(R3"TI C-CW[]1HO>[ZG\H<>6-BKR<.WGU@]1YO$CK(V:3H# M6[C9IDPB08Y(0F:0'YH FWJGC=Z!I@\KY+0XB5'3)R;RY7SN,A290X;U[5%D")1G?Q1KE,C@ M/A0W%HA>6F#Q8 HQ2+9G47;KWE-G=A!&#U)?ME]E&27%>FWJ-Z:L$?E)KM@I MY8-=P\M>TD$^-&_+]F7J-=U(15&9-QN>@QIMW3G2[8$A!)&[W-P"J 2NWL23 MU[ZN)-=;=@HE&(_/BIWQ?X9<5YN#=Y45B8['>8"[N16F],;SN+KFI;;^V-O: MAV:>7-QA#TRQ^5T))Y;\*7E]G)YA3Y$-I8L^T.?4A/:H0'S88\SE9>'DO*/(WWR";#+-CW!%>^2 9T"9C8=%WW%!NAQ*CO]CD2G0D ZRQ*HV"B(?/H5@1+)^M#,K%)>%"5V#>ZWU7+76V-F])@ M0&5@YL/(J"I)4*46U>90WURU 9*><]5NH^PYA4>;VWU=3=5"$@3#\[ VQ3C% M_8!1E66A ##!W:5^[L=HM[N8X$1R>-"V[=:?D<=8TO:H=T,]Q6B"]X7]EZ;@ M=IL#7J6[@ \?>ZV9]9[5V!\L/E"@H#?I$:PJVW/VO*F)2GX / #%2C'>3>E! M:DA9S>:99-;;&[U:MY*KJK'"KZ+PX))48TY>=A=L0#B^S'X]?:O;I?Z&C $[ M;D^1"]7XT#5M-KY/51VF(G&I,/SQM)V0:G*(=O:YN;\_!!:CV+IVZ@)O^P\/ M$[A:G" .H$JM>?'J@CWY%I"V3$9*_M&U+9;QK\ )4V5Z%;=T"TV)J(1-GX?X MB!MD)IQ:?A4!IK4KB'W(DK,@4A"%N7*P/-(&C%M#8&\L@?W0X-%C2$WE5/F, M#F"AJB3'@ &+8\L-!T 8^'A(S$ODX=@4G@#T$%M:*1H_FZ"J A]6_2J:GE[+ MOOJ>)-79**UNT,@:3,JT5O:$2LL1N>^MV%LD ^;NC0M;ZEC#;N7EIGRZ Y62 M.IQW7O9G5E*/[?O[\GF]@7*+K\1W']NE>U3Y'(0"!S"DM>'$'.=RBX*63249;EW2 MM/EX%[*9I;7GJR/JGM#?*K/_6,ISB.0:T"I)GQA M[F>)O6(C;H%RCPG) .PJ.>W$OJV1)C][69?'<].B1-/=JV;P:HT="L*28(>/ MTM"B<2N0Z=1*M+GC-H 9GPG<6V/2UYZFJ@R[$B,3A$%$M1^PRQTQT.@)//B' MAI6D7B)AM@2]KG.N0Y+HYNFI*9RR%4!PY4Q 9>I;2HD!$.4ZB/U/.55/NT\- M^>)2"W179+G5#?M'96@H&7A%ZDV_9.@F.M2%Y4J4XCM.^[F?M+0;/2*V.T%B MCY%[5WDD:PEF@4!04K\QMV-3K-?@US]O1P:ED]TWEP;H">GP?&TOYM0N ^HB MMCM>K-&#&+ -=>!LCE .Q4/\)F/KRMK?"5=.!3B&=#L&Y\H! ML/)T:BW5*H]";)2_"M8#K@,/F/].2Z8@R5 @=H(*4DB=Z)!L46;&V>0)I-'S MF!!'#&5FDXPO,KZRQZJ^2,3;*OBU$/ZI$D$#Y.M25$G(#\&'S[,W0TFQF13; ML#:NMM[P[U1TQ)O54=C"4/DP\V5225%S1/ MMNVEK:Y%V7=4P$>[EKGQKF(6T4P%V$M^DBB -2L=%]S+8KGLU#B6#^[CK3]& M,&:*[R4Y9J1[)@[IJ>!R%L934W&[Q !4+RO] M)E:2(ECRBP,5J1YY>$-EVW,#14DM<=M[4HYSC50;CX*\I&Q%[U!HY%[;"R#9:S6.% _H5[>K>+C* MH':S]?"T+[)X.V&;J UXWNM6M$RUJ?$T94P0L'!:XE+(=C>=D1PLH9%J7UHQ M<27&Z)YS9R1MA,IZU(M6N4U10$T\L--CE709(I5OKC;E*0>NKJ"J ?;#9HH( MAFPN#=2@;@1I_K2SDF4R-MO]53QI_F>Z2\&W/)JH#C65J+>+'>87: M 2-8JH,Z%?]I6<%RW4?O3<$0=VUB;-0#[G(T]VE!0[M535GVYE+!)2I;P%!^ MJ&M%81N%27.Y*SRU$:08,Y+]6(+/6B"?XK?;]FZ]?R^R M+$6B3_%:%8D'#N[$D .2R)G(UNW-/,-.2K6K_JZ /% M4S3)EM]MR3MW#P@D M;ML,YDIB_9Q6W=(;KBWHWBV-DJ1)=3WE1TT69-J7PKN(?KAN)M-'6$A%26U> M;2N3TBQC"@Q\JHU_; E('54N)(.0&0"05:EP0-FM'(+*O.IWU&%U+WV16>O^ M#4^SQ=7<=ZN-"T"T?U/>8UT*:49UWK58ZEJJNJG;[:[G@@P!9 F6 Y.#/#W< M>#G=FCZ,=I7)'-*F9;?:E\ ,ZEZ+(J&UI%(J3THP?@?L9K\V51D?MSJ74P=A MDE -'Y3E-^"82%PVLJE+ UADC7^6X>[E23RS12^P)'-^G#PLW%4N[>H$7>U4 M^5--0VIQBGP%T2DJ&+KFPU:OY&$)29P[@TU7TV,-K8VI08G%1]@GF$#YR/-R M3\#3O\6TH@2WK+S39D7IV1@I'VA.F3X4%G G2*E.43'X]I9ID97LEU5YQ2GGNGSU1G"!\9C=UCG>[D*A]6,1+\,3L-G"S@FQ! MDEUBL>\9#L^(@G]_E,G;/26S!Q X86KL//:]C:!FP;D4W;D/=_'4V=9?%LQ= M6N&6CTL(]M@'%#:*/B ,^7*U3M_IY*E5-YA\1E%!C(3<\O\+RW8$7U7F0/6T;=,5Y+5E(WQ@ =.F[@! D2%N?8M MFPNE!C?91I4W?VWRCL%UDI;(YHZP^B5)>6B*]MV&Y?T^;;367$)]$:4C6)JV M4%^4JBH;DY*.WIYMGSOUX9Y%.LIV,["V9"MK9\FZ.LGBDU1K\81;HVRFW&%; M>;UL#SHE%%:MBL\M 9VXQ:G\9=?]G0HDV8(A!U3'!F[3MC'U+1YU'5GUQ8!V MB^EU367XU%CFOH K+NNG.^K&:V-7:.8^E<+"[J9\I M[8GC8]JQ/D5C5,*LB/(L"Y!*.95!95U>%?CO7G*=2H8=@C!J1"X"Y&Y38%0+ M^-*CI*LR2?UW45;OLK>'1.?F> TM/H[;W6T*EK%+&R#/%Z O("+QO"_P2_&@ MA7JP>OSDQOFB'!Q4* I-$:""MKQ=.L40LT4W,N)>>(84\Y0^=1GO$@D9<7?. MP08:VJ=JDR2KAE';B,:/,F_.Y&E3WE&D*61W\"5R'M:P07'J["9U)(%EG6.5 M/'^BH$!U6M(XU;MM]]U6!G]ZI'5..Q7/5EXJ,Y+J&%U5+K[R)Y15BRCRSZ9##K)/)!6NR=_6G5TJ1YUNH-N MXP%SU+,C\M=.N:-JA%;REHZ*?;"R;71IP1..I<@DV:^9A72 7B?D_/O4('L M8 X='X!4Z9$X3W'3T[/VB%0VZ4"MDR"KJ^,'.1]E# MPO1V2YI1"RQ'IH;"QJJDV^"\:D6F\Q&4:P;84/WR;+L$/. J196B"Y3@E%B* M2\IB!3U?FCC<87/?6IEEBJ LGV4L(7L-R*F9KWBY%[#Z_\LJRCQM!V(0VRFP MCL(R]'!NV(5.1D_*=;=!N,UN)0-_3HJMJG*YFT#7:M*\/5!CDND_<\EF:C8? M$CET2&9)CY:7MT?SK#_<*S;4ZRQ29Q78((*M[AW%2FM2!=\JGWKLL6.)YT-" M]#!9HJ)5]L'.59"1/#DH;F!9!8^F?"W39M<.?,ZJ.%'[2OG MP YQ8NNUFB=W/TP:A$II/,9JN=3ML>9&\\W?)KNLHA($@6A58R;7N-_#:IA- M4Y:=B]U;5[)ZZX ,2M#CL+U,:RK6J MMN6N#I!Z8YX($M$W-9L!][N?_V@K=('\6]$Y0)\FYH8;!ZH+>U2ATL7E/E]> M55.6#=&F6Y3[/I1'##JIA\7?VQMHU39Y8( M++J[&S4*@ZH(OBV/<%*[HNNJ<0"'LY.2Z&=J/]7F6IN6*B0J]U;\.7-'I3A[ M+L,E>5U""I"*![LWE;FOO(2&33V4Y11&*O+>[F( :D<63AQ5[4'6N^TLY*OK M5F">))54S HM8FG*(0%]@FW+R;B6E(%;7BIM$<"Y5&PVB#@D&JZ6' MQ1'L0@ /2DPH!S$#K'G;M+JUTF&E#V2;H*=F6HC*?9>2<@ MG4&@-9Z:^V9)*U.(,G4DD6X'D!.$Y*L)2 D,MQPDZT2R@7M63=,1!%" M VFXAB71O;EE.IL$1NH]"A()IH>,)4G_CIT;'=.TV_A$.[#]J#2GVX"4@]0A ME']D=S#]IF+8E/9^*2S>]8OALRRK/7H&O11QL2P&F?=J+*GQV%3_WXU#-J@0 ME;3=8I[%(ZOV^X0,PN.>FNIL4MJ V0;5H6< $,^S1()OE?@93N6>*@^WUO-4 MJ$]U$$I$%J6]!3/QBD5-:J.*JDKD2KQCZ(]X:Y+"N^<2-6,F4_)=1JXN;[#8 M+L:'7-FN(NE?]BQ+-V.,R!"'%0]5WAYL$'13* ZQ%\F$[%IT[% !2D,I-Z]D MNTA,WO;.-%$L3V'10NH_EIM!=UN99,U",76?]=C;4F;??4.S'P*(?C&=V,($ M=Q\C;_;!-&\J$8W5BCV&74;:<:F=2(UW>X+AVB(3DO85'W82V_Y9D[3!J*9O M(K)OBC+KP@"V) \1($-9;,G)-#0@%%(4SZ.Z!7!>VC4=2H&0ME26#>ZO)^9* MX'$E]<\82PIY*A(F4[+<);Z8N[)V$O?(>ECU;&92T_VPFT0@,MUDH73)@9+W MMHUIF]E=\,SRGZDF=6V4TI+"/0T^ICWM$C:TKS[)YN M4A=CL_A6PL^=97U$[+4_/0;V@)I*4W,"!4CU)EAB5"V.=5P)5#KU8%,^UX;- M?MQ;3-'JC^3AX?ZMA]GN,;&>*;=D([$=2$".E20LVY@?11X6O<_N@J?*+"/' M]LT=X]FT]_,8R28?=PJ+=EW^(E5S4L3/#FMR9W*,($&^A0E<%&141*11D()8/)28]?.<:\OSPV84,ACO 444!7SN MC=IX%?=9V686FLG[4=*W E**XA"'HI-$H^2A.-GI4'33,A2$JJ&ALR@X1!)- M+8-.STCNIO):D"D3352/:K*LK#W;%BA1@D$5MS/5-ZO3 MZQF>-B4165F"0)^UH*8]%',9.9"0W2F:2PR#2P$:)T6J9/0]CSVQY(R-<#(\ M4*/6 _N4PA=K_?'8@4:,K[)B+I(K=8?*^&K64AZO-0 .M\';/'!IIE4V:AUK M$/40^=]E@Q8G1=^3[*>/5D(RUBCCB,=+C9;<+1\;].L.T&6P)Q()5#=E_VQ) MD#BX^]@ [J1TBNEL$[RV-]D^+&92'9B3R284NA4IK)Y\'59MZE+6ESLE4C3WLMNDFJ7CW^12>ILSZ-E,HE M#Q7MQO)\L(.:Y6Y#KZ=!I_*\6L,08NL@6ZC]I3$*:88P.UF-@6]AG=6YM<]J MF-07585H,+S6+1#(37KF-$7D8OQ&@ UKJA(?_1PKZNTUI>RD#)K00N'[2)8 MZ!1&A'/<]/0 M*:A9\^C,,^6T/H'$RW7=T1TWH)>^J22D; LI:$1]3*U>SN2 M&X[1 IJQT# 5*#8S8_4 (Z:G2P #,E*J00,1I0KNIL(/ /=<@F.)W#ZXN>53#[$U6JI:,349F5+3*$OE9C?"WIAM,9^)6W\QF MLVB9L+Y8*[3*$ACJ)_.<0 R*3:9;ERO*N)OGKI29)_'4U,,3SR'?B*OLU $M MJ4<>K]4BZ28U58#JS12]67DMD90;P5"WWL85/W[ZP%'3NQ4FE6B)Q(L79%DG/#>X@\>Y:[4CW(+ZD6^WH8&_94 E/ M$SZ@@"I?2B5>$MO<^R)N@+GT+61=[!IVN&NI4HOF 448$D[2P*8P7P^' :\1 M\,A-A\9;C*^&-8(BF2^=K*W3*$!?)> $/E\XA&"K\<58&E_[EIFHP.W'%E%F M!<%"Z2Z"0+ %)N351J\EW3VT?Y67/)EFSS!8NGTQRW7?2EZ>92MNV-[+S8HX^^*5D"8/]^<\L ;B!1T2/P:GV I5N ->C0<^Y-"E9DH!%CWF9!O?8N@?BDLMTO-%) M@LE[F@RT$2'G:.OLB6+0/$.!9*% =4OK#LO?4$X+O\*<'EOP/,Z"(W?;EQI5 M-MF%AT,!1CUYGZM%,H8$$#ZIC0@A0*A#- *T#%*1$]AJE>1\@!*$/.7>2Z. MG(PO9G^=9".EY37PY0G8Q>P$#5*(EJ[>12XYQNHP7.YP8=-'3G7X=40HD5T5 M#2O&?;6"47=53]?#RA\V/"5;$RG(P=S4>RK*R*#CMWKI6U[>G8.XRZLT[KQ*(ATVEM,]3[SD)VSM!$?Q7$W!0V&61 M'#V'NN0QNR-:W=U=W&EMM3SRDLO3M=6,![.*R.$.\,A;+N)FVUMC55"3>NBP M7^)D%LJVO"8CIF015?A!JK+RU#J:E<4\)V!G<,9X//;=MUN.; ORA*AT;?16 M(&5QW8ZYZS\&HN4"]W6H,CSE/_7>YH)(L"GMCUV>0#R _L9<5-F"T:F,A_J3 M$B)9%$INZ1C*#.Q[4'WZ4"Y!:8MTJDRH%JE22X=6IGJ,7YND$O6KQVK)T.V" M%#VL6#KUU#5V94:7K84%*E_E;I9-QZ3G05 @.D_-O4\ _M:7PIR&(L\Z4$K6 MQ/U4U_DT#*F_9WHZ!U+I47)USREN.YE* =,&-](2 M,U)'0T^\@X?ARUJ/!>Z$7Q:S57-L7=B' FYIYVG&);3K,=(!Q+,#9?6)!8_, MEY4QH:H38D^9,1Y/,-5.?7+L450JO6FDK##-!BZ:/*FBSJ><.8FTQ(&=Q>,4#53W7=@5ZJ]PUI;%2)C,#A@]"?+FMV M/O2:8J5>_%'EK0:Z.75L[-J",EF?&JWMX7#M:DK&;."92_R_$M65_9BLO2$<%-1K!Z?$T#!C MJH2V[QIZ/-K-!!5&%-.YNXJ&Y[$I4 )$G0I%VZ7 J!#BYM(EB(04785CHZZ6 MT\5S8XK++#<'REGE4^7VJ=9X[UMQ)SHJJWMZIO$H>&:ZE#^ ME:S*)P).5I.7H5W1*PFP$E"N1+G38M-X>6H(I#FV!]MY^9L J$!ZU?W=)GA1 M>]F##R5PDK%3OT4 6R_W9Z6V32(&L%BU+K6.K.$[$UG#D>E%)9#L4G@)D7#- M$SZ:I#F9FNIJ2E&,SNH^/K?V7G;.JS!G/ZM"9*J;=HIRE<&90B8>8$G2B;:J M=$'V5?Y#L[>I<%4_@KY=;1,M1749I0=(%U10PQ."H,--U?4UWBWH_1=M=&UJ MHWBR]BPG:R* M:\_?PX[L3PS6?:T++I#FN$A L4;#UQM\53*NK+*]AR*^P+EP>'A*^L"(GFU$,,?4_E MO>9CT\IYRM)L57*N7O"FR/O1=>!DW9"RE\=;:WP% ,J6-KK';8I^Y&[].VTVZ"1 6W1!2R#GDV9XQ#JM-I1S,0GV%0EX\"C(Q#E:W= MNOT,:_-CE*&E.2.QZ:I$E2TU@"HL'1[!KH.#NRL*H@"M9JLN51;7K6J[?;\F M&?L.V@VL/B]21Q]N$RKP8?6EF9ZR$?Q&LOL_NJ5\ZRNB1\CA$<^[%I0:?4QC#BH SYH$801%@),.[:6ZFT]([*!I MI5X];O+KB%.4LV+:J,UQ\P@Q RL.]TGM@[ATH\XNPV.2&>?C">FP6*O,-#[W M-&N%IVL60@10T71*EO/$33&WSUM5!_^G7U93 Y!H5L>G3 M,VY3FAME/:OIJQBSO&ME!BDL=1'-SSQ7T*?N 'C9)D?\ MXE$M&5F@T9:4&@9_$"5N!?& ;GF,J)F\[H(V$-KKHTBR1DYQJ'+:@KLS.G 4 M40VS7#7/OK5@74TE*[."^91//UH!7-6>J)]/&VV)AP\CYSY $!:[T4<6_[RV M3GUV6:ICJR,;I(IZY['=RX5,^TXW5>I#A74MX3FF4A752*^MSG@CK= M!=+ACVIH6\J!RVQ)E!MT%$I;/9OD\BZ3Z2R^IRM.C7W>88[J58]Q.FY6#=:C48PQA=%XDJ'241"DX0 G^:M%?5KJ%)D[>#OH7;'A=/I5A!PUV/0T8OM:'G;:1Y MQNR99%-)6P!+K8C4I:GGQ;7;"I7)$'>01YK<8-:>]XA#)B[QC"D=E@'.,30/ M83D1 @_=A?)A!Q'H(BE@1AV]4O@ [YC2W36I:77'&.C MK(F WF(Y7RB$JE8H-OD36I5+OI):41=X=BK(2OV>DRW@\U2]H\1=14^YCF'4 M33VE7=4RS0#Y#U#3_JY;<9AE2%,H"IK+U0"V H8TP MJ[O2D]3626O[A>5N[>OQV*Y,^,[28FK>NB$2."G=]1&;/2B"#4C-5&TFM[#) M"";5N!UZZLS5=3)EX?*O/."Q[&B?I+^+W6/VN+@/TAI7-;+JY\W*;-K96[>Q M_%*#XM5<*BC7KOE(*B6\DCND8UM*:Y)9)1?QO S*4BZ/\])^0K5EHGD+)R5B M*7H&L_ (*)=FQF-)?2M7)K6\>Q*RP 1)L$?9'W9"KEW;DJC%+QV$= >)6[V\ M"TG'RQO;8Y8FM3\ ]%7]$O(F-V(&T?W4$J*X'YRUUB#W5U,(_[5Q\I!B<:A] MHLEH4\?T/I2O<]--TCF!:%[V-KA5KA+%X&FN-A^J!E.D6)"REXG,I-6,;-I" MH0_]6"XZ8))+T>%Z>Y62^_:\+CA31@?J#"U-!M7Y[1;7KNF;VXK7OEE_QD&4 MV,_56,:D8GFI3OF0 GVD[GPR!L%TQ%+)X(NLL-4$B*EUS&QF6EEH=Z]#H!<\'XS/4F50Y,\-:5U'W\2)2(AA"?< M1/RL%[<##N7IM82T(@Z,KI])VM#N0G5($%W?9; "C,;!YR1+UBET-];J,1B6 M9'BP%YIRY2 0>DC*;&)L9GOXB5Q'O>B<9UD91?T$54R_;-W=[XT2F/IZYXU+ MU[+#$W-R*_7O4I'PA%(;I2!1B1639$=S5]J)C7U*"0/IGZSE MD:>I.*A_,M52MG2.IZ055=Y(>EW/!::W*O:,J:VT@YE 7>NAX>0V'VXZZ!F@ M$H0VU3PWB8^ZA7&A*FIX.$UI,Q_WTC,H)!K#5#G4E(1D%541*FJ4=WVWU2=C M9'=M=>W^SQX9>J)2I(6HK,X3(ST"Z1G6NEH9\BGQS6,T&9MGV@*(E9@*!J66 MIS;US-8'[HG&B<>2Y/6IP/BCF0+#&I$RO (IMFY1[G' K+ M/K9U@&8U*SD\ 9=)VX%NMYJC00/A2LT?W-U6(^9P!SUI\DN4J?NF)Y2MXB;8@22B/)(V;8']V"X3=O6]@E48#Y' M&1[^OF>Z$FM:52Y8:%(88THT#:F4ME,=[%K6#2#/2UTU@O1F/F9J:G]J_[F$ M59()$1Z48E>W>Z![.]738RI0),ZZZ+?:4W@VI2X)@5SJJ%M>5)VJU$4/2(ZU MD\!CU(KIN+I[I3H\,4VZ/>Z@#B**KB.'1L :-[IH2%/4?L^V=[7^*,JB%-F6 M#"]#(2,F\TZA7J[[L#273C44BK4WB#\,-2E:.IUD2:F9FZE15;;M=MYE+^9KICQ!]XCA?U^=,P@ZGDB:.->,."@[!-"DN>S/(>T87\ M1 D@;8E8XF$T** NA3.^G()Q57<:#ZEL5TG\=U $Q[.7<&V?V9PR3^V KHJ8 M1XW?=.R,LMH'T=L=E>ZYWZ$EP0Q-V^&C @%#4TA/!BMEPE:6;9CJZY&4!N*0 MTZ! S+7T!+@"CX&RO!6MCY.$!%57>;#1;6D%\K0AL;/1C#YEX)D4=*->O4PJ M7I%B":<>\F#5:,E,2TE,>#C4JOI(#$HI:J? M9KSTX&C7$B8-5%#WD$F;UW:Q>YB5(2:\,Q$EXSIZ;3NU00H6!AY&W2R5)BDS M"U\ULXF U+3OE!99*<#+MAV3_%3R46FNY#;A)2&*[.2)L/HOQ#>%1HD-9%8[ M0,YS"4:K),?(6?8NRJ3M[0H0>AQR Q[<3#DUM(W/=ATRZ$D 1#6+1Z62>;!! MH;_B_$Q+!UI70!L4@7O/3D:*>8$@PI<*;,FMQ>0I(M='1KWL$V6J!3E+!&7B M&LN-A0 $NI6XA?JT43:L(^5.H!KDZ?-G]RN8FK56L!9W0W,R')=VH%N28,ZY;,5'[H% M9;2E=".IV5?#D+9EMUN5?6[L(!"]MS&P]&K6-$G M2A]5OVZY*CH9+A4T9C\PF2FB,-.\AH<_X+*^VFVT&[>F!Q98Y61)!Y2=;JI7 M?:3*I=WIE$EQ=7FIQU$\H3K6_MI4I^+H9,JM9(_.;WNMQ^?/.-\MX M/=LAHIV4Q[#!T^>3%>"T?ZAAW(+JRR;O4#EWZ"PIV2Y%E7!9Q&3"II&P!Q'A M\?!=MJ#];Z=GL7VI-'?PBNWA5<$?UN3RJW/\DL)>K)^F;R9H-'O\+Y>GATO< N;:Z8O<6. MLMN-9,_$0I7 ME.FW\CPCH'V)1A;Z#A9!YFICVQ2\.@GLNG&0Y'@41?5B @E1NC2M;BJYKMI M?X.2M.R4I'%X!1J Y*$XO+24:I?(&:1XN7>B)9X+,8JK&%\2=: <.#W+4W"6 MV7.QXL(B_6M@;'T1W8G@28$<59[LHS<':,FJ7H:Y=6HMJ$\M2EO$0)QLGB@+[3/U8 MEN_+])P&%,!2U HFVIZU35\D045WVX[2F5EL$7<0K06YV;XM8/4\EZ\T*T=! M,V:O\J]$1P6H'G66E!4/K,W536XGK^*41,="-435>8M*=$%5@8&YI A%M'MS M6/&I$VM9%_1#Y2EV#6G(W-,];\K#6_^/:]%;YMHZN*5P=F;%X;'X+<:077%)&=M1?ZD&)1NONZ-BO:9X.17+=(\GV)!76.(W MW]<40F,9-_W!)> I<#+=KUAB4HHN*)EPN,/7NMH9%KYER;(]16OFI//'[8F7 M=8/B4NH @=9VPL]VC 7A=>KMAQ@UZ[Y35]\#D8'4V]P34Y)_: +)E//8C ?: M[>TXFL8/6HE0K&^DYZZ3=-' J#\Z?ZN86)SKEYY*57:HC;-4JN?:G9WV1IS$ MY6G 6.;?7 ( ;"-A\EA)#W4L11\>IVU 5$>"MAQ6MK*JM1%2O$-0M7/1;L<\ MM!O5KVT"S25-SAJK#@S!;N]FU__A]C807&X^L'#?W3\"SFO>JO>E6[,*[JFF MS"!W=\\LS<[-KKFAET94'M;& 06#@QI<+%- E[K/YJ\!QGJFRAX:;%-%RJ>B M>*6V53I+H<#MHM8 ZDM8SX_FB4Q7O7'#TB[5:.@&34S=R8=)XAD>%JL,U6*>L(B5N@\8MZJ:) M1]54$PP1\[:BXANA";M,GT>JR>^I)1&5WB&YU^LB? MQ37&^F4DF4!AL_EK[&Y!>=2QE-&I)/9==:_3N#9G4^1<^E+D=[L>K?'B*I\F MGO8;0O B:=99<9X$M3J=*>2?QQNYTB3UD)T,JM9["J/EJZ\BV?S52UM*3'6 MDIH3-DJ19>NAT&X="JK<&Y^?R8F0< M 1@/$Q!\H4J_/2^-C'E[;*EVTYTN6]/ [: -"TC"[+0351T\,,JOV6/-H>J8QME-3!K_Y?_M_W_ M'_#_B0_X\NN7]Y]^^/C-^T__M&W;G_W9^/:K^?';'_BWZ^6W'[[UW__BW?U7 M?_\?*"K^[+_[V[__\_[5QU^_^/:?AU^%?_W1N_ K?OQG]Z>7]S]\^/CM\_Z' ME[]X%UH+[_J/OWT7^7GYB[S_1=SYBG?WQ^_^\.G#;W_WP[M_=_][?ZN^Z]^\ M?/KPY?MOW_W5^Q]^]_(-'_+E^Z_?_?W'+S^\_/"'7[U[U[_^^MW?^2??O_N[ ME^]?/OWSRU>_VK80WGWUXN/_OGE MT_=OG-]L5??^3;7KB6_\>7]2>NZN?_KT_@\; M_D]E_K%K[[]^ -_\HX1^6_O?O/QT^;3#"6\^^*_ M?__--^]]_X]OQ7=?/"]?__#VK?3NBW_XW??&? M/KQY7=Y]\;=O7]=W7_S]A]_^Y,O.=U_\XW???_B:N?3Z9N/O?O?F#^O.&]^_ M?8,+^IMO7G[[YI,J%_2;W[QYS<7\YNV?<#&_^?K-Z^KOO_V%TS?>_@:7\=7' M'[Y^^?[M5Y_[O[W[?[YYEW'\[:?W__SRYBW&\?V7S+\W;W'97[[_]/9>3R[[ MUY]>?O*'7/DW[[_\Z:]Q]9]\SJ_OYU;>O_F*QDU\?/N:R__X_=?OO__=F_>X_C[>O';,W[[FRO_FYW_#I7__ MXW???6)TWKS+Q7_UX84W/[R^N_]BXOU\VL6?3[KTBRF7?S+ACI],M_+SR59_ M.=7.GTZT]K-IMO]BEH6?3K+XTSF6?CK%\L]FV/&S"5;^U/RJ?W)Z_6)VM9]/ M+G+"S^96##^?6C'^8F;%]+.)%?,OYU4\_N2TBN4GLRK6GTRJ>/YB3L7VDRF5 M]I_,J!1^,:%2_!/S*7')Q+2OWW_S^A87_9]__/C#"]?W.>7\VT^X]&]__.;7 MYJO?OMYV6F///7YZ?8O+_^[ETY\^SVW_OIN^^.W_?2K,K?S MW?M/+]]^_?*;-^^&/[[[LU\V.GSO1WS_3Z]O/K%6;NY:/K&]S$QV]?']?!U?_P+Z\_ M/[CN'W[WZ>7-;SC;/_[X.F*'\_W#F_EU<+G?D[G^[;7A@ GX>JUDJ2]>?C(0 M!Y?Z[8>W%W)ZSV]7Z='\F&\^_/3=LO_K-/CJX[^\>9OK?OG//[Y_767K*R[F?WQ]Q;7\3Z^ON);_\/J*:_FKUU=]>7W$M?__ZBFOYA]=77,L_OK[B6OZ7UU=YZ/IB>#Z_LN?+'+3T_KXGWXV-_&Z[!HW\>O75]S$EV_2 MA)#@S4MGX)N7+ILW+[GF-VE\YTK?)-"=*WR;@+BT-VE@YYK^Z0&,Q>;Q"$J>OCFY=>DZ?O.2J_KAS4NNZL??OSFZ_<_OKDV4]0/'[[^ZLWS,$W] HT$L]4OD8LQYOOOWG_Y^<]_"?"O MZ^/O_^N?$V#^/!(_@Q=*<)6F4F^^^6/G\@)/ZRZ MBEO\U]>_^4"Y\?+R^Y]ANTH_[I;: M4F_AYO9ZY3JTKNA:)Y]9PLJ]M69=D&W.W+D8.]U5,MDZ0W^M/W?"F;._)9=RV['VXX^*:B"W) M@IN2MNO+-KWTW?&P7B*;?07;>4GD:W$9_[J'U^SO/_5F4$3IB%D1(&G[RI-= M2E,<6F5GET882DXLYU-F]U3):%8LP*G M4^W)/E6#.IZN Y^B7MR CHS;OI^U21?E:A\E9'K0.=&&_3JFHG]1#XS.QWH M=+6X[.N&-'>E,_.CDM.Y]_BT;9=VRB7M6NLT.VOTM%^[QGY@MH/ZTEE7=E+6 MWU/QKI3XGZJ^4UAT.GON]WNSA3W=_8DQI*GHOBI=DG7&>7$]^6S[O+(N.RUIWM.H^HV1IA2GY^..>6SV.1Y=S!^>V]? *A:E3U*31>_26ANB('H.; MU*&KM_NRDTB6:]Z#6@%I.1JW38VEEG>)VK>.5^-)T=?>,/\6E9U[HOK)G9)0 MZR]I@&.T\U+(S3FL8/N\3B;MO=_,9NWLNUVK^A.W6\M;^\KV7I]I_RBK0KMT M/F\PV>ME?V))QY(\OT\/)KC@LH5G;^J%W$49JGSLE_T88TJ/.!F[/52ID':< M:<&EQ;W]T7EUS7)Q2AC(B8WS&9M2K'66>-R2 .Z@XA'_[?9=>QR8])\^%;Y4 M%;$7/8IU.LCW:7MCE5O1O; X^]:*!V.'!J,:1H0KV.=6I5IRY>VQ2>1RR_+Z M;#-2M8_3>5N+A'BQ8IU-,Z5Z'MNLO>=C.!45[[*5JSX\!0_Z'\]N\VIZN))- M8>KQ3P6XA6,&V0=) O/V=-XAEJ1'XQI%34_"4=8%E#7',UO2U7FP MF(?#YPPBAB2WS'?6L5)HC&:R9WZS!7(H$$=<>3PG9:Q2WR^5OF[IL*>&DNL< MG-4VM%WU8'6,L[-R;-R\&I/Y?-R]OWRCMZ1RD&@Y^"^3GEOZWSD+*IA7YH0 M'PI8:A^LX?W!!*B/YR>74L=#!M2YJ29I.T /*66W\(/K\?#82#G325J)*J]Y MTR0L53 >J9/\3JMV4Y5>;9\(.J7U+F-X;[5JXZTOLIK[QVWQV[,0=135K1[WE4=7GNSB+7.-8:PU7+( M&^/7#M4M=$EG.A*<$C/[E$$B'69K)$:57L.,LNE93*$K!%%T$_+8XA([(KC:D(5=^4&Y79M;JF5'<8E1_(PNRV-_<8/?-E&9UY MW![8IYGR(=-T:.K6]$)HMG^2,;?"71_U.0S,Z299/8A%/ M=;*XV-Q(A9VWFK+PH)3#1VIS0.^;XBCIL4LGV[W/O-^9*A[GJCF4]->4/3.2 M%D?DG4)@:"0;U1W5ICNN"W"ANA\/0&%ND 7XQZ8&LM_)Y1#UB \'?ZA>W"PJ M+&N.O=AV%_DE*3S70&\VT2IS/=_?BKHF3@,29CJ9,-+&5A]MM!LECL\:143+ M0QGCX2$<3W?UL\QT[$7M6]M,6\N;0N*U=57#9.;JLQSD@.@,_G3Y)(C_U[ 9TI,:S\M&<==D;RG0)'-8RD 8%0MJ6*?Q@.\L5E%+MWHCX&$A!OGJXM1%PC((W; MROM1I&:H>'4RDUCLJL4#-\<]]TV27K1UL\KG!'1<626N0[D1AIOTI)DEP>FV M#5/>D')[CJG?SL5[XFN> M=>,;&Y%-* @PJ8 [-2^A'RJ#W8$/#W87V>MH1J"3^V$1"TE1) M;V\*9X).)M]1J[TE\6Z/8G!#120"5Y0"?!\29"Y!"$7,E5FZ#B9W>2>B\"Y8 MK&WOC];*154'_9D>I2!N\T/6?#;J!:TFNBT2NZX']Y T%52_)5NR%(;ZR,-\ MLYS(LC8A9-A[EUW(JM'4\09[;D&!P9@<7XE,@,T[V/OS!))H*<*GF*M*86=5 MHI>L.R][9J=A50;=U*SK5C!L,TF'PZ9"N<_2D>UVH-A]&61N)#)2 Y."Z#W,ZJ=*!T35:>_4M-=8W5S52R\" MYE3@Z0E+PEB74?V+6/E'5]MR _%I\:3%"3E-:2 0"9&/S[7!ID]UZXZ#2O,B M.5TB09((:2+.U1,V;QM^5-T[[XT\<1P W(,<9;R^5EL2.4GJ"*M87ZBDWOR@ M>-"^R-;8%C4M(-B03QYFLI 1@VGL!&31>8PBTYR_)X8B.RZV;W,'[]D&[<=M7K-RH[4*+)A$&[Y!PH@'\Q#]5848T6=#XT M =%J4G.T8ER)>AJJDR-YT4 -N!^4.X_"F.2*2."]=U.#O@P*C))"#.G-9F_& MNBG\J7BO=J+:3I(*P'S74KDF5A <;TKNNQ(MU4U4*/2F6*!87GHG0(XA3DO: M>G/[Q'N6#J/(I-4X^7R(94 /_4%3W+2GE!SW#HH$/( (*T@7VJYX[V71N0$Q56=7.DAI>J*/N$>G)YFEJL9K1*-! MJ9Z\6;? Q;@0PRDXY3#P 3R>BT),J?9C+JL'E8Y!O()7= MTE8R4=OA:^HV33+XP^A=_>MLE M=R^J:@7=*UN?IT)I$YSZ*#Y@7-T$'DK"=S6W*;5 '=<1['98'9DD0A[$<]C7 MPPRU(Z$I:1-U'(G2RG3GG<]BHVZGE90*;/E(*TGP "0^W50$U>:JT'N707Z0 M("6\0(=\TQ2!?*>C10E,_6<,AJI[ZK%6Z/\ ]RE'U M9H@-X&K#$/6O!4-7#E^E>_ HD<\^@R$93$N,PW;N,N:M.RRSBH+_ZNK2@WRH M"JXLV-' [ZA-]JE22X LUJ=BF-.&[TLPPAH"G":@2KC77I;>.[#F^6@NIM^)SIU5+'$K;D4588UY*POK M"EM]..6:)G(-9JRUU(E?MN?GLUGG$_M(N\%N/RI&PF)U>ZD2+BF3U4<1@U?Q M,<$V\3"K'0109<.R.V::5BDI))(IT327$M*@$9AZ'>E=48DH#Z1[N MW5!@W#Q:T,=C"5*6)D75!J92SVQY#U&G ZZ!O)DU]];\DJ=0IRI'BUY^KW;- M7=,5QFF9-E%MBV?8')X),4J#N(%$N7.I<7@^NF<; M$PF8%!'WHW])''(9U6NN:2BHO9TJ;?!T9[ 9J>EJFD_W6;@5L*KR&#N(F2L$ M75J1V21WQO#H*1)UPG(?H[*0=-@U<;A5;BJM3-S3T?2IJN\SU2Y^%H%1<1F?>Y(H.S60-M%,'>>!8T\;"&SE-%!)T\L=?-99*#:NWVZ23%M<+Z5'@D\MLZY(%IK[46LQ<$]3S69? M!M2435/Y15OH%.Q-85/F[%C.YLDTPEP[I%XJ*W^F2R^Y0D97BTQ%>I ]4V07 M@N^GVPK@E<-&] -L"71/L:\E*;U0$^2;&#REA .N8Y/T&$-Z+E:\WK9U23\O MB2E)CSP/N\V"=M=4*%D.JUK5]OQ/.?AN@&;W+L T$C]]<,,=M91O%J+$)_-0#^EA*S;P)%I.0)-I24LBV MR/0H;WK(?1<$\J7V&2B3?NF_0?8$ND^%PR)1 G1V\M0N!39U@E7D5!-0K=&G M6KFG1KE*(S)4_$K=0!R/YN%=LCII):GQ2A18O/;DOLQ5N_W CW:>P"<3UMZR MJ,+-=6#+8>\$D_G:6,/Z8(A+"*E,!EN ;LG%2M%=1VE5.K5B!\JZ76 +8D(\ MTBGWV1E4=651-.S22GCLV7;5Y-X)R8YTKNU*?8B@>[ZT>-39D@76XKZ275D2 M--I"9Y4I-2T2P):-OZ(,UD]W'M9C(U-%2<5]B&\\[JEH.I43L7JW_\F-"6+" ML+%"%PZ-98Q@?3YALQFJY^*F,^N3Y\3L&L-S"W M8RAT(9XS&"IWIN5MF8 & M!SCOB8,,\LQ2)5J7L2T\Z';0:MA1)V?:2DL"($Q3>63=Y1U\M1\H.,@CU] ' M;)Q*@O"55]%+_1FU;<2M)M_]MF?Q.:FWU/^0"*UO=-F[*ADV88$SF0;N%1;)=0.93&I M99S=V'H"X?N4S$\"+YNVCG=5LHA\VM?^8WAVY07&;A.^Y:^-J-I8*46JM(YN MU7MT;]B==6(LV*Z"'3;]"FN9/[7!#^GF6"'B*,L UX5#,@'*HWD4/:K*K=Y1WH\-9%2>KV0YAQII0 M$))V!*I 49;JA4 >W22-NX";CB!:D52;'7%T<;K1KK05XB)I2D?4;G^,>IYTUEH:D*X_:T)EDU7]BT\ M)#-^7[^81JT!7@4N:M)B [D]@'JN=1TL>1ZV(=P>]R6EGINJYIJF*#'%<]%. M*VGBH\:/:O",7[(_3[$ W;GU8+D>FQ$(1,1J'6*I)K@P>5-VR-K'3;QB7]@N2@#?V&>?#]Z;>MNJ(:8+ZJZOL_J9 M*;2G,5T4?J?@916GN:T=#_LC9DU5MQ$"EWW;E)3E<+>0BV3JCZA^T*E7X='= M#&@^ZVN9VFAO2(:C>*4TIS@DC$? &""'"*/C'VG1?M2V5/2Z&R^1V7LJ@'JX M0[W$\"G4'KT4J&7XUJD#_'WR;:3)2 !*A?^>H#YJ"UT:3K=7U+_W*(]1T3K= MM/5PYVF);CVZ;//,:VAI8R(N>5&N5N<%$!KQGUM2&+\KD # (+&HVA@]@+/Q MRCT_)N>A"(+]H]PON5N!_K'ZJ $M^HWQ%TFU68+ 3B*U*_]6HD-IM7#HN:OP MJ1F9T%J*#A)K=U6U!ML0QZV,*?,7".]N;/% U8))N\$KN+&L:EJSQ9XX.BC> M2:&Q'%3IK&6*9-4R!3Y9B(#^%ENAQNRR1H2X*1+P*%>BMJ0L4>5 MHT$@/!-R/1=H(Z$FOE;ML6W[R>]E*C$FQ6CJVIRBA:HNK.JR/#NBG6=8MPX3 MQO!=)S?J!1.JW=^*WUP>*F_7_=BDVEJI=BJ#WQ0+LUM]>-1 KMVU46H^5+,1 M\\2-'4+2!8+C/W85%K53J9V45[NC>KT*7#./&!'% TAL3*2\E.-MFU=62DEC MZC4*X,N=J*4U9("^UMW4NNU90S EL"9EN&VI+#HWSBEN]UUQ,WD!'?SJ-DZR M&T@SG[HG-^NK);^'1X1[]:TH/:1Z,/N4 U(,DQ"I,T)<_2O/KE7AKO+)J?HB MV,(L[E:GQRB?W1=4)LON[+7_B[V_:=8EQZ[TP+G_BJL!S:0!F0 <#H?7#( # M+4IBJ50?DKK;>A#,N,D,561$5D0D*RF9_KN>!S>+]T8$)[*>M76*JLQS[CGG M]0]@[[4V]E[+TID*7:04SZJL!3Y*(L?594)J92UE0._IV0VI(03=V*X'H&[5 M9^H#I73GJQZ,!51!?H.#.D2O5(E#Q:SSI,[<6QVD>PAG()ZVK=,)1-J4.[&< MV'9L;?(EBS:[WAX0$WNV-IA64IJ;E.*,:CQ)4 Z$!56(66F#-+T5JQV:5GVB M[U*EA\JKZ1FNB[B.\;#"07B"32;)M2(:T(6BRZ]Z%T[NM4LABPM8PEH"D3D. MSVUXN 1_.YP]BR4H8[U&;]MK82KZZZF:#GO\DP1$N\BE7!AP-6MY">-5 (?< M!C9:-1,,#@6MB@*:G;#FN'BQ;T?,JO"6C4$DI0(=U;^HV7%RQ^HH\-3.UF/C MH:*-F/XZR/ZG K"S['5,=%1^7'F)+OSG 81K(]%W:8#!>IA/)BD[/:=S[IW5 M!?8YG_T(0&_/ Y0F!!WEK6G7]C0\P=.!KJW9Y&2]WKPM9LU*-%#(CIWN0/_H M'0 ?5Y**J-R''361%/C:4! ]IP5UJ!":[WW&RCTV&W,T!K1I*1#1FLIC<>F- M @2XVC&?K8 /QG9F,1*MM=P$]XRM\0TX[=&X[-H@0_,CI+^HC*KPT#89$DBZ M@J3Q*%IIJ+6LUP&O8=H;Y)%;?*'9YGEBQJZ=L8>LN:M=9R$Q\:2:=0R"NS/# M.=5#Y9KFB)KT6A@!MH\RU%=OJ96AAZ_B-&?9M>T,#2 N*.(%]5,+:#ET'SQ! M"H=J)0@29I$A%4.39'JT) MES^+^*D;TQG;Q%@H&Z1TO#+\"CG@!6/XL^T/EUF'[QB&I3WI($"\J.%L@4 M>>%Q'D'RF1_]:30BKR:\=7X:B[4YQ0HR%SI5OV(AZ/&\759]Z_P^ ME!FLP;H82G1HJ\8F+&)OMC1//GD4 <\)Y^X@4?*4OZ68,]1B*8-R1K6VB="* M7?:C*5H>U:Z+6LER,8^%F^TQP^90,INT[)2[DF%D;[VB' UGPP#9*M#^W-4K MR,$!.M)E@95$HGO=/6S3FUA*) GVJ\'O1(,:A<8 ?EF)_:=LF:/=Y8E*W3DQ M2KX_> *#*6B9PB1V'%X1U7)6=VV$Y6>=.'F/G9A@#OT?$C!?-!^LU)"#,O- M>'=(PT_UR)ISSWN"G0U@F<^R/)'==7?RKN6Q00D&DC,L#\;6EAYJ<"LPL=S[ M.I(VY3IFAXCZ\6P]9>&(:_P]/A)6Q:.$I"BF1Y!1PYRW MH1SPYHNM<(O@TS3SI:U32CS- >;S_,K6C8 V4>]M 18GG45_,H M9))0R$PP,M(^\+45A<-(,4VOQ^YY\M0D%G(+0+HTH6+CG;?*ZZ<:><4?UL=4 M"G_HMWDIU)P!:?'F=B'C$!(=7!21Y6T$73F-+'=;?*S:CI!B^^2"9X@J0)>0 MMR.?.L?"#+BB$C+D6]M0M"V-FLAK?<(#LB]1ND-J#29+:9Z6Z00>'6X4B.OL M@'&ST>^C M6F32<5%!JD'6EW$[^;QN&T(R<(L_D!4?,%&MKCC^2SJQW\YI\&O;RQ(XYWVX MCBO1(-I?"ED=ZJEPD<9EA+89D24.S#Z)Y7W?%V '=P-/6 K0PN4D$DZ.++OU0*P M=?,V7$K?G[;_/89,D%M%A0)U2_B7H%JE;-BSI'NM(7N(W/"Y'3 F]1)7_ MSVW+OH KUB:@+F^V \^CWYJZJ85L"1QTR8(82B;:"SOW%B 4ET/_M:4[ATX? M1>=(WJ_NQ.!O0)2E3A4YU']42.92%>I2WTE]Z9I>@?$). RIAD.BGN&A'@@0 MVEAN\%WR"[B(+4&Z58Q&]5+/7;N&N'F;*D:R$ZMZ\A0L%6B,\QXP-?'PUBQ9 M^L)%Y+-@8>U_7"IAY%!"]5 M NSA*X^,FE "&;F+SN'3,W9N!9*0M&<\%?V^[8KM]EDH!09+/?0FR/JGZF,: M ;7@2M7\BCZ(>2N7D\]LU-&;/%7Q$&O&0U@;;0BVIU(&191ZJ)@3JJNYJ\2> M[<%(E@3U1H30J%R0^KZ,G=AM!!J^'=8--*@IDE8?>Q"Z11(;/*&]-G)&3;?N M[4-\J96O-JL-Q##$ G'KS\$" LNJ7OW:4V=( MJ5>R_+>"@C#Q)F18F-:PKZ7'NT MPX[;5ZD;'I9=IZHK]@08!'#OWD^ %8&L^*1AER1$> BL[F'))AMC'NU_TCY$ MZ,F8K23<,]JNU+JU"IM%3T!>-,&4FXTR0,_$=P_]Z6X 1PGU8\??8 M9E:O5D\DR)I3(W]VCS)9.@#A8FM%C$WW@3EXR/:$@*D.:X(D)2<3V#@V?*OG MHNJ:)H,N @VCV)%3$?:B]U2U18R0?8)Y%6PGG8QIT#DR3+B3IKNV5X%,^115 MW872O!6KAYYNL?ZBZKG7YNP$E%4O*V60-R7$5+6#,WONU&WS5X).S]*;9PF0 M>33_8B//>QLYY\LV ;6JZ](36"\C^TT]Q7&ZP=ZKKO@?[ -LH3!357KP5J-3 M!U"H758/-4C<*CB$6Y\*0*9M^,=S*\JLPK;Z-D]=YT$DB18$'N697P"\ZVL& M:Y!#Q%FBU@Y14'-SKYZ'L3*X#BZY>< .M'TCVZ[614)9KR58H/ARI$=EES(/)L@KSYZ-*]FDWJV>\-@!7 AIH0M'8T([\:O7!7M3@Z=S^@18V M -'6FAKL 'QR09Z!:6QI=N0ETR\YL!M>.9E-F+K5.2&C;);2R,"H'F^;M5YW MO6+(:4'((2ZF93BT[LD]0H)YZG;N>=8&BM2BPJ(ZT/T=R988_D8.ZM#"SX;" M-EK1E;,\T].Q!R[E:;%XI 8-7K-3)-K%)P]\DJJ[Q#/]F>[I\(9*X[G;7'1. M3<*3'F"W;D JW,3=#V[GN3K,JJSMPBTW*,HP5*2;2 L:T1S$DIM4J&IKK("D M JD!$L/S(Y(K(978&"SR@@ MTK5+;@BRDF+5# DUR6,]SQEY,;S:FQUMDX8T8ER'OKJWYPV%W/= OZ9-2M+< M94^/8^'!VP@:<=CJ_.5;<4G"%+L;Q^[[ -, MJUEPE:D=("_,'MV3JR!JLU.W"]H%^68?CZ+P[Z&6)&B/H";_LUU/_T0[T711 M]9!C#-U+XJ.\FZZBKSG,%K;N1I,7$ ^CX?.(C@NQ]:8G.K,3$NR_4/#O5OFP MG/I1$NK?/7!BV?$&&%Y-5T:]/U8B[P9/G,]P %M8;CI/<*&[+S01#MD6^FL M&XEVTY:19&-$!Q+JPW9M[\Q=C67YJ8BK#^U]0*:3]F\0NNUE2$)B3T&?G.>R'R!RO&7)0$H^K#?"O*U=Q:&VQOJ3 MJ;Y:CQ!.;@^R [ 3)!LA&7;:94 ?!IF\.MP!M%3884.>6A!0:\]%&>.@OO8 M5%RDHCPI *[T!>H+X_6(.6IQ]H(AB*+CF8?P&S3<[6?5 UG^SL#XYCL7;)%!IS1;&!7\F:GH0S_[2&8V =$-= M/..W:U21?W<" 2MDQ19A<_JP:8:H)&"NO(#&AY#Z">J\!>)*#+:_WWUS+7VN MVI8]?=0/Y-;!^J?(':+%#P0EZW8O*)L*(N8DRWMM&;L( NE$D.[!0V.YP< ] M!CY5,'->0EE"/1)59*RZQ5?XI8:_]FLD-OHMWK:CEFG!Z8Q.D>DIU26 M*X,/HYX=PVYGG7JWNX:*[?K%Z?TPB6"Y#W MG.P#4PIM0;Z%^'_I^SH=$6*E@SYB.!S3\&.(4I7'U07QCB=QA41&K6*V49WZ M\R ('DWP[,$.C.=T[)=JB3M50 YY-NCWN',I6"M9DR.FS5]W*>X!]BC5<4=" ; MV59\D$: TIA+[UMSP4M/60^UV9V'+/R;E[NU@1\)?F45@% MOEPVYK+VE9M<;BLB"#_!71HYUO,ZN].5GA_[[*R)LNUX7TN/!0@4V+@"7;8Q MF;KM&B)UG?5T?):F1*ZCAV?O38(8(3!Y*OTT]NV]A"[1 -O-N:S:P-\OI:]15_-5KA'2<-8L;,A^=-M@4-:8M$GNR MY F7D_M@2,PX?OF?08GDYW5(+#"AOEM:XO)$9^\93)[T;35 MQCTV0X2^1L(EG'CZA% E_EJ\)2=Y74J3UE&,D/0W7)J M:%+$!$O*KO8 =HZ=Y=6$YZV3\0XL5A-0=%DNJL6 ;36V6(V M31!^ZD4XM7Z>7F[SNHE&A*"B01%KAYA_VEP/-%'Y=]G5PQ,^[T^BDJ,YN*-% M'-&M>Y(-B+H]QYS:-)%\(C 4"NKQ3 ZHB,#1^!(7GAX!H@2[D]UC0&)VM1F957(]%<;'">&T0$H^3]X>2UQX$#8< [KL%K8/JS&#[9E346WU8 M8P$I#OYHGH=<(;IL"S!9[N\[3N*>FA*6F^S;X,]I/S^ME)YD$%Z? M'3]J,Y!.SJ#J* B'S<.3>(^D,30O:,*1(>- @24?3MO\EEC3=>.QAYBG0&R) M0__7N6WDMF2I [^@3>9..\+1#U0-2\/!$K2Y3+"'L"O<>(AKJ$\-$I&_^&K2% M$*./3K=J3BB,?#IA>U?7!I@VOL\2RFJQHPOA8]N](SF>E,'R'2ZP&V[J&DTJ MX\+US7FVP;?.M6+:;FWR /+:R]L :,/4#;ZS7N*PQGLVW:19]\2=88[J,H5"^ U.G(J9HB;B%W9QC*P^AW$ M560AO/[?NF-Z*M3(DD-3Y*', M,(G,(D(IM@P2@,.ARC&/:_NI36L=2O3KX\GRA$%M8C9G*ZIU--!#MD5?[Z1K M]ZI!3=*>^ ';Y,,N3YMXM'J^G.P$3^@( 1!YG'J"'7<;RO-S[0DO5U5RA'P. MN='I_&>[+181-4A5W>F+:!#9ZQKP/]T7'B/;?9@LRTZ/)4YP>GS5.7GG:3^= M$8H$#PIQYM$.3"LA[Q*N$R?U_*ZX"'IP=(65=ZAWY49B&0WU$] MYEN#)K.\1S6'&Y0\EO372IYU !^"8]F+L%5T. :8D:H2T^>!838,\_%3+T;6>F;0UQ.;0Z0 M8]3'*S=V;*H'0=VJDLK3 *25 5:.1CD;>]IT"2D=CLWD/3$/06+_@^V@CC5' MY]65N2=RV<)Y^%'.&*@_P;)^R-$ 1(]OR$(7Q)V%8_5H3/,1$EJN> M\;=K5<_9 ?K'ZT PB[6>VF-J9%+[3OKVL6LN Y3YYIW"*V!=?/"R]$G M(FZ'Z$WG)*=6=6JG<$VD5R+_LF32.YO\YC;/M,CC MB;!./^,>9&5> '3\#EK%%' M5'&<+!,U.2L'$,V>8 [4H&BV,,.(%S&&9OS"5SDQ&Q5G1P9 M[,5]8O7LIYT'% UNHD*/+-[1V%D$S@8H1I'3"K8=8/)&VZ;86*^C8)7=O*$9 MC/'2G:^S-^/]*EG%]HCJ(HU+!:I<']@*M%KCXV"S),$;!$4T8H/96@PX?!_] M DX/Q]E]?-S1K?;:::^AK<;B+C(KN:4#(9U/=S]8+AJ@!Z0)<16L&5H/@01"2A\5\\VCO9JV,)[:EO #SX*6H[:>7S2XB MKI,BG-A[RWO<02) ;M%RTT,>V"6W:3O5[61Z4)I]&2[T^>#E@GV=3;')FOAM MGRG1%]8/A#V #PT63?"%1KP\HJSE #N@VQ:C,<+I*+*M2BIIY.&99K Y5;X1 MS9?ZXMQ: 1]<5[42=D<;($ $9/!G#Q=G/3JK]H5LCC5Z&_.5I>\]:> )UDMW*8^=CQ)*"+4VNG6I:@9P;'D[7 !R( _@%;>3^WSN<:7],42 M*Z;(<^5TV'ZIW UHJ6DR\@KT+A*A! (2/7'0K21>=*+6YLT>GQ^$FL,/I\>'K"+Q36L42)M=^ M:V%15:_*!X'^4G2O>#DZEI*M@/;!E.A]1:<&EJD:M.E,\;6*BEH!IFN(E#Q4 M D5HX3SX!@R/M#"L?)%')JR3A^?)2758-M8VM@Q94%?ET21/299TUQ %',#F M4%BF("Y"D'(+6L'.;2C'7^O-N4T;" >PCB0S%65Y-:W;H3L\X$!B;A475L6# M]'M)/1^$HQ0$1RQ+W3D?J(F1Z"%,:78)R@ZVCFNRV5QE[%C0.EOYN7>=OA6P M-)M=JSJ>NV>WGGV(*O702+9S5NMED$=%!_5(4T+"]D5'X&/UD--6(>6\HLHD MS;FD8_%JB/F*,X$XBZ&,? MN>?P:%G]J)W2;9HE?1!N_XJ3:X[P>:Z#4L2!NMXX[3@V<^WA& ML<(0CYEBMSIU.\=KWX''_!<)4H+PZD&G()O-%F0O>ZS R\6&=7:&[<\@A)PN M9V?"?0"AFH:8+A1^GJ4FB1*M.S-GS^14_*?:MPC^B*Q08*51_ *TD*;)9)[O MSGE=1[1,"'-+NXU'I1,[(.+YL!I-N%,'#Y[+)"._2XOI&IW"[H_]98X8R2-. M4HX=F(+(4W?;Y"F'!8'H^>!4=\1Y0E#LY(G$!$ MK/1*?TDYB=O9XZVNHZ5&S*6?*O?X\I[CS)Y0GF0!3V3&11Z^A3N*52JT.133 MNHXZYS:S'@KPV">AYH0"'S=K1G]>UGI2P8"H!#F0;"C+)$ZH<"R@2K^<+M2' M^'"<$[AQ&9BUUW*-:-Z[[+EXNE(\1H_7YJ.N]$#M+]F)348B@TGNJ55/3J\: M#GVNU9$#GQ2G@%ZKW+HJL3 E-Q!H-N!K-3Y*&$BWJ:1SNRD#:#Q '\%6*2+^ M\6:A#_P)0D &[K?EZZNJ3$5*;*I\PB9%]*0?T\#KH(N><@U:%M@F^6%;*_ZA M[L'#[R@A1.)_6<"L\MLF0,"JQ 7TP.7J(4O^L#LC>@BV5.HBRBH[0UPBTP$X MM%V# \!57./J8&F=\ZBH=#DTQ@JT;J4]<2D&]E)4W%3";)"Q88.ZH<[7)NF; M[10M)2[5 ^0DVF^?T\ENW7IL!X70=;/W!5.WI^&QOTGKN-?JFE.YS=K#T^QS M#.P^Q0C$ZIX8G!'V F_6X5GT!-OVG$1?O.38-\FAB :M>BB@L'9_).NXY>.U M40@P%C5Q!E_:OJ=@BZ?K50MTH)%#".PN63? O=FLP6G?K!! M\MC:7-:TD_UXGBX3"2L"W"4E7'J%5WDY%ZA&JG M=,+M8W\R6?)1&.P1WH'VARI)IUJ=)K2G;4LFTG56WA/,U[6?=>1,2T21G]!@ M::7GS1>GI43]_?7=W[5HW@1,X[:/;>-;(&N=RJ 5K;8,_K)TSDCL[ZNMNM>+&"@OY)JC'"N@^U8GCID)4: MK6UDCY.7(G,0E#9U;H9'K>6,>G+4D. #&[&5=]Q;#4NK3)(G._> ]1C/%/4$ M&6MIZ+@"B)]-8R^<'68:JNP'5;^YHW8LBU'G-D#= M\^6OD@'.O/%R67#3K@B/=9-*D)._$/,'RJYF#%=6R5YCWL'^U/68N8PQ_KRJS86PB!(0_HQ>XSY0$# M9W3,"XK#O:<* WEW]9$J6 P GJJ6D.WW)ZR"B'K QJ/SCM"-;5&JD(KK*:A% ME, K@9=F@[7=]!;=E.HHCJ/LCEF95UN.T?-LC]/#6^Z/=\.6"O!C;B<1')Q> MS7#YJI0F.!> '*Q]A105:(#V.Q>4'-CG=4=E@(^U>\S#'JGBJ:NO&M>PWV\^ MC<3WOKN%AK!;]_LVHO0]3,QZ":^C#M=[$4+XM8,;<=99L\*WD<6T&A5*@9G% M)U=?FAZ>%M8TK8?]=B(949W$LUO8G?BH'G>6<*RL-C+A8+X\YQM@O0G3&R7+ MRQ/RQ\D-]5.S.E5K@']>!9,E[G$6VUJVQH271H/68>S%B6="&+!Z>L,L'6TYPE>=S^J'3*.&U3;&9J'77!!_AC\>HGB M/7RK/%@/I(=G?\!<$(9"KDV'\N(T<5/>:AR66<:CW+2B'1<$W]ZI\EN>M @!%LMEH-XBT*DE) MI'F*QSA)+<5B01U\RBL"!1(S@T2'5 2\10,\$@*!,FF6=:WQT]N7]!?\FRQ;:&^ M..PR.*/*[&#U0)+A8FM00D<7S7P;D/B?QQZY\R2CVSU]KG7"J]LI:"$;*6:: MY+X\?;#/4VVH]<\JXG#.E#RUG=;N7G;^$9R8M G4#E-@D,-:("R5S&&\=5L& MO\_9;0UNR6,%V[9/ZZQ.:5S=E/YVV^W&(5:Y(AN.])AMF'Q5>E9M*JEA';HG M&UTZ#STE?Q#3"2N/9[R>.>[^4. M5!1.\5.?$"B@;UU\A=&"KLJ\Y<5@.="RRJJB_P*1[ OYV MH[T$]SV(5& E#@M$B)XC!,D.O4QT=%#;HFEFZ]S7[N9GW>HA;2_%M-V*: PM MO;J-F'>MHV7/'%G[ =1M$3&^3E\8W!ZR$PGE4HR'![G]=-D;$Z9C=Z,(8JDR M )@$*7A4ST5_6AJ6B0M54/D0L0/,X2##U!9GFAKLP.8(K@5E)RHQ-ZN!EAT MX,LLH-R@BAC7%I(/U5.G\Y1M/)X%/\?K=/%P9O!:SE",NN4WTV6]S=;@B[2< MJW,#M2MO']7Q:UH$)W*QKA4E\&@)9TXP)X#_7)=>W>E6Z(.\9T<0*-8DXA#) M8MVY2K0HO;90MZ72]U*F\SP[3\":3#B:JL /\5+Y% 6-N"A6-AD.;.G8J_#_ M5!TZJ,+$FU"QDF![6AQ*[U:VA8%Z"'@H0>14?%(B=>;DN#SD';ZON?AE6R3A MR_G7[ !CL$+2K*>H26]1:<5;U62(CK)(_73<-:G*R [G%K1"(/9ZK/V<,N8% MY.67D\W+-H3R("%$%@"5>[ZKH4"@=1 :59PEWFKW;AUY>/[N231AK_%Y[&'V MTM/R&Y14T_W5J8Y:; 2!CV?[>DS$[2B6@NPB6\,3&%$S>]_#I^A<..LBVC@S MH:N6(8""CHH00X!8CWIBCC*K^OF:ZKA_-IN"$BP>6YT44,SVH7++) 0>"%_U MV-D ) FU0 GR.@ZK01V?Y# CP1%H<3R.Y?2JR?UP#$W#X*9PU=.[RC,9,JZ" M90Z6%>VU>/<6Y5(\?DQV]0$$R+,\LSNJ+.K1%Q=:[VPYZO&LZ0785IO_U-() M:K25+?)1;)VWYIL4-5:R%\DI&(E MOW6%J??<0ZOJ(+ACX#I#[FNW3WL/QVA&!Z.QU9LZP KF*0KD\P6Q*AB!J@C2E88AU76H#D8C'Y,F"AZYE?9,D,%WK)%R04M;+83JA7<]] MXKVU%)I4MG6TXN :GKBN[7>LJT4MEC9H-QSX;GP MC>)YKF8@*;\5"D3NB)?8ZMKRJH>=H9^> DF07<>ZZ2_.4H%1I M]#VOM&5[88I1R3:'D5362_R5?#0NN'HXYD3,#)[YSA2)GRQV52S@HO=>ZF>KJ*A>DKEC=-(!I#G>09 V>5YIBJJ( A^ MGZ4%< J7;?DL;7(,"^9T--]1@>%>UQY7X7H?18S8 M+P /P&(]I=#\Z;R[8:_!':M5Q(4^YW$^;./E+#J0E7@)P*N]V%+2-I.JPQ1M M'2I:@B*FKD>12=+SR<<[HV)G5%<&YFC:NS^..N4)D(-!67:QU\"F=5W,V6XV M+G8AL-B:#&];DO7;MU:6U5 \U5.ZPZX4TZ/G#\ZYY<$: 'R1O EEZ4O;,SHVT_00L4R4IWE)^ MBN#%$W\]P09G@#Q!8N=H=K0GH1%T)YA0P ^Q*=7^6A*24CQ*!G(3-N6#FOH6 M']6FP48X:XDYF3!UN&EV!;*:#["W@U:$F*J&S#HQKY[)\$P] 0.J!;HXE;!.[2"1G.3L^QVJ!K&I65Q+?Q)>Y^*) 8>'/@$L M^/5LMQMG/353L>W:8G6"ISB""'>*RK#N@7,UI=CZ9(ULGP1;?(<_]74]'%5* M+85H$>=6S9!H%KO"X?PE0O[-E1^N34 J]':H2ZD702L88<&[9YK('BQ_'SN MH[5F/^2")JR^]: ?U@"IYSRXO^BP>'*Z$LX#0$I+J5!B528+."NMXGRUNQ[^ M)UUTX%G8-J1A M8SM\O#RT=*:B-&&4QB97/R)P//$ZRV[K)4<.R4%F/ K()A$R65AY6.Q[%D4Y%&.$J=N]7]B8WT9,$?:HD!AT8H"'6KF,Q M86-@=MV\%-AAIU\F %598<+)0#GT67 (K=2F2+A,&/#KIQH"G:MQUOU1TCCO M1D^/*L%4A*W7\1DI+#P S@)M[,KI69%Z]C1*.)6TG?:ED96'0KQ)]LO#K.P< MHMB"#_@HLX9#FF4T6!U1WAZ[VR$DGI]PQPF#Z^57-()3#&VW1K!KG,V[^"[/ M^+YLO-.5X=7AY[E&[0<@Z+I!?&9=L.48; _^A'.RJDSJ$]95+X9 F2N#)GIJ M6K$>)GD6]F1KMYW6\SQN10RR8D2L3,)I5=+5,O(TL3 MTO?J^*Q%H^R9V'@TB^KDI^U<$3Q!36VJPV=R9X_\._%!@5$N1JGA[EJ MC]JLR.\YL?&^VE,\QSC? +\FZ;"@'K);EQ!!7QHIREJ-QX$DSO/43DAGB),, M!I2"I"S2' %-8T2/%P#(T"O3P[*[@+C ;;"(-';S7%V)_-W9Q&NY).3=_!Q( M+NKP>T::'/RT!#IM A=&0V7LM9FLK,L1+0@3+.ZYBZ4)>S+.Y$] %J*3NJ3W MT[>I'O"]MORWHU[C",12GA"PUO3K_)"B^*=M(JQ,S\3S+F,0:!+AA'V3IR-# MS<(+<-/61$*@IE'L@'3!#5\"3 G;DTW5O*H<2RF$IN4H7I;1#Q8%'%$I]Y&M M,)!*HTV1S_9)LJ?_N!\M"V^/[>VP<*P]P*JA9C.H/,16V-VX2I@G(*VG3.J] M*4"@C!ND.1M9:E'1U%*"VC*R>Q:7VNL0$B)U\3&OK08+;HZ3#$%8GI \U26( M7QZWD\"B]'D+,Q_NP>R)H'XLCI*":3V\!2*#AJ&4:%;9\UA.UYD2>W;CV!X)[M8K8+FO^L/8MSP7]U M2P P@'M6HPU##+ZJ1-;A09-S;B"JKYLASWPRLU<5[NUIBR[@O@$YRM>W1'T M0NI.;\>7D$LTNLK1)D$YQ6FK6%&I3YTWEA4[ZDQZ]A#B"3DZ96CF$FV)?!4* M?!]/RH<^I#;16@ Y[((H-L!;O7:&T:&]LB^-6)K9UN=EFY?;I%QV\GER#')T MQ%IY#.(_/Z9+ Y#JC03/4 !"4P%3$J(^E!4J7R')^A?5J-K.K>7JI:ZP1S-/ MYL6HQABV]&"QJW,> 2C?16Z\-&>#% 0B =PZ"\((PIXJ<[Z>R4;B)@ M]JZF/"%_JBV0X4[D3\*0;7:UV/BN[ *P]Q[\=_)\DXN[].6*VYA-0<;ZD(/L M+!24!3WKH-GI90^%JKM/074@V)MN1RIQ2B^G=E1M M:X%6Y1O8T>\\4E.%2$DA148 JXOXQVXA0RC]H99,OYT]/&]H*S>I$AZKL6[; M Y[SY;I'8":8RT%]S:;3S#,)DN>Z=Y M"PD6DK=";+B.=UCU)(?9?3>U$%& 0HJDI6YPHK WMBU9/G4_&7(H[.=NV"\W M),6.38>R)CN@-"FWBI:7UC/KC,JIQUMQ *?O7BX+CD>HL5EQ>#@9C22-#-EC MW0K2^7D>WL'1V#..3 W%85KU;##2UPOB_'995W MFILH?'$,I5,N'E3_BP&DQV]9%XA[#(YFK8#.1M..&1QVV; "^DL8&4WA^ZF.P@K922V64BT>']W.^I#YG2!MBOY!*31!A&H7C^6G/>RV M#6Z> .@T"<_M?:A6WJVB=IG.BT':/2B%,9XD M#/>AQO>Y55>115XLZ"VOLP MO$W4"*4$1_>Q^L > /1NJ+,?O 0U[IV7G\,9N6H A,ZP3HNWYN+7<,7.)G7E M0SO7<1E="&!#E<'IR0FOA5P!/7N<0&Y"C2W(M@\ '3A2;G%,VRY!CP1G<\_B MTLJAQ-3C$9HO0".)JB/Y'FVRE=6!I9;?;;]U.Z3TP)S-'\"UODPIX+5I0POK MX#A7A'QX(&@SM@[D#I:$EB'(Q6WB9 EKF;!9U*F\/:R$"3U;Q0$\?UG$(ULJ M<")H8#,X+Q@=(2M;K0MJII@A#U;[;->#KC%P3@*\HLH=WGF3B=5Z8T?;74HR M/W113;JMC:FL-C?L&E-;CSAY1J/:722#9+7U@!9?&]&:^FG5YD2/9:J^1V$V MP%XIJB\H= 6?405,@TN *X251UP]*5T$UE/'+TW ME"_+;*+;' +=4F0QE,- MZA^ES5B1[$=UEKK>$K5J#F7)/-\*ZSA+X:1DVD?P0"3;5+1VO%2XU-=,A=SC M]I"._>L@6&[650>Q2L]PV+5]-R0#!U^6\U0@/FEG*Y<2JXJ4ON MB_IQ\$$' M3^0$-=I65!R1O1Z>!OAMK: R!JC&1&85AGPN2N110:0].H4B3@TQB2Q;482\ M.08HC@^YL@<*X&DAJ"T?[$R 6:IF=9!LKTP1H^W+852 1MKL-)+L1,\ T)YO4EDYU M7(J9ZB)Y!-]V!E%-V[@ .E>Q>Y'OW*]KN=F&H8X4JX:W"F(GF5V &0O5#?IT M6.*T@@G^AM+N.@R!W;KV*+03*B9&(*01)2ES:+-H&@=D M?EVW2F/36!9XL*\]>J"A5_59H@#8J8=*%O$.2;+1NBSHQD&D"E;@SLJ;V4*' MULN\9QW7EWJC-FVQQFS/62RNK.="2Q[K2))@ZLZ>)E#D;A!LDE$P8E>FZ#[@ M)]EC+SZ>"!>>.2Z[=>OV(8/LJ>HMA+_WL?(JPDJ/"M5R8HO>-T%SC,P]7/6 MJ-Q[K;$E]!Y0Y<3*L<8.:OQKVBY1(,_;?D.,4%(&_!).U=STF2/*.- Y[Z.P M_-6/+_RI+92[V%3ZP&IL6[4-K"R7[3#VL@I>W0)-'O95F;.RMT] #WS, 9[1 MFU'/9 \FBUJ\+1M5R(4K$5]+-SY$-1U>IY-@Y$YK$0,CE/W4(LUU>9=V*)1R M;TW[J"VI\VUJ*,Y'2?8&7!EG5AA8CZ.X.TE:TW9DGQ6LJB@8RX]H7\B;,-A4 M_ 8@[[+U[K7MTFY[0IQ3D<&>%]:?MJ+\%2=2FI:"3N]O1E>UI[O483E@WH %=.CPO19FU*A"U.?\)_?,\(!G3@>"L M &?1'96#5:A:J2K1$QP+AA(WH*3&TVMH_:KL,^F[3K47P3< !I@R>1,H#1(; M>CIICLW^5Q&-;U1BJK/^Z&:;]^#WU.THZ\:V? <6HK)="41:_L<[;/;K M^O@JB4H>5!/"$130&^LW*-)/.#^5S;055'5 KONJ?+12A=IR -N/K)\\L!L. M^WF!&%739K2332[B@0JVCA[/"J,0VS4 M,6)E/C ,DINFH]NGV-FEK+:3\H9DY,C.M%-Y-H\G]*=2BB8[8=?.8XI&EL;% MK%RB(I^N*25DO+ VEH(]P%I/.U(&BA.=^">08%*:5)/U[E)_R&)//H8MW/;] M69X@:>DS#IQ2G/?4;M;.G2A_C$KDVFX?M0"OMOHULJ,"90"CEU7W'%;H8>^$ MGE?AV<[S?.M%8 1"*1Y]:I+.?6I2HOR!.IYZ);3^.&_6Z[5UC[A&-KH871%V MG>; [T/)'/B,7;%5SP;SAF7\%[KH@U#YRU L2,!IZ9CS0?7U9K035,+/4+YL/7[4.<",.&$ M)G&AC% N11747^,=V*56A@?) )FF1S%[3#D^$JB*&,.S-P6,P1QYL -65U'/ M'-Q+M!TW*S2N889MY3J?*8IM^V -C\*-Y"'PO?*0G@=?4)='Z C8BP2:/4&8 M]@"9!?%E9,MA3]N_+D)8 5GI<1T7[;G>KEN 7%X("Z+LV^HR'CP1VPN#QH_. M6FD!L3L@]?%KIBD-UEZ'2"-@_^'!L0H4(LC2:^?1/=!VV=W'S3ZVVWK+Z#T^ MI$?;T7L+J+D9>'NLB1<D8NN[+] M;HH \1@);;PNFV)NT%W7R4A!'Y9U:W6[)-FG 1!UU-8L%?,!)BC$7C:.D_]* ME(U:*\2''1\-P=6A RY^;%DN^Q*K(07\X3,#PK%&M#Q.'N69"D^WMSM%JRT8H+8YJ"-(=L37HU@;4[QWMN=NS%+-%];0K0&KPP!M M@^2%5ST]?O=5$^NVJ5NCE-3U"H:6ZY]%$/34K]I_JT#0=2Q;O\A]FO,4(,(8 M4 '>!TX+^*="I$XV5?<7518NJM%XA175@871C*)AO;0Z/6M0-4-VE&@,JIX M8_SD542ES($LI(!DS:&V;>%I?&8O.!+"$M6):[N&W+7Q IH>#*2@UP&%\!8M M(I_IX'%WA@!(_.HSQ!Z]BMH\H&.M=>%IJH8-!^0L*Q56[]'Y*8M&SR<%P&B7 M%+1P[9.G6=0R>RQWV6BF\+.%]]/>@'XF&_U;6GNXGB5U'=:AKNA<0-1TVR'" MU[JG9\C!\9^E+Z[>0HJ;7Q:5G2TJV_-'OK ;:CTXJL^AF15Y"OI7\E9NUE'R M94DO'E3,1)$UHUK_'DG418(&601GU%?E8A3L=PZ+/='S1+J"FT.ORK%9= M1!*OHRB7;;J. @"X=(W:UDO!QG!;8UG_\$+6//QZJP@<0#4]JW6(7.JW5H?: M+ZNQNI);TN+.H+#5EOCB4;>' @C;/Q3K?V;0UT+/,@8C;LR=P]'/87#I>/9I>TK$'.[J3 M;O3E2<+C!,^C^ = SL-\ FA0IU6*R^0]+FSQFMY_@ 4.9^HB?(XR4;:784V MJ^.Q#N0H%T0L\*^)N!I$,3C)S#QI%3XU_51"*$%#BP<.,#:/6P:Y$*A 0<.R#AP8 0 M!5_?X[+')9UUBSN#@EZ;XQ3\]VBN M*J37-Y *5M!?![8N<(PE8B6 4R:8 6 2J6W7-I.'\M&YNALFR>5/\*IS)4I; M%%NE^3%%-E,?6RU2/>]5 "\ 0Y736+U58R 55M-QVJK%+B-2979HT1SLM9LM M.8]4\VFCB4=;_->[ZSP:&#.)UO((]M/5.8]/YARK)14,[?G4YN151'Q+ M+NA^*5M3'8ZGFY:/T%]5 F&ELBUXWU3I2\U&-6!B/F&< M>N$E>#4(#G9.(.Y;CI!0 ,_:;F"VUO7F,:YB3DHML=Q8:/Z92,S0!XKW!/!\ MA-=IK&WKIH(T:\)9>OLC57,!^D%YP%J')11K]S:Q. O.1; .75X$.H]MIDY. MD_11[%)5?%Z7U\"M!=(8,)E9H5O$"\L)C MM]P=;3'?U"9K0K8UP>1;(FF?;#Q,^[6M^C$*!N?HMH%Y.?'MDGQ/ZP.A $FWHC*(Q)[%+6BVT)&)-*-P:8]S(IV M/I+V3$;8H\H\R]34E8IV6_6CR!7LY;!=W1'KJ7@"CYH]8\2:ZLBUNU:7Q?2= MI72[R6QNYO)@@PHDW+RJ=#Q!21,B>C1I#4)U8LD9.N*GNKI"TZ^SO-UY)WCK M1EG*=)W:=5VJCBR",(B:['0Y;>W\+6_N-+;#GD^-6P!3( SV?N2-\B>&XQ?! MZ6S=&+9AG[^I2B41D)1^L)1D"H+ENBP/\CA7-#@H/XC1=^KV?.M$;UCC<4SHE,>K?C8*OEMDYVO'\ZM:HIC MRE#,:1NV3?:7H87T-@ZUPCJ7OEOYV/UZ9X^%FT097"V@-N4O0Q%VYQ3*$H%0FPWY[.RKG2'TFYWU#3U]D"8'YB> MOGETL^ M 6ROI\R:AQ8V$)I7PT\@#QO"\>'M1+0\MP[[O&FCVKGLJ5&%ZE9) MH309A_D_E$]^AY *@BKIK>J>>MD4+\!P=!4,H0]K)14ES_K)1,1.;5JCLB.K M.&U]6?J-VT:H9KV^I3Z M*L%1<^$[[7)#J&QR-I;U886D/$NWEA O6*3=/V?.SM(] MBH.O[6@YCKA-@PA9:D:PA1VV'+J$?-R0;LH,KHPU]23&&K'!?%<.=^,-,ZDS3+F0WN016ZSBL@ MV,'H0+8V /8XV6<>A5;%L^ KO)]$5M3#_;1<):J\ED>5_+L:DMF^DT<-$1', M)'IK==#)3N0BGF!/RO4!,O3>!D 2[NT_C_9FF\EGLA*BH?+:%:E\PL*F!X(* M5CD0<<]C),=;;.]+3AN#R4F[GK%!X(743@0V,=VMHB+K*H$RM _M>H,DDIH# MG6<@-H5#1]ZF4I?5[L<"HBIAGB7<*0_0[\-B\XP7QE[D$$E1O:8.S<3:@WI#)Z_6 ]L'^@\A2Y?&R*_&4JF81'E.G6SF9?CT MP"OO.FQ?]=BT:[<#YE]S=R5!8 D\2^E/S6D$/<3E.))#7;K^7)9>G^3TLX8< M0YY^-(?J"'^6KK)2H_ 2NX!AB7L4W:Y ;F/UXED;28ZTU2A,!N#H -[J=EFM787OUW:>1[]U H_U#HMV MO "'EO<$,1&8YY*L^J4]:JW9ZKA4$=&8VE2A:YT30^1[/9*/N1L"%&)^JOT(VECU M8_O!;:U6+GC;R3EP>7O@JHMR4?AH I!S;1NI77/)]?DAC8%+5!Y!'6P[A0^U MJTNQ95Z!1"*KBI][R)38II*]$^S+B1SEZ8*B(5UKUMRVR=2LVYV*C <.)]6Q M2B%259?BT\X\A^I:J->$HJECJ:3XLWM!=2H)6M[&Q[H[KZC:V:KXD:B)1=M\ M@-6*F)UA3;$ Y2G5++52U1PW):';=V=![17=:[[GT";_.AU3(FZ#+B 59!;- M=^+-[.<#^_#:6C)5W3&A[>4SBN_5@?U 7GY>\ #/4Y3 MWL9_Q#G+H@.4=8$SM^3-4/LI!3VPJOZJ%^1/N[Z<<%J@M M0Z9M23HTGXR6^)<(95O:$A7V 5'HR8ROZTX;'M/IE3,\#-50$*#)HIVA*-2I M(I'3FI&E#82QLF)GN)T5^I]JES-%[Y8 DZ:="O_&^[7W!8BPJE/?KYU4[*=8 MT[.DLT_U",DSIZAU]IAW5X^ ,/UT9Q8\NY@[P\9H';#HY D\!\0=]A^I*$;. M:DJ]J9;;01SW'E*K^AF0*8.]P+<,JCW*N?;J(.;.YI[V%Q$I7IMEBGX&BLO9(NI8*KC1\8=WZNG.)O+,!A[^LO6<0]'_;)HC M:FY*U'@P456J[^%\VMN6FJ<>9X 4(FA0EUW"@KH"Y(ULOWNK6U[^&$WQ87XN MV!>B'9/^N3QK&#YI$(##KZO@L,T[!ZO?"22 L>I=V__0L^3E_$H^DN=5\U3* M).NO'HW+$([.57D=JM:DL.0H9A1/-;RS$B-W7)U MX K40I[AX/8 )X/,G&,HMN/;*.! JGY^/N2DY!1P4L4LK43'4K:SV& G"E[D M( ,]/$ ;(@LWBP6M 3S81F>5R0*"W9L@2/5C@;[SH>*4\YZ.L;:=J0E:6?.( MQ7+1]5OI!EZK_E#V4=_.B($'K!/LB;[W"4[G %B.R]./6-_J0*-F\$Z-"#36!:,74/B" 'CK+H=7O?QG=2R'-P+=L54[=.?2<\<7B4'=(; MO5ISC,#*U[57'&.R<*H"%S^QFD/?C[KWT8/-Y^"99#4]P,C-VL9MTRY WT;V MX*%TO56(T8346R?C%"M^Y)+WDS%#/?=?U\O^<#QDV;MRJ7X RE/+,RFMW%21 MC4I$E(U BB[ENG MYQK;?BXJ#4/Z[L..MG>O5UWP()*Z.%H*C.JX@ HUG"MV"GI@T&PRX ZO1KK@ M1?%&+N4< )CKG2STRY.JQ!(S1CU*U<5+L>1ZJ.^L[?92SL8.+):-ULFCJEKO ML:WE"W#(:B(1K@2TKE\W5/E.'F>IFYLR:;$<0%]VDWU&JCZ0#FVG-BDY-"R= MWE9TV>+XI=K$REL\4F=T:([GL1[,D5-SN(YG"WP%RREWWDJI^LT:$[^VH7,.K:*NF$$B+F MK4^)K2DOZ9C5W?3L87^]N\JM1'965>8\(L\_/E?TH*^7W<[/>QPN:#C%_:B^ M"KY];F7FL\[N;"7(=]V&ASVH*T1D-6SU8^K;XB2G+)"\S*,XB3BRLL?S9HOF M;(@N]@TJ4CW:1EU.9!6'>6S=)J,\RMD?YX+FQ.V%8DP@1U]6>:/MJKR'BY@3 M+&OH'ZX($2C6TR+]URW)6>TEHH$'0/:'0PB.J(Y;EP553BIL78SL20$K T2M M]G=0 *:<#C?=/>]P?EOW+I^6QW774;5-AI6 O@*;I\XV+T7\M\46Z/61+DQB M(^N$!7LF1X!XVALS"!VC33FP,N4IX^'D(T2U[\/>R^9($BR0&X)$5"-/[)%3 ME2/4;HFV"T.^,$\5PP$?O5>UQQ2 _PYK0I?17S"/EN*#+!ECZSHZ5@K"'V MK,JIJ:U1[9(! SQ.@7JB8=J$,KSW05JWP6:29V-3"GM+)V6G;/C# PC)!N%E M&P+ %-K20+:CW4>]>TY2]B!#MV/\("WU8<6VZNEH0XHM:$.1^^K1-D]#+[7) M#BAV)$A[='X-=LO,?;+L&:=]*+?)&?DWB%7?; PZ7 M6GI9D5T^[)[;*$FK=.+%T7F1VUKOF;8<.) QSO%ZZ /N #2QI:)22GVC;(#F MVIIQIPKBGJR(C%8QN[/.I@4G[D?-7VCTO?U>;WW>IBY@#F]F;=2Z947'N#RW M9EM8@+O//:BJ<))2&X>:5^3>=UL7)K6K(#JW\W7-FG3WC'DK?_$MG;UL%2W. M9D(PIY6A0I^70-G_T^U7AQ<> MZAG400#3LI,4Z=5[."J?T.U6!UUC&0";Y]<:P[Y;"V[9'@A"[46F<>+#R?BPR\/6= &=Q?)<(%08 M2X#N; -WH[.NYH'\9[6@MJ^V%7<'>R=7 M-GP@G@.J>Z,V_^O),*]$?"".KR?8;IY1.5;4>&[D=] $]\62V=Z )(AQJ M ,7M2"IWUB]76?F:G8-SGA &4F#<;\H>SV;-OUC ;0\S)-YZ)QQOV_3V5E5@ MV:] ,OM4G(N!JCZJ1*1EDZ^%9"Y&7UOVD9-9<$7G@K9JAX*,7G &/ ']CO'( ML%6F>'S707\](K*:A+=MILG3>3(/\=NC:IA44PNQ4L:6J1J T4ND[!05,1!8)! MN_;_5[AK@W$TVW4@38-US,* SQ H6?!<^>G2L-M8^T7[>_K-)C2+.CI[6B31 M^QM,PI\ES^?M(IH]3\]*2E\:0W I4;<+EJIU,0^NG*L#X'%#0U\*6"&D LYX MWQNOQ&V IGG):[/^K585@>CTTJT]E.11_S3'E4'(?2ZENQ\VV:T]!CGD@!!; M6+4ZVV^[QTC[G8W\]CTNF.S%\0CF50E>@]ML"?-6P !(W6PD[-;\@2?EJ$_8 M#85%QV=]:N"($2A0B#M$A3,J#KC16,CG)^?N8697;YS+5U@0]#$=5G\/?8EL M8=6FN8/?/43F]APU(VP A.!FPA6K5%F?&V"0 ?11DH-XII <=-N $U7^6 1- MN-NKD:5J[^ #_1.=M29<9]"L)G&/02@O7\ UTE H2W5:7I$^R"58\GJ[G9(L M_LMY4'YE.L''="DHUC!W(5*]?]4.-"-[7M7CX(#.5J^E9:FM MB.K@5N.OK>,E*.$ VV.S NYNG>'M*K?Y7^&M1JXN.?'.V[EWGROS\((T#.;U MJQLY'+-;DBCX;17%5E[MFBIG6@NV,.1N9C7V91GQ&D,CF5&(J8<-DQY.[WMS MZ#LKX+[RJ9B+35 M.FH$4(RM^F!IQ]EO31/9VJ4RJ?+JBLT>#I&^3.T+=:Q%4 MM8=DI=>!9MLJE >._.'N$(D5>2U,-7 L]C7 +I6D51SR=+ Q.F6]G!/B\1 @ M"Y=I0YK=FC:WEQ$@2>X3W\;L3L4K*KC[R#S@S9D5!PH\((_JAL*IIY*4XP** M5[WN;K5VDWX9)%I-9MAXDQ>GKT?1H29>#@63;A1TF"2+0A*^X$/!YZD'II-- MMT;JP!_;A+H@24U=&Q5@<6#$P'( 3FH8%&PF!@9P+X"P=B2/QVV& /N";NWX M!,/JI79Y>DCX*!;V3D?36>NWAX"9!0[&B:^',3(WDJ-&? ?H7%=)-Q')65%0 M/E9IWV8EP6FKTPY(&]\>'5ZS5>2@2=)N>WP<=4C[Q.@\CPGIJ-'*J?[J"6RB MW7A'FGN;/:?O;:\[F'OJ4 CLSS:OL.Q( MDF2*2S=,LJHGI_J'F,^ A/D,&C5:7%W+*@%XB1V3%7 [[*DC'U8>8K).YS.T MPZ$I)>%<4 &OZTL"#^9!!8UM+BX22@BZ9/4MV74BS&>%="YV$)>W-# ?5CO^ MO_S/\?__ _\_\0=^^^W'KW[XZ?L_?/7#?SR.XZ_^:G[W]?K^NY_X7_WC/WSS MG?_[7WT8?_=W?QO#\5?_U;_Y=W_=OO[^[S_Z[;^.?Q/_RS]]X'_SQ_[JK\8/ M'[_ZZ9OOOWN_^NGCO_H0B=0?_KL_??LAG1_"_:^N\U]=-Q_R87S_QW_ZX9M_ M^/U/'_[K\=_X4_>']H>//WSSVZ^^^_!W7_WT^X]_X(_\]JMO/_R[[W_[S<>? M_NEO/GQHWW[[X=_Z*S]^^+NZY=_?/WIVV__]5=_\,_OA_6K?__J#]]\^T]_^8GO M__#'/_WT\8MO_O2'7_[KW_[TU;??_+9] M]P_??OSPUS'_3WK^,U?7NO^[K_YZIOO?OKW__3'CQ_"YQ_;7\?/7_-T?OCFSQ_^W^%O2 #\ M(/_??_E?_Y]??,K\[K???_W-=__P@1SSX:L??OCJGPX6$%]='_Z/^.&;[[[^ M^.:"OOKVC[__\EM?/_W'Z_WJBS_Z M<+5_^N7K>+C@/W[Y.AXN][<_^P;7^L67B^G^Y5KZU5)Z?K&24OCE0DKQ5^LHI9\M(Y+'EZLHY9\MHG3]; VE M\O,EE.Y?KJ!4?[Z TO/K]7.&GR^?,_Y\]9SIYXOGY!*__]F+./,_/\'/W[O^ M\GP^/].S>/5??'WOR__B&_4OU__%MYY]<9^_D;E:XNCW__G;C[_[Z:?O>?O? M_N[S/\8O_O'OO__IY_^8_O*/.^G]ZE?/+__U5[^;__*OO__^^__H'__\+]<7 M__(IG?[S/[G)?OCF*W/4+_[E_OPO/_]KU67WP_???_OUCS_]T[>?-VCF.7S_ MW<=???_B.=#]\_!=^@\?PN^__],.O_X$G\+MO_O%?^(WL:_GS MK[_/K?_X\1\_?O?K?^'.=_;^];]PY]]]\R_=B.&1Q_3]UY^_Q3W_]OLO-V_A M;K_]^../G[_!;?[X[5<__O[S=[B]?Q"8@2O^^7O?O^*J_KO/7W$M__WGK[B6_^'S5US+WWW^BFOYUY^_XEK^Q\\QU&+I,=5?9'\38)?@ @SX!^_^)*K^D]??,E5_?#% MESZU+[XT7GWQ)5?U!?0PX?WC%U]R59^??S37_?F++[FJ?_KB2Z[J?__B2Z[J MZ^]_OOMCYT>3WCQ]_^]/W7]R0"?!+ M6!/-?S\#/D:0'__XU6\__V??OCAXW<_;2X&V_@O7__N&X+]'IZ5Z[X\%K\]=ESW&1P$ZQ:W=0RY]MABO+*6 M,J\M3^U]G]S&MC0,&A&JV1)MHU'NZ^[WBM=IRUP:H\1'P^.[Z VSMMR[%K*Y MU>,==I>-=Y]7\@MYKFM=SUFCWE3Y7#KP^"G!=M6[=>>V^NUAM@T#8UF?/V?1 ML/:HRL5>UZE_<,_I[J\'3,ZUYMX4PWQ/.U9R=-)(5;OJ"'V?Z\V775(/?W-V M9^7?>CSWL]4';L%6;) MZJM>9S_&TC\W/I[ROA[Q*='M6TPJY#YC9/67U;!7._)>:B7/>>FJJ/"+#J"Q MP>:L1!YO5,[+'J?=Q,,=A+O5D)1G#Z_R%&KBQE'4?$@/?\GIT7XKGL:'ZCL: MGA@WNS!Z4D[.%_[7\]B<^YPQ%9E %V2GI4TW>6Z M=HM35 WUF-Q\&7F/B-=[5KLNRPR::["@DO/DCTKO+ E*(HR[X^ZG>UUN-&6 M(CO+KNHD2=R-"RE%#5Q/+36L[C25$!Z,+S.Z,=B '28Q6[I_.^ MU VJ6?'\=;B%:KNUUJ_T$._)M%E5N4J/$9$L=2YK-J^J8AM%#];Y1FO-' MBLRHDJ7$KQXHI0='0U)Q7/Y^>.]W3C;'O4MSH.$@#H^,IY>"IR-:U7@$D^NR M%;-VQ>AM$WI/GF.SPR*'=9Y+]16'T?9T8_LT''/;UY^F4CY^8&0%Y=A.&S=M M4&15\_FUEZ-HP7KEX#G^J[SUF9399 .YINYL,?MZV/R:JUS!R<3M3JM'AG<* M]U?LH^^IB!FZ6OIJR3KB<[G_@@V><>9309VF&%^U/)]9NF?J_-?RI0]6OZ'- M7K@V&^_GJ.I5>9"E8V1R,U_J5MW*B-J)_.JFZM3!2;!Y5KJ3; M=LFAHW=?O8J1Q->%$HRI&Z\W82?[TJ:C46?.,.AW+"CHQ< M0ULE==*.96_YC$JN+T*&CH:.X/)42=6OZK>Z%7MGVH+1N(MZ;[C)J5+HJG;EIU'&_ M-^O25C:G2^NQC^WNZ"+TQ-Q5J_A$(")HAZREIPUMYHESBZ[R9])VGX@.XBKE MF-UKSCXFB^>HNR T]VDSTJ01FOKKGG/&^5/N=JB!GY8*#@H G MBVDXLD H)*N8-U752EIZ*L4_E);UE+#.9B>!'6B!M.61*UF/U:E<_Y8HXWWK?6]G\5O%K$4/B%MPH*L 3?:)F34W-6X*T5K5=1\>ETO78 M$J2W#7V.K1Z>?BJLRN*H!(KUN"H56K=+TPE0<_S4X=IVAJX.EJKV>JO;B$+, M5L$3<,/-'Z/H5!ZVBV;=)EXD3+OPG-'.MFOO_JP>'_Z)T)H(GD%IXCAL%"?9 MV KYV,5'WF3W>%QI9V+2>:BTHA(:"VJ&=O6QC\_NK2&5SF*P.\^MY5?JHWR: M:AO!IHR9#I9)VK-N-PL6\,'72TMW!_L 44-MKMQG<0:/BF0?\%C>MQY1CPO M8NG^H':]SZ%>"XL+K*4P;']L_%/4]&E1Y MJ5752F4CR4[LBIKB5H*X3T %;\L9BCJZ9Y.*P2D[S([(Y)KSW8=U3@YX0EYV M&Z6C;"6^V<[K=W4=P!2[*O=04B"JFYHU5R2'GA[*$C:OARS)X^ >^GH#08-- M-3WM YBJ99S64099T[;1NXZIZ^C4OR4 "\Q^MO3:Y*LE.ZNX:B9%J#:-K>BS M4]SLR4"*6[T3%:CF4^SFR?I35X5H/)[>O5Z_M+J)7@^Z@3ND0'JY; M$\$@V-"DNQ[[Q%[)9?Z)NFQ_$$0^1K<&QMF]RHO)9^T M+PK@Y.2!OY[HR;[IH(XP:U_+]]L> L_F=8APJ2@E1DISF)DPY#BU7M$V'[-M M"ME+E>_#J32R]'63E5_NFW6I5G8+FON "]0F:'92G_RJ\R+[]JA]T-J7G M+Q?O=*;K2$K%@( 4H==PSF-5-F?4J\NF46&*&K2/0^5J^47U#)W#JR?1=%[Y M?86^RER24!3<<3@JUTX\A@*QO==B2C5W$U?"*76>HNK0#C1MIUF%H8JZ&:L]&7=P P9AX M2C@9JI >W0E/K8-)J#S)/;9/P,D:ZSDH;,-$N,*T88-WK;"\H@^J<+UL.JY/ M%S]@]S/C\?!8>8GV=\+HM'ODR=B^[M"4$T)VKA2@(H%D;DU^,+\S,3JZWEOT M->C^],3V''PT$AP:/,P=:2VP.C&V7U%%4MN6T\5M\Q9@E/#3JDMA!7+K\*4$>5G9&+AT M>""H7A>_]1X:R;ICN(A3CUGPR:N6\N-$(SFV$MP?K68,_+Q-^YYXBR>7KDQE M&AL^\2S9"$=2ZKFH4WO":(*")QH @M@)(( +G66K.@F7_D5:UG*OU:BEKZZ" MTX[6MIN,]8 UIK/DN?#V3C5/;JZ?>UZZOU5-5#O8>:N..I(\-MTAB"BHN/CG MK(F(DAILU>.Q:FR#1-UPIA$,Q^2(;$&>F%KEQ;7HN9R MFU9)M*S$@Y08]5N_;/<$T@'3(EFS@Y) /6JA3["LWPY"/4%NT'E#B9]U-6*C M:5D44,?1(9/:C&H$KL^07EE)&4)>[BQBQ?V(ZF/ MLS,M'QJ6\8ZWCD'7'F(X6W/;&+GLIW*6#":C'W%GL^N1K5ETF7_'5.5N;ZV8!K-"(9].NPINZF47(_ZI+ \H%_!"7G[X-0!>OH650840#1(ZH^FAPHB MDI?*(9$F8*I63"9E9SC1V(#P(\E0:] 7SEVK?U#2UI1HQO;)NN6I(+:E#A_] MVUZP!A$G1FV2SLH_60=@SP$_M4NMZDLKR'D5A?$*=PV2T$:1V*(L)YP$@@7. MX'_#-^.KVXUCQ*\RDD[@-6/.5.Y--2E^$)3;U-=7K.C>:A@\_4PDE^$6!TY! MR82@=+'2@'H.8W$7TMS3< \19)G#%8)]N+(V%G/77,>\" FV$WOPAQ4$X25 M2&YV@*#4=0A:AWA$=?:R1A$&\ABX.8>6W^MT2%HY,5ZQ?6E/UHLR**MM*Y\& M]8=+T^51IO-N8IYF0]BKMX)25X,') JZ-3]E[T&#ZBE-Z<:#>C<["Y5Q?7F\]0+Q.%TPE\)#]Y5.&S-9P^]E(_VC#1HA7BE%;H,7.UH] MJJU?K$:>F1*33G*R-@ E;W\<;-;YNE?+,2QQ$N2EP'!6<5"WJ:5WHH1!.9=Q M<._$$,4W'LU/V9-) [JH%APWGA0Q!E>I!E>AXN >/0= QX&?0RF3E[86M>^>I$/&ZG02XE6(6%CIO863F69Y<,:1:;3?+8X^F@FK;$@* M5" 8N\(-D*Y3RVMCPBD# \BM<7VR62Q7SOGH MB4QR7<\>7R3OC5WT>?6L/W45=$11"9])?&?%.5G^3,73#20@OD)83$KDCG,= M2[MAU826/>\Y&8-U@>ZFVV&5-*I_/_0::03Q99\AH9X[&=:RE+5AJT25)0_V M:U]$7R=6[<@&,ED8L%V=IZN?V+18<<5'Y>Y;-\OI:-]ZK%?;,K\GO;:SV=&4 M:%=GI-L)J+>+=;NA#VQ4=D(7*%[(HZT"\4ZQQ-N")Z\O6 E\"",$)>N2_;#G M6)-0WKWBW,K * :FC6%LXU&>WIJ@K?5D6I)JCB3#SL<"EQ$XZX.WY!#J\;KNI810I3U[GQ>)4"MP;?Y![O.W,ZI%"- MO'=:<.D.2["4IXYK*GR,2V$#6$2''.13AV+US: O7*XZZ H3WUD^./>F)%MV> [R 1 TR/6Y4$ M2Z^),+BJ BN=I&YUVZ5AORG -%LM >0FY3&#AG:BB I7.EG$^EXY"'20&SI M@> .:+R\5=D.F M(L:).S5:/$1$ER[Y;X+\H;'9@IX*79=ZD^X?P;-3R9HUG Y9\*H()X]>>"?+ M>3@M#9XB&@S')O? GQG&XP+H 8M 1[JJXRQ(\.:O+8M9_7;>%K(ML#ZT5+3F M3C[2" ;NH0P4BU=W>@MMX#H=.IP1$+T]_# 9,'8EZ>2"W F_O-T##J)U![/P M/J=NJWR[04!"(G\0^J""2GMHQRZ"(1B 7]B(X #_],9BW"A0Y^0Q'R8FPS9M5 6DYR2(7?]^A99M<+ZTH+HMA\][7? ;K0RIT 5Q.Z([F>ZGS MDGDX^K\X":J0Y):G%M[% *[3K5@E7(5H@^_Y!3-HP*3T\YSV<^] 'A=_7B MD6EWA0]TH^0J7)@2TZ*(]3O#Y$J2%4Y "F\"5,;FUS>[ 6;XB'%D"XW199C; M&:U(\ > UK%8PO!^@K!A6Z8\$[>GNOTAQ6S M$[=C-1?)(TV==J?':X3^Z\QLH;>N1X 0-!MPHJZW:;M\F>FP7!'R<,3V;7[, M4BF K1=JUR)M74I4"-O8UQYK\#>B,(NL+NR'8V2'2R MQ86SJL.7)ECFJC.JB@(F44K6DE!AA;]=J4 2'U'ANB&0/#-MP)TQL]+X$$!@ MR(VT]WKPI'[AK:@.^\HZ\=0%GB4(E(!E7*JQ.%3U;'/1J"(C+V28^BTP.2"N MC.CKC-')#CC;51U6=%8]P')R" Q\5#>^S4WV-0X'9H+&"V:'?.^P6Z*_CLJ,Y?2F'$ MN\L*+AN0=]!2@<+LF *]4'GT+7>S[L?-!:+IV70-5LOMA520HUFK"M:_\I'N MC(2^ ]U3Q3[3=C8OS\6_3]UW/"HG_:C2T:QI[(VO\ 5TAUQ9%*T\54]*;6J$ MNG1< "00YJ/9,7@,H78<<;0ZUT?VTM*+QT>4OT@#*J_V=MQ;BV99FM]\MVU+ MB2NWHA_5V]7,;E'MP0XMAPDX;YHUJA=2"Y+D:'0U[/9<6*)6%(5DWS ML>8)NQXZ8[W*$YU#Z9#K=!Q<^PO"[.V8$.M9@VO].,"T#4IV>C(!*$T.2VI$ M]VSE>H!M<*1.A=T!/E-'X *BL+O)ODJL)(?)HX/67)F3),OCSC-*NU@ANV>! MG;JXKPY">17]FSI:-^-?.Z<.\XHH@8>B/&=9A">/@WZ/\#9N^E$-]%)I4!FD MQ@8CG^GVS#(AV'.E(!)>WJO8)Q^\8M*7A4^]%0 E&'E6I@<&T;]<4HK;;/%N MISZ/B6 39W8H7J?OTW,'332_TO/[40[1I> []2MTWPW-/,N73Q'*I: M0'V+,UN]#)<*]YW(P_IXHP[)&;0BY3CY[,FF*[I!SW T-3\[ "*QFN:P#41? M)]9&XB9KA\R^R1,%]H"@?_'/3MI%&2W_FBR%90?;:SU8>KKX6&:$7O.O8 I+ MK>=@(>H29=Z&[(L=@@T<.CSIAQUT$=#K;Q"VE$AM[Z$?5%9\IZF;=$E]]%-U M]:I4IFC%>[_: .ZQMZ2>P*D D<9L"EU(8_I.L^-0IU,I!;VVR,Z*I/C#]7)D MGPS5'!0$!>OADY1FT3UMY>T05MV3K-AAR0 T>A3H3]KVU,KD)0'0=-!+%0 ; M:>"8A*K6'Z[)Y)2L3B4PX*.-9X=O ^[8OW G(FU0G#38@*+8MX-\->QY6Y8H M].$FE&:6PK/;+0B_T:6D2)MP1?$V\( "F7SDT8CK,&NB[F)AZ?NEZ9@S[Y8@ MH\?@2AMKS WD BR!$)O>&P^H!"*@-'2LEE[(3DE1+4\DN^KY(*4EB9Z79FP: M,9XL$$45"-<53&7)W7X;7OC0%:IV]HE!S?.!PVKXTV];;@I/2X'61%1W%#,Y MPUZ3QL[ZE%_;PD#M_]-"!I2&_*DM,0]:9=X!/CL5&YUW3"!0G4VVM92ZV-"A M;7"C "W/03>)(BAVZAI8/;;V+V1K-A[H^:0W'9O\%>+J23H*CUJ Y^"YZVNT M+G4,BWIIV[O1H\.E"U32.S2]JLSPZL[,3BGW2@>_)]M>T].1P-_DC<=]=N]L M9/-<395S"]6.1<]M-K'G?#5!(70J?!N4!!CO08 1^;[6@@""2PT2=W78@\4. MPL*=6)\7USV4?>C:+#2E=J]B8#\7P-!V*X@82(6PD@FAPZ,Y()MSM ZJ)D_( M[%/*)H AKM\&O]IY74F>=2>M+DBV]AS$:QP/Z$HS"G6,BO:SH"2-24ZB5U-' M^W;X-VY;>+&D:]>CP;-K)[&VVU>X] \,ZZBOIY&J_)$G.X0.<-2 DR284QUJ MI4^4")G; ( \HY2$IO'%VG3M&BK"1Y9&<(="UB!)PNC6V.4)DZDO'CCXG+R@ M6ZX3TA8O)RQ!9XWX*FB\P\ID)Y8FXDN \(/WMK6 ]8L@=MU6GYN-.!'HI_IW MSV47HEGU=ZUP)<\*U-U4;U&ILM>1:@!/FTE!_I2 875TX]'1J4D1:VDK/D$0&N886C!D)U6 MW;;W&FQ8LM+X+;;F3[!Y+<00N81V9!K54B^HX[F/K%0O$6CPRAHT!=23_6.J M&2@K4(*R@YZ_9MWM% CUR)4E\.CES>8ZI@IL7 -AEYQL=:TH!# ]S%:22$?@ M5$4+WW^=1QYCNW:#:S74*+?&RP,TL2>#)9.L1X#=91M<5'O: M!@4 I-.T! (V90[6+*WJ)M6*2Q-%WL+)!M)[A;U-")++D<#WO.W6G[0=;'N?)S4WTD@#1L'([0I_AP MZ>'X5"56]6@_U0@F.<(/+$Y 8^LZ (*-'$9TRZ>P#B;"KN)S+E^:*L(VCZJ) MHS+UZ.9 NZ((0I[N[Y(5,?G6 M1UYOE\-SZ0"-@O(-R7^/[86L?=$\VTI[)U MX24CD1JX+FM^O''5 LK0Z1CN.@'(_%M^Q*E*&>CCRY+0$#6H.!")F]K:*<:2 MS8YK'] #GU?;5O,>7KX!795#M83T)GZ*\C^:&*])5!W#$VVK M&!N4U%8D*EGK4S0:=ON SS=04KP#"/W GKCD;0:]7-;-AB2C)FD'(X!(( M*.O(W/9JP\##71I8G.H$]J-W]N:M1T7172=S]T"H6VW':*S=NCBG8K$L=LM M67XBA#W)5_<@ZI'IQZUQZ?'N706BR>JY=00Z;D_G?,E91)52'GW^;_SZ4,].8)V M];3"PL<:$"B1X..2=XD=BDV*HN#)BLEH"&*7GJ9I>B6:Y75N7'HS#X$0//?> M9:%L,_/&!?#9"24^#S6M8!I*1H(B/.)GWS^66TZ0).0 \%["; 1=U:=5$ =. MQO:D%.QE$%%;E+![YKB!=MG#A[D1NMJ)13?=6\O#ER\4]>6Y@?WA5+&/J&+8 MN96P/5QN^H>8;,\W'*]Z2SK"V^W0D^543SAY;,"?L?V"/!1RO)TGRMXH2[@O]]_AMVV$6]F8^U9%BHW,Y:\N9PJ[8Q#;1#NN),'8(H";D6A:I$#E9 M,E)Y7@'(D(L@Q(A##RYFJ'7N\?MM5T.SD,\Z+N?N1^#[M=OCK<_=U!88 /HT MUF*N]GL#'CQV-5R4(Y"768I9LPM@NK)$TI=3"W%-)N'#59TQ_L\F3+XSG['Z MUFF3]T $[V2@!MOJ/*TT#510S7N[VH<&75F-X@D9 R&M+0VL7-)IPY.9]]EJ MR,J])1*LE6R^AHB-1;;4OU37/ CUIW8FGIO"[:3]9AYBMY[3@XDG6N31YHU' MJ3*RPG3OVM!D^,?F]D5H5<&'3I#?;M-MFY.>Q++=/**Q8NLJ4(B_ ?HP7KNU M=3D'W%=/(8 'HN:\Q9-8@Y?JHYK>J0)WJU-?W1]L,@T9[.H9)IZW%N)CLZI, M[I(U9/[L>TP=LD)DZQL;EPN1O/$D.Q4((Q=O$\CZ\)X\&^+_][!42Q/X6R1< MJO:M=TX*9U!R28LCMEK^I.)G=T%<@ Z-E^Q>7EJ[%( 8:$63E& ]&J+U=D5< M>"@DNWV.' _-GCT$7*I2>IA%FM#E%-:A]8]'/%.3TE1CFSP#J[Z$;6C%8^D, M8 KC@OM9Z#M(T&4['C]7>[/FU9^Z 71C=9O,"X@4NB4/F#8;V-.U:6LQ%RQS M4B%$^JGE'\G5>07K_J783:S_$^R&,$K>MSJF6P=)@L#$B_! W3Q.](XR\+2E M"KOR5^]YD,]VQ8$=R;[1FD2=2G:-WK,P*6#+M=V.("69Y*W@-+N?N*_3ILUE M'A-!$F!JQV-38E-?-;;3'E=--/3$\0TH3JU\.%C.DN6K<:?G>F1%J";@3_,; M1:4L@YP Y(= "5I[-#)Y+6Z0(82VK@!5C((%;31E T&Z;Y)G9FI MD.XU$B^ C#04A.9Q!45QH/**V[*83WO] J"G7 [H@&*CHL=Z$[Y<*&_U\;37 M\\\.FX^LLV(G=8+%CZ0Z-?3'XMRZ]"L\-5:_FE9D*^;%=K0%C-5_";/Y>>75 MW4SJC+[+TYUMPJ'SJP86\2$ZZ&[5WIO%UW0G+)W/>DU#M[+.X.B;,'WRYLBK M$*K'^R07'=D6_LKS6"S#6RTCC1%MT9DJSGA&WBP%\"=3M..>W#85WB>8=(+S MXM$KLVF573O.$Z1- KHU:C7O:(#IA$_5?5&C;1."09ZEU TJ=*LI>Z@.3_&T!2UJK527;55)J3K],CU.ND?T= M-;E9#^]SO"3FK'O&I6/V[75UFLQ*B M)/U5'@"=,^J1L+9*6B./V!S/8R$T7.]I-8M8P&.O&K(! FZN6,7_>K.33Z4/ MW4+DXGHXE>69@W]IP"ILLR8V;8=GRYBD"@WJSNX9Q0CVKP#)B\@Y0;&:8NX$ ML#5JO0]6&$^6;;!L^(6D$UH(*SX#_>JYDM?#(2*YZFVG0R8+/ UL)1* (&VC M<[.SG]>A,85]A#7P#& $RI^J\NO)6.':=6$?W*JO7#>";I,@L56=GKS=2R?; MTKZJD Y%$CW?F#;Z#E71VE9;)=3P"X,<>IV=(*8:8N8]-KTXV*/Z[W5':4H% M5(J#6K2?5FCD4;^MT1X5GBH,G8WM1-A1EHI=&[1KZ57/#LO76]OV8E%E MD^@X^!V[_=A1)'*MXQZ"<'CL2GYM(F;9744'#^M)KZTMZ5JSUFUA$BUG^1W/ MQR](!1&11 *&LK_C5H/*$PE+6-H+7SS, <3I^@F$RWNR?AKVG6M^.W;$U(;' M=H%3IRMGA@#I40GV2[L\9>;Y7,V_%42=FHIWA<:R&QGFFP"U,G*>+,%.=O;4 M8]F/5'35<'1@6IC6V^@L @>*:=;+$,\C,8[+C8*NQ106[BI[8 MKWG9 R:> $\(5G&J0:V@!Z9N'-/*=F SQP)U8T@+ F^Y"KG8&XP["I(K&$>AU*!@. /88A M'ARP<1[0>(==A.<<,'9=[-3/NM2RYXD_%M8U@2]VNT$U7O@3#X65?&J,Q/[S MI*O7P_,X2(D@@R<+DF9CE*L[0,.>5E\_7V7;CL_7KOC=2 AZ+KHJ#XY8,+; MY_&>Q\F'L0A@R/9UJF@O9U5<> ),GZCO9@2$J_7VV@>YIUH>)?2S)FMZT(8& M?@8T'4#1)VD8QQ;5:3K9WJI0MN5O&WEY!_:8=%MW9QIZC\)/G.F[RS6EZZPX MPE9+.@ X.CEO5ZR= (]>DA")J,&N1X7$H&&;%9$ARI+[!*XJW]TO\8A_W"3W7/UV'SF%16G\+[52K'1.UL0G8R]>M0*7/%JAF$YS^ M"N2Q0ZS%-IN.*MGP%G?.AFX"&K@XQS4UV._<==R:CDU$Q0JK-H;ICHT@DI9-Z[@ )EV:-4-NF7/ 11I MP3;>0U]H=LS;/&JU/GON<8UMUMKV&22,ZW[EPJ(ZA28U])PJ-Q-0BQIO.6]Q M_G94$WNK10?;=?+_KK5/AJ:= &4X'>+\RB?A3O39=3N*^U2)/JFO:KA#&,D"ZHKRGM>%R MV$(#X[#1WR/KJFXGJY8]02JKVFMJDR?+!MOPZU/W+ G4#7GA#>@3T0+[F:!P M/.1!,/&UO3-Y"=%&K@G/'P0+@-(JY $2*<&V1;E^T@%@%R>Y8XU6=K.'DSCA ML)N@\B26T=)9295/'3X%C#KV85.)Y<7K]4U69RF[.L$=>,93U3[N6JJNLXW@ MZ.UQ_ 'JL+;PLYX3[-V59,Z>8CZEZI\ X$D&% )0U#=(CR]/H:J+40>#T Z M:G'&-EDC8:=;!;H)L4U:I\"\ IU*M]L^M,J]#WYL3&AFM0!_?90RO6K?=D_K M>B#*!"1V%A<7\N[==1C(JFXR=MQ"1.M.(^D=3&1QKI-X5=7L)_5?P 3@ 0]; MMU[=V&P+F/;1LLP$/^.L*VG3[*]?>G/?S_O8#91X^M;/@AU7"M6?NS.(J,%> M"1XS%SY+,Y6D"KDF3G"*00QD8U?KRB0IRW0DEGN0T.R*5,:. \NUZL%= M\SYXY\2D<]=I/:\&\A)2+ 7LMKNAZSJK-VO+]L)&7]AI92N#]+?\LZK9O$U[ MH+B3U]E7WHN5+)@'RXLE1"J3ML>I#NEN"[*J#JQ?VFC:ZLI[9.>+#2J+#;Z9 M;&+)FBVR^N9)*%NV7<%.H2!3]?VZBUVW9G+VMU_B#-LX/3G0(BB1?K2/.1Q[ MR/&YE&'G@WEH>T: C'F3#.%VUZ[C]?E:V]3Q BC%@O5%W[6A@LLKADXT(/W;K.+2CF$+1I6]$">M\ MJX8$T%+;P^!87<\6S5NTY.L:2SCIK6/@9=)B]26/DIS$ B>SC$$DAVFJM2W8 MR>8N17_F+?D;%M:O%#27\* FA_IYBX(@J$ Y!)YQWS M/_JLL\ Y=&CN#FA;70?.)/7M]8-7,4(KT< *!,E#@]\.UYM@(H+_ 1*RWRYX M#.LOL>>'XV*.:_ARI7 DI\!GQY&J@QL&+NAT MVZXXU^['NK8UHV-T-4ZUQDG244L3R[O*QCM^P/+6Y$637I*D=5KR2+?!@%C+ M]3B4%)V#R2+JN;FF,UN9[QT(:E6ZR]5<38 M--\H Z4I:C.4Z":=&A0O#Y* 541QKC([$GJ[;&W%K.;H\R "6K8*1#&6%\', MQ5U('.QINBY=#+>NH>;^F 7'2[U&9,0'_>R?[89QZ.Q"3;4ATZG;S:HL6: M ];.X4M8=&+44L'9:)8>R_5Y8%.F479-W,+<+)?I*:+=+?9Q@U:KF=<.TU.U MC,S5$AC Y>#>KG"T/?F@6Y?FL*F7:R<"\P,%#D3,(3L1M%Y51)0);I=SLU:5 M6ME^*220(2! $] VF[=AP ; M8W-7<4!EEV@H)<.I;1UV[Z;2YUP-MYJB5N7 _6-OY1CLT=1?BO0'4+7YD.O=H*>5<$$P-O5V74^[]XU J?%4VGO.AHPF^6@6G>7#BKD70-[F'0! M#>:BN&, OP6.; S8>1$W#-\J M\%(@K^7/T!;+OA5BWT-:94F1U%[/K!-+[++H?3Q*IQ ]V6IM[XE7GQ2;A/3Q MB]ES!5"-"V+LPE\&/X3X%!O&WN&HLP#%;DCHCKV0S[1_!Q WG10"E)'NM/C9 MK2.R,,MI2BE'SU^U1;9?FI@Z>0CJA40 7FJ';H'791?>LG, ?/$"W6#I;+2>& MAH%;;$ZV!]V1_ MP*>3RM!H3VVXSA9;# \_#'G+UI6A,2XP $JF6PA@<+SG$^ M"ZUVTL]MF;>G,LBM4 ;X17(F2^2=^SPT30YV/"JYD-VRX()E35(Z;>\, M_^Y(LD?I:1 2@EU Y>Y)O9VVM(C7]"\^XY@.^C3?QN0%\R1L9+:)K]O4#$9: MNC6_NK$67[.E*6T:V<]I;N5X-FZ%J0(GCOO1W2[8G&1_R+CO1S>61\^\,/;1 M'7FXL'HN.XF=^:J$3L+1HWI5T?(K6@JVF] & QN1V"?;P!W>?^_A*: >N,#! M;QX18:T/4%QU /DD-\6LAE.WP_',[,#74;$#DA4?QVT7 4RCJE?#AJ62#"\C M/LYQO+9=0W()1K=6@]TP$U7FT=)O>@BG9V$\= =5*41'TUZT)\_.7R[E=+9W MGV^HS"1F&[U6V%&^U[(8G2R+V]*^ZP]:?WN:D1QN3JKPV[=)P"%XP,SN$S0( MJ%F:)L*R 1PVPWE\PPMQ.# YHSG24(^!'73;A) MFU(BG@:0!Q524-<#> /6964]@I] O)G.A1V>!=Y!,97E3W##YZ5.U1NW\$>P M>K:C;E>]9]@QJB'4;= K\&?M+K><#ECZ\-1\Z1GN<]$!XM4EKQ&J'Q]VTSZ3 MS/(^W V+^HE=TW9'*Z8&!^SP1%0_4]&(:FB9!.3*48O&HDV X_9D@JJV@_Q8 M_;6BLY$-/-Q#]X#N9*NMD6T?9Z-&7I5%7S:-)Q.O;D>Z)0^'[H Q8(W9!'B5 M;0SIL?>"(+>+KGJ<7&2OY8F QP3$&2[NT$;'\W:QXW,[,G 2T-8FV/!X$ZG9 MA^=Y@:2)]-K#G.Q+N#X/#.[Z:$K"L[I>^.8EHV7%L+3D=1XFG#H&PV?AYK;E M:-T1; S6*H-':/L?$?XAA3FW%VN8*F( 0_-9;66)/&H^A)R3@U,NW(M6#.H4 M:(NK46Y1N(E$>D>)!(GGA+Z7&_0PE3X8]^$LP*EE)1R3&WH]U;N!?+I)98^O M/ #-!@R2A)W]=CVGJF5VLOGX.B$L]@P3M(Y:G0U2T4Y',^Y%7TH=;T!P3_-P M&FCE!(9.PZQ&5M N.K;MU7"R=#O/E,P*A =K#++5]BYA!5X6M)VC(1<6/9;V M9"RI+%X>#@!@GVX[LK73T4&AI+CAO/EE>>68JCL!2+0]==TZV4.P%'AN%V(G MU,G:=I/95K9.N_^@'\^X;)>"!L&TR'YS9;B3U7\61_+0L>SY/2#E92L,Y-KA M;["N;>%RIL2;4-5'#_#3:KJ^VA"V!\#'^W2J*&_S9""%)MVN7>"$A6> J84. M7MJT*?9\P%9$-!8L>27K'[_?$0G!IN>@3:)_C ^TL'"!>RMI!M8X]Y33HW6* M[HD*;O'ZB<-L!'M,PBE,!F"I;\0%*R@VCF@,""Y<'O<:]E2?NJEJ 1XU3 JW M'C_VR^NP&;4TNIQA&_6Y20B:CQ:U@^Y2#@*<6E&CGW?P0.*$&STZU#^.DYYU MBWX0OL6\#H/IE/3H6Z4'&LA!IG-KF5C5OHG;0F.8*)?-0#V$26*8CO,45\[^Z7*AN"TXC!%868!O@1:+U83D MP=MX;*/EK[U.,/$P'52H@#O3=FP_NKH]52%)JR!D8W%[Y<)3L))L.N(1'._FQX^.]TM!,6N>%B:KJ6+AG;53 M&Q$5"J=M'9?B&/JH6:[2%:WIM:*HBA9@G;#(BYV*=!2PXSOL%X2O:ES\)&*J M3U +.O"V\38[3<1NULV1/'L>38MJXBP7QKH5WC=2U? U$#I\\X0*R(-007L3=E"+AI1 M5@&0E\NE,5:TB:6MV=H!@N 2QQ9()"OI5V]CP9A1(T6-"@%KKSG:_S64M%1/ M,C@T#@0>4%#2!L\35GLD)X\(0:^-JD4O];Z;>D<&G2<%3?0G7PXCLQ*>'L*S MQW'+PRHF+:A-F6 V\/UXJ O"KR1>;9DN4NAI3K2":XX[9OU/%^8 M5N"[>GD%SP58*\NV3@B_M-1]]-I0^4X"Y@RBO[QMKF]>K*@9+ RM8;=TW1ND/1@;[ #J:P%K6X"&6)E8+=ISJA D;]VH-M")DH MZ.U,OB.VK/#:SJ._M@4[XTEX,ZB#%6^E*1QN5(T6)L+J":R7J?GH1O'+F=?K M! M,&9#]#+^5SN&#TOGMHS^>; MR*:4H^Y>BSX\!%[-$$/7IT: ^A!,AH* M*1ZXMN9R8NB.4$3B+DNXVF@"EKN=U1M*"RN5U6^]IIPKN3S(WFH--Z3C?<"P M?+B2C)I?0[_N\1P$JUO3L]=^_I2X'$]Z[@5DU@ROO(K=V*9^LX+.JL9GL??R MLLWKU7C.L,,5WWEZALJ3L!?ZO M$31E6^J7 00%F.-HBA"=[&D[12$I%\E6"9XFZR55#;FL#5%$0]OC3L"=IP3\ M+A$E+@.EQS**"AS!!3SU^H0!L3F*7,0!&R>@(A#0NE]MMIC7!X(7?)D>&&3] M1?FIY[))C8VEX5E0.T0-%1X.$;XYRZ?JY[+*+$NO M6V;*OJ+WY=_"X<%_K@"SEVLIBN^\!B 2'K!/J5%A7M X$)1-9&"WO"X9C5<) MMRQW7CK[0B@/#RA[:$K9DFO 8 4_W2D:.#0(^FGPQSEUMC,'7XF<\NCIIK11 MV1,AMKL!(NIU6&JSQ2QXU.W,IVTWSEU5CT[MDGU)#J0ST0W<(QE1^VS]L=6S M!7_&+11S'ZQ&I\*MM1+*7KLRX,F)RR)*VNS-+50MS?*R3^4NV6Y_!X?E3J2G M1( DG1),G\/.NMWL\"9BV.OXLDW2VA^K*?YXE/RPX."6Q4(,0'>0J]K8XA?9 MYOAT]W"IETA"X6$"_A9OF0 668^0UF$$(S!G56XF.0](0)@2;EX\/ M3VLZ)W!KZX7;.._\Y6,+$6%3D>@8[&IGK6]CS1BK7HVD"&V7[5:]1JPF_,6+ M<$9X=XP3CK+5T%KO?;9=%>3.RE ^JIDX/:P8Y.T4AITO4LJH>O9-2+)C=7D,,SR9(38HBSSK5T8F M$:K4@!E/.%2_L.G:03TKHT+7QZ;O>?* [NEL]04#J> A@DWWX,ZVYT'VYBK! MT=%C&]V$R4[)7@?P&$B*%& 2.97$M8=0D2U[C3RVU;?/J7RN^!3JD!>D%BVIC_*\[P4

K 1Q25>BK.++Y. QLD[?B M@DDS\,'%'EPNFT.)HY-89G.SS]XN>K,4%#BKSL1NS]&4J/=E9 M3+S==I),8'7LCG)I:=FZ4UPJ">S#^,=&%W 0GZDRF8UC,)97B=&FG.FC""[! MS4[-8;,$STP!C;5-#^>6>&65P(->9QB 'V"*J.KS5LX^522[B/[JPT-(;U@N M8#HIP@U^6X=.WR$XH,G%3?)!&IYXJ=J=[ ]0(F /< 'D2<$ D 89*UN*$01; M(0U)>UZ0ZN4A5KXU_0P:(%_*V+X0 T_[B$<\?[MK(]&"9ZE0!U"#V]*>'G*7 MH3-*[O%;I*/SL/"OOE0)'MXMH.[:HP7%SC$-;6>S-8;+?E=JGO+Q4C3^A9EX MW)\4A+9-S"6]XY.J@_7W;_K,U"*9;.MLE+= MOZZ2=9D'C,-=GXD]Y(Q7)#!/*T8R=>V8V2)D'Z>>.J^FV[ ,%GAVP\H"[FO0 M?$>/MVQF Q;##!Z'E.'=*GXD'O;]*./'PJI%:-4],8U.X*U:E/Q\:]"IV;[L M2@B5QS['UK2_7P-$$6EK2UXU96;I=?[-LX)W>D@R8*K[$37%[4R"0XFPH9W# ME74(. #Z@: 4FGKMP*_)S6OXP JZ+-.Q1F:QCUZE$07FFUF+IP]TUN( ) D' M97.S0(_I.]+8%ZADCYT#ELM&ITOOBF7?B3V&CSK:4:9_*FD"RK)M_ P7__TJ MY%F2,_P#=!"E[]'3_ZR'*LC&V6LI@FK=6;$PCSP6SU3AMGTV)-^PT6+H.!PK MRP-,"U\'^*C+R&VI)TB2WK*G522IZ?#4^MFFKN2)F*JQ, ,;DNY(0.Y+(>?' M;N3C=8Y7X;SL?KL4C.YV*7?[Y.>YQ_A/*]D*:X +8.:.TS^UJ660U!1V"ITL MH(P(K\;$[_@]E)#P!&YS@47MH"&;[PGSUK#L^NBS6'O8ZC=W[$ MI8?N%@0DUKFS3_[(R^8B3E\RB;GA^?/N4Q'V-_GDA)BK_P_<8:5;;UWL[GS8 MMOW)M$1-.E"7*B-@XK=/V,QC'B3[.8=WV2PJ5WG4O>A>Y "[3D6#KJV71]1X M3)FDA]2=W75>**N9:G"=SMH!LHAJ-QDIDBU;ZC MVA2NB.[NYE>[EQWL#)JV))Z#*>T'*+@=X[H;["O%[:#!SHSLR(O%9^=06[4? MEU2Q9J?^>&>D9%XE&#X["!$R3"$)_G@[EXQ/:]D2N^6@E M/ONH+-FEXT$BH8N+F":DTWFZQT%$: _TX?)0W,;GN*?X@<+5,ZA7 P+@W)&O MQR7<;#*=A+RDO4%38]"XH'+*I[.74_7^I@Z03-0L^^JX*"M#3A M4IJ.#=4D>(86KBWCSN*Q>8N<"(M7JA= 5EOR",?F7Y4IN6A6MV%J\%F'6+6> M[.S5@_WY"20H)*SL@.&P?0Z#7PB6!Q,O53$PE5\UH]\=P=,C"Q2ZQGO9F8?VE:,"&#\-K;>6/;)!;O]YD*3U1OF"4ZX*?';1NQ ME,CFH*G?RZ-PE"U7,\OUJZ,"GG0 _2Y5$P&IMVV7K^I4VC" -%EIY-0C*6VF MV\[MC!.@AIC8H.AGY2?9)CQ7,#U_L8=X[TX;\JOKF#1U>HP; YG"J?&Y#MMC M=YDTV!6C:3AQ^7%VG3U9U!95HV3HA]!5P"'6E:I2$OQ-0N8I(X_5ZNIYV&5F M*0%XTAR;8J\3,\2I>:CMN05D!&1)J6/8B&(Q)VO-!G%R@=5G\*C3_-LL*LF4 MAZJ*MP.)S[U/N1P\# INU[*UTE4]);H-.W* 6R0G1XB3!9+[X?]AWQR*V*C1 MH4(LD4^M6-!"(.J"8ONI+90'(AF2K9(R=\2E=E_,5+L%1&2S%F\8.G(01>R< M4$FB&8BN=3Y ":B'3:2QVY2O+F-ATP52$/"BQ#(/ ME(K5SUW5;EIO$9RPUG0#4$76CIY76X-1^KVOML;7X28$B.@D+\R8X.FP6 M'C[T=%&L]=H<, M.3XXTK6Z(\0>W8(%6:K->GW2&D(VPC8];3NOO*@\@)9=!#K5 [Z=4DX*-E6( M'FB<*^#/L>X$$TNAR>C)RJGW_'LG;=(@4D,[@.@XOYW#\&TUJCRR ?X61 P@EOKIHZ)EOQ>=U<<#2+\]?%[C*0\"3Z.0Z)B/22 MB]G',6YQ-I518JG44W:5$ 39[:BTDJQ@^=N\*-;?'=0,",XQJ_X$O?'('-S/ MVSR;[7CV4\+A@2W[R).D'&!5BA)VQQ7M^R-?DDRG/?UP3Y@?$"4ZC:N,GCJ( MY[O;%4'""CL/ AX15*$S:YS$Y?NQ;=+!*Q!8/LC"/8T:XVRK 7 M(\!W"!C7I8L0W"!9,GVVC#;!Y;F *N_,*A5X5$3R!9B2M@0([ T(?]'^B5W4 M5+=L3C?N1 )*DG#WH*W?._6((Z9 MBF,CPX68'.@"&3G\U#QUL&6=#;F%HM2W!EZS$F E7;N*0P6Q-R@\\JH->@), M/'A1'BOK;?9>:6SFH'K4 Z89!&A&<2WK$T* M3,C!D>%9IPDDE^V/D5[OC:=7\K MO]B&AZ>E59TC,C?YAFCE'%Y"T&]VK#TJE4:U7F #)\_?1 ^KRV>Y;"DG7XN' M=^N*AHJ%';UUARRX?CC"J!;!B+OCS'J@ MGN;MFF-6U'A M9$C'B1H IJG7%KN3;P4!5_8L?NRVPZ5- 5O0!MT^GS6/L)R19\6;[8B/\2YJ MD8^VA0 E?WSWD!_NE'AOGL%4WJ,; M-0C5G#8#[@.%]F/84S>*:/"K*2JSAZD8J[1;65\@^75N76SSN'\E3-] MRWS85=BZ+T_@^^.&2&8J]KP5G. /TGOAE9[]&AO(<3:02'^3X+IW**=E,#; M/4UV>L!OL]>Z/>G@*<[M#@MR[EK8%N>8^J$!FIVBKX+F"N_&76$GP "JX!KZ M_]GTX('=K2F3RG:!;[NVWJ:V,0<5"/6I&C$N9C6"=JBI>=MQ8W MP4,D=AQKZM+C _3L"8&V$FS=,+9?DR+QKS:LULU8-I_.&'4$M>4J;S53#Y7: MU.7&8*LHKM1H/I:$"0@M\9P]S^^[?I:S@A=LSZ4IIZ8J396C90 BO%P&L9-\ M-:PVV0H-5&P*O;Q-I'#:K O!<.+M.$&LNFP2%!LTKMH")O%W_,K!JIVG;NF< MTY0:J)K7M:*&>]H&J+ER=Y(AP0-VK&*0RXBY6&;N*$ M>M)QYQJ=50@P0J2B>31!HA]7DTC=K$N%R0SQVLP\UB6[ E3DR9.M1?9A,^;3 M4CM8P0-]!R&J,A,\ U%J30[IK?>4YP1--\*N'-6IS9IA0V,1%>G4RB6KL2\4 M;,F.,H&S;*52]]'B.9]T9(6I3AOV;[=15;$_>6I/+J^V1 #K6U8><9[J:14 M7+<0E>Q,28G<15Y:#F2R-%R;B7RDX6J9-FZR4YZM5C^M!#?+FIQKGW<1PJ$8.F!9)>A MO2!D,]VK 7IE-+WFCJ"EBP]LO#Y8FRR?;5\F,+6^ $V(+K!I\XM>*C;$Z)!7 M5 64O,=D11LD="R+H-%AS0:"L^+8]Z"X,1*D;XM_VSIWW.2KEP[!),3M4ZYE M?%NAVF35'4$[(*,O?[=LYT:EHSR?MM5&&?/2[$5:R_Y(T9#E(][//K)0S4=_ MF9YER<[BJ#A?"4&:DN[VL"RV37:!L?" I:!2LH=2.YI$>DHI^ L:@7D2KQ@: M[RT137G6A^=?-?D[T<%C*X5=^\/!:V-!$/BOW6G:(#J$Z:J:_6.]AG2J$"@T MBH?V0K">>%18!<_=43AE+(2I23%S9:T<]KB2(P!^KHY32Y1Z:ID#.=W)LY"> M\ZU%H;7MTU; V_+3-3^YD$^+@5*O%[AX.[]XJR1H75JCD=7SIH\ FLDT@@T-!N-3GI%_0LU=1 ?II/;? ;-*ITFOE2_/OQQ$ZE*N6.;+0=RBJ0'R,1SG4#&PU> ML4=%,%G''.[WW@V]9+SA22UIA)?UGDJ3.<=0 ,O@2\(%L-,4[D"M _\$>Q+H M8(V0G3Q2T^)G$22+(6O!I(@,FM>UC0"#A&9[QG3[<@@"8^@N8AU'U2_]-;<_ M_74\58TL%K&M%C! B/G?D T*1LL(Q MUW X8VZC7E7<4/LR6,GC#GZ:]=I'W=JDG>\IT9''O3:+6GTLSM+?6BX"AZ_S M?MF;JI7V5_3&WR //W8KOAK>E1D5Y@U.^1 X5.[2WW+IA,%MV;&@B+QRK)=: M1(.M[:'KGZ=/('C\)IDBC=MP#N1"J"6ALG54B6#E*PKL47'<\F^/AK+RN=>&<=99 M M9L#>IX;ILO>A>/G%V^CV+]U9G1K:1 M@36=BJ7VDS3PKOR3QZ$JFB<]3ZW-M6V)\_<'N0E'2!. MJ'OCX7]28SOWT:EGEB7N%_60W,!S&A!Y4M7FW&OD5B7$=NUA?U*Q5V'+;VGL MU'=G']3JM)&@:<8&0M#-T.X2-1Y4._@/VZ=N*J[%T0W-M._]JF.Z5 PYP!K3KH$#7UTSG(M8[S ML/V&%L9HH<_!VE3J& MH]ET;\"A/4+> M>]D%E3NI)*41JEU8]WHU+[L!C0KLUD\>#M-&4Z[J)-)9-B64JJ<:08[VJ\*Y M[%$PL"GH637AU6XZB^U@Y,^C%XXC0V4;$CC;H#"7#9Z::NEF!GP_/-Q)3N4X M$'./]LJ%(00(BKG?$WZH,Y*!>:YC5NTNGFU3 M"OI1I/4>SK[VKNV '>&\5+@L:1C 3OI?)]ROVAJLRL^XDBGD3.LMAZ%?*<*F M1O-U*0,]%*0I&^L0?HB%^BR"U\1#$!(N56F1I0] =FR@%+UE!F@[[3:21ZM! M.!49S49W%Z;N<] M@,U&/V5+3V? H00S=H>2+!C6K'NAE6,%#Z>03:M$P")8THP9C]W':4^JYZQ: M2+YP%<7_I_TICJ?T/M(=V>P@#H>Z;-+9G6%928"LIYK&I/=G,@>]Y\!*S;9*8E"> ^#B@,132?FU@(>= M@4'TKUU^C;5HR0+@K=P0GT\Z*GX4ZYR-=IF?FFTJ.J=#ALYZ$&5L\R!@6W1B MW3R:%B2)(QQ5WT(^E*5#ZKYS)XA, M?V=?/PD47X:A5!+KKMOF$K+A<2W&&6 M4P'7/9ZOY;5D1_$ML ,;0I%\!5/@@LENWJY(P*EJ"9 4V 6I #Q=6NVDXK $ M7$N/+Q5,'<4NO)I'Q;0)+^-1..W"@O4<]E)="T#UOHX!ZC?C!'-6L]Z.XN1! MENV'6K2"_IQ8'3&R;XI&.J$H[4-0('MIR<=_>.RWWANS5IY*GXNGJZ5"T4FEQT#TR[SZ2"MVT>#J6CFK._MZ1KDYK3FR.=?+]? 4^,O M187OH/]M2^R]]SE8RH^VEXHN#*5UE@+X=L?IQJ0;CKV6^B2<\P W$5=V$T;F MD5X5M"EER-MJ6C_C]_0IW<%Y J.E!VCVW"CPJUHMK!3 =SIRR2NV^JFU%NR( M5,."4AO)KBG=A**F.NJ%*/H;98=0=I7/WF%#A-+B%PQNV%M^Z$G%.I3^ M(&(^GB6KVK$TN%$ ST1T 4N'O?/5$U1?=MR]PP9'-U>[)XM,ZTD#/@A\OJO_-')<(4W_> ';+C]8D!_T\_ M18G;O4TW)"MTT?/#,CY2MZ96W9]J1[\: MF3;%IG2!*'O:CAMK8 3%%D-2#94]2GQD VJMKKJH(^QEK8,']A0],R"O/9L; M>%")$!;:K33V4O;!@5RQAS15H5)31;M)LF6?78#'5:@>U+8>^*U5PUG9;44"P6KRN8EL% -0H!X0\4H4W*^Z?]8"U M]1BL,DATRN%(+H&K*3H(RKZS?>>T!MQ.#[83$5>IDJ/JLS'L/G]=L*QKX@E/ M.VE>!-^'*T3B\KKM%9=.)=LKM(D@[Q0[ M5# 9:Q:P\6U..$RJ670=E&+A#= M"(?ETQ7;.76Z=(QR[2J^SDSD#""DCKD'7YXF-8V* M5.[6,7R8\$\0.ENV7LZ^-E4HXNOQ/_0S#W"V)G7VWQ^L@&:BXS7J<:3K)\') M+4!$="C,IB?63XZ[TTLQ1C!/OM1J@M8HN\?C-#=D\J:5\F5OVW0):H'5YTO> M=OJ>-&H%2NLU*$9E21F4']>>#KHOE"H2H%6)2^6$[EP.U";MSX)M[.KM$G=JHK:>\5 -<<*>M<\?3>Q3A[4H- M@R^TFK 8WV1#D3&(! 0@P!Q[XM$5 M1F]C^Z%A2%8TK:;5L>R_BRIY!>5[R(T\<1LB2>"'$IZ.<0U/'OB;MD;J]E.B M+:MVL(:>@?TZ]DSK.,=MIV4.V$D4G4KCP[4"[/4(NGKI&TT"?=[<[Z[WJ MYSGQM=+3^ZD3,.E,QYA;D>KE/M[&Q%M6$\B5CNYV=%8AZ)BBL^OL6_H!: SZ M:):^=-5@1:B/;8F$ 5?NT\5.UGA358 (LZULO:,=[DON^ MNB) [GM,9\S+E%NM7< T&?S)JBZNKJ@&.=@!IGO[K1*5MKY+ MM'B7=$IXJI/2CH<[)SV5CKP$T[8SL[D.:V4BT9I\G/>[+)];38G*HDUK#GIN MNT2KKHJF7/7EMN;9=6GB1I:".?!QCERN[KQ.<,+A4@IS:3<-%M;\S=DFFXIM M05H>7B0%Z!V@A \%*"G[])%CR:H.\L12;AD02+!6]@8@4^"_!)[>AKWH"CLT M&ZPWYF$1[!;?4RUA!\-9@W"!EQ1]P*<5; 80!"=-0>QI#P #\I\].@NUZ':$ M$LF)%;5K"$[&X->TF;(Q/R\/'8@3!_E,$W9/D^SOM7G"%JZH"I)_Q6ZY*^X9 MK]TCT"Q\D=JFYQ&7$N4.=3J:2!)^;7%D U[[-JRE$0G8+M"19@M+\*U< 73] M;"EL2"K\TJX[VPVULLYC:P1!TD7Y*\ M;9-R4A:LYM#3K4B#'=.WADW 2B5EV;0 <%*1D^SPDXMDEAR",=J^SB=<#LO= MVBI4?T;+4EL]3=>JW$[%@E?OX2=N/ M:3.PLK!61+,=$[8$.,COI% YUU%+=Z?95+MNK6E>SSP\XR:GW,.V?N^S.G^H M+;KJI&J\.9([[&=H'F5I8>M)Q:U5*%&'!_-H,WUQ+X1P.[VAH9H#V*NB#V'- M6<4@)X#S)E@U\01-F)?BFU<[;)@K3J,U$G'4R-=2Y'8.+QXK!!:)!USZDF3M M^IKJEO8E0:WAKG'=OA4E*;"\S .#S5!59\-T,=3$<[7HQ^R&@_4 M&$0.32T L%7ZM)GA5-CIC#=OT]FH/4+ 1T:EBWGC!+A7P?+3&O+VT2-H$^F4 MX-%*09/C27+28]OVDZX,[7NHDY2=3U82'^R@+CD+("J+GM];R1?E?KG\+4V]-X J/!1.=']?2SY3EMD+25]KA3;9P> M;T_D+5TM!\3W"*WB, !7,*V-G@] 8D-"%0JS?HQYFUVH#^D&J8YF0.X)P?>6 MJR;XZM/GR?\9@_X=1+G#7G,#MJJLR=./.ZMI\7;#;J! ML!O/D%5O(%UX0@Y//SQQMQ1>/0I624[W 6*36KC6XI3D F=#2K+2ZZ@ M3\-<91XML"HS5$([;%^!Q5I1R2J8$Q>'+6'F'7VV%)74N,'3,=)='$WOZ;OJ M4#3O3;8]@"/ MGX8Q.-U*K.BCQN4ZHE:F1'%ML)](H1P"ZE9#>(Q+(\]2.(/ MP#*X@ :0CH5.&MUB'>QFVW*''1P:1T\OM@%@;#E4YQZ2 ,Z[-.MHCYS#-C=B M3;#K"SK/W<)#7A5-H7,[^LC6WZWI(OP@'#OU!H.&ZRM13-;*VUR9Q3T4I9&H MJ^/SJ.Q,^G\!+J[/9:VE:@V0N2+'6-0G::"SU+4/3I?->"J@:RVGP++!!NP7 M>36JG!Q%@VGN+=@+);&S65Q:">5_V.=^6UH(FW]M_,D:>CX@R6BJM/&JE MRU+1K- YA(?L=(7"8_94\B[6#-G#?,].JZ]5%2CX#W!TI0; MEK(190B:S[""W)K5.\WL/2^!><.RNRTY2RTP^Y=A>II"Z"]7K9YIVS/S-@K6 MBA[P7^W%S(> 665)F$B=K1+->.BJW*3H0U5T-?,R21/7-N.!2A,86+-:DUQ: MNM]ABR80J@Y@0R%66[F04BA&H,]$!7K93@H!5' M1Y&+OM52]@YTL,)B:E4 =X0>G"E M1*N#O*@]:E)4:-L)3[7XE+)EP]:YXG<.,S;&$HJ&A39MD"UOE%+^Q M;1A 6\K6*TS*AX#KNVWGP5AFNQ1_-WLXN-UHY#R7-IHJ5I C;5^?/6Y5Y&,[ M*:LQJN#6) E$Q3'&MI4B@CXD8-V=]77ZY&83G7&VIR$IB'#-EK97N)Y !ZO" MCH>>V6+P95YS<(#O4=7G+>S1[=H)<5+%UTS'EY?+ ["3=NO%-+%O1'N?=04% C52V,>+FO"24V=*G[.U1:73"SYMCE!4.I -6["1$T M!W%?[L9_)4V#?*]JO#94F(0#<.&PBD"^KP#M*ZJE>JKIJW%T@SNIE*\LN,HY M*B,WB-@ 8UCS!";R6[OO@BRBV6C4*T.!3B)I<%C2:N/E6!5I![YYB7K9'OJL MVR:M72/UG#:''/OD:#@I$[F.3WV9VEKHKA 8(?0IJS:"5,&FLV M$:NMY%QRT^^@J#VABCS[NIP:(:VHB_7I#*RCTB4YEW0_,\?K4)9*5Z+I3CG- MB'DS$&6C]B B/T#&4E@N.S$1AO7"H*+"TCT1O!-M2(7%G0=)R/YC^GI2BW%2&9M7+5 "SZ&VE]U.=U-_0-WR MZ9$:V,4&WTJP(%F\#KHH>J<;2=U^4^D%@,%5N?97.4$SU:$\D'K:X24^ZO'3 M;(M11[\Z8L'*.;NC1DMS2O KO^@#U=L-H'VV'2X<_"0>'8JWD3F&8^730R]; M:K=.QAL>EN_0!8^HJ4SM[>%2T.+&@U]V/CC; Y6^9Y@2T+U#\]FRGF-/=7%4 MQ(F.GSOPKPWM+FJI=:CCF-10% 7]>F,'E+\B;:^1[7NH2BWV*U$!'*A1<9C@ M5EH/S&;G3S_9:^J/-378'*)7_:'UOJTS51K_)(+"E3UL(IBNK1)U%\;$0/U1 M*E5]6J75%9'.)2MJH6V:5:X4>=":18 7V2;C:G&E>("DV4*W YILY7T23585 MUBO:KWPOU,)S:;.,FC"O"DAW;[JB*M6A57:Q*[Q!^"OA5V':4!SNUB_V5'CU M[,0T5=LN5=4<-+$YSF'DYWPL""W('&')(S0QKE.?AW,851\VQ_(!.:=1*T[G MB)3352E44=#,-9]\5' 27,^5O+L%*N06'D\$L=YP^.+@SYHB*GEA8T>_IF\L M=J@9;#_87&&AWDJSX_W;!=(^]*T->&XO\MV*?!3QP[LG^7BKKTP+"*-(:=1C M^1F:XDK;U'8G1(T07P\/'6"_MQ!*M *N#HDZ>VG3-GF&DT\3V!&4UM!54+>6 M--F2, B/(J1!4:'A1Z+ &B-I@P3(D\E*VE'#'I0"W#M;,]4,Z7RXFA/; WE/ M_.PCV(MEDJRQR)_F;NSB>W=F.RH.1)I4L$E_!]"+_3RWA\J>YYX:#+2=R: B M5I*NZ/GKM$'4?BQ"QJ,I8-LX.2@!F0Y^2R694*W;:YFRV#_:O;- X%$\__%: MOI1"=X5]%23UB&MG]Z1-5-M%.0#FT9H#0HJ4\8HO)PI?Y^73N/?X*TLJ;MD@ M/8*"[5:>X%XZ!*C;,^[P7JPF>Q=)=2^0 D!RIZ%_L5V\6WO=;MP6#=^P+[)Q MX6ENF0D>)6BCV1@SG?1.YUJ+PQ%7F.S* M<&FTP+UJ51T%[,[*6.*J4I4K9NCXJ3IH-I[VJCB*4@C3LH#0CV6S1310Q157G0GE,/O#@U%1UF4[=S"^;=N+;Q, M4X7BN) 3:_Q*SA%F2'5G.,!B_+WHY#Y);9ZK;GDP[FBV=^,RKP9F9$U9G)\&/53"@M9#0QV,8OMRAXHXYNPQIS,S9._BWSJ5 M5M=C J+^.NI.:#@C2^* M;&(V<,*B93AG B!1Z0N[F@"Q>1)$5CT=>O%<]U& MNZ>RB1V7%JI/^4?N!\3+SEM#L_H;XW$.[(25:PFJ.'&L59=:NU,D4KPAE?"6 MVBT0)A+7:Y?6Z/)-X4<^B7& WE79&S>8G]!#T N"@;"V/]VC?KA]%4ZL\)@N M!0QYWA"SYL?C<-.MQB%N]>NYU3>&-B,0SW:F* B$AV&XY[E/# MI^I9(!$/L/1T]AT[P$8('J^MCU)+]@ [G?L@Y]UV5]U1'YZNCJD#5MR''6F+ M)$!0')H,VU9 E$C@L[X-K@:)>6H#X;SE-IZQ72\W#==(M;S]/>2G&82=;5H\ M=.6S55=@17I =U_'Y':=JE2ZM;LK?/#DS4JTM\F]:N5M*[2VVZ>M%_"XD_< M,55B6?_NI='HA%8[ NZQYVX2(9]8)RM*3#AEU),:@#&KL#.(-(N_#P?4 S80K"9%B3UHGE MN;;.3V9=Z)%^]WZH#&>/*03K5,EH^\<9I]P#:G'P'K28':E8-%RFU,L"PZ,^ MYB"0J!7K#,B:1WWL_K<+CD0.I\\J5?#*]0]I/&X5:R^E8/<()CB@#NLG?1^> M+[GA9D]DT7 =^J8K9]*JQ_@D2"T(G'2XV-U.']U7/V&:C]H*,U^"!&W )2Q\ MC(Z&LWO8 T X$J_S5%JSJ+N6M]E.]USE?"%X^JSL]ONKRL(5OR(IZTUZZ"ONJJGU+\>Q/ NFQ%9Q6N+?%";EL5^,[L%9I!>,[45Q_FX?U MZ!3W1=XTH PM;UX+I3<96_>N2FRQ&8DUMHWMFE!MZ-YB.P+I@75%H&2G]-T" M_S@[ M'\ .-"?NTV,XV_NL_W9QHEH@4'%X$('EM!TDZT5U2^=G!JYWNTBW]A*[O.9+ MYS^[5I57T:#/%J^BS6[=IXZ$E^E!H4ZCMP %3 [CS+2X>Y["/V**:W:=;DNDA494 \C"KLCHKBP34UO_] M?)\G@-Q9B:*93&\R@02J]EI[KQ7AX3[GF+=N?*[HN;Q=V<&_ -LV\Z M*1)*G*H]Q1L\PF(0T[8JF9S,)OMQ27M[R1%Z.#TNC1PQXHS.#-HCS8>=K.D! MTDQ:9O<'0+^Y>X"(2J5;A0P.X^.+FT=>#A!.NII2P&.I%IQ[%P9>JP=9LH15 M=+=GP9I$5V?#*06"#U5C !2@(O-8EJ/5I)$Y08%FR9TDCR-.ZY/;M$FWKL:G M)D5:E+-9(5JGD!6-)$CG: !Y'PNY(&T[!97'G6EQ9AD\RFYYUP:&9PTORA&UOEBZ/$^TRD ASL)]!X\.@'F8NZ6LT3V MA-.ZOCHJN)8U NF$U)K<+'CXJ1I7LD\VRRD%_L;7J>=NU6<[BRTT78.L8FH, M=G^K8\6Q!Y&9823L2S:G9@SP<+X*+"KC4QIL7$O-29::6=/FL Y1!W#59!5' MQ*$$\=JC!@]/#BO-TVL.-&/+,+$RA-_$X1(]<](?*^RK4Z%N&OGDQ*E]-!Q& MUI(CE MU&X1'02J5I<](#$8ZCZ*ACB,8<)?&JRD3AI>&UL7'!A*,LZ;U]JZ.TGS8U*U+*C]V@!7^*275(-@5V4&]H ZX M(KB$"%@LP/52#3@5(.;)C\.)DV0W0?+8Y'*HT"EG)^NM%]@<>[+![!-Y&J>M M.K>F)&^6QD;0!K#4OX Z)&' 0>%E,7?)42- >)?'69$Z@E?5\FK2#7*R."Y3 M;KVEAF=I7C$[P*%-&5*/6;BS_VL'UE2I-R^YDH/BWR#<[5&=7)I !_M8*HEI M<;?V.W&S.X\@2%+L3*-RL78!5K73M6MS-6J5$^2W!E"V,592A&^\KC@$**#N M\52+7BR_W4#@.Z70;QSN2Q=\KMPEHK-Y@?3-L]S9]-Y_+8K%=T5J*8 M\THJ+G#WH^#>I-?FB&$/%N'J[ OLJ^HTE"TC7K+_@:B7XP2X8$]R534O^O+L M;*8=?>IKX]!OC6=I>0IR(G2?<"4N?WH2VC <^-/W< M[:ZV=>&2338KRA9.8:0:!L!UE6;D+)3(2TW7(9K<)8E7"Y68@A.E8(($7K@. M+-%E\9PO&4N*R+F\KK*1*93+Z8E/,\DF5U,D#N"@7\0LG FNKDN'NMIV<[2K MV\*@';V/9?$\'@>Q[&1X!$A1=+Q8IA9'R%LH*JXLNDE<)K&Y M\H?JAENCX"1:K6HJTMB6&61&/Y\P55H%%#J)AQ,FKN4"=U"8LNG!1*@5.@'T MSCY)"OS=476N1[F :JT7WP>XL5.$8%8J+,D[V% ;D.&6DV7)XMAHEY4MF?@5 MI^N-H8?!5"S[$N*92:XO'BD&Y%XMH1.7:Q,;.!84I$;GX1"7">0EGC7ERRCHBZ^F5C ,W9X([-^8H-KL$X\LJQ1@Y[G;M M80;D.C,?OG=IL"1>>[!>MODOTY&7SO<2^=VB.=;'JNNQ!KM&=CX7N"=QUJQ. MS\CEY2!VL]/ZD6=8-2H\":&;#"2A+ZKZ6Y7+XHS7+8$=?LTY#:=G;\L3X&%" MLL5>>BIG?]XF@D 0&2!QUV@2O%19O6Z=[;XEFR'GXA.ZL2A.\%F# +I'Y[_# MFL)2%Q#G(<&Q/"+$BG@28=0G=L=%UPF"V-2%Y,[;!43'N1/WI&PWE((L@)F@ MLI.B4(1 BG2K<.;PE3IL^W206TOH<",[9 O.@$@!KTA6KN8Y60C^_Y"=OT<6 M0.X(Q_!7SF@/[)?HM+PT$+M';G'L5,R+/2YVN0"!V1T2/T<@8U,Z6V(,PT3I MV&=0T5:>*SG?EJRE0W,J!0?\I_.D>+*M1O=J9>UQYG:A\PP3SUQ]+96]%,^R M.7MQ,>'LZRGQXB RW=M3I5["JF.X![$6^&S%C#(9/7*VGVL6-O%'3NO>M4JI M58 WPY'T:UXVZD;[G8Y5,+)A\Q'4 B6VLE@OV(QV A?;)_D( L+"X7EL][@L M[BQ1,!YOE?K!Y+#][+L3\M9"=@E5 D^S\+R5.)%7S_D=(HV"E0J*850M6"FG M"0*\:6=,NP4*MR)BH<8/>D02[!G$A>>[$X%8*7%X7*Q:+I@KJH1S83)7#,"5SS!4[%J*903T\J8X#&PH MVM?&VG7$DI0G9^"P6(0U"K'*F5V !_+I!F)(,=4L?*I .K> M;1HW1S?!C.S&R<[F02LI;(T7^[F5F*VS'ROCI"@?C_,Y,;^F#K&1V2&)I^V+ M=T="%FR^YI4XQ$#.EB:@N>Q596ZKVZT.98(XKY="X)?78$>-TR$VV1$=2">C M=F74AQD&XZ5XY((BN?W5S4S9H6, \P281)!5 '83!RJ9FELVCW59@SU2V-?@ M6'3&"3,=GI1!=OP7;\:#"7H:CA/AH%T)J5WZ-R)DX>;!FJY 3U;2:.N;U!RG M"B)R\N!!LZ2Q-KV7LS!@YP.&<@Z2Q@A/6WJSF#M#^$. M,,L*V6/UF3#:06?G[4Y3;MJ@L6596YS] ]>=H.0EW\Q./O&>MM[="F^H5[:G M)46/Y2/*5-U19B"+KM+'/HX:ERU*&SD)3W9V%Y^[X*,54T+MNYF6YE+FZ@TQ M5624OSO'JE K^$\:J6SM= 6O_<;XJXI:.'-+,X_2 M:'._6 WYTVBB="6IK4][*FMK!"F\CB"8J(6 MZ7!56%<@!"WA)AJ-+K$IU)XMWPF\UG, M>/=TC6V>?Z1I*UHG-2GZ0;P9G" M13*O+ G )5?+M2\Z*WDV>=J'QOHF0]FJQ$8;<3!5 M@9][)!KG*M04,',@O4386&[E!62=[LG)8:/F8U'9@SYRG'@(=IE Q"N\AAV? M1''7K0(;@5>6CV\8P(TMG8L]BAB@RLS"X5+^_1ZJ@9W#='"VJSX0A(#T[.$@ MHLH3*U+M1 IK EHM#^S.YF 9!S'I5,Q;#J=+3PNONGK;[[C%8W9-G"1J>+9[ MQY06;!=H$Q!M_O4T+8,].Q05K2D.T<"I:F'%$G0IS;#EH-I9JUB[RK4@R8*# M,=4B/RO+E59%\J3N.<=6FU):3A3A[TO/HD?#(_D&RVG57?8!5=:!Q]GI7H>V MB,LOTRK/4N;%HSE"P--L1%-@-J=.1I)$S(E8UD#9+AL!3TNBL@:<*TT[>7R+ M5=HN22OQJ2X.W^,>.)2#&)WC%3I?=@QY(S$U'Z#_BNK\0Y #]<$MP@ M9WD68 KTBR'%.F?A02XB=]P M,((-I*J=NAS*@;*[CLW<3E)N*SJ+C6GC_ .?M>7G4.G7[DDY_&T_2_:4./EF MGXS).) 4AF6J4I[O:\-@G%PEC\B1RI&;MB@%Z0YEXY(.0)6S65 M8I?!FU \2U7*[V 0!QX]:11/O@,_O7SNQ]VQJ2 ,J!2W%H09T:3#) 03U *1$, M94_YE1.HY%I4JV4#4ELL5$5Y<3(Z(J7T&6=.Y]44YTJQ/@#8*WE?:WUN&+M71@C/TV WL\+05"(=G8757FE:ZW[%D M'=JQ5/XVWK(QAH<-*AO2@U;;39),DR+.?OF=*^-R:TK6A+L^E=NJ.\2P#6U9)WTY'\?)]N) MG _[R+8UX2!749:.Q9#\4/T/0%!L8#J(0P#W9ZR<&)Z,V86LO"QA7U!MXVXA M/@KCLH*;G!V7NNNI[)<]S;:2_E_ZS_;_?,#_+3[@FW=O7G_X^/Z[UQ_^:=NV MO_JK^?VWS_OO/_)OYYO?OOW>?__;5]??S_\"R/RK_^$?_O&OCV_?__J-+_]U M_)OXI[=>Q;_AL_[JKZX/;UY_?/O^^_OUQS=_^PK[FU[]NY_>O4KY58I_F]+? MELYWO+K>__"'#V]_^[N/K_[-]6_]K?W5\=V;#V^_>?W]J[]__?%W;[[C0[YY M_>[5/[[_YNV;CW_XFU>OCG?O7OT'_^3'5__AS8]O/OSSFV__9MMB?/7MVV\^ MOOJUE[K]RJOZN^]_\_[5_NGE;W_ZX4]O_?.;#S]R7:_^C1?Z;U]QF=^^__[= M'UY]^^8WVZ_^_7N^[@T7\W_ZNO["9?W\PY^?WKW[]Z^_\^/74GWU_NOOWK[[ MPQ]_X_UW/_ST\?+N[OWWS[]J?O?O[NWWU\_>[M M-\?WOWWWYE7X]-+;'Y^WOW_S[3^\_?C-[U[]YO6[']^LU]]\_^W/+X*56Y?P MJS\^S_7J/[Q^^_W'__B''_[\>?[:^CE^_IF%^?#V]Z_^M\#"1GZ1__O3O_WO M/_N6^?TW[[]]^_UO7Q%0OWK]X?/5G^WAC^]\_4<[]_;Z^]_^TNWMY>7; M?^'/N<-_?O/[C^R'']<%OWBK_?FM;]__].LOWN(6?WSW^L????E9W-RO^9Z_ M\,YX\=3.E^_T\/*I??G6SQ[UR[=^_JQ?OO?5PW[YYM=/^^6[/WO<+]_Z^?-^ M^=Y7#_SEFU\_\9?O_NR1OWAK_/R9OWPO_H6'_O+]])>>^LM?R)\?X,N7RY=/ M\.5;]OUO_+]_]T M8+Y\]>6)^?*=]OGW/[^X?_GKG]]X>5H^_O#Y]2_.RHLWZI4[/SLG+]_Z MF^W!, KC^_\[,=\?*MER?DY15\<3Y>OO&%R7SQ[5^:S,]O MM)=[X+NWWWY^XXLM\,4[?[S]-R\N5*RWG!%P_^4-B/,^FZ\77UN_,%XOWGAI M(E]^T!<6\N4;7]F#EQNB?6T.7KXMPOOI>\*3'_\KG_GY*O;XY]>_??OC#^]> M_^'S6]S]-Z!O /J;WWYX_>[+O\M?OOG5'VLJWWX@]/OV_<.>K/VM_ M>O.'=S_]^.7?[2_?^NH/^Y_>_>ZG=Q_?_O#N#U_^\?CYVS__ ('BCS]]]]V* M+;_XVX43/[S_]J=OOKP10>)?7!L1XEK3+U\MGW[]PX]OOOGZ.^H?_V1=WI=O ML23OWO_6H/#U]]]^^=;^Y[?>?_CRG?[B;KZZU?'G&_KY6X+"7WJDXT];Y:LW MTI=W]M7[^>7-??5N>7E_7[U;7]SB5V^Z6][_I6V[;]]\\1$QI!>+-W_F/5^\\W/O^>*MK[SGB_>^]IXOP.3/O.>+=W[N/5^\Q6)\>/VM M#^Y+9)K__/J7OU]>_O[+-^K+/WCY1OO\%R\6583YQY=_9J*C$/./;[WP)%%\ M^<*D$V6\0,KAC^^]_ .1Y7KQY?>F/SF+WV%?OGW_+\NNOW@[_^SM3UF@S^^7 M%^__],//_KA^\>;/__1%?/3%9>Y_,6Z*J?]BJ*63_/$'OFB]]'4"YSS?__Z_ M_377^M=I\+NQX.SW/?WW+W_S/WW_]K_^].;O[E>F@'=<@:]^\],'OO+CRIH1 M7OSIY]^\)I@.B+30[M#KVFWX%&.H,AOMW]O-61?5Y;,N)=8@L0G M_5S-5GF$.(NZ#'*.*)TE>>4?5N:L.[0HEHXM7$;K%F_SBPSP9K%"Q)A5BO(-R&U[56GI/GE>:14 MN6MS&+ZDL,:K)4O(_:[]MOP0]NUYYG[+=ES.>16;L67.V97>2.=J,4YGMM=A M./.JKN,=K=Q%IPW*,<9U/ [3.+2Q[;?-:N=HUR$YBA3O$@WLU::D)'2/K>Q_/D^2J-KC%[M%V+ M$?PN\5)_8+_/NSY/6,7$X[Z+_+Y2.3@',4;(Z>AY<'WUD0#7!R*)I$07/)98 M+$<]R0X^+JN.^)RY/7;_/4V&TM :WRN7D=1K/P_N8U/#/C\2I@_NS[8TF]H=_G+R MZKBO._$\[!E6C_>\I4(?=U"I,; K*G=I@RU?UNIV-6O!LM'<\RSS6.U"A2V1 M*_?G(.S1Y.X?;LMF@\*(URYKB9+UUN:YC[V5J_6YC:J$BUU*UU'"V?!F MN_3JI63VW>YDY+QM1+[.VNN\Y()@.^=IW3M=UUXE]2_R0&YGMS]_CL?YD7[S M%!-G3BDAQ\K*?%42$9M&<*6V8%RDB2]NWM MOB4)D7HKLUUF7HV3,3R[0Y R1U=)>MG\\YHA.G.K$E51P/#@;"WYP<17['81 M8MIDOF>%U+FJZCO6O;2JB'#%I,:GV$P8VU :\9FGO,[8!@DZL:);5+%QZOXG242ESLK1U3OW'\9BO' M4AWM/(#99#2\@B):)8>R]$8"A[#Q(-C$'=LI.Y*3DS*,Z M'\[;5,\GCF9+B61.BS1-)=*C87NZH-6;W/_(A;SNF M[[YM/G=%6[!T[7QOE!576;)3Z0"6C2.0;2MN'+JET)X/3,8A5^HSHS.*W&:K MI\)$#\_V8L==BE3*'HX-4D.;6U).5;&L735$GAYK?W-L'J=F[<$*Z\E@]+>H M#!^'U&F]L?. ;^E")@;\.'5?^:[8UAF6$O50&,%VR0>3FA629F7O=#ZVB'$V M4X^5CQQE Z0QR>=LB( MO7&L[=7K#XW9B]S[]WI-)QJ M/O9G&_G4XGCFM&;G=0L$AMR.F'W;'/=+IF:%6QL.3#X"05IPV1CH!F!QR6WR>[ZD*_IY:TQO#Q<&PU?*< MH6SV=Q_Z8)E"@"WX44[QE&SWX&!DM<)FM4.KLV$O#FS&1&)B%YOWP74X\K&X M /MV/Z[5*?<(#Q"+(F4^IB5R=6(E9Q5LIEI"ZO/JJGM(PGIPLC,/V>?YV+V_ M[TJ<'=)&J9&+[YS#N;X[A0!T.H=$ETI5-YM*[D^]"^UQUIG%=6I%SOQZX@9.]C;-HNI[=T44G2B2K=-;T!@N5 MQLIN0Y[S*19DP[7=@7X>E10(57+RK :>%$?AG+LLX1YE^1]*P4@"'KH\;DJ[ ME+QO\\&D V,<(?*CKBIAE;VAS]W&N ^%^*)$4%EE;9RYFGV?MA;[055D10G* MZK6.=@$];,B[GHH(2F;'\BG<+O,*R,>6,+N868R19"=+TKA4IP=4SSS/RVX_ MN=]QPIZBV8!CS^5?^-I LC8 M,^WNQ[:85WM)TB;/7=++'%4\Y\%+YA+=MFHM2R=U*4#F)"QN9$I$Q'(DY;"< M',-N\0 JAA-\J<0OV+//HKCM9'ZA\VL+R(4K[857W;;VE;Z60;*U(D#=MP$E_=%KP* MCK$O(M%^/!OF $3&2CA#7=VA]MYV%0.ND494+_.T98BH33.BNOD.KE3 )@QU MD 5"DC"7:U-L218%;!SX4"8CC5I.DRT@]QH&:>D5.S,?!:&7W%PJ* ($9+QC MK6[67&JQ35T].Y+5@>RX.EO.XM2S.\(5U.>I;DUCN-UMO[.#3D>Y]^:4N3WE M]L[)][[A0AZ'-L&81'0A EFB-[=CA^-@_X\2EDSC418&M"W9UK9!:/<$H=5U ML5-36<([I:JU)*T"(%%7@G=T?B(E[&GB/:PE+KC>1!BYJ1NBT\+'5@G8L,\< MD<)C:_'96%M)5&5-B;NSXD2,0&5.6ZI?11F '$J?*SX\]L<>ED5POLM8CEN$A 7AW- MD4Y.1R!&MV.28",_N:HO*.?G@J.+GD<.?0)X:0947,YK8!L@TAV9E-BK=6>L MDVV_N>8MVS-]*?QRM8--(TQ^<71S.T2N7#R^E163RV6G7,/-."RLY/6 M#B"70QF+[71BWF&,1"C%UGX>18@>X"T7&7:[?N/3*H>[S)?JKX(E6G8V#*RD\#WAC\Y6>C7<9^,9<'VX.Q[HX:";9,3L MZ*;#*0">>]^&DWP#GW*EO-KO[9W$-O!C.4[V--:( MZ//&HT_%(9X[;&IGMT-U+YX:2T2(L;@JP7]$#H^4')=\2E(MJGA.A,";H'*# M,:G+)/;N=1%(;3CKV-7V?I82O;#7^3^1:JN2[V%1-4(.-F,-GJED(,[3]OAE MUG>5@]K-ASP;Q^N13>902A2/+$D[ED:Z?*F% +LRZ#P\%BQCEN&UJZ^) 7[4 MII7XOSEG<9[IWF1NJ.H^2$$U@K_,@68G$GIA+#ACM^D_Q\\Y.;/+\>B(M\SX MBEH7]<@.N[!GV)88,QOC[+=,_&Q'!U$![[+[IJQH0E9:"R#<5' VM@16GI_& MMXFQ@W,RB@(15%RI.9)7L%-2BWHY+Q_K B1*F=0*([$""I,!'I,[ )K%7@ M 7)CEXWF3UZ4+0=^ F[)LRN6J)WC*"_V8QI"<&WC!+9U2NTI]7)0D MQ9(?5Y<9Q1>DPCB)%D\R4:D))>GGEI0&O/KOCJOT8]S3XO!J( M)ZT)>/Q 4%"'+S]/!P045)#7J2[Q9_;-$6ZUTMTYZKRPE, 970 H]\9Q8YMO M$/:AF+9BZF)5UNP^-J 9)UKJ+@S5^;!4&"\ W:ULE_F'4]IQ/8 =[.8OB",O M?8J'X+3U/QD$37..)T V2HM\GQ)_+R.-'\O.^!S.25:"IL>N:P(UN3F"U"CR M@CFL;;(:#(!K<>QX$[2/:EZK11,6!$03#X=Y3&K]!$(:XA0@3TLF<@CC\(H' M1HQ()3FTQ4Z<*K7ADC?,#JB0D*ZM>.8ZB 98Z&341#QS:".0]5 MWIMCQ_&6*DG]%>X@%/-.J>RI+1<-++ O5O- MGL3I2FO@A(W*EI7?JVXJMY]2@:F+@TR52Q"X09VX$056Q8:6^) 5MBY@%HS9Z6X*66)S:J^/"4A*S!FIF MZ8 4I;_E/0 (.'JZAZW)B>6ONC< 1ICZ2S:/TX,8P9WLXEVM @)E30, V@E> M!=/NLFJ)G\,]HD7"0V")-G.P:D#:X9"NOI+)\"V!AFH)0LR MQ"ZQE8'"1-D@#D?1""J62DXH4NDJL]K'80Y!WCOB)$X-6^/F&P?_.5(<)9)I0;P6@4UY+E)$&I,=^0;!R:S871,XQ.ET^50.5:/('Z-&U\ "RZ0 M> 8\*[6@=+M*T]QJC=\;%N )*]E-+!Z<*C8_KV)3DIXQY'K+N!&GDT_$<6;I ME&4]9QT)NP6T?/ PK&Z(&U"G3-6KCXJ;4$Q#^0""))F/'?B60P$\QZ(3Y2O! M()!3%P8KBS%4KF<$4W>X0( 2OV1,\/YTXJ M5(DQITP=D?/^F#X'!52)J107D1N'C^B'6KC2(ZDS7DZ'3 ZE$!]S>SR<(ZO MY'0ARX+18),\CF8 GV6JPV]>DA.T)J^A$X:R0*GI"T@ETLFEZ>55YB,!O MW=.)-9B+%^TTOQOE':E;D22B21_1NU-6@F*%181$-38)D G*^WXK;8TC .W;^)V(Y$R!YE.GLV,,^CO!M1;:X\I%I2$FON=U='CH/:% G*SL9I&@&! M;'>\$@[EB/A()V1O(H;6QS:(CZ?6KDH&,.NSRXFKS=7T#Q.1QB-=.L\JR,>2 M8.%P80]!*NBNJ2D,&F%7;IRC1UE.(0IQ(DCCPY#Z:9SL>-&;%#=! 2LZ5A0"D!/B/3(:BY'NX0]%\_Y" XWF6%DT93T MNY9TO!/:8:9;ZJVE%<%M2EH@8SR^D[_2]C<)ZY)%5&)\,R-$;/4BAB+F=;P1 MTY!4@3FB$3_FBDO$#I_;Y-(!:S=.EFLMW"&K0 0X !*&&F>1K"48\[.Z MT]V.:S 0"U6\R3$X^J%N\H-; "S*4CY-)F9S6DF>I#%EOY6B]*[6 L /*KD1 M7W9C@E-'B/L ]/'U(21='9$"V'M7X6Q(_I*>([(Q".),KATX.-4FU&R[ "^G M EK7\F4BI0S8/Z*D2H40T=&\VVP&$02V1;K[Z&IPSO'@[J=N%8-?4.!<9OQ3 MJ\..2CAW'FJM>[4>.ZY-CB;B,X]- =SMGZIS21NMO\.8 NJ3:A'2Y.8E9<[B MN\VENYJ$]$KW@8O#M1V$=6QA%EM&6\4$.:21)(?DOD?ACVCYK#N0B3V22V11WM, M CYEYZWM-&>YK3TH6-?4FU) $X\L!0&KHASUWJ4#!+T2H]UFX8LTOM@U92VP M$#OQ *$L >YIM)B S&%N;"B'ELV!A<7\:\T,T] N;@\K-Y5MOK(ZXONN<\(T M*I2+B5$E4"+K0[W".TV)J9KB@'>7"*(%,]]$36F7J=")<-F]\7XW[IU86>TD MD1Z6EA.03D!U%N%=JMFGC:/!265K.XR?L[HD._X53&BF)RBL M)X"FLDO>2- M=[UX\$N&O@P9EJN$HA48$C<96\QR=CQ7C\[@6R67L#,9**6QE(JX<3" O1N+ M,B\I(R8ENP/SJDW+]E+&9ER_*SRQRAWSV!5G4+<*[V% .*M4/\N'-&R+W3LS M6TB62 3SQ_OCSBRO+1;*,-C!8KD+&ZQX(^&7Q2*U'7MAK=@]1#RM@PW9#*H( M2J.A/M>5',:_K&74]NQ@6O7"XR*H4+/ 6KMD'*SJ]%C@]T'5%P!BM_M&]AX, M >YUJ)1G1EPI+WS#Y 2DIKC4D:0SY,"IVW,!/^N.]>&"9%:Y5R5>6ASQ*'C@ MP@ ZU'LOVD"B??EFRPR;?MTR>YU*7T9I=)_(1CE,;#JCOX@)3H AR/*2D=32 MF-/RJMJ(EQ[CR!2C]4"3R6I@![ M1K;,!FPR6L>O@()+V3#09ATVVF07;<$]"Y57V!(9V^3CVBWV&Q]QW5J)*J;[;/I54V%)JXXI6.I/\3&P^ M[*22C.Q4C1M7-J2&7EOCX.;C[NP^X#*IOL!IER>JV>"TE/7VPZXP&4?5%RE9 MMOTP5;?2?F'X+E;YV=0<)1 E;,F+ NLF2K(K19;):\W/ _L\3U%*"/9PT$OA MM@#T,H-=\D;OJF#TLN%_Y;<^VJ7B"P%A$:OBTJ37)G3!HJW(],*E5E.;H$M\ M.(&,2K.*NN.7\0<8S[9)2"SKH7D="VN#_\,6'P5P:K^6)#$R-EP&/WCA![ ] M3L+%6$49\MA)7?A$<,+&P>K2@7&.:ISUCCR /9KGDUT2[+T4 ^Q* 4/+?5HL M 7 @6+ZEZ4J]7MM,^A2ABDXI(P Q0QA&=S#/[I'KK]C")B[M"=O#VUC) M^\1Z /:GI ,ULD.S4&#\IZR2DQ@6+&;Y^"T@Q%P MP<3)6N<;)Q(G43RNBS^8VR''H5DWVW"Y9I/XYA@;B-BR9%NKU<'@%H12MU]H M'VMAL5VXB,YN4)O'5AYV^F-NMLJ28U YI7P%5V/N;$8X;7H,&.,J0:/-PEA* M^V&Y@"$[TB%CM]R(\P"?]453*'/P@SD.3S-W)'^[02U 8ABOF_IB97$W=H6 M1 #+5?HO8"]WU(.]*EN1B$3M:Q41S(*K/L33G)]:,%0WK$1V29I/<]/R$7$W M*80]6<"1E.E2JK?$:Y.*DC"L262[ R-Y0->>&R'T;CV/)5?A&0QKRPWA6Y#6 M";!KTO*V=IUYJ$!X; -^LP;QIW?2.3/S::E$$*XRH_DJ6*RZ5(NN$(@'H@S. M4KL71? F8-+NRT?).IP-'R8;/N\3HZ=1FI1XN!)+^0_?&Z7N,J1E>X:U2-+# M[XKSL"[R.MI,M_)2L_%A%UY MKAJX&&#V5TY-VPWY7SQS "19W+=M\HT>'%Y MKI7M6WDKLPX]7U(2AK#9%E0EK0/I[<2Z4S-XX4"G'3<C5T!ID^ ,A1UL.EPR&PE7$*FI,5"X0-.OQ MM ?3;QI/4-S&)/#6VG)4X.]'D5>+C8 M#]4)?7B*)QM-Y;GCW-@!-IJ";6IO3Y(!37/!TA"KW@)ZF4=MM<4X3^(I:Z'8 MHYS-5&:[T+I-?Z,<83/8E;-_7"(\S!8A0R,;5J:_F+AV<'I/)*]TLN61T%[LFL>$_Z)!LYU;*[<$/%S"%/I!,GC"P8 M[(26R7XC;C9)NSBWNTN.'67^6]W/#<.2?7HJH>'Z"($XXE?$\A";<;^6+PS% MM9R*)+'3#S/[7.DFTS]X,9EV&M;SI/$5PG"XJG29S@4T^[%NZXFJ(DYAX"0H MLH&#<#CHJUFMMF7[&'?9V*L$6_4$*WEP1VM\K^WO^*W23[P^%AB<&Y_6U2DG M%)?355V(V\(6NV33"!:9*8%P%RMNI@9@5XE GVZ_>+-EC[N]%S/3L*\)OVJG MJR2,;6%AK P!];GA[UN38@_/<%X EZ0 KN(!LPR;!7BJ]XY+Q@#+7-<>0%?4 M%5=5O;)=2^VR&['U38#2E]B@^O&L<0.2CVANARU: (6'XN2L4ST..P5W<]IV MX.)K. 6ROF.>C5WBICB+WQ>JW$DKO6=CS;&4%:3Q"\-A^]WDGCB(C;!^,[_^Y>%KYN&[S#)!S M"-O;HSBDB5? C55$-4KMGV!K\6 : 1L(+=I6B8-O)ZN]:.4!QU;64^#?0&R% M\R.7&?=@"Z6R9'/&C7.;6I(K[)(7CXA/WD+"=0G/U:0#I$7;*2\Y_N6B9ZES M7*+"\B<^[ $EG>R?WB2"QX&Q*D>R0Z'(;#T4W' .!9-%+()I'>9$)H;KD/P: MF&R$3)QI6]AE\X>[&DL;9*,'=5[V5JE[P1+3;&WG&LM)EAM^^R' MS<.]9(G\'JQE/8:2%&E3DTV914*T=!MXU1"C;0T'$))3HMLE)$S$-[8@3H_5 M5'_ADC5:P6\X<[BVKD$RXQPI'!WKD##OM&_+VF^;8"^;6T_ MXRM]31557MPC>"%I RYJ@%*?+.Q@!5AD81>UN*GZ]>EJ#7<2;R06 MX[S@&W0(BNT!?]@E(,=HKNN62LV:O,U#IP@^:$?+&D[LYF\$FLR=8[GZD)5:M!;N/>R#.BFH0%PYJXA$GY8MY M[784"%0>JKU;R;ZO32[NZPE++CYBOVW/4"]7#:TRAV[Y"B!$+MZ%OT4\3Y)$^+2L67N\5BWFL8\ M:A@-S&7DEXZT"2:"%0&EF7?L4TA];RI.KPR'2IE3Q*50L03*&FSV:>]8 XD: MI0&_U7?EE&Q$H+RCP;RM?]S6GM06'>M6<+F='L!_&([A[\P)V?E0^D\B! M,\UA!%N7U#= CTHH.9E%>:205_P7@]]D83U98^,$[/F#J79F0*$>4RY1Q66; M5K$)=KY.D"/XUITU>:@@. 3N(FPVH9'/)Y]X#8X6$946'?R]^HM@[X/HJYH MS70H@RID[QNN$H/$03>*N6RM/DZ[X\&?#7Q>LX)7)S!$Z'7:8GY= '(SBU M&; I(Z]=+OETY%(9+: VSDO)0&)&9N6'N94:>Y%7[S7"*/=HNS'%9.@]VJ MQ$][=.1&H;^\J:FEB5];BDMWKJ@:-T*:H&M D64^6F(\;?V!G[.F8JE)Y4]5J%=(;#_2>CIX^ QE$R9$S'8-CCB)\!UL#4HMZIG :TJ5WJZWA:@8JXWL"JM[M.=JK"2P MPL]A/+.UP;\QXBPPD%*=3XKFH8 ,64>5]$H M)) ZQ^*<=;LOS$HWHX]')WQEYQZ8!#M3[G"?CG%A575D#B<93N- ]EU.3]PM M.X;'8!B+P;XWGN5A^VI6:#/F01@NOZ^KW$ )P)3;FK"#KU&1#W"I1MSF785; M[;J8CM.R1G6S[QXR8G2U17FJ>L%*5((7X3$?XD,0J1,)>S.H5FP)SVPZ,H[]NC.1TZEZ MW533&9_^$%EM[5$R4HR)2[#6EPD1!*3Z=:#QT_D4UHQ#@=,:BH)H:[EZO[(5 M_#)'6XYP-8!/@%S"SL39E81Q0@@;6.W44HM!8.=4'U%=&!AW#H;^(SG;#!IS MT$\%T=N?-@ROF/A1__S!-L9@NS/AA&,'RKX>3S=/YB+8[62>-7:<4&!1'XT- MJ#LI_7<,ZYL1F&%;>50$B-.87&)97-L:6G?\D)#K5OMS@HU84%7B9ZTV/TY!T.$2*K/VU0ZQ\]]@^>G&F]1 4,*I+-TQ7? Y M.QE?TRYE:6P@10H;/%@)]C-=D1E:W0I&. MW5G-97,VGG'R4.,/3& H;P_Z4<)V**WX*%Q[GEB,LDM:7XAU"OZ?<$B5!RYL MFOT'3 ,_MWJH.<$)#F.51' VEZ>0)EQ"0QSUSM6)1.;3)WYSCGRXP'OU;'C M9XE6S:GTE U)DB4[0H^5;:=[*+$K?%2/JJD8@%59NI6W4?4+IV-#+''W%!IP M_N1 L#%+'48UY.SQK*H2'&HGQ6ZCX$%$>=9XX=3L[-_!DKA.L*0M5C9\<<=B ME;;&X:\-F(6I>;K3L3&MII0!QCH QT:;);K]'.HLT>9R%K\U$YO7/$_LM8*% M7>5Y@KVX813L2[.9-[''G \2[CAW0>0TU!G:Q5("$ M_0K[3OC$"5!4%9A]K5S@ P[D]Q3)[BOL=)#*:8.G8NN6(" VO8/]5*IA560P M)^A_U &X-]4'C"$%JBJ7=()0FX!QMNX.45H*/)ND2U H=-%$#-#49\YBU@)PQVIH-GH]J))+1V5H<::6$P+ MSICE;"HB>7"*?3&V[)@FYI8\)MSA&XYU(]L*>1P6UG_R;0HJ3Z9ZN[*3@35DA40=M^,QIZ>+AG 4L[S,A9C M]B2J"Q)Q7* 'P!A[?,1'D6VLX]D)H1P4Y(C9('GN"\* B:2_/JW:XT/CM5@O M;H _,-2BQ:EFXXX=%EW,JG&Z%65081B(_!B^"!\4AA'F[$2+ZD5RX.0#?PX\ MM>VQ4^IQ/$&N(EZ/WD MLBGXW(?Q][YZAVZ= Y\V@JD$P3M H)K^[=C8IA<)5L45C=F% K;A$+=@:D!! M )B@7"V(Z?$6<"1$#)R>3C!E>]5P$"(Z_N6PD#3_A]4]$2U+K-4BX".XKV&3 M)-PY&AQ@96.H9'6;O12X.%&W$VD 82X3V*S">?NTUC-U?HT57UHKE_+B=0,) MYL?QH$A<:GKP4Y-;Z4HO+8\K19CR<%54M%QK.ND2#7$1S&S@V58, NA2,J/\W)S)2@=JU&PN^%RO^].SR^Q/$R):GT#%]Z4HM\(T C% M<;T@8@5SYNJMNIQ 6$ILRCSP1HA#P3 @?;(?58S!=0].//"3E??F[)1M2D!QTX!J/G(A5^2,*H%NGM$V!?; QDWTQT;? MITF S_[!4==Z<9#E.2$:50@8**8*EM5PT(IVZI8!P9*@CJO6/6$Y""H$(H^S MA6IR.H7"TO(Q1@I%?,S-J1[C!S0..#[EN36I1ZM3!=T3+^#@S\.5G8<\(6P^ MUB>/'N3P42GF%9\42$XM%^Q$\]&!YF/EF1T&+/(U%DF!JF89F([5?WI1A//)Z 8VS$N1GQ+35- M>R0L130G6KND(D(BQ=>Y57:MXT+6,[2E! M0+OG+MB;V:GPNGHV>2C ?8)E22EP$TNJS.+\7IU05+DORYPQ,WYGFQ(2V$F0 M]FL-3$8P&-"Q$.LH; 4JPQ\XO6IS.DCMP)P17>+HL4]V9MHC?46; S:'^;$/ M"B]A?#'=^&3[.9K:1-6Z.9>CK* 5I9/8$R_#?K[5O+^PC[8>%H.W%O)V68H# MM*J6>:DU?#@&-02VTF !R1[LN;P7[,1B@C_+ :&63HA!"BKB^2)=1ABJ^%CR MMPB])#/%%$&1X&2_=CTY+%[V6,PDU1(W^SD2=%ANQN/)/@*0EANBV19 MTAL_C-J()8W4I I:=6UB!E8/M*0>=)D&[P#I[!PA'^L@!LOXW)O\/!:JPNU, M3'6.Z'YX(MRE#&C BL ZE&(T;-*_&Y. ?.@FLLK>3IY'_8M#/[@S.R MT8S3JD31OKS%.77-CC,X$:8:3P81J+.JHY*SK6=@"C[=R9#$CM_6MJM$6<4[ MDX>$*#.KU%U4Y<*2 S MQ>%B[LM$1>EJ#J>YIFU'=K#L*4U)W^U^Q(UGQ_@3 M(5X@K=.X+^Z$)9W;B<[UJ[4F<<5%\$DT*U(85[Q4)!ED!:E==K1W/XQR4^9)[6ZGV:K=S M&XK0L1K%.NFPZD)4W 22BF2-9S?W=IL%22S\$X%5G3"[VY9A)PE8 S<5G?V8 M)D#E+$M%99[G-@:V:,0;$7BP-51V$4WN'#<-JLVD]'U.W!LZJGA_S4%R; VZ!>4:;G.TM#,EY MJ6YV.:,I6($YDYI8\-KC8NCCSM/ M<=7]AK9 23([Q;&5(!]%KD 5V+A:K.LG@F1B%/Y,XHT(--[+EI43M(.D.H)V M6:?@MP[3G-&(P!FD0V#?5^!./&%QFQ.WPN!C-349BQ%WW=ONK$0+84F)<;P) M=ZV)F2W'_&7S3=+F@ U8IPPJ3[:I99Z*EGY*J>*L65(6'A.D9AQFQ(*)D[R* MP$J+%!\>GHO+,AS*5MH,=@+X"6MW=NM\5J/8,#=\.W?;]XV-:"I>5B*5G8E] M4U"PW&2A%#'QD?[P*8_GB/V30PI%8+&7-2_,=7#2'(QJ7>()&TYM.NGL 0VA MC%^ :WM0%#OS3G'_#X%&-<8$.Q>GP(@LK+0"]N M#/SMH^#8@-:G_P"" XT,1/$!H"\ESZ/C@<5Y3PEHCM*VH!XKKA$,IIR58P-* M8,:4I!5RISCB$##BN;6ENWX27>. U!>5*V.W"T9ZNU"W)B\=)_ TJ2$'9&+A M%:-U^@&+W:(16KYW3$C(:H\"2AZIUPQBCQC,_BH:Q;=L:ZY*"5DK*YPI.X-N MU?M,N"2@4/9?FOKE93?)GYU4Q.D CR0A8'N#=)6Z?O;-5.2-I0)_.!AD.9Q] M4&V^#%ADIT;XTD6K9['/!"A>!8QL$X,%7:?LN%%N?&Y63R=A8;,,[YB(801@ M+CJ">%GH3]J;C@'!I60) 1R12@Y7/1?8V>0M)V>"Q,"T.R_<($=A,T!+[4^" M3(*$4\X7?#P&1KI0K!T+KJ-Y&L$55B09N;2-#97X)6S(_=@$T@PF M#J?U%"T[97$Q[Z/J[*.\I]F](7^/;&BVFQ/?'3PI*>4V'?MMR5?!KFO-7 #7 ME4&\+N"&\SHR>_'O4?+1S%GFWY6Q(QS!4#K"P3]E%%+1^?:3IQWB2J%>SI19 M\N\8@KC;TIK[#J1Q]H>KV=*<#$R2S@[G.0XY$@F3^I[OA MA]-:7.4*LK9Z2*;A)#WH\"IL]VRG!UJO].:-[M SR%J%%B M&I"H [YLZ^>PMC?8JH[T^6F@\F[W[KT>;XU$8&$[9#WA@0KBB-%&KIPXS"Y+ M=V"O"'F5(;7WYW2&B@ +%]%L3C7=H!CFGI.-Y@\?)LNL>4;S ,-I%$)QR^UK M8OX!W40PBAV;!B4S.93DR8S5(I:-1]H,L&7#WVW:[-BE8V2;VIB>Q5H$L;=9 MC=0-G&RKVIT19=,2C4J 4#%OMQ,34XX'3A%?4;:H='NN'#0"'# IQURM2HR_ M*I61900N7%6F =S'G);(K=/>5D>):1]I$H.&\VR;72NRJ]T$T,[.-[:1E6TV MGS+:N[4>RV]3HD!P1TVVN&0@'NN5+;3+EF-_.CY DKAI.MLA@]V&H9,0QEX, M$R $:P1J %6VJJ9<\D/E):.9Z<,.K.=TM\5%';(Y!<)ZK+*#@I(F%V/&.091<<]LPTNBH>C' M.ZH0S*8"7.]LAK.? UAIT9H8=5=,U['E<*3 A[6>EBAWP18UEJ,X;_/TO!A8 ML<@ 1'U6D B86V0+V62='6X!+=ZR(1V6;?:6QA:?E'8,@4[M2* D11V)Z2S*"-EQPYFJ/?_. M)Q']@. -*0AU G#DL0KGBO$K:8#E@RA;K@!N?:;M#NHD*C:/DW4JT?98X$1: M#&C@&,SW#II]C)D7$!R0ILC%T0]U2%\"I!#;99=]8 M-[UE(R7GHUK*D!E\.-#_>(:FA(]KNYA9W;?I?&56C_4XUE1WYL?GTUR1W498 M;X :%S0EY %& >3M,PI*,9L)G2YX>WA:8YM"Y>$Q"LU<@6Q@"FW:3FI=!;AQ M!ZLJS1:FIUI^"GT<%JZ 0V79Z%3&TR0X>:P# (#9Q<"ZD8#X7";QSKZ\QRW% M\"D0/*X3))2-$OO L%\'V^8QVI7O QSV;$J;2SBMGYNC$F M)LB^: QYE^?FMHOB8+EQ1U?E"R@D/$J3./%P39WYYF;R M?AB:2FUU!J?MN-+;+ 0H8F)'FQV-5O1XGIO]6" !OKG:VN/H%H $H'5CMS%% M^[V&(B2?&C;]'T #PO\G2)B\RM%VL=P?];H=D]#. 0+#4&B/V=F^7O*VQC83"'NN6 7S10?)J2S_+H+8(% M;F6_B. (5C#)I[65:G:RP2RG,O#8]Q$O'+80.J(UZOQ_8X4*[#!1B;',=&LH5X5@W8"N#( MG$],(Y&&G8(!$+I:R&7[E<]U)6*<]&]\Q%9N;*8=O&Q3&RT=!C$W"HX$_-8) M2A58!ENR"$T6DI78Z6AF:;@W/##XFHLHYT8PCJ/EZR11XHDTY9NEI@4L[PD4 MV''\!RL^5P\S02S #XO0Y#62304+T"29FRUM62XWB="QOC8,\1COZC3@(@/K MTO1$MQ=WVP6B,QMCD8NH$PR8K5C8)!";LB]O+-,EN:4=>)V0C\-@ BMP MD'06G]1L9;?D.('<.$420//\ M&WY(Z5POS*>3><2MK/-M,:1+NBLO(E@>CVYPQHLS.-G%M9X26<5@3<5BHRK2 M#KZ 'P(FT"H ID2F:6(7;$S_!%%EWA];-7F*M3 R @X B4[G?$>M$2,CU;K4 MQ^FVW69(A9P?_!,Q'AOS674H3M,I=T9LFV2*6LGK.:5V>)PULC6>>[DKB)8P M\KP <\X[W;CW)+TK5NQANU5[W'B@=5_=47&SM=5N9#Q]9^7-'($X]J2*W>Q8R6^" M2);@9W(X#ENM[2V3CDUK:;6@V7#%YI.X(O5-$CNM(K[*48:TZU_,U08AEE0K M//AK7&Y+W8-]\7G80TCX"0E#5OB*%7[=3G$!'"XF@N3V+/(-=NP MSC:SENWH8W3FM=K0B9.99TN+U^%BRSM!CJMK-AO('ZU?$8CSFTW&GA2:\THR MH[!QI8\VA#M]J+9L6'G="9-:O?]L'D'JR$? MC_>/G>51!>*"@P#^41K#-/^8(GV,Q M=Q*6'%FW$:70 CJ(G*\QLS/O0CF">%L3%4+'J9WF*YJ=A&S8B2_M]@\:2DG' M=\-UN0^ U;9NIS 6$,,8C3U^K(I?.P MYZ,FTQDQ7*Z,?-D&CU:7IU$@?A:BKN?9'D=8Y1A4(\)4:@5>\HQPH+C3&875 M=D ]1L$&K<&Q'D:K@"]CG4E?;> MDV,#?6@361F9310&O?3X$6( 10CKEP(\1 M5$Y8)#8/2^58K]VWJLP/26&' P<UA6QYN:K1B+#^&24?X@ M/"4N'((ZH-(I.8 A4L9P=IYH4U4DL_./;9?\G&C725&.L(VZ4TF':+*M@IW3 M,.'&#FTK*WD #K!U^'!.@,VCA[T!LCQBMJ]I?,0YP_L(R4_V[[!ESY[&WI17 M6-1CSG[R>5-F F[*EO9@%8@%B7*T8(GW#/.IUK";\4^\M''K;8;"8<_Y@HL=@U\)3L$7LK)7)/POD# M3(=/Y\04N9%MD0.ZL45,C +A3#S%%MN^K7Z<('9:*>XA)_FUR(_PFC:D'U(^ ME:[A.0?/4?Y6 *IC&?'J MS*\(:CH6M,@8V,P.W.R4(9$C3ZEC.[;=1ATN3@F,TU:(?#N9I-8]7V/24_:Z M*!MPL,@6/98##CX;PV%_8780B-.?;(;$.M@7)$,6 =]EUN8^]TK .DQ <;F@7-EU MCCBD1)\$D [1V.=NQ'!PX9H5&:X!F?(>N%#GF8,Y/TMTEU $)&>E04KU? FO M9"@,=PZV (_ AGQDV]YE/@3C1D'@G%N7!=M(Q#=6N;!B-/8F?V5Q_,:XUW0Q MM@X_#7B704'B3:GYP4\._SAG6F^S5!9#R[X& GB4X5D-E!9.JG@?TRE2L_]/ M+JV)D:.\0?(]\',$1SARDK _'%/G@K-=5=:= M\#&W;;05O&WI=$K#QZ^H%H%QM&7(7S9Z'A*%](AK4O]C),8M/\5E$+L%FXNY\T.WC*FPGY!8+ XNEQ23E=@B7$S-R#R M!DI)>BP;3MVEV:Y1C,@&MEJ])JZ:0]Q:Q<4BX$BH=SF&.&U8)>L"AN;6\T,M MS.3K E@NL2N@TJH>Q8VPMU]X0$#3D)V"Q]R+W5;<&)\8\FKP[XOP"[-K#VH/ MCXR;$@((.,C4;RU'1MK[4&V61'(:,.!"C98:3#7KD 2)]X\ MF .2 "=L$\8G.6)>]F-;1/"&53%(I[ZSV6:QC*"W)=J/MZU_H"E;WM@J?"$0 MY%!_".-H+]F]6M%!BJ @_,CNL+D\_K8(I0#:7M.@)G N.;KY-*GI>(;=9KOL M&!PGU.FQS+Z[PR7;?4^$.QB7W3+/& Y62IZ1C$!K!4EZM#LB+C*M83^>UER&*/&R.>M&0A#H%,D'D$UEPIA M\GI[/I-,@.N*Q\%YB[>YH+H[UG(ZS@"6X1/,='=I\(#UR@WA&N5>X(@9B7-W M*0D(KG8J&L)!,49W*F!KV.J+C7E):&3UV72")(+G:J>[^5$E&,Y0["OKD*II M4WD2E4:Y=8Z7O/ELSZT"\^.\=H4V5)0SJ"$@[R>[;-B*=3Q%>8FVB 7L.;N' M,]-U.A">5\L=9_0ZN;Z-S;]X_]R@^EV5&3 5H.LB)X0[H9L\P8ZI?5-DWP58 MVS C23A&VJ'E[$0-D; T F,YPG#8UR,#90CFCG?5J:21[("^N=LI2'2'@>#< MLT6Q00XT'7I2BU2!$_#$*A,VSPGKE\#<5KEPK(26,CCB;&\5TM)=B5G2ZGA, MC]0Z]\2L=8E4.>9@Y5 +L/4"V A 91QB&5-7"6K!X NC @F,:X[$M\OM@B) M*DVX.V;FY.]M B+VOCU*VSD>)5=HS4Z9]-6&)*W;X+$>0_8* E?5O_@W38L\ M51P1RT='7./#;,GGWFX)=FW_PZ9A9+>9RKRSA5L,8Y]MQULE=R[A-#4^4QXO8?/GY8 /@TT2(>[2M'8D&- M&%%S8M#@)((90_NV3_#E4QQL+>:/BQ/EW+?%DK1X_PG'P*Y1\VBC.7AJE^Q! M;WPL4CT5^ZYK;EA>FU+!94YNFGC:F_2+7$"W*+AG97+"T:];NA'%NY1-23'85-L$]5WN5T_N2VID]L8,1CQ1,Q:$F^>(J8&B'MDEZZ7;4=$?0T'5L0#_QK6G) OR MA7=;8NUVX@KS9E./T)[(/3@.@J&K(TN>Y!#[+D$,P7NT7_!VWH)(&!<[Y)*/ M$^LC]S5!B+*!?5, XI QV.8;GND:/L+>&D6)XR= ;PV:Z\'4<&'.'T]IJ)[AEG@ T%5V@\DQEJX&W"VN-'@0D@R"L; M5)PU6$=*SPU7C2_9YFL !N,W!N)I[&- GH0'VBZ;.)\UW$?3N1 1^.?" M(!-3!"W[N:SI4N)Y5=-P6OHV'G9RW/_1,5\+$M_ZFF)O%.\\*%\V@2 !#7*G:^A/^J--T.2Z:TRW$=+FY"8C,0G?IG@)#+ M:;(3ET/<*[_P=F)>(N$9FV]7-POD^+ =RV*G[_*"F_%C>P-=R\F&Z:P/$(9 MZTB.9 4"NMOFYMDW/$;"![B9Y>+KS@*U5:;CWL85%><:]I54750I$OP2]R@7 MZ7%O,FT>2F),BU@ . G;TNY-7%@!W++'HB4H #(XU@X=Y=RPJEAYI10?H@9.]0C* M(^"8V"2K"Y40^S9$O.39[1I.MI=U>15%["$KQ- JK( 0E]2F&ASXO,Q.N4S: M.=]GRJ4X8O.DBZ<9K92 I%9B('E^RFYYT$,IO";4E#:?1QD:FT7-UB$/B%19 MV>1>DT]+;#07$[C\0-BVJ*2=73[\;/#+KA*\.,.J9)=0'/P,>&8W\/Q5I $9 M[O.2G.K$U&\//EZ^4WP-4%7^1P<=AYVK]CO)\+5*9?U:Q%ZW39ZJEAPX5GRP MR596;0QVWKE)U+*'-8<]P)=\+=#$RY#4N]>T27LWV,SP6YL*, M"7["#L[:9MEDI(Y+VZ]V27DL,;6V M-,=NUS\N DM[LGX8R&SQTP&\ V\ZTFEKC;R*#X=2<1D.@F&I#U;^)<#WXM\U M=>M($>O#)6RER.> F:U6'B3CY^RR0(?*>5P0&]2R<"/(?.RNM>N.PXJIR8!F M8NTLXM36U8AW*KND1.'$?TF(>&M1L'!6->4<(^;G8 /DSWL1.2BIJY:-I/3\ MPW+M(9S$>#C8:!G-1JL>/BD0F-!?77G[J12S,TQU=7:="ZK?GYJ\AL2;344- MM[!$@W$#-185-*2Y[J*TS,>89UV3M0I3YUO)0%"O A=9V5 3;TGS=-AU*#=T MD$KIV R]PR&CE6F$W7Y]V9G:&C2*"M=$&\Z[,S+ F=W\TB!$%[RBZ MP\GJFVF,^#BY[8R?6&K7;U<>HCR?R:G'ZX"?'RS(;G":>"503@XM=QVGZ5 M.8;*02?>DY]T.C/[*,XM/QS8M[NZQ+[XNJO*"]\/VW!2DD$O$.!*^P@X,[!0 MXP(;MSD1[JF^G@P0ON_ CF*O F/:O&O$E?*7F-^N8I<%Y_)(++2S*UE/'I&Z M .#W2"S+A]VVSW @0.F8C&%!GJCVD5"2+Y25#5.$=R\<+:F B55NR;Q.MG$ M.F:51CB&%T^S/Q+HV?Y^V=0B?1B//>=UE4[9UEO>)QG%%9V427_'\$09B2\> MH]0[/-QV>38?!Y*B&;=RL@-Y2'A6F[RN2?AN3SKQ; ):X;-YF,'<;5_<5" ( M;#@KSM:JDI1O069_!W*3;,O!QBBS=5E9,SM"#=.(0(]#/[PFH!J(PFI.6Z-U MWC!(KPZ'#7#EASUE079K%6/VQ\2X:@C]5"A77??'OB>^%&B^IF)-F!(<6GJ_ M[K[Z]R:^?E-9$),;I-^)AB'9OCY5YDW828.,:=-%F"DRA].>!6^51683J'Y. MO-I637535(F8T<&_)9"WYE(=Q@9M6JHIJI]R9JRT)]M7V3&8,:QS7FRAQB(B M$^=P,4$R]H,)"3$'#D,-%B7>3P>CNLKQ5=8%!W5E<6RV=$E5)[!R2(&=H*1C M-PVTX8&GLQR/L:HM$JLFK\"]O(-&Z5;V.7?TYY^=T,Q65O$Q'LN8N 8BOJ M/VWV$([][(O,>Q)&WP3P]D+:UI&Q1*>\7_-TNI)S&P$SCRILM],%MF4$+/RT MCMR>C6-6NTW76:SA7-2PE=:$P2,/NXY!52MR\(\M8XK3EJ_F@*!TU0][ MA#@ 0!7W:U=>3&+R+*_SHRP2'K, WFS9EHV%S;O?2A8N)AU16%U\U?;"L+8V M %I5/1_[VY5L ITTB9!/"[E+P1,C:%OU:2UFS.RQ>OL>7%B22@Z,7Z; M3NX337C@Q-SQ5N?!YCHI9>OXA!GN88._;5!\]A+UE=.KJM,B>#4BPR[F;3BB M69SR CSC0+BO9JM1LF\0^%?5[#83XL J"V%"6/VBQ#^P5*>:%7*N:S8W6P2O M.]H93,"4%VEXX^LJJP]N=0Q"Q5FLDIG*V_Q7E$+O4';T4GQZKX_RA*W'S>+^ MHZ"->Z?-;+= BV58B*MTN M\-%0Z(,E!ZHUVQ,,L(C!JF06JH5(PWHX17X3=-FIK>B5I$ :NRG5K\.K#:QA MX3]BK'LM]@U9!JG.:;)Y^0+;7Z1!/&X6T>C-%GH'0^[%^'VYC2Y#"&(B 7)6 MLLADM7S>KT(-]S4#?3XL M#%E6J>IFVSK:I\+:#D:_V5 V*\F[/*Z][XN:"[=" -7P7=RH[7685LGMCRT: M2ML:!XXD(L/;JZ^,/9JK7^.XZN F<3O\.?#Y&J"6QQE8?L/YU_VZ!L^=&SRF MS;D8_Z3@.X9H-.57-%;)ZG7N04$K;%DI2WL@*2X"3AQ!3I_37C,";(FI3'%M MP4'06T:JO$NS:PE4>>(D^:5)4X "&Z\H<])3Q\+;!Z3>Z^*)%Y1&R_W@LB%M M90L\>G9==>ZU.78CV"CA^&1U.;+<@[%M M#1,BK5@2?_"I\MJ!V/GC>Y&9@B%'4S^L/']]_]_K# M/VW;]E=_-;__]GG__4?^[7SSV[??^^]_^^KZ^[__NWW[J__A'_[QKX]OW__Z MC:_^=?R;^,=W7O&O?-1?_=7UXOWOUC^^_>?OFXQ_^YM6KX]V[5__!/_GQU7]X\^.;#__\YMN_V;887WW[ M]IN/KW[ME6Z_\JK^[OO?O'^U?WKYVY]^^--;__SFPX][5E^]_?J[ MM^_^\,=?>/_=#S]]?//AU=^___;-A^]__JO_^F[G[_[=Q]? MOWO[S?'];]^]>?77L?Q-*)]>?_OC\_;W;[[]A[_?46@].KUAP^O_[ %/HI(ZM5_BZ_>?O_M MF]^_>O-[KO17?_/]^X_\R2M6Y+^_^LW[#YN/,[;XZE?_K]?????:U__X4GKU MJ_O-NX\O7\JO?O4??_?FBY?*JU_]CZ^_^_6W+U^KKW[U7]Z^^+F]^M4_O/QY M?_6K?WS[VR^^K+_ZU7_ZX<>W[]A,GU\<_-WO7OSA'GCAQYWO?K:8G8O_[J<7/W/IW[_\ MF>O^_8LEZ5ST#R]_YG(__.[]YQ<&5_OCEZL_O-[7+SYT<+4__?QQ#"[XAY>/ M8W"YWWSQ M?ZP\OG@Z'ZU<>W;_[\0OAJE_U\CZ6?[[#\U?XJ7^RN^L7>:C_? M6?O7^ZI_N:O&S_94^&I+Q:]V5/KYALI?[:?RU7:J?VDWM9]OIOWG>^FKK31^ MMI-2^/E&2O&K?932%]L(U_%R%Z7RQ29*]8L]E-J76RCM/]]!J7^Y@=+X>O_D M\.7VR?'+W9/3EYLGO_L7/^[K\%R_T/U[_ MBY?&NKC/+Q2N%COZ_E_>O?G-QX_O>?KO?O/YS?CBS5^___CEF^F/;RZ7]]6? MYI?O?O6WY8_O_N[]^W_RPS^_4U^\\\F9_ODM#]F'MZ]U43][9__\SI>?UMUV M']Z_?_?MCQ__\.[S 2VLP_OOWWSU>F4Y/O[+U[]?EZ7[\.8O_ 7+\)OW/WWX M^@U6X#=O__DO_$7QL?S^Z]>Y]1_?_/.;[[]^ASM?SOOK=[CS[]_^I1O1/+), M[[_]_!+W_,W[EX>W<;?OWOSXX^<7N,T?W[W^\7>?7^'V?BLL U;\^37N[,>/ MKU^\P!W] Q\^_K=MV]_\_DQZR"/SS]Q%^?GG[CRZ_-/7.[]^2>N='XV;5SE M\_DG/?CGG[B\__?GG[BPO_O\$U?U[S[_Q+7\?S[_Q+7\CY]_XEK^_O-/7,N_ M__P3U_(_?;:I>N;//W$M__/GG[B6__#Y)Z[E'S__Q+7\Q\\_<2W_Z?-/7,O_ M]_-/7,M__OP3U_)?/O_$M?POGPTZU_*_?OZ):_G-N]>?][Z^[?O7'W_Z .#\ M\VL^N=^]_O##YU?_\OG5^NG5U__^OT_?]Y3>KEW/W[SX>T/ M+[Z%R_V\H0:7^^O//[GA7C@_.@Y>O&CGN;%CUSF[U[\R/6] M=&5O?B1Z[JNQ=.CZMZX?QU@B] A![PAQ<_@$]='C__.)'KNKS^D=]W>]?_,A5_>'%CUS5__'B M1Z[JV_^#@C.\_WO_UMX]=<)P\H*1(YA^.]?_MI_^O[M M?_WIS=_=KV3RSAPB7_WFIP\?WGS_<<5AA!I_^ODW;S%Q;][\_LTWV]9#+OOH MZ9 Q,RV=C-!D'K-OVY;26Q&3[D3SR4+E?WC7?7)4E2!NASR MO9U9N/KCW$ZR9Y5_9X_<%JK._=R?6'/O3TK2(8TN25M3=/FYYFD+W)SEZ(I$ M*H&[&/DZ?U"FHD>V^RC[KF($'^^WA"[/[Z$&2U5R\78"7_;\R[2H$UG[UB\% M0.P%:+8L[.=]2W64:K;D9!>FB3D)6X9#J1+9'K,M99 6RL'M'T,]P'/6] MF9%M^^H;DS T3.]^OZP5G2QY>IZY1"6[>._=H[E\X3..H1;'B]^ 84BD4I6-&560DC$L5[7'-PZC,;L$JG9)38NP M:V2T[(\I[K@8M%L+,DW*(.%PBU*N?7:>39>RY>%W9&-+BQM.(I_#8CTMGG,VRX.!9L]'3SC*9.RS.9DOZU1[9 9WI<(QB5!;CD<-]*9:?CZ36>W$R MI\K"L;/%>7[I5->KLZ1GS,153N"XX:&_&JSR[$:7KM<=,Z7EJ??9LEJ (?$8[VQS]U2H];([*SH1[M2%0])1 MJ;P:MR4[<*79':?U6>9#6HX4Y-9W%ST.NN)".,B7H@6VSCLGKBY06UJ F Y5 MY.]GLUPD;Y?MP%;KQ]-&7&,^MAC9QG??/:CC-X=J'7<++4H#E1/V(UU!0K!X M^2S8&BW4*3E^E%"?]V45C,K3VKYYC,IF''=5LKWFVPY,C[M*:'?J29JJW;2R M,FUSL\WG6+G@(P3+MI@-1Q>CY!72T;8^L\)5TKCRA)-2I'UO9^J\;I?\+-<2.U1M17) C(TLE)S=ZK0/B$H8Q)>E:)V>EY*R?C4O6WR&W6#W<$W]/MO<-I M8(_R)C>$S45JM]?NUTCX6V\L5\OL^K.%Q"K>4OXX/;_981='+_V>:]U+#!20WJ:Y&W58G.V3)*E45K M/1@MK(9"#\IB.1+[2"XICWWG)/]/W&0*DC;OL4@A 6DL<=BM/FUPM(?._D>> F9'[HPD,Q86O-S'HJ"+TD@J MH9C/N9VYC[N7KEZHMT MT@H$;W9YX;VEHN'LX:]];H_J(NR_(HGL*8G27(I3W?*="IL.JW<%11J;MJ\O MQMQO]<"+66ET+#QT2>4=>+&MP1%?J]^/%4QPB)<^<[4+U5%F9]SMT;G$$W+% MUJWKALX#O^%PLB+0JB$Z0E8>/NM1L.VYE43F:+$#<)HRIL@?QR8.SMCQ7_LH M]9NMW4&''9]QJ,(SIG--+N^H10K6?$7LM!/2T\;P^0PGH'K# #M^[.AARA*B M7*OAAXV%BSA&8JW"J,YF-)4]G]9LX5-:B0-^R#:/@^-2,9)5)I0"BF$YG12; MUR%SR:,VA?*F]JSFU1'B[5[8C4,)!:=/'W?8O4OF9>?98$EM)'T6A\A]221: MSR:UGXK>T@@]MOF4H]B[7H-C\ _Y=SN(0_BM3NJO]M&A:\#&SQ84I"%SINE MB<^]Q>-2W-BNOL$N!3.Q:MWQ+7EUQLX^C6H72Q,=<-\\1EF>\*O\9BUVJG2) M)9QAV?AT#+AR"H<"MDX%J(@'$.Q%X:$N-X*,C#$]7=C&T[?'\5$ MRAXB*WJ M$M<7A0'8.;M]Q6<'+V#2I"G0*,CR8E?-E.]X%_5(P6O'A=,>N)BKG$%V+WS# M?>AEMD>&C$7GTB^04(X8#8ZB6A^X4!M[@L)\]DQP &+A022EGC"7/&=\O"J+ M3D/)R H^Y3NBJC;#P5$]9K&ZR///YPULPGR%-JO3C+H*9ROW/='EZLH2[AKFK(WP:$N4/#ONZF^3-AYWHTKT! M!]6@EGR\!I=C.O=<@BV94G_A]C&DMGUQGT?%S-5H^Z_DA#S1, Z[WH*U9'5> M *7 @U,!(W5M)2?^I)<'%+HEZ3CJ0E/2.W/V\'-LDXJ=Y9>&>D&[E#\*4PA4 M.<%%H6 5RS28$N3(!P2$E1]6A8O(!E=&\+(7OT?\>+7?74EH280?&XBEY=9) M['&[B\)<:KT""9YK2)]=N/6##7R*,)S'6E.Y$<_B=(P,%;8L >;4,96W7^VF MDBIHVWE;J\5U,;T_1?JQP(X^=F<';4M(/./4!B@.S'5(K-)P(,=]K>YGG*<< MKJ,>6^^XCHH]=L#/UB& ^R[))8L M]L$^'IMZ-;)BR,>$S7:VF]N6Q(Q]<3N@"=B6=B_7;L>Z_%+29]9$T!4DAS@D M,V@JE&^JHA2Y/QT,=*)ZU.BHM"XR'1$OR/VGPU[(2V*Y'<1WX>3QGB"A+@M=4:Q9W\A5%IL;PB=[N4.3:$5:UU-D\MEQQB)?6 M"T_]L.=PC_9[#?RHA%(2'2J-"D)7[0X,<0+S5#Z1*UNY!/V];+!=1?)[S-4 M5!U+XS3UQ["M';?4=8T5)61MRD^>H+Y32NY8A,B7O4(&TTD]OR09T5QR\DEM MOGHF^YKN2B#.IR69(@U$HD.K'%7)7/S$2LT =JPQ(EMEWV B;]9 MA%9'W=;\DB<9EKD&>*:&%Y$:V)X@(L5C8*8<^R<.P^QBPT4[AXR1$U2?G>*4HPD# MAEW+ZB$O3'ED_48%C%]K$E3'S!;D$1Y)4BI,VAF"C:_L0EFR%-UXI,\)9Q@ NIA M=>:^RB298*9;TX1[M.I].A2BWB\B&QPYL,K4%J<.!MC-KGE7'(R"[.W\PDZWR@#J'UOD>P0V[UMDJHCO)NTP8 MG'+@\ 2<)L;IC^$EC38NW?0E<6D#6:GFPT,SBI-1FJU69K(YFO"C5ZE->#C) MR'N8!=L>-B_/)IS<'6$?6(.#3@#/">'^34QQ^-@-$AX-A>G.[JRH0TQ\K4KG MZA&HNMV?C3!090T6A19-S2X7;P/D<(>RANG;.DCG")>'L+77A+@.U MY.A=1:WCW'"H3;8@;$76_U]+5:9TQR:!^(=SKJKHL<,;FT'IK\E=GSO8]U$Y M@D#\='H:>+X=')D@.T5B$>L2;&]!*7LB#TE ]1:'NNLX$[8/^)./8J>9M9-] MP7@RV3K/AL0[R9*+D7>X^^ZR#1!F"O>(TX:$D?;6&TT2L'/&'?YFK0@H=X>E M")EVY5!LXL0XRH$IF]PM(2@7S7]45EQD8_,6$LL0RFE7B?L3+7%W!F-_F@#6 MF7XS%-*6X5!,.SU.T0 ?@!7]D'E!7:GG:OV^]QGY13-+73ZZX* LNXJXTSG< M'!>Q93,]LV_*\67N>E:.O:.7> ^GZN;*D 6YO$'MP&/A-)+J9*BX7L:*AVT0/5U6C.MBTK5\%&C[*DJ>#:36_*5)#;,#UO>W+U0$A1 MC^^O:W!NNS!XY9S$.88TDGNW&NP(-FZ*OLK6*VI#Q0@TQBOT?:?Q6^ MAO/'W!(!X&8$U<%C)O"EAYCOVM)EDCT?2U47*W0>.&M9 MO L/OF.* P[ :N&, Z+HQ7#4LW MSKD(-06'(?R DZ;<"S+>#QP*;IO,!)!)'LM,M9*>U6 S%$7"1GCD/=>:+F MVIXBUMU-]ES^:9R^3'QB-0PHP4=/VDHE6NTN(')RK=2_'N823 M@##/"ATNYQGP 5-,T*SAF3*?LL2(!KGQAVUG182 RS;Z7>Y%3E#C&W99N7;Y MN CW',!X"(6W2_K\B2$_'-3\3G3@O[DC)&][*I#8S!.; M@$%T-HX">V()=[%[\X$[)E*-Z]M!&KD% 'Q8?\N/ MCWIJCDS>::_;4!=2IRZ-%G [K>+HOD<5V[%[^',G*7#$4VXTN7*41Y""DTVK M705W;76)M,"+[)3MJEJ3$66IYF NY MUU4:(!\8!GV4F'PH?BJK&A2V:D&KT = 27@80TCXVX(&:6^ M=K@N ,W50[RV6XZY_*RZ"N)0T(@Z9.G$EIQ45<[CY5P MC;=\$X2" /P1-X'4WA6?)';% SAXPH%P9!T[04P*V%4N63I6*2K#8L62PFK( MXQCDCC/EFH$+6VP.WUHHWB79OJ4>'8N#B@A/.0RBO;DK#W4.TZ\@O)N@AD5Q MP.D&,"NZ>,OF/C8QH,/],FK=P>60CL?9P$..+^]K"+;E=SAO03J!D:/K=\AC M59( 5IQ7,[K$ 1)")-PXEA1=YXEZXEV,HY*T E(JX#SC"4F_K>$P)5P@% ME-TVZP5 '%T!U_-80NPL0+<@@>6LL@G>E$IKD8H"# MRSFK"9AR8*S=V[TH %EF+IYK\XA>G*>BVEB0,>QTOXSNZ"S[Q6HKN)!('OB; M%@VY CJG_0IA YR!3>I*/4=GR,UH/PJD&&OA.P@>LF0C@N D^=D)RI-6]K0( M!8S$J!BRL#U!CNP%,*Q,"$/Y=?,722*KX12R<:WZB!(>$XIY]LSM&,PI9LH: M@&T :$/-M2W=#MQ:(=UW":U+XMD4@JCD*97UFHN:ZE/OJX%!IBXCJRHKUL%S M+E+^UVBLM\6L2H(^/P39%S.G6LY[)T:=*F7/MP4PYJ',CTK%H RB*AE2K4P0 M/ZIVX$/>5B7<-)+SYB>^@7!O8.9MGAFK+:6>#B5A5HI2'*J$C08@!O!P-##D M%F.P(D\K6Y<07^[_1-BRBRP#>_B1H9#W;9TIT@O)\:F@7W T4D)Y?E?!/\!I MX9-3!5J8)$DW4)X+/+IR(>D('#I<@./>/ % #) "EXV5=7+9XB3A(4&M]'K MPUAN"7]!P&/;L6>7$XJ/$%J4O<8Z:S"XEE/.]%,P'+F-;^V[R9GP0K-S$6B# M1YH'T"O?4I6++SO Y^ =%@H4:[#">2/,?:;*)(!V;H/G&\*C(16@)"YBVHGP ML,C@-^#4!M"04%7V,X59^9_'/)[*,E,>XAU= ^KX\$. M%MP3%PT*R@[&2PF0U2 K6,U]28@/]AT1A!SZ5JQ.XR2V:%MD\_54CYB H1>, MU@/ZO>3= %)%=D)];(>ZK J<:2CQRDI/3"N!XWS,V^.80 *._=:Q!$K9'FQN M#D&/:\/A9#?.5G;QU8-FA8'%&)^^B/_-9.,["(P513<-X8;#9;F-5'R='"Q% MDBW&.?1&(-;LMSE8.UV48FQCT1:CYHBR#;B%3063+@&/ M-7Y/.+3AU4"B^S6EOY<#(YCW/),H'%?*/?!ULK+:83+O79TR0Y2%=LJM6BI& M2?ZRT#&.DH9)JG5-(O^XB 6Q,98* ;F$-G%A/OD!B+P4RV7\$#C<>MB7I M'H_+^MZ]-=MDY)_"SJ>X& RR9*=9,KJA\H5$WBI-V7\5'6,'IYN\PU4IX& G M1)\JEHSMP$ TR2\O#3W.WL.>8_8\J(T(&@9GJ>I^WBI-V D!R,E#C9_"R9$_ M9JC7'?*FCE:0DC8.==CP7VTIC[6$EXCJ/)[#G#_!Q_ Q$9VQ3R0!U"&O-@K. M$N"_7_*#<)T8>4=)IY[W5KJ$WY).OC3S.NT8^]0[+HHDP\)Y$QZ9[5'^@Z=D M*PM@A2N;6%".?;:6!>!6T.)2X^"0P4]*<,N&:>4$W].>$5 NI5_]VK)Y !W7%%![@1E+/"5BOV60X:9;!-WARLI5*_F"10@W(-3Q.SRIE G W6WIT7 MQIABMNVCBHJ\XEG8IG*SX(!&4F$.O*$^UBVYXE3I)$DO;=:NVW*F8C./X%!N M)IMNW7A6W# H1>()63+M0.*OS%[(&MCVA]@#ZXC/DW>!+Y" 71T$8&7+8J2Z MJ)]SVB1L3D?-LU:ID83 "B!F6W6XD%.Z8?4N5!63RJSL'-0D1:1"8/RW2)Q9 MC?2( [(RA(5=M2]ETQ2QA,.JK4HEX$( '/9/:(QK2*""N>25^5OKP!*P-7$% M+ANS?9N+Q F"+8QFIBK0;%&/[!5+Q-9) =^/I0P/[*IVNG3+'V ]5V+YT26 M:=L%5)>0@,P^0+:"E6_'S@GAVE@J#/C0N(0S5+<7\ -J3Q/-T?3O +G7,V$+ MPV:K[BG*YCE+1B&3C5Q*DNB-KE*%)+=GXT#S*5=5\EK1U]O,(/O@<>;\V-E5 M(VR$H%9!!SN!$##==AOA"=T;==D'@KYILQ([8]CZ>5NL4.B XX4[- HSPM H M;EBKLXA\^*)#60%52NV/()94@&+A4FQ'G18PIN2O6%(Y^(&'IDS70+T,*WO? MS#,I:JEW!,3BP\P!'TFD+FQD>XK.9%6ZR#50>B2X9BXPER@UP?I1_V!2V MY')UPEFIIVE,+XC4[X-.S4?*[!0E-JBFMJ6!ZZ';3O4$_GP0'#TI86PWY4"/ MD\M(X/(B)0 /JK&V>C%,C>?CK'*M\7B+;>^CS$?+$^VUM5)@R$\,RYI->:@Y M*TW0I@K=L*/S8BGLSE4,\I+TZ.ZU*^+M^9:$A:NVZ)=M]%9SAR/\/!L7?$H\ ME.7S$]'WW4Y4 HZ8"4[5J)X:?(QLLN,'\WVH%'O+AZAZIG*P2PWLY#;YCD-& M&PN0':-E!1AS-62#YQEWZ[V&UPTS+!@QC"C!1@J@8U* M@A; AYQ/=F,'FR8)GB)WETUO64.0+!&+_YC5E1TG27.%WR3^*#K(ME7%K&X9 MEY(ZF%6%9[XJQL@G=@!I)!Q+@^-%I&F?A$I(ZA;SZ43 2]47SR!'+$&%*9VD MCJ$-+;='1_E+Y5$Y-%I%D)! ^;%OZ%&, 3P0+T 2!W@1NIV1I;7_;;L>A=(> MV3)PII:!) -IL1Y="@IY94ZUQ?1U0%+"8 +)NWQ2G+E/%767W)D- \1.SBO, MPJW)[ WZ5%E!3>SAAYYL]ZL9NY:BI>O57([YT!L["<;EV=B68:5V;(I-G.RX M7&_,=I4';#=Y1Z"A4%.SG,Q6XNL4T .82G(MHY\(8N A=UG1QC[?XD-E4T=#!"- MX/Z0C8O847)I:=>(.KD$%=>::Q MR<.AE9YYOCSRW=":N.D6P./TK+,H>H(5^>0ZKLS@U%.S;'L2ACM[@H\\UU M28#"[N,0VIF_&MGEAVQX6O7=[ M#HEI<6QF"IJAQVT]13+FA*V9U>;=.ZMWA1W3I,BER\$ACM=$@KQF<)J0]%D&DS6'7HEZ.=;74.ZJ M#=OE1[$AM4M^=]O649]D;8SEY"OY$O8O)\+ROI78G7TK[VJ*LC_UB*;SHB,P\G<)LS(Z_7 XCE^T\PXEDVR2%WQRD(VA0@ ML+F9W6(_@-J;UE57IWW<52=1(_#(#U_*&>:F/*?V1YGT3G%3E4X]4;:\,;BT M2#8CV_2ION#1I<.7]C1D^1RMUBR.R-T<;M&U*BR4HGR(&$="-&G3@<5'. C2 M[(F+37Y)3HG1D,TM6+%FY,@]'_=S+$9VOF''"!,WMQZ4_-@( H-4I.WJ83@, MP@IQVD-?Q*CP@EP@@BNS\I<-H(GC3?9F5XFYYB$)9 M!2@P:2HG7Y5H3(%$R0]/@*[#10]>&WB6V+4$*OTY;+[!5(YS8_VK*+;(P7S: M=>&(@@(O<0*!E.(Q]SIL*BW6#$V&YRJ<4Y%@%RT':UD\A\V>HRSAMTS!"A'B MG'"NBZ+J,AUGT5^9[^!03E605)%W(=7 JP#I@)."+K8E'^:I&9,GSUNX+T>O M#-EQO\U4>2-LK,E6=A9_MQ7*P--\"OJ&VU@4%Q0F[N4)U-SX.[: J5/+ULCK'(77U+*YYZL-T'%!\D MEQJ/\@J[E-RGXV$3;YR"\V[8[O8XU4-T!.2^"?)E%\4:"XA8"E"-\%#AQGW- M+!4N1IE%KT*M/F)$?$Q1ZX'C:AI]R+QU 'F"\?7<'B>YL-^ 6-O])>'>B=TD MCW9,06)>D+=\F(ZG2"RYX]R=EK#?&:]J)PG_R ?PH(1/8D-8Q<!H( M7T+B#!"2B5$YT2(KV^UPW&Y?1,$@BVGYUD'P?AC'B8*F F.L$$YP&''>"O-( M479B$K,0D MK.AYF4[0)DM5QC')B^\95YCQ"*=B*_*V88W+-5?##.;')F506P$1G4,ZO7B: M;Y!I&7?M3>W3-!LLU[%UZ"P(2@^;0Q$P\@'3[FOE@CKO:2G<=ETM=F;V6^.>7##H52FVRO MX]'1E=UR<<$350DF@0IJ-R2LKZ([IHI8<=O7AV9I VRGS(/=5\N[4W+/OE0B M :QKXU>U8NU@_ B5N"T[O*)<@JCG'4V.[ P_%([MV2*Q;0KQH=-/\UN39EX MG;HA,"[U6,@/8WYXMKLJNY<]CG7IF9J\G^NXI494AV^7(N[8%3,[I+7666"X M=?%8A>#83J_*00WO MXK-[1=_G?3@A%PX%/,O24<0DV>)Q7*IYG=EAO;@IT9?6W ^!0HKFAZ,J#TKS MAL4@C-"1M[#>"Z6.+J/+LE4.<7E0*X MSX-7IAH>O>Y3[^=\:9/&_L)H)UF-\T(D74;QP:8E3DX)T&S+#3OL=C[5.N,X M<=[5W#!&U#.F#(H4M$W5^[0#:_.!^5''4>@-<@3^8]@4H5XMN%.USJA=6?I= M%U@YR97EU(1/_V$]>5!JIZEK/S _%DHDAV33%KZZVFJ7[O&<^(BS\P!M>SX< MM%[ZT]@/!SSN1WW)D]^5TC19U<681_F>ZP3FA4U>>1X&N^T*"E$J8LNWFBZ7 M'G^VZ:#@3@QOS2E(%>N(8.QE6R6K_L$ M6;"8[-BO0GCEX2UPQ3Z($QPXRJ&*2-<0B!F=#4M-K",1-"B,N,2$&3Y >3\) M^_G\K-:Y4VW5OJ.);\+HE,.6S"AOLF&%.^?$ZLEDO1Q*00PA'L/;N M"@ <+M:RGD,Q:M.9J25$*":6B7E -QT8Q?-_XA:Q)ME.;;".CT&"^'TXLHL] MN')3TLY12&DAV42F$Q[.C)4:N2]9UR,Z%H1!+UR9<">9#W&_GD;T8HJCW2J1 M@ 6<#3DO9_DQTG%UY5SB,YLYU+H(2C%8N0&&$IT?QQ,5RRKWJ8RETL,@QI,P M@\@LQC7:HYY&49F#/6BN=\K%:(:ZC=M>8]4[-J)-!QLQ&MA!U61!VY'#KAQM M'<3T&1.:U;BI!H JQ+.UG9N70ER!1>5#CZ/D>6\[)GUP8G&(]QI &;8'/5QA M;)[S3C"IZBO+[F1KNP9AT\E/YR70J?BAN'@L5/N:3L'1W(UG!%O\<#%A:L[P,7^ MX] O&'7P-]FI.5O"!%=EL2#@^1[ Y#&MUNW;8S-(L$%[)RY;W)**J_" L"$G M\+X0YUW\D\.* [L8B*/<[3-5. M;CM9FR\L2/U439/..7W*Q;' P>6];0Y5R';#L>+#.62[#2,/Y\WQ[*BP%( M%2HXE_;'$MN\5)(P UYN&Q&3LNA ?>"G,V($V7RLK5P);RD@OYYZ+F$B/M(9 M/!S2C@\?R@]:&6$/.O;KWJH2W]])%XS!W!J1E]*-;+=N)IE /!KDF20@IER< M!O)A7XF9JK)TDN2U\=N,L.EZ)]S*+:MD5W.WP"-#15-GZ3XV(Q.2=C$ M>F,UL:L'QL+H.5GO @]DP9>P:3>XNARK4UC38JO<\NS+9N7;J8_55J32D),U MSA/44UH&"1:")VBZL:]QL=J7FH9Y-Q%)B C^EB5"9>MQ6'+E'(*'H^GL\VP3 M)X@+V6K3_6] M@/TR8P VQTH]J14:9>G/=@Z*@F9L6 -.@(D"C@57X0@B]DI:XM3-.:XEJ\JW M*>D9E)=,JM-$<6:VR[.K/Q9DV+:+>]]LU:[V(CIA'$X')6\%=V M 1/?@3V(I.\/*()'+KH*V M*X@=(4AEU9>.+6C)3D43:>R.J/*%W4-;@" MVU.= S9,:KA)^;PSD=.(=O)QQ"P;.>"YJM_LN.%< M',%"(2RQZ]B6$X51L#6$08H] C0C46W9-Q$K $"=Z*C!WQ?X,)N(X35/O3L@ M ?R5.43)A>M80_67XY.F0&_;P937F*!M(UZCML<59;MC==AJ39F/QSEOQ3X) M%EG_)7AT/"-:?EU)R'DZ]=.!::H2VOXD&3,[954[B)LS6$-HF&Z[M\]+#O<\ MP(:R'V21;P=0)IM;G1>:U>]1QW,^&W%R?AP*QJ)9NJ8#-+5ZU^Y'/N6GCL@MV"?65O+$$4]T!G3P#Y M+IZ+U.!#T3YX^=#(>R(3."?!]#Q-.NE!-TNGIC'9O54-_&IP>.J=C#*UD] MV)\(P%#QDH9=W73^,JM7B]VM7AE[L-^>"5G:37"S"YIA[JWW[W*_='N@.1*V M V*3[&0?NVPXN"'BJO80?10S)AN[5<&8D=>DR6X5&_3$<:ZJ_@*-.X802'\, M#P:').,;>+H\A3VI!^NTG\)G$IP8W:[YFL>>Q$"$P_X],;>XH:BX/$="K MO1YL#I=.)G\;_E5&[\U<:&L\F4T1:("%M95XV#/ KL0.0)_.?-C+9C<%1D9Q9;.\DNT[Z:K^ MQ@D2/.W2"L[U)BV/JEBZ^'DH=F7+^*F&>%IRF<.0^7RD=%?8F,TT0(GZGJ ^ MLO$,.W\/2[-*,A[VP27'>7/L?K=]X110]ER4MN @X8Z[,HE983ILF?SQQ^'P M/>$\ ;\";-6/"H=CIE.I%F*OS;["#%8"_-R+:?R:RU'81$O[CSW**F!&0C6MC7IU $R MW4D-(JJZY(_X ,Q;D:B'+R!\/;?C:+494&2;,6SYUG[+OG->52$3)2D' (^H M4 F[7;@\5^I AGO[F[%>EK5CWZI]6I?J!(9H1>4=U8B#NG0 ?MM:AMW)($MG M'O"_YK*G/8^RK-QV!8LK#H,*PF:'S3BST6$P^[JLRAM[5LEQ0GUL(7@ND"%P MW_E9M-9AH/3VYVN52^Y[!!1^1VC#BZP$72DITVVU66R[9&. MXI2&X+:-A-,U9,\"PV9%UM?4ZJ;)G YR*2OLG$T%3V/XAF5DU5B5D24.9_L< MV78*:6#6!URV68'TXQJNXF[C!JQVQDK.>S;.4]?0N8\U*3GL>+.(G8C,>;ON MAE\)ENGTG4!>B1NUN=@*=3MDF:BQXVCWG"61*([M.)"A"F\R4]T5:7ML5PW6 MQ2PA>%2V4T%' =XXZ9TK]64:*G(L+-HCW$=5B8!9$D&,7RYXNN8CFQO MNK-DA8A5&%\P77;LENL[WRBAC MN73[1'C1]OXB"KDXT,^ALNG#V1EFJ5BZK(PVX2R1G$E=(?V2TC,;%BOXT?;8 MR0=Q@[<3O,FFC(@9<$(X;.8[A-@A5\N5LIWP>!P"-/JWR#>#TP_#=*Y=1L&@ M?-H8QJ4:T;+JP"Z,:MEBD\' *3_RJ'6X2F)(@;A,4O><*&@F<*%J40B?P_GF+.Z MQ*MX,NRFNG#^!##(LV=+MP-)CV6#L2:2'30.8(AAT24KDN.]&7I^:H*1;\\%M"_PP)>SKVQ\.8U^[!LH^V+.XT@,K$22 MQ D7/#E&7(42+):*0)^<'?9N4B%K+%ER#IM\2#DTN0F\)_L5=VM]!EJW&?Y@ M6VF2(VNVRKGG;!)] -:(V\ OF, *@?+@U$Z[7(VI ;R &EPR,U M6#WB:/[0-MB\GT1UMN![7Z8;0KXSS_)8!$*J1K)X6/ZJA<'@I"K 'PF;X+]_'4: M%1!Q16NO43?46]W.(4?: B#]+%:=+@U--*ULIV@ T%E8D&1R!U8!/[/=W\'0 MU;9Y.\K5;SWMV[8A\52;'/1Y2DQBOD JK\*^=E*I&LLUE5WC^,3/@-T^\=/$ M!=8^L45*IVFV\7+%GLN@HAC M=DUC:W.ZJCM@$W"NMR$Z;48)$E%M(,2B"N* M[GG:'[?+=W(6S#9NMC0\]6$\8C]XLZ<@+MI*ZY-U/JK6]3VM]+]C7"JJ)):- M4+4Y(,3#9R-[+CKGNLU MDQ,/1&-9CL^Y81:EV,RR;Q!C$L1%G#__&IR??\(JN.Q1^=U'Z> 5/_<'X^S$ MH.23/$P3.$206\8@NU%.FYW*$L%Z%'UL$:0B7\V\UBP7W[_C:>5;8N?55 66 MCKHK;+P/F6'P3MRGS51F6Y8\Z\B7O8A9?@[.&)& 4KG.M!C'8E+X%4ON4<)0 M=Q@165/^\ @;!A&/+(,$/D$61-MQ+L+J*:=I;J:TQJ8P6L?HM- M<4W#.V&I8$\P[XSMD,$,,](3B\%VE _!JGV5>-"$/0]6L5KI!23$&PX"*\CU ML'!.6O/]FY5XLQ[%J70>E,7DV^E'VPV?XR2(U3?'X"@,N_+ %#T=H#UQ;:3NY[+ATC;-BA7@E %Q8E&C! MUEX;0W.M6[*%O1.<$)'W1WG$7?G7J\IP$D^3^^8;)=%LJHK%PJ^J5;0\'"8T M:=>GXX)%TCY\?B#,KHLZTC#4.4^<7^)W.,?L!#:/67(G1W37A4T#NG9P+R=V MFJ-+/+'*AQ$IZC(!L$ 3EB5HE2IQ29$M"X2HAKH5_E55M1V]6Q]327Q>-NPT M&R?QM7.;0R+>PP>&+RT7R%B??*V6Q"4[>=R/&G(7=IO8_5%FDP7E>43.Y)DT MX:QOY<+Y,#Q$XQ@MI2O RVG^*D;5!JM;:V"C;0+J/J#B6-T CF5%"IW5DE<% MTY94#=[PAM89A9I=A>R =>6!F%7&V3V+2G)RL7-MU1,O[W /]M]> 4)(UH*H M67H;4!"W/8B>^9PX39TI*,C]Z\LJ_QRT>T%.K4ISW29Y;2 M1@I54%"7]7!/TLHYJSI9.?7H+", N:*@&]NPJPSFP(,PF2 D"^3!YK?MZEH$ M&>TV*7\MXP*_PA$4R .Q[E62+FD9B&6=$ IV;',+M[I_)^ZD8+G-9,?^5:EW.DB\U4K6:Q@*6&19TG=!X/F-&N;Q:Q M& <8B9W$.* A\[NRQM*U/^T? $P/(N<@;< ) MXMX4.A^U-)D#)D\&6(G[5DR/?ZP.EF##]+SU+755A4Z3*>I_]E/#1V!!4'H;@P'][06.\ M;V=WKD7()AJ0;;M9T 81XEM9]B$_KTQC'0@*AJEVD+')@;$K4P06J9B.NDO0 MUC:0?@F']=EC-5C;$'18SR1( " $?8VH ]MV.HN:;6*] 3BXTG/'8=G4$YS9 M3NJ@32%U,9]7;7TNH*U/)'Z D/Y(WTM<*J4R3]#^"9#XTK/$B/!LD]G;[(A2 MO3>#B*K/.!3MG28).#7#%C\'!SGX=Y,V.DF?BVD8N]DZ.1V*C2]ULJ4(HIW4 MW3=[%D[ 0[YVKG,]^S6RZS[.;5A$ ^ 3P_;B?C WO[BT-+%DV8# M/YO]$[=,#<1=PXYJT%(SG73)CL-&<3=@&=6MEHF, +*F'J7Q,X2S//)D!Y!" MG%O'_5>1[&Y/FP/*$]O0K4Y--3U96:*;)N,Y7NT)3N9WA717EOA2U/H")0&R M""H6LZDDVN5TXIBH5%'B8^\-90R]9J7;V;W1Y D1/PD MQ\4FB%&;N++:<'&V" MML.D1 2#:*?9P008!(\/RY,]Z)<:QUFZF;F:OTZ'(WFN'(B"$3_. MMJE[WB]"??VKQ>E[RB4"6E"<$H].O'(]_#TWSU:(%^6A+@,UK"BN^VVR,+ D>M33P_<>CM " ?R^]&Q8AW"33CX:2VC:72,"4YY]>PCH;S$P 2)+79,\E_)4S\6(31/,-"H2[)2UN ]2/*M8-B\^?U>)$6,,AOGYX M6(H1@ =-1CA]SMWN80HCF@T\-DNK$[\&$=FJ398OEA8?TPD?*OAQ6!8-63G1 M/6_9QK=AUR4Q.+]-7+12XO)$7(_AFJ;RL+@ET0G1A7TSTLO*0Q%LOUEMG]=S M[UN,?.QC#I;P82YN9<#B-6!8 M[PTD83)G#G4,P&]$U;=7CTWZVOWFAC"' M:7/OX>T&U[-XD'QNT^ERC.T5"1( B:S"'9=/SF5&_!&NR4SHF#)J76/B-*59 MW)9\:-P]4#TOGXZ7 T:Q'>?"I@ >&;(F#T4*#V*KBP"3P$$N=B#FKOBPW;M7 M$6N4:]4\DM-B)3Y)!WID43E/X+%5:#]OH)-'Y5J(2JQ[FSX!!JE!:WZ%#;6M M$0-'C138$*S<1\-4GY;FL+)FMA_S%(3@%N*S^Q\GO=L9&"4/"XL'+K14):6]W-BTC!DS!.KDIH$AZQB_I9RW84 M=5/*D>1AX',PZ56Z.W"?3:!8^JF' ;S8\XIY,>:6<,D6=/M;)<'!R-2SXH1O M%3J 2"Y9Q?%J^@F$31ER$X=SY,X#V='6)=4]6$Y]GU[QZ)*[M,'^:5U;+0;%ST1'*00Z /%8GD#,%O3BR5-W0SQ8Y2/(- M%#:]O=;#CE*IGE6]7Y+,5AN&<\W9OG_NN7(M>\8O8/K!3<2=4X;V(V["FLQ6 MFM(:+(K1$XS[>!%%DN^5*C].VXXR0%$*=/O]+2=B5'#3%]:;A\^3'YN=Y#B5 M PPJDLFJ>US6#4H&.7+95Y\6SY)T'[?:T%U"CB(;!E[:8J22ZBH,X#>E]I4= MM*V^._8GP0R6&\]"I,"N!]GCH6_S?_+= N$PO?CMN>8K^ZDD@_PF(*WML%@G M\"Q."LO]YS0H"*438E" CM]9N#>824@4B&.G!9%WB"3B2"^X]') ?>) <<.Q32+\=:DL0 M.4A]8(+HZ0Z$JG)"S'E:2HN)I0 ,*L-QU=S.:I:;36C1J[ 5AFTR//YG:U(? M*K;.G6 QY/G"7!9I[:1SP X1F[6>=ONXY2S?U>[1Z_HY-V%?J&OH%.L(/#A: MK (@K*/UK%U:#QN$1:>P (2SYU2JI64

@?I76WXXU!DYWCXZM:LVFS$AI5G M,L0Y[083*_TNO2O1K,R+@&B3FO+,G^S5 J3R(01\^8X/(MI M2A\[#CP&X'-(SH=U?T739N&UHQI-OCY$TJ M=I(3B!66RR+EK@#Z96X%V$ULC2M4003W/S&JV&9;!(CD=SEOBK@=7)NVW1S% MD/ J75E*-[G)Y#5D(6Z9?K*=(PY:]9NU?**,;6QJVP\"V/=ZI/Q7Y4BEELZ% M F&F&CS/ )L$H".!/^[Q2?3+^SKNX5%^0!P#T3AP Q)3@PX&;O*VOPF'#BAPAB^#T.Y]L97=!/!VZ$_9'(XU M67HJU(2)NQSIO*SR'KF;9%%CHCCH0YA<^3W\I+T"X'*3O&P*+'F3<9E%L!4L M;.P[L%AR,JGBU"6IPDW9W>UH_\@9QF087H15W8&@I![Y^ K$#]6/]6Q.Q.Y MGQOAKU[.CJ#'(FDI4OD[\JR/(2YVAK1[B;A0PB'"-S-=^&QI3=)4I^8V[W+, M&W@@3UF9L@Q=CUSR4GTN)0E'G,01[5,/S>GP/2?-98'S[*72)!AN (.K7;\3(3NWD72CG"'^2@DKL"EHK]L&SUF4> #\FN\C.!]7Y0Z0%^[!8HJ" M0#-Y5W\"/WN(>!^,N,WPX3!4E[I85L&!7135\ &$[79X!^Z33\$RV@YSL2YU MZPX350?AL&BZU%4&ETYL,4U>>YPI2[++V7>>^Y#K=#>S)L9)CDC@5^2*ZNRS MG;@&$YX(%KK-\)ESQ$8GZ@1K7QWH#?8EDB9,P+(1B7"4GAJ2Q('!;E4"#.Z: M;9PWX[;2@V3GLYS.U!;%RZH]\)Q]J:ZXEYEVCBINET53^6S*.I!7-IW8_-D= MK0W/YH0L!GY4;!K7:$%'A&.1AXUFM^S!$V87LANF#-W/7=D(I_%5=".PZ4,?G3B:3S+CZ=&ZZV;T4U4V)#G3@966BNA1$ M8>\6BUAV"\8V^'/ECX(CM43YQ[X3KIY20>F$G0F\+^4(XM%KQ2N+@R6,:UQA M)33;K\U4:<9;*O@$<.FR!X1[T8S(ZAB)ND\[9 :;@:-@05Z=$;R3+=2+;&8X M^F8>C:UQXO5/6::EI;'/U;8&4'MW+%=B:&<&94CC 9Y+*6=W4/WVT]AFGV;: M'F/P+Y=9,2 MD/=FR\,4J;-XSNL^T=2H,Q&6O+OX###$,Q>2NAOD", XFH?L2\S.'/.:CL[; M$P+7FZ2NN8#C29VI'&S]O!QZF1)1J!MP6FI5B:AD7&%5\45.;JRA%9K5:-$V M6WD[<>HCL<5SVC$(;(U!VDEKD$.J%/\ YUCKZF!TQE<9MH('!1$[E5+-\;!F M26TL)3+DXY!N$E#A?IHM=-#&$V>Q1Y/S=\K*8-NH]#F>(+MA.=K2[CM .S>, M-[Y]5ZS*].N9)$BU]=X>@$,.HR*)TA)EB.R9PU8G#LMN2H+GM;A.XGGC,68*!B4SZYLE%3^MJ:?=DL>^.@N69S:63C/NHEV M;28]YRT#6W&8CRB7YX5YYX=H)W1P,'O7BN;#.5,32CF;C.=B#3Q,LE_WQHI; M6O;9VO9:)3QV9E)NP6A;LXDGA2U&3_(*V5=(=")& MDKEGYP9M>#PDWMN-4W=9BST=@5@<5 7PLG_'BJFSI,M:$$5'*<'F)D6%Y4F" M<> TV((KD;\P*9.#0]U7_^UI,1?K*_>,-19#:?MTAG1A1RB'U9I$6.WTK 5( MX*4YIKEF0.UA26#EAT.8^ CI3NIRN?CX0XII+Z%8DYN8U$DT^22,(Z'%<<>= MP-!QYVB3(D^>F+>O/CAG+J]G5;^G+9A$5>QC&\G*Y-)CJ+HZWV8 M^Y64! =U 7F,P6\IJS#PSL8DFX>C-'"[$X1*$@!]9!^U]T4!0-O36S4X%IE) M0'@1K2S:.CZA2&NFGWG,_.V*V("D>D*B?T M;.;3SW,U$8 +@!K.0&+5G*P"GO?C7L00\?Y$R"6+O)/P1>J(+1X:2;50P+1L MZL'%X(MW(R@BQ8Z8+L;8LG5P1KE7>_EOJ[0T/CH%8\^*' M!"U5IIM@&O)10%>+?V!Q>0YL0FEABRTE!+95E(*%>8[K4IP#_[MA ?.16B[V M3H+8%;@#UUDZ#XM.TUZC*HEY49T(VA4JSZBAF@IWG/)=A4Q=,@3(EA"@QD>:$, U M=[DKZ:KB8B: W]WXJQQQV 6X&/N<;MVSIF82H?'HI:J7$QX@MN%&<"E-46)0 MBDUQ]<3<'XS]+XDRAR)9[-L'/$<7]F#SGWP92[?#%@5OM"BH1M;$HBE(>OL=7J MDD0?4*:8A#W9 &%)())"RF8-8UDT?&W<5;J39%[+?*39?77#<@5K<+J4<=9$ MGB*F ?@:CSR^2M%QB,&Q:N. ?BWQR9'1B8Y5V@(XZ6A<,=8;>U:DI&[$(R=6 MK!%41]LMVFW8%ZQP P)/LUM8_F:14=YE]@^G2.X:>XHNQ\("5S:(W7 T5CE- MH!!# 3J"-+<$'7H"H$F-]FFGE<3 :)B;O(W6I2W (Z_>!XM-FU$>$(*36OO M@YG"CVZGG0@\1DY+L_\^!C&O3!A*Z8(L6TA+!B)K#[MD;FW8-CSMGG7S@2@" MYYIPEWOF'(JSK:X*F(E0S': !?.,'%H,QMCEK^+$M4 L;U1W+T%A3:RJAP1= M6#GG70\G&M90J$U,R9X;F8FL\COV\<@ &NV=MZ=3PGS@\&;7B-H(PK-1R;3FJ)0$4 M0#@382B?QTZ0HUHN/X!S!B':8-1&M1T/ORL#TLX)Z%F*PVA7!T[O^L1$*=P< M2C+* 9%TV1Q>94MXB%VM*G9]*T$2C5M-S0",GG,;#R;DY-XP(T=T< -[0*2U M<[U:FR 'B0HA4QT$HZ3VD6-X4F3+M;4'&UFZH/GL,JDV_"$K M8;:9/7'XOX[B6*LDZK21OSOQ9P=?,.'XR7C,#<_[R.)XK9*0"(-'1#A_.;<% M5 ;7'2;K0[=L=YO>)S!8,])3-GB>#QLDZWNCO0?N5/"^(N,8C]-VJRY]Q;WG M)1ND+H:]DLTIYL$MF++><4F7/&3$X&HX289K"E\. !56,)+X-)!&40C#QH9B M)H^ 6,;[2T*556-B%^ X%5E)P3EK?)^DCJ;P,9$X:T=_DU2O-;-]+*,>'&WC MV'A+;CP<>)D*Z.2KV(1-),7C)R181>-H]_"QJ>$M=R'"F99F:Q3QE1)Z#DB&VY>''YX-IIL/'M[B.?R()!E MKP\+2\[$>JE+J@&S$52NM_WS-NL8;"%NQ(UMPYX0/<;D\WNBF[>L_Q'V8VGN M52)U.*@!;+O-16RC.BR6KNE4%<_P?;:)1?EI)3)J^9B@62STZHP;S7[5J;R* MXB=1TH4Q+R]P9BC%VM0G^.*I54>_'RPOS:<"T@>Z5PDC1F.$4AC M>(\4)5D ?A+^.AS#UUK=)GZ6V MLB$^.A([G1+F*D$&BYI^R%3R./K+/JW;?8F@[7JY59"60+')TG2 #JXLRTN2 M(>NTO'&I=QM$HV.)@G>>"\C.-C6%0L_-U$?3#%R/R0_5 RQ; AWP20HO[7M@ MO;GFA1KX7<+N(?. /0(RLMB, #QGV\KE59TH)X)7\.5V-9X(-LEEU4>!P4N\ M>3%+7H="(2S%L*E#*?A^.E3S2='UW"P-JWD19(:<;0\LCKK&N9UJ!*U]7)<> M[B4/X2% W1_GPYW-E[C8C'C'J3!C8U[C0X6 "3NBP)7R3!P_;?R6,F#4[SW(_; 2\S9J 7F (3"M5?C]BO9YL6LKUNB2)5YEUV;>Z$D8;]FQ M;LSC23C "T#V:==F487,2%;NB+Z9 >![VYIR,T9M50%YPFKSN0ZZ@ F6G0^. M/ST.F#M-9L\D^X9S?K%KG+Q4+DUK(_4YP"PX3>)D#9M@_T1V$EFZ:"TG$61) M H8?DNM$WAI.9%!XG;#!G&AY-DDBRI+7;+?-H5++2]'LF8J/4D2"KZ2VC-I_ M+O:U1"8+L0Z'>\J3J=$--S#T(-AICA[84=64:B%>6;J]C]7FMGB7B#$#<3'F M>LI"-#5 3K8,7+:M(Y<,,J>QTZF$9MG;+AOPU/$DI_KM"VIV)E7'@1K8QRYX M.44FN-4"D'IZN_=?)88B$I:**4L5Y9RB)WC(.+EDV=]>*1J5,[U=U)= M7,FV?CNV0?R77?<<@DTV5IFTJNP]DLK;S\HM3'G%M%F[@P'$$4[EL/#$4T7- MXEQ4)" Z 40Z)B\M]Q94_)!U4_Q-D'"J#\CB$,WV-800S264\Y2K!M^'BS.= M"90_\8A109ZP9E Q)1N1\V$<<4K9Q\DG8+> [Q"J/?%@.Q$-X0%QY0,H/IS) M>$Z"K:>8F5<$1& 5)RBH-L>8K--:4[%,6]@&=DRLA$\+QO_<S6R[.>\=%"6]]0)VG09_#KXTK'IHIZP TN12.PV#09^QK%BI%G6&AX=IIRG MV<=.\$1\*]L>3@3\MUE5UZ#.8,\G,6 :V4H1=CS:(7#*TR"'J31@;5@2N8B= MB6E'E>O>0I>Q2TFE;*%(CU*P'/EPW(A?EL8=B(M5LHM;K8QY62=6ZL?#' MD4W:2:;?. M-NT<8,$5*? X=4N%HF&'34]>%3L18P\AUW%]GC9O=?,'G6IP2[K+;)V$XQ0?JPQ*<*DI3%2>$/L\=[/V7>^8"HF^)8,>A,%$AY?SND[XMU4TBN.T:RPSG_NII5G53MTC^( ME&YV I8-([1)=C_8B)B8G1TJ41Y>Q]E_VPB[[5I\ U],E#GL^SOLDJS.SW&J M)3,A/@1-2ZRZV?.A-"#.M+-?5#BP9S57$TT"%2=$P\&1-_' JP^G2)I6<+#T M=VH#'-W4?QV*12FR#.:,G )J]($UP'90)/9.1SIE9W[;XX,/';E\%'$P&]4J,!)KA1)W'82$T" QQ M5.:EE)55P;1L^Q,E8#;AG6=DF1R63.9?,?9'.4W?[<4&U>/$.Q+L1:V_Y.GQ/8/2X[QL89K:5QR*)[M,<56K&7B M!*MRTVT1BBF((B$$JQ+( M8(O8VF Y.R 3\>;>[?^4%44O@OL'9&.0ID,;!@7G$17MPG!BVO95","(<:?@ MR:K>$MAL$C7<>9W- 1=\/C8 M6EFM>V"AAW;)\'&8U6M26%D)U1ZS/!Y&-4( M.LZJ:;7+N6R*Y!!&93&OBEP$JSA&;,XIA2'G1V+,QUXMS$CI?>4%B9#9)1;6ZXE !6FH*]?LYL;^2HUK2=XRA&*]FVLPP,?1R4(! [+?IR^@ *2MY; MACF3[>CXZYHW5:45/],-R2=:9V.DM@=RF?WJSI9)-2NRAI7HO#N@L4K&U*7J[9$R'* M'J T]BQ9.5<\+-D\6,)Z@"4*S7I=J[$[JL66S.6,@*S%\["<^ MMCIU6Y]M*1H1C7RJWE5#E^Z,4#6L.,^&XXAJP"_& P5KE%H5-7#6;<]1NHVO MW))IJX?4Z/S,WFM\JB'<'C<"O6>CG3*YO=L@QC@*2RWE>=E?!KBG(C:X.+ MWOKJ^I)VJ_!LJE2-FAH=^LX]RM/(F;'[#;AG5FA,M6%L>0#X27+!DY:RJ($U MXDJW#(Q"QK0_ZX0K&T$DR7XYY).S[0*',!QI,:X?=GN!6@2BW14<,@P2EQ$[ M+=;98"%2 @&IAZ]+Q:/+CEX'?NN06BE=3C5SU1+R6AZZS'* 9;/,65S7I<:? MPLC2'T4)RLT_\QRP<6HP)Z7,KQ\J=*P6=2FD3JM3HV"\"J'JT!WBP M&GBTT# W2/"/9PS_XB0*#6[*;);W9),@T35!9 OLS*+654DH+;^ M[WH>3P WJPIXS62:R030B#SGWGM.A(?[WFM_K:7G.JI6 V^L_FJ=]6@X"R!Y M(-J?F]VA^4S[HU0>8HNB;)8,_GF[E5(;KNR$H6M M 1"_!!=JO[/A3L>2I[D5#4C%E,MR<*G));&^4R&R$05,D#U/L0",&F$S00$ )2CE<2&NXIZ"??XB+@ BR&T6%05]\D13G%MKM M7C2BL9D<]$CPXZ13/C!N<;7%R8DN,]LXI6%AZ\J"MX'MSE4:B$M#0=E0'KP] M=[+,WH 9JXZG-.]IWZ MZ X;ED\LB&R.315?GJ7U\&JU:V$/N4&+,-!\5L,$^#Y)GO\F,>4E-^\N 9HT:,Y%V_M%S*I@K#)\(V]VL>"ZRVD4GZPA$,+FN5ND M(6QTR'HZ@5,):TX)>4SP$ S--8$59:I7#X1+JC*!=TFVB97MU.?QJ+YMO 8: MXYI!S1)878M:M ML>=A+!..\W7)I.[N=@T7H"P/5S%GR582=@E'.V\0+MF)-N5R!W_8*"K/J%*X:Q;QC&EWHLD)WP<0'66>F<[)LE)# M>G.QCT-TV$TG_3CPMNQ=&)]CD )P(Q[C,HQ3'N*GKNL M(;1C-1LJ]DV0I/1ID;@W175TQUPRMY:1V0C;HTH9R UG(+ H(MVN3H) W+;3;$(8-+6>59'=ZI M$RM0,&N+<.L1K,75"YRB="G2Z3I5QX5/-62:^;.CS"ZQZF(MDE6F*<"EWY=N M75I>%\8A7YMMFOD,F\*5L1U]4TF(*Y3<:X:2_427IO2]7L9ML MG:J3N9F=:R)25;2:JSX'#IOX7GQ=Q\;!E*4MR;XDOET7IH1%777/ ")KHADZ[DXG>6^M[6"-4/ M+ELIB?6M4 !:)*CNJWVTN=F!O=MRYH^=OFK!K R=F<2LRB-A4G"<&B (/(O3 M%'NS<018HOH%>"\3C,LG!SRKRC]BLU4-4CT95)%M'.5"$O?+L1P$/ 5GGFW5 M9>>4E"72<_8CMRK&L'CG8!J(8U,B^;8'6EYD$UN157IDNRAX.K:)QKT%50(; M2(ZX*I^GM)%R'W*J']LOHE)^Q]Q.EA_4*";O$DK$0VE=G$NY]"&'K*J/M)KC M44W\4%M$_J9LN:)2'AMRGN7)@[03Y#=5L1UFVGA34LR M58:667!,(!70<&8G@U7P(A.KH?+K9[DD-PDV+/35Z%;W2[EK(=AMDTU]9).2 M9YIUXAI41K) ;<:'B[ZMFHK#04Z. M@&@V;0[!#B;[@05I0&''H0FF3=#SO]4T^J,,ZZ'IW:.4;'*INDL(7)S9.I:6 MA_H&4:$:CF^0^V 05(:\79(V.@SNE!T@K*H*7_&3C]I9[13#*)9ABI^C6C!? M?)>\>W(82GH$]"9^JGB15:W&P:OD,Q6L-4VB%#F&D;BU$;TY60#H9-6B(7$Z M<";[J2(8@7]5@!>K[T1-D[@5_[M?2GS:(Y <,03O$EW4&/:PY1TC9"X.;J XBG2]SZ')MB?%AC+C#)]\EQ>9P-B:/S7/5&0NT"4P+A%=BDV."9[]X;.J?5,N]4Y8KF]?QQ9R%Q]YS_-A% MB,41/6PQN!T75$!:N>UMYB7U4&_6]-$K$>CB)B__W0A:"6#XW&C*%U_B6%J^ MS!>95.$.DP)8BT<']+@1NV35+WG.<[7(V''D!)R\<7L?K>=TJCVE4M5036MQ MT\<91RQ/\O;*<, ?9+3I?TY+I0I[FPQ(9O-,X!Q9$2+):I>X*/9IC2"*B!^I M)CBYT78SX _V$0=?O@V0BV]4$.7KB.13)RH M/^"H+CDI$L[Q.E($GW&U?9ZR)IBW3SZYN,;K>/+6#[&'AFQ."2CQ&W%P=H6O M$=P8L&_8F.D.\@%(%U!YR@Z'9,-QXJ_E@=0%SAY8A"M]T\*S(BGPD>3@%"3#O.T)X_DV%X:;!B#K(/ MJ6RG23VS&C+2!;'365;\%0?>#IO3PL&3EF:$%:ZI6H!LJ:JH.G4Y%99QQLN4 M= (,K#+NE).0+<4.Y=T8Y-&)AM^UR?/J ,\^+32I&FK*\'2RA?V P[NYX7;? MC@;*YGQ:0[$:-18CDR(.EP,[.-U=$MY\\BEV>+$7#!"(3N/2,B0(;0>;6I_- M-KELYCUMG+^3\].X+^S&N319FW)/)]$?O@ +5:MI#=LH92]8"C98YWU13AJ4 M2T&<)!\RGKYD^K5=]CHTCQ(>3PM$MC0/"^:"0;:(+7)-(6QUF(X=5#;2X!'M MJB.'>&V2_ <97F[^<.*,^1"L@JUR1/_$_F>^2=7AP)VMV\ZB<&F+)?2Q[C7,H *P.>:R\T7P\@YX4=J!\\/_J,4$!*]% MINV^89LY;_60?51MH$=]<9QJ42:$PWGO-I$Z%%PE];3UM"[AK:96IIT 35)4 MZQ#7)BO%Y/JE03S8)DF!V-9O/E%RFR1OMHHQ0Y[^.BYKGZR8["1"[U/ZKPL' M[)3 -I3?MCD\G&'%%?AL_:7J?>?V8ETAS[L M&\V;_-;WN8*$RX6SV22KK)=I*J;WRAVUW6P196I,3KW%>QO,Z9F MI39V0'S)4/Y[MPJ:!'3"W'Y-(]@;AEUAC6CTP91VR9PX2?"52J[6UX M P+^';M\K$35-6S;EY!&PA;\<=UGP=<%>VJO.1U7(MKDF-U8.2%TL!ZY9+TQ MY97CI!:>MEUA(O9IB&4-M=I 9&NL^@-MMV39S&JSNX\N?A&W8,?D>BL^SFB( MF%00:%&IS?-4SHP8LMKRC $,H$"/O?7JP]X^)3NO)D3HF,A3# L0/Q3L8BTV M#A=K,R^E3:O/X;JB%?O;<AT.WGC^I=M-(B$_ECG MC6A7<;%Q.6YP)Q-M4B:RHVR,Z0\8\W+H%6= X*!HM6X.?^<\( A:*DRT_1>#UM#%'1<94_SN>PEYV#VN:+?,H'N M)L%,<0%?@%"#FZQK9G^(,HO$"8X#M&$>^M'[/\2=>@<= 6:0(X>QP_)V+"UK M*P4%SR"IZ6SHI[9U.&V, J M'?,J/<7J!ZD=Q,KN!>Y<-LO;=(^#>$;R 8#3 M@1VV17 H650 "[O[>.PP#3S@UH<$_A-DS 8*_3+])$<-:%P6QLL.@S)%]2!' MM0"]+2Q?MYH&&)6>O*K+6I]56@5#3H>IG2!M*A \I>6A+(^,5H1#\Y&A:F-S M$Y\1I4M9?CAV',#B5LG:H7Q7&^PYA;"(]'GSN9V8F3XJ*Q?/JJ&*2]6L,]&<[ _&>$K/<]E_9F]^ M4>IN+E&"I4P&WD\6;%2S?'QT[+ ':[LX&=E[FI"*A<%1*@F$7P0W8!P!>X\U M2,,%&;CP%XNX-(7'@O(=./TWL-@^H;I:7+)"6(?]0VK!VGL994+MFZ+>>UN* M28P8W684PJPY_ M/>QRS+],,$FR_8?/B&#G"])!7*0I+,4X[/HBDB.VF/(-.>1>*LLLZH;<"Q&%29S'8Z;M7 )0.P0KQ) S@S3_T"[.T\ M;F? ;V"%U?ULPI(GX-#9$CF8MP.[ %=PVF=:(CZ0*SO85R-LQX$/%,Y+YN// M'_ _<'(5S3@#^ O"V$>^ MJ.#2L;YKMH)"8^#\S+9^L"V6[[D+'BQ1L SM@;/4O>*GW4B265 M+H5P5@%-F]PP19A_&=L=U<\H"(>+$/"IQ=_% @KV8;-WAS/,: M(K"3=:_$"E.^#>QXDQ\+ 7\P4L-K++SG=;E%XN%#5!9"A,[H9^5L,%?RB./ M<:V'Q!NA+,5W"W_\4_ H/K&P7H\#B^< UK&Z\/D,U9DU%NC[/>A3)H=8H>M\Q@O..QW8YQ,'J+'GXZ[+I :"G%3*A%W!2 M12WF4>R?.KDAR954.Y,8ZQ&7JJ93"A' L6$6J\=,[[/!M:RQ%V=(XA*UB&/(4Z, ..O3 M"8=X8+AM)<-.'JW%?0[2X?-54J=@?96 VQ[AIOI:PZ16D^N21V8%4Z;4N(3$ M+7$?3@]G.P%8O#AL^^\.?;DG;GD&B-*WC!7!4?.@)UB[6 Z5:L=I<4FG\D$( M]@@_XW08(2XM7RP27WQF>2 (HJ6W)88*..$E/F[I/QSF:#G0@,/+QNKKL;Q. MC%)6#MDTCD(?AY;'"?W*S1/8/&J1%$SA!GPC8O$@JS;"R13B655G;1K(LI_=MG%U5<10](>#A5 M3BX#KVX_)-;HC(=DMT5Q72U&:PI931MFQ/M93C-Y;8F*@VUFMIT3[1X^)%ON M'K,W)Z9$/3("G,6W@TFS8A8(:V]";T"[7!$RC<6'&>:G+;7&BI0P(P69\ MMOS-@D=*ZH-Q'_88 TT,__9F"<59N;Y)C&ATP"YR5-ATHDH0.["NVAK(!M N M* DJ0QWK-D^'$54R2_A7=;P6077;JPQ.:!.F^H? MC:'[\VQ% F,V:J_V(./LS1RG 5@KJFTI1G_; M,\="I#&&BJ_7+?/OL(ELINL6!%DO55'[6A\EH8-";S90W[%-55XV?C7:RKL7*&Q[>A9K;%BOX8R]G-?6FQF]IUD*.I%!7DD>U!SR#'" M(+M]@5ES? ;H"1F1GLBK/ MR.EQ->"$N](?<\HQ4O)0W\D2L!-_R:E?Y<\,M8'/N_/7>TVX;QXZ*'!IZ18@ ME".+JBL& *9\1ZM?#Z,['/]7WF/#4"9+YHYPC""5&,&/K46!$,4:6G94Z;;+ M-$L4R)YW3E3*CJ&1)4"I/'AI'I64^ MCHX[C7MG\YA740O;I%"0SV/G/MIF.;0X'-_LJ;V.L0C)] $VT9HUOQ3ZU>2I MDB+ORM%.[<1MHCM)_W@7&[;2N3EMY&K:=V?%%M?!QHRF;=9UWK;>N^-ERVU& M4Y=M[[@Z DX>O>+SECHXTVK*WY+YAD,^(5 _BZ&QLW!-*(%-O[(4&3**%J=L M%#=9>3\[)1R5O^U.;9I<&>>#]:40];8L?#%K_P308K'%*>"L%+%K5F!FN[40 M/A*3<:R3.CP1WR>%<@ )O+!LZQ\+"9_B?:< M01U(O(3"1WL4O$F:28(MVR;;M69MSL6!X?P/P!T?+J/DK8?E)O!A M[.=1TRF]XM)RQB3L<]NK4[6+2>EQ$'.JE&';F\PFCL9_GGRZU)RP>T:N,GG^ M6K;GS\##!KAVR"QJL;3JF!7)T+ECO67.KQ+KKU0+YMF9,SNH;7ITTF\TH8Q/ MZ5#L*EB&L3=^ ]B%HF1)E]5'<5EK1$ZA-L7"V>\*WB2SV/QSF&0+J_<:)YUW M^65-U*K&'N:FGH#45D2E.E17SH*3K?/8&0QL=UOR"*Y+D<:Q0E8LM5T(EO 5 M:;)#Y;F/@[#:>7'5?9JLP_TV_7<*RT-1W\SIC'1[&@^S@B >^90O0$X3JA'I MRF^M[2A]4V')-^1VO]+ 16+IKZ>:@S6EB354:R$X*6^/WF+4!:[C'0ZY?/+Q M3-4XI>HRJM,MX1Z"S<3LF^B#X-C;1F)OXWWO<@D0B _%::6!/G'BG# >MZR# M#AZRX25LDG_A!B"?BDR>[)EY!04X5)'&EW15R,0 U^ WL"EF..Y@=M9&HXZM MER;4![MONW^5I9=Q^" DQPUP6_?J(=$T2+_9.YA6TY@Q3[M2=+6L=-ZT<]^L MLX66?7OJH@?GP>XX_:'T-E!KL=6?Q3XT\/QMQQ,/>?(1G#:PWZ[V$R%GL+=: M5?D;W#WL,AOY[3 MS+*F;+PT+R8N&;#-)D MS!KW-N5KG)+2XT85WY;'Z[9Y>77;2!/5V! "<P?RHM_BUO:[[6M(_I"Z_K#K M>EL7&\H*YPXMPZ$^IX)E5<(ZJU$8+0%#V/Z(3-7!H"6")QK[TKC2LC MS,$8*<(;\'-*>>JA6=*#*"PI%=AE(QR]6W 3(YJCN71M"9R,J5J=NP1RUV8N M3&7(()6KW.UXCS56DCA$6+[$3UH@U*NVQA<@D&%:!2E>RJ+M2IZQ^T( +VR6 M6^,ZXU*F)FMTV<&W71U7>_WL?SW5A)32HBN#LF3"QH[Q.VQ%K(N@& Q8-X)Y M@B6V"6@#B.P(*8] <2M+TTT^<+8#8:*@5I:61BS35MN#,T*+JZL?*V&_;VRF MPQDF6:+LQ3?\<,91QN4J"PXF!=2H-"96CX\AX!>JS]9NZ[,\K47/XTC8IDQI MLN>AVJVIL%2W8>H>]MA*6F@:WDYWS,EC)/TX$#HU(PI,J47*HU'W/H\M+II_ M_MRAES0?@1GO),52@-2*0NYW%%[P '&<>GQ3^;BYPRX+7#Q+A-TDL-P&. !+ M&E"\.TJ*\>75.;+ >>/K>.Q]E-I'EL_I+Z-LI[<$;\I8M8C M\@ EYY7+V0(.X2;>C4"/%<<9*G\)RKZ5(=OOU0KXF(A5E-G8P8+0OCE'S"9S M&GED,0F'/*A5UUMRF.HT&W%.'6Y3*76W^^M4A];!FMUT2EWCI/D(VPFP! ]> M,DTY";4DA3@=XICR./FRJ^AIK!B,[0EB+N4<OW< M$M=8.<,/='O)U8=UB!3;55008R% =U%IQ2&G7Y-=T"[;Y@"/HFX;QL0ZXBG5 M=G%$2Q9<3*OF?#QVQ"L?EYUCN\OAX.XI'_9T)/14 Q=C*V? +C]M=I,&8YZI MI,YU60SAPJP33<4!"7'Y(\+*(G&QVB^%4R)IQTK>YZH-1 MX1\'+434YORG93(SM#[#]BQ%HK/C_G=9:,_9%>1HK)6UULI5G%N1T\G>@)95 MC'5^3*XUV=\P%?70O-0#^WD^3H8[:#&K=&JV4W#$)!J:1(M/'OA-DR%W>=P\ MV;&1C/'>+2E)2'7),[QX4TVZJ"27):1>VFNFR' 'SP-"#')]J%/A]*345M&9 M+.LX2@D'N4CP8R!^!4,<:W%$))CQ?6SL:T2.:(=XWV22%?E*;UB8,W#7'!;=Q6P:7&L)9C5MA^WKF;6*?^]Q7#I#S M'\52@'X\R!55YEM\:M+GJ1-G_Y(\$ +_BV-+ ,\YK8OL=_;+/.UA?IY301R2 M'3_OTG[$R]:3:]'_ET4L3BBP8PPM<\D+G.3/59:<)VI,WTO<(E?D8 H?)8_D MN;3EGE$, R4VJ"HKLMAST8A:>@:%8CF X[(O<1/8F<[2C!PWI;?:FM>W?]K6 M)/6:;$)U6DJI=TQ#<()+MU1PEOC%@B=E=P/<@PSKTJM<]TB;=+%X3.)-GDK* MZUC+X$*<:PO\8BRNPD?,FC*<#UBJJ#ZJ]VFC\ 2?]6:Z53%O2=?L M@[\?1Y[8$H]G?PEM.>0G?;>_IG)'V]DG' W_1L7;HN!XW(AFE/IQS.7,EEH+ MEA=(MK(.TEN.Z00"OR4#$D!-+&C3C4TMCMNK;VGY%/<+<&GRYF/^#8JL5=DA M\N":]S#D\Y+MY@(]U1%7S9;UTA?9:")%-Y"U+DG.FI8 MJZR*M^&KB00",P#)M:B:3+"VQ,><;>EG:6M+6LUE=6PVH$KM)/.'#28S. Q MZ,SB'DL&3T9ZL&QQC,B,0#/#O)LFLX5(NA@Q?>"D;J'MI[P%!F=#NV=H7DT_ M8&*'&^WH4^I-26)-)&,)I?7,()>BT)IYQ3ALNU>2B;NS#.P$D%TK%Z@=T%HD M6\R=>^"S9&G9;1A0TGL'/#@G?"F6>#?Y >3/OS9$401,:#-M3*D=$MHCA MT&OI59)9"3@Y1GAC':@B=55R"\Q(:-O8!+E98[5HZ?%44 H_/I1"G MK!'] @AI1*(Z9W*LVOIUXY/B+6\$7K[),IWD*#= 9!7P:\GNP:JB$;BCWO>: M,%(Q+4Q3ZS5#S#%J^2%B4 SD>2$C"5N>WS<0IJ ME+DF3BK9= M=5';Q66S/A0%8$LX)#;D3;^+\CO$''I%"0$41L-FS4YP)O>. Q!%TCA9S)3% M&\&B LZ!(&FE\H9=5@<6D(UA2ZBM34JNRC2Y2_.W6\1@BG6$FQO(>!0J(7G%KNWR:.N]F!I:+MBZ&:Y]V*]P2M(+T-[O+'*&[GB7Q6ZN +U["Z8@_B6=0 M\;3)QE/Y'2#-H8\T8\EO9@)#(&!6XJP W$Q!J MDP !#U3:?9P&4%*%')W@1.&YBRCRENB0( 9X@'%WZV YJT>&K69F)RF W-6( MMG/*(Z^ \!+ BWU8H M;^<2NDB?XS2CY$I*'E^*SQ(U.?>%/1GGEF]K^HY<\(]F/M&O_R]M/W'[]Y^^F?MFW[J[^Z/WS]?/SP/?_J+[]Y M]\%__\V;\7?_\6]CV/[JO_O[?_SK]O7'7[WX]E_'7\0__NA-_ 4F@C\:GU[> M?O_NXX?Y]ON7OWFCXN6;Y^57_(/_^YLS_TW,?,F;\?';WW]Z]YO??O_FWXQ_ MZV^5-^V;ET_OOGK[X_,/+]^]?/J7EZ]_L0&?WGS][JOOW_S*:]U^Z67][8=??WQ3/K_]]0_? M_O%'__+RZ3NNZ\V_65?Z;]]PG5]__/#^]V^^?OGU]LM__Y'O>^%J_F]?V)^Y MKI]^^//#^_?__NTW?OQ:K)_]_.TW[][__@^_\?&;;W_X_N73F[_[^/7+IP\_ M_=7__/+YXO[NY>MW/WSSTY_^[?=OW[_[JGWXS?N7-W\=CU^$X_/[[[Y[WOWN MY>N_?_?]5[]]\^NW[[][6>^_?/CZIU?"^JWK^.4?'NMZ]^_?OOOP_7_\_;_>_.^!Y8W\(O_]X[_^CY]\R_WAJX]?O_OPFS?IS&_> M?OKT]O<;&XA7YYO_&M^\^_#UR^_>O/R.2_WE+SY\_)X_><.2_+_G"_OO__RK?W-+__C;U]^]-;QYI?_[NTWO_KZ MR_?.-[_\+^^^>)W?_/+OOWQ=WOSR']_]YD=?=KWYY7_Z]KMW[]E.KV]6_NZW M7_QA";SQW9=O<$'_X9N7WWSQ284+^O6OOWC-Q?SZRS_A8G[]_HO7Q=__\AO?_]\6[K.-O/KW]EY?OKS7B\O^U:>7'_TA5_[-VZ]^_&M<_2>?\^L[7/]7;-WW[[]8A(M[^,W+ MIV_>?OCZ5^^_^^)];N7M%U]1N8F/7[[F\C]^]_[M=[_]XCVNO]U?O';-OWS- ME?^'G_X-E_[=#]]^^XG5^>)=+O[K=R^\^>[UW?"SC??3;9=^NNGVGVVYXT<; M[OS1=LL_W6SEYUOM^O%&JS_99N%GNRS^>).E'^^Q_<=;[/C)#CM_LL'RG]M? MY<]NKY_MKOK3S97"3_=6BC_=6BG];&>E_2<;*QT_WU?I_+/;*N4?[:I4?K2I MTO6S/97JC[;4'GZTH_;XLPVUIS^SGW8N&9OV_NTWKV]QT?_\P\?O7[B^SS[G M3S_ATC_\\,VO=%F_>;WMG4O_#M_P_LM;W[F!;U\^??7RX8N_YR[>?L.[WW'S MK^_6/WS?C[_LX(:^??OIYGV3>_OV_0^O M-WOX.#Y^>4X.[NBWO__VMR^O=W/D=>'O/KY>X<&]_'@M#^[D_WSY]/'U#6[B MXX?7!W9R]=__Z^O/3Z[[^]]^>OGB-]SO'W_X]/J&._[=%SOLY'*_PW?]Z;4& M@2WX>JWXJ5^^_&@A3B[UP[LO+^3RGK\\IV?U8[YY]^-W<_CC1OCZX[]^\3;7 M_?+//[Q]/6FZM'_^X>4[T=2/?W5__<'KF]S#V]?+TZNUUU=7W%-?_OZBHOY'U]?<2W_T^LKKN7?O;[B M6O[N]177\N]?7W$M_^'5ZNE.7U]Q+?_SZRNNY1]>7W$M__CZBFOYCZ^ON);_ M]/J*:_E?7E]Q+?_Y]177\E]>7W$M_^NKR>5:_K?75\MDO?WJGUZ^_]$1JNGU M?/_X!_N?_N#'ITOO]-6[3U_]\,VOW[^\[D<=%.;U[5<_.N0ZJ/7Q/_YL;N+U MV%5NXE>OK[B)K[YP%(*"+UZZ []XZ;'YXB77_(4C!UG^\@L7&KC"+UT0E_:% M(PA,E5_?#%2Z[J7[YXR57]ZQ<^DZOZW1/O_NM?BY#_.F% 6;?,=JK_[<>_^9\^O,/,_.W$ MQCH(=*UWO_KA$T[A^Q5=<8]_?/WK=X0<+R^_>_EJVY9T2#QLQQSIFHWO"4H- M.P69+LDPGL?&QY3K8?76OI?:%YWB>4O;YT"AY#Q7J5LTSUFJU'J27,I.Z$B> M"K[7KC#/T2[YP=)LUY16LAY'DFS2R>9\SY!K::/87A"W>W<6Z#EL2SW&?9R/ MY0Q%B6L9=C!$]8\N&XG4KSB58@8RKDFAZ3SZWF^Y9=K1]JWL04K\:X^+DB@K MJY?NP^1@S\G9RY964Z,$E^DY=C5K4G-^H-CDY5+8D/#,<6_29?=R=C43)>"U M%V#4TVI7SM:CCUP:W]";C>AR^JE8=4D!,/-E0DNAMJ+,S;,=CRH.CX-OCN?5 M6WGG8#-[6;3(?%"WC' 5R_T2 DO6VE4-=T! N5"E4E/7/?;JSM;BF*Z3);/V:DUO)H2@ 5)S4OVP\>QJ/8#I6NO>M$<$$R M58/UE21HR+0;9!5Q3.'*=B78?6-Z_+R?/PQF!_R5;D3$XRV<;6&2LK7XXT9"RQ!M:7@FN2>$ZQ7D6@2[_8-#8Y M/O8%KDY&MIP50OG75(.SG7GFT,\KVF3-GCZG$QFLLI3=1:TTN1-J7^)M$FVQ M0^?J?.QG[%(?SUW=Y.!(F*QVCY/Y)@-G5#2O5\[2L<\T\Z&(V):7SD!V1N2( M\@A+ZQ%Z+[L4&IDU.CI_?T@@EF:0)D-"YY'BHG.18B#9PWJ?\=J<*SR/.0\E M"*14:$ZJNO)UR4M(!F)AT:UU#T<3CJF82^4D.V:'&2WA"L>,9]LDJ*B+3;>T MBY-[V0D2CA+9PU(K.?$@)U66(F_/T=8E&0<<^97+2<;N_3J/\%QCD^7]42GN MEB>#M>+855LJK8\6>R/3DQ9#HE=SE=9/F8SE",[M/"06Y6PLI?6ZR<+Q=$O^ M"I-*WZZ2=;3J.YWGY^NM@M]CXG.Y%_>.L37*$MMQV3DN7FNPG?SB7[.)G"W;@'56Z ML?U6J5Q6V$M*@R[#1.=(E@N;AUV-\[1-O>?2N\*@*<\1[WQ+D.186MOFWBSH M'>I0J+^3:F-/2\^<'"R.MT)+X7 *+9[]=O7YYG1PRT?CA8(.B\WU"F&3'OF< M&) T',I]Y$66->\P%Y\D/; -O.:F/K%J\]CN0W6EZH2H?+"*@& <9S^VIB<8 M!^\7"58XC6'Y3BVTU_'TY$!EOTZ,37*^PVYI7(VKQ"9-7F<;W$\N!\U3^X2]]"?OBSIQ&HU:\+9^C[/*3KMNT^=FJH47 _$G!SG!QK;WTJ)^&H[N#*,&!YPYK& MQF.3T_]Y\JC*PUM@:*4&B\+V$"J7S)9O&,W*,99FY^H\@RI55^G6]-@_:4OR M@2C9?5ZY2&W#$LEK\-P.%-=%S^5^MU;$X\"M,=K,;)U$BI6T;ZTL M#6&>5%?9]>) MMLB_AZ4.)(H^+2"E6S18+L[(:*R6@_[H@)Z9-/&"G"8$YOV MLJNNA"*/A,8H!L"9*"J9X7"=>F&//XSS9$OF(/HI=FJ6PGY[#N>,#\1Y; MZ>QJU>8D '% -E]KSN4,0$7."C97E^(P 3M1C?'+7H>E5YY53.7\LL;X\//< MTOUDIS5&3^R[7%A.=BP&AE^3!6\^16[\,REP:7=S;0H=\=!\*JJ#MF89LV$9 M-C:9^AX*I]@N?',45!_'L>LD# VT!$-.]!8YC8>3#_V5Q:M MJV^3T[WF)W:)'MSBY](Z(2'[G&9$%)NQJ-33W%*&/4 MMH:I.)V[#>G FC,[EWH>DJT,];3V5OM]AWQD*YS\\CU3JD'MXWT\K>S*U43< MX0P;SVVHO(%E.O&&5C^=HTTVR4AJ41V6W-=XSLG)36/Q*8I%\KF$#&7FLXJ/ M\][XFMX?91^7^U)@5UU7?/Q81E#Y+Q"C?,WC=M8T^+POR6,PT%&JEWXEA\G. M>Y.J\%2V5<&)1Y[(TQ[Q4W9[B7%M-[E.%EAR3,R)[09 *QXV>("5C ]QDO5( MG//F:'4*#@0K#2[_*%ON I/;CE6!2Q)]ZKL\$,I.],1&SDO[%& M[6+F[EJ+?4N!;L%4]ZI+:Y.?.V #J6)@6M4W!.$\NU8RL8!PY+FU?#L]24 MO6TXPBDWVJW(+I_*&4[V[^*C#_F(U1AB]79.V.& H^P B05MH)7LB%H>V)MH MF39MAS:FR[LVU7Z[G#FV@R(UQZEYJH]B)C/KZ#C%49YJ8%]53GN>9U<'Z+I" MER4:A\+/3ON MKB5'7:UDJP2V'D27B0E((L59/(F-.45QS,:VV,?Y! 7E\#YEBJ5DUY+XNO$H M,/%E*TZNKG&&QY][W%SM@)3_?@_V9Z@:W1]K=JL&'1?@AH&04VPZE^6=-BMF&!B)Z8J*;NL MZ*H&;W;E2TU*(%:;#02.<:MC.J;T/)^' .T]!A$$#OYBSCW/6/"G4;FI*!FH MRJ?J'3UKJ TD KIE03"1ZBN+M,JC4)TPS8$!/R!XST ";'BPN]GA0KP>>T:) M\[%Y" -KWJ5AD0W=F;3#'7%EA2%E<<71UB:"4I J M3AC ' 3MP^%1R^W1.)<\E_4&H&8UE0/K/VFX@.2+6 M?=OC6=3?4??*;LF)!90+G'TIF5%?DD.7].P9".,3\0@]#F9A%T$90?V\*6=V MWR3?38L03E$-C)AS?1?VX[HD R1DW6UXEBU)%EK\XZE=5=7:ULQ3@A.V-Y#C M/#8W,O?/!Y]R=ZJ/I8*@G2PX2CNMY1>^V;G5MB.E@)(D5(1D> CB7OS.FMXM MN6_G?>-.\-W2=ZG\WB4X5="Y"4JQN+A=!?!N#E#0TW&$VM%56<6@+]G,:.O= M:!C'+N%8[4!D,,I=YR'RJDK9A<=L3.AC@!: BZ"8H M &YSEQ,14P& RV[)70F TY:WX"A-2ZH@>KW858FIL?+S,DN1,W>F2F/LJJ'@ MAS;&T9D]3E"+9\VNHG:Z:->7R7&NFW W JZQV7DV[89Q'> M)'9*SO@Z;LX= *MJ7LSYN3ER?!AH)IN_[73F>]6^K9(97ZOI"E.+%26P4$*Y M2F8-7AG#QFP)XO%'*E[%['K/S_14W /1AM+GMH?V-<91Y2&-022CI%OGFAZ' MB3CH& ">Y?/1L+9?EV2IF[% M@1,;3W$GW5FIONL_@DS5I\KJLG(M4CX3CH'XJZ+:][1'2$J(? V>C3/H:K#P+*72 H,Z=C!Q_ #D M;$?B?MGDGJ^EX3P'AE75=/-$R6XY&]UE!L96[KR,;A0O1W;T8;Y/8<[R%RI#/H@K-MV M.VZ+?6L\7N+[Q!X0>-H=MK0,%#Z37+M*XT <>"K(S+Y?DZZ3G8C1$VOL\]HJ M,8#42I//DY_./KS^X&15^N'7U WAH:DA=2?5[,UBU\M:5L5R%GA,*G(^H8O'\B1H) @4V/H&3]G,EG/#V"K"&PXK'\8% M/Z?^G@6+'+WI: E.;6)8([YGI4:6Y(E!IA.=&7=N^$=@!1 [E1Z=*N(61ZHQ M))ATO(IS?AYBOIM]4,P_A"E3LR+O,RX2+.51'0GC62R^XJ0^L(.#A4VX@9T3 M(!Q4MGND+IGV)/<9-F;O+"7?I:P-YWJ"&K-YM90D;@#&^^CZ(IJS]WALA =& M<&J:E#HG]OULCW-H6>$3QUEP,,X7L%L(+4SC. QD3Y]D KLJYUG;# S:B)F; M:=A=JY>)ER6P%N\ ];&0IZCO 3Z+7MJ0+9L'+@.#4LI\;EY5 0[M@W?D3U/'";J5Y3)-U^))2-\;6JGREJF_F,RN\P/,#BLZ'1N BL(9C\<[CNN3?8) M@)^RYT0M)L].!6#:'6_E&7=%]' V!-/9$5),I;-GCMIJ=!MA8U-1S!&(P]4+=$_<8>X'8]E,,?CD3NSG9PJ\S3 PAB5*G4B M)^'G )W#;)V]SP_'N2_B=)/^(YR0BLK[[-/%XC47CF&Y) M:W&:!P]&"MY6'2 >[K>T^+ON:9C2K;!ZLF*90ZX+3D/A,(COB$[8@6WQN2IP# MW+*T69@/(1Z@;Y=JB!@3(#FY4@?>38RN?(0P8^E2#'Q"/Z\/!K")15.9<(4K\"CHQC,S!$!6#>ITC 0=$-S^ $ M<%%6,]DMWD2OP+PE67 ?5W,(F'4%@7 GN1OM5;DPS=RJ*KD_4I 2>#W;)<]' M4+]OF.:4 .>(IV,EJD9*1<-QRPZCF_]7F6;II@S'(Y532:J4*8-R/$Z,W*K2 MX)DP7\!PCM[B7#O,0B0&8#%!7IND'3C%>8<:!4E2="FZ%4\GGG(T6.R ?@X=8;Q3GDUUF>= M-+@W+*$][ISH;#C*.&XG3,U^*9.0U/W!JYR2H2Q9$%P7&UFM!$SV)BF#Y#[1 M#,:=C0>J!#Y#%12%L![ULK&460'/0E3& NT25E>L8L1:))4'0)D$%14W?;>[ M.2+&.=:AY[Z8Y^79X1#@5;AD)1N.X0 *FY\H/"CZP!//;4E3JYAR'UM1'9A+ MN^20DL%6>6E !5==;21W^G=*3GZI;Z= #4;[E!*9TVOWOP0YK'F7/41.Q.ZT M@$F[VR)146P'?!WQ.%>M71DS1[FD+N&^URRN^BX3B\J&(/A?KI UW@ 9!3LO M!]VMFDIJ0C<0OGP"7?*G8OVNG,Z:?6I7[<3F FK'%N!&H#$DW+[4) MU.(,>4%?0D93I#PJH_G=AG]IU IH$^#%@9&TMT@Y7#C2-]XVADV2=$=',+/] M*?A*+/:MZE269.<&/$["8PMELIJ>-]>,A9*6:WC0+HAOO3!S /[ -Z<$L*SRLHIQQVV[ 4"U!E M<58VZ13?+.*J*H\1J)X549]E5U,,QWAA/H>*"CT[?AI%]D2OK.MFJ%+&F#,N[DR'E(QL*&7Q+CD?3' $R;,S!E>:7AX )K,0O;-. M0%2/>RN.R?44'MF4RQ*YXCSE8D1*& P>X;X5!%+P!2^)L3FEM"L6Y<_/HP[Y M4HS':5BB=M709 SEV'8A/:MXX.PC3S. M>,G_&FXW0 +6J@_$CVT;M5;DO^-CM)#K'+#DL?#IW MSQ^72WHMIWIDFUU$U3E[@DZKZB9L"4KRXI'D3*I[X"1O52ES'E(*K>(CL0;8 M(-UR:W(6;P[GR:;C.CFYM1Y.0RGK&JU]$ HDIP"EQ+"^(4.E)Z77$.<# "4FN8=(RK[)R? ^E5V!H8K M]51QM#/8UC12!2G=\ZZW8XGJ9!JG[S)&P."T!5T1GK-&RV*C6KKL3Q6%->\M)-<^( %]%6E\67;7:( MA_'_'+A=1GW#O*6ZHV/B"UG[&XM@C935N %*LE"=$C$,FWYD3,5>G@]FG34R M[<(E[C:XV+R@BB^!Q27M)[ UJ;!^%Z6FNFF#QPN0HG:SO43M2ER&0KS^-QB8 M9@^*IZ[V="N?HR:WQ+)[ESG)>KITX;HA>9<'@G$H9&YQG9$\\:@<==^#.CW H M*5Z46TV3@&$ LC"S&%GGBH/\;9-#:"[/@R,905*2H!<",>QOM$U@EV7'1@^S M/8J3G0N-$F.TP*'-$M8KBW9ACEI6?7#5@S$,)W_&$TB;?)J<<1DM3.)(2<]Q M44QAE^XG>F)[4&&8/>#P:R;*5^SLQ*(0BK.S95$;!=?,AZFK.]0?Y;$:M21% MV'9I@&Y0/EL5V+?R=(3XRJUS*8G(,*I=G@@Q\'KJ*9Z6!%BDGNQ)40"[;43!6SZ$4^NS:Z:<' T<%)QPH*.M4Q $ ^RHVI M\;2KX9(649JYJK(;N!@VL/79\54C3Y "W.8^0P%YIZ(9\X];1.X].WNE8I64U M1V]A'1!TFCQPQM-"'9;/GC#\R&/%2&4.N58(VO@:3=NP)+9U.>.L7$L8NX-?O,H@.[I]Q8 MCUC\2,"S)-*.PG,,EYR0A#53]4F3(-*$1X]RE]9"EOW,TS2O=/!?W"V/%-PF M+)WJ>.!R;C: ;*K6\C@8\O[;+HB)VPT=(FC'W/^#PTO/QJDC9M]!1L5&28X[ MD()0W_:HMIC%I;?+BK!D+T J0X+_HRC7*D6L^5 ,@AJ:FXP@MZTYES+%MU1? MQ-$]+8;^:4HX[JI&GA:;16/3 :H-\-/WDS0996"V&Z/N9X$ MC+79,A0%ISB=&JFLR.I7^G(ITV50#W))##7"MPGWH M!!VRK)^8\*-)=1GD*=[I4J.GXIOE?B>^_#P@S_^J@ .LKP"Z,YO: M%10I)"9_$&'2R>("L^SZ6U/*<\G;) N..(?.PH5[-X&PL1)U5],8D\TG!7N2 M'-[WEII_1@" \Y/E-K*K%%&HH:N*/25Z5A>M<+J,W.JF;-^4P32K_2C?J$V, MNY*:_;8%C0-#C+;4EH!#-K3*B'J95'?#BH3G4IQKUS:46\0:809.OP"TPG.\ MK%"5]BEUWB !D9GLA/;D7 +;%5U:D/S!V_C"?--B8?#U=\;N8\Y]6E1R*0W*G6X&K22AW]5\;AP-#.ST) ];GC G;!M)NB M%GOF4'*8L<=AJ"US+@X*X '&78'&)J]&LGJ"E\%KJ(^]J5L_E:J5/^=0Y5L" MXR#W Z8VLX%/_^26@Z(HMV)+PK,D%X)]7#&#C8[#[.+<)-+ON]XFWZ((/@L M8WLS"T@HV$WO5G6K'J71)9$7)O*!O!T R&SD8R63^KT]CWF3KAZD+-XF=[LV MV"[E0C1FN2GL$"T,BJ!ZS@"#2G56AFMR^)X21AO39N*7B'[+>@VH;BSO8R M'RJ-X:C2;;A'2-%EB7,)C"E#EL*+;?"88&E*BDZ9?7BNOCK4(I>%_#1-SDU* MA2<_Q\"*V3LPQ9Q&@OCLNJIPNQ'G(USNJCL$=9RGG;.$9X1;QDIJ207.*B<1 MAV0[S*F^VU4O%=MFP/O$I6BWQ+$FWX.Y5*?]$6W+W3= //A@&>W5)L8BE4,& M?LLMYD(S>&CR()538GO*L(_3PHR CU=$ M21+R2]*#^[D:.S&Q8ZUNJ[N.$23X..R:F-R&JHN;G2BL$F;!OG]"JE/E!"P?I'J@BZ(_7R;Y!K!ML\PF>\GMT(/;R@0E:#!;9',= MKU9,-P].(KL$ZS--1"9;#'@*Q*[LAB.X263?[1@._&:5Q$A5;344E [DA!U9 M66X>IHG=4ZE/Z^R+Y5YI)P#2$(7QL J'-F^C !/ %_&QH[?)E"(J5P%NY!Q94;N-0EXYSL'V-W2X)YWZ8Y0:7% &QBSV3["L#&462T M!<0#YPQKC33J/4"$59F)]'9:1BM@.;_)F"!3_V; 9^DE1V&Z0/3LUDRU[Z""+2Q=)3 M\1A*DTRYJ-F'Q'?.1#R:W!.(;RDN*18?MGVVM-SP[>4I:[(#K //;5[ML:5=9NQ M@.J9)WZ<8_7N.<* _P$] 0X;KC4?)2M"KA"0S:)[*=A V?YE+$R77$M#-\09 M /,'YYHNY;%; F"E:HVEJ+XB?NVW5-22V/F)_!8PD^-FFC+'?15BQ^?>N\)# M3-$BZ6'7(D OL3YR.,NT0ZS=$BN=9,PLF[3]LJB%$D(FJ0NUUZ>U^YW".4P05(,394M=H4>AO7!,A^/"(&0S\LJ M,^!MA3LY3'6BU6[\+"K\\M]6=+.W5?=C=P5*/@T@G-04![&J+M;-[ MDDJXVH'+\K341SR!/2EL8AQ7 M' KG)$<9BUJT!D%,.!\E3@07YP%0;'E3D.V\V+'2;V$L=@VETT1V/4>[HPW- M:R, #@:^IYR7//MQ*G#F*2J2R^W6,#>K-'BCKF (5HBP1$'Q&+!@IJ+P7Q0ZX M%XLV=O)T@Q0IA7?!!)&4%(J +7SZM6_!CGH3I:JB7TJ6[$ZM64FX^#TY/(.$ MZ#[D")I4&5W=GUVIE*4:W5>=JA/^;^RH6)=DO"21P![SG]51K4XT2 RFRC;! M[!$-,.U+P_YSX&H2SAZ2=Q-=R8Z8QJ:0$>9_\"&F4TX+#_G,-QXLA25))"M9 MDIUS9-8"U()!(^X%(52,C7*N>SYD*9P EX,?J0U$]*#""28+ X._4I_QCH\- MIYPMAP YMV >!=5JD17P$5ND?=&&)C#.IAZA3<#J"U_F4-)CKX7:ITI!WZ69 MV^NF. "@G/,0NSWLA%1! CCP/9MGJ- /)CV_+-@?%Y5D:NV8DT1CQ)L'QDR M'#^K-A+L9F7[J(Z85GL1 >_U\/@$3B#LC4A$^OFJUA]X0@(SEN-LMH&>"NT" M3^Q=T^@JMQ[$'9RPJM<"P#0[;MDEF-:P.>]CO9PU8BW F#9GNA:<_C,DT"N^ M6(4#]@"QB829ZE&!R:W%=$O\!9.!B^UETUO<]J9WO.-%H)HTXI)(LGPJ?805>#ASYT,V9L]+5SG8287X\/: M& %59U""-.,"'/SGX-1=/-S]4OKQ <4\FV%)P^W9;7QCPZ2YMVK4>7A@K=-H MUW:((/0S6!:0+QE;9X3R<4;6H(C<[F-;6(CH/]M#:H6KSL/61^,0B4LUQ,(V MC[D$ZV;;UCRLF0&+K(ZMJ$@P=ZQ&/RZG>VJL2A'W[M#OHZ0[YD7N=)6DVVT+ M?R.Z4M$[#[OWL%;LDP&^M8\RI QV/;B8UD5:Q%>M2;I387J/94*R-(.;I+5$X0 MQPF+?,XE:5^T,TWT<:15X633G7?>V.7!LH1]D_VZE1X$UP(T;B*F?08-\Z$B M@BV#^.$AM5VL2P$(("EWGDC6*]0-_L0B- !1TG&S)U%8JD<;&(7.JWW(1Q-WM+^-#]4HXZ%4X(BTDBS@EY.^NM A0WEE'6VJ[&BL/?OEDY=4- MNM6. +0#C]A(EV/#ZJ9=6I5%\\9(FWVRH\8S/WLEKWQVI!Z?A43K$!40V+2KE9 MMV:=<@'_X1W+*"(>_L#IH.*3M?)"+-^W&56]!.,J&RG%ZQJ#X:=VRK*V[-A3 M@WN:5F2*V9[@IC64<4_ND,T6'*HCI'S\137$#5T< M_"VK(L?FZ58(*AC'N8H9B2L DK6-3:YP1SN:)8'K(<; )\H)'=28OF5YM\.' MG7$MQ;M= 3O5"3#*.$.-**YU3I70-U/%D:?/\:CVP-U6)6!9,#YFV*)SSX7RPL41C0?R^;8T*%:(@@W=R'LFH83O;]]=3L/$_! MSCI>H9]O4]70YYI(L"28^6*CQ5,$!@O2G1@6FE/SV,A\\"Z3'O[]/]F M%0.WJJ**L^SE-@Z :G?$Z)+1GIB@6Z)I(LUZVT7.'LU 4;EQ,?$U M>@"&LR5S5%N7J!37BRPN4K"R0_ MR.GL7(]NNA/+-,9JOAGJ:H1&6#9V9UXO"3IVQ^X<@SGLWVO*FAI3V2QA/S4' M@.T6'&#C-*L5+,SEA@+@WCY?_&W8;.?@T /<+NUVP7!FA2&.Q7TO6;69,QR* MI G.INM(@%0WRV4OTJT!4!.8N&\S)V7_OZT>CK5?Q!@A^5#2Q'%);8]-4E, MXX_%5*9,4=4&[NT=(,.)Y53LOMA829/4-G?9CNUA^$#N2K39<(0E/.J&-;%-]I&G]K:7YI%W8JBP<=HNK&*]TV 1 M8'3+QIO8=(>6O-_'Y:)L(^+.5FYH ^);M]M7YQ 8/0:YY+A]X!QRQ MX()IMYL\8<8X+])C7$3:@86MWV6F M=E2&&/:V'XO@%8"-\3R]* P)1<-^5K]$(]70X S.6J+1#-Z#< M1;6PZNP9D.7 Q*)=N.)S9:V)DUA.24I[,@A#^Q)9$P. >)P1*%%/ ]I3)9?G M5X&OI[+3*JZI^Q"C,Y$%M(VT6 NTF2MRS4K2 1"U M7[Q! % LFTH:<8'^I>\Y'+E4)_"V_R(1"R7!H&/=H=4GJO?'V09%9R%&U]:> MDSB'IQ2*RA9J#Q'_5G"V_2NYM\TPZ507+#I#-[F=J;H9Z."T9FB7(3&,L\*& M1)4?@'&SXF)F#?DS<%R6V8>P85,>#D@KCS81Y6$FN5B9&X:9]EX2(>8@ =&Y M2@]$.NR9)1,PN;#+RAYH0EUY(F%GO^SA5'/54L75#^Z:!UJ7ML)B3 C@R3RY MK2R#1%#IUR(T1X8_C$IJ#$G7G:UF^SK[%0GC[>.Y+_V="G!L#TL(A(]2K#L/ MZ;!N58/1GF*B -GD3[5NU8-MVW@N%7M4G)+9QPHEML7"(KNRWS->]D0TLVH< MM"DSO*ETTRSVB)Y&$7M5T?4\-H>"SSN9$C&A[J.MZH0?BGSSH0?1A]5LU1K. MP9-@UTMU,Z08E5K2Y=:9)A/_CHMK2Y+LX10!JMV7 \E3+H#]G$$.;=& MN]9(-4:X.UY_>C0O'JB%W32R)4EK0Y<+!L+KMKC[#I$[(-[:ZU,M.MA2GF6! MB(XQL+$JSA6[M"91K:XY]4W 1<"0U)V<#7.6]%$*JVN0(XT4P=O[*5*':0F,D>'TR)YZ-SOM0!B3X/HI5HH=)QY$/= M3@Z!PK&87@E1FCQ'QMYWV+CS/3F&(AU,TZ TNXFJU3Z-VY/D5(C5$N7)$RX M'4/&9N\(0:):)T6)PLM->\35/'WP@_[D8^?V6!.@M,<^7/:3BFO/\5E#27AT M"'8(5@D_;N7IE1G ZY:-&\]1BADL:GP&<2PV5-I\)TN>I '.GX?%CKB2UL'I M\$<=JF!8]=@KSLI*6+(Y>EA51U05]22"BH9+T_WU*%UK:Q;60^E(&PB)3FQK MR&SF.YF^(K3BK)H MUU 1JGXV+>"0^&3%&VV=:_MQ%KLX"Q=QF7M*0?[*$$C MSI>S2W"KEF+ET+>--O04\7JSS[DS.8:LCQBI][CL(W*X"ZL2/>?TE]A&; MIAM3G/)<4E$U+7FL9R/ <9#A4@>)?6DPS,>=#\#T.0SE1!>EF=TF7@!9J6KM$$DP%9 MBK0:#H+@A\ZKKZP6/^/*%/4B*O!9)Z(7QT5WV4%LYN&93@"ZRGL.3)UL_ZLI MM_(0/KV0RIIP_[9I,(@E D@2T4A@$_[M:9N^!O[AHOT4\K^8772;&M M.1WJ@; CLZVA=OZ"94$,&U@3:Z'*SND(]'S$&OL G4B*PEI;]Y,V"R0\U.VT M%FT"U#D"##+6AIU.S"&GO.$G:\9>6[\Z"5]]P18NQ@7)\AO^S#2^F>()"65,)>5MJ&:A7P/1O/A8OUP4<4! &Q#6@*6/)C;T5DY%-0J8AF. MY5\)L Z^RW9Y$TG[ADLK)A:XJ,R88Z,$]6G_["HZM T9Z-,*08&_$6TEP2J6ARV-9M) MF?J<<1$JOOIXY\Z&Z%O%8:KP*7!W^'HO_,JM+J#-2FOEW(TO_8&.2;;(TK M68]F=YO#!IZ9",&F;/:G+B9(S"L1J)5;.TAL".W "S5>+P5,,5PX:R5.>DX. M(@)E[^=9&7#3[CR#L0&/FSCU27,ZW&R9_]H7(63'P>ZK79< J*H0RBYP9G7: MVN](=V9+S]P66RY1S6VWDI*^2H^T'$N "Y M>N)8;&(:8US%]MCJ2;%:O),V*68I2_"D_;BK[$=K]%GR1W8"U^X(K@7O;#O% M%!0H9/K8>6X0SSR1CEDU QQ('4ZZ8>^0IW3%;+1V*N!/M@ 64L>0C,/-$ MEE>Q!,-&;L?Y2"*V"ZL_/EL/ ][D"_[G$S#'::W^7H;,' C'L)%$/@00O)T+X6.ANRJ M;)IS1H*P F[WO%YI$SQ?QN&*TD4_]UR)0X,=<(C=*_@7S#H+9+F(6,5A0D<@ M,4[S46,+='Y*7[H-KH@G$_$BA&U$Z-4[)C0T1[8L[J/ 5%*9.IC]R+CQM.-E M5'9M2N'M.Z%7'.;/]O/Q8FMWWY[LQR+/"3YC/"H.6#]63+,IQ,XLR1V M"_'J)'AS:,/;"6?9,M$_1S<1JV;=N84/+ORP6)#Q8"T8"7SF3#%_K*X>IB(] MSC7$E=95_*TI R6+!;M1?R!%U(D!!XP1<12,3)\&UC(QVE8]%>&<:[P@*-A% M-.KTSMXYMM4V@4!8;9-,M'=AY0-/10"M8;%IL1CX.C C#C^QK(2@#HLKO_I8 MIP>8=5X 0<[@(/6FMKR@_AH'-@VXM4BBA@2^0(!HMXN=6)>'Y)(Z8(]+.UL= M6K8/IL4D/3?;=,+&FFNH"O"P6E BCV1?])TJ(@>)6@3*<@U-XT&;7#%311E: MHD-"'5GD]% ;D,-!2A5ABZW.:UI[V*)S3;L(=]Q*,F 9IR2R(A)%W*6NXBZD MHXE. 8-Z0MMF6U&JO!C<+<"V$V#;A$&BS09- 6Y/@5QN_7 X/ M^8CS>.JU87WE[#O-+Y:Z2VGGC+ ZU7VHSGI+(/PH%CB[1(0\/9D1DLU8BRG$ MA# 8_%+BVWGST:?#E.)3%HL/'HFX66I/GZ01^#VM18(#B5YO=8?MW2>FP@]) MTJ*\7WTV89@'Y19-$>U)9C;DK&S!I@S[ 36&06H),! G3KK2R3-R[,R>A.Z0 MM_%Q%3GRC*0IW7&;Q)"2/T?9GHB-"H2?55&,M;:2HB[!/ M=&YA;;,IR=S4S6Y*+(0$5^"^*$,9EY)M"P!^MLD>R18M1V[^0R+1TQ8I(4!3 M2/N*&]#78M8D\"LX<'S-(8-"660B20$SK'QS.X_]CJN:GGF@SVZ604U+IS3E M?\ 4;[8CLSR[?4@\I8,=@(>TRN=>IB01F@#JU M\=K6#CG[(@],I\9^XJXS[AX\)<,-.!^#@-';10&/$JC1(E8.F%&'6'7W#DN; MC]V:G3V?]<:;^I/X&F7\]FJWP&GQDO,.SF/K=+P=.X7=J.KQM:30[%AD"_AX M#F)T%:@E0*U#N=@0C3-9'ZQJL(CZ %-7Z1,XFSFZBD%F#TJ+^0R'/IY((QSL M4'E#]^=8TV$G"T? Z_P@X2^0F[ P%<7&@R.6,95G/Q0";L.4YU,L8["3LM42 MFTH&9U,)8A.4!*>.Z#W28RSA6L='<\6D$8 %T\_+ID=\+T%8*1IK[GDNMA V M9"$2EDWZL)6^$<1(!C#DA$F+/IQ5QXP/]B8H5$IL\P)=)RSE[^-#W'MU$FGN M^ 5U3W'W15;K+H/>+=%B8)7:!=3WDTUXW<]0$)A#37A @$@P>ZE(2&AAE35Q MNVSV;=$JK7FG)O.9Q6KV5DG&#^>MGJ(9>6QQ6!.Y1;56P"B;K-J6;48K9(F* M (J;PT:@X6;]KWT6:U?6M %:,0$UIK]D/-C6#12E-I@%O>]F\YJ M95,T3T8]LS!]7]0>73Y*._\\VDY8W[L1@6Q-0?J.I-B?4Z\!T,$7 S5D'*AY MJ]W>5%N][BBMCPU?5W"HRTYC('IU@K[Q#J!C3T]PMI%?*!+@*:L[3 H"!#$. MX#-I@+")XJ.#K;30.X[*QGS7]TPEIS>FC@V"TBZ')MC M"MCD(]P80+Y7<&G7IMT-2FYV8J=.R,>%O9 MY(::V1Y:.WA7!\C=;];'W?0X5F,LC0.Q^RXY6"<;$B>,*!XP+)V9=+)./3[; M<;CAFP,]\K'PWY6X(1#OSJDZJ#D60;@=RRW9=8&WBME.-DN* )1C3<$38FPX MF-,^@&$X+0G:V:7^3PLD' >.H6&> ;RK#B030BD1QV$2'-DX'UBL(".QI\SZ[%\=TVM&H'[HX M3EA0W 01&[C+H9-=G4P0MD[3C).6*R.&_S6+LEE %C'G$EI;'Q>$!C;(LCR6: ?REN/%6NQ>%F%N5BUV79JU='^@$0[18OI^.#]HPX #U3 M+]LJ+E7++^!=N8]D!+[90(8]45YI.[G!E2?[M>!<^>&JVF+BN3V<(;N:+U![ M=Y.456I\MH#<*$<(['4IVIRZD7AX=V366]WK[#?N X.A?._DJ7;IAG7L#[^2 MGXV;(B"7!.[&\*K7H/!">V(T_.=A&HCNUHK='C8/')+%XZ"6([#U"GM2G8%, MF[4/*8JX'FW4XLH4B'-$;.#>AYR<[@R6U;JATNJ9R#RUE40Y"9DX&$,^V A M?NRMYLQ6:?IQWTGU<\"$J!WG9F@WL([A5.,$/'Q+8WDV&Q"4!E#+?& ).1^; MJ2@I+ R95NJ""'OO6?3,,SP4OW!0'1=O3N*R"FL[&5'EHG!IM@ZP[;&Z2IA8 M:-0X=74>.&Z'U0A<^"6O30R<)@ [VV$^-V! C&OB16)4SM(PP$M._ .7BTQ& M/+-KWV>0CJ6PG3%QYF E23PL_]O-1@ HA;TLMP0^\E]9&99/7_J2J61&"AM8 MV9F,+ M\O8D53Z<.^B#J(3X'EQIE8&N;Q,GB&,+/)TFYLZ:D1DJ+,$5*M[KM MIL (C&RK)6HW[]HYY!R9??5O*HXNE ,^R3R-<^\.$7)9=5Z5\XI3'W)H F"W MXL$*6$T#M\6;Q[&V_^$^/E<,-&0NI(.<-P9+$B9GI7"'PQ)%D00D*IAQ;X?] MMD0CNN4J^>^NK;2T[MRG6AR>ET5-XJ1J;9(RU\<"-M@UR:%MF>8$2=@5<ZU\3C0'!>7+=!HRY)',2LHD,QHN%%RQB(8YAFP74.&NUZEMD\U? M^B+9P)WW!O(]A#/.C-F/R ?-Q:DU-'=M38#>F'?"@!.8WHZ+8,D)9+Z^;_LY#.X='X)$%:4X#/, MM[,B/A\[^].T=!NN5;CE.2@(7453.WC%&IL]%J<]1X%HRM7>F7WVR._D M_/;45G4Y_Z[+PTOLR.58SKC96QP/#D7C;!%#])-G=#KT9#+ZL=(M3V?;3J-3 M@S6S@7:S'&,OE7BM.F"0VFU2ZI:UQ#C=K^S+F2A:$/DS0L=P2U=!B"45.U#O MPFX[& *PBA.6=-M\HY31@^B\<=&NN@LU123N!HIRYGZR*GM/!@8(&^>R!MH M4)QD8G^-/2ZOVY3HT'@4I)B= M7 '-X.AN;&@'@[(/RW-.BT6'E6SL?U>:G=/A;+8DW5Q8PQYS'@FB-YF'!"W& M1T6&P%UB-$X(EA[4E*4PDR\8),OA!+%UZUVVZ5CGP;+@4HA996QUVJ---N]P MBFD1Q"3.$H9F43T,%L$C%VFHW)*#@)!PTZ0G6-MNNO 0XO(SI@!;(-G75!L"U=FIMISG5('-$ M.Q_[DZX=PT#8<3<\)E?0)4D"D*ACL+3,VVJ2<4U M'QUL9CPE!#KC331G@MJBH/LP[WC30)C0@)_85( TAD&4T6=>&Z!(]3G!).Y5 MXGIGST(&*)V2I4:^BRT:'-\$AQ<'PH^^IF YVFL\M!%L<,U\PCUE0=GXIVW2 M]QIXY Z=U@%;@"4@M9KE6%MVG/FH-P$_X* MB-74C)%5 %OEM(5\)]RAI'BW;SJ:<<80U M;3<'N@946-(B7>S*FJJ6#C)7\$,\OA0XC1MZ!6VC.2 M@CW1+@%@+#CF:=(".[XY=@&'S9UBEVX4E/A8CO"A^$TJ["E"+XX%:+OACQU> MD(VA.>!L#S0KEN7=X.B'U6=O)OY1 (K0_[3]FA#'\C A0G 4>+$W;F Z?*-3 M7<=>' %2>D)"9OM4I1!T8A*X M3[P':_?86GRT!A(4'AQ:20Y38<(.42DPS(D7J:^BW!RQR3)VGTY%R[$IRZW: M--56$ R?;#0\-Z"<W1DC^9Z>:2I[-1G=;/8D@84\ MHUD::?5"S(T^5E-D" ?B@A5J4 _$@2+P'([%08WLG +;I_2Z+3FUWMFKQR(# MLS==BD/B"E%\OF2JMG>6,&\:J ]92##N//V(5^*,/*#!),W^)ODNMO26,L[Y M(6^OQ;2Z,I,Z>H6H/8EKU2RQ)"Q;VF&ESNYOQQBMHLD]<&]F/1R,8>M>ZODY M^C9[ECM(9D>)1H\N2;H:BZIX7"JF6/W<=C9RU9#:ETTR9Y%:9'U;;5@50/ M?N#\>YT%OVR4R9I4'LB7AA'F/*=\E(9FT M;%VO2X"A"J11O[VEMO2-!V0FS4M-/+%KD0HTK-UTC.F0.YJ_MK=)GFF^"WMV M.J6WR^X1*WBER2/"?W"1Z<(2K 9E668#KMEVL[#4D&H\-B?+5Z]A+":O'UM@ M>1R@46N;^K.Y2'SC@=UW;+F:R#>_8:'\R8]N:>ZVUY M$#,,Z+!A^9*B;CK+V\2K^3'$=,)30C_5AK#BDGV7+>*\.V?.063N%%?JJ/^A M)L"0@S#DU5A\GZ9>.151IJ5=^NV@RMAI0'0YM2S!22=^)+1/TM1-,(;".XZJ M*:+Q#.>0%-ZR/:PZ7D\X- $!MH?:''MM0[GM_K2/2C45&V2X4G]D(U6V9S/:;)5M%XB6'SO?D"7J=(M=$FL3 ME3H7>#Z+Y"19&3S/H]AR[6P'B-WA18RZ&E-2XJ5Y;\O Q+#8,S$DMT.Z' *_ M23MJ5NU:96.@RU. W&)GO.H=)*-5W$@I&:F;G[%-;7J3A04G;!T'P#VDK!?J MLJ%GPLAHRVT^4#^V@%PL!B7GQ:6\PP_MBH&.L/$S-M\2GE(\;,@<>0]%+PLG M'I-_'RI^$<,/<1*Q OX-^#)V'&&6A_\U1!*:R.1"D"]Q546#1R1-:,BW,/\KJ*J+(D>:! YZ?K&AB? M[)7!DV.WL]4=AQV"M!UP0DA[8,\32P$6:IR&K41[5:\@J;(I14>1NA0ONXF@ M8Y5;=VR?N@I/RQVK&MF8%'FMWFH'95R4%N1,5;N$/0 MO;(:A^-OF'VPN78CN7:L8M4&RQZK:2BVIY_[F4Q@@S0.XCRPCRR:BZWYV?.B MIB^24=IR(D@VX>>)S!*?WG+;J5P(CBDM51#8=L1 +-*^-*$F"TENF(W:^Y2'YF%3Z.3(AV2T^ M>HHC=QPCYX^2'5YGM9MN!IZ&R/>2;?)H-9^IJR"%CO4O^OJ[^T&4;.]9Y M,8#SH&T^4O#SBIA*VVBG_SRP0%64'Q132>AGS?#93@=!;1)1>7C*+*+00I,OP_9K\(MRB8UP M+ :"=JQN(%!-II* F@DT*HVIPC?$3D5?5D&!DG(HOL3WQ4[T_4C=+$F[[*-M M-4GMQ ;L6O8E2VS;5W_LECXU/",;H\NCK,(>%N$4?UQ%&2BV'@;;4;M^X+FE M9,0&AU4W5VQ&V@IE&31MMVESSO(.0$[FP>2M3L(GT;#S97DZSG$!N/ES]JUM M&^JF=2#9"=9M%CDQ<;+98,PP9"%LS@Z".P"7=O%E:2K4N+ RB-UTG%CQY';A M6WA7JOUBRW'<"8H!^5=R#+5R6-BVFR <[+Y0[([7.6PZEYG?CG@5,<'"XDY1 M@+B\-K5>I /B[#ZF_24ILJI:BR.72?6-PIF0FM$.%L>>'O-X#^X"LV'!Z%3J M*/#!:[YA/E]]^.V70#2L]'116E#!\44NQZZ5K+Z>E@6T"Y&<)H6<'/V4OD:'L!(BQ%:QF&$FO1 -&7C9M MA1\D&^5DV8(./I-;QVF:N2E2%9J'FSLG&B;VJ=9GD[0 3J_+C;9W1\>=G> 3 MHG;*AXY[=3+^J!G)O M.D]ED^TE,X8YV%-RVU/:2CR.++VRB8,$)T;@KC;0##4H<# VTQXVV:0'5-A- MME_#*?[;*HZPO^N'B0Z)*+,D_L1>?-;8KF7\47)JE_UC(X[DR'NY+>*Q MR1Q?X\8B2$W58V(8!Y.VHTIRA &;=NPX *1JV>YWG!9X0,Y3G1>9]P'8RQX5 MB^,/+E$1M[BET;AI$X^[+>PXZZRR X?8(:9=3DK"A6(D5E4_5/80 M2#?G90-O<0B8G3QU)9-]AC=0K>H = 8S [GQG;B."W 1G>M6]R#+6:!>X^'_ MJ1EP2842%4EQ9.8$ (?M6?I=.%A%[Q_ +P_&:H)!13#?RM41]%4'&J9B]T! MFWV)*NQ"&$U2)V*4I)0ACZNRRY5_$U,:H=N B64O^'5);0BE;-;@!(,(+YM$ ML$0!<+?8Y&[1A@F7XR*J.V2$&+;:R92K;*44_G8(30L..(/'1.24",#,F1U. MBZ-,P=O++-ELF!I,P;G=A\6T1X(4QV>>:8-8D@6=6,&.FTO:W*1Z@FC<:G/N M!@B2D:]\PKGZ@5FW(J/I8J%?=5UK_29&@P(BK%%U'K-[Y,.Y%+"EY-5$ M NPLYQ!Y[C4HYL6:$$!/O$0WPE*R7GY=R1/5I\;S/$M) $M*4*6* MHLPL^*%##1'G SS7-BM@JY,=!M+!VCJFZBDHP^;69"N<1-+$N3*'8>6(_L-I ME7A7F(RP#GNSK?(!,=/HLO!VV[*SLZ*@R@E,#1@&F=6GHP,\;D4BVQ$LF=@B M*-N^ Y65Y>-L2ABK;,78V])-P;@3I)_\I11VN[TL&=@S50F\'G;> ]95%=LX M\5R44,YORE8[MZX@0[]+?JS4R:3M,4S&_XN>S-Z*X,C9Q# V(EW^ +R!H3\5 MDS;+]JBXW#%BFP,!NPR)*L$T*5?*M,E#8L13*MDK83VK"-VL^9"^U3!'M?6T M/+7#F:-+FK#A[^R]'6NF]-I!+G+ACI$SHZC>Y?<+-JK/A]KGD MR)2AL,!<9+ (>UC*1JNL[?9F:E6N#F,8Q*1N1V7)$#^!TQ]T>D3!'O,5[ M%4CR/H"A%Z&&HC3X-\76+NFTY=_&^DO99-NI] _R1%JTGHL6?U\A0C:.5]"Q M*BU];+7*%7_+17V 32/+)3\W&-P)$1M41.7&NX"=G@G8S&[O%DO+[?PP@<"T MB;2HOQG,9IZ?DZ$W($5ZP(/_=:A@?T24:RQ)DF:GXFU\Q@C=CI(5J> UN%UH ML><-/X!'5RU-X8AB_ \$D1$YV/U9I2ZMBA6ZU'+R5MEZY+?FIF6EJ@Z2L[2- M*Y-!6.WQ2Q*GR@DEW)-484A4QDY0JFR_9XH$Z3;V[YSBVS(5Z.'N*JR[/0W>=] M;VS5 &J2JI'(5'9D2:+/.:PT'8Z@[[8NF-F^;%25[\$AE\H9M M&M6"P3P8;_< G-$"DEO+\MSO-8X019/WIO$ M@QRZ"T<'[AI 7+4W.SOW8>VBL[)AM4;BK)Q8YNV\>(.DH-ME))S2JKE A(@7 MMRMBR$=>4\+X!_RWI,Q)]D$"0&YJOS \JDG)P]Y6XSRPH3D(<!L MF:9/,_\LTP0OV[&M7<9$[O)$K/!USAN7=78SG,$80<4&8)OF$?=G=_?<;(5X M;-6PO_QPU',.%9=/ #@["Z@B;:>Z)+QF,YU^+U$G5U;G22!$:&&>YWC.NLE^ M?1,B3!,9-HHZU?*'Q=%HR-!4;N;*CZ6@D4SNQ9L/B!Q[51[D=258(>[=5&CK M4@/9D:R7Y%!Q3)J=969\L4QJ#57C@IVCZ?&6G>(TJ:V9NI6FGXO28R,V*.K+ MFPS9S2K9M2O7($[R*(\,]83DZC=>/OW%;I!,N'),@8;.PBS]]."2MFZTI^W M;8G$$$W5;V>R%TF3G+D$*QRWI,*QA8#$ME6$P)KGJ;#3938T%@7.\]R:.RO> MU3D^8M*7P\KC[:PW[[9C*4=LM^S7TPJ MW)),';8I@%) 9HB#0H9.R M1VFDY2Z4%4J=Z/!(P+IF'6\ &[;83 M/\Y'_IQF!7E2G5 @X#4"<)G"28U MR31-,*E_X:2[W-CV#1@4%!NV)"**S@:=:B8,Y0"D0+2.KI@Y""#;19"[A!2G M0TSGDKN8JP-> 4NYR.V.V9N:'8];]U1ZPTJ%'+32MF4Q)+S8@V$I_VFG$FG>W!EB.(,V!&4E'Y:[< M)5<[5[VA!Q^$?;'N 9!36X04#KI=,I!A&"?>HN)>S@UCSK?'1:"ONG62? +D MJ/SID0WL] /V[JG1:<[REF9F30O)!,O*1$GZ@0MQ8RUC-1-T2L@F,.30W%() M @A65_Y-,*L2*P>ZXV3ML&1-G6Q4(>:I72GTW)^IUJ5\ MB;C2.$_<#K0_54JW&&O^6?:N5$!8=P; %LEB@3!L6CFJA[T?J=FMQS/)1[T6H#.OC[&0@_#J#X .,VZ2Q%ZQ;4RU"#S&+$Y5Q-G(O%FV ME/2GRX^DR.*TE[+8;G4Z?+?;DB!]05,TG,NZE9@[IGE 6X>!.?.J;2D'%/R/ ME!;##"-WWY+4!%:]J_(Y$X<^E#/G1BSA1"7J2C,5<3B;)!'U82L2ZW8J/MP7 M)MVQ;Z#7XI0 'K9()V ]02$?.9;-\I0Z.;#=PM_]6/%K=P3N 182H3?S M71H+V4"XI\50913P5[')DN65E-8'\T6P:I2&;;PV.Z.Z3"CX3;OS,'A#B74'=P]3 MB^>8]NZLXYVR]T$ MD&$IS&6K +?C_C;^]B29\FY$J6F7JO&\^ZX3=K0)#\/>)4A^#$&"%8MRQ1 = M6)7K X\2S?S@=CF^5LVG^SMCOA;?TF%B?UNBW.&V@-1#\2W# MD=0"^[#?*A\05O"8PJ'^1+=(?AV[E*6W-+R2:G6KKS9R IQ9.-SPQ.%I%41/ M,OL#A[+K-*0 4C_[E,E<+YH)X:*-"?=#)"P9;,5@M;Y+ ,(I4\_#"57'8^[/ M4?@2;G!T#OJ7](:%YM!=N%U JHH(K!'7,[1#V.D/VV ]*V(K_=MH/>YI;505G MG'+77,!T\5YSMR8.CRPF56IZXFME)BKA#I&;)=H4Y7'5[0?5@Y1;GP*BV%4[ M!B8K;" ?"5@$AW:T;J]_^RS&S+)&F=&WE:=1<,L'*C_0(VF>33'Y\/ZK2MZG M$KB 'K9ID7_"LC:'?$G>&70"_@FK^H8!3L[--[$\-X$95$;.!.>3 #6Q W'9 MHZ>:/$/1.0Q$DC3K7H,L& #+*2W4![ 7#?T35GKQ8 $A%!)35,KN?K"PTN;W M>AH!S\UN8(>!.FR6E>(W."!CYA,8L0%D\7PL_,"+)DMHQY6* ^G!VLBC9@G1 M Y91@3O3P(=M>SQ&;(-.10OIHP&6;D1QF!U=7UI]0?:U2] I _@IU\49M< R M&[MA#M6CUIRP/0.7="7@-2>V\[-O!(/&8=JA*SJEK5L]5;MUZ,C1M&E=PFGN MU=->[D<%XX!1&858'$=V.Q:M;=^1ESUX9,]@/DEJLN#$#A(VMWWR4/LEF2P+)8&E2L;)":75-?G\W6& (VC#ZK:^FC8@I85>)2AY550SULN[+' MK9@@&7E8))0C:TB*?RW"=\DI/*4C:/8,PDT;'.ZG:0S^Q[D 6)I5)2&M^&'VMQA:/)DSW;G6;/#LD^P.0P=/71P==='R3E@%/$ MBIF%C>PL*+C7#XP%"?H:..I5B[K!HXT4TL(AY<)?,27 M)E?]$6F\<80! +DE^W .:$KG(B%PO[+8?5G)@,AHMG@;A O=_=QBW): @= MH](K)C@QA=BV*$G\V.4W+>=2^>FV)9;%_<:5[FT2(^.EIYH478@Q6&!"B]Z4 MDXTJ]75S@6>3?&A=TKZKMZ,X$I&23,J'U4E]I5IHQ++2A\@@1O!U&Z.5H)2M M-#+=ZF $NH*E+"X$$[Z2L#N1" #8ETB"]&0 ER'[YK 0\EDZ3.ZE9TT_ST#D M:;+5Q)5'N&]#7E8?(3%=)AZ;#_BTJA59[,]BHRFN;0A#9#M462'\"K+35\EG M>6:JQ'0[T)]-XE^AD?2H3O98&)*^T,C_X5D2M=D6>15]J*E+V:(4<[.AB!W0 MY:LC+'.P9YN[K0/M.NNTF/)(12?M0I!"R*'M _?:UFD[+V_::5,WHJJ-[]AWQO M+I.SJ_#1<^A2JJU3Q)Z'S>4%[-EE/\1Y=H&D39A\S&5;]WZ!*( Q=A,G<)\S M_!B#?EG&!4TNNLL+T]U#L)K5=HMYX)8].)RII*@$=TZ_ 6$>\Z'<1G(RI%E- MWO>SS$/R;MM?HVHQ)N"7T]J7P)!D+P&33\B3K>1'DZ\V.DE1)ADFWV.(<1O: M7%<\M\N,77- M$\@@/J:T5/"Y^T?M,50@XG&20OYD3N)!:,E! M!K#<6 TSXAA.Y<,54FLJ>N! Y&@.;.QJJ[5\02;]U.AV3GZWNB)SN6WVDNX< M*G$ZN1#O9@@=I=L&9.VV0LC@J'E+^![L+6#?@/4"[ [[=+&UX%UU6P%@E1"0 M)\Z>W+($6LZ%CVHG;UUMHB8UUV\*#P";:U;F6F,@/!B10I]8O45VA&4,M[#KXI1)='C40#U?32N9I[338Y=_8A_/ Q 5->8GA&.I4;$L28*QH MW?-F:9MXV>CZG,H:FL8&U5K0)9*2HL/HY,0WU;Q;4 #2!P?$B%XXAY)-GHZ$ M*!@HEY!<'Z>I?0!OM79I&SI.Q^*3+4\/OJH%:62#+" 24A-^+YQOHHKH(:J# M=&WS_PE*1#4@&W CEGUCZJD@0WFW Y[P%;O>CKD ML$D2>F%C\H'!JH\]S_:KM#6PJ?D6/J2\IRN?GB/,\M-L'S.58^<+=D\>@1P4 MVOT\JLM9O5O 'D_)=Q9]H03!.!?-;.*;)4YJMFYPZ;?+AW^)$B998L19"L],;K>PU-NR78.*8.@FARP;7/%Q'FIPL,WDV^ XJCH" MSI #?#]F7N,&MG?;N#M7[YR9VFECEX*!0D>AN-H$WB9GM JKX,W"C_-^V_N/YB7TVAXDE M]B=^O9J-1V&U+9B^M*7\<2[=2>3C&99^@,11-K0;:Z?P5#'-J"0#QJ82O$;5 MT*5O4SXI%7%^Q2U4HN)C]5C*8'\YVC(*)FJ1,EPL^H'%YLJL;1'7F '9-.99 MVR[;CMC&\;-FC4&N^^F<9Q$.-CND'A:>".R0(UCX$#G1:O+M4H_ELNV*@E;S MNKO:6+7@K;%/$CBNQR[^P<=5A^=N'B[8V*GM<'TFR^W<\5TU?Z :()7S4: = ME=6=WVL*#BJ8-UQDXA39!W@L"C(H4A!5;RU&GC<[4:I5Z^^$R_NS11-.3EBF MU1J2%?<\"7L(;H)Y$?:I"GYGZI(A@$8-59)/8V1-TO@70DI7$U7 MX41- ER0C7G2@[(L,A)9D+VD;A#U^!JCXF"U3V&7(_]\CKS)9H"3O%65]?N< M-[#C9W$_RG*>LJ15CU-80_*VFE9V0ANKS ;&^LH"<'5-@"TG5C[:AQ,>W=0 M*F6CBUOYID "8O &M0I"XV#*Q] M@,[E:U?D40)GV;4<471[86FOJZ@8?JBX-6^9GE0QO3?.OY(\H"RLNN.46>6? M@=/&1\B4P9G2#*@$?!Z.YG0>O0S;P+ULGSXNRQ8E//QF0=006:%Q9TW4+O;@ MML3'69Z*:BB&U3C(U;&$#E*T&UB[]'.X^_WV:#RJ7'K!&EVSI KQ5H?FRVE] MA[.BZH5-([4"(/.T2](\_B.KYE&S$A9\YGTM_43+Z*>=%4DZB M%>ENSJ57VSDF*J/CO7F(;76.8(.##$SRIW@4QL;6Q,DN^KQ%G'E90:SELNK5 M+)C<#L.S($W4I.YVYLC8 FM6Q];#1_5/I]@)=[SF,H"3>0DZ-<#NY(A*A&Q< M?)OJ/94CZ33P$&Y(*BM3 9=MM/_(Y:S? MD(A%*L>ZF@4.Y_R]Z22S:'R&73]H2&SNPR=QX[(?S:Y@%?;6CC7R^HA-5 M/N^S$<=P/\]G00/Y)Q.6 */IU!5&KJ@BM06[;*:#(8ZU#6Q>+YPCPX"S#&-1 M6="P1FVQ0$0+R1+>WTJ7AL$N6VTESISO&T&RW7USY@Q0)%*XA@VJ"DZ=4M-A MOK-2'!<^9 DHF1YS!EAZI$?2++N-Y;X!GP']GFQ*VAPJD4Z_0:+6S@O+$ A# MBQ+D(RCYM+![>N1UY+@U"6'K<"^Q00OGT-M4'N#!Y78+/H\MH7;0+&!Z6[@G M<%;5_G1 C(L+SGQ<,G2J%6*@%,::P:E* -OQB&E0M?QRG%+.UD,^JF$O9W3* MH#D-*O=O&;8\OH-HTQJ+1'UN1+]Y:T]V4V$V*P2AQ!#IPSH!?,1-2 MI$-43..6P,\CD;WJT\%T[,/G&#%N3I89O3EAT>\8[EMI,J=I"#NJ0D;8&BPI MP/G4;2BM+8T4(;!'SQ$!T&FQ\$94MSI; (Q:4^6PE-[KHRO [G2QLV[-.5UM MG.FPH% K:_^S>Z<&)O]L&60(%#"YWV-[=\"GG(($0EZ MFCP"Q%GX)%OVS(,_#R=_M]WXWB2;R(N8['24^; ,CV\*!#:7.G15?@2PL=.6 MAP@^RF![36F='JJ$.RU(='HY MI&SRSU4!;L]LYXDQETWI^2I(!*XZ$;QF(^THZ!5K3 0/P)0?RN9L M4[FGI $*96J33_$\"([;N-0/ (:,6XT\@,-"]<DCCI/R1I7D]$M0?]N:AYH!M):E5F\1TQ-!0[[_^T&.&RZ/S#NJLB< MN';"9T 'L?&PE]FB)0+(%BH04[+4ZX3 MA:(D>F%90+]J7.@&]E0V'KF<1(LQ>=''5J54;)#%I;3Z_L2N(1 M)9"B*EO*Q#]JM@#%#!%]\-CHWBRIZ=X ^OF8BJ:!Z1\EM'BT$60CR;^I#>E2 M@@0#\7$:J%XS'/;3$=790]V:?33JH%A%F CIQ:EY'1&]\BWQ*%Q?)8;!^E% M26\M/8CHCZ(D,D:T#HRC%/S5!J]+4CDV5KW=N*IG/PORX4: !9XW'@@[BT#T M$&-SP#E_BAR>@-&CG%MW,UP@S@OH7-6))XQQ1O"N$^N)!VX*Z^"TP0[LJT-B M^\MF1/?N8WX-A&9#7VE;L.\ RVVZ)4R;40^II>3'N9T%<**2,]DN6][P9$71 M9L"IBIWD<+#J6;UP5W6@XS/#D(;XG\E*Q[ MQ@V>Y^T&] ;MV[)I"4Q)IG:LB6P,U.XL7G(4,"NX56W/81O;:;W(B@CZ+/C( M_T'P8N//L>JENWW@SU5FV,H]PDS1=*]D5?9A&3/B8G2O-E=Q:#(Q@I2&F5#? M6&R_I-NWFA=5D]^=C^\W(2([QR[W4)4X4VHP3@#S8?>\\CEF?A0$PHG+I]-9 MTMCQGL40RFK?UC\Z8$_G^VP$\IN42N+D@/) MZ]!X2-R[FF#79%5CPZ"P$ZYM"6Z0HI32PS MREG9T:>S=" $9_KW->BW28C<;98Q,)DRK$XLX93'SW@GV?G$H7G.I;CC\[;X/?,F;;N<'JS6 $4KTZ#T2E:#N/H\AKV]B_3P5KW)V+Y9 MZC_LH36 2#;,J!Q[;-7I+^5S[H= 54'!:M-9DR+Q)G0HS@@[\(9?)X2MELD( M1?G.=GZFP%>! N>XI[#I_.>5L_R!"MW<]K^RKQ\; "VZ&8*:(+PYJ,W\SUQ] M>_9#'39>$0J91&>EU7DE"G..Q/G]YW0DC.>7%;E47(SM+.U//P]\*LXD2+LD M,R'> (\C18Q+.A=UZY:-&:1G4K;/+VOVB"L^H 93E7+>HI B7-%Q6FY7(D>. M\+U*#CRHIMZPREQ;)&0\O'ZGSW&H=U= [V$Y^-#6+@REK",.)DUYS<6/MX)& M%X\'QX5#EM6@2VU)'$! ;N7Y"M,*SDV(*5.J! Y!R8)N#4.F5HE?BLWFW?1] MN=5.":=PULP13F!LN]4/M3R"5"5*=ZBY9BL&MU\-5+LM9L5IZCOM=N+NI1/ N7;E],Z O/%]RT+LJA[NH/$'A MX )G=X'%YOM8^-/9G7SBV0@YGL?,C/57@F!Y8EJ07UMP&W#<,N>H-XZ#(%Y/ M\J4^X!@VZ!,EUN(6CFTN&1K'PWBW"T(4N4I6C=6UW_&I]TZH,6ZQ;%>=TRF) MBCW!#F+2L[)) L:8V1J.QA,!*U&=N]JNBKOL:[[G=B9OJAG'92CL>[3#T<>J MB#C :+58G!%;53^3PDPIDYVBD09/A4:>X6ZL&PQYI[*8P*$N9X+?E98:EA73 M)<^A6&,4V6M-MVJ;>RKCGFQ^50UXUO;P.X&8'6\.T4UL] M<8"HG:E$8/BL[9!QP2Z=V_DVO%2WA2I+#J-F[53,?$Q[.8N5A9;(*LFX"7 M+@P_IFR\YL?.336AEI-"+U,+^"Q>:),:5J'#HO 8P=3VYWFM)MU&4?=R2%X> M;:TMSI>"!C=G#Y5\)8*MOPL0VYYDR>+!8:8.1* MZW#I.#P"!OEILG+@CEAB ML%\DXU,@< ._1C4L\-2E:(,DM;Q, C@'(C_BJ;JYI>IKJ2$FM>2?/"1KM(/I MD2S0N3# WG0(&*RV%)R5F[0/CLC**O8^YU(=7\,,$D?SO4IHXYDY -N:EFABA"HCLM 8.Y@?**\J)FXB/0R.$3)=FT?HB'HC= M:H^&^,(.7DP%JVG'@%JFNDKO[FK \V+38 M.%MCBP^*P"TM-FW<'@X,SR/F67S=B[%,O@W '>;;L>M+U> 8>;)JM$G4O@WE M@;&/[,+BY%DR)N67JJT=T:X$M\J.#[T=2'KLLTG*6E4566V-M$**X0#_;Z;S M;978S4D0P,AP9*:<%WVI"4@VPPFTP;$H="#QN4W_O#EL5[A,Y;!T5XO;9'_; M#$RLT^7HD/)/344U$8_F<>:8\4S 5A*8[::#Y;16[+78F^N>Q:I83-K6G(DM M-I6+.O!7X$G+W[>A$==^[-4FZ\/Q:2),JUP-I& CY%Y-M@A[%> "]VQ#U"1] MC,2N5S9RD5RVZ4JF64&!PTTD)T&-:52'L9U[64*>5FN:M#32K=W;+BYX'*H" M?0-"Y,F^0/IG69*%@#V"KR*5JDK-*RN_FX:QZS08$HZ@)!P/Z583*P*P'KL! MKB83N?SHH+$L*1'62:*20VAQ&$:9E).<-U5[F[U8\);='(OM='-J$Z/-SZ_' M<36G3[N*P_9AF2(X,(SJ:IOP9^GW;O8FFL)=<#$-V^*47#W$&CN6,>R*"![* M!G \%!U4$U2Q;$%:41'H[*)O'86B301R,B<.BVR+WG3NA#OV/%JT%\8ZQ#>4 M8[2L?!*VGMI)#(*%5Y;(N76Y/DV]V%TEQY$/:.7DV./Z3:-M09XM7*GR"4/] MSJ&T^6/1T)9DJ3KN=J]!145!Y*DG9)&E^;:-3EKJON&2=WN&3/IB6L .NVJ" MB2L+=KXWUFJE9W%O8LN^1#1P#E5E3U-L\@L#Z8,#&ME!Q,H'J1O$KN=3B9YL MBU=VIRYY(C6756'*BH#9>&(9*LFTQYE4H8Z@YW%"QL+*ZAB_;H*)BK52W//A MN50-?%B$D?+P8]EE+VF+-J@JH2,)]AG9C2RSQ.*;=$($4@XK>BDJ))@XD)'9 M6J:L0-;^,;*W6#WK1+M9$26Z%78;:@R,4]WC#:_/%JYVC$SYBFURM.]^JGAK MTX,$96[5$3\GRY=UVTN:X3&JQZ]4^PKSN6[9"C\)6Q/U.1O';_&TT;YW;EI-Y0E&@PO*=(U".)7U@ZWNH M:R281SE!ZTWU1,O4[KK5L94^4_M(B7\_8%J;=H=Z@?G MNAZ6V,'"[$H_H_+65\;;AWS&C;[L\P$KZ#,(18.QCF+-F_*@IM5?U&WLTO1 MO]L4 N08-WNJ<5=)2NRYJ./JP=D&%BZ&YDM5I0'.713$A.%S=]+F4.CJXF2H M!\7/AOITAH:JVA+L '*LO W#GRR5)&N\[<9[!,=^$79++Z95LW_6ODQG=62I M4?B3[9<.6P@X7'FZ/LFG+ M/L">]C6%>ZS^7@R=?$!877Y1L4LE3+!9^/TYKZ+;,L^+T6P O4O= MY6R8]4L<-=Y$DM3@ ,"P#>5FFP]@*!LBK:L" PRI^&\696GMLF_#*JMR=$XY MQI4[6FG5 JL#E1:RCX#+&R6K&IO;O/*044+0@*>YHXD*U1$LE=;5[/1@261G. M>//3)M\2%T$,:IN]V7&5_#!!?)\$]T^_QKFS 91 -[V]6J^*_7&K7/Q8JPLR MY5Z*'MD'I0Q*EZJ#.(8XWJ=)!'NI5+ ZQ:8=1VK.8?_PCUGJ!MP7*R4SL9<3 MLD$[6"ZM%$:V: +0R,1XMD2JG8YG-CKS?B% "&'/ 14,)!<< 6@'28GS:[!5"PTX;8D#M/ M9=4%^E*#CBI4^;[%"^5T-GY#5,<72#GJ)-WSF?))5;?5>4)4,6]9MD;WB)VR M7HD!B&DY80XY./GJ/-56Y7)PS[5+]M!,'),B%G5W5@E_;.:'^P3HI1L<#3KB M-RZ58:YHJT&Z*]9N=R*W;G**YF"-EZ!71FPB@J(*NEM)@F%[%!]'C&1LPO%9 MK58.]%%+(%[VWBPA\)UPQP!AFJ?PN1G>7]Q!6MEPY:;B/CCXH1(*'++(.SUC M\^TAWT+S?&'DG>K;+=.=BS.)9A<#94A. M;1)9'4XB6$I-T64N99-D>D[S-:S=*44E$;&81;$&,)!F'Z.N-K96P.EC"9YV M!SS:Q-5.&1*Q:<#=C3.XSM^:]+H!Q"HJ&A-+G,<"MV3/5[!1DQT9S+HZER)Z MQ'9-._^E0K+&\6RROV"A>'=UD?("$ MO-P_VP['90$M)&E$3!@YXJY&DRSWCY)) /:4:W,*T(3NN.P14+99%8Q+X:XD M\6ET4EB^W,%];2K"-\F"GKH?!.755@L6@@7$CR=EG6Q@ %JRAPRH%.,&(&-C MA[U!1340D!6/.FUV06+%0!E*F=B# M),J@O/+@^"[.R3F4B 6=+5E@PI!JQO>Q0GI* M?&$O5+_D"#]EQZG;R!*DR2@>^5/9#20KPC83+F7)>ES]RD[A&033)68B;0[B M2("JHBS[BTFZY[S9WA'%89P?>X47J:$B3GP7H"$JV<82)),>V#+,&-O/%FC3 MRD%.OXDG*FK]^ "<9.].N"?;ZT)62>E6]T^&#>G M=P F7=E3UL_^L\4P?#CT%BYLZY2BR2DB,WG'ZF11*ET6ZFFKDFGLL.C=#4-N M.5"CTV.9V&RKIW-.@B\!W>?Q &F45\L+8-MX\2K+3#S3Q.]^&_FQ26YV$$O4 M.^X"AV/'$N[OX(QAT("%CU-_2H9'GL"E]M6%/9*^NS]V[WAPI6IM "3.F+H_ M>+RJB(49]DV18RS[Y4!4K1PF^]YP0'RS;#V7I2Q,4L(6?E8*%W98AN4D66PW M/%:,S[FPS4!I*<[X$R6 XF)+MF_>R;EQF;(7\&#+\BK%V4U(^"5W/A[-M#P[ M=ZH0O:E]DR01O:/-A%[:>1H,@O>QD()'+,0MW6[Q8;^.Q1ZEE95SQX91>QM-NUI)5=7YBR'[6)<)_G)Y,;8UD ML>?ZBNJZ#(M.0K5 M#]Y@LT)OJW81-1%.-",5 GP5O]*BNPA:(+F'0?.*=$J_;UL7LE19UJ"50*' MDL%GQXJVA;K$DY@^GC2VEJ!'P7( >BQ&PY(@WO8!2FAPR$?]'-JNPL,'C&!L M<9.;4Y7#07GGK]O3;.(Q,T?4I("]\ET%4-FQK$%.&[,!JB?^/_O/]O]]P/\K M/N"K]R]O/WW_\9NWG_YIV[:_^JO[P]?/QP_?\Z_^\IMW'_SWW[P9?_>/_VL, MVU_]=W__CW_=OO[XJQ??_NOXB_C''[V)O^#'?S4^O;S]_MW'#_/M]R]_\X: M-KYI/_SF33S?A/(W*?S-6?B*-^/CM[__].XWO_W^S;\9_];?*F_:-R^?WGWU M]L.;OWO[_6]?ON%#OGK[_LT_?OSJW_GT M+R]?_V+;8GSS];NOOG_S*Z]T^Z47];OOEO__(M[UP+?^W+^O/7-5//_SYX?W[?__V M&S]^+=3/?O[VFW?O?_^'W_CXS;<_?/_RZE/__;[M^_??=4^_.;]RYN_CL_A%")%?Y+]__-?_\9-ON3]\]?'K=Q]^\P;#_>;MIT]O?[^Q>WAU MOOFO\NO7CZP?B]??_&SG5__X?WW[[[E E[?/=[\\NUW_.J[ M[_Z)I_K;+WYROOGEU^_^Y=W7+U^\EWWO[3WOW*??_D3[N+CMR\??L56??GR?6[C9^]Q#R___,.[?WG[W>^_^?9[3\[K M#Z_PQQ^^?_GPU1>7=/',/KW\^OW+[[[[X5????EY5WK]"8_PQS_C]M^_?/<= M'\FA>WV;._^-=H8'_9.?<.???GKYZN7KEY_]$7?_ZX_OWW_\UY_]A+O_[AV' M\.VG+][DUM]^^^VGC[_[Z6]7O^*CE_J3.ZGA]2<_O1/,X+J3;W[XZHO=4].? M;N0G/]A?[^.+=X\_W<(7;W++'**/__K^Y==??B&W^]VW;[_8%N%GI^8OGIGT M9T[,_A?.R_&STW+^^;.2_]Q)*7_NG%Q_]I34OW!&PE\^(O$OG9#T9P_(_I?. MQ_'GC\?Y\].1__\]O!GCL,>?WX:]O3G#L.^_^'=S[[] M3V\??WB;?__IO3^>IJ\__NN'UW?S'][]U<_O#NAX^?P :-_G!7;_[\.MW M']Y]_WH^3[T%YQ;S\_H>-\MEO+SNNI.;!%N\7;CF3V_NKV^^^_ OK^]SAQ]> M?K,@Z'?OWW[W>HN@BU]^\_;;[[[_^/H6M_;#AW*7WX._WG=R]? M??^C'^Q_^-7EEU[?/OZTC=Y^>'6YNO$_O/WQ]6'KQ=DM'[[[_MW[EQ\9!4*3 MUY_\V"I4[N;7[S]^_/3C/ZA_>/?'OQR#_O/EW?MW'J4O$42(?_K!3_^$6_X5 M^_CE)W^P_^'MG_ZZ._;#;_S1/[U\_Y._.;_\V4__D+O_U9>@+)3U!M;KB_>N M+VSSOWSQ?OVQK?OB1T*&7_&%/S804;CPKWJ?WV+4OO[AJR^N1,#PZ>W7*_9[ M?5.\\/'GOZL)>ONK]V^_>.O\O$=^\^E'?Y__L$&^^^?WG+Y M7YB=*$3XZOT/O_KBG5?H]\6;W.9OS3!\\5;Y*3B-Z?JIY_YY:-K[Q]_]U[\& M)/QUQ?O?RU;8I#FIER-I:,N.]:(GM29!!U-X7680=LJWJ3;1N1]U"]<<]S-4$%K2Z_=4]3+?BLSD_9CAJI(=-*5XKC6*=40' MXD)?S9R]Q&);X%V?IV]2,N?0%>AJ"O;U,,JJ?*F2$I(D+JED!YWVT-)C#U$> MUY-+.%-Q/J2$O7<9J.JY[6L(8K3XJ?&O'SAT=AY1#ME_M=3ME+E'#7(9F=>#&S9VKUUD& KV[)1R5/6ZU M3Q1+<(:ZVS5CQU#E"H+\A#E)@7(HMGX1F^W/_4B=%FZGS5CCLI0\2H]/.V;9 MJY- SS6S0@W9VCIK>';%!9XM2S"7NF0,!++\GMV0E]+<*=JG.NT5&Z$Y5^[ M["7YSW/;(MP>MHVJ\V=AR0Y%ZBVDUQ#.N]E3=,]>*G_;M]T:]QJXO,?59ZI7[!M[<)<\S[F?8P^2.3W-/FF9[Z,);2Y$WAQG M#"ZU!L,S%9,\4[L?238/AWZ;*QS*=S24W347M:BVZ&]^@P+&TZ5A&G5 MQ,_JK=O;)(%Z2GTH%3C*:,E>U[!%1X;RV%<[I+-F7?J0&F1V;NQ1#WJ:]BQSX%5_YK]VW>=F:=YW:>DX6KQ-747CD=Z5*>U#)SMXG,< M2N5@;H?_M\9TN=+PW+*/#V?'G%[PN,:B(&XX[37I]EB6,OP\A;3WO,J?/#ME M$ ;[]=Z=^0B.V"MC)N^QS>+QOK9+2BBG8_8]RCEX>60<1L\\GW0IC2J7G8V% M$9NU!NNEFGARRC='S+I83658O654# MN[5MUXC%.O_#B>6ZE US[[ 1WU[T.MW+4JEWCW&9ZB.YY!#WNZFV%)>'.<87S:J;>\N_1T/FP5+4E?B M&*.-J2Z'HHY6(WL<.8SI6+W<2+7'M$DX5H_CN*4@PFM-=4EYXKE=PPY^63Z. M70V0JCX9EO$N"9.A9&_ADF_5 .)^WXM.2MKZLO3'/83L+_9,GZ?JR!(]V-Q1 M97)1XH1+R[)0[H&+9EM.JZ4EIED>F6>V.=0HR+,A/IXR7XH5QD9PD#D>0M%OIM8,BIH QB MDR4SIN=,N-:L&%17&<8%5&! "\(5S&=N4Y+SX^#_=B5[,602Y]M1/JI5WAV7 MW:]X=#N]9^F2>/>J (R:[D5E@YX]8AB$[5J:A 7_*#D9WZ#$W2[?-"LQ8G[X M+*N8RA(Z*(,%=YZ#LQF#:JAQP8D;![''S5Y@:=W*D@@$'\@_L]N*XHA$Q[?7 M>BKA>3U#F=P#W" BJ%G.=0RNK&N8Q!9"V6S@B*F6T=/I$$FQ@WPLHO+520[D M8=,>"BO8H5R3?:PJP?;F MAJKM],X/'7BJ^NPIRAB:G#64S"?:V@P.J[(T=VU?Y^DYY=Q"O]B[BJM5?(_B M;,Z%86MLQIQ*0E8_AMMFQ M'*$'KRD_'!N7?;0/3FX_GCTKVVK/=8B.[CUQR[CIPM[JAWH#0QEOEK"F-C,F M%Z?"]G3'\/OW8NF4>%@2%/8R)D'Z0.] %<[I$&V5/J_RX:!8R8_ /^?IC-PI MK5<"ZQQ.C1]37I+(KDO)Z34_6FZ( !>*L8?<6NVM\%@G GRF5=]N+PQX8#DMA,PDJ+N&JW.S93O!LI+5E?N; M$WQ(:'"?/(BIHAU;I_#TQ%Y5E@4G$_LI.60"L1T.)VTK4@(@%P?&^7FN]RXK M,-BT+-'#(0_%' -+K'OZG5@>?;N%/&0HJP:,ZA@N+#&:MC 7D^'=Z,D$$V) M(B5=NB2!CL7:(W=)'EA8'LPOE\CB916"#EV_4RC"@]LG-HF30$> M\G(.&R/,5O"L6XE0P+HX]UK %[$+Y 8@K MD@W[$;-%\*?>]2B3J%B C9FR%1DKE.)D^)3;Z0G5WGT9P7&VH;'/CL]N;%=0Y5&0H]D*GG & MS=9LCC]F#4QQ7X1YCJ0Z,L..D\+]4>>%TW\ PDRMF[W[B,[V6S[XL16NG17 M_%K&2"?;<4JR?3JN3(AU'G< ]H$M 1&5B'!B2F34NLHV^KU(>1:M&;;0=O'# ML77<3VNX_F-Y48XCCWA-,&5O)"BWL"_^" O75>B^/#D8AKB8B7HJM2N0Z M"L#!)R17>$NQQ4<5^H%C$:[Z.MI(SH6L$;3;=JBR-36TI?C6PO'-1#+86Q5C M\7"G/9F/QTLQC[@&Q+BG0SHS.X3-:! F*E,K"<[&Y9TVU2>=@XCTQ!E=P$\9 M<-?:5 ^\/7@\H[6 #C6%G;>,3*2H$1AQ#2>;UB%<$+9B<:#Q'9,--B Z<$J0 MV^4FHKH7>=& />IW[BHA2PPK[[6\LU??%SU>"2/&K&#=+F$[MW%AKE0S/^VP MCVHRR=IB2 ,^ UL4-4H5*?#O<+))0CX@RSDV_ O^D(B<:Y/V784FD+X*IPXI M5P?3[4H4GPB?XYH!Y2-9!B=A%4CJH:FILV]1PCD0VR.)>"MV(7.8[=Y749QC M]00994_/8"ZH*@+.G>IP"+Z)>,[-8T^,=_&]389W FS375E-*O4/ MI$5M5364RH]ZQ91>0C9'K'=BI*D$L $9N\T!]R)"=7,TLPB84'6G9!E4W((W M=IZ72EV[VP0#)O&:?8^<;;FTCKK&3HBL-OT/2SJYI=/-QR&499U%Z!*99)'; MT $"70@:VQ+%S'+I2[0_[Q[B*=4%"'_IK]7B?*N8Y#3LX5@[CJ":AYP9.-1= MV8;3.>@AI1!Q7"Y\>QNK(]Q!'#4"S[ I_V[21"%V>9Z[!/.V"*?BW .QM$SJ MZMYA1&P7=MJW29Z8G9V]#:=W#>U#6"TE^LV&OV^9>@BA0)=+,FF1N7G@>:KL M@$,V;/8&43);<(+C56;NQYK-5_Q:DF#^J1PACYR+"W9:YBAY+A"6T)HX[Y2" MM7.K!&RAI.? X;(,-Q$0YS7L2]%56U?FANLFP&>_1#;IH2B00Y !^P@&5_(" M:ZM%D/8J/)\OC -<5=]T:APWR/E[,#B/C';/49TWPADIZ':J'B0=P"7#Y<2. M9L5K);)3' H7[* X,$3QK'YD 0+%,6+81N'_I$5W:M=P@"X"5"19HV@6MW9 MI85^CSO*-;[B"6F;DT-@4G0I]"!3Z^0@;Z5*<]2X'&+>VLIR7WAI@R3)\,ZJ MZH;#=\UQO%L=:HX$*%)^>*?SAY3(]K2'[90-27UI7 #?58&OAQRGSHXEI0RK M??'MN+*\24JTX:Z54&K/H]*.HB"<4@(KD.,\+UQG)]1^=CF(+J4V<(;.-$KZ MI:!"EE+M,AUUR YZ=*)8=:'8&7)3G>H\$(6W317QTXTI_[$V/PP5YI06_)0]64<+Z$:,S!8FR<@U[$G*Q'D69DL]<]\,V8;E#HI29(9^]*R(W3K]>^J8*MF&-R0*U*1F8Z5KI_I:G@WIR]-I5S\G!:=J??1Y_ MX)W58P^W_G41^V$ @ 2RX5X\[6[R5(V\LW7']\NUN1V(WU@SM="3CFY)#. ' M[)IFDU89%R/)EQURW<=]*ML7+\?_=956([L'N MLX.2E)K8O@/H60:1JY\+[MO3V3^C?%RN8N3R'*=K,T O4292J>?X;OFCE(H= MQ/ "C5TF@&A)9Y_7P2%A]ZD#E64HEG<_*8_4C,PW^4 !OEYE7$$3&XF_E3D3 MK,5AL321 81X<"4/",C/I<-^L@FC/*\K :D4 M8?&,CS6U(AV!JI1+].V4Y/!V0A7?0SBM@BA[OTF+D:-/^U:,:VFW[%TZ6/RM MD_N*@1!)^TAX@54BT-Z.#DZD+$\1"S@17/57:X>@12*4V$<;Y,DW$2%'FXU.$- M<:Q$%-]S2W>497-C4Q J13EY.*..E9N22')'C+BQ;QPSX$!B-YR^B3S;0[HX MK%SVW&.[&A>%29/RI6//B^[8JII,8WDXU5"D\Y65@:TBFF8=4E9C=#I#,2T% MRJJGJ#7@7AX>,$, #$OR>:\*FII$@%4SFZFVN?$QA $8\(EU%[& 0M8,_U6X MF [*L@K)HN'=)!P Y1 _N&V*=)HX04 *JWWS5=O*C\4EUA;D<\4W3:MQ*AD" M="4826LCGLFZF/3D>-QK%HP)^^!U8=_%#B61%W(F+L,!L.'W5IZP' :E [D8N-5):*\%S1:,=( -ZJSG/; MTL/@C:88PE"?A]B<+FM.F>$=L@)6JAMAXKD\C:.@I;JEB#H.9>=,01!%$VA: MSL);<"P40\@FZ@YV_@Y "\IB[8(% H4K@T<*FU91\EYBPLN(S^5H!NY+@]7/ M-?H(REU,:<>EN(*\+3A^B3853^\2"$K'R!G;B$HF-K\&JU0S*O)T%,+]V)S< M(?Y7[TQ^&!,!:VQ4824)<;DY( -[\9%5&22X;X]\Q7Y45&IM!Q7*2&*)TDP@ MF.]H16D+_/.9',H#BJJ8+K4,]\GAMQRMKR%$O&1K'BHA)077%2A=DVR&0"I^ M!9 QGI^GY(-1?KDO[1&L+<"7[924H+E-M>7-'R]'5SRNP61%PCE)7$.TC6&+ MN^4R;,7=P3LA@U6#IIBCY?QJ&)(0\$YK8;O8T8_L&\J7$F\\>+S%,F+"4,VG M2S)Z8OJ4%J S=W6= HSH3*IES\:I")K.[5SZ!>P;WN*KP\7' !+ "E(Z6H]] M%EIC9_!M7,A0<6.7PD/;Q+X&@NX*XV'/0%8R:G%VG'Y*BY-O<-. %DQYXDFJ MN#.;%R;U')"K%GY=%QZ3XX1+]S5A:(TY\CA"5AWT,GC?(G\TREN9J M-L'!;MG]JJ@HFI3;-^ #W[GP6C4@J@ Z-FU2G[,5\V9WYCC<%KL(6O>9CBH! MB*3&4G9EI_;&Q$"YCC5K?TNJL(%C/5CX$CNZ.*:+A-7/YI M1;\I2VL- Q.B=.UYXB'$G-9HF-=NOJ M-G7@720 #W)&@V[!_!@#H,WM:CV=TYBF(<]6'OE% Z"(8TU8#(3,1/A%=,3M MX.M!2V;I5")0<)OP1U[M'?Q:>="<_BH!V5/"W'!+JZ8LOV!)BS2!YW\YCWLJ M=2X1-T^2>$!R>IE4RDJ?==F2>80$JXK7@0;<9U9ALQF*YCPO6%/6BE GOMH, M)@Y&S1X>]T*!-_:@I,5D)S.-?/<2) MK'R/AA3LOE1.G[17-Y]4E;+72*9&? M*I?9U@_%&NJ#^> ^\= [/P&"[F;_Y7.0@ C_YO&1+]"9?FWIFAOLAQQDL?(7 M&#@I,G$77:8&=J.JPY_[?@XY#8B7@"@<=+G;!C@J*I1A4 D6\6) 3 ZIJSU6 MS>\KZ#[D)%)_>P0#Q=)D'5<7%9NZ/QO6Z5(Z?#%2>YC=O(M7.%E Q3FTML5(21%WK6QPKFS2:6 MZ:^Q[=Q:9<=,+XO4S88-(G(0\];4P>,$LLPQRQ<:W5D8ZL0I(U22GE?Y-UR\ ML^)$J;LEYFRU3!ZK6#Z+RO$$"!%OQ8R(6+/$Z;B1)QA( *78Z6M8OSDV AIS\7+CW>P\4LY=4EC)\>(R.@:DB39 '1- MH_I]R27*I83#WWD:V#6Q HXDG(0[CPS0%\@L6J3B>8=L?P((\HB$H.P62?!X MCL=2@@#E9G,_MR#E&?;]ULZJ3TD)0Q$$/AQ9]DYX]D2PXZ]\\4('/Q MV8RQR'^K(N$\3K5)B5"ZK&5VA6TY* _$(\)S&H-5;,C5 (*@B35 JI&?MB@)]NF*5#VN5+H<:7\ MLWH9O!>DD_R_V/O7)CN2ZTP7_!Z_(F?,9 .,B57AMPAWC8W9Q/6(9T21AV2W MU%/='[* +"!%7$H)@&2)P_]^GL=WHC*!(BE2DO7ITW:D8A5R8^?>$>'N:[WK M]KX.J9N3E6=@!^Q->([C)'C=[.(*A($RN22%WF)4.890.ZCEEHDOIKX8RR0M M^U(5BN=VN-Q)J0/^QS/CQ Q3D.IC-F&3II-OE*MJ5Q9U,@[@/)B!#]+MR*RF MGEF2NWTKTMB9#,N.Z%O/Q EOG%".\4KT+=G76A?[&GE-VLAQ2]TM*Y=+U&Y> MILFT0^"N+N$D47LZ>@R3\SG(68O14=32NM,T1VR$5$IL64(,54*( 7>E6>7> M)WZ1I- '*B/#(;UR2N9/,.T#7M?LBXIV)S@.-V^NF7L!Z-DEMBG0;?F<+^>+ M.+TRMYN'/>6$L\:\;^PDHPJ>&9NS6B4P<])U'KSO9$Q4Q3&91[S-DLAP_)60 M[:RN:Y)_DY#RP#[("["Q40=Y%!;SAT'UWVVM7>:/QP#<(Q9M7=D.?V8;X2HI M1EZRDCXCH3(HFAVG4]E4\6;36*41EJA (RY'<\A!,5!B*)J,94['R4& M2@I(65.,1T>S31'E5>&A@9U35G5MS=^>*H.5KI_&$LVV8&'9-H^DC^TR7KHPN]3A& M"S\597)BIW4L$8@']SB B\:L=NH",%.WGB<2)ZG.6E1&EMV]*[8JFV(\;,DM&.:>T2P3T!V]2;UKA! MBX2;>K(2B%WTUC=3TT,P"\8Y-ED6Y7TY9?&5'FP)MMC9YK&=-BT"$A>S[<=F MK[R4028R5YP>V"PM8Y$). K=6P!+HOM.G8LK8 BXHQ=_.%F M![J?V/9.TD8@(:VDR=.!*SDL[C9%-M2XPVEF N5BAR/QXC9U@A6\49[9^IL4 MNUGR<"UX!"?5T[P^9RH=@[N/(%2J'[9 DAZP>=" H<>LXJYDOX;MGO^1^PUV MQ)KF*BI#3V$",V(;U7X";=M/,*D*#6!9.I\MT:KDM)S,T$.450ZM9@?2);EY MB+H42>?^#KG#Y19?ED->7]E'M06FN=@(#62+U[@$/\'^LE,&5-/ AS)6T?84 MH>K>O#XEGY7$X+@.,]^G>35S/LL%AH=0HGY1LNJ8 R8ZK?:I8(DQ\TJ/VTF$ M&Y[MA9XDLC7Q88PS+*;)@9/9IX'%X8ZW<9&-*2B/(Q^M^E#%E+..J)AMF)J) M;A#SKDI(L\)KB]\ 2F4;KIN<>F;3)YRX Q#FB&+"I1X*2DL5B*O$M">UF%WY MS3X2B79XV/+D+:O]&N*E MXY#,YP/P>1'W[>%,'A#FNSR7IE 4,JBHP0&HHZ MLQR,NWJ&FT6@R>!5FAS.?%1:EXACMA-DDGZ>F)FU.\U *54Z[7D>E2,XL91@ M (QN6H/D: :6X,"CL,\DF[<0HY:/G*@<&REUU6>C- MP%^FT"BH5)R4$ZC.W[AV>6',1U%132Y8]D_$Q56[GGK':Y.8+4IROP43+J)PO M6ITDL&-=)3-I@ 96Q9R,47+@G>,$* H\@\J1L"\+^\B%$=V5:*LW6QY@45GB MD*7/M@O/S*,FJ@V3M'DJ6DLOZU(17-F(8LYP5Y3F)."UE\0' [2IQ""J8JS6 MT)-LQ:>_4HQ4>&9=(9W(,J_=7?I%"X$$<:'90?SEK!&S'L MHW+M+)4M"8,J2R"(;"Y>$D5%)@IX-JSJHQ^VJ%8BYS[O&P@U=@7CG %0%RN=T]G3(-S>:F*3!Y:BPKR QRH#\3SU_CT.&;O( M88*=7]+%CT..<:"'X'4$$@JL-VG!U"&YRO;)LEJ@$\GXYYQ; ;Y7#8G&J2>EH>07.# M:B446:YE'MP'.]L6D-RZJNT$OCH -2L6!'P' @9'\MQ.91./H\OZS0"812E8 MDV>SAKN/A355S@Z\/A=A5XE2+6KQ52(F8O0XIDZ2!V1)R5Z.V<(-L4N5^9L/ MXC/Y:V*F%<_*5HX#OC#WWIJR9TPDQ@;/Z8P0X77)5HXOTUTR6I\R[V$Z@9H\ MEEYHR*E"7G#)9MTY;/^?4\]<@K]T8]F3OF)W;FFZ% MG43\D0B)I#)/=D%MRW#8R-")[U?;AG%*@*7%/H\9H"@YH)(#9^E27\ %66+# MWENV3\-QG, N*>^^I3S(Y3?./"!\D1-ZNZS!%ST"@Q5Y:2RO<=DCFR5M;)@\:>%AVSO@8+.VSU+]+2;(<.7$)_)H#NK$MJAN P:'9<+:FH]<+H2RUN\L*DX%KPU:2F[C MK2O/VY.C"H,"]_ M6/7,T388$*-"A\J[CT>6]/PT2B9VX.1.QIJL,RA!ZFN@951LWM2>TQF'X9]J M=HHS;I/:-K'8@C/+PKD-G.ECMN241"?!.59;6[6A1.Y@LV*!V8*7V<"-Y04< ML/N(31(@"=,\VSJK $:TDR3W.:RPV.>D".TFK#1;*U-MY-[V4Y@$DJI=DL_I MD4V93RX28X 3BC8TCF$ 8W*,%S8F?VDAA*-HQI([<-)X[1+%Q1"3J!1<695I M G,LW40>EP+8-B%B]CG6FJT^K-+C+RJ]SZMI+8/C MT&GW^P2U+;UFGE63<0JO#I-)MKJK-P_FQ= "MZ,$SJH$@6MGK.5(B.-8%C>, M*[5)SA$(D'$MQ4+C9 38I M8=;'NQV&<"P,].]$#.&2DVJ@[=%^6- IH9Q=WY%'<E< M^8?W+5EH;UFOO9"S /> !!//C#-GHH%GY):=BD->V5A[-H<_MM8XG*N1:CT7 M.PF 0MN,+3EMP!]-?P.5QMTJHET=A?,(# /SC'/N4^($2^]W80_3B42 2) M\7!<7')GS(:2!,JKGC5:D #LU'-(>L$]A^PX1.JL+%JJSGD/GL"*BN0A)PFQ_$6NT)?QMA1J?O-<5G.\\)" M-"5KB[T$(..#+1 (/.1SQ0[GE;,)7#@5?[%T0+2=G*$%AF$1-I5!0S M[L P#(##@!R5U%'6? 3;49!='4NP, M("Q3>3HY(!_ .9UQ6M=50W!.F'V1MZXBR2X6E1,L.]B3[& #3^"HL#D2Z"M, M,O9Q1279 /FQMXPX=\6'LOL2 -D2G7,OCNFYV:P$C''N0VN-4#YSSC7FFP'N M& !@F#^\J4.(&$;WN[*6:3M 04!WE@6+ 6APDU95%1+&2YW/&4^,_4LVV6*I M9T= 5Q-K[:C $1G:K0OJ&Z46YTCWBJR#>^ X$Z_J=K)%)HO7X]B5X@'NQKLC M#KJ%0W$W;C=*++MOFF!BH.T<[&5Q?,!)UZ,W-#9.R]69.5PS'P_W+^ M[G9# G,!.K5 A!5==BN*W*$80]*T;,:C6A7'=9JK]VLT;;:O]J9IF7RI#D5 M,&')5)5:5#_$I5L$Q@*%W28C<*ZCLVSI:HY06G!5;,M. ++8GU"=<'<'I,R9 M9VLMLHLKX7A*"DYL?9:Y!Z0#Y^2 MC(_32#QG"O>8M#X\:JXAZ< CM[EB"!U7*H9].Q%^6&R0GC'6)I63A;VF0MNA MYL)D;=(R&R92N48^+!$Z1G.]0S=N E2%ZZ3!E^B;"&JOZG-M1CZ$SOR5A1-, MC=(5A)386"('<_J'6K-@<)9_F%60 Q@# $>+'"=[VSX!!\8)M$8;4EI7)DV& M66WW,!&?BR7A^EXH=Z&':WG>*B_7"FP/1+)UKNB:I3 M_@IP(0Y/#:PN+>+I[T3QQZ(VU=QG03&V]D-7E7(2GF/!'7(U[B1+;$UE91QG M8]OI-AWVF\=L>W;>+76Q !&;[O2Z"J*J?CN0VIL[#RSRSI> ^=G+QWZHK;LZ MN&"E"A $F)WZ9%LN[!ZS!W9/2D%][B?QDR.CLO0[7:Q*H<@,@RSS23^"0%N MELTVB_KO$1 /"!LMVUB2)!+D4XOB$\)DS(R]QJ;5<>O\P!$?YRX>3\1'!*[F M0"\W-ED:K)YQ;)SC.,9AQ+HO"DV:(0S;(3N";26.83LZ4NT,)#"+RDT3>C@J M"(@#&6]6=X_#UB& !#L1&.H7L)086$$8==!W6W#=[O1RGJO9T9&NBA'X$(V#J3M_!9]E3;&.C M&7>"03 R(,]V1/:3AG^PZKAW^HJJ*'E56*S@6XEJNG0N#W#$GHN!:9;;AGE\-?YQ)MTY6'"P!ETUQR(X:!. MGFKB >(MI2SJ^[AK*T$#VQRK1:BV2.6@ZM;1!NR4# RJ@1G@$^<[3*'EX$!J6_9#8;!V MV 1OUC[S'U-%QDD<"H)NV,>_@F"PG35NBXSA1W07'#-C-$^#?)I^-RU+WQ$H\2&A1$\P6 M6QD0[!Q8[%8I-NMF*_SJ M@!$WTKR'%5^8<#K3+;61=;A[$^^%YV%28#OZ;" M%&<3PR>]O&)O978,E:!6)=]6[3ZWKC5@J$#''+-9!0\ULT2=^YBD%F =0 Q1 MUH1M56!]-O2WK'E4$]%ULV6BX8-WNUB&X!26&$\9;5$CS:"F%6A64)LFTX M916%XS.N>NF!5]AGMAEGRP.QV_H_Y6601V.S>!3ML.^:?)@X'!Y'UD;ZJ5&\=(;LVCT.R9U-9U\I.5V$D@FW5G@.7XWBX305! MH[( J_F)J"W'$;.XB6<.)EHPO:+J+0TJ&.QJ# ;<&9XP5,:'AJ M1W0?LUW=5BKE.0'N0!EN#Q.[=PFRN<5A RSR*+(=>W(&S0$TI>A7/*=6=F4$ MBYJ!.L2V!(%7JM*[ MV!L&_ ?O[ILY[9Z8XO2"-V8YTM MFP(TYN(=-%E\Q,[AZ>R+,BVJ 6)I)L6/./>+'T'X!S);)Z4 L:O1!K[=9#=/ MA6@_]J90![/ZCT%M"'F_%'&R;_&,P[AQCC$,VU[ 'HOJXJ-M"_;)VM,\KTD] M7_5CK$@4 ^(3%+TIJL1:JOF43R)VT/=@+S*;BOT^XY3 8B-AE",,9E>X!P]* M3*KQ');\3U7=JF4=SL8V^IPG.=L:]Y.&0Y6_UINZHL]O-[-A?:9VI0R'ID:G MU)Q8.$"WQ5F72(B+Z78:N=AJ/]9%D;J!$X8G![XZ<;:HG9;-(-FO5PG7',#*5G;SV4;)]-0O+#42.!$^-1X:Q MQ>*EM!M&*T]DF=/6R]$N$"*CW4G.7;TD8"C6,($>)R/'-+%'K23BKJ:=)<V&;C68"VBI14.= D MGDBVB[%W[=II$H/@G>T:=3P2C^_/8L@#7W4,32X $_2KXX>C LP 1&EP1@=R MM:?!WK_)-P)"082XNQ@R/M]65C$Z]L$6%3M]60=N>=/0?>@QD+4HK$>T@J/K<- 895\-JXAR)'JHQ(&=T&[L8%3!FGMF[ M"M^J"XO[ I.(DM37G"LGV(FLJKKY;DMAEFIF4% (=$.,4_2(:J8VY[\(WQ*; MH&;GG;%T38A'D-,G=\J9FW0L1\"-*N_,42#&&H"7G'S[R<&X>-/973J//>(/ MT:U]VOML@A/#=BJ6BI<*Q4KMT4O([.3-V9PS#9N9-%L9DL.?RCNF(QFC6SMC M=57ZM@K"TBM_O,B^[B7H:P'@L\Z!PYVF\T"L#O D1SCS.6!L== MH,N1L/T0ER(E*%BZ1*R67# M<5)-]@$P01<15]13_;.%V$C(7NU5-Z+- _$XR&OEYG=AZLG.L8>G]UT[?2XM M@>#ETK.[\T909B;4)-"2""#VM\[8"9PP&SW)+[,T5>P<$EUB4$ J;4X=-K8: M%H(H=.&3Y#3M*8W8)K7?1@N4[.+#T@^V60YW<[1D9O2O[(W01XX+^+A MFN2M4KW6GB!%(N-B7F3 C<.RD>7N M,>I^R.]#3&M$WQD^I!DKDW)41 [C.F0!&.&\3#2RNQG&SJL#SI8WP"[93HW1 MQCSB_G _2=:;86.UR@,&&8U0G!,V-88_+PZ<%RJ>$O%:$[Z-ZQ_PA*!*FQ8VV M>2YX<0)JB0OP=5T&+)AIPZ&H-LCW@Y(.RZ&8#*F;DL.\F\979M1 _&;MB4!^ MR<>T9+NS9"@ZV#0F^(.,0<,YSG@M.Y[,V<#GCED[^F4&@V)' Z@VGO=S.>W-ODZ3 G!'V&$NLFO18 ZA-!F+BW;W* MJ2H9A7K.A2C#$#%&,80]HFR-IM[@9N>*$L?V@)I_X+2STR0HZ\TN!T?(08<^ MQ+G@%IW ._'T7/G8)RV<-Q^,IS);]$RXIXD@6OH.D4= P&2Q2LY4 M4(<<0D95@)-EMW]L6^+B%"EQS(!]6#!:10[BS:Z:VNP+!A0>/"=)?K-5BB5W M.M9.(BEO#)$=]T4@"@8"],M*-AV#_'=XW2:)\DH4F51I/GB>>0U-T3T":IYW M$ON*9;&!+*AIW6II2%%-(M!ID$[,UIRE< $'.U".&QEB07)-@H%5;V7_ M*U&1$XM!WK?C2.+6.BK:>2CX"+3. [OF5$)]649GF$(;)8(2@6:?!U@VJE.L M>K LE66+SB<5;)!BYPY*C\3I]A[&,J@_SL[.ZA*"ZV72"2E)B$H<,W.D"#1P MCUOF9M=% ;^REYZ>R%%MF*]E'LC_)>0'0)U3"+'%H,_M4YD!7:Y?D M3M]O/E>>;%!G9X^4TV66QK@=TRE-(J&_'$O'N6]LZ$DM44?N%J"W[C-9,-GJ M(;-)LO*&-=PQ_).JG>R?S8Z1T#OU=YLGXV ?32E'Z8U;8%&WY$2@(ASBE' C M+-#!L\+:R@O0A$)=Q_9PD)#S5#'ET?ZY:3"CF+$<@)<@.L=^XC(7636E2!9R MRO&9LM0ILO(H6+^"<7$_!#>IF:<]FU1(V] ,U1QCL$/:^BAKFD1";#Z;*D[A M>^5S[)P\;0]>#"HVO8:$=FRSP#/HY "#_3J3X9L$(,6G1U2Y8PPE2Y4L@8VG MA#PF!O/'WTDLV;ENB5PF6=! 5UFRLYD(I3DA=\IJ40B[3USX@3UKDM;9S"3! MG;5^W;K3L2)0^0!P($00V]A,J(UR.+!I\S$F*WL\$@Q"'OLH.CZ]R28[RLI& M(& 4<-CTRRD8Y4TBV# B"S)]LC--)>4\\@TK""4/71V M/_;D(8 U06*-9W3J9#=BT9 :FW+O$\YQ'P[K]V,G6MWEA7%TTVDI&4>(T _I M%.T]%XTVA=1/J\NAQ>P<^2;+*@9=FASB@)/8T[;$8L%#XG6@;8HG 7-2MMJ0 MN35: \J2H6SKB2.Q8ZY8%&OL,@DJ[+EP*VV3 MAW3S8C@UJ^+?V6)E![/#X]P$3*?]TZFX$FR9K2^) M\T15:AK2$M(R9@.\I W2<,CZ=T][&@55+^ "SAB'76\:9QDK$E!A#^;V@MT[,M)N M3DWIAS?GKW3&C8VJ!:OG?#;'=B7EQ]3S9 YY7$"K+*AD3-'6ARA7YN;H+'#% M;N0BB@^J5!.F;)(!LZ=#9ZEVP@\;8HMPJN<@WR2^M=CPLP49ZNSE(PY):J<# M>(U1H^U>:ZFSS3 $84 C0_G=1A8VC3-*$FCAT4%2S:;CJ;=G @0451X))M*F M2(704"[WP]%FC 7K+L5^MK-4GA]V"/YQ-F<_$"IFV^?8F*9:U#N7Z$CG+YL\ MJRCQL/21FYVQ+6-K*XYP'N78LKQBB#1&.<4&X#[F8]PY=AS3XD C>-F*;VH2 M :ZCK9BMR>[0YY(P_S[%"+:=NE@YP9HB WE*NKJ@I>5?IH4(G!QP9,L1)1Q6 M26S(X#_QE+^.ZPTR%Z326\_8WZEWV4S\XKX/IBKB(=^W/4..[:JXG=DE;*C9 ML1PG)"QZV;3"<6Y=V+TZW"^#0K#R*8^GQ^E43AH4D*MT:<5V.%M#Y1383$_O M,J>;-B+TQIYSM$8!V\KG3V+2%E"V32:Z\$0.=E7&7VYV_DDC5GFO0P\#.)>+ (ID#8[$6=P4+1NRM M6KH355.P 3PX^"HW@Q+JB[583): AG/:)-0^TT",BQ$8I<"5EN4$DTG!,2IC M(:>C.:FNR\BB M"'@L#D%AO,L.L V;:1UE(8@@'>4\(\<4?P-PX#OFX=@G\7B%SUSC5@I7M" VR7 M)0 CC'51 FEQ(!28>B!@YHIPT;ATD]G=5^*&Z$F\<. MN">Q*AC6S?FQS7+,8J!I]XG\D\N\L%C)-B..S>X$YS0-HHCJR!0+%60*#+;U ML.P)0\E%K$>2%H4# &[GF<_!JGDO6?<36MA@F:A3SSS(HCV:9^$J"&K#NG;B M2F#TV.G*#'%Q4K(*IBPR4[=$^KGB#+\$2G(7 *RQYH-H 4"S8]]J,HL(WG!: MPMYSA4R6<=2->10YN*8:G!<.G;MVL1''1)U .0XFE(OAT^S@1;+3<#F* MZA* 1J< ;?(C7F:-BD%OSX9O<7*8RAY/5E#JR'68'/R5T#'S:$YX(WS!.P5O%DVH;=@ M1 6K#(7A!/W+$W6'5E"G3Z8]7321\:8B,6;9U:>H"+8@60R;N1YCE*Q ^\) M_W&!MIX"XPZ9?IM#XZO4]2"^G:LZC,UWHW>%L^3%'-Q$EMNP5*L45!-?-VZ$ M;C,G-$MZ*4,+ ,CP*$;E W;WSFK%'\C,EI>=J"A_-$A$Z9P8*&RW"&P8;'H0 M1Q&GPU:/*$GU+"O4:"':ILO1)E^^SW)QDN6'V W8/> *+;KR7($:F8AP"8# MV"1HB%E"7'8[;!PBQ\84(X[(7'K18G0)(-XN%^>@P!%@'O!Y.*AB->=P MWYF:B_9E51;.OO%YM@4)1V6GKKVTF4TU.P.X%]6"%GO=59-8P>VV?PB-9%W) MH%EB/+D2&X>Z[H"T0^IS,PO)7%\ "IN%)U9(LY-O4SGJ8-#DT)?E.6(&>V&= M7C&+4)U>G5>.# L$6%35H96]GCS M9?)9+3>?CSD5E*2*BC>8IZ' M5&*!E9CL'; O4!()O)]]$L!EC"E;QE"DA'J8JMEQRC+'3-LP*:W#+H_^N@R& M$M;9L0 PD )FLC:CELYA2"C53CEY2N;]S=/+CP1FRIC*K0ZX7UM.G,X@E#IE MLR?\RVP5_;=Z29.;"H-;\/L$UU'5,LG2G)6U)828DW,8VW8.JY7#5?Y"Z2N: M_(9&F2?VE0L,,L+R=7RN*A(K,046BV#)L5-LE1EP,%8;'6UI.N'([NWJ&\HY M=0*.U2&=7@R+B@_@+^JADAK[1.HR3+S-NA9_L,IY]45>PF]:!I092-Z2*"/H[!G+4=CM@3H#LH M>DLR'%G;LK=9H:UB%<+06=[%<<=.LDW!3;RB2)DM;=%(O@X8DG)1PL(D+(Y$ M37T0>CZ5&3HO+%M \4/Z\@7PYLBT4$C2$U4_6#_3B!.[;Y!,%DS$&A*^Q5V6 MY@92 Y/8DVS?H!(?1&&<3PDR>]4T&K6-97;\A=_8=N(%S"5!!79=$Z:JS((/ M6:20=QRBR.$#0G8T&R\U!QD*<34!HQ'L)Y1]G,C0+$H^N,AEV)W*B?P_EK F M/.)IKR X#W1MBN@TJS!RMRREC3+$QU4V706,N.ED=54U!;Z[#-@Q$)LY6^(R M//TB.P.>&^/"*>BU>2(FV2W&0_$0.TEDM;?Q(\HG-5O,5GLC[8-5C#R?G1.A M@']Q+XNJ=!DLQ6=+@]Z'GK*\K4[SS\J9G+NU+*F4U"$Z9+J?+'WCSIOD<#S! MTR&*-FMZ1UONL&QU4?.-5/&)7!=AI#3D#5 MYG1*Z]7TQ@US?#O6E:IUDA:L,^IQL\LZ8K8Y*.7LPVT8^F,XY;%C@^: MX9H-6C8Y0T8>C[*43?-B6W5:U+()VZ8$U.JN$PV;!V10;N M#;L(H#S,K/=96$D5".[Q9T(]SA@!F'UI AI33?Y\6U6#,J:ID&[JRC#; >' M%#\RZ.UV_0J4J]$BT6C/+'1*:7"[W?< 4-R#7]],;U3,V!&&S(/L$X6C=$#1 MPN.)R9"YRR8S]&]U9$H#7*H)J"[B9G?@"9V E#Q" EXS'D#A=N/G3+A0+ M92.7-#O2%+S?- %G.H<4P9# :3/]NQ]<0@LRZMLV%$9[EYV47Z27PMBG1@RU MJ!!F%W129!2K02QF*D4V(PV1<^JBQTY_6ON,@T0RN'7'65R )"$+T'!+@4T9X^XZ!+(O-7A) 82RPGYCH5#=SCIO-,1(M+-(L M6LS)ZLGQHX2P2LRJL"2/7N($AA63@*G6$]JNJ32+*R=']2!I(: _R>[$GADQ MOV-:E7&TST*FG")1]UEDX%\X@;@=#E7I;=2Z%7>HK6-U/0;%:M5!V Z[ #:< M:^LSI0I6]!Z*/)MI/$>.XBH_EIT[R8Q*-M[" "YIW1T3 B"OBI0Z1U/$"Q:J M1CO*L8ATX51%-MI+AF*PTX+)54AOE(<*?+>PQ !!A-6>7HZNT#6L1 M5:PE=@=]E]6$L2DFR;.S2HCG8C/'(NR8@'Z377RA22.P.$N>!]9"8*A(VIID MIIR<)[)/8"^S$;<5=9-R2W6>[U1=1,R\6C9J89OZY8_J(FU#:VK>@(HQ&JJ/ M6#3F^1GP.NGJT*[$H_LLLSG1HXU<5NZSFH6R 9]*;NQ;EJY&3&>5EZC4%G5U M?^S[G@3,.!;B87 9&R9;';:7/CN], +@"1A8Q$EYMUU-V;T.5N() -KHO!&G MA5@P&4",4N^HHN8T\'AA]\4$=123M6X\LZZL#*R4W=JAX$%N:*4;)5S8) C" M-\51O$14'OD@<:R%$;Q;50>,X%(&[]%*EHIU54(H%8FWF4UKG^;%GAK582"; M^G155OU# B9NG W%>VR<'GNS^GATJ@SBI]'0@> +%T86RK0]V8#78;@IS]!$K>6A-PCIE MN>+DS1=BJF9KSERX8=@B;Z&6:LO2_&56&9BP!SYJF0:BYIHNBY'5OPXIRI^1 M38?($"&S@38Q*(J01,I@WE-R/K8>F%']1>FSS![%4K#@=E&6WI+ MG[5UIRE.Y69L.N!L8M]KDF"Q-]I(73NJ/4< LY=MB+O/<4]%"O1S"T4]N\6Q M5Z.W()F"H;GA*WNGJT#N'-_=0?2U1<=Q)O8],'^/ R"4H]K%:&9U#E6*PK.P MAAR!(,)<:A]-.8LJ.,0^X%PI#,RTR(,ZV4-K&^UJ8HF06W[1NH+)SM5X*^() MLNJW>V<24\E*FE<>+S@-,RB%55)4CG@W\I5)$(8M&W@$6#0;I\W;=%&2.4U$ M7?$T^)O+*E;?P!5KZ^:ES[NR3S9%'=3N8YS[G!FIS =0MEB40O6G/9LZ8VK MVU56&Y7$J^INF5Y25)QXHLJQ9V9(<9Y9CDGI"OMG+G'@C-EM-,MXO[8UUJ)] M#O(L[6K]JA.R.CP/FC^$@8O) %5.1O77$A<$CI3&DJANM,U'N1]]BLQ'5%-E;[\O%4"H<8S-,ECJ\ M2OZDD(2#V1)C='HA>VV;2[1.\K+S\=RQQ-0\8J*;8V#G>LF8!IU2+]TG;7XZ M@RVC;6N]")5LM<"OSN;=@3UAEGJW:Q4>YM0X8LY,L M'0K=*I@$#(]=!=YW%$F$DU*(TF"NDJ_B]Z:J?BX >:QL_*YF!?R7_VU3LX^ M;.N;1W74C2^NW "NB?_?4U.\$]K)N%XZXY74+OC^(Q(B$A"L]H]QV/&H;27T\RQ+T !Q3-J(%BR*]:>%( UX+A:9-^DDSOW@25DNU39+N)BO6K$^(@YH21#^]N1N\, MZ[$GR@*:&G4]M[5TH68([[FJ,4$P["/O7U-DF\.9Y4J5Z ^? M=#J24GBBTSDJ%(6]98FR[ YA7S@12N0Z>0ZT7/%.ZY1L'Y<"5G8ML(+M:^K- M2B@JV_M.$(JI$?/PL-BG6*PSXO^E6TL<<%L$95' ! $@<+^U.(F#,>:,@9>S M6H860'E8TQ72*]\ MFF@SI"/L!ZZS3=B71%W@2_N&C2O,=)^Z $=,6=PPS-W$RV@I":5$)\FAT& 3 M:[%0,$DC)'.H[&?6;G>C0_8<2+]GXY3J9I%9! *Q584$&:U7GW_2OK-:R9 <2IRXEM:'*6=LWG3FLBFJ)5')L[*T(=]P&40L1Y.D%83!IS$-H(0"#QM MP2TV:-E!;>A6SDZ>E@HFL1 0\;QPSUGQ0@)2GEE5&/>P$Q*?QP$AQE-,1*I: ME402P!W/[5"=0MWJKES+U+^)^V\$P"C=';@E[TI/&!T M9DTF)"O$7:9+?5Z?SB'E)D$?6]H>N&Q-$U]U#L=LD&R*1&22"?UQS[9]GLH[ MV0V]3=,K\^[:/ ^BG5LI<,:=C0-"KPP\< ;'+O@ M3-3=XB9N;G;X8,0,S,J&+JMBG.IRLQXF6'FZ@W.DME%+>L#7.'IJ\<#1_*), M$.MTLCURE6&?4)/H#@@S*< KL8( :B1VXH"6G;,YZR7DP$T:; &G3#U=%YEP MA4U%F,)"FB:63*K*9^+$ ?$B!@Y\[)CIXLSZ(+T0CTC11)6LE-*1#N=P_9S> MY]U1*39=4,P*D>P*B9X.M:L2%M6:)=Y+R@MM4^]/KN;RV/JU!KL<9Z?C.=J* MT5A3P5GFP_[55,^NUQT=B0<&.G9DV:R8*!ZB!$%5==O0U58!S]7R5)1\%Y^/ MG50I+BC"NP,,3.Z!&U594JK3EK*D0YE+W0?"F,D6YG@XD1; ,0#FE5W-\57> M;3R#U6Q.*9O'B D@*O?*;/D\G'[.*L.+:32>65XFF_; ;9,"5>"X!"C>G?X[SY %*?>V(LE8]GIQ5[^<;)FI;L;-KK$'@2/&3\YGG.:L^="KV K4H$ MAL]]ADWN>:'*JL9#<6*%"'%;%DEA5\>G,9Y^S+#OD^*-O]2(ER'8NE+D2'">4%*5/8Q*TRL)9?TJVS([/Z6\L=P\0<)^ M.09%W=T1.?#JJZCE7C*WU>8B@3 M[=0<@XS)VM5K8&*MBM03#Q:RE+;%B$D(:LX#8 M^HW[/GC68>Y>=3[4TC5<:#C7PJX:)++%V.T]?"].Y1,_8@O-3MOF@5=UX ## M+,A6 ,%!!<*PPWX;<*A\*GWRK"R#=A1+8/>\+$0 MN?7$1QK5,%FS/9!2L#29<4SJ*5V*WU2:2/8>2X^2*ROMBH\-_#\?-7GS7&H8 M.6V!>[:7BKU@&@T3+7F(0P!+' E[AME9.F-HXD"K[Y8Z,2C*#XM-NV:(TF-- M3L;= 9/]M+!O#?MTHO:0;#C809^&25F \[ -;QG/+K^[$(6D9FX*R^1T#$%' M4AF-P*.)M?/D\$)2*J8J<*9 LHF^#5NO#E]O<.G5$Q[Z0IR0%)G2 M_LRGTUU2*P$T1PD+09?\!D#)"8K!C!K(DVLAW E.9/PZ;2-9YJKS.1,"#..>\@HS<0QAP$%VBB;.I_4G[<+O]5 MT[K(>&WYD1W@]-!2I2);#0SR.FP*3@D-MSZBV?2!AC. TB*'WG@H%*?(]62N MC&A2ECN+]!B6TZ&O#)AP\'T[!IF+;.N3TX$-0,R_.G'E] IK*C,?KGFWIEM" MSJO4J3O8PFYBEF62$5R%=(65ST&26Q5*)H"QZ2X)AI:MJ1U(=,3"R0ZY;GLS M1[7:_%3%:B8(MV4T2N3HVWR$[1P(N@D?#J>ZE&E6ZT<)59;1R=.Y2_+9KAL4 M#=MU:=(K)KF[)W.1ARR^^^BH_S%H,_?@U#+0@A.X%9FSI3OC/"ACYF20O;P8 M$=/USA:!=G'=JUV;N[V&X;#3H>0AI":?&X?>42U#>N,M=5F!-?:# I"WV+45 M;2!TG'VT/7:71[J/94AHH!.; GYSC%P\1JU@EJ9-Q GVP>*N> 8L#XB,[6<> MG!#5-K-9V!S6(&T SEC5W:81.';\YJ$9F.5L.F6&"([=1U5\TR;\C@ZH:5O4 M\>99 &T*/FS%$H#IV'T@'G9IRWD>'$,!"*NGL^+'90Y6[VAU!I OSMQ*Z+WO MA0#+L:!.S61#KA-Q<[*33PH:KJ4Y].@VYIZRB_A C8?3/U+)+4$^JXQ3 M!57NHV0)78$:*('-[)1A0C6N>A[P=Z8:5Q.!JA]86&,S"'7D&9FLU+,I)**S M L"FM$@S.XUI5\6(+8CJ[:G'-7264S51-AO""(^S8='1^R_.@$EV;F>V(\UA M'E5<%*VW"(\=W_U5LS3.8:]E&"=CQU60GB4NPA[/CHJQZ*/Z,7AL3E5:%7U< ME!\S:"U2>I]FIH[3\1T/!X]^T!S9J#]G&34VQ]K9NMVRB7EC-(HPU7GP>?(V M9@*$;G2WMJCGI416S>,$4!S :=A[=C7?9".5O"&VFF,U5ME4BV-VZVX; *@E MJ0I.?*#(6"M9]2!.1Y,$FHZP?TW-8J=)IK6:S)KB M)#W,Z #]WI'$$B7BMHIF8\KLA,RH44@2:K&>)@MF'??N #_4R.PB4TFIU7! MA*?E)C6XU.'U,)]62P >A(C1^CSGA*<%B.KD9^>J J8^R1R00R]"5H7>!WG?\:0 4PG'V2])U@+EZKK0LXTHCJ$HJ^-$JYX" MQ(GGY( %&SDWA6&+8[QQ6)*TQU9-]J0 W,+!/\=50Q1!D/976.<,>Y97>3*K MSJUPG:0^/BR#*QE^!*KR+ M[K033!,E.PHWGG;,8N4N"4LH6H&(APG$C8=AW_B- !!G%,C)U&)9!K[JH@:"\D[FW#7:249-.72 MV*/L:;87[UT&3=38-/\#5ZXJ3%GJ115-FH0D8?G$)E>,LP\E36I"K!:7%EV! MSGH&^X/F/.(8A'F;MVVPOEYY>&L.2D2-Q@!FT7C^J\>Y6\I)?ZKN"]#.I!!Q M*$<[>V=!*NPS#2)MJ)$&PA4L@V?U>L4W4])1-5=XKX MEM#3PMLQL45.F9E6JX4<)W6=U7PBA'>,SG9P@M%JGR(1(@^^2<3@X"1>8),C MV[1V4E>IJ"VF!\Q."(_##!:WJPHH ]S/*@(T.>\WM0O'U6NMM)U.G\OWYGXG)!80IS> M]<66WMWM0DAP]IJ&8">K*4"")Z7NI-SF;($E5BG+UJ!)SQF+N@ "@8#&[--,^VK8A%2UP MV=&4L9?"TBP!F!A^'QQ4Q@RRTYNC.83"6/.6W#"XB^*\Q;:!H!S2 7H >@X; M$T9EX\J\]/$1_*Q[Z<0['5,?J&9)"T9%PLU=1[R9F.#,=!*+&%IT:!(_NLJI MWZM);-95=. M\6@!+1U' M*-O"+E-NJX#"*N/N.EA$Y6S8DRXEDP1$.$PHB4; M$UTQRIISG:ZVSQVEYNS::.K5R)?#G;9#DK26%#K@KD\U>, &.8S5V[&R[=!;FA;Y M:QR?=)NLLOL#_P9']?7 ?,ZA)5%[!J\D+]BT-16D)^4UND+.&7"%LY^KQ.M9 MN3?\1W9K8@'3--A59D;%6-L^.\?_CZT'":M,YGNO4$L!?XQ]LMA! 96^P>B> M69[785@ #!O!M-*C2.)3[!$(9JJBY851W@1LP;Q95G"T?I+O4EI?O[D2CMC;W#N3^ZPQXH"+,'MG79+TK>$=MK/I M7%30;IS3, RBJ?A4!;;884*?+41,TM0K_LC(MA48%+1=I<9*QI"],$4*9)5 MP32'3%##V72(?,1J@\*4MNA_UYQ_2&)7MOD\=YRRKG(6J?N=5A3A" M28 ?AE<3U&+#?<4J&P+8VP8-.P:QQ99@Q_/BY;$5F$\PNLI9BJJ9?>",B7##+T>G,9<]MDT+1]N\#2@D \1Y160NV=V''RK%0 ML%5X"G;.(-LSUA9'E\XN\#TKEFUER:[SW@%FB_(RF@/?P K@"\.GQ0M#=KQ+$B/6N&2;10RDG<5I?7+EG&T'=;,=FW,@Q9QODL;>S5HDPC7_ MU?FL!SYPD]=SV^?$Q>#\N;$Y=\'3+@%')%547N=B65V1=I2LNCFAWTED"/KM MG6L5[]1OO3C$V M2<*CKR?^7I[QE=.(_R4@W+;2L\@.[:C2>*K6&3HCB+A.U=9B3@'4QII+OX/= M3-M@5_?))CGEV5D<^07&6&U0QH3P110^:6%D7K1A6R*MQ:0!P66N7"J[-(O0 M0AOL.(V2W^%+17%SY/'+H##9]% C(=RDXK!$E=*FVJ+6JV1'Z/4-M=.5IS+ M'B:61U/*ELTV<<%*_8O*/U'EZ-M'D M,'//:D^?79C+U",1+M$)6&)T.F!5^-9EC8KQL/TLV"2B/F%\=#(?0(+YQ9XO M@RPC^,2@K- "BL2$$Z\D/.U<5E&^#0N@5#F+ EB\')U4QJG^R!:73Y"0F2MB M*PZ@,E9$CFT,D!GT7>]N6TNV <3B8E:* +N,5\"A\LLRSTBM( M#KD"C A;VF'CX&97\3E'61I-M"@$ ;A3E2 "($_[_U=6>I0 5&!1^ [<>)9H?]4IY[@T.V9SP3[1#5 M8V_BX$8XK5HZAY!LDY5^KXUV^TS8CWG":TDRM.Q.B\RFO:QU3WU$C; 1Q"^G MX7S&-N0H=="\)"=P0Y555H$0J9:="B=LF^1'M*=,T1&0DV->$M<"CRQY*]%T MVHF!@G4>FI3JV:'>5PC-&\%[9O,J5L "'%IGB-EY,T7FQ7[F ) M(C]Y+0;@##@OK38=*U$IT^E*]"\6PK@1.&VVBQ?973V_8-@-V,GS+FP7>73D MO4YZA3;(SB3;ODHK@O!U\U#9<<-2L18U3R;#S@VC EIR^0XEWH]6"'8Q"=BJ M YBL6F7U'UVJ&8MLMF.)FXY7/MA4\G)XS!2:39LU]UI(&-4 M]=D(3<)PX-'/0Z'QHP]A<7M$<&S68H^!"1V;;S&E^',IEG@;[L1\;583/"C) MPS,O$F@/!UZ\LWV!^9PKBHN4EK($=F/;SJ@0"+AAS6S44]9D-NU2)+FQM0 O M ^K?;$Z9!A9%PIT-Y#M720-E;" $MXO. OPJ%TMS%7'B[)XDZ\ V_CO_;_B_ M/N!_B@]X]NKF^N[]V]?7=[\:AN&O_NIX\_Q\^^8]?UIO7MR^\<]_<[7]Y)>_ M#''XJ__;SW[QH^7YVZ]O?/E'X8OP\:^NPAKJY_[*NZN?W[R[N?OUS?,OAB&$ MJ^>WS]Y??>V5#E]Z43]^\\W;J_GR\O,/WW[\JU_?W+WCNJZ><)U/K[C*YV_? MO/KNZOG--\.7?_^6;[OA6O[BR_H#5_7YAY\?7KWZ^^O7?GQ_4#_X^^O7MZ^^ MNW_'V]???GA_?/[6?[BY7-Q/;I[??GC]^=_^^/WUJ]MGRYL7 MKVZNQLM+M^_.V]_>//_9[?MG+Z_>WWVXZ2_?O'G^^37PW/H5?'F_F/W5GUW? MOGG_R^^^_?[C?%O_.3S\S'.YN_WMU5?C%^,8>"/___%/_^VS;SG>/'O[_/8- MNZ%,5]=W=]??#6P+?BI7OPM7MV^>W_SVZN:W7.F77[QY^YY?N>)A_/[JF[=W M@PL9IG#UY?]R_?KUM:_?OQ2OOMQO7KU__%*Z^O*7+V\^>2E???EWUZ^_?O[X MM7+UY3_>/OIYNOKR9X]_GJ^^_,7MBT^^K%Y]^9^^?7?[BFWT\&+C]UX^^L5Y MY(5WCU_@@G[Z^N;%HT^:N2 >P-O?\,/#B^7^Q>=O?_/H"V8N[)\_O'U_\^ZV M+^W#7W"%/*Y7UZ\_^X7J+]R\\QA^]C=O0J#_O% MW?6O'WUAY6%?/V-_/GJ)>WMV???X@53N[>N[FT]^D3M[??WLT[=Q6W=NAH=7 MN)]G[.Q7KQX]JWW]YOG7K]X]>IU;N7[T%8V;>/OX9R[_[;M7U^]> M/GJ-ZU^.1S^[,(]_YLI_^OGO<.F_OGUW^S6/Y]OK9X^_@1MX?GMSQ[H\7-?X M@QWZ^?Z,G^_.](.]F3_9F>63?3E]OBOG'^[)^NF.;)_MQ_$'VS'\@=T8_^!F M3']D+^8_O!7+']N)TQ_:B/,?W(<_V(;M\UV(<_EL$\;P^1Z,\0=;,*;/=F#, M/]R L?S!_1>G3[9?G#_9?;'^8//%]LG>2^,G6R^%'^R\%/_(QDOIX[-^>"G? M+PO7^/ B5_[FP^NO]7LO'NXZ]4?/+=X]O,35?WMS]^SFS?N'U[B%Z]>\^HX[ M?WBUW7_1Q4M^OV&YFV^O[V[>O+KYYM&KX?[5S][LSGKG1[S[U<.+W-2WKSX\ M/.#L6KQ]?)(R]_/RNV]?WCS<2Y[ZA=^^?;C"S+U\^B S=_(O-W=O'U[@)MZ^ M>7B@A:M__YN'OR]<]_N7=S>/WL$E?_/VP\,3*USN-[>/ME?A+GI*#Z?QX44]T<,UZ167AY^XYO7A)ZYW>_B)B]T??N)"'[:S M+O!\^$FW_? 35_:W#S]Q33]^^(F+^5\??N):_K\//W$M?_?P$]?RDX>?N):_ M?_B):_GI@S'4'3_\Q+7\;P\_<2T_?_B):_G%PT]?N)9_?/B):_DO#Y:8:_G_/?S4C=3ULU_=O/_DW.BFON;E3[>QSNK^ MW9^>)[W6];MGM[?/;N^>?7@P"GJN#V"JNW?/WMX];++V$4Y\^IW.B4M[9/E'KNE7 MCW[DHEX]^I&K>KC9H%=[Y%]T:6\?_UO?_>C MG.+I?GQCFWMW(S]U6=O;@$2 M-S>_O7DV#,WVA#(I3G+&SCUY%HN3V[B7&,N\+O+W2.N^[DLQ-9\DF1O#I/C4 M.8[KM*DHLL^3VH75OMM1?;#.'SB,DW;NFZ6. ?S5LO>LXXF>]-:[ **IT4QF9;65LZRVG2\C(D++>:!K=7$ M*2_CG&=+M,'4<6B#+&Z[W;8VH+=)58 EFL!I>UW5;5\./LO^YBGM)1>5%5J, MJUH8Y\1?6$T\' 4LRQ!DJFZ=UTUNT+W&E&HYCV*3B++ EG[2FK.6;'83;'/.V)T1RJG$[+VTADWJK:CP[Q*GZ[2C;]M;+*8X;1[GI MZKP?>9SD([8$V2R;ID'E$&=FI:H^O2?._[BH4RC-(^Z'\MMRGG9\F[4YV MM-(9IB9YTB4^.1S_8#4/Q7.7,K$!U.ODJGE#.\]YL=M6HJUFQ[8SV]:8]C-, M%OD7QVAY0E4&@RD=2H [_WPJ#!4%#:0D% =SW5;'4I3H2=VRFHV[5*DJMQDD*XK M]WKNLQ6IA9UQJE5N2T@]<\F#>JFI3J?43%'B?KF2+TQ+=KOPI6=8XK%N5XIJ/W^6$4AWL.)5+D<4GN0HF$ M"HML%Y@]EVU69FO=%?L:SV9!MNP/9;\?'+&I;NV#[K5D<_!/.1QR#/?&GK?].1,#9?'#\F,H['36)# M"W$.]TMCBM$:MTZJW.SOV:4PW=,8L3Y8JXR'!3LC%B&I(!$E[H->9JWQ!9(ZR'U(M:N2@PL MB=)Q8JY83?4/+3:HT":SM()3AXK.05,V\!SLGCW4C,1>R?AXRGSHO/18J@+F M+/6LA.!\2)I0BJU--AK*S<,-2IT^QK+.5A-DG@2#IP91?[+%E?Q9?.W&V1+6$])T=F@D06PS;OBC>/G1G6-NKNU20W'"61 MLMTX<>;Y/V>?I)X=Z\J96M2BYG(=ZE)I1+X89Y*P7KHEQ0JB*BO3+F-/=,IF M.]7_FBUFQ"/8I8)IE>UY3ASX.MN9.(]137(N9G \-N4^^;\O/*BU.5&V*EME MW[^3";9J[ZN$4#5U:IVBM-]<#@TS[S.SNZ=@]5%M=Y5*#AX@%**GO-J M*=XG*#4VJ&5;55BH[H.L7KMCU#,W+9G+@B6P^C\Y,[Y;MY5=;DQ-"7;9.VTF MYRES..R\CPZT8#/79)OHVGJ9N:J3[9C\!"Y:HNP1@T(GEO4J.B:*.5 M/_FN1XF5%US2WB5!1XS0O,K><31KB;:M.TMG57RIV[ N7-JY*%#D3&*H-GY8 MGSV"13O[&1(#JK6%3=D-@!L^2$.FM0RG3,TCEO?:)X6^2IW*+BFLH5C '<":1M;+,+ MI?MH*Z@M\;O]%6N?(?*J)[D*V6Y84ZP8!^[ 68)54AV $/:ZI)'/P6HH*8&0"JV##<-)KES*ORA_6,'C:G"]5\YU?XT) MSQ@L'L@HAZMC\Z"I"6@T[;8::V(.+-YD1T"6UU-4D;#=^^ 0;,4>%96]8Q"! M2Y#01<[*KE+GSI-1#GO!3I^R*TP KL7>NSC4=@G7$N+:Y. ML>5-1G^>^FE/Y>%$_5+DFV,OC=C5V7' 8UV;RH1.\\P.L$O#.]@O)06&Q!-\ M\;$K^82C&UN3XM%>KCEA*:K30VGA\,OP*@EQZ$,Y=GNQA0OP)@S8JG53T/>, MHMK3&[8ET!')3L43P*'6X_&%!,23/!$8"]NQ=WX7<^KH3Q0IY$%3I::%8F*R M2N>.ZV7H7+IZ,^LN/[#C&[.RTNM4))Y0RX ;9ERN+7&UL<=..W5FDW54LVQTY5KF',FXG.:!:_&"5#H($D8*^F] M<_%2C"KA,ML2G*6_D\!H[XWC#C$4+TX&%"E>.Y,(/N"81XZ3*@AAQET"%"?V MX\8#QR0*?J(CIGB>ZLFDZK8U]VUC848UD#D =5!M3RA#O8C,, M'YI.V='5' $[J7.%[[/UB3U6Y0O?)J X5]O?%S5>&Y$C[8@#V 0M;3E/TE] MZL_^_TUJ)QGV0::.U6">FT ];_+P!/7.JGT59,SVMV[J-]ED-QC3*#@V,GWVNG@NQWTP%!,MVITDW0# M3=ICG7B4Z@#,:6LI;VQ+IW-R/!][R?,-S1;\S%J [9W@LE.UU2&G&2C&3A?: M;_)S!+^0LZSVA\1L$BO6+A9O<(MK63N8L(EG$S&-7;I4-&1;C+! M!AQV*PE'9BYF'.WRLX'0,6O<5 DGUH,@O=9Q:34JAZ:<6L$Q+X/3;;.R:CC( M4O->58W+TA\Y(@I4M@F;3ZN*H*AM(8$M :9*IBRC2JF$1 Z_$E2P2LI2$"D0 M@P6;&E,?8W08U&2$E+B3'>=S,5 J]JDOSD9+YK))O0:JL#>77W6^1E:G+%6& M[$)^!!A&FN0\:Q<724X5().0/Z8HDJ7H4 H>M_88W.#9L;%/Q+^X;?W"62.&2::[L, M*IC$<^T#1UEMQ+(*7+6&/ 0\JBRYRJ)@P@"_'F8L#&-X-P#3W<' )TX($6# MU"4\#$6J[%:;.1O;2F5M]\\$)9P[Q7!";8/OX"D;5(>9,$]G.IF YDY MY(X$UM@E0H[Q<.I9W=&9Y>?<;5VT-'4Z=U&[2<$^ GG3K%.G2W0N./4V1D)"J<5!>+C(KAB*ZYF'SC:#"5F$A!PR M,[98_HV3+DN,U&AV#BN=0&C(1Q_.#@%%L.RX2"6D5\][41\-ZYSP\H[0*]+$ MRU+&Z/@;GMZ;7-06Y;GAB=>TV$L/&I*K/,IP-:=5V+*:_!C46[%)< &M+8ZL MRDP]*PG''73D52A@= :M$D'.GRP0,':,3J!-G<]HXI\GFO7"! MB[)K$Y=PNGG+.8E:\()G=:H@8JLJA\V.>>60E,F:I38>%QMHB?*$,DJK2T/! MYE.O@C.SC42R>$ IB4N)6?&="!Y/++U,&W7NJC&'/)T$*_OJ3-+JA+83%/:W MS@X:< _GJNMDSRH^:K?Z*D'.C 4B*,'8.',VW M;;+Q+3@BY1(WZ2!R'PJP8QU4>,@_MS=5SE3XR!]JY2F;*X2 M>4!.W2;9TV,J1*+SJM+QG.02+(=*7BK!^X#BV+/$:W!$JJCX4(3!^MI[K2V0[NW(FW63:U_@B2IAYO8!S9=<[V\>A7 M&9*D]BI9AE1YVB5U!FOE1:8? IQ) 4ICS R#+U^_P"FA&CMVJCD!PJ.P\QBR_@L090-$LRE(#'GQ6K/6P "SH=#BIEGG,IW'D7@>,?G1XJ29- MXJA V[AC!S)^*'"C["I"A+7S-^X.3&'!NS KT;J:4A/6 60J/409B/$!K*N- MQUG)ZB:Z7ISMRGA3QP7Q2X16:GVT76%P+(;L#WQ%=)37GO19S;1-HH-C5-$8 M\!!C'PA;V*Y%<@M-=SY2GX4JR8 &XRN]O2Q Z92+YL0!5(^*ZB5B$%>@95R1(^>T>C@GK([)_4>CI4N@]-^MKH? MRX%)4(&1'<'!\HSMBR*5,YN #3;)7KCL60%N9TZEFIVHSLD>0J1T FPF]_+V<9*@(L,I+AB_SY%EY^- V;R;!MJ3KL[?H>)G[J4HY_2Y]V6(8(XS M]'PJ:RU)E,(46,;#I+..1"HTDU KJ]C)HB^\Y+N,(YUK M'V2)P=G=Q K/C;%7\R9K83RMF?W1E3EG9^FE4I>IUU*IE;L6M$0#%PS$7OF MJ>9#]\W6L):T2.\WJQCI)N(S0!5[CO)K290O>^[$23Q-D_'8J@YEDWRHR):O M2(P**+B*LX) HRR@4NO&2Z)B5W+" MQZ%8CK ,6YA+,+UCH9)7\EPD!@WI/++LSXH J"PMD822? Y$$SOA_;$6N:F6 MH::']:+0%C/>6(2E=+_N/I;UCOAN8Q?,BRS^)MLBP,^D1HN2VSBPR?$RQ6YT M#=8.>&Z0#:%PO0S612O"8\7X%\WE(D'B;&)0D>C-I/CJ0079#+,:KS&[RW8Y M V;YJIU$6(4/$BM8TUP+L&$G?BUJF8%\"#IP$MKUR9&$%&2*'U0UXK/96MA0 M-6IPPP CN1]G\PZ[491(T521:(\_++*8]0#>JC&(HQVK9+7#.3L>+LE/X7,E M\.9P+.:DSU4_F9WG$7/%N[Y&-ZP./NA)I(*.:MDT5&-3<4AHYPZ MF^RW;<4BM+1T:2E0E1IQE6_?MQE42@ UF]N95)66AT,C(A'2D!I14)#HK-<( MV+V5$V)R(DD8[8E(6GRCRU%^O46]7RD5E95IO,CQ-W99I)8,+#%A7PE6CKKT M+N8MSNPRK%-:E=J5)L+T+-80B^_GRR2Z="*;F;T_-TF9N;()SU)E73>BQ0$[ M)3_IF=41(E3!JA,H[\[75^E$9IZH(DZK*A)JJYNO2WN24W\ OLP'CP>PLDO7 MJH< ,J@/R7WNT[;*API<.!WD->-#@ ELG8&5O%$P9;M!4X-PD('';X@*,7)Z M5A643-EB<1=U(B);E1A:C1J91N0*G!2LTXU-HT-A"V!,.4OB /:#@_?6)\1_ M/7G"0YR[\,=F[,1BG]@[-A]V2*[\Q"DAQL+F@M]G*=P(\_9Q'$#CN_'Z*#_- M-%>C1,4:PK8E3&N[2! X?BS-(@]#*4 9G236660N3E)+B^3J$&RU:'6SF("/ MXI JN9/45 &@LU&R4F>S"@ R28]9=1H1)M]8;)S@;U7,"#U$S-9%CDZ?C),] M#9QPE&NU.BU_;W"XBD/">T281[ET+6R-,U)W8*;))F(+XK7!@@4X[YR=[%?- MU8J)>NZ[*"/J(E7_P;IE\12@Z029S,I71[M*=F/GL(-%0QY J*LJ 3""O$< M29[.H+\B]LLRT$C@U]4^93KHA+$2;O$[79"%X,[](%/>,I28N'Q.<$RCTKQ+ M6#>NP"8'K#MXEO!@5'Y[!S\2%($]N'P.@TP:A<4V)4L )!G&H&WTF61BX8S[ M(]Y8%$\B4,HRYEIPXYM-=>&!D\@$_ <^P2H%4PR"""40087]4' MR&Q7<5/G@U^7C45:AP6#*)X3.,QR#R+6=_<_0NG M=]RYG\FAPF52 %)Y'-LT++OV_&-0$SXIB+XH37P"'F2H55]RP!LEY2O*.-MY M$%7M7CJE/VYCS>O9!2BY45G))D.K0_F3I1<\""?+PZ"@TB+KI5=3 M4Q=) 9<#0$"O!'.2=F*.C*85*FU2V9YR'!&!*'?1)1HTI:,#Z(58"NM\ABH1 M%2=ZMB< 9PMDQRT"1X^NB;CTQH#-4@*>%9 AXSR&166\:KO4[G&2I6134AY$ M&02:4?6)MH_ ?ZSX<9@#Q^L2PA(!A9Z5P+[B:.5N;>J4*C T;[NR24DTM?I\ MYR[> RRSH+!;!@ $ HF30!>D]+'DP>$35K MEXWM)TEIN 1YW')GON?R#ME7RFKV=\0+9 O=6UP)4%.6:>!4+!),/#3Y$95, MYCKTDIA!D.HV:16PR!*@=%93S-B6<,.[OK2HKYEZ+7XTH%ID6<1O'C:[%.D* M-N6EE3),=E!B_7?Y/I93-V/]&;@MI2RG-,E*4H&!ZD"PLY>*.S]J&A:9^!;9 MSB>U:Y5>/RP%$9/.676_9$#0I! KTN Z_0WXF1V\/)P%Y?X(:YS>;>R:02+_GDR1 MX\QLYMHS:7(LJA)RJ"-NU2ORK.QI"VUS^A[WHB:T=0 S3UTA;B(.L'?0%/8L MX0,6=)'HIBC?8K>.<:6IHQDX80^4\:R-A3P:'&;")\5DFH03,PU B#"%#@'E MO2MJ '*^U2'G.:V-Z,VB$)Y(M28W[RDM1ET56"#@P]=+AVX.>Y6\:W)I5;HF M-BQJ0!^V(LZV;^!0)K,&\F41I1%'X<"77E=F[/K(SM%OKM36HLXA:3Z%(+6BZ7F@5(AW?%JRDY:_<@/E@T M;YOF#FY5T3.<R$U,"J3Q FD8V M4R& 5Z_VL"-@E2D4FX%['Z61*UU +M61&$KV'ZJYQ-63UE MX^0X![L7 <]!>2);H_5H>]X7[)LY[XA1L:L+1"QRFIO-V997W2KK/#0KS%,\ M+,:HLP9(P@!@C<7?/3DON,#@ DU'F],.R=HVE>4D1LBGS#T&\9NWF=>I5R,V M 2_[8#89LQ#,QTW1GL4T.A!I2GA8]#RD-BM97>5QKPD%:#P#. MXVI3\P2P3$%4>8>A,63]*>MT/R#L["+/V]0DUIL7-9&D_;TV-? M)&?^=2SG!/#DLM)F*XY$[:Q4,ULO-L);\A0Z2TRVTR;8CS#9R8KS'*QS$\J+ M,]GZX<@RPPH?,$BC5-EL3M,'&WL(3XCSE*#[C-68>.G*K4>0Y)[-"3S@STOK MO4EGZB!IQ_PLBE6 >T:A%? Z+)J,3L//:JL]*6W?!%:00U$IQ8V@XI!$IQJ\ MXDF('[?>MZ4=5AO#W)LI=X"F'5-9UJ(R*FZB4D4,(/Q.N,VQ&[#KG%.W( &TUY0%57LLR JN(NA,4 M1-MRV &&B0A.V;)!G^IO2$6$F3Y6MDX,0_2(&@Z= MLN< 7.P8-^0_E+W;59N64#%W3NG,QL+WS$KF;!43 Y0]8.!8P)'P M!U_M I]*CD?G 3"[Y[ZP$?BP29I&%E,E5WM-"-<)%Q4WE;/\P/2<*U%=Q8XJ M'G@D>4RP FPJFS) EP?!C6*PV(@N/R._T*(4=NH"#\K8XV:\_[))]3+(R]=E M/<&B^T2HT(S15SQW+IUP;TT\FM$%DIF59=.SJ[1] (%LK&V$L@>@J<4!=$8$ MM-BI)-'/V;6YFMD@X)6)+]L6]NCJ?EJ0IOWM.8/R [<#=<4^L_&;+Q"%_H$L$ M6MR/WK&6%%K"F4ASJ^2G3%)UEM1VW^Q?B@"6>2Z84_.A1-L*(MO_4N:!+U:Z M97,&0Y;]D] A+,6"GP!N MG$W !8LPJ0>]C;;> 6.#.KH6G7G:@G)18N4YV#[9G%H!:MD$BML"WBC_P#4M M1)>$EU4)>3MH)"&6E$GP+.>=:>&=.)$C="K8X>=8@F'S+^$,R1B.D&=PBD8D M$-3U3GSDDA9)JE+#*66E8=D,G>5UXX*R1;_U3,XPJ/R$VRI28P9,YP)R5-MT M!QU;_,^+-4BN;,/:L;9T-T5_^+6Y>!7_#QA@W%YL\%&!![14QR M0GPIJ-[8&7"ZV;1OX'66A86Q+ J24644JV;!S/ZJ3I>CH#58$8=#_-+9("4I M-:FBVB>6(LZ; R&IAR'G:K12@$UL6WLN[3AG1R1EP:10DYI8X2\<*;'38D'; MQ""8/;!8S6UK1Q=G#T,4*ADGU:>MV M:]]IJS1'J_W:>!*U:9Q%42_DE,:=I67/6666SS(DMK9PGF5AV>2C7 MM4G0C8U0!LZ!H8LX-?&/\PC&[LJ,[.>J7#/_SG-MTOA;(PC$>W,$TXYV!?&R M*0! JEH[0$<'=\8FSQ9NE"L0\. =[6A+:E'8/7=(VV69:,<:*^&,WU2KK$NK M.18CF^VN)N=N5":XPLCG/"N7*L-FF!4K5@%UBM$!#HL(6,%%6#XHB8(SQ>J+ M4"-7U%2'"OA+.6Z=P3DX#?F0Q7L+1.S)[O13NL0U=06-X(&0Z]D",PC6XAJO M23.<5P5J#WYKE#%KKX7PW+W4U%)2(HL[FL9"!(P#Q5J9=99'9R,691T& [101($>Y8M]FZGI+I M6H*;Q<%$-:8(9]AFLH;S9;'5TW:7[-Q8!0<6%HXS1H[V'IHP4-UL382+[V*2& AG[IR@\>$D@,2>XYWP_?;?&H'- M!G]]D(S(2?;LVGO#9L=$>F\(OFN7DGP^)NM>3:!-=(D)QO:!-22M)P0 (Q0" M#7;;O/J)P0?,IQ&[V+%%Q&&_ME87F[5%^X2P"7ZXG/B6.61,RETSUSQJ$3D< M:FU(27K.(,::[+_$FQ'RJ &GQKT$HPHILS'*9M"X9H).U=#6P1E#-Q=G:3T) MBL:>V#@ A4OGAJW #5 GH#IW4=!=_=]10V!;QI0"3S, \50B'%20%9V A'O; MG#G 2&"T84]E.V21IZQAL@F++5=6V?DJ9S%,ZA#S91Q.6[BV.F@,NUQA/FU- M!_3.J9=%@LMX A,6^,1-EF/T*V -9[S*]XGR4 M20][GVGE>)KXDIFTJK)AL<]0U"2#QM)N68"(14JGK>J*72&J2S;.U&*(3E- VQ'5< MY9QFK5D@_$]P,-6Z)%:4YS7I8-BN\JP['.G0R<&;>>*QI^J'41N>UI,#93W^ M< P4_%$Q1B%7!3 XK=-N5]CAT,XVRI:/%UI[GW^21!7LJRS<,JS :@"H%'VG MA..3TITG\9=-I]@N95,.>\N;.9>QLYOB4/HA(V(A"K(B1L3/8V,!P!^Z$.P$ M)A0(ZAP3\?4BL*O*A -K\=_FLC/X:,J &1EA#_G E17DPVQWVD9\ '&9U9+U M(%12SO P[["-.GS'(2IXWBRVLC"F?2T6R#QJ'7;%HBI-J/XCMF/ HQ)+$3Q@ MK8MBL&-QL@E+8+FDVPRCQ )@*TX)C^ *1=:X3D/4T:8/U<8;UVO*:^HM!=5X MN7:R_E4]73N^>>C2K4Z]T[!+[?%VPN_"!Z\V/1.+@I>P] +?>4AL7RTZ;J-= M&M67V2\#I;?%/N+-)O1J.EX2UF3O454U+K/<'Z"CD5]69%PO9Q[1)AJVW1]@\6:=V=D)$JEG4<"E"9<,K&[\GPP-D: M,.C&,9I&R0SE=A,OZ20)H$W 6>4XK]SC#72'5=7$BQ&Q;VQ;1-@BEL2AAVC@? M/#&B@<#?G7/O=09ZG39$*#Y9URZ#NN^V%2]=B'A1D^.8<> L@)J+7>'HL)IK M@[5UPZ,+V2:977'=JETJ?SX6_-TLFEUL3 9,Q[ K2^]<$V!VL"N8P 7_H. Z M 1AWQ0XY=Z?GB6*QL ;-J@<1&4BR?DD(%Q6LN<5I36SB<07ZK<,YFZ%G(^.9 M5X=XG+G# F)T)P<-\48$#5-B$RS$,5A#["9A@=V!"G.!OOB.N@'!-V=W=!N8 M=IUE<_00:X([XB)2E9_5IQ)!6^#WPD8,LC#8^$%X"FS%B.#25>0;EV$.2BQR MGHASE8S I &,#O:=1PE[1CA'6#WC58_26V;X4IZ"$K$V+^VC@@W8.EX< 'Q$ M(/9]KV;IB&P)VH K?2"C@B_2V?N)3+?6!(Y:P8\[1G3J$L)@"JR4FNFM30,6 MA3 =QPHR5D?$M,+H%)W\S98B9QM7"I8.CV'6ITHC6FUN#:JWB=J<@=XYE<.\ M6?KG'#>9:(F0+=^XHGUY35*O (7,0V/%",U/!2N!^H2?ITC318.*4 QG.^/;G6 WX+?'N)[&JF#'(25% M%L!(; VB&BSD L826AR\.C?0:+72%B7\D/*Z8BUB&=YJ]GXL[[V*+U2&SC7T?0^)RSN+6:^V/X_@G=6< M#I:)QZ=DBL* =:[5'LN9,'IE\Y<=D,E>YC38?J$(+N]24W->G#+ /FT[IF_I M62HV2U"H& 1[$)>J>K$8\=1Y PFK80A0"MP7.R!(WZ_&G&?"HJ':5NMN=6%GJL5\['6/AWFI< M"5[K="AIN%A@!HQ.,M.K[U.5.H_69'AT:AE5$Q9E3$=FRSJJD5WD9DL69IKX M;[#C =%2*2:1YLGB X"!AR=G6#3:!2Y*$H5A*[DA1F@_T_*F' M:BI2J0"$0]9LQ M[ G'I((HVVR1N>2P9#O%R6J"G;P8,8J$"VT"5;G^#JV/Q)E>0N![GSOWP((% %6P9B;+P MZ$GUF-.NB65WBJV7]\]Q3J&GY2( MX#8-LMQSD_@B3E.2$<&^\P*@;EIPT()SN/(U-'J<)8P MF&\:Y+9PITV$E(8O>76HSRZ8Q9'-(JQI#MA.\X9/.F20("0G(B7"=U!(@>.H M.&JTS2X[<2'_/G9D-YNUE!Y3;):!1_#R9TR]$E_DX%[U@3#*39 M")[&('-(Y)#NUNR#NV:ISB5$GEM8!"T;L%8)0%S8TH@_B+LFJ7HJN[IW4[2F MPBL/>UCL!,%>--PZRYC!03D=ANJG!4D'RW9LLO\/ MX49PX_9MJTQ=<*Z."TLJ#_0VT3N:257M+4?YGS;LN](G["X? C=IG].BYN%J MW1D<-TRK77[8&.'9(=+'(B[>.EYBMKUC=5 JJKYWYCX7@S]EN=FTBM)QG&08 M*&8[AT2X,%KY9\=64:\Z?2>H8K*3/ZOM)7^'O@L_Q\/M&@ESM6TQV>&3;)XK MRJ1/P]0KUUU="0NE,.1A=YGUY$-*!_DU@C-Z)^M3)IGCI][PR__8J@[1:TC; MM!,'S).,^4H<8O15<52ND&.X'297Y:=W]/Q4S&VUSTJ]31NU[4LB/HV."YAH ML %IV!1]-0\4P:(KWK89<2L/O'6PI7JPZH( -GM%#Z<>P,;U\! [(B=O$B$L MVW,<#OLT';*SITTP.+FM[PZ-4K!VT!6MF2ICQ/ MZV $Z017F>VD4Z" " H@?/36KKGC0J(E%Z[W5F$-PK%6&[U8EH9#61U!L56S M#>PM94C4AU;)*=BO,;/7VNR$V=2+'ZI]222@ZS"]ILCLV3Q+Q)D'_B#8Q"S) M59R4QU.8U%Y_HE*.E5A^WM,)ZK0L3T@L@X8ZI.QT&>X;QWBVT ,8CC;EK[E. M97!JQ0G'>#C?=*@-.6% "%Y4O.9O.+8J_,[2R?!X5!/:3"(0>=$ M!Y$?YSLJ-=F.H%SWR&9?[-4.6"M[%GH<3Y2G6/5L_#X="FAGT]H.7P8G]W9N M$R?OZ*$R?*>JP3>RM C$\H](/JZ,T6'#[4YQMQT#O]@TJIKN#U<)N M=[0._H@6APCF*N#"@K+-*DUO!VB056?GVTR^*V:S]L+!4GOGJD6'40:T/0^I MLQ2PL&P M[ N M9+KQLML%S,1,F?K,'$B/-L2*>="*,Q01!RV&RMV/M+)&< M@-*K WH:>P$Y)$0UT@66(JM.M8\;5])[W9+4#R&$906'6@3&1A'L%6DBEW;P M87F5RD'!(Z]+$@$';8LA@/27ABP<=0OO^!T#!2F/#G>"Z68BS[A4K>EZ[$/* MJZJPUD-F0F:>"1::YZI42E$:V.&]3@W#CD\.<#G"B'.RN0=4SYWE7H1G<0O$&20=L),X@V)!X""H W'C18)NQ2(,U30QW*?BE$.3N:$ M#GV2(DR[PC)MFIQ^-Z^_;4W^M%46.%-O .7.&6@:0BL&T.'8$.':THEWZOK' M2W#V0]I"/IT]*@WDJCZ\!5T3UIM6J"H2PT*"?K 3,S>Z2=\X%8?^YD+P&L?( M+YIJM,=G4<9-^A=B)N7$10PZ'8UMJR M)>$D#6&WP XC&1C&R:U[*OVZ - )*'Q H'28IL=.&43 ML(W*\VFUWF9#026*R!8FV&!%4A?B=516Q#AD!\)M MZ#!!+A%$-79/#N=(U:?VD0W>T[F9#2=&IBM*R$19FU3[R/F.(T:?ZPI MT9#=WA@)NWV4?-HM*\U3-140EX1E<\I.T$SLLEJ1(U)DLH;"%;=.*Y'UCAT2FUC*6Q9YJ W^JE MJ5$36(FX)$Q!4+)B?)V!"Y*R]K$C'HJ<:Q%7@O.&T;.)C@TEZXV"WK;7<[! #PD@"P6T8BRFW)NJ1Y6+>,;YDT"&H>"!5=O_FSQ-$H+BQ(FEB4'"0*P) MFL2&LW@8_%5_>MK# ?@$XVWF;*>8I 24?]FV+#VP%2, ^^BX],SZ2GL2!H=. MB/PYPT49TBA-52=.(M[9)NM;N*X$-'@)G?NA^@PP;#;_^EM.OLRJM&WF.]A%8HGCV-F1P\G-SB[[) "C[3)]\:U8255')>;D5ZAD\Y4BPLX MR=;X,^<,9SWWM+<#SJVD*%/C9G@\FI=B_P-D6*R\X27D2S(F3;();=BN(8I* ML!3<:\":5O>W1 M"<=SE<2NB)*:8NV._> B+2#AOW9IB+&@;7ZQZ#E&-U%4D M%>2LZ_,I1!.V/QOB$HFP84$^/,PP*(*#D?N9Z;\W]U($9S3(T= M-ME,;1690*SS'327$R^V]PPI2/;@Z-C\X0#5%&UNDUJ)55"2DT,\C"L6U$2! M"$N]D8;NQ M]^7QV$V8\+O3FJP!L?0294Q=Y'>SE69Q6-H9O,,"Z)3BR1NF#'QF/3MSKGA' M#DMY[ @#=%U$%;MT@7)'2\%4)'MS)_.D06@CF'/H%&K9 MEGELR.Q,(^8:A[81TQ,:5^D]FM%8T=PV'&GFTMQDS'::2DP=.QQJJ0D\E;V05),\6EEF9/$=W.^"&$\[.8."_, A8 ,SZPJ-43& / ^%GV(-# MRSN'V(YS^;U6XII0EJ BNB2*]9S(TCLV!K\V!#/V]9 M>JTTIAG0$^1650@B2J[#-X"6JAUF.U:%V-A:\LSQC-/,UI.,4K%7+,,P.0S. M+B.F2-$"^1GDV#+K4#E$U19H+HD[WW1KLZJX-EP2]NP6=0^UPH%I( F0(T%F M1T06![%\NQPOQ(#!,0^.Z+C.MIZ,\ER!O, LXX(782,YZ^JX2;"CE) U@6G! MA=MX8F0.[)M]'#AK[):A.3>- ^X\NG&U?"<8DPDX1DP4BVT7PF3-8-XY.0YJ M[X!5O(=L$*"E$10B)]^IB=CD9+(?U<$6GB"WU';B#957M^-8Y,Z,%D(Y<$2< M SO:0?^1!2*85MHV<6,XCH40L?KTY\6"GXDJ-M_,/G#"565MQ]?7<7?*'BAQ M).U9D!KU2-$>KG:LO4.N.,2_R#DR*V:,*[&B+3D" 8&4F%F.'YDIC3JPP\E. MCT$16HO\> !V>> X3#9U B: M[3TLG7!%4IM3[FL.&D8&1\HU6;VPN&SU>5UVB2GG-CL,(V!EKT0 O)V('(3M M!/(/*B>P!Y6+/B9\A$]<.0:L'4=1IT.NK/*\D@&*FV/\E% N!LMMV>3.]%ERER:##2./(P,E M\S0-H1CI.L0"ML%B"F@3D5(-10CGS(/Q JO'-TV%]:J=U"7LY^G(B_/OM@$K MD#XH_[SWYP*))]$[)$$?; MN>9!#ESN+,B[Z@R;04?%6)X9A.)1T8.!ET^*M@U@U_CYFSFECE%5#-_CAX8"-GNW-M MCD<;DCUA-9LA,[7@5(X]O%-G^K1.3.2 39IE673,=L;D]^P,9TY'+;]9W?HD M6,&CLR-,+8 .*P=&%@ .JH,1[(@9VRY1JH0?CH7&<6E6?8[# K^49&PQQYI. MYZB&>EB6E@7"[C2;%Y/=FY,,#SCCW4 L+;W%B9M/)T$ '^0D.8^D8GOC>FX\ M4'#.,MAS'L;21V)7PT,SHT6='(+:8H%.2Q"(#Y4SF<7VT;;#H\?61'P$HR// M!!^=!XE=-MGE%YFL >($/<$A-@F?1URI$RMK,!4"C'6P2F'JR2XD'Y8LS;*E M*D&!JR,V$ (8=%S M-[^[U"%-3J79LW4D C5O94T%) 4P#0!V.>SUAE%"9FM^I]9GQ8'P1X>B=>)[ M61W.&_#];)(^?UIZC47QI3BKE<*)8#5G (9Y60XPB#;:]S%9?7(<7MYC.?(6 M%8:6>9B/)]IWK99-+E'HFQ;G9 M5-)IG<,I;UU<=UN>FD7\=>YUM"AUEMRB$@"K$@[\K*4W\/2J.^Y\=BY;KI*L M.R,P&#@C&+%I5&-#)L6EYQ:=2C2R(QZ1IF+I10E\7^-VVR0?C8TBN*+F4/!T MSA:"YH'-+4$"D9Y*0AP/[.Y:4SR"?042KF&Y(PZKCK:G!WS8X>.USD"T$WK' M%TL8RS(-\M6>-E:8][*;;C&"FT*:@COB&'FON@,X)!"5V!T,CMU* -& M3\( M]NT[-4P9@DT@3@OB8F5\ZHQ-,5D%5(N>T)(M!;YO95WLBCO5O0"+!7M)(H_8 M3,\RF@4O0Y\W3/;W:2DREE7] 5G@ 3$V1M4.=FU-Q,?9]"H)OYF>0R4PE=V! MDL#2(COGZE \;GZ6:6]Q4(XGU/!P@(/->'Y3;(,G16C))W#C5A>L$,QV(1(. MR%;<9JS2,.-X;'HA .RE@/ZH_;^KG[/00]=2FSHC%KD(D,9[D$E1-6%9B2P\RZCZUW2T@1PA_L)7,:7[5[ M@M]SYBYW4)",MH=3 OO9QXT)I(,,_.,*6,4NZ$Q;!%[NMAK$8N*'[8/E/9V( MFMQ .2R$T/N Q95?"F,!?.$:DRI;3I^8R9#MB$W 1ILWE4ZLL^5N2@2>O,/^ MJ^8$)T'YVMBTNY-#^20TJHZ&$#S+Q'Y4V_JKK%(Q"U1G^S2PYG9698",P^08 MW=46%I7>5B7F6I2.&]\16V?(.JK=U1+H':>SG/9D8:_&T0;"(DPML\Q"/+M2 M8Y*88K%A"5PWV$[7JG6(Q>XT@B&C5=.;K"]?-#IC8MD":PWJQ_@K9H1K.E9) M^)!97,XB#S2L7"<:F_=SX!2Z:\.C&5H?8B XP,@6SA8[-U<)$A1G&$+:3<7 MX-"BZ24KY*N#[P3\1[? 68MD==:$!EN[#[UQ]YQ]PHHS.FDEQRT@H(/DXFA8 ME)K#.+P4#/G1)_Y6V>[2UDDP&X Z9_5PB$ MM>-CUP.?8LB7BF 59PD(62;Y MV@M@Z#@B1P;G40<;A:##*#T;01$L@$(6.8Y4;B)* MYM%Q,*;1&2%[Y 8/4">DEX)!FMYJ#7>Q51MX9!,F07:1A"@[/\=2KR?^"N]O M1Z7E85LN9-OCRDP>XTH5 DP]H'3&3M+6>93ES>8">2-BFJXQ1#::M4!G@L-9XP/YAC^81L022DM%43L)5'88=:B_,D2V9O M/3JM,XZAS^JW80&:GP[UKZ (?)"(6Y2:DT&Q>C9Q0&?WL(K_ %JD@%RP:?CM!(Q0_K-S18&"%4=H%<^N+)H\ M7ILU#FX[R=BP.2><(J&;&F6'DIQ^[&JK)2Q38RFN+^#*K4"#!,;YT66C:&Q4,CJ_PJ_Z[<"P=NH@_N;+T1I#F4 MPJ*WJECA/."]G&-;#,5.%[]H.?!UZM* :"WD$01BZZU$!AFAP&<8CL,9?3NV M5KL 7"C@@:23S=C8PE?B(;&KSGV4$UCRA*TS@!%YF%\(2I9@91:V$HA;_^PL MP7)B'H/5:BP\_F>5E7*-6/.(;W%&2[+$2FQ S*/H3<3_YE/ZCKS:G-H :BJ9 MF/8"RX"83EO&V'.$8OQ'];?6'#=F]4'YDQ3;G98"KZ8Y?-L%"*I/HP:YE2R3'&XC#L?I%)N,*;;_ M "LE"L5$#X[/;(H327 %\IO;N&JU2]/J.DLH!05@$0QHDVHG7#'])2OT+IV] MU+L[$'RS+66?%,8<#7XI350='SKG--)2#]P=U51 U$A,9%,M MWF]=;V\ ;R99RZ40P^)P?K-L$]+1C@2\4O"%S:;DI9.IV:DB$/ [QE A@EW(^IJY:5XL# *G8'IVKG"D@Y$TF%;FW\E)EM^"3EB/O=BD2 MIDA7F1-FVS[! _OA(96T:];2Y50QCBOA6Q4.RUYN@5)@TOR 9I.IW'): !PJ M>W8.<0@8QEGA%9E2+"R>\DM[6;-(0L+H -1U[4!N%Z$D!LSS*&9UE<-Q[Z&T)>L1)3D?F=,YJC^$X MB<)G&42!!P$?'.VUE(!DE0!0_@]'Q54>P"!BAK4J4+MQP-G#-E!: M'I]L^0'=# X)X\UD!^1Q*3%5B4LXK';"IU,M!O,Y83_-11+=V!#'4N BZLSM M ]O&*GLSF'X@]-LEV#*2/QQ=W83.L_.#T@. HN2BF"Q3X3(USQF M*<^B-%3$#N" H8G3L,"$S"(,K+7$4#8N.& JXK5B5CO9J]W"CD3*'T*$B57( MF]6#M3<@U#(X@\5]8N\P:DGHE@FJ=UMKDCUZ^ \[0O"GTR%7_JBXS28%O5:* MZU%5SCX3X.Y0/?8 -E,&$F/-X^E\]6:8R-./J@*:C-P=][!=923"4*%/(E;) MRW!^AB(8:Z(Z0J]=G@\@<9N ITE5E7GK\87N3!*H:E\21LG^;=4.'/\@N#I9 M?36[V!J.4,=!TC.\<.B.I$C#0L!7@-SR(4ZMDT=HUVVW2VF6J=_=4'GP30KZ M,Q,.[5WG8!MTT0[-$4[UTH_\I"Z4ASTZJ[/OQF#59'VS+TMI%)S)Y)BFU'-- MFL%FB)N'QG>:K&3;BQX(D/115K*B$;=D_GW&9+1&D>UXV%7[E.^V%0RK,*!P MHB6V'C"YLT1IQFRJ5?4 7X5'&Z$GIRXGC*GQD4,O"ZE#Z6/ MQSHDQT8=(W-PAV,IG]%Y7"2AXR&'Z M!G:XH\R<=NM!B]0AHN M0[&"8R/VZ?@:F')QZ4ZI^QRCOJB"L=6;.=9TNYWM4:IV(%@)PB=9F]@' M&]7MRBECQ(.%BLANJI-"!K:*&[FEUN:5,_-9O=G)3[QC)&U:3EOV !ULJ9 ML!,4-!^B742M:],^@T Y$J_80&9!7$+V">,( M* *@19-.SJFH\@Z",@3ALC 5\]@!D4T;JSPGK7%SC("%K MMHN!V+2J$&"[F\RKVXX+]\2 '.QG6,K2=65ZVG4WD6(N"^P"LB.4DW729C;# MHXM& 2=Q#'8(;2ETF+\&;H60'SA[8IRRY/Y->LY3"6N070<\?)KP?AIB!4CS M+5@WR4D![ILL\C;/. O39O&)JCB=ET6B[T,V5S.9"LYP =Q6E*)HW ?%"VPV M!E/;86?RF@ :R%12EU2SX#ENK)_2DIG5FN5J;K)B;NPM+)Z]QH'MAU5W=C'V#'/'(\)W M (8M#LJ*T9OUU-TYG1OKNNQ3Y\Z54]%@7&4=,P)!G3(!S.IX#W' :B>N65@L MG"-X6>*;2 AA6;U4%8;9&(IF31@-Z7(E]62!OZ*@-11EH$_%%2SMV/!HL5]E4'#G:L_49FQC ML0;3&#H@88OPZ.S8W>4X,ID_+IEP0E#I2$&0/H [3+.S7FU0>M!9^$W^?+E* MY-=VF"C*J#*)2D#CFVP0BZF%0"B6S'@$Z47,U.#W>;J85P"RU7XKA)UN2OGQ MT3H@L$DB, (FYQ_ER,;0JJ 1'?HY,\A/[(@SL36>\Z]PP,!J;%V_!$\[FTT1 M"2AW$@LG1EE7X);1BAGQ/!IY$%7;.B N2U8J0I]S+.,VV.>GW.,XC[,EB$T' MA<=8^G%=-P\>L.@(LO[/*K_&'4"Q.\XQ$\;V(LH^"5W.X1CM8@Q=8'RSA,$> MSH2_N+Y%BOB5\SJ#1V9";6(9G,2Z%H,:_'QT@Z2@K>0*4AQ4IW!>8E-]PE%5 M4PER/CFEG!R#P*':Z=?&H#: I3 UF*H"JJ/8"9=W]+)#&RR\2#\)[E0RMPM+ MM[.3)<5-K(O1(QQ0L:QLNV3T@ %VM=3R :.W6)PF6C6N'!29!*3RZ!PJLF>( M[5S7T>D''M$I+>F17L3?)=YR/"+C/O?<.W2Q M\C%*=+,E3A1WO!=.FZ6J:M]*-)2&20FLWPR /(9L$[_3>6U6?HP; M6^4/. ZMC/,U/2N?HH=9Y;JLI$Y4**UGVY;8LQ93,F$YL,R;(H6C)"+1B;\3 MT+L3!VXCA@^SIZ3R16F)F#0XR3=C*(!?+9SJ_Q%]REO*&]EG4EZ8G5]V)1[5 M?;3'SKJ*? ZV4A3'DS'E&"[>NH?.4<8S9R\>E8UB\R!A_S+,Q-!L33NX;.A: MB?T47LZF.!R;:;4+4#N!W)M=V5T)Y"P#GO7Q.7*88B>8F(]!'BFS+/B(3C9N M(%9=$55UHK3L^+TI&*T2=[:+),GAC[TAE[/89ZUQ>CAA@A^IN8D6Y(N93.+G MR4EE0AO[)7"+0"NU<*52P*'PK9*-+)8N]=^%@-(.(Z#=$ D^=[F)@"K M[9) MUR)+.V:O%\)VQP\P[5BIAO_EHA7)V_O,*7'V@K,V)VNQ;G";@R@E>I^=.,:V MKK,ME^,!8 AE;-,R<^XX"2 O8-FI\C7[?)(PU6[R:#FE/_#!5K8-5,K%'"Z MW1;L3PR]E7?7FH>0]MZT?AZR9*XF<8!VQK5"#M8NVWNWM,&)A+GK0^ <04G; M?LJ#>>JO%*1U_F6U9X/EC)*8+GM1MR9W;L06-,@E2 NWUT%-;\T!('6?);7# M%%^T*)2WDB_#R[#)=)$O8%)2K9DZQYO;AJLZ&]&:UK8.YOZE!#2H:6K "U2M M&LG*(,$_QI3H?=-7$21.15&E:NIBK?@R,$IP5 VST_*@KG*QJ])120+SU:'^ M"CBS$W;!IN%$)K6]<^K2#:=TM8Z-8@=Q3&",G4AC<[IG'1PW)-ID0X?4C$P2TU1/)Z'$, RP%^V7Y):"F_ MS"3A;Y36QZ9L.79P6STZ'$_579S[P!@V\\))8JTSFBP:\T"XM/>AD7: 2QW4 MWC9GQ!=U"/M,';O=(:7J@)SR&J>,)$=/PJR]645UUVT$= R.CMK!KUKRF>5: MBIZCF58;8\YXRB9""M6 M,;>$NFK"R&4DF30/U(T&#)R:$GZ$N@%?ODF7ZK!05;G+(VS9(TGN%NO8R3@ M1W@FD, L6]"(^;!I#Q/@PYSLME.'MYH;L+7 ?*$\'*PP5S^$C=.].&,PXWL6 MD25;/\MC(@47Z.O,DF\#QU>'[)P=P-.I=-%4WE&J3CZ9E) M@8+M98!B*354W$LF;MF $\'=9"OK:B9C5-E#I=IYZ\(]W.:)"5*[L/%T./]$ M!-E]D)1>FJ#+DVZQ+B)=GLE),U[;#W M]*?XQ=J^10\UF7@81&*[5)FM,W:Z^8M26T0NYCAZX!;6XRR#T8+A5Y32'WO8 MY]C9=T?RW/5FI!UKT2O*'#^3"6S0UENV^+HI3_RTVO?>9!D+S5L*Y=3E3.V=@LY:I00."I[%S8),U;^,O#U3PXFEUQ3^U:.7$) M=/ %$M%'&:]MA;6SE"!NWE488_5!18I5++:*.P#C< N0:9#G+( $SHN@URR_ M/<88_ZOB3U3?=G7BNMK*.1)D1M.*BOU8.\)_)5T"6&--KAT?&'F/=>]3 M/@.>K\4+PS&5]O#1&/!11@:R:1*=[1RV3TY"V)F%/ZIE/@LK5YJNL7 /KN)<.]HH$=V:QS$4K,GU. M1H!5@>N:HE7EW5E +*,T5W?G @SD8CB8N=^G0B7$[5,CC$%X.,\W;Z+^K(Y4X*#O*Q M%+Q:6)78.51)U3;S8#(X*3#%T35[[*RL"KR!*P.Q@B&J+DZI\((%!-\2\A0G M7U6@30ZV8RMG"\^6,':VPZH$C=Z9;:JT:L]>SVR"_S,38[H63F2K.84RKHC'CD*MRH?(XJ_5<"''RH)*LB>"N5]+L*%&F%Y/MI)": M(+80;,U9-[L=Y/S:Q31-4M->)Y3/9]J12PIX3%RQWI"ASPYR66T7T-9";L5\<0LX624I&#[9K I ML=)H(4#A]NJ0&G%*FSDB_(Y:&JR8-!?9ZL(P]B1_'$52GH.ZFRS0#2D$M.T. MWS@CX)=,,D:R+3>9W5>I656-'1V03NVLX\#2$RY:N @6*4:U&T &SGT ) Y> MEX0XL\G4G>!QJ-5$+&K[FF.^3KTM%FHV%1O7T?0=QX_G%/"QV%V"1FU!XZ0Y M.4LL(1UU;T!6$X:#O]O!=<-B&W]V^7-S7IK>K??9A$"%BBARFL^].G5/Y'&K 3/1.#7DP M=3^'4IZ',EOJS6T2%2XQ)K4>0,PXQ^@8A,S,T=8 ,[A Q1-S9:/#ICGO_;?< M1=>WE!8\AHX6UF!GCUTD2 MS5&97.$J,:BSO,TF%7R@[0&K\>IPRH0PLJN+& ZP2+AFCI-OVQ3V4[#MD)Y@ MPZ5@W-E/Q*%'%=J/*O\XD6-C'@;,3M]-4;^"$QU7]P4;#."QJ/YIQZS*:E.) M&MR9SP>:JA/*K6Q. QSX/O.+\@Q. XZV$E'>#-(LK@X &8[&>@F1AN!Y"SBTJNS!8!I/('* M$$T%@5B('^9N68'ZJQ+C-L.= M:-GFE!5X8HY9F?33@?NR^O'G4&1^-^;":)J[VD2^TM\ C[.01.QDQZ=%2C:( M H*IB3XVZ7TL[30JKL$'(52_[)(\9UXY5:JO9H MF^7E++@=E#+9[-R=CK"/,U>6YWD\02B$VAZ/0V4+'GHO:;")^"2 I3H8)\X> M?(/+VNU;/F0*([[9'$C8,-YQB$JQX]3[H)>)PR!+8;V,88>=B/_4/F#>Y'&9 M^61" $Z, K6SYQ] ,SL9G,)&\*IXAX;4?C8U?L)LC@6//>;..:#*F1K!7%3O M/,LL%DLA(T:06JYX6H :81XDMU:ZRA9(*6^F9HW<$H1KK"A:Z>W:++,]A7:! M8F*,[D\&&+&7V*\K5:OS!Q8%[56"V"AXZ@:%4@>>B M::Z*[&VC@"Y8,R(6.=*@56,[RQS7S )X8)0]Q3CT/<9F"I[0:OT3:+P466Y' MB]R$I6 E9X#SXJ)/ ]NU]TS/4A%4.YF=@YK4EP5=;%TYG.AJFE5M.^R,X8B/ M]C%;,E<3-UOS:"'A ZPX=@F=L^MR@:A.PC)BEU!74[N\L#G5SS/)UC;'8*_5 MIMKS6!4$ +$4*=Z+1-06*SEBEE"5#NS5!YL!DP=.L2G5TG$N%J8;&+38^QYE M@5;5:AF[])Q"VC@4]J"4NH!OHVO@\L+^J6H;GCAT,%23#54.K+)OTZ5+L;<* M+D",I7?J+_818 =!0>+CP[ ,) (:93^3(I@]AV63P*H$DL=U MY.]!/9N-:$?7J2P#\%MIZ\PJ NUMNAQ!S@XQG&S*C1OJRC/FM9(D6CM M![J M=3OO9[]HC9W'IS9.@&1#:H,F1=-VM[VJMQGX-9N773A[,G781VB1=[M,(;)% MP?FG!1F'!S ?DG?+CV)QTKK2!K#@,9O&G*3%X!G9M5S/L3<26AEL,C\ZDV?K MVZH6+%:+U3MM !O4NL%/ILIFX'XO(R<8C:059FE0S$ U;K7O.N_G9= MIJS*Y"C'G2U''&2EO+A]\[.[M\]^W_SVVW=??'OW=OCES3_NM\_>7WWMWU]] M>??-[[ZY??/\&W[IZOF';Z]>W;QY\?[E5;BZ?O[\ZOGW;_Q=N.)=-[^]^O+\ M\7[UYN8J#O<__Z;RXO6;Y[][?O/-[W_W[=MOK_C?[V^_N7GU[N;W MW[R]NW[UZJN/GS%>35<_"E=W;U^]&FY^>_.,%VY^^^SE5?GXZM5__OG-N[>O M/KR_??OFZM$?G]_^^NKUAU=\U0M^9_QO7_[DYOW=[;-W0_]UOOG1%5\=;YZ] M?7[[YL7O+G_)O;W_[MN;JR]OW[R_>7%SUW]X<_/Q4KGC=Q^^'GS;R$/PY=__ M[JN/-_ ['^I/KODRK_[%S?M^*???_N@5;W[XY*:_?]/':[UZ]N'N[N;-^WZE M-V^>^SM?Q?LG\^COAON_NWUSTQ.)_.+JV=MW_3IY@+]?K[[L?^VM_2[? M7X!/EY6_?,CQV_7U]^^:+Y[^^?3K\?]Z]9[.S M!:^O<+-?@2&NOO_?_4]?/?JA_[N_;8C]SZG_^Y,_3_T_>?KJ=[\/Z2J.\Q?) M[JAV]>7VDU_^,L3ACIL\O^;[YJ]X=8I7.?=__'Q^*I.OM73%]<>O^!<_Q:]* M&/R[D?>4S.]^U5^=YZOIJ]S_-/+]E;_F[Z>K1_\,9;I\3+^B6'T47UR.NE>T M_F.(5_V*GO&IQ8_UL_TR_ND7U/^5O_KD1__[_9OY_(^_]O"VJ3\ [BFT+QK_ ME^>/#^#R=<_YNOS5[#W. M_L =LWOX4I_@E%T1]E,>/K[,-?D!];(]^%,:_;3$]\S^,O=:'JYU<&U^',;+ MVKRX"KE]%7DP;N"O4NO;*OMK<;PJC5]FO>JCW_W)C^?+KV+GR_P5>SEG;_+A MG['_TB=?>/SCQR^\[:>!)Y/K93'ZNO4G$'QFT5O*(\_$:_DJ>50X,OQ*O9J: MQX/U^XKMD_Q3] WLQ-8W)D_D?G7Z[;#%J@+E4E7]YLE#J7OF_Y2OIB<3S?@WWV\ MKU=YOSE_WS1W\K?/SW/B9 M7WG816_Z95>O59O6[W0:AXM_T7@E_[G\Z,:9^OGIK\1^0"ZO:RD(/:>K;AB[ MX;G?=1X@34XM5Q<_@ WV4[2XG+VIZ#KF27/..1S[.SC^^K-%]=7NY;J?3++OVQM:]:MSB3/W>C M,^-LOFKAZJ--XD+3U9Q\Y"SH'+7.]?ZS^G\__C/TU^*]4\KYTWM8O[>;WW[O M5'20 W;6/R1M_>4?/CAUA\&7LL(N7+R\HS](?S,-_=^^TK1U4;O-S\4;+GU] M@_"BFV:>?^E>M?EEKFK50-6K/_%/\"OCY+=W$T44/)='$.3G[7(S_\RF+E]= MKKL;2_'.X_=-EY6[N[ROZ#7OWS=-7ZB=,G63^O-Z^;QW_>%X?Z GK_71%?%3 M;KY6@RL:?=:7U_QR;AY#DNY? 6SQA[F;8\^R"RCR2CX5#732$;6K_H_VN&F/ MY\O-W!>G">@T%M/%R8:<_R!8^W!!3VQ++V+N M9U( !2KJ/W*A_#L$0%/WE>/EO[S,'PLNZBL7KK\/O]4=[IPZ@G7K5N^0*PO5 MWYBF>X]Z 9##I]?T\] ]_V-$_NKMBX_1(MC\P[?\<-Y?8G?>^[/K;V_N?G'[+[S[[V[>O[^YNX]"/W[6SZY?\%?8FR$0)WUM MH-7-:F7S7E^='Y[\P],?<>-?/[F[_O;;I^^?W-P]Y01]_>2G7S^=^<\_W3Q[ M_^XIV^+K)\133U\\^<7;5[\FPG@:1L_OB&WZ[LDUK_\=<=)U?\-W[][?O.8/ M;[_A7\<_?[CV\M\]Q9^J+ :*^^[)AW=^Q(NK\_V37_SLIS_]N^,7_O#A2?PB M/)5%A@/ =OWNZGSW9'MU\^NGKY_O7QV=_W-^Z>3WSZS@M\]6=\^ M???DQ@^\>?*+E]=W-\^]BIN[7]\^NWGW]/;)_W+W]L.W3T-K!;,4^L?>/0E/ M8V;A'K[G9WX)C^_I-T]^\8P_\T'O_^6IDYW#_?=LOUA^SM]N;^^^Y0L)+KVO MITF']/"Y\6DHNLL1E]4_]^_?\F']#E[SKZ^]U+NG+Y^$^:^Y7"ZJG-#\ M@'_FP@1%N?F55^>W7->/)M;A"^[?5?F">^.&WSSY+9<2<\K37S_%^G[]Y"?7 MMZ^>/G_RB_=OO^6#Y[_[40Q__73X%0_B^OW[5S=_S>_]P^6CKM^]Y&&]]]I= MZ.:,PA=/)__\RY>W[RX/^N[F'O^.RWWU@D]QQ\^]YRC=/ M;M_PE]_RI/BKKWG/=[SV_N7-TW$H8W9G[+RX_/S^'I:G^.FO>8!O>/7]W?6S M]T__Z?*.]9=3^E$K/]I^-(886;/K-\^?/A_Z9WWS9'^[\_E_>_O"2_D9[[^Y M8R^^OG[S[(:W;F]??\L)8?F_>?*3MUS<\YN[-[?_W[6S[LUW[O%WVQ M9#F]+%9TL3 E,5\6*SJ!^A17^S47???V_>F+^] M??7JG:]L"V]IG(_PQ5/,_<=EZ(?R#RW#BT^7X9M'R_#B?AF^N3R[ES]8@/K9 M NC$P5S?_<%UZ#O!I;CY,U;BY0]68OAD*6Z_7XEO/J[$B[X$WWR^!.R>/,Y< MTZ.5B.[^S];BVZN;MX]-'/B!?W<3-Q.GAAECBXE[^V3Y^MW'NPWMLE9O>,@W M_7$,O.&1$7KSY-7MUW?7=R[;N_?]NV%R\\M/+"U\_ M+??6LG_HU],?M2OGRWSW]=N#EB[E\Z2O'Y8WWEO+^BRZO86S[4^;X M3ZS%C_ET#SO;X^;);^YNL?<^6-;_F[Y"+YYLW&,K>\%RO;M]\8:5=,V_>?+LVC^_N[\&OO'NYOH5K^@'AB?/ M6.U7-[_EYU>7>_GFR;MN^MV@M_TW;^YNKU_]-7_QF@_X\.K][?N7?,1SO@M7 M;'#P7?\F_H#]^MF/^;U^,;^^O7O[YO7ENMY]<;%2WGGFTI]=]N[U+1[%>[Z[ M\:[??GOQ,2^>O'_KCW?/NR'WD=P^>6W:$%?P-WP2G_#Z]LUMOY[7?"*?_/SF M!1_B5;ZX>7-S=_T*7^K=O[EYYU/A<480]W=/GM^^>\=SZS;?M?;*7WY_9_=_ MA1V-W8[>7!;LXW?[#*[[R=10WCWQHM]]]_IU3TG^-1?YMS=WK]W<;WC,;K;A MR1MNZ.,[^%BMP<_ZSG_;CUB_!O'G[Z@:#W/?1\.2;#V_Z'5U__/UO=.@O[[?9PQGI M'_KUW=OKY[J8B]$Q)_ZFVP&VR8>[R_;YN)\NM\^%O+^Y^99?Z6?K_A=O^P%_ MQ:L?WKGIL[L5MR42N?%.2[_4;S6+?1]<=G&W?^]?]DOY]MK;Z\O_[NWK&R_A MO_[7WW1PX\O_=[?'PV%]QX.Z?,#M_9U]W+0W+NWPZ:Z]'(P7?W2O]ONX?L]G MW5R_TX[%*6M;_>3N^K!";][=7C9*NCCJ/6;!O[M_^]NGPLL.7_X='Y.^OM8::C(_OZ\_W M?C/,LUBG&T7 =2]SYS![6HYN1:Q_$]=/;X6$CW'#,Q&/_K_X, MW4_O7W8(>'E@+S$MSS]#3!X]]<_U,T]-WS4_OL MPZN.=]_<>)#Z^;SX;9_+\SM/^V^^OM9U_TH\SNPX_W>?>&G7-R.8,EAK/L]_/)B65DX MS@7_S0/R?\<^S^&3\\SE7G_+JCD8Y.W.4O/$7\[83K M_LY]'9[.6K(?OP$\O[\3Z;-/+D8XCC[SY-MK-X"1]_(*D<_%0@9^$>3_\AZ\ MW+NIE_=NZJE,J;R]]'T?S&!W7& ,4HUWN##VBM_&AW4SH?VZ.E]Q-=_^Y/UO MGS[O'OJ1YY_\-:Q6Z,?IY1/!^A=\\^7/G__W3_W=\&_]Q4_^;O!0=SMSN0.K_[8'0[Y#9PY"?/EJZ_OZ+>>P!R6O?%8@%E-6/0>K'X"%H^.W'QF)KX^RB',S;@$RY@ M__;3 _$7/8[_L#W4TJ-;G#J&2!\/P<W MQNY\^62]?L>F[(;KT?7-^>K/N;[_+@;J3]_8\/V-$?O7RYJQ+5]BI P] 3Z? MW]L_]0TX_)M.T^>O#?_67_SL[X9/;^IAM61+N;^IQ!M^UL/["]Q@7PV?W%B] M7[2__'#]AUC:/_DP+OXI3N7^GC)OZ%E6S,>G-S.-?]8._ .O_<=;AG_] M:,V7&TNUW1^MPAO.2U#0$=YGN_#I5/_D[0U_[F7^*W_W9UF'?_V W=]>"1_W MXN2Z?4QJ?'9K^9)K??;9I_U@C_V;[FWX#W@HWU_-Q[4#H,^7W/';)_DS;/"3 M3Z+7"T08/H4(5W\&1%#!RR=YP5FI>JKU"?G/A@B7T/J' ?4WCS##B^\A0XU_ M:G_]13O\7]\>[7)3;3)0SW\<%/SDEX]@P>TC6/!/PP^O]7^0[1$OB">/M?6; M^^. X'[5;X=_%1'P'&+^ 2:8TY_"!/]A[O1R5[&?:#NG+W?U"188_BU8X ^\ M]G^ )?YX8W977&[LS\ "?QI9_T>5IO%^M/X %KC[# O^# M ^V8+_=4ZL<=^!@+7'V&!?Z[HN5_]>_^F'>^W-@%N.6YEU_R(RPP_&$L\.Z2 M<_OS[^\/H>Y_R^(,?_EF_/[^AES3Q\WX)\ UN/_3$ G3A;SQG2?."N?8X&> ML_X+D@0O/DD2- UIG+L_*8%-W1% ^',0/P?+^_7]WL:+_=V*:>6_Q@ P&/X P@@MO]^""#%IZ'%=E6F M(FH+GV6:XU4>XE7JF>;:.XJNYHQ5N_KU50MC__GZ<1O>+3&>7__?;K\4=*^IUCL\7AYZ?'XEF X],;ZJ__<+^8W/=5\"4W:>%D< MKJ#I^OY=:8V/?_X_UM"F?FM#L2VFW]J_"\G\CY&J21O?\'#?/-W1?/NL?R[___%P2S/'WQL1+R&+>\^+[G2%8GGYP)$_4L[!M\ M6M@/GWWT3W[IAY>'#[^Z?/BGJ91/ON.AQ4S)(=Z?>TUR2OJF[6F9?G#]N- O MGKY]\JR[B<^_J..TAX]_^?#IM??^E/'IM\-C=Y>NRI#P;A\+JZD75O_IR?;R M^ENMTN36#OV^V0G?67/]L277X>M>4>WEZON:JOU1Z;X_ZJ=O[G?2LX_-6N^O MW_V*A;*@=E\\?]P[]],FW%_/L&HF]Z??NS;B'/4B]PWWS?*?KBZKQ] MLORCI;DW3_[?O3W(5_[+!7U]<:FP7_#9QQ:;W_:VI\NEWXI&TP6@W IA7EW? M]2ZH2U[KW;WSWO-T&_6A'^L&$:7ZF-; MKDU@MT_^L;=E^8;?W+YZ=7G'R^N/N$ 4]>92/1<#O^T]$\_X@-=O>GO3<'\W M'NWO&X:X'ZN;WWWL&^IK_[%UJ#=BV2G"A][W87'^NI_YOELF]:X2+^<;NZ:\ MFX>>J&?VI]P\^#OV9O;A_8#PBEN+NQAZ8RR-Z]O;#*Y_(]ZT[#YU+ MWSQT+OWUT\%FJ=Y:R97=?-;!U$M3J=3[[I*^B/]U#/GNG<^TM#S'P9U]4C M(QN08@[3_;5630C^+/V-[A6!S57_;BR>_9 W&\?O?LY_BW:7+ MZ]IK8)^]_=53R;[KDRZ)O^ZU7.S.=T]NO[CYXJ\OV.!_;^_- MF]PXLCS!__U38-EF50 [R8H3AWHT:RP=4S3391)+)6U15H9,1 0B$PGD $A) M[!Y]]_5WN3_WB$ B*58UN;9M,UEB9KB'AQ_/W_G[+6LXI_G"#@J&RJ/,9U-\ M5@:)L6EX)V?#8!(,]2[)N)CKLQZ_'D/V8#O^ZP0XL P0,\DGI"4D\'.OV_&_ MLZQKQR\AW1M^]7I"C3^=[.&%TM?+2M[7=_=86T!]B MA?DB^!+9:2H'[O7DPJJ!\#*#'6<+J^_Z@?_%;F?(LQX:N D'/GK4P T/'/B5 MHA6 0I^>@4,FVA06T6U^&/^*MKV\^ N4 _3BYLR1)FZD6<]((*YF.%C.];Q129X7?&$TW11/ M*\E,-E](GMSUV/YE1U?&$5,:6Y>)JL66$[1X4\II34LH$)O/$K>4)=1I8?>\ MZ8PL1S [?@E9MCRGP@T4KDF8U[P.IWJ-2>1+3$C#S["S@W(2IXIR?&NXF.T$ ME]6O[:7/ <7$7DRUI*_5MS$*/'O9K.VNVMA-LAGO)AMC.[?_M;Q;OZ&49LAV M?6UO'OO":KP"5XI5!<25 AO6OO!PA*=^H;RVRPWFDI-CJ>8Y8%4!TM/0?#XN M;W!C8GK2W69Y59%$@5VUDHO+V,L?_NNJA9U#N8J8Z0P9?W#1XIAU*BY(#[H1*(FV MHNP]EX3-XZXQ2Q"TCO&]Y&72O;R[QQU"BAHYVY;-MCW>KRI8*U2QZ/?^9$(W MD#M+Q[Z68[\.!,_S2;G@%;:SG>'(P\P_=/V$R;W5KY!N7]N%I@0\2$'U^D#W)@A(F$,[W2N>CW6PQTASR:KC7-H!JTH#H1/-6)/1[4"9WJ-$V3Z(GYPO@G?IA)\>V MT"(KH Q0O2<#ZTI_QU3V49&)IKL870;:FQW,G)Z";-H#/8!3*AO*"5(#DA32 M\@%G% [^SJXJ%*'8CX?WJH$LYOP03]-???'#8[U>KQ$.>#NZ!6>R=89#73CM+>M%;J< M>[T#A[/7MDD5MX]4$\G GQ;^[,]QT#20(UM?< :>X5<_P^-0T_!H= V+Q!.% M(/;D/IA3CS8)N:7Q6U!NPT@)*X<^S:PY(3Q?2 C$^79&)QWN%WW3/@R(YS@GADOQNT'9D4^!G*R&L3H3W M[J&U$R8W3DVB;DDV"AG3B2DP;$-U @MO%SW#I:AY*7 S./,.9U]-"HX5JV'@ M_;_0G7L']_ >;R?)XS5!X0.G?/_"9NHO^QV6%7@3/Z@XP.HD5@TZE0?)J$AS MULY%U4!#V-LE6$'I"A">4WW9GRNJ^]J"@,8&OV E2LL;_T0% NC#[?9POX%B M"-G(G/6.!Q>J;K9\\ZH;<%79\PVU=W;FLYPK--Y V2$4"=2N2& B!2WJ"@_* M8.B.-O1U6#8@K[BB2D2Y&>B7JFZ@BM/1K61 *> 7&#YTO;MSB[OD\4!E"28) MV'&KR;D1EY\98\T:FOXD+>!(K4"G /]+0WMXX]<6#ZRX@'# :[$1@@H1OE_( M)T";KD8QUV"L#Q.H&KCZ04!@#1&L00/K2=M=CFA1Y*74;%RAE&JDZ )K1[85 MB ]ZKY'*E*+$# +1-+'U'P]TH#96V<+1KUT(L2)9N@D*,*-S0^*V'"X&P3=BS;SR';#2H2H.XG8'DNPH@7DJ9][W"%@/XK;JS -\ M-#965S 6Z+7A[5D'N\G^,R.;MDPPGX7]Z"B*O1A;8_TW^#&C*YZV'O[!WN6K MU9Y^?;BS9XVKUD/G.?HYI6,Q<+2WU+A3!'*$/ '+%>SZPWH)9CZ6<.-8:3S= MMSJ?:C8:]CG8B_78@BL ODR_LO&O-/85&S3OTA97$Z.#?H>UAKQ"2V4LYS6 LK;WM9H7T9G=)-15@()MU:"%3.:_H5;"C M7;#G.6K2X.#'N A)\0'=ZL()Y#+'<>++,'2M7K>6ZF?8Q&S!KT.M%[WB4\-> M>G%\BN-ZZAS7+?A7K#RYO$>+5V9NB3[J7T!&[_8WI)KB4!H]#E(]X,_VZCBX@$0I $7I""C ^M:M^(Z!"&$_@O:?F LIO$ZR#E22FN128@^ZO3/0F[H'822W M_PH#='R)K=7MMMMSF?;?2&.AC#"JI=WA1.)WKD#[)R'&>T\JXNRW^]X0-<=> ML\ G 3=X!>K9S(46G2Y"R5BX Y=W:^V[$W7L@OK)R&D<]4/@!]@)Q?JPFPNJ MZ\0=N'.?#36<+NLS) MQM4+8-^<3%R),UW*J TWQL8K !C?*6I=G2GH-TCL.75Z"(W=]O)XRXL-K=MEO> M9I=\P()KB^]!XR7>A>BPZ\!=4'D@'HGHDDOAZJJZ.X*+VDIZN&2X>L?VC8-1 MY> 0XDM;>VAVI3 Q6C/4CBJ1#K'^1(1"$WRD7>/ D-M)- M3?@K*?_.]^/&W9. :G='F&-A!;,I1U.?8U'VY%ADE&.14XZ%E*'/YE2&+M/( M=G\E^0^(2<-^DZ_O[/7XO2!?40]:@9D#0!@)?*+7 M:% \H!G>L@Z/YP#5CK7*C9B'(4-Y:TOQJX;/Y1N7Y %J^)T].$!"J@4.S\%57'O8$KK+(+YP.&+YN+[IK!PK EF[5L70+\21:,W&W M61TB88#!FXK\AMZ*8*N5@M^N1NZ"Z>?'XWC/A6&'U)(XB;@<[6\"[S( M:SJ?&, 5@8N^P\:=,U _!P+L(@IROGI1A=1>RMIY*1.39PEE($#PG@ N&;*0QJS1M[55\=T19KM^3!&Z,RK@<,P=0$ M\EUXW!=T,'84? ;QUZ)N)M8H6*RPW/>'X^[6>Q%KP]K7<\K.(M-A)DH(2LN: M':!@M?"W*TL'S(ZL+\._0!MMN5M5XVE#NTI+24>OR?%?S7[MDE!,D.D*C"L%5D68P_PM)&6;ZP>\A@X-N4/5XT_\LFJ?98C:%Z-F"$O3:_[BV^Q>PD/FSK1@0;R'* M"M(Z:QX791;:3LFUA[_]]9IS.(H<%3/<+)@M(EM-98.L*LP4]5E1/NK! M3@!*SR+_ CAO5FB/@:\41O896U>D-+LEJN,EPO>OE^(?>OT:SYKT!H:ARU1[ M@A$AS%Y$M0$7"3?%-.E>Y/:57WWSY:L?[/<7,T"Q!F*,&;HF[=WZR_C//UIE M!K(/\"_? ]7%+^-OO_[;=ST3O(X6W@PL/.IL']-ZN(6ZX64P#^P:].!_3*: M^SWO^MET]N 'PC/?Q]]&O\1O^^3K+_[ZY5?^\TKW>>WC/J\*1GC!]L.CO[$5 MC16_$"K/'OI">*;SA?1+^L*_?/;]MU^K3RS<)]Z<^XD\0%!5>C[$\'/!1S\D M#C"B[A:VH8],$E;YU$1 ":!;)!O\9+F\C_)%D?KC?.PX/AMZF=6SF^6]ISL M?#"9DGQ0VW(GUHS#0U6?*TK#=Q_MABV@G_OHEXH"23"*AZ^U'Q2Q+@F(*UY9[T05,T@DE)P4>>7KUU;7 MHH2C)[ @F W8DM'"7KK0!?L\J$ MHV#3=#0WT]'L_0\V31G]1#(K3MOY<&"O MT#A BZR1LA;RE>[)^4:7H,%\;=[PP0Y"!>;U:]3,*#5UNWD#.O%KT/C;X&'# M>J2/(6 &.]6_2!C*-^#\(73,>GAB^W?C4M$%=96>]#PN- M_B]W*X:)?OOSD,[A+YFEN^ _PCJ^_^N)'5ZO-%RB?2=$745AL[)OMF;3[ M;4.;9__0[:AU076OF ?T1KE06C8H>1$;S&.I5.K M013.H*#-;OUG"/RZN4?/HKGL[)J.O7GKS*26 NI5?;]QTH7DB@'!0@YP#*%P MA&Y1Y#W7OYQD>]5G*3[#B_/M9R^^X-3XK=;1K)!/K,:Y*$M_\:1I/C7D)$-+U_M[B$]'3TH:C)HO"E?9"<'C _QB#_Y^LMOOOCL!P?] MIS0O.^@4N&NLW#%^U!F K;OKTOEF?<9J9^1NQ2NC?#,4U:BN[KFHA!Q$\G&C M\.,POR*%D_7&2I-/G(E$>@.JC$H?=[8 ")X[#/CR%G@"V^TU5!^VKG?.D(-+ MY<)'TII07$22S6YT(QJ/?UJ<3@IGUV%$^S0DRHZPGY,OP.2,9%!+ 9-&T+'; M_R2(_>4V2$"J(_\9*&EI.<=0HWLHQ0#FT]OCKR_([?#Q9,U_^\>V^@4%DKFR MIQ4*6#'#AO](X@K;[<87:$M9)>W5FSM,UG4@;TU0)!#Y?0,5Q7RNE,;B;08?USNV17C/F\ME?E-9CH5\>O[(Q;X9.5 MP,T#8R#=&V9#/K4*9"\%1R!7T6"P#0&5]V.()!S(*7)58;@&\35!5#@5M@F] MQI(T#\HOA@M:!)S&!647*P:.&8=YC1O;N(V-N7LO:W((O8$M= ^QO_:P%IWD M'KTS\LG+>V @/=J1K_4IL8H6.J0SCFYN7;#%)P!F"7X,J.?@V<$Z+CMFYVV5 M(39N\!<31OBN=PPX;4>,E9_EHF>O^:WV'Q,IGI1-95_T*?9O]]3Q\W:RLYHP M_+>=H9T]DW^XA=__:G^\ !5_)GT4N@_:F'^XI>]BT9X]%/8[D"/N\K$#3V:OH",;HLJM[J'?W^^/:)3_!M-88 M!UONFWN7];XR+$N+E8LX1-.;<2TRD MI_+F.7X!^-?:($C@XU[Z5)#FYB/-G5M%;([@>_$Z_QD.-(WYP@7NR8((_#OP M JLR8$(@^BZMX4J.OF!5G4*W%E-U2!MG*!]1WV)\4?R72!E];W MG.J-(WM"[T?Q1H<48_WL3N4 #6?,!/JT+KQJN*K)X='#S9T+4'\%>8;W>.]B M)A?55[K7X.1$=X]D+-"<0^7:E \YNV11$99J>Q813"WB4WR&LV2YN"HO3SF- M#.B[^(SH5"_^9@7[-'>_19_*IR]>O? >,>,\8I)Z BHEL6NLO?HK/@HJ!N-P M^OT6DVB@JMI@;9'4@&7==)=(+<=GOC(I&!:@ (O5JMJK'2JEF)M#*3\JV\Q[5&JM8('*G$_A(T(!)S5NL_FL M$\J+OP^>49ZM$7BV^)>X"M]_]LFKK[_]SH5?%P-?S1%_^>J6=R@')ER:WT%5 MM[>AX!*_[PI%H]NE& "7SX>(:CZ?3^,O!N6H2&:2:[=R$8:5D^?7;.JZVE%' MH0!KPCH'J+E4A0BVG[;Z1D@XAN]@:^P*&W\GYP;NN=0*.+SA-1' M7,4A6<:4P.H)]LVT$!TLH-;N#3-[2)J21(*.(&TH/>ZU"^YQ=4I$'E C<=W: (0/KL*ME/ MQZ .YIERBCB-NW5&$S_WS)Z19QAH6,RX, _2X)]<1#+/] J]VI\U[PWS4H99 ME 0GA5 Y9-X@BPF$"\.%0+(6H?G>4\S8O20Q18F#>_W:VNWVZ,"W'7=-!4Y: M;]^W &I0BZ&K84WX0C=>@XD89[A@^LU$\IZ7JQ6GL=!;./GYM6)5$Z:4 Y99 MT_F!"IY%&%*56)+5,#%UI]I4/N=-4IE TPGJ[KMEXU3 !]]$E=N>B\4EC/+9 MK)5CHK-?S*6NQ[7CG2VH= V5>8H'2!7%KEV1D>CBJVQ2@TBURP[R]Q>R",@[ M?6@Q>Q ]Q3Y[$/OD@B[,H^Q\\"=TGI*EFBC6$B>1+%.\ M[L"ZN%$YWQ"3+E. ^N9$2GN 6W"D!U%\]*W0YKYP 8^#.L6'^TO9NE*!L1Y7 M+L&4WGNMI&O-,4_A6CO":11 CH9T#I<(94=V@5$2'*?X>$D?!!-+=O$,56W, M;M1C9X4]\-UZURVT_0M,&M57N\J!%M)20D!+OK;IF/-B8TB@DT.%J1L=M#NA M)>OZJ4TC9S0F.)J-%F8VFK__3O\9*8*+A#3YG^V)H(O6F=1V2C[;0CSJ"MRZ MJ"5(4("<1Q>XX^%ZW>]^N4 Q<*3M!A.$0BQY?L0KZ_W;WB_W-8.^F MKWO[#[#.+G"?\E_M^OS])U@I]TY3(NX#OK,*WOD)G :K<&U/O1F[!G5OMW'_ M@G_0FU?\9ON+GC=/A]Z,F3_VS;^>\^8M?G3#'[U5 Z$IL%V!.R/-[1Z>S>F@ M\>S+WRH3S= %AD1XS+A"U^"3!W_V7+N'T8=\^DPP^)@^FO#M:4K6@]M0HW!# M?6N;?0:3?]S;G[*U"K?M[,R$$S$.IH%G@;W!4&&_N4=#!Y)%_F-B8+.E&0RA M;_[AY=_:U]I--[REU\9/4)WRM)GV$-/D;^("-?1)QN+M/P/Y+?@NJU]I MD]L?5GZ:$[NM;[/A/$%9CBTE[!)X-[ M\!#P#C,#DC6K?/L>W=T7Z M"8FN3X/QQ\'-/4S])YA(C<,>KSEQ&SO M@V^Z2G8G>QSA,Y:HY)*2B.;XAO3U%1DGK7QS)>CG_&6UFH,P5R1"\0@#!9#. M/<,+&7*Y5Y0>P6G5#5M)I&&W0 MH?HMS[)LE.=Y1M!(&?["?@ONX<+:DZ!IHG/%)9.AKRN=Y'F*P%'!GPS^*<6\ M@@)\45&;DC">^KJ;6S/?#R3'7XQX("7B12T8V;9\AC9ORPS"<&Y=03X5]1&% MKV#T\-2H1DS'#1G'%U+^0KGA8@*'Z)98F[9CQQ@5# O:& 61T#ARO*W=K"RD M><*ZO==@(MT(G@;M7K,E,!%Y&N^$3M4HED8L)"#,<3G3&P*F"'"1("7"0 38 ML&/X'W_^\1^0C H'C4V;?T#2 WQSW(80P)7F0U M_*(9_P\0DV :_0<^\N__#EXO^*S_LGI8:HHL[&8]OKZV+2 =,L$WX2\JV\T: M=CC\IK&_L=VPOOY?UE;*K(Z%W;37/ 1\];_CHT_Y[?:Q42'W'8J$OR=67MK' M;Z!=@[HG/$-7FQ6\H#/ ,U?X3/$\\?W0A72UN\:CP>(GW M!0T59XV^H"2)_!N.N&19!QX OP8XXBP<<9G/%F>.>$M##DUKJSXG9CY:O/^V M]1R_U]G6YTXWF)S/HV]-EU@IU:Y&"[Y9=U73^%2 M,)BS!.45_I6*F=MN?AX@UN8&1Z43]$06KCHY(D$>3D4%A1@4@82DZ9P1A_*P MXN,. CLC_/OW408@VMS!&PC.@.!MR1F/?DV.O+A+)DR5Y/+66#.RW[?(\^C- M8A+OZ!OSQ(1\+I@\E$\=6#><%4:]5 -MC7[-HIA2F_YX%^\4CG=1=!"]\:]? M*Y?[X0E_P@UYD2M,"XUB7N(3MQ^MT#:$$3XMIE':\LI#HESS#8YHTQA%L6]< M&Q$QVZY: *I&8A\C"L M]-7X"K!&*E_4;#C,.:F#W&=7H#?H8G;;GU)^ EYXS(Z':M<& 0,.KHQ5-!W4 M1U;MS^WJ'B%/]MY[.DJG**$\NCSL",&%USJAZ#37"A$C=NZ3UQZ_>25[6^IJ M3 !8[50JT' !J(53(4@SY=?3(KDD.I)EKHR,E+RY!"YA(W&2PU'RL'QH%"J$ M8V)[4/(/H/*!5OYBKX%"@OIHC.J8=([#AZ@R MA;$ZX@KXJ_$I/F< MB29&$SA"H%)^7DKQ9=9??&E\\:6FD8_++S.$YY5K *KU@L+5*ZH"W^TI.4#2 M8#L1 D(8\)6*IBRXJJ"0N"WLCYK2E*2V=;]?B5*(#.;+H\*#>3NAG M;"Q""MH\B&_,1F'Q"T@F_F.0>CR/@H_M41+Z$/1ZTKB2\!#@:!"&9^*Q<;R] MHF W(%,"P.IQN +A1L!+L.\Y%O2KQ'$TO@[;.!1PF8^X^%47)*]5'B8>WM,% MW;A]9C/6C,"9D6/T^XB9>I@B"/Z(U05[:U:X"N0Y6;//!([154K.LZN,%8IL MC@E5[L4I'D;PP$B.:^O^Z$P.T:\873XQ/N?8H>&M>7@XS$Q< MTYA;DTZU+[)VZL^,V6'L2Q@8'O8[5S'51F=JVSL\S:@G/OJ87$Z%BGN:?9_6 M;0]J^+#D=:M<$VLN3SL9/V$]-'XR73!8>RO.H)7/R'8I>A2%Y1M@K&L N$PHD( -YC# M?=]"?&PDBY1GQ&O-[BNC(RN)Y)M+J5P*N6D M<1<:AM'E*@KO$\G'*OL GDAK-E%%4^?\.86 PM*"&'R3>#^@WT#Y0>8_Z:2ED)IVLG% M0IDLR0W.;>D_'5/4@R3%_8-!#!;-AQP2RNT0;'_[+_L)[KJ8"%_'I/8*0YH*6INH1&!U-7,5\ M$E9.4VB-Y#E6[NI/P@JI+>WP%EU6'[G_#SX!K,[#/7GMW)^X:U, M7S9[Z0^8Z$)93S.$.7CL(."@MFX0+0U"X_I(F"'*/]\S< JF?>-UYTLYN.7_ M4^T5:'!8$.@QG #GQF5>AD?E;I1G\Y2^C%-5_]/V^=H9GEP&R"EA KT >,$X M%U=6EP7\/BZ\ 3>K0)LLB42$T3$(,MXPWV)0,-'F3!^"D0!6S\M2/( M%&LBL"*.4J0Y""#,6>A^6B\QN&K@-"V#[.'M4H%8S]"S.9:DC^/Z_WNOEGC)#)=Z#J(E0"J+M6: M22@6I+4[\_9TO+1C 'J]ROXXJ."*&_ ?. M"5 S=I?=;K>3GOHDNS]GO&=X)E/LX*G,(*H@8 Y,L:04UB.;PJAIA7"/R29Y M2JN$YLE3WBDU-I[/9MJ4T'N12IJ?SM1'_=MHYUQ0]064II-.7(6N7_0EG8P M3S\NSN&#S!*>KX>MS!7U_:ST%U)=Y2#3;@A M#:9&$J0UQ._0CJ*6J"]?C?[3I^BXB>W@R8 CT+$ M^E:]VE>N8*L)"G&,# ;W8A7MQ;0L,V\%%T22<95B ,M.7[A_[$M@G>U[[+JH M-0]6:%IFG$$CO6746V<303?2)2:JJ,@!=FDN)7UF7DC*@$/8)V(;ET@+/E6K MW1$:N;C7>+K,R?E"'%!QE^$^VH/#K]+*=(MZBJE[[#HV#>-HN.P'IHT G-"L M<^QM8_)%2:S!?!I2]1@.T@L!W'PTM;!9Q.] X$1^N2##C3-_8%:-4CV[ MG8 D^0,.Q->O%R[L72KA A&>;#+&^YO;>4(?HS5C?X G^,[+M$^ M=AW;>07W_X,=&]4D3T%E67$()6G?0,R3)0&"*!P[S0"E_@?A;\3NN MW2O83OAWN HPO9E7!'Z1P1N-N'M2KI!_P,O4GY#U2L MQBD0:TZ!R-GFQ% _ Z^Y(HI]]7.[N\,'O!8D59=QH>(8*W:QN?H! MNZL0?GJ\@MJZW#;T3.C.WP8.YL/A_K92P),.R0:53>.US;73-D&@@X8+#OY? M 0J8JQQKG;- "'N4(X(2=9L^2R^2C[;9LU0JD"ZH$)L>8QQJR!W"@=]OT5T) MRC"_U!!(H-/<(U^A*J45)IPZH-R051G493%E(4M2E[+PH[/-3<>E]Q\$4YCT M._/&O_[XL EH;[/TZ39#6Y!_K.E7TNXA_=$%DN$;R"!^[@WB?([]_4:9(F(;[V@#D,_=?EHC MIF9#6U0K L:9=2V', 'AE)>^PJS("H!>1R%1"5RCDJ\_!K! MI#4XM<*#Q( $Y7SI.,4JBE.@55@NTA GTH'=>.CHRCCLZ DC/%R?HO*A\.&V M^A6Q$!VO#U76"-N&I]L)2?((W!PN)@8SGT@U^2][D#7,22U"#3AX%GR6"XKC M.1A..+;?*7-;$<&!'D?!9Y%OOL*0334GGFH=BQ>^TA")M(?H)A\);R1]M62? M\4>@-G^HA 6"Q3(6/B4<.A6BP+6'=2^H[!QJO1)T"F[%[" G-$;TJ&Y-\6]. M/-+/[8[ %S4$?( 9BQK!5@28-I#PTR,86$+W9%AXB"RR>XCP#2G:UV*,&H4E ME)G6,"B?VZ7]'.@ M>^LK!]A=7F,1TQIYTI[6]KDM@'I4NGZAM%J3 DNJAMYN'Y-(B'LQUF\=00]> M?0YR$ 82V-(^GY?'\OG++S[#L=R17=W0*.+JHL%1P&/1*/[<;NUV(?B+!]Z_ MIORB,4+105KW:X@["RYL9+(3=GN'\:M7_0O8)%F[R%2AT% M6YF!M2NGLG3R6MX_X/F!]:/E,X]P>3TOV[BU'/,5); MM]%E$ICQY;]^X-WVJ>#=]MO_6_!DJ45RAJJ99A2QI.&F8WAA7(7+F3)Z ]OQ*H* TBX^3SJ86^&',&\(@ M*^S:=OR4+DZZWD ;M1L8R$O@5#KD6CBQV@6,WQW %]BIQ6=)7UD18.0UDQG@ M%;+U\-R3QOO9(9\*/T!9VD1]> \9-K\224, M(3A6VTD=7/43S=)"-<'TNJ?/[31:3;)&5TO"QB+LFA5>@K4[MHV?5U2SC&I] M21-/I %P-U_B67-M5.R36*PQCA G0<1:3X GQB^O:5$1>'-?R3=@8HM\!4.> MDUXEF87^F4OQ7)7ER-/9AG 4Z6Q._<27H)6*E"VTB)( .>V/5 ;4,47=PPWJ MQ.D542HY]"(PC3G^O=QL)+0(-#_P%3*/Z'_%D^S7@Q7!*BA[OK;Z,Q6Q<\FY MYS@WL@MY+P3#DF@4F",O2%/(H'AXD^8XR?( M6UN/S&$X#8<.C U<$ MLQ$(=;VHR19'2V+[O7.2OQ]X=<24.#4+AJ!&Q M3+XH7.D_'LB*D;6Y<6M3B>VXTYK2X^*.+S:#AO MCZDQ4O2-D5U4'42X;=KMS2 Y4F:\_4<]8KI80"VA& !V.F 8 M\T2L3_-$$,D,C']5V<]'XD[*./!XJ.L.M:8:"B7;9$7:QUSR8LO)<&KHCJ@ (?)8A>L'EIY9!YCWBJ41 M:'YDGG;W 9/5X8*Y9%)80 'KN$$8#<7[I#]J(1^%E"A$L,#G%GT)*E&&J(U$ M+,C?C?@:"-)B4JL)< S0M4LUV7IAWVZ]]6TXZ*\W!J[$##_E2J 7\'QA'4PG M>^T%7EL*G0[_=FHC+6 MNASCJJ!N9HJWYL@:DX:-6=8R YU+;!FT7!E7@C7#XU8Q#=(2)MHZ:.\\[7) ]==AO#1+)?,15@8#[5 M-#3:OGRX<>JIZDM6XYKZQ-0=F36O3!/ 7E'V719"4M7N5Q/%B @HK2N? ] Z M6R<,-'2+A=W%\, :2"J-4[."F]8H-B0$UD,\2"7K?3(=-A[BX?G'#P-)81O.9N0N2G.Y7F=XT5-QPXPBIG!//>,&B8-6 MX$H \$4!5Y" _5*)AMN)ABD.2T=Q.!?ZP3)Q\HQPOF!69;!1[KR!*EX,$'S' M/.C8))T$) U &OE'.&":-M*#CY'--B$X-+HS=F"O,7B#TS%?;#8OMU]OJ^=7 MG/"]5:&#&[>1^)BUCL^Q$3['J?O8A7QLRN8:$2")%R5U:N:VW5+6;W7G\)]J M7^LC.:?X":]?W[:K9QN*OF^>4'4&?('&,B,7#5YY 525JCLZD+7E2X\'N==Y M8TX!9,^E%V#C?;6ZO_)$;!P#9V(I7APV*40]##J]H/J,#&NE,490.F$==[9O M#S0!*SO[ *#,)6:MP.K674YKB5+XB@P3E&0<@*)@[6(_5Z[,R>V&/^];F$ZK M8&/-<"?FF8L13U$9X,M%NB=L!KXJ1\YK@)V7^.L/=\OMUM.UKK%^!-/G.,5/ MM(.JG6T<=F2M@*A?IQ43W-KNOH[:V<>U1!3J& GMK03^8[UWKNE M/QI7X;FX=L>"XTVT,QS>)5]E0E,KU!^$WJ'F67#L8]A9:X3.^NB+7P;)O+ZX M!\&\[^_X3/']3"1A:.*E3BE0+^^P2*5S(3M1\.(*Q7S2Q'FMW),UFM,IDAN6 MO76JXNX [?L;N(L=XGPZ94H$C*2ZXZ/WXIV]OM*2.N>46?OH4S)W40])2MJI M.A73DVFDJ' ?D>;V;KT\$*,KD)=)$JGQ90ET?H ;>[FGRC?$S>32"G=WK;3P MN(8KN\.9SFH&\&D3'KLGL(YK^ 1/UE^R; +HU"Q40HI9-QBQ%0=GT"OY064S MV"DD3^_:8RY0H&XM)86#T+'!0@,@4H*]&?9$4&N]S%0?,NTR46W'WPDI+"J\ M:G@+]%V]6BL68F&(Y7&ZZ0&S#,:YIHQG5100#A0PL+%?'BBTKW2B-68V)PLW M+ZIYOQU.8(.W'.A?&TV=X,HC**A[W.^\=H6[C?V#<2G,!0>387.B=-EQ%?EQ MM[&7V!9A_8N4\37:FB1P^&B+]P1XN&6E1@"EU=\_5\0(;2+>=&?KM$!V+._+H(GIDA\?7E_1Z*JE:"&$(PP;H" M/+RZV50E)[?*IS@B1VJM)ME'IP5K=65/I!0;:L8"HY+R4.^XO&\W1P+3);B, M28";$W)>3CT$9N)T%JRV#$(D+.NI8$&*S?:8CH4>7;4[&C*'.00 M;&CK&-H[C>)VY\<131?0-60_@4N6&:#6<@TX&6(4XHI^(R\5HF*-(96 MV<<@9=Y6_2*H8MM-$)=?=VZ157@SKMW-"#OME_7N0 #5J-T<$1B&]5&^.247 M%4V9%W<(&CS#88IC'=+$7P#BLIEF6B>>XNBS,(GEX#:9&.I;]*JC?%X;SW.A M:<#4Y\3.1JL'9J;STIQL:'C!LMWZ,$(Q1U=0!_,SFS(%G9C!=YQ4P[RFFTU7 M_$2%!6G*Q4SXZHN% MQ+.V A-XC5+T]ATS*Q!:.!G_@$D%V2#R05;:_6+$TTI#1A^I=N2J[TVX]M# ML_D9 -(SC]VR/.[:UQ#R^OGOZ4^<](=\5$C*:UM ' /Y9^:Z%3P__0D3">%I MJC;:5O]["^P6L.F[W>?2/0)<+K %U@K#5_4U*/1X[(0 LB+#*;RI-TL0"=U& M9= H3:!H\/;XJ_J*T>!7V&4"]6N_/@Q_]$P]3N%P*T.[O1M^?*X>I^#S 7R) M0Y^\4*,WZ31E6 $/%>PHJ918QT05]90A2KNB_:1%(Y MVQZ\.AU7*G/0W.HQJ'SP9V99DL1]XC8#H1H,[C0+UDUP?^'7Y'ENHJ\)SH 8[0' M'XY?=SZL43:+-.G>)*^^OJKSC!PIDQF M!7UG7]+![]O?N >U@JTR1M Q7GNG,$-$<#Y''&[MXC7"056Q"C%GQ9. 5UEX M&- Y8Y#("N=E"M\2PAZR+0BI(748;\EH_<5R/5A#-. M*&^A]CDAL/UF!%"H)Y7%HXL=NTE=JTD533F%,F\D8GUOCT(SWY M/@TFF'Z=-6)':K(%T4RH9T_%_WSG);<,^O] M/"DJ\1S>2S9Y'7CUGU/&JW-[!PE!N )Y!A_A)KHW+DCS;*)YO@IVJYOD8(YK M$\VQ:^2"N#HY1P*Z&,]ZLMUMJR09KR+RHQ33KB'90#M3=1SBIUA1?X>GI\H0= M&'V304I<@*?Q7H1*67;L;<'XCHF]+=_"690XT3G(7"+GFD#.H8-F7@3@G(R* M86)T3G23_X=@3:#R=66/DL+Q]+E=F)2JB]%><#6:4N\4A'21%BH40Y?_!KI' MY[WGNFV\CM&X9"5*0N(L])=;KU@WNE""2':0J_N(KA3> TY2[ S4.P![K^\,!,U$0@JHA0AQ?P!/)&<%7Y MA!!:Q6(JU>E4KY0:PC890B#"-C,L\K;S[*!'=%4AKN7$0)+QQJ'HW4J-3L]R M.O:%>3+3!86K]M;^)]2I[[:JA)BKHUQ%\@W\Q_K N;I(J9 (^(75O[A-'!&/*?[=SY6@OOEDB;BCL-BXSOT0N ZA7@*F$O6!]? V@I+BM+_'-*X0JA;U-5AL6M;+EQ>7V:.UCK_;\M7CX M?/?W=Z_Q^WFS&+K7I_.9@>X' MXST7SBGI25_!-YK".)5O5,BQ[!>IL T.AC@AP[O/GA^8:T* 12$+^\TYTWT M$N*/5R"/M4/;\PHQB1EJ+T<7)<2$/0K*8%"*DB*8*"W"2T>UQ@>IREF*N+02 M;J %HB"5W<:R$B&=.DC_HN]X8Y);X !R]E[P04QP4I3, '%G/\DV1%,242$! MZ#D580GE_3GMIIHJ57D[211'=F:%A= BOE]P;;CJ'$S%/^"%2.6>W/VLY*CQ MWR#+),]HQ^E!29(!%,%E=(>G?L.T1TQ 6;)\=I5@"CD,$@6-*"*XB0D\D!)I M@9*X:G]ZY,KWBOH^4>M G'SFW@?Z$4- M"-<09YE4$*Z4*)$9@W@/$90"]Q5%1P"6 .I'L8'/I&O=1%24LLY ASCB19G: M6[1>[EW )8XNNN0GU%D9V$DT2%>9][)V5R=<]5(9[)9&I95U(4C)MV_MOA:_ M9(=@J+X>%KY'TH[3/J*K[R1J@=<97":Y'Z-R@0#;ZWIMU[J8R*NZ59=N^Z5^U*2 M7J]4J;C(SBHU,HB [KE4^R))# M,I[*G!/!7!H;[?L#^0<"^@NI_R?@32Y<0'V3[8EF_/)X8/ L*;.F!%3X"@8A M4ZS?#""P'Y,W8\QH3 X_M=$,R!4JY]=4Y0^V5H/A*TR%7P/QPCAJ)1YAN4;N]VMRO$+R8'+3M^)[0]>R8#N(*)J_F MF+#V[.\9@&]\[SR^6";%5/'\W'W\D/B]R0R6[S#J.[XZ;X9'\0P3D+$*$A+% M+.:'Z G,9X$;V:@7\P2>^V:>0+U2ZJVUO!4-^K)(>[;@UZ)9X$47[4(VM?O6 M^G;YZVIW"V8KB%6IAOMH4J:H^_[:WM*H47W&9QJ/0W2XO\21B8L6%26 "MRT MP3U=W^_1^=5*E8$X\;;D"P%?)ECM"!1S8& (/D_*(85?LBB2_M6V@]V".#\X M9RN'+=178/RBR%7M$GE;\@+S7B?MS.'BHYUK!@U=$D/3HN\B_)), MJ6S6(X-F!"C3W5T<($Z#>0P4OHY"EGF9 M&&C0%U)%:DM.^KK10&QTVJ1FUO>60_Q=]>9CNR2U%LDB]M_SR0H"M$FP@_0< M3 TGF$L#"E(XM<5Y*<)IR4#NVY"9+. ZE["*UHH2#W3[I=A-_@LRW3M.S+"NW/7^W9 MG&D^I PA[FU[I!6R"JZL4!9]/M2,%-0/#_33S[[Z[C-,;,URH__P^;=??_7J MNTDJQ55<; _>^ST841W/D@];J:7*\]*]#M?VFQ??XONL\COS S'N?;B$11(' MK:2:5F=KKN(1M";(@E0'@E--XN-54AK+PO#H9#*R63FE47QOY:Z?#'58TA( M ?O6XJ[]&3-3R0>5RFDIBW@KIB5>,]E4)N>;E]]__>KE5_\+42[]I.ML5Y O MX,A Z&" 38CF.RV3H,NOOD;,Y>E4?FL'I%Y4&?<6JQ3@W$\1CU"]D^N;PIE] MX#Q@+_C#Y3G@'BOL'J/?XK2Z<>B)G5&<2T^LN\V.RWN4V[R]X>5X1Q")#!FJ MG>1@-6<-8\-KVYLL/;CQ6 ZS;=B._^JPNU5H%Z^-VV6S;8_WZ /;,%_/&HOF M($ +TSB'KT!MG=.S,3(+XW?7I,QH&PEOGE& .">=)UU,.[>2FQ)(<3[N-BYL M\A%IP30M&;$!X(4*'Z\/$,.A4X9_@.0-\V%P/EPM29W!6;/ MWD5!\,JH><* 2EN:2M7/%MDYL-LR:?)[BC4-G22N3MOR?,D M23F))IUU\CV^61ZOUB^VJ_^U>[FM=X#"

_:>$?Y!F"2<0Z&871**H%T,:T5=+^_?O$%^5M<5@NN6HZC M(J_T%:4/J*^JX>)R[B+C6;3[E;X[!6!!3X%D^-(_Y*TNH_(2=G) M'>%57E6('UIY-,UP<9'HO7K>/)=BA&ZV P=#G;DCV.W +5I5M"-F,X[SO('K MSL[)A3=+.\D3F#ZH\[X;J:VI?N7?5(H(A3:?+SN4@4CDJG9JVQUL+[KS>K_D$$.4;Q M(&Q3& 0@G P.PL@HJ+PL[:O&_Y)SD_%B52+T OU=T-O!GEO%@71W#R*GO:U8 M1N;SZ8"SD!.K(R5#DJ&QR%#2JIUDH1PS*)HUXN=W?"Y;0$26)+1K^FM-0+;, M!J?&RQ"J!@?"FD\XQT4^R"F\""D5_ M32N%N>A)$&>KT$[A 0H"HJ&KJ?4Y;WVWV//)S.[Y(D^9$HHZ3)AJ_J,)N*,N MQ__&VQQN'U&^#]2R"%NF/Y&0.]42 [T'Z:!,Y[J#[$0'JVI#P"=8).D9OVH3 M$ "%I7=-/%'Y3^1ZO/19+'@CL6;T=&-28)1-]$7%C^13:6Z&9WJY@ONQGZG M4=V4W=$,=F-(?L).F!8=_X!W!-[=VP6PX],.?\!KN;OOV08>"IT]M [IZ+FU M9 N@Q.84).PWB=8%CJ@#;])X*[B#*1)ENQD5<\0AH;&Y;Q[H@_R(G2X6OHOL M=!?H7HS;EPFJ6-@^'VQ/1E18W=]Q.E)_J="98)>%[A*UTZ-5PW"^I68=WX)- MLZ!IJ2?5=+XFR.OP"3+844[Q/.[(2H"5&9X6S26FE3?N, ,4WVB]9_ZK,%>-??(NZ/)]I<^N'0.Z QK;IK MG YL8#,PUY!=2?V$JYW:37QU8JI=?2HU#M<[S4ZO4SP(%ZC'Z8W6/,TC*:TW MGJJTAU=$*,7E*)T9^#G] "(@I? /41@>(>9MPV^H!'4#ONDCE*!B$1]9-4$) M*JK_)9K]+F!?H-MTQ6E-1RAV3D;E8B;!^I:B=P(.+\6PQF767EKQ7*.1&!2[ M4N"9W'B=&ED*C)DQ 0\$'(2L5./$;'8$).*R'%3.0(>_#'B/*+\.JW:A-3 M.03WR%6"*RZ)AF!J2LE[[7T4ODX90:(WU1(#F2M?IQ"D: +,;PXL.U#E?*$Y M?VMK2/]1QW)#I!'PK>40(QJGSWG5/3P(\GGYA%J"0;\1FC&?RFW28I;IK9&[ M:86LFY8@$B$6H@8-ZRW@;/RQ\EF1#' M)R:O8G'L]5RCQ3,;94G>]2O%19L?,[,B9T#0K_#@4;BTYH?H-_B0_&J,+MP9 M."*[H4 M4PV1[EZAXV'J%5$ !E]A>^@$P\I%&?PACO_,(&C9S7#9A,&?!UX\\WBV%!XI MIKG\=B \8M\[S[L)TQL.C,CKD"_U.<>?Q8M>TPYJO7]\!@S;?=O?.\133J_B MG:?\I%?JRY2;;L5//76Q7 MV\,$B)0[,!UO44U_\OBZK=>2"M;[G)L':]3VE=Q!.D&9:'(.G/^8DZND'G]K MM0S!K$8NKH\.O3,%5 M4^:0JYT_9^CA2.KBG8DYAP%IQ4DI:_+IM- 7V2RXR/@B]I[5T MK1+W"._?@ M,ZL$Q!Z-*#V^CK"A/8EGE8%"".\1/"NW8W@TVJ!9Z%1$1\XDD#L\N . M,#X'XJA%BH@Z$IXHS8*X)4G%8D$EUWH=;LX^%FX1S"./!:U"-7Z600 (&I&P MPF_1A<%],J[$_4^:98^,$D]@*O5I\;5?B\I'ZQMW M+M:A!R6=OS/I="NT)'W'8E&F\2)JB(/#XLWC-X:7W_I,] OL/ZFDY.-PP/BO-Q<^K+,DSI- MX#WL+S9I=#E7 "ZVCD.14E>N4K^Q@8E:4'J39-E036C948C6LEUF\RDX/+A* M+J5@*&\53')@63H,3!IEDLS(/[!5KDB:A]=M-((UWP!EZ1K(!6VW$R M2:>PZ#B:\;,7 S M38!N5%O--9M_J?:W$-1#^A8L1PYJ5/$9I.4&!VY.9$(G'+A4MP4@#@UN9@"( MX,U,Y*"P[V)CUN_58PO7LM;D[9\]?HX\3$ MV8'BEE5T!O*B/&E>\1E08 PK+#6M5F I*'Y55?6)_9:+CBWE?#]I8K=2/IO. M>S?MS&_:-)EAQLWL_%U+3=AG%VS;R)&1_3G'90?%H3HC'P,4;["GM@K7; MJIAEILAP*+QO*O"68DXL_;L6%RET'F4'5SH[V."-*N B1;XXJ6KV["[CME>P MN[J(%J.BS#K*I=MB9C$KH5JR?&B++8H9 V5Y^\P;+%(BLX&Z_6H]PLK0#DP M-#PM*'M=XV$/1O7@!NX%IG=R0W4:XEYESQ-^'PY:A*/V>]-W[6F*#\@BP! 9*#O#J_X=3;*5K-W! K=O)CQ>:%PXLX5O*G:^-SA2K,6(=$ M3F*GTP&:V#ARL-?;NP= MMT6[[F)23!=V+(L%*V$-_HE6;+NZ0&[B([I1Y=<5M%*WK_T#8KGL@-H(7\&W M[+5OLT.R&8"IN7%.@ERG4""2AI:"#I\_)&,6')8. $NM[9 >T@E*I:B$HYPA%$9XZ(R MTP(\O47VD.$U!7?P A$>GZ7NYNTJ&'[/VQ:C+"E8!*&"$=A1KLFZJUC V[(4 MD"6T7A&:49GK@ K"8M4"WY]ASH_6+#HO1^NH0>,)DS]ZDQ90>_&V%O9-^42H MAX!X$1%)B?](+TLO("9&A8L)^-1VTA>0R/1L:J^(G/4F.IO]TTF-%@N9SUG0 M3@YN,."@K=TG"\ZL>3;OMJW@O<-M4]=VH=N* -!-):.%6Z>%R;(%&_;/TL1K MB4I&]+X9N;F4OZ;DG+;/)\\8,V\7^VO0RLUF8C;UWJGN.)Z0J@+W"F*18.%$ MT$;(<&2N/KT3*#,58\_FB\ O4P22+D)K\X@_&OYM:S1W"Y6N.,RV%=/D]$#/ M"2V=O#8E.C3ZE/&]\R@Z3./$^3\PTD:N(* MU+4)+O=\SR&%-J5K0[++T/+LF9^^\R:K-,[(?T$;?2I:(]P!M^,X=,W!KKP\ MI3C"P00SM#?[P&L*T79V2&JD3_Z ]43NEW08?@P3]HI$--B7->&%!\B,B=N) M>-6G%RZMD6?R1PJ[$+5Z"&"X[@G:E=ZCY0-%4JT8.M&PI?^DJ6NIZPBY M)?EK0+TB-RK=VDNE5+0;!):D7F=8!FMOX87@,*NJP/XN3=3GR/<9&;V@.)D4 M0"\]-VS1PPU;$#4']LJ2Y]"27N2",1#CRBBP6V6*"7]215 M,(;Y1#-<&:&+U47G=4@7:]\'L2!(-';43VU$B2ELL5^^ KY8MB0]@CH.>Y Q M5NAQ%^[3<_ETCU->,HC@GHOS"0#KB"ER3!AKI#Q;2K-YF(9G .6BG&Y) 9MG7,L(SB!?:T MU![1TC,->A-,-) 0S=@ZB,EA1]DB A>D03R"'':4)S-P_B(/55&PHVD=#*&# M&HMD2*&V#E(U9 AMA A ML&:F19HU4J^G7 "GW@.L0?B'F"M6@)Q"EEA>=B3(E6GJ9XD-26(;3Q);FW-8 M8G'6LRFKP$A'&)9Q"!R*'-=>EM@.22S@4@@8*G/$]@*%D*M5H3B3W\;J5U<@ M^DQ?#"8OD6GO)9T_C)G"#KJ(UQ;*IA)ZFB>=W74> CVT@W&;$/$T(-TX+!%' M6PHQ(_N$O85N PBU-O:>5KP8L "&B&YQS#B_S?#DR@L0:;BZNF>P&2SN,B(" M'9IL'T+[(&B99K4M!DAW'^3<->&F3N=3[NX4ZZXITIZ:C ?77F-AH**=Y4GO ML<(_R+$"2\HO<.X]PD42+;!0I%*M;SS]ZN6S'$^C]"$0 &LN_J]=KV $[+9 M>EDQ0E--F =+MA0P1R':*F@%[[9,+]0("H)[/P;<)\SLZ\X4P[D6\SY^%D5G M/%(+;^V%5+BI'D=GK-F,HRV0)3EH[;9CO0(Q[[*U(^;&7\:G!3H6.!)XOI : M-V>2&K?:X8+\O2'"82U7L08CTSS$P)6*% [O.ZDQ$4V\UZ3&93*?*5+CJ]Y2 M3RL>2LSS1J%%R:*_G?MV']KS_X;J2IG$ K7U7C666-)HU%3148 M:7&(FCL6S]:?$4=ZJHPSL2VMMY;!4OK 5JX&?R 82"%[I:O2 F8W,&DS'GS=D_1K8P M,1N/B;--,1LO(DZHAXF->TSM6NWKYD&*XS\SD< #%,<-4QP'N%N>XMB>T]F\ M#]SH 59@LU@(MY=C!1X]Q IL-3?D)@QI@4?#A+HI/NYX@7MIA_. L3?#%A$O ML#G!"YQCS4L/+W#8*.0%+K!1+R^PZ?D,*&^->8%'0[S QEH3Y1 OL#RN>8%G M]#CS O?.T2(8_7P!J3M;VG>3#- 8>KXX37X**:VR-.&(S@-\PJ:/4+C#)YQE M\P @T'Q^#I]P1"=LLB+KH#&=02< 3"+ MHY\]=,+F%)_P:(A/V.#;SN43#MH;XA.&]B?YA.?$B*-!^MZ&3]A9M^91?,+T M_N_-(_F$(5R5&6I[DD]X@80Y#_$)PU,/\@GG2=%A5_A0^83S%+[E/> 3SK,N MJ.B'R2>FW=,#0@2>>>\.(V06BCNGCY79^L\).S; MZB=*?(CC>%#V=CF.BZ)DOQ=S'#,[[C#%<5%"BY,4QX8YCL^C.)X5,V6V?# 4 MQ_-B^B#%<9FD?;[)=TUQ7&:/ISAFI\,[IS@&9\#OIC@.L>DRB- :^)F^_]9^ MEGBR7MS1R-OY:&;F""_8F:N01_B91[U\3)' MKK-N.!73P*F">XC<^,M7?:((R[[]$U1["45%KOS2",DQ4Q CQS%3$'@F1'>LQ]_$= MIWFI..(IJTG-=R7S[7#)I[TA30&."P.B=\!#4= [-(%1Q'HLX-(AZS%&&I5K MO?$QS>>3:2;I6M.18STFOT8)9(WNJEY[7[O/Y;Z.:PRNXM#'-=48K'J*!]:> M\UBP#07 M=RAW%.8TBL-%BE/C%*OYT8XO*_#O-9*$7A+P7 RYZ03YN\VG23J@+^;IO<,_FX3$7@[ M+?M1!-ZFP^"M\E^)W!;&_R"!MXD9O,\A\(9S_ "!]UG\W28@\,XS1.]^+(&W MB1B\1^

)N'&;P?(/ VN362SA':H0C*IT5Y0CY++H'=KW!E1-H)ZNJ^I'U> M!!!]2!VJR@>X7-1I7 U37>F,MXGP#BU5JDDP:(Q'PX3.S(D)G9XE0'!7 !"$ MY(2 CJ,D2)'VLA6?S8E>,"G>HSC1BP)-GG\6)[JUI.=G=0OT?,Z-80F7TXS.AEDDP_1&;T,L5Q MOP-F],AF!Z@< S^S#\!F3\,(?<81>M@#(:T[V:],[([H\HK;'0+PIG/N0L/7 M WM?#Y.[UQ[/F\3E;-[G!CS![;[HY8@F,H MM;O=P9W8\+^>VCW+IIU@ZN^C=L<,@:)+CR4 4N8Q].A80$;TZ.9\>G2?LX%W M^YGTZ$!-W.5'-X\F2%?\Z)T4=S3?I]->(KD3#.F"Q_9/I$C'5SR*(QU;O#N2 M=-U=Q))NLAXRWG\=33J^_3$\Z=*@2Y2>)U.NWA\D2L='WCU1NG0[2)2>9UE? M<.%LHO0\7PRMT:.(TK&?/J)T_8=W1Y0NO7:)TMW[0J+TO! (A7\!43J\K)?G_ :+T?%&^.Z+T(IEWF(0_1*+T(@4K[U])E%[D.H^29N[])4HO*"#QGA&E M%R5F:_[W$J47TWF?._411.E6:^@>*+U8%.6'0)1>)NC_IHK:QQ*EE^FL M^_6S#BE,HD7ZER6=QTA M&)_/\B[7XLJ?>21X9G'LOR#KE-_4SSITG>_2!ZF.;/(7E7 M'.\&"3.ZEGE0H,6)@^X*8(_O?,"-XG)8P^7M^ 69^=JGL/9GL+(/*DS&F#BR M=A5.1(#+;, DV^QV-\LUCLMY_PI:1@BRY]JG34&$\LCU)%V MA9G%R'/;Q%_%7T"W"3H!LZQ3.OV<&S3'$<&,2R,SLI'5.,K0GEG@GC\8$; M^F*Y;T2R*&7F0 KBCD&L_+=@KNFQ(KHO3!G8@E/IX*5I[_ ()1&G#XN?I(Z< MK:&@BU;A#1#[, ?9OF?;'L?G7$71^&"B12EN22,F9D[>V,3PMZ\>&\Y%-W3F)!G1/ BQ^L+( :K+OC05#= M7SHUN=8#;]3 <2?.YJ5YT_L!G(<&'X#@,._R%^$[E],M>O# M,92TBL#;03=&ELWSOBN#2PRQN;HL,,L5;I^#U5&=V62 &'-"I/3B\2V&0HA< M'IDZN9T3G"6_$+0=!U0N:C15BC"0'L6X0<2CZ-P"X+Z4DES37VM(L:C'UP2% MH091.A_'@)*TRVYY,9^L$+SKNA#I.(;_[?6"^"&U>VZ@%;YDG8,F4. MUE,M,7WL(!VDQ5QWD)WH8%5MZ#9"K)'&676U8<7?9;P74X26"H:6,VOL1X2H M^&].-VJZCB#2>+&;^ N+G\B!J+H9G>KF"^[&?J=1W93=T0QVP_HVUB@N.CO! M,Z@@"RYL!A4KAEO._KZ[#5:MW=(YN"4XN%??;Z^XN!B"#7E1< D1]AMO"53" MR S=D1%*7AAR8E$.@^UFE)>(H4QCB]:VTP>%SV!^@RZFOHO,35MO%QA3Z[2? MY0MIGP^V)X^A,YP-A]HBN8W]S?.%FIE"?Q6Z8HY"W2$H7/@6;+H(FI9Z4DWG M:ZAYKZL%>RN2G/<4]C8]O40!4NE$F)MPK8LTGZMAS4ZOD\\8"Z+#1GK,TKG= MJ>'VF?MYQ^S#J$O67*JHCS+H8_$3N:H'^M!8QH84!G$72G_3H+\TB3<#KYQ# M'>:KB%O/@K5+!W:S"19/])T>E"CN%3>3<;T^L,'C180").C'1#LKS4^O83 ( M QM)-RX>M9.,3Z;#3XIV4UK&0_'3K"'@X!U \4LI*9"PE4/"EFWP#4'0;"#J M>@0(&D3K(&]=@$*#1F$YCU*[2%"N.+?V"+P<">!::2I#?(\DBT2 .%"\5-7H M_M2(-X8SE,CJ[,#D2 8%AEX\!(ZD4-=,,K#94>K'3E<,*NS$8I:6/=B)X"6= MY00H;2<*T&<0.?W/RX.56C$-23(J4V#R@WOKQ8&4N?O#_7+C$9ND8@;J*."3 ML9]&#YPL( /Y*7C4]L\3X&#!Y"@FH"W7)5Q4+UD M!YZ5J2$0O N/ TGT=0JNJ28>=*]X CM48[[4-P:5\ MVF/+@9HC$B$:YA^EP(+)1\@]#4""G.O;&V5&@VUF=\>LF]430\=\S*X3SOVC7[4^R:GF MA^@W^)#\:HSAUIFQ^[:;C-KAHLOD?9(&ZQ/ET.'T,6%S2Z:9'@GF?;FW/DNI MU&.0@TY>PN,#5IG0(*93$<#=?!SG.BP6W##(_^&\;.BTF'8=LP/\(!]/;L*T M@S0'8A7HH9O^,O*O*(G/(WY%'P7;Q^1I4#'T$*0R%--M5U:GK-FY< >B>.P= M"(LJ*&LH)9;K.(O%,"/B/YM7& EDIE/')-][,:!F\BE<#,>E8N@RZB)P1(&3 M@)PYFRV".S<)[UQ#2H\/U78T**7?D&,,+TKQW!($"JA#G!ORDIL=*3<7KE#V M>ZJ*YCR9+@R.[/NS[D[\D$6&R"DAK]3H\E]%3H]TM@DFSPP0.T*M*)S0F.@G MO*6-OJ;S+-5$GQ%C'@P9XCF5GGBCU"%26@BIY@0^N+UR#+Z)9YMWTW&)Q6M7 MW@_-ZA)^12U1ZKOEE3@:"0?FS6U2%+$.$3^]8A%4FOT,'6.(]S.I\2! M1&9(QKPV+[<,@-]'B)C/9WW$-JI6CF6DW9*_ C#]WTKO-(4>59 7@M5NJE" M\IID>DH%/I" M%)A65J,.5F->GB2K/78>A\'U?C3)%(*AB<#58%00VX>_MCR_. M.1A?#)R,,IN]$R&EU-.AM:#$J0]G+2)/3C'*I@9^EA^ )Z=0GIQR<".Q\2 P M%UW>PLY&"A/R:ME2;;BEPM-M!G;4Z/2.4I8-HK]T=Y2 1PUL*/,6Z@>Y!1ZY MGYB$[YRSC>E8XRDIE69 T!*8F6*PU^MQ%:R'R[MK@J58:SRKAP^W>6@MG#E9 M#9SM-)EWS*KK]_AL(UDR8B&.9X/'@RU@U#T>7@S4/DROD$WS^;O1!,4D'UR& MDCPO']0R8+[2>#Y\W9&KP2[#W5EGPB4[]9^)=)[.3RR&.5M .1=(WVH0<_*B M[) MGK\^X* :2_$V _B6>)4II&F1R-V]Q403+,,3DWKL,'@36#"[%U.4?I MPIJ$_UP"V,]!U+)>%Z"P1U\+J%#%JTS 0XUX.(+(@E[U4#:'DLL%?TA,->^I M:V>E_> 9/'8Z>G=.%ZBCX?L IEHR2<$^#5&'_*\\VN"*VY"N"5\ M"&GLT5. >M[IL"9@>"!0*D0TM\TWL(]I,Q\>EE&\F4T8_KN@,P5_NO&!OXM) M6@)/<(ICHH%P_$^.@;G&Z!^6?[IDM3#HAVB3Q+S,/'08$]KIB,%VJQ M,)5+LGHU\S( 8W,M M!#LX"K%BQ1?OY!O:R5FRF$(Q(+XN=WS$#L^CA+N3F[2ZR0PA!)&'F9IT0JWP M,LA3S9RL1^=' C7[)\(C=OH_!P*@'=2PVEW6)RA/[ZT@ LK0CK2S=(3R8@)Z M8@G%D&]D[]002\3J3ODW!Q O*"<'.G?W". :1+6OM:Y]7>N;MP2ZFM^_Z4PG MQY:0N1?#G-^1EZ,<63T,(3T^ "]':6]? #Q NFPX#*;_S ##3T&&6A1 MBF=,G9@H>&YZ!+$3Y=#'%/K0=T 4!#_500:L(,A#JL^1+\D'\!B$M,^>)_1P MB6<'2YR).:+%DMT7H?\_G24G(J&M, :O#,>I$<\(Q"Y!*D*BV"JN M?:ZPB/L""VP0-%C"W*3Z!B7)'1P3G%'R#2"^%97X'#1HJ/!H@Q _67;)>0;I M(N\XQ'KWTKLW;RYZS!M)L'%!IK8T9YR[%93H 40[ M_^XJL-%0J4#(Y#U477-FR.62"$T]V3&8?[IV#3JD+Y+:;)C4,D?^,?T@.V:F MT\XIT8D>TV)J,N1%Z;/J_ T_32%I!,-FST@/Z#\I?MM#BSPI2G7#]Z3UM0Q7 M$U[,V#9%I B\V?OXXC+7 0&E]/1A\@Q1')2=UWTY6EY4&KONL025_N -.1Q? M3GVS!>CD)%6V0\B4H;RA! R!L!WM##/2+5@UL+>B^*WP9 ;SZ6K&J-%B(1,Z M"]K)L0ULU[ M*GC4=MYM6\%[A]NFKNU"MY7S'S*GTW)Q:X"$XLHFVSI-O**F M1 0T-_QFUQ:XVAL5[,,IKW0_G B*6J M:_/E%UA33)*W,B+_UN,KLL&:(#UI$6A4J-2'R6-29W5P^4+@_%X+4(D&93SN MX!IWE;25N&/M?+2Y6X M1M/E">*HM?/AK8."^#52GG-=!=8IV".C:^$I8[I(IWV@IGS-_Q^0W7LLF\;R MZV1F"J"7[3;(?(/+Y0:RF5:Z49'WH2WFOM'A_A*.^#/[OY!SJ9J6TSX&]L(W M)7\ 9H;#"F%A4\LZ#J9[PCK,\F+DZ='IHV0WD&LO&K:03-HK3 W=.'@,9+05\3%1 MW3,C!8' M5[%1IGF&3AGX-/O!(&Z!IX0O8CG1>:(\K53IK$XQ(NYGH)'F.'WV1R'84487 M1M >0S/*_HW^@Y*K@E#6=#9%R2QIZO4E+1VW'ZI]?C["G1NDI4 M"$TW0(4FU\VTDV2Y'G#=3.VE;>#G[ -PW4Q)2^GSW'B]SJNLGF5CU8*)*!01 MDQ)0NP9=.SV*7Y;;2]N^UW3<^0&LC7-\I-2"WU$Z=4]#F.6ALH M@EU]PG$N"%/]!I715SW;UFNRK<6H:D,V!^A\"XT07OH;P0\45Z; IZZ^"Y]@KI82831@,<)M11*7KX) MZFZI[%:[!I;:'$^ZKAWG H6DG#2;EKU6QLQ<*L].C,<3[4;L*9_"$!/:U#W8 M&]2&!))KF950,(0IXJ=-F&NEO&*-4=JU88:M?6I3I*+PDF/2T/+ !NE]DY4< MTZE2=:><:XWL*K?C_ESK=%[TJ;DQ+\EWD'EVO,?LCE->I:#4P:2+V4G_GWAP M-.J;I(7TI#/@@R\>V%B3^7P!.0K% M^4')=&:/E>]:B;%:,L)ZI1^UR^?A^O>V4YP@'K.+3QP>.$,G;D6^HQ(9F$X$ M!F'ZSW0"=P69XYJY1J'W _H8W2]K_.6/89Y/-DO9D_FRIEJI@!4L<:8SJGHI MHT%NV;,*W:V<%1Z(PI7X!$#T&27[-'D)0BH)?6),.00UD^WXQ0]. ?^861:! M'[-4MPERE<%G:'88A+QYR;!; :F8#@QW/^@'2M8X_4&NIGFS"KX'_3B+;L6' M%Z+SF;7#L^S!O5XN )@[.W^OVQ8FSZ6<6&WU'S2-VEH_/\J+C$.I:HO_V/]\ M.K-FI1\ZQEK4'7\[?):@7>;:E:Z=2EWM32:AEOZ3IJZEAB\S4C$!.=[ SSFJF*!1VN-I M5"#WK8'6.2SX5O:QG]P="![-?\]P^\UTE>+P+L2U()/SU4.VQCNY+HBX# MX%V@T$#CV6N'!Z%.;X2X/' 5P]W\8K-YN?UZ6\'\2;C<",4T,DD=D#C1(SWF0. G BN$GB+>%%79G M/+Y^?=NNGDFH[8F=@)OM#B;@ETU%%SE^W8$>V./*[0([@W'[&&K.*(,%3=%- M>[D'+BZ$^A-3G?ZUD\ OHC=*!ZQF_=JB@QZ^($.[%]]!RRFP=KYON]TN\. S M?;=#?M-*!=]B=ET<"[$1) A4Y:DF'_0+$+ZP@YWRZU@ M^PE8$M>S)5C&J/FJ6;W/6W+3[Y[\:W]QU=+N]&1 M:=$>PTU[)8$LYEOD:\;Y98[$408;8:(A?&$2EFI[)B8K3D]2)XIC1QB*BLQEN3+4+@2T7ZYL\/.53:6S+X MM&Q5N9.AL!BW&&-7(+CY('H<[-N II=0^8Y(=,.D1P=FVTQ[,7#[*))/,"13 M/2R5#+Q$CQTA>\(>NHBWRIV]& %YS3XN7!="GRQ\SMH$AAT%&P6AY1B7@]F# MUY),)B9(>[@E:'+^4QM'LRM>#U@#3)O,<FL&@>_ 1'EL54(, 7!$ M ;U$7I4RZP.''^15\<D*YP>IKH]. ]&$SPPNK%V%\P MP?KLX.+/S^;'UHNO\+IQ#A=EUG^N\"]RKIB!E5G M*WC[E*2P2Y-@Z$8'VNAZ!;5\M[T"Q9QI)&J*'"\Y=@*E"/%>P:M[A]L,#QJC M5[KWH_^=T)&,/U=,$9"E?;&$[QP@%Z%!\M*;(H=L?T)W$'NH$7N(]X S MA!*N ,]:O FR9&9%)_0LX )$=1KN@:($3P2^.F53H.?>%JF.NBDQ*=YR(7YM M0M+Y#O.$4Q^4\\MQS"LJ)K$6-6>*E22[C56#Z(XOICA6\IS!F#KT*E@7\K_O M,8H ;K.6XV>0ZQ5T!J2#3".$M/0AFT\5 ?-#5]>2LX" AE;H@88\_G:)K'<( M^8# I^!QQ5%>WMO/W3K*Y?L#;C@.Q]"7HNHGFE]%DX(O,0ZC"Q_%"\9/LD<' MD]#1REXC@A>I48N,!J2&R_+ROK5_2H" KG/V+"500;: X9G_TK7I\B"(;UN M%! @!$8&9+3;KCM6?DS(6$5!Q3MQ/-RVV]8X#> 9[H2]8M. M7YF@EU&,#_R0\GF**:JHX0B9+!)39E.AUUAUX?5$\P@Q M^4@G1F ./PB:4*UAI0N(ZF#AZCB;Q?8UY*18)0Z C][_$,Y<<]S"WB..VQ<4 M(,-]MY%]=X1]UXR7DBM5HR^@IKVV"?>:G?^%,O#QO-'1;Q$ML&,EX]93_6VY M$*PEVL-[)INV/_1>M)80VVA_(\6%(32W0IA9_6H-)&1>LW+I&)H]WDR""V;6 M&_;_M!+N>L7'@PEC=",NIJRK,5 M<[CVS=$B&/UBRL44:# *XCS%S;57/DO12?A;FJ/+[Z%B3(X(BY8UGV%N'^ME\[]Q$C&WWO\E67: M@4'O5D2%B91CC,5';)_,A&S?1P4J?,W6>E?3W9<"F'H#;^K.O_HROC+$C/8E>OR!";7K?B#EVL'[ MOS=]%)Z@RJWL_%SWM,V+TDX.MB6-V;-YRN0@]CT!5P>S%&(0+I(I/>5@^F)B M3YXI.\1IAY""#W[?_L9=J!VIQN]03C5S"29,C8%Q>^65XP#YJC?05Q/Y:VLO M*L$.=(XZ9/0.CD,-)I=!FPOG98'24;'N>;YUX&+ PMCG]J#;#[RD <#[KM&: MO6RW2TP$YE>@T57I)C6E\DL3-+J 9X&\CE*K@'#L29>;E,6CW7DFG-2UFE0Q M-\,Y;:(Y;6A.C9I4%VWK^,$PA.\]-;9MVZS96;YF1K1#NZH(E5Z[GI&Z,5V( M=1;2'>"8&V?RV@,R-.U4C_Q\!2/$B9?T6QC4#:K!//>UZ9M\:1A-?Z-F'^Z% M/$,\E6 9BK1#>:[4AJD1I1>#X:XK1T8,X[-%HAM@6?N19: M3OO<&N^KY?89;/$EU?&Q3LF+"KRI\:)J[G!<41@XLX=W80@::M 8XIA::RXX MYR.H @9U]*PMX"--AW91\=#0:4OLMA;F)LS&<]:/R+[.(>V7?>0;6C" .R:. MP%L!U)2[^H=XI-$!Q36RUBXP5A^[LL, 3%U^$D;TN14GB&6\J1#9D MKJZ6AZ-/,)*D*(Y-MT:AH?,.HM+=.9+T1EQ%B(%9D]6 +A;JKL;\U*NK^SVN M/$P*.V_<0NG,)N+S\0D5.RSN1*<7QIK9TP4)+S@.H4BV9PVB1K@T>-$0KB-$ MN83#L^CS>T>;R0QMIE#Z=+T@0G7+,GTNTH:2<+/2[:@?_8Z2_OR> E.3]]0" M2VWMNA>DJZ_]X[*Q[%:RVP<2XWEO 53"CQ?43;BW'!I5DH'IX+I:M;?V/P%F MP4K*W?B@-NF/F"7_A^U^]PO$QNU_K ^VI\;A6B7ST"Q%M1AX$! _6&?(=NF] MVB'D!'=9-H9NRP8ORP.+-(16:%VN.:G!FS=VJ2Z4SRKHW*C>'2\-)I,F5"A/ M%$%ZT7*P#,.=@71*DD/2TIM%*/0)TPX$*\ MO(,ZPCW\N(4S^=IV"T=SA9!TZ##?VK6]@N-X^Z9%1G%H;RVR+__QMZ^__>)3 M6#Y^R:SG)5BFN&\GQA[O (@"WP7OYG?9'Q=8%X 8*BB!J&ZF#J%3U/OF"#L1 MO@_ZL7:U=/D21$R] QECY-.P,!J)P[C4^4;,=#1,&;@-^[:RL$6$_? M$%_J MC)W"0_;^]@F^)DWG,Y4IDSP8^T"=DCP9&-$V'-(6^.%N#!OX[_ UFA[!Q; ) M95SR#T2([=L=T$*!!UB%56H?TXY5UN75$9)GR#T%G^1UJ)QS1>*+]9JR*XPO M^[V*@U\4[5CUE/.N'9<(CPJ8%AWC'NMS9-'@:S7&6S _!D*$^!N?HH%B^ MSCE,ES;02W9 ^Q\=K,;%GTG,4E^I?B/I*C-,O\6;\!)16V23XA%.+L@;ECQ/ MU X5;#/)P)USM ^N@0J!P#ER?4XTI=>/1#X ,_8[?WT)ZFP@FS['/=^H/3\WEP/"P^_]UNW]1K9\ MI;:\R;/962DFOG( 4TJ*V>*4>-;%$7=]ZDJH8>73V3P6QQU E-KGF_3FME:< M5[2<]*:C,.?H2[;^<+U=VM*.4@[NQ/\17;8U;N66'L/OG\& Y?E*O^3TRI%. MH4)J76G5/+1BBZ++.+2ET?VPIN1[^KIFL[N4E"1R[Y'')"DPYS%T]"6X/*Q;!62>E$11_0JIGBW8 MCWR!P/2C;WG,5,JXJE2A A<;]%>)@:DJ',@E5&3.A?##"1>"0150H MR0VK]8!P@NRX\,/I_36:\_!;+)_ W]I72* 0$HF,ZAXF4'>O0H24(0/+\@+R M\."\A$;JBK[[FD2BJVFO1,WA^GB1QF;8O4O.$^&7/"%-0(28/K,AN *;,178 MW*#OQFM\IDQS)E%XT2S;+2='VZU2.0V,LMJON)JWCN])X;^"\1%S\2RZ+6OG M,ZJB&J2:%;^6L%%4\4H=%:^T>/7YDN@+024'ER7>?6Y7U2Z423Z,T%4+7;0- M> HFNA0F] [8&]&J!/ S??^] WD2YFQDG+.!*;]HD%PI9;W RWXU!OJ820%2 M^3O'N@=)&F77&Q9I^IZE[YI3ZB2:@*F$QLII](-++@_ID+-9GPI)K+KXG5X_ M)VKQ13[ +.XA.HDW&45%;&=(N<%:@YC:3?6\>GXQZ%E;3O M]O=3 ILFK ?HQZ28'>:+CKY /0=7_$,F].?T9GAP'(S#AT24S_U M!.99)W8L+^8)//?-/(%JH=1+K?+(;T4CO)CWI;9^+2ITB&=,F]"D4X*S[N&W M#V$V%[+D90J6R/)7A'NPH\: 0@B&4 ,6 HY,XK)D$1SL/:ZT&V,UM_L]>ERM M)7B_U^RDC#[^$.1<)OQ/G'29#?05.3K\M M3T1L$^:<78H,D+V H4 !*EJ'W]$"^2OVM643PMKWM\M-8W\\P^ALND"%$C_K MNO--4J?;^TVT+B&/O?ZBN:Q+[=?%LT\3SH?;RAH'9XD):[A8/(PL'SA('& , MQL#AQ=X9I1;<:SXMXX#E$-RMA,9YX=I:&4%8H(@'>L5HD8A;$76 +X"CD>3. MHT""UL'/L6I#EZ@^9G3*B$NPP%0*3M(#M]J%7-J5N&1:\?+@AJ$B!!>\BQU\ M3>Q)X-J@+HOC=OPEM,;Y8M,M=MQ,UJ MI"3!*HOS1Y70Q'LT9^NH9XTT0FV:.WF219\/];D%]1,SO,ZRW.@_,,-K.O5) M-2WZ"%;MOL($V) M/+IY-IW*;^V U(LJX]YB;UC*N)F!EU>]D]TNO:310^!QFW-[P<[PHTZ=AHD:)4U+)OD:%'4/#A >&2Y>"-U& M,!\&YV,M\U'S?/!V1C]N)G7CU1B+3^ZB+++*J'F"22E2Q+5N\$;?.Q"_+6WE MBF>+_;J?>R!KV1V%VH9.,G?GS=$YVYG+RH[F%<&SKS0\>S:7:QZ@ T)Z'S+2 M28E%\#7MT\N, Y/Q!6)@>0@6VG(3.[2E%M/*S3M29HL<*T2.[:U< WQK7E%A M#Z>);!N,0E7^;RWG^.N6VZ7FS>'%EU;_8(1$S-:YJ!"E HBVY&T4%RU M D=%L8PKRK]37U7#Q455Y"WZ]+D4: VA_9R@XFB M#"(@Z3OMBA@ VEMQ;[G(9".V"AD!N(!3A/.)-%*LC.$P$HU& MB2&G[@_>O3P&RF"T V]W]XQ/84@%1;#J_0WY5X1&&!=QAB,#ARX6&/KPJBY. M@XJN%62Y(I#-%\M](]M>PU[20=PQ%HW_%O1T'RN[2V_(:FVWH+P??#YI[_ ( MYQ:G;XZ#Y.)3OG6"+EI5IMS@JC"XY_>L0^'XG$H>C0\F6H1/2Y('I7) X@X" M38"Z[*S7]QNIO2NZC.Y;K-)W(H*KNNW'7P?@%J2^02I9K#(0EMQZ_%0CRTU% MDJ-/5V7C4*H&RQD)4;N@>R1>X(JIGC?/+R:>-LOT)J,IM&@IU$(D1M@XD#YF ML"KN#56@WUZX]_77@ 2%>R2UU@;JJN@WU7A/=?H3 2X12!$_$('(KIWI<,=& M-A0":!\<'F(<)Z6+48Z:,],1CA.#(.V1PQQ&I>F!*1T6X^6@91OXF7T CMV4 M-*:%)G%9BHC^SA[$G%6!ZC_$43&-R#./J3H#Y.B)O@ZBV3 MCLX2\HBN$+]+()-R-[X2=GMPN<[\$.GQ$.(->^W4?1R"=B!LJNB@H,R98G:D M4G\<8LB:=1N\+%J=RZTJ]>%+9UE'QW ,G36?;,23*KS;-_I$O0HX5)>M3'JI M!$I *_N4$#PPC2G44@4UF3Q9I!O0$.<4^M1#?/D][! -/>56 $>CQ8[&RG/# MLTV?'7?/"/]Q@!W!$#T"W>&+:<=ZI4%HL*I<%# WB-&I0=BF, B(G:[#](@. M1P-[>3'-H.L: I"E&7(".N-RZ #5+(V9%;)ITB(/EFF76CUSY'*H>\+F,,7O@!1-#_%^;VZO]W='3[]7KFM;R2$WSDJ!+!"J8N-&,>2 M+WDWX1HPHS'<&9AI<'K)GFX], RZ=!."QQ&)R[$,<0J$RA7F6W?G$GC3 H!W M!P(]A.Z^5KF9]H^BBAO&<]L35!/ EI4=E9PL3\D6"1PL4E4[&Q!5/\.-=?>N M=KC69!J7QF5WRMH$0/H].R0+;GT]Q/WN%QIBGLHFN>[;)*C%=X<8 ?SO*5IS M8B?'>Z22Q6B=79056$/GLWU:C>!*ZG[C #)6 !R>@Y7(H18:"FCJ;OJ)_*B& MF$\'*D7'U_L ME(U#$X=G\I(_G,0.%N F,Q,*!$8/UI;F6J=-P5:89YU $!>$->.G+S9P22T" MDX)>F,9Z5C+P>8%S" EFL)AL[3Q!DFG$>&@;OYD)=U1_S\IM#R/[8Y11%5!D M-U/%:]&Y(3T"K!7E/^#GA=?7T27#=81BSY$T?M@JW\I9]TWOG.?V$HSG7"/3 M_C@\K%CU&Y(4:E2^6HB+A;BT=AV'??T@,=Z0IUF/R?HE@P#@SE+ZS@4J5O8_ M#U8B>8?3U=T];#QK:W/,.T<8AUZMA? +(E>D@ Y A;(G8Q/KCTHY&="1\H,P M[_P"P]Z@9W*MYS7]U2YZ"G;1-52M!@.NU8#).7#@8N-R"GEGU#DBA[(3H!+W M(_;(.%C4"?_#C0Z^&QDQ(T4?^.K6GJ].Z_CZTY'*Q15?8U3,=3UW'R[L)#2- M*V* (_*^"TY@XO>@+T-J=V_87<%.'(\Y_HXOF(@([_ MC4]SR'7,#O01FFK83?R%Q4\4>%'=C$YU\P5WDX937'9',]B-(4,1/*E9,1Q? ML4?'SI^=0)VB9#\1?M_=!MV+^GY[Q> ?TP6@O]&!V5"_B5\73.UUW$(N3$O9 M7MBT0/99;)>Z[Y1VE%K \C5H5B(#+7W&3Q3.D6:89-!M T2WB>$V>=0F%T1I:^V:+6+"GUMV,]0SM:FI6@+N).]\NW*WI+&S'*4"T7;V"IJ.T^ KX?\@G]>'JR,CXD%$V OYE29 M%P=,TK,*X?URXY$TQ31#_CJ@:(-^P#CUXV;OVN$>==B[8LG#?'TQ^256(RB,JKV]HZBP^HC M#NRJ)U0V#ZH<(XF:*".>S LI?ZF./GPG\CQ24HT)*@P^YI/J?//6^P7*LL47"ZF_P)U\2 -,-6@VTZ@DAX*AVU74-@. M]23081]7):T'0P8TBG!WE"YFKHR8C2,W17\\Z F0( P )[>"DMV3B,10?>_1C%[F..^G)R./VJ]6FP-3]$O\&'Y%=CS,B9F2SK 7_@FRW8IK+;P>RW>Q[F=8D>B_E MNU/MUI9E\S[1;1!.DF'#?@G4<1K&AS S9;O+EA+8.0 ME-N5\'R>=R&'[-RYK"JNWDS9RE.I#KH 3 6K)47.?![0ZO"OKUTG$%7E7Z(@ M5-%,?N>*CK^++P9/2[2*?XEH;X40-[H8D:J41[5-8C!Z[,XOS:_%_ITC/GZI M[^"&(N8B^\UU8PU54]Z#PG!>P=GI^J_&ZKYX)?,\P3.="^!E)#4 MI-J[L$37'Y)(-8J&[UF*9:IJRU?+(#F(Q]@*;-7&^HKG\+5!I!0 MRRYAV?!55J390ND.J=?0F),.NO;88P'FO*_%0JV'7*X4$S ^3D#8UX(\QLU8 M?P!%X!#SI=R9/)G/:&2"D!\J 2!9;]B-W)[H8J6L M#0V)KN-B>*5@HKJ,@>'RF&!]RJE&+$$OL^:[W%>034?5TF[N1:\3]:N->2EB MK2O+R]3@JQCRA7:473>R<+4PW6(^R=WR2OS"5.<]G28!X-*=6J<9 M\8^'ZV3>9IW4,CU,/,E#B*S0W H: S^+#\ *S;T52M95QI26+[=,M]1':HN))9SG23=^&YFWV$:D*9RQ MC2J@]%OK1O@EO?2EVDI)DN2TE4)W/5HEI]?"G+,88%_GP6J8QZ]&I(+@)=JS M&FE&RMN'M!RH+='-VK\Q(DH+ M'5P1=M%\2"LR1U3[XH09CVJV78RKE_:'5;;//"!?1"?$K<=B,7T7ZZ'4_Z'U MR%C7^H#6(\L ,,%>-H/K0?8-J)T(5=5/!MY9CTXJ+7^O]5AJ,W3YV M+2M1Z97(LT7Z+DZ&\R#T+02^J,@Z*M;U^WTN\A)S]>8G;A#TC(#$NCOO7+C< MV_YSD<^R_)V<"^>R&3P7.5-E?DCGHDB0-WLQ?"[(^_0.SD61EN6[.!=AFF;/ MN; WT_P#.A=3K(*$/.(T>>Z\Z; ,&FZ+_'WG6H!V-PVO0SF?G64#FM,'PGD@ M!];!%+.THU&=?Q[<.IA'GH?N0ICSS@,LQ!PJ0<=I.KP0Y&.U"[$#U/C[6X1\ M]TM2!"<#^7S=JK2!*=BH**$I';#$^8?#]"Q*G';, 9R>U2G3LJ-5/ZB [87^H7&:#>\N],J?=$'"=+MD8+L(O)O6VK%0GKSS MSC[A.)AZ8/],NY==^Z]RY[[=X9[C59?FP[/_XSN9?2ZO^;VS_^.IV4^3[AWW M%M/_KY2M*3%=I\7P_%/(\!P')[:TTW_'4<; :<"XZ6^Y !H-O5/-W,78!J25 MSC6W_F]<"JX<5*QZ?8LQI8NN'%X,#,D^>!@PSQL6 A\/W9OS,^^T4^N G7:* M$EU-(B[ HGN3O44,\)TM0!#+'IC_+$6"K'0Z//\46 >W#3C4'EX*PSGW3^]\ M2'ZEHU6$L?[VIA MB%#^$F0#!?X#/"EVVG#UZ8,"RCQ""0_6Q)RU)JQ:=+,4 M^AK:=9D6*H23I0XZ(MPW$0-\L@;]#:$K. M4.BQPVM!%:Y$ !+T<,.O"[)EPK6/N!5B1RKFBC6G99_",O5\FL:S% 00=0(H M(W!M30^M :)!&%?83]#R\XY/PPG3F97K>0:%W@8W#R:U\I;!K'6F#9J5MJ,< MG(:P>Q:+AS<.MB@DF&MWCS32<*^0@I(55""?3-(I^#-P-.-GN6O0Y1_%B]ME MDUG10"UY?(5KV9OJA- M ST4U$/)6<@RTT)Y"!#ZS-GPEVI_"^GI",9R?T0@ M';\:_-"^LM.(3AKFDA[V"2#9SDO8P+R/&++!L45FEJIZ, ?9X.>+3MC-MV M5E80C]W ONO1CB!7T?B^]<;C^G_X5[3Q(+^1Z?+4QE.W#N!LKNEA(ORB6B\4 M8PX@X9UQ=9.+<111_.!IV>S!LYY V0EO' M:*:6%:*%5U!53CAGG#3L<+LI96(ZG(&4 @]BLU3"#!]/3> M\3(+F@""^JRS=Z),T5SMH1O:%EFRF)IB@<1'L(=\"BDUT=NN]4WL".=00PQ2 MBYOT9HS";LO<'1]E=93V%!OX.?T S/:2D[R2!^*>U?'SY15$>??7D-.)0&SR;T[D1-1Q[-LI0!>3*Q/# MU-4:IFZM]89I=C)#@>7MPVU.V0AZ1$GS@V ,*<)/'CV MN;%-C"]M4.>F-Q-XX ;&]U*9@1+"O2F]_3UD4.NSF.>CX#CYW%P0XIB-F3U/ M\&&P^7.^\/EI2=>E[V1XY2TD[5+W:3K/X+A.70NM!TL;E@F4$ZZ1^QT(:I;48USZVNN30L%?NAR-P8?J&@X- KJDP+)V%&9)A!FM+=RE3E]A_(I8W]$F<+U (LXIA MURJ#1:T7B/6"C":2 =L\@"<&RB?,*A*.D?Y-U7\'73P+FC%B"8*BV(\\Q2G* M$@]'1>5M'4"_RXW>NZ-@$1Z*^V68!'I*Q^$R'.<..F&57L#> M(1GP]&Z+N087DV(*\.$X(&H!?Z*%VZY 2/@&^-L*&EU1/S@8^Q<,S^[N#GQO M\D6H&MF_41R,KS:3S1>Z,"M*WET+U"@F[Q[P8^Q>DWJ[P/YMN*I0&;L>JL5! MDY,PJIR7Q3'<0"<>"+;6]4GH>>& -CHO'XP>2O +Z'?[= M56"JXT6-[&=6PU\)5,$E0B/=Z +>.H11@@[IBZ1J&2RI!,<9/,B6?4:\&T/Q MIFD!P9PDZ[>RO'$_MCM3>TM@6 MDV;IFC<]IGKF.B"8X)X^3#Y/(G._^W(TP FP=-WC$%!8KMZ>Q_$M,&]5' %. M4!*F'24[MD+]AYQV0*E$CY0%E/J6.)M3T+I8CZ&C&X;8SUW:AV\KYUTVS.2T7MP9 ]+EKG29>:U,B0C " MX)C5)28IA7"M7'IA]@\OE!FH#5KK1 M@O+'HD:Y;W2XOX1C_[TC3QC MR&I$@[6%6;JOM"@'>2ME* M8,_T3CH+UHB_4$Z/T)52-@R.BT#YWMA+]Q :=K>.">VAT^H+5C_]_W[9X0ZLESR0*. N.:P1AY>W'?;6Q D=4G9 T"\JV:/T]>"1 FQ%YI:>* MIP^SGPO7PLL:^86U$,H3%1@@7"TE>) A,@,)FN/DV1^% &P;79ON%I?HF#\B M%'B>53QD/<<;=Z-Q-/,C/Y=RRR-Y\Y]>C[.G,(L>71--#2!N0_,YR3K15D)Q M)SVN< 8/SGO';HZ9=P%0D["QB&OU HM_B7M$BN[Z ZD@#\#X<5G+JN "3"6< M8*JS@2$KO8?+&8CXG6T@,WPYGQ.>8R,8YZV)69N]#(&7H;7(9I\FTTP73L?$UZ9 ^R?KY\#R/^$%68EG^]:.9AKJ>'H#P9BN\4BW 6][12+K:/7D'.G M4+OM18WABQ0C::<"NC#_9U@>$L,+A-K*9\2Q^/L!GM2(I\W M^8^:KV:M3D62C_S05:S$I.!J*7_)!\]T80&W)*B M7> +NT1R>/2QC)?*!=1N #":>H4/AX#,S'6IZ0F*T1E=&M]E%%B=V4$#=3F( M?6NL@6UF_],:9]?C%]8"@\%8(P#P#.%R?P%A@X+NCR4"GOX-#+5J__QJ,L>4 MM%MK,:[&X-#_SFXSQ K^=&\5Y&=P7=K) _97W/[?['<-Y $D)DLIZVLS_M/3 MR1Q]ZD''5^.G?X)["Y/#QO_&Q,.3(K%?]>3Y\S^1T'F^?@(/E7-P2_WIZ;/@ M_^R5)#_]#_E/$_YMZ+$'_V0&'J/13W%@( F1=S-%:P7M#RL\240"G->^N0+E MY&J]!/ODJ?WWSW__20)<_P5MY]C63E5JK>9L@5"ASY[U?.]#GQ \]>A)@+?G M";[][GY_MSL _:']_?58S#2[[.BON>.5;HA1GJZ-RN[-5J1H942,0FH4D5(Z MGIQ(524_$0 UUHSU0F#^:,LY1IZZW6" QO:6H0[G0,XFC<<_K$CE_V7?'H_5 M5BCOT7*##I[31Q;8 3,,R$;3\F7V _[$JDERG/*. AXON*!-C4*7(K[^,0I1M3D>(S;!7QP%$!1HQX M>)V].J=\C'+D5$-5]X(>D !Q)1F/:SL4C/M8>5AC6,CJ&A) LD_9SP-3>;O? M_6*[L,M'<\3G+UB:L^R55,9P4+G%EABAG^*][DO@T\!;"K(*L; MQ,BC&%BE$SX,/K3 ATYTE0"**CR# RGMS6'WN+5#468V*"SM[/U? /V5)EY( MPF$LD3!C7-]97>=8OQX?CG:+'G&5 987_O;D]>NM_7](J$38.L!+\3HI2C!; M.<;>^$@ZYW4R_S)X=]3:/[&&,+C'IF(IY;/XJIW;0V!R<#9^ '[1.9X'QJ;9 MX%Q9F8!,\20FZ-BR@ "A:@_$$SI$Z+3$%BDR./!4SD$-L2M+9Y43+VI(O*@V MU)*6-:2&V$4+OUPQ13T]/XZ=3,D+P::"LW#8'Q/MA:WSJ@U164%C[^&WH#2$0M)*0-9CP&]8M&W^MFQ;=?J2^%.>3(QT&X1MZ.] M5;OY^3?(7-JAP@&/(EENGZ+T:F#.()=)G ML9=+GC-N=O Y\G3\RH]BX8P>4!""!&\:RE M9?RT'OY: IS<]=1NN+X5YMVT5;WC\S.L;I$/,6>O"3BV:_N^FMSKU^X7E[3D M6>([H/61,_O X'[4YKC5T&18,"I2V4^.:@5-<5PK&->-4;^[Y%XRWPMO'=(O MU-#HL,G8:L.XMC],5$G=*AQ;/C VPV.S2X_>U^X8>X988#*<'B+@H.*'XOCV M5E[L(.]\>W][B3$%)P@-&R/0^ GI%VP%H%:?_&2O*U"B4(\GBX ,ZM?CQ/X) MU0+#ZOYOH/DO4"]F:;I&S_ORN&M?4W\I](?>.]3+$GS87I:XY_&^/!SW5[=W M_'CVTP7YZ)[0U?@$B[ ^_MC^2"@2W-BKU*!BF\J+<7%6@#?*%ZK]!VJ3I&3_ M!O'6#7*CMB![X*W&_M0M(7/DKMKJ4<"8G_QB!X >[8_A.B?F7RH,PPO=Y#F^ M0E_H5O>3;X#UP46IET>,') +M"&21+S3:4U8F\<&Z_$]\C*)X@_C8C$MC=S2 M&=#N_=*A(YL^@)<*)VJ*S\@J/DO=,K)._IO7O$FX6%78#OICOGK\8N:TF(:5 M=5*R*1J$:F^W11$L/ZO;@2A>X[JI)J5N@MJWW>K*"I 6\"Q <-)CI($KR\#^ MP3TVH\=,(JJTMAC4*KLIYF^3UN$XR1%V6T$WEQV)Q0+P\JJJ':B MSGDE]*,G\-R(U5C>!GRDR"[A]T/#%3],VBP^7+O-G)4+7@AS*3L,GU[HIWF9 M]:+YG@VKM_PLK>\B[7L4M5__:%BT97!B]<.9?EAN(S_BD1ZQUH?!P.'KH>_I M2*.U'VL/)KCF/@"-=H$S$VJT>"G(I3,P/5J?K7FCHB+]GE1* M]#+4"")->AC -A)2*LX>ES[OK^""0J04>@K&\?E^=XO0\X#M45F!-$& KMWX M!=].:M5D.0QKF_::O*'+V7;=@"EK-S$%/6JV9%F[[)%WL.^';KX:IXCHXO#C MUH[$5%UO%_1BLT9,;]K)I*FPWAEN./LLEVK#C^3Z\)K6&5+_?O%\7J1-Q)E@:5\ T-DXG#'E"6@#H8P.3P6H S,>- M3R\GS=#^QQ.>>NR%%#->0W#_59_O]G^!P"6B2$%IPF=O(+=.5O.%_ =W.\+>*\_8A)T__N3G_K)X^A"8^A:);\BEDY7'0,2,=F<%7 M393>B&<5MZ@_KD@@"/:-;$'-OH0LT[YX""&QP.:$VF-Y! M=;$@W&'W&A=I>_9L%*2@>7-#SKQ] Q][O5%^]!M%"6? M<>Q_A*D=/O?=8\_*:7"OP#VCSKUHHR?//>B?IGONQ<7[FUF1-M3-1AJPF5E9Q,D@?=2]?M;?V/Z'J'Y)9_?:R/WY$V(8_D-/Z!OYC?>#/ M2$15/5? G.$#/N=/IP,6Y$5>\,#(.VOUWK<-E>#I8&V8>;@:KC^@^B/(^A-, M#'"*T#; 5J06O]UK$]&3[?>$>G !F]G S_3]UX.+Q&..NR!]0?ILR[,6*3^D M /.?"),"A/1N_,T2DM"IF-L>8;L/+A&I8H7 L2H0<].KVOVDH?B M;XXTL<+MW!C#@II

->T1R/'9WOO"/>TBSYT7E2PW7 MZAG>WFPVJ#B]BMWCVJ]UA'XU[JZ\& ]=U8N]DVP7O*TA=K[+XW0/8]V--E+$ M$",SI$]A(2.!S F>RYLP5P8[F UW ,%HU.3IQ:35Z^Q#N\1IZ3VFS"%HAK_ <^09/\ZH\ ']ND=/<>4;883OA"ZW<)4[97+S89S M>KB_@C37^GZS>:/O.\,FQF\DT#B.\5_:-GC0!^-N]ZO=JE(NEV X5]IIO'HR MF5NMDDT%=C**LH"]+%(5(E"VFOBZ]Y@P)E-:B>U!!H42*A2(8 /A-Z^2GZ\6\?"7'IPT[SOL[-@_J)#3@Z.8/:^0*,&@-_,P^ (LA[?&K>;]FM @T([(@]L%?TI_TE-+O,J6YDD$3_CV'E>AI5_3\KM3K8QZT:Y0R M%5TE']D/W2]_@06\K3>0X%B[?0IJR<[.-7"R5?+GM?LSS8R8.NGSZMGTJ5-< MP(#^$]FW:)>"??OL?]H?=GO!W_YN?_B=*4&+M^A$=BK=>&S@=+4D2DED2^5! M)NPRG(1>WT>@G[5CRE#%__W1^5/8!(D<(J*D MF<"8F@]9*Z&OEE9EK;0S2 2/U#/:KSP%9+7T:&B2[W+BG4_HIGJ"&>.HIE6A MFF9X0#5ZPE#$T;U2D[TFCF*V3SHN&)<$X\R+,UTP7W_Q_6?]+ABV!OI%%>>; MO[5*!3GT8.'97]MYAW*GUE4'L7%'YL4C'"#$V\[6'V?W-WS@N,]9?Y^G]2H_ M:I>\W]#06ZQK$@>.'SJ9-JQ0G](H9-5-I$FP012Z4_@.NXI^#1<8II^0C13^ M,:,VD?^L?>Q7$#N[TUT 8D)Q7>'0T#9 MC?_D##AC+3@0MO\3P GM6.W/OZ?VAW(FL:WT-KWD^@IREE7_%638+@K2V((X M41;$AS&D8LX3/?<.P8*<)*#!K+V=4:L=U;6K3D6)5)#(N"C1#SAU=5^4B"RR M[@RP5;IP!AL;6&_AM!@J37KD5=T3?W:9^?$J2;*ARTFQ3]^2W]Y0QA_D89+U M^']%68>)F'42+LK1>.SS8ISK98GL+VMQ%P9^YA^ _95QV)7M+]QR%+)A?48V M\THV\]I5,E'8%_?9HC^F_XC$G83-*[OH<.>Z$$L3!LAQ@*]LD]WGH&IL=+24 MS@&:@2I;2=VN+N[BM]+>5WGXTP[DT%'H13+SX W3--%)]C7'R2OVK:QQ%A&* MR)!>QW71->-)#D;)H6,P;\R;,-U*)<= V9D$87J"Y)AB@,^0(1(%R54"TV\^ M6>DWGZOT_CDMV8Z0'"XR&TZ?5M+<.;4)$#B$*N"7W?X&UH5(QJG# 04_'(F/ M29#.3IH]Y_C *UY3(I2R?UC'=QM7GL*-ZLP@UOY[GP+]V&IN2N\7KR@^="GQ M2A\VF0X4J/YWY^&QTBZYR[(;KTF?33@]Z*&=]Z\M3HO"\/FH* W\+,ZI9?[S M4"WSEZ^>7TW,'%$/H)SY"LN9OP24(L*VL8:**V,.BIMG !'@"IM')PN;\2US MN%-H^CO5S2-=W6R?/J>^^2T6_]3A/G_[2+#J='WSP^7-IEO>_%8)&[\[4T[9 ME&]=WFQ3,V)5/UJZ]??0;> MK=M@FZ/S\ !]&16.DE+HEB9D,3]4=UD1E$)/!\).__P-ZNJ?*:I%9J <(JG! M[51#+X)JZ%&W&MJ<4PTM,3)?#6T&JJ'3H!IZU%,-+:7.)ZJAQ0KKJ88VYU5# MGRJ&-FR:!<70C.X%??3517-9=%0;R[759,IQ;:+*?SNW0'K&=5--7X"W>O"9:K? M&2J2YE(3PX4DK1PH]$]"3ZJH.2R>+JCB$ /' 6H]%$]#RTY!LZ^DK:%X>NT* MEV%"5'PIKJ2M7?&T7$=!<,HV7L2-'ZR=KJ!PM@U&T*UD=B(P&7'-L/]0JIW& M=JJ&6==.5S0](ZC3;2+R*6Z9Q2VY=CJ3N95?U5'M-+;.AXN/:ZZ=AG6(2IJ# MVNG:UT[CH^7IVNFY\>-RY=,K+I_&#E2&6EPQ7^OR:7QX%C^L/T!53^/7SN.' MLV [;>/.K8UFWFI5N@7*[O"X?4 2LAZNGC9QQ0>-:JA.&?[K$FQ.7SV-%<#7 M1I=/8P^=&F57/GUJ=":JGUZ%PQHH44Z-&Y8O3;[J*4W&3E1:&E6=N^II-S*N MGJ;C0_"C]N= \30NAB]9[I\P*IZN'R[PQB%.@R&.HNKI1JJG&ZF>K@V73V/K MF4 MG5E^35KUNRF_+N3%@^77)5<7_Q/+KZ>S<]*<'RR_5M&?QY5?DR)_NOR:M/B> M\FO6RW_SJG=/7>Y@^35KXMWRW.'R:RY^?DSYM=6VH_+KN:X-YR+LE:Z!UD78 M1L!E6T^GPD8:L%MAI( M%O-ET:>JN(VNB=95W'&^7%]-M*_B-GU%OV%-]' 5=Z0XE]9,,?#S ^ I*\JA MBNB3A>AA.71('JK*T$U8$/UP&3JHOL8]?*H*W==#RRA\!7?O8LYU(*!WHZJ: M?*_G@@FN#)JG17T8"DW::I2RGU^);?IK>26H,,9)9VLC?Z^ MDLX7CRWI9 VV QV@2SJE_.%D*3=!X71*.EEE_$V!7)Y7TCE774#Q5SDQ;ZML7KNB>+N:6BXF0Q=XZJ M:;>8N^""":>0GEO,31KI/[.8^^$TG<<69*]+1E3-4E/[E*^=U.9F9,SYC55T<8.YP+DB/ M=BP+OJS[RU?=;.69*KVV?^?J;I"$OWZ#9T17>$?)Y4KK?:# FQ3PX"U0#6)[ MQHZ"*N^@C*QVNO9UM\2;-/6HQ)NZQR+O>+2]==ZLW9]1Z!W75?^^2F\_3ON* MW7BHW+N;(\3UWIT,H=]?[UT.]".UT.^NWGOVN,+JT_7>\[?HK+_>6V%MOKMZ M;^W??KMZ;[8;^NJ]8399P1^J^V;=OJ_N&UN3&[E3 "ZMR^Z?BZ"(9+#@P.YP MKH*&V\X70LL1UQ4(_<7@E2H&3_-<+ 8I!F]=,3C>H3I.'5:#X(MQ$)[Y_.HX3!LT0K ?3/?P#E08>;C/IP&*&%0(> M[/+LRG#6U-]!9;@J'GA7E>&D]/^^RO#Y 'J15(:34O_^)5FR#<%*%^OVYRE= M<8&6UOQ)Y$AIE.-%B@I8R8HAK_9;*7K@6B9S@3Z&'=A7$/3HEQA,)!5)##,6 M,\&EHEQ##=4U$-B[HW["P CJQ.56_.;%MR^^^.(SB'E0H;.[*=?!15EI'WG_ MF=-@H>?7M] J5)J7*KQ*N+Z$C(QN>:L3#6Q[#!=,)"B@?,4$&QD/FJ9T14DM M.Y9'N./)R*[P?<^3FJU/-A(^_?X?A_O;UW[,4(MX2]6*G\)Z?H^!)V5NLNN] M.Z(HW1-83PW\G'\ 9L*L!T\?(_7WD QJ)_!R=X_F A)Q'NZJ:F4WQ&J\N@9PK]V;F8XMUB[ M_0FZ*+%0;?P"3QJ+'B-OY>=]BSIQ?&CK5G(!.U9;$(%:(.8&:&H*FBJ6@L4)T^%$00SQH:M,G MY(=T04(-P6T3Y!A>>>"0:UV?W(,;8AX!HCHZ 1QBSD(.$<.AKRY50%([+XYA M](>K4OO00R1D176M$9:^5TD90*2(T(I?>T!Z,@YZ,43$-(@Q1'H\_B=M3^.N MV0A$)+A:6UUEW _NK1(ZWJ;@U2@0D0#J0X,AG=&OX8X?QA#1=L+Y@!F#&"(P M!VP2/'8.SL'@8*OB'8!PL%'2![>!WU!T_ZQP-]@"Z0!O2.MI]\\+U7K6_3.5 M[?JD'C8!3I;;/@#0(<17#R%T# )TF$&$#E;T'X;H$,/K%$;'$$2'U!P/0'2, MSH7H,%(0G/5TET]V@Q =YA1&QPFXU\(EIC^$T?$ 1(<9PN@0X^1,> VC\37F MJD2:;)"WZ<7MURN=^=Y55!H-Z?0>6JP=S-*$K%E,FB@DBM!D7UUN^[Y M*LZ3'_7AN,[M(.UTCHH/@*&KF&L<5_2^FG%MC-+V.XU=E@XI\H6P'YP!;,-:_SL'MF$SX2%@&];V M>_W, FTSZ8OX]*+;7 NZ#4,=S;4I@07GF B;ZD1<5O,?C6O3!VOCMB(;"+VV MPX/Y0N\$T\9A'0D;PSD &B(*&+RF&TXZ0=7@PPIOC0*CL6OZH&M,D'I^OF2) MD&M, %T3)*2?'VEZ$+LF@JX!,\Y_4M#.@;!A\Z(#/F,4^LPI\)D@ M./(VO90!A WC, VAJ'G*AV&/;) =\S#SPVD,&V7GUKT8-FS_/#HY9AC#9I 2 M0I)C.OGW[U_VJN>C>!#$QA"&R>@!$!LV8B1B0PG^Y^B_0_^)01@R3@@$IGH, M HP QOZ>$;C@!T' 2+3CT1@P1B:P'P2&+8>'46 ,E+ / ,].! 1[5SWCV, /WLF/NB_7)2SHMZ+92-:]?OF+@GE0 E) ME@9^IN=@V7RBL6Q, #/SS4O F8G!;+YY:;=F@%T#M12(:',N?@UU#'F.&B-U M$,#&/GX2P::3H_"6MK=YBQX(@8>+%_Y_!)L/&\$&]O;:X=;@+(2P-17- L'6 ME );<\WH!7?7!UWP^OB%ZSG>CULXQQ;<@V!CORW-P SHA; Q F&#A8H1A UH M6R&$31-"V*QUJ:Q V&"1G(*PR1>C'@B;@H!;-'Z#*IP5"!OL*X2P,1K"!@L. M!<(&:\\Y]]<:.&_:E?(G-2[?RT@.6.W2PLHLE]*$+<2\\'%T/ZT9W:;666*U MB?DI(!I*F N(9H/]E9V"7D8QQ%K)&YUUY+_E2*&-Z4]J2F8(4.HQ;V;IR&/> MR'__R!G.IUW[;R/JWF*;]MVP7+[[>-?^VTKLA\87A Q@1X G 8GC2:2T*[M? MVN,;@?8XKEL0/Q(3);$%F;@HS$)8 7GH9*AA'$SG[_F>CH[1^58=PHBP?,HD MJJ8H(:'*P,\/@&JB3'50PTJ[?[Q$)_,?Z-I%DPG^^V[V]A_[ MY?;FM?VGG2;[&_OSZR_MCR__87_\[>MO[<\O(!_H OP2?P"9XG))R#9Q_1S: M_ZS.[0>%C,M@.->T&;[JW_K6/ZD3>]/&"JEYKR6BQH-/D5T#&%77?1A5\,B M3:,&$QHT$I<8P*A*%$:5STCJ(#HA07$1$#54"L])\ (J(XZVQOD$& T-##4" M(M,BG3 J-"K/66A.#8.68&/-&1< .,&!L5."-Y_@&M4"X(1-._@\'L&I 02G MVN$GX02$"#U&P_DT#L)IA8+M.DA?4/S.792B80RGFN![U!CZL'LTC-TSB!#X M;R4,)VR7QJ@ZM"JUFZ%_ ^=X#6X:CQ:$+3MX/(SAE*OIY:4-,9RP=0=X1\\9 M83AA6E01P. $&$Z-QW#"1\L.QDV X;0P#%7C )SJL=MK 4).=\T5QI+!IU4 MHCM\A>"$#ZLP0HS@U$0(3OB\SH)"/*%@V^-:DA1HAG&81-=;.U0A$Q=,:%@A M6*Q+Z,GC,%6(PZ1AF!#^)0T&IX[A X,+4)BL0)!AX:A4PM/ J!X .<)>YNL";35T@RMHLO[ MNK83[XAX/_F>PNOT*C;?_OCZ=?)'7;S-R#YR/U(G6.3]!*_ Y^*LOO;3M1ZS MXA/52OLKV7O030 9)=T/(D;5&IQ="J8?A1A5DY. L5O Q=A9 M7#5\%G06J[?G06=)3L[YT%F@# ]&SR,FLD$0+(TW^2 (EM9M'P;!TLKL*1"L MN*:W/HT@I377&$+*: RIN"CW00RI0"%]&$1*JZ$/HT@IU5,*@ MH?J0H5CC[*#T#$)#^>2=TY#PXV0].1(4%"2DH MM7\/6I,0X(2\KDVUW&[>Z!+=QWQ69S5<02\Y?!UT)%_'<%V+A3R$#>DQK_@B M#F AUUZ?242?$W2@88+@AYV&C_)4B()H!1[?V^29JSG-%(,$:OD:;U00D,;5 M!F(8W,QX8AM6+O\%GT#:J_'9#Z2>XNPW?8AC+.E1B, M>J>S) 93W%6=89>Z."#%TM6LP^ZHWRD&ST)C47YB+Z? (+F&HH?=W/M9L;HK_\<\[*W?16GD*&2UP:O\ H:$:DIC7Y)W^ZA7<^@G" MTZ#S^.LOO_S'W[[^]HM/?4VSZ,S#P!,:96;J'-&!1>(E"7MR Y3;M4+9.;-B M=7B)'Q&)/[E)PKA.MV)U=*)B]=$:QZD_!1GQYVD.!"_6$+Q8PX!V1BL4HI^? M5B@JU"/6^ORN6(^X#O2(DVB99^H19\V%HQ'3S%T>_6A V4!O_$SP-7_LZAJL MTX>ZAF!M2BY$ ".U+!B!(?QP$(L1Q..3-AQ2!@0I;IPCH(MN'%($?'ZD(@ YN8D#" M4!$0'M]3BH #90]+)E0:202]!_,)Z]#V%G(E8G^ )Y?\L M _WY\6DB;W5N!RYPKW"P(N_%6PT*QSGZAGE8X1#/[C]=5)_22SSBIL;#Z;NR MS7E7=M^-;8+LEK.N;/0LF]-W-BOJ/9=V%T3S_>-W93^S)++/'DHC?SPA/%I( MI-\S@F([#)_XS><:,I.SMAJ-RFBW30>REA5\_P1 )MKOWL'()QZ1<;*+^-QK(TE/-YPTM1Y4 M3"//=3$JIP9^?@"D3V6A-?APFI98.0CKOAM_ Q4;>RS;Z,>>D]"S@K TO1B6 M[ (/7U7!U6*W%/0&B[.MX0+'0D03(V6*:_"F4R%4JJQSUO_[=J)2_NE0K*4F M>K^[W-@YA.;]F1TL/LDLT)JX%&Z8\,,ZL%MNLB+XS XH9NC"]H1+I$[08 1; MJU8HE+'+^S$%=OTHDP$1TR-@/3S,9-!9V=_9Z8+%/I#)QP)IQAB3I@^[X[&( MFH;&Y[0#0#"![$G FMI7U6EDS=/?K/MTHV[[L$RT:W_]0*%C'S"F>/O[@#%7 MO7B8424CPV":(9#-O+=5T?O;\B$!:=1,G;UR/FIF.!^$(HKS\7KR9.+AV:]$WV-[B*R8$RJ9! 14T5+K M$/Y' <)_/W1!5-W: Z[9Q=;,9X[BY#QLS5YH3:.30QZ UNQ%UC0]T)KE +1F M/[*FZ8769(ZH7FA-@NPWO[?PIE?5>GP/THU.L1>+[E'AA%AE1@4Y>32RYF/0 M/./O<%2QI*OGOZ]-A8SZ$]4D,>K-S'P^@03O(H.8,:%!W MOL@:Z0$5,N=A@SIH4.^.>L(&&4@:LF?.0 <] 0YJ !U48QI(TF_3_R?CKD(VF\ U0Z>'0OXARJ;VQE!%X+7QVE20"Y ^ M1 EVEB?Q49_82S*FH4\ID]2!GG+M<8]A[>ZP7F5^),BGUU$]FO&XIVL-&736 ME63. =TDT\>3]S@\4)#5(85$QMSU.NRZ"+H^ M$R;U0?A5HZD,'D ==0/P*K(<1F U0PY1$X"L K":1^$ M:N2V6/3^%@ HS5B@H1;=S@A/#R[."&4JA/84C*F)AO8DZ^CE]X3S-@6!1X6R M/B:2NM#.MU8WNJI<;.?*!W8"^%#VAO!3U_A4R]V"7)Q*N ?#/VB)9.X=W_WU M2[!X$_3]NJ'O;F^=8#H%1RK /B+\TJRSO%0U'7L#P$YRGD"L B#S![].@&2] M!X" 9)O' ,DJ8ZOS H&%K1@SZM,+YY)HHC\"GNS@WQR>+%E;7/),V;!'CQV[ MEG]D/WF>!..>SW$O'3T^K'N^=+B]DO7570730QKQ82W0"XG8VT'4_PNWZ+T+$-O%AW6$R(^G%7L( )8-LAXPPP TR9P; MX(\9UI1'*Z@6'O9H=1U::OKO8?[O-!?4J(<(CJR>WE(EE9W5T1M=8I8S3=X_ M(@LV:*12(/V=65J=S]"FBT^0:3!!QJN1D"&SU*RC*Z-9&MDXL1OP>KP&W$X! MWVLVNTM,DG*P-760=$:6R[O\'!>2T746BGN5F1D0^ ((P9D'/,"9=KX#P'CA MN_80J#S8Q9F]FY-8T $4M#(V'N&R:):871G<%#0#&J+TK;PVYT%+ZYA2%UK: M#&)+/]$Q(]F&S;O _89,B_/-\THO$O>C^+DM44DO994+(E 5*!D@' 5L!8)L!!&S%*\FZL =;MA+ $V2B+4;?L2# G\!5"WQQR\8K#D":3^DYJUTNS7-YPK M+_!(G2F[$INA0"/G-X_K^INO^7C_(*H&PD#.#UJAH&M@KZ07LGSEV*CUI=WPP!]TYT M4MG4\[*AGA\$GPC981+$G7Q3TL3?/Z!!)ACHF+TD,UBIUT"_K0/Z=84:C]CG MPQOV+3ZWY\N[0+_ST30Q]F>Y8*#?^70*%]RMW42KZE<*+ZX07W+:Q[V%'+FNE]O?^U;[K;'SUY% M[>V;IQB\A2W2;3^+VMM3JELWW'K>WWKN6]N&M\NM7'7W%[L M[N"SK:#J;8B_]@U?[;[>K%Y^K]NON#VD??:TAU]S>ZL@OMI]5?T2MF^X?=;? M/O/M#]7QTZI>WF^.G[?59B59F7:S8T4!QU]CKOG&\@#$%)TN\?4 M3%J!.9OV]0._]OU\B3?RR7[*_G[*L!^J%#F\W-:[@7ZF_?U,@WZ^9D4 1S3A MD@W3V2=67H,-V.T-?NU[ Q^M'\@U'2VK5O0VG:NF9*<'WX!-%V#&=9O"KZ7I MF]M+>[1??O^%;D]GRVK%87NH4+FS-GU*?[%=S+MR24:09RC>!WM(?0]:+AF6 M2_F4_#OY0'/X2]#\NWC^JG%>TATRU$?>Z<.+-_<9)94'#O51J#Z;W>YFN:Z6JV@* M"O(CI0,]P%^XAUA8BJB@02P&NUBH+@"]+)S%@CQ)<340-\:_<&,G;(-=6*2# M;=.@;2!O@Q4HLL$N,M4%0L6JUBT//I\N!EK#7[AU++#=-L8!%(-=%*J+7[;5 MZA-KP=QNXWV,G92#G91A)_M#. K>1\5T.A_H /["'>QWO]PN[\(.9 2SP0YF MOH/HZL&8*=T](]E0N*[SZ6R@,_C+]T8ZT]>/7&-WKJL28\\]71GL"O[BQZ5O MH*@K.BFF3(9&A7]17:E+R'45R)TRG4X'NH*_J*Z^>7G'EV*P9@66)@YVD@6= MZ,L,RZC]%:L_<%3F@QW:OQC?H&FR,SO3]"?IP5]K(W\K M4 ^1LJM[8(77]6"W8K3@.7=2A$HK?0=U4D2=?!=_32UC,:3[QM-!W92JF]Z; MMO&CFF 5^:3FD/%. MC=5DU4W6Z::K/+AN\L%NG5 C72SG82QGUTM$B,E[> M6"U6?4Q]'P.*A.LDTH95)ZP0G](E7"_SP5[FOI=((U!S&BG'JOG"JZ9#2H'T MTE&172]:1=X>U_MH-OR4=G1DWX72D?N5 W]D.JJR[T6IROU7NQM)K"K[/KRJ M;#J&871+5'Y,L=K\"H4T]*?4YHYYZ.]YMV5,1XGV0U-*=,="].:JWWT=9=IW MY95IT[42@V'QP>[HU?X+9\&P D/1F]*=SXRU;#\VI65WKM9K&9#IZ-B^ Z5C M=V[61@2GZ>C9K@.M9X<7:WPR._JV[R.=#=ZKKA<6X1V5V_>B5.ZA:]7N046= M,2[GSC'W:K]L-]7>5-N5N3]4^U5[=1S]R?[KV=J*K='-UAZ2_Y)__M;6MLEG -7W]N_E^ QG_MDW,/ -N5 end Q?ZL]U7!MO[O+@G%]0CF1.^_%J\NJSI=\NOLinSol/doc/wrappers.ps.gz010064400020550007177000017265110663201514600167040ustar00clevecompmath00000400000006fh6wrappers.psa% ~_EؑFh9S3]jŽȈH }F#]`[݊{9K7ha?=?˭|p_LJߚ~/>G^|w߽x o?>߿zڇo_^|{}G~~~-z[^o߅;Z;??go??s?~/|ï?~||/W׻o_}^}~3_/wy{|o??ˏq ?=;_ȓ_?WOz7?>oït>|Oo?yї/|x|?05pć~xSΧ/7[>?jq??Kxx~iyeۗ/>~?{M3>~+}\<}Ü^|?}?<{a}xӯ߿޿>=??><_o}x >O޿x+G8㏟]׏~>LO/?M?/\_w>t翄÷o}ߗ׿_R>?>$_4q_?=w>ȇ_-o /޿G 5Ƕ-?ͫ߾|+z`Z?|W_{|~)~~?>+ #vz5_׬;i>O/ eNц??~{?s8q_ty>lӴy>ߟ+^w_XʋO/_ym5]^l#~FOWO&ggV2W{7s?Yp??=4_wŜ%<|祚sKx巏kmorNI@ NW/_-߭בkOnrro?{ cɟ&lr7n| \OO>wÇ<~woz;~ Okq =|ͣasxd䘾:<jq,U?կ2݋R:GFX>O_?>oW/=ϗ.9󰆟Jxsx_/x ~N@`}ZF#mٷCoӯ괋>}Oq=W|z[>` ?q2?G Xn_Ӿi ߿!8|qsOIz8o?~z1q>?[R6+Ow?"#?=駯o0÷?~~_%b,o~wΟӧs;^?o?.:u/?7G?<)7$WxOdq)7> XOo}8NwRCż,|о{|k}y~U~7^~_><4ʯyv_. i/nۯ߱?,L~!-|޽}Gկ}4aQo {:O߽~/x?K'lś/oS?x|?=?~=lWr>O>^" ه9,S_}qUb̓f}"Qmn裏/_綇~|R+_?~'+?<O|x=~3 ͳLJ_0^.Ϟeyxzy|{~Z?~|/c3?=_bo=Wy#*_ ݇7/>|9nj?o+ӳ/ fnt/L.ap؎4՟Y +[4/M,¶Un\DV\nZ1e3Ê/*nլUAk6&ֿ0=%O{⻧#l~gk9|OO1߿<=wx~?=[?ڗ:߿ yٳgb'f==b{K2?~wwO#|/g2MwOO%޽}ZoBkӌmg1Xw>(1Էҭ6߽Yg3x{zq?/~U|izӓ|O3G |zЯG~zĘL6t1cG {zXG?==b,cO>`GOo1zzXӣ??b,c#<9\|z4֋-T26|} O8/䆧_7_iU%^> Bgg62ga<0g40= 1볇 Y8 %FgCFngg22=dTQɨ!㳇<{ a|zgx͋?|f峧F<+E/?_{ᡷ 8#?}5NoBB7s 4v%*wX1ΐϽ>[;XR1Žka-޵2y[gږp#w&,ArBR+SUc+gض9ļnUk;SH3^w8cHgO}zJWs=/v>(Z Ż~8ϫ,ka~3pȝ'#{7 b°^S18W~a u%Й- xG`cR[d1u=45̎eL7aekϒ3Uު d!(L`K >7 |W5!>ehˑx;Pˆ}K#O>B<2ڙwdR˅!ccM}P{ v&Fp'z>:c9Jf#;/k[R';+3.p|ZH䩣e=6|@m H? 8#L~?%-P(cnv {->egXb/}̲gVc=F {#WݏoKGjgY ß֣|k4Vo4Q>ƲϬcggyM |<͎#ܠ-^s32ù81BJK܁O,+2 LIJk^qD뱱]ۭWvIܶ0C#}ԃyߖrڕ^S..;cpIpc"VY.˕f?aoq 9o6]ignObE1¾>*['ޘ5+^Hb+Xr0'LiX0x]穄*7FKis ?O˽NۈXVL  ߸:q[44 'x]s;q`cW7|8/k bm`at2"\LĻmaDÈiKϊ-1op5bM*3’Xr>i;x 6z1ZFI+Nn7>?Wݝ)7o댄,1J/> udfū@$,Иr{;4r!ߩ:[nƍWčMg\ J>c`8uB,@kw9,u\K5@ l(eXՏ9d…Su-R G+p7=/ ՟Au2[+37Y^ ȕ7O 3Ћہ,_ sDgv6>oδijg&0J,VJ\҉"(Ӆq 6l ^پ G'fNXphxWe P$1]ڌwl "f@x5xW13Ve6/猨@_D 8͢.\'t¹h<:6A/JX"zb{&qL7Ѣ\*&0A `v8dgJ5T!ދY6V3sKa9aVm7& V9o ~ep֕ 0(Ps4`:_QYBH7&,0F`kZu.džqܔ0B9Fo?'A)u*U %.s'<lLh*'VGˀQ'%k%n>xϬ ;q;XKE):<4bw22k҉y#uD"]M"=v ڻ1X <0@Eh ! 8&u>]N+`Ƴ:޻d ΒA;$ 0 ;Ν-cmkֱ<`bs2kc#jy-a(.Q^^KX\AH+ $nX2=q{,>Ҿ&$ 7 ` K wN`6? +ʙ:N1p4 w%NY,T/F ]̨;bz.hIok${o_1lBoY]sC 'kȗ` W#iz8Hlc,lΒa|8gb mb5_WPlP[#&&@#'xWNJ4{ #$/`Fh$BSt@ JHm + dev1w6^ = 2 ltSWbwezaN <Ҳgd/D?1*"6]6Hw2b| ZpV0>=( =AdT8.j?!K$D#vLHýBDea'B b.w?=;f7lXd]gg1/ a0"|57vW,Άv3Dhsǃ+〿a0qL!gPA/'y+«pzpl;U0(1 d_ HQ[WkڽXY"8pQC$W <0'0Nԉzg&y4XMn( &a4Mou!ri 𖨙r?pGEB?Ym@6 gZx4OA3V0NɯOZr=XVcax:ц~΃Ex,lI}4lmqIo  h,zS`orλ4xzxL{lsaa~܌;bq9ʽoiऍͻ% DЍ>"X*k`81w!Va!HCK|璆/vzR^ d@2`ٽ0BĀd|X+TW YK/݃<Buv3膥jv8ƸVhF [ 汼e$lRg3==v,I>7 ){1n% Rf68(S&F0!3XX*1Ň'әSfu"*|wOHA#a"T9xغ(zyF){Y>`uӕ<5H̗42{^$bqg*@,^\z_Wf>d@/ϥ("i&|Ц@<7=!} R@L Xٟ+|`K yu/W_=5ȱqmڀ``|?f)'mٳX\̗9HBpW7ַ{%fal{Ɏ*[^ЀD_7xKM2\)y=/}0-ԝxT :S0=vpB+B[j{ l88+f܎0 >i&2CWT_a>GB D1&JA<H9b.Ej'p[Nq6Mn ;׈]! g=ς M*B:z ;nKuã@%aRf04qiO CPXyW1x"_ΏKnmfI1|y!y"nßqG noǟp(B0= R2_c*cGՍ4V`gؘO@fb%|Lj{f|NY8Fe杔qg3 N Q;NDON 2@X %͘Y+ 衳of SbŠimv1%/,Op<;mvDZxQ^D̦oi0])ޤak<d%=^\@c)P=6ֱy ?* zðNmCw:kpt({9wPc$+V^#ƌ7\''S-xPTI3fH7S lkǃbrCo~tx&[NXF`? UX=Pf ѬyfbyY*s8:6 Oh9Bm:"0OW8I]p2y{A W6v鞂fռ[0ptsލ-؂MOvx J6Վo IW~83HK<8sH-kxN]bL!'r*cHgfZ ?œذ1ôP, aM<8gśtX#* xizC7\.&ӟz_ v'=5rȺAו{@Cp.yty3ooM: o'T6}=HpB=ƽK7lyamǨ Bo+NK*i_HƼz@@-莽ܣ9-j/DyWU1'JÊSٽtNչ;T 칳7L[\*'CT6^*n -8鷳h;n&|A0T.1mC'vVXةT$bǛГf|ی]U@Lf ]3߷@9Qf<_$BkMa7S@dZ@ȭ 7LD L`yd`}gYFl^d( &ه0hQ5$X OB|-,f!wq0>`Xf^*ˌ@骀|]y:3༒=eI K汎c-=y|1*QM,Q]b@-vJPA>f><+37{,“^yy|{Lpu!\F {ǀ[=iv0p#4h~zygQ>cQ, V Gm'|ih59Sf wŬx-|.R# {e`6B+G|eA{R+"sVM ΗX$pM f|S4o`&zyr&cCği.q#lhL2i]͋>pG\2f*yg=6kVߣxe:n+j vNv vMG:`J>g˸ ,ׅ ?dTUkhdm3?ٺ+ZebHv2Lr{afV6PbP`+,IY[C}3& "tKbwia]BFQ%Sds-k:k5\RaaY4BWafch| ,<.v c+iz'zۙ ]4nGs8I.W+ ai+Q 7+o3n҉kaRÝy{:zh-Qkֲp_l}$|wӊb["DA[{ڞn!vþd9U{ȼdept\ beNX_t_<%,9p83- JwCJ2i P#|UpjÃ8m XJeԔs2r*cISFY\,WH +jK.`_r|?b>nSww!g[z,H&B܆#Vg_b^\G@XbK+"Zw|}zJYU 7X h^_ ~c/LHtU!Z&{%Po^0{S v#p܄La&sQq-m0X`> /.=Ņ^^VD"f}T긇wb#XRXk8Zΐ0Ir !wBfm.O0NNo7Е*3|x7NBDNpd;ֿ6ej Aw7qŖ ČZ:$pńZ Xoe5^t;ˌ}X8n#zc^*yǝ͊lowx1L v6D Yd傈R [=FumQ$y{>oZq/Dz8 U^-ng4Gv,Q5+&oblÉ%XGd@!Ӻ!f2 'vT Ȕ>0 p>A\=SD#f]w3{,`|PC3mYqLzXpȎL7E8MaQ~~S lN|u]gSE= ~g*9v`7>V9q<'݀N]W $_OQ,n)Òϸ$ۛ]->6^8fCخ7/Ť{f<%zi{k%Q` ۓ?LيVKO-,vn1Q`lp*L)f_+K Yv)".VL<p'4eghI=|y5:ʼn {nB*̥Ď.i\* Ak؀|I0Q2{`VOxl17~l'HR#nx8 HY|{a>dcM+9˓fvVz[{a۽I o[VdU5^N_LԖyksiLO{ g,G/\P1=v ›lgͳFTX|]:Z`+gQpy_YITE*KKW1a1tQN^2@8ͩc=啢eÙM#Xk(k\ dV(4'6z``+%ބjO\⇡ރRxy7 ̈5Ӻ˜348g,F_ cWF_`ϖ!)7m4-`Uo%3 Tk:Ul<\%ddOu ,JueӔMQKu!m晱zuYeG%ˬQ9ƽU3LTR)?0'؏ ᾁE y.+yp[C oU-I>#I%eL`am\2Z4s׎PJbGīъQMA{7Cu o@vviqY [BOda`17԰ydp&`y yv^|0#=T=_AfCf3=sSD2$yTپʥUT)O6OY$d4yxѝdE&v祆U]SFcM~G(AESs_oVЃ`B0;/B GkU#C Q:9FYjw`0v&]ޮ=(a4mTj/wCX싙913&XV3|9J(%JVeƊ2ePV{Сj;)80oվa[V?b1cqI ( ;Fр Ƕ4򭘍RK:Zv m`Y+xyancnl#zEjW& a.ZsqB8qozOY>1 x,fJUK~H26xN:O0 JVP `uign˩m-w m`cٻ;db2X:;.PbȐ .,[ exSJP_zéK15_1,TwB֫b9? &#٥~'8הc,,ZWv~*u#.(?%k7fED J 2̈́U!,rTzhf'`HpIR4BYW'Ch5)(xP6 &&H1 6bwNzS Gtӛ,H}uj^ ma)vFa M0/ V%;#l$ Lۺ%B⭵I{sv;Csj6Y/Ҿ49YAw 9~l}74Qp5>X8 %H3xw햦bZWEm A/ c5bٳ[I} TxdSXm]P7l&+_tVaƄMY$V,!Ք|XsHee|;bevfΠX ' RR jc*ڄsX)<cxxzV40! {W7I\_*ުϜ~y)AA*C\ )ن^CpdJVr2&*pAMHEu~q]w.<`Ȅ;%O .M|p^BfKr1d"QLO.o7o:}1 6<21?d;h-BHikSt,_-ʮR@׫zͭEBNJ fQW@ӫ,EN5'ȆL@`x &qdU d*OTVZ2aLkùգPtN"0r"M6Bꒀqn] +=oǓIr-L2IA3hF8 6km?939xE>loUjY>Y1u&aa q9pP +\ ѕ괐ܰ{19mJs3O*avaBg'^ƄoC\bh50W RU:B]vAufP؅L |"NnRUhVZI+v(* @jE f]">3E`j'! ,VK^w'mt4M/\PVu14@`zzwG_՞a Ng{7w;2ڔ4 -WR$ܧYo[nnlҔW'yLSa3q@EaO&XɯG?+h)E}@]"t1MNNRݱ1x@5>cQET|8+%uΤ Cz+뛣x0`0=ݴFmj\|g̉Tc3u 2 ~)-b*I?ӹ\{O-ja8W[GGu*΃AqOL ʻXu<ߓh9f+ͫa}m(4^$*?mfZjvV0fɆq2j}jG@]j D0`;wgv%LP/-yj ߚ} .eLe)R7XfMخ͔26!{` *W }ʘ؁D(g;1vP\gCPdc`LiiLbވɯ?R*(P# .q, 24.gߔp6:,ɜB0 8lR>\V3!d!Y>FQR *)Ѹ-eXoUQڻ͠4zar0S*M<ú.[3\]"BD/Y"s&hꍋ&"b H1H"^=վRb/TSElqB dcǡׯ`WQK zB7 ]`\gN)SW ~`MXv%?@E11pdfc{!ָTɲEgvY`rƇ,Q޻8ge֝ e6\ͅD%77{; N̈b˞g@246SҺgnQ9 aի3,_(Ȫ*J[Tq:uO+N'{Sl=cvո{iwTub9l:c l PōIxڼVT+1;jj%y `yZ\U "ۮ̼j?!&+ʢaUBg3{YNK_)[xv1oSBzh)`%6GP4eK&,ÝY+ Ygr\JT&x/{6WFXgzS>n+QY30p.j㚦 >ql}%^/Qdzc(mx:G!CTq"FUܵR`s 7=ڜS9~SݣSeX)W" @$uMS֌e n|P=Xz ]K8G߽ ^6Ɓ)+rxՖ]IQVߜ` 6R7Dn"f%!II 2nj)Y3e,apmǸ!lev&ܺ-/VMC2xb|SSJ'cݰ%|iwŴ,(p5``cz2iYGv{b"22O@4zX6՚m3ΛiLz$w,HW n[<1jOsN\Lδ|w%/^AX@z ? ^K!3v>w{q>vL4n4֦$;4fE5ܞlV.,9/㴏Mʮȡ/;58T qʹ q]%d BZ0^XG& U-ՍP\+Kl/&Nx*l֤S:j4v'U<8ªb .bug\;{:VHig )bf<+ OgVNg̈́4 Ca͊RvOĦaPuY2|!׿Tc["{H(°8YMԨce 0&Ę}2qL˷SPPe\nBEWbdٰ!cn^0 b!we6&;K u/rh`^Llm0c'*1=Sr)h/z^VNYzQUЪR<ߴ^ڱ RV˗-]k7{޼&[8t?;4)teT۳}h^f{*:Ɩ#[K !6+S";*yͲ%y_dB6l{b(m~zqլBg@twS?j2~[pY0ykQZD t%,h_2y- ߀XOM=gNc1/٤[giyWg'X3ewIgJ^Ok`!ه-+-k0qT!e؏c7o 5[>/ Swc 94)j?=6 O 4fv6C=VdAlƎkxLgUrYnd//B&h7cG*Y0Y-D~4Vp03p^6l=yL{rg|2{;w4ĻS,#Ϧ8 ]-H +`oDjxЗ"j:1>(`-0jm{ S0\7a&{m؛W5GkOx61)뺁-%gtЗ۩l߲=} ؀r'du[*q6Sks0NÀabPK5{Y{QZŜigp*Z0čSgJ|>KPсdzz؉^Qζ[nu,Ko\k@XӖʕz lkjΞb!)F]_V?SM\Yָ\u>aW#e-gTUwe&3.ӢŎDh{C޼T+y&^{RM5#LE5:؛ĝjUb3VK6lZV:/óf(++,){/'om#0}ЅB>8QJJV3%Lo)S@:˥A۶a 8[vs9Z͓;k[E[6uնWǞ`zoF?WTެ`"ͬvH¼*Lnk8~F2 K$mMqf@kwTA}-:l?#O*-u5ԥ\`$` ޺;ct2 c N}v&՛Llo9a}hݠ|:LR3!3ucxh@yl%egO׊Z[مXjJd–)7R@ "9;o;ں2PS9~5v'{&+kekwP bT9ny$ Ͼ.J'.ll[ +nj N ̈ Z:0ڰ`PSv/Cǡ`7Rr̒]nL% u5De4}H ]yqP'48O'奺QH ug'z}}pDkb]Vߌ+1a1OaG ,=%<+cG+(} ?&%+l2Y.r' lL ĖYat8X88v(gnVC5bxN Xt! :OCDo6ԌcS;WA7u~{5c0cHܞ0 /?xWƦ0k pmKw\ٽ`^;ŋl|7iٚ2[3zTS݀HB`ұ2x%zR[:[;N#Sm-=`T;܋Fmq:kecț.,ؙBlW5wbALv<AsHM}*s#(jg". ևj2l'Mqj7P4!Eθ.,w_z6cb!LR4 &3V^}ۤ}5F  ]1{@ں:',5FJ&+^^l7M G[_ĪVhOLXhfݤz0'A,yE_;O?f!K3n[84n(L LFa6ֺ5am!۵(An#Z껛Sk35gYGhYUs5r蝖 `V0AAA(dف,dW(bj>Sz:!"ѭJ LmHԠP1޼%zh7K?6e_vNu)΋ґM!ޚM:N5#|tP]me?$9.#/pv)N$8@bOi:U &qZ]͊%kG@n^DfFa.<|;ZexB&1MwejGK ^l]\'dOpꞰJydD4.d=kJ}o ⊀bʵi0(ٹULUfR̠]7XR؀F5+_ Qo瑈J+.pT!Ou=C \dc7 /|*Ϙ(WJPtb˦,vimSIe_KV58lCkRQͤ~"KF[<(е@ Ly$ʲ>nf"FeRWDv%fnsZ P5ItQK7v[KQŰ)ihK/ZS@pU2f!]ge dXf(S2 w].M5hCq:|lae›6՜ȧu яqʗ*a§e 1n?aF١#oYa؈ _fFP2o$i0V"4 uj2YaWEǤoce{ ޷d .^`{Kd{vb=l={W bߴnuJ٭<g:ɭo9Tr+fdOkuW1Iq23 -F P _yk)g;՝fQCѢή^,&22붠`B߁̘06?:@ L]qzL)KŠGS=#R&󰃥D0(ު\J0WSmI/dR4Zӣ|M3Y-ƒjb;v{Rj6;ڠ{,J/[b*eA-p3fvMwrأSG[Vw. ؋j9JΦѫJdiRuLp3}kV6Q"t-9_ˢ4[r`MMyAtIՆfp6 :2YfiƖo}YblE\9[Lc!Ww $;Du6M9tEC劈Mp6୊ e^ͪP7M]`=ʂ tCy`* Cj 8) ̑|͇W?6絜o?x}z̴ BO?}Jݫo1mx?.Xׇo_= _}?y`.|yw/|SO/_綇~|x7W`EOOVgx {; 믟=f0_?g_'az]Ÿ?=<~==7O_5]>3˙||wokcg4c}m ϏuXR_=~1C}@.ݪo/Ofݿ?{q?/~x OO^< Ϙ֞1C1c~2mxzd}zקG1cߟ1#G??<#_1_?=b,yzXcO??=b,c#<9\|z4֋-T26|} O8/䆧_7_iU%^> Bgg62ga<0g40= 1볇 Y8 %FgCFngg22=dTQɨ!㳇<{ a|zgx͋?|fͫga 4c>|?K/K3٤O_}Ͼ=1dT|şǗRzqmx4ϱyr{ьw;w]MSi n!,T8%΍?g|zožv}&1|~B=)Knɵ=.cK^z[B]Vyqž6 5T#F]}v=m{߮Vĵ)պ!}8Y ;-QykEG=Ck:&ѩXxYoXnT葡*t# lb^I|׻ acy5a~U=Л/,̣U w>9teD{IMaX!%3vHL{^c52Y ޚyebƔ<2Ԋ'^ӾDcIͫE̓xkv^2[)uf}W)vZ1_mng~l{wKr+Fu;yRf˚ɋ짨}\߶yx*Wl-:[ Îǰr7a19fFzqPkӿdC0YG9y4v˪aUQ&'P=DtnBNU1-MASyˁ_˽4{b|qM/o PqxMunö{L qg]Ԗԁ[Y"K _MjSdvKTBMMOxdiS0,0i$d[~߹}9llMsf:_mOI(.t} $*k5GI#PXφt&O]ex'كHm8ɥG\o/a͞Ef]o3^ o =jT_nOۢ>QxM-cXbY,3Y}Uخ3 P˜s\ +fD0S W%Ьh,/;?n\0O CAHX2\-]ل3fkJT$,&~xϾޙG|Y6ݧĘƐ ݻ="N{Fij`#paUuV^QW4]T@u2–[&֮,Q{ k$|_*@lԌ&B#pWڄؤ;(9TF8sZ0veJC˻x$,m?cf0~Jѩl`#ll7'j?;Ov:7v.DfBiCZZgn**j t(Ǧ~yoW?(}mehE;օ6@&}e@JBOWS[ nVuz}.fE6QDVl cS Akݞn\yU$w#((jeN@-SOU&o On2v4@KK#1 %pT". ,)7'0ζ„Վ">Nӟ.v Lj#1܀85bHصfi>JTȽ t|2FA+6}W~q|^9` 48 yBww7cԬx17%]q¨.< +5fI͢Uiϓ"ʹV#V=`[ۊ|OS!08nzqζ[obn.u-H ؛#m"MA ȑ,Ci6K$6]*qCaU!AfhVH[}fvT0&[ϸk穑>~8qޣeeY[ iBMlWڼ1`C}6>X-ȶ_Z)t FX'Q$&Uu'X߫L ΄ڱ.MdF/1pl fy#eayjJԙ>k%D1!1:Oep뗒M#ub>n놘U܂Pٻe {L |0'0gcUںpzOwNΩh T1jU[=߲6d_aGol'ۤƬPhӣu=dHoؒ'3vRh N-.Mv8oHO  a,і Ld6SN bmŠ=S_%]c"x2ۗuj6@ƠBhml4+Um6j 7-PI =qPPUtM⼬7= .|4p7كdcDTN{ͻ梁l3a]̂,תovʘl0lXfyïv6gT8XֹVM(OGL'bmt- X;l} Ց4n=鵨q`h808ܒ̜O{D~Rt0 ԙ{LB\jcl4evƗl 3APd QU0ʪ&⫸ivlG{]x*PbO, ʟg}c f0\+gy+)paYTf&{)u֪bk<\h͗ӔҶݧНͼ//svx9 a=SK Ǭ!~Ari% ^')T,;SԒ7)n } v/,00x _)>VO|m{4ѫ(9x&KWEO8=ހRBoŖcwFU͢t/7le"57y4`#;J)1>;>vY-m #0.[ی;݅v%LhkX"E)y۝fX@jfIK]˸x۾+1 +blZ^zҧ,W;y1t9lIgQie{ |O|m`DEmlES $a@@Bqc65''U`вՔAζ3_B,sDbrCDOS{5[-ZDdOof[^lñPwr3eo=,`thZ6ud7lejm6ՠ"Lk/ál*lصVJf:'62'-W#je)Vh|,C*nVBw<}N1Y_y%5uVI,d-aZja,r#W ]nVgΞ2O]A,b=j2njm% 9 $Aq)lǂRlA=D{ղpRiHyu.V,Mb0df@aˌ|ԯ}QuSaMmkc2[S eSs`Uk)T,pZnB=o٠"X~tK6NhSk<& % ^Die-pVT1aDNXcBgC%*1uiFXT !*e})U7[svRsX~ǪP$,ph2oI.޸ixIb}6%[gxAZBm8gtnu[obGUO6ۗmOCܽ`٧3<#yعGͻ>wG VU0Lnv'[c9mr0:mj Ss\Ifu7x= d4!WYɞ}J4@ܕ,Վw : ?uF_eOaHlrl@. c-L7=`BڮU\ؿxuGh33N=,|]<ǓbesgqQsjt߼gѕ]g:D r6`!/;;7[kVYr2їbBmCw&:  aMUE> #\Vxsҽ('!6(g '  1fk~k4{`?L9[K$Z\o^7&yc5T" fc5g>Ď籰0NְXzi+F%ۢy1Nz=<uz6>sէg·=j0A8U'r<$.NB:`&<E`pI={@S* lUVE ZS6K@bZ)[ri6(NcM' OFJ/8IgKZx ۥƛ!SqA염zSUvbu@dr6!+tyVYlUGy7/wxcsE಼6y;a=v>okYsdM)sn;'պULR!soiz n~auqD<Ჵ5UHhG}'r[[pQѮ<@ϻAdm-z?LM"QƲ=WM1BnfpI(2"6.U}M6UZm]({!\q!"(R@*ALFFػWe9{şOf[bȒ~GU 1e"K 2Kx7uD(Jy\0Sa*G  6<ڼ @[p6ֲM*XӾf(~!ͼfH9fVzdi&7\W~J'n^{ rJ^m?g"CD3ذ.72l(}t>?y `ԉH0sPoWY qmayx?wlTR2_y:qj)%UAHJ %66T(lNټR5(ur98Хuɡ!3߅o@nCUNv;> 0>Lc 1bτV)?{;V@S]V5dճye@f_ήx$`F#Qkl=lsoZ=RNˋM*b7") qGr]0!5"nfڏYfقL%ab2ӄ||X@];p%7Y1Y5v5]„(gǢ^`ϦG$ş+T"| M[{m_SDf 0#[3)wLzi6gLL)1|v|{Wb sKjW7G4s3[WmdUIͶ CMF⌓݄no25a) bOq7b[ e9"ުGmmE&2b> 4`}'|8Nn2[Tkx[=3R<,uQ/lnE(55MLcxkY,&R'o0YȝwMzyAq^ڈn[j⨁6OX6:D>bw̛[ERf 轃`{BcQ\dVФ 8Zr@kQpvPE@ ]eHSc4v| =qї4x&|%+En[9bMX*bV^929 ̧dx[BO\̧ZKLKW Tͺ۪“S[yzب;$f%sҚ=>y v/Cԁ6k(z.l:%l}p>$>޼;F3`"9zm?o31 )^zYUaeaV ? 7Lm;?[`*bjQԋGmhHÎüz9D%)Osՠ::UӲf@`Dc;vHXRs*Գ!׎ez&A?%ULm^pwBosfE{mK8NO5st`|6zf,ݛɻ lednTfz1SR{1ڻbVօ{(OϳlO>Ԃ?.SK?PgF/v\"a@ht`?\P0}ko-ƺܶ ws4D,u((oD~'q0ˑigX2obl (ꌚybf-uD}K ] m툠XziL~\$z%uFܮVl[8@dVƾT]g LE4iS6 $^Wŝ=ޏmn6DE)d-fo67j3ǂ O`h6;dZok6E#8{ @fC /n܌Q,,}cf{<QFIo2Ћ|d7XȸA*in&^̟3qɣOw:; ͙P;lbUG=“1ι4 M|aCytޖn-݊Y .=*QmdN,3lL]TtMUI]?%;#m]߬\5.N+7 ) ӄf5.#fi#m̞RՄir/0hM5`PG*uH8Zǽ[š?͟gbMue8u=`VW:6)$ߗXp孢y}B]^)whŁ +L4&YXlh8p vؾ/AOb[1 {I*ĈQ1x+G5Y`xe`E,!\g9=%+ 0ىQmfutH6Ά5-6 dy4"&?cqw7[UTÓS -J= 6C9շl&-6yd|vļ`؄M(*.+/CV vJlh,y ]y{,v(lGv3sUe0zc6δmE)5 *s.ʬ'O.{#V6A(z׻$.xZ6~QU7 ڇm8D츘g ˂}ZӴ#vL[p34JL`i3*g tC#V wqv/apR-Q٬ֲbTޡ*ee 2ʎr^?l\cgay|n}}s)ס)iM3l Y:)'ػr2ct4hfRKmWyjĄ`Q:0t%^j͌G?UХh:XoE2ȷFRO@.fsvv$N (GROf1ﭙ!e1x30=mᲿm;m' ޴nv_J@%rw"=6'fsjq.|kl1 Y=J$*TV,z4k3y9A`|!LE~]0u4|aBALNEV`aaLuo޻\,=o>0Nә-xim"ձu%3! 3t)Ozb [VuÓ銳J{M7ͬ31'PRyT*u:=eRa>7S;/o,ζm=YXf{ozᝁhT=g]So#..v5ىuJ4ـEO0<61$O畒:'lCŕ dȝtH.vϩij jX$ghak'uC>{۲cR:63 4m?lܸz˓vsvJѤ hZ9ZϨ2ILy)69f妸 d6e: .YxYԭH72ACd~'@0 ~䙑\R ;2Hآ$3BG{ p=t6rwX1SǴ=^7@Щox `26稾j\]P@n^+`[l:14iMh'blj84M8AD|]T`F;gDbge86dW|ű`-j` VY*`b$Kb)uX?hQjKn n6i7-+x+aBVjBei+GKXomS~9MSRAt GD-y)[w`pxi++XT5L*1/D ؾL=8j$fkL̇&-Xo|+Lenh學U eHkJ. ;W PL0 Y |Pl{|Vn"0IvDJDUONR[[5ɡ[>S- Ye:J + $837Mr bael5Gk:t0do: 3 Ht0zUt֙JC`Lsv_fNrB- U0 u|^"ay7paCUS,IA7ohWQI&[ bJF0I'Ѵg9ݻ'ͭFLU@[6xˢ3J]yspۢ;G7Ĩ(a{2nպ=+qߊb ~oϺ&},R'm bθUD1(S=AxO+7eK{P5`5ʵLua9mC0{g[ݤޘ#(X%9KʸyF5o_"U}F5saSلD6b^ʁ KbوҴLMP`M8:u]Jü} 9VAJӒ>oa}gzn-'00^&A=am nJ1=њ1/\jò>w(d7Vdz ld+45^cpX:xUU pv?Yzh iӋzfف]UϫiZe2)`qxfEDbz(lvYCٔݧwKfȻ&TzEV~gQ5k5JI13oPI\PʦjC/pTuV*myrT =VLvڪޢf uY8nq[Zݕh_:6lͬjВՄfϚo36ωkFCm&"PK j(MiSRa.,B1LbXTyPw2l Kz4dIzrG+NϝyB嚺G7BKydq1@(EX"'̌lk6<| D,!*mGQY<,?{c<55EC]LB |mjUb|%*<[ooVM n`,n_7@u.a/$IáL,YРʲ_!kfnS9x"f Fשn=<)VsΫI O ,> 0Ц:ǧIOAݺN3l.yn|?15lkt ;0=WSjjTʞ^QɂVj$6qXe}Z˭tR`Uqb}Z6F5 5wg|;ll -e&n|pcx BGTdɻHM^s*(43%#1hsT(* (ە5 M w%g"zaVrI6 [1#pi^Xf1A1<0bYĆa统XheH/[dQ o՛05[V~_e&l; aOGCo/5@ykY~O7FDmۀmmJG>Aƅ Oay)Bm"u`MUz h6xyQ|#A 2S~ s*9zNÛ!p;Ӯ_K%GvW7YD݃pREݒL, *D&:K"%,g=F ~r+po,-.-P#ˁ?|' pq{5(H%Hw!dmC]u5!%'Tr'9eaOڳ} ęH5+pj a;g&7dH9M #LӱB?Q`(-xl$Rv!9,BbʱM(-]ny{[ڊ 1Ev unH(sr-ێþj-Ysn֮K3Ԛf4]HbZכ``j DI9on$-<-)CekJϽ4OVm>.T:J^YLoCPξ ##b c$= fP#mRl_stSV@PQUҐ񐔮"حQ0wmIL2q=9>둭v'M+$)IF&2l>X|۬c׏eUyunݖcl a!q01I&#"5oeǧ+[=v(񊗍:|/lکp#1cosdEq6,d] ]ՙU Z#As Z/ ?t!G罫FL]Rb s;'`F+d@I :0(DP~a$ql3O4" `BjU;}FI0VfsvOϴ@Gsc-8C'ov`#SDm(} (#t%I (b +&G7WNO&{Pap[j #lQm^(ٹ*Z}5Oҹ5e_V=/j]M; E|Hc_XdI *(sT\eƳ*H'y:mˑ_7Fd(lZ6&m;U ZkwB $9@Dsv*buHm?V\"T|i9YԖŇYViɑfM0Źt]c`kl$m0[UnoYaGg* 29bA.BT xZR09"yS}J瓗Vnދ k (:ARM8E.5R_C%3K=loYGp?w7hčt:.M&cR.5B+šCiRCMcz0 XęG4AA.k:FC"No fE$M*~09zbwSƱimdR~?q2s2jIG]U{M#:d!gbÍ&>RXI1!(.ӗNmeWMKEHUȔ"cͯ`c=UuLEmo o kuςw_5ڢ#ξ7@*8`VSlAK_eey̟Ud[tsb/BbTοm@ u[Z**MTܣϨ i6qL !6v=Y:8vn\43i "t:(QhϟL U0B]xTM VZx Jۍg[LIs I-|B]WoW9 ՟k aRS׊Q6X]fEUo"UGccՍ<x i'@lb5f bK&UX3J ldK}PvP"&%Ԁ4۩fƴ;$80WVH!rMhA1Ƭ6ӰA]$_5A~8 P?Όf+5w$l1l6q.C6w5]CyA,ᐏФTs^IbkXS _U[Ƴ֒tP;3 : Ll [>FIGc9Y7w^JTsi^!T(X NAYa:7+c)=J* P=ITVUҁ'JPjv_$eКPt5~tAL č3߂wywfK5d(-kQH־=%]lcO6[M7\0nٚma@H}MexlRR^z>*\mN&)цEN}Hڐ+c+cILdܡ NIM*5eY;b3}ۜ!:ȭmL"\vSZp gZ2*=p&d'`PHaM+FYwnEmsc/<;2O&yK&sZv3XT6믗=&-L]Ed%ˊ- K{8:9N2HYDQ3*슃%$K2*j?{mD5eP3;à1iɱ;@qKd'W 2{zIn9/}5K(y/x_(NVT4 hr[Ђ G`dwiBs}Cf({q/"H.d[q.Håk.Q-ko6c(+[z#J&\j-bct]Rfأ^ "切 $J;ny8X;p[~#4=WH,LkHkj_;x1Zc_|RjPȒ_u)!*V r[o¤'9*3#28禲RVU&ɪ/Ǩd Nf%}tgiL⇢UI)9vԊAha%*~I6yRTD@2 GFD$~?!\0JP<'EU_Sɇh(v85n3&8+L.PM2qqcvc En)Enb[:SF-q5fkVk Sf*wv 8\13pppbtBT%=gݼs5c\jw>v[7wwm!?׹}5~zӾ?7o>}7߽ͿķZo_ֿrUxW?~/|z_珿˵/W?>{y?o߭}K˳\o?/o5_{?/?~ y?n ^7-ywx\7O㿿ϛ1߿?|sқoz+߽7߽~?o^noo`ywm_'5.跿}?b~O/_e?{[ޫo~~}w_!Wo5[6s{͇_ϭ}7k.ӏWqk5W~7\?gVջ\ww_m_nM~W|/7[V_ol. _oK_oV~꿶ڿ~_n./V Z1jgU,궊]W*_x|ՎJW*e?%./oqO?8 m痷}W=w_=m_Uv~x~wZM?ja|z}J2?w/^0s/_dNϟ^&>}|y\鿼p?WnˊWp? rxo}Kt)-߭?o>Woso_Ι?G!׿^~&i+.+zy5lmJ_^qM^^q-+߽Z_^q-L_^q-+o_^q-kW\?ZחW\|yŵW\bp2Xow?}urA?t雾}۟w/Qq}W\>&^M7+7!$xK߹Wt _; .ع|zNv$+%WëW/ϯ^z_~zK^+UKꏯ^rUK-ツw=xkEwnWh$~\1?/k|?Ƨ??y^lVHPؙϟq ?;׿}O}m8T8Pd<ߪWYK']Px}Թx_Yk;IϮt/yhUڻ"WqjG;_vٴunSouuA1>*Q%N۷Vl|5{~ CA,gKԳ$Qg[p^h;ЫJBX,܈BEjWu 1ܥX`VYP+Yyps;'I98斜Qw.3ٯ6=%YqBU͕=G*7rIҁE7w;$0;|(%s5+JN8!h~M*x4p9e萜!ѦAU6\$ &Z);W;mvmЈ$[j0æ'5.>?ܧ:d14X~x=͎#\‰ˢVe%5{2+v_Nr]KJ!BmZ㊧z|Hx-ڨӗU=Ɯ yq5q;Fv7=i| ctWQ:U6:*T|jvZ("!aƘ}J&ɢ=rd+:T=ȥ=gQIȕ{ vyʸk\m<r5Rr;H±2"+{| }tڅR­%Tqsq:v7VxR`Vi4T>ii)ً-$rsd0<`shOJipדr4ljnJ.`X|L²eWyNVU1wdcrhp}i hL͹QLN˩zsę=-3[!DijoT96>NB$%f3RUbC2.Ji_%38BZL*oN(ީk;X\Ä,GAfrKYw'kB+~R]4dM[]c< A7Nزu-{'HO۪P(8Nv̾>/ V儝W§Ky]Rur+wrK5KࠆQK*skn`WUnqPdxvϓueff9Rvc9kMG`cAHdvJ_v\bg##.7v2/dJM1O <45D Hڰ]>50rPuK~x،PoL\C ABp;{~6:h~P4ؤ ]+l%T }2zCӥT@'IΣfE 8ˍ/6D\x5,}7'1钰ёНOh㓜)Uo皨@w]%$z|JzQCxIaH"ؿϒs!Tô>xPpd˪2qWJ)VG\_8b{0UˆU"8y)Y vWP\ X.ӫS>>Nd'.]B1 cDt1'McÑ_Ɛɱ冹a1rŸbJf\dǔ·ppyAx \-nOv^/uKht5SMA3vaɹ Y?,ߙ A$MK:69v"8د Aܳ]" }Ks1.wUO]Cy`) :7~lRջaʹ*+%sX~)adE=8 ', )) NDRq#W?yY|<5DP_e.&HNC9T|]4Pc*xp$,y(0ġ?<uwذ*y}qeg\p.4$&H}eل<Ɲ8͉hKx08Uвy9jݪ ݖJ ^>3 "PQ\MU# v)&Es*\KW90.װvm^'B@Q/},3Q:C Msnw}svy42`S(G(UIcݬIهob}C,n5StgҒdx$j=+^`^< PHmޣ5eGiMR^vF+VN¸دzKBbrXtp*)ĠTDSPݭٴ]f3ƱpI$]m~ < RG}ihցm|0ǝE:~5XL,OôF%!D‹OfPBde;rjjr,+| s?vuxt0I6,6^&ڒ G4d3ΚÍ}(FjU c>{-q),qp]z,+ah ND4ܗ[)XhB.ۢÖqBVZe Q-;pᶇ2K'(g^ *kNT==ʕJl; e@ X9O>"5k.~E.^Db`sw*B8#wKYUdC8_^6@ao\sުIxo7:u8M DzKW(4q?m=jl<i.MNjɂASzAvcR m`#sPVЙc8^eIX_jHQ6 n>ۈx29pfPPVüm v92ąRw՚s ju*uvHL)e!1ףtkw\;VHS=MU^2l_%v#A`ΒJZjFN>hG2T3qTqB=_:7'PXn!k^|q2tdy^ɢƫrqsNP_RV~Vqzٌ 7J{HȞ5nل^A/̨Qf@)􄵠Yʎ[ŪA9Jc&hcA02ړ{kFͱ$@m(,hrX` n *,,ac2K&P֣K5iJCb Ú'URX^|i nΜ49)$@wת-A@j7|/N2 ,2(;./@91ʂݷ]VM-sO RvJ8dT6XMW$f#DҖ+werwچd)@yq }8OߦT9)uRX9L(2K{ߦgyMCm(g[kh+&N|h5=hӡTJM }7 )8-C1% fe^$P3gD=n^Vu sIr3NK1o}Ws.GߓӥȁeCi1zFeqs7aQ`%oE)unkN*gQ'`Y橔D+vMy)A%3@LdBj^^CW5*{6#ha'IwzGq/'LD,O*(>˴_SmXI .t]q+ewaNyA=d/t1/g%.Fa̪.''nj (gSto zxpl mjYJ06ƺo\=N<*Q$ډ F}qtHH\tsQMEw̃L!T4qDy/Lo#qemvs+c*̨Oq̝sꋂgc]5)35-L q\_ˢʛ?: t0qfGG &n4nָ "`cِy}8H~ceOpȺSPS̟2C MJӨRNxx7{,L`\bse܏(˷ǕX!Eo.idWġ9$PWs+ Zk1hݤ"'[px*sg'Zܴύh*EuQbTflwZ&j,%ea uU@iLn t#37IJRJ_(ZZ=ltw%nj84-.*b vpv-z`VF97P[T"uf6^ba38T#\㬹]3T$e[;KAiIN.;Rfu/,>[x옥/58cG":f"8Ud(R UL_Ҝ[(b >5^y#.3!.ܲ ηiV%?Υ5x`'L'`s8X[NS5ELt[k0 XWNoĖBl@2Xbut#ɈD!Ĵ/hT/0]81k D+x0*pėR2sW+ev+zr"?]Ԫz?ܞtI9Ƀ |<]XÕzH"̾JA%VJS:6#LjV'"gjk Ry؜z8PI٣r'B-c3{Qr6Î"~t_2_Zb~Dp4+e|ÎD |2`FVOye S:|g2rЪbة,$xcqMSjRP[]E; *tS &EܮX6x%FG0 S[RiIa{_vz7I͍r H[LVcxƖswtl:D_GqnN?˲?2*YqsgEfGYKXCwqHV~f*sͲ ̗ylvhj{81oRZ=,t˛vF:*bwSGx4t/a 4$}UZ [Bn- \C2Gۚ|9rdpM68.ZcsjO'2/@\ +"b. v7\EMK=Mm\GEj"Q{NՍyVͺ8?o(i*.={61k~'pW(ec!D$_sRfyէsg33d¦cGYZξ(w4@3[r=B=K;1CY:4 Gab5Ft92Wm4ɅpyXb\Q:QE-ͣT%8=eD%wapn SeMr D:=jpCA{I0<n7UzK,ѯ,/5+ 2&<S:mSS ȱ a"N`I+Lw(QyJEZ&X/ gaW9ɵȘԇ`ӈ@L amep DM LæTYOx]1X Z ,,ATUp}(%2CS|< sNymrAd;; h6X&yf~М*`UϒgٕUY$ǔMh;-TQj]>@v_KBN5ٷ"Y7Ij?9D\ΡW '4eh`ux>4v{swV[d~)BgWaMm*†e9I+4Ѐ;X^<7t򴅩i#YVy<ǃmzؔtѼٱ x~vE\U6V=1ݯLo6͑qWBMѡ,cgjz,̫uMi] 8å20Q ՃBcQz18gԡc^Ĉ}Y&ϰ4Xn8sYԹ-ij__iFWXl"3G RѺbX?AI,z;pcHr}EG8$` dYZ,OVRP -cd;X#[l<y95?w&V.&jO)RΉ4[ZdN?G7N( ڲԜVe7#:V')gk' @oyqb,}TnO`{~:ΎzJKwDA2_sQr2=ű˾cvپwp]D be'h&[P$ iǁղ"5r;+Gl`.,VPMeCw/,Dp~辥ھPcZ"v1&[1sDnb _%DU6GaMMe=}yxο*}|~B4rqleŭq_\P7Y>,nte<3bMA$\q)w&\NYC>@5tz0As1c?pDFzݲw;;+JAƣ=ڭV3ټ 4{ZZN87ΉyPL/u6TUƘpo}8wlSNeslvqP8[%[1P^lJ& p`>)lt i+)U쒓bR‡[6(jƦ+.W ع0wN8ئ`Y씟dI_SRnp(̩ŋK:^B{-)M/B5l6!ζ" ؏iӇb (cEԯWJ{6p2eI\L,[<A- 6Ao_vJeWAK_lޏ]Nu.>IC$ʘ* gC^1D{+6'U7ʱć\+> Úvl:.w\o$NjCZ!V˜M%5P#È;E,Y#u3"uL׷/J&WI*{.NݤUp}?-cmճfẠ@1 Z6=IEg\Y#w{!0ܔ6 v̰f-v^rN qMp=@CcGTI4:՚]f(?j_ ѹWNOgɔiY [q><%AΨ,f >6Y%mrH9KԫcO70 *{}:< E|6UF($G6=ҝ&Zc;$x]6[9Vܒ:}@$յBSr D{w8ZJwdju@vu؛kG(؎-ö/RZSaNR8'[˶P]4W#b*IoG)2HCǹM *  4GiFoaK##jVlaf/K#8QitƁx};?p@cT۰R' Y-ôI]ĩҶޱ(4$8$w^LJJ݁ߣ͖0'wtל|0J{VM 29S}d,v9Y-=]SW<9wrqR(spfN!vP'ש|iDž{ Bݬ '  TM*(G`s^B{OY[ 89[鰦 vY9;p 8z4 ;~kJs&|a#OqIrZ|Q(\Sm'׭ $>|eKxan6W;9l*!8˖ӕ48VBYYېe0+&)K؉ 2na.>dS$: M?XMw;_gcnCBgu&dYLV3!h#3j*<\w3D"MxrGKڜeۘE6!hgP8if"HjF-}K4>e21n2VUW+ Zfo_VId1X_;`s.VSr|Rd';62BZ=`FMsO-]>Gcv>3le^ hkxm' -I;{&vցKV닥M>wݤ`Qq0RSI Tl0풺ƉV*%.L~~48Ș:'JO{VP<!-yکYj{h:V1TY0=P0R1|fvf;Zzwm^B[( TN6θ$|즴kd^Cd x8EbsߌkV=MS [YΘmwLJɓdh͏K~E@Ǝ7yhsU‹VusL-txd |tiD`@'ܱq'>f{;5W8O az`mpzZLfeg+_A;x4st.^kє>up k&-9x!J$;g]N( ݓ*Q2ŀ ;9}%8G_=J3`tY[%xdmVѫr=ϧ ? Etk >GivqM&v^@ 6ġ;$©`7M/mSؖ UgU2 \ a6aO)Ȉ: ᝏy^`m 5e;0-_"8>zmQu">pdaa; 9@Dۋ]xՇXΔ~jOQ"h8Mt[5c|Hc (+/3SK - oM ;2(Z G: dXt>n].⠙vM6ARܥLQgA;|m$9s0SRaD.G-@(we}sNv(jA36B ϳoȫuCx/v%axdeN"";$=Gl`W8$>-E] %X 1Z{.ԟV $^'v>iN2P$XݩNA61>b[:bY_IlOJE;W˜#3\@j̔&M978xt\S6hv:rݱ%Þ7.AIk5fo[ձ֋̾)P!_u–7H8_=ګݽ|d2jQq&%VĨ@'gڷrVްl7Ox7a6\W4,%;ۤ&#R |a8Tkx*RtayjeDdzoAr%mEl~ ?=X9 >- tHCDK "#o,C&~\.⍩LEbjJeMkFiV|ṋ!$]FfjJo5;#|Xُ1_ɹ/]GU?qdNj+14!l' f@Tc3ƜUP Pl8疾P :Sf*3̃8$o }(87#OZAmgPe|#*֤{kϛ䊠_Wkm&4҉n%rl#m 3NP0P1}?N69^:Z: kLkv;L%^cL%p$uWtaCUOUsQet"."v3ME-vٚ4ZI'.ڑ~&2woJ!f䦶3'9Jg$}mչŚ$oSp|a5~B{4ꬊQe] ^` 6bw]܇Uxl[ 2 O*I+ VYc%UT!btl:\"/9N;o|,EvVٲ-|m+P؊%Y {)2ήJ-=>vu[Ufp6#$6bbԪ o]޶`$L'V%]e0anihc鶳ש$d YXN G!NCOqy 1[Ym`Rbήϻ a8 #m$6G:+l'y,IPkZ=J?7|<΢nX c]X"eEx/`'xMbr z;ѻaa5fInsIlzq~)ϱdeR+Ye+"h OiIw5 7kd{v- ;ԄI<.ښ C+eg Ȱ ?ZDs{,g.*[Ű'^uȭwnR%pꉥ ՈIѦ3MwipoRXղ2LSMVW[쳍JrtsPT?W%=O#$#e4 MH&v5*ląquDN#`q"Kߍ1Xsk55Հ%kk([ }b<^kqhhRS+7'euFlضITt`"JM8vL@z}vmoL5|6F es[CMib)DVwa\r_):sl C C b&w*w orȜ{ }'0=#݀f%NʸM嬖UdG6bT.+ EMox|;`pg!b5dSXcJc7"K&)*i?>Nd)/ 8Bep98[/SՏdl>iWA9̪ULIc;N߳+b:;M!n-} G vgr&zUNPCȦȆGbo{00sh,Z!ړ:(I_ؠQ־8jMJpZ, 8꓀"~Pp:pq}uX_eo+#+ByZ6=3n2ٽ+=J6Z8jo"i %Vs\U KY&6іZ5բg][MH`b UGY\VGnu6K8Q F T\9;&ݦic}g߂-YɥeI\lDAF=M׳}U*rChS0g2Q]<6)ʂGj36"le\faX8^Dt͆g.hN{Ʉ-ׅVM'e*Oft29v, ,eĭ8Q(lE\ If凼 DLYrEB'E 1SZPoonY܃8;G#(/pKp>MKZap!E.EZ>.uε8;Vhgm-T;)RSW?ӥQR:Xv%K%#$)50UfkI{OYRx4[/w`WU>F%풻o7kɍ!c^ijiZqw.#xkir0ⶣƄzL6+RUvU+B|ԜKz6tOSF̴9 yU!7n#I>;wN6ΜE!d*8FSIL!եgC!hjgb՛o8ķTrwKQfcim֐9ngM6^R 2`,8#=6Г6Ac[c%R@1UA?jB{+jX "L{ob_p'!b?.GЉ,jBprb3aZ|kvh'8W|&:9E܉Օ'&0|ZgPgn5A〵zl?f(=ʬaCN9/g5(O歆 ߃ßuTH<j[ _Ԍ!{ܕS4SC$&edYjVlJݠ/G8z0#˿cꘟ :O%$wls6_q-^O ,yg mE q)/9a6YCiH;:Vu\E5Jl;a괡 0W1U-6i6`RS>o~䓕˄y=-Gtqdo$eS+GA}$иmV? dn/`̾㢚<DZDp4>HE6N!}ﰑi,5lh+Exv"%ӛ1"̵g (281K&lڐ@Ou@: A1]]%܃%J'~1uJ{U*ࠅCݵ|-Lm{7Q205 Ƙpm_)Us/J!y:F+t pcq% Y %QUKdKGDzY0`;`l}BZĠD^ʷ%!Oed[nyذU%өJXZP~Mͫ %v,q]a[ōDڤrZ)b=*؁X$G]I8a&]ŗyY `:|d㝽T%^)-d]'reFMجF6%uD*5uߔ`qTӦ(θ=A8St|ֈvQU- N]vQ3y>F1,RplCݤQ\s>:j$G꓎ >jv|vO'5k -V/+FӁæ d$ vLN+Õ%Qu>- ȉ?aOoCb{d"ZIIZH 32&=f^TVF2c,Z*vHM&A?o?{O߿۶ٟ{>}~o_m7w~7^ozoq7Ͽ{7e:2|?~~o7>7߿7~_ys~o}w,ozrK}yӻ?r]o op}o{o{ǵ߾~>,ӯ~z_珿˥/W?>{y?o߭}Kf=߼}iz^^(ž~㷟{P꛷?ƞUy›{7~?ğa-~qo~[[7׻?~+oʛoWo替{~˛Wv\^}R~W߾.^n_7>ݏ]wӻWooezڹ|~r߿_?_e~j:w|W_qp^?폿ޯ^_så?|fu^oyw嶋tW[.Wۭr_oF;~_&_˿akWbo˭vVLX1z_nXU}b՞W[*_~RWS⒱i~;p7߽vZk=~~yo}|yGnOWen燷} zuя_~˭fƧק$s?r/  3Jf俾 nǗU ?{O?Xq #_^k؀/׊W Qԏ__H_r1߿ݺ6y6?~@}/oro_.Ov+.}⺯W\ց=/t/W/?Z+_^q-^l򿼼Zw/yŵ+}yŵǗW\zyŵo/k_^-|WG/O~xuO׷~uuOlno^^q߾rBW/݁^zl^_+}@w^kW/Wd^Lb{BO^rU?zQxKW/_K꿼\^%W__+z/(wo??6]O?|y~FEo翆c|sɟG'g_2uab_?')n_=ƻwx3wysOsKc*K:VΣyζK]R.9.a#ﵘ;tImwi#Q5-پMZY}oEmTVm8r$ [[5v'HʞVm9K&~G<48w<̔[xFcmT)ЪzSUXەrm6:</eWQV +U! 6^Dby̤X>'F{pl̖Wsjw]ɞ,KEmwVCxRO 3Q&3~sr#*JQJ{ vhȻ2l=S&C~quXt[=!ǩcY[` $[)ߪ̑qxZƄj׭buŚ} ۙU_ i͘'lqf6C:X5d%ۚ=VwkhȑYJǗm,w8QZ.EdUaHQGG' " ԡ &ȞTtXM\n bt,v,3)-rZr3@o©>&m`*O"^kbXNܫ XMWGzU$+v< nvӻ$pcǑVT"(-sXRM>=)୮%-(kX?$ToV pZuXx,˱Mo^l\{adSTTpw`GZTO[(IJ4FD3V{z>piE }rT%Lx6Cs*o 5S/zGK!! 7r¬"8ٽNK#ܭoIiñfǸJ$*i3ѥߑ]in~\M99Vx%͒֩ a[٥7-ˑmMHx<ǯ˒RqpظYҬ$L*([ojjT[W_TwtZSX 8~YJJ2YZ YW_?#wz{݁$(H%*FTiOtY9l笎&J lLJ9@f;9*/`?>%MTܐ[K 9᧶cY,%XNVtT͝hwٹ.{ X>fUĮƺd[VD*.s.G$B<~댽Β̡R)eMkv^* RklYڜF5/꭪et<* ynpÁu 9;TYYp?&C\>Q(Ku* ն1)R OBX)YS4V(#ѧR=<)K:K\峃l7s/6Y[jn#{mOU}x$pH'uJٔ]%lX6I@ڃ2D]_.HxuM)."m>| Ǣ.+889~:L4VA4Wnܐ>[p+@ }bM.UVL8wߵN3bA\9`\(HY>ۑE) p'H|=O"8a'2Зb( e(£j n7Ax;AG, ,?.U^xOY8*8m aYv%ʢ"df%gl2ZF*2V͙mwcu}vI#=' *W_ &{gCȪťԶjzVlEd/JcΜ 6T"ve$ܓ$#yzW N31k웡t&s~$AUe "d`b6퀎1rDhC9 z"klY=T Τ6$' Mk7GgurJ! 8F9G*0^˟l2ʻHpҢɎ^ 8E#Y \(+9ٗB)mT@%s*Z>Ik8}AKx]aCu:_6OYkl?Ի-׸%$Si.g}qԼ(ToIV'lNB[m`ruYV품Ttlre g6x3Yf{*JF@j8pt}{tnjr*_|ʤH/堑L)6mtC̮n6x9;!Ϊ /hMĢNvYO:p9t(02p/o-u0]~ymĢ0P?yÆ*̟i!G\D4$RȏK{ٔ2H* y6qܧR7F4@薈LثcfO@p+:"uP61b͞v[N*<wH\J';A#~jPYdUAcݨʌdL_gP:Kdv&R9@J)w.[PUWewڀ[Xe[#!cCoqqOe+kKJ|I'!J *#uq)%Vx!oj+p)c%%tv>۽i2d>aNTKD͂]iNvw2)VՈ90i#X!X$YL2OLAL Sj+z}^8QZ7yqp]F8%\srD#ӶkM)_)Cؤz}_ S^RAgOw6Tlfe2 +1/%g0K-խՀ9퇖P( anpq\Fa8^t7%Gf.۸ijE?= HQ).՜Pan'0 :Ғhru[J~mg^P ȯwq1(ciMM2Hٮ6U[+ݬ 썕;~̉ uXTC/c3y-Δ=ˇs؋/.{DbZWD; 0F&&jE ~7g9$j|Ò+h%=E%32c֍7 Թ '+ES[ޠ: 8mD A@swvOKVY*jX.e$ҵ1`Zi$R*0gA:aY9dG>bg`6P}a;'Vϒߩ" U`,ێ@t9dqoY…L"\S{lojD3攞{ce=;L8ƿ$*^6넣Q\Ѥא,5#0P+%Dej7cr1Ӗpp78JKz8 oZUȎ~$+|ͳdf v$CRCSט|$i]Ai%A$ wP\F8ċ_vm:`/y*N0`a"V`jS4U#ՃTpL!(: J +8([P9;E'qxӘT%`݃}dR ',&Zͥ v9_9XP<-QwYeSE8pij%sqZ9$[;J982a8fwA JXKVO9+jh+Y4\h |9noF Ͽ_*'n| dtE9)>ȑ6BړH8b,V_6U>Uj"RT-( +GMPPZ;|UBb!>-KpHM]kJskb+-@(094w<}iKEζI R2:P uAZ0G|1ȴ4' !pӾIĆykD>A7ZNȐPsSߪjLT/V|7ijثrX8M/)4vv)&+Mds[1m0:-.qlS%x:ZtbKADfX \N1=Fv[x/2i}X SM ]s]#Ux|,qm_冹eCkUױqͯjl cс` ;Zq-i*  Iy%+h(qmMy(/MFLg@~,s)7|ʡUWv뒓x̞;=Cۄ-CF^Y@CxL*?i%z0ҏ 0K 2?PvܡhFk1~Z2O]#nR:d}>clYIkw ď5A#3bmi|D|?` qǗYV>R#D:Q^]Ytk周K_7r<%aEI=v1O,dL)+8,DN$/ +XrJlQUMJ4L޳@;r3Q%6@rٰB[NlXL;&SM-P gzeZّOn v~|2Co] ,1bKM<Xή N (r <`R>9d9 魊DL0А,+ؽt⮋ *~Ze`w唟ޜ6e,V۩Upfa3P Wk 燉eeU;LiOO]dL/'6m1wFVW#l KȦc}(*"M.9\達56An.Nr o'  H{4ZpYCf#^Vmh ~U&PajvDƶJ_7<$QD9`%,JzԒlw$YT_̓S^4 mri3H&PZgX'0l{1V S%X*:%Je112rzgL`t ƴY]Ar)r >VF:S xɠƾ٨YzܿUfj,U]?ۀnIւ[.~4즂UQ%؝Y#F)X\U@I hᴨ6$*Gox>Ogњ};NCY{Cۻ9ߏ;7P{=inI] nHh.JfdsRH[Zªc4gd(vHn0W3IsYQspNԼ%$|z8qNe l^h&*]97y [/6ǭf\rw vP$3)n:˕u jj)$Tlyb>Rݺ&P(7$9Cpl]d D4-03KB4}~Lt[RU('1,N@"Tu9$sQh׶\,b)W>Td| ۻ'><&,oiKN'`%< OLV֟†"!a^dyktڻ1<9XFQP/ 4%mZ81Jnh#fa4yU24_8#*%(؃GfHAzcw 6("VltJGD9C¶$Dm86C6\5,苪\ޕEV 7ښ@,, 3)1?3JZ)n2`p!撱 Ӌov,W޶v]h2t"Rpc[ɽNmV긂trYOEWc7ugT< NքpvG۰4'MM -RI«7n۰|S1ݶ&x @bI@KPد[tU_~jWvs'|J*z&6p&tU/ծR},홰QL @%\-鹳(nCS{߆i8Nx (0k6 7I9Ed%V)kb! MB%C띪a8*77 hQ˦@`QxY:,=onZiָ 0ԽeYU=g;PNF+lMANutlŌYf@&~j fyMsoT0">g-}<#  V81|%`埮lZ, x*eʼLlo>DT׼=c̲6;lYojI 6aEj NR/KJD_cT٬'ΒDON+R XD\$qP;alvG21’z(K)9y!<$Sīǃ1P(FhgR;؝eV/=]|9 ?*|Nik;y[N- @' 4 6ORsN]+zeUTDl{JZ`lAY=gqc;`WjQWF &i)s`08c>fy -mjZjA7vTE]Y&S*ūqZqy[Q{4 y]R&ES-Wn"eCɟ hES5 Oħ*7Ȗvҙ[$dIQiOƗGJ\fdPedTy 3Guӎ$e_ OަNک6VEey< H88ɥz.~;ELy@b* \ZRSUIPtsФ'\-7qԸF} +_{޶?fe6Fxxp%A]GO"ӱzi0럻'1Rxrl|RKO{>vI\D ́~0bU(3xgl]vJg6^si9 =8Ԑ U- XP[`了K:8liAF.ؼNs?cFh9nxw/B`qlgw%74 󲮈fKC8D֌U](j4P2>Nۆykwj [#s)̪u $M/=HYa"Z#[}vڮxVWN9&fmʒ;D~kf몧/$;dnS[~:mE. ˻nK| .)]6e8̺?,Lf,v4'8#>PVn/քo?6T4{ӡ z%¬KN,uF(.5v Y|nT(%sԚd3qHaErrT!xXl?N%I>-Q١"VÝ&mcv_e/zV,AgNX @l06OŠܒK-b5r AN샃tN? zS s(;*3YqǸע?\n cX`<僶bbY=m_M. 8GUNJUJrh0$N5ҵ30[lUãׇق8YP, CS;,xw N~ޛ,5g%9Qw?jB 3 bU-̧RoVߠ}k69 UZS8aQ Wa8U6ԥϕ%e%.zPK*IbH  LBt:7Ȫ (0Dܺި(a6șONlwy"M c@-sهB־ 17 *#M8Ϩg9Z|˞L9Jԓo3RA qM}^aynvIwbtdP&8ܗS MJRڪI,8M|} 3cܺ *Uf ,pNzqڧi¨!*ؙ0v8fNv'#2t,(̈́M'#JhI1uA7V%)l7>v2l+Lo*=&^q4nVo,xSOV` g=jk< XOLR|LD.t0?dii*,Y܈Pg/lf n9/TN9eak5@ōb{$XēD(Oa(D(]ܴؕNHg%-^:YQ]fSQB $S8t$B ϖ],Al";K&}=UB}voÍ5᱆ӪʽR2^Q:BG[NW:kԂի`aՃVN*jf$NapZ :Q+صh"C" J]Uv+ Sc8Lf蜢rgs%,4EH͆}p ^>Ք;NJI`qn^[Mu$- u\']`<.*c*d움I(lFŮLM_''V;H'щ馮+ ޴lS $NvfTxMɕ.X1ݕ"HrM =UI[te↔9VB2eCC|J ,0ڣK"E reؑK8,~_Ex7rgږRQ*r&+l˲hBH3ܔg@gIPVΣ3Za?wN 8NZKk_j$6os s%t9+2@!~QQ ;kqŻr{kp&ɖ  M\q55T`g5ULZp[a,r"mX!'NخT$}ᨸJ]IfoWW37"N۶RA c :qRs5?' V?0չC̉K{egcYn*z8'rq 8jcE+ZhLHNjyJB7x.G?NM bKAٸ5KɻK4=l7LFۅ~`}Xh(B̙+TC>fs9v]yOrʚ,ȣfnӮ`s?`r ^fQ$(_-VTMځnSz-6IC$Vlw tB ƅumw)[ TOi}%þ}ʰIJ)! vVlP@ɆرIBެV )iTf[t$f`Avg4heІk>x*3 iFqyX04ަtUE]G]-a1a?mJ.G+ڑzJT6\|("_@sgڿiKi7>ڎ6lGβ؊2NDBgâtG2",'vD{Nu-9n B@+QbwT6վ}LH jUL[ZeJK3rWe1 w1& @ǷL͠R%DaU8TtPW (TvRv"l2nDYvڐ _Zo`ۈIU mmJ4dR*v;~^AJc02n$j7,EHʏ1RL5p9p(S} Oje ڰf3r/RZk'a9R#`NM' >rv&rSn ж""-1Z;x\B]m^ #|-8};֬!imdU?O)&$2ǡ|q]|x1Vn1XΦ,’DA%>P[9*yszvXhd8oUmWHuhoiX⭝sqjU*w!OifeXQwyF>xް1l_{I!nѾ3 4ZquX >-p -7;[A&˻EPiemPJZAqqtaa`_|9MvF`M٦2nRKCsM\NU:[$%fr'jvmrs)s1RzaR]&˧[36=ܕTfq<|-%4WO]yY*U 7vXPrSB˼2"w snۆD'~ԇЌhHQ#%:+t~;9,᳡&/hJlvMCbش8BS98갽!{oU. \_F|oHw?m\"*I$r>wNQBX5S/~tUsngS[g2͞@oYUJ/S(aA,4o-SOCk?u rܤWr=G!'еWC+~&|bb#󴻤q˄]Mn?ac7Dn]4Hhz+=HW4+DI0Ep)2:X*"\4qx.'5/-o7Il2Q֚*?ڇ+Kgw>,0F3nR--Dl6PjGn.}i,ð9C*tIKnk9 !t@90 Xe+L} [_p*TlW^s՗@=zx]EmC~WUr{!:Hw N_ܴak3<)3l< &k젗;ct S B.͛ X wCZ!iC[ѐLф!xtxEƕU dUÓrP>2 6w0Z]&]Z256uy:p0sD0!ȗC7d/ ۼT\_GG-1=G#_a+mfQ:V[2t-إi9.1;99CR)B9y 8Y| I]=8`5֣ccqjpvb;:Jvo[sdܬhcʝ%I9렴}uon'1@ɘS0r Q[4*btåV;C8 iGKfٺ s3Q .{*45YǗ1S]miou8y=Yy&ne r,4v1GG=]lD(E>)nCU`-{s8=Y]sׂN9mXq@X)F?;MH#nRRv-+UCTeo|Qg}|ٛ0PI&*{`N)I.@ b>'/y$qufZ"0cUvq/.\Nl㵆$3Ve #Le[dC @EeNorX Mָ*`5oCdI&sg}0[Xz)̺?{ҬY]+3? !4"%QQU!DF$#3*߿(DL`|o4{}R"ADYKTnӊloJZ ռMO<#UM׫ 1LhHww% v"*ѡ™ 6 ƆGKLж5\Kk!hB \p>ި5nޣGJ¶%":TK7S"K]3-ZTKD} u `gJ`;ժSŪEd\gVh<8[􈀩c¥jUҸBx")-s lOYjθYg%` "ZbZpa4"mmd*)PlM~J/!%Vx<:mx~e_Oq*"#xnU\.&.( *ҙWÏLHGu P6T?/~}CqTW6 uj->" lDҲjкfya%*v (.P+E`JI<+򦈿21ݡя'%\TQUgzJgghP )x鮲}E?츩0_KTn:6w"ְd|0MH `nd ˕#֨En7rX!t|vx}i8L)G^BӒܓʚn;d&G5Rܸu`XYϼS4[Yhͅ$m=T?.%/lrg]ws:pF%n^Ց◇J1IEK]ō=+6IWE8l쏰x js]Mᢦ~*؆jG=$oo(QRtΞ Ua+թzr6Y6̚Qo'|$ ZT"hhC@KQ|j| h(.NbԖbM$]$pgTU^-sMŦZsr Qzl#,!EBJ ,x'0p†PCG1`ԭ..ʲ_ Rnb$+[SbGR|z2.LK8kvplq뙫=bzz8)T 7xl}Ge<zD.ui%(s6 CU=>5; 6 w.hknqo-p\Y, mۦ9yCvA-iJM}<+ G7ϬTQH"7~{SV6:òicɑ)Pdgj)ljm}5t9Af`\T恟 e oG>@r*[K۳ֳmV ^mho%ӈu)(i@D;-r5*xMA?* +M!,m\ g85%whG-LJ#`]IҊ>OYi7ӝЄ\Y&Yw"Od#xU(ץ^xꘄ`y O-4bBL~ǭĄ1ٵ0/xuZs:!{+)?@3 A H h>QhIbU2:yFijMT՞j],\/dU^1|uYuYAUjJ6%lRNH=Ydvn¸Ӫ{2"F<jyH2 1B&){~[ѡF0tIim\׀7|=bX+Ugv^;(XBz~YeԸٚՖS6 eC$r5hϲk'ObdZNwHuwx-Ԣ*;!(:8\R%꩏sNaIܪγW$N8YBlrXj`uUlzuRqU#ʝcU1lwjw[8 8FN\(U;su?4 %)dVu I#ђ~ Hi<g{Ҵ/gQ#v'Zore \*gUv9Q)U(,;ZOE}C7+/!ƹx D*jĥ0ֹx}=~K1U-MKdyQRo|w}K)V(*9󽝎еeqhj=YރK"}VdL_*Pcd}۸Dr)s?YD!m(xQxԥ||Mj%}QӨbӣ޳i&~[UŤY- GA@ Uxr~ӂ[xT;}qw%CWQe&czK1#) ҧn}HTRK)5~UDYv]9B$)]vSc#*X!ٝjkl;%MPxTH0M 햇H,(6 vu|s8+ձZc9l<`JfDt# " MgP,I"{V:huB+m}m_+ϩX[t,K;s>U>!~qۤ9 umj}%4 &k.Ec HO)V,O۾>-bE')l5$tpXE !M9BTiǭDVeת(^oZ"Z亚LeϒmdFwjM+5O[VMUau >9g(=>K1jkËu<=5{+X( [i]PvڬWYY-JfEc MV 5gY:ۀ*7kX|u\.[F[˙E{5&Իfq ):\dytmP`Kgif;\3 ><Ѐ*/}UMwulUqڳl%_lDCiTGpu0;hPR4|UD7ws-:jn`g@5WΎ!w󔢯Rc3Ah?wb|*7o|ϵlwl"I Wi5Ԏ݁ˆd+CBs"9¤[8b:_,,eYih?/7;Y3HwyЎ(F*<۞W) Cf52:}U /-֏G.(V=H}ASIWӪC7`h1(DZR(ZrmNZ3,:-"S= :C$ĵ0٤TkX)]SÙ!POL}EܜcԤ:ةSF*5;PЍ%+Zϱ [FOmɣar3(E"WD"gBtiSJ3dcXg¾ z}蛮PⒼ;DzpA=x9Ó'Yk{>/y W\n&Q7vuzRZ>$6VIS[z帻 MԳUF[P~צ.KTL 5U#'B;)'mNaہ M]Jdx+ǃS J''H]e>wʸk2>5f@Z ~e)[uRPޝkSjVNKN$ DuQU~&q3E/k9t_9s'=ϒC- E͝lFAx|bb巨WgM(4~xWKDTG}vݣK7n}2/E}p ʹ e4ߧPq!'bGNM.Rj /:GWn4ߦv!CS0+v5@CQМռgDnU>({Nz_$SU]ۖnjL,E zye6XܾvxTmeyخܧsG'+"^t2F$ ؈Sgxgu_9nTB/.64|;˔_.جyf%8өvm$J]Ku aTn[cG=G;{OTlIգL uTS`-Jiu4WQdH;O'=Nj9U?h=dڵۊ~ :eڄ[s9g*\ Q% volTB%R)]v'BN=;h{S:HVI{ B*C*(Qv ZSzPfCTΥ!\.uԩjȹ΢5٩]Gm)@ۡ- l&%`ܗ")F8f%0$D7}E4sm Uvvz6^%h?zЮybσV%Vq`m -vg;4^*v\ln`FV(<5I~[֗>藼T 8(9 /OSg" >OP s,J=$`Y`х(΍+Cl+"=~@<<[;nj$(1/xK G0};åF*أ.nME2$01r?&::؄iQAco/%9ʠbE'&:0.Vyy(툢y;Pjh,)*L$R4d{@N7(hcJw2/n<1鏝(*;geL{8ə'. ܭ$8>,~vPE#(+Tfm˒}A®_^yÓ$ |3:}*z AD\OިN brͨ$j6iQgܛ#\v(V4.I=;OB= e.{o*JSiCH_uchb/JϼS޵]ܛȴaZDm ,o:濕wW Jr g*?Qjʟv92(H(ڣJ:C-Qbqb!K%WACwvTnb\G0Y=v %^2$IV%}w ViA=rVmElǗiȤMC%6qumҕmt6ՃAErQ:QT[P:xBNbRRW >"{5\ +'R.gĕ)Q˸R4Mm [ǗnDQ,X*C,}567,g9%G5.0}S}49H'w vU}D͆ CiPzvF')up؊ԦrX5B`KZqA ȖGULP쾰9/CZ!KQLEoꟙ2rQ>5_ P(UóeҖPXU$駅e6 >7돡j9uT\amPۨÖ\kpx͢^ǽ T˂bg:cؓ {TJ;ϥrDʟ%)w_.}￝ݛK|woo?n}~y77w_XC/__` |_~75.跿}b~^ݧ>_*wӻW_9K\o?e~+_W[B~o?~?:՟ħןO?~x_}>ן˟>t^};W .r_-ՂۿZnz2 ZeE^c%V~_,._E.JK+_RJRjUբJWk*T_rWS撉i~%.?w\ߗT/¥ߘ~ry={˗}W?=ȭ|u} >~xW_/|"wÇ_n2>%{)u]O/WXdNϟ^M|v;?{O?<ڹ\p|V7z; ]j _^}~~Lhw? /_޾\9m|O\^>q/K|2|ǗO\_|bO\kw/~ĵO\xy&ӗO\kۗO\߽|Z/_>q-\oO_m^v]oz4=\~&7=_&^&~U |m#*U \ĥJkWW$pU/!1^!SקW^}t+U}~}#Wӫ\ϯ>rU#W_^eL>rU|>?~0?_3(wo??6SO?|}~Fo㿆Ϲ?OOؤ=Q.Bl W39UOq)4޽ûom(׶+IcCt2M5~;Ҿ?uJ~<{#~uoR#lȈ^tڄwڞݹ.^oܮܷe*Ǒӡ#P;;H)sJ sױpopb8n|{SŸ1֛]r-ܢlq(,S}n%h)ОKXc32ޒ&z>yxK.:<4ˬ];+*շZdRy!䖣m^FGm;RʙBѤpVeQxQސnגRvr ^T!YڡD#Ϗ#RފþIIcC)%>Rs-\n:CC\Fwk)rnFxT#ڵSYNijy=y8>Kv%aTMS<6G`kF?=ܻ&{*j0ݻftߛ25X|IR:j>$.HuMsMe<;+nqZo f9eB+fqkV w^*qáO]UՔhs򈞚Hja ;0/L5TQTk=UUl9 umӶ ׫&UיE!QU> +S'<oҽTkSY[ ɖvj uQ7Hƽ%TǑR.%]K !)Qt]D6ɂ3:tSȓ(Zf-,P..vw{xˮ'm5Uv%Njn멖}nMڧ 4QVƥM; Y5ԖFBъ&=sTb#3,DzZD##Z  ]mNls3=dYK)e}$^8ox peBHZr}\[sI&[r0>\SAi{Sӕ]5E8Y_ǩճDpR&&^{ۤ|TZ E+؎G#՛BjZV7=ʓ 8p2Jo*wSlHv<0MKHwؿH߁KS CuGwi m9NK%~jأ5cN2λ'mX *c!Sq6xtSyYIYmRˮq>hWbdi{.I-C ӫ9+2ꑐF.)ҴK=Mx:z+ @%+jє#qwJ*a\ r-N8NYhuy&uŵ -8Pj<6h7ֶ<|dCr^R課N dBtefyU]讗IDq^6oSa@L\‰hb'nMbK$F,=IT15:gv8%I&+`seq%t"Ot$v狗.߆HC2p{t-R5uzF =Fp̉=e陼PHpo:fuqRBSR9A?bmHޡzOe=BߡxvNBZl=eb7=֙\Y"rO>rdN"Vf RKrh y:G$_Zk-5W/Ud5QEׅj$iiL@Y*+ov /Dk`8|^%PkD>dbEbN"bQXځt*#2Qyaq:Lf)MǖyjS?RVX4CDΨ|[+$X Xa.+eMnRI E+e_'%UlNp{P^O;4R`p8vHo&Xk* { KPPYfiU' V~]0kBPx8$=0Mw%.KzL")dz.p(wտI5)iqb*fc> -=&jV3IXC!ո$UbpvXFg-q?N^*kEQ;#:Y^U'u@5(d{ڮ{%Z}k,0N=5zH`zXR( չn.;x[pN1)`:ƶm%ŅaJ˝[Ƣ.LMiǬj]|awl͉ OqS L4+eпДlSju,{5\Q3SW}r2I$X?EVnoJ7l6O75> ZMA:`tO]NCngӃȀxL ydAX/5-P;8I ?I4E^"0ǡw4Ea ޞnj}*s jh}9ZBTyS;-vjW1r"Q!i.supk%$LOU{renA?+hzͶ2jǏ ^r.<qS`j:SaKW;Ÿ+.*/kAۈ_Ba]zp9 T JT5{NT55_Nnx| g [z錭eǔL]y[r@|-^KD"}"#{$%O"e'li}m,Mazl^)ov'LkEABj,LKkkTHsWE6kLSb?DI("M3"\uWZtZX7=uhxWS9T۔ Q/qH\* /fHdspg<d,LҍH\? bC$*z!BtPb[ղ߹HԊDR+ǭ: ɗZA .'ۭw'sSbe4TY_2/m#̡ gՊ^Ӯ~=T x`SDd*sG5yS$3!t%ʀPj~+0㡲$ALAMpZwLrs&Qa%zN'(ԣpՠگj`f55e@8| xX 9^jL!)u rE͇(ҕlʯЧie4v^™tX~Q;X^ ,=4v۽,7&,'7~azt^ l &EKj 78S'2@ʝːmimIˠ .rJN 4i). Y7g \RGM޲wQ"oxw[Z*gc qp}_>eKPвPӋp%7f`nfiQ*gpzY} ȳY>W/-eRk 5V+ *컠}"^]͉غWP$(QvHm0)]mǞs&Oо`0h=WjD:ʩaӒM|A(īCe1-s0nsXUDQD}P]xq7-3lUwxn lM+O԰e'^c=Q`^Iqb9 hv-KʊU0^7ap:I9Gѱ5*z]<uuCݗU fS^YGhՍxʞ0~tlzynFS~p~d;۠7]:Zw{֠\C8.nZq̢ " 3;1vyE<G,N)xO cmo*yk \ 6/b@*:^M PF^bHΏǒOۺfbUY,fYJ@jr?J♐&<'般)WqV!$,ICЋ*#DLVWG]CyP4ǃw/Sqӑ &C%ku$C^yȥK Q<lek]#ݞ] += ^s=L]/#yO7@uLH\m]y㨌|!\o64Rj#Dn&hP7Ad鸭\W[-H*ҖvV(LT {r !3,_[=<=qqU~pUgoKZq?lRIqctyd. {@-SfNje?HTE$TTn.{'S9F{-]Q@eg7C7G>4.o*hÏ NxS:ٻs _^*P'hYvW:lzGY#g8ISFzHyNͼU?i*P Xj v55M+Rxm嚢ƴMPX-;j amEnqoҁqT(izgS*E9|P2Be|ɷ jlX<<• sjQH t]蜭Alr_^%R)Әh OEcBw·ՔHYqAy g=k-?<tH&UDIڛ}~kk;(󺥃%5/ӓ[ǒe.$f:f; )f]1uO[bo6Ov=sYKgif4&<0z7V%<_v!NAp ٰzZf6K%Vnxx32DcYv2%g9A#&Xi;oV^J8E_8 CM*iЕ43%kzzŷ:5,tiO+ H |˩D`(5+(wQP_'),*&$6e ^iޯ[wSJL fɿBf5 ^BϦk6[ezQ14(ZO z j %6ʤHṆuJSN2-Y+5\ 4(^wa 7NKHϦx*A 8"o|V%{k% [~Melc :s s<Pl)WVA+1$*:Q>*Z084ɝ+i$?-W"];Y'ZyiWZ")2aSaVmd+%Ur1qIz%zo(&$1wUy@GZZekgt(ҤޮWH T䪏:z 𐄬(JK>lľz>zNLL*M37$Uu-K[IGPC',[T9Йȡx Bۦ!tpZ:Akp2D0lr7)]2ob-ҮO퉇i.PS@aglqvy} ,= 2,2-BB'L dOx>KY}v%tاig׺=󓍟l6lՖ+@4N#tP\/` 7HL:(|6'j%jK+w}x!tݖ5fLD8a-4dX4q=V9SF T%&Ws[ͿSKj=̿zrs[JܦIb#v~)QSnwZO=P:mHIJdj ^ԶdUQw)1ԫpSOw`ͶO9msKp*Hu짼hz"u`%RW]ݠNc:ѠZXSRR'{h-7(EyfhUۏ~SJ3pC1t*KHMxfaj{Tiͥ劶HEʊC`9٬{>Fls<=fv^{ƒ̐&:Y!ӋK2Ew@i<\CTUÑG] סQJBs;p @rWKeQlf>><&SKR^֮\^/;i !<+$R;FK#ܝbm !6W(4D ~c'?Y2yN` =W 0Zl`u=4 E0=lϽ{j^ 8U;xnzgnśigLyBK"F2Y)?b\mD8|&E.noEqqXg:ᩎuvǚޒWRu#Fo1)#7[SE/Bw aۗaQM4b'+TXh"n礕_{%PY4amAčN Vk7/=7K˝yZ@OGʚ=%뒛;J )VޏhJ /sT@:j H-Y9A=0O=^}iss>]}4jZeR-yW^`{Fie}iH<:Ta$ܲx Z܀Mj@sb5>b^fo@@eS\VnM6p: @seAF.`nW;+Lhg:gtXC>.!4v_&ƺ3l{l!`Mɚbfx'-M@QAS? iRٰvs~qiK/&ʐo?zh)(L[UW2}Iz%N&lGVwuKUx|F ;K#佑zDzŰ:Kӄ$DG%3hHoOE*A$O-OY3I=zW1҃ys `G8呪2=tkRt譫_A\\\L3NT{}Ozjf։H@KM7E坁Q>ytv =;cȁ GVOVgVN0m;8=5}̗ꌉ⑳OڲXQ^a>ݦ*Q;u #I2)7E0~MU?k ,d,KlV,mO˾vVeJ:S7 y+(('omOWrYjdPy{ &Px#tPM`pPGdCE`4[:d}ɋִwT[ub)NMI0^Ir )޾#"z6e,_,%%e$vtT4Vl΅ƳZtsldٺP/.V9\͒>|2RKp"_f'T1J<] sû,vGs'̖|I02Jp{[ `J;&`Fw}<5,ktŇj=oUfOe*Է3ڊN ]~g#U/I@P/),Yw;epSFHNٛcyCBbS Zfe54B^wОTw  >JHM_z4{\vWuGoN1MK@GiH%L;{?g2|Q t9\Blt)0^,5YM[[-TO ZTkGsGLlܞDhzgcK)w۟QB%.p&xvֱ#M R^MrId#"F:{,%;[毨7vl^@ܓ]& ݮҙ8$pp8m[C=`O.faϊxPw!_ɬ.{A/2ȡ-5MsDK_گDaF>.Gǡ\3je*T)S ^ F>m!mˁ 0 y%/evy(հecqx2 @)C&J1ո:5iLR Fc2ݤ_ gjMUn֙zQ-5 {%׀i˻>6ۥ&A&;yC ~'ԒQא_IBbSvR}A>F$yEzb6ڞ, V_*@'zj=Lde`{BBwmzz,NVHgv.Sʈ5^ˎLPT<J-5?HG#A_YƄ ZH{&82ScL|Iԍl8 9:*C*+X/ihOX܁m{=i$l[3Tm>ݫIaFko\  <*u@]HRlVIהǸ*i#I9eAl$ TiY$JQ 5B8%~dEc^n\<>2 ɢ{]r㖕8*Njpq$vgX؁YV3{އov5."RK#%W՗[h>ڹڶ9K]MBKEĞz^\̎(OlU f#7TTUd% 9Kd;zY j6.ls#1k\)QAϰ$P2P)贑AV]jD¦mgSWG"jD]Ξ*R$OFXhfT& 8pu(oXP%j;|F !|v='7;]{֦resνT:*ʄGQP۰KǕ}@Ng^:ݳ sYUd*r.^hӣTPMs{JeKډ_{42pʯ/ Pw&@rYV#e Fd͗gIl"L 'v {}t]YMmM<ۯ5/M#:,c}T|.n !-iă UϪVϑJzWOOXHɁA{]Q$_r'ƐpלcT| vө#wun N9oEpO^Ϯh5wg8kø%8%%;װK#+s(<2_`zAlc՝nb!RɊBJAy[%~!MIppAt:U%dO\,G_ eI/Q AӨxNAke4iI_O?:??JV%p$_D3 xG<1hMI'XalsPX ݲjS[GG@2ss*Jj֌@*GY4mEp▤iv~f `4ΑOv\PRoT[l:8NY X 1$8Së_ t9*2J[Kĸg"moN]010%IUP&ߜa&R=(*;?jLpPu&Ҏ!u{M_Q=wXp.PRN٠ pUP9H9Bb{y$Z],K7(W[Y4 oږwe"=ko]N1;y4.F5Q^lﲘ'JVN $9{$'6Wq>u*/v] ǚʅײ< * zN"+Wl*4*þaMU/)Q]S0qt{'!>@fބ%?e1׉'p%.@oJ"nx|N,Ól?'L|Ew9:AsęZtnvyYR* <(+|9m* JhGoݻKnÕ7sUiѶ{x+v2CDٺ  !>P<*g/Pf]>gbF-Uq+T0erS)\\asU`=DIM𡩊H-:h(P6Y"UY\-Sk87ʖ.򔚐(".%Ge5r^v=-κyLM!7*F&!qZ )$qs``[Tx4Y]l[m6L[e3-vv4Xo6'>'9YFC~'n~:~K,lJZ2պ6^ȒwhVJZ;}K(++Qv/K.EJ#kK1$zwZMQ*n* `Z`,Yyܐ@MJRyc0f~F)i{݊+dZgM(妖JPNM Y,RJ#oN 5CyppܓlNd&?xxrz(x-'MknsyBrv~ʴ`lxZFEȤIIEXsKp{Ăgc5IR.vȸ@BdwGĎ8jl@HoA^  PD1nR`Czj,]$get[ YqO-9md˜$Ky-:S3"K.+ K{&Dlj`Ą RV7W!-M$ԉ`q`NbA`\)[(}G`x\[*WШ7[E$K:OrJ,J\OњT W@ҝQFOcH*o^#^jJyi2KܾN1?V$ll+zn)).@u!y>iP,>R6䦞Rr]OBiP$rDp l@ #tW>^6K܎ H*}WSVSI$Đ$*pnw*S.N#.GJpq^oE AY|@VĞ-={m.qHxbqB7%keG 6TSS N|Uƥհb&IA<1va҃n}k cHJ%z81 *조S=ҭXLFDdqxDTjarR;$6%/H?eك=O?/4㾋|HzS XؤdH:t f ~9$^c)P [N'e{ 3frɝ;Ojy#߂Nj6qxw{Pw pS"T z ҤLT]JNbtM%mUcIOM=s]F6Ib6 N0T֝mE:¼~(ڄbzgytHYM9KyoǥiG8=罝2VdO h bo@I)z=YTƬM8H*YZ[qW_'1DDsD\la{Z/5a-@j%b =sVT^1);9\Co~WUSPIQ rZjއ;pϫ ]zs#?`S/8rR g6yd\N'>pR#A3ٻc[(ɫ!{^Kf~9~ Ǻשztٞl$bB‗K':h,بlht-xn8)]!AٸEӨqYpOz=vM~wnRkl$ l*㌉4pDkf=c-*-kˡ@9UV s\V|J "S%(;o *c5[j؝iUFGO 9`AOURtЋ+R.J7U?p#Tݲ~M,>tWŞ;n"X¸9L7*y[gnAbO"){OK&#p u8d4Ny NIj{St\Z]_c,TRm8*\NMarjTwm xݎ6J N:3=k'?CMvϩy8* a Ldx^A))!P%,"Eb7NpǏm>((JY[,OϚ;uU~:`VP[ZnV-Z+]ή(AvmˎWY4 yy޷t?♬˽f˳z:t再[]l< Rj"R>Jn*UK\88}֚9GZsg*J<Z@:4XvR9iF&*ۭܤ3 $-E?k{ɮC(ĭ8U8Ƕ(MS=o0vt嬝 +W؃:C7,gjDzO9byYclvn*%5Z) Ez xꭗ'㱆^-qsĜ`?c.F}:\P-:23Q `H$oAS+Xu uD穙RQNEPrtu (wwB[]Ǧllї?+q[J$_Bcg#<>4w!S4OK2KH\mN;CAveϫYCBᜅQۗ ӯ:K^)PU(Y) (j迫sB=Tzg&M޻5Z=.(sF@;|'TlBD'J1;'J MT de 6PQx;iMJޭjՒ\>&*`*sͅ%d͡6Swj^G1T&9@<=<˒7RPWʎ_nKw4d{gNDEv{rGh9ٶ2g@Su_4EA~=<8hd:g?glqPGXİiCߡۺgO OǑO 錗2d0<Vx,D]R>nD3 ,]"95+Q,Oi۲ayM{V ˾:Tdӎ+Tɲ ҝG`ϩ%x&^Y>׽άmrm]d ; !~r6෧<JvIn<9<Ѓ^`PI56).9qlAyd+9d7]?]ҖZLΩYPg^-ۧPtR9[ ͇|kzR9鮨ÔeGc"%EF]I,(<{ t<. 3˥Lze8Q:GX'33nmt{ei+ha%=Q)>K]jjI~iEzV_\2tf;V%~%(]{=I& --+;_ZdS_:@L^D=Itvv{Za p)PvF 'I❦U{T虜6|d5K偓<n?:I׺ 8)w:aNGyk C JV8IEi`tXx'ޤ>k}̛t0;IER۹ܸ/R?;;I阔teok3uȡNK*->2f5Dώ+ݩmLBVEpYܓ1K޷ۮ8 q뉠קSr\"u]64MREqnM,,}hrؤ^ђ$EF߲8@҆jRBtȈL]7_nh{'iV=`>edTz׹hc[5:(5KGw?1zTUzNGGšPro;YNaq8v0+}CU8=qCH4[0JvMuW;'bku!\QѰ#yyfJrTq3]nWQ5Oy,9P>I( @cSy):hySx g(ZT$pj tH5x)Q s C^ 9TVz]jC9a-1;TЕiĥ}]v59isRHB.G2ȻyScBAIEl͎%slVYvY+ >lĩ t;%*A|@tv84=nez;7Wc7=jl#>[OW[֧1лD4e5A_yL^rb_{<9Ro S#dr|ek:1:K1-%(Uk#8.{`,IְcrJq\)D2Mxк㦢mekԽp|hRg:ziL.zVUDS@穱mA(7hY4rB#H~+G5x1~rTE]˹reV[޴^6Lm2c6oN؜M³ɪ\)VF| <_qbղn m?G{Y~J4k\SmM3 v=meO{d&[`} 15Wоelq_w+LRFh=SiuiW#L,H<$h(aIs^ |@U1os* zB^3__wo?q۶?wϧ?_ǻ߽vlݧ߼"~7/~~~>^ozowoRx_׿9?]߾wK}}o?㛿} o{Oo~UnxI޴/_7o>}7߽Ϳ_{ǵ߾~˟?|o~oOO>O߽}~Oo?v~݇wo—/yw߾wE%|߼}9||~7G o,y?n >o[|wo㧟7<淟>oE ›o֯K7׻?R~W_*owow?o^no7?z~[ ?WqA\o_>77t;>ݏtWy޽W_ⲿ}v.7}\o۸Ͼ痯p߲f?|x:w|׹&>k\_}̕_ ?\w/_ Zx\v闋.jɕr\lK/Y*_/_/bm}uyju_..r/V\Z)jeʯUeW*UZSi|rjEӿ2LL/qO?.i|GnO?U~~û߾jWF?>rŗ.)߽Kz½|$ w_}nǗ׵s?߹~ݫpHφ˵yՃعԏ__H_}kWkeݧ\ۗ}fB?Qx"i|ϗO\k~Y&I?|?|ZO\˿{ĵ'߿|ZK3|ZO\߾|Z/xĵ/kO/%r-˧~~j /?27}?^֣ۯ6i777Oķ҄GW૏nWWiU[GW^}~~W*crUx㫏\}H A珿{?յ~zW4+4VF.Ƙx5?OoN>DV6i_?||OƒW39UOq)4޽ûom6o<@^և>yp^Wݗj 'aQ}jW3CMN{GIp-aHT+iLG5Yvq_Z3Y8i'irNmjzLVxIǂ*~ձMlo^o8Q)%ߥO͋rv(j']I#Vk-f,黧H ֳع㺔5i5t笻Hmq9GS-9qQ5phW gEo٪%:yXt:nPky:<Ϩv&LͯttgxsWʙUё{]5˝Crv)ys^WC=E,#_J~JK8tϊeEt^7% 1-I7g^K*("<`/iXeAr}`gnq*D/c>ρM<5}ījkhvwJlC,”ٍ̚bcJpťUY0=T p{:IS=iŭEy|fzIxMz$ ؒ$JuLͿ{Hgk]Fc;(?քq)7eё=ןNW}ڈkey&-˔P,˃ˣV.IDpFKצ}MQ˹_B YRRqpm ڻ~5r?y"e{rwSa>YAwBũB?&KҖpi'4.xw.W T|ch;ENR%M ȔX"S8 #ѓWqJ XDEi=r9~xՏ.XMS-  Vy7C*1[p(+8{Ѱ%V|QrHȪ;_XV#.bN#i>y,,8VAqnxYk.[Pt3q16|+1q.vQSW׮d_ePzTi-Ms}UP"H6ʓ&Na/kbQH{7ntWni9Q5$GʨxS)Cu5P|mImij D\ñ/P (S+l..kL(jQ+\Qʹ,eR{*߮d?ϽpD.ʗRKrM7A3Җu&<^gU=\;ϪZSPb#\sۼ.Gܝ㩣) mÈh8v*Ojm_ S]JrLoΌ ¡\&@7eˤPN$>j Yc]Ϧ,Y*?>'{xݬ`id8I &A=IU_T '@Z@9 FQR؆FX*GKádR'su6"KӏA!GD1a^;8 ;&j4*5,ߝR;SQ|Kk/)ϋ!rYg0eoA*X~zXڌ妫7 yzXoSdғL<'<J ]mv#kT9ˮ@#7鐲KI(IK؀$Zå>NNϬ~>_)oʘ`S&MͥӜD_'m>K栐}sco}bLYSn+nJ- LIJ-a+pOJ2$1#5¨AiȴZU&|R?QM"Oyp`VeQP ^|sP2&%{֟qSc=EcRT6i볩󻵤Qn]X `ѥg40[IcA`vbQW\SXv}٭$AHz馴UE&^5¢:Jft|] XLrgiCSPWk|((2)Z p{*7eAիG mRRm4B%ktKZt*%ao[ ކkU׿@ZEA+H4U.o#"ݕVIIk6cTjz{)ὍcA%˙yX^T9ڀ\b-gƉ Oj`*dl ~RlP>Ntq$Rɾ6\ yXe8*,kRp X`vߪ*9T]<)sYYR.::a$=)n\2GP>o"vsnDZڑC;aU!੊~{8]MLaJ2y Nx6 ;Hgr;L(<Sɔ #ZC{ )S@]j;{AJ8K* ^D0UVSp$NjGXgGZmH_.w-HUTĞvE,hSuΖ)5nqP`(ޮ4`EӧyrMå o݉GVjMJu/hK:!yj3CRWIù~tMΗ^f0i3q҇-uR=ѓDJXd|)r! =,yVg ө>ҫۜUM+ ?sfj+k ě !X~#{gxlx'kCAcY^MmԓjM vdOX[ؖYkUEeG%ȟba,p2н%)<σz"|oΞΤ (U#j2έ{@9JFt za]&u;o7]_!PwѡLSuP`rNc[fZS9ve*)q 4PxLS~-KFT۞ʂ5jC>OVlʿu̕]@0ׁ En{&yH/F~wM4*q <@o4]沱Odz]xCXgj=W)ISs3,[ _m;򰼰7%it .n2Ǘ5{\ZtPzu:$`@uQ %NE˨3#uܧВ^&-=kC GFQܸEP? v6UVUJ@8vJ^Ҧr?PMD /\O?(h-lw'[sFbjo)*гndaJPR\VS TESGIb[/I*Д&:ھP V0GQy_kx]zLd9(rH͛`' ,[ٹEϓ]+Qd넴ۢ@FT9Ϻ{o{Al:# Us+m:#5ijKIXei"L{ga%;zV(%;O焍 ah=4¨!Q)UOUٽӭ#~)*H@\ATGEN4mϥ鰠S{ҥ QJZ)+=H`BiTOЪ~hl ĩQR(m, ->%lb(EX5!X%S/[:oWFESQMǓ_b| P)GDM$r_ Ecx:DS6\~rrx/ фȃN ˥}R .^݄f8o rv-\2-Xg~%:rrN8YhU#Xf1jҫd@m|tTg\Na2QNj 8J#MjMwt^8ߨ2lxK(F̲tǩOA`te?FݯeIdF汲[J8 FYcwmZU!P@ynҼuKʙlIn NAJGP79.?b[)STTsKAK1.O':.O:_7>6-'mXDKVoM'V6>U:Xd_G'Z}ȉ(Ȓ N_P{T~(X]J GQnQ,HN*X]F̞V4+^SYՐy. '?5_9yg&[r*j(*_Mw,e3X4iZLPcD+Zʇe x4{g6(=;sRgޔ[8@|bp&{>|cq܃>yi+CWKP~sT{͜i8v׸٣Ł"8 "jiab}'8dn_rh^UX;<ԾmO9a;萑JT>cl _:-G;M8X}r씘+XkKV~RLjjr;է򤊂>yKN<6im*VUHJaF~;Hᩇ<&m#D^1yṮ3NqsU}nA \Nf5BxHwmb ֥^dq}h$*ƣ.,ۧW **E0M=~ 3$uG=>q5 ?~ K@g~=Ǣ%=p<7d ᶪ)zj#\:OAʪڟ-$UEcXC8z~1IMxb ! `# _ZW$ZROdBQf,kmh:.E`KH,;xJ&V$p-=zx}@PY]KiLۋvn>;1;8GlM?di> mәL<k;ȝ^'6 NEJTq)|j3(Jvi6s"Ekf4EpBIiD^ >/6Z :aKY`IQŐ=JWr$PDwv@\u{n ttrY]`J@WwɩbU` &ݎIAo><8ZݳI(v[^ʭ%uiλ=6r>%%q6ढƁ༇C%܈:}O*R [ɪLesm]eq Vͮq G#;ZmJzL.˛Oa5-ؚZщ1"$,/$ws2{oK7MW6aRjTr$QdJև4wm\?fK&9vW7Z2a0 $JnuKZDezUɮ^߿Ahi8g}>YS#-|XUΓ!rpzrZ`o}M.k܈v$GhP%ĕU<Сýd~Z!Ջʧrej|>u0&t+-U&q GduB=LU#h`l1ID y#65ĵ,vǍ@%P~)NmtT&6wHwvl|gl}yM[dƑa)4NQLTiIۀf%7πT%Önm9s"eFQrVm{V@Ep7w@d?RbL [^Wr2 N Zih@v5\BHEboY<ūY|<,kIS"c~6r!梢S~yfMN|Va6)aT=S #X@@Nix0^ըߐu>"XֆR+2!nLM{dbiuU TsH)UvMJ8NUIYGWV(Z5G">kZ8WYCQhE ;EmeGI¨&Y9J\ܚK#P<9šSjY\2SUqU/D(9T#)1Q!خaQ6my G+St&'#p%w `fɞǒ2:[DAa8~x+|P %><Ϥ a&NنM`({̎? 6bM?2sݩS h/P_]-guxUڈNWgHϭr@OA#t'uڤ*Y9~obEYR1'y(qv9lTV-˔"sː"5uL۲pUKuX.K~ԑ^Y2}'[PUډ۴M7)gDʊ=L_ۉQj{ye΃Ȏ1Lqw@@|NwbW_&{SYڟF\tG4XU]NTNih=mu(Րݸ˴* 9EKʠܚ>@( w@GVW>LJN?c,qPB] )Ɠ3h\ߙܐ$!9v< Nf[3VSo (R_P-iՒS7<@\&l -@;=rgLn+8.I 8GWǾM򎇝է'?^;wB8poF⊲4f._g XF+ JЯ;$i.}79܃s`+]Gy&SBO2l){+k,Ymsjp),RpI%A*;nqH\'*߆zwX;ratFn{:~yF.c!9oa{dRUֶg\:*"U<P;^uI1S7N`Հ)؜?5293Jņ ȏN%AL5{y8"M]E9ӦlOzf !Fq%ßu}MQ* ¯i.mnW@ =B:^Ašx^QP`0mbǃCdXXmJ`;Qs.>_&2:[AyحsK+#^^3P8tr<Axس\SۡM*1@r, E.-odW$1ismg~{RnEw8@J:;]Y&RЀW+B\Ʊl(fQN"&A1P%Y˓L[u$B( \FM$5)tk6nͼHh vi9^M6瞔6!Od/@&ګ :8xHf)2dT0zwV~>l ŎC|gz.x,r 0h?D6!:Wx,8rF*%)3S:Y9u0 U$iD$pRs΄=<^D{2•;SƫC_S=*?ٸ8&\k9c- uO9؃2BgX}S|MM3iSם|p;(FSk鲴\ꀷFY(Ԁ08٤ QIwF:te*vIŐ0&)PTv(Kʛ(Eû+#};8o[ "OeTG^^Et ^ȲnˏC `0'S$Pj %o,'\A=K `'7UFQNHK=(6]4P"f ϦD a]; gn&84J|y@ױ)| ])h=]Gt.kٻN-Qn*=nI?<>ihm(8ḺQhNI-y(pepJ~\<7Ux1la85: 8SԬø;5AY;lSp jh57XD'ǀSѺ v1S~!L|m Ľ}~ْ>y]J ֯'{Ff֓5NHcPr~/Φ'd5deEUo֟jn֮"D#MAE.5<3v5PO?(E%d۝%'C)X>T59jd<%;a9>eoan2k HLD|[]]aՕ)naq)aU gיTVRh+v}Ֆ#%Տc_ KWg:%_Si. ǥp,—y8%ӄux2:|cᘚnIP$96 OאLMjI}ToJ9r:-r CWУXƷ$,T>dلmPcI> Aj4vr8IԱy g*DyچQ*RВL;? 1Q9]sűsg#Oʌ%rhRT".0V۩68(SH Y7:UOw ܨ&zɡהTճU8-[>$.Ҧ㒆OTYT(+˩5GwvQs+.yR|xxq0"q>恤]{A:b$ H&N:̶`aP{SӖ7`K <ե[֡r Sj7R4Q) mO=́TEE^c39ZR1 ͖.tBBd&o^J@ )MeQ*&!5HsXgZQAIj Y<]ʥ  8nxSp$6bZ[O0H*T^jFfvʍOl3J j*Mmu{j*8N^li:ñeź(Rt(,ZO=R-r*45#pRΌ`ES@p Z3=)-N9b5jܔϩ}:p'vy]!^3UdB:JLSe @VS75W"ET)Ǜ|u%Pk:cCR+58rjRS8FSWJ<v. nELE#GvQL@q`(FBYWkk؅ <]8$,^ /BU5Ƶ:h:@%:Şۙ7* ']էyŝn:o~g]K[&Kse|+/ga{zG nD*x<8 $Sb2]a)y*-%8HSoR#錺Wam"Awz &yav@ճoc]MLiEVgÑ'ŜQ53ǠᨺZu(U%̣;pv3oAhN5x(<ǐ;;~U@@aeț]wqHzV}gȚ 3 p-ً9p%4ZA5|kq9Hf"+_iˇVK*6Ņw: S y/TsQGyRbYS&J9W![ݳ:.-0AjLueF*%)^F0G H;nKF6V`ơgOU^j?%qA)л~r >|2ũ.;?oŮSQAp2iLs{m_[a=R-1kj0r5TEⶋ- ('+&ԃ<9Q!=STW)y jVi6[9QyQBFV~}y%^J%A}WrHkpr,BGs[Z5} YR1](]Z^t#TAO;BSzv?Ckk@~RhRN0Jrg Rrfcrߋ#' M!p鬥*BR$[a|bӫx<]kRp)i{97vlU^KSrQ } =?`~yt3MYqVymy=#% ;@TDt߭(]u=x3Wuvo93J91ݫz S6q19Щ]T]lh.!I|f \j$fa.(C$}J[DZŸS2Rbq{+*E=riWI8BޏqK nqUEi":MC5C\hz)zFf;jAN{Ph*E蔇~|{ 74U% [MI7 FO4GMJ^'5Dt`ϊʗPk{.eÔB]l“a W)(yΦMQve̚.T4\{5:D]§`>0&.&3nx[D8hD@lʒ*S]J~@Z2?K#xܓԻ6>Hm[f07.P}6 OtY]]Ggʨ昚WgUaQUa,/{;@ ɓE]A$U:դT,~n "-m[†A~MILLP`^<+Ԏ;q h؅?G O^*:V+}ޝQU'5 DH:\F="squyK4zS8yldJuMFԪnb(ۦTVU(1x(avN[dU+t79gP@Z2$oYe&3uSuu+$KlJDPd}bF6{NQ'adf1RBKُX#uC%)A }=(^Kqi}2%R;ѲW#rO~}0yߺ$T +_.Ÿ­[To(]eV+ R/aKfxqػ7<3}(zQC@PZSF'֞b :bܱm&+z<wt#U^8+mGO蓑[Rx50#f&tW5y >Kú~8W'{?#@Ӈ|G5ӕN5uU.u~ȊѦ. ~!&3:y|}qϲ )ؗAvN*I]N˳V5:Nih9\@͢rHKqs_J-TI?m)OK ULG4 Tsa.҆TyD_(N{XĝaP5id'qrIӪK8V!e+lWWaKIT%]+uXYs]JNy:Ql)ێ-VC3ASߴ{sz^s_|{OF7S0'/\($EZv$A.v׉ YG,C4,U#ԥڜO=XT)Qy 58X$!\RUcđv3@4/̅R|+sŵA{DTrn̰ٞ =UW8q>Q9Ea:4!U8o?ӻ/BO>~/͗/y?O~o}w|}wݻ_߾^mw|wZߕӏ\׻߾:|oG Wϟ߿Ώ_WO?~ӻ˧՟}y>Ï^?}w}//K Os}oyze|o>|ww?}zǍW}?{_|'~⿿Oor?w_ӷ⻯ozW/}o~/?}xyuy}~÷o^b |Ƿw/{I o|p1şo .㛏?}?]ÿ|z]>79[\?eȕ/{~7C^>}o~oϭ'.nۯ?~߿ƛ}o/K~y]./|wï/];~ ._.V\h/Y*ۿ\d5v|/VX;Uurq˵_.ӯU겊*/UZSbIuZPGW%Ӿ}뷸ǟ^_K~cms^6;#O?zۗ߾⇍??7V/]߿K:ׅz{I&俾| n+s?\O'\~}b\dp|VW/_<̥~T.͗݇/{^|/ou߿3GAԗ?z7gNk_qW\z~^_ l~e}_+.zk_ZW\_~ŵׯL_q-W\߾~ŵW\߿~ŵW\_ZW\p/?}_~enç߾G_lr/?xv7ׯߤ !/]otۼk~W&mޤ5/7$pU!q7{Ao~x[͗\է7_|UK7_rUK꿼ɘ\|U͗\}o槗~=oӇoy>LSB#G.,߿a毞wGO$VQ=׿@򇗯|==5bK$6sx|[aG[i9-BQo,l|Naǭ{{IN\W(tVkBv!eq/ Qϫkz(ӳ#Y cYi};rkS{ץ&JxҲU 4;)i µ*k9$k)kH)NÎ }ڣy$85ݼz=6$1.x?uI[;);gr{LWPoEbӺݼ Fwu9yh'5s u暓;O۬=1~wZŲUV*<~<9.PҧLu%O%ZW޺WS)POñqz83wQfR+Td;osjf͈5J£ONtš~ž*'0'LJ-؏G @~zڹ%yhA"\ Uyt9d|vzρmgdq=#[2 {0s5]NsӎV;mzs(5a['lbYS']:N5 S6_?ikM zUxڿ,FғZ~D}ioJS+{j[*e 8]I9d*{M4o< :KA\}~Z7e6\@"DKTU5bǒxOH䁨 %E=5ӡaNS14xML<xڔ'hpKR&ioi-Si T-M~;k`WsEw$nq8k/c\:afHLUHە?wա[1L;F`]ɅjdͅxqHW;7ȭt/J#IsI"OT'U6n3n^, o*wuSB}Qe.tm=X|s9GA@ CĦΞnIѕ 2slƤDvF2qXCWKKN;71Bwy"O{t9sT"f&굑7%>xMQYuPJ}xh}u{URBT.g:+g?=lgRDvȤG Ȓ?% 8iY3to{yUPaA7ļ}3<\Ջ,SM"xiJ.Ȏȝ?t$_KħXg6Hq:%gtpf1xL2-x$OUZ-+/bNV Td2N&|Q+Ǔc7 [q]b&/YskLv{=/C:V+al:OD:r[hV d*[hS&*%$wޔ#(:?)'|GH+n9iY˨E%Y seO䏢~w3:_,0!/c(Ϟd o؋,u'ՐW<$AyP_"En^!/yMw+{_db>iAM2FNեZ˱bҜ[.}2ai6T+Ri4U΁CP Mg/M^Z}hV>PRI[R{%wۈE!v~J&(0xCxP *Yt&[kewѧTŭ;"€XZ n呎@kq_`̜,fCKP֬#%OnMI%mȉj֜XӒ\nGG@V[q o -*#n(sap(bIhpD! J-ϱU1c55KdV+UsvW: (m99w˧iQd7W5̿vGsZQ_@Wˍb::qɭZ城vik ;ǶCIq2zq&l*i]H`PnTT7nzK`DO&z|С;F`Fp/Oz0 Om% ɬ@'c7Ԛ&{ ԸH9x4JQIU@)gol39_ֽ0N,uȫPn#*SRy*e. Ϲz2HBSF5-k DVy aLch8Z__A,U~ǹ -tʕ=*VI# -3l$qSVMlyPRsy)$ƈ(+14lrjҔ]2;0Rw:yf Ps.:@;TԳC 5J²^6}o<`$*N;|ɉӜ9H "[Xuh.yĝC+"'H}r t[5wt]b vNRpM 5Mh@x̒"qtSOOQh1(Ah2FcIpU, `^"o\mBoXJlӪ X[#ᓿ<ҡ}W0+wVxg TDʡgnV,eA|B~NUu{ʩA{~'lz)D *uMtR=\*#? yI:K`q$%M/¦]]&W^ uPH c\T1[Sv6B f}ӡӹ^'mu"Kmlʡ/ Yr[ rw4LDo+ )zY  I裂L/B/b]\O3gS//+r%vGgYU0cpz; JNV,6Y<@Iũ tl>E6SsVkl=&;1nt^RUb}Ssӑm4 rx+`(5gQhy* (r973Bb_*$_Z ":i+4VrS{y6[ !i..n]zXχ]6KP"|5cң< &Zls;mS.:wx>S=uBoyJvU9noRnMMZKSZbtsFeί]܊f,-e HQHgfA=Ĝ~n'fWX [)âo3lpA)Gd@eoInh -5N{jބNi#h9FV5<% 蔤a賙mdJ 9CrmX+&3ҰI f;1Lw׺SDx:0t;[蟻 i˪N~􌠁}I-86>f+mLKf!d8HPUDM@ZYѳnRQ.u n=t<<97g:xAUH5Y6J#{nH,D޾ PM;A k+ E%r+s,\c>Vd%> (f>mSa=+muMIKHE]٢{@`[jC"!l]~Ux!4uЃt/M}<.l ǩqU쀛:=\B@E#j'lFͧ-' &ص!'v'KWJ±|NP}8Bh\0eYj"E7nutFd}л5<:E6!(xՀ|m+>N]C#ws$a<σEI-+Uxgu6䪦exz`͆Po麩yyH$Jr4uSUvo7ԪkVqRb3iFc} W'%ިє;r4qk^۶@4SeFQ VRDw R.;YӠV"ʮ'vG'('~HӕSŜV6T0MB)]2̤q|ʩv~uEWf?xNVK30 ٸf*(doMJP<Ț/;lQ\xQX j)IYTM7G?Ie15ͼ_<7+xI?&cZ <J>TRuS-MتMe6y~zW^kId% r✷e!KXK\1ŕQ5#YzTS }$R4 n=UER[VTxAJ+zu\,Jj+x8aK|Hxdbm x}屏1%3ȸ,Nv߼^SX04()ڞ/z<ߖee ѓ ARtF܈,^օ E,}j%MjT/eHN  f뜛Nl'WGj[J*8Xq k;+M,tAt* ]]CYҜȇ6+j7"wBg,oU@=(I2a\ F**PKO<), $0sBUwhUu}Y+?+Qwŀ#@ep~Ts`58-E.mZI.j:Hjvݗ-ئD6$tgU1Y!RonfmHh&a0㣲٭L*m\V?@ ֮5HۆlZ- mNĉIZ6!Sg܂sYNICzIy5EU=;73 $0~Rv.e-ELgAd_d74Z1jn0R[[U)y3(()T*:ou@<GQ֫7)YlFe V~z%B{޴{7aj< 8ͧ^C{f1$X`"MD)xP wOٹY)S!R&jt RvZm 'hAjX)ݧ};jcX+K8(V%PιrwYV;ôYNmz]nʮ62 (@{$f-(i]Hu n{޳ ^SVSOi/R Q T)d.DZ]ݛˇWy"<朴]MnEʉe1 :)qK`&Q_D6[A;jyG6HzxErIg۝lZS;oz}Czl_%cYJ"ud$[ur [RMb0OQ;h͙"NK2%Gy \Ap۳`,q벼]GBשMq԰dA<{mc9tC0>:/dWeTj2>ԺcT?L|{ӒQ^E^vҢ,gN,=- !,5<7ƃ2ӗ>΃ \}No}.ϱ,alQ$9gGsLW 4kTpL#Zڹŭ_%t_ʉ gOm'/ tTŽiۜ Yk&uuy̪1]iڪ(mǚDPr/63ZXd㺦!Cl'jޤ0ܔ% *54U##Afxa|kXͥSuf{kyԒ58azʱs>9YRTd==jmpIRՍa*@@F+QScG`mP:`.yNgo=}9\,%0_).8yjGhO}6;wHN4؝z~m^L͒_Izx5ήc*d{ Na|< Ps̓ _7Jǒ%Yeٟ–DčaOl"t VI<] @<Z*[V6;_%N^妥4~hRsD,y|Cv[?j%[]sُ:էͰ]nd]V$CyКϥ lmx7Xw8<ߓ- 2uYJeBu ?-3vm(`z4MyWEf%L^m[ky.mKyrȷ<QVľMZQ'mA%d8)@ːϓ<:P ٗ.0`.VЬѺm o)/:- Ǯ%7uMW(˧Wg8e3F@XOºK3 ^@6{UWOқ յBY!}VG0Ҷ^j8M2QI2-ErkWGǣ8E&p&'y~ƃzR\]ӵ]qO|cj+Hʺʭ}M.-fY<çFf)MÃ6=eG-?k&fVVG?!3ٸ[I6.kn!.`+a0 t6KQ]@|rxڇ =kŧW}%4dWwv轞W]NQf YCo3{wMPj\R öɚ"INHUҋ)؈SxyxR$琒WN p`k]@tr7iw7KSNʦ#rG1dje, MZ`zS32$$qE}E6Ag̒=4ư,n`x/^XJSV&S:B@WpVl~p)shO:qSAX Ep4IY@BۂmwJԉnNE 8-yvqѧX=x\sj,),:pyPpv|]P$HM]w8V&` SoI'5=Z{7l޷ |xn+M"*MǡїN4!̓{}NU,?HlLEOx0\Zu.m>@Kpx%w/nOmyDPZQuhYr*;`@ [U?=j́[o- OT{OM5% V mIqhvKTqUlƉA֓+jPQ+dŧc]c[:G j RP³XaM3-nj8#j9 r2X-4-=6 HMI7M'1Qn(`ćGTSZXAJ\ΏrwUFԌ{,ڮݳb>qFv% '|ap;jkʊJsHMq)#_cg[NvaDmYEf@sY4'pfdw!ÒyxC_XEy$Ҝ:`ŸX#9|@x1!<דWb\2⁨]=.n0GyuN$)c)n2c؜tᆕ+;Pl剷YP*DvH|ai\(mޖ <CRXʍyg&>lUeO/ӭzm=eB?dmX# kMz'kvXU)= {4?ԽcoCS4de<[-zq=5>A HEy|>Q ԝ K <2U6{TiN5O" W:GE])'u9cˏzi|HUwێ²?j)wujqk Mgs@b NXVn\ ZY|㤊ڬ2}, jw76 hO]dLAyB QVxWV*FBf٢ɾd8%ĞF+b׬*R҆ũj\XMn}]FmI`3)RM5n>-rʈyZdT0/sWUp-4,#뢍c j׬N)yUzj=|ytbpr%4M_S>Pҽ+ #m S]yǛO+G{fU׼͖w&y8Xl_p̔FPu+͎SxT*1h.tJѤ j(lTr[JuR,;VI.X59Z(:N .TwzH})x:I"zYDco]uÖH]ZoDSgI By96,z6y䉑@,Iz}F x mj}TN>wSS ,+amk5Mgd^/\a,kNME|㸮(}؊y~k5tk!xT Xz%H$`ۨC))O/HkF|;٢hD=Gg+ ha~"2΅X&5gHmY23JN+ (STix>Ua1h(^݇8w*V>a);U̮FC`@prIPKA 3K㮍\@r9<].Qk$qx (kQyyx]3q &ۧR]gdpYɓC2e P;xܤ6Y38QLpK8*Sy~7#,7g iV&6ɦSzV?6~҄I \/%9`/V~+04X>y.1M<ԋ~JóŒUcR}G ~bچlwTܷqF*@vGWa%R1P(x9*|R\nǩ)UGyM`~R?=*dnIP.׹%Y(6fϢp lS(*sȨ@&5>N AVǵ ~Z39 A嘒T8a &Tĥl۹HdU~'Jp^P7ׁݖ{4֌Du!mr>R8pJ@:vA*UxtŠ[^c&2J`lҍܲ"R)E)('sORp뾞msI'dG57E٭cOc_D eu ̯kSJ&H+iKs28quӥ8T@F dE;iw̄*]|@۔yI[&v*QC"&e[&2kzg*:'>l"r2XMsUm}v=u|K:bN-%-@t.|e$4~ȑBI)yS啝\ͷ~>곻}9Q@+*[men.ںӔH7rL`od(.n6ePNv]NUt<EjVN-xVX|}TFtPN.'gsTKz2I J+C褹gufQO?./mwM T:ڭdVκ6b):kh>=wZ}4y@E2d_)vLI5wO"G쒵sj| hjK@-yP;7)/e<_ugHYx@O4>-2؏t(ϯ9W537_K,ĚG1,8#Oxn[=|򆏚l-Eql%WfQχK5/G-\9:xҁ*AH`/ey_Fx)9}7L27NR]yG Fި]`k^`cj3ʩT'ؙE;˔ت%n&O}2LɖZ8F`T;e6}qX`wfG n}]G3&RY9 *(bu}2H,E(1/GJ g'^& Dѐ^4^-;PR4NCKO=ee!]HuA_f#%ߚ^Qdᧄ,ݜ Og/]f_Iw)>ۮ_T\LaPWM3$Vh[^z` 8u\Dؔ{]**BPp& HFM#@kG"R[(}j-TTN>OkdN]wƾ(/@̴&@J%#VFb [_- Eo(W$)1 /xHWzpU|Ƥ/ub6v:*)%ws^'”$jtb)H}5M#yBguVK=iMwR/symyFA&?LPШPM:qނ)¢r.b5d\xmߌ''$%^>MF( &Aqu7 !yXm&'bkdf[~S9q^GNJ8j+>ڪBc&,7">:ɗ6qnZaA.{_/MNǤ*E8D1裡v<6MeXQS|aN*e##Y++,تٚ5:%Ʒp~Qn4 CW^,ħGyiic+Q@* q &eF:}E^[]~j/D-C<_khGEȿ*%5L2.(<~Y˨v[d1<ԤLt(WT[,Z%v>OM&ٟzWhWe]{7R u:LUN}95@*%?44̟M6Jn<@4d#޵YsWtqK[7 | XEQZgl@xkCu_j IP3 pɰOʕ};ߛ \w%;m wڬMՁV &KU[@zCyvy/;1Jd f+J*?ǫSD9rx! ]*5yVm;{Yǟ'v"9L|qSrp,Ny%&R*{U-Z4覨s҃FqiJ(Y:Zr.<x2<24b=՘IqVgZǁ(|$@*sf[g_傓^2CQP(|t;n-" =mS˨`geL<|_ۯ.QQ( ׮ XEn}\DOf6_tI-.O' " 6^Gz R4Ϭ'-$"eXj\!J~ڧ$@ 1ouVv6r!sMUt|!;dϨ% iAG*Jyb &bxVQa ӞV̊Ȟ0ͣYs&/bУ pT.*z%td$(n1x0ќlʾ|)VN^+Y=B$,')CӂhX깬1%7-*u%|eM!qؾPMUJi)W Eh\w=vNcakp"lx^K-ᑝ2vꚡSE"!;zU)*fü4yƾuaNjȱ! /1t) u= 6Knn*=3*H><%$\ \ZgLnSvoMqyJưoA,pʵ(s'}B턅 ;KZj:S 4CsoA/Z^PqIBCQOa"}v2mlZkhBW鍬8w*:k5Me禷Uqit\IXTpʼn /%dIwV;@9ʮmO_~BDJiY܄KZ. *'䓘6qp猿.kgF;kә%NqIb MrҫVX\X#֗O ;d󈎶?ҥ& 95yʖwl(<$D6&yJbH^PX\b M |#q|E'wQ6 :^jK|8[mNRT%&AR!P\IR?.VWtW٦% AOSZOπ~>l[sUlquw)^)OڨD)xVwekj2ί旪aGMm1]JMayT?q֜Cd"O4Ϫ!B&-l@ydnr#> AP'>9"'e~->zSSquy cIߵAWjӃZH^坂 ~ZkpX_%s7+.yv_=dJS@F=JQY7kuYR)AO{bdT dfġ͝Ch@wòr>3joxkMKԺ&=ꗰ mj)$qLjE{80MV Tր!trC?;e\XZdu*1)~x8NϦs䩑|Kf uajSE,IkUF=5&ݒI5Plv0n<%s=O{xM[y髨I/q5BŗeG֨]{%_ת@piFx6%yƤFէ2lqNOR֘E%?4a/mPE2Gu8G! z*G"׳ R߷]c);!REK=79wJ'U >nT9W;׮r:ϛKRדGj>T3$p@Dx7!ރ6sFإ}N3ڞvO~R72z?H7\= Xyhu^[z2cC%bH%K lO9ZKR4jEМ$ܸ+ȉlR[J)"AGnNҧ6.qJTRe +a*!Zq-`erbk"ޮX.M9*IuZ7PT(/)$=لH{Zڢ׬iʳg\; LpAه+Ё܍RG$HfjPOO PǗfǒCTP"!tR'n%Wd*J4QVFw"; H{3󐏸w#55TFqM`@")JqF]GT_`79r%l>~?ng6f~'~݇|oo7w|On v??;neN]?}zoʻ˧__/!_}Owڷ߾[w˧z/m}+ݾ~|W>O?r]ͺ7/ݾ{/\ W>;?g~݇o?_?}y>Ï^?}w}//ˋɭK\ÿ|?_|wG E>>|޽+/7}[W˷?Jw7o}>|߼>?V}?[7/~o~opAỗ߽ob~W~Ͽ7ǟ}ퟮ_.w˛o{-.k_ʿ{?=~EoB~o|}n?qq~?6|35W~;\?'Λr|x^~~/%Xpvr_/B~¯V"_%~/._뗋+_ri_,~bWU|32ym?u/? ^=}wu=b붻߼~M|&M | |͗\47 4po& |EI'z 0u}|%WÛ/ o>}K7_rU?7_rUMKo/0?|w?ݷ~sm>|͛aVF.Ƙx_5oJXN'z (,ZϟH ?{R/_o*saǺEaIG 3j[^"0^8u|׫;2ˡ[>8Ks/YQ$%=ge&*\QJuuR7,ga;Y:aߗJUW=ZԄ/j.W%;}cOIO_Wxic NM,'y~ofu!Kd_d%ʡke Oiʈ!~V%gpQ9FL^aЊk~"8q澧ϚԷ(G.r*B.Fzgw:>Q\@lkv!4*U 9;6L]yvrwt6y0-@Rua<ٓCISGOlJ{~ 8U$5h2wVK jq$-f:X&jWYoeC Qh8 G-eq=g~r0#,%'b.{q =9|U!t%]B?TmUrX;̕禎s%yyrnunOye5kpH~v}\|gBT8s 6=IoIWR|(;4} hӻV WcrsKh~I_OYERַ*"d-v& {_<:==Qg'DTȩYGG?E6Ub{gz%/.=/ixtlxZ^Q }r?ɡr< e+q>j&:>3I]v=`w3pkD蚛L]2c 1ctR2ɬ/:~ k6%S2ORSeTc(9JVQABx؛ ]{icQn,R P]cW[IȑH+t Oj$yMG}:<$Hݳۦzu\7d'/9>p 6ܦ9u:% iXөP\W̚AIy4nY73IJ P~SmJP)xK=(|%vO<Zּqs:[*M@tPє.Y[缗7vz, 3W]xZP{-# :Ⱦ7$Sy't $-TrlewqC2J$@wfSGГ? pύu*K58q8oHW,pYi6"ػ^%=1l)?\=WwlAv/l Wᑣ|L*!]Chsc: n2!ЁCY3mSG`4\< ZH@{ĉF1b_Ң`GpLsp^KׁkW9̤Ka3,ID9ݹe=qb$(]ʱHx9(rgY"_l r4[CtI1?KrIFjNz}E!hZ 8*n6[X9t8(ήjVo=Jg%rƭ.t6r3q)GNF%BYI<l3 $ʩ!eb=R4t/v/A%z2\OK( c1ˈ'4xَQ'=u0eF< ?i(*CIS]uj,nS{S澤vK{U'~J8\squ2KQG6!] rfn!jYaS8TLdGլ Y>hsF,oݫ6|-tٗC",fVOQ9(Yv-eAx@=r֠ʥ'%FF9@~zvM]vc[C*h$S-OJ9Joi*e.Զs?PjB0gIO'*>Ji=A֞9PsX|Ne弳K$_rnp`@GR܋ŧNoݕ )'}RE@@،HӌUq@]"JJOB#KO Eo4"Jy hP2.y FɇI_UŔ2t2<cDwmYRP`oaSU4j47{T`t }ҭ{fXqB  N{Togo^ *뾘4 6ilR3<Ҭ %***:"%-o䦗pUhPá|\ $b]x*LM+"1ݱ &\a%3˖|ek)i1NeleR]I$@(wH"ۇJzV!q:p+sjϪ0וpmpS;)`"$Q'7{D|vWf˳5& ;*iN[߻H~ZOmʊsr=']{P PDTQ0mYB1YRd;{ƍ;49\r:*[ j;*7S؏OpO] jgԭ C`Ң<`s\5,Ai&VϊcͳPI{sWd&w~IZ`أܖ\VrN^'rIJDˋ=Mn!(5$xWAڲM;,agI3F5E' S-!d*IId=b XFzSQQ's ͒5I䙭ٜ},N]Vo/*_Jfވwsls@$JcXcRf{xowF،9\̱ƚ6svyDn?՜juSX^҉%AV!*gȯihR'Qf:9ѽWS(Zْ:S.3ʝ,Ty~ekEe%ݨGݑ3!ھ9p"[CN:|n\>Y5mIچ^6I&TٹfKak9I'jwe|v+xΈw)yUk$c%gK% S-?^Bwpr+6@oOu(/R#-Ή' ZR)m֠7{8*NEOX=X4> 8ř@E%F 6WێL &u܆fauq lrPVa_QZ[E-A5oM2O%&/_2i,4  924 >tPWNU_?/2vNvOeTDJ2_%JfXehe"яUJUeʦlJϩd{CQN MZ41;C}9>ycbs{hr Z/!܊J[k,I\ţU6f7k(SQ ѾB\a+yԫc=KϒX`JfW!PL{h ;xCITO9o(fZT M S uP+pȢy+`;2yH:tSmbS#Fo688={'jޝDZJUa()4rKC\ MbN[B1g):1>}U^ۀ(g*/Mؕw&96Uv2Yګ+r|-5Ъf7eUS͆'eylY=>vvBE;KQ tϾStK-V:|/MĖ^$Gϒ~j|( /w3=ɥP@QsL:/2CTQXrԒ8nf;\!?3\>O3Cuכ}_.8.6b~`m{4+A2l7W>v,(~L $Qs@=-&Q+%eaˆ)vbge#Ք:{p N>q^#rQ. hTBhh?q#:qks`u'o ~IƇֱͶɷڅː@im*p:AQ}? ("ID?EAɡÆBJ$(}(\y66.M\A׀5TP2T!AnH=u)*æETu̴G0][%UNvj܏$%/\`y*X Hwנ'=)7sR  *ja%zͦ*KՊ>ˮ?G] ֻx6X$s)vq H @$Rߨ7[T85 x2꾫 wL|[(|,B*^V&IbkѬ3;eNw>bChR= JU}Fz.vSP!amnl(W3)繞])-,Vޔ2$% ؖNVu] PNU'HKL-U)c{U4(/@!|S(4ڷC-ĺQ({(P&ɝ,!ZѲ٢yZDqkFݞB.δ: k8]6 %q8p$%7pk\mΩ{$R: !έ:&#Gm+=Pr',Z GZreR)4P8qO}˚*$.iϷ9TOI- pIo5zQ]!Cjѣ$][59UW֍EF *JD;*$b𓜺m:GC>Wq1@2%%ᐒ@Gix-'QX`!ž Dix]I 3vmcxfvЁB, `\C֩y.j*)o^V.QlׁV $6J&6n$QEQJPw4]-a%x9.a:u-riLJWOӛW rCfݏzf"~0A(-HRcRC{^)t Ex4{JXi|>V;9k$_®hQvBVʓ,k'rmkE߲=6m:*dj8FIoȒX KPjS\tQ\ d`r[ :>:QR=@ (t$FS?"{Tה.JEw2ĒU6}SSK IN\a%DiI!%eeDIR qVjiLQ} bmOHm%AeAH.71X/yԺ(Gehט2g] yIRԒU | 2)h9&NZd x]:T[Uש%F\<3:us#zkLnznb@6y,elKTMnk>L XrƞRz힇/y'ڪ )qIuۍ>Ϣፒpf(t]l}y k"`R^C$)jE⯓td՟AuӰ)@߉$&rبf3n]U]-u\=g@m1j3Y|f_^PUp'L#e{;3۝1&@ O t}Z{(m}=J\'dWF2i'7Tl*/{j5Ndj✶g?"V->QkttLU "{7Hd5в=WKkB" Tq,UFd4|T]a䭏C]&l\C@G±h ovw Vo2@.:{dKh~.[QiTzJ>qUgI@΢鸫X"%OEO" K-7v׏_qU %!"[va=\e{qp-<$*$g8;e,{&C#6hضhLu&- %\vO[L`&5ocϤx2 9K֛ږ^lAH,w#h 3ߏv|GgLЂvJ#V ָC=4="P+d猩DB[Q'uJf~i4u#['Lwe~8r;PhfG8KC6" 5f|Գlr<ah.e*&Tǖ!w[ K@qde:F)?@LE򶚰27oR4b#Ogr?jE8IT 9g' IfQ1MHrPzXvr> 5,J*{ [c lv 64và.J=AqӉs]|x4S Vpy0#0Z"'뿩]rsP Ir,ԇVKbAT^Ζ.vָ b`뛭 wQ-qVk(o-|`BmW= dzoȢ {ӹ+R{ 0&k"@Nmҋ{ u%2#mC򇺆}pDh7بݞS/IiU֘knHr}uv_BnВK~@,=g9A$Ei} 5f%BZHx[mVY*Af "&B_vv/_8K:^w= KwPR҈uFd=UMp(mH0sh99Iq)u.3]mv͓}U?LGި/t0U5F!]R)Gb'#RXReV11B,"85!`*'{kgF=tTwNd>D}[ɵ5-K U"p;:#CqjK^M$T!XĐnpLUz]}G5"e-A%*#: QT]e랓hXMz܉dqmDdch3D@PPX݄7QzWJϡH[j3)visϬϣۻ2=Ҵ6#WDemBy}-˺b?N.<+2=5USCח{\ՔMO,a"t.i9ROyMj :HhN|rWxNsGX_v`KMUL=d?r8-剉W=#صhp̥ǧ2``rw<'6u0)7ggdxaPAӣceU2`dt?ܖvxnfKvWא9:qAZg0*]gXP#yA١N 2!LQaP K8K^\mZeARP)eg0A9۵z H.p}!\N)B];KBr :}Ƕ *Vyۥ4{8t+7;&?&VKSQHA6@ ):f_z{R@""ANV5XZ` QBx^D4dΐJxldnT (nH-;iLjawmp)nE]g;~_mI)R%]?GsYQbZ"FIb'̠-xL'P3eڦ|@ԕsX z>//*Huٸ1]T\'9kRMsnY>nT.7Uu*oXd<<мm358)ȳ**@x&$iO/+aSWsfTjrXVY^ط 6S2u.>>p6;!}c$djPg=8-ogQ0x\caɎVed4&m*I7X=ZB%*HwU@!7.|q/vT*Z֤9 .˗:?oVxӅgDww[oB&Z On`,*)DP%+H|>ηLvw&K.՜' ,^v(?u|:xcG0U*(FnXRDcFjا'᰹t?U&^g)8j[/A`7me@%2L5UK*/gY:_Od^xp):ʤAo 5(Q$ /Y܊ivk!^$Q51AוdsPze[c0rQ[SnY%ϯϋ4H^m\AC=U)`,p@]f@jȣ!ZLIX<, M<7NKQ+SF*|(KFUc!BƛDqMD҈R scE'^lLEJD*.FʪR$%J2W ھL0#F2Ic=C@n_rܧ$o6: {Q5s8m@DEbE9D5|Qݿ*GVmZ @dŕSU1s1 5PyXnY]0`R8Rdε]@ޙD?ݺ=P>!3T{ 6>u|ryB}UE~rV GVP0"l<[\֬1xt:|IVAJMٮ@=М`$  Ҭ(Z.,͂H!b"LE"gOj (D?ɧ4,=> eީx !l<~wUyY av ! LȾ/͜<P}"-%j8E9M)K3=.$N.0@݊]S!Y8% %㷙^r5𝺢PjbIU%9=ϛm<`/(PM;p9QGj K.7=I97ywH Zݘ y<<pXۣlq-AyTufQcq;jKʑC\1OBRh7c0wQH[~Nd(Q$($n4apUzD 0+={6e WhvwoGh=dI)Ru[Lp:ْ{u`SʏQs"X DFꡞӦrYݦN@r'oȥnP:n7T׫ڐγR&F*,TuK.UdRu-nubaӭp@vxnC=+_ly `cvtD履}NOԶգܭPɍa4n+]P43>Iה~qB 8a嶪ҍ(AQQP?vIUm ?3!~Wxx+LW8I#g5`!PLNǵ S?DCYhsӈM$ɻaZ9.juoQ A1x.RP^:ʄhkcYEBSZ(r94u= %}y䵣 {JUڋ~% LbPe LulU UMwHH<=xm耕Jn8y|I]k_(̢R- pY -{uY/)IUj/ xŒ@{SB]Uׯ"q/1:cðKnR€q n5Yn %X<Ǎ&v3)GQ=,OS9 H9T!m '8\op5hVG A)|YJvET{>w=GNЍi[e ӓ>4U h#p(00tnQĒbg7 x6J)`^Ӵɻ2uYTUh>X]U4 ofxYNZprKe2,VRSj2ޖnˬDeSݵmМj8Bc Cc^+p yު[Y3,%[ZU/@:*1MO$EI L+LXd.Z:š}UI ,Yj!]|>U#4)qQJ1##JB47=iI}<Т,ս=n>5Y{sKct.؊MXPۛ#{d$<<~8+>Td:~SnR1sVt *]Jbɓ>*H^6I‰MRST4(i(ehݿU"Ki9$֜*ɴ (ģ}#*82<϶l#%⇴z1\?./j.l,,OUiAŊb}Un{S+&]Pm,,_jԀkunG^U$1v]^ŷ {+h[Ê% x§s:.ݵ&$p*LjWլ m_?DVI-GHSCb%jhM3[LT 2t"XP 6cg'ⰄYrKkl\" !,k&0+ zm^bY%vUEa9#ɢ3VkqRZ7<$w%[mwYmI} c'Qx@g.7=O2Q/Qsv'7STd{9uaC5%}o/b5$լ.} Sbq׬޸ZZW-ψ͘nP)\yp}FH %wVh'U"FY^Kp e yʤa> ze޻c#X;/yx$]dyGC wr LPCLK6G凊N7yžd;$yX)/c*v^~P$Sڹir[r{n C=u+c1IŎ<&iaؗ Sm>ێnKQtgj>n'LleBѩ܆Vz$Ϧ& M`ξԱI5-י !O:]$Oѿv/唕q}ȄWRY*m_J? RE*;++tT㤰sދK.725$k~뺕!QXmHKӋ\%2wL~೹t=]HNQ{/h_ޏ{=2i5|DtH7E,o Q$jUtK˅}cim+&sF]'Px$L(wwlR^cs93H=QL d9ܝV @BzDX4zt 25;ݾr;` Jt{8lQ!/(/o=:@VYj2`n] BF'J8|@P->۔I^5dѻ(fqAw% 1L_(<+{d2ͅl7mIg@m3JJ7D頣Sf`͡Qős5pZn(C8T_˵KM2Ui"/6ٮ,Q[y+ޢeO;Mn*Ef'߮;Hj*6{!$ L+MyOisȀotnl#[X!nW׊Ak5It:=^#T}$hF-UIe\صXJ"[TlC74p/Nl:eaOGk{h(VS6A>_6=H25\nH#-U?\#I% A`#b e'.V$L=Vwfܫ9cpf*/3E k2ѦQ5(zh'k|͗ -HtGeHkW.fcf):~zJ7E~ ӳM[D G^ u@2Ԕ¡nq+'b5wa[ޢwxQz[~B"]whI AISϮg'`T[|{ 5k=z~5(':$==CG0ܙXwuj\E,5i#C6:z xw$` n')j}Mc=BMQ{=Q!Lvԉ Y"V09+ZGtU}ʣkcGw$B R'H7?n}v !{jS;^z^<*Pw *﹮m]t\{} {Z2xv&rKo=UZ=K}wĢah_gr9.S4[\DM<-,3D9&,uE?Huƒ6@~5{%. V;5v&n9D5 puI),`wPΥn\f hDmyY.icJ~oR]~[lUjێ^n͢e'ϖO)?:VFo JZ7XVw=m+ tGSw#Hl h8ĩ"PiZ{PcJWP""R鷥A nyl7.Ec~O٧ dK&f+h ԣ,vƇqʬS]t<(vE"~Ћ(LT6iXnyUB!Cu(/_K/… \tqgEP}+õ(2Z`yo?8=66`,^CUoq̠U5_:c՛,((4`:vC]챧VẗDelR;S AQ74 UVI'S;Qw1HP_x+"E&]Uv_a1,BZ6Ѱ~%X:4-3pC0˨I#!R_վK+N5e+cG.K ~: ?<չ¦YR NrS܀ćMWzV\RӮȠ.Iڈr\ywD6W+A Z~\pۙon9ԾTRt 3iCA ! ߼mATj;]ׇg(C!/ `qجM2TdϓۣgĻ_il#9eZ#oB"|t9$PucTYM*))/1]0EW]Df)M_럊 BpZN# aNZAkP!Px{~%i,tg1wAVOy>D5*2%wA3u@p|1<zK̶I%,UH29wKl8&6UJPIŒ6I*5X C YTO,B4/i \4mYwiSCBщm"fQي~q]5K<1η~;.>o.O]p\=c^R<zK Y+FS|>vM4oxe0(*-<<A..O<<8Uq6j'Ttקh<5Q-<_xGMr[5l}Q&% .1VUY?! 3tL0BF]ZdQU[^۷=:2Jw.vܒ̺5*A;wH%j,&7iơS"_nAp˾)g*nC@e$ZlS@MsC_6 $T^X%+!7+̛'1qtUK d1;G*qSR 󩝙Z!R\Wf=Xlnp9qo {K7rF]GtStKPlWQb򔀞|[&k~q jGRYٷC=tx&|jΟC0óR 7AW)J V@Xe~{nx2[DRڄV(iTEi=ό|ۻ.3&%NJFzAsVm-@!AmIג]!F;'^짵n{P E),Wޢ&s@>JO4Jd$oBe%YogHomk(A߱~6w'♪II6RR" I[Nb] {p*I,I*IE kg3xT4h6)o]6Yy]ONv=֕ .jmWI)GcQe˞7_Hʀlf?sySo˺Ll4e@JmO=Id3 b% 5O)2`~P|<7:[|QCC4ys;9Vn'Ɣjm4r m&)6B YF dR*7KC8iTUMcyUR1Pcزn OUbFԻt"rTFEG9NOҒ XrntW\JrS%Ck;x=)<NOm4&dK*Y !8@"(~SM{7 hZ1^ZG)ACכL>+<.;Zͬ/3iռ*rٲb>.iv[ _Y'cuc> [fޫ<|) Je߀u:.XQm7 x#0r0X%{{q+bK֓U5]%+:ٺx V$1Yii#U)6bN[٩aݾףNĦDD]Wڒ!s[iݒgjѱ4IX:HܲT݌`٘RRyebj~,Ebi7ZrG@F㱇V=gRS?Wj%c_MN,@7_"%$3% W۲X? Tît&5;mOAzYf'9~Ay":B+pĨ?,-˩i(XOӞz^* Nb/ScWPzNV\Dv>=*)vhڻSYRbNդn=e1mc?Mr.A>s,OuU P·IؒϤ`Xuv:g#&u5 N+ ˒2iϾܯ4$ hRNM;%PȢagOlj{VC/Om8 ײ|COJWE B$+tZ, yU&)AwM9`G1F%vFiZ rT zdI'A_m*RWt{a(è%u&5:3ٙ;}N=(Jg0#_GYXEbEn3(`Dj@,:He!NޓaIKf<튳wXDZDG%$,!lL. e֍%,9jРK2T@.zL l-] S*M{4vE} %ڳjyuhV%nJ*bӅX3*z-C  !A2wv[=`bgdGB۸UChWCw)O%^i(olZݳZq3(2K_T=N/LhUvi<5.kTuý%fW \)%=td6CڬXzv vZϾ*ϜMT-U?28Cj p ynD錄3F0U5Dv r,4($~ /Ţ.f" _3rQӐhKW`|-'].Jبky#ݦ O^؊Y߽@WqÄRѵqS*p Q'}=?$>-$pXfqc*L %^Vg HEc |cuII(XIĿU7Ѯnk9ah.v:Sd cKTLsnwAfjWݶKS/H]p-t d2gw4RhbY'>(A:Ԯho)j&3LYe b m.ZZː$c.Jww)N%hUYóY+3-K[>K̞݌v&MSԾ%\` b $17̱X=Ui%qe\\FBjژ{8OeG0jgFK*g^Cn,2wIlMV hvk:fqj'hՏϠu4-w{ Pgԉ06W1dNwnͧo>N|]5F:s]IڊeKd+|KkYtutՂZUa4dHKwgTjk.JΈ74=CrrQy/DYa[("&\\ORT%Uii)eN-ȢF34KUiz_W-Qդm[r̆zGtm'pR=hԣ'D@z>k*ccy9ygϷR[{tKbuP\+`{K`E̽d.NC}AGlEq]zW8f"?jnmIi00彮ϴE7E'~Y%96&ACO"Ю%;#̣ +s(yXBNv&dh`U\6dجyօsٟk g.MQ4u2 H}\ WhOvóH+2S#=CQ C>k`s:4 ssVJ5{y4 \j ep$;alBsE$:eKw{ewXŠkׁQIMN򽓻]Nj5{+ p_HIv+ j.>kY)}1CVhcmM)!XF*8u t9@a;N #Ց;kP;( z#QDt$_LmD OAn׶T='Us # T{زtEP K[РLkHVx7O9-DU#ɋ<?p^{*%~[n#)Kx&}FLM`:OЎ8@5:Rq 6޺ﻳbx_B8ydhr&4fζWl:uǦiDAwuH:kgVI܀S؛RP] ͷn 7xƗڳflFMrU0ZU y6;@"ڟĞ2'iMD oT R,/AY.b9O SQ1A#t$IT5F[.㱁Sy9K7zey(53ZϹ RT;6Y̻g $HzV6%kzxh#!Sٶb䥳uv514kYz%|'Idl;v5(Kj3oOZvũ*#KirZcIBqē/w 33&eջ;e65?Zh<{뽒F3>?דϪ5EKq,"U{`Jf[K1cXB_澝#֩Sn%(D4eǪVf8_5:UO|_omƷ_͏]/\oW~G¯v?>|y_ dwObyȑKç×}W7|ȗ~~]w|^/_jBxՇ/xkuo]W?~?Os]ݺ_W/پ| Wu_`^>_|_>__|o~ӿw>|??嫿×{ç_/~k`|ݿ}^׌˧ lϿo~]<ʻ>w^~ϕ~o?c0ۻ|()}߿Ƿ/xVz?'ow_O޼.۷/oe/?|Dz}w{u߾7/}I b> /^l Lۯ?Z+^_q-k`h:~}ŵϯ{}ŵ+^_q-k_^_q-^_q-k$ZW+H^~ɺ1M:MVퟮ'5(~S}ˏ^'YW8^Z~{M.y{ҥ%W&\so&\?yE}%Wz&>yUm+yU}zҵ%WÛ\Տo^rU%W/o(W7/?yU7/dYou0%<+'9~Wo@%41B>y~SI]?~Hu׎l叟H?Ҍ__@/_n۹+ָg /Nj^O)2>ʝ$뎡;}=;ztmל4*xT='3׾]c1׮@kGɲ{5>Whb= '~|ֶWGPޗ[Druj*)˞/d ڞZZf9_Z&ŐT4SIGmݪQ U}6miW+F)c3hN ~W \^m=tm] Rz-3rMc"tyO͍Χ^Mۘ~1W8z ˭v\>$t=gvgԥDBMK O[I}x xDyOV=~r>]Rk=jGjdݩ67h^soڛ?x- q3mɨk_ٻG`4F9m)߂vŚOwYbYSJ1~(9#6l r_x[ #;VexL۔4kTx)[q7;-sd=mkΟ-=Ѷ斐|V)I<"i 琉G5s#--F__.L-]O3p(f>Hy?Z 0Q[?iZ G톾s-ݏ]{yz;tlj3&wPJ}\ɮRBϱ-W3&f<Ğ⁗M Ou{lfF*wBiTfF"GVR\ěFS1yh~f ùU1=}gp I8u% &T3庻 =ra mp.,.IAC vgx0חP$e]|RR~j'l֮S)?gˊ=l'iI!rw%RU=A86PLL #嗔U{Ω|<6jtf89dRKXRr!x{jR vCKڲ>1NYd^EcgJ5=+Di`|b#@VeqI(5M]ãnec*,*el0/RQ=?8;MAֹ[=4MԢ9VpؔCp@c$Mq(t@Ožt&UB~KUBf[9+n:H$t˹b#hjT,NZ֚kzP$ Pb|,NH6emw WD]U3@"]~Q)$ ْKbc`q X"vG⏢0vKr04to$j>TZNSKbRHC Pۉ4-3(m6*#!u]8>{ay[hFbxboIȿk*qپ4cUH箹IBե8\ %7%$ QQ K]5$ZBХMRd$FtELEPi퓍6j:RTI(i )*ۆsNB8'xGj0sRFيYd˶j#Ξ(ldT:T64ah.quKcY HNY=.3LX>x:lThsU_Wdo[?ML埨jדa/"ZI Qi#>F*N)aLl(C{^ )sF|bS *3*>ݘT& MYf/#@6zL3Q8MI4t`.D&%/mV>P?4sjoDU sjt}˭㒮+„}];R&4a#3JYu5D]$ VzdEjSL"j_^vY%b7 a')cWgc}Hd'E&ӹcҾ䪚ݒF 랿RI'D9PC?Rcl h|3;#FxTŲ.J "*\=ؙ#U^@NinѦ2DQ 8)' X#c]f/v5lL =FQ9OJ,t n9 JPtdQ[7M6F3il0&Iۄu” @2܃y1%*PHL˴yԗY"+/;nF]"i/pl[$/!& "kVAKjbl6vXoiZm6 @MKnK5!D j'8꒮BIYܧbCI$U]))":WLͦ:bpȊ ֛eIUG6 fV]n2u)l-9QU;SeSx-C1@lVOÆ4ްkMN,ɉZ, r6/=*C4= p0UH>mM,qJpnҸlݩoⷁ*(JDJ¢$Bn;$]TJX QWrx` )/E,Aڃ] P\h*l2iIS 'f;^i&<qѽ牨FvX嗊s o@trx̶kZ;FgOuÿ#X4$:9`(7rZQIFܐ=\ou;U|J"UztW-{u2hrjKo**n0eIraz0+ D][".vkwnBfn{-]!u9hwޖc Lho+hw>Q2JM>b=pâzՎ$ÚʰD u@:7p G˿lR_)'ôQY4[Zp@ٖ:3cǞ_1WV~FۺhP ;"}Q|-KKJ֪Şe-Hqۢ?+9[fSe=묮xpWY-K2އίݸH4yJ\岩Cβs^jTuYNg"BV*rꙨ>xȃ#{ynBPIE{)WJӝGT=ך:d$R)V' V]CH3uy)F7QRs)u}KCA (9YO(ۦ>{@~ϤcN]V!5V#gjDM4oe8FT {Q|{p>gfCllL9p!gT; 1F|lmi ^ՋF)UՍr޶ 5)'Ch 7Bzg6S E"vXguS%c01X9c@u|:5uU,$XXjSqEtf?J 8+4Gw娉+*N7_Y`Z/QN)w{N$]pGTLh€|,#ÿ4V5MkTWi:DWA|iE6Wi4uUP@@ âh*knc!`?tZjū@7譳/s|RW^l'0aESZ-XgfbL.48>8k'[njC cY`&~%]I.c]cP)<^dU6y(Ovڒ ߪY[婱(=I9KjV9Po9eE.HIc|ϭ}&5n?/H=bZփKaV]Lj 'l񃩕rD?^y;uWUh'+P,4Qpr}܏$ܖ}@eޯkL#>0 (uPԺǙpYaUyx{[}\*= 1nha%g E*V5f,~ꦣ)?@QQ[ R})S>DոO8}Y:smBh$tnnaLI5ڲ^h|4786Sn&u@2I)wv=A՛Lht_0FNL1-1ң b"E#* :CkʅRLw 5),уZhJS3% (E GrR,kE<*&KeuP<*,U04 J|Q"ˣqe2!z⃃%O߇YyWv$4W V;3gSM%rB?L23[ |\zi>uFU1N6!1vȊ%ZK"}TPt?ꥻKʤI{$ɂC4GU%䀴E,B']w|p>+7O<xd#2vS }WUd 4&Qn R🃡n2I` tQMuUWC..?疝U@ |ۗ9I%OܠU9)}FW-~fon}\IjT_c\N8s260R+}iQ,&U%(LC]]P͝dz-%bM͔?֓YΪSt삺aS|)ZvwCJk*'zr`f=# ULSe,-3欝BXڤQLxN⼩f"lj^y85`<Ǫ#c@RV8Q]-[oEEf5Z+ns( yYU|]` Sqݝ")GF*>y@* {GJ"IL"W\=r1O xh t Bֵ/P =s&{ox]`TŞHոeS85t= nݖ`;IT?Z2ԿuQ#<3$*4,I_zvf:iƣӒ[8"0>Uo۱XYHKf5E&M8רGGCDy4*Ĺ1vkbY)CTWPC0+2Dʮ?v D6f+0nojj7lijgp)R(෮!Qܫ!&YW=4Fأw?Td^6S=˰ o*2sKz.+BpU=Jn\<y=<fjwjl/>)RV3OTU8m)ZӺ@m1E;@kR,z}r$hZDܗhWX5{6##;S+>-w\5~:gϪBͧCY*Mb#urWͧW#C@E(gHn52:sx0dtբX/̲@R|lPl0AX&ש4$)\S*(EoSzyD&۩e7NnhzPpqJEL ;!_g'H/O)7na7V$VE't,yX{|ulv( ,-D7o }I3 ve (wI8ad[d+7Md?K|ϒnNrd%Ww۝ E5A]3rM"G{2(v0!>׸mʒVǨSԃlj˭K @dW Y+86O.5FrѲʨIZ>vy?'ՓJl#g=dLBXO5*QS& ro\+1=7zɭej6gAND*SE)M7jܠMaoPT]9쬶iFU:9m8Qܘ"sqDƭDq_@Ì p_cٕU,"#fNK/J[&[Q,P$)SC+e$o[ i)}籏˘]AהJy44v~*I40@eڹr.K:0[TȀ Gɔ3˔~H]quSE7T6CݚSJMOK]ϫn^;|nUb)F-qn@B$>nM e/Ҋɞb} K'_Qm Z{NF%/{w6$Z۞m'k֬>Kt$ vkVQj$_j]j|bjELL:u8l_X|ɭ06ROr|\.r舞Ȏ,[]Oz-Ud|87J6f)ؽg`|;1lʴlFD|>\8JqJ;$*vv׵.ؗX˻6fy]:͟2Ni8qXV6^I@Tw_Sv %,cMYP}d/z+n8"kM`hUˀn=7S&kQw}o7(9+ @ ͝dC[>"ZrBD\F*ubem]moJ9xUAKp,X$nfFM$9E0fM).Rͧt,8WS?;w$΂kTV#),pR)kfSG)C5ep`KUyQRviܧ< 7F0K1^ ]< ފgܪV϶ 7=wN آ]ZC52eN 6гGZ㶄b݅ql{S~Aݴč" k&+eYj%SS[lum%_|WAkAr|8 :+VU2HL n#gKZ*;4mkna)΢(iEPXZ4Ma$U/ .؆hn,P`> h}#qiz.J泝`*Ჶy2iBfj1qܭ¶{Agt09Pgٸt}UBz9Y`1 A٣&ܔvbYtuǚ[8\}:+ըճFp/j3=wסj# xr `1Cz,G358U`XMjqPE LBMOms!hR9᡽ `<4LʴJ;tQ#p_|V= &-@Hn+U=/n#S1\5-JN+*ܗk_l>r־Ř,?jQ,._g8Q"KS\ÈDqe}Ȇ۸Qԩ`^ϖx9zifJ+\F}zaUu20e+B]ѱ+ά߭_ƪRtbq:$ dBϩ |.:K`}nO` w'J7Bٴ_žql;ݖk]?%CG;!$l]$l d-ꎁެ6{30YJmRwva J#WSb흱k!H4]Q| vQԾ{z蜗`=4xݚI}BPO23'̋ȳ_J@I=[;261=t| A Q>C}'}xL'so2kd9,;k!5JOj&;5Rp|/nd)ůnL4L16fzۢMHnic6y^" w㴫]? k/>i.փ`s4)[NVchIS2F<y5$;zQ{cuoxXyW4Kѧf))[tƜOl!AZV>wn7[ʹɃa}Ur r|q8R%]c&dL U]A'-è~oM8ma8x펋pPmGsTVґݖٽnhZMbHZhtnM+d=gyuهՍѳ{(xtlk]K cr 7=H\ϚO҉Z_ )v\ ,oTrFv;w^CJ*"g]4Nl6Ai`AjʇRw"rt^v ٵT,NNvt)Mʧrƅ,g x=|3NF>08= @˓fB`1?VH?v07^Z`` 1HgQvSgvFR__e%zm7I)]^A>4oe5HEQ7m9!ē׾$[v %ϊ\Wwy楶ڇf\aL] ')y}aO >Ԅ@w'@0a^rg{69Yxy/)Z=r\֚YTjçD 3rbt BTM}>A [!ힰN'hLmK~XTQޘNP7*sJ~<J1MAjHYdZ¯TcN^vl@8~=}ۥ;nO 5m6OU"q0񴝐jrv?غvoZ Jy=LFJѵ- Sezt MMd&Z~+}Ȓ Rr<[C`o,cHMT`$ǀc @xHK[Z)?V*^˾$(nLʴVJ[$ [Xn|:w^gVRyrwۥ{T4:u6iPV)yVL`X[BA +0rM%n]Ҵx#sM:1vz{C|c)#k@&|agb#nr *9ľ&?{YsӢDݫfj ’`Тq+J6 [cמ #AD1 <^"asC)@pL@e[J:O9UOO R tWd Geh(xEMd&:ԅJ;N=";Ab{Wy$k f@PR1cS?oG7 |m/."rU~޶;^у ulPC&c WN8t;tj-*Bl NK P v RHlQf G ef/2ǪH*ARTIϳ7CI۰6Ttěr=7VL$|a 몿y,;U Qcȑ˺mMVe%6U$4OEwTGbLK~(5+b8?F0ḟ{# t &NYɃjxnT/+&V"XyxCesEI-q{RsTlEš6tɧB=\H0Ժkv[zeUa{Ph^ k5Wxʠv/x;a xVL4eLpZRv7,j_Z1q%sg$mzԋVMQ@MvҦeڗ ^"R*OJ0~f6U:SaP 7H\6KXdIp'HNQ1iUyZ\sap"m1Jy=Q |f7uw}XK6plA]bψ=%8aj rNU7|FQA,Xmյ˗chɮ Xţgs/-}WѷLWՔND- 7F7mu掰%Iyh݆>m\B}#XP_*ޞm;E:v3d+kgɺ:Tk[la[yl:%V-ũe $ق!TnӶ1-uYŀvuMg!s51R49jwy~59 ˺9p)cڱ>EcT¬, J9Ae]^^rJ0jD.nS`T ң2IwQVﲷDx ->m K / "/KzzT( M]:E72^x>u qwڧj$QۈƏ2oiSQ)dw%rְAq&u$ec<@uZ8ջmVzuN;V^*3/F!&^l׹~|.0׋auT͍xQV,> : +%؏T-~R}ؼR6GCvKQ ,GƪjEkPl<*E XKb=_8asZe,e,!{ ȩx*M\9:G+qb뵚'w?LJi_^US Ѧ[>G ["Hh@ѓJ|]Sg,5 -pRqgj?Z*$*V9sG8{.%y]B 7M=F*bjGNUAֻ,V`$TbRXr@_`rn% V׊Dp.U  ܭԡke@WdWLO,<׆~[L1)d#H@$,ۘE,#ٴ&w v]"UsRkrgrg A%*LJ5lE3ڨi\dTDQX#qJdT*|ILA-8 X'fw[! 4,qeiܷyKv3Q=(QA376%YY@=s9)K K'Ed==䌍p2,fR"Ne&^'bRI8WFbeO6ʧvkGǜ(Ѓp5ѳfmz$I.Jk'UzT=&xq%|nCAZb [1 i0;YoaչjUh1TOB_؋g3#p~Pꏖ=%20*eXC!55Hp֗2kA "XFw7)~(\0O\@`e#۴i?gǏs)Y3>u7$l )hD}L\䐲DZ{;0(63c#K2RA \r-,_$5҆/f砘w.yTMVMFfTYLgVfhX+'@ M[+ʸ箔'!߈-G"&5UYyY$֦RR|cFp"2at62?]deT-O߾tG/o*aKrn:3u;<\qU{-f ]]5i.F"%KPh*_J%^"n-d]vkREN0_M[5"/(@_%>_8`X_QfB.@&F%=L9y8═&<?&4U]5`Fa0$ynףAϹ4)YEyغtI{ !hb!@C4 1JDOaWJy./fd#5  RE.90\paGNuuD(] +}QwUO6<%[){*aqIa7 N(8޺V׷`2;MS9 ;AWpPe=1#Z]im<ӵՌ[.f[cUPz_dʶ&#dUA:<'`gpx<ݷ[l tmV eqݎ?u2QOے/ٌqNbsrK?/d=u =XAcҀs.RzQ0e߸T,5tQUvEC0ҩ :RQru)n;J73RGCOZ_Usl]؇nii%1ije̗1bO1O0N}rQT*i0.<Χ9ā%kyꀺ˦jRpb^Or1@Ou݁^ ilTП.kv>b^Q9ulڂ2Ys3Ix j[rf4K\`.#ٯ!YbI +ϦND4c',4$ enSG)^KU*ni OU9jJQ>>^vΫ0g?BdvrB&`I҉tAUCpU?]m-EuHTPM5-mtmjx,'k"?;<3Y,C!]I5%&.ч't\YKUl=qS*+r+ C }OcylUr^udݐ[k|ʖ67+nvاFӶnDDy6gCiG3aPCݺ kc9#D-5*,+ f.U׭j}& >/RGn*aF?|+GΓ:vFTͼv'nM pncٗzt VC0gˣPb5>6Rs=X0,`8D|M mK 7ԍ|E|"7EIKtr&9j<)+V`CX\XYǜiA0ܳz*ϚaEOHi^=nSbڨq1+I탸t.c X4>4kkBPtJM"ٯuB(ԁ]]OKﲘ^L( ͑y1[Us0QS5PMՔ3nSe=g*U zR]fqe),u@GN}vYc#z˅LN7UCu-9RH~g:jh[ʁlItȷG'_SƇ lvpཷ"ׄپO">rX`j5']]`c/*w5fK4Im] .I8_M7u7]*% NWծIOXA]CF/mydSI[Kԥŵ wG`֞C&.)14a9݅a")`FR5iups3bg7\6{+şQsBS{M]# EtR~`HU`M[ZcZ}]NP#k鈈?Ju[\vxcb9_(V(6ZKZQxv*J-T]EOaM=]2P[qێ% у cDֺi?KL FxsM9h^6Ui6SX̤ՌlBX.:`Kz{.8SF -M׮ۊ׾YAXƤbyN}|2tRulfrYS}=ICeMEk[I̵ra-WZJJb';Hf]X yie޽\~3=IC<5u%"!'D鵄"IBuH]e$K)t71dxr zHlblf{\GgYEULlzKײsr+RR QdGsWډ}J 韬sIM>~^82RtUHz]*@]6n:6<7q*jx8Mi33($T9ԔdU*jw}'cdwmuzR#=ֺZ)c4g 6rpn6XS 梪]m{sekWr$%,sI>oٲ(RUv@c'yP[,ɢN8ۺRz4R0^ ɬYL y.OZ9,1+"f >uf5+9<IہnAJV#p=iK'*(bw]Oul\:YAl0u>q[l#.-}@0iK﷒bHٶ`M T`>GgkZU.XhRcJ4 SZ K]5f>fjjjU bW{{;c*P$κSx6. \[^TEHcԊ鸺{:<1M="#F7hHS~϶w(ʢٖ /C!#&N^4N57? 5)Z:dIQUrB(#vzAmRfcx0䉣xÂM KхD mXa4(.3qUwlWIwPdzpmٜ2O퀮Gt쌲ߡ% MCSHO+eVm둔Ӡ@̵UWymi!ь>et^L*^b p եE W#/{ɃU%1-%1R 1(fh& TPIv{!&3%:zm;A F,&)3 _5ԴY)˶TQi6%!䉰/7F dV;@s F$Y.ʤ zrL95v2ID5GyALKZW@{NFy — lɭ)"GFe9KeˍsUM]:Se,9#(Q "h }bGΕzDڰ:k͟ܮbjZY r]ځnI:e͇| R M{0;m#42Uhn͡T6=M"F'qK6ҕЎe_BٖnUBѫX'JUn*:.4f?0)0Ӽ?ಾmXdInW}ʥIquyQ<:Tdʭdo{r1G7x=!ǰa܂&P9w,).EpYd¦]og}4wUs^o&h4{/*mPB؇o͙֮J$n *izxt.mŎۍdBϳМjڟӶ ଗ X`9Q5dwY j>uf]nFшpJIijh^<#}FAjc: qxEb Q4n*6nRMSy#|Nծӄr*Dc P.zg[U '씤qx8jxw% 1_u8=Sps"k`l}݉IU!sF6sbXҧ F(LX;8{(2j]ZjR''LXR &ڞM_$AEwێҙYlwپ-`<4+GA3fDGuMn'DB5DyJtAUE{sXkYC)v i=o[k[:pvf-$c:.,=yƐ]qIQ%bx9t'ؐWX7Bc7%)p2ݯXbR.(p׺eɲ=Ek퉗uRvvu5SWShɔ،8ZPo箓t?:X뗞JUvTڝFiX\l#aXIu,Em@TGVRCPsn<կm%M nf6\n>p?kު[  ww,ͮFT\,S@zlSEʧxU:KKXϏLWq.hMLɇI r\2^zoF},9M;"Bܣ䶖NX"%n-ꦉGT CTym\~!Zܵ-3LH͍9WeRXh.ivmsvòߞBn'{IDewnuȟ5e$@aknAyԱѩ$]uӸ6gS\Rw*&BYextnHBt2Y*gU-m)1֒6JeԠ1eȓgۈcYd<%V_y\d*0QM4ztBbd|J=/y{lvӝ.[ HU8pcC8ot*e6ce50\b@GC~ʸeJj<]lb E>Qp(Up]7~Om۟W(*ۿ__ѻ+~g?|xZ }yEwoûw{߼|o~ /?_{׿'߿_>Wڶ}+ݾ||W?Տ\׻uw\Wz_^Ǘ'>~?͇w?_}ӷ??~e_\>/_ݻ߼˷_Bu_wo?|n:fp>}}վ~?-S(sWǻ}߿{=ůo~ %7}ow_y]}o_w_w_wf~߿} o^~*߼yp17~Wyq-̿7oq_^O.ן^~\7q|ίp_2s o_>}ۯ~oV޿M||ݛ>޼v߾åw}bt޼7?b|şO)2᎟LV9ΟNibN9~:f VrzbvO.rV ?Z1bf/U<䴊'*֟LxbN)̨~1R)qĴ 9Oo߾vZc=~z}ӗ/߾k7=n2O/~7?_6:|G|Oorg}fǷ$s?w{yRf#o_/??~o8?:bÛupߓ zd/^~2퇷rzoWo>ݲ4㿼y~?]g&jz3W\K__q+uj++.x}5+.|}ŵOkW\_Z5L__q-+^_q-kW\?ZW\|}ŵW\p X~Z|]?A?27}ӗ?~_^˟,r~677Wėo҄Kg.7/7i|J$Н+|7i`K.M:ٹא^o㛗\wo^޼>y:~K7/~7\޼˛Fo 0?| ?~~?6S0M/1 `<?\D|)VI叟 ?[׿@/]]:Tx ϡaJ?Roz:Z'Yʽg])Zݐ:o99d>a{=2H]9ƼvOdqI]Js}W`L(m<*Lj}'٬T%OeˑS-7|);Yw-n8 r@6^"}yIkq?fPDY iʓ]JSY6RsU8zm*6I镞]a)8MS%XS>U:^܀۾Ij%dz9ц:Qzt4w3ӹmv%Z4;k_~`YWvRSSXt:{{=1*]uyq=l.svwZw>di)[=Gs SԤ{ԡHkރZi9MwڷWI0{ɝP/icR9`N&f][[^i(Bt>o0ebIǒT=u:i{c[ѽ8֊cF+VZrIrl3Ry[xbM3z۬c8ﲕ><njzMarb>wS(K y{myʩW˼<Ο(J΂ъKDOcIt!GEMOQ53[y "$wֱRhfg~r(G\y<'eR/n鰧6]`urlܼ|ܽ|rg$Ip_},9iα,'YnASV{U^{5r-tIg:3A"fk$F^ÌYL+Qt܎| Ɇy!#+UߔٵTw7=eyا!thBh1]9 &\>ɥ(̓1ڃJ,tہ=Gmbg|byS4jݵnWMk "wkj#,bGvhhp[}D:nN}2X.#uObOuHGjs@(K'۽ϼߙ*9ה=3GB`h$զ; p@anǦ^,*,kv%)<@o6*ssbh.ȵ&sO]TXEcCB~eSl:=ߊ&Nf:0Vm%EDC!OwtE[L[˛BuUd rꧣ{8~,_.U>clAGb[aGe# nk@a% 4|3a/  *|G{ThvtLm2h|NS32B{#^gJLk?HO D]gvFG5Pew>o-D\# Qfxu2X7=M^ut\Y%C%s"h~ Wq+&-`;9Q Sސr{{kuM(0;5'3TԤfD~6ϑY˄0醰Dnߎ奰mq{Gʠ`C݅z$DBTIoo gN&Q%nbpCE$W|d.AE̕Y&wy'.XmEU nC|6&-4T%[|Ȳ6!d{]Ȫ{nA_L;h)§JagU;/{faUԬV0l3IæBYTmP\ب _+.NA[wv}dn$2R=JDiԴX\K/T KXQXGWri 9Mi  ϵOu뎃J"9]"Ai"6o~T;4jRsb\z#y@ ;˜HwS B foƺ)xvN |R&VoJ-MT(XX^z'@!NKzs{Ȥ8|e@ASܴ2a:)Pr8yG<+Hڮxeѹ1UgW:HizG'kDAYŸ)80tg ~叮 x0z%w/j+[Bi(>`\Jw5)@vX$Bs #)iutbn lH+I$>T{A~ %r#:FW2ߤ!4 _)BS?Y!U?=Qf jCW_{(>!LKv2;,҃| ,MRK,֧bӆK0&J^;*0ZI\ǴN҄rL(#Xqh.߉ΝU,q+nEay+ [}8&r fԉ_YHn?*Fbu{.)GW160$&%>yp٦JI$tM%ĴfzWTbJP`g Irki(*mtgjOY;+]Z$w)ur+ 3*a*d2šS>N~hmP)MWV=pQ!V;Ȯt/]&/EWǜ KkwU5jPQJYK*- E%E䩪3.~Qq{(;56LauΐB-6)U ?Ha6m8 ۝{cu;A[wR{̣]{Ol4PI|Y(6nL[\/GO-HQk1pOSf_ԔMSE[MaSX4\;^*+K/BFWLEz=Sd Fl tO%)P<cCz.V޶uI?/)I<͂vT(YZO9nf.4?}ps><veh̽AdgGeŨ XJͼ $RRȶ(oz}(~AO"Qtv.6uUTPѧZFJ#2TJ@]:i%JXUv'޲u`aX`KL[nJ]GiU:bʺ]` bB<)TueQ4Jxv ɎtJ}{xْ⾒]Y4Bg)5- Owc#SEI}oa3s p-c(t!3*wm8 R%Z-H^av *sNmlWdFC'`l7xm½WWND`f5Ұzj,pR3/LN[]MKu U 3nTܺ@T[%e1ezO/wU|cxvn寍X)En{to؝ub,خ6 kr9--_aJch垴WO(jpCyx25P̀rEjwwY'aƚPv@Q@$ɏJbQEFm+3 au6MuވU&\]nkxRrHdU?7&2Wˢ6JA<(fEuyYhjB MW-<$3~_F^.jb=zu,y!%暦(1sN+iƏj_?Oݹ`Djb&0rkhoHx48$G i~ԶT/{*zC)e֩}mHJ>j ]NWԿ(Q:ݴpin=lkhic".yQV[R+ ==?&/[-IYN"+VCip蹫ZkwUǭ)nl@ՂI+jZŞ8:(ITed&wf"YnK^ڐGA <r=h#&Vme*1&hڜ.<;gX]'7ߊ\*oؤZv* [}x@ݵQj>TčB?vSWz \3HlLmWVJIc5 ˝5dԺYC0%&em,:7)n]q3y6NH3'7%G{(=z0R 3B\+ϮUɩ",V(T&i%Ǯͤ -JbTz̸ UdDVD$+)7F'us9`6^ҙ ]Ϫ>J"eBje-e@ !خngtTA~:DTCŬ[{g Dڔ;vlm%6{6VRj՟ΐXtAo שӼʷu~jSޒ ʎyqAi4Ñ'&u~9 2:Ub!]V}>Jth&,bo4O>y Q򔿥3b)rFЊ])ZծZr11P2씻ado g*+:eD{=lӛXJ$ D~YlJ91J?x gqxGUYݶt>va;|H|~RB xwHOȚs{ `ϲVţ(GQÜr,1EgzsÚ./LΖM(4o?̭hebyW(dPL02>H1My$r @4b㝷yT y)Ԝiv!\m]9,w[|ڎbg*@#: 2[P-k}/QCj &Kinq.ب*}zj%GTX72Y9_: Zv@+$)\b\8-df[gA*gĨ,9c*9okM]{8? yjw L.. ۼ¡;7S N 5OCךּ"ܯDzRtCZdqQAA֗q;nB2p?0Q8K:ik8}+ _ Y-[99y fXKaPWJn']՗dXyҘmZ|] =`+C I:8u6\Jߟ=L[EuKZlس{!{74?ҳpLA6H+tG%e@ٴ&BZR)2XZdyt0[Su -eu%rR捻k[b?ӰUkwԕ-F@Jxcw9*#gM6$ #߿YխTH3'*Ե<2y  Dm˾+&.oϣߚl tɂJ& ; C;NEHޯo@N9THRRI}^ 8 CXn] -AUFR]y*Fz,h05,Y\<0>sOIQs.@Gv.Kix^K6¦E/U+P3vng<Y(K=&cJ>y+lћj6^`S!˫s4O,84Ck0b[iuѰ3%[#D`Edvlr plP ]fkV%Y {W:8za(ڲ4Il%EőOf/UsS1<[AT<uXe\g{+ ^'xEk \{ÎW]+pOa$Dxa&c>Dɘ$3ڮԺ EO@^42@wstkg[}XfVVO$ȚS#v2Y:bkEM9xk$%'86|&. ؑSTE}yl'i92LWLU݅ҼnU/+e7%T3{mWNқg y4b#{96X/#M=qޫl0SUzVSP]V5H*8[ @ms+ʬ¶6O]A$_kkCYQPss2.y}#ۮEBY%XrGe7,nYxɲ Ji7g6WhBЎj^6֚|rAiliv%/9^9M9!lo^wbiA!.e8=ByvyԢ¢:ɖFφ6Zѕ<ӱ.ix ^S$'|3J\tNM“`n@*n:̪-7(0TH ĒTjk#+!,s*E ]pZMMo4\MbJkD,s;CКiNKM!gKkU~aQ+c |m tAiS:v&I}#S35=5Pyl icm'RoLYp /ݓ jS f$h&]OD;tQc K⣼9F ':PVQ=pb^MWF?V"Op[Xn:Op/4kvӖdcDvm]e}@oeHBbOA"05np X ビe re@J>7¼]šZNnLlei|fpSayhAA=gT\<) 9jq!㙇4gY~ʤ]Д_'O$U$aﳰ>9$Pi&jztC]U0s^BYB=UdWk$6-޶s\=iIUvpS"OS7_dƓ]0vIMl ?U.>pEԾ.H=)َu }0I̲e1:GT+ngz0g,n^rjANȡITl'G+:4]Nj= xOښ,AQ-Nʪ\ЂF*:Ô4P{mA?|LxdtԂTv0DD S mA:b>b8cR'qDFbQ Mt\˅VfeI,bnƴ:&UzOJr~dW}sjZty;d$l`y  b}RfI G?l\K!L t+n0$v=9p22j9߆xBC!FSmcO9Eѭ{ =ǜ4|"0 suGkcu~H]nHUO2Fa,bu(/u :bBc]ld*ѷC,U/IV^Rc;@HY{08V oa04~燀h.XFfU\EqxmsQPaPN6ε6Mge΂n3UXfٕl&q/%Pk2H߬QL(cj9 `fT[}Xc)h\r=Z:C^!l 0Y;N➚i??d^?j3NΠ(Óx14/h‘!@%NXu㱇@lC׹m܆`vO s,ȬKAzKfJ;d㜰Ϋk}˳C̼F 8+m vL^{73rtYdc:CRD.S,! "DoNjN(|:a{W6j c۽#9.nM*yεbnmh ^{6ݤYĝa/Gyv"hss%ȵnMP:7 5:r*f]2sV_sЫȦ<{ $.}l\RQK=keG[ iAsLAơ;vg Ud!ߺcz*ȒCS0"B) á1kMkJAmb6g+u4CE_kAMҞ.OxzOyzws /WUr|g-5HUh?#},N%Npz|9yi? qL+!'2X.6(t"}(\Ӧ#MtlQo}\\ PECEgJ]23l ygno_뀇HYWz~Tf!Q=[&G5zFKO3LYC\Nmc+7vlAݪVF9{t )=1Ab5GՕ'ryQ?~DoBĝc-,?ВskZl{[Ppfj[ΡiKĩ]CsZyZ}ĚOQGTq,59+3uE7tgy;R \ \lU}b짝 nBs8/ ~ߚTsYpziӡ=`DL)?Z !Y ~p:=vs5PXƣlN'LV>63pB9L,+]jլsS$/k^,Y(F `FۦX`ݼҝ7*Y"K\ Z`$E4bZ 8|N}|ѭi.2+!\eb i&IG \EkVA|hf'२.""{{A"@nrC%i;dzP}.}Mɚm)= MF<;1(J*if9U͗Z\WvG @dgg=:l3\ lER2 JEu'KtK4Ŧ[bEk2P3# ck )WKqR#Kpm'l߯Nͦ-BMcqm= zZ\^i{ZxuályDG/7]) tx>v$/ctC+qNj[…kԱ n;N xFb:u;k߁ RA d/{ņuv .gg}.~&;3gTڷP`Qdy]GLsKG; MS$#Ke#NRSw)TwyBPvZOxj׈@DJI9㭮F̥*̞PdOdE;U*9Ӻ:6 '7kF^zR9l($Np,J.ԇpqrh޻xRJHs)h<@V)"f B@뫪LEJl|&E렋r Z&a[+(!DY&@!K;#zT"*;C\"8]U\`it94 n=q)RTTla&-%.$onzluS᱿ISs >oYD_7ɡz(v$Q05q_ھ`U tC.Y7ٜCU1\޳~A\ִx',s[3/n=y]lQnjU,'^Oj!dAO._3PVt+V0-RUǨUwzjtc2YQށ*IZ&mK&uV׵uLKD`iDߵh\eA^HMR:]ox;h5ܪZ`'LۭxI1ºbx鐕md"s6unGzrԐw[ KL';kiMc/f鳃hֹNCG Dʰ:vbs'px!ÁGO8C RSGe-D1W^쇛\'>C>2ZuwcIzerPJHOS y߀f ^sAPL`ބPM6,Ȕ>˩kl={Z __8>zLv MjKf`(qQxXS@vfo[*$BZl֎K]Z ҩl"/Wt0@MWOtXD+$ZzH ?|+}xl[6lxZ0|`ul=OYʬ[!3gt ý yw*X 'zƣЍmQ)E+fݔ(YW[l[wÖ cn'^p&8}h;uGe{⩫װo>[6=Lz {BqY·ŴJ'W_4v"Qij[؝wp62`<` % S:Uk^%˫'HkGLڌ71*ecS_6jzqZƄFaܽ0v)VrPk;Spgk%b u ^w?2T]pAz=|gR wZs0Qǎ˧{)R6ƾ{_QhjZ$-UCB3PYhk"ޮXt,ܠSm<?tpfZP7es+okZ'r%h gN0'\^V胼gG($bݹJ(PR<;OL8R(V6lثT:ěP`{ZJVzx(AT|R"u<e[$cBҬIoQi[dHt5B z2嗓6 !D{@uU%jnyxI4ayaTթZlgzL("[Q3{ç\8"83!CXzb26,[Pr$_$ @ :A0#hq

5ɑ&)8ɵ$gҤGzӗ׿I45 I>K#%;k3Mͱ)G[%əV}ocW z|{RʥzJqž?͍\jM3*4b QS 4流jqT 4/ gӪU*i3旡t SeϚkЙAK])4rJ3m%P*̓5 K3mư|ﺯȡZC[(i4&2=iӯ i=} K$*4BjBgZa-Z+Z Owڑ]*i5ƷJ_3X/δP#OUrJW)*.)E뙮™V3m̆*4xT>:VL]jvP IDgՕYmRLzU ,&Bg"zJy`j_KJv!nP Z(bS-V IDUY%z;@@!O\)w•gP T&`ESTLo3}.:b:}@ Й>f[-&݃TLD+HV`B)t&E]!9aIV=vEUjhD@\ńRբ2O^ QtnJZJ-&B',kZL8S3_ Й>WPtbB)t&/h(`P+ ]X:J3]2 Uj t&?LPj -J3`(|k1[(APQT%告,F2BbB)tҎBTXBM\#yYͅ3L Ll0y~+ Ef5 IJڃB˄RL 6f-&| _3!_$FiSYh( gYL(NAfJS!چ P(NZRLpi1T@P tp혀_iL@tҒ+ڢ*xZ&B'-)Z-HZńR$K(Z;@B!O\)^ѯ'`k2:љ xd;JTL@ҙL۶IJ d%њm)\m[DT2:iG:J37~-x{&u V EKTOzM&B(}VT[ EKJCM45e{| ^&&Rt-&BW x+$,&\鼙*] ĶVS^`U{PhP ]dX:^ ЕNsީT4jv1 ^ZJv<2~h ( +v ^ZJ+'Z,bxT+]0Eh1hI2Ozńk; 0狀MRɅ+}ϑ=%*ͅ+\Ty&'h{LH굘P ] <5e[J70Eh1L^!e1J߾I.ZBLާR 2hIJVɄR%ͳVT[ EKʘ T/L^ E;`heL@JW"RAeB)t%Rx[,&| _3}* ʄ+BW"!ۋ*Հ᛬$\pd{AU 1I &R0z-&B7Dw(8`Vh3T/.c{PhP ]D|SOz2ńok&ZOz:JЕLS^ Е V+0 ҕn0PbB)t%LN`j+o(ՋZ&BW"/Ջ'ZWe1sGR yJd@VńRrt{5j"Lu{5dV@3Oz;YF bCT/&W{PhP ] ľT/hńR\Ty&'hM& zjZL(.A*DהeTLo1&Rt-&B-)C&V,pti> EKTOzM&BWz5@w*- ZJϴL0zajZL(HdheLRJϴiM_IK3^Lz-&BWQr!Z5Srd^勮c^zJqk4-,#hVe,k| _3MP_T/Q~TNSTx\8*4s!EUƲd)tҗ^ҫh)to=}$kNopԘ^ZƥНVXxk26#;B٥ҝec|Oz2^z)texȉvCTTy&'h;M& zjZL(}3DהeTLo;)LHeP ݉c&VಘpmJw"T$X.-J;}. VɄRND?iMzRBPDt T/L^ Н.'ZCY'ҝn0T/.cƷL(nZRL^oNzII]@A!O\)܉Rpz-&Bwz茙'Z,bxT+3 ^tJ;=6fh . wvtGlާR 2ks^<5P nީT4j1 ^ZJv<2MK36\(ɾ溽BQq!&ȿnak> V НvT/hL(ZhMzRBP| T/L^ Н:Lޡ, [%d̄RAeB)tӒbJVoUƲ-kT <ӇbZRIbk1zВBDmAZ*GC^ \* xۉ3d@S+rY퉡1BIj5_M%)1Pk;c=t/ڽ#T g'zo Np./ )T x"5@Shoh?EUj-/T /H .iN| < V /\A_ \*O<5;NR,ć#닡.á +}fא ($~=_trBAp8:AS.{Y 2Od-PPF;$jGrxbxDaEɇQR5r1l.@:XUZ O8c!R;9`-Q'0Ҋ}xi@c¬J7ʇR cVˁ W!_͙Uo9 9^?=V H.sz1lڴj`OT'1W{ല`>p` i}限#\ 2!Zp>H\%Ӧ35pVj8ҟ@@\.iK?^`"MR1k7 cHw _ ׂP*sT|_)1ѕ&@~UEM+hj01l_VʼnkA cÒ)&.H\0˷ׂ2+pT.cHhhN(b L1\&Jp}$qҔHjAxĥ&]zvtExĥϞ,- 5I㫖$qWGawǵ L1|Va4c0\ b$ñ"Kș$.CBeT؈I\1kE>I\04D %OukA _?\4L# j4K'U2kA cxTH(PclbUҬĐI\1ϺLm: bgi7y PcHhHeUZC&qetXj|$qmXZ_1dW|sfd虏$.C]?bY{"\ b${E0$.C]i` ihSĐI\1ˤ@"F$.CIwbBĐI\C˕E{'V!G!4.1dWTG: # ư}}XZ1dW᳢2St֒)fJ*H1$42֛^1dWZѝ'<=A!iԵ L⊯W:T(QÕcx55 L1M* SH1lsCꪳW b$g&WݪUÕcHh`UZC&q'`# ƐАKJֵ L1\+ H1_n_Z虎Ԥ+8r:>~E ]?ֹe0dWW*^H1ٕ&3kWĐI\1I6\ lI\04DY[kA c8L* DbH1$47ylb1dWz]*c`v-!b|=(gR+O# ƐXZЮ1dWὢK$.Ci@UDkA ctdrQw`juۊH_437_#8ВcM{DXLz~Q{0юEIhF;#]RtQ{0#EC;g ~j$W?Ў+kBYSBhX˻5RRo7_J`&͂m)SAoT6S.HƩ|Yom3xL1|L\%*Vf~L1ZגFU#l3m&S )|nQLۻiJ*5[T6Ӷ5bLZW*f>MnOEl3m{)؟xe6v4bx=m)x)}fa{ *f&S "VM^Y.ZTFOCuQec8i!D ܝbh*pSR8ӎ p[f)E4cɇ,O.˚x".b oON8x?` mȰ+l4c<QcحIeqh*pFrUEIc8-p`Y{ 1\Nw isΒnOK\1>zJRv`WѩкHBS1[TUPm I\0͢<.$4cNEYP- I\0ݢʗW@Ih*ptg2$~$.iQ ˂.TZQ6 cBᶨ*q" M׋_iY[T Cu*QH1蹋$4cxUUlPr` E%y'2.Tәf̴%Ԧ$]t%>z_ ÌR꘤c8-*IC9?tb iP-UP` E%覓v$4_\@OG+T$$.ˢ]${UR]粀:&)$q6JXVwb ꘤c-*A(>Q[wb _eQ 1I! pZTZSNkE1\;S!vT DuLRH1ܖ:;:4591,0E[VTLӇb('BeE1='2꘤c,*!, HBS1SvKU Q` m*" Mh"꘤c8-*aYE1\N]` E%Y'2.T|i;Z:&)$q^0R~w]$۴yh$$.fQ 3-^C1|K_%d0ij\NxMó:&)$qNJXVwb ׊dH1,(I I\0ۢªv$4_xNDh1I! wj.TWYFQ` E%'.T3rYoł9I1+ư[X%9ITB٥f iI2H{^f g&E&I 6!(8q.O~$Fѫ#׌ "5g сj.T߲ѫ#m$IaqT4׌ic$V* Ó1l&֣-Jڇ.f ^&#TEh co7R".f G) h5Qf|lnle{\\3 9/$$4j=FbֽRכVis{FQj / bߗ. R7ɱ >̗.Ǹl [2B-Kz,,1|䇪%4D_hKQ>~}VO M?壭K҉ec4נu%נucW;g)b m\NqcV,~u q^O$NFKe~*i#4R䚲1lK} s8n }E)nܣN0ԍaoa_ cH;X_xjԦx*#4XmiftǕc4k򏱧Ke ǥcGBN?d~M^_Pe!{Ӈﴤk.ԯs~hJ^S/@VF!Gvȕcڳt!t p0] ȥcM>G[4]r Cc* RLCAR:䡖S}2r5і&}GySH1ܚ!MK3qu]*ȥcxd|gER9#|7 WyT\:4ѮTLKWD#j7RPwZeVlLȕc8ӀX1\O0âjt I'6(=J;GPo.AM`K2n,*L2rk#*-(T*ǰi0^2X1|Rxv*#a7}mi(T*ph0!(p5Ke ȥc8MGJiӥb\:k͙`DEIb0íሶfƶ%i=)ihߴ`כ%qhvw6b--@o\0Ƣ6BR:ՙ@IJsâ"WSJ㙕J6Zt Fo!w/)>Q\o7kvS\}&;^MS;ݒKOEj4j%+C5߱5bLsu.=T&_ s#Tis|uF_YW Z,,=Oo;mF:%!뎾Z95F-Y՝KS6{BOv{c0O!`)&fFoS9ǯ8`N2K-\:d5~ES:3sR<+F\9¯:ʤCKp{±@m ȥ;|p^S+LdQ+c).oNTt miҕuǕçHCĠ>Fhl_׹%ˏcgW.N)EEB1\` EE@7H \:<1Ŷ4zTDS:g 2uA!ԼXT1[0w!mPC,r6,DxT OB|*ȥc!,lc51j_1"x#J!ץb\:syf(4 XlT+pنWE$m[*cE.o$T.ұI;בc'2HJuhJ !<,**rI!t V$pDv]*ȥc=Sg$hK<,**r3;I[4i[ X1Mp)@ڔTLKp~%, 61J/bK籃 ,*a^2r^3+_Mr oj뱩I[u7T\:s7&pz]*ȥcD5uM*I,OвI â"W,12?Wȥc LD|=*)١LPFv(, 6|#Ei+m!t / E4H*#8 (T*ǰi0b(NdR+cE.w ,*_2rvE噉 Ҥ~cQTM۩IT\:U*p$]*ȥcqn G+Aٷ9sIZOwJFUI~>4MەU;aNٯJQQJǰyF, <,**r>4~V&Y\uXTX15KνGE4c8тB)cQTlZ~gR+cE.ص$KTt оmmR(TJ>bό\ # ~!x /j7tG 1Gw. hC> H1l RcH j-.ӑMٿc%KLӟf J_$(Ic8`*\|yT{ټ\AhD{]^үNc-bnnI`ALhdr'NcjŅ9L=Vy0,Yh3:Y'T LJ1.J=sJiE)׏iǰiZ>3r1#6Mb́f'IPNzτVw v#҄fUb~FfvZbX- ha@c;B03qTc}[(SxdTC!d XҔb8g5rI1$ĥ'Hl4m&6д^@šufJm^&s qf6ȓM=r>:@]Ah]6=|H~/ZN7a(![M!, 7:\Ku+$|L3cgr/7 nzee|p& nz}FgaqcO<8$t=\COZnqSJcM D=U1R?^㦇-ܪkNhԈ۝grÇWZy>g@e(>.FvZ.:T=k `~byY,=| AűYPQ&H$3{8+f;7'= *YszÃ,p<ֽֽ́'Cfa]kfŃ x2+uh=k-z>0NoS;{.<T=[*r ;mtXMV^=yK`_Oht?*ÞYqX ~i33Z*r{^g5;8dV[=V>T=[*r {f;AUOF,'3ׁcw&khIfa55p'4=R{is]z8dVȬ:{T==+;VrkLu!X{ʩ,ع!=PGf>szdAPQJ=dT-y{ -ڪ쓙{i ANAm $oXdvZ\#=b43k;qApȬՑYy8S!*Ĵ6,hyMi=u`W,(?$9g{ism~h/\0 psf*j2 *vFCpȬģՑYy= !3Z^*-==o4W% {nDƴk-!VGf松zD=kd,X[i k17:wڴOfau3=BC&&8¯5X5+=ôk2+!judV`}&aG}Z**̂=o~EU#F '3mVcG#&Ԩl&=o{8 XF23k;q_oqJZwzziR'bmaMs={i Ys[p~N=0 )uOgwLHKCOfAžWrߩÞWN f*>wGj[ q^_&={A &if*vZY|#NoS;q.IT=k ;mM"B#퓙{iYPQ$_`{is_.*Fc3k;q`oJ\wzziR'bma4!3mVYKqUdr\ NT&uGd$hLNoR *fnLOfau3Z*>e*De7=k/:wΠif*v3&}dV`ma5oMT2 *Ҿjyջ =y`ʼn,(\>R p=yG a)4N=!X{:,:!tGfgzd6 TO2 *v$; ָTSjָiLf23Z|r;q<{Pz< =:L.|x ևorε>.'|(,#n4bgTw~T`i!<@uhqQ2c ylSp3ټTVjK婽8\<Ҩ5 zN GcՒ~ǁC˞N{: 8_i:"Xc)M>\=t2r)ՂVh$ƛ Ms˴ qFR'Aq:uy.w[8߹dMh=tвvY(:ָ=/R=ԕǒ`y |uu3x5IחIf+82%4#̂2+vudV`>GIOfAA";L2z}!4">ָT~1A{4=ƹ/ B#ރ8Cf% D= AE)ޓYPp&9M=u`-R p=yG+ a`6&R} AÑYM斏i2+{udV`>}&lgJJJ<71)rkT=kgbȬ|g'A (e{2 *Zaye g=u`FKEo,(%ޣIf[82++cj AÑYM斊2+udV`>}&GfÊ AEߓYPpm?${860'K-!3p7s)Cؔɬ{0CPpxvepȬDՑY8S2T:=[zr m}߹ 3O3GFcڵjfJN^|z8yjkAE))ߓYPp䕓/ȼoЈdi0CPs:SdT=oe{8h9!<}&57&h f*Ĵ6 mBf53ZCf5nf0pGY`b5-Y̫#A3QG^g=2O (u{2 *\]KYdj:CVV"ڀ1{=APQdT-$ B̫jȻOf QT:+Nj8d!Xj|f*&qH{W58dV:Ȭ|ÑTJg3|OfA‘Y6F]Xu}2sGf5!z$3pmV{_ AÑYMfA?8#A3Q3]ԙ,X[8hWM2!4">̂Jg~z- εA̋ R=Ԛw|fH ,DB#{8ʩ Ař ԙ&# ,ރ#{̂2+yudV`>m5nюMRg'bmM= 2?sd+DR:>ָT)[jָ/B#63Z*r'qlpȬtՑY8Sk6*J-6lky՚ y=y`ԙ_f;H$3pmV{Y`FOlgϩ T&̩ Y}3{'{!(u旬z}dNڵflқ!ҙI֢52+yudV`>m}%Ԛ Rg'bm &WwÙT f*J%kt}L2sgfő7Al|f*μj2 *vlpȬtՑY3lT:=k gfs̫lȻOf535A>&ָ5fsȬt{0CPphJg^Ozz8iSAϱ*<{<{Nm1k|]kf͆ 2+T=ydTY̫#IoSg9=2ORQdT-yݣ -2Z!4">ָT:Kl鉚dNZflқ!ҙ AIkܢ52+yudV`>}&5%Ԛ -|OfAI$۩ȼj͆ЈdNZ:0CPQ/Y{8iY!Ho6Jg3kg^g5;k68dV:Ȭ|LÙYSk6T:=[zr gfi:VmJx~јvEk68dV:Ȭ|IK5|OfAI;L2Z!4">ֽT:Kl'鉚dNZflқ!ҙ AÙTMfAΚ μ:2+0>pu#Ԛ Rg'bm,_hy՚ y=y`ԙ_f;yÙYqd `7Cf3߃ָEk68dV:Ȭ|LIkK5|OfAI$Od^fCh$}2s'q!+xn+qϩ\;j̒=1!Z.lT:=k g^9B̫lȻOf+3Z**%k^_&3{ Ho6Jg3k'qlpȬtՑYϷ8Sk6*Ĵ6I:wd^fChD}2s'q!(u旬N4=ͬ7Cf3߃ָEk68dV:Ȭ|LIkK5|OfA™YWwÙY fG3dvIf,չ0hYܤ~GǪ-4z i;iբsIUk6FN'3pҺׁfɚXdNڵflқ!ҿ AIޢ52+|udV`>m5%Ԛ 'bmK*W|ÙY f*J%ktM2sgfő7Alf*μj2 *vlpȬԑY3lT0=k 'I1s:&W[IrP!(`= 2s'i1ͬ7CfcЃ->x KxnSWzᙝ\Fx>Ӻw^Rf**l'L2sg^9őfClLf*μrj2 *vlpȬiԑYϷ3{lT=5LOfAIzIt0ɼj͆dNR;0CPnvIfmvf͆ 2+?T=.Z!rQGfgNZg]2O X{ ̂Yz&$5Bc㓙{8i Aú5I&3o[!Ho633kg^g5[>lpȬԑY3=:sz(@qg&볖v&hO)LuVmK>< hGCF̩ ,::8t4Ag&ƿ?'ޛf?!Fxg&F?rP 2 1vHٙS8wAMN1ݺqrqhy\%ySWbEVrb09ED95Y鏳^Ęj 5)9E䢝ɳj+YNmMHs^Ϊ-;/JвD/Y]I#̚ Az9R:=r{dhZJg Q.Ӧlht.:t^lȻG#ZKT:Kl}hҔ{8fClk|^.: S=6R=ԕcry|3ET:KlL2sglқ!ҙ AEEk68dV:0|{VEF.lT:=k m3wZ!4">ָht旬.$3p7fCl|f*.ZY̫EQq.lT:=k mwZ!4">ָht旬.$3pmVd{Y`b&sޚ μ:+0_#puS;<{NmJxyѮ5fCl|f*.ڵY̫#EQZ.lT:=k {t0ɼj͆Јd.Z:0CPQ/Y]GÕTqd `7Cf3߃+̂52+yudV`}&G5|OfA•Yz"5B#{6 AE3dvM2sq3k6Y`b5nњ μ:2+0_>pyj͆Jg'sKOnMs<m%Mg=:|d4}]kњ μ:2+0_>p#Ԛ Rg'bm+'_hy՚ y=\y`ԙ_f{&ָ5fsȬt{0CPp0ɢ52+yudV`}&"USk6*Ĵ4Bay՚ y=\SҁRg~ɚM2sI̬7Cf3߃GY̫#E3QW^g=2O (u{2 *͒~EUk6F'3pmVr5us[uxf1{.lT:=k '"5B#{h AE3dv$3pѺ7fCl|f*.&YfCf3 }M=\yKpyjAE3ߓ"p&WwMk\fG3dvwM2s7q36txnKxnSk:ѱj |NJ;{7Zt0ɼj͆Јdrj0CPQ/Y}wÝWNqd `7Cf3߃-;{̂52+yudV`m5%Ԛ Rg'sKEnM&WwMk\f*J%kl{iY!Ho6Jg3k7qlpȬtՑY8Sk6*Ĵ6I6ɼj͆Јdj0CPQ/Y]mÝYqd `7Cf3߃->;==6R=36txfݴu`ԙ_fe{iךY!Ho6Jg3k7ZlpȬtՑYϷ=Sk6*Ĵ6D:wd^fChD}2swR5!(u旬.z~$3pmV{Y`b&bgJg^ozz:yj͆Jg'bm,}cy՚ y=ܴu`ԙ_f)Mk̚ Az9dV:=!X{i[fCf3 7D=ܴ ԩ&6ugϩ-wZ9oڵflқ!ҙ AÝWNMfAΚ μ:2+06p#Ԛ Rg'bm_hy՚ y=ܴu`ԙ_fOMk̚ Az9dV:=!X{i[fCf3 7D=ܴƹdZAPQdT-ܴIҳ&WwMk\f*J%kt}L2s7q3k6Y`b&bgJg^ozz:yj͆Jg'sKOn,UǪs[I"OZ>2ӾwӮhJg^o|zirָT:Kl7鉚dnZflқ!ҙ AMkܢ52+yudV`}&5%Ԛ Rg'bm,U̫lȻOf۬ҙ_fI$3pm{\{Fx=XFl#1{7%ѹ$5B#{I/35w7=ܤ4fCl|f*nLZfCf3 7}M=$yjAE3ߓYPp%t(-2Z!4">;oT:Kl8d͊#so 2+T=ydTY̫#M3Qw^g=2O (u{2 *nf9̫lȻOfm35}3Afmvf͆ 2+h=ܴ9Aܦ;3|7h AEJdv$3pS{Y)`b+&bgJ^o|zyjAEߓYP &Wm}̵^#0CPQ*/Y`{-z[!Ho6J3*r1l#2 *vlpȬ4ՑY9C lT=*r 1 s̫lKf!cf*Jw%k',2s15fsȬ z0"5"sޚ :2K0{SMϱJ<xJqڵflқ!rC ;k68dV^3,Z@!mF53MOfAB 4uB̫lKf!}f**kl2s15fsȬrz0CP9"bgOGS =piU[`6drڂf⃜6#Lw\%npNԆmmkpCE7ڬۧ-~=o\:mmoltJ޷ͺ9{w%4Mʊv;1kwjC`6v5Yc=bXVmmn c+P/9AOI|R =1T:+l=pƬ֙ 2`CC l(lΌV:N- =ZA^3xnCG ޯZ!bnbxv+k ;3hyT@C <5!3c)C Ofl|:>ĸ)VX}r13\jyT` C 5Z37C ŲrdQszgϩ^_?c<gtY!Ho6Jg~f*bx,Y!FS =İsw|_kdZAPQRM]z"5dbF`ԙ_fK-&3G0fCl6hX{aYPfMf3 ̩b8fdZAPQR/ȼj͆">!(uWR =plқ&ҙ-kW^g5;k6dV:ȬZ@!׌Sk6* [*b 2Z!ȻOf!mfG3b͖ZhϵC Wޣa6³H~GǪ-|r/Zay՚ E}2s1#0CPQ̯X}wC al͆ l2+!XzYPfMf3 ̩/Z\2O (tdT,-@SU̫l,{=35[j66ؚ AzdV:0CPgDfAΚ 6μ:2+0{ayjAE3? bi!B!U̫l,{Rg~Ś-C al͆ l2+{sj,M=sj3k~oh AE3b͖ &3[0fCl6T,=İ,Y&ҙWGfr1|fdZԙYPM]zo"5db8F`ԙ_fK-&3)z[!Ho6Jg~f*bFdT`Y̫#sjlT:2 *ޯ0WX'3kf*Jkl2s1Eck6fY AC ۈ-{k6dV:ȬZ@!Rh<==*#<ǬhךY!Ho6Jg~f*b8GdT`Y̫#sjlT:2 *bGZd^fC`wEk\f*Jkl2s1Dck6fY AC [*lɬtՑY9C یSk6* K 1ģa,2Z!ȻOf!}fTT:+ldb8Dck6fY AC -{k6dV:ȬZ@!kF5^*zr 1$Xi*kB{Udbe\ {Umwtͷ|d47hsIUk6y=Rg~Ś&6ؚ AzdV:0CPgDfAΚ 6μ:2+0{ayjAE3? bi!~EUk6y=p AE3b͖ZMf!K0fCl6T,=p,Y&ҙWGfrw^g=2O (tdT,-@EUk6y=Rg~Ś-C al͆ l2+{3ƳYóH]9vj3k)#0CPQ̯X°=plқ&ҙ-k1\#2 *vlɬtՑY9C Sk6* [*oay՚ E}2s1F`ԙ_fK-&3[0fCl6|fT=İ,Y&֙Gfr1|fdZAPQdT,-@(a,2Z!4:.!(uWR =plқ&֙ AC ׈-{k6d:ȬZ@!{Nm4<{NmJx~μiךY!Ho6Z3K1GdT`Y;#sj6#Ԛ R'bi!~EUk6F%3>35[j6ؚ Az9dVB=!XzYPfCf# ̩bfdZ%,XZ}cy՚ w=T~+ldbxlқ!2 AC ;k68dV0ȬZ@!mF5Z^* =h\u:<4!sx~&hL_yӮhҚMS =p!+xn+q_S7ZϴmLYU5{:Vm=;\BԖ#`F*!q>fNm%Ώ:,aŒCxwhrjChTd#P\nO5]d Vmo&k ѱj+YN4Mփ.~LzImRVdY9!4MdY9!ǜ3ԋ:QfeDf3Y!Ho6g*yr1'cv`g*~{a 5JgB t~1—لμ;็ټW:Kl8b8Dck6Bb8'(XAҙozAZ@!k5ҙw-@s L-[!4".ĸ̘t旬R ==7D3{= >|Cr1lέkμ^n!4W6r-Ǖ4!swx~&hIdњ |`N- 9!ܚ Rg'bi!B!3d^fChD]2s1#0CPQ/Y`{xoͬ7Cf3߃^#2 *vlpȬtz0{=!ܚ Rg'sKB 4uI 5B#{335[j6vؚ Az9dV:=R1"bgJgsj lT:=[*b \5ȼl͆HdbGt㹭E8MݜkVmYswLlkyd[APQdnX[.d^fChD]2s1l#0CPQ/Y`{#z[!Ho6Jg3K1#2 *vlpȬtY9C DŽsk6*Ĵ{gyٚ yw=p AE3d͖ZMf![0fCl|f*[^g5;k68dV:ȬZ@!ׄsk6*Ĵhg1wC -5[j=*2s1|d\ {U"sЈ34w7Zy+lȻKf!sf* %knb{=7Cf3߃;k68dV:ȬZ@yn͆Jg'bi!d^fChD]2s1G`Й_fK-&3&z[!Ho6Jg3K1|FdTY#sj lht{2 *b \5ȼl͆Јdb8G`Й_fK-&3%z[!Ho6Jg3|r1CY#sj>C*%kB{Udbe\ {UmΤplV-1ȼl͆Јdbx AE3dVvC alOȬt{0b!ψ̂52+yydV`N- >!ܚ Rg'sKB 4ui_5ȼl͆Јdb8G`Й_fK-&3%z[:2+hX{YPfCf3/ ̩ޟ:d[APQdnX[5UlȻKf!T:KldbDckVg~Bf3߃ >>C|f*b8GdTY#sj lT:=K 1Ѐa 2/[!4".'oT:+ldbxlBg'ҙ AC ;k68dV:ȬZ@!mB5Z^* =h\u:<4!swx~&hLoahZfCf%R/ ̩b8'd[APQJdT,-@( 2/[!4J.!(WR =?ͬ7Cf%߃^#2`Y #sj32O (e{2 *bKZd^fCh]2s1|F`FKfeb͖ZMf!]0fCl}@f*b8Fdn[!2Gfr132O ( z2 *b \ȼj͆dbGt㹭E8MݜkVmɥswLoahr"bgFS =p.Ђ5[j=*2s1|d\ {U"3 (3 36>\;Bs6rG!軑0͇X-juj1ujs9gx>Jad8uߝ tލv|N ž#?fsD3\6#~{m\C wCU[hL/!0AIP5}2)XNm)+Jg\co^?m̜Py׫!*v;U[h׻!\~:N :# ENxԖ>m!5Mn!&뵷YwB̩ %J_YwBPgLZFlɚNqu'^3 gsNq;! ORV|~ͺ0϶ C4=k',ZJgޟ;R{g7lRSžYK|5B#0Þ'8İ:+l8{1fClW:= nas΢5X(y;=R;_\ϩ5|O NgzϪ5B#0ɨP5[jĸQ3k6 NăSaܢ5 *y;}N=tDsMl:=Mj ;Bl<0B/#1dm%.k1j̒=ӿc:TttN!(uWR p=d=T:+le7=yGAz9dV:=!X{,Y!ҙWGfD8Sk6*Ĵ6I:wd^fChD}2s;q!(uWR p=ͬ7Cf3߃ָEk68dV:ȬLNkK5|OfAN$\d^fChD}2s{f5!(uWR p=yGAz9dV:={:sj,I=sjCg|yON^fTT:+l02s;Z3k6Y`ba]kњ μ:2+0'J=dZAPQdT-!ҹ$5B#{Jg~Ś-ÞYqd `7Cf3߃=-{k68dV:ȬLÞYSk6*Ĵ=o9EUk6F'3ׁ-5[jָ5fsȬt{0CPhJg^wzziS[*mϞS[{Z9wڵflқ!ҙ AÞWNMfAΚ μ:2+06#Ԛ Rg'bma_hy՚ y=u`ԙ_fK-!37fCl|f*vZY̫#N3Q;q.lT:=k ;m7}cy՚ y=u`ԙ_fK-!37fCl|f*j2 *vlpȬtՑYy=lhyt{2\u:<4S#1{; ,Z!ҙWGf>ߦvRq*kԂ8*2sGf΅Gêm&uG;:VmoXxuU&WwA^f*JkXdڵflқ!ҙ AAޢ52+yudV`>m5%Ԛ Rg'bmK*WwÑY f*Jk2sGfő7Al|f*j2 *vlpȬtՑY#lT:=k mIUk6F'3pׁRg~Ś-Ak̚ Az9dV:={8hsj,M]9vjCg|HA^f*JkT# Ho6Jg3kG^95;k68dV:Ȭ|Ñ=Sk6TT:=k mt0ɼj͆ЈdZ:0CPQ̯X{8hY!Ho6Jg3kqlpȬtՑY8Sk6TT:=k mLIUk6F'3pׁRg~Ś-ÑYqd `7Cf3߃#-{k68dV:Ȭ|LÑRtxnR9+_rkͬ7Cf3߃vEk68dV:Ȭ|AK5|OfAA;L2Z!4">ָT:+l8d#so 2+T=ydTY̫#A3QG^g=2O (u{2 *0WwÑY f*Jk2sq3k6Y`b5nњ μ:2+0>pyj͆Jg'sKOnM'<m%Mg=: >2ӾwЮhJg^|z8yjAE3ߓYPp䕓/ȼj͆Јdi0ҙ_fK-!3p7fCl|f*ZY̫#A3Qq.lT:=k mt0ɼj͆ЈdZ:0CPQ̯X{8hY!Ho6Jg3kqlpȬtՑY#lT:=k GfiZd^fCh$}2sGf5!+xn+q_Sְjz=ӿcڵ\2O (E{2 *Zay՚ =u`_fK-!3pк7fCl5T=-Z!WGf>ߦzdZAPQ dT-y -2Z!4>#oT+l8d͊#so 2Kk!X{8:,Y!PGfgbr2Ӻw^;L2Z!4F/>#TT2 le7=yGމAz9dl0CPp}OYPfCfic }M=$yjAEizӓYPpВJ̫lOfm3΂5[jٙ5fs,`buvњ U:2+0>p:yjAEiӓYPp6Kd^fCh {|2sGf5!LR p=yGQAz9dl0'pudzYszV8D k}ΜĹV儏>TPE{6qsQc҄C>xfNm̧dئiU7'S>[Ɍ̩MdTiip4vvD љNg: 'kԆf`)$LgEz| $ɚN$ѳj+Y?Mt<\KiOBk;Ŭ(i6Irz&~~lj͆Ј4N:ulhYt旬NQ'poԆmmjM;:VmohLgʓN>IUk6F'3p 35w7=tY!Ho6Jg3k'5/Z!ҙW'/t}8Sk6*Ĵ6Iz$5B#{8iJg~ɚM2s'q3k6Y`b5nњ μ:]*0B=ƹdZAPQdT-I{C&WwÙY fTT:Kl'}h{86+N fsȬt{0'pudzYszԆϬ>ֽֽht旬Nz}dNڵflқ!ҙ AI֢52+yudV`>}%Ԛ Rg'bm &WwÙT f*J%kh{86+̽ fsȬt{0CPpuVYPfCf3 'D=yVΓv5fsȬt{0CPpSYPfCf3 '}vB=y}&$Sk6*ĴtJr̫lȻOf$T:Kl'}$3p̚ Az9dV:=!X{8:,Y!ҙWGfgμzdZҙғ[86KdU[綒3D:|d4}洛sњ μ:2+06pyjAE3ߓYPpI̫lȻOfu35I[dNY!Ho6Jg3kgR5;k68dV:Ȭ|LÙYSk6*Ĵ3o~EUk6F'3pmVRg~ɚ$]ÕYqd `7Cf3߃ָEk68dV:Ȭ|LEkK5|O斊E$}$5B#{h Ys[p~NڱU[g|L{ njSk6*J-+~EUk6F'3pSRg~ɚחIf820қ!ҙEkܢ52+yudV`m5%Ԛ Rg'sKEnM&WwEk\f*J%k2=\ͬ7Cf3߃ָEk68dV:Ȭ|LEkK5|OfA•YWwÕY fG3dvIf,չ0hYܤ~GǪ-4biݻhբsIUk6F'3pѺׁRg~ɚ-&&v5fsȬt{0CPpѾhJg^/|zhsָT:Kld.Zflқ!ҙ AEkܢ52+yudV`}&5%Ԛ Rg'bmMa,2Z!4">ָT:Kld͊#so 2+T=\ydn[!ҙWGfgx~vs M=6z}뷁+Z3k6Y`b]kњ μ:2+0_6pѮyjAE3ߓYPpѺG̫lȻOf53Z**%kDM2sWRő7Al|f*j2TY̫#E3QW^g=2O (u{2 *0WwÕY fTT:Kl8d.Zflқ!ҙ AEkܢ52+yudV`}&5%Ԛ -/|O斞E$OxVmJΐ{WwEzI!(u旬.z}d.lY!Ho6Jg3k &-Z!ҙWGf>ߦzdZAPQdT-\y%T̫lȻOf۬35EZ&+o Ho6Jg3kW^g5;k68dV:Ȭ|LEK5|OfAE+od^fChD}2sm5E&ٙS:+T0Kl"3pS{Y`b&bgJ-_/|zispu#Ԛ ,X[6KXd^fCh,x|2s7q!X{XfH$3p7fClgPf*nZY9 #M3Q7q4I=tY!Ho6CJgZ.q7PK3p9eԚ -|ÀxM.߫t՚ y=tDpJg~ɚMr7glқaҙыM}YszV/tׁRg~ɚחIfᦳ̚ Az9dV:=!X{xhJg^ozϊzɨ%Ԛ Rg'bm Qyf0Sk6F'3p-URg~ɚM2swf!7Al|f*j2 *vlpȬtՁQ娇;lT:=k wf/3fChD}2s7t`ԙ_fGM'3k6Y`b&Ek68dV:P|{M#DA:0CPQ/YGM[̚ Az9dV:=!X{i]fCf3 7D=ܴκdZAPQdT-ܴ;H"5B#{i AE3dvM2s7m3k6Y`b&bgJg^}0lhyt{2\u:<4!rԩcA^#2 *vlpȬtՑY9C lT:=*r 1ԥ -2Z!4".>#0CPQ/YGC al͆ 2+h=p,Y!ҙWGf r132O (u{27Tb WwC T:Kl7}o{~6+̽ fsȬt{0"kDfAΚ μ:2K0{=#Ԛ Rg'sCEn!4W-2Z!4.>#:CVV"Svl%{:ӿczӮyjAE3ߓYP/ȼj͆ЈdbF`ԙ_fe{=7Cf3߃ָEk68dV:ȬZ@!׌Sk6*ĴhWwC T:Kl7}_"3G0fCl|f*bGdTY#sjlht{2 *b \ȼj͆ЈdbF`|T:Kl7}'"3-{\{xnSwtNcXl#qKF;L2Z!ȻOf!T:+le71=İlқ!ԙ>#2 *vlp,uՑY9C Sk6T:2 *bKEUk6y=p AE3b͖ZMf!K0fClT,=p,Y!ԙWGfrO^g=2O (tdT,-@EUk6y=Rg~Ś-C al͆ 2K{3ƳYóH]9vj3k?u35[* C al͆ l2+!XzYPfMf3 ̩bgdZAPQ,XZ~hCsIUk6y=-5[j6ޢ5fɬt`b!mD斊5l2+yudV`N- gF5̂9EUk6y=pJg~Ś-C al͆ l2+!XzcoJg^S =pЩ-szgϩ^_1#Z3k6fY AC [*lɬtՑY9C یSk6* K 1ԥ -2Z!ȻOf!}f*Jkl2s15fɬt`b!sDfAΚ 6μ:2+0{ᚑyjAE3? bi!P9EUk6y=l?y`ԙ_fK-&3ëfCl6T,=YPfMf3 ̩bfdZҙ' tUƳ C6GF^_k-Z&ҙWGfr132O (tdT,-@( -2Z!ȻOf!{f*Jkl2sq3k6fY AC ;k6dV:ȬZ@!Sk6* K 1%̫l,{335[j6vؚ AzdV:0CP1"bgJg^S =pȼj͆>^#0CPQ X`{-z[!Ho6ʙ`f*bFdn[&1PGfr1|x~Ԗ@Y9Wqr9fMF̚ AzdV10CP9"bgkFS =p+ldb8Dck6fY AC ̂5l2+ udV`N- 5#Ԛ /Ѐ =h\u4E%Mg܎i`ʯjX+N)+\}|iy)p*p88iQZ>woqHSV𸤙Mc36/ƿ?}D'ڼ-NK)+Pvd3bΊ1Ur69gmi8CxdG40!^˂~uиCPJʘ»&ASYӗj0q;5U[5}7fY>U[`67YU[0yڬ;]~>@(iWja;!F~5}fa obYYGdz Vmu۬O5k& Ǫ-5mփ.hIHuqhRVǻ)>rjC`65YcDֱS۲jk&k ̚\3ԋgNmS5-}<"QR̯XM*{6fμo)uCb^bfCfsfҙGvj>.f̚ b ys 1yj͆"]zbKk ;Jμo*u`B!kޚҙZ@!{)5_μ1na{ވϴUk6y Ok@VIk 3\jyT` C 5Z37C eɢ}#,RxX4GxYӟ(̚ AzdV:0CP9"bg֞|uV4oڵ`Y#sj32O (u{2T-@St,2Z!4:.>#0CPQ̯X`{a=7Mf3߃;k6d:ȬZ@!sF5|OfAB Bҽȼj̻͆dbG`ԙ_fK-&36+̽ fɬu{0CPkDfAΚ 6μ<2+0{=#Ԛ Rg'bi!4W-2Z!4.>#:CV,*qϩ\;j̒=1Үyj͆Jg'bi!B!_hy՚M̻dbF`ԙ_fK-&3-z[!Ho6Jg3KָۛEk68dV:ȬZ@!׌Sk6dV:=K 1ԥ -2Z yC T:+ldblқ!ҙ AC ̂52+yydV`N- 1#Ԛ -|OfAB BWلμKf!kfG3b͖ZhϵC 쁫sazѰjM9U[h>2޴jѹ$5Йw=Rg~Ś&6ؚ Az9dV:=!Xz3"bgJg^S =İsֽ̚h(u旬Radb8Eck6Y`b!kD斊52+yydV`N- =#Ԛ Rg'bia{ӆH̫lBg%3kfT:Kldbxlқ!ҙ AC ۈ̂52+yydV`N- gF5|OfAB B"5Йw=p AE3d͖ZMf!fCl|f*bFdn[!ҙGfr1c1ȼl͆hdbG`FKEd͖ZMf!C0fCl@f*b8Gdn[!rGfr1\2ϭRdn-@cṭ S6GFcz {]kњ 5:2+0{=!ܚ kf@fAB 4uBlKf!TT5 ldbEck6Y AC Lĵ52Kk6udV`N- 9!ܚ Og@fAB Bz 5B㒙{ʛg-CfClT,=YPfCfiͦ ̩bxO=;7RAq6sjG-q~Ԕ%CxZ?XydP%vxNm)+:N:l'x?!f?䛴<6ovc휝Uϩ-emzr-GCbǴ-4mi%W6^^ߵj)`V.K#sx6ug Mo\,増,eu4Y&d 3LUu1^F.5=7 [^ǗO_۬~-y\s#/ΔZcoF\⾅qݶBU^ @kj,G,!-L0ʛR|[ m[% @Yv UUq-N.*XnQIE-@a27ɤFөlI9A u<4Zg;IL-ie7Pgp6deQY-LfPp+N-e+ePUgp6d󟩝O|Y| zfPpN-eePgp6dUbm@lmYVlπӆl@3 L7 ̂Ilj}_Ԓ/,\vr Uv6 WYiC6gڭmne@e6 ? (bjIK.:+%!LHDBmE5^&t.ӆl2G7 ǂlj,r%m9&pi#T,\ dԆ3 !Ld$B ;Jf2 zR5Yt.hӆ2Y j? f̂pt*@8 g?>E2UEe*g,5~*m,Tj+Y8SKLf᪊h(Y Љw&,~*ݒ,TJ$Y8SKjLffj!Y NT3X*,T –YT:&pUَ3!";2W?ۋYr+Y0&p )ԷUP+pA6dcYt%P)ELfT/QL-0 9LgႦ!8mS`Pi.,NgRQ©ZRa2 WC4"+Xg3,j% &pU/T,\ Y`*,~*,TY8ճSKLfB]Y9N TF.X*r,T pY &p&/UP pA 6dU5b5պȒ+Yt.螁ӆ,22 Y? ˊ8tJ!,ꍉ%\fpUA,T!,\ Ye*,~J!,B.Y8SKf᪺VB.YNjT+X X,B.+WcbyUsI*9s$NQ1|DA7j0^ 拧 5~3q'5 fg4X3g"Jփ}$vlk71\fChD=ܙz̢Jg~ɚ=S{3kPn֙gҙG6ڙ=ܙGlp&ҙĤC=tpԚ W:Mp 7H|Uk6FgpC Z(%k>4I=tY!Ho6CJgZ.q7PK3Matrices/BCSSTK24/004275500020550007177000000000000654223642600150155ustar00clevecompmath00000400000006Matrices/BCSSTK24/sep2.bpgf.gz010064400020550007177000000017660653602325100171430ustar00clevecompmath00000400000006&x5sep2.bpgfW E `:I琸HW0DTrѨKir.L+rHK*pkKsʗI|tiWiHk\?<ܛ'l1hМI

A;#0{CL QM靖`Xbxآſ$>t^sAƨju֎GnnDD>I3E1/v|!cBds,rOx"͹!4OU"٘lT6~* h ~$O-q@:p\KB;!ytg?Հ>}`VW%p< 9im{9n#xm=1C4 hxK L`Sf&қa]|AtAlJ}m?<Ƚ|*{q GȣW G kfG .Rr`O")\)J\;)r)}.`/Vuelԟ [P3iK Z`JCy+z(,"!Y5 3 X,n)-{T(QMx oAa2O P9z4!~r0z=X^%ԋH_4ϙkR[:pns K5m:f 7-OQZMatrices/BCSSTK24/mmd0.permf.gz010064400020550007177000000172120653602325100173130ustar00clevecompmath00000400000006#4mmd0.permf%[J ^E.AXs&))R qG\w]w?~\9~?߷f?ϱ}yϵwwxxxcޏsy`p`kŻ/>{wɳw8w{w?}o/z}{Gѷw}{Gѳ}k?~f?{џ;{zOg~g_|cϵǮ=vDZv깞ln݋v{/o/;^?>qOt~oݿk?{w]?;鿳^S>;Agڹzwޝwkg/07s1)X7efk#]էO'N|xڷAaM3{anbmݷ/wwb='7}s=f1yxSbG 9o~{k.di0fqc9VyN.K%D<,D|J+q5m7lL*5yJ+xu7JqSj5{_? ^5I|Mkn̡ygySKP-Q5Hz99_^5z˵^n[6׼d>e&5OS4SXNYwL1[s3N\?YrޑN.'ϭyur9sN줭qiЧOW8]qK%%K>|.\anbNf}ٍ_%cw}6ޚi8Lq^&փ`1e@>;c-vߕ1eˀc18o3%g.+fnXzH#m4H0MCA glhaKZ,iŒ5{-w-Bo -ЬYhlM4G_ ݆nw u0l䈡e2v1kC nj'zPe~ -Ňkӂ4s;ucwlX˪Vw2=;|py QƣG?h֯n.=-X̹l(:N.P&| ^BҨ|RaTUHJrp9GrL('%% vd̘~d'4&4,`(&zW>y;x?Yj}FM؁Fe5ӒK$aIU2Km%&IZ2~8X7 ߸o;a#U鏃/Ż8^JY_uEoۯ[)^=jpNjl掰u<>mc4 лH点PMf~2Aڠ!Śk:]Qx|#Ie$~&KJjTRS?FuQwuT,>0ry: ,g> YϢ}p ϖ@f> ؅A/ O2|e,jpmýϭqў?4遨f)=y79<}&hp簢=( .~'.~'8~Qk^ e)}lwo_T/~9`ގ?{ {3Qrp`)Ϸk&c*%ҌPt ocɌ;(@mә{S\I:UG¥iWQI۲m}m۷l'Z&#voǫ ^e*WʠTò;˒zcX0g_ &c- baXB:Ȣk\b['ʼ{'eʙlD;j=V`مc<Pfm,8P$J p/[P-$'ż?Ϝiu< 3Zpomvn!NE=rH#kkX$4B l 65.1t' Jޖ ı  2FIjQ#iVV[551hD#'9hF4ʦQ6}STcM1 ?IC|)e 7 /%l)>)R'%(yBF5 &WCF?S \!n!dB|^ nPx dӨF4jQ#iHFXbZOoeF4V"iȚ#>w0uƏ5~cjrM 7bSM6emGvt?Píj9͉oN|hF5Zzk^ֻN!RW RT.r)K\JR oq5ǜ9w<|ZW5"G9o(2-̿jZpRC 85എb@!V mo(U};u4umd5oa S蒺S0—W* ϲWE>o'wBՉ8oZV_͗DLYW A:BJ iRHByʣP(WHX\2= RMjTZT&K5]pmy!oyFbJ߭kޤ.V >Q2|=D kXa통nX{M|C79 y7&$ 6[rɄ;Vݚ5kk֓ґ!YHF6uK0^e+R(ZPDC EZ ~I%5"8c _*T~Hy$E+:ɚ9 K*j hwRD-v/<UWRUVf`VYf5*k&KnEJt(ѡĎ5Wb ,ֈ)2RIQ:Nx"G"`ߨdɢx7޿CEKZ FX2kr_-Eʋ_8Ye zC'ii2E0z`'ayӃ |n}aNT?RBbDiDOMr uNI]'q)H彑'~Ҭ16jldJ,D5 *Zx6]#j逦k2uYT.|w$h-ZFi'|1$DQKLdyR K`J'SwbdvGf9dv'&Z`ywvl#y̖ˉggw)PLE6ʶQmpvvQK('5-tns凫|& P @-P @-R<ODOpW\~(5E)J&UctT(%G)9*YhAsQ#3 MkH$&yD6 mBWȎBvs&=a:qO/a/ָ#;0)=co=co=co=Vf̟Ii&*%w$I6- 4$8F,lt?q[2 f䓴)JgCt6A8r_)wׂKk4-4lްyV ZjȪ! #h& i` su0;wʁ+G̀VIǓ>4P"-PL2>.a@FR"bB-a-5ҏJ*?F(NdUZ`@ -%Gh(X__5=KiNaSg䆓Nn85YMPn@Vu9%)).B$h$A# >x‹EHQ=[B-~K}R| ^rwpbJ1NL&&yi^JBKFJԑhF'8@)PT {ma{6?+3A\x%[|RFG11Z Oa~a&Fk~a%BG5  H!El2 W"jDD Ä1tj".G|D>G{=iG]G#3*Q gT8Bc|,Kħ`pfYA)R"'҉l"od6&#҈,"!R "`L_/%iH/_]©1$?GM-&ӊįF3#C!0D,MVYm*w{!Pɨ9Z)HFETi19F B&2IpIKpI4٢MhE-ld?}Xxu'QV ) 5eГX^t]NSEJ U*uUU ǂb(vCe2/H[WqU=UOm ii4~?@FF"K{%R^ IzW+5/S]$"qvg{_Up$aӅ ?TYp iKU?FSp[aQzFsF^6oTr #hGiVtAhB iR4 Lr&5}q\,}E.pч>\:b2<`=Dyyͫffmg@PD!sagY,i2K˒ez󚎷toGjۏ^~ԡG?zOF?v A!iC҅ IM$Poh0_޾ݮ]ov h%I@.;lC!lH6t;]%qs.UdFSbа[:u 4/x)l/ ?$L KE'!,!-Oh 9ޙL/bڝ7~BҐW_/%*%vP p\h"T+ؔ+yviwܴ[N#cв{vW q0auܣf3eK#x~ YI#пe&x$}[&+o?Ei΋'Ϣ) [ [X/YzO}r|3uѯ]<4^Y o:H]¢& I O>6''<|3 q#"zwHࡰr&uƪja/;ɬE[]do2 U %tdߺtM而#X Zgvꌳ*EIQ};$i$2l3c#! ?!ҫAaD1HGAAZAVW9b)挛P8׃5l~ $[r]ctfMq#]7n; JCOnAv׊ֵ/O-mXY@ŵpHK N#J4. {"IMatrices/BCSSTK24/eqmap.ivf.gz010064400020550007177000000041530653602325100172340ustar00clevecompmath00000400000006 4eqmap.ivfukv* E`@?eDaKcj%!G~,'Rp+VíM֗_niE:"ǐKyCw G#ÍF~HGr9BG7 yqFyHGJ#zD[!ٯ_oL}H??ܨoqF}HGd/;zD=~A1hxT#zD=.{qĴ菇/dg뺣QhpqxHY_v#zD Y;1|HG,;zDEw Go$LHBD%ڗx҉A:qB hD7`(eɚa١$4>2ZćxLLJ4~gh0A['#; 2Q$PFHB1y6!$"X76X%p47{lyBKD6JMbpnt%;fB\ѿēf`O["sLB1'vT?mD!NJ4&yH"PgphikY${U\& C7D#БNw)? (c/k.p_dW%x҈Nlޡ-):;rD%\;etg/upsbޡܥ/$PWՃwPpwL#; ޗw%˰3Cgh K!_ɼCZR`uv%7wБ*[iѲNW7{$HDvk`"9PB%4`؛aKՙ(`zQFt#; 1 ֳW:ogoܽ1#W%"'P`A;NHD&JTm 6WҖpNi_ɼCK7 Je}щad' I, r ZҝnM%(_h76X'1Z-Pcѐ^;`4EX bW,/8˳`)^ppaƊXꪭj'b( mމm,O =*ض V|X-p0V jdbh9ۦ]\ ^p0wn8k3c+f)4LbMZ܁: gpd;GeW@]s%=6p Т`ULcl[T-0*OŴ6ӦbTLR]aT̗ 1m*͒mwWuٶQ5ci/lfORgb8^؆fZGUלm 07BI(.3b_I`aM~׈~c b!tLB$D#&A̫<"(NbhX1q7 ʝ3Út jkK D$D%Z$ 旬KK*M_:V㆕x7;,wuT%f=I, (BJ/1Wv8 l1cWFvB] n`71 E"2Q%Yps@tf5;%*a ԉAYXɟ<.VgWuX@%# ZxNm-,Н::2o0:]"2QlrD%z`ļC#r HD&J$P:5\G[[悎ѝu'A!76X#:1:OTwFvBI,9\RsAgZpJ]iHBQF/d>WJMZU!ߙ}М}gh&4h< M,jd'A%7 7CHBN],Mx|'PD#:1l%=D"Pn hD'F$wTwK*\AJIu)(vݨqB,6$ec%~Matrices/BCSSTK24/mmd1.permf.gz010064400020550007177000000062740653602325100173220ustar00clevecompmath000004000000064mmd1.permfu[:D .A|C؜ʮ;IHOJDyvmqu5J{5\6677lؽvio|m\{w,o/<䡇Z &(U+_>=jeq_;.`=xUݼg@L2ZA2) 4h4ֲ&IuyOչ+g{?tнѸ qEHkpkpM>o(MO=)$0Vcpq0Yde"L 2_ySxw (`NaB8”q SL9I 5h8eg䛚Ǝ0[O6EXfps٬?m[L#x7nx3&Mli%qwdΗv7$*ȿ=}u0kq5]n|yV]9 ل)W`Ӆ25lsV;O|FA4v2Œ%Wg5$z@TQGI%G֒$DCa ly~ $^AHې ZN{!-|A Z h=r6-vA0dH#TvZ=_ս"ppb>ʳFŠzzAr31aT$p^)FLQzI1!Ζ X7&C QIWc xnW˦s˃õꄰHɖHyJ1{)̴$o'9 r|;>Gs" ř^DV4!d=IMR`jɁA+5kyg4i-_PFc;!Aw 4=v?ь'O}&U,wrfAa)_ >?Mϲ)x+b+워8YIr Co$,2$Z}֋\)z2W/DPR_~`lJT^|m' `I؊QNj\\[qڿ Z<)A},/*S3a0W[M*ƒj+U5v[s[%\U T rP\kfbL^'1`;jCBv'7D_cK* I2S&1Vdk [ŕ9@/ oIډ: U^zkMv_µGX?^(\9)LjlY\Tn}Cs$W=GCQW{Vr>iin1zԔU۱%OŁ+RXQ%j)f}V$i'zWVh:-Ը$m;;|~z;Pн0l0KebL#wC) ~\}r>%Uc=H%Ճt`H/D$ }u38[r^ގ%F?DO ~f*6RX|9L2vrC"hӴeǚI!t(4JDKrkYH=nVsDYefF!ɒH%4UN/_Oj)iTLjZ&x R Iǵl#'Yِ<TG $$R2BY*r%SRv*I^@FM!(%y%^F,C&[%'=&u\?9z}QsS. 1WI Cz ک`_G7tt <,V囮W̔Ҫa= :[z(} =-r:H*0 ӏj)K&UipGSґFanobjR6%U8MB/9ؚ +_.!K^<^I,$HJ?3>F@3<gd`7o('W*Tk$"/'JKYjhJ?]wI!/ggGk ɟ5t 2O˳0y+9ֽTUW Eb#œ#FLMK6jO_V&ҫHcݵ?koVΑn/Gw25`%3 {.eĝƈ]=]n~p>RP}RWt◿vՙ-mĭ^O=gAvvK:4K~>ʰU.#21d~А_gVrK_q28EpOO!O 6K%;+#D-Wt=UPm16@!5?ɤ#1tO1%t$rLq(^suTg]P4% t?? |I7)x44/jjt10ggMatrices/BCSSTK24/fishnet.ivf.gz010064400020550007177000000004250653602325100175670ustar00clevecompmath000004000000066 4fishnet.ivfU[ )r/b ai͆M +yO•wD EuAx@c  ?5ʅr2LX.٘o0iq(o_s,`> B$©ˣ^jk IT?t^=x^:w:NJ !3 bGҴOj: ]R!W"ZEt!iE8?8yNH@eh'@o!𗾼Qg *Ѥ y9l_@*2zrd@-AWay, V?A";,-BEXu[Z=|ۯgE .lMd(SE}Sa,*Q+5':(SXT8b= 5wv/#g,?-NL )@c{,{@oR\.+zYqOt [Ӥ)z%@_#+% p(X 7D&qZf(+0qD{yOtD ¾).]ès\W>eRR:.E~\fHOYᲟ24,2/SE^R>x|聑z%v8O@֌M B]Z\t^SBP@A$A=`AX %=vpJT( ReINp8$7Oǁ3G/F?/QS&N WD[d-u@-:,ْ&f'5}Psf^ۊ . ԽXMhPݯ ܹ?{yUpp@`8~y~;AN{@a]\ `iN1 SPi3]\(mW,L= cz`Ql"Hbf;[PwK͢\Kω"-Ң\}z] 5JRI/WNl4e"< jٿyGㆃ9sQF)owpds+#ES``^91oz= P rk @OZ\bM@5&jA4B }c?u*A$?נy݆OOAE@QE!E&%TjO>MUVkg+=lkp@x,)got y `&^wI>`;M^PNDD3p'"?}"DzerQD3p'"?yX)*캐|H=,N DV2#ۜ[zm\s0lL)q4L#Vw[ipB@}F[]? P&C 4ByrA}c=# I+rz`Н$EU$)Н$!,&= ()$9r]|CС$ .{xLɎUq{=PC(ӿ(zQ$w]@EOڨ܃]>& B",Gp9!3 $a{i Ff'ɕH'+@^t1V 4r6?`uVC3r'@O =An=v"2]4* rOAړ'O9Wx b_~!:>YUl[хf{iB3(>[t,^]$lXh}4m}ZmH. pwaħ/ QrfG`Ԡh6305P|g24ܬ0 _@. N`4A^vg<.drf|ԗ_WTZh}0F4qz(%de(ɯ_az./ ƞ|7݈` :Р+e70JUn6,c2|ڽ2LurDk.}v~7:` P @+%tk[ ٰ )S=4<ɩի™wynlZgG4emFs&M Usx&k|#޵dS5d'pA[t>H b+x|x&k_7[V< VpIc-hI;<{4 mUi[ӝ6kvXhk0Sip{Sx݊^#a,brƖJ|4LYh8~+FLN OhؚLtK F =0Mi͟6鱏]&2\o{H[]ݬ'@hْ܋}N v?O5hX0,ceF5$0틜lt4S!y 2h8MN?hۣQ8l/ $ iiF/I3AW c K@A(ZK4:W8?(OI3uwf 3]_L  KCp482p6sZz`A͟fmO_L sLEH} 7J,VXc9[%mC(^&[xQ j10jh9j^jlGhfΈ\GeBhU7q ]Rl7(ERE S5O֨[c>Y О4@;!aI3y uM;֭O1<Tbk\fBMK&c'io(܊@]ސkMQ@CN }g56v6XVi,4i|;}u|Olw~h8 ngѨv)P9-=0OI3c'E,N89E`i=kF5W8-OI3cGv7 𛰜&2=|dF+43xlLb,'Ѩn$F9-5%iIW^L Ik%9lFHxR ._f4:l쌙9MkiNQ#UΏ9-=SLݝY>%249}@ás3T1qyOc󧤙1@nQ>f@ r,/ ;8s^vڽuЇ w ݦ}[l v?'ٙuр;=4#FmRKbB x1b@yXXP_ObĨJf7('*z%%#LaNmxR#*:2|k$~]5G/pxGD"7rAU! {~ re+맊{ȜIsS9q6Le{yB Xw.l>],ˍ}MB8 N&k@?FX~r á҄C 5p^"7W[:&Q0p#r]ß+6pJW!rO8r`. b~)wypgbt=&ߝX0BQ+;4}VQD;PDw@zDnt;P QGHX'6rcq ccl < ` ]Xm=Oп!>C.1ª F150ȭAlyʌ3b!MpIC;P{$@ES :W!PWXJ8w$ v|hRC{@nʍ)uE$) $w\hPJ+9Њ:6Q@v5zl (DCn`do[j#RB$@? 6\F/^6Kй `o)qu!k,i Ӥ~I0.(=#5v%"GJוvXFDD2r%"GT`9nr{y/P8{"a Aw0:=3p'?>V3a9_^b % o)Fm,@ !r}!"Yr,OZ/8U-G@#E1#'H х4Bz:yfY~E 00&﹃ za1Zh `|-b ņNG[{' H.zQR{ND#ꮢfbJ}rJ:$G*r95ɱ&<"PQH}oppau,Vc k9]A(/{I]hwyx@aLq3  w{@n$L[Oo~@ lČ9ɍrwz3&$7.nr7ė02'G$x/=]:trDf+Y ʢ4ʨcR%ecưlDQdUq,&@-Nˌ2 Z6ɻ |hL* ʞtǪ36|vaz45Ra{FS K̕ E1UF3IN%W?kMaAULh-9*k\Q%A2v2Lr,x#)=o/dnCnXba5,/5,"XjJA{A" `nBF(}l{;䆅zo25J`dx؃ZtF~}=nv,}13` CQI[2S>'-v]):U2/ۀ0ɝC;±Q-;t) i춤mmz1+VjfncL饢W`Fp G;0nAkTp;ɋ%s.kQ/{^#k&dKZ K!(|(QXa Tp8"V%mO1cHt틔 \ĸ y~ _(^qcx^g街#;V/h&W4#)@7s)<G *|YE,Qh:2eڊqOQ@Cܜ A%Qg *x(:Rl|owaIÀv%ͳ|]RZN#G8~TvL(G97gjbc3. I!H+i"%NSHsҞ:7<߆?qYrbET-EʸD$єV!_#勼еA\QejPSrPrC0P|yԹ)QNm* 3](4NlFcR"BtAa>E,Q>4[ yHȟ QCPH0+ʔL4IS3>U̒)}i9Cb977]T?S}3j7T2Gh3 z%:csWN( N1fPp;$D0C̔~1ׁ{fdGAZNѕCjߙe_ \?Matrices/almond.9/004275500020550007177000000000000654276404300153005ustar00clevecompmath00000400000006Matrices/almond.9/orig0.adj.gz010064400020550007177000000122230654275667700174300ustar00clevecompmath00000400000006݋5orig0.adj]b㸮߳ /nEE#rϝc H( xL}__Ӱ81.W}kvL\g\" ih iHrĄdmJ:-K̸nI&ͶoY_ l{ Sɾk4٥ɮcq<£iCk{1ѱh\xlVG,r{#Ƹsר l4Z9v}>jzem I_HP_w {|?=c5{Ӭ?Hi ASlJ4u'sXug،%l-|Y4_b3r-VͼJkz[z[]~ M9nqڦhͷKC}۾]%x:#lfpH 3?Cx8\uj[lNokc5.7G ]381&}q~Ƹjp} קOpSz6p}^ts,@חQk̡ٲje_>5v|M㦵޸ǚM6iw:}]'.Y_,qa Э# fivIlzA]'}?k\ϛ~3v卞1h1^c1v 'nN]t&M z9 R)y,? ]> =5 b,kz)qӸ!_5BALq)nYCѬ]5[5r>4x^ IOQ 1([~I|+4ך=cҝTHpCKcXI)/OHCVhBvsB w L&2Ԩ/y,5L5z ~K>9]UϹYtЇu,CY@N˂& TT06s.!p,'${r$Lm3&VmeY_l:xM#I$]B]>>:9]w&Y4JP7F&&Oiv|]5"Κp<?&L}/ \s^*% Zc7 jK9,K3jշ#hW s`m9D~щ5{IamqX&]9M|?5̱a -"zc9V'B[4qLXaiĔyvLԯqnhrkM~ޢ4u"Auyt_]y]VXoORnN湫!p"i˘[nJd!$9lˀ L'¦pZgx+Nh/n-qaǦ˵c;u" @<6_ R$k  =q}I`ccrD;05t*V, I2l !U3o G0[^a䱀$hHNj7alMՈi)B0Y>bȳq_+#,YڀA_WH*^!Ocŝߑi7v-W<pW!״p嘁&炰27)4]<7[^ q[+!?E4$zɜM"dxdRr'Ɩ>!q=~ǃ HZ辂},x&[Ȝf$DJzwm%$K K1I2ǟȩҁ`뇰r#Y(ړ9l3Ex4kiεL[汱 0$IN\$+C愄Q0o'Ė96Ǝ#6{a֟)(ɶ2\e76L`7d"X 9x A =؄5H08%Ù4FL qUNImv\zۤ ₸Lр<$f$lO k4 bׇA0#iSAsn?(♼҇+1e>?1bAx'J;8+3L9MT Ĩe.>tD2*:G,'0@Cxl`4|~`M))g,&JI1xF 9> I->LLݷ"W}1`2 1~Wƨ{W[Z3&M>i褟1=7vW V<ӄ/w:&$ P Mr7yvs\Gezn9- 8~\)-Y:minR׋֤67[\I䉉>C_ z}Y~| ,۹N_Mc#n;U?~+xps0h[M06'lJHM6|zk F~ X6;8c c\4La %B{eiOJjv؆zwԤX>Rs"y/-v&Q0=M< cSHݬgKӃ126>e$ܔsg#~H?8W3~ФR)p(&x`9:|pqkpz WxZos'n5kh0űLX$^';O̒ԓƏ'%V-wMq"\\u{q-G, ] 4S͊M)  Gh瘭Pcƻħ& ME>kT>Mzz 47ws;Ql(Ӄ~mQt9Lo ^qt.0qy@u 76OD#H.k% gdL38ES@siI!%,;̒= 5QjwLSMbKYcg0ɮD*[&"`?֤R[MçE0llSǘjf@e}9oúRKb;C 8q]x=ryi|qBPR)h)5Y\+}JfTx_qoKJ1}Uѹ)ОP\.O'{[89|%٬JX:`Np+?EW} S xZI9L``;TMcP8&-*2vO4M`Se5qQoՁϦB/"Ab&ײ]ó[4ccW|J=`lѻO @`HBsJ>˂mL. xѨ͸{MנaF=';H'oNj!Ѱm^z{;妘s=h8#:CWl`J,?+K$sh7.W9$G"ƾ.֕XȋP2G2CcD a \q #9bsM`̤ c pn@ą9D#h5qdo7e@_3T9;$9ɴ[dylZc7Lud z+c7d]6,x~a|!IoZ-K2zq@q>%5)]z0EIV$RȂsֶzdwDj,FKnTJlC)m "Y̽4 96-` q,MBV@lMlفq\ynzC!ƻώO_{4@k۶E#ҕwq_֖MCegVf(1AߖF?~cV~0g=54z[WAn-FRt'hd\ 1p:"|+y{vYdn7醽ļ~P&F|r. Ie0}<\zf,>/Iqxh,0 O ǯ,To)nWnN{bN6o}?$lOSsȨx57A|ؖPMu -ӛg~]rhiٮUB="@[k~4,sfc4~Kg^fvpE'dl1A7 (x~qopxM#I$]B]>>:9]w&Y4JP7F&&Oiv|]5"Κp<?&L}/ \s^*% Zc7 jK9,K3jշ#hW s`m9D~щ5{IamqX&]9M|?5̱a -"zc9V'B[4qLXaiĔyvLԯqnhrkM~ޢ4u"Auyt_]y]VXoORnN湫!p"i˘[nJd!$9lˀMatrices/almond.9/orig1.adj.gz010064400020550007177000000130450654275720500174200ustar00clevecompmath00000400000006ދ5orig1.adj[#){^BB:oq "*].kHd?Zۢq=4bcը=WW! zTbc e(qŖg\ AM^ߧ3 !Ѫ 7:p*N%XfKc"|`Ca/ljYH{7] ت'p8L}/F {t _"fm&O-9xsNgLJ~8GlBcBu} ij([`{V{."o,!Ֆ4={`1!\ =( ^x=+R hSe9lR6QVXiWB*M".Vf^Ub`Y6zJ֫si:|=wg#NL{~êl`8ش8DhڄVtw"jw:Dg2RCt(;ٹNE_)>^SX\K{F\"tio/KeU6,jcŲ4S]TFsWaJiN5mlv4~ɱ~wǥ,43UjVAE&^KѨ8\BaJYOqJMS^oM_+W#([ղ5.8ZplW/큽S,fE`{jk89(Grh+qt;Η456M?h_C,8ꔯj1qDGuiեmM]#jˮ//Z_- Ըi<4^bתk&-yӥC7cQfZ\5ږ^CMK~)~%oV5j϶__&ޮvʯPֽ۩]~^,hHCqp4R%Sd')[ϧ±z4^ZӾԫzf`lKuO)[vz/kˋ66_K[K:66So4*BUxr8rRi̗=rU*G/AZ4*P\"H-aCToPBᬌ[?,O pdd M,F=A hg!/%n"w5BRRK[#(lV!1rMi#0D@m~Г[$)dp!G3#r (0tUۗ\roZ!{k.M\a7*: ό!QnA$J1&Xi?U͡$ӍC)! Ed#|`첒‰tW*Dlp'g#eLș6Vgfb_/v>>+T;+>Ë3ZcAi!Faޛ"0|&.1E3*d-,N1ꗜMݻw"7a;5I8/&x"6졼[A.-QQ X!NNՓPh|6LNA)16 'D-CV}@PgLYt"`P*k5 .nu^yK@(l1闅PDf)?NN~.J1Zŏ=K '.LN`*7ǟEE(l5|8A{ +:CZr 9X{b[miof٫R48=ʸiNC@7}r58Pe 85 V=C"d94' 8h|YdqV,T+lJs̬Q¾4t&5#s'>i5AkN 8z9r"DTY~_"r0W_15$;&ʺXdBbAxr$p <&!GDHË5~CSny6+Q9J?|~UtHF/3J7: iFEн8NdX1g/w`ڍcǬuet'}U!o9!4̍Oh?oy5O,-! SwK8->&k%A1t5z<'L~g&@Z}lK'C9%`QPI `$%NIb2WqJ{P[ j V1Z61N,n>~t-`ڎ?6m. Lcc`E`1!npˈ#c0ڿoC&1Al+.q,zhm!8nH]2$`F ĉ%΀I4JPceI@Ǽ&p8p ݜ)X+/, T, { Bǰ ^E'ԷxN=<9[q H:ih,!VL,ums\FRo L ]$r;}k @ֿ߂P7s]LF)4wNdѪcVWC\a&Db  Vڕ׬z.h; YX 07#{W5"X-N}IIO?~ FRT|ŧLU؇hNuDBc@3DYIi@ZFJ)apG93˲}:W{/d[RR̘L4b~  yPkOo~V*G$\xAxG(F[Z3M=*a耟Q=WvMw tbuH+8aĝP xB\ߠzH~rzg ۂ QO9>%=oqˍ;q0JD[:J}Paxpv;gM8MN!^-5&"OFcT_S@yi{ G|3#3d9!_rO6+!&ofL 84L~q H%bμa}XBa@%hʹi4%x3Fߊm2\&)fYޒV+Ÿ%8Mx9e'L@| KA-ճɍz>Ll3N( #lGZ;nph$9=[Jbh#pM0]dO#:JPZ XZ'kauь&`“}48י)ЌJ8cPٛώ_!\Snȗ&a3Uw~YR> Ha~%< =0txd8! PkjSP F3.an өQ":{' Dຌx$].yy՛EqdC<:0a1!ZN WH h ;iJwX3rhz+(q6RR=wc)sBRCj4~XҌ; }IN5 W/P8q1'#r>.pgLU3 DKԗ#6xdux]eݩbezYbYM^ I3ؤ!'b@5 y8@%|X]>ds{h7?gV;%;d}:uIl>D6H`JSX:.qU ,r咟yR@]p\,4zRUIG#0\0稪š$FפIWfYSoS4l._VOF=W'<: ^0=LDz]a X.H m莖!9 $9%pkގem&xѨø{Max='$vNvsq Mᅣ'}ֽrUsr8s1 Xxxx_"ȡep*sPدD}]+b!/7OSU۳f Lm%Z>F{9'G&JOPhc6_^377[?~3^/"dan5! vnWl 6kc7H8Q2Io!sޛI2) &oj_>DIMe$'<3(}=BhkM f`GN3 ;XAbsֶzdʫRKߚJɗ 8Md1ҰrO3/"6n-`zH*7n]@0۪.TuhKS]cM!Gf"t;?wQYoL7&HV9Anz{ 5f̕`Fo늞;ȭ[͈ćC^1oN"ՙ V&pKI7%K"6;s` N@C㛗Y${5`y 4S f0arfꐼE>~A򂒬M3d:Ge<75-]|NOF`AG|ugCx-QF>a[VwmZwmoo6.$]t{hiѮBq46fZ3 9}|ol!m:O4zjF?:q?UqTw c~NxMatrices/GRD7x7x7/004275500020550007177000000000000654476726300151315ustar00clevecompmath00000400000006Matrices/GRD7x7x7/nd.etreef.gz010064400020550007177000000016020654450345600173270ustar00clevecompmath00000400000006.5nd.etreefV[9SzU=;/Gh!W2Smbe\Z%$՜l@v*MTңZ8lfj=,hUA#qXjK&A9uԯwKIi#.u v3"iv q״]iU-iM¶Ht=AbV5qyĚ}Yb/dW"t2e!oEk0-d1R"*c8C1R@1R(j瘶m}(ZqC wV A+s2F*m-Ū1NǏ=s#vYn|3vh%Ur1UJKvNbJϨZp݊8(a\gz:,|IxKCla3%Az4^2qFJ,yXM=rHv3AN<q-Lwͬ79Μfo7?_n/"ߙ ߘ'ڎ|,v79VL6V G [헞s˻ʛsd[@SnOO3?s_!ɡ0\!|ɡ|y E7JUZth}H>TR(*  .P|@Ee-ݯKi2"N3˺PnP?_?/`d<=:>,u{;ť,"ܢ/,**bt tuBH11.&맂HZ+J)eơ_bxA y:;YmǸÇ/bmG#gn1,kG7,d063ח{aBaCh5W:1N1l eGцec#Tfo Matrices/GRD7x7x7/orig0.graphf.gz010064400020550007177000000100170654450331600177360ustar00clevecompmath00000400000006Ά5orig0.graphf\m_8N ħ{^9ŨdDU8K}.~/營oa_rm/~/°ԾMMOn_GD!?x?Ko x^s>O^+>t-k|JW|9(2^<\P3^|S.>_*o/6t7þ"w L_gi^u(EoJ9rW Tjw_(JVv+Z|ܸK}n.]^P/K7#a-`#G(76"|FZO9Yˈ+jsweY2Bwqě +[7IŘ544'3kAQb+I1?'40󍘵9&BAso)xuWԼi9w~(K÷(W'N9$"49&\BAs\sEkAs CW Vs1Qs@YմjzWSP tEkA C:94ւ C94ւ+4\gPskiYj ^ZĵvGRKՀTu˖KΛ׾i=R{ws"޿eI܂| r~LA(QF0}at/ØFt_}`CI|/KB ?,*V&ffLQ1f l .uTI¨8 iTxRa!%nTRa t"L H̫p{n?Iǘ Q .iWL(+o.&b4 Q:`?6SFh-AhBZ|!Nb7 7J"JaUIS`4`+-8H5EX]o5=i (Q`Y~ LwН<%iJ(H5Ex>taXQla]DYyZARU5haXQF1IMU85XYտl`@hoU4k#V 봦8Q!~h6VrqqpwJ"[F;ZTEO&1Q] w&)Y6 \5pDG|ocNZ3ذLUX;OyJ7E0T5/孠t"߈KIMa g*͆?R] S3*BJoE&)1p ŠHo@ҭo.I4ml@7;5j7)tc|*jU7WlD d`#+$`RՈB7wn@T.t+JDmF |n;Ѝ]X EQb|g1*ʘr.KEE 薻ɰAcpcE8.ثЍ]ruэ]%3f%L g9KrST3^N.-~gn[?\SUGwl@79Uj4Ѝ]WJkn"ܨ3**XHfZ`CRHpK2OqtWs.ڮǽ88ap@DGB S"d]A| T&HfWA| ܪEa Ŀm5i|4b'9eZ=#W4&BehA_) Ds"HoC8'@QD?y"'J~l54Mu&VTOXux'%"^BӀ %J f@&j4r"OMi4#Q9'@Ah @kQ9',-ڀăoLVOyX?#@ jjJ@MD<,D5FTN 0'd&<:b *gU7 <j3`3dm@a;Ta&[X?f#A jjND_x4dC%*myګ`NɆxBt<@T p^?FTN p5(u(f6Q)fzzk?1`5)Dp+H B%*myV`{:E"_t<@T dd@Q9'ۘڀ&O-S 39.G }L˼{u zxtt"-F&~ҝtSBЄA"1(J,51|~Sz51WA<*,"n0H 3O" ${烬ڳ8 Uo.:}zF цhN0u$gw&Ж('@.[@#N =8a2@TZ&j{ AȺr%d'z!ؚ!3Y`%+OY=}#jv%jjJDY %J P#@&j?+DDl3@T)r&Og#&Tʉ<^fL ${!P͐jHZA?`5@l5w5'/]|,JT%u? r"Oa O13y4&e͐ )X9uoitҚ52 v3$7g2JwY=gQ&h;G `jxF(A t 7CV1[Aeߛ!6΄I 3HShҦ 7$fH+ț1LЛάAgZx!P͐!& tkyɳmI0w$ۤ] lm:D6≮h' tFjG5L)uJ/NpB5Cf6 J2Qd ~qoV jjJDZ %JHLݸ x)+5r@2^T3d&k[ X?SĽf[99bXD-Q@@6F>MZ~_q?5OUOߐE~hdocumentation/004275500020550007177000000000000665014165000147525ustar00clevecompmath00000400000006documentation/ReferenceManual/004275500020550007177000000000000665315046500200155ustar00clevecompmath00000400000006documentation/ReferenceManual/algorithmDesign.tex010064400020550007177000000661160664721267000236640ustar00clevecompmath00000400000006\par \chapter{Algorithm Design} \label{chapter:algorithmDesign} \par Let us begin with a very quick description of the sparse factorizations we will use. We assume that the matrix $A$ has symmetric structure, or more generally, if $a_{i,j} \ne 0$, then we treat $a_{j,i}$ as nonzero. \par Let us ignore pivoting for a moment. The matrix will be factored as $A = (L+I)D(I+U)$. The rows and columns of $A$ are partitioned into {\it fronts}. We use the upper case Roman letters $I$ and $J$ to refer to index sets for a front. We use $\bnd{J}$ to represent the {\it boundary} of front $J$, namely those rows and columns $k \notin J$ such that $l_{k,j} \ne 0$ and or $u_{j,k} \ne 0$. \par There are two steps to compute the entries in a front. The first is to form the temporary matrix \begin{equation} \label{alg:eqn:1} \left \lbrack \begin{array}{cc} T_{J,J} & T_{J, \bnd{J}} \\ T_{\bnd{J},J} & T_{\bnd{J},\bnd{J}} \end{array} \right \rbrack = \left \lbrack \begin{array}{cc} A_{J,J} & A_{J, \bnd{J}} \\ A_{\bnd{J},J} & 0 \end{array} \right \rbrack - \left \lbrack \begin{array}{c} L_{J,*} \\ L_{\bnd{J},*} \end{array} \right \rbrack D_{*,*} \left \lbrack \begin{array}{cc} U_{*,J} & U_{*,\bnd{J}} \end{array} \right \rbrack. \end{equation} The $*$ subscript means all rows and columns that precede $J$. We think of the temporary matrix on the left as {\it fully assembled}, i.e., the original entries are present plus all updates from rows and columns that precede the front. \par The second step is to factor the front as \begin{equation} \label{alg:eqn:2} \left \lbrack \begin{array}{cc} T_{J,J} & T_{J, \bnd{J}} \\ T_{\bnd{J},J} & T_{\bnd{J},\bnd{J}} \end{array} \right \rbrack = \left \lbrack \begin{array}{cc} L_{J,J} + I & 0 \\ L_{\bnd{J},J} & I \end{array} \right \rbrack \left \lbrack \begin{array}{cc} D_{J,J} & 0 \\ 0 & H_{\bnd{J},\bnd{J}}^J \end{array} \right \rbrack \left \lbrack \begin{array}{cc} I + U_{J,J} & U_{J,\bnd{J}} \\ 0 & I \end{array} \right \rbrack. \end{equation} \par In equation~(\ref{alg:eqn:1}) there will likely be many columns $i$ such that $L_{J,i}$ and $U_{i,J}$ are zero, in which case they need not take part in the first equation. Since all preceding rows and columns are found in fronts themselves, we can rewrite equation~(\ref{alg:eqn:1}) as \begin{equation} \label{alg:eqn:3} \left \lbrack \begin{array}{cc} T_{J,J} & T_{J, \bnd{J}} \\ T_{\bnd{J},J} & T_{\bnd{J},\bnd{J}} \end{array} \right \rbrack = \left \lbrack \begin{array}{cc} A_{J,J} & A_{J, \bnd{J}} \\ A_{\bnd{J},J} & 0 \end{array} \right \rbrack - \sum_{\bnd{I} \cap J \ne \emptyset} \left \lbrack \begin{array}{c} L_{J,I} \\ L_{\bnd{J},I} \end{array} \right \rbrack D_{I,I} \left \lbrack \begin{array}{cc} U_{I,J} & U_{I,\bnd{J}} \end{array} \right \rbrack. \end{equation} \par The fronts can be grouped into a {\it front tree} using a {\it parent} relation: $par(I) = J$ means that $J$ is the parent of $I$ in the front tree. There is one special property that relates the boundaries of fronts and the front tree: if $\bnd{I} \cap J \ne \emptyset$, then $I$ is a descendent of $J$, or conversely, $J$ is an ancestor of $I$. Front $I$ need not update all of its ancestors, nor does front $J$ need to be updated by all of its descendents, but when an update does occur, it is between two fronts that have a ancestor-descendent relationship. The front tree is defined by the parent relation: the {\it parent} of $I$ is the front that contains the first row and column in $\bnd{I}$, in other words, the closest supported ancestor to $I$. (Of course, if $\bnd{I} = \emptyset$, then its parent does not exist, and $I$ is a root of the tree, actually a forest if $A$ is reducible.) There is one important property that relates the boundary sets of a front and its parent: if $par(I) = J$, then $\bnd{I} \subseteq J \cup \bnd{J}$. \par Using the front tree, let us describe the fronts that are descendents of a front. We use the ${\widehat {\ }}$ operator to denote a subtree. ${\widehat J}$, the subtree rooted at $J$, is the set of fronts that contains $J$ and all of its descendents. We can write the subtree relation in a recursive form. $$ {\widehat J} = J \cup \bigcup_{par(I) = J} {\widehat I} $$ Using these two relations, we can rewrite equation~(\ref{alg:eqn:3}) as follows. \begin{eqnarray} \label{alg:eqn:4} \left \lbrack \begin{array}{cc} T_{J,J} & T_{J, \bnd{J}} \\ T_{\bnd{J},J} & T_{\bnd{J},\bnd{J}} \end{array} \right \rbrack & = & \left \lbrack \begin{array}{cc} A_{J,J} & A_{J, \bnd{J}} \\ A_{\bnd{J},J} & 0 \end{array} \right \rbrack - \sum_{par(I) = J} \left \lbrack \begin{array}{c} L_{J,{\widehat I}} \nonumber \\ L_{\bnd{J},{\widehat I}} \end{array} \right \rbrack D_{{\widehat I},{\widehat I}} \left \lbrack \begin{array}{cc} U_{{\widehat I},J} & U_{{\widehat I},\bnd{J}} \end{array} \right \rbrack \\ & = & \left \lbrack \begin{array}{cc} A_{J,J} & A_{J, \bnd{J}} \\ A_{\bnd{J},J} & 0 \end{array} \right \rbrack - \sum_{par(I) = J} L_{\bnd{I}, {\widehat I}} D_{{\widehat I}, {\widehat I}} U_{{\widehat I}, \bnd{I}} \end{eqnarray} One more trick is necessary. Recall equation~(\ref{alg:eqn:2}). Once we have assembled the temporary matrix, we factor into the $L$, $D$ and $U$ portions plus an additional matrix $H_{\bnd{J},\bnd{J}}^J$ which we call the update matrix. Using the update matrices of the children, we can rewrite equation~(\ref{alg:eqn:4}) as follows. \begin{equation} \label{alg:eqn:mf} \left \lbrack \begin{array}{cc} T_{J,J} & T_{J, \bnd{J}} \\ T_{\bnd{J},J} & T_{\bnd{J},\bnd{J}} \end{array} \right \rbrack = \left \lbrack \begin{array}{cc} A_{J,J} & A_{J, \bnd{J}} \\ A_{\bnd{J},J} & 0 \end{array} \right \rbrack - \sum_{par(I) = J} H_{\bnd{I},\bnd{I}}^I \end{equation} This is the defining equation for the multifrontal method \cite{duf83-multifrontal}. The matrix on the left is the {\it frontal matrix} for front $J$, and is usually dense and almost always treated as if it were dense. The first matrix on the right consists of original entries and is usually sparse. Each of the $H_{\bnd{I},\bnd{I}}^I$ update matrices are treated as if they were dense. \par There are many advantages to the multifrontal method. The computations are almost all dense matrix operations. In a serial environment, the temporary storage for the update matrices can be handled as a stack, a last-in first-out list structure. This makes the transition to an out-of-core implementation very easy. But, the one disadvantage is that the frontal matrices can take up an immense amount of space for the largest fronts, typically near the top of the tree. This is the main reason that we do not use this algorithm in the {\bf SPOOLES} library. \par Return to equation~(\ref{alg:eqn:3}) for a moment. A left-looking block general sparse algorithm computes three of the four submatrices on the left. \begin{eqnarray*} T_{J,J} & = & A_{J,J} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap J} \\ T_{\bnd{J},J} & = & A_{\bnd{J},J} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap \bnd{J}, I} D_{I, I} U_{I, \bnd{I} \cap J} \\ T_{J,\bnd{J}} & = & A_{J,\bnd{J}} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap J, I} D_{I, I} U_{I, \bnd{I} \cap \bnd{J}} \end{eqnarray*} and then factors the three as follows. \begin{eqnarray*} T_{J,J} & = & (L_{J,J} + I)D_{J,J}(I + U_{J,J}) \\ T_{\bnd{J},J} & = & L_{\bnd{J},J}D_{J,J}(I + U_{J,J}) \\ T_{J,\bnd{J}} & = & (L_{J,J} + I)D_{J,J}U_{J,\bnd{J}} \end{eqnarray*} If the fronts are large there are good computational kernels to be had. The disadvantage lies in the irregular access patterns for the computed factor submatrices; this makes an out-of-core implementation problematic. On the other hand, working storage is modest, for there are no update matrices waiting to be assembled. \par \bigskip \par \noindent {\large\bf Pivoting and delayed rows and columns} \par \bigskip \par Let us now turn to pivoting during the factorization. It is not the actual swapping of rows and columns that gives problems --- one must merely keep track of indices and permute rows and columns. What does complicate matters is when rows and columns cannot be eliminated from a front due to stability reasons. (The remaining lower right matrix in $T_{J,J}$ may be zero, or eliminating rows and columns may result in large entries in $L_{\bnd{J},J}$ or $U_{J,\bnd{J}}$.) The delayed rows and columns must be {\it passed} up to the parent front, enlarging the parent front where an attempt will be made to eliminate them with the rows and columns in the parent's front. \par Let us assume symmetric pivoting for the moment, where the row and column permutation matrices are identical. Let the rows and columns in front $I$ be partitioned into two sets, $I_e$ contains the eliminated rows and columns and $I_d$ contains the delayed rows and columns. Let us look first at the multifrontal method for it is easier to understand. \begin{equation} \label{alg:eqn:mf-delayed} \left \lbrack \begin{array}{cc} T_{I,I} & T_{I, \bnd{I}} \\ T_{\bnd{I},I} & T_{\bnd{I},\bnd{J}} \end{array} \right \rbrack = \left \lbrack \begin{array}{cc} L_{I_e,I_e} + I & 0 \\ L_{I_d \cup \bnd{J},I_e} & I \end{array} \right \rbrack \left \lbrack \begin{array}{cc} D_{I_e,I_e} & 0 \\ 0 & H_{I_d \cup \bnd{I},I_d \cup \bnd{I}}^I \end{array} \right \rbrack \left \lbrack \begin{array}{cc} I + U_{I_e,I_e} & U_{I_e,I_d \cup \bnd{J}} \\ 0 & I \\ \end{array} \right \rbrack. % \left \lbrack \begin{array}{cc} % T_{I,I} & T_{I, \bnd{I}} \\ % T_{\bnd{I},I} & T_{\bnd{I},\bnd{J}} % \end{array} \right \rbrack % = % \left \lbrack \begin{array}{ccc} % L_{I_e,I_e} + I & 0 & 0 \\ % L_{I_d,I_e} & I & 0 \\ % L_{\bnd{J},I_e} & 0 & I % \end{array} \right \rbrack % \left \lbrack \begin{array}{ccc} % D_{I_e,I_e} & 0 & 0 \\ % 0 & H_{I_d,I_d}^I & H_{I_d,\bnd{I}}^I \\ % 0 & H_{\bnd{I},I_d}^I & H_{\bnd{I},\bnd{I}}^I % \end{array} \right \rbrack % \left \lbrack \begin{array}{ccc} % I + U_{I_e,I_e} & U_{I_e,I_d}, & U_{I_e,\bnd{J}} \\ % 0 & I & 0 \\ % 0 & o & I \\ % \end{array} \right \rbrack. \end{equation} \par The update matrix for $I$ contains the delayed rows and columns as well as the usual update matrix $H^I_{\bnd{I},\bnd{I}}$ that would normally occur. $$ H^I_{I_d \cup \bnd{I}, I_d \cup \bnd{I}} = \left \lbrack \begin{array}{cc} H^I_{I_d,I_d} & H^I_{I_d, \bnd{I}} \\ H^I_{\bnd{I},I_d} & H^I_{\bnd{I},\bnd{I}} \end{array} \right \rbrack $$ Recall, the $I_e$ rows and columns are fully assembled, so they can be merged into the parent front. Let us define the new front after merging all delayed rows and columns from the children as $$ {\widetilde J} = J \cup \bigcup_{par(I) = J } I_d. $$ We can now write the multifrontal equation with pivoting as follows. \begin{equation} \label{alg:eqn:mf-pivoting} \left \lbrack \begin{array}{cc} T_{{\widetilde J},{\widetilde J}} & T_{{\widetilde J}, \bnd{J}} \\ T_{\bnd{J},{\widetilde J}} & T_{\bnd{J},\bnd{J}} \end{array} \right \rbrack = \left \lbrack \begin{array}{cc} A_{J,J} & A_{J, \bnd{J}} \\ A_{\bnd{J},J} & 0 \end{array} \right \rbrack - \sum_{par(I) = J} H_{I_d \cup \bnd{I}, I_d \cup \bnd{I}}^I \end{equation} Delaying rows and columns from one front to its parent really doesn't change the multifrontal algorithm very much. This is the reason that a factorization with pivoting has usually been implemented by a multifrontal algorithm. \par Now let us return to a left-looking general sparse factorization and try to incorporate pivoting. The equations that accumulate updates from the descendent fronts must be modifed to include the delayed rows and columns from the children. \begin{eqnarray*} T_{{\widetilde J},{\widetilde J}} & = & A_{J,J} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap J, I_e} D_{I_e, I_e} U_{I_e, \bnd{I} \cap J} + \sum_{par(I) = J} \left \lbrack \begin{array}{cc} H_{I_d, I_d} & H_{I_d, \bnd{I} \cap J} \\ H_{\bnd{I} \cap J, I_d} & 0 \\ \end{array} \right \rbrack \\ T_{\bnd{J},{\widetilde J}} & = & A_{\bnd{J},J} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap \bnd{J}, I_e} D_{I_e, I_e} U_{I_e, \bnd{I} \cap J} + \sum_{par(I) = J} H_{\bnd{I} \cap \bnd{J}, I_d} \\ T_{{\widetilde J},\bnd{J}} & = & A_{J,\bnd{J}} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap J, I_e} D_{I_e, I_e} U_{I_e, \bnd{I} \cap \bnd{J}} + \sum_{par(I) = J} H_{I_d, \bnd{I} \cap \bnd{J}} \end{eqnarray*} It appears that since we do not know the structure of ${\widetilde J}$ until the delayed rows and columns of the children of $J$ are known, we cannot start the computation until the children of $J$ are finished. This is not quite true. Write the above equations as follows, marking the ${\widetilde T}$ matrices on the left as distinct from the $T$ matrices on the right. \begin{eqnarray*} {\widetilde T}_{{\widetilde J},{\widetilde J}} & = & T_{J,J} + \sum_{par(I) = J} \left \lbrack \begin{array}{cc} H_{I_d, I_d} & H_{I_d, \bnd{I} \cap J} \\ H_{\bnd{I} \cap J, I_d} & 0 \\ \end{array} \right \rbrack \\ {\widetilde T}_{\bnd{J},{\widetilde J}} & = & T_{\bnd{J},J} + \sum_{par(I) = J} H_{\bnd{I} \cap \bnd{J}, I_d} \\ {\widetilde T}_{{\widetilde J},\bnd{J}} & = & T_{J,\bnd{J}} + \sum_{par(I) = J} H_{I_d, \bnd{I} \cap \bnd{J}} \end{eqnarray*} The $T$ matrices have the following form. \begin{eqnarray*} T_{J,J} & = & A_{J,J} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap J, I_e} D_{I_e, I_e} U_{I_e, \bnd{I} \cap J} \\ T_{\bnd{J},J} & = & A_{\bnd{J},J} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap \bnd{J}, I_e} D_{I_e, I_e} U_{I_e, \bnd{I} \cap J} \\ T_{J,\bnd{J}} & = & A_{J,\bnd{J}} - \sum_{\bnd{I} \cap J \ne \emptyset} L_{\bnd{I} \cap J, I_e} D_{I_e, I_e} U_{I_e, \bnd{I} \cap \bnd{J}} \end{eqnarray*} The computation of $T_{J,J}$, $T_{\bnd{J},J}$ and $T_{J,\bnd{J}}$ does not depend on any delayed rows and columns from the children, and so it can begin to execute before the children are complete. It is key to note that $J$ and $\bnd{J}$ are known before the factorization starts and do not change due to any delayed rows or columns. It is true that we do not know $I_e$ for each descendent of $J$ {\it until} front $I$ is complete, but in some sense that does not matter. All that is necessary is to keep track of which descendent fronts $I$ have $I_e \ne \emptyset$ and $\bnd{I} \cap J \ne \emptyset$. The three equations with ${\widetilde T}$ on the left are simply an assembly of matrices --- one matrix comes from the updates from the descendents, one matrix from delayed rows and columns. \par \bigskip \par \noindent {\bf A serial factorization} \par \bigskip \par There are five simple steps to a serial factorization: initialize the front, load original entries, accumulate updates from descendents, assemble any delayed rows and columns from the children, then factor the front and update any delayed rows and columns. Here is the algorithm step by step. \par \noindent Loop over the fronts in a post-order traversal \begin{enumerate} \item Initialize $\displaystyle \left \lbrack \begin{array}{cc} T_{J,J} & T_{J, \bnd{J}} \\ T_{\bnd{J},J} & 0 \end{array} \right \rbrack = 0. $ \item Load with original entries \par $\displaystyle \mbox{\qquad} \left \lbrack \begin{array}{cc} T_{J,J} & T_{J, \bnd{J}} \\ T_{\bnd{J},J} & 0 \end{array} \right \rbrack \mbox{\tt +=} \left \lbrack \begin{array}{cc} A_{J,J} & A_{J, \bnd{J}} \\ A_{\bnd{J},J} & 0 \end{array} \right \rbrack $ \item Accumulate updates from descendents. \par For $I_e \ne \emptyset$ and $\bnd{I} \cap J \ne \emptyset$. \par $\mbox{\qquad}\displaystyle \left \lbrack \begin{array}{cc} T_{J,J} & T_{J, \bnd{J}} \\ T_{\bnd{J},J} & 0 \end{array} \right \rbrack \mbox{\tt -=} \left \lbrack \begin{array}{c} L_{\bnd{I}\cap J,I_e} \\ L_{\bnd{I}\cap \bnd{J},I_e} \end{array} \right \rbrack D_{I_e,I_e} \left \lbrack \begin{array}{cc} U_{I_e, \bnd{I} \cap J} & U_{I_e, \bnd{I}\cap \bnd{J}} \end{array} \right \rbrack $ \item Assemble postponed rows and columns. \par $\widetilde J = J$. \par for $par(I) = J$ and $I_d \ne \emptyset$ \par $\mbox{\qquad} {\widetilde J} := {\widetilde J} \cup I_d$ \par $\mbox{\qquad} \displaystyle \left \lbrack \begin{array}{cc} T_{{\widetilde J},{\widetilde J}} & T_{{\widetilde J}, \bnd{{\widetilde J}}} \\ T_{\bnd{{\widetilde J}},{\widetilde J}} & 0 \end{array} \right \rbrack \mbox{\tt +=} \left \lbrack \begin{array}{cc} H_{I_d \cup (\bnd{I} \cap J), I_d \cup (\bnd{I} \cap J)} & H_{I_d \cup (\bnd{I} \cap J), \bnd{I} \cap \bnd{J}} \\ H_{\bnd{I} \cap \bnd{J}), I_d \cup (\bnd{I} \cap J)} & 0 \end{array} \right \rbrack $ \item Factor the front. \par $T_{J_e,J_e} = (L_{J_e,J_e} + I)D_{J_e,J_e} (I + U_{J_e,J_e})$ \par $T_{J_d \cup \bnd{J},J_e} = L_{J_d \cup \bnd{J},J_e} D_{J_e,J_e} (I + U_{J_e,J_e}) $ \par $T_{J_e,J_d \cup \bnd{J}} = (L_{J_e,J_e} + I)D_{J_e,J_e} U_{J_e,J_d \cup \bnd{J}})$ \par $H_{J_d,J_d}^J = T_{J_d,J_d} - L_{J_d, J_e} D_{J_e,J_e} U_{J_e,J_d}$ \par $H_{J_d,\bnd{J}}^J = T_{J_d,\bnd{J}} - L_{J_d, J_e} D_{J_e,J_e} U_{J_e,\bnd{J}}$ \par $H_{\bnd{J},J_d}^J = T_{\bnd{J},J_d} - L_{\bnd{J}, J_e} D_{J_e,J_e} U_{J_e,J_d}$ \end{enumerate} The last step needs a bit of elaboration. The factorization of a front is a complex process. The matrix $D_{J_e,J_e}$ is diagonal or block diagonal. Our codes try to detect large block pivots as a way of taking advantage of the speed of BLAS3 kernels. \par Consider symmetric pivoting for now. (Nonsymmetric pivoting is much the same but the notation gets more complicated.) \begin{center} \begin{minipage}{3.5 in} \begin{tabbing} XXX\=XXX\=XXX\=XXX\=XXX\kill $J_e = J_d = \emptyset$ \\ while a pivot block $(\bfj, \bfj)$ can be found \\ \> $J_e := J_e \cup \bfj$, ${\widetilde J} := {\widetilde J} \setminus \bfj$ \\ \> $D_{\bfj,\bfj} = T_{\bfj,\bfj}$\\ \> $L_{{\widetilde J}\cup\bnd{J},\bfj} = A_{{\widetilde J}\cup\bnd{J},\bfj} D_{\bfj,\bfj}^{-1}$\\ \> $U_{{\widetilde J}\cup\bnd{J},\bfj} = D_{\bfj,\bfj}^{-1} A_{\bfj,{\widetilde J}\cup\bnd{J}} $ \\ \> $T_{{\widetilde J}, {\widetilde J}} := T_{{\widetilde J}, {\widetilde J}} - L_{{\widetilde J}, \bfj} D_{\bfj,\bfj} U_{\bfj,{\widetilde J}}$ \\ \> $T_{\bnd{J}, {\widetilde J}} := T_{\bnd{J}, {\widetilde J}} - L_{\bnd{J}, \bfj} D_{\bfj,\bfj} U_{\bfj,{\widetilde J}}$ \\ \> $T_{{\widetilde J}, \bnd{J}} := T_{{\widetilde J}, \bnd{J}} - L_{{\widetilde J}, \bfj} D_{\bfj,\bfj} U_{\bfj,\bnd{J}}$\\ end while \\ $J_d = {\widetilde J}$ \end{tabbing} \end{minipage} \end{center} Note the matrix-matrix multiply with the explicit inverse of $D_{\bfj,\bfj}$. We actually compute the inverse $D_{\bfj,\bfj}^{-1}$ as part of the test for acceptability of the pivot block. (See Section~\ref{section:PivotFinder} for more details.) \par \bigskip \par \noindent {\bf Parallel factorization } \par \bigskip \par We have one major assumption as we move towards a parallel algorithm. {\it Once a front is complete (all updates from descendent fronts have been made and any postponed rows and columns from the children have been assembled), the its factorization takes place inside one thread or processor.} This does not lead to a {\it scalable} algorithm \cite{sch93-scalability}, but it is important for efficiency to have the pivot selection process inside one thread of computation. \par In light of this constraint, let us look at the five steps of the factorization. Steps 1, 2, 4 and 5 must be done by one thread, the owner of the front $J$. It is Step 3 that must be parallelized across the processors. Now for the major question: if front $I$ updates front $J$, who performs the computation? There are three possibilities. \begin{itemize} \item The owner of front $I$. (The fan-in method \cite{ash90-fan-in}.) \item The owner of front $J$. (The fan-out method \cite{geo87-fan-out}.) \item Some other processor. (The fan-both method \cite{ash93-fan-both}.) \end{itemize} We have chosen the fan-in paradigm for this library. It is a simple method, fairly efficient and can take advantage of subtree-subcube mappings \cite{geo87-fan-out} better than either the fan-out or fan-both methods. Any algorithm will distribute the factor entries among the threads, but there can be only one owner that computes the factor pivots of a given front. Furthermore, the fan-in algorithm features no exchange of factor entries among the threads, rather it is partial updates, or {\it aggregate} updates that are exchanged. \par Step 3 needs some modification for thread $q$. \begin{itemize} \item[$3^\prime.$] For $I$ owned by thread $q$, $I_e \ne \emptyset$ and $\bnd{I} \cap J \ne \emptyset$ \par $\mbox{\qquad}\displaystyle \left \lbrack \begin{array}{cc} T^q_{J,J} & T^q_{J, \bnd{J}} \\ T^q_{\bnd{J},J} & 0 \end{array} \right \rbrack \mbox{\tt -=} \left \lbrack \begin{array}{c} L_{\bnd{I}\cap J,I_e} \\ L_{\bnd{I}\cap \bnd{J},I_e} \end{array} \right \rbrack D_{I_e,I_e} \left \lbrack \begin{array}{cc} U_{I_e, \bnd{I} \cap J} & U_{I_e, \bnd{I}\cap \bnd{J}} \end{array} \right \rbrack $ \begin{tabbing} XXX\=XXX\=XXX\=XXX\=\kill If $J$ is owned by thread $q$ then \\ \> for each supporting thread $r$ \\ \>\> $\displaystyle \left \lbrack \begin{array}{cc} T^q_{J,J} & T^q_{J, \bnd{J}} \\ T^q_{\bnd{J},J} & 0 \end{array} \right \rbrack \mbox{\tt +=} \left \lbrack \begin{array}{cc} T^r_{J,J} & T^r_{J, \bnd{J}} \\ T^r_{\bnd{J},J} & 0 \end{array} \right \rbrack $ \\ \> end for \\ % else \\ % \> send % $\displaystyle % \left \lbrack \begin{array}{cc} % T^q_{J,J} & T^q_{J, \bnd{J}} \\ % T^q_{\bnd{J},J} & 0 % \end{array} \right \rbrack % $ to the owner of $J$ \\ end if \end{tabbing} \end{itemize} Of course we are omitting the rendevous (in a threaded context) or send/receive (in a distributed context) logic in the algorithm description. It should be clear that the aggregate updates (on the left) and the delayed rows and columns (on the right) $$ T_J^q = \left \lbrack \begin{array}{cc} T^q_{J,J} & T^q_{J, \bnd{J}} \\ T^q_{\bnd{J},J} & 0 \end{array} \right \rbrack \qquad \qquad H^I = \left \lbrack \begin{array}{cc} H_{I_d \cup (\bnd{I} \cap J), I_d \cup (\bnd{I} \cap J)} & H_{I_d \cup (\bnd{I} \cap J), \bnd{I} \cap \bnd{J}} \\ H_{\bnd{I} \cap \bnd{J}), I_d \cup (\bnd{I} \cap J)} & 0 \end{array} \right \rbrack $$ must be made available to the threads or communicated to the processors that need them. \par The presence of pivoting, and thus the possibility that a front may not have any eliminated rows and columns, makes an implementation somewhat tricky. This is a key point and needs to be explained further. It is simple to determine {\it prior to the factorization} which threads will support which fronts, but it is possible that a none of the fronts owned by a thread will have any eliminated rows and columns that support some given front $J$. The aggregate matrix $T_J^q$ would never been created but the owner of front $J$ will be expecting it. In short, the communication patterns of the factorization without pivoting must be obeyed for the process to terminate satisfactorily. If an aggregate matrix is indeed empty, meaning that due to delayed rows and columns the updates that would have been performed will not be forthcoming, the entries are not actually transfered, but the notification is made. \par \bigskip \par \noindent {\bf Parallel solve } \par \bigskip \par Let us now consider the forward and backsolves. We make one assumption: the data partition of the factors $L$, $D$ and $U$ will be maintained during the solve. In other words, the entries in $L$, $D$ and $U$ are found in basic submatrices, $L_{J_d \cup \bnd{J}, J_e}$, $D_{J_e, J_e}$ and $L_{J_e, J_d \cup \bnd{J}}$, and these submatrices are not split up across threads or processors. There is still the concept of a thread or processor owning a front. In the threaded code we do allow for different maps from fronts to owners.\footnote{ For example, the forward and backsolves could be done with fewer threads than the factorization. } \par We do not actually compute $A = (L + I)D(I + U)$, instead we compute $(L + I)(D + {\widehat U})$ where ${\widehat U} = DU$. Recall, the eliminated rows and columns for a front, $J_e$, are split into pivot blocks that we denote by $\bfj$. By convention, let the boundary of $\bfj$ be $$ \bnd{\bfj} = \{k\ |\ l_{k,j} \ne 0 \mbox{\ for some\ }j \in \bfj\}. $$ Note, $\bnd{\bfj} \subset J_e \cup J_d \cup \bnd{J}$. The serial solve $(I+L)(D+U)x = b$ is found in Figure~\ref{fig:serial-solve}. \begin{figure} \caption{Serial forward and back solve} \label{fig:serial-solve} \begin{center} \begin{minipage}{3.5 in} \begin{tabbing} XXX\=XXX\=XXX\=XXX\=XXX\=\kill for $J$ in a post-order traversal \\ \> for $\bfj \in J_e$ in ascending order \\ \>\> $y_{\bfj} = b_{\bfj}$ \\ \>\> $b_{\bnd{\bfj}} := b_{\bnd{\bfj}} - L_{\bnd{\bfj},\bfj} y_{\bfj}$ \\ \> end for\\ end for\\ for $J$ in a pre-order traversal \\ \> for $\bfj \in J_e$ in descending order \\ \>\> $y_{\bfj} := y_{\bfj} - {\widehat U}_{\bfj,\bnd{\bfj}} x_{\bnd{\bfj}}$ \\ \>\> $x_{\bfj} = D_{\bfj,\bfj}^{-1} y_{\bfj}$ \\ \> end for\\ end for \end{tabbing} \end{minipage} \end{center} \end{figure} \par As we distribute the forward solve across threads or processors, we see that the right hand side vector $b$ accumulates updates of the form $L_{\bnd{\bfj},\bfj} y_{\bfj}$ from descendents of $J$. Since these updates are made in a distributed fashion, each thread or processor needs a copy of $b$, or at least of copy of the entries in $b$ that it will interact with. The same holds in a slightly different sense for the backward solve. Instead of a vector $b$ that needs to be gathered and accumulated, it is a solution vector $x$ that needs to be scattered to threads or processors that need it. \par A well designed map of fronts to threads or processors will no doubt take advantage of locality within the front tree, e.g., a subtree-subcube map. In these cases, the entries that {\it active} on a thread or processor will be a fraction of the total entries. It thus pays to take have local vectors $b^q$ and $x^q$ for thread $q$. These vectors should contain only those entries that are active on thread $q$. This is particularly important when we are solving several right hand sides at once. \par Figure~\ref{fig:parallel-solve} describes the the parallel solve $(I+L)(D+U)x = b$ as done by thread $q$. \begin{figure} \caption{Parallel forward and back solve} \label{fig:parallel-solve} \begin{center} \begin{minipage}{3.5 in} \begin{tabbing} XXX\=XXX\=XXX\=XXX\=XXX\=\kill for $J$ in a post-order traversal \\ \> if $J$ owned by $q$ then \\ \>\> gather $b_{J_e} = \sum_r b_{J_e}^r$ \\ \>\> for $\bfj \in J_e$ in ascending order \\ \>\>\> $y_{\bfj} = b_{\bfj}$ \\ \>\>\> $b^q_{\bnd{\bfj}} := b^q_{\bnd{\bfj}} - L_{\bnd{\bfj},\bfj} y_{\bfj}$ \\ \>\> end for\\ \> else if $b_{J_e}^q \ne 0$ then \\ \>\> communicate $b_{J_e}^q$ to $b_{J_e}$ somehow \\ \> end if\\ end for\\ for $J$ in a pre-order traversal \\ \> if $J$ owned by $q$ then \\ \>\> for $\bfj \in J_e$ in descending order \\ \>\>\> $y_{\bfj} := y_{\bfj} - {\widehat U}_{\bfj,\bnd{\bfj}} x^q_{\bnd{\bfj}}$ \\ \>\>\> $x_{\bfj} = D_{\bfj,\bfj}^{-1} y_{\bfj}$ \\ \>\> end for\\ \>\> store $x_{J_e}$ in $x^q_{J_e}$ \\ \>\> communicate $x_{J_e}$ to those who need it \\ \> else if $x_{J_e}$ needed by thread $q$ then \\ \>\> obtain $x_{J_e}$ and store in $x^q_{J_e}$ \\ \> end if \\ end for \end{tabbing} \end{minipage} \end{center} \end{figure} \par The interplay between local and global information can take many forms. In our present threaded solves there are global right hand side and solution vectors that are protected by locks. In the MPI version explicit messages will communicate information among the processors. gets more complicated.) \begin{center} \begin{minipage}{3.5 in} \begin{tabbing} XXX\=XXX\=XXX\=XXX\=XXX\kill $J_e = J_d = \emptyset$ \\ while a pivot block $(\bfj, \bfj)$ can be found \\ \> $J_e := J_e \cup \bfj$, ${\widetilde J} := {\widetilde J} \setminus \bfj$ \\ \> $D_{\bfj,\bfj} = T_{\bfj,\bfj}$\\ \> $L_{{\widetilde J}\cup\bnd{J},\bfj} = A_{{\widetilde J}\cup\bnd{J},\bfj} D_{\bfj,\bfj}^{-1}$\\ \> $U_{{\widetilde J}\documentation/ReferenceManual/intro.tex010064400020550007177000000000660664721267000216670ustar00clevecompmath00000400000006\chapter{Introduction} \par \input softwareDesign.tex documentation/ReferenceManual/intro.tex.old010064400020550007177000000075510664721267000224520ustar00clevecompmath00000400000006\chapter{Introduction} \par The {\bf SPOOLES} library is based on three concepts: pivoting for numerical stability, approximation techniques, and BLAS3 data structures and computational kernels. We now discuss each in more detail. \par \begin{enumerate} \item {\bf Pivoting} \par Let a matrix $A$ have the factorization $P(L+I)D(I+U)Q^T$, where $P$ and $Q$ are permutation matrices, $L$ is strict lower triangular, $D$ is diagonal or block diagonal, $U$ is strict upper triangular, and the nonzero structures of $L$, $D$ and $U$ are disjoint. The entries or blocks that lie on the diagonal of $D$ are the pivots. When $A$ is symmetric, $Q = P$ and $L = U^T$. \par Any nonzero entry can be a pivot. Some are better choices than others. What we really have is the equation $A = A_E + E$, where $E$ is an error matrix and $A_E = P(L+I)D(I+U)Q^T$. Not pivoting, where both $P$ and $Q$ are the identity matrix, may be impossible (due to dividing by zero or a singular pivot block) or inaccurate (where $\|E\|$ is large). \par Here are four examples. \begin{itemize} \item Partial pivoting has $Q = I$ and $|L_{j,i}| \le 1$. \item Complete pivoting has $|L_{j,i}| \le 1$ and $|U_{i,j}| \le 1$. \item Bunch-Kaufman pivoting has no bound on $|L_{j,i}|$. \item Bunch-Parlett pivoting has $|L_{j,i}| \le 2.7808$. \end{itemize} Our strategy to control $\|E\|$ is to bound the magnitudes of the entries in $L$ and $U$. \par \item {\bf Approximation} \par What if you were offered an approximate factorization, not exact but accurate enough, whose footprint (the total working storage during the factorization and/or solve) was small enough to justify the decrease in accuracy? Where would this be useful? One example is a very large problem where one simply cannot store the factor entries. A second example is where the solution to a linear system does not need more than so many significant digits. \par % Let $A = A_E + E$. Here are four different factorizations, in relatively increasing order of accuracy. In each case it is the $P(L + I)D(I + U)Q^T$ product that we will use to solve a linear system. \begin{itemize} \item Fill $E_1 = A - {\widehat A}$ with entries of $A$ to drop. Factor ${\widehat A} = A_E + E_2 = P(L + I)D(I + U)Q^T + E_2$. \item Factor $A$ approximately, i.e., construct $E$ on the fly. \item Factor $A = {\widehat A} + E_1 = P({\widehat L} + I)D(I + {\widehat L})Q^T + E_1$ then drop entries from ${\widehat L}$ and ${\widehat U}$ to create $L$ and $U$, and set $A_E = P(L + I)D(I + U)Q^T$. The error matrix is $E = A - A_E = {\widehat A} + E_1 - A_E = E_1 + P({\widehat L} - L)D(I + U)Q^T + P({\widehat L} + I)D({\widehat U} - U)Q^T$. \item Factor $A = A_E + E = P(L + I)D(I + U)Q^T + E$. \end{itemize} Some of this functionality is in the present release of the software. The rest is easily built using the objects and their code. \par \item {\bf BLAS3 design} \par Matrix-matrix operations have secured their place in dense matrix computations, and to a certain extent in sparse matrix computations. But are they appropriate when pivoting and/or approximation take place? \par The {\bf SPOOLES} code is firmly based on BLAS3 kernels. The fundamental data structures for $L$ and $U$ are not rows or columns, but submatrices. The fundamental pivot element for $D$ is not a matrix entry, but a submatrix. The algorithms we use are true {\it block} algorithms, not {\it partitioned} algorithms \cite{hig96-asna}, inverses of matrices are actually computed and used. \par There is a price to be paid for this strategy. On matrices where there is not a lot of available block structure, the BLAS3 data structures and kernels are not efficient. But for matrices that have good block structure --- multiple degrees of freedom per grid point, large matrices from three-dimensional applications --- the BLAS3 codes outperform older codes that are based on rows and columns and BLAS2 kernels. \end{enumerate} documentation/ReferenceManual/main.aux010064400020550007177000002020310665314325400214470ustar00clevecompmath00000400000006\relax \bibstyle{plain} \@writefile{toc}{\contentsline {part}{\uppercase {i}\hspace {1em}Introduction}{15}} \@writefile{toc}{\contentsline {chapter}{\numberline {1}Introduction}{17}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Software Design}{18}} \newlabel{chapter:softwareDesign}{{1.1}{18}} \citation{hr98-msndtalk} \citation{karypis98metis} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Changes from Release 1.0}{21}} \newlabel{section:intro:changes-1.0}{{1.2}{21}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Changes from Release 2.0}{21}} \newlabel{section:intro:changes-2.0}{{1.3}{21}} \@writefile{toc}{\contentsline {part}{\uppercase {ii}\hspace {1em}Utility Objects and Methods}{23}} \@writefile{toc}{\contentsline {chapter}{\numberline {2}{\tt A2}: Real or complex 2-D array}{25}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {2.1}Data Structure}{25}} \newlabel{section:A2:dataStructure}{{2.1}{25}} \@writefile{toc}{\contentsline {section}{\numberline {2.2}Prototypes and descriptions of {\tt A2} methods}{25}} \newlabel{section:A2:proto}{{2.2}{25}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2.1}Basic methods}{26}} \newlabel{subsection:A2:proto:basics}{{2.2.1}{26}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2.2}Instance methods}{26}} \newlabel{subsection:A2:proto:instance}{{2.2.2}{26}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2.3}Initialize methods}{28}} \newlabel{subsection:A2:proto:initial}{{2.2.3}{28}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2.4}Methods used in the $QR$ factorization}{28}} \newlabel{subsection:A2:proto:QR}{{2.2.4}{28}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2.5}Norm methods}{29}} \newlabel{subsection:A2:proto:norms}{{2.2.5}{29}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2.6}Sort methods}{30}} \newlabel{subsection:A2:proto:sort}{{2.2.6}{30}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2.7}Utility methods}{30}} \newlabel{subsection:A2:proto:utilities}{{2.2.7}{30}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2.8}IO methods}{33}} \newlabel{subsection:A2:proto:IO}{{2.2.8}{33}} \@writefile{toc}{\contentsline {section}{\numberline {2.3}Driver programs for the {\tt A2 object}}{34}} \newlabel{section:A2:drivers}{{2.3}{34}} \@writefile{toc}{\contentsline {chapter}{\numberline {3}{\tt Coords}: Coordinates Object}{36}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {3.1}Data Structure}{36}} \@writefile{toc}{\contentsline {section}{\numberline {3.2}Prototypes and descriptions of {\tt Coords} methods}{36}} \newlabel{section:Coords:proto}{{3.2}{36}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.2.1}Basic methods}{36}} \newlabel{subsection:Coords:proto:basics}{{3.2.1}{36}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.2.2}Initializer methods}{37}} \newlabel{subsection:Coords:proto:initializers}{{3.2.2}{37}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.2.3}Utility methods}{38}} \newlabel{subsection:Coords:proto:utilities}{{3.2.3}{38}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.2.4}IO methods}{38}} \newlabel{subsection:Coords:proto:IO}{{3.2.4}{38}} \@writefile{toc}{\contentsline {section}{\numberline {3.3}Driver programs for the {\tt Coords} object}{39}} \newlabel{section:Coords:drivers}{{3.3}{39}} \@writefile{toc}{\contentsline {chapter}{\numberline {4}{\tt DV}: Double Vector Object}{41}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {4.1}Data Structure}{41}} \newlabel{section:DV:dataStructure}{{4.1}{41}} \@writefile{toc}{\contentsline {section}{\numberline {4.2}Prototypes and descriptions of {\tt DV} methods}{42}} \newlabel{section:DV:proto}{{4.2}{42}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.2.1}Basic methods}{42}} \newlabel{subsection:DV:proto:basics}{{4.2.1}{42}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.2.2}Instance methods}{42}} \newlabel{subsection:DV:proto:Instance}{{4.2.2}{42}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.2.3}Initializer methods}{43}} \newlabel{subsection:DV:proto:initializers}{{4.2.3}{43}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.2.4}Utility methods}{44}} \newlabel{subsection:DV:proto:utilities}{{4.2.4}{44}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.2.5}IO methods}{45}} \newlabel{subsection:DV:proto:IO}{{4.2.5}{45}} \@writefile{toc}{\contentsline {section}{\numberline {4.3}Driver programs for the {\tt DV object}}{47}} \newlabel{section:DV:drivers}{{4.3}{47}} \citation{and90-random} \@writefile{toc}{\contentsline {chapter}{\numberline {5}{\tt Drand}: \penalty -\@M Simple Random Number Generator}{48}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {5.1}Data Structure}{48}} \newlabel{section:Drand:dataStructure}{{5.1}{48}} \@writefile{toc}{\contentsline {section}{\numberline {5.2}Prototypes and descriptions of {\tt Drand} methods}{48}} \newlabel{section:Drand:proto}{{5.2}{48}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.2.1}Basic methods}{49}} \newlabel{subsection:Drand:proto:basics}{{5.2.1}{49}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.2.2}Initializer methods}{49}} \newlabel{subsection:Drand:proto:initializers}{{5.2.2}{49}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.2.3}Utility methods}{50}} \newlabel{subsection:Drand:proto:utilities}{{5.2.3}{50}} \@writefile{toc}{\contentsline {section}{\numberline {5.3}Driver programs for the {\tt Drand} object}{50}} \newlabel{section:Drand:drivers}{{5.3}{50}} \@writefile{toc}{\contentsline {chapter}{\numberline {6}{\tt I2Ohash}: Two Key Hash Table}{52}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {6.1}Data Structure}{52}} \newlabel{section:I2Ohash:dataStructure}{{6.1}{52}} \@writefile{toc}{\contentsline {section}{\numberline {6.2}Prototypes and descriptions of {\tt I2Ohash} methods}{53}} \newlabel{section:I2Ohash:proto}{{6.2}{53}} \@writefile{toc}{\contentsline {subsection}{\numberline {6.2.1}Basic methods}{53}} \newlabel{subsection:I2Ohash:proto:basics}{{6.2.1}{53}} \@writefile{toc}{\contentsline {subsection}{\numberline {6.2.2}Initializer methods}{53}} \newlabel{subsection:I2Ohash:proto:initializers}{{6.2.2}{53}} \@writefile{toc}{\contentsline {subsection}{\numberline {6.2.3}Utility methods}{54}} \newlabel{subsection:I2Ohash:proto:utilities}{{6.2.3}{54}} \@writefile{toc}{\contentsline {subsection}{\numberline {6.2.4}IO methods}{54}} \newlabel{subsection:I2Ohash:proto:IO}{{6.2.4}{54}} \@writefile{toc}{\contentsline {section}{\numberline {6.3}Driver programs for the {\tt I2Ohash object}}{54}} \newlabel{section:I2Ohash:drivers}{{6.3}{54}} \@writefile{toc}{\contentsline {chapter}{\numberline {7}{\tt IIheap}: (Key, Value) Heap}{56}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {7.1}Data Structure}{56}} \newlabel{section:IIheap:dataStructure}{{7.1}{56}} \@writefile{toc}{\contentsline {section}{\numberline {7.2}Prototypes and descriptions of {\tt IIheap} methods}{56}} \newlabel{section:IIheap:proto}{{7.2}{56}} \@writefile{toc}{\contentsline {subsection}{\numberline {7.2.1}Basic methods}{56}} \newlabel{subsection:IIheap:proto:basics}{{7.2.1}{56}} \@writefile{toc}{\contentsline {subsection}{\numberline {7.2.2}Initializer methods}{57}} \newlabel{subsection:IIheap:proto:initializers}{{7.2.2}{57}} \@writefile{toc}{\contentsline {subsection}{\numberline {7.2.3}Utility methods}{57}} \newlabel{subsection:IIheap:proto:utilities}{{7.2.3}{57}} \@writefile{toc}{\contentsline {chapter}{\numberline {8}{\tt IV}: Integer Vector Object}{58}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {8.1}Data Structure}{58}} \newlabel{section:IV:dataStructure}{{8.1}{58}} \@writefile{toc}{\contentsline {section}{\numberline {8.2}Prototypes and descriptions of {\tt IV} methods}{59}} \newlabel{section:IV:proto}{{8.2}{59}} \@writefile{toc}{\contentsline {subsection}{\numberline {8.2.1}Basic methods}{59}} \newlabel{subsection:IV:proto:basics}{{8.2.1}{59}} \@writefile{toc}{\contentsline {subsection}{\numberline {8.2.2}Instance methods}{59}} \newlabel{subsection:IV:proto:Instance}{{8.2.2}{59}} \@writefile{toc}{\contentsline {subsection}{\numberline {8.2.3}Initializer methods}{60}} \newlabel{subsection:IV:proto:initializers}{{8.2.3}{60}} \@writefile{toc}{\contentsline {subsection}{\numberline {8.2.4}Utility methods}{61}} \newlabel{subsection:IV:proto:utilities}{{8.2.4}{61}} \@writefile{toc}{\contentsline {subsection}{\numberline {8.2.5}IO methods}{63}} \newlabel{subsection:IV:proto:IO}{{8.2.5}{63}} \@writefile{toc}{\contentsline {section}{\numberline {8.3}Driver programs for the {\tt IV object}}{65}} \newlabel{section:IV:drivers}{{8.3}{65}} \@writefile{toc}{\contentsline {chapter}{\numberline {9}{\tt IVL}: Integer Vector List Object}{66}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {9.1}Data Structure}{66}} \newlabel{section:IVL:dataStructure}{{9.1}{66}} \@writefile{toc}{\contentsline {section}{\numberline {9.2}Prototypes and descriptions of {\tt IVL} methods}{67}} \newlabel{section:IVL:proto}{{9.2}{67}} \@writefile{toc}{\contentsline {subsection}{\numberline {9.2.1}Basic methods}{67}} \newlabel{subsection:IVL:proto:basics}{{9.2.1}{67}} \@writefile{toc}{\contentsline {subsection}{\numberline {9.2.2}Instance methods}{68}} \newlabel{subsection:IVL:proto:instance}{{9.2.2}{68}} \@writefile{toc}{\contentsline {subsection}{\numberline {9.2.3}Initialization and resizing methods}{68}} \newlabel{subsection:IVL:proto:initializers}{{9.2.3}{68}} \@writefile{toc}{\contentsline {subsection}{\numberline {9.2.4}List manipulation methods}{69}} \newlabel{subsection:IVL:proto:listmanip}{{9.2.4}{69}} \citation{ash95-compressed-graphs} \@writefile{toc}{\contentsline {subsection}{\numberline {9.2.5}Utility methods}{70}} \newlabel{subsection:IVL:proto:utilities}{{9.2.5}{70}} \@writefile{toc}{\contentsline {subsection}{\numberline {9.2.6}Miscellaneous methods}{71}} \newlabel{subsection:IVL:proto:miscellaneous}{{9.2.6}{71}} \@writefile{toc}{\contentsline {subsection}{\numberline {9.2.7}IO methods}{72}} \newlabel{subsection:IVL:proto:IO}{{9.2.7}{72}} \@writefile{toc}{\contentsline {section}{\numberline {9.3}Driver programs for the {\tt IVL} object}{73}} \newlabel{section:IVL:drivers}{{9.3}{73}} \@writefile{toc}{\contentsline {chapter}{\numberline {10}{\tt Ideq}: Integer Dequeue}{74}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {10.1}Data Structure}{74}} \newlabel{section:Ideq:dataStructure}{{10.1}{74}} \@writefile{toc}{\contentsline {section}{\numberline {10.2}Prototypes and descriptions of {\tt Ideq} methods}{74}} \newlabel{section:Ideq:proto}{{10.2}{74}} \@writefile{toc}{\contentsline {subsection}{\numberline {10.2.1}Basic methods}{74}} \newlabel{subsection:Ideq:proto:basics}{{10.2.1}{74}} \@writefile{toc}{\contentsline {subsection}{\numberline {10.2.2}Initializer methods}{75}} \newlabel{subsection:Ideq:proto:initializers}{{10.2.2}{75}} \@writefile{toc}{\contentsline {subsection}{\numberline {10.2.3}Utility methods}{75}} \newlabel{subsection:Ideq:proto:utilities}{{10.2.3}{75}} \@writefile{toc}{\contentsline {subsection}{\numberline {10.2.4}IO methods}{76}} \newlabel{subsection:Ideq:proto:IO}{{10.2.4}{76}} \@writefile{toc}{\contentsline {chapter}{\numberline {11}{\tt Lock}: Mutual Exclusion Lock object}{77}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:Lock}{{11}{77}} \@writefile{toc}{\contentsline {section}{\numberline {11.1}Data Structure}{77}} \newlabel{section:Lock:dataStructure}{{11.1}{77}} \@writefile{toc}{\contentsline {section}{\numberline {11.2}Prototypes and descriptions of {\tt Lock} methods}{77}} \newlabel{section:Lock:proto}{{11.2}{77}} \@writefile{toc}{\contentsline {subsection}{\numberline {11.2.1}Basic methods}{77}} \newlabel{subsection:Lock:proto:basics}{{11.2.1}{77}} \@writefile{toc}{\contentsline {subsection}{\numberline {11.2.2}Initializer method}{78}} \newlabel{subsection:Lock:proto:initializers}{{11.2.2}{78}} \@writefile{toc}{\contentsline {subsection}{\numberline {11.2.3}Utility methods}{78}} \newlabel{subsection:Lock:proto:Utility}{{11.2.3}{78}} \@writefile{toc}{\contentsline {chapter}{\numberline {12}{\tt Perm}: Permutation Object}{79}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {12.1}Data Structure}{79}} \newlabel{section:Perm:dataStructure}{{12.1}{79}} \@writefile{toc}{\contentsline {section}{\numberline {12.2}Prototypes and descriptions of {\tt Perm} methods}{79}} \newlabel{section:Perm:proto}{{12.2}{79}} \@writefile{toc}{\contentsline {subsection}{\numberline {12.2.1}Basic methods}{79}} \newlabel{subsection:Perm:proto:basics}{{12.2.1}{79}} \@writefile{toc}{\contentsline {subsection}{\numberline {12.2.2}Initializer methods}{80}} \newlabel{subsection:Perm:proto:initializers}{{12.2.2}{80}} \@writefile{toc}{\contentsline {subsection}{\numberline {12.2.3}Utility methods}{80}} \newlabel{subsection:Perm:proto:utilities}{{12.2.3}{80}} \@writefile{toc}{\contentsline {subsection}{\numberline {12.2.4}IO methods}{81}} \newlabel{subsection:Perm:proto:IO}{{12.2.4}{81}} \citation{bent93-sort} \@writefile{toc}{\contentsline {chapter}{\numberline {13}{\tt Utilities } directory }{83}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:Utilities}{{13}{83}} \@writefile{toc}{\contentsline {section}{\numberline {13.1}Data Structures}{83}} \newlabel{section:Utilities:dataStructure}{{13.1}{83}} \@writefile{toc}{\contentsline {section}{\numberline {13.2}Prototypes and descriptions of {\tt Utilities} methods}{83}} \newlabel{section:Utilities:proto}{{13.2}{83}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.1}{\tt CV} : {\tt char} vector methods}{84}} \newlabel{subsection:Utilities:proto:CV}{{13.2.1}{84}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.2}{\tt DV} : {\tt double} vector methods}{84}} \newlabel{subsection:Utilities:proto:DV}{{13.2.2}{84}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.3}{\tt ZV} : {\tt double complex } vector methods}{90}} \newlabel{subsection:Utilities:proto:ZV}{{13.2.3}{90}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.4}{\tt IV} : {\tt int} vector methods}{96}} \newlabel{subsection:Utilities:proto:IV}{{13.2.4}{96}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.5}{\tt FV} : {\tt float} vector methods}{98}} \newlabel{subsection:Utilities:proto:FV}{{13.2.5}{98}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.6}{\tt PCV} : {\tt char *} vector methods}{101}} \newlabel{subsection:Utilities:proto:PCV}{{13.2.6}{101}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.7}{\tt PDV} : {\tt double *} vector methods}{101}} \newlabel{subsection:Utilities:proto:PDV}{{13.2.7}{101}} \@writefile{toc}{\contentsline {subsubsection}{{\tt PIV} : {\tt int *} vector methods}{101}} \newlabel{subsubsection:Utilities:proto:PIV}{{13.2.7}{101}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.8}{\tt PFV} : {\tt float *} vector methods}{102}} \newlabel{subsection:Utilities:proto:PFV}{{13.2.8}{102}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.9}Sorting routines}{102}} \newlabel{subsection:Utilities:proto:sort}{{13.2.9}{102}} \@writefile{toc}{\contentsline {subsubsection}{Validation routines}{102}} \newlabel{subsubsection:Utilities:proto:sort:validate}{{13.2.9}{102}} \@writefile{toc}{\contentsline {subsubsection}{Insert sort routines}{102}} \newlabel{subsubsection:Utilities:proto:sort:insert}{{13.2.9}{102}} \@writefile{toc}{\contentsline {subsubsection}{Quicksort routines}{103}} \newlabel{subsubsection:Utilities:proto:sort:quicksort}{{13.2.9}{103}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.10}Sort and compress routines}{104}} \newlabel{subsection:Utilities:proto:sortAndCompress}{{13.2.10}{104}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.11}{\tt IP} : {\tt (int, pointer)} singly linked-list methods}{105}} \newlabel{subsection:Utilities:proto:IP}{{13.2.11}{105}} \@writefile{toc}{\contentsline {subsection}{\numberline {13.2.12}{\tt I2OP} : {\tt (int, int, void*, pointer)} singly linked-list methods}{106}} \newlabel{subsection:Utilities:proto:I2OP}{{13.2.12}{106}} \@writefile{toc}{\contentsline {section}{\numberline {13.3}Driver programs }{107}} \newlabel{section:Utilities:drivers}{{13.3}{107}} \@writefile{toc}{\contentsline {chapter}{\numberline {14}{\tt ZV}: Double Complex Vector Object}{108}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {14.1}Data Structure}{108}} \newlabel{section:ZV:dataStructure}{{14.1}{108}} \@writefile{toc}{\contentsline {section}{\numberline {14.2}Prototypes and descriptions of {\tt ZV} methods}{109}} \newlabel{section:ZV:proto}{{14.2}{109}} \@writefile{toc}{\contentsline {subsection}{\numberline {14.2.1}Basic methods}{109}} \newlabel{subsection:ZV:proto:basics}{{14.2.1}{109}} \@writefile{toc}{\contentsline {subsection}{\numberline {14.2.2}Instance methods}{109}} \newlabel{subsection:ZV:proto:Instance}{{14.2.2}{109}} \@writefile{toc}{\contentsline {subsection}{\numberline {14.2.3}Initializer methods}{110}} \newlabel{subsection:ZV:proto:initializers}{{14.2.3}{110}} \@writefile{toc}{\contentsline {subsection}{\numberline {14.2.4}Utility methods}{111}} \newlabel{subsection:ZV:proto:utilities}{{14.2.4}{111}} \@writefile{toc}{\contentsline {subsection}{\numberline {14.2.5}IO methods}{112}} \newlabel{subsection:ZV:proto:IO}{{14.2.5}{112}} \@writefile{toc}{\contentsline {section}{\numberline {14.3}Driver programs for the {\tt ZV object}}{113}} \newlabel{section:ZV:drivers}{{14.3}{113}} \@writefile{toc}{\contentsline {part}{\uppercase {iii}\hspace {1em}Ordering Objects and Methods}{115}} \@writefile{toc}{\contentsline {chapter}{\numberline {15}{\tt BKL}: Block Kernighan-Lin Object}{117}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:BKL}{{15}{117}} \@writefile{toc}{\contentsline {section}{\numberline {15.1}Data Structure}{117}} \newlabel{section:BKL:dataStructure}{{15.1}{117}} \@writefile{toc}{\contentsline {section}{\numberline {15.2}Prototypes and descriptions of {\tt BKL} methods}{118}} \newlabel{section:BKL:proto}{{15.2}{118}} \@writefile{toc}{\contentsline {section}{\numberline {15.3}Basic methods}{118}} \newlabel{subsection:BKL:proto:basics}{{15.3}{118}} \@writefile{toc}{\contentsline {subsection}{\numberline {15.3.1}Initializer methods}{118}} \newlabel{subsection:BKL:proto:initializers}{{15.3.1}{118}} \@writefile{toc}{\contentsline {subsection}{\numberline {15.3.2}Utility methods}{119}} \newlabel{subsection:BKL:proto:utilities}{{15.3.2}{119}} \@writefile{toc}{\contentsline {subsection}{\numberline {15.3.3}Partition evaluation methods}{120}} \newlabel{subsection:BKL:proto:evaluation}{{15.3.3}{120}} \@writefile{toc}{\contentsline {subsection}{\numberline {15.3.4}Partition improvement methods}{120}} \newlabel{subsection:BKL:proto:improve}{{15.3.4}{120}} \citation{ash97-DDSEP} \citation{ash98-maxflow} \@writefile{toc}{\contentsline {chapter}{\numberline {16}{\tt BPG}: Bipartite Graph Object}{122}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:BPG}{{16}{122}} \citation{ash98-maxflow} \@writefile{toc}{\contentsline {section}{\numberline {16.1}Data Structure}{124}} \newlabel{section:BPG:dataStructure}{{16.1}{124}} \@writefile{toc}{\contentsline {section}{\numberline {16.2}Prototypes and descriptions of {\tt BPG} methods}{124}} \newlabel{section:BPG:proto}{{16.2}{124}} \@writefile{toc}{\contentsline {subsection}{\numberline {16.2.1}Basic methods}{124}} \newlabel{subsection:BPG:proto:basics}{{16.2.1}{124}} \@writefile{toc}{\contentsline {subsection}{\numberline {16.2.2}Initializer methods}{125}} \newlabel{subsection:BPG:proto:initializers}{{16.2.2}{125}} \@writefile{toc}{\contentsline {subsection}{\numberline {16.2.3}Generate induced graphs}{125}} \newlabel{subsection:BPG:proto:induced-graphs}{{16.2.3}{125}} \@writefile{toc}{\contentsline {subsection}{\numberline {16.2.4}Utility methods}{125}} \newlabel{subsection:BPG:proto:utilities}{{16.2.4}{125}} \@writefile{toc}{\contentsline {subsection}{\numberline {16.2.5}Dulmage-Mendelsohn decomposition method}{126}} \newlabel{subsection:BPG:proto:DM}{{16.2.5}{126}} \@writefile{toc}{\contentsline {subsection}{\numberline {16.2.6}IO methods}{126}} \newlabel{subsection:BPG:proto:IO}{{16.2.6}{126}} \@writefile{toc}{\contentsline {section}{\numberline {16.3}Driver programs for the {\tt BPG} object}{127}} \newlabel{section:BPG:drivers}{{16.3}{127}} \@writefile{toc}{\contentsline {chapter}{\numberline {17}{\tt DSTree}: \penalty -\@M A Domain/Separator Tree Object}{129}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:DSTree:intro}{{17}{129}} \@writefile{toc}{\contentsline {section}{\numberline {17.1}Data Structure}{129}} \newlabel{section:DSTree:dataStructure}{{17.1}{129}} \@writefile{toc}{\contentsline {section}{\numberline {17.2}Prototypes and descriptions of {\tt DSTree} methods}{129}} \newlabel{section:DSTree:proto}{{17.2}{129}} \@writefile{toc}{\contentsline {subsection}{\numberline {17.2.1}Basic methods}{130}} \newlabel{subsection:DSTree:proto:basics}{{17.2.1}{130}} \@writefile{toc}{\contentsline {subsection}{\numberline {17.2.2}Instance methods}{130}} \newlabel{subsection:DSTree:proto:instance}{{17.2.2}{130}} \@writefile{toc}{\contentsline {subsection}{\numberline {17.2.3}Initializer methods}{130}} \newlabel{subsection:DSTree:proto:initializers}{{17.2.3}{130}} \@writefile{toc}{\contentsline {subsection}{\numberline {17.2.4}Stage methods}{131}} \newlabel{subsection:DSTree:proto:stages}{{17.2.4}{131}} \@writefile{toc}{\contentsline {subsection}{\numberline {17.2.5}Utility methods}{132}} \newlabel{subsection:DSTree:proto:utilities}{{17.2.5}{132}} \@writefile{toc}{\contentsline {subsection}{\numberline {17.2.6}IO methods}{132}} \newlabel{subsection:DSTree:proto:IO}{{17.2.6}{132}} \@writefile{toc}{\contentsline {section}{\numberline {17.3}Driver programs for the {\tt DSTree} object}{133}} \newlabel{section:DSTree:drivers}{{17.3}{133}} \@writefile{toc}{\contentsline {chapter}{\numberline {18}{\tt EGraph}: Element Graph Object}{135}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {18.1}Data Structure}{135}} \@writefile{toc}{\contentsline {section}{\numberline {18.2}Prototypes and descriptions of {\tt EGraph} methods}{135}} \newlabel{section:EGraph:proto}{{18.2}{135}} \@writefile{toc}{\contentsline {subsection}{\numberline {18.2.1}Basic methods}{136}} \newlabel{subsection:EGraph:proto:basics}{{18.2.1}{136}} \@writefile{toc}{\contentsline {subsection}{\numberline {18.2.2}Initializer methods}{136}} \newlabel{subsection:EGraph:proto:initializers}{{18.2.2}{136}} \@writefile{toc}{\contentsline {subsection}{\numberline {18.2.3}Utility methods}{136}} \newlabel{subsection:EGraph:proto:utilities}{{18.2.3}{136}} \@writefile{toc}{\contentsline {subsection}{\numberline {18.2.4}IO methods}{137}} \newlabel{subsection:EGraph:proto:IO}{{18.2.4}{137}} \@writefile{toc}{\contentsline {section}{\numberline {18.3}Driver programs for the {\tt EGraph} object}{138}} \newlabel{section:EGraph:drivers}{{18.3}{138}} \@writefile{toc}{\contentsline {chapter}{\numberline {19}{\tt ETree}: Elimination and Front Trees}{140}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:ETree}{{19}{140}} \@writefile{toc}{\contentsline {section}{\numberline {19.1}Data Structure}{140}} \@writefile{toc}{\contentsline {section}{\numberline {19.2}Prototypes and descriptions of {\tt ETree} methods}{141}} \newlabel{section:ETree:proto}{{19.2}{141}} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.1}Basic methods}{141}} \newlabel{subsection:ETree:proto:basics}{{19.2.1}{141}} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.2}Instance methods}{141}} \newlabel{subsection:ETree:proto:instance}{{19.2.2}{141}} \citation{liu90-etree} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.3}Initializer methods}{143}} \newlabel{subsection:ETree:proto:initializers}{{19.2.3}{143}} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.4}Utility methods}{144}} \newlabel{subsection:ETree:proto:utilities}{{19.2.4}{144}} \citation{liu91-generalizedEnvelope} \citation{ash89-relaxed} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.5}Metrics methods}{146}} \newlabel{subsection:ETree:proto:metrics}{{19.2.5}{146}} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.6}Compression methods}{146}} \newlabel{subsection:ETree:proto:compression}{{19.2.6}{146}} \citation{liu85-mfstorage} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.7}Justification methods}{147}} \newlabel{subsection:ETree:proto:justify}{{19.2.7}{147}} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.8}Permutation methods}{148}} \newlabel{subsection:ETree:proto:permutation}{{19.2.8}{148}} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.9}Multisector methods}{148}} \newlabel{subsection:ETree:proto:multisector}{{19.2.9}{148}} \citation{duf83-multifrontal} \citation{ash89-relaxed} \citation{ash89-relaxed} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.10}Transformation methods}{150}} \newlabel{subsection:ETree:proto:transformation}{{19.2.10}{150}} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.11}Parallel factorization map methods}{151}} \newlabel{subsection:ETree:proto:map}{{19.2.11}{151}} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.12}Storage profile methods}{152}} \newlabel{subsection:ETree:proto:storage}{{19.2.12}{152}} \@writefile{toc}{\contentsline {subsection}{\numberline {19.2.13}IO methods}{153}} \newlabel{subsection:ETree:proto:IO}{{19.2.13}{153}} \@writefile{toc}{\contentsline {section}{\numberline {19.3}Driver programs for the {\tt ETree} object}{154}} \newlabel{section:ETree:drivers}{{19.3}{154}} \@writefile{lof}{\contentsline {figure}{\numberline {19.1}{\ignorespaces {\sc GRD7x7}: Working storage for the forward sparse factorization of the nested dissection ordering. On the left is the storage required to factor ${\mathaccent "0362\relax J}$ and its update matrix. On the right is the storage required to factor $J$ and all of its ancestors. Both plots have the same scale.}}{158}} \newlabel{fig-GRD7x7-FStree}{{19.1}{158}} \@writefile{lof}{\contentsline {figure}{\numberline {19.2}{\ignorespaces {\sc GRD7x7x7}: Four tree plots for a $7 \times 7 \times 7$ grid matrix ordered using nested dissection. The top left tree measure number of original matrix entries in a front. The top right tree measure number of factor matrix entries in a front. The bottom left tree measure number of factor operations in a front for a forward looking factorization, e.g., forward sparse. The bottom right tree measure number of factor operations in a front for a backward looking factorization, e.g., general sparse.}}{162}} \newlabel{fig-GRD7x7x7-metrics}{{19.2}{162}} \citation{ash89-relaxed} \citation{duf83-multifrontal} \citation{ash97-DDSEP} \citation{ash98-maxflow} \@writefile{toc}{\contentsline {chapter}{\numberline {20}{\tt GPart}: Graph Partitioning Object}{165}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:GPart:intro}{{20}{165}} \@writefile{toc}{\contentsline {section}{\numberline {20.1}Data Structures}{166}} \newlabel{section:GPart:dataStructure}{{20.1}{166}} \@writefile{toc}{\contentsline {section}{\numberline {20.2}Prototypes and descriptions of {\tt GPart} methods}{167}} \newlabel{section:GPart:proto}{{20.2}{167}} \@writefile{toc}{\contentsline {subsection}{\numberline {20.2.1}Basic methods}{167}} \newlabel{subsection:GPart:proto:basics}{{20.2.1}{167}} \@writefile{toc}{\contentsline {subsection}{\numberline {20.2.2}Initializer methods}{168}} \newlabel{subsection:GPart:proto:initializers}{{20.2.2}{168}} \@writefile{toc}{\contentsline {subsection}{\numberline {20.2.3}Utility methods}{168}} \newlabel{subsection:GPart:proto:utilities}{{20.2.3}{168}} \citation{ash97-DDSEP} \@writefile{toc}{\contentsline {subsection}{\numberline {20.2.4}Domain decomposition methods}{169}} \newlabel{subsection:GPart:proto:domain-decomposition}{{20.2.4}{169}} \@writefile{toc}{\contentsline {subsection}{\numberline {20.2.5}Methods to generate a 2-set partition}{170}} \newlabel{subsection:GPart:proto:2-set}{{20.2.5}{170}} \@writefile{toc}{\contentsline {subsection}{\numberline {20.2.6}Methods to improve a 2-set partition}{170}} \newlabel{subsection:GPart:proto:improve}{{20.2.6}{170}} \@writefile{toc}{\contentsline {subsection}{\numberline {20.2.7}Recursive Bisection method}{172}} \newlabel{subsection:GPart:proto:RB}{{20.2.7}{172}} \@writefile{toc}{\contentsline {subsection}{\numberline {20.2.8}{\tt DDsepInfo} methods}{172}} \newlabel{subsection:GPart:proto:DDsepInfo}{{20.2.8}{172}} \citation{ash97-DDSEP} \citation{ash97-DDSEP} \@writefile{toc}{\contentsline {section}{\numberline {20.3}Driver programs for the {\tt GPart} object}{173}} \newlabel{section:GPart:drivers}{{20.3}{173}} \citation{ash97-DDSEP} \citation{ash95-compressed-graphs} \citation{dam92-compressed} \@writefile{toc}{\contentsline {chapter}{\numberline {21}{\tt Graph}: A Graph object}{177}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:Graph}{{21}{177}} \@writefile{toc}{\contentsline {section}{\numberline {21.1}Data Structure}{178}} \newlabel{section:Graph:dataStructure}{{21.1}{178}} \@writefile{toc}{\contentsline {section}{\numberline {21.2}Prototypes and descriptions of {\tt Graph} methods}{178}} \newlabel{section:Graph:proto}{{21.2}{178}} \@writefile{toc}{\contentsline {subsection}{\numberline {21.2.1}Basic methods}{178}} \newlabel{subsection:Graph:proto:basics}{{21.2.1}{178}} \@writefile{toc}{\contentsline {subsection}{\numberline {21.2.2}Initializer methods}{179}} \newlabel{subsection:Graph:proto:initializers}{{21.2.2}{179}} \@writefile{toc}{\contentsline {subsection}{\numberline {21.2.3}Compress and Expand methods}{180}} \newlabel{subsection:Graph:proto:compress}{{21.2.3}{180}} \@writefile{toc}{\contentsline {subsection}{\numberline {21.2.4}Wirebasket domain decomposition ordering}{180}} \newlabel{subsection:Graph:proto:wirebasket}{{21.2.4}{180}} \@writefile{toc}{\contentsline {subsection}{\numberline {21.2.5}Utility methods}{181}} \newlabel{subsection:Graph:proto:utilities}{{21.2.5}{181}} \@writefile{toc}{\contentsline {subsection}{\numberline {21.2.6}IO methods}{182}} \newlabel{subsection:Graph:proto:IO}{{21.2.6}{182}} \@writefile{toc}{\contentsline {section}{\numberline {21.3}Driver programs for the {\tt Graph} object}{183}} \newlabel{section:Graph:drivers}{{21.3}{183}} \citation{ame96-amd} \citation{sparsematlab} \citation{ame96-amd} \citation{ng96-mindefIdaho} \citation{rot96-mindefIdaho} \citation{rot98-mindef} \@writefile{toc}{\contentsline {chapter}{\numberline {22}{\tt MSMD}: \penalty -\@M {\tt M}ulti-{\tt S}tage {\tt M}inimum {\tt D}egree Object}{187}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {22.1}Data Structure}{188}} \citation{ame96-amd} \citation{ame96-amd} \@writefile{toc}{\contentsline {subsection}{\numberline {22.1.1}{\tt MSMDinfo} : define your algorithm}{189}} \@writefile{toc}{\contentsline {subsection}{\numberline {22.1.2}{\tt MSMD} : driver object}{190}} \@writefile{toc}{\contentsline {subsection}{\numberline {22.1.3}{\tt MSMDstageInfo} : statistics object for a stage of the elimination}{190}} \@writefile{toc}{\contentsline {subsection}{\numberline {22.1.4}{\tt MSMDvtx} : vertex object}{191}} \@writefile{toc}{\contentsline {section}{\numberline {22.2}Prototypes and descriptions of {\tt MSMDinfo} methods}{191}} \newlabel{section:MSMDinfo:proto}{{22.2}{191}} \@writefile{toc}{\contentsline {subsection}{\numberline {22.2.1}Basic methods}{191}} \newlabel{subsection:MSMDinfo:proto:basics}{{22.2.1}{191}} \@writefile{toc}{\contentsline {subsection}{\numberline {22.2.2}Utility methods}{192}} \newlabel{subsection:MSMDinfo:proto:utility}{{22.2.2}{192}} \@writefile{toc}{\contentsline {section}{\numberline {22.3}Prototypes and descriptions of {\tt MSMD} methods}{192}} \newlabel{section:MSMD:proto}{{22.3}{192}} \@writefile{toc}{\contentsline {subsection}{\numberline {22.3.1}Basic methods --- public}{192}} \newlabel{subsection:MSMD:proto:basics}{{22.3.1}{192}} \@writefile{toc}{\contentsline {subsection}{\numberline {22.3.2}Initialization methods --- public}{193}} \newlabel{subsection:MSMD:proto:init}{{22.3.2}{193}} \@writefile{toc}{\contentsline {subsection}{\numberline {22.3.3}Ordering methods --- public}{193}} \newlabel{subsection:MSMD:proto:order}{{22.3.3}{193}} \@writefile{toc}{\contentsline {subsection}{\numberline {22.3.4}Extraction methods --- public}{193}} \newlabel{subsection:MSMD:proto:extraction}{{22.3.4}{193}} \@writefile{toc}{\contentsline {subsection}{\numberline {22.3.5}Internal methods --- private}{194}} \newlabel{subsection:MSMD:proto:private}{{22.3.5}{194}} \@writefile{toc}{\contentsline {section}{\numberline {22.4}Prototypes and descriptions of {\tt MSMDvtx} methods}{195}} \newlabel{section:MSMDvtx:proto}{{22.4}{195}} \@writefile{toc}{\contentsline {section}{\numberline {22.5}Driver programs for the {\tt MSMD} object}{195}} \newlabel{section:MSMD:drivers}{{22.5}{195}} \@writefile{toc}{\contentsline {chapter}{\numberline {23}{\tt Network}: Simple Max-flow solver}{198}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {23.1}Data Structure}{199}} \@writefile{toc}{\contentsline {section}{\numberline {23.2}Prototypes and descriptions of {\tt Network} methods}{200}} \newlabel{section:Network:proto}{{23.2}{200}} \@writefile{toc}{\contentsline {subsection}{\numberline {23.2.1}Basic methods}{200}} \newlabel{subsection:Network:proto:basics}{{23.2.1}{200}} \@writefile{toc}{\contentsline {subsection}{\numberline {23.2.2}Initializer methods}{201}} \newlabel{subsection:Network:proto:initializers}{{23.2.2}{201}} \@writefile{toc}{\contentsline {subsection}{\numberline {23.2.3}Utility methods}{201}} \newlabel{subsection:Network:proto:utilities}{{23.2.3}{201}} \@writefile{toc}{\contentsline {subsection}{\numberline {23.2.4}IO methods}{202}} \newlabel{subsection:Network:proto:IO}{{23.2.4}{202}} \@writefile{toc}{\contentsline {chapter}{\numberline {24}{\tt SolveMap}: Forward and Backsolve Map}{203}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {24.1}Data Structure}{203}} \newlabel{section:SolveMap:dataStructure}{{24.1}{203}} \@writefile{toc}{\contentsline {section}{\numberline {24.2}Prototypes and descriptions of {\tt SolveMap} methods}{204}} \newlabel{section:SolveMap:proto}{{24.2}{204}} \@writefile{toc}{\contentsline {subsection}{\numberline {24.2.1}Basic methods}{204}} \newlabel{subsection:SolveMap:proto:basics}{{24.2.1}{204}} \@writefile{toc}{\contentsline {subsection}{\numberline {24.2.2}Instance methods}{204}} \newlabel{subsection:SolveMap:proto:instance}{{24.2.2}{204}} \@writefile{toc}{\contentsline {subsection}{\numberline {24.2.3}Initialization method}{205}} \newlabel{subsection:SolveMap:proto:init}{{24.2.3}{205}} \@writefile{toc}{\contentsline {subsection}{\numberline {24.2.4}Map creation methods}{206}} \newlabel{subsection:SolveMap:proto:maps}{{24.2.4}{206}} \@writefile{toc}{\contentsline {subsection}{\numberline {24.2.5}Solve setup methods}{206}} \newlabel{subsection:SolveMap:proto:setup}{{24.2.5}{206}} \@writefile{toc}{\contentsline {subsection}{\numberline {24.2.6}Utility methods}{206}} \newlabel{subsection:SolveMap:proto:utilities}{{24.2.6}{206}} \@writefile{toc}{\contentsline {subsection}{\numberline {24.2.7}IO methods}{207}} \newlabel{subsection:SolveMap:proto:IO}{{24.2.7}{207}} \citation{liu90-etree} \citation{duf83-multifrontal} \citation{eis76-elementModel} \@writefile{toc}{\contentsline {chapter}{\numberline {25}{\tt Tree}: A Tree Object}{209}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {25.1}Data Structure}{209}} \newlabel{section:Tree:dataStructure}{{25.1}{209}} \@writefile{toc}{\contentsline {section}{\numberline {25.2}Prototypes and descriptions of {\tt Tree} methods}{209}} \newlabel{section:Tree:proto}{{25.2}{209}} \@writefile{toc}{\contentsline {subsection}{\numberline {25.2.1}Basic methods}{210}} \newlabel{subsection:Tree:proto:basics}{{25.2.1}{210}} \@writefile{toc}{\contentsline {subsection}{\numberline {25.2.2}Instance methods}{210}} \newlabel{subsection:Tree:proto:instance}{{25.2.2}{210}} \@writefile{toc}{\contentsline {subsection}{\numberline {25.2.3}Initializer methods}{211}} \newlabel{subsection:Tree:proto:initializers}{{25.2.3}{211}} \@writefile{toc}{\contentsline {subsection}{\numberline {25.2.4}Utility methods}{211}} \newlabel{subsection:Tree:proto:utilities}{{25.2.4}{211}} \citation{liu91-generalizedEnvelope} \@writefile{toc}{\contentsline {subsection}{\numberline {25.2.5}Metrics methods}{213}} \newlabel{subsection:Tree:proto:metrics}{{25.2.5}{213}} \@writefile{toc}{\contentsline {subsection}{\numberline {25.2.6}Compression methods}{214}} \newlabel{subsection:Tree:proto:compression}{{25.2.6}{214}} \@writefile{toc}{\contentsline {subsection}{\numberline {25.2.7}Justification methods}{214}} \newlabel{subsection:Tree:proto:justify}{{25.2.7}{214}} \@writefile{toc}{\contentsline {subsection}{\numberline {25.2.8}Permutation methods}{214}} \newlabel{subsection:Tree:proto:permutation}{{25.2.8}{214}} \@writefile{toc}{\contentsline {subsection}{\numberline {25.2.9}Drawing method}{215}} \newlabel{subsection:Tree:proto:drawing}{{25.2.9}{215}} \@writefile{toc}{\contentsline {subsection}{\numberline {25.2.10}IO methods}{216}} \newlabel{subsection:Tree:proto:IO}{{25.2.10}{216}} \@writefile{toc}{\contentsline {section}{\numberline {25.3}Driver programs for the {\tt Tree} object}{217}} \newlabel{section:Tree:drivers}{{25.3}{217}} \@writefile{lof}{\contentsline {figure}{\numberline {25.1}{\ignorespaces {\sc R2D100}: domain/separator tree. On the left {\tt heightflag = 'H'} and {\tt coordflag = 'C'}, on the right {\tt heightflag = 'D'} and {\tt coordflag = 'C'}.}}{218}} \newlabel{fig-R2D100-tree-HC}{{25.1}{218}} \@writefile{lof}{\contentsline {figure}{\numberline {25.2}{\ignorespaces {\sc R2D100}: domain/separator tree. On the left {\tt heightflag = 'H'} and {\tt coordflag = 'P'}, on the right {\tt heightflag = 'D'} and {\tt coordflag = 'P'}.}}{218}} \newlabel{fig-R2D100-tree-HP}{{25.2}{218}} \@writefile{toc}{\contentsline {part}{\uppercase {iv}\hspace {1em}Numeric Objects and Methods}{219}} \@writefile{toc}{\contentsline {chapter}{\numberline {26}{\tt Chv}: Block chevron}{221}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {26.1}Data Structure}{223}} \newlabel{section:Chv:dataStructure}{{26.1}{223}} \@writefile{toc}{\contentsline {section}{\numberline {26.2}Prototypes and descriptions of {\tt Chv} methods}{223}} \newlabel{section:Chv:proto}{{26.2}{223}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.1}Basic methods}{224}} \newlabel{subsection:Chv:proto:basics}{{26.2.1}{224}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.2}Instance methods}{224}} \newlabel{subsection:Chv:proto:instance}{{26.2.2}{224}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.3}Initialization methods}{226}} \newlabel{subsection:Chv:proto:initial}{{26.2.3}{226}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.4}Search methods}{227}} \newlabel{subsection:Chv:proto:search}{{26.2.4}{227}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.5}Pivot methods}{228}} \newlabel{subsection:Chv:proto:pivot}{{26.2.5}{228}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.6}Update methods}{228}} \newlabel{subsection:Chv:proto:updates}{{26.2.6}{228}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.7}Assembly methods}{229}} \newlabel{subsection:Chv:proto:assembly}{{26.2.7}{229}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.8}Factorization methods}{229}} \newlabel{subsection:Chv:proto:factor}{{26.2.8}{229}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.9}Copy methods}{230}} \newlabel{subsection:Chv:proto:copy}{{26.2.9}{230}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.10}Swap methods}{232}} \newlabel{subsection:Chv:proto:swap}{{26.2.10}{232}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.11}Utility methods}{233}} \newlabel{subsection:Chv:proto:utilities}{{26.2.11}{233}} \@writefile{toc}{\contentsline {subsection}{\numberline {26.2.12}IO methods}{234}} \newlabel{subsection:Chv:proto:IO}{{26.2.12}{234}} \@writefile{toc}{\contentsline {section}{\numberline {26.3}Driver programs for the {\tt Chv object}}{235}} \newlabel{section:Chv:drivers}{{26.3}{235}} \@writefile{toc}{\contentsline {chapter}{\numberline {27}{\tt ChvList}: {\tt Chv} list object }{240}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {27.1}Data Structure}{241}} \newlabel{section:ChvList:dataStructure}{{27.1}{241}} \@writefile{toc}{\contentsline {section}{\numberline {27.2}Prototypes and descriptions of {\tt ChvList} methods}{241}} \newlabel{section:ChvList:proto}{{27.2}{241}} \@writefile{toc}{\contentsline {subsection}{\numberline {27.2.1}Basic methods}{241}} \newlabel{subsection:ChvList:proto:basics}{{27.2.1}{241}} \@writefile{toc}{\contentsline {subsection}{\numberline {27.2.2}Initialization methods}{242}} \newlabel{subsection:ChvList:proto:initial}{{27.2.2}{242}} \@writefile{toc}{\contentsline {subsection}{\numberline {27.2.3}Utility methods}{242}} \newlabel{subsection:ChvList:proto:utility}{{27.2.3}{242}} \@writefile{toc}{\contentsline {subsection}{\numberline {27.2.4}IO methods}{242}} \newlabel{subsection:ChvList:proto:IO}{{27.2.4}{242}} \@writefile{toc}{\contentsline {chapter}{\numberline {28}{\tt ChvManager}: {\tt Chv} manager object }{243}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {28.1}Data Structure}{244}} \newlabel{section:ChvManager:dataStructure}{{28.1}{244}} \@writefile{toc}{\contentsline {section}{\numberline {28.2}Prototypes and descriptions of {\tt ChvManager} methods}{244}} \newlabel{section:ChvManager:proto}{{28.2}{244}} \@writefile{toc}{\contentsline {subsection}{\numberline {28.2.1}Basic methods}{244}} \newlabel{subsection:ChvManager:proto:basics}{{28.2.1}{244}} \@writefile{toc}{\contentsline {subsection}{\numberline {28.2.2}Initialization methods}{245}} \newlabel{subsection:ChvManager:proto:initial}{{28.2.2}{245}} \@writefile{toc}{\contentsline {subsection}{\numberline {28.2.3}Utility methods}{245}} \newlabel{subsection:ChvManager:proto:utility}{{28.2.3}{245}} \@writefile{toc}{\contentsline {subsection}{\numberline {28.2.4}IO methods}{245}} \newlabel{subsection:ChvManager:proto:IO}{{28.2.4}{245}} \@writefile{toc}{\contentsline {chapter}{\numberline {29}{\tt DenseMtx}: Dense matrix object}{246}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {29.1}Data Structure}{246}} \newlabel{section:DenseMtx:dataStructure}{{29.1}{246}} \@writefile{toc}{\contentsline {section}{\numberline {29.2}Prototypes and descriptions of {\tt DenseMtx} methods}{247}} \newlabel{section:DenseMtx:proto}{{29.2}{247}} \@writefile{toc}{\contentsline {subsection}{\numberline {29.2.1}Basic methods}{247}} \newlabel{subsection:DenseMtx:proto:basics}{{29.2.1}{247}} \@writefile{toc}{\contentsline {subsection}{\numberline {29.2.2}Instance methods}{247}} \newlabel{subsection:DenseMtx:proto:instance}{{29.2.2}{247}} \@writefile{toc}{\contentsline {subsection}{\numberline {29.2.3}Initialization methods}{249}} \newlabel{subsection:DenseMtx:proto:initial}{{29.2.3}{249}} \@writefile{toc}{\contentsline {subsection}{\numberline {29.2.4}Utility methods}{250}} \newlabel{subsection:DenseMtx:proto:utility}{{29.2.4}{250}} \@writefile{toc}{\contentsline {subsection}{\numberline {29.2.5}IO methods}{252}} \newlabel{subsection:DenseMtx:proto:IO}{{29.2.5}{252}} \@writefile{toc}{\contentsline {chapter}{\numberline {30}{\tt FrontMtx}: Front matrix}{254}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {30.1}Data Structures}{257}} \newlabel{section:FrontMtx:dataStructure}{{30.1}{257}} \@writefile{toc}{\contentsline {section}{\numberline {30.2}Prototypes and descriptions of {\tt FrontMtx} methods}{259}} \newlabel{section:FrontMtx:proto}{{30.2}{259}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.1}Basic methods}{259}} \newlabel{subsection:FrontMtx:proto:basics}{{30.2.1}{259}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.2}Instance methods}{259}} \newlabel{subsection:FrontMtx:proto:instance}{{30.2.2}{259}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.3}Initialization methods}{261}} \newlabel{subsection:FrontMtx:proto:initialization}{{30.2.3}{261}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.4}Utility Factorization methods}{262}} \newlabel{subsection:FrontMtx:proto:utility-factor}{{30.2.4}{262}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.5}Serial Factorization method}{264}} \newlabel{subsection:FrontMtx:proto:factor}{{30.2.5}{264}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.6}QR factorization utility methods}{265}} \newlabel{subsection:FrontMtx:proto:utilityQR}{{30.2.6}{265}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.7}Serial $QR$ Factorization method}{266}} \newlabel{subsection:FrontMtx:proto:factorQR}{{30.2.7}{266}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.8}Postprocessing methods}{266}} \newlabel{subsection:FrontMtx:proto:postprocess}{{30.2.8}{266}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.9}Utility Solve methods}{267}} \newlabel{subsection:FrontMtx:proto:utility-solve}{{30.2.9}{267}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.10}Serial Solve method}{268}} \newlabel{subsection:FrontMtx:proto:solve-serial}{{30.2.10}{268}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.11}Serial $QR$ Solve method}{269}} \newlabel{subsection:FrontMtx:proto:QRsolve-serial}{{30.2.11}{269}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.12}Utility methods}{269}} \newlabel{subsection:FrontMtx:proto:utility}{{30.2.12}{269}} \@writefile{toc}{\contentsline {subsection}{\numberline {30.2.13}IO methods}{270}} \newlabel{subsection:FrontMtx:proto:IO}{{30.2.13}{270}} \@writefile{toc}{\contentsline {section}{\numberline {30.3}Driver programs for the {\tt DFrontMtx} object}{271}} \newlabel{section:DFrontMtx:drivers}{{30.3}{271}} \@writefile{toc}{\contentsline {chapter}{\numberline {31}{\tt ILUMtx}: Incomplete $LU$ Matrix Object}{273}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:ILUMtx}{{31}{273}} \@writefile{toc}{\contentsline {section}{\numberline {31.1}Data Structure}{273}} \newlabel{section:ILUMtx:dataStructure}{{31.1}{273}} \@writefile{toc}{\contentsline {section}{\numberline {31.2}Prototypes and descriptions of {\tt ILUMtx} methods}{274}} \newlabel{section:ILUMtx:proto}{{31.2}{274}} \@writefile{toc}{\contentsline {subsection}{\numberline {31.2.1}Basic methods}{274}} \newlabel{subsection:ILUMtx:proto:basics}{{31.2.1}{274}} \@writefile{toc}{\contentsline {subsection}{\numberline {31.2.2}Initialization Methods}{275}} \newlabel{subsection:ILUMtx:proto:initializers}{{31.2.2}{275}} \@writefile{toc}{\contentsline {subsection}{\numberline {31.2.3}Factorization Methods}{275}} \newlabel{subsection:ILUMtx:proto:factor}{{31.2.3}{275}} \@writefile{toc}{\contentsline {subsection}{\numberline {31.2.4}Solve Methods}{275}} \newlabel{subsection:ILUMtx:proto:solve}{{31.2.4}{275}} \@writefile{toc}{\contentsline {subsection}{\numberline {31.2.5}Utility methods}{276}} \newlabel{subsection:ILUMtx:proto:utility}{{31.2.5}{276}} \@writefile{toc}{\contentsline {subsection}{\numberline {31.2.6}IO methods}{276}} \newlabel{subsection:ILUMtx:proto:IO}{{31.2.6}{276}} \@writefile{toc}{\contentsline {section}{\numberline {31.3}Driver programs for the {\tt ILUMtx} object}{277}} \newlabel{section:ILUMtx:drivers}{{31.3}{277}} \@writefile{toc}{\contentsline {chapter}{\numberline {32}{\tt InpMtx}: Input Matrix Object}{278}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:InpMtx}{{32}{278}} \@writefile{toc}{\contentsline {section}{\numberline {32.1}Data Structure}{279}} \newlabel{section:InpMtx:dataStructure}{{32.1}{279}} \@writefile{toc}{\contentsline {section}{\numberline {32.2}Prototypes and descriptions of {\tt InpMtx} methods}{281}} \newlabel{section:InpMtx:proto}{{32.2}{281}} \@writefile{toc}{\contentsline {subsection}{\numberline {32.2.1}Basic methods}{281}} \newlabel{subsection:InpMtx:proto:basics}{{32.2.1}{281}} \@writefile{toc}{\contentsline {subsection}{\numberline {32.2.2}Instance Methods}{281}} \newlabel{subsection:InpMtx:proto:instance}{{32.2.2}{281}} \@writefile{toc}{\contentsline {subsection}{\numberline {32.2.3}Methods to initialize and change state}{284}} \newlabel{subsection:InpMtx:proto:initializers}{{32.2.3}{284}} \@writefile{toc}{\contentsline {subsection}{\numberline {32.2.4}Input methods}{285}} \newlabel{subsection:InpMtx:proto:input}{{32.2.4}{285}} \@writefile{toc}{\contentsline {subsection}{\numberline {32.2.5}Permutation, map and support methods}{286}} \newlabel{subsection:InpMtx:proto:permute}{{32.2.5}{286}} \@writefile{toc}{\contentsline {subsection}{\numberline {32.2.6}Matrix-matrix multiply methods}{287}} \newlabel{subsection:InpMtx:proto:mvm}{{32.2.6}{287}} \@writefile{toc}{\contentsline {subsection}{\numberline {32.2.7}Graph construction methods}{289}} \newlabel{subsection:InpMtx:proto:construct}{{32.2.7}{289}} \@writefile{toc}{\contentsline {subsection}{\numberline {32.2.8}Submatrix extraction method}{290}} \newlabel{subsection:InpMtx:proto:extract}{{32.2.8}{290}} \@writefile{toc}{\contentsline {subsection}{\numberline {32.2.9}Utility methods}{290}} \newlabel{subsection:InpMtx:proto:utility}{{32.2.9}{290}} \@writefile{toc}{\contentsline {subsection}{\numberline {32.2.10}IO methods}{292}} \newlabel{subsection:InpMtx:proto:IO}{{32.2.10}{292}} \@writefile{toc}{\contentsline {section}{\numberline {32.3}Driver programs for the {\tt InpMtx} object}{293}} \newlabel{section:InpMtx:drivers}{{32.3}{293}} \@writefile{toc}{\contentsline {chapter}{\numberline {33}{\tt Iter}: Iterative Methods}{301}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {33.1}Data Structure}{301}} \newlabel{section:Iter:dataStructure}{{33.1}{301}} \@writefile{toc}{\contentsline {section}{\numberline {33.2}Prototypes and descriptions of {\tt Iter} methods}{301}} \newlabel{section:Iter:proto}{{33.2}{301}} \@writefile{toc}{\contentsline {subsection}{\numberline {33.2.1}Utility methods}{301}} \newlabel{subsection:Iter:proto:utility}{{33.2.1}{301}} \@writefile{toc}{\contentsline {subsection}{\numberline {33.2.2}Iterative methods}{303}} \@writefile{toc}{\contentsline {section}{\numberline {33.3}Driver programs}{306}} \newlabel{section:Iter:drivers}{{33.3}{306}} \@writefile{toc}{\contentsline {chapter}{\numberline {34}{\tt PatchAndGoInfo}: Pivot Modification Object}{311}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {34.1}Data Structure}{312}} \newlabel{section:PatchAndGoInfo:dataStructure}{{34.1}{312}} \@writefile{toc}{\contentsline {section}{\numberline {34.2}Prototypes and descriptions of {\tt PatchAndGoInfo} methods}{312}} \newlabel{section:PatchAndGoInfo:proto}{{34.2}{312}} \@writefile{toc}{\contentsline {subsection}{\numberline {34.2.1}Basic methods}{312}} \newlabel{subsection:PatchAndGoInfo:proto:basics}{{34.2.1}{312}} \@writefile{toc}{\contentsline {subsection}{\numberline {34.2.2}Initializer methods}{313}} \newlabel{subsection:PatchAndGoInfo:proto:initializers}{{34.2.2}{313}} \@writefile{toc}{\contentsline {chapter}{\numberline {35}{\tt Pencil}: Matrix pencil}{314}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {35.1}Data Structure}{314}} \newlabel{section:Pencil:dataStructure}{{35.1}{314}} \@writefile{toc}{\contentsline {section}{\numberline {35.2}Prototypes and descriptions of {\tt Pencil} methods}{314}} \newlabel{section:Pencil:proto}{{35.2}{314}} \@writefile{toc}{\contentsline {subsection}{\numberline {35.2.1}Basic methods}{314}} \newlabel{subsection:Pencil:proto:basics}{{35.2.1}{314}} \@writefile{toc}{\contentsline {subsection}{\numberline {35.2.2}Initialization methods}{315}} \newlabel{subsection:Pencil:proto:initial}{{35.2.2}{315}} \@writefile{toc}{\contentsline {subsection}{\numberline {35.2.3}Utility methods}{315}} \newlabel{subsection:Pencil:proto:utilities}{{35.2.3}{315}} \@writefile{toc}{\contentsline {subsection}{\numberline {35.2.4}IO methods}{316}} \newlabel{subsection:Pencil:proto:IO}{{35.2.4}{316}} \@writefile{toc}{\contentsline {chapter}{\numberline {36}{\tt SemiImplMtx}: Semi-Implicit Factorization}{317}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:SemiImplMtx}{{36}{317}} \@writefile{toc}{\contentsline {section}{\numberline {36.1}Data Structure}{318}} \newlabel{section:SemiImplMtx:dataStructure}{{36.1}{318}} \@writefile{toc}{\contentsline {section}{\numberline {36.2}Prototypes and descriptions of {\tt SemiImplMtx} methods}{318}} \newlabel{section:SemiImplMtx:proto}{{36.2}{318}} \@writefile{toc}{\contentsline {subsection}{\numberline {36.2.1}Basic methods}{318}} \newlabel{subsection:SemiImplMtx:proto:basics}{{36.2.1}{318}} \@writefile{toc}{\contentsline {subsection}{\numberline {36.2.2}Initialization Methods}{319}} \newlabel{subsection:SemiImplMtx:proto:initializers}{{36.2.2}{319}} \@writefile{toc}{\contentsline {subsection}{\numberline {36.2.3}Solve Methods}{319}} \newlabel{subsection:SemiImplMtx:proto:solve}{{36.2.3}{319}} \@writefile{toc}{\contentsline {subsection}{\numberline {36.2.4}Utility methods}{320}} \newlabel{subsection:SemiImplMtx:proto:utility}{{36.2.4}{320}} \@writefile{toc}{\contentsline {subsection}{\numberline {36.2.5}IO methods}{320}} \newlabel{subsection:SemiImplMtx:proto:IO}{{36.2.5}{320}} \@writefile{toc}{\contentsline {section}{\numberline {36.3}Driver programs for the {\tt SemiImplMtx} object}{320}} \newlabel{section:SemiImplMtx:drivers}{{36.3}{320}} \@writefile{toc}{\contentsline {chapter}{\numberline {37}{\tt SubMtx}: Submatrix object}{322}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {37.1}Data Structure}{323}} \newlabel{section:SubMtx:dataStructure}{{37.1}{323}} \@writefile{toc}{\contentsline {section}{\numberline {37.2}Prototypes and descriptions of {\tt SubMtx} methods}{324}} \newlabel{section:SubMtx:proto}{{37.2}{324}} \@writefile{toc}{\contentsline {subsection}{\numberline {37.2.1}Basic methods}{325}} \newlabel{subsection:SubMtx:proto:basics}{{37.2.1}{325}} \@writefile{toc}{\contentsline {subsection}{\numberline {37.2.2}Instance methods}{325}} \newlabel{subsection:SubMtx:proto:instance}{{37.2.2}{325}} \@writefile{toc}{\contentsline {subsection}{\numberline {37.2.3}Initialization methods}{328}} \newlabel{subsection:SubMtx:proto:initial}{{37.2.3}{328}} \@writefile{toc}{\contentsline {subsection}{\numberline {37.2.4}Vector scaling methods}{329}} \newlabel{subsection:SubMtx:proto:scale}{{37.2.4}{329}} \@writefile{toc}{\contentsline {subsection}{\numberline {37.2.5}Solve methods}{329}} \newlabel{subsection:SubMtx:proto:solve}{{37.2.5}{329}} \@writefile{toc}{\contentsline {subsection}{\numberline {37.2.6}Utility methods}{330}} \newlabel{subsection:SubMtx:proto:utility}{{37.2.6}{330}} \@writefile{toc}{\contentsline {subsection}{\numberline {37.2.7}IO methods}{331}} \newlabel{subsection:SubMtx:proto:IO}{{37.2.7}{331}} \@writefile{toc}{\contentsline {section}{\numberline {37.3}Driver programs for the {\tt SubMtx object}}{333}} \newlabel{section:SubMtx:drivers}{{37.3}{333}} \@writefile{toc}{\contentsline {chapter}{\numberline {38}{\tt SubMtxList}: {\tt SubMtx} list object }{337}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {38.1}Data Structure}{338}} \newlabel{section:SubMtxList:dataStructure}{{38.1}{338}} \@writefile{toc}{\contentsline {section}{\numberline {38.2}Prototypes and descriptions of {\tt SubMtxList} methods}{338}} \newlabel{section:SubMtxList:proto}{{38.2}{338}} \@writefile{toc}{\contentsline {subsection}{\numberline {38.2.1}Basic methods}{338}} \newlabel{subsection:SubMtxList:proto:basics}{{38.2.1}{338}} \@writefile{toc}{\contentsline {subsection}{\numberline {38.2.2}Initialization methods}{339}} \newlabel{subsection:SubMtxList:proto:initial}{{38.2.2}{339}} \@writefile{toc}{\contentsline {subsection}{\numberline {38.2.3}Utility methods}{339}} \newlabel{subsection:SubMtxList:proto:utility}{{38.2.3}{339}} \@writefile{toc}{\contentsline {subsection}{\numberline {38.2.4}IO methods}{339}} \newlabel{subsection:SubMtxList:proto:IO}{{38.2.4}{339}} \@writefile{toc}{\contentsline {chapter}{\numberline {39}{\tt SubMtxManager}: {\tt SubMtx} object manager}{340}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {39.1}Data Structure}{341}} \newlabel{section:SubMtxManager:dataStructure}{{39.1}{341}} \@writefile{toc}{\contentsline {section}{\numberline {39.2}Prototypes and descriptions of {\tt SubMtxManager} methods}{341}} \newlabel{section:SubMtxManager:proto}{{39.2}{341}} \@writefile{toc}{\contentsline {subsection}{\numberline {39.2.1}Basic methods}{341}} \newlabel{subsection:SubMtxManager:proto:basics}{{39.2.1}{341}} \@writefile{toc}{\contentsline {subsection}{\numberline {39.2.2}Initialization methods}{342}} \newlabel{subsection:SubMtxManager:proto:initial}{{39.2.2}{342}} \@writefile{toc}{\contentsline {subsection}{\numberline {39.2.3}Utility methods}{342}} \newlabel{subsection:SubMtxManager:proto:utility}{{39.2.3}{342}} \@writefile{toc}{\contentsline {subsection}{\numberline {39.2.4}IO methods}{342}} \newlabel{subsection:SubMtxManager:proto:IO}{{39.2.4}{342}} \@writefile{toc}{\contentsline {chapter}{\numberline {40}{\tt SymbFac}: Symbolic Factorization}{343}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:SymbFac}{{40}{343}} \@writefile{toc}{\contentsline {section}{\numberline {40.1}Data Structure}{343}} \@writefile{toc}{\contentsline {section}{\numberline {40.2}Prototypes and descriptions of {\tt SymbFac} methods}{343}} \newlabel{subsection:SymbFac:proto}{{40.2}{343}} \@writefile{toc}{\contentsline {subsection}{\numberline {40.2.1}Symbolic factorization methods}{343}} \newlabel{subsection:SymbFac:proto:symbfac}{{40.2.1}{343}} \@writefile{toc}{\contentsline {section}{\numberline {40.3}Driver programs }{344}} \newlabel{section:SymbFac:drivers}{{40.3}{344}} \@writefile{toc}{\contentsline {part}{\uppercase {v}\hspace {1em}Miscellaneous Methods}{346}} \citation{bha93-localND} \@writefile{toc}{\contentsline {chapter}{\numberline {41}{\tt Misc} directory}{348}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:Misc}{{41}{348}} \@writefile{toc}{\contentsline {section}{\numberline {41.1}Prototypes and descriptions of methods in the {\tt Misc} directory}{348}} \newlabel{section:Misc:proto}{{41.1}{348}} \@writefile{toc}{\contentsline {subsection}{\numberline {41.1.1}Theoretical nested dissection methods}{348}} \citation{bha93-localND} \citation{bha93-localND} \@writefile{toc}{\contentsline {subsection}{\numberline {41.1.2}Multiple minimum degree, Nested dissection and multisection wrapper methods}{350}} \@writefile{toc}{\contentsline {subsection}{\numberline {41.1.3}Graph drawing method}{351}} \@writefile{toc}{\contentsline {subsection}{\numberline {41.1.4}Linear system construction}{351}} \@writefile{toc}{\contentsline {section}{\numberline {41.2}Driver programs found in the {\tt Misc} directory}{352}} \newlabel{section:Misc:drivers}{{41.2}{352}} \@writefile{lof}{\contentsline {figure}{\numberline {41.1}{\ignorespaces {\sc R2D100}}}{355}} \newlabel{fig-R2D100}{{41.1}{355}} \@writefile{lof}{\contentsline {figure}{\numberline {41.2}{\ignorespaces {\sc R2D100: fishnet domain decomposition}}}{356}} \newlabel{fig-R2D100-fishnet}{{41.2}{356}} \@writefile{toc}{\contentsline {part}{\uppercase {vi}\hspace {1em}Multithreaded Methods}{361}} \@writefile{toc}{\contentsline {chapter}{\numberline {42}{\tt MT} directory}{363}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:MT}{{42}{363}} \@writefile{toc}{\contentsline {section}{\numberline {42.1}Data Structure}{364}} \newlabel{section:MT:dataStructure}{{42.1}{364}} \@writefile{toc}{\contentsline {section}{\numberline {42.2}Prototypes and descriptions of {\tt MT} methods}{364}} \newlabel{section:MT:proto}{{42.2}{364}} \@writefile{toc}{\contentsline {subsection}{\numberline {42.2.1}Matrix-matrix multiply methods}{364}} \newlabel{subsection:MT:proto:mvm}{{42.2.1}{364}} \@writefile{toc}{\contentsline {subsection}{\numberline {42.2.2}Multithreaded Factorization methods}{365}} \newlabel{subsection:FrontMtx:proto:factorMT}{{42.2.2}{365}} \@writefile{toc}{\contentsline {subsection}{\numberline {42.2.3}Multithreaded $QR$ Factorization method}{366}} \newlabel{subsection:FrontMtx:proto:factorQR_MT}{{42.2.3}{366}} \@writefile{toc}{\contentsline {subsection}{\numberline {42.2.4}Multithreaded Solve method}{366}} \newlabel{subsection:FrontMtx:proto:solve-multithreaded}{{42.2.4}{366}} \@writefile{toc}{\contentsline {subsection}{\numberline {42.2.5}Multithreaded $QR$ Solve method}{367}} \newlabel{subsection:FrontMtx:proto:QRsolve-MT}{{42.2.5}{367}} \@writefile{toc}{\contentsline {section}{\numberline {42.3}Driver programs for the multithreaded functions}{367}} \newlabel{section:MT:drivers}{{42.3}{367}} \@writefile{toc}{\contentsline {part}{\uppercase {vii}\hspace {1em}MPI Methods}{373}} \@writefile{toc}{\contentsline {chapter}{\numberline {43}{\tt MPI} directory}{375}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:MPI}{{43}{375}} \@writefile{toc}{\contentsline {section}{\numberline {43.1}Data Structure}{375}} \newlabel{section:MPI:dataStructure}{{43.1}{375}} \@writefile{toc}{\contentsline {subsection}{\numberline {43.1.1}{\tt MatMulInfo} : Matrix-matrix multiply information object}{375}} \newlabel{subsection:MatMulInfo}{{43.1.1}{375}} \@writefile{toc}{\contentsline {section}{\numberline {43.2}Prototypes and descriptions of {\tt MPI} methods}{376}} \newlabel{section:MPI:proto}{{43.2}{376}} \@writefile{toc}{\contentsline {subsection}{\numberline {43.2.1}Split and redistribution methods}{376}} \newlabel{subsection:MPI:proto:split}{{43.2.1}{376}} \@writefile{toc}{\contentsline {subsection}{\numberline {43.2.2}Gather and scatter methods}{379}} \newlabel{subsection:MPI:proto:gather-scatter}{{43.2.2}{379}} \@writefile{toc}{\contentsline {subsection}{\numberline {43.2.3}Symbolic Factorization methods}{379}} \newlabel{subsection:MPI:proto:symbfac}{{43.2.3}{379}} \@writefile{toc}{\contentsline {subsection}{\numberline {43.2.4}Numeric Factorization methods}{380}} \newlabel{subsection:MPI:proto:factor}{{43.2.4}{380}} \@writefile{toc}{\contentsline {subsection}{\numberline {43.2.5}Post-processing methods}{381}} \newlabel{subsection:MPI:proto:postprocess}{{43.2.5}{381}} \@writefile{toc}{\contentsline {subsection}{\numberline {43.2.6}Numeric Solve methods}{382}} \newlabel{subsection:MPI:proto:solve}{{43.2.6}{382}} \@writefile{toc}{\contentsline {subsection}{\numberline {43.2.7}Matrix-matrix multiply methods}{383}} \newlabel{subsection:MPI:proto:mmm}{{43.2.7}{383}} \@writefile{toc}{\contentsline {subsection}{\numberline {43.2.8}Broadcast methods}{384}} \newlabel{subsection:MPI:proto:broadcast}{{43.2.8}{384}} \@writefile{toc}{\contentsline {subsection}{\numberline {43.2.9}Utility methods}{385}} \newlabel{subsection:MPI:proto:utility}{{43.2.9}{385}} \@writefile{toc}{\contentsline {section}{\numberline {43.3}Driver programs}{386}} \newlabel{section:MPI:drivers}{{43.3}{386}} \bibdata{spooles} \bibcite{ame96-amd}{1} \bibcite{and90-random}{2} \bibcite{ash95-compressed-graphs}{3} \bibcite{ash89-relaxed}{4} \bibcite{ash97-DDSEP}{5} \bibcite{ash98-maxflow}{6} \bibcite{bent93-sort}{7} \bibcite{bha93-localND}{8} \bibcite{dam92-compressed}{9} \bibcite{duf83-multifrontal}{10} \bibcite{eis76-elementModel}{11} \bibcite{sparsematlab}{12} \bibcite{hr98-msndtalk}{13} \bibcite{karypis98metis}{14} \bibcite{liu85-mfstorage}{15} \bibcite{liu90-etree}{16} \bibcite{liu91-generalizedEnvelope}{17} \bibcite{ng96-mindefIdaho}{18} \bibcite{rot96-mindefIdaho}{19} \bibcite{rot98-mindef}{20} rline {37.1}Data Structure}{323}} \newlabel{section:SubMtx:dataStructure}{{37.1}{323}} \@writefile{toc}{\contentsline {section}{\numberline {37.2}Prototypes and descriptions of {\tt SubMtx} methods}{324}} \newlabel{section:SubMtx:proto}{{37.2}{324}} \@writefile{toc}{\contentsline {subsection}{\numberline {37.2.1}Basic methods}{325}} \newlabel{subsection:SubMtx:proto:basics}{{37.2.1}{325}} \@writefile{toc}{\contentsline {subsection}{\numberline {37.2.2}Instance methods}{325}} \newladocumentation/ReferenceManual/main.bbl010064400020550007177000000100140665023132400214000ustar00clevecompmath00000400000006\begin{thebibliography}{10} \bibitem{ame96-amd} P.~Amestoy, T.~Davis, and I.~Duff. \newblock An approximate minimum degree ordering algorithm. \newblock {\em SIAM J. Matrix Anal. Appl.}, 17:886--905, 1996. \bibitem{and90-random} S.~L. Anderson. \newblock Random number generators on vector supercomputers and other advanced architectures. \newblock {\em SIAM Review}, 32:221--251, 1990. \bibitem{ash95-compressed-graphs} C.~Ashcraft. \newblock Compressed graphs and the minimum degree algorithm. \newblock {\em SIAM J. Sci. Comput.}, 16:1404--1411, 1995. \bibitem{ash89-relaxed} C.~Ashcraft and R.~Grimes. \newblock The influence of relaxed supernode partitions on the multifrontal method. \newblock {\em ACM Trans. Math. Software}, 15:291--309, 1989. \bibitem{ash97-DDSEP} C.~Ashcraft and J.~W.~H. Liu. \newblock Using domain decompositions to find graph bisectors. \newblock {\em BIT}, 37:506--534, 1997. \bibitem{ash98-maxflow} C.~Ashcraft and J.~W.~H. Liu. \newblock Applications of the {D}ulmage-{M}endelsohn decomposition and network flow to graph bisection improvement. \newblock {\em SIAM J. Matrix Analysis and Applic.}, 19:325--354, 1998. \bibitem{bent93-sort} J.~L. Bentley and M.~D. McIlroy. \newblock Engineering a sort function. \newblock {\em Software -- Practice and Experience}, 23(11):1249--1265, 1993. \bibitem{bha93-localND} M.~V. Bhat, W.~G. Habashi, J.~W.~H. Liu, V.~N. Nguyen, and M.~F. Peeters. \newblock A note on nested dissection for rectangular grids. \newblock {\em SIAM J. Matrix Analysis and Applic.}, 14:253--258, 1993. \bibitem{dam92-compressed} A.~C. Damhaug. \newblock {\em Sparse Solution of Finite Element Equations}. \newblock PhD thesis, The Norwegian Institute of Technology, 1992. \bibitem{duf83-multifrontal} I.~Duff and J.~Reid. \newblock The multifrontal solution of indefinite sparse symmetric linear equations. \newblock {\em ACM Trans. Math. Software}, 6:302--325, 1983. \bibitem{eis76-elementModel} S.~C. Eisenstat, M.~H. Schultz, and A.~H. Sherman. \newblock Applications of an element model for {G}aussian elimination. \newblock In J.~R. Bunch and D.~J. Rose, editors, {\em Sparse Matrix Computations}, pages 85--96. Academic Press, 1976. \bibitem{sparsematlab} J.~Gilbert, C.~Moler, and R.~Schreiber. \newblock Sparse matrices in {MATLAB}: design and implementation. \newblock {\em SIAM J. Matrix Analysis and Applic.}, 13:335--356, 1992. \bibitem{hr98-msndtalk} B.~Hendrickson and E.~Rothberg. \newblock Improving the runtime and quality of nested dissection ordering. \newblock {\em SIAM J. Sci. Comput.}, 20:468--489, 1998. \bibitem{karypis98metis} G.~Karypis and V.~Kumar. \newblock Metis~4.0: Unstructured graph partitioning and sparse matrix ordering system. \newblock Technical report, Department of Computer Science, University of Minnesota, 1998. \newblock Available on the WWW at URL {\em http://www.cs.umn.edu/\~{}metis}. \bibitem{liu85-mfstorage} J.~W.~H. Liu. \newblock On the storage requirement in the out-of-core multifrontal method for sparse factorization. \newblock {\em ACM Trans. on Math. Software}, 12:249--264, 1986. \bibitem{liu90-etree} J.~W.~H. Liu. \newblock The role of elimination trees in sparse factorization. \newblock {\em SIAM J. Matrix Analysis and Applic.}, 11:134--172, 1990. \bibitem{liu91-generalizedEnvelope} J.~W.~H. Liu. \newblock A generalized envelope method for sparse factorization by rows. \newblock {\em ACM Trans. on Math. Software}, 17:112--129, 1991. \bibitem{ng96-mindefIdaho} E.~Ng and P.~Raghavan. \newblock Minimum deficiency ordering. \newblock In {\em Second SIAM Conference on Sparse Matrices}, 1996. \newblock Conference presentation. \bibitem{rot96-mindefIdaho} E.~Rothberg. \newblock Ordering sparse matrices using approximate minimum local fill. \newblock In {\em Second SIAM Conference on Sparse Matrices}, 1996. \newblock Conference presentation. \bibitem{rot98-mindef} E.~Rothberg and S.~C. Eisenstat. \newblock Node selection strategies for bottom-up sparse matrix ordering. \newblock {\em SIAM J. Matrix Anal.}, 19:682--695, 1998. \end{thebibliography} bliography}{10} \bibitem{ame96-amd} P.~Amestoy, T.~Davis, and I.~Duff. \newblock An approximate minimum degree ordering algorithm. \newblock {\em SIAM J. Matrix Anal. Appl.}, 17:886--905, 1996. \bibitem{and90-random} S.~L. Anderson. \newblock Random number generators on vector supercomputers and other advanced architectures. \newblock {\em SIAM Review}, 32:221--251, 1990. \bibitem{ash95-compressed-graphs} C.~Ashcraft. \newblock Compressed graphs and the minimum degree algorithm. \newblock {documentation/ReferenceManual/main.blg010064400020550007177000000000000665023132400213770ustar00clevecompmath00000400000006documentation/ReferenceManual/main.idx010064400020550007177000002474300665314325500214530ustar00clevecompmath00000400000006\indexentry{A2_new@{\tt A2\_new()}}{26} \indexentry{A2_setDefaultFields@{\tt A2\_setDefaultFields()}}{26} \indexentry{A2_clearData@{\tt A2\_clearData()}}{26} \indexentry{A2_free@{\tt A2\_free()}}{26} \indexentry{A2_nrow@{\tt A2\_nrow()}}{26} \indexentry{A2_ncol@{\tt A2\_ncol()}}{26} \indexentry{A2_inc1@{\tt A2\_inc1()}}{26} \indexentry{A2_inc2@{\tt A2\_inc2()}}{26} \indexentry{A2_entries@{\tt A2\_entries()}}{26} \indexentry{A2_row@{\tt A2\_row()}}{27} \indexentry{A2_column@{\tt A2\_column()}}{27} \indexentry{A2_realEntry@{\tt A2\_realEntry()}}{27} \indexentry{A2_complexEntry@{\tt A2\_complexEntry()}}{27} \indexentry{A2_setRealEntry@{\tt A2\_setRealEntry()}}{27} \indexentry{A2_setComplexEntry@{\tt A2\_setComplexEntry()}}{27} \indexentry{A2_pointerToRealEntry@{\tt A2\_pointerToRealEntry()}}{27} \indexentry{A2_pointerToComplexEntry@{\tt A2\_pointerToComplexEntry()}}{27} \indexentry{A2_init@{\tt A2\_init()}}{28} \indexentry{A2_subA2@{\tt A2\_subA2()}}{28} \indexentry{A2_makeStaircase@{\tt A2\_makeStaircase()}}{28} \indexentry{A2_QRreduce@{\tt A2\_QRreduce()}}{28} \indexentry{A2_computeQ@{\tt A2\_computeQ()}}{28} \indexentry{A2_applyQT@{\tt A2\_applyQT()}}{29} \indexentry{A2_maxabs@{\tt A2\_maxabs()}}{29} \indexentry{A2_frobNorm@{\tt A2\_frobNorm()}}{29} \indexentry{A2_oneNorm@{\tt A2\_oneNorm()}}{29} \indexentry{A2_infinityNorm@{\tt A2\_infinityNorm()}}{29} \indexentry{A2_oneNormOfColumn@{\tt A2\_oneNormOfColumn()}}{29} \indexentry{A2_twoNormOfColumn@{\tt A2\_twoNormOfColumn()}}{29} \indexentry{A2_infinityNormOfColumn@{\tt A2\_infinityNormOfColumn()}}{29} \indexentry{A2_oneNormOfRow@{\tt A2\_oneNormOfRow()}}{29} \indexentry{A2_twoNormOfRow@{\tt A2\_twoNormOfRow()}}{30} \indexentry{A2_infinityNormOfRow@{\tt A2\_infinityNormOfRow()}}{30} \indexentry{A2_permuteRows@{\tt A2\_permuteRows()}}{30} \indexentry{A2_permuteColumns@{\tt A2\_permuteColumns()}}{30} \indexentry{A2_sortRowsUp@{\tt A2\_sortRowsUp()}}{30} \indexentry{A2_sortColumnsUp@{\tt A2\_sortColumnsUp()}}{30} \indexentry{A2_sizeOf@{\tt A2\_sizeOf()}}{30} \indexentry{A2_shiftbase@{\tt A2\_shiftBase()}}{30} \indexentry{A2_rowMajor@{\tt A2\_rowMajor()}}{31} \indexentry{A2_columnMajor@{\tt A2\_columnMajor()}}{31} \indexentry{A2_transpose@{\tt A2\_transpose()}}{31} \indexentry{A2_extractRow@{\tt A2\_extractRow()}}{31} \indexentry{A2_extractRowDV@{\tt A2\_extractRowDV()}}{31} \indexentry{A2_extractRowZV@{\tt A2\_extractRowZV()}}{31} \indexentry{A2_extractColumn@{\tt A2\_extractColumn()}}{31} \indexentry{A2_extractColumnDV@{\tt A2\_extractColumnDV()}}{31} \indexentry{A2_extractColumnZV@{\tt A2\_extractColumnZV()}}{31} \indexentry{A2_setRow@{\tt A2\_setRow()}}{31} \indexentry{A2_setRowDV@{\tt A2\_setRowDV()}}{32} \indexentry{A2_setRowZV@{\tt A2\_setRowZV()}}{32} \indexentry{A2_setColumn@{\tt A2\_setColumn()}}{32} \indexentry{A2_setColumnDV@{\tt A2\_setColumnDV()}}{32} \indexentry{A2_setColumnZV@{\tt A2\_setColumnZV()}}{32} \indexentry{A2_fillRandomUniform@{\tt A2\_fillRandomUniform()}}{32} \indexentry{A2_fillRandomNormal@{\tt A2\_fillRandomNormal()}}{32} \indexentry{A2_fillWithIdentity@{\tt A2\_fillWithIdentity()}}{32} \indexentry{A2_zero@{\tt A2\_zero()}}{32} \indexentry{A2_copy@{\tt A2\_copy()}}{32} \indexentry{A2_sub@{\tt A2\_sub()}}{33} \indexentry{A2_swapRows@{\tt A2\_swapRows()}}{33} \indexentry{A2_swapColumns@{\tt A2\_swapColumns()}}{33} \indexentry{A2_copyEntriesToVector@{\tt A2\_copyEntriesToVector()}}{33} \indexentry{A2_readFromFile@{\tt A2\_readFromFile()}}{33} \indexentry{A2_readFromFormattedFile@{\tt A2\_readFromFormattedFile()}}{33} \indexentry{A2_readFromBinaryFile@{\tt A2\_readFromBinaryFile()}}{33} \indexentry{A2_writeToFile@{\tt A2\_writeToFile()}}{34} \indexentry{A2_writeToFormattedFile@{\tt A2\_writeToFormattedFile()}}{34} \indexentry{A2_writeToBinaryFile@{\tt A2\_writeToBinaryFile()}}{34} \indexentry{A2_writeForHumanEye@{\tt A2\_writeForHumanEye()}}{34} \indexentry{A2_writeStats@{\tt A2\_writeStats()}}{34} \indexentry{A2_writeForMatlab@{\tt A2\_writeForMatlab()}}{34} \indexentry{Coords_new@{\tt Coords\_new()}}{36} \indexentry{Coords_setDefaultFields@{\tt Coords\_setDefaultFields()}}{37} \indexentry{Coords_clearData@{\tt Coords\_clearData()}}{37} \indexentry{Coords_free@{\tt Coords\_free()}}{37} \indexentry{Coords_init@{\tt Coords\_init()}}{37} \indexentry{Coords_init9P@{\tt Coords\_init9P()}}{37} \indexentry{Coords_init27P@{\tt Coords\_init27P()}}{37} \indexentry{Coords_sizeOf@{\tt Coords\_sizeOf()}}{38} \indexentry{Coords_min@{\tt Coords\_min()}}{38} \indexentry{Coords_max@{\tt Coords\_max()}}{38} \indexentry{Coords_value@{\tt Coords\_value()}}{38} \indexentry{Coords_setValue@{\tt Coords\_setValue()}}{38} \indexentry{Coords_readFromFile@{\tt Coords\_readFromFile()}}{38} \indexentry{Coords_readFromFormattedFile@{\tt Coords\_readFromFormattedFile()}}{39} \indexentry{Coords_readFromBinaryFile@{\tt Coords\_readFromBinaryFile()}}{39} \indexentry{Coords_writeToFile@{\tt Coords\_writeToFile()}}{39} \indexentry{Coords_writeToFormattedFile@{\tt Coords\_writeToFormattedFile()}}{39} \indexentry{Coords_writeToBinaryFile@{\tt Coords\_writeToBinaryFile()}}{39} \indexentry{Coords_writeForHumanEye@{\tt Coords\_writeForHumanEye()}}{39} \indexentry{Coords_writeStats@{\tt Coords\_writeStats()}}{39} \indexentry{DV_new@{\tt DV\_new()}}{42} \indexentry{DV_setDefaultFields@{\tt DV\_setDefaultFields()}}{42} \indexentry{DV_clearData@{\tt DV\_clearData()}}{42} \indexentry{DV_free@{\tt DV\_free()}}{42} \indexentry{DV_owned@{\tt DV\_owned()}}{42} \indexentry{DV_size@{\tt DV\_size()}}{42} \indexentry{DV_maxsize@{\tt DV\_size()}}{42} \indexentry{DV_entry@{\tt DV\_entry()}}{43} \indexentry{DV_entries@{\tt DV\_entries()}}{43} \indexentry{DV_sizeAndEntries@{\tt DV\_sizeAndEntries()}}{43} \indexentry{DV_setEntry@{\tt DV\_setEntry()}}{43} \indexentry{DV_init@{\tt DV\_init()}}{43} \indexentry{DV_init1@{\tt DV\_init1()}}{43} \indexentry{DV_init2@{\tt DV\_init2()}}{43} \indexentry{DV_setMaxsize@{\tt DV\_setMaxsize()}}{43} \indexentry{DV_setSize@{\tt DV\_setSize()}}{44} \indexentry{DV_shiftBase@{\tt DV\_shiftBase()}}{44} \indexentry{DV_push@{\tt DV\_push()}}{44} \indexentry{DV_min@{\tt DV\_min()}}{44} \indexentry{DV_max@{\tt DV\_max()}}{44} \indexentry{DV_sum@{\tt DV\_sum()}}{44} \indexentry{DV_sortUp@{\tt DV\_sortUp()}}{44} \indexentry{DV_sortDown@{\tt DV\_sortDown()}}{44} \indexentry{DV_ramp@{\tt DV\_ramp()}}{44} \indexentry{DV_shuffle@{\tt DV\_shuffle()}}{44} \indexentry{DV_sizeOf@{\tt DV\_sizeOf()}}{45} \indexentry{DV_first@{\tt DV\_first()}}{45} \indexentry{DV_next@{\tt DV\_next()}}{45} \indexentry{DV_fill@{\tt DV\_fill()}}{45} \indexentry{DV_zero@{\tt DV\_zero()}}{45} \indexentry{DV_copy@{\tt DV\_copy()}}{45} \indexentry{DV_log10profile@{\tt DV\_log10profile()}}{45} \indexentry{DV_readFromFile@{\tt DV\_readFromFile()}}{45} \indexentry{DV_readFromFormattedFile@{\tt DV\_readFromFormattedFile()}}{46} \indexentry{DV_readFromBinaryFile@{\tt DV\_readFromBinaryFile()}}{46} \indexentry{DV_writeToFile@{\tt DV\_writeToFile()}}{46} \indexentry{DV_writeToFormattedFile@{\tt DV\_writeToFormattedFile()}}{46} \indexentry{DV_writeToBinaryFile@{\tt DV\_writeToBinaryFile()}}{46} \indexentry{DV_writeForHumanEye@{\tt DV\_writeForHumanEye()}}{46} \indexentry{DV_writeStats@{\tt DV\_writeStats()}}{46} \indexentry{DV_writeForMatlab@{\tt DV\_writeForMatlab()}}{46} \indexentry{Drand_new@{\tt Drand\_new()}}{49} \indexentry{Drand_setDefaultFields@{\tt Drand\_setDefaultFields()}}{49} \indexentry{Drand_clearData@{\tt Drand\_clearData()}}{49} \indexentry{Drand_free@{\tt Drand\_free()}}{49} \indexentry{Drand_init@{\tt Drand\_init()}}{49} \indexentry{Drand_setSeed@{\tt Drand\_setSeed()}}{49} \indexentry{Drand_setSeeds@{\tt Drand\_setSeeds()}}{49} \indexentry{Drand_setNormal@{\tt Drand\_setNormal()}}{50} \indexentry{Drand_setUniform@{\tt Drand\_setUniform()}}{50} \indexentry{Drand_value@{\tt Drand\_value()}}{50} \indexentry{Drand_fillZvector@{\tt Drand\_fillZvector()}}{50} \indexentry{Drand_fillDvector@{\tt Drand\_fillDvector()}}{50} \indexentry{Drand_fillIvector@{\tt Drand\_fillIvector()}}{50} \indexentry{I2Ohash_new@{\tt I2Ohash\_new()}}{53} \indexentry{I2Ohash_setDefaultFields@{\tt I2Ohash\_setDefaultFields()}}{53} \indexentry{I2Ohash_clearData@{\tt I2Ohash\_clearData()}}{53} \indexentry{I2Ohash_free@{\tt I2Ohash\_free()}}{53} \indexentry{I2Ohash_init@{\tt I2Ohash\_init()}}{53} \indexentry{I2Ohash_insert@{\tt I2Ohash\_insert()}}{54} \indexentry{I2Ohash_locate@{\tt I2Ohash\_locate()}}{54} \indexentry{I2Ohash_remove@{\tt I2Ohash\_remove()}}{54} \indexentry{I2Ohash_measure@{\tt I2Ohash\_measure()}}{54} \indexentry{I2Ohash_writeForHumanEye@{\tt I2Ohash\_writeForHumanEye()}}{54} \indexentry{IIheap_new@{\tt IIheap\_new()}}{56} \indexentry{IIheap_setDefaultFields@{\tt IIheap\_setDefaultFields()}}{57} \indexentry{IIheap_clearData@{\tt IIheap\_clearData()}}{57} \indexentry{IIheap_free@{\tt IIheap\_free()}}{57} \indexentry{IIheap_init@{\tt IIheap\_init()}}{57} \indexentry{IIheap_sizeOf@{\tt IIheap\_sizeOf()}}{57} \indexentry{IIheap_root@{\tt IIheap\_root()}}{57} \indexentry{IIheap_insert@{\tt IIheap\_insert()}}{57} \indexentry{IIheap_remove@{\tt IIheap\_remove()}}{57} \indexentry{IIheap_print@{\tt IIheap\_print()}}{57} \indexentry{IV_new@{\tt IV\_new()}}{59} \indexentry{IV_setDefaultFields@{\tt IV\_setDefaultFields()}}{59} \indexentry{IV_clearData@{\tt IV\_clearData()}}{59} \indexentry{IV_free@{\tt IV\_free()}}{59} \indexentry{IV_owned@{\tt IV\_owned()}}{59} \indexentry{IV_size@{\tt IV\_size()}}{60} \indexentry{IV_maxsize@{\tt IV\_maxsize()}}{60} \indexentry{IV_entry@{\tt IV\_entry()}}{60} \indexentry{IV_entries@{\tt IV\_entries()}}{60} \indexentry{IV_sizeAndEntries@{\tt IV\_sizeAndEntries()}}{60} \indexentry{IV_setEntry@{\tt IV\_setEntry()}}{60} \indexentry{IV_init@{\tt IV\_init()}}{60} \indexentry{IV_init1@{\tt IV\_init1()}}{60} \indexentry{IV_init2@{\tt IV\_init2()}}{60} \indexentry{IV_setMaxsize@{\tt IV\_setMaxsize()}}{61} \indexentry{IV_setSize@{\tt IV\_setSize()}}{61} \indexentry{IV_shiftBase@{\tt IV\_shiftBase()}}{61} \indexentry{IV_push@{\tt IV\_push()}}{61} \indexentry{IV_min@{\tt IV\_min()}}{61} \indexentry{IV_max@{\tt IV\_max()}}{61} \indexentry{IV_sortUp@{\tt IV\_sortUp()}}{61} \indexentry{IV_sortDown@{\tt IV\_sortDown()}}{61} \indexentry{IV_ramp@{\tt IV\_ramp()}}{61} \indexentry{IV_shuffle@{\tt IV\_shuffle()}}{62} \indexentry{IV_sizeOf@{\tt IV\_sizeOf()}}{62} \indexentry{IV_filterKeep@{\tt IV\_filterKeep()}}{62} \indexentry{IV_filterPurge@{\tt IV\_filterPurge()}}{62} \indexentry{IV_first@{\tt IV\_first()}}{62} \indexentry{IV_next@{\tt IV\_next()}}{62} \indexentry{IV_fill@{\tt IV\_fill()}}{62} \indexentry{IV_copy@{\tt IV\_copy()}}{62} \indexentry{IV_increment@{\tt IV\_increment()}}{62} \indexentry{IV_decrement@{\tt IV\_decrement()}}{63} \indexentry{IV_findValue@{\tt IV\_findValue()}}{63} \indexentry{IV_findValueAscending@{\tt IV\_findValueAscending()}}{63} \indexentry{IV_findValueDescending@{\tt IV\_findValueDescending()}}{63} \indexentry{IV_inverseMap@{\tt IV\_inverseMap()}}{63} \indexentry{IV_targetEntries@{\tt IV\_targetEntries()}}{63} \indexentry{IV_readFromFile@{\tt IV\_readFromFile()}}{63} \indexentry{IV_readFromFormattedFile@{\tt IV\_readFromFormattedFile()}}{64} \indexentry{IV_readFromBinaryFile@{\tt IV\_readFromBinaryFile()}}{64} \indexentry{IV_writeToFile@{\tt IV\_writeToFile()}}{64} \indexentry{IV_writeToFormattedFile@{\tt IV\_writeToFormattedFile()}}{64} \indexentry{IV_writeToBinaryFile@{\tt IV\_writeToBinaryFile()}}{64} \indexentry{IV_writeForHumanEye@{\tt IV\_writeForHumanEye()}}{64} \indexentry{IV_writeStats@{\tt IV\_writeStats()}}{64} \indexentry{IV_fp80@{\tt IV\_fp80()}}{64} \indexentry{IV_writeForMatlab@{\tt IV\_writeForMatlab()}}{64} \indexentry{IVL_new@{\tt IVL\_new()}}{67} \indexentry{IVL_setDefaultFields@{\tt IVL\_setDefaultFields()}}{67} \indexentry{IVL_clearData@{\tt IVL\_clearData()}}{67} \indexentry{IVL_free@{\tt IVL\_free()}}{67} \indexentry{IVL_type@{\tt IVL\_type()}}{68} \indexentry{IVL_maxnlist@{\tt IVL\_maxnlist()}}{68} \indexentry{IVL_nlist@{\tt IVL\_nlist()}}{68} \indexentry{IVL_tsize@{\tt IVL\_tsize()}}{68} \indexentry{IVL_incr@{\tt IVL\_incr()}}{68} \indexentry{IVL_setincr@{\tt IVL\_setincr()}}{68} \indexentry{IVL_init@{\tt IVL\_init()}}{68} \indexentry{IVL_init2@{\tt IVL\_init2()}}{68} \indexentry{IVL_init3@{\tt IVL\_init3()}}{68} \indexentry{IVL_initFromSubIVL@{\tt IVL\_initFromSubIVL()}}{69} \indexentry{IVL_setMaxnlist@{\tt IVL\_setMaxnlist()}}{69} \indexentry{IVL_setNlist@{\tt IVL\_setNlist()}}{69} \indexentry{IVL_listAndSize@{\tt IVL\_listAndSize()}}{69} \indexentry{IVL_firstInList@{\tt IVL\_firstInList()}}{69} \indexentry{IVL_nextInList@{\tt IVL\_nextInList()}}{69} \indexentry{IVL_setList@{\tt IVL\_setList()}}{69} \indexentry{IVL_setPointerToList@{\tt IVL\_setPointerToList()}}{70} \indexentry{IVL_sizeOf@{\tt IVL\_sizeOf()}}{70} \indexentry{IVL_min@{\tt IVL\_min()}}{70} \indexentry{IVL_max@{\tt IVL\_max()}}{70} \indexentry{IVL_maxListSize@{\tt IVL\_maxListSize()}}{70} \indexentry{IVL_sum@{\tt IVL\_sum()}}{70} \indexentry{IVL_sortUp@{\tt IVL\_sortUp()}}{70} \indexentry{IVL_equivMap1@{\tt IVL\_equivMap1()}}{70} \indexentry{IVL_equivMap2@{\tt IVL\_equivMap2()}}{70} \indexentry{IVL_overwrite@{\tt IVL\_overwrite()}}{71} \indexentry{IVL_mapEntries@{\tt IVL\_mapEntries()}}{71} \indexentry{IVL_absorbIVL@{\tt IVL\_absorbIVL()}}{71} \indexentry{IVL_expand@{\tt IVL\_expand()}}{71} \indexentry{IVL_make9P@{\tt IVL\_make9P()}}{71} \indexentry{IVL_make13P@{\tt IVL\_make13P()}}{71} \indexentry{IVL_make5P@{\tt IVL\_make5P()}}{71} \indexentry{IVL_make27P@{\tt IVL\_make27P()}}{72} \indexentry{IVL_readFromFile@{\tt IVL\_readFromFile()}}{72} \indexentry{IVL_readFromFormattedFile@{\tt IVL\_readFromFormattedFile()}}{72} \indexentry{IVL_readFromBinaryFile@{\tt IVL\_readFromBinaryFile()}}{72} \indexentry{IVL_writeToFile@{\tt IVL\_writeToFile()}}{72} \indexentry{IVL_writeToFormattedFile@{\tt IVL\_writeToFormattedFile()}}{72} \indexentry{IVL_writeToBinaryFile@{\tt IVL\_writeToBinaryFile()}}{72} \indexentry{IVL_writeForHumanEye@{\tt IVL\_writeForHumanEye()}}{72} \indexentry{IVL_writeStats@{\tt IVL\_writeStats()}}{73} \indexentry{Ideq_new@{\tt Ideq\_new()}}{75} \indexentry{Ideq_setDefaultFields@{\tt Ideq\_setDefaultFields()}}{75} \indexentry{Ideq_clearData@{\tt Ideq\_clearData()}}{75} \indexentry{Ideq_free@{\tt Ideq\_free()}}{75} \indexentry{Ideq_resize@{\tt Ideq\_resize()}}{75} \indexentry{Ideq_clear@{\tt Ideq\_clear()}}{75} \indexentry{Ideq_head@{\tt Ideq\_head()}}{75} \indexentry{Ideq_removeFromHead@{\tt Ideq\_removeFromHead()}}{75} \indexentry{Ideq_insertAtHead@{\tt Ideq\_insertAtHead()}}{76} \indexentry{Ideq_tail@{\tt Ideq\_tail()}}{76} \indexentry{Ideq_removeFromTail@{\tt Ideq\_removeFromTail()}}{76} \indexentry{Ideq_insertAtTail@{\tt Ideq\_insertAtTail()}}{76} \indexentry{Ideq_writeForHumanEye@{\tt Ideq\_writeForHumanEye()}}{76} \indexentry{Lock_new@{\tt Lock\_new()}}{78} \indexentry{Lock_setDefaultFields@{\tt Lock\_setDefaultFields()}}{78} \indexentry{Lock_clearData@{\tt Lock\_clearData()}}{78} \indexentry{Lock_free@{\tt Lock\_free()}}{78} \indexentry{Lock_init@{\tt Lock\_init()}}{78} \indexentry{Lock_lock@{\tt Lock\_lock()}}{78} \indexentry{Lock_unlock@{\tt Lock\_unlock()}}{78} \indexentry{Perm_new@{\tt Perm\_new()}}{79} \indexentry{Perm_setDefaultFields@{\tt Perm\_setDefaultFields()}}{80} \indexentry{Perm_clearData@{\tt Perm\_clearData()}}{80} \indexentry{Perm_free@{\tt Perm\_free()}}{80} \indexentry{Perm_initWithTypeAndSize@{\tt Perm\_initWithTypeAndSize()}}{80} \indexentry{Perm_sizeOf@{\tt Perm\_sizeOf()}}{80} \indexentry{Perm_checkPerm@{\tt Perm\_checkPerm()}}{80} \indexentry{Perm_fillOldToNew@{\tt Perm\_fillOldToNew()}}{80} \indexentry{Perm_fillNewToOld@{\tt Perm\_fillNewToOld()}}{80} \indexentry{Perm_releaseOldToNew@{\tt Perm\_releaseOldToNew()}}{81} \indexentry{Perm_releaseNewToOld@{\tt Perm\_releaseNewToOld()}}{81} \indexentry{Perm_compress@{\tt Perm\_compress()}}{81} \indexentry{Perm_readFromFile@{\tt Perm\_readFromFile()}}{81} \indexentry{Perm_readFromFormattedFile@{\tt Perm\_readFromFormattedFile()}}{81} \indexentry{Perm_readFromBinaryFile@{\tt Perm\_readFromBinaryFile()}}{81} \indexentry{Perm_writeToFile@{\tt Perm\_writeToFile()}}{81} \indexentry{Perm_writeToFormattedFile@{\tt Perm\_writeToFormattedFile()}}{82} \indexentry{Perm_writeToBinaryFile@{\tt Perm\_writeToBinaryFile()}}{82} \indexentry{Perm_writeForHumanEye@{\tt Perm\_writeForHumanEye()}}{82} \indexentry{Perm_writeStats@{\tt Perm\_writeStats()}}{82} \indexentry{CVinit@{\tt CVinit()}}{84} \indexentry{CVinit2@{\tt CVinit2()}}{84} \indexentry{CVfree@{\tt CVfree()}}{84} \indexentry{CVcopy@{\tt CVcopy()}}{84} \indexentry{CVfill@{\tt CVfill()}}{84} \indexentry{CVfprintf@{\tt CVfprintf()}}{84} \indexentry{CVfp80@{\tt CVfp80()}}{84} \indexentry{CVfscanf@{\tt CVfscanf()}}{84} \indexentry{DVinit@{\tt DVinit()}}{84} \indexentry{DVinit2@{\tt DVinit2()}}{84} \indexentry{DVfree@{\tt DVfree()}}{84} \indexentry{DVfprintf@{\tt DVfprintf()}}{84} \indexentry{DVfscanf@{\tt DVfscanf()}}{85} \indexentry{DVadd@{\tt DVadd()}}{85} \indexentry{DVaxpy@{\tt DVaxpy()}}{85} \indexentry{DVaxpy@{\tt DVaxpy()}}{85} \indexentry{DVaxpy33@{\tt DVaxpy33()}}{85} \indexentry{DVaxpy32@{\tt DVaxpy32()}}{85} \indexentry{DVaxpy31@{\tt DVaxpy31()}}{85} \indexentry{DVaxpy23@{\tt DVaxpy23()}}{85} \indexentry{DVaxpy22@{\tt DVaxpy22()}}{85} \indexentry{DVaxpy21@{\tt DVaxpy21()}}{86} \indexentry{DVaxpy13@{\tt DVaxpy13()}}{86} \indexentry{DVaxpy12@{\tt DVaxpy12()}}{86} \indexentry{DVaxpy11@{\tt DVaxpy11()}}{86} \indexentry{DVaxpyi@{\tt DVaxpyi()}}{86} \indexentry{DVcompress@{\tt DVcompress()}}{86} \indexentry{DVcopy@{\tt DVcopy()}}{86} \indexentry{DVdot@{\tt DVdot()}}{86} \indexentry{DVdot33@{\tt DVdot33()}}{86} \indexentry{DVdot32@{\tt DVdot32()}}{87} \indexentry{DVdot31@{\tt DVdot31()}}{87} \indexentry{DVdot23@{\tt DVdot23()}}{87} \indexentry{DVdot22@{\tt DVdot22()}}{87} \indexentry{DVdot21@{\tt DVdot21()}}{87} \indexentry{DVdot13@{\tt DVdot13()}}{88} \indexentry{DVdot12@{\tt DVdot12()}}{88} \indexentry{DVdot11@{\tt DVdot11()}}{88} \indexentry{DVdoti@{\tt DVdoti()}}{88} \indexentry{DVfill@{\tt DVfill()}}{88} \indexentry{DVgather@{\tt DVgather()}}{88} \indexentry{DVgatherAddZero@{\tt DVgatherAddZero()}}{88} \indexentry{DVgatherZero@{\tt DVgatherZero()}}{88} \indexentry{DVinvPerm@{\tt DVinvPerm()}}{88} \indexentry{DVmax@{\tt DVmax()}}{88} \indexentry{DVmaxabs@{\tt DVmaxabs()}}{88} \indexentry{DVmin@{\tt DVmin()}}{88} \indexentry{DVminabs@{\tt DVminabs()}}{89} \indexentry{DVperm@{\tt DVperm()}}{89} \indexentry{DVramp@{\tt DVramp()}}{89} \indexentry{DVscale@{\tt DVscale()}}{89} \indexentry{DVscale@{\tt DVscale()}}{89} \indexentry{DVscatter@{\tt DVscatter()}}{89} \indexentry{DVscatterAdd@{\tt DVscatterAdd()}}{89} \indexentry{DVscatterAddZero@{\tt DVscatterAddZero()}}{89} \indexentry{DVscatterZero@{\tt DVscatterZero()}}{89} \indexentry{DVsub@{\tt DVsub()}}{89} \indexentry{DVsum@{\tt DVsum()}}{89} \indexentry{DVsumabs@{\tt DVsumabs()}}{89} \indexentry{DVswap@{\tt DVswap()}}{89} \indexentry{DVzero@{\tt DVzero()}}{90} \indexentry{DVshuffle@{\tt DVshuffle()}}{90} \indexentry{ZVinit@{\tt ZVinit()}}{90} \indexentry{ZVfprintf@{\tt ZVfprintf()}}{90} \indexentry{Zabs@{\tt Zabs()}}{90} \indexentry{Zrecip@{\tt Zrecip()}}{90} \indexentry{Zrecip2@{\tt Zrecip2()}}{90} \indexentry{ZVaxpy@{\tt ZVaxpy()}}{90} \indexentry{ZVaxpy@{\tt ZVaxpy()}}{90} \indexentry{ZVaxpy33@{\tt ZVaxpy33()}}{90} \indexentry{ZVaxpy32@{\tt ZVaxpy32()}}{91} \indexentry{ZVaxpy31@{\tt ZVaxpy31()}}{91} \indexentry{ZVaxpy23@{\tt ZVaxpy23()}}{91} \indexentry{ZVaxpy22@{\tt ZVaxpy22()}}{91} \indexentry{ZVaxpy21@{\tt ZVaxpy21()}}{91} \indexentry{ZVaxpy13@{\tt ZVaxpy13()}}{91} \indexentry{ZVaxpy12@{\tt ZVaxpy12()}}{91} \indexentry{ZVaxpy11@{\tt ZVaxpy11()}}{92} \indexentry{ZVcopy@{\tt ZVcopy()}}{92} \indexentry{ZVdotU@{\tt ZVdotU()}}{92} \indexentry{ZVdotC@{\tt ZVdotC()}}{92} \indexentry{ZVdotiU@{\tt ZVdotiU()}}{92} \indexentry{ZVdotiC@{\tt ZVdotiC()}}{92} \indexentry{ZVdotU33@{\tt ZVdotU33()}}{92} \indexentry{ZVdotU32@{\tt ZVdotU32()}}{92} \indexentry{ZVdotU31@{\tt ZVdotU31()}}{93} \indexentry{ZVdotU23@{\tt ZVdotU23()}}{93} \indexentry{ZVdotU22@{\tt ZVdotU22()}}{93} \indexentry{ZVdotU21@{\tt ZVdotU21()}}{93} \indexentry{ZVdotU13@{\tt ZVdotU13()}}{94} \indexentry{ZVdotU12@{\tt ZVdotU12()}}{94} \indexentry{ZVdotU11@{\tt ZVdotU11()}}{94} \indexentry{ZVdotC33@{\tt ZVdotC33()}}{94} \indexentry{ZVdotC32@{\tt ZVdotC32()}}{94} \indexentry{ZVdotC31@{\tt ZVdotC31()}}{95} \indexentry{ZVdotC23@{\tt ZVdotC23()}}{95} \indexentry{ZVdotC22@{\tt ZVdotC22()}}{95} \indexentry{ZVdotC21@{\tt ZVdotC21()}}{95} \indexentry{ZVdotC13@{\tt ZVdotC13()}}{95} \indexentry{ZVdotC12@{\tt ZVdotC12()}}{96} \indexentry{ZVdotC11@{\tt ZVdotC11()}}{96} \indexentry{ZVgather@{\tt ZVgather()}}{96} \indexentry{ZVmaxabs@{\tt ZVmaxabs()}}{96} \indexentry{ZVminabs@{\tt ZVminabs()}}{96} \indexentry{ZVscale@{\tt ZVscale()}}{96} \indexentry{ZVscale@{\tt ZVscale()}}{96} \indexentry{ZVscatter@{\tt ZVscatter()}}{96} \indexentry{ZVsub@{\tt ZVsub()}}{96} \indexentry{ZVzero@{\tt ZVzero()}}{96} \indexentry{IVinit@{\tt IVinit()}}{96} \indexentry{IVinit2@{\tt IVinit2()}}{96} \indexentry{IVfree@{\tt IVfree()}}{97} \indexentry{IVfprintf@{\tt IVfprintf()}}{97} \indexentry{IVfp80@{\tt IVfp80()}}{97} \indexentry{IVfscanf@{\tt IVfscanf()}}{97} \indexentry{IVcompress@{\tt IVcompress()}}{97} \indexentry{IVcopy@{\tt IVcopy()}}{97} \indexentry{IVfill@{\tt IVfill()}}{97} \indexentry{IVgather@{\tt IVgather()}}{97} \indexentry{IVinverse@{\tt IVinverse()}}{97} \indexentry{IVinvPerm@{\tt IVinvPerm()}}{97} \indexentry{IVlocateViaBinarySearch@{\tt IVlocateViaBinarySearch()}}{97} \indexentry{IVmax@{\tt IVmax()}}{97} \indexentry{IVmaxabs@{\tt IVmaxabs()}}{97} \indexentry{IVmin@{\tt IVmin()}}{98} \indexentry{IVminabs@{\tt IVminabs()}}{98} \indexentry{IVperm@{\tt IVperm()}}{98} \indexentry{IVramp@{\tt IVramp()}}{98} \indexentry{IVscatter@{\tt IVscatter()}}{98} \indexentry{IVsum@{\tt IVsum()}}{98} \indexentry{IVsumabs@{\tt IVsumabs()}}{98} \indexentry{IVswap@{\tt IVswap()}}{98} \indexentry{IVzero@{\tt IVzero()}}{98} \indexentry{IVshuffle@{\tt IVshuffle()}}{98} \indexentry{FVinit@{\tt FVinit()}}{98} \indexentry{FVinit2@{\tt FVinit2()}}{98} \indexentry{FVfree@{\tt FVfree()}}{98} \indexentry{FVfprintf@{\tt FVfprintf()}}{99} \indexentry{FVfscanf@{\tt FVfscanf()}}{99} \indexentry{FVadd@{\tt FVadd()}}{99} \indexentry{FVaxpy@{\tt FVaxpy()}}{99} \indexentry{FVaxpyi@{\tt FVaxpyi()}}{99} \indexentry{FVcompress@{\tt FVcompress()}}{99} \indexentry{FVcopy@{\tt FVcopy()}}{99} \indexentry{FVdot@{\tt FVdot()}}{99} \indexentry{FVfill@{\tt FVfill()}}{99} \indexentry{FVgather@{\tt FVgather()}}{99} \indexentry{FVgatherAddZero@{\tt FVgatherAddZero()}}{99} \indexentry{FVgatherZero@{\tt FVgatherZero()}}{99} \indexentry{FVinvPerm@{\tt FVinvPerm()}}{99} \indexentry{FVmax@{\tt FVmax()}}{99} \indexentry{FVmaxabs@{\tt FVmaxabs()}}{100} \indexentry{FVmin@{\tt FVmin()}}{100} \indexentry{FVminabs@{\tt FVminabs()}}{100} \indexentry{FVperm@{\tt FVperm()}}{100} \indexentry{FVramp@{\tt FVramp()}}{100} \indexentry{FVscale@{\tt FVscale()}}{100} \indexentry{FVscatter@{\tt FVscatter()}}{100} \indexentry{FVscatterAddZero@{\tt FVscatterAddZero()}}{100} \indexentry{FVscatterZero@{\tt FVscatterZero()}}{100} \indexentry{FVsub@{\tt FVsub()}}{100} \indexentry{FVsum@{\tt FVsum()}}{100} \indexentry{FVsumabs@{\tt FVsumabs()}}{100} \indexentry{FVswap@{\tt FVswap()}}{100} \indexentry{FVzero@{\tt FVzero()}}{100} \indexentry{FVshuffle@{\tt FVshuffle()}}{100} \indexentry{PCVinit@{\tt PCVinit()}}{101} \indexentry{PCVfree@{\tt PCVfree()}}{101} \indexentry{PCVcopy@{\tt PCVcopy()}}{101} \indexentry{PCVsetup@{\tt PCVsetup()}}{101} \indexentry{PDVinit@{\tt PDVinit()}}{101} \indexentry{PDVfree@{\tt PDVfree()}}{101} \indexentry{PDVcopy@{\tt PDVcopy()}}{101} \indexentry{PDVsetup@{\tt PDVsetup()}}{101} \indexentry{PIVinit@{\tt PIVinit()}}{101} \indexentry{PIVfree@{\tt PIVfree()}}{101} \indexentry{PIVcopy@{\tt PIVcopy()}}{101} \indexentry{PIVsetup@{\tt PIVsetup()}}{101} \indexentry{PFVinit@{\tt PFVinit()}}{102} \indexentry{PFVfree@{\tt PFVfree()}}{102} \indexentry{PFVcopy@{\tt PFVcopy()}}{102} \indexentry{PFVsetup@{\tt PFVsetup()}}{102} \indexentry{IVisascending@{\tt IVisascending()}}{102} \indexentry{IVisdescending@{\tt IVisdescending()}}{102} \indexentry{DVisascending@{\tt DVisascending()}}{102} \indexentry{DVisdescending@{\tt DVisdescending()}}{102} \indexentry{IVisortUp@{\tt IVisortUp()}}{102} \indexentry{IVisortDown@{\tt IVisortDown()}}{102} \indexentry{IV2isortUp@{\tt IV2isortUp()}}{102} \indexentry{IV2isortDown@{\tt IV2isortDown()}}{102} \indexentry{IVDVisortUp@{\tt IVDVisortUp()}}{102} \indexentry{IVDVisortDown@{\tt IVDVisortDown()}}{102} \indexentry{IV2DVisortUp@{\tt IV2DVisortUp()}}{102} \indexentry{IV2DVisortDown@{\tt IV2DVisortDown()}}{102} \indexentry{IVZVisortUp@{\tt IVZVisortUp()}}{103} \indexentry{IVZVisortDown@{\tt IVZVisortDown()}}{103} \indexentry{IV2ZVisortUp@{\tt IV2ZVisortUp()}}{103} \indexentry{IV2ZVisortDown@{\tt IV2ZVisortDown()}}{103} \indexentry{DVisortUp@{\tt DVisortUp()}}{103} \indexentry{DVisortDown@{\tt DVisortDown()}}{103} \indexentry{DV2isortUp@{\tt DV2isortUp()}}{103} \indexentry{DV2isortDown@{\tt DV2isortDown()}}{103} \indexentry{DVIVisortUp@{\tt DVIVisortUp()}}{103} \indexentry{DVIVisortDown@{\tt DVIVisortDown()}}{103} \indexentry{IVqsortUp@{\tt IVqsortUp()}}{103} \indexentry{IVqsortDown@{\tt IVqsortDown()}}{103} \indexentry{IV2qsortUp@{\tt IV2qsortUp()}}{103} \indexentry{IV2qsortDown@{\tt IV2qsortDown()}}{103} \indexentry{IVDVqsortUp@{\tt IVDVqsortUp()}}{103} \indexentry{IVDVqsortDown@{\tt IVDVqsortDown()}}{103} \indexentry{IV2DVqsortUp@{\tt IV2DVqsortUp()}}{103} \indexentry{IV2DVqsortDown@{\tt IV2DVqsortDown()}}{103} \indexentry{IVZVqsortUp@{\tt IVZVqsortUp()}}{103} \indexentry{IVZVqsortDown@{\tt IVZVqsortDown()}}{103} \indexentry{IV2ZVqsortUp@{\tt IV2ZVqsortUp()}}{104} \indexentry{IV2ZVqsortDown@{\tt IV2ZVqsortDown()}}{104} \indexentry{DVqsortUp@{\tt DVqsortUp()}}{104} \indexentry{DVqsortDown@{\tt DVqsortDown()}}{104} \indexentry{DV2qsortUp@{\tt DV2qsortUp()}}{104} \indexentry{DV2qsortDown@{\tt DV2qsortDown()}}{104} \indexentry{DVIVqsortUp@{\tt DVIVqsortUp()}}{104} \indexentry{DVIVqsortDown@{\tt DVIVqsortDown()}}{104} \indexentry{IVsortUpAndCompress@{\tt IVsortUpAndCompress()}}{104} \indexentry{IVDVsortUpAndCompress@{\tt IVDVsortUpAndCompress()}}{104} \indexentry{IVZVsortUpAndCompress@{\tt IVZVsortUpAndCompress()}}{104} \indexentry{IV2sortUpAndCompress@{\tt IV2sortUpAndCompress()}}{104} \indexentry{IV2DVsortUpAndCompress@{\tt IV2DVsortUpAndCompress()}}{105} \indexentry{IV2ZVsortUpAndCompress@{\tt IV2ZVsortUpAndCompress()}}{105} \indexentry{IP_init@{\tt IP\_init()}}{105} \indexentry{IP_free@{\tt IP\_free()}}{105} \indexentry{IP_fprintf@{\tt IP\_fprintf()}}{105} \indexentry{IP_fp80@{\tt IP\_fp80()}}{105} \indexentry{IP_mergeUp@{\tt IP\_mergeUp()}}{105} \indexentry{IP_mergeSortUp@{\tt IP\_mergeSortUp()}}{106} \indexentry{IP_radixSortUp@{\tt IP\_radixSortUp()}}{106} \indexentry{IP_radixSortDown@{\tt IP\_radixSortDown()}}{106} \indexentry{I2OP_init@{\tt I2OP\_init()}}{106} \indexentry{I2OP_initStorage@{\tt I2OP\_initStorage()}}{106} \indexentry{I2OP_free@{\tt I2OP\_free()}}{106} \indexentry{I2OP_fprintf@{\tt I2OP\_fprintf()}}{106} \indexentry{ZV_new@{\tt ZV\_new()}}{109} \indexentry{ZV_setDefaultFields@{\tt ZV\_setDefaultFields()}}{109} \indexentry{ZV_clearData@{\tt ZV\_clearData()}}{109} \indexentry{ZV_free@{\tt ZV\_free()}}{109} \indexentry{ZV_owned@{\tt ZV\_owned()}}{109} \indexentry{ZV_size@{\tt ZV\_size()}}{109} \indexentry{ZV_maxsize@{\tt ZV\_size()}}{110} \indexentry{ZV_entry@{\tt ZV\_entry()}}{110} \indexentry{ZV_pointersToEntry@{\tt ZV\_pointersToEntry()}}{110} \indexentry{ZV_entries@{\tt ZV\_entries()}}{110} \indexentry{ZV_sizeAndEntries@{\tt ZV\_sizeAndEntries()}}{110} \indexentry{ZV_setEntry@{\tt ZV\_setEntry()}}{110} \indexentry{ZV_init@{\tt ZV\_init()}}{110} \indexentry{ZV_init1@{\tt ZV\_init1()}}{110} \indexentry{ZV_init2@{\tt ZV\_init2()}}{111} \indexentry{ZV_setMaxsize@{\tt ZV\_setMaxsize()}}{111} \indexentry{ZV_setSize@{\tt ZV\_setSize()}}{111} \indexentry{ZV_shiftBase@{\tt ZV\_shiftBase()}}{111} \indexentry{ZV_push@{\tt ZV\_push()}}{111} \indexentry{ZV_minabs@{\tt ZV\_minabs()}}{111} \indexentry{ZV_maxabs@{\tt ZV\_maxabs()}}{111} \indexentry{ZV_sizeOf@{\tt ZV\_sizeOf()}}{111} \indexentry{ZV_fill@{\tt ZV\_fill()}}{112} \indexentry{ZV_zero@{\tt ZV\_zero()}}{112} \indexentry{ZV_copy@{\tt ZV\_copy()}}{112} \indexentry{ZV_log10profile@{\tt ZV\_log10profile()}}{112} \indexentry{ZV_readFromFile@{\tt ZV\_readFromFile()}}{112} \indexentry{ZV_readFromFormattedFile@{\tt ZV\_readFromFormattedFile()}}{112} \indexentry{ZV_readFromBinaryFile@{\tt ZV\_readFromBinaryFile()}}{112} \indexentry{ZV_writeToFile@{\tt ZV\_writeToFile()}}{113} \indexentry{ZV_writeToFormattedFile@{\tt ZV\_writeToFormattedFile()}}{113} \indexentry{ZV_writeToBinaryFile@{\tt ZV\_writeToBinaryFile()}}{113} \indexentry{ZV_writeForHumanEye@{\tt ZV\_writeForHumanEye()}}{113} \indexentry{ZV_writeStats@{\tt ZV\_writeStats()}}{113} \indexentry{ZV_writeForMatlab@{\tt ZV\_writeForMatlab()}}{113} \indexentry{BKL_new@{\tt BKL\_new()}}{118} \indexentry{BKL_setDefaultFields@{\tt BKL\_setDefaultFields()}}{118} \indexentry{BKL_clearData@{\tt BKL\_clearData()}}{118} \indexentry{BKL_free@{\tt BKL\_free()}}{118} \indexentry{BKL_init@{\tt BKL\_init()}}{118} \indexentry{BKL_setRandomColors@{\tt BKL\_setRandomColors()}}{119} \indexentry{BKL_setColorWeights@{\tt BKL\_setColorWeights()}}{119} \indexentry{BKL_segColor@{\tt BKL\_segColor()}}{119} \indexentry{BKL_flipDomain@{\tt BKL\_flipDomain()}}{119} \indexentry{BKL_greyCodeDomain@{\tt BKL\_greyCodeDomain()}}{119} \indexentry{BKL_setInitPart@{\tt BKL\_setInitPart()}}{119} \indexentry{BKL_domAdjToSep@{\tt BKL\_domAdjToSep()}}{120} \indexentry{BKL_evalgain@{\tt BKL\_evalgain()}}{120} \indexentry{BKL_evalfcn@{\tt BKL\_evalfcn()}}{120} \indexentry{BKL_eval@{\tt BKL\_eval()}}{120} \indexentry{BKL_exhSearch@{\tt BKL\_exhSearch()}}{120} \indexentry{BKL_fidmat@{\tt BKL\_fidmat()}}{121} \indexentry{BPG_new@{\tt BPG\_new()}}{124} \indexentry{BPG_setDefaultFields@{\tt BPG\_setDefaultFields()}}{124} \indexentry{BPG_clearData@{\tt BPG\_clearData()}}{124} \indexentry{BPG_free@{\tt BPG\_free()}}{124} \indexentry{BPG_init@{\tt BPG\_init()}}{125} \indexentry{BPG_initFromColoring@{\tt BPG\_initFromColoring()}}{125} \indexentry{BPG_makeGraphXbyX@{\tt BPG\_makeGraphXbyX()}}{125} \indexentry{BPG_makeGraphYbyY@{\tt BPG\_makeGraphYbyY()}}{125} \indexentry{BPG_pseudoperipheralnode@{\tt BPG\_pseudoperipheralnode()}}{125} \indexentry{BPG_levelStructure@{\tt BPG\_levelStructure()}}{125} \indexentry{BPG_DMdecomposition@{\tt BPG\_DMdecomposition()}}{126} \indexentry{BPG_DMviaMaxFlow@{\tt BPG\_DMviaMaxFlow()}}{126} \indexentry{BPG_readFromFile@{\tt BPG\_readFromFile()}}{126} \indexentry{BPG_readFromFormattedFile@{\tt BPG\_readFromFormattedFile()}}{126} \indexentry{BPG_readFromBinaryFile@{\tt BPG\_readFromBinaryFile()}}{127} \indexentry{BPG_writeToFile@{\tt BPG\_writeToFile()}}{127} \indexentry{BPG_writeToFormattedFile@{\tt BPG\_writeToFormattedFile()}}{127} \indexentry{BPG_writeToBinaryFile@{\tt BPG\_writeToBinaryFile()}}{127} \indexentry{BPG_writeForHumanEye@{\tt BPG\_writeForHumanEye()}}{127} \indexentry{BPG_writeStats@{\tt BPG\_writeStats()}}{127} \indexentry{DSTree_new@{\tt DSTree\_new()}}{130} \indexentry{DSTree_setDefaultFields@{\tt DSTree\_setDefaultFields()}}{130} \indexentry{DSTree_clearData@{\tt DSTree\_clearData()}}{130} \indexentry{DSTree_free@{\tt DSTree\_free()}}{130} \indexentry{DSTree_tree@{\tt DSTree\_tree()}}{130} \indexentry{DSTree_mapIV@{\tt DSTree\_mapIV()}}{130} \indexentry{DSTree_init1@{\tt DSTree\_init1()}}{130} \indexentry{DSTree_init2@{\tt DSTree\_init2()}}{131} \indexentry{DSTree_NDstages@{\tt DSTree\_NDstages()}}{131} \indexentry{DSTree_ND2stages@{\tt DSTree\_ND2stages()}}{131} \indexentry{DSTree_MS2stages@{\tt DSTree\_MS2stages()}}{131} \indexentry{DSTree_MS3stages@{\tt DSTree\_MS3stages()}}{131} \indexentry{DSTree_stagesViaDomainWeight@{\tt DSTree\_stagesViaDomainWeight()}}{132} \indexentry{DSTree_sizeOf@{\tt DSTree\_sizeOf()}}{132} \indexentry{DSTree_renumberViaPostOT@{\tt DSTree\_renumberViaPostOT()}}{132} \indexentry{DSTree_domainWeight@{\tt DSTree\_domainWeight()}}{132} \indexentry{DSTree_separatorWeight@{\tt DSTree\_separatorWeight()}}{132} \indexentry{DSTree_readFromFile@{\tt DSTree\_readFromFile()}}{132} \indexentry{DSTree_readFromFormattedFile@{\tt DSTree\_readFromFormattedFile()}}{133} \indexentry{DSTree_readFromBinaryFile@{\tt DSTree\_readFromBinaryFile()}}{133} \indexentry{DSTree_writeToFile@{\tt DSTree\_writeToFile()}}{133} \indexentry{DSTree_writeToFormattedFile@{\tt DSTree\_writeToFormattedFile()}}{133} \indexentry{DSTree_writeToBinaryFile@{\tt DSTree\_writeToBinaryFile()}}{133} \indexentry{DSTree_writeForHumanEye@{\tt DSTree\_writeForHumanEye()}}{133} \indexentry{DSTree_writeStats@{\tt DSTree\_writeStats()}}{133} \indexentry{EGraph_new@{\tt EGraph\_new()}}{136} \indexentry{EGraph_setDefaultFields@{\tt EGraph\_setDefaultFields()}}{136} \indexentry{EGraph_clearData@{\tt EGraph\_clearData()}}{136} \indexentry{EGraph_free@{\tt EGraph\_free()}}{136} \indexentry{EGraph_init@{\tt EGraph\_init()}}{136} \indexentry{EGraph_mkAdjGraph@{\tt EGraph\_mkAdjGraph()}}{136} \indexentry{EGraph_make9P@{\tt EGraph\_make9P()}}{136} \indexentry{EGraph_make27P@{\tt EGraph\_make27P()}}{137} \indexentry{EGraph_readFromFile@{\tt EGraph\_readFromFile()}}{137} \indexentry{EGraph_readFromFormattedFile@{\tt EGraph\_readFromFormattedFile()}}{137} \indexentry{EGraph_readFromBinaryFile@{\tt EGraph\_readFromBinaryFile()}}{137} \indexentry{EGraph_writeToFile@{\tt EGraph\_writeToFile()}}{137} \indexentry{EGraph_writeToFormattedFile@{\tt EGraph\_writeToFormattedFile()}}{137} \indexentry{EGraph_writeToBinaryFile@{\tt EGraph\_writeToBinaryFile()}}{137} \indexentry{EGraph_writeForHumanEye@{\tt EGraph\_writeForHumanEye()}}{138} \indexentry{EGraph_writeStats@{\tt EGraph\_writeStats()}}{138} \indexentry{ETree_new@{\tt ETree\_new()}}{141} \indexentry{ETree_setDefaultFields@{\tt ETree\_setDefaultFields()}}{141} \indexentry{ETree_clearData@{\tt ETree\_clearData()}}{141} \indexentry{ETree_free@{\tt ETree\_free()}}{141} \indexentry{ETree_nfront@{\tt ETree\_nfront()}}{141} \indexentry{ETree_nvtx@{\tt ETree\_nvtx()}}{141} \indexentry{ETree_tree@{\tt ETree\_tree()}}{141} \indexentry{ETree_root@{\tt ETree\_root()}}{141} \indexentry{ETree_par@{\tt ETree\_par()}}{142} \indexentry{ETree_fch@{\tt ETree\_fch()}}{142} \indexentry{ETree_sib@{\tt ETree\_sib()}}{142} \indexentry{ETree_nodwghtsIV@{\tt ETree\_nodwghtsIV()}}{142} \indexentry{ETree_nodwghts@{\tt ETree\_nodwghts()}}{142} \indexentry{ETree_bndwghtsIV@{\tt ETree\_bndwghtsIV()}}{142} \indexentry{ETree_bndwghts@{\tt ETree\_bndwghts()}}{142} \indexentry{ETree_vtxToFrontIV@{\tt ETree\_vtxToFrontIV()}}{142} \indexentry{ETree_vtxToFront@{\tt ETree\_vtxToFront()}}{142} \indexentry{ETree_frontSize@{\tt ETree\_frontSize()}}{142} \indexentry{ETree_frontBoundarySize@{\tt ETree\_frontBoundarySize()}}{142} \indexentry{ETree_maxNindAndNent@{\tt ETree\_maxNindAndNent()}}{143} \indexentry{ETree_init1@{\tt ETree\_init1()}}{143} \indexentry{ETree_initFromGraph@{\tt ETree\_initFromGraph()}}{143} \indexentry{ETree_initFromGraphWithPerms@{\tt ETree\_initFromGraphWithPerms()}}{143} \indexentry{ETree_initFromDenseMatrix@{\tt ETree\_initFromDenseMatrix()}}{143} \indexentry{ETree_initFromFile@{\tt ETree\_initFromFile()}}{144} \indexentry{ETree_initFromSubtree@{\tt ETree\_initFromSubtree()}}{144} \indexentry{ETree_sizeOf@{\tt ETree\_sizeOf()}}{144} \indexentry{ETree_nFactorIndices@{\tt ETree\_nFactorIndices()}}{144} \indexentry{ETree_nFactorEntries@{\tt ETree\_nFactorEntries()}}{144} \indexentry{ETree_nFactorOps@{\tt ETree\_nFactorOps()}}{144} \indexentry{ETree_nFactorEntriesInFront@{\tt ETree\_nFactorEntriesInFront()}}{144} \indexentry{ETree_nInternalOpsInFront@{\tt ETree\_nInternalOpsInFront()}}{145} \indexentry{ETree_nExternalOpsInFront@{\tt ETree\_nExternalOpsInFront()}}{145} \indexentry{ETree_factorEntriesIV@{\tt ETree\_factorEntriesIV()}}{145} \indexentry{ETree_backwardOps@{\tt ETree\_backwardOps()}}{145} \indexentry{ETree_forwardOps@{\tt ETree\_forwardOps()}}{145} \indexentry{ETree_expand@{\tt ETree\_expand()}}{145} \indexentry{ETree_spliceTwoEtrees@{\tt ETree\_spliceTwoEtrees()}}{145} \indexentry{ETree_nvtxMetric@{\tt ETree\_nvtxMetric()}}{146} \indexentry{ETree_nentMetric@{\tt ETree\_nentMetric()}}{146} \indexentry{ETree_nopsMetric@{\tt ETree\_nopsMetric()}}{146} \indexentry{ETree_fundChainMap@{\tt ETree\_fundChainMap()}}{147} \indexentry{ETree_fundSupernodeMap@{\tt ETree\_fundSupernodeMap()}}{147} \indexentry{ETree_compress@{\tt ETree\_compress()}}{147} \indexentry{ETree_leftJustify@{\tt ETree\_leftJustify()}}{147} \indexentry{ETree_leftJustifyI@{\tt ETree\_leftJustifyI()}}{147} \indexentry{ETree_leftJustifyD@{\tt ETree\_leftJustifyD()}}{147} \indexentry{ETree_newToOldFrontPerm@{\tt ETree\_newToOldFrontPerm()}}{148} \indexentry{ETree_oldToNewFrontPerm@{\tt ETree\_oldToNewFrontPerm()}}{148} \indexentry{ETree_newToOldVtxPerm@{\tt ETree\_newToOldVtxPerm()}}{148} \indexentry{ETree_oldToNewVtxPerm@{\tt ETree\_oldToNewVtxPerm()}}{148} \indexentry{ETree_permuteVertices@{\tt ETree\_permuteVertices()}}{148} \indexentry{ETree_msByDepth@{\tt ETree\_msByDepth()}}{148} \indexentry{ETree_msByNvtxCutoff@{\tt ETree\_msByNvtxCutoff()}}{148} \indexentry{ETree_msByNentCutoff@{\tt ETree\_msByNentCutoff()}}{149} \indexentry{ETree_msByNopsCutoff@{\tt ETree\_msByNopsCutoff()}}{149} \indexentry{ETree_msStats@{\tt ETree\_msStats()}}{149} \indexentry{ETree_optPart@{\tt ETree\_optPart()}}{149} \indexentry{ETree_mergeFrontsOne@{\tt ETree\_mergeFrontsOne()}}{150} \indexentry{ETree_mergeFrontsAll@{\tt ETree\_mergeFrontsAll()}}{151} \indexentry{ETree_mergeFrontsAny@{\tt ETree\_mergeFrontsAny()}}{151} \indexentry{ETree_splitFronts@{\tt ETree\_splitFronts()}}{151} \indexentry{ETree_transform@{\tt ETree\_transform()}}{151} \indexentry{ETree_transform2@{\tt ETree\_transform2()}}{151} \indexentry{ETree_wrapMap@{\tt ETree\_wrapMap()}}{152} \indexentry{ETree_balancedMap@{\tt ETree\_balancedMap()}}{152} \indexentry{ETree_subtreeSubsetMap@{\tt ETree\_subtreeSubsetMap()}}{152} \indexentry{ETree_ddMap@{\tt ETree\_ddMap()}}{152} \indexentry{ETree_ddMapNew@{\tt ETree\_ddMapNew()}}{152} \indexentry{ETree_MFstackProfile@{\tt ETree\_MFstackProfile()}}{152} \indexentry{ETree_GSstorageProfile@{\tt ETree\_GSstorageProfile()}}{152} \indexentry{ETree_FSstorageProfile@{\tt ETree\_FSstorageProfile()}}{153} \indexentry{ETree_forwSolveProfile@{\tt ETree\_forwSolveProfile()}}{153} \indexentry{ETree_backSolveProfile@{\tt ETree\_backSolveProfile()}}{153} \indexentry{ETree_readFromFile@{\tt ETree\_readFromFile()}}{153} \indexentry{ETree_readFromFormattedFile@{\tt ETree\_readFromFormattedFile()}}{153} \indexentry{ETree_readFromBinaryFile@{\tt ETree\_readFromBinaryFile()}}{153} \indexentry{ETree_writeToFile@{\tt ETree\_writeToFile()}}{153} \indexentry{ETree_writeToFormattedFile@{\tt ETree\_writeToFormattedFile()}}{154} \indexentry{ETree_writeToBinaryFile@{\tt ETree\_writeToBinaryFile()}}{154} \indexentry{ETree_writeForHumanEye@{\tt ETree\_writeForHumanEye()}}{154} \indexentry{ETree_writeStats@{\tt ETree\_writeStats()}}{154} \indexentry{GPart_new@{\tt GPart\_new()}}{167} \indexentry{GPart_setDefaultFields@{\tt GPart\_setDefaultFields()}}{167} \indexentry{GPart_clearData@{\tt GPart\_clearData()}}{168} \indexentry{GPart_free@{\tt GPart\_free()}}{168} \indexentry{GPart_init@{\tt GPart\_init()}}{168} \indexentry{GPart_setMessageInfo@{\tt GPart\_setMessageInfo()}}{168} \indexentry{GPart_setCweights@{\tt GPart\_setCweights()}}{168} \indexentry{GPart_sizeOf@{\tt GPart\_sizeOf()}}{168} \indexentry{GPart_validVtxSep@{\tt GPart\_validVtxSep()}}{168} \indexentry{GPart_split@{\tt GPart\_split()}}{169} \indexentry{GPart_vtxIsAdjToOneDomain@{\tt GPart\_vtxIsAdjToOneDomain()}}{169} \indexentry{GPart_bndWeightsIV@{\tt GPart\_bndWeightsIV()}}{169} \indexentry{GPart_DDviaFishnet@{\tt GPart\_DDviaFishnet()}}{169} \indexentry{GPart_DDviaProjection@{\tt GPart\_DDviaProjection()}}{169} \indexentry{GPart_TwoSetViaBKL@{\tt GPart\_TwoSetViaBKL()}}{170} \indexentry{GPart_domSegMap@{\tt GPart\_domSegMap()}}{170} \indexentry{GPart_identifyWideSep@{\tt GPart\_identifyWideSep()}}{170} \indexentry{GPart_makeYCmap@{\tt GPart\_makeYCmap()}}{170} \indexentry{GPart_smoothBy2layers@{\tt GPart\_smoothBy2layers()}}{171} \indexentry{GPart_smoothYSep@{\tt GPart\_smoothYSep()}}{171} \indexentry{GPart_smoothBisector@{\tt GPart\_smoothBisector()}}{171} \indexentry{GPart_RBviaDDsep@{\tt GPart\_RBviaDDsep()}}{172} \indexentry{DDepInfo_new@{\tt DDsepInfo\_new()}}{172} \indexentry{DDepInfo_setDefaultFields@{\tt DDsepInfo\_setDefaultFields()}}{172} \indexentry{DDepInfo_clearData@{\tt DDsepInfo\_clearData()}}{172} \indexentry{DDepInfo_free@{\tt DDsepInfo\_free()}}{172} \indexentry{DDepInfo_writeCpuTimes@{\tt DDsepInfo\_writeCpuTimes()}}{173} \indexentry{Graph_new@{\tt Graph\_new()}}{178} \indexentry{Graph_setDefaultFields@{\tt Graph\_setDefaultFields()}}{178} \indexentry{Graph_clearData@{\tt Graph\_clearData()}}{179} \indexentry{Graph_free@{\tt Graph\_free()}}{179} \indexentry{Graph_init1@{\tt Graph\_init1()}}{179} \indexentry{Graph_init2@{\tt Graph\_init2()}}{179} \indexentry{Graph_fillFromOffsets@{\tt Graph\_fillFromOffsets()}}{179} \indexentry{Graph_setListsFromOffsets@{\tt Graph\_setListsFromOffsets()}}{180} \indexentry{Graph_equivMap@{\tt Graph\_equivMap()}}{180} \indexentry{Graph_compress@{\tt Graph\_compress()}}{180} \indexentry{Graph_compress2@{\tt Graph\_compress2()}}{180} \indexentry{Graph_expand@{\tt Graph\_expand()}}{180} \indexentry{Graph_expand2@{\tt Graph\_expand2()}}{180} \indexentry{Graph_wirebasketStages@{\tt Graph\_wirebasketStages()}}{180} \indexentry{Graph_sizeOf@{\tt Graph\_sizeOf()}}{181} \indexentry{Graph_externalDegree@{\tt Graph\_externalDegree()}}{181} \indexentry{Graph_adjAndSize@{\tt Graph\_adjAndSize()}}{181} \indexentry{Graph_adjAndEweights@{\tt Graph\_adjAndEweights()}}{181} \indexentry{Graph_componentMap@{\tt Graph\_componentMap()}}{181} \indexentry{Graph_componentStats@{\tt Graph\_componentStats()}}{181} \indexentry{Graph_subGraph@{\tt Graph\_subGraph()}}{181} \indexentry{Graph_isSymmetric@{\tt Graph\_isSymmetric()}}{182} \indexentry{Graph_readFromFile@{\tt Graph\_readFromFile()}}{182} \indexentry{Graph_readFromFormattedFile@{\tt Graph\_readFromFormattedFile()}}{182} \indexentry{Graph_readFromBinaryFile@{\tt Graph\_readFromBinaryFile()}}{182} \indexentry{Graph_writeToFile@{\tt Graph\_writeToFile()}}{182} \indexentry{Graph_writeToFormattedFile@{\tt Graph\_writeToFormattedFile()}}{182} \indexentry{Graph_writeToBinaryFile@{\tt Graph\_writeToBinaryFile()}}{183} \indexentry{Graph_writeForHumanEye@{\tt Graph\_writeForHumanEye()}}{183} \indexentry{Graph_writeStats@{\tt Graph\_writeStats()}}{183} \indexentry{Graph_writeToMetisFile@{\tt Graph\_writeToMetisFile()}}{183} \indexentry{MSMDinfo_new@{\tt MSMDinfo\_new()}}{191} \indexentry{MSMDinfo_setDefaultFields@{\tt MSMDinfo\_setDefaultFields()}}{192} \indexentry{MSMDinfo_clearData@{\tt MSMDinfo\_clearData()}}{192} \indexentry{MSMDinfo_free@{\tt MSMDinfo\_free()}}{192} \indexentry{MSMDinfo_print@{\tt MSMDinfo\_print()}}{192} \indexentry{MSMDinfo_isValid@{\tt MSMDinfo\_isValid()}}{192} \indexentry{MSMD_new@{\tt MSMD\_new()}}{192} \indexentry{MSMD_setDefaultFields@{\tt MSMD\_setDefaultFields()}}{192} \indexentry{MSMD_clearData@{\tt MSMD\_clearData()}}{193} \indexentry{MSMD_free@{\tt MSMD\_free()}}{193} \indexentry{MSMD_init@{\tt MSMD\_init()}}{193} \indexentry{MSMD_order@{\tt MSMD\_order()}}{193} \indexentry{MSMD_fillPerms@{\tt MSMD\_fillPerms()}}{194} \indexentry{MSMD_frontETree@{\tt MSMD\_frontETree()}}{194} \indexentry{MSMD_eliminateStage@{\tt MSMD\_eliminateStage()}}{194} \indexentry{MSMD_eliminateStep@{\tt MSMD\_eliminateStep()}}{194} \indexentry{MSMD_eliminateVtx@{\tt MSMD\_eliminateVtx()}}{194} \indexentry{MSMD_findInodes@{\tt MSMD\_findInodes()}}{194} \indexentry{MSMD_cleanReachSet@{\tt MSMD\_cleanReachSet()}}{194} \indexentry{MSMD_cleanSubtreeList@{\tt MSMD\_cleanSubtreeList()}}{194} \indexentry{MSMD_cleanEdgeList@{\tt MSMD\_cleanEdgeList()}}{195} \indexentry{MSMD_update@{\tt MSMD\_update()}}{195} \indexentry{MSMD_exactDegree2@{\tt MSMD\_exactDegree2()}}{195} \indexentry{MSMD_exactDegree3@{\tt MSMD\_exactDegree3()}}{195} \indexentry{MSMD_approxDegree@{\tt MSMD\_approxDegree()}}{195} \indexentry{MSMD_makeSchurComplement@{\tt MSMD\_makeSchurComplement()}}{195} \indexentry{MSMDvtx_print@{\tt MSMDvtx\_print()}}{195} \indexentry{Network_new@{\tt Network\_new()}}{200} \indexentry{Network_setDefaultFields@{\tt Network\_setDefaultFields()}}{200} \indexentry{Network_clearData@{\tt Network\_clearData()}}{200} \indexentry{Network_free@{\tt Network\_free()}}{200} \indexentry{Network_init@{\tt Network\_init()}}{201} \indexentry{Network_setMessageInfo@{\tt Network\_setMessageInfo()}}{201} \indexentry{Network_addArc@{\tt Network\_addArc()}}{201} \indexentry{Network_findMaxFlow@{\tt Network\_findMaxFlow()}}{201} \indexentry{Network_findAugmentingPath@{\tt Network\_findAugmentingPath()}}{201} \indexentry{Network_augmentPath@{\tt Network\_augmentPath()}}{201} \indexentry{Network_findMincutFromSource@{\tt Network\_findMincutFromSource()}}{202} \indexentry{Network_findMincutFromSink@{\tt Network\_findMincutFromSink()}}{202} \indexentry{Network_writeForHumanEye@{\tt Network\_writeForHumanEye()}}{202} \indexentry{Network_writeStats@{\tt Network\_writeStats()}}{202} \indexentry{SolveMap_new@{\tt SolveMap\_new()}}{204} \indexentry{SolveMap_setDefaultFields@{\tt SolveMap\_setDefaultFields()}}{204} \indexentry{SolveMap_clearData@{\tt SolveMap\_clearData()}}{204} \indexentry{SolveMap_free@{\tt SolveMap\_free()}}{204} \indexentry{SolveMap_symmetryflag@{\tt SolveMap\_symmetryflag()}}{204} \indexentry{SolveMap_nfront@{\tt SolveMap\_nfront()}}{204} \indexentry{SolveMap_nproc@{\tt SolveMap\_nproc()}}{204} \indexentry{SolveMap_nblockUpper@{\tt SolveMap\_nblockUpper()}}{204} \indexentry{SolveMap_nblockLower@{\tt SolveMap\_nblockLower()}}{205} \indexentry{SolveMap_owners@{\tt SolveMap\_owners()}}{205} \indexentry{SolveMap_rowidsUpper@{\tt SolveMap\_rowidsUpper()}}{205} \indexentry{SolveMap_colidsUpper@{\tt SolveMap\_colidsUpper()}}{205} \indexentry{SolveMap_mapUpper@{\tt SolveMap\_mapUpper()}}{205} \indexentry{SolveMap_rowidsLower@{\tt SolveMap\_rowidsLower()}}{205} \indexentry{SolveMap_colidsLower@{\tt SolveMap\_colidsLower()}}{205} \indexentry{SolveMap_mapLower@{\tt SolveMap\_mapLower()}}{205} \indexentry{SolveMap_init@{\tt SolveMap\_init()}}{205} \indexentry{SolveMap_randomMap@{\tt SolveMap\_randomMap()}}{206} \indexentry{SolveMap_ddMap@{\tt SolveMap\_ddMap()}}{206} \indexentry{SolveMap_forwardSetup@{\tt SolveMap\_forwardSetup()}}{206} \indexentry{SolveMap_backwardSetup@{\tt SolveMap\_backwardSetup()}}{206} \indexentry{SolveMap_owners@{\tt SolveMap\_owners()}}{206} \indexentry{SolveMap_upperSolveIVL@{\tt SolveMap\_upperSolveIVL()}}{206} \indexentry{SolveMap_lowerSolveIVL@{\tt SolveMap\_lowerSolveIVL()}}{206} \indexentry{SolveMap_upperAggregateIV@{\tt SolveMap\_upperAggregateIV()}}{207} \indexentry{SolveMap_lowerAggregateIV@{\tt SolveMap\_lowerAggregateIV()}}{207} \indexentry{SolveMap_readFromFile@{\tt SolveMap\_readFromFile()}}{207} \indexentry{SolveMap_readFromFormattedFile@{\tt SolveMap\_readFromFormattedFile()}}{207} \indexentry{SolveMap_readFromBinaryFile@{\tt SolveMap\_readFromBinaryFile()}}{207} \indexentry{SolveMap_writeToFile@{\tt SolveMap\_writeToFile()}}{207} \indexentry{SolveMap_writeToFormattedFile@{\tt SolveMap\_writeToFormattedFile()}}{208} \indexentry{SolveMap_writeToBinaryFile@{\tt SolveMap\_writeToBinaryFile()}}{208} \indexentry{SolveMap_writeForHumanEye@{\tt SolveMap\_writeForHumanEye()}}{208} \indexentry{SolveMap_writeStats@{\tt SolveMap\_writeStats()}}{208} \indexentry{Tree_new@{\tt Tree\_new()}}{210} \indexentry{Tree_setDefaultFields@{\tt Tree\_setDefaultFields()}}{210} \indexentry{Tree_clearData@{\tt Tree\_clearData()}}{210} \indexentry{Tree_free@{\tt Tree\_free()}}{210} \indexentry{Tree_nnodes@{\tt Tree\_nnodes()}}{210} \indexentry{Tree_root@{\tt Tree\_root()}}{210} \indexentry{Tree_par@{\tt Tree\_par()}}{210} \indexentry{Tree_fch@{\tt Tree\_fch()}}{210} \indexentry{Tree_sib@{\tt Tree\_sib()}}{210} \indexentry{Tree_init1@{\tt Tree\_init1()}}{211} \indexentry{Tree_init2@{\tt Tree\_init2()}}{211} \indexentry{Tree_init3@{\tt Tree\_init3()}}{211} \indexentry{Tree_initFromSubtree@{\tt Tree\_initFromSubtree()}}{211} \indexentry{Tree_setFchSibRoot@{\tt Tree\_setFchSibRoot()}}{211} \indexentry{Tree_setRoot@{\tt Tree\_setRoot()}}{211} \indexentry{Tree_sizeOf@{\tt Tree\_sizeOf()}}{212} \indexentry{Tree_postOTfirst@{\tt Tree\_postOTfirst()}}{212} \indexentry{Tree_postOTnext@{\tt Tree\_postOTnext()}}{212} \indexentry{Tree_preOTfirst@{\tt Tree\_preOTfirst()}}{212} \indexentry{Tree_preOTnext@{\tt Tree\_preOTnext()}}{212} \indexentry{Tree_nleaves@{\tt Tree\_nleaves()}}{212} \indexentry{Tree_nroots@{\tt Tree\_nroots()}}{212} \indexentry{Tree_nchild@{\tt Tree\_nchild()}}{212} \indexentry{Tree_nchildIV@{\tt Tree\_nchildIV()}}{212} \indexentry{Tree_maxNchild@{\tt Tree\_maxNchild()}}{212} \indexentry{Tree_height@{\tt Tree\_height()}}{212} \indexentry{Tree_maximizeGainIV@{\tt Tree\_maximizeGainIV()}}{213} \indexentry{Tree_setSubtreeImetric@{\tt Tree\_setSubtreeImetric()}}{213} \indexentry{Tree_setSubtreeDmetric@{\tt Tree\_setSubtreeDmetric()}}{213} \indexentry{Tree_setDepthImetric@{\tt Tree\_setDepthImetric()}}{213} \indexentry{Tree_setDepthDmetric@{\tt Tree\_setDepthDmetric()}}{213} \indexentry{Tree_setHeightImetric@{\tt Tree\_setHeightImetric()}}{213} \indexentry{Tree_setHeightDmetric@{\tt Tree\_setHeightDmetric()}}{213} \indexentry{Tree_fundChainMap@{\tt Tree\_fundChainMap()}}{214} \indexentry{Tree_compress@{\tt Tree\_compress()}}{214} \indexentry{Tree_leftJustify@{\tt Tree\_leftJustify()}}{214} \indexentry{Tree_leftJustifyI@{\tt Tree\_leftJustifyI()}}{214} \indexentry{Tree_leftJustifyD@{\tt Tree\_leftJustifyD()}}{214} \indexentry{Tree_fillNewToOldPerm@{\tt Tree\_fillNewToOldPerm()}}{215} \indexentry{Tree_fillOldToNewPerm@{\tt Tree\_fillOldToNewPerm()}}{215} \indexentry{Tree_fillBothPerms@{\tt Tree\_fillBothPerms()}}{215} \indexentry{Tree_permute@{\tt Tree\_permute()}}{215} \indexentry{Tree_getSimpleCoords@{\tt Tree\_getSimpleCoords()}}{215} \indexentry{Tree_drawToEPS@{\tt Tree\_drawToEPS()}}{215} \indexentry{Tree_readFromFile@{\tt Tree\_readFromFile()}}{216} \indexentry{Tree_readFromFormattedFile@{\tt Tree\_readFromFormattedFile()}}{216} \indexentry{Tree_readFromBinaryFile@{\tt Tree\_readFromBinaryFile()}}{216} \indexentry{Tree_writeToFile@{\tt Tree\_writeToFile()}}{216} \indexentry{Tree_writeToFormattedFile@{\tt Tree\_writeToFormattedFile()}}{216} \indexentry{Tree_writeToBinaryFile@{\tt Tree\_writeToBinaryFile()}}{216} \indexentry{Tree_writeForHumanEye@{\tt Tree\_writeForHumanEye()}}{217} \indexentry{Tree_writeStats@{\tt Tree\_writeStats()}}{217} \indexentry{Chv_new@{\tt Chv\_new()}}{224} \indexentry{Chv_setDefaultFields@{\tt Chv\_setDefaultFields()}}{224} \indexentry{Chv_clearData@{\tt Chv\_clearData()}}{224} \indexentry{Chv_free@{\tt Chv\_free()}}{224} \indexentry{Chv_id@{\tt Chv\_id()}}{224} \indexentry{Chv_type@{\tt Chv\_type()}}{224} \indexentry{Chv_symmetryFlag@{\tt Chv\_symmetryFlag()}}{224} \indexentry{Chv_dimensions@{\tt Chv\_dimensions()}}{224} \indexentry{Chv_rowIndices@{\tt Chv\_rowIndices()}}{225} \indexentry{Chv_columnIndices@{\tt Chv\_columnIndices()}}{225} \indexentry{Chv_nent@{\tt Chv\_nent()}}{225} \indexentry{Chv_entries@{\tt Chv\_entries()}}{225} \indexentry{Chv_diagLocation@{\tt Chv\_diagLocation()}}{225} \indexentry{Chv_workspace@{\tt Chv\_workspace()}}{225} \indexentry{Chv_realEntry@{\tt Chv\_realEntry()}}{225} \indexentry{Chv_locationOfRealEntry@{\tt Chv\_locationOfRealEntry()}}{225} \indexentry{Chv_setRealEntry@{\tt Chv\_setRealEntry()}}{225} \indexentry{Chv_complexEntry@{\tt Chv\_complexEntry()}}{226} \indexentry{Chv_locationOfComplexEntry@{\tt Chv\_locationOfComplexEntry()}}{226} \indexentry{Chv_setComplexEntry@{\tt Chv\_setComplexEntry()}}{226} \indexentry{Chv_init@{\tt Chv\_init()}}{226} \indexentry{Chv_initWithPointers@{\tt Chv\_initWithPointers()}}{226} \indexentry{Chv_initFromBuffer@{\tt Chv\_initFromBuffer()}}{226} \indexentry{Chv_maxabsInDiagonal11@{\tt Chv\_maxabsInDiagonal11()}}{227} \indexentry{Chv_maxabsInRow11@{\tt Chv\_maxabsInRow11()}}{227} \indexentry{Chv_maxabsInColumn11@{\tt Chv\_maxabsInColumn11()}}{227} \indexentry{Chv_maxabsInRow@{\tt Chv\_maxabsInRow()}}{227} \indexentry{Chv_maxabsInColumn@{\tt Chv\_maxabsInColumn()}}{227} \indexentry{Chv_quasimax@{\tt Chv\_quasimax()}}{227} \indexentry{Chv_fastBunchParlettPivot@{\tt Chv\_fastBunchParlettPivot()}}{228} \indexentry{Chv_findPivot@{\tt Chv\_findPivot()}}{228} \indexentry{Chv_updateS@{\tt Chv\_updateS()}}{228} \indexentry{Chv_updateH@{\tt Chv\_updateH()}}{228} \indexentry{Chv_updateN@{\tt Chv\_updateN()}}{228} \indexentry{Chv_addChevron@{\tt Chv\_addChevron()}}{229} \indexentry{Chv_assembleChv@{\tt Chv\_assembleChv()}}{229} \indexentry{Chv_assemblePostponedData@{\tt Chv\_assemblePostponedData()}}{229} \indexentry{Chv_factorWithPivoting@{\tt Chv\_factorWithPivoting()}}{229} \indexentry{Chv_factorWithNoPivoting@{\tt Chv\_factorWithNoPivoting()}}{230} \indexentry{Chv_r1upd@{\tt Chv\_r1upd()}}{230} \indexentry{Chv_r2upd@{\tt Chv\_r2upd()}}{230} \indexentry{Chv_maxabsInChevron@{\tt Chv\_maxabsInChevron()}}{230} \indexentry{Chv_zeroOffdiagonalOfChevron@{\tt Chv\_zeroOffdiagonalOfChevron()}}{230} \indexentry{Chv_countEntries@{\tt Chv\_countEntries()}}{230} \indexentry{Chv_countBigEntries@{\tt Chv\_countBigEntries()}}{231} \indexentry{Chv_copyEntriesToVector@{\tt Chv\_copyEntriesToVector()}}{231} \indexentry{Chv_copyBigEntriesToVector@{\tt Chv\_copyBigEntriesToVector()}}{232} \indexentry{Chv_copyTrailingPortion@{\tt Chv\_copyTrailingPortion()}}{232} \indexentry{Chv_swapRows@{\tt Chv\_swapRows()}}{232} \indexentry{Chv_swapColumns@{\tt Chv\_swapColumns()}}{233} \indexentry{Chv_swapRowsAndColumns@{\tt Chv\_swapRowsAndColumns()}}{233} \indexentry{Chv_nbytesNeeded@{\tt Chv\_nbytesNeeded()}}{233} \indexentry{Chv_nbytesInWorkspace@{\tt Chv\_nbytesInWorkspace()}}{233} \indexentry{Chv_setNbytesInWorkspace@{\tt Chv\_setNbytesInWorkspace()}}{233} \indexentry{Chv_setFields@{\tt Chv\_setFields()}}{233} \indexentry{Chv_shift@{\tt Chv\_shift()}}{233} \indexentry{Chv_fill11block@{\tt Chv\_fill11block()}}{234} \indexentry{Chv_fill12block@{\tt Chv\_fill12block()}}{234} \indexentry{Chv_fill21block@{\tt Chv\_fill21block()}}{234} \indexentry{Chv_maxabs@{\tt Chv\_maxabs()}}{234} \indexentry{Chv_frobNorm@{\tt Chv\_frobNorm()}}{234} \indexentry{Chv_sub@{\tt Chv\_sub()}}{234} \indexentry{Chv_zero@{\tt Chv\_zero()}}{234} \indexentry{Chv_writeForHumanEye@{\tt Chv\_writeForHumanEye()}}{234} \indexentry{Chv_writeForMatlab@{\tt Chv\_writeForMatlab()}}{234} \indexentry{ChvList_new@{\tt ChvList\_new()}}{241} \indexentry{ChvList_setDefaultFields@{\tt ChvList\_setDefaultFields()}}{241} \indexentry{ChvList_clearData@{\tt ChvList\_clearData()}}{241} \indexentry{ChvList_free@{\tt ChvList\_free()}}{241} \indexentry{ChvList_init@{\tt ChvList\_init()}}{242} \indexentry{ChvList_isListNonempty@{\tt ChvList\_isListNonempty()}}{242} \indexentry{ChvList_isCountZero@{\tt ChvList\_isCountZero()}}{242} \indexentry{ChvList_getList@{\tt ChvList\_getList()}}{242} \indexentry{ChvList_addObjectToList@{\tt ChvList\_addObjectToList()}}{242} \indexentry{ChvList_writeForHumanEye@{\tt ChvList\_writeForHumanEye()}}{242} \indexentry{ChvManager_new@{\tt ChvManager\_new()}}{244} \indexentry{ChvManager_setDefaultFields@{\tt ChvManager\_setDefaultFields()}}{244} \indexentry{ChvManager_clearData@{\tt ChvManager\_clearData()}}{244} \indexentry{ChvManager_free@{\tt ChvManager\_free()}}{245} \indexentry{ChvManager_init@{\tt ChvManager\_init()}}{245} \indexentry{ChvManager_newObjectOfSizeNbytes@{\tt ChvManager\_newObjectOfSizeNbytes()}}{245} \indexentry{ChvManager_releaseObject@{\tt ChvManager\_releaseObject()}}{245} \indexentry{ChvManager_releaseListOfObjects@{\tt ChvManager\_releaseListOfObjects()}}{245} \indexentry{ChvManager_writeForHumanEye@{\tt ChvManager\_writeForHumanEye()}}{245} \indexentry{DenseMtx_new@{\tt DenseMtx\_new()}}{247} \indexentry{DenseMtx_setDefaultFields@{\tt DenseMtx\_setDefaultFields()}}{247} \indexentry{DenseMtx_clearData@{\tt DenseMtx\_clearData()}}{247} \indexentry{DenseMtx_free@{\tt DenseMtx\_free()}}{247} \indexentry{DenseMtx_rowid@{\tt DenseMtx\_rowid()}}{247} \indexentry{DenseMtx_colid@{\tt DenseMtx\_colid()}}{247} \indexentry{DenseMtx_dimensions@{\tt DenseMtx\_dimensions()}}{247} \indexentry{DenseMtx_columnIncrement@{\tt DenseMtx\_columnIncrement()}}{247} \indexentry{DenseMtx_rowIncrement@{\tt DenseMtx\_rowIncrement()}}{248} \indexentry{DenseMtx_rowIndices@{\tt DenseMtx\_rowIndices()}}{248} \indexentry{DenseMtx_columnIndices@{\tt DenseMtx\_columnIndices()}}{248} \indexentry{DenseMtx_entries@{\tt DenseMtx\_entries()}}{248} \indexentry{DenseMtx_workspace@{\tt DenseMtx\_workspace()}}{248} \indexentry{DenseMtx_realEntry@{\tt DenseMtx\_realEntry()}}{248} \indexentry{DenseMtx_complexEntry@{\tt DenseMtx\_complexEntry()}}{248} \indexentry{DenseMtx_setRealEntry@{\tt DenseMtx\_setRealEntry()}}{248} \indexentry{DenseMtx_setComplexEntry@{\tt DenseMtx\_setComplexEntry()}}{248} \indexentry{DenseMtx_row@{\tt DenseMtx\_row()}}{249} \indexentry{DenseMtx_column@{\tt DenseMtx\_column()}}{249} \indexentry{DenseMtx_init@{\tt DenseMtx\_init()}}{249} \indexentry{DenseMtx_initWithPointers@{\tt DenseMtx\_initWithPointers()}}{249} \indexentry{DenseMtx_initAsSubmatrix@{\tt DenseMtx\_initAsSubmatrix()}}{249} \indexentry{DenseMtx_initFromBuffer@{\tt DenseMtx\_initFromBuffer()}}{249} \indexentry{DenseMtx_setA2@{\tt DenseMtx\_setA2()}}{249} \indexentry{DenseMtx_nbytesNeeded@{\tt DenseMtx\_nbytesNeeded()}}{250} \indexentry{DenseMtx_nbytesInWorkspace@{\tt DenseMtx\_nbytesInWorkspace()}}{250} \indexentry{DenseMtx_setNbytesInWorkspace@{\tt DenseMtx\_setNbytesInWorkspace()}}{250} \indexentry{DenseMtx_setFields@{\tt DenseMtx\_setFields()}}{250} \indexentry{DenseMtx_permuteRows@{\tt DenseMtx\_permuteRows()}}{250} \indexentry{DenseMtx_permuteColumns@{\tt DenseMtx\_permuteColumns()}}{250} \indexentry{DenseMtx_sort@{\tt DenseMtx\_sort()}}{250} \indexentry{DenseMtx_copyRow@{\tt DenseMtx\_copyRow()}}{250} \indexentry{DenseMtx_copyRowAndIndex@{\tt DenseMtx\_copyRowAndIndex()}}{250} \indexentry{DenseMtx_addRow@{\tt DenseMtx\_addRow()}}{251} \indexentry{DenseMtx_zero@{\tt DenseMtx\_zero()}}{251} \indexentry{DenseMtx_fillRandomEntries@{\tt DenseMtx\_fillRandomEntries()}}{251} \indexentry{DenseMtx_checksums@{\tt DenseMtx\_checksums()}}{251} \indexentry{DenseMtx_scale@{\tt DenseMtx\_scale()}}{251} \indexentry{DenseMtx_maxabs@{\tt DenseMtx\_maxabs()}}{251} \indexentry{DenseMtx_sub@{\tt DenseMtx\_sub()}}{251} \indexentry{DenseMtx_copyRowIntoVector@{\tt DenseMtx\_copyRowIntoVector()}}{251} \indexentry{DenseMtx_copyVectorIntoRow@{\tt DenseMtx\_copyVectorIntoRow()}}{251} \indexentry{DenseMtx_addVectorIntoRow@{\tt DenseMtx\_addVectorIntoRow()}}{251} \indexentry{DenseMtx_readFromFile@{\tt DenseMtx\_readFromFile()}}{252} \indexentry{DenseMtx_readFromFormattedFile@{\tt DenseMtx\_readFromFormattedFile()}}{252} \indexentry{DenseMtx_readFromBinaryFile@{\tt DenseMtx\_readFromBinaryFile()}}{252} \indexentry{DenseMtx_writeToFile@{\tt DenseMtx\_writeToFile()}}{252} \indexentry{DenseMtx_writeToFormattedFile@{\tt DenseMtx\_writeToFormattedFile()}}{252} \indexentry{DenseMtx_writeToBinaryFile@{\tt DenseMtx\_writeToBinaryFile()}}{252} \indexentry{DenseMtx_writeStats@{\tt DenseMtx\_writeStats()}}{252} \indexentry{DenseMtx_writeForHumanEye@{\tt DenseMtx\_writeForHumanEye()}}{252} \indexentry{DenseMtx_writeForMatlab@{\tt DenseMtx\_writeForMatlab()}}{253} \indexentry{FrontMtx_new@{\tt FrontMtx\_new()}}{259} \indexentry{FrontMtx_setDefaultFields@{\tt FrontMtx\_setDefaultFields()}}{259} \indexentry{FrontMtx_clearData@{\tt FrontMtx\_clearData()}}{259} \indexentry{FrontMtx_free@{\tt FrontMtx\_free()}}{259} \indexentry{FrontMtx_nfront@{\tt FrontMtx\_nfront()}}{259} \indexentry{FrontMtx_neqns@{\tt FrontMtx\_neqns()}}{259} \indexentry{FrontMtx_frontTree@{\tt FrontMtx\_frontTree()}}{260} \indexentry{FrontMtx_initialFrontDimensions@{\tt FrontMtx\_initialFrontDimensions()}}{260} \indexentry{FrontMtx_frontSize@{\tt FrontMtx\_frontSize()}}{260} \indexentry{FrontMtx_setFrontsize@{\tt FrontMtx\_setFrontSize()}}{260} \indexentry{FrontMtx_columnIndices@{\tt FrontMtx\_columnIndices()}}{260} \indexentry{FrontMtx_rowIndices@{\tt FrontMtx\_rowIndices()}}{260} \indexentry{FrontMtx_diagMtx@{\tt FrontMtx\_diagMtx()}}{260} \indexentry{FrontMtx_upperMtx@{\tt FrontMtx\_upperMtx()}}{260} \indexentry{FrontMtx_lowerMtx@{\tt FrontMtx\_lowerMtx()}}{261} \indexentry{FrontMtx_lowerAdjFronts@{\tt FrontMtx\_lowerAdjFronts()}}{261} \indexentry{FrontMtx_upperAdjFronts@{\tt FrontMtx\_upperAdjFronts()}}{261} \indexentry{FrontMtx_nLowerBlocks@{\tt FrontMtx\_nLowerBlocks()}}{261} \indexentry{FrontMtx_nUpperBlocks@{\tt FrontMtx\_nUpperBlocks()}}{261} \indexentry{FrontMtx_upperBlockIVL@{\tt FrontMtx\_upperBlockIVL()}}{261} \indexentry{FrontMtx_lowerBlockIVL@{\tt FrontMtx\_lowerBlockIVL()}}{261} \indexentry{FrontMtx_init@{\tt FrontMtx\_init()}}{261} \indexentry{FrontMtx_initializeFront@{\tt FrontMtx\_initializeFront()}}{262} \indexentry{FrontMtx_factorVisit@{\tt FrontMtx\_factorVisit()}}{262} \indexentry{FrontMtx_setupFront@{\tt FrontMtx\_setupFront()}}{262} \indexentry{FrontMtx_factorSetup@{\tt FrontMtx\_factorSetup()}}{262} \indexentry{FrontMtx_nactiveChild@{\tt FrontMtx\_nactiveChild()}}{263} \indexentry{FrontMtx_nactiveChild@{\tt FrontMtx\_nactiveChild()}}{263} \indexentry{FrontMtx_loadActiveLeaves@{\tt FrontMtx\_loadActiveLeaves()}}{263} \indexentry{FrontMtx_postList@{\tt FrontMtx\_postList()}}{263} \indexentry{FrontMtx_aggregateList@{\tt FrontMtx\_aggregateList()}}{263} \indexentry{FrontMtx_loadEntries@{\tt FrontMtx\_loadEntries()}}{263} \indexentry{FrontMtx_update@{\tt FrontMtx\_update()}}{263} \indexentry{FrontMtx_assemblePostponedData@{\tt FrontMtx\_assemblePostponedData()}}{264} \indexentry{FrontMtx_storePostponedData@{\tt FrontMtx\_storePostponedData()}}{264} \indexentry{FrontMtx_storeFront@{\tt FrontMtx\_storeFront()}}{264} \indexentry{FrontMtx_factorInpMtx@{\tt FrontMtx\_factorInpMtx()}}{264} \indexentry{FrontMtx_factorPencil@{\tt FrontMtx\_factorPencil()}}{264} \indexentry{FrontMtx_QR_setup@{\tt FrontMtx\_QR\_setup()}}{265} \indexentry{FrontMtx_QR_factorVisit@{\tt FrontMtx\_QR\_factorVisit()}}{265} \indexentry{FrontMtx_QR_assembleFront@{\tt FrontMtx\_QR\_assembleFront()}}{265} \indexentry{FrontMtx_QR_storeFront@{\tt FrontMtx\_QR\_storeFront()}}{266} \indexentry{FrontMtx_QR_storeUpdate@{\tt FrontMtx\_QR\_storeUpdate()}}{266} \indexentry{FrontMtx_QR_factor@{\tt FrontMtx\_QR\_factor()}}{266} \indexentry{FrontMtx_postProcess@{\tt FrontMtx\_postProcess()}}{266} \indexentry{FrontMtx_permuteUpperAdj@{\tt FrontMtx\_permuteUpperAdj()}}{267} \indexentry{FrontMtx_permuteLowerAdj@{\tt FrontMtx\_permuteLowerAdj()}}{267} \indexentry{FrontMtx_permuteUpperMatrices@{\tt FrontMtx\_permuteUpperMatrices()}}{267} \indexentry{FrontMtx_permuteLowerMatrices@{\tt FrontMtx\_permuteLowerMatrices()}}{267} \indexentry{FrontMtx_splitUpperMatrices@{\tt FrontMtx\_splitUpperMatrices()}}{267} \indexentry{FrontMtx_splitLowerMatrices@{\tt FrontMtx\_splitLowerMatrices()}}{267} \indexentry{FrontMtx_loadRightHandSide@{\tt FrontMtx\_loadRightHandSide()}}{267} \indexentry{FrontMtx_forwardVisit@{\tt FrontMtx\_forwardVisit()}}{267} \indexentry{FrontMtx_diagonalVisit@{\tt FrontMtx\_diagonalVisit()}}{267} \indexentry{FrontMtx_backwardVisit@{\tt FrontMtx\_backwardVisit()}}{268} \indexentry{FrontMtx_storeSolution@{\tt FrontMtx\_storeSolution()}}{268} \indexentry{FrontMtx_forwardSetup@{\tt FrontMtx\_forwardSetup()}}{268} \indexentry{FrontMtx_backwardSetup@{\tt FrontMtx\_backwardSetup()}}{268} \indexentry{FrontMtx_loadActiveRoots@{\tt FrontMtx\_loadActiveRoots()}}{268} \indexentry{FrontMtx_solve@{\tt FrontMtx\_solve()}}{268} \indexentry{FrontMtx_QR_solve@{\tt FrontMtx\_QR\_solve()}}{269} \indexentry{FrontMtx_colmapIV@{\tt FrontMtx\_colmapIV()}}{269} \indexentry{FrontMtx_rowmapIV@{\tt FrontMtx\_rowmapIV()}}{269} \indexentry{FrontMtx_ownedColumns@{\tt FrontMtx\_ownedColumns()}}{269} \indexentry{FrontMtx_ownedRows@{\tt FrontMtx\_ownedRows()}}{269} \indexentry{FrontMtx_makeUpperBlockIVL@{\tt FrontMtx\_makeUpperBlockIVL()}}{269} \indexentry{FrontMtx_makeLowerBlockIVL@{\tt FrontMtx\_makeLowerBlockIVL()}}{269} \indexentry{FrontMtx_inertia@{\tt FrontMtx\_inertia()}}{270} \indexentry{FrontMtx_nSolveOps@{\tt FrontMtx\_nSolveOps()}}{270} \indexentry{FrontMtx_readFromFile@{\tt FrontMtx\_readFromFile()}}{270} \indexentry{FrontMtx_readFromFormattedFile@{\tt FrontMtx\_readFromFormattedFile()}}{270} \indexentry{FrontMtx_readFromBinaryFile@{\tt FrontMtx\_readFromBinaryFile()}}{270} \indexentry{FrontMtx_writeToFile@{\tt FrontMtx\_writeToFile()}}{270} \indexentry{FrontMtx_writeToFormattedFile@{\tt FrontMtx\_writeToFormattedFile()}}{270} \indexentry{FrontMtx_writeToBinaryFile@{\tt FrontMtx\_writeToBinaryFile()}}{271} \indexentry{FrontMtx_writeForHumanEye@{\tt FrontMtx\_writeForHumanEye()}}{271} \indexentry{FrontMtx_writeStats@{\tt FrontMtx\_writeStats()}}{271} \indexentry{FrontMtx_writeForMatlab@{\tt FrontMtx\_writeForMatlab()}}{271} \indexentry{ILUMtx_new@{\tt ILUMtx\_new()}}{274} \indexentry{ILUMtx_setDefaultFields@{\tt ILUMtx\_setDefaultFields()}}{274} \indexentry{ILUMtx_clearData@{\tt ILUMtx\_clearData()}}{274} \indexentry{ILUMtx_free@{\tt ILUMtx\_free()}}{274} \indexentry{ILUMtx_init@{\tt ILUMtx\_init()}}{275} \indexentry{ILUMtx_factor@{\tt ILUMtx\_factor()}}{275} \indexentry{ILUMtx_solveVector@{\tt ILUMtx\_solveVector()}}{275} \indexentry{ILUMtx_fillRandom@{\tt ILUMtx\_fillRandom()}}{276} \indexentry{ILUMtx_writeForMatlab@{\tt ILUMtx\_writeForMatlab()}}{276} \indexentry{InpMtx_new@{\tt InpMtx\_new()}}{281} \indexentry{InpMtx_setDefaultFields@{\tt InpMtx\_setDefaultFields()}}{281} \indexentry{InpMtx_clearData@{\tt InpMtx\_clearData()}}{281} \indexentry{InpMtx_free@{\tt InpMtx\_free()}}{281} \indexentry{InpMtx_coordType@{\tt InpMtx\_coordType()}}{281} \indexentry{InpMtx_storageMode@{\tt InpMtx\_storageMode()}}{282} \indexentry{InpMtx_inputMode@{\tt InpMtx\_inputMode()}}{282} \indexentry{InpMtx_maxnent@{\tt InpMtx\_maxnent()}}{282} \indexentry{InpMtx_nent@{\tt InpMtx\_nent()}}{282} \indexentry{InpMtx_maxnvector@{\tt InpMtx\_maxnvector()}}{282} \indexentry{InpMtx_nvector@{\tt InpMtx\_nvector()}}{282} \indexentry{InpMtx_resizeMultiple@{\tt InpMtx\_resizeMultiple()}}{282} \indexentry{InpMtx_ivec1@{\tt InpMtx\_ivec1()}}{282} \indexentry{InpMtx_ivec2@{\tt InpMtx\_ivec2()}}{282} \indexentry{InpMtx_dvec@{\tt InpMtx\_dvec()}}{283} \indexentry{InpMtx_vecids@{\tt InpMtx\_vecids()}}{283} \indexentry{InpMtx_sizes@{\tt InpMtx\_sizes()}}{283} \indexentry{InpMtx_offsets@{\tt InpMtx\_offsets()}}{283} \indexentry{InpMtx_vector@{\tt InpMtx\_vector()}}{283} \indexentry{InpMtx_realVector@{\tt InpMtx\_realVector()}}{283} \indexentry{InpMtx_complexVector@{\tt InpMtx\_complexVector()}}{283} \indexentry{InpMtx_range@{\tt InpMtx\_range()}}{283} \indexentry{InpMtx_setMaxnent@{\tt InpMtx\_setMaxnent()}}{283} \indexentry{InpMtx_setNent@{\tt InpMtx\_setNent()}}{283} \indexentry{InpMtx_setMaxnvector@{\tt InpMtx\_setMaxnvector()}}{284} \indexentry{InpMtx_setNvector@{\tt InpMtx\_setNvector()}}{284} \indexentry{InpMtx_setResizeMultiple@{\tt InpMtx\_setResizeMultiple()}}{284} \indexentry{InpMtx_setCoordType@{\tt InpMtx\_setCoordType()}}{284} \indexentry{InpMtx_init@{\tt InpMtx\_init()}}{284} \indexentry{InpMtx_changeCoordType@{\tt InpMtx\_changeCoordType()}}{284} \indexentry{InpMtx_changeStorageMode@{\tt InpMtx\_changeStorageMode()}}{284} \indexentry{InpMtx_inputEntry@{\tt InpMtx\_inputEntry()}}{285} \indexentry{InpMtx_inputRealEntry@{\tt InpMtx\_inputRealEntry()}}{285} \indexentry{InpMtx_inputComplexEntry@{\tt InpMtx\_inputComplexEntry()}}{285} \indexentry{InpMtx_inputRow@{\tt InpMtx\_inputRow()}}{285} \indexentry{InpMtx_inputRealRow@{\tt InpMtx\_inputRealRow()}}{285} \indexentry{InpMtx_inputComplexRow@{\tt InpMtx\_inputComplexRow()}}{285} \indexentry{InpMtx_inputColumn@{\tt InpMtx\_inputColumn()}}{285} \indexentry{InpMtx_inputRealColumn@{\tt InpMtx\_inputRealColumn()}}{285} \indexentry{InpMtx_inputComplexColumn@{\tt InpMtx\_inputComplexColumn()}}{285} \indexentry{InpMtx_inputChevron@{\tt InpMtx\_inputChevron()}}{285} \indexentry{InpMtx_inputRealChevron@{\tt InpMtx\_inputRealChevron()}}{285} \indexentry{InpMtx_inputComplexChevron@{\tt InpMtx\_inputComplexChevron()}}{285} \indexentry{InpMtx_inputMatrix@{\tt InpMtx\_inputMatrix()}}{286} \indexentry{InpMtx_inputRealMatrix@{\tt InpMtx\_inputRealMatrix()}}{286} \indexentry{InpMtx_inputComplexMatrix@{\tt InpMtx\_inputComplexMatrix()}}{286} \indexentry{InpMtx_inputTriples@{\tt InpMtx\_inputTriples()}}{286} \indexentry{InpMtx_inputRealTriples@{\tt InpMtx\_inputRealTriples()}}{286} \indexentry{InpMtx_inputComplexTriples@{\tt InpMtx\_inputComplexTriples()}}{286} \indexentry{InpMtx_supportNonsym@{\tt InpMtx\_supportNonsym()}}{286} \indexentry{InpMtx_supportNonsymT@{\tt InpMtx\_supportNonsymT()}}{286} \indexentry{InpMtx_supportNonsymH@{\tt InpMtx\_supportNonsymH()}}{286} \indexentry{InpMtx_supportSym@{\tt InpMtx\_supportSym()}}{286} \indexentry{InpMtx_supportSymH@{\tt InpMtx\_supportSymH()}}{286} \indexentry{InpMtx_mapEntries@{\tt InpMtx\_mapEntries()}}{286} \indexentry{InpMtx_permute@{\tt InpMtx\_permute()}}{287} \indexentry{InpMtx_nonsym_mmm@{\tt InpMtx\_nonsym\_mmm()}}{287} \indexentry{InpMtx_sym_mmm@{\tt InpMtx\_sym\_mmm()}}{287} \indexentry{InpMtx_herm_mmm@{\tt InpMtx\_herm\_mmm()}}{287} \indexentry{InpMtx_nonsym_mmm_T@{\tt InpMtx\_nonsym\_mmm\_T()}}{287} \indexentry{InpMtx_nonsym_mmm_H@{\tt InpMtx\_nonsym\_mmm\_H()}}{287} \indexentry{InpMtx_nonsym_mmmVector@{\tt InpMtx\_nonsym\_mmmVector()}}{288} \indexentry{InpMtx_sym_mmmVector@{\tt InpMtx\_sym\_mmmVector()}}{288} \indexentry{InpMtx_herm_mmmVector@{\tt InpMtx\_herm\_mmmVector()}}{288} \indexentry{InpMtx_nonsym_mmmVector_T@{\tt InpMtx\_nonsym\_mmmVector\_T()}}{288} \indexentry{InpMtx_nonsym_mmmVector_H@{\tt InpMtx\_nonsym\_mmmVector\_H()}}{288} \indexentry{InpMtx_nonsym_gmmm@{\tt InpMtx\_nonsym\_gmmm()}}{288} \indexentry{InpMtx_sym_gmmm@{\tt InpMtx\_sym\_gmmm()}}{288} \indexentry{InpMtx_herm_gmmm@{\tt InpMtx\_herm\_gmmm()}}{288} \indexentry{InpMtx_nonsym_gmmm_T@{\tt InpMtx\_nonsym\_gmmm\_T()}}{288} \indexentry{InpMtx_nonsym_gmmm_H@{\tt InpMtx\_nonsym\_gmmm\_H()}}{288} \indexentry{InpMtx_nonsym_gmvm@{\tt InpMtx\_nonsym\_gmvm()}}{289} \indexentry{InpMtx_sym_gmvm@{\tt InpMtx\_sym\_gmvm()}}{289} \indexentry{InpMtx_herm_gmvm@{\tt InpMtx\_herm\_gmvm()}}{289} \indexentry{InpMtx_nonsym_gmvm_T@{\tt InpMtx\_nonsym\_gmvm\_T()}}{289} \indexentry{InpMtx_nonsym_gmvm_H@{\tt InpMtx\_nonsym\_gmvm\_H()}}{289} \indexentry{InpMtx_fullAdjacency@{\tt InpMtx\_fullAdjacency()}}{289} \indexentry{InpMtx_fullAdjacency2@{\tt InpMtx\_fullAdjacency2()}}{289} \indexentry{InpMtx_adjForATA@{\tt InpMtx\_adjForATA()}}{289} \indexentry{InpMtx_initFromSubmatrix@{\tt InpMtx\_initFromSubmatrix()}}{290} \indexentry{InpMtx_sortAndCompress@{\tt InpMtx\_sortAndCompress()}}{290} \indexentry{InpMtx_convertToVectors@{\tt InpMtx\_convertToVectors()}}{290} \indexentry{InpMtx_dropOffDiagonalEntries@{\tt InpMtx\_dropOffDiagonalEntries()}}{290} \indexentry{InpMtx_dropLowerTriangle@{\tt InpMtx\_dropLowerTriangle()}}{290} \indexentry{InpMtx_dropUpperTriangle@{\tt InpMtx\_dropUpperTriangle()}}{290} \indexentry{InpMtx_mapToLowerTriangle@{\tt InpMtx\_mapToLowerTriangle()}}{290} \indexentry{InpMtx_mapToUpperTriangle@{\tt InpMtx\_mapToUpperTriangle()}}{290} \indexentry{InpMtx_mapToUpperTriangleH@{\tt InpMtx\_mapToUpperTriangleH()}}{290} \indexentry{InpMtx_log10profile@{\tt InpMtx\_log10profile()}}{291} \indexentry{InpMtx_checksums@{\tt InpMtx\_checksums()}}{291} \indexentry{InpMtx_randomMatrix@{\tt InpMtx\_randomMatrix()}}{291} \indexentry{InpMtx_readFromFile@{\tt InpMtx\_readFromFile()}}{292} \indexentry{InpMtx_readFromFormattedFile@{\tt InpMtx\_readFromFormattedFile()}}{292} \indexentry{InpMtx_readFromBinaryFile@{\tt InpMtx\_readFromBinaryFile()}}{292} \indexentry{InpMtx_writeToFile@{\tt InpMtx\_writeToFile()}}{292} \indexentry{InpMtx_writeToFormattedFile@{\tt InpMtx\_writeToFormattedFile()}}{292} \indexentry{InpMtx_writeToBinaryFile@{\tt InpMtx\_writeToBinaryFile()}}{292} \indexentry{InpMtx_writeForHumanEye@{\tt InpMtx\_writeForHumanEye()}}{292} \indexentry{InpMtx_writeStats@{\tt InpMtx\_writeStats()}}{293} \indexentry{InpMtx_writeForMatlab@{\tt InpMtx\_writeForMatlab()}}{293} \indexentry{InpMtx_readFromHBFile@{\tt InpMtx\_readFromHBFile()}}{293} \indexentry{DenseMtx_frobNorm@{\tt DenseMtx\_frobNorm()}}{301} \indexentry{DenseMtx_twoNormOfColumn@{\tt DenseMtx\_twoNormOfColumn()}}{302} \indexentry{DenseMtx_colCopy@{\tt DenseMtx\_colCopy()}}{302} \indexentry{DenseMtx_colDotProduct@{\tt DenseMtx\_colDotProduct()}}{302} \indexentry{DenseMtx_colGenAxpy@{\tt DenseMtx\_colGenAxpy()}}{302} \indexentry{DenseMtx_mmm@{\tt DenseMtx\_mmm()}}{302} \indexentry{FrontMtx_solveOneColumn@{\tt FrontMtx\_solveOneColumn()}}{302} \indexentry{bicgstabr@{\tt bicgstabr()}}{304} \indexentry{bicgstabl@{\tt bicgstabl()}}{304} \indexentry{mlbicgstabr@{\tt mlbicgstabr()}}{304} \indexentry{mlbicgstabl@{\tt mlbicgstabl()}}{304} \indexentry{tfqmrr@{\tt tfqmrr()}}{304} \indexentry{tfqmrl@{\tt tfqmrl()}}{304} \indexentry{pcgr@{\tt pcgr()}}{304} \indexentry{pcgl@{\tt pcgl()}}{304} \indexentry{pcgl@{\tt pcgl()}}{305} \indexentry{pcgl@{\tt pcgl()}}{305} \indexentry{zbicgstabr@{\tt zbicgstabr()}}{305} \indexentry{zbicgstabl@{\tt zbicgstabl()}}{305} \indexentry{zmlbicgstabr@{\tt zmlbicgstabr()}}{305} \indexentry{zmlbicgstabl@{\tt zmlbicgstabl()}}{305} \indexentry{ztfqmrr@{\tt ztfqmrr()}}{305} \indexentry{ztfqmrl@{\tt ztfqmrl()}}{305} \indexentry{zpcgr@{\tt zpcgr()}}{306} \indexentry{zpcgl@{\tt zpcgl()}}{306} \indexentry{PatchAndGoInfo_new@{\tt PatchAndGoInfo\_new()}}{312} \indexentry{PatchAndGoInfo_setDefaultFields@{\tt PatchAndGoInfo\_setDefaultFields()}}{312} \indexentry{PatchAndGoInfo_clearData@{\tt PatchAndGoInfo\_clearData()}}{312} \indexentry{PatchAndGoInfo_free@{\tt PatchAndGoInfo\_free()}}{312} \indexentry{PatchAndGoInfo_init@{\tt PatchAndGoInfo\_init()}}{313} \indexentry{Pencil_new@{\tt Pencil\_new()}}{315} \indexentry{Pencil_setDefaultFields@{\tt Pencil\_setDefaultFields()}}{315} \indexentry{Pencil_clearData@{\tt Pencil\_clearData()}}{315} \indexentry{Pencil_free@{\tt Pencil\_free()}}{315} \indexentry{Pencil_init@{\tt Pencil\_init()}}{315} \indexentry{Pencil_changeCoordType@{\tt Pencil\_changeCoordType()}}{315} \indexentry{Pencil_changeStorageMode@{\tt Pencil\_changeStorageMode()}}{315} \indexentry{Pencil_sortAndCompress@{\tt Pencil\_sortAndCompress()}}{315} \indexentry{Pencil_convertToVectors@{\tt Pencil\_convertToVectors()}}{315} \indexentry{Pencil_mapToLowerTriangle@{\tt Pencil\_mapToLowerTriangle()}}{315} \indexentry{Pencil_mapToUpperTriangle@{\tt Pencil\_mapToUpperTriangle()}}{316} \indexentry{Pencil_permute@{\tt Pencil\_permute()}}{316} \indexentry{Pencil_mmm@{\tt Pencil\_mmm()}}{316} \indexentry{Pencil_fullAdjacency@{\tt Pencil\_fullAdjacency()}}{316} \indexentry{Pencil_setup@{\tt Pencil\_setup()}}{316} \indexentry{Pencil_readFromFiles@{\tt Pencil\_readFromFiles()}}{316} \indexentry{Pencil_writeForHumanEye@{\tt Pencil\_writeForHumanEye()}}{316} \indexentry{Pencil_writeStats@{\tt Pencil\_writeStats()}}{316} \indexentry{SemiImplMtx_new@{\tt SemiImplMtx\_new()}}{318} \indexentry{SemiImplMtx_setDefaultFields@{\tt SemiImplMtx\_setDefaultFields()}}{318} \indexentry{SemiImplMtx_clearData@{\tt SemiImplMtx\_clearData()}}{318} \indexentry{SemiImplMtx_free@{\tt SemiImplMtx\_free()}}{319} \indexentry{SemiImplMtx_initFromFrontMtx@{\tt SemiImplMtx\_initFromFrontMtx()}}{319} \indexentry{FrontMtx_initFromSubMtx@{\tt FrontMtx\_initFromSubMtx()}}{319} \indexentry{SemiImplMtx_solve@{\tt SemiImplMtx\_solve()}}{319} \indexentry{SemiImplMtx_stats@{\tt SemiImplMtx\_stats()}}{320} \indexentry{SemiImplMtx_writeForHumanEye@{\tt SemiImplMtx\_writeForHumanEye()}}{320} \indexentry{SubMtx_new@{\tt SubMtx\_new()}}{325} \indexentry{SubMtx_setDefaultFields@{\tt SubMtx\_setDefaultFields()}}{325} \indexentry{SubMtx_clearData@{\tt SubMtx\_clearData()}}{325} \indexentry{SubMtx_free@{\tt SubMtx\_free()}}{325} \indexentry{SubMtx_ids@{\tt SubMtx\_ids()}}{325} \indexentry{SubMtx_setIds@{\tt SubMtx\_setIds()}}{325} \indexentry{SubMtx_dimensions@{\tt SubMtx\_dimensions()}}{325} \indexentry{SubMtx_rowIndices@{\tt SubMtx\_rowIndices()}}{325} \indexentry{SubMtx_columnIndices@{\tt SubMtx\_columnIndices()}}{325} \indexentry{SubMtx_denseInfo@{\tt SubMtx\_denseInfo()}}{326} \indexentry{SubMtx_sparseRowsInfo@{\tt SubMtx\_sparseRowsInfo()}}{326} \indexentry{SubMtx_sparseColumnsInfo@{\tt SubMtx\_sparseColumnsInfo()}}{326} \indexentry{SubMtx_sparseTriplesInfo@{\tt SubMtx\_sparseTriplesInfo()}}{326} \indexentry{SubMtx_denseSubrowsInfo@{\tt SubMtx\_denseSubrowsInfo()}}{326} \indexentry{SubMtx_denseSubcolumnsInfo@{\tt SubMtx\_denseSubcolumnsInfo()}}{327} \indexentry{SubMtx_diagonalInfo@{\tt SubMtx\_diagonalInfo()}}{327} \indexentry{SubMtx_blockDiagonalInfo@{\tt SubMtx\_blockDiagonalInfo()}}{327} \indexentry{SubMtx_realEntry@{\tt SubMtx\_realEntry()}}{327} \indexentry{SubMtx_complexEntry@{\tt SubMtx\_complesEntry()}}{327} \indexentry{SubMtx_locationOfRealEntry@{\tt SubMtx\_locationOfRealEntry()}}{327} \indexentry{SubMtx_locationOfComplexEntry@{\tt SubMtx\_locationOfComplexEntry()}}{328} \indexentry{SubMtx_init@{\tt SubMtx\_init()}}{328} \indexentry{SubMtx_initFromBuffer@{\tt SubMtx\_initFromBuffer()}}{328} \indexentry{SubMtx_initRandom@{\tt SubMtx\_initRandom()}}{328} \indexentry{SubMtx_initRandomLowerTriangle@{\tt SubMtx\_initRandomLowerTriangle()}}{328} \indexentry{SubMtx_initRandomUpperTriangle@{\tt SubMtx\_initRandomUpperTriangle()}}{328} \indexentry{SubMtx_scale1vec@{\tt SubMtx\_scale1vec()}}{329} \indexentry{SubMtx_scale2vec@{\tt SubMtx\_scale2vec()}}{329} \indexentry{SubMtx_scale3vec@{\tt SubMtx\_scale3vec()}}{329} \indexentry{SubMtx_solve@{\tt SubMtx\_solve()}}{329} \indexentry{SubMtx_solveH@{\tt SubMtx\_solveH()}}{329} \indexentry{SubMtx_solveT@{\tt SubMtx\_solveT()}}{329} \indexentry{SubMtx_solveupd@{\tt SubMtx\_solveupd()}}{329} \indexentry{SubMtx_solveupdH@{\tt SubMtx\_solveupdH()}}{330} \indexentry{SubMtx_solveupdT@{\tt SubMtx\_solveupdT()}}{330} \indexentry{SubMtx_nbytesNeeded@{\tt SubMtx\_nbytesNeeded()}}{330} \indexentry{SubMtx_nbytesInUse@{\tt SubMtx\_nbytesInUse()}}{330} \indexentry{SubMtx_nbytesInWorkspace@{\tt SubMtx\_nbytesInWorkspace()}}{330} \indexentry{SubMtx_setNbytesInWorkspace@{\tt SubMtx\_setNbytesInWorkspace()}}{330} \indexentry{SubMtx_workspace@{\tt SubMtx\_workspace()}}{330} \indexentry{SubMtx_setFields@{\tt SubMtx\_setFields()}}{330} \indexentry{SubMtx_sortRowsUp@{\tt SubMtx\_sortRowsUp()}}{330} \indexentry{SubMtx_sortColumnsUp@{\tt SubMtx\_sortColumnsUp()}}{330} \indexentry{SubMtx_fillRowDV@{\tt SubMtx\_fillRowDV()}}{331} \indexentry{SubMtx_fillColumnDV@{\tt SubMtx\_fillColumnDV()}}{331} \indexentry{SubMtx_fillRowZV@{\tt SubMtx\_fillRowZV()}}{331} \indexentry{SubMtx_fillColumnZV@{\tt SubMtx\_fillColumnZV()}}{331} \indexentry{SubMtx_maxabs@{\tt SubMtx\_maxabs()}}{331} \indexentry{SubMtx_zero@{\tt SubMtx\_zero()}}{331} \indexentry{SubMtx_readFromFile@{\tt SubMtx\_readFromFile()}}{331} \indexentry{SubMtx_readFromFormattedFile@{\tt SubMtx\_readFromFormattedFile()}}{331} \indexentry{SubMtx_readFromBinaryFile@{\tt SubMtx\_readFromBinaryFile()}}{332} \indexentry{SubMtx_writeToFile@{\tt SubMtx\_writeToFile()}}{332} \indexentry{SubMtx_writeToFormattedFile@{\tt SubMtx\_writeToFormattedFile()}}{332} \indexentry{SubMtx_writeToBinaryFile@{\tt SubMtx\_writeToBinaryFile()}}{332} \indexentry{SubMtx_writeForHumanEye@{\tt SubMtx\_writeForHumanEye()}}{332} \indexentry{SubMtx_writeStats@{\tt SubMtx\_writeStats()}}{332} \indexentry{SubMtx_writeForMatlab@{\tt SubMtx\_writeForMatlab()}}{332} \indexentry{SubMtxList_new@{\tt SubMtxList\_new()}}{338} \indexentry{SubMtxList_setDefaultFields@{\tt SubMtxList\_setDefaultFields()}}{338} \indexentry{SubMtxList_clearData@{\tt SubMtxList\_clearData()}}{338} \indexentry{SubMtxList_free@{\tt SubMtxList\_free()}}{338} \indexentry{SubMtxList_init@{\tt SubMtxList\_init()}}{339} \indexentry{SubMtxList_isListNonempty@{\tt SubMtxList\_isListNonempty()}}{339} \indexentry{SubMtxList_isCountZero@{\tt SubMtxList\_isCountZero()}}{339} \indexentry{SubMtxList_getList@{\tt SubMtxList\_getList()}}{339} \indexentry{SubMtxList_addObjectToList@{\tt SubMtxList\_addObjectToList()}}{339} \indexentry{SubMtxList_writeForHumanEye@{\tt SubMtxList\_writeForHumanEye()}}{339} \indexentry{SubMtxManager_new@{\tt SubMtxManager\_new()}}{341} \indexentry{SubMtxManager_setDefaultFields@{\tt SubMtxManager\_setDefaultFields()}}{341} \indexentry{SubMtxManager_clearData@{\tt SubMtxManager\_clearData()}}{341} \indexentry{SubMtxManager_free@{\tt SubMtxManager\_free()}}{342} \indexentry{SubMtxManager_init@{\tt SubMtxManager\_init()}}{342} \indexentry{SubMtxManager_newObjectOfSizeNbytes@{\tt SubMtxManager\_newObjectOfSizeNbytes()}}{342} \indexentry{SubMtxManager_releaseObject@{\tt SubMtxManager\_releaseObject()}}{342} \indexentry{SubMtxManager_releaseListOfObjects@{\tt SubMtxManager\_releaseListOfObjects()}}{342} \indexentry{SubMtxManager_writeForHumanEye@{\tt SubMtxManager\_writeForHumanEye()}}{342} \indexentry{SymbFac_initFromGraph@{\tt SymbFac\_initFromGraph()}}{343} \indexentry{SymbFac_initFromInpMtx@{\tt SymbFac\_initFromInpMtx()}}{344} \indexentry{Symbfac_initFromPencil@{\tt Symbfac\_initFromPencil()}}{344} \indexentry{mkNDperm@{\tt mkNDperm()}}{348} \indexentry{mkNDperm2@{\tt mkNDperm2()}}{348} \indexentry{localND2D@{\tt localND2D()}}{349} \indexentry{localND3D@{\tt localND3D()}}{349} \indexentry{fp2DGrid@{\tt fp2DGrid()}}{349} \indexentry{fp3DGrid@{\tt fp3DGrid()}}{349} \indexentry{orderViaMMD@{\tt orderViaMMD()}}{350} \indexentry{orderViaND@{\tt orderViaND()}}{350} \indexentry{orderViaMS@{\tt orderViaMS()}}{350} \indexentry{orderViaBestOfNDandMS@{\tt orderViaBestOfNDandMS()}}{350} \indexentry{drawGraphEPS@{\tt drawGraphEPS()}}{351} \indexentry{mkNDlinsys@{\tt mkNDlinsys()}}{351} \indexentry{mkNDlinsysQR@{\tt mkNDlinsysQR()}}{352} \indexentry{InpMtx_MT_nonsym_mmm@{\tt InpMtx\_MT\_nonsym\_mmm()}}{364} \indexentry{InpMtx_MT_sym_mmm@{\tt InpMtx\_MT\_sym\_mmm()}}{364} \indexentry{InpMtx_MT_herm_mmm@{\tt InpMtx\_MT\_herm\_mmm()}}{364} \indexentry{InpMtx_MT_nonsym_mmm_T@{\tt InpMtx\_MT\_nonsym\_mm\_Tm()}}{364} \indexentry{InpMtx_MT_nonsym_mmm_H@{\tt InpMtx\_MT\_nonsym\_mmm\_H()}}{365} \indexentry{FrontMtx_MT_factorInpMtx@{\tt FrontMtx\_MT\_factorInpMtx()}}{365} \indexentry{FrontMtx_MT_factorPencil@{\tt FrontMtx\_MT\_factorPencil()}}{365} \indexentry{FrontMtx_MT_QR_factor@{\tt FrontMtx\_MT\_QR\_factor()}}{366} \indexentry{FrontMtx_MT_solve@{\tt FrontMtx\_MT\_solve()}}{366} \indexentry{FrontMtx_MT_QR_solve@{\tt FrontMtx\_MT\_QR\_solve()}}{367} \indexentry{DenseMtx_MPI_splitByRows@{\tt DenseMtx\_MPI\_splitByRows()}}{376} \indexentry{DenseMtx_MPI_splitFromGlobalByRows@{\tt DenseMtx\_MPI\_splitFromGlobalByRows()}}{377} \indexentry{DenseMtx_MPI_mergeToGlobalByRows@{\tt DenseMtx\_MPI\_mergeToGlobalByRows()}}{377} \indexentry{InpMtx_MPI_split@{\tt InpMtx\_MPI\_split()}}{377} \indexentry{InpMtx_MPI_splitFromGlobal@{\tt InpMtx\_MPI\_splitFromGlobal()}}{378} \indexentry{Pencil_MPI_split@{\tt Pencil\_MPI\_split()}}{378} \indexentry{FrontMtx_MPI_split@{\tt FrontMtx\_MPI\_split()}}{378} \indexentry{DenseMtx_MPI_gatherRows@{\tt DenseMtx\_MPI\_gatherRows()}}{379} \indexentry{DenseMtx_MPI_scatterAddRows@{\tt DenseMtx\_MPI\_scatterAddRows()}}{379} \indexentry{SymbFac_MPI_initFromInpMtx@{\tt SymbFac\_MPI\_initFromInpMtx()}}{379} \indexentry{SymbFac_MPI_initFromPencil@{\tt SymbFac\_MPI\_initFromPencil()}}{379} \indexentry{FrontMtx_MPI_factorPencil@{\tt FrontMtx\_MPI\_factorPencil()}}{380} \indexentry{FrontMtx_MPI_factorInpMtx@{\tt FrontMtx\_MPI\_factorInpMtx()}}{380} \indexentry{FrontMtx_MPI_postProcess@{\tt FrontMtx\_MPI\_postProcess()}}{381} \indexentry{FrontMtx_MPI_permuteUpperAdj@{\tt FrontMtx\_MPI\_permuteUpperAdj()}}{381} \indexentry{FrontMtx_MPI_permuteLowerAdj@{\tt FrontMtx\_MPI\_permuteLowerAdj()}}{381} \indexentry{IV_MPI_allgather@{\tt IV\_MPI\_allgather()}}{381} \indexentry{IVL_MPI_allgather@{\tt IVL\_MPI\_allgather()}}{382} \indexentry{FrontMtx_MPI_solve@{\tt FrontMtx\_MPI\_solve()}}{382} \indexentry{MatMul_MPI_setup@{\tt MatMul\_MPI\_setup()}}{383} \indexentry{MatMul_setLocalIndices@{\tt MatMul\_setLocalIndices()}}{383} \indexentry{MatMul_setGlobalIndices@{\tt MatMul\_setGlobalIndices()}}{383} \indexentry{MatMul_MPI_mmm@{\tt MatMul\_MPI\_mmm()}}{384} \indexentry{MatMul_cleanup@{\tt MatMul\_cleanup()}}{384} \indexentry{ETree_MPI_Bcast@{\tt ETree\_MPI\_Bcast()}}{384} \indexentry{Graph_MPI_Bcast@{\tt Graph\_MPI\_Bcast()}}{384} \indexentry{IVL_MPI_Bcast@{\tt IVL\_MPI\_Bcast()}}{384} \indexentry{IV_MPI_Bcast@{\tt IV\_MPI\_Bcast()}}{384} \indexentry{InpMtx_MPI_fullAdjacency@{\tt InpMtx\_MPI\_fullAdjacency()}}{385} \indexentry{Pencil_MPI_fullAdjacency@{\tt Pencil\_MPI\_fullAdjacency()}}{385} \indexentry{FrontMtx_MPI_aggregateList@{\tt FrontMtx\_MPI\_aggregateList()}}{385} \indexentry{FrontMtx_MPI_colmapIV@{\tt FrontMtx\_MPI\_colmapIV()}}{385} \indexentry{FrontMtx_MPI_rowmapIV@{\tt FrontMtx\_MPI\_rowmapIV()}}{385} \indexentry{InpMtx_MPI_alltoall@{\tt InpMtx\_MPI\_alltoall}}{385} \indexentry{makeSendRecvIVLs@{\tt makeSendRecvIVLs}}{386} \indexentry{maxTagMPI@{\tt maxTagMPI()}}{386} ntry{Pencil_writeForHumanEye@{\tt Pencil\_writeForHumanEye()}}{316} \indexentry{Pencil_writeStats@{\tt Pencil\_writeStats()}}{316} \indexentry{SemiImplMtx_new@{\tt SemiImplMtx\_new()}}{318} \indexentry{SemiImplMtx_setDefaultFields@{documentation/ReferenceManual/main.ilg010064400020550007177000000005010665314315000214160ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx.....done (1439 entries accepted, 0 rejected). Sorting entries..............done (16334 comparisons). Generating output file main.ind.....done (1480 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. documentation/ReferenceManual/main.ind010064400020550007177000001531000665314315000214210ustar00clevecompmath00000400000006\begin{theindex} \item {\tt A2\_applyQT()}, 29 \item {\tt A2\_clearData()}, 26 \item {\tt A2\_column()}, 27 \item {\tt A2\_columnMajor()}, 31 \item {\tt A2\_complexEntry()}, 27 \item {\tt A2\_computeQ()}, 28 \item {\tt A2\_copy()}, 32 \item {\tt A2\_copyEntriesToVector()}, 33 \item {\tt A2\_entries()}, 26 \item {\tt A2\_extractColumn()}, 31 \item {\tt A2\_extractColumnDV()}, 31 \item {\tt A2\_extractColumnZV()}, 31 \item {\tt A2\_extractRow()}, 31 \item {\tt A2\_extractRowDV()}, 31 \item {\tt A2\_extractRowZV()}, 31 \item {\tt A2\_fillRandomNormal()}, 32 \item {\tt A2\_fillRandomUniform()}, 32 \item {\tt A2\_fillWithIdentity()}, 32 \item {\tt A2\_free()}, 26 \item {\tt A2\_frobNorm()}, 29 \item {\tt A2\_inc1()}, 26 \item {\tt A2\_inc2()}, 26 \item {\tt A2\_infinityNorm()}, 29 \item {\tt A2\_infinityNormOfColumn()}, 29 \item {\tt A2\_infinityNormOfRow()}, 30 \item {\tt A2\_init()}, 28 \item {\tt A2\_makeStaircase()}, 28 \item {\tt A2\_maxabs()}, 29 \item {\tt A2\_ncol()}, 26 \item {\tt A2\_new()}, 26 \item {\tt A2\_nrow()}, 26 \item {\tt A2\_oneNorm()}, 29 \item {\tt A2\_oneNormOfColumn()}, 29 \item {\tt A2\_oneNormOfRow()}, 29 \item {\tt A2\_permuteColumns()}, 30 \item {\tt A2\_permuteRows()}, 30 \item {\tt A2\_pointerToComplexEntry()}, 27 \item {\tt A2\_pointerToRealEntry()}, 27 \item {\tt A2\_QRreduce()}, 28 \item {\tt A2\_readFromBinaryFile()}, 33 \item {\tt A2\_readFromFile()}, 33 \item {\tt A2\_readFromFormattedFile()}, 33 \item {\tt A2\_realEntry()}, 27 \item {\tt A2\_row()}, 27 \item {\tt A2\_rowMajor()}, 31 \item {\tt A2\_setColumn()}, 32 \item {\tt A2\_setColumnDV()}, 32 \item {\tt A2\_setColumnZV()}, 32 \item {\tt A2\_setComplexEntry()}, 27 \item {\tt A2\_setDefaultFields()}, 26 \item {\tt A2\_setRealEntry()}, 27 \item {\tt A2\_setRow()}, 31 \item {\tt A2\_setRowDV()}, 32 \item {\tt A2\_setRowZV()}, 32 \item {\tt A2\_shiftBase()}, 30 \item {\tt A2\_sizeOf()}, 30 \item {\tt A2\_sortColumnsUp()}, 30 \item {\tt A2\_sortRowsUp()}, 30 \item {\tt A2\_sub()}, 33 \item {\tt A2\_subA2()}, 28 \item {\tt A2\_swapColumns()}, 33 \item {\tt A2\_swapRows()}, 33 \item {\tt A2\_transpose()}, 31 \item {\tt A2\_twoNormOfColumn()}, 29 \item {\tt A2\_twoNormOfRow()}, 30 \item {\tt A2\_writeForHumanEye()}, 34 \item {\tt A2\_writeForMatlab()}, 34 \item {\tt A2\_writeStats()}, 34 \item {\tt A2\_writeToBinaryFile()}, 34 \item {\tt A2\_writeToFile()}, 34 \item {\tt A2\_writeToFormattedFile()}, 34 \item {\tt A2\_zero()}, 32 \indexspace \item {\tt bicgstabl()}, 304 \item {\tt bicgstabr()}, 304 \item {\tt BKL\_clearData()}, 118 \item {\tt BKL\_domAdjToSep()}, 120 \item {\tt BKL\_eval()}, 120 \item {\tt BKL\_evalfcn()}, 120 \item {\tt BKL\_evalgain()}, 120 \item {\tt BKL\_exhSearch()}, 120 \item {\tt BKL\_fidmat()}, 121 \item {\tt BKL\_flipDomain()}, 119 \item {\tt BKL\_free()}, 118 \item {\tt BKL\_greyCodeDomain()}, 119 \item {\tt BKL\_init()}, 118 \item {\tt BKL\_new()}, 118 \item {\tt BKL\_segColor()}, 119 \item {\tt BKL\_setColorWeights()}, 119 \item {\tt BKL\_setDefaultFields()}, 118 \item {\tt BKL\_setInitPart()}, 119 \item {\tt BKL\_setRandomColors()}, 119 \item {\tt BPG\_clearData()}, 124 \item {\tt BPG\_DMdecomposition()}, 126 \item {\tt BPG\_DMviaMaxFlow()}, 126 \item {\tt BPG\_free()}, 124 \item {\tt BPG\_init()}, 125 \item {\tt BPG\_initFromColoring()}, 125 \item {\tt BPG\_levelStructure()}, 125 \item {\tt BPG\_makeGraphXbyX()}, 125 \item {\tt BPG\_makeGraphYbyY()}, 125 \item {\tt BPG\_new()}, 124 \item {\tt BPG\_pseudoperipheralnode()}, 125 \item {\tt BPG\_readFromBinaryFile()}, 127 \item {\tt BPG\_readFromFile()}, 126 \item {\tt BPG\_readFromFormattedFile()}, 126 \item {\tt BPG\_setDefaultFields()}, 124 \item {\tt BPG\_writeForHumanEye()}, 127 \item {\tt BPG\_writeStats()}, 127 \item {\tt BPG\_writeToBinaryFile()}, 127 \item {\tt BPG\_writeToFile()}, 127 \item {\tt BPG\_writeToFormattedFile()}, 127 \indexspace \item {\tt Chv\_addChevron()}, 229 \item {\tt Chv\_assembleChv()}, 229 \item {\tt Chv\_assemblePostponedData()}, 229 \item {\tt Chv\_clearData()}, 224 \item {\tt Chv\_columnIndices()}, 225 \item {\tt Chv\_complexEntry()}, 226 \item {\tt Chv\_copyBigEntriesToVector()}, 232 \item {\tt Chv\_copyEntriesToVector()}, 231 \item {\tt Chv\_copyTrailingPortion()}, 232 \item {\tt Chv\_countBigEntries()}, 231 \item {\tt Chv\_countEntries()}, 230 \item {\tt Chv\_diagLocation()}, 225 \item {\tt Chv\_dimensions()}, 224 \item {\tt Chv\_entries()}, 225 \item {\tt Chv\_factorWithNoPivoting()}, 230 \item {\tt Chv\_factorWithPivoting()}, 229 \item {\tt Chv\_fastBunchParlettPivot()}, 228 \item {\tt Chv\_fill11block()}, 234 \item {\tt Chv\_fill12block()}, 234 \item {\tt Chv\_fill21block()}, 234 \item {\tt Chv\_findPivot()}, 228 \item {\tt Chv\_free()}, 224 \item {\tt Chv\_frobNorm()}, 234 \item {\tt Chv\_id()}, 224 \item {\tt Chv\_init()}, 226 \item {\tt Chv\_initFromBuffer()}, 226 \item {\tt Chv\_initWithPointers()}, 226 \item {\tt Chv\_locationOfComplexEntry()}, 226 \item {\tt Chv\_locationOfRealEntry()}, 225 \item {\tt Chv\_maxabs()}, 234 \item {\tt Chv\_maxabsInChevron()}, 230 \item {\tt Chv\_maxabsInColumn()}, 227 \item {\tt Chv\_maxabsInColumn11()}, 227 \item {\tt Chv\_maxabsInDiagonal11()}, 227 \item {\tt Chv\_maxabsInRow()}, 227 \item {\tt Chv\_maxabsInRow11()}, 227 \item {\tt Chv\_nbytesInWorkspace()}, 233 \item {\tt Chv\_nbytesNeeded()}, 233 \item {\tt Chv\_nent()}, 225 \item {\tt Chv\_new()}, 224 \item {\tt Chv\_quasimax()}, 227 \item {\tt Chv\_r1upd()}, 230 \item {\tt Chv\_r2upd()}, 230 \item {\tt Chv\_realEntry()}, 225 \item {\tt Chv\_rowIndices()}, 225 \item {\tt Chv\_setComplexEntry()}, 226 \item {\tt Chv\_setDefaultFields()}, 224 \item {\tt Chv\_setFields()}, 233 \item {\tt Chv\_setNbytesInWorkspace()}, 233 \item {\tt Chv\_setRealEntry()}, 225 \item {\tt Chv\_shift()}, 233 \item {\tt Chv\_sub()}, 234 \item {\tt Chv\_swapColumns()}, 233 \item {\tt Chv\_swapRows()}, 232 \item {\tt Chv\_swapRowsAndColumns()}, 233 \item {\tt Chv\_symmetryFlag()}, 224 \item {\tt Chv\_type()}, 224 \item {\tt Chv\_updateH()}, 228 \item {\tt Chv\_updateN()}, 228 \item {\tt Chv\_updateS()}, 228 \item {\tt Chv\_workspace()}, 225 \item {\tt Chv\_writeForHumanEye()}, 234 \item {\tt Chv\_writeForMatlab()}, 234 \item {\tt Chv\_zero()}, 234 \item {\tt Chv\_zeroOffdiagonalOfChevron()}, 230 \item {\tt ChvList\_addObjectToList()}, 242 \item {\tt ChvList\_clearData()}, 241 \item {\tt ChvList\_free()}, 241 \item {\tt ChvList\_getList()}, 242 \item {\tt ChvList\_init()}, 242 \item {\tt ChvList\_isCountZero()}, 242 \item {\tt ChvList\_isListNonempty()}, 242 \item {\tt ChvList\_new()}, 241 \item {\tt ChvList\_setDefaultFields()}, 241 \item {\tt ChvList\_writeForHumanEye()}, 242 \item {\tt ChvManager\_clearData()}, 244 \item {\tt ChvManager\_free()}, 245 \item {\tt ChvManager\_init()}, 245 \item {\tt ChvManager\_new()}, 244 \item {\tt ChvManager\_newObjectOfSizeNbytes()}, 245 \item {\tt ChvManager\_releaseListOfObjects()}, 245 \item {\tt ChvManager\_releaseObject()}, 245 \item {\tt ChvManager\_setDefaultFields()}, 244 \item {\tt ChvManager\_writeForHumanEye()}, 245 \item {\tt Coords\_clearData()}, 37 \item {\tt Coords\_free()}, 37 \item {\tt Coords\_init()}, 37 \item {\tt Coords\_init27P()}, 37 \item {\tt Coords\_init9P()}, 37 \item {\tt Coords\_max()}, 38 \item {\tt Coords\_min()}, 38 \item {\tt Coords\_new()}, 36 \item {\tt Coords\_readFromBinaryFile()}, 39 \item {\tt Coords\_readFromFile()}, 38 \item {\tt Coords\_readFromFormattedFile()}, 39 \item {\tt Coords\_setDefaultFields()}, 37 \item {\tt Coords\_setValue()}, 38 \item {\tt Coords\_sizeOf()}, 38 \item {\tt Coords\_value()}, 38 \item {\tt Coords\_writeForHumanEye()}, 39 \item {\tt Coords\_writeStats()}, 39 \item {\tt Coords\_writeToBinaryFile()}, 39 \item {\tt Coords\_writeToFile()}, 39 \item {\tt Coords\_writeToFormattedFile()}, 39 \item {\tt CVcopy()}, 84 \item {\tt CVfill()}, 84 \item {\tt CVfp80()}, 84 \item {\tt CVfprintf()}, 84 \item {\tt CVfree()}, 84 \item {\tt CVfscanf()}, 84 \item {\tt CVinit()}, 84 \item {\tt CVinit2()}, 84 \indexspace \item {\tt DDsepInfo\_clearData()}, 172 \item {\tt DDsepInfo\_free()}, 172 \item {\tt DDsepInfo\_new()}, 172 \item {\tt DDsepInfo\_setDefaultFields()}, 172 \item {\tt DDsepInfo\_writeCpuTimes()}, 173 \item {\tt DenseMtx\_addRow()}, 251 \item {\tt DenseMtx\_addVectorIntoRow()}, 251 \item {\tt DenseMtx\_checksums()}, 251 \item {\tt DenseMtx\_clearData()}, 247 \item {\tt DenseMtx\_colCopy()}, 302 \item {\tt DenseMtx\_colDotProduct()}, 302 \item {\tt DenseMtx\_colGenAxpy()}, 302 \item {\tt DenseMtx\_colid()}, 247 \item {\tt DenseMtx\_column()}, 249 \item {\tt DenseMtx\_columnIncrement()}, 247 \item {\tt DenseMtx\_columnIndices()}, 248 \item {\tt DenseMtx\_complexEntry()}, 248 \item {\tt DenseMtx\_copyRow()}, 250 \item {\tt DenseMtx\_copyRowAndIndex()}, 250 \item {\tt DenseMtx\_copyRowIntoVector()}, 251 \item {\tt DenseMtx\_copyVectorIntoRow()}, 251 \item {\tt DenseMtx\_dimensions()}, 247 \item {\tt DenseMtx\_entries()}, 248 \item {\tt DenseMtx\_fillRandomEntries()}, 251 \item {\tt DenseMtx\_free()}, 247 \item {\tt DenseMtx\_frobNorm()}, 301 \item {\tt DenseMtx\_init()}, 249 \item {\tt DenseMtx\_initAsSubmatrix()}, 249 \item {\tt DenseMtx\_initFromBuffer()}, 249 \item {\tt DenseMtx\_initWithPointers()}, 249 \item {\tt DenseMtx\_maxabs()}, 251 \item {\tt DenseMtx\_mmm()}, 302 \item {\tt DenseMtx\_MPI\_gatherRows()}, 379 \item {\tt DenseMtx\_MPI\_mergeToGlobalByRows()}, 377 \item {\tt DenseMtx\_MPI\_scatterAddRows()}, 379 \item {\tt DenseMtx\_MPI\_splitByRows()}, 376 \item {\tt DenseMtx\_MPI\_splitFromGlobalByRows()}, 377 \item {\tt DenseMtx\_nbytesInWorkspace()}, 250 \item {\tt DenseMtx\_nbytesNeeded()}, 250 \item {\tt DenseMtx\_new()}, 247 \item {\tt DenseMtx\_permuteColumns()}, 250 \item {\tt DenseMtx\_permuteRows()}, 250 \item {\tt DenseMtx\_readFromBinaryFile()}, 252 \item {\tt DenseMtx\_readFromFile()}, 252 \item {\tt DenseMtx\_readFromFormattedFile()}, 252 \item {\tt DenseMtx\_realEntry()}, 248 \item {\tt DenseMtx\_row()}, 249 \item {\tt DenseMtx\_rowid()}, 247 \item {\tt DenseMtx\_rowIncrement()}, 248 \item {\tt DenseMtx\_rowIndices()}, 248 \item {\tt DenseMtx\_scale()}, 251 \item {\tt DenseMtx\_setA2()}, 249 \item {\tt DenseMtx\_setComplexEntry()}, 248 \item {\tt DenseMtx\_setDefaultFields()}, 247 \item {\tt DenseMtx\_setFields()}, 250 \item {\tt DenseMtx\_setNbytesInWorkspace()}, 250 \item {\tt DenseMtx\_setRealEntry()}, 248 \item {\tt DenseMtx\_sort()}, 250 \item {\tt DenseMtx\_sub()}, 251 \item {\tt DenseMtx\_twoNormOfColumn()}, 302 \item {\tt DenseMtx\_workspace()}, 248 \item {\tt DenseMtx\_writeForHumanEye()}, 252 \item {\tt DenseMtx\_writeForMatlab()}, 253 \item {\tt DenseMtx\_writeStats()}, 252 \item {\tt DenseMtx\_writeToBinaryFile()}, 252 \item {\tt DenseMtx\_writeToFile()}, 252 \item {\tt DenseMtx\_writeToFormattedFile()}, 252 \item {\tt DenseMtx\_zero()}, 251 \item {\tt Drand\_clearData()}, 49 \item {\tt Drand\_fillDvector()}, 50 \item {\tt Drand\_fillIvector()}, 50 \item {\tt Drand\_fillZvector()}, 50 \item {\tt Drand\_free()}, 49 \item {\tt Drand\_init()}, 49 \item {\tt Drand\_new()}, 49 \item {\tt Drand\_setDefaultFields()}, 49 \item {\tt Drand\_setNormal()}, 50 \item {\tt Drand\_setSeed()}, 49 \item {\tt Drand\_setSeeds()}, 49 \item {\tt Drand\_setUniform()}, 50 \item {\tt Drand\_value()}, 50 \item {\tt drawGraphEPS()}, 351 \item {\tt DSTree\_clearData()}, 130 \item {\tt DSTree\_domainWeight()}, 132 \item {\tt DSTree\_free()}, 130 \item {\tt DSTree\_init1()}, 130 \item {\tt DSTree\_init2()}, 131 \item {\tt DSTree\_mapIV()}, 130 \item {\tt DSTree\_MS2stages()}, 131 \item {\tt DSTree\_MS3stages()}, 131 \item {\tt DSTree\_ND2stages()}, 131 \item {\tt DSTree\_NDstages()}, 131 \item {\tt DSTree\_new()}, 130 \item {\tt DSTree\_readFromBinaryFile()}, 133 \item {\tt DSTree\_readFromFile()}, 132 \item {\tt DSTree\_readFromFormattedFile()}, 133 \item {\tt DSTree\_renumberViaPostOT()}, 132 \item {\tt DSTree\_separatorWeight()}, 132 \item {\tt DSTree\_setDefaultFields()}, 130 \item {\tt DSTree\_sizeOf()}, 132 \item {\tt DSTree\_stagesViaDomainWeight()}, 132 \item {\tt DSTree\_tree()}, 130 \item {\tt DSTree\_writeForHumanEye()}, 133 \item {\tt DSTree\_writeStats()}, 133 \item {\tt DSTree\_writeToBinaryFile()}, 133 \item {\tt DSTree\_writeToFile()}, 133 \item {\tt DSTree\_writeToFormattedFile()}, 133 \item {\tt DV2isortDown()}, 103 \item {\tt DV2isortUp()}, 103 \item {\tt DV2qsortDown()}, 104 \item {\tt DV2qsortUp()}, 104 \item {\tt DV\_clearData()}, 42 \item {\tt DV\_copy()}, 45 \item {\tt DV\_entries()}, 43 \item {\tt DV\_entry()}, 43 \item {\tt DV\_fill()}, 45 \item {\tt DV\_first()}, 45 \item {\tt DV\_free()}, 42 \item {\tt DV\_init()}, 43 \item {\tt DV\_init1()}, 43 \item {\tt DV\_init2()}, 43 \item {\tt DV\_log10profile()}, 45 \item {\tt DV\_max()}, 44 \item {\tt DV\_size()}, 42 \item {\tt DV\_min()}, 44 \item {\tt DV\_new()}, 42 \item {\tt DV\_next()}, 45 \item {\tt DV\_owned()}, 42 \item {\tt DV\_push()}, 44 \item {\tt DV\_ramp()}, 44 \item {\tt DV\_readFromBinaryFile()}, 46 \item {\tt DV\_readFromFile()}, 45 \item {\tt DV\_readFromFormattedFile()}, 46 \item {\tt DV\_setDefaultFields()}, 42 \item {\tt DV\_setEntry()}, 43 \item {\tt DV\_setMaxsize()}, 43 \item {\tt DV\_setSize()}, 44 \item {\tt DV\_shiftBase()}, 44 \item {\tt DV\_shuffle()}, 44 \item {\tt DV\_size()}, 42 \item {\tt DV\_sizeAndEntries()}, 43 \item {\tt DV\_sizeOf()}, 45 \item {\tt DV\_sortDown()}, 44 \item {\tt DV\_sortUp()}, 44 \item {\tt DV\_sum()}, 44 \item {\tt DV\_writeForHumanEye()}, 46 \item {\tt DV\_writeForMatlab()}, 46 \item {\tt DV\_writeStats()}, 46 \item {\tt DV\_writeToBinaryFile()}, 46 \item {\tt DV\_writeToFile()}, 46 \item {\tt DV\_writeToFormattedFile()}, 46 \item {\tt DV\_zero()}, 45 \item {\tt DVadd()}, 85 \item {\tt DVaxpy()}, 85 \item {\tt DVaxpy11()}, 86 \item {\tt DVaxpy12()}, 86 \item {\tt DVaxpy13()}, 86 \item {\tt DVaxpy21()}, 86 \item {\tt DVaxpy22()}, 85 \item {\tt DVaxpy23()}, 85 \item {\tt DVaxpy31()}, 85 \item {\tt DVaxpy32()}, 85 \item {\tt DVaxpy33()}, 85 \item {\tt DVaxpyi()}, 86 \item {\tt DVcompress()}, 86 \item {\tt DVcopy()}, 86 \item {\tt DVdot()}, 86 \item {\tt DVdot11()}, 88 \item {\tt DVdot12()}, 88 \item {\tt DVdot13()}, 88 \item {\tt DVdot21()}, 87 \item {\tt DVdot22()}, 87 \item {\tt DVdot23()}, 87 \item {\tt DVdot31()}, 87 \item {\tt DVdot32()}, 87 \item {\tt DVdot33()}, 86 \item {\tt DVdoti()}, 88 \item {\tt DVfill()}, 88 \item {\tt DVfprintf()}, 84 \item {\tt DVfree()}, 84 \item {\tt DVfscanf()}, 85 \item {\tt DVgather()}, 88 \item {\tt DVgatherAddZero()}, 88 \item {\tt DVgatherZero()}, 88 \item {\tt DVinit()}, 84 \item {\tt DVinit2()}, 84 \item {\tt DVinvPerm()}, 88 \item {\tt DVisascending()}, 102 \item {\tt DVisdescending()}, 102 \item {\tt DVisortDown()}, 103 \item {\tt DVisortUp()}, 103 \item {\tt DVIVisortDown()}, 103 \item {\tt DVIVisortUp()}, 103 \item {\tt DVIVqsortDown()}, 104 \item {\tt DVIVqsortUp()}, 104 \item {\tt DVmax()}, 88 \item {\tt DVmaxabs()}, 88 \item {\tt DVmin()}, 88 \item {\tt DVminabs()}, 89 \item {\tt DVperm()}, 89 \item {\tt DVqsortDown()}, 104 \item {\tt DVqsortUp()}, 104 \item {\tt DVramp()}, 89 \item {\tt DVscale()}, 89 \item {\tt DVscatter()}, 89 \item {\tt DVscatterAdd()}, 89 \item {\tt DVscatterAddZero()}, 89 \item {\tt DVscatterZero()}, 89 \item {\tt DVshuffle()}, 90 \item {\tt DVsub()}, 89 \item {\tt DVsum()}, 89 \item {\tt DVsumabs()}, 89 \item {\tt DVswap()}, 89 \item {\tt DVzero()}, 90 \indexspace \item {\tt EGraph\_clearData()}, 136 \item {\tt EGraph\_free()}, 136 \item {\tt EGraph\_init()}, 136 \item {\tt EGraph\_make27P()}, 137 \item {\tt EGraph\_make9P()}, 136 \item {\tt EGraph\_mkAdjGraph()}, 136 \item {\tt EGraph\_new()}, 136 \item {\tt EGraph\_readFromBinaryFile()}, 137 \item {\tt EGraph\_readFromFile()}, 137 \item {\tt EGraph\_readFromFormattedFile()}, 137 \item {\tt EGraph\_setDefaultFields()}, 136 \item {\tt EGraph\_writeForHumanEye()}, 138 \item {\tt EGraph\_writeStats()}, 138 \item {\tt EGraph\_writeToBinaryFile()}, 137 \item {\tt EGraph\_writeToFile()}, 137 \item {\tt EGraph\_writeToFormattedFile()}, 137 \item {\tt ETree\_backSolveProfile()}, 153 \item {\tt ETree\_backwardOps()}, 145 \item {\tt ETree\_balancedMap()}, 152 \item {\tt ETree\_bndwghts()}, 142 \item {\tt ETree\_bndwghtsIV()}, 142 \item {\tt ETree\_clearData()}, 141 \item {\tt ETree\_compress()}, 147 \item {\tt ETree\_ddMap()}, 152 \item {\tt ETree\_ddMapNew()}, 152 \item {\tt ETree\_expand()}, 145 \item {\tt ETree\_factorEntriesIV()}, 145 \item {\tt ETree\_fch()}, 142 \item {\tt ETree\_forwardOps()}, 145 \item {\tt ETree\_forwSolveProfile()}, 153 \item {\tt ETree\_free()}, 141 \item {\tt ETree\_frontBoundarySize()}, 142 \item {\tt ETree\_frontSize()}, 142 \item {\tt ETree\_FSstorageProfile()}, 153 \item {\tt ETree\_fundChainMap()}, 147 \item {\tt ETree\_fundSupernodeMap()}, 147 \item {\tt ETree\_GSstorageProfile()}, 152 \item {\tt ETree\_init1()}, 143 \item {\tt ETree\_initFromDenseMatrix()}, 143 \item {\tt ETree\_initFromFile()}, 144 \item {\tt ETree\_initFromGraph()}, 143 \item {\tt ETree\_initFromGraphWithPerms()}, 143 \item {\tt ETree\_initFromSubtree()}, 144 \item {\tt ETree\_leftJustify()}, 147 \item {\tt ETree\_leftJustifyD()}, 147 \item {\tt ETree\_leftJustifyI()}, 147 \item {\tt ETree\_maxNindAndNent()}, 143 \item {\tt ETree\_mergeFrontsAll()}, 151 \item {\tt ETree\_mergeFrontsAny()}, 151 \item {\tt ETree\_mergeFrontsOne()}, 150 \item {\tt ETree\_MFstackProfile()}, 152 \item {\tt ETree\_MPI\_Bcast()}, 384 \item {\tt ETree\_msByDepth()}, 148 \item {\tt ETree\_msByNentCutoff()}, 149 \item {\tt ETree\_msByNopsCutoff()}, 149 \item {\tt ETree\_msByNvtxCutoff()}, 148 \item {\tt ETree\_msStats()}, 149 \item {\tt ETree\_nentMetric()}, 146 \item {\tt ETree\_new()}, 141 \item {\tt ETree\_newToOldFrontPerm()}, 148 \item {\tt ETree\_newToOldVtxPerm()}, 148 \item {\tt ETree\_nExternalOpsInFront()}, 145 \item {\tt ETree\_nFactorEntries()}, 144 \item {\tt ETree\_nFactorEntriesInFront()}, 144 \item {\tt ETree\_nFactorIndices()}, 144 \item {\tt ETree\_nFactorOps()}, 144 \item {\tt ETree\_nfront()}, 141 \item {\tt ETree\_nInternalOpsInFront()}, 145 \item {\tt ETree\_nodwghts()}, 142 \item {\tt ETree\_nodwghtsIV()}, 142 \item {\tt ETree\_nopsMetric()}, 146 \item {\tt ETree\_nvtx()}, 141 \item {\tt ETree\_nvtxMetric()}, 146 \item {\tt ETree\_oldToNewFrontPerm()}, 148 \item {\tt ETree\_oldToNewVtxPerm()}, 148 \item {\tt ETree\_optPart()}, 149 \item {\tt ETree\_par()}, 142 \item {\tt ETree\_permuteVertices()}, 148 \item {\tt ETree\_readFromBinaryFile()}, 153 \item {\tt ETree\_readFromFile()}, 153 \item {\tt ETree\_readFromFormattedFile()}, 153 \item {\tt ETree\_root()}, 141 \item {\tt ETree\_setDefaultFields()}, 141 \item {\tt ETree\_sib()}, 142 \item {\tt ETree\_sizeOf()}, 144 \item {\tt ETree\_spliceTwoEtrees()}, 145 \item {\tt ETree\_splitFronts()}, 151 \item {\tt ETree\_subtreeSubsetMap()}, 152 \item {\tt ETree\_transform()}, 151 \item {\tt ETree\_transform2()}, 151 \item {\tt ETree\_tree()}, 141 \item {\tt ETree\_vtxToFront()}, 142 \item {\tt ETree\_vtxToFrontIV()}, 142 \item {\tt ETree\_wrapMap()}, 152 \item {\tt ETree\_writeForHumanEye()}, 154 \item {\tt ETree\_writeStats()}, 154 \item {\tt ETree\_writeToBinaryFile()}, 154 \item {\tt ETree\_writeToFile()}, 153 \item {\tt ETree\_writeToFormattedFile()}, 154 \indexspace \item {\tt fp2DGrid()}, 349 \item {\tt fp3DGrid()}, 349 \item {\tt FrontMtx\_aggregateList()}, 263 \item {\tt FrontMtx\_assemblePostponedData()}, 264 \item {\tt FrontMtx\_backwardSetup()}, 268 \item {\tt FrontMtx\_backwardVisit()}, 268 \item {\tt FrontMtx\_clearData()}, 259 \item {\tt FrontMtx\_colmapIV()}, 269 \item {\tt FrontMtx\_columnIndices()}, 260 \item {\tt FrontMtx\_diagMtx()}, 260 \item {\tt FrontMtx\_diagonalVisit()}, 267 \item {\tt FrontMtx\_factorInpMtx()}, 264 \item {\tt FrontMtx\_factorPencil()}, 264 \item {\tt FrontMtx\_factorSetup()}, 262 \item {\tt FrontMtx\_factorVisit()}, 262 \item {\tt FrontMtx\_forwardSetup()}, 268 \item {\tt FrontMtx\_forwardVisit()}, 267 \item {\tt FrontMtx\_free()}, 259 \item {\tt FrontMtx\_frontSize()}, 260 \item {\tt FrontMtx\_frontTree()}, 260 \item {\tt FrontMtx\_inertia()}, 270 \item {\tt FrontMtx\_init()}, 261 \item {\tt FrontMtx\_initFromSubMtx()}, 319 \item {\tt FrontMtx\_initialFrontDimensions()}, 260 \item {\tt FrontMtx\_initializeFront()}, 262 \item {\tt FrontMtx\_loadActiveLeaves()}, 263 \item {\tt FrontMtx\_loadActiveRoots()}, 268 \item {\tt FrontMtx\_loadEntries()}, 263 \item {\tt FrontMtx\_loadRightHandSide()}, 267 \item {\tt FrontMtx\_lowerAdjFronts()}, 261 \item {\tt FrontMtx\_lowerBlockIVL()}, 261 \item {\tt FrontMtx\_lowerMtx()}, 261 \item {\tt FrontMtx\_makeLowerBlockIVL()}, 269 \item {\tt FrontMtx\_makeUpperBlockIVL()}, 269 \item {\tt FrontMtx\_MPI\_aggregateList()}, 385 \item {\tt FrontMtx\_MPI\_colmapIV()}, 385 \item {\tt FrontMtx\_MPI\_factorInpMtx()}, 380 \item {\tt FrontMtx\_MPI\_factorPencil()}, 380 \item {\tt FrontMtx\_MPI\_permuteLowerAdj()}, 381 \item {\tt FrontMtx\_MPI\_permuteUpperAdj()}, 381 \item {\tt FrontMtx\_MPI\_postProcess()}, 381 \item {\tt FrontMtx\_MPI\_rowmapIV()}, 385 \item {\tt FrontMtx\_MPI\_solve()}, 382 \item {\tt FrontMtx\_MPI\_split()}, 378 \item {\tt FrontMtx\_MT\_factorInpMtx()}, 365 \item {\tt FrontMtx\_MT\_factorPencil()}, 365 \item {\tt FrontMtx\_MT\_QR\_factor()}, 366 \item {\tt FrontMtx\_MT\_QR\_solve()}, 367 \item {\tt FrontMtx\_MT\_solve()}, 366 \item {\tt FrontMtx\_nactiveChild()}, 263 \item {\tt FrontMtx\_neqns()}, 259 \item {\tt FrontMtx\_new()}, 259 \item {\tt FrontMtx\_nfront()}, 259 \item {\tt FrontMtx\_nLowerBlocks()}, 261 \item {\tt FrontMtx\_nSolveOps()}, 270 \item {\tt FrontMtx\_nUpperBlocks()}, 261 \item {\tt FrontMtx\_ownedColumns()}, 269 \item {\tt FrontMtx\_ownedRows()}, 269 \item {\tt FrontMtx\_permuteLowerAdj()}, 267 \item {\tt FrontMtx\_permuteLowerMatrices()}, 267 \item {\tt FrontMtx\_permuteUpperAdj()}, 267 \item {\tt FrontMtx\_permuteUpperMatrices()}, 267 \item {\tt FrontMtx\_postList()}, 263 \item {\tt FrontMtx\_postProcess()}, 266 \item {\tt FrontMtx\_QR\_assembleFront()}, 265 \item {\tt FrontMtx\_QR\_factor()}, 266 \item {\tt FrontMtx\_QR\_factorVisit()}, 265 \item {\tt FrontMtx\_QR\_setup()}, 265 \item {\tt FrontMtx\_QR\_solve()}, 269 \item {\tt FrontMtx\_QR\_storeFront()}, 266 \item {\tt FrontMtx\_QR\_storeUpdate()}, 266 \item {\tt FrontMtx\_readFromBinaryFile()}, 270 \item {\tt FrontMtx\_readFromFile()}, 270 \item {\tt FrontMtx\_readFromFormattedFile()}, 270 \item {\tt FrontMtx\_rowIndices()}, 260 \item {\tt FrontMtx\_rowmapIV()}, 269 \item {\tt FrontMtx\_setDefaultFields()}, 259 \item {\tt FrontMtx\_setFrontSize()}, 260 \item {\tt FrontMtx\_setupFront()}, 262 \item {\tt FrontMtx\_solve()}, 268 \item {\tt FrontMtx\_solveOneColumn()}, 302 \item {\tt FrontMtx\_splitLowerMatrices()}, 267 \item {\tt FrontMtx\_splitUpperMatrices()}, 267 \item {\tt FrontMtx\_storeFront()}, 264 \item {\tt FrontMtx\_storePostponedData()}, 264 \item {\tt FrontMtx\_storeSolution()}, 268 \item {\tt FrontMtx\_update()}, 263 \item {\tt FrontMtx\_upperAdjFronts()}, 261 \item {\tt FrontMtx\_upperBlockIVL()}, 261 \item {\tt FrontMtx\_upperMtx()}, 260 \item {\tt FrontMtx\_writeForHumanEye()}, 271 \item {\tt FrontMtx\_writeForMatlab()}, 271 \item {\tt FrontMtx\_writeStats()}, 271 \item {\tt FrontMtx\_writeToBinaryFile()}, 271 \item {\tt FrontMtx\_writeToFile()}, 270 \item {\tt FrontMtx\_writeToFormattedFile()}, 270 \item {\tt FVadd()}, 99 \item {\tt FVaxpy()}, 99 \item {\tt FVaxpyi()}, 99 \item {\tt FVcompress()}, 99 \item {\tt FVcopy()}, 99 \item {\tt FVdot()}, 99 \item {\tt FVfill()}, 99 \item {\tt FVfprintf()}, 99 \item {\tt FVfree()}, 98 \item {\tt FVfscanf()}, 99 \item {\tt FVgather()}, 99 \item {\tt FVgatherAddZero()}, 99 \item {\tt FVgatherZero()}, 99 \item {\tt FVinit()}, 98 \item {\tt FVinit2()}, 98 \item {\tt FVinvPerm()}, 99 \item {\tt FVmax()}, 99 \item {\tt FVmaxabs()}, 100 \item {\tt FVmin()}, 100 \item {\tt FVminabs()}, 100 \item {\tt FVperm()}, 100 \item {\tt FVramp()}, 100 \item {\tt FVscale()}, 100 \item {\tt FVscatter()}, 100 \item {\tt FVscatterAddZero()}, 100 \item {\tt FVscatterZero()}, 100 \item {\tt FVshuffle()}, 100 \item {\tt FVsub()}, 100 \item {\tt FVsum()}, 100 \item {\tt FVsumabs()}, 100 \item {\tt FVswap()}, 100 \item {\tt FVzero()}, 100 \indexspace \item {\tt GPart\_bndWeightsIV()}, 169 \item {\tt GPart\_clearData()}, 168 \item {\tt GPart\_DDviaFishnet()}, 169 \item {\tt GPart\_DDviaProjection()}, 169 \item {\tt GPart\_domSegMap()}, 170 \item {\tt GPart\_free()}, 168 \item {\tt GPart\_identifyWideSep()}, 170 \item {\tt GPart\_init()}, 168 \item {\tt GPart\_makeYCmap()}, 170 \item {\tt GPart\_new()}, 167 \item {\tt GPart\_RBviaDDsep()}, 172 \item {\tt GPart\_setCweights()}, 168 \item {\tt GPart\_setDefaultFields()}, 167 \item {\tt GPart\_setMessageInfo()}, 168 \item {\tt GPart\_sizeOf()}, 168 \item {\tt GPart\_smoothBisector()}, 171 \item {\tt GPart\_smoothBy2layers()}, 171 \item {\tt GPart\_smoothYSep()}, 171 \item {\tt GPart\_split()}, 169 \item {\tt GPart\_TwoSetViaBKL()}, 170 \item {\tt GPart\_validVtxSep()}, 168 \item {\tt GPart\_vtxIsAdjToOneDomain()}, 169 \item {\tt Graph\_adjAndEweights()}, 181 \item {\tt Graph\_adjAndSize()}, 181 \item {\tt Graph\_clearData()}, 179 \item {\tt Graph\_componentMap()}, 181 \item {\tt Graph\_componentStats()}, 181 \item {\tt Graph\_compress()}, 180 \item {\tt Graph\_compress2()}, 180 \item {\tt Graph\_equivMap()}, 180 \item {\tt Graph\_expand()}, 180 \item {\tt Graph\_expand2()}, 180 \item {\tt Graph\_externalDegree()}, 181 \item {\tt Graph\_fillFromOffsets()}, 179 \item {\tt Graph\_free()}, 179 \item {\tt Graph\_init1()}, 179 \item {\tt Graph\_init2()}, 179 \item {\tt Graph\_isSymmetric()}, 182 \item {\tt Graph\_MPI\_Bcast()}, 384 \item {\tt Graph\_new()}, 178 \item {\tt Graph\_readFromBinaryFile()}, 182 \item {\tt Graph\_readFromFile()}, 182 \item {\tt Graph\_readFromFormattedFile()}, 182 \item {\tt Graph\_setDefaultFields()}, 178 \item {\tt Graph\_setListsFromOffsets()}, 180 \item {\tt Graph\_sizeOf()}, 181 \item {\tt Graph\_subGraph()}, 181 \item {\tt Graph\_wirebasketStages()}, 180 \item {\tt Graph\_writeForHumanEye()}, 183 \item {\tt Graph\_writeStats()}, 183 \item {\tt Graph\_writeToBinaryFile()}, 183 \item {\tt Graph\_writeToFile()}, 182 \item {\tt Graph\_writeToFormattedFile()}, 182 \item {\tt Graph\_writeToMetisFile()}, 183 \indexspace \item {\tt I2Ohash\_clearData()}, 53 \item {\tt I2Ohash\_free()}, 53 \item {\tt I2Ohash\_init()}, 53 \item {\tt I2Ohash\_insert()}, 54 \item {\tt I2Ohash\_locate()}, 54 \item {\tt I2Ohash\_measure()}, 54 \item {\tt I2Ohash\_new()}, 53 \item {\tt I2Ohash\_remove()}, 54 \item {\tt I2Ohash\_setDefaultFields()}, 53 \item {\tt I2Ohash\_writeForHumanEye()}, 54 \item {\tt I2OP\_fprintf()}, 106 \item {\tt I2OP\_free()}, 106 \item {\tt I2OP\_init()}, 106 \item {\tt I2OP\_initStorage()}, 106 \item {\tt Ideq\_clear()}, 75 \item {\tt Ideq\_clearData()}, 75 \item {\tt Ideq\_free()}, 75 \item {\tt Ideq\_head()}, 75 \item {\tt Ideq\_insertAtHead()}, 76 \item {\tt Ideq\_insertAtTail()}, 76 \item {\tt Ideq\_new()}, 75 \item {\tt Ideq\_removeFromHead()}, 75 \item {\tt Ideq\_removeFromTail()}, 76 \item {\tt Ideq\_resize()}, 75 \item {\tt Ideq\_setDefaultFields()}, 75 \item {\tt Ideq\_tail()}, 76 \item {\tt Ideq\_writeForHumanEye()}, 76 \item {\tt IIheap\_clearData()}, 57 \item {\tt IIheap\_free()}, 57 \item {\tt IIheap\_init()}, 57 \item {\tt IIheap\_insert()}, 57 \item {\tt IIheap\_new()}, 56 \item {\tt IIheap\_print()}, 57 \item {\tt IIheap\_remove()}, 57 \item {\tt IIheap\_root()}, 57 \item {\tt IIheap\_setDefaultFields()}, 57 \item {\tt IIheap\_sizeOf()}, 57 \item {\tt ILUMtx\_clearData()}, 274 \item {\tt ILUMtx\_factor()}, 275 \item {\tt ILUMtx\_fillRandom()}, 276 \item {\tt ILUMtx\_free()}, 274 \item {\tt ILUMtx\_init()}, 275 \item {\tt ILUMtx\_new()}, 274 \item {\tt ILUMtx\_setDefaultFields()}, 274 \item {\tt ILUMtx\_solveVector()}, 275 \item {\tt ILUMtx\_writeForMatlab()}, 276 \item {\tt InpMtx\_adjForATA()}, 289 \item {\tt InpMtx\_changeCoordType()}, 284 \item {\tt InpMtx\_changeStorageMode()}, 284 \item {\tt InpMtx\_checksums()}, 291 \item {\tt InpMtx\_clearData()}, 281 \item {\tt InpMtx\_complexVector()}, 283 \item {\tt InpMtx\_convertToVectors()}, 290 \item {\tt InpMtx\_coordType()}, 281 \item {\tt InpMtx\_dropLowerTriangle()}, 290 \item {\tt InpMtx\_dropOffDiagonalEntries()}, 290 \item {\tt InpMtx\_dropUpperTriangle()}, 290 \item {\tt InpMtx\_dvec()}, 283 \item {\tt InpMtx\_free()}, 281 \item {\tt InpMtx\_fullAdjacency()}, 289 \item {\tt InpMtx\_fullAdjacency2()}, 289 \item {\tt InpMtx\_herm\_gmmm()}, 288 \item {\tt InpMtx\_herm\_gmvm()}, 289 \item {\tt InpMtx\_herm\_mmm()}, 287 \item {\tt InpMtx\_herm\_mmmVector()}, 288 \item {\tt InpMtx\_init()}, 284 \item {\tt InpMtx\_initFromSubmatrix()}, 290 \item {\tt InpMtx\_inputChevron()}, 285 \item {\tt InpMtx\_inputColumn()}, 285 \item {\tt InpMtx\_inputComplexChevron()}, 285 \item {\tt InpMtx\_inputComplexColumn()}, 285 \item {\tt InpMtx\_inputComplexEntry()}, 285 \item {\tt InpMtx\_inputComplexMatrix()}, 286 \item {\tt InpMtx\_inputComplexRow()}, 285 \item {\tt InpMtx\_inputComplexTriples()}, 286 \item {\tt InpMtx\_inputEntry()}, 285 \item {\tt InpMtx\_inputMatrix()}, 286 \item {\tt InpMtx\_inputMode()}, 282 \item {\tt InpMtx\_inputRealChevron()}, 285 \item {\tt InpMtx\_inputRealColumn()}, 285 \item {\tt InpMtx\_inputRealEntry()}, 285 \item {\tt InpMtx\_inputRealMatrix()}, 286 \item {\tt InpMtx\_inputRealRow()}, 285 \item {\tt InpMtx\_inputRealTriples()}, 286 \item {\tt InpMtx\_inputRow()}, 285 \item {\tt InpMtx\_inputTriples()}, 286 \item {\tt InpMtx\_ivec1()}, 282 \item {\tt InpMtx\_ivec2()}, 282 \item {\tt InpMtx\_log10profile()}, 291 \item {\tt InpMtx\_mapEntries()}, 286 \item {\tt InpMtx\_mapToLowerTriangle()}, 290 \item {\tt InpMtx\_mapToUpperTriangle()}, 290 \item {\tt InpMtx\_mapToUpperTriangleH()}, 290 \item {\tt InpMtx\_maxnent()}, 282 \item {\tt InpMtx\_maxnvector()}, 282 \item {\tt InpMtx\_MPI\_alltoall}, 385 \item {\tt InpMtx\_MPI\_fullAdjacency()}, 385 \item {\tt InpMtx\_MPI\_split()}, 377 \item {\tt InpMtx\_MPI\_splitFromGlobal()}, 378 \item {\tt InpMtx\_MT\_herm\_mmm()}, 364 \item {\tt InpMtx\_MT\_nonsym\_mmm()}, 364 \item {\tt InpMtx\_MT\_nonsym\_mmm\_H()}, 365 \item {\tt InpMtx\_MT\_nonsym\_mm\_Tm()}, 364 \item {\tt InpMtx\_MT\_sym\_mmm()}, 364 \item {\tt InpMtx\_nent()}, 282 \item {\tt InpMtx\_new()}, 281 \item {\tt InpMtx\_nonsym\_gmmm()}, 288 \item {\tt InpMtx\_nonsym\_gmmm\_H()}, 288 \item {\tt InpMtx\_nonsym\_gmmm\_T()}, 288 \item {\tt InpMtx\_nonsym\_gmvm()}, 289 \item {\tt InpMtx\_nonsym\_gmvm\_H()}, 289 \item {\tt InpMtx\_nonsym\_gmvm\_T()}, 289 \item {\tt InpMtx\_nonsym\_mmm()}, 287 \item {\tt InpMtx\_nonsym\_mmm\_H()}, 287 \item {\tt InpMtx\_nonsym\_mmm\_T()}, 287 \item {\tt InpMtx\_nonsym\_mmmVector()}, 288 \item {\tt InpMtx\_nonsym\_mmmVector\_H()}, 288 \item {\tt InpMtx\_nonsym\_mmmVector\_T()}, 288 \item {\tt InpMtx\_nvector()}, 282 \item {\tt InpMtx\_offsets()}, 283 \item {\tt InpMtx\_permute()}, 287 \item {\tt InpMtx\_randomMatrix()}, 291 \item {\tt InpMtx\_range()}, 283 \item {\tt InpMtx\_readFromBinaryFile()}, 292 \item {\tt InpMtx\_readFromFile()}, 292 \item {\tt InpMtx\_readFromFormattedFile()}, 292 \item {\tt InpMtx\_readFromHBFile()}, 293 \item {\tt InpMtx\_realVector()}, 283 \item {\tt InpMtx\_resizeMultiple()}, 282 \item {\tt InpMtx\_setCoordType()}, 284 \item {\tt InpMtx\_setDefaultFields()}, 281 \item {\tt InpMtx\_setMaxnent()}, 283 \item {\tt InpMtx\_setMaxnvector()}, 284 \item {\tt InpMtx\_setNent()}, 283 \item {\tt InpMtx\_setNvector()}, 284 \item {\tt InpMtx\_setResizeMultiple()}, 284 \item {\tt InpMtx\_sizes()}, 283 \item {\tt InpMtx\_sortAndCompress()}, 290 \item {\tt InpMtx\_storageMode()}, 282 \item {\tt InpMtx\_supportNonsym()}, 286 \item {\tt InpMtx\_supportNonsymH()}, 286 \item {\tt InpMtx\_supportNonsymT()}, 286 \item {\tt InpMtx\_supportSym()}, 286 \item {\tt InpMtx\_supportSymH()}, 286 \item {\tt InpMtx\_sym\_gmmm()}, 288 \item {\tt InpMtx\_sym\_gmvm()}, 289 \item {\tt InpMtx\_sym\_mmm()}, 287 \item {\tt InpMtx\_sym\_mmmVector()}, 288 \item {\tt InpMtx\_vecids()}, 283 \item {\tt InpMtx\_vector()}, 283 \item {\tt InpMtx\_writeForHumanEye()}, 292 \item {\tt InpMtx\_writeForMatlab()}, 293 \item {\tt InpMtx\_writeStats()}, 293 \item {\tt InpMtx\_writeToBinaryFile()}, 292 \item {\tt InpMtx\_writeToFile()}, 292 \item {\tt InpMtx\_writeToFormattedFile()}, 292 \item {\tt IP\_fp80()}, 105 \item {\tt IP\_fprintf()}, 105 \item {\tt IP\_free()}, 105 \item {\tt IP\_init()}, 105 \item {\tt IP\_mergeSortUp()}, 106 \item {\tt IP\_mergeUp()}, 105 \item {\tt IP\_radixSortDown()}, 106 \item {\tt IP\_radixSortUp()}, 106 \item {\tt IV2DVisortDown()}, 102 \item {\tt IV2DVisortUp()}, 102 \item {\tt IV2DVqsortDown()}, 103 \item {\tt IV2DVqsortUp()}, 103 \item {\tt IV2DVsortUpAndCompress()}, 105 \item {\tt IV2isortDown()}, 102 \item {\tt IV2isortUp()}, 102 \item {\tt IV2qsortDown()}, 103 \item {\tt IV2qsortUp()}, 103 \item {\tt IV2sortUpAndCompress()}, 104 \item {\tt IV2ZVisortDown()}, 103 \item {\tt IV2ZVisortUp()}, 103 \item {\tt IV2ZVqsortDown()}, 104 \item {\tt IV2ZVqsortUp()}, 104 \item {\tt IV2ZVsortUpAndCompress()}, 105 \item {\tt IV\_clearData()}, 59 \item {\tt IV\_copy()}, 62 \item {\tt IV\_decrement()}, 63 \item {\tt IV\_entries()}, 60 \item {\tt IV\_entry()}, 60 \item {\tt IV\_fill()}, 62 \item {\tt IV\_filterKeep()}, 62 \item {\tt IV\_filterPurge()}, 62 \item {\tt IV\_findValue()}, 63 \item {\tt IV\_findValueAscending()}, 63 \item {\tt IV\_findValueDescending()}, 63 \item {\tt IV\_first()}, 62 \item {\tt IV\_fp80()}, 64 \item {\tt IV\_free()}, 59 \item {\tt IV\_increment()}, 62 \item {\tt IV\_init()}, 60 \item {\tt IV\_init1()}, 60 \item {\tt IV\_init2()}, 60 \item {\tt IV\_inverseMap()}, 63 \item {\tt IV\_max()}, 61 \item {\tt IV\_maxsize()}, 60 \item {\tt IV\_min()}, 61 \item {\tt IV\_MPI\_allgather()}, 381 \item {\tt IV\_MPI\_Bcast()}, 384 \item {\tt IV\_new()}, 59 \item {\tt IV\_next()}, 62 \item {\tt IV\_owned()}, 59 \item {\tt IV\_push()}, 61 \item {\tt IV\_ramp()}, 61 \item {\tt IV\_readFromBinaryFile()}, 64 \item {\tt IV\_readFromFile()}, 63 \item {\tt IV\_readFromFormattedFile()}, 64 \item {\tt IV\_setDefaultFields()}, 59 \item {\tt IV\_setEntry()}, 60 \item {\tt IV\_setMaxsize()}, 61 \item {\tt IV\_setSize()}, 61 \item {\tt IV\_shiftBase()}, 61 \item {\tt IV\_shuffle()}, 62 \item {\tt IV\_size()}, 60 \item {\tt IV\_sizeAndEntries()}, 60 \item {\tt IV\_sizeOf()}, 62 \item {\tt IV\_sortDown()}, 61 \item {\tt IV\_sortUp()}, 61 \item {\tt IV\_targetEntries()}, 63 \item {\tt IV\_writeForHumanEye()}, 64 \item {\tt IV\_writeForMatlab()}, 64 \item {\tt IV\_writeStats()}, 64 \item {\tt IV\_writeToBinaryFile()}, 64 \item {\tt IV\_writeToFile()}, 64 \item {\tt IV\_writeToFormattedFile()}, 64 \item {\tt IVcompress()}, 97 \item {\tt IVcopy()}, 97 \item {\tt IVDVisortDown()}, 102 \item {\tt IVDVisortUp()}, 102 \item {\tt IVDVqsortDown()}, 103 \item {\tt IVDVqsortUp()}, 103 \item {\tt IVDVsortUpAndCompress()}, 104 \item {\tt IVfill()}, 97 \item {\tt IVfp80()}, 97 \item {\tt IVfprintf()}, 97 \item {\tt IVfree()}, 97 \item {\tt IVfscanf()}, 97 \item {\tt IVgather()}, 97 \item {\tt IVinit()}, 96 \item {\tt IVinit2()}, 96 \item {\tt IVinverse()}, 97 \item {\tt IVinvPerm()}, 97 \item {\tt IVisascending()}, 102 \item {\tt IVisdescending()}, 102 \item {\tt IVisortDown()}, 102 \item {\tt IVisortUp()}, 102 \item {\tt IVL\_absorbIVL()}, 71 \item {\tt IVL\_clearData()}, 67 \item {\tt IVL\_equivMap1()}, 70 \item {\tt IVL\_equivMap2()}, 70 \item {\tt IVL\_expand()}, 71 \item {\tt IVL\_firstInList()}, 69 \item {\tt IVL\_free()}, 67 \item {\tt IVL\_incr()}, 68 \item {\tt IVL\_init()}, 68 \item {\tt IVL\_init2()}, 68 \item {\tt IVL\_init3()}, 68 \item {\tt IVL\_initFromSubIVL()}, 69 \item {\tt IVL\_listAndSize()}, 69 \item {\tt IVL\_make13P()}, 71 \item {\tt IVL\_make27P()}, 72 \item {\tt IVL\_make5P()}, 71 \item {\tt IVL\_make9P()}, 71 \item {\tt IVL\_mapEntries()}, 71 \item {\tt IVL\_max()}, 70 \item {\tt IVL\_maxListSize()}, 70 \item {\tt IVL\_maxnlist()}, 68 \item {\tt IVL\_min()}, 70 \item {\tt IVL\_MPI\_allgather()}, 382 \item {\tt IVL\_MPI\_Bcast()}, 384 \item {\tt IVL\_new()}, 67 \item {\tt IVL\_nextInList()}, 69 \item {\tt IVL\_nlist()}, 68 \item {\tt IVL\_overwrite()}, 71 \item {\tt IVL\_readFromBinaryFile()}, 72 \item {\tt IVL\_readFromFile()}, 72 \item {\tt IVL\_readFromFormattedFile()}, 72 \item {\tt IVL\_setDefaultFields()}, 67 \item {\tt IVL\_setincr()}, 68 \item {\tt IVL\_setList()}, 69 \item {\tt IVL\_setMaxnlist()}, 69 \item {\tt IVL\_setNlist()}, 69 \item {\tt IVL\_setPointerToList()}, 70 \item {\tt IVL\_sizeOf()}, 70 \item {\tt IVL\_sortUp()}, 70 \item {\tt IVL\_sum()}, 70 \item {\tt IVL\_tsize()}, 68 \item {\tt IVL\_type()}, 68 \item {\tt IVL\_writeForHumanEye()}, 72 \item {\tt IVL\_writeStats()}, 73 \item {\tt IVL\_writeToBinaryFile()}, 72 \item {\tt IVL\_writeToFile()}, 72 \item {\tt IVL\_writeToFormattedFile()}, 72 \item {\tt IVlocateViaBinarySearch()}, 97 \item {\tt IVmax()}, 97 \item {\tt IVmaxabs()}, 97 \item {\tt IVmin()}, 98 \item {\tt IVminabs()}, 98 \item {\tt IVperm()}, 98 \item {\tt IVqsortDown()}, 103 \item {\tt IVqsortUp()}, 103 \item {\tt IVramp()}, 98 \item {\tt IVscatter()}, 98 \item {\tt IVshuffle()}, 98 \item {\tt IVsortUpAndCompress()}, 104 \item {\tt IVsum()}, 98 \item {\tt IVsumabs()}, 98 \item {\tt IVswap()}, 98 \item {\tt IVzero()}, 98 \item {\tt IVZVisortDown()}, 103 \item {\tt IVZVisortUp()}, 103 \item {\tt IVZVqsortDown()}, 103 \item {\tt IVZVqsortUp()}, 103 \item {\tt IVZVsortUpAndCompress()}, 104 \indexspace \item {\tt localND2D()}, 349 \item {\tt localND3D()}, 349 \item {\tt Lock\_clearData()}, 78 \item {\tt Lock\_free()}, 78 \item {\tt Lock\_init()}, 78 \item {\tt Lock\_lock()}, 78 \item {\tt Lock\_new()}, 78 \item {\tt Lock\_setDefaultFields()}, 78 \item {\tt Lock\_unlock()}, 78 \indexspace \item {\tt makeSendRecvIVLs}, 386 \item {\tt MatMul\_cleanup()}, 384 \item {\tt MatMul\_MPI\_mmm()}, 384 \item {\tt MatMul\_MPI\_setup()}, 383 \item {\tt MatMul\_setGlobalIndices()}, 383 \item {\tt MatMul\_setLocalIndices()}, 383 \item {\tt maxTagMPI()}, 386 \item {\tt mkNDlinsys()}, 351 \item {\tt mkNDlinsysQR()}, 352 \item {\tt mkNDperm()}, 348 \item {\tt mkNDperm2()}, 348 \item {\tt mlbicgstabl()}, 304 \item {\tt mlbicgstabr()}, 304 \item {\tt MSMD\_approxDegree()}, 195 \item {\tt MSMD\_cleanEdgeList()}, 195 \item {\tt MSMD\_cleanReachSet()}, 194 \item {\tt MSMD\_cleanSubtreeList()}, 194 \item {\tt MSMD\_clearData()}, 193 \item {\tt MSMD\_eliminateStage()}, 194 \item {\tt MSMD\_eliminateStep()}, 194 \item {\tt MSMD\_eliminateVtx()}, 194 \item {\tt MSMD\_exactDegree2()}, 195 \item {\tt MSMD\_exactDegree3()}, 195 \item {\tt MSMD\_fillPerms()}, 194 \item {\tt MSMD\_findInodes()}, 194 \item {\tt MSMD\_free()}, 193 \item {\tt MSMD\_frontETree()}, 194 \item {\tt MSMD\_init()}, 193 \item {\tt MSMD\_makeSchurComplement()}, 195 \item {\tt MSMD\_new()}, 192 \item {\tt MSMD\_order()}, 193 \item {\tt MSMD\_setDefaultFields()}, 192 \item {\tt MSMD\_update()}, 195 \item {\tt MSMDinfo\_clearData()}, 192 \item {\tt MSMDinfo\_free()}, 192 \item {\tt MSMDinfo\_isValid()}, 192 \item {\tt MSMDinfo\_new()}, 191 \item {\tt MSMDinfo\_print()}, 192 \item {\tt MSMDinfo\_setDefaultFields()}, 192 \item {\tt MSMDvtx\_print()}, 195 \indexspace \item {\tt Network\_addArc()}, 201 \item {\tt Network\_augmentPath()}, 201 \item {\tt Network\_clearData()}, 200 \item {\tt Network\_findAugmentingPath()}, 201 \item {\tt Network\_findMaxFlow()}, 201 \item {\tt Network\_findMincutFromSink()}, 202 \item {\tt Network\_findMincutFromSource()}, 202 \item {\tt Network\_free()}, 200 \item {\tt Network\_init()}, 201 \item {\tt Network\_new()}, 200 \item {\tt Network\_setDefaultFields()}, 200 \item {\tt Network\_setMessageInfo()}, 201 \item {\tt Network\_writeForHumanEye()}, 202 \item {\tt Network\_writeStats()}, 202 \indexspace \item {\tt orderViaBestOfNDandMS()}, 350 \item {\tt orderViaMMD()}, 350 \item {\tt orderViaMS()}, 350 \item {\tt orderViaND()}, 350 \indexspace \item {\tt PatchAndGoInfo\_clearData()}, 312 \item {\tt PatchAndGoInfo\_free()}, 312 \item {\tt PatchAndGoInfo\_init()}, 313 \item {\tt PatchAndGoInfo\_new()}, 312 \item {\tt PatchAndGoInfo\_setDefaultFields()}, 312 \item {\tt pcgl()}, 304, 305 \item {\tt pcgr()}, 304 \item {\tt PCVcopy()}, 101 \item {\tt PCVfree()}, 101 \item {\tt PCVinit()}, 101 \item {\tt PCVsetup()}, 101 \item {\tt PDVcopy()}, 101 \item {\tt PDVfree()}, 101 \item {\tt PDVinit()}, 101 \item {\tt PDVsetup()}, 101 \item {\tt Pencil\_changeCoordType()}, 315 \item {\tt Pencil\_changeStorageMode()}, 315 \item {\tt Pencil\_clearData()}, 315 \item {\tt Pencil\_convertToVectors()}, 315 \item {\tt Pencil\_free()}, 315 \item {\tt Pencil\_fullAdjacency()}, 316 \item {\tt Pencil\_init()}, 315 \item {\tt Pencil\_mapToLowerTriangle()}, 315 \item {\tt Pencil\_mapToUpperTriangle()}, 316 \item {\tt Pencil\_mmm()}, 316 \item {\tt Pencil\_MPI\_fullAdjacency()}, 385 \item {\tt Pencil\_MPI\_split()}, 378 \item {\tt Pencil\_new()}, 315 \item {\tt Pencil\_permute()}, 316 \item {\tt Pencil\_readFromFiles()}, 316 \item {\tt Pencil\_setDefaultFields()}, 315 \item {\tt Pencil\_setup()}, 316 \item {\tt Pencil\_sortAndCompress()}, 315 \item {\tt Pencil\_writeForHumanEye()}, 316 \item {\tt Pencil\_writeStats()}, 316 \item {\tt Perm\_checkPerm()}, 80 \item {\tt Perm\_clearData()}, 80 \item {\tt Perm\_compress()}, 81 \item {\tt Perm\_fillNewToOld()}, 80 \item {\tt Perm\_fillOldToNew()}, 80 \item {\tt Perm\_free()}, 80 \item {\tt Perm\_initWithTypeAndSize()}, 80 \item {\tt Perm\_new()}, 79 \item {\tt Perm\_readFromBinaryFile()}, 81 \item {\tt Perm\_readFromFile()}, 81 \item {\tt Perm\_readFromFormattedFile()}, 81 \item {\tt Perm\_releaseNewToOld()}, 81 \item {\tt Perm\_releaseOldToNew()}, 81 \item {\tt Perm\_setDefaultFields()}, 80 \item {\tt Perm\_sizeOf()}, 80 \item {\tt Perm\_writeForHumanEye()}, 82 \item {\tt Perm\_writeStats()}, 82 \item {\tt Perm\_writeToBinaryFile()}, 82 \item {\tt Perm\_writeToFile()}, 81 \item {\tt Perm\_writeToFormattedFile()}, 82 \item {\tt PFVcopy()}, 102 \item {\tt PFVfree()}, 102 \item {\tt PFVinit()}, 102 \item {\tt PFVsetup()}, 102 \item {\tt PIVcopy()}, 101 \item {\tt PIVfree()}, 101 \item {\tt PIVinit()}, 101 \item {\tt PIVsetup()}, 101 \indexspace \item {\tt SemiImplMtx\_clearData()}, 318 \item {\tt SemiImplMtx\_free()}, 319 \item {\tt SemiImplMtx\_initFromFrontMtx()}, 319 \item {\tt SemiImplMtx\_new()}, 318 \item {\tt SemiImplMtx\_setDefaultFields()}, 318 \item {\tt SemiImplMtx\_solve()}, 319 \item {\tt SemiImplMtx\_stats()}, 320 \item {\tt SemiImplMtx\_writeForHumanEye()}, 320 \item {\tt SolveMap\_backwardSetup()}, 206 \item {\tt SolveMap\_clearData()}, 204 \item {\tt SolveMap\_colidsLower()}, 205 \item {\tt SolveMap\_colidsUpper()}, 205 \item {\tt SolveMap\_ddMap()}, 206 \item {\tt SolveMap\_forwardSetup()}, 206 \item {\tt SolveMap\_free()}, 204 \item {\tt SolveMap\_init()}, 205 \item {\tt SolveMap\_lowerAggregateIV()}, 207 \item {\tt SolveMap\_lowerSolveIVL()}, 206 \item {\tt SolveMap\_mapLower()}, 205 \item {\tt SolveMap\_mapUpper()}, 205 \item {\tt SolveMap\_nblockLower()}, 205 \item {\tt SolveMap\_nblockUpper()}, 204 \item {\tt SolveMap\_new()}, 204 \item {\tt SolveMap\_nfront()}, 204 \item {\tt SolveMap\_nproc()}, 204 \item {\tt SolveMap\_owners()}, 205, 206 \item {\tt SolveMap\_randomMap()}, 206 \item {\tt SolveMap\_readFromBinaryFile()}, 207 \item {\tt SolveMap\_readFromFile()}, 207 \item {\tt SolveMap\_readFromFormattedFile()}, 207 \item {\tt SolveMap\_rowidsLower()}, 205 \item {\tt SolveMap\_rowidsUpper()}, 205 \item {\tt SolveMap\_setDefaultFields()}, 204 \item {\tt SolveMap\_symmetryflag()}, 204 \item {\tt SolveMap\_upperAggregateIV()}, 207 \item {\tt SolveMap\_upperSolveIVL()}, 206 \item {\tt SolveMap\_writeForHumanEye()}, 208 \item {\tt SolveMap\_writeStats()}, 208 \item {\tt SolveMap\_writeToBinaryFile()}, 208 \item {\tt SolveMap\_writeToFile()}, 207 \item {\tt SolveMap\_writeToFormattedFile()}, 208 \item {\tt SubMtx\_blockDiagonalInfo()}, 327 \item {\tt SubMtx\_clearData()}, 325 \item {\tt SubMtx\_columnIndices()}, 325 \item {\tt SubMtx\_complesEntry()}, 327 \item {\tt SubMtx\_denseInfo()}, 326 \item {\tt SubMtx\_denseSubcolumnsInfo()}, 327 \item {\tt SubMtx\_denseSubrowsInfo()}, 326 \item {\tt SubMtx\_diagonalInfo()}, 327 \item {\tt SubMtx\_dimensions()}, 325 \item {\tt SubMtx\_fillColumnDV()}, 331 \item {\tt SubMtx\_fillColumnZV()}, 331 \item {\tt SubMtx\_fillRowDV()}, 331 \item {\tt SubMtx\_fillRowZV()}, 331 \item {\tt SubMtx\_free()}, 325 \item {\tt SubMtx\_ids()}, 325 \item {\tt SubMtx\_init()}, 328 \item {\tt SubMtx\_initFromBuffer()}, 328 \item {\tt SubMtx\_initRandom()}, 328 \item {\tt SubMtx\_initRandomLowerTriangle()}, 328 \item {\tt SubMtx\_initRandomUpperTriangle()}, 328 \item {\tt SubMtx\_locationOfComplexEntry()}, 328 \item {\tt SubMtx\_locationOfRealEntry()}, 327 \item {\tt SubMtx\_maxabs()}, 331 \item {\tt SubMtx\_nbytesInUse()}, 330 \item {\tt SubMtx\_nbytesInWorkspace()}, 330 \item {\tt SubMtx\_nbytesNeeded()}, 330 \item {\tt SubMtx\_new()}, 325 \item {\tt SubMtx\_readFromBinaryFile()}, 332 \item {\tt SubMtx\_readFromFile()}, 331 \item {\tt SubMtx\_readFromFormattedFile()}, 331 \item {\tt SubMtx\_realEntry()}, 327 \item {\tt SubMtx\_rowIndices()}, 325 \item {\tt SubMtx\_scale1vec()}, 329 \item {\tt SubMtx\_scale2vec()}, 329 \item {\tt SubMtx\_scale3vec()}, 329 \item {\tt SubMtx\_setDefaultFields()}, 325 \item {\tt SubMtx\_setFields()}, 330 \item {\tt SubMtx\_setIds()}, 325 \item {\tt SubMtx\_setNbytesInWorkspace()}, 330 \item {\tt SubMtx\_solve()}, 329 \item {\tt SubMtx\_solveH()}, 329 \item {\tt SubMtx\_solveT()}, 329 \item {\tt SubMtx\_solveupd()}, 329 \item {\tt SubMtx\_solveupdH()}, 330 \item {\tt SubMtx\_solveupdT()}, 330 \item {\tt SubMtx\_sortColumnsUp()}, 330 \item {\tt SubMtx\_sortRowsUp()}, 330 \item {\tt SubMtx\_sparseColumnsInfo()}, 326 \item {\tt SubMtx\_sparseRowsInfo()}, 326 \item {\tt SubMtx\_sparseTriplesInfo()}, 326 \item {\tt SubMtx\_workspace()}, 330 \item {\tt SubMtx\_writeForHumanEye()}, 332 \item {\tt SubMtx\_writeForMatlab()}, 332 \item {\tt SubMtx\_writeStats()}, 332 \item {\tt SubMtx\_writeToBinaryFile()}, 332 \item {\tt SubMtx\_writeToFile()}, 332 \item {\tt SubMtx\_writeToFormattedFile()}, 332 \item {\tt SubMtx\_zero()}, 331 \item {\tt SubMtxList\_addObjectToList()}, 339 \item {\tt SubMtxList\_clearData()}, 338 \item {\tt SubMtxList\_free()}, 338 \item {\tt SubMtxList\_getList()}, 339 \item {\tt SubMtxList\_init()}, 339 \item {\tt SubMtxList\_isCountZero()}, 339 \item {\tt SubMtxList\_isListNonempty()}, 339 \item {\tt SubMtxList\_new()}, 338 \item {\tt SubMtxList\_setDefaultFields()}, 338 \item {\tt SubMtxList\_writeForHumanEye()}, 339 \item {\tt SubMtxManager\_clearData()}, 341 \item {\tt SubMtxManager\_free()}, 342 \item {\tt SubMtxManager\_init()}, 342 \item {\tt SubMtxManager\_new()}, 341 \item {\tt SubMtxManager\_newObjectOfSizeNbytes()}, 342 \item {\tt SubMtxManager\_releaseListOfObjects()}, 342 \item {\tt SubMtxManager\_releaseObject()}, 342 \item {\tt SubMtxManager\_setDefaultFields()}, 341 \item {\tt SubMtxManager\_writeForHumanEye()}, 342 \item {\tt SymbFac\_initFromGraph()}, 343 \item {\tt SymbFac\_initFromInpMtx()}, 344 \item {\tt Symbfac\_initFromPencil()}, 344 \item {\tt SymbFac\_MPI\_initFromInpMtx()}, 379 \item {\tt SymbFac\_MPI\_initFromPencil()}, 379 \indexspace \item {\tt tfqmrl()}, 304 \item {\tt tfqmrr()}, 304 \item {\tt Tree\_clearData()}, 210 \item {\tt Tree\_compress()}, 214 \item {\tt Tree\_drawToEPS()}, 215 \item {\tt Tree\_fch()}, 210 \item {\tt Tree\_fillBothPerms()}, 215 \item {\tt Tree\_fillNewToOldPerm()}, 215 \item {\tt Tree\_fillOldToNewPerm()}, 215 \item {\tt Tree\_free()}, 210 \item {\tt Tree\_fundChainMap()}, 214 \item {\tt Tree\_getSimpleCoords()}, 215 \item {\tt Tree\_height()}, 212 \item {\tt Tree\_init1()}, 211 \item {\tt Tree\_init2()}, 211 \item {\tt Tree\_init3()}, 211 \item {\tt Tree\_initFromSubtree()}, 211 \item {\tt Tree\_leftJustify()}, 214 \item {\tt Tree\_leftJustifyD()}, 214 \item {\tt Tree\_leftJustifyI()}, 214 \item {\tt Tree\_maximizeGainIV()}, 213 \item {\tt Tree\_maxNchild()}, 212 \item {\tt Tree\_nchild()}, 212 \item {\tt Tree\_nchildIV()}, 212 \item {\tt Tree\_new()}, 210 \item {\tt Tree\_nleaves()}, 212 \item {\tt Tree\_nnodes()}, 210 \item {\tt Tree\_nroots()}, 212 \item {\tt Tree\_par()}, 210 \item {\tt Tree\_permute()}, 215 \item {\tt Tree\_postOTfirst()}, 212 \item {\tt Tree\_postOTnext()}, 212 \item {\tt Tree\_preOTfirst()}, 212 \item {\tt Tree\_preOTnext()}, 212 \item {\tt Tree\_readFromBinaryFile()}, 216 \item {\tt Tree\_readFromFile()}, 216 \item {\tt Tree\_readFromFormattedFile()}, 216 \item {\tt Tree\_root()}, 210 \item {\tt Tree\_setDefaultFields()}, 210 \item {\tt Tree\_setDepthDmetric()}, 213 \item {\tt Tree\_setDepthImetric()}, 213 \item {\tt Tree\_setFchSibRoot()}, 211 \item {\tt Tree\_setHeightDmetric()}, 213 \item {\tt Tree\_setHeightImetric()}, 213 \item {\tt Tree\_setRoot()}, 211 \item {\tt Tree\_setSubtreeDmetric()}, 213 \item {\tt Tree\_setSubtreeImetric()}, 213 \item {\tt Tree\_sib()}, 210 \item {\tt Tree\_sizeOf()}, 212 \item {\tt Tree\_writeForHumanEye()}, 217 \item {\tt Tree\_writeStats()}, 217 \item {\tt Tree\_writeToBinaryFile()}, 216 \item {\tt Tree\_writeToFile()}, 216 \item {\tt Tree\_writeToFormattedFile()}, 216 \indexspace \item {\tt Zabs()}, 90 \item {\tt zbicgstabl()}, 305 \item {\tt zbicgstabr()}, 305 \item {\tt zmlbicgstabl()}, 305 \item {\tt zmlbicgstabr()}, 305 \item {\tt zpcgl()}, 306 \item {\tt zpcgr()}, 306 \item {\tt Zrecip()}, 90 \item {\tt Zrecip2()}, 90 \item {\tt ztfqmrl()}, 305 \item {\tt ztfqmrr()}, 305 \item {\tt ZV\_clearData()}, 109 \item {\tt ZV\_copy()}, 112 \item {\tt ZV\_entries()}, 110 \item {\tt ZV\_entry()}, 110 \item {\tt ZV\_fill()}, 112 \item {\tt ZV\_free()}, 109 \item {\tt ZV\_init()}, 110 \item {\tt ZV\_init1()}, 110 \item {\tt ZV\_init2()}, 111 \item {\tt ZV\_log10profile()}, 112 \item {\tt ZV\_maxabs()}, 111 \item {\tt ZV\_size()}, 110 \item {\tt ZV\_minabs()}, 111 \item {\tt ZV\_new()}, 109 \item {\tt ZV\_owned()}, 109 \item {\tt ZV\_pointersToEntry()}, 110 \item {\tt ZV\_push()}, 111 \item {\tt ZV\_readFromBinaryFile()}, 112 \item {\tt ZV\_readFromFile()}, 112 \item {\tt ZV\_readFromFormattedFile()}, 112 \item {\tt ZV\_setDefaultFields()}, 109 \item {\tt ZV\_setEntry()}, 110 \item {\tt ZV\_setMaxsize()}, 111 \item {\tt ZV\_setSize()}, 111 \item {\tt ZV\_shiftBase()}, 111 \item {\tt ZV\_size()}, 109 \item {\tt ZV\_sizeAndEntries()}, 110 \item {\tt ZV\_sizeOf()}, 111 \item {\tt ZV\_writeForHumanEye()}, 113 \item {\tt ZV\_writeForMatlab()}, 113 \item {\tt ZV\_writeStats()}, 113 \item {\tt ZV\_writeToBinaryFile()}, 113 \item {\tt ZV\_writeToFile()}, 113 \item {\tt ZV\_writeToFormattedFile()}, 113 \item {\tt ZV\_zero()}, 112 \item {\tt ZVaxpy()}, 90 \item {\tt ZVaxpy11()}, 92 \item {\tt ZVaxpy12()}, 91 \item {\tt ZVaxpy13()}, 91 \item {\tt ZVaxpy21()}, 91 \item {\tt ZVaxpy22()}, 91 \item {\tt ZVaxpy23()}, 91 \item {\tt ZVaxpy31()}, 91 \item {\tt ZVaxpy32()}, 91 \item {\tt ZVaxpy33()}, 90 \item {\tt ZVcopy()}, 92 \item {\tt ZVdotC()}, 92 \item {\tt ZVdotC11()}, 96 \item {\tt ZVdotC12()}, 96 \item {\tt ZVdotC13()}, 95 \item {\tt ZVdotC21()}, 95 \item {\tt ZVdotC22()}, 95 \item {\tt ZVdotC23()}, 95 \item {\tt ZVdotC31()}, 95 \item {\tt ZVdotC32()}, 94 \item {\tt ZVdotC33()}, 94 \item {\tt ZVdotiC()}, 92 \item {\tt ZVdotiU()}, 92 \item {\tt ZVdotU()}, 92 \item {\tt ZVdotU11()}, 94 \item {\tt ZVdotU12()}, 94 \item {\tt ZVdotU13()}, 94 \item {\tt ZVdotU21()}, 93 \item {\tt ZVdotU22()}, 93 \item {\tt ZVdotU23()}, 93 \item {\tt ZVdotU31()}, 93 \item {\tt ZVdotU32()}, 92 \item {\tt ZVdotU33()}, 92 \item {\tt ZVfprintf()}, 90 \item {\tt ZVgather()}, 96 \item {\tt ZVinit()}, 90 \item {\tt ZVmaxabs()}, 96 \item {\tt ZVminabs()}, 96 \item {\tt ZVscale()}, 96 \item {\tt ZVscatter()}, 96 \item {\tt ZVsub()}, 96 \item {\tt ZVzero()}, 96 \end{theindex} em {\tt PIVsetup()}, 101 \indexspace \item {\tt SemiImplMtx\_clearData()}, 318 \item {\tt SemiImplMtx\_free()}, 319 \item {\tt SemiImplMtx\_initFromFrontMtx()}, 319 \item {\tt SemiImplMtx\_new()}, 318 \item {\tt SemiImplMtx\_setDefaultFields()}, 318 \item {\tt SemiImplMtx\_solve()}, 319 \item {\tt SemiImplMtx\_stats()}, 320 \item {\tt SemiImplMtx\_writeForHumanEye()}, 320 \item {\tt SolveMap\_backwardSetup()}, 206 \item documentation/ReferenceManual/main.lof010064400020550007177000000046000665314325500214350ustar00clevecompmath00000400000006\addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \contentsline {figure}{\numberline {19.1}{\ignorespaces {\sc GRD7x7}: Working storage for the forward sparse factorization of the nested dissection ordering. On the left is the storage required to factor ${\mathaccent "0362\relax J}$ and its update matrix. On the right is the storage required to factor $J$ and all of its ancestors. Both plots have the same scale.}}{158} \contentsline {figure}{\numberline {19.2}{\ignorespaces {\sc GRD7x7x7}: Four tree plots for a $7 \times 7 \times 7$ grid matrix ordered using nested dissection. The top left tree measure number of original matrix entries in a front. The top right tree measure number of factor matrix entries in a front. The bottom left tree measure number of factor operations in a front for a forward looking factorization, e.g., forward sparse. The bottom right tree measure number of factor operations in a front for a backward looking factorization, e.g., general sparse.}}{162} \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \contentsline {figure}{\numberline {25.1}{\ignorespaces {\sc R2D100}: domain/separator tree. On the left {\tt heightflag = 'H'} and {\tt coordflag = 'C'}, on the right {\tt heightflag = 'D'} and {\tt coordflag = 'C'}.}}{218} \contentsline {figure}{\numberline {25.2}{\ignorespaces {\sc R2D100}: domain/separator tree. On the left {\tt heightflag = 'H'} and {\tt coordflag = 'P'}, on the right {\tt heightflag = 'D'} and {\tt coordflag = 'P'}.}}{218} \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } \contentsline {figure}{\numberline {41.1}{\ignorespaces {\sc R2D100}}}{355} \contentsline {figure}{\numberline {41.2}{\ignorespaces {\sc R2D100: fishnet domain decomposition}}}{356} \addvspace {10\p@ } \addvspace {10\p@ } documentation/ReferenceManual/main.log010064400020550007177000001146260665314325500214500ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 25 JAN 1999 11:30 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) (/home/tex/teTeX/texmf/tex/latex/amslatex/amsmath.sty Package: amsmath 1996/11/01 v1.2c AMS math features \@mathmargin=\skip43 (/home/tex/teTeX/texmf/tex/latex/amslatex/amstext.sty Package: amstext 1996/10/28 v1.2b (/home/tex/teTeX/texmf/tex/latex/amslatex/amsgen.sty File: amsgen 1996/10/29 v1.2b \@emptytoks=\toks14 \ex@=\dimen103 )) (/home/tex/teTeX/texmf/tex/latex/amslatex/amsbsy.sty Package: amsbsy 1996/10/28 v1.2b \pmbraise@=\dimen104 ) (/home/tex/teTeX/texmf/tex/latex/amslatex/amsopn.sty Package: amsopn 1996/10/28 v1.2b operator names ) LaTeX Info: Redefining \frac on input line 188. \uproot@=\count88 \leftroot@=\count89 \classnum@=\count90 \DOTSCASE@=\count91 LaTeX Info: Redefining \dots on input line 335. LaTeX Info: Redefining \ldots on input line 418. LaTeX Info: Redefining \cdots on input line 422. \Mathstrutbox@=\box26 \strutbox@=\box27 \big@size=\dimen105 LaTeX Font Info: Redeclaring font encoding OML on input line 500. LaTeX Font Info: Redeclaring font encoding OMS on input line 501. \skewcharcount@=\count92 \familycount@=\count93 \pointcount@=\count94 \accentdimen@=\dimen106 \accentmu@=\count95 \minaw@=\dimen107 \c@MaxMatrixCols=\count96 \dotsspace@=\muskip10 \c@parentequation=\count97 \dspbrk@lvl=\count98 \tag@help=\toks15 \row@=\count99 \column@=\count100 \maxfields@=\count101 \andhelp@=\toks16 \eqnshift@=\dimen108 \alignsep@=\dimen109 \tagshift@=\dimen110 \tagwidth@=\dimen111 \totwidth@=\dimen112 \lineht@=\dimen113 \@envbody=\toks17 \multlinegap=\skip44 \multlinetaggap=\skip45 ) \@indexfile=\write3 Writing index file main.idx (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen114 \p@intvaluey=\dimen115 psfig/tex 1.10-dvips ) (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 31. LaTeX Font Info: ... okay on input line 31. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 31. LaTeX Font Info: ... okay on input line 31. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 31. LaTeX Font Info: ... okay on input line 31. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 31. LaTeX Font Info: ... okay on input line 31. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 31. LaTeX Font Info: ... okay on input line 31. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 31. LaTeX Font Info: ... okay on input line 31. Underfull \hbox (badness 3635) in paragraph at lines 90--90 [][]\OT1/cmr/m/n/9 Boeing Shared Ser-vices Group, P. O. Box 24346, Mail Stop 7L -22, Seat-tle, Wash-ing-ton 98124, [] Underfull \hbox (badness 3635) in paragraph at lines 90--90 [][]\OT1/cmr/m/n/9 Boeing Shared Ser-vices Group, P. O. Box 24346, Mail Stop 7L -22, Seat-tle, Wash-ing-ton 98124, [] Underfull \hbox (badness 3635) in paragraph at lines 90--90 [][]\OT1/cmr/m/n/9 Boeing Shared Ser-vices Group, P. O. Box 24346, Mail Stop 7L -22, Seat-tle, Wash-ing-ton 98124, [] Underfull \hbox (badness 3635) in paragraph at lines 90--90 [][]\OT1/cmr/m/n/9 Boeing Shared Ser-vices Group, P. O. Box 24346, Mail Stop 7L -22, Seat-tle, Wash-ing-ton 98124, [] [1 ] [1] (main.toc [2 ] Underfull \hbox (badness 10000) in paragraph at lines 36--36 [] []\OT1/cmtt/m/n/10 Drand\OT1/cmr/bx/n/10 : [] [3] [4] Underfull \hbox (badness 10000) in paragraph at lines 145--145 [] []\OT1/cmtt/m/n/10 DSTree\OT1/cmr/bx/n/10 : [] [5] [6] Underfull \hbox (badness 10000) in paragraph at lines 202--202 [] []\OT1/cmtt/m/n/10 MSMD\OT1/cmr/bx/n/10 : [] [7] [8] [9] [10] [11] [12]) \tf@toc=\write5 [13] (main.lof) \tf@lof=\write6 (partIntro.tex [14 ] [15 ] [16] Chapter 1. LaTeX Font Info: Try loading font information for OMS+cmr on input line 8. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 8. Underfull \vbox (badness 10000) has occurred while \output is active [] [17 ] [18] LaTeX Font Info: Try loading font information for OMS+cmtt on input line 238 . LaTeX Font Info: No file OMScmtt.fd. on input line 238. LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined (Font) using `OMS/cmsy/m/n' instead (Font) for symbol `textbraceleft' on input line 238. [19] [20] [21]) (partUtil.tex [22] [23 ] [24] (../../A2/doc/intro.tex Chapter 2. ) (../../A2/doc/dataStructure.tex Overfull \hbox (22.05931pt too wide) in paragraph at lines 44--54 \OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 A2[]copyEntriesToVector() \OT1/cmr/m/n/10 method uses the fol-low-ing con-stants: \OT1/cmtt/m/n/10 A2[]STRICT[]LOWER\OT1/ cmr/m/n/10 , \OT1/cmtt/m/n/10 A2[]LOWER\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 A2[]D IAGONAL\OT1/cmr/m/n/10 , [] ) (../../A2/doc/proto.tex [25 ] [26] [27] Overfull \hbox (9.5478pt too wide) in paragraph at lines 290--295 \OT1/cmr/m/n/10 Note, \OT1/cmtt/m/n/10 firstrow\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/ 10 lastrow\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 firstcol \OT1/cmr/m/n/10 and \OT1/ cmtt/m/n/10 lastcol \OT1/cmr/m/n/10 must sat-isfy \OT1/cmtt/m/n/10 0 <= firstro w <= lastrow < mtxB->n1 [] [28] [29] [30] [31] Overfull \hbox (0.273pt too wide) in paragraph at lines 776--779 []\OT1/cmr/m/n/10 This method fills the ma-trix with ran-dom num-bers taken fro m a uni-form dis-tri-bu-tion on \OT1/cmtt/m/n/10 [lower,upper] [] [32] [33]) (../../A2/doc/drivers.tex [34]) (../../Coords/doc/intro.tex [35] Chapter 3. ) (../../Coords/doc/dataStructure.tex) (../../Coords/doc/proto.tex [36 ] [37] [38] Overfull \hbox (16.26517pt too wide) in paragraph at lines 330--336 []\OT1/cmr/m/n/10 This method write the \OT1/cmtt/m/n/10 Coords \OT1/cmr/m/n/10 ob-ject to a file in an easy to read fash-ion. The method \OT1/cmtt/m/n/10 Coo rds[]writeStats() [] ) (../../Coords/doc/drivers.tex [39]) (../../DV/doc/intro.tex [40] Chapter 4. ) (../../DV/doc/dataStructure.tex) (../../DV/doc/proto.tex Overfull \hbox (5.16449pt too wide) in paragraph at lines 23--1 \OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 size\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 max size\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 nowned \OT1/cmr/m/n/10 and \OT1/cmtt/m/n /10 vec \OT1/cmr/m/n/10 fields need never be ac-cessed di-rectly --- see the \O T1/cmtt/m/n/10 DV[]size()\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 DV[]maxsize()\OT1/c mr/m/n/10 , [] [41 ] [42] LaTeX Font Info: Try loading font information for OML+cmr on input line 197. (/home/tex/teTeX/texmf/tex/latex/base/omlcmr.fd File: omlcmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OML/cmr/m/n' in size <10> not available (Font) Font shape `OML/cmm/m/it' tried instead on input line 197. [43] [44] [45]) (../../DV/doc/drivers.tex [46]) (../../Drand/doc/intro.tex [47] Chapter 5. ) (../../Drand/doc/dataStructure.tex) (../../Drand/doc/proto.tex [48 ] [49]) (../../Drand/doc/drivers.tex [50]) (../../I2Ohash/doc/intro.tex [51] Chapter 6. ) (../../I2Ohash/doc/dataStructure.tex) (../../I2Ohash/doc/proto.tex [52 ] Overfull \hbox (17.40442pt too wide) in paragraph at lines 80--86 []\OT1/cmr/m/n/10 This method is the ba-sic ini-tial-izer method. It clears any pre-vi-ous data with a call to \OT1/cmtt/m/n/10 I2Ohash[]clearData()\OT1/cmr/m /n/10 . [] [53]) (../../I2Ohash/doc/drivers.tex [54]) (../../IIheap/doc/intro.tex [55] Chapter 7. ) (../../IIheap/doc/dataStructure.tex) (../../IIheap/doc/proto.tex [56 ] Overfull \hbox (80.88438pt too wide) in paragraph at lines 44--49 \OT1/cmtt/m/n/10 heap->keys \OT1/cmr/m/n/10 and \OT1/cmtt/m/n/10 heap->values \ OT1/cmr/m/n/10 vec-tors, then sets the struc-ture's de-fault fields with a call to \OT1/cmtt/m/n/10 IIheap[]setDefaultFields()\OT1/cmr/m/n/10 . [] Overfull \hbox (12.15446pt too wide) in paragraph at lines 80--87 []\OT1/cmr/m/n/10 This method is the ba-sic ini-tial-izer method. It clears any pre-vi-ous data with a call to \OT1/cmtt/m/n/10 IIheap[]clearData()\OT1/cmr/m/ n/10 , [] ) (../../IV/doc/intro.tex [57] Chapter 8. ) (../../IV/doc/dataStructure.tex [58 ]) (../../IV/doc/proto.tex [59] [60] [61] [62] [63] [64]) (../../IV/doc/drivers.tex) (../../IVL/doc/intro.tex [65] Chapter 9. ) (../../IVL/doc/dataStructure.tex [66 ]) (../../IVL/doc/proto.tex [67] Overfull \hbox (1.08043pt too wide) in paragraph at lines 166--171 []\OT1/cmr/m/n/10 This method is used when the num-ber of lists and their to-ta l size is known --- \OT1/cmtt/m/n/10 type \OT1/cmr/m/n/10 must be \OT1/cmtt/m/n /10 IVL[]CHUNKED\OT1/cmr/m/n/10 . [] Overfull \hbox (1.49115pt too wide) in paragraph at lines 199--199 []\OT1/cmtt/m/n/10 int IVL_initFromSubIVL ( IVL *subIVL, IVL *ivl, IV *keeplis tIV, IV *keepentriesIV ) ;[] [] [68] [69] [70] [71] [72]) (../../IVL/doc/drivers.tex) (../../Ideq/doc/intro.tex [73] Chapter 10. ) (../../Ideq/doc/dataStructure.tex) (../../Ideq/doc/proto.tex [74 ] [75]) (../../Lock/doc/intro.tex [76] Chapter 11. ) (../../Lock/doc/dataStructure.tex) (../../Lock/doc/proto.tex [77 ] Overfull \hbox (18.04205pt too wide) in paragraph at lines 40--47 []\OT1/cmr/m/n/10 This method clears the data for the ob-ject. If \OT1/cmtt/m/n /10 lock->mutex \OT1/cmr/m/n/10 is not \OT1/cmtt/m/n/10 NULL\OT1/cmr/m/n/10 , t hen \OT1/cmtt/m/n/10 mutex[]destroy(lock->mutex) [] ) (../../Perm/doc/intro.tex [78] Chapter 12. ) (../../Perm/doc/dataStructure.tex) (../../Perm/doc/proto.tex [79 ] [80] [81] Overfull \hbox (17.45987pt too wide) in paragraph at lines 317--323 []\OT1/cmr/m/n/10 This method writes out a \OT1/cmtt/m/n/10 Perm \OT1/cmr/m/n/1 0 ob-ject to a file in a hu-man read-able for-mat. The method \OT1/cmtt/m/n/10 Perm[]writeStats() [] ) (../../Utilities/doc/intro.tex [82] Chapter 13. ) (../../Utilities/doc/dataStructure.tex) (../../Utilities/doc/proto.tex (../../Utilities/doc/CV.tex [83 ]) (../../Utilities/doc/DV.tex [84] [85] [86] [87] [88] [89]) (../../Utilities/doc/ZV.tex Overfull \hbox (23.13327pt too wide) in paragraph at lines 51--57 []\OT1/cmr/m/n/10 This method fills \OT1/cmtt/m/n/10 *pbreal \OT1/cmr/m/n/10 an d \OT1/cmtt/m/n/10 *pbimag \OT1/cmr/m/n/10 with the real and imag-i-nary parts of the re-cip-ro-cal of \OT1/cmtt/m/n/10 (areal,aimag)\OT1/cmr/m/n/10 . [] [90] [91] [92] [93] [94] [95]) (../../Utilities/doc/IV.tex [96] [97]) (../../Utilities/doc/FV.tex [98] [99]) (../../Utilities/doc/PCV.tex [100]) (../../Utilities/doc/PDV.tex) (../../Utilities/doc/PIV.tex) (../../Utilities/doc/PFV.tex [101]) (../../Utilities/doc/sort.tex [102] [103] [104]) (../../Utilities/doc/IP.tex [105]) (../../Utilities/doc/I2OP.tex Overfull \hbox (4.87234pt too wide) in paragraph at lines 57--62 []\OT1/cmr/m/n/10 This is an ini-tial-izer method for a vec-tor of \OT1/cmtt/m/ n/10 I2OP \OT1/cmr/m/n/10 struc-tures. We set \OT1/cmtt/m/n/10 base[i].value0 = base[i].value1 [] )) (../../Utilities/doc/drivers.tex [106]) (../../ZV/doc/intro.tex [107] Chapter 14. ) (../../ZV/doc/dataStructure.tex) (../../ZV/doc/proto.tex Overfull \hbox (5.16449pt too wide) in paragraph at lines 23--1 \OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 size\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 max size\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 nowned \OT1/cmr/m/n/10 and \OT1/cmtt/m/n /10 vec \OT1/cmr/m/n/10 fields need never be ac-cessed di-rectly --- see the \O T1/cmtt/m/n/10 ZV[]size()\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 ZV[]maxsize()\OT1/c mr/m/n/10 , [] [108 ] [109] [110] [111] [112]) (../../ZV/doc/drivers.tex [113])) (partOrder.tex [11 4] [115 ] [116] (../../BKL/doc/intro.tex Chapter 15. ) (../../BKL/doc/dataStructure.tex [117 ]) (../../BKL/doc/proto.tex [118] [119] [120]) (../../BPG/doc/intro.tex [121] Chapter 16. [122 ] [123]) (../../BPG/doc/dataStructure.tex) (../../BPG/doc/proto.tex [124] [125] Overfull \hbox (66.05252pt too wide) in paragraph at lines 260--262 []\OT1/cmr/m/n/10 This method has the same func-tion-al-ity, call-ing se-quence and re-turned val-ues as the pre-ced-ing \OT1/cmtt/m/n/10 BPG[]DMdecomposition () [] [126]) (../../BPG/doc/drivers.tex [127]) (../../DSTree/doc/intro.tex [128] Chapter 17. ) (../../DSTree/doc/dataStructure.tex) (../../DSTree/doc/proto.tex [129 ] [130] [131] [132] Overfull \hbox (21.79298pt too wide) in paragraph at lines 428--437 []\OT1/cmr/m/n/10 This method writes a \OT1/cmtt/m/n/10 DSTree \OT1/cmr/m/n/10 ob-ject to a file in a hu-man read-able for-mat. The method \OT1/cmtt/m/n/10 DS Tree[]writeStats() [] ) (../../DSTree/doc/drivers.tex [133]) (../../EGraph/doc/intro.tex [134] Chapter 18. ) (../../EGraph/doc/dataStructure.tex) (../../EGraph/doc/proto.tex [135 ] [136] Overfull \hbox (27.34856pt too wide) in paragraph at lines 264--274 []\OT1/cmr/m/n/10 This method writes an \OT1/cmtt/m/n/10 EGraph \OT1/cmr/m/n/10 ob-ject to a file in a hu-man read-able for-mat. The method \OT1/cmtt/m/n/10 E Graph[]writeStats() [] Overfull \hbox (59.98613pt too wide) in paragraph at lines 264--274 \OT1/cmr/m/n/10 is called to write out the header and statis-tics. Then the \OT 1/cmtt/m/n/10 adjIVL \OT1/cmr/m/n/10 ob-ject is writ-ten out us-ing \OT1/cmtt/m /n/10 IVL[]writeForHumanEye()\OT1/cmr/m/n/10 . [] [137]) (../../EGraph/doc/drivers.tex [138]) (../../ETree/doc/intro.tex [139] Chapter 19. ) (../../ETree/doc/dataStructure.tex) (../../ETree/doc/proto.tex [140 ] Overfull \hbox (10.32721pt too wide) in paragraph at lines 32--35 []\OT1/cmr/m/n/10 This method sets the struc-ture's fields are set to de-fault val-ues: \OT1/cmtt/m/n/10 nfront = nvtx = 0\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 t ree = nodwghtsIV [] [141] [142] [143] Overfull \hbox (6.7411pt too wide) in paragraph at lines 354--354 []\OT1/cmtt/m/n/10 int ETree_initFromSubtree ( ETree *subtree, IV *nodeidsIV, ETree *etree, IV *vtxIV ) ;[] [] Overfull \hbox (9.87708pt too wide) in paragraph at lines 468--475 \OT1/cmr/m/n/10 (1\OML/cmm/m/it/10 ; \OT1/cmr/m/n/10 2)$ blocks dur-ing a fac-t or-iza-tion. The \OT1/cmtt/m/n/10 type \OT1/cmr/m/n/10 pa-ram-e-ter can be one of \OT1/cmtt/m/n/10 SPOOLES[]REAL \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/10 SPOOLES[] COMPLEX\OT1/cmr/m/n/10 . [] [144] Overfull \hbox (22.49097pt too wide) in paragraph at lines 565--565 []\OT1/cmtt/m/n/10 ETree * ETree_spliceTwoEtrees ( ETree *etree0, Graph *graph , IV *mapIV, ETree *etree1 ) ;[] [] [145] [146] [147] [148] [149] Overfull \hbox (14.4601pt too wide) in paragraph at lines 1095--1102 \OT1/cmr/m/n/10 us-ing \OT1/cmtt/m/n/10 ETree[]mergeFrontsOne() \OT1/cmr/m/n/10 fol-lowed by \OT1/cmtt/m/n/10 ETree[]mergeFrontsAll()\OT1/cmr/m/n/10 . See the driver pro-grams \OT1/cmtt/m/n/10 testTransform [] [150] [151] [152] [153] Overfull \hbox (30.76532pt too wide) in paragraph at lines 1493--1501 []\OT1/cmr/m/n/10 This method writes an \OT1/cmtt/m/n/10 ETree \OT1/cmr/m/n/10 ob-ject to a file in a read-able for-mat. Oth-er-wise, the method \OT1/cmtt/m/n /10 ETree[]writeStats() [] ) (../../ETree/doc/drivers.tex [154] [155] [156] Overfull \hbox (31.12537pt too wide) in paragraph at lines 320--328 \OT1/cmtt/m/n/10 outETreeFile \OT1/cmr/m/n/10 is \OT1/cmtt/m/n/10 none \OT1/cmr /m/n/10 then the \OT1/cmtt/m/n/10 ETree \OT1/cmr/m/n/10 ob-ject is not writ-ten to a file. Oth-er-wise, the \OT1/cmtt/m/n/10 ETree[]writeToFile() [] [157] psfig: searching ../../ETree/doc/FS1.eps for bounding box psfig: including ../../ETree/doc/FS1.eps psfig: searching ../../ETree/doc/FS2.eps for bounding box psfig: including ../../ETree/doc/FS2.eps [158] [159] [160] psfig: searching ../../ETree/doc/GRD7x7x7_nzA.eps for bounding box psfig: including ../../ETree/doc/GRD7x7x7_nzA.eps psfig: searching ../../ETree/doc/GRD7x7x7_nzF.eps for bounding box psfig: including ../../ETree/doc/GRD7x7x7_nzF.eps psfig: searching ../../ETree/doc/GRD7x7x7_forwops.eps for bounding box psfig: including ../../ETree/doc/GRD7x7x7_forwops.eps psfig: searching ../../ETree/doc/GRD7x7x7_backops.eps for bounding box psfig: including ../../ETree/doc/GRD7x7x7_backops.eps psfig: searching ../../ETree/doc/workingStorage.eps for bounding box psfig: including ../../ETree/doc/workingStorage.eps [161] [162]) (../../GPart/doc/intro.tex [163] [164] Chapter 20. ) (../../GPart/doc/dataStructure.tex [165 ] [166]) (../../GPart/doc/proto.tex [167] [168] [169] [170] [171] [172]) (../../GPart/doc/drivers.tex [173] [174] [175]) (../../Graph/doc/intro.tex [176] Chapter 21. [177 ]) (../../Graph/doc/dataStructure.tex) (../../Graph/doc/proto.tex [178] [179] [180] [181] [182] Overfull \hbox (11.29308pt too wide) in paragraph at lines 531--536 []\OT1/cmr/m/n/10 This method writes a \OT1/cmtt/m/n/10 Graph \OT1/cmr/m/n/10 o b-ject to a file in a hu-man read-able for-mat. The method \OT1/cmtt/m/n/10 Gra ph[]writeStats() [] ) (../../Graph/doc/drivers.tex [183] [184] Overfull \hbox (27.02443pt too wide) in paragraph at lines 200--204 []\OT1/cmr/m/n/10 This driver pro-gram reads in a \OT1/cmtt/m/n/10 Graph \OT1/c mr/m/n/10 ob-ject and tests whether it is sym-met-ric us-ing the \OT1/cmtt/m/n/ 10 Graph[]isSymmetric() [] psfig: searching ../../Graph/doc/rad1.eps for bounding box psfig: including ../../Graph/doc/rad1.eps psfig: searching ../../Graph/doc/rad2.eps for bounding box psfig: including ../../Graph/doc/rad2.eps [185]) (../../MSMD/doc/intro.tex [186] Chapter 22. [187 ]) (../../MSMD/doc/dataStructure.tex [188] [189] [190]) (../../MSMD/doc/proto.tex [191] [192] [193] Overfull \hbox (39.69234pt too wide) in paragraph at lines 336--339 []\OT1/cmr/m/n/10 This method cleans the nodes in the reach set by call-ing \OT 1/cmtt/m/n/10 MSMD[]cleanSubtreeList() \OT1/cmr/m/n/10 and \OT1/cmtt/m/n/10 MSM D[]clearEdgeList()\OT1/cmr/m/n/10 . [] [194]) (../../MSMD/doc/drivers.tex [195] Overfull \hbox (2.44388pt too wide) in paragraph at lines 72--75 []\OT1/cmtt/m/n/10 stepType == 0 \OT1/cmr/m/n/10 --- one ver-tex elim-i-nated a t each step, like YSMP, and QMD from SPARSPAK. [] [196]) (../../Network/doc/intro.tex [197] Chapter 23. [198 ]) (../../Network/doc/dataStructure.tex [199]) (../../Network/doc/proto.tex [20 0] [201] Overfull \hbox (10.01547pt too wide) in paragraph at lines 232--238 []\OT1/cmr/m/n/10 This method writes the net-work to a file in a hu-man read-ab le for-mat. The method \OT1/cmtt/m/n/10 Network[]writeStats() [] ) (../../SolveMap/doc/intro.tex [202] Chapter 24. ) (../../SolveMap/doc/dataStructure.tex) (../../SolveMap/doc/proto.tex [203 ] [204] Overfull \hbox (1.13116pt too wide) in paragraph at lines 223--230 \OT1/cmr/m/it/10 Error check-ing: \OT1/cmr/m/n/10 If \OT1/cmtt/m/n/10 solvemap \OT1/cmr/m/n/10 is \OT1/cmtt/m/n/10 NULL\OT1/cmr/m/n/10 , or \OT1/cmtt/m/n/10 s ymmetryflag \OT1/cmr/m/n/10 is in-valid, or \OT1/cmtt/m/n/10 nfront\OT1/cmr/m/n /10 , \OT1/cmtt/m/n/10 nblockUpper\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 nblockLowe r [] [205] [206] Overfull \hbox (43.46613pt too wide) in paragraph at lines 391--404 \OT1/cmr/m/n/10 and \OT1/cmtt/m/n/10 mapidsUpper[*]\OT1/cmr/m/n/10 , and if \OT 1/cmtt/m/n/10 symmetryflag = SPOOLES[]NONSYMMETRIC\OT1/cmr/m/n/10 , fol-lowed b y \OT1/cmtt/m/n/10 rowidsLower[*]\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 colidsLower [*] [] [207] Overfull \hbox (48.40392pt too wide) in paragraph at lines 508--513 []\OT1/cmr/m/n/10 This method writes an \OT1/cmtt/m/n/10 SolveMap \OT1/cmr/m/n/ 10 ob-ject to a file in an eas-ily read-able for-mat. The method \OT1/cmtt/m/n/ 10 SolveMap[]writeStats() [] ) (../../Tree/doc/intro.tex [208] Chapter 25. ) (../../Tree/doc/dataStructure.tex) (../../Tree/doc/proto.tex [209 ] [210] [211] [212] [213] [214] [215] Overfull \hbox (0.79317pt too wide) in paragraph at lines 830--837 []\OT1/cmr/m/n/10 This method writes a \OT1/cmtt/m/n/10 Perm \OT1/cmr/m/n/10 ob -ject to a file in a hu-man read-able for-mat. The method \OT1/cmtt/m/n/10 Tree []writeStats() [] [216]) (../../Tree/doc/drivers.tex psfig: searching ../../Tree/doc/R2D100HC.eps for bounding box psfig: including ../../Tree/doc/R2D100HC.eps psfig: searching ../../Tree/doc/R2D100DC.eps for bounding box psfig: including ../../Tree/doc/R2D100DC.eps psfig: searching ../../Tree/doc/R2D100HP.eps for bounding box psfig: including ../../Tree/doc/R2D100HP.eps psfig: searching ../../Tree/doc/R2D100DP.eps for bounding box psfig: including ../../Tree/doc/R2D100DP.eps )) (partNumeric.tex [217] [218] [219 ] [220] (../../Chv/doc/intro.tex Chapter 26. psfig: searching ../../Chv/doc/simple.eps for bounding box psfig: including ../../Chv/doc/simple.eps [221 ] psfig: searching ../../Chv/doc/simple2.eps for bounding box psfig: including ../../Chv/doc/simple2.eps ) (../../Chv/doc/dataStructure.tex [222]) (../../Chv/doc/proto.tex [223] [224] [225] [226] [227] [228] [229] [230] [231] [232] [233]) (../../Chv/doc/drivers.tex [234] Overfull \hbox (28.32214pt too wide) in paragraph at lines 99--107 \OT1/cmr/m/n/10 been fac-tored to store the en-tries into dense $\OML/cmm/m/it/ 10 L$ \OT1/cmr/m/n/10 and $\OML/cmm/m/it/10 U$ \OT1/cmr/m/n/10 sub-ma-tri-ces. Use the script file \OT1/cmtt/m/n/10 do[]copyEntriesToVector [] [235] [236] [237] Overfull \hbox (47.11063pt too wide) in paragraph at lines 406--415 []\OT1/cmr/m/n/10 This driver pro-gram tests three meth-ods: \OT1/cmtt/m/n/10 C hv[]swapRowsAndColumns()\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 Chv[]swapRows() \OT1 /cmr/m/n/10 and \OT1/cmtt/m/n/10 Chv[]swapColumns()\OT1/cmr/m/n/10 . [] [238]) (../../ChvList/doc/intro.tex [239] Chapter 27. ) (../../ChvList/doc/dataStructure.tex [240 ]) (../../ChvList/doc/proto.tex [241]) (../../ChvManager/doc/intro.tex [242] Chapter 28. ) (../../ChvManager/doc/dataStructure.tex [243 ]) (../../ChvManager/doc/proto.tex [244]) (../../DenseMtx/doc/intro.tex [245] Chapter 29. ) (../../DenseMtx/doc/dataStructure.tex) (../../DenseMtx/doc/proto.tex [246 ] [247] [248] [249] [250] [251] [252]) (../../FrontMtx/doc/intro.tex [253] Chapter 30. psfig: searching ../../FrontMtx/doc/simple.eps for bounding box psfig: including ../../FrontMtx/doc/simple.eps [254 ] [255]) (../../FrontMtx/doc/dataStructure.tex [256] [257]) (../../FrontMtx/doc/proto.tex [258] [259] [260] [261] Overfull \hbox (13.35185pt too wide) in paragraph at lines 368--376 \OT1/cmr/m/it/10 Error check-ing: \OT1/cmr/m/n/10 If \OT1/cmtt/m/n/10 frontmtx\ OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 frontETree \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/1 0 symbfacIVL \OT1/cmr/m/n/10 is \OT1/cmtt/m/n/10 NULL\OT1/cmr/m/n/10 , or if \O T1/cmtt/m/n/10 type\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 symmetryflag\OT1/cmr/m/n/ 10 , \OT1/cmtt/m/n/10 sparsityflag [] [262] Overfull \hbox (24.57285pt too wide) in paragraph at lines 503--508 \OT1/cmr/m/n/10 gre-gate fronts and help syn-chro-nize the fac-tor-iza-tion. Th ere is an anal-o-gous \OT1/cmtt/m/n/10 FrontMtx[]MPI[]aggregateList() [] [263] [264] [265] Overfull \hbox (1.49115pt too wide) in paragraph at lines 765--765 [] \OT1/cmtt/m/n/10 ChvManager *chvmanager, int msglvl, FILE *msgFile ) ;[] [] [266] [267] [268] [269] [270] Overfull \hbox (42.7928pt too wide) in paragraph at lines 1297--1302 []\OT1/cmr/m/n/10 This method writes a \OT1/cmtt/m/n/10 FrontMtx \OT1/cmr/m/n/1 0 ob-ject to a file in a hu-man read-able for-mat. The method \OT1/cmtt/m/n/10 FrontMtx[]writeStats() [] ) (../../FrontMtx/doc/drivers.tex [271]) (../../ILUMtx/doc/intro.tex [272] Chapter 31. ) (../../ILUMtx/doc/dataStructure.tex Overfull \hbox (59.24767pt too wide) in paragraph at lines 14--18 []\OT1/cmtt/m/n/10 int symmetryflag \OT1/cmr/m/n/10 : type of ma-trix sym-me-tr y, \OT1/cmtt/m/n/10 SPOOLES[]SYMMETRIC\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 SPOOLE S[]HERMITIAN \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/10 SPOOLES[]NONSYMMETRIC\OT1/cmr/ m/n/10 . [] [273 ]) (../../ILUMtx/doc/proto.tex Overfull \hbox (11.74596pt too wide) in paragraph at lines 32--40 []\OT1/cmr/m/n/10 This method sets the struc-ture's fields to de-fault val-ues: \OT1/cmtt/m/n/10 neqns = 0\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 type \OT1/cmr/m/n /10 = \OT1/cmtt/m/n/10 SPOOLES[]REAL\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 symmetry flag [] [274] [275]) (../../ILUMtx/doc/drivers.tex [276]) (../../InpMtx/doc/intro.tex [277] Chapter 32. [278 ]) (../../InpMtx/doc/dataStructure.tex [279] Overfull \hbox (10.7373pt too wide) in paragraph at lines 74--79 []\OT1/cmtt/m/n/10 int maxnvector \OT1/cmr/m/n/10 -- present max-i-mum num-ber of vec-tors. This quan-tity is ini-tial-ized by the \OT1/cmtt/m/n/10 InpMtx[]in it() [] [280]) (../../InpMtx/doc/proto.tex [281] [282] [283] Overfull \hbox (9.61465pt too wide) in paragraph at lines 390--400 []\OT1/cmr/m/n/10 This method changes the co-or-di-nate type. If $[] = []$, the pro-gram re-turns. If $[] \OMS/cmtt/m/n/10 ^^U [] [284] [285] [286] Overfull \hbox (34.11732pt too wide) in paragraph at lines 734--745 \OT1/cmtt/m/n/10 INPMTX[]BY[]CHEVRONS\OT1/cmr/m/n/10 , or if \OT1/cmtt/m/n/10 s torageMode \OT1/cmr/m/n/10 is not one of \OT1/cmtt/m/n/10 INPMTX[]RAW[]DATA\OT1 /cmr/m/n/10 , \OT1/cmtt/m/n/10 INPMTX[]SORTED \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/ 10 INPMTX[]BY[]VECTORS\OT1/cmr/m/n/10 , [] Overfull \hbox (6.7411pt too wide) in paragraph at lines 751--751 []\OT1/cmtt/m/n/10 void InpMtx_nonsym_mmmVector ( InpMtx *A, DenseMtx *Y, doub le alpha[], DenseMtx *X ) ;[] [] Overfull \hbox (17.24101pt too wide) in paragraph at lines 751--751 []\OT1/cmtt/m/n/10 void InpMtx_nonsym_mmmVector_T ( InpMtx *A, DenseMtx *Y, do uble alpha[], DenseMtx *X ) ;[] [] Overfull \hbox (17.24101pt too wide) in paragraph at lines 751--751 []\OT1/cmtt/m/n/10 void InpMtx_nonsym_mmmVector_H ( InpMtx *A, DenseMtx *Y, do uble alpha[], DenseMtx *X ) ;[] [] [287] Overfull \hbox (34.11732pt too wide) in paragraph at lines 787--798 \OT1/cmtt/m/n/10 INPMTX[]BY[]CHEVRONS\OT1/cmr/m/n/10 , or if \OT1/cmtt/m/n/10 s torageMode \OT1/cmr/m/n/10 is not one of \OT1/cmtt/m/n/10 INPMTX[]RAW[]DATA\OT1 /cmr/m/n/10 , \OT1/cmtt/m/n/10 INPMTX[]SORTED \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/ 10 INPMTX[]BY[]VECTORS\OT1/cmr/m/n/10 , [] [288] Overfull \hbox (11.27731pt too wide) in paragraph at lines 964--972 \OT1/cmr/m/it/10 Error check-ing: \OT1/cmr/m/n/10 If \OT1/cmtt/m/n/10 inpmtxA \ OT1/cmr/m/n/10 is \OT1/cmtt/m/n/10 NULL\OT1/cmr/m/n/10 , or if the co-or-di-nat e type is not \OT1/cmtt/m/n/10 INPMTX[]BY[]ROWS \OT1/cmr/m/n/10 or \OT1/cmtt/m/ n/10 INPMTX[]BY[]COLUMNS\OT1/cmr/m/n/10 , [] Overfull \hbox (11.27731pt too wide) in paragraph at lines 980--988 \OT1/cmr/m/it/10 Error check-ing: \OT1/cmr/m/n/10 If \OT1/cmtt/m/n/10 inpmtxA \ OT1/cmr/m/n/10 is \OT1/cmtt/m/n/10 NULL\OT1/cmr/m/n/10 , or if the co-or-di-nat e type is not \OT1/cmtt/m/n/10 INPMTX[]BY[]ROWS \OT1/cmr/m/n/10 or \OT1/cmtt/m/ n/10 INPMTX[]BY[]COLUMNS\OT1/cmr/m/n/10 , [] [289] [290] [291] Overfull \hbox (13.68219pt too wide) in paragraph at lines 1411--1418 []\OT1/cmr/m/n/10 This method writes the ob-ject to a file suit-able for read-i ng by a hu-man. The method \OT1/cmtt/m/n/10 InpMtx[]writeStats() [] [292] Overfull \hbox (10.59344pt too wide) in paragraph at lines 1465--1471 \OT1/cmtt/m/n/10 readHB[]mat[]double() \OT1/cmr/m/n/10 from the Harwell-Boeing C IO rou-tines from NIST[], found in the \OT1/cmtt/m/n/10 misc/src/iohb.c [] ) (../../InpMtx/doc/drivers.tex [293] [294] [295] [296] psfig: searching ../../InpMtx/doc/BCSSTK23.eps for bounding box psfig: including ../../InpMtx/doc/BCSSTK23.eps [297] [298] [299]) (../../Iter/doc/intro.tex [300] Chapter 33. Overfull \hbox (5.20291pt too wide) in paragraph at lines 4--15 \OT1/cmtt/m/n/10 Iter \OT1/cmr/m/n/10 is com-posed of 5 Krylov space it-er-a-ti ve meth-ods, PCG (Pre-con-di-tioned Con-ju-gate Gra-di-ents), BiCGStab, [] ) (../../Iter/doc/dataStructure.tex) (../../Iter/doc/proto.tex [301 ] [302] [303] [304] [305]) (../../Iter/doc/drivers.tex [306] [307] [308] [309]) (../../PatchAndGoInfo/doc/intro.tex [310] Chapter 34. ) (../../PatchAndGoInfo/doc/dataStructure.tex [311 ] Overfull \hbox (58.84337pt too wide) in paragraph at lines 14--18 []\OT1/cmtt/m/n/10 2 \OT1/cmr/m/n/10 --- used with struc-tural anal-y-sis ma-tr i-ces, if $\OMS/cmtt/m/n/10 j\OML/cmm/m/it/10 A[]\OMS/cmtt/m/n/10 j ^^T []$ \OT 1/cmr/m/n/10 then set $\OML/cmm/m/it/10 A[] \OT1/cmr/m/n/10 = [] \OMS/cmtt/m/n/ 10 ^^A []f\OT1/cmr/m/n/10 1\OML/cmm/m/it/10 ; [][]\OMS/cmtt/m/n/10 fj\OML/cmm/m /it/10 A[]\OMS/cmtt/m/n/10 j\OML/cmm/m/it/10 ; \OMS/cmtt/m/n/10 j\OML/cmm/m/it/ 10 A[]\OMS/cmtt/m/n/10 jgg$ [] ) (../../PatchAndGoInfo/doc/proto.tex Overfull \hbox (3.66177pt too wide) in paragraph at lines 5--7 \OT1/cmr/m/n/10 This sec-tion con-tains brief de-scrip-tions in-clud-ing pro-to -types of all meth-ods that be-long to the \OT1/cmtt/m/n/10 PatchAndGoInfo [] [312]) (../../Pencil/doc/intro.tex [313] Chapter 35. ) (../../Pencil/doc/dataStructure.tex) (../../Pencil/doc/proto.tex [314 ] [315]) (../../SemiImplMtx/doc/intro.tex [316] Chapter 36. ) (../../SemiImplMtx/doc/dataStructure.tex [317 ] Overfull \hbox (59.24767pt too wide) in paragraph at lines 14--18 []\OT1/cmtt/m/n/10 int symmetryflag \OT1/cmr/m/n/10 : type of ma-trix sym-me-tr y, \OT1/cmtt/m/n/10 SPOOLES[]SYMMETRIC\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 SPOOLE S[]HERMITIAN \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/10 SPOOLES[]NONSYMMETRIC\OT1/cmr/ m/n/10 . [] ) (../../SemiImplMtx/doc/proto.tex Overfull \hbox (7.96838pt too wide) in paragraph at lines 32--41 []\OT1/cmr/m/n/10 This method sets the struc-ture's fields to de-fault val-ues: \OT1/cmtt/m/n/10 neqns \OT1/cmr/m/n/10 = 0, \OT1/cmtt/m/n/10 type \OT1/cmr/m/n /10 = \OT1/cmtt/m/n/10 SPOOLES[]REAL\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 symmetry flag [] [318] [319]) (../../SemiImplMtx/doc/drivers.tex [320] Overfull \hbox (2.85498pt too wide) in paragraph at lines 111--114 []\OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 FrontMtx \OT1/cmr/m/n/10 ob-ject is read from the \OT1/cmtt/m/n/10 inFrontMtxFile \OT1/cmr/m/n/10 file, which must be o f the form \OT1/cmtt/m/n/10 *.frontmtxf [] ) (../../SubMtx/doc/intro.tex [321] Chapter 37. [322 ]) (../../SubMtx/doc/dataStructure.tex [323]) (../../SubMtx/doc/proto.tex Overfull \hbox (2.80563pt too wide) in paragraph at lines 32--40 []\OT1/cmr/m/n/10 The struc-ture's fields are set to de-fault val-ues: \OT1/cmt t/m/n/10 type \OT1/cmr/m/n/10 = \OT1/cmtt/m/n/10 SPOOLES[]REAL\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 mode \OT1/cmr/m/n/10 = \OT1/cmtt/m/n/10 DENSEMTX[]DENSE[]COLU MNS\OT1/cmr/m/n/10 , [] [324] [325] Overfull \hbox (36.46364pt too wide) in paragraph at lines 223--237 \OT1/cmtt/m/n/10 [firstlocs[irow],lastlocs[irow]] \OT1/cmr/m/n/10 when $[] \OMS /cmtt/m/n/10 ^^U \OT1/cmr/m/n/10 0$ and $[] \OMS/cmtt/m/n/10 ^^T []$\OT1/cmr/m/ n/10 . [] [326] [327] [328] [329] [330] [331] Overfull \hbox (38.45969pt too wide) in paragraph at lines 911--917 []\OT1/cmr/m/n/10 This method writes out a \OT1/cmtt/m/n/10 SubMtx \OT1/cmr/m/n /10 ob-ject to a file in a hu-man read-able for-mat. The method \OT1/cmtt/m/n/1 0 SubMtx[]writeStats() [] ) (../../SubMtx/doc/drivers.tex [332] Underfull \hbox (badness 10000) in paragraph at lines 97--106 \OT1/cmr/m/n/10 (\OT1/cmtt/m/n/10 SUBMTX[]DENSE[]SUBROWS\OT1/cmr/m/n/10 ), 6 (\ OT1/cmtt/m/n/10 SUBMTX[]DENSE[]SUBCOLUMNS\OT1/cmr/m/n/10 ), 7 (\OT1/cmtt/m/n/10 SUBMTX[]DIAGONAL\OT1/cmr/m/n/10 ), [] [333] Overfull \hbox (65.22816pt too wide) in paragraph at lines 228--234 []\OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 mode \OT1/cmr/m/n/10 pa-ram-e-ter must b e one of 0 (\OT1/cmtt/m/n/10 SUBMTX[]DENSE[]ROWS\OT1/cmr/m/n/10 ), 1 (\OT1/cmtt /m/n/10 SUBMTX[]DENSE[]COLUMNS\OT1/cmr/m/n/10 ), 2 (\OT1/cmtt/m/n/10 SUBMTX[]SP ARSE[]ROWS\OT1/cmr/m/n/10 ) [] [334] Overfull \hbox (65.22816pt too wide) in paragraph at lines 279--285 []\OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 mode \OT1/cmr/m/n/10 pa-ram-e-ter must b e one of 0 (\OT1/cmtt/m/n/10 SUBMTX[]DENSE[]ROWS\OT1/cmr/m/n/10 ), 1 (\OT1/cmtt /m/n/10 SUBMTX[]DENSE[]COLUMNS\OT1/cmr/m/n/10 ), 2 (\OT1/cmtt/m/n/10 SUBMTX[]SP ARSE[]ROWS\OT1/cmr/m/n/10 ) [] Overfull \hbox (65.22816pt too wide) in paragraph at lines 331--337 []\OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 mode \OT1/cmr/m/n/10 pa-ram-e-ter must b e one of 0 (\OT1/cmtt/m/n/10 SUBMTX[]DENSE[]ROWS\OT1/cmr/m/n/10 ), 1 (\OT1/cmtt /m/n/10 SUBMTX[]DENSE[]COLUMNS\OT1/cmr/m/n/10 ), 2 (\OT1/cmtt/m/n/10 SUBMTX[]SP ARSE[]ROWS\OT1/cmr/m/n/10 ) [] [335] Overfull \hbox (65.22816pt too wide) in paragraph at lines 381--387 []\OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 mode \OT1/cmr/m/n/10 pa-ram-e-ter must b e one of 0 (\OT1/cmtt/m/n/10 SUBMTX[]DENSE[]ROWS\OT1/cmr/m/n/10 ), 1 (\OT1/cmtt /m/n/10 SUBMTX[]DENSE[]COLUMNS\OT1/cmr/m/n/10 ), 2 (\OT1/cmtt/m/n/10 SUBMTX[]SP ARSE[]ROWS\OT1/cmr/m/n/10 ) [] ) (../../SubMtxList/doc/intro.tex [336] Chapter 38. ) (../../SubMtxList/doc/dataStructure.tex [337 ]) (../../SubMtxList/doc/proto.tex [338]) (../../SubMtxManager/doc/intro.tex [339] Chapter 39. ) (../../SubMtxManager/doc/dataStructure.tex [340 ]) (../../SubMtxManager/doc/proto.tex [341]) (../../SymbFac/doc/intro.tex [342] Chapter 40. ) (../../SymbFac/doc/dataStructure.tex) (../../SymbFac/doc/proto.tex [343 ] Overfull \hbox (10.96967pt too wide) in paragraph at lines 54--65 \OT1/cmr/m/it/10 Error check-ing: \OT1/cmr/m/n/10 If \OT1/cmtt/m/n/10 etree \OT 1/cmr/m/n/10 or \OT1/cmtt/m/n/10 inpmtx \OT1/cmr/m/n/10 is \OT1/cmtt/m/n/10 NUL L\OT1/cmr/m/n/10 , or if the co-or-di-nate type of \OT1/cmtt/m/n/10 inpmtx \OT1 /cmr/m/n/10 is not \OT1/cmtt/m/n/10 INPMTX[]BY[]CHEVRONS\OT1/cmr/m/n/10 , [] ) (../../SymbFac/doc/drivers.tex [344])) (partMisc.tex [345] [346 ] [347] (../../misc/doc/intro.tex Chapter 41. ) (../../misc/doc/proto.tex [348 ] [349] [350] [351]) (../../misc/doc/drivers.tex [352] [353] psfig: searching ../../misc/doc/R2D100notags.eps for bounding box psfig: including ../../misc/doc/R2D100notags.eps psfig: searching ../../misc/doc/R2D100fishnet.eps for bounding box psfig: including ../../misc/doc/R2D100fishnet.eps [354] [355] [356] [357] [358] [359])) (partMT.tex [360] [361 ] [362] (../../MT/doc/intro.tex Chapter 42. ) (../../MT/doc/dataStructure.tex) (../../MT/doc/proto.tex [363 ] Overfull \hbox (63.2698pt too wide) in paragraph at lines 11--27 \OT1/cmr/m/n/10 There are five meth-ods to mul-ti-ply a vec-tor times a dense m a-trix. The first three meth-ods, called \OT1/cmtt/m/n/10 InpMtx[]MT[]nonsym[]m mm*()\OT1/cmr/m/n/10 , [] Overfull \hbox (34.11732pt too wide) in paragraph at lines 64--75 \OT1/cmtt/m/n/10 INPMTX[]BY[]CHEVRONS\OT1/cmr/m/n/10 , or if \OT1/cmtt/m/n/10 s torageMode \OT1/cmr/m/n/10 is not one of \OT1/cmtt/m/n/10 INPMTX[]RAW[]DATA\OT1 /cmr/m/n/10 , \OT1/cmtt/m/n/10 INPMTX[]SORTED \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/ 10 INPMTX[]BY[]VECTORS\OT1/cmr/m/n/10 , [] [364] Overfull \hbox (34.11732pt too wide) in paragraph at lines 101--112 \OT1/cmtt/m/n/10 INPMTX[]BY[]CHEVRONS\OT1/cmr/m/n/10 , or if \OT1/cmtt/m/n/10 s torageMode \OT1/cmr/m/n/10 is not one of \OT1/cmtt/m/n/10 INPMTX[]RAW[]DATA\OT1 /cmr/m/n/10 , \OT1/cmtt/m/n/10 INPMTX[]SORTED \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/ 10 INPMTX[]BY[]VECTORS\OT1/cmr/m/n/10 , [] Overfull \hbox (34.11732pt too wide) in paragraph at lines 130--139 \OT1/cmtt/m/n/10 INPMTX[]BY[]CHEVRONS\OT1/cmr/m/n/10 , or if \OT1/cmtt/m/n/10 s torageMode \OT1/cmr/m/n/10 is not one of \OT1/cmtt/m/n/10 INPMTX[]RAW[]DATA\OT1 /cmr/m/n/10 , \OT1/cmtt/m/n/10 INPMTX[]SORTED \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/ 10 INPMTX[]BY[]VECTORS\OT1/cmr/m/n/10 , [] [365] [366]) (../../MT/doc/drivers.tex [367] [368] [369] [370] [371])) (partMPI.tex [372] [373 ] [374] (../../MPI/doc/intro.tex Chapter 43. ) (../../MPI/doc/dataStructure.tex Overfull \hbox (0.87425pt too wide) in paragraph at lines 30--34 []\OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 MatMulInfo \OT1/cmr/m/n/10 ob-ject store s all the nec-es-sary in-for-ma-tion to make this hap-pen. There is one \OT1/cm tt/m/n/10 MatMulInfo [] [375 ]) (../../MPI/doc/proto.tex Overfull \hbox (59.838pt too wide) in paragraph at lines 97--1 []\OT1/cmr/m/n/10 See the meth-ods \OT1/cmtt/m/n/10 MatMul[]MPI[]setup()\OT1/cm r/m/n/10 , \OT1/cmtt/m/n/10 MatMul[]setLocalIndices()\OT1/cmr/m/n/10 , \OT1/cmt t/m/n/10 MatMul[]setGlobalIndices()\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 MatMul[]M PI[]mmm() [] [376] [377] Overfull \hbox (31.97972pt too wide) in paragraph at lines 249--256 \OT1/cmr/m/n/10 dis-tributed matrix-matrix mul-ti-ply. The gather op-er-a-tion $\OML/cmm/m/it/10 X[] \OMS/cmtt/m/n/10 \OML/cmm/m/it/10 X$ \OT1/cmr/m/n/10 is per-formed by \OT1/cmtt/m/n/10 DenseMtx[]MPI[]gatherRows()\OT1/cmr/m/n/10 , [] [378] [379] [380] Overfull \hbox (11.99106pt too wide) in paragraph at lines 517--517 []\OT1/cmtt/m/n/10 void FrontMtx_MPI_permuteUpperAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[],[] [] Overfull \hbox (11.99106pt too wide) in paragraph at lines 517--517 [] \OT1/cmtt/m/n/10 int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ;[] [] Overfull \hbox (11.99106pt too wide) in paragraph at lines 517--517 []\OT1/cmtt/m/n/10 void FrontMtx_MPI_permuteLowerAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[],[] [] Overfull \hbox (11.99106pt too wide) in paragraph at lines 517--517 [] \OT1/cmtt/m/n/10 int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ;[] [] [381] [382] [383] [384] [385] Overfull \hbox (11.99106pt too wide) in paragraph at lines 981--981 []\OT1/cmtt/m/n/10 void * makeSendRecvIVLs ( IV *supportedIV, IV *globalmapIV, IVL *sendIVL, IVL *recvIVL,[] [] Overfull \hbox (11.99106pt too wide) in paragraph at lines 981--981 [] \OT1/cmtt/m/n/10 int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ;[] [] ) (../../MPI/doc/drivers.tex [386] [387] [388] [389] Overfull \hbox (31.23914pt too wide) in paragraph at lines 409--426 []\OT1/cmr/m/n/10 This driver pro-gram tests the dis-tributed \OT1/cmtt/m/n/10 IVL[]MPI[]alltoall() \OT1/cmr/m/n/10 method. This is used by the \OT1/cmtt/m/n/ 10 makeSendRecvIVLs [] [390] [391] [392] [393])) (main.bbl [394] [395 ]) (main.ind [396] [397 ] [398] [399] [400] [401] [402] [403] [404] [405] [406] [407] [408] [409] [410] [411 ]) (main.aux) LaTeX Font Warning: Some font shapes were not available, defaults substituted. ) Here is how much of TeX's memory you used: 2333 strings out of 10908 33520 string characters out of 72189 70848 words of memory out of 262141 4393 multiletter control sequences out of 9500 18288 words of font info for 69 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 28i,17n,21p,614b,426s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (412 pages, 1580660 bytes). m/it/10 ; \OMS/cmtt/m/n/10 j\OML/cmm/m/it/ 10 A[]\OMS/cmtt/m/n/10 jgg$ [] ) (../../PatchAndGoInfo/doc/pdocumentation/ReferenceManual/main.tex010064400020550007177000000125040665015236400214550ustar00clevecompmath00000400000006% % main TeX file % % \documentstyle[leqno,11pt,twoside]{report} \documentclass[leqno,10pt,twoside]{report} \usepackage{amsmath} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \input psfig \newcommand{\bfi}{{\bf i}} \newcommand{\bfj}{{\bf j}} \newcommand{\bnd}[1]{{\partial{#1}}} \pagestyle{myheadings} % \markboth % {\quad \hrulefill \quad {\bf SPOOLES} : {\it DRAFT} \today \quad \hrulefill} % {\quad \hrulefill \quad {\bf SPOOLES} : {\it DRAFT} \quad \today \hrulefill} \markboth {\quad \hrulefill \quad {\bf SPOOLES 2.2} : \today \quad \hrulefill} {\quad \hrulefill \quad {\bf SPOOLES 2.2} : \quad \today \hrulefill} \begin{document} \bibliographystyle{plain} \title{ The Reference Manual for {\bf SPOOLES}, Release 2.2: \break An Object Oriented Software Library for Solving \break Sparse Linear Systems of Equations} \author{ Cleve Ashcraft\thanks{ Boeing Shared Services Group, P. O. Box 24346, Mail Stop 7L-22, Seattle, Washington 98124, {\tt cleve.ashcraft@boeing.com}. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} \and Daniel Pierce\thanks{ Boeing Shared Services Group, P. O. Box 24346, Mail Stop 7L-22, Seattle, Washington 98124, {\tt dpierce@redwood.rt.cs.boeing.com}. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} \and David K. Wah\thanks{ Boeing Shared Services Group, P. O. Box 24346, Mail Stop 7L-22, Seattle, Washington 98124, {\tt david.wah@pss.boeing.com}. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} \and Jason Wu\thanks{ Boeing Shared Services Group, P. O. Box 24346, Mail Stop 7L-22, Seattle, Washington 98124, {\tt jwu@redwood.rt.cs.boeing.com}. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} % \and % Joseph W.H. Liu\thanks{ % Department of Computer Science, York % University, North York, Ontario, Canada M3J 1P3. % This research was supported in part by the % Natural Sciences and Engineering Research Council of Canada % under grant A5509 % and in part by the ARPA % Contract DABT63-95-C-0122.} } \date{\today} \maketitle \begin{abstract} Solving sparse linear systems of equations is a common and important application of a multitude of scientific and engineering applications. The {\bf SPOOLES} software package\footnote{ {\bf SPOOLES} is an acronym for {\bf SP}arse {\bf O}bject-{\bf O}riented {\bf L}inear {\bf E}quations {\bf S}olver. } provides this functionality with a collection of software objects. The first step to solving a sparse linear system is to find a good low-fill ordering of the rows and columns. The library contains several ways to perform this operation: minimum degree, generalized nested dissection, and multisection. The second step is to factor the matrix as a product of triangular and diagonal matrices. The library supports pivoting for numerical stability (when required), approximation techniques to reduce the storage for and work to compute the matrix factors, and the computations are based on BLAS3 numerical kernels to take advantage of high performance computing architectures. The third step is to solve the linear system using the computed factors. \par The library is written in ANSI C using object oriented design. Good design and efficient code sometimes conflict; generally we have preferred to cater to design. For large sparse matrices the serial code outperforms its FORTRAN predecessors, the reverse holds for moderate sized matrices or those that do not have good block structure. The present release of the library contains a serial factorization and solve, a multithreaded version using the Solaris and Posix thread packages, and an MPI version. There is considerable code overlap between the serial, threaded and MPI versions. \par This release of the package is totally within the public domain; there are absolutely no licensing restrictions as with other software packages. The development of this software was funded by DARPA\footnote{DARPA Contract DABT63-95-C-0122.} and the DoD\footnote{DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} with the express purpose that others (academic, government, industrial and commercial) could easily incorporate the data structures and algorithms into application codes. All we ask is an acknowledgement in derivative codes and any publications from research that uses this software. And, we hope that any improvements will be communicated to others. \end{abstract} \par % \input preface.tex \tableofcontents \listoffigures \input partIntro.tex \input partUtil.tex \input partOrder.tex \input partNumeric.tex \input partMisc.tex \input partMT.tex \input partMPI.tex \bibliography{spooles} \input main.ind \end{document} documentation/ReferenceManual/main.toc010064400020550007177000000767450665314325500214650ustar00clevecompmath00000400000006\contentsline {part}{\uppercase {i}\hspace {1em}Introduction}{15} \contentsline {chapter}{\numberline {1}Introduction}{17} \contentsline {section}{\numberline {1.1}Software Design}{18} \contentsline {section}{\numberline {1.2}Changes from Release 1.0}{21} \contentsline {section}{\numberline {1.3}Changes from Release 2.0}{21} \contentsline {part}{\uppercase {ii}\hspace {1em}Utility Objects and Methods}{23} \contentsline {chapter}{\numberline {2}{\tt A2}: Real or complex 2-D array}{25} \contentsline {section}{\numberline {2.1}Data Structure}{25} \contentsline {section}{\numberline {2.2}Prototypes and descriptions of {\tt A2} methods}{25} \contentsline {subsection}{\numberline {2.2.1}Basic methods}{26} \contentsline {subsection}{\numberline {2.2.2}Instance methods}{26} \contentsline {subsection}{\numberline {2.2.3}Initialize methods}{28} \contentsline {subsection}{\numberline {2.2.4}Methods used in the $QR$ factorization}{28} \contentsline {subsection}{\numberline {2.2.5}Norm methods}{29} \contentsline {subsection}{\numberline {2.2.6}Sort methods}{30} \contentsline {subsection}{\numberline {2.2.7}Utility methods}{30} \contentsline {subsection}{\numberline {2.2.8}IO methods}{33} \contentsline {section}{\numberline {2.3}Driver programs for the {\tt A2 object}}{34} \contentsline {chapter}{\numberline {3}{\tt Coords}: Coordinates Object}{36} \contentsline {section}{\numberline {3.1}Data Structure}{36} \contentsline {section}{\numberline {3.2}Prototypes and descriptions of {\tt Coords} methods}{36} \contentsline {subsection}{\numberline {3.2.1}Basic methods}{36} \contentsline {subsection}{\numberline {3.2.2}Initializer methods}{37} \contentsline {subsection}{\numberline {3.2.3}Utility methods}{38} \contentsline {subsection}{\numberline {3.2.4}IO methods}{38} \contentsline {section}{\numberline {3.3}Driver programs for the {\tt Coords} object}{39} \contentsline {chapter}{\numberline {4}{\tt DV}: Double Vector Object}{41} \contentsline {section}{\numberline {4.1}Data Structure}{41} \contentsline {section}{\numberline {4.2}Prototypes and descriptions of {\tt DV} methods}{42} \contentsline {subsection}{\numberline {4.2.1}Basic methods}{42} \contentsline {subsection}{\numberline {4.2.2}Instance methods}{42} \contentsline {subsection}{\numberline {4.2.3}Initializer methods}{43} \contentsline {subsection}{\numberline {4.2.4}Utility methods}{44} \contentsline {subsection}{\numberline {4.2.5}IO methods}{45} \contentsline {section}{\numberline {4.3}Driver programs for the {\tt DV object}}{47} \contentsline {chapter}{\numberline {5}{\tt Drand}: \penalty -\@M Simple Random Number Generator}{48} \contentsline {section}{\numberline {5.1}Data Structure}{48} \contentsline {section}{\numberline {5.2}Prototypes and descriptions of {\tt Drand} methods}{48} \contentsline {subsection}{\numberline {5.2.1}Basic methods}{49} \contentsline {subsection}{\numberline {5.2.2}Initializer methods}{49} \contentsline {subsection}{\numberline {5.2.3}Utility methods}{50} \contentsline {section}{\numberline {5.3}Driver programs for the {\tt Drand} object}{50} \contentsline {chapter}{\numberline {6}{\tt I2Ohash}: Two Key Hash Table}{52} \contentsline {section}{\numberline {6.1}Data Structure}{52} \contentsline {section}{\numberline {6.2}Prototypes and descriptions of {\tt I2Ohash} methods}{53} \contentsline {subsection}{\numberline {6.2.1}Basic methods}{53} \contentsline {subsection}{\numberline {6.2.2}Initializer methods}{53} \contentsline {subsection}{\numberline {6.2.3}Utility methods}{54} \contentsline {subsection}{\numberline {6.2.4}IO methods}{54} \contentsline {section}{\numberline {6.3}Driver programs for the {\tt I2Ohash object}}{54} \contentsline {chapter}{\numberline {7}{\tt IIheap}: (Key, Value) Heap}{56} \contentsline {section}{\numberline {7.1}Data Structure}{56} \contentsline {section}{\numberline {7.2}Prototypes and descriptions of {\tt IIheap} methods}{56} \contentsline {subsection}{\numberline {7.2.1}Basic methods}{56} \contentsline {subsection}{\numberline {7.2.2}Initializer methods}{57} \contentsline {subsection}{\numberline {7.2.3}Utility methods}{57} \contentsline {chapter}{\numberline {8}{\tt IV}: Integer Vector Object}{58} \contentsline {section}{\numberline {8.1}Data Structure}{58} \contentsline {section}{\numberline {8.2}Prototypes and descriptions of {\tt IV} methods}{59} \contentsline {subsection}{\numberline {8.2.1}Basic methods}{59} \contentsline {subsection}{\numberline {8.2.2}Instance methods}{59} \contentsline {subsection}{\numberline {8.2.3}Initializer methods}{60} \contentsline {subsection}{\numberline {8.2.4}Utility methods}{61} \contentsline {subsection}{\numberline {8.2.5}IO methods}{63} \contentsline {section}{\numberline {8.3}Driver programs for the {\tt IV object}}{65} \contentsline {chapter}{\numberline {9}{\tt IVL}: Integer Vector List Object}{66} \contentsline {section}{\numberline {9.1}Data Structure}{66} \contentsline {section}{\numberline {9.2}Prototypes and descriptions of {\tt IVL} methods}{67} \contentsline {subsection}{\numberline {9.2.1}Basic methods}{67} \contentsline {subsection}{\numberline {9.2.2}Instance methods}{68} \contentsline {subsection}{\numberline {9.2.3}Initialization and resizing methods}{68} \contentsline {subsection}{\numberline {9.2.4}List manipulation methods}{69} \contentsline {subsection}{\numberline {9.2.5}Utility methods}{70} \contentsline {subsection}{\numberline {9.2.6}Miscellaneous methods}{71} \contentsline {subsection}{\numberline {9.2.7}IO methods}{72} \contentsline {section}{\numberline {9.3}Driver programs for the {\tt IVL} object}{73} \contentsline {chapter}{\numberline {10}{\tt Ideq}: Integer Dequeue}{74} \contentsline {section}{\numberline {10.1}Data Structure}{74} \contentsline {section}{\numberline {10.2}Prototypes and descriptions of {\tt Ideq} methods}{74} \contentsline {subsection}{\numberline {10.2.1}Basic methods}{74} \contentsline {subsection}{\numberline {10.2.2}Initializer methods}{75} \contentsline {subsection}{\numberline {10.2.3}Utility methods}{75} \contentsline {subsection}{\numberline {10.2.4}IO methods}{76} \contentsline {chapter}{\numberline {11}{\tt Lock}: Mutual Exclusion Lock object}{77} \contentsline {section}{\numberline {11.1}Data Structure}{77} \contentsline {section}{\numberline {11.2}Prototypes and descriptions of {\tt Lock} methods}{77} \contentsline {subsection}{\numberline {11.2.1}Basic methods}{77} \contentsline {subsection}{\numberline {11.2.2}Initializer method}{78} \contentsline {subsection}{\numberline {11.2.3}Utility methods}{78} \contentsline {chapter}{\numberline {12}{\tt Perm}: Permutation Object}{79} \contentsline {section}{\numberline {12.1}Data Structure}{79} \contentsline {section}{\numberline {12.2}Prototypes and descriptions of {\tt Perm} methods}{79} \contentsline {subsection}{\numberline {12.2.1}Basic methods}{79} \contentsline {subsection}{\numberline {12.2.2}Initializer methods}{80} \contentsline {subsection}{\numberline {12.2.3}Utility methods}{80} \contentsline {subsection}{\numberline {12.2.4}IO methods}{81} \contentsline {chapter}{\numberline {13}{\tt Utilities } directory }{83} \contentsline {section}{\numberline {13.1}Data Structures}{83} \contentsline {section}{\numberline {13.2}Prototypes and descriptions of {\tt Utilities} methods}{83} \contentsline {subsection}{\numberline {13.2.1}{\tt CV} : {\tt char} vector methods}{84} \contentsline {subsection}{\numberline {13.2.2}{\tt DV} : {\tt double} vector methods}{84} \contentsline {subsection}{\numberline {13.2.3}{\tt ZV} : {\tt double complex } vector methods}{90} \contentsline {subsection}{\numberline {13.2.4}{\tt IV} : {\tt int} vector methods}{96} \contentsline {subsection}{\numberline {13.2.5}{\tt FV} : {\tt float} vector methods}{98} \contentsline {subsection}{\numberline {13.2.6}{\tt PCV} : {\tt char *} vector methods}{101} \contentsline {subsection}{\numberline {13.2.7}{\tt PDV} : {\tt double *} vector methods}{101} \contentsline {subsubsection}{{\tt PIV} : {\tt int *} vector methods}{101} \contentsline {subsection}{\numberline {13.2.8}{\tt PFV} : {\tt float *} vector methods}{102} \contentsline {subsection}{\numberline {13.2.9}Sorting routines}{102} \contentsline {subsubsection}{Validation routines}{102} \contentsline {subsubsection}{Insert sort routines}{102} \contentsline {subsubsection}{Quicksort routines}{103} \contentsline {subsection}{\numberline {13.2.10}Sort and compress routines}{104} \contentsline {subsection}{\numberline {13.2.11}{\tt IP} : {\tt (int, pointer)} singly linked-list methods}{105} \contentsline {subsection}{\numberline {13.2.12}{\tt I2OP} : {\tt (int, int, void*, pointer)} singly linked-list methods}{106} \contentsline {section}{\numberline {13.3}Driver programs }{107} \contentsline {chapter}{\numberline {14}{\tt ZV}: Double Complex Vector Object}{108} \contentsline {section}{\numberline {14.1}Data Structure}{108} \contentsline {section}{\numberline {14.2}Prototypes and descriptions of {\tt ZV} methods}{109} \contentsline {subsection}{\numberline {14.2.1}Basic methods}{109} \contentsline {subsection}{\numberline {14.2.2}Instance methods}{109} \contentsline {subsection}{\numberline {14.2.3}Initializer methods}{110} \contentsline {subsection}{\numberline {14.2.4}Utility methods}{111} \contentsline {subsection}{\numberline {14.2.5}IO methods}{112} \contentsline {section}{\numberline {14.3}Driver programs for the {\tt ZV object}}{113} \contentsline {part}{\uppercase {iii}\hspace {1em}Ordering Objects and Methods}{115} \contentsline {chapter}{\numberline {15}{\tt BKL}: Block Kernighan-Lin Object}{117} \contentsline {section}{\numberline {15.1}Data Structure}{117} \contentsline {section}{\numberline {15.2}Prototypes and descriptions of {\tt BKL} methods}{118} \contentsline {section}{\numberline {15.3}Basic methods}{118} \contentsline {subsection}{\numberline {15.3.1}Initializer methods}{118} \contentsline {subsection}{\numberline {15.3.2}Utility methods}{119} \contentsline {subsection}{\numberline {15.3.3}Partition evaluation methods}{120} \contentsline {subsection}{\numberline {15.3.4}Partition improvement methods}{120} \contentsline {chapter}{\numberline {16}{\tt BPG}: Bipartite Graph Object}{122} \contentsline {section}{\numberline {16.1}Data Structure}{124} \contentsline {section}{\numberline {16.2}Prototypes and descriptions of {\tt BPG} methods}{124} \contentsline {subsection}{\numberline {16.2.1}Basic methods}{124} \contentsline {subsection}{\numberline {16.2.2}Initializer methods}{125} \contentsline {subsection}{\numberline {16.2.3}Generate induced graphs}{125} \contentsline {subsection}{\numberline {16.2.4}Utility methods}{125} \contentsline {subsection}{\numberline {16.2.5}Dulmage-Mendelsohn decomposition method}{126} \contentsline {subsection}{\numberline {16.2.6}IO methods}{126} \contentsline {section}{\numberline {16.3}Driver programs for the {\tt BPG} object}{127} \contentsline {chapter}{\numberline {17}{\tt DSTree}: \penalty -\@M A Domain/Separator Tree Object}{129} \contentsline {section}{\numberline {17.1}Data Structure}{129} \contentsline {section}{\numberline {17.2}Prototypes and descriptions of {\tt DSTree} methods}{129} \contentsline {subsection}{\numberline {17.2.1}Basic methods}{130} \contentsline {subsection}{\numberline {17.2.2}Instance methods}{130} \contentsline {subsection}{\numberline {17.2.3}Initializer methods}{130} \contentsline {subsection}{\numberline {17.2.4}Stage methods}{131} \contentsline {subsection}{\numberline {17.2.5}Utility methods}{132} \contentsline {subsection}{\numberline {17.2.6}IO methods}{132} \contentsline {section}{\numberline {17.3}Driver programs for the {\tt DSTree} object}{133} \contentsline {chapter}{\numberline {18}{\tt EGraph}: Element Graph Object}{135} \contentsline {section}{\numberline {18.1}Data Structure}{135} \contentsline {section}{\numberline {18.2}Prototypes and descriptions of {\tt EGraph} methods}{135} \contentsline {subsection}{\numberline {18.2.1}Basic methods}{136} \contentsline {subsection}{\numberline {18.2.2}Initializer methods}{136} \contentsline {subsection}{\numberline {18.2.3}Utility methods}{136} \contentsline {subsection}{\numberline {18.2.4}IO methods}{137} \contentsline {section}{\numberline {18.3}Driver programs for the {\tt EGraph} object}{138} \contentsline {chapter}{\numberline {19}{\tt ETree}: Elimination and Front Trees}{140} \contentsline {section}{\numberline {19.1}Data Structure}{140} \contentsline {section}{\numberline {19.2}Prototypes and descriptions of {\tt ETree} methods}{141} \contentsline {subsection}{\numberline {19.2.1}Basic methods}{141} \contentsline {subsection}{\numberline {19.2.2}Instance methods}{141} \contentsline {subsection}{\numberline {19.2.3}Initializer methods}{143} \contentsline {subsection}{\numberline {19.2.4}Utility methods}{144} \contentsline {subsection}{\numberline {19.2.5}Metrics methods}{146} \contentsline {subsection}{\numberline {19.2.6}Compression methods}{146} \contentsline {subsection}{\numberline {19.2.7}Justification methods}{147} \contentsline {subsection}{\numberline {19.2.8}Permutation methods}{148} \contentsline {subsection}{\numberline {19.2.9}Multisector methods}{148} \contentsline {subsection}{\numberline {19.2.10}Transformation methods}{150} \contentsline {subsection}{\numberline {19.2.11}Parallel factorization map methods}{151} \contentsline {subsection}{\numberline {19.2.12}Storage profile methods}{152} \contentsline {subsection}{\numberline {19.2.13}IO methods}{153} \contentsline {section}{\numberline {19.3}Driver programs for the {\tt ETree} object}{154} \contentsline {chapter}{\numberline {20}{\tt GPart}: Graph Partitioning Object}{165} \contentsline {section}{\numberline {20.1}Data Structures}{166} \contentsline {section}{\numberline {20.2}Prototypes and descriptions of {\tt GPart} methods}{167} \contentsline {subsection}{\numberline {20.2.1}Basic methods}{167} \contentsline {subsection}{\numberline {20.2.2}Initializer methods}{168} \contentsline {subsection}{\numberline {20.2.3}Utility methods}{168} \contentsline {subsection}{\numberline {20.2.4}Domain decomposition methods}{169} \contentsline {subsection}{\numberline {20.2.5}Methods to generate a 2-set partition}{170} \contentsline {subsection}{\numberline {20.2.6}Methods to improve a 2-set partition}{170} \contentsline {subsection}{\numberline {20.2.7}Recursive Bisection method}{172} \contentsline {subsection}{\numberline {20.2.8}{\tt DDsepInfo} methods}{172} \contentsline {section}{\numberline {20.3}Driver programs for the {\tt GPart} object}{173} \contentsline {chapter}{\numberline {21}{\tt Graph}: A Graph object}{177} \contentsline {section}{\numberline {21.1}Data Structure}{178} \contentsline {section}{\numberline {21.2}Prototypes and descriptions of {\tt Graph} methods}{178} \contentsline {subsection}{\numberline {21.2.1}Basic methods}{178} \contentsline {subsection}{\numberline {21.2.2}Initializer methods}{179} \contentsline {subsection}{\numberline {21.2.3}Compress and Expand methods}{180} \contentsline {subsection}{\numberline {21.2.4}Wirebasket domain decomposition ordering}{180} \contentsline {subsection}{\numberline {21.2.5}Utility methods}{181} \contentsline {subsection}{\numberline {21.2.6}IO methods}{182} \contentsline {section}{\numberline {21.3}Driver programs for the {\tt Graph} object}{183} \contentsline {chapter}{\numberline {22}{\tt MSMD}: \penalty -\@M {\tt M}ulti-{\tt S}tage {\tt M}inimum {\tt D}egree Object}{187} \contentsline {section}{\numberline {22.1}Data Structure}{188} \contentsline {subsection}{\numberline {22.1.1}{\tt MSMDinfo} : define your algorithm}{189} \contentsline {subsection}{\numberline {22.1.2}{\tt MSMD} : driver object}{190} \contentsline {subsection}{\numberline {22.1.3}{\tt MSMDstageInfo} : statistics object for a stage of the elimination}{190} \contentsline {subsection}{\numberline {22.1.4}{\tt MSMDvtx} : vertex object}{191} \contentsline {section}{\numberline {22.2}Prototypes and descriptions of {\tt MSMDinfo} methods}{191} \contentsline {subsection}{\numberline {22.2.1}Basic methods}{191} \contentsline {subsection}{\numberline {22.2.2}Utility methods}{192} \contentsline {section}{\numberline {22.3}Prototypes and descriptions of {\tt MSMD} methods}{192} \contentsline {subsection}{\numberline {22.3.1}Basic methods --- public}{192} \contentsline {subsection}{\numberline {22.3.2}Initialization methods --- public}{193} \contentsline {subsection}{\numberline {22.3.3}Ordering methods --- public}{193} \contentsline {subsection}{\numberline {22.3.4}Extraction methods --- public}{193} \contentsline {subsection}{\numberline {22.3.5}Internal methods --- private}{194} \contentsline {section}{\numberline {22.4}Prototypes and descriptions of {\tt MSMDvtx} methods}{195} \contentsline {section}{\numberline {22.5}Driver programs for the {\tt MSMD} object}{195} \contentsline {chapter}{\numberline {23}{\tt Network}: Simple Max-flow solver}{198} \contentsline {section}{\numberline {23.1}Data Structure}{199} \contentsline {section}{\numberline {23.2}Prototypes and descriptions of {\tt Network} methods}{200} \contentsline {subsection}{\numberline {23.2.1}Basic methods}{200} \contentsline {subsection}{\numberline {23.2.2}Initializer methods}{201} \contentsline {subsection}{\numberline {23.2.3}Utility methods}{201} \contentsline {subsection}{\numberline {23.2.4}IO methods}{202} \contentsline {chapter}{\numberline {24}{\tt SolveMap}: Forward and Backsolve Map}{203} \contentsline {section}{\numberline {24.1}Data Structure}{203} \contentsline {section}{\numberline {24.2}Prototypes and descriptions of {\tt SolveMap} methods}{204} \contentsline {subsection}{\numberline {24.2.1}Basic methods}{204} \contentsline {subsection}{\numberline {24.2.2}Instance methods}{204} \contentsline {subsection}{\numberline {24.2.3}Initialization method}{205} \contentsline {subsection}{\numberline {24.2.4}Map creation methods}{206} \contentsline {subsection}{\numberline {24.2.5}Solve setup methods}{206} \contentsline {subsection}{\numberline {24.2.6}Utility methods}{206} \contentsline {subsection}{\numberline {24.2.7}IO methods}{207} \contentsline {chapter}{\numberline {25}{\tt Tree}: A Tree Object}{209} \contentsline {section}{\numberline {25.1}Data Structure}{209} \contentsline {section}{\numberline {25.2}Prototypes and descriptions of {\tt Tree} methods}{209} \contentsline {subsection}{\numberline {25.2.1}Basic methods}{210} \contentsline {subsection}{\numberline {25.2.2}Instance methods}{210} \contentsline {subsection}{\numberline {25.2.3}Initializer methods}{211} \contentsline {subsection}{\numberline {25.2.4}Utility methods}{211} \contentsline {subsection}{\numberline {25.2.5}Metrics methods}{213} \contentsline {subsection}{\numberline {25.2.6}Compression methods}{214} \contentsline {subsection}{\numberline {25.2.7}Justification methods}{214} \contentsline {subsection}{\numberline {25.2.8}Permutation methods}{214} \contentsline {subsection}{\numberline {25.2.9}Drawing method}{215} \contentsline {subsection}{\numberline {25.2.10}IO methods}{216} \contentsline {section}{\numberline {25.3}Driver programs for the {\tt Tree} object}{217} \contentsline {part}{\uppercase {iv}\hspace {1em}Numeric Objects and Methods}{219} \contentsline {chapter}{\numberline {26}{\tt Chv}: Block chevron}{221} \contentsline {section}{\numberline {26.1}Data Structure}{223} \contentsline {section}{\numberline {26.2}Prototypes and descriptions of {\tt Chv} methods}{223} \contentsline {subsection}{\numberline {26.2.1}Basic methods}{224} \contentsline {subsection}{\numberline {26.2.2}Instance methods}{224} \contentsline {subsection}{\numberline {26.2.3}Initialization methods}{226} \contentsline {subsection}{\numberline {26.2.4}Search methods}{227} \contentsline {subsection}{\numberline {26.2.5}Pivot methods}{228} \contentsline {subsection}{\numberline {26.2.6}Update methods}{228} \contentsline {subsection}{\numberline {26.2.7}Assembly methods}{229} \contentsline {subsection}{\numberline {26.2.8}Factorization methods}{229} \contentsline {subsection}{\numberline {26.2.9}Copy methods}{230} \contentsline {subsection}{\numberline {26.2.10}Swap methods}{232} \contentsline {subsection}{\numberline {26.2.11}Utility methods}{233} \contentsline {subsection}{\numberline {26.2.12}IO methods}{234} \contentsline {section}{\numberline {26.3}Driver programs for the {\tt Chv object}}{235} \contentsline {chapter}{\numberline {27}{\tt ChvList}: {\tt Chv} list object }{240} \contentsline {section}{\numberline {27.1}Data Structure}{241} \contentsline {section}{\numberline {27.2}Prototypes and descriptions of {\tt ChvList} methods}{241} \contentsline {subsection}{\numberline {27.2.1}Basic methods}{241} \contentsline {subsection}{\numberline {27.2.2}Initialization methods}{242} \contentsline {subsection}{\numberline {27.2.3}Utility methods}{242} \contentsline {subsection}{\numberline {27.2.4}IO methods}{242} \contentsline {chapter}{\numberline {28}{\tt ChvManager}: {\tt Chv} manager object }{243} \contentsline {section}{\numberline {28.1}Data Structure}{244} \contentsline {section}{\numberline {28.2}Prototypes and descriptions of {\tt ChvManager} methods}{244} \contentsline {subsection}{\numberline {28.2.1}Basic methods}{244} \contentsline {subsection}{\numberline {28.2.2}Initialization methods}{245} \contentsline {subsection}{\numberline {28.2.3}Utility methods}{245} \contentsline {subsection}{\numberline {28.2.4}IO methods}{245} \contentsline {chapter}{\numberline {29}{\tt DenseMtx}: Dense matrix object}{246} \contentsline {section}{\numberline {29.1}Data Structure}{246} \contentsline {section}{\numberline {29.2}Prototypes and descriptions of {\tt DenseMtx} methods}{247} \contentsline {subsection}{\numberline {29.2.1}Basic methods}{247} \contentsline {subsection}{\numberline {29.2.2}Instance methods}{247} \contentsline {subsection}{\numberline {29.2.3}Initialization methods}{249} \contentsline {subsection}{\numberline {29.2.4}Utility methods}{250} \contentsline {subsection}{\numberline {29.2.5}IO methods}{252} \contentsline {chapter}{\numberline {30}{\tt FrontMtx}: Front matrix}{254} \contentsline {section}{\numberline {30.1}Data Structures}{257} \contentsline {section}{\numberline {30.2}Prototypes and descriptions of {\tt FrontMtx} methods}{259} \contentsline {subsection}{\numberline {30.2.1}Basic methods}{259} \contentsline {subsection}{\numberline {30.2.2}Instance methods}{259} \contentsline {subsection}{\numberline {30.2.3}Initialization methods}{261} \contentsline {subsection}{\numberline {30.2.4}Utility Factorization methods}{262} \contentsline {subsection}{\numberline {30.2.5}Serial Factorization method}{264} \contentsline {subsection}{\numberline {30.2.6}QR factorization utility methods}{265} \contentsline {subsection}{\numberline {30.2.7}Serial $QR$ Factorization method}{266} \contentsline {subsection}{\numberline {30.2.8}Postprocessing methods}{266} \contentsline {subsection}{\numberline {30.2.9}Utility Solve methods}{267} \contentsline {subsection}{\numberline {30.2.10}Serial Solve method}{268} \contentsline {subsection}{\numberline {30.2.11}Serial $QR$ Solve method}{269} \contentsline {subsection}{\numberline {30.2.12}Utility methods}{269} \contentsline {subsection}{\numberline {30.2.13}IO methods}{270} \contentsline {section}{\numberline {30.3}Driver programs for the {\tt DFrontMtx} object}{271} \contentsline {chapter}{\numberline {31}{\tt ILUMtx}: Incomplete $LU$ Matrix Object}{273} \contentsline {section}{\numberline {31.1}Data Structure}{273} \contentsline {section}{\numberline {31.2}Prototypes and descriptions of {\tt ILUMtx} methods}{274} \contentsline {subsection}{\numberline {31.2.1}Basic methods}{274} \contentsline {subsection}{\numberline {31.2.2}Initialization Methods}{275} \contentsline {subsection}{\numberline {31.2.3}Factorization Methods}{275} \contentsline {subsection}{\numberline {31.2.4}Solve Methods}{275} \contentsline {subsection}{\numberline {31.2.5}Utility methods}{276} \contentsline {subsection}{\numberline {31.2.6}IO methods}{276} \contentsline {section}{\numberline {31.3}Driver programs for the {\tt ILUMtx} object}{277} \contentsline {chapter}{\numberline {32}{\tt InpMtx}: Input Matrix Object}{278} \contentsline {section}{\numberline {32.1}Data Structure}{279} \contentsline {section}{\numberline {32.2}Prototypes and descriptions of {\tt InpMtx} methods}{281} \contentsline {subsection}{\numberline {32.2.1}Basic methods}{281} \contentsline {subsection}{\numberline {32.2.2}Instance Methods}{281} \contentsline {subsection}{\numberline {32.2.3}Methods to initialize and change state}{284} \contentsline {subsection}{\numberline {32.2.4}Input methods}{285} \contentsline {subsection}{\numberline {32.2.5}Permutation, map and support methods}{286} \contentsline {subsection}{\numberline {32.2.6}Matrix-matrix multiply methods}{287} \contentsline {subsection}{\numberline {32.2.7}Graph construction methods}{289} \contentsline {subsection}{\numberline {32.2.8}Submatrix extraction method}{290} \contentsline {subsection}{\numberline {32.2.9}Utility methods}{290} \contentsline {subsection}{\numberline {32.2.10}IO methods}{292} \contentsline {section}{\numberline {32.3}Driver programs for the {\tt InpMtx} object}{293} \contentsline {chapter}{\numberline {33}{\tt Iter}: Iterative Methods}{301} \contentsline {section}{\numberline {33.1}Data Structure}{301} \contentsline {section}{\numberline {33.2}Prototypes and descriptions of {\tt Iter} methods}{301} \contentsline {subsection}{\numberline {33.2.1}Utility methods}{301} \contentsline {subsection}{\numberline {33.2.2}Iterative methods}{303} \contentsline {section}{\numberline {33.3}Driver programs}{306} \contentsline {chapter}{\numberline {34}{\tt PatchAndGoInfo}: Pivot Modification Object}{311} \contentsline {section}{\numberline {34.1}Data Structure}{312} \contentsline {section}{\numberline {34.2}Prototypes and descriptions of {\tt PatchAndGoInfo} methods}{312} \contentsline {subsection}{\numberline {34.2.1}Basic methods}{312} \contentsline {subsection}{\numberline {34.2.2}Initializer methods}{313} \contentsline {chapter}{\numberline {35}{\tt Pencil}: Matrix pencil}{314} \contentsline {section}{\numberline {35.1}Data Structure}{314} \contentsline {section}{\numberline {35.2}Prototypes and descriptions of {\tt Pencil} methods}{314} \contentsline {subsection}{\numberline {35.2.1}Basic methods}{314} \contentsline {subsection}{\numberline {35.2.2}Initialization methods}{315} \contentsline {subsection}{\numberline {35.2.3}Utility methods}{315} \contentsline {subsection}{\numberline {35.2.4}IO methods}{316} \contentsline {chapter}{\numberline {36}{\tt SemiImplMtx}: Semi-Implicit Factorization}{317} \contentsline {section}{\numberline {36.1}Data Structure}{318} \contentsline {section}{\numberline {36.2}Prototypes and descriptions of {\tt SemiImplMtx} methods}{318} \contentsline {subsection}{\numberline {36.2.1}Basic methods}{318} \contentsline {subsection}{\numberline {36.2.2}Initialization Methods}{319} \contentsline {subsection}{\numberline {36.2.3}Solve Methods}{319} \contentsline {subsection}{\numberline {36.2.4}Utility methods}{320} \contentsline {subsection}{\numberline {36.2.5}IO methods}{320} \contentsline {section}{\numberline {36.3}Driver programs for the {\tt SemiImplMtx} object}{320} \contentsline {chapter}{\numberline {37}{\tt SubMtx}: Submatrix object}{322} \contentsline {section}{\numberline {37.1}Data Structure}{323} \contentsline {section}{\numberline {37.2}Prototypes and descriptions of {\tt SubMtx} methods}{324} \contentsline {subsection}{\numberline {37.2.1}Basic methods}{325} \contentsline {subsection}{\numberline {37.2.2}Instance methods}{325} \contentsline {subsection}{\numberline {37.2.3}Initialization methods}{328} \contentsline {subsection}{\numberline {37.2.4}Vector scaling methods}{329} \contentsline {subsection}{\numberline {37.2.5}Solve methods}{329} \contentsline {subsection}{\numberline {37.2.6}Utility methods}{330} \contentsline {subsection}{\numberline {37.2.7}IO methods}{331} \contentsline {section}{\numberline {37.3}Driver programs for the {\tt SubMtx object}}{333} \contentsline {chapter}{\numberline {38}{\tt SubMtxList}: {\tt SubMtx} list object }{337} \contentsline {section}{\numberline {38.1}Data Structure}{338} \contentsline {section}{\numberline {38.2}Prototypes and descriptions of {\tt SubMtxList} methods}{338} \contentsline {subsection}{\numberline {38.2.1}Basic methods}{338} \contentsline {subsection}{\numberline {38.2.2}Initialization methods}{339} \contentsline {subsection}{\numberline {38.2.3}Utility methods}{339} \contentsline {subsection}{\numberline {38.2.4}IO methods}{339} \contentsline {chapter}{\numberline {39}{\tt SubMtxManager}: {\tt SubMtx} object manager}{340} \contentsline {section}{\numberline {39.1}Data Structure}{341} \contentsline {section}{\numberline {39.2}Prototypes and descriptions of {\tt SubMtxManager} methods}{341} \contentsline {subsection}{\numberline {39.2.1}Basic methods}{341} \contentsline {subsection}{\numberline {39.2.2}Initialization methods}{342} \contentsline {subsection}{\numberline {39.2.3}Utility methods}{342} \contentsline {subsection}{\numberline {39.2.4}IO methods}{342} \contentsline {chapter}{\numberline {40}{\tt SymbFac}: Symbolic Factorization}{343} \contentsline {section}{\numberline {40.1}Data Structure}{343} \contentsline {section}{\numberline {40.2}Prototypes and descriptions of {\tt SymbFac} methods}{343} \contentsline {subsection}{\numberline {40.2.1}Symbolic factorization methods}{343} \contentsline {section}{\numberline {40.3}Driver programs }{344} \contentsline {part}{\uppercase {v}\hspace {1em}Miscellaneous Methods}{346} \contentsline {chapter}{\numberline {41}{\tt Misc} directory}{348} \contentsline {section}{\numberline {41.1}Prototypes and descriptions of methods in the {\tt Misc} directory}{348} \contentsline {subsection}{\numberline {41.1.1}Theoretical nested dissection methods}{348} \contentsline {subsection}{\numberline {41.1.2}Multiple minimum degree, Nested dissection and multisection wrapper methods}{350} \contentsline {subsection}{\numberline {41.1.3}Graph drawing method}{351} \contentsline {subsection}{\numberline {41.1.4}Linear system construction}{351} \contentsline {section}{\numberline {41.2}Driver programs found in the {\tt Misc} directory}{352} \contentsline {part}{\uppercase {vi}\hspace {1em}Multithreaded Methods}{361} \contentsline {chapter}{\numberline {42}{\tt MT} directory}{363} \contentsline {section}{\numberline {42.1}Data Structure}{364} \contentsline {section}{\numberline {42.2}Prototypes and descriptions of {\tt MT} methods}{364} \contentsline {subsection}{\numberline {42.2.1}Matrix-matrix multiply methods}{364} \contentsline {subsection}{\numberline {42.2.2}Multithreaded Factorization methods}{365} \contentsline {subsection}{\numberline {42.2.3}Multithreaded $QR$ Factorization method}{366} \contentsline {subsection}{\numberline {42.2.4}Multithreaded Solve method}{366} \contentsline {subsection}{\numberline {42.2.5}Multithreaded $QR$ Solve method}{367} \contentsline {section}{\numberline {42.3}Driver programs for the multithreaded functions}{367} \contentsline {part}{\uppercase {vii}\hspace {1em}MPI Methods}{373} \contentsline {chapter}{\numberline {43}{\tt MPI} directory}{375} \contentsline {section}{\numberline {43.1}Data Structure}{375} \contentsline {subsection}{\numberline {43.1.1}{\tt MatMulInfo} : Matrix-matrix multiply information object}{375} \contentsline {section}{\numberline {43.2}Prototypes and descriptions of {\tt MPI} methods}{376} \contentsline {subsection}{\numberline {43.2.1}Split and redistribution methods}{376} \contentsline {subsection}{\numberline {43.2.2}Gather and scatter methods}{379} \contentsline {subsection}{\numberline {43.2.3}Symbolic Factorization methods}{379} \contentsline {subsection}{\numberline {43.2.4}Numeric Factorization methods}{380} \contentsline {subsection}{\numberline {43.2.5}Post-processing methods}{381} \contentsline {subsection}{\numberline {43.2.6}Numeric Solve methods}{382} \contentsline {subsection}{\numberline {43.2.7}Matrix-matrix multiply methods}{383} \contentsline {subsection}{\numberline {43.2.8}Broadcast methods}{384} \contentsline {subsection}{\numberline {43.2.9}Utility methods}{385} \contentsline {section}{\numberline {43.3}Driver programs}{386} 0}{\tt FrontMtx}: Front matdocumentation/ReferenceManual/makefile010064400020550007177000000000270664721267100215100ustar00clevecompmath00000400000006clean : - rm -f *.dvi documentation/ReferenceManual/partIntro.tex010064400020550007177000000531010665023122500225030ustar00clevecompmath00000400000006\part{Introduction} \chapter{Introduction} \par The {\bf SPOOLES} package is used to solve two types of real or complex linear systems: \begin{itemize} \item $AX = Y$ or $(A + \sigma B)X = Y$ where $A$ and B are square. $A$ and $B$ can be real or complex, symmetric, Hermitian or nonsymmetric. The factorization can proceed with or without pivoting for numerical stability. The factor matrices can be stored with or without dropping small entries. \item Minimize $\|AX_{*,j} - Y_{*,j}\|_2$ for each column of the solution matrix $X$ and right hand side matrix $Y$. This is done by computing a $QR$ factorization of $A$ and then solving $R^T R X = A^T Y$ or $R^H R X = A^H Y$. \end{itemize} In both cases, the linear systems can be permuted to reduce the fill in the factor matrices. \par The {\bf SPOOLES} software is written in an object oriented fashion in the C language. Parts of the software run in serial mode, multithreading using Solaris or POSIX threads, and with MPI. \par The software objects are naturally partitioned into three families of objects. \par \begin{center} \begin{tabular}{|l|l|} \multicolumn{2}{c}{\bf Utility objects} \\ \hline {\tt A2} & dense two dimensional array \\ {\tt Coords} & object to hold coordinates in any number of dimensions \\ {\tt DV} & double precision vector \\ {\tt Drand} & random number generator \\ {\tt I2Ohash} & hash table for the factor submatrices \\ {\tt IIheap} & simple heap object \\ {\tt IV} & int vector \\ {\tt IVL} & int list object \\ {\tt Ideq} & simple dequeue object \\ {\tt Lock} & abstract mutual exclusion lock \\ {\tt Perm} & permutation vector object \\ {\tt Utilities} & various vector and linked list utility methods \\ {\tt ZV} & double precision complex vector \\ \hline \end{tabular} \end{center} \par \begin{center} \begin{tabular}{|l|l|} \multicolumn{2}{c}{\bf Ordering objects} \\ \hline {\tt BKL} & Block Kernihan-Lin algorithm object \\ {\tt BPG} & bipartite graph object \\ {\tt DSTree} & domain/separator tree object \\ {\tt EGraph} & element graph object \\ {\tt ETree} & front tree object \\ {\tt GPart} & graph partitioning algorithm object \\ {\tt Graph} & graph object \\ {\tt MSMD} & multi-stage minimum degree algorithm object \\ {\tt Network} & network object for solving max flow problems \\ {\tt SolveMap} & map of submatrices to processes for solves \\ {\tt Tree} & tree object \\ \hline \end{tabular} \end{center} \par \begin{center} \begin{tabular}{|l|l|} \multicolumn{2}{c}{\bf Numeric objects} \\ \hline {\tt Chv} & block chevron object for fronts \\ {\tt ChvList} & object to hold lists of {\tt Chv} objects \\ {\tt ChvManager} & object to manager instances of {\tt Chv} objects \\ {\tt DenseMtx} & dense matrix object \\ {\tt FrontMtx} & front matrix object \\ {\tt ILUMtx} & simple preconditioner matrix object \\ {\tt InpMtx} & sparse matrix object \\ {\tt Iter} & Krylov methods for iterative solves \\ {\tt PatchAndGoInfo} & modified factors in the presence of zero or small pivots \\ {\tt Pencil} & object to contain $A + \sigma B$ \\ {\tt SemiImplMtx} & semi-implicit factorization matrix object \\ {\tt SubMtx} & object for dense or sparse submatrices \\ {\tt SubMtxList} & object to hold lists of {\tt SubMtx} objects \\ {\tt SubMtxManager} & object to manager instances of {\tt SubMtx} objects \\ {\tt SymbFac} & algorithm object to compute a symbolic factorization \\ \hline \end{tabular} \end{center} The {\tt MT} directory contains all the multithreaded methods and drivers programs. The {\tt MPI} directory contains all the {\tt MPI} methods and drivers. The {\tt misc} directory contains miscellaneous methods and drivers. \par Each of the following objects that hold numeric entries --- {\tt A2}, {\tt Chv}, {\tt DenseMtx}, {\tt FrontMtx}, {\tt ILUMtx}, {\tt InpMtx}, {\tt Pencil}, {\tt SemiImplMtx} and {\tt SubMtx} --- can hold real or complex entries. An object knows its {\tt type}, {\tt 1} for real (define'd constant {\tt SPOOLES\_REAL}) or {\tt 2} for complex (define'd constant {\tt SPOOLES\_COMPLEX}). Since C does not yet have a standard structure for complex numbers, we have followed the FORTRAN convention of storing the real and imaginary parts of a complex number in consecutive memory locations. Internally, we unroll the complex arithmetic into real arithmetic. The user need not be burdened by this process if (s)he uses the input/output methods for the different object. For example, {\tt DenseMtx\_setRealEntry()} sets an entry of a real dense matrix, while {\tt DenseMtx\_setComplexEntry()} sets an entry of a complex dense matrix. \par All the heavily used computational tasks have been expanded where possible into BLAS2 or BLAS3 kernels, for both the real and complex cases. There are a multitude of driver programs that test the functionality of the objects. A common output of a driver program is a file that can be input into Matlab to check the errors of the computations. This convention inspires confidence in the correctness of the kernel computations. \par \section{Software Design} \label{chapter:softwareDesign} \par The {\bf SPOOLES} library is written in the C language and uses object oriented design. There are some routines that manipulate native C data types such as vectors, but the vast bulk of the code is centered around objects, data objects and algorithm objects. By necessity, the implementation of an object is through the C {\tt struct} data type. We use the following naming convention --- a method (i.e., function) associated with an object of type {\tt Object} has the form \centerline{{\it (return value type)} {\tt Object\_}{\it methodName}{\tt (Object * obj}, $\ldots${\tt )};} The method's name begins with the name of the object it is associated with and the first parameter in the calling sequence is a pointer to the instance of the object. Virtually the only exception to this rule is the {\it constructor} method. \centerline{\tt Object * Object\_new(void) ;} \noindent Two objects, the {\tt Chv} and {\tt DenseMtx} objects, have methods that return the number of bytes needed to hold their data, e.g., \centerline{\tt int Chv\_nbytesNeeded(int nD, int nL, int nU, int type, int symflag) ;} \par Scan the directory structure of the source code and you will notice a number of subdirectories --- each deals with an object. For example, the {\tt Graph} directory holds code and documentation for an object that represents a graph: its {\tt doc} subdirectory holds \LaTeX files with documentation; its {\tt src} subdirectory holds C files that contain methods associated with the object ; % (each method is a C function of the form {\tt Graph\_*}); and its {\tt driver} subdirectory holds driver programs to test or validate some behavior of the object. \par The directory structure is fairly flat --- no object directory contains another --- because the C language does not support inheritance. This can be inelegant at times. For example, a bipartite graph (a {\tt BPG} object) {\it is--a} graph (a {\tt Graph} object), but instead of {\tt BPG} inheriting from {\tt Graph} data fields and methods from {\tt Graph}, we must use the {\it has--a} relation. A {\tt BPG} object contains a pointer to a {\tt Graph} object that represents the adjacency structure. The situation is even more cumbersome for the objects that deal with trees of one form or another: an elimination tree {\tt ETree} and a domain/separator tree {\tt DSTree} each contain a pointer to a generic tree object {\tt Tree} in their structure. \par Predecessors to this library were written in C++ and Objective-C.\footnote{The knowledgeable reader is encouraged to peruse the source to discover the prejudices both pro and con towards these two languages.} The port to the present C library was painless, almost mechanical. We expect the port back to C++ and/or Objective-C to be simple. \par Objects are one of two types: {\it data objects} whose primary function is to store data and {\it algorithm objects} whose function is to manipulate some data object(s) and return new information. Naturally this distinction can be fuzzy --- algorithm objects have their own data that may be persistent and data objects can execute some simple functionality --- but it holds in general. To be more explicit, data objects have the following properties: \begin{itemize} \item There is a delicate balance between encapsulation and openness. The C language does not support any private or protected data fields, so the C {\tt struct} that holds the data for an object is completely open. As an example, the {\tt Graph} object has a function to return the size of and pointers to a vector that contains an adjacency list, namely \begin{verbatim} void Graph_adjAndSize(Graph *g, int v, int *psize, int **padj) \end{verbatim} where the pointers {\tt psize} and {\tt padj} are filled with the size of the adjacency structure and a pointer to its vector. One can get this same information by chasing pointers as follows. \begin{verbatim} vsize = g->adjIVL->sizes[v] ; vadj = g->adjIVL->p_ind[v] ; \end{verbatim} One can do the latter but we encourage the former. As an experiment we replaced every instance of {\tt Graph\_adjAndSize()} with the appropriate pointer chasing (and a similar operation for the {\tt IVL} object) and achieved around a ten per cent reduction in the ordering time. For a production code, this savings might drive the change in code, but for our research code we kept the function call. \item Persistent storage needs to be supported. % Currently this means file storage, but in the future we expect to % need to ``bundle'' a data object into a block of storage to be % passed or communicated to a different processor. Each data object has eight different methods to deal with file I/O. Two methods deal with reading from and writing to a file whose suffix is associated with the object name, e.g., {\tt *graph\{f,b\}} for a formatted or binary file to hold a {\tt Graph} object. Four methods deal with reading and writing objects from and to a file that is already opened and positioned, necessary for composite objects (e.g., a {\tt Graph} object contains an {\tt IVL} object). Two methods deal with writing the objects to a formatted file to be examined by the user. We strongly encourage any new data object added to the library to supply this functionality. \item Some data objects need to have compact storage requirements. Two examples are our {\tt Chv} and {\tt SubMtx} objects. Both objects need to be communicated between processes in the MPI implementation, the former during the factorization, the latter during the solve. Each has a workspace buffer that contains all the information needed to {\it regenerate} the object upon reception by another process. \item By and large, data objects have simple methods. A {\tt Graph} object does {\bf not} have methods to find a good bisector; this is a sufficiently sophisticated function that it should be implemented by an algorithm object. The major exception to this rule is that our {\tt FrontMtx} object {\it contains} the factorization data but also {\it performs} the factorization, forward and backsolves. In the future we intend to separate these two functionalities. For example, one can implement an alternative forward and backsolve by using methods to {\it access} the factor data stored in the {\tt FrontMtx} object. As a second example, massive changes to the storage format, e.g., in an out-of-core implementation, can be encapsulated in the access methods for the data, and any changes to the factorization or solve functions could be minimal. \end{itemize} Algorithm objects have these properties. \begin{itemize} \item Algorithm objects use data objects. Some data objects are created within an algorithm objects method; these are owned by the algorithm object and free'd by that object. Data objects that are passed to algorithm objects can be queried or {\it temporarily} changed. \item They do not destroy or free data objects that are passed to them. Any side effects on the data objects should be innocent, e.g., when a {\tt Graph} object is passed to the graph partitioning object ({\tt GPart}) or the multistage minimum degree object ({\tt MSMD}), on return the adjacency lists may not be in the input order, but they contain the values they had on input. \item Algorithm objects should support diagnostic, logfile and debug output. This convention is not entirely thought out or supported at present. The rationale is that an algorithm object should be able to respond to its environment to a greater degree than a data object. \end{itemize} \par Data and algorithm objects share two common properties. \begin{itemize} \item Each object has four basic methods: to allocate storage for an object, set the default fields of an object, clear the data fields of an object, and free the storage occupied and owned by an object. \item Ownership of data is very rigidly defined. In most cases, an object owns all data that is allocated inside one of its methods, and when this does not hold it is very plainly documented. For example, the bipartite graph object {\tt BPG} has a data field that points to a {\tt Graph} object. One of its initialization methods has a {\tt Graph} pointer in its calling sequence. The {\tt BPG} object then owns the {\tt Graph} object and when it is free'd or has its data cleared, the {\tt Graph} object is free'd by a call to its appropriate method. \end{itemize} \par By and large these conventions hold throughout the library. There are fuzzy areas and objects still ``under construction''. Here are two examples. \begin{itemize} \item We have an {\tt IIheap} object that maintains integer $\langle$ key, value $\rangle$ pairs in a priority heap. Normally we think of a heap as a data structure, but another perspective is that of a continuously running algorithm that supports insert, delete and identification of a minimum pair. \item Our {\tt BPG} bipartite graph object is a data object, but it has a method to find the Dulmage-Mendelsohn decomposition, a fairly involved algorithm used to refine a separator of a graph. At present, we are not willing to create a new algorithm object just to find the Dulmage-Mendelsohn decomposition, so we leave this method to the domain of the data object. The desired functionality, identifying minimal weight separators for a region of a graph, can be modeled using max flow techniques from network optimization. We also provide a {\tt BPG} method that finds this Dulmage-Mendelsohn decomposition by solving a max flow problem on a bipartite network. Both these methods have been superceded by the {\tt Network} object that contains a method to find a max flow and one or more min-cuts of a network (not necessarily bipartite). \end{itemize} \par The {\bf SPOOLES} software library is continuously evolving in an almost organic fashion. Growth and change are to be expected, and welcomed, but some discipline is required to keep the complexity, both code and human understanding, under control. The guidelines we have just presented have two purposes: to let the user and researcher get a better understanding of the design of the library, and to point out some conventions to be used in extending the library. \par \section{Changes from Release 1.0} \label{section:intro:changes-1.0} \par There are two major changes from the first release of the {\bf SPOOLES} package: we now support complex linear systems, and the storage format of the sparse factor matrices has changed from a one-dimensional data decomposition to a two-dimensional decomposition. The factors are now submatrix based, and thus allow a parallel solve to be much faster than in Release 1.0. \par In the first release, all numeric objects had a {\tt `D`} as the leading letter in their name, e.g., {\tt DA2}, {\tt DChv}, etc. A natural way to implement complex data types would be to write ``parallel'' objects, e.g., {\tt ZA2}, {\tt ZChv}, etc, as is done in LINPACK and LAPACK for subroutine names. However, a {\tt DA2} and {\tt ZA2} object share so much common code that it is a better decision to combine the real and complex functionality into one object. This is even more pronounced for the {\tt FrontMtx} object where there is virtually no code that is dependent on whether or not the matrix is real or complex. \par Virtually no new work has been done on the ordering objects and methods. Their algorithms were state of the art two years ago, but a recent comparison with the {\bf EXTREME} \cite{hr98-msndtalk} and {\bf METIS} \cite{karypis98metis} packages on a large collection of finite element problems shows that the {\bf SPOOLES} orderings are still competitive. \par The serial, multithreaded and MPI code has been modified to force greater sharing of code between the environments. ``What'' is done is identical in the three cases. The multithreaded and MPI codes share the same ``choreography'', in other words, who does what and how. The main differences between multithreaded and MPI are that the data structures are global versus local, and that explicit message passing is done in the latter. This common structure of the codes has a nonzero impact on the speed and efficiency of the individual codes, but the gains from a common code base are well worth the cost. \par The MPI methods have been extensively reworked since the first release. A number of bugs and logic errors have been detected and fixed. The code appears to be more robust than the first release. \par \section{Changes from Release 2.0} \label{section:intro:changes-2.0} \par Release 2.2 is partly a maintenance release. Some bugs were found and fixed in the MPI factors and solves. Some minor new methods were added to the {\tt DenseMtx}, {\tt FrontMtx}, {\tt InpMtx} and {\tt Utilities} directories. The multithreaded methods and drivers have been removed from the {\tt FrontMtx} directory and placed in a new {\tt MT} directory, much like the {\tt MPI} methods have their own directory. \par Some new functionality has been added. \begin{itemize} \item There are now multithreaded and distributed matrix-matrix multiply methods. See the {\tt MT} and {\tt MPI} directories. \item The {\tt FrontMtx} object now supports more robust reporting of errors encountered during the factorization. There is one additional parameter in the factorization calling sequences, an error return that signals that the factorization has failed. \item In response to customer requirements, we have added some ``patch-and-go'' functionality to the sparse $LU$ and $U^TDU$ factorizations without pivoting. There are applications in optimization and structural analysis where pivoting is not necessary for stabilty, but where the location of small or zero pivots on the diagonal is meaningful. Normally the factorization would be ustable or stop, but special action is taken, the factors are ``patched'' and the factorization continues. \par There is a new {\tt PatchAndGoInfo} object that encapsulates the ``patch-and-go'' strategy and gathers optional statistics about the action that was taken during the factorization. This object is attached to the {\tt FrontMtx} object which passes it unchanged to the {\tt Chv} object that performs the factorization of each front. If the user does not need this functionality, no changes are necessary to their code, i.e., no calling sequences are affected. \item New MPI broadcast methods for the {\tt Graph}, {\tt IVL} and {\tt ETree} objects have been added to the library. \item The {\tt Iter} directory contains the following Krylov accelerators for the iterative solution of linear systems: Block GMRES, BiCGStab, conjugate gradient and transpose-free QMR. Each is available in both left- and right-preconditioned forms. The preconditioner that these methods use is a {\tt FrontMtx} object that contains a drop tolerance approximate factorization. The {\tt ILUMtx} object contains a simple vector-based drop tolerance factorization object. (The {\tt FrontMtx} approximate factorization is submatrix-based in both its data structures and computational kernels, and supports pivoting for numerical stability, which the {\tt ILUMtx} object does not.) We have not written Krylov methods that use the {\tt ILUMtx} object, but it would be simple to replace the {\tt FrontMtx} preconditioner with the {\tt ILUMtx} preconditioner. \item The {\tt SemiImplMtx} object contains a {\it semi-implicit} factorization, a technique that can require less storage and solve operations than the present explicit factorization. It is based on the equation $$ \left \lbrack \begin{array}{cc} A_{0,0} & A_{0,1} \cr A_{1,0} & A_{1,1} \end{array} \right \rbrack = \left \lbrack \begin{array}{cc} L_{0,0} & 0 \cr L_{1,0} & L_{1,1} \end{array} \right \rbrack \left \lbrack \begin{array}{cc} U_{0,0} & U_{0,1} \cr 0 & U_{1,1} \end{array} \right \rbrack, = \left \lbrack \begin{array}{cc} L_{0,0} & 0 \cr A_{1,0}U_{0,0}^{-1} & L_{1,1} \end{array} \right \rbrack \left \lbrack \begin{array}{cc} U_{0,0} & L_{0,0}^{-1}U_{0,1} \cr 0 & U_{1,1} \end{array} \right \rbrack. $$ A solve of $AX = B$ with the explicit factorization does the following steps \begin{itemize} \item solve $L_{0,0} Y_0 = B_0$ \item solve $L_{1,1} U_{1,1} X_1 = B_1 - L_{1,0} Y_0$ \item solve $U_{0,0} X_0 = Y_0 - U_{0,1} X_1$ \end{itemize} while an implicit factorization has the following form. \begin{itemize} \item solve $L_{0,0} U_{0,0} Z_0 = B_0$ \item solve $L_{1,1} U_{1,1} X_1 = B_1 - A_{1,0} Z_0$ \item solve $L_{0,0} U_{0,0} X_0 = B_0 - A_{0,1} X_1$ \end{itemize} The difference is that the semi-implicit factorization stores and computes with $A_{1,0}$ and $A_{0,1}$ instead of $L_{1,0}$ and $U_{0,1}$, (this can be a modest savings in storage and operation count), and performs two solves with $L_{0,0}$ and $U_{0,0}$ instead of one. This technique works with either a direct or approximate factorization of $A$. The semi-implicit factorization is constructed via a post-processing of any factorization computed by the {\tt FrontMtx} object. \end{itemize} and free'd by that object. Data objects that are passed to algorithm objects can be queried or {\it temporarily} changed. \item They do not destroy or free data objects that are passed to them. Any side effects on the data objects should be innocent, e.g., when a {\tt Graph} object is passed to the graph partitioning object ({\tt GPart}) or the multistage minimum degree object ({\tt MSMD}), on return the adjacency lists may not be in the inpudocumentation/ReferenceManual/partMPI.tex010064400020550007177000000002360664721267100220500ustar00clevecompmath00000400000006\part{MPI Methods} \par \input ../../MPI/doc/intro.tex \input ../../MPI/doc/dataStructure.tex \input ../../MPI/doc/proto.tex \input ../../MPI/doc/drivers.tex documentation/ReferenceManual/partMT.tex010064400020550007177000000002440664721267100217420ustar00clevecompmath00000400000006\part{Multithreaded Methods} \par \input ../../MT/doc/intro.tex \input ../../MT/doc/dataStructure.tex \input ../../MT/doc/proto.tex \input ../../MT/doc/drivers.tex documentation/ReferenceManual/partMisc.tex010064400020550007177000000002040664721267100223110ustar00clevecompmath00000400000006\part{Miscellaneous Methods} \par \input ../../misc/doc/intro.tex \input ../../misc/doc/proto.tex \input ../../misc/doc/drivers.tex documentation/ReferenceManual/partNumeric.tex010064400020550007177000000041370664721267100230310ustar00clevecompmath00000400000006\part{Numeric Objects and Methods} \par \input ../../Chv/doc/intro.tex \input ../../Chv/doc/dataStructure.tex \input ../../Chv/doc/proto.tex \input ../../Chv/doc/drivers.tex \par \input ../../ChvList/doc/intro.tex \input ../../ChvList/doc/dataStructure.tex \input ../../ChvList/doc/proto.tex \par \input ../../ChvManager/doc/intro.tex \input ../../ChvManager/doc/dataStructure.tex \input ../../ChvManager/doc/proto.tex \par \input ../../DenseMtx/doc/intro.tex \input ../../DenseMtx/doc/dataStructure.tex \input ../../DenseMtx/doc/proto.tex \par \input ../../FrontMtx/doc/intro.tex \input ../../FrontMtx/doc/dataStructure.tex \input ../../FrontMtx/doc/proto.tex \input ../../FrontMtx/doc/drivers.tex \par \input ../../ILUMtx/doc/intro.tex \input ../../ILUMtx/doc/dataStructure.tex \input ../../ILUMtx/doc/proto.tex \input ../../ILUMtx/doc/drivers.tex \par \input ../../InpMtx/doc/intro.tex \input ../../InpMtx/doc/dataStructure.tex \input ../../InpMtx/doc/proto.tex \input ../../InpMtx/doc/drivers.tex \par \input ../../Iter/doc/intro.tex \input ../../Iter/doc/dataStructure.tex \input ../../Iter/doc/proto.tex \input ../../Iter/doc/drivers.tex \par \input ../../PatchAndGoInfo/doc/intro.tex \input ../../PatchAndGoInfo/doc/dataStructure.tex \input ../../PatchAndGoInfo/doc/proto.tex \par \input ../../Pencil/doc/intro.tex \input ../../Pencil/doc/dataStructure.tex \input ../../Pencil/doc/proto.tex \par \input ../../SemiImplMtx/doc/intro.tex \input ../../SemiImplMtx/doc/dataStructure.tex \input ../../SemiImplMtx/doc/proto.tex \input ../../SemiImplMtx/doc/drivers.tex \par \input ../../SubMtx/doc/intro.tex \input ../../SubMtx/doc/dataStructure.tex \input ../../SubMtx/doc/proto.tex \input ../../SubMtx/doc/drivers.tex \par \input ../../SubMtxList/doc/intro.tex \input ../../SubMtxList/doc/dataStructure.tex \input ../../SubMtxList/doc/proto.tex \par \input ../../SubMtxManager/doc/intro.tex \input ../../SubMtxManager/doc/dataStructure.tex \input ../../SubMtxManager/doc/proto.tex \par \input ../../SymbFac/doc/intro.tex \input ../../SymbFac/doc/dataStructure.tex \input ../../SymbFac/doc/proto.tex \input ../../SymbFac/doc/drivers.tex \par aStructure.tex \input ../../Chv/doc/proto.tex \input ../../Chv/doc/drivers.tex \par \input ../../ChvList/doc/intro.tex \input ../../ChvList/doc/dataStructure.tex \input ../../ChvList/doc/proto.tex \par \input ../../ChvManager/doc/intro.tex \input ../../ChvManager/doc/dataStructure.tex \input ../../ChvManager/doc/proto.tex \par \input ../../DenseMtx/doc/intro.tex \input ../../DenseMtx/doc/dataStructure.tex \input .documentation/ReferenceManual/partOrder.tex010064400020550007177000000030150664721267100224740ustar00clevecompmath00000400000006\part{Ordering Objects and Methods} \par \input ../../BKL/doc/intro.tex \input ../../BKL/doc/dataStructure.tex \input ../../BKL/doc/proto.tex \par \input ../../BPG/doc/intro.tex \input ../../BPG/doc/dataStructure.tex \input ../../BPG/doc/proto.tex \input ../../BPG/doc/drivers.tex \par \input ../../DSTree/doc/intro.tex \input ../../DSTree/doc/dataStructure.tex \input ../../DSTree/doc/proto.tex \input ../../DSTree/doc/drivers.tex \par \input ../../EGraph/doc/intro.tex \input ../../EGraph/doc/dataStructure.tex \input ../../EGraph/doc/proto.tex \input ../../EGraph/doc/drivers.tex \par \input ../../ETree/doc/intro.tex \input ../../ETree/doc/dataStructure.tex \input ../../ETree/doc/proto.tex \input ../../ETree/doc/drivers.tex \par \input ../../GPart/doc/intro.tex \input ../../GPart/doc/dataStructure.tex \input ../../GPart/doc/proto.tex \input ../../GPart/doc/drivers.tex \par \input ../../Graph/doc/intro.tex \input ../../Graph/doc/dataStructure.tex \input ../../Graph/doc/proto.tex \input ../../Graph/doc/drivers.tex \par \input ../../MSMD/doc/intro.tex \input ../../MSMD/doc/dataStructure.tex \input ../../MSMD/doc/proto.tex \input ../../MSMD/doc/drivers.tex \par \input ../../Network/doc/intro.tex \input ../../Network/doc/dataStructure.tex \input ../../Network/doc/proto.tex \par \input ../../SolveMap/doc/intro.tex \input ../../SolveMap/doc/dataStructure.tex \input ../../SolveMap/doc/proto.tex \par \input ../../Tree/doc/intro.tex \input ../../Tree/doc/dataStructure.tex \input ../../Tree/doc/proto.tex \input ../../Tree/doc/drivers.tex documentation/ReferenceManual/partUtil.tex010064400020550007177000000033540664721267100223440ustar00clevecompmath00000400000006\part{Utility Objects and Methods} \par \input ../../A2/doc/intro.tex \input ../../A2/doc/dataStructure.tex \input ../../A2/doc/proto.tex \input ../../A2/doc/drivers.tex \par \input ../../Coords/doc/intro.tex \input ../../Coords/doc/dataStructure.tex \input ../../Coords/doc/proto.tex \input ../../Coords/doc/drivers.tex \par \input ../../DV/doc/intro.tex \input ../../DV/doc/dataStructure.tex \input ../../DV/doc/proto.tex \input ../../DV/doc/drivers.tex \par \input ../../Drand/doc/intro.tex \input ../../Drand/doc/dataStructure.tex \input ../../Drand/doc/proto.tex \input ../../Drand/doc/drivers.tex \par \input ../../I2Ohash/doc/intro.tex \input ../../I2Ohash/doc/dataStructure.tex \input ../../I2Ohash/doc/proto.tex \input ../../I2Ohash/doc/drivers.tex \par \input ../../IIheap/doc/intro.tex \input ../../IIheap/doc/dataStructure.tex \input ../../IIheap/doc/proto.tex \par \input ../../IV/doc/intro.tex \input ../../IV/doc/dataStructure.tex \input ../../IV/doc/proto.tex \input ../../IV/doc/drivers.tex \par \input ../../IVL/doc/intro.tex \input ../../IVL/doc/dataStructure.tex \input ../../IVL/doc/proto.tex \input ../../IVL/doc/drivers.tex \par \input ../../Ideq/doc/intro.tex \input ../../Ideq/doc/dataStructure.tex \input ../../Ideq/doc/proto.tex \par \input ../../Lock/doc/intro.tex \input ../../Lock/doc/dataStructure.tex \input ../../Lock/doc/proto.tex \par \input ../../Perm/doc/intro.tex \input ../../Perm/doc/dataStructure.tex \input ../../Perm/doc/proto.tex \par \input ../../Utilities/doc/intro.tex \input ../../Utilities/doc/dataStructure.tex \input ../../Utilities/doc/proto.tex \input ../../Utilities/doc/drivers.tex \par \input ../../ZV/doc/intro.tex \input ../../ZV/doc/dataStructure.tex \input ../../ZV/doc/proto.tex \input ../../ZV/doc/drivers.tex documentation/ReferenceManual/preface.tex010064400020550007177000000031770664721267100221500ustar00clevecompmath00000400000006\newpage \centerline{\Large\bf Preface} \par \medskip \par Please note that this is an alpha release of the package, probably a 0.5 release in anticipation of a 1.0 version that will be useful and self-contained. \par The serial code and the threaded code using the Solaris thread package is relatively stable, meaning that every once in a while we shake out a bug but the code does factor and solve sparse linear systems relatively efficiently and in a fairly easy to use manner. The MPI version of the code is still under development, and we are reluctant to release the present code because we want the present code base for the three versions --- serial, threaded and MPI --- to be coherent. We don't anticipate any major changes to the code base as a result of the MPI development, but we offer no guarantees. \par The {\bf SPOOLES} library depends quite strongly on the objects found in the {\bf SMOOTH 1.1} library for ordering sparse matrices. The code conventions are the same between the two libraries. At some point in the future we will merge the two into one library. \par This reference document is not complete. All the objects are documented, their data structures and methods completely so. The background on the objects, the ``why'' and ``how'' of the design is lacking. The reader simply interested using the library should have little difficulty. The reader wanting to know more will appreciate a later version of this document that will contain a much better background discussion on motivation and software and will include a respectable bibliography. \par Please communicate all questions and comments to {\tt cleve.ashcraft@boeing.com}. documentation/ReferenceManual/quickstart.tex010064400020550007177000000133560664721267100227350ustar00clevecompmath00000400000006\par \chapter{A Quick Start} \label{chapter:quickstart} \par The {\bf SPOOLES} software package is large and complex --- there are seven objects, roughly 32000 lines of source code and another 4000 lines of driver programs. Furthermore, it is built on the {\bf SMOOTH} software package for ordering sparse matrices which contains twenty objects, 55000 lines of source code and another 12000 lines of driver programs. We like to think of the software in these two packages as boxes of Legos (plastic building blocks for children) --- by pulling out the right objects and fitting them together we can easily build code with complex functionality. \par Each object has its directory, a {\tt src} subdirectory that contains source code, a {\tt doc} subdirectory that holds \LaTeX\ files for documentation, and possibly a {\tt drivers} subdirectory that contains driver programs for this object. \par There are twenty objects in the {\bf SMOOTH} library. \begin{center} \begin{tabular}{|l|l|} \hline {\tt BKL } & block Kernighan-Lin algorithm \\ {\tt BPG } & bipartite graph object \\ {\tt Coords } & coordinates object \\ {\tt CV } & {\tt char} vector object \\ {\tt DInpMtx } & input matrix object \\ {\tt Drand } & random number generator \\ {\tt DSTree } & domain/separator tree object \\ {\tt DV } & {\tt double} vector object \\ {\tt EGraph } & element graph object \\ {\tt ETree } & elimination and front tree object \\ {\tt GPart } & graph partitioning object \\ {\tt Graph } & graph object \\ {\tt IIheap } & heap object \\ {\tt IV } & {\tt int} vector object \\ {\tt IVL } & {\tt int} vector list object \\ {\tt Ideq } & {\tt int} dequeue object \\ {\tt MSMD } & multi-stage minimum degree object \\ {\tt Network } & max flow/ min-cut network object \\ {\tt Perm } & permutation object \\ {\tt Tree } & tree object \\ \hline \end{tabular} \end{center} Nine of these are used in the {\bf SPOOLES} library: the {\tt CV}, {\tt DInpMtx}, {\tt Drand}, {\tt DV}, {\tt ETree}, {\tt IV}, {\tt IVL}, {\tt Ideq} and {\tt Tree} objects. The {\tt DInpMtx} and {\tt ETree} objects are the most important. The {\tt DInpMtx} object is used to assemble, store and make available to the factorization object the entries in the original matrix. The {\tt ETree} object stores the {\it front tree}, which is basically the blueprint or DNA that defines the data structures and the computations for the factorization and solves. The {\tt ETree} object is the end product of a matrix ordering that can be obtained from the {\bf SMOOTH} library.\footnote{ One can also use a permutation vector obtained from some outside source. There are {\tt ETree} methods that will generate an {\tt ETree} object from a permutation vector and a graph. One is not restricted to the ordering methods in the {\bf SMOOTH} library. } \par There are seven objects in the {\bf SPOOLES} library. \begin{center} \begin{tabular}{|l|l|} \hline {\tt CA2 } & character two-dimensional array object \\ {\tt DA2 } & double precision two-dimensional array object \\ {\tt DChv } & double precision chevron object \\ {\tt DChvL } & {\tt DChv} list object \\ {\tt DFrontMtx } & front matrix object, factors and solves \\ {\tt DVL } & double precision vector list object \\ {\tt PivotFinder } & object that finds pivot elements \\ \hline \end{tabular} \end{center} \par The {\it user} need know about very few of these objects --- \begin{itemize} \item {\tt DInpMtx} to assemble a sparse matrix, permute the matrix elements, and map the elements into the factorization, \item {\tt ETree} to hold a front tree that drives the factorization and solves, \item {\tt PivotFinder} that finds pivots for the factorization, and \item {\tt DFrontMtx} that computes and stores a factorization and solves linear systems. \end{itemize} We refer the reader to the {\bf SMOOTH} documentation for information on the {\tt DInpMtx} and {\tt ETree} objects. \par The {\tt PivotFinder} is a simple object that looks for suitable pivots in a front. If the user does not want pivoting enabled, (for example, if the matrix is diagonally dominant or one just wants to live dangerously), just set the {\tt PivotFinder} input parameter to {\tt NULL} in the calling sequence for the factorization method. The {\tt PivotFinder} object has several options and a user defined tolerance to give a range of behaviors. Furthermore, the {\tt DFrontMtx} factor matrix object knows nothing about pivot selection, so the {\tt PivotFinder} object can be extended or even replaced without touching any of the {\tt DFrontMtx} code.\footnote{ Were we working in a language that supported inheritance and/or protocols, (e.g., C++ or Objective-C), replacing the PivotFinder object would be a simple process. Since we work in C, we find it easiest to duplicate the {\tt PivotFinder} directory, change the functionality, and then link the new object into the {\tt DFrontMtx} code. } \par The {\tt DFrontMtx} object is the workhorse of the library. It handles symmetric or nonsymmetric factorizations, exact or approximate (the latter is not yet implemented though the hooks are in place), pivoting or no pivoting. Furthermore, there are three modes in which it operates: serial mode, multi-threaded, and MPI. The present release of the library uses the Solaris thread package to implement the multithreaded factor and solves. However, since we only use thread create and join operations along with mutex's (mutual exclusion locks), the port to a POSIX thread package, or just about any other thread package, will be straightforward. The MPI version of the factor and solves is still in the development stages. \par To get started with solving a linear system, read the {\tt DFrontMtx} documentation in Section~\ref{section:DFrontMtx} and see the {\tt testFactor.c} and {\tt testPFactor.c} driver programs in the {\tt spooles/DFrontmtx/drivers} directory. documentation/ReferenceManual/reference.tex010064400020550007177000000106610664721267100224750ustar00clevecompmath00000400000006\par % \chapter{Library Reference Manual} % \label{chapter:reference} \par \par \input ../BKL/doc/intro.tex \input ../BKL/doc/dataStructure.tex \input ../BKL/doc/proto.tex \par \input ../BPG/doc/intro.tex \input ../BPG/doc/dataStructure.tex \input ../BPG/doc/proto.tex \input ../BPG/doc/drivers.tex \par \input ../CV/doc/intro.tex \input ../CV/doc/dataStructure.tex \input ../CV/doc/proto.tex \par \input ../Coords/doc/intro.tex \input ../Coords/doc/dataStructure.tex \input ../Coords/doc/proto.tex \input ../Coords/doc/drivers.tex \par \input ../DA2/doc/intro.tex \input ../DA2/doc/dataStructure.tex \input ../DA2/doc/proto.tex \input ../DA2/doc/drivers.tex \par \input ../DChv/doc/intro.tex \input ../DChv/doc/dataStructure.tex \input ../DChv/doc/proto.tex \input ../DChv/doc/drivers.tex \par \input ../DChvList/doc/intro.tex \input ../DChvList/doc/dataStructure.tex \input ../DChvList/doc/proto.tex \par \input ../DChvManager/doc/intro.tex \input ../DChvManager/doc/dataStructure.tex \input ../DChvManager/doc/proto.tex \par \input ../DDenseMtx/doc/intro.tex \input ../DDenseMtx/doc/dataStructure.tex \input ../DDenseMtx/doc/proto.tex \par \input ../DDenseMtxList/doc/intro.tex \input ../DDenseMtxList/doc/dataStructure.tex \input ../DDenseMtxList/doc/proto.tex \par \input ../DDenseMtxManager/doc/intro.tex \input ../DDenseMtxManager/doc/dataStructure.tex \input ../DDenseMtxManager/doc/proto.tex \par \input ../DFrontMtx/doc/intro.tex \input ../DFrontMtx/doc/dataStructure.tex \input ../DFrontMtx/doc/proto.tex \input ../DFrontMtx/doc/drivers.tex \par \input ../DInpMtx/doc/intro.tex \input ../DInpMtx/doc/dataStructure.tex \input ../DInpMtx/doc/proto.tex \input ../DInpMtx/doc/drivers.tex \par \input ../DLinSystem/doc/intro.tex \input ../DLinSystem/doc/dataStructure.tex \input ../DLinSystem/doc/proto.tex \par \input ../DPencil/doc/intro.tex \input ../DPencil/doc/dataStructure.tex \input ../DPencil/doc/proto.tex \par \input ../DStairMtx/doc/intro.tex \input ../DStairMtx/doc/dataStructure.tex \input ../DStairMtx/doc/proto.tex \input ../DStairMtx/doc/drivers.tex \par \input ../DSTree/doc/intro.tex \input ../DSTree/doc/dataStructure.tex \input ../DSTree/doc/proto.tex \input ../DSTree/doc/drivers.tex \par \input ../DV/doc/intro.tex \input ../DV/doc/dataStructure.tex \input ../DV/doc/proto.tex \par \input ../DVL/doc/intro.tex \input ../DVL/doc/dataStructure.tex \input ../DVL/doc/proto.tex \par \input ../Drand/doc/intro.tex \input ../Drand/doc/dataStructure.tex \input ../Drand/doc/proto.tex \input ../Drand/doc/drivers.tex \par \input ../EGraph/doc/intro.tex \input ../EGraph/doc/dataStructure.tex \input ../EGraph/doc/proto.tex \input ../EGraph/doc/drivers.tex \par \input ../ETree/doc/intro.tex \input ../ETree/doc/dataStructure.tex \input ../ETree/doc/proto.tex \input ../ETree/doc/drivers.tex \par \input ../GPart/doc/intro.tex \input ../GPart/doc/dataStructure.tex \input ../GPart/doc/proto.tex \input ../GPart/doc/drivers.tex \par \input ../Graph/doc/intro.tex \input ../Graph/doc/dataStructure.tex \input ../Graph/doc/proto.tex \input ../Graph/doc/drivers.tex \par \input ../IIheap/doc/intro.tex \input ../IIheap/doc/dataStructure.tex \input ../IIheap/doc/proto.tex \par \input ../IV/doc/intro.tex \input ../IV/doc/dataStructure.tex \input ../IV/doc/proto.tex \par \input ../IVL/doc/intro.tex \input ../IVL/doc/dataStructure.tex \input ../IVL/doc/proto.tex \par \input ../Ideq/doc/intro.tex \input ../Ideq/doc/dataStructure.tex \input ../Ideq/doc/proto.tex \par \input ../Lock/doc/intro.tex \input ../Lock/doc/dataStructure.tex \input ../Lock/doc/proto.tex \par \input ../MPI/doc/intro.tex \input ../MPI/doc/dataStructure.tex \input ../MPI/doc/proto.tex \input ../MPI/doc/drivers.tex \par \input ../MSMD/doc/intro.tex \input ../MSMD/doc/dataStructure.tex \input ../MSMD/doc/proto.tex \input ../MSMD/doc/drivers.tex \par \input ../Network/doc/intro.tex \input ../Network/doc/dataStructure.tex \input ../Network/doc/proto.tex \par \input ../Perm/doc/intro.tex \input ../Perm/doc/dataStructure.tex \input ../Perm/doc/proto.tex \par \input ../SymbFac/doc/intro.tex \input ../SymbFac/doc/dataStructure.tex \input ../SymbFac/doc/proto.tex \input ../SymbFac/doc/drivers.tex \par \input ../Tree/doc/intro.tex \input ../Tree/doc/dataStructure.tex \input ../Tree/doc/proto.tex \input ../Tree/doc/drivers.tex \par \input ../Utilities/doc/intro.tex \input ../Utilities/doc/dataStructure.tex \input ../Utilities/doc/proto.tex \par \input ../misc/doc/intro.tex \input ../misc/doc/proto.tex \input ../misc/doc/drivers.tex documentation/ReferenceManual/softwareDesign.tex010064400020550007177000000240050665017152300235120ustar00clevecompmath00000400000006\par \section{Software Design} \label{chapter:softwareDesign} \par The {\tt SPOOLES} library is written in the C language and uses object oriented design. There are some routines that manipulate native C data types such as vectors, but the vast bulk of the code is centered around objects, data objects and algorithm objects. By necessity, the implementation of an object is through the C {\tt struct} data type. We use the following naming convention --- a method (i.e., function) associated with an object of type {\tt Object} has the form \centerline{{\it (return value type)} {\tt Object\_}{\it methodName}{\tt (Object * obj}, $\ldots${\tt )};} The method's name begins with the name of the object it is associated with and the first parameter in the calling sequence is a pointer to the instance of the object. Virtually the only exception to this rule is the {\it constructor} method. \centerline{\tt Object * Object\_new(void) ;} Two objects, the {\tt Chv} and {\tt DenseMtx} objects, have methods that return the number of bytes needed to hold their data, e.g., \centerline{\tt int Chv\_nbytesNeeded(int nD, int nL, int nU, int type, int symflag) ;} \par Scan the directory structure of the source code and you will notice a number of subdirectories --- each deals with an object. For example, the {\tt Graph} directory holds code and documentation for an object that represents a graph: its {\tt doc} subdirectory holds \LaTeX files with documentation; its {\tt src} subdirectory holds C files that contain methods associated with the object ; % (each method is a C function of the form {\tt Graph\_*}); and its {\tt driver} subdirectory holds driver programs to test or validate some behavior of the object. \par The directory structure is fairly flat --- no object directory contains another --- because the C language does not support inheritance. This can be inelegant at times. For example, a bipartite graph (a {\tt BPG} object) {\it is--a} graph (a {\tt Graph} object), but instead of {\tt BPG} inheriting from {\tt Graph} data fields and methods from {\tt Graph}, we must use the {\it has--a} relation. A {\tt BPG} object contains a pointer to a {\tt Graph} object that represents the adjacency structure. The situation is even more cumbersome for the objects that deal with trees of one form or another: an elimination tree {\tt ETree} and a domain/separator tree {\tt DSTree} each contain a pointer to a generic tree object {\tt Tree} in their structure. \par Predecessors to this library were written in C++ and Objective-C.\footnote{The knowledgeable reader is encouraged to peruse the source to discover the prejudices both pro and con towards these two languages.} The port to the present C library was painless, almost mechanical. We expect the port back to C++ and/or Objective-C to be simple. \par Objects are one of two types: {\it data objects} whose primary function is to store data and {\it algorithm objects} whose function is to manipulate some data object(s) and return new information. Naturally this distinction can be fuzzy --- algorithm objects have their own data that may be persistent and data objects can execute some simple functionality --- but it holds in general. To be more explicit, data objects have the following properties: \begin{itemize} \item There is a delicate balance between encapsulation and openness. The C language does not support any private or protected data fields, so the C {\tt struct} that holds the data for an object is completely open. As an example, the {\tt Graph} object has a function to return the size of and pointers to a vector that contains an adjacency list, namely \begin{verbatim} void Graph_adjAndSize(Graph *g, int v, int *pvsize, int **padj) \end{verbatim} where the pointers {\tt psize} and {\tt padj} are filled with the size of the adjacency structure and a pointer to its vector. One can get this same information by chasing pointers as follows. \begin{verbatim} vsize = g->adjIVL->sizes[v] ; vadj = g->adjIVL->p_ind[v] ; \end{verbatim} One can do the latter but we encourage the former. As an experiment we replaced every instance of {\tt Graph\_adjAndSize()} with the appropriate pointer chasing (and a similar operation for the {\tt IVL} object) and achieved around a ten per cent reduction in the ordering time. For a production code, this savings might drive the change in code, but for our research code we kept the function call. \item Persistent storage needs to be supported. % Currently this means file storage, but in the future we expect to % need to ``bundle'' a data object into a block of storage to be % passed or communicated to a different processor. Each data object has eight different methods to deal with file I/O. Two methods deal with reading from and writing to a file whose suffix is associated with the object name, e.g., {\tt *graph\{f,b\}} for a formatted or binary file to hold a {\tt Graph} object. Four methods deal with reading and writing objects from and to a file that is already opened and positioned, necessary for composite objects (e.g., a {\tt Graph} object contains an {\tt IVL} object). Two methods deal with writing the objects to a formatted file to be examined by the user. We strongly encourage any new data object added to the library to supply this functionality. \item Some data objects need to have compact storage requirements. Two examples are our {\tt Chv} and {\tt SubMtx} objects. Both objects need to be communicated between processes in the MPI implementation, the former during the factorization, the latter during the solve. Each has a workspace buffer that contains all the information needed to {\it regenerate} the object upon reception by another process. \item By and large, data objects have simple methods. A {\tt Graph} object does {\bf not} have methods to find a good bisector; this is a sufficiently sophisticated function that it should be implemented by an algorithm object. The major exception to this rule is that our {\tt FrontMtx} object {\it contains} the factorization data but also {\it performs} the factorization, forward and backsolves. In the future we intend to separate these two functionalities. For example, one can implement an alternative forward and backsolve by using methods to {\it access} the factor data stored in the {\tt FrontMtx} object. As a second example, massive changes to the storage format, e.g., in an out-of-core implementation, can be encapsulated in the access methods for the data, and any changes to the factorization or solve functions could be minimal. \end{itemize} Algorithm objects have these properties. \begin{itemize} \item Algorithm objects use data objects. Some data objects are created within an algorithm objects method; these are owned by the algorithm object and free'd by that object. Data objects that are passed to algorithm objects can be queried or {\it temporarily} changed. \item They do not destroy or free data objects that are passed to them. Any side effects on the data objects should be innocent, e.g., when a {\tt Graph} object is passed to the graph partitioning object ({\tt GPart}) or the multistage minimum degree object ({\tt MSMD}), on return the adjacency lists may not be in the input order, but they contain the values they had on input. \item Algorithm objects should support diagnostic, logfile and debug output. This convention is not entirely thought out or supported at present. The rationale is that an algorithm object should be able to respond to its environment to a greater degree than a data object. \end{itemize} \par Data and algorithm objects share two common properties. \begin{itemize} \item Each object has four basic methods: to allocate storage for an object, set the default fields of an object, clear the data fields of an object, and free the storage occupied and owned by an object. \item Ownership of data is very rigidly defined. In most cases, an object owns all data that is allocated inside one of its methods, and when this does not hold it is very plainly documented. For example, the bipartite graph object {\tt BPG} has a data field that points to a {\tt Graph} object. One of its initialization methods has a {\tt Graph} pointer in its calling sequence. The {\tt BPG} object then owns the {\tt Graph} object and when it is free'd or has its data cleared, the {\tt Graph} object is free'd by a call to its appropriate method. \end{itemize} \par By and large these conventions hold throughout the library. There are fuzzy areas and objects still ``under construction''. Here are two examples. \begin{itemize} \item We have an {\tt IIheap} object that maintains integer $\langle$ key, value $\rangle$ pairs in a priority heap. Normally we think of a heap as a data structure, but another perspective is that of a continuously running algorithm that supports insert, delete and identification of a minimum pair. \item Our {\tt BPG} bipartite graph object is a data object, but it has a method to find the Dulmage-Mendelsohn decomposition, a fairly involved algorithm used to refine a separator of a graph. At present, we are not willing to create a new algorithm object just to find the Dulmage-Mendelsohn decomposition, so we leave this method to the domain of the data object. The desired functionality, identifying minimal weight separators for a region of a graph, can be modeled using max flow techniques from network optimization. We also provide a {\tt BPG} method that finds this Dulmage-Mendelsohn decomposition by solving a max flow problem on a bipartite network. Both these methods have been superceded by the {\tt Network} object that contains a method to find a max flow and one or more min-cuts of a network (not necessarily bipartite). \end{itemize} \par The {\tt SPOOLES} software library is continuously evolving in an almost organic fashion. Growth and change are to be expected, and welcomed, but some discipline is required to keep the complexity, both code and human understanding, under control. The guidelines we have just presented have two purposes: to let the user and researcher get a better understanding of the design of the library, and to point out some conventions to be used in extending the library. \section{Software Design} \label{chapter:softwareDesign} \par The {\tt SPOOLES} library is written in the C language and uses object oriented design. There are some routines that manipulate native C data types such as vectors, but the vast bulk of the code is centered around objects, data objects and algorithm objects. By necessity, the implementation of an object is through the C {\tt struct} data type. We use the following naming convention --- a method (i.e., function) associated with an object of tdocumentation/ReferenceManual/spooles.bib010064000020550007177000001143400665023426100221430ustar00clevecompmath00000400000006@incollection{ash93-fan-both, author="C. Ashcraft", booktitle="Graph Theory and Sparse Matrix Computation", title="The fan-both family of column-based distributed {C}holesky factorization algorithms", pages="159-190", publisher="Springer-Verlag", year="1993"} @article{ash90-fan-in, author="C. Ashcraft and S. Eisenstat and J. W. H. Liu", title="A fan-in algorithm for distributed sparse numerical factorization", journal="SIAM J. Sci. Stat. Comput.", volume="11", year="1990"} @proceedings{geo87-fan-out, author="J. A. George and J. W. H. Liu and E. Ng", title="Communication reduction in parallel sparse {C}holesky on a hypercube", booktitle="Hypercube Multiprocessors 1987", editor="M. Heath", publisher="SIAM Press", year="1987"} @incollection{sch93-scalability, author="R. Schreiber", booktitle="Graph Theory and Sparse Matrix Computation", title="Scalability of sparse direct solvers", pages="191-211", publisher="Springer-Verlag", year="1993"} @book{hig96-asna, author="N. J. Higham", title="Accuracy and Stability of Numerical Algorithms", publisher="SIAM", year="1996"} @article{bent93-sort, author="J. L. Bentley and M. D. McIlroy", title="Engineering a sort function", journal="Software -- Practice and Experience", volume="23(11)", year="1993", pages="1249-1265"} @article{and90-random, author="S. L. Anderson", title="Random number generators on vector supercomputers and other advanced architectures", journal="SIAM Review", volume="32", year="1990", pages="221-251"} @misc{ash94-utah, author="C. Ashcraft and J. W. H. Liu", title="Generalized nested dissection: some recent progress", howpublished="Minisymposium presentation at the Fifth SIAM Conference on Applied Linear Algebra, Snowbird, Utah", year="June 18, 1994"} @misc{rot96-balance, AUTHOR="E. Rothberg", title="Exploring the tradeoff between imbalance and separator size in nested dissection ordering", howpublished="unpublished", year="1996"} @misc{ro95-hybrid, AUTHOR="E. Rothberg", title="Robust ordering of sparse matrices: a minimum degree, nested dissection hybrid", howpublished="unpublished", year="1995"} @misc{rothberg95, AUTHOR="E. Rothberg", howpublished="private communication", year="1995"} @conference{rot96-mindefIdaho, author="E. Rothberg", title="Ordering sparse matrices using approximate minimum local fill", booktitle="Second SIAM Conference on Sparse Matrices", year="1996", note="Conference presentation"} @article{rot98-mindef, author="E. Rothberg and S. C. Eisenstat", title="Node selection strategies for bottom-up sparse matrix ordering", journal= "SIAM J. Matrix Anal.", volume="19", year="1998", pages="682-695"} @techreport{hr96-msndtalk, author="B. Hendrickson and E. Rothberg", title="Improving the runtime and quality of nested dissection ordering", booktitle="Second SIAM Conference on Sparse Matrices", year="1996", note="Conference presentation"} @article{hr98-msndtalk, author="B. Hendrickson and E. Rothberg", title="Improving the runtime and quality of nested dissection ordering", journal= "SIAM J. Sci. Comput.", volume="20", year="1998", pages="468-489"} @TechReport{ karypis98metis, author = {G. Karypis and V. Kumar}, title = {METIS~4.0: Unstructured graph partitioning and sparse matrix ordering system}, institution = {Department of Computer Science, University of Minnesota}, year = {1998}, number = {}, note = {Available on the WWW at URL {\em http://www.cs.umn.edu/\~{}metis}} } @conference{ng96-mindefIdaho, author="E. Ng and P. Raghavan", title="Minimum deficiency ordering", booktitle="Second SIAM Conference on Sparse Matrices", year="1996", note="Conference presentation"} @article{gib76-profile, AUTHOR = {N. E. Gibbs and W. G. Poole Jr and P. K. Stockmeyer}, JOURNAL = {SIAM. J. Numer. Anal.}, KEY = {LLt band profile}, PAGES = {236-250}, TITLE = {An algorithm for reducing the bandwidth and profile of a sparse matrix}, VOLUME = {13}, YEAR = {1976} } @techreport{rag95-PCO, author="P. Raghavan", title="Parallel ordering using edge contraction", number="CS-95-293", institution="Dept. of Computer Science, The University of Tennessee", address="Knoxville, Tennessee", year="1995"} @techreport{ame94-amdTR, author="P. Amestoy and T. Davis and I. Duff", title="An approximate minimum degree ordering algorithm", number = "TR-94-039", institution="University of Florida", year="1994"} @article{ame96-amd, author="P. Amestoy and T. Davis and I. Duff", title="An approximate minimum degree ordering algorithm", journal="SIAM J. Matrix Anal. Appl.", volume="17", pages="886-905", year="1996"} @techreport{hr96-msnd, author="B. Hendrickson and E. Rothberg", title="Improving the runtime and quality of nested dissection ordering", institution="Sandia National Laboratories", year="1996"} @article{ash89-relaxed, author="C. Ashcraft and R. Grimes", title="The influence of relaxed supernode partitions on the multifrontal method", journal="ACM Trans. Math. Software", volume="15", year="1989", pages="291-309"} @techreport{ash95-pivoting, author="C. Ashcraft and R. G. Grimes and J. G. Lewis", title="Accurate symmetric indefinite linear equation solvers", number="ISSTECH-95-029", institution="Boeing Computer Services", year="1995"} @article{ash98-pivoting, author="C. Ashcraft and R. G. Grimes and J. G. Lewis", title="Accurate symmetric indefinite linear equation solvers", journal="SIAM J. Matrix Anal.", volume="20", year="1998", pages="513-561"} @article{ash98-multisection, author="C. Ashcraft and J. W. H. Liu", title="Robust ordering of sparse matrices using multisection", journal="SIAM J. Matrix Anal.", volume="19", year="1998", pages="816-832"} @techreport{ash96-multisection, author="C. Ashcraft and J. W. H. Liu", title="Robust ordering of sparse matrices using multisection", number="ISSTECH-96-002", institution="Boeing Information and Support Services", year="1996"} @techreport{ash95-DDSEP, author="C. Ashcraft and J. W. H. Liu", title="Using domain decompositions to find graph bisectors", number="ISSTECH-95-024", institution="Boeing Computer Services", year="1995"} @article{ash97-DDSEP, author="C. Ashcraft and J. W. H. Liu", title="Using domain decompositions to find graph bisectors", journal="BIT", volume="37", year="1997", pages="506-534"} @techreport{ash95-robust, author="C. Ashcraft and J. W. H. Liu", title="Robust ordering of sparse matrices using multisection", number="ISSTECH-96-002", institution="Boeing Computer Services", year="1996"} @techreport{ash96-maxflow, author="C. Ashcraft and J. W. H. Liu", title="Applications of the {D}ulmage-{M}endelsohn decomposition and network flow to graph bisection improvement", number="ISSTECH-96-017", institution="Boeing Computer Services", year="1996", note="Accepted for publication in {\it SIAM J. Matrix. Anal.}"} @article{ash98-maxflow, author="C. Ashcraft and J. W. H. Liu", title="Applications of the {D}ulmage-{M}endelsohn decomposition and network flow to graph bisection improvement", journal="SIAM J. Matrix Analysis and Applic.", volume="19", year="1998", pages="325-354"} @techreport{ash93-compressed-graphs-TR, author="C. Ashcraft", title="Compressed graphs and the minimum degree algorithm", number="BCSTECH-93-024", institution="Boeing Computer Services", year="1993"} @techreport{ash94-partition, author="C. Ashcraft and J. W. H. Liu", title="A partition improvement algorithm for generalized nested dissection", number="BCSTECH-94-020", institution="Boeing Computer Services", year="1994", note="Accepted for publication in {\it BIT}"} @article{ber90-mindeg, author="P. Berman and G. Schnitger", title="On the performance of the minimum degree ordering for {G}aussian elimination", journal="SIAM J. Matrix Analysis and Applic.", volume="11", year="1990", pages="83-88"} @article{bha93-localND, author="M. V. Bhat and W. G. Habashi and J. W. H. Liu and V. N. Nguyen and M. F. Peeters", title="A note on nested dissection for rectangular grids", journal="SIAM J. Matrix Analysis and Applic.", volume="14", year="1993", pages="253-258"} @phdthesis{dam92-compressed, author="A. C. Damhaug", title="Sparse Solution of Finite Element Equations", school="The Norwegian Institute of Technology", year="1992"} @article{duf83-multifrontal, author="I. Duff and J. Reid", title="The multifrontal solution of indefinite sparse symmetric linear equations", journal="ACM Trans. Math. Software", volume="6", year="1983", pages="302-325"} @inproceedings{eis76-elementModel, author="S. C. Eisenstat and M. H. Schultz and A. H. Sherman", title="Applications of an element model for {G}aussian elimination", booktitle="Sparse Matrix Computations", pages="85-96", publisher="Academic Press", year="1976", editor="J. R. Bunch and D. J. Rose"} @inproceedings{fid82-partition, author="C. M. Fiduccia and R. M. Mattheyses", title="A linear-time heuristic for improving network partition", booktitle="ACM IEEE Proc. 19th Design Automation Conference, Las Vegas, Nevada", year="1982", pages="175-181"} @article{geo80-1way, author="J. A. George", title="An automatic one-way dissection algorithm for irregular finite element problems", journal="SIAM J. Numer. Anal.", volume="17", year="1980", pages="740-751"} @article{sparsematlab, author="J. Gilbert and C. Moler and R. Schreiber", title="Sparse matrices in {MATLAB}: design and implementation", journal="SIAM J. Matrix Analysis and Applic.", volume="13", year="1992", pages="335-356"} @techreport{gup96-WGPP, author="A. Gupta", title="{WGPP}: {W}atson {G}raph {P}artitioning and sparse matrix ordering {P}ackage", number="Users Manual", institution="IBM T.J. Watson Research Center", address="New York", year="1996"} @techreport{hea92-dissection, author="M.T. Heath and P. Raghavan", title="A Cartesian nested dissection algorithm", number="UIUCDCS-R-92-1772", institution="Dept of Computer Science, University of Illinois", address="Urbana, IL", year="1992"} @techreport{hen92-partition, author="B. Hendrickson and R. Leland", title="An improved spectral graph partitioning algorithm for mapping parallel computations", number="SAND92-1460", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1992"} @techreport{hen93-partition, author="B. Hendrickson and R. Leland", title="Multidimensional spectral load balancing", number="SAND93-074", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @article{ker70-partition, author="B. W. Kernighan and S. Lin", title="An efficient heuristic procedure for partitioning graphs", journal="Bell System Technical Journal", volume="49", year="1970", pages="291-307"} @inproceedings{lei89-fidmat, author="C. E. Leiserson and J. G. Lewis", title="Orderings for parallel sparse symmetric factorization", booktitle="Parallel Processing for Scientific Computing", year="1989", pages="27-31"} @article{lip79-separators, author="R. J. Lipton and R. E. Tarjan", title="A separator theorem for planar graphs", journal="SIAM J. Applied Math", volume="36", year="1979", pages="177-189"} @article{liu89-separators, author="J. W. H. Liu", title="A graph partitioning algorithm by node separators", journal="ACM Trans. on Math. Software", volume="15", year="1989", pages="198-219"} @article{liu85-mfstorage, author="J. W. H. Liu", title="On the storage requirement in the out-of-core multifrontal method for sparse factorization", journal="ACM Trans. on Math. Software", volume="12", year="1986", pages="249-264"} @article{liu85-mmd, author="J. W. H. Liu", title="Modification of the minimum degree algorithm by multiple elimination", journal="ACM Trans. on Math. Software", volume="11", year="1985", pages="141-153"} @article{liu89-mindeg, author="J. W. H. Liu", title="On the minimum degree ordering with constraints", journal="SIAM J. Sci. Stat. Comput.", volume="10", year="1989", pages="1136-1145"} @article{liu90-etree, author="J. W. H. Liu", title="The role of elimination trees in sparse factorization", journal="SIAM J. Matrix Analysis and Applic.", volume="11", year="1990", pages="134-172"} @article{liu91-generalizedEnvelope, author="J. W. H. Liu", title="A generalized envelope method for sparse factorization by rows", journal="ACM Trans. on Math. Software", volume="17", year="1991", pages="112-129"} @article{mar57, author="H. M. Markowitz", title="The elimination form of the inverse and its application to linear programming", journal="Management Sci.", volume="3", year="1957", pages="255-269"} @mastersthesis{ng79-master, author="E. Ng", title="On one-way dissection schemes", school="Dept of Computer Science, University of Waterloo", address="Waterloo, Ontario", year="1979"} @techreport{rag93-separators, author="P. Raghavan", title="Line and plane separators", number="UIUCDCS-R-93-1794", institution="Dept of Computer Science, University of Illinois", address="Urbana, IL", year="1993"} @inproceedings{ros72-elimination, author="D. J. Rose", title="A graph-theoretic study of the numerical solution of sparse positive definite systems of linear equations", booktitle="Graph Theory and Computing", publisher="Academic Press", editor="R. Read", year="1972", pages="183-217"} @article{ros70-elimination, author="D. J. Rose", title="Triangulated graphs and the elimination process", journal="J. Math. Anal. & Appl.", volume="32", year="1970", pages="597-609"} @techreport{ten91-separators, author="S.H. Teng", title="Points, Spheres, and Separators", number="CMU-CS-91-184", institution="School of Computer Science, Carnegie Mellon University", address="Pittsburgh, PA", year="1991"} @article{tin67-order, author="W. F. Tinney and J. W. Walker", title="Direct solutions of sparse network equations by optimally ordered triangular factorization", journal="J Proc. IEEE", volume="55", year="1967", pages="1801-1809"} @book{aho83, author="A. V. Aho and J. E. Hopcroft and J. D. Ullman", title="Data Structures and Algorithms", publisher="Addison-Wesley", address="Reading, MA", year="1983"} @book{duf87-book, author="I. S. Duff and A. M. Erisman and J. K. Reid", title="Direct Methods for Sparse Matrices", publisher="Oxford University Press", address="London", year="1987"} @book{geo81-book, author="J. A. George and J. W. H. Liu", title="Computer Solution of Large Sparse Positive Definite Systems", publisher="Prentice-Hall", address="Englewood Cliffs, NJ", year="1981"} @article{ash87-progress, AUTHOR = {C. Ashcraft and R. Grimes and J. Lewis and B. Peyton and H. Simon}, JOURNAL = {Intern. J. of Supercomputer Applications}, KEY = {LLt vector}, PAGES = {10-30}, TITLE = {Progress in sparse matrix methods for large sparse linear systems on vector supercomputers}, VOLUME = {1}, YEAR = {1987} } @techreport{ash90-partition, author="C. Ashcraft", title="The domain/segment partition for the factorization of sparse symmetric positive definite matrices", number="ECA-TR-148", institution="Boeing Computer Services", address="Seattle, WA", year="1990"} @article{ash95-compressed-graphs, author="C. Ashcraft", title="Compressed graphs and the minimum degree algorithm", journal="SIAM J. Sci. Comput.", pages = "1404-1411", volume = 16, year="1995"} @techreport{AELS90-comparison, author="C. Ashcraft and S. Eisenstat and J. Liu and A. Sherman", title="A comparison of three distributed column based distributed factorization schemes", number="Technical Report YALEU/DCS/RR-810", institution="Department of Computer Science, Yale University", year="1990"} @inproceedings{ash90-lookahead, author="C. Ashcraft and S. C. Eisenstat and J. W. H. Liu and B. W. Peyton and A. H. Sherman", title="A compute-ahead fan-in scheme for parallel sparse matrix factorization", booktitle="Fourth Canadian Supercomputing Symposium (1990)", editor="D. Pelletier", year="June, 1990", pages="351-361"} @inproceedings{ash94-multisection, author="C. Ashcraft and J. W. H. Liu", title="Generalized nested dissection: some recent progress", booktitle="Fifth SIAM Conference on Applied Linear Algebra", address="Snowbird, Utah", year="June 18, 1994"} @inproceedings{bar93-partition, author="S. T. Barnard and H. D. Simon", title="A fast multilevel implementation of recursive spectral bisection for partitioning unstructured problems", booktitle="Proceedings of the Sixth SIAM Conference on Parallel Processing for Scientific Computing", year="1993", pages="711-718"} @inproceedings{bar95-partition, author="S. T. Barnard and H. D. Simon", title="A parallel implementation of multilevel recursive spectral bisection for applications in adaptive unstructured meshes", booktitle="Proceedings of the seventh SIAM Conference on Parallel Processing for Scientific Computing", year="1995", pages="627-632"} @article{bui92-partition, author="T. Bui and C. Jones", title="Finding good approximate vertex and edge partitions is {NP}-hard", journal="Information Processing Letters", volume="42", year="1992", pages="153-159"} @inproceedings{bui93-partition, author="T. Bui and C. Jones", title="A heuristic for reducing fill-in in sparse matrix factorization", booktitle="Proceedings of Sixth SIAM Conference on Parallel Processing ", year="1993", pages="445-452"} @article{geo73-nested, author="J. A. George", title="Nested dissection of a regular finite element mesh", journal="SIAM J. Numer. Anal.", volume="10", year="1973", pages="345-363"} @article{geo89-mindeg, author="J.A. George and J. W. H. Liu", title="The evolution of the minimum degree ordering algorithm", journal="SIAM Review", volume="31", year="1989", pages="1-19"} @techreport{goe95-partition, author="T. Goehring and Y. Saad", title="Heuristic algorithms for automatic graph partitioning", number="", institution="Computer Science Department, University of Minnesota", address="Minnesota", year="1995"} @article{hal35, author = "P. Hall", title = "On representatives of subsets", journal = "J. London Math. Society", volume = "10", year = "1935", pages = "26-30"} @article{Harwell-Boeing-Matrices, author = "I.S. Duff and R.G. Grimes and J.G. Lewis", title = "Sparse matrix test problems", journal="ACM Trans. on Math. Software", volume = "15", year = "1989", pages = "1-14"} @article{dul58, author = "A.L. Dulmage and N.S. Mendelsohn", title = "Coverings of bipartite graphs", journal="Can. J. Math", volume = "10", year = "1958", pages = "517-534"} @techreport{sparspak80, author="J. A. George and J. W. H. Liu and E. G. Ng", title="User's guide for {SPARSPAK}: {W}aterloo sparse linear equations package", number = "Tech. Rep. CS78-30(revised)", institution = "Dept. of Computer Sciences, Univ. of Waterloo", address="Waterloo, Ontario, Canada", year = "1980"} @techreport{hen93-chaco, author="B. Hendrickson and R. Leland", title="The {C}haco user's guide", number="SAND93-2339", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @techreport{hen93-partition, author="B. Hendrickson and R. Leland", title="A multilevel algorithm for partitioning graphs", number="SAND93-1301", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @techreport{hen93-spectral, author="B. Hendrickson and R. Leland", title="Multidimensional spectral load balancing", number="SAND93-074", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @techreport{kar95-kway, author="G. Karypis and V. Kumar", title="Multilevel $k$-way partitioning scheme for irregular graphs", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} % number="Technical Report", @techreport{kar95-multilevel, author="G. Karypis and V. Kumar", title="A fast and high quality multilevel scheme for partitioning irregular graphs", number="TR 95-035", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} @techreport{kar95-metis, author="G. Karypis and V. Kumar", title="{METIS}: Unstructured graph partitioning and sparse matrix ordering system", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} % number="TR 95-???", @techreport{kar95-partition, author="G. Karypis and V. Kumar", title="Analysis of multilevel graph partitioning", number="TR 95-037", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} @inproceedings{kar95, author="G. Karypis and V. Kumar", title="Multilevel graph partition and sparse matrix ordering", booktitle="Intl. Conf. on Parallel Processing", year="1995"} @article{lip79, author="R. J. Lipton and R. E. Tarjan", title="A separator theorem for planar graphs", journal="SIAM J. Applied Math", volume="36", year="1979", pages="177-189"} @techreport{mai94-partition, author="H.S. Maini and K.G. Mehrotra and S. Ranka", title="Genetic algorithms for graph partitioning and incremental graph partitioning", number="Technical report", institution="Center for Science and Technology, Syracuse University", address="Synracuse, N.Y.", year="1994"} @article{pot90-triangular, author="A. Pothen and C. Fan", title="Computing the block triangular form of a sparse matrix", journal="ACM Trans. on Math. Software", volume="16", year="1990", pages="303-324"} @article{pot90-partition, author="A. Pothen and H. Simon and K.P. Liou", title="Partitioning sparse matrices with eigenvectors of graphs", journal="SIAM J. Matrix Analysis and Applic.", volume="11", year="1990", pages="430-452"} @book{aho83, author="A. V. Aho and J. E. Hopcroft and J. D. Ullman", title="Data Structures and Algorithms", publisher="Addison-Wesley", address="Reading, MA", year="1983"} @book{ull84-vlsi, author="J. D. Ullman", title="Computational Aspects of VLSI", publisher="Computer Science Press", address="Rockville, Md", year="1984"} @book{duf87-book, author="I. S. Duff and A. M. Erisman and J. K. Reid", title="Direct Methods for Sparse Matrices", publisher="Oxford University Press", address="London", year="1987"} @book{geo81-book, author="J. A. George and J. W. H. Liu", title="Computer Solution of Large Sparse Positive Definite Systems", publisher="Prentice-Hall", address="Englewood Cliffs, NJ", year="1981"} @book{zzzz99-book, author="J. A. George and J. W. H. Liu", title="Computer Solution of Large Sparse Positive Definite Systems", publisher="Prentice-Hall", address="Englewood Cliffs, NJ", year="1981"} @article{arn85, author="S. Arnborg", title="Efficient algorithms for combinatorial problems on graphs with bounded decomposability - a survey", journal="BIT", volume="25", year="1985", pages="2-23"} @techreport{bar81, author="E. R. Barnes", title="An algorithm for partitioning the nodes of a graph", number="RC8690", institution="IBM Thomas J. Watson Research Center", address="Yorktown Heights, New York", year="1981"} @inproceedings{bar85, author="E. R. Barnes", title="Partitioning the nodes of a graph", booktitle="Graph Theory with Applications to Algorithms and Computer Science", editor="Y. Alavi and G. Chartrand and D. Lick and C. Wall and L. Lesuiak", publisher="John Wiley \& Sons Inc.", address="New York", year="1985", pages="57-72"} @article{bha84, author="S. N. Bhatt and F. T. Leighton", title="A framework for solving {VLSI} graph layout problems", journal="Journal of Computer \& Systems Sciences", volume="28", year="1984", pages=""} @inproceedings{bre77, author="M. A. Breuer", title="A class of min-cut placement algorithms", booktitle="Proc. 14th Design Automation Conference", year="1977", pages="284-290"} @inproceedings{bui84, author="S. N. Bui and S. Chaudhuri and T. Leighton and M. Sipser", title="Graph bisection algorithms with good average case behavior", booktitle="Proceedings of the 25th Annual Symposium of Foundations of Computer Science", year="1984", pages="181-192"} @article{dji81, author="H. N. Djidjev", title="A separator theorem", journal="Comptes rendus de l' Academie bulgare des Sciences", volume="34", year="1981", pages="643-645"} @article{dji82-linear, author="H. N. Djidjev", title="A linear algorithm for partitioning graphs", journal="Comptes rendus de l' Academie bulgare des Sciences", volume="35", year="1982", pages="1053-1056"} @article{dji82-planar, author="H. N. Djidjev", title="On the problem of partitioning planar graphs", journal="SIAM J. Alg. \& Disc. Meth.", volume="3", year="1982", pages="229-240"} @article{don72, author="W. E. Donath and A. J. Hoffman", title="Algorithms for partitioning of graphs and computer logic based on eigenvectors of connection matrices", journal="IBM Technical Disclosure Bulletin", volume="15", year="1972", pages="938-944"} @article{don73, author="W. E. Donath and A. J. Hoffman", title="Lower bounds for the partitioning of graphs", journal="IBM J. Res. Develop.", volume="17", year="1973", pages="420-425"} @article{fie73, author="M. Fiedler", title="Algebraic connectivity of graphs", journal="Czechoslovak Math J.", volume="23", year="1973", pages="298-305"} @book{fre86, author="G. N. Fredrickson and R. Janardan", title="Separator-based strategies for efficient message routing", booktitle="27th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1986", pages="428-437"} @book{gaz87, author="H. Gazit and G. L. Miller", title="A parallel algorithm for finding a separator in planar graphs", booktitle="28th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1987", pages="238-248"} @techreport{gil80, author="J. R. Gilbert", title="Graph separator theorems and sparse {G}aussian elimination", number="Ph.D. Thesis", institution="DCS, Stanford University", year="1980"} @article{gil84-genus, author="J. R. Gilbert and J. P. Hutchinson and R. E. Tarjan", title="A separator theorem for graphs of bounded genus", journal="J. of Algorithms", volume="5", year="1984", pages="391-407"} @article{gil84-chordal, author="J. R. Gilbert and D. J. Rose and A. Edenbrandt", title="A separator theorem for chordal graphs", journal="SIAM J. Alg. \& Disc. Meth.", volume="5", year="1984", pages="306-313"} @inproceedings{gol83, author="M. K. Goldberg and M. Burstein", title="Heuristic improvement technique for bisection of {VLSI} networks", booktitle="Proc. IEEE International Conf. on Computer Design", address="Port Chester, New York", year="1983", pages="122-125"} @techreport{gol87, author="M. K. Goldberg and S. Lath and J. W. Roberts", title="Heuristics for the graph bisection problem", number="Report", institution="Rensselaer Polytechnic Institute", year="1987"} @techreport{hen92, author="B. Hendrickson and R. Leland", title="An improved spectral graph partitioning algorithm for mapping parallel computations", number="SAND92-1460", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1992"} @techreport{hen93, author="B. Hendrickson and R. Leland", title="Multidimensional spectral load balancing", number="SAND93-074", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @article{hu81, author="T. C. Hu and M. T. Shing", title="An O(n) algorithm to find a near-optimum partition", journal="Journal of Algorithms", volume="2", year="1981", pages="122-138"} @article{hu85, author="T. C. Hu and M. T. Shing", title="A decomposition algorithm for circuit routing", journal="Math. Programming Study", volume="24", year="1985", pages="87-103"} @article{hu86, author="T. C. Hu and M. T. Shing", title="A decomposition algorithm for multi-terminal network flows", journal="J. Discrete Applied Math.", volume="13", year="1986", pages="165-181"} @article{joh88, author="D. S. Johnson and C. R. Aragon and L. A. McGeoch and C. Schevon", title="Optimization by simulated annealing: an experimental evaluation", journal="Operations Research", note="((submitted))", year="1988"} @article{kan91, author="A. Kanevsky and V. Ramachandran", title="Improved algorithms for graph four-connectivity", journal="J. of Computer Science and Systems", volume="42", year="1991", pages="288-306"} @article{kan9x, author="A. Kanevsky", title="Finding all minimum size vertex sets in a graph", journal="J. of Networks", year="199x"} @inproceedings{kan90, author="A. Kanevsky", title="On the number of minimum size separating vertex sets of a graph and how to find all of them", booktitle="First Annual ACM-SIAM Symposium on Discrete Algorithms (SODA '90)", year="January 22-24,1990", pages="411-421"} @article{kao90, author="M. Kao and F. Wan", title="Not all planar digraphs have small cycle separators", journal="Information Processing Letters", year="1990"} @techreport{ker69, author="B. W. Kernighan", title="Some graph partitioning problems related to program segmentation", number="Ph.D. Thesis", institution="Princeton University", year="1969"} @article{ker70, author="B. W. Kernighan and S. Lin", title="An efficient heuristic procedure for partitioning graphs", journal="Bell System Technical Journal", volume="49", year="1970", pages="291-307"} @article{kir83, author="S. Kirkpatrick and C. D. Gelatt Jr. and M. P. Vecchi", title="Optimization by simulated annealing", journal="Science", volume="220", year="1983", pages="671-680"} @article{kom85, author="J. Komlos and M. T. Shing", title="Probabilistic partitioning algorithms for the rectilinear Steiner problem", journal="Networks", volume="15", year="1985", pages="413-423"} @article{kri84, author="B. Krishnamurthy", title="An improved min-cut algorithm for partitioning {VLSI} networks", journal="IEEE Trans. on Computers", volume="C-33", year="1984", pages="438-446"} @article{kri87, author="B. Krishnamurthy", title="Constructing test cases for partitioning heuristics", journal="IEEE Trans. on Computers", volume="C-36", year="198", pages="1112-1114"} @inproceedings{lei82, author="F. T. Leighton", title="A layout strategy for {VLSI} which is provably good", booktitle="Proceedings of the 14th Annual ACM Symposium on Theory of Computing", year="1982", pages="85-98"} @book{lei80, author="C. Leiserson", title="Area-efficient graph layout (for vlsi)", booktitle="21st Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1980", pages="270-281"} @article{lin77, author="T. D. Lin and R. S. H. Mah", title="Hierarchical partition -- a new optimal pivoting algorithm", journal="Math. Programming", volume="12", year="1977", pages="260-278"} @article{lip80, author="R. J. Lipton and R. E. Tarjan", title="Applications of a planar separator theorem", journal="SICOMP", volume="9", year="1980", pages="615-627"} @techreport{mac78, author="R. M. Macgregor", title="On partitioning a graph: a theoretical and empirical study", number="UCB/ERL M78/14 (Ph.D. Thesis)", institution="Standford University", year="1978"} @inproceedings{mil84, author="G. L. Miller", title="Finding small simple cycle separators for 2-connected planar graphs", booktitle="Proceedings of the 16th Annual ACM Symposium on Theory of Computing", year="1984", pages="376-382"} @techreport{moo88, author="D. Moore", title="A round-robin parallel partitioning algorithm", number="TR 88-916", institution="DCS, Cornell University", year="1988"} @article{pai87, author="R. Paige and R. E. Tarjan", title="Three partition refinement algorithm", journal="SICOMP", volume="16", year="1987", pages="973-989"} @article{pow88, author="D. Powers", title="Graph partitioning by eigenvectors", journal="Lin. Alg. Appl.", volume="101", year="1988", pages="121-133"} @book{rao87, author="S. Rao", title="Finding near optimal separators in planar graphs", booktitle="28th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1987", pages="225-237"} @article{rav87, author="S. Ravi and H. Hunt III", title="An application of the planar separator theorem to counting problem", journal="Inform. Process. Letters", volume="25", year="1987", pages="317-322"} @techreport{ren90, author="F. Rendl and H. Wolkowicz", title="A projection technique for partitioning the nodes of a graph", number="CORR 90-20", institution="University of Waterloo", address="Waterloo, Ontario", year="1990"} @inproceedings{san76, author="A. Sangiovanni-Vincentelli", title="An optimization problem arising from tearing methods", booktitle="Sparse Matrix Computations", editor="J.R. Bunch and D.J. Rose", publisher="Academic Press", year="1976", pages="97-110"} @inproceedings{sch79, author="D. G. Schweikert and B. W. Kernighan", title="A proper model for the partitioning of electrical circuits", booktitle="Proc. 9th Design Automation Workshop", year="1979", pages="57-62"} @article{sen92, author="A. Sen and H. Deng and S. Guha", title="On a graph partition problem with application to vlsi layout", journal="Information Processing Letters", year="1992", volume="43", pages="87-94"} @techreport{she87, author="T. J. Sheffler", title="A graph separator theorem and its application to {G}aussian elimination to optimize {B}oolean expression for parallel evaluation", number="CMU-CS-87-123", institution="DCS, Carnegie-Mellon University", year="1987"} @inproceedings{shi80, author="H. Shiraishi and F. Hirose", title="Efficient placement and routing for masterslice {LSI}", booktitle="Proc. 17th Design Automation Conference", year="1980", pages="458-464"} @article{sua88, author="P. Suaris and G. Kedem", title="An algorithm for quadrisection and its application to standard cell placement", journal="IEEE Trans. Circuits and Systems", volume="35", year="1988", pages="294-303"} @article{tar??, author="R. E. Tarjan", title="Decomposition by clique separators", journal="Discrete Math", year="to appear"} @article{ven87, author="S. Venkatesan", title="Improved constants for some separator theorems", journal="J. Algorithms", volume="8", year="1987", pages="572-578"} @article{wan91, author="F. Wan", title="A linear-processor algorithm for finding small cycle separators on undirected planar graphs", journal="SICOMP", year="1991?"} @article{whi81, author="S. H. Whitesides", title="An algorithm for finding clique cutsets", journal="Inf. Proc. Letters", volume="12", year="1981", pages="31-32"} @incollection{matrixmarket97, author="R. F. Boisvert and R. Pozo and K. Remington and R. F. Barrett and J. J. Dongarra", title="Matrix {M}arket: a web resource for test matrix collections", booktitle="The Quality of Numerical Software: Assessment and Enhancement", publisher="Chapman and Hall, London", year="1997", editor="R. F. Boisvert", pages="125-137"} techreport{gil80, author="J. R. Gilbert", title="Graph separator theorems and sparse {G}aussian elimination", number="Ph.D. Thesis", institution="DCS, Stanford University", year="1980"} @article{gil84-genus, author="J. R. Gilbert and J. P. Hutchinson and R.documentation/ReferenceManual/temp.aux010064400020550007177000000015120664721267100214740ustar00clevecompmath00000400000006\relax \bibstyle{plain} \@writefile{toc}{\string\contentsline\space {part}{\uppercase {i}\string\phspace\space {1em}Introduction}{1}} \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}Introduction}{3}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Software Design}{5}} \newlabel{chapter:softwareDesign}{{1.1}{5}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Changes from Release 1.0}{7}} \newlabel{section:intro:changes}{{1.2}{7}} \citation{hr96-msndtalk} \citation{kar95-metis} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Future Developments}{8}} \newlabel{section:intro:future}{{1.3}{8}} documentation/ReferenceManual/temp.log010064400020550007177000000030240664721267100214600ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 19 JUN 1998 10:07 **temp (temp.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) (/usr/local/lib/texmf/tex/generic/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen100 \p@intvaluey=\dimen101 psfig/tex 1.10-dvips ) (temp.aux) [0 ] [0] (partIntro.tex [1 ] [2] Chapter 1. [3 ] (softwareDesign.tex [4] [5] [6]) [7] LaTeX Warning: Citation `hr96-msndtalk' on page 8 undefined on input line 147. LaTeX Warning: Citation `kar95-metis' on page 8 undefined on input line 148. [8]) [9] (temp.aux) ) Here is how much of TeX's memory you used: 415 strings out of 11977 4158 string characters out of 87269 38617 words of memory out of 262141 2357 multiletter control sequences out of 9500 19913 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 16i,9n,17p,149b,272s stack positions out of 300i,40n,60p,3000b,4000s Output written on temp.dvi (11 pages, 30700 bytes). documentation/ReferenceManual/temp.tex010064400020550007177000000107020664721267100215000ustar00clevecompmath00000400000006% % main TeX file % \documentstyle[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt % \makeindex \input psfig \newcommand{\bfi}{{\bf i}} \newcommand{\bfj}{{\bf j}} \newcommand{\bnd}[1]{{\partial{#1}}} \pagestyle{myheadings} % \markboth % {\quad \hrulefill \quad {\bf SPOOLES} : {\it DRAFT} \today \quad \hrulefill} % {\quad \hrulefill \quad {\bf SPOOLES} : {\it DRAFT} \quad \today \hrulefill} \markboth {\quad \hrulefill \quad {\bf SPOOLES 2.0} : \today \quad \hrulefill} {\quad \hrulefill \quad {\bf SPOOLES 2.0} : \quad \today \hrulefill} \begin{document} \bibliographystyle{plain} \title{ The Reference Manual for {\bf SPOOLES}, Release 2.0: \break An Object Oriented Software Library for Solving \break Sparse Linear Systems of Equations} \author{ Cleve Ashcraft\thanks{ Boeing Shared Services Group, P. O. Box 24346, Mail Stop 7L-22, Seattle, Washington 98124, {\tt cleve.ashcraft@boeing.com}. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} \and David K. Wah\thanks{ Boeing Shared Services Group, P. O. Box 24346, Mail Stop 7L-22, Seattle, Washington 98124, {\tt david.wah@pss.boeing.com}. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} % \and % Joseph W.H. Liu\thanks{ % Department of Computer Science, York % University, North York, Ontario, Canada M3J 1P3. % This research was supported in part by the % Natural Sciences and Engineering Research Council of Canada % under grant A5509 % and in part by the ARPA % Contract DABT63-95-C-0122.} } \date{\today} \maketitle \begin{abstract} Solving sparse linear systems of equations is a common and important application of a multitude of scientific and engineering applications. The {\bf SPOOLES} software package\footnote{ {\bf SPOOLES} is an acronym for {\bf SP}arse {\bf O}bject-{\bf O}riented {\bf L}inear {\bf E}quations {\bf S}olver. } provides this functionality with a collection of software objects. The first step to solving a sparse linear system is to find a good low-fill ordering of the rows and columns. The library contains several ways to perform this operation: minimum degree, generalized nested dissection, and multisection. The second step is to factor the matrix as a product of triangular and diagonal matrices. The library supports pivoting for numerical stability (when required), approximation techniques to reduce the storage for and work to compute the matrix factors, and the computations are based on BLAS3 numerical kernels to take advantage of high performance computing architectures. The third step is to solve the linear system using the computed factors. \par The library is written in ANSI C using object oriented design. Good design and efficient code sometimes conflict; generally we have preferred to cater to design. For large sparse matrices the serial code outperforms its FORTRAN predecessors, the reverse holds for moderate sized matrices or those that do not have good block structure. The present release of the library contains a serial factorization and solve, a multithreaded version using the Solaris and Posix thread packages, and an MPI version. There is considerable code overlap between the serial, threaded and MPI versions. \par This release of the package is totally within the public domain; there are absolutely no licensing restrictions as with other software packages. The development of this software was funded by ARPA\footnote{ ARPA Contract DABT63-95-C-0122.} with the express purpose that others (academic, government, industrial and commercial) could easily incorporate the data structures and algorithms into application codes. All we ask is an acknowledgement in derivative codes and any publications from research that uses this software. And, we hope that any improvements will be communicated to others. \end{abstract} \par % \input preface.tex % \tableofcontents % \listoffigures \input partIntro.tex % \input partUtil.tex % \input partOrder.tex % \input partNumeric.tex % \input partMisc.tex % \input partMPI.tex % \bibliography{spooles} % \input main.ind \end{document} documentation/AllInOne/004275500020550007177000000000000665314606500164235ustar00clevecompmath00000400000006documentation/AllInOne/LU_MPI.tex010064400020550007177000000353540665235221500201720ustar00clevecompmath00000400000006\par \vfill \eject \section{MPI Solution of $A X = Y$ using an $LU$ factorization} \label{section:LU-MPI} \par Unlike the serial and multithreaded environments where the data structures are global, existing under one address space, in the MPI environment, data is local, each process or processor has its own distinct address space. The MPI step-by-step process to solve a linear system is exactly the same as the multithreaded case, with the additional trouble that the data structures are distributed and need to be re-distributed as needed. \par The ownership of the factor matrices during the factorization and solves is exactly the same as for the multithreaded case -- the map from fronts to processors and map from submatrices to processors are identical to their counterparts in the multithreaded program. What is different is the explicit message passing of data structures between processors. Luckily, most of this is hidden to the user code. \par We will now begin to work our way through the program found in Section~\ref{section:LU-MPI-driver} to illustrate the use of {\bf SPOOLES} to solve a system of linear equations in the MPI environment. \par \subsection{Reading the input parameters} \label{subsection:MPI:input-data} \par This step is identical to the serial code, as described in Section~\ref{subsection:serial:input-data}, with the exception that the file names for $A$ and $Y$ are hardcoded in the driver, and so are not part of the input parameters. \par \subsection{Communicating the data for the problem} \label{subsection:MPI:communicating-data} \par This step is identical to the serial code, as described in Section~\ref{subsection:serial:communicating-data} In the serial and multithreaded codes, the entire matrix $A$ was read in from one file and placed into one {\tt InpMtx} object. In the MPI environment, this need not be the case that one processor holds the entire matrix $A$. (In fact, $A$ must be distributed across processors during the factorization.) \par Each processor opens a matrix file, (possibly) reads in matrix entries, and creates its {\it local} {\tt InpMtx} object that holds the matrix entries it has read in. We have hardcoded the file names: processor $q$ reads its matrix entries from file {\tt matrix.}$q${\tt .input} and its right hand side entries from file {\tt rhs.}$q${\tt .input}. The file formats are the same as for the serial and multithreaded drivers. \par The entries needed not be partitioned over the files. For example, each processor could read in entries for disjoint sets of finite elements. Naturally some degrees of freedom will have support on elements that are found on different processors. When the entries in $A$ and $Y$ are mapped to processors, an assembly of the matrix entries will be done automatically. \par It could be the case that the matrix $A$ and right hand side $Y$ are read in by one processor. (This was the approach we took with the {\tt LinSol} wrapper objects.) There still need to be input files for the other processors with zeroes on their first (and only) line, to specify that no entries are to be read. \par \subsection{Reordering the linear system} \label{subsection:MPI:reordering} \par The first part is very similar to the serial code, as described in Section~\ref{subsection:serial:reordering}. \begin{verbatim} graph = Graph_new() ; adjIVL = InpMtx_MPI_fullAdjacency(mtxA, stats, msglvl, msgFile, MPI_COMM_WORLD) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; frontETree = orderViaMMD(graph, seed + myid, msglvl, msgFile) ; \end{verbatim} While the data and computations are distributed across the processors, the ordering process is not. Therefore we need a global graph on each processor. Since the matrix $A$ is distributed across the processors, we use the distributed {\tt InpMtx\_MPI\_fullAdjacency()} method to construct the {\tt IVL} object of the graph of $A + A^T$. \par At this point, each processor has computed its own minimum degree ordering and created a front tree object. The orderings will likely be different, because each processors input a different random number seed to the ordering method. Only one ordering can be used for the factorization, so the processors collectively determine which of the orderings is best, which is then broadcast to all the processors, as the code fragment below illustrates. \begin{verbatim} opcounts = DVinit(nproc, 0.0) ; opcounts[myid] = ETree_nFactorOps(frontETree, type, symmetryflag) ; MPI_Allgather((void *) &opcounts[myid], 1, MPI_DOUBLE, (void *) opcounts, 1, MPI_DOUBLE, MPI_COMM_WORLD) ; minops = DVmin(nproc, opcounts, &root) ; DVfree(opcounts) ; frontETree = ETree_MPI_Bcast(frontETree, root, msglvl, msgFile, MPI_COMM_WORLD) ; \end{verbatim} \par \subsection{Non-numeric work} \label{subsection:MPI:non-numeric} \par Once the front tree is replicated across the processors, we obtain the permutation vectors and permute the vertices in the front tree. The local matrices for $A$ and $Y$ are also permuted. These steps are identical to the serial and multithreaded drivers, except the fact local instead of global $A$ and $Y$ matrices are permuted. \begin{verbatim} oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; ETree_permuteVertices(frontETree, oldToNewIV) ; InpMtx_permute(mtxA, IV_entries(oldToNewIV), IV_entries(oldToNewIV)) ; if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; DenseMtx_permuteRows(mtxY, oldToNewIV) ; \end{verbatim} \par The next step is to obtain the map from fronts to processors, just as was done in the multithreaded driver. In addition, we need a map from vertices to processors to be able to distribute the matrix $A$ and right hand side $Y$ as necessary. Since we have the map from vertices to fronts inside the front tree object, the vertex map is easy to determine. \begin{verbatim} cutoff = 1./(2*nproc) ; cumopsDV = DV_new() ; DV_init(cumopsDV, nproc, NULL) ; ownersIV = ETree_ddMap(frontETree, type, symmetryflag, cumopsDV, cutoff) ; DV_free(cumopsDV) ; vtxmapIV = IV_new() ; IV_init(vtxmapIV, neqns, NULL) ; IVgather(neqns, IV_entries(vtxmapIV), IV_entries(ownersIV), ETree_vtxToFront(frontETree)) ; \end{verbatim} At this point we are ready to assemble and distribute the entries of $A$ and $Y$. \begin{verbatim} firsttag = 0 ; newA = InpMtx_MPI_split(mtxA, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; InpMtx_free(mtxA) ; mtxA = newA ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; newY = DenseMtx_MPI_splitByRows(mtxY, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; DenseMtx_free(mtxY) ; mtxY = newY ; \end{verbatim} The {\tt InpMtx\_MPI\_split()} method assembles and redistributes the matrix entries by the vectors of the local matrix. Recall above that the coordinate type was set to chevrons, as is needed for the assembly of the entries into the front matrices. The method returns a new {\tt InpMtx} object that contains the part of $A$ that is needed by the processor. The old {\tt InpMtx} object is free'd and the new one takes its place. \par Now we are ready to compute the symbolic factorization, but it too much be done in a distributed manner. \begin{verbatim} symbfacIVL = SymbFac_MPI_initFromInpMtx(frontETree, ownersIV, mtxA, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; \end{verbatim} The {\tt symbfacIVL} object on a particular processor is only a subset of the global symbolic factorization, containing only what it needs to know for it to compute its part of the factorization. \par \subsection{The Matrix Factorization} \label{subsection:MPI:factor} \par In contrast the the multithreaded environment, data structures are local to a processor, and so locks are not needed to manage access to critical regions of code. The initialization of the front matrix and submatrix manager objects is much like the serial case, with one exception. \par \begin{verbatim} mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; frontmtx = FrontMtx_new() ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, pivotingflag, NO_LOCK, myid, ownersIV, mtxmanager, msglvl, msgFile) ; \end{verbatim} Note that the nineth and tenth arguments are {\tt myid} and {\tt ownersIV}, not {\tt 0} and {\tt NULL} as for the serial and multithreaded drivers. These arguments tell the front matrix object that it needs to initialize only those parts of the factor matrices that it ``owns'', which are given by the map from fronts to processors and the processor id. \par The numeric factorization is performed by the {\tt FrontMtx\_MPI\_factorInpMtx()} method. The code segment from the sample program for the numerical factorization step is found below. \begin{verbatim} chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 0) ; rootchv = FrontMtx_MPI_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, ownersIV, lookahead, &error, cpus, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; ChvManager_free(chvmanager) ; \end{verbatim} Note that the {\tt ChvManager} is not locked. The calling sequence is identical to that of the multithreaded factorization except for the addition of the {\tt firsttag} and MPI communicator at the end. \par The post-processing of the factorization is the same in principle as in the serial code but differs in that is uses the distributed data structures. \begin{verbatim} FrontMtx_MPI_postProcess(frontmtx, ownersIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; \end{verbatim} After the post-processing step, each local {\tt FrontMtx} object contains the $L_{J,I}$, $D_{I,I}$ and $U_{I,J}$ submatrices for the fronts that were owned by the particular processor. However, the parallel solve is based on the submatrices being distributed across the processors, not just the fronts. \par We must specify which threads own which submatrices, and so perform computations with them. This is done by constructing a {\it ``solve--map''} object, as we see below. \begin{verbatim} solvemap = SolveMap_new() ; SolveMap_ddMap(solvemap, symmetryflag, FrontMtx_upperBlockIVL(frontmtx), FrontMtx_lowerBlockIVL(frontmtx), nproc, ownersIV, FrontMtx_frontTree(frontmtx), seed, msglvl, msgFile) ; \end{verbatim} This object also uses a domain decomposition map, the only solve map that presently found in the {\bf SPOOLES} library. \par Once the solve map has been created, (and note that it is identical across all the processors), we redistribute the submatrices with the following code fragment. \begin{verbatim} FrontMtx_MPI_split(frontmtx, solvemap, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; \end{verbatim} At this point in time, the submatrices that a processor owns are local to that processor. \par \subsection{The Forward and Backsolves} \label{subsection:MPI:solve} \par If pivoting has been performed for numerical stability, then the rows of $PY$ may not be located on the processor that needs them. We must perform an additional redistribution of the local {\tt DenseMtx} objects that hold $PY$, as the code fragment below illustrates. \begin{verbatim} if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { IV *rowmapIV ; /* ---------------------------------------------------------- pivoting has taken place, redistribute the right hand side to match the final rows and columns in the fronts ---------------------------------------------------------- */ rowmapIV = FrontMtx_MPI_rowmapIV(frontmtx, ownersIV, msglvl, msgFile, MPI_COMM_WORLD) ; newY = DenseMtx_MPI_splitByRows(mtxY, rowmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; DenseMtx_free(mtxY) ; mtxY = newY ; IV_free(rowmapIV) ; } \end{verbatim} \par Each processor now must create a local {\tt DenseMtx} object to hold the rows of $PX$ that it owns. \begin{verbatim} ownedColumnsIV = FrontMtx_ownedColumnsIV(frontmtx, myid, ownersIV, msglvl, msgFile) ; nmycol = IV_size(ownedColumnsIV) ; mtxX = DenseMtx_new() ; if ( nmycol > 0 ) { DenseMtx_init(mtxX, type, 0, 0, nmycol, nrhs, 1, nmycol) ; DenseMtx_rowIndices(mtxX, &nrow, &rowind) ; IVcopy(nmycol, rowind, IV_entries(ownedColumnsIV)) ; } \end{verbatim} If $A$ is symmetric, or if pivoting for stability was not used, then {\tt mtxX} can just be a pointer to {\tt mtxY}, i.e., $PX$ could overwrite $PY$. \par The parallel solve is remarkably similar to the serial solve, as we see with the code fragment below. \begin{verbatim} solvemanager = SubMtxManager_new() ; SubMtxManager_init(solvemanager, NO_LOCK, 0) ; FrontMtx_MPI_solve(frontmtx, mtxX, mtxY, solvemanager, solvemap, cpus, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; SubMtxManager_free(solvemanager) ; \end{verbatim} The only difference between the multithreaded and MPI solve methods is the presence of the first tag and MPI communicator in the latter. \par The last step is to permute the rows of the local solution matrix into the original matrix ordering. We also gather all the solution entries into one {\tt DenseMtx} object on processor zero. \begin{verbatim} DenseMtx_permuteRows(mtxX, newToOldIV) ; IV_fill(vtxmapIV, 0) ; firsttag++ ; mtxX = DenseMtx_MPI_splitByRows(mtxX, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; \end{verbatim} \par \subsection{Sample Matrix and Right Hand Side Files} \label{subsection:MPI:input-files} \par \begin{center} \begin{tabular}{|l||l||l||l||} \hline {\tt matrix.0.input} & {\tt matrix.1.input} & {\tt matrix.2.input} & {\tt matrix.3.input} \\ \begin{minipage}[t]{1 in} \begin{verbatim} 9 9 6 0 0 4.0 0 1 -1.0 0 3 -1.0 1 1 4.0 1 2 -1.0 1 4 -1.0 \end{verbatim} \end{minipage} & \begin{minipage}[t]{1 in} \begin{verbatim} 9 9 5 2 2 4.0 2 5 -1.0 3 3 4.0 3 4 -1.0 3 6 -1.0 \end{verbatim} \end{minipage} & \begin{minipage}[t]{1 in} \begin{verbatim} 9 9 7 4 4 4.0 4 5 -1.0 4 7 -1.0 5 5 4.0 5 8 -1.0 6 6 4.0 6 7 -1.0 \end{verbatim} \end{minipage} & \begin{minipage}[t]{1 in} \begin{verbatim} 9 9 3 7 7 4.0 7 8 -1.0 8 8 4.0 \end{verbatim} \end{minipage} \\ \hline \hline {\tt rhs.0.input} & {\tt rhs.1.input} & {\tt rhs.2.input} & {\tt rhs.3.input} \\ \begin{minipage}[t]{1 in} \begin{verbatim} 2 1 0 0.0 1 0.0 \end{verbatim} \end{minipage} & \begin{minipage}[t]{1 in} \begin{verbatim} 2 1 2 0.0 3 0.0 \end{verbatim} \end{minipage} & \begin{minipage}[t]{1 in} \begin{verbatim} 2 1 4 1.0 5 0.0 \end{verbatim} \end{minipage} & \begin{minipage}[t]{1 in} \begin{verbatim} 3 1 6 0.0 7 0.0 8 0.0 \end{verbatim} \end{minipage} \\ \hline \end{tabular} \end{center} abel{subsection:MPI:non-numeric} \par Once the front tree is replicated across the processors, we obtain the permutation vectors and permute the vertices in the front tree. The local matrices for $A$ and $Y$ are also permuted. These steps are identical to the serial and multidocumentation/AllInOne/LU_MPI_driver.tex010064400020550007177000000425530665235223500215460ustar00clevecompmath00000400000006\vfill \eject \section{{\tt allInOne.c} -- A Serial $LU$ Driver Program} \label{section:LU-MPI-driver} \begin{verbatim} /* allInOneMPI.c */ #include "../spoolesMPI.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ------------------------------------------------------------ all-in-one MPI program for each process order, factor and solve A X = Y ( 1) read in matrix entries and form InpMtx object for A ( 2) order the system using minimum degree ( 3) permute the front tree ( 4) create the owners map IV object ( 5) permute the matrix A and redistribute ( 6) compute the symbolic factorization ( 7) compute the numeric factorization ( 8) split the factors into submatrices ( 9) create the submatrix map and redistribute (10) read in right hand side entries and form dense matrix DenseMtx object for Y (11) permute and redistribute Y (12) solve the linear system (13) gather X on processor 0 created -- 98jun13, cca ------------------------------------------------------------ */ /*--------------------------------------------------------------------*/ char buffer[20] ; Chv *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxX, *mtxY, *newY ; SubMtxManager *mtxmanager, *solvemanager ; FrontMtx *frontmtx ; InpMtx *mtxA, *newA ; double cutoff, droptol = 0.0, minops, tau = 100. ; double cpus[20] ; double *opcounts ; DV *cumopsDV ; ETree *frontETree ; FILE *inputFile, *msgFile ; Graph *graph ; int error, firsttag, ient, irow, jcol, lookahead = 0, msglvl, myid, nedges, nent, neqns, nmycol, nproc, nrhs, nrow, pivotingflag, root, seed, symmetryflag, type ; int stats[20] ; int *rowind ; IV *oldToNewIV, *ownedColumnsIV, *ownersIV, *newToOldIV, *vtxmapIV ; IVL *adjIVL, *symbfacIVL ; SolveMap *solvemap ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 7 ) { fprintf(stdout, "\n usage: %s msglvl msgFile type symmetryflag pivotingflag seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 (SPOOLES_REAL) -- real entries" "\n 2 (SPOOLES_COMPLEX) -- complex entries" "\n symmetryflag -- type of matrix" "\n 0 (SPOOLES_SYMMETRIC) -- symmetric entries" "\n 1 (SPOOLES_HERMITIAN) -- Hermitian entries" "\n 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric entries" "\n pivotingflag -- type of pivoting" "\n 0 (SPOOLES_NO_PIVOTING) -- no pivoting used" "\n 1 (SPOOLES_PIVOTING) -- pivoting used" "\n seed -- random number seed" "\n " "\n note: matrix entries are read in from matrix.k.input" "\n where k is the process number" "\n note: rhs entries are read in from rhs.k.input" "\n where k is the process number" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { sprintf(buffer, "res.%d", myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], buffer) ; return(-1) ; } } type = atoi(argv[3]) ; symmetryflag = atoi(argv[4]) ; pivotingflag = atoi(argv[5]) ; seed = atoi(argv[6]) ; IVzero(20, stats) ; DVzero(20, cpus) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 1: read the entries from the input file and create the InpMtx object -------------------------------------------- */ sprintf(buffer, "matrix.%d.input", myid) ; inputFile = fopen(buffer, "r") ; fscanf(inputFile, "%d %d %d", &neqns, &neqns, &nent) ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, 0) ; if ( type == SPOOLES_REAL ) { double value ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else if ( type == SPOOLES_COMPLEX ) { double imag, real ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; InpMtx_sortAndCompress(mtxA) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- STEP 2: read the rhs entries from the rhs input file and create the DenseMtx object for Y ---------------------------------------------------- */ sprintf(buffer, "rhs.%d.input", myid) ; inputFile = fopen(buffer, "r") ; fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxY = DenseMtx_new() ; DenseMtx_init(mtxY, type, 0, 0, nrow, nrhs, 1, nrow) ; DenseMtx_rowIndices(mtxY, &nrow, &rowind) ; if ( type == SPOOLES_REAL ) { double value ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", rowind + irow) ; for ( jcol = 0 ; jcol < nrhs ; jcol++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxY, irow, jcol, value) ; } } } if ( type == SPOOLES_COMPLEX ) { double imag, real ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", rowind + irow) ; for ( jcol = 0 ; jcol < nrhs ; jcol++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxY, irow, jcol, real, imag) ; } } } fclose(inputFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 2 : find a low-fill ordering (1) create the Graph object (2) order the graph using multiple minimum degree (3) find out who has the best ordering w.r.t. op count, and broadcast that front tree object ------------------------------------------------------- */ graph = Graph_new() ; adjIVL = InpMtx_MPI_fullAdjacency(mtxA, stats, msglvl, msgFile, MPI_COMM_WORLD) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } frontETree = orderViaMMD(graph, seed + myid, msglvl, msgFile) ; Graph_free(graph) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } opcounts = DVinit(nproc, 0.0) ; opcounts[myid] = ETree_nFactorOps(frontETree, type, symmetryflag) ; MPI_Allgather((void *) &opcounts[myid], 1, MPI_DOUBLE, (void *) opcounts, 1, MPI_DOUBLE, MPI_COMM_WORLD) ; minops = DVmin(nproc, opcounts, &root) ; DVfree(opcounts) ; frontETree = ETree_MPI_Bcast(frontETree, root, msglvl, msgFile, MPI_COMM_WORLD) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n best front tree") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 3: get the permutations, permute the front tree, permute the matrix and right hand side. ------------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; ETree_permuteVertices(frontETree, oldToNewIV) ; InpMtx_permute(mtxA, IV_entries(oldToNewIV), IV_entries(oldToNewIV)) ; if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; DenseMtx_permuteRows(mtxY, oldToNewIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- STEP 4: generate the owners map IV object and the map from vertices to owners ------------------------------------------- */ cutoff = 1./(2*nproc) ; cumopsDV = DV_new() ; DV_init(cumopsDV, nproc, NULL) ; ownersIV = ETree_ddMap(frontETree, type, symmetryflag, cumopsDV, cutoff) ; DV_free(cumopsDV) ; vtxmapIV = IV_new() ; IV_init(vtxmapIV, neqns, NULL) ; IVgather(neqns, IV_entries(vtxmapIV), IV_entries(ownersIV), ETree_vtxToFront(frontETree)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n map from fronts to owning processes") ; IV_writeForHumanEye(ownersIV, msgFile) ; fprintf(msgFile, "\n\n map from vertices to owning processes") ; IV_writeForHumanEye(vtxmapIV, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- STEP 5: redistribute the matrix and right hand side --------------------------------------------------- */ firsttag = 0 ; newA = InpMtx_MPI_split(mtxA, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; firsttag++ ; InpMtx_free(mtxA) ; mtxA = newA ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n split InpMtx") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } newY = DenseMtx_MPI_splitByRows(mtxY, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; DenseMtx_free(mtxY) ; mtxY = newY ; firsttag += nproc ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n split DenseMtx Y") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 6: compute the symbolic factorization ------------------------------------------ */ symbfacIVL = SymbFac_MPI_initFromInpMtx(frontETree, ownersIV, mtxA, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; firsttag += frontETree->nfront ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n local symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- STEP 7: initialize the front matrix ----------------------------------- */ mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; frontmtx = FrontMtx_new() ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, pivotingflag, NO_LOCK, myid, ownersIV, mtxmanager, msglvl, msgFile) ; /*--------------------------------------------------------------------*/ /* --------------------------------- STEP 8: compute the factorization --------------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 0) ; rootchv = FrontMtx_MPI_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, ownersIV, lookahead, &error, cpus, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; ChvManager_free(chvmanager) ; firsttag += 3*frontETree->nfront + 2 ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n numeric factorization") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } if ( error >= 0 ) { fprintf(stderr, "\n proc %d : factorization error at front %d", myid, error) ; MPI_Finalize() ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ STEP 9: post-process the factorization and split the factor matrices into submatrices ------------------------------------------------ */ FrontMtx_MPI_postProcess(frontmtx, ownersIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; firsttag += 5*nproc ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n numeric factorization after post-processing"); FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- STEP 10: create the solve map object ----------------------------------- */ solvemap = SolveMap_new() ; SolveMap_ddMap(solvemap, symmetryflag, FrontMtx_upperBlockIVL(frontmtx), FrontMtx_lowerBlockIVL(frontmtx), nproc, ownersIV, FrontMtx_frontTree(frontmtx), seed, msglvl, msgFile); if ( msglvl > 3 ) { SolveMap_writeForHumanEye(solvemap, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- STEP 11: redistribute the submatrices of the factors ---------------------------------------------------- */ FrontMtx_MPI_split(frontmtx, solvemap, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n numeric factorization after split") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ STEP 13: permute and redistribute Y if necessary ------------------------------------------------ */ if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { IV *rowmapIV ; /* ---------------------------------------------------------- pivoting has taken place, redistribute the right hand side to match the final rows and columns in the fronts ---------------------------------------------------------- */ rowmapIV = FrontMtx_MPI_rowmapIV(frontmtx, ownersIV, msglvl, msgFile, MPI_COMM_WORLD) ; newY = DenseMtx_MPI_splitByRows(mtxY, rowmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; DenseMtx_free(mtxY) ; mtxY = newY ; IV_free(rowmapIV) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs matrix after split") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 14: create a solution DenseMtx object ------------------------------------------ */ ownedColumnsIV = FrontMtx_ownedColumnsIV(frontmtx, myid, ownersIV, msglvl, msgFile) ; nmycol = IV_size(ownedColumnsIV) ; mtxX = DenseMtx_new() ; if ( nmycol > 0 ) { DenseMtx_init(mtxX, type, 0, 0, nmycol, nrhs, 1, nmycol) ; DenseMtx_rowIndices(mtxX, &nrow, &rowind) ; IVcopy(nmycol, rowind, IV_entries(ownedColumnsIV)) ; } /*--------------------------------------------------------------------*/ /* -------------------------------- STEP 15: solve the linear system -------------------------------- */ solvemanager = SubMtxManager_new() ; SubMtxManager_init(solvemanager, NO_LOCK, 0) ; FrontMtx_MPI_solve(frontmtx, mtxX, mtxY, solvemanager, solvemap, cpus, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; SubMtxManager_free(solvemanager) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n solution in new ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- STEP 15: permute the solution into the original ordering and assemble the solution onto processor zero -------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n solution in old ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } IV_fill(vtxmapIV, 0) ; firsttag++ ; mtxX = DenseMtx_MPI_splitByRows(mtxX, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; if ( myid == 0 && msglvl > 0 ) { fprintf(msgFile, "\n\n complete solution in old ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ MPI_Finalize() ; return(1) ; } /*--------------------------------------------------------------------*/ \end{verbatim} ee = orderViaMMD(graph, seed + myid, msglvl, msgFile) ; Graph_free(graph) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree from ordering") documentation/AllInOne/LU_MT.tex010064400020550007177000000213420665235217700200640ustar00clevecompmath00000400000006\vfill \eject \par \section{Multithreaded Solution of $A X = Y$ using an $LU$ factorization} \label{section:LU-MT} \par The only computations that are multithreaded are the factorization and forward and backsolves. Therefore, this section will describe only the differences between the serial driver in Section~\ref{section:LU-serial-driver} and the multithreaded driver whose complete listing is found in Section~\ref{section:LU-MT-driver}. This section will refer the reader to subsections in Section~\ref{section:LU-serial} for the parts of the code where the two drivers are identical. \par The shared memory parallel version of {\bf SPOOLES} is implemented using thread based parallelism. The multi-threaded code uses much of the serial code --- the basic steps are the same and use the serial methods. The usage of {\bf SPOOLES} for communicating the data for the problem and reordering the linear system is identical in the serial and multi-threaded versions. Only the numeric factorization and solve steps are parallelized using threads. What is different between the serial and threaded versions of the numeric computations is how the computations are scheduled. \par While the storage for the factor matrices lies in one global {\tt FrontMtx} object, all processes access the data in a disjoint way. During the factorization, front $J$ is {\it owned} by one process that is responsible for factoring the front and computing its updates to all other fronts. In other words, only the process that owns front $J$ performs computations with that data. During the solve, all $L_{J,I}$, $D_{I,I}$ and $U_{I,J}$ submatrices are stored in the front matrix object, but the computations with them are mapped to different threads, i.e., each thread {\it owns} a subset of the factor submatrices, and performs computations with it. We will now begin to work our way through the program found in Section~\ref{section:LU-MT-driver} to illustrate the use of {\bf SPOOLES} to solve a system of linear equations using multithreaded factor and solves. \par \subsection{Reading the input parameters} \label{subsection:MT:input-data} \par This step is identical to the serial code, as described in Section~\ref{subsection:serial:input-data}, with the exception that {\tt nthread}, the number of threads, is also input. \par \subsection{Communicating the data for the problem} \label{subsection:MT:communicating-data} \par This step is identical to the serial code, as described in Section~\ref{subsection:serial:communicating-data} \par \subsection{Reordering the linear system} \label{subsection:MT:reordering} This step is identical to the serial code, as described in Section~\ref{subsection:serial:reordering} \par \subsection{Non-numeric work} \label{subsection:MT:non-numeric} This step is identical to the serial code, as described in Section~\ref{subsection:serial:non-numeric}, with one addition. We need to map factor computations to threads. The {\tt ownersIV} vector object specifies which thread {\it owns} a front. The {\bf SPOOLES} library has four ways to do this. Two are of academic interest --- the wrap map and the balanced map -- for these maps yield too much interaction between the threads. The subtree-subset map is suited for extremely well balanced front trees from nested dissection orderings. The domain decomposition map is more robust over a range of orderings, and this is what we recommend, as we see in the code fragment below. \begin{verbatim} if ( nthread > (nfront = FrontMtx_nfront(frontmtx)) ) { nthread = nfront ; } cumopsDV = DV_new() ; DV_init(cumopsDV, nthread, NULL) ; ownersIV = ETree_ddMap(frontETree, type, symmetryflag, cumopsDV, 1./(2.*nthread)) ; \end{verbatim} The first step is to ensure that each thread has a front to own, decreasing the number of threads if necessary. We then construct the owners map using the front tree object. The {\tt cumopsDV} object is a double precision vector object whose length is the number of threads. On return from the map call, it contains the number of factor operations that will be performed by each thread when pivoting for stability is not enabled. \par \subsection{The Matrix Factorization} \label{subsection:MT:factor} \par During the factorization and solves, the threads access data and modify the state of the {\tt FrontMtx} and {\tt SubMtxManager} objects in a concurrent fashion, so there must be some way to control this access for critical sections of code. Inside each of the two objects we have placed a {\tt Lock} object. The {\bf SPOOLES} {\tt Lock} object is little more than a wrapper around a mutual exclusion lock. It provides a simple abstract interface so that other objects which contain locks need not know about the particular thread package we use, be it Solaris threads, or POSIX threads, or another. \par To notify the {\tt FrontMtx} and {\tt SubMtxManager} objects that they must have a lock, their initialization method calls differ slightly from the serial version. See Section~\ref{subsection:serial:factor} for a discussion of the similar features. The code fragment below shows their initialization calls. \par \begin{verbatim} frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, LOCK_IN_PROCESS, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, pivotingflag, LOCK_IN_PROCESS, 0, NULL, mtxmanager, msglvl, msgFile) ; \end{verbatim} The difference is that the {\tt SubMtxManager} and {\tt FrontMtx} objects are initialized with a {\tt LOCK\_IN\_PROCESS} flag instead of a {\tt NO\_LOCK} flag. The scope of the mutual exclusion lock is for threads within the same process, not across the system. \par The numeric factorization is performed by the {\tt FrontMtx\_factorInpMtx()} method. The code segment from the sample program for the numerical factorization step is found below. \begin{verbatim} chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, LOCK_IN_PROCESS, 1) ; DVfill(10, cpus, 0.0) ; IVfill(20, stats, 0) ; rootchv = FrontMtx_MT_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, ownersIV, lookahead, &error, cpus, stats, msglvl, msgFile) ; ChvManager_free(chvmanager) ; \end{verbatim} Note that the {\tt ChvManager} is also locked. There are two additional parameters in the calling sequence of the multithreaded factorization. \begin{itemize} \item The {\tt ownersIV} object maps the fronts to threads. \item The {\tt lookahead} parameter controls the flow of execution during the factorization. Since the threads work cooperatively to compute the factor matrices, there is idle time while one thread waits on another. The {\tt lookahead} parameter controls the ability of the thread to look past the present idle point and perform work that is not so immediate. Unfortunately, while a thread is off doing this work, it may block a thread at a more crucial point. When {\tt lookahead = 0}, each processor tries to do only ``immediate'' work. Moderate speedups in the factorization have been for values of {\tt lookahead} up to the number of threads. For nonzero {\tt lookahead} values, the amount of working storage can increase, sometimes appreciably. \end{itemize} The post-processing of the factorization is exactly the same as the serial code. Note, this step can be trivially parallelized, but is not done at present. \par After the post-processing step, the {\tt FrontMtx} object contains the $L_{J,I}$, $D_{I,I}$ and $U_{I,J}$ submatrices. What remains to be done is to specify which threads own which submatrices, and thus perform computations with them. This is done by constructing a {\it ``solve--map''} object, as we see below. \begin{verbatim} solvemap = SolveMap_new() ; SolveMap_ddMap(solvemap, symmetryflag, FrontMtx_upperBlockIVL(frontmtx), FrontMtx_lowerBlockIVL(frontmtx), nthread, ownersIV, FrontMtx_frontTree(frontmtx), seed, msglvl, msgFile) ; \end{verbatim} This object also uses a domain decomposition map, the only solve map that presently found in the {\bf SPOOLES} library. \par \subsection{The Forward and Backsolves} \label{subsection:MT:solve} \par The parallel solve is remarkably similar to the serial solve, as we see with the code fragment below. \begin{verbatim} mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; FrontMtx_MT_solve(frontmtx, mtxX, mtxY, mtxmanager, solvemap, cpus, msglvl, msgFile) ; DenseMtx_permuteRows(mtxX, newToOldIV) ; \end{verbatim} The only difference between the serial and multithreaded solve methods is the presence of the solve--map object in the latter. \par \subsection{Sample Matrix and Right Hand Side Files} \label{subsection:MT:input-files} \par The multithreaded driver uses the same input files as found in Section~\ref{subsection:serial:input-files}. thread {\it owns} a subset of the factor submatrices, and performs computations with it. We will now begin to work our way through the program found in Section~\ref{section:LU-MT-driver} to illustrate the use of {\bf SPOOLES} to solve a system of linear equations using multithreaded documentation/AllInOne/LU_MT_driver.tex010064400020550007177000000323460665235221100214320ustar00clevecompmath00000400000006\vfill \eject \section{{\tt allInOne.c} -- A Serial $LU$ Driver Program} \label{section:LU-MT-driver} \begin{verbatim} /* allInOneMT.c */ #include "../spoolesMT.h" #include "../../misc.h" #include "../../FrontMtx.h" #include "../../SymbFac.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ------------------------------------------------------------------ all-in-one program to solve A X = Y using a multithreaded factorization and solve (1) read in matrix entries for A and form InpMtx object (2) read in right hand side for Y entries and form DenseMtx object (3) form Graph object, order matrix and form front tree (4) get the permutation, permute the front tree, matrix and right hand side and get the symbolic factorization (5) initialize the front matrix object to hold the factor matrices (6) get the domain-decomposition map from fronts to threads (7) compute the numeric factorization (8) post-process the factor matrices (9) get the map for the parallel solve (10) compute the solution (11) permute the solution into the original ordering created -- 98jun04, cca ------------------------------------------------------------------ */ /*--------------------------------------------------------------------*/ char *matrixFileName, *rhsFileName ; DenseMtx *mtxY, *mtxX ; Chv *rootchv ; ChvManager *chvmanager ; double droptol = 0.0, tau = 100. ; double cpus[10] ; DV *cumopsDV ; ETree *frontETree ; FrontMtx *frontmtx ; FILE *inputFile, *msgFile ; Graph *graph ; InpMtx *mtxA ; int error, ient, irow, jcol, jrhs, jrow, lookahead, msglvl, ncol, nedges, nent, neqns, nfront, nrhs, nrow, nthread, pivotingflag, seed, symmetryflag, type ; int *newToOld, *oldToNew ; int stats[20] ; IV *newToOldIV, *oldToNewIV, *ownersIV ; IVL *adjIVL, *symbfacIVL ; SolveMap *solvemap ; SubMtxManager *mtxmanager ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 10 ) { fprintf(stdout, "\n" "\n usage: %s msglvl msgFile type symmetryflag pivotingflag" "\n matrixFileName rhsFileName seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 (SPOOLES_REAL) -- real entries" "\n 2 (SPOOLES_COMPLEX) -- complex entries" "\n symmetryflag -- type of matrix" "\n 0 (SPOOLES_SYMMETRIC) -- symmetric entries" "\n 1 (SPOOLES_HERMITIAN) -- Hermitian entries" "\n 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric entries" "\n pivotingflag -- type of pivoting" "\n 0 (SPOOLES_NO_PIVOTING) -- no pivoting used" "\n 1 (SPOOLES_PIVOTING) -- pivoting used" "\n matrixFileName -- matrix file name, format" "\n nrow ncol nent" "\n irow jcol entry" "\n ..." "\n note: indices are zero based" "\n rhsFileName -- right hand side file name, format" "\n nrow nrhs " "\n ..." "\n jrow entry(jrow,0) ... entry(jrow,nrhs-1)" "\n ..." "\n seed -- random number seed, used for ordering" "\n nthread -- number of threads" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; symmetryflag = atoi(argv[4]) ; pivotingflag = atoi(argv[5]) ; matrixFileName = argv[6] ; rhsFileName = argv[7] ; seed = atoi(argv[8]) ; nthread = atoi(argv[9]) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 1: read the entries from the input file and create the InpMtx object -------------------------------------------- */ inputFile = fopen(matrixFileName, "r") ; fscanf(inputFile, "%d %d %d", &nrow, &ncol, &nent) ; neqns = nrow ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, 0) ; if ( type == SPOOLES_REAL ) { double value ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else { double imag, real ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- STEP 2: read the right hand side matrix Y ----------------------------------------- */ inputFile = fopen(rhsFileName, "r") ; fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxY = DenseMtx_new() ; DenseMtx_init(mtxY, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxY) ; if ( type == SPOOLES_REAL ) { double value ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxY, jrow, jrhs, value) ; } } } else { double imag, real ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxY, jrow, jrhs, real, imag) ; } } } fclose(inputFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n rhs matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- STEP 3 : find a low-fill ordering (1) create the Graph object (2) order the graph using multiple minimum degree ------------------------------------------------- */ graph = Graph_new() ; adjIVL = InpMtx_fullAdjacency(mtxA) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- STEP 4: get the permutation, permute the front tree, permute the matrix and right hand side, and get the symbolic factorization ---------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; oldToNew = IV_entries(oldToNewIV) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; newToOld = IV_entries(newToOldIV) ; ETree_permuteVertices(frontETree, oldToNewIV) ; InpMtx_permute(mtxA, oldToNew, oldToNew) ; if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; DenseMtx_permuteRows(mtxY, oldToNewIV) ; symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n old-to-new permutation vector") ; IV_writeForHumanEye(oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation vector") ; IV_writeForHumanEye(newToOldIV, msgFile) ; fprintf(msgFile, "\n\n front tree after permutation") ; ETree_writeForHumanEye(frontETree, msgFile) ; fprintf(msgFile, "\n\n input matrix after permutation") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fprintf(msgFile, "\n\n right hand side matrix after permutation") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 5: setup the domain decomposition map ------------------------------------------ */ if ( nthread > (nfront = FrontMtx_nfront(frontmtx)) ) { nthread = nfront ; } cumopsDV = DV_new() ; DV_init(cumopsDV, nthread, NULL) ; ownersIV = ETree_ddMap(frontETree, type, symmetryflag, cumopsDV, 1./(2.*nthread)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n map from fronts to threads") ; IV_writeForHumanEye(ownersIV, msgFile) ; fprintf(msgFile, "\n\n factor operations for each front") ; DV_writeForHumanEye(cumopsDV, msgFile) ; fflush(msgFile) ; } DV_free(cumopsDV) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 6: initialize the front matrix object ------------------------------------------ */ frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, LOCK_IN_PROCESS, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, pivotingflag, LOCK_IN_PROCESS, 0, NULL, mtxmanager, msglvl, msgFile) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- STEP 7: compute the numeric factorization in parallel ----------------------------------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, LOCK_IN_PROCESS, 1) ; DVfill(10, cpus, 0.0) ; IVfill(20, stats, 0) ; rootchv = FrontMtx_MT_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, ownersIV, lookahead, &error, cpus, stats, msglvl, msgFile) ; ChvManager_free(chvmanager) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } if ( rootchv != NULL ) { fprintf(msgFile, "\n\n matrix found to be singular\n") ; exit(-1) ; } if ( error >= 0 ) { fprintf(msgFile, "\n\n fatal error at front %d", error) ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- STEP 8: post-process the factorization -------------------------------------- */ FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 9: get the solve map object for the parallel solve ------------------------------------------------------- */ solvemap = SolveMap_new() ; SolveMap_ddMap(solvemap, symmetryflag, FrontMtx_upperBlockIVL(frontmtx), FrontMtx_lowerBlockIVL(frontmtx), nthread, ownersIV, FrontMtx_frontTree(frontmtx), seed, msglvl, msgFile) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 10: solve the linear system in parallel -------------------------------------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; FrontMtx_MT_solve(frontmtx, mtxX, mtxY, mtxmanager, solvemap, cpus, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n solution matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- STEP 11: permute the solution into the original ordering -------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------- free memory ----------- */ FrontMtx_free(frontmtx) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxY) ; IV_free(newToOldIV) ; IV_free(oldToNewIV) ; InpMtx_free(mtxA) ; ETree_free(frontETree) ; IVL_free(symbfacIVL) ; SubMtxManager_free(mtxmanager) ; Graph_free(graph) ; SolveMap_free(solvemap) ; IV_free(ownersIV) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ \end{verbatim} , value) ; } } } else { double imag, real ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxYdocumentation/AllInOne/LU_serial.tex010064400020550007177000000522610664720136600210240ustar00clevecompmath00000400000006\vfill \eject \par \section{Serial Solution of $A X = Y$ using an $LU$ factorization} \label{section:LU-serial} \par The user has some representation of the data which represents the linear system, $AX = Y$. The user wants the solution $X$. The {\bf SPOOLES} library will use $A$ and $Y$ and provide $X$ back to the user. \par The {\bf SPOOLES} library is based on an object oriented design philosophy. The first object that the user must interact with is {\tt InpMtx}\footnote{ {\tt InpMtx} stands for {\tt Inp}ut {\tt M}a{\tt t}ri{\tt x}, for it is the object into which the user inputs the matrix entries.}. The {\tt InpMtx} object is where the {\bf SPOOLES} representation of $A$ is assembled. The user can input the representation of $A$ into the {\tt InpMtx} object with methods for single matrix entry (consisting of the row index, the column index, and the value), for an array of entries, for a set of entries in a specified row or column, and for a dense sub-matrices (useful for finite element applications). All of these methods can be used interchangeably with each other. \par A complete listing of a sample program is found in Section~\ref{section:LU-serial-driver}. We will now begin to work our way through the program to illustrate the use of {\bf SPOOLES} to solve a system of linear equations. \par \subsection{Reading the input parameters} \label{subsection:serial:input-data} \par The program starts by declaring a variety of variables and pointers for the program. It then reads the following parameters from standard input. \begin{itemize} \item The variable {\tt msglvl} controls the level of output generated by the program and by {\bf SPOOLES}. \item The printed output is sent to {\tt messageFile}. \item Whether the matrix is real or complex is controled by {\tt type} (1 for real, 2 for complex). \item Similarly, {\tt symmetryflag} controls whether the matrix is symmetric (0), Hermitian (1), or nonsymmetric (2). \item The matrix data will be read from the file {\tt matrixFileName}. The matrix data has a simple format with the first line containing the number of rows ({\tt nrow}), the number of columns ({\tt ncol}), and the number of entries ({\tt nent}). The remaining {\tt nent} lines on the file contain the row number, the column number, and value for each nonzero in the sparse matrix. In our sample case, the matrix is symmetric so only the entries in the upper triangle are given on the file. If the matrix is complex, there would be 2 values, one for the real part and one for the imaginary part. {\bf SPOOLES} follows the C language convention for indexing all arrays starting with 0. So the row and column labels for a matrix of order {\tt neqns} range from 0 to {\tt neqns-1}. \item The right hand side matrix $Y$ will be read from the file {\tt rhsFileName}. The first line of this file has two numbers: {\tt nrow}, the number of rows of $Y$ that are present in the file, followed by {\tt nrhs}, the number of columns of $Y$. (The number of rows of $Y$ in the file may be different from the number of rows in $Y$, since often right hand side matrices are sparse. This allows us the option of only reading in nonzero rows of $Y$.) The remaining lines of the file have the following format: the row id, followed by either {\tt nrhs} floating point numbers if the system is real, or {\tt 2*nrhs} numbers if the system is complex. \item The {\tt seed} parameter is a random number seed used in the ordering process. \end{itemize} \par \subsection{Communicating the data for the problem} \label{subsection:serial:communicating-data} \par The following code segment from the full sample program opens the file {\tt matrixFileName}, reads the first line of the file, and then initializes the {\tt InpMtx} object. The program continues by reading each line of the input matrix data and uses either the method {\tt InpMtx\_inputRealEntry()} or {\tt InpMtx\_inputComplexEntry()} to place that entry into the {\tt InpMtx} object. Finally this code segment closes the file. finalizes the input to {\tt InpMtx} by converting the internal storage of the matrix entries to a vector form. (This is necessary for later steps.) \begin{verbatim} inputFile = fopen(matrixFileName, "r") ; fscanf(inputFile, "%d %d %d", &nrow, &ncol, &nent) ; neqns = nrow ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, neqns) ; if ( type == SPOOLES_REAL ) { double value ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else { double imag, real ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } \end{verbatim} \par The {\tt InpMtx} object is created via a call to {\tt InpMtx\_new()} and initialized via a call to {\tt InpMtx\_init()}. The arguments to {\tt InpMtx\_init()} are the pointer to the {\tt InpMtx} object created by {\tt InpMtx\_new()} followed by four integers, {\tt coordType}, {\tt inputMode}, {\tt maxnent}, and {\tt maxnvector}. \begin{itemize} \item The second argument {\tt coordType} = {\tt INPMTX\_BY\_ROWS} represent a general purpose mode that is well suited for most users.\footnote{Note that {\bf SPOOLES} has some pre-defined parameters such as {\tt INPMTX\_BY\_ROWS} for some objects. These parameters are always uppercase and either begin with the name of the object which they apply to, or the library name, e.g., {\tt SPOOLES\_REAL}. They are described in the reference manual in the section for the particular object.} Some users may want to use other settings for {\tt coordType} whose complete descriptions are found in the reference manual. \item The third argument {\tt inputMode} controls whether the matrix is real or complex. One use of {\bf SPOOLES} not illustrated here is that the {\tt InpMtx} object can have no values. This allows {\bf SPOOLES} to be used to generate an ordering for use by another package. \item The fourth argument {\tt maxnent} is an estimate of the number of nonzero entries in the matrix. \item The fifth argument {\tt maxnvector} is an estimate of the number of number of vectors that will be used, e.g., number of rows or numbers of columns. \end{itemize} The {\tt maxnent} and {\tt maxnvector} arguments only have to be estimates as they are used in the initial sizing of the object. Either can be 0. The {\tt InpMtx} object resizes itself as required to handle the linear system. \par Every object in {\bf SPOOLES} has print methods to output the contents of that object. This is illustrated in this code segment by printing the input matrix as contained in the {\tt InpMtx} object, {\tt mtxA}. To shorten this chapter we will from now on omit the part of the code that prints debug output to {\tt msgFile} for the various code segments. The complete sample program in Section~\ref{section:LU-serial-driver} contains all of the debug print statements. \par After the matrix $A$ has been read in from the file and placed in an {\tt InpMtx} object, the right hand matrix $Y$ is read in from a file and placed in a {\tt DenseMtx} object. The following code fragment does this operation. \begin{verbatim} inputFile = fopen(rhsFileName, "r") ; fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxB = DenseMtx_new() ; DenseMtx_init(mtxB, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxB) ; if ( type == SPOOLES_REAL ) { double value ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxB, jrow, jrhs, value) ; } } } else { double imag, real ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxB, jrow, jrhs, real, imag) ; } } } fclose(inputFile) ; \end{verbatim} The dense matrix object is created by a call to {\tt DenseMtx\_new()} and initialized via a call to {\tt DenseMtx\_init()}. There are seven arguments to {\tt DenseMtx\_init()}, not counting the initial pointer argument. \begin{itemize} \item The second argument specifies the type of the matrix, real or complex. \item The third and fourth arguments specify row and column ids of the matrix. This is useful when the dense matrix is a submatrix of a larger block matrix, but this feature is not used in the present context. \item The fifth and sixth arguments are the number of rows and columns in the matrix, here equal to {\tt neqns} and {\tt nrhs}. \item The seventh and eighth arguments are the row stride and column stride for the matrix entries. For our application we require a column major matrix, and so the row stride is {\tt 1} and the column stride is the number of rows, or {\tt neqns}. \end{itemize} The initialization step allocates storage for the matrix entries, but it does not fill them with any values. This is done explicitly via the {\tt DenseMtx\_zero()} method, which places zeroes in all the entries. This is necessary since the right hand side matrix $Y$ may be sparse, and so the number of rows in the file may not equal the number of equations. \par The right hand side entries are then in, row by row, and placed into their locations via one of the two ``set entries'' methods. Note, the nonzero rows can be read from the file in any order. \par \subsection{Reordering the linear system} \label{subsection:serial:reordering} \par The first step is to find the permutation matrix $P$, and then permute $AX = Y$ into $(PAP^T)(PX) = PY$. The result of the {\bf SPOOLES} ordering step is not just $P$ or its permutation vector, it is a {\it front tree} that defines not just the permutation, but the blocking of the factor matrices, which in turn specifies the data structures and the computations that are performed during the factor and solves. To determine this {\tt ETree} {\it front tree} object takes three step, as seen in the code fragment below. \begin{verbatim} adjIVL = InpMtx_fullAdjacency(mtxA) ; nedges = IVL_tsize(adjIVL) ; graph = Graph_new() ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; \end{verbatim} The ordering modules requires a graph of $A + A^T$. (The {\bf SPOOLES} $LU$ factorization works with matrices of symmetric structure.) The {\tt Graph} object represents the graph of the matrix. Its internal representation uses adjacency lists, one for each vertex, which in turn are stored in an {\tt IVL} object. The {\tt Graph} and {\tt InpMtx} objects are at a high level in the object hierarchy. To promote independence of the objects, the two do not know about each other, so we cannot create one from the other. Instead, the {\tt InpMtx} object creates the lower level {\tt IVL} object\footnote{{\tt IVL} stands for {\tt I}nteger {\tt V}ector {\tt L}ist, i.e., a list of integer vectors.}, which is then used in the initialization step for the {\tt Graph} object. The {\tt Graph} object is quite general, and can be used to describe a graph with unit or non-unit vertices and edges. We refrain from describing all the input parameters to initialize the {\tt Graph} object and instead refer the reader to the reference manual. \par Once a {\tt Graph} object has been created, it is ordered via the multiple minimum degree method, whose return value is a front tree object. The minimum degree method is the simplest of the ordering methods provided in the {\bf SPOOLES} library. For more information on ordering, please see the user document {\it ``Ordering Sparse Matrices and Transforming Front Trees''}. \par \subsection{Non-numeric work} \label{subsection:serial:non-numeric} \par The next phase is to obtain the permutation matrix $P$, (stored implicitly in a permutation vector), and apply it to the front tree, the matrix $A$ and the right hand side $Y$. This is done by the following code fragment. \begin{verbatim} oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; oldToNew = IV_entries(oldToNewIV) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; newToOld = IV_entries(newToOldIV) ; ETree_permuteVertices(frontETree, oldToNewIV) ; InpMtx_permute(mtxA, oldToNew, oldToNew) ; if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; DenseMtx_permuteRows(mtxB, oldToNewIV) ; \end{verbatim} The {\tt oldToNewIV} and {\tt newToOldIV} variables are {\tt IV} objects that represent an integer vector. The {\tt oldToNew} and {\tt newToOld} variables are pointers to {\tt int}, which point to the base address of the {\tt int} vector in an {\tt IV} object. \par Once we have the permutation vector, we apply it to the front tree, by the {\tt ETree\_permuteVertices()} method, and then to the matrix with the {\tt InpMtx\_permute()} method. If the matrix $A$ is symmetric or Hermitian, we expect all nonzero entries to be in the upper triangle. Permuting the matrix yields $PAP^T$, which may not have all of its entries in the upper triangle. If $A$ is symmetric or Hermitian, the call to {\tt InpMtx\_mapToUpperTriangle()} ensures that all entries of $PAP^T$ are in its upper triangle. Permuting the matrix destroys the internal vector structure, which has to be restored. But first we need to change the coordinate type of the {\tt InpMtx} object, from rows into {\it chevrons}.\footnote{The $i$-th chevron of $A$ consists of the diagonal entry $A_{i,i}$, the $i$-th row of the upper triangle of $A$, and the $i$-th column of the lower triangle of $A$.} This is necessary in order to assemble entries of $PAP^T$ during the numerical factorization. At this point the {\tt InpMtx} object holds $PAP^T$ in the form required by the factorization. What remains is to transform $Y$ into $PY$, which is done via a call to {\tt DenseMtx\_permuteRows()}. \par The final step is to compute the symbolic factorization, which is stored in an {\tt IVL} object. \begin{verbatim} symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ; \end{verbatim} \par \subsection{The Matrix Factorization} \label{subsection:serial:factor} \par The numeric factorization step begins by initializing the {\tt FrontMtx} object with the {\tt frontETree} and {\tt symbacIVL} objects created in early steps. The {\tt FrontMtx} object holds the actual factorization. The code segment for the initialization is found below. \begin{verbatim} frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, pivotingflag, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; \end{verbatim} Here is a brief description of the initialization method and its input parameters. \begin{itemize} \item The fourth parameter is the matrix type, real or complex. \item The fifth parameter specifies whether the matrix is symmetric, Hermitian or nonsymmetric. \item The sixth parameter defines whether the fronts in the factor matrix are stored as dense or sparse matrices. The latter is necessary for an approximate factorization. \item The seventh parameter says whether pivoting is enabled for numerical stability. \item The eighth, nine and ten parameters are used during a multithreaded or MPI factorization. Their present values are for a serial factorization. \item The eleventh parameter, {\tt mtxmanager} is a {\tt SubMtxManager} object, an object used to manage instances of submatrices that form the factor matrices. The {\tt FrontMtx} object does not concern itself with finding storage for the factor matrices, instead it asks the {\tt SubMtxManager} object for submatrices. While this seems awkward, it allows the {\tt FrontMtx} to operate in serial, multithreaded and MPI environments with little internal code differences, and it is the hook we have left in the library to extend its capabilities to out-of-core factors and solves. \item The twelveth and thirteenth parameters define the message level and message file for the factorization. \end{itemize} \par The numeric factorization is performed by the {\tt FrontMtx\_factorInpMtx()} method. The code segment from the sample program for the numerical factorization step is found below. \begin{verbatim} chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1) ; DVfill(10, cpus, 0.0) ; IVfill(20, stats, 0) ; rootchv = FrontMtx_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, &error, cpus, stats, msglvl, msgFile) ; ChvManager_free(chvmanager) ; \end{verbatim} Working storage used during the factorization is found in the form of block {\it chevrons}, in a {\tt Chv} object, which hold the partial frontal matrix for a front. Much as with the {\tt SubMtx} object, the {\tt FrontMtx} object does not concern itself with managing working storage, instead it relies on a {\tt ChvManager} object to manage the {\tt Chv} objects. We now discuss the arguments to the factor method. \begin{itemize} \item The third argument is used when pivoting for numerical stability is enabled. Each entry in $L$ and $U$ is bounded above in magnitude by {\tt tau}. We recommend a value of 100 for this parameter. \item The fourth argument is a drop tolerance that is not relevant for this case. When used with approximate factorizations, this argument is a lower bound on the magnitude of the entries that are stored in the front matrices. \item The sixth argument is an error flag. After a successful factorization, {\tt error < 0} implies that the factorization finished. If {\tt error > 0}, then the factorization failed at front {\tt error}. \item The seventh and eighth arguments are vectors to be filled with statistics and breakdown of cpu times. \end{itemize} The return value of the factorization is a {\tt Chv} object, which will be {\tt NULL} if the factorization succeeded. We have left this as a hook for future extensions where only portions of the factor matrices are created. \par The factorization is performed using a one-dimensional decomposition of the factor matrices. Keeping the factor matrices in this form severely limits the amount of parallelism for the forward and backsolves. We perform a post-processing step to convert the one-dimensional data structures to submatrices of a two-dimensional block decomposition of the factor matrices. The following code fragment performs this operation. \begin{verbatim} FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; \end{verbatim} \par \subsection{The Forward and Backsolves} \label{subsection:serial:solve} \par The following code fragment solves the linear system $(PAP^T) (PX) = PY$, and permutes the solution $PX$ back into the original ordering, yielding $X$. \begin{verbatim} mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; FrontMtx_solve(frontmtx, mtxX, mtxB, mtxmanager, cpus, msglvl, msgFile) ; DenseMtx_permuteRows(mtxX, newToOldIV) ; \end{verbatim} First we initialize a new {\tt DenseMtx} object to hold $X$ (and also $PX$). (Note, in all cases {\it but} a nonsymmetric matrix with pivoting enabled in an MPI environment, $X$ may overwrite $Y$, and so we can use the same {\tt DenseMtx} object for $X$ and $Y$.) We then solve the linear system with a call to {\tt FrontMtx\_solve()}. Note that one of the arguments is the {\tt mtxmanager} object, first created for the numerical factorization. The solve requires working submatrices, and so we continue the convention of having the {\tt FrontMtx} ask the manager object for working storage. The last step is to permute the rows of the {\tt DenseMtx} from the new ordering into the old ordering. \par \subsection{Sample Matrix and Right Hand Side Files} \label{subsection:serial:input-files} \par Immediately below are two sample files: {\tt matrix.input} holds the matrix input and {\tt rhs.input} holds the right hand side. This example is for a symmetric Laplacian operator on a $3 \times 3$ grid. Only entries in the upper triangle are stored. The right hand side is the $9 \times 9$ identity matrix. Note how the indices are zero-based as for C, instead of one-based as for Fortran. \begin{center} \begin{tabular}{|l|} \multicolumn{1}{c}{\tt matrix.input} \\ \hline \begin{minipage}[t]{0.75 in} \begin{verbatim} 9 9 21 0 0 4.0 1 1 4.0 2 2 4.0 3 3 4.0 4 4 4.0 5 5 4.0 6 6 4.0 7 7 4.0 8 8 4.0 0 1 -1.0 1 2 -1.0 3 4 -1.0 4 5 -1.0 6 7 -1.0 7 8 -1.0 0 3 -1.0 1 4 -1.0 2 5 -1.0 3 6 -1.0 4 7 -1.0 5 8 -1.0 \end{verbatim} \end{minipage} \\ \hline \end{tabular} \qquad \begin{tabular}{|l|} \multicolumn{1}{c}{\tt rhs.input} \\ \hline \begin{minipage}[t]{2.75 in} \begin{verbatim} 9 9 0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 3 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 4 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 5 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 6 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 7 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 8 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 \end{verbatim} \end{minipage} \\ \hline \end{tabular} \end{center} \par \tt Graph} object. The {\tt Graph} object is quite general, and can be used to describe a graph with unit or non-unit vertices and edges. We refrain from describing all the input parameters to initialize the {\tt Graph} object and instead refer the reader to the reference manual. \par Once a {\tt Graph} object has been created, it isdocumentation/AllInOne/LU_serial_driver.tex010064400020550007177000000267230664720137200224000ustar00clevecompmath00000400000006\vfill \eject \section{{\tt allInOne.c} -- A Serial $LU$ Driver Program} \label{section:LU-serial-driver} \begin{verbatim} /* allInOne.c */ #include "../../misc.h" #include "../../FrontMtx.h" #include "../../SymbFac.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ------------------------------------------------------------------ all-in-one program to solve A X = Y (1) read in matrix entries for A and form InpMtx object (2) read in right hand side for Y entries and form DenseMtx object (3) form Graph object, order matrix and form front tree (4) get the permutation, permute the front tree, matrix and right hand side and get the symbolic factorization (5) initialize the front matrix object to hold the factor matrices (6) compute the numeric factorization (7) post-process the factor matrices (8) compute the solution (9) permute the solution into the original ordering created -- 98jun04, cca ------------------------------------------------------------------ */ /*--------------------------------------------------------------------*/ char *matrixFileName, *rhsFileName ; DenseMtx *mtxY, *mtxX ; Chv *rootchv ; ChvManager *chvmanager ; SubMtxManager *mtxmanager ; FrontMtx *frontmtx ; InpMtx *mtxA ; double droptol = 0.0, tau = 100. ; double cpus[10] ; ETree *frontETree ; FILE *inputFile, *msgFile ; Graph *graph ; int error, ient, irow, jcol, jrhs, jrow, msglvl, ncol, nedges, nent, neqns, nrhs, nrow, pivotingflag, seed, symmetryflag, type ; int *newToOld, *oldToNew ; int stats[20] ; IV *newToOldIV, *oldToNewIV ; IVL *adjIVL, *symbfacIVL ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 9 ) { fprintf(stdout, "\n" "\n usage: %s msglvl msgFile type symmetryflag pivotingflag" "\n matrixFileName rhsFileName seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 (SPOOLES_REAL) -- real entries" "\n 2 (SPOOLES_COMPLEX) -- complex entries" "\n symmetryflag -- type of matrix" "\n 0 (SPOOLES_SYMMETRIC) -- symmetric entries" "\n 1 (SPOOLES_HERMITIAN) -- Hermitian entries" "\n 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric entries" "\n pivotingflag -- type of pivoting" "\n 0 (SPOOLES_NO_PIVOTING) -- no pivoting used" "\n 1 (SPOOLES_PIVOTING) -- pivoting used" "\n matrixFileName -- matrix file name, format" "\n nrow ncol nent" "\n irow jcol entry" "\n ..." "\n note: indices are zero based" "\n rhsFileName -- right hand side file name, format" "\n nrow nrhs " "\n ..." "\n jrow entry(jrow,0) ... entry(jrow,nrhs-1)" "\n ..." "\n seed -- random number seed, used for ordering" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; symmetryflag = atoi(argv[4]) ; pivotingflag = atoi(argv[5]) ; matrixFileName = argv[6] ; rhsFileName = argv[7] ; seed = atoi(argv[8]) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 1: read the entries from the input file and create the InpMtx object -------------------------------------------- */ inputFile = fopen(matrixFileName, "r") ; fscanf(inputFile, "%d %d %d", &nrow, &ncol, &nent) ; neqns = nrow ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, neqns) ; if ( type == SPOOLES_REAL ) { double value ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else { double imag, real ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- STEP 2: read the right hand side matrix Y ----------------------------------------- */ inputFile = fopen(rhsFileName, "r") ; fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxY = DenseMtx_new() ; DenseMtx_init(mtxY, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxY) ; if ( type == SPOOLES_REAL ) { double value ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxY, jrow, jrhs, value) ; } } } else { double imag, real ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxY, jrow, jrhs, real, imag) ; } } } fclose(inputFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- STEP 3 : find a low-fill ordering (1) create the Graph object (2) order the graph using multiple minimum degree ------------------------------------------------- */ graph = Graph_new() ; adjIVL = InpMtx_fullAdjacency(mtxA) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- STEP 4: get the permutation, permute the front tree, permute the matrix and right hand side, and get the symbolic factorization ---------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; oldToNew = IV_entries(oldToNewIV) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; newToOld = IV_entries(newToOldIV) ; ETree_permuteVertices(frontETree, oldToNewIV) ; InpMtx_permute(mtxA, oldToNew, oldToNew) ; if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; DenseMtx_permuteRows(mtxY, oldToNewIV) ; symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n old-to-new permutation vector") ; IV_writeForHumanEye(oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation vector") ; IV_writeForHumanEye(newToOldIV, msgFile) ; fprintf(msgFile, "\n\n front tree after permutation") ; ETree_writeForHumanEye(frontETree, msgFile) ; fprintf(msgFile, "\n\n input matrix after permutation") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fprintf(msgFile, "\n\n right hand side matrix after permutation") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 5: initialize the front matrix object ------------------------------------------ */ frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, pivotingflag, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------- STEP 6: compute the numeric factorization ----------------------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1) ; DVfill(10, cpus, 0.0) ; IVfill(20, stats, 0) ; rootchv = FrontMtx_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, &error, cpus, stats, msglvl, msgFile) ; ChvManager_free(chvmanager) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } if ( rootchv != NULL ) { fprintf(msgFile, "\n\n matrix found to be singular\n") ; exit(-1) ; } if ( error >= 0 ) { fprintf(msgFile, "\n\n error encountered at front %d", error) ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- STEP 7: post-process the factorization -------------------------------------- */ FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------- STEP 8: solve the linear system ------------------------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; FrontMtx_solve(frontmtx, mtxX, mtxY, mtxmanager, cpus, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n solution matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 9: permute the solution into the original ordering ------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------- free memory ----------- */ FrontMtx_free(frontmtx) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxY) ; IV_free(newToOldIV) ; IV_free(oldToNewIV) ; InpMtx_free(mtxA) ; ETree_free(frontETree) ; IVL_free(symbfacIVL) ; SubMtxManager_free(mtxmanager) ; Graph_free(graph) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ \end{verbatim} documentation/AllInOne/QR_serial.tex010064400020550007177000000204540664720137400210240ustar00clevecompmath00000400000006\vfill \eject \par \section{Serial Solution of $A X = Y$ using an $QR$ factorization} \label{section:QR-serial} \par Let us review the steps is solving $A X = Y$ using a $QR$ factorization. \begin{itemize} \item {\bf communicate} the data for the problem as $A$, $X$ and $Y$. \item {\bf reorder} as ${\widetilde A} {\widetilde X} = Y$, where ${\widetilde A} = A P^T$ and ${\widetilde X} = P X$. and $P$ is a permutation matrix. \item {\bf factor} $ {\widetilde A} = Q R$, where $Q$ is orthogonal and $R$ is upper triangular. \item {\bf solve} $R^T R (P X) = A^T Y$ (if real) or {\bf solve} $R^H R (P X) = A^H Y$ (if complex). \end{itemize} \par A complete listing of a sample program is found in Section~\ref{section:QR-serial-driver}. We will now begin to work our way through the program to illustrate the use of {\bf SPOOLES} to solve a system of linear equations. \par \subsection{Reading the input parameters} \label{subsection:QR:input-data} \par The input parameters are identical to those of the serial $LU$ driver program described in Section~\ref{subsection:serial:input-data} with the exception that the {\tt symmetryflag} is not present. \par \subsection{Communicating the data for the problem} \label{subsection:QR:communicating-data} \par This step is identical to the serial code, as described in Section~\ref{subsection:serial:communicating-data} \par \subsection{Reordering the linear system} \label{subsection:QR:reordering} For the $LU$ factorization of $A$, we used the graph of $A + A^T$. For the $QR$ factorization of $A$, we need the graph of $A^TA$. The only difference between the two orderings is how we create the {\tt IVL} object for the graph. For the $QR$ factorization, we use {\tt InpMtx\_adjForATA()}, as we see below. \begin{verbatim} adjIVL = InpMtx_adjForATA(mtxA) ; nedges = IVL_tsize(adjIVL) ; graph = Graph_new() ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; \end{verbatim} The minimum degree method is the simplest of the ordering methods provided in the {\bf SPOOLES} library. For more information on ordering, please see the user document {\it ``Ordering Sparse Matrices and Transforming Front Trees''}. \par \subsection{Non-numeric work} \label{subsection:QR:non-numeric} \par The next phase is to obtain the permutation matrix $P$, (stored implicitly in a permutation vector), and apply it to the matrix $A$. This is done by the following code fragment. \begin{verbatim} oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; oldToNew = IV_entries(oldToNewIV) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; newToOld = IV_entries(newToOldIV) ; InpMtx_permute(mtxA, NULL, oldToNew)) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; \end{verbatim} The {\tt oldToNewIV} and {\tt newToOldIV} variables are {\tt IV} objects that represent an integer vector. The {\tt oldToNew} and {\tt newToOld} variables are pointers to {\tt int}, which point to the base address of the {\tt int} vector in an {\tt IV} object. Once we have the permutation vector, we apply it to the front tree, by the {\tt ETree\_permuteVertices()} method. We need $A P^T$, so we permute the {\tt InpMtx} object using a {\tt NULL} pointer for the row permutation (which means do not permute the rows) and the {\tt oldToNew} vector for the column permutation. At this point the {\tt InpMtx} object holds $AP^T$ in the form required by the factorization. \par The final steps are to compute the symbolic factorization, which is stored in an {\tt IVL} object, and to permute the vertices in the front tree. The symbolic factorization differs slightly from the $LU$ case. \begin{verbatim} symbfacIVL = SymbFac_initFromGraph(frontETree, graph) ; IVL_overwrite(symbfacIVL, oldToNewIV) ; IVL_sortUp(symbfacIVL) ; ETree_permuteVertices(frontETree, oldToNewIV) ; \end{verbatim} We do not have the $A^TA$ matrix object, so we constuct the symbolic factorization using the front tree and the {\tt Graph} object. Note, at this point in time, both the graph and front tree are in terms of the original ordering, so after the {\tt IVL} object is created, its vertices must be mapped into the new permutation and sorted into ascending order. Then the vertices in the front tree are mapped into the new ordering. \par \subsection{The Matrix Factorization} \label{subsection:QR:factor} \par The numeric factorization step begins by initializing the {\tt FrontMtx} object with the {\tt frontETree} and {\tt symbacIVL} objects created in early steps. The {\tt FrontMtx} object holds the actual factorization. The code segment for the initialization is found below. \begin{verbatim} frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; if ( type == SPOOLES_REAL ) { FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, SPOOLES_SYMMETRIC, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; } else { FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, SPOOLES_HERMITIAN, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; } \end{verbatim} This differs little from the initialization in Section~\ref{subsection:serial:factor}, except that the matrix type is symmetric or Hermitian, and no pivoting is used for stability. \par The numeric factorization is performed by the {\tt FrontMtx\_QR\_factor()} method. The code segment from the sample program for the numerical factorization step is found below. \begin{verbatim} chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1) ; DVzero(10, cpus) ; facops = 0.0 ; FrontMtx_QR_factor(frontmtx, mtxA, chvmanager, cpus, &facops, msglvl, msgFile) ; ChvManager_free(chvmanager) ; \end{verbatim} Working storage used during the factorization is found in the form of block {\it chevrons}, in a {\tt Chv} object, which hold the partial frontal matrix for a front. Much as with the {\tt SubMtx} object, the {\tt FrontMtx} object does not concern itself with managing working storage, instead it relies on a {\tt ChvManager} object to manage the {\tt Chv} objects. On return {\tt facops} contains the number of floating point operations performed during the factorization. \par The factorization is performed using a one-dimensional decomposition of the factor matrices. Keeping the factor matrices in this form severely limits the amount of parallelism for the forward and backsolves. We perform a post-processing step to convert the one-dimensional data structures to submatrices of a two-dimensional block decomposition of the factor matrices. The following code fragment performs this operation. \begin{verbatim} FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; \end{verbatim} \par \subsection{Solving the linear system} \label{subsection:QR:solve} \par The following code fragment solves the linear system $R^T R {\widehat X} = {\widehat A}^T Y$ if real or $R^H R {\widehat X} = {\widehat A}^H Y$ if complex. \begin{verbatim} mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; FrontMtx_QR_solve(frontmtx, mtxA, mtxX, mtxB, mtxmanager, cpus, msglvl, msgFile) ; \end{verbatim} Last, we permute the rows of ${\tt widehat X}$ back into $X$. \begin{verbatim} DenseMtx_permuteRows(mtxX, newToOldIV) ; \end{verbatim} \par \subsection{Sample Matrix and Right Hand Side Files} \label{subsection:QR:input-files} \par Immediately below are two sample files: {\tt qr.matrix.input} holds the matrix input and {\tt qr.rhs.input} holds the right hand side. This simple example is an $8 \times 6$ matrix $A$ and a single right hand side. The solution is the vector of all ones. Note how the indices are zero-based as for C, instead of one-based as for Fortran. \begin{center} \begin{tabular}{|l|} \multicolumn{1}{c}{\tt matrix.input} \\ \hline \begin{minipage}[t]{0.5 in} \begin{verbatim} 8 6 18 0 1 1.0 0 3 2.0 1 2 3.0 1 3 1.0 1 5 1.0 2 0 1.0 2 2 2.0 3 0 3.0 3 2 4.0 3 4 2.0 4 3 1.0 5 1 2.0 5 4 3.0 5 5 1.0 6 0 2.0 6 3 3.0 7 1 1.0 7 4 3.0 \end{verbatim} \end{minipage} \\ \hline \end{tabular} \qquad \begin{tabular}{|l|} \multicolumn{1}{c}{\tt rhs.input} \\ \hline \begin{minipage}[t]{0.5 in} \begin{verbatim} 8 1 0 3.0 1 5.0 2 3.0 3 9.0 4 1.0 5 6.0 6 5.0 7 4.0 \end{verbatim} \end{minipage} \\ \hline \end{tabular} \end{center} \par documentation/AllInOne/QR_serial_driver.tex010064400020550007177000000242430664720152000223700ustar00clevecompmath00000400000006\vfill \eject \section{{\tt allInOne.c} -- A Serial $QR$ Driver Program} \label{section:QR-serial-driver} \begin{verbatim} /* QRallInOne.c */ #include "../../misc.h" #include "../../FrontMtx.h" #include "../../SymbFac.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* -------------------------------------------------- QR all-in-one program (1) read in matrix entries and form InpMtx object of A and A^TA (2) form Graph object of A^TA (3) order matrix and form front tree (4) get the permutation, permute the matrix and front tree and get the symbolic factorization (5) compute the numeric factorization (6) read in right hand side entries (7) compute the solution created -- 98jun11, cca -------------------------------------------------- */ /*--------------------------------------------------------------------*/ char *matrixFileName, *rhsFileName ; ChvManager *chvmanager ; DenseMtx *mtxB, *mtxX ; double facops, imag, real, value ; double cpus[10] ; ETree *frontETree ; FILE *inputFile, *msgFile ; FrontMtx *frontmtx ; Graph *graph ; int ient, irow, jcol, jrhs, jrow, msglvl, neqns, nedges, nent, nrhs, nrow, seed, type ; InpMtx *mtxA ; IV *newToOldIV, *oldToNewIV ; IVL *adjIVL, *symbfacIVL ; SubMtxManager *mtxmanager ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 7 ) { fprintf(stdout, "\n usage: %s msglvl msgFile type matrixFileName rhsFileName seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 (SPOOLES_REAL) -- real entries" "\n 2 (SPOOLES_COMPLEX) -- complex entries" "\n matrixFileName -- matrix file name, format" "\n nrow ncol nent" "\n irow jcol entry" "\n ..." "\n note: indices are zero based" "\n rhsFileName -- right hand side file name, format" "\n nrow " "\n entry[0]" "\n ..." "\n entry[nrow-1]" "\n seed -- random number seed, used for ordering" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; matrixFileName = argv[4] ; rhsFileName = argv[5] ; seed = atoi(argv[6]) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 1: read the entries from the input file and create the InpMtx object of A -------------------------------------------- */ inputFile = fopen(matrixFileName, "r") ; fscanf(inputFile, "%d %d %d", &nrow, &neqns, &nent) ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, 0) ; if ( type == SPOOLES_REAL ) { for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else { for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- STEP 2: read the right hand side entries ---------------------------------------- */ inputFile = fopen(rhsFileName, "r") ; fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxB = DenseMtx_new() ; DenseMtx_init(mtxB, type, 0, 0, nrow, nrhs, 1, nrow) ; DenseMtx_zero(mtxB) ; if ( type == SPOOLES_REAL ) { for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxB, jrow, jrhs, value) ; } } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxB, jrow, jrhs, real, imag) ; } } } fclose(inputFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n rhs matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- STEP 3 : find a low-fill ordering (1) create the Graph object for A^TA or A^HA (2) order the graph using multiple minimum degree ------------------------------------------------- */ graph = Graph_new() ; adjIVL = InpMtx_adjForATA(mtxA) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n graph of A^T A") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- STEP 4: get the permutation, permute the matrix and front tree and get the symbolic factorization ----------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; InpMtx_permute(mtxA, NULL, IV_entries(oldToNewIV)) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; symbfacIVL = SymbFac_initFromGraph(frontETree, graph) ; IVL_overwrite(symbfacIVL, oldToNewIV) ; IVL_sortUp(symbfacIVL) ; ETree_permuteVertices(frontETree, oldToNewIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n old-to-new permutation vector") ; IV_writeForHumanEye(oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation vector") ; IV_writeForHumanEye(newToOldIV, msgFile) ; fprintf(msgFile, "\n\n front tree after permutation") ; ETree_writeForHumanEye(frontETree, msgFile) ; fprintf(msgFile, "\n\n input matrix after permutation") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 5: initialize the front matrix object ------------------------------------------ */ frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; if ( type == SPOOLES_REAL ) { FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, SPOOLES_SYMMETRIC, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; } else { FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, SPOOLES_HERMITIAN, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- STEP 6: compute the numeric factorization ----------------------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1) ; DVzero(10, cpus) ; facops = 0.0 ; FrontMtx_QR_factor(frontmtx, mtxA, chvmanager, cpus, &facops, msglvl, msgFile) ; ChvManager_free(chvmanager) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix") ; fprintf(msgFile, "\n facops = %9.2f", facops) ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- STEP 7: post-process the factorization -------------------------------------- */ FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------- STEP 8: solve the linear system ------------------------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; FrontMtx_QR_solve(frontmtx, mtxA, mtxX, mtxB, mtxmanager, cpus, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n solution matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 9: permute the solution into the original ordering ------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------ free the working storage ------------------------ */ InpMtx_free(mtxA) ; FrontMtx_free(frontmtx) ; Graph_free(graph) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxB) ; ETree_free(frontETree) ; IV_free(newToOldIV) ; IV_free(oldToNewIV) ; IVL_free(symbfacIVL) ; SubMtxManager_free(mtxmanager) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ \end{verbatim} documentation/AllInOne/intro.tex010064400020550007177000000116430664720140700202730ustar00clevecompmath00000400000006\vfill \eject \par \section{Overview} \label{chapter:overview} \par The {\bf SPOOLES} software library is designed to solve sparse systems of linear equations $A X = Y$ for $X$, where $A$ is full rank and $X$ and $Y$ are dense matrices. The matrix $A$ can be either real or complex, symmetric, Hermitian, square nonsymmetric, or overdetermined. When $A$ is square, there are four steps in the process of solving $A X = Y$. \begin{itemize} \item {\bf communicate} the data for the problem as $A$, $X$ and $Y$. \item {\bf reorder} as ${\widetilde A} {\widetilde X} = {\widetilde Y}$, where ${\widetilde A} = P_1 A P_1^T$, ${\widetilde X} = P_1 X$ and ${\widetilde Y} = P_1 Y$, and $P_1$ is a permutation matrix. \item {\bf factor} $ {\widetilde A} = P_2LDUQ_2^T$, where $P_2$ and $Q_2$ are permutation matrices. \item {\bf solve} $LDU (Q_2^T P_1 X) = (P_2^T P_1 Y)$. \end{itemize} When $A$ is symmetric or Hermitian, $L = U^T$ or $L = U^H$, respectively, and $P_2 = Q_2$. For a $QR$ factorization of $A$, there are also four steps in the process of solving $A X = Y$. \begin{itemize} \item {\bf communicate} the data for the problem as $A$, $X$ and $Y$. \item {\bf reorder} as ${\widetilde A} {\widetilde X} = Y$, where ${\widetilde A} = A P^T$ and ${\widetilde X} = P X$. and $P$ is a permutation matrix. \item {\bf factor} $ {\widetilde A} = Q R$, where $Q$ is orthogonal and $R$ is upper triangular. \item {\bf solve} $R^T R (P X) = A^T Y$ (if real) or {\bf solve} $R^H R (P X) = A^H Y$ (if complex). \end{itemize} \par The purpose of this manual is to describe the solution process in a step by step manner for several different scenarios --- serial, multithreaded and MPI environments, and $LU$ and $QR$ factorizations. The following sections describe driver programs to solve linear systems of these types. \par This document largely replaces the {\it ``User Manual''} from the {\bf SPOOLES 1.0} and {\bf SPOOLES 2.0} releases. The material of those documents that deals with ordering sparse matrices has been removed and can be found in an improved and extended format as the {\it ``Ordering Sparse Matrices and Transforming Front Trees''} user document. \par The four simple steps described above to solve a linear system translate into a fair amount of code, as we shall see in the following sections. The user who is looking for a more gentle introduction to solving square linear systems using an $LU$ factorization, might first take a look at {\tt LinSol} directory and the user document {\it ``Wrapper Objects for Solving a Linear System of Equations using {\bf SPOOLES} 2.2''}. The {\bf SPOOLES} library has been integrated into the CSAR-Nastran finite element package, in the serial, multithreaded and MPI environments. To make the process easier, we wrote ``wrappers'' around the code found in the three driver programs. These wrapper objects insulate the user from much of the complexity of using the package. There is a cost, functionality is somewhat restricted. They are meant as learning examples rather than final code. \par In a similar way, the {\bf SPOOLES} library has been integrated into a Block-Shifted Lanczos eigensolver for symmetric eigensystems. See the {\tt Eigen} subdirectory and the user document {\it ``Integrating the {\bf SPOOLES} 2.2 Sparse Linear Algebra Library into the {\bf LANCZOS} Block-shifted Lanczos Eigensolver''}. This set of wrapper objects has also served as a model to integrate {\bf SPOOLES} into the {\bf PLANSO} eigensystem package. \par The {\bf SPOOLES} library is based on an object oriented design philosophy. There are several data structures or objects that the user must interact with. These interactions are performed with a set of methods for each object. Every object has some standard methods, such as initializing the object, placing data into the object, extracting data out of the object, writing and reading the object to a input/output file, printing the contents of the object to a specified file, and freeing the object. \par For example, consider the {\tt DenseMtx} object that models a dense matrix. The {\tt DenseMtx/DenseMtx.h} header file defines the object's C struct and has prototypes (with extensive comments) of the object's methods. The source files are found in the {\tt DenseMtx/src} directory. The \LaTeX\ documentation files are found in the {\tt DenseMtx/doc} directory. The files can be used to create the {\tt DenseMtx} object's chapter in the Reference Manual, or in a standalone manner to generate the object's documentation. The {\tt DenseMtx/drivers} directory contains driver programs that exercise and validate the object's functionality. \par Almost all the methods in the library are associated with a particular object. There are some exceptions, mostly found in the {\tt misc/src} directory. The {\tt misc/drivers} directory contains the serial $LU$ and $QR$ driver programs. The {\tt MT/drivers} and {\tt MPI/drivers} directories contain the multithreaded and MPI $LU$ driver programs. documentation/AllInOne/main.aux010064400020550007177000000124550665314563700200740ustar00clevecompmath00000400000006\relax \bibstyle{plain} \@writefile{toc}{\contentsline {section}{\numberline {1}Overview}{4}} \newlabel{chapter:overview}{{1}{4}} \@writefile{toc}{\contentsline {section}{\numberline {2}Serial Solution of $A X = Y$ using an $LU$ factorization}{6}} \newlabel{section:LU-serial}{{2}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Reading the input parameters}{6}} \newlabel{subsection:serial:input-data}{{2.1}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2}Communicating the data for the problem}{6}} \newlabel{subsection:serial:communicating-data}{{2.2}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.3}Reordering the linear system}{9}} \newlabel{subsection:serial:reordering}{{2.3}{9}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.4}Non-numeric work}{9}} \newlabel{subsection:serial:non-numeric}{{2.4}{9}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.5}The Matrix Factorization}{10}} \newlabel{subsection:serial:factor}{{2.5}{10}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.6}The Forward and Backsolves}{11}} \newlabel{subsection:serial:solve}{{2.6}{11}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.7}Sample Matrix and Right Hand Side Files}{12}} \newlabel{subsection:serial:input-files}{{2.7}{12}} \@writefile{toc}{\contentsline {section}{\numberline {3}Multithreaded Solution of $A X = Y$ using an $LU$ factorization}{13}} \newlabel{section:LU-MT}{{3}{13}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.1}Reading the input parameters}{13}} \newlabel{subsection:MT:input-data}{{3.1}{13}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Communicating the data for the problem}{13}} \newlabel{subsection:MT:communicating-data}{{3.2}{13}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.3}Reordering the linear system}{13}} \newlabel{subsection:MT:reordering}{{3.3}{13}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.4}Non-numeric work}{13}} \newlabel{subsection:MT:non-numeric}{{3.4}{13}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.5}The Matrix Factorization}{14}} \newlabel{subsection:MT:factor}{{3.5}{14}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.6}The Forward and Backsolves}{15}} \newlabel{subsection:MT:solve}{{3.6}{15}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.7}Sample Matrix and Right Hand Side Files}{15}} \newlabel{subsection:MT:input-files}{{3.7}{15}} \@writefile{toc}{\contentsline {section}{\numberline {4}MPI Solution of $A X = Y$ using an $LU$ factorization}{16}} \newlabel{section:LU-MPI}{{4}{16}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.1}Reading the input parameters}{16}} \newlabel{subsection:MPI:input-data}{{4.1}{16}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.2}Communicating the data for the problem}{16}} \newlabel{subsection:MPI:communicating-data}{{4.2}{16}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.3}Reordering the linear system}{16}} \newlabel{subsection:MPI:reordering}{{4.3}{16}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.4}Non-numeric work}{17}} \newlabel{subsection:MPI:non-numeric}{{4.4}{17}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.5}The Matrix Factorization}{18}} \newlabel{subsection:MPI:factor}{{4.5}{18}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.6}The Forward and Backsolves}{19}} \newlabel{subsection:MPI:solve}{{4.6}{19}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.7}Sample Matrix and Right Hand Side Files}{20}} \newlabel{subsection:MPI:input-files}{{4.7}{20}} \@writefile{toc}{\contentsline {section}{\numberline {5}Serial Solution of $A X = Y$ using an $QR$ factorization}{21}} \newlabel{section:QR-serial}{{5}{21}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.1}Reading the input parameters}{21}} \newlabel{subsection:QR:input-data}{{5.1}{21}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.2}Communicating the data for the problem}{21}} \newlabel{subsection:QR:communicating-data}{{5.2}{21}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.3}Reordering the linear system}{21}} \newlabel{subsection:QR:reordering}{{5.3}{21}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.4}Non-numeric work}{21}} \newlabel{subsection:QR:non-numeric}{{5.4}{21}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.5}The Matrix Factorization}{22}} \newlabel{subsection:QR:factor}{{5.5}{22}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.6}Solving the linear system}{23}} \newlabel{subsection:QR:solve}{{5.6}{23}} \@writefile{toc}{\contentsline {subsection}{\numberline {5.7}Sample Matrix and Right Hand Side Files}{23}} \newlabel{subsection:QR:input-files}{{5.7}{23}} \@writefile{toc}{\contentsline {section}{\numberline {A}{\tt allInOne.c} -- A Serial $LU$ Driver Program}{24}} \newlabel{section:LU-serial-driver}{{A}{24}} \@writefile{toc}{\contentsline {section}{\numberline {B}{\tt allInOne.c} -- A Serial $LU$ Driver Program}{31}} \newlabel{section:LU-MT-driver}{{B}{31}} \@writefile{toc}{\contentsline {section}{\numberline {C}{\tt allInOne.c} -- A Serial $LU$ Driver Program}{39}} \newlabel{section:LU-MPI-driver}{{C}{39}} \@writefile{toc}{\contentsline {section}{\numberline {D}{\tt allInOne.c} -- A Serial $QR$ Driver Program}{49}} \newlabel{section:QR-serial-driver}{{D}{49}} c}{\contentsline {section}{\numberline {3}Multithreaded Solution of $A X = Y$ using an $LU$ factorization}{13}} \newlabel{section:LU-MT}{{3}{13}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.1}Readdocumentation/AllInOne/main.idx010064400020550007177000000000000665314563100200340ustar00clevecompmath00000400000006documentation/AllInOne/main.log010064400020550007177000000205250665314563700200550ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 25 JAN 1999 11:52 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/article.cls Document Class: article 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@section=\count80 \c@subsection=\count81 \c@subsubsection=\count82 \c@paragraph=\count83 \c@subparagraph=\count84 \c@figure=\count85 \c@table=\count86 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file main.idx (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: External font `cmex10' loaded for size (Font) <12> on input line 55. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 55. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 55. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 55. [1 ] (main.toc LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 2. ) \tf@toc=\write5 (intro.tex [2] [3] LaTeX Font Info: Try loading font information for OMS+cmr on input line 16. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 16. [4]) (LU_serial.tex [5] LaTeX Font Info: External font `cmex10' loaded for size (Font) <14.4> on input line 3. [6] [7] [8] [9] Overfull \hbox (2.16098pt too wide) in paragraph at lines 358--363 \OT1/cmr/m/n/10 The nu-meric fac-tor-iza-tion step be-gins by ini-tial-iz-ing t he \OT1/cmtt/m/n/10 FrontMtx \OT1/cmr/m/n/10 ob-ject with the \OT1/cmtt/m/n/10 frontETree \OT1/cmr/m/n/10 and \OT1/cmtt/m/n/10 symbacIVL [] [10] [11]) (LU_MT.tex [12] [13] [14] Overfull \hbox (0.49548pt too wide) in paragraph at lines 186--188 \OT1/cmr/m/n/10 This ob-ject also uses a do-main de-com-po-si-tion map, the onl y solve map that presently found in the \OT1/cmr/bx/n/10 SPOOLES [] ) (LU_MPI.tex [15] [16] Overfull \hbox (7.99084pt too wide) in paragraph at lines 149--149 []\OT1/cmtt/m/n/10 IVgather(neqns, IV_entries(vtxmapIV), IV_entries(ownersIV), ETree_vtxToFront(frontETree)) ;[] [] [17] [18] Overfull \hbox (0.49548pt too wide) in paragraph at lines 248--250 \OT1/cmr/m/n/10 This ob-ject also uses a do-main de-com-po-si-tion map, the onl y solve map that presently found in the \OT1/cmr/bx/n/10 SPOOLES [] Overfull \hbox (2.74089pt too wide) in paragraph at lines 256--256 []\OT1/cmtt/m/n/10 FrontMtx_MPI_split(frontmtx, solvemap, stats, msglvl, msgFil e, firsttag, MPI_COMM_WORLD) ;[] [] [19]) (QR_serial.tex [20] [21] Overfull \hbox (2.16098pt too wide) in paragraph at lines 115--120 \OT1/cmr/m/n/10 The nu-meric fac-tor-iza-tion step be-gins by ini-tial-iz-ing t he \OT1/cmtt/m/n/10 FrontMtx \OT1/cmr/m/n/10 ob-ject with the \OT1/cmtt/m/n/10 frontETree \OT1/cmr/m/n/10 and \OT1/cmtt/m/n/10 symbacIVL [] [22] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 0 1 1.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 0 3 2.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 1 2 3.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 1 3 1.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 1 5 1.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 2 0 1.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 2 2 2.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 3 0 3.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 3 2 4.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 3 4 2.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 4 3 1.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 5 1 2.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 5 4 3.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 5 5 1.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 6 0 2.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 6 3 3.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 7 1 1.0[] [] Overfull \hbox (0.61469pt too wide) in paragraph at lines 226--226 []\OT1/cmtt/m/n/10 7 4 3.0[] [] ) (LU_serial_driver.tex [23] [24] Underfull \vbox (badness 10000) has occurred while \output is active [] [25] Underfull \vbox (badness 10000) has occurred while \output is active [] [26] Underfull \vbox (badness 10000) has occurred while \output is active [] [27] Underfull \vbox (badness 10000) has occurred while \output is active [] [28] Underfull \vbox (badness 10000) has occurred while \output is active [] [29]) (LU_MT_driver.tex [30] [31] Underfull \vbox (badness 10000) has occurred while \output is active [] [32] Underfull \vbox (badness 10000) has occurred while \output is active [] [33] Underfull \vbox (badness 10000) has occurred while \output is active [] [34] Underfull \vbox (badness 10000) has occurred while \output is active [] [35] Underfull \vbox (badness 10000) has occurred while \output is active [] [36] Underfull \vbox (badness 10000) has occurred while \output is active [] [37]) (LU_MPI_driver.tex [38] [39] Underfull \vbox (badness 10000) has occurred while \output is active [] [40] Underfull \vbox (badness 10000) has occurred while \output is active [] [41] Underfull \vbox (badness 10000) has occurred while \output is active [] [42] Underfull \vbox (badness 10000) has occurred while \output is active [] [43] Underfull \vbox (badness 10000) has occurred while \output is active [] [44] Underfull \vbox (badness 10000) has occurred while \output is active [] [45] Underfull \vbox (badness 10000) has occurred while \output is active [] [46] Underfull \vbox (badness 10000) has occurred while \output is active [] [47]) (QR_serial_driver.tex [48] [49] Underfull \vbox (badness 10000) has occurred while \output is active [] [50] Underfull \vbox (badness 10000) has occurred while \output is active [] [51] Underfull \vbox (badness 10000) has occurred while \output is active [] [52] Underfull \vbox (badness 10000) has occurred while \output is active [] [53]) [54] (main.aux) ) Here is how much of TeX's memory you used: 580 strings out of 10908 6266 string characters out of 72189 63903 words of memory out of 262141 3468 multiletter control sequences out of 9500 10666 words of font info for 39 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 30i,11n,21p,160b,391s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (54 pages, 146964 bytes). x file main.idx (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-ddocumentation/AllInOne/main.tex010064400020550007177000000031540664720142500200620ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,10pt,twoside]{article} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \input psfig \newcommand{\bfi}{{\bf i}} \newcommand{\bfj}{{\bf j}} \newcommand{\bnd}[1]{{\partial{#1}}} \newcommand\WHILE{{\bf while}} \newcommand\IF{{\bf if}} \newcommand\END{{\bf end}} \newcommand\ELSE{{\bf else}} \newcommand\THEN{{\bf then}} \pagestyle{myheadings} % \markboth % {\quad \hrulefill \quad {\bf SPOOLES 2.2} : \today \quad \hrulefill} % {\quad \hrulefill \quad {\bf SPOOLES 2.2} : \quad \today \hrulefill} \markboth {\hspace*{0.5 in} {\bf SPOOLES 2.2} --- Solving Linear Systems \quad\hrulefill\quad\today} {\today \quad\hrulefill\quad {\bf SPOOLES 2.2} --- Solving Linear Systems \hspace*{0.5 in}} \begin{document} \bibliographystyle{plain} \title{ Solving Linear Systems using {\bf SPOOLES 2.2} } \author{C. C. Ashcraft, R. G. Grimes, D. J. Pierce, D. K. Wah \\ Boeing Phantom Works\thanks{ P. O. Box 24346, Mail Stop 7L-22, Seattle, Washington 98124. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} } \date{\today} \maketitle \vfill \eject \tableofcontents \input intro.tex \input LU_serial.tex \input LU_MT.tex \input LU_MPI.tex \input QR_serial.tex \appendix \input LU_serial_driver.tex \input LU_MT_driver.tex \input LU_MPI_driver.tex \input QR_serial_driver.tex \end{document} documentation/AllInOne/main.toc010064400020550007177000000057160665314563700200660ustar00clevecompmath00000400000006\contentsline {section}{\numberline {1}Overview}{4} \contentsline {section}{\numberline {2}Serial Solution of $A X = Y$ using an $LU$ factorization}{6} \contentsline {subsection}{\numberline {2.1}Reading the input parameters}{6} \contentsline {subsection}{\numberline {2.2}Communicating the data for the problem}{6} \contentsline {subsection}{\numberline {2.3}Reordering the linear system}{9} \contentsline {subsection}{\numberline {2.4}Non-numeric work}{9} \contentsline {subsection}{\numberline {2.5}The Matrix Factorization}{10} \contentsline {subsection}{\numberline {2.6}The Forward and Backsolves}{11} \contentsline {subsection}{\numberline {2.7}Sample Matrix and Right Hand Side Files}{12} \contentsline {section}{\numberline {3}Multithreaded Solution of $A X = Y$ using an $LU$ factorization}{13} \contentsline {subsection}{\numberline {3.1}Reading the input parameters}{13} \contentsline {subsection}{\numberline {3.2}Communicating the data for the problem}{13} \contentsline {subsection}{\numberline {3.3}Reordering the linear system}{13} \contentsline {subsection}{\numberline {3.4}Non-numeric work}{13} \contentsline {subsection}{\numberline {3.5}The Matrix Factorization}{14} \contentsline {subsection}{\numberline {3.6}The Forward and Backsolves}{15} \contentsline {subsection}{\numberline {3.7}Sample Matrix and Right Hand Side Files}{15} \contentsline {section}{\numberline {4}MPI Solution of $A X = Y$ using an $LU$ factorization}{16} \contentsline {subsection}{\numberline {4.1}Reading the input parameters}{16} \contentsline {subsection}{\numberline {4.2}Communicating the data for the problem}{16} \contentsline {subsection}{\numberline {4.3}Reordering the linear system}{16} \contentsline {subsection}{\numberline {4.4}Non-numeric work}{17} \contentsline {subsection}{\numberline {4.5}The Matrix Factorization}{18} \contentsline {subsection}{\numberline {4.6}The Forward and Backsolves}{19} \contentsline {subsection}{\numberline {4.7}Sample Matrix and Right Hand Side Files}{20} \contentsline {section}{\numberline {5}Serial Solution of $A X = Y$ using an $QR$ factorization}{21} \contentsline {subsection}{\numberline {5.1}Reading the input parameters}{21} \contentsline {subsection}{\numberline {5.2}Communicating the data for the problem}{21} \contentsline {subsection}{\numberline {5.3}Reordering the linear system}{21} \contentsline {subsection}{\numberline {5.4}Non-numeric work}{21} \contentsline {subsection}{\numberline {5.5}The Matrix Factorization}{22} \contentsline {subsection}{\numberline {5.6}Solving the linear system}{23} \contentsline {subsection}{\numberline {5.7}Sample Matrix and Right Hand Side Files}{23} \contentsline {section}{\numberline {A}{\tt allInOne.c} -- A Serial $LU$ Driver Program}{24} \contentsline {section}{\numberline {B}{\tt allInOne.c} -- A Serial $LU$ Driver Program}{31} \contentsline {section}{\numberline {C}{\tt allInOne.c} -- A Serial $LU$ Driver Program}{39} \contentsline {section}{\numberline {D}{\tt allInOne.c} -- A Serial $QR$ Driver Program}{49} documentation/AllInOne/makefile010064400020550007177000000000270665014155300201070ustar00clevecompmath00000400000006clean : - rm -f *.dvi documentation/FrontTrees/004275500020550007177000000000000665314620000170445ustar00clevecompmath00000400000006documentation/FrontTrees/background.tex010064400020550007177000000265320663202361300217070ustar00clevecompmath00000400000006\section{Algorithmic Background} \label{section:background} \par {\bf SPOOLES} is an attempt to provide the capability for solving sparse systems of linear equations for a diverse set of applications on a diverse set of parallel computers. We have included innovative approaches for the ordering of sparse matrices. We have also taken an object oriented approach to providing the sparse matrix technology which is different from the more traditional subroutine library approach. The algorithms for the numerical factorization and solve steps are based on established algorithms. \par The purpose of this chapter is to give a quick overview of the algorithms used in {\bf SPOOLES}. We will leave the complete description of the algorithms to the references. \par \subsection{Ordering a sparse matrix} \label{subsection:intro:ordering} \par The past few years have seen a resurgence of interest and accompanying improvement in algorithms and software to order sparse matrices. The minimum degree algorithm, specifically the multiple external minimum degree algorithm \cite{liu85-mmd}, was the preferred algorithm of choice for the better part of a decade. Alternative minimum priority codes have recently pushed multiple minimum degree aside, including approximate minimum degree \cite{ame96-amd} and approximate deficiency \cite{ng96-mindefIdaho}, \cite{rot96-mindefIdaho}. They offer improved quality or improved run time, and on occasion, both. \par Nested dissection for regular grids \cite{geo73-nested} is within a factor of optimal with respect to factor entries and operation counts. One of the earliest attempts, automatic nested dissection \cite{geo81-book} used a simple profile algorithm to find separators. It rarely performed as well as minimum degree. Better heuristics to find separators were brought in from the electrical device simulation area \cite{lei89-fidmat} and while these algorithms produced better orderings, the run times kept them from practical application. Nested dissection came on its own with two developments. The first was the application of spectral analysis of graphs to find separators \cite{pot90-partition}. The eigenvector associated with the smallest nonzero eigenvalue of the Laplacian of a graph generates a spectrum of separators. While the ordering times for spectral nested dissection were still on the order of ten or more times the cost of a minimum degree ordering, the ordering quality sometimes made the cost worthwhile. \par The key that made nested dissection a competitive and practical alternative to minimum degree was the introduction of multilevel ideas --- to find a separator on a graph, first find a separator on a coarse graph and project back to the original. Early implementations include \cite{bar93-partition} and \cite{bui93-partition}. Multilevel algorithms are very popular in current software including {\bf CHACO} \cite{hen93-chaco}, \cite{hen93-partition}, {\bf METIS} \cite{kar95-multilevel}, \cite{kar95-metis}, {\bf BEND} \cite{hr96-msnd}, {\bf WGGP} \cite{gup96-WGPP} and {\bf PCO} \cite{rag95-PCO}. \par {\bf SPOOLES} also includes a hybrid ordering approach called multi-section \cite{ash95-DDSEP}, \cite{ash96-maxflow}, \cite{ash96-multisection} and \cite{ro95-hybrid}. For some types of graphs, nested dissection does much better than minimum degree, for others much worse. Multisection is an ordering that uses both nested dissection and minimum degree to create an ordering that is almost always as good or better than the better of nested dissection or minimum degree and rarely much worse. \par \subsection{Background on permutations and trees} \label{subsection:order:background} \par Two important structures that are used in the solution of sparse systems of equations are permutations and trees. Because of the object oriented nature of the {\bf SPOOLES} library the user needs to know some information about these structures. \par For an example, let us examine the matrix R2D100, a matrix generated by first randomly triangulating the unit square with 100 grid points. The resulting matrix has 100 rows and columns. We ordered the matrix using a generalized nested dissection algorithm from the {\bf SPOOLES} library, and present the vertex elimination tree for this ordering in Figure~\ref{fig:R2D100-tree-vtx}. The vertex elimination tree is a representation of the order that the vertices in the graph will be eliminated. This order corresponds to the order that the rows and columns will be factored for a square $A$. The dependencies of the order form a tree structure. The leaves of the tree (our trees hang upside down with the leaves at the bottom and the root at the top) represent vertices which can be eliminate first. The parents of those leaf nodes can be eliminated next, and so on, until finally the vertices represented by the root of the tree will be eliminated last. \par \begin{figure}[htbp] \caption{Elimination tree for R2D100, 100 rows and columns} \label{fig:R2D100-tree-vtx} \begin{center} \mbox{ \psfig{file=R2D100vtx.eps,width=5.0in,height=5.00in} } \end{center} \end{figure} \par The elimination tree illustrates the dependence of the vertices. The basic rule is that a vertex {\it depends} only on its descendents and will {\it affect} only its ancestors. It should be clear that the tree allows us to identify independent, parallel computation. For example, the computation of the factor entries in the subtree rooted at vertex 47 is completely independent of the subtree rooted at vertex 89, so we could identify one process to compute the left subtree and another to compute the right subtree. \par While the vertex elimination tree is useful to communicate the data dependencies, it is not a good granularity on which to base a factorization or solve, in serial or in parallel. It is important to group vertices together in some meaningful way to create larger data structures that will be more efficient with respect to storage and computation. The first step in this direction is to group together vertices that form a chain with no branches in the tree. Using this grouping we generate the {\it fundamental supernode tree} given in the bottom of Figure~\ref{fig:R2D100-tree-front}. \begin{figure}[htbp] \caption{Top: vertex elimination tree with the vertices mapped to the fundamental supernode that contains them. Bottom: fundamental supernode tree.} \label{fig:R2D100-tree-front} \begin{center} \mbox{ \psfig{file=R2D100vtxmap.eps,width=5.0in,height=5.00in} } \par \mbox{ \psfig{file=R2D100front.eps,width=5.0in,height=2.50in} } \end{center} \end{figure} \par A factorization based on the fundamental supernode tree requires no more operations than one based on the vertex elimination tree. There are many small supernodes at the lower levels of the tree. By {\it amalgamating} small but connected sets of supernodes together into larger supernodes we can reduce the overhead of the processing all of the small supernodes at the expense of adding entries to the factors and operations to compute the factorization. This amalgamation of supernodes generally leads to an overall increase in efficiency. We call the result of the {\it amalgamated} supernode tree. \par The tree in the bottom of Figure~\ref{fig:R2D100-tree-comp} was obtained by allowing up to twenty logically zero entries into the block column for a supernode. The top tree shows the fundamental supernodes mapped to their amalgamated supernodes. \par \begin{figure}[htbp] \caption{Top: fundamental supernode tree with the supernodes mapped to the amalgamated supernode that contains them. Bottom: amalgamated supernode tree.} \label{fig:R2D100-tree-comp} \begin{center} \mbox{ \psfig{file=R2D100frontmap.eps,width=5.0in,height=2.50in} } \par \mbox{ \psfig{file=R2D100comp.eps,width=3.0in,height=2.00in} } \end{center} \end{figure} \par There is one final step to constructing the tree that governs the factorization and solve. Large matrices will generate large supernodes at the topmost levels of the tree. For example, a $k \times k \times k$ grid with a 27 point finite difference operator, when ordered by nested dissection, has a root supernode with $k^2$ rows and columns. The data structure for a top level supernode can be very large, too large to fit into memory. In a parallel environment, we follow the convention that each node in the tree is handled by one process. Having a very large node at the top levels of the tree will severely decrease the parallelism available to the computations. \par The solution to both problems, large data structures and limited parallelism, is to split large supernodes into pieces. We can specify a maximum size for the nodes in the tree, and split the large supernode into pieces no larger than this maximum size. This will keep the data structures to a manageable size and increase the available parallelism. We call the resulting tree the {\it front} tree because it represents the final computational unit for the factorization, the frontal matrix. \par The amalgamated supernode tree has been transformed so that except for the leaf nodes, which are not changed, no node in the tree has more than four vertices. The new tree is given on the left of Figure~\ref{fig:R2D100-tree-split}, while the right tree shows maps the nodes back to the amalgamated supernode tree. Splitting large nodes into smaller nodes will not increase the factor storage or operation counts. \par \begin{figure}[htbp] \caption{Left: tree after the large supernodes have been split. Right: tree with nodes mapped back to their amalgamated supernode.} \label{fig:R2D100-tree-split} \begin{center} \mbox{ \psfig{file=R2D100split.eps,width=3.00in,height=3.000in} } \quad \mbox{ \psfig{file=R2D100splitmap.eps,width=3.00in,height=3.000in} } \end{center} \end{figure} \par This front tree is now the defining structure for the numerical factorization and solve steps. The structure of the front tree defines the order of the computations that will be carried out in the factorization and the solve. The methods for almagamating and splitting to produce the front tree is found in Section~\ref{chapter:manipulating:ETree}. \par \subsection{Matrix factorization and solves} \label{subsection:intro:solve} \par One of the most important design consideration for our numeric software is to support pivoting for numerical stability. Much of the time pivoting for stability is not needed --- when matrices are diagonally dominant or well conditioned positive definite --- but there are cases where pivoting is crucial. \par For symmetric matrices we use the fast Bunch-Parlett algorithm to choose $1 \times 1$ or $2 \times 2$ pivots \cite{ash95-AGL}. For non-symmetric matrices we use its analogue. It has recently come to our attention that this pivoting strategy has been known as {\it rook pivoting} \cite{fo96-rook}, \cite{ne92-rook}. We compute the factorization $P L D U Q$ or $P U^T D U P^T$ where $L$ is unit lower triangular, $U$ is unit upper triangular, and $P$ and $Q$ are permutation matrices. When pivoting is enabled, the magnitude of entries in $L$ and $U$ are bound by some user supplied tolerance. \par For the {\bf SPOOLES} library we chose to implement the fan-in algorithm for the numerical factorization \cite{ash90-fan-in}. When it is time to begin the computations for a given front, the processor owning the rows and columns for that front receive the modification to that front from previously computed fronts which are owned by other processors. The incoming modification is computed by the processor that owns the previously computed front. Idaho}. They offer improved quality or improved run time, and on occasion, both. \par Nested dissection for regular grids \cite{geo73-nested} is within a factor of odocumentation/FrontTrees/R2D100comp.eps010064400020550007177000000044410663202231100212330ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 300 200 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 280 180 rectstroke newpath 280 30 280 80 ML 280 80 264 130 ML 249 80 264 130 ML 264 130 151 180 ML 218 80 186 130 ML 186 80 186 130 ML 155 80 186 130 ML 186 130 151 180 ML 124 80 108 130 ML 92.5 30 92.5 80 ML 92.5 80 108 130 ML 108 130 151 180 ML 61.2 80 45.6 130 ML 30 80 45.6 130 ML 45.6 130 151 180 ML stroke gsave /Helvetica-Bold findfont 12.5 scalefont setfont 1.0 setgray 280 30 10 FC 0.0 setgray 280 30 10 OC 280 25 moveto (0) CSH 1.0 setgray 280 80 10 FC 0.0 setgray 280 80 10 OC 280 75 moveto (1) CSH 1.0 setgray 249 80 10 FC 0.0 setgray 249 80 10 OC 249 75 moveto (2) CSH 1.0 setgray 264 130 10 FC 0.0 setgray 264 130 10 OC 264 125 moveto (3) CSH 1.0 setgray 218 80 10 FC 0.0 setgray 218 80 10 OC 218 75 moveto (4) CSH 1.0 setgray 186 80 10 FC 0.0 setgray 186 80 10 OC 186 75 moveto (5) CSH 1.0 setgray 155 80 10 FC 0.0 setgray 155 80 10 OC 155 75 moveto (6) CSH 1.0 setgray 186 130 10 FC 0.0 setgray 186 130 10 OC 186 125 moveto (7) CSH 1.0 setgray 124 80 10 FC 0.0 setgray 124 80 10 OC 124 75 moveto (8) CSH 1.0 setgray 92.5 30 10 FC 0.0 setgray 92.5 30 10 OC 92.5 25 moveto (9) CSH 1.0 setgray 92.5 80 10 FC 0.0 setgray 92.5 80 10 OC 92.5 75 moveto (10) CSH 1.0 setgray 108 130 10 FC 0.0 setgray 108 130 10 OC 108 125 moveto (11) CSH 1.0 setgray 61.2 80 10 FC 0.0 setgray 61.2 80 10 OC 61.2 75 moveto (12) CSH 1.0 setgray 30 80 10 FC 0.0 setgray 30 80 10 OC 30 75 moveto (13) CSH 1.0 setgray 45.6 130 10 FC 0.0 setgray 45.6 130 10 OC 45.6 125 moveto (14) CSH 1.0 setgray 151 180 10 FC 0.0 setgray 151 180 10 OC 151 175 moveto (15) CSH grestore showpage documentation/FrontTrees/R2D100front.eps010064400020550007177000000205100663202231100214200ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 300 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 580 280 rectstroke newpath 30 105 30 130 ML 30 130 30 155 ML 30 155 50.6 180 ML 57.5 105 57.5 130 ML 57.5 130 71.2 155 ML 85 130 71.2 155 ML 71.2 155 50.6 180 ML 50.6 180 50.6 205 ML 50.6 205 88.4 230 ML 112 180 126 205 ML 140 155 140 180 ML 140 180 126 205 ML 126 205 88.4 230 ML 88.4 230 162 255 ML 168 130 181 155 ML 195 130 181 155 ML 181 155 181 180 ML 181 180 202 205 ML 222 105 222 130 ML 222 130 222 155 ML 222 155 222 180 ML 222 180 202 205 ML 202 205 236 230 ML 250 180 271 205 ML 278 105 291 130 ML 305 80 305 105 ML 305 105 291 130 ML 291 130 291 155 ML 291 155 291 180 ML 291 180 271 205 ML 271 205 236 230 ML 236 230 162 255 ML 162 255 302 280 ML 332 30 332 55 ML 332 55 332 80 ML 332 80 332 105 ML 332 105 332 130 ML 332 130 332 155 ML 332 155 332 180 ML 332 180 332 205 ML 332 205 357 230 ML 360 130 360 155 ML 360 155 360 180 ML 360 180 381 205 ML 388 80 388 105 ML 388 105 388 130 ML 388 130 388 155 ML 388 155 401 180 ML 415 155 401 180 ML 401 180 381 205 ML 381 205 357 230 ML 357 230 441 255 ML 442 130 442 155 ML 442 155 456 180 ML 470 130 470 155 ML 470 155 456 180 ML 456 180 484 205 ML 498 130 498 155 ML 498 155 511 180 ML 525 155 511 180 ML 511 180 484 205 ML 484 205 525 230 ML 552 130 552 155 ML 552 155 552 180 ML 552 180 566 205 ML 580 130 580 155 ML 580 155 580 180 ML 580 180 566 205 ML 566 205 525 230 ML 525 230 441 255 ML 441 255 302 280 ML stroke gsave /Helvetica-Bold findfont 12.5 scalefont setfont 1.0 setgray 30 105 10 FC 0.0 setgray 30 105 10 OC 30 100 moveto (0) CSH 1.0 setgray 30 130 10 FC 0.0 setgray 30 130 10 OC 30 125 moveto (1) CSH 1.0 setgray 30 155 10 FC 0.0 setgray 30 155 10 OC 30 150 moveto (2) CSH 1.0 setgray 57.5 105 10 FC 0.0 setgray 57.5 105 10 OC 57.5 100 moveto (3) CSH 1.0 setgray 57.5 130 10 FC 0.0 setgray 57.5 130 10 OC 57.5 125 moveto (4) CSH 1.0 setgray 85 130 10 FC 0.0 setgray 85 130 10 OC 85 125 moveto (5) CSH 1.0 setgray 71.2 155 10 FC 0.0 setgray 71.2 155 10 OC 71.2 150 moveto (6) CSH 1.0 setgray 50.6 180 10 FC 0.0 setgray 50.6 180 10 OC 50.6 175 moveto (7) CSH 1.0 setgray 50.6 205 10 FC 0.0 setgray 50.6 205 10 OC 50.6 200 moveto (8) CSH 1.0 setgray 112 180 10 FC 0.0 setgray 112 180 10 OC 112 175 moveto (9) CSH 1.0 setgray 140 155 10 FC 0.0 setgray 140 155 10 OC 140 150 moveto (10) CSH 1.0 setgray 140 180 10 FC 0.0 setgray 140 180 10 OC 140 175 moveto (11) CSH 1.0 setgray 126 205 10 FC 0.0 setgray 126 205 10 OC 126 200 moveto (12) CSH 1.0 setgray 88.4 230 10 FC 0.0 setgray 88.4 230 10 OC 88.4 225 moveto (13) CSH 1.0 setgray 168 130 10 FC 0.0 setgray 168 130 10 OC 168 125 moveto (14) CSH 1.0 setgray 195 130 10 FC 0.0 setgray 195 130 10 OC 195 125 moveto (15) CSH 1.0 setgray 181 155 10 FC 0.0 setgray 181 155 10 OC 181 150 moveto (16) CSH 1.0 setgray 181 180 10 FC 0.0 setgray 181 180 10 OC 181 175 moveto (17) CSH 1.0 setgray 222 105 10 FC 0.0 setgray 222 105 10 OC 222 100 moveto (18) CSH 1.0 setgray 222 130 10 FC 0.0 setgray 222 130 10 OC 222 125 moveto (19) CSH 1.0 setgray 222 155 10 FC 0.0 setgray 222 155 10 OC 222 150 moveto (20) CSH 1.0 setgray 222 180 10 FC 0.0 setgray 222 180 10 OC 222 175 moveto (21) CSH 1.0 setgray 202 205 10 FC 0.0 setgray 202 205 10 OC 202 200 moveto (22) CSH 1.0 setgray 250 180 10 FC 0.0 setgray 250 180 10 OC 250 175 moveto (23) CSH 1.0 setgray 278 105 10 FC 0.0 setgray 278 105 10 OC 278 100 moveto (24) CSH 1.0 setgray 305 80 10 FC 0.0 setgray 305 80 10 OC 305 75 moveto (25) CSH 1.0 setgray 305 105 10 FC 0.0 setgray 305 105 10 OC 305 100 moveto (26) CSH 1.0 setgray 291 130 10 FC 0.0 setgray 291 130 10 OC 291 125 moveto (27) CSH 1.0 setgray 291 155 10 FC 0.0 setgray 291 155 10 OC 291 150 moveto (28) CSH 1.0 setgray 291 180 10 FC 0.0 setgray 291 180 10 OC 291 175 moveto (29) CSH 1.0 setgray 271 205 10 FC 0.0 setgray 271 205 10 OC 271 200 moveto (30) CSH 1.0 setgray 236 230 10 FC 0.0 setgray 236 230 10 OC 236 225 moveto (31) CSH 1.0 setgray 162 255 10 FC 0.0 setgray 162 255 10 OC 162 250 moveto (32) CSH 1.0 setgray 332 30 10 FC 0.0 setgray 332 30 10 OC 332 25 moveto (33) CSH 1.0 setgray 332 55 10 FC 0.0 setgray 332 55 10 OC 332 50 moveto (34) CSH 1.0 setgray 332 80 10 FC 0.0 setgray 332 80 10 OC 332 75 moveto (35) CSH 1.0 setgray 332 105 10 FC 0.0 setgray 332 105 10 OC 332 100 moveto (36) CSH 1.0 setgray 332 130 10 FC 0.0 setgray 332 130 10 OC 332 125 moveto (37) CSH 1.0 setgray 332 155 10 FC 0.0 setgray 332 155 10 OC 332 150 moveto (38) CSH 1.0 setgray 332 180 10 FC 0.0 setgray 332 180 10 OC 332 175 moveto (39) CSH 1.0 setgray 332 205 10 FC 0.0 setgray 332 205 10 OC 332 200 moveto (40) CSH 1.0 setgray 360 130 10 FC 0.0 setgray 360 130 10 OC 360 125 moveto (41) CSH 1.0 setgray 360 155 10 FC 0.0 setgray 360 155 10 OC 360 150 moveto (42) CSH 1.0 setgray 360 180 10 FC 0.0 setgray 360 180 10 OC 360 175 moveto (43) CSH 1.0 setgray 388 80 10 FC 0.0 setgray 388 80 10 OC 388 75 moveto (44) CSH 1.0 setgray 388 105 10 FC 0.0 setgray 388 105 10 OC 388 100 moveto (45) CSH 1.0 setgray 388 130 10 FC 0.0 setgray 388 130 10 OC 388 125 moveto (46) CSH 1.0 setgray 388 155 10 FC 0.0 setgray 388 155 10 OC 388 150 moveto (47) CSH 1.0 setgray 415 155 10 FC 0.0 setgray 415 155 10 OC 415 150 moveto (48) CSH 1.0 setgray 401 180 10 FC 0.0 setgray 401 180 10 OC 401 175 moveto (49) CSH 1.0 setgray 381 205 10 FC 0.0 setgray 381 205 10 OC 381 200 moveto (50) CSH 1.0 setgray 357 230 10 FC 0.0 setgray 357 230 10 OC 357 225 moveto (51) CSH 1.0 setgray 442 130 10 FC 0.0 setgray 442 130 10 OC 442 125 moveto (52) CSH 1.0 setgray 442 155 10 FC 0.0 setgray 442 155 10 OC 442 150 moveto (53) CSH 1.0 setgray 470 130 10 FC 0.0 setgray 470 130 10 OC 470 125 moveto (54) CSH 1.0 setgray 470 155 10 FC 0.0 setgray 470 155 10 OC 470 150 moveto (55) CSH 1.0 setgray 456 180 10 FC 0.0 setgray 456 180 10 OC 456 175 moveto (56) CSH 1.0 setgray 498 130 10 FC 0.0 setgray 498 130 10 OC 498 125 moveto (57) CSH 1.0 setgray 498 155 10 FC 0.0 setgray 498 155 10 OC 498 150 moveto (58) CSH 1.0 setgray 525 155 10 FC 0.0 setgray 525 155 10 OC 525 150 moveto (59) CSH 1.0 setgray 511 180 10 FC 0.0 setgray 511 180 10 OC 511 175 moveto (60) CSH 1.0 setgray 484 205 10 FC 0.0 setgray 484 205 10 OC 484 200 moveto (61) CSH 1.0 setgray 552 130 10 FC 0.0 setgray 552 130 10 OC 552 125 moveto (62) CSH 1.0 setgray 552 155 10 FC 0.0 setgray 552 155 10 OC 552 150 moveto (63) CSH 1.0 setgray 552 180 10 FC 0.0 setgray 552 180 10 OC 552 175 moveto (64) CSH 1.0 setgray 580 130 10 FC 0.0 setgray 580 130 10 OC 580 125 moveto (65) CSH 1.0 setgray 580 155 10 FC 0.0 setgray 580 155 10 OC 580 150 moveto (66) CSH 1.0 setgray 580 180 10 FC 0.0 setgray 580 180 10 OC 580 175 moveto (67) CSH 1.0 setgray 566 205 10 FC 0.0 setgray 566 205 10 OC 566 200 moveto (68) CSH 1.0 setgray 525 230 10 FC 0.0 setgray 525 230 10 OC 525 225 moveto (69) CSH 1.0 setgray 441 255 10 FC 0.0 setgray 441 255 10 OC 441 250 moveto (70) CSH 1.0 setgray 302 280 10 FC 0.0 setgray 302 280 10 OC 302 275 moveto (71) CSH grestore showpage C 0.0 setgray 30 155 10 OC 30 150 moveto (2) CSH 1.0 setgray 57.5 105 10 FC 0.0 setgray 57.5 105 10 OC 57.5 100 moveto (3) CSH 1.0 setgray 57.5 130 10 FC 0.documentation/FrontTrees/R2D100frontmap.eps010064400020550007177000000204430663202231100221230ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 300 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 580 280 rectstroke newpath 30 105 30 130 ML 30 130 30 155 ML 30 155 50.6 180 ML 57.5 105 57.5 130 ML 57.5 130 71.2 155 ML 85 130 71.2 155 ML 71.2 155 50.6 180 ML 50.6 180 50.6 205 ML 50.6 205 88.4 230 ML 112 180 126 205 ML 140 155 140 180 ML 140 180 126 205 ML 126 205 88.4 230 ML 88.4 230 162 255 ML 168 130 181 155 ML 195 130 181 155 ML 181 155 181 180 ML 181 180 202 205 ML 222 105 222 130 ML 222 130 222 155 ML 222 155 222 180 ML 222 180 202 205 ML 202 205 236 230 ML 250 180 271 205 ML 278 105 291 130 ML 305 80 305 105 ML 305 105 291 130 ML 291 130 291 155 ML 291 155 291 180 ML 291 180 271 205 ML 271 205 236 230 ML 236 230 162 255 ML 162 255 302 280 ML 332 30 332 55 ML 332 55 332 80 ML 332 80 332 105 ML 332 105 332 130 ML 332 130 332 155 ML 332 155 332 180 ML 332 180 332 205 ML 332 205 357 230 ML 360 130 360 155 ML 360 155 360 180 ML 360 180 381 205 ML 388 80 388 105 ML 388 105 388 130 ML 388 130 388 155 ML 388 155 401 180 ML 415 155 401 180 ML 401 180 381 205 ML 381 205 357 230 ML 357 230 441 255 ML 442 130 442 155 ML 442 155 456 180 ML 470 130 470 155 ML 470 155 456 180 ML 456 180 484 205 ML 498 130 498 155 ML 498 155 511 180 ML 525 155 511 180 ML 511 180 484 205 ML 484 205 525 230 ML 552 130 552 155 ML 552 155 552 180 ML 552 180 566 205 ML 580 130 580 155 ML 580 155 580 180 ML 580 180 566 205 ML 566 205 525 230 ML 525 230 441 255 ML 441 255 302 280 ML stroke gsave /Helvetica-Bold findfont 12.5 scalefont setfont 1.0 setgray 30 105 10 FC 0.0 setgray 30 105 10 OC 30 100 moveto (12) CSH 1.0 setgray 30 130 10 FC 0.0 setgray 30 130 10 OC 30 125 moveto (12) CSH 1.0 setgray 30 155 10 FC 0.0 setgray 30 155 10 OC 30 150 moveto (12) CSH 1.0 setgray 57.5 105 10 FC 0.0 setgray 57.5 105 10 OC 57.5 100 moveto (14) CSH 1.0 setgray 57.5 130 10 FC 0.0 setgray 57.5 130 10 OC 57.5 125 moveto (14) CSH 1.0 setgray 85 130 10 FC 0.0 setgray 85 130 10 OC 85 125 moveto (14) CSH 1.0 setgray 71.2 155 10 FC 0.0 setgray 71.2 155 10 OC 71.2 150 moveto (14) CSH 1.0 setgray 50.6 180 10 FC 0.0 setgray 50.6 180 10 OC 50.6 175 moveto (14) CSH 1.0 setgray 50.6 205 10 FC 0.0 setgray 50.6 205 10 OC 50.6 200 moveto (14) CSH 1.0 setgray 112 180 10 FC 0.0 setgray 112 180 10 OC 112 175 moveto (13) CSH 1.0 setgray 140 155 10 FC 0.0 setgray 140 155 10 OC 140 150 moveto (13) CSH 1.0 setgray 140 180 10 FC 0.0 setgray 140 180 10 OC 140 175 moveto (13) CSH 1.0 setgray 126 205 10 FC 0.0 setgray 126 205 10 OC 126 200 moveto (13) CSH 1.0 setgray 88.4 230 10 FC 0.0 setgray 88.4 230 10 OC 88.4 225 moveto (14) CSH 1.0 setgray 168 130 10 FC 0.0 setgray 168 130 10 OC 168 125 moveto (10) CSH 1.0 setgray 195 130 10 FC 0.0 setgray 195 130 10 OC 195 125 moveto (10) CSH 1.0 setgray 181 155 10 FC 0.0 setgray 181 155 10 OC 181 150 moveto (10) CSH 1.0 setgray 181 180 10 FC 0.0 setgray 181 180 10 OC 181 175 moveto (10) CSH 1.0 setgray 222 105 10 FC 0.0 setgray 222 105 10 OC 222 100 moveto (9) CSH 1.0 setgray 222 130 10 FC 0.0 setgray 222 130 10 OC 222 125 moveto (9) CSH 1.0 setgray 222 155 10 FC 0.0 setgray 222 155 10 OC 222 150 moveto (9) CSH 1.0 setgray 222 180 10 FC 0.0 setgray 222 180 10 OC 222 175 moveto (9) CSH 1.0 setgray 202 205 10 FC 0.0 setgray 202 205 10 OC 202 200 moveto (10) CSH 1.0 setgray 250 180 10 FC 0.0 setgray 250 180 10 OC 250 175 moveto (11) CSH 1.0 setgray 278 105 10 FC 0.0 setgray 278 105 10 OC 278 100 moveto (8) CSH 1.0 setgray 305 80 10 FC 0.0 setgray 305 80 10 OC 305 75 moveto (8) CSH 1.0 setgray 305 105 10 FC 0.0 setgray 305 105 10 OC 305 100 moveto (8) CSH 1.0 setgray 291 130 10 FC 0.0 setgray 291 130 10 OC 291 125 moveto (8) CSH 1.0 setgray 291 155 10 FC 0.0 setgray 291 155 10 OC 291 150 moveto (8) CSH 1.0 setgray 291 180 10 FC 0.0 setgray 291 180 10 OC 291 175 moveto (8) CSH 1.0 setgray 271 205 10 FC 0.0 setgray 271 205 10 OC 271 200 moveto (11) CSH 1.0 setgray 236 230 10 FC 0.0 setgray 236 230 10 OC 236 225 moveto (11) CSH 1.0 setgray 162 255 10 FC 0.0 setgray 162 255 10 OC 162 250 moveto (15) CSH 1.0 setgray 332 30 10 FC 0.0 setgray 332 30 10 OC 332 25 moveto (4) CSH 1.0 setgray 332 55 10 FC 0.0 setgray 332 55 10 OC 332 50 moveto (4) CSH 1.0 setgray 332 80 10 FC 0.0 setgray 332 80 10 OC 332 75 moveto (4) CSH 1.0 setgray 332 105 10 FC 0.0 setgray 332 105 10 OC 332 100 moveto (4) CSH 1.0 setgray 332 130 10 FC 0.0 setgray 332 130 10 OC 332 125 moveto (4) CSH 1.0 setgray 332 155 10 FC 0.0 setgray 332 155 10 OC 332 150 moveto (4) CSH 1.0 setgray 332 180 10 FC 0.0 setgray 332 180 10 OC 332 175 moveto (4) CSH 1.0 setgray 332 205 10 FC 0.0 setgray 332 205 10 OC 332 200 moveto (4) CSH 1.0 setgray 360 130 10 FC 0.0 setgray 360 130 10 OC 360 125 moveto (5) CSH 1.0 setgray 360 155 10 FC 0.0 setgray 360 155 10 OC 360 150 moveto (5) CSH 1.0 setgray 360 180 10 FC 0.0 setgray 360 180 10 OC 360 175 moveto (5) CSH 1.0 setgray 388 80 10 FC 0.0 setgray 388 80 10 OC 388 75 moveto (6) CSH 1.0 setgray 388 105 10 FC 0.0 setgray 388 105 10 OC 388 100 moveto (6) CSH 1.0 setgray 388 130 10 FC 0.0 setgray 388 130 10 OC 388 125 moveto (6) CSH 1.0 setgray 388 155 10 FC 0.0 setgray 388 155 10 OC 388 150 moveto (6) CSH 1.0 setgray 415 155 10 FC 0.0 setgray 415 155 10 OC 415 150 moveto (7) CSH 1.0 setgray 401 180 10 FC 0.0 setgray 401 180 10 OC 401 175 moveto (7) CSH 1.0 setgray 381 205 10 FC 0.0 setgray 381 205 10 OC 381 200 moveto (7) CSH 1.0 setgray 357 230 10 FC 0.0 setgray 357 230 10 OC 357 225 moveto (7) CSH 1.0 setgray 442 130 10 FC 0.0 setgray 442 130 10 OC 442 125 moveto (3) CSH 1.0 setgray 442 155 10 FC 0.0 setgray 442 155 10 OC 442 150 moveto (3) CSH 1.0 setgray 470 130 10 FC 0.0 setgray 470 130 10 OC 470 125 moveto (3) CSH 1.0 setgray 470 155 10 FC 0.0 setgray 470 155 10 OC 470 150 moveto (3) CSH 1.0 setgray 456 180 10 FC 0.0 setgray 456 180 10 OC 456 175 moveto (3) CSH 1.0 setgray 498 130 10 FC 0.0 setgray 498 130 10 OC 498 125 moveto (2) CSH 1.0 setgray 498 155 10 FC 0.0 setgray 498 155 10 OC 498 150 moveto (2) CSH 1.0 setgray 525 155 10 FC 0.0 setgray 525 155 10 OC 525 150 moveto (2) CSH 1.0 setgray 511 180 10 FC 0.0 setgray 511 180 10 OC 511 175 moveto (2) CSH 1.0 setgray 484 205 10 FC 0.0 setgray 484 205 10 OC 484 200 moveto (3) CSH 1.0 setgray 552 130 10 FC 0.0 setgray 552 130 10 OC 552 125 moveto (0) CSH 1.0 setgray 552 155 10 FC 0.0 setgray 552 155 10 OC 552 150 moveto (0) CSH 1.0 setgray 552 180 10 FC 0.0 setgray 552 180 10 OC 552 175 moveto (0) CSH 1.0 setgray 580 130 10 FC 0.0 setgray 580 130 10 OC 580 125 moveto (1) CSH 1.0 setgray 580 155 10 FC 0.0 setgray 580 155 10 OC 580 150 moveto (1) CSH 1.0 setgray 580 180 10 FC 0.0 setgray 580 180 10 OC 580 175 moveto (1) CSH 1.0 setgray 566 205 10 FC 0.0 setgray 566 205 10 OC 566 200 moveto (1) CSH 1.0 setgray 525 230 10 FC 0.0 setgray 525 230 10 OC 525 225 moveto (3) CSH 1.0 setgray 441 255 10 FC 0.0 setgray 441 255 10 OC 441 250 moveto (15) CSH 1.0 setgray 302 280 10 FC 0.0 setgray 302 280 10 OC 302 275 moveto (15) CSH grestore showpage 2 80 ML 332 80 332 105 ML 332 105 332 130 ML 332 130 332 155 ML 332 155 332 180 ML 332 180 332 205 ML 332 205 357 230 ML 360 130 360 155 ML 360 155 360 180 ML 360 180 381 205 ML 388 80 388 10documentation/FrontTrees/R2D100split.eps010064400020550007177000000071460663202231100214350ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 400 400 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 380 380 rectstroke newpath 30 100 51.9 135 ML 73.8 100 51.9 135 ML 51.9 135 51.9 170 ML 51.9 170 51.9 205 ML 51.9 205 200 240 ML 118 65 118 100 ML 118 100 118 135 ML 118 135 139 170 ML 161 135 139 170 ML 139 170 139 205 ML 139 205 200 240 ML 205 135 249 170 ML 249 135 249 170 ML 292 135 249 170 ML 249 170 249 205 ML 249 205 200 240 ML 336 100 358 135 ML 380 30 380 65 ML 380 65 380 100 ML 380 100 358 135 ML 358 135 358 170 ML 358 170 358 205 ML 358 205 200 240 ML 200 240 200 275 ML 200 275 200 310 ML 200 310 200 345 ML 200 345 200 380 ML stroke gsave /Helvetica-Bold findfont 12.5 scalefont setfont 1.0 setgray 30 100 10 FC 0.0 setgray 30 100 10 OC 30 95 moveto (0) CSH 1.0 setgray 73.8 100 10 FC 0.0 setgray 73.8 100 10 OC 73.8 95 moveto (1) CSH 1.0 setgray 51.9 135 10 FC 0.0 setgray 51.9 135 10 OC 51.9 130 moveto (2) CSH 1.0 setgray 51.9 170 10 FC 0.0 setgray 51.9 170 10 OC 51.9 165 moveto (3) CSH 1.0 setgray 51.9 205 10 FC 0.0 setgray 51.9 205 10 OC 51.9 200 moveto (4) CSH 1.0 setgray 118 65 10 FC 0.0 setgray 118 65 10 OC 118 60 moveto (5) CSH 1.0 setgray 118 100 10 FC 0.0 setgray 118 100 10 OC 118 95 moveto (6) CSH 1.0 setgray 118 135 10 FC 0.0 setgray 118 135 10 OC 118 130 moveto (7) CSH 1.0 setgray 161 135 10 FC 0.0 setgray 161 135 10 OC 161 130 moveto (8) CSH 1.0 setgray 139 170 10 FC 0.0 setgray 139 170 10 OC 139 165 moveto (9) CSH 1.0 setgray 139 205 10 FC 0.0 setgray 139 205 10 OC 139 200 moveto (10) CSH 1.0 setgray 205 135 10 FC 0.0 setgray 205 135 10 OC 205 130 moveto (11) CSH 1.0 setgray 249 135 10 FC 0.0 setgray 249 135 10 OC 249 130 moveto (12) CSH 1.0 setgray 292 135 10 FC 0.0 setgray 292 135 10 OC 292 130 moveto (13) CSH 1.0 setgray 249 170 10 FC 0.0 setgray 249 170 10 OC 249 165 moveto (14) CSH 1.0 setgray 249 205 10 FC 0.0 setgray 249 205 10 OC 249 200 moveto (15) CSH 1.0 setgray 336 100 10 FC 0.0 setgray 336 100 10 OC 336 95 moveto (16) CSH 1.0 setgray 380 30 10 FC 0.0 setgray 380 30 10 OC 380 25 moveto (17) CSH 1.0 setgray 380 65 10 FC 0.0 setgray 380 65 10 OC 380 60 moveto (18) CSH 1.0 setgray 380 100 10 FC 0.0 setgray 380 100 10 OC 380 95 moveto (19) CSH 1.0 setgray 358 135 10 FC 0.0 setgray 358 135 10 OC 358 130 moveto (20) CSH 1.0 setgray 358 170 10 FC 0.0 setgray 358 170 10 OC 358 165 moveto (21) CSH 1.0 setgray 358 205 10 FC 0.0 setgray 358 205 10 OC 358 200 moveto (22) CSH 1.0 setgray 200 240 10 FC 0.0 setgray 200 240 10 OC 200 235 moveto (23) CSH 1.0 setgray 200 275 10 FC 0.0 setgray 200 275 10 OC 200 270 moveto (24) CSH 1.0 setgray 200 310 10 FC 0.0 setgray 200 310 10 OC 200 305 moveto (25) CSH 1.0 setgray 200 345 10 FC 0.0 setgray 200 345 10 OC 200 340 moveto (26) CSH 1.0 setgray 200 380 10 FC 0.0 setgray 200 380 10 OC 200 375 moveto (27) CSH grestore showpage documentation/FrontTrees/R2D100splitmap.eps010064400020550007177000000071420663202231100221270ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 400 400 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 380 380 rectstroke newpath 30 100 51.9 135 ML 73.8 100 51.9 135 ML 51.9 135 51.9 170 ML 51.9 170 51.9 205 ML 51.9 205 200 240 ML 118 65 118 100 ML 118 100 118 135 ML 118 135 139 170 ML 161 135 139 170 ML 139 170 139 205 ML 139 205 200 240 ML 205 135 249 170 ML 249 135 249 170 ML 292 135 249 170 ML 249 170 249 205 ML 249 205 200 240 ML 336 100 358 135 ML 380 30 380 65 ML 380 65 380 100 ML 380 100 358 135 ML 358 135 358 170 ML 358 170 358 205 ML 358 205 200 240 ML 200 240 200 275 ML 200 275 200 310 ML 200 310 200 345 ML 200 345 200 380 ML stroke gsave /Helvetica-Bold findfont 12.5 scalefont setfont 1.0 setgray 30 100 10 FC 0.0 setgray 30 100 10 OC 30 95 moveto (13) CSH 1.0 setgray 73.8 100 10 FC 0.0 setgray 73.8 100 10 OC 73.8 95 moveto (12) CSH 1.0 setgray 51.9 135 10 FC 0.0 setgray 51.9 135 10 OC 51.9 130 moveto (14) CSH 1.0 setgray 51.9 170 10 FC 0.0 setgray 51.9 170 10 OC 51.9 165 moveto (14) CSH 1.0 setgray 51.9 205 10 FC 0.0 setgray 51.9 205 10 OC 51.9 200 moveto (14) CSH 1.0 setgray 118 65 10 FC 0.0 setgray 118 65 10 OC 118 60 moveto (9) CSH 1.0 setgray 118 100 10 FC 0.0 setgray 118 100 10 OC 118 95 moveto (10) CSH 1.0 setgray 118 135 10 FC 0.0 setgray 118 135 10 OC 118 130 moveto (10) CSH 1.0 setgray 161 135 10 FC 0.0 setgray 161 135 10 OC 161 130 moveto (8) CSH 1.0 setgray 139 170 10 FC 0.0 setgray 139 170 10 OC 139 165 moveto (11) CSH 1.0 setgray 139 205 10 FC 0.0 setgray 139 205 10 OC 139 200 moveto (11) CSH 1.0 setgray 205 135 10 FC 0.0 setgray 205 135 10 OC 205 130 moveto (6) CSH 1.0 setgray 249 135 10 FC 0.0 setgray 249 135 10 OC 249 130 moveto (5) CSH 1.0 setgray 292 135 10 FC 0.0 setgray 292 135 10 OC 292 130 moveto (4) CSH 1.0 setgray 249 170 10 FC 0.0 setgray 249 170 10 OC 249 165 moveto (7) CSH 1.0 setgray 249 205 10 FC 0.0 setgray 249 205 10 OC 249 200 moveto (7) CSH 1.0 setgray 336 100 10 FC 0.0 setgray 336 100 10 OC 336 95 moveto (2) CSH 1.0 setgray 380 30 10 FC 0.0 setgray 380 30 10 OC 380 25 moveto (1) CSH 1.0 setgray 380 65 10 FC 0.0 setgray 380 65 10 OC 380 60 moveto (1) CSH 1.0 setgray 380 100 10 FC 0.0 setgray 380 100 10 OC 380 95 moveto (1) CSH 1.0 setgray 358 135 10 FC 0.0 setgray 358 135 10 OC 358 130 moveto (3) CSH 1.0 setgray 358 170 10 FC 0.0 setgray 358 170 10 OC 358 165 moveto (3) CSH 1.0 setgray 358 205 10 FC 0.0 setgray 358 205 10 OC 358 200 moveto (3) CSH 1.0 setgray 200 240 10 FC 0.0 setgray 200 240 10 OC 200 235 moveto (15) CSH 1.0 setgray 200 275 10 FC 0.0 setgray 200 275 10 OC 200 270 moveto (15) CSH 1.0 setgray 200 310 10 FC 0.0 setgray 200 310 10 OC 200 305 moveto (15) CSH 1.0 setgray 200 345 10 FC 0.0 setgray 200 345 10 OC 200 340 moveto (15) CSH 1.0 setgray 200 380 10 FC 0.0 setgray 200 380 10 OC 200 375 moveto (15) CSH grestore showpage % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def documentation/FrontTrees/R2D100vtx.eps010064400020550007177000000266720663202231100211300ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 600 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 580 580 rectstroke newpath 30 75.8 30 98.8 ML 30 98.8 30 122 ML 30 122 43.8 145 ML 57.5 75.8 57.5 98.8 ML 57.5 98.8 57.5 122 ML 57.5 122 43.8 145 ML 43.8 145 43.8 168 ML 43.8 168 85 190 ML 85 122 98.8 145 ML 112 98.8 112 122 ML 112 122 98.8 145 ML 98.8 145 126 168 ML 140 98.8 140 122 ML 140 122 154 145 ML 168 98.8 168 122 ML 168 122 154 145 ML 154 145 126 168 ML 126 168 85 190 ML 85 190 85 213 ML 85 213 85 236 ML 85 236 85 259 ML 85 259 169 282 ML 195 122 209 145 ML 222 52.9 222 75.8 ML 222 75.8 222 98.8 ML 222 98.8 222 122 ML 222 122 209 145 ML 209 145 229 168 ML 250 98.8 250 122 ML 250 122 250 145 ML 250 145 229 168 ML 229 168 229 190 ML 229 190 253 213 ML 278 30 278 52.9 ML 278 52.9 278 75.8 ML 278 75.8 278 98.8 ML 278 98.8 278 122 ML 278 122 278 145 ML 278 145 278 168 ML 278 168 278 190 ML 278 190 253 213 ML 253 213 253 236 ML 253 236 253 259 ML 253 259 169 282 ML 169 282 169 305 ML 169 305 169 328 ML 169 328 169 351 ML 169 351 308 374 ML 305 52.9 305 75.8 ML 305 75.8 319 98.8 ML 332 75.8 319 98.8 ML 319 98.8 319 122 ML 319 122 319 145 ML 319 145 339 168 ML 360 145 339 168 ML 339 168 374 190 ML 388 52.9 388 75.8 ML 388 75.8 388 98.8 ML 388 98.8 388 122 ML 388 122 408 145 ML 415 75.8 429 98.8 ML 442 75.8 429 98.8 ML 429 98.8 429 122 ML 429 122 408 145 ML 408 145 408 168 ML 408 168 374 190 ML 374 190 374 213 ML 374 213 374 236 ML 374 236 374 259 ML 374 259 374 282 ML 374 282 448 305 ML 470 168 470 190 ML 470 190 484 213 ML 498 190 484 213 ML 484 213 522 236 ML 525 145 539 168 ML 552 122 552 145 ML 552 145 539 168 ML 539 168 559 190 ML 580 122 580 145 ML 580 145 580 168 ML 580 168 559 190 ML 559 190 559 213 ML 559 213 522 236 ML 522 236 522 259 ML 522 259 522 282 ML 522 282 448 305 ML 448 305 448 328 ML 448 328 448 351 ML 448 351 308 374 ML 308 374 308 397 ML 308 397 308 420 ML 308 420 308 442 ML 308 442 308 465 ML 308 465 308 488 ML 308 488 308 511 ML 308 511 308 534 ML 308 534 308 557 ML 308 557 308 580 ML stroke gsave /Helvetica-Bold findfont 12.5 scalefont setfont 1.0 setgray 30 75.8 10 FC 0.0 setgray 30 75.8 10 OC 30 70.8 moveto (0) CSH 1.0 setgray 30 98.8 10 FC 0.0 setgray 30 98.8 10 OC 30 93.8 moveto (1) CSH 1.0 setgray 30 122 10 FC 0.0 setgray 30 122 10 OC 30 117 moveto (2) CSH 1.0 setgray 57.5 75.8 10 FC 0.0 setgray 57.5 75.8 10 OC 57.5 70.8 moveto (3) CSH 1.0 setgray 57.5 98.8 10 FC 0.0 setgray 57.5 98.8 10 OC 57.5 93.8 moveto (4) CSH 1.0 setgray 57.5 122 10 FC 0.0 setgray 57.5 122 10 OC 57.5 117 moveto (5) CSH 1.0 setgray 43.8 145 10 FC 0.0 setgray 43.8 145 10 OC 43.8 140 moveto (6) CSH 1.0 setgray 43.8 168 10 FC 0.0 setgray 43.8 168 10 OC 43.8 162 moveto (7) CSH 1.0 setgray 85 122 10 FC 0.0 setgray 85 122 10 OC 85 117 moveto (8) CSH 1.0 setgray 112 98.8 10 FC 0.0 setgray 112 98.8 10 OC 112 93.8 moveto (9) CSH 1.0 setgray 112 122 10 FC 0.0 setgray 112 122 10 OC 112 117 moveto (10) CSH 1.0 setgray 98.8 145 10 FC 0.0 setgray 98.8 145 10 OC 98.8 140 moveto (11) CSH 1.0 setgray 140 98.8 10 FC 0.0 setgray 140 98.8 10 OC 140 93.8 moveto (12) CSH 1.0 setgray 140 122 10 FC 0.0 setgray 140 122 10 OC 140 117 moveto (13) CSH 1.0 setgray 168 98.8 10 FC 0.0 setgray 168 98.8 10 OC 168 93.8 moveto (14) CSH 1.0 setgray 168 122 10 FC 0.0 setgray 168 122 10 OC 168 117 moveto (15) CSH 1.0 setgray 154 145 10 FC 0.0 setgray 154 145 10 OC 154 140 moveto (16) CSH 1.0 setgray 126 168 10 FC 0.0 setgray 126 168 10 OC 126 162 moveto (17) CSH 1.0 setgray 85 190 10 FC 0.0 setgray 85 190 10 OC 85 185 moveto (18) CSH 1.0 setgray 85 213 10 FC 0.0 setgray 85 213 10 OC 85 208 moveto (19) CSH 1.0 setgray 85 236 10 FC 0.0 setgray 85 236 10 OC 85 231 moveto (20) CSH 1.0 setgray 85 259 10 FC 0.0 setgray 85 259 10 OC 85 254 moveto (21) CSH 1.0 setgray 195 122 10 FC 0.0 setgray 195 122 10 OC 195 117 moveto (22) CSH 1.0 setgray 222 52.9 10 FC 0.0 setgray 222 52.9 10 OC 222 47.9 moveto (23) CSH 1.0 setgray 222 75.8 10 FC 0.0 setgray 222 75.8 10 OC 222 70.8 moveto (24) CSH 1.0 setgray 222 98.8 10 FC 0.0 setgray 222 98.8 10 OC 222 93.8 moveto (25) CSH 1.0 setgray 222 122 10 FC 0.0 setgray 222 122 10 OC 222 117 moveto (26) CSH 1.0 setgray 209 145 10 FC 0.0 setgray 209 145 10 OC 209 140 moveto (27) CSH 1.0 setgray 250 98.8 10 FC 0.0 setgray 250 98.8 10 OC 250 93.8 moveto (28) CSH 1.0 setgray 250 122 10 FC 0.0 setgray 250 122 10 OC 250 117 moveto (29) CSH 1.0 setgray 250 145 10 FC 0.0 setgray 250 145 10 OC 250 140 moveto (30) CSH 1.0 setgray 229 168 10 FC 0.0 setgray 229 168 10 OC 229 162 moveto (31) CSH 1.0 setgray 229 190 10 FC 0.0 setgray 229 190 10 OC 229 185 moveto (32) CSH 1.0 setgray 278 30 10 FC 0.0 setgray 278 30 10 OC 278 25 moveto (33) CSH 1.0 setgray 278 52.9 10 FC 0.0 setgray 278 52.9 10 OC 278 47.9 moveto (34) CSH 1.0 setgray 278 75.8 10 FC 0.0 setgray 278 75.8 10 OC 278 70.8 moveto (35) CSH 1.0 setgray 278 98.8 10 FC 0.0 setgray 278 98.8 10 OC 278 93.8 moveto (36) CSH 1.0 setgray 278 122 10 FC 0.0 setgray 278 122 10 OC 278 117 moveto (37) CSH 1.0 setgray 278 145 10 FC 0.0 setgray 278 145 10 OC 278 140 moveto (38) CSH 1.0 setgray 278 168 10 FC 0.0 setgray 278 168 10 OC 278 162 moveto (39) CSH 1.0 setgray 278 190 10 FC 0.0 setgray 278 190 10 OC 278 185 moveto (40) CSH 1.0 setgray 253 213 10 FC 0.0 setgray 253 213 10 OC 253 208 moveto (41) CSH 1.0 setgray 253 236 10 FC 0.0 setgray 253 236 10 OC 253 231 moveto (42) CSH 1.0 setgray 253 259 10 FC 0.0 setgray 253 259 10 OC 253 254 moveto (43) CSH 1.0 setgray 169 282 10 FC 0.0 setgray 169 282 10 OC 169 277 moveto (44) CSH 1.0 setgray 169 305 10 FC 0.0 setgray 169 305 10 OC 169 300 moveto (45) CSH 1.0 setgray 169 328 10 FC 0.0 setgray 169 328 10 OC 169 323 moveto (46) CSH 1.0 setgray 169 351 10 FC 0.0 setgray 169 351 10 OC 169 346 moveto (47) CSH 1.0 setgray 305 52.9 10 FC 0.0 setgray 305 52.9 10 OC 305 47.9 moveto (48) CSH 1.0 setgray 305 75.8 10 FC 0.0 setgray 305 75.8 10 OC 305 70.8 moveto (49) CSH 1.0 setgray 332 75.8 10 FC 0.0 setgray 332 75.8 10 OC 332 70.8 moveto (50) CSH 1.0 setgray 319 98.8 10 FC 0.0 setgray 319 98.8 10 OC 319 93.8 moveto (51) CSH 1.0 setgray 319 122 10 FC 0.0 setgray 319 122 10 OC 319 117 moveto (52) CSH 1.0 setgray 319 145 10 FC 0.0 setgray 319 145 10 OC 319 140 moveto (53) CSH 1.0 setgray 360 145 10 FC 0.0 setgray 360 145 10 OC 360 140 moveto (54) CSH 1.0 setgray 339 168 10 FC 0.0 setgray 339 168 10 OC 339 162 moveto (55) CSH 1.0 setgray 388 52.9 10 FC 0.0 setgray 388 52.9 10 OC 388 47.9 moveto (56) CSH 1.0 setgray 388 75.8 10 FC 0.0 setgray 388 75.8 10 OC 388 70.8 moveto (57) CSH 1.0 setgray 388 98.8 10 FC 0.0 setgray 388 98.8 10 OC 388 93.8 moveto (58) CSH 1.0 setgray 388 122 10 FC 0.0 setgray 388 122 10 OC 388 117 moveto (59) CSH 1.0 setgray 415 75.8 10 FC 0.0 setgray 415 75.8 10 OC 415 70.8 moveto (60) CSH 1.0 setgray 442 75.8 10 FC 0.0 setgray 442 75.8 10 OC 442 70.8 moveto (61) CSH 1.0 setgray 429 98.8 10 FC 0.0 setgray 429 98.8 10 OC 429 93.8 moveto (62) CSH 1.0 setgray 429 122 10 FC 0.0 setgray 429 122 10 OC 429 117 moveto (63) CSH 1.0 setgray 408 145 10 FC 0.0 setgray 408 145 10 OC 408 140 moveto (64) CSH 1.0 setgray 408 168 10 FC 0.0 setgray 408 168 10 OC 408 162 moveto (65) CSH 1.0 setgray 374 190 10 FC 0.0 setgray 374 190 10 OC 374 185 moveto (66) CSH 1.0 setgray 374 213 10 FC 0.0 setgray 374 213 10 OC 374 208 moveto (67) CSH 1.0 setgray 374 236 10 FC 0.0 setgray 374 236 10 OC 374 231 moveto (68) CSH 1.0 setgray 374 259 10 FC 0.0 setgray 374 259 10 OC 374 254 moveto (69) CSH 1.0 setgray 374 282 10 FC 0.0 setgray 374 282 10 OC 374 277 moveto (70) CSH 1.0 setgray 470 168 10 FC 0.0 setgray 470 168 10 OC 470 162 moveto (71) CSH 1.0 setgray 470 190 10 FC 0.0 setgray 470 190 10 OC 470 185 moveto (72) CSH 1.0 setgray 498 190 10 FC 0.0 setgray 498 190 10 OC 498 185 moveto (73) CSH 1.0 setgray 484 213 10 FC 0.0 setgray 484 213 10 OC 484 208 moveto (74) CSH 1.0 setgray 525 145 10 FC 0.0 setgray 525 145 10 OC 525 140 moveto (75) CSH 1.0 setgray 552 122 10 FC 0.0 setgray 552 122 10 OC 552 117 moveto (76) CSH 1.0 setgray 552 145 10 FC 0.0 setgray 552 145 10 OC 552 140 moveto (77) CSH 1.0 setgray 539 168 10 FC 0.0 setgray 539 168 10 OC 539 162 moveto (78) CSH 1.0 setgray 580 122 10 FC 0.0 setgray 580 122 10 OC 580 117 moveto (79) CSH 1.0 setgray 580 145 10 FC 0.0 setgray 580 145 10 OC 580 140 moveto (80) CSH 1.0 setgray 580 168 10 FC 0.0 setgray 580 168 10 OC 580 162 moveto (81) CSH 1.0 setgray 559 190 10 FC 0.0 setgray 559 190 10 OC 559 185 moveto (82) CSH 1.0 setgray 559 213 10 FC 0.0 setgray 559 213 10 OC 559 208 moveto (83) CSH 1.0 setgray 522 236 10 FC 0.0 setgray 522 236 10 OC 522 231 moveto (84) CSH 1.0 setgray 522 259 10 FC 0.0 setgray 522 259 10 OC 522 254 moveto (85) CSH 1.0 setgray 522 282 10 FC 0.0 setgray 522 282 10 OC 522 277 moveto (86) CSH 1.0 setgray 448 305 10 FC 0.0 setgray 448 305 10 OC 448 300 moveto (87) CSH 1.0 setgray 448 328 10 FC 0.0 setgray 448 328 10 OC 448 323 moveto (88) CSH 1.0 setgray 448 351 10 FC 0.0 setgray 448 351 10 OC 448 346 moveto (89) CSH 1.0 setgray 308 374 10 FC 0.0 setgray 308 374 10 OC 308 369 moveto (90) CSH 1.0 setgray 308 397 10 FC 0.0 setgray 308 397 10 OC 308 392 moveto (91) CSH 1.0 setgray 308 420 10 FC 0.0 setgray 308 420 10 OC 308 415 moveto (92) CSH 1.0 setgray 308 442 10 FC 0.0 setgray 308 442 10 OC 308 438 moveto (93) CSH 1.0 setgray 308 465 10 FC 0.0 setgray 308 465 10 OC 308 460 moveto (94) CSH 1.0 setgray 308 488 10 FC 0.0 setgray 308 488 10 OC 308 483 moveto (95) CSH 1.0 setgray 308 511 10 FC 0.0 setgray 308 511 10 OC 308 506 moveto (96) CSH 1.0 setgray 308 534 10 FC 0.0 setgray 308 534 10 OC 308 529 moveto (97) CSH 1.0 setgray 308 557 10 FC 0.0 setgray 308 557 10 OC 308 552 moveto (98) CSH 1.0 setgray 308 580 10 FC 0.0 setgray 308 580 10 OC 308 575 moveto (99) CSH grestore showpage 8 305 ML 448 305 448 328 ML 448 328 448 351 ML 448 351 308 37documentation/FrontTrees/R2D100vtxmap.eps010064400020550007177000000266720663202231100216260ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 600 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 580 580 rectstroke newpath 30 75.8 30 98.8 ML 30 98.8 30 122 ML 30 122 43.8 145 ML 57.5 75.8 57.5 98.8 ML 57.5 98.8 57.5 122 ML 57.5 122 43.8 145 ML 43.8 145 43.8 168 ML 43.8 168 85 190 ML 85 122 98.8 145 ML 112 98.8 112 122 ML 112 122 98.8 145 ML 98.8 145 126 168 ML 140 98.8 140 122 ML 140 122 154 145 ML 168 98.8 168 122 ML 168 122 154 145 ML 154 145 126 168 ML 126 168 85 190 ML 85 190 85 213 ML 85 213 85 236 ML 85 236 85 259 ML 85 259 169 282 ML 195 122 209 145 ML 222 52.9 222 75.8 ML 222 75.8 222 98.8 ML 222 98.8 222 122 ML 222 122 209 145 ML 209 145 229 168 ML 250 98.8 250 122 ML 250 122 250 145 ML 250 145 229 168 ML 229 168 229 190 ML 229 190 253 213 ML 278 30 278 52.9 ML 278 52.9 278 75.8 ML 278 75.8 278 98.8 ML 278 98.8 278 122 ML 278 122 278 145 ML 278 145 278 168 ML 278 168 278 190 ML 278 190 253 213 ML 253 213 253 236 ML 253 236 253 259 ML 253 259 169 282 ML 169 282 169 305 ML 169 305 169 328 ML 169 328 169 351 ML 169 351 308 374 ML 305 52.9 305 75.8 ML 305 75.8 319 98.8 ML 332 75.8 319 98.8 ML 319 98.8 319 122 ML 319 122 319 145 ML 319 145 339 168 ML 360 145 339 168 ML 339 168 374 190 ML 388 52.9 388 75.8 ML 388 75.8 388 98.8 ML 388 98.8 388 122 ML 388 122 408 145 ML 415 75.8 429 98.8 ML 442 75.8 429 98.8 ML 429 98.8 429 122 ML 429 122 408 145 ML 408 145 408 168 ML 408 168 374 190 ML 374 190 374 213 ML 374 213 374 236 ML 374 236 374 259 ML 374 259 374 282 ML 374 282 448 305 ML 470 168 470 190 ML 470 190 484 213 ML 498 190 484 213 ML 484 213 522 236 ML 525 145 539 168 ML 552 122 552 145 ML 552 145 539 168 ML 539 168 559 190 ML 580 122 580 145 ML 580 145 580 168 ML 580 168 559 190 ML 559 190 559 213 ML 559 213 522 236 ML 522 236 522 259 ML 522 259 522 282 ML 522 282 448 305 ML 448 305 448 328 ML 448 328 448 351 ML 448 351 308 374 ML 308 374 308 397 ML 308 397 308 420 ML 308 420 308 442 ML 308 442 308 465 ML 308 465 308 488 ML 308 488 308 511 ML 308 511 308 534 ML 308 534 308 557 ML 308 557 308 580 ML stroke gsave /Helvetica-Bold findfont 12.5 scalefont setfont 1.0 setgray 30 75.8 10 FC 0.0 setgray 30 75.8 10 OC 30 70.8 moveto (65) CSH 1.0 setgray 30 98.8 10 FC 0.0 setgray 30 98.8 10 OC 30 93.8 moveto (66) CSH 1.0 setgray 30 122 10 FC 0.0 setgray 30 122 10 OC 30 117 moveto (67) CSH 1.0 setgray 57.5 75.8 10 FC 0.0 setgray 57.5 75.8 10 OC 57.5 70.8 moveto (62) CSH 1.0 setgray 57.5 98.8 10 FC 0.0 setgray 57.5 98.8 10 OC 57.5 93.8 moveto (63) CSH 1.0 setgray 57.5 122 10 FC 0.0 setgray 57.5 122 10 OC 57.5 117 moveto (64) CSH 1.0 setgray 43.8 145 10 FC 0.0 setgray 43.8 145 10 OC 43.8 140 moveto (68) CSH 1.0 setgray 43.8 168 10 FC 0.0 setgray 43.8 168 10 OC 43.8 162 moveto (68) CSH 1.0 setgray 85 122 10 FC 0.0 setgray 85 122 10 OC 85 117 moveto (59) CSH 1.0 setgray 112 98.8 10 FC 0.0 setgray 112 98.8 10 OC 112 93.8 moveto (57) CSH 1.0 setgray 112 122 10 FC 0.0 setgray 112 122 10 OC 112 117 moveto (58) CSH 1.0 setgray 98.8 145 10 FC 0.0 setgray 98.8 145 10 OC 98.8 140 moveto (60) CSH 1.0 setgray 140 98.8 10 FC 0.0 setgray 140 98.8 10 OC 140 93.8 moveto (54) CSH 1.0 setgray 140 122 10 FC 0.0 setgray 140 122 10 OC 140 117 moveto (55) CSH 1.0 setgray 168 98.8 10 FC 0.0 setgray 168 98.8 10 OC 168 93.8 moveto (52) CSH 1.0 setgray 168 122 10 FC 0.0 setgray 168 122 10 OC 168 117 moveto (53) CSH 1.0 setgray 154 145 10 FC 0.0 setgray 154 145 10 OC 154 140 moveto (56) CSH 1.0 setgray 126 168 10 FC 0.0 setgray 126 168 10 OC 126 162 moveto (61) CSH 1.0 setgray 85 190 10 FC 0.0 setgray 85 190 10 OC 85 185 moveto (69) CSH 1.0 setgray 85 213 10 FC 0.0 setgray 85 213 10 OC 85 208 moveto (69) CSH 1.0 setgray 85 236 10 FC 0.0 setgray 85 236 10 OC 85 231 moveto (69) CSH 1.0 setgray 85 259 10 FC 0.0 setgray 85 259 10 OC 85 254 moveto (69) CSH 1.0 setgray 195 122 10 FC 0.0 setgray 195 122 10 OC 195 117 moveto (48) CSH 1.0 setgray 222 52.9 10 FC 0.0 setgray 222 52.9 10 OC 222 47.9 moveto (44) CSH 1.0 setgray 222 75.8 10 FC 0.0 setgray 222 75.8 10 OC 222 70.8 moveto (45) CSH 1.0 setgray 222 98.8 10 FC 0.0 setgray 222 98.8 10 OC 222 93.8 moveto (46) CSH 1.0 setgray 222 122 10 FC 0.0 setgray 222 122 10 OC 222 117 moveto (47) CSH 1.0 setgray 209 145 10 FC 0.0 setgray 209 145 10 OC 209 140 moveto (49) CSH 1.0 setgray 250 98.8 10 FC 0.0 setgray 250 98.8 10 OC 250 93.8 moveto (41) CSH 1.0 setgray 250 122 10 FC 0.0 setgray 250 122 10 OC 250 117 moveto (42) CSH 1.0 setgray 250 145 10 FC 0.0 setgray 250 145 10 OC 250 140 moveto (43) CSH 1.0 setgray 229 168 10 FC 0.0 setgray 229 168 10 OC 229 162 moveto (50) CSH 1.0 setgray 229 190 10 FC 0.0 setgray 229 190 10 OC 229 185 moveto (50) CSH 1.0 setgray 278 30 10 FC 0.0 setgray 278 30 10 OC 278 25 moveto (33) CSH 1.0 setgray 278 52.9 10 FC 0.0 setgray 278 52.9 10 OC 278 47.9 moveto (34) CSH 1.0 setgray 278 75.8 10 FC 0.0 setgray 278 75.8 10 OC 278 70.8 moveto (35) CSH 1.0 setgray 278 98.8 10 FC 0.0 setgray 278 98.8 10 OC 278 93.8 moveto (36) CSH 1.0 setgray 278 122 10 FC 0.0 setgray 278 122 10 OC 278 117 moveto (37) CSH 1.0 setgray 278 145 10 FC 0.0 setgray 278 145 10 OC 278 140 moveto (38) CSH 1.0 setgray 278 168 10 FC 0.0 setgray 278 168 10 OC 278 162 moveto (39) CSH 1.0 setgray 278 190 10 FC 0.0 setgray 278 190 10 OC 278 185 moveto (40) CSH 1.0 setgray 253 213 10 FC 0.0 setgray 253 213 10 OC 253 208 moveto (51) CSH 1.0 setgray 253 236 10 FC 0.0 setgray 253 236 10 OC 253 231 moveto (51) CSH 1.0 setgray 253 259 10 FC 0.0 setgray 253 259 10 OC 253 254 moveto (51) CSH 1.0 setgray 169 282 10 FC 0.0 setgray 169 282 10 OC 169 277 moveto (70) CSH 1.0 setgray 169 305 10 FC 0.0 setgray 169 305 10 OC 169 300 moveto (70) CSH 1.0 setgray 169 328 10 FC 0.0 setgray 169 328 10 OC 169 323 moveto (70) CSH 1.0 setgray 169 351 10 FC 0.0 setgray 169 351 10 OC 169 346 moveto (70) CSH 1.0 setgray 305 52.9 10 FC 0.0 setgray 305 52.9 10 OC 305 47.9 moveto (25) CSH 1.0 setgray 305 75.8 10 FC 0.0 setgray 305 75.8 10 OC 305 70.8 moveto (26) CSH 1.0 setgray 332 75.8 10 FC 0.0 setgray 332 75.8 10 OC 332 70.8 moveto (24) CSH 1.0 setgray 319 98.8 10 FC 0.0 setgray 319 98.8 10 OC 319 93.8 moveto (27) CSH 1.0 setgray 319 122 10 FC 0.0 setgray 319 122 10 OC 319 117 moveto (28) CSH 1.0 setgray 319 145 10 FC 0.0 setgray 319 145 10 OC 319 140 moveto (29) CSH 1.0 setgray 360 145 10 FC 0.0 setgray 360 145 10 OC 360 140 moveto (23) CSH 1.0 setgray 339 168 10 FC 0.0 setgray 339 168 10 OC 339 162 moveto (30) CSH 1.0 setgray 388 52.9 10 FC 0.0 setgray 388 52.9 10 OC 388 47.9 moveto (18) CSH 1.0 setgray 388 75.8 10 FC 0.0 setgray 388 75.8 10 OC 388 70.8 moveto (19) CSH 1.0 setgray 388 98.8 10 FC 0.0 setgray 388 98.8 10 OC 388 93.8 moveto (20) CSH 1.0 setgray 388 122 10 FC 0.0 setgray 388 122 10 OC 388 117 moveto (21) CSH 1.0 setgray 415 75.8 10 FC 0.0 setgray 415 75.8 10 OC 415 70.8 moveto (15) CSH 1.0 setgray 442 75.8 10 FC 0.0 setgray 442 75.8 10 OC 442 70.8 moveto (14) CSH 1.0 setgray 429 98.8 10 FC 0.0 setgray 429 98.8 10 OC 429 93.8 moveto (16) CSH 1.0 setgray 429 122 10 FC 0.0 setgray 429 122 10 OC 429 117 moveto (17) CSH 1.0 setgray 408 145 10 FC 0.0 setgray 408 145 10 OC 408 140 moveto (22) CSH 1.0 setgray 408 168 10 FC 0.0 setgray 408 168 10 OC 408 162 moveto (22) CSH 1.0 setgray 374 190 10 FC 0.0 setgray 374 190 10 OC 374 185 moveto (31) CSH 1.0 setgray 374 213 10 FC 0.0 setgray 374 213 10 OC 374 208 moveto (31) CSH 1.0 setgray 374 236 10 FC 0.0 setgray 374 236 10 OC 374 231 moveto (31) CSH 1.0 setgray 374 259 10 FC 0.0 setgray 374 259 10 OC 374 254 moveto (31) CSH 1.0 setgray 374 282 10 FC 0.0 setgray 374 282 10 OC 374 277 moveto (31) CSH 1.0 setgray 470 168 10 FC 0.0 setgray 470 168 10 OC 470 162 moveto (10) CSH 1.0 setgray 470 190 10 FC 0.0 setgray 470 190 10 OC 470 185 moveto (11) CSH 1.0 setgray 498 190 10 FC 0.0 setgray 498 190 10 OC 498 185 moveto (9) CSH 1.0 setgray 484 213 10 FC 0.0 setgray 484 213 10 OC 484 208 moveto (12) CSH 1.0 setgray 525 145 10 FC 0.0 setgray 525 145 10 OC 525 140 moveto (5) CSH 1.0 setgray 552 122 10 FC 0.0 setgray 552 122 10 OC 552 117 moveto (3) CSH 1.0 setgray 552 145 10 FC 0.0 setgray 552 145 10 OC 552 140 moveto (4) CSH 1.0 setgray 539 168 10 FC 0.0 setgray 539 168 10 OC 539 162 moveto (6) CSH 1.0 setgray 580 122 10 FC 0.0 setgray 580 122 10 OC 580 117 moveto (0) CSH 1.0 setgray 580 145 10 FC 0.0 setgray 580 145 10 OC 580 140 moveto (1) CSH 1.0 setgray 580 168 10 FC 0.0 setgray 580 168 10 OC 580 162 moveto (2) CSH 1.0 setgray 559 190 10 FC 0.0 setgray 559 190 10 OC 559 185 moveto (7) CSH 1.0 setgray 559 213 10 FC 0.0 setgray 559 213 10 OC 559 208 moveto (8) CSH 1.0 setgray 522 236 10 FC 0.0 setgray 522 236 10 OC 522 231 moveto (13) CSH 1.0 setgray 522 259 10 FC 0.0 setgray 522 259 10 OC 522 254 moveto (13) CSH 1.0 setgray 522 282 10 FC 0.0 setgray 522 282 10 OC 522 277 moveto (13) CSH 1.0 setgray 448 305 10 FC 0.0 setgray 448 305 10 OC 448 300 moveto (32) CSH 1.0 setgray 448 328 10 FC 0.0 setgray 448 328 10 OC 448 323 moveto (32) CSH 1.0 setgray 448 351 10 FC 0.0 setgray 448 351 10 OC 448 346 moveto (32) CSH 1.0 setgray 308 374 10 FC 0.0 setgray 308 374 10 OC 308 369 moveto (71) CSH 1.0 setgray 308 397 10 FC 0.0 setgray 308 397 10 OC 308 392 moveto (71) CSH 1.0 setgray 308 420 10 FC 0.0 setgray 308 420 10 OC 308 415 moveto (71) CSH 1.0 setgray 308 442 10 FC 0.0 setgray 308 442 10 OC 308 438 moveto (71) CSH 1.0 setgray 308 465 10 FC 0.0 setgray 308 465 10 OC 308 460 moveto (71) CSH 1.0 setgray 308 488 10 FC 0.0 setgray 308 488 10 OC 308 483 moveto (71) CSH 1.0 setgray 308 511 10 FC 0.0 setgray 308 511 10 OC 308 506 moveto (71) CSH 1.0 setgray 308 534 10 FC 0.0 setgray 308 534 10 OC 308 529 moveto (71) CSH 1.0 setgray 308 557 10 FC 0.0 setgray 308 557 10 OC 308 552 moveto (71) CSH 1.0 setgray 308 580 10 FC 0.0 setgray 308 580 10 OC 308 575 moveto (71) CSH grestore showpage gray 85 213 10 FC 0.0 setgray 85 213 10 OC 85 208 moveto (69) documentation/FrontTrees/smooth.bib010064000020550007177000001070630663202233300210260ustar00clevecompmath00000400000006 @article{and90-random, author="S. L. Anderson", title="Random number generators on vector supercomputers and other advanced architectures", journal="SIAM Review", volume="32", year="1990", pages="221-251"} @misc{ash97-utah, AUTHOR="C. Ashcraft and S. C. Eisenstat and J. W. H. Liu", title="Practical extensions of the multisection ordering for sparse matrices", howpublished="Minisymposium presentation at the Sixth SIAM Conference on Applied Linear Algebra, Snowbird, Utah", year="October 29, 1997"} @misc{ash94-utah, AUTHOR="C. Ashcraft and J. W. H. Liu", title="Generalized nested dissection: some recent progress", howpublished="Minisymposium presentation at the Fifth SIAM Conference on Applied Linear Algebra, Snowbird, Utah", year="June 18, 1994"} @misc{rot96-balance, AUTHOR="E. Rothberg", title="Exploring the tradeoff between imbalance and separator size in nested dissection ordering", howpublished="unpublished", year="1996"} @misc{ro95-hybrid, AUTHOR="E. Rothberg", title="Robust ordering of sparse matrices: a minimum degree, nested dissection hybrid", howpublished="unpublished", year="1995"} @misc{rothberg95, AUTHOR="E. Rothberg", howpublished="private communication", year="1995"} @conference{rot96-mindefIdaho, author="E. Rothberg", title="Ordering sparse matrices using approximate minimum local fill", booktitle="Second SIAM Conference on Sparse Matrices", year="1996", note="Conference presentation"} @techreport{hr96-msndtalk, author="B. Hendrickson and E. Rothberg", title="Improving the runtime and quality of nested dissection ordering", booktitle="Second SIAM Conference on Sparse Matrices", year="1996", note="Conference presentation"} @conference{ng96-mindefIdaho, author="E. Ng and P. Raghavan", title="Minimum deficiency ordering", booktitle="Second SIAM Conference on Sparse Matrices", year="1996", note="Conference presentation"} @article{gib76-profile, AUTHOR = {N. E. Gibbs and W. G. Poole Jr and P. K. Stockmeyer}, JOURNAL = {SIAM. J. Numer. Anal.}, KEY = {LLt band profile}, PAGES = {236-250}, TITLE = {An algorithm for reducing the bandwidth and profile of a sparse matrix}, VOLUME = {13}, YEAR = {1976} } @techreport{rag95-PCO, author="P. Raghavan", title="Parallel ordering using edge contraction", number="CS-95-293", institution="Dept. of Computer Science, The University of Tennessee", address="Knoxville, Tennessee", year="1995"} @techreport{ame94-amdTR, author="P. Amestoy and T. Davis and I. Duff", title="An approximate minimum degree ordering algorithm", number = "TR-94-039", institution="University of Florida", year="1994"} @article{ame96-amd, author="P. Amestoy and T. Davis and I. Duff", title="An approximate minimum degree ordering algorithm", journal="SIAM J. Matrix Anal. Appl.", volume="17", pages="886-905", year="1996"} @techreport{hr96-msnd, author="B. Hendrickson and E. Rothberg", title="Improving the runtime and quality of nested dissection ordering", institution="Sandia National Laboratories", year="1996"} @article{ash89-relaxed, author="C. Ashcraft and R. Grimes", title="The influence of relaxed supernode partitions on the multifrontal method", journal="ACM Trans. Math. Software", volume="15", year="1989", pages="291-309"} @techreport{ash95-AGL, author="C. Ashcraft and R. G. Grimes and J. G. Lewis", title="Accurate symmetric indefinite linear equation solvers", number="ISSTECH-95-029", institution="Boeing Computer Services", year="1995", note="Accepted for publication in {\it SIAM J. Matrix. Anal.}"} @techreport{ash96-multisection, author="C. Ashcraft and J. W. H. Liu", title="Robust ordering of sparse matrices using multisection", number="ISSTECH-96-002", institution="Boeing Information and Support Services", year="1996", note="Accepted for publication in {\it SIAM J. Matrix. Anal.}"} @techreport{ash95-DDSEP, author="C. Ashcraft and J. W. H. Liu", title="Using domain decompositions to find graph bisectors", number="ISSTECH-95-024", institution="Boeing Computer Services", year="1995", note="Accepted for publication in {\it BIT}"} @techreport{ash95-robust, author="C. Ashcraft and J. W. H. Liu", title="Robust ordering of sparse matrices using multisection", number="ISSTECH-96-002", institution="Boeing Computer Services", year="1996"} @techreport{ash96-maxflow, author="C. Ashcraft and J. W. H. Liu", title="Applications of the {D}ulmage-{M}endelsohn decomposition and network flow to graph bisection improvement", number="ISSTECH-96-017", institution="Boeing Computer Services", year="1996", note="Accepted for publication in {\it SIAM J. Matrix. Anal.}"} @techreport{ash93-compressed-graphs-TR, author="C. Ashcraft", title="Compressed graphs and the minimum degree algorithm", number="BCSTECH-93-024", institution="Boeing Computer Services", year="1993"} @techreport{ash94-partition, author="C. Ashcraft and J. W. H. Liu", title="A partition improvement algorithm for generalized nested dissection", number="BCSTECH-94-020", institution="Boeing Computer Services", year="1994", note="Accepted for publication in {\it BIT}"} @article{ber90-mindeg, author="P. Berman and G. Schnitger", title="On the performance of the minimum degree ordering for {G}aussian elimination", journal="SIAM J. Matrix Analysis and Applic.", volume="11", year="1990", pages="83-88"} @article{bha93-localND, author="M. V. Bhat and W. G. Habashi and J. W. H. Liu and V. N. Nguyen and M. F. Peeters", title="A note on nested dissection for rectangular grids", journal="SIAM J. Matrix Analysis and Applic.", volume="14", year="1993", pages="253-258"} @phdthesis{dam92-compressed, author="A. C. Damhaug", title="Sparse Solution of Finite Element Equations", school="The Norwegian Institute of Technology", year="1992"} @article{duf83-multifrontal, author="I. Duff and J. Reid", title="The multifrontal solution of indefinite sparse symmetric linear equations", journal="ACM Trans. Math. Software", volume="6", year="1983", pages="302-325"} @inproceedings{eis76-elementModel, author="S. C. Eisenstat and M. H. Schultz and A. H. Sherman", title="Applications of an element model for {G}aussian elimination", booktitle="Sparse Matrix Computations", pages="85-96", publisher="Academic Press", year="1976", editor="J. R. Bunch and D. J. Rose"} @inproceedings{fid82-partition, author="C. M. Fiduccia and R. M. Mattheyses", title="A linear-time heuristic for improving network partition", booktitle="ACM IEEE Proc. 19th Design Automation Conference, Las Vegas, Nevada", year="1982", pages="175-181"} @article{geo80-1way, author="J. A. George", title="An automatic one-way dissection algorithm for irregular finite element problems", journal="SIAM J. Numer. Anal.", volume="17", year="1980", pages="740-751"} @article{sparsematlab, author="J. Gilbert and C. Moler and R. Schreiber", title="Sparse matrices in {MATLAB}: design and implementation", journal="SIAM J. Matrix Analysis and Applic.", volume="13", year="1992", pages="335-356"} @techreport{gup96-WGPP, author="A. Gupta", title="{WGPP}: {W}atson {G}raph {P}artitioning and sparse matrix ordering {P}ackage", number="Users Manual", institution="IBM T.J. Watson Research Center", address="New York", year="1996"} @techreport{hea92-dissection, author="M.T. Heath and P. Raghavan", title="A Cartesian nested dissection algorithm", number="UIUCDCS-R-92-1772", institution="Dept of Computer Science, University of Illinois", address="Urbana, IL", year="1992"} @techreport{hen92-partition, author="B. Hendrickson and R. Leland", title="An improved spectral graph partitioning algorithm for mapping parallel computations", number="SAND92-1460", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1992"} @techreport{hen93-partition, author="B. Hendrickson and R. Leland", title="Multidimensional spectral load balancing", number="SAND93-074", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @article{ker70-partition, author="B. W. Kernighan and S. Lin", title="An efficient heuristic procedure for partitioning graphs", journal="Bell System Technical Journal", volume="49", year="1970", pages="291-307"} @inproceedings{lei89-fidmat, author="C. E. Leiserson and J. G. Lewis", title="Orderings for parallel sparse symmetric factorization", booktitle="Parallel Processing for Scientific Computing", year="1989", pages="27-31"} @article{lip79-separators, author="R. J. Lipton and R. E. Tarjan", title="A separator theorem for planar graphs", journal="SIAM J. Applied Math", volume="36", year="1979", pages="177-189"} @article{liu89-separators, author="J. W. H. Liu", title="A graph partitioning algorithm by node separators", journal="ACM Trans. on Math. Software", volume="15", year="1989", pages="198-219"} @article{liu85-mfstorage, author="J. W. H. Liu", title="On the storage requirement in the out-of-core multifrontal method for sparse factorization", journal="ACM Trans. on Math. Software", volume="12", year="1986", pages="249-264"} @article{liu85-mmd, author="J. W. H. Liu", title="Modification of the minimum degree algorithm by multiple elimination", journal="ACM Trans. on Math. Software", volume="11", year="1985", pages="141-153"} @article{liu89-mindeg, author="J. W. H. Liu", title="On the minimum degree ordering with constraints", journal="SIAM J. Sci. Stat. Comput.", volume="10", year="1989", pages="1136-1145"} @article{liu90-etree, author="J. W. H. Liu", title="The role of elimination trees in sparse factorization", journal="SIAM J. Matrix Analysis and Applic.", volume="11", year="1990", pages="134-172"} @article{liu91-generalizedEnvelope, author="J. W. H. Liu", title="A generalized envelope method for sparse factorization by rows", journal="ACM Trans. on Math. Software", volume="17", year="1991", pages="112-129"} @article{mar57, author="H. M. Markowitz", title="The elimination form of the inverse and its application to linear programming", journal="Management Sci.", volume="3", year="1957", pages="255-269"} @mastersthesis{ng79-master, author="E. Ng", title="On one-way dissection schemes", school="Dept of Computer Science, University of Waterloo", address="Waterloo, Ontario", year="1979"} @techreport{rag93-separators, author="P. Raghavan", title="Line and plane separators", number="UIUCDCS-R-93-1794", institution="Dept of Computer Science, University of Illinois", address="Urbana, IL", year="1993"} @inproceedings{ros72-elimination, author="D. J. Rose", title="A graph-theoretic study of the numerical solution of sparse positive definite systems of linear equations", booktitle="Graph Theory and Computing", publisher="Academic Press", editor="R. Read", year="1972", pages="183-217"} @article{ros70-elimination, author="D. J. Rose", title="Triangulated graphs and the elimination process", journal="J. Math. Anal. & Appl.", volume="32", year="1970", pages="597-609"} @techreport{ten91-separators, author="S.H. Teng", title="Points, Spheres, and Separators", number="CMU-CS-91-184", institution="School of Computer Science, Carnegie Mellon University", address="Pittsburgh, PA", year="1991"} @article{tin67-order, author="W. F. Tinney and J. W. Walker", title="Direct solutions of sparse network equations by optimally ordered triangular factorization", journal="J Proc. IEEE", volume="55", year="1967", pages="1801-1809"} @book{aho83, author="A. V. Aho and J. E. Hopcroft and J. D. Ullman", title="Data Structures and Algorithms", publisher="Addison-Wesley", address="Reading, MA", year="1983"} @book{duf87-book, author="I. S. Duff and A. M. Erisman and J. K. Reid", title="Direct Methods for Sparse Matrices", publisher="Oxford University Press", address="London", year="1987"} @book{geo81-book, author="J. A. George and J. W. H. Liu", title="Computer Solution of Large Sparse Positive Definite Systems", publisher="Prentice-Hall", address="Englewood Cliffs, NJ", year="1981"} @article{ash87-progress, AUTHOR = {C. Ashcraft and R. Grimes and J. Lewis and B. Peyton and H. Simon}, JOURNAL = {Intern. J. of Supercomputer Applications}, KEY = {LLt vector}, PAGES = {10-30}, TITLE = {Progress in sparse matrix methods for large sparse linear systems on vector supercomputers}, VOLUME = {1}, YEAR = {1987} } @techreport{ash90-partition, author="C. Ashcraft", title="The domain/segment partition for the factorization of sparse symmetric positive definite matrices", number="ECA-TR-148", institution="Boeing Computer Services", address="Seattle, WA", year="1990"} @article{ash95-compressed-graphs, author="C. Ashcraft", title="Compressed graphs and the minimum degree algorithm", journal="SIAM J. Sci. Comput.", pages = "1404-1411", volume = 16, year="1995"} @inproceedings{ash90-lookahead, author="C. Ashcraft and S. C. Eisenstat and J. W. H. Liu and B. W. Peyton and A. H. Sherman", title="A compute-ahead fan-in scheme for parallel sparse matrix factorization", booktitle="Fourth Canadian Supercomputing Symposium (1990)", editor="D. Pelletier", year="June, 1990", pages="351-361"} @inproceedings{ash94-multisection, author="C. Ashcraft and J. W. H. Liu", title="Generalized nested dissection: some recent progress", booktitle="Fifth SIAM Conference on Applied Linear Algebra", address="Snowbird, Utah", year="June 18, 1994"} @inproceedings{bar93-partition, author="S. T. Barnard and H. D. Simon", title="A fast multilevel implementation of recursive spectral bisection for partitioning unstructured problems", booktitle="Proceedings of the Sixth SIAM Conference on Parallel Processing for Scientific Computing", year="1993", pages="711-718"} @inproceedings{bar95-partition, author="S. T. Barnard and H. D. Simon", title="A parallel implementation of multilevel recursive spectral bisection for applications in adaptive unstructured meshes", booktitle="Proceedings of the seventh SIAM Conference on Parallel Processing for Scientific Computing", year="1995", pages="627-632"} @article{bui92-partition, author="T. Bui and C. Jones", title="Finding good approximate vertex and edge partitions is {NP}-hard", journal="Information Processing Letters", volume="42", year="1992", pages="153-159"} @inproceedings{bui93-partition, author="T. Bui and C. Jones", title="A heuristic for reducing fill-in in sparse matrix factorization", booktitle="Proceedings of Sixth SIAM Conference on Parallel Processing ", year="1993", pages="445-452"} @article{geo73-nested, author="J. A. George", title="Nested dissection of a regular finite element mesh", journal="SIAM J. Numer. Anal.", volume="10", year="1973", pages="345-363"} @article{geo89-mindeg, author="J.A. George and J. W. H. Liu", title="The evolution of the minimum degree ordering algorithm", journal="SIAM Review", volume="31", year="1989", pages="1-19"} @techreport{goe95-partition, author="T. Goehring and Y. Saad", title="Heuristic algorithms for automatic graph partitioning", number="", institution="Computer Science Department, University of Minnesota", address="Minnesota", year="1995"} @article{hal35, author = "P. Hall", title = "On representatives of subsets", journal = "J. London Math. Society", volume = "10", year = "1935", pages = "26-30"} @article{Harwell-Boeing-Matrices, author = "I.S. Duff and R.G. Grimes and J.G. Lewis", title = "Sparse matrix test problems", journal="ACM Trans. on Math. Software", volume = "15", year = "1989", pages = "1-14"} @article{dul58, author = "A.L. Dulmage and N.S. Mendelsohn", title = "Coverings of bipartite graphs", journal="Can. J. Math", volume = "10", year = "1958", pages = "517-534"} @techreport{sparspak80, author="J. A. George and J. W. H. Liu and E. G. Ng", title="User's guide for {SPARSPAK}: {W}aterloo sparse linear equations package", number = "Tech. Rep. CS78-30(revised)", institution = "Dept. of Computer Sciences, Univ. of Waterloo", address="Waterloo, Ontario, Canada", year = "1980"} @techreport{hen93-chaco, author="B. Hendrickson and R. Leland", title="The {C}haco user's guide", number="SAND93-2339", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @techreport{hen93-partition, author="B. Hendrickson and R. Leland", title="A multilevel algorithm for partitioning graphs", number="SAND93-1301", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @techreport{hen93-spectral, author="B. Hendrickson and R. Leland", title="Multidimensional spectral load balancing", number="SAND93-074", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @techreport{kar95-kway, author="G. Karypis and V. Kumar", title="Multilevel $k$-way partitioning scheme for irregular graphs", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} % number="Technical Report", @techreport{kar95-multilevel, author="G. Karypis and V. Kumar", title="A fast and high quality multilevel scheme for partitioning irregular graphs", number="TR 95-035", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} @techreport{kar95-metis, author="G. Karypis and V. Kumar", title="{METIS}: Unstructured graph partitioning and sparse matrix ordering system", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} % number="TR 95-???", @techreport{kar95-partition, author="G. Karypis and V. Kumar", title="Analysis of multilevel graph partitioning", number="TR 95-037", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} @inproceedings{kar95, author="G. Karypis and V. Kumar", title="Multilevel graph partition and sparse matrix ordering", booktitle="Intl. Conf. on Parallel Processing", year="1995"} @article{lip79, author="R. J. Lipton and R. E. Tarjan", title="A separator theorem for planar graphs", journal="SIAM J. Applied Math", volume="36", year="1979", pages="177-189"} @techreport{mai94-partition, author="H.S. Maini and K.G. Mehrotra and S. Ranka", title="Genetic algorithms for graph partitioning and incremental graph partitioning", number="Technical report", institution="Center for Science and Technology, Syracuse University", address="Synracuse, N.Y.", year="1994"} @article{pot90-triangular, author="A. Pothen and C. Fan", title="Computing the block triangular form of a sparse matrix", journal="ACM Trans. on Math. Software", volume="16", year="1990", pages="303-324"} @article{pot90-partition, author="A. Pothen and H. Simon and K.P. Liou", title="Partitioning sparse matrices with eigenvectors of graphs", journal="SIAM J. Matrix Analysis and Applic.", volume="11", year="1990", pages="430-452"} @book{aho83, author="A. V. Aho and J. E. Hopcroft and J. D. Ullman", title="Data Structures and Algorithms", publisher="Addison-Wesley", address="Reading, MA", year="1983"} @book{ull84-vlsi, author="J. D. Ullman", title="Computational Aspects of VLSI", publisher="Computer Science Press", address="Rockville, Md", year="1984"} @book{duf87-book, author="I. S. Duff and A. M. Erisman and J. K. Reid", title="Direct Methods for Sparse Matrices", publisher="Oxford University Press", address="London", year="1987"} @book{geo81-book, author="J. A. George and J. W. H. Liu", title="Computer Solution of Large Sparse Positive Definite Systems", publisher="Prentice-Hall", address="Englewood Cliffs, NJ", year="1981"} @book{zzzz99-book, author="J. A. George and J. W. H. Liu", title="Computer Solution of Large Sparse Positive Definite Systems", publisher="Prentice-Hall", address="Englewood Cliffs, NJ", year="1981"} @article{arn85, author="S. Arnborg", title="Efficient algorithms for combinatorial problems on graphs with bounded decomposability - a survey", journal="BIT", volume="25", year="1985", pages="2-23"} @techreport{bar81, author="E. R. Barnes", title="An algorithm for partitioning the nodes of a graph", number="RC8690", institution="IBM Thomas J. Watson Research Center", address="Yorktown Heights, New York", year="1981"} @inproceedings{bar85, author="E. R. Barnes", title="Partitioning the nodes of a graph", booktitle="Graph Theory with Applications to Algorithms and Computer Science", editor="Y. Alavi and G. Chartrand and D. Lick and C. Wall and L. Lesuiak", publisher="John Wiley \& Sons Inc.", address="New York", year="1985", pages="57-72"} @article{bha84, author="S. N. Bhatt and F. T. Leighton", title="A framework for solving {VLSI} graph layout problems", journal="Journal of Computer \& Systems Sciences", volume="28", year="1984", pages=""} @inproceedings{bre77, author="M. A. Breuer", title="A class of min-cut placement algorithms", booktitle="Proc. 14th Design Automation Conference", year="1977", pages="284-290"} @inproceedings{bui84, author="S. N. Bui and S. Chaudhuri and T. Leighton and M. Sipser", title="Graph bisection algorithms with good average case behavior", booktitle="Proceedings of the 25th Annual Symposium of Foundations of Computer Science", year="1984", pages="181-192"} @article{dji81, author="H. N. Djidjev", title="A separator theorem", journal="Comptes rendus de l' Academie bulgare des Sciences", volume="34", year="1981", pages="643-645"} @article{dji82-linear, author="H. N. Djidjev", title="A linear algorithm for partitioning graphs", journal="Comptes rendus de l' Academie bulgare des Sciences", volume="35", year="1982", pages="1053-1056"} @article{dji82-planar, author="H. N. Djidjev", title="On the problem of partitioning planar graphs", journal="SIAM J. Alg. \& Disc. Meth.", volume="3", year="1982", pages="229-240"} @article{don72, author="W. E. Donath and A. J. Hoffman", title="Algorithms for partitioning of graphs and computer logic based on eigenvectors of connection matrices", journal="IBM Technical Disclosure Bulletin", volume="15", year="1972", pages="938-944"} @article{don73, author="W. E. Donath and A. J. Hoffman", title="Lower bounds for the partitioning of graphs", journal="IBM J. Res. Develop.", volume="17", year="1973", pages="420-425"} @article{fie73, author="M. Fiedler", title="Algebraic connectivity of graphs", journal="Czechoslovak Math J.", volume="23", year="1973", pages="298-305"} @book{fre86, author="G. N. Fredrickson and R. Janardan", title="Separator-based strategies for efficient message routing", booktitle="27th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1986", pages="428-437"} @book{gaz87, author="H. Gazit and G. L. Miller", title="A parallel algorithm for finding a separator in planar graphs", booktitle="28th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1987", pages="238-248"} @techreport{gil80, author="J. R. Gilbert", title="Graph separator theorems and sparse {G}aussian elimination", number="Ph.D. Thesis", institution="DCS, Stanford University", year="1980"} @article{gil84-genus, author="J. R. Gilbert and J. P. Hutchinson and R. E. Tarjan", title="A separator theorem for graphs of bounded genus", journal="J. of Algorithms", volume="5", year="1984", pages="391-407"} @article{gil84-chordal, author="J. R. Gilbert and D. J. Rose and A. Edenbrandt", title="A separator theorem for chordal graphs", journal="SIAM J. Alg. \& Disc. Meth.", volume="5", year="1984", pages="306-313"} @inproceedings{gol83, author="M. K. Goldberg and M. Burstein", title="Heuristic improvement technique for bisection of {VLSI} networks", booktitle="Proc. IEEE International Conf. on Computer Design", address="Port Chester, New York", year="1983", pages="122-125"} @techreport{gol87, author="M. K. Goldberg and S. Lath and J. W. Roberts", title="Heuristics for the graph bisection problem", number="Report", institution="Rensselaer Polytechnic Institute", year="1987"} @techreport{hen92, author="B. Hendrickson and R. Leland", title="An improved spectral graph partitioning algorithm for mapping parallel computations", number="SAND92-1460", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1992"} @techreport{hen93, author="B. Hendrickson and R. Leland", title="Multidimensional spectral load balancing", number="SAND93-074", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @article{hu81, author="T. C. Hu and M. T. Shing", title="An O(n) algorithm to find a near-optimum partition", journal="Journal of Algorithms", volume="2", year="1981", pages="122-138"} @article{hu85, author="T. C. Hu and M. T. Shing", title="A decomposition algorithm for circuit routing", journal="Math. Programming Study", volume="24", year="1985", pages="87-103"} @article{hu86, author="T. C. Hu and M. T. Shing", title="A decomposition algorithm for multi-terminal network flows", journal="J. Discrete Applied Math.", volume="13", year="1986", pages="165-181"} @article{joh88, author="D. S. Johnson and C. R. Aragon and L. A. McGeoch and C. Schevon", title="Optimization by simulated annealing: an experimental evaluation", journal="Operations Research", note="((submitted))", year="1988"} @article{kan91, author="A. Kanevsky and V. Ramachandran", title="Improved algorithms for graph four-connectivity", journal="J. of Computer Science and Systems", volume="42", year="1991", pages="288-306"} @article{kan9x, author="A. Kanevsky", title="Finding all minimum size vertex sets in a graph", journal="J. of Networks", year="199x"} @inproceedings{kan90, author="A. Kanevsky", title="On the number of minimum size separating vertex sets of a graph and how to find all of them", booktitle="First Annual ACM-SIAM Symposium on Discrete Algorithms (SODA '90)", year="January 22-24,1990", pages="411-421"} @article{kao90, author="M. Kao and F. Wan", title="Not all planar digraphs have small cycle separators", journal="Information Processing Letters", year="1990"} @techreport{ker69, author="B. W. Kernighan", title="Some graph partitioning problems related to program segmentation", number="Ph.D. Thesis", institution="Princeton University", year="1969"} @article{ker70, author="B. W. Kernighan and S. Lin", title="An efficient heuristic procedure for partitioning graphs", journal="Bell System Technical Journal", volume="49", year="1970", pages="291-307"} @article{kir83, author="S. Kirkpatrick and C. D. Gelatt Jr. and M. P. Vecchi", title="Optimization by simulated annealing", journal="Science", volume="220", year="1983", pages="671-680"} @article{kom85, author="J. Komlos and M. T. Shing", title="Probabilistic partitioning algorithms for the rectilinear Steiner problem", journal="Networks", volume="15", year="1985", pages="413-423"} @article{kri84, author="B. Krishnamurthy", title="An improved min-cut algorithm for partitioning {VLSI} networks", journal="IEEE Trans. on Computers", volume="C-33", year="1984", pages="438-446"} @article{kri87, author="B. Krishnamurthy", title="Constructing test cases for partitioning heuristics", journal="IEEE Trans. on Computers", volume="C-36", year="198", pages="1112-1114"} @inproceedings{lei82, author="F. T. Leighton", title="A layout strategy for {VLSI} which is provably good", booktitle="Proceedings of the 14th Annual ACM Symposium on Theory of Computing", year="1982", pages="85-98"} @book{lei80, author="C. Leiserson", title="Area-efficient graph layout (for vlsi)", booktitle="21st Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1980", pages="270-281"} @article{lin77, author="T. D. Lin and R. S. H. Mah", title="Hierarchical partition -- a new optimal pivoting algorithm", journal="Math. Programming", volume="12", year="1977", pages="260-278"} @article{lip80, author="R. J. Lipton and R. E. Tarjan", title="Applications of a planar separator theorem", journal="SICOMP", volume="9", year="1980", pages="615-627"} @techreport{mac78, author="R. M. Macgregor", title="On partitioning a graph: a theoretical and empirical study", number="UCB/ERL M78/14 (Ph.D. Thesis)", institution="Standford University", year="1978"} @inproceedings{mil84, author="G. L. Miller", title="Finding small simple cycle separators for 2-connected planar graphs", booktitle="Proceedings of the 16th Annual ACM Symposium on Theory of Computing", year="1984", pages="376-382"} @techreport{moo88, author="D. Moore", title="A round-robin parallel partitioning algorithm", number="TR 88-916", institution="DCS, Cornell University", year="1988"} @article{pai87, author="R. Paige and R. E. Tarjan", title="Three partition refinement algorithm", journal="SICOMP", volume="16", year="1987", pages="973-989"} @article{pow88, author="D. Powers", title="Graph partitioning by eigenvectors", journal="Lin. Alg. Appl.", volume="101", year="1988", pages="121-133"} @book{rao87, author="S. Rao", title="Finding near optimal separators in planar graphs", booktitle="28th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1987", pages="225-237"} @article{rav87, author="S. Ravi and H. Hunt III", title="An application of the planar separator theorem to counting problem", journal="Inform. Process. Letters", volume="25", year="1987", pages="317-322"} @techreport{ren90, author="F. Rendl and H. Wolkowicz", title="A projection technique for partitioning the nodes of a graph", number="CORR 90-20", institution="University of Waterloo", address="Waterloo, Ontario", year="1990"} @inproceedings{san76, author="A. Sangiovanni-Vincentelli", title="An optimization problem arising from tearing methods", booktitle="Sparse Matrix Computations", editor="J.R. Bunch and D.J. Rose", publisher="Academic Press", year="1976", pages="97-110"} @inproceedings{sch79, author="D. G. Schweikert and B. W. Kernighan", title="A proper model for the partitioning of electrical circuits", booktitle="Proc. 9th Design Automation Workshop", year="1979", pages="57-62"} @article{sen92, author="A. Sen and H. Deng and S. Guha", title="On a graph partition problem with application to vlsi layout", journal="Information Processing Letters", year="1992", volume="43", pages="87-94"} @techreport{she87, author="T. J. Sheffler", title="A graph separator theorem and its application to {G}aussian elimination to optimize {B}oolean expression for parallel evaluation", number="CMU-CS-87-123", institution="DCS, Carnegie-Mellon University", year="1987"} @inproceedings{shi80, author="H. Shiraishi and F. Hirose", title="Efficient placement and routing for masterslice {LSI}", booktitle="Proc. 17th Design Automation Conference", year="1980", pages="458-464"} @article{sua88, author="P. Suaris and G. Kedem", title="An algorithm for quadrisection and its application to standard cell placement", journal="IEEE Trans. Circuits and Systems", volume="35", year="1988", pages="294-303"} @article{tar??, author="R. E. Tarjan", title="Decomposition by clique separators", journal="Discrete Math", year="to appear"} @article{ven87, author="S. Venkatesan", title="Improved constants for some separator theorems", journal="J. Algorithms", volume="8", year="1987", pages="572-578"} @article{wan91, author="F. Wan", title="A linear-processor algorithm for finding small cycle separators on undirected planar graphs", journal="SICOMP", year="1991?"} @article{whi81, author="S. H. Whitesides", title="An algorithm for finding clique cutsets", journal="Inf. Proc. Letters", volume="12", year="1981", pages="31-32"} @incollection{matrixmarket97, author="R. F. Boisvert and R. Pozo and K. Remington and R. F. Barrett and J. J. Dongarra", title="Matrix {M}arket: a web resource for test matrix collections", booktitle="The Quality of Numerical Software: Assessment and Enhancement", publisher="Chapman and Hall, London", year="1997", editor="R. F. Boisvert", pages="125-137"} @article{ne92-rook, author="L. Neal and G. Poole", title="A geometric analysis of {G}aussian elimination II.}", journal="Linear Alg. and Appl.", volume="173", year="1992", pages="239-264"} @misc{fo96-rook, author="L. V. Foster", title="The growth factor and efficiency of {G}aussian elimination with rook pivoting", note="Accepted for publication in {\it J. Comp. and Appl. Math.}"} 91-407"} @article{gil84-chordal, author="J. R. Gilbert and D. J. Rose and A. Edenbrandt", title="A separator theorem for chordal graphs", journal="SIAM J. Alg. \& Disc. Meth.", volume="5", year="1984", pages="306-313"} @inproceedings{gol83, author="M. K. Goldberg and M. Burstein", title="Heuristic improvement technique for bisection of {VLSI} networks", booktitle="Proc. IEEE International Conf. on Computer Desidocumentation/FrontTrees/spooles.bib010064000020550007177000002003170663235746700212200ustar00clevecompmath00000400000006@article{ash97-partition, author="C. Ashcraft and J. W. H. Liu", title="Using domain decomposition to find graph bisectors", journal="BIT", volume="37", year="1997"} @techreport{kar94-mf, author="G. Karypis and V. Kumar", title="A high performance sparse {C}holesky factorization algorithm for scalable parallel computers", institution="Dept. of Computer Science, University of Minnesota", year="1994", number="94-41"} @techreport{SuperLU95, author="J. W. Demmel and S. C. Eisenstat and J. R. Gilbert and X. S. Li and J. W. H. Liu", title="A supernodal approach to sparse partial pivoting", institution="Xerox Palo Alto Research Center", number="CSL--94--14", year="1995", note="Accepted for publication in {\it SIAM J. Matrix. Anal.}"} @article{roth98-minfill, author="E. Rothberg and S. C. Eisenstat", title="Node selection strategies for bottom-up sparse matrix ordering", journal="SIAM J. Matrix Anal.", volume="19", year="1998", pages="682-695"} @article{pot93-proportional, author="A. Pothen and C. Sun", title="A mapping algorithm for parallel sparse {C}holesky factorization", journal="SIAM J. Sci. Comput.", volume="14", year="1993", pages="1253-1257"} @article{and90-random, author="S. L. Anderson", title="Random number generators on vector supercomputers and other advanced architectures", journal="SIAM Review", volume="32", year="1990", pages="221-251"} @misc{roger97-amalg, AUTHOR="R. Grimes", note="personal communication"} @misc{ash97-utah, AUTHOR="C. Ashcraft and S. C. Eisenstat and J. W. H. Liu", title="Practical extensions of the multisection ordering for sparse matrices", howpublished="Minisymposium presentation at the Sixth SIAM Conference on Applied Linear Algebra, Snowbird, Utah", year="October 29, 1997"} @misc{ash94-utah, AUTHOR="C. Ashcraft and J. W. H. Liu", title="Generalized nested dissection: some recent progress", howpublished="Minisymposium presentation at the Fifth SIAM Conference on Applied Linear Algebra, Snowbird, Utah", year="June 18, 1994"} @misc{rot96-balance, AUTHOR="E. Rothberg", title="Exploring the tradeoff between imbalance and separator size in nested dissection ordering", howpublished="unpublished", year="1996"} @misc{ro95-hybrid, AUTHOR="E. Rothberg", title="Robust ordering of sparse matrices: a minimum degree, nested dissection hybrid", howpublished="unpublished", year="1995"} @misc{rothberg95, AUTHOR="E. Rothberg", howpublished="private communication", year="1995"} @conference{rot96-mindefIdaho, author="E. Rothberg", title="Ordering sparse matrices using approximate minimum local fill", booktitle="Second SIAM Conference on Sparse Matrices", year="1996", note="Conference presentation"} @techreport{hr96-msndtalk, author="B. Hendrickson and E. Rothberg", title="Improving the runtime and quality of nested dissection ordering", booktitle="Second SIAM Conference on Sparse Matrices", year="1996", note="Conference presentation"} @conference{ng96-mindefIdaho, author="E. Ng and P. Raghavan", title="Minimum deficiency ordering", booktitle="Second SIAM Conference on Sparse Matrices", year="1996", note="Conference presentation"} @article{gib76-profile, AUTHOR = {N. E. Gibbs and W. G. Poole Jr and P. K. Stockmeyer}, JOURNAL = {SIAM. J. Numer. Anal.}, KEY = {LLt band profile}, PAGES = {236-250}, TITLE = {An algorithm for reducing the bandwidth and profile of a sparse matrix}, VOLUME = {13}, YEAR = {1976} } @techreport{rag95-PCO, author="P. Raghavan", title="Parallel ordering using edge contraction", number="CS-95-293", institution="Dept. of Computer Science, The University of Tennessee", address="Knoxville, Tennessee", year="1995"} @techreport{ame94-amdTR, author="P. Amestoy and T. Davis and I. Duff", title="An approximate minimum degree ordering algorithm", number = "TR-94-039", institution="University of Florida", year="1994"} @techreport{hr96-msnd, author="B. Hendrickson and E. Rothberg", title="Improving the runtime and quality of nested dissection ordering", institution="Sandia National Laboratories", year="1996"} @article{ash89-relaxed, author="C. Ashcraft and R. Grimes", title="The influence of relaxed supernode partitions on the multifrontal method", journal="ACM Trans. Math. Software", volume="15", year="1989", pages="291-309"} @techreport{ash95-AGL, author="C. Ashcraft and R. G. Grimes and J. G. Lewis", title="Accurate symmetric indefinite linear equation solvers", number="ISSTECH-95-029", institution="Boeing Computer Services", year="1995", note="Accepted for publication in {\it SIAM J. Matrix. Anal.}"} @article{ash98-multisection, author="C. Ashcraft and J. W. H. Liu", title="Robust ordering of sparse matrices using multisection", volume="19", pages="816-832", year="1998", journal="SIAM J. Matrix. Anal."} @techreport{ash95-DDSEP, author="C. Ashcraft and J. W. H. Liu", title="Using domain decompositions to find graph bisectors", number="ISSTECH-95-024", institution="Boeing Computer Services", year="1995", note="Accepted for publication in {\it BIT}"} @techreport{ash95-robust, author="C. Ashcraft and J. W. H. Liu", title="Robust ordering of sparse matrices using multisection", number="ISSTECH-96-002", institution="Boeing Computer Services", year="1996"} @article{ash98-maxflow, author="C. Ashcraft and J. W. H. Liu", title="Applications of the {D}ulmage-{M}endelsohn decomposition and network flow to graph bisection improvement", volume="19", pages="325-354", year="1999", journal="SIAM J. Matrix. Anal."} @techreport{ash96-maxflow, author="C. Ashcraft and J. W. H. Liu", title="Applications of the {D}ulmage-{M}endelsohn decomposition and network flow to graph bisection improvement", number="ISSTECH-96-017", institution="Boeing Computer Services", year="1996", note="Accepted for publication in {\it SIAM J. Matrix. Anal.}"} @techreport{ash93-compressed-graphs-TR, author="C. Ashcraft", title="Compressed graphs and the minimum degree algorithm", number="BCSTECH-93-024", institution="Boeing Computer Services", year="1993"} @techreport{ash94-partition, author="C. Ashcraft and J. W. H. Liu", title="A partition improvement algorithm for generalized nested dissection", number="BCSTECH-94-020", institution="Boeing Computer Services", year="1994"} @article{ber90-mindeg, author="P. Berman and G. Schnitger", title="On the performance of the minimum degree ordering for {G}aussian elimination", journal="SIAM J. Matrix Analysis and Applic.", volume="11", year="1990", pages="83-88"} @article{bha93-localND, author="M. V. Bhat and W. G. Habashi and J. W. H. Liu and V. N. Nguyen and M. F. Peeters", title="A note on nested dissection for rectangular grids", journal="SIAM J. Matrix Analysis and Applic.", volume="14", year="1993", pages="253-258"} @article{hr98-msnd, author="B. Hendrickson and E. Rothberg", title="Improving the runtime and quality of nested dissection ordering", pages={468-489}, journal={SIAM J. Sci. Comput.}, volume={20}, year="1998"} @TechReport{ karypis98metis, author = {G. Karypis and V. Kumar}, title = {METIS~4.0: Unstructured graph partitioning and sparse matrix ordering system}, institution = {Department of Computer Science, University of Minnesota}, year = {1998}, number = {}, note = {Available on the WWW at URL {\em http://www.cs.umn.edu/\~{}metis}} } @phdthesis{dam92-compressed, author="A. C. Damhaug", title="Sparse Solution of Finite Element Equations", school="The Norwegian Institute of Technology", year="1992"} @article{duf83-multifrontal, author="I. Duff and J. Reid", title="The multifrontal solution of indefinite sparse symmetric linear equations", journal="ACM Trans. Math. Software", volume="6", year="1983", pages="302-325"} @inproceedings{eis76-elementModel, author="S. C. Eisenstat and M. H. Schultz and A. H. Sherman", title="Applications of an element model for {G}aussian elimination", booktitle="Sparse Matrix Computations", pages="85-96", publisher="Academic Press", year="1976", editor="J. R. Bunch and D. J. Rose"} @inproceedings{fid82-partition, author="C. M. Fiduccia and R. M. Mattheyses", title="A linear-time heuristic for improving network partition", booktitle="ACM IEEE Proc. 19th Design Automation Conference, Las Vegas, Nevada", year="1982", pages="175-181"} @article{geo80-1way, author="J. A. George", title="An automatic one-way dissection algorithm for irregular finite element problems", journal="SIAM J. Numer. Anal.", volume="17", year="1980", pages="740-751"} @article{sparsematlab, author="J. Gilbert and C. Moler and R. Schreiber", title="Sparse matrices in {MATLAB}: design and implementation", journal="SIAM J. Matrix Analysis and Applic.", volume="13", year="1992", pages="335-356"} @techreport{gup96-WGPP, author="A. Gupta", title="{WGPP}: {W}atson {G}raph {P}artitioning and sparse matrix ordering {P}ackage", number="Users Manual", institution="IBM T.J. Watson Research Center", address="New York", year="1996"} @techreport{hea92-dissection, author="M.T. Heath and P. Raghavan", title="A Cartesian nested dissection algorithm", number="UIUCDCS-R-92-1772", institution="Dept of Computer Science, University of Illinois", address="Urbana, IL", year="1992"} @techreport{hen92-partition, author="B. Hendrickson and R. Leland", title="An improved spectral graph partitioning algorithm for mapping parallel computations", number="SAND92-1460", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1992"} @article{ker70-partition, author="B. W. Kernighan and S. Lin", title="An efficient heuristic procedure for partitioning graphs", journal="Bell System Technical Journal", volume="49", year="1970", pages="291-307"} @inproceedings{lei89-fidmat, author="C. E. Leiserson and J. G. Lewis", title="Orderings for parallel sparse symmetric factorization", booktitle="Parallel Processing for Scientific Computing", year="1989", pages="27-31"} @article{lip79-separators, author="R. J. Lipton and R. E. Tarjan", title="A separator theorem for planar graphs", journal="SIAM J. Applied Math", volume="36", year="1979", pages="177-189"} @article{liu89-separators, author="J. W. H. Liu", title="A graph partitioning algorithm by node separators", journal="ACM Trans. on Math. Software", volume="15", year="1989", pages="198-219"} @article{liu85-mfstorage, author="J. W. H. Liu", title="On the storage requirement in the out-of-core multifrontal method for sparse factorization", journal="ACM Trans. on Math. Software", volume="12", year="1986", pages="249-264"} @article{liu85-mmd, author="J. W. H. Liu", title="Modification of the minimum degree algorithm by multiple elimination", journal="ACM Trans. on Math. Software", volume="11", year="1985", pages="141-153"} @article{liu89-mindeg, author="J. W. H. Liu", title="On the minimum degree ordering with constraints", journal="SIAM J. Sci. Stat. Comput.", volume="10", year="1989", pages="1136-1145"} @article{liu90-etree, author="J. W. H. Liu", title="The role of elimination trees in sparse factorization", journal="SIAM J. Matrix Analysis and Applic.", volume="11", year="1990", pages="134-172"} @article{liu91-generalizedEnvelope, author="J. W. H. Liu", title="A generalized envelope method for sparse factorization by rows", journal="ACM Trans. on Math. Software", volume="17", year="1991", pages="112-129"} @article{mar57, author="H. M. Markowitz", title="The elimination form of the inverse and its application to linear programming", journal="Management Sci.", volume="3", year="1957", pages="255-269"} @mastersthesis{ng79-master, author="E. Ng", title="On one-way dissection schemes", school="Dept of Computer Science, University of Waterloo", address="Waterloo, Ontario", year="1979"} @techreport{rag93-separators, author="P. Raghavan", title="Line and plane separators", number="UIUCDCS-R-93-1794", institution="Dept of Computer Science, University of Illinois", address="Urbana, IL", year="1993"} @inproceedings{ros72-elimination, author="D. J. Rose", title="A graph-theoretic study of the numerical solution of sparse positive definite systems of linear equations", booktitle="Graph Theory and Computing", publisher="Academic Press", editor="R. Read", year="1972", pages="183-217"} @article{ros70-elimination, author="D. J. Rose", title="Triangulated graphs and the elimination process", journal="J. Math. Anal. & Appl.", volume="32", year="1970", pages="597-609"} @techreport{ten91-separators, author="S.H. Teng", title="Points, Spheres, and Separators", number="CMU-CS-91-184", institution="School of Computer Science, Carnegie Mellon University", address="Pittsburgh, PA", year="1991"} @article{tin67-order, author="W. F. Tinney and J. W. Walker", title="Direct solutions of sparse network equations by optimally ordered triangular factorization", journal="J Proc. IEEE", volume="55", year="1967", pages="1801-1809"} @book{aho83, author="A. V. Aho and J. E. Hopcroft and J. D. Ullman", title="Data Structures and Algorithms", publisher="Addison-Wesley", address="Reading, MA", year="1983"} @book{duf87-book, author="I. S. Duff and A. M. Erisman and J. K. Reid", title="Direct Methods for Sparse Matrices", publisher="Oxford University Press", address="London", year="1987"} @article{ash87-progress, AUTHOR = {C. Ashcraft and R. Grimes and J. Lewis and B. Peyton and H. Simon}, JOURNAL = {Intern. J. of Supercomputer Applications}, KEY = {LLt vector}, PAGES = {10-30}, TITLE = {Progress in sparse matrix methods for large sparse linear systems on vector supercomputers}, VOLUME = {1}, YEAR = {1987} } @techreport{ash90-partition, author="C. Ashcraft", title="The domain/segment partition for the factorization of sparse symmetric positive definite matrices", number="ECA-TR-148", institution="Boeing Computer Services", address="Seattle, WA", year="1990"} @article{ash95-compressed-graphs, author="C. Ashcraft", title="Compressed graphs and the minimum degree algorithm", journal="SIAM J. Sci. Comput.", pages = "1404-1411", volume = 16, year="1995"} @inproceedings{ash90-lookahead, author="C. Ashcraft and S. C. Eisenstat and J. W. H. Liu and B. W. Peyton and A. H. Sherman", title="A compute-ahead fan-in scheme for parallel sparse matrix factorization", booktitle="Fourth Canadian Supercomputing Symposium (1990)", editor="D. Pelletier", year="June, 1990", pages="351-361"} @inproceedings{ash94-multisection, author="C. Ashcraft and J. W. H. Liu", title="Generalized nested dissection: some recent progress", booktitle="Fifth SIAM Conference on Applied Linear Algebra", address="Snowbird, Utah", year="June 18, 1994"} @inproceedings{bar93-partition, author="S. T. Barnard and H. D. Simon", title="A fast multilevel implementation of recursive spectral bisection for partitioning unstructured problems", booktitle="Proceedings of the Sixth SIAM Conference on Parallel Processing for Scientific Computing", year="1993", pages="711-718"} @inproceedings{bar95-partition, author="S. T. Barnard and H. D. Simon", title="A parallel implementation of multilevel recursive spectral bisection for applications in adaptive unstructured meshes", booktitle="Proceedings of the seventh SIAM Conference on Parallel Processing for Scientific Computing", year="1995", pages="627-632"} @article{bui92-partition, author="T. Bui and C. Jones", title="Finding good approximate vertex and edge partitions is {NP}-hard", journal="Information Processing Letters", volume="42", year="1992", pages="153-159"} @inproceedings{bui93-partition, author="T. Bui and C. Jones", title="A heuristic for reducing fill-in in sparse matrix factorization", booktitle="Proceedings of Sixth SIAM Conference on Parallel Processing ", year="1993", pages="445-452"} @article{geo73-nested, author="J. A. George", title="Nested dissection of a regular finite element mesh", journal="SIAM J. Numer. Anal.", volume="10", year="1973", pages="345-363"} @article{geo89-mindeg, author="J.A. George and J. W. H. Liu", title="The evolution of the minimum degree ordering algorithm", journal="SIAM Review", volume="31", year="1989", pages="1-19"} @techreport{goe95-partition, author="T. Goehring and Y. Saad", title="Heuristic algorithms for automatic graph partitioning", number="", institution="Computer Science Department, University of Minnesota", address="Minnesota", year="1995"} @article{hal35, author = "P. Hall", title = "On representatives of subsets", journal = "J. London Math. Society", volume = "10", year = "1935", pages = "26-30"} @article{Harwell-Boeing-Matrices, author = "I.S. Duff and R.G. Grimes and J.G. Lewis", title = "Sparse matrix test problems", journal="ACM Trans. on Math. Software", volume = "15", year = "1989", pages = "1-14"} @techreport{sparspak80, author="J. A. George and J. W. H. Liu and E. G. Ng", title="User's guide for {SPARSPAK}: {W}aterloo sparse linear equations package", number = "Tech. Rep. CS78-30(revised)", institution = "Dept. of Computer Sciences, Univ. of Waterloo", address="Waterloo, Ontario, Canada", year = "1980"} @techreport{hen93-spectral, author="B. Hendrickson and R. Leland", title="Multidimensional spectral load balancing", number="SAND93-074", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @techreport{kar95-kway, author="G. Karypis and V. Kumar", title="Multilevel $k$-way partitioning scheme for irregular graphs", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} % number="Technical Report", @techreport{kar95-multilevel, author="G. Karypis and V. Kumar", title="A fast and high quality multilevel scheme for partitioning irregular graphs", number="TR 95-035", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} @techreport{kar95-metis, author="G. Karypis and V. Kumar", title="{METIS}: Unstructured graph partitioning and sparse matrix ordering system", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} % number="TR 95-???", @techreport{kar95-partition, author="G. Karypis and V. Kumar", title="Analysis of multilevel graph partitioning", number="TR 95-037", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} @inproceedings{kar95, author="G. Karypis and V. Kumar", title="Multilevel graph partition and sparse matrix ordering", booktitle="Intl. Conf. on Parallel Processing", year="1995"} @article{lip79, author="R. J. Lipton and R. E. Tarjan", title="A separator theorem for planar graphs", journal="SIAM J. Applied Math", volume="36", year="1979", pages="177-189"} @techreport{mai94-partition, author="H.S. Maini and K.G. Mehrotra and S. Ranka", title="Genetic algorithms for graph partitioning and incremental graph partitioning", number="Technical report", institution="Center for Science and Technology, Syracuse University", address="Synracuse, N.Y.", year="1994"} @article{pot90-triangular, author="A. Pothen and C. Fan", title="Computing the block triangular form of a sparse matrix", journal="ACM Trans. on Math. Software", volume="16", year="1990", pages="303-324"} @article{pot90-partition, author="A. Pothen and H. Simon and K.P. Liou", title="Partitioning sparse matrices with eigenvectors of graphs", journal="SIAM J. Matrix Analysis and Applic.", volume="11", year="1990", pages="430-452"} @book{aho83, author="A. V. Aho and J. E. Hopcroft and J. D. Ullman", title="Data Structures and Algorithms", publisher="Addison-Wesley", address="Reading, MA", year="1983"} @book{ull84-vlsi, author="J. D. Ullman", title="Computational Aspects of VLSI", publisher="Computer Science Press", address="Rockville, Md", year="1984"} @book{duf87-book, author="I. S. Duff and A. M. Erisman and J. K. Reid", title="Direct Methods for Sparse Matrices", publisher="Oxford University Press", address="London", year="1987"} @book{zzzz99-book, author="J. A. George and J. W. H. Liu", title="Computer Solution of Large Sparse Positive Definite Systems", publisher="Prentice-Hall", address="Englewood Cliffs, NJ", year="1981"} @article{arn85, author="S. Arnborg", title="Efficient algorithms for combinatorial problems on graphs with bounded decomposability - a survey", journal="BIT", volume="25", year="1985", pages="2-23"} @techreport{bar81, author="E. R. Barnes", title="An algorithm for partitioning the nodes of a graph", number="RC8690", institution="IBM Thomas J. Watson Research Center", address="Yorktown Heights, New York", year="1981"} @inproceedings{bar85, author="E. R. Barnes", title="Partitioning the nodes of a graph", booktitle="Graph Theory with Applications to Algorithms and Computer Science", editor="Y. Alavi and G. Chartrand and D. Lick and C. Wall and L. Lesuiak", publisher="John Wiley \& Sons Inc.", address="New York", year="1985", pages="57-72"} @article{bha84, author="S. N. Bhatt and F. T. Leighton", title="A framework for solving {VLSI} graph layout problems", journal="Journal of Computer \& Systems Sciences", volume="28", year="1984", pages=""} @inproceedings{bre77, author="M. A. Breuer", title="A class of min-cut placement algorithms", booktitle="Proc. 14th Design Automation Conference", year="1977", pages="284-290"} @inproceedings{bui84, author="S. N. Bui and S. Chaudhuri and T. Leighton and M. Sipser", title="Graph bisection algorithms with good average case behavior", booktitle="Proceedings of the 25th Annual Symposium of Foundations of Computer Science", year="1984", pages="181-192"} @article{dji81, author="H. N. Djidjev", title="A separator theorem", journal="Comptes rendus de l' Academie bulgare des Sciences", volume="34", year="1981", pages="643-645"} @article{dji82-linear, author="H. N. Djidjev", title="A linear algorithm for partitioning graphs", journal="Comptes rendus de l' Academie bulgare des Sciences", volume="35", year="1982", pages="1053-1056"} @article{dji82-planar, author="H. N. Djidjev", title="On the problem of partitioning planar graphs", journal="SIAM J. Alg. \& Disc. Meth.", volume="3", year="1982", pages="229-240"} @article{don72, author="W. E. Donath and A. J. Hoffman", title="Algorithms for partitioning of graphs and computer logic based on eigenvectors of connection matrices", journal="IBM Technical Disclosure Bulletin", volume="15", year="1972", pages="938-944"} @article{don73, author="W. E. Donath and A. J. Hoffman", title="Lower bounds for the partitioning of graphs", journal="IBM J. Res. Develop.", volume="17", year="1973", pages="420-425"} @article{fie73, author="M. Fiedler", title="Algebraic connectivity of graphs", journal="Czechoslovak Math J.", volume="23", year="1973", pages="298-305"} @book{fre86, author="G. N. Fredrickson and R. Janardan", title="Separator-based strategies for efficient message routing", booktitle="27th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1986", pages="428-437"} @book{gaz87, author="H. Gazit and G. L. Miller", title="A parallel algorithm for finding a separator in planar graphs", booktitle="28th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1987", pages="238-248"} @techreport{gil80, author="J. R. Gilbert", title="Graph separator theorems and sparse {G}aussian elimination", number="Ph.D. Thesis", institution="DCS, Stanford University", year="1980"} @article{gil84-genus, author="J. R. Gilbert and J. P. Hutchinson and R. E. Tarjan", title="A separator theorem for graphs of bounded genus", journal="J. of Algorithms", volume="5", year="1984", pages="391-407"} @article{gil84-chordal, author="J. R. Gilbert and D. J. Rose and A. Edenbrandt", title="A separator theorem for chordal graphs", journal="SIAM J. Alg. \& Disc. Meth.", volume="5", year="1984", pages="306-313"} @inproceedings{gol83, author="M. K. Goldberg and M. Burstein", title="Heuristic improvement technique for bisection of {VLSI} networks", booktitle="Proc. IEEE International Conf. on Computer Design", address="Port Chester, New York", year="1983", pages="122-125"} @techreport{gol87, author="M. K. Goldberg and S. Lath and J. W. Roberts", title="Heuristics for the graph bisection problem", number="Report", institution="Rensselaer Polytechnic Institute", year="1987"} @techreport{hen92, author="B. Hendrickson and R. Leland", title="An improved spectral graph partitioning algorithm for mapping parallel computations", number="SAND92-1460", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1992"} @techreport{hen93, author="B. Hendrickson and R. Leland", title="Multidimensional spectral load balancing", number="SAND93-074", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @article{hu81, author="T. C. Hu and M. T. Shing", title="An O(n) algorithm to find a near-optimum partition", journal="Journal of Algorithms", volume="2", year="1981", pages="122-138"} @article{hu85, author="T. C. Hu and M. T. Shing", title="A decomposition algorithm for circuit routing", journal="Math. Programming Study", volume="24", year="1985", pages="87-103"} @article{hu86, author="T. C. Hu and M. T. Shing", title="A decomposition algorithm for multi-terminal network flows", journal="J. Discrete Applied Math.", volume="13", year="1986", pages="165-181"} @article{joh88, author="D. S. Johnson and C. R. Aragon and L. A. McGeoch and C. Schevon", title="Optimization by simulated annealing: an experimental evaluation", journal="Operations Research", note="((submitted))", year="1988"} @article{kan91, author="A. Kanevsky and V. Ramachandran", title="Improved algorithms for graph four-connectivity", journal="J. of Computer Science and Systems", volume="42", year="1991", pages="288-306"} @article{kan9x, author="A. Kanevsky", title="Finding all minimum size vertex sets in a graph", journal="J. of Networks", year="199x"} @inproceedings{kan90, author="A. Kanevsky", title="On the number of minimum size separating vertex sets of a graph and how to find all of them", booktitle="First Annual ACM-SIAM Symposium on Discrete Algorithms (SODA '90)", year="January 22-24,1990", pages="411-421"} @article{kao90, author="M. Kao and F. Wan", title="Not all planar digraphs have small cycle separators", journal="Information Processing Letters", year="1990"} @techreport{ker69, author="B. W. Kernighan", title="Some graph partitioning problems related to program segmentation", number="Ph.D. Thesis", institution="Princeton University", year="1969"} @article{ker70, author="B. W. Kernighan and S. Lin", title="An efficient heuristic procedure for partitioning graphs", journal="Bell System Technical Journal", volume="49", year="1970", pages="291-307"} @article{kir83, author="S. Kirkpatrick and C. D. Gelatt Jr. and M. P. Vecchi", title="Optimization by simulated annealing", journal="Science", volume="220", year="1983", pages="671-680"} @article{kom85, author="J. Komlos and M. T. Shing", title="Probabilistic partitioning algorithms for the rectilinear Steiner problem", journal="Networks", volume="15", year="1985", pages="413-423"} @article{kri84, author="B. Krishnamurthy", title="An improved min-cut algorithm for partitioning {VLSI} networks", journal="IEEE Trans. on Computers", volume="C-33", year="1984", pages="438-446"} @article{kri87, author="B. Krishnamurthy", title="Constructing test cases for partitioning heuristics", journal="IEEE Trans. on Computers", volume="C-36", year="198", pages="1112-1114"} @inproceedings{lei82, author="F. T. Leighton", title="A layout strategy for {VLSI} which is provably good", booktitle="Proceedings of the 14th Annual ACM Symposium on Theory of Computing", year="1982", pages="85-98"} @book{lei80, author="C. Leiserson", title="Area-efficient graph layout (for vlsi)", booktitle="21st Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1980", pages="270-281"} @article{lin77, author="T. D. Lin and R. S. H. Mah", title="Hierarchical partition -- a new optimal pivoting algorithm", journal="Math. Programming", volume="12", year="1977", pages="260-278"} @article{lip80, author="R. J. Lipton and R. E. Tarjan", title="Applications of a planar separator theorem", journal="SICOMP", volume="9", year="1980", pages="615-627"} @techreport{mac78, author="R. M. Macgregor", title="On partitioning a graph: a theoretical and empirical study", number="UCB/ERL M78/14 (Ph.D. Thesis)", institution="Standford University", year="1978"} @inproceedings{mil84, author="G. L. Miller", title="Finding small simple cycle separators for 2-connected planar graphs", booktitle="Proceedings of the 16th Annual ACM Symposium on Theory of Computing", year="1984", pages="376-382"} @techreport{moo88, author="D. Moore", title="A round-robin parallel partitioning algorithm", number="TR 88-916", institution="DCS, Cornell University", year="1988"} @article{pai87, author="R. Paige and R. E. Tarjan", title="Three partition refinement algorithm", journal="SICOMP", volume="16", year="1987", pages="973-989"} @article{pow88, author="D. Powers", title="Graph partitioning by eigenvectors", journal="Lin. Alg. Appl.", volume="101", year="1988", pages="121-133"} @book{rao87, author="S. Rao", title="Finding near optimal separators in planar graphs", booktitle="28th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1987", pages="225-237"} @article{rav87, author="S. Ravi and H. Hunt III", title="An application of the planar separator theorem to counting problem", journal="Inform. Process. Letters", volume="25", year="1987", pages="317-322"} @techreport{ren90, author="F. Rendl and H. Wolkowicz", title="A projection technique for partitioning the nodes of a graph", number="CORR 90-20", institution="University of Waterloo", address="Waterloo, Ontario", year="1990"} @inproceedings{san76, author="A. Sangiovanni-Vincentelli", title="An optimization problem arising from tearing methods", booktitle="Sparse Matrix Computations", editor="J.R. Bunch and D.J. Rose", publisher="Academic Press", year="1976", pages="97-110"} @inproceedings{sch79, author="D. G. Schweikert and B. W. Kernighan", title="A proper model for the partitioning of electrical circuits", booktitle="Proc. 9th Design Automation Workshop", year="1979", pages="57-62"} @article{sen92, author="A. Sen and H. Deng and S. Guha", title="On a graph partition problem with application to vlsi layout", journal="Information Processing Letters", year="1992", volume="43", pages="87-94"} @techreport{she87, author="T. J. Sheffler", title="A graph separator theorem and its application to {G}aussian elimination to optimize {B}oolean expression for parallel evaluation", number="CMU-CS-87-123", institution="DCS, Carnegie-Mellon University", year="1987"} @inproceedings{shi80, author="H. Shiraishi and F. Hirose", title="Efficient placement and routing for masterslice {LSI}", booktitle="Proc. 17th Design Automation Conference", year="1980", pages="458-464"} @article{sua88, author="P. Suaris and G. Kedem", title="An algorithm for quadrisection and its application to standard cell placement", journal="IEEE Trans. Circuits and Systems", volume="35", year="1988", pages="294-303"} @article{tar??, author="R. E. Tarjan", title="Decomposition by clique separators", journal="Discrete Math", year="to appear"} @article{ven87, author="S. Venkatesan", title="Improved constants for some separator theorems", journal="J. Algorithms", volume="8", year="1987", pages="572-578"} @article{wan91, author="F. Wan", title="A linear-processor algorithm for finding small cycle separators on undirected planar graphs", journal="SICOMP", year="1991?"} @article{whi81, author="S. H. Whitesides", title="An algorithm for finding clique cutsets", journal="Inf. Proc. Letters", volume="12", year="1981", pages="31-32"} @incollection{matrixmarket97, author="R. F. Boisvert and R. Pozo and K. Remington and R. F. Barrett and J. J. Dongarra", title="Matrix {M}arket: a web resource for test matrix collections", booktitle="The Quality of Numerical Software: Assessment and Enhancement", publisher="Chapman and Hall, London", year="1997", editor="R. F. Boisvert", pages="125-137"} @article{ne92-rook, author="L. Neal and G. Poole", title="A geometric analysis of {G}aussian elimination {II}.", journal="Linear Alg. and Appl.", volume="173", year="1992", pages="239-264"} @misc{fo96-rook, author="L. V. Foster", title="The growth factor and efficiency of {G}aussian elimination with rook pivoting", note="Accepted for publication in {\it J. Comp. and Appl. Math.}"} @incollection{ash93-fan-both, author="C. Ashcraft", booktitle="Graph Theory and Sparse Matrix Computation", title="The fan-both family of column-based distributed {C}holesky factorization algorithms", pages="159-190", publisher="Springer-Verlag", year="1993"} @article{ash90-fan-in, author="C. Ashcraft and S. Eisenstat and J. W. H. Liu", title="A fan-in algorithm for distributed sparse numerical factorization", journal="SIAM J. Sci. Stat. Comput.", volume="11", year="1990"} @proceedings{geo87-fan-out, author="J. A. George and J. W. H. Liu and E. Ng", title="Communication reduction in parallel sparse {C}holesky on a hypercube", booktitle="Hypercube Multiprocessors 1987", editor="M. Heath", publisher="SIAM Press", year="1987"} @article{sch82-etree, author="R. Schreiber", journal="ACM Trans. Math. Soft.", title="A new implementation of sparse {G}aussian elimination", pages="256-276", year="1982"} @book{hig96-asna, author="N. J. Higham", title="Accuracy and Stability of Numerical Algorithms", publisher="SIAM", year="1996"} @article{and90-random, author="S. L. Anderson", title="Random number generators on vector supercomputers and other advanced architectures", journal="SIAM Review", volume="32", year="1990", pages="221-251"} @misc{ash94-utah, author="C. Ashcraft and J. W. H. Liu", title="Generalized nested dissection: some recent progress", howpublished="Minisymposium presentation at the Fifth SIAM Conference on Applied Linear Algebra, Snowbird, Utah", year="June 18, 1994"} @misc{rothberg95, AUTHOR="E. Rothberg", howpublished="private communication", year="1995"} @article{gib76-profile, AUTHOR = {N. E. Gibbs and W. G. Poole Jr and P. K. Stockmeyer}, JOURNAL = {SIAM. J. Numer. Anal.}, KEY = {LLt band profile}, PAGES = {236-250}, TITLE = {An algorithm for reducing the bandwidth and profile of a sparse matrix}, VOLUME = {13}, YEAR = {1976} } @techreport{ame94-amdTR, author="P. Amestoy and T. Davis and I. Duff", title="An approximate minimum degree ordering algorithm", number = "TR-94-039", institution="University of Florida", year="1994"} @article{ame96-amd, author="P. Amestoy and T. Davis and I. Duff", title="An approximate minimum degree ordering algorithm", journal="SIAM J. Matrix Anal. Appl.", volume="17", pages="886-905", year="1996"} @techreport{ash95-pivoting, author="C. Ashcraft and R. G. Grimes and J. G. Lewis", title="Accurate symmetric indefinite linear equation solvers", number="ISSTECH-95-029", institution="Boeing Computer Services", year="1995"} @techreport{ash95-robust, author="C. Ashcraft and J. W. H. Liu", title="Robust ordering of sparse matrices using multisection", number="ISSTECH-96-002", institution="Boeing Computer Services", year="1996"} @techreport{ash93-compressed-graphs-TR, author="C. Ashcraft", title="Compressed graphs and the minimum degree algorithm", number="BCSTECH-93-024", institution="Boeing Computer Services", year="1993"} @article{ber90-mindeg, author="P. Berman and G. Schnitger", title="On the performance of the minimum degree ordering for {G}aussian elimination", journal="SIAM J. Matrix Analysis and Applic.", volume="11", year="1990", pages="83-88"} @phdthesis{dam92-compressed, author="A. C. Damhaug", title="Sparse Solution of Finite Element Equations", school="The Norwegian Institute of Technology", year="1992"} @inproceedings{eis76-elementModel, author="S. C. Eisenstat and M. H. Schultz and A. H. Sherman", title="Applications of an element model for {G}aussian elimination", booktitle="Sparse Matrix Computations", pages="85-96", publisher="Academic Press", year="1976", editor="J. R. Bunch and D. J. Rose"} @article{geo80-1way, author="J. A. George", title="An automatic one-way dissection algorithm for irregular finite element problems", journal="SIAM J. Numer. Anal.", volume="17", year="1980", pages="740-751"} @article{sparsematlab, author="J. Gilbert and C. Moler and R. Schreiber", title="Sparse matrices in {MATLAB}: design and implementation", journal="SIAM J. Matrix Analysis and Applic.", volume="13", year="1992", pages="335-356"} @techreport{hea92-dissection, author="M.T. Heath and P. Raghavan", title="A Cartesian nested dissection algorithm", number="UIUCDCS-R-92-1772", institution="Dept of Computer Science, University of Illinois", address="Urbana, IL", year="1992"} @techreport{hen92-partition, author="B. Hendrickson and R. Leland", title="An improved spectral graph partitioning algorithm for mapping parallel computations", number="SAND92-1460", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1992"} @article{ker70-partition, author="B. W. Kernighan and S. Lin", title="An efficient heuristic procedure for partitioning graphs", journal="Bell System Technical Journal", volume="49", year="1970", pages="291-307"} @article{lip79-separators, author="R. J. Lipton and R. E. Tarjan", title="A separator theorem for planar graphs", journal="SIAM J. Applied Math", volume="36", year="1979", pages="177-189"} @article{liu89-separators, author="J. W. H. Liu", title="A graph partitioning algorithm by node separators", journal="ACM Trans. on Math. Software", volume="15", year="1989", pages="198-219"} @article{liu85-mfstorage, author="J. W. H. Liu", title="On the storage requirement in the out-of-core multifrontal method for sparse factorization", journal="ACM Trans. on Math. Software", volume="12", year="1986", pages="249-264"} @article{liu89-mindeg, author="J. W. H. Liu", title="On the minimum degree ordering with constraints", journal="SIAM J. Sci. Stat. Comput.", volume="10", year="1989", pages="1136-1145"} @article{liu91-generalizedEnvelope, author="J. W. H. Liu", title="A generalized envelope method for sparse factorization by rows", journal="ACM Trans. on Math. Software", volume="17", year="1991", pages="112-129"} @article{mar57, author="H. M. Markowitz", title="The elimination form of the inverse and its application to linear programming", journal="Management Sci.", volume="3", year="1957", pages="255-269"} @mastersthesis{ng79-master, author="E. Ng", title="On one-way dissection schemes", school="Dept of Computer Science, University of Waterloo", address="Waterloo, Ontario", year="1979"} @techreport{rag93-separators, author="P. Raghavan", title="Line and plane separators", number="UIUCDCS-R-93-1794", institution="Dept of Computer Science, University of Illinois", address="Urbana, IL", year="1993"} @inproceedings{ros72-elimination, author="D. J. Rose", title="A graph-theoretic study of the numerical solution of sparse positive definite systems of linear equations", booktitle="Graph Theory and Computing", publisher="Academic Press", editor="R. Read", year="1972", pages="183-217"} @article{ros70-elimination, author="D. J. Rose", title="Triangulated graphs and the elimination process", journal="J. Math. Anal. & Appl.", volume="32", year="1970", pages="597-609"} @techreport{ten91-separators, author="S.H. Teng", title="Points, Spheres, and Separators", number="CMU-CS-91-184", institution="School of Computer Science, Carnegie Mellon University", address="Pittsburgh, PA", year="1991"} @article{tin67-order, author="W. F. Tinney and J. W. Walker", title="Direct solutions of sparse network equations by optimally ordered triangular factorization", journal="J Proc. IEEE", volume="55", year="1967", pages="1801-1809"} @book{aho83, author="A. V. Aho and J. E. Hopcroft and J. D. Ullman", title="Data Structures and Algorithms", publisher="Addison-Wesley", address="Reading, MA", year="1983"} @book{duf87-book, author="I. S. Duff and A. M. Erisman and J. K. Reid", title="Direct Methods for Sparse Matrices", publisher="Oxford University Press", address="London", year="1987"} @book{geo81-book, author="J. A. George and J. W. H. Liu", title="Computer Solution of Large Sparse Positive Definite Systems", publisher="Prentice-Hall", address="Englewood Cliffs, NJ", year="1981"} @article{ash87-progress, AUTHOR = {C. Ashcraft and R. Grimes and J. Lewis and B. Peyton and H. Simon}, JOURNAL = {Intern. J. of Supercomputer Applications}, KEY = {LLt vector}, PAGES = {10-30}, TITLE = {Progress in sparse matrix methods for large sparse linear systems on vector supercomputers}, VOLUME = {1}, YEAR = {1987} } @techreport{ash90-partition, author="C. Ashcraft", title="The domain/segment partition for the factorization of sparse symmetric positive definite matrices", number="ECA-TR-148", institution="Boeing Computer Services", address="Seattle, WA", year="1990"} @article{ash95-compressed-graphs, author="C. Ashcraft", title="Compressed graphs and the minimum degree algorithm", journal="SIAM J. Sci. Comput.", pages = "1404-1411", volume = 16, year="1995"} @techreport{AELS90-comparison, author="C. Ashcraft and S. Eisenstat and J. Liu and A. Sherman", title="A comparison of three distributed column based distributed factorization schemes", number="Technical Report YALEU/DCS/RR-810", institution="Department of Computer Science, Yale University", year="1990"} @inproceedings{ash94-multisection, author="C. Ashcraft and J. W. H. Liu", title="Generalized nested dissection: some recent progress", booktitle="Fifth SIAM Conference on Applied Linear Algebra", address="Snowbird, Utah", year="June 18, 1994"} @inproceedings{bar95-partition, author="S. T. Barnard and H. D. Simon", title="A parallel implementation of multilevel recursive spectral bisection for applications in adaptive unstructured meshes", booktitle="Proceedings of the seventh SIAM Conference on Parallel Processing for Scientific Computing", year="1995", pages="627-632"} @article{bui92-partition, author="T. Bui and C. Jones", title="Finding good approximate vertex and edge partitions is {NP}-hard", journal="Information Processing Letters", volume="42", year="1992", pages="153-159"} @article{geo89-mindeg, author="J.A. George and J. W. H. Liu", title="The evolution of the minimum degree ordering algorithm", journal="SIAM Review", volume="31", year="1989", pages="1-19"} @techreport{goe95-partition, author="T. Goehring and Y. Saad", title="Heuristic algorithms for automatic graph partitioning", number="", institution="Computer Science Department, University of Minnesota", address="Minnesota", year="1995"} @article{hal35, author = "P. Hall", title = "On representatives of subsets", journal = "J. London Math. Society", volume = "10", year = "1935", pages = "26-30"} @article{dul58, author = "A.L. Dulmage and N.S. Mendelsohn", title = "Coverings of bipartite graphs", journal="Can. J. Math", volume = "10", year = "1958", pages = "517-534"} @techreport{sparspak80, author="J. A. George and J. W. H. Liu and E. G. Ng", title="User's guide for {SPARSPAK}: {W}aterloo sparse linear equations package", number = "Tech. Rep. CS78-30(revised)", institution = "Dept. of Computer Sciences, Univ. of Waterloo", address="Waterloo, Ontario, Canada", year = "1980"} @techreport{hen93-chaco, author="B. Hendrickson and R. Leland", title="The {C}haco user's guide", number="SAND93-2339", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @techreport{hen93-partition, author="B. Hendrickson and R. Leland", title="A multilevel algorithm for partitioning graphs", number="SAND93-1301", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @techreport{hen93-spectral, author="B. Hendrickson and R. Leland", title="Multidimensional spectral load balancing", number="SAND93-074", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @techreport{kar95-kway, author="G. Karypis and V. Kumar", title="Multilevel $k$-way partitioning scheme for irregular graphs", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} @techreport{kar95-partition, author="G. Karypis and V. Kumar", title="Analysis of multilevel graph partitioning", number="TR 95-037", institution="Department of Computer Science, University of Minnesota", address="Minnesota", year="1995"} @inproceedings{kar95, author="G. Karypis and V. Kumar", title="Multilevel graph partition and sparse matrix ordering", booktitle="Intl. Conf. on Parallel Processing", year="1995"} @article{lip79, author="R. J. Lipton and R. E. Tarjan", title="A separator theorem for planar graphs", journal="SIAM J. Applied Math", volume="36", year="1979", pages="177-189"} @techreport{mai94-partition, author="H.S. Maini and K.G. Mehrotra and S. Ranka", title="Genetic algorithms for graph partitioning and incremental graph partitioning", number="Technical report", institution="Center for Science and Technology, Syracuse University", address="Synracuse, N.Y.", year="1994"} @book{aho83, author="A. V. Aho and J. E. Hopcroft and J. D. Ullman", title="Data Structures and Algorithms", publisher="Addison-Wesley", address="Reading, MA", year="1983"} @book{ull84-vlsi, author="J. D. Ullman", title="Computational Aspects of VLSI", publisher="Computer Science Press", address="Rockville, Md", year="1984"} @book{duf87-book, author="I. S. Duff and A. M. Erisman and J. K. Reid", title="Direct Methods for Sparse Matrices", publisher="Oxford University Press", address="London", year="1987"} @book{zzzz99-book, author="J. A. George and J. W. H. Liu", title="Computer Solution of Large Sparse Positive Definite Systems", publisher="Prentice-Hall", address="Englewood Cliffs, NJ", year="1981"} @article{arn85, author="S. Arnborg", title="Efficient algorithms for combinatorial problems on graphs with bounded decomposability - a survey", journal="BIT", volume="25", year="1985", pages="2-23"} @techreport{bar81, author="E. R. Barnes", title="An algorithm for partitioning the nodes of a graph", number="RC8690", institution="IBM Thomas J. Watson Research Center", address="Yorktown Heights, New York", year="1981"} @inproceedings{bar85, author="E. R. Barnes", title="Partitioning the nodes of a graph", booktitle="Graph Theory with Applications to Algorithms and Computer Science", editor="Y. Alavi and G. Chartrand and D. Lick and C. Wall and L. Lesuiak", publisher="John Wiley \& Sons Inc.", address="New York", year="1985", pages="57-72"} @article{bha84, author="S. N. Bhatt and F. T. Leighton", title="A framework for solving {VLSI} graph layout problems", journal="Journal of Computer \& Systems Sciences", volume="28", year="1984", pages=""} @inproceedings{bre77, author="M. A. Breuer", title="A class of min-cut placement algorithms", booktitle="Proc. 14th Design Automation Conference", year="1977", pages="284-290"} @inproceedings{bui84, author="S. N. Bui and S. Chaudhuri and T. Leighton and M. Sipser", title="Graph bisection algorithms with good average case behavior", booktitle="Proceedings of the 25th Annual Symposium of Foundations of Computer Science", year="1984", pages="181-192"} @article{dji81, author="H. N. Djidjev", title="A separator theorem", journal="Comptes rendus de l' Academie bulgare des Sciences", volume="34", year="1981", pages="643-645"} @article{dji82-linear, author="H. N. Djidjev", title="A linear algorithm for partitioning graphs", journal="Comptes rendus de l' Academie bulgare des Sciences", volume="35", year="1982", pages="1053-1056"} @article{dji82-planar, author="H. N. Djidjev", title="On the problem of partitioning planar graphs", journal="SIAM J. Alg. \& Disc. Meth.", volume="3", year="1982", pages="229-240"} @article{don72, author="W. E. Donath and A. J. Hoffman", title="Algorithms for partitioning of graphs and computer logic based on eigenvectors of connection matrices", journal="IBM Technical Disclosure Bulletin", volume="15", year="1972", pages="938-944"} @article{don73, author="W. E. Donath and A. J. Hoffman", title="Lower bounds for the partitioning of graphs", journal="IBM J. Res. Develop.", volume="17", year="1973", pages="420-425"} @article{fie73, author="M. Fiedler", title="Algebraic connectivity of graphs", journal="Czechoslovak Math J.", volume="23", year="1973", pages="298-305"} @book{fre86, author="G. N. Fredrickson and R. Janardan", title="Separator-based strategies for efficient message routing", booktitle="27th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1986", pages="428-437"} @book{gaz87, author="H. Gazit and G. L. Miller", title="A parallel algorithm for finding a separator in planar graphs", booktitle="28th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1987", pages="238-248"} @techreport{gil80, author="J. R. Gilbert", title="Graph separator theorems and sparse {G}aussian elimination", number="Ph.D. Thesis", institution="DCS, Stanford University", year="1980"} @article{gil84-genus, author="J. R. Gilbert and J. P. Hutchinson and R. E. Tarjan", title="A separator theorem for graphs of bounded genus", journal="J. of Algorithms", volume="5", year="1984", pages="391-407"} @article{gil84-chordal, author="J. R. Gilbert and D. J. Rose and A. Edenbrandt", title="A separator theorem for chordal graphs", journal="SIAM J. Alg. \& Disc. Meth.", volume="5", year="1984", pages="306-313"} @inproceedings{gol83, author="M. K. Goldberg and M. Burstein", title="Heuristic improvement technique for bisection of {VLSI} networks", booktitle="Proc. IEEE International Conf. on Computer Design", address="Port Chester, New York", year="1983", pages="122-125"} @techreport{gol87, author="M. K. Goldberg and S. Lath and J. W. Roberts", title="Heuristics for the graph bisection problem", number="Report", institution="Rensselaer Polytechnic Institute", year="1987"} @techreport{hen92, author="B. Hendrickson and R. Leland", title="An improved spectral graph partitioning algorithm for mapping parallel computations", number="SAND92-1460", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1992"} @techreport{hen93, author="B. Hendrickson and R. Leland", title="Multidimensional spectral load balancing", number="SAND93-074", institution="Sandia National Laboratories", address="Albuquerque, NM", year="1993"} @article{hu81, author="T. C. Hu and M. T. Shing", title="An O(n) algorithm to find a near-optimum partition", journal="Journal of Algorithms", volume="2", year="1981", pages="122-138"} @article{hu85, author="T. C. Hu and M. T. Shing", title="A decomposition algorithm for circuit routing", journal="Math. Programming Study", volume="24", year="1985", pages="87-103"} @article{hu86, author="T. C. Hu and M. T. Shing", title="A decomposition algorithm for multi-terminal network flows", journal="J. Discrete Applied Math.", volume="13", year="1986", pages="165-181"} @article{joh88, author="D. S. Johnson and C. R. Aragon and L. A. McGeoch and C. Schevon", title="Optimization by simulated annealing: an experimental evaluation", journal="Operations Research", note="((submitted))", year="1988"} @article{kan91, author="A. Kanevsky and V. Ramachandran", title="Improved algorithms for graph four-connectivity", journal="J. of Computer Science and Systems", volume="42", year="1991", pages="288-306"} @article{kan9x, author="A. Kanevsky", title="Finding all minimum size vertex sets in a graph", journal="J. of Networks", year="199x"} @inproceedings{kan90, author="A. Kanevsky", title="On the number of minimum size separating vertex sets of a graph and how to find all of them", booktitle="First Annual ACM-SIAM Symposium on Discrete Algorithms (SODA '90)", year="January 22-24,1990", pages="411-421"} @article{kao90, author="M. Kao and F. Wan", title="Not all planar digraphs have small cycle separators", journal="Information Processing Letters", year="1990"} @article{ker70, author="B. W. Kernighan and S. Lin", title="An efficient heuristic procedure for partitioning graphs", journal="Bell System Technical Journal", volume="49", year="1970", pages="291-307"} @article{kir83, author="S. Kirkpatrick and C. D. Gelatt Jr. and M. P. Vecchi", title="Optimization by simulated annealing", journal="Science", volume="220", year="1983", pages="671-680"} @article{kom85, author="J. Komlos and M. T. Shing", title="Probabilistic partitioning algorithms for the rectilinear Steiner problem", journal="Networks", volume="15", year="1985", pages="413-423"} @article{kri84, author="B. Krishnamurthy", title="An improved min-cut algorithm for partitioning {VLSI} networks", journal="IEEE Trans. on Computers", volume="C-33", year="1984", pages="438-446"} @article{kri87, author="B. Krishnamurthy", title="Constructing test cases for partitioning heuristics", journal="IEEE Trans. on Computers", volume="C-36", year="198", pages="1112-1114"} @inproceedings{lei82, author="F. T. Leighton", title="A layout strategy for {VLSI} which is provably good", booktitle="Proceedings of the 14th Annual ACM Symposium on Theory of Computing", year="1982", pages="85-98"} @book{lei80, author="C. Leiserson", title="Area-efficient graph layout (for vlsi)", booktitle="21st Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1980", pages="270-281"} @article{lin77, author="T. D. Lin and R. S. H. Mah", title="Hierarchical partition -- a new optimal pivoting algorithm", journal="Math. Programming", volume="12", year="1977", pages="260-278"} @article{lip80, author="R. J. Lipton and R. E. Tarjan", title="Applications of a planar separator theorem", journal="SICOMP", volume="9", year="1980", pages="615-627"} @techreport{mac78, author="R. M. Macgregor", title="On partitioning a graph: a theoretical and empirical study", number="UCB/ERL M78/14 (Ph.D. Thesis)", institution="Standford University", year="1978"} @inproceedings{mil84, author="G. L. Miller", title="Finding small simple cycle separators for 2-connected planar graphs", booktitle="Proceedings of the 16th Annual ACM Symposium on Theory of Computing", year="1984", pages="376-382"} @techreport{moo88, author="D. Moore", title="A round-robin parallel partitioning algorithm", number="TR 88-916", institution="DCS, Cornell University", year="1988"} @article{pai87, author="R. Paige and R. E. Tarjan", title="Three partition refinement algorithm", journal="SICOMP", volume="16", year="1987", pages="973-989"} @article{pow88, author="D. Powers", title="Graph partitioning by eigenvectors", journal="Lin. Alg. Appl.", volume="101", year="1988", pages="121-133"} @book{rao87, author="S. Rao", title="Finding near optimal separators in planar graphs", booktitle="28th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1987", pages="225-237"} @article{rav87, author="S. Ravi and H. Hunt III", title="An application of the planar separator theorem to counting problem", journal="Inform. Process. Letters", volume="25", year="1987", pages="317-322"} @techreport{ren90, author="F. Rendl and H. Wolkowicz", title="A projection technique for partitioning the nodes of a graph", number="CORR 90-20", institution="University of Waterloo", address="Waterloo, Ontario", year="1990"} @inproceedings{san76, author="A. Sangiovanni-Vincentelli", title="An optimization problem arising from tearing methods", booktitle="Sparse Matrix Computations", editor="J.R. Bunch and D.J. Rose", publisher="Academic Press", year="1976", pages="97-110"} @inproceedings{sch79, author="D. G. Schweikert and B. W. Kernighan", title="A proper model for the partitioning of electrical circuits", booktitle="Proc. 9th Design Automation Workshop", year="1979", pages="57-62"} @article{sen92, author="A. Sen and H. Deng and S. Guha", title="On a graph partition problem with application to vlsi layout", journal="Information Processing Letters", year="1992", volume="43", pages="87-94"} @techreport{she87, author="T. J. Sheffler", title="A graph separator theorem and its application to {G}aussian elimination to optimize {B}oolean expression for parallel evaluation", number="CMU-CS-87-123", institution="DCS, Carnegie-Mellon University", year="1987"} @inproceedings{shi80, author="H. Shiraishi and F. Hirose", title="Efficient placement and routing for masterslice {LSI}", booktitle="Proc. 17th Design Automation Conference", year="1980", pages="458-464"} @article{sua88, author="P. Suaris and G. Kedem", title="An algorithm for quadrisection and its application to standard cell placement", journal="IEEE Trans. Circuits and Systems", volume="35", year="1988", pages="294-303"} @article{tar??, author="R. E. Tarjan", title="Decomposition by clique separators", journal="Discrete Math", year="to appear"} @article{ven87, author="S. Venkatesan", title="Improved constants for some separator theorems", journal="J. Algorithms", volume="8", year="1987", pages="572-578"} @article{wan91, author="F. Wan", title="A linear-processor algorithm for finding small cycle separators on undirected planar graphs", journal="SICOMP", year="1991?"} @article{whi81, author="S. H. Whitesides", title="An algorithm for finding clique cutsets", journal="Inf. Proc. Letters", volume="12", year="1981", pages="31-32"} @incollection{matrixmarket97, author="R. F. Boisvert and R. Pozo and K. Remington and R. F. Barrett and J. J. Dongarra", title="Matrix {M}arket: a web resource for test matrix collections", booktitle="The Quality of Numerical Software: Assessment and Enhancement", publisher="Chapman and Hall, London", year="1997", editor="R. F. Boisvert", pages="125-137"} , title="A parallel algorithm for finding a separator in planar graphs", booktitle="28th Annual Symposium on Foundation of Computer Science", publisher="IEEE", year="1987", pages="238-248"} @techreport{gil80, author="J. R. Gilbert", title="Graph separator theorems and documentation/FrontTrees/main.tex010064400020550007177000000026310663232262600205140ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,10pt,twoside]{article} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \input psfig \newcommand{\bfi}{{\bf i}} \newcommand{\bfj}{{\bf j}} \newcommand{\bnd}[1]{{\partial{#1}}} \newcommand\WHILE{{\bf while}} \newcommand\IF{{\bf if}} \newcommand\END{{\bf end}} \newcommand\ELSE{{\bf else}} \newcommand\THEN{{\bf then}} \pagestyle{myheadings} % \markboth % {\quad \hrulefill \quad {\bf SPOOLES 2.2} : \today \quad \hrulefill} % {\quad \hrulefill \quad {\bf SPOOLES 2.2} : \quad \today \hrulefill} \markboth {\hspace*{0.5 in} Orderings and Front Trees \quad\hrulefill\quad\today} {\today \quad\hrulefill\quad Orderings and Front Trees \hspace*{0.5 in}} \begin{document} \bibliographystyle{plain} \title{Ordering Sparse Matrices and Transforming Front Trees} \author{Cleve Ashcraft, Boeing Shared Services Group\thanks{ P. O. Box 24346, Mail Stop 7L-21, Seattle, Washington 98124. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} } \date{\today} \maketitle \input intro.tex \input ordering.tex \input fronttrees.tex \bibliography{spooles} \input main.ind \end{document} documentation/FrontTrees/R2D100.eps010064400020550007177000000265720663202343100203710ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 300.0 300.0 /radius 2.500 def /Helvetica findfont 3.125 scalefont setfont /M {moveto} def /L {lineto} def /ACF { % stack : x y radius newpath 0 360 arc closepath fill } def /str 6 string def /drawLabel { % x y label radius /radius exch def /label exch def /y exch def /x exch def gsave 1.0 setgray x radius add y moveto x y radius 0 360 arc fill 0.0 setgray x radius add y moveto x y radius 0 360 arc stroke x y moveto label stringwidth pop 2 div neg radius 2 div neg rmoveto label show grestore } def gsave 0.100 setlinewidth 0.0 setgray newpath 40 10 M 10 10 L 70 10 M 40 10 L 100 10 M 70 10 L 130 10 M 100 10 L 160 10 M 130 10 L 190 10 M 160 10 L 220 10 M 190 10 L 250 10 M 220 10 L 280 10 M 250 10 L 40 280 M 10 280 L 70 280 M 40 280 L 100 280 M 70 280 L 130 280 M 100 280 L 160 280 M 130 280 L 190 280 M 160 280 L 220 280 M 190 280 L 250 280 M 220 280 L 280 280 M 250 280 L 10 40 M 10 10 L 10 40 M 40 10 L 10 70 M 10 40 L 10 100 M 10 70 L 10 130 M 10 100 L 10 160 M 10 130 L 10 190 M 10 160 L 10 220 M 10 190 L 10 250 M 10 280 L 10 250 M 40 280 L 10 250 M 10 220 L 280 40 M 250 10 L 280 40 M 280 10 L 280 70 M 280 40 L 280 100 M 280 70 L 280 130 M 280 100 L 280 160 M 280 130 L 280 190 M 280 160 L 280 220 M 280 190 L 280 250 M 250 280 L 280 250 M 280 280 L 280 250 M 280 220 L 246 43.8 M 220 10 L 246 43.8 M 250 10 L 246 43.8 M 280 40 L 246 43.8 M 280 70 L 43.8 111 M 10 100 L 43.8 111 M 10 130 L 179 246 M 160 280 L 179 246 M 190 280 L 179 246 M 220 280 L 94.4 94.4 M 43.8 111 L 229 229 M 220 280 L 229 229 M 250 280 L 229 229 M 280 250 L 229 229 M 179 246 L 26.9 162 M 10 160 L 26.9 162 M 10 190 L 162 26.9 M 130 10 L 162 26.9 M 160 10 L 162 26.9 M 190 10 L 60.6 263 M 40 280 L 60.6 263 M 70 280 L 60.6 263 M 10 250 L 196 128 M 145 145 L 128 60.6 M 162 26.9 L 263 196 M 280 190 L 263 196 M 280 220 L 69.1 35.3 M 40 10 L 69.1 35.3 M 70 10 L 204 170 M 196 128 L 35.3 137 M 10 130 L 35.3 137 M 10 160 L 35.3 137 M 43.8 111 L 35.3 137 M 26.9 162 L 103 204 M 77.5 212 L 103 204 M 111 179 L 103 204 M 137 238 L 238 69.1 M 280 70 L 238 69.1 M 280 100 L 238 69.1 M 212 77.5 L 238 69.1 M 246 43.8 L 52.2 153 M 43.8 111 L 52.2 153 M 26.9 162 L 52.2 153 M 35.3 137 L 120 85.9 M 94.4 94.4 L 120 85.9 M 128 60.6 L 255 221 M 280 220 L 255 221 M 280 250 L 255 221 M 229 229 L 255 221 M 263 196 L 85.9 52.2 M 94.4 94.4 L 85.9 52.2 M 128 60.6 L 85.9 52.2 M 69.1 35.3 L 85.9 52.2 M 120 85.9 L 221 187 M 229 229 L 221 187 M 263 196 L 221 187 M 204 170 L 221 187 M 255 221 L 153 120 M 145 145 L 153 120 M 196 128 L 81.7 175 M 77.5 212 L stroke newpath 81.7 175 M 111 179 L 81.7 175 M 103 204 L 81.7 175 M 52.2 153 L 217 39.5 M 190 10 L 217 39.5 M 220 10 L 217 39.5 M 212 77.5 L 217 39.5 M 246 43.8 L 217 39.5 M 238 69.1 L 149 242 M 160 280 L 149 242 M 179 246 L 149 242 M 137 238 L 48 73.3 M 43.8 111 L 183 208 M 179 246 L 250 141 M 280 130 L 250 141 M 280 160 L 31.1 225 M 10 190 L 31.1 225 M 10 220 L 31.1 225 M 10 250 L 166 90.2 M 153 120 L 234 158 M 196 128 L 234 158 M 221 187 L 234 158 M 250 141 L 132 124 M 145 145 L 132 124 M 120 85.9 L 132 124 M 153 120 L 64.8 191 M 77.5 212 L 64.8 191 M 52.2 153 L 64.8 191 M 81.7 175 L 200 56.4 M 190 10 L 200 56.4 M 212 77.5 L 200 56.4 M 162 26.9 L 200 56.4 M 217 39.5 L 73.3 81.7 M 43.8 111 L 73.3 81.7 M 94.4 94.4 L 73.3 81.7 M 85.9 52.2 L 73.3 81.7 M 48 73.3 L 208 217 M 179 246 L 208 217 M 229 229 L 208 217 M 221 187 L 208 217 M 183 208 L 141 149 M 145 145 L 141 149 M 111 179 L 141 149 M 132 124 L 107 250 M 70 280 L 107 250 M 100 280 L 107 250 M 130 280 L 107 250 M 77.5 212 L 107 250 M 60.6 263 L 107 250 M 137 238 L 107 250 M 103 204 L 242 115 M 280 100 L 242 115 M 280 130 L 242 115 M 212 77.5 L 242 115 M 196 128 L 242 115 M 238 69.1 L 242 115 M 250 141 L 242 115 M 234 158 L 39.5 48 M 40 10 L 39.5 48 M 10 40 L 39.5 48 M 10 70 L 39.5 48 M 69.1 35.3 L 39.5 48 M 48 73.3 L 175 183 M 145 145 L 175 183 M 111 179 L 175 183 M 196 128 L 175 183 M 204 170 L 175 183 M 183 208 L 175 183 M 141 149 L 124 31.1 M 100 10 L 124 31.1 M 130 10 L 124 31.1 M 162 26.9 L 124 31.1 M 128 60.6 L 124 31.1 M 85.9 52.2 L 259 166 M 280 160 L 259 166 M 280 190 L 259 166 M 263 196 L 259 166 M 221 187 L 259 166 M 250 141 L 259 166 M 234 158 L 56.4 234 M 10 250 L 56.4 234 M 77.5 212 L 56.4 234 M 60.6 263 L 56.4 234 M 31.1 225 L 56.4 234 M 107 250 L 191 98.6 M 212 77.5 L 191 98.6 M 196 128 L 191 98.6 M 153 120 L 191 98.6 M 166 90.2 L 191 98.6 M 242 115 L 158 64.8 M 162 26.9 L 158 64.8 M 128 60.6 L 158 64.8 M 166 90.2 L 90.2 132 M 43.8 111 L 90.2 132 M 94.4 94.4 L 90.2 132 M 52.2 153 L 90.2 132 M 81.7 175 L 118 130 M 94.4 94.4 L 118 130 M 120 85.9 L 118 130 M 132 124 L 118 130 M 141 149 L stroke newpath 118 130 M 90.2 132 L 50.1 198 M 10 190 L 50.1 198 M 77.5 212 L 50.1 198 M 26.9 162 L 50.1 198 M 52.2 153 L 50.1 198 M 31.1 225 L 50.1 198 M 64.8 191 L 50.1 198 M 56.4 234 L 185 62.7 M 212 77.5 L 185 62.7 M 162 26.9 L 185 62.7 M 166 90.2 L 185 62.7 M 200 56.4 L 185 62.7 M 191 98.6 L 185 62.7 M 158 64.8 L 151 96.5 M 128 60.6 L 151 96.5 M 120 85.9 L 151 96.5 M 153 120 L 151 96.5 M 166 90.2 L 151 96.5 M 132 124 L 151 96.5 M 158 64.8 L 83.8 29 M 70 10 L 83.8 29 M 100 10 L 83.8 29 M 69.1 35.3 L 83.8 29 M 85.9 52.2 L 83.8 29 M 124 31.1 L 219 164 M 196 128 L 219 164 M 204 170 L 219 164 M 221 187 L 219 164 M 234 158 L 67 45.9 M 69.1 35.3 L 67 45.9 M 85.9 52.2 L 67 45.9 M 48 73.3 L 67 45.9 M 73.3 81.7 L 67 45.9 M 39.5 48 L 202 181 M 204 170 L 202 181 M 221 187 L 202 181 M 183 208 L 202 181 M 208 217 L 202 181 M 175 183 L 134 248 M 130 280 L 134 248 M 160 280 L 134 248 M 137 238 L 134 248 M 149 242 L 134 248 M 107 250 L 101 147 M 111 179 L 101 147 M 81.7 175 L 101 147 M 141 149 L 101 147 M 90.2 132 L 101 147 M 118 130 L 33.2 79.6 M 10 70 L 33.2 79.6 M 10 100 L 33.2 79.6 M 43.8 111 L 33.2 79.6 M 48 73.3 L 33.2 79.6 M 39.5 48 L 168 215 M 111 179 L 168 215 M 179 246 L 168 215 M 137 238 L 168 215 M 103 204 L 168 215 M 149 242 L 168 215 M 183 208 L 168 215 M 175 183 L stroke grestore gsave 0.1 setlinewidth 0.0 setgray 10.000 10.000 () radius drawLabel 40.000 10.000 () radius drawLabel 70.000 10.000 () radius drawLabel 100.000 10.000 () radius drawLabel 130.000 10.000 () radius drawLabel 160.000 10.000 () radius drawLabel 190.000 10.000 () radius drawLabel 220.000 10.000 () radius drawLabel 250.000 10.000 () radius drawLabel 280.000 10.000 () radius drawLabel 10.000 280.000 () radius drawLabel 40.000 280.000 () radius drawLabel 70.000 280.000 () radius drawLabel 100.000 280.000 () radius drawLabel 130.000 280.000 () radius drawLabel 160.000 280.000 () radius drawLabel 190.000 280.000 () radius drawLabel 220.000 280.000 () radius drawLabel 250.000 280.000 () radius drawLabel 280.000 280.000 () radius drawLabel 10.000 40.000 () radius drawLabel 10.000 70.000 () radius drawLabel 10.000 100.000 () radius drawLabel 10.000 130.000 () radius drawLabel 10.000 160.000 () radius drawLabel 10.000 190.000 () radius drawLabel 10.000 220.000 () radius drawLabel 10.000 250.000 () radius drawLabel 280.000 40.000 () radius drawLabel 280.000 70.000 () radius drawLabel 280.000 100.000 () radius drawLabel 280.000 130.000 () radius drawLabel 280.000 160.000 () radius drawLabel 280.000 190.000 () radius drawLabel 280.000 220.000 () radius drawLabel 280.000 250.000 () radius drawLabel 145.000 145.000 () radius drawLabel 77.500 212.500 () radius drawLabel 212.500 77.500 () radius drawLabel 111.250 178.750 () radius drawLabel 246.250 43.750 () radius drawLabel 43.750 111.250 () radius drawLabel 178.750 246.250 () radius drawLabel 94.375 94.375 () radius drawLabel 229.375 229.375 () radius drawLabel 26.875 161.875 () radius drawLabel 161.875 26.875 () radius drawLabel 60.625 263.125 () radius drawLabel 195.625 128.125 () radius drawLabel 128.125 60.625 () radius drawLabel 263.125 195.625 () radius drawLabel 136.564 237.814 () radius drawLabel 69.064 35.312 () radius drawLabel 204.064 170.314 () radius drawLabel 35.312 136.564 () radius drawLabel 102.814 204.064 () radius drawLabel 237.814 69.064 () radius drawLabel 52.186 153.436 () radius drawLabel 119.686 85.936 () radius drawLabel 254.686 220.936 () radius drawLabel 85.936 52.186 () radius drawLabel 220.936 187.186 () radius drawLabel 153.436 119.686 () radius drawLabel 81.718 174.532 () radius drawLabel 216.718 39.531 () radius drawLabel 149.218 242.032 () radius drawLabel 47.968 73.282 () radius drawLabel 182.968 208.282 () radius drawLabel 250.468 140.782 () radius drawLabel 31.094 225.157 () radius drawLabel 166.093 90.157 () radius drawLabel 233.593 157.657 () radius drawLabel 132.343 123.907 () radius drawLabel 64.843 191.407 () radius drawLabel 199.843 56.407 () radius drawLabel 73.282 81.718 () radius drawLabel 208.282 216.718 () radius drawLabel 140.782 149.218 () radius drawLabel 107.032 250.468 () radius drawLabel 242.032 115.468 () radius drawLabel 39.531 47.968 () radius drawLabel 174.532 182.968 () radius drawLabel 123.907 31.094 () radius drawLabel 258.907 166.093 () radius drawLabel 56.407 233.593 () radius drawLabel 191.407 98.593 () radius drawLabel 157.657 64.843 () radius drawLabel 90.157 132.343 () radius drawLabel 117.577 130.234 () radius drawLabel 50.077 197.734 () radius drawLabel 185.077 62.734 () radius drawLabel 151.327 96.484 () radius drawLabel 83.827 28.984 () radius drawLabel 218.827 163.984 () radius drawLabel 66.952 45.859 () radius drawLabel 201.952 180.859 () radius drawLabel 134.452 248.359 () radius drawLabel 100.702 147.109 () radius drawLabel 33.203 79.609 () radius drawLabel 168.202 214.609 () radius drawLabel grestore showpagedocumentation/FrontTrees/R2D100perm.eps010064400020550007177000000271560663207500200212550ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 300.0 300.0 /radius 5.000 def /Helvetica findfont 6.250 scalefont setfont /M {moveto} def /L {lineto} def /ACF { % stack : x y radius newpath 0 360 arc closepath fill } def /str 6 string def /drawLabel { % x y label radius /radius exch def /label exch def /y exch def /x exch def gsave 1.0 setgray x radius add y moveto x y radius 0 360 arc fill 0.0 setgray x radius add y moveto x y radius 0 360 arc stroke x y moveto label stringwidth pop 2 div neg radius 2 div neg rmoveto label show grestore } def gsave 0.100 setlinewidth 0.0 setgray grestore gsave 0.100 setlinewidth 0.0 setgray newpath 40 10 M 10 10 L 70 10 M 40 10 L 100 10 M 70 10 L 130 10 M 100 10 L 160 10 M 130 10 L 190 10 M 160 10 L 220 10 M 190 10 L 250 10 M 220 10 L 280 10 M 250 10 L 40 280 M 10 280 L 70 280 M 40 280 L 100 280 M 70 280 L 130 280 M 100 280 L 160 280 M 130 280 L 190 280 M 160 280 L 220 280 M 190 280 L 250 280 M 220 280 L 280 280 M 250 280 L 10 40 M 10 10 L 10 40 M 40 10 L 10 70 M 10 40 L 10 100 M 10 70 L 10 130 M 10 100 L 10 160 M 10 130 L 10 190 M 10 160 L 10 220 M 10 190 L 10 250 M 10 280 L 10 250 M 40 280 L 10 250 M 10 220 L 280 40 M 250 10 L 280 40 M 280 10 L 280 70 M 280 40 L 280 100 M 280 70 L 280 130 M 280 100 L 280 160 M 280 130 L 280 190 M 280 160 L 280 220 M 280 190 L 280 250 M 250 280 L 280 250 M 280 280 L 280 250 M 280 220 L 246 43.8 M 220 10 L 246 43.8 M 250 10 L 246 43.8 M 280 40 L 246 43.8 M 280 70 L 43.8 111 M 10 100 L 43.8 111 M 10 130 L 179 246 M 160 280 L 179 246 M 190 280 L 179 246 M 220 280 L 94.4 94.4 M 43.8 111 L 229 229 M 220 280 L 229 229 M 250 280 L 229 229 M 280 250 L 229 229 M 179 246 L 26.9 162 M 10 160 L 26.9 162 M 10 190 L 162 26.9 M 130 10 L 162 26.9 M 160 10 L 162 26.9 M 190 10 L 60.6 263 M 40 280 L 60.6 263 M 70 280 L 60.6 263 M 10 250 L 196 128 M 145 145 L 128 60.6 M 162 26.9 L 263 196 M 280 190 L 263 196 M 280 220 L 69.1 35.3 M 40 10 L 69.1 35.3 M 70 10 L 204 170 M 196 128 L 35.3 137 M 10 130 L 35.3 137 M 10 160 L 35.3 137 M 43.8 111 L 35.3 137 M 26.9 162 L 103 204 M 77.5 212 L 103 204 M 111 179 L 103 204 M 137 238 L 238 69.1 M 280 70 L 238 69.1 M 280 100 L 238 69.1 M 212 77.5 L 238 69.1 M 246 43.8 L 52.2 153 M 43.8 111 L 52.2 153 M 26.9 162 L 52.2 153 M 35.3 137 L 120 85.9 M 94.4 94.4 L 120 85.9 M 128 60.6 L 255 221 M 280 220 L 255 221 M 280 250 L 255 221 M 229 229 L 255 221 M 263 196 L 85.9 52.2 M 94.4 94.4 L 85.9 52.2 M 128 60.6 L 85.9 52.2 M 69.1 35.3 L 85.9 52.2 M 120 85.9 L 221 187 M 229 229 L 221 187 M 263 196 L 221 187 M 204 170 L 221 187 M 255 221 L 153 120 M 145 145 L 153 120 M 196 128 L 81.7 175 M 77.5 212 L stroke newpath 81.7 175 M 111 179 L 81.7 175 M 103 204 L 81.7 175 M 52.2 153 L 217 39.5 M 190 10 L 217 39.5 M 220 10 L 217 39.5 M 212 77.5 L 217 39.5 M 246 43.8 L 217 39.5 M 238 69.1 L 149 242 M 160 280 L 149 242 M 179 246 L 149 242 M 137 238 L 48 73.3 M 43.8 111 L 183 208 M 179 246 L 250 141 M 280 130 L 250 141 M 280 160 L 31.1 225 M 10 190 L 31.1 225 M 10 220 L 31.1 225 M 10 250 L 166 90.2 M 153 120 L 234 158 M 196 128 L 234 158 M 221 187 L 234 158 M 250 141 L 132 124 M 145 145 L 132 124 M 120 85.9 L 132 124 M 153 120 L 64.8 191 M 77.5 212 L 64.8 191 M 52.2 153 L 64.8 191 M 81.7 175 L 200 56.4 M 190 10 L 200 56.4 M 212 77.5 L 200 56.4 M 162 26.9 L 200 56.4 M 217 39.5 L 73.3 81.7 M 43.8 111 L 73.3 81.7 M 94.4 94.4 L 73.3 81.7 M 85.9 52.2 L 73.3 81.7 M 48 73.3 L 208 217 M 179 246 L 208 217 M 229 229 L 208 217 M 221 187 L 208 217 M 183 208 L 141 149 M 145 145 L 141 149 M 111 179 L 141 149 M 132 124 L 107 250 M 70 280 L 107 250 M 100 280 L 107 250 M 130 280 L 107 250 M 77.5 212 L 107 250 M 60.6 263 L 107 250 M 137 238 L 107 250 M 103 204 L 242 115 M 280 100 L 242 115 M 280 130 L 242 115 M 212 77.5 L 242 115 M 196 128 L 242 115 M 238 69.1 L 242 115 M 250 141 L 242 115 M 234 158 L 39.5 48 M 40 10 L 39.5 48 M 10 40 L 39.5 48 M 10 70 L 39.5 48 M 69.1 35.3 L 39.5 48 M 48 73.3 L 175 183 M 145 145 L 175 183 M 111 179 L 175 183 M 196 128 L 175 183 M 204 170 L 175 183 M 183 208 L 175 183 M 141 149 L 124 31.1 M 100 10 L 124 31.1 M 130 10 L 124 31.1 M 162 26.9 L 124 31.1 M 128 60.6 L 124 31.1 M 85.9 52.2 L 259 166 M 280 160 L 259 166 M 280 190 L 259 166 M 263 196 L 259 166 M 221 187 L 259 166 M 250 141 L 259 166 M 234 158 L 56.4 234 M 10 250 L 56.4 234 M 77.5 212 L 56.4 234 M 60.6 263 L 56.4 234 M 31.1 225 L 56.4 234 M 107 250 L 191 98.6 M 212 77.5 L 191 98.6 M 196 128 L 191 98.6 M 153 120 L 191 98.6 M 166 90.2 L 191 98.6 M 242 115 L 158 64.8 M 162 26.9 L 158 64.8 M 128 60.6 L 158 64.8 M 166 90.2 L 90.2 132 M 43.8 111 L 90.2 132 M 94.4 94.4 L 90.2 132 M 52.2 153 L 90.2 132 M 81.7 175 L 118 130 M 94.4 94.4 L 118 130 M 120 85.9 L 118 130 M 132 124 L 118 130 M 141 149 L stroke newpath 118 130 M 90.2 132 L 50.1 198 M 10 190 L 50.1 198 M 77.5 212 L 50.1 198 M 26.9 162 L 50.1 198 M 52.2 153 L 50.1 198 M 31.1 225 L 50.1 198 M 64.8 191 L 50.1 198 M 56.4 234 L 185 62.7 M 212 77.5 L 185 62.7 M 162 26.9 L 185 62.7 M 166 90.2 L 185 62.7 M 200 56.4 L 185 62.7 M 191 98.6 L 185 62.7 M 158 64.8 L 151 96.5 M 128 60.6 L 151 96.5 M 120 85.9 L 151 96.5 M 153 120 L 151 96.5 M 166 90.2 L 151 96.5 M 132 124 L 151 96.5 M 158 64.8 L 83.8 29 M 70 10 L 83.8 29 M 100 10 L 83.8 29 M 69.1 35.3 L 83.8 29 M 85.9 52.2 L 83.8 29 M 124 31.1 L 219 164 M 196 128 L 219 164 M 204 170 L 219 164 M 221 187 L 219 164 M 234 158 L 67 45.9 M 69.1 35.3 L 67 45.9 M 85.9 52.2 L 67 45.9 M 48 73.3 L 67 45.9 M 73.3 81.7 L 67 45.9 M 39.5 48 L 202 181 M 204 170 L 202 181 M 221 187 L 202 181 M 183 208 L 202 181 M 208 217 L 202 181 M 175 183 L 134 248 M 130 280 L 134 248 M 160 280 L 134 248 M 137 238 L 134 248 M 149 242 L 134 248 M 107 250 L 101 147 M 111 179 L 101 147 M 81.7 175 L 101 147 M 141 149 L 101 147 M 90.2 132 L 101 147 M 118 130 L 33.2 79.6 M 10 70 L 33.2 79.6 M 10 100 L 33.2 79.6 M 43.8 111 L 33.2 79.6 M 48 73.3 L 33.2 79.6 M 39.5 48 L 168 215 M 111 179 L 168 215 M 179 246 L 168 215 M 137 238 L 168 215 M 103 204 L 168 215 M 149 242 L 168 215 M 183 208 L 168 215 M 175 183 L stroke grestore gsave 0.1 setlinewidth 0.0 setgray 10.000 10.000 (71) radius drawLabel 40.000 10.000 (84) radius drawLabel 70.000 10.000 (79) radius drawLabel 100.000 10.000 (80) radius drawLabel 130.000 10.000 (90) radius drawLabel 160.000 10.000 (22) radius drawLabel 190.000 10.000 (41) radius drawLabel 220.000 10.000 (37) radius drawLabel 250.000 10.000 (35) radius drawLabel 280.000 10.000 (33) radius drawLabel 10.000 280.000 (48) radius drawLabel 40.000 280.000 (49) radius drawLabel 70.000 280.000 (51) radius drawLabel 100.000 280.000 (50) radius drawLabel 130.000 280.000 (55) radius drawLabel 160.000 280.000 (91) radius drawLabel 190.000 280.000 (8) radius drawLabel 220.000 280.000 (11) radius drawLabel 250.000 280.000 (10) radius drawLabel 280.000 280.000 (9) radius drawLabel 10.000 40.000 (72) radius drawLabel 10.000 70.000 (74) radius drawLabel 10.000 100.000 (73) radius drawLabel 10.000 130.000 (87) radius drawLabel 10.000 160.000 (56) radius drawLabel 10.000 190.000 (59) radius drawLabel 10.000 220.000 (66) radius drawLabel 10.000 250.000 (53) radius drawLabel 280.000 40.000 (34) radius drawLabel 280.000 70.000 (38) radius drawLabel 280.000 100.000 (44) radius drawLabel 280.000 130.000 (2) radius drawLabel 280.000 160.000 (0) radius drawLabel 280.000 190.000 (6) radius drawLabel 280.000 220.000 (3) radius drawLabel 280.000 250.000 (18) radius drawLabel 145.000 145.000 (28) radius drawLabel 77.500 212.500 (62) radius drawLabel 212.500 77.500 (42) radius drawLabel 111.250 178.750 (92) radius drawLabel 246.250 43.750 (36) radius drawLabel 43.750 111.250 (88) radius drawLabel 178.750 246.250 (17) radius drawLabel 94.375 94.375 (75) radius drawLabel 229.375 229.375 (19) radius drawLabel 26.875 161.875 (58) radius drawLabel 161.875 26.875 (27) radius drawLabel 60.625 263.125 (52) radius drawLabel 195.625 128.125 (45) radius drawLabel 128.125 60.625 (93) radius drawLabel 263.125 195.625 (4) radius drawLabel 136.564 237.814 (67) radius drawLabel 69.064 35.312 (82) radius drawLabel 204.064 170.314 (13) radius drawLabel 35.312 136.564 (57) radius drawLabel 102.814 204.064 (60) radius drawLabel 237.814 69.064 (39) radius drawLabel 52.186 153.436 (64) radius drawLabel 119.686 85.936 (94) radius drawLabel 254.686 220.936 (5) radius drawLabel 85.936 52.186 (83) radius drawLabel 220.936 187.186 (20) radius drawLabel 153.436 119.686 (31) radius drawLabel 81.718 174.532 (63) radius drawLabel 216.718 39.531 (40) radius drawLabel 149.218 242.032 (95) radius drawLabel 47.968 73.282 (77) radius drawLabel 182.968 208.282 (14) radius drawLabel 250.468 140.782 (1) radius drawLabel 31.094 225.157 (68) radius drawLabel 166.093 90.157 (24) radius drawLabel 233.593 157.657 (21) radius drawLabel 132.343 123.907 (29) radius drawLabel 64.843 191.407 (61) radius drawLabel 199.843 56.407 (43) radius drawLabel 73.282 81.718 (78) radius drawLabel 208.282 216.718 (15) radius drawLabel 140.782 149.218 (30) radius drawLabel 107.032 250.468 (69) radius drawLabel 242.032 115.468 (46) radius drawLabel 39.531 47.968 (85) radius drawLabel 174.532 182.968 (47) radius drawLabel 123.907 31.094 (96) radius drawLabel 258.907 166.093 (7) radius drawLabel 56.407 233.593 (70) radius drawLabel 191.407 98.593 (26) radius drawLabel 157.657 64.843 (23) radius drawLabel 90.157 132.343 (89) radius drawLabel 117.577 130.234 (97) radius drawLabel 50.077 197.734 (65) radius drawLabel 185.077 62.734 (25) radius drawLabel 151.327 96.484 (32) radius drawLabel 83.827 28.984 (81) radius drawLabel 218.827 163.984 (12) radius drawLabel 66.952 45.859 (76) radius drawLabel 201.952 180.859 (16) radius drawLabel 134.452 248.359 (54) radius drawLabel 100.702 147.109 (98) radius drawLabel 33.203 79.609 (86) radius drawLabel 168.202 214.609 (99) radius drawLabel grestore showpage 229 229 M 179 246 L 26.9 162 M 10 160 L 26.9 162 M 10 190 L 162 26.9 M 130 10 L 162 26.9 M 160 10 L 162 26.9 M 190 10 L 60.6 263 M 40 280 L 60.6 263 M 70 280 L 60.6 263 M 10 250 L 196 128 M 145 145 L 128 60.6 M 162 26.9 L 263 196 M 280 190 L 263 196 M 280 220 L 69.1 35.3 M 40 10 L 69.1 35.3 M 70 10documentation/FrontTrees/main.log010064400020550007177000000104750665314610200204760ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 25 JAN 1999 11:55 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/article.cls Document Class: article 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@section=\count80 \c@subsection=\count81 \c@subsubsection=\count82 \c@paragraph=\count83 \c@subparagraph=\count84 \c@figure=\count85 \c@table=\count86 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file main.idx (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: External font `cmex10' loaded for size (Font) <12> on input line 51. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 51. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 51. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 51. (intro.tex LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 4. ) (ordering.tex Underfull \vbox (badness 1132) has occurred while \output is active [] [1 ] (fig3x4grid.tex Overfull \hbox (41.53922pt too wide) in paragraph at lines 46--47 [][] [] Overfull \hbox (10.1674pt too wide) in paragraph at lines 67--67 [] \OT1/cmtt/m/n/10 1 chunks, 70 active entries, 1024 allocated, 6.84 % used[] [] ) [2] LaTeX Font Info: Try loading font information for OMS+cmr on input line 154. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 154. [3] [4] [5]) (fronttrees.tex psfig: searching R2D100.eps for bounding box psfig: including R2D100.eps psfig: searching R2D100perm.eps for bounding box psfig: including R2D100perm.eps [6] psfig: searching vtree.eps for bounding box psfig: including vtree.eps [7] [8] psfig: searching fsvtree.eps for bounding box psfig: including fsvtree.eps psfig: searching fstree.eps for bounding box psfig: including fstree.eps psfig: searching fsmtx.eps for bounding box psfig: including fsmtx.eps psfig: searching amvtree.eps for bounding box psfig: including amvtree.eps psfig: searching amtree.eps for bounding box psfig: including amtree.eps psfig: searching ammtx.eps for bounding box psfig: including ammtx.eps [9] [10] [11] [12] [13] psfig: searching spvtree.eps for bounding box psfig: including spvtree.eps psfig: searching sptree.eps for bounding box psfig: including sptree.eps psfig: searching spmtx.eps for bounding box psfig: including spmtx.eps [14] [15] [16] [17]) (main.bbl [18] [19]) (main.ind) [20] (main.aux) ) Here is how much of TeX's memory you used: 616 strings out of 10908 6087 string characters out of 72189 57871 words of memory out of 262141 3472 multiletter control sequences out of 9500 8931 words of font info for 32 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 30i,11n,21p,249b,439s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (20 pages, 58620 bytes). documentation/FrontTrees/main.idx010064400020550007177000000000000665314607700204730ustar00clevecompmath00000400000006documentation/FrontTrees/main.aux010064400020550007177000000120310665314610200205000ustar00clevecompmath00000400000006\relax \bibstyle{plain} \citation{geo81-book} \citation{geo73-nested} \citation{ber90-mindeg} \citation{liu85-mmd} \citation{ame96-amd} \citation{ng96-mindefIdaho} \citation{roth98-minfill} \@writefile{toc}{\contentsline {section}{\numberline {1}Introduction}{1}} \citation{geo73-nested} \citation{geo81-book} \citation{lei89-fidmat} \citation{pot90-partition} \citation{bar93-partition} \citation{bui93-partition} \citation{hen93-chaco} \citation{hen92-partition} \citation{kar95-multilevel} \citation{karypis98metis} \citation{hr98-msnd} \citation{gup96-WGPP} \citation{rag95-PCO} \citation{ash97-partition} \citation{ash98-maxflow} \citation{ash98-multisection} \citation{ro95-hybrid} \@writefile{toc}{\contentsline {section}{\numberline {2}Sparse matrix orderings}{2}} \newlabel{section:ordering}{{2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.1}The {\tt Graph} object}{2}} \newlabel{subsection:graph}{{2.1}{2}} \citation{liu85-mmd} \@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces A $3 \times 4$ 9-point grid with its adjacency structure}}{3}} \newlabel{fig:3x4-grid}{{1}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2}Constructing an ordering}{3}} \newlabel{subsection:order}{{2.2}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.3}Results}{5}} \newlabel{subsection:results}{{2.3}{5}} \citation{liu90-etree} \citation{sch82-etree} \@writefile{toc}{\contentsline {section}{\numberline {3}Front Trees}{6}} \newlabel{section:front-trees}{{3}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.1}Vertex elimination trees}{6}} \newlabel{subsection:vtx-elim}{{3.1}{6}} \citation{ash89-relaxed} \@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces R2D100: randomly triangulated, 100 grid points}}{7}} \newlabel{fig:R2D100}{{2}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Fundamental supernode trees}{7}} \newlabel{subsection:fs-tree}{{3.2}{7}} \@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces Vertex elimination tree for R2D100, 100 rows and columns}}{8}} \newlabel{fig:R2D100-tree-vtx}{{3}{8}} \citation{ash89-relaxed} \citation{duf83-multifrontal} \@writefile{toc}{\contentsline {subsection}{\numberline {3.3}Amalgamated or relaxed supernode trees}{9}} \newlabel{subsection:am-tree}{{3.3}{9}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.4}Splitting large fronts}{9}} \newlabel{subsection:sp-tree}{{3.4}{9}} \@writefile{lof}{\contentsline {figure}{\numberline {4}{\ignorespaces Top: vertex elimination tree with the vertices mapped to the fundamental supernode that contains them. Bottom: fundamental supernode tree.}}{10}} \newlabel{fig:fs-trees}{{4}{10}} \@writefile{lof}{\contentsline {figure}{\numberline {5}{\ignorespaces Block structure of $L$ with the fundamental supernode partition.}}{11}} \newlabel{fig:R2D100-fs-mtx}{{5}{11}} \@writefile{lof}{\contentsline {figure}{\numberline {6}{\ignorespaces Top: fundamental supernode tree with the supernodes mapped to the amalgamated supernode that contains them. Bottom: amalgamated supernode tree.}}{12}} \newlabel{fig:am-trees}{{6}{12}} \@writefile{lof}{\contentsline {figure}{\numberline {7}{\ignorespaces Block structure of $L$ with the amalgamated supernode partition.}}{13}} \newlabel{fig:R2D100-am-mtx}{{7}{13}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.5}Results}{14}} \newlabel{subsection:tree-results}{{3.5}{14}} \@writefile{lof}{\contentsline {figure}{\numberline {8}{\ignorespaces Left: tree after the large supernodes have been split. Right: tree with nodes mapped back to their amalgamated supernode.}}{15}} \newlabel{fig:sp-trees}{{8}{15}} \@writefile{lof}{\contentsline {figure}{\numberline {9}{\ignorespaces Block structure of $L$ with the amalgamated and split supernode partition.}}{16}} \newlabel{fig:sp-mtx}{{9}{16}} \newlabel{table:R3D13824-tree-stats}{{3.5}{16}} \@writefile{lot}{\contentsline {table}{\numberline {1}{\ignorespaces R3D13824: front tree transformations}}{16}} \newlabel{table:R3D13824-comp-stats}{{3.5}{17}} \@writefile{lot}{\contentsline {table}{\numberline {2}{\ignorespaces R3D13824: factor and solve timings for five different front trees.}}{17}} \bibdata{spooles} \bibcite{ame96-amd}{1} \bibcite{ash89-relaxed}{2} \bibcite{ash97-partition}{3} \bibcite{ash98-multisection}{4} \bibcite{ash98-maxflow}{5} \bibcite{bar93-partition}{6} \bibcite{ber90-mindeg}{7} \bibcite{bui93-partition}{8} \bibcite{duf83-multifrontal}{9} \bibcite{geo73-nested}{10} \bibcite{geo81-book}{11} \bibcite{gup96-WGPP}{12} \bibcite{hen92-partition}{13} \newlabel{table:R3D13824-maxzero-maxsize}{{3.5}{19}} \@writefile{lot}{\contentsline {table}{\numberline {3}{\ignorespaces R3D13824: the influence of {\tt maxzeros} and {\tt maxsize}.}}{19}} \bibcite{hen93-chaco}{14} \bibcite{hr98-msnd}{15} \bibcite{kar95-multilevel}{16} \bibcite{karypis98metis}{17} \bibcite{lei89-fidmat}{18} \bibcite{liu85-mmd}{19} \bibcite{liu90-etree}{20} \bibcite{ng96-mindefIdaho}{21} \bibcite{pot90-partition}{22} \bibcite{rag95-PCO}{23} \bibcite{ro95-hybrid}{24} \bibcite{roth98-minfill}{25} \bibcite{sch82-etree}{26} documentation/FrontTrees/main.blg010064400020550007177000000005060663235754600204700ustar00clevecompmath00000400000006Repeated entry---line 1285 of file spooles.bib : @article{ber90-mindeg : , I'm skipping whatever remains of this entry Repeated entry---line 1335 of file spooles.bib : @techreport{hen92-partition : , I'm skipping whatever remains of this entry (There were 2 error messages) documentation/FrontTrees/main.bbl010064400020550007177000000123570663235754600204720ustar00clevecompmath00000400000006\begin{thebibliography}{10} \bibitem{ame96-amd} P.~Amestoy, T.~Davis, and I.~Duff. \newblock An approximate minimum degree ordering algorithm. \newblock {\em SIAM J. Matrix Anal. Appl.}, 17:886--905, 1996. \bibitem{ash89-relaxed} C.~Ashcraft and R.~Grimes. \newblock The influence of relaxed supernode partitions on the multifrontal method. \newblock {\em ACM Trans. Math. Software}, 15:291--309, 1989. \bibitem{ash97-partition} C.~Ashcraft and J.~W.~H. Liu. \newblock Using domain decomposition to find graph bisectors. \newblock {\em BIT}, 37, 1997. \bibitem{ash98-multisection} C.~Ashcraft and J.~W.~H. Liu. \newblock Robust ordering of sparse matrices using multisection. \newblock {\em SIAM J. Matrix. Anal.}, 19:816--832, 1998. \bibitem{ash98-maxflow} C.~Ashcraft and J.~W.~H. Liu. \newblock Applications of the {D}ulmage-{M}endelsohn decomposition and network flow to graph bisection improvement. \newblock {\em SIAM J. Matrix. Anal.}, 19:325--354, 1999. \bibitem{bar93-partition} S.~T. Barnard and H.~D. Simon. \newblock A fast multilevel implementation of recursive spectral bisection for partitioning unstructured problems. \newblock In {\em Proceedings of the Sixth SIAM Conference on Parallel Processing for Scientific Computing}, pages 711--718, 1993. \bibitem{ber90-mindeg} P.~Berman and G.~Schnitger. \newblock On the performance of the minimum degree ordering for {G}aussian elimination. \newblock {\em SIAM J. Matrix Analysis and Applic.}, 11:83--88, 1990. \bibitem{bui93-partition} T.~Bui and C.~Jones. \newblock A heuristic for reducing fill-in in sparse matrix factorization. \newblock In {\em Proceedings of Sixth SIAM Conference on Parallel Processing}, pages 445--452, 1993. \bibitem{duf83-multifrontal} I.~Duff and J.~Reid. \newblock The multifrontal solution of indefinite sparse symmetric linear equations. \newblock {\em ACM Trans. Math. Software}, 6:302--325, 1983. \bibitem{geo73-nested} J.~A. George. \newblock Nested dissection of a regular finite element mesh. \newblock {\em SIAM J. Numer. Anal.}, 10:345--363, 1973. \bibitem{geo81-book} J.~A. George and J.~W.~H. Liu. \newblock {\em Computer Solution of Large Sparse Positive Definite Systems}. \newblock Prentice-Hall, Englewood Cliffs, NJ, 1981. \bibitem{gup96-WGPP} A.~Gupta. \newblock {WGPP}: {W}atson {G}raph {P}artitioning and sparse matrix ordering {P}ackage. \newblock Technical Report Users Manual, IBM T.J. Watson Research Center, New York, 1996. \bibitem{hen92-partition} B.~Hendrickson and R.~Leland. \newblock An improved spectral graph partitioning algorithm for mapping parallel computations. \newblock Technical Report SAND92-1460, Sandia National Laboratories, Albuquerque, NM, 1992. \bibitem{hen93-chaco} B.~Hendrickson and R.~Leland. \newblock The {C}haco user's guide. \newblock Technical Report SAND93-2339, Sandia National Laboratories, Albuquerque, NM, 1993. \bibitem{hr98-msnd} B.~Hendrickson and E.~Rothberg. \newblock Improving the runtime and quality of nested dissection ordering. \newblock {\em SIAM J. Sci. Comput.}, 20:468--489, 1998. \bibitem{kar95-multilevel} G.~Karypis and V.~Kumar. \newblock A fast and high quality multilevel scheme for partitioning irregular graphs. \newblock Technical Report TR 95-035, Department of Computer Science, University of Minnesota, Minnesota, 1995. \bibitem{karypis98metis} G.~Karypis and V.~Kumar. \newblock Metis~4.0: Unstructured graph partitioning and sparse matrix ordering system. \newblock Technical report, Department of Computer Science, University of Minnesota, 1998. \newblock Available on the WWW at URL {\em http://www.cs.umn.edu/\~{}metis}. \bibitem{lei89-fidmat} C.~E. Leiserson and J.~G. Lewis. \newblock Orderings for parallel sparse symmetric factorization. \newblock In {\em Parallel Processing for Scientific Computing}, pages 27--31, 1989. \bibitem{liu85-mmd} J.~W.~H. Liu. \newblock Modification of the minimum degree algorithm by multiple elimination. \newblock {\em ACM Trans. on Math. Software}, 11:141--153, 1985. \bibitem{liu90-etree} J.~W.~H. Liu. \newblock The role of elimination trees in sparse factorization. \newblock {\em SIAM J. Matrix Analysis and Applic.}, 11:134--172, 1990. \bibitem{ng96-mindefIdaho} E.~Ng and P.~Raghavan. \newblock Minimum deficiency ordering. \newblock In {\em Second SIAM Conference on Sparse Matrices}, 1996. \newblock Conference presentation. \bibitem{pot90-partition} A.~Pothen, H.~Simon, and K.P. Liou. \newblock Partitioning sparse matrices with eigenvectors of graphs. \newblock {\em SIAM J. Matrix Analysis and Applic.}, 11:430--452, 1990. \bibitem{rag95-PCO} P.~Raghavan. \newblock Parallel ordering using edge contraction. \newblock Technical Report CS-95-293, Dept. of Computer Science, The University of Tennessee, Knoxville, Tennessee, 1995. \bibitem{ro95-hybrid} E.~Rothberg. \newblock Robust ordering of sparse matrices: a minimum degree, nested dissection hybrid. \newblock unpublished, 1995. \bibitem{roth98-minfill} E.~Rothberg and S.~C. Eisenstat. \newblock Node selection strategies for bottom-up sparse matrix ordering. \newblock {\em SIAM J. Matrix Anal.}, 19:682--695, 1998. \bibitem{sch82-etree} R.~Schreiber. \newblock A new implementation of sparse {G}aussian elimination. \newblock {\em ACM Trans. Math. Soft.}, pages 256--276, 1982. \end{thebibliography} sh98-maxflow} C.~Ashcraft and J.~W.~H. Liu. \newblock Applications of the {D}ulmage-{M}endelsohn decomposition and network flow to graph bisection improvement. \newblock {\em SIAM J. Matrix. Anal.}, 19:325--354, 1999. \bibitem{bar93-partition} S.~T. Barnard and H.~D. Sidocumentation/FrontTrees/main.ind010064400020550007177000000000000663202363600204510ustar00clevecompmath00000400000006documentation/FrontTrees/main.ilg010064400020550007177000000002730663202363600204660ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx...done (0 entries accepted, 0 rejected). Nothing written in main.ind. Transcript written in main.ilg. documentation/FrontTrees/intro.tex010064400020550007177000000055070663236123300207250ustar00clevecompmath00000400000006\section{Introduction} \par If the ultimate goal is to solve linear systems of the form $AX = B$, one must compute an $A = LDU$, $A = U^TDU$ or $A = U^HDU$ factorization, depending on whether the matrix $A$ is nonsymmetric, symmetric or Hermitian. $D$ is a diagonal or block diagonal matrix, $L$ is unit lower triangular, and $U$ is unit upper triangular. $A$ is sparse, but the sparsity structure of $L$ and $U$ will likely be much larger than that of $A$, i.e., they will suffer fill-in. It is crucial to find a permutation matrix such that the factors of $PAP^T$ have as moderate fill-in as can be reasonably expected. \par To illustrate, consider a 27-point finite difference operator defined on an $n \times n \times n$ grid. The number of rows and columns in $A$ is $n^3$, as is the number of nonzero entries in $A$. Using the natural ordering, the numbers of entries in $L$ and $U$ are $O(n^5)$, and it takes $O(n^7)$ operations to compute the factorization. The banded and profile orderings \cite{geo81-book} have the same complexity. \par Using the nested dissection ordering, \cite{geo73-nested}, the factor storage is reduced to $O(n^4)$ and factor operations to $O(n^6)$. In practice, the minimum degree ordering has this same low-fill nature, although topological counterexamples exist \cite{ber90-mindeg}. A unit cube is the worst case comparison between banded and profile orderings and the minimum degree and nested dissection orderings. But, there is still a lot to be gained by using a good permutation when solving most sparse linear systems, and the relative gain becomes larger as the problem size increases. \par This short paper is a gentle introduction to the ordering methods --- the background as well as the specific function calls. But finding a good ordering is not enough. The ``choreography'' of the factorization and solves, i.e., what data structures and computations exist, and in a parallel environment, which thread or processor does what and when, is as crucial. The structure of the factor matrices, as well as the structure of the computations is controlled by a ``front tree''. This object is constructed directly by the {\bf SPOOLES} ordering software, or can be created from the graph of the matrix and an outside permutation. Various transformations on the front tree can make a large difference in performance. Some knowledge of the linear system, (e.g., does it come from a 2-D or 3-D problem? is it small or large?), coupled with some knowledge of how to tailor a front tree, can be important to getting the best performance from the library. \par Section~\ref{section:ordering} introduces some background on sparse matrix orderings and describes the {\bf SPOOLES} ordering software. Section~\ref{section:front-trees} presents the front tree object that controls the factorization, and its various transformations to improve performance. documentation/FrontTrees/f.aux010064400020550007177000000006400663203711400200030ustar00clevecompmath00000400000006\relax \@setckpt{f}{ \setcounter{page}{3} \setcounter{equation}{0} \setcounter{enumi}{0} \setcounter{enumii}{0} \setcounter{enumiii}{0} \setcounter{enumiv}{0} \setcounter{footnote}{0} \setcounter{mpfootnote}{0} \setcounter{part}{0} \setcounter{section}{2} \setcounter{subsection}{1} \setcounter{subsubsection}{0} \setcounter{paragraph}{0} \setcounter{subparagraph}{0} \setcounter{figure}{0} \setcounter{table}{0} } documentation/FrontTrees/ordering.tex010064400020550007177000000332170663302154500214020ustar00clevecompmath00000400000006\section{Sparse matrix orderings} \label{section:ordering} \par The past few years have seen a resurgence of interest and accompanying improvement in algorithms and software to order sparse matrices. The minimum degree algorithm, specifically the multiple external minimum degree algorithm \cite{liu85-mmd}, was the preferred algorithm of choice for the better part of a decade. Alternative minimum priority codes have recently pushed multiple minimum degree aside, including approximate minimum degree \cite{ame96-amd} and approximate deficiency \cite{ng96-mindefIdaho}, \cite{roth98-minfill}. They offer improved quality or improved run time, and on occasion, both. \par Nested dissection for regular grids \cite{geo73-nested} is within a factor of optimal with respect to factor entries and operation counts. One of the earliest attempts, automatic nested dissection \cite{geo81-book} used a simple profile algorithm to find separators. It rarely performed as well as minimum degree. Better heuristics to find separators were brought in from the electrical device simulation area \cite{lei89-fidmat} and while these algorithms produced better orderings, the run times kept them from practical application. Nested dissection came on its own with two developments. The first was the application of spectral analysis of graphs to find separators \cite{pot90-partition}. The eigenvector associated with the smallest nonzero eigenvalue of the Laplacian of a graph generates a spectrum of separators. While the ordering times for spectral nested dissection were still on the order of ten or more times the cost of a minimum degree ordering, the ordering quality sometimes made the cost worthwhile. \par The key that made nested dissection a competitive and practical alternative to minimum degree was the introduction of multilevel ideas --- to find a separator on a graph, first find a separator on a coarse graph and project back to the original. Early implementations include \cite{bar93-partition} and \cite{bui93-partition}. Multilevel algorithms are very popular in current software including {\bf CHACO} \cite{hen93-chaco}, \cite{hen92-partition}, {\bf METIS} \cite{kar95-multilevel}, \cite{karypis98metis}, {\bf BEND} \cite{hr98-msnd}, {\bf WGGP} \cite{gup96-WGPP} and {\bf PCO} \cite{rag95-PCO}. \par {\bf SPOOLES} also includes a hybrid ordering approach called multi-section \cite{ash97-partition}, \cite{ash98-maxflow}, \cite{ash98-multisection} and \cite{ro95-hybrid}. For some types of graphs, nested dissection does much better than minimum degree, for others much worse. Multisection is an ordering that uses both nested dissection and minimum degree to create an ordering that is almost always as good or better than the better of nested dissection or minimum degree and rarely much worse. \par \subsection{The {\tt Graph} object} \label{subsection:graph} \par Our goal is to find a permutation matrix $P$ such that the factorization of $PAP^T$ has low-fill. This is a symbolic step, we do not need to know the numerical entries in $A$, but we do need to know the structure of $A$. More specifically, since when computing $LDU$, $U^TDU$ or $U^HDU$ factorizations we consider $A$ to have symmetric structure. We need to know the structure of $A + A^T$, and so we need to construct the graph of $A+A^T$. The way that {\bf SPOOLES} deals with the graph of $A + A^T$ is via a {\tt Graph} object. There are several ways to construct a {\tt Graph} object, some are high level, some are low level. \par Inside each {\tt Graph} object is an {\tt IVL} object. {\tt IVL} stands for {\tt I}nteger {\tt V}ector {\tt L}ist, and stores the adjacency lists for the vertices. For example, consider a $3 \times 4$ grid with a nine point operator. The adjacency lists for this graph are stored in the {\tt IVL} object, displayed in Figure~\ref{fig:3x4-grid}. (The listing comes from the {\tt IVL\_writeForHumanEye()} method.) \par \input fig3x4grid.tex \par One can construct the {\tt IVL} object directly. There are methods to set the number of lists, to set the size of a list, to copy entries in a list into the object. It resizes itself as necessary. However, if one already has the matrix entries of $A$ stored in an {\tt InpMtx} object (which is the way that {\bf SPOOLES} deals with sparse matrices), there is an easier way. One can create an {\tt IVL} object from the {\tt InpMtx} object, as follows. \begin{verbatim} InpMtx *A ; IVL *adjIVL ; adjIVL = InpMtx_fullAdjacency(A) ; \end{verbatim} During a block shifted Lanczos eigenanalysis, one needs the graph of $A + \sigma B$ for a pair of matrices. There is a method to construct the {\tt IVL} object for this case. \begin{verbatim} InpMtx *A, *B ; IVL *adjIVL ; adjIVL = InpMtx_fullAdjacency2(A, B) ; \end{verbatim} Recall, we actually construct the adjacency structure of $A + A^T$ (or $A + A^T + B + B^T$), because the graph object is undirected, and so needs a symmetric structure. \par Once we have an {\tt IVL} object, we can construct a {\tt Graph} object as follows. \begin{verbatim} Graph *graph ; IVL *adjIVL ; int nedges, neqns ; nedges = IVL_tsize(adjIVL) ; graph = Graph_new() ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; \end{verbatim} This is an initializer for the {\tt Graph} object, one that takes as input a complete {\tt IVL} adjacency object. The {\tt 0} and {\tt NULL} fields are not applicable here. (The {\tt Graph} object is sophisticated --- it can have weighted or unweighted vertices, weighted or unweighted edges, or both, and it can have boundary vertices. Neither is relevant now.) \par \subsection{Constructing an ordering} \label{subsection:order} \par Once we have a {\tt Graph} object, we can construct an ordering. There are four choices: \begin{itemize} \item minimum degree, (actually multiple external minimum degree, from \cite{liu85-mmd}), \item generalized nested dissection, \item multisection, and \item the better of generalized nested dissection and multisection. \end{itemize} Minimum degree takes the least amount of CPU time. Generalized nested dissection and multisection both require the a partition of the graph, which can be much more expensive to compute than a minimum degree ordering. By and large, for larger graphs nested dissection generates better orderings than minimum degree, and the difference in quality increases as the graph size increases. Multisection is an ordering which almost all the time does about as well as the better of nested dissection and minimum degree. The user should know their problem and choose the ordering. Here are some rules of thumb. \begin{itemize} \item If the matrix size is small to moderate in size, say up to 10,000 rows and columns, use minimum degree. The extra ordering time for nested dissection or multisection may not make up for any decrease in factor or solve time. \item If the matrix size comes from a partial differential equation that has several degrees of freedom at a grid point, use multisection or nested dissection, no matter the size. \item If the target is a parallel factorization, use nested dissection. \item For 2-D problems, minimum degree is usually good enough, for 3-D problems, use nested dissection or multisection. \item To be safe, use the better of the nested dissection and multisection methods. The additional ordering time is not much more than using either of them alone. \end{itemize} Before we discuss the different ordering methods found in {\tt SPOOLES}, what is the output of the ordering? \par One normally thinks of a permutation matrix $P$ as represented by a permutation vector, a map from old vertices to new vertices, or vice versa. That is sufficient if one is just concerned with permuting a matrix, but there is much more information needed for the factor and solves. The {\tt SPOOLES} ordering methods construct and return an {\tt ETree} object that holds the {\it front tree}. We will discuss this object in the next section. Let us now look at the four different wrapper methods for the orderings. \begin{verbatim} ETree *etree ; Graph *graph ; int maxdomainsize, maxsize, maxzeros, msglvl, seed ; FILE *msgFile ; etree = orderViaMMD(graph, seed, msglvl, msgFile) ; etree = orderViaND(graph, maxdomainsize, seed, msglvl, msgFile) ; etree = orderViaMS(graph, maxdomainsize, seed, msglvl, msgFile) ; etree = orderViaBestOfNDandMS(graph, maxdomainsize, maxzeros, maxsize, seed, msglvl, msgFile) ; \end{verbatim} Now let us describe the different parameters. \begin{itemize} \item The {\tt msglvl} and {\tt msgFile} parameters are used to control output. When {\tt msglvl = 0}, there is no output. When {\tt msglvl > 0}, output goes to the {\tt msgFile} file. The {\bf SPOOLES} library is a research code, we have left a great deal of monitoring and debug code in the software. Large values of {\tt msglvl} may result in large message files. To see the statistics generated during the ordering, use {\tt msglvl = 1}. \item The {\tt seed} parameter is used as a random number seed. (There are many places in the graph partitioning and minimum degree algorithms where randomness plays a part. Using a random number seed ensures repeatability.) \item {\tt maxdomainsize} is used for the nested dissection and multisection orderings. This parameter is used during the graph partition. Any subgraph that is larger than {\tt maxdomainsize} is split. We recommend using a value of {\tt neqns/16} or {\tt neqns/32}. Note: {\tt maxdomainsize} must be greater than zero. \item {\tt maxzeros} and {\tt maxsize} are used to transform the front tree. In effect, we have placed the ordering functionality as well as the transformation of the front tree into this method. So let's wait until the next section to learn about the {\tt maxzeros} and {\tt maxsize} parameters. \end{itemize} There is also the capability to create a front tree from a graph using any permutation vectors, e.g., a permutation that came from another graph partitioning or ordering library. \begin{verbatim} ETree *etree ; Graph *graph ; int newToOld[], oldToNew[] ; etree = ETree_new() ; ETree_initFromGraphWithPerms(etree, graph, newToOld, oldToNew) ; \end{verbatim} The output from this method is a {\it vertex} elimination tree, there has been no merging of rows and columns into fronts. But we are getting ahead of ourselves. \par \subsection{Results} \label{subsection:results} \par Let us look at the four different orderings and compare the ordering time, the number of factor entries, and number of operations in the factorization. (The latter two are for a real, symmetric matrix.) \par The {\tt R2D10000} matrix is a randomly triangulated grid on the unit square. There are 10000 grid points, 100 points are equally spaced along each boundary. The remainder of the vertices are placed in the interior using quasi-random points, and the Delauney triangulation is computed. \begin{center} \begin{tabular}{rrrrrrr} & \multicolumn{3}{c}{minimum degree} & \multicolumn{3}{c}{nested dissection} \\ seed & CPU & \# entries & \# ops & CPU & \# entries & \# ops \\ 10101 & 1.4 & 212811 & 11600517 & 4.8 & 213235 & 11092015 \\ 10102 & 1.5 & 211928 & 11654848 & 4.6 & 216555 & 11665187 \\ 10103 & 1.5 & 222119 & 13492499 & 4.9 & 217141 & 11606103 \\ 10104 & 1.5 & 214151 & 11849181 & 5.0 & 217486 & 11896366 \\ 10105 & 1.5 & 216176 & 12063326 & 4.8 & 216404 & 11638612 \\ & \multicolumn{3}{c}{multisection} & \multicolumn{3}{c}{better of ND and MS} \\ seed & CPU & \# entries & \# ops & CPU & \# entries & \# ops \\ 10101 & 4.6 & 207927 & 10407553 & 6.2 & 208724 & 10612824 \\ 10102 & 4.6 & 210364 & 10651916 & 6.2 & 211089 & 10722231 \\ 10103 & 4.6 & 215795 & 11760095 & 6.4 & 217141 & 11606103 \\ 10104 & 4.6 & 210989 & 10842091 & 6.1 & 212828 & 11168728 \\ 10105 & 4.8 & 209201 & 10335761 & 6.1 & 210468 & 10582750 \end{tabular} \end{center} For the nested dissection and multisection orderings, we used {\tt maxdomainsize = 100}. We see that there is really little difference in ordering quality, while the minimum degree ordering takes much less time than the other orderings. \par Let us now look at a random triangulation of a unit cube. This matrix has 13824 rows and columns. Each face of the cube has a $22 \times 22$ regular grid of points. The remainder of the vertices are placed in the interior using quasi-random points, and the Delauney triangulation is computed. \begin{center} \begin{tabular}{rrrrrrr} & \multicolumn{3}{c}{minimum degree} & \multicolumn{3}{c}{nested dissection} \\ seed & CPU & \# entries & \# ops & CPU & \# entries & \# ops \\ 10101 & 9.2 & 5783892 & 6119141542 & 27.8 & 3410222 & 1921402246 \\ 10102 & 8.8 & 5651678 & 5959584620 & 31.4 & 3470063 & 1998795621 \\ 10103 & 8.8 & 6002897 & 6724035555 & 25.8 & 3456887 & 1986837981 \\ 10104 & 8.6 & 5888698 & 6652391434 & 29.6 & 3459432 & 1977133474 \\ 10105 & 8.5 & 5749469 & 6074040475 & 30.1 & 3567956 & 2223250836 \\ & \multicolumn{3}{c}{multisection} & \multicolumn{3}{c}{better of ND and MS} \\ seed & CPU & \# entries & \# ops & CPU & \# entries & \# ops \\ 10101 & 26.9 & 3984032 & 2807531148 & 34.3 & 3410222 & 1921402246 \\ 10102 & 29.7 & 4209860 & 3266381908 & 37.0 & 3470063 & 1998795621 \\ 10103 & 23.5 & 4044399 & 2963782415 & 31.7 & 3456887 & 1986837981 \\ 10104 & 25.9 & 4239568 & 3325299298 & 34.8 & 3459432 & 1977133474 \\ 10105 & 27.2 & 4039078 & 2945539836 & 35.9 & 3567956 & 2223250836 \end{tabular} \end{center} Again there is about a factor of three in CPU time comparing minimum degree against the others, but unlike R2D10000, the minimum degree requires far fewer operations than the others. Note how the multisection ordering requires about 50\% more operations than nested dissection. The situation can be reversed in other cases. That is the reason that we recommend using the wrapper that generates the better of the nested dissection and multisection orderings. nine point operator. The adjacency lists for this graph are stored in the {\tt IVL} object, displayed in Figure~\ref{fig:3x4-grid}. (The listing comes from the {\tt IVL\_writeForHumanEye()} method.) \par \input fig3x4grid.tex \par One can construct the {\tt IVL} object directly. There are methods to set the number of lists, to set the size of a list, to copy entriesdocumentation/FrontTrees/fronttrees.tex010064400020550007177000000561720663304062200217660ustar00clevecompmath00000400000006\section{Front Trees} \label{section:front-trees} \par To illustrate the different types of front trees, and their transformations we do for the sake of efficiency, we will use an an example the matrix R2D100, a matrix generated by first randomly triangulating the unit square with 100 grid points. The resulting matrix has 100 rows and columns. We ordered the matrix using a generalized nested dissection algorithm from the {\bf SPOOLES} library. On the left in Figure~\ref{fig:R2D100} is the triangulation. On the right we have labeled the grid points with their place in the nested dissection ordering. Note that vertices 90 through 99 form a separator of the graph. Vertices 0 through 47 are found on the right of the separator, vertices 48 through 89 are found on the left \par \begin{figure}[htbp] \caption{R2D100: randomly triangulated, 100 grid points} \label{fig:R2D100} \begin{center} \mbox{ \psfig{file=R2D100.eps,width=3.0in,height=3.00in} } \mbox{ \psfig{file=R2D100perm.eps,width=3.0in,height=3.00in} } \end{center} \end{figure} \par \subsection{Vertex elimination trees} \label{subsection:vtx-elim} \par Recall that the four ordering methods from Section~\ref{section:ordering} return an {\tt ETree} object. % In addition to the tree structure, an {\tt ETree} object contains % other information: the number of internal and external rows % and columns to a % front, and a map from each row and column to the front it belongs in. There is another way to construct a tree using the {\tt Graph} object and the permutation vectors. The following code fragment shows how to do this. \begin{verbatim} ETree *vetree ; int *newToOld, *oldToNew ; Graph *graph ; vetree = ETree_new() ; ETree_initFromGraphWithPerms(vetree, graph, newToOld, oldToNew) ; \end{verbatim} The {\tt vetree} object in the code fragment above is a {\it vertex elimination tree} \cite{liu90-etree}, \cite{sch82-etree}, where each front contains one vertex. \par Figure~\ref{fig:R2D100-tree-vtx} contains the vertex elimination tree for this ordering. The vertex elimination tree is a representation of the partial order by which the vertices in the graph may be eliminated.\footnote{ Vertex $j$ is the parent of $i$ if $j$ is the first vertex greater than $i$ such that $L_{j,i} \ne 0$. } The dependencies of the rows and columns form a tree structure. The leaves of the tree (our trees hang upside down with the leaves at the bottom and the root at the top) represent vertices which can be eliminated first. The parents of those leaf nodes can be eliminated next, and so on, until finally the vertices represented by the root of the tree will be eliminated last. \par \begin{figure}[htbp] \caption{Vertex elimination tree for R2D100, 100 rows and columns} \label{fig:R2D100-tree-vtx} \begin{center} \mbox{ \psfig{file=vtree.eps,width=5.0in,height=5.00in} } \end{center} \end{figure} \par The elimination tree illustrates the dependence of the vertices. The basic rule is that a vertex {\it depends} only on its descendents and will {\it affect} only its ancestors. It should be clear that the tree allows us to identify independent, parallel computation. For example, the computation of the factor entries in the subtree rooted at vertex 47 is completely independent of the subtree rooted at vertex 89, so we could identify one process to compute the left subtree and another to compute the right subtree. \par \subsection{Fundamental supernode trees} \label{subsection:fs-tree} \par While the vertex elimination tree is useful to communicate the data dependencies, it is not a good granularity on which to base a factorization or solve, in serial or in parallel. It is important to group vertices together in some meaningful way to create larger data structures that will be more efficient with respect to storage and computation. % The first step in this direction is to group together vertices % that form a chain with no branches in the tree. Any grouping of vertices imposes a block structure on the matrix. The {\it fundamental supernode tree} \cite{ash89-relaxed} has these property: any node in the tree is \begin{itemize} \item either a leaf, \item or has two or more children, \item or its nonzero structure is not contained in that of its one child. \end{itemize} The top tree in Figure~\ref{fig:fs-trees} shows the vertex elimination tree with the ``front'' number of each vertex superimposed on the vertex. The bottom tree is the fundamental supernode tree. Figure~\ref{fig:R2D100-fs-mtx} shows the block partition superimposed on the structure of the factor $L$. Note this one important property: within any block column and below the diagonal block, a row is either zero or dense. \par \begin{figure}[htbp] \caption{Top: vertex elimination tree with the vertices mapped to the fundamental supernode that contains them. Bottom: fundamental supernode tree.} \label{fig:fs-trees} \begin{center} \mbox{ \psfig{file=fsvtree.eps,width=5.0in,height=5.00in} } \par \mbox{ \psfig{file=fstree.eps,width=4.71in,height=2.63in} } \end{center} \end{figure} \par \begin{figure}[htbp] \caption{Block structure of $L$ with the fundamental supernode partition.} \label{fig:R2D100-fs-mtx} \begin{center} \mbox{ \psfig{file=fsmtx.eps,width=5.0in,height=5.00in} } \end{center} \end{figure} \par The code fragment to convert a tree into a fundamental supernode tree is given below. \begin{verbatim} ETree *fsetree, *vetree ; int maxzeros ; IV *nzerosIV ; nzerosIV = IV_new() ; IV_init(nzerosIV, vetree->nfront, NULL) ; IV_fill(nzerosIV, 0) ; maxzeros = 0 ; fsetree = ETree_mergeFrontsOne(vetree, maxzeros, nzerosIV) ; \end{verbatim} The {\tt ETree\_mergeFrontsOne()} method constructs a new {\tt ETree} object from the {\tt vetree} object. When a node $J$ has a single child $I$, it looks to see whether merging $I$ and $J$ together will add more than a given number of zeroes into the block columns of $I$ and $J$. (The nonzero rows of the block of $I$ and $J$ together is the union of the nonzero rows of blocks $I$ and $J$ separately, and all nonzero rows are stored as dense rows.) To create a fundamental supernode tree, the number of zeros allowed into a block column is zero, i.e., the nonzero structure of the fundamental supernode tree contains no zeros. The {\tt nzerosIV} object contains a running count of the number of zero entries present in the factor storage. It will be used in later calls to other transformation methods. \par \subsection{Amalgamated or relaxed supernode trees} \label{subsection:am-tree} \par A factorization based on the fundamental supernode tree requires no more operations than one based on the vertex elimination tree. There are many small supernodes at the lower levels of the tree. By {\it amalgamating} small but connected sets of supernodes together into larger supernodes we can reduce the overhead of the processing all of the small supernodes at the expense of adding entries to the factors and operations to compute the factorization. This amalgamation of supernodes generally leads to an overall increase in efficiency \cite{ash89-relaxed}, \cite{duf83-multifrontal}. We call the result the {\it amalgamated} or {\it relaxed} supernode tree. \par The top tree in Figure~\ref{fig:am-trees} shows the vertex elimination tree with the ``front'' number of each vertex superimposed on the vertex. The bottom tree is the amalgamated supernode tree. Figure~\ref{fig:R2D100-am-mtx} shows the block partition superimposed on the structure of the factor $L$. \par \begin{figure}[htbp] \caption{Top: fundamental supernode tree with the supernodes mapped to the amalgamated supernode that contains them. Bottom: amalgamated supernode tree.} \label{fig:am-trees} \begin{center} \mbox{ \psfig{file=amvtree.eps,width=5.0in,height=5.00in} } \par \mbox{ \psfig{file=amtree.eps,width=3.25in,height=1.38in} } \end{center} \end{figure} \par \begin{figure}[htbp] \caption{Block structure of $L$ with the amalgamated supernode partition.} \label{fig:R2D100-am-mtx} \begin{center} \mbox{ \psfig{file=ammtx.eps,width=5.0in,height=5.00in} } \end{center} \end{figure} \par The code fragment to create this amalgamated tree is found below. \begin{verbatim} ETree *ametree ; maxzeros = 20 ; ametree = ETree_mergeFrontsAll(fsetree, maxzeros, nzerosIV) ; \end{verbatim} This method will merge a node with {\it all} of its children if it will not result in more than {\tt maxzeros} zeros inside the new block. On input, {\tt nzerosIV} object keeps count of the number of zeroes already in the blocks of {\tt fsetree}, and on return it will contain the number of zeros in the blocks of {\tt ametree}. \par \subsection{Splitting large fronts} \label{subsection:sp-tree} \par There is one final step to constructing the tree that governs the factorization and solve. Large matrices will generate large supernodes at the topmost levels of the tree. For example, a $k \times k \times k$ grid with a 27 point finite difference operator, when ordered by nested dissection, has a root supernode with $k^2$ rows and columns. The data structure for a top level supernode can be very large, too large to fit into memory. In a parallel environment, we follow the convention that each node in the tree is handled by one process. Having a very large node at the top levels of the tree will severely decrease the parallelism available to the computations. \par The solution to both problems, large data structures and limited parallelism, is to split large supernodes into pieces. We can specify a maximum size for the nodes in the tree, and split the large supernode into pieces no larger than this maximum size. This will keep the data structures to a manageable size and increase the available parallelism. We call the resulting tree the {\it front} tree because it represents the final computational unit for the factorization, the frontal matrix. \par The amalgamated supernode tree has been transformed so that except for the leaf nodes, which are not changed, no node in the tree has more than four vertices. The top tree in Figure~\ref{fig:sp-trees} shows the vertex elimination tree with the ``front'' number of each vertex superimposed on the vertex. The bottom tree is the amalgamated and split supernode tree. Figure~\ref{fig:sp-mtx} shows the block partition superimposed on the structure of the factor $L$. Splitting large nodes into smaller nodes will not increase the factor storage or operation counts, in fact, as we shall soon see, it is possible to decrease them slightly when compared to the amalgamated tree before splitting. \par \begin{figure}[htbp] \caption{Left: tree after the large supernodes have been split. Right: tree with nodes mapped back to their amalgamated supernode.} \label{fig:sp-trees} \begin{center} \mbox{ \psfig{file=spvtree.eps,width=5.00in,height=5.000in} } \quad \mbox{ \psfig{file=sptree.eps,width=3.25in,height=2.21in} } \end{center} \end{figure} \par \begin{figure}[htbp] \caption{Block structure of $L$ with the amalgamated and split supernode partition.} \label{fig:sp-mtx} \begin{center} \mbox{ \psfig{file=spmtx.eps,width=5.0in,height=5.00in} } \end{center} \end{figure} \par The code fragment to split the large fronts is found below. \begin{verbatim} ETree *spetree ; int maxsize, seed ; maxsize = 4 ; spetree = ETree_splitFronts(ametree, NULL, maxsize, seed) ; \end{verbatim} This method creates and returns an {\tt ETree} object where each front has {\tt maxsize} or fewer internal rows and columns, except for the fronts that are leaves in the tree. Here we imposed the condition that no non-leaf front has more than four vertices. The second parameter in the calling sequence is non-{\tt NULL} if the graph has nonunit vertex weights. The last parameter is a seed for a random number generator. When we identify a front with more than {\tt maxsize} internal rows and columns, there are many ways to split the front into smaller fronts. We try to keep the sizes of the fronts roughly equal, but which vertices to play into which fronts is not specified. We shuffle the vertices using a random number generator and assign vertices to smaller fronts in a block manner. \par \subsection{Results} \label{subsection:tree-results} \par This front tree is now the defining structure for the numerical factorization and solve steps. The structure of the front tree defines the order of the computations that will be carried out in the factorization and the solve. The composition of the front tree can have a profound effect on storage and performance of the factorization and solves. \par Our {\tt R2D100} matrix was small enough to illustrate the steps in the transformation of the front tree, but is not large enough to realistically display how the front tree influences the differences in storage and speed of the computations. Now we look at the {\tt R3D13824} matrix. Table~\ref{table:R3D13824-tree-stats} contains some statistics for a sequence of front trees. The original front tree came from our nested dissection ordering. \par \begin{table}[htbp] \label{table:R3D13824-tree-stats} \caption{R3D13824: front tree transformations} \begin{center} \begin{tabular}{l|rrrrr} & CPU & \# fronts & \# indices & \# entries & \# operations \\ \hline original & & 6001 & 326858 & 3459359 & 1981403337 \\ fs tree & 0.040 & 6000 & 326103 & 3459359 & 1981403337 \\ merge one & 0.032 & 3477 & 158834 & 3497139 & 2000297117 \\ merge all & 0.020 & 748 & 95306 & 3690546 & 2021347776 \\ merge any & 0.012 & 597 & 85366 & 3753241 & 2035158539 \\ split & 0.043 & 643 & 115139 & 3753241 & 2035158539 \\ final & 0.423 & 643 & 115128 & 3752694 & 2034396840 \end{tabular} \end{center} \end{table} \par There are 13824 rows and columns in the matrix, and 6001 fronts in the nested dissection tree. While there is an average of two rows and columns per front, most of the fronts are singleton fronts at the lower levels of the tree. The top level front has 750 internal rows and columns. \par \begin{itemize} \item In the first step we create an fundamental supernode tree with a call to {\tt ETree\_mergeFrontsOne()} with {\tt maxzeros = 0}. We see that the number of fronts decreases by one and the number of entries does not change. \item The second step is also a call to {\tt ETree\_mergeFrontsOne()}, this time with {\tt maxzeros = 1000}. Here we merge fronts with only one child with that child, in other words, only chains of nodes can merge together. Note how the number of fronts is decreased by almost one half, and the number of factor entries and operations increase by 1\%. \item The third step is a call to {\tt ETree\_mergeFrontsAll()} with {\tt maxzeros = 1000}, where we try to merge a node with all of its children if possible. The number of fronts decreases again by a factor of five, while the number of factor entries and operations increases by 7\% and 2\%, respectively, when compared with the original factor matrices. \item The fourth step is a call to {\tt ETree\_mergeFrontsAny()} with {\tt maxzeros = 1000}, where we try to merge a front with any subset of its children. The number of fronts decreases further, and the factor entries and operations increase by 8\% and 3\%, respectively. \item In the fifth step is a call to {\tt ETree\_splitFronts()} with {\tt maxsize = 64}, where we try split the large fronts into smaller fronts. Note that the number of factor entries and operations do not seem to increase, while the number of fronts increases by about 8\%. In reality, a large front that is split into smaller fronts may have a non-dense block column structure, a one of its smaller fronts may have rows in its block column of $L$ that are zero, whereas that same row in the larger front is nonzero. \end{itemize} Merging fronts and splitting fronts can have a large effect on the computational performance of a factor and solve. Table~\ref{table:R3D13824-comp-stats} contains some results for solving linear systems of equations for the {\tt R3D13824} matrix using the five different front trees. \par \begin{table}[htbp] \label{table:R3D13824-comp-stats} \caption{R3D13824: factor and solve timings for five different front trees.} \begin{center} \begin{tabular}{l|ccccccc} & & \multicolumn{2}{c}{factor} & & \multicolumn{2}{c}{solve} & total \\ & init & CPU & mflops & postprocess & CPU & mflops & CPU \\ \hline original & 4.0 & 131.7 & 15.0 & 5.0 & 7.3 & ~7.6 & 148.0 \\ fs tree & 3.3 & 130.4 & 15.2 & 5.4 & 7.8 & ~7.1 & 146.9 \\ merge one & 3.1 & 119.9 & 16.7 & 2.7 & 4.6 & 12.1 & 130.3 \\ merge all & 3.0 & 120.7 & 16.7 & 1.4 & 3.6 & 16.2 & 128.7 \\ merge any & 3.0 & 121.6 & 16.7 & 1.4 & 3.5 & 16.9 & 129.5 \\ split & 3.0 & ~84.9 & 24.0 & 1.9 & 3.5 & 17.1 & ~93.3 \end{tabular} \end{center} \end{table} \par The first thing to notice is that factorization performance improves slightly as small fronts are merged together. The large improvement comes when the fronts are split. The explanation of this behavior is that all {\it inter-front} computation is done using BLAS3 kernels for the operation $Y := Y - L * D * U$, where $L$ and $U$ are dense matrices, $D$ is diagonal or block diagonal with $1 \times 1$ and $2 \times 2$ pivots, and $Y$ is dense. The {\it intra-front} computations, done entirely within the block columns of $L$ and block rows of $U$, are done using BLAS1 kernels. This is necessary when pivoting for stability. Had we chosen to write BLAS3 kernels for the intra-front computations when pivoting is not enabled, the factorization timings for the first five front trees would have been higher. But splitting fronts into smaller fronts is necessary for parallel computations, so it made sense to make it the recommended route for serial computations as well. There would be very little difference in speed had the intra-front computations been done with BLAS3 kernels compared with using the final front tree, for the intra-front computations are a small fraction of the total number of operations. \par The solve time improves dramatically when small fronts are merged together into larger fronts. Our solves are submatrix algorithms, where the fundamental kernel is an operation $Y_J := B_J - L_{J,I} X_I$ and $X_J := Y_J - U_{I,J} Y_J$, and is designed to be a BLAS2 kernel (when $X$ and $Y$ have a single column) or BLAS3 kernel (when $X$ and $Y$ are matrices). When fronts are small, particularly with one internal row and column, the submatrices that take part are very small. The overhead for the computations takes far more time than the computations themselves. \par This multistep process of merging, merging again, etc, and finally splitting the front trees is tedious. There are simple methods that do the process in one step. \begin{verbatim} ETree *etree, *etree2, *etree3 ; int maxfrontsize, maxzeros, seed ; etree2 = ETree_transform(etree, NULL, maxzeros, maxfrontsize, seed) ; etree3 = ETree_transform2(etree, NULL, maxzeros, maxfrontsize, seed) ; \end{verbatim} Inside The {\tt ETree\_transform()} method is a sequence of four transformations: \begin{itemize} \item Merge small fronts into larger fronts using the {\tt ETree\_mergeFrontsOne()} method. \item Then merge small fronts into larger fronts using the {\tt ETree\_mergeFrontsAll()} method. \item Then merge small fronts into larger fronts using the {\tt ETree\_mergeFrontsAny()} method. \item Then merge a large front into a chain of smaller fronts using the {\tt ETree\_splitFronts()} method. \end{itemize} The {\tt ETree\_transform2()} method differs from the {\tt ETree\_transform()} method in that it omits the setp with {\tt ETree\_mergeFrontsAny()}. Either method will be suitable in most cases. \par However, there are some times one method is to be preferred over the other. If we look again at the vertex elimination tree in Figure~\ref{fig:R2D100-tree-vtx}, we see the top level separator with nodes $\{90,\cdots,99\}$, and the two second level separators with nodes $\{45,\cdots,47\}$ and $\{87,\cdots,89\}$. If one looks at their block columns in Figure~\ref{fig:R2D100-fs-mtx} we see that either of the two second level separators could be merged with the top level separator without introducing any zero entries into the factor. Using the {\tt ETree\_mergeFrontsAny()} method could merge the top level separator with one of its two children, and produce an imbalanced tree, not as well suited for parallel computation had the two separators not been merged. \par In a parallel environment, it is much more efficient to not merge the top level separator with either of its second level separators. The transformation methods in {\bf SPOOLES 1.0} created front trees that were not as efficient for parallel processing, precisely because of the use of the ``merge-with-any'' step. This led us to write three separate merging methods to replace the single method from the 1.0 release, and thus give us the ability to avoid the trees unsuitable for parallel computation. \par The values of {\tt maxzeros} and {\tt maxsize} will have a fair amount of influence on the efficiency of the factor and solves. This is illustrated in Table~\ref{table:R3D13824-maxzero-maxsize} for the {\tt R3D13824} matrix and a number of different combinations of {\tt maxzeros} and {\tt maxsize}. \par \begin{table}[htbp] \label{table:R3D13824-maxzero-maxsize} \caption{R3D13824: the influence of {\tt maxzeros} and {\tt maxsize}.} \begin{center} \begin{tabular}{cc|ccccccc} & & & \multicolumn{2}{c}{factor} & & \multicolumn{2}{c}{solve} & total\\ {\tt maxzeros} & {\tt maxsize} & init & CPU & mflops & postprocess & CPU & mflops & CPU \\ \hline $~~~~~0$ & $\infty$ & 3.3 & 129.8 & 15.3 & 5.3 & 7.8 & ~7.1 & 146.2 \\ $~~~~10$ & $\infty$ & 3.5 & 129.2 & 15.3 & 3.3 & 5.3 & 10.5 & 141.3 \\ $~~~100$ & $\infty$ & 3.0 & 119.3 & 16.7 & 2.0 & 3.9 & 14.4 & 128.2 \\ $~~1000$ & $\infty$ & 3.0 & 121.8 & 16.7 & 1.4 & 3.5 & 17.0 & 129.7 \\ $~10000$ & $\infty$ & 3.5 & 138.1 & 16.8 & 1.5 & 4.0 & 17.8 & 147.1 \\ $~~1000$ & 32 & 3.3 & ~89.8 & 22.7 & 2.6 & 4.1 & 14.7 & ~99.8 \\ $~~1000$ & 48 & 3.1 & ~85.8 & 23.7 & 2.1 & 3.6 & 16.5 & ~94.6 \\ $~~1000$ & 64 & 3.1 & ~85.2 & 23.9 & 1.9 & 3.5 & 17.1 & ~93.7 \\ $~~1000$ & 80 & 3.0 & ~85.9 & 23.7 & 1.8 & 3.4 & 17.4 & ~94.1 \\ $~~1000$ & 96 & 3.0 & ~86.1 & 23.6 & 1.8 & 3.4 & 17.6 & ~94.3 \\ $~~~~~0$ & 32 & 3.3 & 100.3 & 19.8 & 6.6 & 7.9 & ~7.0 & 118.1 \\ $~~~~~0$ & 48 & 3.2 & ~97.0 & 20.4 & 6.1 & 7.6 & ~7.3 & 113.9 \\ $~~~~~0$ & 64 & 3.2 & ~95.8 & 20.7 & 5.4 & 6.9 & ~8.0 & 111.3 \\ $~~~~~0$ & 80 & 3.2 & ~96.7 & 20.5 & 5.5 & 7.1 & ~7.8 & 112.5 \\ $~~~~~0$ & 96 & 3.2 & ~97.2 & 20.4 & 5.2 & 6.7 & ~8.3 & 112.3 \end{tabular} \end{center} \end{table} \par \par As the matrix size grows, the number of zero entries we can allow into a front can also grow. We recommend using {\tt maxzeros} somewhere between {\tt 0.01*neqns} and {\tt 0.1*neqns}. The exact value isn't crucial, what is important is to have the smaller subtrees at the lower levels of the tree merged together. The {\tt maxsize} parameter specifies the ``panel'' size of the large fronts, and so influences the granularity of the BLAS3 computations in the factorization and solve. If {\tt maxsize} is too large, then too much of the computations in the factorization is done inside a front, which uses a slow kernel. If {\tt maxsize} is too small, then the fronts are too small to get much computational efficiency. We recommend using a value between {\tt 32} and {\tt 96}. Luckily, the factor and solve times are fairly flat within this range. A value of {\tt 64} is what we customarily use. 139 & 2000297117 \\ merge all & 0.020 & 748 & 95306 & 3690546 & 2021347776 \\ merge any & 0.012 & 597 & 85366 & 3753241 & 2035158539 \\ split & 0.043 & 643 & 115139 & 3753241 & 2035158539 \\ final & 0.423 & 643 & 115128 & 3752694 & 2034396840 \end{tabular} \end{center} \end{table} \par There are 13824 rows and columns in the matrix, and 6001 fronts in the nesteddocumentation/FrontTrees/fig3x4grid.tex010064400020550007177000000036510663204644200215440ustar00clevecompmath00000400000006\begin{figure}[htbp] \caption{A $3 \times 4$ 9-point grid with its adjacency structure} \label{fig:3x4-grid} \begin{center} \begin{minipage}{1 in} \setlength{\unitlength}{0.40 cm} \begin{picture}(10,10) % \multiput(1,1)(0,2){4}{ % \multiput(1,1)(2,0){3}{$\bullet$} % } % \multiput(1,1)(0,2){4}{ % \put(1.1,1.4){\line(1,0){4}} % } % \multiput(1,1)(2,0){3}{ % \put(1.35,1.1){\line(0,1){6}} % } \put(1.35,1.0){\line(1,0){1.25}} \put(3.35,1.0){\line(1,0){1.25}} \put(1.35,3.0){\line(1,0){1.25}} \put(3.35,3.0){\line(1,0){1.25}} \put(1.35,5.0){\line(1,0){1.25}} \put(3.35,5.0){\line(1,0){1.25}} \put(1.35,7.0){\line(1,0){1.25}} \put(3.35,7.0){\line(1,0){1.25}} \put(1.00,1.5){\line(0,1){1.00}} \put(3.00,1.5){\line(0,1){1.00}} \put(5.00,1.5){\line(0,1){1.00}} \put(1.00,3.5){\line(0,1){1.00}} \put(3.00,3.5){\line(0,1){1.00}} \put(5.00,3.5){\line(0,1){1.00}} \put(1.00,5.5){\line(0,1){1.00}} \put(3.00,5.5){\line(0,1){1.00}} \put(5.00,5.5){\line(0,1){1.00}} \put(1,1){\makebox(0,0){0}} \put(3,1){\makebox(0,0){1}} \put(5,1){\makebox(0,0){2}} \put(1,3){\makebox(0,0){3}} \put(3,3){\makebox(0,0){4}} \put(5,3){\makebox(0,0){5}} \put(1,5){\makebox(0,0){6}} \put(3,5){\makebox(0,0){7}} \put(5,5){\makebox(0,0){8}} \put(1,7){\makebox(0,0){9}} \put(3,7){\makebox(0,0){10}} \put(5,7){\makebox(0,0){11}} \end{picture} \end{minipage} \qquad \begin{minipage}{4 in} \begin{verbatim} IVL : integer vector list object : type 1, chunked storage 12 lists, 12 maximum lists, 70 tsize, 4240 total bytes 1 chunks, 70 active entries, 1024 allocated, 6.84 % used 0 : 0 1 3 4 1 : 0 1 2 3 4 5 2 : 1 2 4 5 3 : 0 1 3 4 6 7 4 : 0 1 2 3 4 5 6 7 8 5 : 1 2 4 5 7 8 6 : 3 4 6 7 9 10 7 : 3 4 5 6 7 8 9 10 11 8 : 4 5 7 8 10 11 9 : 6 7 9 10 10 : 6 7 8 9 10 11 11 : 7 8 10 11 \end{verbatim} \end{minipage} \end{center} \end{figure} documentation/FrontTrees/temp.tex010064400020550007177000000764060663211004600205370ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,10pt,twoside]{article} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \input psfig \newcommand{\bfi}{{\bf i}} \newcommand{\bfj}{{\bf j}} \newcommand{\bnd}[1]{{\partial{#1}}} \newcommand\WHILE{{\bf while}} \newcommand\IF{{\bf if}} \newcommand\END{{\bf end}} \newcommand\ELSE{{\bf else}} \newcommand\THEN{{\bf then}} \pagestyle{myheadings} % \markboth % {\quad \hrulefill \quad {\bf SPOOLES 2.2} : \today \quad \hrulefill} % {\quad \hrulefill \quad {\bf SPOOLES 2.2} : \quad \today \hrulefill} \markboth {\hspace*{0.5 in} Orderings and Front Trees \quad\hrulefill\quad\today} {\today \quad\hrulefill\quad Orderings and Front Trees \hspace*{0.5 in}} \begin{document} \begin{center} \fbox{ \setlength{\unitlength}{0.15 cm} \begin{picture}(102,102) \put(-0.5,0.5){\framebox(100,100){}} % \put(-0.5,0.5){\line(0,1){100.5}} % 0 \put( 0.5,0.5){\line(0,1){100}} % 1 \put( 0.5,99.5){\line(1,0){1}} % 1 \put( 1.5,0.5){\line(0,1){ 99}} % 2 \put( 1.5,98.5){\line(1,0){1}} % 2 \put( 2.5,0.5){\line(0,1){ 98}} % 3 \put( 2.5,97.5){\line(1,0){1}} % 3 \put( 2.5,0.5){\line(0,1){ 98}} % 4 \put( 2.5,0.5){\line(0,1){ 98}} % 5 \put( 2.5,0.5){\line(0,1){ 98}} % 6 % \put(-0.5,0.5){\framebox( 1, 99){}} % 0 % \put( 0.5,0.5){\framebox( 1, 98){}} % 1 % \put( 1.5,0.5){\framebox( 1, 97){}} % 2 % \put( 2.5,0.5){\framebox( 1, 96){}} % 3 \put( 3.5,0.5){\framebox( 1, 95){}} % 4 \put( 4.5,0.5){\framebox( 1, 94){}} % 5 \put( 5.5,0.5){\framebox( 2, 92){}} % 6, 7 \put( 7.5,0.5){\framebox( 1, 91){}} % 8 \put( 8.5,0.5){\framebox( 1, 90){}} % 9 \put( 9.5,0.5){\framebox( 1, 89){}} % 10 \put(10.5,0.5){\framebox( 1, 88){}} % 11 \put(11.5,0.5){\framebox( 1, 87){}} % 12 \put(12.5,0.5){\framebox( 1, 86){}} % 13 \put(13.5,0.5){\framebox( 1, 85){}} % 14 \put(14.5,0.5){\framebox( 1, 84){}} % 15 \put(15.5,0.5){\framebox( 1, 83){}} % 16 \put(16.5,0.5){\framebox( 1, 82){}} % 17 \put(17.5,0.5){\framebox( 4, 78){}} % 18-21 \put(21.5,0.5){\framebox( 1, 77){}} % 22 \put(22.5,0.5){\framebox( 1, 76){}} % 23 \put(23.5,0.5){\framebox( 1, 75){}} % 24 \put(24.5,0.5){\framebox( 1, 74){}} % 25 \put(25.5,0.5){\framebox( 1, 73){}} % 26 \put(26.5,0.5){\framebox( 1, 72){}} % 27 \put(27.5,0.5){\framebox( 1, 71){}} % 28 \put(28.5,0.5){\framebox( 1, 70){}} % 29 \put(29.5,0.5){\framebox( 1, 69){}} % 30 \put(30.5,0.5){\framebox( 2, 67){}} % 31-32 \put(31.5,0.5){\framebox( 1, 66){}} % 33 \put(32.5,0.5){\framebox( 1, 65){}} % 34 \put(33.5,0.5){\framebox( 1, 64){}} % 35 \put(34.5,0.5){\framebox( 1, 63){}} % 36 \put(35.5,0.5){\framebox( 1, 62){}} % 37 \put(36.5,0.5){\framebox( 1, 61){}} % 38 \put(37.5,0.5){\framebox( 1, 60){}} % 39 \put(38.5,0.5){\framebox( 1, 59){}} % 40 \put(39.5,0.5){\framebox( 1, 58){}} % 41 \put(40.5,0.5){\framebox( 2, 56){}} % 42-43 \put(42.5,0.5){\framebox( 1, 55){}} % 44 \put(43.5,0.5){\framebox( 3, 52){}} % 45-47 \put(47.5,0.5){\framebox( 1, 51){}} % 48 \put(48.5,0.5){\framebox( 1, 50){}} % 49 \put(49.5,0.5){\framebox( 1, 49){}} % 50 \put(50.5,0.5){\framebox( 1, 48){}} % 51 \put(51.5,0.5){\framebox( 1, 47){}} % 52 \put(52.5,0.5){\framebox( 1, 46){}} % 53 \put(53.5,0.5){\framebox( 1, 45){}} % 54 \put(54.5,0.5){\framebox( 1, 44){}} % 55 \put(55.5,0.5){\framebox( 1, 43){}} % 56 \put(56.5,0.5){\framebox( 1, 42){}} % 57 \put(57.5,0.5){\framebox( 1, 41){}} % 58 \put(58.5,0.5){\framebox( 1, 40){}} % 59 \put(59.5,0.5){\framebox( 1, 39){}} % 60 \put(60.5,0.5){\framebox( 1, 38){}} % 61 \put(61.5,0.5){\framebox( 1, 37){}} % 62 \put(62.5,0.5){\framebox( 1, 36){}} % 63 \put(63.5,0.5){\framebox( 2, 34){}} % 64-65 \put(65.5,0.5){\framebox( 5, 29){}} % 66-70 \put(70.5,0.5){\framebox( 1, 28){}} % 71 \put(71.5,0.5){\framebox( 1, 27){}} % 72 \put(72.5,0.5){\framebox( 1, 26){}} % 73 \put(73.5,0.5){\framebox( 1, 25){}} % 74 \put(74.5,0.5){\framebox( 1, 24){}} % 75 \put(75.5,0.5){\framebox( 1, 23){}} % 76 \put(76.5,0.5){\framebox( 1, 22){}} % 77 \put(77.5,0.5){\framebox( 1, 21){}} % 78 \put(78.5,0.5){\framebox( 1, 20){}} % 79 \put(79.5,0.5){\framebox( 1, 19){}} % 80 \put(80.5,0.5){\framebox( 1, 18){}} % 81 \put(81.5,0.5){\framebox( 1, 17){}} % 82 \put(82.5,0.5){\framebox( 1, 16){}} % 83 \put(83.5,0.5){\framebox( 3, 13){}} % 84-86 \put(86.5,0.5){\framebox( 3, 10){}} % 87-89 \put(79,21){\makebox(0,0){$\circ$}} \put(79,20){\makebox(0,0){$\circ$}} \put(79,19){\makebox(0,0){$\circ$}} \put(79,18){\makebox(0,0){$\circ$}} \put(79,16){\makebox(0,0){$\circ$}} \put(80,20){\makebox(0,0){$\circ$}} \put(80,19){\makebox(0,0){$\circ$}} \put(80,18){\makebox(0,0){$\circ$}} \put(80,16){\makebox(0,0){$\circ$}} \put(80,10){\makebox(0,0){$\circ$}} \put(80,4){\makebox(0,0){$\circ$}} \put(81,19){\makebox(0,0){$\circ$}} \put(81,18){\makebox(0,0){$\circ$}} \put(81,17){\makebox(0,0){$\circ$}} \put(81,16){\makebox(0,0){$\circ$}} \put(81,10){\makebox(0,0){$\circ$}} \put(81,4){\makebox(0,0){$\circ$}} \put(76,24){\makebox(0,0){$\circ$}} \put(76,23){\makebox(0,0){$\circ$}} \put(76,22){\makebox(0,0){$\circ$}} \put(76,18){\makebox(0,0){$\circ$}} \put(76,17){\makebox(0,0){$\circ$}} \put(76,15){\makebox(0,0){$\circ$}} \put(77,23){\makebox(0,0){$\circ$}} \put(77,22){\makebox(0,0){$\circ$}} \put(77,18){\makebox(0,0){$\circ$}} \put(77,17){\makebox(0,0){$\circ$}} \put(77,15){\makebox(0,0){$\circ$}} \put(77,14){\makebox(0,0){$\circ$}} \put(77,12){\makebox(0,0){$\circ$}} \put(75,25){\makebox(0,0){$\circ$}} \put(75,22){\makebox(0,0){$\circ$}} \put(75,17){\makebox(0,0){$\circ$}} \put(75,12){\makebox(0,0){$\circ$}} \put(75,11){\makebox(0,0){$\circ$}} \put(75,6){\makebox(0,0){$\circ$}} \put(75,3){\makebox(0,0){$\circ$}} \put(78,22){\makebox(0,0){$\circ$}} \put(78,18){\makebox(0,0){$\circ$}} \put(78,17){\makebox(0,0){$\circ$}} \put(78,15){\makebox(0,0){$\circ$}} \put(78,14){\makebox(0,0){$\circ$}} \put(78,12){\makebox(0,0){$\circ$}} \put(78,11){\makebox(0,0){$\circ$}} \put(78,6){\makebox(0,0){$\circ$}} \put(78,3){\makebox(0,0){$\circ$}} \put(82,18){\makebox(0,0){$\circ$}} \put(82,17){\makebox(0,0){$\circ$}} \put(82,16){\makebox(0,0){$\circ$}} \put(82,15){\makebox(0,0){$\circ$}} \put(82,14){\makebox(0,0){$\circ$}} \put(82,12){\makebox(0,0){$\circ$}} \put(82,11){\makebox(0,0){$\circ$}} \put(82,10){\makebox(0,0){$\circ$}} \put(82,6){\makebox(0,0){$\circ$}} \put(82,4){\makebox(0,0){$\circ$}} \put(82,3){\makebox(0,0){$\circ$}} \put(83,17){\makebox(0,0){$\circ$}} \put(83,16){\makebox(0,0){$\circ$}} \put(83,15){\makebox(0,0){$\circ$}} \put(83,14){\makebox(0,0){$\circ$}} \put(83,12){\makebox(0,0){$\circ$}} \put(83,11){\makebox(0,0){$\circ$}} \put(83,10){\makebox(0,0){$\circ$}} \put(83,7){\makebox(0,0){$\circ$}} \put(83,6){\makebox(0,0){$\circ$}} \put(83,4){\makebox(0,0){$\circ$}} \put(83,3){\makebox(0,0){$\circ$}} \put(73,27){\makebox(0,0){$\circ$}} \put(73,26){\makebox(0,0){$\circ$}} \put(73,14){\makebox(0,0){$\circ$}} \put(73,13){\makebox(0,0){$\circ$}} \put(73,12){\makebox(0,0){$\circ$}} \put(71,29){\makebox(0,0){$\circ$}} \put(71,28){\makebox(0,0){$\circ$}} \put(71,16){\makebox(0,0){$\circ$}} \put(72,28){\makebox(0,0){$\circ$}} \put(72,26){\makebox(0,0){$\circ$}} \put(72,16){\makebox(0,0){$\circ$}} \put(72,15){\makebox(0,0){$\circ$}} \put(74,26){\makebox(0,0){$\circ$}} \put(74,16){\makebox(0,0){$\circ$}} \put(74,15){\makebox(0,0){$\circ$}} \put(74,14){\makebox(0,0){$\circ$}} \put(74,13){\makebox(0,0){$\circ$}} \put(74,12){\makebox(0,0){$\circ$}} \put(84,16){\makebox(0,0){$\circ$}} \put(84,15){\makebox(0,0){$\circ$}} \put(84,14){\makebox(0,0){$\circ$}} \put(84,13){\makebox(0,0){$\circ$}} \put(84,12){\makebox(0,0){$\circ$}} \put(84,11){\makebox(0,0){$\circ$}} \put(84,10){\makebox(0,0){$\circ$}} \put(84,7){\makebox(0,0){$\circ$}} \put(84,6){\makebox(0,0){$\circ$}} \put(84,4){\makebox(0,0){$\circ$}} \put(84,3){\makebox(0,0){$\circ$}} \put(85,15){\makebox(0,0){$\circ$}} \put(85,14){\makebox(0,0){$\circ$}} \put(85,13){\makebox(0,0){$\circ$}} \put(85,12){\makebox(0,0){$\circ$}} \put(85,11){\makebox(0,0){$\circ$}} \put(85,10){\makebox(0,0){$\circ$}} \put(85,7){\makebox(0,0){$\circ$}} \put(85,6){\makebox(0,0){$\circ$}} \put(85,4){\makebox(0,0){$\circ$}} \put(85,3){\makebox(0,0){$\circ$}} \put(86,14){\makebox(0,0){$\circ$}} \put(86,13){\makebox(0,0){$\circ$}} \put(86,12){\makebox(0,0){$\circ$}} \put(86,11){\makebox(0,0){$\circ$}} \put(86,10){\makebox(0,0){$\circ$}} \put(86,7){\makebox(0,0){$\circ$}} \put(86,6){\makebox(0,0){$\circ$}} \put(86,4){\makebox(0,0){$\circ$}} \put(86,3){\makebox(0,0){$\circ$}} \put(61,39){\makebox(0,0){$\circ$}} \put(61,38){\makebox(0,0){$\circ$}} \put(61,37){\makebox(0,0){$\circ$}} \put(61,36){\makebox(0,0){$\circ$}} \put(61,35){\makebox(0,0){$\circ$}} \put(60,40){\makebox(0,0){$\circ$}} \put(60,38){\makebox(0,0){$\circ$}} \put(60,37){\makebox(0,0){$\circ$}} \put(60,33){\makebox(0,0){$\circ$}} \put(60,31){\makebox(0,0){$\circ$}} \put(60,8){\makebox(0,0){$\circ$}} \put(60,1){\makebox(0,0){$\circ$}} \put(62,38){\makebox(0,0){$\circ$}} \put(62,37){\makebox(0,0){$\circ$}} \put(62,36){\makebox(0,0){$\circ$}} \put(62,35){\makebox(0,0){$\circ$}} \put(62,33){\makebox(0,0){$\circ$}} \put(62,31){\makebox(0,0){$\circ$}} \put(62,30){\makebox(0,0){$\circ$}} \put(62,8){\makebox(0,0){$\circ$}} \put(62,1){\makebox(0,0){$\circ$}} \put(63,37){\makebox(0,0){$\circ$}} \put(63,36){\makebox(0,0){$\circ$}} \put(63,35){\makebox(0,0){$\circ$}} \put(63,33){\makebox(0,0){$\circ$}} \put(63,31){\makebox(0,0){$\circ$}} \put(63,30){\makebox(0,0){$\circ$}} \put(63,11){\makebox(0,0){$\circ$}} \put(63,8){\makebox(0,0){$\circ$}} \put(63,2){\makebox(0,0){$\circ$}} \put(63,1){\makebox(0,0){$\circ$}} \put(56,44){\makebox(0,0){$\circ$}} \put(56,43){\makebox(0,0){$\circ$}} \put(56,42){\makebox(0,0){$\circ$}} \put(56,41){\makebox(0,0){$\circ$}} \put(56,13){\makebox(0,0){$\circ$}} \put(57,43){\makebox(0,0){$\circ$}} \put(57,42){\makebox(0,0){$\circ$}} \put(57,41){\makebox(0,0){$\circ$}} \put(57,36){\makebox(0,0){$\circ$}} \put(57,13){\makebox(0,0){$\circ$}} \put(57,12){\makebox(0,0){$\circ$}} \put(58,42){\makebox(0,0){$\circ$}} \put(58,41){\makebox(0,0){$\circ$}} \put(58,36){\makebox(0,0){$\circ$}} \put(58,35){\makebox(0,0){$\circ$}} \put(58,13){\makebox(0,0){$\circ$}} \put(58,12){\makebox(0,0){$\circ$}} \put(59,41){\makebox(0,0){$\circ$}} \put(59,36){\makebox(0,0){$\circ$}} \put(59,35){\makebox(0,0){$\circ$}} \put(59,34){\makebox(0,0){$\circ$}} \put(59,32){\makebox(0,0){$\circ$}} \put(59,13){\makebox(0,0){$\circ$}} \put(59,12){\makebox(0,0){$\circ$}} \put(64,36){\makebox(0,0){$\circ$}} \put(64,35){\makebox(0,0){$\circ$}} \put(64,34){\makebox(0,0){$\circ$}} \put(64,33){\makebox(0,0){$\circ$}} \put(64,32){\makebox(0,0){$\circ$}} \put(64,31){\makebox(0,0){$\circ$}} \put(64,30){\makebox(0,0){$\circ$}} \put(64,13){\makebox(0,0){$\circ$}} \put(64,12){\makebox(0,0){$\circ$}} \put(64,11){\makebox(0,0){$\circ$}} \put(64,8){\makebox(0,0){$\circ$}} \put(64,2){\makebox(0,0){$\circ$}} \put(64,1){\makebox(0,0){$\circ$}} \put(65,35){\makebox(0,0){$\circ$}} \put(65,34){\makebox(0,0){$\circ$}} \put(65,33){\makebox(0,0){$\circ$}} \put(65,32){\makebox(0,0){$\circ$}} \put(65,31){\makebox(0,0){$\circ$}} \put(65,30){\makebox(0,0){$\circ$}} \put(65,13){\makebox(0,0){$\circ$}} \put(65,12){\makebox(0,0){$\circ$}} \put(65,11){\makebox(0,0){$\circ$}} \put(65,8){\makebox(0,0){$\circ$}} \put(65,2){\makebox(0,0){$\circ$}} \put(65,1){\makebox(0,0){$\circ$}} \put(54,46){\makebox(0,0){$\circ$}} \put(54,45){\makebox(0,0){$\circ$}} \put(54,33){\makebox(0,0){$\circ$}} \put(54,31){\makebox(0,0){$\circ$}} \put(54,9){\makebox(0,0){$\circ$}} \put(54,5){\makebox(0,0){$\circ$}} \put(50,50){\makebox(0,0){$\circ$}} \put(50,49){\makebox(0,0){$\circ$}} \put(50,45){\makebox(0,0){$\circ$}} \put(50,31){\makebox(0,0){$\circ$}} \put(48,52){\makebox(0,0){$\circ$}} \put(48,51){\makebox(0,0){$\circ$}} \put(48,47){\makebox(0,0){$\circ$}} \put(49,51){\makebox(0,0){$\circ$}} \put(49,49){\makebox(0,0){$\circ$}} \put(49,48){\makebox(0,0){$\circ$}} \put(49,47){\makebox(0,0){$\circ$}} \put(51,49){\makebox(0,0){$\circ$}} \put(51,48){\makebox(0,0){$\circ$}} \put(51,47){\makebox(0,0){$\circ$}} \put(51,45){\makebox(0,0){$\circ$}} \put(51,31){\makebox(0,0){$\circ$}} \put(52,48){\makebox(0,0){$\circ$}} \put(52,47){\makebox(0,0){$\circ$}} \put(52,45){\makebox(0,0){$\circ$}} \put(52,31){\makebox(0,0){$\circ$}} \put(52,30){\makebox(0,0){$\circ$}} \put(53,47){\makebox(0,0){$\circ$}} \put(53,45){\makebox(0,0){$\circ$}} \put(53,34){\makebox(0,0){$\circ$}} \put(53,32){\makebox(0,0){$\circ$}} \put(53,31){\makebox(0,0){$\circ$}} \put(53,30){\makebox(0,0){$\circ$}} \put(55,45){\makebox(0,0){$\circ$}} \put(55,34){\makebox(0,0){$\circ$}} \put(55,33){\makebox(0,0){$\circ$}} \put(55,32){\makebox(0,0){$\circ$}} \put(55,31){\makebox(0,0){$\circ$}} \put(55,30){\makebox(0,0){$\circ$}} \put(55,9){\makebox(0,0){$\circ$}} \put(55,5){\makebox(0,0){$\circ$}} \put(66,34){\makebox(0,0){$\circ$}} \put(66,33){\makebox(0,0){$\circ$}} \put(66,32){\makebox(0,0){$\circ$}} \put(66,31){\makebox(0,0){$\circ$}} \put(66,30){\makebox(0,0){$\circ$}} \put(66,13){\makebox(0,0){$\circ$}} \put(66,12){\makebox(0,0){$\circ$}} \put(66,11){\makebox(0,0){$\circ$}} \put(66,9){\makebox(0,0){$\circ$}} \put(66,8){\makebox(0,0){$\circ$}} \put(66,5){\makebox(0,0){$\circ$}} \put(66,2){\makebox(0,0){$\circ$}} \put(66,1){\makebox(0,0){$\circ$}} \put(67,33){\makebox(0,0){$\circ$}} \put(67,32){\makebox(0,0){$\circ$}} \put(67,31){\makebox(0,0){$\circ$}} \put(67,30){\makebox(0,0){$\circ$}} \put(67,13){\makebox(0,0){$\circ$}} \put(67,12){\makebox(0,0){$\circ$}} \put(67,11){\makebox(0,0){$\circ$}} \put(67,9){\makebox(0,0){$\circ$}} \put(67,8){\makebox(0,0){$\circ$}} \put(67,5){\makebox(0,0){$\circ$}} \put(67,2){\makebox(0,0){$\circ$}} \put(67,1){\makebox(0,0){$\circ$}} \put(68,32){\makebox(0,0){$\circ$}} \put(68,31){\makebox(0,0){$\circ$}} \put(68,30){\makebox(0,0){$\circ$}} \put(68,13){\makebox(0,0){$\circ$}} \put(68,12){\makebox(0,0){$\circ$}} \put(68,11){\makebox(0,0){$\circ$}} \put(68,9){\makebox(0,0){$\circ$}} \put(68,8){\makebox(0,0){$\circ$}} \put(68,5){\makebox(0,0){$\circ$}} \put(68,2){\makebox(0,0){$\circ$}} \put(68,1){\makebox(0,0){$\circ$}} \put(69,31){\makebox(0,0){$\circ$}} \put(69,30){\makebox(0,0){$\circ$}} \put(69,13){\makebox(0,0){$\circ$}} \put(69,12){\makebox(0,0){$\circ$}} \put(69,11){\makebox(0,0){$\circ$}} \put(69,9){\makebox(0,0){$\circ$}} \put(69,8){\makebox(0,0){$\circ$}} \put(69,5){\makebox(0,0){$\circ$}} \put(69,2){\makebox(0,0){$\circ$}} \put(69,1){\makebox(0,0){$\circ$}} \put(70,30){\makebox(0,0){$\circ$}} \put(70,13){\makebox(0,0){$\circ$}} \put(70,12){\makebox(0,0){$\circ$}} \put(70,11){\makebox(0,0){$\circ$}} \put(70,9){\makebox(0,0){$\circ$}} \put(70,8){\makebox(0,0){$\circ$}} \put(70,5){\makebox(0,0){$\circ$}} \put(70,2){\makebox(0,0){$\circ$}} \put(70,1){\makebox(0,0){$\circ$}} \put(87,13){\makebox(0,0){$\circ$}} \put(87,12){\makebox(0,0){$\circ$}} \put(87,11){\makebox(0,0){$\circ$}} \put(87,10){\makebox(0,0){$\circ$}} \put(87,9){\makebox(0,0){$\circ$}} \put(87,8){\makebox(0,0){$\circ$}} \put(87,7){\makebox(0,0){$\circ$}} \put(87,6){\makebox(0,0){$\circ$}} \put(87,5){\makebox(0,0){$\circ$}} \put(87,4){\makebox(0,0){$\circ$}} \put(87,3){\makebox(0,0){$\circ$}} \put(87,2){\makebox(0,0){$\circ$}} \put(87,1){\makebox(0,0){$\circ$}} \put(88,12){\makebox(0,0){$\circ$}} \put(88,11){\makebox(0,0){$\circ$}} \put(88,10){\makebox(0,0){$\circ$}} \put(88,9){\makebox(0,0){$\circ$}} \put(88,8){\makebox(0,0){$\circ$}} \put(88,7){\makebox(0,0){$\circ$}} \put(88,6){\makebox(0,0){$\circ$}} \put(88,5){\makebox(0,0){$\circ$}} \put(88,4){\makebox(0,0){$\circ$}} \put(88,3){\makebox(0,0){$\circ$}} \put(88,2){\makebox(0,0){$\circ$}} \put(88,1){\makebox(0,0){$\circ$}} \put(89,11){\makebox(0,0){$\circ$}} \put(89,10){\makebox(0,0){$\circ$}} \put(89,9){\makebox(0,0){$\circ$}} \put(89,8){\makebox(0,0){$\circ$}} \put(89,7){\makebox(0,0){$\circ$}} \put(89,6){\makebox(0,0){$\circ$}} \put(89,5){\makebox(0,0){$\circ$}} \put(89,4){\makebox(0,0){$\circ$}} \put(89,3){\makebox(0,0){$\circ$}} \put(89,2){\makebox(0,0){$\circ$}} \put(89,1){\makebox(0,0){$\circ$}} \put(33,67){\makebox(0,0){$\circ$}} \put(33,66){\makebox(0,0){$\circ$}} \put(33,65){\makebox(0,0){$\circ$}} \put(34,66){\makebox(0,0){$\circ$}} \put(34,65){\makebox(0,0){$\circ$}} \put(34,64){\makebox(0,0){$\circ$}} \put(34,62){\makebox(0,0){$\circ$}} \put(35,65){\makebox(0,0){$\circ$}} \put(35,64){\makebox(0,0){$\circ$}} \put(35,63){\makebox(0,0){$\circ$}} \put(35,62){\makebox(0,0){$\circ$}} \put(36,64){\makebox(0,0){$\circ$}} \put(36,63){\makebox(0,0){$\circ$}} \put(36,62){\makebox(0,0){$\circ$}} \put(36,61){\makebox(0,0){$\circ$}} \put(36,60){\makebox(0,0){$\circ$}} \put(37,63){\makebox(0,0){$\circ$}} \put(37,62){\makebox(0,0){$\circ$}} \put(37,61){\makebox(0,0){$\circ$}} \put(37,60){\makebox(0,0){$\circ$}} \put(37,59){\makebox(0,0){$\circ$}} \put(38,62){\makebox(0,0){$\circ$}} \put(38,61){\makebox(0,0){$\circ$}} \put(38,60){\makebox(0,0){$\circ$}} \put(38,59){\makebox(0,0){$\circ$}} \put(38,56){\makebox(0,0){$\circ$}} \put(39,61){\makebox(0,0){$\circ$}} \put(39,60){\makebox(0,0){$\circ$}} \put(39,59){\makebox(0,0){$\circ$}} \put(39,58){\makebox(0,0){$\circ$}} \put(39,56){\makebox(0,0){$\circ$}} \put(39,54){\makebox(0,0){$\circ$}} \put(40,60){\makebox(0,0){$\circ$}} \put(40,59){\makebox(0,0){$\circ$}} \put(40,58){\makebox(0,0){$\circ$}} \put(40,57){\makebox(0,0){$\circ$}} \put(40,56){\makebox(0,0){$\circ$}} \put(40,54){\makebox(0,0){$\circ$}} \put(28,72){\makebox(0,0){$\circ$}} \put(28,71){\makebox(0,0){$\circ$}} \put(28,70){\makebox(0,0){$\circ$}} \put(28,69){\makebox(0,0){$\circ$}} \put(28,55){\makebox(0,0){$\circ$}} \put(28,53){\makebox(0,0){$\circ$}} \put(29,71){\makebox(0,0){$\circ$}} \put(29,70){\makebox(0,0){$\circ$}} \put(29,69){\makebox(0,0){$\circ$}} \put(29,68){\makebox(0,0){$\circ$}} \put(29,55){\makebox(0,0){$\circ$}} \put(29,53){\makebox(0,0){$\circ$}} \put(29,6){\makebox(0,0){$\circ$}} \put(29,3){\makebox(0,0){$\circ$}} \put(30,70){\makebox(0,0){$\circ$}} \put(30,69){\makebox(0,0){$\circ$}} \put(30,68){\makebox(0,0){$\circ$}} \put(30,55){\makebox(0,0){$\circ$}} \put(30,53){\makebox(0,0){$\circ$}} \put(30,8){\makebox(0,0){$\circ$}} \put(30,6){\makebox(0,0){$\circ$}} \put(30,3){\makebox(0,0){$\circ$}} \put(30,2){\makebox(0,0){$\circ$}} \put(23,77){\makebox(0,0){$\circ$}} \put(23,76){\makebox(0,0){$\circ$}} \put(23,75){\makebox(0,0){$\circ$}} \put(23,73){\makebox(0,0){$\circ$}} \put(23,68){\makebox(0,0){$\circ$}} \put(23,7){\makebox(0,0){$\circ$}} \put(24,76){\makebox(0,0){$\circ$}} \put(24,75){\makebox(0,0){$\circ$}} \put(24,74){\makebox(0,0){$\circ$}} \put(24,73){\makebox(0,0){$\circ$}} \put(24,69){\makebox(0,0){$\circ$}} \put(24,68){\makebox(0,0){$\circ$}} \put(24,7){\makebox(0,0){$\circ$}} \put(25,75){\makebox(0,0){$\circ$}} \put(25,74){\makebox(0,0){$\circ$}} \put(25,73){\makebox(0,0){$\circ$}} \put(25,69){\makebox(0,0){$\circ$}} \put(25,68){\makebox(0,0){$\circ$}} \put(25,58){\makebox(0,0){$\circ$}} \put(25,57){\makebox(0,0){$\circ$}} \put(25,7){\makebox(0,0){$\circ$}} \put(26,74){\makebox(0,0){$\circ$}} \put(26,73){\makebox(0,0){$\circ$}} \put(26,69){\makebox(0,0){$\circ$}} \put(26,68){\makebox(0,0){$\circ$}} \put(26,58){\makebox(0,0){$\circ$}} \put(26,57){\makebox(0,0){$\circ$}} \put(26,55){\makebox(0,0){$\circ$}} \put(26,54){\makebox(0,0){$\circ$}} \put(26,7){\makebox(0,0){$\circ$}} \put(22,78){\makebox(0,0){$\circ$}} \put(22,73){\makebox(0,0){$\circ$}} \put(22,59){\makebox(0,0){$\circ$}} \put(22,10){\makebox(0,0){$\circ$}} \put(27,73){\makebox(0,0){$\circ$}} \put(27,69){\makebox(0,0){$\circ$}} \put(27,68){\makebox(0,0){$\circ$}} \put(27,59){\makebox(0,0){$\circ$}} \put(27,58){\makebox(0,0){$\circ$}} \put(27,57){\makebox(0,0){$\circ$}} \put(27,55){\makebox(0,0){$\circ$}} \put(27,54){\makebox(0,0){$\circ$}} \put(27,10){\makebox(0,0){$\circ$}} \put(27,7){\makebox(0,0){$\circ$}} \put(27,4){\makebox(0,0){$\circ$}} \put(31,69){\makebox(0,0){$\circ$}} \put(31,68){\makebox(0,0){$\circ$}} \put(31,59){\makebox(0,0){$\circ$}} \put(31,58){\makebox(0,0){$\circ$}} \put(31,57){\makebox(0,0){$\circ$}} \put(31,55){\makebox(0,0){$\circ$}} \put(31,54){\makebox(0,0){$\circ$}} \put(31,53){\makebox(0,0){$\circ$}} \put(31,10){\makebox(0,0){$\circ$}} \put(31,8){\makebox(0,0){$\circ$}} \put(31,7){\makebox(0,0){$\circ$}} \put(31,6){\makebox(0,0){$\circ$}} \put(31,4){\makebox(0,0){$\circ$}} \put(31,3){\makebox(0,0){$\circ$}} \put(31,2){\makebox(0,0){$\circ$}} \put(32,68){\makebox(0,0){$\circ$}} \put(32,59){\makebox(0,0){$\circ$}} \put(32,58){\makebox(0,0){$\circ$}} \put(32,57){\makebox(0,0){$\circ$}} \put(32,55){\makebox(0,0){$\circ$}} \put(32,54){\makebox(0,0){$\circ$}} \put(32,53){\makebox(0,0){$\circ$}} \put(32,10){\makebox(0,0){$\circ$}} \put(32,8){\makebox(0,0){$\circ$}} \put(32,7){\makebox(0,0){$\circ$}} \put(32,6){\makebox(0,0){$\circ$}} \put(32,4){\makebox(0,0){$\circ$}} \put(32,3){\makebox(0,0){$\circ$}} \put(32,2){\makebox(0,0){$\circ$}} \put(41,59){\makebox(0,0){$\circ$}} \put(41,58){\makebox(0,0){$\circ$}} \put(41,57){\makebox(0,0){$\circ$}} \put(41,56){\makebox(0,0){$\circ$}} \put(41,55){\makebox(0,0){$\circ$}} \put(41,54){\makebox(0,0){$\circ$}} \put(41,53){\makebox(0,0){$\circ$}} \put(41,10){\makebox(0,0){$\circ$}} \put(41,8){\makebox(0,0){$\circ$}} \put(41,7){\makebox(0,0){$\circ$}} \put(41,6){\makebox(0,0){$\circ$}} \put(41,4){\makebox(0,0){$\circ$}} \put(41,3){\makebox(0,0){$\circ$}} \put(41,2){\makebox(0,0){$\circ$}} \put(42,58){\makebox(0,0){$\circ$}} \put(42,57){\makebox(0,0){$\circ$}} \put(42,56){\makebox(0,0){$\circ$}} \put(42,55){\makebox(0,0){$\circ$}} \put(42,54){\makebox(0,0){$\circ$}} \put(42,53){\makebox(0,0){$\circ$}} \put(42,10){\makebox(0,0){$\circ$}} \put(42,8){\makebox(0,0){$\circ$}} \put(42,7){\makebox(0,0){$\circ$}} \put(42,6){\makebox(0,0){$\circ$}} \put(42,4){\makebox(0,0){$\circ$}} \put(42,3){\makebox(0,0){$\circ$}} \put(42,2){\makebox(0,0){$\circ$}} \put(43,57){\makebox(0,0){$\circ$}} \put(43,56){\makebox(0,0){$\circ$}} \put(43,55){\makebox(0,0){$\circ$}} \put(43,54){\makebox(0,0){$\circ$}} \put(43,53){\makebox(0,0){$\circ$}} \put(43,10){\makebox(0,0){$\circ$}} \put(43,8){\makebox(0,0){$\circ$}} \put(43,7){\makebox(0,0){$\circ$}} \put(43,6){\makebox(0,0){$\circ$}} \put(43,4){\makebox(0,0){$\circ$}} \put(43,3){\makebox(0,0){$\circ$}} \put(43,2){\makebox(0,0){$\circ$}} \put(14,86){\makebox(0,0){$\circ$}} \put(14,85){\makebox(0,0){$\circ$}} \put(14,84){\makebox(0,0){$\circ$}} \put(14,83){\makebox(0,0){$\circ$}} \put(14,53){\makebox(0,0){$\circ$}} \put(14,1){\makebox(0,0){$\circ$}} \put(15,85){\makebox(0,0){$\circ$}} \put(15,84){\makebox(0,0){$\circ$}} \put(15,83){\makebox(0,0){$\circ$}} \put(15,81){\makebox(0,0){$\circ$}} \put(15,80){\makebox(0,0){$\circ$}} \put(15,53){\makebox(0,0){$\circ$}} \put(15,1){\makebox(0,0){$\circ$}} \put(12,88){\makebox(0,0){$\circ$}} \put(12,87){\makebox(0,0){$\circ$}} \put(12,80){\makebox(0,0){$\circ$}} \put(12,79){\makebox(0,0){$\circ$}} \put(12,55){\makebox(0,0){$\circ$}} \put(13,87){\makebox(0,0){$\circ$}} \put(13,84){\makebox(0,0){$\circ$}} \put(13,80){\makebox(0,0){$\circ$}} \put(13,79){\makebox(0,0){$\circ$}} \put(13,55){\makebox(0,0){$\circ$}} \put(13,53){\makebox(0,0){$\circ$}} \put(16,84){\makebox(0,0){$\circ$}} \put(16,83){\makebox(0,0){$\circ$}} \put(16,81){\makebox(0,0){$\circ$}} \put(16,80){\makebox(0,0){$\circ$}} \put(16,79){\makebox(0,0){$\circ$}} \put(16,55){\makebox(0,0){$\circ$}} \put(16,53){\makebox(0,0){$\circ$}} \put(16,1){\makebox(0,0){$\circ$}} \put(9,91){\makebox(0,0){$\circ$}} \put(9,90){\makebox(0,0){$\circ$}} \put(9,82){\makebox(0,0){$\circ$}} \put(10,90){\makebox(0,0){$\circ$}} \put(10,89){\makebox(0,0){$\circ$}} \put(10,82){\makebox(0,0){$\circ$}} \put(10,81){\makebox(0,0){$\circ$}} \put(8,92){\makebox(0,0){$\circ$}} \put(8,89){\makebox(0,0){$\circ$}} \put(8,83){\makebox(0,0){$\circ$}} \put(8,9){\makebox(0,0){$\circ$}} \put(11,89){\makebox(0,0){$\circ$}} \put(11,83){\makebox(0,0){$\circ$}} \put(11,82){\makebox(0,0){$\circ$}} \put(11,81){\makebox(0,0){$\circ$}} \put(11,9){\makebox(0,0){$\circ$}} \put(17,83){\makebox(0,0){$\circ$}} \put(17,82){\makebox(0,0){$\circ$}} \put(17,81){\makebox(0,0){$\circ$}} \put(17,80){\makebox(0,0){$\circ$}} \put(17,79){\makebox(0,0){$\circ$}} \put(17,55){\makebox(0,0){$\circ$}} \put(17,53){\makebox(0,0){$\circ$}} \put(17,9){\makebox(0,0){$\circ$}} \put(17,5){\makebox(0,0){$\circ$}} \put(17,1){\makebox(0,0){$\circ$}} \put(3,97){\makebox(0,0){$\circ$}} \put(3,96){\makebox(0,0){$\circ$}} \put(3,95){\makebox(0,0){$\circ$}} \put(3,94){\makebox(0,0){$\circ$}} \put(3,82){\makebox(0,0){$\circ$}} \put(4,96){\makebox(0,0){$\circ$}} \put(4,95){\makebox(0,0){$\circ$}} \put(4,94){\makebox(0,0){$\circ$}} \put(4,93){\makebox(0,0){$\circ$}} \put(4,82){\makebox(0,0){$\circ$}} \put(4,80){\makebox(0,0){$\circ$}} \put(5,95){\makebox(0,0){$\circ$}} \put(5,94){\makebox(0,0){$\circ$}} \put(5,93){\makebox(0,0){$\circ$}} \put(5,82){\makebox(0,0){$\circ$}} \put(5,81){\makebox(0,0){$\circ$}} \put(5,80){\makebox(0,0){$\circ$}} \put(0,100){\makebox(0,0){$\circ$}} \put(0,99){\makebox(0,0){$\circ$}} \put(0,98){\makebox(0,0){$\circ$}} \put(0,94){\makebox(0,0){$\circ$}} \put(0,93){\makebox(0,0){$\circ$}} \put(1,99){\makebox(0,0){$\circ$}} \put(1,98){\makebox(0,0){$\circ$}} \put(1,94){\makebox(0,0){$\circ$}} \put(1,93){\makebox(0,0){$\circ$}} \put(1,79){\makebox(0,0){$\circ$}} \put(1,54){\makebox(0,0){$\circ$}} \put(2,98){\makebox(0,0){$\circ$}} \put(2,94){\makebox(0,0){$\circ$}} \put(2,93){\makebox(0,0){$\circ$}} \put(2,79){\makebox(0,0){$\circ$}} \put(2,56){\makebox(0,0){$\circ$}} \put(2,54){\makebox(0,0){$\circ$}} \put(6,94){\makebox(0,0){$\circ$}} \put(6,93){\makebox(0,0){$\circ$}} \put(6,82){\makebox(0,0){$\circ$}} \put(6,81){\makebox(0,0){$\circ$}} \put(6,80){\makebox(0,0){$\circ$}} \put(6,79){\makebox(0,0){$\circ$}} \put(6,56){\makebox(0,0){$\circ$}} \put(6,54){\makebox(0,0){$\circ$}} \put(7,93){\makebox(0,0){$\circ$}} \put(7,82){\makebox(0,0){$\circ$}} \put(7,81){\makebox(0,0){$\circ$}} \put(7,80){\makebox(0,0){$\circ$}} \put(7,79){\makebox(0,0){$\circ$}} \put(7,56){\makebox(0,0){$\circ$}} \put(7,54){\makebox(0,0){$\circ$}} \put(18,82){\makebox(0,0){$\circ$}} \put(18,81){\makebox(0,0){$\circ$}} \put(18,80){\makebox(0,0){$\circ$}} \put(18,79){\makebox(0,0){$\circ$}} \put(18,56){\makebox(0,0){$\circ$}} \put(18,55){\makebox(0,0){$\circ$}} \put(18,54){\makebox(0,0){$\circ$}} \put(18,53){\makebox(0,0){$\circ$}} \put(18,9){\makebox(0,0){$\circ$}} \put(18,5){\makebox(0,0){$\circ$}} \put(18,1){\makebox(0,0){$\circ$}} \put(19,81){\makebox(0,0){$\circ$}} \put(19,80){\makebox(0,0){$\circ$}} \put(19,79){\makebox(0,0){$\circ$}} \put(19,56){\makebox(0,0){$\circ$}} \put(19,55){\makebox(0,0){$\circ$}} \put(19,54){\makebox(0,0){$\circ$}} \put(19,53){\makebox(0,0){$\circ$}} \put(19,9){\makebox(0,0){$\circ$}} \put(19,5){\makebox(0,0){$\circ$}} \put(19,1){\makebox(0,0){$\circ$}} \put(20,80){\makebox(0,0){$\circ$}} \put(20,79){\makebox(0,0){$\circ$}} \put(20,56){\makebox(0,0){$\circ$}} \put(20,55){\makebox(0,0){$\circ$}} \put(20,54){\makebox(0,0){$\circ$}} \put(20,53){\makebox(0,0){$\circ$}} \put(20,9){\makebox(0,0){$\circ$}} \put(20,5){\makebox(0,0){$\circ$}} \put(20,1){\makebox(0,0){$\circ$}} \put(21,79){\makebox(0,0){$\circ$}} \put(21,56){\makebox(0,0){$\circ$}} \put(21,55){\makebox(0,0){$\circ$}} \put(21,54){\makebox(0,0){$\circ$}} \put(21,53){\makebox(0,0){$\circ$}} \put(21,9){\makebox(0,0){$\circ$}} \put(21,5){\makebox(0,0){$\circ$}} \put(21,1){\makebox(0,0){$\circ$}} \put(44,56){\makebox(0,0){$\circ$}} \put(44,55){\makebox(0,0){$\circ$}} \put(44,54){\makebox(0,0){$\circ$}} \put(44,53){\makebox(0,0){$\circ$}} \put(44,10){\makebox(0,0){$\circ$}} \put(44,9){\makebox(0,0){$\circ$}} \put(44,8){\makebox(0,0){$\circ$}} \put(44,7){\makebox(0,0){$\circ$}} \put(44,6){\makebox(0,0){$\circ$}} \put(44,5){\makebox(0,0){$\circ$}} \put(44,4){\makebox(0,0){$\circ$}} \put(44,3){\makebox(0,0){$\circ$}} \put(44,2){\makebox(0,0){$\circ$}} \put(44,1){\makebox(0,0){$\circ$}} \put(45,55){\makebox(0,0){$\circ$}} \put(45,54){\makebox(0,0){$\circ$}} \put(45,53){\makebox(0,0){$\circ$}} \put(45,10){\makebox(0,0){$\circ$}} \put(45,9){\makebox(0,0){$\circ$}} \put(45,8){\makebox(0,0){$\circ$}} \put(45,7){\makebox(0,0){$\circ$}} \put(45,6){\makebox(0,0){$\circ$}} \put(45,5){\makebox(0,0){$\circ$}} \put(45,4){\makebox(0,0){$\circ$}} \put(45,3){\makebox(0,0){$\circ$}} \put(45,2){\makebox(0,0){$\circ$}} \put(45,1){\makebox(0,0){$\circ$}} \put(46,54){\makebox(0,0){$\circ$}} \put(46,53){\makebox(0,0){$\circ$}} \put(46,10){\makebox(0,0){$\circ$}} \put(46,9){\makebox(0,0){$\circ$}} \put(46,8){\makebox(0,0){$\circ$}} \put(46,7){\makebox(0,0){$\circ$}} \put(46,6){\makebox(0,0){$\circ$}} \put(46,5){\makebox(0,0){$\circ$}} \put(46,4){\makebox(0,0){$\circ$}} \put(46,3){\makebox(0,0){$\circ$}} \put(46,2){\makebox(0,0){$\circ$}} \put(46,1){\makebox(0,0){$\circ$}} \put(47,53){\makebox(0,0){$\circ$}} \put(47,10){\makebox(0,0){$\circ$}} \put(47,9){\makebox(0,0){$\circ$}} \put(47,8){\makebox(0,0){$\circ$}} \put(47,7){\makebox(0,0){$\circ$}} \put(47,6){\makebox(0,0){$\circ$}} \put(47,5){\makebox(0,0){$\circ$}} \put(47,4){\makebox(0,0){$\circ$}} \put(47,3){\makebox(0,0){$\circ$}} \put(47,2){\makebox(0,0){$\circ$}} \put(47,1){\makebox(0,0){$\circ$}} \put(90,10){\makebox(0,0){$\circ$}} \put(90,9){\makebox(0,0){$\circ$}} \put(90,8){\makebox(0,0){$\circ$}} \put(90,7){\makebox(0,0){$\circ$}} \put(90,6){\makebox(0,0){$\circ$}} \put(90,5){\makebox(0,0){$\circ$}} \put(90,4){\makebox(0,0){$\circ$}} \put(90,3){\makebox(0,0){$\circ$}} \put(90,2){\makebox(0,0){$\circ$}} \put(90,1){\makebox(0,0){$\circ$}} \put(91,9){\makebox(0,0){$\circ$}} \put(91,8){\makebox(0,0){$\circ$}} \put(91,7){\makebox(0,0){$\circ$}} \put(91,6){\makebox(0,0){$\circ$}} \put(91,5){\makebox(0,0){$\circ$}} \put(91,4){\makebox(0,0){$\circ$}} \put(91,3){\makebox(0,0){$\circ$}} \put(91,2){\makebox(0,0){$\circ$}} \put(91,1){\makebox(0,0){$\circ$}} \put(92,8){\makebox(0,0){$\circ$}} \put(92,7){\makebox(0,0){$\circ$}} \put(92,6){\makebox(0,0){$\circ$}} \put(92,5){\makebox(0,0){$\circ$}} \put(92,4){\makebox(0,0){$\circ$}} \put(92,3){\makebox(0,0){$\circ$}} \put(92,2){\makebox(0,0){$\circ$}} \put(92,1){\makebox(0,0){$\circ$}} \put(93,7){\makebox(0,0){$\circ$}} \put(93,6){\makebox(0,0){$\circ$}} \put(93,5){\makebox(0,0){$\circ$}} \put(93,4){\makebox(0,0){$\circ$}} \put(93,3){\makebox(0,0){$\circ$}} \put(93,2){\makebox(0,0){$\circ$}} \put(93,1){\makebox(0,0){$\circ$}} \put(94,6){\makebox(0,0){$\circ$}} \put(94,5){\makebox(0,0){$\circ$}} \put(94,4){\makebox(0,0){$\circ$}} \put(94,3){\makebox(0,0){$\circ$}} \put(94,2){\makebox(0,0){$\circ$}} \put(94,1){\makebox(0,0){$\circ$}} \put(95,5){\makebox(0,0){$\circ$}} \put(95,4){\makebox(0,0){$\circ$}} \put(95,3){\makebox(0,0){$\circ$}} \put(95,2){\makebox(0,0){$\circ$}} \put(95,1){\makebox(0,0){$\circ$}} \put(96,4){\makebox(0,0){$\circ$}} \put(96,3){\makebox(0,0){$\circ$}} \put(96,2){\makebox(0,0){$\circ$}} \put(96,1){\makebox(0,0){$\circ$}} \put(97,3){\makebox(0,0){$\circ$}} \put(97,2){\makebox(0,0){$\circ$}} \put(97,1){\makebox(0,0){$\circ$}} \put(98,2){\makebox(0,0){$\circ$}} \put(98,1){\makebox(0,0){$\circ$}} \put(99,1){\makebox(0,0){$\circ$}} \end{picture} } \end{center} \end{document} x(0,0){$\circ$}} \put(41,7){\makebox(0,0){$\circ$}} \put(41,6){\makebox(0,0){$\circ$}} \put(41,4){\makebox(0,0){$\circ$}} \put(41,3){\makebox(0,0){$\circ$}} \put(41,2){\makebox(0,0){$\circ$}} \put(42,58){\makebox(0,0){$\circ$}} \put(42,57){\madocumentation/FrontTrees/temp.log010064400020550007177000000045270663210567000205220ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 4 DEC 1998 17:26 **temp (temp.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/article.cls Document Class: article 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@section=\count80 \c@subsection=\count81 \c@subsubsection=\count82 \c@paragraph=\count83 \c@subparagraph=\count84 \c@figure=\count85 \c@table=\count86 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file temp.idx (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) (temp.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 34. LaTeX Font Info: ... okay on input line 34. LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 878. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 878. [1 ] (temp.aux) ) Here is how much of TeX's memory you used: 443 strings out of 10908 4246 string characters out of 72189 96016 words of memory out of 262141 3386 multiletter control sequences out of 9500 3993 words of font info for 15 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 23i,9n,21p,115b,194s stack positions out of 300i,40n,60p,3000b,4000s Output written on temp.dvi (1 page, 17784 bytes). documentation/FrontTrees/temp.idx010064400020550007177000000000000663210566700205110ustar00clevecompmath00000400000006documentation/FrontTrees/temp.aux010064400020550007177000000000100663210567000205150ustar00clevecompmath00000400000006\relax documentation/FrontTrees/ammtx.eps010064400020550007177000000157650663230676700207310ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.000 0.000 550.000 550.000 %%EndComments /MainFont /Helvetica findfont 8 scalefont def MainFont setfont %----------------------------------------------------------------------- % % utility procedures % %----------------------------------------------------------------------- % % procedure to produce a filled circle % /circle { % stack : x y size % % store input data % /size exch def /y exch def /x exch def gsave newpath x y moveto x size add y size 0 360 arc fill grestore } def %----------------------------------------------------------------------- % % procedure to draw the outline of the matrix % /draw_outline { % stack : xnw ynw dx dy nrow ncol /ncol exch def % number of columns /nrow exch def % number of rows /dy exch def % column spacing /dx exch def % row spacing /ynw exch def % northwest y coordinate /xnw exch def % northwest x coordinated /width ncol 1 add dx mul def /height nrow 1 add dy mul def newpath xnw dx sub ynw dy add moveto currentpoint width 0 rlineto 0 height neg rlineto width neg 0 rlineto closepath stroke } def %----------------------------------------------------------------------- % procedure to draw matrix adjacency structure % /draw_matrix { % stack : xnw ynw dx dy adjncy % % store input data % /adjncy exch def % adjacency structure /dy exch def % column spacing /dx exch def % row spacing /ynw exch def % northwest y coordinate /xnw exch def % northwest x coordinated % % loop over the columns % 0 1 adjncy length 1 sub { % % pop and store the column id and set the x coordinate % /j exch def adjncy j get /column exch def column 0 get /jcol exch def /xj xnw jcol dx mul add def % % loop over the row entries % 0 1 column length 1 sub { % % pop the row id, set the y coordinate and draw the tick % /i exch def column i get /irow exch def xj ynw irow dy mul sub 1 circle } for } for } def %----------------------------------------------------------------------- % % procedures to draw the supernode partition % /draw_sn_overlay { % stack xnw ynw dx dy nrow ncol sninfo % % store input data % /sninfo exch def % supernode information /ncol exch def % # of columns /nrow exch def % # of rows /dy exch def % column spacing /dx exch def % row spacing /ynw exch def % northwest y coordinate /xnw exch def % northwest x coordinated % % draw the left and bottom border % 0.1 dx mul setlinewidth newpath xnw dx 0.4 mul sub ynw dy 0.5 mul add moveto 0 nrow dy mul neg rlineto ncol dx mul 0 rlineto stroke % % loop over the columns % 0 1 sninfo length 1 sub { % % pop and store the column id and set the x coordinate % /J exch def sninfo J get /Jinfo exch def Jinfo 0 get /vJ exch def Jinfo 1 get /nJ exch def % % get location of first diagonal element % /xj xnw vJ dx mul add def /yj ynw vJ dx mul sub def % newpath xj dx 0.25 mul sub yj dx 0.5 mul add moveto nJ dx mul 0 rlineto 0 nJ dy mul neg rlineto nJ dx mul neg 0 rlineto nJ dx mul 0 rmoveto 0 nrow vJ nJ add sub dy mul neg rlineto stroke } for } def %----------------------------------------------------------------------- % /xnw 40 def /ynw 510 def /dx 4 def /dy 4 def % %----------------------------------------------------------------------- % % factor matrix for R2D100 % /adjncyL [ [ 0 1 2 15 16 ] [ 1 2 15 16 21 85 ] [ 2 15 16 21 83 85 ] [ 3 4 5 15 18 ] [ 4 5 15 16 18 20 ] [ 5 15 16 18 19 20 ] [ 6 9 17 91 ] [ 7 8 18 ] [ 8 9 18 19 ] [ 9 17 18 19 91 ] [ 10 11 20 21 84 ] [ 11 14 20 21 84 86 ] [ 12 13 14 17 86 99 ] [ 13 14 17 19 20 86 99 ] [ 14 17 19 20 21 84 86 99 ] [ 15 16 18 19 20 21 83 85 ] [ 16 18 19 20 21 83 85 ] [ 17 18 19 20 21 84 86 91 95 99 ] [ 18 19 20 21 83 84 85 86 91 95 99 ] [ 19 20 21 83 84 85 86 91 95 99 ] [ 20 21 83 84 85 86 91 95 99 ] [ 21 83 84 85 86 91 95 99 ] [ 22 27 41 90 ] [ 23 24 25 27 32 93 ] [ 24 25 26 27 31 32 93 ] [ 25 26 27 31 32 42 43 93 ] [ 26 27 31 32 42 43 84 85 93 ] [ 27 31 32 41 42 43 84 85 90 93 96 ] [ 28 29 30 31 84 86 ] [ 29 30 31 32 84 86 94 97 ] [ 30 31 32 84 86 92 94 97 98 ] [ 31 32 41 42 43 84 85 86 90 92 93 94 96 97 98 ] [ 32 41 42 43 84 85 86 90 92 93 94 96 97 98 ] [ 33 34 35 ] [ 34 35 36 38 ] [ 35 36 37 38 ] [ 36 37 38 39 40 ] [ 37 38 39 40 41 ] [ 38 39 40 41 83 ] [ 39 40 41 42 83 85 ] [ 40 41 42 43 83 85 ] [ 41 42 43 83 84 85 86 90 92 93 94 96 97 98 ] [ 42 43 83 84 85 86 90 92 93 94 96 97 98 ] [ 43 83 84 85 86 90 92 93 94 96 97 98 ] [ 44 45 49 ] [ 45 47 48 49 ] [ 46 47 51 65 ] [ 47 48 49 51 65 ] [ 48 49 51 65 66 ] [ 49 51 62 64 65 66 ] [ 50 51 63 65 91 95 ] [ 51 62 63 64 65 66 91 95 ] [ 52 53 54 55 87 ] [ 53 54 55 60 87 88 ] [ 54 55 60 61 87 88 ] [ 55 60 61 62 64 87 88 ] [ 56 58 59 63 65 92 99 ] [ 57 58 59 60 61 ] [ 58 59 60 61 63 65 66 92 99 ] [ 59 60 61 63 65 66 89 92 98 99 ] [ 60 61 62 63 64 65 66 87 88 89 92 98 99 ] [ 61 62 63 64 65 66 87 88 89 92 98 99 ] [ 62 63 64 65 66 87 88 89 91 92 95 98 99 ] [ 63 64 65 66 87 88 89 91 92 95 98 99 ] [ 64 65 66 87 88 89 91 92 95 98 99 ] [ 65 66 87 88 89 91 92 95 98 99 ] [ 66 87 88 89 91 92 95 98 99 ] [ 67 68 80 ] [ 68 70 80 81 ] [ 69 70 82 87 88 ] [ 70 80 81 82 87 88 ] [ 71 74 79 88 89 94 97 ] [ 72 73 74 78 79 81 ] [ 73 74 78 79 81 82 88 ] [ 74 78 79 81 82 88 89 94 97 ] [ 75 76 77 78 80 ] [ 76 77 78 80 90 96 ] [ 77 78 79 80 90 96 ] [ 78 79 80 81 82 88 89 90 94 96 97 ] [ 79 80 81 82 88 89 90 93 94 96 97 ] [ 80 81 82 87 88 89 90 93 94 96 97 ] [ 81 82 87 88 89 90 93 94 96 97 ] [ 82 87 88 89 90 93 94 96 97 ] [ 83 84 85 86 90 91 92 93 94 95 96 97 98 99 ] [ 84 85 86 90 91 92 93 94 95 96 97 98 99 ] [ 85 86 90 91 92 93 94 95 96 97 98 99 ] [ 86 90 91 92 93 94 95 96 97 98 99 ] [ 87 88 89 90 91 92 93 94 95 96 97 98 99 ] [ 88 89 90 91 92 93 94 95 96 97 98 99 ] [ 89 90 91 92 93 94 95 96 97 98 99 ] [ 90 91 92 93 94 95 96 97 98 99 ] [ 91 92 93 94 95 96 97 98 99 ] [ 92 93 94 95 96 97 98 99 ] [ 93 94 95 96 97 98 99 ] [ 94 95 96 97 98 99 ] [ 95 96 97 98 99 ] [ 96 97 98 99 ] [ 97 98 99 ] [ 98 99 ] [ 99 ] ] def /sn_info [ [ 0 3 ] [ 3 3 ] [ 6 4 ] [ 10 5 ] [ 15 7 ] [ 22 1 ] [ 23 4 ] [ 27 1 ] [ 28 3 ] [ 31 2 ] [ 33 6 ] [ 39 2 ] [ 41 3 ] [ 44 5 ] [ 49 3 ] [ 52 4 ] [ 56 4 ] [ 60 2 ] [ 62 5 ] [ 67 4 ] [ 71 4 ] [ 75 3 ] [ 78 2 ] [ 80 3 ] [ 83 17 ] ] def %----------------------------------------------------------------------- /nrow 100 def /ncol 100 def /row_ids [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48] def %----------------------------------------------------------------------- % % draw outline and gridlines % xnw ynw dx dy nrow ncol draw_outline xnw ynw dx dy adjncyL draw_matrix xnw ynw dx dy nrow ncol sn_info draw_sn_overlay l sub 1 cirdocumentation/FrontTrees/amtree.eps010064400020550007177000000076120663232310200210260ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 390 165 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 350 125 rectstroke newpath 30 77.5 66.923 101.25 ML 54.615 77.5 66.923 101.25 ML 79.231 77.5 66.923 101.25 ML 103.846 77.5 66.923 101.25 ML 66.923 101.25 203.077 125 ML 128.462 30 140.769 53.75 ML 153.077 30 140.769 53.75 ML 140.769 53.75 159.231 77.5 ML 177.692 53.75 159.231 77.5 ML 159.231 77.5 180.769 101.25 ML 202.308 53.75 202.308 77.5 ML 202.308 77.5 180.769 101.25 ML 180.769 101.25 203.077 125 ML 226.923 53.75 226.923 77.5 ML 226.923 77.5 245.385 101.25 ML 251.538 53.75 263.846 77.5 ML 276.154 53.75 263.846 77.5 ML 263.846 77.5 245.385 101.25 ML 245.385 101.25 203.077 125 ML 300.769 77.5 319.231 101.25 ML 325.385 53.75 337.692 77.5 ML 350 53.75 337.692 77.5 ML 337.692 77.5 319.231 101.25 ML 319.231 101.25 203.077 125 ML stroke gsave /Helvetica-Bold findfont 15 scalefont setfont 1.0 setgray 30 77.5 10 FC 0.0 setgray 30 77.5 10 OC 30 72.5 moveto (0) CSH 1.0 setgray 54.615 77.5 10 FC 0.0 setgray 54.615 77.5 10 OC 54.615 72.5 moveto (1) CSH 1.0 setgray 79.231 77.5 10 FC 0.0 setgray 79.231 77.5 10 OC 79.231 72.5 moveto (2) CSH 1.0 setgray 103.846 77.5 10 FC 0.0 setgray 103.846 77.5 10 OC 103.846 72.5 moveto (3) CSH 1.0 setgray 66.923 101.25 10 FC 0.0 setgray 66.923 101.25 10 OC 66.923 96.25 moveto (4) CSH 1.0 setgray 128.462 30 10 FC 0.0 setgray 128.462 30 10 OC 128.462 25 moveto (5) CSH 1.0 setgray 153.077 30 10 FC 0.0 setgray 153.077 30 10 OC 153.077 25 moveto (6) CSH 1.0 setgray 140.769 53.75 10 FC 0.0 setgray 140.769 53.75 10 OC 140.769 48.75 moveto (7) CSH 1.0 setgray 177.692 53.75 10 FC 0.0 setgray 177.692 53.75 10 OC 177.692 48.75 moveto (8) CSH 1.0 setgray 159.231 77.5 10 FC 0.0 setgray 159.231 77.5 10 OC 159.231 72.5 moveto (9) CSH 1.0 setgray 202.308 53.75 10 FC 0.0 setgray 202.308 53.75 10 OC 202.308 48.75 moveto (10) CSH 1.0 setgray 202.308 77.5 10 FC 0.0 setgray 202.308 77.5 10 OC 202.308 72.5 moveto (11) CSH 1.0 setgray 180.769 101.25 10 FC 0.0 setgray 180.769 101.25 10 OC 180.769 96.25 moveto (12) CSH 1.0 setgray 226.923 53.75 10 FC 0.0 setgray 226.923 53.75 10 OC 226.923 48.75 moveto (13) CSH 1.0 setgray 226.923 77.5 10 FC 0.0 setgray 226.923 77.5 10 OC 226.923 72.5 moveto (14) CSH 1.0 setgray 251.538 53.75 10 FC 0.0 setgray 251.538 53.75 10 OC 251.538 48.75 moveto (15) CSH 1.0 setgray 276.154 53.75 10 FC 0.0 setgray 276.154 53.75 10 OC 276.154 48.75 moveto (16) CSH 1.0 setgray 263.846 77.5 10 FC 0.0 setgray 263.846 77.5 10 OC 263.846 72.5 moveto (17) CSH 1.0 setgray 245.385 101.25 10 FC 0.0 setgray 245.385 101.25 10 OC 245.385 96.25 moveto (18) CSH 1.0 setgray 300.769 77.5 10 FC 0.0 setgray 300.769 77.5 10 OC 300.769 72.5 moveto (19) CSH 1.0 setgray 325.385 53.75 10 FC 0.0 setgray 325.385 53.75 10 OC 325.385 48.75 moveto (20) CSH 1.0 setgray 350 53.75 10 FC 0.0 setgray 350 53.75 10 OC 350 48.75 moveto (21) CSH 1.0 setgray 337.692 77.5 10 FC 0.0 setgray 337.692 77.5 10 OC 337.692 72.5 moveto (22) CSH 1.0 setgray 319.231 101.25 10 FC 0.0 setgray 319.231 101.25 10 OC 319.231 96.25 moveto (23) CSH 1.0 setgray 203.077 125 10 FC 0.0 setgray 203.077 125 10 OC 203.077 120 moveto (24) CSH grestore showpage documentation/FrontTrees/amvtree.eps010064400020550007177000000337540663232310600212260ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 600 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 580 580 rectstroke newpath 30 75.833 30 98.75 ML 30 98.75 30 121.667 ML 30 121.667 43.75 144.583 ML 57.5 75.833 57.5 98.75 ML 57.5 98.75 57.5 121.667 ML 57.5 121.667 43.75 144.583 ML 43.75 144.583 43.75 167.5 ML 43.75 167.5 85 190.417 ML 85 121.667 98.75 144.583 ML 112.5 98.75 112.5 121.667 ML 112.5 121.667 98.75 144.583 ML 98.75 144.583 126.25 167.5 ML 140 98.75 140 121.667 ML 140 121.667 153.75 144.583 ML 167.5 98.75 167.5 121.667 ML 167.5 121.667 153.75 144.583 ML 153.75 144.583 126.25 167.5 ML 126.25 167.5 85 190.417 ML 85 190.417 85 213.333 ML 85 213.333 85 236.25 ML 85 236.25 85 259.167 ML 85 259.167 169.219 282.083 ML 195 121.667 208.75 144.583 ML 222.5 52.917 222.5 75.833 ML 222.5 75.833 222.5 98.75 ML 222.5 98.75 222.5 121.667 ML 222.5 121.667 208.75 144.583 ML 208.75 144.583 229.375 167.5 ML 250 98.75 250 121.667 ML 250 121.667 250 144.583 ML 250 144.583 229.375 167.5 ML 229.375 167.5 229.375 190.417 ML 229.375 190.417 253.438 213.333 ML 277.5 30 277.5 52.917 ML 277.5 52.917 277.5 75.833 ML 277.5 75.833 277.5 98.75 ML 277.5 98.75 277.5 121.667 ML 277.5 121.667 277.5 144.583 ML 277.5 144.583 277.5 167.5 ML 277.5 167.5 277.5 190.417 ML 277.5 190.417 253.438 213.333 ML 253.438 213.333 253.438 236.25 ML 253.438 236.25 253.438 259.167 ML 253.438 259.167 169.219 282.083 ML 169.219 282.083 169.219 305 ML 169.219 305 169.219 327.917 ML 169.219 327.917 169.219 350.833 ML 169.219 350.833 308.438 373.75 ML 305 52.917 305 75.833 ML 305 75.833 318.75 98.75 ML 332.5 75.833 318.75 98.75 ML 318.75 98.75 318.75 121.667 ML 318.75 121.667 318.75 144.583 ML 318.75 144.583 339.375 167.5 ML 360 144.583 339.375 167.5 ML 339.375 167.5 373.75 190.417 ML 387.5 52.917 387.5 75.833 ML 387.5 75.833 387.5 98.75 ML 387.5 98.75 387.5 121.667 ML 387.5 121.667 408.125 144.583 ML 415 75.833 428.75 98.75 ML 442.5 75.833 428.75 98.75 ML 428.75 98.75 428.75 121.667 ML 428.75 121.667 408.125 144.583 ML 408.125 144.583 408.125 167.5 ML 408.125 167.5 373.75 190.417 ML 373.75 190.417 373.75 213.333 ML 373.75 213.333 373.75 236.25 ML 373.75 236.25 373.75 259.167 ML 373.75 259.167 373.75 282.083 ML 373.75 282.083 447.656 305 ML 470 167.5 470 190.417 ML 470 190.417 483.75 213.333 ML 497.5 190.417 483.75 213.333 ML 483.75 213.333 521.562 236.25 ML 525 144.583 538.75 167.5 ML 552.5 121.667 552.5 144.583 ML 552.5 144.583 538.75 167.5 ML 538.75 167.5 559.375 190.417 ML 580 121.667 580 144.583 ML 580 144.583 580 167.5 ML 580 167.5 559.375 190.417 ML 559.375 190.417 559.375 213.333 ML 559.375 213.333 521.562 236.25 ML 521.562 236.25 521.562 259.167 ML 521.562 259.167 521.562 282.083 ML 521.562 282.083 447.656 305 ML 447.656 305 447.656 327.917 ML 447.656 327.917 447.656 350.833 ML 447.656 350.833 308.438 373.75 ML 308.438 373.75 308.438 396.667 ML 308.438 396.667 308.438 419.583 ML 308.438 419.583 308.438 442.5 ML 308.438 442.5 308.438 465.417 ML 308.438 465.417 308.438 488.333 ML 308.438 488.333 308.438 511.25 ML 308.438 511.25 308.438 534.167 ML 308.438 534.167 308.438 557.083 ML 308.438 557.083 308.438 580 ML stroke gsave /Helvetica-Bold findfont 15 scalefont setfont 1.0 setgray 30 75.833 10 FC 0.0 setgray 30 75.833 10 OC 30 70.833 moveto (0) CSH 1.0 setgray 30 98.75 10 FC 0.0 setgray 30 98.75 10 OC 30 93.75 moveto (0) CSH 1.0 setgray 30 121.667 10 FC 0.0 setgray 30 121.667 10 OC 30 116.667 moveto (0) CSH 1.0 setgray 57.5 75.833 10 FC 0.0 setgray 57.5 75.833 10 OC 57.5 70.833 moveto (1) CSH 1.0 setgray 57.5 98.75 10 FC 0.0 setgray 57.5 98.75 10 OC 57.5 93.75 moveto (1) CSH 1.0 setgray 57.5 121.667 10 FC 0.0 setgray 57.5 121.667 10 OC 57.5 116.667 moveto (1) CSH 1.0 setgray 43.75 144.583 10 FC 0.0 setgray 43.75 144.583 10 OC 43.75 139.583 moveto (4) CSH 1.0 setgray 43.75 167.5 10 FC 0.0 setgray 43.75 167.5 10 OC 43.75 162.5 moveto (4) CSH 1.0 setgray 85 121.667 10 FC 0.0 setgray 85 121.667 10 OC 85 116.667 moveto (2) CSH 1.0 setgray 112.5 98.75 10 FC 0.0 setgray 112.5 98.75 10 OC 112.5 93.75 moveto (2) CSH 1.0 setgray 112.5 121.667 10 FC 0.0 setgray 112.5 121.667 10 OC 112.5 116.667 moveto (2) CSH 1.0 setgray 98.75 144.583 10 FC 0.0 setgray 98.75 144.583 10 OC 98.75 139.583 moveto (2) CSH 1.0 setgray 140 98.75 10 FC 0.0 setgray 140 98.75 10 OC 140 93.75 moveto (3) CSH 1.0 setgray 140 121.667 10 FC 0.0 setgray 140 121.667 10 OC 140 116.667 moveto (3) CSH 1.0 setgray 167.5 98.75 10 FC 0.0 setgray 167.5 98.75 10 OC 167.5 93.75 moveto (3) CSH 1.0 setgray 167.5 121.667 10 FC 0.0 setgray 167.5 121.667 10 OC 167.5 116.667 moveto (3) CSH 1.0 setgray 153.75 144.583 10 FC 0.0 setgray 153.75 144.583 10 OC 153.75 139.583 moveto (3) CSH 1.0 setgray 126.25 167.5 10 FC 0.0 setgray 126.25 167.5 10 OC 126.25 162.5 moveto (4) CSH 1.0 setgray 85 190.417 10 FC 0.0 setgray 85 190.417 10 OC 85 185.417 moveto (4) CSH 1.0 setgray 85 213.333 10 FC 0.0 setgray 85 213.333 10 OC 85 208.333 moveto (4) CSH 1.0 setgray 85 236.25 10 FC 0.0 setgray 85 236.25 10 OC 85 231.25 moveto (4) CSH 1.0 setgray 85 259.167 10 FC 0.0 setgray 85 259.167 10 OC 85 254.167 moveto (4) CSH 1.0 setgray 195 121.667 10 FC 0.0 setgray 195 121.667 10 OC 195 116.667 moveto (5) CSH 1.0 setgray 222.5 52.917 10 FC 0.0 setgray 222.5 52.917 10 OC 222.5 47.917 moveto (6) CSH 1.0 setgray 222.5 75.833 10 FC 0.0 setgray 222.5 75.833 10 OC 222.5 70.833 moveto (6) CSH 1.0 setgray 222.5 98.75 10 FC 0.0 setgray 222.5 98.75 10 OC 222.5 93.75 moveto (6) CSH 1.0 setgray 222.5 121.667 10 FC 0.0 setgray 222.5 121.667 10 OC 222.5 116.667 moveto (6) CSH 1.0 setgray 208.75 144.583 10 FC 0.0 setgray 208.75 144.583 10 OC 208.75 139.583 moveto (7) CSH 1.0 setgray 250 98.75 10 FC 0.0 setgray 250 98.75 10 OC 250 93.75 moveto (8) CSH 1.0 setgray 250 121.667 10 FC 0.0 setgray 250 121.667 10 OC 250 116.667 moveto (8) CSH 1.0 setgray 250 144.583 10 FC 0.0 setgray 250 144.583 10 OC 250 139.583 moveto (8) CSH 1.0 setgray 229.375 167.5 10 FC 0.0 setgray 229.375 167.5 10 OC 229.375 162.5 moveto (9) CSH 1.0 setgray 229.375 190.417 10 FC 0.0 setgray 229.375 190.417 10 OC 229.375 185.417 moveto (9) CSH 1.0 setgray 277.5 30 10 FC 0.0 setgray 277.5 30 10 OC 277.5 25 moveto (10) CSH 1.0 setgray 277.5 52.917 10 FC 0.0 setgray 277.5 52.917 10 OC 277.5 47.917 moveto (10) CSH 1.0 setgray 277.5 75.833 10 FC 0.0 setgray 277.5 75.833 10 OC 277.5 70.833 moveto (10) CSH 1.0 setgray 277.5 98.75 10 FC 0.0 setgray 277.5 98.75 10 OC 277.5 93.75 moveto (10) CSH 1.0 setgray 277.5 121.667 10 FC 0.0 setgray 277.5 121.667 10 OC 277.5 116.667 moveto (10) CSH 1.0 setgray 277.5 144.583 10 FC 0.0 setgray 277.5 144.583 10 OC 277.5 139.583 moveto (10) CSH 1.0 setgray 277.5 167.5 10 FC 0.0 setgray 277.5 167.5 10 OC 277.5 162.5 moveto (11) CSH 1.0 setgray 277.5 190.417 10 FC 0.0 setgray 277.5 190.417 10 OC 277.5 185.417 moveto (11) CSH 1.0 setgray 253.438 213.333 10 FC 0.0 setgray 253.438 213.333 10 OC 253.438 208.333 moveto (12) CSH 1.0 setgray 253.438 236.25 10 FC 0.0 setgray 253.438 236.25 10 OC 253.438 231.25 moveto (12) CSH 1.0 setgray 253.438 259.167 10 FC 0.0 setgray 253.438 259.167 10 OC 253.438 254.167 moveto (12) CSH 1.0 setgray 169.219 282.083 10 FC 0.0 setgray 169.219 282.083 10 OC 169.219 277.083 moveto (24) CSH 1.0 setgray 169.219 305 10 FC 0.0 setgray 169.219 305 10 OC 169.219 300 moveto (24) CSH 1.0 setgray 169.219 327.917 10 FC 0.0 setgray 169.219 327.917 10 OC 169.219 322.917 moveto (24) CSH 1.0 setgray 169.219 350.833 10 FC 0.0 setgray 169.219 350.833 10 OC 169.219 345.833 moveto (24) CSH 1.0 setgray 305 52.917 10 FC 0.0 setgray 305 52.917 10 OC 305 47.917 moveto (13) CSH 1.0 setgray 305 75.833 10 FC 0.0 setgray 305 75.833 10 OC 305 70.833 moveto (13) CSH 1.0 setgray 332.5 75.833 10 FC 0.0 setgray 332.5 75.833 10 OC 332.5 70.833 moveto (13) CSH 1.0 setgray 318.75 98.75 10 FC 0.0 setgray 318.75 98.75 10 OC 318.75 93.75 moveto (13) CSH 1.0 setgray 318.75 121.667 10 FC 0.0 setgray 318.75 121.667 10 OC 318.75 116.667 moveto (13) CSH 1.0 setgray 318.75 144.583 10 FC 0.0 setgray 318.75 144.583 10 OC 318.75 139.583 moveto (14) CSH 1.0 setgray 360 144.583 10 FC 0.0 setgray 360 144.583 10 OC 360 139.583 moveto (14) CSH 1.0 setgray 339.375 167.5 10 FC 0.0 setgray 339.375 167.5 10 OC 339.375 162.5 moveto (14) CSH 1.0 setgray 387.5 52.917 10 FC 0.0 setgray 387.5 52.917 10 OC 387.5 47.917 moveto (15) CSH 1.0 setgray 387.5 75.833 10 FC 0.0 setgray 387.5 75.833 10 OC 387.5 70.833 moveto (15) CSH 1.0 setgray 387.5 98.75 10 FC 0.0 setgray 387.5 98.75 10 OC 387.5 93.75 moveto (15) CSH 1.0 setgray 387.5 121.667 10 FC 0.0 setgray 387.5 121.667 10 OC 387.5 116.667 moveto (15) CSH 1.0 setgray 415 75.833 10 FC 0.0 setgray 415 75.833 10 OC 415 70.833 moveto (16) CSH 1.0 setgray 442.5 75.833 10 FC 0.0 setgray 442.5 75.833 10 OC 442.5 70.833 moveto (16) CSH 1.0 setgray 428.75 98.75 10 FC 0.0 setgray 428.75 98.75 10 OC 428.75 93.75 moveto (16) CSH 1.0 setgray 428.75 121.667 10 FC 0.0 setgray 428.75 121.667 10 OC 428.75 116.667 moveto (16) CSH 1.0 setgray 408.125 144.583 10 FC 0.0 setgray 408.125 144.583 10 OC 408.125 139.583 moveto (17) CSH 1.0 setgray 408.125 167.5 10 FC 0.0 setgray 408.125 167.5 10 OC 408.125 162.5 moveto (17) CSH 1.0 setgray 373.75 190.417 10 FC 0.0 setgray 373.75 190.417 10 OC 373.75 185.417 moveto (18) CSH 1.0 setgray 373.75 213.333 10 FC 0.0 setgray 373.75 213.333 10 OC 373.75 208.333 moveto (18) CSH 1.0 setgray 373.75 236.25 10 FC 0.0 setgray 373.75 236.25 10 OC 373.75 231.25 moveto (18) CSH 1.0 setgray 373.75 259.167 10 FC 0.0 setgray 373.75 259.167 10 OC 373.75 254.167 moveto (18) CSH 1.0 setgray 373.75 282.083 10 FC 0.0 setgray 373.75 282.083 10 OC 373.75 277.083 moveto (18) CSH 1.0 setgray 470 167.5 10 FC 0.0 setgray 470 167.5 10 OC 470 162.5 moveto (19) CSH 1.0 setgray 470 190.417 10 FC 0.0 setgray 470 190.417 10 OC 470 185.417 moveto (19) CSH 1.0 setgray 497.5 190.417 10 FC 0.0 setgray 497.5 190.417 10 OC 497.5 185.417 moveto (19) CSH 1.0 setgray 483.75 213.333 10 FC 0.0 setgray 483.75 213.333 10 OC 483.75 208.333 moveto (19) CSH 1.0 setgray 525 144.583 10 FC 0.0 setgray 525 144.583 10 OC 525 139.583 moveto (20) CSH 1.0 setgray 552.5 121.667 10 FC 0.0 setgray 552.5 121.667 10 OC 552.5 116.667 moveto (20) CSH 1.0 setgray 552.5 144.583 10 FC 0.0 setgray 552.5 144.583 10 OC 552.5 139.583 moveto (20) CSH 1.0 setgray 538.75 167.5 10 FC 0.0 setgray 538.75 167.5 10 OC 538.75 162.5 moveto (20) CSH 1.0 setgray 580 121.667 10 FC 0.0 setgray 580 121.667 10 OC 580 116.667 moveto (21) CSH 1.0 setgray 580 144.583 10 FC 0.0 setgray 580 144.583 10 OC 580 139.583 moveto (21) CSH 1.0 setgray 580 167.5 10 FC 0.0 setgray 580 167.5 10 OC 580 162.5 moveto (21) CSH 1.0 setgray 559.375 190.417 10 FC 0.0 setgray 559.375 190.417 10 OC 559.375 185.417 moveto (22) CSH 1.0 setgray 559.375 213.333 10 FC 0.0 setgray 559.375 213.333 10 OC 559.375 208.333 moveto (22) CSH 1.0 setgray 521.562 236.25 10 FC 0.0 setgray 521.562 236.25 10 OC 521.562 231.25 moveto (23) CSH 1.0 setgray 521.562 259.167 10 FC 0.0 setgray 521.562 259.167 10 OC 521.562 254.167 moveto (23) CSH 1.0 setgray 521.562 282.083 10 FC 0.0 setgray 521.562 282.083 10 OC 521.562 277.083 moveto (23) CSH 1.0 setgray 447.656 305 10 FC 0.0 setgray 447.656 305 10 OC 447.656 300 moveto (24) CSH 1.0 setgray 447.656 327.917 10 FC 0.0 setgray 447.656 327.917 10 OC 447.656 322.917 moveto (24) CSH 1.0 setgray 447.656 350.833 10 FC 0.0 setgray 447.656 350.833 10 OC 447.656 345.833 moveto (24) CSH 1.0 setgray 308.438 373.75 10 FC 0.0 setgray 308.438 373.75 10 OC 308.438 368.75 moveto (24) CSH 1.0 setgray 308.438 396.667 10 FC 0.0 setgray 308.438 396.667 10 OC 308.438 391.667 moveto (24) CSH 1.0 setgray 308.438 419.583 10 FC 0.0 setgray 308.438 419.583 10 OC 308.438 414.583 moveto (24) CSH 1.0 setgray 308.438 442.5 10 FC 0.0 setgray 308.438 442.5 10 OC 308.438 437.5 moveto (24) CSH 1.0 setgray 308.438 465.417 10 FC 0.0 setgray 308.438 465.417 10 OC 308.438 460.417 moveto (24) CSH 1.0 setgray 308.438 488.333 10 FC 0.0 setgray 308.438 488.333 10 OC 308.438 483.333 moveto (24) CSH 1.0 setgray 308.438 511.25 10 FC 0.0 setgray 308.438 511.25 10 OC 308.438 506.25 moveto (24) CSH 1.0 setgray 308.438 534.167 10 FC 0.0 setgray 308.438 534.167 10 OC 308.438 529.167 moveto (24) CSH 1.0 setgray 308.438 557.083 10 FC 0.0 setgray 308.438 557.083 10 OC 308.438 552.083 moveto (24) CSH 1.0 setgray 308.438 580 10 FC 0.0 setgray 308.438 580 10 OC 308.438 575 moveto (24) CSH grestore showpage .75 moveto (0) CSH documentation/FrontTrees/fsmtx.eps010064400020550007177000000166730663230554000207270ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.000 0.000 550.000 550.000 %%EndComments /MainFont /Helvetica findfont 8 scalefont def MainFont setfont %----------------------------------------------------------------------- % % utility procedures % %----------------------------------------------------------------------- % % procedure to produce a filled circle % /circle { % stack : x y size % % store input data % /size exch def /y exch def /x exch def gsave newpath x y moveto x size add y size 0 360 arc fill grestore } def %----------------------------------------------------------------------- % % procedure to draw the outline of the matrix % /draw_outline { % stack : xnw ynw dx dy nrow ncol /ncol exch def % number of columns /nrow exch def % number of rows /dy exch def % column spacing /dx exch def % row spacing /ynw exch def % northwest y coordinate /xnw exch def % northwest x coordinated /width ncol 1 add dx mul def /height nrow 1 add dy mul def newpath xnw dx sub ynw dy add moveto currentpoint width 0 rlineto 0 height neg rlineto width neg 0 rlineto closepath stroke } def %----------------------------------------------------------------------- % procedure to draw matrix adjacency structure % /draw_matrix { % stack : xnw ynw dx dy adjncy % % store input data % /adjncy exch def % adjacency structure /dy exch def % column spacing /dx exch def % row spacing /ynw exch def % northwest y coordinate /xnw exch def % northwest x coordinated % % loop over the columns % 0 1 adjncy length 1 sub { % % pop and store the column id and set the x coordinate % /j exch def adjncy j get /column exch def column 0 get /jcol exch def /xj xnw jcol dx mul add def % % loop over the row entries % 0 1 column length 1 sub { % % pop the row id, set the y coordinate and draw the tick % /i exch def column i get /irow exch def xj ynw irow dy mul sub 1 circle } for } for } def %----------------------------------------------------------------------- % % procedures to draw the supernode partition % /draw_sn_overlay { % stack xnw ynw dx dy nrow ncol sninfo % % store input data % /sninfo exch def % supernode information /ncol exch def % # of columns /nrow exch def % # of rows /dy exch def % column spacing /dx exch def % row spacing /ynw exch def % northwest y coordinate /xnw exch def % northwest x coordinated % % draw the left and bottom border % 0.1 dx mul setlinewidth newpath xnw dx 0.4 mul sub ynw dy 0.5 mul add moveto 0 nrow dy mul neg rlineto ncol dx mul 0 rlineto stroke % % loop over the columns % 0 1 sninfo length 1 sub { % % pop and store the column id and set the x coordinate % /J exch def sninfo J get /Jinfo exch def Jinfo 0 get /vJ exch def Jinfo 1 get /nJ exch def % % get location of first diagonal element % /xj xnw vJ dx mul add def /yj ynw vJ dx mul sub def % newpath xj dx 0.25 mul sub yj dx 0.5 mul add moveto nJ dx mul 0 rlineto 0 nJ dy mul neg rlineto nJ dx mul neg 0 rlineto nJ dx mul 0 rmoveto 0 nrow vJ nJ add sub dy mul neg rlineto stroke } for } def %----------------------------------------------------------------------- % /xnw 40 def /ynw 510 def /dx 4 def /dy 4 def % %----------------------------------------------------------------------- % % factor matrix for R2D100 % /adjncyL [ [ 0 1 2 6 7 ] [ 1 2 6 7 21 46 ] [ 2 6 7 21 44 46 ] [ 3 4 5 6 18 ] [ 4 5 6 7 18 20 ] [ 5 6 7 18 19 20 ] [ 6 7 18 19 20 21 44 46 ] [ 7 18 19 20 21 44 46 ] [ 8 11 17 91 ] [ 9 10 18 ] [ 10 11 18 19 ] [ 11 17 18 19 91 ] [ 12 13 20 21 45 ] [ 13 16 20 21 45 47 ] [ 14 15 16 17 47 99 ] [ 15 16 17 19 20 47 99 ] [ 16 17 19 20 21 45 47 99 ] [ 17 18 19 20 21 45 47 91 95 99 ] [ 18 19 20 21 44 45 46 47 91 95 99 ] [ 19 20 21 44 45 46 47 91 95 99 ] [ 20 21 44 45 46 47 91 95 99 ] [ 21 44 45 46 47 91 95 99 ] [ 22 27 41 90 ] [ 23 24 25 27 32 93 ] [ 24 25 26 27 31 32 93 ] [ 25 26 27 31 32 42 43 93 ] [ 26 27 31 32 42 43 45 46 93 ] [ 27 31 32 41 42 43 45 46 90 93 96 ] [ 28 29 30 31 45 47 ] [ 29 30 31 32 45 47 94 97 ] [ 30 31 32 45 47 92 94 97 98 ] [ 31 32 41 42 43 45 46 47 90 92 93 94 96 97 98 ] [ 32 41 42 43 45 46 47 90 92 93 94 96 97 98 ] [ 33 34 35 ] [ 34 35 36 38 ] [ 35 36 37 38 ] [ 36 37 38 39 40 ] [ 37 38 39 40 41 ] [ 38 39 40 41 44 ] [ 39 40 41 42 44 46 ] [ 40 41 42 43 44 46 ] [ 41 42 43 44 45 46 47 90 92 93 94 96 97 98 ] [ 42 43 44 45 46 47 90 92 93 94 96 97 98 ] [ 43 44 45 46 47 90 92 93 94 96 97 98 ] [ 44 45 46 47 90 91 92 93 94 95 96 97 98 99 ] [ 45 46 47 90 91 92 93 94 95 96 97 98 99 ] [ 46 47 90 91 92 93 94 95 96 97 98 99 ] [ 47 90 91 92 93 94 95 96 97 98 99 ] [ 48 49 53 ] [ 49 51 52 53 ] [ 50 51 55 69 ] [ 51 52 53 55 69 ] [ 52 53 55 69 70 ] [ 53 55 66 68 69 70 ] [ 54 55 67 69 91 95 ] [ 55 66 67 68 69 70 91 95 ] [ 56 57 58 59 87 ] [ 57 58 59 64 87 88 ] [ 58 59 64 65 87 88 ] [ 59 64 65 66 68 87 88 ] [ 60 62 63 67 69 92 99 ] [ 61 62 63 64 65 ] [ 62 63 64 65 67 69 70 92 99 ] [ 63 64 65 67 69 70 89 92 98 99 ] [ 64 65 66 67 68 69 70 87 88 89 92 98 99 ] [ 65 66 67 68 69 70 87 88 89 92 98 99 ] [ 66 67 68 69 70 87 88 89 91 92 95 98 99 ] [ 67 68 69 70 87 88 89 91 92 95 98 99 ] [ 68 69 70 87 88 89 91 92 95 98 99 ] [ 69 70 87 88 89 91 92 95 98 99 ] [ 70 87 88 89 91 92 95 98 99 ] [ 71 72 84 ] [ 72 74 84 85 ] [ 73 74 86 87 88 ] [ 74 84 85 86 87 88 ] [ 75 78 83 88 89 94 97 ] [ 76 77 78 82 83 85 ] [ 77 78 82 83 85 86 88 ] [ 78 82 83 85 86 88 89 94 97 ] [ 79 80 81 82 84 ] [ 80 81 82 84 90 96 ] [ 81 82 83 84 90 96 ] [ 82 83 84 85 86 88 89 90 94 96 97 ] [ 83 84 85 86 88 89 90 93 94 96 97 ] [ 84 85 86 87 88 89 90 93 94 96 97 ] [ 85 86 87 88 89 90 93 94 96 97 ] [ 86 87 88 89 90 93 94 96 97 ] [ 87 88 89 90 91 92 93 94 95 96 97 98 99 ] [ 88 89 90 91 92 93 94 95 96 97 98 99 ] [ 89 90 91 92 93 94 95 96 97 98 99 ] [ 90 91 92 93 94 95 96 97 98 99 ] [ 91 92 93 94 95 96 97 98 99 ] [ 92 93 94 95 96 97 98 99 ] [ 93 94 95 96 97 98 99 ] [ 94 95 96 97 98 99 ] [ 95 96 97 98 99 ] [ 96 97 98 99 ] [ 97 98 99 ] [ 98 99 ] [ 99 ] ] def /sn_info [ [ 0 1 ] [ 1 1 ] [ 2 1 ] [ 3 1 ] [ 4 1 ] [ 5 1 ] [ 6 2 ] [ 8 1 ] [ 9 1 ] [ 10 1 ] [ 11 1 ] [ 12 1 ] [ 13 1 ] [ 14 1 ] [ 15 1 ] [ 16 1 ] [ 17 1 ] [ 18 4 ] [ 22 1 ] [ 23 1 ] [ 24 1 ] [ 25 1 ] [ 26 1 ] [ 27 1 ] [ 28 1 ] [ 29 1 ] [ 30 1 ] [ 31 2 ] [ 33 1 ] [ 34 1 ] [ 35 1 ] [ 36 1 ] [ 37 1 ] [ 38 1 ] [ 39 1 ] [ 40 1 ] [ 41 3 ] [ 44 4 ] [ 48 1 ] [ 49 1 ] [ 50 1 ] [ 51 1 ] [ 52 1 ] [ 53 1 ] [ 54 1 ] [ 55 1 ] [ 56 1 ] [ 57 1 ] [ 58 1 ] [ 59 1 ] [ 60 1 ] [ 61 1 ] [ 62 1 ] [ 63 1 ] [ 64 2 ] [ 66 5 ] [ 71 1 ] [ 72 1 ] [ 73 1 ] [ 74 1 ] [ 75 1 ] [ 76 1 ] [ 77 1 ] [ 78 1 ] [ 79 1 ] [ 80 1 ] [ 81 1 ] [ 82 1 ] [ 83 1 ] [ 84 3 ] [ 87 3 ] [ 90 10 ] ] def %----------------------------------------------------------------------- /nrow 100 def /ncol 100 def /row_ids [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48] def %----------------------------------------------------------------------- % % draw outline and gridlines % xnw ynw dx dy nrow ncol draw_outline xnw ynw dx dy adjncyL draw_matrix xnw ynw dx dy nrow ncol sn_info draw_sn_overlay documentation/FrontTrees/fstree.eps010064400020550007177000000230610663232311600210420ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 565 315 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 525 275 rectstroke newpath 30 128 30 152.5 ML 30 152.5 30 177 ML 30 177 42.375 201.5 ML 54.75 128 54.75 152.5 ML 54.75 152.5 54.75 177 ML 54.75 177 42.375 201.5 ML 42.375 201.5 79.5 226 ML 79.5 152.5 91.875 177 ML 104.25 128 104.25 152.5 ML 104.25 152.5 91.875 177 ML 91.875 177 116.625 201.5 ML 129 128 129 152.5 ML 129 152.5 141.375 177 ML 153.75 128 153.75 152.5 ML 153.75 152.5 141.375 177 ML 141.375 177 116.625 201.5 ML 116.625 201.5 79.5 226 ML 79.5 226 155.297 250.5 ML 178.5 152.5 190.875 177 ML 203.25 79 203.25 103.5 ML 203.25 103.5 203.25 128 ML 203.25 128 203.25 152.5 ML 203.25 152.5 190.875 177 ML 190.875 177 209.438 201.5 ML 228 128 228 152.5 ML 228 152.5 228 177 ML 228 177 209.438 201.5 ML 209.438 201.5 231.094 226 ML 252.75 30 252.75 54.5 ML 252.75 54.5 252.75 79 ML 252.75 79 252.75 103.5 ML 252.75 103.5 252.75 128 ML 252.75 128 252.75 152.5 ML 252.75 152.5 252.75 177 ML 252.75 177 252.75 201.5 ML 252.75 201.5 231.094 226 ML 231.094 226 155.297 250.5 ML 155.297 250.5 280.594 275 ML 277.5 79 277.5 103.5 ML 277.5 103.5 289.875 128 ML 302.25 103.5 289.875 128 ML 289.875 128 289.875 152.5 ML 289.875 152.5 289.875 177 ML 289.875 177 308.438 201.5 ML 327 177 308.438 201.5 ML 308.438 201.5 339.375 226 ML 351.75 103.5 351.75 128 ML 351.75 128 351.75 152.5 ML 351.75 152.5 351.75 177 ML 351.75 177 370.312 201.5 ML 376.5 128 388.875 152.5 ML 401.25 128 388.875 152.5 ML 388.875 152.5 388.875 177 ML 388.875 177 370.312 201.5 ML 370.312 201.5 339.375 226 ML 339.375 226 405.891 250.5 ML 426 152.5 426 177 ML 426 177 438.375 201.5 ML 450.75 177 438.375 201.5 ML 438.375 201.5 472.406 226 ML 475.5 128 487.875 152.5 ML 500.25 103.5 500.25 128 ML 500.25 128 487.875 152.5 ML 487.875 152.5 506.438 177 ML 525 103.5 525 128 ML 525 128 525 152.5 ML 525 152.5 506.438 177 ML 506.438 177 506.438 201.5 ML 506.438 201.5 472.406 226 ML 472.406 226 405.891 250.5 ML 405.891 250.5 280.594 275 ML stroke gsave /Helvetica-Bold findfont 15 scalefont setfont 1.0 setgray 30 128 10 FC 0.0 setgray 30 128 10 OC 30 123 moveto (0) CSH 1.0 setgray 30 152.5 10 FC 0.0 setgray 30 152.5 10 OC 30 147.5 moveto (1) CSH 1.0 setgray 30 177 10 FC 0.0 setgray 30 177 10 OC 30 172 moveto (2) CSH 1.0 setgray 54.75 128 10 FC 0.0 setgray 54.75 128 10 OC 54.75 123 moveto (3) CSH 1.0 setgray 54.75 152.5 10 FC 0.0 setgray 54.75 152.5 10 OC 54.75 147.5 moveto (4) CSH 1.0 setgray 54.75 177 10 FC 0.0 setgray 54.75 177 10 OC 54.75 172 moveto (5) CSH 1.0 setgray 42.375 201.5 10 FC 0.0 setgray 42.375 201.5 10 OC 42.375 196.5 moveto (6) CSH 1.0 setgray 79.5 152.5 10 FC 0.0 setgray 79.5 152.5 10 OC 79.5 147.5 moveto (7) CSH 1.0 setgray 104.25 128 10 FC 0.0 setgray 104.25 128 10 OC 104.25 123 moveto (8) CSH 1.0 setgray 104.25 152.5 10 FC 0.0 setgray 104.25 152.5 10 OC 104.25 147.5 moveto (9) CSH 1.0 setgray 91.875 177 10 FC 0.0 setgray 91.875 177 10 OC 91.875 172 moveto (10) CSH 1.0 setgray 129 128 10 FC 0.0 setgray 129 128 10 OC 129 123 moveto (11) CSH 1.0 setgray 129 152.5 10 FC 0.0 setgray 129 152.5 10 OC 129 147.5 moveto (12) CSH 1.0 setgray 153.75 128 10 FC 0.0 setgray 153.75 128 10 OC 153.75 123 moveto (13) CSH 1.0 setgray 153.75 152.5 10 FC 0.0 setgray 153.75 152.5 10 OC 153.75 147.5 moveto (14) CSH 1.0 setgray 141.375 177 10 FC 0.0 setgray 141.375 177 10 OC 141.375 172 moveto (15) CSH 1.0 setgray 116.625 201.5 10 FC 0.0 setgray 116.625 201.5 10 OC 116.625 196.5 moveto (16) CSH 1.0 setgray 79.5 226 10 FC 0.0 setgray 79.5 226 10 OC 79.5 221 moveto (17) CSH 1.0 setgray 178.5 152.5 10 FC 0.0 setgray 178.5 152.5 10 OC 178.5 147.5 moveto (18) CSH 1.0 setgray 203.25 79 10 FC 0.0 setgray 203.25 79 10 OC 203.25 74 moveto (19) CSH 1.0 setgray 203.25 103.5 10 FC 0.0 setgray 203.25 103.5 10 OC 203.25 98.5 moveto (20) CSH 1.0 setgray 203.25 128 10 FC 0.0 setgray 203.25 128 10 OC 203.25 123 moveto (21) CSH 1.0 setgray 203.25 152.5 10 FC 0.0 setgray 203.25 152.5 10 OC 203.25 147.5 moveto (22) CSH 1.0 setgray 190.875 177 10 FC 0.0 setgray 190.875 177 10 OC 190.875 172 moveto (23) CSH 1.0 setgray 228 128 10 FC 0.0 setgray 228 128 10 OC 228 123 moveto (24) CSH 1.0 setgray 228 152.5 10 FC 0.0 setgray 228 152.5 10 OC 228 147.5 moveto (25) CSH 1.0 setgray 228 177 10 FC 0.0 setgray 228 177 10 OC 228 172 moveto (26) CSH 1.0 setgray 209.438 201.5 10 FC 0.0 setgray 209.438 201.5 10 OC 209.438 196.5 moveto (27) CSH 1.0 setgray 252.75 30 10 FC 0.0 setgray 252.75 30 10 OC 252.75 25 moveto (28) CSH 1.0 setgray 252.75 54.5 10 FC 0.0 setgray 252.75 54.5 10 OC 252.75 49.5 moveto (29) CSH 1.0 setgray 252.75 79 10 FC 0.0 setgray 252.75 79 10 OC 252.75 74 moveto (30) CSH 1.0 setgray 252.75 103.5 10 FC 0.0 setgray 252.75 103.5 10 OC 252.75 98.5 moveto (31) CSH 1.0 setgray 252.75 128 10 FC 0.0 setgray 252.75 128 10 OC 252.75 123 moveto (32) CSH 1.0 setgray 252.75 152.5 10 FC 0.0 setgray 252.75 152.5 10 OC 252.75 147.5 moveto (33) CSH 1.0 setgray 252.75 177 10 FC 0.0 setgray 252.75 177 10 OC 252.75 172 moveto (34) CSH 1.0 setgray 252.75 201.5 10 FC 0.0 setgray 252.75 201.5 10 OC 252.75 196.5 moveto (35) CSH 1.0 setgray 231.094 226 10 FC 0.0 setgray 231.094 226 10 OC 231.094 221 moveto (36) CSH 1.0 setgray 155.297 250.5 10 FC 0.0 setgray 155.297 250.5 10 OC 155.297 245.5 moveto (37) CSH 1.0 setgray 277.5 79 10 FC 0.0 setgray 277.5 79 10 OC 277.5 74 moveto (38) CSH 1.0 setgray 277.5 103.5 10 FC 0.0 setgray 277.5 103.5 10 OC 277.5 98.5 moveto (39) CSH 1.0 setgray 302.25 103.5 10 FC 0.0 setgray 302.25 103.5 10 OC 302.25 98.5 moveto (40) CSH 1.0 setgray 289.875 128 10 FC 0.0 setgray 289.875 128 10 OC 289.875 123 moveto (41) CSH 1.0 setgray 289.875 152.5 10 FC 0.0 setgray 289.875 152.5 10 OC 289.875 147.5 moveto (42) CSH 1.0 setgray 289.875 177 10 FC 0.0 setgray 289.875 177 10 OC 289.875 172 moveto (43) CSH 1.0 setgray 327 177 10 FC 0.0 setgray 327 177 10 OC 327 172 moveto (44) CSH 1.0 setgray 308.438 201.5 10 FC 0.0 setgray 308.438 201.5 10 OC 308.438 196.5 moveto (45) CSH 1.0 setgray 351.75 103.5 10 FC 0.0 setgray 351.75 103.5 10 OC 351.75 98.5 moveto (46) CSH 1.0 setgray 351.75 128 10 FC 0.0 setgray 351.75 128 10 OC 351.75 123 moveto (47) CSH 1.0 setgray 351.75 152.5 10 FC 0.0 setgray 351.75 152.5 10 OC 351.75 147.5 moveto (48) CSH 1.0 setgray 351.75 177 10 FC 0.0 setgray 351.75 177 10 OC 351.75 172 moveto (49) CSH 1.0 setgray 376.5 128 10 FC 0.0 setgray 376.5 128 10 OC 376.5 123 moveto (50) CSH 1.0 setgray 401.25 128 10 FC 0.0 setgray 401.25 128 10 OC 401.25 123 moveto (51) CSH 1.0 setgray 388.875 152.5 10 FC 0.0 setgray 388.875 152.5 10 OC 388.875 147.5 moveto (52) CSH 1.0 setgray 388.875 177 10 FC 0.0 setgray 388.875 177 10 OC 388.875 172 moveto (53) CSH 1.0 setgray 370.312 201.5 10 FC 0.0 setgray 370.312 201.5 10 OC 370.312 196.5 moveto (54) CSH 1.0 setgray 339.375 226 10 FC 0.0 setgray 339.375 226 10 OC 339.375 221 moveto (55) CSH 1.0 setgray 426 152.5 10 FC 0.0 setgray 426 152.5 10 OC 426 147.5 moveto (56) CSH 1.0 setgray 426 177 10 FC 0.0 setgray 426 177 10 OC 426 172 moveto (57) CSH 1.0 setgray 450.75 177 10 FC 0.0 setgray 450.75 177 10 OC 450.75 172 moveto (58) CSH 1.0 setgray 438.375 201.5 10 FC 0.0 setgray 438.375 201.5 10 OC 438.375 196.5 moveto (59) CSH 1.0 setgray 475.5 128 10 FC 0.0 setgray 475.5 128 10 OC 475.5 123 moveto (60) CSH 1.0 setgray 500.25 103.5 10 FC 0.0 setgray 500.25 103.5 10 OC 500.25 98.5 moveto (61) CSH 1.0 setgray 500.25 128 10 FC 0.0 setgray 500.25 128 10 OC 500.25 123 moveto (62) CSH 1.0 setgray 487.875 152.5 10 FC 0.0 setgray 487.875 152.5 10 OC 487.875 147.5 moveto (63) CSH 1.0 setgray 525 103.5 10 FC 0.0 setgray 525 103.5 10 OC 525 98.5 moveto (64) CSH 1.0 setgray 525 128 10 FC 0.0 setgray 525 128 10 OC 525 123 moveto (65) CSH 1.0 setgray 525 152.5 10 FC 0.0 setgray 525 152.5 10 OC 525 147.5 moveto (66) CSH 1.0 setgray 506.438 177 10 FC 0.0 setgray 506.438 177 10 OC 506.438 172 moveto (67) CSH 1.0 setgray 506.438 201.5 10 FC 0.0 setgray 506.438 201.5 10 OC 506.438 196.5 moveto (68) CSH 1.0 setgray 472.406 226 10 FC 0.0 setgray 472.406 226 10 OC 472.406 221 moveto (69) CSH 1.0 setgray 405.891 250.5 10 FC 0.0 setgray 405.891 250.5 10 OC 405.891 245.5 moveto (70) CSH 1.0 setgray 280.594 275 10 FC 0.0 setgray 280.594 275 10 OC 280.594 270 moveto (71) CSH grestore showpage documentation/FrontTrees/fsvtree.eps010064400020550007177000000340020663232312100212210ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 600 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 580 580 rectstroke newpath 30 75.833 30 98.75 ML 30 98.75 30 121.667 ML 30 121.667 43.75 144.583 ML 57.5 75.833 57.5 98.75 ML 57.5 98.75 57.5 121.667 ML 57.5 121.667 43.75 144.583 ML 43.75 144.583 43.75 167.5 ML 43.75 167.5 85 190.417 ML 85 121.667 98.75 144.583 ML 112.5 98.75 112.5 121.667 ML 112.5 121.667 98.75 144.583 ML 98.75 144.583 126.25 167.5 ML 140 98.75 140 121.667 ML 140 121.667 153.75 144.583 ML 167.5 98.75 167.5 121.667 ML 167.5 121.667 153.75 144.583 ML 153.75 144.583 126.25 167.5 ML 126.25 167.5 85 190.417 ML 85 190.417 85 213.333 ML 85 213.333 85 236.25 ML 85 236.25 85 259.167 ML 85 259.167 169.219 282.083 ML 195 121.667 208.75 144.583 ML 222.5 52.917 222.5 75.833 ML 222.5 75.833 222.5 98.75 ML 222.5 98.75 222.5 121.667 ML 222.5 121.667 208.75 144.583 ML 208.75 144.583 229.375 167.5 ML 250 98.75 250 121.667 ML 250 121.667 250 144.583 ML 250 144.583 229.375 167.5 ML 229.375 167.5 229.375 190.417 ML 229.375 190.417 253.438 213.333 ML 277.5 30 277.5 52.917 ML 277.5 52.917 277.5 75.833 ML 277.5 75.833 277.5 98.75 ML 277.5 98.75 277.5 121.667 ML 277.5 121.667 277.5 144.583 ML 277.5 144.583 277.5 167.5 ML 277.5 167.5 277.5 190.417 ML 277.5 190.417 253.438 213.333 ML 253.438 213.333 253.438 236.25 ML 253.438 236.25 253.438 259.167 ML 253.438 259.167 169.219 282.083 ML 169.219 282.083 169.219 305 ML 169.219 305 169.219 327.917 ML 169.219 327.917 169.219 350.833 ML 169.219 350.833 308.438 373.75 ML 305 52.917 305 75.833 ML 305 75.833 318.75 98.75 ML 332.5 75.833 318.75 98.75 ML 318.75 98.75 318.75 121.667 ML 318.75 121.667 318.75 144.583 ML 318.75 144.583 339.375 167.5 ML 360 144.583 339.375 167.5 ML 339.375 167.5 373.75 190.417 ML 387.5 52.917 387.5 75.833 ML 387.5 75.833 387.5 98.75 ML 387.5 98.75 387.5 121.667 ML 387.5 121.667 408.125 144.583 ML 415 75.833 428.75 98.75 ML 442.5 75.833 428.75 98.75 ML 428.75 98.75 428.75 121.667 ML 428.75 121.667 408.125 144.583 ML 408.125 144.583 408.125 167.5 ML 408.125 167.5 373.75 190.417 ML 373.75 190.417 373.75 213.333 ML 373.75 213.333 373.75 236.25 ML 373.75 236.25 373.75 259.167 ML 373.75 259.167 373.75 282.083 ML 373.75 282.083 447.656 305 ML 470 167.5 470 190.417 ML 470 190.417 483.75 213.333 ML 497.5 190.417 483.75 213.333 ML 483.75 213.333 521.562 236.25 ML 525 144.583 538.75 167.5 ML 552.5 121.667 552.5 144.583 ML 552.5 144.583 538.75 167.5 ML 538.75 167.5 559.375 190.417 ML 580 121.667 580 144.583 ML 580 144.583 580 167.5 ML 580 167.5 559.375 190.417 ML 559.375 190.417 559.375 213.333 ML 559.375 213.333 521.562 236.25 ML 521.562 236.25 521.562 259.167 ML 521.562 259.167 521.562 282.083 ML 521.562 282.083 447.656 305 ML 447.656 305 447.656 327.917 ML 447.656 327.917 447.656 350.833 ML 447.656 350.833 308.438 373.75 ML 308.438 373.75 308.438 396.667 ML 308.438 396.667 308.438 419.583 ML 308.438 419.583 308.438 442.5 ML 308.438 442.5 308.438 465.417 ML 308.438 465.417 308.438 488.333 ML 308.438 488.333 308.438 511.25 ML 308.438 511.25 308.438 534.167 ML 308.438 534.167 308.438 557.083 ML 308.438 557.083 308.438 580 ML stroke gsave /Helvetica-Bold findfont 15 scalefont setfont 1.0 setgray 30 75.833 10 FC 0.0 setgray 30 75.833 10 OC 30 70.833 moveto (0) CSH 1.0 setgray 30 98.75 10 FC 0.0 setgray 30 98.75 10 OC 30 93.75 moveto (1) CSH 1.0 setgray 30 121.667 10 FC 0.0 setgray 30 121.667 10 OC 30 116.667 moveto (2) CSH 1.0 setgray 57.5 75.833 10 FC 0.0 setgray 57.5 75.833 10 OC 57.5 70.833 moveto (3) CSH 1.0 setgray 57.5 98.75 10 FC 0.0 setgray 57.5 98.75 10 OC 57.5 93.75 moveto (4) CSH 1.0 setgray 57.5 121.667 10 FC 0.0 setgray 57.5 121.667 10 OC 57.5 116.667 moveto (5) CSH 1.0 setgray 43.75 144.583 10 FC 0.0 setgray 43.75 144.583 10 OC 43.75 139.583 moveto (6) CSH 1.0 setgray 43.75 167.5 10 FC 0.0 setgray 43.75 167.5 10 OC 43.75 162.5 moveto (6) CSH 1.0 setgray 85 121.667 10 FC 0.0 setgray 85 121.667 10 OC 85 116.667 moveto (7) CSH 1.0 setgray 112.5 98.75 10 FC 0.0 setgray 112.5 98.75 10 OC 112.5 93.75 moveto (8) CSH 1.0 setgray 112.5 121.667 10 FC 0.0 setgray 112.5 121.667 10 OC 112.5 116.667 moveto (9) CSH 1.0 setgray 98.75 144.583 10 FC 0.0 setgray 98.75 144.583 10 OC 98.75 139.583 moveto (10) CSH 1.0 setgray 140 98.75 10 FC 0.0 setgray 140 98.75 10 OC 140 93.75 moveto (11) CSH 1.0 setgray 140 121.667 10 FC 0.0 setgray 140 121.667 10 OC 140 116.667 moveto (12) CSH 1.0 setgray 167.5 98.75 10 FC 0.0 setgray 167.5 98.75 10 OC 167.5 93.75 moveto (13) CSH 1.0 setgray 167.5 121.667 10 FC 0.0 setgray 167.5 121.667 10 OC 167.5 116.667 moveto (14) CSH 1.0 setgray 153.75 144.583 10 FC 0.0 setgray 153.75 144.583 10 OC 153.75 139.583 moveto (15) CSH 1.0 setgray 126.25 167.5 10 FC 0.0 setgray 126.25 167.5 10 OC 126.25 162.5 moveto (16) CSH 1.0 setgray 85 190.417 10 FC 0.0 setgray 85 190.417 10 OC 85 185.417 moveto (17) CSH 1.0 setgray 85 213.333 10 FC 0.0 setgray 85 213.333 10 OC 85 208.333 moveto (17) CSH 1.0 setgray 85 236.25 10 FC 0.0 setgray 85 236.25 10 OC 85 231.25 moveto (17) CSH 1.0 setgray 85 259.167 10 FC 0.0 setgray 85 259.167 10 OC 85 254.167 moveto (17) CSH 1.0 setgray 195 121.667 10 FC 0.0 setgray 195 121.667 10 OC 195 116.667 moveto (18) CSH 1.0 setgray 222.5 52.917 10 FC 0.0 setgray 222.5 52.917 10 OC 222.5 47.917 moveto (19) CSH 1.0 setgray 222.5 75.833 10 FC 0.0 setgray 222.5 75.833 10 OC 222.5 70.833 moveto (20) CSH 1.0 setgray 222.5 98.75 10 FC 0.0 setgray 222.5 98.75 10 OC 222.5 93.75 moveto (21) CSH 1.0 setgray 222.5 121.667 10 FC 0.0 setgray 222.5 121.667 10 OC 222.5 116.667 moveto (22) CSH 1.0 setgray 208.75 144.583 10 FC 0.0 setgray 208.75 144.583 10 OC 208.75 139.583 moveto (23) CSH 1.0 setgray 250 98.75 10 FC 0.0 setgray 250 98.75 10 OC 250 93.75 moveto (24) CSH 1.0 setgray 250 121.667 10 FC 0.0 setgray 250 121.667 10 OC 250 116.667 moveto (25) CSH 1.0 setgray 250 144.583 10 FC 0.0 setgray 250 144.583 10 OC 250 139.583 moveto (26) CSH 1.0 setgray 229.375 167.5 10 FC 0.0 setgray 229.375 167.5 10 OC 229.375 162.5 moveto (27) CSH 1.0 setgray 229.375 190.417 10 FC 0.0 setgray 229.375 190.417 10 OC 229.375 185.417 moveto (27) CSH 1.0 setgray 277.5 30 10 FC 0.0 setgray 277.5 30 10 OC 277.5 25 moveto (28) CSH 1.0 setgray 277.5 52.917 10 FC 0.0 setgray 277.5 52.917 10 OC 277.5 47.917 moveto (29) CSH 1.0 setgray 277.5 75.833 10 FC 0.0 setgray 277.5 75.833 10 OC 277.5 70.833 moveto (30) CSH 1.0 setgray 277.5 98.75 10 FC 0.0 setgray 277.5 98.75 10 OC 277.5 93.75 moveto (31) CSH 1.0 setgray 277.5 121.667 10 FC 0.0 setgray 277.5 121.667 10 OC 277.5 116.667 moveto (32) CSH 1.0 setgray 277.5 144.583 10 FC 0.0 setgray 277.5 144.583 10 OC 277.5 139.583 moveto (33) CSH 1.0 setgray 277.5 167.5 10 FC 0.0 setgray 277.5 167.5 10 OC 277.5 162.5 moveto (34) CSH 1.0 setgray 277.5 190.417 10 FC 0.0 setgray 277.5 190.417 10 OC 277.5 185.417 moveto (35) CSH 1.0 setgray 253.438 213.333 10 FC 0.0 setgray 253.438 213.333 10 OC 253.438 208.333 moveto (36) CSH 1.0 setgray 253.438 236.25 10 FC 0.0 setgray 253.438 236.25 10 OC 253.438 231.25 moveto (36) CSH 1.0 setgray 253.438 259.167 10 FC 0.0 setgray 253.438 259.167 10 OC 253.438 254.167 moveto (36) CSH 1.0 setgray 169.219 282.083 10 FC 0.0 setgray 169.219 282.083 10 OC 169.219 277.083 moveto (37) CSH 1.0 setgray 169.219 305 10 FC 0.0 setgray 169.219 305 10 OC 169.219 300 moveto (37) CSH 1.0 setgray 169.219 327.917 10 FC 0.0 setgray 169.219 327.917 10 OC 169.219 322.917 moveto (37) CSH 1.0 setgray 169.219 350.833 10 FC 0.0 setgray 169.219 350.833 10 OC 169.219 345.833 moveto (37) CSH 1.0 setgray 305 52.917 10 FC 0.0 setgray 305 52.917 10 OC 305 47.917 moveto (38) CSH 1.0 setgray 305 75.833 10 FC 0.0 setgray 305 75.833 10 OC 305 70.833 moveto (39) CSH 1.0 setgray 332.5 75.833 10 FC 0.0 setgray 332.5 75.833 10 OC 332.5 70.833 moveto (40) CSH 1.0 setgray 318.75 98.75 10 FC 0.0 setgray 318.75 98.75 10 OC 318.75 93.75 moveto (41) CSH 1.0 setgray 318.75 121.667 10 FC 0.0 setgray 318.75 121.667 10 OC 318.75 116.667 moveto (42) CSH 1.0 setgray 318.75 144.583 10 FC 0.0 setgray 318.75 144.583 10 OC 318.75 139.583 moveto (43) CSH 1.0 setgray 360 144.583 10 FC 0.0 setgray 360 144.583 10 OC 360 139.583 moveto (44) CSH 1.0 setgray 339.375 167.5 10 FC 0.0 setgray 339.375 167.5 10 OC 339.375 162.5 moveto (45) CSH 1.0 setgray 387.5 52.917 10 FC 0.0 setgray 387.5 52.917 10 OC 387.5 47.917 moveto (46) CSH 1.0 setgray 387.5 75.833 10 FC 0.0 setgray 387.5 75.833 10 OC 387.5 70.833 moveto (47) CSH 1.0 setgray 387.5 98.75 10 FC 0.0 setgray 387.5 98.75 10 OC 387.5 93.75 moveto (48) CSH 1.0 setgray 387.5 121.667 10 FC 0.0 setgray 387.5 121.667 10 OC 387.5 116.667 moveto (49) CSH 1.0 setgray 415 75.833 10 FC 0.0 setgray 415 75.833 10 OC 415 70.833 moveto (50) CSH 1.0 setgray 442.5 75.833 10 FC 0.0 setgray 442.5 75.833 10 OC 442.5 70.833 moveto (51) CSH 1.0 setgray 428.75 98.75 10 FC 0.0 setgray 428.75 98.75 10 OC 428.75 93.75 moveto (52) CSH 1.0 setgray 428.75 121.667 10 FC 0.0 setgray 428.75 121.667 10 OC 428.75 116.667 moveto (53) CSH 1.0 setgray 408.125 144.583 10 FC 0.0 setgray 408.125 144.583 10 OC 408.125 139.583 moveto (54) CSH 1.0 setgray 408.125 167.5 10 FC 0.0 setgray 408.125 167.5 10 OC 408.125 162.5 moveto (54) CSH 1.0 setgray 373.75 190.417 10 FC 0.0 setgray 373.75 190.417 10 OC 373.75 185.417 moveto (55) CSH 1.0 setgray 373.75 213.333 10 FC 0.0 setgray 373.75 213.333 10 OC 373.75 208.333 moveto (55) CSH 1.0 setgray 373.75 236.25 10 FC 0.0 setgray 373.75 236.25 10 OC 373.75 231.25 moveto (55) CSH 1.0 setgray 373.75 259.167 10 FC 0.0 setgray 373.75 259.167 10 OC 373.75 254.167 moveto (55) CSH 1.0 setgray 373.75 282.083 10 FC 0.0 setgray 373.75 282.083 10 OC 373.75 277.083 moveto (55) CSH 1.0 setgray 470 167.5 10 FC 0.0 setgray 470 167.5 10 OC 470 162.5 moveto (56) CSH 1.0 setgray 470 190.417 10 FC 0.0 setgray 470 190.417 10 OC 470 185.417 moveto (57) CSH 1.0 setgray 497.5 190.417 10 FC 0.0 setgray 497.5 190.417 10 OC 497.5 185.417 moveto (58) CSH 1.0 setgray 483.75 213.333 10 FC 0.0 setgray 483.75 213.333 10 OC 483.75 208.333 moveto (59) CSH 1.0 setgray 525 144.583 10 FC 0.0 setgray 525 144.583 10 OC 525 139.583 moveto (60) CSH 1.0 setgray 552.5 121.667 10 FC 0.0 setgray 552.5 121.667 10 OC 552.5 116.667 moveto (61) CSH 1.0 setgray 552.5 144.583 10 FC 0.0 setgray 552.5 144.583 10 OC 552.5 139.583 moveto (62) CSH 1.0 setgray 538.75 167.5 10 FC 0.0 setgray 538.75 167.5 10 OC 538.75 162.5 moveto (63) CSH 1.0 setgray 580 121.667 10 FC 0.0 setgray 580 121.667 10 OC 580 116.667 moveto (64) CSH 1.0 setgray 580 144.583 10 FC 0.0 setgray 580 144.583 10 OC 580 139.583 moveto (65) CSH 1.0 setgray 580 167.5 10 FC 0.0 setgray 580 167.5 10 OC 580 162.5 moveto (66) CSH 1.0 setgray 559.375 190.417 10 FC 0.0 setgray 559.375 190.417 10 OC 559.375 185.417 moveto (67) CSH 1.0 setgray 559.375 213.333 10 FC 0.0 setgray 559.375 213.333 10 OC 559.375 208.333 moveto (68) CSH 1.0 setgray 521.562 236.25 10 FC 0.0 setgray 521.562 236.25 10 OC 521.562 231.25 moveto (69) CSH 1.0 setgray 521.562 259.167 10 FC 0.0 setgray 521.562 259.167 10 OC 521.562 254.167 moveto (69) CSH 1.0 setgray 521.562 282.083 10 FC 0.0 setgray 521.562 282.083 10 OC 521.562 277.083 moveto (69) CSH 1.0 setgray 447.656 305 10 FC 0.0 setgray 447.656 305 10 OC 447.656 300 moveto (70) CSH 1.0 setgray 447.656 327.917 10 FC 0.0 setgray 447.656 327.917 10 OC 447.656 322.917 moveto (70) CSH 1.0 setgray 447.656 350.833 10 FC 0.0 setgray 447.656 350.833 10 OC 447.656 345.833 moveto (70) CSH 1.0 setgray 308.438 373.75 10 FC 0.0 setgray 308.438 373.75 10 OC 308.438 368.75 moveto (71) CSH 1.0 setgray 308.438 396.667 10 FC 0.0 setgray 308.438 396.667 10 OC 308.438 391.667 moveto (71) CSH 1.0 setgray 308.438 419.583 10 FC 0.0 setgray 308.438 419.583 10 OC 308.438 414.583 moveto (71) CSH 1.0 setgray 308.438 442.5 10 FC 0.0 setgray 308.438 442.5 10 OC 308.438 437.5 moveto (71) CSH 1.0 setgray 308.438 465.417 10 FC 0.0 setgray 308.438 465.417 10 OC 308.438 460.417 moveto (71) CSH 1.0 setgray 308.438 488.333 10 FC 0.0 setgray 308.438 488.333 10 OC 308.438 483.333 moveto (71) CSH 1.0 setgray 308.438 511.25 10 FC 0.0 setgray 308.438 511.25 10 OC 308.438 506.25 moveto (71) CSH 1.0 setgray 308.438 534.167 10 FC 0.0 setgray 308.438 534.167 10 OC 308.438 529.167 moveto (71) CSH 1.0 setgray 308.438 557.083 10 FC 0.0 setgray 308.438 557.083 10 OC 308.438 552.083 moveto (71) CSH 1.0 setgray 308.438 580 10 FC 0.0 setgray 308.438 580 10 OC 308.438 575 moveto (71) CSH grestore showpage 1.0 setgray 30 121.667 10 FC 0.0 setgray 30 121.667 10 OC 30 116.667 moveto (2) CSH 1.0 setgray 57.5 75.833 10 FC 0.0 setgray 57.5 75.833 10 OC 57.5 70.833 moveto (3) CSH 1.0 setgray 57.5 98.75 10 FC 0.0 setgray 57.5 98.75 10 OC 57.5 93.75 moveto (4) CSH 1.0 setgray 57.5 121.667 10 FC 0.0 setgray 57.5 121.667 10 OC 57.5 116.667 moveto (5) CSH 1.0 setgray 43.75 144.583 10 FC 0.0 setgray 43.75 144.583 10 OC 43.75 139.583 moveto (6) CSH 1.0 setgradocumentation/FrontTrees/spmtx.eps010064400020550007177000000160610663230747500207410ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.000 0.000 550.000 550.000 %%EndComments /MainFont /Helvetica findfont 8 scalefont def MainFont setfont %----------------------------------------------------------------------- % % utility procedures % %----------------------------------------------------------------------- % % procedure to produce a filled circle % /circle { % stack : x y size % % store input data % /size exch def /y exch def /x exch def gsave newpath x y moveto x size add y size 0 360 arc fill grestore } def %----------------------------------------------------------------------- % % procedure to draw the outline of the matrix % /draw_outline { % stack : xnw ynw dx dy nrow ncol /ncol exch def % number of columns /nrow exch def % number of rows /dy exch def % column spacing /dx exch def % row spacing /ynw exch def % northwest y coordinate /xnw exch def % northwest x coordinated /width ncol 1 add dx mul def /height nrow 1 add dy mul def newpath xnw dx sub ynw dy add moveto currentpoint width 0 rlineto 0 height neg rlineto width neg 0 rlineto closepath stroke } def %----------------------------------------------------------------------- % procedure to draw matrix adjacency structure % /draw_matrix { % stack : xnw ynw dx dy adjncy % % store input data % /adjncy exch def % adjacency structure /dy exch def % column spacing /dx exch def % row spacing /ynw exch def % northwest y coordinate /xnw exch def % northwest x coordinated % % loop over the columns % 0 1 adjncy length 1 sub { % % pop and store the column id and set the x coordinate % /j exch def adjncy j get /column exch def column 0 get /jcol exch def /xj xnw jcol dx mul add def % % loop over the row entries % 0 1 column length 1 sub { % % pop the row id, set the y coordinate and draw the tick % /i exch def column i get /irow exch def xj ynw irow dy mul sub 1 circle } for } for } def %----------------------------------------------------------------------- % % procedures to draw the supernode partition % /draw_sn_overlay { % stack xnw ynw dx dy nrow ncol sninfo % % store input data % /sninfo exch def % supernode information /ncol exch def % # of columns /nrow exch def % # of rows /dy exch def % column spacing /dx exch def % row spacing /ynw exch def % northwest y coordinate /xnw exch def % northwest x coordinated % % draw the left and bottom border % 0.1 dx mul setlinewidth newpath xnw dx 0.4 mul sub ynw dy 0.5 mul add moveto 0 nrow dy mul neg rlineto ncol dx mul 0 rlineto stroke % % loop over the columns % 0 1 sninfo length 1 sub { % % pop and store the column id and set the x coordinate % /J exch def sninfo J get /Jinfo exch def Jinfo 0 get /vJ exch def Jinfo 1 get /nJ exch def % % get location of first diagonal element % /xj xnw vJ dx mul add def /yj ynw vJ dx mul sub def % newpath xj dx 0.25 mul sub yj dx 0.5 mul add moveto nJ dx mul 0 rlineto 0 nJ dy mul neg rlineto nJ dx mul neg 0 rlineto nJ dx mul 0 rmoveto 0 nrow vJ nJ add sub dy mul neg rlineto stroke } for } def %----------------------------------------------------------------------- % /xnw 40 def /ynw 510 def /dx 4 def /dy 4 def % %----------------------------------------------------------------------- % % factor matrix for R2D100 % /adjncyL [ [ 0 1 2 19 20 ] [ 1 2 18 19 20 96 ] [ 2 18 19 20 96 99 ] [ 3 4 5 15 19 ] [ 4 5 15 17 19 20 ] [ 5 15 16 17 19 20 ] [ 6 9 21 94 ] [ 7 8 15 ] [ 8 9 15 16 ] [ 9 15 16 21 94 ] [ 10 11 17 18 95 ] [ 11 14 17 18 95 97 ] [ 12 13 14 21 86 97 ] [ 13 14 16 17 21 86 97 ] [ 14 16 17 18 21 86 95 97 ] [ 15 16 17 18 19 20 21 86 90 94 95 96 97 99 ] [ 16 17 18 19 20 21 86 90 94 95 96 97 99 ] [ 17 18 19 20 21 86 90 94 95 96 97 99 ] [ 18 19 20 21 86 90 94 95 96 97 99 ] [ 19 20 96 99 ] [ 20 96 99 ] [ 21 86 90 94 95 97 ] [ 22 27 41 93 ] [ 23 24 25 27 32 88 ] [ 24 25 26 27 31 32 88 ] [ 25 26 27 31 32 42 43 88 ] [ 26 27 31 32 42 43 88 95 96 ] [ 27 31 32 41 42 43 83 88 93 95 96 ] [ 28 29 30 31 95 97 ] [ 29 30 31 32 84 89 95 97 ] [ 30 31 32 84 85 87 89 95 97 ] [ 31 32 41 42 43 83 84 85 87 88 89 93 95 96 97 ] [ 32 41 42 43 83 84 85 87 88 89 93 95 96 97 ] [ 33 34 35 ] [ 34 35 36 38 ] [ 35 36 37 38 ] [ 36 37 38 39 40 ] [ 37 38 39 40 41 ] [ 38 39 40 41 99 ] [ 39 40 41 42 96 99 ] [ 40 41 42 43 96 99 ] [ 41 42 43 83 84 85 87 88 89 93 95 96 97 99 ] [ 42 43 83 84 85 87 88 89 93 95 96 97 99 ] [ 43 83 84 85 87 88 89 93 95 96 97 99 ] [ 44 45 49 ] [ 45 47 48 49 ] [ 46 47 51 63 ] [ 47 48 49 51 63 ] [ 48 49 51 63 64 ] [ 49 51 62 63 64 65 ] [ 50 51 63 66 90 94 ] [ 51 62 63 64 65 66 90 94 ] [ 52 53 54 55 98 ] [ 53 54 55 60 91 98 ] [ 54 55 60 61 91 98 ] [ 55 60 61 62 65 91 98 ] [ 56 58 59 63 66 86 87 ] [ 57 58 59 60 61 ] [ 58 59 60 61 63 64 66 86 87 ] [ 59 60 61 63 64 66 85 86 87 92 ] [ 60 61 62 63 64 65 66 85 86 87 91 92 98 ] [ 61 62 63 64 65 66 85 86 87 91 92 98 ] [ 62 63 64 65 66 85 86 87 90 91 92 94 98 ] [ 63 64 65 66 85 86 87 90 91 92 94 98 ] [ 64 65 66 85 86 87 90 91 92 94 98 ] [ 65 66 85 86 87 90 91 92 94 98 ] [ 66 85 86 87 90 91 92 94 98 ] [ 67 68 80 ] [ 68 70 80 81 ] [ 69 70 82 91 98 ] [ 70 80 81 82 91 98 ] [ 71 74 79 84 89 91 92 ] [ 72 73 74 78 79 81 ] [ 73 74 78 79 81 82 91 ] [ 74 78 79 81 82 84 89 91 92 ] [ 75 76 77 78 80 ] [ 76 77 78 80 83 93 ] [ 77 78 79 80 83 93 ] [ 78 79 80 81 82 83 84 89 91 92 93 ] [ 79 80 81 82 83 84 88 89 91 92 93 ] [ 80 81 82 83 84 88 89 91 92 93 98 ] [ 81 82 83 84 88 89 91 92 93 98 ] [ 82 83 84 88 89 91 92 93 98 ] [ 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 ] [ 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 ] [ 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 ] [ 86 87 88 89 90 91 92 93 94 95 96 97 98 99 ] [ 87 88 89 90 91 92 93 94 95 96 97 98 99 ] [ 88 89 90 91 92 93 94 95 96 97 98 99 ] [ 89 90 91 92 93 94 95 96 97 98 99 ] [ 90 91 92 93 94 95 96 97 98 99 ] [ 91 92 93 94 98 ] [ 92 93 94 98 ] [ 93 94 95 96 97 98 99 ] [ 94 95 96 97 98 99 ] [ 95 96 97 99 ] [ 96 97 99 ] [ 97 99 ] [ 98 ] [ 99 ] ] def /sn_info [ [ 0 3 ] [ 3 3 ] [ 6 4 ] [ 10 5 ] [ 15 4 ] [ 19 3 ] [ 22 1 ] [ 23 4 ] [ 27 1 ] [ 28 3 ] [ 31 2 ] [ 33 6 ] [ 39 2 ] [ 41 3 ] [ 44 5 ] [ 49 3 ] [ 52 4 ] [ 56 4 ] [ 60 2 ] [ 62 3 ] [ 65 2 ] [ 67 4 ] [ 71 4 ] [ 75 3 ] [ 78 2 ] [ 80 3 ] [ 83 4 ] [ 87 4 ] [ 91 4 ] [ 95 4 ] [ 99 1 ] ] def %----------------------------------------------------------------------- /nrow 100 def /ncol 100 def /row_ids [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48] def %----------------------------------------------------------------------- % % draw outline and gridlines % xnw ynw dx dy nrow ncol draw_outline xnw ynw dx dy adjncyL draw_matrix xnw ynw dx dy nrow ncol sn_info draw_sn_overlay ------------------------------------------------------- % % procedures to draw the supernode partition % /draw_sn_overlay { % stack xnw ynw dx dy nrow ncol sninfo % % store input data % /sninfo exch def % supernode information /ncol exch def % # of columns /nrow exch def % # of rows /dy exch def % column spacing /dx exch def % row spacing /ynw exch def % northwest y coordinate /xnw exch def % northwest x coordinated %documentation/FrontTrees/sptree.eps010064400020550007177000000114730663232312600210610ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 390 265 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 350 225 rectstroke newpath 30 54.375 66.923 78.75 ML 54.615 54.375 66.923 78.75 ML 79.231 54.375 66.923 78.75 ML 103.846 54.375 66.923 78.75 ML 66.923 78.75 66.923 103.125 ML 66.923 103.125 203.077 127.5 ML 128.462 30 140.769 54.375 ML 153.077 30 140.769 54.375 ML 140.769 54.375 159.231 78.75 ML 177.692 54.375 159.231 78.75 ML 159.231 78.75 180.769 103.125 ML 202.308 54.375 202.308 78.75 ML 202.308 78.75 180.769 103.125 ML 180.769 103.125 203.077 127.5 ML 226.923 30 226.923 54.375 ML 226.923 54.375 245.385 78.75 ML 251.538 30 263.846 54.375 ML 276.154 30 263.846 54.375 ML 263.846 54.375 245.385 78.75 ML 245.385 78.75 245.385 103.125 ML 245.385 103.125 203.077 127.5 ML 300.769 78.75 319.231 103.125 ML 325.385 54.375 337.692 78.75 ML 350 54.375 337.692 78.75 ML 337.692 78.75 319.231 103.125 ML 319.231 103.125 203.077 127.5 ML 203.077 127.5 203.077 151.875 ML 203.077 151.875 203.077 176.25 ML 203.077 176.25 203.077 200.625 ML 203.077 200.625 203.077 225 ML stroke gsave /Helvetica-Bold findfont 15 scalefont setfont 1.0 setgray 30 54.375 10 FC 0.0 setgray 30 54.375 10 OC 30 49.375 moveto (0) CSH 1.0 setgray 54.615 54.375 10 FC 0.0 setgray 54.615 54.375 10 OC 54.615 49.375 moveto (1) CSH 1.0 setgray 79.231 54.375 10 FC 0.0 setgray 79.231 54.375 10 OC 79.231 49.375 moveto (2) CSH 1.0 setgray 103.846 54.375 10 FC 0.0 setgray 103.846 54.375 10 OC 103.846 49.375 moveto (3) CSH 1.0 setgray 66.923 78.75 10 FC 0.0 setgray 66.923 78.75 10 OC 66.923 73.75 moveto (4) CSH 1.0 setgray 66.923 103.125 10 FC 0.0 setgray 66.923 103.125 10 OC 66.923 98.125 moveto (5) CSH 1.0 setgray 128.462 30 10 FC 0.0 setgray 128.462 30 10 OC 128.462 25 moveto (6) CSH 1.0 setgray 153.077 30 10 FC 0.0 setgray 153.077 30 10 OC 153.077 25 moveto (7) CSH 1.0 setgray 140.769 54.375 10 FC 0.0 setgray 140.769 54.375 10 OC 140.769 49.375 moveto (8) CSH 1.0 setgray 177.692 54.375 10 FC 0.0 setgray 177.692 54.375 10 OC 177.692 49.375 moveto (9) CSH 1.0 setgray 159.231 78.75 10 FC 0.0 setgray 159.231 78.75 10 OC 159.231 73.75 moveto (10) CSH 1.0 setgray 202.308 54.375 10 FC 0.0 setgray 202.308 54.375 10 OC 202.308 49.375 moveto (11) CSH 1.0 setgray 202.308 78.75 10 FC 0.0 setgray 202.308 78.75 10 OC 202.308 73.75 moveto (12) CSH 1.0 setgray 180.769 103.125 10 FC 0.0 setgray 180.769 103.125 10 OC 180.769 98.125 moveto (13) CSH 1.0 setgray 226.923 30 10 FC 0.0 setgray 226.923 30 10 OC 226.923 25 moveto (14) CSH 1.0 setgray 226.923 54.375 10 FC 0.0 setgray 226.923 54.375 10 OC 226.923 49.375 moveto (15) CSH 1.0 setgray 251.538 30 10 FC 0.0 setgray 251.538 30 10 OC 251.538 25 moveto (16) CSH 1.0 setgray 276.154 30 10 FC 0.0 setgray 276.154 30 10 OC 276.154 25 moveto (17) CSH 1.0 setgray 263.846 54.375 10 FC 0.0 setgray 263.846 54.375 10 OC 263.846 49.375 moveto (18) CSH 1.0 setgray 245.385 78.75 10 FC 0.0 setgray 245.385 78.75 10 OC 245.385 73.75 moveto (19) CSH 1.0 setgray 245.385 103.125 10 FC 0.0 setgray 245.385 103.125 10 OC 245.385 98.125 moveto (20) CSH 1.0 setgray 300.769 78.75 10 FC 0.0 setgray 300.769 78.75 10 OC 300.769 73.75 moveto (21) CSH 1.0 setgray 325.385 54.375 10 FC 0.0 setgray 325.385 54.375 10 OC 325.385 49.375 moveto (22) CSH 1.0 setgray 350 54.375 10 FC 0.0 setgray 350 54.375 10 OC 350 49.375 moveto (23) CSH 1.0 setgray 337.692 78.75 10 FC 0.0 setgray 337.692 78.75 10 OC 337.692 73.75 moveto (24) CSH 1.0 setgray 319.231 103.125 10 FC 0.0 setgray 319.231 103.125 10 OC 319.231 98.125 moveto (25) CSH 1.0 setgray 203.077 127.5 10 FC 0.0 setgray 203.077 127.5 10 OC 203.077 122.5 moveto (26) CSH 1.0 setgray 203.077 151.875 10 FC 0.0 setgray 203.077 151.875 10 OC 203.077 146.875 moveto (27) CSH 1.0 setgray 203.077 176.25 10 FC 0.0 setgray 203.077 176.25 10 OC 203.077 171.25 moveto (28) CSH 1.0 setgray 203.077 200.625 10 FC 0.0 setgray 203.077 200.625 10 OC 203.077 195.625 moveto (29) CSH 1.0 setgray 203.077 225 10 FC 0.0 setgray 203.077 225 10 OC 203.077 220 moveto (30) CSH grestore showpage documentation/FrontTrees/spvtree.eps010064400020550007177000000337560663232313300212550ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 600 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 580 580 rectstroke newpath 30 75.833 30 98.75 ML 30 98.75 30 121.667 ML 30 121.667 43.75 144.583 ML 57.5 75.833 57.5 98.75 ML 57.5 98.75 57.5 121.667 ML 57.5 121.667 43.75 144.583 ML 43.75 144.583 43.75 167.5 ML 43.75 167.5 85 190.417 ML 85 121.667 98.75 144.583 ML 112.5 98.75 112.5 121.667 ML 112.5 121.667 98.75 144.583 ML 98.75 144.583 126.25 167.5 ML 140 98.75 140 121.667 ML 140 121.667 153.75 144.583 ML 167.5 98.75 167.5 121.667 ML 167.5 121.667 153.75 144.583 ML 153.75 144.583 126.25 167.5 ML 126.25 167.5 85 190.417 ML 85 190.417 85 213.333 ML 85 213.333 85 236.25 ML 85 236.25 85 259.167 ML 85 259.167 169.219 282.083 ML 195 121.667 208.75 144.583 ML 222.5 52.917 222.5 75.833 ML 222.5 75.833 222.5 98.75 ML 222.5 98.75 222.5 121.667 ML 222.5 121.667 208.75 144.583 ML 208.75 144.583 229.375 167.5 ML 250 98.75 250 121.667 ML 250 121.667 250 144.583 ML 250 144.583 229.375 167.5 ML 229.375 167.5 229.375 190.417 ML 229.375 190.417 253.438 213.333 ML 277.5 30 277.5 52.917 ML 277.5 52.917 277.5 75.833 ML 277.5 75.833 277.5 98.75 ML 277.5 98.75 277.5 121.667 ML 277.5 121.667 277.5 144.583 ML 277.5 144.583 277.5 167.5 ML 277.5 167.5 277.5 190.417 ML 277.5 190.417 253.438 213.333 ML 253.438 213.333 253.438 236.25 ML 253.438 236.25 253.438 259.167 ML 253.438 259.167 169.219 282.083 ML 169.219 282.083 169.219 305 ML 169.219 305 169.219 327.917 ML 169.219 327.917 169.219 350.833 ML 169.219 350.833 308.438 373.75 ML 305 52.917 305 75.833 ML 305 75.833 318.75 98.75 ML 332.5 75.833 318.75 98.75 ML 318.75 98.75 318.75 121.667 ML 318.75 121.667 318.75 144.583 ML 318.75 144.583 339.375 167.5 ML 360 144.583 339.375 167.5 ML 339.375 167.5 373.75 190.417 ML 387.5 52.917 387.5 75.833 ML 387.5 75.833 387.5 98.75 ML 387.5 98.75 387.5 121.667 ML 387.5 121.667 408.125 144.583 ML 415 75.833 428.75 98.75 ML 442.5 75.833 428.75 98.75 ML 428.75 98.75 428.75 121.667 ML 428.75 121.667 408.125 144.583 ML 408.125 144.583 408.125 167.5 ML 408.125 167.5 373.75 190.417 ML 373.75 190.417 373.75 213.333 ML 373.75 213.333 373.75 236.25 ML 373.75 236.25 373.75 259.167 ML 373.75 259.167 373.75 282.083 ML 373.75 282.083 447.656 305 ML 470 167.5 470 190.417 ML 470 190.417 483.75 213.333 ML 497.5 190.417 483.75 213.333 ML 483.75 213.333 521.562 236.25 ML 525 144.583 538.75 167.5 ML 552.5 121.667 552.5 144.583 ML 552.5 144.583 538.75 167.5 ML 538.75 167.5 559.375 190.417 ML 580 121.667 580 144.583 ML 580 144.583 580 167.5 ML 580 167.5 559.375 190.417 ML 559.375 190.417 559.375 213.333 ML 559.375 213.333 521.562 236.25 ML 521.562 236.25 521.562 259.167 ML 521.562 259.167 521.562 282.083 ML 521.562 282.083 447.656 305 ML 447.656 305 447.656 327.917 ML 447.656 327.917 447.656 350.833 ML 447.656 350.833 308.438 373.75 ML 308.438 373.75 308.438 396.667 ML 308.438 396.667 308.438 419.583 ML 308.438 419.583 308.438 442.5 ML 308.438 442.5 308.438 465.417 ML 308.438 465.417 308.438 488.333 ML 308.438 488.333 308.438 511.25 ML 308.438 511.25 308.438 534.167 ML 308.438 534.167 308.438 557.083 ML 308.438 557.083 308.438 580 ML stroke gsave /Helvetica-Bold findfont 15 scalefont setfont 1.0 setgray 30 75.833 10 FC 0.0 setgray 30 75.833 10 OC 30 70.833 moveto (0) CSH 1.0 setgray 30 98.75 10 FC 0.0 setgray 30 98.75 10 OC 30 93.75 moveto (0) CSH 1.0 setgray 30 121.667 10 FC 0.0 setgray 30 121.667 10 OC 30 116.667 moveto (0) CSH 1.0 setgray 57.5 75.833 10 FC 0.0 setgray 57.5 75.833 10 OC 57.5 70.833 moveto (1) CSH 1.0 setgray 57.5 98.75 10 FC 0.0 setgray 57.5 98.75 10 OC 57.5 93.75 moveto (1) CSH 1.0 setgray 57.5 121.667 10 FC 0.0 setgray 57.5 121.667 10 OC 57.5 116.667 moveto (1) CSH 1.0 setgray 43.75 144.583 10 FC 0.0 setgray 43.75 144.583 10 OC 43.75 139.583 moveto (5) CSH 1.0 setgray 43.75 167.5 10 FC 0.0 setgray 43.75 167.5 10 OC 43.75 162.5 moveto (5) CSH 1.0 setgray 85 121.667 10 FC 0.0 setgray 85 121.667 10 OC 85 116.667 moveto (2) CSH 1.0 setgray 112.5 98.75 10 FC 0.0 setgray 112.5 98.75 10 OC 112.5 93.75 moveto (2) CSH 1.0 setgray 112.5 121.667 10 FC 0.0 setgray 112.5 121.667 10 OC 112.5 116.667 moveto (2) CSH 1.0 setgray 98.75 144.583 10 FC 0.0 setgray 98.75 144.583 10 OC 98.75 139.583 moveto (2) CSH 1.0 setgray 140 98.75 10 FC 0.0 setgray 140 98.75 10 OC 140 93.75 moveto (3) CSH 1.0 setgray 140 121.667 10 FC 0.0 setgray 140 121.667 10 OC 140 116.667 moveto (3) CSH 1.0 setgray 167.5 98.75 10 FC 0.0 setgray 167.5 98.75 10 OC 167.5 93.75 moveto (3) CSH 1.0 setgray 167.5 121.667 10 FC 0.0 setgray 167.5 121.667 10 OC 167.5 116.667 moveto (3) CSH 1.0 setgray 153.75 144.583 10 FC 0.0 setgray 153.75 144.583 10 OC 153.75 139.583 moveto (3) CSH 1.0 setgray 126.25 167.5 10 FC 0.0 setgray 126.25 167.5 10 OC 126.25 162.5 moveto (5) CSH 1.0 setgray 85 190.417 10 FC 0.0 setgray 85 190.417 10 OC 85 185.417 moveto (4) CSH 1.0 setgray 85 213.333 10 FC 0.0 setgray 85 213.333 10 OC 85 208.333 moveto (4) CSH 1.0 setgray 85 236.25 10 FC 0.0 setgray 85 236.25 10 OC 85 231.25 moveto (4) CSH 1.0 setgray 85 259.167 10 FC 0.0 setgray 85 259.167 10 OC 85 254.167 moveto (4) CSH 1.0 setgray 195 121.667 10 FC 0.0 setgray 195 121.667 10 OC 195 116.667 moveto (6) CSH 1.0 setgray 222.5 52.917 10 FC 0.0 setgray 222.5 52.917 10 OC 222.5 47.917 moveto (7) CSH 1.0 setgray 222.5 75.833 10 FC 0.0 setgray 222.5 75.833 10 OC 222.5 70.833 moveto (7) CSH 1.0 setgray 222.5 98.75 10 FC 0.0 setgray 222.5 98.75 10 OC 222.5 93.75 moveto (7) CSH 1.0 setgray 222.5 121.667 10 FC 0.0 setgray 222.5 121.667 10 OC 222.5 116.667 moveto (7) CSH 1.0 setgray 208.75 144.583 10 FC 0.0 setgray 208.75 144.583 10 OC 208.75 139.583 moveto (8) CSH 1.0 setgray 250 98.75 10 FC 0.0 setgray 250 98.75 10 OC 250 93.75 moveto (9) CSH 1.0 setgray 250 121.667 10 FC 0.0 setgray 250 121.667 10 OC 250 116.667 moveto (9) CSH 1.0 setgray 250 144.583 10 FC 0.0 setgray 250 144.583 10 OC 250 139.583 moveto (9) CSH 1.0 setgray 229.375 167.5 10 FC 0.0 setgray 229.375 167.5 10 OC 229.375 162.5 moveto (10) CSH 1.0 setgray 229.375 190.417 10 FC 0.0 setgray 229.375 190.417 10 OC 229.375 185.417 moveto (10) CSH 1.0 setgray 277.5 30 10 FC 0.0 setgray 277.5 30 10 OC 277.5 25 moveto (11) CSH 1.0 setgray 277.5 52.917 10 FC 0.0 setgray 277.5 52.917 10 OC 277.5 47.917 moveto (11) CSH 1.0 setgray 277.5 75.833 10 FC 0.0 setgray 277.5 75.833 10 OC 277.5 70.833 moveto (11) CSH 1.0 setgray 277.5 98.75 10 FC 0.0 setgray 277.5 98.75 10 OC 277.5 93.75 moveto (11) CSH 1.0 setgray 277.5 121.667 10 FC 0.0 setgray 277.5 121.667 10 OC 277.5 116.667 moveto (11) CSH 1.0 setgray 277.5 144.583 10 FC 0.0 setgray 277.5 144.583 10 OC 277.5 139.583 moveto (11) CSH 1.0 setgray 277.5 167.5 10 FC 0.0 setgray 277.5 167.5 10 OC 277.5 162.5 moveto (12) CSH 1.0 setgray 277.5 190.417 10 FC 0.0 setgray 277.5 190.417 10 OC 277.5 185.417 moveto (12) CSH 1.0 setgray 253.438 213.333 10 FC 0.0 setgray 253.438 213.333 10 OC 253.438 208.333 moveto (13) CSH 1.0 setgray 253.438 236.25 10 FC 0.0 setgray 253.438 236.25 10 OC 253.438 231.25 moveto (13) CSH 1.0 setgray 253.438 259.167 10 FC 0.0 setgray 253.438 259.167 10 OC 253.438 254.167 moveto (13) CSH 1.0 setgray 169.219 282.083 10 FC 0.0 setgray 169.219 282.083 10 OC 169.219 277.083 moveto (30) CSH 1.0 setgray 169.219 305 10 FC 0.0 setgray 169.219 305 10 OC 169.219 300 moveto (29) CSH 1.0 setgray 169.219 327.917 10 FC 0.0 setgray 169.219 327.917 10 OC 169.219 322.917 moveto (29) CSH 1.0 setgray 169.219 350.833 10 FC 0.0 setgray 169.219 350.833 10 OC 169.219 345.833 moveto (29) CSH 1.0 setgray 305 52.917 10 FC 0.0 setgray 305 52.917 10 OC 305 47.917 moveto (14) CSH 1.0 setgray 305 75.833 10 FC 0.0 setgray 305 75.833 10 OC 305 70.833 moveto (14) CSH 1.0 setgray 332.5 75.833 10 FC 0.0 setgray 332.5 75.833 10 OC 332.5 70.833 moveto (14) CSH 1.0 setgray 318.75 98.75 10 FC 0.0 setgray 318.75 98.75 10 OC 318.75 93.75 moveto (14) CSH 1.0 setgray 318.75 121.667 10 FC 0.0 setgray 318.75 121.667 10 OC 318.75 116.667 moveto (14) CSH 1.0 setgray 318.75 144.583 10 FC 0.0 setgray 318.75 144.583 10 OC 318.75 139.583 moveto (15) CSH 1.0 setgray 360 144.583 10 FC 0.0 setgray 360 144.583 10 OC 360 139.583 moveto (15) CSH 1.0 setgray 339.375 167.5 10 FC 0.0 setgray 339.375 167.5 10 OC 339.375 162.5 moveto (15) CSH 1.0 setgray 387.5 52.917 10 FC 0.0 setgray 387.5 52.917 10 OC 387.5 47.917 moveto (16) CSH 1.0 setgray 387.5 75.833 10 FC 0.0 setgray 387.5 75.833 10 OC 387.5 70.833 moveto (16) CSH 1.0 setgray 387.5 98.75 10 FC 0.0 setgray 387.5 98.75 10 OC 387.5 93.75 moveto (16) CSH 1.0 setgray 387.5 121.667 10 FC 0.0 setgray 387.5 121.667 10 OC 387.5 116.667 moveto (16) CSH 1.0 setgray 415 75.833 10 FC 0.0 setgray 415 75.833 10 OC 415 70.833 moveto (17) CSH 1.0 setgray 442.5 75.833 10 FC 0.0 setgray 442.5 75.833 10 OC 442.5 70.833 moveto (17) CSH 1.0 setgray 428.75 98.75 10 FC 0.0 setgray 428.75 98.75 10 OC 428.75 93.75 moveto (17) CSH 1.0 setgray 428.75 121.667 10 FC 0.0 setgray 428.75 121.667 10 OC 428.75 116.667 moveto (17) CSH 1.0 setgray 408.125 144.583 10 FC 0.0 setgray 408.125 144.583 10 OC 408.125 139.583 moveto (18) CSH 1.0 setgray 408.125 167.5 10 FC 0.0 setgray 408.125 167.5 10 OC 408.125 162.5 moveto (18) CSH 1.0 setgray 373.75 190.417 10 FC 0.0 setgray 373.75 190.417 10 OC 373.75 185.417 moveto (20) CSH 1.0 setgray 373.75 213.333 10 FC 0.0 setgray 373.75 213.333 10 OC 373.75 208.333 moveto (20) CSH 1.0 setgray 373.75 236.25 10 FC 0.0 setgray 373.75 236.25 10 OC 373.75 231.25 moveto (19) CSH 1.0 setgray 373.75 259.167 10 FC 0.0 setgray 373.75 259.167 10 OC 373.75 254.167 moveto (19) CSH 1.0 setgray 373.75 282.083 10 FC 0.0 setgray 373.75 282.083 10 OC 373.75 277.083 moveto (19) CSH 1.0 setgray 470 167.5 10 FC 0.0 setgray 470 167.5 10 OC 470 162.5 moveto (21) CSH 1.0 setgray 470 190.417 10 FC 0.0 setgray 470 190.417 10 OC 470 185.417 moveto (21) CSH 1.0 setgray 497.5 190.417 10 FC 0.0 setgray 497.5 190.417 10 OC 497.5 185.417 moveto (21) CSH 1.0 setgray 483.75 213.333 10 FC 0.0 setgray 483.75 213.333 10 OC 483.75 208.333 moveto (21) CSH 1.0 setgray 525 144.583 10 FC 0.0 setgray 525 144.583 10 OC 525 139.583 moveto (22) CSH 1.0 setgray 552.5 121.667 10 FC 0.0 setgray 552.5 121.667 10 OC 552.5 116.667 moveto (22) CSH 1.0 setgray 552.5 144.583 10 FC 0.0 setgray 552.5 144.583 10 OC 552.5 139.583 moveto (22) CSH 1.0 setgray 538.75 167.5 10 FC 0.0 setgray 538.75 167.5 10 OC 538.75 162.5 moveto (22) CSH 1.0 setgray 580 121.667 10 FC 0.0 setgray 580 121.667 10 OC 580 116.667 moveto (23) CSH 1.0 setgray 580 144.583 10 FC 0.0 setgray 580 144.583 10 OC 580 139.583 moveto (23) CSH 1.0 setgray 580 167.5 10 FC 0.0 setgray 580 167.5 10 OC 580 162.5 moveto (23) CSH 1.0 setgray 559.375 190.417 10 FC 0.0 setgray 559.375 190.417 10 OC 559.375 185.417 moveto (24) CSH 1.0 setgray 559.375 213.333 10 FC 0.0 setgray 559.375 213.333 10 OC 559.375 208.333 moveto (24) CSH 1.0 setgray 521.562 236.25 10 FC 0.0 setgray 521.562 236.25 10 OC 521.562 231.25 moveto (25) CSH 1.0 setgray 521.562 259.167 10 FC 0.0 setgray 521.562 259.167 10 OC 521.562 254.167 moveto (25) CSH 1.0 setgray 521.562 282.083 10 FC 0.0 setgray 521.562 282.083 10 OC 521.562 277.083 moveto (25) CSH 1.0 setgray 447.656 305 10 FC 0.0 setgray 447.656 305 10 OC 447.656 300 moveto (29) CSH 1.0 setgray 447.656 327.917 10 FC 0.0 setgray 447.656 327.917 10 OC 447.656 322.917 moveto (28) CSH 1.0 setgray 447.656 350.833 10 FC 0.0 setgray 447.656 350.833 10 OC 447.656 345.833 moveto (28) CSH 1.0 setgray 308.438 373.75 10 FC 0.0 setgray 308.438 373.75 10 OC 308.438 368.75 moveto (28) CSH 1.0 setgray 308.438 396.667 10 FC 0.0 setgray 308.438 396.667 10 OC 308.438 391.667 moveto (28) CSH 1.0 setgray 308.438 419.583 10 FC 0.0 setgray 308.438 419.583 10 OC 308.438 414.583 moveto (27) CSH 1.0 setgray 308.438 442.5 10 FC 0.0 setgray 308.438 442.5 10 OC 308.438 437.5 moveto (27) CSH 1.0 setgray 308.438 465.417 10 FC 0.0 setgray 308.438 465.417 10 OC 308.438 460.417 moveto (27) CSH 1.0 setgray 308.438 488.333 10 FC 0.0 setgray 308.438 488.333 10 OC 308.438 483.333 moveto (27) CSH 1.0 setgray 308.438 511.25 10 FC 0.0 setgray 308.438 511.25 10 OC 308.438 506.25 moveto (26) CSH 1.0 setgray 308.438 534.167 10 FC 0.0 setgray 308.438 534.167 10 OC 308.438 529.167 moveto (26) CSH 1.0 setgray 308.438 557.083 10 FC 0.0 setgray 308.438 557.083 10 OC 308.438 552.083 moveto (26) CSH 1.0 setgray 308.438 580 10 FC 0.0 setgray 308.438 580 10 OC 308.438 575 moveto (26) CSH grestore showpage 5 moveto (0) CSH documentation/FrontTrees/vtree.eps010064400020550007177000000340030663232317300207000ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 600 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def % 20 20 580 580 rectstroke newpath 30 75.833 30 98.75 ML 30 98.75 30 121.667 ML 30 121.667 43.75 144.583 ML 57.5 75.833 57.5 98.75 ML 57.5 98.75 57.5 121.667 ML 57.5 121.667 43.75 144.583 ML 43.75 144.583 43.75 167.5 ML 43.75 167.5 85 190.417 ML 85 121.667 98.75 144.583 ML 112.5 98.75 112.5 121.667 ML 112.5 121.667 98.75 144.583 ML 98.75 144.583 126.25 167.5 ML 140 98.75 140 121.667 ML 140 121.667 153.75 144.583 ML 167.5 98.75 167.5 121.667 ML 167.5 121.667 153.75 144.583 ML 153.75 144.583 126.25 167.5 ML 126.25 167.5 85 190.417 ML 85 190.417 85 213.333 ML 85 213.333 85 236.25 ML 85 236.25 85 259.167 ML 85 259.167 169.219 282.083 ML 195 121.667 208.75 144.583 ML 222.5 52.917 222.5 75.833 ML 222.5 75.833 222.5 98.75 ML 222.5 98.75 222.5 121.667 ML 222.5 121.667 208.75 144.583 ML 208.75 144.583 229.375 167.5 ML 250 98.75 250 121.667 ML 250 121.667 250 144.583 ML 250 144.583 229.375 167.5 ML 229.375 167.5 229.375 190.417 ML 229.375 190.417 253.438 213.333 ML 277.5 30 277.5 52.917 ML 277.5 52.917 277.5 75.833 ML 277.5 75.833 277.5 98.75 ML 277.5 98.75 277.5 121.667 ML 277.5 121.667 277.5 144.583 ML 277.5 144.583 277.5 167.5 ML 277.5 167.5 277.5 190.417 ML 277.5 190.417 253.438 213.333 ML 253.438 213.333 253.438 236.25 ML 253.438 236.25 253.438 259.167 ML 253.438 259.167 169.219 282.083 ML 169.219 282.083 169.219 305 ML 169.219 305 169.219 327.917 ML 169.219 327.917 169.219 350.833 ML 169.219 350.833 308.438 373.75 ML 305 52.917 305 75.833 ML 305 75.833 318.75 98.75 ML 332.5 75.833 318.75 98.75 ML 318.75 98.75 318.75 121.667 ML 318.75 121.667 318.75 144.583 ML 318.75 144.583 339.375 167.5 ML 360 144.583 339.375 167.5 ML 339.375 167.5 373.75 190.417 ML 387.5 52.917 387.5 75.833 ML 387.5 75.833 387.5 98.75 ML 387.5 98.75 387.5 121.667 ML 387.5 121.667 408.125 144.583 ML 415 75.833 428.75 98.75 ML 442.5 75.833 428.75 98.75 ML 428.75 98.75 428.75 121.667 ML 428.75 121.667 408.125 144.583 ML 408.125 144.583 408.125 167.5 ML 408.125 167.5 373.75 190.417 ML 373.75 190.417 373.75 213.333 ML 373.75 213.333 373.75 236.25 ML 373.75 236.25 373.75 259.167 ML 373.75 259.167 373.75 282.083 ML 373.75 282.083 447.656 305 ML 470 167.5 470 190.417 ML 470 190.417 483.75 213.333 ML 497.5 190.417 483.75 213.333 ML 483.75 213.333 521.562 236.25 ML 525 144.583 538.75 167.5 ML 552.5 121.667 552.5 144.583 ML 552.5 144.583 538.75 167.5 ML 538.75 167.5 559.375 190.417 ML 580 121.667 580 144.583 ML 580 144.583 580 167.5 ML 580 167.5 559.375 190.417 ML 559.375 190.417 559.375 213.333 ML 559.375 213.333 521.562 236.25 ML 521.562 236.25 521.562 259.167 ML 521.562 259.167 521.562 282.083 ML 521.562 282.083 447.656 305 ML 447.656 305 447.656 327.917 ML 447.656 327.917 447.656 350.833 ML 447.656 350.833 308.438 373.75 ML 308.438 373.75 308.438 396.667 ML 308.438 396.667 308.438 419.583 ML 308.438 419.583 308.438 442.5 ML 308.438 442.5 308.438 465.417 ML 308.438 465.417 308.438 488.333 ML 308.438 488.333 308.438 511.25 ML 308.438 511.25 308.438 534.167 ML 308.438 534.167 308.438 557.083 ML 308.438 557.083 308.438 580 ML stroke gsave /Helvetica-Bold findfont 15 scalefont setfont 1.0 setgray 30 75.833 10 FC 0.0 setgray 30 75.833 10 OC 30 70.833 moveto (0) CSH 1.0 setgray 30 98.75 10 FC 0.0 setgray 30 98.75 10 OC 30 93.75 moveto (1) CSH 1.0 setgray 30 121.667 10 FC 0.0 setgray 30 121.667 10 OC 30 116.667 moveto (2) CSH 1.0 setgray 57.5 75.833 10 FC 0.0 setgray 57.5 75.833 10 OC 57.5 70.833 moveto (3) CSH 1.0 setgray 57.5 98.75 10 FC 0.0 setgray 57.5 98.75 10 OC 57.5 93.75 moveto (4) CSH 1.0 setgray 57.5 121.667 10 FC 0.0 setgray 57.5 121.667 10 OC 57.5 116.667 moveto (5) CSH 1.0 setgray 43.75 144.583 10 FC 0.0 setgray 43.75 144.583 10 OC 43.75 139.583 moveto (6) CSH 1.0 setgray 43.75 167.5 10 FC 0.0 setgray 43.75 167.5 10 OC 43.75 162.5 moveto (7) CSH 1.0 setgray 85 121.667 10 FC 0.0 setgray 85 121.667 10 OC 85 116.667 moveto (8) CSH 1.0 setgray 112.5 98.75 10 FC 0.0 setgray 112.5 98.75 10 OC 112.5 93.75 moveto (9) CSH 1.0 setgray 112.5 121.667 10 FC 0.0 setgray 112.5 121.667 10 OC 112.5 116.667 moveto (10) CSH 1.0 setgray 98.75 144.583 10 FC 0.0 setgray 98.75 144.583 10 OC 98.75 139.583 moveto (11) CSH 1.0 setgray 140 98.75 10 FC 0.0 setgray 140 98.75 10 OC 140 93.75 moveto (12) CSH 1.0 setgray 140 121.667 10 FC 0.0 setgray 140 121.667 10 OC 140 116.667 moveto (13) CSH 1.0 setgray 167.5 98.75 10 FC 0.0 setgray 167.5 98.75 10 OC 167.5 93.75 moveto (14) CSH 1.0 setgray 167.5 121.667 10 FC 0.0 setgray 167.5 121.667 10 OC 167.5 116.667 moveto (15) CSH 1.0 setgray 153.75 144.583 10 FC 0.0 setgray 153.75 144.583 10 OC 153.75 139.583 moveto (16) CSH 1.0 setgray 126.25 167.5 10 FC 0.0 setgray 126.25 167.5 10 OC 126.25 162.5 moveto (17) CSH 1.0 setgray 85 190.417 10 FC 0.0 setgray 85 190.417 10 OC 85 185.417 moveto (18) CSH 1.0 setgray 85 213.333 10 FC 0.0 setgray 85 213.333 10 OC 85 208.333 moveto (19) CSH 1.0 setgray 85 236.25 10 FC 0.0 setgray 85 236.25 10 OC 85 231.25 moveto (20) CSH 1.0 setgray 85 259.167 10 FC 0.0 setgray 85 259.167 10 OC 85 254.167 moveto (21) CSH 1.0 setgray 195 121.667 10 FC 0.0 setgray 195 121.667 10 OC 195 116.667 moveto (22) CSH 1.0 setgray 222.5 52.917 10 FC 0.0 setgray 222.5 52.917 10 OC 222.5 47.917 moveto (23) CSH 1.0 setgray 222.5 75.833 10 FC 0.0 setgray 222.5 75.833 10 OC 222.5 70.833 moveto (24) CSH 1.0 setgray 222.5 98.75 10 FC 0.0 setgray 222.5 98.75 10 OC 222.5 93.75 moveto (25) CSH 1.0 setgray 222.5 121.667 10 FC 0.0 setgray 222.5 121.667 10 OC 222.5 116.667 moveto (26) CSH 1.0 setgray 208.75 144.583 10 FC 0.0 setgray 208.75 144.583 10 OC 208.75 139.583 moveto (27) CSH 1.0 setgray 250 98.75 10 FC 0.0 setgray 250 98.75 10 OC 250 93.75 moveto (28) CSH 1.0 setgray 250 121.667 10 FC 0.0 setgray 250 121.667 10 OC 250 116.667 moveto (29) CSH 1.0 setgray 250 144.583 10 FC 0.0 setgray 250 144.583 10 OC 250 139.583 moveto (30) CSH 1.0 setgray 229.375 167.5 10 FC 0.0 setgray 229.375 167.5 10 OC 229.375 162.5 moveto (31) CSH 1.0 setgray 229.375 190.417 10 FC 0.0 setgray 229.375 190.417 10 OC 229.375 185.417 moveto (32) CSH 1.0 setgray 277.5 30 10 FC 0.0 setgray 277.5 30 10 OC 277.5 25 moveto (33) CSH 1.0 setgray 277.5 52.917 10 FC 0.0 setgray 277.5 52.917 10 OC 277.5 47.917 moveto (34) CSH 1.0 setgray 277.5 75.833 10 FC 0.0 setgray 277.5 75.833 10 OC 277.5 70.833 moveto (35) CSH 1.0 setgray 277.5 98.75 10 FC 0.0 setgray 277.5 98.75 10 OC 277.5 93.75 moveto (36) CSH 1.0 setgray 277.5 121.667 10 FC 0.0 setgray 277.5 121.667 10 OC 277.5 116.667 moveto (37) CSH 1.0 setgray 277.5 144.583 10 FC 0.0 setgray 277.5 144.583 10 OC 277.5 139.583 moveto (38) CSH 1.0 setgray 277.5 167.5 10 FC 0.0 setgray 277.5 167.5 10 OC 277.5 162.5 moveto (39) CSH 1.0 setgray 277.5 190.417 10 FC 0.0 setgray 277.5 190.417 10 OC 277.5 185.417 moveto (40) CSH 1.0 setgray 253.438 213.333 10 FC 0.0 setgray 253.438 213.333 10 OC 253.438 208.333 moveto (41) CSH 1.0 setgray 253.438 236.25 10 FC 0.0 setgray 253.438 236.25 10 OC 253.438 231.25 moveto (42) CSH 1.0 setgray 253.438 259.167 10 FC 0.0 setgray 253.438 259.167 10 OC 253.438 254.167 moveto (43) CSH 1.0 setgray 169.219 282.083 10 FC 0.0 setgray 169.219 282.083 10 OC 169.219 277.083 moveto (44) CSH 1.0 setgray 169.219 305 10 FC 0.0 setgray 169.219 305 10 OC 169.219 300 moveto (45) CSH 1.0 setgray 169.219 327.917 10 FC 0.0 setgray 169.219 327.917 10 OC 169.219 322.917 moveto (46) CSH 1.0 setgray 169.219 350.833 10 FC 0.0 setgray 169.219 350.833 10 OC 169.219 345.833 moveto (47) CSH 1.0 setgray 305 52.917 10 FC 0.0 setgray 305 52.917 10 OC 305 47.917 moveto (48) CSH 1.0 setgray 305 75.833 10 FC 0.0 setgray 305 75.833 10 OC 305 70.833 moveto (49) CSH 1.0 setgray 332.5 75.833 10 FC 0.0 setgray 332.5 75.833 10 OC 332.5 70.833 moveto (50) CSH 1.0 setgray 318.75 98.75 10 FC 0.0 setgray 318.75 98.75 10 OC 318.75 93.75 moveto (51) CSH 1.0 setgray 318.75 121.667 10 FC 0.0 setgray 318.75 121.667 10 OC 318.75 116.667 moveto (52) CSH 1.0 setgray 318.75 144.583 10 FC 0.0 setgray 318.75 144.583 10 OC 318.75 139.583 moveto (53) CSH 1.0 setgray 360 144.583 10 FC 0.0 setgray 360 144.583 10 OC 360 139.583 moveto (54) CSH 1.0 setgray 339.375 167.5 10 FC 0.0 setgray 339.375 167.5 10 OC 339.375 162.5 moveto (55) CSH 1.0 setgray 387.5 52.917 10 FC 0.0 setgray 387.5 52.917 10 OC 387.5 47.917 moveto (56) CSH 1.0 setgray 387.5 75.833 10 FC 0.0 setgray 387.5 75.833 10 OC 387.5 70.833 moveto (57) CSH 1.0 setgray 387.5 98.75 10 FC 0.0 setgray 387.5 98.75 10 OC 387.5 93.75 moveto (58) CSH 1.0 setgray 387.5 121.667 10 FC 0.0 setgray 387.5 121.667 10 OC 387.5 116.667 moveto (59) CSH 1.0 setgray 415 75.833 10 FC 0.0 setgray 415 75.833 10 OC 415 70.833 moveto (60) CSH 1.0 setgray 442.5 75.833 10 FC 0.0 setgray 442.5 75.833 10 OC 442.5 70.833 moveto (61) CSH 1.0 setgray 428.75 98.75 10 FC 0.0 setgray 428.75 98.75 10 OC 428.75 93.75 moveto (62) CSH 1.0 setgray 428.75 121.667 10 FC 0.0 setgray 428.75 121.667 10 OC 428.75 116.667 moveto (63) CSH 1.0 setgray 408.125 144.583 10 FC 0.0 setgray 408.125 144.583 10 OC 408.125 139.583 moveto (64) CSH 1.0 setgray 408.125 167.5 10 FC 0.0 setgray 408.125 167.5 10 OC 408.125 162.5 moveto (65) CSH 1.0 setgray 373.75 190.417 10 FC 0.0 setgray 373.75 190.417 10 OC 373.75 185.417 moveto (66) CSH 1.0 setgray 373.75 213.333 10 FC 0.0 setgray 373.75 213.333 10 OC 373.75 208.333 moveto (67) CSH 1.0 setgray 373.75 236.25 10 FC 0.0 setgray 373.75 236.25 10 OC 373.75 231.25 moveto (68) CSH 1.0 setgray 373.75 259.167 10 FC 0.0 setgray 373.75 259.167 10 OC 373.75 254.167 moveto (69) CSH 1.0 setgray 373.75 282.083 10 FC 0.0 setgray 373.75 282.083 10 OC 373.75 277.083 moveto (70) CSH 1.0 setgray 470 167.5 10 FC 0.0 setgray 470 167.5 10 OC 470 162.5 moveto (71) CSH 1.0 setgray 470 190.417 10 FC 0.0 setgray 470 190.417 10 OC 470 185.417 moveto (72) CSH 1.0 setgray 497.5 190.417 10 FC 0.0 setgray 497.5 190.417 10 OC 497.5 185.417 moveto (73) CSH 1.0 setgray 483.75 213.333 10 FC 0.0 setgray 483.75 213.333 10 OC 483.75 208.333 moveto (74) CSH 1.0 setgray 525 144.583 10 FC 0.0 setgray 525 144.583 10 OC 525 139.583 moveto (75) CSH 1.0 setgray 552.5 121.667 10 FC 0.0 setgray 552.5 121.667 10 OC 552.5 116.667 moveto (76) CSH 1.0 setgray 552.5 144.583 10 FC 0.0 setgray 552.5 144.583 10 OC 552.5 139.583 moveto (77) CSH 1.0 setgray 538.75 167.5 10 FC 0.0 setgray 538.75 167.5 10 OC 538.75 162.5 moveto (78) CSH 1.0 setgray 580 121.667 10 FC 0.0 setgray 580 121.667 10 OC 580 116.667 moveto (79) CSH 1.0 setgray 580 144.583 10 FC 0.0 setgray 580 144.583 10 OC 580 139.583 moveto (80) CSH 1.0 setgray 580 167.5 10 FC 0.0 setgray 580 167.5 10 OC 580 162.5 moveto (81) CSH 1.0 setgray 559.375 190.417 10 FC 0.0 setgray 559.375 190.417 10 OC 559.375 185.417 moveto (82) CSH 1.0 setgray 559.375 213.333 10 FC 0.0 setgray 559.375 213.333 10 OC 559.375 208.333 moveto (83) CSH 1.0 setgray 521.562 236.25 10 FC 0.0 setgray 521.562 236.25 10 OC 521.562 231.25 moveto (84) CSH 1.0 setgray 521.562 259.167 10 FC 0.0 setgray 521.562 259.167 10 OC 521.562 254.167 moveto (85) CSH 1.0 setgray 521.562 282.083 10 FC 0.0 setgray 521.562 282.083 10 OC 521.562 277.083 moveto (86) CSH 1.0 setgray 447.656 305 10 FC 0.0 setgray 447.656 305 10 OC 447.656 300 moveto (87) CSH 1.0 setgray 447.656 327.917 10 FC 0.0 setgray 447.656 327.917 10 OC 447.656 322.917 moveto (88) CSH 1.0 setgray 447.656 350.833 10 FC 0.0 setgray 447.656 350.833 10 OC 447.656 345.833 moveto (89) CSH 1.0 setgray 308.438 373.75 10 FC 0.0 setgray 308.438 373.75 10 OC 308.438 368.75 moveto (90) CSH 1.0 setgray 308.438 396.667 10 FC 0.0 setgray 308.438 396.667 10 OC 308.438 391.667 moveto (91) CSH 1.0 setgray 308.438 419.583 10 FC 0.0 setgray 308.438 419.583 10 OC 308.438 414.583 moveto (92) CSH 1.0 setgray 308.438 442.5 10 FC 0.0 setgray 308.438 442.5 10 OC 308.438 437.5 moveto (93) CSH 1.0 setgray 308.438 465.417 10 FC 0.0 setgray 308.438 465.417 10 OC 308.438 460.417 moveto (94) CSH 1.0 setgray 308.438 488.333 10 FC 0.0 setgray 308.438 488.333 10 OC 308.438 483.333 moveto (95) CSH 1.0 setgray 308.438 511.25 10 FC 0.0 setgray 308.438 511.25 10 OC 308.438 506.25 moveto (96) CSH 1.0 setgray 308.438 534.167 10 FC 0.0 setgray 308.438 534.167 10 OC 308.438 529.167 moveto (97) CSH 1.0 setgray 308.438 557.083 10 FC 0.0 setgray 308.438 557.083 10 OC 308.438 552.083 moveto (98) CSH 1.0 setgray 308.438 580 10 FC 0.0 setgray 308.438 580 10 OC 308.438 575 moveto (99) CSH grestore showpage documentation/FrontTrees/makefile010064400020550007177000000000270665014157500205450ustar00clevecompmath00000400000006clean : - rm -f *.dvi documentation/Install/004275500020550007177000000000000665315046500163675ustar00clevecompmath00000400000006documentation/Install/main.tex010064400020550007177000000027410663623311300200250ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,10pt,twoside]{article} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \input psfig \newcommand{\bfi}{{\bf i}} \newcommand{\bfj}{{\bf j}} \newcommand{\bnd}[1]{{\partial{#1}}} \newcommand\WHILE{{\bf while}} \newcommand\IF{{\bf if}} \newcommand\END{{\bf end}} \newcommand\ELSE{{\bf else}} \newcommand\THEN{{\bf then}} \pagestyle{myheadings} % \markboth % {\quad \hrulefill \quad {\bf SPOOLES 2.2} : \today \quad \hrulefill} % {\quad \hrulefill \quad {\bf SPOOLES 2.2} : \quad \today \hrulefill} \markboth {\hspace*{0.5 in} {\bf SPOOLES 2.2} Installation Manual \quad\hrulefill\quad\today} {\today \quad\hrulefill\quad {\bf SPOOLES 2.2} Installation Manual \hspace*{0.5 in}} \begin{document} \bibliographystyle{plain} \title{ {\bf SPOOLES 2.2} Installation Manual } \author{Cleve Ashcraft, Boeing Shared Services Group\thanks{ P. O. Box 24346, Mail Stop 7L-21, Seattle, Washington 98124. This research was supported in part by the DARPA Contract DABT63-95-C-0122 and the DoD High Performance Computing Modernization Program Common HPC Software Support Initiative.} } \date{\today} \maketitle \input overview.tex \input makefile.tex \input threads.tex \input globalLibs.tex \input drivers.tex \input source.tex \input cleanup.tex \input afterward.tex \end{document} documentation/Install/main.log010064400020550007177000000066050665314622400200160ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 25 JAN 1999 11:57 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/article.cls Document Class: article 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@section=\count80 \c@subsection=\count81 \c@subsubsection=\count82 \c@paragraph=\count83 \c@subparagraph=\count84 \c@figure=\count85 \c@table=\count86 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file main.idx (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 38. LaTeX Font Info: ... okay on input line 38. LaTeX Font Info: External font `cmex10' loaded for size (Font) <12> on input line 55. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 55. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 55. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 55. (overview.tex LaTeX Font Info: Try loading font information for OMS+cmr on input line 26. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 26. LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 38. [1 ]) (makefile.tex [2]) (threads.tex) (globalLibs.tex [3]) (drivers.tex [4]) (source.tex [5]) (cleanup.tex [6]) (afterward.tex) Overfull \hbox (9.7445pt too wide) in paragraph at lines 4--65 \OT1/cmr/m/n/10 Any ques-tions, com-ments, and par-tic-u-larly, sug-ges-tions, con-tact Cleve Ashcraft, \OT1/cmtt/m/n/10 cleve.ashcraft@boeing.com\OT1/cmr/m/n /10 . [] [7] (main.aux) ) (\end occurred inside a group at level 1) Here is how much of TeX's memory you used: 528 strings out of 10908 5142 string characters out of 72189 52622 words of memory out of 262141 3426 multiletter control sequences out of 9500 9591 words of font info for 34 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 30i,11n,21p,160b,355s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (7 pages, 27428 bytes). documentation/Install/main.idx010064400020550007177000000000000665314622300177770ustar00clevecompmath00000400000006documentation/Install/main.aux010064400020550007177000000014030665314622400200210ustar00clevecompmath00000400000006\relax \bibstyle{plain} \@writefile{toc}{\contentsline {section}{\numberline {1}Overview}{1}} \newlabel{section:overview}{{1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {2}Makefiles}{2}} \@writefile{toc}{\contentsline {section}{\numberline {3}Setting the thread type}{3}} \@writefile{toc}{\contentsline {section}{\numberline {4}Building global libraries}{4}} \@writefile{toc}{\contentsline {section}{\numberline {5}Exercising the objects' driver programs}{4}} \@writefile{toc}{\contentsline {section}{\numberline {6}Modifying source code and new development}{5}} \@writefile{toc}{\contentsline {section}{\numberline {7}Cleaning up and packaging}{6}} \newlabel{section:cleanup}{{7}{6}} \@writefile{toc}{\contentsline {section}{\numberline {8}Afterword}{7}} documentation/Install/overview.tex010064400020550007177000000077350663623317100207630ustar00clevecompmath00000400000006\section{Overview} \label{section:overview} \par The {\bf SPOOLES} library is {\it object-oriented}. Just about everything is an object, data structures and algorithms. The directory structure reflects this design philosophy. First, make a directory (say called {\tt spooles}) and place the tar file {\tt spooles.2.2.tar.gz} in this directory. unzip the file and then extract the files. For example, here are the Unix commands. \begin{verbatim} % mkdir spooles % mv spooles.2.2.tar.gz spooles % cd spooles % gzip -d spooles.2.2.tar.gz % tar -xvf spooles.2.2.tar.gz \end{verbatim} The top level directory has many subdirectories and many header files. Most subdirectories deal with a single object. \par Let's look at the first object, the {\tt A2} dense matrix object. ({\tt A2} stands for {\tt A}rray, {\tt 2}-dimensional.) The {\tt A2} directory has two files and three subdirectories. \begin{itemize} \item {\tt A2.h} --- This is the header file that defines the {\tt struct} that holds the {\tt A2} object and has prototypes of all of the {\tt A2} methods. If you don't have printed documentation in front of you, this is a handy place to look. This file contains comments from the source code telling what the method does and describes the calling sequence parameters. \item {\tt makefile} --- This makefile is called by the top level makefile to compile source, drivers, and clean up the subdirectories. \item {\tt doc/} --- This subdirectory contains \LaTeX\ files that document the {\tt A2} object. These files also form a chapter of the {\bf SPOOLES} Reference Manual. \item {\tt src/} --- This subdirectory contains all the source code for the {\tt A2} object. \item {\tt drivers/} --- This subdirectory contains all the driver programs that exercise and validate the behavior of the {\tt A2} object. \end{itemize} Each object's directory contains a header file, a make file, and a source and document subdirectories. Most but not all contain driver directories. \par {\bf SPOOLES} is written in the C language, which does not directly support object-oriented programming. There is no inheritance in C, and so there is no nesting of our object directories. For example, there are three tree objects --- {\tt Tree} for a simple tree, {\tt ETree} for a front tree (which contains a {\tt Tree} object and so could be descended from it), and {\tt DSTree} for a ``domain/separator'' tree (which also contains a {\tt Tree} object) --- but they are separate objects whose directories are at the same level. \par There are some directories that are peripheral to the main library. \begin{itemize} \item The {\tt LinSol} directory contains some ``bridge'' or ``wrapper'' methods used to incorporate {\bf SPOOLES} into CSAR-Nastran, a finite element program, to solve linear systems. \item The {\tt Eigen} directory contains some ``bridge'' or ``wrapper'' methods used to incorporate {\bf SPOOLES} into a block-shifted Lanczos eigensolver. \item The {\tt FanBothMap} directory is an experimental object used to investigate the feasibility of replacing the fan-in method with the fan-both method for a distributed factorization. \item The {\tt ReferenceManual} directory contains \LaTeX\ files to construct the reference manual (currently 400+ pages). \item The {\tt UserManual} directory contains \LaTeX\ files to construct the various user manuals. (This document is one.) \item The {\tt Matrices} directory contains some matrix files that can be used to run the example programs. \end{itemize} \par The goal is to get work done. The {\bf SPOOLES} library can be used in several ways. Here are three scenarios. \begin{itemize} \item I want a global library to link with other application programs. \item I want to exercise the objects in the library to get a feel for performance, e.g., test out the matrix orderings, or the factors and solves, or the multithreaded and MPI programs. \item I want to do development work, modify existing objects or create new objects. \end{itemize} We will discuss each in turn. But first, let's talk about makefiles. \par bject. These files also form a chadocumentation/Install/makefile.tex010064400020550007177000000041330663627035300206620ustar00clevecompmath00000400000006\par \section{Makefiles} \par Each object's {\tt src/} and (possibly) {\tt drivers/} directories have their own makefile. Each of these makefiles ``includes'' (via an include statement) the file {\tt Make.inc} from the top level directory.\footnote{ Many thanks go to Clay Breshears from CEWES, {\tt clay@turing.wes.hpc.mil}, for the prototype {\tt Make.inc} file. } This is the file where one sets the following parameters. \begin{itemize} \item {\tt CC} is your favorite C compiler. \item {\tt OPTLEVEL} is the compiler's optimization level. \item {\tt CFLAGS} is the compiler's compilation flags, which normally includes the {\tt OPTLEVEL} data. \item {\tt LDFLAGS} are load flags for executables. \item {\tt THREAD\_LIBS} are system dependent libraries for multithreaded programs. \item {\tt PURIFY} and {\tt PURIFY\_GCC\_VERSION} deal with the Purify program from PureAtria. This is a handy program that detects memory leaks, overwriting of storage, and the like. Most of the code at one point or another has been run through Purify. \item {\tt AR} and {\tt ARFLAGS} are the loader and its flags. \item {\tt RANLIB} is used when the library must be postprocessed to get a symbol table. (Some systems still use {\tt ranlib}.) % including my ancient home NeXTStation where a % good deal of development was done.) If {\tt ranlib} is not needed (as on most systems), {\tt RANLIB} is set to {\tt echo} to echo out the library name during the {\tt make} process. \item The {\tt .c.o} and {\tt .c.a} suffix rules are defined. \item {\tt MPI\_INSTALL\_DIR} is the installation directory for MPI. \item {\tt MPI\_LIB\_PATH} is the library path for MPI. \item {\tt MPI\_LIBS} are the libraries needed for MPI programs. \item {\tt MPI\_INCLUDE\_DIR} is the include directory for MPI. \end{itemize} The {\tt Make.inc} file contains several different values for each of the parameters along with some comments about which lines are for which system. We have found most of this to be fairly straightforward, but getting the thread libraries and MPI libraries correct may take a bit of doing. Contact your local system administrator for help. \par documentation/Install/threads.tex010064400020550007177000000050370663627043300205420ustar00clevecompmath00000400000006\par \section{Setting the thread type} \par Once the {\tt Make.inc} file is modified for your system, it's time to think about what functionality you want to use. The {\bf SPOOLES} library operates in serial, multithreaded and MPI environments. The code for these three environments is fairly segregated. The {\tt MPI} directory contains all source and driver code for MPI programs. The {\tt MT} directory contains all source and driver code for multithreaded programs. All other directories contain serial code.\footnote{ This is not quite true. The {\tt LinSol} directory contains serial, MT and MPI subdirectories, but the {\tt LinSol} package is {\it adjunct} to the {\bf SPOOLES} library, not part of it.} The MPI source code is compiled into a {\tt spoolesMPI.a} library. The multithreaded source code is compiled into a {\tt spoolesMT.a} library. The serial code is compiled into a {\tt spooles.a} library. \par If you are going to operate only in serial mode, then you should edit one file, {\tt Lock/Lock.h}. Here is where we hide the operating system specific details about {\it mutual exclusion} locks. Presently only POSIX threads are actively supported by the library. The original development work was done using Solaris threads, and there is some Solaris thread code still in the {\tt Lock} and {\tt MT} {\tt src/} directories. (The library has also been ported to use the NeXT and WindowsNT thread packages, but this code is not included in this release.) % (Some work was done using the NeXT thread library, but we have % removed this code from the present library.) % The {\bf SPOOLES} library has been ported to use WindowsNT threads % by a finite element software company, % but the changes have not been made available to us. The decision to use threads or not, or which thread library to use, requires the {\tt Lock/Lock.h} file to be modified. Line 9 defines the thread type. It is presently set to POSIX threads. \begin{verbatim} #define THREAD_TYPE TT_POSIX \end{verbatim} To use no threads, one would replace this line with the one below. \begin{verbatim} #define THREAD_TYPE TT_NONE \end{verbatim} {\tt TT\_POSIX} and {\tt TT\_NONE} are defined in the {\tt Lock/Lock.h} file. There is also a line to define Solaris threads. If you are planning to port the {\bf SPOOLES} library to another thread library, add a {\tt THREAD\_TYPE} define statement and modify the definition of the lock in the {\tt Lock} structure. The files in {\tt Lock/src} and {\tt MT/src} will also have to be modified to use different subroutine calls to create and join threads, etc. \par documentation/Install/globalLibs.tex010064400020550007177000000043330663623422100211530ustar00clevecompmath00000400000006\par \section{Building global libraries} \par To build the global serial library {\tt spooles.a}, type the following. \begin{verbatim} % cd spooles % make lib \end{verbatim} This visits each of the serial objects' {\tt src/} directories, compiles the source code and loads it into the {\tt spooles.a} library. Note, this option requires the Perl language installed on the system, for we use a Perl script to generate a temporary makefile for each object. If your computer system does {\it not} have Perl installed, this option will have the same result. \begin{verbatim} % cd spooles % make global \end{verbatim} This approach uses hard-coded makefile inside each {\tt src/} directory, and is less reliable than the first way. \par The result of either of these two commands is a {\tt spooles.a} library that is present in the top level {\tt spooles} directory. Recall, this only contains the serial code. This process may take a long time, for there are about 140,000 lines of source code in the library. \par To build a multithreaded library, one must go to the {\tt MT/src} directory. Now we have two choices --- to build a separate {\tt spoolesMT.a} library, or two merge the multithreaded code into the {\tt spooles.a} library. We recommend the first, via typing {\tt make spoolesMT.a}, though the second is perfectly fine by typing {\tt make makeLib}. If Perl is not installed, type {\tt make -f makeGlobalLib} for the latter behavior. \par Much the same applies to the MPI library. To build a MPI library, one must go to the {\tt MPI/src} directory. Now we have two choices --- to build a separate {\tt spoolesMPI.a} library, or two merge the MPI code into the {\tt spooles.a} library. We recommend the first, via typing {\tt make spoolesMPI.a}, though the second is perfectly fine by typing {\tt make makeLib}. If Perl is not installed, type {\tt make -f makeGlobalLib} for the latter behavior. \par Note, in the top level {\tt spooles/makefile} there are two lines commented out under the {\tt lib:} target which will compile the multithreaded and MPI source code into {\tt spooles.a}. If you uncomment these lines, (replace the {\tt \#} with a tab), and type {\tt make lib}, then the multithreaded and MPI source will be included in {\tt spooles.a}. \par r The result of either of these two commands is a {\tt spooles.a} library that is present in the top level {\tt spooles} directory. Recall, this only contains the serial code. This process may take a long time, for there are about 140,000 lines of source code in the library. \par To build a documentation/Install/drivers.tex010064400020550007177000000063320663623401600205620ustar00clevecompmath00000400000006\par \section{Exercising the objects' driver programs} \par Each object has a {\tt src/} subdirectory that contains source code, and a {\tt doc} subdirectory that contains \LaTeX\ files for documentation. Most objects also have a {\tt drivers/} subdirectory that contain driver programs that exercise and verify the objects' behavior. \par Once the global {\tt spooles.a} library is built, one can compile, link and load the driver programs. This can be done inside the {\tt drivers/} subdirectory of each individual object, or all the executables for the driver programs can be created by typing {\tt make all\_drivers} in the top level directory. \par Let us look at one particular example. The {\tt Chv} object is used during the sparse factorization to store a ``front'', a submatrix of the sparse matrix that is worked on at one time. The most expensive part of the factorization is the dense matrix-matrix operations that are done to a front. The {\tt Chv/drivers/test\_update.c} program exercises this functionality. To create the {\tt test\_update} executable, type {\tt make test\_update} while in the {\tt Chv/drivers/}{ directory. To execute this program, there is a {\tt do\_update} shell script. Here we can test the accuracy and performance of this particular computation. \par The shell script has a number of parameters --- real or complex entries, symmetric, Hermitian or nonsymmetric matrices, sparse or dense fronts, sizes of the updating and updated fronts, etc. The message level parameter {\tt msglvl} governs the amount of output sent to the message file. When {\tt msglvl} is {\tt 1}, only timing information is written. When {\tt msglvl} is {\tt 2} or greater, the program dumps output in a form that is readable by Matlab, (and, with some tweaking, by the GNU Octave program that is very similar and free.) This is our usual practice to validate the behavior of small parts of the computations before we link them into larger pieces. \par While the source code is very well documented, and the driver programs are fairly well documented, the shell scripts that exercise the driver programs are rarely documented. Consult the source of each driver program to understand their accompanying shell script. \par If you want to get a feel for the speed of the {\bf SPOOLES} library on your system, see the {\tt test\_update} program in the {\tt Chv/drivers/} directory and the {\tt test\_solveupd*} programs in the {\tt SubMtx/drivers/} directory. These are the programs that exercise the BLAS3 computations used during the factors and solves. Remember to set {\tt msglvl} to {\tt 1} to get just timings. To test out the numeric factorizations and solves, see the {\tt testGrid} program. in the {\tt FrontMtx/drivers} directory. There are similar programs in the {\tt MT/drivers} and {\tt MPI/drivers} directories. Many shell scripts, particularly those that deal with the ordering and factorization objects, attempt to read in matrix and graph files you will not find on your systems.\footnote{ What you are seeing is a snapshot of my development environment. You should be able to customize your environment. } There is a small {\tt Matrices} directory that contains test matrices, which can be used in some of the shell scripts, once the files are un-zip'ed. \par documentation/Install/source.tex010064400020550007177000000121200663623406000203730ustar00clevecompmath00000400000006\par \section{Modifying source code and new development} \par One of the strengths of the {\bf SPOOLES} library is its open design. Objects manage much of the complexity of 140,000 lines of source code. There is a great deal of compartmentalization or encapsulation of data structures that make it relatively easy to replace modules or extend the functionality. \par To make a new object, simply copy over the directory structure of a similar object, and then modify the header, source, documentation and drivers files as necessary. Let us call this new object {\tt NewObj}. When in {\tt NewObj/src}, typing {\tt make updateLib} or {\tt make -f makeGlobalLib} will load the new source files into the global {\tt spooles.a} library. Or one can make a local library by typing {\tt make NewObj.a}. In the {\tt NewObj/drivers} directory, modify {\tt makefile} as necessary. If the {\tt NewObj} source code has been loaded into {\tt spooles.a}, then the line \begin{verbatim} LIBS = ../../spooles.a -lm \end{verbatim} will be fine. (Of course, if {\tt NewObj} has multithreaded or MPI code, see the {\tt makefile}'s in the {\tt MT/drivers} or {\tt MPI/drivers} directories.) If instead you have created the {\tt NewObj/src/NewObj.a} library, modify the library line to \begin{verbatim} LIBS = ../src/NewObj.a ../../spooles.a -lm \end{verbatim} so the new source code can be linked. As changes are made to the {\tt NewObj} source files, they need to be recompiled via {\tt make updateLib} (for the global {\tt spooles.a} library) or via {\tt make NewObj.a} (for the local {\tt NewObj.a} library). \par Any driver programs will have to be re-linked after changes to the {\tt NewObj} source code, whether it lies in the global or local library. There is currently no connection in the {\tt driver/makefile} between the drivers and the accompanying source code. That can be easily added by the user. \par The flat directory structure and the relative independence of the objects is not without its faults. It makes keeping libraries current in an efficient matter difficult to do. We now explain some of the details that hopefully will save time and confusion later. We focus on the situation where some change has been made to an objects source file(s), and the new source must be loaded into the global {\tt spooles.a} library. There are three choices. \begin{itemize} \item If your system does not have Perl, you must call {\tt make -f makeGlobalLib} inside the {\tt src} directory. The {\tt makeGlobalLib} compiles and loads {\it all} source files in the {\tt src} directory, at least that is what it should do. The {\tt makeGlobalLib} file contains a list of source files, which {\bf should} be the same as in the {\tt makefile} file. It is the user's responsibility to keep these two files current --- add or remove a file to/from one, add or remove it to/from the other. This approach can be quite cumbersome if only one file in the {\tt src} directory has been modified, for all the source files will be compiled. Alternatively, you can edit the {\tt SRC =} line (or preferably, add a second line below the first) to reflect only those files that need loading. \item If your system does have Perl, you have more flexibility. \begin{itemize} \item To compile all source files into the {\tt spooles.a} library, type {\tt make makeLib} while in the {\tt spooles} directory. Execution proceeds in each of the objects' {\tt src/} directories in turn. The Perl script {\tt makeLib} found in the top level {\tt spooles} directory is executed, which scans the {\tt makefile} for all source code names, compiles them and loads them into the library. \item Inside an object's {\tt src/} directory, you can compile the newly modified source files into the {\tt spooles.a} library by typing {\tt make updateLib}. The Perl script {\tt updLib} found in the top level {\tt spooles} directory is executed, which scans the {\tt makefile} for {\it all} source code names, compares their modification time against the {\tt spooles.a} library, compiles the newer ones and loads them into the library. This last step can be somewhat tricky, at least when changes are being made to source files in two or more objects. \par Consider the case where we are running the {\tt testGrid} program in the {\tt FrontMtx/drivers} directory, and we have made some modifications to some source files for the {\tt Chv} and {\tt SubMtx} objects. We change directories to {\tt Chv/src} and type {\tt make updateLib}, and the modified files are compiled and loaded into {\tt spooles.a}. We then change directories to {\tt SubMtx/src} and type {\tt make updateLib}, but nothing happens, our newly modified files are not compiled nor loaded into {\tt spooles.a}. The problem is that the {\tt spooles.a} directory was modified when the new {\tt Chv/src} files were compiled and loaded, and so is newer than the modified {\tt SubMtx} files. \par The solution is to modify files in the {\tt Chv/src} directory, type {\tt make updateLib}, then modify the files in the {\tt SubMtx/src} directory, again type {\tt make updateLib}, and then type {\tt make testgrid} in the {\tt FrontMtx/drivers} directory. \end{itemize} \end{itemize} bj/src}, typing {\tt make updateLib} or {\tt make -f makeGlobalLib} will load the new source files into the global {\tt spooles.a} library. Or one can make a local library by typing {\tt make NewObj.a}. In the {\tt NewObj/drivers} directory, modify {\tt makefile} as necessary. If the {\tt NewObj} source code has been loaded into {\tt spooles.a}, then the line \begin{verbatim} LIBS = ../../spooles.a -lm \end{verbatim} will be findocumentation/Install/cleanup.tex010064400020550007177000000042320663623423400205320ustar00clevecompmath00000400000006\par \section{Cleaning up and packaging} \label{section:cleanup} \par Let's say we've just created the {\tt spooles.a} library and then typed {\tt make all\_drivers} when in the {\tt spooles} directory. All the executable programs are now on disk, and taking up a lot of space. To remove all the executable programs, we don't need to go into each object's {\tt driver} program and remove them one by one. We can do this from the top level directory by typing {\tt make clean}. \par This process visits each of the objects' {\tt src/}, {\tt doc/} and {\tt drivers/} directories one by one. In the {\tt src/} directories, any {\tt *.o} and {\tt *.a} files are removed. In the {\tt doc/} directories, any {\tt *.dvi} files are removed. In the {\tt drivers/} directories, any {\tt *.o} and {\tt *.a} files are removed, as well as all driver program executables. (The {\tt makefile} in a drivers directory keeps track of the driver programs in the {\tt DRIVERS} variable. Modify this as necessary if you add a driver program to the directory.) \par Let's say you've got {\bf SPOOLES} working on one system and you want to move it to another system. Even after cleanup (via the {\tt make clean} call) there may be a large number of files that don't need to be moved. Or perhaps you'd like to {\tt tar} everything that is necessary without removing your {\tt spooles.a} library and executables that took so long to compile. \par The {\tt dotar} shell script is used to package up everything that is necessary into one tar file. You should modify this as necessary. Here are the lines from {\tt dotar} that archive what is necessary from the {\tt A2} object. \begin{verbatim} A2.h \ A2/{*.h,makefile} \ A2/src/{makefile,makeGlobalLib,*.c} \ A2/drivers/{do*,makefile,*.c} \ A2/doc \ \end{verbatim} This {\tt tar}'s the header file and middle level makefile, then goes into the {\tt src/} directory and {\tt tar}'s the makefiles and source code, then goes into the {\tt drivers/} directory and {\tt tar}'s the makefiles, driver programs and shell scripts, and then {\tt tar}'s everything in the {\tt doc/} directory. This happens for every object, with a few minor exceptions. \par documentation/Install/afterward.tex010064400020550007177000000002170663623303500210570ustar00clevecompmath00000400000006\par \section{Afterword} \par Any questions, comments, and particularly, suggestions, contact Cleve Ashcraft, {\tt cleve.ashcraft@boeing.com}. documentation/Install/makefile010064400020550007177000000000270665014161500200530ustar00clevecompmath00000400000006clean : - rm -f *.dvi documentation/PP99/004275500020550007177000000000000665014163700154605ustar00clevecompmath00000400000006documentation/PP99/ASHCRAFC.ps.gz010064400020550007177000022141170664741211400176150ustar00clevecompmath00000400000006L6ASHCRAFC.pso%Ǖ OE՘n|F3-ZRWk/R SLVfR%5﾿eRIiŲJd7;yy?ώ/gp{|z򏯾{~p^}͇??ŗ^x0۷_}^}xOu?"_?mz#pK;~Wo>V/oᡴۗ.q=~:_Ο׏\_b/`ww7y?^'ż?Wc3~Jw~Çwrz~C_|(=Ż>r wy].۷|gw/}qō,9_zwo_?=|xϿ{v^~xi}|7<|x/?z˯z_~|~𫿜_7?|x/>=l?,z4|y_o_7<}֛ǯc̏g,0g-<}/w~}?^_?l/ҿ^~Ňww0~;֟=_嫷^~OWtgqN~W_Ë߿F? j ˷߽z|?<ދܿ|_9E?o|}~6^yO_~x/ه^fϟU?~qzݟ~|<Z7_?|L^{+{~/o^W[=7uw?|۷W|_§~/Qc/ח_Xb޹ux?~ ?;tGv hi0_|'y՗|]^?7i׏?~GO>|OW<p?; ~f[(>ާƫo8?~p/>N g.9) w|_F?9'̍Z㏖Ͽ}/?اGU1aY> çq|Tx9>}t^x㗏|3Opa?-۟|?]|^s?_濿}xPPx7MG> q]4>̥_g?.$}_|_w=~۷o~|/cZ;C_6y{d䘾z}5t/K c?xx~n7o;πCǿ|zc<>{>~Cʟx3K;+ 4:e/8_oKNn?/??|Lj{|Hi!oYy]߿kçWg-埗oY@__~?̍f^zy>zw>|BU,_OCoisEC3?]g__e#4|OHt7'4&Swqë~u{M 閈ˏ}H{_a̅gL~|S`]G R6+_g/x~YWט>O~wò^^?Ǐ?}~XtNw?N_~Og'| |-/>zRoIGxdq?2_}gϷz:$G')eg; 亿}?a~㟼ѳ@p2/|ba~G.c/_#?߿sW?׿br9P߾zOx-/߂a#<_|xׯdWWzׯ>>?.>y_|_קO_$B_o?Sy`E}3ӕ|7o?Jy0P7 (z+z+By?|_={PϾ>|_{7l7gW*W_={|O^?{]Tx n˷^?u׳wǯb_m|Vn?$#}ǸƟ_>~_6g;4>ϣxx5yg篹ӿwxg޸/_޿zzwم]?3[[SZceF>?Ͼ5S"ĶS o,+ğV֮BfgV}nTThT\?Aw)r/}z~x>[0R}q=-nw/!3O /<ӻӷ}U; ǯ}z';ſɓe*yo7Oϲy>γ|>;O߽}zxiwߟ~߼{| O#W+q_|W DV߼z~#g~JS2߾]'36o߿xZgLTOo /nϘv<ϧWO'6O OW{ߟ^q/˧W˯^q/L^q/Wo^q/{zŽW^+Or/ӫ^-V翈Ww/׏Ohx¹x"7<~mi5Ox„K-Kͳ0r>@ڳ0rO%7,ՓK܌^w^={:~%wY%wg/쥞͗A ?yO_/von^>{4A.߽x? KFH׿|^ໟ&%~z O|x|eigۺ;\[zS{ُ4z1X|Wך%K-53置>?׫{ﶜq u糯q={Rݏ_}O;ùrlڽR֑:wv\k΍^Ӳcq]0֎ҮQrC=X}LX]5\ap喯z]G{uCnKƤ҈)6f'p1 wXss-뼎PnRq\c09p*|dGD x\F{dxqeX׈޵3ǵ)Zko ;;0İ~uOku|k7-;׊9vWĎ8#ֶ^ sE\"pU+`׋@gtFZֶ{ 8Vr^7~?Q];v&b7&a8qYOa+-߹}ͭm;Y)8Z[k,.'`r?K(fDq9p/_ݘft;Yu{gBƓs/w14uBϒxpnX(L\݄q-=mxZo` *ZGi)b܃{mJgg'FX`tꪪ&롍HliGa n:Ѷ^so[9B(ylяk?B;A]id=׈ظQeҎagXu׵qŋ`l7 Mߍq`F•RJt׍8h84rj.w+D⫘j!O ·.Qqc.Ďx87aH Ws(t<ͲcYW0xTp/[-(|] 4ƭE[Z %3DA)i= 흱79˻\Q2Pq.Y\na:3ygwbd rUETHJ uD<]o݀Yn `nm5FUay$feR*X[Ar\-bMxv`rc0p<$t T`as_DFY{Dq*''f~rT\RA1q({7!<~34%{^A.2sH0}9Ƽ0}cԆQ[ G(R#l]p7yA3\Gjd<',r+˱5'ijE8 H4ٽOn ܉݀>7 0TfBb~R.L)SlUreht єم7#qja|L,@ 8q#xG" ri [gHq c iǙ437G@^V4gdm1=ȍn $B$E.]ݙ"OeC 8ý299}ϰ(݁[5n \UYɵX6.JK1vD'˦U\`Q\GD\rs1mKwf#lr@&G\ G!D^` `Ȕu|op&& s""&q ")vOpqL=,yj+~sF tq؋{jL$bJCa~.#c1F窸ȇ5H{@ d Dlp.fɁVLō *^{{eց,)ӹr1;4N޽Lݝ'Wrۖ^d\Ͻlh|2?[ǺÄxÄ-3q%\ݔYAt8 =|!#pH<X bn9b6سtzJ`{e &yBl0$ 7|>F ИsY@3xk?\,2hJnϮ 0= P@<`_[}&sp udJ sN1 h% ێ6w ,תV.FoԜ!`2e!%@ױ%0" X!\s!,wV/-f%NȈd뷇!`be+0 .8Db4v,$`\Vg*!ofn㚘 P!)JA0{֣/:ECS:?1xFx`y/y2.ƭMh ,\)h( #u`7pygLЉ+.; q`:z<.]5h9Xdd&c' o| YyT9LGn#]'ς៹A:vZJ8B+C9B Y=l-ѓDXk"NIf <e/<7߲zFsx7x=a4R3rRXk§V׭7 y[ݔ _ȊAØYh( b{I1@T`h^Y1_j߈`Ct:D nb A%ӺPVͭ5v\fo, s=",V0!Vp%;`|*C'PnĸA7@o4,tlpkۂmoT<8ªi@j' K s | -,MA5'$'zƣԠ6tp@ +c"x#x9< 8GnUgwi . ~7ύ%7|ۅ&IaVb]Fp`$DdOA:sȿӾ{Ur1ߺѥ-?p8jq|ʂ/weP ڽu79#΂\YT@kkGO@}ܘ#QqcpB7 L,ޡ  x96bgG0V8 `7yp}Bֺܫ礰^x;agz(3ĝj;Č]WOX`(ԯbgewȕLH ) xq),cH8e73 w6- s?qHtLF O2;XN0vGX=K/$ | &t^OB83=XŁc d@N@s-)݄z@e 8?3JU<7OԈPڎ --duEQD6%b mr.pĀ  r@󫇤 l*Q=@&n+~9Ǵ/XKgir1)ynL0NYD@ C@%*uA61SWOܷ`m%xGO?\D;ng3wœ˲X0}a-O- .4mX+#yA=6=>'RAge`[ţݺLgȶpr#+TC ,09έHD. QZap \ 16pe4k]#0xn +a)`e:^RG]s!SSYnO9̎wg;l9 ~78LB\%ȉwe9%k'Hw_1Ul7; `<T&0`SP]"^כ: 1@ω} \ݾYY oHN1 f񐣀Z+v/DgO vXPe E:@<Y&qo,n֣׼7;/(|g]dbpW=۹v@se|NÅ r$NBnLmvzzTG0̀v8 Dh&@@n( &)_0a s^<+q@qD@*u,8px L1v*7VP=cM3@ݪ\ZXGbKâ9ȈS|.=+ Do`8`WnwW!bDEkw5*8ےܮEyx 3;cg IIlJx9/܎AAɣ$߂;j$I];ϝpې†BxY@ *;w- 5B`Az{d.=m7J.|=~|i  X u{v}g+,V;7/7PٍdeZqaj*8nX=%|s#vq ]grw|T+K Bd1=2lͯDoffb<^{Xx8ps\+g@-X53'wϱ(zz">=Aqi`ke'fiF(]Z7%1@8 CVw;53;ß;\x.ZS1N-nnøoMAzn_ld(2{2b }n̔6& !gsKnoh{VܕаmXƓUXS^xpn@ц',z x|`By\\|Sq {\1#9{ÿlc7f*XL@s:rUSD[XճAd czHX=PXA,]kaSv`h'q! Xӫ9<;H]X 8|O! m!Do#n*]*(nn6h{T<tÌv7y_#yX+ˁؓW&pA e3 )?b$q+ʶ v v#m\}y ky;Y< g͹c.ǀ ‡H]<$r_/րu<@mɘ.nX{xz ,f*xx:j?Z]a&G3EyT `Yy7Z 9U0T./ (h`2L YWs'"th&gfIG%)Ap?3"`2n؛Ǧ:f<!L3 c򬱍kc)S%h5ʈF0-^-tB") A8̣.P20V, -˴Pq6y+V]1QguFn2".$HII󾳄>!XY  ${x^0ۥ *v>`TNmnyv&>Qe y$ʹԻxbεr}SclznG]M&Y,&"kޑ"p`2g#Evy@qE0dq^VI%-ܻߞ2oche7^B1 ndVd_͉d6gGMb\)#y7خ!;<P gi dC`UY붕 @p6k3)b`bpSI ('.eSrdXpQ̺K2Is#Fqe@-v`>C"y?XI; 0#VK0L34LIV`Mgړqf|xhDDsv XYw<́"/su,XƯ03~T/{^@Lcȏc- X[""cpʒy1`q'* Ma=˂>U1  K*+\' Ǖy2xPXfN#뙨̨ly̸&h-)w]*A(e-i<[.`_9]P[;q0!x/jg J,+?@,|tg+p8.֠)U!EM?;D FnV6`Mߙ̄G4eB`xS\LhR8+XzKtN%^{ISf^p@d _ŗ1O4)L̔H|'XB;*rIg\c g5z"K92:EȾ Uݙf2A'G=V[" 4v!1^[1@DnXXm#|x8>Osg3pU8-뎋'xUaEE`ٯf#;0"=&Vo"0>s ]W[~A hD G||c7e< q=-^mi^1nBٞf0Fϵ&LͷZ]%wBL3 ps[(.pl]Uhw-/2 [Sހ3Kn["bFO: sOKGdxN-wpOtM 2Ck6>RȺN6/kqg,|{E ͼ^9$?DmY-63ʹQ[gqEzښp߉7Y+;C)'zy+\3=;`=;~8iOiԵrN,GUc w#=Lx,`@ep,>l*yb.B HL&';7EK'RYva>T\>^0fP9dMz(l9 N ^.9.ʁ\2]8-VUP3G)CxzE+X+P!Ԙ+i)xV mMXX.` \ԎgSn3.m=+SF%y2=ZqU-Z㎺8I\] IP hppA8xe$sY HaRjI-*dE3h]wfg7 U1qo&C|gOKoG6z*3s >xΘnT25x,xD'@Ju"< Ud:Us&H#@5ndM#+4CԖ;܏ro-5WإDx Ƴ-Rpc;){$UW' g+FDiWjzrlpYbtO ^ T@u xE8i'0V`E3kGallxl4WIO=Xd=s!ݡl542U0Sdy'ja Do ޱƒ!g+_'.< z Y,ϛ۱ghKAI"\(Nm;p' q}ȝQȸ~!;XsYj?2 1HZX{c:ڮ07r<<b,lVp"PZs\~pb)BʽeB9lQY(\_*%enP HuXpCc3d GS}u\aJ`Sˊ~7ߠ[@(0/0k6Nu+#K7'.6,j<G"?q7x<0 X_J .L~l!N.ˮH)J| 5<|;YV팶9Y3}SB oV ]@"WQSfCϝ$X=se*ļ,,gp:@XaTdR<# ŲZx-Tm)t8$7AgUݠu(,ܧA%zXݦ w(f#Ǚ$ [;: >\c{1&]n9BVW_OiLŰZ!I b<7;eu@{L̯KD}[]q5Kww[@YЋ bڅ{]~ iJUNl!rv>l튄uٙ<(7‰Kj,VfdAT˻ëC8Vd)Yja=K.+X+g ^5:c` R8^;Ll, ܟ-_b@$k &X}w`sᔗH*1AZN#WwL~SJJpY:Štw\/ CV M]Q8sc˽Y‰.p@c"dS sܾYl5nPn~Ja骔 9e 0MZp$A([?JY7۸nX`;_T Ho6.R;.Y!k² ^O|A;M/Jp-M#7Ҳ6DpRpJkV ϳ<3ZQYXBC;S%5e6Q3F_ | ,ϒd؇)!3s[RM`]g^U{,TX`gd{PfK==|m԰-̉WԊ[jq4xUwiWaK< ۷g|D' WBJ"J]R/5)T}*5ř7T5#Ԛ+Cے@)qxN)׺TT$k{HOJ1$nnǹb@Rg n%P"Q08'מhe ֭M_ 1ܗrM H03"<_2KuI~"6z Q{8 5b}px`Rhx>b{݃MTi:/ qqǽ#P.hO1X-۽.˵]|0k!{JԼ03!sbߍЅXzDĹ`4I GG+{ & @<:1WMd2C B WISuN8 OiyձV"DXѥB^p[>f #/c6$6F((IjXAsxUR BeH45 u_+o#tsH `>(OxvZ$gj$ Uf,XqXLH*k[} 0"؅cUY7xE:e o|Ji-]0Xu(Ozb .tYkޮ5wq)Inr(Nɰ:O"vTgd?mLҝ8 O)>s7TΩ{κ>7e0kʆ)r,z᱈&y5$=9a3W0 l>KE^S-f[^N bүxw`5⓺. \s %i [6wz'؊)&hq^> z`=$eKk~ɗIql7T5hSpbS: C۪.qX!D ZȞO0®@0 ~䞑\Rҝ3ArX Kp4kΎ3t + uNeuˑ7'At{08UꒀO#SC\ʳyL I#Zr=DK:ap>`j0aC Ԑ(|Xj6,Y[Mbw]^ne}OA(uܸѡuٹct\V=(/B ş"X%:r`]uma &!]`؜@XxjJ88&u5|rTL+d̙넛F7R β՛l<]F[܁:*YmZ;ahmfYb<'F5b&K!aຫ|X(ɻ`}aytu)Qr2IdY\'Z  B>8\}}k!lѽȭPO+^:Yp8O Zn ؼ Mgab]z J,u*~۴ ɴRɊ^b3K^jRf壬[X"vEHFi}χ CE,3!R-ɓƮnzm-"*GϱѹGT;;m^XSe<<r3oS7Bge8cnecݛ'%Xo@Z3TG٬үxX fI*BSX?hѾXC!tQS< իqW*XVn !bm_NT%x4oP QY^aQEut%#׮`Q➠Ub/=D}. '>ܖk3#@a>4Ae|{R8\j+.녥/*`2$m^#wn=%`%iunCY0MPh\b[8Y>N]9 =Wӕ%-"2S-<̹faD*%ܣ# }{,>wamBu×I*=w92EwnQ뢄md}4ʳ{x+qߊb U'ZSiEmU̹h]3n ֋1hFl)ƚ`Zr-S]q l[fvk@=q'XDCPֽaSLv~X481)Uy"=xSFW_M[]Ȉ3|Bi<${+5&nAиՀt~.2F'fp-#-)(MX 8r37j.SFy`[CtHYx`9[V\S=>kPRY}n] "lpV f|"hi% ` AIl?ԇBS#Y؎v2X 2 *JIVݖ\s/tľ:Xނ4m30CM0_c8L$)yx+s=;Kۮnʲ_!kf\Hﺑ TW<_79 $aG N N܈[i%؍eU76YaK^cY,}"iRGXD({z% H,RԲ>KW:R`@7$kd--ڝ9ǹ`g¯xdSWyn_G;} ]cܧ{[ RcS-5`:UU"Vx}npTm@-Z_1le nګ[ OĨw!Ckq22 [jWlA LW:Sf`žxܥЛm̀a b #[kJb!, ֛tM8[g&'+e{FYXDcn`G۽-IR`7ղuYsqj4V['Yv:RMaw ~Z"oi&Μ9DMg-?t@=C kN\5[1)4:7G UyGm}0V6,т\p{WJ~ j6VMir[*%yed6 XSő W@xL(Mve`&DZ%{0GufWn&AS][u0lf{9Γ5XU!9z<}Ae6Ac&Py: O_.6Ij96-  A+K's9 :\V)Bm">T*KA QL6-`U5رw 5v مVJŖ\'zM[qD]MZܭ%xnPjuMmO{T2S="U^RĞ)M[P_mw'VnbovQT?Lqe  QAM)ٕ*SnT@^<R OLE*0GӋ>qH#ᲪXX>"qPQE\lvRG9پ-&٪W V ٳP9fBPON;@*mi)22p+ύw1&K8v凓? p;Ӯj)@ȹ `ELKG3.ñ kYSd;nʤ!Hn~%nMyl,WԺvf b(2\leV|2PU!]:ɻf) r xGF`gYZE.$gn²=Lm@ΒzSK=‘+"*9z _,NcfK&$h=pb4")dRj)s#Sl~]oS c\jj`YH~' b^ @tUd7| =^6uDL)d=7۾0L DU0V`&Pdxar`Pviu;qL5@[V.Bx{'[ي-@1Ef᣶AJq}V禣ڄwYs,C`Ϯ,>gP4IՁӺOxPU^l(5Q<41K IfNS.ey YHɶ)W&7NAMp@NyF?|M**v%[g8-wO0E `QQ!"IV2Sp90[#GVmJ3ZUTc!ruI;hl|#EeQsbBfIMfo~N30l̵)z`d0yKRM`qQ%#Hv˧[&;'jm(6þT)Œk 33UE@}>TN֬fJ8 wV7U-zPr GڍĠu+pG+ddH( |Z"GP wnm S }P-F萈vE"yW>o y^ !l ̨;pޏ5,f93c+6{q;Vz=`|נ(0sg玹['fgm` a\]k5c8f'X`u6:mF} (#T[u$hh0@Z^ě Ce 7'G$S=08ŭMb(-G[ͱn|\갼Sazv+ܬrvU=eUh$jfL+EAUp b mĨ}tMT#+&}XH-F삄-,qʱ. }\s( M naJdiP:eT<,1`a%3Y\ d)p1[xj\HWkR +^9*vf3Te+P o?=uM8LiFWkeUڃ9 v6@ =ih#DP%#a&ܶv zZ!)=F vU[n|!OT;K(Ƙym h DR5~b iβd6۹ռ%kA ή e#vSIJ/XND`N OyzŃ_T]ꬮ3xl٪1Xy`M' U#TgѨjc ]GpʿZ1:in oՉ s&!Mr&㖥*E;| jPDiOcz[0U̶$GuAt˴QH>c(DdqXQ`%iñN؃A?ٓM;UNYI$nsL r""Qj:yΖͩcu'SN.BpBVxEq7zh6*T,_Ⱟ{DcLШ&խQgJ[ (^8vQˍlR21Y0=aY5A~ݎv!˺מӻRBqe5uzSfm`uH;D[L7xXv 0'`y?n zU.oɯ:'B*l7 h-)}%&;MKz<цS D Ă3j7s `dMMvK 8:|ib[1%u?[0%#ڦuÚշbjN̂%qa62L99\on(tl^ G~k-֑ۥv6@U`=ce٭vRﷂ)t ʼ*'oq-j%'Y Lp`dLl S/*n!nJ1 2WwuZY\ևUMdJE҇2" UۼbվX%v^Khv_+a6X]eEEgynApm%lMyb(Vgf=>EE`%6 ٣>V|; T*xؑaQUi@4i*q8n˞LmY:+yW6af< "x8+h;v3TS`Ͷx2*dzWS=T5ݔ*9Sae0 d⏅M}:0~VqOE:I@ =V rNPD SP/2fdWSLF;ArNX#\3+mysnmay8pPU>7sWl#UU6)(e q}ULԜE`spcuB|X{)87x _U3w9Y**˚lp2g{O{m۸ݧB)n7 ՚f \(p-lCgmҕ-5̕=RݫMQIb@Zhذ4o.VN2YJIn 5ړJ!9әT=]NnWHML[o"te.,B/ΩwV'8ٝSQ_HaV'+-F^ܒ ÚasY\x6}bʔ>Z7u=h+ni<&lPU?15xH`@&+/lӞ>vh]U=uCҭݓ'ew<z-V1łU܉g_ Jzzz!0^~vZu(6*dx>Dݐf*Je[&~{)UP,(85>%u6+wZrͮ<gNMBсs`Oױ[YjXu]S^R̤A ZPTPEU@WUMP!Aw%8VV&rP*aXu D;ͷ]ùIB0=]Gޢg"dY.Sg,P1*&pxJq=/Ԥ#סD>}w[lv9݋7Sl+sRwI촒"P5uݚjH#ii,S6TA,vX}i n%4n`Nղ<^j0g3YaUhA{^Tz{m;jfYK|׫j$ s6L[ў,x?+]XvS^m; iqq|N0pg .]ZkJ)y0.6Sx6V!n MVoekݸq`%Vd?l3J b(,wkBTY^)ಳ"gᔈ)G9`R,$*heWJck,-V~p .+ǫdL go6϶rXZQ?Y (HJpŕIo%O6ckVMamFÊtEUyCn2aaV9MnmRz6wLqӪ7|\T8MfҬqKztIA;pdŚ[ie̷BT[[t{\y H|s8T*c *1~]=zG|$/Us=vQLj2^)Ō \a v " pZ]!?S~o||헏_۟^~xLJ[߯_}xW/^?7[\7՛w ˻WzAǟOdyWo0^{ V͗zxw߼<0yyo_oŇ/~go_磊/~ů._ן}Y}|k} o~v }ճW?@6|_]׿={q݋?>>{q|{ŻZ?{o_c;%FA<׏}?~}ųh<篹_xͳc<{?͝ {<{#ozzwم]?3[[SZceF>?Ͼ5S"ĶS o,+ğV֮BfgVgFThT\?Aw)r/}z~x>[0R}q=-nw/קW/^q3+zŽǧW/^q/zzŽ'g0}zŽWo^q/}zŽ_^q/{O?^'˽Oz_?|ZxZݟ">_]Ʀ޽ۯ^?>٣ g4/yex? Bg/g/]6^rʝ> +w<qk=볗ԳprWO.q3z=C^rW={RxzKó^rW|gӳ՟z7_~1O=o~o_ٽ>z0L ٌV\1{-?Ϸgg97p2 Lw_~a*_h<>岴٩[REu4Ձ=T9>.F[5ĽgF/XܵVV߇u}<|7O~1xn. ަubbImZ<y-k=n?qc31duq{}3b҂Wm\u흮pƴU-\wJ ={`ZҾ@=ה-hM&dx%u VvP{IN}FEhe M˼L=-~o=}]q5z),_扯euh2ISm\5DK]CY=JT[Imx\A>>5{X*m:ⓘnb ׺bWeWq-[3&e ٽ\#^8zlpwuG+\ LñxUU_7v1%ٳTI)ne&aæ2Tojj*lRV|jSǑcNA9[e~oխ|ɱĽ&~î*XZ)=|H̒[uT֍'!jkٔeۏl1oQ3 dUEE\,%+t3xT8I; 5+\8[(snV$L0a恶V.&%N1C;<|9ݡ` /qZ8q|nS(vg\Z7OEg5ݐ|fܫUn;r[mP|V>`K5.͙?6ՌlbbvP`wjz[N'ۡż{Sjg&mTW^>AXRlj! U0wtkfE@g[8o //jٰqs5;_&LKUє .؀-A^a7-:kbMGc L>{!Z^Ʋld1߿[Ӻ]l:hC5Y#Vk],AۈJF / r*yʶcŸ,.uMl7y؎ˮ<|u-Sn1}T2n\6ElY>+{Ywc)i+ d'muǽ(.2f -xT ՂC9C!Vru|Ƀ;0Mx`z=vo2ʔ 8e(WU˝%/+~f5n+a,1q%T8Wp}7#ԭ2粘&kV:K7iUa<HGd{G{6TZw|bxoz$c}>EcMf5A"C>v,r}0}H TfS++D GϛZ-}Rm-Vm5pMtLK8{Z=3se6 ;M`bi:TIzWPì-l2Ѱ>-%(?j,P'K)=sވg#hsAƚd 89^aQ\ڋoVv[*"_jpYAZlgji1Tҙ^(gl}8z}XҀ-IX!hf% Z2<ދQ̈́pmZJ`s۩71ﶬS%*!* ˟ TAaЭ8M P6rA/m!šHԌvm"N3EY7dM*'T6߯B aઐ"幞L1(!T&P @t`&e%ӘdY&h9Lƽt?~;-n:iΤEnJV=ž|MP-Ԭ6{tZFD tdQCԀFqmM7dV{]Ym.baʬ R`Ġ U/ eXg  ۩`mVx IG7hD&W jLVHDB(ʤ+=_Qj x;]ee)oqڛ`V3Gy|fF.p y¾ ڹ Y/;iܭYI?gd=,Krb7'kYUVr+)}TƑbN{Jq5EN |9+& aXA4,8 6*SgM3@Hp3򲂒fY`m+V6g NX~M& ^uoYm*ыݷ#`>Y"1A8Hlc,4{u -u6wq8]=-5˰*PQ V: a!@R"@Պ|v^퀲%:x+wRjܛ-ީ/#,pA}Y"frtSnm#}VlyJuD] lxq[egq%[?ۓcm6`IU 5;-/ ]bN6l[p'LM?@-aCGwLol5He@РF3Pv(W9-PJbUIW,18V5g1Cm΄>{JrMZmm"Bx qS N{&#+[agf5%[xD~)0iOEWTqp*OVaS7rg ,֢Ҏ`|-*3A]0y^K]XEcGUF|QweW h*I{PHtagE,BU+4eJ]kS~Y偬lqۭTpaD3v`Raͦ7=RZA@ {629j4EU^bx*QՇc}Z% ?[o56GY0KW( DugX]SiAҝUlW2uG9A~0;ƼaG 5X g Q6Oyg qS>d؝GE}x~üGbA+Xlh}J8 h0Ũ(IweaWVstTfKqĀK XE@Glg<۸kWlVՒjh&4xO}V܆"pvNV{Ar(;I+%9'xt%`J R4Yk7}&M.ؓ Ym{OZ\@u`E c#Od' @%Lx;K`haj% L/yf_blje?0&͒\o,"V31?o.uc+a̪"]Yam M YeJ]@iHu9͚l-e֌ϱrnڝ'6NC ^O΀8loC8$qPRAQrAc㮖O uX[W7L[l#7US Pef (Os#&̽fuŃ"2,x5{5N$M9]ϧޏ  {Vǹ@p;oK:\H2@lš_^NVkmdWQX6%]&x?eYyZƧvWT{ z-;P6tnՓ!@<(X=I3sgsKqWZnղ.׎'#_KMX`#0DAwQiP i*Anؓ<~P81ЇyY*)n U<]Vv<Y~׹wsq3m?wX;ٍ-Xu f'){WO1V°8EmڏQ6?qWHqc!0gWi3=wgVC2lAj:b>v\.Ac2d'++K۬i(:ao u 뙇Fޭ={Uun911b􄒕]coϊj?jjzL TJȚ-@.QW}w(8^ܧ+*69}ͱw®A<$<*t\>m0KFZ}[\0+'CTn6yKq{ħEPduF{JD]jF=YR Il:'SD=V@׬}Q;ϓw=Rolw݌nl2 ^<@ڗeWcJ}!j, .h–甬Q \ڵ V[g5,.'3 D!1IŠyB!`KB|`u1 <z&)ntU@Īm3#RsE}]BV n=pEw0omo9%,oQ 7 d@lqH=v}HTꞲǺPN@ȄY$ k{MrvfAli (*3C0e1Dcۊ/֩Hܪ.wOH:mX 0߹º)~=nr+}?`UkB-J1 iE)׾Gf'F +ފj§)TB0/:F>>L*3/M-E%R{ f~ؿ4!ᰚ (EQMrvΔƂq liO${S`OIgh[k;5CʝGDA4)Ç/D_Zk`B,JXM6[U:^[S߹X\Xx5 6rDȋrP9Oe맖ڔVAMͼhuJ+gTH{6ݓ5f+ ]2)62p0aըdI6,+ȳ}XvxL՛TKM e{3zד=m٫I!ݝ7E.6A9\vJ\n\^"e)ffbR&J,r πLj`|7RĞT|rnaR-O3ʲ\SdqnfketݹGZY'Tq:> uUM4Vs26O񸘛*V-g0zLa,wmҐ,JX}@ԦOʶ_6C\GlH*8JٴϹamIXƊ=" ;eIhʦhe0&(0{8ͽnby*=`14,D#(# ܶk!q!(!E#fP GsJJo]x$c}jh=Iqn..NF9,b4$wHNld~á&僭7Gm[i[ X9Y}wI-KnN.w0ՕvЕ}4v+7Xaޚf*hDķ>KqMb3\)5%x4{Orj'l`{R珂M창۵/bpe .6S/M V1RSCȶpN[ƅm&kEQ͖vni'ºn;~ P?|f'&l薜^Z0fy{ĀóKe*8mzx2>4Gwjxz(]=ن%ŁX[1d, [Yɔcd\QssN`;XAl3f&@GrJ{1`m(S1>^_ւAf+bh&h'+1Ϸ-7%۶mXXͳU>sOxxTf}eO+7O$˅(E.aI  y:PdH"n.N cLssYDm\8t)B|g`ݝ%iقF|8e]kV, 2|G<Jƥ{=[=>m”/*D=mf3Xpd~KxQ`/a*j%ob0{jI]<Ә,Yg˪ǟ?N 3}zF7aO-Еv걗}v-;qX:$q]⼲}v4^6^ !lSsp<<ѹW H퉯6D;V!Z\V` tlmn NX)%׬"8mԠϲKYAepB@fW\{;)[ԩX;7MH9Ua{yu5?}n gK?p~ۤڦv];CL SxIRY(-E1Ifgk6߲,vL  6k1R TFfKdAݩ՟hmb׽?fl>"v Q4>p êT;^uX?nI]mi3CR >&Ĭfb Anou L{0v(2k[lJQ`$aVpKm|i6+í.ƥXt?͉YWW<̯Hۍx mb6h$}2In{_ (P*$Ч31D0 !&60’L^ roۨp*<9up̸S^)i\QI!k sp] ewWX6sNv*~J/55M7fD`}5Ӻ˜wh=X昝&o~끱+AoDn1冢f Uق%2 T[<իX 9-@l7yx7aE>' B"}x]FD4%3)Js.c晱Jac(lx-#,G20& \nQL`Ko`Qﳇ\a7%šni$u %'pX9qCN|5f'4J|Fn-.fG0scM#T2j6.*FE6ސ/0jVX]2-R8e%8#@ [dp$4Y^BCك3X7KlgYyq]~[z. TD?L5^kgVy7SiJ,2QiXFzt=91NOͳu5 p5_P.@4P=k: s4jz$+#0w+"^y~,a4憕:0xwX8WE"-=mr)x'K/5dlؠZ:=vYY٪mw#`5ZLV1&܅[pQ (hc=.~\1q6,<XǢ",ӶY׾Ӥd j\F)8kΦ"I lVr,N"b^lH;r>;R Dx 1?oh:ѳb nQ 6YpY"=o27ƍEpٖݒ2[bJEEDy ެ\pmV6;׆&ġVrPm~f-Y6ҥ|zmVR0Wk<]:2lm*_^HTfHc$(sȂECvSXP-0]wΛ0;HŶ2 ɖ_W!7XN_½2Z0xҤRyֺfvKs4L{ڍmkE-lv+`?n2]' ;c,?7m8,SlMl8h`ȒLܛ%Ʒi 3h&$aG0)vx_{.R4V|3Qҋi~xgWj}CJ@ZKh%'oª" 繪 / 3WONK0d'D+i<4%R +TWǝQD5~;<Yqm&ij[}{9gi2WCyt:-$57/1!Ńݣ47tf)$nyL~veL(9M ݠ]]rz.KXHc!A\ \Pa&a VY'⌛y̖ )5fU(bGO^ r"f覧P(VW+jXuwUSm|=OBNY: NuaUO+a^[ZO4nܕ={ϳx!k:s֠^AUUT[׳'f~.g9XR:Sp[9,\z`Xg}b&oK/pؠ>f0z F+qVLQjX\!\&F,h2~3]Ծ 3/ ]~[47jcT߁$\ͅ4׶{"J\kYVĭ(/t?C쉯lX+wD^9`.TKӎ8ӆJ[a&*auʩ4-Cac,j]Z=1,&cYDnkLxY&\ \|dr@@>a`*wN'N +[f|U֛a{p2B i[L<۠a@i+^2ӔiH&0(Ly mz Z@K1X_Z+t]\fm4x}v-ge}7 jRp)# ס,oy=ٷRn@ 1jpuclWJѶ4f)0{`<+Bcdvn8ewYYk5n`3lbmr{X|7q\A<}ٗ 8lys[L)cmC\ V޵W*"llHRxam6Y܅H pIq[Z&'bk(5jP`y_D?Ku2]< P^áKntX92/3a@ %!0pebQ,kp]bZ͈_V_hn*ŠBi%VEz J2 (xϚRiubv`*SGOTfe쇠jMD>$;1tȰ7nOԄX =15Ŕp[HPCI6x+e0ؕ}GlWw@z:+CܘY,̮CaՂXb.|Ϯ 7M"=11 xؑm{%ָTe~CA/aYVu³JN:[X|\ɅEx؛)7ڨFZjE w-b4[U+=Wzzy:/Stjz*Vu6+Kq1sVyz WhnQ-U2qMD7H"݉TRV:6ROSq|QTUg^kb)^ķ۵/ 9a1H{[[blsu\ ߙ<,<qZ=? ^K!{, 1e>nm {qWk͇CIvj7p/(U,r\9XSX/ia5CC ^Qw<,S'i7*x J@軵` oM@[+5f[QnAD6kEha1w7k)`fZe5vuk;V5(SKiaVɶ\\Jv=Ϙ^.ДLI%'՘sp7hFjW>+h$Ivf-R 2yAItl_OvPpBIbJ|GiǴUnЍqw #ilN.gM ,vEZƱ$Cʚ?y[y- 85\z4Z !z;[g3QZʾDjQɻwfPFjc0\JfI(D_Xts+huRT~FԏR?8|#3LArSoV~1r Ȋp Ļ u Ϫn`kGQ5h;Sf|t9boHǶjۃ-С86[_Vg{H5$0@wW-'y$dMKs컄%)OZY:IT05%/z"tkѦ Εʾ)8zS-D^~CoK>HT)s;-5IKĦvp:/$xlH,)pH.*j;[:9hB-5!"C=G_'H{P͹%Es؉v)ʵ]3$T]MfքFSYW!zlR`w {ݢGƎ?`TmKR#JRW!Ҿ]:Š)#{ܒ Az* Ά7pۿzAG8Rne^cјm;K u}l]9UA648~yTMַfF f6%bn3OG-;-Mx v"Tjyh==yZtX:4)tCUe5}=DKUjuGݷ7B6ȕi Zd[F Eq*oeԞS"jԃъ M%%ڱ-9HقFmR?Dw83ǦK(ZZ9 4;q1Kkr?sl%?G˧=ɝ%CUL)-](4ϓ!VS?q$*Q"S*4÷_8H٧gD2KHS~2[EN Z:AC̣˼)#Zpʨ7s5T AtcSMU5#jao.wQSb3N[lhAkH:WS##nx.geo,}ЅB>Q] -JL -;HԺ" :4n!nVі"ZWzѴ|m-I&sRE;?y -*k؝u̪oQKkw$e%wBU[ɟO_ۻ\I4҅mKK sAx\mXTSv.q`'RrdP SCWaM6Q= x, 㡼.T"O3eRhwߋ.Hͧ́N[]23:so\3ֺ4՗vQ'Nu6.TI4@αsCF&ٍp5U%o0:+OM@$[RQze$y#9Ou ]C_)*tu4$d;%S:Pd";+0G 0χDKjܹ 1ZjN8R*s;GTzzI}^@ZW.Fp(*97G+ PMɓȝ%v: ,<'tRemz휃_ݐr3eZ$R݀qHB`ҹ2[S8:.[xTVY SmC0%N>漲z 4.SGG"1+yt]W *NQ|Ȕ &.`?ЧrNl?ۂ=]I'2 SnvŁnipP4aIR\)n똲}meċri sQ6H"Z:}kRRվZ>+iD|C`:ާ:j!PCSqXQk҂TykMqQ!``MqE$W(v`dxt!9}ͪMԼmH76A(yˋ?*wr\VX`r/e.ZkT;ApxztQMRXlZ2nMkQ9ܞ!V3{Gt "5DbNF!b'AugD.!T$4P @Y)9zգl:$NC,/+TQ aDÞsT,bPE Vh[T Ugwzܪi=VANMn A&@{ @$Bu.RƜ a"l7{rF!j?'ٶ)dѪ2]UKe HڬsPJfrKsSAB߹v+XéSG" wq)ͺUrbz2"X/q1:P~KWsw5'l`DI7`5YvfVCS>L6v<H;Pc:Jէj˕x` A(i-S'Ƣn C5)ʾ v"@).:=vkE_Dt`ڨ~HK9ˏ.OيpvY`cO!c'<@bird5}4#W&w$:ē,,epeеFO?rƮVեX> JD]BUwW_[ 8.$fS#{.A%@T[3iK]:BP HAF`~Y9ƒpT=a<@",M1Vfp?+8RSNF@gVʬ*V AoYJa)Yv>?6J+Sojܺ)Q/J>\Mw3J NF˪4Hk'e\.\2D`mޣ:J&8DbK&-((y r(*[YdVe/ Js:`Mj`n߻Z.S3Ɣ|+RL4m~/)@8Uk; qIv\5lǩ6sD]Y,ym4%;l>%Wf S o.gm_#M7/*aw§ 1 !x 9tVx4"xcE`Ѩ:ߋ {EPiH?6yT8fb3mI|ZSۗii+ܳ \,nuX?kQ՛$Nʨ6׵Z,/0=:@NeO]qz'%')L؊Dj^pR֧ZHC7EC6j*Xlm[?BRA [Wɡڑ(L#CI%WD3ǚ7UF.\A: $' U~4&hru}\XӠG;/B4ŁqV~v߼k _wݿ?zj|zy߿o|͛ ߤ7ތӻ7f[|ӿy oW^/޼߿wo廗O/67_7J_zQߜG;Ϳ:/~?^ۗg~wͷ?|}Ӈ~|qO}?˛?xw/__}ˇz)|˛k5ӻ߽/6"_}݇߼!yo݇_~w\/7<?mOJ7݇VzoyQ/~[./~ǯx'_~_}/?|Dŷۛ_~?9~;8ӫ=?_|㷿r/~R}Ͼ=w9??|/.>W}y5Wq_dӽ~;qp~z뗟#߿? w;6O_|[>ԟI ?ם|W_t#?A~/[t _|[f}/r}e~kIf俰_vvI=i?A_o9ο7hqg6Fa_EaWM?'D:Hl~lrs!?|snӷ^{ỿł'G??QӃS,Wt%wPO_(?y+[z7 /ow߼.]w}?w=nxy]u;7 xp͟_ÿ~;A{[]~oqk?|x'2w>|b?Fየru?ۯF-orw~/+c:܄ Y^fWW>_#1~ŵ_qW\߾~_q-W\˿{kׯ^_q-W\?~ŵW\|kO_q-W\~k/_q-kZׯZ2_9󻗯~uo?-^Si⬖}ˏO~w?~?h9˻J_"nW㗟o]~˟rs}_~qGB_ p_>%}W_\ۯWMǟ!޿[5O?w7/[a矠Rs~(Zꌂ7_D(N=bA·o?;Q~w^6ko?1՟fw :S_O/{]W?|D8_=B5{^ڶvDcs=]n;o{OINҨ]?*sL+Sʾ) HBU{KGdC?ש~k͞+8v %L{$u3I]N~4$&ԩ*fQdk6( 5%E'pMeVmzP3vVU1ehKHٷI] *ܷ+c=<5 CZ}K \coԧ,GE9rzYȰwpsC.(֭G!tB_ei}z5h7gѥl?lIrT3IP|˻N[M8vIg--P:=~\ xD` dzy̒)ñͮK!WU UO宥m.TECv9S)eVKT&p'05y]rcC3;-UX+qkda)sպAV1܄/֌շ,.um\J}Q́fYSzlL>yEd cev5zd[_DP_ޚ~#t'落Ջr`p]Ts(ORV ϽݤJ'E$σf$ayWyK9+HT-F@*?Ka=Y$ܧ΀|ēރ7؛1V$YoOy&?@z,י4Vv,sS<ȑqAW^㢊TmtI/>L[4kROU9viMG\A2s1'x)>.rW϶mζW!:v '7c=j&G,:nM ΣJa'xiH@TgX=^z<enp3O]&OXƩ%T}.順S屳sw;b>q;-]U7Sg"j}P3WoRl!0pPpU&TD&Yu)kO\>p'"1˱h'iR8XrbW2Ԟ \U5t,* ZVvmM+Uv^NEwG!= FTT}T0<4 '9 ٱhdBq?#&WQNYm@y)ُ^2*7u߉YĖAH,C9]#K[rQK疑 ITˮIEA7ٗ-SpYI!%ȕW}ZJ,?yelX n3;ʌdGi$oVcWəF{zfg㬇ֻ|Uɴ+ۯ{9y~"ReXMȄ`ȇtQ |drL㮲P [gS[2^&t`p&۪Zs]t)-ԐyŹG;եJ)cZ3𾰆d"tȀyUG$U(By<LUP ԯm@of")gӊf+ب;ސ&Mҹ2KAvmYPV8Nָs*RJBbePe jM19º|&;׮$32W)RH6VUoAe+Z)+R xzLwt|$P㔠U\NEL8RN'k„z>5U P)w r=8N\i,KN.5JPWL%$2`qYqAgW@,ط,Z~0^1a"pRz8WQބι_w/9|+8^JYYԉ^-oT׌ Nᬠ0\֊Mp]S =/C *Fbut "4"d概CۢCuw P>Ax8͂޸<3drXC$#E$g#%VR_ Aj#agoj_BZ&zDtp$<2s@"ub42Tۨ+0 ^3g>;ʶ\(uGMNY_ȇ˥7BU),fܓU3U_@8{[0I\)ǖͼK|~b3-!:M_Ku?0h4?|/m#OT RpwT).*zΡW=qv "csf#o:a 7"5oJ_A k[ձpydq [_:K$*:KPxNȇ1=?ay^`S Zg5ܢBSay{r}Tdz<8J~oi(&d<:$hzʳ&{\-$)YYi*8tw)rv,ȳ8xQH9A9wb}L)R[$DZz37 DRB:jR<8DFF~S"-Ӭ˛l}y p:9yKWSՊQ!C.N\{e?);y+xwOx}>deS9pc:,y=wz5qm6RZ/L!>ؕVI˿+z76Pdv-z夕^ v K tӶ1g_&*$Qi*Ұu1I*sYK3e^kJljxGWH'ߪxAFP?t5(獳iWWLU.I[(!NO B]J"; 9;FapuΉ VױCջEB TD%GX(bÃtMSU%cm`1 V$+.^6.xy!%QO:\:$~%(f*ʨp7uYTqfj?.S]^O'AYBfick݈1N R8y <}Fyj@S:M5&Hk!s1Ͷ)I0b'73/39_bm$@KGB5mTmSD$_Yu=xzov<igjdMȕ eh#Ǡ9m)[ aKK#Iq/`T&syGAh vUtZӧk%4ҙMxܴ'uD'p:p_kw>&dNبZ&\a+Z(VT7h] @HF:57C(<TӅ7i\sݗGvIl*0vgx&pkWtYZNs %^jS=R?+^c)VǾxaw% dꔭc+ѩqKoNlёB CP֪J HaiI '~"4]Sӧ+x][,OmήPm; khsU6y,7|&¥ǣڟ8L@VsVѮt ;:)0N?K!~Fi}H (܊'KbO 2<~2hFw+4V` >-hd[XD?F}^0u T1"UA$Qx  Q;:NgtmK\ ufAt,ڤE?)RO"kBw5 SV2Tuw 37is 2.담I=!g!vǼEם=q.: QxɱQʥNKܡ1Fgp;Kvt31b.aG%AR8T GJZ]*ZȂς&5m#T/]cPrT6FPo%}zptGiD Cƴq~wHZ=$ BVyORޢ]0ڡ3\p㻲]xI׉rg55%Qʷ";̪z1Kבt؁O=DE!͠ӭ,]&)#+QC{]#"UlTTTGMZU{=͟? :OT-e?pQFm}O+B͡q 7we%Ph4#iUd }nnNQy ~M2w}=|X`K[[s-W}SrJSw[WTЗjp!?=o2gaOu8.s.gW8Nk=<򮆺>ϳLlt ok  :ԚSUnAwQqRQݑ*TDuN\h=2d^5uQ鉳D=)V^8Tncҩ- ۊt2%oa ْ4NVq!AՐxUH gZYE4jW}V*ÿ$fyfDuwxjƽKQ%@Q)6wʾ:S>˱{ kU[%*Y䩼:G\ҰN4*Hmd )~7PAS}AhKѶTezJCw$E/7t$7m]A!kj."ȳtxRvyi^caoS!ɲX% '^Sڡ\ӃjJagL6raYܚ.H»n]~~NYW*䱬՛6tMC* -&Pu}O`iD?()}9=CE.ؕl-{Qq;spJ.aUuo֦9%TQkw\ eO 8OyrO@[rvtY3xMD[n2y*;Y[W͠8<[ Yꖛ/wJםGU)NAܥ#W_>Q_nąU{ܗޫ "!f"I.4!$^ ӇpnsJ}Dj4tR[Q/$Z\SgdR`д;ŗe7ۡ4Pym9:vVn6!P;%T$a߲9s%}S'ՖhGZt(7 \f$ Ęg Ѡ<`$A AkjW 2nkKO ilMd$:*Jx ^A\\ON z1űz j)Ct6*łIng*?D@X7@(1xo5GhbJ^a{Slj꩜}֥XG vpv:0ca'b(TmSJ9Yߩ-G} z5K}{9ANml4\W>R˥"K4yIQ7=EձeeM'U&] h(Yc9K.I*B^ԖZ/[{vM +KEǁy$;ٖ]bq"fq7Jtp[E6ټmTc_vtT@r'[iLe&hM|uBӡДboHJo<aDތ_cYqd䅲s ++?iCJ;ow$Efeq9Ni^=ݵEdl 1'mk\1+d':wŇ2#b$ s 5J>7 `6p~4Ls/M z"EZ,riJ?t6GtfT{Ƴ7g['l^>7p $h]{#Ha&']"4*LDNU351𞊔U;4of&,d}8I\,eyUo="kH UG~hvjQ#ORI|6CɵozL32Ӝ 8d<]+D&ӋI[v*9}ʨn|)89[0𨹆lOkI%Hkك=i:z{61!Rx>lVpm9.oj۰tGjX1u"Z9x۩OlM5I7##{PYѭ> r/cszPsZ˻k[']AMn>zJiY-KKN<8yJze3z.).3_%Q_.$15O5 } 1 dN:|ƧnP)Sôl$bՙߑҽso<5qp,Yz5v5u{ {rދL<0w-"3'k mZmzX`HJ0gkl[l@B'y Jgl8fѝȡ֚PAZc؎Tf)PPz8*Ow:L|sW$:tv $R6xITH\[x*GN'mqƒNn{dNo^f%^\upʨE֕r୰7 kO0 il&ϔo׾lY')JR85-I޺(ؽN O\ _/N? 2vUmb)ɟmhF({E53\ch{Ͼ 'o]L,JǡçCNv61&HDE]Q_I>ܩ' !gRlU@9eu'rU# C .uӴ"P?U?+KCt VVe{3BmSyĐTMah=֜FtR&9ŲEx7aXxhڛ]x.kߊ1ic(4@'mR-׵Hjn5]j#ᮮE=wQL5iCPSIXWHR$:/>';5G)c%hD/jTp* ϮW5Oco!nG:ã$Þ+;!.ifnȉu X.sOdo!- 1MBRѓ).'hb㌟ld,'rG^QМGYW@:J{!6UV'ms:jeͻhNB+k6; 4>O6lހ>=)]>bsd-#5) fɆљ&<l/;X˪@iKxzM+EfASAWb :<QL|ZkvwDqڵ.b{AVʻ waO{5ؽIfwbw4ٞERx΋x?" wPi4mYFdOa9_p1,@fUɣgUw~Hf/cMy~ϟ>&0[NU=X,伉J4U[95In7K^^v^>[~|V"+ I" Qj8Y3iBuv=`*iEy(H³m'D.ڕ!;uX?dc(w]@m NԕJC=.NgU=\:%jtdEh̯MɋzXI6 Vh@=}{lW&ũWD,e{ըT߇֊~)|(3DVڊr^%,cg7.fEZdalaS P5F>8瞬TJ54]2!b uIJg2,/QsQ:EUޡ>ӔB[TsA磼,bIxʜ|waPЎe$Maӣ *z^ܠߋz4yiY*/8k*zǎoD%cZ߫K7W.rQu? '8ur[HMxoVouatZJ*s(Yrl8G>TY%˝~{=%x(`f7*+63(&Xͮ.kngm(RET@]0R Mpz]ψ*7q6a(€FD3J hARM@5>m&Xޕ/2KaO{b>´2=/v䯚#J͐ȕiSP5.A (,&S#hc=o2Ҙz.Y{e;ume (x,A`mm! |۔|poۼwdҞj]5$+l#88GX?IVT6¦jG/=ԉr(zv6L\n8$Xcn)D~v^VfĶ*$"y)* $qbSJ͡KzUMk],u17mDK ?-^&Fy q\u?[9HP';%;lS#,ѷ3˾Am ļBRv(Ԧ6ĉi.MiTk$mT2yYڮJ cjۣI:Or(Kr5P˘j;cLڏYŴGH%Ka6IDw#Ʋ48>*Lם$/䍟$L]Eu:xuI\vB#UW hOƦ7 m*}ng!@a tg,xA.+vӫŖuuh]ൎTiөl}X@烀It.4r<駩TQ{z}Mҧ3C@E$~$SUsU9vh*Os 0PlF/iIۧW Tn_)'NgPJ=S[EEI2ҜB>Lm<~M}ĊFas|.5bɱSbp0V 4pb. 휖: K/Iut!^?DrMEPe usnkLBRdꀏLk'b?C堂sg-ÑxtE‘g[r5=tVw1I)hR&-Y׍@v"$tG5}> =USxsdZ(艮?ۈoSLL;|K* &,oP04Yt1n%EqL't%!;M: HЈ U2R&ٷ۩ k&#>ryk[D]*%PWt50⦳)8bgK]F3 .u6OŤE$Q^GRO0[|obY;u+`)>[5Tmu=RJI7)|h7H#ծܴȑa^ɜۼ4yP>Nr$1Ȣq׫U9zjy& xTs<7#HActԴ=;~?Z 67gg= 9go=L);[Y.MvC'$| /H}TPw/Z jTmfõ7"rY_*Pܓτz1 0yieMy3jpPG[֯@Z-R’˾F%͸( %B]p;] rѧGTs*IYPkcS)'/5P2K5P:LLM,v*O"GPE~NeqDPr]aI`F[vz*ƕ#$pKHAfOo=x=Em4sS_ <%24B,pI#MpfiHQ {r -/m(NwQCudAgMFbRT329.z\u8($CZwdS(NQ?*;t^ @,\=!9F̢9E?9TVYxfBZԨ-g՝X3򥍣< rv]$E6Bkn0,ArmkTÊš('/dd;*zu;&@4)uf/xPd#c>fd$&OH:ug5fu]$kAeE'ħKŽwM,yxCMҮ2<<{?=Q)׫|"bcDZ.?44tИg뤫C ާT$ap x:,8 C{[OٻnSZ0[@wtQs8|V%-Sn< TڡMmh\ R/Q'>H٭Fqw$KǺ dOMTgA;"2):6}wR$oT/:C*"A>QEn{.w5J#Iϳu)f$75+6J(`}l9yWqϮ;jS4|e,ț{;~8iUͩϡNQd![ 0{])Ϯ 8W ;-rh^6(칬~{/%1yJXeMw2 ˆe&qھ2%9AՕs\q^ּ+dhxU^-00OS$gSuUJSa&_y=w]MFKJNeF'TW6]KA gƭPƗ4_[m-T>܉TM:ÙKtH^O޸[g%^wU=;CjL*W>=&TjW9tO;VGLu37VLh0)lO2F[PYy쉧һ˫pScS䳨='@VYn5Log_%U\r,fWmGA6u+7@j܊!l7Fk*̀.yQ;$zy3Dv*KJirL16;]~`p=M>Aze*愴)ANSֳ?Ma-xg{aSkQ'NBf?m ,=D08I^iѩdse]،sxL0`Iu՗Q3 V{-vϑ\3naâ+M%1SIlրHDeI- *%TW_Y\BXT@Oԓ^v'lWAf#R#'=< EoyEEuxwvN-/udJV߬1uJz_"!A8cxeuzlCbvhWހ1+W~lYQY&K.a ;ݏ)S^nUTRPhĺ{Pp(#rgV9iK%P]:$h}񝷥(IEM|s7=Zeҩ }7Rt0`'B𔂻KВAm?K<-ĝEz.R̪ƸS&$9 BR:d;ۡ:[W@םb(+N/wx3=!^6]t},i9p3Mrճ"ȤP}>;Ɇq^T.J+NU/}@Ksi] YP.N(kf> V# mwmձg6({nNa6_qݜ#FSߵ ==,RUاԤ* Nlfof 5p[RE\aQQ"m+&U3qz>v̴;)/#4Q'+tÙ?)(HnDu KzReƱ^K(t:g*$2,H<0б#v n*z<%'u{F]RM(^2œi`Xl_=fxjϹTx3+n;xn~9i{<@8HŔɪͩ[VT7G٣t$Uʋ%TTUi]Y'[M%%i]-\)*v89^RL{(D* _>ДB;%bJ S+䑈^  '>RCC]@͹L`)^2p83s&֙U_"ӃY:N+'kZt-$x9{4z[ ~6*+TwEa/ǧ ~v߇޸tXrѺewa=tQ5P}mX!I퇤Kb˕q(fEQ7!= ʋH^Qb7Gg)m8E%星<`]JRS :;$= }0PjΨ9~D-?{;M͓,I"&{ `]/Q "0z KE4^# ec'Iaϴ?DD\0%B_|h ״νUç2WBѫvzN߷(ueW#yBEU~KcKtwO@ג"lU+}NuG/GNGfX&gUS{.sCQL{Z[b_"'+P$Uiފn%gA=[Q_eY秴7V'*دƠ{%"zh[hxzZ= ΤrcώidCɵ`=2LE+G=7Raɣ+v\!3]gXȥZm"icc{4f|m,^㨪\3!6-Lʸjaa\R v-ĊI(i=y\YzZ.4Ϊ%ݫ|ߝʧ~$ڝAVu,Aʰ)ʚ4齢Jvo-BFb Hx'kӂm5>r*r `i*Ӻ5==*+96|s1",`xC=ʞt:w: (MgcMM`3ljکpAC[gJY*$7{SD&c(:hM]V1z0x0wCr{9?YL\N Gn#'pAAׇo\ S'dM?tJ͠`!PrbZ(wS 6YתI% HctMI% s; (;~\eh*^{ pzW. rmC)X#h9( S8M{eTyHO`y* T.֧ rީ|3=r)z-dZuHXաR`w /Nuk%lE7tKf~P5:yz.K>QӰ۔bV9U񽃣s3fѩe;p*g+w~ vIݗ[a2sc;eIo/+F>(y(q =VGze(h`;"y3$.!q/2DN*6+*@2uMޜSͦGe}7wr@آ7h."aR1~:y\`.gÅ[S`9$:wf|Jp-ͩov>Ց+i,kɔidAع:Fr'&di8W. N(%ףzV b ˁ(A\aB5w/xb3rxRϢP4Ә* 鷧׶TND(e\'9e9̣o]簯} %H/ OGxA26*_>v,Zw%;Sq| GϢp"7%[SP ;ZKZPi{V5I"!R͉jcv- Ԓu>dE vGS9-a*MbI:ҡxǡ.Dt݄v\]S{\E4z߶ Le՞$51)M{) ٸ8-ib4*q== Q?Uxc, ^ނN{t 5̴JXMjTH rZfa 0Dz)iIc@^C Uv`i'SmDσӛ X9O$~OťI&̎<;XE¥NaM;(7=UE]@S<^& ᱂z+%tN|toi7 Ac@M=EAlukHRudeؼNk)Kˑ})#6s1벢o0frAO S[l*U"fQGE0t`V+YB%uLQt<AaZ[5ؕe~ \E>3뿠P`ޖ/vN]+WI> ޚ3unߝ,%CLm&-ɂDF9%b[ 'x.ctx A-5W!%h${YXA뜥݇"W.+ Ogy>d#*\0\rChR @Gւ彳bX؉Ud VΦ3іDe}jɒ܃=V_X>uy]UpE ssNvj#=u 68h#Ь !sĭ8ޥx/E,ikr9pd盕w Zz8?7vex,ਤv׹XޮH;)Vݜ_"2rZ%;[Uf˪'($?Iz'mgLo|ˋ[ϡ B |8SE ;=7 g pYۖ2;a^$ѯ|n$R.C;4>uƥ"ӵuj+CcHuv#O1|F%l+mP\ʥJ-MiR\*;_CCMp U**Em͸7Nמ{;x=2Dm}ENWlad^%҄S?~1G*\Dp:ך4ay`| x7UFȉQ[$Sd2_| T5"X|KTƩWO+b)n2ވ ;]ZKbъLV ]b֛dgWPQ)qp*~ΤJ w$#M^YOtpj^KGiPUv\rvr$O **b?I8˹Exڡ'ޤͅxjB&^ }y"m/Ϻ5FW|RJR: XU De)i:rrKZGZ4=2KnNER-J(d-(eojy wIU R R0xu`WO!VtKijUl םaFxŽZҪQ{[JlvVƋ(Sb΀%XJN/iHUwua罳\Q:ڦ:j:¯ᦒqë]r {AZ϶SUKC^xtqjZژTE=OFgH[JƧe@5v܊\j-랒JJ]oQg4$?S񹆰=*8.[B)\%~tb  ho,Ծ|*+ض'in Q5EwEne@CrʱR ߳*b%,:/Xo$ɪ__y߼O۶__??|^~oތW/~/~&"Ƨ߿~߼qM7oRxox3>~O~oMӻ~xwo7|Wo߿Ǐ_{x'߽^>׿ض|~5_|s~?|˧︮7oʯ?~x7_z_{Zo_֟~7~g?~ͻ/|>~O?|{~Mw=~߿߾߽|s[r}߾8k}_|z7{E_᫏_b؏7o?}zUW߼޼+/>|oyV~ۗ}{ͯ{_w_|}7?c/ӷ߽{*zfxݗ7/N.׿k._.7 .߿?]ß<|z//_|+ⲿz{\>r߼ǿ=~Ery_w_|[yşh/?~w{\_|3k?px:_| |e~ϖ\т܎.Kx,UҏX+?YaOgVW"dmӥVV?YX|].thUG*՟~rъg *?2LL{oq_O??ͯTy=[\/zſ~w_~ O/޿?|'ltΏ^ɝ}[-_^ʱ.+,ˏdNϗO_M|v}uO/_Olwb}\wd?}m8`^+Y/?z;ݗR/woG2~mxLhwBj~7gN_qW\x__ yʤ?~5W\?~ŵׯ{k_q-5L_Zׯxkׯ^Zׯ_^Z׀˵o_zG[?.sW>}7~MO׷_hm׸_~M|E|+/6_|5WE \ K" 韾"5$F/oҭŗ\է/t%W_rU?|%W/_|U_rUKK#1O/{>y/_>LS?C#lsb۷_}?w>~Ӈw!LH ߯;׿~G򻗯I*-E##=;_wmgBxwxwmCݴ\dͫdP;$CE.%3sc<#eHH*%T2LʵU. zIQ}ʱͫU#уU,T Uţ3dW40`}LmUQLe}M*6决k\!IR18uu_['-=%kwaM^Yu% YGi?ϡkk?RrpɂU"(\5^_Z&<.!cq:ҕ\o"OBUߣ/w`٘q9\~~|!n~4˦2bwQs!JV5mǵ|!59MASV|P$kwHp;P7^doۛ[?2z^KFP]jW$WeB{dxg3T4X;38*ό鉣rlDFxvzu7g=FQi%yc$%9N%kv4m \<)m&(U}Jeeux ڱEdy7ۮ[J|&YH#'iZ~lT1+'eG˕L@!DkN})͕& Ԓ-nL'hHMG|9 HוTz/Ep#99ZFQ8t? aD"!q(Yu>NU@=YG)xQkw-~27?*yxz $?iAZSˢ!?eaas)|tA"1GV}KZSrp:35>/=dHU>8Iztߏ)iuv.c3^2t{Z*Juxpw-ftp^>o%I,;kZ'#$O4LM'4M)GQB?D-T)׻V-lfT%}y)HJԋ}GA8D}?A(xE ?yRC_r?ámܯ]Taʼ>3?b&EWǒ2Wi!ug% {U-be1f8/CkmiO5E !QJ׉8\;1l/R7֟WS}SUwb0Mv 5+PuvYnvDCuWtP'U\X0>0d,/Aw2NuddţZ>Jt[<ʼn#&ϤgAKj-ԗNK-ZHxq(BHmPt,k/1@c5%} ČX4{Ԯyf-H}Bq p7~͇|tKd$Ǫ}-e)MA‹%88Tpb*_EvUXTdzi[ f}u@ASAʼn]'^㣥#' ZT_H:hrbw:UknP$&JJi od2uHvH ;Ow CȨCE>ݪV٦V -Q5^RZ}$B>p+[0P}iIܒTxuQ"J~k6!M ڬgCr4Ů҃ ]`KE".6-<|k9I#Mc i#Th2j 8A!,gaWPY(qn4lLߗ$^ OyqI$s 8R$ӦpS3k& rMb|o'tE{UUiO>JՀ`NJBďsgŰ=NTAr0 )W IJHO'-ڀSٙoA r3՛ۚ%R^KZN\7KAjm{ '_ZE+=˿3 Ջ>R;I +W91ׅL7uIr`Kѡó œ.9rl;Gá?uM+xW7ş-=Q3A %\Juٴ'(G`{}6Y伔uAhU+ޡ)݂lZ(ڂ<9 ؝H5J&ijC9ӊ)kCpkax16rk+7eՎ*_cJҰ%[|%&ejYO!Xu>N']G ^`Yu/iR $+>Ӯ5W^Y!^JRc%:IzIgys9GxXR^ԭ5~O)z^a!`XW TK;k^TrBU ? 1B H@E&ra `FfLu~VTUO]){5<~D紟=(x3o:"ZTSWv/@KŅMKFv} *@uvu&c"U%Bfo7Npe'i*ʛ4#pڭFQ)+^>u"ɡ({v)z4mPWH';E^d;sDt-Z\_4U*C3<%͈έ| Y]q]IzŎP1Wt.dqJIItX}YsE[t[4+鶯DvKOňYc3EC>q68[so,kϱ&YE{86cXvXU{7WqZ"9://.B7)\=Ddw^VZ_p>IbayRM®)Jdy !*UTt؉r pkQK,ƣ4]"ΰ(PFI{Ys(ͅe@%4O[ߗһӄ[Ml6Ͼ+@31О8咛RFf5ܿ*h١O.M)껐PTMv |C`_vwc)s՝6 !]bU(G9R\=Tcq=*7 `IӓVV9$0yqY1t]oԹ k_o6ؚ3EMf'P, ~!jjGeD/6W"4#?qRqV=Inmg՝f7dd@qTf l,fr\K$+8*:U %m% %NV1:3 T؜%=JȷNK!\d͇m$_F5ޤ3Y䨱|&kcMRS'q;t/1;Q<ƃ5ZuFts;9$eØZI߼5e)%sʃ'%aLkywQ 2!4s, Z"(an՛l-`u7J(x=1j^N/f^Tqi=,]?WeSu*NQ]bgIp3ic# 8 qTk MPta4T~bF5 Sun *MMe9*ģ6VU=\6R*&O%6Uqm-"7_jzP-t"]RZsic>iw0w ):Eg),)㠮JJ;p(EFŦfRQ/P꒿'r,49ϹR^v$RNlvجy'-4OӨrXma6pKŘXFsFV %b[. Rw:*]a6.DWYk }cSmTƬC PـJ4ҫbl9|%ʻ dgUp>#W5 Pl8oOuԓPx]l~j@yn TA2(O>l-5=ν=5{GZ&m4gSsAjD7Q&REA2V<@X75dʤ3GHz,%G_)|`-%*[}T[,G`E¿@l6eZXw]QDR:R[o r: |Y: ^JM~Vndaˏ*oz|u,~O53M@MI ڋ ޮWUBZi{HdǢ@QVxjr;*di (Gƪ. BK`[|' @"X-=RJ,y/KT-K}7 jEBP[E_3YDXj0a'Eg`PmRS,`K_t %Q=r  FͭNe5arkd)'I9宯+${:oqj&$3$unK.%Cr%I_KUPX?w֓`訝euRpJS賳V-QTG ,t{2lJ i!̪ܺsÇA!]k_c,PԖpi5s#>kPbwW$}[){YA{}(:TsnM>XUVIRFzXQ cSXUusQI:4yCn{ i5c$'Q^Xj:\@/pD" .ZocVq#$& N;s#/.ÿz*~ۣcV$Ȯ`G4T N d=dȟ \xK!dwe8\eҿ>)VF N)P5w}loE*d.eeϬ->6Qf]S_:2&y/aSzX= יTG$nפ nDnqd5?t_,p^U&`ag9$0D:.ds, ]:Vz u׶o%9bm$;pG (:Q!#nc\ c6RVٔՎ:^ ͐{L9 z! 'CcMD:h+qi!ɣhxOO, QRݕVՋ{z7vGS +Z;ajTTixGO ۞14PK=(bTp8nAЎC7rstO%cZTcpvL=G,v40M^˶9lD!jSp,$!.a ?;#?n8iWT!-֞br䥫uV1lM6̕ htyy]cekHl3C6 JwNZ΂8bۨr@(ŏkPXKi/ Yhr7Z^h74ltVłO'H^,".K ]1slN*]j 8f7J0;3|LfʝYw.+iѧ5nA9Ck4j^b%UձV6rMOdCkP0 @{(+6 vj hVhV=䏀Qy`z?& )it@D4|(A!yIul7vTǐ/k1}.,S\(V.iT'PW=ɹ4L ُ G ,78J=Ց(q&6هe}_@/ilDZ>:紱.gÆ@qŇ`Q, ^ 9XK MR^3#H[k0\ Fm)/re5e^=@Oq/OQjC`TLN<荸LpcvxS'TdSQ\5gZD^W,+,(F:ODwD>`hVCGG.@=4f]H!w$#L:4^T'*g|JTIk5ITWolH}=ەݧvA{#Ujɇl}K;aݭ̼gFqNvdkT%PD rفq@*q.ObAңE6>D6E)݄a_~WCeIuUYXj jp9"m7o'k*$ͲT`<ñ{ ^bǍ$? pre''pݦ#|wsܣJ9K]Y#;^qu U&TDם%[jlg5SoV ;ZJABza'X̷}lVhrc ܤ>&Y1sS?/_i"w脼^cuDjAAw\JlV A+UY=UЎ*]xMRrmYpu#u& W0d˨"_%L+["D5Az>gn;;ž4@2آ ʙe,;k1o[\dގ}!]TcWTt$Qե̙hL(wTos/Y"#+,pv\ϝأ^za tO:էpβv(rPfzHhUz9oDAf HGs{7/ ETuyu{R^٢1&ª n'u=r>D*က'X\stiNP$a37PME@2j]O HYGn2?tT7]=kQv5jEv Saf=%Y| "[$V9nKvYa5XCdj:Y-UY'=ݡټ\Vu:1h9%vXX#AyN`lQڱQ@J6=HD ӆp7fprcSwg5Wl LKի b20OJh )5; -WORQhg4w/tnqҼf ?;. +UW0Ryk>7əz6)oJe\j-(O͝o|E M=N )Z Z$*gwu.O k52u'poI KSⴿ$P* k 0Bh28dG)d{,v>t=ȔM-p͑Gy'l"ʠinI[H.8I-7;hL5I}0+-uG .˗gY^xкSދ%EB!uJI`5_![My%|V' j'+iަI.$hRI74 Dwה^q[ѽZnX=z j|׵֥: yأҩDpCF@Ab,~r KCj[ X+[%#~N:j5W"W[D*e'+AQi{5+ Ү,AHu(Ry$YTXԁaPu}"4b3]¯:ܢQSK7/I[kvv1m܁"곱Δt~PBFjL ^63+O6}Tv'1Zj N|hE,מfS m6_[ Бyy]>ģ(ư4Q((VīakԞ;fhS/0:\nCS>ôӑe5tHg-!1w[Qֹ:c'nĻ.ɺ.g.HDRu@Hixi-"gRltXIgi[֢tJ9aaOt ++̢ND}]ZUǑ_;+E1-gL.@*fev;dҵx& lP"YD"& ;vh6nW#a#ls ]/V1d? nD(m5s]Wy6tZ.g Ђd&)(Xjp'wa<.ax֭# mc-!?#c(~L+巤 @5m u<@|(= mOuU'Q#?Nμ큊|vU5I g36gQaȒ}8/s.E>Oz[ Bڴ"+?rˮ:Ъ^Vs֦pxv4 gp9R kۤ%!_J}nj ,9KA މ Sb_bI'N{eg6py%s l$%EWA BSX2OAK7@rjfC =2t`v, 8a[ H~+BRz[ Bԥ]ϔ{`C ?v|T[MWΙu'M̼֛19Z?T3npLYu__FeFW\X,"mbxߪWgMnwmVR@c'qP}RSU{;! RwrlSWN&KWRU9ֱci<ƖƦ6#5;C^AYH oR=U p evIM~n(|,~v$8EM,QW&~{/m=WjT9uWg=RNi ׾υwmۮϘm:37r kP4t(aI&l>&шZkoH ,lݠsY*YO&g]I&$%Yڔ$N:WmU@$bt yʽ9Ȅ 3.b+{׊$)q &IWg " $n}֒JZiX9ǧx'\Lpx]Mf\HJkԯ'.1TL Qu fx3*hv* h ~*5NM aK5";B,CZBkk^N`#9ˡg_j)fy+ƫ}Z垎1N ZS_DrO0ȇE}ON+m[I; NÑ\)|RHQM惏 WLG$`H׮!zר@=Խ$H %IG jm{vZІ1Wi6CTRUƃz_$)ji9Ēl@`iG᪏LQm/!DJ$"6 1bmge‘ 2zmRLriC7lMH]k`e%%xIkRmM [μ4yilW-x8;֭Mj:r*ľcjr?ʒÑ6y8pCslE֥Dh^{.ߥz(7v&$+Ah};xO=nBV$:N,Q~ Ȗ![xL%Нfޡ F"*T.=zRgTD2$s\Qdi+Y^*{ BC SN0懺OXWku0}},L"hWLt i/{%8ĵVoؠUD'8#qJGtθYT}L.HGP kB̳yZTOrM{Ir]).keﲲ*m"E%t{fH }w?O63#sX9/;;^kfRnY 86Lmet{6*=YDW* K ?vZUbaqxv%qjm,9LPb8( '*eZOF T)ݹxO f &ldo&Z:BFڝUf(㻢6] AaU?]rUENg]Q$). HNq̡xk Y7ÔqM;Z6gp s |CP~ РfRV\`;6[X-ZSaNR胈ЭǶPA9?cc؊DUQx:{<裖Av7ʐ&m * Q \6G aFo?8p8`44:X9\ler $bgvۺQEר\jV)[ TNݭJf.RBviN 6{,GЅ\{{f@djQXU뜬;bɼ6<%QA> Fwew"m+zP";l$ **B`Qa Kr]1]'00M T(ݜ_dPxDө' U8UdT/MU}R56W.C8y$)=K=e@j_pш`c/  \=adi|ژ{ޚhUTw!]Mmfe` =pGa%Bݹs:v7xɀ@[FUWlo ~u)GI&vyc}ţ$Mgߔ`qV0T9= ]Qq*źqMv#/W]T࢝ϪXFǓ:Ls*rK눑zg{V*,Arݺ.Fw)Spe}n`@U 㹒 rV խc>^Nf5L & ;wxCcSszlgyw, (šciN=XO rUYWdP=vM{]PM)/.8!M7ĥ*T(_ʪúוaGL@yةА%Љ2w4iu:?`Au{"-{_e_M `tU[xUm'dpaǒ*)zajsWgCW']:9[xp+dH,t XxSxڡԘ;pBz/M]qd"^Qqdn@jUP)k}l/w%uѯ";HՃP8xףͣh<%0H*y>`QTIhzjDko0kޚjI#6J,9> #E鋦%%~! V F[9<@%r;1qQ%Nɇq|M8T]I5\LIKʜ)Ȫp:gIzb-s3H{R#[ eJ+>rrܦ,"ꚲ۴Sj<,(CxdTg*~4oa(G]ؖ ]gɀb;*rM+ٔ}d< ,!ӐuR"Rtj&)Ӳ,{8CܛvC >BgR}^9ym %NB$NogYbp0Ue"";8_#1+E^A Xڥ Z9R!s@*E:q>N PXW w;UTv}Ċ @#WvV9Gedå5rј4ܔs xqQM1TSduNKD9o\dKoVlPukGS:T(;abb8)G{ݛM%{B=PjEI ? ݁{v<6RW4"GvҤ&|8RkTIQ1j;&l(b`i`kA}Z5"nT,\~A;J-m7βQT#(]׉7Vq΋=9(v͡^}ՑV/r8hoEr!RtY @:dD 6(R,#~SLNET$i鲌Wch(!n 3 ޱZzwkNɣȤ = F6z3i175VLMgk L\2*Ip@ [XZZa{#R HL`6ohbU'χ%y+U&$fʳQK<<¤(Bv'Mb҆irف"p'^j'f[/\Ihf/H" W}]JްdI <렞4cQT@ˀS?VKwlWj9Wz1Ɂ=O#m<=:cL!w$\+=h>S_؊}$]k\հܿZ8 4@sjZ) Փna4l.=XIMjGl] c=*.#ZZajD2ƪT;au*Luh `^ ?2F*G:\X_E ,=M h\55)w0zg,סA/@ ݬߪn5aGSL@bTnfM4gsyxђFpDܔ޵|Yd*Sn8Nj\B`Uiưc mO8z?03:Y& 1DY@y&t6bO^JDmx,$VپRR!eg5Q]~#,bnY7geMSrH\%D!譛UX䬧M*U/v՚2ZY޳'.H)Lfgk`Ied*dFc]$;XueoyQqxR~,q6l9N쀽\vlI߱:aPOͅho[%ߩT:*5 rkTlulI& Xy};LN<"(,)UhVY5dɫ` bO6OOwPe*Ua5h$عMTuT}Bt$UM-Ǘ`]u|VΪZHNilEݒe 6a-%JS:)+%vTu^tx >j؈ӫ2*[uuۢ&1(2t"N&Aman41uj,"g-&+OzzEBT7չ)?!&;b L9yԪK0#"<&8,}]٥ cF9#X )I!~:K,R}GIj]es$}2k0爞wtM+1"@$ :)FXzC&/t`5S=^mtr 6򴸟9UU9e>^Y]h&nxKKM nPxxFr3Ȅ^ShIs)z6CK Pc*jOdU% SqRi {4NJtRjMmMggήD"DZF5Ϻ\fK{]F6:9CsDeN#'^huLEPʯ~>7Vk{)xCs/.ښK+Ugxz3#$d!}mz^0g)Nnȭ۩wiJ%멥,ǡf2`x9U]2oҀXײLMVW)ylV"Զ<.ݸGwr$%LVfD>DB\șTWAT0< ,2wUM~8CO4Nfa쯡襬M  zǹNE׆dKe MMt<v\~{R[gD Tӕ̴@86a1Ykt i5>nwQ'1LpDVq]?giM讎.uJu.9l]Y 4^5[PРAQmY|]KӖC2wӓ9t6+uR!``c^-gTǭ:2 pasx®1NQzH.̣)gXpMZjkR=mW`;d78h8׷͑4CE aIil2Do Xi]t#W:(6%u:\=^](\(׌z"+P̒Hu@Nk M֨ u($\jՐTTgA 2l"QWʾ I HeYA!m6 ućTM=> <*2*?!_Kyt/5ͳZg<FV-\iDJFEf_mx:Sm_JXR"#JtGga}nIDOT7iƤFT4x6~){x@CZغI6,W!|vVz13HsY|N;ʅ8sZj~EUATi!^ih⨇c=L穌:ĮT@Ϯ͎aK\bDqlֱL[s*a 5VBXEM1t<4pJצ`:!۬0T{ Wg 4+ T!jڷFCmC5u,Ix$^[^P #S.?$W㨯J_(TˢvF]=wmv 㶩jE3y /AOnr5/bۮ Źka* &Jx^4l~Ժ0 йSɬN[]ffLJuw;gRx TLEqEJ'E)15)-uI8xǃS܃;w+8?eKCCZ>nuΕM k&Zj[zj5(kO" Ge+IƩ4eeE>HJll܁]y{R^Rme7N,PjX?mJ 9N jJ䱯x*=zGB{9i*dȢjAGumZQ7UdjPIV=k Qwa7(U-];; E87_H(Ut R>N5:+&vA].ĮInxh/I52MӅwxyzM%}͡TJU+|R{$eLI©>Fד)* S?ghW5A)F@Mxdؐ_T6#^×]agA1:Rܰ-}Vn˝R Ȓ̢OTɕƃs?zF<*wdI:13V,4TʭR g R~naʓPn)џ#T{VBrv"-x^ |2Ϭj':׎3?Iɞ$ȓMS>=gg!՚f:`-U姖\.0bUhjJAfI l;Լ \9١guUQRjM8R]U-G9̽3vj( \EՄ 7:ĺ0R=uЗ#Nl=ppx@O?ZuO2jI |&OKדbHdw.3rBe i2; RPԱQ)WK#CB )y~Iw Hxl{2X6̋Ry9NM~rgaYn$9թU#'Q}"4Om39; CWV\󃷢ҳ8p4 9DEQ6T4_niJQ*yi9' FxX[Q7؉2j t HzڥLW{{-lrUUbDObYݢ؉u6Y-oxp!vjtv1Ww.Ņ] _,}KG.*=Rk'l,Lcϴ(1QeYu]~ud-lM,HԞ?Q$*XMq<ݑc9^&Q)ovUe5S|<9 P%zorCꦼHOzK8N'%b֊"r%E >nC Ha0`n_Gq8o6[(I-)J-+Pׁb[0;#~>C?*wWT9Qiq*TK/o?}񛷟i۶o_Ϗ翮߼ۿW/~/~&"Ƨ߿~_~&7uJ?ooǿڛ˧w_o~ۗo޾zM?O{/߽||~5͇_|>w\כu7\?_~>^ۗg>x~~߼{?oOo/>WkۗO7߿}7_U,~߽|o~w//օ]>|˛[5ӻ߽/B"?~G_}݇߼IuӧE7>|7/J矼7imw~[/5}}'>z?3wB\w_}z}|[2㿾۷_,]L3;&R~[+)/HK;$ (~{ԟhioqŝŸ)}_)]7E~O/lHǟ!?rnmϙO.6q7}_?~ww'G~~OO?_AI?&J~VJV-oU_} wï}xf -{,*7 x`͟_ÿ~;@{[]~oqk?|x'.wu]#EԨC\;wxqߋ> -(/7./+w_⦮ׯp~ŕ?K_qW\7_q=W\_Z+^ZkZ+~kׯ|k_q-+ykϯ_q-+}M;\U\K23~?Aïek5__Y߽QP0yɏǏ~?|ǿwn/DO +OA÷GOMg?eoEl/8}#!ï?QfԾ/D׫{xW~yӏ?q3wT*VcE ?]QH G,H\a' zï+o.|Sp>`Nyvx?װ_|u7//{jXgre8DjtԄ@YH;;;d꽍g(1u=d܏3t ϑwypVTZ}8 A *<Ճ[X/T!才-쎒ssO5˳*lBA8[]{*]T8׻o!0ևgbV3}ԞK;z[hCǩrS_S {ґw5Q58&9WGhq[TA׾8 ]T#,UGLv t> T3fYm\55˸FR 뀻\v4lYttxMШ(7XYMc5ys#QyV/u[^C+JD?"^j[Ŭ*8Xʐn2,JQ6i^gINgZy"z_,>8ByN1m]D}u4(s]ε I+7OQI~kLMtQ ׭R"xXrp-(^n nE(N:;A9=lէa)˷*'$ $V¡cЉvr0ǣM|V<,}rDbH A8*{:ƤY%Z %Օ㽕8wr}ć(k8}@TEoI5a% L. .=n ,ӮKeGѹOb7"A0Fws;p tP_-evY7q 5$Tp'A'2&$NrV FRiM}HWU\ٱeB]wz< )IGowMLޔu]T w!$WvvUO9ӹv" fŠiwe2S1.ITEiH`m,p\(W8 Y"8UUX&$એLBN%!C忈@u7TϩU(KnG (mʀ$MIXo!o8iT|)3M)4!Ga6eJTP:L~1 z'ip=Ic J\u&hᒈS7@.BMH/EvFr+*QKu`5Lkq@Tb/#JVѴխd]wA|4t|B28ՉApP t@(m#GQIŭBh5A@z{3)Hk9)C@'_˪-i]N;P'DJB3,:ْ޳=Yt=|t-Jc_LN^TE'Lkp&84΋b(besOlE_y\$/{jtV)5XC]i*VU!'ٍZ;giꢶۥP TDӠҔў$ڡ8d!;ir-[!\5fa}j:l6-%U 4 h%.S EnpUTizyYysE׻u-|R8Qk ǒ:-( hXW,"=(M\$jN$4H C^# Sp'ŐF^!zdْz,}%YwJǪC(e-Vkwݜ,pRNe ٙP8ǥ~nV2Coǰ)XRjęlޝu͉BT?[{(6eG [+j 1s5_* (㘚'gk%Y@X&NT;8PJ=iӹ^.6k~剂/j=]"+g>o˜ Hu{cwFcJgٺE:KPrT>= gC@ pDވQCKte#N']Td9{ G6 Th!; Q*3ȹP/f6.TITP3"3{^Vs\yⶓюͩ,E 5;x\`ꗝstLl iغkr?g-[Y|]XS?;vLדDR&\=C^&Pic6%(?lP̧v@$\A"棚gTd[B+%{Z[3̸u J\٣L$2TT _ RLB xD{10}µ?*9w{tN|*R= :-t+ NtF0hiP5𞭗Z@jt6PzfHX瞗ܖO_ "m6lН-)keNQZKKčk%Jr١O^+v"& \m97=Ϟ4UQ$9^jjEEly[cWQ^%FBmhF^8A?@ըJ#YuUyO`bS 4|nnj,3aRMYsLVuE^ufvTXZ_rh^u*V)pL0z1B@`:Yzx.-GJY]=߹kkWr @UZT0,g*C t(2 c^=,ݞvo˂KckA؀甙N=rF3]ĥfW(Ks3Fq.)xztLE q2<*G;Hݓ` JLvvezɺ:tL9u*;YuvUVq٣$;j#k9E8"?GgπVU2~Y8mw |7a]ѡ}k瞉r5֋,3?ĢN3lY7L1>J % s)*yZśJ!pڏ-N~ ˂ЃfUG|NPj5. USB;W'Y4Nj*l*ocC0*T>*|5nZh;X0ƞIBYzRnD4Eyj}aU8Om~g̜`peKD:Xr6nCW<hҴhWԟƞ虆 l>g[U bbwmIh:cXJA xenrw3vC^\ijŧHY,޲"h6痕9 ZzKlQ7I*3*YX+~\8j(b6FP~WЎ)&E^УْSћS@kȶJT]<#|P9v..}6y#<.%|txwt`d6JR?Z&T.m:2)'/SE=VbՋpEֳ:6} 9&K#>#L4nS^UMkXV'W_#> 9[7rzrr`(RuUhRWbЬvr^>$怾jn"Z6,h'NY b֞*PW*ϼKBF NP x-&romCbREJrU*q⇩u'$'yA7/H2p(Р9#̧*ˉT4fCڒ}mž n+Sd4 꼪h:aPh"e8;8ӯ?(|gIh` +TxVt Qn6fSM{xw+ -jczj㚈'{uW1B,D)Td4J#hW T4˵z/O]Y%yW~1̺!2)~G/qV펒)E𘊍 ;z_5mY(5WS,,G6,㕒ʓG3:CK[KʛDYb(2$ K7~՗H9SXPd&i)!JͲ'u]xMf:+NN1%ScN)ϣ HQǓ*۰dQN>YQp6|&+fQ,M0O/ɩ@.~=)EqMqkzl%2Jup^U-)FsWWLy۲ME7*l*8`5f^f![h@-u<zo =\@}J,qšjJy'YOWZxυ#{ha}7_i/P@&-faYH=l'|!Wb&er/$Xm [-:"wxigVSj`Q0x0&X;}Rx&)RvSl#MPCWYeT2=D$hn[V#X &Hь .m!Gqw7C*sk2zpǒ>Q]"4:+cqo ICªT> hb뫙}ֻSYCy6TȬLlV _j.tV9ND;E6V5eGTOSUPu;(Z,ڸd؋5]e"j?*&`|/%ޓ;0TB3ox+MgKEC{RQv$^&ʵ٢ b¢r [,(ڰkGiTqbKFԨ>Sz-^0K*bD,jC>gT؉6,N. }~j9HЗ'b͢w7ͧ#KrW&s]}.U6৮֢@?u3Sċwh@H 81Ü" ݖ醐LvvV ٩w*ٝyG@.? z5NΎۑdXHym({}hD(r2VW y]OU𰶪a E5 Pl`pDJrwӡVإ(Ϙu2 &FhƑDWi?β NcEݳ7WGB3hgw:A\w= `ڥl0>WjPsM!ٓ:)=2i{e!ಷV񶁲kd.e޴Cj' QQh;?S'څOl)l \eـH.= R쿛u2)D1Nƛәj) !qLd!K9LI{PM:i4rٝDAx M;XLбƥN=Xojs rmn5\@ӺE 6=ABNCCꢭܜZBuNr@J 㥩zHRȝgNC:w'5N+m iIݶ#;4i}CJ@Vr:,H-iy[#y$\X_ˤ0 zHh)2zȠqy\i'V4lP;,MǎMD:Zǎjmd|PCvd%Z\ϐ`XCEW{]n˾o][ҷJeUJѵ*Wuv}a>:7j[&Iu.:{8!t[lpyq+,|=TRs]~entv<2 . O3w}XϟdsP{m b$Umv[2]] Fm}yϊ+_`d [sBqYޗI"-CA վN)lQKvQ ulr6.H㑶)I3\RszsFA KNntYdCS9q[WHŤ. ETk5ec_RkBPXr˳h\Tu H.4q*񖃳w#ZjYo'E3ARkۇ6Z5 WW,sGMn٣<:!5Qk+pf֜5+ҥNlM~fx(kt8_ڕ".^x \_Ud] /|˅5qכHُք>pV;A_2,j BOJԠ/IF݅%uMRgH4,S~ =#l&ʹ9ȵad pLI=C$l ĴV55gQ r ]("RO,l|MVbIAylR^N(enɪ>hP}%D4-q7 ;USo~g{ԚSTŶyTu&;t9QճSdJX|@$z4Anv0Q LS|LmݱCN{(l;T,睻$U7dL`#X[Sh{mgv'PV.VIf}؝lط (@OOwdMs%=BY$Wur |HPҫhOlT౑@cUr@KPt C*!ϡjf a{r˶űҚxtRLjOBU QdsHp=eN2̑ʃ7񘃘qc^LǚZJ-üȈ"lIN 7/$ D¶ /<Pt )z+EܥYu>Wg/ ^=u>٥D *HH y8u̠a1=vHv*u!(9ڥP_YÖNEYĦx<>a~WT72Q$G:RSPMvp,;1shcAgȞX yg74S_+4AᅑIzt@ӜvS'u}r<&|k |;6ުER'qy mܫ^VGIM%!־=iQ_^\uu>u0q(5l(K7iWgĝ۹R3zze%7*%Wt P>\-@Q31q9; ^:_qZpFB6յw0cQL*W).b=f:@ȉml< ֭#=٫IylZkCh伜;x&9Uyeg& df k{(w =䀦2Xh+j]/@pyW#l # 59{9#[mI@`DABNxU`EK'*%bJW˓0`C_38 ˤl-H tYOiGV8Ԏx.>jGZG ;魩b钄2D)sl>C+zS=k+~N87}Q^wI ]eZtrU;DN&Sp{A$I+3;K2#>]]ݳu)E佺0:i$k5@ z難mLHĭS.k@Ǿ+.`}:RMJ|:'Eg#//Q KQ [JvI VWb gT*C*YZ\57")j 9pXSE{$ s0k-&ꔪUCX`שr@A, 4~[5 P -[G!a5Io ĹR$r~Iu+'fw>c5"L݁}$ mKl8Zc(;ҍ=ǰfY()f|:e$qJ `t؅Np%طƋh*>87FTP4RHnY28Rnrum;,Id9 cZU@óff "]ecQk_/]{6v/fVcb,)M٣z'$}J jCFi1{"$Zk3~+E*mWD2z\~`I4>SGXe%C泳7B+e=exW |o$ad:aXA8.sabur>DluISQlLvîɺl=wm'+*JDM󾝤q";Ɗ=F幣0@7~ХҞ X} 7jXZQUE)-al'uB`Art;y (fvo%?VfKe_[tyƉodMQ[&j@Na(*VWE$7'\r7 8+wrI$ _W13 # /8d7Hh+xNWDj[J6XU#+wX<5[X&lj'M#:b [v!]ɍ-|fi atDe跪(d'۰(ւB}=T7)?dagw>0uҼSȏd_UxMQl<Du-?rPtщzCY a 󒊯r۾M)X-r *Q4 .pv8oY@S.yu M?MɒVTQ#5S*I=M<,@Vu˚g Ky@i{츫FPIu ZM$[tR+w{>aBنL9lO瑇^@sƫ.MB |'$)qxT]RG 㵼Yo`l2#Ƞcp3*%f1H.a\*ݵ;}|Ū TX #K h*N 泊v[AɛTqǮP b.;HwX3#Hx7NQɃkWD\OU[@ludzOJ<Me:}`EhIKDSB4ixzˈhG*k.z<:.$\@kK2'BX:ϣͭs,3f 7VIlc^?^iP>_UJr):qxH. 7U.r[m%^D *QHp8X=,#3UyGZ;i&Z!.v[}DIUMec Os gɰ@Σ򇄥^^B=TuvU>i0(-u,U ݢem*dKU,Ic2 4ͅ,>3j@A^L, K UIqNi/L)ᷚ1qB6{&X~ا[Xpxձ6I;8Y{ ZߩCTqE Nx%6UX.yvD鮢h+}Q0U vNlJSӺ ͛:mx|:fp) 7zA@,]eV] imjZ=o$x+"]QR…eSbV%!䋦Sfӵ-Kky5m>kT5#M$Wv) A6))Okb-s8s 6G4|+~r֡F:"=)j CYaIAUMBO xRP2 ȺVLLU*aT  5#RbG.W5% N~ "IV&x_YB|?l5׼ b;\̭m/ Քk摍g+O *z9gJ2l5:0{@%/ɻ?Ub pei)8\]ZF2vxxÔ6.%ե`[RoaJRV'*qҕr E]ޮo2DZbLP}vAVNq\V Zv,sH44yIijV 飵%,ODk:k~e(QrKOWMb!Czl(E}5tֻ%#B-T{l[ޜ@">c:AR n7&E.'wQ3uk-n}x#(S*byy6)*OD:CoVC "eӨھCP7NpUDMM~<]v+hϭiThTU;Z6#/͑5ﴋcBFm D [xUI|]z] Q .T٪{W<A+I3Կ<~/XFCdI:K~wRQi@))n&QQlD+5-[Z")t S] 0ê\xm'Qԩ&;2 ,dVԛKrB J/N1޶dW$Y(l$eݮ_'jV(owlIj)@WK}kKz":XSL$Ӎ+#o- FhFsTRܺ_U:<۰EY#^iYa)aϕt#KޅJxWgX֥IP:"^b𡂜N*SǹòӬǦv{k*YhwßU8R7W6m=!^`)&vo@:ˣC/@h'abx| =qjM䇮-`{IE_ : pgK#@iSѬ#JgK{.o"j5 %;"e7c<ւzbK)> vBO\k4Z,dR|BxdUd3>l:{y֦ss&T*4Aj,GոDIPe]:27"7l.Qzgݔ7d`^Qu W]FRb@un,yDu(W&KRi.WkU 6N萙 OC;Z%)#.KZw6GɣݹxMN|6y.pw C.:I{}P4Y!m̈́Qpܦo\rzh"GwKKBxDc5DC1Pb?JjR\d13<--n5 Nt6ב̔R,7gRQgh+|,^267ߕRHqn:SKKG{rѐ^u2Q< %N`G)lqBF8$9N#xښyY29\̀SXᕂ檠r{`}ynP=%L+5޲~"-y-j@s:5E[CBv,,\ ZZ}CW0"1d'"R)6ЦR̄ M U,l ~C1;rz6,ehP!&x8Ja{?JtQR!+^OEZzpvc#Ss5Y%+tƳ2}FkKHTYDMщ cȐJqc`뭩.E48i`ЖZ29e.{+*g8dLyF%d5ՏP[`|}㾸2([*[tHE1@!h[MHm X/z)nҩ &g/)}NY^uXhW ñjۍJZhr, aC1%UY3OgjJ+eK@gSNgMs9{њ,o,*&洕‘s,O]pH||:;8iqԹGYwУc&T}hD;Ra·$ɢkZZ,&:oyN= nxথA $)Iҩ(ܘ|Pvg Z \ v!TB(`Ds"d0ڴ 6Ѓˉm ˬfP]; 둱R$,lDFv^T*[d; 3K+-CX;ԲjRe“a1yՎJ Ͻ:f/JEM Oݾb~#x LLSJfVϣfO(N;29]v5 HL:'s?jQn;UC>SqOW5pan5Q<L!jILH.JHv9gY#,˴N38]l/Ҿ8LPX%^:Hmg:eQ2Է]*}/6f+H~ ӣ4Jݪꞇߞ.@F1Z˜ܜ<|SJ O+-8 7 Jg"kO-uRVwUyQLL {A 1*Lr;7)1YZ*X *vf]"!F'W$lm9652ӣFN(fЕ5RKݩ'&xS)1; '*lZ\e@(6"r̢@F;bwXm+"Їl:E$.Au J'̀2bz htPT5cLʱz苄Eݭ s kAW$5DtXҶpM2B0&{*vRTtWJ9̄27{#&?VF"kp^qX0u\-;={7@-:e{%};S*Ѧbu(:tP[I_mFm .sAEO;[ޚ-p#_.$U$c*JJRv=T <"fqz湉6?Oe?(&)IJ!&]]f:yA/XJʒadm~U_C+{pPsU =yt č]NQYTI)ɷ; (γ씼GΞʰgwćp=|:@Ni@P:8Su@VPGEЌWb ow\\wx ^HBV??qӁM}k]Wr\4J}DUJb9MCG=RLŽ%ZE8Р4MQv*ڰ&+OH='9?Ȑ[UOJ&ŋX̞%6ɶɦ\@ӳS}V e`M6 pru_z! Qt쀥3>jD B[z`k4T[Yi#O, \ K%J D9b'WE[,c?NUs&v.~p*)9pM0A2ePZIV?EaKh,<yP.xD]JGgdO`qoUPG{>X+9zrmxF}X@P08sv8ꛞTU Kx%Nr/X43_8Pq= XAwzR13.jNMf5._ WGhXȇ\%Pr?XᾱLрyP1R{p];-wjt{Rseߌ%)pJ'ShjW"nf~>I AZ} XaHzBUʧȇk`NlL"L:WOhᩯ|TsTp (oJ >d%"Fj#2@2ҹ34eIƒWx.!sSLisJdx#ݟLbå8Yc%;$S^Q>D5J];5JH֛x*+(<$ kZ.ī('>R~Y1c]eG_EoK.e)K+ӓ@޲g}|6I/{H^v'u2C=|Vn;{R0x;!,Q8yʔZ@vQ<̲pUlN8@kid !-dP(RE,1/o]t2ؗ!+>IzRD!_7puB%*M>ȡW :^sz!W$ðmHlSʣ=F^P4Ģ)[Yو< eHqTw(YIjHs8Y⸠Y[~g;!asLGFSQNH1\vyϊN.2[U˞yf\;<؜`v+p50(@Qq=AFMT,KK4NcFPAPsm;0.~IdvjcC x@* dx~(&|4UT[8Pŗcŗv9NಲBQ)FGSaprĺշT,4"/Sr Kr LqWb)tZX%77$tq#GiUGUxWvUؗk5XQ6e.AMSaxJˍV@"[ź"Xt HɠmKHaG斎@_jufxUFs[S ʼqV/T1$m6^NۂznyJ~j<7J'oP|H~vFV塘""#rub&{'AQ12%r0= Z+Sv]_Lyދ<gvLcM;K>GQ]sgLb}Ye^K \*FujjuY9)ي$K첗*Q :2gEy+ǫ`OzUOܲlpQũQ6@zZ}7%H=V!1D2}$"inZi)RzI1-= R&ȃ&U|e9+gPxw^5o&XW h 53Њ'VEresď6|NPsVU5}w GwYN\].C  n~m؆s\""? 5_I&Ifq3Q|u`•.z8N0I&ֹ )7/xwa[{.`pF'5ggVpv4Cn"'`(qy7A5MRknwYLOe:qlټk:"w@nָ<]=]h"`k'IuݞDz{ҾYi'qiph/("j:ZT4ۮ@Lb %RQwsŚj}z%(Qq)pՙIrä`hx4 W-AoEwҜڗ9R_#hIaH(u,@Et)&ѥn#?W{vhʣRzq%@HRCB0rWjD뗕aUy"ՀmSM_::5{8筞cٵ gffgJrl#el{Se*Tlk 4z:_*QYYaɰ<>;Y6r5]NPKSTgBCp2oK1l<~{ܞ-OO2)5 4xƪ׊6|,YVʻMBW`>xu~рt'2  mJOM-9qλLGNp *veMoS1GXtNn K‚PXUiRY ꬉH[@ v o$5{=Z.`2ZJ}_'ެs UM"3˒-NSbw7e);ey8ka-E <$& iu[gSj"h۟g>Omۿ7χ_o}a7_?UEO_'}pD2ț+׵uM7㷿7Ϳjo7/}Û}o_Cz?~ś77??|_^Ŷw_}W^Ko>_//u _o޿>7oӛ˧?w?|ӟo߿7}7W}{YO/'.ᗟ߿}oq:~cwos"?~G_}݇߼IuӧX9|U݇_~w\/7<?mIJ7~[o7__߾[/o~߫o~_}/o~ǎ7O~='_w_~ ߼Oj\Я\̯'\̯uo|\ݗ|-ۯXz_|/G+W?5;\W,xO߼_\޿_|_̿+?7\w?|'~7߽~7lt٥.%W~ꏖ~Ԏ/',l/5OVXjvylu?]\)tmӥVV?YX|]gURѢJT:rъg *?2LL{oq_O??ͯUy=[\/zſ~w_{On۷^>ߍO~?~;Z|%뽔}]WX?/>~uU}y庿/~'V]X_ ,k%KGr}y!.ͻw\_/uo_ xN_ͯ?x&i+.zK_qW\6ׯL_qyW\߼~_q-W\˿kׯ{k1d?~ŵW\?~ŵׯ~ŵׯ\{j_?Bgz?A?27}W?|/Dp}Տ6i}?xv'7ׯHB/t~//xJH+2qi_5_rQ_UhA>~%W_ŗ/䪾K//"crUK_|U_|i 囟|ϠÇ߼7ŵ/އigh$~\1}>U"VWr:ۏ?}xGBcݯ~DR~U;J߽|m8#2]W>́g8kZ9>PY⼉[;..mN= QRRYAb{:c\<@05e98l8m+ߠΞcƞFwan&9snG|6CgEq'=iFjεMjLΣz(K1ԔyT.,ܼZӣ[`efr Uy|Wy*?JNJU59Pq֜wҮgktcqgĺ?SUފGaɑ8+޻K+JSeGFMv>q.¢-`BCXLYbA/ɢIR۹!6lQ]NGB׫JzKפp.V<"X鵦l泄}ZTyh,p"AJ=SyuݛITNEݑk%_\7칍&\yH uB\3 댪GXGݒ,@AT:G|<$B˕U tQ5c*}k}'2gJX(!b TpDJ_evR26\q$PQJzhYi亮FKxFc,+dOa#Rϥ|<*mOc(7yd&sUvуS1vM_A&Vg/[tZ:?z, ӏ7M$8E,Butn韨iM w9|V˛i`./CAHO2z&Iy ѯVѩrO7 <76|BOQ]qr:f`J`!N5s\|q(^bq#A7PPP]Wrscew C!̟ JJ9zE f{3c y( Ve$vDF2,"'vs-M Bӯ-[TZhYjj.MGp`lU6mg!vJYC`w\-S,N5jզ ]% TRMq !ہ0I (m5:(kFXšN?VXYHTl*!LUA gItslE!4:TCrCPMY/ C@s~ R=,Vf<69Ίqz..rSgWGRgG(V){ Euϡ/wr)孪@gQtPpʒ◤Y]];kgޏȵ/K'B'Ne{|ģL۩%a-ȴB| 5W_*TѽHZ7Ql*GceB3Sh;Ȼ* lcEDnO8J`OokMYA䣱5A33SW!7 J5eGW%o<z1R ?u{~<~mꄩ`$բ y{b|~9򲣌ʊb`Uu& 6ɕvM/u5/vmOJ:X;ϥPc9[}⪵EW$KV]SNduZk}A+)ުkr8 ]V+:>}EuZ/LD#9U]1hOeK"q(X W6kPE=L.-le }iOA732 T)pkrcփ =?;_kc; &i4aX,oECxzSGiքӃ('|T294HkrЁuKUao|v)=,dgGo>?9ݥKRCړ"''# 6p RӳRH2&F7L1r?VثH:1Q;,UURXv 1;DaB$fOUD'qDע"H=P&qY&:dDKdu%hPf4^{:JL<)F0=Թe ď>π U h^hRj{,Oj橄wSu[K.neCJ⼀\HE;d $G5N=^d3-MK]ݭyYT;{!J0.u#A<əWJu7J8 lV킅b㘴 "hd↲cK{`(G'7MX PaR-4(]AuxB`Z5 `7E<]a%׏=ccIXC}AejxX\CD [RhA;"?Eӈ!iX.;iҽDPQ&gDɩ+ikp#M{=sMFGWf Yxxa8'`7;kpSt scH{)%Tߞ/zj^@&]05SțڽU"iN'B$O{ϻ}V7Y<>M# #]S162cVC[!iN{,栄h,svG ?{ڞ:õ-uof{p۔E9GDDª-3 sY!X-j96NW˲cT:z_cݗ3 k̫ݳ/%!L. [ زɁ{+vgg/Ck |&$9[E-pY-=KZ^.K\Z$ ;>j:C0^?I@.UGW;HwIԃX{)(䧲qu}!']C uVGȾ?ezGɼ%AeTLNRd㞗S^ lU Xvmpk1/<`Շ~\^H3:+UkFmJNK#0oG U-WI\h t0جQ gT[5(lJ>+;5iVӑj\㷟{, ldBDo ~Έ֔}9ȉN ~I]Tivz{wpQb/ց8}(,Qmo\2(DI @ڮ{)dYkx+[>jv)HVx$\ۮpwԡN5ZPI2/ cyKCÔ X3K [48x!䃱ďZ,)DW4‹N9Ui pԛcXT4:*pP, :hq;/M g 4eXn͌ `>|n\Jl'-{n'ORr4ViG@.b|J8#oS(B3P(HUVE.1.j,RҦ"Mi:;dմU6{ Sg"i }&붐No:n٧;=V~UeB$n[m[Ux*@ԛU36C{({ѩ, Gyim iXK.>eKw>,18F"XuX]eP%$*uj*hx؜}$UQe*;zzĽ/n?WXTR$/9ju#!qrix.5wlW0XPv=:ԛl6\t.t@)cllYhR$8)l)J ^`*>=vy]W!m b|IO]Ie"z`f$(oVȽkE16 }=g]]2#o8iRj_& ?.aOn =D7~=ý3k+B&> xR(vYjmYU2 '=ZU1ȣhVt}k?Xn4 >kg{Rot~\wz T5AW4ws;me>!4H7IN5&=)}8`δ6lS .}J=UfhTAqAO>k:ܩ:T 2ڮ6dyu9{KQYa~ޜV@B6Ri܋ZPʲ uG YF!ƾ|S>65/Jj\ h>I`R.szLVh,a0&n9]TҤu)#zD$I="߅ob3ʑ˸<$ PyO{WUrC\4~Oe\fQ.~u9T&.M{EiP C==)K븮'*ZٲHlPzݡ=2䓖C#ZQƢ{ZDqkFs!5~%B5W9PWۄbwr@bs8td$_$ܵ0@*OJM%E|wE(]˔50i{t ހÆkg?{O}".tx*1z>k*/;T)Jv!Zd'6YD T\kJ *M}׭Ы(\[-{CFOX{l܃YG>U[Pk_{s"-ӓADJrDJeqfkжRyTНp8 Aͯ^gG W5 T&Q'|ךezqj\<(b f*tVIXk'ˈN*مzL)Rދꎪ?eQ]cۨfCvm?NCy.3䥠4yw53Y}fǟj6 YTHΌv./ PP q6MDj%F}y%;jX.WnPۥ H˦:Y>$$gKgzD)_[^wzUUjw pH'AAאzD $r MT匲W3oJYVa"Z?VvW B mAh@} zΏEg|<]?J/I@ $p=& .uYR`m!t۱ VUtߴtXVrkA=MD~+ϣm3H(oQuM~<Φ-2pթ:5UέzT'_C.tb<>'jǂksߒ?RzY4Y]OByI$R@^@ΛSY2=ppcdY,! %\; y9=qg-TqOH2&*g)PϮCjewF[SF쾃Gc,}&%s%sEw|y.OQ NiĎ*뚓)};5.)ka#ː ȟ54'&uLޡ岩T@fͨm(TbyUĮ-yixۈ#k6I:%YNXBJ&mIb\mOE{z<.7i%j6Hrl`gs&GbճQ]>"7oQ tG3ejW]?dVTQޥYwhEvS:Dɛnwj}#o|?rC4f`##aG4\Xr0n4yâuzJB56A";-=)vĂ,z:U68A?mN K "uTxQj]&*B#c!8,ȋ1%;uyT׏Lp=NPz6nPuX-L5uζy -#TʇI^j4{S,ٺͬC2v6 @))̯0ۧóm[j-/ϯd9,Y7-MRbH/:BHx蓲ˏ֗ MO$c (NFkq w0 7l)FM`PJ<&^+u[s54? 0t '~Ki-EXB_R#}\tW=h\=pkߺG:4ZUs_.鰊.&ٔ㓧91_ z'sr;R ]rN.>CVsa$!q[CX ޹y3KIjfg;V5t2Y/Vb{vັq()TÜD!PȫzYlT5t~<*t))eYF,|`vjwn g(Ôj<>RẔ;{4VyY|L1|7;E,#n bqzGiAyU2QtE@F^I|<>gڃDEN89oᅧFM]l+WI|r x9 U.nIwyب3]Om`n;a9۳%Dw-=M]֘nYR!Yzvqp O.ހ!)U$i'2VA@*8n{:~L'%'{x:]+ /5.a_Y]h)̔uS2i@uϓ/NaA.eu’/" .qڑ]mڥMZڐ`.TLtKNa+ֹ`A?`<Vi`977 %F}CdUC ѥRFO I1#GSC]X#t*bom)\x=fίR d/lEI0_–M5Z#/iUc]541$9ګ<~>@lzA%*J+^~.LD#d}~I6zؒm9.a5:6 ʈ _cla\mbP6~hHQ6aQ %BuLM _1V6d呸׾d- u bj5xjNtF]jaGQ*RzTU=]uA@>9$*M։ƮZgH1Lga95lBj̪ ׾d>šځDJR0=&3RBSȉ2DHAa3Au@^gj+^S0h\r@۲7Ց.4S;fS9vW2'9tiKM\t%r D"S98rW J΍}Huzzsk. dGIuejȨHh'.Y4Xq{4l'!ˉdzVBRf$y.4X꠲;x<8'kͽ_MH)B #I+} l1;c[nKzҕbFƾգ<($y3M^ӉLQrcǴOѸ6Գe$|" itZӗ˽vxSמruJ==[W(qAUޥ"5fCBpSCҎ}sc$mIJ)Q~!Ege'e@;/J*"ԨJla}P~D ` yy9C*- 8*9=*ؓ-Pڔ |[v$Z{ƿl[c{$<&q% ,H궱QKVjcjӪVȃQckGEaog2JSxt?K+n)pvr)VߒB$K:UwYg|X8rP>$jD>v=λK6<7QIBpjYf7B*¤Ꮜ}GZXj NJ2l?ѐBCPaOJI&9v/Nv¦}aٽk#;+(YEԴݏ݈5~Xesvn.IK)<=TcRuxn3(Z}d #Xz9KIlHYǺOen= c Rߞ`-=뇪g|Y4I)^ڵZϧgmɋ cޒHN.-$;WO2ߨ&E DYB L>JR%Pu¾7'mmMp&| fxA>]xFywYz9-ȳ On`,*)DP%rC&6҄^9sɥSEk4A :OoUz IX"a4RhEd+ؑ*e8칑}(WT-e++S41,2ky*RĩVp8i~|v^MJRCue҉J@%k% A%[Ѡe A{N/N1A׍dI:v@X1HE'&80ཙ=/Y4HBh6t]u,8#5E85 R6x7{A 7%WtT8(KBDŽ%BxIBgzҵ*؝"ĎWS't,FQߒ7S`FjwE>ln:K>+sWJnWR桞~̷r%UA}*! B ">9wi$W:ANmdgwD6ե%[@AM**ER?z\$ϓ,@d;6!Y<(L.qXQ+PK!Ի`9|@;IVKߩQ^=tz[x{ׯ:+<ܨ+nk[n}+e[Lִ{HcNeƉb xȩlvɦVDŇp5)b=3j2xȦnPA(2F >7QTRMt?MV%R$TXذkN r;[ r.\[iC!2@=|ʏn dkpݔ}Ԟk) Ǩ7G+u+6 3ocvI%[l2l>Tes(e U:YchlFK[}-ph|~d -yt2y_<>6ڕ1 u# B㨠K_уŽ;NZ}DZ| vt$59UogDt:`2$;8/$ dz|[̛HR]㩠/J:C.0Uagӝᓟ%BUԷRTI* 6=G!]7"X@C rOJrAYųgʔ1Q;m՟R3};RF^N12* EX mTzԭ#d&Jczо{igjxBuݲ`yp"ॢ d u\kK s'Qhn=T|o#f?KN<(p)}vԓ#>i$Y)4F? `eiZ܆)G 7}6eVɻxz=" @ȓHOKҸ<Ĕ I=]1=oXaL!5Eԩ\E\Yw[ y|O>B=R@IS&/ xʡ"G}qoI fjS7ʣd6-˳0i;"nqc,W5?Sbe YPphNS0H bXivxCXx]pƂ2RXOlopcId'28Q /&CzKpf}+WG&NX8aPgB~iܬ#  H"Sٔ/ĝB⺸p#@;[k*$ peDxk@NM]IVRj※&JruDO Y ^KBZA {X, ռӉKg]xnT!K96ywO1dQ=upa nCH;fd.̢Pi;7w6.)%+_ǴUEc$r]#o4UͷoyIQQ$($n4axUg@Q`V{ʈ MVe =Woh6x6ʷQZ$$Ya|eʨ<N]ƽZ[q 8tzxQy OӡrYݦN@r'=oȥvswWQs wL U"~Pͣ^r޵GY/j;_æ[쎥M[wLK[^,<~VCX}ImlnNn KХyϣFH{ffէ;RާPNXt#JP(jb*2L_voהI 6M9QcOhljwqy]]J#H>4"r InVZӛ؁}I֗Ey$e Mk %XGaOԁQ蜞^:O^' 27TXAλ,i`J.S`☫U5.hTrMSspV `5OU},4uGaݍ sXIݎLrbrЉWSve9F;Vl,%mWW Tn17Ce ^n"T gNo"Tٱ-!e% 4WepSU㮤PNR~uosB aV)Ho0}yW!1T CM˝k%"aƧcd r?I3IATi/[~{(e~0YJS uiQ^q0(JQG h܇ȑ*x.qsT},sXXU@amX ixԿq?91q2<,V,ـ'y@]kaSeG{MJ_VQ >LVhʇ!H2niHpm.#u] vJ ,%ЪǛgsd)2uE:cC5*۰uJ%|˒[_9$iIXTY`]H"$̢, ۽FWя2y$<,I eQhqRZwv ]ɖё}/N@=t&gI&J 2XFUujUt8QyC:'d]MUw߼K=T͂HZDTU!K ]wW8x {3_nkIC5l\Nv4 y$m=kL}^flUIEtgb#5FG@!ٖS}EQ< bT0HFJKB%$Qsc3N% s lLSNUQoz){;'}I feMvkx?ʵN\zjakq(Z 4-xR+6sO/^ы[Ǔ|Epls <ۍSmZ&CQq sk/S&߶^]ױ=G*,kixe(Ikc-"';N9C%J5Oeɏ%$TD,-j^\dO7@ (K V@4\d탪"AY^Kp;0tb=d+E <ƺ A/Y-ktfyrXQ&"o؞OVzLyoPkz4>g{.qr[rl=2T<{u+jv9KN&i7j ϰXKi4϶)JLqr6M^}KcwmBj`0XUCtuFIo)ϡ! ^IeE^|h TZwVV4ӤދKn725$k~뺕r QXmHKEa>=86~nݴt!9%۞ v=d.kݥ(#"i L*by^"I-6O_.KClS\X5Y4*$=<+p7c'4rɒCKwl.g'JiXY{Z@SݛfWG@.A&9*y XGTPr6cqxD^F[@ θI)*4ۥ8 d4m@D Î6Z>{*1-iȢwSQ1JmDV%RQxW ei"v=$k_!J^_ L}Nc}2.JfEְO&R0Ģ"XO]BjSU& 쎱DooЩg=4<9T]I dD^ ;ӊzͳL:@Cɞd"jU"gPAZMBc?\a\5"MSGfRTKթV޲jdjGJ f}nS(_aqW|VCC $e iYA$߭x(j=Rӑ&)G[>EpZJRK@$.ylźhAfN\H!E&xVsx Ù{5DNGJF6oP<#]ڶdN7KQ!TӓԿlV9J(H6]7ZyE%^&:e)CS=V-3WS=~BUHN(E),?IOQGg$2Lk=O,;RƉd\E,k#C6:mz xWv` ')}ۅz 5ESᶏB:49KDޭZasjW jUGLljDJ)Nn=qۧTCSfyBz9^@6AydȫVx.uvZ9:ʳUm',,ٱtˡRrǡx$6uEVPE4%4XlzTRXb, K:bXAEgR =9(Hm1h-i4uN'quTEjeAZCG^M21ysAHP]*IKp!=u?.jܷ2lšT'OuvF'vRqcrzGeZM[u ^+]'=Y~[:U(TIZST>$z\0>).E+/`VDp\%lmŬ kF +)ׁLm7Cr/&j̗.CK)Sp~4Zi)-#,_8NrJS++sM FNqRnJn:^T*YrIMA+J7g|T%\)mV$Vp ,ڈg7`j~8L*:FGYCC߼A+΂.b<ŐO#E)kS<*_I1F#HLk-C][ߝu%$/m: pEX5;WbjUZ92[.b?{J K T7^."_kꟊ BpZN# aX]C dH=fm$흍*@9rw|zSOT*Zr?Pt ׈aHJU{/E۞)dWUmMNLʼ,r( QK|:q,-MFmvoSmT!ki'|mTu-`0-ύp夦yIc=uuIM`{I&2 rvy괬ggPUq*Kjz)}OM`Tm 耹InkAֱ_D՚C2'dS1 3k: QiLҝ4$4 ȝH%j,&7GD>T(Fu@}U)gnC@e}H,?٦ʥ}l _wPcyNbլ|8)*2ont\VCħO"߮NqG'%0ڙxi_r2$-lv:byOS ku;׮oLᑸة`*!=KLzKufRfߎ?Ş=F:>m"JQ3]j(}/qI]ox3GDeq)s^+9n+Mthx* "?=?8ǻn3fKzu'cqx:Ѡv$vm坻S1%''^쇵Lp<.Id:!r 5ەPjVsM Jy@((jUj܄ N\J{S<։xnR;u^JJbA }KxS gp)MZamXTxo &5%6sע gT5Mʷ.ɎǵӲkue e+reve@ _ \rDkn7eLXX2 Lg6$N;jw^(A({P,Ζ54t ۘXs-<*SOă)5gs7(xnDV4A(1!LPFsGyt iIb*l.!^_/}E4x^ZG[!D8MV&ȻtfV͗CΙj:9lY?b>.iv[ &fwA̼,xR5.ۧ<{˾7u:.XI7 x– .L'| %Ih ◚ɠpMN~l]m5!- zԀ4 X}#U)ǚ6bM[9aݾד.SZAW%-C tKiUrixjK` a,̓>+5<.u0ǰXQiPʮpV=gS;p/Zl*u` Z迖,ή~FXB`0 ڿZoWP=c=ÃA~Št&A~z;OAzY$9~e#˶G޴=e95 [t$ ?絭4)-v25vZ/yY= sktCvh ]ũ\l~1jΔ _K|(a4y#ʽc/=*?&EQĖ vpMI{פF7ɾDn .IH*ASjM&htWu5}Ի,vIv/G2etϋ*ٸ@`~,*J~Rz.J"\MbaPnϹ;4w0I kEkmHV؃ pA%αj:yuhV%nvM̃HVߣXlc! rO} yA58 Nq0v32I#m*!h״Cw)OK22^H@ CǏPj+ ZU 1eKjnӾ*/=a_bv]#i20={#M>(TKNq:n[k9Wedk:*ny2@$ԂAn"=oD]gZ Nak%@Рhn^A^%]L:*E|g4!=JTzXhI=z&WډƓ7r;!?`כ9ݛ?;ZZ^R Q1.cJNu 0ȑ{BO ay;jV<$SXJd`5E)<dhw{K+kJJB)J"̽iGONV$t(vGt[IC'tٞ->lĜd(4QwЋ% T@/Λ"1F R,; lJn/d7oyVdzu <&pƪX2m,! HA JOXWlql,K.ҖAs/ҽfiF@'&)i_Ȗnb0WxmZ8[Ȟ*4꒸\\*WԬ1p6eGV`(dk @/-FyY y:$bk*,nnrZzbQ;ut'N2BQh*{ݞO]+$@8(yv0z:j:RZ5r)ݭ4xlj?qH@Cg+/I[@>lwWYZ㬢;{Ԣ OCƁ|G-y`/TE8˚/(7`uK(AN-9amd8ЈEXViwd ;Y ,GGG%J+˵iA&͚'8=]8@ʀqv?]å)|Nv( B;}J" FjO=xp:9֋? ǜ4S1a/,z(%5,MBiX<Iw 8Z ChrN(D` ̒㵳j^ zͰm!d.{tXuسi%uU[շbM҇OVs M֤R6($U'n'(<ݓ RD;{ }( Il;ۮ#=dQnaA ΟFi퓈٪ysB]uN|Y#/ XyI⣔]lC^S FQ ;$NEbusunρzNW5pXB4yd?W `J8YE8J^IvreԱ)KH:uH:kw? H܀Cػ˥tAoN_kϚVpuP.`"q+'n.-14@<ˈ%kJw2'v&"EwgR,/=AY.b9O SQ1AnzʎWr-6xX6p*/VKUHikTNM.MQ03H.KUxTiE-b˹Sj,6O_]}QnUɻr΍tU?f5)SR gT*%4.cvY" O>^olXXE7 ڕ&/7Tkxky,ɯ8g؎'T) cT4;ĪVf84I:U??_>}?ng|n~u_Oݧ߼"?(Nw&w?Y_ʇ?SM߾wG}}o㛿}ض|۟kݾo?i_??ӻ?r]oͺ|ݻnO|;+?>߿?֯?O?~7w?G/w}~xmބ/z|w߾w%|7oÿ=l}_|~7GF~S~߽Iy?n*o[|wo㧟7<淟>oI7oӷқoƻ?替|~^?u}߼;|?'W7߽K o_}p1Ͽo .O?}x>¿|z]>ws|-+շo~~}E~c\gwo}ÇW~o?~?>Għ_s~߿ߟW__͕_?\w/ Zx\v闋nՒ_-r\lKzXfW,~klz_Vurq˵/VJZYiJ*uYժJE_t~ՊԞsĴo;K?oU{}={˷}W=ȭ|ӧ}Qw??}?lt??|;/}^?˽.+O2s'O/&>}|y]鿼{w~'V\_H ,k%K}Qԏ__=ޥ|Oշw/̄~ _ۗ3+.~/_q/K6_2|/_qM?|ŵ/_q-+_ZW\xy&ӗ+o_Z+_Z+}k/_q-+{ \ Xow?}_~eno޽G_mr_mne۝o^&}&tmKU\ K{􏯾^Uhz L]^}UK«/ϯt՗\ϯ՗\y1?/K#ツw{ş?矿Wf^ԯH4[c~_~>D3O@?&)*{jwm;f='ȞRgp,k+G}޻4H}붻:Y5N6J0o:(yyߊ*%֌Merx?g:r Z䐟~9t*|U&壝8U¼ܚ3"Қl䣆q^ꐯ ϖ$6ƩW|W5ujwBReW8)K3أ-SGߚ'uylW,G?]rLQq5ay_Kt<4Y4 1q3_n*G|?q)ƫվ~ى{j[1ie%П#_S3 }i{V{~߱]7Q-6]?3porAxmyg >د纏x<2!$}ד]2l OeQP c嵺UOi ?1!Vin#/Rr:Va3G0v]v+zٗ=" i4U :ɞuOo֍eHW9׺Ni-13Ꜯ (|m9CI)Vj7Z1Ԯ/zwj^jF[4!xJҟy+yU%;Uz 1&V50nM(\\FtFETlHEs^kT`e_o _"rN VFPzzN=>Sv$B&@ 4OIg0*ǩ9Vo=w:ӖtƵG@R٠&Ae~1Kt"-ͅlxʹB W~43 iU.4\k-l4y|\|u@mI&QIQP~j\B*߱ J{soJ6K4[ng;ORQTQ1Sr¢#hc5~џXNpN/vծhA=lPqֆSG]eD<53'%tvSwJB45Cpx72lGŏ+ꄡ+(QܥiBNrfg«w›s>>*z mP*؉V `;e ؛I2 A,:@B9 _i L1۲92ڸ Um EΰUЮ{ii&݋L@$,f+k$t:e­GF@”ډ"c^&))P$%IRK5)y>YxlM&9 5_$:xf.R?+0[jl}UgkT(l;Y\#~6OCjJt &ZYv~}yxBf>&K5CJꍍ;"€TY .j,kqI60tAJ!oz<OwaR]2ՑN}/;KWnF zZkUo>n x]QJэfiQcjWt$)Z"$'̦$ ;/KCƀgQh)fNCq(:v.5/q :{Q=n h]eU!u*أh[UdG2*.w8Ѡ@\ ڕV좧'8oC`Źf uЂB҈D |L̽$~.[m[՚h5vv4oӏ#8C9 Yw/.ջS&s8I7!SM#uTdFZ׹t}*<)43}b=jJ$ PD2u=@HLC)JX2uD$7lN6~ mZTjLu/ɣ?soZF;JW6h$pDZ+6J@B?安G[5FXȃ+.m8O%V F4e;e<3gT#szSgmgKRu)(6K=*H(?guvK0NmW?ESfpYd|jbU7è*M5cyND~. )#*x9yQuZPX'֔bS?~tZ{csrZx4TU%侻h5 ~@]]E9l!Nm0`{8Ekq(yPл.ϪV}Jjk^␻OysԬ-I,+ g\Պx+c[YuN R*[%r)GUm6zlʮiMEcשq2B+kTXId`(6˧ևcla1' ZӻwuƇ﬚ K@D=o_ľ[U{e(dn6<= m^[ʰY5p ,B]ӗ6*@MMFmgn,/օIfzvHCIXħ'=9+3$j-re{[;ՏR9EK܌ Cg2ȥ"|:ݭdQԏs6(h 0$MXځ_>CѮpR8sE-+u75ävUBH҉I-mb*R)N+AyY@iMeJ*6\)g x{Xuƪ';pn:t!9d""=W*ԍZbضU +J C"goEl`' Q˝?5;xp8-IƧyW þa6NǍ`2MTK eyz\<μd%x6=Dhymg˕}uNjU %AQ:)k #> {R_c? OP듫%@m|.^*A0$yЕg Swڡ'ߔ|.c.ous:1OⒿI? ]IH %K<灵0eu.XQLx,meqZ!vѮخn!P=fh}Ej-jFV0.["ؾV 4W,IPJETkH%NPBØ& Z]>ϠiԊz4R-G'¹^{'ز)+{y*Vty;b )(AW3lV]4ʊz<<ԭGҝ&D ´0O?"kě]wlΚOyǮ1/xőf*,k|p/#z^ MXYg$&׭ЎFBeYwT]؜zU 8zsk sCZ ]l~  Th۽bkSCMҒ@ ?G[o3Nb~,oб:Ք -ߍ*]C ̂zxȒu';C(ǁF$gxh\j7C(7N~x g(|wD C[¾;4qKō"ɫb_ί[QClr,NMMoF3sx4c8ҷu$'lBLy<ў@{F]C;/ؒչ5~KI~$IzEʾ?"EJ+M<C9L=GhD_Q`S}xj0$C$Kj'_*dY` RY\va8o2i왝͑RY>ϼ<([ҏ r|@Q푴[~קUpJSrĉ&2حo]?oHV\EoDFԷÓl]*"}h6wdIdZ=UT̃U?KJi]=ԔovԵ> .ۯ`pD\ _ɢdy"AqTlY DzgqԷQ3k)D;I4$P:y wZ\-^sIzJA6|Auu-?֟˲WTq {7,P@$}A1QY" I)?r3 ƒ+yxXpũlya+٘HɍyGKF-z+}ka2/nV7;4P6VOY5]n>+d[*~3M=&s۸EFF@!L1f^Nm аz.ܯ cʷ%A`Za7S˞dFTp({AP(K(5tƷ6a^ cB~ :v -^kk]'t3 x i~}-jQcUF'I 2*e$m~qE]R;^""ejOCai\g_k.Vٰ= }k g $E=ۀA:nW \59MoJăsǡ [v _9TY&lI5I6d?Ev к3٪?Y( 73׵$ 7#SYiy]4:I/u8zv)t7ա)NgAO(f{c>H7C )Sod ԺK/.?E.1ܞS;avyfu 3'{C3BY|܈M%ٸj[%wiX7z¡˭Z#1QQLo]h3InM>5la7Iç #z54::%kPAd}{E9YRTU督F܆ok(< #KI'2%ۏK{@ j#DS^,u ghŚ,keT)&vx@.K+C`#nNjG9je+"ju֮cۿLqO`)=5KS&~#kѴ ӡ]™̠G/5T1yKp6QlT%Kʦ.e\DD*'( QxE=45'܊rryNqJIm Ԝr\7'';vw,C1}fX},$eY*]'? Ko8Gі *oh^GBcd?f$ :x3xHp `K ͭ)њ1˱V/8\FڥInr<\s}37EesHV 3JhE(5TZyNmJTAAWaA(8qIv!/[;a@T#yYOAG.nݤh)HOXοa#kM~k*xjsM2 @QYn*g[0A !!. J,[w],VI!OWZc/FK-xI yI aF5xZ'ZĚvJ}(5] ('/]yu͏ +O]Z$ f\s&i #.}˝ $t9̓;hAٶZT/FdEO-CvWl|Sf!'m@qr]Q{j7&>'0ۥY:8*擛epq}h3ˬ!*jh\>w *@* R=r0HplYH~N @$x:Ϯeݦ9"=Xu!%Cee$'r-Vդ=AeRmڂ P.OoyìNU9 H>tb7e%Ilw::&&,+hdsjW a^*PW.ÛQ줎^8 `Owg a JNܔyHt%(OoyUʻ~\pκNkѝ*~Ն. ͖ c^QܒZ.jX 6sM4 MʪѸ;汅ǷBv@XErvzﻎ8*$ڗK${L"urayF'9~s56<Ѭ4n;6(E&"ipeRjé.!>:|ēӭ%vh?⊲oȐSC%Wʦ=*Pd1+$Y: }1f֜!AC\MpTfz7ư,.OGZj?-U 3):nggl}$շץtl L6AP\bhޖ$v$=čU{[ kNYY@-׆좄 :$kz{ACPe[[tTCfYI%0adӣf9*2IvVN4k紽,&IL=(DM5d/ufCI0KD}8jM 3+ n؁q '|ap;x;ֻJþ@z8Ϲl7<+偎 OD1,(u,ZL;>Cg^'+dBM ;ϐ9gA֝:؞Rh.,UUǚ /ͻ"=x=e$++s*J\&;b^Ήd{]bۺ6|7']a%5K(TkݎYŹ#I҆ر{qs\W/%@U$c6PI@YqҪ'PWjǥQSS& o+vI6wY{>*VvH璓r-کixS þܒ5I؍y.\o0Ng1EL]FokJwcJv^3E恍ʒAUT<%$s/TAm"+?ݎUz opIv>9OY)+ > %ptd1ש̛|$k.V}e(Ҷ|6xJglۦWHS".D)+h8m_׸A 6I;-,.M\h2d\J2>ݪe&1C"QFueOY[25H` )[ȘUx֟|7B̰I"᪻rRYA 3פH} (Sù)X)|6-] TK;|:Kv *TI=<Z0GV) !_T‘,.7TZpg0]}[(|;huRxXa1p&a"q>kB\)@)@A TjHԵjYpS,EHFm/j?S$l%\vϥ<UBw.YU6v5)gy|z6ԝ K byFa4_"=ӟ޶lԝ@vd:ؠΧe =w4Sj&U[=l(;G> (W 9V}KwܛZY|㤊ڬ &EYOռ)#oM2TAc;u/;]d|Kǿ_~4EF/¶2RuAP$ڳFUy5:FMH޾*~a)VSx2TxТYT^ԶAb92ڝTnnUo6AH9p87~AuHo,T' Jr\ Zj9z nPJn}JpY='n).5 $z.vgl}75klڔ!0?8JЧ4xzTF'7xSRHYQښ@C式FyC}!+_'oJ ,U`W&B9h-lJ]мw3t5==ۚ N?M7ץ,2vvDW'pq<09-T0T.zETz;۬ف!9'<>ੜ!D.ti amP|$(VcH-FI)`@B<"_(b_|bK:;{Y%vn:$cM'e]XẠUPsFsv?\rsCzmS%..vs YAդlu5>\^1@8TyVaJʨBYKz4uF)NU:W_qn3vy"OofTWKa$@]wb @5`/ţ.ť7iW5+AzLUdX pVDxiCY9ҾD5 wL&rrEjPI1QBHHS8<\a;Xfϊo/ga\{u~ۓR$v8W+9ayxh3_@@ьxط40T~T 9Kg`(2 Ql)v+NBeߩZ?Zںye&iC(vo F(YD2խB!PNGV3L5#T[b$0'Y>]))[ 8^IrS %^FM%O== DHHZn0`T siD@CfC]y&Qɠ侄9=}嶘6:6$'튊((# 'XhJI$[!WR5@ԍ+*^`U81&EKjKyŸ=^$v+zudՔ/y@ӚPB"FNĿL,W]Kݔ3j?}%453N{[ǜxfcI}Y&hy*GvxAlگGiy(YM]S[G< ZذȬn۹B[YCR_,_U3JN+ (STix`cPJqfU$US9,cJ;ٙt N. j)HbfiܵK.q˅R8p΋$|0(k%-ʄZE^a`Sy`=Rgp͓'l|["xUnQaYXƨ^&hR.N 4z+(ԅ`_Gq锞mQ0A"v ʏC]ti2^0R+ V=KN~ ŹϮɪ5K`bP&#rT"x:Ta ,kYv%iB2KZ}S QDmD=yw>K Ƀ҄EQ9jȨ@&5*p?r݅AԛrLIٕa &TGy^s0ȪNZEj^|ŗo-Y3jS In[ ߻CDVqk|Q֕ +/xkPGPcn%dOlJ\M)4)=_I:z&j}K&8$<ؼ)Hvʎ=@B[:-2M)ŋt"G%dp,Dz#=Sq+|t *;`,ɛ g&ls:-ݦĵ)m$!ݪD 鏗LdrzPոL9ADHdUԅAlYiURqTZ: kEGQsm$OħQ=FΏ`8^bQJdxlȶZ.HKUSGot}>ݣf2LG;`>F))z?%8˫9^Din~ z@\ <99H@d]y[Ԝ|q(2je̝F 6O/28y6ZDyA{ Aq*RՔ)zeSHJ3ISh*]vjDϳlyӇNrsefs^o w `HD«VFQھGlTuP>qtEIES"UuTV=;Hн'; McjJɃ -OUj}il΀VmSOEcտPC(.ol ne *VYSe{˺%Ӻ*1$9+ "oTzhg]N{ {), ȉU73kgUXv=jgi-(}p5;\L*ϓ*RHڔMĔtp_mg)Qzb @SMkGSk_JoaAnJcS(&يnp#ϐlAO4AG{ڕW֜+ߛ5 7؈5Cٔq%GGG=|?5ml>[N@=J,l.<p.p(U!^ӑ{#4-uHf2U\Iu$;Րu:AX ͫ}{&<̩rw"؁eJl%zBꂾNFJ42)ë"ݜ Od.W/Р睻yL_R\Lu ]ʹ#[J.M|x)xv"v;`e RQ4B3EHE2Iw;/1SQnxؗw,ΪFBEu$ZǧZ#;Tuu/4K}S^iM !{E2U6|b?e_ (@ljsPj]rERAax@҃^gʪR^+uicQQakuH)bxgW]Rb GjuVK=iMWїҺL/RԁZ)2GfR[:CYMA w:$$5J`\vSP"VUVn}fb:&爤*O`=d0t=A $LaQۧ\ ¥z};f;:băô^ahç~Q%KBPܯGO@دi^M ( O*clw/=⒢n`SE(/ y>n$EL**Yf7q"l]$5ۗ4 %`V{=2L;:6ė7'%uκnBjr"O7fS!3u&g%t)E$DvFh>"&Mw5NѱpV\9#@uF4FR i cYl?bBpHZ(+X"u᭎O%)6[ Lģ;q9T(FBuP ĪW5xԎg^QH_\ɴ K0zqE&}tc uڨ9-yM}p, *6MhAAl7KEt"_oƥN`:NrS<=rևI-qZ9.5Aà&`CսZj78 ڝl:0ԻBC~Ձu#@lh~9H`#Ǥ2#hx(1F*6,M=XJLS>nrϚQshtB_C!ӒVI9##+, Hw.h֜w uk:0Ro C!'qsQG=@kCt_jIP3 p9)W7v64$PN2/k6Odp59^]5d6) ED톝/~|$n(iT?H,ArFbo{ftdOޫ,u|5'NU)1F`PǙާl5X~Uy%&R*ˎ]*6GCx-tS9Ai} %KGKE7*3,a Еs4kUcF'YkTQ L p̚ U§S4Myig_&]A^rV@@*WƽJUؘVme \^ҬC F9'n=& =eR0^d&,_OQyK=(G4u1 2H3*B)qQ!j z5hK:AJ i>ޡ/dbZxoFb=P)蓏OZ1+B"{r\6C+8LY3Ġ 0Je:.jzetd$(n1a.M;ٕ}r[:kz"?"ym9HgHMbY$8%p=f?K=LGIM w]E@ _O*=J9/e@jR\!`K 5,vur/+T-^ ؔfp? ?B~l99\(oU>ЭQX$*qAIWgTG78@9S13olK 0: 9lh*%f iD H]G%7*JBܻMMoڳS$K!] Rq@DZk+sDbS5E<]zn',)YRɞwʜk z59O*ȋwFz D?ņaxZTlϦeDM(2zz3@MT&;ynzPvm˕U+NgϭMx/10%tzg%޿ +LvY$'DMX442B>is&9)]]2kFo֦3K<`+|@W5=ϻbsbX_?-X`"7J8e#:zlO5.u7-+y0Hl2Ox)E-"zAUbiևrE4` F>&J10'+zIOl'\U^jK;[mNRKLCй\-~09\x4N.xu@g~m[r)-2F~MW{@ǚ~l[sۇ*ڑlq2r:*OڨDee|S\*QIC"9U=d{kS9znvEҬA}a]<[=yj~ 0O)3W3HZ?zvIɔOTQRcNO.s64K=i8ղ95yû&Gu}sQ5K91\{q ԃ4ck9OIFTfZXS 'h?¯ȞY5mմX"Kyn d;5;?EEmlL 둦Lt'$<UPMi*M/ZVw|c,sU8+g_}AԤ./t KR Ir]g7cS١UU4*veR7vqJt} ׹kU ٔu,v ,:*WSG)tC#T "9Ģ`a"Z )CY0QzRHMpKS|jSh{8ޝj Ȯɯ:: >j /m;dRx!,O'ۚD&TAJ.dWna P]2/#|%MA3(1-FM9"'eu<N_p1:=<*]mzPѫ) \MU2gyj+Cz8C6:cRDTV'zz~Pk(zFY`аW,*Q!" 8pgW#*Y5;ݰL^Z .IKN΄yMJigÌ{LjM{80MVQ ր!t Rg9G?;9gmZdu*1)8NϦsW)Ī䩑|Sf ui[M|%IS-YʨgƤ2p:i@-f{!OxI\?%A胧޵ŝٜ% ]#]|^UWSZuT\#Б2-cSgLjDP}*jOOu| 8m:ݤ:b`'&m^VU Up?@QH&@VYzt#\Jr9q;&$S Գ`iq)IuKgB2/yvIm P9 LN~Z4ËuؕS<$iN\H:&9&D!ijK^BxܾX.@ >q*Wp=S/zw ć\U@q)LNfSsیӎGx$4ǡi 0趼WIUAb"Z||G&.Tꊢ؁Hl~X򮾖,kF}pxH;u鳭?M[Q׼Ȓ4ԋ" v9@!Y-㙜%V@ !;@b"U㺿> ]cSYBZw= =M Hd$'+%*I#`Bnε>@$ N)G{Mўe88Q.[ѕfIzGޱ*G2|GuEZ+Hf5." Iwr@f5\WIG*Qu;ԪĉJwJ ,iozlI-2IQdI *-5jfNz ;JG)_ 5qo$dGUΊ=ϰ.USŎAxUXsWkvnCKASσЪ$נWtRvDbLh-A~-!mK$Q(Rߗ2eWN<55,vuϒOl3JhNm%N]CC)}f(~+c#)}G[@Otw'Y]Kʱͪߡz|qڶ}_NdJa{%E G"[K)|v7݀FX~(T8jey L 4LaHm)_hDelTIN OՂrhn&L5f6Ɩ]t^F?Ol}.!gNY$~6[QVv`eSCRPI %7LB8v? 9ּy{R-R"RQ< JõX춬h쒶s%9B:nHYKʀ@l`|G:#M'u/L%uTW$ M6'E!Yf"% ñلn1S6T>J p|jv/Y}O7oo_߾z_l[o{Oo~UnxI޴/7o>}7߽ͿħZo_ֿrU<_?ӻow>w_.}ݛ[yӷ۷~|wۺo֛\?_?/_P>Û#??o?}#K7o?~Ǎ5Wo޼_|gͷk|?}+foo߿[7ʛoW_7ۛo7Ï?^y{-_ ߿ݫԸ\o_ n82Ӈw?#wW9z[<Ƿ߲^}zpٿ_ʿ?=|5ëpp{͇_}[y#Nn믹O?~x_}ϫ}毿/K~y]._-_.Ej\j_.v|_,U^d5/VXj:X[)ri_,RWU_ԾZT՚JWKj_=jA_YO;LLoqO?.<׳?|o}|w?}~~û߾nwF?7>rٗ.߽Kz̽|$3w_} nǗU˿~'\~~yb*\dp|V7zK]ZNn _^}~~Lhw? ^=}N*7vxwH=`?x{^@ǦUXqlQ)dk(.iuu]|pHg\8mq|i!t>(E'mLYoG3!XK1?~{6#*|ݦeWl]><ՍGްx*` 8[NN_KGR:4_ *Q㘆x,#XVi/?4K&7OgYQ/c+{fX#ͺww?kQuTƹ|ӦԨ{خCq Uܔt9[Vzv8ҹ5^<ӱRhrhO۪'^xZX55X6@'91Z8CXE=*ɪ'hu\16w|z%uR 9ηLt.6HNw2` 챰TN}')P%oiBhO46u N:N${Uޤ""o):%ZuO,ݠY +r ^ʪu|=o_I ggMWxY[p8(RQf]N]KJ!Nݦѣעaz~v^`O[ bd¢cg‘gkJ87%R1+E?5 m k%鲹(Fq٦jqɡFI!)-Ɏ4ymϪkNPIPohW@bC; bwhʑ-R[ aYJ+3ˇHݳx"+:`yZR'Q>eb*j'`OD]nca9t4|z^ˈLZVA%nV ThE/ej<D݁iƮ0: Z~ך|U=l+DxS0ey>ړX(o?bꠇ[Obihod(חPNe&6JpWW= j߫`eo2 &VţRNitQ[[S-JŲ Kuyv67)`w3ZndYTh _sdSvs<đku/恽Z)28JUl'g7gP%;h<(Paчn! ;AJފcߩQ]l:$Xd9RY k{ޭ 2剒&7"YnPKE6GڔzN\PũO~QgۺMߝ(xd|KGZ zUծuU=К,>r"t=M?vA^˔TA1þQNZ U+j%Rz:L8]`@|~%aM(d,s m 3X?Ʉ= g0^6S%/x!ilLV#k{ Vރi 9 ͝ld-R/TŝOKXTo&-.[و%NwNtە;8Y٨&\8Rl(]Tr9N2ϚѾH*sUbN]8ɜ`/=#T- SÓT#=b!zEjzq.V"uL?W&,;:.qOlyDj)8IS d.( Ҿ i%ɮyA¿=z." )4HTB:+H)ެĄLMs9޾Z`hH!o O2'Gn:Yq N z&lPm):&6T X{ъ llbB TҀ9n& zD"9ǫ%B(B*&j;(%xJ~(&KV;H6_>,y#WյO\acHYf\ZsDX1=$?Lm?VāvThgkڕ#(`?}L/  i9POzTor=H :[)-˹kp遮i!Eߏs}IPsd<9y·4Y>nrŽ^jZve2y*&<KXpJmq7`F61D'X1&*"U=Xf4ʢl^11F5C}zr30IAMYl9Q鐡'+,n:,<|*4[d۠NKj긌fxHt`8xӜJS*ˢ v.+cʢ鹥Ź|C});2%]#=.U%Y*JtMī2SgOp Jj|(PxtRt(Qe?UdJd&HJ[C "IG}ܰE1h/a`_Ԃ'{! b~<GrMa u>b ; ׁ3*YM vnhZݱN=ȷ4x̮F|;$Xr*iT6I>Me{RiPh{xнN(Dw2z+HbQT;?9JRs d'Zo/^9ˡ 7Ifx{/iϷ<Uoi:NzT!`)+n\SGRpmGuW1l;77NB-/#k/\Y[}+@p_QH|uI*Ҙ(yZ ޻::hRn+/ 52n# (O)=DIBiG<~Lٖ2zWާ=NT\{Rgۉي$x,ӹM%Vs+F“p>SyͷIj/bշOߧTKkApQTgM՞swG^ՂY/]e~IڦI{XH)ѹ)]N:=h)nF0K B>ݚw+6 JO_XxI6[=)[ niDbQQʉzܣz> GK#*knBaCp9JXzk*mSf XA$rDrKةD%rd1A 9*¶N}CRd]>j߱T]%7E2$MeA;r;1#GțrDzt^jWcbTg fA,N++6nf$o?yYK:}eXuh~TR7,7`RаCZeZ1e*BOaQDB0`*EaD/@+6::a?iAƼQi+s(uR5vÂfj>1UXˉwh&{b XJ;ܖDTpb~[LQ=&S F?QDBP$iDjm :b:{B//'$ś;;wXdiv2JF4q1l>ي>U_g^5ʵYAkupCwrf[_9+Qv}}5aْ,s'i*B5t+qIkgWXm^HzUjM&C%`,'W@i-41~(ꌱۆ=:{%Qy7;nY1TIMuz{ ():&hPWE^&kq IgV $ .mR$H!k r-usg"FJHCB[Ju=•^%Bɘ=FVn6K H#8GvKP+M;hWl:_jw-edjD^'`.] B^nS/՚JB(x02IpցC#0g$KwcsOT@*yqAʭIaÑubijW?,nJgN9wւXcMMrqG%<7yΗ,G"VgEQ KnRGE3nAƛC[A)Xps'DxpMgt^JxWi]12[q C0bf;|YT$I݇s 0Oi8Aa !pq*.¼ʹD< {fIք{0":[IRad܊Qqk|͔6FKv $  $E&@>̃푆V`Iԇ-RԳLEtJGuܞl#2W@Q"33RL\Y^ri.u-Nbm|S rVXӎ.T3ë`y u8dO=Iӛsd$E.tvu-U# xyd[Z*<:>rg N v'0%N{d)vP1qRR<֔ſ5~ېp<QiL ڣ ˒O$SS3:]6:;//e#{ڣ_%cit5%GWBĢ`%p ukMc]f(WBjI>=&B+y̵IEa5+y7sh>NBiږ/$rM@#jk;+rUrD<],ڙ8€"%PGʙsCy`o^鑮4+|P:G9FU!lߵYɗN<۫25S4fr.kpk=cNy{^zrDT%K=0͵&bħ.j#PmB POÝS&=1;N¿T/fKWyt>sMy'Cl\ -i0Z' "+ 2{,Z}(I~c+/%ڋx&r:zsuI|,IXc% kSZn^xTPR%%=깊cd쾩{CUIGp&я `mpdz{Q(]4V yùm3^^ExGUNJe^Y 0Q&kTDM!Rvx݇TGs5H pd2{?U8psq[Wy͔D\MB 3Z|yL`dKԷv<";!z&A-OF<pT!yOWʌ, LKJ.9Z]"e&$-%3 㸳c@=#!<_ (r"ilT^Y_bfƼJeS)w#K2s^ӵ#W h6=jޮ|:&x/i&s%B&$K_>yfecRcԹ6/ִ^aRW6%xW'Ԕ0q%0өhlQ7vB'Rk%T_i,˅Si>6!bXQxYxl&i&/z '|:-*5W>Tkw8kIZG7V?lMAmm?.uFY}dl%mL]^њ^f WfUѬOɑqҭwv{.(wJkJ7)-R/sȞF:+ᥳ @ʩGjB30 5#OP($ OX,bupjiAKǫoX^;ו#(Yj(:фO%MFm;I[ީ9JU) qJ}e87Ls,`BN % tx6 ߪY}ũ湄^i\!D֢eP2-*׹{*w'ܒͬGsz܍;i7UH:]ـ)GQ픬 EZ>JYVW] ei)hIx_\_t 3Kz^'7Q;y?;[xF%%hV$Հi{"]UBIv뚵\.$RX gݵDŴDa' ehlvZ_N)?zx}ѣOq~FBzP0jŪ1kIgrdqH II6ug"PrUKP=<M^٘C#woyY`mv&H<YBVP07re6zsqi2دtTL ĩ^ݝCC$'NIPS\mي=LjvZ&9~XǤըQ#+~?$9#xS aʃRN7?մ$09ج|оAe(iExjN 78{ؤ0X4]PB?iɳYEjrA**TgrpA*("(i.u+Bܖ%fYРKٙKZ -K3,2F|W7|՗fvS'i.{UTa)7qU`R|UdKkGI%{y,@mѢYnX䞪sZ`1hG4]Ƣ 6]!+}i}S\ e-!i,7y(չ!Ƚ4*ձ ꆜzΏ(KlNR<^!& H{ "t_I L<׿v.[Pm>Ct=x>:0Ont7O5,o"A+9 h:Q8.8nq/´oe3<jBgkr5,9 ֽ<䏇 $.` `Y 7uym!7(| #흫 _؊"9sT(֥D U=HrylWUҢIJm)lOMq mҀ>ۤà1"8U\͓C\lP8pnc}5DM96刓^aH4UʵUWWeC%L|5]P*e x<~z}#:@ P oY9˥yU|YzDv'Q',g=9\lnbQ58jd$c'9^N%-kGAO`&`ŻWC sƻm87eUU^T%Fyέҷ';_/[8;^Z =~SQEyX@hJ.jJǍXh5i>zL0ϗ/{EiFGRըb :w##5#HG46 n`ÒX6䲊Gupa{Cx[>ko=^00yH=R'f=>U)ܐv*ijT#oηwIeɋsU "ds}VQdͤ"Y]Qe.9X%ΩROu3l&w>;ϹƧX^ԧboMϖzE%쉉D󴧢ҳ&B9X {mdy^`m [b[k8Ʌ .DJ֭ZT{Ep)2z :WswjAI<'_#=ׯ,oxt$yH'G풇KiQvaS 70A3RyJb *Mn! ]r* UTR\鴝k5 .t\ (A\q5_ U6{9K>=yM1Ũͻڰ'_&ы*(<2t R%OEW L{ {΄.p( +{=@/5%ljRo"doA[GSK>^ӕT_8ɑxʳ)~sUPTI Iű{'|s@DBA4ꊾ(`#ʝ Hnlx{ĥ_Xm[`2xTM(^u52^v * 无ICg:e)ŔyG̕UKDɾ~< } `'J`;ժsUq ɰϬA@YHu{C{¥jU̬YFi"!里E t}KMM O\(%*~/`4?1ʡ nK-;Vyy9$ةwvJɣ7Wb}T/p[Nj2z¦nC&hSUnfds%P!r!zBxۘSH֎S$O䤎\ J]V Nkkx1#pX9UP|%A:Lk>)bQCّ 9PøTay[C9,,瘱dLT-}sYBo%(Y*t$Lq:i=<C>_ ؾpc;Pa DoWJgيqbqNPGPC|#ii=䇾FȀ\H\v?u=s/=B-]vz6ޛU _8ػͤǂddp[qyCtVj kSۓl[1+S~$eu-˕i{ tĔ >UrthgN)?6]*8ހ'ʡT4ɄkD7D6Kkl,,nP2$g;O#;xKH>`%e$PTp$t&39ꮑ۟:`ϊ}Blag~?k.$AmkW9x<ҿmϺrrTt7?omT&%IY)~@iQXynnwYI(GzhM6ЖgWt]Vb*?-CzVբH@ %*YDKؤldpÊ~oGo`w꩞|$MQE-3Pb?Z:ԧl_H v?ެS-)U?h-Iiϛ U8ѣF+]YB(B_^H575eldJg̖"w"J}{iyM%-ܤzsFւ)St.PEfƖIœ1zx=TN#in.(%hxgۂ95l[!m3KXgҋ@2ObW%F6*=[nuP*^eXz*KH6 YX6+Sb=dd>TyI=7 tѥx4;?ޭWz&aũV'C a(eUMtgœ5&.!ޭTLc6w?qjc$@*CV6iǾH|dgjM{CjlUHSf`kL.*jCF!E1sWgz{6UZRMCK6M֊Dd.!g% hc#bt*W2D#+@{Y\Jf~MT@TX(h]/ڹj[LJkC>kȊaTٹArVI]N{YmJQo"Ak6fdknP&P%E-_jQe˝@ێ+]?;(8m)^鬭";d Na1^Y_\ENJ;.Ȅr'k$åuX8 h #vbD˾s0@bqCPBP%%[UoDTDK) OjUZ%{ҴmgQߠYRa7 `J3[Tnt]wyfgTZ:Qvj]OWֻ_B0@NU*՚[a25s {c騛[#PRWHaKu aPߤ}k"xAۨ^3; )Ww1TǭX鞷d=pbʣF|),MoiSC7K_~v=I-K@GGnc(1>6.Q?h,ED҆bmʃ&VG-k][@Ij\HU>4*]CZ=yZ'L3imw)&tvZ,|iN6sS0Wۉ5 Bg~ӂ)<* m_M3󑪄st&`@Č4 K5çoTݑzSk&u(Sɳ֍}s$ ]ҧt4S *X!ٝj_a3miKG=viaw֑ts*H,(6 v>T~Y)[˱^>{s^'qY`ҋJXt# 4}%jh mM~_Ec +edhQSoOi@^gt+E,4РFdXHS!p@:6#D5ֵJk} \v)zyYk[Dtfcv;SGh}ْ6qfݚVjN^zlr_ SDcN5yǬFWc\#^\nwֻ ef=~ge*އ]Jm_CLTY7oŧZ낱Im$֔XoVcrT.53p$ヂh|b+˯ANOQhxoDTG}Q UOZDQ_v ʹ eTߧPq!>ZAףunRkjxӇNѣoSc3Cc,jl[Q:YyX褗K2]յc xupvUcb3-(35٠SNtù}%XXI="raarNr K'+"t2J$ ؈zka&u_S-զP'χ r M+n&5ϩY`j2c,/8{(N{&QJZJG-s!JTqwGcgK1T j@ՇMP(ģ0@$0¬DѼ~C`& +kUbguh*A{Ayr>;zl[6U[A ک4^v\l|60#J t<֞ΤemIWW^@ݪpPU\-J8[`~`CMAµN b8<-FZYzHEw衟Evn~:t J"pw 9vQ&M(1mxK=y, Ǐ``vKuUGͽܚ:dRI@srwjiBˬ!|Gaj,_J6ʠlY'&:0.\6QZy;+K3èKJ&fyG)=iKs@.u;ݠXM 5)ldd~Ǥ?vIQцGg@D+kgL{8љWƻ" S%8.?VE$PP?$ۖ%= ~{ݞ$QÊ_4Cq$P"ʡT"bNBK7[bQ%X[gtT˞{6?zX( ]aZPJmvUW~\ePPGJ:C(!yصX8VIH]}Ŧ#'Coo']Lj虦ud$j{lצxcD墜!;/ZPiU̎~-vhFp EDl:WkD V-<̚˷Jꗳ I{Q*hGi3c;J}eIJq ViǛXr뚖edǗQ4$|]硡rum+۰ilt5%7:ɕF}ة:Z(QyBNbRRW ^Uy.פns3|T*K\NZJ~aLڢF6V5>oeh{3<}f٬l׸M>hrNn vuĿ4z@HcSr0Ȗm~0U"GtT*XLIghjFM9Ⱥz/fŪj T~ytNhItiT u2f5B>BI٫Z7be&}Iw͟O(A&U\83T|}edy'ֳMK]23t-8|hR9}R (լVyvHx FY8U2Z12D *:~^[R"l5-6)l6ԉ I)nT@iĂ{m1 a|*ԧ0pqs( ܧщJG4"|nzx՚XMP !B]5S URr&Ps;s@mUBRs~E'ϓmւ*q\F*@@Ѯ"uϖI[w^CaMVgzn[0zSиbI=|n jxrTu:h LfVwIx*ImAQXyXb{ҙXaKěrg*=y,AœrT߬ҩM0~K)&n*_v kelBv lƤ3拒w.ztzCZ-j10AjQa+2rZs*[yy<ۦ8PJ쫠Y D={ 6 s(K`)s)~Tb6ÄNj[|բ,CxUdœ!zL5,rCQV?Jكs՞nI{+ML`ceJyG<{PIzTyBTq&@Q*plU2t娳:K]j漛FVuVEãOmiTCT6$;͟{ԍ ѳ!%5⢞k͢6t`7Ψ__fOW~Oooy懿MƏO1}:-RiۿOS?~oϿC~wOן>=}?+>7}!|ͷyǯ?|͟#W~:ӧ|3W_~?>o>\~ͷ_w߄g\o>y+՟_Oϟ/?_?~}_||W>}o>ȥ꯿'~~<| ~[ӯҧ_}ٷ_~ʧ_~W_og}7~|_ ~}~UW~orQ?.*|]٧5.ixp?oql\\_uWqk.7Wǟ??븹?|:n.?W?}_qb/W*?[[_u~XS/TŊ/Sr*jr1տ\KXJ_xB(Ɵ-#׫(-X~%_~Ο/~zRI\?{)噦˫/o?_Wߺ}Fj?>~/ǿ᧟c?_M_/~7_/HOnR?~~ǟ/4~/_x?_|ّo~ß~?~?+}-sp;{_nc7_=7~ n}}3pſ|;O| @o7k6A>_.+.W:6r} +.+.o|Uw_Z_Z/_q-+}kT3󗯸ۗ+?~kO_Z󗯸W\+йǗ~͗on#_7?w\ǿww˚2}_+\us+W W_r}՗f2՗\ש %_/I+aW_rUW_rU?~O/W_}U}=Lx՗\՗u՗\?}%W~%W~r'PuWƔ_?KEӏ|>!װ&~| 7_Vۿ!Hh566/7'-)O?v-F_[4-[dºpHk3uA7WsS+_mIUzuw ŕp>IҪCZB<%~?3տ^^e\tYl~ڸPrzSؑ;MEE0JR ^'mHYLi8YUu1make]gZ\\՞o߸:Fϕg*a-O};Xn{rQ}_5qKV,x[ y]()mq:;7ՕLorӾUV1'͡VT78:Ac]M~-W&wrd=0zsJRժ v=uz= KM65'˪yBeA67D#?{ovۣ>A⬞bĉwϫv^*ht˧CH٪HDP=ԣyxJFdյ7]D>*ֳ8$v&*"|[>L:7tOdW?䢇RdѰ.Ym5yMQ%UNySWeӅ򪻽TzaUBɬcuͶQ͡J™>xWy߽5(XNWj3iM77ۯ:e7V d'W8RX쵛T5lb)iWézO+ղ:oy}*e_g.=a[v\-%8weU-C7) 9 yg'f85qĺuVzLRQe9 Tr~{$%ٍӁ }TΧtX8t!ҥnD#ЬѨ'{RFi| Q-6jw+:óg!?x쪚&vGe>;q6.wPo {%l+V7[ =1.ezi^F$͑Z*J;{0HM)N]cn #E[mK۱i4'6mx-DzH=/æCgu\)-WfŪBv0u=r~nR@񼏿d#vOR`J9[xPM4e/~M{XqkI%1ġ>a[:ɾ$E⭰_YNp ]Nr(1$vR(p̽aꗾ"Vv01cFW&NT]v?8J4yU %f6Ґud8̈́:l Ħ6MS\Pyי&[]=ojՖl7"۽E0%kI`VۜϒWۆ /RB.Ngb.A9ȕ/9*,IE9hmkY$ WO ۊ]y{ K6Nuxm2+Uuĺ-PP][TWz&||uɈA<%-V?H$a^7]')""{US<5p92e/g8nk|t3S逸¶.[PQXa2j4I 5U,Vxؔkܢ`J\m7y#uTLeͽ-ċN3{3@ V' KM}H%l`tan$/|zh3ɼNYUh)5 s/•,gzSE'+VYp|/ ߪ=`~42ԹN(U>/2!LՃYx;x|Q1Soq*Q @UuWX!MRE8ƞ8,E5}p!tMSS:)C5"2v% ȀWH%Z1v ]KgUew< N:[/} [ZTeQ@aZNO,JqzS <Α]om%/Gn'ÞLVP"RHpI$I$؛@.aM9`T5m8;NA74ƶ)jK[_=4pҩl~i ֿYL<|LJ9Y<,n L*mn9qXH0S0T$z*-_\v4u"#Zu%0>nw{-Nr%,:QjkīVr=*SGN vMV(}O.E_W){k#m B\ wn| l*X*qЦ]Y]gd  Wu~rsCےXcYTSȩD2Nۘہ)YCZuR>uOq|(m[ATJ` JGRx)Gd%Gg 4R 4nchT܎랚, 2UV7E.(N;i@ڨ[V*N *}{mf^ރ8'dwqAdy-.FfR81TqaNށsō9}m{LRR`HN&b)cHN:İ-p'U,; ֓.-VPB٢ ҢjcBs>b&'# ;($;85n8pHKjsh toIxgJnTG٥;^~Q`M3NGl 5LztWYj:K&!~iLh:s5@17F0Y?OEWm$AVYz78cK#C3WaJ |< *[ .eYJ{4R IL)ށ2"z|XRba¡XE(:+P1u wFUU@V57Q78<1Kj»prc]5ʳV\ *Z\3ytr.EJuICojBZFVuGկэq9C!4X$u]Js_ Těv8W&=#hT[ pLͲ*w8] *GN[p`ѤbhV "1F][] jUeGSlTF~*%SEsĪs EuuHh|]:csN*jƬ80%o!t{Fk|/mӞ5aakx͟QK'S[KƾXQ톤GV/!N1 Y_%?̖QiU35e%2hjȳuM>; ^QOG'.q[WLT1$kD-ra;7 ׃'NЖY.A܃TpPnM6#]ۭX(f4KPyv+<;DEId $8PuhxhNK֗R'~fVu@ݝ+j"Xt!Blߏ;ΊГZչH'xzjJkԐQRYyS+֔h~i?K=ȕT/y Ex.D4c"1N.i<>H7i?G:]L"`>ѣ)E^c;jYMD@;#Yn-KґU銒樖_V(B1(Ǘ7;YXmrQrՖ7sVop)3 ONB}1-NՋ# Omu&1ls i q }U' Kv  kdӎk UCr6{ԂҼM/v8%p(!Z!*aubJixL}L2)>m?LW׷zU:j"@{GA–8XǾr @K"c]8VnV嗖2=y;K(mw0KT<\]G+`rRU- Pw_M0@k;ʎ\A5W%f½R4•+:&xVQ[zdUX3ztp{*Kz!;Dv{"xTY SW].߆>' R<8+]AiaI)>mJHYAM,(֐o'>jqF*>C{*ÙggAP?n/ HuPm j'֧SCΆr2Jk8.̒: a%BGs@6`o 2yJ0C>R.:yvϔs8nC" Gg"z=c{SH(F׮G;w}S6Fsp :ѣ+K-ab/trgluָ$ځ$20=5f6/~kgWwNaG>:/ՌK&~]j]v#U_[V`8[O3@ \Jz\ut\VEEK"HTYünI]P~J{ZY$Ǖ$BHzo>քbdzd[U7A/8N[[A1J!Փ  mUPew<]udv q2;C.g[kaG&Տg ӾHVlՓnyVDW{gUzf˒=d*hcrRFF%T;cɺHPӢnu@ 1Ǵp{g1VU0Ҭ&m%5͹[j޷6TLcffo;<2llO^,mlzMCTb=կ#N*~^Ȱxe[N)5):8=#~4=-M3@U=6߇' mPUϼSxkUITK<>zoblBLx=EY/emOBʶacfۤ|XEgKKozNjЩ귧畎).RI6%eHzt޲_I,ru IԖXt*0w</ %}:k-2pQF3vĤ\g[H@F,˼vR)chFV$n/%(T~<^OLk8ʻͪLG%n󟨟>4iM#IPE|՛}' wISW]`'M%li)=pRhrb2v[T?{ֺdK4J?'ymD.K.kk~7'dm8!$r{燒?+g{,嶣3j4a#[s;]̐qO45]B5c+9..{4J'"="{&SUS|gA!Iz[jC~kIdQn챹ՍƎ*D4@^BM^4sti( v6g3)ĞCξn15a ] jKiAvՁ+U:S+OT+JbDէ`VSJINIm7!ۋ8C'w$\ñ4dl1+0j jf\.PSO*J,)M"6tfs*l5 uQzJSG{)NySJGԂ% 0vvݶ`O$~d8ySI1_c!Iz5V<0fC~Ť%9N[=0M=TW:R4j>R0I$ߵ"?JS`mPȤ>ۼ)H0M^*F B^d @_KḘ\K8y s`7w3Z(B[BX.նxzMH`1nƠ:enk)^n(+n#lUg%0um &w&TY($ӒGb-PN6̦U{qlj94k GrE٬=2(' Wp-Aҥ{ yyޔV*f3G+gl[D1vR">hY oUxٻKەr {cBVǿk1Dތ k%DBH*mX;;͗V }M&;P \\[mb{}YOzFy;kFz&;+-աɫԇw9| $_iro)(FrܙY.SD-u50Of $<)uiI\;Xkj bى"gSXg<26k)NdQپ&QLt1 '`m>16wTv mmy@Bٮ kxr8hnҟL太Џܣh*u^=x,u =L 梸c ŭc h7|UPT$-G[͚NˮV}7i%ER{=,bЄU*ڳeSu%!{qA3ܗ1}ӡjNKwqS; F.:bf;M*WKzⁱ/>zݥƃ,'oJ_`Q]^L̕xZᤤd}R]|^Tד6lT Xc[ XJbo_6-:Wiի*I[5B::Iua+D9wY6qN}kuZbMfK&x4!}{ НW/s,[|ԧ?Yp hc8tT)w)Lc9ťMZí)a8 ৳yN ewJu:T&-;_B.O5v!og,1Ԏ0~uZZ;JE6ve[AHeR>Hq`Üxĕe q>2g"{*J@}"ƹb[!\*Apaɖ,{rgwG=Jc6cToY$M]ŦԮt*,V<0!EbrxJ .WBrL}gN195,G9tʅ{=Eu 1M$,$h|*a*}0,Б]P^xW]f7[kz<7mS}Pth dcN(BZPA%kM0}:U#nycSxMI[ѴF&a3oIF~B*4C8ۓ ٶPl9&g&7G0.\}`A9S>!Ksmu8FO@"Q74QkLIEڐQqibǎzY6dCw h_LR$| A4zg{ETP݃FnLMVhZԦMi"@!m)'7gigGi;̛O5 z7*^*JuivHI\9R>Z)cXb5!y6ni|A3]|N2WAYEKjM$ 4n1MzN])\<]kEb/EGu{]&Jhu&[tWZ37:X*MpjT":38B}xn{E'^ *_o#y'L֕\!pm/ l^ՁųYJ˯<8ʩs&tZ1jl+M)G֬o(|3Dg8ۆb&kb=XDnMƻJ*-TVݷs%ŃP): W X 珑. 3؍4 JMKeʪ`IY}U<~iվ#L:GnS_% AjK2s"D=-S"lyzIUZVBPz\J77Je8NӨ4q )MӗAEA$56VY9 4U"3`fK3CP4hn3VIvu-YPj{B9eӞxSseJo[fJ^o?Z.w^ اԨ0jldД%-ǃKg_=4l}c+J^|K$gHl )V[mRNvUT[D3* _&T{mBJW'"&ͭ=A;*h9={Yf)J`ˣG,U2 Cer(ux^ )5,:Vs—eaVsS~eLVp Ҏ7dnB[ lRmFo4-b>dBUf*:ť>%2<&qE _4Oչ}d ĶQUB:SUrvRՇ ML.,\2R,dg' OT\;x(Ʈ-m U@C\KÿKz) <#LQ. !ɠRݏQ$89C? J^;kr>m:ȼѫ4c8IRY&e©;,ԧȂVIIPt𢡄`<]4X OXGgp>ސh1Yh,0-z֑S Iz˞6X!ܪ6<S5T/oyV<okwb2j ;NPFWcwPs_ ,μʻ)NFؤMyQޥ<AJe+[U.`_YW e}uٮO{YO>OjDǽۯseՓdRmRHgҒ F˳˞^;? Y b;;!/8]$OEt[;Ҷ?LKԤu2&~̓d?dQk[݋ET4lT_1l vf`G̡g~KŖ㝑y` ę3י5h)l{J,gJ7d@m[ki#]Ws}qqlA ħ:ql|pTT~-M0Nc O:Rekod*O75.m>^@,M㙺wv-јtUYD"(L<$z-ޔ b9Q>:4x{$/!~֛EӂI1H][7&xTxy,A}zTiĖD~/QR6N D.&RWu*m@4r6m:!&>l+OgiC~uǸ$S85>!=vIOY1T|;ΞUdU!]M$7 2OyvW!VqlN桶EFI5 QYTR*VO<<nJW6dHNG$oElP!ȧV,ha;Pdl#.b- "Zaʑ("sB%@TVHC.Ŧ;IAν^'ՀpYqv ]ˋMؽ(+|n{5u~ok@&8:lv1lo]P7GvV[9bȫeEtcꀽSI3"a eCU-S]ŧ&GGm9J:@28MB&Ͳ8@|I~RTQ6@D/!C?Zbn,~}jm7^T@.WMB4q;Rh2xG شIeSoQ 쁴VQg`㹼myj)(.()}۲b,0嫆8GֵHJ9"*}HBQf/+p m#ŕGW1Q41&$Wźd(}~SgXvS"$ޮjPo.>7cָ\gl /UmER.4RBާ OT8uȸr6jf%Ǧźl[w@y&9Mdc1Uu N+jȀ\3uLlΗ2$z%cl*R]BdQi'YXT3tY'HǓOI lG$哪JQ?%tqS1Vy $.[ڤW =Qpim}&9 ɚv_%ۣ啼*23; Yz++* O vΩK[Ҡ @rrxxSW4T[wȆ+Nb\ H!I֥pH V]6 e\fU;OU9)5P5kEM) Ps$CEJB6E!%p|~ @yUtL=IF TvXX#I &yF^MV7Naݬ4t'ԓ;B"]G$Q ʺTm_+@ELl-1'[`hL D-:dsjqQڬ64QN\B(8K*6KGV*IدnbԞ\ޤD러V:vn%eU^KbLAQ ,{<[HXR"k9W͏ Xyo$gzuGbg <'̵HXz 2 B6ӽwG6^${ۗ L/P&ؔ.U-C :M1/:w䫗 ۧ\gMUw}k;7*Te̯G.Z#ECx?B5ezJvGFҔtò6cKAdv4RwjIbhH4YvA/iPjҩBQ<G; 05*f%:qjR9;y^\(VOe~O^/p:XU x#Y ;Ikesx=M5yH#l48ݹ< S/^4Ԩi퉝JUI*uC5zzQ:Pߺ dI-i&ɜcK@{`//.Q%R(p)`OΌ,74nb Մzⷤזv*Emi]'BU4zۛz'W<@C-S,_Mri@I3^#UC~%Waoi7*I$x4c!f(DUN2otBkY%wxCA/`*{ot\a΀6tZy~tz9h _ ,J`+a-ڲx+7'])9i*:S veym:nnM #5QN#*\Te߰ a^I=Ŏ[`6" P Fټ]j EQx*Za j-=T0u*M2.,XaZu P'2Yh9:B`\霗>|?{{cSE'2kB%c`2Һ}4 fVO(n=G~y[`)^*0Y ˎӍI7$y+y6-M>z:O`M΍R#bZkQjXPj#ɚM(h^ꐒ]wHPZP 凞T,GC"YKLDX:7OP}asEagwi#96u*CEĆ}q ΍P 6kx  ,'{$RoL_*1ʖSBd,3- e+P)AuȎ'?+JF#DzM|M L{ݕ/o tȔӉMr'KȄ0*8 ol;["=cvxljoz$>f$ .5BDˏܦJuv2>bܟjG>Mqi;n#(xFP٣G6ꪋ:~uK מ V}bkLvQ)?9F nև̒:1𼒓qPw MC֨XŲDn9VeqXlA"{DU~DR)Iu*S2vD );)tu$ծ5뙇g:{CmU'U͑!(K [O*VḒt^2)C5aY '.Z 09$]N=$⠑~ypH<җ$kn)/Қ5[Q:diG7.)gٲMBv0YǍZŶ}$p cX{o@::ituGO/H9T"W4xnkinĚS2U>^L#)>8yl) ha v+s`Ku:GG/}-;Ys{yۂ'}+*Aι)RxCQQm'{VS^ZilOKt\3RDirz9/hb|jFkO΍ NkYaCIſ4nI:rG{(T#U-Pׄ ]VeBi4q_n⿒^xm0I SU.A-դJʂ2C!6<]E4 ze(I$=X"PoQ/Cui5,,96r+!ޢrl;Ym`k`M]UN2sO2%HSf[9ɋmV5쐝%<nZe aK !$9Isgik?4J4H"V[ɹGK UWi]3J_ѹzʡ,Dӝ̈yW FAD~\vb O !*.$!ob UzRqoٳ[)xj ;|`8Y?UR[lVs-pr8Uc\j8^mo2>/ɣRw;+N]Iel^@ <^#5F Y(zI~SQrrfCy ϗ#-F+'uGW~@;=;\8I<:o#s ʧ^RjN{,ߡ QSҩō|p*}0E{gz=Q'8~6֡c(ʯ7t@+پb+(Cit9LP鉽أC?kQ4|Mq-v'D3:^J:{qmN>M`ǩɖ(2((4|[(H dvsJjtyO#2X&vَ&l"zyn`ٙRNR N ɧT9}{-SGwu/-¾ zĵ{&M9<)R+.NQ+K*l =NV| I"RHjq`"_<-3m<cњwdtʠk(dWEU `wV>?aQ`Tz.7Gطv<^ˉL` qVƖT08Q6}A[Bz K-TPOt >4,y!QC4EV8:'~80|)o꤃qq̌_rd rBC-Cn|n؞&J8IA7IT!NZX)(Nh (n-LS'#̐y>Imն<w4w2Ȟe޾}h_+ W?Rt~ Z u0.˝R1g9!{_~VRZ] QwBC ,EVHΉxDG=)nV5ݍM츴P}Z~Pxɼ541nUtb!R oBDzein)ȉ]Q)8W (`0[,r5Ϗf=qWϽ)x;UQ $-GM>5x!xR--tWeWՠOW+CF" & |ַ 1Om 34٦CW>[uVtuR7^{[*Iu\=P*htRV;&O]JL8eԣ!34ϧLZ$1Kt#zrʐ \*O@!QE ƎIQ(~ DWsX1g^+Ά&S5ixedօCe89XI%gr{bv˦2 @V3 k/ DNMUU-JLp@O><_ֆz"7]9yOԂIv4of.m-X3:aሼΤZf;sR鳲Y+~ERҕSOk鵕IG U1V zG{՝80%O.;cj|S} vؓ*GFs锉7uymgޢvj7XVg.g4,0;),"%*Bh)R>YW,rjcʥkT_MoKN+#G83r3}@_ VB㓋/ t=J-8. X>tDg)]c"XGIr͊;)G&)IlӥDZPY#Z5Hgky mθ5,UJ[*fnv G*f!Ibd/3pBo)0r%'tQ!H'f&Oݸ<٤\>GRhYpNJm"H%&|XTŧxp=ju:6"%ז<94orXFU!W虝|ڒRCt^]r@i4 qÆ2XQ46t`(8oW'-UY<Vzk(I&KOeo(ŢwXb U;ޮ]b8qeDMʏjvcO>mŹ5-y266ԡ ,K›:ΚQWivjm7<5JPz̃;_XSj%p;2%wf+TؙFbeӍksrwS8F({xwZ$5urDk"t.:ٞWq3Mym` ζNeKzN $WUҖ/Of_<<)Aj+lG^:8Osnz*sZPM6ivvauf,TKO[4Y a^"?ro+"FP36Wc`jWהCݴdu{0(wy, L%@ *J傳Y!άʖ$eRkogDO.ie*uNVN⑄k 6 NoНkiP<%ndP*x 2jl[vIےI^q n#@M \IlXPC\6yTˁ|u2H T\bzd=5"K vK@IT`Ctv':ց3sUB)jM,Ki|o#c]>{NΚľdZ/uu"P@r-Urz#9xlvk#o 6sQ5#J[O%8=8}),}I #BH&F};nNġ/$w~ :ɝ'&PfN4Ҥ[3aAn#ÍtD xMRɃTovcgTOKpZ^;"E աs2^Zg+a5JFKga#[Zxs;>搨;=H%U/X2I>0yt6lgN{RT9yʼnzPidԩF1mM+J^uʰ)3ipUgkaGy-_)$L-p澝UJ nj|J;Qѣ 1r&IQv*+n C{]uQj&Z[+Y(Q~WlͷŇe_j}lW{vrFdθM jY|<-:(y7i$yԀf~,n.dSd[2 U ?fe@@m<*3i&SjskxO[n7+kiIc2UwȢQEi#“s|bJ}W\ʳzCL7XjI#[;]k1fܒ Xۮlb <q*X +}ö89*ղ>%Nc YEyEr-K#jv=uz(R\۹?#|Y1"n tA5BW,`, rHܒ/k)$0eQ23[6]>a7t.(b"3 K{v] g`EHaM@, &ytiUWox<]'nҌmͿeg%!8U-,X.T".r-H`LϓJ"yRc+U)-'G#i]Uցǻӽm_URţ9BjV)0S'#I"D,@.OK+M|U.I+,8:_v y#1>7rJ6JU8JIEϣG^) 'ݳw}%# r T!YgAXbnFŕɢqu"s."w0 ʁNRn+:iPI9m?K8f8Q| qr,9a .ZCxt;vR어C|#uVv$ƙn"#آ;K:UΞB2Y.7.U)Ax1Sw7Im <4lċskT[n:-+c3S @;usӄe!u?9 0 >ldΩL8̡x^6@hAAEu "2SnM8}X:Wer%v#gmkH(.šuj0D0=WNkQ HmP舔gq 2ACz8.x*c26YkCJBqX 5B 9!v'\Rb3wU|2I E>Ӝ%V |Cθl۽*¶8(,H.B32cգsdondm6$Ŝ}s- v+7ԛpU-Y'=d;aٶ&*ڥc1$?Td '1+/KT۸kSa\&gǥzVGlzOymz=?Ŀo~7_O}|Wo|/?yſQW7?~߼Ww*)ߔW>|oOoǷ_~^o^{Oz~ݫO{o{woŶ_}z+tWU︮Wf]}u~?ͯ_ Wuox~/|?>|~o?O߽xwo^u̿oox߾w߽YyOǷ㗟u߾Wg_!D~?W~7_GR^՛sW<>n.g/|x+ݧ/_?͏ʯ~_󫯿|y7?޾c39~-w_oOj\w˷_Wn㢾6.狊_U?e ?|Gpo|kٹo5\x$\~xycp: \W?zkP7z#ltg+hwӝ~wɞ ?Rg;*tC?Og۩TO϶NJ)ş~p_RJ[(Ï{ͳs~{|y|^^/^u_/^\-vÿ{O>~ӏ~ry?˟o?쇿|O?}|ZӺ޽s/|yx+ww߽m~w}y X> [`~eA/W~rW\bڸJ^^qaw/_^q-kW\xzW\kǗW\?Z+?ZחW\~yŵW\}1\k/{_?8+}yzÿ[>W~ro.eC .W/p_8/^rox9⥞拗\ox}ʸ/%\7_8= D%W/_>~ҧK//w_^\xU_䪾ɓCFo|u~{է_ܐKX?>Z}y@p~Ki>V/o7{2sp|?~|ӊ6o1roWÞ8wnIZ\wYoS)<;H80VT@-%+jR!PͲ{ij,TylΕR͜ܕ9Jp;ʦ)-. mlӑ>SZ|O9cǒ/mj[~ #?e{펋%Hpg5[ǁݶKc}Sh`Kqb_Xm_0..1.}v{Q`єar|f?,Hǽ愷vm?Esrʺ(7eC(J&~2jcz[gWJnm$Ŭr^J?穀Z}lǻ-?Ͼc۬]N}&ٗ4?]u<ꎉ='KƭďEo{aWQd`^{V5726s EȪvfOTawad%RWԨtkdL$t3MEPq001e9sMO6*W(Ou徨HcI,3nPbK~dZ1 [ek$Xƃvdv@CϻN>0&mEqfQP$ {Rk i)[).tZ!\I<,g9{2K'bea1׻NCͻw[?[0՘,%tnX]SlJ°sV~9=KTM1[NJ(̝ۍ5ZiB:q ֍Tאd%-Bܒ a+:5_G# !GMxl]Bw{W1v50o3>R!;=MNW{X=*nxՖLry;‘}إGCm,HE~w<=K90C Vuiz؅.xjqMye+/Oqz7CY]%%0#9$?{6@rg[?U m7*e-~lT,l,PKل ,^]3s8cd *|Rsvsi/xt؏JKJ;rR\[gI9{U魕qlfGRncK+o]V]Ue;h~QSjg[':o3=S Pw^@uv+<-<7N!AچdvciXyig {(lB-Mk~!;erc;ssU"&#W)%q̸ܨ*b^1=;*99-GN+O>z஥w#l{l1wǹ >R%ru*TYZACn.񰡹03}훚9Yˇ#Cj֖Br3.vU;c_‡WA,yiU΄cᩏy)A.kOq= Tձ_Je*Nuzwt׮\e)}J|2X㮹/r&ܡl95S!(k,'W9ng/3 %%Ɲ-)wHo^^^-"z7'H}RdTo8_X+FhXt+Uu􊲁'RR5j!LG[?gtsc1CN gVi/'~C/ Hr:-g : R$ۘ!s:%.)㹝]`)"!#+Rs $T,2(*fv¸l*m ˌ')T ]rlgEdCe)5[حuز|셜y5|W? VFKehq~?h c&P12HnXt<ݩR)amSXK҆QՔqp^a=U5lmλ2Y=2PP sB bܝ 3# (`[mr,%Ϗ[ OdqB2;K؜t*KUnt6ATE%# ꎫMfGO>Q[?U_ZrkF-a> qiie'lvdGDIZ)Xkv-7䂯'HY$9mb1wi'20,`@R،9\Qx2Gxsnlg.$#շN+I%l,.Y=]zfq͢Q};TUP^AnpE9J$X(鱟Rp߱aJ} ?X3[2la56 Xw|x8ܲ#؋ҍy=}bU_ ^Ȱl0g[bA nU]cjV/e^ )ᗈe uo6]P?OBjڀС)ʬ dkx4Q-~-Ѐei<俜; ?¯!Zơi!phpJEQxrb*x+&9t w{'dPK g3x JSyqxx)ܞ"YhYn#`uP]* uw;,%[W\NNI`AΔIkx2p>ةJa:ppD=86mqH΂I $`Ք/uT2n i4-$M`&~%1Jo<%y njp<(jenvT=_?)ǫ48 Ӑdx$4n+I3kB.-#fwDQ4F?A9#I_`oN+rYVtƜ J),"' ^ O,#Z#U|vVʖC YoTՀ 3@g(V0tپí;CāQ P7Eyvi%`sNDZc ZaI :ʘ,׺dLd%P;~)'(z|$M<|dS ,ltW@12#6j?lQrlM<. S5k;L&8h8#~0 :fdA,Sa;UWPZZmL# cT]]kjHjw6Hc.=ut6{ՙi7lqT;Ow cqXNG+XFa+ ƃ l556{#Px*vG?*6~_Sq5+6Q@_eJiĸ-o>မ Brg)quG[j­@vfUym%6sY `|FT.!I}; ?%e7<]=l0?Cv30L]겫i'qr8fe\դf=%6[׀y0CIV\zصd!kC,N.G nh\<lݷx2: ƌO bJ'Xjp{BHjKV5)Lۦɣ3d NB&lQ51UWXhl$gPD FʕyNW6 枦q8{ĉ@vZ:BTyM-s>SLeP@ W\ C:(uӏ8sM*&T\,Қ__Ջ:bd9AYo}#O 0NT#!#$AZppjbj{ܘqK{Ś!x~3۟kkKFU7î~40у!@aeCw5mT Os*bEST~b C$O&Gʃ5ZG33/fŊĖwwՄ4B 0ʜg3{wsMVUYMpݷ̓9XwE $ KUp&lZtqϞ./2.}3UtX5I]%=l'?놥C*4σZc]bɬ/>u*q(`J8?.Yd1of 1, .p<Čh!e٧r-tS.7L/19:|,MiO Ⱦ  bG4;0YkgC>;؅9 lnU"" [NgM WW\&"ތYLexJ \u)7vufG<`r÷YKeXZv( XuxYՀ~l DV mXNj6uGQXXY\sǡreQ*X _s.n=P2K:9joˏq< pDJDΐ6uAx=YNoUvQr9)9|uG.Lda9kF1oI;ו՛gs? 8ۃQ"Ő鑪jFWXGps\)VCZ&Յ.cKx*sxa\:gMRA.Kx _$HGv# sW9e[=yIEy(8;>V8c +?7J'8P !nL-O)MW%e؜VqiSi7U#15Ĥ1rr2:N-+*\\6p O($ .$n )g={JRJ"^$#xvl 0@Y%7ŒT;uFiۻ2.ݥčޛ)f&wyˁػQ}zlݜ6a3 gj7\lF YZ,.a"DW`Ohp.wU6p@Ps,UJ#vOiüp\9`(Q= 94%=XbnȥZ0HiHݏTH1jWaG^^YB8gQ&fpjMy~@&w~,rP|whwP*7 x\iM">{22ձppuZ+ހE7E(_Bc\nM<8cz|5娽=**N Q0#{4vhni;U|c|W3qBSGR@~PG!/[B<.'FժVmFEBT)]ӢRdDʦ>E*M3[R臢2uL&,F<M$4<3xʦ`ByNJbC,hlPpiVe>,gƫ o[6/YbY>cMls(@;=Q-CCM4\+;ٚlKlY 7 ɦA^VT@^na˚8Nl8oe_=A_tjϝ^"1ME q)+m5SG@Y Me_\vh|0TI^[)+C=34-s=ށӺ` .]{ r_vd'&}Z-l"&\ˆKv3.`nNwߐen " C󖿕;I)oQ}(>]URk>u{s+Yi%IAgaLV4g (Pm!iZ?LPq v4`z(E ٍ7jy*ޟ6ȕhrA2I|Up0L}-d@]g7/|6Eorʎo%$V| d8'¬;-)3XR. ^)*r.yRX3^ N  AB(%%nXgr 0rɁk04(`4;}}3%PXe&_`xUq5Wُ7 zxYbYXEOp"hʽ ci5n jZIQ$@_1|TbEPU=`mKxU;,۸ Y]l*6'X 9JS\͆ƊK(*ק&uϳ-}hTa7U 4V3LnI>?Y̵hAIJ+U`gK+[7,D $P79;2{sT0a;HHȥj([HGB+*\-hOVL@3Jؚ8qT ¤疂*]!uT ?U|t4'pIwv 6C u0%R2R3[wJVg\hM|Yç\ikdcUD7CB{ص̱g\@NipSE;HefD c n8Jg#2>m @6{٩wVKnNe΂~m&lNfaHɶνrڰ [QbDa# )' eQkqF>,5|$[j) &ʲwP1E Bͱ)ǡ@8y9TtK"9.1r&7žFVIX srBRU?\=sd'%_x>ǶڮWLC!,RmCxpɊ( \5 f :Ȟ87Y˲}DV^tjf>=Ma,sT($35*c/,r<@XphKQe)_T =?IV$6צQY`wG{w~ wGŏ<+ڐ ipT͒أu"2geS+$)94G1BUxԮtcaz]'i8u̵^[e43 4 *U!^n2[M~* N[)-Η5=W>pzvSXZ+js( >% G`1H6᪖R*6%ձXE^Dŧ2 f e:Ͷ]96Ʈ6sk@{Qdӊ颓b;9˔\  tn{c*@'smaKm p\.YU]ԴϠtfZH S55v8 *Tcv 1G%uU ;[rR[x.%bΦcu){лR(yi9uwΧ5@Hwسc04 ʲ.Ud*읖%L-N  ?^X 68؍71|%LLt,nUۻ|+)rFS>5JX26ohs6#;ƪ_Jh1*ޠzS5,["v;f a{)eͿή|UMqbE}J틓Oj"'`WDFz8>|FnA!fZX7`֑g)6RI5j|^< ;yAc3~w[ʚ^I PT a9Sc3~=]v׮J>syk7E)e/WR Gt@< Eγ;븀Sg[bKhjP;]o 8~Zr^]{Nf`ƚB4sTN_.BF(9mޢ1dL 2&&'-ev՚y~&~M"2߫ZA-vL}QٝoCrكaȨ s[p]1W6창8*&pB^Fx<` 1C.'?;y(.ĸҧNc7˻&*Ys5MzL@Uceܿ8پ3a]KYlGbަ@4cYdHAvXu<"<,nJ)vQ=op2W 43-pN:! 1$[` >Igayn2[Bqq j2;qJs< .k;)JKdY! eRǀBNߤE] /gdIX$-xc275u8^{ZێQdaEai s9q&4Q5IÃUsjNTHcW 0 ?;;G{_ òJ[00Q&[R r0K㪊r ۹\(;t6xtcla<0V ';X% 9z*xRXZ6b((+3jU~6\؋Me8_`x7CErQwA> Lxcc)^:fivGpd`"RT~rl)m.<@=p TVѭ5q_"]{S;ozly<<\l5eO2fKs2j6>^f WC-a'fo]]n e&CXkiw5u[!S~kKQ--+2 K_msS1_/'b\L89<s%@8łpÖj.+;݉v/ G YmPxUPY u4+B2x7x 7)Hv7 T&PdDžT(ȼeRH/!p;dcر.I(P$62>eM8YK' xu"|_D;O$ՠ幈dTw{4wmH2}`vǚTz~jj2.4cq-1VL&0s` q~ fJY y=:N۬~KP_rƄj\&KԮA9ۉMcb^5Y}lW.so~s7lTv,Hv<[Dh=^cR[Y ĕ=!į*4!Y*& :$p 峄 3(3}Etorȍú6&\0U"6\*7,Ov!n+ҝėv?W'v:U)qhӸD /mb8k+5sWfn&ɘ5e!7` e,eS?S|x)29MS+f,2 3*>*pl@OHj*Hg_^sbӂ}mKC1{s VO"(ӱx&(+fk|@CғGC`C8rƚaX{ Nw [Ped'$M"5^I-:.[R4 ~>f31樵FR!RYtF}\Ck8:&q㉖&l:#3g|Z,hӺ"Ѧ#oqُYENc"&, TkމE[ic {n9H͠\C:g$oq|Rt9:d:T IkK̖d:(RQpWs4B\` } YgQtuoǩ͜jT9$owgCokV ƖQW~dY7ǤBL18MzĶc5.Y@w`#;aFd/PDGl!I|< 8!?'mqS9,47 n١S椈Q=X>1,Q{ls1uX%dQ*b;GG2\,Ӟ³[6*[s4~+߹`u$Aa=grwP xe G~Zy51Sep,9.&!yBlȁ5 =xKzm]n9w 86ŰND;uvWi9q(9kss8FU\/ z ɇ v7ח8Ku2O~kE[YE5c:ձ_ V*{wΩ\ ܯ}庇,Y.h\ úZ- '4',RTYȹ>_  7PA2bS\qN9<6޷{leRږ㲀Wa4JP`-xPbWV4f9Jz\b@᭪)xhUK*$Ur&^vA{ݰVɴ.7 nx:q!R1=#_ҶH& -#:zO5 x Jl886_r$AY}Jxơ*yn6Jy6WՐ՞> >,aT;2XSQB ̗؝A.-`8?8`LTYVl=ۧ*(,W$j8lb29 fPB|s*mB$dC%@j<`ǥcV3Xģ>Q ]LYR5ͭOlĴ Zӑ%$hڜ P:wSlAX'c]Ak*K#rrR~]XfnZcB$?DɃc\d'P.|x2;/z*\rfGwբf'X5Em^(8c51%V% 6>b|->lwQ:]$Gx*T05Ls9.O͹٤sP}#@lgԜNه=(g{,ldhdm XJ 9+5\,%Ηv1D+KhUe~4  :Gm($(}*5>$' s]jYc#{a98_gLY 6j|Rpa6I]R4T^f#O؋t-;SDupUAiD@:9N: Ȯ)oE N|LTLڪފWЅrmK*pr]N`ɞCWA Fnıo]A `1m0""-Zi{2<,sS1[pd99(zEq8-1l? n&›e}Ŋ#gYh Ͷ X1YW]˼?&Q;RcBK"f?+8cҰx vDn:/bv7 Do[1 u[\9fN 楺Rh[PVBs$S|@ ՆBe.mLv'PUa&`r=G`dʹgd#sZ0>pְH;>Omу; ҞE6vJ<4n?Rc)LFgmHt$wEƁP:} q[7 OW&CnP lΌ@VӃ˨ٔ eoH^YU{ư? m\ bD4@ i1NǏ\k%Jc8ز' scRfJ2A`K'J8A`WqNs}lc=k]Rݜ>#0ASuO[wF6ݘcOWq C]WNRPr'7'w=.qg$yePEJ L8ǖcXB)/b]pI`ܷYzR$s:AjssPo-gMSҗyn2q9a$+CGd#$i$6m88%qwC.ڨSHHy =^ǵu)7&.~甊N⯎HBЌUUn1't_\\}V~dvWրB{EESoC3dxKMr-q aAgeB*dubf|6ש[z)4> gT;M I-Ǟ,&h"<ѭ+aȽ]~ROm\[|Nk rQD oKqd('ʢ> m䒧Xu1yԜ݃C(hLٜyԺܚ3X5q`}A? i¥iPiL,r{ 8:c|aw% 8f;8@Ұt&+W&w٢]H%'?.r&9s5-؉.VPUjKG+l28Q[<Ǐ3 @=5=%/Qb',.產_"q=3{4-ז1 ?Ȫ-ӆ`l~8aTőaЦӵN.J0:[R$_ba6e-"%C WX`KVc#KD^٨hvGS$YM!+9q [8AO%涷{Mۂv ge>G9)$ rK#PYZ, %f_"vm$v`rM樦.BnuS9հ{:'|9-%rCnPsqJq?6ep.N/`Zs/C@gN: |ici-k D{1H`baAZ!Jepm>cUi}JqAh$sٔ%/ֲ#=NY% ੝l=I+KvᏈ휂8 M픃v`ҭ`,d] ^ $[=4}y*nN{ĄG/K%!H8R opy, !q?|\/&eFv>LP뮜 ֐GqJEIh^&$U3ƵrYfdéHcQ~=1b]x88*qu#݊YP2e=]D0Jf4o*INul΋ڔ䵰q-F !6.yp:0hחgߍiW}ہbRTEh)G?٦$@i.io WCb<0~|j|bp_^n=s=}/ ܻ 3;8]]X\ #f Vik7hB&1@;X(v,SO^;,v۟YB̗ ǪA%Vs+}G_FUVIî]ں S]0C.qfY83]ZdN^FNb,eRFG7sYV9nKn Lkk?$("B(ġځH[8O'oYpxlD(43J$XLClJ O<f1l;ր#k%8bNR*<Ț3N?/ |$XZ+zZ4%(DQw ѩ !|w sw4;`\ex,cMvq^M , r[zo]ٻu8N: K6#q~M.hg+\Hϖ2}&p}%*u;Hވ&ڮ!-߄~[uw$ Sp G# ?Vh29@Vsdc|22(% E}ǵG&k0^}3[9)LS'MGXm<+!iiIBG(FA7;\4B2m|OibǬG9@^;\> ލD[YSņNJJ㒗{GvVdΊk*M9l ͏u~biYrnIµaRby I|_8xeLd5h\k>O+ p~ yA*R fl):[O$7W2M0W2Scr(Vg_mK\^@ŀˆ~ʳ L7nXםEt-c,`Q+v^'ӂ¤Gnm#K*]JcXeANخ֫Z0Am{j_8@MC'q,Jjx8AL29x9L9pPGt;ɒPaA4䗜Yӎ= 4aM)huXS촮 N[deJ1-'Y=)Sւum3O ɎY*1!2m6G"12a1vH;c;1;?^mll63xV.loEg_=:798:l\n'( =-u?W r*+?؂N&aX!ea^"gs/)dϙzEw_ߜPAKnp+ |a5xhB\sBkReS#ko`->HCDY1 u)=;R,p(q 7QAi6Dtw;&[EmS!`,)ơn9,Je3[4[śuw\jcC&;zlNeq23=j"ۜz2x n㢪lܼM!`5SpjˏTbW`b6J҈v^x6,fΛkoʊ Q92V$= 3jX"r`\ns륈tAĴxgkKUUYgω1CfO)QdsAASSN , | 7 ΡZD(Zp oISU$D*`9/vJ_YO%".[:R3KwBdTxp T؅cxSѶ n¥ $X#Dxeyƪ!9e]톎v،mtSj˿9Z!EǤ4`Vſ;PRگG۱+swV Ci,O{9^KS>/O"եm/GRZ;+NuE4M?|wO)M#L<NUVJt &!ǎy#5mUA\bU0/,N0w:֓+pv:Y;iDp V}ʪYsG IhgoXGa@)m f^ǐ P:G3N(Նb6\ʼntF/%ypͶm\LԲ{}*xhٮ])dI['Dg1ef&azcOݱ]kew9|g}꫌9?cUUyQ*ˆu4N盫ܬUc& Ii e7x86@lHXjUQ P=SkVdz!XD#TLHM&\f $*PQH6/.q#tUFDLcȵK>-Xj e⯦^St|L7cЂѹrV٫D0|J&͔sQjU6ۡrZTeߕ5¡I^5,Rۙe,}k.A;l]V6pjJ5c7| pm%/i_h͹a7p(&c'ZVe,U@ ~9 Y"HVSJ?t%RFfiv;XTҮTr2bx &%`c%itK-x6 Z.9ltR'K7ʜU=L_\߻+ӷت9Cl32:WliìgG9s(w`Ԝ5b]9d;8Qe=\BD1DҒ(t2KsrT;~*vX'c:zP \ <7U.\(v/5ġ 6tp0m6L~mʜ椂B #UɈB&:V$-;^bl[N,&Mi<<WU*Iڈ i {1(x4bټ1XF3u-bG,ϴ XY_~-`ZK۔j+fX8nXH؊|f՗ -*y,Wg]IC+,D*c=2i+Ւ1?#FD5{I)H(nRXw}8Z,iÊޜ$N7#$5[ ԬJ)qvj-<b4&8%&LtK6vYkg,^n[h,~ vTI3h ~gǩ'q8A`ӂsR텼"P7Fzqvˆy6P(%i(7H#W{hyIe7--IƖ!(uHi, @ܱc5TnV [Z#K] {D.Ć@ nCZC򍣻²efWP-VFX*{=㪈*vSӪxΓS8z%OVOU`琟Bj[RM*{7|ޣr),J25h >ruzT(njENݛ8Ey-̬L,$Bw wDžɨR&?:h7nS!j8J.7cPNˮ8I{}Z* ke\p>p3fi%]*;,uND6q՟~M %I)K8U*@4.uqxsGCr"O)WP֭-Nv?99Ls&{? IIJն "Elҭԕ8ň,.x؊蟻;퓾ثg*7vRNJ9es<=llφC5k*44 -S@e 鳭Xv_(qz`l͕/ݺvX}%\uyK {Y09WdͰب'nu FnNeEL-X3{Ul VCtqse ́ut{!Jq vgԛ]v?͐kU5420L5u7vk&9O: />3q8o%_ϡF#@%\ڦ?y4?CZyUCAU&=D0fI.ſ yPk 0xp[R(] z6C9fS؁ HؤoZE#>j|(gƞc [6" IMP!t`>7, . 4Uw>8Hz:4B,V ]|jS#J]N9Mɐ2ܖgjt)\=1dO?‘s;_A܇Z/%F>q6]TE/P.4x  J&?"|8o2:LGptT5z>3⻐UL'CYӪ<$D,Iqxv<,O$ h<4Rb:dքJdEuش'=~ͫ,졶+#Ri<@ФBhڞ\`aV)ѕV]d<" I.+I_O,uCa5xK3Q PV<~?yVg65'U@8xnmҼTے}l1*$^†on)<{[cDTIz= Yf=58}ѝ:  5-;&qlS&#>vFʘpAMH `ĆW7-&1.`.; z䋊ƑC(caVw?G OnvAOl;dH9BR9uݜ%|Xx<4SJdJil6gV+Zl1U+Ūlۂ:T㮐[mI()5vHk/ي.7܆䪾_ezv#c<,?RWSRĥ%B!6{@˴42TC&'4}>ˇs]ET@AĔYGH2902BpFyXl!7YʋΒӤZtrje8@1sR{Dx |ԙ[8|A:7\٥"[q8Ijzb&St_ gD6[q+}{lT3lb?-it?Zi.M/J"0ͻ}^ymo~:='Y/\mL:pğufJW]7"dzFsR+/%{ ^֜Oaexh,V7{kvxb;y8F@H҂3KoDvl@66x 83[tx]  RRг;iŢXdskr4v 5V8}Г R3T|MU9ER6|Jǣ0+4vg.FIC \bD;8{3h}K.*cuvRK.H&H j>@|OEuN6V pꍔ$B)DI1bLsE54#rԱc9DrKόsvA8/5 Xl|r|NdF^umz~fZVv59Ki#Zlm*1]3˞G[% 76Y]r-ç4NaJn'Q+mQ?)D' !cYBZSg.܏E+%q~\)t.I#{mӧ^\"`ɻDX|܅ ͊٩l†sqRmXtޢC>c_o3f/bݦw*;~qG'ih%B?wC~1?ҠZZ[CI==Mg_A HFRx՝b،4}J%0Wt@Nȇ6"mb[5|! UJ fـ.֤L蒁qۄ&[t6G.ʇf[M`!I0` +nGdDH ۔.){hP*p:쫽 %xuR^٤l%^Y 5슅]ܢ3$y:ZHe|1F{r`u45mD.5{h\LdmݖXk!*ܸzbw-j[ʸSlǕ%uo54MPхۖD$ ߍiAJ[e'2xH C5ros* erf \X +=FHnnx>Ks۔#!VGx8?])[B ?Xm}UmIO,yK [%3[\gJII4lèƟ V-lM3|!qTHޡnBaj!~^8hq1I b*$Մ,1H!zrQ$>cNSD"÷ &-㊥G79aA`n!R5e5C|ߡlUViR5ɻW$fq1U0$TJz~7PEpzn2ê+0? JPȮi6AY.>ڵP%v :a*I0\w V+өa~.kcmtlCWpNl_Hm {Q8w}{N@4cK45X_|Q_L%VQݦx;ih1N=`31'RmΪ]ҜO!Ve?cp PX"Bcq%Bs$Hk22\Tz[6]'s `,V/cn~sߞsr)NpOr0Y⍛%){"{IΘ;nMFլ˵R2//v?;??2e]vw-+{jpற9-=լ$r ՘? eg٪bE`>ӹ0/՜-]`)@BS9-[ G!Ijw*Cօ0S)tF1R4#vf-+%حg58~qr+۪͛u  ll̆hFC(ЕǦ6SCj"@jCHDv{uyb3VO I.\PP*"hYҧlct~uyؚ]v}ي*IcjY {ZN2@Ӧ#nW/{"-L#;z aYΜKاTNщ9({ϑQ|AŃ݋g H$lAԈŝK}G 8E v_N CVڅ{&k+WНWڙm<L]ۭ:bLjOc4yG86sRT|,b k.u4~y͖6#=X)jܩJdE$ƹЌQNlEh޶/MN₉/ :R:*f]J`Ή&d`Ϸ{O- o}^ > C&'-gqjWB(D8*U1jXkUAuM HXzۺȒ׉&%+ۍfղN#NfX63mHtEV0C(CZqYJ/vJEhUUXfQW;}Ӣ.G!^AW&((@\c'B9R/ZtN@xv)Feht*v-/s- "{Lvk$Q#Z.؏knٓ=QZSv(Mʃ2,In8S1l;l;-vVtjja m w;|eu!>}uhb}&K滛[ 鞛B=wc«m0gku3:z;5(wyf:ϱq-v7=$ \z{q ,);aA( LQf I\mW=ǐv!yqe ^"-q:lcdu4^rKqdwpwlϪ!̜nz0ќpY8C,[ˇ27Q,񝇉p Y)8#$FSZutEVlf}eGp*/7n\ڡ,ĸ!CbSzX hH7 gTNZy?`B,il)K$$v1sX8#>n0nS K,Vy;t547ă˯\erliD 6;?2;]QpJqs"/9+uj jd-)P3H)`tp%(C iнbk;* IdCN9vgD#>~0;K.5Rv8x괇a$ǵ$ t,Ijx-Q7ɭF4,hX~CG̼W0>; 2 ؈!*;+ A:,xuYK6C¯HqgݹJAwؕHϘgA4(O$L{CsnHuEYm<[ycݍAYl3nܧ)) QU좌˙[怭LXĕj*b?/Uˋ^-OL#lXh^_KTd / v؞&T;_;*kIlm)HvKr"N׸{xUJ|bIX̩]S2YG u87NOAfl O⠩޲C@├}MtL60Xy7U0R`S6;[m@VyF\bɳq=WUx<͵zSs]C&nGxüǩ`8GP.6$x}%5 Ґ5il'y*QB8ʄQ]Kͼ59mړk7^`*g*Qہc~cǕZ!W˝xnVٺ y4n)q!ʸ~d$yo3^@@OɵvuaO|vh83lFIS6&lrmMsTqvP`@j ;+M[cbXG*6nHy8q[C ,ƺX8Kls.,50!~¥>A |lw;|dl]&*Le˖PwRT+Ŵ 2&S+e6\V-Ȋ\lu؏v역ʵ83Xv&)G-!NhHpsC4E:NzϧS.xlkYNJDї V^0ݪ.'$dƻu&خ5\5xt+[VACDLNuzubO;xCMwDgI㾷tVkI8y:3ʣbi#a2o9Ci^ɜSإnhgѰBݽM1L.w9Js=owųN){(*g=΃ژ8;+'mUS)v9j&4(}ٮp-$,d q'b^2" );/]|}0~e@#8^M7ìݍcʼnjoum bd@I\ƊuhBgn.36K^IdYdJQ (_*lYCo]1oz3)@{`xwEN'r/<*]?. DBWqH!*aHamGqOJ ͭ*mVtosFQĶ\EMx)@{z|Y]6|]4W!IG\"ɪTՌϡbn"-8t0~ƪʒ A!_/rpگ"Jvͱ$.8ϔɲḚGTVK%-밣i>F2IǪL*<wqWvN+F'|bBuC{ D&'L& Jv{X7V:αՓfA A>j9s`CE )T!b&}X:d4krp슐6dó8mU_dS ȟS$C!WL=?=iYJ5L)oQ>ZZ,MI|+gHY<@ef9:ݽe̔6pajopcVswݏ%2ԶE2oMB5ZG%m,^H.9K"PdpMH-I &>֭a,63ؐ*r̪Ɂ(xdrK -_>S4HY-PL}x̉&{Γk*S*5,+baw g(ĭrO dzl%"b t^xPVfug$MTm7l__{߼۶_=￞7yW_O}|Wo|/?yן~xo^E߼Uh/xu}淟^[͛oz߽7!_~>|ͧ?իݻW|||moW^Koë?ݛq] o_q_x~o{õ߾?sU?w?? Oo>_|{Owo:ݛW/^>w|o?}W~77օ7}*z_^p>="/'_o?(ի_}߿z{xG_Ռ57oVzoY_=_l׿\˻/_ǯY~_ۯ|^|xO~D/z[??^m+ɇO_]W/]|_Q|>7߽|swo%u_{w_~^O/?a 3nݛ#9r/osʰ? w7_w>~3or믿_Kɝ Fp7O7/ŻOś2ÿ{/_lSL3'f %촔?V;)ϝgO g$# I|?|?=?տz?^~MG/?ѭ/7/o?ayp՗o^6y߾o?Ϣb~^f7/p` ͷ>wo^nto^ݧ/oqk߿+.ou?}w߈a5/ww_޽$e -(/./ +wvΗW[_^qϋ%+|yEO/}yW\k/{yŵ+?8^^q-+_^q-k/k__^q-_^^q-p-˫̇3W~_]~mՍ֋[7?2 &/?Uͯ}0~xǿwo=J_" +?uw~'SO՗,w_?~lW| D.+0||^/|j^/*o>q=wT*VE ?ݝQ K #$|k. _W_xم/j?1zG8)c0"_k?~Ěy|mU9Si  R#dLjQTb${z.?tn(=dcw ]6v3)-t T}ߓrۢ;8up(AVζ2W(Xs'S.j;7}oR,뾧Moq9ʯۥX,tiH#k ~e&6k*: ]<\&&xٳc~N;NJ^-O#43}?D{$9`JwͲ;T3,⢎(jM mdGzgj(}W%{nSP0TM9%`lE)|d_͙k'`>bv>{[ SO1|Ҩc_̙A2(JKV|Ji~OV ]6NFނ4:&lcQɴ9^R9i~_@JN` j72*䉈6)g$8F^s={6e K(H?ciGnݐ9'1M2{hcci_auv{Tk.=M ElkTwxȪs9q=*aeZƾkigcE"hQ0S@tpHi܎-;jZrvBvf)crY3~Q*IP7-䃽_1kd9Ru#/|"Mr7,Y2Ϝ : r'83A,[fn^6h)"hr(bh)oPUig+.ngZdTB&651ݫvgKۺ!y=#`> ⒯`sT'-5Hi&7׈ZsH[ISrP>1b5%(=vد,ɖϐ辀H%k^S`5Y;#=,vlǙdhF>|8|H>  dSW`*{۬2҃f'QV,G*nnv-Gm(p.$8wTjvv Lnd܎˓Vo{;a.Vfpw/tdMtMF9XcS/Vf_,Lqc-;6I;A;2s<Q8/,YN?Nix!C5+%ǁuB)q\ׅ&x$ z->_heݸ|AhO(B Xu"_MX/#%v#g]TAY7 S |9a㷵;j=*rٯuFГVO&"nW<1KԎmO[R=΅tz ?R&ض^ yOGP$#dD~7OeH[SQP@Me34qJ!׃ D~$6la[*΢Q %3g wqt}n^b TOsPwB:O-]"ݰ\VdVo%/1MPCq6qKrQN>B}M>iS`b̎'̵ehLQz$ <w# X^-S*6&rG 8lP,X4Wr{ dbpqMkԗY|3;~؇頺A\le1<2/-ryF* ~CbR㈫q~}c|\ψ`DP @}d>1 ԙ'ه;\NyQ@C,;} U/⒃F {Wf8(=Lsթ-EqJ?z5\c87fѤ4 Rc;Uo)I$uBܺ:u7u镴hmf"v_h $;%S%6 I3mkR貂^;;oÁUTpkMY'3USrCo2>!dq׵Vpإfa*f!cDE.&=ٜlʁG~dqRI]LusIYmc04ao 63Ѿ&CߧQĨJzfD(>O>Gќ`fKQ8Vp.e8`R 09gΊf6R}k;l<&Ahԥ.?9ND `_ǵil`SEwb!0“Ā:"gzZvƥC=QI ,`;=d:Al\ZVZPQ TfsEK IUc[:aS3(9{vX.;*,Z%*3Fj 9*3QDc#r'F@)#ldX!isVs S-K;(CӳJ8BU*Y0to76HAs^o'ݚ$V޻sMQ+±QLB.Y;7>WGC{Tޞ S<PaJNi,.R%2.IlUc.]O|FX"2jSǵz:(v|tP[:yKN;\?"=ET>i=Ib9l&fEicy_TFH𧷴ӹDLI:ŭDR*c Jvx0@r~$?37s %'+>eU^a,?ik.*ǼÝ4Y,{c w d0(m(N,%6b2U7-UJ(JSĭ\et;+k!׸sM/C5,}ݺ)Gm2V$=깙d fI.Չ0tk1G%*aE(2)Xo踳 ['BC;$b?,`x4#fCryn벨:*a8KNx |Z8Ԗ6R¬<`qB&C6jN.&<:3`@MMZMLED4ĝYƯ*5LA .S0z o8ճzRQb۸4L8 ?ڡZ<;_EJYj7J:RP-eYEk<AۖvRKvNгqLʛ=&Ӕɫ1PsLP.SCPZu`KZ,TdwIhgxDq欸IҘNASR$[cMxi.Y汅*䐞K2ʃlnGq+)d$-Ҩ#YD QN"T扳]"U{`FKP$ky?lc,g,r`3RHE08PAJͰF`b*Xdݮ!D<|Vq͋(dH]fM< ]6:<ʴkzH5WSwwBpxJXM ?~ڿoCN:v4>V>]|wZ9 ~@v7<`n{KOp8R]mIY& {b(ֆUCdp2p@abb57vY=6 <۬mezcg*sUrS$ɴwEN6"zҎ >\/AYJ;mHMm^4DU͌{l%-ƀ9H˓FL9ru)Hܡ=ξ^|wh؈6gIPHr*u쬲>66!سDh lZe"7f*r\1ژDbG)8qsf7V>BU KGM{7TV*jԅf8o*j&0z0UnXYd}^q*?UQN>@mh!>6<%!]7'FT Qq +#YR2"p,s+dUVZ^m=~UNql5;\*+c5Mz|eJ2kԭciC9ܗHV%Z*F;IKnq~D]ڥ#}CwGUa#ICvAև%CD@ [ji3Ӷ p1LQaMRQG>QlnJplj)r9*S1>K5 j'Gnkζ5acf<7TǼ&yv%\,C.(x]&ebQTjY`Ia.bŔ2V"9y 4VLk췎Yy qŽ妤6UM`[,-,[ Z>kX`ƍQHvG˓So26͸^Ee(0R)E;ftXo)Kk@KUA>h90팻Jo;†^ַSbFZʪZ~Mz%8qbtr\'T75[L`(!th[5+dXpwMzfPekFuR궦Z2jI`.D%7 vN<7n;jHfƻAi)M~v+a ,u`n+ϑ>@3E]ѵ2&SuEw(Pބϭ"B|sJA8aq^]N 9AUcZ;$'!p?`˭iJif"HT[򵷪-*'u3ىsݕٕUnߟ*VS;4,%ӜRBsF$G6B}`J|Qp $%e~,yZmp467ϫvQfQwtJ2 )ע(C8Z4hY`F}fN(.x6—•p ( V¸+??scB e;wudGۢnoJz'[r֔o%9HPW/@NL86 Gclr^쒓|(O \2ʇiώ ŘEYG#KFc@s:0ri'}ȫ~|6 c2N,O];{8fqI Jk\FfYl#/-9A@tĘ[E e p5{,=Tq)I.8i.%xg͠"~f\6#TppZujpq<Ęa3XyuK%_m:!MS% Y Қ:(lj,.pZ7:@Mx|HmP<mYkrʫc˒5UI@r}%bYzǩJtb3*φK6:` j<аUm#/; 59(XB)iMG]Te2~xkU:?pXrGX41f^g7~?İdoaK|p(pKr9=Jr`Kj&^^. x\EY68ގ|iZ[.SO5 +bAXgj9)m}Xjkf3P"њM{NIx;?0kj΀RK_C7BN߭饶eCgƋCF5ƙBKvࡧ?[lU FPɅ\%Q5L\؜n_Z}d5>Sc>>Idb3mP ag[`V+}nD;F {^SX$/ xn9ӎV#LBiU݂GV$Mơ< +u+K\֥uO^/6:gr<ޮXLljp+ޘ[v X7wS61ýN/U(WOg\zaΊJ9y7{fp.U-l"zŚ&UCyfNgD0ܲCs?x\#@H+ṹ$52 Yϱpraj[Fk]vBnki5yp58ZK#ZF CuK5/Kl2( 2 jł@<ڽ\3c σ)ʥU4Yj.7FΚСFe(|DFG]b^9(nJSM) ,#b(r Bl-4glƾPͩUjfcRu$:4ÊpUqdrnD6#-w9w5wU\s ~&zR ؃'wGwt1TL Ș_l;KƢ`J%>1_F$R)v %Dy Xq %;؛ ^4s1zZYCqjۦty.6 a1vpkʊC]6,2 Ԭ Em\3F ʕ^lk(\-T)x q4U[ũoj(#K܀Ȗ:i~S.y'~鎟2N S7;Z] C5e (x X #l(pZ`Z0 +P"da \Q)Z0,5z(H*݄ e/Ne,S.`+x%رK-[Z*8k n'ܥBZ U28ӆgO%Ռ#1r&8,uxy_)H.zR`[ Y9ipD~}{$Zs ĦX+)<G*JhWV:V.ֹ,B;n(rrtTV8A1r0= ꩙:;t'1OhII̻%n nv<*̹ ).8`;)ܴ\X=\ Gy4.QJ_'4t2llFé`o<;K9+IE =crR㣲[W-6T!VB%Tx8yJ)W.aFiԙ\~N {b\N 0ő!0i®݃\u`XU5{վ9iw=H]^!\ݦͰ10;@Z}p%pҤjIJqcvvv(x- /65$ۓqBĬbʇߋ{6b8*"1 sA CirR'NbjC}>s4#҅2ݦ񼘭Von6MʏhiIMIp4peMFiD JƣE>ZkVnp>p%S;%(>^uhXIJ.Q8zX g*i= hʓނXTaĖ$:@تF}ceZP43\ ,Mp̻M^!n%E.GЍdp0tݱw7WhK'P $8ɇ#+Vz/-aeX CBCL֐3C ͆< 8٥c?=enӤL_vƙ߳ޓ,?!ks d?țK=ڶ- fVڦNTs#Oqs&-ݰ(G$IxoO)n{°`^qVnpʢyRǹz״9d)]KR%=f#FV $:!9J$5{BWAvZI9kUc(#/k=f:*I 'isWݍqȍ`oљ Ls a૫0}m4-ƶL؟4Rh~TqÀ tO UO%l-N8 dգe5v*01Z> yO#D.ӄ v޻4[rdWzͺ,{x{p!Qj>ć%Y$:U]YJf2Ĺy9qگ𩬡BJȮq>R! [- 0L-P"qN.:ڹu`tPvJÕ0tepK&0}Ld|<w.`:Ӂ]&o,btlДȢ:a1¹ؙ5w jGxT v+b;bL?$=@K%[n١h2:PLsG @T1R²6&{mErAvD6A\;vFqqe"Ãqk%ޙj׭C^sQ0ܵD7eseه UdsV3&ۯ0@gf&<>\kX?a7%䗯b7,MMt! \vl8 ~\ ]̛6\,0,u+C qpDfi\K \pn@8o"jK 8m8n/] |c57Ek4v/3mJf/vw>`wu6S2Om*/'A >sʀ1#N 7dmҶ!.Wk𜀐|l7e;41B-uh2m$qRE!:b[-# S+,aQj7˖.-jyW"/ G9eEEO@Ez͖,|Gk(#uÏ&Tf\eH6ؐpf9Xd\sK(dEC2MQiSVt&"\pmlK#< CMFԝ%$(4Z2Q™RXUՑ4f-8, VQe#@ g>>g`GFk%BE6vri]W\&<ތ)Iپ.򽈂,N%;żlw7X>UuG9&,\jE`lmyh 0v UEbUx$γ< !V[m`! g!&Ȋm\0'e\N6,nl/A\9m26+,&pycShZȻ~onvS-ȹoy9vYY2{</W Ͳ;XZJ2Xp˽[rqRN5DkbF@Mr}LIEEy±q*v#WP&z!."Xv>s]e#0S&1;L RxEEEMXe27MΡn_;`htlև ߉f,/^>E֠8/ /YM%+<~h 494C068a@87. o@<7&vX&=qmޢ70;n7qmj:f羈CذLO'.+* l` 8p IW)NrFxz-jY/+Z]s&W '>8mqx-[(^fs #AgO9vݎqC-Sk6z usUS .`up_)cbuXN~W 8Vg,W();q:rS !rӼ.W *ʪrPjU,\jd, Ti\ :P }B'81 )hйK^~lUCLdz.b.aؓ!e%,r+@.!WS:'yNiP_WL-}J$ϦYZ:l4M &] N4 ƗNa~gڼbŠ;ny,'1H)n?78%8Пe }5Ǻs¥ױR֧5eP\gJׇߴLnj΃Y*p1q.wZMDT'H_ocCs!8wiUeʮK:ΝqTJk0ե+eP βҩ`υg=~3Zu4`~ f (w-pA(sfO¶K56(p3Ɗ7 `Su S=`^qQz.]O'!e+#W9|AKe!K3)W^F-~d^NՔ˸m00+oz*}q5)6eZl %Vk^)(쩌e&WO\$U=$]vGY)]Ԯ0_&U"a&!6R,],1w#uV ͆jN쨩t_-2vܶ`ͨu;)9tC!cd5 tL55 };8v.Yy;Φ,1Lha M~t 0[ ږ\U]}'Y4ߋSD`UI+P: &IR: TᅫI!c>vdoArHM 2Ni5.Kq\7\ K`.9WOފ.MlJǸ8 |2hwX,|mjZECoDvWA֨Eueo1Smnq//JmM(2,% 62;1r*~pcvQ;(oݐCRPxD-Egk=#bg1W&l;%s?5qVGW,.z]!E2M/, rQkUlHKF ~Ki+;; M au bGO $_ 3(LTjM]prt*[TVv G.;YN$><^FZ?l\}]eNQ[[,_vQHV T2c&Odb] 8ѹY0M{$(Dj |6އ}6Z_scYWȱkIMO]9ɸ73]~L3Z]ie-asKKA~y]`tJP/SzDl!87-,VHxZ8`XRO; l$RW|7{y1.RNi`?*ZSn*UPzkRT`^"cޮ28D$A).\n>-ۣVD9U&`\(cG#gŻr}=D¶fKSQ&L(orp ħXTn}JNqW%}E"­M6 %tTjQٟ%p:ڠf8|-ʤ)~Pg Mͪ}"l` bQ`k&$;G Jc)3(˯Aqѥ6ZtI oek}#,d!0z{yk *y&챩6y})W8a?9Ǫ =ZCW4\R_bb1.1P!MM),kwL$꩙֚)WUX5"g4wk@b8ېʼn G.X_lC21x5"HTݍ9\k1#E,>y8%K):3wXKG~tXΡ,Dx]R%*`60߶N(/ET\ypWf%bs| Epײ։i+jRy -qVC#$Hˉl=Rh7P ʒENV`7P7ȔTj擣t9qlW`#8uD73'p&K$P&GME*+cV@aC-pTm f@OA fKo(xkgG"]DumDG2 l"*m|9P[][Z-4;=ɿTz&&[Śj S& 6[,c%]hJx/ݽkOV ,5$uQȷr[+O@alߝ5%&t,z3Buv82u$*狛/W{cT>/5PXx=E^ KqJ&OZ%.VQ^{ (Km+$طr u{z;:SzJIh.g$ٗA:Ct ))g0*&}eBN*{ wZ]=oh_JT lj@6-b9=r:]hA,/a3f 㓉Z  #h?+mj&ds21թ|)VPf%m/.#_0춮d/IkH%b"F)m)2e!܇3Bh|,F63 ǹ;!jEΘs9/^5s(5;*Z̿* .[!ʢkZX5/{SJEa@Aƥ[p\/)َhKboٵL,XhB:4/ɅJX(&2>vyI%|V$CaWXEإ}SAO錱.1;UsN:eWUJxZgo}b\LBP(V]Nvrr7~Ma @d[<lDUN6Ry㻬;6zeb/ٮǩ2ɑa1Q!83 XA!".[n/a,p/qzM@j[ee\% D Xh`ƫ-Ym-3d#ҍr@0$;w$_«X"'+W$\`ɹ6B6%1Yj/},rc<ݎuZk >bH5ut+ ϖPeʚy XTN;B(Z>1j) IYGlTģě #%gkBq۴R^F>Lh%6, Ki)D d ue=&FB,Uqx;W0iQAe.Tr%PN Db wٶieBXҽH]O!SN|c\LCivp$"c!|=:=RՑYQhE0T%rrd[H^}SzqU%2j3S$T1~~)88]*lkv9x]e;|$M7Ne3qtuq/Zxi Xc̬: dWgY q}*}l<] B( &'Bvvu1/&R%{ @Ϭ; VC f:j˛,~)%LԕJtm}ٗQ > w\Yl*EF@ajVĝm.XTueGm14n581| vɉv`r5xODkG8r:2(CoWr&A-:4yϭCt\y SrmApbh3=PTo1  X5P!O5_>`(l%oBH ֎kRLb8AEl K7RYD<#vU&w۹O UuӣzSm3CKRL@QE%&e {UZVq$O]mܲ8,+U#gΖʢU OuY0SՅ^X٭MQѰxfUܣm>׽98lCp)M:%T7.%+e^F_UXo2<0xbHΔ~c$&N %)~*'Q2i4JdU1(K沘%1tuqu,1.8Hn5'c^5^l(3p+}<>9U6UHlɥ.>/^tۋ底,y䘭ZXՐM tx,GRNpyt5 M~JOf&J#Ѫ`8`Mʆ6KdUGܾ@dݮu ,'FNs_]RYr *G#oI.)BvT:F^%%0flvꄛʹr6dްV%ie̱<=a7 B:qGi/G#XlWg[ͫcrnOǵ lwI5$X5Nҩ؀zn:g ؕK 2Mu+`l%B ie]`Vzoձ@KPh@,O55+~?]Qq8EcG"Oܥ4,9YqTRlcKԮ8OyYIf;)<.ܐ  Xq>e)GB&>S֭զ"}fD|V7.ӝpQz.a^UO0|εxCim`"NV?)xFNJNC&CV|jx/"{9B5 hd*PeS*+#~MKKZWuZF[Xg1&(7~ZiqdWn0I+6eiw#u\C/dEh_׍{%m/wofU'&8hڽDyɥ{ԋ -B~HL$t[:_ѮwJ(IS!)jӑ0i!l* }[" $VYES%s 5a.K[a),mVY4xZ< -{\HVSVPqMLPu p? ;f4wjaz)WXv ac.B>L8C>=y(o兕e׊[$.*fY;;"fnLs/iWIE\,+ị (0TrB> =&m"`:b&]l=^ 8N\{zX\;u7'x: Wm/3VXsu٭S}d0߫|r~I@5(Ԉ0g6cVZTgyS"FULvMG$!{dvWƱW:T<;W#"M -Jӱmqay8P!3i벲əu0XYuN%q*cHQSf4Pb*cpVFɔ7/Hu<6DtwPL|Ma5\SDJ L+Z.Aqz;f/]ji*-i)x:T=6;|TfٻC)@પH/p=Qij_ƿH;)Ao>T8TT{(἖vH,&g򚲱B^l#a1d{*U u.𬊜ggY)8`I=ϯe𦓹w YpOHiN.vV[^/cj|.Vg͋ @zK{bsUvS9{UcHo/ADk=$P]w08A]&`m7=Vq*v ;a Ulߔ쵥 ,>ݱF_ x+%pL]v`1J Շ.vU<:LxR7#x ddh5Uws?8YY`` Kob5ǡydiwKB㆝OfW)RcyoR4e0)2mȆl >~?mg6]۟w޾W? zxww)__o>w?w[]Ӈ/ox/?~?ݻ?߽|_ն_>_ݿ?|zx_W/پ| S͟۳L||/ǯ^>}_/^7?׿lw>||W/7eۯ~,z/N_ZkӇ߿ïpv"_goՇo9 Oq&xu݇oz_ۏ?'X7?mb}훿;~WOGew?|o4?eCw_U-|߽~| 3+&%>~]OÿsO/o~;<ޜo5gK}8xo?}w~{K˷Oz=_}7?__?꧿_O^_++hW:W}7<0%={%^ŗ+ėo܄KO^7/y7nyS}WKӛ7/y޼~|7/yy1y߿ySK꿼y@ 7?Foӏ|7Ϧ_/H[hc?9SA.io?V/&Q~叟 ?x@/_nnq~VQkm5Qtz>㪻aEt=(u81{嬎qTPNTpZ'8ҳYmcUE`He,ۦ'kW)wG䑊(ek6և=r{RCVξejj['qĖz͠\Ii1N+2[y$vWO%َfꕬ:_-HZi`ՇuǞ*Y{%=oZ zn✅42fLo%g)TrQ,Jh{9F,d[հUIiI\&)d/{Xׂ9z0EJ&ܱMEZ%l#A܎tz36n13\ _FKq=+GEI { j:ǨԬmIr%q'񆟗cDx9q_ngmڲd?$ϖofge;੨+_رO՘v\Qzar,8&޾Ö0SnTs|챫D( 1A6CQVB~j5^RkiUuنGoAn_:8$YP܇>8ERӡ+ӧD-J6 rn56l W g+Mq;GE_MF%} Ǒ$pUrsW~79bsvYz&^{VU!t+NXl]qC{`_,,jɸb_!Y5]Od0emb[U'^O<.mo${fW1_8»s)=ʓ KRh*0b7&XӖZ1aC$wW; ڃįJPT1eWq+{Yn/I>Ƿ{U5'o΀rSGzK8Â!-brϕvۺt!\pPr ÙilC9̝q3в2 +͎gxLٵ7QC$#d18eNv sWj@6 e YO y3ij=x)&(%fAF@}۞iSQE]x'{gO&J7[C9#Rrjg'D;I:@+B߄JѱnKf|կqϥ>+N-@ (3UGPNɇxaXj; > Awr((Ҿ*v*I+r^8e(bpBVWM7Oʁu]Jm*zbs DŞ[5vt?% /))-Φ^p^>>)'I峽mt|q=R3궨qLygu'<`C%K>}'ajY%ՙ.V9r*$?~*R\I\+9qy`iӃvȎÒSTw*HeNֶȅS%$ЊNUqcEAXLwy 620; (Htt+1ܗ-G0(GTO:AؒӰpPN:DL=*.{R 1H5e&nE?ED@!W鰁dMr).GflT?2B6 gcjLK^-Ez@k?$h nlpL f!L*)`8$u#I˽)d&IJX@U:aM\ Ib*8d7ۂ= eSB^ U^cYOxPNC+"D_R]'miށM0R܎QH䇥*>8Hr%}R(Te&fIdj;h,{LUJ$%C'I٠7W:䦙1(n&8tXڃ M6/=L+5 >9s&'<2X*m=QkډgSùtzcrVer63_3J{u9/ v1V;G |hKXťcpo(|r昀O%=_dzT KMϜr.["ǜ2kL$,D^3)Wd7Sfkՠ,hI9Dq]ҳ(;3-J[z7ihT OB(W@I땨R^&pQ2peGZS6el4#"0MB& !߿mҽqXbt`(ʃ6]y/(D)Vq?=f]ږZ5cy`nH(JXH3:@WQ o6TN/!*=nl&$>)f)*>܂1̓8@&̛̌J Xke.LV6ͻt`Q pBܙC@ P:KƦ(?Kܔ 4I-MyOM'N&5G*+D偋&6w@}1Cř CR6C/n%NTM}Drwk!x#iՕjw{HM5l~̯=JȐNxRfxދ}2^ um$&(u<.ݔ?,:ר\)G]N㔒.҂Z#*5wCT_kLH}XC-$ gSΪZ&+bu"H_jsyRiI=W 1Ipr? 7;Yjpwt$ 'S1mCP-L8 gR`;5̵$"{"a OՀAVMDzfNuw% \\'Ui9J;/Iͭ/ Lűs$5I*:Ǩ([as-Ƅz϶M6$LgǼ9otFve-V;Km̹?|&J_Ҏ+pÚ$֥ ຟf7 6[{uS3ⶪħQ$ZIQ.IN,2aã~IX7ѽ*i;ɮ:$ R Sf. 7ZƁkX OYثJXgV!ifNY+GՆ 6]]`h=5󶼟 eh'lf8@ɄP&wMq5 xHɿ̫h8+WMV-b$dHΎfL$q_a\4/L5Lt-:T7*%IJSm^#m53x9R#$/ZpuJlTmz8$.'q,ǐAT—"H(*l]]dćE"xmic$>Yv4IƎc%W x*} Ekhw.eL1k"cպ}S*we+1y^\tLIm' Lz8UZf$Eh[&3(Q1d_ 啱m 9&RF1E~9V e hrF8x& d>0h\IN .XBPĔpvU=@0ρWN4wxozXs(:Uf醩3,2& O,ΏrgS N3;Kd<8x"PZv D\:w+xPK(NI9Lh.wnBFNGwGBm֭{joNOZ2/=VUH|/E z–U JeHҢuK7LC!GKDH2Z5T^Jc,yH(CLײP҃%٭h=Ղ$Ka~e 7o̶Ph-X} 6q#\%lf`/t !P],1k"pR&a\0˼Y;f(\ -N99,g)ճD@xv_xig(Ex (\D e6¨dWan18WZ,SELJTُr$p` a㞑=ʓKHb1{9 ƕnYޒ <ٱHp6|35};@9k.e1qej킟#K nٽRedS٩2l=뺠#唴|az=ɹ " hnʹrUH U @./ǺQ{S͜eBV1tTɊcqOӱjSEǸzT5]*ӵAAF\E,^,:gyP;ۑZo*sm#Gjٚl0a xB2W6ryK,dӳ\#.#hND)ى@l9UƐ&(((&'{?YyDj +s ҤK4v]^}\j[P$Ȉվ}7C]bJg 2#Pt "I7R2Ujt8kp.YW:MWjhv6Df4TJQ9q,s'(G`w Iz#\!E.c&RvlXH+K'^.I!3*89YMܦv/8r*+(W`KޭKtK岟+L*cTliZY=t bhk\'lT!VɄ(5C e _h۾HϥqYk (DZ#֭ۤɗ^ Ƞf\Bvk^ ^We]Wyi'B!&g%cLa)bflV[OOEVdd`)R2v1;jNTaUUcoEΦQ uѤ$ & zW-$ʬ=_uչ?(/\'8lT>tァL]rrFyc/n#F@̝ )Ȗqwl3=ju)ĭϱr%kIR7< W0#Dx&qn+%xqv  vVY(I[ćǭ1A-|~|QjQzEʄxnYQl]4{qu6ȻJoiDfS3|\#Q^i2UI!L[mb5c3f>bU:qbK SqF .i6Ǵ& 5O~ue/A9baB0YS SMY|ê#Ei,o4#Sұ(vUq81m%Ri!x0luKzEv1TϤS؆ՌG+TV=ha6uV#KWP'pKufQ{g GsnuBR} :UFy񨤆E@ U\mMFQB3z n)>wef8 wɣ|=oeT1t@ EJPE`c?1thg81.NdCK"+3w%kϋ7ZW Q1zlQL۷ ~MQk&dYFHu$FW%^(Rl:<6QSEbM۸Ek{QnŬQ Wol5MGcWbԵFsK/=r4TQ5ojRD(8r2<9yT*ME{ﱙ(5(L1MPqj< (>GY]Ah7ŝ*o+Cxf#L.6@-lv%mY0-E@/0\, h ZdA"Q6))s CCk)o&Y)1dC]:m gbkx4.vRg{~R83 9{vi9Eɋ"6(ƊNSǬpTW9k߆>;Q Z5H gc0HױU,>ArZ[::ܵSG*!H|`[qNTZ2r{%LRwrU).׬Ͷcp5LoRGhG)n39kqV'ApS[t`zwdO~d܆c A%f b6 yd=2 B?O"ev,I?pEf|yqj{U,vkD`ĕMl=l)C͟a}VY6 t$ܖzkjN tX)Tmeqtd%U+J&xc|4#n 9'*Nƙ9C[:ZTCng$sT4-Wp4IMPx:~1YU Dq+:j,_e>hzT>,^Z-ا%ޚbal{XR=HiшfMQ9YI%cIfreIwaDN `gzl⣌8cO(r)6\!~bG$Z( b^g7F5Q:W8dV٧q(T%{=%[IOZf> c^ T<} $9pgȫm6ul-S6ġEǿ;2Q&Z%Wa25'(p^#vU^g]C<ZykgmsYK"?U`9@QU+s>p5U@G yN\isZ"h{*o:p^ƹb*jDcc{k~/6!aǏ7b415ބ^+&6p|hQ"$Vkqx5YH7# 9Z`AN ?rs%= J:d ê x]e=Y˜emci0j$ےcYO+q\ 8G]&M|h~g~=aiK9I7*]bPp޾d镛DG("d\"zi[Ǘ![墔gBl&*Ӣ遴&*.G,}8 xaR(B>< +-)3ɞGhv-smh3\#.@dtsA6p-P>~'"H˸*9X$$G X_MrXPAtALqj|f‰4MymSv5Wb-(=B*#*BNdet6XB3Y1 {(`bBd79cPٹͬ 㚫xi\iR .-hSNa«|Ϡn .D¶0픶") ¦q`ZfJ<"?1q=X< Z!N" ;s& v+]ۦl{(_",?o*LB q! DXl8tp9kOJ)v`iL-28qsN; lM*J/.9VG2rar$a'.m GQa pW +Gӱyƍܭ"=0?hNMf?<N~.mnKuadKNE02S8FXw)8`ܽ\3 mfwf̣wS4Pc={UtI{9piėUp-p9FΤ̮Z WI:l VT;]pMOTLSU`n<.791ErG^-int&_1DžETx#y(砀gvfWKϚLԉ9iRJ4|{/I0T̶*$J"9+~`)IE`v/_Ϻ-YK56EaiS˞"|fN5U#* 1֢ Lm!b019k*ʗr2x)!2 gŞwUeޚp|K}?JW~9lϺ=C9ޞw,ps. #3o- 6vm΄W]PG+-q MSKKFS>k*$`az&̰k .rs:Oh\@b "jFq.roGwSNPԏץ0u0/y}ʰ@v[Ҝ^#m* [tۑ,KVM1B(O]IjfoD]K=c$xScKdzU&:JܛћMOQ|;Gwm[]ڨTX#pF~.Dܜ7δlݚ Pi|JaE6i'QW6s|$(vy9 )ĹT#5e+"xM$Ǵʱ`#zo8!GMـ`s0d]KŗkdٝpO>dT DN)ER'JaMBʕsp\e},8eβb*`Ǻu?Od1O9r9o(Kpl hOBa<(jR-"|s~mfOAT7,ϤϨQmps!̆;31D X|?vDpꒌNOutzVSYʆ=wsQmXG&06=6yze Qz`|=;%[%\\/癀Txt)n|t5ZmvERB'[cbJŃ &C}hޘ峙˷9D) ] ʳ(tO(5 zX`RlRM@hE{j%\ usUCجZT-_ͤp"5ۄ-}r1s7e֦hS0T(RMN.d)C?4NrV-:썄%sܜ 6 Z{Ḑͷ]9)y8\$#pqeǞ\!mQ6>X4U2U e%ʦsddX8(Zm:ä8qRc#a0xrPc^(*$Lj~aM*;pC;dwt[C{'sMV ;,Bw4L,n8oPMn*Y9US&_?E.#Λ@`b`&n68a4bAY-k׃wg%8{AOkdm5@w mh:LD`sf VĊۡ%Cf5shGL.L/dRvvDxzXKϝ@v,yqnܦi)"%k񝻹NltHj%gK@q)|b$%p|l1礦 qR1N BQRﲽb-ҀLSʜUjwk,s$Gҕ;>N+bB+,UpV09,b]rjVMV {DXJ\nD8n?qVqRIv˾[sX viY a68pRReā"6?;=2 -ﲗ4isM5^~uuS*}r ߷~z}OaسrIȱ[ V.s$5c*r$,V~Vyw.`3ӄI+H# O6=jR V åaSZ!KB3-1ĵ=̿!G'f#ΛǖrNB쀸J͂N%R|*O'h/9>1?M aq:ӽ#EEaa x`L "hvvO8߻93R2ĕc D L[ֽRzyngHpM f`* O)7*Z2]ӗL·?'eL8^xhĪvs6Kk;0ųm-1'8X|'mz~NP F}*.|`O,bt*sW:N2tø&aQIQq#c%&Apƶ8psՄDcOjbVZ6{Y٘b Lg?MF0MX y69ĵvYEǍ@6J)bQK;ltxjq tWc燐_S@l6/10Nkz%(&p<6.@C”i"A{zUZgV>mgQ +,HF$9'+forٴ='=,]0o}e+*2:$uV?8ݥyoskGٕSPp#{p2cw/lp@QeYfUR \,>&cND#l aCv gb•[gENn )ޜiWQܕ=-y1yc-!فMuia<RŌWIgݶM曒}…$&zV+n}_ 3 r'_bFO[#4Vm]z?(J 4ᆷ hX8CN-T%+!+/ ZV4n{Ybd'L;-kj_+h(~ũ~ʢSgWN[y/5B[ˢ):x|Y=~k?O.Wud육${4"JjmFq$'{I6펳,6%ˑ6Z!w׸JW~"P2Sq_nv< ;9XEy/z>+%,r߸ óؾ)D[iC9LgLclȁSaj_2l%(PeiM;Շ<8#^ п.ǻ\a`o|8DiOB#Nⴇ*Udǒ0.~ob3EXR1~u~q90\TN-ǔ s!k8 %1 pᲖT8=r4E}./jgip!AC[;,k_BN ۊ;w>!dM4w xg Nwթ?ax/Md\?L0,cT4N%JTXt/9nKnv7.rAmHCN(G"w;2W3Z+_C@GVO[RϪC( ;BE q1VB= ^&$Τy8y8͢əlTĨ{44 |׃FM&8[=q*€-(h``Ųf[]>m`biO6 =nCy㟻y1{NN$\.iO_g 8Z+_69Iݰ̉da/odƔ,k&{Kk,Ym/f6ܓHs%*s M5vHRf!p]gk0ᤛ'^Μ_g^̓8HN.2wϺOQZ#W!Ŀb:82E,,  ~:s9hp֛Y90pX+Ay.ť@(arVR*gs泸Zɑۏz,>0s y>]쀍XwNٌ) '`̍}vcai54ACj] q\_&<$#E:[A z@Н221/Oqgy2]5 #cd_ұ E-pok2+VS[6Z0NÙ|[ɛNN7?Dj0j$6X os%{$1 E@S ,?EV.qmj6l9[qkņ`9'ԫwi3-o6&L&-ؽ$=\MPYa3QdرyZSnj8IX_8 >N.9h?7:rW >t#J%iKA8^qta\"AHWSDqm=?5q`!*gd󞲌yp`۩Jgrs䌵¼'Z2aAcXbǨj~P;\?frƛ 2g<ߏI]oeɅ ^KKUnYîyğdQX:x!js=qkks6oi '<bA=KM4gob7.X|K#|T:pno`i8M5A)8Lhcһb;gn8J |rQ<} "󵯄~2rkZ8efG3,AiݓgwIUjIt=6R?smq csLT;mvNdl5ܥ$\e86?_R.l&c$m0L[V!)|Yø;5FY;l)]FimruS6[g]- ܽ8ETl2RX<,*?7,9'4M4ݴtus}lnV)٘xʇyn+"(&(!}O'V/#+ /806^t#(&|#]$1:͒"ǡ;na[/-VX4I@XqB6V<rIxlږ6vE_ 4GqVp~=`$pCdv[H$iQ%{G1MSq3?<r#M8Ҳʼde!V%K,gV^f68X["EA ǞMj57I}wq+ 'R$=ĵ~z9|eBƛ?Oa“",+d4w%~—V杯-8GA (/)L ىL]IEoIVdm#nߡNv{in߮jĻxZ"ⲒL1_,D%82NGqg198)5aqߧg[T;l^:-@HG sA4[i>?`kG϶v4)mɝ?{[ϣ֖d޸sJ~E07޻гqLrW˄{p65!hVTi)WƶvY% iN"|`) /&qBv ~P8 ŏ'C 0X#>vʚ`ih6p}LBN~r,ӑRoW"vٍgMJ!HS`#.X{Î#!,Rp}/{ufYZ 6baul}@ҘJ#i. QWė%SuKyrZfi8f bN_ c_7[⛷Tk\>D9i+QlǷۃYr&&h5Ug!Ym%Ӕbیv78:9~w<+Ŏ[yuEg%|ō]Fœc6GiW Bf"IcT@P:˛ke;j#,YG#j <M%ѥ,Dd;+Zs;Y,܎^"b hb<+uVck.]8I8cBĖW 3\fUБ+\:Poxg'Y cўbk'R!N*%NjkڨIΛC$ c ~;v,Iiϻ:GYo,K2nI;.m _KeatLzz,,_Oe_-LU Ls8ȝM5pQ J-u>=ehyQ\ڽk0ΏxW $q%av ZPejs wG0Cu}1!bݢT `7 (8U԰H*-%9eT^`Ov\Mˋi`YbJtxC δMKjU\=_GEd%%xW9IpC?8aM%TN J@tn9*f͡(Rܭl;2 2^rXSS\v꺳{uyq brNc'y,,:\\5$wbvZvZ7}7ijJwyFm+{X $#iäpҙljrl\@[󏣫2$`A6%Zm845gږf$Jk% `BZK綟&置M%5)VT9D(+˩5{wv& 9v%q )$M3/sàFl? 9K"v&ީ}P*6Jc'TZpװYBFiҭWPM8ntVMrT8r6`BQM1Rx=$Fz'A',+Lsdn?C>Ve|M0y?ҐV dz۽`n8(*;l؏rx쉰;$%]9($Aj6e N9wƛ+< pA[ߑ'Y *$P!w3xaG SKu`~lfTؘRM$|&`MbhelU%ZṔEqE^cs'r K!,c@x6SB'/Bf%F\">.#R ٴRč}&UT$L̟j`t[.MԻaTذrmX;Ᶎ- &WR52˧:L 2k$Tsߛ7cTTB5,3j++e O E%48gu=%X>2+Wd˫Ҍn֌=pfnxQK yˆ5XYOT/ V UQ.M8N Ԇ;s3;%sj DyD!hwKQn2MvR1YO _<,fH84ϩ+ZyvK-oWni䤔U8F NX\[B.ӹXe1e#q`3'@1ar΢\Ӡ^{rT6BV5PƵ:h8Á8%:Ş՜RۙBSZJ"pWm8Ozʛ&YWS,Wɣ_>XzΗJ퍭B7Lzo +xgZ՗k}-S{<&[n\ÁD >fkcJLbE t198)F$1[{?ILJy`XņvGՍUrr3lxfhnl>$\ͣ:"]tzYpc8:7 ? yp22]#njmz}֧8ӛ27f/ZIn*/h>]>kx'hYHE4rl2w(Y;N6|'E(}O͓W/;Dҡˏ) lM躔Y/ʚ*EL3za;I9AcYs7^T#vᰍ=b'jw_.4& tF' (GFp2D5e- ;`k~2r18ϷcbOY^jk?Ԍ8-Q=9{lKhTԕzlla8n羝l̔<@!ߝO[xj,RXc4i` j3^ۮnXRO@8)Y 1 ى  XM"cLi')Y\ D{N6kqLaWf8 hj\C>c*TS56LnxIv9EG g<=2DgOXTK][Bv딫lLjA*UqrrL{ikH &kp%*B[acS}GWW:™a-a:݄(jlזփ:u^.4(#D䲻C?8f EҬ;ܶ}"JaMi'{_K,Ҵk2*eiyhXRc%ɸ$%:+'nSM68aqrpZi =CQ3RͼU {S/vKr/R [ 3q|\6k*EQ&ۇJb<%v7s|pO:)9<=3R91ݫ-;H&mX+!@" *w:gD MK0kFXd׃p J!>m ^Hž 4U(⩬Q';A~JZgTLk*&=eCťCK3/2V 1-nBW)jH$<}nm4 վ' L av)_y3 0ɊO6J˝ʒFyzu߰-ҔKde'aiSVtꈳc;t6-S-'8۝*U.KV4Mǖ>@ &{&VufovߦM@|ɡ|.a~?Yn}) (srnF9d eܛ_|U6Rsr;DZ7}(TFU0Y\wrNx<ԅW;#W /nj~r\ฆ/Z5 8ԶPNzttp렏BDkQ-ᆿJZD*QHEd+mK6%/IH8&Cv.Zq1 Ѝ62Q!gJvm)܅Ѐxx!<JC~/LfEфL_ .Tb6wr[ 4Dl(Qf QT+5:P{59D'˅O|`]HgS ݭZ|);p@ .pbC %A!ex'^cc,@I!sNSG+i|!۶>fzW@|}En^FrY^̨3aTsLM*1LO2BK-DodW~bIm%)(K[}pK-xaĿĦ&Ô`^4+Ԏ;构i (؅?'zVV ۵Tsw!]tOrc|7Lи>F-Dg䋻7z8`, Rm5K=6Vm>A)4M%4'E)5焛%NDw6{] r%S}QI av&p3UquHMLڈlRb ! ȚxۢZ~DŶA17ԼZc ߌ(;"y-vƙ[𫜦u%J֟KD^[Q#b?EbauRYǘ{!hK_i:hVU`RCؙh110\2V%*XfٟMC(Gm1;F+j4j.6<t%+: (\]Yt/FFWnRe#^]`mѦCRlH0>" yeǧq+i|^:p0AɾM7؝^zJ6N QWk* .μϽؿǶ֝Qł&DeAXESyJl`l 8H`ޖQ+nOhpßFi 8q4vͻ¢! `R3AH~C eG$F)v+Xu y9Dmz|RbVjCxuWld8PL fU^ji宓P=Lc$v[jƵb=-X)EO'{/ijpHM .ݮ]*;y5 բd$C~d橞pWD#d% A*M;a.eƝw¯S7dVRg'YFf_5IX8B9ME1OEG TThSGlJOƉJch39y~yqkYXՆ)طϲAnVcGw9-ϩ'Z\,m8PrE86ˉÙ.[My J[ԝ8驿dy0"Tza_P]Gـf2 $vOI|| l&{ڭÉmbܭ\iَm8!WƯN'`/”Buہ LNWߝ[3Hw[URvycUP)oVpNR8śq$a4y:} eIN]%J O|A5N9r]?esWLаw%Wئ.О'ƀ9ZLTd)^/-PkqrqiBb8Recᴉ@.4/ %3 רE, mY]BE#7&|†e'>Yщ+|8HXМ"Ϫ6!qŨ& U䬂_>.oB!rK^ l4krLYh=;ho8&ichqz5і=_O_om_=_~[/?}/]U?|x_S]RxϿ_p?{?~O~}×}W7ɗ~~]w|^/_jb|Շ/xksgo]~__>}sw<S~ۯl_G>gX~Ϗ_]_o>|?oOW/ǗW/_}__o˻G>嫿×{ç_֏_'VZkVӇ߿ï E~rOaPx_~w/AշOޱo>~xw_?һ/?O~}x}?'V}}k/wo~@o߼SX‹W??}7?|%ٿ_}>_ OY~zo>x.HOo/k|Oן}`|߾|_G\|o_{37ݘyfy{O |\'3t8''ɹ<~*/d鉼~v/c1øߜw?u˟<8O!g0ş~q/`:KO_*?9}'go?9z{]?n C^﷯z_KW#O_| _z>;|z߼iO˞}|u{M|߽~| 3 &%>~OÿsO/o~G_Wq:xq/^~퇷Rooq6|OO[?u>^I^_+a+8WW>!ܧsS* >jO0tRu2t#r5> vLMF$uU )}>j>*1dIj%,泤jMN݋%/;,úNx"zJX?27Sbμh}Ҹv/r]yYq;pl_%1Z})Z=G^%+=]Ӟ#k_\jTzKSMNZQ䉻l,RhiE=xU䤕J%5~~?PQuv<[(љXL%6`I+W붢Tn|I8GP"k>O5ݴEqG81ٷ(ZN.XzJ51Zۏ?Òݡg6v׳]};;y>G<'=xQ9ulFb.`˭؉Z!eΠeQ.e DU˗q&ځnFIJ79`fSDE Eyΐj#PP>3|aLv)_+Ku5h_;=#'Z≭8NƬ1s ѩL&FGV X9'lAa?s a.>jkDI z khǪn*7OqR5Ww <˹j-ư9񑻧(#:Нl!8J c&ҮܖmM#teXgld+{FȖ5[H33哷r*[;%LúMR+Oi{o$!r=uXFrX-T\tE?U `Tz>8J=H;њ< IPZېRזÖ"5C`nYz$eG=µ*vd7L-aEH?shFK,DUf.c3d뱏Sxs\*M~᝟+.8`Sͻb@l:ר~P.1=Ij%MqEA#2IXvQ(Uxdh]ї|Sk6,> O:*Z!6y!ddɬ:׃rK͋4I+5b*#z~Tnܙ;\$/w"ݩHn^GRoق-~le{X{dMq}A)7;-ץ PIT$|%YR"&UZ%zz k6L:lCΐOٔ [t G3E*@xĊ ;6-)B$ɷ+ fJR/u LW/V albJը"OI,]D b5Rca_~%., R癡8`A*V8nc,g/ou|˂#A!?Ycn:_olKȞW MJ| M q}:qyxـRWVh8Pfnysb7pλ#l+ @E%fqǥ"XWj*S{' bnU` ϝ*2?\Irڟet]v]ʨXX(IYaXHF ^X%<ƕllJRV-&!5>Sb|Zo4!rfÃF]ю)o8*=(ި)n˩t оo=MSa]յٞT4`a'oL!ҦOtz\ɗ4\dpӯ`˭ݽVY,777(^8ERz/gSD6*ڍU`OvLPi>k<{(dGXh++8\˼Ű0S/l+ `\X3,ȹ"z_Oy L`QV)MxBNB\lp<-U);6g#4Rr+51jɸFvOɪ$ʬ7a1^ۦ썒:brRאā N0EnGهĊcoQWޚ4ՀrΠE NȴqeP ,SI: iLivͤl%0W&MH6 xEOsčPnlN㸌 M2/ZmSJjJ* ,\+0DE,cpsFޕW$6ɤrў\J{ű 8#kiS_hP~C9Ǡ߼wd~]?"A\>dhL׉qUSvE&K]fnXZ`b$>o>NbA.;׵سx٠2;v0søgD`ymf=Rprý]>rK]R S*cَud$>gӗk-|f]a{Qfb!ZG%Rq+N>𿓆6)#VgЙh,qzwf»Uk-vVB<ت:b<{驧%9;Kwb+"XҨrLm1u;Nκa$ԐTjP f p&*/6#ձ8\:Q)tk[Ӊ`b,lK2ovp5e~[q&o)A}d5fdUogAM9lk bԍAAFj:Ҹ){px 厃[pB}페R)Ja sJL|XD ND-/o ̜*r$*L݃<<ߥzͻJeP[6{n5{-ū%+Jj|Xbb7ɷGy?M#M7 R֜e+lf+po .7k `ۑS:S]!Ȫ>{' 6gƄp-%JI azSne#K<Ùwm|]HULY첳Ro3[3ɝ{$8<QA QOZv(U#٪@@Dut,ٷ6=DKG:\eoO)qA*2bqsT_s6G8L.Nk̨Ș !pIJ `ǙEp A3HHvSڜ3uJ y,[\#.yv8{}Z6cxƟ D7WgV8A橪9gJxxiP<G$UJ8Jþb#x%-50KI9$ a'6!K;iXM'Y5$E5Rw',g殶X [`J*+nqΐ6vl U>\N-{)&:M]>~Ľ(qʼn(4u $ }lNǢ&ϕ 1jw85bZuL+(e}lR6`G*Xx'Ɋ%֛ )0,oO1m^]":ӄF!HJL@񙊄"bNKJGT ~> <5 <6S0()l|B+5< jdDECl\aN):TjM1iB7Bq*ə/@ #3Ł;]ԣT)7 &vQ@d߂Vy>FX87xyn2U~C*xJ+l;&4aO(LϦ*MZ%?ӰG!u iǕ䴈R) @܄{ B(`T,[^v @\Z¤40gE3bb!(g#8i&an Yq>9al(AAM]T_z-aM:. Veܹw%`d.ߎR)9;dɁvQtC~hHR~'ԗHevyحRdXΧdfu8iͲJ MK6+51 KMp-+_lSiV 7Ap98D@ÄaDd8w!UxU Fp[x5m̮l@@Yq^@ F,4ƪq3g-*@z}:{Qn@;V&Ӛ›;c㖮Gnj\I<8CG-l{AlWwe)G ˚)GX;YC$f9%j8%bC6`w,  ,*a$4nG|JȲnL9ŵ2 z1C@%$S=ɸd,7{˗hX]d 8<3WF0FB,t^.la҃ZIn<)SwP Kahb ijm@GNN$IvNW3ǥ\=oHT ^QxpQ8ʠRTkDt \%ʰWICZTLcظAhGr)t ;B^x Ɲ_Z? M:2.JN+q(i#4N+m[0#W>+:꓋,Į F%דNN*hx6{g#bA`BJT!2R8b#dۗ"l ` >i)KQ5`3XF-lyH˥aIi}RJy- Y ;%e&C7g b0b>-0(ORl痓% 8&[,ju?TE:c?CK0SGlϤwQG=)H0ŊVY-VCcaþlxPqb90&~Kf9a5Yj@%N|[*ErzG25YS4Sn˃DX8sݖ-vp_9iF-=aq2"b%e"ahzS Û*y=w_2N ԐZoɯ-եQ=n/n,ce*/$yds ~iL֩$՞ޟC$ Y&uhf_uQ٘@5aʿavD C6I3%U%ĒitcE'wRP7"[e*lz #ʝa'%W@P;od@78.%wxdU^qwT8υ!e uueu0N"rcչ_C|{ŁK%l3ad/l8d,FΣ2č1kvP! i~c^%շ&z"ճR4/OõK(k0d?:xؚ)Qԗ66=juť%5."7r3'$cm>8Y콮[㵣N е}ʆx笛EN$}2Qņ}G2܁ґr織@ԕr#*?HZNi V[.v'5[ݜ>.OS{.΃91e"<4 xܻ8&,F9o01L5EU j8"\YbѲc_G5D0Es;'o;ꓷS}8(JHVLNJm6 Bu.2a~KMP RlӔՑ::ɍ7^Ӿ0[2GS#luNlpTV&W9VfimX^ V@{273`?9:zqM;TVH(`P oK`xt<勇ocj\Џ׆'YuJPaL+qZ3q6"p/cn(gEcw@Uznۙ$@H;<}#"fB X{6;e9" .4lH#P&J (e"m0s Va49v, .g'&,`Q:M1YT ԪEǙHP+#jܝL3,x&H^nty~fuJ3h#ofEܖ|ñ[jK]S,15Q!yV Ò,r NeIlz훎o8^W*&!yUD<9Ws9T˷yc朔=[]'F;FN]10W]9k4:/FB]9G 6%NF:],s€qq{m~ dw:ͲK8a+\NuIX]× _tFydIo¯nc9Z6Pa ɱ{qC/o+59/͖$y<_߀f(Dc!A"HL2 YU`7ix6pNVa"L&t{sp_]Y8|@~zbkCki{ϧX'+%ŘV+o$+.c 7! 9,HJh {u701VB\N;r5KnYOܼ\(o`ц9mLgQ9Gy9ʟ*gkXRuK%-ze~58HDlC&XPDe.ŭ w^My375[ǾʸuKh ,8Svձ?SY[vD_ki2 S xl-GC{IӨorb+F`Ư%OkNy{Y3J=j͙R M_틍:B]"5RoTau@(ILEx`ڴ_[YNfj` +ۈED͏:=م s@ACrYllSc֝0`Z!a%1OֈCERor<;oq,1G(7 ͎=_.-H ؎%G{kJ-ݞ>[z)[PAGg̠G4 bf[ձ@^g %. Wxt <;f>z4{" ϲ͆ S,c8b@KpPĂ.U.߃"UWOv'' xp90Y'Q4͎垏=Y>^NZZ3Hr^ [`W y' h_{FT%~IZU0&ڣjV%#/OWg =6^Fr9aSM*'̦ԣpqkƮcρ^5I$ęCȷscMM!M6vep!qB.D(bVuEveU hճ!A6zm#쳉X< / i4=KR CKe/'H(w8{}T _aJž'U[Z GtC|M4tP>١<,eg#;~?ζ5& ތ֏T_^cifq4 lqyB1bEN!OR 5'D^1t} &hb6])NM,k7n)k8m~4plΨ6&ry㢈XF3^WϨ\W4.cWD|79'IyKYq\-S%X%]*Jq[ٱ\ܟ궥<(ɶ*^k)nꩃAu).~QYf؞pwuى쟺ÔUM0|HJ<Љ?QlЕ+07LVK-{tdI+dxnOְ!g\8'>bmZsD=+oM<@Cv3! }n3rf!h%}-2MLjGp,AeAOrW̦{ ({ 2Dk;ҽ،@,B6QPf(pFE!͚;Eg.DPJeK`k[;!5/`6|6vz6Qvw˴#Q\Z mNGvy8, >7;F&a⯟;U{2&<;!!184`@-ˤmgPRgYj~BSj(=:a+UvSAeVL1ژݖ(.mɔb>Grl5IJگ42aUd;ǔ@VbOҗ:S}yCT`_=M%GN˴o\̀ Ű"K6قnO@2T:TL,z- WXȁT4Y 8FԆKg)ls):xS>ɪ 9W ũQ!΂cAcrD'yl%5WVyP8 ي ,^4Sk 2S<ƩD [[!BۈoD4d(@b2pN$lW )$ ,UӘ95l@zHT0sx;P2!;{q*Fܙifk-G< _pu{= .Ez몜}RV5.`z.tBQ"f䚔>SQs nۃ/txt- ˹ԁ ~P+\LwUJ|4| zt23,QQu/%.z:f:o}jP])- QnMeJH۸S|XO)IHM;unHm,c,|g'46kV`Cif:hξY)fim{f.|h6<4Qލ6ETNF%$pA *jm:e%݆_yMV pp${܀`SKUN +9#ngqu':ZaX FZ\UQ>2k{Ű8<S!9aI =6gdI;t[diMZE9'* X:{vsNO8/irP&|DWIm>Wsh#!ى$RyvĮ{ =i~[snv:9`JҴ}A*qM8QN'GW\`7ARg8Sy6LQglŮMY8!;[ v\Q}<|Exepeթ Hbݬ㜭JJ]50͹#pzS a,49z"i3ؐN79Jaէ6$Xd糱DS3[2sGx xRA%SMXQ?1gd yLy~ɾij_Җ{ob4*Pv҃7-uXd c (14lNEvض{F|ϓL"'azGsx&3}ɂ35^`m8RNedY `=NWܭ]ָtS⠑BF"OC8 WH,-kvV*q0mSzT)1 <<+W0~E)lvS9p6K~#S_|5uG`'%sW'*W$nYd5zq5S*I ve Vsip <&]vȨBm'!7HƢze ,I]ꂭrQbawH1Uqo9qNpcdFސCծDB(HBbU-p rR޵c9;͢G%89fUj 9W\PkmQ;VK|˯.o¢o;QTZsq<yk¾YI:Lzr]Uk,K6s̫=T/SA&7.mgӻI&5mW!Ӄ8V9[g#met4bcw쩪\;&0^`V1v:ǩܲ'_fZr:-jcC0neSY.;11KQ2/0΃ k1U`-8v9\ɜ`AV!cɸ`\V6_RU.1(O``.-!U S9Rm NOE\ P09Ȗlʚi{#4WJPTf]mB{sQAU0#'8+U6ߜ%&*|f@s&XCn(ЙW9 k޳ PTpV-q6 AK[[APmk#0=AxHG89>w̜ wgQl!geض&aNWsFg,/JxI,Zq?(5ӪխX/c_d d> skjհrv;9ңe`BR]w]Xb(M9g7ZwWrүYN;Љ݋dُmXP%HƦ؞TU/R½?ig8ύM܁ҹ%C'c^vp6M3.b0pTV6 !@5psw=&X zre{6݇WM- =%-a/Z OP 1(/˨}/1yG}2͞VPyfOb1\\,0.Ń52ϐXrEN'`im(1$8lqܤHҁ@\j!Q:" 9 tpUVC2Q D6Q6L5b(}%>V%nrtw*M0o<œxPV4,vd\gJۀg^`xҶ$.=/|#T/i#El_Yh7dlad:~lN5;xـ%>֏SRa䍐؆ekѥFls0V;Wᄈ/w$ ;ZvI8j n}S㗉(tv9etPXnd`C sePq$MfA$EU>#8kN0-X{QЃ=7Ԝ1GRqBɚ2;9Nr+!{L"^FuXS"G8Zyq"bN:6~0kUg2[UF(NE91Wb%I<=~"xUBD-L,njaQC/jPPL8r7"}1VqbϫD@ ^oV lNkbNnbJ aGĿ'&/?TH0&g*Hb*|IbJ_xcǬ[ S̀hGEf 3hZh,.{cSOPcRQ4HL e< Žɱ&I}OchsyI&U: .*TuےY_9{]\&X̭Cu]4%[*c{>1ר$@=Ei3Nqʿj B€^0Y![$:{|ްEֻoD8Ԛ&mI*h0(r(KY/6̜l4[X< ulMޗKT$'-MlH1kMI] cpN9V[fg jE~KnkʎxUE~!4l=qyfY9/06YV<?i@0jhf#;fV{nTRRrfWF<(KII_X#9v-8R_M;9 wxZُe8g%_{m]+d`Lm,ekM_v ?=+tiX ,3)%[rB\Edq΢(ebIg=Qq^2l}/8ץ%sۜI̪՘5 j mIڢ.pg2#`ZUW3WTg\ ^Y8|dDz5!}W,qc)98V.ˊVoST<"k3aZ%r5`ح\'fDNLk *j=VfTx8Ĵv%DHu;eO%yHmФf53z,ގ􂉪:$n[nŠm*\A:  we_A(\see1@im"cY=l\ui&[,}Xrwd=6v`ffbA[7b8WD`ec5*:ىau6D |.{E}emwe0.vYgqoDq.{]B)۔7L@=E2%l4ZVD&}ᩪ ufɪ94OȻU:q(iMWm?#.nQƢ t(Y%ΖJPSW$NF 4gT]?upu4r5Z J`%3wP㑝YQv|U[Tv:`3.pbd 2I,9`i߮jg'v3{_!BfC(kKִJ`N҄ 3y1<˛إ]Nbe6 v6M:KVlj 9&R?$qhÂdb'GGKps4n6m1W4,1`,.5ay^3dYA *ap{+&"AчSIXd[6IѢI EaYj,~e|D4Ҫ#s;mEٛ|R9b'~58+q3;MJsw21YЦobYC.[݉l RZ/!a<Μ޻̭Q]kXT.I鼞R(P?V`|-TX]wusEj۸ЦvRQ/&hWu˷KwD^,Mgι}+*)ЧLjF3V 2nǼu΁`GS(î"!fiyâ> ty;]$H--bF1`i#KV1ZNp?9Ɏ]c7W+YUdk)8!Yiُ2G<8(kKš Hg_FQw!CY|aي%\9p7ȑ,T5uuPSQVaɥ̦ sL3 Iɦp3#UDڞbbBDe6ŚlnɥJbe7=ƞDCi)uKneS}cʝإ"9r+ز;u{ 8sh֖9{Ed|@*Ǯ _b6iE|ey`jTwKe'>n=>SVV J_(÷=+4]5c)Jst;;-Js2[~u3|jא-"SftvZ:;m,-ӭkt*K4;^B.b ~9NIh|nD3겏 Ϊ8AfcTԉ|j[0R:,{GÉRmG(Z,G%(])gXp9\;A(P Cx_'2GWH9.U@F=:Z-@T$ i ۳Bo,M;ivi@ r2 Jt&bFZ]{Qm8gÖ<\܏*9_]֧Ӕņ@2sL+SbGA!me #ibA!)#PCB ;6}GfPP(WFDֵ殸n5 M8U ҼjKC_ )iz!;ty>!@A}dE7-u*%t3Ȓx#rmN4&3C+r&]nyq$;n|G%qi)s &sprXz<%0=XMW{tEA8}^Y ɮi0a&٧NKXYS9^'-K>R%|[]=Ij8 紊Mެ'۟tC};sif4 q ձ<׈&jtm`R 5s8KO:,'NБ=z _hfEY6CN˵5 @ǎ(ňQ]5<b+p]X i\3Jk_%uEwy.2J[—ׄUwS$rGr'tO+}OURb};l$5S/O^* \x}E.2jt~.!L: BwDi <,*]/=U}0lm\2֚eJj%.e@*r\^8a}iYO}~6c0k%AP '$U:}$ P!1@2SONu1"jZtu]*)vQq e+'3zl.F)np8+&)ɞ}kHbۙ* ,ƯsWTIiII6E?bmֈ=22H1]ȠIjaXm)T92𲈸CP[ZNKhqQzK[ եۙQJ5m +OfYM,8?_ (:;RD:NYb$2 R慾lz[T-ȹ}K6ߺl{.04=O"[xlx}WϤ{s-r9)uhY2S令͗QU]a8m3pH[m{kI"envsb򧬜J*VӜ#ƸK~,) @^!.9UYv1B]_5:Hm֮]5= $dyAC0Ή!R1yx8c `eҲJ=%TgO̥&ATjNj}s KpẂ.%ͼhc,MD XN68eaVOM$&s td2liMVrv[: ,6 rφ4M,%1,w17g(v[t±4y$sJ_3k2$t=&GǩZ-㱴4rO.|X! T /]s.E̗!+O*EFPc+Gu1fj`v WR*\wX&g#7 bX2vr@⩝gg* Xnt/I@UWԇqpWOV ʉJ|7vL6+YK̍0&U"^Cd_TnVN@*`t"Q8Ϯ(gOe̪5o`+=ޗds&UיkPCIy'Ф{ң&{Ovng^:y8rdN)ֵj'h{a!5| dHҭߺal̲J,sQ و/.Zk.ikYR, NCD-an ؕG$X4]l9ɇ*ްf/*W~Q!kAsK2W,BBoYEے|u4DҐ#p_V( , Xi(CʮxB84&%>6YAcU7teplg8`պdbIGj`qJ^wD$)|lo鬿ÖIzY>!TۈYeRq2Ea )9~/DR[B:aSҪT; XmےiwIgzxn/2^"r|*ȡ-084@0Dyy)%8mV=L?e0baBl7[(IhzbdsJ\PHqNUTmLζꬎOz TMM>@= .eUta#5%vEpp f.]wGjS~kyℳOZ6r43I} P +A`6[ք;=Qb6cd@UQ[8p6d;e';aΉ[ ڥc,U'ûmۿ7wϧ?9ݧ߼?|7~O?}ozoyݛ_!oO?7wo~|Woo~x󷟾}?7Ç7o?Ϸm|۟ƫܾo?9?7wo>}7߽ķZo_ֿrUxW?}?}?>}_zw?˟~xmބ/oyw߾"Xu ߬'?w_>_Z,x?7;o?}#[o~{W߼ݻ?y.?' kͧoV|xo7}V~Ϳo{^y~替~|߾W_V|?{7~|WtrA\o_ ^_7>ݏyz.oݫXǷ߲^e{\o>~q}/p߲g?|x{ݻ߿o>}nhħׯO?~x_k5W7\?gVջ\wwï6/]Kr Wn/7Vh,j_oK_oV~mj\_쭸rk/6V̿W*_x~b՞-W;*P)+)qشoyǟ?j'\ǟ~w/s_xw_5{[y۾ջ/k~#~7>rه)߽K>օr{z%3w_}7*\O߽ w_V߿_/5lkK}(\/zϯOii~~ _^uǟ߾3?G׿^~&iW\xy5lmJ_^qM^^q-+߿Z^^q-L_^q-+o^^q-kW\߿ZחW\zyŵW\bp2Xow?}uZ|9_ |}M߾û{¸C{Zgs/ǮqyyM|M ^tzyk~Wʁ^5ë\+w^!]קW/^(zU}~s%Wӫ\ϯ^rU%W_^yL^rU|^j?~?i۟_].{Y܅vJ/3יGsdh6<3S9%!-'9^ZmWLG>LlRq=pU0deC_zu'[RV'?Ζ[+1 Pg"yg1+R2J|!;dHP[pf-AپZrJkRi xl0$g[ξ[YʵR{Tt\gҎN:namX<3)H":s2[IMK)[OTv: 1mmbckmU\O|JTYq!eן]~)HL'[Bо+:P҂dXR76>l6ɖXQsl֊,e!.js|`m ; 5ƊDAݖt9''rq2ft"쓪UF{ 6XيZ-QIv`xRVm2S"ܩtIGTL VXe6\t\9CzpGADU䓪E]> L$u1ik9%(MLU!&8 V:+ ؐt,QEE"p\*t6SvIՕrb"v ;H>N5ѕ&ăYd d.1\ntla 1A @p;+R3yy=Ԁc3+k! _:uT&G'8`¸)ph Occ=%Ǔd),î Ae .~=f}r6mh5^-;}5~#-a6ig鮒¥|+u䄫nQ>9K۟tM{8\îiN"j3g?sk)V R\ Me9!ކ\R"$u( Ǫgw8S`|<#VuV%q&pEYǓxtu5oPCKĪ 9.)ŤĹl,X|!/"ZK6ШD|KyAu\]sšW,I#{.iӡΙƌ:Bx%R&:;9urqLfɀI5!(gXOuyWU( O2hA2KM ĎX)>~zpJAsɀ Kkoſφ[zmw&SF[E6Egt<\.ף\;IɉÀ&;<"$L1-xkIxPu:aVlcs$vC>xJFufӈ-|ɗ.cΦ"jWFCAWŁCW ɒ~3踺4LcrilDŽuze dEˬ,76-68A60Tr+zќhZs FzZGוJ"ǩ HP/U6Zi cBv"Rv/^,{b yd^7AtF?{gŷ\rΨ#O{2G 'r &*21SR3Y}yϢݵ18I}.݁AšȮ0Ͻ;GP m˹}9Z0"ňRrK5 fVOR2zHٰRE(ndmwn]ac fK0>N$+GuϒE%H{۔Rl6eXGu,U =I(?LrAd=džoL&(hY50rXxwrJ̡s4ɱ{&]mnB+1Ce#xI/uD@y/)h#ցܔ 6LÒfrEdR5^qLV{@H×@ 1Ԍ{Ũ㐰jKDvALpңH4fcä_JZ+ڿߜTY@<&c /rKdLN}.ewT>o;A$of,*EJ8U\Hcs6y4Xgٴ`<,($8ߎ[Vm"˕ ˥\-; 7lU2j{6wnI֙9zC4%~Ptsf$}=& Lj."KJpv2gky,}Н+65YLm8>&%M=k<.f(ivF;H)@0&+l#ߪV_yۙ.N*PY ӏϩlX5 ,0 7dq;ad/}l_&=Y ,L..V$fsrcPh?ww WCVx qp =U%q6i@ˎHuxwj&̎nrqldU#Iݜ,"6[wM JD_u'2ǨVheL9|Y>ž-*G3`U(iרQbCZD2];-Q }`;+q"ߜ&}.lqgR3Zr]_WdS%td]D&PW<ҏ%)^}WKXnAKC(@L-[XHP8 ad@`qzb6<>viߜ{DV}tfR]N! N([Г4q1ʴJӜ|V;lw癋]1L2.%WR=J:Z<$-Fn}VUXYEs;%JR\)u`G]ӘxoVP lA2H|OoL҈C DxܽlA冃-cYas9I/40=6Q0ʹ }o^P|YʮAAaӕ1,|H4V242sH =%7vj UX tUU@TZ:Q! /Z16FsZ:b4' }KХ-mJIQ[ݙlL:pqE<^ ?NC\҇rƂ/Bv*P.i3x4ʢU1yFi-pik9DK AA]oXh@[(xW3_sX>:-s5_NZj0Nŧf受O49g8K93T `n '_-EVF$~q(=^I/|ك@d,#1zm kz=M~epO9h~>tMb|d4F3g{X;=fϐ0^v ֌l ETkE"63}b d~#%g1&)".nO +G~䮲c)vi 82z72ke>CAK&U^[0[Sfy}s8XŬPQjeOF_K*VV_R?VRAgoڀؿa^2Q `P"}o 3@eI/~db-wKRԎjQ$bMn.}bmߋ?*Uߤ:10#R8$9TׁvyR^uʒϊrE(XT0}Jr\`p$j13}~*q5Mvƽ`hX'zZ>u"sSf(58` r/d/M[DeIr+- r" Tχ`U6˪!M ]×wd)|OiHJX)Ha]8 2;I2AHSN3 H\j[!E=%J*lds>uVn65S~E[¥L\m 6qB^ERՁZ얪.1]rue"f*J&e&vᴹ[$ՔB8Et/9͖FKHY[Mo* l 3PN+:Ő'6G ҹ6nLR{ /7t-7#MA  LKsX(DKf,2]GsoE@w\ޖ/D_P.Y&q6m8kus; gNW9 +x nI lw +'AC؂LIYp2FʪβWssW?Cʝ8LW79MKe1 $M&`ampOt_n S뽅w!)KLl%9}u6©adJ,[5 QMNˉlp<fȍD0p!qRF@mrYʓFZEVZR+bm D@<)"(nž$ By g, wd2ڄ}=flio2UĦvפbAD[X٭z>٘3i367 UK<ժO حi4/*sVִLLIkT*Ӣ5/QɶbE2[6rym;$/knZ$xUl;H2.|4e/@Iv $vl:7EC ^ gW|xqAxIn2iA\8GYҼ:pϔY}ҬW Yy3ckϮx={$x/ժ(,~]gjP_;Gϸ]o@G[gwOeywy0{Six0aftֱV$8,1H]|;lE]C+ifĎW9,̥-wYX;t`wɷ=scoى:-=kXšҎ6Crci9 Õ82r aLuGm8bH8Ն?I]W*RB[)#3&*bJ{ڬ|*;&h؝;au"XRÔ>K]$46S;7.8 禨Ԕilr̔=Ɓ_xhKhGx//8SES/U( o0ANRtaAboS[)x\"6Td܋m΃#,ފQmK/)U8Hrk& Sp14Glr[M'8Uɳ,4_Zeias~h:8:xRGWswLIE&;gi!oɑ˜,ៃ3"ĦJFqDKFn5YzD[s_iP Kv.-GkSnT; %A*vn \?Fm ͮ_,#QiTs: 'kB!ȋWB,^8ϪO5{€+|O{Bޚcȱ6NcLwf2RE1?LzvE;@:&N0j+v}%4gLoxk@dEHUiWg 8~Q{ n+I*@4sXKܜF7^f\ ow9C!7gd^NDKI 4\ݕe5j?cSZ<,iM4P s>GeYe(v*3U\vZj2¥a4c^W ,Νu|шX^xBpr,zַHҁ涗L]DI;ocՙW6rl&j4 H(T 1p,IC.PҚ9xg'ϛ+eP:x %?avE^uSۆ;n#X?Moᜪs<VŕC);ƍГgÅ]% ρE=gќ`uiX!Zpq\$&kMbf4(;xDw( >J$eU0f0_q?nyQ-0z*V:= E8lU[2l$XSՔ9*Q'1vyMy#{YCLn:9qyI?)\+\U,Inl#0$MBa1ZHhl}O,yS/lq${DkyK續I+P̣i\sY_K;lr 4x~TG1#r+=@3-:U8`&&P11@Vyѕ1ጃK,Tvz:wi09PydA*;,vnuF\쇍8< q<&N<0 F#wl=ܥX+Zmvp C,\: k'݂~y72>h8H5;{|A:Kg*qtl%ÖhYhlq| .+?X9[+qEa Y$]i:~K˽`hzAP!j'AN{7`U۲a `w1)M3$fd0c.,ˉwlrʷ:9udov ~kGX{̖}:py\Zd ~!9Ȯ 5Wcc1}ɳ}V7ɵÉÉR;UlŁOTqOU {Fp~7,\,A ya5`c-Ee˘Nl(u&2aw&6f%bj2瀫7W_OX$Xcvppq_aBk9l 1n xr6M̉E%|{[}ot`FcKV퓠'эYć lsʪk, v廉-GBc"{GXQŤ*'OvXMQLQﴃ(VjJyI޴iMT*)G$f @>r<:3h #vx\R7=>Kom_S_sf8fQyE,썽5<%E`I9M-9'T(M|Vi5o! ,͹0NۺSPĊ7AX+8T%9P z!PNmٟi6mŸe5wT \[*W M]|XK ZeJ_Ǘ r2pwfI&M-ΦZH>P(G-m¬[CH[)Y;Z9PW$cO Ÿ|p` Ad(N92tS|e$u~wʶeqa +[z| V?1Gt;E脲3b6m43Tx8_i;){̩uIyג) J+tVK<*xVOnUH`_ҥC9^G:d&} 5;LNs^DNN\C[RUBݺ)T^&VϡfA=% fk>aZuQO謽Kf^/qvȱ ޲~FmIaN;9x:'S<.U:f,nf)V 'ݏv1b.+U܆r iAL^&P|DJ;BFg?ү1#xc/T $=_0Ive?J&SY[.$Df`=ɢr9\fn5%&ֻC.Yh+V̛.m; ϵ/s>&{q=9>"=YWRNTd<6 /L-,b/ڔzPÄa1h}{ԑr˦ h ˦B76 hW9zVbBM{[R=C{u@D-E]J}%p+b~@gXf1Ƴy#m)K[; GL:XEl;w6hGGTSdFo"7lMlV*M]K{MPOY@iWMIpO^ܧH835bRk؊$/vF8Ʋ;Mb%EndI!ӻL΍ Ax[TmBMK#6J8 8өB`ŞC6iI-}3#U=P ʅK:W_H'nqJ$N cwԮwZC)%GC \i>eyy?A3`ըC #ewH4Xhv>rVmc_H:'ǣSN}wvB%aN6(2"6) g^$ۛl!kJiE[sgw"DUjN;Y^rc5V>N&c?urFіi餀4vvE;p6V#vtH+9<;ˮfcM҅jג} T@&j'sΑqM&S2YջEeإ * N96O"vFӮnؕ#'aAOX u \[Mb 7)7g>Dr:<_n? +8 fq&"d?6~5YM$y[fqPc}mUvL%]]#p QfXB#X'@@oAZ+GNF[#d@qs[ߠ>ata|Cn9q$`]<Cn̫ec:Ar@2,^; #+r\KA-bCf ;d`,ھS. riȎ\$LVN/UbӈP眺R;|+5YY-.nEJ hwKm#88?S]s?sw b;-,$ ITF9^FA> ;OO?pCE66m|D d34HmK&YZe% Kp ą+Kl7dIݞ?8Նanu Uieг".L!YN[o>< ΃'ϰ7y^rtSrE;}DY)Uq'HV''|lM1-Cr7N r4MzppMv(E)LI~qr[H<Nd-Ɇ'j9meϕH_Oe ;QFocpcٮV'8Rְ&=‰8*]%0wNGf_差x6+5Ӗ$2' pnC2dL|%T2˿F8WɸLv0)pŝj.Kd/˄tv'8Ez)zZ!D;R ~)D}& ^]$}r#z`B;vlj4, e*b:۷p79r6@0 ٛI`"oua&^?D`36:Uvz3]q#<]9:F2Y&r_ i1:t&8W.ϋP\ݥ[{[$:"L<9eNMl҇[7K_$@]HjqO2K$Oĝ7?\0DI`a˄)_kw"97P u I+Ju.KEnFp2RdwjG6DMmS8W ad'wKisrdQs:%-%Is&:KN10֢7qa`MBd@ٻeTT![g3 z*Z|LjرjQټ0҂0&ۃ,Ht_>}52]ۚ `8(iX%Į[؞`$Wuv!h&h'MFJKt]{RV;u;%r&]jrWָ\L$%2B‹}pNΙH;3/.1Ĩq\ `J.gc>{7O@ \eXژMV שn#C?e@0RB1cH'D]ALpӞ3J+6 ja(3']/Uh8J#ǐ4M@pþ(fя9Xvyh$bl %[D$•H"B;h Eķ( NBjvQ1yQR:t4Qw6k.l&56dH{4䌱Wv}Д -3RlK0iZiŃwfE+{H|L8vϮxHkJWPC 1U 0wnJ4 &,T7:IN8@lB848W%Aߕ*p[Rq"e)&~uuږʄy꾦uxcmq]A"s5pO6GTzaS, 38JT->Y&n!Y&Ʌ YUr6l⺘tgjU)6 ìm2:\ <` uж%iC84L#Y5(믩{ cbe[p0WUϗҩu`\[iGw`"-o~C cpR%OqfX)d閬KMcs#+",E0{JUY k$~񁿟0Dd!)ϓo Zj㾫AJ0W [L` 6NbtM$m^ecKwE-9nF6Yf'`BAS}68"VL aKlTQ2;x :5m|[Mvûәzq6 /lEf)/0m2&mGMA aO H(W#Gj66k,l)d[[T8#SJQ}.^T|0ZVk3VCe<#!Su\`SM"gw̰r bk}CNAM\լXxץ9j/~mO|nz'> lOY5 رcO]hm=ɣ{ʼnDq߆cd='O1&|iKq˭;h]>ı@jǺskSPt8Qۮ}s:>dpsNnl(jRk26Xl*#Ʃ6q1Xc/J-ϥP !n*[p6|J "[&;o "c;oMB֚%[ zF+b]dejj'S\<-q%՟#PiVUFEO }s`A!i6$p9ԡ7?W$]rNb~#Dհ|MlڷtW=w9K81TϚr|1.LAlo,)gV Пx c+QhEh͛= pNyq6E9(Uu:PB%iޖcQa:M MGQ,3T*8vt0[K$c?N»;Xe팬,-}9*`[$BDhɭ'(lUNp?'|*հپ͵HJ^GlW=w. [Co9rSsjk"/Cc١UňNEf5bxcYVʥVD&.[6v[c$$q܍3,t/7O%:;Y: C@`&PY#)@XjJM>Ҝm&eHi6F9OՏh&+2lyR\ON>XUņ@J,%'"ᣍ1>M{5b244N9Gs'"J }@:w;yȜs*oRdY=ҽxfh7 y>E6MjqPC :2Fux<J[bd_lf$>*m;k9KiAV[/:Ojc v͕s͌w0"۹UshoyXB5 !yM/a=TBj$:uܤr*K Qu$p &棇IB_;!]4FiR7F[d *9MKk҉r*qA+l!$ǪlqdNGy}*lxN} !:Ky9ARw̋T-6d(oP qMnV[fpcx(Ͻźҵ: :[om \Am< Lʑ(3M>@a_56sSCzOGD a7@ >[w7O_pwWux((qN<%1$iYz|I9j?ZeK%3/ P+ E)|b=&eݮhD ro⠐"Ў8M|c/sXVpPDUI@j YLS?m)"ܛ-qUq0QS;0\XlI9f1 (7:i)H\/!3ɓ,2Kh@U+V:'ytb6DŚHV ln-h 96O;g@]v_ AP^.%)y@%nl]=p"K#ưr*Ӄ7ߡںKg wǑO4d0Nd51;5l8T{Ěa}]Yʼn^-`Y= ˣlYb|ѸddS+ɲۯ5M6KB^Y;|\5+N&ƔY!d'_id J:`0Vts=Hʁde@l*CnKR㾍wU:݉ kBjݲҺ@`⽸QC6}HpH@ )9HCҾv&`U /"ϑoNe`/RXi/V!q.?2.+oD\S$v|LOBdnxR%':`r Pz() XX@TR,pշ=i#n 7faylZ)%u>1|:  ~xD2m4oYcZN}L-du帉 ²ݎ&oCoslmU\]Q Y~O1'+`Z<8BtNͰ88H5L^yZ>{][.$dczpcކ)5`FY 1݉c!0Bz\6!rxAn`" nj7]xeZӠI@}yKأK\][SplQxƗ Ӑy䩝Soz!M|eȗjYf|f mn= hZ&Þ])>U}diۭvd;֓ˮcgR2G JWqGۤk G4m.u,Ŀח,gaf㜪B+[[pN\tY#$;LNRḈ / 57z!b)*&EyTWu{P8q9iT%@Ұxn \cV_CHڕ($Nd`) Ԏq\rN))"9 vdz:ZNq!k8MJ3=6baAC#6z+*E6ft-Ȑ&WdĬb,XwKFXe₴92yfiVݹ`>Ijt֪riQNbt3Vs<gm?Ѣ:d kC.f;aصĈ Qa(TP'nB`B)rƘ;'bŔj)7DZ# MB' %3Q'Ko?Hkq;.-/6<Tx@tiǮޤ0 C13rx[sfQaj9;.nf,s$f %,q(ᄦ4s.wf܏\ W'}VBC +rC>΋KZh#:V_7,\ީD aب̒Q&_\NsdO|m,.;8o3zmZWm6;O+'&.(6=qHY]bӔ4[Us?x ܃|m{y?޻j^g 'g1&!ְ|լ #oAkV-:P>ύJ@ZfcI<7]Ix*a[`BDY80'2w_@QL֢].Z1?!4pgR`,\nYDnNiJ`k|]r{C9a$B-7Dݜĥ.[A4R9R*$E!mG԰|icBAˤfnECugŇ3. @O T@xjUQu:7R4=jl->GOU[6л"oyP̾ȹ<9Ro[!ho*xiLʚNymj(02N3lp[jf@.ǔBI;+qN5۔DJ~&5Wo(J%?Ѥ>PyNc'nѲinZ=c(䨞9D׳Zùr%vDܔʹ i΃qtOoNYU5yxU<닙 /R-wHHmy7GO.v{8v|Fͣ,TKV a`L 0SZs s0!PW%(cS9kUi%#&ll2هe/B exm>^=Qو]|o?{O߿۶3?~|Gosw~wlO?yywfomݛ_/b ܟ~OoM߾w!߾o?}O7oo?߼zݟo7߽7:oOo/ozGͿ:O?w~}>m︖ۗ\/?Ç{?uՏ~ }~W{/?rmקMx_߿?[//U[͗'?w_>Z,x?'?ŗ̏~GB9޼7ʛywx\7O⿿ϛO߿?|3}[7w_|~^W|߿z}_>|՗7?zywg_'\o5ëקo .O?}x믮_^:z-lWoq߾^+C~k\g;\{ëE}~Ws+o_}E&>~=W]ׯ˿>:{7߿~~/7]Ֆ_mv;~_oFkfWlzůXz_ vkWׯvWbo[+_~b_VjWMTl_mQiՆJ_OKƦ}x[\?w\W/??oS{֞{û߾꯹˻OWen燷}/~Y?ɝ[>OOI~~~^.++7O_W//?/\Oo?b*\xy9`\+^w_-DR?}!{~}JKcGmݧm?w? 7/O/~+ekW:ݗW\k˗W\k_^q-W/k/6Ogk_^^q-kۗW\߽Z򿾼Z+?Z˵/z?#_ӥoo޽G_r?x9v+nWnBH;Kͫ\+7W4p ^^U] A>zUGK󫗞W/^~~W/crUx㫗\}RK xO߽tQ?ݫ硛VF.ژx?5Oo?g _29(-yb4|۟?~ZϯHݻ?v;EQRgU1X$vPq0%pwX>Gk9.GG lmma,jتZm+YH50>Ŏ~,ܦWWqqIog'>- Ny"+]c?is4~.]N4s-^4(GuFqaFR\,CZʓc N4ev.Y$)X0,vJXue}Omp\|H؜e"E3d;~i6#lRґ=<#!mǼIOve0leC\}n|ٺywzJJJ~fA,\/ 1*,] giܺy M)#X}W}¾Sg0gP:{ U8R6n\fRYrn)d,*թ ߮HThq:/m"Ӓ6zϖSDc$s'.%n˴T=NIJ{Y aLz4j)~^#_*޽q!ړēؕζ,B[II3Q%Ҕxl?Gr:'Ѳ+K[Q:#N7v쟍Ҟx[`j5(Veʋkvv K4wԶ?sT9QdB&W%q#ԃ\L~.1CO^Y;J9Z<_?38=Oy.?8w =+ ۓ[O=eUت6GIzƪ9Օrrd'CgG}{wc'5pt Uݗmq %9ڥJ<Ք ՙ8OGw`#罗ͩqZGc/KM?:v|qwxHk]w;dg5&}0殚}NzR"J+oܗ$fĸnq$0,LkOQ!ȿz%# A-"o" {TTKI*6ؓ7p9%}?Fn"Ld;{ALa<죹X֞ +JЄŊaq^C&W,lhaS`I4.;|DsY.f]O,X˩s9 u؃a)֎ZQ(0E;XHShA* #р>?fp쌜{ y~C(`MpXɩף#x0W^Kn-M'<G&CIFY>'F-܀ ߑk>[vM)tR/W G؇f@mo2̒c\ o弉J Ӝ=6EGk'N˗MGLB4/_s"9ծ=vr5yqA6J:5N["fِ}/84~+g`IbTRIoyB9 8tckdCɇˡ*k"Et U.MpLO?.236$}* ~-WՈEC\> &/Q`W׮5iA5ᣉo[7M>A4dSs\,s1qD\Cv{@v瑂IT'LdLy+i>rٮkO qLD8 05 x=>kB)ѯfvP{(ox f\>B)AJŖNfۢ6XT S-)q\606ܱʚ'9at9{cbp؞ 9vh8SL8@71߾4!ѱp>f*jȯ9(ͣZ$|vx]J.(ޮ|Y@eQn6q7X$D*X!{4eVޒFVmLNw '.lljEXrݡ Wuᕠڝ uֹ5nzI7O/ zE|ѥ;oc^0wXR]SґcW+K%ґjСqYI>T'1`!oԷ kqrU).^`5S^:*e =1n -[\Ѳ3 l$va*2krsO$<tx*xے0qfvV9݀iGnvHYNsǭ& Gv֛M8%ܥ8K4T00rۨ&kYBC[ktj7*4c'bLpC&iDGl`E Zbk< |w٥m7bOxU}ܘl. {\+b&e{)u6S̭=M+_"3P$s\%*8tݗ/%{qYJpRmtҪs_Y_.Musd۩ZR: NJ/d$NBD|`o-F.e+20+-Z95錦q \l5 Ӷ9տ*O,556+ dXκsUȋg`%ƾ>m(g$<%ge|8l J6V+چQlkZϛyS9(MϞ|FkUTCnR\vB.č(FL V) _btq,PU$UXܧܘ l@JEm֭Fx)g I C +6JYYOD=q١˃t(䐞PFlz"œ B7NATM nk1R w2p t.+;c暚Meya]}DS[H{瀵Q@޻MjMV㼭IÚ=&63<E^VpA MIM3a-)az7Ŭye]U(ylfS# c/*A3( )o0C*7T MMY*˓[jPJ$R"ݹe]*)*bjFKYWڕZ G50_a*'.ݲbT+7Nl};u 㔩\udFWZNY/N↝r"6ۄϗsvtϣYN0;(rZGV{xBHt۫:p[kuLi3dVI6 XU##8M]=MLI)Djtd3#ڐ~sNDLRg5~Ի"J< 8a5s-tt4I*u+V)1~\S@+TL lCJTJTqg T,RM. 6ˋuP0%<3cbET)UY[) A]Vt /煣1y# r֡HuUÀ_ϐ v, W%x@)~H09xIm[C 輄 w9G dZ!qab ]`->!VSG jDʴ+q܅'UmKf-rI8"A@U=^o$eS<64̊36XWdWI6t$,gOrdXsީz1ePq_IKay'Nl?5 p`$UPOU`tXgNaZ1SZ$G;fr<.D#V[~Jb*,uZ2!Z5X_eC) &拦#PaZ lJ.MFv'x,q,<tPqclt^f˶ nI߽'mg?pV"1MUh@=a1qݚ%hIi.2b<&~_2nzLJ+ƨv >%ȟZuǮ :@#0&T>ć[&?UQQФrwTsRrUo0gos5?*mR^9I8ӜKҪ 6JeZufl o6'|"Q?R-*qTBp~}mMpm-_=m=±v)tm(s ̿YەqZQu*qRRD`ѤVjmH(e˫$a/K|>,AxKI7:LRUQԞձcӄ.ٳJע3Y1mߪe@eΤr{lX_jɑzLʧ`*on-o}IP؁p[#[.2eÚv ,e,K7pJdTB`@Tz1&!LkNWyasCt5G俶s\8͸%>#Xed9rҜQSyc} r+-6+p[*x4{ՉƚU:w룖VDy+qں hː|U𪺷U'9VIN֣նơة6{rv1tp0̌ G .~^کd ` HA6S\-@@m-tWUl6yH] "0~<<йܼKqj99WoAFlMP |œ`Sk~xl$S\,7؛Tcu*u~Au&o7@4nTH m͗Vnu˕=jVQT~xV̖=ZAͦN>;8p]«?bf[ђɢ,Yh̯OR%2 "ʱ|4}&1&Cqa"ITsx̿ynf.)zZDؿHB`i_Xr(cz+V 4rY4> Ӣޗ-/kP/v$O.L?ʯ*Wkfx7`3C騧M̂uBE#XrP+T&|N₧qx2@K?څ jۡe{RkMc%ľYoMk1K9n7X| BOM(]cEaE~`pm]8}IjdӞS$1jpomUrspH- 1֥ ڹls} .7,uXEApDnut+5iG'kcN8J`/{c(obo,JWmgk# 8%@ _ m]:Ȇe+P.ۗ6Ǿh7ߠjڇSgbY- ıT[鬢l"8g(IddJ?% N˞Fbɶlɵ 6-%@FDLL<M*bu4P1l*F9燩7Lc ј 8r멘qGSYw<Cn,v#]ҢtL< @%ڥDɋML~߫KP }y|,P,Yq; Wi4@'ǰdqtdTtc띿sط K[cyMYW,IzŸԁaPD˜( >]ĹH>/kv3AYI)bq8R&QKq:X皺]^7{=f'eEe{PH4GCiKBoKD0y  `J)omyv؃[UnSRvbFܳD>Mt".q>(H6,yC'+k<91;ţdv5sdtWpmjP/fVBD 9b? Cdyr$7a׊6s?UC>j)֓S]-CEww [xTԱɓ96)JU aqX6! p;e _US*XQhVϙ)vu8eܶrc,òGʙv5c˕>F`%srV&Ke'~TyԑNf_2V?v|:b\!宾x]R]/q(vwa1$EIpIQY )Z0KY՛}IKLSNuô{|rzp͓:lњH`I4X5Q'v5idA ^,m dѕekm$|t:QJ8F7R$|pb,mPW+ÌՒ笾 Oa3Y]>*~>K~iHT\Ua×g#,YO,tBg&~& Iȝ cnc-'BS9@ao:} Yk%qO]^Cr+D['ݔ*FSÐM+=%3;FT2.3N9SH +y7lTfoN+#O1N0ղ 5$:lyww x׵1ˣHiVLw,6쀴z\#ōVS k&&ؘC i9q3E8MjRC;ʳfɀ-OuN}d :țХFsCV[g /q0bmښ=֝K*r[͑zW^nSv'!SvLdO0Ҽ*Y~;MMj˪ϣg㛠˱ K4Jċ{֜ q4v8ӌ!g1D)"/:3^7s4q׶XgSiƠjiy8!M΀;[gԼINXqOxk"!)i[,wR=1\햻*;7se FY%xQH.3_+!EA~9VΕ=@g}r!SFr,x"x7g/4YLp>Пg8]Z`61'@o  ;!±5+ك_..y#.rP&B<;\eڳIu?$wI6\Oٟh,Q\ylO+A&Un͊8g82wRNӃjCcGJ6A*`4S!S7}g6H^{V֑*3'y˸Ylg9KZ^w&B02aS-`fJِTh7GYwIRw/Soj+[ꀲqʟz>2 w0T6\QHxh@*~,!ɰ̗. wftc$0Dp@j3Ns1qQA> {k[wU{MK=N\S 5GclnT1FZYoSB+Hs`WrPxNF;j#&g3mA2 #:/;Tn tbCwAY'.6q5biDRmTksܳInjT)I#!{ј{c+Vt9RGƅͭN |c35*_I ဥEVkZ-f RS;6hSoIWfwA * 1"v-ImHg)m=p,FDS2z̗Vp`vbfـ:6ld5I9{QcƾKE7 bGHZv^S[#N.sMM]>OgC1]<"\^m#&g 0f`:mtLM sj|ɸj*\Rs[] f"LobJ>&0!ɼ6dcu#>Xn;ZIOygꏷeT~rG.W4#~߷xxwGp~yWy!hs gMH ;Ov-L1G7Ε}U[j;ϖVSXлDx Emji].pw&:"!r%*7=x=}!l5Jpi3~vDVa8Q/vއ=RKbgL&z_<$,ŸXNp# YN&**Ob1Ti,p` E%tC:6g$Mm\5DYK'd> pq㒰9a^ZR_x Sbl) 3UD8x'H!I& ^+3B6؊T3X 8 ;3lKAk"PI `}_CPFԴuBNVe P=@"uͼgBQ15kyڐ8K8FUTs4j8gvaRE7QxؓXDt " Fʝ* KO<]87i܇-hmɑF'Ý7i`8xI[IeۘM^FĢEs^'Y(=p%d×PLrЦUPrx oⷃ3zN~EŻMHudcNQ lZ=l)c3Y4CwNRrjLяE>d\5(zU=t0ņ˲-.7 }&YP3Τ2^DV0-mb)!ٸٷ˾.&ݞR/4 T733@6Rb}kc7Q5_^6He/C+3 Ov=yz¶ݪsfI#Ud%( P˼I|z/p|mEm<# H(NlEh༒bܣ&gUEO92eA}ˬ3eBŗ6x9m;s pqltReSkg1Vt+-DĞ %!T?׳apV^S!5.oQ@M vj^=~Ǖ]n=w* FȋM¢jB%p2LYSc"?:81SߎufgtljӴ <:)/ffǼ=C;T:# F%vTz({4a8 fmь?-7#5Jxy`f,:1L_{|qw8Ni)3Ք<ٽs;We42m%Hd> pcRInvCA!|qs(Tp<'.f@|?W'rD9Z`y>hOK6aaM mc@jļslUyT,O]C>t1KöpJP34;|T;1j͡ n HGuA*-Js[! +N.dAD;7s6u VE˫)V,;`-\9k8^@_V9:쇞){@jԜ5:JnbDvvM`˃ٺF~΂*~H_IH)-ԁ,RJؠiVb q`%bu;ִn)~S Ek_t b2Έ4 \#JT7lwf3"2Xt ¥2z廙Ʉmy}+f”V¦-MN*Lc75y|N,6%T6qK-r:ts"\92:ne"ZVgH1z Zˎ]}lUE,tW"i_0qql'5,"3eVN:r s[}붼'Ա& hf. >6;7bjUE~.,Hi# tXjvYd{7gOՄ*vW~Nfp9'`%J- =9S2HQ g-gvY{aiyȉ*93,Z壚"/Cf\W1HM' {an$:z.q^Im{v{vGJb0F<$iw}$DxLPem2J:#(iRWT>+1Y# wY Ƃ%{ZWBa"4@C(S$  z(ωw"g_)[@m!㽣2IӢ2T ɻAM)*Lӣvӵr{2Ij] ?l2K\++m/Uޡl ܉hN#<~W@tPLaXrxdͤAXVIE,D2JNq|[l n*of,&_f^,g ? /MɂY={=4[AjBtr`g-Tp2oyCfslĜ|VPLF5J<2(1ak"yI먭5qY9f/e[=wy)gYV}aj`}ZJ uRgbyb6W7j*_RXb8҈B('ĜaVO%{"WAEB "p+Zu{Ŏol<ݡQٜ3Oȏ:Ra36)"3 /hGuKFnV=orsgJQ TORzrrkq (kwF_tp@QN95鋕_Ugǀ >MJYv;1R{-Kf$Z+*+*--ۢ[u0ю18 ;vVAuJ9w,9-PP./Kiٶl6:8KK&mjT\#)g0ŘYm +M|beM*їd#؏{|iqvWIȜ-1>=@R9#B<&F(|#vT54Xv:éUX ۑQбv{vr0~ˠմ/RFg/tJ\r%Cݖ. jk6KD). 8M6gAL"~ID{ֹ:'~I..¬xucQa~>vN>llWViiN!7oLA)̘l_iY+DZ5*Q-: N2OW7Gh4|k J.ˣvL=Y~'6C't]3lXkpwTmsyХA] Nfol;OU'5 @2n8Ue4dllLDxD@ﲲf3 /8FXZS rv%o7¥k$P"YX}\y R8w b6Կɼ/[)Xpfr8vnub͏J^+p?'ٞԖܚlcJC WXі|>}?nqo7g _W/~/_w_w^]7._y7???W_Sǻ_߾/!_?}?ջww_ݿ?|W7ݯ|+owǗoO{ݿ9;O}ûo^~}o?^xۏg}e~O^>O߼|?_<߾|o˻[>囿׿}Y?+?߽s5KB Oٟ7ͻT?w^~ϳ~W}_yrwys/c{ow_]/xWۗ|+߼W߼^y{WwIzf~7 }7t@,o?~O</Xכؿ~5'ͷx~ '/?E_x>_s?~|R'/߾_}yoD%>x~ڍy5O~;wh}G|~WnƧW)>~. 3ӕ̼yħ^?~~yK7_T?7_TƍT%O7_T͗ )|i 7??y6>~f?M)QKLaw bef=w4Fo.j'?~b2O_ /_o*>$\TM'U*j/21n%PT80W:-_sFGI,yODW%ᐥ.[r?[#}"f3 w9JjI uEɑCRݨ!~+1G;/yK-/ڰbyl.^f/"#8K|)+ޜfUj"Iz׬4 o"L@>YpَeBݜ8Wǣ|qFCrwVFJpQ>9&s;TK {R(qK=E<ϜSTKU},ѭ6Qtm6x+Ze]^ f_gcԡSx\ڥ\ XGiw٘t-I:cmk.}2;mKf idJ/,8GUa)zӥ'EJJ^Ö^M} QʈhM`Hx񴲸nTcbvJ %RC!QŭvGϝ{TK^\"yu`U|޺rNy]xöIO=Z//)%xҚ'39n "lC3V1Qي$~*ԣm>pȃ µ_g.ބA)NKk u* UwlI#]Ӷ_M޼{l2'l-%zH'N7W}i+ wD8x~C-jN%%yWʇ,Yd|WsG8e@{vI+`#6᭢v;hnBK-849`m>^~\mq^[\[Lelv,:QkY=NHγxSΉ# ,N7KΞ}YvֱrNR)ۤ+ǛUک)oyʲTY w5eRiR y\n Q?Sja[ڔư/*Ku196f{XIS*OvMv;s< >"=iN`J$·tCa-.)K^3ɵ@CCz~%gFZ5`3v ۫;S>Lt03`Xyy8WȻ!#9+n'nnXN6}#ώs`/_}X56y~PP|7mGEp~uW4աL6rC⃡H6zy}ns+GGpEbuJeY3rCdFUZ*$%,qiš 믥sӲ+^.B,Z?LA> #bށwG"$Ot}T6=H#nJ;ïsYqPM^I>I'c+4#܏oY`wF'U*n)&ԩ/u<#l!8$&?}PFWᬯ̬Xe#Fg߯ET% a KK8ue; xql2*(lw(+Qye7(`Х/H4iVAYJ?b򣠏v4id >?ҥ& X!# wU"yԼsK+/˜G`frl ȉxYE1joU :lzk?<]I{a>cq#s{l9mt| xNN}'&fg wSLrϱR#=*'-.M@E L&_)4ɮ!NJ*~)SWy+SxhxBpx9ŝ\2}r@e;AdA9Qm>)2[>ծv+*.9lGIV:N(R>/w]X8yT/,=%m$٨*EKTG%ںWK {w?qʀ<.7R1pMQ,ej]J2%p$2a8) jgK2`w p3`Ҕ9w/x'-tfZ*cX4/ a9Xrg)Zfr87Mq4 q^¡P x+m+k-qykŵM)Yxant̖(I>zM658$i6yҶD9#vځPEXeC#V cDJsN0bڛ b_IvLqb(A/eAyאy94>`g ' qԙZyYBx -ˎ8rJ@Q C)<{>VNߗYhPG &$Vv v2mC;K]l~R@V;5u*S걔8RkpٜEER Z m:͒Ew].1nѫJQɦtLS ^`ɂdrRupFCA{ 5& v D,gWƩl0l'ϚXO̸ꎼģ>e ˘ ܝ<";3yn1ȃ,öhg9otLvh)\KFc+vڢ%2;9bV=\ {KQ9$Trʾvɜ{Y,ҽ\nD,V901 lKQ3\p$y D4SV:DdfJ9QM;4tq83Btsr K| /U|^lg_FI<3쎼M܈hkKrl d/cK*&\;|l{2]'')H 1v!]RI|\|VAA6yr4'rp,y9_n*EFr/,yW0u>''~&4KƯ8ZtS"dVW]1&1IF_A7V0$ ]v1Sf%pu:<&W攷uK+ޔ@"->-۹  ]!>QQ?C+RE՚lť-%'.ʽ+22$x)v6'IKX"܉W(BU3Nt:@Hd*jW[\M3-Ĩ{yC6SS]o#qo:l&M[y? kMzuC麢VA_Nr<,7NvKѱ9(2ē/4rzJ3{6ҹ&Ur:G803z5Zt췑fxR[:wJ>]kTPDUY2|s٥+lY X$A,\oAk~Вqw)tMacBVyZa"tEtpǔ% Ki()˝xzU$?Ȅ|US[U)HV y295]RIg/6^csٝGe([ 4% U^}XvN&(˚ۺI<),MbXb׏c.d=ENJEZbY_/ѫ @(E5v^S)Nt|ia-~g]82h+gTU-K{Si{3'.ݡH[|=r|8 gxԈ*WdۖM|$E>s"Ip5']*9i$BŦb{,w& tlEe9>I ,fw>$ TU&LA.MrHXޔXiKQ6ҙyשʍ:#x(GZq$extVϠ"4J-)UU;] t8#2H23bAz8V FV&b*wՌ%25 gbw&|C@e`cOCiglʵ|Y4>Znp>p0䯔 9VvVoɫe uAl!0Q]2ve,TLHS8L]>Qr *q8l;\ձd&E5c2ItXCܗbL [LedU3BE1Ea[7½daߓTijj$-7#[;Qoĺu &dzרxn 2J2GtPՍ 1Lk@{:Ed9xTaݝTԵb)WB>KsK#&)92=78i:TX&, a4~@y"%CR?bv5wIYp.6Tb4q*Tq yI%' K["})+bzjո̭2$Z<{K۳9(=9ЏӴxĬl,W:6K D7~[%wv|WYSf.K V擇 hm7)J]I=)m-jDHR"=wWU,cϞ:%NeNE0x`\`ۥ\i=FY@^!NTɊzįFM/2 *x.uKJ8yg ӫ.c_U-;p3/5}o㊢5S \$ vc;zZ (ڭ[nin 4Hg( )8Xqⅻr֜b5`W0X$&L[tܜzƀ7xT #%R߀Eds@,cP*ULn PF':d #Uڗ٬>A4cyuX0noqbbo"/mS];]x6Vc:\uqFnԽ8lHVq3i!r֘ejTdv{A?8 Xr7%Br?%:.2av3Lw\mwij8R =V PG lGG (Y;sn=M~Ri4Wp  n;<BΒ17g.Ar(>Rg)+.%80}V mĥf إ^@Qr;#iu&ήR=ov"1Aط.^QzUCfD~St`)z,&0h7.A#@\,( K8ti/yXCD>8:TʁYY)VT.%N/VR,ECrLgjA4KÓo9.n0D4|2qpw9¤r ~%GV &bU,YpO*$RT J`+9( `^YwŰﶍc\/7 솨  a^گXh8e~cו?fhJVWCE6)(^܂ O0E*Yw.?Vg23MJUtqEb<j=\t]|<yZSy"iy>.w}\ K\Id#07 A4tYnŕLh}EA2>5r1P*`(Sw-TcmZ\;$θ׽\DbvT X&## &YSPp1ϤL9IhYgK8QdE&RB|H{iKlCmAV1Y=m.k2(R p:U`݁1a}|)S?%-oC3ھGONЬr5=c}@Z2bΪlvU&4̈́n=*KHu>D|]F^DjsCf8D_%SLb^00enJx3f"S%')qc΃Hڭ{ޤ=iƞ(.(]œW9T2)*F][JMO18BA]71Nf;rp^AWgt3]ZńoRIyŽaIdnѹjC~_w"x Eؾ^l[C^]IXU(3M$%.XU3]%j@{T)A:ġJ*_.RyKiX[NɂٱdJ1'0|`,*29as1X%>qh>S=Y@,n+֩X )TPs<P3^tllxp'[űZ { hI71R u=PͷO #v~5Kg<$H I-M\mrTJ^Er'y^.fȊu@wosyڣRe#F0u0-X7UȃeRٶc@&rdDELNY^!_x=1cc+-iiwt@QDV^^> ʰ;"Aq2Ue,' sTc&$Mb=9u W5C뽵eńjy*F`De$7&H钕~8oK"X0%9N/[2Q,Kr"^w$BST{n-Jt7zhj`(P]f¥jO&KT|TenɤO~!+vWƕ7uk#F]:!x2E#%~`klEڢdMҬvEGe s9\;?{>pՃLA)vm$*zs] "/KoL-XYK6|Tb^3;7"P}6HkotqL츮Z*G6bnR5-NUjYOu.u|k`NppXȜ+~:uϒx1S]")?q8nl.>CBMv[|; ? 7 ;n9'>uvTmbJNVꞺZ-3zV%]RuMsZ*"Iʗ*5}qr9;n=9|OvW`.JO!_oÆDb/c,& zԣ g䯃nwE~p !(v벁~ߕ,iVΔ< ,m®@ݨ31eᖰs> "sZk7^geAΪm e\"Luf۴`w,yҌ9zaPtKA 86USݸ:$sL!$Sr <ֵ%aM/ D{osh)-f`aYX\N XuB0m6E{C|&9TFhxO?|8r{@ ɬ] Ťzx\lʑ8ٸICY#ۦ LLp:.MdzXҖT%Ҋ mSFSE%=Υtx9wӒ}*wh;u Q +%eC1R=YXJ%#yON(`J^6g_딗Cz|*a7@ B.i:&D gmu3as•m`vWz1R&3>;89@&<8-L_/QĎ4d'vlp9/zKr0forhb&S rAW[EB񺄨8L_;/~lf|Q>rk5ޖPP4j S0 ָ8_h7X`$Xa% BwgގpL@8%p!x̟q%|Pq.3)9*~.)9J ԵӁCdO?ZK͇:^ \sc6q3gj#Aq#cpb͹C` n!Ǣ0xrJk& d>Q;(uS7}U0h,HU`ŭ*KQaXTu2"QͲ fU@K`Y ^$mk:9F5aG-}avK.He(qL@s褱—m$^JWb%GCT #w_ݚi"_+:L϶tf{;Qm䔮Wc H 5&BD_XG)Z"h\8f' Zƹk36fv-c2 XCjUFAce-hf[V?o*fGƒu֣X-sbO,[6ېivu 5{xMKramb3œΚۥ ,@xJC٢`׍h 8ǯLtX0j*MX[-FS{c3h(R:ZyӊtF\@6ZPet0us* NQs8<* Y357J"BV#5OXTKN1{]ܬSuJZ}7 1?TU%2e^,EEbjԲ-><بmUN<pl'Hsߪ{^( ${+>=%CLʳc)砱( ixL-\oEX ߻fկwrcW20 1b8{N3L<(qlJ]N3W&'"se;c' &qVN[lqT׵mž6<&0:ߊ}KdP VlnaU$m%QyKksy茊L;wP6q!jqx<-nT\5UX)O>@MMЮ2h$Qx3D]ME$n Xm 1ɄŸW&>OGEA>D[ "7kiQnpUGOֳ:"q'Kαe0U&簨.Twb#O *ee'"A&DMklvʃߩjdH;*fʮ:0Xk cFN5o v`/_9˥hTX JŐЂ4čv9&cI;1 He3@NGKuw M&g-#6fZ=umB__͂kcamĔ׮2ޫ6<*7V~#>"fIO 5;w5n,.Zi¸+TpˠXZhPZ宍km,kVw+JWٹBzynܡz&3z͎*;5=m,?IlCk?Eqi]gǥy@G poa1D+M9E@~i[P&6Z{T\4窟`PYQpR8+\)-vq X]!WJM?T !G;@Ǹ^W۞S-6C%%/_אW3%Rt` 'ߪw_6sx3O Q]r>@[Exq%-w+ϊ+P#MkcIW5qUc% z2^z'jb:L%Cpp2J&hr+p6:!bn 2Vgk(A:K>p>g' 8CԄwu0%曽,r<4NѱLV>#ؕ=rŶM{Y]RㄅaEӱ. fI5ĽI\|d.>J :nsffsL)Jn ˖0 L&a!+KYTd6Leն2숾)(\ۮ6jY4@izL}'a}# A=xTS So-(vu^K rKysTCK!= ʄ5C5/!cjfZw:7w4a%JE%juʒr& [_XzSC[Ogɵ7Ǖ8aVwITNn|$);L8if}C ueN Lv9%pjȡ>qTTe .vVwy ϭxCGcr,EQ{&(H9b'sN8@]鑎e2tjO ٚ,6*J@rk#qFS"c6BiR f9bG[RO(9 dpc,'LTw;73&i6l|ZBUIC*pUǗGSBr&!Q9Kߍ&ѷ4g5K |8eIHbK;.~Z&n!JtfʰLKޔu8rc iJڂ&4`JgߏiT?O-8KH86brtp[=Ζf:?䖭YKN疢Z!vl(ibSGǛDɵ>*W;)heo,;撍1$yl,[l׎-4sYTO7a2&\͋@0tlX$؆SiM*;.+ܛP@x#n%c)_&p_ E,E0P Kmi> Z _j}1F:[(,t.І!B傶<Ŭ  rv*V:to?QjLCസ8m ={AAd@kIg7XT .!̲ ۗ L˪YjATw&'ھ`,8{|fZ<W`7yPʼn)6aWlv7[h';< Fؿ"id:U䀋$H fv|cjGzGuXgmc#3c%8 /,w:JbN֨[$bu񧭣x9l@}$fc% DVv!er 4e?-V:YV[xNZXJl ^Yr`I15@+pi'-^/l2+9.?@bK/?-WUܚ=')EnD$p?$ު:b2–_iEʂ 6F<xW E3?upH >J(+Z6q5U:F xcˑs;fx"WQBR]Fu9S^&ڔ.b'7՜_u)WM@16I8Ձimv@^=ir:F>yY!,5lɖʤmeMLy]b{cH~yb{Ƿ-I@T,"1R)穽ź<8]N6Hܚ< ׭pa13f~MN66*6-fgθM';q?N93 -J`DiO vO;NLQґ WDmHu+0ΩQt&O oiBV@έ߸Aѣ5uvz|pj0Ё+t';{d%8 C0v >!؅ԥwknC[pBʍJOXޠc{-I]!K{5\sr0gYd] Xij>yv;4.wXX^do5GvP)qwRoheCPw: \)g)Il$ۖϖۜ 8L aeͫE( *ng}@0Abe:-K1[Oa1)\Pʕ;*`'g(xW]%zWQ KUv72 O.` avCV<Ѿ9F&]1돴‰>u +Kxwc1@̀6;,wrDe,4LX(~V;\/X$Kk Tq${l:pq|7K=sWp(/Vb B-9$&vYϗM`G`&!e l_a+Vd{K}E{8.R68X+rNZy^BanjJnp$ٹlp g=рV8WY](զv7Y 쬔$3o|ݙXx9š HO-Q]2E(e,M'ufD ܯb~R;qoĭYJ3n+* EK:x\AZ-+cW[]5ŇicEK /d4 @ך[=G<]te|NJ7~{ZpQL%ɩ*-a]⮻9&]_C7j 4}Γ/qaBqD'?rBdG:/cI3M.s# n;b$JFcβ #_D( F0-0[9ɆqLٶ&]!ͶM"O<'{Bd{ X7g8ŢxC~ rc)EQv2ݜ6Q (`RyU$&^W#AV[%QE 6[<vщ{s'kcg#9ec7ʨte)Zlw.4[yD8955:t~ZXㄪ8rZ@03.'g&|~lb mZfiK?o4"Y.3Dߍ l <\lb& ]T2~Gv2n@cqœOXw<҉¨iO |X > zĴJqBds:Eu7`_ݏ:bK++_=`#K$tǞw! MP%3+@J\<qmS?|:L#_RŔIz峩"V6( eCZlȗn&g(~5(u@K48&$6 M HZʛY* *1zUYN>[pӡȋ˜HL6P+'s6TbܦY]#p3/ @0wT[Ivy w xNޣNDr(;a֥bfw̿^[JjMV=nGy֗o%^d[%#^s)ö,+fj)[Zz SGYX{ plJS r Jn7™NzyH1҉OGF9Z{ڇv}dYC@x>w[C]_6ȁ9q X7}ro;WOZP<"2 %]L<_ <L( r8h#ґZ'Qa6|׸qDID:=e;vgTg"ScϢC{q5MȝȇչxA Qu Y q@ XeV0t3G!紃ZMGF ZqEf ^pkrYolN;~l~Z .{VW|VZg>6duzJ}XpYD~JbGCަzI&|^%M < d vEIIX8 UK缈A6)",n9V+Ʀhyd" g8( aT{5}ʠi.ԑ,P@ 6zHA?5VvqJ] ZoY5u)  }=+'@S<<$fRJ^G]/y*6Ų-8'e͗,Y/gz( ұ@.N,AѯYUMbFNwod>;GXKix-Qc7(}ӣm"taq=M$L0qX SMx4rHd,$Nn$kT(ܠǪ1lAQkCXim4hyM!&65m'p s6|orv`PJzqj\vےbH+胨a{bǚB>b=<_ʅ[g_S Pu Zy9'd`P5ޅ< Qas}uC!X3,UI,*ZVg|xI{=a{udVS5hcp;Yͳ&g[ @i/Ϥ-5fj' 4ƾ9KJ/ rhTpSB>Me$$Zdr`s_0V{{ tKAV! ˿p"5NRDgڬeդyG)&*`X߭ 7HhJ,DK{'$dPljv`v^J#)ۜlNBj2ޘ!a999fXUDh+zpr8W\_20#qnށE|*asb4FpR)dejLv-c̮֘­-& R^#7Uw %6Q f(V`5N ̅y>dN6Uv4fj,M%iq- 6lh_aْ҆ԑKPV&ǰ@>_t|X00WGQ]6Û@@1$laCmk-*;\)(MmW۱c2/'Fd%;6T8ξZy>̎8*z +v훭tKk^D}*S vײM !:XǭL OQP%l}(DmD #IzR~L6˽}I7%D ';WE8j!S=%fj}PyC*$ lvtN8x ǁ8`+ sfL`LiK8+`@r&l-[>&4,i%DN d\t3^7#QwJ.L, 26amZz Δ*Or0S1 gO҄?l{y'l ˭ ZhCh ,ƛf.eJM}چ6{>{sI3K[iq{r[yJZޗbmI9GI'\t7k2c/s[)L*oQ$$si1SNG~TQO=/X+Z\M[::1TT>TK8ntO2cr\ui݌VT%kE&ጓlwJ4G֙wT c=]8$>p*!CJnIi>Fx~E{(߲,V䥆Rb"+7{e(mѴp̫3[tXVl/3V&x2/ :vZ&MnafشKT}?6UpxI kuDQЪe+b2.JzF6B*7'.pI!W<׼M_2o3gnxV+J2ݞTL6w+%K=LzUc|C&T$qʼn orN}!Y4ڔ;R伧G@K'SZ1ym %f~ d};2D)p(q.!091<*^6^7CGIYNGd'zG(P{8Uiai`tFpL56W,Y:fuYZ]FE(u`+UFxqpzMxDRrIm+/) X!e}lpY0ǧ//X:kgx:\9oER4s>spHX>+xSg̓R6ea8Y#G+=dd"e`Q [4kGb#m{X sjZ[ҿrwQ[D$ WaM^@cr!67=;Mhbz$m;-] q"}y\?Nxʠ_DږC 6=X_w*Nbs;/_=كskfK3Dc@],+"YN,७mq@:M6!-`4 7l浪2a6 {a.JTY$5uq [۾U%s")p<TgiO:rXCmEBAC>6C.<'< c|t5)pRZtm,(6 \2|Md z̈p~|jcgp*;a32MAQ_N㾧ώTγ5"^zJM@e(Z\z w/wJZo[4hFE!u/:RQJ%s{q1ʫg6F}v4 !+`eC X-V>X;;س\1'lI=7vCZӖ(3}29PYP~/-> 7 Lb3mʣ=NaQwy7΂OrȘ֫Y:55ǰQ5k!?O-&y#B;??!"ӈ7ٜ%RW}w[=laƨy ,'hXHQ( Ǵ|Fhϛ#^.ވ޲n 68U/ԓ$jcc8;=]&\.\V^$G똮'N JqvZNdPCƙStFn‰K 2Jhf.u]bk b~v;-kb`:hTVlz8HX6Dg0 \+kYσ;3l$MKrq0;wJ K:K1KIǑKCy碖bwS!4 RT8WzH͗(s鞫ɱwƈCyIT)}ɩ5]:+L QGF9xb|eM8 kt/I3o6a@^ZK]><q\_YZL|~vN z#\sEt$nr- UG?|ܶ/w?o>|wobwOz*ſ/b~~yÇO]xwV}~:'?n~>oxwۗ~ݻ}o_C~wǏz毶-w|wY|ן_͏?ywj=~s~黏x˯' Osß?~bݏ?|~y?|y}Ï_?|ݿǗw˷>||7ᇯ?o|ϟ[O7t}u|uF~}]*ϟaUy_}w/I>c1ۻ_w_һ?O}oo~?}xu}߽xO?| ~{}G߿}͛O:x ?7ͧ~?釗?}۟/|Eٿ|o wY|~Oob[?]w痟"ocgwx9?Yoͯ>~7~{<|Ƽ'w?>|W,/|x̾>W L??/f,?9<z"cq4?{Y(I ~~SLG0?;)gKON_:qROq9x~Vɿ_~Zz^x߽|^+~ϛ~}r`y߽Ǘ_nwÞ>ٽ&eo_^%>>a]~7//?~~s/o~G_Wx{|~{}V\W/?Y£~태ۛ\퇟~ޒo/_`z_'z}&bg_+z}=κ+W<7_0W<o^Y+߾~ųWc;~g_^YW<߿~ųW<xg__YW<zg^-1~凟ԯO?z>|?=׏`!k?Ukï^~> oҫK<xķG{co>z}٨W{_ti|SmˍK/y|SK|S'S͗<|S7_q3Q7:<?|͛-9D}ԟ6o2P_wp1 w4s3uz?~B3B?}߿|mg2_g: +tڟ9$i~<6ݶw<XsY8ƶt{Ґ|%y)"3g D߮]vu`}{BaQ [kjn4Z%14Rg3KOB3;W|ʡ)%>FRN}feUrޮbq*sұYDGM~+U}i 9c ?TfqmUjlXRGۮKK{}9Xm?''˖_,80rӪpJ[x{!&<{Qy;| 'grej-@s(qBVҗaC2;5%np/8<&)VcwqׄfoxYe{| @>s笌5KJ %:t[-^ޠv0]KYզSNJ\<O8gQ;XZre!x6X)j;Ě/&6L?.30;@%m6⤃LʆEi#gs>E`XlrenCGz|iՐdTJ)%pқ3`UzpN;kǐgq7]dGԤUfF;SzSzكfC?p9( !YNV(#8p, o2Iٝd1ng9Pl%ڲ[ `l2ԔS9Ko hsreN :PSX\xP#ޝsw)Cǚ-u80ᜆCAt p̆vTb 1@qxk:XY21{v eNw--pΞ3@4Q s^c<`xx@1oueDҺH-IV\T'[܄;6KzUa8@86֩  @,?(H(qLV\0ߖ"㔴*˭0XB'ew-;3[:Gy udiZ- ! P#PVF=}z.QM*իCL>QO&|+'?p0.=P%ODrؚfյ%uv. bx8l{rdy'Mx4p1K|RP-.2o[vJbGűw,h?c>K^/iR>~McR9L=ϝ]4ߵd1'8Вr{>)LJ'MZרe%&ծk:Y{:o` i$µٶ?6W™1\n' @ K]'^9d/}V)\ GQZsb v?]LZuq2u- ]T^J&> ڪB@3}"}1bV?SL2N[b_:ƱiK?; );皤X4'*<kם7bo2Z1;=S˱bx8qMNh sk=ζ% 47Ľ&(Nhfg5nO(#Np;R m?~*#,̛@y'(jp'_0|̬B!OB!<إB'[lw`UA;dN!&a:9Ta*ߊ%3KYq^d *:Fh !ЅI炈|>Q.?hUM-Ը45$%)Jaή4*aA s əa}䊨 ȺNT joJ4ES> fǞQoنtT\-pѪC3Y5 G}3F]}Gl {")Ж Ta¤!h*:Êݠ۴7{D14fݔ!gchI0j[ x^e*jOxK4JcZ" ':JD*8D*lN]ʋU_ 6l=+ ~嬫})E94`w134ClބlZ)]KS)tH)ͶT2mjZ8+Tɘմ@6.a tHhA2  Cu-AI68U|BKeWb `ی 1`wWSp/q+B4ZFS.^`MZ].η,p]JTC~ pᪧUqntr`f<|#xx G܀Aplh sŸZU3vq"ڛ Y71cr%9fbFG 6]+z?l%(*hԮ2!"u s7 σszѦ~A NX,e^ q8Ά{HI< U6l|8ۥЁ?29T+$ϳ(Ϙ"O#zaI4X"EQAX S{n8^w Gn4O6nZSoůG&"ڻVfv&k2 = =Ź;p+/C6Z`gcE' 7Eۉ5X"s" <@`!i8aGY\FX bJIHy_YAJ?AXa\n@r2=[VXl5JRmbP=NKu PrD]"JpR Dsf3&o5-HY+<98UtvTPNnP بZI/GA7;Lfp$^߽1n/98Uu2Ia%@$@bx[7LjUd8WٕlG&T Uk4BmOz5M˛?k2wl 2A\晠Ɂg.n4@)*vPh9rBiJAHYM`༳ Y#$nUKdm"{`Mx'57evH27Y@ V8&/-&% *S ,S¢ Ol!nnufٮy&Jٴ)xdY>>^Kz 4}qXY Q jdaI +t/'a!dØ5gMpVNNفkHޫjDz,ro&dj&Ʀ#(!_S˨*8T $ *Ѷ9%W_ '8lg4wy)Ƽ\tNωdپdSrҳmA+ERG{~VC˸y_Q;rea_nR5<z@fW<3;9ou:d)ϞYd$)ub.1)im# .vf܀OB9L #4PCFOЏ5zLvAܖ$˗jb/_Eڧ䨄ordKFPҚ8ѹ'_f Yv5 :1%FJ_26R)IH@o ͞ [;ʷ=AT;ؕO_ClsDK&,Υ t:y"̀d񬦦9"?8wsCBW_IyyIer6 Vy4s>J-p00Cpd3r,.lI(*sDF&Ꙑ58*x+|.3rT|⤁t+ag 5J+-g{vIo/p'$hꌯ$Ē;/;@(u9 e9 ' =)`ЍnLx( TiT dN;RdGwm]y5.5DTEQM1k#N U\ SgP u[3oBfTYhT,R( ? 'T|ڛ [͊tpse[SO\|ɥ,-Pغm~L}M:װ+n,p+G* +v"˜jYT ˵ ,$Uர6?4o_O.DRù1JxL歨q3z4 r*RdZ[nSK%TG^)RT#T׮%ܞJVl+s<>nveB & ţ>[Ǹu3I RiPJ;iqBwq!mE@S"2T eyy%~ G9? N|su[Ely"Pqw #KxͿ Khb}.|,$^1/tܪ7*:6yf%aTvIUp05$QeNR/\gz+ζ%4fo >)?z(J)unj,jUU(AMS34}5|V$O0:۳aԡdӡn"T[^|`U`!)bXyAؒΧIޱ )t)M$ Mq }{KRzp[,P;OSo*'iob|3XxH 1Iݡ.Ӷc_} cRTMdv ƻCL1hƂ`Ih=]8dFɚ\ ㅹQmeE4q t>}-]pszs~n͢}"=} 4uđRokmRS!v}_ hp-,^gyiN*S$3?{I]gs{ Djjf&fu ᙈf\$(|>uIIJ 8]T^kk)RcAGd'A j'BE{Җ]9O<2Hmd΋ `3T$k{[ᯁhbO. j<$鲭 QFץ[h*[UJ0x'6~_$1ULn%j dJeHA""˒u6 ޼N4"v.iWuC=oW>Q qPiڼ'IaIONl/߆ s 6<&:T,ߧ肋F@h\j `hP\x132`w\bGZrD.(0s:&H=!7Q7cA}j' +4엧 ~h懱[<1#AHK`ǣ,rgKX{Վm kJGF>-ۚl*&h֮ig@؆͏T͛m$f')q5srkRRm) /O]@=!_x[u$:@xV\ -I~56D6-pF6=*tsaG-I'ÊVQ:;ۚ~Ux܇Nk<+ bT" a㏶NUXsZt<='Eqrh@ɴ#6]تZuZG3`EY䛯mJa,ol6jБ5t5hmSr< c!Ƴ쯥,mn{=Ѷ;*ij1r~pgWJX~l  6u;=,~!RF"$,N֖؁p8 \%yK4yh?6Y0vFB `$GVf<^"6t0nbڭ6kj:i8]ewe {NhVȡ3.&QL]n CsXu :Z==`OLvjj˰jnTrYAESQؚGDpLڴ&pV:!c\mOģ+j;$pld-s"/G Mr͛:6l%Fk( &5 M3ܰL2WvrA rɦ$$2`HϦ2iLQ=b2!A{jmf՘-aiNvqGX-я~y!y=;;HXNՙuEe i1|48~_ <};rN.ex/@u^vOqE;p 2t\f{u]ŧQ W')c ne3׳/O``mUu|-SۺEqeP`GhX"wYoLWT6Y:TiJYy N{mo}tzĦv=t}X`ЀH[{#SG'q60+"Z5/t}ks0z5,8zzؠ р+nWWH]SV(~8'<0N7"(PǶbg UG@=A/֛8wgUR*Rp/k.N ([U`">kZWtL/=I;Ɨx.ٴZm?"pI[ؿ1k :qm[ ?YL-휷ސ{節-zjچDD34sUOd'&)a(:lSis(2_'όk+:G[|m^Jԧ~j6@vyG݁5ksXOCɾ i;Ҳ9c"'5[̀z)<]R[Y̯ݢ2VfnJVyλҝoɞK=wedͥ)[RO$|`Zo-C4,=R/xVڊF,NI:qDb5lw,iaXe#f[vîl޳8ʾT}k1H`^ϖxDd֛Uw4c`tkuR_uv`.!WrvZhsJJj(U^so>њ* =.oXgUu]` Nru%㨉Inѩ޲P872~ٲd܋xXs8|#oI%䘄uM6sIbW6g3/`%&jtlkj:<3iD3b鲢{Wm *\T;n#vc-/w=1,Z'uф0;d"1_|[2ԃpA'8_3԰I|kB;_u>Sgչ7}{L&[ϥ2B]ձ^irU5]cEg6k ݘhXKgvmLFu-F9kHʹ Jg@I6T=T9l{<lb?8^mSMINߵ:<C I/lWȎ}V5u$6-،X//tsm@bl$ =ҵz; =^[ b6wr<3ub$7vC>!AZܽϜ뚴\H(L"h\d wFk^bb;8aA?3d.n4+WCZB/w{[Eu?K # ~yu*]?C{TۭH+m!b;eqvb }}!({%:]w!F0w˖R+9?195i|?QgO!B`7bx7eTUXv"z<{ >N䚤DתiMܰnw8(8#hh^C4y\Y¼z`W `OB؍ꤎuݗ L4z~(|#s١9EBD.gaglx `+^.`&:NF>18/izhw#Ni 4)R9傭# F30;Zd]C&^X~5=kKTOig`A.&^T:ۍ^5?"@S1c,ꀙt:k/<<.*trlv{R`EX-~R g5y"M>lQ& G$!3SOW5 h{; 8%"ɌPjsWh!_'ЦԚl"kȰ~ E@yGG ֡4$z?/ XM^Z(\npjxNB\fFys9V]#B@%p&6vSnmFN;L{]>UV$:ws+,#k-8ZJ\J83{D6PU0[v=>:+Ԓ H]_ =`7#vpXVS?_mT!tՀԻl_%8-/]&IV//y 1e;v>B:ѐuF>MVE4P9x2JT$v{jv[$)<Z=q>X|@A-G9ӡ&*/C᫨$ ޚxKcdoNnpõ N,*p6MO!YgX I+ݷr8H!4TW`TMO6 ptBmDSmPJx;dM<mBGKUS :X1;ĽR/0IA[kD9$r&2-myd: ew`,wQ;4 lpS]XD);;= 6OG9ў)vW1PW?#mtzv>jT#rޯٶ{&S8#CرXWWd8v<`eTj3T'ׁٙ`W%:\(\ɿ ͰJ#+{ꋍx ~}DyTIyQRl]mMCatě=r*$U1ַQtֆHuU<9}2Fc#[}[ӲXyL>T$Q CF.lnf(=k;.ҜԸ脛r.v,$b9x93eWG7 Jj[<ەމG^T6([K,{/8tX#LwVvtO'W, \F0- [B#}@m<iWkӾ歄m6|gTe,XjN۸MY3zaWb֜+OA(˒W 7)&Hlm Ԡni>;Y6*gYீj*'iMZ7!ɀ[V5GީD U\$\n f};7lWUB^A]`ڡ`UKՕcAh<,Kݨ,~k$m$ǣuFt_d?3cd䣫F$f$8X!\"g"[u63T}yZeH^>'0;eݶ7?^G-6unwt,F 7+َ)0pV>. uT Bf@Jʺr*Nٽ틬Z7Mv}]m\=[!ͨw%K(Tg߈\!,v`qli6O.$HdHڦR'9 +UA$TA6ukm3^f#z-pq7]: j%!\ :GW| s98t<>\`#s&K+u(=#͡Sa+AJuNd]-.5wg=چ(.>n$tӶD\:_ZOw CQhEW =lBF<!dc5mVbv=a!Iv O e\ˡM!YũEHK+y>@uZ8ݱ(z_v)Tb-7F!!^k\Re?>{ 5dGO\,bC'jOjǻ;xuBwT`RG> VdٯnE2az87B'_uIM?\n!Lf7Sq' ЩccD=X{/ˇ 'x?$DmN{ {Cj=y(Yw6ruPkρֶ'O?6xt:c͍^NYE%ꍉ\cݰ,'{dQPvLib[/O[(m<0g7z!\xfp8AIRջ)k!YfU; 1 ګzc5?j OkUtѬ͚eY<ϩֱqxEZQTE#%@!-9Ud3˶w- )"];TP.6&ge(C꿷ALf{e+~C~1`7uՊSFq`Ȅ}Ň]ĎmQMߋ~(ʬ ׁؒz#^QGpavzLgJHl&,ǘ"YFU!+v] R krs.1+({Rpμ=hK(ȨHXʄX-~lЯf' TeIqI79,V;" 3y1E$WFbmO\O׎58v4P9j^gZx=}އc#:AզRdNt/[zoAJ咧vs{>8AvwӠ<0w-4C]_a(0 b3=@w3#pl9~CCfЙg:ъKTRr4>V.[rHY"Z/ Qͳ0(j#K2 D*Enr-lW3pLTl6|:'dˣV%S2;2URỦ,gV=f2aa^T?bPl\A:])3OiWYR<="iz37)c{ɩeG)QL#Yy;at6v~! ^{hsLO\ 'U<'mdS(c(+A[-2ZJ-Z1Jԯ{$C RTT2Bʟ1yKs ?VPdKN\0Ӆ+@SfY>QO[mf^ sV~/zL04{+=k7ux1*Le7n5ɻ.JBv*z)Eu!{ hݦ R KM892=UЋMlߪ(8jJaC$,JZ*Ha_F+u€yT)s)0vXIެEfpw5%c5moyL 굃Sbh1UB;O =v3AtzU0߇%@ԥPS <Bںp,j{xo,q;́͞i 兂TBTdU>p ^kJ;%@c{ Z-=P2v`Ov؈,VK#9|e!k8 $^B$\bӜjڢ]u~mNΫ0tRx+?r&pE9oӃW;ʑ&`p[D!pƼmuN4y A8l֝gŏL-yJl[`a>8UQh5[ud;(XN˄ |Ⱦ4S6"zጴ--+0Ӊ& [e^݂-LyyJAӱ 問g< 4`{ݰkqh@h;Aod|E|N[q !>ܤtGxR+ Y =Ϣib%}hA4ܳ|T= _:?|BbM+q8FmG Xq['uF܆"3 锬4>7¨T4]6y auB(ԁ]UO [Iw'Yݔ ͑X۹jn h`T=v+,IikԪC%/2Aˡ#"j$&Y[vxD@# BV(ZKnZQ <dUx⩢azJe?@M绺݉% у cDѺh| ȥNJtc`R4>r i=gS@-0Ҹֹv.xT&dk4nN>bE fr ˡYg)mG;.]s:H)\Lr=K Ws\#J[*Iksˠl坛-KP3G@i-\Փ &H5$>\ ;H<]t=f)_BB$g-!Ik rk 98ybq}hQǴYt@ U=k0E,dfd }v4EUw} ZLyujfY3Nę`: J| 鈭IaSpC7=_=ߟ=(Ey+sX]{'Q夒DLW YU<8v9 ƭLlZYw |v'rj"BxE~p+O%8tL҆vCi+h|%e]BwcaKg+7CRVf,)ݳP`7e'VVR`;;Nl˖0~f/E&9ӎlVU@c'yP[,ɢ/1!9;Rzxi`5$g2Cs⽌k|@@ĤJ{s+,;jVr{n'mu5G/?XV#涂~iKyCO.U1PLE{S18yW!Xg肪kI+ 4dezheA*nŻ=Vm6Gۿqxd-n)c'jPvU+*5a,Op aw^Qm\OebI)dmT3$ϖe̗/yRNq uꭷ5"XSjɒ،ZZ@sIUL|\MOPgayWg K$L^+[чHЖVZ!;U'vLSQܦWwq 7Xx֏}iiV=Քy,NM4(b}6M0X*{h U:K56y"UoܰK5ꠉ;4Ia wF2ܨt̛Y#" Mu::e)q4nQ7M<`w< KusT]`Bj.̵Ia[QOkG8-= хܡOUszj\De+D]>c$Y@pk<0T+*۾٪Gkl\(iB 6_;c< *R-&bUU}.Ϳji#Ԝ@E5kPƈ#tbFiJx턚.D ul=9ZNz.*gؔY<_@Wekf;d^_TJճmP(~*n*0jdh& FOaP1,6;=pϗ#OUWL&T JCynᩇNq*58ۋ,@*μ2fR~5G $av9f8HձYN]e)~V;r{:3:m5{ :xze%A  ؅"Gb*~VT\ S'9?|ǯ~?g6fWoC+HşO~"?}O_/?r__??okPӷ_Ç=W}?~ǟ>}w8>|?{W?o??\7?>|ǯGG ~w~~X_}w?}㧋|_篾oC3}[o۟}7|%<}׺_}~p~u5Oorx?W_ͷ?C_W8X@|uo÷?|?|G.WÏ?+x$ï'|ӷ_差o7_}|ïoï~~oc9}f_|O/?Oz__+\̯ן'o~O|wyoŷ쯿{\ȕ׿1'p_t|~VOn/w___̿+;\~\7~~' ]EwɒKXp/Njӥ-OVY"\c/Xv{OVW?^[1ҊOVVha*Ⲋ/VU|b5/ubE]OtqĴ}9_~ߛ~/.wᄐǟ]|=7/X~O㯿no>{w|$qGw} gO?~7__?u?}'\?p ߑk%O/ͥ/]w7?/uϿN3h?z}|yf+.}K篸ϋ>eWbZZ篸7Zg:>ŵ_q-+?|kkZ_q-!k~jO*?\~N_׿}MPׯ&7Ags]&W_$ A_mŗ\d/R~/5/䢾H('W9(_rUK_rU?}/_rU/E/?|%W}o~2Po￸6~D'x$c~ۯ [۟<@yn˩_[_e?~{-urʭU$PBW5sw4Vkn\=GȻDwMge6G|Ndpxݞ9Χ\wRߧ{_i<Su1OrlMkئm3^̚(V&vb.=ҷNWrftࣨ>~<emOn>Ծy^߶gNZϫ{ KyPc*]]f3TޞcY)[]T"cEyk֦'wTj y]5":A|gS~ .Q^q\DfW%h;8"jT﹧er2sf7O)ꞔ=Wj3ߑqҙAkԞ{~56mjO6 ;ՓvUJ,^UySqmأC{eū>E=X4XT 6p˶c*û}$;4m#tJZ#{ڔD=={@zRҥI(ʺS*pޫ{]HLfsGmfbm]Nly|Gu7D#7ʅR uqf8JIv\% X_'=`yU;80Q%;ݖW_,aEt%(ʝ}9 y2ͩ,om:N8Cp^Q&k1;9`ͱ؛? Y%Wwќy{-klYMg Gy\SIzU^I]~5MM#(Aٻ|S)WgNㅢYXK3erI_ėuݔ+ol7_0ls> nj<^ƚ{Ni'X&NĥH[ TvTb$<>5uX6r&_ҩֻFqV7B|:;Ljz4JRƳrĺ

;_FP k%s]<˶bgOܭK!_T,*kʲe?窼\܃Shr*] rT;zr3jƯ"xxW7єWnQ۔U-ma̶U{kZ5bݣɎ`نpjmj4au]jɂe}$0]$\Ra:]}⽵sb/–acxRiRӋjz⻵޲X٠syf ) D򪇝I]ǺsHWKTi=e{aQ6TK|4.z8D ',)4Lkms-t?s<{@ٻȂ]b`# pI݆z.Ve!jZ'T{zJHy@y* ~p m,mr t4Q9^݀O(1~ Kǻ- A&>dekȣ<N9S>'Miq}&eGms^WzE/b=鼻aUą>q>l,:x R6m*Z"GI;bgTWhڻ?: AYvu]n6.v!ؚ o[۷VP,lg=5Sbu8wʰs5dl[|?u=UJ-hV͐h%B͕M@*vKADO9VNuUu6{tWLQ]X >K .ZLPW`ɒc ZS֗=NUYcXUrt# :le}9[pR%:l]e/:Qak x|f?&UY[h;mT6ac;|=.PisAmywVV;őNE*vW&7ѓ}$!֮c1ac`vݼa_&UYa@9YpԦHLqQ8FO*T),<mYz4J8BIì؂(Ce4XQ!$p W4S mFkͻ.lӕF A|f]lsLU/@+&zjZ&ydk6Z9(6[vѡ/Xeۤ\vyr rtZy ??KPBSS>*_!ըέꥮG3OŨ`s(En4g": ž*skHÚ N!F`9dd& 5/BY\5Ϧ)^i8n"`u?r(n/7$ŎM&;4)3ʩ[q^. GYqx8$ c y3L aZl7*[SY8[dyY'=,"r@| C~}o_Ťr:.qZq3Y5Q ~8ݤߞ *?ᤳNXkrmEŻOI|:M.e(ac*{ ؾĠS/zxECRQ9t@V. W. h,@~d5T -p/ew"imeAA^8TԦO>d(gzC)Tˇ|6sNl- út0$ԔC2Rph H*$PSsS00M*_%>S8<$ x& ;c4qyvݮ5:8ӌ !^OLvxj m8m/.@DQig+-qAO5VTm2Df|.JQA=:"N 1,[Q9(A < sN'c/>9.u!-*J rb7As=\{%Pʱjk.Q ~CPRN#89Տ/-Tjl[ ,0 ^MUO@|ћQd&Z-Uȅ+_K7>D5^`Nk#"uyv(roM-mj(GI\gVX;IZvd(ˏh_ț0T n{BS֟'RNoFWa9`"tؖo`^, m׍urڛ9x:9݇"\d@c;\7'f_%]:0 ۧ٥dδSy6'R&;acFŬ\")%d6=ZO;R'`RTRbO>-Y i3RnΝ(Jn5eUVaW|E`B)}j}jR:z%8ouF6]vC]Ueɭ͍7 hc"bnm]=l9C-@#c՚MS =BP0&qP.E_إVG1{L9>ó7yVWQK7+4am:)m` !_PG؋=AedaOۿ.BXYqޮ[\^ 2< ƏZi; k) ^H#` "k=v>z=>G{ x{~cPCp)PA66;zF.n m.bn]HAuku$٧u,&(^6JZ+ć ա.~lY.!3±Faz%x5vN [Pn`1bNJ-XhH|im릂4kYz#UsAyZ%k68 E]^:mNNQRU|^ $-oa' Ƞ*sm 4aa9ǖ(ǶI?&ވ#{BF$ҍ=̊v>LFأ<ԕv[]x=cĚȵVtln` $ܼtA-*9i $`ڿ[[tcYvǣE߫c3S*mέjcPiM6:[܉c>mep۔pš$;^7O?$=ܣj"#&Y?aW,(i-ahF| EۜS(JBl7糲tnw4@yt-l̚6WO D<iڹQVI4?O~ *z/pt k%%DNmZ#8m}YFf>&3HԶEpNȥе4]cmEvlX=*'8 )^+H5~d倂gWn*Qs;rClr6a>_gWhW{Qa˨G_RLap~0:4˙ A+ @68gVų+DV\%GپG $zkuN"`O2@?fg|¦ V9qc$[lKNIAN61ݭ"*2z$g 6CGަR*a%)b^IQs~]Rr}Ķ޽ڃzC'!KȯRDyNle+:l_شk_sw%A` iï; $]гJ>UT$UyaL:XL"4e<XKߌgidGJpR,DR`' ^ =<@" 7m6)94,Vt[W{.h8 }nel%w݆=+Dd5lc$,̣88fl. *R=F]Ndyl&<bL G_Vy,k("-Y%@C[UN*l]I+DwP7=p~[.uQM6/E.Lb#{&Gx3M92)#DH,DT#OS#n C|kf >:St vl,{\0{\qH)}n(2>`!ʩQ(ItyZ81z4RJ}lښq ➬V1Φ'G_h^o}ަ.`ofmԺeEǸ5:,o]cþ[sHuDed.F_[YpE炶j^p<ȰUx|A="my2&\( kӶAqXpV\չ,COٿYmX+Fr)\r+t~g8T|~g6E0,ij NASAWkq4u Mu€(Y\ҰXE{&4::{Z$LŸ%"=OJJ_Cp)Q u1qCC_ X!xmykVҭ=Q4ǕA}.6٭=9[X:oH=.U ^l VHl$'O Eg}j(P;D3*X'afWoWX1V}laզ=D5#lfTY`QxtۀUXM۫j&\gЬ&qA(/_5P(KuZ^>%Xz,yP~e:sK~t)(0w!R4#{^VeV㯭%(cn*_F.9۹w+4 9[(mV^*gZ 0nf5eC#Q N{s;+򩘋MW, ggQyK[ŝHϡE~mcTT%åOK?s:mgߖcA8SJf;"(Q[:jP`ioMڧ2ܦqyL|Go;BkTdׁf*y-L5p,5.Ut1:e iCݚ6 IN+*<͙ < ©Wnv~$ZMfxGѡ&^nt$BCMFۄ IM]`q`rNjl&p/v$mnvyzH(NGY뷇Ɖ127F|\WI7YQP>Vif%iH^UIn{|uH< ʩ lrjEs7 35M[E=Af4BdlUxG{=m;{P6HdK7L'π 5Z\]*xp;#VbN3á)%\PKAm..Jd-u"gt.v40V;?~ǯ~?||h~+?~?~o#_۟>z~ӷ?~>J\?}\ |oW|O??|tqo_շ}~1Mȟ͏?|ow_}}+_^~Ǐ__t~oH __|w~_]̥o'~8||?|7o[ٷ_{ׇ|uogV??oe9}_opA>悾[\o~~7o>~wgrY?O?}k__~kr_s}5/I\7ǟ??px?~:.?/7?}~~/W˕uz]՟k*jI_uj=_-_ZM嗋ZRz~RBJW(-#Ǘ(-tl %_Ts/3|ً8??߻|>?ӳx_|}/ŷ}qZۏy?/;W/W/)?~+s//?ke?ӷ7h9|_}q׎t?|~ï'o_kϭ?~wp}/݈ן=/7on㏟mW?w+{ُ?}7?ۯll.篸+.W:?6r} +._q-篸W\}kןZ1+o?ŵ_q-W\?k_>ŵZ:om}ӟ~r|s?~??_yM?|/>.?"p_%/G_|iK._|}ʸ/ŗ\Է_|UዤU}M_3O_|Uŗ>/4^}%W0_rU4/KKr'PuƔ?~釯_ܐ KX?>Fo?̯AkR_'B+}o_oO6~w?m./_ǏDgg0l\Y𪸼=<#'5 2~)݊iIuT2퓶w<=v\u b2-O}ƶ4 mQi\G ܻvwW yk]YT\:)vջua cY?gѰ^שpLε|O;VrtHU}͗]Rsvgz<n1l HTVmaf+Smўf^g??7>)[L*>cdհW;^j%y骨DoTՐgjQ|H~+Ƈ;ݽWYq؛I;8__bspVe]4vST |y{V. kJ,%(2uі";ˮ$I܍ )E ͆βZIQ;c Yr):VrJTM*c$yV5S)朠f?v>n!Zu;mUnRdKKͫꘆCQG̨į(GCRq\~xwN6ǽKs #ZxvmzOc"uKtc4sןR>~`dN7mPdUhz9dl1z\NGw W煮Zj:s qSA_ :ڷ0Z x4Uuzn񹊲\Bk\¨sCqcNtJ:q5oEqis\j}:V9U _iIA. =LfT g傃'i8@($7UJZz*?f'h+Yթ\(r!7^t~1>THE[_Uls5هypա ZNyjc舁~H|-(c[c7Sm^^*ۤq:NPU1X0kߍǸz[VkC(*}fMM[V]Gǥ }~**ZK PsvzۈBVpTf&^$LζkКAi8l' Gdx\igby jv!b;ϭW|jIڳn7 KKwE q>)czyF,GR깨S{h' e: EZrըӎֶ5N5On{^UMT;y:<6!(笉lsWk6D("%6ě[ϦpTʎg_LUd[%ו;/<,W(pu烤 y u˜D3!zakעrVIă[l"Y@=jOB=AnyCu5biYP!ڌjϐ^YIB^'UK%i4V籋#3-񎷎Ab8[sr &qg둭Y\Q ON>nB8;A_]S>n]&_9[pܵ`}:)\<_ yzU@4Hꏦ "!&`VL&eg8؀#Pk]P֔hɺ ^'Fm?Y`?KK+y w Fآ,'7ۍcį2N5cTM5)~WjC5hZ\ksD5*9Hyy=zbEg L[K0+nuۥa)4[-&1v W:Y^9t:@h}sRSvTpi"*TN> Wwz m::=00v% u>n|A@B"J{h.!_؈b(P1&Ț4,͛Ui9"ߡe\/(.a|C*t\N{y88 䖧ӭX%\h3hɥxK&PUY]ڞ'+vtm0YK QYՆ4s>G`~YB=vr4ŤCO0`wg>wiwt*\Ӣ;JN@ oT7fqd eHs%6,܏jd ׷vWi"gȇMඑ_Z>YjJe)YҾ/m.rd]d-ŶC:ZvE@$4>B{Zc nNޞc5#MvklG4pi|\pm~R)j"m]JTk70.cdIC$MixuWN.9+?=z?id)۟j;iFUa" MײŅ×&X3&QJ֒Pa]@Q!<3m1@`ȍz~᭨:%e\8TlsѨ"#/d-09 8UVtV=w4&uU#y#(}y <"%`[o<0݉,' C{cPvh,`hw+_JaĻ .wRPy-wt VTY ֿS>v6/ſOw<*'Ѭi썯t\YSGɾJ$ɣ\$3JX!gBy:Z7_;(`gv(^sM4eɂu_" 3+:% n=ԁLvil'K&y-$TZϠTW%bfD.IC,O CixJ7sO27rEn#+ytZ@}3[ x"8ɦ+Ap45?;" D_'F&k̾NE-,ek=XzXf^` K`!eކ :<toHmTV|tI}SuTh{l ]HcNPS)Ίrd ᓔf=mVݓa4zO%tKi䔬N%0࣍goؿp'"mP4؀ط|5y[(&f³-ѥHpE6|ш0kba3 Jk ,"4t^NIQ-O$ %fl1,ELe~^vAjo[n OKDTw39^_@B-1Ze>;wL PMСmp-A7"(vX=/dk67I: Zk.u ziۻѣå T;4N)J'^ӑ}vld\Ms ՎEm6|5A!t*|AւK wu؃X=},4vb`?v+H ã9 s&OS&!y]Iu'.HkJ3 u$INWSGv7n[xkףk'W 먯';pԀ$SjO/ ܗZʹu%#.k~q:[~ĩJ˒58)ƒ͎kWVr$Y^^]C&~?ITm5 z3?p'9AW5a(ɚA(j]XwGE]'s@[mhݺ8b,v@Y~"=W ǭqrRӵslY6hJOģ5Z"قyt'?%eUHyC=9v(wMɊhbiz%un\z35`JF"ĝ;09)q\>B-V:+z maf>Ցbs9k˙®60v&Z9Y2Ry^Ȑ ĈC.fumWC:.G4b{q@vÒ\-;[2{"HuВ٥+иڸV2є I5/4qEq۲O{\bz\(ob'uŏ:5ܺ+<5VVd+v yLꌾӝm¡!:nޛt',zMC0}ȫ$X,[-#mљ*xF,'S6't+i];M5j5hO}fAGs~;y6>}0MThDguJ*^mKZU%URjNLS5Ys${ƥc '@&3wT4ﰩ]]f$U3ꑰJZ#c!4\i5XcnXzOBz8噃i*l&6mg˘ ɋ9Ab5jVOmlZ+>깒!"mC& < l% msס1}5 `ʟXuaܪ\7n UK'ҾE=ߘ6UV[% z b=68أuGiJTZVg5j .gޏ7lie|鯎䅯V~L)Q* DQ]kU[bQe8Q$rpxJ~m"f]EI-Zma-g/HDV KX _< {~k~;vԆvS+gQ KprE뎀S%N8:)zf9`ɇ`uh/gU\xLfZ%&kzІ~4@'ii:ުPoyyt[wgzO58VK:8:9oW^GĠa!ʒ*/\a`Ҧ^b =?]aQZ T ׭@f C6*wΆn85`C-%d:gM. ^cqrj95*:4JY7vh ei6C_hv{qm$~¢:&5*7Po9oqvT{EuOe8'Mf %g ,qDl0T?B '6]N"Okڮ2@rB#n'=A*kj'S, y p:aSMVg):xS>Zq갶ݕdΞb>IP7H/OQjq6Y#a[ MZJ>ʽ~lLhf}2jvOz $vuȪn2vBDN#LdqxU'_[^l Ѳ?+i_zs xςW ՟3^ 3>K3 &NpA dcW$)t${U5GW8oߥarxnpjFm{h!I@. xƎ˵]>xĤsi=R,춻:7kF_ie+ټM{Wދ,ˋ%D*ǩn _h{d * lbɚ-I([]N S]fr_ 8=9"(~9{ayh{Fy v׮Z(ł\*o1_' "}T4w֨ary']IBV&ڑmNw\f=k`;lT4y9t$`/{"-u͡ݲwh`ᓍ?v8BѥoD |RX][K8ceb%'A$i-.E4kiXzbߑmjCI h" I?9thh[]$W1B+ Cכ`".x /bkrp$3 X9KHstpQ{vQӻ|x&yl7T[mgǑ.tۮ8Ǻ5ct5NIQK˻;~E^uZHX8t݆E+ x<.c5І[U4()j3&/UDq2;zlmŬ Z D1rIc}j˺ g~vmV=?t&JW'Zh@|7Sz.b"\ґm=TKUZMEGڄzgI"Uԁƛzo\tfL@g$R:ڢŚKXtbRhy`SQvM,)-qVSޮp=[氩k'D!;^UD nsVZ~)$!ȷX Z;:}Mc; sǼmkO@n݇csWq@eh(%émv\ Vco_P9,H'هCvUu>5Si:0Zw*]{t 梸cl.ӊ2h>PʫIȱI+y7 *R ˾bCZeI^ϬK} vm2ȭPEr&K<4Mv<*ݲeMR:m HGi]@I/>4$ld FZ5_)minx6n'.؜dȸG7Gϼ0yz.;NѣzU+Z ')oaP\u$7ŬSQmLWÆ /#>q]Cr FV0Uozga> ]vG+DT?SшjhQƢMdX  hJ³^%eŰu&:ghl *Gh!9k*bCYmeS.܋V hQnQDzG焾0>,e%z=ջ|Ie< v=ev:!, Z RNG3E_Jo@pOphNìFV.:pt;ϔ k .a^!=d,,^`n;Aey嘪;H=u:Cxnb'vVNϸl~seGб= e+ omrěPGjt(od &ݮ]g^ڴ)|VD4,y% Mp{+i8ӣu nl{L)L`o+(6h .\Tj5L ?4aIRZQw@=:?u~ż[AskXվBc(A' p4C s5ƶ($Y0(֜RLKAW 4f N)x2KN2?MDBV%[ROnNie'2FPB&{O Ax=IbWr-8XYoՄxl寽N00T;uGh;^UHRj^s[Uأ I_ySl:ǏKA1k'+o`IM櫩b᝵S mY鵢`ȋt;j\$bOP :6;Mn͑<{Mj,ƺ7R5:| ȃPAw8kM褙wLKg`6P9v O.o,Bŀ_-fSӲ۝N}>ĺ,3Oɛ;alMB.QV˥1VH$+WocQ#E k95TO284PPV{$'AE/zG'M'_#³q*&-M`6x r`!X$aC-jCk'vʢ5Ň-F"{zydK: 8<_VzyX+˶N}PN mo^, ats%a5ӑ{tnr/k&mI.M`8C*v]!QZ$r=kk[XX-s$oݨ6М.#B /Wi2R:h 3IJqlZ/EG2^&JL#Σ;Ix3o)nT& F˙r~w5ңɩ%<\8dYw„a]>HWww0fC2W;K綌RX~ >lskSpE{Ȧ\_ _ hEIz,{4A^A2 )rbPD.KhJ +o+8=/RʨzMH9CQ봀 w g0dآ,ܕWF&ԀO8TA=+BǦyl!MζA*c݄N^H`9ĵP-{<շϩ||Q|.(8,hu^X?sRU88 lI3\.CXfs.z8nr2*?U/|y::xl"ke*=YLvL`uriiٺS\* Fp2c0WѦ.NaLMxe^g`V>U$CHoX.`:) ~[N!8MAxڝP"`pI+[[! I{^!V5  _ؾOG<k#тgPPҞr3J[T -ڣ1 mg5~WjR4xܟMs-eTSqˇpVZ.tb *BOq!A~~b.G ox}VJ,P/1+x ݢ݋U#T=} fT.i6 2eaAZ8ɷr{PeRݿu]=W$0O+F2u"d:۰ xvk|Glf *~$(ªEh=1NZ|kЩپJ>ִ_DikK^5efuͳwzH2`5LCÕu8zk ,ӱFf^Yt$ es@;dFKe߉=:Q*iʲm *Y3t*k)jY0<T}6$߰b8+L _m'H޲U$٦䉘0H@K!nuW~v)wO+ k `?ev ,=nsE! ְܳ[Mn5'Eh-i;Z"P ,pTao?ѮGsGiZ+ kB_ZT(XWce/2IzϮ5w~ĥ$ֹO"N_2S7䄘a[o]|ضɴDM:P*#`Oc$9w,*WyԽ^NEGxLԝu^(ew;h!dG# v/9)Z/Ak6S_T5 F.k54`߰cVseվW $)(+ΌȋgP[Tfxgd^%>;2L! x;sGKfylU>n(ްj<\6ٿ=A>iq,AmOuLDh%>,٥A"&yADhP縧3Wܑ%l2AScиrʧSL,KA@WߝT0ʖ]B\$~Cr.a Um{4R $x-yW@V[_)hVajYXՃ $($}_/U10_5r1cx%וT*pAyD*|0XzJ6$ۖUhtM@ M۔.caRso p5 tV\2]nZo^g,5u~kI": &8:l>u*[r׳4ꑲ7Q )AG<&;4#rZ5Xk8 ŧy}t:@2-q L&]6@&|^k=v 9>8ҵ#݂Yz}B66=m;<]:RN 6Uh+ϱKʩ{'m RC;8m5<ѓ=*l<<MOMp;NeYoۮ p4U6RQTVcG.iw5]D0c&$W*v(}~gX@NޮjP^ >7ciO8ςcD'^XcEB*h}QC_;[E8_":d άmb]֭^dZM`yYY̗A'Qyd@ o:&[y\p42$91nq6QbSv`ۼ( 1"ܯ@I{f`ٳg2[})w{ VJ!+z7-Qk(񴿮G)f ~kx LsOXS,x -]{rkOap>N5gś툏.jpHb;z !>fœ<1jUer TP̳ڇIzt.w{ca岭֕;01=dMVU=[%KU*.?mUxoTޣ5՜6cS7hxbme|չu3}|Uغ/OHf*?IV{ho!A!Oܢ=Mvzo׺=) rZ ]a'ݭ)voަrQ8aqPZcX'j7C$vk l0_"6X6u*o5S`(h> -=~lϥ)*Me"\|56 Tl Mpڬ p8Al4&wnӔ׵{rw!vrQ4f(M@LUXʅUbgܧҤRBFfɹjґg) nzqU0By4AWHݬK <%TɓEa3R;X}!2<QjMM7®թ͚aCc%/lɎ2lR9tdNoQU?yjO.D[Vqi\LIE^Zd4\|j6nSV?7rV}X  ;*Q9H0$:# ? &g_$+%>Q-se|2Jc~l6>- o!:VnC2*RX,m_&0M.i^*6WTdE$t,a1o:w䫗$Se|[dA; /lFPGe8_ A,MvRR;DzJ) y-Myև_5;c+]kcAi :骚ct(4BxTXQ8e,I1se#~SKzj9ɳEV5?ORx;x$h]W#)!6ն'% N{Rc;ѩg%syRkV%vaRWaoiwg광iB5T9ɼ=/TUn|Tْ3bܗ eRv]Nڦ;@Ü:59ȵ$hsyb05βV-@ᅱ(sv:to(A_;M˹/YRD۶W(– VTTrR.+H9=B{;$]Xz5/ OFS$Y6%A¹Q0)Y5n:`ϣ#Ce8۠0 jf|? lٝaYIr*Jd>Eu3h!j7gg8WVJw=́ym1yiRTPapqCs'LuEjA.a+.aS=dG-B|SnޮHj <]Z\K/L.GŴ /Q8‚R] @7sVގAZX1oF:(CP {ixVJ.$d E&. Gh_/S/EmK9Xʏ. uvƤ$7WvF^)ejZ?)yh(Z-w:r+TÂRɮ)݄:(ePvaC n[~Ir: b>%ڱ4QDtKT_vܽr@.qMqJ(ذ.N5Ȩ 5R |=)7&/햜SB0dsu{xδ3G%O?EiHl`"{8ޜ˴!Ti[o9vfs= ه-KȄ0np>YS3v:dt)㱙u顒;ͷ8 l4M7$+t2>RVݟjG6Ŧt({ڎk`CR =J|dj#e=3 =xPڭ4R\4URSEIe]s)'xۗ3jbhNj-+Upv[Q@Zb[(]k O;i^߇+DN%+ ;CkʥAF.9utr*L ^ZkKiZ_&5T1|O:[^ξ6U(?3p&uf5q'-@Dt(̦'OK1F0Oj(47deot jKv4jJ5(FeIמ/*UK\&ςmw5 QȪf_m4\Ih0yڨT\ps{J /rU--syJ/+ :GGb |JCͺYDBmWxo0eݞdC1 {FocaHV4ձ쿋*y{ȍ[VȕvtV!蘢[h ht`Em_O;YMW5I%]z`^j u;3 [u5$Ds>JCrXoCh0j˺5R{]BLr@G J]Ʈ2sxisw.,:%m!`,[/h{"@{\+5Sy<g隩=sp'Oo}b酪{S)FѢ=@d)8NL<]?zL~;!kRbYvfݾxӒbptx|̹EArQVf6"88rӵ`Sc(, I5N^m"8 di5/ꋧ'xS=ɪ.9{KxtJxҎ;'=Ӷ3ke"њ|,[MʢMkznD\uiF9q\NpR si7 &mAZ^$()cɪRnHV Sކ ;47aS-aYp}l'MAi=: vɉkN״1?/LvOy n+#,|ڦu:H~mqd^6 .Бf K\tl)lH*Ү; ckAsHRuo,m>ca-$_mrRӭHӷMJ%eٴpRd1ھ'\'8j9,>7[|(QzѲԖSu`Iۏi3VD8P9QKwTni^<<&ö~:-j9;gheiaIŭU(Qh3}q/p;ثaY '&X5MW;l+N5qRv/+\d%Aqݾ%)avrB  we4 7XzVn(VEqў[05AU SףDM-UT7o٨=BGFyW#hJAIrc {OV.9 *[~Dr΀Gf6E;m={xDG9mSmoO-]-0W0@bCB ~y]f@ &D^sӏs8a5ix ϐUo ]xBO?uqORPXȳ|vg`{vllWy_9ߖւ&2F2Z*$`ݝufq!)p͖W@Žbe^spQ- qRLǗv4\~`$=JE z$ ؞<\g,HBr^TtY1|8ɹmSpv_eӖurzGPPP#U-x %6t;TZ]0Cջ 4q_%M|j6Tpᰊ@+zqt;,9*#7cX&[,h+CN"ipXjXiyz&]r9NG)8cnÂb`M]U>qf|)AjV*9O~^YVf6n᱃_ 1b9_l!psN9=gik@Bh%Lk6\r=<! %9t?3PJWN9͈y3e "?@RX.;1 =mHŝIcr]m[;NP)eϾ[MS[d 3᥊Y=%k ua9jZV;޶e\󘤨zzRqRW-PϡNwS@J Y(zI~SUW9A3աlQG:b9FKsJ+ }.$9cC/[jNLRƃ_v>8gнCٲcOuqTĉ; .juPzc"m{J-+QQqVZfO?k55W3U$•=l"u@Q*U}Z%+jmUyКE&jqxBl}MV+گ|/si0 Hwo*աUv+A+WaP/Tx4U.U49a|,-a#41SsU69Q+N爔U)TQ5|Tp\ϕ*OpϚ"*yacGo,vl?\aJ> xn/݊|û'xL HicJv'D_`J:{i6yOUP4ْ0"AQG#iȓJQ;[3 |yO#؋eȟn{wf;*DTIЋ<ʞ ɠ"VA~,Bƣ)`89(~K%Pk?ڽ@QImny0hw2fdM\/Twf:JbǙ=T‚CCbr8133d:Vc:Nh8#K‵ G.hIXusFOG[Cq섕k 8qUZS$R!-&kMG>qU7C ?ݣ~}N. yP*W4q[zuMፈ3ݩ!!n9SçY t;FRK; vWQV܇i$@P V@H೾ yj6]/7 H=mZ  ȚG} D*Uik4'Lt|ZD8mu瘷1vݜ o:)J=); <:bDӺ:*5Ԛ,xWO6)שng;-4]bj vcűa$K6f p ,*Sl\KIYQpdGġڣO+k4c02=s+Snĩ}4F֒#rkA  % 9W7ӔQ=6;nV= 1>8a_N^[J2Λɏx.V;%A&^n{"^|ԭK*?v)% A"X,R 8 ɏÉd7Ar)g'{y:$oFԿ:$aAe1wQ#@xY:Wj r8.Sngi^1;MRYkT7/ Q\@X*iq;q; HRLrvVӵks5jP1VRo8(T^,@;os%wZ+7L=͟MجWtVJ*.pޤa 4-#^`OrU5/l}kogiy͓bwe%+QB' Kބ>4uM6+Nauf,KM!%W `^,e/Kȹ)O3&WS$_, Kvs e<dxHQtXaTMzG[(*,I\&[$Zj*ؖdF?0UZ:&wPD:>I QuGjS`V*,;Pᖓeh-덡T,I/)^-k8F %5r 2$ N*l \z(WW<3:NXm SvKKI$d`CT3#2vS':"镌7g;7(6*9va:3wi$^{^/ӑݢ9ǪFv>'q֬N vgX5*< $/[-~9 goaB^z*g&@ qhTYn%!(NYGÚR!<"Ċxa'vE ԅDǹl7,P@tp:lt[Kp#;d ΀HHV9YG@Wh贼4GnqT̋=.v?G cS:[b DgPV+9ߖCs*xFjeqv \}-ϲ9{q1) 2S^ªclŌ2=rk6GN޵JU7Ñk^6FU0a%X/،v'yl,,Q0oBv UO8W" aT-X) ig3b%W2ʂ|vg>7r[[R>2o&ͬiGdw ]w*܉=KgN`rh:穂G6%p 'G>v_r},[y639Vrf@Zf)7@Q0TZe8 l(uĒ'gX5 ʙ]iREclK(%) gjP/'d7gaZ)c>ֆ4 ㊊icߛjɓ~uU Tm7G7A+)l+(91!wGBl8@Ζ&Uenۭe8B`G!6H'veԇx"L١cDUv*[6uY=RXt 3Avoƃ z] ]7"d@OVh "rA6q٤:K!=m`0 c0AgNSnڠeY[ם%N> oW%E#TQf >-J9 OvvSBR 1Ud;ǪP+OltZ8sKr&`Io f9.TcZ +}b|th~rjY#Nc y@# ml?,*Z֝hK%@c*%ؘeQSΪ~@w`d[YH{芥EAV[emr<1d,Jp3hw% #89[Y1P8u"l4}I&s/@M0avS*nw.ԝl%`7MЖ=쩭8bpUrB>ڣlgCYöUya\j4ħRx|&Yxtmi+Z'5)A -E2, %W˵/:+y6yڇr}دo (X=uc-/%9l05`'lU}kkT+n*w5XGfORR^&C٪Fq0U{$*0s DXndacQك>rxv@+Dq׭Wo-=Rtp> +RD kZ-`1T[KO zcvM$jx{ǔlhm4-=;)jat)ͰYXʵ ɂ1"?+˕VE9VRZNKϢG#i]Uց^/*Rţ9BlDS`6NFD̉X@.OK+M;y|U.I+.8:_v y#1>5rJ6JU8xn(F5DTjwyuP |5ee{Q9?\ gy`+,韅!Jb޳]#+7a0y."w0 ʁNRn+:iPI9m?K8f8eRk`\%Ȝb!%)mt:%c}oa;@}?N7ʑ(e@YW(\bPӜ%V |Cθlő۽*(,H.B32cգsvǩnde߆[m6I2L9tɭ+ZWn5d'ۉȶ5 WQŐP@Pl`:Cgم,a_Pmn!> 㲂=Ͷ_|->wo^i۶?o߾Wo/u^ſ꯮o^|7 ^޽JUߖwooݛoywoCy?훏Ww^W͏o>ofb|o>ʫoOo?r]o_q߾^}7ۯ{ eß޽R}޾w?͇W77.|~}|7}U?^߬|/[?>?~y9~F~ӿ?7}o_Pz?l~[|o՛sO^o|W7߿{󛏿~[;[կ~7V_WyG_}>Y{ǧKy՟|G;Ϲ~xo/|}YܯxΗ}˷~_~O?{/~W_?쑿xk|/_ȟ˗˗O[G-ֆ__N/4-pB/sd_<_=_?e3Yґt"//1_>)+g1_:_:AL_91L/Cƿ~sKG0_:9g[f{_\/_/7Kx__oot`|?xyZ>/ʋ7';?;'/l|M拷?'|q>^|_o{໷~~-;7/.Tp >_[0^/xi"_~_ك}m^-{“+*׿}^[7o~x˿_k*~ /x?kzw?/w_??}݊-ۅ?oA_\Z/_-~Ïo;d]ޗo$֠~n[_zO[7җw}nyy_[_Wo[g3|g,^~7c/@V?~|2+o|1//>+⽯7=_s⭯/ϼw~=_b|xKd_^7?xF/UǗfo$Q|¤e@z?9a_}/ˮx;OY~E|e1nbhu<5i=/?}Ww\~ʚ^߼%fze=gadjNI&sN9U},He`:"CCiQoo5d_W̸X'\Vy8 r)̒$#.?[ G˨=>ZWU W0LۜX}KҎTJ۟mO\=6sU󺄱5t}[ТZ8qY,3 aV+7!UyTksƫ%Ky~v\yeٕHj1Nga8E 1u<8jh!9 զr=Rg>kv#{ϓڏMԤG6r lg].R`ϻ>OX㾋R981Fyp}"D.=v=Msm?϶4r긯;<VBwP1+*wi-_v5k,XB-+ nfˆ.k湏,GwMWr>sg6p:4RoJ),mGð٣o?**tq!,)3wCQt8h]VRbɻ"a6]JQfddmD`;i;]^%/@ng?~gN)EBє(C0vG_lUqwE[t|oWYS#m+nОL!W33fDb]T RC[RNU]5Dkslf ` ioB&8u_Pvfet>q6SފB)wMф]+liwk,BҁYmy-Hp9pt|sd^pw{`;yXP:CvȈq,;$ͷgxfu ܎}Kf[L>p.kBQ]V6F:r[| 8tȕ4^gFg:܉BJ(TG0jƙe)%rub%glZB{Hzp3ؽJFù;t:DJU7JO q֙ujE\vf&\쌌SEhE'J$t nC)dõ݁~UrG᜻,eJH;fv.3w),ˎaLduq'sUERG6RU}oi[d+R$ p_ /"~<DJ8C]ݡvFT/eM3T& uB0kSlIlP&#ZN- i;3\*(dcn\jM]=;Ձ:[Գ;nMcmNG改=B6Dt!Y7c`LQ-ֶAhuSSY;$ QWwt~"%i=%.DV ذckX[ITeMDrK$F P\)}hv!K9I%u5J(B* uSN <ԝώ aVlg ag%mr`ZL5+VE,24*Swۣ,*g V%ʜ9L9bg$Q lrHKT庥QĩlqdW 쵈H@^͑NNG Fc`#?/(炣G}xiT\k` ثugm-3})rM#G7DZpTVO-s4ಳ CtbaD(~E-v~*sJsy'@-:->q Yq RTTڗ((lc|IswZ([^̗ꯂ%Zv6 =Vz5gp};᠛d){߆|r5 tw_. _zc9N4ֈƣO!;ljgCu/KD*D|JR-xNr1$uHm8~?jaQ5B6c d ew͇<MPJ,I;F|2<<,cᵫ~Ԧ9gqdn>HA5́f'za,8c?99舷Zgؖ3LlGQhBVZ Tp6VƷs2T\9WS\ڍLi!*eOwyl]v@ m%Zy("D@; 03 UrcO^-~r+瀛l'x Ɛx-RJ}\$ŒẂg~n㸔 8DS ގqFb4O+f9i)/Y'a)$Ʀ$#0|8`fr'΢9ԐvqE0"E̔jBIzy>4' x@PP/?OTש.gn9꼰](qcobbU>6'Z. T/ݭlSq=/#/}?Ms'@6J|/#IVǮk59(9m kqxj^EDyLjB OK&rFH%9N*7x:XdDTZ#3^NLs{<#t!˂`M&fsZI1e*_vcSG!$]{WlH#1L88&l/Ze" ?JѼlEjpn_P\fSÎJ8wj{;M&3MퟪsIØj%eͥJõula[F[9]{U6ӣ85JM1j1ͪs]B-s*g)|`ܒKPgǰ+]8LPm? qP9vAu z Tg#TlDdvŎH>.Li$I!/c>kr/ix*W5(I"/N5s$sTf@,dLX`>`uu)xˡ{b*fI:j'|.Zѫ kC5mE`G+RʢϢodInMrƦ-2M5;hNj5X jKm,{)_grCB$I-G{L>e4g=(XԛR@,ޥf45e-;,ianl(́k .n+7m:s4*Q%P"C;Mw3DMiЉpٽ~7XY$N@u]٧Iek;$;Lh'(x k$wxK 7[rvוƿe`Z"PZdXAbF ugF\)/|ԑ3s?dVW%^Z(x:{/@}f ~2{J_FitF9Ll: N!Ҙڈ@dk5T");#W# <{Fl2ZǯK0f1\AȃOǕ,4.s${MpOBUv8}wVJ>TRjV:Ll>줒TW6^[>2i'ഔî0G)Y0U~a.V%%lɋ&J+Ekڥ aҤ&t¥VSK|8J϶IH,y kpj$126\?x=NXEI]Dpҁqj<=]JC}Z,p XJg{ϡJ!NY/%ʝK#.;Iz37 qKj&tD˪*MpRQ$) B?srV^6v.۱([Ѐ:vP [L[fI>[JN'#فc`Bǭ OSxh gjQZĂJpMVL<AijD(9č:5{P3}̈X//\؎ #ֶ2{1CFw0&. Xz5Gv@X0&d,J"-7ѩԐ?)KfOԼIx[W;i:'8LB.EF !׶Tv˶ n@d6*tw=L8Cte$DS{tKn 2 |a]IZ d4VTuMw6f'͡947.]C$ b[L(.Օ i5Kc:d=nXė³yAJL`XഃpZ''QӜZ0T7DvIOsq7)=YRk0Id#y@מ!n=%W k [ kvy@xl~w93iD2*XT RE&`G: &>QxK2e{H.:LRa^@ja]97l7|grݷ4xqy[y+=_RT%ĺS3x@73` feɌi}p9\]$P^j2QVRTV%->l1P<*L7lgNYd!G[ U*jLT.4oOP$rTGCHB3<e6ȘǕx }x'M6mjoOMszGm8O)kأTfкMa3ؕ\"<!C#yR\{] Sb:+Kd! Nͻ\Vn7Rv25[Ldإ,f$yjkgJK.YɬxO$9ղpC!O',섖~#n6I8Ke[ Ò}z*8Wq/ ŵ$3\&?x1vpt4n뉪"Na$(p8Yewث[+ypGk|O>)'U]d)p+n`W@nxe3Ӱ j$maa [bp^ xK\@WWU]KMҗؠqhn-ZS=;wsvk8c]8I+gcͱ !1c*)!=N$eoΦv@G/[rju$Da8~3ܤ"iJ'NNٳ+`'xZn sۣ8WUD5J`k`-Vo'hVS@l#` dsƍsZ+OBu դE)/9gs\'>%$ǁ*GCl=pE,iD&lLi[eKdu^V{ܻJg4Mk-&Xmýde=iSMEBtxm S%$L7 NT5ZrSQWz<\摭Ңe'Y`;)Cfpn Dv- I\v᫒ 94BZcIFe#^ݮJ7[-L Gz ;sOm5Xj @ir7]~m+)xoo`/[O4\č+"_ @EU{p J|a^ץ5mYo$t% hJ͚C>hG15bBqvX1C q@yƓ9&'X~%V{ Ίjj'yvT[ɾM. K.>bmP'/2&#{khq& )YsS#6/>WppY0U6pQ+FN )#ۭ\6(z>IұeXȁ3a[7@J(9EyWda=Ycvf@S.QeV vN#֝5y 8چG<}68XFTXw-ht(*dA7l>N |^W'0Dub~]6G#8)#].tR-|VӂܣIf+.L#&徛6D{l伔$fnX{Q~\"vVNݪO{tF_[KwrNr\ˉ]@N%)$ MUk \SL.fQ `@F& p&~Vc`HY6{;RUǍЦ$YO`g阪RySj)6'׸ e&Dv 8l J-kJޮ {j$rpw-afdРb=_qrlY8궧I~mHv a =LjAJu>+1eW($:u/J7G'|e;SpqaUud'N@]NO-;`7ajVh3A.@ ۚQpF][ӲFu\cB;g!twTg~\g]Ձ,Ƅ{2btEyzJT1C {3Vl l:23өzTYmQ2RK֗ u֌Chkz2G[p5O\ٕqBXRA`TQ]w#9 sO۟6 Q6`3cʾO7O"d5vP`Q ;)w a[yT+Ee_“v+'wp>8ӺlIQP?M$+7> Ulr<ҪgӘ\bY\ZwVsXPUg6?NA*@4*bC s̵. `NFk J`$wtgL21cO) n+((cD&-#lo#`ƛ@P©,1]9;_θ칕(l`'vG9S=NUٚ_Ƶ:}FVBYes6qPL`(oQv((\{XKZ_u pH.lL?z9 cDp^@q s;V%L9ձgVͩ I%;Bm{(+|TUYQ cC,qp@1KF5j'nADyxN-V6|qb yӱ1:F%,r5P5&ˑ@ ̊MWfy9X I-ƚXL Θl*"yp}1&<&sD[gxn9ԏl)p[YʳK&ĵ)ߜ~$NVĹTݖ?A?$'no\}6ɯy(>NՒvߌƞ.R2c$ q\{|Gm  y €>CX/n?0Ԣũf]̪qePaDEr<휲Xީ%)܇zn6;@ئ Vم`j@A\-p$D N0e{p":尐4=-K"#a$9`ecdu8Qia.جy3u~_Z+u H\jzS[J/-+sR*Zo;1Y'UKEƳ  `.#*?9˜gc愱Y;ߵRXOI射S> jVUŊ֓N%v%(QrN/r!W*n6MFߧIQzq9!U( pЊv=a9*"jr:1F E|ͩ48>5GS/Õi%g1T 6W wYb#QdaWOdJM1b=VIA$F$gAN; 356mK3뚗fE_=lCIkJ}daܝAS9ڕ=T&9ndY?ڈ%Ԥ ZumbVt! ܛ<LLu~x"ܥ h:b4lҿ4@;սjꩂ e <,iܣWI4"fБn=ӂ>8ͣ;|Gt_ݺcqmĺx΂k,ش33ьӪDѾ9u͎38Og` >ɐĎֶDY;(3]T’0-bDEjmGv)MI~čg!^ Ӹ/%ۉ&qEI4+RW& ׍q0 x`ۆtАpWTP.{ YjW]{[jsб:BTdg7vI,U0ۖa' X7&@,KEe6h7N&IpKDf쭒C,ڗy^, US{ ji=SΪP\nyF- yn\݊+*lNʙol%挥bNick;Oq@I2;ű E@ظZ'dbL4˖:vYӜшC`WNk^%\`q e@i:!݆^  kjU\C%tE9z*}FdNTT9^5vf\˔x&c9QqlK;̦\lXiњuWLױp(w58oXD}V[d dn-޲!mv NH$Eba<1Eθ7BAS/"[&fϊK56 2dQْk'f)}%S*y,qÙ=' )up +i([n}$*6u*XDZ h}eۨTݕAt"9Y9K`Ђ@2p9H҈؀ݾMM}EA mX(q%mațĥ(v{+vq>ǎ{;e핳ˋj6RTE[N-TTW"mT"Nf0H ,;=$)1tCR6eX7e#%Zʐ|8xkYݷ|eV8Tw\FXo4%F3 J1 .x{xZcB1 \l` mNj]q*Z~ }CeT$8y\&ξ-)<$_1ڕlJK8s{ꑱ~M1&&Ⱦh y涋`qGW ȍOU{($W3A,5M $-mY.7б6 4"DwrpH1#QR`^6_o]ing3c X$/o,%x`':ptle88E@%/~"v$=i=~H\/̧yĭm1K+/"XnpƋ38ŵY`Mb*&*DiblLQe[5y02N|G##պfH1Yu(N)wFldZ9vx55{+0s;ݸ$+VaU{xu_Qqnd<}g8s,Η–G%]N|1`w|F5q n;D(>OW`ŏR1؅m`{#3ٶa&pQ^XoHgr8[-Mkip擸"M;"Q_!T+* Kx$% [(Uu9p س5۰6ctЉgKb;Ak6_MƞJ2q6;}lY~oP)=mt&Mjy!Q₃Q4r ,00Z D8_爟c1wY:13B9x[Bǩ+l؉/JIw"[^Ny@|v0wWa\7[ [fsa 1ȥ&1\|VQ ~GXT#Tj^pv@=Fr#{ʼnr@pPݛϏWؕj9ԕޓc}hYoN\8fzbC-SE}>XB:TNX$6KXݷIa7V81{XVǛQ <%.:)9!RpvhSU$mhIQSIh0m++yupNͣ9QVc8۵@Ya٘&i7Qo̯j:!#Oc;F.N V|;=_cS(p=sUxׅ ed\E\T&]gGnp˳&>aavӟl:$Ce>J:L@q\u8DnppP癃9?KtP$gAJ| d( w|de>FA[H7Vb4&eqƸt1? xAAMO8gZoTC˾xY Nx)ROsDŽ5on{6Ş.A=sG8r?S炳]U֝1mmtJǯqe_6zkr%!ON IjcׇRc$-?eCX,8\RNW`q37 JIz,NݥٮQZ&CZ"Hw98mX%C-X.+Ҫō_x@@Ӑ܋Vj kjp%w8 =_*H^[  aD^@ROi!Prbc$<60`vlH #QkAYhÁ 6Xi0׮@'<'l'9b^c[DU1Hf%ڏ)[*|!Ph/ٽZA <^Ӡ&p.94xf'̾%}O;2܍;QI;1'UfiSηZTH ֘?䌝m+xdT\-_1c&gw±Tyܓax;enʵ{YrCS$A5 az{>Ly;r:twi ^sw) v*A1Fw*`kꋍyIhdt$jQ%P+됪iSyFulϭv6T3! 'l؊u~X4"+GbAQsb$COSl-揋ܷŒx Qh9xjAo|,R=knX^ReNnxڛ\@(gerѯ[Ż\w5ҥ)kS!؋RLv6=W{ڙ=Lŧ&ͼԃ9Tqׄ爩%QCAձƵ$ w[bv fSО=8#K.A {_vނH;䒏#5A}S1>rLMdpu!UeaX2tٮGg Wh<jmG +T5XGJ \pRhrS ;I N_ydq BʕP4].'ʅ$OhϠ\!G#}p Ğn_},6b9a-P"-IIVw.˵YPgYQ+] XBH{9lj(e2uwTͶasہjʆh|kL{+W!>e;z~z-9xzM4y 3*Ķ853Mʒ6xEr!Ʉ>8*C0 t؂+5=ͮ`V^ӌTj]rA,mvЫW#,njhfYyxfn3pn&4 @}ƏOlܷKh-[bT̉BpC?k9'鳉]};9 S-tyRyUpZ6vr1_<+ADI@,}Ex-&N…h*v4Kq.nBb3giC+vb^"oW7 bc{]Ɇ@Hd7lˮ8êdP xf7Uo>^S| PUG;JeZ^M8V|VVm v޹IԲ5=|-r0`nEDz5.^3<Œ ~fdKۯvIy,1EX/ϒH*2bS|V'4n?.K{~lo:ikRqaV%5uH%l瀙V$@y\Բp#|쮵Êɀfb,Ոw*DIxkQpV5#`{9(r!x8hF>)_]y3Luuv ߟěME Dq54ǘg] S[@PYPoItu(7tJ !i~}ٙ4 Dλ32sc4 ~( Z*5_ ,+5\`>(i8팟Y<-yUO"U8,iNE~$Xi7( 1mgvq#~ ̆ Uq~9A'ޓt:3(-?طľ pRA/J83P9 bcڼkĕ߮bH,+YOH,ˇݶp @阌aAP/ Sw/-UnɼNq:fF8O?~"}=uN['ID/;UMIiE)2ӞoEf~NVMuST%RmZ)rf'W11s^l""p1A2 1C %OUueqltIU'rHc7 ၧ-.^ݲK ~YSjA,AJ5Vp\4Hӕ(qSy5^j 4nocNy eo칋b+?m{FB֑D_ts3*le,ܞcVMY\԰ք#ArB68Uhie͵գߦ~WNxl0Z$߭K:^U+r-cӖ怠t{8@kW^Lb,,lٖͻJ.&QX]|°6ZU=ەl4O K#h[i-fr[P@ /NwK!nll.U.mwS_YW,n[EJCV^_ 'z:9Q*^Hymd&,,tri`Ғx572j/BJRkzLGU83䪅2dʋ(>WGť6Jq딛\]RUZJ 7;|?mW5yG|۷}ouw^|_oo_1ګӻW) ?s[ku|o^_ݛo^{yիݻW?xۿٶ_}~n߼z۟~[Ï\׫߾:}?o_|??{_ǻV__x?}|߿͇ͧk7߾黟w_{o߽yױM(^oݫ߼~|:~顮??U[g߿߄EOK߼}E>H~߿z{W+V俿3W}Rzͻ/_ʯ~拗ʫ_/_~_޾?y|/ǷL_^xǗ/pAwo~v.~%_\ݹoݝzWO\֗/\j}+\?ᇗ/q~?s߿%\/r?W㗫?/>tp?q .cp|烡ǷoBj|*_j?YTjKůvT_vi7o{髭4~RFJ}r&J=ڗ[(?Azݓӗ'sxy?V>47/?^ƺ/;_޽Ǐy~_o.՟~?S_ə-هuQ?{gΗv޿-|ze9>׿_/?} V7o/E׹~;_wĵ>ĵZO\˿?}z?q-矸'?ĵ?q-O\O\_>ĵ/ :~kͻןk>߽W܌~7WW_?Szw?~/?^8?ro^9zŏ\^te\ŏ\?zGNzu/@?rUŏ\Շ?j/~^z=txGG}_Uŏ\G=/E_W_._޼%u~曏_ܐ%/^w[x Da_ݯd"_|qa7o1qo7C.13-doۖ[D`ަE=1FꞒMų~BI)؄f[,Rd=s% ]RTYNggܟXsOJ!.I[Sti ܜD*:PG(bﷄ.KUrv_˴Y/@h,}Kujd9 [C-eC=ssrYR e96euLEuz3ťB,m04L~,yzD%r<;8lxsVn=mh{R)cFUd$Kqç1R1vIMkd)[ 2M pR}vMwdcKN"b76+Ωѯ;*w2ju&._RegYcm8I۽m{KgͲY2;,fKpbT}){q2±y~T׫gUN3v_ۣ}s\s..sզ{s Pݫ}S6g%ǙZ) cIF3ٲZ!lsT;+:ԅCQ%;pYCZw=B8ȗ;'.P[ZUg\$oVF\c>w=7jw -J#]ABx,-)9~PeھyfwULJhwIݴ2msX#˶ GѶ>UҸR}oe`bn(}{n,;TmEr@,ײE>|<ؕ#[ZSޭ0}ggE"+/uuYȉD*i;lWuď#xIzVy+'Rmwi`&7EjH[o,W*R8=+Jy9C(2OYyrJyqytr԰I kU2JEk=-Bb9H.)}$"ՖnSkz]N;؜UOd 6H!i,qح>mpGfG$3ǢH*Ϲ^͹w)m(hv6|l>vfE&V+l^ܗu_ZR>m$#$29Ԥ ovyὥ}n"")\S wE/oYit,s Qfgѹr֭p"Ъ!:BV>QDhp2&_(Aq3sM.E |E 'z;~a\ᇍ8Fb¨f4=lSZ~6R1U&a9!sɣ6^؍C OwؽKe`Im$}}I$Z&=ػ^c?!;FjKp;6Q=f l|6ӌ g+=9wGݎ~*Rβxyz#|͇ҽՠ|c:\-R1}qGh<0ނdu^S#um%'%8BS;ssl嗆zA? ST9E`4VWFGx]IhIIq\j kH] |0ZSt ,1_*hy[u1?E>vgmKH<(uHp }g[︎=v!.%,sn#A3uFxl* W>z5bDŽvۖČ}q; ؖv/nǺRgD$8$3h*o? tz訴'] 3%ڙ&-a̴1 NZ3_q)q2 ՟-2h b~O\Dv^8l0'fv`9Qܥq H<ZԢS!E3K {g"Y<ɿHĨܒ5ГMwrF'qUix?""fq>#yj+V\C-fG2/^Kbw . ]QYrԝ7MlPՖdz9DmE糀DJ7t%jfvZ:+G6S'Z}\%څvX+[l]E{TK4ǰu%dmOSJXȗBI=$\rImz&J Χ%" DCUlW?1@ Hw9\nK A)o~]|)}ӆrXn["^YVGrd6:/Dw[ LM^Y,a3(Msv:1F,ظ,3,J=2>BHEZQ=;B˓U@f@e P8D} Vy'x؞ "c`'bE;T┣ ]!/LydF_kTIR*LBYx e FEqT93/juR/9$>GWv]k`aut&E7މ&X):N(1#1,Pߒ& <; pJnϯԹ t`\JkZ+v GFq񇼔 |hW_G6ӊq{Ȇl2Á3kU# ;0: *;ɻLr&%6.%qiYC3QVf9WMx8{6/&aXN MLq  CL|Jݟ0\pCEEsK!졺vΒ9%-u.]EpM lE_KUt&sA];Q9@tzx ;EbloA){"I@8b}x2:φ;ɒw f ӆMsf(wvPl8ʁ)-!(TV\dciW-qwc֙~3ҖPL;=NyA]jE3K]>,9e3=oezVxʐAcܪө`{)ױNEM$*.͔)`X[_fē-[epG[M o^hvhζ-+WFMoT0=o{r@HQkpn0xrbwg1a$ƻ TH%`$q]CB:cҘU7',K8Gp-&m!0:.W K7ι5! /Xr^g-Mi+@}d9/-& yF7dP~ 4UgIAPN){.bz"qɬY:m-IY)V1D\$gCyڞ"ˮ&ܣ͓$\Nŭqv/b/MmQq^A8:*qQVCArb5^S}?g/C 0QVKu/ǹ0 .SLЬ2ĈmgE6]ENPvYvxK!?ܥb2zJnNt࿹#$o{*G,ϡ#oQSK*S&!Y쏡|+5! I$M2Z[M;3ΉRoR_?)#:N)-O`Vp\'+ 1Q- q7S/ @.L𙳓X& 91+Mh) ?+qcv,;:w :«it6{b w{;&RA|XˏzjLiPR.p;G۱{s')pSn4rGMrp#i?°yV}A]]bm0"%;jYjy sv͇*Tn:A"Rۍ0@612j后C/kw8oA:wcUVW3B$&ktY !-s|EUid1\t@J *Y|9>p=ṈQ6KCFI2$MG&;$֠%y^c(8RoxL W6@]XB,@ 嬲 rXN՗{I8F̦Ȍup0_wCTlÆ6UeMrl\,vb9 r`۽(Yf.k^X1t,j+H : aMJ=Ggh? k;d#$ ʓVĨ=A0LCuI"qy)fmhC͵-Z!w K)S贈A.#*+s.RhŬJ>?3Z{'F*eϷ0̏JŠ *RL?vCV%4'po`m-%aVR p40c"O+[_Dز,{m) _p4RBy~W?iSZ$I7P -T$I/m֮rb3Pn&nxV0(E Y2@^ϓw/]`ebs$lNGͳV f[uSa.Tʬ$EB`HY2]/eêJ%BOhkH[5q.} -f*lQKIߏ vt`]DiT>@o X* и3TjO3a f)9KF!\J荮R$g@)WUZ qU#lVA;0v ui;cy[P;4 3(nX|CYUJ TbRlG0XR9L@ +{3)jw Go2>ʭquTџl:}QȎG 0UءJKh*ԩVJ+_y*{"P3z$Em+$ȆP_<_:.fx-g.@l `wwr¶2q`PKD2NTZL^i ⳙn T.% p~ruYiL/NG%6N|=)al7@H"%z1LrxmGR`O ˚My9+MЦ ݰb)U +mVs#<|J<NT Nը|l}{ˇzrK 6CF es5dw1oY\4̰`0*JOvc& "wMoYC,Օ'Is$(:ȶUŬn:Ug*'vi$KEiJHDK G,A) -GGKQ94ZE@oQ</@xm2p$i] yeNu@R`ɻ|ROuܙ N+­ TYAMᇞl\; ؖavlM\ovl7yGPSVJr-=C&21jI1f#JvMO]*^!gG M Qrii׈:ךrbdc4fQ%P&▻t& %͆UBx> Oٟ-ja |Ģy?7%áy<К(}(!_C E;6DZ(c(uIڙlxZܕ3hItY:Js6Ļb{iqlf m=E2愭;wӤȜ5'싷} 2LLr;[erHc &=Aaע^u; G!K~wQdm+/'؝}+sB|$-.6v=H QXPj|Fȯa} K?YjEnK&tĢqUc8oU<-.u϶: 7EY#Xo:"3'p3#O0Y6!w) b?ڛUW}U'Q#_pͭ;,hѳ)p (3/O'۰MNu%v<,lD7@^\ 7mAqBnPMσh bD|LQj}ȼuy'߀X%މ$vLAb^|H,ܝj' ObCX |x_B Q9"+pn_D iA~ljcNpq HQw-^V*jJ+ q6&p8lfkaJ1f[Py$yN&KU1ɋWb+a5W &eP[C:xoiwM4!8LYDWEBFGUOo~TL{^1 >X#efoe9RlѕrqU & j7$;Xqׇfil̃W˻SrϾT"^Ջ"Vr u6;0R;dŴ+ƇM?nMx!0.Xc~x*=u陚븥FTo"3;Y`uXNA P2).:Xv~%B+ub$ׯ{E}8!:8q0F3 MkQQ rc^-SΨ]Y]X9ɕԄOa=yPjk?0?J$djm{>^8ʡH KM#4(Ą>@y? ֹSmվoÖ(oaqxS|NKĤ= .ֲC1jә%D(&y@7&NmA}8=rSQHi!DΌ/Y#:A/\p'qFb* 9/g1qu\39ԺJ1X* Ɠ0,5ڣFQ=hwh^c;6M1AdAۑîmո*ijB\ECyo;&}pbq@=\alN0+r1曣9Όv{ t ɴ N|w {O%?BSi;Gr5oŅ;/u7٩9[We 1c3HA{'.[ܒ!']ÊGyK, bZܪ$0"(;LNn;Y/,HTM9}űmUvñ9d #쨜ASlLX儿$RvB=Տl[RNS j\ˡ{H*8ۼT0^n@}3b|\ o) z.a"><ҎZa:ުIҍln&@<$ \a_*8بGf[id.}fKn2#}EJ8#L>[L=Ve h9{}rsʝS1@ %9lq8 Hl=.`=m?Iez8mBs9}MY} fIW(] M،NIzc59Ydi7SXbf۩VҐ5SZ 'hqڗy7I%BeqXrl' r\5 6VI졕E[վU4dJVGeN߬%("B$JK7(.rQ?| BA z*;.{eO2c6J=evflXNW"JZ9%ʷ)LDqf˳?dض{lծ":asguKcmrVWv߁=sR/*mLeP'tL|; ˮ+!He՗-hNEi쎨C[pn茛@.\ ׃P~"m2Dd8pP&|-;W!qwmS6LjI3ӈvq,9Ȳ4oOϏꜵy๪\B!,ؖQ5A=4#Qm7+@05O; 9DɅXC㓦@oטm#^ecujM9o> Y%xt<#Z~]Iy:Ӂi$3;eU;3XChnK<doP&[Qs>qr~ۛ7$V3XQrЈwxj%`3KW~sZx݂}eo,A@gO.ȦSaKqoQc\\>gXG#@k=珝 !3|CӮtzcPƧ+Y=؟P]t2Wݭ^{ߞ YMp art{9bdl8!}3&Uפnq;H $x<=봟gݮǞ@=1&eXߦƒal1Q;;u'rh! `z@|f7FFqe; < &-Xy(vexZrÐ|tWؘ4@> ;KJ2%ys~}P\ Ꮋ2Ya:l=<lՏ cSb; V܋iQsnjNl6ynmeyb?V Io1pDݣIkGU)5}ƭ7Ԙy/<(ֶ52I "[/ |=hPd1l~˾s^U!%)P ]Π:Lď6Uo_rB('c,rʀ?bz(ctDx" 8ϡfX6,I]!3+qɦpB8l;!W˕x47t]F|ƥѲ.jb)7%j)[- Ϗ7u v?9GV5uL&'Y"MP940gEFݨ4c}gʡ)"1Kp…D"瘳īx2즺p0ȳgKIe&4`a%yt@~>狇z~jo/l|9~(bH D <9F\,@nR!k,Yr|H94 'wk}Z`[i#kʹl}ֈ/6sW*˃Q:r6ip@X=h6ؼDu{_B3XBFxX|RiI<>KnSȹUJ9DrY׌|&ouqEkQ7[!G ,V. M4lhYXdrV?նy;o=۶!TyJLb@*¾vR5]π>>EJirŞˠ5Mº܄$IE+ywr6n4=c\*$P9 sw3|Ǥm ),*'ݼ ȯy5DcYϹa̲ocE?*QG?ĠADq.)ish_?ukLjc~MqM;a`O0 3v}xЄ=VZ$+pNZxũtG $7( 0FY.ni4W Vʈcz9,*"_R/3M6ݳ~8vGixGh\[i;tbx%\Xh^Cs[Gy]׫pO%l¯U<&4iקE>|~ ̮:09O_w86Yr'GtׅMvp/'vK<ʇ)2@%h*qI- UU[SI|^64'sC"/-X|%;y܏rvQfyD4o0XeE ՒWӖT ]u偘U=Jrrsm/p^BHւYzP=8M)(*zYlUGԧ=gF UPPpO9:Y9,#۰ 0 $ Z6)-U.ie vls '`d}ֵ+*7U\?EК70LYbܮb*8S.\As4yC=1Ӓ{sTfE'tѮo8!rهբYYA ҵ?L" m :4&OXVL`-uUN)SG`\Oo -u-d#Z sG wHˑT{AcogwE&mY[Y!?Lc vɁ+SK6~ c5XtX$H }v:mb8saNM!u1Wm}.O$~HK\*2O ҳĈlR78& 85?9w6:Ii:9/u7{NC&, 1%m٪JWOZ,O풲Pܝ( [3mڹˬ9aOۉœf?L ]ÎjR3tɎFq7`խ3~V‘ޞN"2sXIG :ɶclүn]݂?Ը&rjeORXkv5SUkiQ_j|s>xv\vhܹeCEf,m*ƪ/)U=jQjB< \X%4Vtan)Dh˓=YN#y?ζ{/B}{%ZPNr==7sL[ wɥdaH=mї\sȖ""fWє qD86XWgV5]Jah~Z3ZŠr}m_s)(z# GMIzdQ9OUh?oGZJ{>Ak~ GGT氲f'%sXlV [+Ӛ<T=9Yl'.Xcid'̙,AkY kSΧ|cn I@xY3Z8rv6܎ bn$I`"lv;}1V3b;;r>b r܉Bi$ 9!{vwJlո}SorVwļWWǫ+1ะrEBZ[͋H0NJhYvuSʑas0U;pMXy1pt[%Գo:H.Yj Mrs%=XN}^r8+m5 /$0WVAsAoExʌgtc'ݛx H48C;Ɉ&;f۽H%A8vpGufx>Ԩ3 038KכIlzQpZjUd\aUENnh6[y;q#s1lAIkCX`tW;RfIm,%2nP~-tgGw`ۨ9 a9;@;77}W$HC"eV'nJ絸Ny1f6pk3}d ]tҖ"M6{we圤.g `(UrթRSxV9F|:57y oNj:7+t'(ϮlTvK.YY8Ϻvm&=-[q(yh'tp0{׊9SJ9b MeoHt"Fgmx<$ۍSwY=XTNJZEG)&EIq4؂+0)CWi1+5CittaG(՚DXH9f@aI`CNrCi/XI4$#qǝqh"O>8g.gU-DUc\fގ}uyo)0$4pJ}dE@[58I@x,:>Hky؀yծ1LJ,[HK"kdnm66JHa.ЋVu;=}iGɢ,eS;N-sKvKive-ǥtZG6Uxrm9%@8a(NZ.?s!`F+ YhWND)J2t^eKx]*v}+A[Ms&0#Gtp{@sZ sJDrg!iGf T@C^q P!wrg,eɾiib5!ScxRd˵Y26!+a=qX$광;g_0x xGD89T&Clw'0X3S6x${T"v.}Ž%.)-qI8uvTɣ~Q?&GpwmcA9[V3q|5:)Uv'!>:;*A~T8>}zU@t,K!봼qwDcw 65BG \,[I /{`]!=2،xNWD`'(6ǘZSL[vLO r{`pu{5tP t:ұ颞KH6 ~ƱbYND|+NYUנ`'1`Jvu1l ,:9Ǘj9UT?nv #Iv?؈*Q^Z|_L9;쒬q%3!>MK4 δ_T8g5WM'D7HVpwjE) 挜 @9镝o rO{ #8<frJR~Sf`GUn_LJDa!4 qT楔Ul%`6gdL_1G9M;E545M}4em^֜61Kki\r(1Verm)FY. JREg)d;H/>akYSCwuUyALÑs[rTI,g"!``9; E/dcCpbUqɪl5yp[TȌ+Kz(Wφ?R^KUK Ex ]?<534Tj=JY;RMw9kVmv^4 10³qe/m` *mfNB CS)*bM0^},nٶğZ@F؎Bʒ(3iǏ8 |8nN"5S-ͥ8yg4bPΥ_|>6if킆'cUIad'Tzy:Ϊi˹lFe1\8Fl)!Gb^-H}%b$mnV~loִ(F+ٶ } ;-r J[97Ur)YӓL:]Zt%goj&lxQͶgYmJz@uBqr e]J`I٣xfyS0ܒuv:K`w)ެdR(i^ú mJ^!؜WA,{NU 6O0 B^jNe9c +1|'>:u[m)|UCP58φj/kZ5pmQs3KmUY'(m_Vl Jo8J!!%&}Nʢp+z9+ݲ cWkr#kvlT=ș gVhLalyIr5J Bƴ?+A$~9䓳0i1v{Z2 ;-`!RKţˎ^~Z)]N5sZreY\ץƟE ?qj0'̭۰ʝ+Ji/zxxr;q)=&1V-\m>bmԡp 77͖$ו<_Ь{@#=3(5)[ݒLD/2YU$zO7 xdЈ<{Nk:Vojh8 ysjںt̢,xj~ov3Py.X3UHnjNǒ HŔrp%S!L=OaìwA%(q!➂}"."m}DSW7m_jcMHz^4HS>0nqɉ.38aaʂUKCAP=wހ4iߧ)[Rh*|7|)a2 Tb^O,lM_jkaA0|Vȱ j}L*x>I&1%7.4hEE̪`2|#ovi![!ltz:S kN yL 5eWK2wImAX]Zȫ孁k*vnEC+y+p ~j^a,uɤv ,W1gWx-sH]JJv G;o.ى6r(*ϨRkiw eɲRCzsCtM'8]c6"cY {1L{!c5*Mi7Eut\2ۣJ gr쎶KG81f_"|rىsY-7dٮK4٭ t3;u;@VK:3 -$ m6!KYYީ+P0kp t):UDžO5d.b-U)ߗn]Z^!_m@n &lG_Tb 7᤿Q%/Wlk"RU>^|]-ɾ$]E]u"kr -oU@`">Sx!w.[)PZ$}فr揝j Ĭ#aRp <{qXx/',p`0JnndRwE1tmVKb|Xc.0qy \FAʾ(ukeY0 c4nбC]b|_ EtMև輐6pGU 1!Y} L WbcgxlT˽S+ŜsE=l1T@Zm%Po+&/Z `h_XZTXGd/ysqq{t=RPMkqG,OpdNK { HfLY"j(i &8v3_Ťy#>ƤxlN (qpvoؘHPyd2 VkrLM W2bxٖqcE?C¸]Pǩ\H|F&-ʮnD Z}K|%L.L`1llbrhsLS5mᓏPg?x7|[kT?hj*)7*X@\B<+2" NBL;О?axiblI=2YVfZl:u9q˔t 2-щߵ>-4jtûvߎ|ZC5#";8]|)vx N2$mZ6l=mӸ/ƹ4YrO' Ui (e/X 6X}QNKA$2d]:4O D4 A-rM!luT6#xm^nprDʴ霝X)}%É֬+R܅y?نdY?<,_eka\L3I#1[hڪ ZMc|S Ҙr,K[HYVlUu.N۵I\~<3 Yt)b{DY"1I΢pi%5̠9ExQځEa9o}TmG}qjQ&y6:\%.᭦VMRT&+A<&Io>Qr$o1C:.k$BS 6߶9͛!Q#sj'.k_+~Z4 Ӯ!Q[q"߄={HJ)$&`$ersrT^Ξ бR],cj7).dr*zvo|vuE1:o3f6v@w0 ^̕pGL-=e֏LGlÄ Tmx|D5lۗFqg{j9W"X9!td1]a"ie @dkmdj.~`z+>hThQTΌ @>%;&DS ?b-6k3/MẢq^C?rekW@/T"&WDa:-Y2bWqgL٣ܒR !=lΝco<Ûktg_ްZiqk%|0PvE @XBSMA*+ϪKլ3ќxJsfo~Qn.QLOlT||tk8{Q* _7`{5H4ǂ87>Z\BXCj{eB훢{[IΏ,kpvMpMkq0tec7Y0=r̿L0IY39W) K1N;><8Y<`ڜoc^KE:q-9mia[ڌ[p9m8杂TR=,EtVZk4%svx/,k1PX}8HtN9٢5"%F< ^F3EWx6|oSRBK@x=~5OՀƘ[7aJxAM=F8IrԎX4vz M, F,OĞ6fǁ>xӞE⬲ΨmTv:n%BI83O+;W#lǁK?pr8 G1ageI})w75MuQk( ip*NKSwHO-K1?rrmȚɻO< YTi[r4X*L]ыN%e羨ұʽRfE +ď$- 2[,xFKYFu՜6\$spr; gs=->):YخKsPef<>XKfSϦR@ƌK.@o>-nv' vK8]N^=K*}ԉ%.pVM0E(> "5O{!<*qw@l"u S x K  PY ;_#q,w S(>^ֱ ՙ#)9E>zɡ(z1v9,y2pRE-Q:!ɕT;S aLkCMʢ>X29Hc6eKَ{gHcS8 x`m%N}UR`}ZäVGfSԸ-qNg;X8l}'nyҷQ'XXjiqIA?t!.-_,_|fy % 8%>n?h9Ѐ뱼NRV4B $[7'D=2ŷIbkoBo@\2&yaymq f|͂GJqM f YIht.rTtJ;.($ w>ET/]Yn9&;V5Ub>?[3-Iv9 wt 's)} %q6`+:<19N]d}VƝ\eRWYxN6BVaU]a#ԓʼn:<6*X#ylEc6j X+m)F3B1-ﰉlY/UQZ%Bo6P߱MUr'O)xk*\Yb2s_Zlfd(Ey${Ps1 $U1K {`yZne3n+5z`V\Fdg*q5s1RPɩ_ ϻ{Mo:(pi #+|G_;WcP&Kp EZvT4KȞwNTʍwbPMj6 TJިdIP*OGe>;{gWQ ۤPc>f98쩽6њ5䩒"Nm;Ixҹ9mjwgƌmu޶޻emFSm:N:8jߒC>!P?pM(M2l7Yy?;%Nm\,|1kb)kV`f>q:<'qmZ,0UhRUK&|,&AHG{Isͺ`c_l0)✟gZkLU 6i5MՍeN%Ϗ<|*`Z K,UARy}SȞI-&۵fmŁ.䭇&aQ)r$s۫SIqsaۛ&|Ԝ{F2yZv,jйceίT ٙ3;mzto4OP*X7~؅dIGqYkDN6 $sd 'weMԪ榞VD:TW΂ lw[KƱBV,]iC幏yq}6w CQt{ /@No(}Sa7vEb鯧55Tk!8)ob|L82-Fbo}r i>q0%l Ly8TƗtU7)f8`vF&oq $ p[!4H;VӘ1ORtt޴s߬}{86Pk՟>4my6߮!gZrM>-=Rۇg?ͧE!-|K;?Y_!̲m[ vKC,Z\S/$'Bb d6kFߖyyuHq.R:4Yqafո ؋r7ѧ-q{kHz[ -á>eU:Q-q=\X"q++#)sJyY҃(,)e#[p#tm Zrf.Le x5V8DXOZ ԫ aZ)^ʢJB/l[:R&kt]W{=ՄҢ+dƎ;lE X7y% h)@q+KM>paVF,Vۃ3B+aol&Y7pQ* &Ԩ4&V!n-.ܡ4$RԊBw^qz|S. \,EwYhhU[ހUu~L50мy>N;h1tjSp$DOM!wy<ٱ-)IHu3xSM$%^kpB r}SVљ,8J Hc ~CkqD$}ls|^5}lҩ~w#!7$~R& 5q[Y[azmbWR~<U[|jg<cK9w03Xu[ 0UU`; NFcUqфStuLgifU1oI샿Gg m9'}rG' Fۢx܈fq̖Z H[%@M,hӍM-۫oi pic U!0=W͖h"E7,l6Ev[ aV+ǎٟ9m-g +2EquǞd2Թ':jX᫉3ɵLǜmgikKZeul6J$ &38 @KOFzlqȌ@3ü&H1}ngCgh^M?`bSMIbM$c Кy8lW ]+Z$[̝{dimP{<8'|)x7rcQ9 rD p3J;OJŘ?:]u(u_R$DS(ND*_ZԼY,8 y~-s_aQZ{)iK&SŤ K K (6͉q>y3͑A S*GDkUY 89Fxc"uUr \g_6.VXZ:|UϥiD:gru-o^2(7@dk0R_E (/[ 4{>T<%G0q jrQYIۭ,YǢf%dl?7Vn.I]uQe>`K8$6M;zE FfNp&E8Y̔΁ i]VaKMJ4K#Qɱ#v43Q$rbVO_ᖴρpiIY7W<B4`AĄw +8Ĭbњ+ќMLIh#Ilzy韶m?||=/y͛woc___?M&?^~yW3M|ɛz~ߌo7훗Oz߽/!_}?~͛O{/߽||k~e_|S>G;ͿYWop_o~{jo_؟~7~Z7oӛ˧?w?|ӟo߿}7_{W}{Y|Wz߾/o믭5"|᫏_7o~W߼޼K/>|?yÒ7i7o}o7//o_~77/x|]G_vwNoV_a ݗopAᛗ|I x?b~.7?~/ zŻo>/b~-.׋է!Wۯ~k\';\WlX{˧o~W}n_Q_?~w=_vͿ|͕ ~].w/m~mGv?l[F?fg,x[;_n͕OV?Z)lg'+?W*T~=ꏶ~ ?v.7oq_>O??ͯtYyK[߹o_>}ዿ.~ûq?|ߏ}_nû?ez}{7{8>~yN跿/wsu>^x-| nvrO~z7;;rw-z_h!N.û///?x@囟Qo~otR߿{CG3<W?.ژ}?9_:a@Yvǿ>:twN]q|w//{jۖtHNFBTy+d͞>E4j_mmC|gR]Hv&gT4Wұ4ؖ@vFKz/5::H f&CBsb zڜ+<9%ThNuKHbaѭuGK$;f- njg$M{ R+9 'U"o%I:\cQ)'U[*{#ӓCWsO<$l,tK J߮u;뭂"m(vc:W3mA6 񫥻n!54^TO6k+#%wJr6rn} dq{EMrvNK'8g vUV\VKJ.DH ]Mһ )|KXZ,PjcOKϜ,BKp -vtpGㅂ a4}E50$= >jCuꄨ|`g?' V8aܥ\w\a:Q?%ԋnshǢnw'N-@eNMrni\&Mrj):OͻrٓW,-xb؞vjQp?psko}*'0`yÚcy[`h*̖o1f<*UW?iK(}^HmkE~VsFl-U^1lDo, aTW@"8(l`;!Zzd p"i˲i@S;+7kƪI*wȶW/Z}zWY1&J x\'^c<>]ù[j$q@6_k @E 6W0;Q^WULd5FO\XNv,_o>En3)piwsm |*fa66 .|sTDZ 5?ܱ笐06 ;X6L?Woӽ'vFq{rl{dAIM=(cԶ8 3;z V}|d+=SA}edג(0e+Nqr9$#|gHS?<zrcܡJ{}qsS?ٞkt}ڬt_AM_tح`b'*)ovKMJ V qc:<=b=XQ(ʧ=k $eA0+ʣP0́? x@lxB{Fykޥa ݙqe!\3cKTUr0q&R*Nrja$P(p<;װTrtN%%Ae@n 9"}YQnɉ })Q_C=faAA)gv$MNQ s}$$dmx-IZ]US7<672rw,8J;ٹն#$Tdx^Κ-o}Nw%8Uй J]nPqUYŠ/hh.X@d0]Z Ca SW|aq:"&(nsSn] Ӗ(MK zU2K3wJc쪡6ܼ3]xm|'ky|p*ng$vJ:nj^9r|h&t{վ_ S%PBJf ^l G*^zTц綇5Q!A$[8I:Sl*.G7,q<ٵz,2!B){B]ćkHjL!HsŮ)m2DrXN{F~]nŁOq'Y?Lէ岥Kh:2j(MR̀w"jur-R>GHJ| 3j,:v0qlG~䞯<UtDn9e!,µeX=<0m*7\J@x*̾_k*1Jϓ>dU ᡩ!u'ba*gBf3h`!+48$h$O̖s*+?h NmbX#gFAwnG`;*G1$ts~b}P?)S"3.,Q Y,>M T{.$6f,%ߥ zy$n"xlFpj:'lshYYp0[-L8 dOd*Y ڈi]%>^ڐ-.R|nW$`ktnjW豛0_gP7~D.f4lPӐL"; [|nJܲY!oj 9Rܝc+rO i'axG5q^ؙtiSC> #kU9Rc30D`ާHA pQV3-D%YpWsup'U0ܪ*?Rx=%GPo爧c%FJEqWf #SI)r Ɲ>CYBTVWbZ$@7}9"9֡羘Ud% (<(mISr[QK䐒Vyi@W]m$wwJN~o@ Fk9y=DNI"QQl|8W]3G.,.ʆ _5;/ݭJjB7|]bΚrkܥGؽ볼C 8ƻId!iࣦYbqeT\4'Zq9Ÿ I7/ yA_BFS<*݆i hŁH9\876MtGG0)J,Td =;~EDfrpbb?9 EW~rRG\LXNwg|w3ΧpJAɟ8-䧺ASDRƘ3.Ll(e.9Lpɳ3W^&N@T{+ٔ,ph"q%' *?1\2 GAǍsVŗmv]F}üc Y`ոJP1 ~dL^f52%6ؼ/%'5~i vDJ\B7ft+&IJ{9ztI@ Mb0fe;t{6_fn^eJgdO[طtʭs)0]1z)"q.6E846iI :1@>ʍQ6U#O>A:<[He^\e\Qni@^,8S؜M ^^i|;NXe5GoatF#J'c y_b]OnE-Uթ'6&W|n<եG"Պ/o8JȂb^Cr[I(wrG8ͻ'T9{U6=8sk[+=nK&WB@v{Pra-s. ]&Fzk[??P[ 6O䖃(bK³$}\1$&ߢ> c{3 H(MVu%&lc%=y,&w6.B4f)܄I"5@+|A8:7e˭L z^* &;TzȪ4Uhf/$a6n)x췠چ2*mGHes )C‹m`iJN}x:"4MMJ'?;0ŜF캪p#\;ug[JjI*'d;̩U/fĥhı&߃Tm7@<`&"C~-B3xh Sb{ʰŒ5ДZdl{WDIK҃;1cn$8욘܆(fBS7Hi8L@9N pFǗd-bť[n}9o:W66%{ZJ(x,z?_&m&{Ѓ%h0[dsVL7N"3MD&[ x Į#IdfHUm5YYnSO^i' 6o񱣷ɔ'3;؈Xe2W8x[TnPs}. ~ra/[Zr7!ɱ0C6>l]MN# ;.L8+a$)? 1Gy3>Wlbd Qd k4=@U*ږMqMrYNb'YR_<)j7<عp d6]лm6;JBdPZ+͘UGWeb?l~TvNd^"SJLهwD<o).)}ʫn<~<*k>S{<%Nq,!$ۑ n/ƁC۪g.l6b(,İJ75|b~*jtdDڻn|-VSLiZgOQai8Atҿzsk6I}H*c1pxJ'ԸlYƷ3dnI|#{*U|OY>+8r/9ce;+}Mw.4xs÷={ƕu'~c9€=5%+B͢{)@e,L\KC7.[`j"~TԒ0f2}b޻CL"a"@/>r8˴C+d,p)ɬC|nu4NX>VDAuxòƹ/,FJYSvn~.wةxI.^w0AR M-v2*3m;9LuYI[ <՝,}RH'5j{JځG<=)lb(^} 4^F6FU-x1 )++FcGG*MaSs ZJ~&JݻB1{)W $GZAL8%NPlySرoa,v Dv=G k#T]ݟ]WoXd$QN4H 6 0Ksjw]ɎƦ!SN 7,%I$+YsdԂA#!Tr{>d) D & R -9`j[}ц&0ΦM _PcڧJAߥ8=TA8=g<`|^UbMl2?6feV{N HDxB3l O]*4;n%ְ9c5b-6g3$+XQɭtKe[wE4Hw1hƼ!Ȃ51BG>2Uϝ ٛ=-\a&UgP4]tHձ%HO5{t81`-ϵEAݑ++pY (LA#XP7GI̝Eblb9s.v=)q3D-JȾoNyon `LB~c58u2B[2&3A`foWMrܳIA@sX-}?7D ]I^| 1Sr)0LG/CJ8U8"-$8:t܀CNd 'ʏݜ 7*8s'﮴PYG[j+~d ՎHc\C@mK6nņPlox(OUR1;6uz0 X]l[[z8A&dй`ckDljL 9h ػbՀht҃-rQslhᔏQvP0,>MJۼA6jwў[i"zE@Qq1m$"{y5zsUT?̑'CfBz}2W5EzMx+ $?\n4jjFX6vg^/ :v9kʚS,a?5`4,>_ml.vpf!}/Y3 ΦHT7e/ҭPo3'e_!PqImMRSTLQ ÉTXI6wَ\a+wGǡ@Jp%<5Mwbq.b``tƛtҜ78ʢ|pdM;Zsڝ){VaAXrb  +0Ƀ }0]TvUf m,:7hAy.xi WM`sscLq aěF7ⰿٹߨ$C [$`՝u=ٺA-QevT<EqJQpߕt83C7EĢ]seXNIJ{2CYx(QOS%W*3>݆/҃af5!"K]JZ7 4P{UVEämq_ђc|&0RT Yq ؤgs_D9NX +rJ_AP,Jq9T'" %cݡ'Eg!F֞8jVp+0T,:C7fh!1†Dqbf 3p\هaSH+6a&X^! ѹJD:%0hB]y"agTsRZbL<,DP"4G?Jj Iםf: / plKR;nUўbOnՃmx.{T %"3^D4j)3t,F{U<6;1|чl`Ku3bUkKZdO:-.KPv\%Lq9FH5F;^z4/4%IkC 붸; S-:Re1*&Q9MEԝ wФ;NWG.^9oE8L(vLs>hqCN±^ QۓT.CfAZ'EM{<}cX>\kYCIxtvV ?n떍Q,j|q,6T|'KΟŎG`X+JX9zXUGT$K(]kkCHNlkl;"⬚]@FطCmuZ,]e)(A#ΗKpbз6-y<^La#*};ܮďy%S\RQ5-yg#qR}i0ǝ9 D&^Yr؈Vќv<@ϱof‘Հpq**) UꖮYΫ?"*Y'EwAlN{Ll)rxC*i٤ KE!OnSaulk@9ꁰ#veA Xk|HZ[6 $<m9 2ֆN!'k^[: _}.4cwg$%0|FbpQlCZOkȼ@֬>[=8e5R\Nl+Yfwl.&H+[;Hl 5^/L1\8k%NzN"eYp<8Is:l!d].pfuHwfKp@Є,E%&2sgA6-K|>Oi\m!C'0Z4|o`6#Q݂"9uc/?€vfgRe}dᮕ نSvCUʴ(UWpGB^͒-_ͳ <ey)+AĸzXlbc\IZ6)f)KGkYGvl;(dsg[3$cM@S{)1[-#0DWFnH"rx% ᳻Xs|zvorl9IDUzCEh_:ߤ ٓ orjhe=QVwGD[dc!.XjɆyx.l<{/Lz0p#EBt/lsFn^i<_E?\Cp+: dXaBG 1NQc t~J_ '"mD;&44G,TR:ȸeTvmJ;Wbkwߞ" >c<*YƩY2̧8$v $xsh g2?G7fݹ.X`- |L1"=5ĕU)%Q EԉqL21V=k (E496@XmLwaOEai:0#?+Xu^A 6 H@hX:`K;[Z$=7tƚk ZP"d_*"Zr MA\1SEZCBYPAJakZ{آsMwJ2`$"Eܥ.NzBf[QsBZQ]6[i'ʳJ@|``gs@MW7 p-6hA@[W\xa};/Ki猰:}zK (8D<=X)Ą0RyѧÔSYjO=E^ou'IҢ_}6aMIf6l 5Aj 0'N3r̞q9)qĐ?Gٞ 'Ij}`42.}#lUGN8#Sy4sVðF*&gy'Tc-mOtnam)nJ,W(Cm ~-GnC")!@SHb$+8p|!BYd"I3|s;ynAMK4o#rح&a5ǻW.R)``!2שf:9"L~3<% 8E"VQXuKݚ=ƛejict;ݨXd xbt%@C3YjSW89AfJ >H#PyCXa' G /0ƃ#1g?nÔS,cJgS b=c,ZGsŤ˦G|/AX)ky.6d!MH0I>Unj&(TJl]',C{uiuOqEV.-b`MxPCMx@H0{HHha5qlm*y&jVI筞ylqXEV(ږmF+dFf}kWִZ19iw֚cX4R`jeS4OF=0}_]>J;q=ߕ!Ω:9A-uN6KcMbl8>a8- ٥O $a&MlE4GɹѷqR ~u{*ÉЊDqD6N+i>tѨ8NXPˡ]LN@~ViqIsfh7T<|Kcy6P|` 9(), V{Y3<pPoN k;QpiJXh8uu8n\%M &;a>7`@kEbT0KNLF_YO_dF Xٙ, |O !>e`k'IFJ0EJl%j79}o*.>>W 4d.7K&gpE$*qoD#*ﮭܧZEMjm265ɡmIqԎܐM:zf@.L݄:}W3?m3Hj'Lr?Cz4t2J$3.\9lPשm_"=3Όُũ54wmMޘw€ގ` ds6=LK÷!UG Le[C;GiGٴ;ӴtU9(]ES;x==Ghܭ'}Vu9KXθ[ElCgt:d2-OgNS5vc/x:`mRꖵ8ݯ˙(Z3BpKWA%;Pn; (NYmSFF,)˙ȩ< ohPdb`湜]RrrڂұDi6!~;WD^CQa:;e jJqKlF]Kn碁ㆍ`KeCy1,7,9JD?)ŕX[lue"Q+{Hb1cծF*l5Ǎ=.۔x\nlhsNElWl$\Xs 7-GE]b4NԔ0/$u]XRYeluڣM6pi$fQ= #ΑܯRR6>DIa⼋M1͞j7$$4 6ۮ86uvjm9 sD;@q7<&W%IcsyrljS|wz3mI5lf<%:M4gڢ0x@ЀT4Ag^H9$UzgB(F-`9k<lp|=eAmx['1߀MvUN.lU v$׼Ƶvºct-)ZpU# ؓ}R?] X[v7?,:NO1M)JvaRVμ?a#bQxq]4GԌU[崅|'ܡxmx>0"vYaxG-nMI(SIl˙T JwYXL><Φq5m7TX"])) ߲a 7̩`%3CѷV3=.`,8i;9v͝bnXM*)B/h^9l4+go&Q0!Bpx7n`:|S]^RzBBfTtbr;YVGX5s@,8I³|%l[U@KKFfxxJQ"#$y9+XSr"QqYbbvEX}]':.պ1/nPp KpWEd8UVAd'Rɇ|M*qcjOkZ|ZISaQ)0̉2vNE˱)˭4V l4<7s'@l3#i*{5l$VSdjPā"Aۧ-9٫"7]C Q|dw0oYH0x?Ao%2f%y)%!l]K Qd&KM$Y<ϣrlESRyoİ31$CI;jVZecSbg$UH)Mmz'l=겡ghm>P?\,%ť튁36Rz#w#珒^gnrx: Xtd35}n`$A6;qc[:+j;8xJQ$,iB=څkrdQ >䒫 ɜ!xsLWsk؝'Ҏp/'%DT}`@t敘}.r%ξۊ9Oo!֒-vD7| gj!cKe;y1m>RJhr撝d㼤@AaP}U0B65 '}+a#@RO#A& .YKpܪqjY{WʻQ@hwjQf8/biX"zS%@USIgNAmQyx,B/krp,vn PM 4*7NE_VAr(NH,Im5IZ%KlW>5<#ˣ\E(Q~๥dU7WlF e4mis@NN'Ѱey:qsmu m91q`0d!l;vei*Ը2tXv[xWbq Wr rXض P9l:ߎx1NQ6^>%)Z#I™ǞxaT(r fjʽI=n UA +A .|il* V^)机͈3o5υ .;1",'klO~;e +=V0|QKkqs0xF83Cl{'LN\@-_cx4F櫫] _ɞ/mg g?e/fIDF^6m$dق>[i)R;'&gNˍwGǝvʇ{u2r2a#?lQ΄F퐻jro:Oe%39SrSJ<,'F6 5(p066٤TM_)*뇉6\mj~ zRBDJ*J8V )Ä (߭($^|خeQrjc#{-_"HMcbJrv8jwx@S.Qt {Ѹi-8묲!]NJ…b$VU?TH7eoq47.Kd۩DZ_!B6Wб*-}lE}M#%?7 TDƻ nK0f7 Ezu`Dk,Ifm|ݎ5]h ?GW-Mb9Y.rVze+AXK %ܓTaHTNPlg62*֥f16CAlԱlLXF呸LV.WTƛ37jR-jL u5u c'F4l{}oljTvdI94.پlT! Fro~8 ?6c/ ӦVpa a E!`P,/fX33;}sZA]-/+)2eEѳC3.S=&0g(5^Z=5ݖ%'A6ܐ<ٰV asD Io/s8AOޛă G@\7;;aaF⬜Xxe$Ҫ@+bG^SIA@nj0) Z@ru^ә\j+3OU yea8lO3,/۱]DDuuv3A`gwlxlհpsO8; "m$f3~/Q'WVI Dhaxκ~}"L6:򜗽6ۂ ONt/ 9,amfAh|Udڈ%ҫzd klav `cQA22;ӂJٺҟmMogI+±ĶU穰e64ܚ;+9>s_ӾIoVH9&[^3F,D%J3q8$a+v*>&ݱoH'`=A!9:9YÙVreVv>8pV+,KMM˫`em"bo[`E\xkw7] @PeS^r@]QEkb XURUC=lǭ yX$#kH-w/9 SL-w÷GJϒ> Q;TY1GƗ򔍣3 4ls3biT5kj,*lEkDE#dl,_ZQ)tt}<LJpȖ&@a{׶"Bg I F=;34;mvv򯆁R=7c4=LKJ/㦣"e.tus\H 1:.^f`ސ *ʵkQ 0Qfb5\ Pǒ߆kqɓ=۝f>0t]$SĊvdˢ ,lmðR? \MpU4꣸^S|xXܲlԾ2vHr+<6a]][Yg% ˳+簰\>0'hV.4SK rc-K Ož|ė&Wiq%qd愮r" -՜ g@-h+&81ض(I7-R%ƕm#㥧]1X`Bޔ*usg|h]Ҿ8LʇI}ZhIJ҇ Fu42`,.;ؗHd!Y:LgM?@iĕGoC^V!1]&Yb)mCd;TY! Wgyft;ПM_NXYy}K٢s#,sg:봘HE'BBȡ&'޷4r* i8X`,V'6KcZ54bl7U/5")v+cT:b,6D\7 P pmCUoCc#r%.Olj&byNT誣{5ѪruYl$Jdf듦S1[K2 wtPSc|[#>0]_TNEZsOrȬccKf&v"$N),!{Uo4( c @^5Cde{|o.sRSĞe?yvM|e[~(1v'p3~YM. Cvy=8wNaFr2YMCn_j1&ڗd/OȓG6:IQ&&cq\W<ˌ]s@O 3VkTG1T qBdNAhAX 3NRk*z@hlj|A&vN~"sm*q:fdByK-`߀t]u[`'ΞܲZ΅j'o]m&5o kVZc <BXEvɚǐ/C-:]5WJi4؇MyTlK`hfixZ%7ռ[PĈ^8M((\}ovi:N-Oid, R~/o!tmrvu>\3r]{%)ԀmY {Vz:Izac=5>+#l3c vOPBbA~1@\WP{?%>= ,uu aksӢٳŜ|(73p߶}6%'~Ga-q.I~Q6kT1ͨ$ƦFХoS>)q~-TcX`92 &j2\,ʬmט4Y.ێfAg6;#X9jR튂VXୱO8.Un.ةp}&]5 Q՝k *7\dx, 2(RUo-F7;QUENNX< {nyf%(F;,=O`K`g{KuZC;DE5!8Wn5&ϵCYUC2bF+}^)H5VI=7K] )\MWDM\y҃,2Yn`Oa#|fU7gq?rUSXCVvB( 6XjL{wP*e[G&[m,)Gmi!Ϡmѫ!m\m_F![PK7ݪY\/, :]^&/kP.6 }kWQgٵQt{ai~5oT17ο<,Y埁GȔ |t l>.%z Л nV쭓I63]jenD4¡~Np?gA'F"l! l^/#À cQYаFm@D J.[m%ΜA}s P$R NRaR>d (sXzG,lJ*NA C#({zu5 ap/A Tv >-v,`z['pVt@ |\2tbƚJiPrRC>a/gtʠ76/uam\9  +xEV C=wնQ\zCJm/4Ƣ[/ZݔM(q:p΀_1RCTL#t1nN9a[i2i;BF,)m(-!GiFT:[ZS尔+tn9]m鰠P|mM>?"5i+yMa uWYKe P}r z<Y$[̃?'$ȋt o 6:tU~Ӗ>`{Mi&9 h" >JT22Uwx2 lcmU!q N\b5|IE0Y;N!+ eb\>^ׁ7FHWr\iv@ѧdC{{NX\m訕#%WL)%]3ʷ=~ϒ:<5U zG3.~χ GlE,:OW-AnjhZYGLM8l?0Ȝvg@٢r#vؾfJsK2 bx XANS$zaY@j\T6D1yVTlť!ؗOJ%*[?j },%xd#ɿ Rq^3Cݚ}4XE#tFȷġq|EIo-=菢$2FKR96Vݸg? F7;@cs9ѣ[w3\ \Չ'qFn CbfDc~ fC_i[m%LQǹp3.[dEfrl81gͰR*ZDDz/]k\h:p: 6 G wZ3<9o{ ۲i LIvl ,^r0+UmaiȊ,Abϱꥻ}Uf=LtdUa3bt6Wqh21PXl۷Uߝ7!";.P8Sj0Na9f~‰˧Yjs9KkCpKrN]QEp{X?nQ+xHܻg6(VeVC;zj vEV<: :Ж )M,3Yѧt g5Im102N,x'ġyΥܕ8MfzZ=&mE+ӠJVSrޢ"\qZnW"GJ<ް\[$d<~qwW@a9. #&MyŏFDžCՠKmI@@n M)SAɂn CV_}N pN`l6%m.x BJVյN1nlW)=bҳIƘ+Qڮkv&oe({Ǫ8hX[U?L)OFn y.gߕ%ϡXckMj{*l~U x9,"#f[ôS[=qD`q.6T*KfT|L{9=֩зLiIK<͡rsYU2J2FyXYl. ?lM5B/S ,^hVây&FQrH^m-Η7g|%V;_ %z L,`Jp8<iΌOۄeR_ GJh>v'pma͏M@6楚 +ʉC#Lf"j$q0l3h&q.f\Q{FQ%T,;(嬞,VP/a+.jӿ,'QID$YC)m.PAt"×FJl\`q ]oKfʅ$tRq7MF :?=Jj5F:TH{0jq<ش8[c--6m #Y|݋L ۱KyjIԾ 偱Y2&嗪ѮʎHzIZUYmBomIpd} H6 (t M9lWLtWd LOME5qLVV؛ŪXL֜-6:WI߷~&i"L\ `#^M{lC$}ĮW6r\JYAM$'AiT{YBVk4ҭ..x}Bɾ@gY="J++4$V+&蠱,)IChqF7U{Xtsjϯq5Oa"80jgn&]p1 \=;1p<TTlAZQoMr2'lt;M]%ǑhMmA-\ CΡcЖd:vAEEA'dNZw{LbZj+ v7jgqob˾D4pUeOSl AĮSlWv.y"5Uaʊxb*ɴǙTqBnRT |Xce/i6*# ٍ,tBR+z)*$8Z@1X=DY%vj S vLmr~xkӇ,x[DOvLj>¼[B(NIq9Pj9-]T5VNFm4oۖyBQ#P%}`{k$G9AMDձ>SH?`Zv\ l4CѾp?6VC v%W8;00:/=fpZ*EUZ2V4"fI(*.F^6X*Jjj>w[تR8:$N{M (Y_n6!96oʂUQKѿ7{qWIJ침.KU]ĄswPdφtr ß,$k{~vK/U־LgudQ Xv6yPi+y˚e2^8l;OmlB;f5*洟X/( H{ni>5{^ |@X]~QK%LY92ϋS$ylKlK5D f`(" oeio*rtN9ƕ;ZiWFgn cl6&3T2] ' i VVR.OrZv/2ɟ'M8 ;=c!B|a-ʧ,!^^tbYpk6yHNmYN"XJMe.edzN5)E%E0f6Vc v*v|k6X{ A꠼.9-Y`jBzJ|a/T?eǩ(S $+6.ez\N%f"mH,Ia{"N|!*$2hAN'*jdN'BVIVOr4&Kj-Ex7w&]S0|8.l딢)"3ydQ*]ii Cn9PclsN/iW `x*L<~InvK;caЀSJGՅ=?vxpjm$Θ?xMc,@T&p@|l=,LR~V vX$Yl7ʹ<;w}$̈́^y G,-nܥ8>̧x{QYYW4Grz,FÒ JhpGڮ`lqSAyl13GԤ]PٱAN'?}+>/o?}񛷟i۶w߼k _wݾ5>/6i?M<߄7)Y7㷿7Ϳ*o7/}Û{o_Cz?~ś77|^{//_bb|+t~M?|˧︮7oʯ?~x7_zȷp-/\O??~-~wͷ?|}Ӈ~|qO}>˛/~~w{}o^/饰|B~g>|˛ku|}|z7{E_o?|w~Oo{xuͻ__7{돟6'/y|o7^>~/__^=w/~r/_}7?|_.|\D/zK??rg?r'Ƿr/~V}}ngq/ûy{Ot>W}yWz ?߿|ɡ{};vp~z뗟wן/~oW⣗;'?ຓo~Sӟn'?_w?or_~!ݷog/gNrI)\ԿpF_>"/gӑ_:/H/ұH_8H?)#_<3"?g~þϾOox??w/6^]wǫx?~^M?xn8}zGx [o^7]w}z>O7e[]Ooo/s^~ w~z_~Çw"/.|7_XSY;sgOo޿^G(h`t?|yp4~aX꯯[s+}E}}^_q-k}ŵϯx}ŵ+?Z+y}ŵW\y}ŵnk^_ŵe>)};w/_}^>~xu?a-Bן*T?~?xǿw/DO[';o?|9O՗,/l|~GB_?6QzbԾ/D+{}S翫 zoxG~GA/,?N?~?Ab?؟P _oQ- ۷r_(DWśo0|V)8yh׿$uFӇwNKW~çO9;o^^~ն)jeZ2hIAYMnrJ?y)Vsn%u Dc;>ߜʛНBus9P;L8➒cYLyu 3TZT2ߊ᪒4x5uDB_͜b[]oR2j 0ʪ|$.dcQדK8Sq>wkbpdI-g\/eFu.ת|kC_u;e.Q\fu͝Y[)`x5afrX.\4rŴg߮zT?OTDedž%=nOKp5cP 9Ir(~HnX㲔i m.Dg .3] >. doo~ߋNJ=/L=QerQK˲Pf[N%YgrH?ac-kNUݯxt;gxEe=bZ(9ߠ.4+1b~,:(wjq^`iʒ?ۊDǷz*y=C "Yu kBlI|,Ia +ء\}*senxإNmmDbg`:x)5' 4wm_9BػU|l΅aklƜJr8QSd$vcl^IVK\)#:V(6L>@ 8v'`eٱ)?}Nn?=+ju=q˸zCo63&tbxX2&A@@m>Xɏ?)WNS^ȮK5?ZnoϟMkmR*ʇV%>$mW_BpX4{aӖU50l\F҂+7K6* ) zr8ʇ,|KVQ YлBA9/9-.) *X_n_7Vcrgm?i~vCE*<=@Bo]T2vذYUmjgps:ؽC%J e,&r8s&N)@U5:9 iDEDZOak| )wۋKa3 *.Ԭ- $Gʼn N5'"\:HX}neޫsus8ġ+3+%!ю%l\$LSqxD Ze;Օ|Hhp<[^U')9d'm+R y.+0ش,! .u`y񐢬3`j^Ow$M"%]$#wIXX/e]S(ƒ'6@Gⳁd^r#U!څ]p8ͯ^Zʩ@l^,)N񟻀k"j`zl3!Iqʞ+T0.=ְB+ E(X+rIh[-VXnɶEA2TQ9GBInGm=STebooFmXCn[,VydE{eHd }qώnlWPQ pl?f Lq_y:2ÎQ 2n#;lVtWZH'qJ}:Luw-pbJdԺ6HyvñuOkcyQ#xM0eo$(/ ^z/F!&"^J: '$WxKGc:H΅v55D2[cp=K1ĸC:3;h&*S+ 6']OpT=x<5Lq '!\bq 6 :pJ&yр=w*!K +ﵼW=^ #Ƭ`.a;qaT3?j2bH>[5J)pIB> 96 k]& )WJ#Y'aHꡩoQ9#x+v!sWQceOܜ;`.*ΝpxcOwMwl]YM*EmU5ʏzŔ^B6Gwb"Bus4PudT܂7vJ]&}mN6K:!eEd]rK?)|4X;8]ن9!q\.|{#A5ϰ)nD!vyLaDlvڷI w CX-%͆oz@K2iyyC6lQ2[pUfǚWZ`! vZ(y.К8sl 75KU[W&gD6(CWkE* <,a9/ $NSt)82w_ˊOb6gy~ <+a5"KvBC8({IOVki]:X\UOp[HxU"ގs8Mm&jOppjl&!BUvzR)MqLqy qDsKwescS*E9y8HrGo3@b7;?fs/Й~md8)2q]vß~9 (t8**aP b@L=V+>$R{dW?R:|1R{ݼW8Y@9%T&{m, JПײMmR6 [,a:wjWmID@j`%$c.`̠ rTz &鯱ZeL/͆ "r1Y)#TW7\D%lLX>oŌX鸑'HkXͱ8ku;C+VTDcuѾb&;ތ3$Qļ:0(bGV]ݸ[VU,.?DYNvh<]Pˆ쏴ho<5iˏwK9uIc'Lj$tM}%ʥy5$; ,Zyl򈄠IxRfs? p 8TYBJBʼI!"xeǒO$tղVe l1CşddK: sٌ"m QyAm]#m]f*)F^>#2(STfr ufPdS]5mnq}A-%D b.qztf=8jm6P?G )#%vƜjv{%J HYSGGMUᡁSVumߞ*Ͷr(&] HH`C2, \w vlrs%pv ,+$ٻ]6r$&5eAtҦdw$;vM#L.8F ?erbu,8Ƭv0S''ZTFݽ+*bg* T@yЀǬd vĚ**COa3b~mO0 `Y:-Ѫ䴜CUf%yI_C^_G d׸?ST2V޼>%3ߧy5s>P~Q&:`1JI텞$5a3,Ɂ٧Ꮇq)(#PŔmnJHkJezf'b¥ JKĴ']>vx-9 p?~kzeC*:zEU|TZcd~;@)U:y#8`nZh$)uɭ!W9Y&~dɢ;m ܎ܤ[o#;U|m\  c?m q,qXޕjs(Y=ӸYǽϯlvmխ$lÜS"UF -N YTbY_(T߸vyaGQQM.XOUzk-Jr-I3T >pgYu:;U 6O9҂͗{(#{P]R%6qZ"hQ$]iIioLa#PH=8b.S$[_I5! мw2FKY2L&%Z/Z$c]%3iVŜQr( <ʑ/ ȅݕh7[`QY␥϶ ̣& y*ZK/R\وbpW$ൗ bГlŧRTxf]!2]E qAܬ%0rU%a.N.`[Vz/%v:?0\ۡ0,(JաE]:yC($C6\O:(T9SV7SV1r,- *K l.^EE& x6V"5 6cW֌V${>5vP+ jb¼*<=a_ŏCr7>v} _Y9>Ij46M~PA vBl%aWR-jU"&b8NdI^ K3kbV0ޚgL$uV/]2Z2a:<^\q392*P2YN[? dۚnD2OvAmpЉWۆqJ>(9gR_Yb[Oq.)ᆬ<7< |z$H-IsBcd3"^e7\ U夲dl`񧅇lw:YR-&p'hĶneښ\.,*N ZJn+ۓrd?`DuJ[1+ŵ`#\zHL%>RJ<' ՙ ,2QnW)[6/u\FX$ۮ0l1)3#mP@>C5xc8Zxb:;m&͊ynk0]I(~֮b1w9lӱ;6|*%ːTp_#XxE0/X6BʻG4J&vNƚ3(AkeTlԞjv3n6؂3¹ cD'9V[[D`bقM <:F$9&4[+SmS]MO.c64acr6&i!hƒ;px\Yis,sH0)? )VeF 鴱&<@kR ;vu$}وD@;D6!b9֚>/*ϫi-i-fUq I7ΪkgHX7+Is׭VRCBB, J~463"c:!1ıPGW8lgiOU7]J\XKqP6)aǻp, D ᒓj~X)]ߑGqb<6okE\-YhoYό3gg䖝C^X{6?8j=; Bی-9mM*] sSqWdFwU_0r_l&,{jKliOqv8Hp\\rğʫ5ZsHz=8Dꜣ2:M3(T koTV[&^j9>{*+&B_QqYB4%k -s5`?CFi;@A@whpVUKOK6bgG@Wkڭ H{8vE&ؕƻ#Cq7n7J,o`beq|Iף746\:({Ϫpl9{DLOm8ipKmw"SoFNxY1rvC Uuخ+raJѳhWjݬѶڿڙe90aTZT?ĥ[&#pljPZpUlN؟Ppw̙gk-+xJ Nl}+'N{THwßsӎ&wH,:FsC7nTjsmF>LX"sZ`pUG'{> FRZW&MYm0'7%wljS{&٤r*)xL 2.)t}o8)A X^\!`l4gOM)#윤--ݽ%`Ĺ~ TQ^zvpK'ZS p!O .-DǢ6gA1CWrcr5$KlMeegc6l{v-u ~;ڛ;,Η~:` d[.vOJA}'#;]J ,I?@[6-X$SďƦq.OG@/76Yql8aĺ/ M! !;m%a;:R $0Mz8*oVw!;XGBj(خ*H9TJ&j]xFt7{tdk~#`NgSlcwA02 vDw(yUX[jt.pĞsf%o(<髤yTa%"q2I Cùa_ :XrNBU4\ A)gbn7&j¡ls`$G vHH% $2;L.ͼ#RQyiۆy|5ȎX\~;DPětatNj-26Td_N㘇FۺE*N5Y{UOy,k+AEH ;L@j[Cavo>SEI *U~sPQj%BUF boI'%٬*;3Piq Xh Vȯ&٬yZ#rɄ6poWPR$.w Nj*=Re/v˴`Q&"fз8'~kSx1,'M[8Q &RJ^v&g'boev V%V>5`@Y5D`@ QքmU`}6yTuewXOmQ#q%lEQͥWĬ,Qx<>rH #PM~^=r6^S}#pjtpMp=(:E,_#QӎC(sL] aVe m8e3zWgg?eGcx|8GFW9 o·?!ZV8cͺ,"ZɁn1ΓH3^# pjkV\РԽM{VgL:YŒmLhxjGt]V*9@nw a,({r4Wb#a# fWJLOUݪe6'9C֛o7a}v FԜX8@YHvj?E':q ٯW QWIcύNB 汱Ay'<02Q}5 DOG⥴F+Od."I]$`(0'#4G$⮦%+-A9 :f]Gr`D. + 9xZ1:8`IւsD9IH^fYT9$Hwiu<b_u M.㇣DipFr޿7BA2>VV1:;}q6a'9JGNӘi)Yny}1(G/ٶql)f8LLt-TeTjq$_w L&9F7)ޤRZVYdӉOEVWa'hcbbB݈ &ioO]3i-6UZ4Wj1 gt0fٻ ߪ ל+'؉nKajfPPtCSj6f睱tMG'wʙt,G*Q |x]:=ѭ}lv* JKٜ3 4[ß;#[;cuU +\":v;偱@ˑ"%(XDr$:RT9r19ZU,n;r١"Gv%$Zn`CKXⲇ[ý`ؐ$a2qRM0AWSH^U78kwaα];}.-ҳFPf&$В 0=/4U]bP@*mN6(t4)&F ܣ^H>d9ёҿ7A8/R֞ E"b]ɂ>{ kI1n0zdò1~CLkD>+rTD:dL4ΫΖ7.NĹ;\'-72[L Z|.4`XvN5sE0ƩZ8 frg-l3G@dJTPBFUel[)q̀}X0ZEͮ <'I~U%w:N")o E J6wx&JTi>xy M=jwrke,ijiHQM"iN֜p;PbArMUoe+QA޷H:*y(TB}YFgB%fX6Sz,e'lbJ2?e )IJ3s4p[fEsLlQCP7'-Nʴ0lQT秲[f+G?y'T,qh3T@WkNo>WlPggeƸ)M"KǹolI-QG3Y0!I51͎;w'`M)G[`QD"p#, ЄB]pT1i0 :~2Y5Hr)(Xqq?7=TH cC(kDBl>*N{s&;F `p)M"0" 2}3M%[plx 0*88D[X%oWXRXsxn93OI }0rc5A8VkH-P}OP)*- 'iKv4 =tv?!5Abgtd7bѐrqc'Zqti)G=6Oˡ&*]–ӶbCum'sRڐr4[:v5Z),b'"2&^ڒ8dK %E8ѲU꒡l#cXk2 *p+mtb85ܳpV6ق8 G>UQcM;Ϗ6 < $؋gbeLөl/DUj䄴)t2>ƁUKqgd ől dx6n%DX]og+Pa;2nNM7tƍ|6v%dy\@,dLև(W,pn"TlCgvbp $#IjxQ^k0a@#CF63JhARͦ㩷gU &ҦHP.f.~Tvq6g?*fؘZ;H/<(-ck+pزb4F9>c9v@#xيoj0>X9"yJ_pd%VIl?񔿎 2[ߩwL*!߷=C%lٱ'$,zٴqn]ؽ:/B)TNtiv8[CLO26"ƞsFObW'\crB45'㣜 ,-_?bc(G$2k.2A`U%}z̨ڼm0& 8BmRw`qA:jv+nC54ơIq۝H՞k%"cw FZUS<8*7ꋵXLs$>@I1*c!9o2> ϋ+Q>jS^jk(x,Aa ie! <#p;'w&I;ݶd1^ O4tU5cMϦ9l<")vZwv@ʼnn8&sT۝Z7;Ca&ވ\5`{Bl%#u\شEg؄X(Ul`;-F(0de>m))VkYf1*RݠS(ڕ *Ȋn̶: y&GYS-8K{Ih I=~(n'*rbi˼X6#4  d CEGny/YZ`S<Ȣ=g*júvJ` qqR ,2SD Jrh@cj2pZsLqԍy9vD\| ߙeyo*ffYk dj=ZYLtGƘśgV"؁d2nyR q~C :wwD۰TT_7nn3'4Kz)C (Fvj̖(4HD(lllzGV(I,+h!ڦ&_rq = -\p -h{vؑey)pY wRW9 ٙ rl:NЛ=BXog|G$hYB\v;l#P;NL2єB%,#.h aŭdQHi<ثt(Fz)' \ƄWü̒9(/ܤ.hT?kc3Ie "#\zbt .`y8b5pߙeUξy GeM5;Ղ{UXd]ɠYb<Cs3 \_ 'VHoS9`З9b{a^1P^W XTա;(zK2Y۲YbYqNMMH-mHrQ$,DM}z>:/,[@CȴPHU?X?ӈoLL]RؓlߠDaO 2{4evv%Av]̂YwBv4/5 q5'},J>e؝ʉ?& ϻC,`-s. Uv,)MTl %s(n[5mo\ɲZB74ؑ-Y*j g`%ǐ8]. e#4;4g:i3\B 26F{_اF ftRdA,f*E6# sNZD2uY\$! p\K0Tp@(BC)SFx,^@a,T7s1-,,Z񣄰J̪$^ڮ4+'G i!?Ğ1cZqB"QYd_8UmԺwcu=jA6k3 V;0 XIy]MٽV X0@R諸4xaun< ڡAnh%\$7QDT q[URJuUB(MkŞa tUVC&n {l{xt Ё F`680cL7 UzEzk!۔FLį'SU #c@"ZN" )`߬>ŷQ岭v`5n s+yhM:ebfk\a"ojeV>j.տ)ʟM!61(D`Sr>QEeY]{JÁF[zKu)Nfl:lbk`7H];=GmqOE s E=űW +{@AEq&=0 hfuU³ \jM9*8>\) ̴ȃ:Ckjb[~Ѻx+ {gSJW/8 3(URTx7I-xX4tQ9MD]4*VkϻO6E*ѩ쩪?rvCbEL<o9= pqMCJ9AfmZœ?q2K.SQl\M6%8<] Mf܊}8~g9y *k%' ֧А;s®@*gspf0BbQ ֜l鍫UVīn^RTxʱgfHqYI g.qm4x5֢},j:<?UNFƒnG}Gr}VY0=>Z1,|ԫ\ޭn#`Z S|US \-L-aإF*A%9$aו[P*c3L:Jctz!{mKNܱ2 {, * ]wIR`~.ylfmSlGuԍ/SW+\f .c%wHt2mc'!ɸ^:.#"qm%s({{̱/@3j X+֞5Zdߤ;%dT-VT~~X#W< ܤ3[-&+֬OD?rҔl0dFX$x"q04_LvЉt&2If p6eqIQ;nh'u=tfZ0#ð}\l.C<ߎͩ6{@q$ȃe(}t/.d[z J*'jjD;|Sdf^0JdÙJt:Rx9*ea_8J:y\NlVv-kJ(*NاX3[Kp[eQ p81持ZENFj^gOc5FK q_^YcLWH|h3#MؗD]K+tGLY0h) D'ɡ`kP0I#$sgnwCHgfYUWҾZri{&@q*r[ZyӚȦG&Ї}eNV6 <!_aϊa:`f @iUN3ۻ* >`-G-4y~}UT@nXMst3v<Ū8>Ye*2;?xa^u>5\h8®$=|/N?b NWu,VA°~p|*},vK`r*Ka 0}2s[bʰ+`ˍmll[$8 q&ev *3K%syT@eSw 2Ἕ&0ݎn8A٩8<]Q%vxG0Y=R4qL)]THK++튏 ?5y\j9m{` -yCK {Y:ch@:1(MfcMNo tl8AIY o.fn t AGRBR*  h 59hY/&\N Gm7wAݬ#ȇ'p@ [_opB̧]R+4G A@ ȓk! Ne(G3=!,:5 !'æ5j30 9 7hlR~.UӺxmR"[ :l N >3"x(dhR;ӡ p};lӁ @̿:q k*3y[BΫԩ;nbe\tA[J&. Htn{3GTj&e4J| iVG UӹKٮ ui+&'s,1h32Ђ;<(cdvqݫ]ӡ!&Q-Cz-uY5صm t}=vGeHh~s\l} viyCeVhu/J˱NdCqsO 9:r:Vem3e@R\J`$!w iBx6枲@?R-A>SUd ](aB5zwWXXc3uԳ)$H3;iWň-5tS5Q6a/΀Ivng#aU\U4ae'cU%.ώ1xlNUZ}\3h-Rzf~٨?g56ٺݲyc40yy6fntDVPi{v5d#!c5VTcvn% N|X+Y NG:8pr8- a*MbI̚$=ޑ%ⶊfc̨QHj& fS#M&U&50VK<焧gX_Y54Ia]C/BVyS /Iг((Dĉ97acqXVM?UCAWX {Wy2Χ&i&ITMX% Ǵj*S3mJÔ\S϶ "|]lj0 qe{\'i _*Ƚ(lk :(O%LFW o?uV(pJm `ƑH/ctv ,^C=)`w ǁ=蟐5&L\Q [RU zM.6rԃ&gA42Syl.RpHvrX ;Qe<01Vy]e96͞кQ>M PRS8|g& 7ufuZ&DӆVqO4AS#'Qd ;pi%4أi]M4W*LYEM$a&W%MjB]z<ym^yxkJDfxǹ[I Τq(G;s=: ˧mOdj ҏ\|r摍\.oQ&‡e QK#B,]zr4KMN7;v<06st0&ډl!R6WSu=%Uw1ENV'u|"wvpj""I$^`#۴vRW-N  (*49xD$f"7*>V{rCbsY 4_-J({8;ciP´\+o꺕Ly x-~\Z/Uu:/ߙXBŖBHp`')@'l%qt#gNz,rl:Ͳ*O} D-vK1ersb`14>ڶ!-pє,~T ӛ9X0ŶzzFeʼ{;SfI FE]GtZth?ʩ߫IlUt436D~N#?UL+g=;fC)"F!h-GrF$)àv^.cPcp۲%|p6 jK9e`8`e۠$zlYf ~Z/Y](.Sn*:XDlؓ.%Dsg! XZ([1JCx0%]1ʚsrhLN $I(Z=voMS'9,_Yzv<\hȗÝC:O5x9۱[ktG|Ρ%Q{$/ش5'5BpY7Gvkb4UfFX>; L{PK}AYaX ңHSfQlYVp~RZ_rΉoʟG\bӴ1 ؍-c@e'О PAgkؑ:cQSp6w^;1​0{g]\Tn02Pa |3KP#"T`Rv+B)U4LPt|j”לHbWps9w.G$UT^bY]v9Idko̖dO` ăo$0,w3cjݾ~N ,#wj2KaY>9,mSu8dN16I£'^ӈ% ܶҳx:#NbNƚKL`W&9YXmPƄE>iad^a["Ťe\*4B8KEqsˠ0P#!ܤDҦڢ֫dG ӕ2&GW&Spʖ"uޮ݆}pRbyz60sjO]#. Xbt:`Ue,$>a|t2@Ş/,#ĠĄ$<\VQ T9XTƩO+b+2VDm ]n[KbVWbe|̳+H[afW9GYM(S  OWVrZYP]©vŃ<ۊN@FljfR{Cg<coF8Z:l~vL؏ykI2N̦uO}D/|6(uм$'pCUV 'lGLc^,y+tډKűv*hvdN9JXuii}vf-َ&n9\aS0Ri6li cTMpCaq{Dplb o1s)x|mV<(3/h^}+vcΨalSd6R$/lNE ;WIel *Ksq$6;o>xwx|=Zo^ܾs䗿 q~ۯo|G#\}f~7W^-^\*L䉯~틗ﯞlO}|}v'_޼C]g7jyʻ߼/!_}_zQ?~۫~_ܽ㺮pOo߼7×oZW^~|P?׷~xswo|\On~xg˛nKy)_}wׯ~r?>ygO^}}wmb^>yw_~ţO Ëo f.?}/_pz{{v}T뻛O~;{}ӷq[wnWgW=ͼ{}ׯ=z[~xg.W^>z_G?0p鿾}w5gx~{sǺ<\􃽙?ٙ}9}+l1fLd/?ۉڈ܇?؆]sl[0v`?܀O_?}`K'[/K~x)/ "W{/:G-={s׸׼;xK~aon޼ѫzGËԷ><K? op)\?}zsm܌gp{`Fon77y6 2)Nr=y۸˼.HK15$ä9봩(ϓڅվQ}ʟ]5.YPC{ZۨlJjM\U2Mۺn8V޳&{ZE1Vβt -恭)/gKqh,nݶ6IU%i{]m_>)%ZZ_XM<,dnMnнƔj9b~Қ˻ȖQ'Drq;/m!zj<;ĩ()Gy#,Agf>'r3Hܧ&Nv&y%>9`5s2yC;yVfǶ3֘3LhyBU)J;|* |@)Utث|mwqtYּѼRcq^6Pu[JS'vj6Rd+zqUnKH=sɃzNLQ~/LKvr[Oi?X9<<'Y8[⚏R8KγqIB l=mVfkfAsMK_[fJ[zS䡕(7KܤX2XNBTG]. <`;T&iiz`<+z۰=|rƥՑƲVdrmcLc\ 9Yղڟ;p::|MQXMMv%H:pe,Y_ŗm-a='GfD676$7%8q?gʙZԢrRiDg^% *+.cOtf;-f#إiyN:ۙ8QMr.fp<6>/<9Q*[e߿ j醙P5uj\%҉I֨+v3m 9T X*̵',:-) !J18;U$+º\EN}Ղer#hwhOlU;쌹oGUhwq8`QHөO& {Ilg`E][bcL}Ro:ڣsDϽCZl_aY]4rc$hˡXOҎزMGϼEU(8xRj)'(56e[UX^c37-˂%?93[]nLM v;m&)s8켏`3dz.ZB'yzh?G\%AGмq4k;KgU|۰.\ڹ(PLb6~X=MO>[;\EQX چ?jf{>YϞד :XTݐ:kPt9o}x[ܢɐGo)e۲xٔ5oeWpz ml h+-k!' nXSYURj()6ܶ,XvD3 rr5`d`pk20xڜ/U_B@,(c h4kb,dG@STlcKEʮRΓQ{N+L޹Y7rTPG`q.-NMFiODRc/qc]ʄNK;/%|+[^9a)Ci* qC9v{ & تuS%Nē< ۱w~sO)ASbbJe\z3.?T$Pˇ#9U@qSCM+ũbhFdǀmr8՚MRͱӕks&s P I+sR*2h1/N)^;>G*a]'$ ~#xɜ"J|HEV9 i%cA_dw0}I :}XQd@TSb3 N;s=V &_o|\xnD `?I}Mj'A`@=oΪ}h+pQ%Cf+KKߢ dGj܎W೿5b? )X>\VRHrl۽]lܟʻp68ݓQr:)q*WԵ#4pG[S67"s`+)Ds ;߹d7qBM=U3ݻecLPLjttMcxik)olKsr<{ ZS!(Nosl+.opkY;g1]T5Yn2v+ Gf.f1kT 'փ qi5*Z1/mj8R^U9" T Om!-J,JDTJR)Sctds1P*/FKI7_uFV,UB~FyӬSKt.86FBBAxȮ뙇6 Y23X.Khv+@hGEH%W{Q +Rޛ\״Kj*AΌ"(8w&)ݻEF!,1V&jM~mgDVy"o]={yCNw;~o#co0BajI15G3Nevh$(݆sxͷm-8"7 r cTx?7UTeڝȜ }ly@N&c*D,J^*سkpDP4r΂t4d'L܉Y6o`uW*YTy%ukEIG)Ļ" T|: 01ٛy0nNnD"1ׄsvid F'>? T\T,Ģvp7G!5ԘT8qD`.egzn}!fg#鿓[Փ@hE©,0',+t&z hFݪ@p<,@,R|V'7XdvpyA펒>Ƙt8y̧q^~tx&M@۸c2~(p*B7La0+ѺRd*=DY&^xSKVj}]ap,|EtמYʹMcTc[خEr Mw>R*ɀ+,@锋sBImJM?[̝W TORyR>+A^rD;%u13Ž R:ı).~ˁIP"3 6^YngNf]0)l*7Btl&:EJ@El4hTZ,.s3lj3q").ϑe@ټړߡg(e`3|*k-IXäD*4P+ɢ/仜G %61e%X49x̽ɽ3msRcEВsA#kd ύW&ka<ѕ9ggRRD ^CְH7&3@{kI/{Inc̋,&"ϤF82nt xn p E+c"AlbPͤA 1v9fDX+X\ a'~-j|:pɑdT5ZP5jp#gQHTh?,ު1d9;.Os%p,U?Γ)YwEް8& 9dQM!:m"ti)Pqo߷TJ5ۙTC#"ҐQPؽbr"IHZ|Q~E_)i7vY ,1a_ V.-2SZڕ&,$t"?7I Re]7;%?"T(WDf"N*jK{SKת2}Ӷʇ \85C lQ0eASpo 1rzVLbqu""[ZF ӍMCa `L9K'=yCfb;6vH)!g)q@(?4WD¶%LkH8~,"C)@$Yd.NRKlhu*TQRg 2IYu&XloU=DEN= pk:-opC{DGt-l3Rw`&b 8WՊz(#"UeWGJvc簃EC@* IΠ"2H>e:脱n;] S2|NpLҼKX7&;x`T~{?=|L6%K$Ơmdb#XO"P2ZpMu֭iܰx)(M|dU_r%+8yU^:?nc(QY&CC<'rGi^à"WSSI@@svb*mRٞr(w%4X |*'z'g d-GƀR!]}{ds.jcssYw@(4zOKL5k'IiyrgWjw d [\ PSiT,L<4L:A6itVSؖpûz-~4ZdYo6 6奕2LvPbw>S7c-,4JR@;?j'k^?,Yud@Ф+: =͎wPU, Vâ#ž(+7D xqFIA $ 6:N]7xkmA"Ll3ir,r#n+i ms&u3O]!n"w,t(bq8a񬍅<f'd3 @0+jr!9͢H&7)-F]X Kn{kriU&6,j@"ζoP&eGLٖmmG[syuvnϬMj,R Z.Hwū)9k >X4onU3rgeb'dl9.9c>%_:R:GT& 3@gYȞf8bڀܖ, Hl9W4u(rRiYSB,Xڹȡ4 *X[`l\$[ÖN[|Ba6] O1H<ZDLNgYgh/ѓZ=edT+)I7S<@F6S!W#`){+]@.ՑJo vŕe'MY=e8Ay"[h{9Q D,rٖW*<4+S<,ƨH`=9/MG6$Fȧ=񛷙שW#6/`6Mў4:iJxX @dEP) Wy\kAZrL>hɓƯᗈ]|}'N.Oi+rr&6?0KGzOҞC,BMisYOc_$gu,f+DT3[/6[:KL&؏0Ɋsʋ32 0HTlN{O՘xʭG VN C\7?UP1wNJls6dJ^$9dnoRY3-vn c^L=`X_JG0羰IFS%W{M 7+Q]Ŏ*x$yLl*2@b؈.?#ТvfI2e=DЌWٜZj(5-DU y;h$!I,i8#t*Xa/ gpF$N|IR)ea uゲEL0*RcLrTt[ϋ5Hl+9g=gCtW[_ {ELrB|)pٴou, QefN5XC %)5'"Λ!!jRMl[{.8gG$ePX/)bA =Xg4C6ͷD-6Ik {Z Iivki4GxiEQ/ƝeYe2$\K`rmL4A*b2534?:*8q٤#)a'Xvy(׵IЍP΁85ʌ\3sm[#{sӎv)@Z;@Gw&n+hKjQ=wHeh+TK9#&nT&<+*f+VuXEX>(3P#WT K9n98 { DS5u3I3Wj~k1kܽRR";BZuGsCݻF3 dj8/0I]VMPn \MNY{3|\ 5PSI6_Kl^,aFJQ;v^7 A^bqHjB7tDN4.ql)tӨ0Щ9|\0&+(`w8ΐ!p9r1fQ`;EHXٺZD5gfevXʲ7N~p jS]G5兣ѣ7[a"ؤg$Ğ}I{fDzok|>&^MMt 5$'# vۼ̧رEaVE ~9dL]3mMΩ\4T! rcضaUD[ ha7a%xwc6وE }om`ž1e Y2|I{ixaP$nYEJ]!K6܍vYDWbNS@Uk*Q!ɞu\fY Op0պ$V5`خ;yⱧQ֓e=p Q1F!W08nW6ʖZ{D,2j}ҝ'M.eS{˛9P!#b! "Fcc&"ʄk3hʀalwF|qՒ TR0ﰍ:|!*x,0}-&j:^dQU5-ˊ?iRR4?{g= 9fEqamiݝ*u Pp01FR *;GB9ZD41e%0NK3$%H&_ށ'6Y./]xQq,]谚kuã &]qݪ]*>,]lLLǰ+K\`v+:w9wbͪH~IiMlq9g#Wxbt' F Sb,1XC&a݁ s7gwtvesk;"RէA[F 0Ax lňUaJ,rsG {F8GX=U[fR6/ :^|D }fl ڀ+} /LZ;Ft` M0 2VGĴ͖"gW a֧J#Zmn ڜ9üY7h-߸}yMRCcO+Hs:dGip`s&StFbݫ ;"gD%NZ}8伣;V*Tx g;۝`7Ǹƪ`!%EHl ,Z:7h%b-br y4k},sSO[%xgy(R8>',-f;M?՜ǧd€u˙0ze^4~.RSs^2>m;oY*6KP{zy aP ; H߯Ɯg=SLQr1`ERp(ox**nVzR2m!gfu*(RU)qt3.sZۨŞ؍ޱ_;cj\ ^t(iX`N2ӫS:dxtjUeLGf:]fKfoܷM*~xcְpMapI7 <2}u0ǧz0"il 8rvuMR(Vf?*aj*RC\ \jc x ԯӇ<  |*Dk`&Ogp[m:i D3p0opM/yu.ő"iNO:d $'"%wPH8j.;q!>vd7pؙA6h&t%NX  sH샻f%D[X-V @\҈?&z*wS+{X^4:˗4.fC9! qlhPQ+UaIVdlc]L,wU^npT|f/ዝv`FpmL]p K*6;IU-G6'.7iӢj7L]~!".:^bcuP*w>?eٴqd(f;D0ZgVQ:}'b?% ? sm1l+ʤO+]] 0awCJ53z'S&تkH۴̓JbUqTc&WwTmJMK"> hi}5+޶q+uz6{E;"'o!,s4M08p6R[%6 j8ؚ-2պMmTd}!*AD;*5َ\f_X+{zOXl> hg_'vn'2|BȲ11 :lUSZBPljVD\1+^M1<4XpSm@ *nw*‚*MohUgL+fR{EQ=l<J,4cQh<;0EHd~6i DMY amWΔ #h&QY!<сtLB\|4zV6͔f?ec8(s;g&v*e˱՜cTr[J>Y%ʳdlӊ}"Q•M}ER]uy*Ws|DlQѢ/ aQf' bEt?A8sN>>AfNYL ~23v:=zLk=(b pT9T5.ls1&~#ͱ"t"Aac,ҫz{9$D5"NW{ݒ!eZFi"vayA#Km!,u )wf"ϸTzCʫCfBf TJQN ÎOp9ˆsTϝ^gq'I2Nb88O>t: ,;$ȡqo\&B>bo3TjؑV'R!VvʳD@ϥ֝@ &,hrQ@vda *8Ŏs/;gxfsLXRԚmzdBdvL  Ǎ 3TrQN}"L2m~7mMU8SohB+҉wKpCB>=* >]֛V*B~37I8B/jgQMb&r0m2lN=[=Páڲ%$ a#ɭ{* )d$`l1b8eˈ)#@5`օ(s͖ͶYlF#t 4,j,,C:ͩ%YsfK_pTEMĖIakͺfrVY?8>YcVk=44^Oƒ%7+ͦy )X7&`ERuTV8dm0A.D5vOHէ ӹ ֦FI[PpPtw$8Ǯ=;w3تnc]=0"T+!fmS#8)ѐ }|-+S5esNLZ#RdW6$6m꒜\4@v𢔕"خ"Q9GNKfkщ 1jD;!?Og`VY+oybA:֤M L[H0T$' gl![tX)gꥩQX$LAPb| #kWs8ǟ8&XDf(^ѳ %덂޶s@r-WO9A܄I:],GnQ@I2Yͣzس шrnV-MrdžU<0)l]rZ[T` *'!k ݍU7ݲkl*w(9u FsL6Lm@4/ )HmnZUPC<+D ]?2qo> 잶=P/GqZQa&li5u3KULشF cJɓeqРٛ#e/c0uCSDz4 n91’blflmL{πk]S`PI=llR/F<=>-c$hqݜ-TTS C$ ,Lbܟ#daMӚeL]wfqX |f=;sxGKyt]DtrGKT${sr%*qZ .El;WQWZڡ i~茀>먎rpコ3E_.iƱN>;VOlVL\Ybt;I;|(c)Ƶ]'Ah#sjٖylL#W=X6irVMa0 ]l ѾCs~˰t[2h/HЀ΁ڧ{Kq1i)0tq$VARLiewsa< 3y|EV/p.i% CW:m2#67E`'$%Q]"rXX2ުD4Pz^0X£TL`g؃C;؎ssB(E`C)n) j+HY̍#`k`C?oYz4VU"J7f;VZ֓RW,09 .#H2P9Dh.;tk6\ui #AfGD|/Ā1ζ\,a#9I5ixbd}8k얡97pUemqw(q$YHvC8Ŀ92+f+-9Y):NAZxvy8L6\}dȣf~n?dUPCVܳ3%8-bgkMZ=S6,C.䄣 Y.Sod"m0 vdl xA b☳6D<2^Uڊ@٤- +ۜ3>ʴc\v+H m:i%=,pERSkFG5Yly]v)6; #`eD*'>&|O\9G\nuBlD61x6-$;2%G[uejb2֤pT0PÉ]P ~Sgo!̎H.b|w" ol .Mϱt|%KCcP.mYr& ##%4 :b hR Ẽ7M%ȋ+>(rI`r~F鲹?n SweING۹A\-˃xȻ AGX+;2E9ƶYT98RYmf"yN%8t` XP8x`#gsmG=a5!3T=SgNLMeYtv gNG-Y$X#L-+F.QqiV}dl1ǚN稆zX4ݛ 8@,-ʼnO'A$9b{znZzE8‰`5gyY061Y}r^c9y%F$C;/oQu|eKz&ŹTi)o]\w[Euu(uܢ7;|v.[;#08#iTcC&ťJ4#bE |_v$"Pt-AJBZS<}a#|@zK2 ՞6Vn1B;y8$ Jр?;5LM N be|M1YTВ-oe];ս{I"L2/C7Li)2UY16FvmM* C%0݁";P)'aR_L A2 0LoZ6C#* nl9¢X<ཛྷc[ Nh9uҀh-bDg};V\(W!}X3y_J`e[,rbj,ƕ%3lLŴ;^<`r>ZW) M&Re#v)HWf>!kT1+[^nR`frZ*{vqYR,,K{Y\3~ŢxJ-M3'C A1LP19i5{PI<ep{m zINGtj8gDdP\RekU b*Pq6PZl  dq)1UK8v§S-9a?ER"*{3~ %2?]݄γ䢘'"qS25)Ϣ4TӰ" P6.8`*bV;٫ŽDBUțՃ7 28}b0jI w[k=z;B!W&VQU>P=6Sc|fӏ]e$PO"Vp~"k:B] qIUyLj_Fm :Y}5PA3p莤HBW!NGhmKiPyM 3]`tNҏ.=:`d}/Ki䘦sMfwdۋQVd}dFxU 0p%0DilU_G'.'C/ !X63ű2e*|uJU - B;vKÒJV0|.st} ҃aSloU & T" G76r:$F#spc)y\$!Ӓ4g|$-Dϫo [LJ£O[u O 'b^v̜vA!r|[r .,W)$Hˬd.Cc#rqN՛9*LlfTdF{1O 0dJY=YItQv X 'Y)căsu^gNb#d;L^mPzYM|Jv(ʨ2J@l@(xEyW~+nJ: I"0&Ъ93O35pjl]O;M (w 'FYWъ<yU: .KV*Bs,68%MXq]7*@;1"> ]b ]`|΄E:GfBmbĺ|t RTp^bS}QUS r>9Ơ605 wC,H? T2 K%M#PldvX&Z5*g\)-"1ψ>eM]#.78O$l/>;t1Jt%NwNjw*I"K;fv0X)q6'knp(%z8ƶ-`el2s8 /`٩5|0nh9?V T.O wך޴~d&qvƵB.{CAI~ʃyueg匒.{Q&wn4%H AMo u%_(/˰t/`RR:Ǜۆ:њֶ4ij T ?Ɣ}W$NEQjb20JpT rQIա 8vD&s tbqL`Hcsg7$dC.b (lmLc$͞}H-5DzC~~Ih)$oǦl9vp[=:O]6Ib3,@vK6guL!ꀜ$GO¬YEumt ZZڙsq;<>%0"R`_U]%qS+/>/q1!y1yȪLJzeXm9(+V1je$4ԍ ~_IPU#l#I8Gx&,[ЈiÜS|<0W?ӽ8c0{%[?c"̒oWөtTQN>@P$n'eb)5TK&nـd+j&cTCy= Rt8D}\k6i>8d'jkso. 'R (8fݰs"f'pT6haSN_y 6%씓5ھE5xDbT3vR[D.8z,тW{wGfk+? l[)Od r?bZR}.ns?Lvq#ndGT(wmG&Y rVƹհ]NT,P@\$[<8]qOZ9q tGm nUcAEU,;p i,΋,=OTvu9dydFӊX;%]XcMyuS> 1QF9 MpJw9;JsNz-a`cMyD{G-Ӑ&aOO櫬\븗wfE+2}NFU뚢UY@,4rNSWle n@ۓiUSs6B'4^bw~p F#t"\N28v/N ZX9TI6`28)05{쬬 +!.N'_UMc+g ϖ0vêޙmrRC;KA쒋w=<ݢ !ʑ2<8w;6@ܶ_lpΦ"] {X8b/16;dJS*ܲ <k9:/* N2fvoMZjcϴ7r'GIGx3H8f;&F,ҫi<MXnY6ÜAlJT, ʓc4bc?.Kugԯl9ʍ&czlHh$6},r˽%1leVjBrK#uZh,2ܝ3Wyd #H0qJ Kaa>`qdBN@3;Fx~65~l=9ʙ\T<,K!#FZxZa$VH)ofk(Z,=vbbUo)a;,e+jŁ{U` :Tim.X3"9ҠUc;x`=8=f jhYnG܄`%gO۵LRT;ԗ]l]9jUm;ሏ1[2W7[h!8v rN2bPWS936`զX)ދD+9bPN)q.eVjB8okj8t0T UoӥK .@w/`AAð $rp[2r1Hy?"=euA=hGש,[i*mA1lʍ3浒$Z;@u;ghǧ6NdCj&Ev5]8{2uGhwL!E0wˏbqҺ1Ɯٵ\ϱ7Zl2?:g۪,V;mԺOfw'*P6@_ +T !fQM2qAVf V^v](ǝ-Gdr]}~5 _{޼}󳻷~qow_|{v?_}_}yᄍ}~o^ݼyU~o]]7~*?7{~ooy߼~꫏1^MW? Wwo_n~{n~Uͻ>}W| ~go_wCu_o}~.ɽۛ/o߼yqsxsRw|C7;O2~)o~䦿kz~7o;_'}s'}p^_җn?z{=o˟~eū7Mw:y_._O|7G;|˟|G~q=y?ۂVU*x*=y}}翾}:޽gp_!O_=mϩ?O?yw*v_2᎛?<|Ry_%'^Un{ ]_4/a,7o*} _^1_%^0"]|ͫ?^{R]S>5=S2Zupm~ڼ }y0nR*kq*_fɏ˯b{9go៱'_x/'e1'|f[#k*yT82JǃS 7&O~uŪ!}P?7JƩI^hh^WMu'|ņ{O~c_59z~5gf*q}oy#HC맋IW%RO7}W\{G+|~~_|?vN~_ggk0yz:Ԯxi0)S9f`u{Ә_%~OwQ5xtsw5A+_yEoeWUtx%ƙ~@.k)=nu MN-W? S:Is9;8ʿLrZ1 [tb~2ѐXAߩK2w#˿8D݇4_]^[.Z8?w3ljMB՜|,?3S{X~Ttv?$m>8u.\?H3 ߾ҴuQ.}}f^ej@ի?O+wE tir>\?xR j^ 4Ɇ XpAOlK/bgR*?r;@S忼 .+:uV+ ߘ{zç=cD틏"÷p\pw7WGXbwoo~q/n޿B?~Ϯ_W؛!'}mje^_q_?ۧ=}_??<{)'SO_=Y>}yw7Ͻ_>yr÷OCk= Ocfg~ 7O~?A婓lX~no .Ii(?a^󯯽Ի/\.rEW\׏& U{<-s_?~'׷>oQ tW7壮߽a]O'˗./zo^}`qy7Onywq(cvg켸yoxOSQ+?~4Y7ϟ>g}d{Kc/~솷no_ ay\7rY؋||kiL?_e; o%[>~}d9,Vt0%1_+:W5}g]~w}ꝯl oiSe-ËOG~ċ|<\ӣ۫Mw7c{dǻ Vox7q zww.ۻܼ&DU#zzn\ _?-ֲJ=v勹|+.alSOŏt;on>XB/lc'߼.[.sxt<ڇ{r}tͿy?'XW7W{ɻnݠ7on_5|s Wlp]&ُ~1{}qRyҟ]-{~{1/wϻ!>ymW7|m|"Uyssw _ݿySqFwO߾{s6ߵ_~gݎ\w P=}uOI57woxnn;XۏX%|ogU3/5Zp̙aLxyo]ot/纘1'ɇ.υ_goū޹鳻%NKo5}\vq_K/tpwa}ǃ|}ܴ7.鮽t~g\ӎ)k[Bo^6J8ܛ.~}LIW߹O־VYo×Gﯵ~3̳XG7Ó>ypK֣ka#pc O_vxy`/1-?\ǝ}sLwG'qsq_;Wz=\#£ >G|sY{W{ëwxm;OouJpխ_^7[/ 1ܯfe:cgrOB-=暍3N;}\܎`a=bYY8&f_?'s?k7 B~ܻnL}`w\` Rw0Ƈu3:_q5o>5V|ϟOoOnPw;sxYE~ݍ{c:I\ܜDo.]?8G .bqx9;ˆ}x;n~ {Ð>Zyk⊆pyՏA!h[FU{q(36.`==ң[:H8}>Dͱ_o7ǿ^`zS?FѷuG/=wz(|N<؟ÿg}?/FT5|d~ǦϹ.O˚-_b =>? 8N _OoadK~ `_ X_pX?0.4])N2oYVǧ73[h͗KKPgT e+gY^ }Lj|vkk}٧`mx(_ǵϗ'3lO D>WDP'yYz φ70Ë!CjE;_rSm2P䗏`#XO/'~ob&ӟarWh;/w -X%xcvW\nYG,Mi_?>/T \}w幗_#,0a,s f\'L@'Nt8+c />I4 i?)M@g`"^w )>*@/{/v)c ~ ŧvU"j eUU;UU cqͤoyӾB~w)~oxy}QҾXxy`8/7=| MxY]i?Ц~kC-ڿ I$3vO2d)$8&]pL1y`L;;Yt>o޽ Ϻ<}HV' ,|Z}O~釗|OL!ޟ{MrJi~p/}򬻉Ͽ㴇cwʐn V[ Ys%^QQ?owҳZv_<;g2moz}n!R/p|)}7O߽=W}}q_˥ߊF a^].K^ݷ6o٬)͎]w{oքFc[M`Oeܾzuy돸@R==oz{p7}ku7b)‡aq[&/gz BC&m~ ̑&nYHsi LYYy1HNSl%$YӰt {NZ)d ff 8oeE5ɷ.d[bJN+ƫŒ)щ3&)- s.opcbzfyUD]명C pq<'lqmUS-/7R;ƅۙ spKLu*.H(=1KeҽB9ۖͶ=ޯ*X+TdB7;KǾcI?tɽկn_ۅS6 [PnH +>ͬ9!<_Hw9v%/7 xO~Py{tσ"9 nvdSg+!N&7NMnI6 Ӊ)0lCu o=åy)p38g_M aН{o'5A|f/x?8$V :ɨHsE@C%XA S}ٟ+ڂ`%JDpbȜn|pU wv泜+4@! ԮH`"- `6uX6 JD藪nѭd@)>ts@e & qɹc$-H@KC{xpk _'@F1`A@` AI]hQl\jkGzʔ 4t6Vѯ]"YsӰnFg .-3h_:8#Lq렐 74>+g1<\Pw%ab2SKkR>f#گnf -cE|+X+um7o' Bmv[Iٌ8g[Eζh;EHma#j.E47l ̄߁US [.7bͼҡ*v(y*gX|46VW0Y3#L0([c71+՞~}gC99c1pԸSr<z f>pXi<ݷ:j69؋؂+L44ܼaZ?&p?nHL!ߡaK9`,ffwI5` uh!S9U]9jǸI 2q0t^glCS^zq|z-W_@F7P=W*KIyPR@:,%k}9ve|.TM5Ҋg?ۨ Z:! ~`,rhK64JWj@:ͦ֗uv{ۃK."\P|bvD$¾k+z"-g 8B.O'lhaA1W=q_[ÖERweH9"ck7XʸQ~BYs5HZqlNRP'NTRb3Лa$ t|sHc0Dw@'!{O*5^'7x̅.BXwkuiC r- Dl:c#&Y:1חnMg `ߜL\3]ʨ 79+I:n >YMC-6pf] I ͹/^bҞt×Wo'ݶ[f|kA%ޅ]Py Kꪺ;JzdzQbE 6٧0M<I^Yae˸S}yΧyK*ċ(NIޒL V#C!)x$6MM+)ݓjwGca)GScQXdcST.v%I~Í^B! Uq? e+RnXVqPM/Ѻ| Ski6"x _QZ@ |hP<޲Վʍ!CykKj=8G4dQQ>64xQBU\{ p8bܠ=c34Cɓb\ {m_T:BI#bӜBsO2kvJrb3@uPAtP q^>O$pˁ]n/k nձt $Z3qY"aފ`߮s K ɭ-C1Q-?% 磬L]v8h=Xg ISiO3.kVR75s1ܶwT3:jx`&Xz%iEKK78 en.sy3Xa$"nڂcNlrqgTOZO)BW)f*(N.j{ k:Ɲ3P?" rzQ^y)g e @|8Nѡ9:={ ) j{U_k2 ]xt0v|עn&(X{ks"a&JJ˚`+K̎E)@2)ĕscZb<+*(iBN$*R(6FE/ADRDD`$cpbK~|lX ew|](+󆶙7$VNOM+e[3t:Ml)y$sԕ!u^.5#=pWBt EZ[Be5FY~W4 gVvLZ{(o0VHvWkӷv#Dz;ە^6;z%°UdY?PF-L4xe<毿%W߾E&Z%?o/YJ11\h;TFۏwzekXBhR?&)lIf!nPx,b6قo! :keNɵʨ{s83,-"[Me*YQ>NJ"8oVhF[W4%%zϚT{!^D 74^_}3@b&?Ze//ow= , Fxã*BxK¿|_O,'ޜ<@PUz>sG?$0LVD@&lo?GmgVo|0|Pr'֌CU)l"*"k{/6*44i̔)՛.8q'Y77ϬUJ H;UE)%0w`.2Io7t|TRf2k;tXÖwJҍτ[CXC?m@цCeK,gp {Jw-藊I0. +^YD3H$yVע' ؒ^<@-`t476MD2+Np`8@F|mBk(5uy:kaz!`;տH7!tzxbwRu768A8L F{ /w+s];k-8V[Tu!z:w<5cW3KinGW(IQXl홴mCguAuFPZ7*\DjǘDo1SAΠngGϢ욎y̤U}q҅Bp pnQ=׿d{g)>Ëg/ѬOƹ(Ki>5ܿsr@t^ /_!==(j2h)_d'?o4/;k1~f}jgn+|3ըDq0"JODzJw; x5TwΐKGҚP\Dnt#ZN gaD4$ʎ/dPKFб$6H@#(ii9P{(/dǶ X1ÆH hKY%՛;Lw2jb 3NlO uͰ|RA1\WLn&asdWW5Wǯ[ᓕc fC> d/G W` c$)rUa5AT8 ƒ4/ Ze+y۸{/kr-t3{` =ڑ):3nn]'f ~ :.;fm!6nFw 8mGg)Me_)ov0=j&}ژ.Ȅp[Zoڙώ7w0w>{شgE=@٫貫{w%?[{2,K޺2?!YEk&{BcJ-L;jz%8){m+7j5 %F%=1b4KL9~ H^T#͝[El{:4ɂ;2`B .J`UqCR+qe7Tr't#{BGFcN g.j͝ Pyxb&WDwd,МCڔ9dQj{L-S|d*/O9 T/f4wEʧ/^1 *ph`mԀetH-g78g!ͼ;$1@)ժګ*C)?*{Tj`ʜO#B'5nʋQx ɫ΅__w(&\AU Eۥχj>O/HfkrlQGk:TFH8`k 'M;$Z kZ I|N{lܤB#CZ2 +>,P(G\!YƔ ʹ, 3{HD m(= quJ\Dk 6o^O]*RMR@ eTD۞%٬c_̥ǵ-t yHŮ]lRH;}h1{=>{.sA@`v^9k&`1'3@!: i)7JMR, Zӝ"4΄oUM 3_2;OTwu#~!bORk~ޣ|'t(',SQ9.SDJ{[pQ|p:ŇKٺRW.{k1OZ;i@teGvQxIKv Umncg=z- LWʁRB@KbcHC;%M#g4&8f6N)4퉠֙vJ>B< ܺ%HPGz~@1pq_ v`羚{.p_'X)NS" pmOuoqЛWf7Oތ?Ϳ-~tU)];#*Dx̸B\ч|L0>iJփPpC}k}۟ ̄1gPaGCEcb` oM7Or8i>/Fǔ'|&w%}Vۣlk>i  msoniPGX*dFظ%/it:/W';rNiW~NfQ::i+uV{a >F #_Dns]hS=,i=ʰtx{-._iV~o^'{37-yrQsg +Q?( 鴘lY?pp7|<(<"pbgyj>ǷwE O=d͓n6?W 9Cuz׫ 0f#Tǀ@,OwtD.)~ 3a"7 zloJv'{3䒒'|s%e0W$B= rWi [IaA6y_XchD(__{۬KlURs>*"levZl#g^-ϲlyFH~ ړis%+yQ )ż|QQ0[3$_x %E-ٶ|6o pn]A>`ԨFL RBbXc 8rݬ,yº`"^%0yN(F,$ q9p %@ذc M@|srA pغia ^d5`>^/zXj,f=- 27/*v8ݰ_Vʬݴ<|OQ!'V^o]''f>ZN7ɝF&LH-' $܂Bj՜/tcBBܭ졟!/@届Ձ@ڭ࿬Xpzr-$|!*Sʠ^>6]`V.eWOR0n~ GD:9"ANE;#Q ΀m~MK&LX3߷bĄ|.-QC\ hEo\v!!xBPo "&.ױ f!0 F*_l89gW7bv۟R~^x̎jU4GV!O{:J(<<:4 #vy%{[jLXT*pS!H3"$:e.a#qQ|h*cb{PVbs[{- g^ޯBhtÇ2: )>gpH4*1>ءyx8L\Ә[N/vόaK;W1Fgj;<ͨ'>\N{}mju\k.O;?a=4~2]0X{+Πv)zs%;@ajX6Y![3a"c*;m0B7}8h)} .Q7r0#ArUG^'m.p*q* *Hk6QESrjbmQdka.%U s%[̡<$߄$ rϋkpdU%)jwF:I|Oz?{uUYOnP8XUx JaM}BiB, m?SҢ֜JuBPX?!|';>vh' ck7P9Q9 WV*\MEVҞ 1`CaD{=悖M\|VNSh9VO -]V>=yܟkS_6{BYO39x ࠶n- BH!?3p }uK9ShpX1e^Gng󔾌SU\)ax8WV>.7@,D1`Mx- % d)l#k""R9 Y~Z/{k\nr#ۇd\\*:1`ᫀжJc?BZ?Y$2]:.՚I(;tcz82T1lO*ڹ1fX/88Z~)oK]s(ϾQ D{YO2ˎ<\MG!)FlbHa P3vn$?ggx&S `L#¨ip&yJS)56fڔ{Jԋ]'g7V5?H>d6;QmqCRM9rЖv0MƵ>Е}i;0Jz0W]IwM! F5r5t^G )j1^'&BVW` q bŴ,3oDqbN_K`{캨5VhZfA#e[gA7%&vi.%}f^HʀC'bH >UxBPq>ڃïtz{:6 hЬsmsLcEI|R |4Y@D~ Í3`VR=$#Z3瞼\tFyom~Ս;.>vy3yIYV\B Zw3$@`@)[;+Nw 0W~{RII HOWIT)kNP?"}s*$Uq+v~zں6LRM͵6A _ k@{#u>K/ٳT*.cjo] 0H#_*&:ܐUe1e!KRMǥS;ƿ ho6C[Wr@N%>ն~F1yaƏʅDɅuʅ$ʅ0 - b V8-g18ƛϰƩ+ ! ~ |F"bh~Z#fC[T+ƙu-sqѱhMxR^ *yD%rJ58ƒĀ|8*SUX.'ҁx8 #<\Uۆ I.&3H5/{5I-B 8x| 9N8)s[GgoM5'j& o$}dG62>%:u/jt n '4FnMoN<5|V6#XBdXx,{ )b%r׀p 6cj;tJ֐A 11*1uI>!艄‘[y !ɬh i,SzRgXns{+]^cyҞ-zT~ZKnH{1oA^}r>/>ñܑ](Qc(nv!޿7FrCz03?Gf~3S6wgذa,J1`аO@v#-vK!7gнEJ[+tZ?3\>}ó,F {Q1R[e~r~oKf #ꞷYIڌ\k@{n ?!T`+Dy(J&t*Q\Y,i8iW!rLJ4Φa +v.N@KT:Z8ةgI_Y`5ܓ! ?@YD}x6IC! &^!8VI\B54ZMFWK"^;WTj}IOp7_YsmTX1'AZO'/iQxs_7`b|C^%K\نplNė-9T1E Q*9"09l$4?2œ׃*({3sɹ87 y/Òh#/HS›6lo'Rp8"O'[[a8 ~I=ܓWq3 6gDQЮ=V"BaãWup=QJb='c*Ϲp : )'opgEؾ\q% BL(\?ȊqkSs, :Ⱥ*m:#}ۍ9.>(h8o1RW$wMTDm 9RfG=bX@-v:`DOD UGN8x %dE\bpj˛[QRGlX3D]RI +S/wD Z)K8pCQ%zE{z!XYh~dvႹdRX@A ?j!(D} *QD,ߍbR p еK5zanm87 ?J|aL'{]_홋PزjrϲuGT[QDHf+ AU8Hf " uv!J4ޟZ)V9'& i#DſdGDyEeA Kzj!lC?M'f2ֺܚs< fT2"6Ő&/e<鋘EK0S>*ߛ jN5g2K*uRmUrRW( `oΜy$0L&W\>5c!"m$]vD_1``>44ھ|qKV5L^Q]BRWň(+:[' 4tH*S(6$Cǩ؅|l %ujRouj_#9 _߶goPu|2# ^yT;:KycNdϥ`}Dlgb)^6)D= : k1FP:awo4+;%f]NkR d`b?W?[N`cp'晋OQE'l*Gkwӵ~8Or Tzuqْ~TOsk;kgS`'޻?WṸvǂM3%_eBS+ޡYpcYk_ɼLL$ahN)P/Hs!;Q |yܓ5)u|:eJ❽Ғ:YS2wQIJک:ӓipn<+Ie t~{7 ww+Ùji'kO_l,TBY7g+Ae3)$Oc.Pn-%бB RDPkT22Qm ),*jx ]Z+baq ƹgU0_(t5f6' 7/yN`_M#({vq)astqqa5ښ$ph\ȼL<4tEH) *ovk{ZT` ]]|@-F~Db!VB0C{ L=Np+C~||CP74eX(\umس_RwH p41,EytA_YB/DR9:W*s1|gfY}6 4 G$S: Tϭi؉Dn37}Epyn ΀c_w>Q64L] _̨~^}"()$mM^Hg~_"QA%ǧx0pLf}g_߸2F1^{0CDp>Gn5AU 1gœWYx9c e -!uoQ2DhPPW#Մ3N(o9!fP'ţI]IM9&SΑ1jRO6c֤fJB|NS:GYg#fmiY.xS&F'#=> &~5bGjLeU/_;_\$a?3<)*K6yxSƫs{ Ay&7.Hly v`kͱk䂸:9Gzm'4<[$+)[8#4D*6z?ӱn`3ykȼ4vPG8_}AJ\^JYvm-Y89\"@Ρf^abtNt`Mue]^p5Rt*CGmѸd%JB,[X7PHv 9K3P\m{taCrW3Q(zPFpUZb*T6B 63,GtU!@ơJNr:y2'ԩﶪ\E H>[4 qK:wz[|o K)稆7 ncA|ܽN. ,>9 B($;oGcsh/Y"n(6.3D.Ȝo-dB&PعΓ{W`}| /+*MVhcx|wycf;)fB?˻dzק=)I_78oTȱ 8!ûϞkBE! 9}W C 1j/G%Ą= `P"(-KGYn Ʋ!:Hxc[r^ALpRqg?6DSQ!9a 9*Uy;IGvf"_pmL?H $hAIet~ôGL@Y|v` 9 (" <irMMkH -Dȋݷ4y++GqxE gT(xEGGϤkDT@8E[^]%.'YI4HWvW'\RFu!Hɷod`GҎ>$j]9 L'y:u PoK} Z~o^c"V]R^TsN<>q&\D+d@L ;U>ȒC2ʜ\ 'M.\@}fx`,)T !S 7chL? *TV+L_r(Aw(O3Ck+ИAڑamíRe`&@A)PICrvi ĭOoQ*\HI)04hڞE۴*~w8\ꒃ t])Mc5p7fm>͒GnQ{ GRAJE} HFGkߚ{ƏTZ=n5HFdTP&xAdr*ijHhyܯ &昰o|O!_(ն݂8?8g+-W`sh }5$P!a;ZU ejMc;-i#h`=,"O:aEk![<Ԣ(mgg .:1 x׵lA44Z,Tw:7q1N+$K+"$?]d^^Uy[^'⣝k ]CӢ"Ll#f(]ruK}JL*:ً Ny ByhREjKN@ltڤfC]c$" IL 'K R8y)i@ۗe/ |G1/ ?b9Nv5p#|dv#nJ[e^ {h O]-Ӵ _ٜi> !m{ P}>ԌϾ3Llr_I*U\l=Qϒ[ҽ;1}EVgk&ȂTSMURd2Y9Q|o実 uX3Si)x+%^3T&盗W Q.lW/@`M;-˯FT~k^TOP™}<`/9+ⴺq艝QKO͎{ۼxG `5g ckۛ,=Xm؎갻Uhem0_ @ 8@mӳ12 wפh oQ8'']L;Hq>6.li4- áS ap>\-r=ry&wfEAʨyœd ~7)ni+W<[dlɧ(6t;o$I9&u=Y/{wsiI:( Ä`-1DMr3ʔ\5w(To-G][n7}wt1t~[\V Z"r"r!]jlTT UQr2B5[ r ]tyfV>HIU^UZy4pqz~T6/;Hvjl-"nlD;ʉ]W;$LiF;b1^~ ,YE++sZMDpv`(x;9V^1I)lݷk%GCG$xmk'"y!GL8)B&M/Vgӈ7&d%i ?Dl`tzn;`WnE15.mVv_Uenp8ann|xAL6 .viW7A9F lS (,sbU"][Łtw"XF逳#%CPҪd3(5w|.[@D$kkM@Ѐ) 2_`b)us-E%vJ#a;-sEivd_뺞uPd!ও1O o EM+IgN 9o}"O:Lj .nQԲ[?;L纃DjC'X$j4G?dśэIQ7?M ~Qݔ vcH~Nwk =蹵d $7ox+)es!o.t^ۗ X>lOFTXq:RЙ`ӣUpf߂Mi't& 2QN?^x"'\;1kl`30א]IM|ub]}*5;NS<<#)7WD((9" Q!mou#bY5A *%.`_tiMG(vNFb&w/Űe^Z\RxY 1Tlv$T@ x(vr^B^to4ig=ЖHy5]b?h S9U+.`jJ{}NA7+_ho,;P|9kkHQrC#y=<yZA1mb魑i ! -R[; ALȩě3W1ڊ@ ÅU 0L SZK>?oSq6, 43Hm>Sz!\BljSinLWjz%'&bq\3eI+E3"g@ЯQ7j.8"MؐY.gcEx F[hzKx|,'0E=b7 yL=s&bTkRWS ^aQ_a{E! hpل^E:(͂%IbA%zn>n#B5~Aoх}2Oesw`:e(3)}ˠ.e(i!-C950eq'B,=!R}L+ۨQ.vұvєX~&_wY&b28./Ӌp͋(wF۳ReX*v( ~pLdA=J O(cf[5nE^jtނLO`*i_Gw.֡%3t+$}bQ"\ )c4Ĝ5o&WK "7_3/\̓:M=/6it9W.CRWRZPzdPMhQֲ]f)8{7o4a]KMglȑ{C7c*3޾sא& jbCY2'ъNԼNqAhN)킵۪ep(o*bN,)teW:;*"E8j.W:ʥbf1+Z|h- 0lH +@904<-({]aFwrCu^e~Z{wr=\a7 H ^M:=Ӧ9dFI1%cjˤSӎ:y E8:u\]VUݑ '$^!oՐc5CFR1 V1>ݲtׇV-#!{!֘,:)Z+vcË8Vks*XDNbs/n C0F<ɞpQ2(3c/S.Bk?mk4w 8̶@ -6%:4rY  xOfz@: qF \0R]auTS{*q§O2~Egx{i7/9 cK/p(.Q// (oyGCZ/|'<@%&4Hih^;nޛwL y8Z(>Wg<$'J|xPv9ds3;0qQBdž9ϣ83e|0b q}wMq\f8f;8g82~x^hf/ܜQZY*U=t!(Z#H9@$UuJ䂐J~Auw(w4ES&4Jqty83@b^A'Ʈ1$tltc]פ!?6f)J+S!:_ _i;P&eA-1Ls򶽬32ј,IDg2n1N!1R0>.VS!9<=޷F8üJxKp26$ꀿ nx;-Qަ_ !sY& 3D~,G0x 65ڡʧEyB>K.ݯpeD 꾤}^}H\i\ S]錷-UI0hGÄ̉ %@pW䄀$H͉^0)ޣ8ыM'gr2*~ebVR]L|:PG}8eL?Df2qff?fO}z!;ٯLsB{_ϛltwG.vBQ:(G1Hnǟ t.=Q:!|(oy|Q;"w?D"+_I^:f%J/( %fky;DVk(X@^&sHtzҹ8魉#+3Aq{82\w!.ʜ$z#yGgMLI z!yW 3yPʼn `|rXڧg*LƘ8vNDl$v75y ZFڧM߃#ԑvs__@ :S:8#FE$D;+Oa0I7.OOvSZCӬ!@K))C–m Al zD o]BFa9RHP8 Zi*C|$D8PTԈ73H^<PL2QNW *b=؉%(m' g9˃Z1 I2*S`{Łrb(F, )x(-) H9GO\qPd! I?D|*Y|\QݦpW~Z}Z]ɳ”Y3;DBI+ |cˁ#czVQYZM8wi|1}X$$F]bbj<e``;v(O!@)6Uz!G= @eFmfwǬC|̮_>ɩ7j֙}1asK }>KcN^V S|:,0l贘v On´4b衛2(#~EiQ'qP\I`nx12\~;`;/mK'I3$]j},f]gˆ/C}a?YL{s#)*4')^/1~u1)_wΔJ?pwe 9/X|IVFp^6_} T8uxZgWVٹpx*(k(%80#?W dS${1f)\ ǥb2"pD9-;7 \CJv4(ߐc /J C)7P{<. NE)!_ENt & ;B(И',Dc 9x!RZ>r gwqkW~E-Q8 :'5HR8DERk0u#ΧāDfHƼ6/ Gg}6Veݒ}+yV@^ UBdzJ>+]my=l0u޼lH웁$& KKK&Xp)l.B]KQN;RP2:I*F VVVc^$=w54y}_2E bp5X6/9_ 2!ӡĩg-"ON1ʦ~'Prp# 0]F jRmmvR twG l(X))f@bq˻kXk<yh-9Y 4w̪l#Y2b!gǃ-`=^ >LM$\|ݑ.Yg%;tO,9[@9Hjs- 0=`xb?Wy8uX3;q(M%%Jidr7oqQ0޻  . FA/P o=s5F2SjEL"uB)1}ˎ8,k7*=u`T_:fr=v!ƚDš\AԲ^G_ PūLCx8Ȃ^QΧc0TG`P 3PUp=uXt!9SpUH_iGsx6HL5kg/Gio_<@l8 OAghQgL(xnzw@?A Cϑ/Ϟ'pgI9A3n!M `Z4aQycbc @քc}@g*1m֧k;8Wg!Y[FȌ_4h&Jj޵pc&iTցK j/J&u`uF{T>ڦ{9Œ?%'"0 ǩ.A*B*} l4Xܤ%Q 4hh?Yvy"8zһ7o.z\<1Y DD!)5a7>s VN Z(ӻ-:/& dIΪ]ۮ@@pd'ڪ$\-W4^lPiςHUβvX0jć65|PQЍ;gD;*P@=T]sfM=1v :/l2G1 ;f)щbj2E ?M!ifH?)~C<)Ju W^6E2a Q}9Z^T 9_N}$UCȔ  3-X5djƨb!: ɱ lװ-*xvm[{ۦB2rqk&:MD47f*3q+h6KO^^2CkXSL2"+ =ihTԇcRgupB^ Pe<wc}tX1ۦ#EAX,+FC KF ⨵ᭃ5Rs])#k)cH}|{,df 6|VQ-3s>7%f aaS:{:bd7k/r3+,Iľ`sEUmb^h86̈́ɷ6sňZcGEЬHkaƳeq_BL+L 8x d1Q3#Y[_6G2/'GN 80Y}ԷjKrC3'hLƸ"`.g偫P}پ+D ;m_WQyN4 n/b9ygB_>]%x -H$PK.]@kNof@鐆dTk1M Gd4Hy8 'vg<~}ۮI퉝&ME9~݁;qj(MM{..S/7Jfڢ CA)vo.3}C~Jbv] $T& 09$@K'w˭` X׳%X %+t%~f=mO{WKёiM{%,[keQa!|aj{&&+r[U[%@ Bu81ӜЏd}{ Xp#u(`BDy9=H)b*+1P~s>h 3Oă|2K1p;I3FITh )<\_-t&MV;;&J4&RmB$yT[2lUcW zۀPHtäGfL{1p(O0$S=, D!{ʝy>.\B,|كגL&&H{%hrSG+^XLq8zzkDylUB pDD^2U,"M+G`qpz=L_0֋qe/rW89T/xkG+xK`Fz|Ŝi$j/9v^{ WБ?WL} Aқ"lBw{{3r&^Z dfE',DuO:eS)1)r!~mBSq+*&5g$U/8V:*X1ngtL#!OCWגV聆.H~m'4HHjQx>t`;4Z!ZNl%Nɋ jp\Q8wajZk.8#u-#MvQiK&s֏Ⱦ!}Z0;&[Ԕx5.0VL]~F'eّl^\0W8ToƷ}7aaV8|bfX' _l^O0(MF9F\EYՀ.ԫ=~ɬ%Xo'wX*(nS;vtDLcӰ0øFt4L E-_ꌝC &M3)<@<6n 5Ű e\DBXUjӎUg=usE+/_X sdk5[0?BzX9L6Kv@şIR_~#*3LśQ[dN.3XVǶ[%HP) ^+ W#o]n |H _ QŒ2ԍc@!K/)C :a`^G[tM];#?8qR(}`4Dn[^)i U qPFЃXMSfoƩ2({О j Sly3RuӺ2vaZn]6iR`@sD;儖 ަs.W\H} eZ%;6,U"8)/@A e$MDE5]pP {6=;x6`ϳ{>=ߨ=?7F|ɳY)&rSJxw}Ja<@VW0Kp]ҎR]5nJʑNBj]i!1ܠk|Ls&Qx,-'GۭR9 گIῂs,-k3QTJx A%%}nW.I>U ] x &&Ѫ3}yld)h\)e~5IR;ǺIeiS$iK.鐳Y I^?'jE>,!:7EElgHZMz~1Y[sߔઘ>;2|ɽC324|@XPxS A(q\?waL l`w.:_ ӟљr3S?Y'v,/ <!㤢P8s%{9 &C}NN-ODl] @*Z+eMc-ܭyZAXzh[u/Σ@ϱjC>ftʈKT Nڅ\ڕdZ"|MIڠ.v%ss&l>pt%u(6:.JgiBSNBm"AO^ق}H#7i |f,ҁ7%F0[K!|A DW3˄snRPtJE4/4XL2g  |`-y\uLo-2mj$*G{4gg4Bm;yE3β?0k:I5-Vyjr@^qqy-/#gp ">0>*fXu =MDmjg$FLʵd2>G!È֮E9Kcˀ,7Oݽ_[1E:ۏLs= xVXw9|3YwioSu.ZU0CJ&ZOKr@M+[w"_A*Y2zT#MEOWeP Q{$^7/&6&)h)B$F8>f* U^׀{$7xOu.H?ȮpF6hb'Q3 F)e}ݔ4rAegIXE܃8>N-K r7v{p {}v l蠠̙bvRbȚu,Z˭*KgYGp 5lē*7D 8TLzJ@+<0)R5^o$9*Bǒ/y701ipzɞn=0 t˱ q [wxw=VsT,O ,RU;U?Íuvdew@=;$ n}=b&$w)Zsb'{h]XC}ZJ~2Vȡ hnO*E=Ӯ"*brf X]_씍Cg?&3 F֖ZMVg@5/6pI-^zV2ys fl|'sP.Lj)Hdcǵ {IJ4$0O[*\.u 0ՠN mWP$aW%C4pw.f#7E< 'ݓ\ycrr8i5?DWcș,9ߙNJ&5nDrH01ؽYJr'17x oI> n iVPPvi03-͋)͐WLN!&LoT@.6BՊCgtNAA./lbo{$z/LbIi>if_3&7Ghs6[a-ە|w!ܹ*LSL%E|]'U_ TL~犎/OKho7GMb0z/ͯ#>~r:/EO-wQdqpi佲7MՉBT? :{5Ռ5UOz {gt/ԤڻDH5Ye5GNG-_,#`)W+P.aUVBИc漯B\0>N@ׂJT=&ҝZdf2=La1E8/gVmtY^ɕͅ@w=DؾUrA$^!yPE4= 2:sALx6_V>v-+QȳE.N -:*}.s'nĺ;\sϲ <9Se~HH7{1|.E8afϹ7:S<4y n}Zv7 C9ey Q:GB,*Ai:c [|KR'|ݪ)ب(),Jv)ӲU=%XLZ1ʧ~{q .ʟtAtd`ڱP>8z`L]rUó;}.O)1]S'Qio S5o\ Tz}1^ >x0ݛ3S뀝v]M".{E -@,Et:<X 8^ 9O|H~U-Pd<)vpbbTC4F|טÈ8g\]dE8v{0l6B[hWPUN8g4p)eb:b{gNbL 2 wL\YbG| )5ۮMPC Rfneu9Dsvp&d8MyOLTѧ3EeyאӉ@loNDq)@+niv2Cg&*DA';d!' 0 L>O"sr4 tPXޞ-0oUNP%;Bv@D8SкX̧CFe) ,h'6PSqF=wV3vM9-@k&^kS"B0ͮ-K]%_O3c_gbax /B=ː4[ $X; vҰpcTµqsKpmaފa5O}:/:&u\,X\XjY֭QtWyiC nš}jVтǢFotc/`L>7% nD Ԟ?g>{ cW94 r aVn JJ`N: ֈPNЕR6 @K4Q^MNZ-#%gh1e|"b&|DuQ)k.5_ 2 aXd[ ^kx>cs\OvpDuˣ}GT4 ʶh=x$@y  \-%x!2 l]?"xUćq-Fa!73c'7ùcEi|%=?8al@dӐ0L>Xa۽wen> |w?8=7fNEUsx{v>jJz$=фܒ] Drxn0zu ]eXAu9}kmfgX# ra% jj2ǔ[k1n3 togp]Ww $&K)k3}AW{ Ó"_?y~spK$?OmdOq` w3Ek+ULg Ya+ < ȣX> >Nt*<)aCQf6(,_&^Ha,0c\Y]XvqHD:K:)J0[9H:u22xw?0Ǧb)C`rp6~~9Ʀ\YL$&زj:D)28TA +Kg/jH6ԒR.i!B QOOOS2Bi6\uzΨ5Eeހ I)YbѷٱmKNy21nU7sCB-q7Z3p'6pcȖ[3%gK3nv9tʏbPg&ݘ .|k"n^eZnݴU3n1g 8]@B=0…^3p,@J@DDkY;3~dX0*ROjMq\+׍Q^2 o/jø?LTI*[>06cK{X`2"V^ |{{1' # lVd+PP' o/P/fiFk_S);|^<Wwx>H(ثԠbʋqqV7jd r {-!sQb:'_* 9B_VoEG !DiMX=2b1-ҡ#> 'j*>K2N׼IXUczb洘uR)joE,?ہ(^㺩&nڷ ,@pc+=6L"ss)x짙O[$Em\v' ʪvy%'܈X|.C?L,>\͜ ^s); ^y ,"{_hXepbÙ~Xn#?ևHk&>v3jx)ȥ30=Zy"ܳFN|ۑUT'3VD]/joRf:*'RWʌ|DcIX욗:|{=U' -XA7 LkGnNK"J'TJ2"Mz6R*>Bz ~wQY4ANjd9 kv݀)k71=jdYwn֎T]obFLoɤn8,jÍ̚e]ok7.3ըאX>&T߼_q&XW46N' yBZcjǍO/'z3^CpU%HAigo NV3F>D!'O9>&>[)dq1#WMވg?H 156N i%}n u ai{lysCμ}{Q~E g'YC|؋xbq>cip=νh'=蟦{W$>h:8+c-WӖD`VĂ]O' cE4@VzdM3Q&VVq2Hu/_?Y?~D؆?c}HDU=W>OE^;k޷ `my?#L p6Vkѓzp׃c }Al˳)?nЩa.b*sӫ 2>JN% ʛ \֨ӵAm\Bw~:&]o4Â\%)5I]]*h'O <*8:+Z>Ijo*rWT٫~Z`.IhV@FmW&~aE,V="JOI|G{Drwz0ϐd:=ǔmT͆sz4~y;&o$8_6xnݪR.`8Wiz2[Mv2,R"P0&SZA*`7'|W_y_Imٙ/8yW!)1g!u tHozu"QL0RF^giyf4#Ǡ*sAĒkw"R :QudUmo0_jK:qgtc}ߧ.o}f:hd$_b''_ҟ2A=iWck2]%/7X} j5pU3͌:S\ٷh}v{n)ADv*xlt$JIdKA%ɼmlwrLb$ÆMGAݚGos1@Em"):+.0Hd\8`s=W 0/hE'*@GK@ wԯh#z2^GcPS"Y+Ve3H3گ<dhhrOz㨦Ufx@5zPѽR&bO:.̋3]0_g.E盿J9`_yrUqG# g7|Y*?j[k:6P(dMIAS~ 16ΐ? 27iSΠ0\@Mt wC@ٍ 8c-8 XϿr&6 rUd. ؂8Qć1b=$QյNETȸ(8uu_, UpXo*MzUv*IIOߒPaEYu.xbe/kq~qؕ/ra}F6J6U2Q٢?ĝ+pKqljlt*[Iݮ.WyQE2 4I5+qȐ^u5IFɡc0ơ0J%@ٙazbϐ!Uo>Y79-َ.2NV9 8*օHƩ?IN=+^S"XwW {jnJ(>t)J6w.˲IM8=衝-N( ,ΩeP-󗯞_MQ ˙"¶+cg G' -sSh;#]l>->Ht}ͦ[V ;SNٔo]l\}(o69,oU[l5^Sy36%S_}ޭ`}R&d1?TwYBON )Ef"TC/jQڜS -12_ mӠzS -' 멆6UC*6lЌ}EsYtT˵dqm;@zur@f}fSt4U'raTHEG $EhuJEf||j}wUBʵ ]\zAM5~e*RÅ$(OBO9,.j=OCNAxz aBT|)]\GAp6^čp FЭdv"0qͰPvYNW4=#m")n-v:_Q4·kuJNr+.TZ\1_i|x??@UOㇳ`;mέfjU}@6qjNlN_=FOceW>}jt&^(QN/M)MNTZUi72C@4./Y0*.!N!F Ock-آW'#Zw˯YYͧY~MZ).Ń%W˯sҜ,VџǕ_"kwO]`5kk.~~Lն빮 "앮EsU,AV:=piRQ=k9lU|$aHeѧUq\_M6}EaMpw8L1)+ʡ蓅a9tHMXp:=| C(|wbu w|܆L}U'M_7qU*nL`58d Yʼn"lXhuq.垞&2j`)7iR}~%䖠%-d K:d)7AtJ:YeM\W9\pn-QF﬘tġbnD0=3(OrQ5yusÅ CS=U]R$+w^M'q17'd1wi [M?4sH1w'OwszsX6 *+ѕ3T+u93>cU]`p.Hv, Wl*n~gDWxGJ}-P b{Ǝ*vuě4ě"xuެݟQUJo?Nxܻ#ޝ _]#{謿[amzo~zoa6Yfݾ[S.dpB*O\,)o]18ޡ:NVs\*B"EXP*£"D':=n3bpAe*xWzTR%Y J)]qIHiE XɊ![)zZ&s>WL$I 33\C 5ػ~Vŷ/3yP)EYiy`׷*T*Jny l{ L$(|tEI-;GȮ}ϓO6>~PxKՊz~'en;(XO f¬O# j'rwqje7j: q쐼4L$L&LO>¿vnf8Xs 9V|=*>k޹Q'++{{j EoU`a8-{&A !W!t tAVFD@t΅0RtOvF %?DLx 5Dl+UT Z3Ge2h+A}u*Γ tkWF̰Î.q ic.xfd.N}GY}uex">QZ0]xzqm;])lZ;a3!`{m3\ C͵)D\Vkk"ÃBa 9" N:A okkLz~dkL]$iz&3'B]߆^&™*&nSt5LUEaӠ~֊R΁a>c) 86 0 yʇal0i eֽ6l<:9ffBc:_x6b$bC CA2Nz AH0F&-Q` N&N`Gy4JhLdRY!QX$.<@om" _)lg%)sJ;t DOFj)QQlua{W=?{&>\ދe#Z. @ I~`|lL3Klyif]hs.~ u y#u>~𖶷y,5֔[sw]9ޏ[8܃`c- 腰1a h[!MBجu@`[4~*+1 k98oڕ'5.HX,҄-ļqt?ݦYb) J f^F1ZuHOjJfP1ofcΧ]o#bݰ\xJ `G'I+_8[?%(BXydaLVˆ|$(!jLuPJD'E g.ؓ<&//ao/ rI6q`8״?{ y%ƃO]U}UȀM4JFH :!Aq5T I*# 5""0*4*YhN `c8S7M;<'=F4i:H_P]a {{43o% 'lƨ:*x n-;x<ᔫ 1uxGa8aZTNpGM0 UkBNwƒU;|0BDN΂B<`ZhqD[;T!LhX!XK0Uäa%  P@aT9^r oarCc&C@Lk106c# 1 Q3EtqւT%0/{ x?*6uG]>r?R'X⬾ӵJ+{M%"F] U[ΡNlՈQkBjz7OFm9O}C >8o`m_oh y[츳~~e,Ņ "'cH#~z"WyY\5|tAgINY F#&A,7 m)> 5Bh (A @!}DJH)S sIC2'X BCӐgkq>٥/Fc% y "~H1YY 㜁C})Wz$SUa8 լ)BcQ~b/ ruse$y:}w%ӿpy2hM|@&'qk#IO74TL#u1*~~Oe5pX9{,Ǟг4_UbBD#ekS!TsvRP&z9,>,Кn:[n"(fKN`[V(1v(#`=i㱈@0IWid߬tnLk@c0x1WxQ%#`!ͼU'. .w Nl@ƒb0'DduQXiL2"8383097iLr>jf8"zdٯDc{*TRG?tATgI zsA;Ƞ hPw2a:hPzHg@=jTcHr[Hbs?#o'B65CB!ʦPET >D v'QK2O)ԁrqa^e~$ȧQ=k t֕d$Ǔ8ծ~=I{pT*BDRXHQ:>~\@U.hTUB,ݛ%$5Hs?ߛyD:>&AU G3S:}\uq 9DN ijX(XO.e*$6G>&ηV7\lvPST݂\J?hdKxno`:G*>"ҬT5{Nr@ Ndd*c3 h?,Y[\LٰGd?yq/=>{t]Cܳ 1cl ~hٕύ"$~nY7H1"~(3s??~rF>ĽPYXKtv6u?zIZ"t .ʸKS Ňuȏ{ 04ɜ֔G+huZja4ԨR%]b3M?" 6hR YZЦOi0Aƫ!Ԭ+Y8zNk6KLr5utF˻u{r>\#{*_Ml.Qh ԹA_ke6 Mh1_t* :Di/#E>gَsKHXpFT J s%%'eU/аCL]f .6 %YM`12[}a/G` }Tq?@V6qe(84X9⼛ua,6J"m Pb 7+/H)@#7x lW\D3 3E C"_gH)xl$  A{']Z] NtR󲡞aĝ|S?A&蘽$3X@u->˻@41g`t ܭDW /:M^b ?;'I4%y<7_k{qЏ::0o(UA}kr_o[^E훧-m?S[7zz[ۆ˭]}_2^೭m _ެ^~ۯ=}_s{ }Uo}>Ӫ^of%YvcG5_w}RtLZ9|7~~ʰ9ֻ~L~fEG4 'V^ ~{5-V6d߀M`u¯K{_~nOgja{P6}J]̻rIFg({H}Z.K;@sKxq^2GË7%Q>9(m qC!g9eu1prMdNC|fh #=_XXA,X.,ł.Z_u,6]_kn}a'C8 Gt:w.df)=#Pl3F:׏\cwc=] ǥo+:)LFQ]Kuȝ2NyyǗbf&v ˨?pTڿߡ㑜r%xi3;'_k#+P{``b9wRJ+}uRD|M-c1Aݔޛz&u0t3HػĬ;N~؄b w u0`;1D񗯰}9xPgFNDAR2 ~z`NdM馫l:atKT~L 4yyeLGCSJtB}ewiӵa gCћҝόl?6ewkؾcwnFٮgk|2;# ޫTkAE1.1jl7Tە?TU{uڊֶg_n_sYC|؋xbq>cip=νh'=蟦{W$>h:8+c-WӖD`VĂ]O' cE4@VzdM3Q&VVq2Hu/_?Y?~D؆?c}HDU=W>OE^;k޷ `myLock.h010064400020550007177000000000740653410636700131450ustar00clevecompmath00000400000006#ifndef _Lock_ #define _Lock_ #include "Lock/Lock.h" #endif Lock/Lock.h010064400020550007177000000076460653410576700140540ustar00clevecompmath00000400000006/* Lock.h */ #include "../cfiles.h" #define TT_NONE 0 #define TT_SOLARIS 1 #define TT_POSIX 2 #define THREAD_TYPE TT_POSIX #if THREAD_TYPE == TT_SOLARIS #include #include #endif #if THREAD_TYPE == TT_POSIX #include #endif #define NO_LOCK 0 #define LOCK_IN_PROCESS 1 #define LOCK_OVER_ALL_PROCESSES 2 /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- this structure contains a lock, presently solaris and posix thread packages are supported mutex -- pointer to a lock nlocks -- number of locks nunlocks -- number of unlocks created -- 97aug22, cca --------------------------------------------------------- */ typedef struct _Lock Lock ; struct _Lock { #if THREAD_TYPE == TT_SOLARIS mutex_t *mutex ; #endif #if THREAD_TYPE == TT_POSIX pthread_mutex_t *mutex ; #endif #if THREAD_TYPE == TT_NONE void *mutex ; #endif int nlocks ; int nunlocks ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- method found in basics.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 97aug22, cca ----------------------- */ Lock * Lock_new ( void ) ; /* ----------------------- set the default fields created -- 97aug22, cca ----------------------- */ void Lock_setDefaultFields ( Lock *lock ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 97aug22, cca -------------------------------------------------- */ void Lock_clearData ( Lock *lock ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 97aug22, cca ------------------------------------------ */ void Lock_free ( Lock *lock ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- method found in init.c ------------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- basic initializer lockflag -- flag to specify lock status SOLARIS: lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize only threads in this process. lockflag = 2 --> mutex lock is allocated and it can synchronize only threads in this and other processes. POSIX: lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize only threads in this process. created -- 97aug22, cca ------------------------------------------------------------------ */ void Lock_init ( Lock *lock, int lockflag ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- method found in util.c ------------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- lock the lock created -- 97aug22, cca ----------------------- */ void Lock_lock ( Lock *lock ) ; /* ----------------------- unlock the lock created -- 97aug22, cca ----------------------- */ void Lock_unlock ( Lock *lock ) ; /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ Lock/makefile010064400020550007177000000001410663622363500144700ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean Lock/src/makefile010064400020550007177000000006450663602576300152720ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Lock $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG Lock/src/makeGlobalLib010064400020550007177000000005550660026106200161630ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Lock SRC = basics.c \ init.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Lock/src/basics.c010064400020550007177000000045230653410576600152000ustar00clevecompmath00000400000006/* basics.c */ #include "../Lock.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 97aug22, cca ----------------------- */ Lock * Lock_new ( void ) { Lock *lock ; ALLOCATE(lock, struct _Lock, 1) ; Lock_setDefaultFields(lock) ; return(lock) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 97aug22, cca ----------------------- */ void Lock_setDefaultFields ( Lock *lock ) { if ( lock == NULL ) { fprintf(stderr, "\n fatal error in Lock_setDefaultFields(%p)" "\n bad input", lock) ; exit(-1) ; } lock->nlocks = 0 ; lock->nunlocks = 0 ; lock->mutex = NULL ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 97aug22, cca -------------------------------------------------- */ void Lock_clearData ( Lock *lock ) { /* --------------- check the input --------------- */ if ( lock == NULL ) { fprintf(stderr, "\n fatal error in Lock_clearData(%p)" "\n bad input\n", lock) ; exit(-1) ; } /* ------------------------ free the working storage ------------------------ */ if ( lock->mutex != NULL ) { /* ------------------------- destroy and free the lock ------------------------- */ #if THREAD_TYPE == TT_SOLARIS mutex_destroy(lock->mutex) ; #endif #if THREAD_TYPE == TT_POSIX pthread_mutex_destroy(lock->mutex) ; #endif FREE(lock->mutex) ; } /* ---------------------- set the default fields ---------------------- */ Lock_setDefaultFields(lock) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 97aug22, cca ------------------------------------------ */ void Lock_free ( Lock *lock ) { if ( lock == NULL ) { fprintf(stderr, "\n fatal error in Lock_free(%p)" "\n bad input\n", lock) ; exit(-1) ; } Lock_clearData(lock) ; FREE(lock) ; return ; } /*--------------------------------------------------------------------*/ Lock/src/init.c010064400020550007177000000027450653410576600147030ustar00clevecompmath00000400000006/* init.c */ #include "../Lock.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- basic initializer lockflag -- flag to specify lock status SOLARIS: lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize only threads in this process. lockflag = 2 --> mutex lock is allocated and it can synchronize only threads in this and other processes. POSIX: lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize only threads in this process. created -- 97aug22, cca ------------------------------------------------------------------ */ void Lock_init ( Lock *lock, int lockflag ) { if ( lockflag > 0 ) { /* ----------------- allocate the lock ----------------- */ #if THREAD_TYPE == TT_SOLARIS ALLOCATE(lock->mutex, mutex_t, 1) ; if ( lockflag == 1 ) { mutex_init(lock->mutex, USYNC_THREAD, NULL) ; } else if ( lockflag == 2 ) { mutex_init(lock->mutex, USYNC_PROCESS, NULL) ; } #endif #if THREAD_TYPE == TT_POSIX ALLOCATE(lock->mutex, pthread_mutex_t, 1) ; pthread_mutex_init(lock->mutex, NULL) ; #endif } return ; } /*--------------------------------------------------------------------*/ Lock/src/util.c010064400020550007177000000045670653410576600147210ustar00clevecompmath00000400000006/* util.c */ #include "../Lock.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- lock the lock created -- 97aug22, cca ----------------------- */ void Lock_lock ( Lock *lock ) { /* --------------- check the input --------------- */ if ( lock == NULL ) { fprintf(stderr, "\n fatal error in Lock_lock(%p)" "\n bad input\n", lock) ; exit(-1) ; } /* fprintf(stdout, "\n inside Lock_lock()") ; fflush(stdout) ; */ #if THREAD_TYPE == TT_SOLARIS #if MYDEBUG > 0 fprintf(stdout, "\n thread %d, lock %p : Lock_lock : solaris locking", thr_self(), lock->mutex) ; fflush(stdout) ; #endif mutex_lock(lock->mutex) ; #if MYDEBUG > 0 fprintf(stdout, "\n thread %d, lock %p : Lock_lock : solaris lock done", thr_self(), lock->mutex) ; fflush(stdout) ; #endif #endif #if THREAD_TYPE == TT_POSIX #if MYDEBUG > 0 fprintf(stdout, "\n Lock_lock : posix locking") ; fflush(stdout) ; #endif pthread_mutex_lock(lock->mutex) ; #if MYDEBUG > 0 fprintf(stdout, "\n Lock_lock : posix lock done") ; fflush(stdout) ; #endif #endif lock->nlocks++ ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- unlock the lock created -- 97aug22, cca ----------------------- */ void Lock_unlock ( Lock *lock ) { /* --------------- check the input --------------- */ if ( lock == NULL ) { fprintf(stderr, "\n fatal error in Lock_unlock(%p)" "\n bad input\n", lock) ; exit(-1) ; } lock->nunlocks++ ; /* fprintf(stdout, "\n inside Lock_unlock()") ; fflush(stdout) ; */ #if THREAD_TYPE == TT_SOLARIS #if MYDEBUG > 0 fprintf(stdout, "\n thread %d, lock %p : Lock_unlock : solaris unlocking", thr_self(), lock->mutex) ; fflush(stdout) ; #endif mutex_unlock(lock->mutex) ; #if MYDEBUG > 0 fprintf(stdout, "\n thread %d, lock %p : Lock_unlock : solaris unlocking done", thr_self(), lock->mutex) ; fflush(stdout) ; #endif #endif #if THREAD_TYPE == TT_POSIX #if MYDEBUG > 0 fprintf(stdout, "\n Lock_unlock : posix unlocking") ; fflush(stdout) ; #endif pthread_mutex_unlock(lock->mutex) ; #if MYDEBUG > 0 fprintf(stdout, "\n Lock_unlock : posix unlocking done") ; fflush(stdout) ; #endif #endif return ; } /*--------------------------------------------------------------------*/ r, "\n fatal error in Lock_lock(%p)" "\n bad input\n", lock) ; exit(-1) ; } /* fprintf(stdout, "\n inside Lock_lock()") ; fLock/doc/004275500020550007177000000000000665065646600135565ustar00clevecompmath00000400000006Lock/doc/proto.tex010064400020550007177000000104210653410576700154260ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Lock} methods} \label{section:Lock:proto} \par \subsection{Basic methods} \label{subsection:Lock:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Lock * Lock_new ( void ) ; \end{verbatim} \index{Lock_new@{\tt Lock\_new()}} This method simply allocates storage for the {\tt Lock} structure and then sets the default fields by a call to {\tt Lock\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Lock_setDefaultFields ( Lock *lock ) ; \end{verbatim} \index{Lock_setDefaultFields@{\tt Lock\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt nlocks} and {\tt nunlocks} are zero, and {\tt mutex} is {\tt NULL}. \par \noindent {\it Error checking:} If {\tt lock} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Lock_clearData ( Lock *lock ) ; \end{verbatim} \index{Lock_clearData@{\tt Lock\_clearData()}} This method clears the data for the object. If {\tt lock->mutex} is not {\tt NULL}, then {\tt mutex\_destroy(lock->mutex)} is called (for the Solaris thread package) or {\tt pthread\_mutex\_destroy(lock->mutex)} is called (for the POSIX thread package), The method concludes with a call to {\tt Lock\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt lock} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Lock_free ( Lock *lock ) ; \end{verbatim} \index{Lock_free@{\tt Lock\_free()}} This method releases any storage by a call to {\tt Lock\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt lock} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer method} \label{subsection:Lock:proto:initializers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Lock_init ( Lock *lock, int lockflag ) ; \end{verbatim} \index{Lock_init@{\tt Lock\_init()}} This is the basic initializer method. Any previous data is cleared with a call to {\tt Lock\_clearData()}. If {\tt lockflag = 0}, then no lock is initialized. For the Solaris thread package, {\tt lockflag = 1} means the lock will be initialized to synchronize only threads in this process, while {\tt lockflag = 2} means the lock will be initialized to synchronize threads across processes. For the POSIX thread package, {\tt lockflag != 0} means the lock will be initialized to synchronize only threads in this process. \par \noindent {\it Error checking:} If {\tt lock} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:Lock:proto:Utility} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Lock_lock ( Lock *lock ) ; \end{verbatim} \index{Lock_lock@{\tt Lock\_lock()}} This method locks the lock. \par \noindent {\it Error checking:} If {\tt lock} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Lock_unlock ( Lock *lock ) ; \end{verbatim} \index{Lock_unlock@{\tt Lock\_unlock()}} This method unlocks the lock. \par \noindent {\it Error checking:} If {\tt lock} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} Lock/doc/main.log010064400020550007177000000065110665065636600152020ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 18 JAN 1999 08:10 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size11.clo File: size11.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file main.idx (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. (intro.tex Chapter 1. ) (dataStructure.tex LaTeX Font Info: Try loading font information for OMS+cmr on input line 7. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10.95> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 7. ) (proto.tex [1 ] Overfull \hbox (64.38225pt too wide) in paragraph at lines 40--47 []\OT1/cmr/m/n/10.95 This method clears the data for the ob-ject. If \OT1/cmtt/ m/n/10.95 lock->mutex \OT1/cmr/m/n/10.95 is not \OT1/cmtt/m/n/10.95 NULL\OT1/cm r/m/n/10.95 , then \OT1/cmtt/m/n/10.95 mutex[]destroy(lock->mutex) [] Overfull \hbox (16.63823pt too wide) in paragraph at lines 40--47 \OT1/cmr/m/n/10.95 (for the POSIX thread pack-age), The method con-cludes with a call to \OT1/cmtt/m/n/10.95 Lock[]setDefaultFields()\OT1/cmr/m/n/10.95 . [] Overfull \hbox (16.3256pt too wide) in paragraph at lines 76--85 []\OT1/cmr/m/n/10.95 This is the ba-sic ini-tial-izer method. Any pre-vi-ous da ta is cleared with a call to \OT1/cmtt/m/n/10.95 Lock[]clearData()\OT1/cmr/m/n/ 10.95 . [] [2]) (main.ind [3] [4 ]) (main.aux) ) Here is how much of TeX's memory you used: 513 strings out of 10908 5184 string characters out of 72189 51716 words of memory out of 262141 3433 multiletter control sequences out of 9500 7824 words of font info for 29 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 22i,5n,21p,176b,281s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (4 pages, 6792 bytes). Lock/doc/main.tex010064400020550007177000000010700665065626200152070ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \input psfig \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Lock} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Lock} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} Lock/doc/intro.tex010064400020550007177000000026710653552773300154300ustar00clevecompmath00000400000006\par \chapter{{\tt Lock}: Mutual Exclusion Lock object} \label{chapter:Lock} \par The {\tt Lock} object is an object that is used to insulate the rest of the library from the particular thread package that is active. The {\tt FrontMtx}, {\tt ChvList}, {\tt ChvManager}, {\tt SubMtxList} and {\tt SubMtxManager} objects all may contain a mutual exclusion lock to govern access to their critical sections of code in a multithreaded environment. Instead of putting the raw code that is specific to a particular thread library into each of these objects, each has a {\tt Lock} object. It is this {\tt Lock} object that contains the code and data structures for the different thread libraries. \par At present we have the Solaris and POSIX thread libraries supported by the {\tt Lock} object. The header file {\tt Lock.h} contains {\tt \#if/\#endif} statements that switch over the supported libraries. The {\tt THREAD\_TYPE} parameter is used to make the switch. Porting the library to another thread package requires making changes to the {\tt Lock} object. The parallel factor and solve methods that belong to the {\tt FrontMtx} object also need to have additional code inserted into them to govern thread creation, joining, etc, but the switch is made by the {\tt THREAD\_TYPE} definition found in the header file {\tt Lock.h}. It is possible to use the code without any thread package --- simply set {\tt THREAD\_TYPE} to {\tt TT\_NONE} in the {\tt Lock.h} file. Lock/doc/dataStructure.tex010064400020550007177000000006700653410576700171220ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:Lock:dataStructure} \par The {\tt Lock} structure has three fields. \begin{itemize} \item {\tt int nlocks} : number of locks made. \item {\tt int nunlocks} : number of unlocks made. \item the mutual exclusion lock \par For Solaris threads we have {\tt mutex\_t *mutex}. \par For POSIX threads we have {\tt pthread\_mutex\_t *mutex}. \par For no threads we have {\tt void *mutex}. \end{itemize} Lock/doc/main.idx010064400020550007177000000005370665065636600152070ustar00clevecompmath00000400000006\indexentry{Lock_new@{\tt Lock\_new()}}{2} \indexentry{Lock_setDefaultFields@{\tt Lock\_setDefaultFields()}}{2} \indexentry{Lock_clearData@{\tt Lock\_clearData()}}{2} \indexentry{Lock_free@{\tt Lock\_free()}}{2} \indexentry{Lock_init@{\tt Lock\_init()}}{2} \indexentry{Lock_lock@{\tt Lock\_lock()}}{2} \indexentry{Lock_unlock@{\tt Lock\_unlock()}}{3} Lock/doc/main.aux010064400020550007177000000016230665065636600152150ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt Lock}: Mutual Exclusion Lock object}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:Lock}{{1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{1}} \newlabel{section:Lock:dataStructure}{{1.1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt Lock} methods}{2}} \newlabel{section:Lock:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{2}} \newlabel{subsection:Lock:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Initializer method}{2}} \newlabel{subsection:Lock:proto:initializers}{{1.2.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Utility methods}{2}} \newlabel{subsection:Lock:proto:Utility}{{1.2.3}{2}} Lock/doc/main.ind010064400020550007177000000004060665065637100151640ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Lock\_clearData()}, 2 \item {\tt Lock\_free()}, 2 \item {\tt Lock\_init()}, 2 \item {\tt Lock\_lock()}, 2 \item {\tt Lock\_new()}, 2 \item {\tt Lock\_setDefaultFields()}, 2 \item {\tt Lock\_unlock()}, 3 \end{theindex} Lock/doc/main.ilg010064400020550007177000000004550665065637100151710ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (7 entries accepted, 0 rejected). Sorting entries....done (22 comparisons). Generating output file main.ind....done (11 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Lock/doc/makefile010064400020550007177000000000270654276745100152450ustar00clevecompmath00000400000006clean : - rm -f *.dvi MPI.h010064400020550007177000000000770660277357200127110ustar00clevecompmath00000400000006#ifndef _MPI_ #define _MPI_ #include "MPI/spoolesMPI.h" #endif MPI/spoolesMPI.h010064400020550007177000001173000660347020700147270ustar00clevecompmath00000400000006/* spoolesMPI.h */ #ifndef _SPOOLES_MPI_ #define _SPOOLES_MPI_ #include #include "../FrontMtx.h" #include "../misc.h" #include "../timings.h" #include "../SymbFac.h" #include "../ETree.h" #include "../SolveMap.h" #include "../IVL.h" #include "../IV.h" #include "../Ideq.h" #include "../Pencil.h" #include "../Drand.h" #endif /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in IVallgather.c ------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------------------------------- purpose -- the IV objects objIV and ownersIV are found on each process. the ownersIV object is identical over all the processes, and owners[ii] tells which processes owns location ii of the obj[] vector. on return from this entry, the obj[] vector is replicated over all the processes. each process sends the (ii,obj[ii]) pairs that it owns to all the other processes. created -- 98apr02, cca ----------------------------------------------------------------- */ void IV_MPI_allgather ( IV *objIV, IV *ownersIV, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in IVLallgather.c ----------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------- purpose -- the IVL object ivl and IV object ownersIV are both found on each process. the ownersIV object is identical over all the processes, and owners[ii] tells which processes owns list ii of the ivl object. on return from this method, the ivl object is replicated over all the processes. each process sends the lists that it owns to all the other processes. created -- 98apr03, cca ------------------------------------------------------------- */ void IVL_MPI_allgather ( IVL *ivl, IV *ownersIV, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in IVL_alltoall.c ----------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ this method is used during the setup for matrix-vector multiplies. each processor has computed the vertices it needs from other processors, these lists are contained in sendIVL. on return, recvIVL contains the lists of vertices this processor must send to all others. sendIVL -- on input, list[q] contains the vertices needed by this processor that are owned by q recvIVL -- on output, list[q] contains the vertices owned by this processor that are needed by q. note, if NULL on input, a new IVL object is allocated stats[] -- statistics vector stats[0] -- contains # of sends stats[1] -- contains # of receives stats[2] -- contains # of bytes sent stats[3] -- contains # of bytes received firsttag -- first tag for messages, tags in range [firsttag, firsttag+nproc-1] are used return value -- recvIVL created -- 98jul26, cca ------------------------------------------------------------------ */ IVL * IVL_MPI_alltoall ( IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in aggListMPI.c ------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- create, initialize and return a ChvList object to deal with aggregate chevrons created -- 98may21, cca ----------------------------------------------- */ ChvList * FrontMtx_MPI_aggregateList ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in splitDenseMtx.c ---------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------------- purpose -- to split a DenseMtx object by rows mtx -- DenseMtx object rowmapIV -- map from rows to owning processes firsttag -- first tag to be used in these messages stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- message level msgFile -- message file comm -- MPI communicator return value -- a new DenseMtx object filled with the owned rows created -- 98may16, cca ----------------------------------------------------------------- */ DenseMtx * DenseMtx_MPI_splitByRows ( DenseMtx *mtx, IV *rowmapIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /* ----------------------------------------------------------------- purpose -- to scatter a DenseMtx object by rows Xglobal -- global DenseMtx object, significant only for root Xlocal -- local DenseMtx object, if NULL on input, will be created if necessary rowmapIV -- map from rows to owning processes firsttag -- first tag to be used in these messages stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- message level msgFile -- message file comm -- MPI communicator return value -- Xlocal, a local DenseMtx object, may be NULL created -- 98may16, cca modified -- 98sep26, cca mtx is not modified ----------------------------------------------------------------- */ DenseMtx * DenseMtx_MPI_splitFromGlobalByRows ( DenseMtx *Xglobal, DenseMtx *Xlocal, IV *rowmapIV, int root, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /* ----------------------------------------------------------------- purpose -- to merge a DenseMtx object by rows Xlocal -- DenseMtx object, can be NULL Xglobal -- DenseMtx object, can be NULL significant only for root firsttag -- first tag to be used in these messages stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- message level msgFile -- message file comm -- MPI communicator return value -- if processor is root Xglobal is returned, if was NULL on input, it is created else NULL endif Xlocal is not modified created -- 98sep27, cca ----------------------------------------------------------------- */ DenseMtx * DenseMtx_MPI_mergeToGlobalByRows ( DenseMtx *Xglobal, DenseMtx *Xlocal, int root, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in splitInpMtx.c ----------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ purpose -- to split a distributed InpMtx object inpmtx -- pointer to the local InpMtx object mapIV -- pointer to the map from vertices to processes firsttag -- first tag value, one will be used stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- local message level msgFile -- local message file comm -- MPI communication structure return value -- pointer to the new InpMtx object that contains the owned entries. created -- 97jun20, cca modified -- 97oct17, cca stats added ------------------------------------------------------------ */ InpMtx * InpMtx_MPI_split ( InpMtx *inpmtx, IV *mapIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /* ------------------------------------------------------------ purpose -- to split a distributed InpMtx object Aglobal -- pointer to the global InpMtx object, significant only for root processor Alocal -- pointer to the local InpMtx object, if NULL and will be nonempty, it will be created mapIV -- pointer to the map from vertices to processes root -- processor that presently owns the global matrix firsttag -- first tag value, one will be used stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- local message level msgFile -- local message file comm -- MPI communication structure return value -- pointer to the local InpMtx object that contains the owned entries. created -- 98may16, cca modified -- 98sep26, cca inpmtx is not modified ------------------------------------------------------------ */ InpMtx * InpMtx_MPI_splitFromGlobal ( InpMtx *Aglobal, InpMtx *Alocal, IV *mapIV, int root, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in splitPencil.c ------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- purpose -- to split a distributed Pencil object pencil -- pointer to the local Pencil object mapIV -- pointer to the map from vertices to processes firsttag -- first tag value, two will be used, tag and tag+1 stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- local message level msgFile -- local message file comm -- MPI communication structure created -- 98may20, cca -------------------------------------------------------------- */ void Pencil_MPI_split ( Pencil *pencil, IV *mapIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in symbfacMPI.c ------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ perform the symbolic factorization in parallel input -- frontETree -- front tree for the factorization frontOwnersIV -- map from fronts to owning process pencil -- matrix pencil object firsttag -- first tag to be used for messages, will use tag, ..., tag + nfront - 1 msglvl -- message level msgFile -- message file comm -- MPI communicator return value -- symbfacIVL -- contains front indices for supported fronts created -- 98may20, cca ------------------------------------------------------------ */ IVL * SymbFac_MPI_initFromPencil ( ETree *frontETree, IV *frontOwnersIV, Pencil *pencil, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /* ------------------------------------------------------------ perform the symbolic factorization in parallel input -- frontETree -- front tree for the factorization frontOwnersIV -- map from fronts to owning process inpmtx -- matrix object firsttag -- first tag to be used for messages, will use tag, ..., tag + nfront - 1 msglvl -- message level msgFile -- message file comm -- MPI communicator return value -- symbfacIVL -- contains front indices for supported fronts created -- 98may20, cca ------------------------------------------------------------ */ IVL * SymbFac_MPI_initFromInpMtx ( ETree *frontETree, IV *frontOwnersIV, InpMtx *inpmtx, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in postProcess.c ------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- purpose -- post-process the factorization (1) permute row and column adjacency objects if necessary (2) permute lower and upper matrices if necessary (3) update the block adjacency objects if necessary (4) split the chevron submatrices into submatrices and make the submatrix indices local w.r.t their fronts created -- 98may20, cca -------------------------------------------------------------- */ void FrontMtx_MPI_postProcess ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /* ------------------------------------------------------------- purpose -- to permute the indices of the upper adjacency structure so that for each front J, bnd{J} is in ascending order w.r.t. K cup bnd{K} for par[J] = K. process q sends to process r one message that contains J cup bnd{J} for all J owned by q and needed by r. once all the indices for the supported fronts are present, the indices in the upper adjacency structure are reordered as necessary. created -- 98may20, cca ------------------------------------------------------------- */ void FrontMtx_MPI_permuteUpperAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /* ------------------------------------------------------------- purpose -- to permute the indices of the lower adjacency structure so that for each front J, bnd{J} is in ascending order w.r.t. K cup bnd{K} for par[J] = K. process q sends to process r one message that contains J cup bnd{J} for all J owned by q and needed by r. once all the indices for the supported fronts are present, the indices in the lower adjacency structure are reordered as necessary. created -- 98may20, cca ------------------------------------------------------------- */ void FrontMtx_MPI_permuteLowerAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in fullAdjMPI.c ------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- purpose -- given a distributed InpMtx object, gather all the indices onto each process and create an IVL object that contains the full adjacency structure created -- 97dec17, cca ----------------------------------------------------------- */ IVL * InpMtx_MPI_fullAdjacency ( InpMtx *inpmtx, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm ) ; /* ----------------------------------------------------------- purpose -- given a distributed Pencil object, gather all the indices onto each process and create an IVL object that contains the full adjacency structure created -- 97dec18, cca ----------------------------------------------------------- */ IVL * Pencil_MPI_fullAdjacency ( Pencil *pencil, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in factorMPI.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------- this is the method that computes the parallel factorization of a sparse matrix A using MPI. input --- frontmtx -- front matrix object that holds the factors inpmtx -- matrix object for A tau -- tolerance used in pivoting droptol -- tolerance used in the approximate factorization chvmanager -- ChvManager object to handle working storage frontOwnersIV -- map from fronts to owning processes lookahead -- parameter that governs the ``lookahead'' behavior, use lookahead = 0 as a default cpus -- vector to store breakdown of cpu times cpus[ 0] -- initialize fronts cpus[ 1] -- load original entries cpus[ 2] -- update fronts cpus[ 3] -- insert aggregate data cpus[ 4] -- assemble aggregate data cpus[ 5] -- assemble postponed data cpus[ 6] -- factor fronts cpus[ 7] -- extract postponed data cpus[ 8] -- store factor entries cpus[ 9] -- post initial receives cpus[10] -- check for received messages cpus[11] -- post initial sends cpus[12] -- check for sent messages stats -- vector to store statistics stats[ 0] -- # of aggregate sends stats[ 1] -- # of bytes in the aggregate sends stats[ 2] -- # of aggregate received stats[ 3] -- # of bytes in the aggregate received stats[ 4] -- # of postponed data sends stats[ 5] -- # of bytes in the postponed data sends stats[ 6] -- # of postponed data received stats[ 7] -- # of bytes in the postponed data received stats[ 8] -- # of active Chv objects (working storage) stats[ 9] -- # of active bytes in working storage stats[10] -- # of requested bytes in working storage msglvl -- message level msgFile -- message file firsttag -- first tag to use during the factorization, reserved tags are tag, ..., tag + 3*nfront + 2 comm -- MPI communicator return value -- if process id is zero, a pointer to the first Chv object in a list that contains postponed rows and columns that could not be eliminated. created -- 98may21, cca ------------------------------------------------------------------- */ Chv * FrontMtx_MPI_factorInpMtx ( FrontMtx *frontmtx, InpMtx *inpmtx, double tau, double droptol, ChvManager *chvmanager, IV *frontOwnersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /* ------------------------------------------------------------------- this is the method that computes the parallel factorization of A + sigma*B using MPI. input --- frontmtx -- front matrix object that holds the factors pencil -- matrix pencil object, contains A + sigma*B tau -- tolerance used in pivoting droptol -- tolerance used in the approximate factorization chvmanager -- ChvManager object to handle working storage frontOwnersIV -- map from fronts to owning processes lookahead -- parameter that governs the ``lookahead'' behavior, use lookahead = 0 as a default cpus -- vector to store breakdown of cpu times cpus[ 0] -- initialize fronts cpus[ 1] -- load original entries cpus[ 2] -- update fronts cpus[ 3] -- insert aggregate data cpus[ 4] -- assemble aggregate data cpus[ 5] -- assemble postponed data cpus[ 6] -- factor fronts cpus[ 7] -- extract postponed data cpus[ 8] -- store factor entries cpus[ 9] -- post initial receives cpus[10] -- check for received messages cpus[11] -- post initial sends cpus[12] -- check for sent messages stats -- vector to store statistics stats[ 0] -- # of aggregate sends stats[ 1] -- # of bytes in the aggregate sends stats[ 2] -- # of aggregate received stats[ 3] -- # of bytes in the aggregate received stats[ 4] -- # of postponed data sends stats[ 5] -- # of bytes in the postponed data sends stats[ 6] -- # of postponed data received stats[ 7] -- # of bytes in the postponed data received stats[ 8] -- # of active Chv objects (working storage) stats[ 9] -- # of active bytes in working storage stats[10] -- # of requested bytes in working storage msglvl -- message level msgFile -- message file firsttag -- first tag to use during the factorization, reserved tags are tag, ..., tag + 3*nfront + 2 comm -- MPI communicator return value -- if process id is zero, a pointer to the first Chv object in a list that contains postponed rows and columns that could not be eliminated. created -- 98may21, cca ------------------------------------------------------------------- */ Chv * FrontMtx_MPI_factorPencil ( FrontMtx *frontmtx, Pencil *pencil, double tau, double droptol, ChvManager *chvmanager, IV *frontOwnersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in splitFrontMtx.c ---------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------- purpose -- after the factorization has been computed and the front matrices have been split into submatrices, and after a solve map object has been computed, the submatrices are sent to the process that owns them. frontmtx -- stores the factor matrix solvemap -- stores the map from submatrices to processes created -- 98may21, cca ------------------------------------------------------------- */ void FrontMtx_MPI_split ( FrontMtx *frontmtx, SolveMap *solvemap, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in Graph_Bcast.c ------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------------- purpose -- to broadcast a Graph IVL object from one processor to all the others created -- 98sep10, cca ----------------------------------------------- */ Graph * Graph_MPI_Bcast ( Graph *graph, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in IVL_Bcast.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------ purpose -- to broadcast an IVL object from one processor to all the others created -- 98sep10, cca ------------------------------------------ */ IVL * IVL_MPI_Bcast ( IVL *ivl, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in ETreeBcast.c ------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------- purpose -- to broadcast a front tree object from one process to all the others created -- 98may21, cca --------------------------------------------- */ ETree * ETree_MPI_Bcast ( ETree *etree, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in rowmapMPI.c -------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- purpose -- after pivoting for a nonsymmetric factorization, some delayed rows may belong to a process other than its original owner. this method returns an IV object that maps rows to owning processes. created -- 98may22, cca ----------------------------------------------------------- */ IV * FrontMtx_MPI_rowmapIV ( FrontMtx *frontmtx, IV *frontOwnersIV, int msglvl, FILE *msgFile, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in colmapMPI.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------- purpose -- after pivoting for a nonsymmetric factorization, some delayed columns may belong to a process other than its original owner. this method returns an IV object that maps columns to owning processes. created -- 98may22, cca ------------------------------------------------------------- */ IV * FrontMtx_MPI_colmapIV ( FrontMtx *frontmtx, IV *frontOwnersIV, int msglvl, FILE *msgFile, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in utilities.c -------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------- return the maximum tag value created -- 98jan08, cca ---------------------------- */ int maxTagMPI ( MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in solveMPI.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------- MPI solve method for (L + I)D(I + U)X = B or (U^T + I)D(I + U)X = B created -- 98may21, ca ------------------------------------------------------------------- */ void FrontMtx_MPI_solve ( FrontMtx *frontmtx, DenseMtx *solmtx, DenseMtx *rhsmtx, SubMtxManager *mtxmanager, SolveMap *solvemap, double cpus[], int stats[], int msglvl, FILE *msgFile, int firstTag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ #define MMM_WITH_A 0 #define MMM_WITH_AT 1 #define MMM_WITH_AH 2 #define MMM_LOCAL 1 #define MMM_GLOBAL 2 /* -------------------------------------------------------------------- symflag -- symmetry flag SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC opflag -- operations flag 0 (MMM_WITH_A) -- multiply with A 1 (MMM_WITH_AT) -- multiply with A^T 2 (MMM_WITH_AH) -- multiply with A^H XownedIV -- list of rows of X owned by this processor XsupIV -- vector of rows of X that are supported by this processor XmapIV -- vector that maps global rows of X to local rows of X that are supported by this processor, if jj = Xsup[ii] then Xmap[jj] = ii else Xmap[jj] = -1 endif XsendIVL -- list jproc contains the local entries of Xloc that get sent to processor jproc. XrecvIVL -- list jproc contains the local entries of Xsupp that will be received from processor jproc. YownedIV -- list of rows of Y owned by this processor Xsupp -- DenseMtx object used in the matrix-matrix multiply YsupIV -- vector of rows of Y that are supported by this processor YmapIV -- vector that maps global rows of Y to local rows of Y that are supported by this processor, if jj = Ysup[ii] then Ymap[jj] = ii else Ymap[jj] = -1 endif YsendIVL -- list jproc contains the local entries of Yloc that get sent to processor jproc. YrecvIVL -- list jproc contains the local entries of Ysupp that will be received from processor jproc. Ysupp -- DenseMtx object used in the matrix-matrix multiply created -- 98aug21, cca -------------------------------------------------------------------- */ typedef struct _MatMulInfo MatMulInfo ; struct _MatMulInfo { int symflag ; int opflag ; IV *XownedIV ; IV *XsupIV ; IV *XmapIV ; IVL *XsendIVL ; IVL *XrecvIVL ; DenseMtx *Xsupp ; IV *YownedIV ; IV *YsupIV ; IV *YmapIV ; IVL *YsendIVL ; IVL *YrecvIVL ; DenseMtx *Ysupp ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in MMM.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------- purpose -- setup the distributed matrix-matrix multiply information object created -- 98aug21, cca ------------------------------------------------------- */ MatMulInfo * MatMul_MPI_setup ( InpMtx *A, int symflag, int opflag, IV *XownersIV, IV *YownersIV, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm ) ; /* ------------------------------------------------------------ set the indices of A to be local with respect to its support created -- 98aug21, cca ------------------------------------------------------------ */ void MatMul_setLocalIndices ( MatMulInfo *info, InpMtx *A ) ; /* ------------------------------------------------------------- set the indices of A to be global with respect to its support created -- 98aug21, cca ------------------------------------------------------------- */ void MatMul_setGlobalIndices ( MatMulInfo *info, InpMtx *A ) ; /* --------------------------------------------------------- purpose -- compute the distributed matrix-matrix multiply Y := Y - alpha * A * X where A, Xloc and Yloc are distributed created -- 98aug21, cca --------------------------------------------------------- */ void MatMul_MPI_mmm ( MatMulInfo *info, DenseMtx *Yloc, double alpha[], InpMtx *A, DenseMtx *Xloc, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm ) ; /* -------------------------------------------------- free the MatMulInfo object and its data structures created -- 98aug21, cca -------------------------------------------------- */ void MatMul_cleanup ( MatMulInfo *info ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in DenseMtx_gather.c -------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------------- purpose -- to gather entries from a distributed X into Y . what rows of X to be sent to other processors are found in sendIVL. what rows of Y to be received from other processors are found in recvIVL. Y -- on return, contains the rows specified by recvIVL. row indices of Y will be in ascending order. X -- this processor's part of the distributed partitioned DenseMtx object. row indices of X are assumed to be in ascending order. sendIVL -- list jproc contains the global ids of rows in X that need to be sent to processor jproc. note, lists are assumed to be in ascending order and are local with respect to X. recvIVL -- list jproc contains the global ids of rows in jproc's part of X that will to be sent to this processor. note, lists are assumed to be in ascending order and are local with respect to Y. created -- 98jul31, cca -------------------------------------------------------------------- */ void DenseMtx_MPI_gatherRows ( DenseMtx *Y, DenseMtx *X, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in DenseMtx_scatterAdd.c ---------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------------- purpose -- to scatter/add entries from a distributed X into Y. what rows of X to be sent to other processors are found in sendIVL. what rows of Y to be received from other processors are found in recvIVL. Y -- on return, contains the rows specified by recvIVL. row indices of Y will be in ascending order. X -- this processor's part of the distributed partitioned DenseMtx object. row indices of X are assumed to be in ascending order. sendIVL -- list jproc contains the global ids of rows in X that need to be sent to processor jproc. note, lists are assumed to be in ascending order and are local with respect to X. recvIVL -- list jproc contains the global ids of rows in jproc's part of X that will to be sent to this processor. note, lists are assumed to be in ascending order and are local with respect to Y. created -- 98jul31, cca -------------------------------------------------------------------- */ void DenseMtx_MPI_scatterAddRows ( DenseMtx *Y, DenseMtx *X, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ---- methods found in makeSendRecvIVLs.c ------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------------- purpose -- to analyze and organize communication. it was written in support of a distributed matrix-vector multiply but can be used for other applications. each processor has a list of items it "supports" or needs found in the supportedIV object. the globalmapIV object contains the map from items to owning processors. we need to figure out what items this processor will send to and receive from each other processor. this information is found in the sendIVL and recvIVL objects. on return, list jproc of sendIVL contains the items owned by this processor and needed by jproc. on return, list jproc of recvIVL contains the items needed by this processor and owned by jproc. as a concrete example, consider a distributed Y = A * X. the matrix A, the right hand side X and the vector Y are distributed among processors. consider the case where the supportedIV object contains the rows of X that are needed by this processor to perform its part of the matrix-vector multiply. globalmapIV contains the map from rows of X to the owning processors. on return, list jproc of sendIVL contains the row indices of X owned by this processor that are needed by processor jproc. on return, list jproc of recvIVL contains the row indices of X needed by this processor that are owned by processor jproc. consider the case where the supportedIV object contains the rows of Y that will be updated by this processor when it performs it part of the matrix-vector multiply. globalmapIV contains the map from rows of Y to their owning processors. on return, list jproc of recvIVL contains the row indices of Y on this processor that need to be sent to their owner, processor jproc. on return, list jproc of sendIVL contains the row indices of Y owned by this processor that will be sent by processor jproc to this processor. created -- 98aug01, cca ----------------------------------------------------------------- */ void makeSendRecvIVLs ( IV *supportedIV, IV *globalmapIV, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ --------------- symflag -- symmetry flag SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC opflag -- operations flag 0 (MMM_WITH_A) -- multiply with A 1 (MMM_WITH_AT) -- multiply with A^T 2 (MMM_WITH_AH) -- multiply with A^H XownedIV -- list of rows of X owned by this procesMPI/makefile010064400020550007177000000002300663622364000142200ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make spoolesMPI.a clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean MPI/src/makefile010064400020550007177000000022160663602604100150110ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- # # set suffix rule *.c --> *.a # .c.a : $(PURIFY) $(CC) -c $(CFLAGS) $(MPI_INCLUDE_DIR) $*.c -o $*.o $(AR) $(ARFLAGS) $(OBJ).a $*.o rm $*.o # #----------------------------------------------------------------------- OBJ = spoolesMPI $(OBJ).a : \ $(OBJ).a(aggListMPI.o) \ $(OBJ).a(colmapMPI.o) \ $(OBJ).a(DenseMtx_gather.o) \ $(OBJ).a(DenseMtx_scatterAdd.o) \ $(OBJ).a(ETree_Bcast.o) \ $(OBJ).a(factorMPI.o) \ $(OBJ).a(fullAdjMPI.o) \ $(OBJ).a(Graph_Bcast.o) \ $(OBJ).a(IVallgather.o) \ $(OBJ).a(IVLallgather.o) \ $(OBJ).a(IVL_alltoall.o) \ $(OBJ).a(IVL_Bcast.o) \ $(OBJ).a(makeSendRecvIVLs.o) \ $(OBJ).a(MMM.o) \ $(OBJ).a(postProcess.o) \ $(OBJ).a(rowmapMPI.o) \ $(OBJ).a(solveMPI.o) \ $(OBJ).a(splitDenseMtx.o) \ $(OBJ).a(splitFrontMtx.o) \ $(OBJ).a(splitInpMtx.o) \ $(OBJ).a(splitPencil.o) \ $(OBJ).a(symbfacMPI.o) \ $(OBJ).a(utilities.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o MPI/src/makeGlobalLib010064400020550007177000000015560662564202100157270ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = MPI SRC = aggListMPI.c \ colmapMPI.c \ DenseMtx_gather.c \ DenseMtx_scatterAdd.c \ ETree_Bcast.c \ factorMPI.c \ fullAdjMPI.c \ Graph_Bcast.c \ IVallgather.c \ IVLallgather.c \ IVL_alltoall.c \ IVL_Bcast.c \ makeSendRecvIVLs.c \ MMM.c \ postProcess.c \ rowmapMPI.c \ solveMPI.c \ splitDenseMtx.c \ splitFrontMtx.c \ splitInpMtx.c \ splitPencil.c \ symbfacMPI.c \ utilities.c OBJ_FILES = ${SRC:.c=.o} OBJ_FILES = MMM.o makeSendRecvIVLs.o .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $(MPI_INCLUDE_DIR) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a MPI/src/DenseMtx_gather.c010064400020550007177000000214330661222232600165360ustar00clevecompmath00000400000006/* DenseMtx_gather.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ typedef struct _Msg Msg ; struct _Msg { int id ; int size ; double *base ; MPI_Request req ; Msg *next ; } ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- to gather entries from a distributed X into Y . what rows of X to be sent to other processors are found in sendIVL. what rows of Y to be received from other processors are found in recvIVL. Y -- on return, contains the rows specified by recvIVL. row indices of Y will be in ascending order. X -- this processor's part of the distributed partitioned DenseMtx object. row indices of X are assumed to be in ascending order. sendIVL -- list jproc contains the global ids of rows in X that need to be sent to processor jproc. note, lists are assumed to be in ascending order and are local with respect to X. recvIVL -- list jproc contains the global ids of rows in jproc's part of X that will to be sent to this processor. note, lists are assumed to be in ascending order and are local with respect to Y. created -- 98jul31, cca -------------------------------------------------------------------- */ void DenseMtx_MPI_gatherRows ( DenseMtx *Y, DenseMtx *X, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { double *recvvec, *sendvec ; int flag, iirow, irow, jproc, jrow, lasttag, myid, ncolX, ncolY, nproc, nrecv, nrowX, nrowY, nsend, nword, tag, tagbound ; int *colindX, *colindY, *recvrowids, *rowindX, *rowindY, *sendrowids ; Msg *msg, *nextmsg, *recvhead, *sendhead ; MPI_Status status ; /* --------------- check the input --------------- */ if ( Y == NULL || X == NULL || sendIVL == NULL || recvIVL == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_gatherRows()" "\n bad input\n") ; fprintf(stderr, "\n Y %p, X %p, sendIVL %p, recvIVL %p", Y, X, sendIVL, recvIVL) ; exit(-1) ; } MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; lasttag = firsttag + nproc*nproc ; if ( lasttag > (tagbound = maxTagMPI(comm)) ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_gatherRows()" "\n lasttag = %d, tag_bound = %d", lasttag, tagbound) ; exit(-1) ; } if ( DENSEMTX_IS_REAL(X) ) { nword = 1 ; } else if ( DENSEMTX_IS_COMPLEX(X) ) { nword = 2 ; } else { fprintf(stderr, "\n fatal error in DenseMtx_MPI_gatherRows()" "\n X->type = %d\n", X->type) ; exit(-1) ; } DenseMtx_columnIndices(Y, &ncolY, &colindY) ; DenseMtx_rowIndices(Y, &nrowY, &rowindY) ; DenseMtx_columnIndices(X, &ncolX, &colindX) ; DenseMtx_rowIndices(X, &nrowX, &rowindX) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n sendIVL ") ; IVL_writeForHumanEye(sendIVL, msgFile) ; fprintf(msgFile, "\n\n recvIVL ") ; IVL_writeForHumanEye(recvIVL, msgFile) ; fflush(msgFile) ; } /* ---------------------- load the internal rows ---------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n loading internal rows") ; fflush(msgFile) ; } IVL_listAndSize(sendIVL, myid, &nsend, &sendrowids) ; IVL_listAndSize(recvIVL, myid, &nrecv, &recvrowids) ; for ( iirow = 0 ; iirow < nsend ; iirow++ ) { irow = sendrowids[iirow] ; jrow = recvrowids[iirow] ; if ( msglvl > 2 ) { fprintf(msgFile, "\n irow %d, jrow %d", irow, jrow) ; fflush(msgFile) ; } /* DenseMtx_copyRow(Y, jrow, X, irow) ; */ DenseMtx_copyRowAndIndex(Y, jrow, X, irow) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after loading internal rows") ; DenseMtx_writeForHumanEye(Y, msgFile) ; fflush(msgFile) ; } /* ------------------------------- post the sends and the receives ------------------------------- */ recvhead = sendhead = NULL ; for ( jproc = 0 ; jproc < nproc ; jproc++ ) { if ( jproc != myid ) { IVL_listAndSize(sendIVL, jproc, &nsend, &sendrowids) ; IVL_listAndSize(recvIVL, jproc, &nrecv, &recvrowids) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n jproc %d, nsend %d, nrecv %d", jproc, nsend, nrecv) ; fflush(msgFile) ; } if ( nsend > 0 ) { /* ------------------------- create the message object ------------------------- */ ALLOCATE(msg, struct _Msg, 1) ; msg->id = jproc ; msg->size = nword * nsend * ncolY ; msg->base = sendvec = DVinit(msg->size, 0.0) ; msg->next = sendhead, sendhead = msg ; tag = firsttag + myid*nproc + jproc ; /* ----------------------------------- fill the buffer with matrix entries ----------------------------------- */ for ( iirow = 0 ; iirow < nsend ; iirow++ ) { irow = sendrowids[iirow] ; DenseMtx_copyRowIntoVector(X, irow, sendvec) ; sendvec += nword*ncolY ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n sendvec") ; DVfprintf(msgFile, msg->size, msg->base) ; fflush(msgFile) ; } /* ------------- post the send ------------- */ stats[0]++ ; stats[2] += msg->size * sizeof(double) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n posting Isend to %d, size %d, tag %d", jproc, msg->size, tag) ; fflush(msgFile) ; } MPI_Isend(msg->base, msg->size, MPI_DOUBLE, jproc, tag, comm, &msg->req) ; } if ( nrecv > 0 ) { /* ------------------------- create the message object ------------------------- */ ALLOCATE(msg, struct _Msg, 1) ; msg->id = jproc ; msg->size = nword * nrecv * ncolY ; msg->base = (void *) DVinit(msg->size, 0.0) ; msg->next = recvhead, recvhead = msg ; tag = firsttag + jproc*nproc + myid ; /* ---------------- post the receive ---------------- */ stats[1]++ ; stats[3] += msg->size * sizeof(double) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n posting Irecv from %d, size %d, tag %d", jproc, msg->size, tag) ; fflush(msgFile) ; } MPI_Irecv(msg->base, msg->size, MPI_DOUBLE, jproc, tag, comm, &msg->req) ; } } } /* ------------------------------------------- loop while there are messages to receive or sent messages that have not been received ------------------------------------------- */ while ( sendhead != NULL || recvhead != NULL ) { for ( msg = sendhead, sendhead = NULL ; msg != NULL ; msg = nextmsg ) { nextmsg = msg->next ; if ( msglvl > 2 ) { fprintf(msgFile, "\n msg %p to %d", msg, msg->id) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( flag == 1 ) { if ( msglvl > 2 ) { fprintf(msgFile, ", received") ; fflush(msgFile) ; } DVfree((double *) msg->base) ; FREE(msg) ; } else { msg->next = sendhead, sendhead = msg ; } } for ( msg = recvhead, recvhead = NULL ; msg != NULL ; msg = nextmsg ) { nextmsg = msg->next ; if ( msglvl > 2 ) { fprintf(msgFile, "\n msg %p from %d", msg, msg->id) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( flag == 1 ) { jproc = msg->id ; if ( msglvl > 2 ) { fprintf(msgFile, ", received") ; fflush(msgFile) ; } IVL_listAndSize(recvIVL, jproc, &nrecv, &recvrowids) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n recvrowids") ; IVfprintf(msgFile, nrecv, recvrowids) ; fflush(msgFile) ; } recvvec = msg->base ; if ( msglvl > 2 ) { fprintf(msgFile, "\n recvvec") ; DVfprintf(msgFile, nword*nrecv*ncolY, recvvec) ; fflush(msgFile) ; } for ( iirow = 0 ; iirow < nrecv ; iirow++ ) { irow = recvrowids[iirow] ; DenseMtx_copyVectorIntoRow(Y, irow, recvvec) ; recvvec += nword*ncolY ; } DVfree((double *) msg->base) ; FREE(msg) ; } else { msg->next = recvhead, recvhead = msg ; } } } return ; } /*--------------------------------------------------------------------*/ MPI/src/DenseMtx_scatterAdd.c010064400020550007177000000206420656432475400173610ustar00clevecompmath00000400000006/* DenseMtx_scatterAdd.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ typedef struct _Msg Msg ; struct _Msg { int id ; int size ; double *base ; MPI_Request req ; Msg *next ; } ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- to scatter/add entries from a distributed X into Y. what rows of X to be sent to other processors are found in sendIVL. what rows of Y to be received from other processors are found in recvIVL. Y -- on return, contains the rows specified by recvIVL. row indices of Y will be in ascending order. X -- this processor's part of the distributed partitioned DenseMtx object. row indices of X are assumed to be in ascending order. sendIVL -- list jproc contains the global ids of rows in X that need to be sent to processor jproc. note, lists are assumed to be in ascending order and are local with respect to X. recvIVL -- list jproc contains the global ids of rows in jproc's part of X that will to be sent to this processor. note, lists are assumed to be in ascending order and are local with respect to Y. created -- 98jul31, cca -------------------------------------------------------------------- */ void DenseMtx_MPI_scatterAddRows ( DenseMtx *Y, DenseMtx *X, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { double *recvvec, *sendvec ; int flag, iirow, irow, jproc, jrow, myid, ncolX, ncolY, nproc, nrecv, nrowX, nrowY, nsend, nword, tag ; int *colindX, *colindY, *recvrowids, *rowindX, *rowindY, *sendrowids ; Msg *msg, *nextmsg, *recvhead, *sendhead ; MPI_Status status ; /* --------------- check the input --------------- */ if ( Y == NULL || X == NULL || sendIVL == NULL || recvIVL == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_scatterAddRows()" "\n bad input\n") ; exit(-1) ; } MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; if ( DENSEMTX_IS_REAL(X) ) { nword = 1 ; } else if ( DENSEMTX_IS_COMPLEX(X) ) { nword = 2 ; } else { fprintf(stderr, "\n fatal error in DenseMtx_MPI_scatterAddRows()" "\n X->type = %d\n", X->type) ; exit(-1) ; } DenseMtx_columnIndices(Y, &ncolY, &colindY) ; DenseMtx_rowIndices(Y, &nrowY, &rowindY) ; DenseMtx_columnIndices(X, &ncolX, &colindX) ; DenseMtx_rowIndices(X, &nrowX, &rowindX) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n sendIVL ") ; IVL_writeForHumanEye(sendIVL, msgFile) ; fprintf(msgFile, "\n\n recvIVL ") ; IVL_writeForHumanEye(recvIVL, msgFile) ; fflush(msgFile) ; } /* ----------------------------- scatter/add the internal rows ----------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n loading internal rows") ; fflush(msgFile) ; } IVL_listAndSize(sendIVL, myid, &nsend, &sendrowids) ; IVL_listAndSize(recvIVL, myid, &nrecv, &recvrowids) ; for ( iirow = 0 ; iirow < nsend ; iirow++ ) { irow = sendrowids[iirow] ; jrow = recvrowids[iirow] ; if ( msglvl > 2 ) { fprintf(msgFile, "\n irow %d, jrow %d", irow, jrow) ; fflush(msgFile) ; } DenseMtx_addRow(Y, jrow, X, irow) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after adding internal rows") ; DenseMtx_writeForHumanEye(Y, msgFile) ; fflush(msgFile) ; } /* ------------------------------- post the sends and the receives ------------------------------- */ recvhead = sendhead = NULL ; for ( jproc = 0 ; jproc < nproc ; jproc++ ) { if ( jproc != myid ) { IVL_listAndSize(sendIVL, jproc, &nsend, &sendrowids) ; IVL_listAndSize(recvIVL, jproc, &nrecv, &recvrowids) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n jproc %d, nsend %d, nrecv %d", jproc, nsend, nrecv) ; fflush(msgFile) ; } if ( nsend > 0 ) { /* ------------------------- create the message object ------------------------- */ ALLOCATE(msg, struct _Msg, 1) ; msg->id = jproc ; msg->size = nword * nsend * ncolY ; msg->base = sendvec = DVinit(msg->size, 0.0) ; msg->next = sendhead, sendhead = msg ; tag = firsttag + myid*nproc + jproc ; /* ----------------------------------- fill the buffer with matrix entries ----------------------------------- */ for ( iirow = 0 ; iirow < nsend ; iirow++ ) { irow = sendrowids[iirow] ; DenseMtx_copyRowIntoVector(X, irow, sendvec) ; sendvec += nword*ncolY ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n sendvec") ; DVfprintf(msgFile, msg->size, msg->base) ; fflush(msgFile) ; } /* ------------- post the send ------------- */ stats[0]++ ; stats[2] += msg->size * sizeof(double) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n posting Isend to %d, size %d, tag %d", jproc, msg->size, tag) ; fflush(msgFile) ; } MPI_Isend(msg->base, msg->size, MPI_DOUBLE, jproc, tag, comm, &msg->req) ; } if ( nrecv > 0 ) { /* ------------------------- create the message object ------------------------- */ ALLOCATE(msg, struct _Msg, 1) ; msg->id = jproc ; msg->size = nword * nrecv * ncolY ; msg->base = (void *) DVinit(msg->size, 0.0) ; msg->next = recvhead, recvhead = msg ; tag = firsttag + jproc*nproc + myid ; /* ---------------- post the receive ---------------- */ stats[1]++ ; stats[3] += msg->size * sizeof(double) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n posting Irecv from %d, size %d, tag %d", jproc, msg->size, tag) ; fflush(msgFile) ; } MPI_Irecv(msg->base, msg->size, MPI_DOUBLE, jproc, tag, comm, &msg->req) ; } } } /* ------------------------------------------- loop while there are messages to receive or sent messages that have not been received ------------------------------------------- */ while ( sendhead != NULL || recvhead != NULL ) { for ( msg = sendhead, sendhead = NULL ; msg != NULL ; msg = nextmsg ) { nextmsg = msg->next ; if ( msglvl > 2 ) { fprintf(msgFile, "\n msg %p to %d", msg, msg->id) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( flag == 1 ) { if ( msglvl > 2 ) { fprintf(msgFile, ", received") ; fflush(msgFile) ; } DVfree((double *) msg->base) ; FREE(msg) ; } else { msg->next = sendhead, sendhead = msg ; } } for ( msg = recvhead, recvhead = NULL ; msg != NULL ; msg = nextmsg ) { nextmsg = msg->next ; if ( msglvl > 2 ) { fprintf(msgFile, "\n msg %p from %d", msg, msg->id) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( flag == 1 ) { jproc = msg->id ; if ( msglvl > 2 ) { fprintf(msgFile, ", received") ; fflush(msgFile) ; } IVL_listAndSize(recvIVL, jproc, &nrecv, &recvrowids) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n recvrowids") ; IVfprintf(msgFile, nrecv, recvrowids) ; fflush(msgFile) ; } recvvec = msg->base ; if ( msglvl > 2 ) { fprintf(msgFile, "\n recvvec") ; DVfprintf(msgFile, nword*nrecv*ncolY, recvvec) ; fflush(msgFile) ; } for ( iirow = 0 ; iirow < nrecv ; iirow++ ) { irow = recvrowids[iirow] ; DenseMtx_addVectorIntoRow(Y, irow, recvvec) ; recvvec += nword*ncolY ; } DVfree((double *) msg->base) ; FREE(msg) ; } else { msg->next = recvhead, recvhead = msg ; } } } return ; } /*--------------------------------------------------------------------*/ MPI/src/ETree_Bcast.c010064400020550007177000000057010657576551200156160ustar00clevecompmath00000400000006/* ETreeBcast.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to broadcast a front tree object from one process to all the others created -- 98may21, cca --------------------------------------------- */ ETree * ETree_MPI_Bcast ( ETree *etree, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) { int myid, nvtx, nfront, nint ; int *buffer ; /* ------------- find identity ------------- */ MPI_Comm_rank(comm, &myid) ; if ( myid == root ) { /* -------------------------------------------- this process owns the front tree, allocate a continuous buffer and load the data into it. -------------------------------------------- */ nfront = ETree_nfront(etree) ; nvtx = ETree_nvtx(etree) ; nint = 3 + 5*nfront + nvtx ; buffer = IVinit(nint, -1) ; buffer[0] = nfront ; buffer[1] = nvtx ; buffer[2] = ETree_root(etree) ; IVcopy(nfront, buffer + 3, ETree_par(etree)) ; IVcopy(nfront, buffer + 3 + nfront, ETree_fch(etree)) ; IVcopy(nfront, buffer + 3 + 2*nfront, ETree_sib(etree)) ; IVcopy(nfront, buffer + 3 + 3*nfront, ETree_nodwghts(etree)) ; IVcopy(nfront, buffer + 3 + 4*nfront, ETree_bndwghts(etree)) ; IVcopy(nvtx, buffer + 3 + 5*nfront, ETree_vtxToFront(etree)) ; /* ------------------------------------ send the size of the buffer and then the buffer to the other processors ------------------------------------ */ MPI_Bcast(&nint, 1, MPI_INT, root, comm) ; MPI_Bcast(buffer, nint, MPI_INT, root, comm) ; } else { /* -------------------------------------------- this process will receive the front tree. clear its data, receive the number of int's, then receive the buffer -------------------------------------------- */ if ( etree != NULL ) { ETree_free(etree) ; } MPI_Bcast(&nint, 1, MPI_INT, root, comm) ; buffer = IVinit(nint, -1) ; MPI_Bcast(buffer, nint, MPI_INT, root, comm) ; /* ---------------------------------------- create an ETree object and fill its data ---------------------------------------- */ etree = ETree_new() ; nfront = buffer[0] ; nvtx = buffer[1] ; ETree_init1(etree, nfront, nvtx) ; etree->tree->n = nfront ; etree->tree->root = buffer[2] ; IVcopy(nfront, ETree_par(etree), buffer + 3) ; IVcopy(nfront, ETree_fch(etree), buffer + 3 + nfront) ; IVcopy(nfront, ETree_sib(etree), buffer + 3 + 2*nfront) ; IVcopy(nfront, ETree_nodwghts(etree), buffer + 3 + 3*nfront) ; IVcopy(nfront, ETree_bndwghts(etree), buffer + 3 + 4*nfront) ; IVcopy(nvtx, ETree_vtxToFront(etree), buffer + 3 + 5*nfront) ; } /* --------------- free the buffer --------------- */ IVfree(buffer) ; return(etree) ; } /*--------------------------------------------------------------------*/ MPI/src/Graph_Bcast.c010064400020550007177000000060070657576400600156500ustar00clevecompmath00000400000006/* Graph_Bcast.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to broadcast a Graph IVL object from one processor to all the others created -- 98sep10, cca ----------------------------------------------- */ Graph * Graph_MPI_Bcast ( Graph *graph, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) { int myid ; int itemp[6] ; /* ------------- find identity ------------- */ MPI_Comm_rank(comm, &myid) ; if ( myid == root ) { /* ------------------------------- broadcast the six scalar values ------------------------------- */ itemp[0] = graph->type ; itemp[1] = graph->nvtx ; itemp[2] = graph->nvbnd ; itemp[3] = graph->nedges ; itemp[4] = graph->totvwght ; itemp[5] = graph->totewght ; MPI_Bcast((void *) itemp, 6, MPI_INT, root, comm) ; /* ------------------------ broadcast the IVL object ------------------------ */ IVL_MPI_Bcast(graph->adjIVL, root, msglvl, msgFile, comm) ; if ( graph->type == 1 || graph->type == 3 ) { /* ---------------------------- broadcast the vertex weights ---------------------------- */ MPI_Bcast((void *) graph->vwghts, graph->nvtx, MPI_INT, root, comm) ; } if ( graph->type == 2 || graph->type == 3 ) { /* ------------------------------------- broadcast the edge weights IVL object ------------------------------------- */ IVL_MPI_Bcast(graph->ewghtIVL, root, msglvl, msgFile, comm) ; } } else { int nvtx, type ; int *vwghts ; IVL *adjIVL, *ewghtIVL ; /* -------------- clear the data -------------- */ Graph_clearData(graph) ; /* ----------------------------- receive the six scalar values ----------------------------- */ MPI_Bcast((void *) itemp, 6, MPI_INT, root, comm) ; type = itemp[0] ; nvtx = itemp[1] ; /* ---------------------- receive the IVL object ---------------------- */ adjIVL = IVL_new() ; IVL_MPI_Bcast(adjIVL, root, msglvl, msgFile, comm) ; if ( type == 1 || type == 3 ) { /* -------------------------- receive the vertex weights -------------------------- */ vwghts = IVinit(nvtx, 0) ; MPI_Bcast((void *) vwghts, nvtx, MPI_INT, root, comm) ; } else { vwghts = NULL ; } if ( type == 2 || type == 3 ) { /* ----------------------------------- receive the edge weights IVL object ----------------------------------- */ ewghtIVL = IVL_new() ; IVL_MPI_Bcast(ewghtIVL, root, msglvl, msgFile, comm) ; } else { ewghtIVL = NULL ; } /* --------------------------- initialize the Graph object --------------------------- */ Graph_init2(graph, type, nvtx, itemp[2], itemp[3], itemp[4], itemp[5], adjIVL, vwghts, ewghtIVL) ; } return(graph) ; } /*--------------------------------------------------------------------*/ MPI/src/IVL_Bcast.c010064400020550007177000000070010660277115300152240ustar00clevecompmath00000400000006/* IVL_Bcast.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------ purpose -- to broadcast an IVL object from one processor to all the others created -- 98sep10, cca ------------------------------------------ */ IVL * IVL_MPI_Bcast ( IVL *ivl, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) { int ilist, myid, nlist ; /* ------------- find identity ------------- */ MPI_Comm_rank(comm, &myid) ; if ( myid == root ) { /* ----------------------------------------------- this process owns the front tree, broadcast the number of lists in the front tree ----------------------------------------------- */ nlist = ivl->nlist ; if ( msglvl > 2 ) { fprintf(msgFile, "\n broadcasting %d ", nlist) ; fflush(msgFile) ; } MPI_Bcast(&nlist, 1, MPI_INT, root, comm) ; /* ------------------------ broadcast the list sizes ------------------------ */ if ( msglvl > 2 ) { fprintf(msgFile, "\n broadcasting sizes[]") ; fflush(msgFile) ; } MPI_Bcast(ivl->sizes, nlist, MPI_INT, root, comm) ; /* ------------------------------------------- loop over the lists and broadcast each list ------------------------------------------- */ for ( ilist = 0 ; ilist < nlist ; ilist++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n broadcasting list %d", ilist) ; fflush(msgFile) ; } MPI_Bcast(ivl->p_vec[ilist], ivl->sizes[ilist], MPI_INT, root, comm) ; } } else { int *sizes ; /* -------------- clear the data -------------- */ if ( ivl == NULL ) { ivl = IVL_new() ; } else { IVL_clearData(ivl) ; } /* --------------------------------------------- receive the number of lists in the front tree --------------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n receiving nlist") ; fflush(msgFile) ; } MPI_Bcast(&nlist, 1, MPI_INT, root, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, " %d", nlist) ; fflush(msgFile) ; } /* --------------------- receive the list sizes --------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n receiving sizes") ; fflush(msgFile) ; } sizes = IVinit(nlist, 0) ; MPI_Bcast(sizes, nlist, MPI_INT, root, comm) ; if ( msglvl > 2 ) { IVfprintf(msgFile, nlist, sizes) ; fflush(msgFile) ; } /* ------------------------- initialize the IVL object ------------------------- */ IVL_init3(ivl, IVL_CHUNKED, nlist, sizes) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n initialized IVL object") ; IVL_writeForHumanEye(ivl, msgFile) ; fflush(msgFile) ; } IVfree(sizes) ; /* ----------------------------------------- loop over the lists and receive each list ----------------------------------------- */ for ( ilist = 0 ; ilist < nlist ; ilist++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n receiving list %d, size %d, loc %p", ilist, ivl->sizes[ilist], ivl->p_vec[ilist]) ; fflush(msgFile) ; } MPI_Bcast(ivl->p_vec[ilist], ivl->sizes[ilist], MPI_INT, root, comm) ; if ( msglvl > 2 ) { IVfprintf(msgFile, ivl->sizes[ilist], ivl->p_vec[ilist]) ; fflush(msgFile) ; } } } return(ivl) ; } /*--------------------------------------------------------------------*/ MPI/src/IVL_alltoall.c010064400020550007177000000121640656764233100160070ustar00clevecompmath00000400000006/* IVL_alltoall.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ this method is used during the setup for matrix-vector multiplies. each processor has computed the vertices it needs from other processors, these lists are contained in sendIVL. on return, recvIVL contains the lists of vertices this processor must send to all others. sendIVL -- on input, list[q] contains the vertices needed by this processor that are owned by q recvIVL -- on output, list[q] contains the vertices owned by this processor that are needed by q. note, if NULL on input, a new IVL object is allocated stats[] -- statistics vector stats[0] -- contains # of sends stats[1] -- contains # of receives stats[2] -- contains # of bytes sent stats[3] -- contains # of bytes received firsttag -- first tag for messages, tags in range [firsttag, firsttag+nproc-1] are used return value -- recvIVL created -- 98jul26, cca ------------------------------------------------------------------ */ IVL * IVL_MPI_alltoall ( IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { int count, destination, lasttag, left, myid, nproc, offset, q, recvcount, right, sendcount, source, tag, tagbound ; int *incounts, *outcounts, *recvvec, *sendvec ; MPI_Status status ; /* --------------- check the input --------------- */ if ( sendIVL == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(msgFile, "\n fatal error in IVL_MPI_alltoall()" "\n bad input\n") ; exit(-1) ; } /* --------------------------------------- get id of self and number of processors --------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; if ( sendIVL->nlist != nproc ) { fprintf(msgFile, "\n fatal error in IVL_MPI_alltoall()" "\n sendIVL: nproc = %d, nlist = %d\n", nproc, sendIVL->nlist) ; exit(-1) ; } lasttag = firsttag + nproc ; if ( lasttag > (tagbound = maxTagMPI(comm)) ) { fprintf(stderr, "\n fatal error in IVL_MPI_alltoall()" "\n lasttag = %d, tag_bound = %d", lasttag, tagbound) ; exit(-1) ; } if ( recvIVL == NULL ) { recvIVL = IVL_new() ; } else { IVL_clearData(recvIVL) ; } IVL_init1(recvIVL, IVL_CHUNKED, nproc) ; /* ------------------------------------------ outcounts[] is sendIVL->sizes[] incounts[] will be recvIVL->sizes[] fill incounts via a call to MPI_Alltoall() and then initialize the recvIVL lists. ------------------------------------------ */ outcounts = sendIVL->sizes ; incounts = IVinit(nproc, 0) ; MPI_Alltoall((void *) outcounts, 1, MPI_INT, (void *) incounts, 1, MPI_INT, comm) ; for ( q = 0 ; q < nproc ; q++ ) { IVL_setList(recvIVL, q, incounts[q], NULL) ; } IVfree(incounts) ; /* --------------------------------------------------- load list myid of sendIVL into list myid of recvIVL --------------------------------------------------- */ IVL_listAndSize(sendIVL, myid, &sendcount, &sendvec) ; IVL_setList(recvIVL, myid, sendcount, sendvec) ; /* --------------------------------------------------------- now loop over the processes, send and receive information --------------------------------------------------------- */ for ( offset = 1, tag = firsttag ; offset < nproc ; offset++, tag++ ) { right = (myid + offset) % nproc ; if ( offset <= myid ) { left = myid - offset ; } else { left = nproc + myid - offset ; } IVL_listAndSize(sendIVL, right, &sendcount, &sendvec) ; IVL_listAndSize(recvIVL, left, &recvcount, &recvvec) ; if ( sendcount > 0 ) { destination = right ; stats[0]++ ; stats[2] += sendcount*sizeof(int) ; } else { destination = MPI_PROC_NULL ; } if ( recvcount > 0 ) { source = left ; stats[1]++ ; stats[3] += recvcount*sizeof(int) ; } else { source = MPI_PROC_NULL ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n offset %d, recvcount %d, source %d, sendcount %d, destination %d", offset, recvcount, source, sendcount, destination) ; fflush(msgFile) ; } /* ----------------- do a send/receive ----------------- */ MPI_Sendrecv((void *) sendvec, sendcount, MPI_INT, destination, tag, (void *) recvvec, recvcount, MPI_INT, source, tag, comm, &status) ; if ( source != MPI_PROC_NULL ) { MPI_Get_count(&status, MPI_INT, &count) ; if ( count != recvcount ) { fprintf(stderr, "\n fatal error in IVL_MPI_alltoall()" "\n proc %d : source %d, count %d, recvcount %d\n", myid, source, count, recvcount) ; exit(-1) ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n send/recv completed") ; fflush(msgFile) ; } } return(recvIVL) ; } /*--------------------------------------------------------------------*/ nproc = %d, nlist = %d\n", nproc, sendIVL->nlist) ; exit(-1) ; } lasttag = firsttag + nproc ; if ( lasttag > (tagbound = maxTagMPI(comm)) ) { fprintf(stderr, "\n fatal error in IVL_MPI_alltoall()" "\n lasttag = %d, tag_bound = %d", lasttag, tagbound) ; exit(-1) ; } if ( recvIVL == NULL ) { recvIVL = IVL_new() ; } else { IVL_clearData(recvIVL) ; } IVL_initMPI/src/IVLallgather.c010064400020550007177000000157750655671743000160230ustar00clevecompmath00000400000006/* IVLallgather.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- the IVL object ivl and IV object ownersIV are both found on each process. the ownersIV object is identical over all the processes, and owners[ii] tells which processes owns list ii of the ivl object. on return from this method, the ivl object is replicated over all the processes. each process sends the lists that it owns to all the other processes. created -- 98apr03, cca ------------------------------------------------------------- */ void IVL_MPI_allgather ( IVL *ivl, IV *ownersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { int count, destination, ii, ilist, incount, jlist, jproc, left, maxcount, myid, nlist, nmylists, notherlists, nowners, nproc, offset, outcount, right, size, source, tag ; int *counts, *inbuffer, *list, *outbuffer, *owners ; MPI_Status status ; /* --------------- check the input --------------- */ if ( ivl == NULL || ownersIV == NULL ) { fprintf(stderr, "\n fatal error in IVL_MPI_allgather()" "\n ivl = %p, ownersIV = %p\n", ivl, ownersIV) ; exit(-1) ; } /* ---------------------------------------------- get id of self, # of processes and # of fronts ---------------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; nlist = ivl->nlist ; IV_sizeAndEntries(ownersIV, &nowners, &owners) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n inside IVL_MPI_allgather()" "\n nproc = %d, myid = %d, nlist = %d, nowners = %d", nproc, myid, nlist, nowners) ; fflush(msgFile) ; } if ( nlist != nowners || owners == NULL ) { fprintf(stderr, "\n fatal error in IVL_MPI_allgather()" "\n nlist = %d, nowners = %d, owners = %p\n", nlist, nowners, owners) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ivl") ; IVL_writeForHumanEye(ivl, msgFile) ; fprintf(msgFile, "\n\n ownersIV") ; IV_writeForHumanEye(ownersIV, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------------- step 1 : determine the size of the message that this process will send to the others ----------------------------------------------- */ for ( ilist = 0, outcount = 1 ; ilist < nlist ; ilist++ ) { if ( owners[ilist] < 0 || owners[ilist] >= nproc ) { fprintf(stderr, "\n owners[%d] = %d", ilist, owners[ilist]) ; exit(-1) ; } if ( owners[ilist] == myid ) { outcount += 2 ; IVL_listAndSize(ivl, ilist, &size, &list) ; outcount += size ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n outcount = %d", outcount) ; fflush(msgFile) ; } /* ---------------------------------------------------- do an all-to-all gather/scatter counts[jproc] = # of int's in the message from jproc ---------------------------------------------------- */ counts = IVinit(nproc, 0) ; counts[myid] = outcount ; MPI_Allgather((void *) &counts[myid], 1, MPI_INT, (void *) counts, 1, MPI_INT, comm) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n counts") ; IVfprintf(msgFile, nproc, counts) ; fflush(msgFile) ; } /* ----------------------------- set up the in and out buffers ----------------------------- */ if ( outcount > 0 ) { outbuffer = IVinit(outcount, -1) ; for ( ilist = nmylists = 0, ii = 1 ; ilist < nlist ; ilist++ ) { if ( owners[ilist] == myid ) { nmylists++ ; IVL_listAndSize(ivl, ilist, &size, &list) ; outbuffer[ii++] = ilist ; outbuffer[ii++] = size ; if ( size > 0 ) { IVcopy(size, &outbuffer[ii], list) ; ii += size ; } } } outbuffer[0] = nmylists ; if ( ii != outcount ) { fprintf(stderr, "\n myid = %d, ii = %d, outcount = %d", myid, ii, outcount) ; fprintf(msgFile, "\n myid = %d, ii = %d, outcount = %d", myid, ii, outcount) ; exit(-1) ; } } else { outbuffer = NULL ; } maxcount = IVmax(nproc, counts, &jproc) ; if ( maxcount > 0 ) { inbuffer = IVinit(maxcount, -1) ; } else { inbuffer = NULL ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n outbuffer %p, maxcount %d, inbuffer %p", outbuffer, maxcount, inbuffer) ; fflush(msgFile) ; } /* ------------------------------------- step 2: loop over the other processes send and receive information ------------------------------------- */ for ( offset = 1, tag = firsttag ; offset < nproc ; offset++, tag++ ) { right = (myid + offset) % nproc ; if ( offset <= myid ) { left = myid - offset ; } else { left = nproc + myid - offset ; } if ( outcount > 0 ) { destination = right ; stats[0]++ ; stats[2] += outcount*sizeof(int) ; } else { destination = MPI_PROC_NULL ; } incount = counts[left] ; if ( incount > 0 ) { source = left ; stats[1]++ ; stats[3] += incount*sizeof(int) ; } else { source = MPI_PROC_NULL ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n offset %d, source %d, destination %d", offset, source, destination) ; fflush(msgFile) ; } /* ----------------- do a send/receive ----------------- */ MPI_Sendrecv(outbuffer, outcount, MPI_INT, destination, tag, inbuffer, incount, MPI_INT, source, tag, comm, &status) ; if ( source != MPI_PROC_NULL ) { MPI_Get_count(&status, MPI_INT, &count) ; if ( count != incount ) { fprintf(stderr, "\n 1. fatal error in IVL_MPI_allgather()" "\n proc %d : source = %d, count = %d, incount = %d\n", myid, source, count, incount) ; exit(-1) ; } } /* ---------------------------- set the values in the vector ---------------------------- */ notherlists = inbuffer[0] ; for ( ilist = 0, ii = 1 ; ilist < notherlists ; ilist++ ) { jlist = inbuffer[ii++] ; size = inbuffer[ii++] ; if ( size > 0 ) { IVL_setList(ivl, jlist, size, &inbuffer[ii]) ; ii += size ; } } if ( ii != incount ) { fprintf(msgFile, "\n ii = %d, incount = %d", ii, incount) ; fprintf(stderr, "\n ii = %d, incount = %d", ii, incount) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n after setting values") ; IVL_writeForHumanEye(ivl, msgFile) ; fflush(msgFile) ; } } /* ------------------------ free the working storage ------------------------ */ IVfree(counts) ; if ( outbuffer != NULL ) { IVfree(outbuffer) ; } if ( inbuffer != NULL ) { IVfree(inbuffer) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n leaving IVL_MPI_gatherall()") ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ MPI/src/IV_Bcast.c010064400020550007177000000032560660300422100151020ustar00clevecompmath00000400000006/* IV_Bcast.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to broadcast an IV object from one processor to all the others. created -- 98sep25, cca ------------------------------------------- */ IV * IV_MPI_Bcast ( IV *obj, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) { /* --------------- check the input --------------- */ if ( obj == NULL ) { fprintf(stderr, "\n fatal error in IV_MPI_Bcast()" "\n obj is NULL\n") ; exit(-1) ; } MPI_Comm_rank(comm, &myid) ; if ( myid == root ) { /* -------------------------------- broadcast the size of the vector -------------------------------- */ MPI_Bcast((void *) &obj->size, 1, MPI_INT, root, comm) ; if ( obj->size > 0 ) { /* --------------------- broadcast the entries --------------------- */ MPI_Bcast((void *) obj->vec, obj->size, MPI_INT, root, comm) ; } } else { int size ; /* -------------- clear the data -------------- */ if ( obj == NULL ) { obj = IV_new() ; } else { IV_clearData(obj) ; } /* ------------------------------ receive the size of the vector ------------------------------ */ MPI_Bcast((void *) &size, 1, MPI_INT, root, comm) ; IV_setSize(obj, size) ; if ( size > 0 ) { /* ------------------- receive the entries ------------------- */ MPI_Bcast((void *) obj->vec, obj->size, MPI_INT, root, comm) ; } } return(obj) ; } /*--------------------------------------------------------------------*/ MPI/src/IVallgather.c010064400020550007177000000147310655671743000156760ustar00clevecompmath00000400000006/* IVallgather.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- the IV objects objIV and ownersIV are found on each process. the ownersIV object is identical over all the processes, and owners[ii] tells which processes owns location ii of the obj[] vector. on return from this entry, the obj[] vector is replicated over all the processes. each process sends the (ii,obj[ii]) pairs that it owns to all the other processes. created -- 98apr02, cca ----------------------------------------------------------------- */ void IV_MPI_allgather ( IV *objIV, IV *ownersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { int count, destination, ii, incount, iproc, jj, lasttag, left, maxcount, myid, nowners, nproc, nvec, offset, outcount, right, source, tag, tagbound, value ; int *counts, *inbuffer, *outbuffer, *owners, *vec ; MPI_Status status ; /* --------------- check the input --------------- */ if ( objIV == NULL || ownersIV == NULL ) { fprintf(stderr, "\n fatal error in IV_MPI_allgather()" "\n objIV = %p, ownersIV = %p\n", objIV, ownersIV) ; exit(-1) ; } /* ---------------------------------------------- get id of self, # of processes and # of fronts ---------------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; IV_sizeAndEntries(objIV, &nvec, &vec) ; IV_sizeAndEntries(ownersIV, &nowners, &owners) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n inside IV_MPI_allgather" "\n nproc = %d, myid = %d, nvec = %d, nowners = %d", nproc, myid, nvec, nowners) ; fflush(msgFile) ; } if ( nvec != nowners || vec == NULL || owners == NULL ) { fprintf(stderr, "\n fatal error in IV_MPI_allgather()" "\n nvec = %d, nowners = %d, vec = %p, owners = %p\n", nvec, nowners, vec, owners) ; exit(-1) ; } /* ------------------- check the tag range ------------------- */ lasttag = firsttag + nproc ; tagbound = maxTagMPI(comm) ; if ( firsttag < 0 || lasttag > tagbound ) { fprintf(stderr, "\n fatal error in IV_MPI_allgather()" "\n firsttag = %d, lasttag = %d, tagbound = %d\n", firsttag, lasttag, tagbound) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n objIV") ; IV_writeForHumanEye(objIV, msgFile) ; fprintf(msgFile, "\n\n ownersIV") ; IV_writeForHumanEye(ownersIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------------- step 1 : determine the number of entries owned by each vector ------------------------------------------------------------- */ counts = IVinit(nproc, 0) ; for ( ii = 0 ; ii < nvec ; ii++ ) { if ( owners[ii] < 0 || owners[ii] >= nproc ) { fprintf(stderr, "\n owners[%d] = %d", ii, owners[ii]) ; exit(-1) ; } counts[owners[ii]]++ ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n counts") ; IVfprintf(msgFile, nproc, counts) ; fflush(msgFile) ; } /* ----------------------------- set up the in and out buffers ----------------------------- */ if ( counts[myid] > 0 ) { outbuffer = IVinit(2*counts[myid], -1) ; for ( ii = jj = 0 ; ii < nvec ; ii++ ) { if ( owners[ii] == myid ) { outbuffer[jj++] = ii ; outbuffer[jj++] = vec[ii] ; } } if ( jj != 2*counts[myid] ) { fprintf(msgFile, "\n jj = %d, 2*counts[%d] = %d", jj, myid, 2*counts[myid]) ; fprintf(stderr, "\n jj = %d, 2*counts[%d] = %d", jj, myid, 2*counts[myid]) ; exit(-1) ; } } else { outbuffer = NULL ; } maxcount = IVmax(nproc, counts, &iproc) ; if ( maxcount > 0 ) { inbuffer = IVinit(2*maxcount, -1) ; } else { inbuffer = NULL ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n outbuffer %p, maxcount %d, inbuffer %p", outbuffer, maxcount, inbuffer) ; fflush(msgFile) ; } /* ------------------------------------- step 2: loop over the other processes send and receive information ------------------------------------- */ outcount = 2*counts[myid] ; for ( offset = 1, tag = firsttag ; offset < nproc ; offset++, tag++ ) { right = (myid + offset) % nproc ; if ( offset <= myid ) { left = myid - offset ; } else { left = nproc + myid - offset ; } if ( outcount > 0 ) { destination = right ; stats[0]++ ; stats[2] += outcount*sizeof(int) ; } else { destination = MPI_PROC_NULL ; } incount = 2*counts[left] ; if ( incount > 0 ) { source = left ; stats[1]++ ; stats[3] += incount*sizeof(int) ; } else { source = MPI_PROC_NULL ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n offset %d, source %d, destination %d", offset, source, destination) ; fflush(msgFile) ; } /* ----------------- do a send/receive ----------------- */ MPI_Sendrecv(outbuffer, outcount, MPI_INT, destination, tag, inbuffer, incount, MPI_INT, source, tag, comm, &status) ; if ( source != MPI_PROC_NULL ) { MPI_Get_count(&status, MPI_INT, &count) ; if ( count != incount ) { fprintf(stderr, "\n 1. fatal error in IV_MPI_allgather()" "\n proc %d : source = %d, count = %d, incount = %d\n", myid, source, count, incount) ; exit(-1) ; } } /* ---------------------------- set the values in the vector ---------------------------- */ for ( jj = 0 ; jj < incount ; jj += 2 ) { ii = inbuffer[jj] ; value = inbuffer[jj+1] ; vec[ii] = value ; } if ( jj != incount ) { fprintf(msgFile, "\n jj = %d, incount = %d", jj, incount) ; fprintf(stderr, "\n jj = %d, incount = %d", jj, incount) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n after setting values") ; IVfprintf(msgFile, nvec, vec) ; fflush(msgFile) ; } } /* ------------------------ free the working storage ------------------------ */ IVfree(counts) ; if ( outbuffer != NULL ) { IVfree(outbuffer) ; } if ( inbuffer != NULL ) { IVfree(inbuffer) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n leaving IV_MPI_gatherall()") ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ MPI/src/MMM.c010064400020550007177000000356260662564176500141340ustar00clevecompmath00000400000006/* MMM.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- setup the distributed matrix-matrix multiply information object created -- 98aug21, cca ------------------------------------------------------- */ MatMulInfo * MatMul_MPI_setup ( InpMtx *A, int symflag, int opflag, IV *XownersIV, IV *YownersIV, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm ) { MatMulInfo *info ; int iproc, myid, nproc, size ; int *list, *map, *Xmap, *Ymap ; IV *mapIV, *XmapIV, *XownedIV, *XsupIV, *YmapIV, *YownedIV, *YsupIV ; IVL *XrecvIVL, *XsendIVL, *YrecvIVL, *YsendIVL ; /* --------------- check the input --------------- */ if ( A == NULL || XownersIV == NULL || YownersIV == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in MatMul_MPI_setup()" "\n bad input\n") ; exit(-1) ; } switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in MatMul_MPI_setup()" "\n bad symflag = %d\n", symflag) ; exit(-1) ; break ; } switch ( opflag ) { case MMM_WITH_A : case MMM_WITH_AT : case MMM_WITH_AH : break ; default : fprintf(stderr, "\n fatal error in MatMul_MPI_setup()" "\n bad opflag = %d", opflag) ; exit(-1) ; break ; } MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; /* ------------------------------ allocate the MatMulInfo object ------------------------------ */ ALLOCATE(info, MatMulInfo, 1) ; info->symflag = symflag ; info->opflag = opflag ; info->YsupIV = info->XsupIV = NULL ; info->YmapIV = info->XmapIV = NULL ; info->XsendIVL = info->XrecvIVL = NULL ; info->YsendIVL = info->YrecvIVL = NULL ; info->Xsupp = info->Ysupp = NULL ; /* ---------------------------------------------------------------- get the list of rows of X and Y that are owned by this processor ---------------------------------------------------------------- */ XownedIV = info->XownedIV = IV_targetEntries(XownersIV, myid) ; YownedIV = info->YownedIV = IV_targetEntries(YownersIV, myid) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n owned rows of X") ; IV_writeForHumanEye(XownedIV, msgFile) ; fprintf(msgFile, "\n\n owned rows of Y") ; IV_writeForHumanEye(YownedIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------------ find the support of the owned matrix ------------------------------------ */ switch ( symflag ) { case SPOOLES_SYMMETRIC : XsupIV = info->XsupIV = IV_new() ; YsupIV = info->YsupIV = XsupIV ; InpMtx_supportSym(A, YsupIV) ; break ; case SPOOLES_HERMITIAN : XsupIV = info->XsupIV = IV_new() ; YsupIV = info->YsupIV = XsupIV ; InpMtx_supportHerm(A, YsupIV) ; break ; case SPOOLES_NONSYMMETRIC : XsupIV = info->XsupIV = IV_new() ; YsupIV = info->YsupIV = IV_new() ; switch ( opflag ) { case MMM_WITH_A : InpMtx_supportNonsym(A, YsupIV, XsupIV) ; break ; case MMM_WITH_AT : InpMtx_supportNonsymT(A, YsupIV, XsupIV) ; break ; case MMM_WITH_AH : InpMtx_supportNonsymH(A, YsupIV, XsupIV) ; break ; } break ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n row support") ; IV_writeForHumanEye(YsupIV, msgFile) ; fprintf(msgFile, "\n\n column support") ; IV_writeForHumanEye(XsupIV, msgFile) ; fflush(msgFile) ; } /* --------------------------------------------- get the maps from global to local coordinates --------------------------------------------- */ if ( IV_size(XsupIV) > 0 ) { XmapIV = info->XmapIV = IV_inverseMap(XsupIV) ; } else { XmapIV = info->XmapIV = IV_new() ; } if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ) { YmapIV = info->YmapIV = XmapIV ; } else { if ( IV_size(YsupIV) > 0 ) { YmapIV = info->YmapIV = IV_inverseMap(YsupIV) ; } else { YmapIV = info->YmapIV = IV_new() ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n YsupIV") ; IV_writeForHumanEye(YsupIV, msgFile) ; fprintf(msgFile, "\n\n YmapIV") ; IV_writeForHumanEye(YmapIV, msgFile) ; fprintf(msgFile, "\n\n XsupIV") ; IV_writeForHumanEye(XsupIV, msgFile) ; fprintf(msgFile, "\n\n XmapIV") ; IV_writeForHumanEye(XmapIV, msgFile) ; fflush(msgFile) ; } /* -------------------------------------------------------------- create the IVL objects that specify the communication patterns -------------------------------------------------------------- */ XsendIVL = info->XsendIVL = IVL_new() ; XrecvIVL = info->XrecvIVL = IVL_new() ; makeSendRecvIVLs(XsupIV, XownersIV, XsendIVL, XrecvIVL, stats, msglvl, msgFile, tag, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n X row send IVL, global") ; IVL_writeForHumanEye(XsendIVL, msgFile) ; fprintf(msgFile, "\n\n X row receive IVL, global") ; IVL_writeForHumanEye(XrecvIVL, msgFile) ; fflush(msgFile) ; } YsendIVL = info->YsendIVL = IVL_new() ; YrecvIVL = info->YrecvIVL = IVL_new() ; makeSendRecvIVLs(YsupIV, YownersIV, YrecvIVL, YsendIVL, stats, msglvl, msgFile, tag, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Y row send IVL") ; IVL_writeForHumanEye(YsendIVL, msgFile) ; fprintf(msgFile, "\n\n Y row receive IVL") ; IVL_writeForHumanEye(YrecvIVL, msgFile) ; fflush(msgFile) ; } /* -------------------------------------- make XsendIVL local w.r.t. local X make XrecvIVL local w.r.t. supported X make YsendIVL local w.r.t. supported Y make YrecvIVL local w.r.t. local Y -------------------------------------- */ if ( IV_size(XownedIV) > 0 ) { Xmap = IV_entries(XmapIV) ; mapIV = IV_inverseMap(XownedIV) ; map = IV_entries(mapIV) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { IVL_listAndSize(XsendIVL, iproc, &size, &list) ; IVgather(size, list, map, list) ; IVL_listAndSize(XrecvIVL, iproc, &size, &list) ; IVgather(size, list, Xmap, list) ; } IV_free(mapIV) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n X row send IVL, local") ; IVL_writeForHumanEye(XsendIVL, msgFile) ; fprintf(msgFile, "\n\n X row receive IVL, local") ; IVL_writeForHumanEye(XrecvIVL, msgFile) ; fflush(msgFile) ; } if ( IV_size(YownedIV) > 0 ) { Ymap = IV_entries(YmapIV) ; mapIV = IV_inverseMap(YownedIV) ; map = IV_entries(mapIV) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { IVL_listAndSize(YsendIVL, iproc, &size, &list) ; IVgather(size, list, Ymap, list) ; IVL_listAndSize(YrecvIVL, iproc, &size, &list) ; IVgather(size, list, map, list) ; } IV_free(mapIV) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Y row send IVL, local") ; IVL_writeForHumanEye(YsendIVL, msgFile) ; fprintf(msgFile, "\n\n Y row receive IVL, local") ; IVL_writeForHumanEye(YrecvIVL, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- set up the Xsupp and Ysupp objects ---------------------------------- */ info->Xsupp = DenseMtx_new() ; info->Ysupp = DenseMtx_new() ; return(info) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ set the indices of A to be local with respect to its support created -- 98aug21, cca ------------------------------------------------------------ */ void MatMul_setLocalIndices ( MatMulInfo *info, InpMtx *A ) { if ( info == NULL || A == NULL ) { fprintf(stderr, "\n fatal error in MatMul_setLocalIndices()" "\n bad input\n") ; exit(-1) ; } if ( A->nent > 0 ) { /* ------------------------------------------- map the input matrix into local coordinates ------------------------------------------- */ switch ( info->symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : InpMtx_mapEntries(A, info->YmapIV, info->XmapIV) ; break ; case SPOOLES_NONSYMMETRIC : switch ( info->opflag ) { case MMM_WITH_A : InpMtx_mapEntries(A, info->YmapIV, info->XmapIV) ; break ; case MMM_WITH_AT : case MMM_WITH_AH : InpMtx_mapEntries(A, info->XmapIV, info->YmapIV) ; break ; } break ; default : fprintf(stderr, "\n fatal error in MatMul_setLocalIndices()" "\n bad symflag = %d\n", info->symflag) ; exit(-1) ; break ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- set the indices of A to be global with respect to its support created -- 98aug21, cca ------------------------------------------------------------- */ void MatMul_setGlobalIndices ( MatMulInfo *info, InpMtx *A ) { if ( info == NULL || A == NULL ) { fprintf(stderr, "\n fatal error in MatMul_setGlobalIndices()" "\n bad input\n") ; exit(-1) ; } if ( A->nent > 0 ) { /* -------------------------------------------- map the input matrix into global coordinates -------------------------------------------- */ switch ( info->symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : InpMtx_mapEntries(A, info->YsupIV, info->XsupIV) ; break ; case SPOOLES_NONSYMMETRIC : switch ( info->opflag ) { case MMM_WITH_A : InpMtx_mapEntries(A, info->YsupIV, info->XsupIV) ; break ; case MMM_WITH_AT : case MMM_WITH_AH : InpMtx_mapEntries(A, info->XsupIV, info->YsupIV) ; break ; } break ; default : fprintf(stderr, "\n fatal error in MatMul_setGlobalIndices()" "\n bad symflag = %d\n", info->symflag) ; exit(-1) ; break ; } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- compute the distributed matrix-matrix multiply Y := Y - alpha * A * X where A, Xloc and Yloc are distributed created -- 98aug21, cca --------------------------------------------------------- */ void MatMul_MPI_mmm ( MatMulInfo *info, DenseMtx *Yloc, double alpha[], InpMtx *A, DenseMtx *Xloc, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm ) { int ncolXloc, ncolYloc, nrowXloc, nrowYloc, nrowXsupp, nrowYsupp ; /* --------------- check the input --------------- */ if ( info == NULL || Yloc == NULL || alpha == NULL || A == NULL || Xloc == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in MatMul_MPI_mmm()" "\n bad input\n") ; exit(-1) ; } /* ------------------------------------------------- setup Xsupp and gather rows from distributed Xloc ------------------------------------------------- */ DenseMtx_dimensions(Xloc, &nrowXloc, &ncolXloc) ; nrowXsupp = IV_size(info->XsupIV) ; DenseMtx_init(info->Xsupp, Xloc->type, 0, 0, nrowXsupp, ncolXloc, 1, nrowXsupp) ; DenseMtx_zero(info->Xsupp) ; DenseMtx_MPI_gatherRows(info->Xsupp, Xloc, info->XsendIVL, info->XrecvIVL, stats, msglvl, msgFile, tag, comm) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n supported matrix Xsupp") ; DenseMtx_writeForHumanEye(info->Xsupp, msgFile) ; fflush(msgFile) ; } /* ----------- setup Ysupp ----------- */ DenseMtx_dimensions(Yloc, &nrowYloc, &ncolYloc) ; nrowYsupp = IV_size(info->YsupIV) ; DenseMtx_init(info->Ysupp, Yloc->type, 0, 0, nrowYsupp, ncolYloc, 1, nrowYsupp) ; DenseMtx_zero(info->Ysupp) ; /* ---------------------------------- compute the matrix-matrix multiply ---------------------------------- */ if ( A->nent > 0 ) { switch ( info->symflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_mmm(A, info->Ysupp, alpha, info->Xsupp) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_mmm(A, info->Ysupp, alpha, info->Xsupp) ; break ; case SPOOLES_NONSYMMETRIC : switch ( info->opflag ) { case MMM_WITH_A : InpMtx_nonsym_mmm(A, info->Ysupp, alpha, info->Xsupp) ; break ; case MMM_WITH_AT : InpMtx_nonsym_mmm_T(A, info->Ysupp, alpha, info->Xsupp) ; break ; case MMM_WITH_AH : InpMtx_nonsym_mmm_H(A, info->Ysupp, alpha, info->Xsupp) ; break ; } break ; } } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after mmm, local supported matrix Ysupp") ; DenseMtx_writeForHumanEye(info->Ysupp, msgFile) ; fflush(msgFile) ; } /* ------------------------------- assemble the owned rows of Yloc ------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n before scatter/add, local matrix Y") ; DenseMtx_writeForHumanEye(Yloc, msgFile) ; fflush(msgFile) ; } DenseMtx_MPI_scatterAddRows(Yloc, info->Ysupp, info->YsendIVL, info->YrecvIVL, stats, msglvl, msgFile, tag, comm) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after mmm, local matrix Y") ; DenseMtx_writeForHumanEye(Yloc, msgFile) ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- free the MatMulInfo object and its data structures created -- 98aug21, cca -------------------------------------------------- */ void MatMul_cleanup ( MatMulInfo *info ) { /* --------------- check the input --------------- */ if ( info == NULL ) { fprintf(stderr, "\n fatal error in MatMul_cleanup()" "\n bad input\n") ; exit(-1) ; } if ( info->XownedIV != NULL ) { IV_free(info->XownedIV) ; info->XownedIV = NULL ; } if ( info->XsupIV != NULL ) { IV_free(info->XsupIV) ; info->XsupIV = NULL ; } if ( info->XmapIV != NULL ) { IV_free(info->XmapIV) ; info->XmapIV = NULL ; } if ( info->XrecvIVL != NULL ) { IVL_free(info->XrecvIVL) ; info->XrecvIVL = NULL ; } if ( info->XsendIVL != NULL ) { IVL_free(info->XsendIVL) ; info->XsendIVL = NULL ; } if ( info->Xsupp != NULL ) { DenseMtx_free(info->Xsupp) ; info->Xsupp = NULL ; } if ( info->YownedIV != NULL ) { IV_free(info->YownedIV) ; info->YownedIV = NULL ; } if ( info->symflag == SPOOLES_NONSYMMETRIC ) { if ( info->YsupIV != NULL ) { IV_free(info->YsupIV) ; info->YsupIV = NULL ; } if ( info->YmapIV != NULL ) { IV_free(info->YmapIV) ; info->YmapIV = NULL ; } } if ( info->YrecvIVL != NULL ) { IVL_free(info->YrecvIVL) ; info->YrecvIVL = NULL ; } if ( info->YsendIVL != NULL ) { IVL_free(info->YsendIVL) ; info->YsendIVL = NULL ; } if ( info->Ysupp != NULL ) { DenseMtx_free(info->Ysupp) ; info->Ysupp = NULL ; } info->symflag = -1 ; info->opflag = -1 ; FREE(info) ; return ; } /*--------------------------------------------------------------------*/ fprintf(msgFile, "\n\n X row send IVL, global") ; IVL_writeForHumanEye(XsendIVL, msgFile) ; fpriMPI/src/aggListMPI.c010064400020550007177000000105330656036236700154300ustar00clevecompmath00000400000006/* aggList.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------- create, initialize and return a ChvList object to deal with aggregate chevrons created -- 98may21, cca modified -- 98jul31, cca now uses IVL_MPI_alltoall() ----------------------------------------------- */ ChvList * FrontMtx_MPI_aggregateList ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm ) { char *mark ; ChvList *aggList ; int count, ierr, ii, jproc, J, K, myid, nfront, nproc, size ; int *aggcounts, *frontOwners, *head, *indices, *link, *list, *updated, *vtxToFront ; IVL *recvIVL, *symbfacIVL, *sendIVL ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || frontOwnersIV == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_MPI_aggregateList(%p,%p,%p)" "\n bad input\n", frontmtx, frontOwnersIV, comm) ; exit(-1) ; } if ( tag < 0 || tag > maxTagMPI(comm) ) { fprintf(stderr, "\n fatal error in FrontMtx_MPI_aggregateList()" "\n tag = %d, tag_bound = %d", tag, maxTagMPI(comm)) ; exit(-1) ; } MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; symbfacIVL = frontmtx->symbfacIVL ; vtxToFront = ETree_vtxToFront(frontmtx->frontETree) ; IV_sizeAndEntries(frontOwnersIV, &nfront, &frontOwners) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n inside FrontMtx_aggListMPI, myid = %d, nproc = %d", myid, nproc) ; fflush(msgFile) ; } /* ---------------------------------------------------- mark all fronts that are supported by an owned front collect lists of updated fronts by owning processor ---------------------------------------------------- */ mark = CVinit(nfront, 'N') ; head = IVinit(nproc, -1) ; link = IVinit(nfront, -1) ; for ( J = 0 ; J < nfront ; J++ ) { jproc = frontOwners[J] ; if ( jproc == myid ) { IVL_listAndSize(symbfacIVL, J, &size, &indices) ; for ( ii = 0 ; ii < size ; ii++ ) { K = vtxToFront[indices[ii]] ; if ( mark[K] == 'N' ) { mark[K] = 'Y' ; jproc = frontOwners[K] ; link[K] = head[jproc] ; head[jproc] = K ; if ( msglvl > 1 ) { fprintf(msgFile, "\n front %d supported", K) ; fflush(msgFile) ; } } } } } /* ------------------------- set up the sendIVL object ------------------------- */ list = IVinit(nfront, -1) ; sendIVL = IVL_new() ; IVL_init1(sendIVL, IVL_CHUNKED, nproc) ; for ( jproc = 0 ; jproc < nproc ; jproc++ ) { for ( K = head[jproc], count = 0 ; K != -1 ; K = link[K] ) { list[count++] = K ; } IVL_setList(sendIVL, jproc, count, list) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n send IVL for aggregate lists") ; IVL_writeForHumanEye(sendIVL, msgFile) ; fflush(msgFile) ; } /* ---------------------- get the recvIVL object ---------------------- */ recvIVL = IVL_MPI_alltoall(sendIVL, NULL, stats, msglvl, msgFile, tag, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n receive IVL for aggregate lists") ; IVL_writeForHumanEye(recvIVL, msgFile) ; fflush(msgFile) ; } /* ------------------------- fill the aggcounts vector ------------------------- */ aggcounts = IVinit(nfront, 0) ; for ( jproc = 0 ; jproc < nproc ; jproc++ ) { if ( jproc != myid ) { IVL_listAndSize(recvIVL, jproc, &count, &updated) ; for ( ii = 0 ; ii < count ; ii++ ) { aggcounts[updated[ii]]++ ; } } } if ( msglvl > 1 ) { fprintf(msgFile, "\n aggcounts") ; IVfp80(msgFile, nfront, aggcounts, 80, &ierr) ; fflush(msgFile) ; } /* ----------------------------------------- create and initialize the ChvList object ----------------------------------------- */ aggList = ChvList_new() ; ChvList_init(aggList, nfront, aggcounts, 0, NULL) ; /* ------------------------ free the working storage ------------------------ */ IVfree(aggcounts) ; IVfree(head) ; IVfree(link) ; IVfree(list) ; CVfree(mark) ; IVL_free(sendIVL) ; IVL_free(recvIVL) ; return(aggList) ; } /*--------------------------------------------------------------------*/ MPI/src/colmapMPI.c010064400020550007177000000120530655671743100153110ustar00clevecompmath00000400000006/* colmapMPI.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- after pivoting for a nonsymmetric factorization, some delayed columns may belong to a process other than its original owner. this method returns an IV object that maps columns to owning processes. created -- 98may22, cca ------------------------------------------------------------- */ IV * FrontMtx_MPI_colmapIV ( FrontMtx *frontmtx, IV *frontOwnersIV, int msglvl, FILE *msgFile, MPI_Comm comm ) { int buffersize, ii, iproc, J, myid, nDJ, neqns, nfront, nproc, ncolJ, nToSend, v ; int *buffer, *counts, *frontOwners, *inbuffer, *outbuffer, *colindJ, *colmap, *vtxToFront ; IV *colmapIV ; /* ------------------------------------------- get the process id and number of processors ------------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; neqns = frontmtx->neqns ; vtxToFront = ETree_vtxToFront(frontmtx->frontETree) ; IV_sizeAndEntries(frontOwnersIV, &nfront, &frontOwners) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside FrontMtx_MPI_colmapIV()" "\n myid = %d, nproc = %d, nfront = %d, neqns = %d", myid, nproc, nfront, neqns) ; fflush(msgFile) ; } /* ---------------------------------------------------------- loop through the owned fronts and store each column in an owned front that was originally owned by another processor ---------------------------------------------------------- */ outbuffer = IVinit(neqns, -1) ; for ( J = nToSend = 0 ; J < nfront ; J++ ) { if ( frontOwners[J] == myid && (nDJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n front %d owned, nDJ = %d, ncolJ = %d", J, nDJ, ncolJ) ; fflush(msgFile) ; } for ( ii = 0 ; ii < nDJ ; ii++ ) { v = colindJ[ii] ; if ( frontOwners[vtxToFront[v]] != myid ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n column %d originally owned by %d", v, frontOwners[vtxToFront[v]]) ; fflush(msgFile) ; } outbuffer[nToSend++] = v ; } } } } IVqsortUp(nToSend, outbuffer) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n shifted vertices") ; IVfprintf(msgFile, nToSend, outbuffer) ; fflush(msgFile) ; } counts = IVinit(nproc, 0) ; /* -------------------------------------------- use an all-gather call to get the number of moved columns that are owned by each process -------------------------------------------- */ MPI_Allgather((void *) &nToSend, 1, MPI_INT, counts, 1, MPI_INT, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n after the all-gather operation, counts") ; IVfprintf(msgFile, nproc, counts) ; fflush(msgFile) ; } buffersize = IVmax(nproc, counts, &iproc) ; inbuffer = IVinit(buffersize, -1) ; /* ----------------------------------- initialize the column map IV object ----------------------------------- */ colmapIV = IV_new() ; IV_init(colmapIV, neqns, NULL) ; colmap = IV_entries(colmapIV) ; IVgather(neqns, colmap, frontOwners, vtxToFront) ; /* -------------------------------------------------------------- loop over the other processes, receive vector of moved columns -------------------------------------------------------------- */ for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( counts[iproc] > 0 ) { if ( iproc == myid ) { /* ------------------------------------- send buffer vector to other processes ------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n sending outbuffer to all processes") ; IVfprintf(msgFile, nToSend, outbuffer) ; fflush(msgFile) ; } MPI_Bcast(outbuffer, nToSend, MPI_INT, iproc, comm) ; buffer = outbuffer ; } else { /* ----------------------------------------- receive the vector from the other process ----------------------------------------- */ MPI_Bcast(inbuffer, counts[iproc], MPI_INT, iproc, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n received inbuffer from process %d", iproc) ; IVfprintf(msgFile, counts[iproc], inbuffer) ; fflush(msgFile) ; } buffer = inbuffer ; } /* ------------------------- set the column map values ------------------------- */ for ( ii = 0 ; ii < counts[iproc] ; ii++ ) { v = buffer[ii] ; colmap[v] = iproc ; } } } /* ------------------------ free the working storage ------------------------ */ IVfree(inbuffer) ; IVfree(outbuffer) ; IVfree(counts) ; return(colmapIV) ; } /*--------------------------------------------------------------------*/ MPI/src/factorMPI.c010064400020550007177000001307000662033400500152740ustar00clevecompmath00000400000006/* factorMPI.c */ #include "../spoolesMPI.h" #include "../../timings.h" #define MYDIAGNOSTIC 0 #define AGGREGATE_CHV 1 #define POSTPONED_NOTIFICATION 2 #define POSTPONED_CHV 3 #define AGGREGATE_CHV_TAG(K) (firsttag + (K)) #define POSTPONED_NOTIFICATION_TAG(K) (firsttag + nfront + (K)) #define POSTPONED_CHV_TAG(K) (firsttag + 2*nfront + 1 + (K)) #define ERROR_TAG (firsttag + 3*nfront + 2) /*--------------------------------------------------------------------*/ typedef struct _FactorMsg FactorMsg ; struct _FactorMsg { int info[3] ; void *base ; Chv *chv ; MPI_Request req ; FactorMsg *next ; } ; /*--------------------------------------------------------------------*/ static FactorMsg * FactorMsg_new ( void ) ; static void FactorMsg_setDefaultFields ( FactorMsg *msg ) ; static void FactorMsg_clearData ( FactorMsg *msg ) ; static void FactorMsg_free ( FactorMsg *msg ) ; static FactorMsg * wakeupFront ( FrontMtx *frontmtx, int J, int myid, int frontOwners[], int firsttag, ChvManager *chvmanager, ChvList *aggList, int stats[], double cpus[], MPI_Comm comm, int msglvl, FILE *msgFile ) ; static FactorMsg * checkMessages ( FrontMtx *frontmtx, int J, FactorMsg *firstmsg, ChvList *aggList, ChvList *postList, ChvManager *chvmanager, int firsttag, int stats[], MPI_Comm comm, int msglvl, FILE *msgFile ) ; static FactorMsg * sendMessages ( FrontMtx *frontmtx, int J, int myid, int nfront, int par[], int owners[], int firsttag, ChvManager*chvmanager, ChvList *aggList, ChvList *postList, FactorMsg *firstmsgsent, int stats[], MPI_Comm comm, int msglvl, FILE *msgFile ) ; static FactorMsg * checkSentMessages ( FactorMsg *firstmsgsent, ChvManager *chvmanager, int msglvl, FILE *msgFile ) ; static FactorMsg * sendErrorMessages ( int nfront, int J, int nproc, int myid, int firsttag, FactorMsg *firstmsgsent, int stats[], MPI_Comm comm, int msglvl, FILE *msgFile ) ; static void cancelAndFreeMessages ( FactorMsg *head, ChvManager *chvmanager, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- this is the method that computes the parallel factorization of a sparse matrix A using MPI. input --- frontmtx -- front matrix object that holds the factors inpmtx -- matrix object for A tau -- tolerance used in pivoting droptol -- tolerance used in the approximate factorization chvmanager -- ChvManager object to handle working storage frontOwnersIV -- map from fronts to owning processes lookahead -- parameter that governs the ``lookahead'' behavior, use lookahead = 0 as a default cpus -- vector to store breakdown of cpu times cpus[ 0] -- initialize fronts cpus[ 1] -- load original entries cpus[ 2] -- update fronts cpus[ 3] -- insert aggregate data cpus[ 4] -- assemble aggregate data cpus[ 5] -- assemble postponed data cpus[ 6] -- factor fronts cpus[ 7] -- extract postponed data cpus[ 8] -- store factor entries cpus[ 9] -- post initial receives cpus[10] -- check for received messages cpus[11] -- post initial sends cpus[12] -- check for sent messages stats -- vector to store statistics stats[ 0] -- # of pivots stats[ 1] -- # of pivot tests stats[ 2] -- # of delayed rows and columns stats[ 3] -- # of entries in D stats[ 4] -- # of entries in L stats[ 5] -- # of entries in U stats[ 6] -- # of aggregate sends stats[ 7] -- # of bytes in the aggregate sends stats[ 8] -- # of aggregate received stats[ 9] -- # of bytes in the aggregate received stats[10] -- # of postponed data sends stats[11] -- # of bytes in the postponed data sends stats[12] -- # of postponed data received stats[13] -- # of bytes in the postponed data received stats[14] -- # of active Chv objects (working storage) stats[15] -- # of active bytes in working storage stats[16] -- # of requested bytes in working storage msglvl -- message level msgFile -- message file firsttag -- first tag to use during the factorization, reserved tags are tag, ..., tag + 4*nfront + 2 comm -- MPI communicator return value -- if process id is zero, a pointer to the first Chv object in a list that contains postponed rows and columns that could not be eliminated. created -- 98may21, cca ------------------------------------------------------------------- */ Chv * FrontMtx_MPI_factorInpMtx ( FrontMtx *frontmtx, InpMtx *inpmtx, double tau, double droptol, ChvManager *chvmanager, IV *frontOwnersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { Chv *rootchv ; double zero[2] = {0.0, 0.0} ; int lasttag, tagbound ; Pencil pencil ; lasttag = 3*frontmtx->nfront + 2 ; tagbound = maxTagMPI(comm) ; if ( firsttag < 0 || lasttag > tagbound ) { fprintf(stderr, "\n fatal error in FrontMtx_MPI_factorInpMtx()" "\n tag range is [%d,%d], tag_bound = %d", firsttag, lasttag, tagbound) ; exit(-1) ; } Pencil_setDefaultFields(&pencil) ; Pencil_init(&pencil, frontmtx->type, frontmtx->symmetryflag, inpmtx, zero, NULL) ; rootchv = FrontMtx_MPI_factorPencil(frontmtx, &pencil, tau, droptol, chvmanager, frontOwnersIV, lookahead, perror, cpus, stats, msglvl, msgFile, firsttag, comm) ; return(rootchv) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- this is the method that computes the parallel factorization of A + sigma*B using MPI. input --- frontmtx -- front matrix object that holds the factors pencil -- matrix pencil object, contains A + sigma*B tau -- tolerance used in pivoting droptol -- tolerance used in the approximate factorization chvmanager -- ChvManager object to handle working storage frontOwnersIV -- map from fronts to owning processes lookahead -- parameter that governs the ``lookahead'' behavior, use lookahead = 0 as a default cpus -- vector to store breakdown of cpu times cpus[ 0] -- initialize fronts cpus[ 1] -- load original entries cpus[ 2] -- update fronts cpus[ 3] -- insert aggregate data cpus[ 4] -- assemble aggregate data cpus[ 5] -- assemble postponed data cpus[ 6] -- factor fronts cpus[ 7] -- extract postponed data cpus[ 8] -- store factor entries cpus[ 9] -- post initial receives cpus[10] -- check for received messages cpus[11] -- post initial sends cpus[12] -- check for sent messages stats -- vector to store statistics stats[ 0] -- # of pivots stats[ 1] -- # of pivot tests stats[ 2] -- # of delayed rows and columns stats[ 3] -- # of entries in D stats[ 4] -- # of entries in L stats[ 5] -- # of entries in U stats[ 6] -- # of aggregate sends stats[ 7] -- # of bytes in the aggregate sends stats[ 8] -- # of aggregate received stats[ 9] -- # of bytes in the aggregate received stats[10] -- # of postponed data sends stats[11] -- # of bytes in the postponed data sends stats[12] -- # of postponed data received stats[13] -- # of bytes in the postponed data received stats[14] -- # of active Chv objects (working storage) stats[15] -- # of active bytes in working storage stats[16] -- # of requested bytes in working storage msglvl -- message level msgFile -- message file firsttag -- first tag to use during the factorization, reserved tags are tag, ..., tag + 4*nfront + 2 comm -- MPI communicator return value -- if process id is zero, a pointer to the first Chv object in a list that contains postponed rows and columns that could not be eliminated. created -- 98may21, cca ------------------------------------------------------------------- */ Chv * FrontMtx_MPI_factorPencil ( FrontMtx *frontmtx, Pencil *pencil, double tau, double droptol, ChvManager *chvmanager, IV *frontOwnersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { char *status, *recvsPosted ; Chv *rootchv ; Chv **fronts ; ChvList *aggList, *postList ; double t1, t2 ; DV workDV ; FactorMsg *firstmsgsent, *head, *msg ; FactorMsg **p_msg ; Ideq *dequeue ; int flag, iproc, J, K, lasttag, myid, nfront, nproc, tagbound ; int *nactiveChild, *owners, *par, *term_flags ; int commstats[4] ; IP **heads ; IV pivotsizesIV ; MPI_Status mpistatus ; /* -------------- check the data -------------- */ if ( frontmtx == NULL || pencil == NULL || tau < 1.0 || droptol < 0.0 || chvmanager == NULL || frontOwnersIV == NULL || cpus == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_MPI_factorPencil()" "\n frontmtx = %p, pencil = %p, tau = %f, droptol = %f" "\n chvmanager = %p, frontOwnersIV = %p, firsttag = %d" "\n cpus = %p, stats = %p, msglvl = %d, msgFile = %p" "\n bad input\n", frontmtx, pencil, tau, droptol, chvmanager, frontOwnersIV, firsttag, cpus, stats, msglvl, msgFile) ; exit(-1) ; } nfront = frontmtx->nfront ; lasttag = 3*nfront + 2 ; tagbound = maxTagMPI(comm) ; if ( firsttag < 0 || lasttag > tagbound ) { fprintf(stderr, "\n fatal error in FrontMtx_MPI_factorPencil()" "\n tag range is [%d,%d], tag_bound = %d", firsttag, lasttag, tagbound) ; exit(-1) ; } MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; par = frontmtx->tree->par ; owners = IV_entries(frontOwnersIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n chvmanager = %p, firsttag = %d", chvmanager, firsttag) ; fflush(msgFile) ; } if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { /* -------------------------------------------- create a ChvList object to handle the postponed data. it does not require a lock. -------------------------------------------- */ postList = FrontMtx_postList(frontmtx, frontOwnersIV, NO_LOCK) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n postList = %p", postList) ; ChvList_writeForHumanEye(postList, msgFile) ; fflush(msgFile) ; } } else { postList = NULL ; } /* ------------------------------------------------------------ create a ChvList object to handle aggregate fronts. no lock is necessary. this object must be created cooperatively, since the aggregate counts are a function of the owners map and the symbolic factorization, and the latter is not global ------------------------------------------------------------ */ IVzero(4, commstats) ; aggList = FrontMtx_MPI_aggregateList(frontmtx, frontOwnersIV, commstats, msglvl, msgFile, firsttag, comm) ; firsttag += 2 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n aggList = %p", aggList) ; ChvList_writeForHumanEye(aggList, msgFile) ; fflush(msgFile) ; } /* --------------------------------------------------- initialize the heads[] vector for the owned updates --------------------------------------------------- */ heads = FrontMtx_factorSetup(frontmtx, frontOwnersIV, myid, msglvl, msgFile) ; /* ---------------------------------------------------------------- initialize the Ideq object that holds the initial fronts of the active paths, owned fronts with no children that are owned or updates by this thread. status[J] == 'W' --> J belongs to an active path for this thread ---------------------------------------------------------------- */ status = CVinit(nfront, 'F') ; dequeue = FrontMtx_setUpDequeue(frontmtx, owners, myid, status, heads, 'W', 'F', msglvl, msgFile) ; FrontMtx_loadActiveLeaves(frontmtx, status, 'W', dequeue) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n status") ; CVfprintf(msgFile, nfront, status) ; fprintf(msgFile, "\n fronts in initial dequeue") ; Ideq_writeForHumanEye(dequeue, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------------- initialize the nactiveChild[] vector, nactiveChild[J] measures the number of children that belong to active paths of this thread ----------------------------------------------- */ nactiveChild = FrontMtx_nactiveChild(frontmtx, status, myid) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n nactiveChild") ; IVfprintf(msgFile, nfront, nactiveChild) ; fflush(msgFile) ; } /* ------------------------------ initialize the working storage ------------------------------ */ ALLOCATE(fronts, Chv *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { fronts[J] = NULL ; } DV_setDefaultFields(&workDV) ; IV_setDefaultFields(&pivotsizesIV) ; ALLOCATE(p_msg, struct _FactorMsg *, nfront+1) ; for ( J = 0 ; J <= nfront ; J++ ) { p_msg[J] = NULL ; } recvsPosted = CVinit(nfront, 'N') ; /* --------------------------- loop while a path is active --------------------------- */ *perror = -1 ; firstmsgsent = NULL ; while ( (J = Ideq_removeFromHead(dequeue)) != -1 ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ### checking out front %d", J) ; fprintf(msgFile, "\n remaining fronts in dequeue") ; Ideq_writeForHumanEye(dequeue, msgFile) ; fflush(msgFile) ; } if ( recvsPosted[J] == 'N' && owners[J] == myid ) { MARKTIME(t1) ; /* ----------------------------------- post any receives for owned front J ----------------------------------- */ p_msg[J] = wakeupFront(frontmtx, J, myid, owners, firsttag, chvmanager, aggList, stats, cpus, comm, msglvl, msgFile) ; recvsPosted[J] = 'Y' ; MARKTIME(t2) ; cpus[10] += t2 - t1 ; } if ( p_msg[J] != NULL ) { /* --------------------------------------- check for received messages for front J --------------------------------------- */ MARKTIME(t1) ; p_msg[J] = checkMessages(frontmtx, J, p_msg[J], aggList, postList, chvmanager, firsttag, stats, comm, msglvl, msgFile) ; MARKTIME(t2) ; cpus[11] += t2 - t1 ; } /* ---------------------------------- check for numeric work for front J ---------------------------------- */ FrontMtx_factorVisit(frontmtx, pencil, J, myid, owners, fronts, lookahead, tau, droptol, status, heads, &pivotsizesIV, &workDV, par, aggList, postList, chvmanager, stats, cpus, msglvl, msgFile) ; if ( status[J] == 'E' ) { /* --------------------------------------- error detected while processing front J --------------------------------------- */ *perror = J ; firstmsgsent = sendErrorMessages(nfront, J, nproc, myid, firsttag, firstmsgsent, stats, comm, msglvl, msgFile) ; break ; } else if ( status[J] == 'F' ) { #if MYDIAGNOSTIC > 0 { double t1 ; MARKTIME(t1) ; fprintf(stdout, "\n proc %d, time %8.3f : front %d is finished", myid, t1, J) ; fflush(stdout) ; fprintf(msgFile, "\n proc %d, time %8.3f : front %d is finished", myid, t1, J) ; fflush(msgFile) ; } #endif if ( msglvl > 1 ) { fprintf(msgFile, "\n front %d is finished", J) ; fflush(msgFile) ; } if ( (K = par[J]) != -1 && --nactiveChild[K] == 0 ) { /* ------------------------ load parent into dequeue ------------------------ */ Ideq_insertAtHead(dequeue, K) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n 2. adding front %d to dequeue", K) ; fprintf(msgFile, "\n fronts in dequeue") ; Ideq_writeForHumanEye(dequeue, msgFile) ; fflush(msgFile) ; } } /* ------------------------------------ send any messages to other processes ------------------------------------ */ MARKTIME(t1) ; firstmsgsent = sendMessages(frontmtx, J, myid, nfront, par, owners, firsttag, chvmanager, aggList, postList, firstmsgsent, stats, comm, msglvl, msgFile) ; MARKTIME(t2) ; cpus[12] += t2 - t1 ; } else { /* --------------------------------------------- front is still active, place on tail of queue --------------------------------------------- */ Ideq_insertAtTail(dequeue, J) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n front %d is not finished", J) ; fprintf(msgFile, "\n fronts in dequeue") ; Ideq_writeForHumanEye(dequeue, msgFile) ; fflush(msgFile) ; } } if ( firstmsgsent != NULL ) { /* ------------------------------------------------------ check the list of sent messages to recycle Chv objects ------------------------------------------------------ */ MARKTIME(t1) ; firstmsgsent = checkSentMessages(firstmsgsent, chvmanager, msglvl, msgFile) ; MARKTIME(t2) ; cpus[13] += t2 - t1 ; } /* -------------------------------------- probe for an error termination message -------------------------------------- */ MPI_Iprobe(MPI_ANY_SOURCE, ERROR_TAG, comm, &flag, &mpistatus) ; if ( flag == 1 ) { /* --------------------------------------------------------- an error message has been received, break out of the loop --------------------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ERROR MESSAGE RECEIVED FROM %d", mpistatus.MPI_SOURCE) ; fflush(msgFile) ; } break ; } } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n done with main loop") ; fflush(msgFile) ; } /* -------------------------------------------- now do an allgather on the termination flags -------------------------------------------- */ term_flags = IVinit(nproc, -1) ; MPI_Allgather((void *) perror, 1, MPI_INT, (void *) term_flags, 1, MPI_INT, comm) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n allgather on error code complete") ; IVfprintf(msgFile, nproc, term_flags) ; fflush(msgFile) ; } if ( *perror < 0 ) { for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( term_flags[iproc] >= 0 ) { *perror = term_flags[iproc] ; break ; } } } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n error code = %d", *perror) ; fflush(msgFile) ; } rootchv = NULL ; if ( *perror >= 0 ) { /* ---------------------------------------- error termination has occured, link all messages together into one list cancel all pending messages ---------------------------------------- */ head = firstmsgsent ; for ( J = 0 ; J < nfront ; J++ ) { if ( (msg = p_msg[J]) != NULL ) { while ( msg->next != NULL ) { msg = msg->next ; } msg->next = head ; head = p_msg[J] ; } } cancelAndFreeMessages(head, chvmanager, msglvl, msgFile) ; } else { /* ------------------------------------------- normal termination, wait until all messages have been received and free their storage ------------------------------------------- */ while ( firstmsgsent != NULL ) { /* ------------------------------- check the list of sent messages ------------------------------- */ MARKTIME(t1) ; firstmsgsent = checkSentMessages(firstmsgsent, chvmanager, msglvl, msgFile) ; MARKTIME(t2) ; cpus[13] += t2 - t1 ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n all sent messages have been free'd") ; fflush(msgFile) ; } if ( postList != NULL ) { /* ----------------------------------------- set the root chevron of the factorization ----------------------------------------- */ rootchv = ChvList_getList(postList, nfront) ; } } /* -------------------- load some statistics -------------------- */ stats[3] = frontmtx->nentD ; stats[4] = frontmtx->nentL ; stats[5] = frontmtx->nentU ; stats[14] = chvmanager->nactive ; stats[15] = chvmanager->nbytesactive ; stats[16] = chvmanager->nbytesrequested ; /* ------------------------ free the working storage ------------------------ */ if ( postList != NULL ) { ChvList_free(postList) ; } ChvList_free(aggList) ; CVfree(status) ; IVfree(nactiveChild) ; IP_free(heads[nfront+1]) ; FREE(heads) ; FREE(fronts) ; Ideq_free(dequeue) ; DV_clearData(&workDV) ; IV_clearData(&pivotsizesIV) ; CVfree(recvsPosted) ; FREE(p_msg) ; IVfree(term_flags) ; return(rootchv) ; } /*--------------------------------------------------------------------*/ /* ------------------------- initialize a new instance created -- 97nov13, cca ------------------------- */ static FactorMsg * FactorMsg_new ( void ) { FactorMsg *msg ; ALLOCATE(msg, struct _FactorMsg, 1) ; FactorMsg_setDefaultFields(msg) ; return(msg) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 97nov13, cca ----------------------- */ static void FactorMsg_setDefaultFields ( FactorMsg *msg ) { msg->info[0] = 0 ; msg->info[1] = 0 ; msg->info[2] = 0 ; msg->base = NULL ; msg->chv = NULL ; msg->req = NULL ; msg->next = NULL ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data created -- 97nov13, cca ----------------------- */ static void FactorMsg_clearData ( FactorMsg *msg ) { FactorMsg_setDefaultFields(msg) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- free the object created -- 97nov13, cca ----------------------- */ static void FactorMsg_free ( FactorMsg *msg ) { FactorMsg_clearData(msg) ; FREE(msg) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- when a front is initially active, post its necessary receive messages created -- 97nov13, cca ----------------------------------- */ static FactorMsg * wakeupFront ( FrontMtx *frontmtx, int J, int myid, int frontOwners[], int firsttag, ChvManager *chvmanager, ChvList *aggList, int stats[], double cpus[], MPI_Comm comm, int msglvl, FILE *msgFile ) { Chv *chv ; FactorMsg *first, *msg ; int aggcount, ii, I, nbytes, nD, nfront, nL, nU, tag ; int *fch, *sib ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || J < 0 || J > (nfront = frontmtx->nfront) || chvmanager == NULL || aggList == NULL || (msglvl > 1 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in wakeupFront()" "\n bad input\n") ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n inside wakeupFront, J = %d", J) ; fflush(msgFile) ; } first = NULL ; aggcount = aggList->counts[J] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n aggcount for %d = %d", J, aggcount) ; fflush(msgFile) ; } if ( aggcount > 0 ) { /* ----------------------------------------------- post receives for the incoming aggregate fronts ---------------------------------------------- */ tag = AGGREGATE_CHV_TAG(J) ; for ( ii = 0 ; ii < aggcount ; ii++ ) { chv = FrontMtx_setupFront(frontmtx, NULL, J, myid, frontOwners, chvmanager, cpus, msglvl, msgFile) ; msg = FactorMsg_new() ; msg->info[0] = AGGREGATE_CHV ; msg->info[1] = J ; msg->info[2] = nbytes = Chv_nbytesInWorkspace(chv) ; msg->chv = chv ; msg->base = (void *) Chv_workspace(chv) ; msg->next = first ; first = msg ; if ( msglvl > 1 ) { fprintf(msgFile, "\n 1. posting Irecv, msg %p, type = %d, J = %d, tag = %d", msg, AGGREGATE_CHV, J, tag) ; fflush(msgFile) ; } MPI_Irecv(msg->base, nbytes, MPI_BYTE, MPI_ANY_SOURCE, tag, comm, &msg->req) ; FrontMtx_initialFrontDimensions(frontmtx, J, &nD, &nL, &nU, &nbytes) ; stats[8]++ ; stats[9] += nbytes ; if ( msglvl > 1 ) { fprintf(msgFile, ", return") ; fflush(msgFile) ; } } } if ( FRONTMTX_IS_PIVOTING(frontmtx) && frontOwners[J] == myid ) { /* --------------------------------------------- post receives for child notification messages --------------------------------------------- */ fch = frontmtx->tree->fch ; if ( fch[J] != -1 ) { sib = frontmtx->tree->sib ; for ( I = fch[J] ; I != -1 ; I = sib[I] ) { if ( frontOwners[I] != myid ) { msg = FactorMsg_new() ; msg->info[0] = POSTPONED_NOTIFICATION ; msg->info[1] = I ; msg->info[2] = 0 ; msg->next = first ; first = msg ; stats[12]++ ; stats[13] += 3*sizeof(int) ; tag = POSTPONED_NOTIFICATION_TAG(I) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n 2. posting Irecv, msg %p, type = %d, I = %d, tag = %d", msg, POSTPONED_NOTIFICATION, I, tag) ; fflush(msgFile) ; } MPI_Irecv((void *) msg->info, 3, MPI_INT, frontOwners[I], tag, comm, &msg->req) ; if ( msglvl > 1 ) { fprintf(msgFile, ", return") ; fflush(msgFile) ; } } } } } return(first) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- check for completion of messages for front J created -- 97nov13, cca -------------------------------------------- */ static FactorMsg * checkMessages ( FrontMtx *frontmtx, int J, FactorMsg *firstmsg, ChvList *aggList, ChvList *postList, ChvManager *chvmanager, int firsttag, int stats[], MPI_Comm comm, int msglvl, FILE *msgFile ) { FactorMsg *msg, *nextmsg ; int flag, nbytes, nfront, source, tag, type ; MPI_Status status ; /* ---------------------------------- loop over the messages in the list ---------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n inside checkMessages, J = %d, firstmsg = %p", J, firstmsg) ; fflush(msgFile) ; } nfront = frontmtx->nfront ; for ( msg = firstmsg, firstmsg = NULL ; msg != NULL ; msg = nextmsg ) { /* --------------------------- set next message to look at --------------------------- */ nextmsg = msg->next ; msg->next = NULL ; /* -------------------------------------- extract the type, front id and # bytes -------------------------------------- */ type = msg->info[0] ; nbytes = msg->info[2] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n checking msg %p : type %d, front %d, nbytes %d", msg, type, msg->info[1], nbytes) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( msglvl > 1 ) { fprintf(msgFile, ", flag = %d", flag) ; fflush(msgFile) ; } if ( flag != 1 ) { /* ----------------------------------------------- message has not yet been received, keep in list ----------------------------------------------- */ msg->next = firstmsg ; firstmsg = msg ; } else { /* ------------------------- message has been received ------------------------- */ source = status.MPI_SOURCE ; tag = status.MPI_TAG ; nbytes = msg->info[2] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n message received: source %d, tag %d, nbytes %d", source, tag, nbytes) ; fflush(msgFile) ; } switch ( type ) { case AGGREGATE_CHV : /* ----------------- aggregate chevron ----------------- */ Chv_initFromBuffer(msg->chv) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n received aggregate front %d", J) ; Chv_writeForHumanEye(msg->chv, msgFile) ; fflush(msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n adding chv to aggregate list" "\n before count is %d", aggList->counts[J]) ; fflush(msgFile) ; } ChvList_addObjectToList(aggList, msg->chv, J) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n count is now %d", aggList->counts[J]) ; fflush(msgFile) ; } FactorMsg_free(msg) ; break ; case POSTPONED_NOTIFICATION : if ( nbytes > 0 ) { /* -------------------------------------------------- post receive for message to contain postponed data -------------------------------------------------- */ msg->info[0] = POSTPONED_CHV ; msg->chv = ChvManager_newObjectOfSizeNbytes(chvmanager, nbytes) ; msg->base = (void *) Chv_workspace(msg->chv) ; msg->next = nextmsg ; nextmsg = msg ; tag += nfront + 1 ; stats[12]++ ; stats[13] += nbytes ; if ( msglvl > 1 ) { fprintf(msgFile, "\n 2. posting Irecv, msg %p, type = %d, I = %d, tag = %d", msg, POSTPONED_NOTIFICATION, msg->info[1], tag) ; fflush(msgFile) ; } MPI_Irecv(msg->base, nbytes, MPI_BYTE, source, tag, comm, &msg->req) ; if ( msglvl > 1 ) { fprintf(msgFile, ", return") ; fflush(msgFile) ; } } else { /* ------------------------ postponed data is empty ------------------------ */ if ( msglvl > 1 ) { fprintf(msgFile, "\n adding NULL object to postponed list" "\n before, count is %d", postList->counts[J]) ; fflush(msgFile) ; } ChvList_addObjectToList(postList, NULL, J) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n count is now %d", postList->counts[J]) ; fflush(msgFile) ; } FactorMsg_free(msg) ; } break ; case POSTPONED_CHV : /* ------------------------------ put postponed data on its list ------------------------------ */ Chv_initFromBuffer(msg->chv) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n received postponed data %d", J) ; Chv_writeForHumanEye(msg->chv, msgFile) ; fflush(msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n before, count is %d", postList->counts[J]) ; fflush(msgFile) ; } ChvList_addObjectToList(postList, msg->chv, J) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n count is now %d", postList->counts[J]) ; fflush(msgFile) ; } FactorMsg_free(msg) ; break ; default : break ; } } } return(firstmsg) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ after front J has completed, remove relevant data from the aggregage and/or postponed lists and send to the owning processor. created -- 97jul10, cca ------------------------------------------------------------------ */ static FactorMsg * sendMessages ( FrontMtx *frontmtx, int J, int myid, int nfront, int par[], int owners[], int firsttag, ChvManager *chvmanager, ChvList *aggList, ChvList *postList, FactorMsg *firstmsgsent, int stats[], MPI_Comm comm, int msglvl, FILE *msgFile ) { Chv *chv ; FactorMsg *msg ; int destination, K, nbytes, tag ; destination = owners[J] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n inside sendMessages, J = %d, firsttag = %d, destination %d", J, firsttag, destination) ; fflush(msgFile) ; } if ( destination != myid ) { /* ------------------------------------------ this process does not own the front, so an aggregate front will have been created. ------------------------------------------ */ chv = ChvList_getList(aggList, J) ; if ( chv != NULL ) { /* ------------------------------------ an aggregate front has been created, send to the owning processor ------------------------------------ */ nbytes = Chv_nbytesNeeded(chv->nD, chv->nL, chv->nU, frontmtx->type, chv->symflag) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n proc %d does not own front %d, nbytes = %d", myid, J, nbytes) ; fflush(msgFile) ; } msg = FactorMsg_new() ; msg->info[0] = AGGREGATE_CHV ; msg->info[1] = J ; msg->info[2] = nbytes ; msg->chv = chv ; msg->base = (void *) Chv_workspace(chv) ; tag = AGGREGATE_CHV_TAG(J) ; msg->next = firstmsgsent ; firstmsgsent = msg ; stats[6]++ ; stats[7] += nbytes ; if ( msglvl > 1 ) { fprintf(msgFile, "\n posting Isend, msg %p, type %d, J %d, nbytes %d, dest %d, tag %d", msg, msg->info[0], msg->info[1], msg->info[2], destination, tag) ; fprintf(msgFile, "\n wrk %p, nD %d, nL %d, nU %d, symflag %d", Chv_workspace(chv), chv->nD, chv->nL, chv->nU, chv->symflag) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n aggregate front %d, chv %p", J, chv) ; if ( chv != NULL ) { Chv_writeForHumanEye(msg->chv, msgFile) ; } fflush(msgFile) ; } MPI_Isend(msg->base, nbytes, MPI_BYTE, destination, tag, comm, &msg->req) ; } } else if ( postList != NULL ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n checking for postponed messages") ; fflush(msgFile) ; } /* ---------------------------------------------- pivoting enabled, look for a postponed chevron ---------------------------------------------- */ K = par[J] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n J = %d, K = %d", J, K) ; fflush(msgFile) ; } if ( K != -1 && (destination = owners[K]) != myid ) { if ( msglvl > 1 ) { fprintf(msgFile, ", destination = %d", destination) ; fflush(msgFile) ; } /* --------------------------------------- owner of the parent is not this process --------------------------------------- */ if ( ChvList_isListNonempty(postList, K) == 1 ) { /* ---------------------------------------- there is a postponed chevron on the list ---------------------------------------- */ chv = ChvList_getList(postList, K) ; nbytes = Chv_nbytesNeeded(chv->nD, chv->nL, chv->nU, frontmtx->type, chv->symflag) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n nD = %d, nL = %d, nU = %d, nbytes = %d", chv->nD, chv->nL, chv->nU, nbytes) ; fflush(msgFile) ; } } else { chv = NULL ; nbytes = 0 ; } /* ---------------------------------------- owner of the parent is not this process, send a notification message ---------------------------------------- */ msg = FactorMsg_new() ; msg->info[0] = POSTPONED_NOTIFICATION ; msg->info[1] = J ; msg->info[2] = nbytes ; tag = POSTPONED_NOTIFICATION_TAG(J) ; msg->next = firstmsgsent ; firstmsgsent = msg ; stats[10]++ ; stats[11] += 3*sizeof(int) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n posting Isend, msg %p, type %d, J %d, nbytes %d, dest %d, tag %d", msg, msg->info[0], msg->info[1], msg->info[2], destination, tag) ; fflush(msgFile) ; } MPI_Isend((void *) msg->info, 3, MPI_INT, destination, tag, comm, &msg->req) ; if ( nbytes > 0 ) { /* ---------------------------------------------------------- there is postponed data, send the data in a second message ---------------------------------------------------------- */ msg = FactorMsg_new() ; msg->info[0] = POSTPONED_CHV ; msg->info[1] = J ; msg->info[2] = nbytes ; msg->chv = chv ; msg->base = (void *) Chv_workspace(chv) ; tag = POSTPONED_CHV_TAG(J) ; msg->next = firstmsgsent ; firstmsgsent = msg ; stats[10]++ ; stats[11] += nbytes ; if ( msglvl > 1 ) { fprintf(msgFile, "\n posting Isend, msg %p, type %d, J %d, nbytes %d, dest %d, tag %d", msg, msg->info[0], msg->info[1], msg->info[2], destination, tag) ; fprintf(msgFile, "\n wrk %p, nD %d, nL %d, nU %d, symflag %d", Chv_workspace(chv), chv->nD, chv->nL, chv->nU, chv->symflag) ; fflush(msgFile) ; } MPI_Isend(msg->base, nbytes, MPI_BYTE, destination, tag, comm, &msg->req) ; } } } return(firstmsgsent) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- check the list of posted sends. if a send has completed, free the message structure and return the Chv object (if present) to its manager. created -- 97nov13, cca ------------------------------------------------------- */ static FactorMsg * checkSentMessages ( FactorMsg *firstmsgsent, ChvManager *chvmanager, int msglvl, FILE *msgFile ) { FactorMsg *msg, *nextmsg ; int flag, J, nbytes, type ; MPI_Status status ; for ( msg = firstmsgsent, firstmsgsent = NULL ; msg != NULL ; msg = nextmsg ) { nextmsg = msg->next ; type = msg->info[0] ; J = msg->info[1] ; nbytes = msg->info[2] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n checking sent msg %p : type %d, front %d, nbytes %d", msg, type, J, nbytes) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( msglvl > 1 ) { fprintf(msgFile, ", flag = %d", flag) ; fflush(msgFile) ; } if ( flag == 1 ) { if ( msg->chv != NULL ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n chv %p released", msg->chv) ; fflush(msgFile) ; } ChvManager_releaseObject(chvmanager, msg->chv) ; } FactorMsg_free(msg) ; } else { msg->next = firstmsgsent ; firstmsgsent = msg ; } } return(firstmsgsent) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- an error has been detected at front J, send a message to all other processors created -- 98aug29, cca ------------------------------------------------- */ static FactorMsg * sendErrorMessages ( int nfront, int J, int nproc, int myid, int firsttag, FactorMsg *firstmsgsent, int stats[], MPI_Comm comm, int msglvl, FILE *msgFile ) { int iproc, tag ; FactorMsg *msg ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( iproc != myid ) { msg = FactorMsg_new() ; msg->info[0] = tag = ERROR_TAG ; msg->info[1] = J ; msg->info[2] = 0 ; msg->chv = NULL ; msg->base = (void *) msg->info ; msg->next = firstmsgsent ; firstmsgsent = msg ; if ( msglvl > 1 ) { fprintf(msgFile, "\n posting error Isend, info = {%d, %d, %d}, dest %d, tag %d", msg->info[0], msg->info[1], msg->info[2], iproc, tag) ; fflush(msgFile) ; } MPI_Isend(msg->base, 2, MPI_INT, iproc, tag, comm, &msg->req) ; } } return(firstmsgsent) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- when an error has been detected, cancel all outstanding sends and receives and free their storage created -- 98aug29, cca ------------------------------------------- */ static void cancelAndFreeMessages ( FactorMsg *head, ChvManager *chvmanager, int msglvl, FILE *msgFile ) { FactorMsg *msg, *nextmsg ; int flag ; MPI_Status status ; /* ------------------------------------------------ cancel all the messages and test for termination ------------------------------------------------ */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n inside cancelAndFreeMessages()") ; fflush(msgFile) ; } for ( msg = head, head = NULL ; msg != NULL ; msg = nextmsg ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n msg %p, info = {%d,%d,%d}", msg, msg->info[0], msg->info[1], msg->info[2]) ; fflush(msgFile) ; } nextmsg = msg->next ; MPI_Cancel(&msg->req) ; if ( msglvl > 1 ) { fprintf(msgFile, ", canceled") ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( msglvl > 1 ) { fprintf(msgFile, ", tested, flag = %d", flag) ; fflush(msgFile) ; } if ( flag == 1 ) { /* ---------------------- message has terminated ---------------------- */ if ( msg->chv != NULL ) { if ( msglvl > 1 ) { fprintf(msgFile, ", releasing chv %p", msg->chv) ; fflush(msgFile) ; } ChvManager_releaseObject(chvmanager, msg->chv) ; } FactorMsg_free(msg) ; } else { msg->next = head ; head = msg ; } } /* -------------------------------------------- loop until all messages have been terminated -------------------------------------------- */ while ( head != NULL ) { for ( msg = head, head = NULL ; msg != NULL ; msg = nextmsg ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n msg %p, info = {%d,%d,%d}", msg, msg->info[0], msg->info[1], msg->info[2]) ; fflush(msgFile) ; } nextmsg = msg->next ; MPI_Test(&msg->req, &flag, &status) ; if ( msglvl > 1 ) { fprintf(msgFile, ", tested, flag = %d", flag) ; fflush(msgFile) ; } if ( flag == 1 ) { /* ---------------------- message has terminated ---------------------- */ if ( msg->chv != NULL ) { if ( msglvl > 1 ) { fprintf(msgFile, ", releasing chv %p", msg->chv) ; fflush(msgFile) ; } ChvManager_releaseObject(chvmanager, msg->chv) ; } FactorMsg_free(msg) ; } else { msg->next = head ; head = msg ; } } } if ( msglvl > 1 ) { fprintf(msgFile, "\n leaving cancelAndFreeMessages()") ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ AGGREGATE_CHV_TAG(J) ; msg->next = firstmsgsent ; MPI/src/fullAdjMPI.c010064400020550007177000000304470657404676000154260ustar00clevecompmath00000400000006/* fullAdjMPI.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- given a distributed InpMtx object, gather all the indices onto each process and create an IVL object that contains the full adjacency structure created -- 97dec17, cca ----------------------------------------------------------- */ IVL * InpMtx_MPI_fullAdjacency ( InpMtx *inpmtx, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm ) { InpMtx *adjmtx ; int ierr, iproc, maxnent, myid, nent, nproc, oldtype, totalnent ; int *buffer, *counts, *ivec1, *ivec2 ; IVL *adjIVL ; /* -------------------------------------- get id of self and number of processes -------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; /* ---------------------- convert to row storage ---------------------- */ oldtype = InpMtx_coordType(inpmtx) ; InpMtx_changeCoordType(inpmtx, INPMTX_BY_ROWS) ; nent = InpMtx_nent(inpmtx) ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n %d internal entries", nent) ; fflush(msgFile) ; } /* ------------------------------------------- find out how many entries each process owns ------------------------------------------- */ counts = IVinit(nproc, 0) ; counts[myid] = nent ; MPI_Allgather((void *) &counts[myid], 1, MPI_INT, (void *) counts, 1, MPI_INT, comm) ; totalnent = IVsum(nproc, counts) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %d total entries", totalnent) ; fprintf(msgFile, "\n\n counts vector") ; IVfp80(msgFile, nproc, counts, 80, &ierr) ; fflush(msgFile) ; } /* ------------------------------------------------- allocate a new InpMtx object to hold the indices ------------------------------------------------- */ adjmtx = InpMtx_new() ; InpMtx_init(adjmtx, INPMTX_BY_ROWS, INPMTX_INDICES_ONLY, totalnent, 0) ; /* ----------------------------------------- allocate a buffer to send/receive entries ----------------------------------------- */ maxnent = IVmax(nproc, counts, &iproc) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %d maximum entries", maxnent) ; fflush(msgFile) ; } buffer = IVinit(2*maxnent, -1) ; /* ---------------------------- now send and receive entries ---------------------------- */ for ( iproc = 0 ; iproc < nproc ; iproc++ ) { nent = counts[iproc] ; if ( iproc == myid ) { /* ----------------------- load the entries buffer ----------------------- */ IVcopy(nent, buffer, ivec1) ; IVcopy(nent, buffer + nent, ivec2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n owned entries in buffer") ; fflush(msgFile) ; } if ( msglvl > 2 ) { IVfprintf(msgFile, 2*nent, buffer) ; fflush(msgFile) ; } stats[0]++ ; stats[2] += 2*nent*sizeof(int) ; } else { stats[1]++ ; stats[3] += 2*nent*sizeof(int) ; } /* ---------------------------------------- broadcast the entries from process iproc ---------------------------------------- */ MPI_Bcast((void *) buffer, 2*nent, MPI_INT, iproc, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after bcast, buffer") ; IVfprintf(msgFile, 2*nent, buffer) ; fflush(msgFile) ; } /* ------------------------------------------ load the entries into the adjacency matrix ------------------------------------------ */ InpMtx_inputTriples(adjmtx, nent, buffer, buffer + nent) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n raw InpMtxobject") ; InpMtx_writeForHumanEye(adjmtx, msgFile) ; fflush(msgFile) ; } /* --------------------------------------- sort and compress the adjacency entries and convert to vector form --------------------------------------- */ InpMtx_sortAndCompress(adjmtx) ; InpMtx_changeStorageMode(adjmtx, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n sorted InpMtxobject") ; InpMtx_writeForHumanEye(adjmtx, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------ create the IVL object that contains the full adjacency ------------------------------------------------------ */ adjIVL = InpMtx_fullAdjacency(adjmtx) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n full adjacency object") ; IVL_writeForHumanEye(adjIVL, msgFile) ; fflush(msgFile) ; } /* -------------------------------- convert back to original storage -------------------------------- */ InpMtx_changeCoordType(inpmtx, oldtype) ; /* ------------------------ free the working storage ------------------------ */ IVfree(counts) ; IVfree(buffer) ; InpMtx_free(adjmtx) ; return(adjIVL) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- given a distributed Pencil object, gather all the indices onto each process and create an IVL object that contains the full adjacency structure created -- 97dec18, cca ----------------------------------------------------------- */ IVL * Pencil_MPI_fullAdjacency ( Pencil *pencil, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm ) { InpMtx *adjmtx, *inpmtxA, *inpmtxB ; int ierr, iproc, maxnent, myid, nent, nentA, nentB, nproc, oldtypeA, oldtypeB, totalnent ; int *buffer, *counts, *ivec1, *ivec2, *tempbuffer ; IVL *adjIVL ; /* ------------------------------------------------------ check for a simple pencil (only one nontrivial matrix) ------------------------------------------------------ */ inpmtxA = pencil->inpmtxA ; inpmtxB = pencil->inpmtxB ; if ( msglvl > 2 ) { fprintf(msgFile, "\n inside Pencil_MPI_fullAdjacency(), A = %p, B = %p", inpmtxA, inpmtxB) ; fprintf(msgFile, "\n sigma = [%12.4e,%12.4e]", pencil->sigma[0], pencil->sigma[1]) ; fflush(msgFile) ; } if ( inpmtxA == NULL ) { if ( pencil->sigma[0] != 0.0 && inpmtxB != NULL ) { adjIVL = InpMtx_MPI_fullAdjacency(inpmtxB, stats, msglvl, msgFile, comm) ; } else { adjIVL = NULL ; } return(adjIVL) ; } else if ( (pencil->sigma[0] == 0.0 && pencil->sigma[1] == 0.0) || inpmtxB == NULL ) { adjIVL = InpMtx_MPI_fullAdjacency(inpmtxA, stats, msglvl, msgFile, comm) ; return(adjIVL) ; } /* -------------------------------------- get id of self and number of processes -------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; /* --------------------------------------------- allocate a send buffer, fill with the indices from the two matrices, sort and compress --------------------------------------------- */ oldtypeA = InpMtx_coordType(inpmtxA) ; InpMtx_changeCoordType(inpmtxA, INPMTX_BY_ROWS) ; oldtypeB = InpMtx_coordType(inpmtxB) ; InpMtx_changeCoordType(inpmtxB, INPMTX_BY_ROWS) ; nentA = InpMtx_nent(inpmtxA) ; nentB = InpMtx_nent(inpmtxB) ; if ( nentA > 0 || nentB > 0 ) { tempbuffer = IVinit(2*(nentA + nentB), -1) ; ivec1 = tempbuffer ; ivec2 = ivec1 + nentA + nentB ; if ( nentA > 0 ) { IVcopy(nentA, ivec1, InpMtx_ivec1(inpmtxA)) ; IVcopy(nentA, ivec2, InpMtx_ivec2(inpmtxA)) ; } if ( nentB > 0 ) { IVcopy(nentB, ivec1 + nentA, InpMtx_ivec1(inpmtxB)) ; IVcopy(nentB, ivec2 + nentA, InpMtx_ivec2(inpmtxB)) ; } if ( msglvl > 5 ) { fprintf(msgFile, "\n\n before sort and compress") ; fprintf(msgFile, "\n ivec1") ; IVfprintf(msgFile, nentA + nentB, ivec1) ; fprintf(msgFile, "\n ivec2") ; IVfprintf(msgFile, nentA + nentB, ivec2) ; fflush(msgFile) ; } nent = IV2sortUpAndCompress(nentA + nentB, ivec1, ivec2) ; if ( msglvl > 5 ) { fprintf(msgFile, "\n\n after sort and compress, nent = %d", nent); fprintf(msgFile, "\n ivec1") ; IVfprintf(msgFile, nent, ivec1) ; fprintf(msgFile, "\n ivec2") ; IVfprintf(msgFile, nent, ivec2) ; fflush(msgFile) ; } } else { nent = 0 ; tempbuffer = NULL ; ivec1 = NULL ; ivec2 = NULL ; } if ( msglvl > 5 ) { fprintf(msgFile, "\n\n %d internal entries", nent) ; fflush(msgFile) ; } /* ------------------------------------------- find out how many entries each process owns ------------------------------------------- */ counts = IVinit(nproc, 0) ; counts[myid] = nent ; MPI_Allgather((void *) &counts[myid], 1, MPI_INT, (void *) counts, 1, MPI_INT, comm) ; totalnent = IVsum(nproc, counts) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %d total entries", totalnent) ; fprintf(msgFile, "\n\n counts vector") ; IVfp80(msgFile, nproc, counts, 80, &ierr) ; fflush(msgFile) ; } /* ------------------------------------------------- allocate a new InpMtx object to hold the indices ------------------------------------------------- */ adjmtx = InpMtx_new() ; InpMtx_init(adjmtx, INPMTX_BY_ROWS, INPMTX_INDICES_ONLY, totalnent, 0) ; /* ----------------------------------------- allocate a buffer to send/receive entries and load with the owned entries ----------------------------------------- */ maxnent = IVmax(nproc, counts, &iproc) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %d maximum entries", maxnent) ; fflush(msgFile) ; } buffer = IVinit(2*maxnent, -1) ; /* ---------------------------- now send and receive entries ---------------------------- */ for ( iproc = 0 ; iproc < nproc ; iproc++ ) { nent = counts[iproc] ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n processor %d's turn with %d entries", iproc, nent) ; fflush(msgFile) ; } if ( nent > 0 ) { if ( iproc == myid ) { /* ----------------------- load the entries buffer ----------------------- */ IVcopy(nent, buffer, ivec1) ; IVcopy(nent, buffer + nent, ivec2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n owned entries in buffer") ; fflush(msgFile) ; } if ( msglvl > 2 ) { IVfprintf(msgFile, 2*nent, buffer) ; fflush(msgFile) ; } stats[0]++ ; stats[2] += 2*nent*sizeof(int) ; } else { stats[1]++ ; stats[3] += 2*nent*sizeof(int) ; } /* ---------------------------------------- broadcast the entries from process iproc ---------------------------------------- */ MPI_Bcast((void *) buffer, 2*nent, MPI_INT, iproc, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after bcast, buffer") ; IVfprintf(msgFile, 2*nent, buffer) ; fflush(msgFile) ; } /* ------------------------------------------ load the entries into the adjacency matrix ------------------------------------------ */ InpMtx_inputTriples(adjmtx, nent, buffer, buffer + nent) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n entries from buffer loaded") ; fflush(msgFile) ; } } } /* --------------------------------------- sort and compress the adjacency entries --------------------------------------- */ InpMtx_sortAndCompress(adjmtx) ; InpMtx_changeStorageMode(adjmtx, INPMTX_BY_VECTORS) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n adjmtx") ; InpMtx_writeForHumanEye(adjmtx, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------ create the IVL object that contains the full adjacency ------------------------------------------------------ */ adjIVL = InpMtx_fullAdjacency(adjmtx) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n full adjacency object") ; IVL_writeForHumanEye(adjIVL, msgFile) ; fflush(msgFile) ; } /* -------------------------------- convert back to original storage -------------------------------- */ InpMtx_changeCoordType(inpmtxA, oldtypeA) ; InpMtx_changeCoordType(inpmtxB, oldtypeB) ; /* ------------------------ free the working storage ------------------------ */ IVfree(counts) ; if ( tempbuffer != NULL ) { IVfree(tempbuffer) ; } IVfree(buffer) ; InpMtx_free(adjmtx) ; return(adjIVL) ; } /*--------------------------------------------------------------------*/ ----- sort and compress the adjacency entries and convert to vector form --------------------------------------- */ InpMtx_sortAndCompress(adjmtx) ; InpMtx_changeStorageMode(adjmtx, INPMTX_BY_VECTORS) ; if ( MPI/src/makeSendRecvIVLs.c010064400020550007177000000117470662564177700166140ustar00clevecompmath00000400000006/* makeSendRecvIVLs.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- to analyze and organize communication. it was written in support of a distributed matrix-vector multiply but can be used for other applications. each processor has a list of items it "supports" or needs found in the supportedIV object. the globalmapIV object contains the map from items to owning processors. we need to figure out what items this processor will send to and receive from each other processor. this information is found in the sendIVL and recvIVL objects. on return, list jproc of sendIVL contains the items owned by this processor and needed by jproc. on return, list jproc of recvIVL contains the items needed by this processor and owned by jproc. as a concrete example, consider a distributed Y = A * X. the matrix A, the right hand side X and the vector Y are distributed among processors. consider the case where the supportedIV object contains the rows of X that are needed by this processor to perform its part of the matrix-vector multiply. globalmapIV contains the map from rows of X to the owning processors. on return, list jproc of sendIVL contains the row indices of X owned by this processor that are needed by processor jproc. on return, list jproc of recvIVL contains the row indices of X needed by this processor that are owned by processor jproc. consider the case where the supportedIV object contains the rows of Y that will be updated by this processor when it performs it part of the matrix-vector multiply. globalmapIV contains the map from rows of Y to their owning processors. on return, list jproc of recvIVL contains the row indices of Y on this processor that need to be sent to their owner, processor jproc. on return, list jproc of sendIVL contains the row indices of Y owned by this processor that will be sent by processor jproc to this processor. created -- 98aug01, cca ----------------------------------------------------------------- */ void makeSendRecvIVLs ( IV *supportedIV, IV *globalmapIV, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { int count, ii, item, jproc, maxitem, myid, nitem, nproc ; int *head, *items, *link, *list, *map ; /* --------------- check the input --------------- */ if ( supportedIV == NULL || globalmapIV == NULL || sendIVL == NULL || recvIVL == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in makeSendRecvIVLs()" "\n bad input\n") ; exit(-1) ; } IV_sizeAndEntries(supportedIV, &nitem, &items) ; if ( nitem == 0 ) { maxitem = 0 ; } else { maxitem = items[nitem-1] ; } map = IV_entries(globalmapIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside makeSendRecvIVLs()" "\n supportedIV") ; IV_writeForHumanEye(supportedIV, msgFile) ; fprintf(msgFile, "\n globalmapIV") ; IV_writeForHumanEye(globalmapIV, msgFile) ; fflush(msgFile) ; } /* --------------------------------------- get id of self and number of processors --------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; /* ---------------------------------------------------- link the items into lists via their owning processor ---------------------------------------------------- */ head = IVinit(nproc, -1) ; link = IVinit(1 + maxitem, -1) ; for ( ii = 0 ; ii < nitem ; ii++ ) { item = items[ii] ; jproc = map[item] ; link[item] = head[jproc] ; head[jproc] = item ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n items linked by owning processor") ; fflush(msgFile) ; } /* --------------------------------------- initialize and fill the recvIVL object. list jproc contains the items that this processor needs from jproc. --------------------------------------- */ IVL_init1(recvIVL, IVL_CHUNKED, nproc) ; if ( nitem > 0 ) { list = IVinit(nitem, -1) ; for ( jproc = 0 ; jproc < nproc ; jproc++ ) { count = 0 ; for ( item = head[jproc] ; item != -1 ; item = link[item] ) { list[count++] = item ; } IVqsortUp(count, list) ; IVL_setList(recvIVL, jproc, count, list) ; } IVfree(list) ; IVfree(head) ; IVfree(link) ; } if ( msglvl > 5 ) { fprintf(msgFile, "\n\n recvIVL") ; IVL_writeForHumanEye(recvIVL, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------------------------- compute the sendIVL object via an all-to-all communication ---------------------------------------------------------- */ IVL_MPI_alltoall(recvIVL, sendIVL, stats, msglvl, msgFile, firsttag, comm) ; return ; } /*--------------------------------------------------------------------*/ MPI/src/postProcess.c010064400020550007177000000602470656705760100160220ustar00clevecompmath00000400000006/* postProcess.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- post-process the factorization (1) permute row and column adjacency objects if necessary (2) permute lower and upper matrices if necessary (3) update the block adjacency objects if necessary (4) split the chevron submatrices into submatrices and make the submatrix indices local w.r.t their fronts created -- 98may20, cca -------------------------------------------------------------- */ void FrontMtx_MPI_postProcess ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { int lasttag, nfront, nproc, tagbound ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || frontOwnersIV == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_MPI_postProcess()" "\n frontmtx %p, frontOwnersIV %p, firsttag %d" "\n stats %p, msglvl %d, msgFile %p, comm %p" "\n bad input\n", frontmtx, frontOwnersIV, firsttag, stats, msglvl, msgFile, comm) ; exit(-1) ; } MPI_Comm_size(comm, &nproc) ; lasttag = firsttag + 5*nproc ; tagbound = maxTagMPI(comm) ; if ( firsttag < 0 || lasttag > tagbound ) { fprintf(stderr, "\n fatal error in FrontMtx_MPI_postProcess()" "\n firsttag = %d, tagbound = %d", firsttag, tagbound) ; exit(-1) ; } nfront = frontmtx->nfront ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n nfront = %d, pivotingflag = %d", nfront, frontmtx->pivotingflag) ; fflush(msgFile) ; } if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { IV *colmapIV, *rowmapIV ; /* -------------------------------------- gather the global frontsizes IV object -------------------------------------- */ IV_MPI_allgather(frontmtx->frontsizesIV, frontOwnersIV, stats, msglvl, msgFile, firsttag, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n global frontsizes IV object") ; IV_writeForHumanEye(frontmtx->frontsizesIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------- permute the adjacency object(s) ------------------------------- */ FrontMtx_MPI_permuteUpperAdj(frontmtx, frontOwnersIV, stats, msglvl, msgFile, firsttag, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n new column adjacency object") ; IVL_writeForHumanEye(frontmtx->coladjIVL, msgFile) ; fflush(msgFile) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { FrontMtx_MPI_permuteLowerAdj(frontmtx, frontOwnersIV, stats, msglvl, msgFile, firsttag, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n new row adjacency object") ; IVL_writeForHumanEye(frontmtx->rowadjIVL, msgFile) ; fflush(msgFile) ; } } /* ------------------------------------------------------------- permute the U_{J,bnd{J}} and L_{bnd{J},J} triangular matrices ------------------------------------------------------------- */ FrontMtx_permuteUpperMatrices(frontmtx, msglvl, msgFile) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { FrontMtx_permuteLowerMatrices(frontmtx, msglvl, msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix after pivoting") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } /* ----------------------------------------------- get the map from columns to owning fronts and create the new upper block adjacency object ----------------------------------------------- */ colmapIV = FrontMtx_colmapIV(frontmtx) ; frontmtx->upperblockIVL = FrontMtx_makeUpperBlockIVL(frontmtx, colmapIV) ; IV_free(colmapIV) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* ------------------------------------------- get the map from rows to owning fronts and create the new lower block adjacency object ------------------------------------------- */ rowmapIV = FrontMtx_rowmapIV(frontmtx) ; frontmtx->lowerblockIVL = FrontMtx_makeLowerBlockIVL(frontmtx, rowmapIV) ; IV_free(rowmapIV) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n local upper block adjacency object") ; IVL_writeForHumanEye(frontmtx->upperblockIVL, msgFile) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { fprintf(msgFile, "\n\n local lower block adjacency object") ; IVL_writeForHumanEye(frontmtx->lowerblockIVL, msgFile) ; } fflush(msgFile) ; } } else { /* --------------------------------------- get the upper block adjacency structure --------------------------------------- */ IV *vtxToFrontIV = ETree_vtxToFrontIV(frontmtx->frontETree) ; frontmtx->upperblockIVL = FrontMtx_makeUpperBlockIVL(frontmtx, vtxToFrontIV) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { frontmtx->lowerblockIVL = FrontMtx_makeUpperBlockIVL(frontmtx, vtxToFrontIV) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n local upper block adjacency object") ; IVL_writeForHumanEye(frontmtx->upperblockIVL, msgFile) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { fprintf(msgFile, "\n\n local lower block adjacency object") ; IVL_writeForHumanEye(frontmtx->lowerblockIVL, msgFile) ; } fflush(msgFile) ; } } /* -------------------------------------- all-gather the block adjacency objects -------------------------------------- */ IVL_MPI_allgather(frontmtx->upperblockIVL, frontOwnersIV, stats, msglvl, msgFile, firsttag, comm) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { IVL_MPI_allgather(frontmtx->lowerblockIVL, frontOwnersIV, stats, msglvl, msgFile, firsttag, comm) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n global upper block adjacency object") ; IVL_writeForHumanEye(frontmtx->upperblockIVL, msgFile) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { fprintf(msgFile, "\n\n global lower block adjacency object") ; IVL_writeForHumanEye(frontmtx->lowerblockIVL, msgFile) ; } fflush(msgFile) ; } /* ------------------------ allocate the hash tables ------------------------ */ frontmtx->upperhash = I2Ohash_new() ; I2Ohash_init(frontmtx->upperhash, nfront, nfront, nfront) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { frontmtx->lowerhash = I2Ohash_new() ; I2Ohash_init(frontmtx->lowerhash, nfront, nfront, nfront) ; } else { frontmtx->lowerhash = NULL ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n hash tables allocated") ; fflush(msgFile) ; } /* -------------------------------------------------------- split the U_{J,bnd{J}} and L_{bnd{J},J} into submatrices put the U_{J,K} and L_{K,J} matrices into hash tables, free the p_mtx*[] vectors. -------------------------------------------------------- */ FrontMtx_splitUpperMatrices(frontmtx, msglvl, msgFile) ; FREE(frontmtx->p_mtxUJJ) ; frontmtx->p_mtxUJJ = NULL ; FREE(frontmtx->p_mtxUJN) ; frontmtx->p_mtxUJN = NULL ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { FrontMtx_splitLowerMatrices(frontmtx, msglvl, msgFile) ; FREE(frontmtx->p_mtxLJJ) ; frontmtx->p_mtxLJJ = NULL ; FREE(frontmtx->p_mtxLNJ) ; frontmtx->p_mtxLNJ = NULL ; } frontmtx->dataMode = FRONTMTX_2D_MODE ; if ( msglvl > 2 ) { fprintf(msgFile, "\n matrices split into submatrices") ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- to permute the indices of the upper adjacency structure so that for each front J, bnd{J} is in ascending order w.r.t. K cup bnd{K} for par[J] = K. process q sends to process r one message that contains J cup bnd{J} for all J owned by q and needed by r. once all the indices for the supported fronts are present, the indices in the upper adjacency structure are reordered as necessary. created -- 98may20, cca ------------------------------------------------------------- */ void FrontMtx_MPI_permuteUpperAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { int count, destination, incount, iproc, J, K, left, lasttag, myid, ncolJ, nfront, nproc, offset, outcount, right, source, tag, tagbound ; int *colindJ, *inbuffer, *incounts, *mark, *owners, *outbuffer, *outcounts, *par ; IVL *coladjIVL ; MPI_Status status ; /* -------------- check the data -------------- */ if ( frontmtx == NULL || frontOwnersIV == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(msgFile, "\n fatal error in FrontMtx_MPI_permuteUpperAdj()" "\n frontmtx %p, frontOwnersIV %p, firsttag %d" "\n stats %p, msglvl %d, msgFile %p" "\n bad input\n", frontmtx, frontOwnersIV, firsttag, stats, msglvl, msgFile) ; exit(-1) ; } /* ---------------------------------------------- get id of self, # of processes and # of fronts ---------------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n inside FrontMtx_MPI_permuteUpperAdj" "\n nproc = %d, myid = %d", nproc, myid) ; fflush(msgFile) ; } /* ------------------- check the tag value ------------------- */ lasttag = firsttag + nproc ; tagbound = maxTagMPI(comm) ; if ( firsttag < 0 || lasttag > tagbound ) { fprintf(stderr, "\n fatal error in FrontMtx_MPI_permuteUpperAdj()" "\n firsttag = %d, tagbound = %d", firsttag, tagbound) ; exit(-1) ; } nfront = FrontMtx_nfront(frontmtx) ; coladjIVL = frontmtx->coladjIVL ; par = frontmtx->frontETree->tree->par ; owners = IV_entries(frontOwnersIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n coladjIVL") ; IVL_writeForHumanEye(coladjIVL, msgFile) ; fflush(msgFile) ; } /* --------------------------------------------- step 1 : determine the message size that this process will send to each other process --------------------------------------------- */ incounts = IVinit(2*nproc, 0) ; outcounts = incounts + nproc ; mark = IVinit(nfront, -1) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( iproc != myid ) { /* ----------------------------------- set mark[J] = 1 if iproc supports J ----------------------------------- */ IVfill(nfront, mark, -1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( owners[J] == iproc ) { for ( K = J ; K != -1 && mark[K] == -1 ; K = par[K] ) { mark[K] = 1 ; } } } /* ------------------------------------------------ compute the size of the message to send to iproc ------------------------------------------------ */ for ( J = count = 0 ; J < nfront ; J++ ) { if ( owners[J] == myid && mark[J] == 1 ) { FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; count += 2 + ncolJ ; } } outcounts[iproc] = count ; } } /* ------------------------------- do an all-to-all gather/scatter ------------------------------- */ MPI_Alltoall((void *) outcounts, 1, MPI_INT, (void *) incounts, 1, MPI_INT, comm) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n incounts") ; IVfprintf(msgFile, nproc, incounts) ; fprintf(msgFile, "\n\n outcounts") ; IVfprintf(msgFile, nproc, outcounts) ; fflush(msgFile) ; } /* ----------------------------- set up the in and out buffers ----------------------------- */ count = IVmax(nproc, incounts, &iproc) ; inbuffer = IVinit(count, -1) ; count = IVmax(nproc, outcounts, &iproc) ; outbuffer = IVinit(count, -1) ; /* ---------------------------------------- step 2: loop over the other processes, gather information and send them off, receive information ---------------------------------------- */ for ( offset = 1, tag = firsttag ; offset < nproc ; offset++, tag++ ) { right = (myid + offset) % nproc ; left = (nproc + myid - offset) % nproc ; outcount = outcounts[right] ; incount = incounts[left] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n ### process %d, send %d to right %d, recv %d from left %d", myid, outcount, right, incount, left) ; fflush(msgFile) ; } if ( outcount > 0 ) { /* ----------------------------------- set mark[J] = 1 if right supports J ----------------------------------- */ IVfill(nfront, mark, -1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( owners[J] == right ) { for ( K = J ; K != -1 && mark[K] == -1 ; K = par[K] ) { mark[K] = 1 ; } } } /* ---------------------------------------------- load the message with the owned column indices that are needed by process right ---------------------------------------------- */ for ( J = count = 0 ; J < nfront ; J++ ) { if ( owners[J] == myid && mark[J] == 1 ) { FrontMtx_columnIndices(frontmtx, J, &ncolJ, &colindJ) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n loading adj(%d) :", J) ; IVfprintf(msgFile, ncolJ, colindJ) ; } outbuffer[count++] = J ; outbuffer[count++] = ncolJ ; IVcopy(ncolJ, outbuffer + count, colindJ) ; count += ncolJ ; } } if ( count != outcount ) { fprintf(stderr, "\n 0. fatal error in FrontMtx_MPI_permuteUpperAdj()" "\n proc %d : count = %d, outcount = %d\n", myid, count, incount) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n message to %d", right) ; IVfprintf(msgFile, count, outbuffer) ; fflush(msgFile) ; } destination = right ; stats[0]++ ; stats[2] += outcount ; } else { destination = MPI_PROC_NULL ; } if ( incount > 0 ) { source = left ; stats[1]++ ; stats[3] += incount ; } else { source = MPI_PROC_NULL ; } /* ----------------- do a send/receive ----------------- */ MPI_Sendrecv(outbuffer, outcount, MPI_INT, destination, tag, inbuffer, incount, MPI_INT, source, tag, comm, &status) ; if ( source != MPI_PROC_NULL ) { MPI_Get_count(&status, MPI_INT, &count) ; if ( count != incount ) { fprintf(stderr, "\n 1. fatal error in FrontMtx_MPI_permuteUpperAdj()" "\n proc %d : source = %d, count = %d, incount = %d\n", myid, source, count, incount) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n message from %d", source) ; IVfprintf(msgFile, count, inbuffer) ; fflush(msgFile) ; } } /* -------------------------------------------- set up the new lists in the coladjIVL object -------------------------------------------- */ count = 0 ; while ( count < incount ) { J = inbuffer[count++] ; ncolJ = inbuffer[count++] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n setting list (%d) :", J) ; IVfprintf(msgFile, ncolJ, inbuffer + count) ; } IVL_setList(coladjIVL, J, ncolJ, inbuffer + count) ; count += ncolJ ; } if ( count != incount ) { fprintf(stderr, "\n 2. fatal error in FrontMtx_MPI_permuteUpperAdj()" "\n proc %d : source = %d, count = %d, incount = %d\n", myid, source, count, incount) ; exit(-1) ; } } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n necessary upper adj") ; IVL_writeForHumanEye(coladjIVL, msgFile) ; } /* ---------------------------------------------------------------- now reorder the supported portion of the column adjacency object ---------------------------------------------------------------- */ FrontMtx_permuteUpperAdj(frontmtx, msglvl, msgFile) ; /* ------------------------ free the working storage ------------------------ */ IVfree(mark) ; IVfree(incounts) ; IVfree(inbuffer) ; IVfree(outbuffer) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- to permute the indices of the lower adjacency structure so that for each front J, bnd{J} is in ascending order w.r.t. K cup bnd{K} for par[J] = K. process q sends to process r one message that contains J cup bnd{J} for all J owned by q and needed by r. once all the indices for the supported fronts are present, the indices in the lower adjacency structure are reordered as necessary. created -- 98may20, cca ------------------------------------------------------------- */ void FrontMtx_MPI_permuteLowerAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { int count, destination, incount, iproc, J, K, left, lasttag, myid, nfront, nproc, nrowJ, offset, outcount, right, source, tag, tagbound ; int *inbuffer, *incounts, *mark, *owners, *outbuffer, *outcounts, *par, *rowindJ ; IVL *rowadjIVL ; MPI_Status status ; /* -------------- check the data -------------- */ if ( frontmtx == NULL || frontOwnersIV == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(msgFile, "\n fatal error in FrontMtx_MPI_permuteLowerAdj()" "\n frontmtx %p, frontOwnersIV %p, firsttag %d" "\n stats %p, msglvl %d, msgFile %p" "\n bad input\n", frontmtx, frontOwnersIV, firsttag, stats, msglvl, msgFile) ; exit(-1) ; } /* ---------------------------------------------- get id of self, # of processes and # of fronts ---------------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n inside FrontMtx_MPI_permuteLowerAdj" "\n nproc = %d, myid = %d", nproc, myid) ; fflush(msgFile) ; } /* ------------------- check the tag value ------------------- */ lasttag = firsttag + nproc ; tagbound = maxTagMPI(comm) ; if ( firsttag < 0 || lasttag > tagbound ) { fprintf(stderr, "\n fatal error in FrontMtx_MPI_permuteUpperAdj()" "\n firsttag = %d, tagbound = %d", firsttag, tagbound) ; exit(-1) ; } nfront = FrontMtx_nfront(frontmtx) ; rowadjIVL = frontmtx->rowadjIVL ; par = frontmtx->frontETree->tree->par ; owners = IV_entries(frontOwnersIV) ; /* --------------------------------------------- step 1 : determine the message size that this process will send to each other process --------------------------------------------- */ incounts = IVinit(2*nproc, 0) ; outcounts = incounts + nproc ; mark = IVinit(nfront, -1) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( iproc != myid ) { /* ----------------------------------- set mark[J] = 1 if iproc supports J ----------------------------------- */ IVfill(nfront, mark, -1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( owners[J] == iproc ) { for ( K = J ; K != -1 && mark[K] == -1 ; K = par[K] ) { mark[K] = 1 ; } } } /* ------------------------------------------------ compute the size of the message to send to iproc ------------------------------------------------ */ for ( J = count = 0 ; J < nfront ; J++ ) { if ( owners[J] == myid && mark[J] == 1 ) { FrontMtx_rowIndices(frontmtx, J, &nrowJ, &rowindJ) ; count += 2 + nrowJ ; } } outcounts[iproc] = count ; } } /* ------------------------------- do an all-to-all gather/scatter ------------------------------- */ MPI_Alltoall((void *) outcounts, 1, MPI_INT, (void *) incounts, 1, MPI_INT, comm) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n incounts") ; IVfprintf(msgFile, nproc, incounts) ; fprintf(msgFile, "\n\n outcounts") ; IVfprintf(msgFile, nproc, outcounts) ; fflush(msgFile) ; } /* ----------------------------- set up the in and out buffers ----------------------------- */ count = IVmax(nproc, incounts, &iproc) ; inbuffer = IVinit(count, -1) ; count = IVmax(nproc, outcounts, &iproc) ; outbuffer = IVinit(count, -1) ; /* ---------------------------------------- step 2: loop over the other processes, gather information and send them off, receive information ---------------------------------------- */ tag = firsttag ; for ( offset = 1 ; offset < nproc ; offset++ ) { right = (myid + offset) % nproc ; if ( offset <= myid ) { left = myid - offset ; } else { left = nproc + myid - offset ; } outcount = outcounts[right] ; incount = incounts[left] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n ### process %d, send %d to right %d, recv %d from left %d", myid, outcount, right, incount, left) ; fflush(msgFile) ; } if ( outcount > 0 ) { /* ----------------------------------- set mark[J] = 1 if right supports J ----------------------------------- */ IVfill(nfront, mark, -1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( owners[J] == right ) { for ( K = J ; K != -1 && mark[K] == -1 ; K = par[K] ) { mark[K] = 1 ; } } } /* ------------------------------------------- load the message with the owned row indices that are needed by process right ------------------------------------------- */ for ( J = count = 0 ; J < nfront ; J++ ) { if ( owners[J] == myid && mark[J] == 1 ) { FrontMtx_rowIndices(frontmtx, J, &nrowJ, &rowindJ) ; outbuffer[count++] = J ; outbuffer[count++] = nrowJ ; IVcopy(nrowJ, outbuffer + count, rowindJ) ; count += nrowJ ; } } destination = right ; stats[0]++ ; stats[2] += outcount ; } else { destination = MPI_PROC_NULL ; } if ( incount > 0 ) { source = left ; stats[1]++ ; stats[3] += incount ; } else { source = MPI_PROC_NULL ; } /* ----------------- do a send/receive ----------------- */ MPI_Sendrecv(outbuffer, outcount, MPI_INT, destination, tag, inbuffer, incount, MPI_INT, source, tag, comm, &status) ; if ( source != MPI_PROC_NULL ) { MPI_Get_count(&status, MPI_INT, &count) ; if ( count != incount ) { fprintf(stderr, "\n 1. fatal error in FrontMtx_MPI_permuteLowerAdj()" "\n proc %d : source = %d, count = %d, incount = %d\n", myid, source, count, incount) ; exit(-1) ; } } /* -------------------------------------------- set up the new lists in the rowadjIVL object -------------------------------------------- */ count = 0 ; while ( count < incount ) { J = inbuffer[count++] ; nrowJ = inbuffer[count++] ; IVL_setList(rowadjIVL, J, nrowJ, inbuffer + count) ; count += nrowJ ; } if ( count != incount ) { fprintf(stderr, "\n 2. fatal error in FrontMtx_MPI_permuteLowerAdj()" "\n proc %d : source = %d, count = %d, incount = %d\n", myid, source, count, incount) ; exit(-1) ; } } /* ------------------------------------------------------------- now reorder the supported portion of the row adjacency object ------------------------------------------------------------- */ FrontMtx_permuteLowerAdj(frontmtx, msglvl, msgFile) ; /* ------------------------ free the working storage ------------------------ */ IVfree(mark) ; IVfree(incounts) ; IVfree(inbuffer) ; IVfree(outbuffer) ; return ; } /*--------------------------------------------------------------------*/ destination = MPI_PROC_NULL ; } if ( incount > 0 ) { source = left ; stats[1]++ ; stats[3] += incount ; } else { source = MPI_PROC_NULL ; } /* ----------------- do a send/receive ----------------- */ MPI_Sendrecv(outbuffer, outcount, MPI_INT, destination, tag, inbuffer, incounMPI/src/rowmapMPI.c010064400020550007177000000117670655671743100153560ustar00clevecompmath00000400000006/* rowmapIV.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- after pivoting for a nonsymmetric factorization, some delayed rows may belong to a process other than its original owner. this method returns an IV object that maps rows to owning processes. created -- 98may22, cca ----------------------------------------------------------- */ IV * FrontMtx_MPI_rowmapIV ( FrontMtx *frontmtx, IV *frontOwnersIV, int msglvl, FILE *msgFile, MPI_Comm comm ) { int buffersize, ii, iproc, J, myid, nDJ, neqns, nfront, nproc, nrowJ, nToSend, v ; int *buffer, *counts, *frontOwners, *inbuffer, *outbuffer, *rowindJ, *rowmap, *vtxToFront ; IV *rowmapIV ; /* ------------------------------------------- get the process id and number of processors ------------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; neqns = frontmtx->neqns ; vtxToFront = ETree_vtxToFront(frontmtx->frontETree) ; IV_sizeAndEntries(frontOwnersIV, &nfront, &frontOwners) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside FrontMtx_MPI_rowmapIV()" "\n myid = %d, nproc = %d, nfront = %d, neqns = %d", myid, nproc, nfront, neqns) ; fflush(msgFile) ; } /* ---------------------------------------------------------- loop through the owned fronts and store each row in an owned front that was originally owned by another processor ---------------------------------------------------------- */ outbuffer = IVinit(neqns, -1) ; for ( J = nToSend = 0 ; J < nfront ; J++ ) { if ( frontOwners[J] == myid && (nDJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { FrontMtx_rowIndices(frontmtx, J, &nrowJ, &rowindJ) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n front %d owned, nDJ = %d, nrowJ = %d", J, nDJ, nrowJ) ; fflush(msgFile) ; } for ( ii = 0 ; ii < nDJ ; ii++ ) { v = rowindJ[ii] ; if ( frontOwners[vtxToFront[v]] != myid ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n row %d originally owned by %d", v, frontOwners[vtxToFront[v]]) ; fflush(msgFile) ; } outbuffer[nToSend++] = v ; } } } } IVqsortUp(nToSend, outbuffer) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n shifted vertices") ; IVfprintf(msgFile, nToSend, outbuffer) ; fflush(msgFile) ; } counts = IVinit(nproc, 0) ; /* ------------------------------------------- use an all-gather call to get the number of moved rows that are owned by each process ------------------------------------------- */ MPI_Allgather((void *) &nToSend, 1, MPI_INT, counts, 1, MPI_INT, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n after the all-gather operation, counts") ; IVfprintf(msgFile, nproc, counts) ; fflush(msgFile) ; } buffersize = IVmax(nproc, counts, &iproc) ; inbuffer = IVinit(buffersize, -1) ; /* -------------------------------- initialize the row map IV object -------------------------------- */ rowmapIV = IV_new() ; IV_init(rowmapIV, neqns, NULL) ; rowmap = IV_entries(rowmapIV) ; IVgather(neqns, rowmap, frontOwners, vtxToFront) ; /* ----------------------------------------------------------- loop over the other processes, receive vector of moved rows ----------------------------------------------------------- */ for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( counts[iproc] > 0 ) { if ( iproc == myid ) { /* ------------------------------------- send buffer vector to other processes ------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n sending outbuffer to all processes") ; IVfprintf(msgFile, nToSend, outbuffer) ; fflush(msgFile) ; } MPI_Bcast(outbuffer, nToSend, MPI_INT, iproc, comm) ; buffer = outbuffer ; } else { /* ----------------------------------------- receive the vector from the other process ----------------------------------------- */ MPI_Bcast(inbuffer, counts[iproc], MPI_INT, iproc, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n received inbuffer from process %d", iproc) ; IVfprintf(msgFile, counts[iproc], inbuffer) ; fflush(msgFile) ; } buffer = inbuffer ; } /* ---------------------- set the row map values ---------------------- */ for ( ii = 0 ; ii < counts[iproc] ; ii++ ) { v = buffer[ii] ; rowmap[v] = iproc ; } } } /* ------------------------ free the working storage ------------------------ */ IVfree(inbuffer) ; IVfree(outbuffer) ; IVfree(counts) ; return(rowmapIV) ; } /*--------------------------------------------------------------------*/ MPI/src/solveMPI.c010064400020550007177000001044440656731345100151700ustar00clevecompmath00000400000006/* solveMPI.c */ #include "../spoolesMPI.h" #include "../../timings.h" #define AGGREGATE 1 #define SOLUTION 2 /*--------------------------------------------------------------------*/ typedef struct _SolveMsg SolveMsg ; struct _SolveMsg { int info[3] ; /* type, frontid, nbytes */ void *base ; SubMtx *mtx ; SolveMsg *next ; MPI_Request req ; } ; /*--------------------------------------------------------------------*/ static SolveMsg * SolveMsg_new ( void ) ; static void checkForAggMessages ( FrontMtx *frontmtx, int J, int nrhs, int owners[], int myid, char recvsPosted[], int inAggCounts[], SolveMsg *p_msg[], SubMtxManager *mtxmanager, SubMtxList *aggList, int stats[], int firsttag, MPI_Comm comm, int msglvl, FILE *msgFile); static SubMtx * checkForSolMessages ( FrontMtx *frontmtx, int nrhs, int J, int owners[], int myid, IP *heads[], char frontIsDone[], char recvsPosted[], SolveMsg *p_msg[], SubMtx *p_mtx[], int nUsed[], SubMtxManager *mtxmanager, int stats[], int firsttag, MPI_Comm comm, int msglvl, FILE *msgFile ) ; static SolveMsg * checkSentMessages ( SolveMsg *firstmsg, SubMtxManager *mtxmanager, int msglvl, FILE *msgFile ) ; static SolveMsg * sendMessages ( int J, int owners[], int myid, SubMtx *p_mtx[], IVL *solveIVL, SubMtxList *aggList, SubMtxManager *mtxmanager, SolveMsg *firstmsg, int stats[], int firsttag, MPI_Comm comm, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- MPI solve method for (L + I)D(I + U)X = B or (U^T + I)D(I + U)X = B created -- 98may21, ca ------------------------------------------------------------------- */ void FrontMtx_MPI_solve ( FrontMtx *frontmtx, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, SolveMap *solvemap, double cpus[], int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { char *frontIsDone, *recvsPosted, *status ; SubMtx *mtx, *releaseHead ; SubMtx **p_mtx ; SubMtxList *aggList ; double t0, t1, t2, t3 ; Ideq *dequeue ; int I, J, K, lasttag, myid, nfront, nJ, nproc, nrhs, tagbound ; int *fch, *inAggCounts, *nactiveChild, *nUsed, *owners, *par, *sib ; IP *ip ; IP **heads ; IV *aggCountsIV ; IVL *solveIVL ; SolveMsg *firstmsg ; SolveMsg **p_msg ; Tree *tree ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || mtxX == NULL || mtxB == NULL || mtxmanager == NULL || solvemap == NULL || cpus == NULL || stats == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_MPI_solve()" "\n bad input\n") ; exit(-1) ; } MARKTIME(t0) ; nfront = frontmtx->nfront ; tree = frontmtx->tree ; par = tree->par ; fch = tree->fch ; sib = tree->sib ; nrhs = mtxB->ncol ; owners = SolveMap_owners(solvemap) ; /* ------------------------------ get id and number of processes ------------------------------ */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; /* ------------------- check the tag range ------------------- */ lasttag = firsttag + 2*nproc ; tagbound = maxTagMPI(comm) ; if ( firsttag < 0 || lasttag > tagbound ) { fprintf(stderr, "\n fatal error in FrontMtx_MPI_solve()" "\n firsttag = %d, lasttag = %d, tag_bound = %d", firsttag, lasttag, tagbound) ; exit(-1) ; } /* --------------------------------------------------------------- allocate the working data that lasts for the entire solve recvsPosted[J] == 'Y' --> any receives for J have been posted, receives can only be posted once frontIsDone[J] == 'Y' --> front J is done w.r.t. this processor note, if |J| = 0, front is done status[J] = 'W' --> J is asleep or active 'F' --> J is finished p_msg[J] = pointer to first message for J if ( J owned ) { p_msg[J] = first in list of incoming aggregates } if ( J used ) { p_msg[J] = message to hold X_J } nUsed[*] -- used to manage scope of unowned X_J if ( J not owned but X_J used ) { nUsed[J] = # of remaining times to use X_J } --------------------------------------------------------------- */ recvsPosted = CVinit(nfront, 'N') ; frontIsDone = CVinit(nfront, 'W') ; status = CVinit(nfront, 'W') ; ALLOCATE(p_msg, SolveMsg *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { p_msg[J] = NULL ; } nUsed = IVinit(nfront, 0) ; /* ---------------------------------------------------------------- set up the working data specific to the forward solve solveIVL -- holds lists of processors that need XJ objects aggCountsIV -- vector of aggregate counts aggList -- object to manage aggregate instances heads[*] -- linked lists for updates local to this processor dequeue -- object to manager bottom-up traversal nactiveChild -- manages placement of parents on dequeue ---------------------------------------------------------------- */ MARKTIME(t1) ; solveIVL = SolveMap_lowerSolveIVL(solvemap, myid, msglvl, msgFile) ; aggCountsIV = SolveMap_lowerAggregateIV(solvemap, myid, msglvl, msgFile) ; inAggCounts = IV_entries(aggCountsIV) ; aggList = SubMtxList_new() ; SubMtxList_init(aggList, nfront, inAggCounts, NO_LOCK, NULL) ; heads = SolveMap_forwardSetup(solvemap, myid, msglvl, msgFile) ; dequeue = FrontMtx_setUpDequeue(frontmtx, owners, myid, status, heads, 'W', 'F', msglvl, msgFile) ; FrontMtx_loadActiveLeaves(frontmtx, status, 'W', dequeue) ; nactiveChild = FrontMtx_nactiveChild(frontmtx, status, myid) ; for ( J = 0 ; J < nfront ; J++ ) { for ( ip = heads[J] ; ip != NULL ; ip = ip->next ) { I = ip->val ; if ( owners[I] != myid ) { nUsed[I]++ ; } } } if ( msglvl > 2 ) { IP *ip ; fprintf(msgFile, "\n\n ### setup for forward solve") ; fprintf(msgFile, "\n\n solveIVL ") ; IVL_writeForHumanEye(solveIVL, msgFile) ; fprintf(msgFile, "\n\n aggList ") ; SubMtxList_writeForHumanEye(aggList, msgFile) ; fprintf(msgFile, "\n\n initial dequeue") ; Ideq_writeForHumanEye(dequeue, msgFile) ; fprintf(msgFile, "\n\n forward update lists") ; for ( J = 0 ; J < nfront ; J++ ) { if ( heads[J] != NULL ) { fprintf(msgFile, "\n %d : ", J) ; for ( ip = heads[J] ; ip != NULL ; ip = ip->next ) { fprintf(msgFile, " %d", ip->val) ; } } } fprintf(msgFile, "\n\n nactiveChild") ; IVfprintf(msgFile, nfront, nactiveChild) ; fflush(msgFile) ; } MARKTIME(t2) ; cpus[0] += t2 - t1 ; /* -------------------------------------------------------- load the right hand side, p_mtx[*] is returned if ( J owned ) { p_mtx[J] is initially B_J and overwritten with X_J } else { if ( J is supported by q ) { p_mtx[J] contains Y_J^q until sent to owner of Y_J } if ( XJ is used by q ) { p_mtx[J] contains X_J when received } } -------------------------------------------------------- */ MARKTIME(t1) ; p_mtx = FrontMtx_loadRightHandSide(frontmtx, mtxB, owners, myid, mtxmanager, msglvl, msgFile) ; MARKTIME(t2) ; cpus[1] += t2 - t1 ; /* ------------- forward solve ------------- */ MARKTIME(t1) ; firstmsg = NULL ; while ( (J = Ideq_removeFromHead(dequeue)) != -1 ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ### forward solve, checking out J = %d, status %c", J, status[J]) ; fflush(msgFile) ; } if ( (nJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { /* ------------------------------------- check for necessary incoming solution matrices needed to compute X_J ------------------------------------- */ releaseHead = checkForSolMessages(frontmtx, nrhs, J, owners, myid, heads, frontIsDone, recvsPosted, p_msg, p_mtx, nUsed, mtxmanager, stats, firsttag, comm, msglvl, msgFile) ; if ( owners[J] == myid ) { /* ------------------------------------- check for incoming aggregate messages ------------------------------------- */ checkForAggMessages(frontmtx, J, nrhs, owners, myid, recvsPosted, inAggCounts, p_msg, mtxmanager, aggList, stats, firsttag, comm, msglvl, msgFile) ; } /* --------------- visit the front --------------- */ FrontMtx_forwardVisit(frontmtx, J, nrhs, owners, myid, mtxmanager, aggList, p_mtx, frontIsDone, heads, p_mtx, status, msglvl, msgFile) ; } else { /* ---------------------------------------- front has no eliminated rows and columns ---------------------------------------- */ status[J] = 'F' ; releaseHead = NULL ; } if ( status[J] == 'F' ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n front J is finished") ; fflush(msgFile) ; } if ( nJ > 0 ) { /* ------------------------------------------------------------ front J is finished, send any solution or aggregate messages ------------------------------------------------------------ */ firstmsg = sendMessages(J, owners, myid, p_mtx, solveIVL, aggList, mtxmanager, firstmsg, stats, firsttag, comm, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n after sendMessages, p_mtx[%d] = %p", J, p_mtx[J]) ; fflush(msgFile) ; } } if ( (K = par[J]) != -1 && --nactiveChild[K] == 0 ) { /* ----------------------------------- all children of parent are finished add parent to head of dequeue ----------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n placing %d on head of dequeue", K) ; fflush(msgFile) ; } Ideq_insertAtHead(dequeue, K) ; } } else { /* ------------------------------------------------- front J is not finished, place on tail of dequeue ------------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n front J is not finished") ; fflush(msgFile) ; } Ideq_insertAtTail(dequeue, J) ; } /* -------------------------------------------- check all posted sends, any message that has been received, recycle its SubMtx object -------------------------------------------- */ firstmsg = checkSentMessages(firstmsg, mtxmanager, msglvl, msgFile) ; /* ---------------------------------------------------------- release all external X_J objects that are no longer needed ---------------------------------------------------------- */ while ( (mtx = releaseHead) != NULL ) { p_mtx[mtx->rowid] = NULL ; releaseHead = mtx->next ; SubMtxManager_releaseObject(mtxmanager, mtx) ; } } while ( firstmsg != NULL ) { /* ------------------------------------------ check all posted sends, any message that has been received, recycle its SubMtx object ------------------------------------------ */ firstmsg = checkSentMessages(firstmsg, mtxmanager, msglvl, msgFile) ; } IV_free(aggCountsIV) ; IP_free(heads[nfront+1]) ; FREE(heads) ; IVfree(nactiveChild) ; Ideq_free(dequeue) ; SubMtxList_free(aggList) ; IVL_free(solveIVL) ; MARKTIME(t2) ; cpus[2] += t2 - t1 ; /* --------------------- do the diagonal solve --------------------- */ MARKTIME(t1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( owners[J] == myid ) { FrontMtx_diagonalVisit(frontmtx, J, owners, myid, p_mtx, frontIsDone, p_mtx, msglvl, msgFile) ; } } MARKTIME(t2) ; cpus[3] += t2 - t1 ; /* ------------------------------------ set up for the backward solve (1) IP lists (2) set up the dequeue (3) set up the aggregate list object (4) nUsed[] vector ------------------------------------ */ /* ---------------------------------------------------------------- set up the working data specific to the forward solve solveIVL -- holds lists of processors that need XJ objects aggCountsIV -- vector of aggregate counts aggList -- object to manage aggregate instances heads[*] -- linked lists for updates local to this processor dequeue -- object to manager bottom-up traversal ---------------------------------------------------------------- */ MARKTIME(t1) ; solveIVL = SolveMap_upperSolveIVL(solvemap, myid, msglvl, msgFile) ; aggCountsIV = SolveMap_upperAggregateIV(solvemap, myid, msglvl, msgFile) ; inAggCounts = IV_entries(aggCountsIV) ; aggList = SubMtxList_new() ; SubMtxList_init(aggList, nfront, inAggCounts, 0, NULL) ; heads = SolveMap_backwardSetup(solvemap, myid, msglvl, msgFile) ; dequeue = FrontMtx_setUpDequeue(frontmtx, owners, myid, status, heads, 'W', 'F', msglvl, msgFile) ; FrontMtx_loadActiveRoots(frontmtx, status, 'W', dequeue) ; CVfill(nfront, recvsPosted, 'N') ; CVfill(nfront, frontIsDone, 'N') ; for ( J = 0 ; J < nfront ; J++ ) { for ( ip = heads[J] ; ip != NULL ; ip = ip->next ) { I = ip->val ; if ( owners[I] != myid ) { nUsed[I]++ ; } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ### setup for backward solve") ; fprintf(msgFile, "\n\n solveIVL ") ; IVL_writeForHumanEye(solveIVL, msgFile) ; fprintf(msgFile, "\n\n aggList ") ; SubMtxList_writeForHumanEye(aggList, msgFile) ; fprintf(msgFile, "\n\n initial dequeue") ; Ideq_writeForHumanEye(dequeue, msgFile) ; fprintf(msgFile, "\n\n forward update lists") ; for ( J = 0 ; J < nfront ; J++ ) { IP *ip ; fprintf(msgFile, "\n %d :", J) ; fflush(msgFile) ; for ( ip = heads[J] ; ip != NULL ; ip = ip->next ) { fprintf(msgFile, " %d", ip->val) ; fflush(msgFile) ; } } } MARKTIME(t2) ; cpus[0] += t2 - t1 ; /* -------------- backward solve -------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n thread %d : starting backward solve", myid) ; fflush(msgFile) ; } MARKTIME(t1) ; firsttag += nfront ; while ( (J = Ideq_removeFromHead(dequeue)) != -1 ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ### backward solve, checking out J = %d, status %c", J, status[J]) ; fflush(msgFile) ; } if ( (nJ = FrontMtx_frontSize(frontmtx, J)) > 0 ) { /* ---------------------------------------------- check for necessary incoming solution matrices ---------------------------------------------- */ releaseHead = checkForSolMessages(frontmtx, nrhs, J, owners, myid, heads, frontIsDone, recvsPosted, p_msg, p_mtx, nUsed, mtxmanager, stats, firsttag, comm, msglvl, msgFile) ; if ( owners[J] == myid ) { /* ------------------------------------- check for incoming aggregate messages ------------------------------------- */ checkForAggMessages(frontmtx, J, nrhs, owners, myid, recvsPosted, inAggCounts, p_msg, mtxmanager, aggList, stats, firsttag, comm, msglvl, msgFile) ; } /* --------------- visit the front --------------- */ FrontMtx_backwardVisit(frontmtx, J, nrhs, owners, myid, mtxmanager, aggList, p_mtx, frontIsDone, heads, p_mtx, status, msglvl, msgFile) ; } else { /* ---------------------------------------- front has no eliminated rows and columns ---------------------------------------- */ status[J] = 'F' ; releaseHead = NULL ; } if ( status[J] == 'F' ) { if ( nJ > 0 ) { /* ------------------------------------------------------------ front J is finished, send any solution or aggregate messages ------------------------------------------------------------ */ firstmsg = sendMessages(J, owners, myid, p_mtx, solveIVL, aggList, mtxmanager, firstmsg, stats, firsttag, comm, msglvl, msgFile) ; } /* --------------------------------- load any children on active paths --------------------------------- */ for ( I = fch[J] ; I != -1 ; I = sib[I] ) { if ( status[I] == 'W' ) { Ideq_insertAtHead(dequeue, I) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n placing %d at head of dequeue", I) ; fflush(msgFile) ; } } } } else { /* ------------------------------------------------- front J is not finished, place on tail of dequeue ------------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n front J is not finished") ; fflush(msgFile) ; } Ideq_insertAtTail(dequeue, J) ; } /* -------------------------------------------- check all posted sends, any message that has been received, recycle its SubMtx object -------------------------------------------- */ firstmsg = checkSentMessages(firstmsg, mtxmanager, msglvl, msgFile) ; /* ---------------------------------------------------------- release all external X_J objects that are no longer needed ---------------------------------------------------------- */ while ( (mtx = releaseHead) != NULL ) { p_mtx[mtx->rowid] = NULL ; releaseHead = mtx->next ; SubMtxManager_releaseObject(mtxmanager, mtx) ; } } while ( firstmsg != NULL ) { /* ------------------------------------------ check all posted sends, any message that has been received, recycle its SubMtx object ------------------------------------------ */ firstmsg = checkSentMessages(firstmsg, mtxmanager, msglvl, msgFile) ; } IV_free(aggCountsIV) ; IP_free(heads[nfront+1]) ; FREE(heads) ; Ideq_free(dequeue) ; SubMtxList_free(aggList) ; IVL_free(solveIVL) ; MARKTIME(t2) ; cpus[4] += t2 - t1 ; /* -------------------------- store the solution entries -------------------------- */ MARKTIME(t1) ; FrontMtx_storeSolution(frontmtx, owners, myid, mtxmanager, p_mtx, mtxX, msglvl, msgFile) ; MARKTIME(t2) ; cpus[1] += t2 - t1 ; /* ------------------------ free the working storage ------------------------ */ FREE(p_mtx) ; FREE(p_msg) ; IVfree(nUsed) ; CVfree(status) ; CVfree(recvsPosted) ; CVfree(frontIsDone) ; MARKTIME(t3) ; cpus[5] = t3 - t0 - cpus[0] - cpus[1] - cpus[2] - cpus[3] - cpus[4] ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- this method is called inside the event loop for the forward and backward solves. (1) it posts and checks for external X_I messages where X_I is needed to update Y_J (2) it returns a pointer to the first SubMtx object in a list of external X_I objects that can be free'd. created -- 98apr02, cca ----------------------------------------------------------- */ static SubMtx * checkForSolMessages ( FrontMtx *frontmtx, int nrhs, int J, int owners[], int myid, IP *heads[], char frontIsDone[], char recvsPosted[], SolveMsg *p_msg[], SubMtx *p_mtx[], int nUsed[], SubMtxManager *mtxmanager, int stats[], int firsttag, MPI_Comm comm, int msglvl, FILE *msgFile ) { SubMtx *firstToRelease, *XI ; int flag, I, nbytes, nI, source, tag ; IP *ip ; SolveMsg *msg ; MPI_Status status ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n inside checkForSolMessages(%d)", J) ; fflush(msgFile) ; } firstToRelease = NULL ; for ( ip = heads[J] ; ip != NULL ; ip = ip->next ) { I = ip->val ; if ( msglvl > 1 ) { fprintf(msgFile, "\n I = %d, source = %d", I, owners[I]) ; fflush(msgFile) ; } if ( (source = owners[I]) != myid ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n nI = %d", FrontMtx_frontSize(frontmtx, I)) ; fflush(msgFile) ; } if ( (nI = FrontMtx_frontSize(frontmtx, I)) == 0 ) { /* ------------------------------------------------- there is no X_I to receive, set local status flag ------------------------------------------------- */ frontIsDone[I] = 'Y' ; } else { if ( msglvl > 1 ) { fprintf(msgFile, "\n recvsPosted[%d] = %c", I, recvsPosted[I]) ; fflush(msgFile) ; } if ( recvsPosted[I] == 'N' ) { /* -------------------- post receive for X_I -------------------- */ msg = SolveMsg_new() ; msg->info[0] = SOLUTION ; msg->info[1] = I ; msg->info[2] = 0 ; nbytes = SubMtx_nbytesNeeded(frontmtx->type, SUBMTX_DENSE_COLUMNS, nI, nrhs, nI*nrhs) ; XI = SubMtxManager_newObjectOfSizeNbytes(mtxmanager, nbytes); SubMtx_init(XI, frontmtx->type, SUBMTX_DENSE_COLUMNS, I, 0, nI, nrhs, nI*nrhs) ; msg->mtx = XI ; msg->base = SubMtx_workspace(XI) ; tag = firsttag + I ; if ( msglvl > 1 ) { fprintf(msgFile, "\n posting solution Irecv," "msg %p, I %d, tag %d, nbytes %d", msg, I, tag, nbytes) ; fflush(msgFile) ; } MPI_Irecv(msg->base, nbytes, MPI_BYTE, source, tag, comm, &msg->req) ; p_msg[I] = msg ; recvsPosted[I] = 'Y' ; stats[4]++ ; stats[6] += nbytes ; if ( msglvl > 1 ) { fprintf(msgFile, "\n post Irecv XI : I %d, source %d, stats[4] %d, stats[6] %d", I, source, stats[4], stats[6]) ; fflush(msgFile) ; } } if ( (msg = p_msg[I]) != NULL ) { /* -------------------------------- check for message containing X_I -------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n testing for X_{%d}", I) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( msglvl > 1 ) { fprintf(msgFile, ", flag = %d", flag) ; fflush(msgFile) ; } if ( flag != 0 ) { source = status.MPI_SOURCE ; tag = status.MPI_TAG ; if ( msglvl > 1 ) { fprintf(msgFile, "\n X_{%d} received from source %d", I, source) ; fflush(msgFile) ; } if ( msg->mtx == NULL ) { fprintf(stderr, "\n proc %d: fatal error in checkForSolMsg, J = %d, I = %d", myid, J, I) ; exit(-1) ; } SubMtx_initFromBuffer(msg->mtx) ; p_msg[I] = NULL ; p_mtx[I] = msg->mtx ; frontIsDone[I] = 'Y' ; FREE(msg) ; } } if ( (XI = p_mtx[I]) != NULL && --nUsed[I] == 0 ) { /* ---------------------------------- we can release X_I after this step ---------------------------------- */ XI->next = firstToRelease ; firstToRelease = XI ; } } } } return(firstToRelease) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- this method is called inside the event loop for the forward and backward solves. it posts and checks for aggregate Y_J^q messages created -- 98apr02, cca ----------------------------------------------------------------- */ static void checkForAggMessages ( FrontMtx *frontmtx, int J, int nrhs, int owners[], int myid, char recvsPosted[], int inAggCounts[], SolveMsg *p_msg[], SubMtxManager *mtxmanager, SubMtxList *aggList, int stats[], int firsttag, MPI_Comm comm, int msglvl, FILE *msgFile ) { SubMtx *YJ ; int count, flag, ii, nbytes, nincoming, nJ, tag ; SolveMsg *msg, *nextmsg ; MPI_Status status ; if ( owners[J] == myid && recvsPosted[J] == 'N' ) { /* --------------------------------------------- post the receives for the incoming aggregates --------------------------------------------- */ if ( (nincoming = inAggCounts[J]) > 0 ) { /* ----------------------- post receives for Y_J^q ----------------------- */ nJ = FrontMtx_frontSize(frontmtx, J) ; for ( ii = 0 ; ii < nincoming ; ii++ ) { nbytes = SubMtx_nbytesNeeded(frontmtx->type, SUBMTX_DENSE_COLUMNS, nJ, nrhs, nJ*nrhs) ; YJ = SubMtxManager_newObjectOfSizeNbytes(mtxmanager, nbytes); SubMtx_init(YJ, frontmtx->type, SUBMTX_DENSE_COLUMNS, J, 0, nJ, nrhs, nJ*nrhs) ; msg = SolveMsg_new() ; msg->info[0] = AGGREGATE ; msg->info[1] = J ; msg->info[2] = nbytes ; msg->base = SubMtx_workspace(YJ) ; msg->mtx = YJ ; tag = firsttag + J ; if ( msglvl > 1 ) { fprintf(msgFile, "\n posting aggregate Irecv," "msg %p, J %d, tag %d, nbytes %d", msg, J, tag, nbytes) ; fflush(msgFile) ; } MPI_Irecv(msg->base, nbytes, MPI_BYTE, MPI_ANY_SOURCE, tag, comm, &msg->req) ; msg->next = p_msg[J] ; p_msg[J] = msg ; stats[5]++ ; stats[7] += nbytes ; if ( msglvl > 1 ) { fprintf(msgFile, "\n post Irecv YJ : J %d, stats[5] %d, stats[7] %d", J, stats[5], stats[7]) ; fflush(msgFile) ; } } } recvsPosted[J] = 'Y' ; } if ( p_msg[J] != NULL ) { /* --------------------------------------- check for unreceived aggregate messages --------------------------------------- */ for ( msg = p_msg[J], p_msg[J] = NULL ; msg != NULL ; msg = nextmsg ) { nextmsg = msg->next ; if ( msglvl > 1 ) { fprintf(msgFile, "\n checking aggregate message %p, J %d", msg, J) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( msglvl > 1 ) { fprintf(msgFile, ", flag = %d", flag) ; fflush(msgFile) ; } if ( flag == 0 ) { /* -------------------------------------- message not received, put back on list -------------------------------------- */ msg->next = p_msg[J] ; p_msg[J] = msg ; } else { /* ------------------------- message received, initialize SubMtx object and put on aggregate list ------------------------- */ if ( msglvl > 1 ) { MPI_Get_count(&status, MPI_BYTE, &count) ; fprintf(msgFile, "\n message received, source %d, tag %d, nbytes %d", status.MPI_SOURCE, status.MPI_TAG, count) ; fflush(msgFile) ; } if ( msg->mtx == NULL ) { fprintf(stderr, "\n proc %d: fatal error in checkForAggMsg, J = %d", myid, J) ; exit(-1) ; } SubMtx_initFromBuffer(msg->mtx) ; SubMtxList_addObjectToList(aggList, msg->mtx, J) ; FREE(msg) ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ this method is called inside the event loop for the forward and backward solves when front J is now complete. if J is owned, then X_J is sent to all processors that need it. (this information is found in the solveIVL object.) otherwise, Y_J^q exists in the aggregate list object. Y_J^q is removed and sent to the owner of J. return value -- any new messages are prepended onto the list of sent messages and the head of the list is returned. created -- 98apr02, cca ------------------------------------------------------------------- */ static SolveMsg * sendMessages ( int J, int owners[], int myid, SubMtx *p_mtx[] , IVL *solveIVL, SubMtxList *aggList, SubMtxManager *mtxmanager, SolveMsg *firstmsg, int stats[], int firsttag, MPI_Comm comm, int msglvl, FILE *msgFile ) { SubMtx *mtx, *XJ, *YJ ; int dest, ii, mproc, nbytes, tag ; int *procids ; SolveMsg *msg ; void *work, *XJbuff ; if ( (dest = owners[J]) == myid ) { /* --------------------------------------- send X_J to all processors that need it --------------------------------------- */ IVL_listAndSize(solveIVL, J, &mproc, &procids) ; if ( mproc > 0 ) { XJ = p_mtx[J] ; if ( XJ == NULL ) { fprintf(stderr, "\n proc %d: error in sendMessages, J = %d, XJ is NULL", myid, J) ; exit(-1) ; } nbytes = SubMtx_nbytesInUse(XJ) ; XJbuff = SubMtx_workspace(XJ) ; tag = firsttag + J ; for ( ii = 0 ; ii < mproc ; ii++ ) { dest = procids[ii] ; mtx = SubMtxManager_newObjectOfSizeNbytes(mtxmanager, nbytes) ; work = SubMtx_workspace(mtx) ; memcpy(work, XJbuff, nbytes) ; msg = SolveMsg_new() ; msg->info[0] = SOLUTION ; msg->info[1] = J ; msg->info[2] = nbytes ; msg->base = work ; msg->mtx = mtx ; msg->next = firstmsg ; firstmsg = msg ; if ( msglvl > 1 ) { fprintf(msgFile, "\n posting X_J Isend, " "msg %p, J %d, dest %d, tag %d, nbytes %d", msg, J, dest, tag, nbytes) ; fflush(msgFile) ; } MPI_Isend(msg->base, nbytes, MPI_BYTE, dest, tag, comm, &msg->req) ; stats[0]++, stats[2] += nbytes ; if ( msglvl > 1 ) { fprintf(msgFile, "\n post Isend XJ : J %d, dest %d, stats[0] %d, stats[2] %d", J, dest, stats[0], stats[2]) ; fflush(msgFile) ; } } } } else { /* -------------------------- send Y_J^myid to the owner -------------------------- */ YJ = SubMtxList_getList(aggList, J) ; /* if ( YJ == NULL ) { fprintf(stderr, "\n proc %d: error in sendMessages, J = %d, YJ is NULL", myid, J) ; exit(-1) ; } */ if ( YJ != NULL ) { msg = SolveMsg_new() ; msg->info[0] = AGGREGATE ; msg->info[1] = J ; msg->info[2] = nbytes = SubMtx_nbytesInUse(YJ) ; msg->mtx = YJ ; msg->base = SubMtx_workspace(YJ) ; msg->next = firstmsg ; tag = firsttag + J ; firstmsg = msg ; if ( msglvl > 1 ) { fprintf(msgFile, "\n posting Y_J^%d Isend, " "msg %p, J %d, dest %d, tag %d, nbytes %d", myid, msg, J, dest, tag, nbytes) ; fflush(msgFile) ; } MPI_Isend(msg->base, nbytes, MPI_BYTE, dest, tag, comm, &msg->req) ; p_mtx[J] = NULL ; stats[1]++, stats[3] += nbytes ; if ( msglvl > 1 ) { fprintf(msgFile, "\n post Isend YJ : J %d, dest %d, stats[1] %d, stats[3] %d", J, dest, stats[1], stats[3]) ; fflush(msgFile) ; } } } return(firstmsg) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- this method is called inside the event loop for the forward and backward solves when front J is now complete. it checks the list of sent messages. any messages that have been received have their SubMtx object given back to the manager and their SolveMsg object free'd. return value -- head of list of unreceived messages created -- 98apr02, cca ----------------------------------------------------------------- */ static SolveMsg * checkSentMessages ( SolveMsg *firstmsg, SubMtxManager *mtxmanager, int msglvl, FILE *msgFile ) { int flag ; MPI_Status status ; SolveMsg *msg, *nextmsg ; for ( msg = firstmsg, firstmsg = NULL ; msg != NULL ; msg = nextmsg ) { nextmsg = msg->next ; if ( msglvl > 1 ) { fprintf(msgFile, "\n checking sent message %p : type %d, front %d, nbytes %d", msg, msg->info[0], msg->info[1], msg->info[2]) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( msglvl > 1 ) { fprintf(msgFile, ", flag = %d", flag) ; fflush(msgFile) ; } if ( flag == 1 ) { if ( msg->mtx == NULL ) { fprintf(msgFile, "\n WHOA!, msg = %p, msg->mtx = NULL", msg) ; fflush(msgFile) ; } else { SubMtxManager_releaseObject(mtxmanager, msg->mtx) ; } FREE(msg) ; } else { msg->next = firstmsg ; firstmsg = msg ; } } return(firstmsg) ; } /*--------------------------------------------------------------------*/ static SolveMsg * SolveMsg_new ( void ) { SolveMsg *msg ; ALLOCATE(msg, struct _SolveMsg, 1) ; msg->info[0] = 0 ; msg->info[1] = 0 ; msg->info[2] = 0 ; msg->base = NULL ; msg->next = NULL ; msg->mtx = NULL ; return(msg) ; } /*--------------------------------------------------------------------*/ created -- 98apr02, cca ----------------------------------------------------------------- */ static void checkForAggMessages ( FrontMtx *frontmtx, int J, int nrhs, int MPI/src/splitDenseMtx.c010064400020550007177000000731150663402262400162670ustar00clevecompmath00000400000006/* split.c */ #include "../spoolesMPI.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- to split a DenseMtx object by rows mtx -- DenseMtx object rowmapIV -- map from rows to owning processes firsttag -- first tag to be used in these messages stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- message level msgFile -- message file comm -- MPI communicator return value -- a new DenseMtx object filled with the owned rows created -- 98may16, cca modified -- 98sep26, cca mtx is not modified ----------------------------------------------------------------- */ DenseMtx * DenseMtx_MPI_splitByRows ( DenseMtx *mtx, IV *rowmapIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { DenseMtx *inmtx, *keepmtx, *outmtx ; double *inbuffer, *outbuffer ; int destination, ii, inbuffersize, incount, iproc, irow, lasttag, left, myid, ncol, ndouble, neqns, nkeep, nmoved, nowned, nproc, nrecv, nrow, nsend, tagbound, offset, outbuffersize, outcount, right, source, tag, type ; int *head, *link, *rowind, *rowmap, *rowsToRecv, *rowsToSend ; MPI_Status status ; /* ------------------------------------------------- get id of self, # of processes and # of equations ------------------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; /*--------------------------------------------------------------------*/ { int rc = 1 ; int *rcs = IVinit(nproc, -1) ; /* -------------- check the data -------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_splitByRows()" "\n mtx is NULL\n") ; rc = -1 ; } if ( rowmapIV == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_splitByRows()" "\n rowmapIV is NULL\n") ; rc = -2 ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_splitByRows()" "\n msglvl > 0 and msgFile is NULL\n") ; rc = -3 ; } if ( firsttag < 0 ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_splitByRows()" "\n firsttag = %d\n", firsttag) ; rc = -4 ; } lasttag = firsttag + nproc ; if ( lasttag > (tagbound = maxTagMPI(comm)) ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_splitByRows()" "\n lasttag = %d, tag_bound = %d", lasttag, tagbound) ; rc = -5 ; } MPI_Allgather((void *) &rc, 1, MPI_INT, (void *) rcs, 1, MPI_INT, comm) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( rcs[iproc] != 1 ) { if ( msgFile != NULL ) { fprintf(msgFile, "\n fatal error in DenseMtx_MPI_splitByRows()" "\n trouble with return code") ; IVfprintf(msgFile, nproc, rcs) ; MPI_Finalize() ; exit(rc) ; } } } IVfree(rcs) ; } /*--------------------------------------------------------------------*/ /* ----------------------- get type and dimensions ----------------------- */ type = mtx->type ; IV_sizeAndEntries(rowmapIV, &neqns, &rowmap) ; DenseMtx_dimensions(mtx, &nrow, &ncol) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside DenseMtx_MPI_splitByRows" "\n nproc = %d, myid = %d, neqns = %d, nrow = %d, ncol = %d", nproc, myid, neqns, nrow, ncol) ; fflush(msgFile) ; } /* ------------------------------------------------------- communicate the type's and ncol's to all the processors ------------------------------------------------------- */ { int *ivec = IVinit(nproc, -1) ; MPI_Allgather((void *) &type, 1, MPI_INT, (void *) ivec, 1, MPI_INT, comm) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( ivec[iproc] != type ) { if ( msgFile != NULL ) { fprintf(msgFile, "\n fatal error in DenseMtx_MPI_splitByRows()" "\n trouble with types") ; IVfprintf(msgFile, nproc, ivec) ; MPI_Finalize() ; exit(-1) ; } } } MPI_Allgather((void *) &ncol, 1, MPI_INT, (void *) ivec, 1, MPI_INT, comm) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( ivec[iproc] != ncol ) { if ( msgFile != NULL ) { fprintf(msgFile, "\n fatal error in DenseMtx_MPI_splitByRows()" "\n trouble with ncols") ; IVfprintf(msgFile, nproc, ivec) ; MPI_Finalize() ; exit(-1) ; } } } IVfree(ivec) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- get the counts of the entries to send to the other processors ------------------------------------------------------------- */ DenseMtx_rowIndices(mtx, &nrow, &rowind) ; rowsToSend = IVinit(2*nproc, 0) ; rowsToRecv = rowsToSend + nproc ; head = IVinit(nproc, -1) ; link = IVinit(nrow, -1) ; for ( ii = 0, nkeep = 0 ; ii < nrow ; ii++ ) { irow = rowind[ii] ; iproc = rowmap[irow] ; link[ii] = head[iproc] ; head[iproc] = ii ; if ( iproc != myid ) { rowsToSend[iproc]++ ; } else { nkeep++ ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n nkeep = %d, row send counts ", nkeep) ; IVfprintf(msgFile, nproc, rowsToSend) ; fflush(msgFile) ; } /* ------------------------------- do an all-to-all gather/scatter ------------------------------- */ MPI_Alltoall((void *) rowsToSend, 1, MPI_INT, (void *) rowsToRecv, 1, MPI_INT, comm) ; nowned = nkeep + IVsum(nproc, rowsToRecv) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n nkeep = %d, row receive counts ", nkeep) ; IVfprintf(msgFile, nproc, rowsToRecv) ; fflush(msgFile) ; } /* ------------------------- determine the buffer size ------------------------- */ nsend = IVmax(nproc, rowsToSend, &iproc) ; nrecv = IVmax(nproc, rowsToRecv, &iproc) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n nsend = %d, nrecv = %d", nsend, nrecv) ; fflush(msgFile) ; } /* ------------------------------------------- allocate the send/receive DenseMtx objects ------------------------------------------- */ if ( nsend > 0 ) { outmtx = DenseMtx_new() ; if ( mtx->inc1 == 1 ) { DenseMtx_init(outmtx, type, myid, -1, nsend, ncol, 1, nsend) ; } else { DenseMtx_init(outmtx, type, myid, -1, nsend, ncol, ncol, 1) ; } } else { outmtx = NULL ; } if ( nrecv > 0 ) { inmtx = DenseMtx_new() ; if ( mtx->inc1 == 1 ) { DenseMtx_init(inmtx, type, myid, -1, nrecv, ncol, 1, nrecv) ; } else { DenseMtx_init(inmtx, type, myid, -1, nrecv, ncol, ncol, 1) ; } } else { inmtx = NULL ; } /* ------------------------------------- allocate the DenseMtx object to keep ------------------------------------- */ keepmtx = DenseMtx_new() ; if ( mtx->inc1 == 1 ) { DenseMtx_init(keepmtx, type, myid, -1, nowned, ncol, 1, nowned) ; } else { DenseMtx_init(keepmtx, type, myid, -1, nowned, ncol, ncol, 1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n keepmtx object allocated") ; fflush(msgFile) ; } /* ---------------------------------------------------------------- copy all rows to keep from the input matrix into the keep matrix ---------------------------------------------------------------- */ for ( ii = head[myid], nmoved = 0 ; ii != -1 ; ii = link[ii] ) { DenseMtx_copyRowAndIndex(keepmtx, nmoved, mtx, ii) ; nmoved++ ; } if ( nmoved > 0 ) { /* if ( msglvl > 3 ) { fprintf(msgFile, "\n\n keepmtx") ; DenseMtx_writeForHumanEye(keepmtx, msgFile) ; fflush(msgFile) ; } */ } /* -------------------------------------------------------------- loop over the processes, gather their values and send them off -------------------------------------------------------------- */ for ( offset = 1, tag = firsttag ; offset < nproc ; offset++, tag++ ) { right = (myid + offset) % nproc ; left = (nproc + myid - offset) % nproc ; outcount = rowsToSend[right] ; incount = rowsToRecv[left] ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ### process %d, send %d to right %d, recv %d from left %d", myid, outcount, right, incount, left) ; fflush(msgFile) ; } if ( outcount > 0 ) { /* -------------------------- load the out matrix object -------------------------- */ if ( mtx->inc1 == 1 ) { DenseMtx_init(outmtx, type, myid, -1, outcount, ncol, 1, outcount) ; } else { DenseMtx_init(outmtx, type, myid, -1, outcount, ncol, ncol, 1) ; } for ( ii = head[right], nmoved = 0 ; ii != -1 ; ii = link[ii] ) { DenseMtx_copyRowAndIndex(outmtx, nmoved, mtx, ii) ; nmoved++ ; } destination = right ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n outmtx for process %d", destination) ; DenseMtx_writeForHumanEye(outmtx, msgFile) ; fflush(msgFile) ; } stats[0]++ ; stats[2] += sizeof(double)*DV_size(&outmtx->wrkDV) ; } else { /* ------------------------------------------ set the destination to be the NULL process ------------------------------------------ */ destination = MPI_PROC_NULL ; } if ( incount > 0 ) { /* ---------------------------------- initialize the input matrix object ---------------------------------- */ if ( mtx->inc1 == 1 ) { DenseMtx_init(inmtx, type, myid, -1, incount, ncol, 1, incount) ; } else { DenseMtx_init(inmtx, type, myid, -1, incount, ncol, ncol, 1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inmtx initialized to have %d rows", incount) ; fflush(msgFile) ; } source = left ; stats[1]++ ; stats[3] += sizeof(double)*DV_size(&inmtx->wrkDV) ; } else { source = MPI_PROC_NULL ; } /* ----------------- do a send/receive ----------------- */ inbuffersize = outbuffersize = 0 ; inbuffer = outbuffer = NULL ; if ( outmtx != NULL ) { outbuffersize = DV_size(&outmtx->wrkDV) ; outbuffer = DV_entries(&outmtx->wrkDV) ; } if ( inmtx != NULL ) { inbuffersize = DV_size(&inmtx->wrkDV) ; inbuffer = DV_entries(&inmtx->wrkDV) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n inbuffersize = %d, inbuffer = %p" "\n outbuffersize = %d, outbuffer = %p", inbuffersize, inbuffer, outbuffersize, outbuffer) ; fflush(msgFile) ; } MPI_Sendrecv((void*) outbuffer, outbuffersize, MPI_DOUBLE, destination, tag, (void*) inbuffer, inbuffersize, MPI_DOUBLE, source, tag, comm, &status) ; if ( msglvl > 2 ) { MPI_Get_count(&status, MPI_DOUBLE, &ndouble) ; fprintf(msgFile, "\n\n message received, source %d, tag %d, double count %d", status.MPI_SOURCE, status.MPI_TAG, ndouble) ; fprintf(msgFile, "\n MPI_ERROR = %d", status.MPI_ERROR) ; fflush(msgFile) ; } if ( source != MPI_PROC_NULL ) { /* ------------------------------------- initialize the object from its buffer ------------------------------------- */ DenseMtx_initFromBuffer(inmtx) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n DenseMtx object intialized from its buffer") ; fflush(msgFile) ; } if ( msglvl > 4 ) { DenseMtx_writeForHumanEye(inmtx, msgFile) ; fflush(msgFile) ; } } if ( incount > 0 ) { if ( nkeep + incount > nowned ) { fprintf(msgFile, "\n fatal error in DenseMtx_splitByRows()" "\n nkeep = %d, nrecv = %d, nowned = %d", nkeep, nrecv, nowned) ; exit(-1) ; } for ( irow = 0 ; irow < incount ; irow++, nkeep++ ) { DenseMtx_copyRowAndIndex(keepmtx, nkeep, inmtx, irow) ; } } } /* ------------------------- sort the rows and columns ------------------------- */ DenseMtx_sort(keepmtx) ; /* ------------------------------------------------------ check that the matrix contains only the rows it should ------------------------------------------------------ */ nrow = keepmtx->nrow ; rowind = keepmtx->rowind ; for ( ii = 0 ; ii < nrow ; ii++ ) { irow = rowind[ii] ; if ( irow < 0 || irow >= neqns ) { fprintf(stderr, "\n process %d : local row %d, global row %d, neqns = %d\n", myid, ii, irow, neqns) ; exit(-1) ; } if ( rowmap[irow] != myid ) { fprintf(stderr, "\n process %d : local row %d, global row %d, map = %d\n", myid, ii, irow, rowmap[irow]) ; exit(-1) ; } } /* ------------------------ free the working storage ------------------------ */ if ( outmtx != NULL ) { DenseMtx_free(outmtx) ; } if ( inmtx != NULL ) { DenseMtx_free(inmtx) ; } IVfree(rowsToSend) ; IVfree(head) ; IVfree(link) ; return(keepmtx) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- to scatter a DenseMtx object by rows Xglobal -- global DenseMtx object, significant only for root Xlocal -- local DenseMtx object, if NULL on input, will be created if necessary rowmapIV -- map from rows to owning processes firsttag -- first tag to be used in these messages stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- message level msgFile -- message file comm -- MPI communicator return value -- Xlocal, a local DenseMtx object created -- 98may16, cca modified -- 98sep26, cca mtx is not modified ----------------------------------------------------------------- */ DenseMtx * DenseMtx_MPI_splitFromGlobalByRows ( DenseMtx *Xglobal, DenseMtx *Xlocal, IV *rowmapIV, int root, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { DenseMtx *tempmtx ; double *buffer ; int ii, iproc, irow, maxnrow, myid, ncolX, nkeep, nproc, nrowloc, nrowmap, nrowX, nsend, size, type ; int *counts, *head, *link, *rowind, *rowmap ; MPI_Status status ; /* ------------------------------------------------- get id of self, # of processes and # of equations ------------------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; if ( root < 0 || root >= nproc ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_splitByRows()" "\n root = %d, nproc = %d\n", root, nproc) ; MPI_Finalize() ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* -------------- check the data -------------- */ { int rc = 1 ; int *rcs = IVinit(nproc, -1) ; if ( myid == root ) { if ( Xglobal == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_splitFromGlobalByRows()" "\n Xglobal is NULL\n") ; rc = -1 ; } if ( rowmapIV == NULL ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_splitFromGlobalByRows()" "\n rowmapIV is NULL\n") ; rc = -2 ; } } if ( msglvl > 0 && msgFile == NULL ) { fprintf(msgFile, "\n fatal error in DenseMtx_MPI_splitFromGlobalByRows()" "\n msglvl > 0 and msgFile = NULL\n") ; rc = -3 ; } if ( firsttag < 0 ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_splitFromGlobalByRows()" "\n firsttag = %d\n", firsttag) ; rc = -4 ; } MPI_Allgather((void *) &rc, 1, MPI_INT, (void *) rcs, 1, MPI_INT, comm) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( rcs[iproc] != 1 ) { if ( msgFile != NULL ) { fprintf(msgFile, "\n fatal error in DenseMtx_MPI_splitFromGlobalByRows()" "\n trouble with return code") ; IVfprintf(msgFile, nproc, rcs) ; MPI_Finalize() ; exit(rc) ; } } } IVfree(rcs) ; } /*--------------------------------------------------------------------*/ if ( myid == root ) { type = Xglobal->type ; IV_sizeAndEntries(rowmapIV, &nrowmap, &rowmap) ; DenseMtx_dimensions(Xglobal, &nrowX, &ncolX) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside DenseMtx_MPI_splitFromGlobalByRows" "\n nproc = %d, myid = %d, nrowmap = %d, nrowX = %d, ncolX = %d", nproc, myid, nrowmap, nrowX, ncolX) ; fflush(msgFile) ; } } /* ---------------------------------------- broadcast the type of entries and number of right hand sides to all processors ---------------------------------------- */ MPI_Bcast((void *) &type, 1, MPI_INT, root, comm) ; MPI_Bcast((void *) &ncolX, 1, MPI_INT, root, comm) ; stats[0] += 2 ; stats[1] += 2 ; stats[2] += 2*sizeof(int) ; stats[3] += 2*sizeof(int) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside DenseMtx_MPI_splitFromGlobalByRows" "\n type %d, ncolX %d", type, ncolX) ; fflush(msgFile) ; } if ( myid == root ) { /* ------------------------------------------------ create a head/link structure for the matrix rows ------------------------------------------------ */ DenseMtx_rowIndices(Xglobal, &nrowX, &rowind) ; counts = IVinit(nproc, 0) ; head = IVinit(nproc, -1) ; link = IVinit(nrowX, -1) ; for ( ii = nrowX - 1 ; ii >= 0 ; ii-- ) { irow = rowind[ii] ; iproc = rowmap[irow] ; link[ii] = head[iproc] ; head[iproc] = ii ; counts[iproc]++ ; } } else { counts = NULL ; } /* ------------------------------------------------- communicate the number of rows for each processor ------------------------------------------------- */ MPI_Scatter((void *) counts, 1, MPI_INT, (void *) &nrowloc, 1, MPI_INT, root, comm) ; stats[0] += 1 ; stats[1] += 1 ; stats[2] += (nproc-1)*sizeof(int) ; stats[3] += (nproc-1)*sizeof(int) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n nrowloc = %d", nrowloc) ; fflush(msgFile) ; } /* ----------------------------------------------------------- if necessary, create the local Xloc matrix, then initialize ----------------------------------------------------------- */ if ( Xlocal == NULL ) { Xlocal = DenseMtx_new() ; } DenseMtx_init(Xlocal, type, -1, -1, nrowloc, ncolX, 1, nrowloc) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Xlocal after initialization") ; DenseMtx_writeForHumanEye(Xlocal, msgFile) ; fflush(msgFile) ; } if ( myid == root ) { /* --------------------------------- load local matrix with owned rows --------------------------------- */ if ( nrowloc > 0 ) { int iglob, iloc = 0 ; for ( iglob = head[root] ; iglob != -1 ; iglob = link[iglob] ) { DenseMtx_copyRowAndIndex(Xlocal, iloc, Xglobal, iglob) ; iloc++ ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Xlocal on root") ; DenseMtx_writeForHumanEye(Xlocal, msgFile) ; fflush(msgFile) ; } } /* ----------------------------------------------------- create a temporary matrix to send to other processors ----------------------------------------------------- */ counts[myid] = 0 ; maxnrow = IVmax(nproc, counts, &iproc) ; if ( maxnrow > 0 ) { DenseMtx *tempmtx = DenseMtx_new() ; DenseMtx_init(tempmtx, type, -1, -1, maxnrow, ncolX, 1, maxnrow) ; /* ---------------------------------- loop over the processors collect owned rows into tempmtx send tempmtx to processor ---------------------------------- */ for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( iproc != root && (nrowloc = counts[iproc]) > 0 ) { DenseMtx_init(tempmtx, type, -1, -1, nrowloc, ncolX, 1, nrowloc) ; nsend = 0 ; for ( ii = head[iproc] ; ii != -1 ; ii = link[ii] ) { DenseMtx_copyRowAndIndex(tempmtx, nsend, Xglobal, ii) ; nsend++ ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n tempmtx for proc %d", iproc) ; DenseMtx_writeForHumanEye(tempmtx, msgFile) ; fflush(msgFile) ; } size = DV_size(&tempmtx->wrkDV) ; buffer = DV_entries(&tempmtx->wrkDV) ; MPI_Send((void *) buffer, size, MPI_DOUBLE, iproc, firsttag, comm) ; stats[0] += 1 ; stats[2] += size*sizeof(double) ; } } DenseMtx_free(tempmtx) ; } /* ------------------------ free the working storage ------------------------ */ IVfree(head) ; IVfree(link) ; IVfree(counts) ; } else { /* ------------------ non-root processor ------------------ */ if ( nrowloc > 0 ) { size = DV_size(&Xlocal->wrkDV) ; buffer = DV_entries(&Xlocal->wrkDV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n size = %d, buffer = %p", size, buffer) ; fflush(msgFile) ; } MPI_Recv((void *) buffer, size, MPI_DOUBLE, root, firsttag, comm, &status); stats[1] += 1 ; stats[3] += size*sizeof(double) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Xlocal rec'd from root %d", root) ; fflush(msgFile) ; } DenseMtx_initFromBuffer(Xlocal) ; if ( msglvl > 2 ) { DenseMtx_writeForHumanEye(Xlocal, msgFile) ; fflush(msgFile) ; } } else { Xlocal = NULL ; } } if ( msglvl > 3 ) { if ( Xlocal != NULL ) { fprintf(msgFile, "\n\n Xlocal") ; DenseMtx_writeForHumanEye(Xlocal, msgFile) ; } else { fprintf(msgFile, "\n\n Xlocal is NULL") ; } fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n leaving DenseMtx_splitFromGlobalByRows()") ; fflush(msgFile) ; } return(Xlocal) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- to merge a DenseMtx object by rows Xlocal -- DenseMtx object, can be NULL Xglobal -- DenseMtx object, can be NULL significant only for root firsttag -- first tag to be used in these messages stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- message level msgFile -- message file comm -- MPI communicator return value -- if processor is root Xglobal is returned, if was NULL on input, it is created else NULL endif Xlocal is not modified created -- 98sep27, cca ----------------------------------------------------------------- */ DenseMtx * DenseMtx_MPI_mergeToGlobalByRows ( DenseMtx *Xglobal, DenseMtx *Xlocal, int root, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { double *buffer ; int iproc, maxnrow, myid, ncolX, nproc, nrowXloc, size, type ; int *incounts ; /* ------------------------------------------------- get id of self, # of processes and # of equations ------------------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; if ( root < 0 || root >= nproc ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_splitByRows()" "\n root = %d, nproc = %d\n", root, nproc) ; MPI_Finalize() ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* -------------- check the data -------------- */ { int rc = 1 ; int *ivec = IVinit(nproc, -1) ; if ( msglvl > 0 && msgFile == NULL ) { fprintf(msgFile, "\n fatal error in DenseMtx_MPI_mergeToGlobalByRows()" "\n msglvl > 0 and msgFile = NULL\n") ; rc = -2 ; } if ( firsttag < 0 ) { fprintf(stderr, "\n fatal error in DenseMtx_MPI_mergeToGlobalByRows()" "\n firsttag = %d\n", firsttag) ; rc = -3 ; } MPI_Allgather((void *) &rc, 1, MPI_INT, (void *) ivec, 1, MPI_INT, comm) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( ivec[iproc] != 1 ) { if ( msgFile != NULL ) { fprintf(msgFile, "\n fatal error in DenseMtx_MPI_mergeToGlobalByRows()" "\n trouble with return code") ; IVfprintf(msgFile, nproc, ivec) ; MPI_Finalize() ; exit(rc) ; } } } /* ------------------------------ check the type of the matrices ------------------------------ */ type = (Xlocal != NULL) ? Xlocal->type : -1 ; MPI_Allgather((void *) &type, 1, MPI_INT, (void *) ivec, 1, MPI_INT, comm) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( ivec[iproc] != -1 ) { if ( type == -1 ) { type = ivec[iproc] ; } else if ( type != ivec[iproc] ) { if ( msgFile != NULL ) { fprintf(msgFile, "\n fatal error in DenseMtx_MPI_mergeToGlobalByRows()" "\n trouble with types\n") ; IVfprintf(msgFile, nproc, ivec) ; MPI_Finalize() ; exit(-1) ; } } } } /* -------------------------------------- check the # of columns of the matrices -------------------------------------- */ ncolX = (Xlocal != NULL) ? Xlocal->ncol : 0 ; MPI_Allgather((void *) &ncolX, 1, MPI_INT, (void *) ivec, 1, MPI_INT, comm) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( ivec[iproc] != 0 ) { if ( ncolX == 0 ) { ncolX = ivec[iproc] ; } else if ( ncolX != ivec[iproc] ) { if ( msgFile != NULL ) { fprintf(msgFile, "\n fatal error in DenseMtx_MPI_mergeToGlobalByRows()" "\n trouble with ncolX\n") ; IVfprintf(msgFile, nproc, ivec) ; MPI_Finalize() ; exit(-1) ; } } } } IVfree(ivec) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ gather the number of incoming rows onto processor root ------------------------------------------------------ */ nrowXloc = (Xlocal != NULL) ? Xlocal->nrow : 0 ; if ( myid == root ) { incounts = IVinit(nproc, 0) ; } else { incounts = NULL ; } MPI_Gather(&nrowXloc, 1, MPI_INT, (void *) incounts, 1, MPI_INT, root, comm) ; if ( myid == root ) { DenseMtx *tempmtx ; int count, iglob, iloc, incount, nrowXglobal ; MPI_Status status ; /* ---------------------------------------------------------- if necessary, create the global matrix, then initialize it ---------------------------------------------------------- */ nrowXglobal = IVsum(nproc, incounts) ; if ( Xglobal == NULL ) { Xglobal = DenseMtx_new() ; } DenseMtx_init(Xglobal, type, -1, -1, nrowXglobal, ncolX, 1, nrowXglobal) ; /* --------------------------------- load local matrix with owned rows --------------------------------- */ for ( iloc = iglob = 0 ; iloc < nrowXloc ; iloc++, iglob++ ) { DenseMtx_copyRowAndIndex(Xglobal, iglob, Xlocal, iloc) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after loading Xlocal on root") ; DenseMtx_writeForHumanEye(Xglobal, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------------------------- create a temporary matrix to receive from other processors ---------------------------------------------------------- */ incounts[root] = 0 ; maxnrow = IVmax(nproc, incounts, &iproc) ; tempmtx = DenseMtx_new() ; DenseMtx_init(tempmtx, type, -1, -1, maxnrow, ncolX, 1, maxnrow) ; size = DV_size(&tempmtx->wrkDV) ; buffer = DV_entries(&tempmtx->wrkDV) ; /* ---------------------------- loop over the processors receive rows into tempmtx ---------------------------- */ for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( iproc != root && (incount = incounts[iproc]) > 0 ) { MPI_Recv((void *) buffer, size, MPI_DOUBLE, iproc, firsttag, comm, &status) ; MPI_Get_count(&status, MPI_DOUBLE, &count) ; stats[1] += 1 ; stats[3] += count*sizeof(double) ; DenseMtx_initFromBuffer(tempmtx) ; for ( iloc = 0 ; iloc < incount ; iloc++, iglob++ ) { DenseMtx_copyRowAndIndex(Xglobal, iglob, tempmtx, iloc) ; } } } /* ------------------------ free the working storage ------------------------ */ IVfree(incounts) ; DenseMtx_free(tempmtx) ; } else { /* ------------------ non-root processor ------------------ */ if ( nrowXloc > 0 ) { size = DV_size(&Xlocal->wrkDV) ; buffer = DV_entries(&Xlocal->wrkDV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n size = %d, buffer = %p", size, buffer) ; fflush(msgFile) ; } MPI_Send((void *) buffer, size, MPI_DOUBLE, root, firsttag, comm) ; stats[0] += 1 ; stats[2] += size*sizeof(double) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Xlocal sent to root %d", root) ; fflush(msgFile) ; } } Xglobal = NULL ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n leaving DenseMtx_mergeToGlobalByRows()") ; fflush(msgFile) ; } return(Xglobal) ; } /*--------------------------------------------------------------------*/ init(tempmtx, type, -1, -1, maxnrow, ncolX, 1, maxnrow) ; /* ---------------------------------- loop over the processors collect owned rows into tempmtx send tempmtx to processor ---------------------------------- */ for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( iproc != root && (nrowloc = counts[iproc]) > 0 ) { DenseMtx_init(tempmtx, type, -1, -1, MPI/src/splitFrontMtx.c010064000020550007177000000421400664716360300163160ustar00clevecompmath00000400000006/* splitFrontMtx.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ typedef struct _msg Msg ; struct _msg { int rowid ; int colid ; int nbytes ; SubMtx *mtx ; MPI_Request req ; Msg *next ; } ; static void split ( FrontMtx *frontmtx, SolveMap *solvemap, char cflag, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- after the factorization has been computed and the front matrices have been split into submatrices, and after a solve map object has been computed, the submatrices are sent to the process that owns them. frontmtx -- stores the factor matrix solvemap -- stores the map from submatrices to processes created -- 98may21, cca ------------------------------------------------------------- */ void FrontMtx_MPI_split ( FrontMtx *frontmtx, SolveMap *solvemap, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { /* -------------- check the data -------------- */ if ( frontmtx == NULL || solvemap == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(msgFile, "\n fatal error in FrontMtx_MPI_split()" "\n frontmtx %p, solvemap %p, firsttag %d" "\n stats %p, msglvl %d, msgFile %p" "\n bad input\n", frontmtx, solvemap, firsttag, stats, msglvl, msgFile) ; exit(-1) ; } split(frontmtx, solvemap, 'U', stats, msglvl, msgFile, firsttag, comm) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { split(frontmtx, solvemap, 'L', stats, msglvl, msgFile, firsttag, comm) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- after the factorization has been computed and the front matrices have been split into submatrices, and after a solve map object has been computed, the submatrices are sent to the process that owns them. frontmtx -- stores the factor matrix solvemap -- stores the map from submatrices to processes cflag -- 'U' --> split the upper matrix 'L' --> split the lower matrix created -- 98may21, cca ------------------------------------------------------------- */ static void split ( FrontMtx *frontmtx, SolveMap *solvemap, char cflag, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { SubMtx *mtx ; SubMtxManager *mtxmanager ; int colid, count, destination, flag, incount, iproc, J, JK, kk, K, left, maxcount, myid, nblock, nbytes, nproc, offset, outcount, right, rowid, source, tag ; int *colids, *inbuff, *incounts, *map, *offsets, *owners, *outbuff, *outcounts, *rowids ; int **p_inbuff, **p_outbuff ; I2Ohash *hash ; Msg *messages, *msg, *nextmsg, *recvhead, *sendhead ; MPI_Status status ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ##### inside FrontMtx_MPI_split()") ; fflush(msgFile) ; } /* -------------- check the data -------------- */ if ( frontmtx == NULL || solvemap == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(msgFile, "\n fatal error in FrontMtx_MPI_split()" "\n frontmtx %p, solvemap %p, firsttag %d" "\n stats %p, msglvl %d, msgFile %p" "\n bad input\n", frontmtx, solvemap, firsttag, stats, msglvl, msgFile) ; exit(-1) ; } /* --------------------------------- get id of self and # of processes --------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; mtxmanager = frontmtx->manager ; if ( cflag == 'U' ) { hash = frontmtx->upperhash ; } else { hash = frontmtx->lowerhash ; } if ( cflag == 'U' ) { nblock = SolveMap_nblockUpper(solvemap) ; owners = SolveMap_owners(solvemap) ; rowids = SolveMap_rowidsUpper(solvemap) ; colids = SolveMap_colidsUpper(solvemap) ; map = SolveMap_mapUpper(solvemap) ; } else if ( frontmtx->pivotingflag != 0 ) { nblock = SolveMap_nblockLower(solvemap) ; owners = SolveMap_owners(solvemap) ; rowids = SolveMap_rowidsLower(solvemap) ; colids = SolveMap_colidsLower(solvemap) ; map = SolveMap_mapLower(solvemap) ; } else { nblock = SolveMap_nblockUpper(solvemap) ; owners = SolveMap_owners(solvemap) ; colids = SolveMap_rowidsUpper(solvemap) ; rowids = SolveMap_colidsUpper(solvemap) ; map = SolveMap_mapUpper(solvemap) ; } /* ------------------------------------------------ step 1: compute the number of submatrices this process will send to every other process ------------------------------------------------ */ incounts = IVinit(nproc, 0) ; outcounts = IVinit(nproc, 0) ; if ( cflag == 'U' ) { for ( JK = 0 ; JK < nblock ; JK++ ) { J = rowids[JK] ; K = colids[JK] ; if ( owners[J] == myid && (iproc = map[JK]) != myid && (mtx = FrontMtx_upperMtx(frontmtx, J, K)) != NULL ) { outcounts[iproc]++ ; } } } else { for ( JK = 0 ; JK < nblock ; JK++ ) { K = rowids[JK] ; J = colids[JK] ; if ( owners[J] == myid && (iproc = map[JK]) != myid && (mtx = FrontMtx_lowerMtx(frontmtx, K, J)) != NULL ) { outcounts[iproc]++ ; } } } /* -------------------------------------------------------- step 2: do an all-to-all gather/scatter to get the number of incoming submatrices from each process -------------------------------------------------------- */ MPI_Alltoall((void *) outcounts, 1, MPI_INT, (void *) incounts, 1, MPI_INT, comm) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n incounts") ; IVfprintf(msgFile, nproc, incounts) ; fprintf(msgFile, "\n\n outcounts") ; IVfprintf(msgFile, nproc, outcounts) ; fflush(msgFile) ; } /* ----------------------------------- step 3: allocate the buffer vectors ----------------------------------- */ ALLOCATE(p_outbuff, int *, nproc) ; ALLOCATE(p_inbuff, int *, nproc) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( outcounts[iproc] > 0 ) { p_outbuff[iproc] = IVinit(3*outcounts[iproc], 0) ; } else { p_outbuff[iproc] = NULL ; } if ( incounts[iproc] > 0 ) { p_inbuff[iproc] = IVinit(3*incounts[iproc], 0) ; } else { p_inbuff[iproc] = NULL ; } } /* ----------------------------------- step 4: fill the outbuffer vectors ---------------------------------- */ offsets = IVinit(nproc, 0) ; if ( cflag == 'U' ) { for ( JK = kk = 0 ; JK < nblock ; JK++ ) { J = rowids[JK] ; K = colids[JK] ; if ( owners[J] == myid && (iproc = map[JK]) != myid && (mtx = FrontMtx_upperMtx(frontmtx, J, K)) != NULL ) { outbuff = p_outbuff[iproc] ; kk = offsets[iproc] ; outbuff[kk++] = J ; outbuff[kk++] = K ; outbuff[kk++] = SubMtx_nbytesInUse(mtx) ; offsets[iproc] = kk ; } } } else { for ( JK = kk = 0 ; JK < nblock ; JK++ ) { K = rowids[JK] ; J = colids[JK] ; if ( owners[J] == myid && (iproc = map[JK]) != myid && (mtx = FrontMtx_lowerMtx(frontmtx, K, J)) != NULL ) { outbuff = p_outbuff[iproc] ; kk = offsets[iproc] ; outbuff[kk++] = K ; outbuff[kk++] = J ; outbuff[kk++] = SubMtx_nbytesInUse(mtx) ; offsets[iproc] = kk ; } } } IVfree(offsets) ; /* ------------------------------------------------- step 5: send/receive the buffer vectors in stages ------------------------------------------------- */ for ( offset = 1, tag = firsttag ; offset < nproc ; offset++, tag++ ) { right = (myid + offset) % nproc ; left = (nproc + myid - offset) % nproc ; outcount = outcounts[right] ; incount = incounts[left] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n ### process %d, send %d to right %d, recv %d from left %d", myid, outcount, right, incount, left) ; fflush(msgFile) ; } if ( outcount > 0 ) { destination = right ; stats[0]++ ; stats[2] += 3*outcount*sizeof(int) ; outbuff = p_outbuff[right] ; } else { destination = MPI_PROC_NULL ; outbuff = NULL ; } if ( incount > 0 ) { source = left ; stats[1]++ ; stats[3] += 3*incount*sizeof(int) ; inbuff = p_inbuff[left] ; } else { source = MPI_PROC_NULL ; inbuff = NULL ; } /* ----------------- do a send/receive ----------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n ### Sendrecv: dest %d, tag %d, source %d, tag %d", destination, tag, source, tag) ; fflush(msgFile) ; } MPI_Sendrecv(outbuff, 3*outcount, MPI_INT, destination, tag, inbuff, 3*incount, MPI_INT, source, tag, comm, &status) ; if ( source != MPI_PROC_NULL ) { MPI_Get_count(&status, MPI_INT, &count) ; if ( count != 3*incount ) { fprintf(stderr, "\n 1. fatal error in FrontMtx_MPI_split()" "\n proc %d : source = %d, count = %d, incount = %d\n", myid, source, count, 3*incount) ; exit(-1) ; } } if ( incount > 0 && msglvl > 1 ) { fprintf(msgFile, "\n inbuffer from proc %d", left) ; for ( kk = 0 ; kk < incount ; kk++ ) { fprintf(msgFile, "\n %8d %8d %8d", inbuff[3*kk], inbuff[3*kk+1], inbuff[3*kk+2]) ; } fflush(msgFile) ; } } if ( msglvl > 1 ) { fprintf(msgFile, "\n ### outbuff[] and inbuff[] sent and received\n") ; fflush(msgFile) ; } /* ---------------------------------------------- step 6: compute the maximum number of messages sent and received in any stage ---------------------------------------------- */ maxcount = 0 ; for ( offset = 1 ; offset < nproc ; offset++ ) { right = (myid + offset) % nproc ; left = (nproc + myid - offset) % nproc ; outcount = outcounts[right] ; incount = incounts[left] ; if ( maxcount < incount + outcount ) { maxcount = incount + outcount ; } } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n maxcount = %d", maxcount) ; fflush(msgFile) ; } ALLOCATE(messages, struct _msg, maxcount) ; /* ---------------------------------------------- step 8: send/receive the submatrices in stages ---------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n starting to send/receive the submatrices") ; fflush(msgFile) ; } tag = firsttag ; for ( offset = 1 ; offset < nproc ; offset++ ) { right = (myid + offset) % nproc ; left = (nproc + myid - offset) % nproc ; outcount = outcounts[right] ; incount = incounts[left] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n ### process %d, send %d to right %d, recv %d from left %d", myid, outcount, right, incount, left) ; fflush(msgFile) ; } msg = messages ; /* --------------------------------------------------- post the receives for submatrices from process left --------------------------------------------------- */ inbuff = p_inbuff[left] ; for ( JK = 0, recvhead = NULL ; JK < incount ; JK++, msg++ ) { rowid = inbuff[3*JK] ; colid = inbuff[3*JK+1] ; nbytes = inbuff[3*JK+2] ; if ( msglvl > 1 ) { fprintf(msgFile, "\n ready to receive mtx(%d,%d) with %d bytes from %d", rowid, colid, nbytes, left) ; fflush(msgFile) ; } mtx = SubMtxManager_newObjectOfSizeNbytes(mtxmanager, nbytes); I2Ohash_insert(hash, rowid, colid, mtx) ; msg->rowid = rowid ; msg->colid = colid ; msg->mtx = mtx ; msg->nbytes = nbytes ; msg->next = recvhead ; recvhead = msg ; if ( msglvl > 1 ) { fprintf(msgFile, "\n ### posting Irecv, left %d, tag %d, nbytes %d", left, JK + firsttag, nbytes) ; fflush(msgFile) ; } MPI_Irecv(SubMtx_workspace(mtx), nbytes, MPI_BYTE, left, JK + firsttag, comm, &msg->req) ; if ( msglvl > 1 ) { fprintf(msgFile, ", Irecv posted") ; fflush(msgFile) ; } stats[1]++ ; stats[3] += nbytes ; } /* ----------------------------------------------------- post the sends for submatrices going to process right ----------------------------------------------------- */ outbuff = p_outbuff[right] ; for ( JK = kk = 0, sendhead = NULL ; JK < outcount ; JK++, msg++ ) { rowid = outbuff[3*JK] ; colid = outbuff[3*JK+1] ; nbytes = outbuff[3*JK+2] ; I2Ohash_remove(hash, rowid, colid, (void *) &mtx) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n ready to send mtx(%d,%d) with %d bytes to %d", rowid, colid, nbytes, right) ; fflush(msgFile) ; } msg->rowid = rowid ; msg->colid = colid ; msg->mtx = mtx ; msg->nbytes = nbytes ; msg->next = sendhead ; sendhead = msg ; if ( msglvl > 1 ) { fprintf(msgFile, "\n ### posting Isend, right %d, tag %d, nbytes %d", right, JK + firsttag, nbytes) ; SubMtx_writeForHumanEye(msg->mtx, msgFile) ; fprintf(msgFile, "\n first seven entries of buffer") ; IVfprintf(msgFile, 7, (int *) SubMtx_workspace(msg->mtx)) ; fflush(msgFile) ; } MPI_Isend(SubMtx_workspace(mtx), nbytes, MPI_BYTE, right, JK + firsttag, comm, &msg->req) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n Isend posted") ; fflush(msgFile) ; } stats[0]++ ; stats[2] += nbytes ; } /* ----------------------------------------- loop while send/receives are not complete ----------------------------------------- */ while ( sendhead != NULL || recvhead != NULL ) { for ( msg = sendhead, sendhead = NULL ; msg != NULL ; msg = nextmsg ) { nextmsg = msg->next ; if ( msglvl > 1 ) { fprintf(msgFile, "\n testing sent msg %p, (%d,%d) with %d bytes", msg, msg->rowid, msg->colid, msg->nbytes) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( flag == 1 ) { /* --------------------------------------------- message has been received, release the matrix --------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, ", send complete, releasing mtx") ; fflush(msgFile) ; } SubMtxManager_releaseObject(mtxmanager, msg->mtx) ; } else { /* --------------------------------------------------- message has not been received, keep message in list --------------------------------------------------- */ msg->next = sendhead ; sendhead = msg ; } } for ( msg = recvhead, recvhead = NULL ; msg != NULL ; msg = nextmsg ) { nextmsg = msg->next ; if ( msglvl > 1 ) { fprintf(msgFile, "\n testing recv msg %p, (%d,%d) with %d bytes", msg, msg->rowid, msg->colid, msg->nbytes) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( flag == 1 ) { /* ------------------------------------------------ message has been received, initialize the matrix ------------------------------------------------ */ if ( msglvl > 1 ) { fprintf(msgFile, ", recv complete, initializing mtx") ; fprintf(msgFile, "\n first seven entries of buffer") ; IVfprintf(msgFile, 7, (int *) SubMtx_workspace(msg->mtx)) ; fflush(msgFile) ; } SubMtx_initFromBuffer(msg->mtx) ; if ( msglvl > 1 ) { SubMtx_writeForHumanEye(msg->mtx, msgFile) ; fflush(msgFile) ; } } else { /* --------------------------------------------------- message has not been received, keep message in list --------------------------------------------------- */ msg->next = recvhead ; recvhead = msg ; } } } } /* ------------------------ free the working storage ------------------------ */ IVfree(incounts) ; IVfree(outcounts) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( (inbuff = p_inbuff[iproc]) != NULL ) { IVfree(inbuff) ; } if ( (outbuff = p_outbuff[iproc]) != NULL ) { IVfree(outbuff) ; } } FREE(p_inbuff) ; FREE(p_outbuff) ; FREE(messages) ; return ; } /*--------------------------------------------------------------------*/ outbuff[kk++] = J ; outbuff[kk++] = K ; outbuff[kk++] = SubMtx_nbytesInUse(mtx) ; offsets[iproc] = kk ; } } } else { for ( JK = kk = 0 ; JK < nblock ; JK++ ) { K = rowids[JK] ; J = colids[JK] ; if ( owners[J] == myid && (iproc = map[JK]) != myid && (mtx = FrontMtx_lowerMtx(frontmtx, K, J)) != NULL ) { outbuff = p_outbuff[iproc]MPI/src/splitInpMtx.c010064400020550007177000000666400664717543700160030ustar00clevecompmath00000400000006/* split.c */ #include "../spoolesMPI.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ static int numberOfDoubles ( int count, int type ) ; static void writeBuffers ( int count, int ibuf1[], int ibuf2[], double dbuf[], int type, FILE *fp ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to split a distributed InpMtx object inpmtx -- pointer to the local InpMtx object mapIV -- pointer to the map from vertices to processes firsttag -- first tag value, one will be used stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- local message level msgFile -- local message file comm -- MPI communication structure return value -- pointer to the new InpMtx object that contains the owned entries. created -- 98may16, cca modified -- 98sep26, cca inpmtx is not modified ------------------------------------------------------------ */ InpMtx * InpMtx_MPI_split ( InpMtx *inpmtx, IV *mapIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { double *dvec, *inbuffer, *outbuffer ; InpMtx *keepmtx ; int destination, ii, ient, incount, iproc, left, maxincount, maxoutcount, myid, nDblIn, nDblOut, nent, nkeep, nowned, nproc, nvector, nvtx, offset, outcount, right, source, tagbound, type, val, vecid ; int *head, *incounts, *ivec1, *ivec2, *link, *map, *outcounts ; MPI_Status status ; /* -------------------------------------- get id of self and number of processes -------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; /* -------------------------- check the data and the map -------------------------- */ if ( inpmtx == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_MPI_split()" "\n inpmtx is NULL") ; exit(-1) ; } if ( inpmtx->storageMode != INPMTX_BY_VECTORS ) { fprintf(stderr, "\n fatal error in InpMtx_MPI_split()" "\n inpmtx must be stored by vectors") ; exit(-1) ; } if ( firsttag < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_MPI_split()" "\n firsttag = %d\n", firsttag) ; exit(-1) ; } if ( firsttag > (tagbound = maxTagMPI(comm)) ) { fprintf(stderr, "\n fatal error in InpMtx_MPI_split()" "\n firsttag = %d, tagbound = %d\n", firsttag, tagbound) ; exit(-1) ; } type = InpMtx_inputMode(inpmtx) ; switch ( type ) { case INPMTX_INDICES_ONLY : dvec = NULL ; break ; case SPOOLES_REAL : case SPOOLES_COMPLEX : dvec = InpMtx_dvec(inpmtx) ; break ; default : fprintf(stderr, "\n fatal error in InpMtx_MPI_split()" "\n bad inputMode\n") ; exit(-1) ; break ; } nent = InpMtx_nent(inpmtx) ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; nvector = InpMtx_nvector(inpmtx) ; IV_sizeAndEntries(mapIV, &nvtx, &map) ; if ( nvtx <= 0 || map == NULL ) { fprintf(stderr, "\n process %d : nvtx = %d, map = %p", myid, nvtx, map) ; exit(-1) ; } if ( (val = IVmin(nent, ivec1, &ient)) < 0 ) { fprintf(stderr, "\n process %d : IV_min(ivec1) = %d", myid, val) ; exit(-1) ; } if ( (val = IVmax(nent, ivec1, &ient)) >= nvtx ) { fprintf(stderr, "\n process %d : IV_max(ivec1) = %d", myid, val) ; exit(-1) ; } if ( (val = IV_min(mapIV)) < 0 ) { fprintf(stderr, "\n process %d : IVmin(mapIV) = %d", myid, val) ; exit(-1) ; } if ( (val = IV_max(mapIV)) >= nproc ) { fprintf(stderr, "\n process %d : IVmax(mapIV) = %d", myid, val) ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- compute the number of entries that must be sent to each other process ---------------------------------- */ outcounts = IVinit(nproc, 0) ; incounts = IVinit(nproc, 0) ; if ( nvector > 0 ) { int *vecids = InpMtx_vecids(inpmtx) ; int *sizes = InpMtx_sizes(inpmtx) ; head = IVinit(nproc, -1) ; link = IVinit(nvector, -1) ; for ( ii = nvector - 1 ; ii >= 0 ; ii-- ) { vecid = vecids[ii] ; iproc = map[vecid] ; link[ii] = head[iproc] ; head[iproc] = ii ; outcounts[iproc] += sizes[ii] ; } nkeep = outcounts[myid] ; outcounts[myid] = 0 ; } else { head = NULL ; link = NULL ; nkeep = 0 ; } /* ------------------------------- do an all-to-all gather/scatter ------------------------------- */ MPI_Alltoall((void *) outcounts, 1, MPI_INT, (void *) incounts, 1, MPI_INT, comm) ; incounts[myid] = 0 ; nowned = nkeep + IVsum(nproc, incounts) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n nkeep %d, nowned %d", nkeep, nowned) ; fprintf(msgFile, "\n\n incounts") ; IVfprintf(msgFile, nproc, incounts) ; fprintf(msgFile, "\n\n outcounts") ; IVfprintf(msgFile, nproc, outcounts) ; fflush(msgFile) ; } /* --------------------------------- allocate the send/receive buffers --------------------------------- */ if ( (maxincount = IVmax(nproc, incounts, &iproc)) > 0 ) { nDblIn = numberOfDoubles(maxincount, type) ; inbuffer = DVinit2(nDblIn) ; } else { nDblIn = 0 ; inbuffer = NULL ; } if ( (maxoutcount = IVmax(nproc, outcounts, &iproc)) > 0 ) { nDblOut = numberOfDoubles(maxoutcount, type) ; outbuffer = DVinit2(nDblOut) ; } else { nDblOut = 0 ; outbuffer = NULL ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n nDblIn %d, inbuffer %p, nDblOut %d, outbuffer %p", nDblIn, inbuffer, nDblOut, outbuffer) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- set up the new InpMtx object to hold the owned entries ------------------------------------------------------- */ keepmtx = InpMtx_new() ; InpMtx_init(keepmtx, inpmtx->coordType, type, nowned, 0) ; /* --------------------------------------------- extract the triples from the original matrix, and load the triples into the keep matrix --------------------------------------------- */ if ( nkeep > 0 ) { int *offsets = InpMtx_offsets(inpmtx) ; int *sizes = InpMtx_sizes(inpmtx) ; int ii, ient, size ; for ( ii = head[myid] ; ii != -1 ; ii = link[ii] ) { ient = offsets[ii] ; size = sizes[ii] ; switch ( type ) { case INPMTX_INDICES_ONLY : InpMtx_inputTriples(keepmtx, size, ivec1 + ient, ivec2 + ient); break ; case SPOOLES_REAL : InpMtx_inputRealTriples(keepmtx, size, ivec1 + ient, ivec2 + ient, dvec + ient) ; break ; case SPOOLES_COMPLEX : InpMtx_inputComplexTriples(keepmtx, size, ivec1 + ient, ivec2 + ient, dvec + 2*ient) ; break ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n keepmtx after storing owned original entries") ; InpMtx_writeForHumanEye(keepmtx, msgFile) ; fflush(msgFile) ; } } /* ---------------------------------- loop over the other processes, gather values and send them off receive values ---------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ready to split entries and send to other processes") ; fflush(msgFile) ; } for ( offset = 1 ; offset < nproc ; offset++ ) { right = (myid + offset) % nproc ; left = (offset <= myid) ? (myid - offset) : (nproc + myid - offset); outcount = outcounts[right] ; incount = incounts[left] ; if ( msglvl > 2 ) { fprintf(msgFile, "\n ### process %d, send %d to right %d, recv %d from left %d", myid, outcount, right, incount, left) ; fflush(msgFile) ; } if ( outcount > 0 ) { double *dbuf ; int *offsets = InpMtx_offsets(inpmtx) ; int *sizes = InpMtx_sizes(inpmtx) ; int *ibuf1, *ibuf2 ; int ii, ient, jent, size ; /* ----------------------------------------- load the entries to send to process right ----------------------------------------- */ ibuf1 = (int *) outbuffer ; ibuf2 = ibuf1 + outcount ; dbuf = (double *) (ibuf2 + outcount) ; for ( ii = head[right], jent = 0 ; ii != -1 ; ii = link[ii] ) { ient = offsets[ii] ; size = sizes[ii] ; IVcopy(size, ibuf1 + jent, ivec1 + ient) ; IVcopy(size, ibuf2 + jent, ivec2 + ient) ; switch ( type ) { case SPOOLES_REAL : DVcopy(size, dbuf + jent, dvec + ient) ; break ; case SPOOLES_COMPLEX : DVcopy(2*size, dbuf + 2*jent, dvec + 2*ient) ; break ; } jent += size ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n outcount %d, ibuf1 %p, ibuf2 %p, dbuf %p", outcount, ibuf1, ibuf2, dbuf) ; writeBuffers(outcount, ibuf1, ibuf2, dbuf, type, msgFile) ; fflush(msgFile) ; } destination = right ; nDblOut = numberOfDoubles(outcount, type) ; stats[0]++ ; stats[2] += nDblOut*sizeof(double) ; } else { destination = MPI_PROC_NULL ; nDblOut = 0 ; } if ( incount > 0 ) { source = left ; } else { source = MPI_PROC_NULL ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n nDblOut = %d, nDblIn = %d", nDblOut, nDblIn) ; fflush(msgFile) ; } /* ----------------- do a send receive ----------------- */ MPI_Sendrecv((void *) outbuffer, nDblOut, MPI_DOUBLE, destination, firsttag, (void *) inbuffer, nDblIn, MPI_DOUBLE, source, firsttag, comm, &status) ; if ( incount > 0 ) { /* ------------------------------------- load the triples into the keep matrix ------------------------------------- */ int count ; int *ibuf1 = (int *) inbuffer ; int *ibuf2 = ibuf1 + incount ; double *dbuf = (double *) (ibuf2 + incount) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n incoming buffer") ; writeBuffers(incount, ibuf1, ibuf2, dbuf, type, msgFile) ; fflush(msgFile) ; } switch ( type ) { case INPMTX_INDICES_ONLY : InpMtx_inputTriples(keepmtx, incount, ibuf1, ibuf2) ; break ; case SPOOLES_REAL : InpMtx_inputRealTriples(keepmtx, incount, ibuf1, ibuf2, dbuf) ; break ; case SPOOLES_COMPLEX : InpMtx_inputComplexTriples(keepmtx, incount, ibuf1, ibuf2, dbuf) ; break ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n keepmtx after storing received entries") ; InpMtx_writeForHumanEye(keepmtx, msgFile) ; fflush(msgFile) ; } MPI_Get_count(&status, MPI_DOUBLE, &count) ; stats[1]++ ; stats[3] += count*sizeof(double) ; } } if ( keepmtx != NULL ) { /* ---------------------------------------------------- sort and compress the entries and convert to vectors ---------------------------------------------------- */ if ( msglvl > 3 ) { fprintf(msgFile, "\n before changing storage mode to %d", 2) ; InpMtx_writeForHumanEye(keepmtx, msgFile) ; fflush(msgFile) ; } InpMtx_changeStorageMode(keepmtx, INPMTX_BY_VECTORS) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n after changing storage mode to %d", 2) ; InpMtx_writeForHumanEye(keepmtx, msgFile) ; fflush(msgFile) ; } } /* ------------------------ free the working storage ------------------------ */ if ( inbuffer != NULL ) { DVfree(inbuffer) ; } if ( outbuffer != NULL ) { DVfree(outbuffer) ; } IVfree(outcounts) ; IVfree(incounts) ; if ( link != NULL ) { IVfree(head) ; IVfree(link) ; } return(keepmtx) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to split a distributed InpMtx object Aglobal -- pointer to the global InpMtx object, significant only for root processor Alocal -- pointer to the local InpMtx object, if NULL and will be nonempty, it will be created mapIV -- pointer to the map from vertices to processes root -- processor that presently owns the global matrix firsttag -- first tag value, one will be used stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- local message level msgFile -- local message file comm -- MPI communication structure return value -- pointer to the local InpMtx object that contains the owned entries. created -- 98may16, cca modified -- 98sep26, cca inpmtx is not modified ------------------------------------------------------------ */ InpMtx * InpMtx_MPI_splitFromGlobal ( InpMtx *Aglobal, InpMtx *Alocal, IV *mapIV, int root, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { double *dvec, *inbuffer, *outbuffer ; int coordType, ii, ient, incount, iproc, maxoutcount, myid, nDblIn, nDblOut, nent, nowned, nproc, nvector, nvtx, outcount, tagbound, type, val, vecid ; int *head, *ivec1, *ivec2, *link, *map, *outcounts ; /* -------------------------------------- get id of self and number of processes -------------------------------------- */ MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; /* -------------------------- check the data and the map -------------------------- */ if ( myid == root ) { int rc = 1 ; if ( Aglobal == NULL ) { fprintf(stderr, "\n fatal error in InpMtx_MPI_splitFromGlobal()" "\n Aglobal is NULL") ; rc = -1 ; } if ( Aglobal->storageMode != INPMTX_BY_VECTORS ) { fprintf(stderr, "\n fatal error in InpMtx_MPI_splitFromGlobal()" "\n Aglobal must be stored by vectors") ; rc = -2 ; } if ( firsttag < 0 ) { fprintf(stderr, "\n fatal error in InpMtx_MPI_splitFromGlobal()" "\n firsttag = %d\n", firsttag) ; rc = -3 ; } if ( firsttag > (tagbound = maxTagMPI(comm)) ) { fprintf(stderr, "\n fatal error in InpMtx_MPI_splitFromGlobal()" "\n firsttag = %d, tagbound = %d\n", firsttag, tagbound) ; rc = -4 ; } type = InpMtx_inputMode(Aglobal) ; switch ( type ) { case INPMTX_INDICES_ONLY : dvec = NULL ; break ; case SPOOLES_REAL : case SPOOLES_COMPLEX : dvec = InpMtx_dvec(Aglobal) ; break ; default : fprintf(stderr, "\n fatal error in InpMtx_MPI_splitFromGlobal()" "\n bad inputMode\n") ; rc = -5 ; break ; } nent = InpMtx_nent(Aglobal) ; ivec1 = InpMtx_ivec1(Aglobal) ; ivec2 = InpMtx_ivec2(Aglobal) ; nvector = InpMtx_nvector(Aglobal) ; IV_sizeAndEntries(mapIV, &nvtx, &map) ; if ( nvtx <= 0 || map == NULL ) { fprintf(stderr, "\n process %d : nvtx = %d, map = %p", myid, nvtx, map) ; rc = -6 ; } if ( (val = IVmin(nent, ivec1, &ient)) < 0 ) { fprintf(stderr, "\n process %d : IV_min(ivec1) = %d", myid, val) ; rc = -7 ; } if ( (val = IVmax(nent, ivec1, &ient)) >= nvtx ) { fprintf(stderr, "\n process %d : IV_max(ivec1) = %d", myid, val) ; rc = -8 ; } if ( (val = IV_min(mapIV)) < 0 ) { fprintf(stderr, "\n process %d : IVmin(mapIV) = %d", myid, val) ; rc = -9 ; } if ( (val = IV_max(mapIV)) >= nproc ) { fprintf(stderr, "\n process %d : IVmax(mapIV) = %d", myid, val) ; rc = -10 ; } /* -------------------------------------------------- if the error code is not 1, broadcast it and exit, otherwise broadcast the entries type -------------------------------------------------- */ if ( rc != 1 ) { MPI_Bcast((void *) &rc, 1, MPI_INT, root, comm) ; MPI_Finalize() ; exit(rc) ; } else { MPI_Bcast((void *) &type, 1, MPI_INT, root, comm) ; coordType = Aglobal->coordType ; MPI_Bcast((void *) &coordType, 1, MPI_INT, root, comm) ; } } else { /* -------------------------------------- receive the type of entries, if < 0 then an error has been found by the root process, finalize and exit -------------------------------------- */ MPI_Bcast((void *) &type, 1, MPI_INT, root, comm) ; if ( type < 0 ) { MPI_Finalize() ; exit(type) ; } MPI_Bcast((void *) &coordType, 1, MPI_INT, root, comm) ; } /*--------------------------------------------------------------------*/ if ( myid == root ) { /* ---------------------------------- compute the number of entries that must be sent to each other process ---------------------------------- */ outcounts = IVinit(nproc, 0) ; if ( nvector > 0 ) { int *vecids = InpMtx_vecids(Aglobal) ; int *sizes = InpMtx_sizes(Aglobal) ; head = IVinit(nproc, -1) ; link = IVinit(nvector, -1) ; for ( ii = nvector - 1 ; ii >= 0 ; ii-- ) { vecid = vecids[ii] ; iproc = map[vecid] ; link[ii] = head[iproc] ; head[iproc] = ii ; outcounts[iproc] += sizes[ii] ; } nowned = outcounts[myid] ; outcounts[myid] = 0 ; } else { head = NULL ; link = NULL ; nowned = 0 ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n nowned %d", nowned) ; fprintf(msgFile, "\n\n outcounts") ; IVfprintf(msgFile, nproc, outcounts) ; fflush(msgFile) ; } /* --------------------------------------------- scatter the outcounts to the other processors --------------------------------------------- */ MPI_Scatter((void *) outcounts, 1, MPI_INT, (void *) &incount, 1, MPI_INT, root, comm) ; /* ------------------------ allocate the send buffer ------------------------ */ if ( (maxoutcount = IVmax(nproc, outcounts, &iproc)) > 0 ) { nDblOut = numberOfDoubles(maxoutcount, type) ; outbuffer = DVinit2(nDblOut) ; } else { nDblOut = 0 ; outbuffer = NULL ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n nDblOut %d, outbuffer %p", nDblOut, outbuffer) ; fflush(msgFile) ; } } else { /* ---------------------------------- receive the in-count from the root ---------------------------------- */ MPI_Scatter(NULL, 0, MPI_INT, (void *) &incount, 1, MPI_INT, root, comm) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n incount %d", incount) ; fflush(msgFile) ; } /* --------------------------- allocate the receive buffer --------------------------- */ if ( incount > 0 ) { nDblIn = numberOfDoubles(incount, type) ; inbuffer = DVinit2(nDblIn) ; } else { nDblIn = 0 ; inbuffer = NULL ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n nDblIn %d, inbuffer %p", nDblIn, inbuffer) ; fflush(msgFile) ; } nowned = incount ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- set up the new InpMtx object to hold the owned entries ------------------------------------------------------- */ if ( Alocal == NULL ) { Alocal = InpMtx_new() ; } InpMtx_init(Alocal, coordType, type, nowned, 0) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Alocal initialized, nowned %d", nowned) ; fflush(msgFile) ; } if ( myid == root ) { /* --------------------------------------------- extract the triples from the original matrix, and load the triples into the keep matrix --------------------------------------------- */ if ( nowned > 0 ) { int *offsets = InpMtx_offsets(Aglobal) ; int *sizes = InpMtx_sizes(Aglobal) ; int ii, ient, size ; for ( ii = head[myid] ; ii != -1 ; ii = link[ii] ) { ient = offsets[ii] ; size = sizes[ii] ; switch ( type ) { case INPMTX_INDICES_ONLY : InpMtx_inputTriples(Alocal, size, ivec1 + ient, ivec2 + ient); break ; case SPOOLES_REAL : InpMtx_inputRealTriples(Alocal, size, ivec1 + ient, ivec2 + ient, dvec + ient) ; break ; case SPOOLES_COMPLEX : InpMtx_inputComplexTriples(Alocal, size, ivec1 + ient, ivec2 + ient, dvec + 2*ient) ; break ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n Alocal after storing owned original entries") ; InpMtx_writeForHumanEye(Alocal, msgFile) ; fflush(msgFile) ; } } /* ---------------------------------- loop over the other processes, gather values and send them off receive values ---------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ready to send entries to other processes") ; fflush(msgFile) ; } for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( iproc != myid ) { outcount = outcounts[iproc] ; if ( msglvl > 2 ) { fprintf(msgFile, "\n ### process %d, send %d to %d", myid, outcount, iproc) ; fflush(msgFile) ; } if ( outcount > 0 ) { double *dbuf ; int *offsets = InpMtx_offsets(Aglobal) ; int *sizes = InpMtx_sizes(Aglobal) ; int *ibuf1, *ibuf2 ; int ii, ient, jent, size ; /* ----------------------------------------- load the entries to send to process iproc ----------------------------------------- */ ibuf1 = (int *) outbuffer ; ibuf2 = ibuf1 + outcount ; dbuf = (double *) (ibuf2 + outcount) ; jent = 0 ; for ( ii = head[iproc] ; ii != -1 ; ii = link[ii] ) { ient = offsets[ii] ; size = sizes[ii] ; IVcopy(size, ibuf1 + jent, ivec1 + ient) ; IVcopy(size, ibuf2 + jent, ivec2 + ient) ; switch ( type ) { case SPOOLES_REAL : DVcopy(size, dbuf + jent, dvec + ient) ; break ; case SPOOLES_COMPLEX : DVcopy(2*size, dbuf + 2*jent, dvec + 2*ient) ; break ; } jent += size ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n outcount %d, ibuf1 %p, ibuf2 %p, dbuf %p", outcount, ibuf1, ibuf2, dbuf) ; writeBuffers(outcount, ibuf1, ibuf2, dbuf, type,msgFile); fflush(msgFile) ; } nDblOut = numberOfDoubles(outcount, type) ; stats[0]++ ; stats[2] += nDblOut*sizeof(double) ; /* ----------------- do a send receive ----------------- */ MPI_Send((void *) outbuffer, nDblOut, MPI_DOUBLE, iproc, firsttag, comm) ; } } } /* ------------------------ free the working storage ------------------------ */ if ( outbuffer != NULL ) { DVfree(outbuffer) ; } IVfree(outcounts) ; if ( link != NULL ) { IVfree(head) ; IVfree(link) ; } } else { if ( incount > 0 ) { int count ; int *ibuf1 = (int *) inbuffer ; int *ibuf2 = ibuf1 + incount ; double *dbuf = (double *) (ibuf2 + incount) ; MPI_Status status ; /* -------------------------------- receive the buffer from the root -------------------------------- */ MPI_Recv((void *) inbuffer, nDblIn, MPI_DOUBLE, root, firsttag, comm, &status) ; MPI_Get_count(&status, MPI_DOUBLE, &count) ; if ( count != nDblIn ) { fprintf(stderr, "\n fatal error in InpMtx_MPI_splitFromGlobal()" "\n proc %d, nDblIn %d, count %d\n", myid, nDblIn, count) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n incoming buffer") ; writeBuffers(incount, ibuf1, ibuf2, dbuf, type,msgFile); fflush(msgFile) ; } /* ------------------------------------- load the triples into the keep matrix ------------------------------------- */ switch ( type ) { case INPMTX_INDICES_ONLY : InpMtx_inputTriples(Alocal, incount, ibuf1, ibuf2) ; break ; case SPOOLES_REAL : InpMtx_inputRealTriples(Alocal, incount, ibuf1, ibuf2, dbuf) ; break ; case SPOOLES_COMPLEX : InpMtx_inputComplexTriples(Alocal, incount, ibuf1, ibuf2, dbuf) ; break ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n Alocal after storing received entries") ; InpMtx_writeForHumanEye(Alocal, msgFile) ; fflush(msgFile) ; } stats[1]++ ; stats[3] += count*sizeof(double) ; /* ------------------------ free the working storage ------------------------ */ if ( inbuffer != NULL ) { DVfree(inbuffer) ; } } } if ( Alocal != NULL ) { /* ---------------------------------------------------- sort and compress the entries and convert to vectors ---------------------------------------------------- */ if ( msglvl > 3 ) { fprintf(msgFile, "\n before changing storage mode to %d", 2) ; InpMtx_writeForHumanEye(Alocal, msgFile) ; fflush(msgFile) ; } InpMtx_changeStorageMode(Alocal, INPMTX_BY_VECTORS) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n after changing storage mode to %d", 2) ; InpMtx_writeForHumanEye(Alocal, msgFile) ; fflush(msgFile) ; } } return(Alocal) ; } /*--------------------------------------------------------------------*/ /* --------------------------------- return the # of double words that form a message of count triples created -- 98sep27, cca --------------------------------- */ static int numberOfDoubles ( int count, int type ) { int nDbl ; if ( sizeof(int) == sizeof(double) ) { nDbl = 2*count ; } else if ( 2*sizeof(int) == sizeof(double) ) { nDbl = count ; } if ( type == SPOOLES_REAL ) { nDbl += count ; } else if ( type == SPOOLES_COMPLEX ) { nDbl += 2*count ; } return(nDbl) ; } /*--------------------------------------------------------------------*/ /* ----------------------- write out the buffers created -- 98sep27, cca ----------------------- */ static void writeBuffers ( int count, int ibuf1[], int ibuf2[], double dbuf[], int type, FILE *fp ) { fprintf(fp, "\n ibuf1") ; IVfprintf(fp, count, ibuf1) ; fprintf(fp, "\n ibuf2") ; IVfprintf(fp, count, ibuf2) ; if ( type == SPOOLES_REAL ) { fprintf(fp, "\n dbuf") ; DVfprintf(fp, count, dbuf) ; } else if ( type == SPOOLES_COMPLEX ) { fprintf(fp, "\n dbuf") ; DVfprintf(fp, 2*count, dbuf) ; } return ; } /*--------------------------------------------------------------------*/ iproc = map[vecid] ; link[ii] = head[iproc] ; head[iproc] = ii ; MPI/src/splitPencil.c010064400020550007177000000040760655671743000157630ustar00clevecompmath00000400000006/* setupPencil.c */ #include "../spoolesMPI.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- to split a distributed Pencil object pencil -- pointer to the local Pencil object mapIV -- pointer to the map from vertices to processes firsttag -- first tag value, two will be used, tag and tag+1 stats[4] -- statistics vector stats[0] -- # of messages sent stats[1] -- # of messages received stats[2] -- # of bytes sent stats[3] -- # of bytes received msglvl -- local message level msgFile -- local message file comm -- MPI communication structure created -- 98may20, cca -------------------------------------------------------------- */ void Pencil_MPI_split ( Pencil *pencil, IV *mapIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { InpMtx *inpmtxA, *inpmtxB, *keepmtx ; int tag ; /* ----------------------- check the range of tags ----------------------- */ if ( firsttag < 0 || firsttag + 1 > maxTagMPI(comm) ) { fprintf(stderr, "\n fatal error in Pencil_MPI_split()" "\n range of tags is [%d,%d], tag_bound = %d", firsttag, firsttag + 1, maxTagMPI(comm)) ; exit(-1) ; } /* ------------------------------------ split the DInpMtx object into pieces ------------------------------------ */ tag = firsttag ; if ( (inpmtxA = pencil->inpmtxA) != NULL ) { keepmtx = InpMtx_MPI_split(inpmtxA, mapIV, stats, msglvl, msgFile, tag, comm) ; InpMtx_free(inpmtxA) ; pencil->inpmtxA = keepmtx ; } tag += 1 ; if ( (inpmtxB = pencil->inpmtxB) != NULL ) { keepmtx = InpMtx_MPI_split(inpmtxB, mapIV, stats, msglvl, msgFile, tag, comm) ; InpMtx_free(inpmtxB) ; pencil->inpmtxB = keepmtx ; } tag += 1 ; return ; } /*--------------------------------------------------------------------*/ MPI/src/symbfacMPI.c010064400020550007177000001103030663623577600154650ustar00clevecompmath00000400000006/* symbfac.c */ #include "../spoolesMPI.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ typedef struct _Msg Msg ; struct _Msg { int id ; int size ; void *base ; MPI_Request req ; Msg *next ; } ; static IVL * initSupportedIVL ( ETree *frontETree, IV *frontOwnersIV, int myid, int msglvl, FILE *msgFile ) ; static void loadInternalIndices ( ETree *frontETree, InpMtx *inpmtxA, InpMtx *inpmtxB, IV *frontOwnersIV, int myid, IVL *symbfacIVL, int msglvl, FILE *msgFile ) ; static void doCooperativeWork ( ETree *frontETree, IV *frontOwnersIV, IVL *symbfacIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; static int mergeIndices ( int sizeJ, int indJ[], int sizeK, int indK[], int nleft ) ; static Msg * Msg_new ( void ) ; static void Msg_setDefaultFields ( Msg *msg ) ; static void Msg_clearData ( Msg *msg ) ; static void Msg_free ( Msg *msg ) ; static Msg * wakeupFront ( int J, int myid, int owners[], char supportTable[], ETree *frontETree, IVL *symbfacIVL, int firsttag, int stats[], MPI_Comm comm, int msglvl, FILE *msgFile ) ; static Msg * checkRecvMessages ( int J, Msg *firstmsg, int nLeft[], int nodwghts[], IVL *symbfacIVL, int msglvl, FILE *msgFile ) ; static Msg * sendMessages ( int J, int myid, int owners[], int nfront, int nproc, char supportTable[], int par[], IVL *symbfacIVL, Msg *firstMsgSent, int firsttag, int stats[], MPI_Comm comm, int msglvl, FILE *msgFile ) ; static Msg * checkSendMessages ( Msg *firstMsgSent, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ perform the symbolic factorization in parallel input -- frontETree -- front tree for the factorization frontOwnersIV -- map from fronts to owning process inpmtx -- matrix object firsttag -- first tag to be used for messages, will use tag, ..., tag + nfront - 1 msglvl -- message level msgFile -- message file comm -- MPI communicator return value -- symbfacIVL -- contains front indices for supported fronts created -- 98may20, cca ------------------------------------------------------------ */ IVL * SymbFac_MPI_initFromInpMtx ( ETree *frontETree, IV *frontOwnersIV, InpMtx *inpmtx, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { int lasttag, myid, nproc, tagbound; IVL *symbfacIVL ; /* --------------- check the input --------------- */ if ( frontETree == NULL || frontOwnersIV == NULL || inpmtx == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in SymbFac_MPI_initFromInpMtx()" "\n comm = %p, frontETree = %p, frontOwnersIV = %p" "\n inpmtx = %p, firsttag = %d, msglvl = %d, msgFile = %p" "\n bad input\n", comm, frontETree, frontOwnersIV, inpmtx, firsttag, msglvl, msgFile) ; exit(-1) ; } MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n myid = %d, nproc = %d", myid, nproc) ; fflush(msgFile) ; } if ( firsttag < 0 ) { fprintf(stderr, "\n fatal error in SymbFac_MPI_initFromInpMtx()" "\n firsttag = %d\n", firsttag) ; exit(-1) ; } lasttag = firsttag + frontETree->nfront ; if ( lasttag > (tagbound = maxTagMPI(comm)) ) { fprintf(stderr, "\n fatal error in SymbFac_MPI_initFromInpMtx()" "\n lasttag = %d, tag_bound = %d", lasttag, tagbound) ; exit(-1) ; } /* -------------------------------------- first, set up the supported IVL object -------------------------------------- */ symbfacIVL = initSupportedIVL(frontETree, frontOwnersIV, myid, msglvl, msgFile) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n local supported IVL after initialization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------------------ second, fill the index lists of the owned fronts with the internal vertices and boundary vertices available from the matrix pencil ------------------------------------------------------------------ */ loadInternalIndices(frontETree, inpmtx, NULL, frontOwnersIV, myid, symbfacIVL, msglvl, msgFile ) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n after loading internal indices") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------- third, cooperate among the processors to generate the rest of the supported symbolic factorization ------------------------------------------------- */ doCooperativeWork(frontETree, frontOwnersIV, symbfacIVL, stats, msglvl, msgFile, firsttag, comm) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n final local supported IVL ") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } return(symbfacIVL) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ perform the symbolic factorization in parallel input -- frontETree -- front tree for the factorization frontOwnersIV -- map from fronts to owning process pencil -- matrix pencil object firsttag -- first tag to be used for messages, will use tag, ..., tag + nfront - 1 msglvl -- message level msgFile -- message file comm -- MPI communicator return value -- symbfacIVL -- contains front indices for supported fronts created -- 98may20, cca ------------------------------------------------------------ */ IVL * SymbFac_MPI_initFromPencil ( ETree *frontETree, IV *frontOwnersIV, Pencil *pencil, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { int lasttag, myid, nproc, tagbound; IVL *symbfacIVL ; /* --------------- check the input --------------- */ if ( frontETree == NULL || frontOwnersIV == NULL || pencil == NULL || stats == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in SymbFac_MPI_initFromPencil()" "\n comm = %p, frontETree = %p, frontOwnersIV = %p" "\n pencil = %p, firsttag = %d, msglvl = %d, msgFile = %p" "\n bad input\n", comm, frontETree, frontOwnersIV, pencil, firsttag, msglvl, msgFile) ; exit(-1) ; } MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n myid = %d, nproc = %d", myid, nproc) ; fflush(msgFile) ; } if ( firsttag < 0 ) { fprintf(stderr, "\n fatal error in SymbFac_MPI_initFromPencil()" "\n firsttag = %d\n", firsttag) ; exit(-1) ; } lasttag = firsttag + frontETree->nfront ; if ( lasttag > (tagbound = maxTagMPI(comm)) ) { fprintf(stderr, "\n fatal error in SymbFac_MPI_initFromPencil()" "\n lasttag = %d, tag_bound = %d", lasttag, tagbound) ; exit(-1) ; } /* -------------------------------------- first, set up the supported IVL object -------------------------------------- */ symbfacIVL = initSupportedIVL(frontETree, frontOwnersIV, myid, msglvl, msgFile) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n local supported IVL after initialization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------------------ second, fill the index lists of the owned fronts with the internal vertices and boundary vertices available from the matrix pencil ------------------------------------------------------------------ */ loadInternalIndices(frontETree, pencil->inpmtxA, pencil->inpmtxB, frontOwnersIV, myid, symbfacIVL, msglvl, msgFile ) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n after loading internal indices") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------- third, cooperate among the processors to generate the rest of the supported symbolic factorization ------------------------------------------------- */ doCooperativeWork(frontETree, frontOwnersIV, symbfacIVL, stats, msglvl, msgFile, firsttag, comm) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n final local supported IVL ") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } return(symbfacIVL) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- initialize the symbolic factorization IVL for process myid created -- 98may20 --------------------------------------------------------------------- */ static IVL * initSupportedIVL ( ETree *frontETree, IV *frontOwnersIV, int myid, int msglvl, FILE *msgFile ) { char *frontSupported ; int J, K, nfront ; int *bndwghts, *nodwghts, *owners, *par, *sizes ; IVL *symbfacIVL ; nfront = ETree_nfront(frontETree) ; nodwghts = ETree_nodwghts(frontETree), bndwghts = ETree_bndwghts(frontETree), par = ETree_par(frontETree) ; owners = IV_entries(frontOwnersIV) ; /* ----------------------------------------------------------------- create the frontSupported[] vector, frontSupported[J] = 'Y' --> this process supports front J frontSupported[J] = 'N' --> this process does not support front J ----------------------------------------------------------------- */ frontSupported = CVinit(nfront, 'N') ; for ( J = 0 ; J < nfront ; J++ ) { if ( owners[J] == myid ) { K = J ; while ( K != -1 && frontSupported[K] == 'N' ) { frontSupported[K] = 'Y' ; K = par[K] ; } } } /* ----------------------------------------------- initialize the local symbolic factorization IVL ----------------------------------------------- */ symbfacIVL = IVL_new() ; sizes = IVinit(nfront, 0) ; for ( J = 0 ; J < nfront ; J++ ) { if ( frontSupported[J] == 'Y' ) { sizes[J] = nodwghts[J] + bndwghts[J] ; } } IVL_init3(symbfacIVL, IVL_CHUNKED, nfront, sizes) ; /* ------------------------ free the working storage ------------------------ */ IVfree(sizes) ; CVfree(frontSupported) ; return(symbfacIVL) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- perform the symbolic factorization in parallel input -- frontETree -- front tree for the factorization frontOwnersIV -- map from fronts to owning process pencil -- matrix pencil firsttag -- first tag to be used for messages, will use tag, ..., tag + nfront - 1 msglvl -- message level msgFile -- message file comm -- MPI communicator return value -- symbfacIVL -- contains front indices for supported fronts created -- 98may20, cca -------------------------------------------------------------------- */ static void doCooperativeWork ( ETree *frontETree, IV *frontOwnersIV, IVL *symbfacIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) { char *frontIsSupported, *status, *supportTable ; Ideq *dequeue ; int count, ii, iproc, J, K, myid, nDJ, nfront, npath, nproc, nvtx, sizeJ, sizeK ; int *bndwghts, *frontOwners, *indicesJ, *indicesK, *nactiveChild, *nLeft, *nodwghts, *par, *vtxToFront ; Msg *firstMsgSent ; Msg **p_msg ; /* ------------------------------- extract pointers and dimensions ------------------------------- */ nfront = ETree_nfront(frontETree) ; nvtx = ETree_nvtx(frontETree) ; nodwghts = ETree_nodwghts(frontETree), bndwghts = ETree_bndwghts(frontETree), vtxToFront = ETree_vtxToFront(frontETree), par = ETree_par(frontETree) ; IV_sizeAndEntries(frontOwnersIV, &nfront, &frontOwners) ; MPI_Comm_rank(comm, &myid) ; MPI_Comm_size(comm, &nproc) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n myid = %d, nproc = %d", myid, nproc) ; fflush(msgFile) ; } /* -------------------------- generate the support table -------------------------- */ supportTable = CVinit(nfront*nproc, 'N') ; for ( J = 0 ; J < nfront ; J++ ) { iproc = frontOwners[J] ; frontIsSupported = supportTable + iproc*nfront ; for ( K = J ; K != -1 && frontIsSupported[K] == 'N' ; K = par[K] ) { frontIsSupported[K] = 'Y' ; } } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n supportTable") ; for ( J = 0 ; J < nfront ; J++ ) { fprintf(msgFile, "\n") ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { fprintf(msgFile, " %c", supportTable[J + iproc*nfront]) ; } } fflush(msgFile) ; } /* --------------------------------------------------------- initialize the status[] and nactiveChild[] vectors and load the dequeue with the leaves of the supported subtree --------------------------------------------------------- */ frontIsSupported = supportTable + myid*nfront ; status = CVinit(nfront, 'F') ; for ( J = npath = 0 ; J < nfront ; J++ ) { if ( status[J] == 'F' && frontIsSupported[J] == 'Y' ) { npath++ ; for ( K = J ; K != -1 && status[K] == 'F' ; K = par[K] ) { status[K] = 'W' ; } } } dequeue = Ideq_new() ; Ideq_resize(dequeue, npath) ; nactiveChild = IVinit(nfront, 0) ; for ( J = 0 ; J < nfront ; J++ ) { if ( status[J] == 'W' ) { if ( (K = par[J]) != -1 ) { nactiveChild[K]++ ; } } } for ( J = 0 ; J < nfront ; J++ ) { if ( frontOwners[J] == myid && nactiveChild[J] == 0 ) { Ideq_insertAtTail(dequeue, J) ; } } /* --------------------------- generate the nLeft[] vector --------------------------- */ nLeft = IVinit(nfront, -1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( frontOwners[J] == myid ) { IVL_listAndSize(symbfacIVL, J, &sizeJ, &indicesJ) ; for ( ii = sizeJ - 1, count = 0 ; ii >= 0 ; ii-- ) { if ( indicesJ[ii] != -1 ) { break ; } count++ ; } nLeft[J] = count ; } } /* ------------------------------------------- generate the vector of pointers to messages ------------------------------------------- */ firstMsgSent = NULL ; ALLOCATE(p_msg, struct _Msg *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { p_msg[J] = NULL ; } /* ---------------------------------- loop while the dequeue is nonempty ---------------------------------- */ while ( (J = Ideq_removeFromHead(dequeue)) != -1 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ### popping %d from dequeue", J) ; fflush(msgFile) ; } if ( status[J] == 'W' ) { /* -------------------------------------------- wake up the front, post its receive messages -------------------------------------------- */ p_msg[J] = wakeupFront(J, myid, frontOwners, supportTable, frontETree, symbfacIVL, firsttag, stats, comm, msglvl, msgFile) ; status[J] = 'A' ; } if ( p_msg[J] != NULL ) { /* ----------------------------- try to receive messages for J ----------------------------- */ p_msg[J] = checkRecvMessages(J, p_msg[J], nLeft, nodwghts, symbfacIVL, msglvl, msgFile) ; } if ( p_msg[J] == NULL ) { if ( msglvl > 3 ) { IVL_listAndSize(symbfacIVL, J, &sizeJ, &indicesJ) ; fprintf(msgFile, "\n adjacency list for J = %d, nJ = %d, bndJ = %d", J, nodwghts[J], bndwghts[J]) ; IVfprintf(msgFile, sizeJ, indicesJ) ; fflush(msgFile) ; } /* ------------------------------------------- all messages received: check for the length of the indices vector, set the boundary size of the front ------------------------------------------ */ status[J] = 'D' ; IVL_listAndSize(symbfacIVL, J, &sizeJ, &indicesJ) ; for ( ii = 0 ; ii < sizeJ ; ii++ ) { if ( indicesJ[ii] == -1 ) { break ; } } if ( ii != sizeJ ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n WHOA, front J %d, sizeJ %d", J, sizeJ); fprintf(msgFile, "\n old bndwght = %d, new bndwght = %d", bndwghts[J], ii - nodwghts[J]) ; IVfprintf(msgFile, sizeJ, indicesJ) ; fflush(msgFile) ; } bndwghts[J] = ii - nodwghts[J] ; IVL_setList(symbfacIVL, J, ii, indicesJ) ; } if ( frontOwners[J] == myid ) { /* ------------------------------------------ front is owned, send messages if necessary ------------------------------------------ */ firstMsgSent = sendMessages(J, myid, frontOwners, nfront, nproc, supportTable, par, symbfacIVL, firstMsgSent, firsttag, stats, comm, msglvl, msgFile) ; } if ( (K = par[J]) != -1 ) { if ( frontOwners[K] == myid && nLeft[K] > 0 ) { /* ------------------------------ merge bnd{J} into K cup bnd{K} ------------------------------ */ nDJ = nodwghts[J] ; IVL_listAndSize(symbfacIVL, J, &sizeJ, &indicesJ) ; IVL_listAndSize(symbfacIVL, K, &sizeK, &indicesK) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n merging J = %d into K = %d", J, K) ; fprintf(msgFile, ", nleft = %d", nLeft[K]) ; fprintf(msgFile, "\n before, boundary indices of J") ; IVfprintf(msgFile, sizeJ - nDJ, indicesJ + nDJ) ; fprintf(msgFile, "\n before, indices of K") ; IVfprintf(msgFile, sizeK, indicesK) ; } nLeft[K] = mergeIndices(sizeJ - nDJ, indicesJ + nDJ, sizeK, indicesK, nLeft[K]) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n after, indices of K, nleft = %d", nLeft[K]) ; IVfprintf(msgFile, sizeK, indicesK) ; } } if ( --nactiveChild[K] == 0 ) { /* ---------------------- put K on head of queue ---------------------- */ Ideq_insertAtHead(dequeue, K) ; } } } else { /* ---------------------- put J on tail of queue ---------------------- */ Ideq_insertAtTail(dequeue, J) ; } firstMsgSent = checkSendMessages(firstMsgSent, msglvl, msgFile) ; } /* ------------------------------------------ check for all sent messages to be received ------------------------------------------ */ do { firstMsgSent = checkSendMessages(firstMsgSent, msglvl, msgFile) ; } while ( firstMsgSent != NULL ) ; /* -------------------------------- post-process the adjacency lists -------------------------------- */ /* if ( msglvl > 2 ) { fprintf(msgFile, "\n bndwghts") ; IVfprintf(msgFile, nfront, bndwghts) ; fprintf(msgFile, "\n nodwghts") ; IVfprintf(msgFile, nfront, nodwghts) ; } frontIsSupported = supportTable + myid*nfront ; for ( J = 0 ; J < nfront ; J++ ) { if ( frontIsSupported[J] == 'Y' ) { IVL_listAndSize(symbfacIVL, J, &sizeJ, &indicesJ) ; for ( ii = 0 ; ii < sizeJ ; ii++ ) { if ( indicesJ[ii] == -1 ) { break ; } } if ( ii != sizeJ ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n WHOA, front J %d, sizeJ %d", J, sizeJ); fprintf(msgFile, "\n old bndwght = %d, new bndwght = %d", bndwghts[J], ii - nodwghts[J]) ; IVfprintf(msgFile, sizeJ, indicesJ) ; fflush(msgFile) ; } bndwghts[J] = ii - nodwghts[J] ; IVL_setList(symbfacIVL, J, ii, indicesJ) ; } } } */ /* ------------------------ free the working storage ------------------------ */ CVfree(supportTable) ; CVfree(status) ; IVfree(nactiveChild) ; IVfree(nLeft) ; Ideq_free(dequeue) ; FREE(p_msg) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- constructor created -- 98may20, cca ----------------------- */ static Msg * Msg_new ( void ) { Msg *msg ; ALLOCATE(msg, struct _Msg, 1) ; Msg_setDefaultFields(msg) ; return(msg) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98may20, cca ----------------------- */ static void Msg_setDefaultFields ( Msg *msg ) { msg->id = -1 ; msg->size = 0 ; msg->base = NULL ; msg->next = NULL ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data created -- 98may20, cca ----------------------- */ static void Msg_clearData ( Msg *msg ) { Msg_setDefaultFields(msg) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- free the object created -- 98may20, cca ----------------------- */ static void Msg_free ( Msg *msg ) { Msg_clearData(msg) ; FREE(msg) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- when front J is first examined, post Irecv's for its messages created -- 98may20, cca ------------------------------------------------------------- */ static Msg * wakeupFront ( int J, int myid, int owners[], char supportTable[], ETree *frontETree, IVL *symbfacIVL, int firsttag, int stats[], MPI_Comm comm, int msglvl, FILE *msgFile ) { Msg *first, *msg ; int I, nfront ; int *bndwghts, *fch, *indices, *nodwghts, *sib ; nfront = ETree_nfront(frontETree) ; first = NULL ; if ( owners[J] == myid ) { /* --------------------------------------------------- owned front, post messages for unsupported children --------------------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n waking up owned front %d", J) ; fflush(msgFile) ; } fch = ETree_fch(frontETree) ; sib = ETree_sib(frontETree) ; nodwghts = ETree_nodwghts(frontETree) ; bndwghts = ETree_bndwghts(frontETree) ; for ( I = fch[J] ; I != -1 ; I = sib[I] ) { if ( supportTable[I + myid*nfront] != 'Y' ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n unsupported child %d", I) ; fflush(msgFile) ; } /* -------------------------------------------------------- create a message, allocate temporary storage for indices -------------------------------------------------------- */ msg = Msg_new() ; msg->id = I ; msg->size = nodwghts[I] + bndwghts[I] ; msg->base = (void *) IVinit(msg->size, -1) ; msg->next = first ; first = msg ; if ( msglvl > 2 ) { fprintf(msgFile, "\n 1. posting Irecv, msg %p, source = %d, tag = %d", msg, owners[I], firsttag + I) ; fflush(msgFile) ; } stats[1]++ ; stats[3] += msg->size * sizeof(int) ; MPI_Irecv(msg->base, msg->size, MPI_INT, owners[I], firsttag + I, comm, &msg->req) ; } } } else if ( supportTable[J + myid*nfront] == 'Y' ) { /* -------------------------------------------------------- supported but not owned. create a message but point into storage for the indices in the symbolic IVL object. -------------------------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n waking up supported front %d", J) ; fflush(msgFile) ; } msg = Msg_new() ; msg->id = J ; IVL_listAndSize(symbfacIVL, J, &msg->size, &indices) ; msg->base = (void *) indices ; msg->next = first ; first = msg ; if ( msglvl > 2 ) { fprintf(msgFile, "\n 1. posting Irecv, msg %p, source = %d, tag = %d", msg, owners[J], firsttag + J) ; fflush(msgFile) ; } stats[1]++ ; stats[3] += msg->size * sizeof(int) ; MPI_Irecv(msg->base, msg->size, MPI_INT, owners[J], firsttag + J, comm, &msg->req) ; } return(first) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- check the messages waiting to be received for front J return value -- pointer to first message still to be received created -- 98may20, cca ------------------------------------------------------------- */ static Msg * checkRecvMessages ( int J, Msg *firstmsg, int nLeft[], int nodwghts[], IVL *symbfacIVL, int msglvl, FILE *msgFile ) { int flag, I, nDI, sizeI, sizeJ ; int *indicesI, *indicesJ ; MPI_Status status ; Msg *msg, *nextmsg ; if ( msglvl > 2 ) { fprintf(msgFile, "\n checking for received messages") ; fflush(msgFile) ; } for ( msg = firstmsg, firstmsg = NULL ; msg != NULL ; msg = nextmsg ) { nextmsg = msg->next ; msg->next = NULL ; if ( msglvl > 2 ) { fprintf(msgFile, "\n checking msg %p : id %d, size %d", msg, msg->id, msg->size) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( msglvl > 2 ) { fprintf(msgFile, ", flag = %d", flag) ; fflush(msgFile) ; } if ( flag != 0 ) { if ( msg->id == J ) { /* -------------------------------- J is supported but not owned, indices are in the symbolic IVL, free the message -------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n supported front %d", J) ; fflush(msgFile) ; } Msg_free(msg) ; } else { /* --------------------------------------------------- message is from an unsupported child merge indices, then free indices, then free message --------------------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n unsupported child front %d", msg->id) ; fflush(msgFile) ; } if ( nLeft[J] > 0 ) { I = msg->id ; nDI = nodwghts[I] ; sizeI = msg->size - nDI ; indicesI = (int *) msg->base + nDI ; /* sizeI = msg->size ; indicesI = (int *) msg->base ; */ IVL_listAndSize(symbfacIVL, J, &sizeJ, &indicesJ) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n merging I = %d into J = %d", I, J) ; fprintf(msgFile, ", nleft = %d", nLeft[J]) ; fprintf(msgFile, "\n before, boundary indices of I") ; IVfprintf(msgFile, sizeI, indicesI) ; fprintf(msgFile, "\n before, indices of J") ; IVfprintf(msgFile, sizeJ, indicesJ) ; } nLeft[J] = mergeIndices(sizeI, indicesI, sizeJ, indicesJ, nLeft[J]) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n after, indices of J, nleft = %d", nLeft[J]) ; IVfprintf(msgFile, sizeJ, indicesJ) ; } IVfree(msg->base) ; Msg_free(msg) ; } } else { /* ---------------------------- keep the message on the list ---------------------------- */ msg->next = firstmsg ; firstmsg = msg ; } } return(firstmsg) ; } /*--------------------------------------------------------------------*/ /* */ static Msg * sendMessages ( int J, int myid, int owners[], int nfront, int nproc, char supportTable[], int par[], IVL *symbfacIVL, Msg *firstMsgSent, int firsttag, int stats[], MPI_Comm comm, int msglvl, FILE *msgFile ) { int destination, K, sizeJ ; int *indicesJ ; Msg *msg ; if ( msglvl > 2 ) { fprintf(msgFile, "\n ready to send messages") ; fflush(msgFile) ; } /* ------------------------------- get size and pointer to indices ------------------------------- */ IVL_listAndSize(symbfacIVL, J, &sizeJ, &indicesJ) ; /* ----------------------------------- send indices to supported processes ----------------------------------- */ for ( destination = 0 ; destination < nproc ; destination++ ) { if ( destination != myid && supportTable[J + destination*nfront] == 'Y' ) { msg = Msg_new() ; msg->id = J ; msg->size = sizeJ ; msg->base = (void *) indicesJ ; msg->next = firstMsgSent ; firstMsgSent = msg ; if ( msglvl > 2 ) { fprintf(msgFile, "\n 1. posting Isend, msg %p, destination = %d, tag = %d", msg, destination, firsttag + J) ; fflush(msgFile) ; } stats[0]++ ; stats[2] += msg->size * sizeof(int) ; MPI_Isend(msg->base, msg->size, MPI_INT, destination, firsttag + J, comm, &msg->req) ; } } if ( (K = par[J]) != -1 && supportTable[J + owners[K]*nfront] != 'Y' ) { /* ---------------------------------------------------- send indices to unsupported process that owns parent ---------------------------------------------------- */ msg = Msg_new() ; msg->id = J ; msg->size = sizeJ ; msg->base = (void *) indicesJ ; msg->next = firstMsgSent ; firstMsgSent = msg ; if ( msglvl > 2 ) { fprintf(msgFile, "\n 2. posting Isend, msg %p, destination = %d, tag = %d", msg, owners[K], firsttag + J) ; fflush(msgFile) ; } stats[0]++ ; stats[2] += msg->size * sizeof(int) ; MPI_Isend(msg->base, msg->size, MPI_INT, owners[K], firsttag + J, comm, &msg->req) ; } return(firstMsgSent) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- merge indices in indJ[sizeJ] into indK[sizeK], there are nleft free locations at the end of indK[]. both indJ[sizeJ] and indK[sizeK] are in ascending order. return value is the number of present free locations in indK[]. created -- 98may20, cca --------------------------------------------------------------- */ static int mergeIndices ( int sizeJ, int indJ[], int sizeK, int indK[], int nleft ) { int firstK, ii, jj, jlast, kk, v ; firstK = indK[0] ; kk = jlast = sizeK - nleft ; ii = 0, jj = 0 ; while ( ii < sizeJ && jj < jlast ) { v = indJ[ii] ; if ( v < firstK ) { ii++ ; } else if ( v < indK[jj] ) { indK[kk++] = v ; ii++ ; } else if ( v == indK[jj] ) { ii++, jj++ ; } else { jj++ ; } } for ( ; ii < sizeJ ; ii++ ) { v = indJ[ii] ; if ( v >= 0 ) { indK[kk++] = indJ[ii] ; } } if ( kk > jlast ) { IVqsortUp(kk, indK) ; } return(sizeK - kk) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ load the owned index lists with information from the InpMtx object created -- 98may20, cca ------------------------------------------------------------------ */ static void loadInternalIndices ( ETree *frontETree, InpMtx *inpmtxA, InpMtx *inpmtxB, IV *frontOwnersIV, int myid, IVL *symbfacIVL, int msglvl, FILE *msgFile ) { int count, ii, J, nfront, nvtx, off, sizeJ, v, vsize, w ; int *frontOwners, *head, *indicesJ, *link, *mark, *vind, *vtxToFront ; nfront = ETree_nfront(frontETree) ; nvtx = ETree_nvtx(frontETree) ; vtxToFront = ETree_vtxToFront(frontETree) ; frontOwners = IV_entries(frontOwnersIV) ; /* ------------------------------------------------- set up the lists of vertices for each owned front ------------------------------------------------- */ head = IVinit(nfront, -1) ; link = IVinit(nvtx, -1) ; mark = IVinit(nvtx, -1) ; for ( v = 0 ; v < nvtx ; v++ ) { J = vtxToFront[v] ; if ( frontOwners[J] == myid ) { link[v] = head[J] ; head[J] = v ; } } /* -------------------------------------------------------- load the internal indices into the owned adjacency lists -------------------------------------------------------- */ for ( J = 0 ; J < nfront ; J++ ) { if ( frontOwners[J] == myid ) { IVL_listAndSize(symbfacIVL, J, &sizeJ, &indicesJ) ; count = 0 ; /* --------------------- load internal indices --------------------- */ for ( v = head[J] ; v != -1 ; v = link[v] ) { mark[v] = J ; indicesJ[count++] = v ; } /* ----------------------------------------- load indices from the first InpMtx object ----------------------------------------- */ for ( v = head[J] ; v != -1 && count < sizeJ ; v = link[v] ) { InpMtx_vector(inpmtxA, v, &vsize, &vind) ; for ( ii = 0 ; ii < vsize && count < sizeJ ; ii++ ) { off = vind[ii] ; if ( off >= 0 ) { w = v + off ; } else { w = v - off ; } if ( vtxToFront[w] < J ) { fprintf(msgFile, "\n error, J = %d, w = %d, map[%d] = %d", J, w, w, vtxToFront[w]) ; exit(-1) ; } if ( mark[w] != J ) { mark[w] = J ; indicesJ[count++] = w ; } } } if ( inpmtxB != NULL ) { /* ------------------- load indices from B ------------------- */ for ( v = head[J] ; v != -1 && count < sizeJ ; v = link[v] ) { InpMtx_vector(inpmtxB, v, &vsize, &vind) ; for ( ii = 0 ; ii < vsize && count < sizeJ ; ii++ ) { off = vind[ii] ; if ( off >= 0 ) { w = v + off ; } else { w = v - off ; } if ( vtxToFront[w] < J ) { fprintf(msgFile, "\n error, J = %d, w = %d, map[%d] = %d", J, w, w, vtxToFront[w]) ; exit(-1) ; } if ( mark[w] != J ) { mark[w] = J ; indicesJ[count++] = w ; } } } } /* ----------------------------------- sort the indices in ascending order ----------------------------------- */ IVqsortUp(count, indicesJ) ; } } /* ------------------------ free the working storage ------------------------ */ IVfree(head) ; IVfree(link) ; IVfree(mark) ; return ; } /*--------------------------------------------------------------------*/ /* */ static Msg * checkSendMessages ( Msg *firstMsgSent, int msglvl, FILE *msgFile ) { int flag ; MPI_Status status ; Msg *msg, *nextmsg ; if ( firstMsgSent != NULL ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n checking for sent messages") ; fflush(msgFile) ; } for ( msg = firstMsgSent, firstMsgSent = NULL ; msg != NULL ; msg = nextmsg ) { nextmsg = msg->next ; if ( msglvl > 2 ) { fprintf(msgFile, "\n checking msg %p : id %d, size %d", msg, msg->id, msg->size) ; fflush(msgFile) ; } MPI_Test(&msg->req, &flag, &status) ; if ( msglvl > 2 ) { fprintf(msgFile, ", flag = %d", flag) ; fflush(msgFile) ; } if ( flag != 0 ) { if ( msglvl > 2 ) { fprintf(msgFile, ", free'ing object") ; fflush(msgFile) ; } Msg_free(msg) ; } else { msg->next = firstMsgSent ; firstMsgSent = msg ; } } } return(firstMsgSent) ; } /*--------------------------------------------------------------------*/ message is from an unsupported child merge indices, then free indices, then free message --------------------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n unsupported child front %d", msg->id) ; fflush(msgFileMPI/src/utilities.c010064400020550007177000000011050655671743000154760ustar00clevecompmath00000400000006/* utilities.c */ #include "../spoolesMPI.h" /*--------------------------------------------------------------------*/ /* ---------------------------- return the maximum tag value created -- 98jan08, cca ---------------------------- */ int maxTagMPI ( MPI_Comm comm ) { int *iptr, flag, rc, tag_bound ; iptr = &tag_bound ; rc = MPI_Attr_get(comm, MPI_TAG_UB, (void **) &iptr, &flag) ; if ( flag == 0 ) { tag_bound = -1 ; } else { tag_bound = *iptr ; } return(tag_bound) ; } /*--------------------------------------------------------------------*/ MPI/drivers/do_AllInOneMPI010075500020550007177000000012560665164115600166310ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res.serial set msgFile = stdout set msgFile = res set type = 2 set symmetryflag = 0 set pivotingflag = 0 set seed = 10101 set nproc = 4 # # for solaris with mpich # set pgFile = allInOneMPI.$nproc.pg /usr/local/mpi/bin/mpirun -p4pg $pgFile \ allInOneMPI $msglvl $msgFile \ $type $symmetryflag $pivotingflag $seed # # for sgi # # mpirun -np $nproc \ # allInOneMPI $msglvl $msgFile \ # $type $symmetryflag $pivotingflag $seed # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # allInOneMPI $msglvl $msgFile \ # $type $symmetryflag $pivotingflag $seed MPI/drivers/do_Graph_Bcast010075500020550007177000000011540665065430400167720ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set msgFile = res set type = 3 set nvtx = 1000 set nitem = 5000 set root = 1 set seed = 10101 set nproc = 4 # # for solaris with mpich # set pgFile = Graph_Bcast$nproc.pg # /usr/local/mpi/bin/mpirun -p4pg $pgFile \ /usr/local/mpich-1.0.13/bin/mpirun -p4pg $pgFile \ testGraph_Bcast $msglvl $msgFile $type $nvtx $nitem $root $seed # # for sgi # # mpirun -np $nproc \ # testGraph_Bcast $msglvl $msgFile $type $nvtx $nitem $root $seed # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testGraph_Bcast $msglvl $msgFile $type $nvtx $nitem $root $seed MPI/drivers/do_IVL_Bcast010075500020550007177000000011530665065430700163650ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set msgFile = res set nlist = 1000 set maxlistsize = 200 set root = 1 set seed = 10101 set nproc = 4 # # for solaris with mpich # set pgFile = IVL_Bcast$nproc.pg # /usr/local/mpi/bin/mpirun -p4pg $pgFile \ /usr/local/mpich-1.0.13/bin/mpirun -p4pg $pgFile \ testIVL_Bcast $msglvl $msgFile $nlist $maxlistsize $root $seed # # for sgi # # mpirun -np $nproc \ # testIVL_Bcast $msglvl $msgFile $nlist $maxlistsize $root $seed # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testIVL_Bcast $msglvl $msgFile $nlist $maxlistsize $root $seed MPI/drivers/do_IVL_alltoall010075500020550007177000000007750665065431100171410ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 4 set msgFile = stdout set msgFile = res set n = 10 set seed = 10101 set nproc = 4 # # for solaris with mpich # set pgFile = IVL_alltoall$nproc.pg # /usr/local/mpi/bin/mpirun -p4pg $pgFile \ /usr/local/mpich-1.0.13/bin/mpirun -p4pg $pgFile \ testIVL_alltoall $msglvl $msgFile $n $seed # # for sgi # # mpirun -np $nproc \ # testIVL_alltoall $msglvl $msgFile $n $seed # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testIVL_alltoall $msglvl $msgFile $n $seed MPI/drivers/do_IVLallgather010075500020550007177000000010130665065431300171250ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set msgFile = res set nlist = 1000 set seed = 10101 set nproc = 4 # # for solaris with mpich # set pgFile = IVLallgather$nproc.pg # /usr/local/mpi/bin/mpirun -p4pg $pgFile \ /usr/local/mpich-1.0.13/bin/mpirun -p4pg $pgFile \ testIVLallgather $msglvl $msgFile $nlist $seed # # for sgi # # mpirun -np $nproc \ # testIVLallgather $msglvl $msgFile $nlist $seed # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testIVLallgather $msglvl $msgFile $nlist $seed MPI/drivers/do_IVallgather010075500020550007177000000007740665065431500170300ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set msgFile = res set n = 10000 set seed = 10101 set nproc = 8 # # for solaris with mpich # set pgFile = IVallgather$nproc.pg # /usr/local/mpi/bin/mpirun -p4pg $pgFile \ /usr/local/mpich-1.0.13/bin/mpirun -p4pg $pgFile \ testIVallgather $msglvl $msgFile $n $seed # # for sgi # # mpirun -np $nproc \ # testIVallgather $msglvl $msgFile $n $seed # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testIVallgather $msglvl $msgFile $n $seed MPI/drivers/do_MMM010075500020550007177000000024150665065432000152420ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res.serial set msgFile = stdout set msgFile = res set nrowA = 30 set ncolA = 30 set nentA = 200 set ncolX = 4 # coordType = 1 --> store by rows # coordType = 2 --> store by columns # coordType = 3 --> store by chevrons set coordType = 2 # inputMode = 1 --> indices and real entries # inputMode = 2 --> indices and complex entries set inputMode = 2 # symflag = 0 --> symmetric matrix # symflag = 1 --> Hermitian matrix # symflag = 2 --> nonsymmetric matrix set symflag = 2 # opflag = 0 --> multiply with A # opflag = 1 --> multiply with A^T # opflag = 2 --> multiply with A^H set opflag = 2 set real = 0.5 set imag = 2.0 set seed = 10101 set nproc = 4 # # for solaris with mpich # set pgFile = MMM$nproc.pg /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testMMM \ $msglvl $msgFile $nrowA $ncolA $nentA $ncolX $coordType $inputMode \ $symflag $opflag $seed $real $imag # # for sgi # # mpirun -np $nproc \ # testMMM \ # $msglvl $msgFile $nrowA $ncolA $nentA $ncolX $coordType $inputMode \ # $symflag $opflag $seed $real $imag # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testMMM \ # $msglvl $msgFile $nrowA $ncolA $nentA $ncolX $coordType $inputMode \ # $symflag $opflag $seed $real $imag MPI/drivers/do_ScatterDenseMtx010075500020550007177000000013360665065432200176740ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set msgFile = res set type = 1 set type = 2 set nrow = 100 set ncol = 4 set inc1 = 1 set inc2 = $nrow set inc1 = $ncol set inc2 = 1 set seed = 10101 set nproc = 4 set root = 1 # # for solaris with mpich # set pgFile = scatterDenseMtx$nproc.pg /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testScatterDenseMtx \ $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed $root # # for sgi # # mpirun -np $nproc \ # testScatterDenseMtx \ # $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed $root # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testScatterDenseMtx \ # $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed $root MPI/drivers/do_ScatterInpMtx010075500020550007177000000013240665065432400173630ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res.serial set msgFile = stdout set msgFile = res set neqns = 2000 set nent = 10000 set seed = 10101 set coordType = 3 set inputMode = 2 set root = 1 set nproc = 4 # # for solaris with mpich # set pgFile = scatterInpMtx$nproc.pg /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testScatterInpMtx \ $msglvl $msgFile $neqns $nent $seed $coordType $inputMode $root # # for sgi # # mpirun -np $nproc \ # testScatterInpMtx \ # $msglvl $msgFile $neqns $nent $seed $coordType $inputMode $root # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testScatterInpMtx \ # $msglvl $msgFile $neqns $nent $seed $coordType $inputMode $root MPI/drivers/do_SplitDenseMtx010075500020550007177000000012640665065432600173660ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set msgFile = res set type = 2 set type = 1 set nrow = 100 set ncol = 4 set inc1 = 1 set inc2 = $nrow set inc1 = $ncol set inc2 = 1 set seed = 10101 set nproc = 4 # # for solaris with mpich # set pgFile = splitDenseMtx$nproc.pg /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testSplitDenseMtx \ $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed # # for sgi # # mpirun -np $nproc \ # testSplitDenseMtx \ # $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testSplitDenseMtx \ # $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed MPI/drivers/do_SplitInpMtx010075500020550007177000000012440665065433000170470ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res.serial set msgFile = stdout set msgFile = res set neqns = 20 set nent = 100 set seed = 10101 set coordType = 3 set inputMode = 2 set nproc = 4 # # for solaris with mpich # set pgFile = splitInpMtx$nproc.pg /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testSplitInpMtx \ $msglvl $msgFile $neqns $nent $seed $coordType $inputMode # # for sgi # # mpirun -np $nproc \ # testSplitInpMtx \ # $msglvl $msgFile $neqns $nent $seed $coordType $inputMode # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testSplitInpMtx \ # $msglvl $msgFile $neqns $nent $seed $coordType $inputMode MPI/drivers/do_gather010075500020550007177000000012670665065433100160740ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set msgFile = res set type = 1 set type = 2 set nrow = 2000 set ncol = 40 # column major set inc1 = 1 set inc2 = $nrow # row major set inc1 = $ncol set inc2 = 1 set seed = 1010101 set nproc = 4 # # for solaris with mpich # set pgFile = gather$nproc.pg /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testGather \ $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed # # for sgi # # mpirun -np $nproc \ # testGather \ # $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testGather \ # $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed inc2 = $nrow # row major set inc1 = $ncol set inc2 = 1 set seed = 1010101 set nproc = 4 # # for solaris with mpich # set pgFile = gather$nproc.pg /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testGather \ $msglvl $msgFile $type $nrow $ncol $inc1 $inc2 $seed # # for sgi # # mpirun -np $nproc \ # testGather \ MPI/drivers/do_gridMPI010075500020550007177000000025760665065434500161260ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res3D.64 set msgFile = res3D set msgFile = stdout set msgFile = res set n1 = 7 set n2 = 7 set n3 = 7 set maxzeros = 0 set maxzeros = 1000 set maxsize = 1000 set maxsize = 64 set seed = 10101 set type = 1 set symmetryflag = 2 set sparsityflag = 0 set pivotingflag = 0 set tau = 10 set droptol = 1.e-50 set randomFlag = 1 set nrhs = 4 set profile = 0 set nproc = 4 set maptype = 3 set cutoff = 0.125 set lookahead = 0 # # for solaris with mpich # set pgFile = gridMPI$nproc.pg /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testGridMPI \ $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize $seed \ $type $symmetryflag $sparsityflag $pivotingflag $tau $droptol \ $lookahead $nrhs $maptype $cutoff # # for sgi # # mpirun -np $nproc \ # testGridMPI \ # $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize $seed \ # $type $symmetryflag $sparsityflag $pivotingflag $tau $droptol \ # $lookahead $nrhs $maptype $cutoff # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testGridMPI \ # $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize $seed \ # $type $symmetryflag $sparsityflag $pivotingflag $tau $droptol \ # $lookahead $nrhs $maptype $cutoff MPI/drivers/do_kwu010075500020550007177000000044470665065435400154400ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res3D.64 set msgFile = res3D set msgFile = stdout set msgFile = res set n1 = 15 set n2 = 15 set n3 = 15 set maxzeros = 0 set maxzeros = 1000 set maxsize = 1000 set maxsize = 64 set seed = 10101 set type = 1 set symmetryflag = 0 set sparsityflag = 0 set pivotingflag = 0 set tau = 10 set droptol = 1.e-50 set randomFlag = 1 set nrhs = 4 set profile = 0 set nproc = 4 set maptype = 3 set cutoff = 0.125 set lookahead = 0 # # for solaris with mpich # set type = 1 echo ' real symmetric tests' foreach nproc ( 2 4 6 8 ) echo ' ' $nproc ' processors' set pgFile = gridMPI$nproc.pg foreach n ( 31 33 35 37 39 41 43 45 47 49 51 ) set n1 = $n set n2 = $n set n3 = $n echo ' ' $n1 ' x ' $n2 ' x ' $n3 ' grids' set msgFile = real.$n.$nproc /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testGridMPI \ $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize $seed \ $type $symmetryflag $sparsityflag $pivotingflag $tau $droptol \ $lookahead $nrhs $maptype $cutoff end end set type = 2 echo ' complex symmetric tests' foreach nproc ( 2 4 6 8 ) echo ' ' $nproc ' processors' set pgFile = gridMPI$nproc.pg foreach n ( 31 33 35 37 39 41 43 45 47 49 51 ) set n1 = $n set n2 = $n set n3 = $n echo ' ' $n1 ' x ' $n2 ' x ' $n3 ' grids' set msgFile = complex.$n.$nproc /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testGridMPI \ $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize $seed \ $type $symmetryflag $sparsityflag $pivotingflag $tau $droptol \ $lookahead $nrhs $maptype $cutoff end end # # for sgi # # mpirun -np $nproc \ # testGridMPI \ # $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize $seed \ # $type $symmetryflag $sparsityflag $pivotingflag $tau $droptol \ # $lookahead $nrhs $maptype $cutoff # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testGridMPI \ # $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize $seed \ # $type $symmetryflag $sparsityflag $pivotingflag $tau $droptol \ # $lookahead $nrhs $maptype $cutoff MPI/drivers/do_patchAndGo010075500020550007177000000017400665065436200166320ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res.serial set msgFile = stdout set msgFile = res set type = 1 set symmetryflag = 0 set seed = 9999 set patchAndGoFlag = 0 set toosmall = 1.e-9 set fudge = 1.e-9 set storeids = 1 set storevalues = 1 set nproc = 4 # # for solaris with mpich # set pgFile = patchAndGo.$nproc.pg /usr/local/mpi/bin/mpirun -p4pg $pgFile \ patchAndGoMPI $msglvl $msgFile $type $symmetryflag \ $patchAndGoFlag $toosmall $fudge \ $storeids $storevalues $seed # # for sgi # # mpirun -np $nproc \ # patchAndGoMPI $msglvl $msgFile $type $symmetryflag \ # $patchAndGoFlag $toosmall $fudge \ # $storeids $storevalues $seed # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # patchAndGoMPI $msglvl $msgFile $type $symmetryflag \ # $patchAndGoFlag $toosmall $fudge \ # $storeids $storevalues $seed MPI/drivers/do_symbfac010075500020550007177000000012130665065437000162400ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 5 set msgFile = stdout set msgFile = res set seed = 10101 set nproc = 4 set matrices = ../../Matrices set matrix = R2D100 set inGraphFile = $matrices/$matrix/orig0.graphf set inETreeFile = $matrices/$matrix/nd.etreef # # for solaris with mpich # set pgFile = symbfac$nproc.pg echo $pgFile /usr/local/mpi/bin/mpirun -p4pg $pgFile \ testSymbFac $msglvl $msgFile $inGraphFile $inETreeFile $seed # # for sgi # # mpirun -np $nproc \ # testSymbFac $msglvl $msgFile $inGraphFile $inETreeFile $seed # # for hp # # /opt/mpi/bin/mpirun -np $nproc \ # testSymbFac $msglvl $msgFile $inGraphFile $inETreeFile $seed MPI/drivers/makefile010064400020550007177000000045130665340700300157020ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- # # set suffix rule *.c --> *.o # .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $(MPI_INCLUDE_DIR) $< # #----------------------------------------------------------------------- LIBS = ../src/spoolesMPI.a ../../spooles.a $(MPI_LIBS) -lm DRIVERS = allInOneMPI patchAndGoMPI testGridMPI testIV_allgather \ testIVL_allgather testIVL_alltoall testSplitDenseMtx \ testSplitInpMtx testSymbFac testGather testMMM \ testIVL_Bcast testGraph_Bcast \ testScatterDenseMtx testScatterInpMtx libs : cd ../src ; make spoolesMPI.a drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} allInOneMPI : allInOneMPI.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} patchAndGoMPI : patchAndGoMPI.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testGather : testGather.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testGraph_Bcast : testGraph_Bcast.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testGridMPI : testGridMPI.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testMMM : testMMM.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testScatterDenseMtx : testScatterDenseMtx.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${LIBS} testScatterInpMtx : testScatterInpMtx.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${LIBS} testSymbFac : testSymbFac.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ ${LIBS} testSplitDenseMtx : testSplitDenseMtx.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testSplitInpMtx : testSplitInpMtx.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testIV_allgather : testIV_allgather.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testIVL_allgather : testIVL_allgather.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testIVL_alltoall : testIVL_alltoall.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testIVL_Bcast : testIVL_Bcast.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} MPI/drivers/allInOneMPI.c010064400020550007177000000433050665165313700164300ustar00clevecompmath00000400000006/* allInOneMPI.c */ #include "../spoolesMPI.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ------------------------------------------------------------ all-in-one MPI program for each process order, factor and solve A X = Y ( 1) read in matrix entries and form InpMtx object for A ( 2) order the system using minimum degree ( 3) permute the front tree ( 4) create the owners map IV object ( 5) permute the matrix A and redistribute ( 6) compute the symbolic factorization ( 7) compute the numeric factorization ( 8) split the factors into submatrices ( 9) create the submatrix map and redistribute (10) read in right hand side entries and form dense matrix DenseMtx object for Y (11) permute and redistribute Y (12) solve the linear system (13) gather X on processor 0 created -- 98jun13, cca ------------------------------------------------------------ */ /*--------------------------------------------------------------------*/ char buffer[128] ; Chv *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxX, *mtxY, *newY ; SubMtxManager *mtxmanager, *solvemanager ; FrontMtx *frontmtx ; InpMtx *mtxA, *newA ; double cutoff, droptol = 0.0, minops, tau = 100. ; double cpus[20] ; double *opcounts ; DV *cumopsDV ; ETree *frontETree ; FILE *inputFile, *msgFile ; Graph *graph ; int error, firsttag, ient, irow, jcol, lookahead = 0, msglvl, myid, nedges, nent, neqns, nmycol, nproc, nrhs, nrow, pivotingflag, root, seed, symmetryflag, type ; int stats[20] ; int *rowind ; IV *oldToNewIV, *ownedColumnsIV, *ownersIV, *newToOldIV, *vtxmapIV ; IVL *adjIVL, *symbfacIVL ; SolveMap *solvemap ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 7 ) { fprintf(stdout, "\n usage: %s msglvl msgFile type symmetryflag pivotingflag seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 (SPOOLES_REAL) -- real entries" "\n 2 (SPOOLES_COMPLEX) -- complex entries" "\n symmetryflag -- type of matrix" "\n 0 (SPOOLES_SYMMETRIC) -- symmetric entries" "\n 1 (SPOOLES_HERMITIAN) -- Hermitian entries" "\n 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric entries" "\n pivotingflag -- type of pivoting" "\n 0 (SPOOLES_NO_PIVOTING) -- no pivoting used" "\n 1 (SPOOLES_PIVOTING) -- pivoting used" "\n seed -- random number seed" "\n " "\n note: matrix entries are read in from matrix.k.input" "\n where k is the process number" "\n note: rhs entries are read in from rhs.k.input" "\n where k is the process number" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { sprintf(buffer, "res.%d", myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], buffer) ; return(-1) ; } } type = atoi(argv[3]) ; symmetryflag = atoi(argv[4]) ; pivotingflag = atoi(argv[5]) ; seed = atoi(argv[6]) ; IVzero(20, stats) ; DVzero(20, cpus) ; fprintf(msgFile, "\n\n input data" "\n msglvl = %d" "\n msgFile = %s" "\n type = %d" "\n symmetryflag = %d" "\n pivotingflag = %d" "\n seed = %d", msglvl, argv[2], type, symmetryflag, pivotingflag, seed) ; fflush(msgFile) ; MPI_Barrier(MPI_COMM_WORLD) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 1: read the entries from the input file and create the InpMtx object -------------------------------------------- */ sprintf(buffer, "haggar.mtx.%d.input", myid) ; inputFile = fopen(buffer, "r") ; fscanf(inputFile, "%d %d %d", &neqns, &neqns, &nent) ; MPI_Barrier(MPI_COMM_WORLD) ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, 0) ; if ( type == SPOOLES_REAL ) { double value ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else if ( type == SPOOLES_COMPLEX ) { double imag, real ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; InpMtx_sortAndCompress(mtxA) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- STEP 2: read the rhs entries from the rhs input file and create the DenseMtx object for Y ---------------------------------------------------- */ sprintf(buffer, "haggar.rhs.%d.input", myid) ; inputFile = fopen(buffer, "r") ; fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxY = DenseMtx_new() ; DenseMtx_init(mtxY, type, 0, 0, nrow, nrhs, 1, nrow) ; DenseMtx_rowIndices(mtxY, &nrow, &rowind) ; if ( type == SPOOLES_REAL ) { double value ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", rowind + irow) ; for ( jcol = 0 ; jcol < nrhs ; jcol++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxY, irow, jcol, value) ; } } } if ( type == SPOOLES_COMPLEX ) { double imag, real ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", rowind + irow) ; for ( jcol = 0 ; jcol < nrhs ; jcol++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxY, irow, jcol, real, imag) ; } } } fclose(inputFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 2 : find a low-fill ordering (1) create the Graph object (2) order the graph using multiple minimum degree (3) find out who has the best ordering w.r.t. op count, and broadcast that front tree object ------------------------------------------------------- */ graph = Graph_new() ; adjIVL = InpMtx_MPI_fullAdjacency(mtxA, stats, msglvl, msgFile, MPI_COMM_WORLD) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } frontETree = orderViaMMD(graph, seed + myid, msglvl, msgFile) ; Graph_free(graph) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } opcounts = DVinit(nproc, 0.0) ; opcounts[myid] = ETree_nFactorOps(frontETree, type, symmetryflag) ; MPI_Allgather((void *) &opcounts[myid], 1, MPI_DOUBLE, (void *) opcounts, 1, MPI_DOUBLE, MPI_COMM_WORLD) ; minops = DVmin(nproc, opcounts, &root) ; DVfree(opcounts) ; frontETree = ETree_MPI_Bcast(frontETree, root, msglvl, msgFile, MPI_COMM_WORLD) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n best front tree") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 3: get the permutations, permute the front tree, permute the matrix and right hand side. ------------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; ETree_permuteVertices(frontETree, oldToNewIV) ; InpMtx_permute(mtxA, IV_entries(oldToNewIV), IV_entries(oldToNewIV)) ; if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; DenseMtx_permuteRows(mtxY, oldToNewIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- STEP 4: generate the owners map IV object and the map from vertices to owners ------------------------------------------- */ cutoff = 1./(2*nproc) ; cumopsDV = DV_new() ; DV_init(cumopsDV, nproc, NULL) ; ownersIV = ETree_ddMap(frontETree, type, symmetryflag, cumopsDV, cutoff) ; DV_free(cumopsDV) ; vtxmapIV = IV_new() ; IV_init(vtxmapIV, neqns, NULL) ; IVgather(neqns, IV_entries(vtxmapIV), IV_entries(ownersIV), ETree_vtxToFront(frontETree)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n map from fronts to owning processes") ; IV_writeForHumanEye(ownersIV, msgFile) ; fprintf(msgFile, "\n\n map from vertices to owning processes") ; IV_writeForHumanEye(vtxmapIV, msgFile) ; fflush(msgFile) ; } if ( myid == 0 ) { IV_writeToFile(ownersIV, "../../Tree/drivers/haggar.ivf") ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- STEP 5: redistribute the matrix and right hand side --------------------------------------------------- */ firsttag = 0 ; newA = InpMtx_MPI_split(mtxA, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; firsttag++ ; InpMtx_free(mtxA) ; mtxA = newA ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n split InpMtx") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } newY = DenseMtx_MPI_splitByRows(mtxY, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; DenseMtx_free(mtxY) ; mtxY = newY ; firsttag += nproc ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n split DenseMtx Y") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 6: compute the symbolic factorization ------------------------------------------ */ symbfacIVL = SymbFac_MPI_initFromInpMtx(frontETree, ownersIV, mtxA, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; firsttag += frontETree->nfront ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n local symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- STEP 7: initialize the front matrix ----------------------------------- */ mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; frontmtx = FrontMtx_new() ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, pivotingflag, NO_LOCK, myid, ownersIV, mtxmanager, msglvl, msgFile) ; /*--------------------------------------------------------------------*/ /* --------------------------------- STEP 8: compute the factorization --------------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 0) ; rootchv = FrontMtx_MPI_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, ownersIV, lookahead, &error, cpus, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; ChvManager_free(chvmanager) ; firsttag += 3*frontETree->nfront + 2 ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n numeric factorization") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } if ( error >= 0 ) { fprintf(stderr, "\n proc %d : factorization error at front %d", myid, error) ; MPI_Finalize() ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ STEP 9: post-process the factorization and split the factor matrices into submatrices ------------------------------------------------ */ FrontMtx_MPI_postProcess(frontmtx, ownersIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; firsttag += 5*nproc ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n numeric factorization after post-processing"); FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- STEP 10: create the solve map object ----------------------------------- */ solvemap = SolveMap_new() ; SolveMap_ddMap(solvemap, frontmtx->symmetryflag, FrontMtx_upperBlockIVL(frontmtx), FrontMtx_lowerBlockIVL(frontmtx), nproc, ownersIV, FrontMtx_frontTree(frontmtx), seed, msglvl, msgFile); if ( msglvl > 2 ) { SolveMap_writeForHumanEye(solvemap, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- STEP 11: redistribute the submatrices of the factors ---------------------------------------------------- */ FrontMtx_MPI_split(frontmtx, solvemap, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n numeric factorization after split") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ STEP 13: permute and redistribute Y if necessary ------------------------------------------------ */ if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { IV *rowmapIV ; /* ---------------------------------------------------------- pivoting has taken place, redistribute the right hand side to match the final rows and columns in the fronts ---------------------------------------------------------- */ rowmapIV = FrontMtx_MPI_rowmapIV(frontmtx, ownersIV, msglvl, msgFile, MPI_COMM_WORLD) ; newY = DenseMtx_MPI_splitByRows(mtxY, rowmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; DenseMtx_free(mtxY) ; mtxY = newY ; IV_free(rowmapIV) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs matrix after split") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 14: create a solution DenseMtx object ------------------------------------------ */ ownedColumnsIV = FrontMtx_ownedColumnsIV(frontmtx, myid, ownersIV, msglvl, msgFile) ; nmycol = IV_size(ownedColumnsIV) ; mtxX = DenseMtx_new() ; if ( nmycol > 0 ) { DenseMtx_init(mtxX, type, 0, 0, nmycol, nrhs, 1, nmycol) ; DenseMtx_rowIndices(mtxX, &nrow, &rowind) ; IVcopy(nmycol, rowind, IV_entries(ownedColumnsIV)) ; } /*--------------------------------------------------------------------*/ /* -------------------------------- STEP 15: solve the linear system -------------------------------- */ solvemanager = SubMtxManager_new() ; SubMtxManager_init(solvemanager, NO_LOCK, 0) ; FrontMtx_MPI_solve(frontmtx, mtxX, mtxY, solvemanager, solvemap, cpus, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; SubMtxManager_free(solvemanager) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n solution in new ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- STEP 15: permute the solution into the original ordering and assemble the solution onto processor zero -------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n solution in old ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } IV_fill(vtxmapIV, 0) ; firsttag++ ; mtxX = DenseMtx_MPI_splitByRows(mtxX, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; if ( myid == 0 && msglvl > 0 ) { fprintf(msgFile, "\n\n complete solution in old ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ MPI_Finalize() ; return(1) ; } /*--------------------------------------------------------------------*/ MPI/drivers/patchAndGoMPI.c010064400020550007177000000457000665165553100167400ustar00clevecompmath00000400000006/* patchAndGoMPI.c */ #include "../spoolesMPI.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ------------------------------------------------------------ all-in-one MPI program for each process order, factor and solve A X = Y We use a patch-and-go strategy for the factorization without pivoting ( 1) read in matrix entries and form InpMtx object for A ( 2) order the system using minimum degree ( 3) permute the front tree ( 4) create the owners map IV object ( 5) permute the matrix A and redistribute ( 6) compute the symbolic factorization ( 7) compute the numeric factorization ( 8) split the factors into submatrices ( 9) create the submatrix map and redistribute (10) read in right hand side entries and form dense matrix DenseMtx object for Y (11) permute and redistribute Y (12) solve the linear system (13) gather X on processor 0 created -- 98jun13, cca ------------------------------------------------------------ */ /*--------------------------------------------------------------------*/ char buffer[20] ; Chv *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxX, *mtxY ; double fudge, toosmall ; SubMtxManager *mtxmanager, *solvemanager ; FrontMtx *frontmtx ; InpMtx *keepmtx, *mtxA ; double cutoff, imag, minops, real, tau = 100., value ; double cpus[20] ; double *opcounts ; DV *cumopsDV ; ETree *frontETree ; FILE *inputFile, *msgFile ; Graph *graph ; int error, firsttag, ient, irow, jcol, msglvl, myid, nedges, nent, neqns, nmycol, nproc, nrhs, nrow, patchAndGoFlag, root, seed, storeids, storevalues, symmetryflag, type ; int stats[20] ; int *rowind ; IV *oldToNewIV, *ownedColumnsIV, *ownersIV, *newToOldIV, *vtxmapIV ; IVL *adjIVL, *symbfacIVL ; SolveMap *solvemap ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; fprintf(stdout, "\n proc %d, argc = %d", myid, argc) ; fflush(stdout) ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 11 ) { fprintf(stdout, "\n usage: %s msglvl msgFile type symmetryflag patchAndGoFlag" "\n fudge toosmall storeids storevalues seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 (SPOOLES_REAL) -- real entries" "\n 2 (SPOOLES_COMPLEX) -- complex entries" "\n symmetryflag -- type of matrix" "\n 0 (SPOOLES_SYMMETRIC) -- symmetric entries" "\n 1 (SPOOLES_HERMITIAN) -- Hermitian entries" "\n 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric entries" "\n patchAndGoFlag -- flag for the patch-and-go strategy" "\n 0 -- none, stop factorization" "\n 1 -- optimization strategy" "\n 2 -- structural analysis strategy" "\n fudge -- perturbation parameter" "\n toosmall -- upper bound on a small pivot" "\n storeids -- flag to store ids of small pivots" "\n storevalues -- flag to store perturbations" "\n seed -- random number seed" "\n " "\n note: matrix entries are read in from patchMatrix.k.input" "\n where k is the process number" "\n note: rhs entries are read in from patchRhs.k.input" "\n where k is the process number" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { sprintf(buffer, "res.%d", myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], buffer) ; return(-1) ; } } type = atoi(argv[3]) ; symmetryflag = atoi(argv[4]) ; patchAndGoFlag = atoi(argv[5]) ; fudge = atof(argv[6]) ; toosmall = atof(argv[7]) ; storeids = atoi(argv[8]) ; storevalues = atoi(argv[9]) ; seed = atoi(argv[10]) ; IVzero(20, stats) ; DVzero(20, cpus) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 1: read the entries from the input file and create the InpMtx object -------------------------------------------- */ sprintf(buffer, "patchMatrix.%d.input", myid) ; inputFile = fopen(buffer, "r") ; fscanf(inputFile, "%d %d %d", &neqns, &neqns, &nent) ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, 0) ; if ( type == SPOOLES_REAL ) { for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else if ( type == SPOOLES_COMPLEX ) { for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; InpMtx_sortAndCompress(mtxA) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 2 : find a low-fill ordering (1) create the Graph object (2) order the graph using multiple minimum degree (3) find out who has the best ordering w.r.t. op count, and broadcast that front tree object ------------------------------------------------------- */ graph = Graph_new() ; adjIVL = InpMtx_MPI_fullAdjacency(mtxA, stats, msglvl, msgFile, MPI_COMM_WORLD) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } frontETree = orderViaMMD(graph, seed + myid, msglvl, msgFile) ; Graph_free(graph) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } opcounts = DVinit(nproc, 0.0) ; opcounts[myid] = ETree_nFactorOps(frontETree, type, symmetryflag) ; MPI_Allgather((void *) &opcounts[myid], 1, MPI_DOUBLE, (void *) opcounts, 1, MPI_DOUBLE, MPI_COMM_WORLD) ; minops = DVmin(nproc, opcounts, &root) ; DVfree(opcounts) ; frontETree = ETree_MPI_Bcast(frontETree, root, msglvl, msgFile, MPI_COMM_WORLD) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n best front tree") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 3: get the permutations and permute the front tree ------------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; ETree_permuteVertices(frontETree, oldToNewIV) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------- STEP 4: generate the owners map IV object and the map from vertices to owners ------------------------------------------- */ cutoff = 1./(2*nproc) ; cumopsDV = DV_new() ; DV_init(cumopsDV, nproc, NULL) ; ownersIV = ETree_ddMap(frontETree, type, symmetryflag, cumopsDV, cutoff) ; DV_free(cumopsDV) ; vtxmapIV = IV_new() ; IV_init(vtxmapIV, neqns, NULL) ; IVgather(neqns, IV_entries(vtxmapIV), IV_entries(ownersIV), ETree_vtxToFront(frontETree)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n map from fronts to owning processes") ; IV_writeForHumanEye(ownersIV, msgFile) ; fprintf(msgFile, "\n\n map from vertices to owning processes") ; IV_writeForHumanEye(vtxmapIV, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- STEP 5: permute the matrix and redistribute ------------------------------------------- */ InpMtx_permute(mtxA, IV_entries(oldToNewIV), IV_entries(oldToNewIV)) ; if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; firsttag = 0 ; keepmtx = InpMtx_MPI_split(mtxA, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; InpMtx_free(mtxA) ; mtxA = keepmtx ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted and split InpMtx") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 6: compute the symbolic factorization ------------------------------------------ */ symbfacIVL = SymbFac_MPI_initFromInpMtx(frontETree, ownersIV, mtxA, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n local symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- STEP 7: initialize the front matrix object and the PatchAndGoInfo object to handle small pivots -------------------------------------------------- */ mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; frontmtx = FrontMtx_new() ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, NO_LOCK, myid, ownersIV, mtxmanager, msglvl, msgFile) ; if ( patchAndGoFlag == 1 ) { frontmtx->patchinfo = PatchAndGoInfo_new() ; PatchAndGoInfo_init(frontmtx->patchinfo, 1, toosmall, fudge, storeids, storevalues) ; } else if ( patchAndGoFlag == 2 ) { frontmtx->patchinfo = PatchAndGoInfo_new() ; PatchAndGoInfo_init(frontmtx->patchinfo, 2, toosmall, fudge, storeids, storevalues) ; } /*--------------------------------------------------------------------*/ /* --------------------------------- STEP 8: compute the factorization --------------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 0) ; rootchv = FrontMtx_MPI_factorInpMtx(frontmtx, mtxA, tau, 0.0 , chvmanager, ownersIV, 0, &error, cpus, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; ChvManager_free(chvmanager) ; if ( patchAndGoFlag == 1 ) { if ( frontmtx->patchinfo->fudgeIV != NULL ) { fprintf(msgFile, "\n small pivots found at these locations") ; IV_writeForHumanEye(frontmtx->patchinfo->fudgeIV, msgFile) ; } PatchAndGoInfo_free(frontmtx->patchinfo) ; } else if ( patchAndGoFlag == 2 ) { if ( frontmtx->patchinfo->fudgeIV != NULL ) { fprintf(msgFile, "\n small pivots found at these locations") ; IV_writeForHumanEye(frontmtx->patchinfo->fudgeIV, msgFile) ; } if ( frontmtx->patchinfo->fudgeDV != NULL ) { fprintf(msgFile, "\n perturbations") ; DV_writeForHumanEye(frontmtx->patchinfo->fudgeDV, msgFile) ; } PatchAndGoInfo_free(frontmtx->patchinfo) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n numeric factorization") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } if ( error >= 0 ) { fprintf(stderr, "\n proc %d : factorization error at front %d", myid, error) ; fprintf(msgFile, "\n proc %d : factorization error at front %d", myid, error) ; MPI_Barrier(MPI_COMM_WORLD) ; fprintf(stderr, "\n proc %d : calling MPI_Finalize()", myid) ; fprintf(msgFile, "\n proc %d : calling MPI_Finalize()", myid) ; MPI_Finalize() ; return(-1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ STEP 9: post-process the factorization and split the factor matrices into submatrices ------------------------------------------------ */ FrontMtx_MPI_postProcess(frontmtx, ownersIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n numeric factorization after post-processing"); FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- STEP 10: create the solve map object ----------------------------------- */ solvemap = SolveMap_new() ; SolveMap_ddMap(solvemap, frontmtx->symmetryflag, FrontMtx_upperBlockIVL(frontmtx), FrontMtx_lowerBlockIVL(frontmtx), nproc, ownersIV, FrontMtx_frontTree(frontmtx), seed, msglvl, msgFile); if ( msglvl > 3 ) { SolveMap_writeForHumanEye(solvemap, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- STEP 11: redistribute the submatrices of the factors ---------------------------------------------------- */ FrontMtx_MPI_split(frontmtx, solvemap, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n numeric factorization after split") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- STEP 12: read the entries from the rhs input file and create the DenseMtx object for Y ------------------------------------------------- */ sprintf(buffer, "patchRhs.%d.input", myid) ; inputFile = fopen(buffer, "r") ; fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxY = DenseMtx_new() ; DenseMtx_init(mtxY, type, myid, -1, nrow, nrhs, 1, nrow) ; DenseMtx_rowIndices(mtxY, &nrow, &rowind) ; if ( type == SPOOLES_REAL ) { for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", rowind + irow) ; for ( jcol = 0 ; jcol < nrhs ; jcol++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxY, irow, jcol, value) ; } } } if ( type == SPOOLES_COMPLEX ) { for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", rowind + irow) ; for ( jcol = 0 ; jcol < nrhs ; jcol++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxY, irow, jcol, real, imag) ; } } } fclose(inputFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ STEP 13: permute and redistribute Y if necessary ------------------------------------------------ */ DenseMtx_permuteRows(mtxY, oldToNewIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { IV *rowmapIV ; /* ---------------------------------------------------------- pivoting has taken place, redistribute the right hand side to match the final rows and columns in the fronts ---------------------------------------------------------- */ rowmapIV = FrontMtx_MPI_rowmapIV(frontmtx, ownersIV, msglvl, msgFile, MPI_COMM_WORLD) ; mtxY = DenseMtx_MPI_splitByRows(mtxY, rowmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; IV_free(rowmapIV) ; } else { /* -------------------------------------------------------------- pivoting has not taken place, redistribute the right hand side using the vertex map used to redistribute the matrix A -------------------------------------------------------------- */ mtxY = DenseMtx_MPI_splitByRows(mtxY, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs matrix after split") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 14: create a solution DenseMtx object and solve the linear system ------------------------------------------ */ ownedColumnsIV = FrontMtx_ownedColumnsIV(frontmtx, myid, ownersIV, msglvl, msgFile) ; nmycol = IV_size(ownedColumnsIV) ; mtxX = DenseMtx_new() ; if ( nmycol > 0 ) { DenseMtx_init(mtxX, type, myid, -1, nmycol, nrhs, 1, nmycol) ; DenseMtx_rowIndices(mtxX, &nrow, &rowind) ; IVcopy(nmycol, rowind, IV_entries(ownedColumnsIV)) ; } solvemanager = SubMtxManager_new() ; SubMtxManager_init(solvemanager, NO_LOCK, 0) ; FrontMtx_MPI_solve(frontmtx, mtxX, mtxY, solvemanager, solvemap, cpus, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; SubMtxManager_free(solvemanager) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n solution in new ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- STEP 15: permute the solution into the original ordering and assemble the solution onto processor zero -------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n solution in old ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } IV_fill(vtxmapIV, 0) ; firsttag++ ; mtxX = DenseMtx_MPI_splitByRows(mtxX, vtxmapIV, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; if ( myid == 0 && msglvl > 0 ) { fprintf(msgFile, "\n\n complete solution in old ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ MPI_Finalize() ; return(1) ; } /*--------------------------------------------------------------------*/ ------------------------------------------ STEP 6: compute tMPI/drivers/testGather.c010064400020550007177000000300720656065065300164670ustar00clevecompmath00000400000006/* testGather.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------------------------------------------- this program tests the DenseMtx_MPI_gatherRows() method. we create a distributed DenseMtx object X, which is partitioned among the processors. the entries of X have a particular form so we can check our results. each processor then defines a set of rows for its Y matrix, and figures out where those rows come from, and puts this information into a recvIVL object. using the IVL_MPI_alltoall() method, the processors then construct their individual sendIVL objects that tell them which rows of their owned X matrix they need to send to the other processors. the lists in sendIVL are then made local w.r.t. X. the lists in recvIVL are then made local w.r.t. Y. the processors then fill the entries in their Y matrices using the DenseMtx_MPI_gatherRows() method. the processors then check that their entries in Y are correct. created -- 98aug01, cca -------------------------------------------------------------------- */ { char *buffer ; DenseMtx *X, *Y ; double error, gerror, imag, real, t1, t2, value ; Drand drand ; int count, iirow, iproc, irow, inc1, inc2, jcol, length, myid, msglvl, ncol, ncolX, ncolY, nproc, nrow, nrowX, nrowY, seed, tag, size, type ; int *colindX, *colindY, *counts, *head, *link, *list, *map, *rowidsY, *rowindX, *rowindY, *temp ; int stats[4], tstats[4] ; IV *mapIV ; IVL *recvIVL, *sendIVL ; FILE *msgFile ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow ncol inc1 inc2 seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- number of rows" "\n ncol -- number of columns" "\n inc1 -- row increment" "\n inc2 -- column increment" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(0) ; } CVfree(buffer) ; } type = atoi(argv[3]) ; nrow = atoi(argv[4]) ; ncol = atoi(argv[5]) ; inc1 = atoi(argv[6]) ; inc2 = atoi(argv[7]) ; seed = atoi(argv[8]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n type -- %d" "\n nrow -- %d" "\n ncol -- %d" "\n inc1 -- %d" "\n inc2 -- %d" "\n seed -- %d" "\n", argv[0], msglvl, argv[2], type, nrow, ncol, inc1, inc2, seed) ; fflush(msgFile) ; if ( inc1 != 1 && inc2 != 1 ) { fprintf(stderr, "\n fatal error, inc1 = %d, inc2 = %d", inc1, inc2) ; exit(-1) ; } /* ---------------------------------- set up the random number generator ---------------------------------- */ Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; /* ----------------------------------------------------------- generate the mapIV object that maps rows of X to processors ----------------------------------------------------------- */ mapIV = IV_new() ; IV_init(mapIV, nrow, NULL) ; map = IV_entries(mapIV) ; Drand_setUniform(&drand, 0, nproc) ; Drand_fillIvector(&drand, nrow, map) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n mapIV") ; IV_writeForHumanEye(mapIV, msgFile) ; } /* ------------------------------------------------ make sure that each processor has some rows of X ------------------------------------------------ */ counts = IVinit(nproc, 0) ; for ( irow = 0 ; irow < nrow ; irow++ ) { counts[map[irow]]++ ; } for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( counts[iproc] == 0 ) { fprintf(stderr, "\n proc %d has no rows", iproc) ; MPI_Finalize() ; exit(-1) ; } } nrowX = counts[myid] ; fprintf(msgFile, "\n nrowX = %d", nrowX) ; IVfree(counts) ; /* ----------------------------------------------------- generate this processor's portion of the dense matrix ----------------------------------------------------- */ X = DenseMtx_new() ; if ( inc1 == 1 ) { DenseMtx_init(X, type, 1, -1, nrowX, ncol, 1, nrowX) ; } else if ( inc2 == 1 ) { DenseMtx_init(X, type, 1, -1, nrowX, ncol, ncol, 1) ; } DenseMtx_zero(X) ; DenseMtx_rowIndices(X, &nrowX, &rowindX) ; for ( irow = iirow = 0 ; irow < nrow ; irow++ ) { if ( map[irow] == myid ) { rowindX[iirow++] = irow ; } } DenseMtx_columnIndices(X, &ncolX, &colindX) ; IVramp(ncolX, colindX, 0, 1) ; if ( DENSEMTX_IS_REAL(X) ) { for ( iirow = 0 ; iirow < nrowX ; iirow++ ) { irow = rowindX[iirow] ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { DenseMtx_setRealEntry(X, iirow, jcol, irow + nrow*jcol) ; } } } else { for ( iirow = 0 ; iirow < nrowX ; iirow++ ) { irow = rowindX[iirow] ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { DenseMtx_setComplexEntry(X, iirow, jcol, irow + nrow*jcol, 2*(irow + nrow*jcol)) ; } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n X") ; DenseMtx_writeForHumanEye(X, msgFile) ; } /* --------------------------------- generate a vector of rowids for Y --------------------------------- */ { int ii ; double value ; for ( ii = 0 ; ii <= myid ; ii++ ) { value = Drand_value(&drand) ; } } Drand_setUniform(&drand, 1, nrow+1) ; nrowY = (int) Drand_value(&drand) ; fprintf(msgFile, "\n nrowY = %d", nrowY) ; rowidsY = IVinit(nrowY, -1) ; temp = IVinit(nrow, -1) ; IVramp(nrow, temp, 0, 1) ; IVshuffle(nrow, temp, seed + 2*myid + 1) ; IVcopy(nrowY, rowidsY, temp) ; IVqsortUp(nrowY, rowidsY) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rowids for Y") ; IVfprintf(msgFile, nrowY, rowidsY) ; fflush(msgFile) ; } /* ---------------------------------------------- set up the recvIVL object, list iproc contains the rows this processor needs from iproc ---------------------------------------------- */ recvIVL = IVL_new() ; IVL_init1(recvIVL, IVL_CHUNKED, nproc) ; head = IVinit(nproc, -1) ; link = IVinit(nrow, -1) ; for ( iirow = 0 ; iirow < nrowY ; iirow++ ) { irow = rowidsY[iirow] ; iproc = map[irow] ; link[irow] = head[iproc] ; head[iproc] = irow ; } for ( iproc = 0 ; iproc < nproc ; iproc++ ) { count = 0 ; for ( irow = head[iproc] ; irow != -1 ; irow = link[irow] ) { temp[count++] = irow ; } IVqsortUp(count, temp) ; IVL_setList(recvIVL, iproc, count, temp) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n recvIVL") ; IVL_writeForHumanEye(recvIVL, msgFile) ; } /* ---------------------------------------------- set up the sendIVL object, list iproc contains the rows this processor will send to iproc ---------------------------------------------- */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; tag = 1 ; MARKTIME(t1) ; sendIVL = IVL_MPI_alltoall(recvIVL, NULL, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : IVL_MPI_alltoall", t2 - t1) ; fprintf(msgFile, "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n sendIVL") ; IVL_writeForHumanEye(sendIVL, msgFile) ; } /* ---------------------------------------- make the lists in sendIVL local w.r.t. X ---------------------------------------- */ for ( irow = 0 ; irow < nrowX ; irow++ ) { temp[rowindX[irow]] = irow ; } for ( iproc = 0 ; iproc < nproc ; iproc++ ) { IVL_listAndSize(sendIVL, iproc, &size, &list) ; for ( iirow = 0 ; iirow < size ; iirow++ ) { list[iirow] = temp[list[iirow]] ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n sendIVL with local lists") ; IVL_writeForHumanEye(sendIVL, msgFile) ; } /* ---------------------------------------- make the lists in recvIVL local w.r.t. Y ---------------------------------------- */ for ( irow = 0 ; irow < nrowY ; irow++ ) { temp[rowidsY[irow]] = irow ; } for ( iproc = 0 ; iproc < nproc ; iproc++ ) { IVL_listAndSize(recvIVL, iproc, &size, &list) ; for ( iirow = 0 ; iirow < size ; iirow++ ) { list[iirow] = temp[list[iirow]] ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n recvIVL with local lists") ; IVL_writeForHumanEye(recvIVL, msgFile) ; } /* ------------------- create the Y matrix ------------------- */ Y = DenseMtx_new() ; if ( inc1 == 1 ) { DenseMtx_init(Y, type, 1, -1, nrowY, ncol, 1, nrowY) ; } else { DenseMtx_init(Y, type, 1, -1, nrowY, ncol, ncol, 1) ; } DenseMtx_zero(Y) ; DenseMtx_rowIndices(Y, &nrowY, &rowindY) ; IVcopy(nrowY, rowindY, rowidsY) ; DenseMtx_columnIndices(Y, &ncolY, &colindY) ; IVramp(ncolY, colindY, 0, 1) ; /* ---------------------------------------------- gather the entries of Y from the distributed X ---------------------------------------------- */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; tag = 1 ; MARKTIME(t1) ; DenseMtx_MPI_gatherRows(Y, X, sendIVL, recvIVL, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : DenseMtx_MPI_gatherRows", t2 - t1) ; fprintf(msgFile, "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Y") ; DenseMtx_writeForHumanEye(Y, msgFile) ; } /* --------------------------------- check that the local Y is correct --------------------------------- */ if ( DENSEMTX_IS_REAL(Y) ) { for ( iirow = 0, error = 0.0 ; iirow < nrowY ; iirow++ ) { irow = rowindY[iirow] ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { DenseMtx_realEntry(Y, iirow, jcol, &real) ; value = real - (irow + nrow*jcol) ; error += value*value ; } } } else { for ( iirow = 0, error = 0.0 ; iirow < nrowY ; iirow++ ) { irow = rowindY[iirow] ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { DenseMtx_complexEntry(Y, iirow, jcol, &real, &imag) ; value = real - (irow + nrow*jcol) ; error += value*value ; value = imag - 2*(irow + nrow*jcol) ; error += value*value ; } } } fprintf(msgFile, "\n\n local error = %12.4e", error) ; MPI_Reduce((void *) &error, (void *) &gerror, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global error = %12.4e", gerror) ; fflush(msgFile) ; } /* ---------------- free the objects ---------------- */ IV_free(mapIV) ; DenseMtx_free(X) ; DenseMtx_free(Y) ; IVfree(rowidsY) ; IVfree(temp) ; IVfree(head) ; IVfree(link) ; IVL_free(recvIVL) ; IVL_free(sendIVL) ; MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow ncol inc1 inc2 seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- number of rows" "\n ncol -- number of columns" "\n inc1 -- row increment" "\n inc2 -- column increment" "\n seed -- random number seed" "\n", argv[0]) ; return(0) MPI/drivers/testGraph_Bcast.c010064400020550007177000000204630657576265000174440ustar00clevecompmath00000400000006/* testGraph_Bcast.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------------------------------------------- this program tests the Graph_MPI_Bcast() method (1) process root generates a random Graph object and computes its checksum (2) process root broadcasts the Graph object to the other processors (3) each process computes the checksum of its Graph object (4) the checksums are compared on root created -- 98sep10, cca -------------------------------------------------------------------- */ { char *buffer ; double chksum, t1, t2 ; double *sums ; Drand drand ; int iproc, length, loc, msglvl, myid, nitem, nproc, nvtx, root, seed, size, type, v ; int *list ; FILE *msgFile ; Graph *graph ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nvtx nitem root seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of graph" "\n nvtx -- # of vertices" "\n nitem -- # of items used to generate graph" "\n root -- root processor for broadcast" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } CVfree(buffer) ; } type = atoi(argv[3]) ; nvtx = atoi(argv[4]) ; nitem = atoi(argv[5]) ; root = atoi(argv[6]) ; seed = atoi(argv[7]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n type -- %d" "\n nvtx -- %d" "\n nitem -- %d" "\n root -- %d" "\n seed -- %d" "\n", argv[0], msglvl, argv[2], type, nvtx, nitem, root, seed) ; fflush(msgFile) ; /* ----------------------- set up the Graph object ----------------------- */ MARKTIME(t1) ; graph = Graph_new() ; if ( myid == root ) { InpMtx *inpmtx ; int nedges, totewght, totvwght, v ; int *adj, *vwghts ; IVL *adjIVL, *ewghtIVL ; /* ----------------------- generate a random graph ----------------------- */ inpmtx = InpMtx_new() ; InpMtx_init(inpmtx, INPMTX_BY_ROWS, INPMTX_INDICES_ONLY, nitem, 0) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0, nvtx) ; Drand_fillIvector(&drand, nitem, InpMtx_ivec1(inpmtx)) ; Drand_fillIvector(&drand, nitem, InpMtx_ivec2(inpmtx)) ; InpMtx_setNent(inpmtx, nitem) ; InpMtx_changeStorageMode(inpmtx, INPMTX_BY_VECTORS) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inpmtx mtx filled with raw entries") ; InpMtx_writeForHumanEye(inpmtx, msgFile) ; fflush(msgFile) ; } adjIVL = InpMtx_fullAdjacency(inpmtx) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n full adjacency structure") ; IVL_writeForHumanEye(adjIVL, msgFile) ; fflush(msgFile) ; } nedges = adjIVL->tsize ; if ( type == 1 || type == 3 ) { Drand_setUniform(&drand, 1, 10) ; vwghts = IVinit(nvtx, 0) ; Drand_fillIvector(&drand, nvtx, vwghts) ; totvwght = IVsum(nvtx, vwghts) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n vertex weights") ; IVfprintf(msgFile, nvtx, vwghts) ; fflush(msgFile) ; } } else { vwghts = NULL ; totvwght = nvtx ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n totvwght %d", totvwght) ; fflush(msgFile) ; } if ( type == 2 || type == 3 ) { ewghtIVL = IVL_new() ; IVL_init1(ewghtIVL, IVL_CHUNKED, nvtx) ; Drand_setUniform(&drand, 1, 100) ; totewght = 0 ; for ( v = 0 ; v < nvtx ; v++ ) { IVL_listAndSize(adjIVL, v, &size, &adj) ; IVL_setList(ewghtIVL, v, size, NULL) ; IVL_listAndSize(ewghtIVL, v, &size, &adj) ; Drand_fillIvector(&drand, size, adj) ; totewght += IVsum(size, adj) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ewghtIVL") ; IVL_writeForHumanEye(ewghtIVL, msgFile) ; fflush(msgFile) ; } } else { ewghtIVL = NULL ; totewght = nedges ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n totewght %d", totewght) ; fflush(msgFile) ; } Graph_init2(graph, type, nvtx, 0, nedges, totvwght, totewght, adjIVL, vwghts, ewghtIVL) ; InpMtx_free(inpmtx) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the Graph object", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; if ( myid == root ) { /* ---------------------------------------- compute the checksum of the Graph object ---------------------------------------- */ chksum = graph->type + graph->nvtx + graph->nvbnd + graph->nedges + graph->totvwght + graph->totewght ; for ( v = 0 ; v < nvtx ; v++ ) { IVL_listAndSize(graph->adjIVL, v, &size, &list) ; chksum += 1 + v + size + IVsum(size, list) ; } if ( graph->vwghts != NULL ) { chksum += IVsum(nvtx, graph->vwghts) ; } if ( graph->ewghtIVL != NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { IVL_listAndSize(graph->ewghtIVL, v, &size, &list) ; chksum += 1 + v + size + IVsum(size, list) ; } } fprintf(msgFile, "\n\n local chksum = %12.4e", chksum) ; fflush(msgFile) ; } /* -------------------------- broadcast the Graph object -------------------------- */ MARKTIME(t1) ; graph = Graph_MPI_Bcast(graph, root, msglvl, msgFile, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : broadcast the Graph object", t2 - t1) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } /* ---------------------------------------- compute the checksum of the Graph object ---------------------------------------- */ chksum = graph->type + graph->nvtx + graph->nvbnd + graph->nedges + graph->totvwght + graph->totewght ; for ( v = 0 ; v < nvtx ; v++ ) { IVL_listAndSize(graph->adjIVL, v, &size, &list) ; chksum += 1 + v + size + IVsum(size, list) ; } if ( graph->vwghts != NULL ) { chksum += IVsum(nvtx, graph->vwghts) ; } if ( graph->ewghtIVL != NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { IVL_listAndSize(graph->ewghtIVL, v, &size, &list) ; chksum += 1 + v + size + IVsum(size, list) ; } } fprintf(msgFile, "\n\n local chksum = %12.4e", chksum) ; fflush(msgFile) ; /* --------------------------------------- gather the checksums from the processes --------------------------------------- */ sums = DVinit(nproc, 0.0) ; MPI_Gather((void *) &chksum, 1, MPI_DOUBLE, (void *) sums, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n\n sums") ; DVfprintf(msgFile, nproc, sums) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { sums[iproc] -= chksum ; } fprintf(msgFile, "\n\n errors") ; DVfprintf(msgFile, nproc, sums) ; fprintf(msgFile, "\n\n maxerror = %12.4e", DVmax(nproc, sums, &loc)); } /* ---------------- free the objects ---------------- */ DVfree(sums) ; Graph_free(graph) ; /* ------------------------ exit the MPI environment ------------------------ */ MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ gc = %d", myid, nproc, argc) ; fflush(stdout) ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nvtx nitem root seed " "\n msglvl -- message level"MPI/drivers/testGridMPI.c010064400020550007177000000717230665073102700165130ustar00clevecompmath00000400000006/* testGridMPI.c */ #include "../spoolesMPI.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ void mkNDlinsys ( int n1, int n2, int n3, int maxzeros, int maxsize, int type, int symmetryflag, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB ) ; /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* */ { Chv *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxB, *mtxkeep, *mtxX, *mtxZ ; double cputotal, cutoff, droptol, error, factorops, solvecpu, solveops, tau, terror, t1, t2 ; double cpus[14], tcpus[14] ; DV *cumopsDV ; ETree *frontETree ; FILE *msgFile ; FrontMtx *frontmtx ; InpMtx *mtxA, *mtxAkeep ; int factorerror, lookahead, maptype, maxsize, maxzeros, msglvl, myid, neqns, nproc, nrhs, nrow, nzf, n1, n2, n3, pivotingflag, seed, sparsityflag, symmetryflag, tag, type ; int *rowindX, *rowindZ ; int stats[17], tstats[17] ; IV *frontOwnersIV, *vtxmapIV ; IVL *symbfacIVL ; SolveMap *solvemap ; SubMtxManager *factormanager, *solvemanager ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; if ( argc != 19 ) { fprintf(stdout, "\n\n usage : %s " "\n msglvl msgFile n1 n2 n3 maxzeros maxsize seed " "\n type symmetryflag sparsityflag pivotingflag " "\n tau droptol lookahead nrhs maptype cutoff" "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- # of points in first dimension" "\n n2 -- # of points in second dimension" "\n n3 -- # of points in third dimension" "\n maxzeros -- max # of zeros in a front" "\n maxsize -- max # of internal vertices in a front" "\n seed -- random number seed" "\n type -- type of entries" "\n 1 --> real " "\n 2 --> complex " "\n symmetryflag -- symmetry flag" "\n 0 --> symmetric " "\n 1 --> hermitian " "\n 2 --> nonsymmetric " "\n sparsityflag -- sparsity flag" "\n 0 --> store dense fronts" "\n 1 --> store sparse fronts, use droptol to drop entries" "\n pivotingflag -- pivoting flag" "\n 0 --> do not pivot" "\n 1 --> enable pivoting" "\n tau -- upper bound on factor entries" "\n used only with pivoting" "\n droptol -- lower bound on factor entries" "\n used only with sparse fronts" "\n lookahead -- parameter to schedule computation" "\n 0 --> no lookahead" "\n nonzero --> look up the tree this many steps" "\n nrhs -- number of right hand sides" "\n maptype -- type of factorization map" "\n 1 --> wrap map" "\n 2 --> balanced map via post-order traversal" "\n 3 --> subtree-subset map" "\n 4 --> domain decomposition map" "\n cutoff -- used when maptype = 4" "\n 0 < cutoff < 1 to define multisector" "\n try cutoff = 1/nproc or 1/(2*nproc)" "\n", argv[0]) ; { int ii ; fprintf(stdout, "\n\n argc = %d", argc) ; for ( ii = 0 ; ii < argc ; ii++ ) { fprintf(stdout, "\n arg %d = %s", ii, argv[ii]) ; } } MPI_Finalize() ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { int length = strlen(argv[2]) + 1 + 4 ; char *buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], buffer) ; return(-1) ; } CVfree(buffer) ; } n1 = atoi(argv[ 3]) ; n2 = atoi(argv[ 4]) ; n3 = atoi(argv[ 5]) ; maxzeros = atoi(argv[ 6]) ; maxsize = atoi(argv[ 7]) ; seed = atoi(argv[ 8]) ; type = atoi(argv[ 9]) ; symmetryflag = atoi(argv[10]) ; sparsityflag = atoi(argv[11]) ; pivotingflag = atoi(argv[12]) ; tau = atof(argv[13]) ; droptol = atof(argv[14]) ; lookahead = atoi(argv[15]) ; nrhs = atoi(argv[16]) ; maptype = atoi(argv[17]) ; cutoff = atof(argv[18]) ; fprintf(msgFile, "\n %s :" "\n msglvl = %d" "\n msgFile = %s" "\n n1 = %d" "\n n2 = %d" "\n n3 = %d" "\n maxzeros = %d" "\n maxsize = %d" "\n seed = %d" "\n type = %d" "\n symmetryflag = %d" "\n sparsityflag = %d" "\n pivotingflag = %d" "\n tau = %f" "\n droptol = %f" "\n lookahead = %d" "\n nrhs = %d" "\n maptype = %d" "\n cutoff = %f" "\n", argv[0], msglvl, argv[2], n1, n2, n3, maxzeros, maxsize, seed, type, symmetryflag, sparsityflag, pivotingflag, tau, droptol, lookahead, nrhs, maptype, cutoff) ; fflush(msgFile) ; neqns = n1*n2*n3 ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; if ( myid == 0 ) { /* -------------------------- generate the linear system -------------------------- */ mkNDlinsys(n1, n2, n3, maxzeros, maxsize, type, symmetryflag, nrhs, seed, msglvl, msgFile, &frontETree, &symbfacIVL, &mtxA, &mtxX, &mtxB) ; /* ------------------------------- free the symbolic factorization ------------------------------- */ IVL_free(symbfacIVL) ; /* ------------------------------------------- send the front tree to the other processors ------------------------------------------- */ frontETree = ETree_MPI_Bcast(frontETree, 0, msglvl, msgFile, MPI_COMM_WORLD) ; } else { /* --------------------------------------- receive the front tree from processor 0 --------------------------------------- */ frontETree = ETree_MPI_Bcast(NULL, 0, msglvl, msgFile, MPI_COMM_WORLD) ; /* ------------------------------ create the objects for X and B ------------------------------ */ mtxX = DenseMtx_new() ; mtxB = DenseMtx_new() ; DenseMtx_init(mtxX, type, -1, -1, 0, nrhs, 1, 0) ; DenseMtx_init(mtxB, type, -1, -1, 0, nrhs, 1, 0) ; /* ----------------------- create the object for A ----------------------- */ mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_CHEVRONS, type, 0, 0) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n front ETree object") ; ETree_writeForHumanEye(frontETree, msgFile) ; fprintf(msgFile, "\n\n mtxX") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fprintf(msgFile, "\n\n mtxB") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fprintf(msgFile, "\n\n mtxA") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; } /* --------------------------------- generate the owners map IV object --------------------------------- */ cumopsDV = DV_new() ; DV_init(cumopsDV, nproc, NULL) ; DV_fill(cumopsDV, 0.0) ; switch ( maptype ) { case 1 : frontOwnersIV = ETree_wrapMap(frontETree, type, symmetryflag, cumopsDV) ; break ; case 2 : frontOwnersIV = ETree_balancedMap(frontETree, type, symmetryflag, cumopsDV) ; break ; case 3 : frontOwnersIV = ETree_subtreeSubsetMap(frontETree, type, symmetryflag, cumopsDV) ; break ; case 4 : frontOwnersIV = ETree_ddMap(frontETree, type, symmetryflag, cumopsDV, cutoff) ; break ; default : fprintf(stderr, "\n fatal error, maptype = %d", maptype) ; MPI_Finalize() ; exit(-1) ; break ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n owners map object") ; IV_writeForHumanEye(frontOwnersIV, msgFile) ; } fprintf(msgFile, "\n\n upper bound on load balance = %4.2f\n", DV_sum(cumopsDV)/DV_max(cumopsDV)) ; DV_free(cumopsDV) ; /* --------------------- create the vertex map --------------------- */ vtxmapIV = IV_new() ; IV_init(vtxmapIV, neqns, NULL) ; IVgather(neqns, IV_entries(vtxmapIV), IV_entries(frontOwnersIV), ETree_vtxToFront(frontETree)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n vertex map object") ; IV_writeForHumanEye(vtxmapIV, msgFile) ; } /* ------------------ split the X matrix ------------------ */ tag = 1 ; stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; mtxkeep = DenseMtx_MPI_splitByRows(mtxX, vtxmapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; DenseMtx_free(mtxX) ; mtxX = mtxkeep ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : split mtxX", t2 - t1) ; fprintf(msgFile, "\n # sent bytes sent # recv bytes recv" "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d\n", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n mtxX object") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; } /* ------------------ split the B matrix ------------------ */ tag = 1 ; stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; mtxkeep = DenseMtx_MPI_splitByRows(mtxB, vtxmapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; DenseMtx_free(mtxB) ; mtxB = mtxkeep ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : split mtxB", t2 - t1) ; fprintf(msgFile, "\n # sent bytes sent # recv bytes recv" "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d\n", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n mtxB object") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; } /* ------------------ split the A matrix ------------------ */ tag = 1 ; stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; mtxAkeep = InpMtx_MPI_split(mtxA, vtxmapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; InpMtx_free(mtxA) ; mtxA = mtxAkeep ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : split mtxA", t2 - t1) ; fprintf(msgFile, "\n # sent bytes sent # recv bytes recv" "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d\n", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n mtxA object") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; } /* ---------------------------------- compute the symbolic factorization ---------------------------------- */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; symbfacIVL = SymbFac_MPI_initFromInpMtx(frontETree, frontOwnersIV, mtxA, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : symbolic factorization", t2 - t1) ; fprintf(msgFile, "\n # sent bytes sent # recv bytes recv" "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d\n", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n symbolic factorization object") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; } /* ---------------------------------- initialize the front matrix object ---------------------------------- */ factormanager = SubMtxManager_new() ; SubMtxManager_init(factormanager, 0, 0) ; MARKTIME(t1) ; frontmtx = FrontMtx_new() ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, sparsityflag, pivotingflag, NO_LOCK, myid, frontOwnersIV, factormanager, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the front matrix", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n front matrix initialized") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /* ----------------------- factor the front matrix ----------------------- */ nzf = ETree_nFactorEntries(frontETree, symmetryflag) ; factorops = ETree_nFactorOps(frontETree, type, symmetryflag) ; IVzero(17, stats) ; DVzero(14, cpus) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 0) ; MARKTIME(t1) ; rootchv = FrontMtx_MPI_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, frontOwnersIV, lookahead, &factorerror, cpus, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : factor matrix, %8.3f mflops", t2 - t1, 1.e-6*factorops/(t2-t1)) ; if ( factorerror >= 0 ) { fprintf(msgFile, "\n\n error found in front %d", factorerror) ; exit(-1) ; } if ( rootchv != NULL ) { Chv *chv ; fprintf(msgFile, "\n\n factorization did not complete") ; for ( chv = rootchv ; chv != NULL ; chv = chv->next ) { fprintf(stdout, "\n chv %d, nD = %d, nL = %d, nU = %d", chv->id, chv->nD, chv->nL, chv->nU) ; Chv_writeForHumanEye(chv, msgFile) ; } } DVzero(14, tcpus) ; MPI_Reduce((void *) cpus, (void *) tcpus, 14, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD) ; cputotal = DVsum(14, tcpus) ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n initialize fronts %8.3f %6.2f" "\n load fronts %8.3f %6.2f" "\n update fronts %8.3f %6.2f" "\n aggregate insert %8.3f %6.2f" "\n aggregate remove/add %8.3f %6.2f" "\n assemble postponed data %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n extract postponed data %8.3f %6.2f" "\n store factor entries %8.3f %6.2f" "\n post initial receives %8.3f %6.2f" "\n check for recv'd messages %8.3f %6.2f" "\n post initial sends %8.3f %6.2f" "\n check for sent messages %8.3f %6.2f" "\n total time %8.3f", tcpus[0], 100.*tcpus[0]/cputotal, tcpus[1], 100.*tcpus[1]/cputotal, tcpus[2], 100.*tcpus[2]/cputotal, tcpus[3], 100.*tcpus[3]/cputotal, tcpus[4], 100.*tcpus[4]/cputotal, tcpus[5], 100.*tcpus[5]/cputotal, tcpus[6], 100.*tcpus[6]/cputotal, tcpus[7], 100.*tcpus[7]/cputotal, tcpus[8], 100.*tcpus[8]/cputotal, tcpus[9], 100.*tcpus[9]/cputotal, tcpus[10], 100.*tcpus[10]/cputotal, tcpus[11], 100.*tcpus[11]/cputotal, tcpus[12], 100.*tcpus[12]/cputotal, cputotal) ; } fprintf(msgFile, "\n\n Local statistics" "\n %d pivots, %d pivot tests, %d delayed rows and columns" "\n %d entries in D, %d entries in L, %d entries in U" "\n %d active Chv objects, %d active bytes, %d requested bytes", stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], stats[14], stats[15], stats[16]) ; fprintf(msgFile, "\n local comm : # sent bytes sent # recv bytes recv" "\n aggregate %6d %12d %6d %12d" "\n postponed %6d %12d %6d %12d", stats[6], stats[7], stats[8], stats[9], stats[10], stats[11], stats[12], stats[13]) ; IVzero(11, tstats) ; MPI_Reduce((void *) stats, (void *) tstats, 17, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n\n Global statistics" "\n %d pivots, %d pivot tests, %d delayed rows and columns" "\n %d entries in D, %d entries in L, %d entries in U" "\n %d active Chv objects, %d active bytes, %d requested bytes", tstats[0], tstats[1], tstats[2], tstats[3], tstats[4], tstats[5], tstats[14], tstats[15], tstats[16]) ; fprintf(msgFile, "\n global comm : # sent bytes sent # recv bytes recv" "\n aggregate %6d %12d %6d %12d" "\n postponed %6d %12d %6d %12d", tstats[6], tstats[7], tstats[8], tstats[9], tstats[10], tstats[11], tstats[12], tstats[13]) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { solveops = 2*(tstats[3] + tstats[4] + tstats[5]) ; } else { solveops = 2*(tstats[3] + 2*tstats[5]) ; } if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { solveops *= 4 ; } solveops *= nrhs ; fprintf(msgFile, "\n\n solve operations = %.0f", solveops) ; } SubMtxManager_writeForHumanEye(factormanager, msgFile) ; ChvManager_writeForHumanEye(chvmanager, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------------------------- redistribute the right hand side and solution if necessary ---------------------------------------------------------- */ MARKTIME(t1) ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { IV *colmapIV ; colmapIV = FrontMtx_MPI_colmapIV(frontmtx, frontOwnersIV, msglvl, msgFile, MPI_COMM_WORLD) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n column map IV object") ; IV_writeForHumanEye(colmapIV, msgFile) ; fflush(msgFile) ; } stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; mtxkeep = DenseMtx_MPI_splitByRows(mtxX, colmapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; DenseMtx_free(mtxX) ; mtxX = mtxkeep ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : solution matrix split ", t2 - t1) ; fprintf(msgFile, "\n # sent bytes sent # recv bytes recv" "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d\n", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { IV *rowmapIV ; rowmapIV = FrontMtx_MPI_rowmapIV(frontmtx, frontOwnersIV, msglvl, msgFile, MPI_COMM_WORLD) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n row map IV object") ; IV_writeForHumanEye(rowmapIV, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; mtxkeep = DenseMtx_MPI_splitByRows(mtxB, rowmapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; DenseMtx_free(mtxB) ; mtxB = mtxkeep ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : rhs matrix split ", t2 - t1) ; IV_free(rowmapIV) ; } else { IVfill(4, stats, 0) ; MARKTIME(t1) ; mtxkeep = DenseMtx_MPI_splitByRows(mtxB, colmapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; DenseMtx_free(mtxB) ; mtxB = mtxkeep ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : rhs matrix split ", t2 - t1) ; } fprintf(msgFile, "\n\n Redistibute rhs and solution for this process" "\n # sent bytes sent # recv bytes recv" "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d\n", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n solution matrix") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fprintf(msgFile, "\n\n right hand side matrix") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } IV_free(colmapIV) ; } MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : solution and rhs set up ", t2-t1); /* ----------------------------------------------------------------- post-process the matrix and convert to a submatrix representation ----------------------------------------------------------------- */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; FrontMtx_MPI_postProcess(frontmtx, frontOwnersIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : post-process the factor matrix", t2 - t1) ; fprintf(msgFile, "\n Post-process communication for this process" "\n # sent bytes sent # recv bytes recv" "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d\n", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after post-processing, front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /* --------------------------- create the solve map object --------------------------- */ MARKTIME(t1) ; solvemap = SolveMap_new() ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) && FRONTMTX_IS_PIVOTING(frontmtx) ) { SolveMap_ddMap(solvemap, SPOOLES_NONSYMMETRIC, frontmtx->upperblockIVL, frontmtx->lowerblockIVL, nproc, frontOwnersIV, frontmtx->tree, seed, msglvl, msgFile); } else { SolveMap_ddMap(solvemap, SPOOLES_SYMMETRIC, frontmtx->upperblockIVL, NULL, nproc, frontOwnersIV, frontmtx->tree, seed, msglvl, msgFile) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : solve map created", t2 - t1) ; if ( msglvl > 2 ) { SolveMap_writeForHumanEye(solvemap, msgFile) ; } else { SolveMap_writeStats(solvemap, msgFile) ; } fflush(msgFile) ; /* -------------------------------------------------- split the front matrix to conform to the solve map -------------------------------------------------- */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; FrontMtx_MPI_split(frontmtx, solvemap, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : front matrix split", t2 - t1) ; fprintf(msgFile, "\n Split front matrix communication for this process" "\n # sent bytes sent # recv bytes recv" "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d\n", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after splitting, front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /* ----------------------- solve the linear system ----------------------- */ solvemanager = SubMtxManager_new() ; SubMtxManager_init(solvemanager, 0, 0) ; IVzero(8, stats) ; IVzero(8, tstats) ; DVzero(5, cpus) ; mtxZ = DenseMtx_new() ; DenseMtx_init(mtxZ, type, 0, 0, mtxX->nrow, mtxX->ncol, 1, mtxX->nrow) ; DenseMtx_zero(mtxZ) ; DenseMtx_rowIndices(mtxX, &nrow, &rowindX) ; DenseMtx_rowIndices(mtxZ, &nrow, &rowindZ) ; IVcopy(nrow, rowindZ, rowindX) ; MARKTIME(t1) ; FrontMtx_MPI_solve(frontmtx, mtxZ, mtxB, solvemanager, solvemap, cpus, stats, msglvl, msgFile, tag, MPI_COMM_WORLD); MARKTIME(t2) ; solvecpu = t2 - t1 ; fprintf(msgFile, "\n CPU %8.3f : solve done ", solvecpu) ; /* fprintf(msgFile, "\n\n cpus") ; DVfprintf(msgFile, 6, cpus) ; */ DVzero(6, tcpus) ; MPI_Reduce((void *) cpus, (void *) tcpus, 6, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, ", %.3f mflops", 1.e-6*solveops/(t2-t1)) ; /* fprintf(msgFile, "\n\n tcpus") ; DVfprintf(msgFile, 6, tcpus) ; */ solvecpu = DVsum(6, tcpus) ; fprintf(msgFile, "\n\n Solve CPU breakdown:") ; if ( solvecpu > 0.0 ) { fprintf(msgFile, "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f", tcpus[0], 100.*tcpus[0]/solvecpu, tcpus[1], 100.*tcpus[1]/solvecpu, tcpus[2], 100.*tcpus[2]/solvecpu, tcpus[3], 100.*tcpus[3]/solvecpu, tcpus[4], 100.*tcpus[4]/solvecpu, tcpus[5], 100.*tcpus[5]/solvecpu, solvecpu) ; } } fprintf(msgFile, "\n\n Solve communication for this processor" "\n aggregates solution" "\n # # bytes # #bytes" "\n send %10d %10d %10d %10d" "\n recv %10d %10d %10d %10d", stats[1], stats[3], stats[0], stats[2], stats[5], stats[7], stats[4], stats[6]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 8, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n\n Solve communication for all processors" "\n aggregates solution" "\n # # bytes # #bytes" "\n send %10d %10d %10d %10d" "\n recv %10d %10d %10d %10d", tstats[1], tstats[3], tstats[0], tstats[2], tstats[5], tstats[7], tstats[4], tstats[6]) ; fflush(msgFile) ; } SubMtxManager_writeForHumanEye(solvemanager, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(msgFile) ; } DenseMtx_sub(mtxZ, mtxX) ; error = DenseMtx_maxabs(mtxZ) ; fprintf(msgFile, "\n\n local error = %12.4e", error) ; MPI_Reduce((void *) &error, (void *) &terror, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global error = %12.4e", terror) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n error matrix") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(mtxX) ; DenseMtx_free(mtxB) ; DenseMtx_free(mtxZ) ; InpMtx_free(mtxA) ; SubMtxManager_free(factormanager) ; SubMtxManager_free(solvemanager) ; ChvManager_free(chvmanager) ; FrontMtx_free(frontmtx) ; ETree_free(frontETree) ; IVL_free(symbfacIVL) ; IV_free(vtxmapIV) ; IV_free(frontOwnersIV) ; SolveMap_free(solvemap) ; MPI_Barrier(MPI_COMM_WORLD) ; fclose(msgFile) ; MPI_Finalize() ; return(1) ; } /*--------------------------------------------------------------------*/ stats[2] = stats[3] = 0 ; tstats[0] = tsMPI/drivers/testIVL_Bcast.c010064400020550007177000000126530657576547100170430ustar00clevecompmath00000400000006/* testIVL_Bcast.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------------ this program tests the IVL_MPI_Bcast() method (1) process root generates a random IVL object and computes its checksum (2) process root broadcasts the IVL object to the other processors (3) each process computes the checksum of its IVL object (4) the checksums are compared on root created -- 98sep10, cca ------------------------------------------------------------------ */ { char *buffer ; double chksum, t1, t2 ; double *sums ; Drand drand ; int ilist, iproc, length, loc, maxlistsize, msglvl, myid, nlist, nproc, root, seed, size ; int *list, *vec ; IVL *ivl ; FILE *msgFile ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nlist maxlistsize seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n nlist -- number of lists in the IVL object" "\n maxlistsize -- maximum size of a list" "\n root -- root processor for broadcast" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } CVfree(buffer) ; } nlist = atoi(argv[3]) ; maxlistsize = atoi(argv[4]) ; root = atoi(argv[5]) ; seed = atoi(argv[6]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n nlist -- %d" "\n maxlistsize -- %d" "\n root -- %d" "\n seed -- %d" "\n", argv[0], msglvl, argv[2], nlist, maxlistsize, root, seed) ; fflush(msgFile) ; /* -------------------------------------------- set up the IVL object and fill owned entries -------------------------------------------- */ MARKTIME(t1) ; ivl = IVL_new() ; if ( myid == root ) { IVL_init1(ivl, IVL_CHUNKED, nlist) ; vec = IVinit(maxlistsize, -1) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0, maxlistsize) ; for ( ilist = 0 ; ilist < nlist ; ilist++ ) { size = (int) Drand_value(&drand) ; Drand_fillIvector(&drand, size, vec) ; IVL_setList(ivl, ilist, size, vec) ; } IVfree(vec) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the IVL object", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { IVL_writeForHumanEye(ivl, msgFile) ; } else { IVL_writeStats(ivl, msgFile) ; } fflush(msgFile) ; if ( myid == root ) { /* -------------------------------------- compute the checksum of the ivl object -------------------------------------- */ for ( ilist = 0, chksum = 0.0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &list) ; chksum += 1 + ilist + size + IVsum(size, list) ; } fprintf(msgFile, "\n\n local chksum = %12.4e", chksum) ; fflush(msgFile) ; } /* ------------------------ broadcast the IVL object ------------------------ */ MARKTIME(t1) ; ivl = IVL_MPI_Bcast(ivl, root, msglvl, msgFile, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : broadcast the IVL object", t2 - t1) ; /* -------------------------------------- compute the checksum of the ivl object -------------------------------------- */ for ( ilist = 0, chksum = 0.0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &list) ; chksum += 1 + ilist + size + IVsum(size, list) ; } fprintf(msgFile, "\n\n local chksum = %12.4e", chksum) ; fflush(msgFile) ; /* --------------------------------------- gather the checksums from the processes --------------------------------------- */ sums = DVinit(nproc, 0.0) ; MPI_Gather((void *) &chksum, 1, MPI_DOUBLE, (void *) sums, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n\n sums") ; DVfprintf(msgFile, nproc, sums) ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { sums[iproc] -= chksum ; } fprintf(msgFile, "\n\n errors") ; DVfprintf(msgFile, nproc, sums) ; fprintf(msgFile, "\n\n maxerror = %12.4e", DVmax(nproc, sums, &loc)); } /* ---------------- free the objects ---------------- */ DVfree(sums) ; IVL_free(ivl) ; /* ------------------------ exit the MPI environment ------------------------ */ MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ MPI/drivers/testIVL_allgather.c010064400020550007177000000141560655671743200177430ustar00clevecompmath00000400000006/* testIVLallgather.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- this program tests the IVL_MPI_allgather() method (1) each process generates the same owners[n] map (2) each process creates an IVL object and fills its owned lists with random numbers (3) the processes gather-all's the lists of ivl created -- 98apr03, cca ------------------------------------------------- */ { char *buffer ; double chksum, globalsum, t1, t2 ; Drand drand ; int ilist, length, myid, msglvl, nlist, nproc, rc, seed, size, tag ; int *list, *owners, *vec ; int stats[4], tstats[4] ; IV *ownersIV ; IVL *ivl ; FILE *msgFile ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n nlist -- number of lists in the IVL object" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } CVfree(buffer) ; } nlist = atoi(argv[3]) ; seed = atoi(argv[4]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n nlist -- %d" "\n seed -- %d" "\n", argv[0], msglvl, argv[2], nlist, seed) ; fflush(msgFile) ; /* ---------------------------- generate the ownersIV object ---------------------------- */ MARKTIME(t1) ; ownersIV = IV_new() ; IV_init(ownersIV, nlist, NULL) ; owners = IV_entries(ownersIV) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0, nproc) ; Drand_fillIvector(&drand, nlist, owners) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the ownersIV object", t2 - t1) ; fflush(msgFile) ; fprintf(msgFile, "\n\n ownersIV generated") ; if ( msglvl > 2 ) { IV_writeForHumanEye(ownersIV, msgFile) ; } else { IV_writeStats(ownersIV, msgFile) ; } fflush(msgFile) ; /* -------------------------------------------- set up the IVL object and fill owned entries -------------------------------------------- */ MARKTIME(t1) ; ivl = IVL_new() ; IVL_init1(ivl, IVL_CHUNKED, nlist) ; vec = IVinit(nlist, -1) ; Drand_setSeed(&drand, seed + myid) ; Drand_setUniform(&drand, 0, nlist) ; for ( ilist = 0 ; ilist < nlist ; ilist++ ) { if ( owners[ilist] == myid ) { size = (int) Drand_value(&drand) ; Drand_fillIvector(&drand, size, vec) ; IVL_setList(ivl, ilist, size, vec) ; } } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the IVL object", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { IVL_writeForHumanEye(ivl, msgFile) ; } else { IVL_writeStats(ivl, msgFile) ; } fflush(msgFile) ; /* -------------------------------------------- compute the local checksum of the ivl object -------------------------------------------- */ for ( ilist = 0, chksum = 0.0 ; ilist < nlist ; ilist++ ) { if ( owners[ilist] == myid ) { IVL_listAndSize(ivl, ilist, &size, &list) ; chksum += 1 + ilist + size + IVsum(size, list) ; } } fprintf(msgFile, "\n\n local partial chksum = %12.4e", chksum) ; fflush(msgFile) ; /* ----------------------- get the global checksum ----------------------- */ rc = MPI_Allreduce((void *) &chksum, (void *) &globalsum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD) ; /* -------------------------------- execute the all-gather operation -------------------------------- */ tag = 47 ; IVzero(4, stats) ; IVL_MPI_allgather(ivl, ownersIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n return from IVL_MPI_allgather()") ; fprintf(msgFile, "\n local send stats : %10d messages with %10d bytes" "\n local recv stats : %10d messages with %10d bytes", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; } MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n total send stats : %10d messages with %10d bytes" "\n total recv stats : %10d messages with %10d bytes", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ivl") ; IVL_writeForHumanEye(ivl, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------- compute the checksum of the entire object ----------------------------------------- */ for ( ilist = 0, chksum = 0.0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(ivl, ilist, &size, &list) ; chksum += 1 + ilist + size + IVsum(size, list) ; } fprintf(msgFile, "\n globalsum = %12.4e, chksum = %12.4e, error = %12.4e", globalsum, chksum, fabs(globalsum - chksum)) ; fflush(msgFile) ; /* ---------------- free the objects ---------------- */ IV_free(ownersIV) ; IVL_free(ivl) ; /* ------------------------ exit the MPI environment ------------------------ */ MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ MPI/drivers/testIVL_alltoall.c010064400020550007177000000131660656762071700176050ustar00clevecompmath00000400000006/* testIVL_alltoall.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- this program tests the IVL_MPI_alltoall() method. (1) each process creates a "send" IVL object and fills the lists with random numbers (3) the processes all-to-all gather the lists to create a "recv" IVL object created -- 98jul26, cca ------------------------------------------------- */ { char *buffer ; double chksum, globalsum1, globalsum2, t1, t2 ; Drand drand ; int ilist, length, myid, msglvl, n, nlist, nproc, rc, seed, size, tag ; int *list, *vec ; int stats[4], tstats[4] ; IVL *recvIVL, *sendIVL ; FILE *msgFile ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n n -- maximum size of any list" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } CVfree(buffer) ; } n = atoi(argv[3]) ; seed = atoi(argv[4]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n n -- %d" "\n seed -- %d" "\n", argv[0], msglvl, argv[2], n, seed) ; fflush(msgFile) ; /* ---------------------------- set up the "send" IVL object ---------------------------- */ MARKTIME(t1) ; sendIVL = IVL_new() ; nlist = nproc ; IVL_init1(sendIVL, IVL_CHUNKED, nlist) ; vec = IVinit(n, -1) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed + myid) ; for ( ilist = 0 ; ilist < nlist ; ilist++ ) { Drand_setUniform(&drand, 0, n) ; size = (int) Drand_value(&drand) ; Drand_setUniform(&drand, 0, n*n) ; Drand_fillIvector(&drand, size, vec) ; IVqsortUp(size, vec) ; IVL_setList(sendIVL, ilist, size, vec) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the IVL object", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { IVL_writeForHumanEye(sendIVL, msgFile) ; } else { IVL_writeStats(sendIVL, msgFile) ; } fflush(msgFile) ; /* -------------------------------------------- compute the local checksum of the ivl object -------------------------------------------- */ for ( ilist = 0, chksum = 0.0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(sendIVL, ilist, &size, &list) ; chksum += 1 + ilist + size + IVsum(size, list) ; } fprintf(msgFile, "\n\n local partial chksum = %12.4e", chksum) ; fflush(msgFile) ; /* ----------------------------- get the first global checksum ----------------------------- */ rc = MPI_Allreduce((void *) &chksum, (void *) &globalsum1, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD) ; /* -------------------------------- execute the all-to-all operation -------------------------------- */ tag = 47 ; IVzero(4, stats) ; recvIVL = IVL_MPI_alltoall(sendIVL, NULL, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n return from IVL_MPI_alltoall()") ; fprintf(msgFile, "\n local send stats : %10d messages with %10d bytes" "\n local recv stats : %10d messages with %10d bytes", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; } MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n total send stats : %10d messages with %10d bytes" "\n total recv stats : %10d messages with %10d bytes", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n recvIVL") ; IVL_writeForHumanEye(recvIVL, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- compute the second global checksum ---------------------------------- */ for ( ilist = 0, chksum = 0.0 ; ilist < nlist ; ilist++ ) { IVL_listAndSize(recvIVL, ilist, &size, &list) ; chksum += 1 + ilist + size + IVsum(size, list) ; } rc = MPI_Allreduce((void *) &chksum, (void *) &globalsum2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD) ; fprintf(msgFile, "\n globalsum1 = %12.4e, globalsum2 = %12.4e, error = %12.4e", globalsum1, globalsum2, fabs(globalsum1 - globalsum2)) ; fflush(msgFile) ; /* ---------------- free the objects ---------------- */ IVL_free(sendIVL) ; IVL_free(recvIVL) ; IVfree(vec) ; /* ------------------------ exit the MPI environment ------------------------ */ MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ ------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- this program tests the IVL_MPI_alltoall() method. (1) each process creates a "send" IVL object and fills the lists with random numbers (3) the processes all-to-all gather the lists to create a "recv" IVL object MPI/drivers/testIV_allgather.c010064400020550007177000000125330655671743200176240ustar00clevecompmath00000400000006/* testIVallgather.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------- this program tests the IV_MPI_allgather() method (1) each process generates the same owners[n] map (2) each process creates a vec[n] vector and fills its owned entries with random numbers (3) the processes gather-all the entries of vec[] created -- 98may20, cca ------------------------------------------------------- */ { char *buffer ; double chksum, globalsum, t1, t2 ; Drand drand ; int ii, length, myid, msglvl, n, nproc, rc, seed, tag ; int *owners, *vec ; int stats[4] ; IV *objIV, *ownersIV ; FILE *msgFile ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n n -- number of entries in the vector" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } CVfree(buffer) ; } n = atoi(argv[3]) ; seed = atoi(argv[4]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n n -- %d" "\n seed -- %d" "\n", argv[0], msglvl, argv[2], n, seed) ; fflush(msgFile) ; /* ---------------------------- generate the ownersIV object ---------------------------- */ MARKTIME(t1) ; ownersIV = IV_new() ; IV_init(ownersIV, n, NULL) ; owners = IV_entries(ownersIV) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0, nproc) ; Drand_fillIvector(&drand, n, owners) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the ownersIV object", t2 - t1) ; fflush(msgFile) ; fprintf(msgFile, "\n\n ownersIV generated") ; if ( msglvl > 2 ) { IV_writeForHumanEye(ownersIV, msgFile) ; } else { IV_writeStats(ownersIV, msgFile) ; } fflush(msgFile) ; /* ---------------------------------------------- set up the vec[] vector and fill owned entries ---------------------------------------------- */ MARKTIME(t1) ; objIV = IV_new() ; IV_init(objIV, n, NULL) ; vec = IV_entries(objIV) ; IVfill(n, vec, -1) ; Drand_setSeed(&drand, seed + myid) ; Drand_setUniform(&drand, 0, n) ; for ( ii = 0 ; ii < n ; ii++ ) { if ( owners[ii] == myid ) { vec[ii] = (int) Drand_value(&drand) ; } } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the objIV object", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { IV_writeForHumanEye(objIV, msgFile) ; } else { IV_writeStats(objIV, msgFile) ; } fflush(msgFile) ; /* ---------------------------------------- compute the local checksum of the vector ---------------------------------------- */ for ( ii = 0, chksum = 0.0 ; ii < n ; ii++ ) { if ( owners[ii] == myid ) { chksum += (ii + 1)*(vec[ii] + 1) ; } } fprintf(msgFile, "\n\n local partial chksum = %12.4e", chksum) ; fflush(msgFile) ; /* ----------------------- get the global checksum ----------------------- */ rc = MPI_Allreduce((void *) &chksum, (void *) &globalsum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD) ; /* -------------------------------- execute the all-gather operation -------------------------------- */ tag = 47 ; IVzero(4, stats) ; IV_MPI_allgather(objIV, ownersIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n return from IV_MPI_allgather()") ; fprintf(msgFile, "\n\n stats") ; IVfprintf(msgFile, 4, stats) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n objIV") ; IV_writeForHumanEye(objIV, msgFile) ; fflush(msgFile) ; } /* ----------------------------------------- compute the checksum of the entire vector ----------------------------------------- */ for ( ii = 0, chksum = 0.0 ; ii < n ; ii++ ) { chksum += (ii + 1)*(vec[ii] + 1) ; } fprintf(msgFile, "\n globalsum = %12.4e, chksum = %12.4e, error = %12.4e", globalsum, chksum, fabs(globalsum - chksum)) ; fflush(msgFile) ; /* ---------------- free the objects ---------------- */ IV_free(ownersIV) ; IV_free(objIV) ; /* ------------------------ exit the MPI environment ------------------------ */ MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ MPI/drivers/testMMM.c010064400020550007177000000420510660745320100156730ustar00clevecompmath00000400000006/* testMMM2.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" #define MMM_WITH_A 0 #define MMM_WITH_AT 1 #define MMM_WITH_AH 2 /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- (1) process 0 creates Y, A and X (2) using a random map, it distributes X (3) using a random map, it distributes Y (4) using a random map, it distributes A created -- 98aug21, cca --------------------------------------------------- */ { char *buffer ; DenseMtx *X, *Xloc, *Y, *Ykeep, *Yloc, *Z ; double imag, real, t1, t2 ; double alpha[2] ; Drand *drand ; InpMtx *A, *Aloc ; int coordType, inputMode, length, myid, msglvl, ncolA, ncolX, nentA, nproc, nrowA, nrowX, nrowY, opflag, seed, symflag, tag ; int stats[4], tstats[4] ; IV *AmapIV, *mapIV, *XmapIV, *XownedIV, *YmapIV, *YownedIV ; FILE *msgFile ; MatMulInfo *info ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; if ( argc != 14 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nrowA ncolA nentA ncolX" "\n coordType inputMode symflag opflag seed real imag" "\n msglvl -- message level" "\n msgFile -- message file" "\n nrowA -- number of rows in A" "\n ncolA -- number of columns in A" "\n nentA -- number of entries in A" "\n ncolX -- number of columns in X" "\n coordType -- coordinate type" "\n 1 -- store by rows" "\n 2 -- store by columns" "\n 3 -- store by chevrons" "\n inputMode -- input mode" "\n 1 -- indices and real entries" "\n 2 -- indices and complex entries" "\n symflag -- symmetry flag" "\n 0 -- symmetric" "\n 1 -- hermitian" "\n 2 -- nonsymmetric" "\n opflag -- operations flag" "\n 0 -- multiply with A" "\n 1 -- multiply with A^T" "\n 2 -- multiply with A^H" "\n seed -- random number seed" "\n real -- real part of scalar alpha" "\n imag -- real part of scalar alpha" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } CVfree(buffer) ; } nrowA = atoi(argv[3]) ; ncolA = atoi(argv[4]) ; nentA = atoi(argv[5]) ; ncolX = atoi(argv[6]) ; coordType = atoi(argv[7]) ; inputMode = atoi(argv[8]) ; symflag = atoi(argv[9]) ; opflag = atoi(argv[10]) ; seed = atoi(argv[11]) ; real = atof(argv[12]) ; imag = atof(argv[13]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n nrowA -- %d" "\n ncolA -- %d" "\n nentA -- %d" "\n ncolX -- %d" "\n coordType -- %d" "\n inputMode -- %d" "\n symflag -- %d" "\n opflag -- %d" "\n seed -- %d" "\n real -- %e" "\n imag -- %e" "\n", argv[0], msglvl, argv[2], nrowA, ncolA, nentA, ncolX, coordType, inputMode, symflag, opflag, seed, real, imag) ; fflush(msgFile) ; /* -------------------- check the input data -------------------- */ if ( nrowA <= 0 || ncolA <= 0 || nentA <= 0 || ncolX <= 0 ) { fprintf(stderr, "\n fatal error, bad dimensions") ; exit(-1) ; } switch ( coordType ) { case INPMTX_BY_ROWS : case INPMTX_BY_COLUMNS : case INPMTX_BY_CHEVRONS : break ; default : fprintf(stderr, "\n bad coordType") ; exit(-1) ; break ; } switch ( inputMode ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n bad type") ; exit(-1) ; break ; } switch ( symflag ) { case SPOOLES_SYMMETRIC : if ( nrowA != ncolA ) { fprintf(stderr, "\n fatal error, symmetric but nrowA = %d, ncolA = %d", nrowA, ncolA) ; exit(-1) ; } nrowX = nrowA ; nrowY = nrowA ; break ; case SPOOLES_HERMITIAN : if ( nrowA != ncolA ) { fprintf(stderr, "\n fatal error, hermitian but nrowA = %d, ncolA = %d", nrowA, ncolA) ; exit(-1) ; } if ( inputMode != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error, hermitian but not complex") ; exit(-1) ; } nrowX = nrowA ; nrowY = nrowA ; break ; case SPOOLES_NONSYMMETRIC : if ( opflag == MMM_WITH_AT || opflag == MMM_WITH_AH ) { nrowX = nrowA ; nrowY = ncolA ; } else { nrowX = ncolA ; nrowY = nrowA ; } break ; default : fprintf(stderr, "\n bad symflag") ; exit(-1) ; break ; } switch ( opflag ) { case MMM_WITH_A : case MMM_WITH_AT : case MMM_WITH_AH : break ; default : fprintf(stderr, "\n bad opflag") ; exit(-1) ; break ; } alpha[0] = real ; alpha[1] = imag ; /* ---------------------------------- create the random number generator ---------------------------------- */ drand = Drand_new() ; Drand_setSeed(drand, seed) ; if ( myid == 0 ) { /* --------------------------------------- processor 0, generate a random matrices --------------------------------------- */ MARKTIME(t1) ; A = InpMtx_new() ; InpMtx_init(A, INPMTX_BY_ROWS, inputMode, nentA, 0) ; Drand_setUniform(drand, 0, nrowA) ; Drand_fillIvector(drand, nentA, InpMtx_ivec1(A)) ; Drand_setUniform(drand, 0, ncolA) ; Drand_fillIvector(drand, nentA, InpMtx_ivec2(A)) ; Drand_setUniform(drand, -1.0, 1.0) ; if ( inputMode == SPOOLES_REAL ) { Drand_fillDvector(drand, nentA, InpMtx_dvec(A)) ; } else if ( inputMode == SPOOLES_COMPLEX ) { Drand_fillDvector(drand, 2*nentA, InpMtx_dvec(A)) ; } A->nent = nentA ; InpMtx_sortAndCompress(A) ; InpMtx_changeCoordType(A, coordType) ; InpMtx_changeStorageMode(A, INPMTX_BY_VECTORS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : generate random matrix A", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n global matrix A") ; InpMtx_writeForHumanEye(A, msgFile) ; fflush(msgFile) ; } /* ----------------- create a matrix X ----------------- */ MARKTIME(t1) ; X = DenseMtx_new() ; DenseMtx_init(X, inputMode, 1, -1, nrowX, ncolX, 1, nrowX) ; if ( inputMode == SPOOLES_REAL ) { Drand_fillDvector(drand, nrowX*ncolX, DenseMtx_entries(X)) ; } else if ( inputMode == SPOOLES_COMPLEX ) { Drand_fillDvector(drand, 2*nrowX*ncolX, DenseMtx_entries(X)) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n global matrix X") ; DenseMtx_writeForHumanEye(X, msgFile) ; fflush(msgFile) ; } /* ----------------- create a matrix Y ----------------- */ MARKTIME(t1) ; Y = DenseMtx_new() ; DenseMtx_init(Y, inputMode, 1, -1, nrowY, ncolX, 1, nrowY) ; if ( inputMode == SPOOLES_REAL ) { Drand_fillDvector(drand, nrowY*ncolX, DenseMtx_entries(Y)) ; } else if ( inputMode == SPOOLES_COMPLEX ) { Drand_fillDvector(drand, 2*nrowY*ncolX, DenseMtx_entries(Y)) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n global matrix Y") ; DenseMtx_writeForHumanEye(Y, msgFile) ; fflush(msgFile) ; } /* ------------------------------- create Ykeep and copy Y into it ------------------------------- */ MARKTIME(t1) ; Ykeep = DenseMtx_new() ; DenseMtx_init(Ykeep, inputMode, 1, -1, nrowY, ncolX, 1, nrowY) ; if ( inputMode == SPOOLES_REAL ) { DVcopy(nrowY*ncolX, DenseMtx_entries(Ykeep), DenseMtx_entries(Y)) ; } else if ( inputMode == SPOOLES_COMPLEX ) { DVcopy(2*nrowY*ncolX, DenseMtx_entries(Ykeep), DenseMtx_entries(Y)) ; } /* ----------------------------------------- compute the serial matrix-matrix multiply ----------------------------------------- */ switch ( symflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_mmm(A, Ykeep, alpha, X) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_mmm(A, Ykeep, alpha, X) ; break ; case SPOOLES_NONSYMMETRIC : switch ( opflag ) { case MMM_WITH_A : InpMtx_nonsym_mmm(A, Ykeep, alpha, X) ; break ; case MMM_WITH_AT : InpMtx_nonsym_mmm_T(A, Ykeep, alpha, X) ; break ; case MMM_WITH_AH : InpMtx_nonsym_mmm_H(A, Ykeep, alpha, X) ; break ; } break ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n Ykeep") ; DenseMtx_writeForHumanEye(Ykeep, msgFile) ; fflush(msgFile) ; } } else { /* ----------------------------- initialize the empty matrices ----------------------------- */ A = InpMtx_new() ; InpMtx_init(A, coordType, inputMode, 0, 0) ; X = DenseMtx_new() ; DenseMtx_init(X, inputMode, 1, -1, 0, ncolX, 1, 0) ; Y = DenseMtx_new() ; DenseMtx_init(Y, inputMode, 1, -1, 0, ncolX, 1, 0) ; Ykeep = NULL ; } /* -------------------------------------- set the A owners IV to be a random map -------------------------------------- */ Drand_setSeed(drand, ++seed) ; Drand_setUniform(drand, 0, nproc) ; AmapIV = IV_new() ; switch ( coordType ) { case INPMTX_BY_ROWS : IV_init(AmapIV, nrowA, NULL) ; Drand_fillIvector(drand, nrowA, IV_entries(AmapIV)) ; break ; case INPMTX_BY_COLUMNS : IV_init(AmapIV, ncolA, NULL) ; Drand_fillIvector(drand, ncolA, IV_entries(AmapIV)) ; break ; case INPMTX_BY_CHEVRONS : IV_init(AmapIV, nrowA, NULL) ; Drand_fillIvector(drand, nrowA, IV_entries(AmapIV)) ; break ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n A's map") ; IV_writeForHumanEye(AmapIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------------ split the InpMtx object into pieces ------------------------------------ */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; tag = 1 ; MARKTIME(t1) ; InpMtx_changeStorageMode(A, INPMTX_BY_VECTORS) ; Aloc = InpMtx_MPI_split(A, AmapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : A matrix split", t2 - t1) ; fprintf(msgFile, "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } InpMtx_free(A) ; A = NULL ; tag += 2 ; fprintf(msgFile, "\n\n local InpMtx object ") ; if ( msglvl > 1 ) { InpMtx_writeForHumanEye(Aloc, msgFile) ; } else { InpMtx_writeStats(Aloc, msgFile) ; } fflush(msgFile) ; /* -------------------------------------- set the Y owners IV to be a random map -------------------------------------- */ Drand_setSeed(drand, ++seed) ; Drand_setUniform(drand, 0, nproc) ; YmapIV = IV_new() ; IV_init(YmapIV, nrowY, NULL) ; Drand_fillIvector(drand, nrowY, IV_entries(YmapIV)) ; YownedIV = IV_targetEntries(YmapIV, myid) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n Y's map") ; IV_writeForHumanEye(YmapIV, msgFile) ; fprintf(msgFile, "\n\n owned rows of Y") ; IV_writeForHumanEye(YownedIV, msgFile) ; fflush(msgFile) ; } /* --------------------------------------- split the Y DenseMtx object into pieces --------------------------------------- */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; tag++ ; MARKTIME(t1) ; Yloc = DenseMtx_MPI_splitByRows(Y, YmapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : Y matrix split", t2 - t1) ; fprintf(msgFile, "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } DenseMtx_free(Y) ; Y = NULL ; tag += 2 ; fprintf(msgFile, "\n\n local Y DenseMtx object ") ; if ( msglvl > 1 ) { DenseMtx_writeForHumanEye(Yloc, msgFile) ; } else { DenseMtx_writeStats(Yloc, msgFile) ; } fflush(msgFile) ; /* -------------------------------------- set the X owners IV to be a random map -------------------------------------- */ Drand_setSeed(drand, ++seed) ; Drand_setUniform(drand, 0, nproc) ; XmapIV = IV_new() ; IV_init(XmapIV, nrowX, NULL) ; Drand_fillIvector(drand, nrowX, IV_entries(XmapIV)) ; XownedIV = IV_targetEntries(XmapIV, myid) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n X's map") ; IV_writeForHumanEye(XmapIV, msgFile) ; fprintf(msgFile, "\n\n owned rows of X") ; IV_writeForHumanEye(XownedIV, msgFile) ; fflush(msgFile) ; } /* --------------------------------------- split the X DenseMtx object into pieces --------------------------------------- */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; tag++ ; MARKTIME(t1) ; Xloc = DenseMtx_MPI_splitByRows(X, XmapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : X matrix split", t2 - t1) ; fprintf(msgFile, "\n local comm : %6d %12d %6d %12d", stats[0], stats[2], stats[1], stats[3]) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n global comm : %6d %12d %6d %12d", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } DenseMtx_free(X) ; X = NULL ; tag += 2 ; fprintf(msgFile, "\n\n after splitting the X DenseMtx object with the wrap map") ; if ( msglvl > 1 ) { DenseMtx_writeForHumanEye(Xloc, msgFile) ; } else { DenseMtx_writeStats(Xloc, msgFile) ; } fflush(msgFile) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------- initialize the MatMulInfo data structure ---------------------------------------- */ IVfill(4, stats, 0) ; tag = 1 ; info = MatMul_MPI_setup(Aloc, symflag, opflag, XmapIV, YmapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; /* ------------------------------------------- map the input matrix into local coordinates ------------------------------------------- */ MatMul_setLocalIndices(info, Aloc) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n local A") ; InpMtx_writeForHumanEye(Aloc, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- compute the matrix-matrix multiply ---------------------------------- */ MatMul_MPI_mmm(info, Yloc, alpha, Aloc, Xloc, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after mmm, local matrix Y") ; DenseMtx_writeForHumanEye(Yloc, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------------------------- gather all of Yloc onto processor 0 and compare with Ykeep ---------------------------------------------------------- */ mapIV = IV_new() ; IV_init(mapIV, nrowY, NULL) ; IV_fill(mapIV, 0) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n mapIV to gather Y") ; IV_writeForHumanEye(mapIV, msgFile) ; fflush(msgFile) ; } Z = DenseMtx_MPI_splitByRows(Yloc, mapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; DenseMtx_free(Yloc) ; Yloc = Z ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n Yloc after split") ; DenseMtx_writeForHumanEye(Yloc, msgFile) ; fflush(msgFile) ; } if ( myid == 0 ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n global Yloc") ; DenseMtx_writeForHumanEye(Yloc, msgFile) ; fflush(msgFile) ; } DenseMtx_sub(Ykeep, Yloc) ; fprintf(msgFile, "\n\n error = %12.4e", DenseMtx_maxabs(Ykeep)) ; } /* ------------------------------ clean up the MatMulInfo object ------------------------------ */ MatMul_cleanup(info) ; info = NULL ; /* ---------------- free the objects ---------------- */ IV_free(AmapIV) ; IV_free(XmapIV) ; IV_free(XownedIV) ; IV_free(YmapIV) ; IV_free(YownedIV) ; InpMtx_free(Aloc) ; DenseMtx_free(Xloc) ; DenseMtx_free(Yloc) ; if ( Ykeep != NULL ) { DenseMtx_free(Ykeep) ; } IV_free(mapIV) ; Drand_free(drand) ; MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ _entries(X)) ; } else if ( inputMode == SPOOLES_COMPLEX ) { Drand_fillDvector(drand, 2*nrowX*ncolX, DenseMtx_entries(X)) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n global matrix X") ; DenseMtx_writeForHumanEye(X, msgFile) ; fflush(msgFile) ; } /* ----------------- create a matrix Y ----------------- */ MARKTIME(t1) ; Y = DenseMtx_new() ; DenseMtx_init(Y, inputMode, 1, -1, nrowY, ncolX, 1, nrowY) ; if ( inpuMPI/drivers/testScatterDenseMtx.c010064400020550007177000000222460660346564700203430ustar00clevecompmath00000400000006/* testScatterDenseMtx.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------------ this program tests the simple split and merge of a DenseMtx object (1) process root generates a nrow x ncol DenseMtx object (2) using a random map, scatter the rows into local matrices (3) gather the local matrices into a second global matrix and compare created -- 98sep26, cca ------------------------------------------------------------------ */ { char *buffer ; DenseMtx *X, *Y, *Z ; double t1, t2 ; double checksums[3], Xchecksums[3], Ychecksums[3], Zchecksums[3] ; Drand drand ; int inc1, inc2, length, myid, msglvl, ncol, nproc, nrow, root, seed, tag, type, v ; int *map ; int stats[4], tstats[4] ; IV *mapIV ; FILE *msgFile ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ /* fprintf(stdout, "\n stdout, MPI_COMM_WORLD = %p", MPI_COMM_WORLD) ; fflush(stdout) ; */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; /* fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; */ if ( argc != 10 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow ncol inc1 inc2 seed root" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- number of rows" "\n ncol -- number of columns" "\n inc1 -- row increment" "\n inc2 -- column increment" "\n seed -- random number seed" "\n root -- root processor" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(0) ; } CVfree(buffer) ; } type = atoi(argv[3]) ; nrow = atoi(argv[4]) ; ncol = atoi(argv[5]) ; inc1 = atoi(argv[6]) ; inc2 = atoi(argv[7]) ; seed = atoi(argv[8]) ; root = atoi(argv[9]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n type -- %d" "\n nrow -- %d" "\n ncol -- %d" "\n inc1 -- %d" "\n inc2 -- %d" "\n seed -- %d" "\n root -- %d" "\n", argv[0], msglvl, argv[2], type, nrow, ncol, inc1, inc2, seed, root) ; fflush(msgFile) ; /* ----------------------------- generate the DenseMtx object ----------------------------- */ if ( myid == root ) { X = DenseMtx_new() ; fprintf(msgFile, "\n X = %p", X) ; fflush(msgFile) ; MARKTIME(t1) ; DenseMtx_init(X, type, 1, -1, nrow, ncol, inc1, inc2) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0.0, 1.0) ; switch ( type ) { case SPOOLES_REAL : Drand_fillDvector(&drand, nrow*ncol, DenseMtx_entries(X)) ; break ; case SPOOLES_COMPLEX : Drand_fillDvector(&drand, 2*nrow*ncol, DenseMtx_entries(X)) ; break ; } /* ------------------------------------------ compute the serial checksums of the matrix ------------------------------------------ */ DenseMtx_checksums(X, Xchecksums) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the DenseMtx object", t2 - t1) ; fflush(msgFile) ; fprintf(msgFile, "\n\n DenseMtx generated") ; if ( msglvl > 2 ) { DenseMtx_writeForHumanEye(X, msgFile) ; } else { DenseMtx_writeStats(X, msgFile) ; } fflush(msgFile) ; /* --------------------- generate a random map --------------------- */ MARKTIME(t1) ; mapIV = IV_new() ; IV_init(mapIV, nrow, NULL) ; map = IV_entries(mapIV) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0.0, (double) nrow) ; for ( v = 0 ; v < nrow ; v++ ) { map[v] = ((int) Drand_value(&drand)) % nproc ; if ( map[v] == root ) { map[v] = nproc - 1 ; } } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : generate random map", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n map") ; IV_writeForHumanEye(mapIV, msgFile) ; fflush(msgFile) ; } } else { X = NULL ; mapIV = NULL ; } /* ------------------------------------------ now scatter the matrix with the random map ------------------------------------------ */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; tag = 1 ; Y = DenseMtx_MPI_splitFromGlobalByRows(X, NULL, mapIV, root, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : scatter matrix ", t2 - t1) ; fprintf(msgFile, "\n send stats : %d messages with %d bytes" "\n recv stats : %d messages with %d bytes", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, root, MPI_COMM_WORLD) ; if ( myid == root ) { fprintf(msgFile, "\n total send stats : %d messages with %d bytes" "\n total recv stats : %d messages with %d bytes", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( Y != NULL ) { fprintf(msgFile, "\n\n local matrix") ; if ( msglvl > 2 ) { DenseMtx_writeForHumanEye(Y, msgFile) ; } else { DenseMtx_writeStats(Y, msgFile) ; } } else { fprintf(msgFile, "\n\n local matrix is NULL") ; } fflush(msgFile) ; /* ----------------------------------------------- compute the checksums of the distributed matrix ----------------------------------------------- */ if ( Y != NULL ) { DenseMtx_checksums(Y, checksums) ; } else { checksums[0] = checksums[1] = checksums[2] = 0.0 ; } MPI_Reduce((void *) checksums, (void *) Ychecksums, 3, MPI_DOUBLE, MPI_SUM, root, MPI_COMM_WORLD) ; if ( myid == root ) { fprintf(msgFile, "\n\n checksums for original matrix : %12.4e %12.4e" "\n checksums for distributed matrix : %12.4e %12.4e" "\n error in checksum : %12.4e %12.4e", Xchecksums[0], Xchecksums[2], Ychecksums[0], Ychecksums[2], Ychecksums[0] - Xchecksums[0], Ychecksums[2] - Xchecksums[2]) ; } /* ----------------------------------------------------- gather the local matrices into a second global matrix ----------------------------------------------------- */ MARKTIME(t1) ; stats[0] = stats[1] = stats[2] = stats[3] = 0 ; if ( myid == root ) { Z = DenseMtx_new() ; fprintf(msgFile, "\n Z = %p", Z) ; } else { Z = NULL ; } Z = DenseMtx_MPI_mergeToGlobalByRows(Z, Y, root, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; fprintf(msgFile, "\n Z = %p", Z) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : merge into global matrix ", t2 - t1) ; fprintf(msgFile, "\n send stats : %d messages with %d bytes" "\n recv stats : %d messages with %d bytes", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, root, MPI_COMM_WORLD) ; if ( myid == root ) { fprintf(msgFile, "\n total send stats : %d messages with %d bytes" "\n total recv stats : %d messages with %d bytes", tstats[0], tstats[2], tstats[1], tstats[3]) ; DenseMtx_sort(Z) ; fprintf(msgFile, "\n\n global Z matrix") ; if ( msglvl > 2 ) { DenseMtx_writeForHumanEye(Z, msgFile) ; } else { DenseMtx_writeStats(Z, msgFile) ; } fflush(msgFile) ; DenseMtx_checksums(Z, Zchecksums) ; fprintf(msgFile, "\n\n checksums for original matrix : %12.4e %12.4e" "\n checksums for distributed matrix : %12.4e %12.4e" "\n checksums for global matrix : %12.4e %12.4e" "\n X x Y error in checksum : %12.4e %12.4e" "\n X x Z error in checksum : %12.4e %12.4e", Xchecksums[0], Xchecksums[2], Ychecksums[0], Ychecksums[2], Zchecksums[0], Zchecksums[2], Xchecksums[0] - Ychecksums[0], Xchecksums[2] - Ychecksums[2], Xchecksums[0] - Zchecksums[0], Xchecksums[2] - Zchecksums[2]) ; } /* ---------------- free the objects ---------------- */ if ( myid == root ) { IV_free(mapIV) ; } if ( X != NULL ) { DenseMtx_free(X) ; } if ( Y != NULL ) { DenseMtx_free(Y) ; } if ( Z != NULL ) { DenseMtx_free(Z) ; } MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ MARKTIME(t1) ; mapIV = IV_new() ; IV_init(mapIV, nrow, NULL) ; map = IV_entries(mapIV) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0.0, (double) nrow) ; for ( v = 0 ; v < nrow ; v++ ) { map[v] = ((int) Drand_value(&drand)) % nproc ; if ( map[v] == root ) { mMPI/drivers/testScatterInpMtx.c010064400020550007177000000174710660347026700200310ustar00clevecompmath00000400000006/* testScatterInpMtx.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- (1) process root generates an InpMtx object (2) using a random map, it distributes the object created -- 98sep27, cca --------------------------------------------------- */ { char *buffer ; InpMtx *mtxA, *mtxB ; double t1, t2 ; double schecksums[3], pchecksums[3], tchecksums[3] ; Drand *drand ; int coordType, inputMode, iproc, length, myid, msglvl, nent, neqns, nproc, rc, root, seed, tag, v ; int ibuffer[3], stats[4], tstats[4] ; int *map ; IV *mapIV ; FILE *msgFile ; MPI_Status status ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile neqns nent seed " "\n coordType inputMode root" "\n msglvl -- message level" "\n msgFile -- message file" "\n neqns -- number of equations" "\n nent -- number of equations" "\n seed -- random number seed" "\n coordType -- coordinate type" "\n 1 -- store by rows" "\n 2 -- store by columns" "\n 3 -- store by chevrons" "\n inputMode -- input mode" "\n 0 -- indices only" "\n 1 -- indices and real entries" "\n 2 -- indices and complex entries" "\n root -- root processor that creates the global matrix" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } CVfree(buffer) ; } neqns = atoi(argv[3]) ; nent = atoi(argv[4]) ; seed = atoi(argv[5]) ; coordType = atoi(argv[6]) ; inputMode = atoi(argv[7]) ; root = atoi(argv[8]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n neqns -- %d" "\n nent -- %d" "\n seed -- %d" "\n coordType -- %d" "\n inputMode -- %d" "\n root -- %d" "\n", argv[0], msglvl, argv[2], neqns, nent, seed, coordType, inputMode, root) ; fflush(msgFile) ; /* ---------------------------------- create the random number generator ---------------------------------- */ if ( myid == root ) { /* ---------------------------------------------- processor root, generate a random input matrix ---------------------------------------------- */ MARKTIME(t1) ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, inputMode, nent, 0) ; drand = Drand_new() ; Drand_setSeed(drand, seed) ; Drand_setUniform(drand, 0, neqns) ; Drand_fillIvector(drand, nent, InpMtx_ivec1(mtxA)) ; Drand_fillIvector(drand, nent, InpMtx_ivec2(mtxA)) ; if ( inputMode == SPOOLES_REAL ) { Drand_setUniform(drand, -1.0, 1.0) ; Drand_fillDvector(drand, nent, InpMtx_dvec(mtxA)) ; } else if ( inputMode == SPOOLES_COMPLEX ) { Drand_setUniform(drand, -1.0, 1.0) ; Drand_fillDvector(drand, 2*nent, InpMtx_dvec(mtxA)) ; } mtxA->nent = nent ; InpMtx_sortAndCompress(mtxA) ; InpMtx_changeCoordType(mtxA, coordType) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : generate random matrix", t2 - t1) ; /* ----------------------------------------------- change the coordinate type and the storage mode ----------------------------------------------- */ InpMtx_changeCoordType(mtxA, coordType) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; mtxA->inputMode = inputMode ; fprintf(msgFile, "\n\n random input matrix") ; if ( msglvl > 2 ) { InpMtx_writeForHumanEye(mtxA, msgFile) ; } else { InpMtx_writeStats(mtxA, msgFile) ; } fflush(msgFile) ; /* ------------------------------------------ compute the serial checksums of the matrix ------------------------------------------ */ InpMtx_checksums(mtxA, schecksums) ; fprintf(msgFile, "\n schecksums %12.4e %12.4e %12.4e", schecksums[0], schecksums[1], schecksums[2]) ; fflush(msgFile) ; /* --------------------- generate a random map --------------------- */ MARKTIME(t1) ; Drand_setSeed(drand, seed + 1) ; Drand_setUniform(drand, 0.0, (double) neqns) ; mapIV = IV_new() ; IV_init(mapIV, neqns, NULL) ; map = IV_entries(mapIV) ; for ( v = 0 ; v < neqns ; v++ ) { map[v] = ((int) Drand_value(drand)) % nproc ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : random map set", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n map") ; IV_writeForHumanEye(mapIV, msgFile) ; fflush(msgFile) ; } } else { mtxA = NULL ; mapIV = NULL ; } /* ------------------------------------------ now scatter the matrix with the random map ------------------------------------------ */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; mtxB = InpMtx_MPI_splitFromGlobal(mtxA, NULL, mapIV, root, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : matrix split", t2 - t1) ; fprintf(msgFile, "\n send stats : %d messages with %d bytes" "\n recv stats : %d messages with %d bytes", stats[0], stats[2], stats[1], stats[3]) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, root, MPI_COMM_WORLD) ; if ( myid == root ) { fprintf(msgFile, "\n total send stats : %d messages with %d bytes" "\n total recv stats : %d messages with %d bytes", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } if ( mtxA != NULL ) { InpMtx_free(mtxA) ; } mtxA = mtxB ; fprintf(msgFile, "\n\n after splitting the InpMtx object with the owners map") ; if ( msglvl > 2 ) { InpMtx_writeForHumanEye(mtxA, msgFile) ; } else { InpMtx_writeStats(mtxA, msgFile) ; } fflush(msgFile) ; /* ----------------------------------------------- compute the checksums of the distributed matrix ----------------------------------------------- */ InpMtx_checksums(mtxA, pchecksums) ; MPI_Reduce((void *) pchecksums, (void *) tchecksums, 3, MPI_DOUBLE, MPI_SUM, root, MPI_COMM_WORLD) ; if ( myid == root ) { fprintf(msgFile, "\n\n checksums for original matrix : %12.4e %12.4e %12.4e" "\n checksums for distributed matrix : %12.4e %12.4e %12.4e" "\n error in checksum : %12.4e %12.4e %12.4e", schecksums[0], schecksums[1], schecksums[2], tchecksums[0], tchecksums[1], tchecksums[2], tchecksums[0] - schecksums[0], tchecksums[1] - schecksums[1], tchecksums[2] - schecksums[2]) ; } /* ---------------- free the objects ---------------- */ if ( myid == root ) { IV_free(mapIV) ; Drand_free(drand) ; } InpMtx_free(mtxA) ; MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ oordType -- %d" "\n inputMode -- %d" "\n root -- %d" "\n", argv[0], msglvl, argv[2], neqns, nent, seed, coordType, inputMode, root) ; fflush(msgFile) MPI/drivers/testSplitDenseMtx.c010064400020550007177000000203440656061507600200210ustar00clevecompmath00000400000006/* testSplitDenseMtx.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------------- this program tests splitting a DenseMtx object (1) process 0 generates a nrow x ncol DenseMtx object (2) using a wrap map, distribute the object (3) using a random map, distribute the object again created -- 98may16, cca ----------------------------------------------------- */ { char *buffer ; DenseMtx *mtx, *mtxkeep ; double t1, t2 ; double pchecksums[3], schecksums[3], tchecksums[3] ; Drand drand ; int inc1, inc2, length, myid, msglvl, ncol, nproc, nrow, seed, tag, type, v ; int *map ; int stats[4], tstats[4] ; IV *mapIV ; FILE *msgFile ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ /* fprintf(stdout, "\n stdout, MPI_COMM_WORLD = %p", MPI_COMM_WORLD) ; fflush(stdout) ; */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; /* fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; */ if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrow ncol inc1 inc2 seed " "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 -- real" "\n 2 -- complex" "\n nrow -- number of rows" "\n ncol -- number of columns" "\n inc1 -- row increment" "\n inc2 -- column increment" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(0) ; } CVfree(buffer) ; } type = atoi(argv[3]) ; nrow = atoi(argv[4]) ; ncol = atoi(argv[5]) ; inc1 = atoi(argv[6]) ; inc2 = atoi(argv[7]) ; seed = atoi(argv[8]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n type -- %d" "\n nrow -- %d" "\n ncol -- %d" "\n inc1 -- %d" "\n inc2 -- %d" "\n seed -- %d" "\n", argv[0], msglvl, argv[2], type, nrow, ncol, inc1, inc2, seed) ; fflush(msgFile) ; /* ----------------------------- generate the DenseMtx object ----------------------------- */ mtx = DenseMtx_new() ; fprintf(msgFile, "\n mtx = %p", mtx) ; fflush(msgFile) ; MARKTIME(t1) ; if ( myid == 0 ) { DenseMtx_init(mtx, type, 1, -1, nrow, ncol, inc1, inc2) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0.0, 1.0) ; Drand_fillDvector(&drand, nrow*ncol, DenseMtx_entries(mtx)) ; /* ------------------------------------------ compute the serial checksums of the matrix ------------------------------------------ */ DenseMtx_checksums(mtx, schecksums) ; } else { if ( inc1 == 1 ) { DenseMtx_init(mtx, type, 1, -1, 0, ncol, inc1, 0) ; } else { DenseMtx_init(mtx, type, 1, -1, 0, ncol, inc1, inc2) ; } } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the DenseMtx object", t2 - t1) ; fflush(msgFile) ; fprintf(msgFile, "\n\n DenseMtx generated") ; if ( msglvl > 2 ) { DenseMtx_writeForHumanEye(mtx, msgFile) ; } else { DenseMtx_writeStats(mtx, msgFile) ; } fflush(msgFile) ; /* ------------------------------------------ set the initial owners IV to be a wrap map ------------------------------------------ */ MARKTIME(t1) ; mapIV = IV_new() ; IV_init(mapIV, nrow, NULL) ; map = IV_entries(mapIV) ; for ( v = 0 ; v < nrow ; v++ ) { map[v] = v % nproc ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set wrap map", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n map") ; IV_writeForHumanEye(mapIV, msgFile) ; fflush(msgFile) ; } /* -------------------------------------- split the DenseMtx object into pieces -------------------------------------- */ tag = 1 ; stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; mtxkeep = DenseMtx_MPI_splitByRows(mtx, mapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : split matrix", t2 - t1) ; fprintf(msgFile, "\n send stats : %d messages with %d bytes" "\n recv stats : %d messages with %d bytes", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n total send stats : %d messages with %d bytes" "\n total recv stats : %d messages with %d bytes", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } DenseMtx_free(mtx) ; mtx = mtxkeep ; tag += 2 ; fprintf(msgFile, "\n\n after splitting the DenseMtx object with the wrap map") ; if ( msglvl > 2 ) { DenseMtx_writeForHumanEye(mtx, msgFile) ; } else { DenseMtx_writeStats(mtx, msgFile) ; } fflush(msgFile) ; /* --------------------- generate a random map --------------------- */ MARKTIME(t1) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0.0, (double) nrow) ; for ( v = 0 ; v < nrow ; v++ ) { map[v] = ((int) Drand_value(&drand)) % nproc ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : generate random map", t2 - t1) ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n map") ; IV_writeForHumanEye(mapIV, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------- now split the matrix with the random map ---------------------------------------- */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; mtxkeep = DenseMtx_MPI_splitByRows(mtx, mapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : split matrix ", t2 - t1) ; fprintf(msgFile, "\n send stats : %d messages with %d bytes" "\n recv stats : %d messages with %d bytes", stats[0], stats[2], stats[1], stats[3]) ; fflush(msgFile) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n total send stats : %d messages with %d bytes" "\n total recv stats : %d messages with %d bytes", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } DenseMtx_free(mtx) ; mtx = mtxkeep ; fprintf(msgFile, "\n\n after splitting the DenseMtx object with the owners map") ; if ( msglvl > 2 ) { DenseMtx_writeForHumanEye(mtx, msgFile) ; } else { DenseMtx_writeStats(mtx, msgFile) ; } fflush(msgFile) ; /* ----------------------------------------------- compute the checksums of the distributed matrix ----------------------------------------------- */ DenseMtx_checksums(mtx, pchecksums) ; MPI_Reduce((void *) pchecksums, (void *) tchecksums, 3, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n\n checksums for original matrix : %12.4e %12.4e" "\n checksums for distributed matrix : %12.4e %12.4e" "\n error in checksum : %12.4e %12.4e", schecksums[0], schecksums[2], tchecksums[0], tchecksums[2], tchecksums[0] - schecksums[0], tchecksums[2] - schecksums[2]) ; } /* ---------------- free the objects ---------------- */ IV_free(mapIV) ; DenseMtx_free(mtx) ; MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ ement" "\n inc2 -- column increment" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; MPI/drivers/testSplitInpMtx.c010064400020550007177000000242570660327262700175170ustar00clevecompmath00000400000006/* testSplitInpMtx.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- (1) process 0 reads in a InpMtx object. (2) using a wrap map, distribute the object (3) using a random map, distribute the object again created -- 98may16, cca --------------------------------------------------- */ { char *buffer ; InpMtx *mtxA, *mtxB ; double t1, t2 ; double schecksums[3], pchecksums[3], tchecksums[3] ; Drand *drand ; int coordType, inputMode, iproc, length, myid, msglvl, nent, neqns, nproc, rc, seed, tag, v ; int ibuffer[3], stats[4], tstats[4] ; int *map ; IV *mapIV ; FILE *msgFile ; MPI_Status status ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile neqns nent seed " "\n coordType inputMode " "\n msglvl -- message level" "\n msgFile -- message file" "\n neqns -- number of equations" "\n nent -- number of equations" "\n seed -- random number seed" "\n coordType -- coordinate type" "\n 1 -- store by rows" "\n 2 -- store by columns" "\n 3 -- store by chevrons" "\n inputMode -- input mode" "\n 0 -- indices only" "\n 1 -- indices and real entries" "\n 2 -- indices and complex entries" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } CVfree(buffer) ; } neqns = atoi(argv[3]) ; nent = atoi(argv[4]) ; seed = atoi(argv[5]) ; coordType = atoi(argv[6]) ; inputMode = atoi(argv[7]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n neqns -- %d" "\n nent -- %d" "\n seed -- %d" "\n coordType -- %d" "\n inputMode -- %d" "\n", argv[0], msglvl, argv[2], neqns, nent, seed, coordType, inputMode) ; fflush(msgFile) ; /* ---------------------------------- create the random number generator ---------------------------------- */ drand = Drand_new() ; Drand_setSeed(drand, seed) ; if ( myid == 0 ) { /* ------------------------------------------- processor 0, generate a random input matrix ------------------------------------------- */ MARKTIME(t1) ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, inputMode, nent, 0) ; Drand_setUniform(drand, 0, neqns) ; Drand_fillIvector(drand, nent, InpMtx_ivec1(mtxA)) ; Drand_fillIvector(drand, nent, InpMtx_ivec2(mtxA)) ; if ( inputMode == SPOOLES_REAL ) { Drand_setUniform(drand, -1.0, 1.0) ; Drand_fillDvector(drand, nent, InpMtx_dvec(mtxA)) ; } else if ( inputMode == SPOOLES_COMPLEX ) { Drand_setUniform(drand, -1.0, 1.0) ; Drand_fillDvector(drand, 2*nent, InpMtx_dvec(mtxA)) ; } mtxA->nent = nent ; InpMtx_sortAndCompress(mtxA) ; InpMtx_changeCoordType(mtxA, coordType) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : generate random matrix", t2 - t1) ; /* ----------------------------------------------- change the coordinate type and the storage mode ----------------------------------------------- */ InpMtx_changeCoordType(mtxA, coordType) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; mtxA->inputMode = inputMode ; fprintf(msgFile, "\n\n random input matrix") ; if ( msglvl > 2 ) { InpMtx_writeForHumanEye(mtxA, msgFile) ; } else { InpMtx_writeStats(mtxA, msgFile) ; } fflush(msgFile) ; /* ------------------------------------------ compute the serial checksums of the matrix ------------------------------------------ */ InpMtx_checksums(mtxA, schecksums) ; /* ----------------------------------- send the first message identifying the coordinate type, and input mode ----------------------------------- */ tag = 1 ; ibuffer[0] = InpMtx_coordType(mtxA) ; ibuffer[1] = InpMtx_inputMode(mtxA) ; MARKTIME(t1) ; for ( iproc = 1 ; iproc < nproc ; iproc++ ) { MPI_Send((void *) ibuffer, 2, MPI_INT, iproc, tag, MPI_COMM_WORLD); } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : first message sent", t2 - t1) ; } else { /* -------------------------------------------- receive the first message identifying the coordinate type, storage mode and input mode -------------------------------------------- */ tag = 1 ; MARKTIME(t1) ; MPI_Recv((void *) ibuffer, 2, MPI_INT, 0, tag, MPI_COMM_WORLD, &status) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : first message received", t2 - t1) ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, ibuffer[0], ibuffer[1], 0, 0) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; fprintf(msgFile, "\n\n after receiving initial information") ; if ( msglvl > 2 ) { InpMtx_writeForHumanEye(mtxA, msgFile) ; } else { InpMtx_writeStats(mtxA, msgFile) ; } } /* ------------------------------------------ set the initial owners IV to be a wrap map ------------------------------------------ */ mapIV = IV_new() ; IV_init(mapIV, neqns, NULL) ; map = IV_entries(mapIV) ; for ( v = 0 ; v < neqns ; v++ ) { map[v] = v % nproc ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n map") ; IV_writeForHumanEye(mapIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------------ split the InpMtx object into pieces ------------------------------------ */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; tag++ ; MARKTIME(t1) ; mtxB = InpMtx_MPI_split(mtxA, mapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : matrix split", t2 - t1) ; fprintf(msgFile, "\n send stats : %d messages with %d bytes" "\n recv stats : %d messages with %d bytes", stats[0], stats[2], stats[1], stats[3]) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n total send stats : %d messages with %d bytes" "\n total recv stats : %d messages with %d bytes", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } InpMtx_free(mtxA) ; mtxA = mtxB ; tag += 2 ; if ( mtxA != NULL ) { InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; fprintf(msgFile, "\n\n after splitting the InpMtx object with the wrap map") ; if ( msglvl > 2 ) { InpMtx_writeForHumanEye(mtxA, msgFile) ; } else { InpMtx_writeStats(mtxA, msgFile) ; } fflush(msgFile) ; } /* --------------------- generate a random map --------------------- */ MARKTIME(t1) ; Drand_setSeed(drand, seed + 1) ; Drand_setUniform(drand, 0.0, (double) neqns) ; for ( v = 0 ; v < neqns ; v++ ) { map[v] = ((int) Drand_value(drand)) % nproc ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : random map set", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n map") ; IV_writeForHumanEye(mapIV, msgFile) ; fflush(msgFile) ; } /* ---------------------------------------- now split the matrix with the random map ---------------------------------------- */ stats[0] = stats[1] = stats[2] = stats[3] = 0 ; tstats[0] = tstats[1] = tstats[2] = tstats[3] = 0 ; MARKTIME(t1) ; mtxB = InpMtx_MPI_split(mtxA, mapIV, stats, msglvl, msgFile, tag, MPI_COMM_WORLD) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : matrix split", t2 - t1) ; fprintf(msgFile, "\n send stats : %d messages with %d bytes" "\n recv stats : %d messages with %d bytes", stats[0], stats[2], stats[1], stats[3]) ; MPI_Reduce((void *) stats, (void *) tstats, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n total send stats : %d messages with %d bytes" "\n total recv stats : %d messages with %d bytes", tstats[0], tstats[2], tstats[1], tstats[3]) ; fflush(msgFile) ; } InpMtx_free(mtxA) ; mtxA = mtxB ; fprintf(msgFile, "\n\n after splitting the InpMtx object with the owners map") ; if ( msglvl > 2 ) { InpMtx_writeForHumanEye(mtxA, msgFile) ; } else { InpMtx_writeStats(mtxA, msgFile) ; } fflush(msgFile) ; /* ----------------------------------------------- compute the checksums of the distributed matrix ----------------------------------------------- */ InpMtx_checksums(mtxA, pchecksums) ; MPI_Reduce((void *) pchecksums, (void *) tchecksums, 3, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD) ; if ( myid == 0 ) { fprintf(msgFile, "\n\n checksums for original matrix : %12.4e %12.4e %12.4e" "\n checksums for distributed matrix : %12.4e %12.4e %12.4e" "\n error in checksum : %12.4e %12.4e %12.4e", schecksums[0], schecksums[1], schecksums[2], tchecksums[0], tchecksums[1], tchecksums[2], tchecksums[0] - schecksums[0], tchecksums[1] - schecksums[1], tchecksums[2] - schecksums[2]) ; } /* ---------------- free the objects ---------------- */ IV_free(mapIV) ; InpMtx_free(mtxA) ; Drand_free(drand) ; MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ "\n nent -- %d" "\n seed -- %d" "\n coordType -- %d" "\n inputMode -- %d" "\n", argv[0], msglvl, argv[2], neqns, nent, seed, coordType, inputMode) ; fflush(msgFile) ; /* ---------------------------------- create the random number generator --------------------MPI/drivers/testSymbFac.c010064400020550007177000000227210655671743200166070ustar00clevecompmath00000400000006/* testSymbFac.c */ #include "../spoolesMPI.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- created -- 98may16, cca --------------------------------------------------- */ { char *buffer, *inETreeFileName, *inGraphFileName ; double t1, t2 ; Drand *drand ; ETree *frontETree ; InpMtx *inpmtx ; int firsttag, ient, ii, jent, J, length, myid, msglvl, nent, nerror, nfront, nproc, nvtx, rc, seed, sizeJ1, sizeJ2, v, vsize ; int stats[4], tstats[4] ; int *frontOwners, *indicesJ1, *indicesJ2, *ivec1, *ivec2, *vadj, *vtxToFront ; IV *frontOwnersIV, *oldToNewIV ; IVL *symbfac1, *symbfac2 ; FILE *msgFile ; Graph *graph ; MPI_Status status ; /* --------------------------------------------------------------- find out the identity of this process and the number of process --------------------------------------------------------------- */ MPI_Init(&argc, &argv) ; MPI_Comm_rank(MPI_COMM_WORLD, &myid) ; MPI_Comm_size(MPI_COMM_WORLD, &nproc) ; fprintf(stdout, "\n process %d of %d, argc = %d", myid, nproc, argc) ; fflush(stdout) ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile inETreeFile seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- name of Graph file" "\n inETreeFile -- name of ETree file" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else { length = strlen(argv[2]) + 1 + 4 ; buffer = CVinit(length, '\0') ; sprintf(buffer, "%s.%d", argv[2], myid) ; if ( (msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } CVfree(buffer) ; } inGraphFileName = argv[3] ; inETreeFileName = argv[4] ; seed = atoi(argv[5]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n inETreeFile -- %s" "\n seed -- %d" "\n", argv[0], msglvl, argv[2], inGraphFileName, inETreeFileName, seed) ; fflush(msgFile) ; /* ---------------------------------- create the random number generator ---------------------------------- */ drand = Drand_new() ; Drand_setSeed(drand, seed) ; /* ------------------------ read in the Graph object ------------------------ */ graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; nvtx = graph->nvtx ; /* ------------------------ read in the ETree object ------------------------ */ frontETree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(frontETree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in frontETree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, frontETree, inETreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(frontETree, msgFile) ; } else { ETree_writeStats(frontETree, msgFile) ; } fflush(msgFile) ; nfront = ETree_nfront(frontETree) ; vtxToFront = ETree_vtxToFront(frontETree) ; /* ----------------------------------------- create an InpMtx object to hold the graph ----------------------------------------- */ inpmtx = InpMtx_new() ; InpMtx_init(inpmtx, INPMTX_BY_ROWS, INPMTX_INDICES_ONLY, 0, 0) ; for ( v = 0 ; v < nvtx ; v++ ) { Graph_adjAndSize(graph, v, &vsize, &vadj) ; InpMtx_inputRow(inpmtx, v, vsize, vadj) ; } InpMtx_sortAndCompress(inpmtx) ; fprintf(msgFile, "\n\n InpMtx made from graph") ; if ( msglvl > 2 ) { InpMtx_writeForHumanEye(inpmtx, msgFile) ; } else { InpMtx_writeStats(inpmtx, msgFile) ; } /* ---------------------------------------------- get the permutation vector from the front tree ---------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; fprintf(msgFile, "\n\n old-to-new permutation vector") ; if ( msglvl > 2 ) { IV_writeForHumanEye(oldToNewIV, msgFile) ; } else { IV_writeStats(oldToNewIV, msgFile) ; } /* -------------------------------------- permute the vertices in the front tree -------------------------------------- */ ETree_permuteVertices(frontETree, oldToNewIV) ; fprintf(msgFile, "\n\n front tree after permutation") ; if ( msglvl > 2 ) { ETree_writeForHumanEye(frontETree, msgFile) ; } else { ETree_writeStats(frontETree, msgFile) ; } /* ------------------------------------------------- permute the rows and columns in the InpMtx object and convert to chevron format ------------------------------------------------- */ InpMtx_permute(inpmtx, IV_entries(oldToNewIV), IV_entries(oldToNewIV)) ; InpMtx_changeCoordType(inpmtx, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(inpmtx, INPMTX_BY_VECTORS) ; fprintf(msgFile, "\n\n InpMtx after permutation") ; if ( msglvl > 2 ) { InpMtx_writeForHumanEye(inpmtx, msgFile) ; } else { InpMtx_writeStats(inpmtx, msgFile) ; } /* ------------------------------------------------------------- compute the symbolic factorization using the entire structure ------------------------------------------------------------- */ symbfac1 = SymbFac_initFromInpMtx(frontETree, inpmtx) ; fprintf(msgFile, "\n\n symbolic factorization from global data") ; if ( msglvl > 2 ) { IVL_writeForHumanEye(symbfac1, msgFile) ; } else { IVL_writeStats(symbfac1, msgFile) ; } /* --------------------- generate a random map --------------------- */ MARKTIME(t1) ; Drand_setSeed(drand, seed + 1) ; Drand_setUniform(drand, 0.0, (double) nproc) ; frontOwnersIV = IV_new() ; IV_init(frontOwnersIV, nfront, NULL) ; frontOwners = IV_entries(frontOwnersIV) ; for ( J = 0 ; J < nfront ; J++ ) { frontOwners[J] = (int) Drand_value(drand) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : random map set", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n frontOwners") ; IV_writeForHumanEye(frontOwnersIV, msgFile) ; fflush(msgFile) ; } /* --------------------------- throw away unowned chevrons --------------------------- */ InpMtx_changeStorageMode(inpmtx, INPMTX_RAW_DATA) ; nent = InpMtx_nent(inpmtx) ; ivec1 = InpMtx_ivec1(inpmtx) ; ivec2 = InpMtx_ivec2(inpmtx) ; for ( ient = jent = 0 ; ient < nent ; ient++ ) { v = ivec1[ient] ; J = vtxToFront[v] ; if ( frontOwners[J] == myid ) { ivec1[jent] = ivec1[ient] ; ivec2[jent] = ivec2[ient] ; jent++ ; } } InpMtx_setNent(inpmtx, jent) ; InpMtx_changeStorageMode(inpmtx, INPMTX_BY_VECTORS) ; fprintf(msgFile, "\n\n InpMtx after dropping unowned entries") ; if ( msglvl > 2 ) { InpMtx_writeForHumanEye(inpmtx, msgFile) ; } else { InpMtx_writeStats(inpmtx, msgFile) ; } /* ------------------------------------------------ compute the symbolic factorization cooperatively ------------------------------------------------ */ firsttag = 47 ; symbfac2 = SymbFac_MPI_initFromInpMtx(frontETree, frontOwnersIV, inpmtx, stats, msglvl, msgFile, firsttag, MPI_COMM_WORLD) ; fprintf(msgFile, "\n\n symbolic factorization from cooperation") ; if ( msglvl > 2 ) { IVL_writeForHumanEye(symbfac2, msgFile) ; } else { IVL_writeStats(symbfac2, msgFile) ; } /* ---------------------------------------- check that the supported part of the second symbolic factorization is correct ---------------------------------------- */ for ( J = 0, nerror = 0 ; J < nfront ; J++ ) { IVL_listAndSize(symbfac2, J, &sizeJ2, &indicesJ2) ; if ( sizeJ2 > 0 ) { IVL_listAndSize(symbfac1, J, &sizeJ1, &indicesJ1) ; if ( sizeJ1 != sizeJ2 ) { fprintf(msgFile, "\n error, J = %d, sizeJ1 = %d, sizeJ2 = %d", J, sizeJ1, sizeJ2) ; nerror++ ; } else { for ( ii = 0 ; ii < sizeJ1 ; ii++ ) { if ( indicesJ1[ii] != indicesJ2[ii] ) { fprintf(msgFile, "\n error, J = %d", J) ; fprintf(msgFile, "\n indicesJ1") ; IVfprintf(msgFile, sizeJ1, indicesJ1) ; fprintf(msgFile, "\n indicesJ2") ; IVfprintf(msgFile, sizeJ1, indicesJ2) ; nerror++ ; break ; } } } } } fprintf(msgFile, "\n\n %d errors in symbolic factorization", nerror) ; /* ---------------- free the objects ---------------- */ IV_free(frontOwnersIV) ; IV_free(oldToNewIV) ; InpMtx_free(inpmtx) ; ETree_free(frontETree) ; Drand_free(drand) ; MPI_Finalize() ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ ; if ( rc != 1 ) { fprintf(msgFile, "\n retuMPI/drivers/haggar.mtx.0.input010064400020550007177000000413700665164051600174710ustar00clevecompmath00000400000006252 252 487 132 132 1.029802e+10 -5.149009e+08 132 136 1.192093e-07 -5.960464e-09 132 137 -1.490116e-07 7.450581e-09 132 138 -5.908699e+08 2.954350e+07 132 142 -5.960464e-08 2.980232e-09 132 143 -5.275624e+08 2.637812e+07 132 162 -1.287252e+09 6.436262e+07 132 166 -1.582687e+08 7.913437e+06 132 167 1.318906e+08 -6.594531e+06 132 168 -1.983635e+09 9.918174e+07 132 172 -6.330749e+08 3.165375e+07 132 173 1.490116e-08 -7.450581e-10 132 174 -1.287252e+09 6.436262e+07 132 178 -1.582687e+08 7.913437e+06 132 179 -1.318906e+08 6.594531e+06 133 133 1.796625e+10 -8.983125e+08 133 134 2.384186e-07 -1.192093e-08 133 139 -4.424986e+09 2.212493e+08 133 140 2.384186e-07 -1.192093e-08 133 163 -2.245781e+09 1.122891e+08 133 164 -1.725352e+09 8.626761e+07 133 169 -6.657689e+07 3.328845e+06 133 170 2.980232e-08 -1.490116e-09 133 175 -2.245781e+09 1.122891e+08 133 176 1.725352e+09 -8.626761e+07 134 134 2.134027e+10 -1.067014e+09 134 139 5.960464e-08 -2.980232e-09 134 140 2.169693e+09 -1.084847e+08 134 163 -1.725352e+09 8.626761e+07 134 164 -2.667534e+09 1.333767e+08 134 169 -5.960464e-08 2.980232e-09 134 170 -7.504762e+09 3.752381e+08 134 175 1.725352e+09 -8.626761e+07 134 176 -2.667534e+09 1.333767e+08 135 135 2.900850e+06 -1.450425e+05 135 141 -1.664422e+05 8.322112e+03 135 165 -3.626063e+05 1.813032e+04 135 171 -5.587704e+05 2.793852e+04 135 177 -3.626063e+05 1.813032e+04 136 136 3.561542e+08 -1.780771e+07 136 137 -1.746230e-10 8.731149e-12 136 138 -8.940697e-08 4.470348e-09 136 142 8.837909e+07 -4.418955e+06 136 143 -3.637979e-11 1.818989e-12 136 162 1.582687e+08 -7.913437e+06 136 166 2.142603e+07 -1.071302e+06 136 167 3.594484e+05 -1.797242e+04 136 168 6.330749e+08 -3.165375e+07 136 172 8.636358e+07 -4.318179e+06 136 173 2.910383e-11 -1.455192e-12 136 174 1.582687e+08 -7.913437e+06 136 178 2.142603e+07 -1.071302e+06 136 179 -3.594484e+05 1.797242e+04 137 137 3.554513e+08 -1.777256e+07 137 138 5.275624e+08 -2.637812e+07 137 142 -2.182787e-11 1.091394e-12 137 143 8.700520e+07 -4.350260e+06 137 162 -1.318906e+08 6.594531e+06 137 166 3.594484e+05 -1.797242e+04 137 167 2.151390e+07 -1.075695e+06 137 168 -2.980232e-08 1.490116e-09 137 172 -1.455192e-11 7.275958e-13 137 173 8.791320e+07 -4.395660e+06 137 174 1.318906e+08 -6.594531e+06 137 178 -3.594484e+05 1.797242e+04 137 179 2.151390e+07 -1.075695e+06 138 138 5.149009e+09 -2.574505e+08 138 142 5.960464e-08 -2.980232e-09 138 143 5.275624e+08 -2.637812e+07 138 168 -1.287252e+09 6.436262e+07 138 172 -1.582687e+08 7.913437e+06 138 173 1.318906e+08 -6.594531e+06 138 174 -9.918174e+08 4.959087e+07 138 178 -3.165375e+08 1.582687e+07 138 179 1.318906e+08 -6.594531e+06 139 139 8.983125e+09 -4.491563e+08 139 140 -2.384186e-07 1.192093e-08 139 169 -2.245781e+09 1.122891e+08 139 170 -1.725352e+09 8.626761e+07 139 175 -3.328845e+07 1.664422e+06 139 176 1.738727e+08 -8.693635e+06 140 140 1.067014e+10 -5.335068e+08 140 169 -1.725352e+09 8.626761e+07 140 170 -2.667534e+09 1.333767e+08 140 175 -1.738727e+08 8.693635e+06 140 176 -3.752381e+09 1.876190e+08 141 141 1.450425e+06 -7.252126e+04 141 171 -3.626063e+05 1.813032e+04 141 177 -2.793852e+05 1.396926e+04 142 142 1.780771e+08 -8.903855e+06 142 143 0.000000e+00 -0.000000e+00 142 168 1.582687e+08 -7.913437e+06 142 172 2.142603e+07 -1.071302e+06 142 173 3.594484e+05 -1.797242e+04 142 174 3.165375e+08 -1.582687e+07 142 178 4.318179e+07 -2.159090e+06 142 179 3.622348e+04 -1.811174e+03 143 143 1.777256e+08 -8.886282e+06 143 168 -1.318906e+08 6.594531e+06 143 172 3.594484e+05 -1.797242e+04 143 173 2.151390e+07 -1.075695e+06 143 174 1.318906e+08 -6.594531e+06 143 178 -3.622348e+04 1.811174e+03 143 179 4.395660e+07 -2.197830e+06 168 168 1.029802e+10 -5.149009e+08 168 172 1.192093e-07 -5.960464e-09 168 173 -8.940697e-08 4.470348e-09 168 174 -5.908699e+08 2.954350e+07 168 178 -5.960464e-08 2.980232e-09 168 179 -5.275624e+08 2.637812e+07 168 198 -1.287252e+09 6.436262e+07 168 202 -1.582687e+08 7.913437e+06 168 203 1.318906e+08 -6.594531e+06 168 204 -1.983635e+09 9.918174e+07 168 208 -6.330749e+08 3.165375e+07 168 209 -2.980232e-08 1.490116e-09 168 210 -1.287252e+09 6.436262e+07 168 214 -1.582687e+08 7.913437e+06 168 215 -1.318906e+08 6.594531e+06 169 169 1.796625e+10 -8.983125e+08 169 170 2.384186e-07 -1.192093e-08 169 175 -4.424986e+09 2.212493e+08 169 176 2.980232e-08 -1.490116e-09 169 199 -2.245781e+09 1.122891e+08 169 200 -1.725352e+09 8.626761e+07 169 205 -6.657689e+07 3.328845e+06 169 206 2.682209e-07 -1.341105e-08 169 211 -2.245781e+09 1.122891e+08 169 212 1.725352e+09 -8.626761e+07 170 170 2.134027e+10 -1.067014e+09 170 175 -5.960464e-08 2.980232e-09 170 176 2.169693e+09 -1.084847e+08 170 199 -1.725352e+09 8.626761e+07 170 200 -2.667534e+09 1.333767e+08 170 205 1.192093e-07 -5.960464e-09 170 206 -7.504762e+09 3.752381e+08 170 211 1.725352e+09 -8.626761e+07 170 212 -2.667534e+09 1.333767e+08 171 171 2.900850e+06 -1.450425e+05 171 177 -1.664422e+05 8.322112e+03 171 201 -3.626063e+05 1.813032e+04 171 207 -5.587704e+05 2.793852e+04 171 213 -3.626063e+05 1.813032e+04 172 172 3.561542e+08 -1.780771e+07 172 173 0.000000e+00 -0.000000e+00 172 174 -5.960464e-08 2.980232e-09 172 178 8.837909e+07 -4.418955e+06 172 179 -1.455192e-11 7.275958e-13 172 198 1.582687e+08 -7.913437e+06 172 202 2.142603e+07 -1.071302e+06 172 203 3.594484e+05 -1.797242e+04 172 204 6.330749e+08 -3.165375e+07 172 208 8.636358e+07 -4.318179e+06 172 209 -2.182787e-11 1.091394e-12 172 210 1.582687e+08 -7.913437e+06 172 214 2.142603e+07 -1.071302e+06 172 215 -3.594484e+05 1.797242e+04 173 173 3.554513e+08 -1.777256e+07 173 174 5.275624e+08 -2.637812e+07 173 178 5.093170e-11 -2.546585e-12 173 179 8.700520e+07 -4.350260e+06 173 198 -1.318906e+08 6.594531e+06 173 202 3.594484e+05 -1.797242e+04 173 203 2.151390e+07 -1.075695e+06 173 204 -1.490116e-08 7.450581e-10 173 208 -2.910383e-11 1.455192e-12 173 209 8.791320e+07 -4.395660e+06 173 210 1.318906e+08 -6.594531e+06 173 214 -3.594484e+05 1.797242e+04 173 215 2.151390e+07 -1.075695e+06 174 174 5.149009e+09 -2.574505e+08 174 178 5.960464e-08 -2.980232e-09 174 179 5.275624e+08 -2.637812e+07 174 204 -1.287252e+09 6.436262e+07 174 208 -1.582687e+08 7.913437e+06 174 209 1.318906e+08 -6.594531e+06 174 210 -9.918174e+08 4.959087e+07 174 214 -3.165375e+08 1.582687e+07 174 215 1.318906e+08 -6.594531e+06 175 175 8.983125e+09 -4.491563e+08 175 176 -2.384186e-07 1.192093e-08 175 205 -2.245781e+09 1.122891e+08 175 206 -1.725352e+09 8.626761e+07 175 211 -3.328845e+07 1.664422e+06 175 212 1.738727e+08 -8.693635e+06 176 176 1.067014e+10 -5.335068e+08 176 205 -1.725352e+09 8.626761e+07 176 206 -2.667534e+09 1.333767e+08 176 211 -1.738727e+08 8.693635e+06 176 212 -3.752381e+09 1.876190e+08 177 177 1.450425e+06 -7.252126e+04 177 207 -3.626063e+05 1.813032e+04 177 213 -2.793852e+05 1.396926e+04 178 178 1.780771e+08 -8.903855e+06 178 179 -5.820766e-11 2.910383e-12 178 204 1.582687e+08 -7.913437e+06 178 208 2.142603e+07 -1.071302e+06 178 209 3.594484e+05 -1.797242e+04 178 210 3.165375e+08 -1.582687e+07 178 214 4.318179e+07 -2.159090e+06 178 215 3.622348e+04 -1.811174e+03 179 179 1.777256e+08 -8.886282e+06 179 204 -1.318906e+08 6.594531e+06 179 208 3.594484e+05 -1.797242e+04 179 209 2.151390e+07 -1.075695e+06 179 210 1.318906e+08 -6.594531e+06 179 214 -3.622348e+04 1.811174e+03 179 215 4.395660e+07 -2.197830e+06 204 204 1.029802e+10 -5.149009e+08 204 208 1.192093e-07 -5.960464e-09 204 209 0.000000e+00 -0.000000e+00 204 210 -5.908699e+08 2.954350e+07 204 214 -5.960464e-08 2.980232e-09 204 215 -5.275624e+08 2.637812e+07 204 234 -1.287252e+09 6.436262e+07 204 238 -1.582687e+08 7.913437e+06 204 239 1.318906e+08 -6.594531e+06 204 240 -1.983635e+09 9.918174e+07 204 244 -6.330749e+08 3.165375e+07 204 245 0.000000e+00 -0.000000e+00 204 246 -1.287252e+09 6.436262e+07 204 250 -1.582687e+08 7.913437e+06 204 251 -1.318906e+08 6.594531e+06 205 205 1.796625e+10 -8.983125e+08 205 206 0.000000e+00 -0.000000e+00 205 211 -4.424986e+09 2.212493e+08 205 212 2.086163e-07 -1.043081e-08 205 235 -2.245781e+09 1.122891e+08 205 236 -1.725352e+09 8.626761e+07 205 241 -6.657689e+07 3.328845e+06 205 242 -2.086163e-07 1.043081e-08 205 247 -2.245781e+09 1.122891e+08 205 248 1.725352e+09 -8.626761e+07 206 206 2.134027e+10 -1.067014e+09 206 211 0.000000e+00 -0.000000e+00 206 212 2.169693e+09 -1.084847e+08 206 235 -1.725352e+09 8.626761e+07 206 236 -2.667534e+09 1.333767e+08 206 241 -4.768372e-07 2.384186e-08 206 242 -7.504762e+09 3.752381e+08 206 247 1.725352e+09 -8.626761e+07 206 248 -2.667534e+09 1.333767e+08 207 207 2.900850e+06 -1.450425e+05 207 213 -1.664422e+05 8.322112e+03 207 237 -3.626063e+05 1.813032e+04 207 243 -5.587704e+05 2.793852e+04 207 249 -3.626063e+05 1.813032e+04 208 208 3.561542e+08 -1.780771e+07 208 209 5.820766e-11 -2.910383e-12 208 210 -5.960464e-08 2.980232e-09 208 214 8.837909e+07 -4.418955e+06 208 215 -7.275958e-12 3.637979e-13 208 234 1.582687e+08 -7.913437e+06 208 238 2.142603e+07 -1.071302e+06 208 239 3.594484e+05 -1.797242e+04 208 240 6.330749e+08 -3.165375e+07 208 244 8.636358e+07 -4.318179e+06 208 245 7.275958e-12 -3.637979e-13 208 246 1.582687e+08 -7.913437e+06 208 250 2.142603e+07 -1.071302e+06 208 251 -3.594484e+05 1.797242e+04 209 209 3.554513e+08 -1.777256e+07 209 210 5.275624e+08 -2.637812e+07 209 214 3.637979e-11 -1.818989e-12 209 215 8.700520e+07 -4.350260e+06 209 234 -1.318906e+08 6.594531e+06 209 238 3.594484e+05 -1.797242e+04 209 239 2.151390e+07 -1.075695e+06 209 240 -4.470348e-08 2.235174e-09 209 244 6.548362e-11 -3.274181e-12 209 245 8.791320e+07 -4.395660e+06 209 246 1.318906e+08 -6.594531e+06 209 250 -3.594484e+05 1.797242e+04 209 251 2.151390e+07 -1.075695e+06 210 210 5.149009e+09 -2.574505e+08 210 214 5.960464e-08 -2.980232e-09 210 215 5.275624e+08 -2.637812e+07 210 240 -1.287252e+09 6.436262e+07 210 244 -1.582687e+08 7.913437e+06 210 245 1.318906e+08 -6.594531e+06 210 246 -9.918174e+08 4.959087e+07 210 250 -3.165375e+08 1.582687e+07 210 251 1.318906e+08 -6.594531e+06 211 211 8.983125e+09 -4.491563e+08 211 212 -2.384186e-07 1.192093e-08 211 241 -2.245781e+09 1.122891e+08 211 242 -1.725352e+09 8.626761e+07 211 247 -3.328845e+07 1.664422e+06 211 248 1.738727e+08 -8.693635e+06 212 212 1.067014e+10 -5.335068e+08 212 241 -1.725352e+09 8.626761e+07 212 242 -2.667534e+09 1.333767e+08 212 247 -1.738727e+08 8.693635e+06 212 248 -3.752381e+09 1.876190e+08 213 213 1.450425e+06 -7.252126e+04 213 243 -3.626063e+05 1.813032e+04 213 249 -2.793852e+05 1.396926e+04 214 214 1.780771e+08 -8.903855e+06 214 215 -5.820766e-11 2.910383e-12 214 240 1.582687e+08 -7.913437e+06 214 244 2.142603e+07 -1.071302e+06 214 245 3.594484e+05 -1.797242e+04 214 246 3.165375e+08 -1.582687e+07 214 250 4.318179e+07 -2.159090e+06 214 251 3.622348e+04 -1.811174e+03 215 215 1.777256e+08 -8.886282e+06 215 240 -1.318906e+08 6.594531e+06 215 244 3.594484e+05 -1.797242e+04 215 245 2.151390e+07 -1.075695e+06 215 246 1.318906e+08 -6.594531e+06 215 250 -3.622348e+04 1.811174e+03 215 251 4.395660e+07 -2.197830e+06 240 240 5.149009e+09 -2.574505e+08 240 244 6.330749e+08 -3.165375e+07 240 245 -1.192093e-07 5.960464e-09 240 246 -2.954350e+08 1.477175e+07 240 250 1.582687e+08 -7.913437e+06 240 251 -2.637812e+08 1.318906e+07 241 241 8.983125e+09 -4.491563e+08 241 242 4.768372e-07 -2.384186e-08 241 247 -2.212493e+09 1.106246e+08 241 248 -1.738727e+08 8.693635e+06 242 242 1.067014e+10 -5.335068e+08 242 247 1.738727e+08 -8.693635e+06 242 248 1.084847e+09 -5.424234e+07 243 243 1.450425e+06 -7.252126e+04 243 249 -8.322112e+04 4.161056e+03 244 244 1.780771e+08 -8.903855e+06 244 245 -5.820766e-11 2.910383e-12 244 246 1.582687e+08 -7.913437e+06 244 250 4.418955e+07 -2.209477e+06 244 251 -3.622348e+04 1.811174e+03 245 245 1.777256e+08 -8.886282e+06 245 246 2.637812e+08 -1.318906e+07 245 250 3.622348e+04 -1.811174e+03 245 251 4.350260e+07 -2.175130e+06 246 246 2.574505e+09 -1.287252e+08 246 250 3.165375e+08 -1.582687e+07 246 251 2.637812e+08 -1.318906e+07 247 247 4.491563e+09 -2.245781e+08 247 248 -1.725352e+09 8.626761e+07 248 248 5.335068e+09 -2.667534e+08 249 249 7.252126e+05 -3.626063e+04 250 250 8.903855e+07 -4.451927e+06 250 251 3.594484e+05 -1.797242e+04 251 251 8.886282e+07 -4.443141e+06 132 132 -1.301143e+10 0.000000e+00 132 138 -3.252857e+09 0.000000e+00 132 162 -8.132143e+08 0.000000e+00 132 168 -3.252857e+09 0.000000e+00 132 174 -8.132143e+08 0.000000e+00 133 133 -1.301143e+10 0.000000e+00 133 134 -1.624548e-23 0.000000e+00 133 139 -3.252857e+09 0.000000e+00 133 163 -8.132143e+08 0.000000e+00 133 169 -3.252857e+09 0.000000e+00 133 170 -6.306821e-24 0.000000e+00 133 175 -8.132143e+08 0.000000e+00 134 134 -1.301143e+10 0.000000e+00 134 140 -3.252857e+09 0.000000e+00 134 164 -8.132143e+08 0.000000e+00 134 169 6.306821e-24 -0.000000e+00 134 170 -3.252857e+09 0.000000e+00 134 176 -8.132143e+08 0.000000e+00 136 136 -2.710714e+06 0.000000e+00 136 142 -6.776786e+05 0.000000e+00 136 166 -1.694196e+05 0.000000e+00 136 172 -6.776786e+05 0.000000e+00 136 178 -1.694196e+05 0.000000e+00 137 137 -2.710714e+06 0.000000e+00 137 143 -6.776786e+05 0.000000e+00 137 167 -1.694196e+05 0.000000e+00 137 173 -6.776786e+05 0.000000e+00 137 179 -1.694196e+05 0.000000e+00 138 138 -6.505714e+09 0.000000e+00 138 168 -8.132143e+08 0.000000e+00 138 174 -1.626429e+09 0.000000e+00 139 139 -6.505714e+09 0.000000e+00 139 140 -8.122739e-24 0.000000e+00 139 169 -8.132143e+08 0.000000e+00 139 175 -1.626429e+09 0.000000e+00 140 140 -6.505714e+09 0.000000e+00 140 170 -8.132143e+08 0.000000e+00 140 176 -1.626429e+09 0.000000e+00 142 142 -1.355357e+06 0.000000e+00 142 172 -1.694196e+05 0.000000e+00 142 178 -3.388393e+05 0.000000e+00 143 143 -1.355357e+06 0.000000e+00 143 173 -1.694196e+05 0.000000e+00 143 179 -3.388393e+05 0.000000e+00 168 168 -1.301143e+10 0.000000e+00 168 174 -3.252857e+09 0.000000e+00 168 198 -8.132143e+08 0.000000e+00 168 204 -3.252857e+09 0.000000e+00 168 210 -8.132143e+08 0.000000e+00 169 169 -1.301143e+10 0.000000e+00 169 170 -3.228433e-23 0.000000e+00 169 175 -3.252857e+09 0.000000e+00 169 199 -8.132143e+08 0.000000e+00 169 205 -3.252857e+09 0.000000e+00 169 211 -8.132143e+08 0.000000e+00 170 170 -1.301143e+10 0.000000e+00 170 176 -3.252857e+09 0.000000e+00 170 200 -8.132143e+08 0.000000e+00 170 206 -3.252857e+09 0.000000e+00 170 212 -8.132143e+08 0.000000e+00 172 172 -2.710714e+06 0.000000e+00 172 178 -6.776786e+05 0.000000e+00 172 202 -1.694196e+05 0.000000e+00 172 208 -6.776786e+05 0.000000e+00 172 214 -1.694196e+05 0.000000e+00 173 173 -2.710714e+06 0.000000e+00 173 179 -6.776786e+05 0.000000e+00 173 203 -1.694196e+05 0.000000e+00 173 209 -6.776786e+05 0.000000e+00 173 215 -1.694196e+05 0.000000e+00 174 174 -6.505714e+09 0.000000e+00 174 204 -8.132143e+08 0.000000e+00 174 210 -1.626429e+09 0.000000e+00 175 175 -6.505714e+09 0.000000e+00 175 176 -1.592926e-23 0.000000e+00 175 205 -8.132143e+08 0.000000e+00 175 211 -1.626429e+09 0.000000e+00 176 176 -6.505714e+09 0.000000e+00 176 206 -8.132143e+08 0.000000e+00 176 212 -1.626429e+09 0.000000e+00 178 178 -1.355357e+06 0.000000e+00 178 208 -1.694196e+05 0.000000e+00 178 214 -3.388393e+05 0.000000e+00 179 179 -1.355357e+06 0.000000e+00 179 209 -1.694196e+05 0.000000e+00 179 215 -3.388393e+05 0.000000e+00 204 204 -1.301143e+10 0.000000e+00 204 210 -3.252857e+09 0.000000e+00 204 234 -8.132143e+08 0.000000e+00 204 240 -3.252857e+09 0.000000e+00 204 246 -8.132143e+08 0.000000e+00 205 205 -1.301143e+10 0.000000e+00 205 211 -3.252857e+09 0.000000e+00 205 235 -8.132143e+08 0.000000e+00 205 241 -3.252857e+09 0.000000e+00 205 247 -8.132143e+08 0.000000e+00 206 206 -1.301143e+10 0.000000e+00 206 212 -3.252857e+09 0.000000e+00 206 236 -8.132143e+08 0.000000e+00 206 242 -3.252857e+09 0.000000e+00 206 248 -8.132143e+08 0.000000e+00 208 208 -2.710714e+06 0.000000e+00 208 214 -6.776786e+05 0.000000e+00 208 238 -1.694196e+05 0.000000e+00 208 244 -6.776786e+05 0.000000e+00 208 250 -1.694196e+05 0.000000e+00 209 209 -2.710714e+06 0.000000e+00 209 215 -6.776786e+05 0.000000e+00 209 239 -1.694196e+05 0.000000e+00 209 245 -6.776786e+05 0.000000e+00 209 251 -1.694196e+05 0.000000e+00 210 210 -6.505714e+09 0.000000e+00 210 240 -8.132143e+08 0.000000e+00 210 246 -1.626429e+09 0.000000e+00 211 211 -6.505714e+09 0.000000e+00 211 241 -8.132143e+08 0.000000e+00 211 247 -1.626429e+09 0.000000e+00 212 212 -6.505714e+09 0.000000e+00 212 242 -8.132143e+08 0.000000e+00 212 248 -1.626429e+09 0.000000e+00 214 214 -1.355357e+06 0.000000e+00 214 244 -1.694196e+05 0.000000e+00 214 250 -3.388393e+05 0.000000e+00 215 215 -1.355357e+06 0.000000e+00 215 245 -1.694196e+05 0.000000e+00 215 251 -3.388393e+05 0.000000e+00 240 240 -6.505714e+09 0.000000e+00 240 246 -1.626429e+09 0.000000e+00 241 241 -6.505714e+09 0.000000e+00 241 247 -1.626429e+09 0.000000e+00 242 242 -6.505714e+09 0.000000e+00 242 248 -1.626429e+09 0.000000e+00 244 244 -1.355357e+06 0.000000e+00 244 250 -3.388393e+05 0.000000e+00 245 245 -1.355357e+06 0.000000e+00 245 251 -3.388393e+05 0.000000e+00 246 246 -3.252857e+09 0.000000e+00 247 247 -3.252857e+09 0.000000e+00 248 248 -3.252857e+09 0.000000e+00 250 250 -6.776786e+05 0.000000e+00 251 251 -6.776786e+05 0.000000e+00 06 178 209 3.594484e+05 -1.797242e+04 178 210 3.165375e+08 -1.582687e+07 178 214 4.318179e+07 -2.159090e+06 178 215 3.622348e+04 -1.811174e+03 179 179 1.777256e+08 -8.886282e+06 179 204 -1.318906e+08 6.594531e+06 179 208 3.594484e+05 -1.797242e+04 179 209 2.151390MPI/drivers/haggar.mtx.1.input010064400020550007177000000502410665164052300174650ustar00clevecompmath00000400000006252 252 573 162 162 1.029802e+10 -5.149009e+08 162 166 2.384186e-07 -1.192093e-08 162 167 -8.940697e-08 4.470348e-09 162 168 -5.908699e+08 2.954350e+07 162 172 2.980232e-08 -1.490116e-09 162 173 -5.275624e+08 2.637812e+07 162 192 -1.287252e+09 6.436262e+07 162 196 -1.582687e+08 7.913437e+06 162 197 1.318906e+08 -6.594531e+06 162 198 -1.983635e+09 9.918174e+07 162 202 -6.330749e+08 3.165375e+07 162 203 -4.470348e-08 2.235174e-09 162 204 -1.287252e+09 6.436262e+07 162 208 -1.582687e+08 7.913437e+06 162 209 -1.318906e+08 6.594531e+06 163 163 1.796625e+10 -8.983125e+08 163 164 4.768372e-07 -2.384186e-08 163 169 -4.424986e+09 2.212493e+08 163 170 -1.788139e-07 8.940697e-09 163 193 -2.245781e+09 1.122891e+08 163 194 -1.725352e+09 8.626761e+07 163 199 -6.657689e+07 3.328845e+06 163 200 2.384186e-07 -1.192093e-08 163 205 -2.245781e+09 1.122891e+08 163 206 1.725352e+09 -8.626761e+07 164 164 2.134027e+10 -1.067014e+09 164 169 -5.960464e-08 2.980232e-09 164 170 2.169693e+09 -1.084847e+08 164 193 -1.725352e+09 8.626761e+07 164 194 -2.667534e+09 1.333767e+08 164 199 -2.980232e-08 1.490116e-09 164 200 -7.504762e+09 3.752381e+08 164 205 1.725352e+09 -8.626761e+07 164 206 -2.667534e+09 1.333767e+08 165 165 2.900850e+06 -1.450425e+05 165 171 -1.664422e+05 8.322112e+03 165 195 -3.626063e+05 1.813032e+04 165 201 -5.587704e+05 2.793852e+04 165 207 -3.626063e+05 1.813032e+04 166 166 3.561542e+08 -1.780771e+07 166 167 1.746230e-10 -8.731149e-12 166 168 -5.960464e-08 2.980232e-09 166 172 8.837909e+07 -4.418955e+06 166 173 2.910383e-11 -1.455192e-12 166 192 1.582687e+08 -7.913437e+06 166 196 2.142603e+07 -1.071302e+06 166 197 3.594484e+05 -1.797242e+04 166 198 6.330749e+08 -3.165375e+07 166 202 8.636358e+07 -4.318179e+06 166 203 5.820766e-11 -2.910383e-12 166 204 1.582687e+08 -7.913437e+06 166 208 2.142603e+07 -1.071302e+06 166 209 -3.594484e+05 1.797242e+04 167 167 3.554513e+08 -1.777256e+07 167 168 5.275624e+08 -2.637812e+07 167 172 8.731149e-11 -4.365575e-12 167 173 8.700520e+07 -4.350260e+06 167 192 -1.318906e+08 6.594531e+06 167 196 3.594484e+05 -1.797242e+04 167 197 2.151390e+07 -1.075695e+06 167 198 -1.490116e-08 7.450581e-10 167 202 0.000000e+00 -0.000000e+00 167 203 8.791320e+07 -4.395660e+06 167 204 1.318906e+08 -6.594531e+06 167 208 -3.594484e+05 1.797242e+04 167 209 2.151390e+07 -1.075695e+06 180 180 5.149009e+09 -2.574505e+08 180 184 5.960464e-08 -2.980232e-09 180 185 -5.275624e+08 2.637812e+07 180 186 -5.908699e+08 2.954350e+07 180 190 0.000000e+00 -0.000000e+00 180 191 -5.275624e+08 2.637812e+07 180 216 -9.918174e+08 4.959087e+07 180 220 -3.165375e+08 1.582687e+07 180 221 -1.318906e+08 6.594531e+06 180 222 -1.287252e+09 6.436262e+07 180 226 -1.582687e+08 7.913437e+06 180 227 -1.318906e+08 6.594531e+06 181 181 8.983125e+09 -4.491563e+08 181 182 -2.384186e-07 1.192093e-08 181 187 -4.424986e+09 2.212493e+08 181 188 2.980232e-08 -1.490116e-09 181 217 -3.328845e+07 1.664422e+06 181 218 -1.738727e+08 8.693635e+06 181 223 -2.245781e+09 1.122891e+08 181 224 1.725352e+09 -8.626761e+07 182 182 1.067014e+10 -5.335068e+08 182 187 5.960464e-08 -2.980232e-09 182 188 2.169693e+09 -1.084847e+08 182 217 1.738727e+08 -8.693635e+06 182 218 -3.752381e+09 1.876190e+08 182 223 1.725352e+09 -8.626761e+07 182 224 -2.667534e+09 1.333767e+08 183 183 1.450425e+06 -7.252126e+04 183 189 -1.664422e+05 8.322112e+03 183 219 -2.793852e+05 1.396926e+04 183 225 -3.626063e+05 1.813032e+04 184 184 1.780771e+08 -8.903855e+06 184 185 0.000000e+00 -0.000000e+00 184 186 0.000000e+00 -0.000000e+00 184 190 8.837909e+07 -4.418955e+06 184 191 7.275958e-12 -3.637979e-13 184 216 3.165375e+08 -1.582687e+07 184 220 4.318179e+07 -2.159090e+06 184 221 -3.622348e+04 1.811174e+03 184 222 1.582687e+08 -7.913437e+06 184 226 2.142603e+07 -1.071302e+06 184 227 -3.594484e+05 1.797242e+04 185 185 1.777256e+08 -8.886282e+06 185 186 5.275624e+08 -2.637812e+07 185 190 1.455192e-11 -7.275958e-13 185 191 8.700520e+07 -4.350260e+06 185 216 -1.318906e+08 6.594531e+06 185 220 3.622348e+04 -1.811174e+03 185 221 4.395660e+07 -2.197830e+06 185 222 1.318906e+08 -6.594531e+06 185 226 -3.594484e+05 1.797242e+04 185 227 2.151390e+07 -1.075695e+06 186 186 1.029802e+10 -5.149009e+08 186 190 1.788139e-07 -8.940697e-09 186 191 -2.980232e-08 1.490116e-09 186 192 -5.908699e+08 2.954350e+07 186 196 -5.960464e-08 2.980232e-09 186 197 -5.275624e+08 2.637812e+07 186 216 -1.287252e+09 6.436262e+07 186 220 -1.582687e+08 7.913437e+06 186 221 1.318906e+08 -6.594531e+06 186 222 -1.983635e+09 9.918174e+07 186 226 -6.330749e+08 3.165375e+07 186 227 0.000000e+00 -0.000000e+00 186 228 -1.287252e+09 6.436262e+07 186 232 -1.582687e+08 7.913437e+06 186 233 -1.318906e+08 6.594531e+06 187 187 1.796625e+10 -8.983125e+08 187 188 -2.384186e-07 1.192093e-08 187 193 -4.424986e+09 2.212493e+08 187 194 1.788139e-07 -8.940697e-09 187 217 -2.245781e+09 1.122891e+08 187 218 -1.725352e+09 8.626761e+07 187 223 -6.657689e+07 3.328845e+06 187 224 -2.682209e-07 1.341105e-08 187 229 -2.245781e+09 1.122891e+08 187 230 1.725352e+09 -8.626761e+07 188 188 2.134027e+10 -1.067014e+09 188 193 1.192093e-07 -5.960464e-09 188 194 2.169693e+09 -1.084847e+08 188 217 -1.725352e+09 8.626761e+07 188 218 -2.667534e+09 1.333767e+08 188 223 -3.874302e-07 1.937151e-08 188 224 -7.504762e+09 3.752381e+08 188 229 1.725352e+09 -8.626761e+07 188 230 -2.667534e+09 1.333767e+08 189 189 2.900850e+06 -1.450425e+05 189 195 -1.664422e+05 8.322112e+03 189 219 -3.626063e+05 1.813032e+04 189 225 -5.587704e+05 2.793852e+04 189 231 -3.626063e+05 1.813032e+04 190 190 3.561542e+08 -1.780771e+07 190 191 0.000000e+00 -0.000000e+00 190 192 -2.980232e-08 1.490116e-09 190 196 8.837909e+07 -4.418955e+06 190 197 -5.093170e-11 2.546585e-12 190 216 1.582687e+08 -7.913437e+06 190 220 2.142603e+07 -1.071302e+06 190 221 3.594484e+05 -1.797242e+04 190 222 6.330749e+08 -3.165375e+07 190 226 8.636358e+07 -4.318179e+06 190 227 7.275958e-12 -3.637979e-13 190 228 1.582687e+08 -7.913437e+06 190 232 2.142603e+07 -1.071302e+06 190 233 -3.594484e+05 1.797242e+04 191 191 3.554513e+08 -1.777256e+07 191 192 5.275624e+08 -2.637812e+07 191 196 -2.910383e-11 1.455192e-12 191 197 8.700520e+07 -4.350260e+06 191 216 -1.318906e+08 6.594531e+06 191 220 3.594484e+05 -1.797242e+04 191 221 2.151390e+07 -1.075695e+06 191 222 -4.470348e-08 2.235174e-09 191 226 5.820766e-11 -2.910383e-12 191 227 8.791320e+07 -4.395660e+06 191 228 1.318906e+08 -6.594531e+06 191 232 -3.594484e+05 1.797242e+04 191 233 2.151390e+07 -1.075695e+06 192 192 1.029802e+10 -5.149009e+08 192 196 2.384186e-07 -1.192093e-08 192 197 -2.980232e-08 1.490116e-09 192 198 -5.908699e+08 2.954350e+07 192 202 -1.192093e-07 5.960464e-09 192 203 -5.275624e+08 2.637812e+07 192 222 -1.287252e+09 6.436262e+07 192 226 -1.582687e+08 7.913437e+06 192 227 1.318906e+08 -6.594531e+06 192 228 -1.983635e+09 9.918174e+07 192 232 -6.330749e+08 3.165375e+07 192 233 0.000000e+00 -0.000000e+00 192 234 -1.287252e+09 6.436262e+07 192 238 -1.582687e+08 7.913437e+06 192 239 -1.318906e+08 6.594531e+06 193 193 1.796625e+10 -8.983125e+08 193 194 -7.152557e-07 3.576279e-08 193 199 -4.424986e+09 2.212493e+08 193 200 4.172325e-07 -2.086163e-08 193 223 -2.245781e+09 1.122891e+08 193 224 -1.725352e+09 8.626761e+07 193 229 -6.657689e+07 3.328845e+06 193 230 -2.384186e-07 1.192093e-08 193 235 -2.245781e+09 1.122891e+08 193 236 1.725352e+09 -8.626761e+07 194 194 2.134027e+10 -1.067014e+09 194 199 5.364418e-07 -2.682209e-08 194 200 2.169693e+09 -1.084847e+08 194 223 -1.725352e+09 8.626761e+07 194 224 -2.667534e+09 1.333767e+08 194 229 -5.960464e-07 2.980232e-08 194 230 -7.504762e+09 3.752381e+08 194 235 1.725352e+09 -8.626761e+07 194 236 -2.667534e+09 1.333767e+08 195 195 2.900850e+06 -1.450425e+05 195 201 -1.664422e+05 8.322112e+03 195 225 -3.626063e+05 1.813032e+04 195 231 -5.587704e+05 2.793852e+04 195 237 -3.626063e+05 1.813032e+04 196 196 3.561542e+08 -1.780771e+07 196 197 5.820766e-11 -2.910383e-12 196 198 -2.980232e-08 1.490116e-09 196 202 8.837909e+07 -4.418955e+06 196 203 -9.458745e-11 4.729372e-12 196 222 1.582687e+08 -7.913437e+06 196 226 2.142603e+07 -1.071302e+06 196 227 3.594484e+05 -1.797242e+04 196 228 6.330749e+08 -3.165375e+07 196 232 8.636358e+07 -4.318179e+06 196 233 7.275958e-11 -3.637979e-12 196 234 1.582687e+08 -7.913437e+06 196 238 2.142603e+07 -1.071302e+06 196 239 -3.594484e+05 1.797242e+04 197 197 3.554513e+08 -1.777256e+07 197 198 5.275624e+08 -2.637812e+07 197 202 -1.018634e-10 5.093170e-12 197 203 8.700520e+07 -4.350260e+06 197 222 -1.318906e+08 6.594531e+06 197 226 3.594484e+05 -1.797242e+04 197 227 2.151390e+07 -1.075695e+06 197 228 -4.470348e-08 2.235174e-09 197 232 6.548362e-11 -3.274181e-12 197 233 8.791320e+07 -4.395660e+06 197 234 1.318906e+08 -6.594531e+06 197 238 -3.594484e+05 1.797242e+04 197 239 2.151390e+07 -1.075695e+06 198 198 1.029802e+10 -5.149009e+08 198 202 2.980232e-07 -1.490116e-08 198 203 -2.980232e-08 1.490116e-09 198 204 -5.908699e+08 2.954350e+07 198 208 2.980232e-08 -1.490116e-09 198 209 -5.275624e+08 2.637812e+07 198 228 -1.287252e+09 6.436262e+07 198 232 -1.582687e+08 7.913437e+06 198 233 1.318906e+08 -6.594531e+06 198 234 -1.983635e+09 9.918174e+07 198 238 -6.330749e+08 3.165375e+07 198 239 0.000000e+00 -0.000000e+00 198 240 -1.287252e+09 6.436262e+07 198 244 -1.582687e+08 7.913437e+06 198 245 -1.318906e+08 6.594531e+06 199 199 1.796625e+10 -8.983125e+08 199 200 -2.384186e-07 1.192093e-08 199 205 -4.424986e+09 2.212493e+08 199 206 -2.086163e-07 1.043081e-08 199 229 -2.245781e+09 1.122891e+08 199 230 -1.725352e+09 8.626761e+07 199 235 -6.657689e+07 3.328845e+06 199 236 -2.086163e-07 1.043081e-08 199 241 -2.245781e+09 1.122891e+08 199 242 1.725352e+09 -8.626761e+07 200 200 2.134027e+10 -1.067014e+09 200 205 -2.086163e-07 1.043081e-08 200 206 2.169693e+09 -1.084847e+08 200 229 -1.725352e+09 8.626761e+07 200 230 -2.667534e+09 1.333767e+08 200 235 -3.874302e-07 1.937151e-08 200 236 -7.504762e+09 3.752381e+08 200 241 1.725352e+09 -8.626761e+07 200 242 -2.667534e+09 1.333767e+08 201 201 2.900850e+06 -1.450425e+05 201 207 -1.664422e+05 8.322112e+03 201 231 -3.626063e+05 1.813032e+04 201 237 -5.587704e+05 2.793852e+04 201 243 -3.626063e+05 1.813032e+04 202 202 3.561542e+08 -1.780771e+07 202 203 1.746230e-10 -8.731149e-12 202 204 -5.960464e-08 2.980232e-09 202 208 8.837909e+07 -4.418955e+06 202 209 6.548362e-11 -3.274181e-12 202 228 1.582687e+08 -7.913437e+06 202 232 2.142603e+07 -1.071302e+06 202 233 3.594484e+05 -1.797242e+04 202 234 6.330749e+08 -3.165375e+07 202 238 8.636358e+07 -4.318179e+06 202 239 5.820766e-11 -2.910383e-12 202 240 1.582687e+08 -7.913437e+06 202 244 2.142603e+07 -1.071302e+06 202 245 -3.594484e+05 1.797242e+04 203 203 3.554513e+08 -1.777256e+07 203 204 5.275624e+08 -2.637812e+07 203 208 7.275958e-11 -3.637979e-12 203 209 8.700520e+07 -4.350260e+06 203 228 -1.318906e+08 6.594531e+06 203 232 3.594484e+05 -1.797242e+04 203 233 2.151390e+07 -1.075695e+06 203 234 -4.470348e-08 2.235174e-09 203 238 2.182787e-11 -1.091394e-12 203 239 8.791320e+07 -4.395660e+06 203 240 1.318906e+08 -6.594531e+06 203 244 -3.594484e+05 1.797242e+04 203 245 2.151390e+07 -1.075695e+06 216 216 2.574505e+09 -1.287252e+08 216 220 3.165375e+08 -1.582687e+07 216 221 -2.637812e+08 1.318906e+07 216 222 -2.954350e+08 1.477175e+07 216 226 1.582687e+08 -7.913437e+06 216 227 -2.637812e+08 1.318906e+07 217 217 4.491563e+09 -2.245781e+08 217 218 1.725352e+09 -8.626761e+07 217 223 -2.212493e+09 1.106246e+08 217 224 -1.738727e+08 8.693635e+06 218 218 5.335068e+09 -2.667534e+08 218 223 1.738727e+08 -8.693635e+06 218 224 1.084847e+09 -5.424234e+07 219 219 7.252126e+05 -3.626063e+04 219 225 -8.322112e+04 4.161056e+03 220 220 8.903855e+07 -4.451927e+06 220 221 -3.594484e+05 1.797242e+04 220 222 1.582687e+08 -7.913437e+06 220 226 4.418955e+07 -2.209477e+06 220 227 -3.622348e+04 1.811174e+03 221 221 8.886282e+07 -4.443141e+06 221 222 2.637812e+08 -1.318906e+07 221 226 3.622348e+04 -1.811174e+03 221 227 4.350260e+07 -2.175130e+06 222 222 5.149009e+09 -2.574505e+08 222 226 6.330749e+08 -3.165375e+07 222 227 0.000000e+00 -0.000000e+00 222 228 -2.954350e+08 1.477175e+07 222 232 1.582687e+08 -7.913437e+06 222 233 -2.637812e+08 1.318906e+07 223 223 8.983125e+09 -4.491563e+08 223 224 2.384186e-07 -1.192093e-08 223 229 -2.212493e+09 1.106246e+08 223 230 -1.738727e+08 8.693635e+06 224 224 1.067014e+10 -5.335068e+08 224 229 1.738727e+08 -8.693635e+06 224 230 1.084847e+09 -5.424234e+07 225 225 1.450425e+06 -7.252126e+04 225 231 -8.322112e+04 4.161056e+03 226 226 1.780771e+08 -8.903855e+06 226 227 5.820766e-11 -2.910383e-12 226 228 1.582687e+08 -7.913437e+06 226 232 4.418955e+07 -2.209477e+06 226 233 -3.622348e+04 1.811174e+03 227 227 1.777256e+08 -8.886282e+06 227 228 2.637812e+08 -1.318906e+07 227 232 3.622348e+04 -1.811174e+03 227 233 4.350260e+07 -2.175130e+06 228 228 5.149009e+09 -2.574505e+08 228 232 6.330749e+08 -3.165375e+07 228 233 0.000000e+00 -0.000000e+00 228 234 -2.954350e+08 1.477175e+07 228 238 1.582687e+08 -7.913437e+06 228 239 -2.637812e+08 1.318906e+07 229 229 8.983125e+09 -4.491563e+08 229 230 -4.768372e-07 2.384186e-08 229 235 -2.212493e+09 1.106246e+08 229 236 -1.738727e+08 8.693635e+06 230 230 1.067014e+10 -5.335068e+08 230 235 1.738727e+08 -8.693635e+06 230 236 1.084847e+09 -5.424234e+07 231 231 1.450425e+06 -7.252126e+04 231 237 -8.322112e+04 4.161056e+03 232 232 1.780771e+08 -8.903855e+06 232 233 0.000000e+00 -0.000000e+00 232 234 1.582687e+08 -7.913437e+06 232 238 4.418955e+07 -2.209477e+06 232 239 -3.622348e+04 1.811174e+03 233 233 1.777256e+08 -8.886282e+06 233 234 2.637812e+08 -1.318906e+07 233 238 3.622348e+04 -1.811174e+03 233 239 4.350260e+07 -2.175130e+06 234 234 5.149009e+09 -2.574505e+08 234 238 6.330749e+08 -3.165375e+07 234 239 0.000000e+00 -0.000000e+00 234 240 -2.954350e+08 1.477175e+07 234 244 1.582687e+08 -7.913437e+06 234 245 -2.637812e+08 1.318906e+07 235 235 8.983125e+09 -4.491563e+08 235 236 0.000000e+00 -0.000000e+00 235 241 -2.212493e+09 1.106246e+08 235 242 -1.738727e+08 8.693635e+06 236 236 1.067014e+10 -5.335068e+08 236 241 1.738727e+08 -8.693635e+06 236 242 1.084847e+09 -5.424234e+07 237 237 1.450425e+06 -7.252126e+04 237 243 -8.322112e+04 4.161056e+03 238 238 1.780771e+08 -8.903855e+06 238 239 0.000000e+00 -0.000000e+00 238 240 1.582687e+08 -7.913437e+06 238 244 4.418955e+07 -2.209477e+06 238 245 -3.622348e+04 1.811174e+03 239 239 1.777256e+08 -8.886282e+06 239 240 2.637812e+08 -1.318906e+07 239 244 3.622348e+04 -1.811174e+03 239 245 4.350260e+07 -2.175130e+06 162 162 -1.301143e+10 0.000000e+00 162 168 -3.252857e+09 0.000000e+00 162 192 -8.132143e+08 0.000000e+00 162 198 -3.252857e+09 0.000000e+00 162 204 -8.132143e+08 0.000000e+00 163 163 -1.301143e+10 0.000000e+00 163 164 -3.271014e-23 0.000000e+00 163 169 -3.252857e+09 0.000000e+00 163 193 -8.132143e+08 0.000000e+00 163 199 -3.252857e+09 0.000000e+00 163 205 -8.132143e+08 0.000000e+00 164 164 -1.301143e+10 0.000000e+00 164 170 -3.252857e+09 0.000000e+00 164 194 -8.132143e+08 0.000000e+00 164 200 -3.252857e+09 0.000000e+00 164 206 -8.132143e+08 0.000000e+00 166 166 -2.710714e+06 0.000000e+00 166 172 -6.776786e+05 0.000000e+00 166 196 -1.694196e+05 0.000000e+00 166 202 -6.776786e+05 0.000000e+00 166 208 -1.694196e+05 0.000000e+00 167 167 -2.710714e+06 0.000000e+00 167 173 -6.776786e+05 0.000000e+00 167 197 -1.694196e+05 0.000000e+00 167 203 -6.776786e+05 0.000000e+00 167 209 -1.694196e+05 0.000000e+00 180 180 -6.505714e+09 0.000000e+00 180 186 -3.252857e+09 0.000000e+00 180 216 -1.626429e+09 0.000000e+00 180 222 -8.132143e+08 0.000000e+00 181 181 -6.505714e+09 0.000000e+00 181 187 -3.252857e+09 0.000000e+00 181 217 -1.626429e+09 0.000000e+00 181 223 -8.132143e+08 0.000000e+00 182 182 -6.505714e+09 0.000000e+00 182 188 -3.252857e+09 0.000000e+00 182 218 -1.626429e+09 0.000000e+00 182 224 -8.132143e+08 0.000000e+00 184 184 -1.355357e+06 0.000000e+00 184 190 -6.776786e+05 0.000000e+00 184 220 -3.388393e+05 0.000000e+00 184 226 -1.694196e+05 0.000000e+00 185 185 -1.355357e+06 0.000000e+00 185 191 -6.776786e+05 0.000000e+00 185 221 -3.388393e+05 0.000000e+00 185 227 -1.694196e+05 0.000000e+00 186 186 -1.301143e+10 0.000000e+00 186 192 -3.252857e+09 0.000000e+00 186 216 -8.132143e+08 0.000000e+00 186 222 -3.252857e+09 0.000000e+00 186 228 -8.132143e+08 0.000000e+00 187 187 -1.301143e+10 0.000000e+00 187 193 -3.252857e+09 0.000000e+00 187 217 -8.132143e+08 0.000000e+00 187 223 -3.252857e+09 0.000000e+00 187 229 -8.132143e+08 0.000000e+00 188 188 -1.301143e+10 0.000000e+00 188 194 -3.252857e+09 0.000000e+00 188 218 -8.132143e+08 0.000000e+00 188 224 -3.252857e+09 0.000000e+00 188 230 -8.132143e+08 0.000000e+00 190 190 -2.710714e+06 0.000000e+00 190 196 -6.776786e+05 0.000000e+00 190 220 -1.694196e+05 0.000000e+00 190 226 -6.776786e+05 0.000000e+00 190 232 -1.694196e+05 0.000000e+00 191 191 -2.710714e+06 0.000000e+00 191 197 -6.776786e+05 0.000000e+00 191 221 -1.694196e+05 0.000000e+00 191 227 -6.776786e+05 0.000000e+00 191 233 -1.694196e+05 0.000000e+00 192 192 -1.301143e+10 0.000000e+00 192 198 -3.252857e+09 0.000000e+00 192 222 -8.132143e+08 0.000000e+00 192 228 -3.252857e+09 0.000000e+00 192 234 -8.132143e+08 0.000000e+00 193 193 -1.301143e+10 0.000000e+00 193 199 -3.252857e+09 0.000000e+00 193 223 -8.132143e+08 0.000000e+00 193 229 -3.252857e+09 0.000000e+00 193 235 -8.132143e+08 0.000000e+00 194 194 -1.301143e+10 0.000000e+00 194 200 -3.252857e+09 0.000000e+00 194 224 -8.132143e+08 0.000000e+00 194 230 -3.252857e+09 0.000000e+00 194 236 -8.132143e+08 0.000000e+00 196 196 -2.710714e+06 0.000000e+00 196 202 -6.776786e+05 0.000000e+00 196 226 -1.694196e+05 0.000000e+00 196 232 -6.776786e+05 0.000000e+00 196 238 -1.694196e+05 0.000000e+00 197 197 -2.710714e+06 0.000000e+00 197 203 -6.776786e+05 0.000000e+00 197 227 -1.694196e+05 0.000000e+00 197 233 -6.776786e+05 0.000000e+00 197 239 -1.694196e+05 0.000000e+00 198 198 -1.301143e+10 0.000000e+00 198 204 -3.252857e+09 0.000000e+00 198 228 -8.132143e+08 0.000000e+00 198 234 -3.252857e+09 0.000000e+00 198 240 -8.132143e+08 0.000000e+00 199 199 -1.301143e+10 0.000000e+00 199 205 -3.252857e+09 0.000000e+00 199 229 -8.132143e+08 0.000000e+00 199 235 -3.252857e+09 0.000000e+00 199 241 -8.132143e+08 0.000000e+00 200 200 -1.301143e+10 0.000000e+00 200 206 -3.252857e+09 0.000000e+00 200 230 -8.132143e+08 0.000000e+00 200 236 -3.252857e+09 0.000000e+00 200 242 -8.132143e+08 0.000000e+00 202 202 -2.710714e+06 0.000000e+00 202 208 -6.776786e+05 0.000000e+00 202 232 -1.694196e+05 0.000000e+00 202 238 -6.776786e+05 0.000000e+00 202 244 -1.694196e+05 0.000000e+00 203 203 -2.710714e+06 0.000000e+00 203 209 -6.776786e+05 0.000000e+00 203 233 -1.694196e+05 0.000000e+00 203 239 -6.776786e+05 0.000000e+00 203 245 -1.694196e+05 0.000000e+00 216 216 -3.252857e+09 0.000000e+00 216 222 -1.626429e+09 0.000000e+00 217 217 -3.252857e+09 0.000000e+00 217 223 -1.626429e+09 0.000000e+00 218 218 -3.252857e+09 0.000000e+00 218 224 -1.626429e+09 0.000000e+00 220 220 -6.776786e+05 0.000000e+00 220 226 -3.388393e+05 0.000000e+00 221 221 -6.776786e+05 0.000000e+00 221 227 -3.388393e+05 0.000000e+00 222 222 -6.505714e+09 0.000000e+00 222 228 -1.626429e+09 0.000000e+00 223 223 -6.505714e+09 0.000000e+00 223 229 -1.626429e+09 0.000000e+00 224 224 -6.505714e+09 0.000000e+00 224 230 -1.626429e+09 0.000000e+00 226 226 -1.355357e+06 0.000000e+00 226 232 -3.388393e+05 0.000000e+00 227 227 -1.355357e+06 0.000000e+00 227 233 -3.388393e+05 0.000000e+00 228 228 -6.505714e+09 0.000000e+00 228 234 -1.626429e+09 0.000000e+00 229 229 -6.505714e+09 0.000000e+00 229 235 -1.626429e+09 0.000000e+00 230 230 -6.505714e+09 0.000000e+00 230 236 -1.626429e+09 0.000000e+00 232 232 -1.355357e+06 0.000000e+00 232 238 -3.388393e+05 0.000000e+00 233 233 -1.355357e+06 0.000000e+00 233 239 -3.388393e+05 0.000000e+00 234 234 -6.505714e+09 0.000000e+00 234 240 -1.626429e+09 0.000000e+00 235 235 -6.505714e+09 0.000000e+00 235 241 -1.626429e+09 0.000000e+00 236 236 -6.505714e+09 0.000000e+00 236 242 -1.626429e+09 0.000000e+00 238 238 -1.355357e+06 0.000000e+00 238 244 -3.388393e+05 0.000000e+00 239 239 -1.355357e+06 0.000000e+00 239 245 -3.388393e+05 0.000000e+00 05 1.813032e+04 202 202 3.561542e+08 -1.780771e+07 202 203 1.746230e-10 -8.731149e-12 202 204 -5.960464e-08 2.980232e-09 202 208 8.837909e+07 -4.418955e+06 202 209 6.548362e-11 -3.274181e-12 202 228 1.582687e+08 -7.913437e+06 202 232 2.142603e+07 -1.071302e+06 202 233 3.594484e+05 -1.797242e+04 202 234 6.330749e+08 -3.165375e+07 202 238 8.MPI/drivers/haggar.mtx.2.input010064400020550007177000001321470665164053300174750ustar00clevecompmath00000400000006252 252 1328 0 0 2.574505e+09 -1.287252e+08 0 4 -3.165375e+08 1.582687e+07 0 5 -2.637812e+08 1.318906e+07 0 6 -2.954350e+08 1.477175e+07 0 10 -1.582687e+08 7.913437e+06 0 11 -2.637812e+08 1.318906e+07 0 12 -9.918174e+08 4.959087e+07 0 16 -3.165375e+08 1.582687e+07 0 17 -1.318906e+08 6.594531e+06 0 18 -1.287252e+09 6.436262e+07 0 22 -1.582687e+08 7.913437e+06 0 23 -1.318906e+08 6.594531e+06 1 1 4.491563e+09 -2.245781e+08 1 2 -1.725352e+09 8.626761e+07 1 7 -2.212493e+09 1.106246e+08 1 8 1.738727e+08 -8.693635e+06 1 13 -3.328845e+07 1.664422e+06 1 14 -1.738727e+08 8.693635e+06 1 19 -2.245781e+09 1.122891e+08 1 20 1.725352e+09 -8.626761e+07 2 2 5.335068e+09 -2.667534e+08 2 7 -1.738727e+08 8.693635e+06 2 8 1.084847e+09 -5.424234e+07 2 13 1.738727e+08 -8.693635e+06 2 14 -3.752381e+09 1.876190e+08 2 19 1.725352e+09 -8.626761e+07 2 20 -2.667534e+09 1.333767e+08 3 3 7.252126e+05 -3.626063e+04 3 9 -8.322112e+04 4.161056e+03 3 15 -2.793852e+05 1.396926e+04 3 21 -3.626063e+05 1.813032e+04 4 4 8.903855e+07 -4.451927e+06 4 5 3.594484e+05 -1.797242e+04 4 6 -1.582687e+08 7.913437e+06 4 10 4.418955e+07 -2.209477e+06 4 11 3.622348e+04 -1.811174e+03 4 12 3.165375e+08 -1.582687e+07 4 16 4.318179e+07 -2.159090e+06 4 17 -3.622348e+04 1.811174e+03 4 18 1.582687e+08 -7.913437e+06 4 22 2.142603e+07 -1.071302e+06 4 23 -3.594484e+05 1.797242e+04 5 5 8.886282e+07 -4.443141e+06 5 6 2.637812e+08 -1.318906e+07 5 10 -3.622348e+04 1.811174e+03 5 11 4.350260e+07 -2.175130e+06 5 12 -1.318906e+08 6.594531e+06 5 16 3.622348e+04 -1.811174e+03 5 17 4.395660e+07 -2.197830e+06 5 18 1.318906e+08 -6.594531e+06 5 22 -3.594484e+05 1.797242e+04 5 23 2.151390e+07 -1.075695e+06 6 6 5.149009e+09 -2.574505e+08 6 10 -6.330749e+08 3.165375e+07 6 11 2.980232e-08 -1.490116e-09 6 12 -1.287252e+09 6.436262e+07 6 16 -1.582687e+08 7.913437e+06 6 17 1.318906e+08 -6.594531e+06 6 18 -1.983635e+09 9.918174e+07 6 22 -6.330749e+08 3.165375e+07 6 23 4.470348e-08 -2.235174e-09 6 24 -2.954350e+08 1.477175e+07 6 28 -1.582687e+08 7.913437e+06 6 29 -2.637812e+08 1.318906e+07 6 30 -1.287252e+09 6.436262e+07 6 34 -1.582687e+08 7.913437e+06 6 35 -1.318906e+08 6.594531e+06 7 7 8.983125e+09 -4.491563e+08 7 8 7.152557e-07 -3.576279e-08 7 13 -2.245781e+09 1.122891e+08 7 14 -1.725352e+09 8.626761e+07 7 19 -6.657689e+07 3.328845e+06 7 20 -6.854534e-07 3.427267e-08 7 25 -2.212493e+09 1.106246e+08 7 26 1.738727e+08 -8.693635e+06 7 31 -2.245781e+09 1.122891e+08 7 32 1.725352e+09 -8.626761e+07 8 8 1.067014e+10 -5.335068e+08 8 13 -1.725352e+09 8.626761e+07 8 14 -2.667534e+09 1.333767e+08 8 19 -6.258488e-07 3.129244e-08 8 20 -7.504762e+09 3.752381e+08 8 25 -1.738727e+08 8.693635e+06 8 26 1.084847e+09 -5.424234e+07 8 31 1.725352e+09 -8.626761e+07 8 32 -2.667534e+09 1.333767e+08 9 9 1.450425e+06 -7.252126e+04 9 15 -3.626063e+05 1.813032e+04 9 21 -5.587704e+05 2.793852e+04 9 27 -8.322112e+04 4.161056e+03 9 33 -3.626063e+05 1.813032e+04 10 10 1.780771e+08 -8.903855e+06 10 11 -1.746230e-10 8.731149e-12 10 12 1.582687e+08 -7.913437e+06 10 16 2.142603e+07 -1.071302e+06 10 17 3.594484e+05 -1.797242e+04 10 18 6.330749e+08 -3.165375e+07 10 22 8.636358e+07 -4.318179e+06 10 23 1.382432e-10 -6.912160e-12 10 24 -1.582687e+08 7.913437e+06 10 28 4.418955e+07 -2.209477e+06 10 29 3.622348e+04 -1.811174e+03 10 30 1.582687e+08 -7.913437e+06 10 34 2.142603e+07 -1.071302e+06 10 35 -3.594484e+05 1.797242e+04 11 11 1.777256e+08 -8.886282e+06 11 12 -1.318906e+08 6.594531e+06 11 16 3.594484e+05 -1.797242e+04 11 17 2.151390e+07 -1.075695e+06 11 18 -8.940697e-08 4.470348e-09 11 22 1.455192e-10 -7.275958e-12 11 23 8.791320e+07 -4.395660e+06 11 24 2.637812e+08 -1.318906e+07 11 28 -3.622348e+04 1.811174e+03 11 29 4.350260e+07 -2.175130e+06 11 30 1.318906e+08 -6.594531e+06 11 34 -3.594484e+05 1.797242e+04 11 35 2.151390e+07 -1.075695e+06 12 12 5.149009e+09 -2.574505e+08 12 16 0.000000e+00 -0.000000e+00 12 17 -5.275624e+08 2.637812e+07 12 18 -5.908699e+08 2.954350e+07 12 22 0.000000e+00 -0.000000e+00 12 23 -5.275624e+08 2.637812e+07 12 72 -9.918174e+08 4.959087e+07 12 76 -3.165375e+08 1.582687e+07 12 77 -1.318906e+08 6.594531e+06 12 78 -1.287252e+09 6.436262e+07 12 82 -1.582687e+08 7.913437e+06 12 83 -1.318906e+08 6.594531e+06 13 13 8.983125e+09 -4.491563e+08 13 14 2.384186e-07 -1.192093e-08 13 19 -4.424986e+09 2.212493e+08 13 20 5.960464e-08 -2.980232e-09 13 73 -3.328845e+07 1.664422e+06 13 74 -1.738727e+08 8.693635e+06 13 79 -2.245781e+09 1.122891e+08 13 80 1.725352e+09 -8.626761e+07 14 14 1.067014e+10 -5.335068e+08 14 19 5.960464e-08 -2.980232e-09 14 20 2.169693e+09 -1.084847e+08 14 73 1.738727e+08 -8.693635e+06 14 74 -3.752381e+09 1.876190e+08 14 79 1.725352e+09 -8.626761e+07 14 80 -2.667534e+09 1.333767e+08 15 15 1.450425e+06 -7.252126e+04 15 21 -1.664422e+05 8.322112e+03 15 75 -2.793852e+05 1.396926e+04 15 81 -3.626063e+05 1.813032e+04 16 16 1.780771e+08 -8.903855e+06 16 17 -1.164153e-10 5.820766e-12 16 18 -2.980232e-08 1.490116e-09 16 22 8.837909e+07 -4.418955e+06 16 23 -3.637979e-11 1.818989e-12 16 72 3.165375e+08 -1.582687e+07 16 76 4.318179e+07 -2.159090e+06 16 77 -3.622348e+04 1.811174e+03 16 78 1.582687e+08 -7.913437e+06 16 82 2.142603e+07 -1.071302e+06 16 83 -3.594484e+05 1.797242e+04 17 17 1.777256e+08 -8.886282e+06 17 18 5.275624e+08 -2.637812e+07 17 22 -2.910383e-11 1.455192e-12 17 23 8.700520e+07 -4.350260e+06 17 72 -1.318906e+08 6.594531e+06 17 76 3.622348e+04 -1.811174e+03 17 77 4.395660e+07 -2.197830e+06 17 78 1.318906e+08 -6.594531e+06 17 82 -3.594484e+05 1.797242e+04 17 83 2.151390e+07 -1.075695e+06 18 18 1.029802e+10 -5.149009e+08 18 22 5.960464e-08 -2.980232e-09 18 23 -5.960464e-08 2.980232e-09 18 24 -1.287252e+09 6.436262e+07 18 28 1.582687e+08 -7.913437e+06 18 29 -1.318906e+08 6.594531e+06 18 30 -5.908699e+08 2.954350e+07 18 34 -1.192093e-07 5.960464e-09 18 35 -5.275624e+08 2.637812e+07 18 72 -1.287252e+09 6.436262e+07 18 76 -1.582687e+08 7.913437e+06 18 77 1.318906e+08 -6.594531e+06 18 78 -1.983635e+09 9.918174e+07 18 82 -6.330749e+08 3.165375e+07 18 83 1.490116e-08 -7.450581e-10 18 84 -1.287252e+09 6.436262e+07 18 88 -1.582687e+08 7.913437e+06 18 89 -1.318906e+08 6.594531e+06 19 19 1.796625e+10 -8.983125e+08 19 20 9.536743e-07 -4.768372e-08 19 25 -2.245781e+09 1.122891e+08 19 26 -1.725352e+09 8.626761e+07 19 31 -4.424986e+09 2.212493e+08 19 32 3.576279e-07 -1.788139e-08 19 73 -2.245781e+09 1.122891e+08 19 74 -1.725352e+09 8.626761e+07 19 79 -6.657689e+07 3.328845e+06 19 80 -5.960464e-08 2.980232e-09 19 85 -2.245781e+09 1.122891e+08 19 86 1.725352e+09 -8.626761e+07 20 20 2.134027e+10 -1.067014e+09 20 25 -1.725352e+09 8.626761e+07 20 26 -2.667534e+09 1.333767e+08 20 31 4.768372e-07 -2.384186e-08 20 32 2.169693e+09 -1.084847e+08 20 73 -1.725352e+09 8.626761e+07 20 74 -2.667534e+09 1.333767e+08 20 79 -2.682209e-07 1.341105e-08 20 80 -7.504762e+09 3.752381e+08 20 85 1.725352e+09 -8.626761e+07 20 86 -2.667534e+09 1.333767e+08 21 21 2.900850e+06 -1.450425e+05 21 27 -3.626063e+05 1.813032e+04 21 33 -1.664422e+05 8.322112e+03 21 75 -3.626063e+05 1.813032e+04 21 81 -5.587704e+05 2.793852e+04 21 87 -3.626063e+05 1.813032e+04 22 22 3.561542e+08 -1.780771e+07 22 23 0.000000e+00 -0.000000e+00 22 24 -1.582687e+08 7.913437e+06 22 28 2.142603e+07 -1.071302e+06 22 29 3.594484e+05 -1.797242e+04 22 30 -2.980232e-08 1.490116e-09 22 34 8.837909e+07 -4.418955e+06 22 35 -1.236913e-10 6.184564e-12 22 72 1.582687e+08 -7.913437e+06 22 76 2.142603e+07 -1.071302e+06 22 77 3.594484e+05 -1.797242e+04 22 78 6.330749e+08 -3.165375e+07 22 82 8.636358e+07 -4.318179e+06 22 83 5.820766e-11 -2.910383e-12 22 84 1.582687e+08 -7.913437e+06 22 88 2.142603e+07 -1.071302e+06 22 89 -3.594484e+05 1.797242e+04 23 23 3.554513e+08 -1.777256e+07 23 24 1.318906e+08 -6.594531e+06 23 28 3.594484e+05 -1.797242e+04 23 29 2.151390e+07 -1.075695e+06 23 30 5.275624e+08 -2.637812e+07 23 34 -1.018634e-10 5.093170e-12 23 35 8.700520e+07 -4.350260e+06 23 72 -1.318906e+08 6.594531e+06 23 76 3.594484e+05 -1.797242e+04 23 77 2.151390e+07 -1.075695e+06 23 78 -1.490116e-08 7.450581e-10 23 82 2.910383e-11 -1.455192e-12 23 83 8.791320e+07 -4.395660e+06 23 84 1.318906e+08 -6.594531e+06 23 88 -3.594484e+05 1.797242e+04 23 89 2.151390e+07 -1.075695e+06 24 24 5.149009e+09 -2.574505e+08 24 28 -6.330749e+08 3.165375e+07 24 29 2.980232e-08 -1.490116e-09 24 30 -1.983635e+09 9.918174e+07 24 34 -6.330749e+08 3.165375e+07 24 35 4.470348e-08 -2.235174e-09 24 36 -2.954350e+08 1.477175e+07 24 40 -1.582687e+08 7.913437e+06 24 41 -2.637812e+08 1.318906e+07 24 42 -1.287252e+09 6.436262e+07 24 46 -1.582687e+08 7.913437e+06 24 47 -1.318906e+08 6.594531e+06 25 25 8.983125e+09 -4.491563e+08 25 26 2.384186e-07 -1.192093e-08 25 31 -6.657689e+07 3.328845e+06 25 32 -8.940697e-07 4.470348e-08 25 37 -2.212493e+09 1.106246e+08 25 38 1.738727e+08 -8.693635e+06 25 43 -2.245781e+09 1.122891e+08 25 44 1.725352e+09 -8.626761e+07 26 26 1.067014e+10 -5.335068e+08 26 31 -8.642673e-07 4.321337e-08 26 32 -7.504762e+09 3.752381e+08 26 37 -1.738727e+08 8.693635e+06 26 38 1.084847e+09 -5.424234e+07 26 43 1.725352e+09 -8.626761e+07 26 44 -2.667534e+09 1.333767e+08 27 27 1.450425e+06 -7.252126e+04 27 33 -5.587704e+05 2.793852e+04 27 39 -8.322112e+04 4.161056e+03 27 45 -3.626063e+05 1.813032e+04 28 28 1.780771e+08 -8.903855e+06 28 29 -5.820766e-11 2.910383e-12 28 30 6.330749e+08 -3.165375e+07 28 34 8.636358e+07 -4.318179e+06 28 35 2.037268e-10 -1.018634e-11 28 36 -1.582687e+08 7.913437e+06 28 40 4.418955e+07 -2.209477e+06 28 41 3.622348e+04 -1.811174e+03 28 42 1.582687e+08 -7.913437e+06 28 46 2.142603e+07 -1.071302e+06 28 47 -3.594484e+05 1.797242e+04 29 29 1.777256e+08 -8.886282e+06 29 30 -8.940697e-08 4.470348e-09 29 34 1.527951e-10 -7.639755e-12 29 35 8.791320e+07 -4.395660e+06 29 36 2.637812e+08 -1.318906e+07 29 40 -3.622348e+04 1.811174e+03 29 41 4.350260e+07 -2.175130e+06 29 42 1.318906e+08 -6.594531e+06 29 46 -3.594484e+05 1.797242e+04 29 47 2.151390e+07 -1.075695e+06 30 30 1.029802e+10 -5.149009e+08 30 34 1.788139e-07 -8.940697e-09 30 35 -5.960464e-08 2.980232e-09 30 36 -1.287252e+09 6.436262e+07 30 40 1.582687e+08 -7.913437e+06 30 41 -1.318906e+08 6.594531e+06 30 42 -5.908699e+08 2.954350e+07 30 46 -1.490116e-07 7.450581e-09 30 47 -5.275624e+08 2.637812e+07 30 78 -1.287252e+09 6.436262e+07 30 82 -1.582687e+08 7.913437e+06 30 83 1.318906e+08 -6.594531e+06 30 84 -1.983635e+09 9.918174e+07 30 88 -6.330749e+08 3.165375e+07 30 89 1.490116e-08 -7.450581e-10 30 90 -1.287252e+09 6.436262e+07 30 94 -1.582687e+08 7.913437e+06 30 95 -1.318906e+08 6.594531e+06 31 31 1.796625e+10 -8.983125e+08 31 32 -2.384186e-07 1.192093e-08 31 37 -2.245781e+09 1.122891e+08 31 38 -1.725352e+09 8.626761e+07 31 43 -4.424986e+09 2.212493e+08 31 44 6.258488e-07 -3.129244e-08 31 79 -2.245781e+09 1.122891e+08 31 80 -1.725352e+09 8.626761e+07 31 85 -6.657689e+07 3.328845e+06 31 86 -1.192093e-07 5.960464e-09 31 91 -2.245781e+09 1.122891e+08 31 92 1.725352e+09 -8.626761e+07 32 32 2.134027e+10 -1.067014e+09 32 37 -1.725352e+09 8.626761e+07 32 38 -2.667534e+09 1.333767e+08 32 43 5.364418e-07 -2.682209e-08 32 44 2.169693e+09 -1.084847e+08 32 79 -1.725352e+09 8.626761e+07 32 80 -2.667534e+09 1.333767e+08 32 85 -3.278255e-07 1.639128e-08 32 86 -7.504762e+09 3.752381e+08 32 91 1.725352e+09 -8.626761e+07 32 92 -2.667534e+09 1.333767e+08 33 33 2.900850e+06 -1.450425e+05 33 39 -3.626063e+05 1.813032e+04 33 45 -1.664422e+05 8.322112e+03 33 81 -3.626063e+05 1.813032e+04 33 87 -5.587704e+05 2.793852e+04 33 93 -3.626063e+05 1.813032e+04 34 34 3.561542e+08 -1.780771e+07 34 35 1.164153e-10 -5.820766e-12 34 36 -1.582687e+08 7.913437e+06 34 40 2.142603e+07 -1.071302e+06 34 41 3.594484e+05 -1.797242e+04 34 42 -2.980232e-08 1.490116e-09 34 46 8.837909e+07 -4.418955e+06 34 47 -1.673470e-10 8.367351e-12 34 78 1.582687e+08 -7.913437e+06 34 82 2.142603e+07 -1.071302e+06 34 83 3.594484e+05 -1.797242e+04 34 84 6.330749e+08 -3.165375e+07 34 88 8.636358e+07 -4.318179e+06 34 89 1.018634e-10 -5.093170e-12 34 90 1.582687e+08 -7.913437e+06 34 94 2.142603e+07 -1.071302e+06 34 95 -3.594484e+05 1.797242e+04 35 35 3.554513e+08 -1.777256e+07 35 36 1.318906e+08 -6.594531e+06 35 40 3.594484e+05 -1.797242e+04 35 41 2.151390e+07 -1.075695e+06 35 42 5.275624e+08 -2.637812e+07 35 46 -1.600711e-10 8.003553e-12 35 47 8.700520e+07 -4.350260e+06 35 78 -1.318906e+08 6.594531e+06 35 82 3.594484e+05 -1.797242e+04 35 83 2.151390e+07 -1.075695e+06 35 84 -1.490116e-08 7.450581e-10 35 88 3.637979e-11 -1.818989e-12 35 89 8.791320e+07 -4.395660e+06 35 90 1.318906e+08 -6.594531e+06 35 94 -3.594484e+05 1.797242e+04 35 95 2.151390e+07 -1.075695e+06 72 72 5.149009e+09 -2.574505e+08 72 76 0.000000e+00 -0.000000e+00 72 77 -5.275624e+08 2.637812e+07 72 78 -5.908699e+08 2.954350e+07 72 82 0.000000e+00 -0.000000e+00 72 83 -5.275624e+08 2.637812e+07 72 108 -9.918174e+08 4.959087e+07 72 112 -3.165375e+08 1.582687e+07 72 113 -1.318906e+08 6.594531e+06 72 114 -1.287252e+09 6.436262e+07 72 118 -1.582687e+08 7.913437e+06 72 119 -1.318906e+08 6.594531e+06 73 73 8.983125e+09 -4.491563e+08 73 74 0.000000e+00 -0.000000e+00 73 79 -4.424986e+09 2.212493e+08 73 80 -5.960464e-08 2.980232e-09 73 109 -3.328845e+07 1.664422e+06 73 110 -1.738727e+08 8.693635e+06 73 115 -2.245781e+09 1.122891e+08 73 116 1.725352e+09 -8.626761e+07 74 74 1.067014e+10 -5.335068e+08 74 79 8.940697e-08 -4.470348e-09 74 80 2.169693e+09 -1.084847e+08 74 109 1.738727e+08 -8.693635e+06 74 110 -3.752381e+09 1.876190e+08 74 115 1.725352e+09 -8.626761e+07 74 116 -2.667534e+09 1.333767e+08 75 75 1.450425e+06 -7.252126e+04 75 81 -1.664422e+05 8.322112e+03 75 111 -2.793852e+05 1.396926e+04 75 117 -3.626063e+05 1.813032e+04 76 76 1.780771e+08 -8.903855e+06 76 77 0.000000e+00 -0.000000e+00 76 78 -2.980232e-08 1.490116e-09 76 82 8.837909e+07 -4.418955e+06 76 83 0.000000e+00 -0.000000e+00 76 108 3.165375e+08 -1.582687e+07 76 112 4.318179e+07 -2.159090e+06 76 113 -3.622348e+04 1.811174e+03 76 114 1.582687e+08 -7.913437e+06 76 118 2.142603e+07 -1.071302e+06 76 119 -3.594484e+05 1.797242e+04 77 77 1.777256e+08 -8.886282e+06 77 78 5.275624e+08 -2.637812e+07 77 82 3.637979e-11 -1.818989e-12 77 83 8.700520e+07 -4.350260e+06 77 108 -1.318906e+08 6.594531e+06 77 112 3.622348e+04 -1.811174e+03 77 113 4.395660e+07 -2.197830e+06 77 114 1.318906e+08 -6.594531e+06 77 118 -3.594484e+05 1.797242e+04 77 119 2.151390e+07 -1.075695e+06 78 78 1.029802e+10 -5.149009e+08 78 82 5.960464e-08 -2.980232e-09 78 83 -5.960464e-08 2.980232e-09 78 84 -5.908699e+08 2.954350e+07 78 88 -1.192093e-07 5.960464e-09 78 89 -5.275624e+08 2.637812e+07 78 108 -1.287252e+09 6.436262e+07 78 112 -1.582687e+08 7.913437e+06 78 113 1.318906e+08 -6.594531e+06 78 114 -1.983635e+09 9.918174e+07 78 118 -6.330749e+08 3.165375e+07 78 119 2.980232e-08 -1.490116e-09 78 120 -1.287252e+09 6.436262e+07 78 124 -1.582687e+08 7.913437e+06 78 125 -1.318906e+08 6.594531e+06 79 79 1.796625e+10 -8.983125e+08 79 80 -2.384186e-07 1.192093e-08 79 85 -4.424986e+09 2.212493e+08 79 86 1.788139e-07 -8.940697e-09 79 109 -2.245781e+09 1.122891e+08 79 110 -1.725352e+09 8.626761e+07 79 115 -6.657689e+07 3.328845e+06 79 116 -2.384186e-07 1.192093e-08 79 121 -2.245781e+09 1.122891e+08 79 122 1.725352e+09 -8.626761e+07 80 80 2.134027e+10 -1.067014e+09 80 85 2.384186e-07 -1.192093e-08 80 86 2.169693e+09 -1.084847e+08 80 109 -1.725352e+09 8.626761e+07 80 110 -2.667534e+09 1.333767e+08 80 115 5.960464e-08 -2.980232e-09 80 116 -7.504762e+09 3.752381e+08 80 121 1.725352e+09 -8.626761e+07 80 122 -2.667534e+09 1.333767e+08 81 81 2.900850e+06 -1.450425e+05 81 87 -1.664422e+05 8.322112e+03 81 111 -3.626063e+05 1.813032e+04 81 117 -5.587704e+05 2.793852e+04 81 123 -3.626063e+05 1.813032e+04 82 82 3.561542e+08 -1.780771e+07 82 83 -5.820766e-11 2.910383e-12 82 84 -2.980232e-08 1.490116e-09 82 88 8.837909e+07 -4.418955e+06 82 89 -5.093170e-11 2.546585e-12 82 108 1.582687e+08 -7.913437e+06 82 112 2.142603e+07 -1.071302e+06 82 113 3.594484e+05 -1.797242e+04 82 114 6.330749e+08 -3.165375e+07 82 118 8.636358e+07 -4.318179e+06 82 119 0.000000e+00 -0.000000e+00 82 120 1.582687e+08 -7.913437e+06 82 124 2.142603e+07 -1.071302e+06 82 125 -3.594484e+05 1.797242e+04 83 83 3.554513e+08 -1.777256e+07 83 84 5.275624e+08 -2.637812e+07 83 88 -2.910383e-11 1.455192e-12 83 89 8.700520e+07 -4.350260e+06 83 108 -1.318906e+08 6.594531e+06 83 112 3.594484e+05 -1.797242e+04 83 113 2.151390e+07 -1.075695e+06 83 114 -1.490116e-08 7.450581e-10 83 118 2.910383e-11 -1.455192e-12 83 119 8.791320e+07 -4.395660e+06 83 120 1.318906e+08 -6.594531e+06 83 124 -3.594484e+05 1.797242e+04 83 125 2.151390e+07 -1.075695e+06 84 84 1.029802e+10 -5.149009e+08 84 88 1.788139e-07 -8.940697e-09 84 89 -5.960464e-08 2.980232e-09 84 90 -5.908699e+08 2.954350e+07 84 94 -1.192093e-07 5.960464e-09 84 95 -5.275624e+08 2.637812e+07 84 114 -1.287252e+09 6.436262e+07 84 118 -1.582687e+08 7.913437e+06 84 119 1.318906e+08 -6.594531e+06 84 120 -1.983635e+09 9.918174e+07 84 124 -6.330749e+08 3.165375e+07 84 125 2.980232e-08 -1.490116e-09 84 126 -1.287252e+09 6.436262e+07 84 130 -1.582687e+08 7.913437e+06 84 131 -1.318906e+08 6.594531e+06 85 85 1.796625e+10 -8.983125e+08 85 86 -1.192093e-06 5.960464e-08 85 91 -4.424986e+09 2.212493e+08 85 92 4.768372e-07 -2.384186e-08 85 115 -2.245781e+09 1.122891e+08 85 116 -1.725352e+09 8.626761e+07 85 121 -6.657689e+07 3.328845e+06 85 122 -2.682209e-07 1.341105e-08 85 127 -2.245781e+09 1.122891e+08 85 128 1.725352e+09 -8.626761e+07 86 86 2.134027e+10 -1.067014e+09 86 91 5.066395e-07 -2.533197e-08 86 92 2.169693e+09 -1.084847e+08 86 115 -1.725352e+09 8.626761e+07 86 116 -2.667534e+09 1.333767e+08 86 121 0.000000e+00 -0.000000e+00 86 122 -7.504762e+09 3.752381e+08 86 127 1.725352e+09 -8.626761e+07 86 128 -2.667534e+09 1.333767e+08 87 87 2.900850e+06 -1.450425e+05 87 93 -1.664422e+05 8.322112e+03 87 117 -3.626063e+05 1.813032e+04 87 123 -5.587704e+05 2.793852e+04 87 129 -3.626063e+05 1.813032e+04 88 88 3.561542e+08 -1.780771e+07 88 89 5.820766e-11 -2.910383e-12 88 90 -2.980232e-08 1.490116e-09 88 94 8.837909e+07 -4.418955e+06 88 95 -1.018634e-10 5.093170e-12 88 114 1.582687e+08 -7.913437e+06 88 118 2.142603e+07 -1.071302e+06 88 119 3.594484e+05 -1.797242e+04 88 120 6.330749e+08 -3.165375e+07 88 124 8.636358e+07 -4.318179e+06 88 125 7.275958e-12 -3.637979e-13 88 126 1.582687e+08 -7.913437e+06 88 130 2.142603e+07 -1.071302e+06 88 131 -3.594484e+05 1.797242e+04 89 89 3.554513e+08 -1.777256e+07 89 90 5.275624e+08 -2.637812e+07 89 94 -8.731149e-11 4.365575e-12 89 95 8.700520e+07 -4.350260e+06 89 114 -1.318906e+08 6.594531e+06 89 118 3.594484e+05 -1.797242e+04 89 119 2.151390e+07 -1.075695e+06 89 120 -1.490116e-08 7.450581e-10 89 124 3.637979e-11 -1.818989e-12 89 125 8.791320e+07 -4.395660e+06 89 126 1.318906e+08 -6.594531e+06 89 130 -3.594484e+05 1.797242e+04 89 131 2.151390e+07 -1.075695e+06 108 108 5.149009e+09 -2.574505e+08 108 112 0.000000e+00 -0.000000e+00 108 113 -5.275624e+08 2.637812e+07 108 114 -5.908699e+08 2.954350e+07 108 118 0.000000e+00 -0.000000e+00 108 119 -5.275624e+08 2.637812e+07 108 144 -9.918174e+08 4.959087e+07 108 148 -3.165375e+08 1.582687e+07 108 149 -1.318906e+08 6.594531e+06 108 150 -1.287252e+09 6.436262e+07 108 154 -1.582687e+08 7.913437e+06 108 155 -1.318906e+08 6.594531e+06 109 109 8.983125e+09 -4.491563e+08 109 110 2.384186e-07 -1.192093e-08 109 115 -4.424986e+09 2.212493e+08 109 116 1.788139e-07 -8.940697e-09 109 145 -3.328845e+07 1.664422e+06 109 146 -1.738727e+08 8.693635e+06 109 151 -2.245781e+09 1.122891e+08 109 152 1.725352e+09 -8.626761e+07 110 110 1.067014e+10 -5.335068e+08 110 115 8.940697e-08 -4.470348e-09 110 116 2.169693e+09 -1.084847e+08 110 145 1.738727e+08 -8.693635e+06 110 146 -3.752381e+09 1.876190e+08 110 151 1.725352e+09 -8.626761e+07 110 152 -2.667534e+09 1.333767e+08 111 111 1.450425e+06 -7.252126e+04 111 117 -1.664422e+05 8.322112e+03 111 147 -2.793852e+05 1.396926e+04 111 153 -3.626063e+05 1.813032e+04 112 112 1.780771e+08 -8.903855e+06 112 113 -5.820766e-11 2.910383e-12 112 114 0.000000e+00 -0.000000e+00 112 118 8.837909e+07 -4.418955e+06 112 119 -2.910383e-11 1.455192e-12 112 144 3.165375e+08 -1.582687e+07 112 148 4.318179e+07 -2.159090e+06 112 149 -3.622348e+04 1.811174e+03 112 150 1.582687e+08 -7.913437e+06 112 154 2.142603e+07 -1.071302e+06 112 155 -3.594484e+05 1.797242e+04 113 113 1.777256e+08 -8.886282e+06 113 114 5.275624e+08 -2.637812e+07 113 118 -1.455192e-11 7.275958e-13 113 119 8.700520e+07 -4.350260e+06 113 144 -1.318906e+08 6.594531e+06 113 148 3.622348e+04 -1.811174e+03 113 149 4.395660e+07 -2.197830e+06 113 150 1.318906e+08 -6.594531e+06 113 154 -3.594484e+05 1.797242e+04 113 155 2.151390e+07 -1.075695e+06 114 114 1.029802e+10 -5.149009e+08 114 118 5.960464e-08 -2.980232e-09 114 119 -8.940697e-08 4.470348e-09 114 120 -5.908699e+08 2.954350e+07 114 124 -1.192093e-07 5.960464e-09 114 125 -5.275624e+08 2.637812e+07 114 144 -1.287252e+09 6.436262e+07 114 148 -1.582687e+08 7.913437e+06 114 149 1.318906e+08 -6.594531e+06 114 150 -1.983635e+09 9.918174e+07 114 154 -6.330749e+08 3.165375e+07 114 155 1.490116e-08 -7.450581e-10 114 156 -1.287252e+09 6.436262e+07 114 160 -1.582687e+08 7.913437e+06 114 161 -1.318906e+08 6.594531e+06 115 115 1.796625e+10 -8.983125e+08 115 116 0.000000e+00 -0.000000e+00 115 121 -4.424986e+09 2.212493e+08 115 122 3.874302e-07 -1.937151e-08 115 145 -2.245781e+09 1.122891e+08 115 146 -1.725352e+09 8.626761e+07 115 151 -6.657689e+07 3.328845e+06 115 152 -1.788139e-07 8.940697e-09 115 157 -2.245781e+09 1.122891e+08 115 158 1.725352e+09 -8.626761e+07 116 116 2.134027e+10 -1.067014e+09 116 121 1.788139e-07 -8.940697e-09 116 122 2.169693e+09 -1.084847e+08 116 145 -1.725352e+09 8.626761e+07 116 146 -2.667534e+09 1.333767e+08 116 151 -2.682209e-07 1.341105e-08 116 152 -7.504762e+09 3.752381e+08 116 157 1.725352e+09 -8.626761e+07 116 158 -2.667534e+09 1.333767e+08 117 117 2.900850e+06 -1.450425e+05 117 123 -1.664422e+05 8.322112e+03 117 147 -3.626063e+05 1.813032e+04 117 153 -5.587704e+05 2.793852e+04 117 159 -3.626063e+05 1.813032e+04 118 118 3.561542e+08 -1.780771e+07 118 119 -1.164153e-10 5.820766e-12 118 120 -5.960464e-08 2.980232e-09 118 124 8.837909e+07 -4.418955e+06 118 125 -5.820766e-11 2.910383e-12 118 144 1.582687e+08 -7.913437e+06 118 148 2.142603e+07 -1.071302e+06 118 149 3.594484e+05 -1.797242e+04 118 150 6.330749e+08 -3.165375e+07 118 154 8.636358e+07 -4.318179e+06 118 155 5.820766e-11 -2.910383e-12 118 156 1.582687e+08 -7.913437e+06 118 160 2.142603e+07 -1.071302e+06 118 161 -3.594484e+05 1.797242e+04 119 119 3.554513e+08 -1.777256e+07 119 120 5.275624e+08 -2.637812e+07 119 124 -5.820766e-11 2.910383e-12 119 125 8.700520e+07 -4.350260e+06 119 144 -1.318906e+08 6.594531e+06 119 148 3.594484e+05 -1.797242e+04 119 149 2.151390e+07 -1.075695e+06 119 150 -4.470348e-08 2.235174e-09 119 154 5.820766e-11 -2.910383e-12 119 155 8.791320e+07 -4.395660e+06 119 156 1.318906e+08 -6.594531e+06 119 160 -3.594484e+05 1.797242e+04 119 161 2.151390e+07 -1.075695e+06 120 120 1.029802e+10 -5.149009e+08 120 124 1.788139e-07 -8.940697e-09 120 125 -8.940697e-08 4.470348e-09 120 126 -5.908699e+08 2.954350e+07 120 130 -1.490116e-07 7.450581e-09 120 131 -5.275624e+08 2.637812e+07 120 150 -1.287252e+09 6.436262e+07 120 154 -1.582687e+08 7.913437e+06 120 155 1.318906e+08 -6.594531e+06 120 156 -1.983635e+09 9.918174e+07 120 160 -6.330749e+08 3.165375e+07 120 161 1.490116e-08 -7.450581e-10 120 162 -1.287252e+09 6.436262e+07 120 166 -1.582687e+08 7.913437e+06 120 167 -1.318906e+08 6.594531e+06 121 121 1.796625e+10 -8.983125e+08 121 122 -7.152557e-07 3.576279e-08 121 127 -4.424986e+09 2.212493e+08 121 128 5.960464e-07 -2.980232e-08 121 151 -2.245781e+09 1.122891e+08 121 152 -1.725352e+09 8.626761e+07 121 157 -6.657689e+07 3.328845e+06 121 158 -2.682209e-07 1.341105e-08 121 163 -2.245781e+09 1.122891e+08 121 164 1.725352e+09 -8.626761e+07 122 122 2.134027e+10 -1.067014e+09 122 127 5.960464e-07 -2.980232e-08 122 128 2.169693e+09 -1.084847e+08 122 151 -1.725352e+09 8.626761e+07 122 152 -2.667534e+09 1.333767e+08 122 157 -3.874302e-07 1.937151e-08 122 158 -7.504762e+09 3.752381e+08 122 163 1.725352e+09 -8.626761e+07 122 164 -2.667534e+09 1.333767e+08 123 123 2.900850e+06 -1.450425e+05 123 129 -1.664422e+05 8.322112e+03 123 153 -3.626063e+05 1.813032e+04 123 159 -5.587704e+05 2.793852e+04 123 165 -3.626063e+05 1.813032e+04 124 124 3.561542e+08 -1.780771e+07 124 125 5.820766e-11 -2.910383e-12 124 126 -2.980232e-08 1.490116e-09 124 130 8.837909e+07 -4.418955e+06 124 131 -1.018634e-10 5.093170e-12 124 150 1.582687e+08 -7.913437e+06 124 154 2.142603e+07 -1.071302e+06 124 155 3.594484e+05 -1.797242e+04 124 156 6.330749e+08 -3.165375e+07 124 160 8.636358e+07 -4.318179e+06 124 161 9.458745e-11 -4.729372e-12 124 162 1.582687e+08 -7.913437e+06 124 166 2.142603e+07 -1.071302e+06 124 167 -3.594484e+05 1.797242e+04 125 125 3.554513e+08 -1.777256e+07 125 126 5.275624e+08 -2.637812e+07 125 130 -8.731149e-11 4.365575e-12 125 131 8.700520e+07 -4.350260e+06 125 150 -1.318906e+08 6.594531e+06 125 154 3.594484e+05 -1.797242e+04 125 155 2.151390e+07 -1.075695e+06 125 156 -4.470348e-08 2.235174e-09 125 160 6.548362e-11 -3.274181e-12 125 161 8.791320e+07 -4.395660e+06 125 162 1.318906e+08 -6.594531e+06 125 166 -3.594484e+05 1.797242e+04 125 167 2.151390e+07 -1.075695e+06 144 144 5.149009e+09 -2.574505e+08 144 148 0.000000e+00 -0.000000e+00 144 149 -5.275624e+08 2.637812e+07 144 150 -5.908699e+08 2.954350e+07 144 154 0.000000e+00 -0.000000e+00 144 155 -5.275624e+08 2.637812e+07 144 180 -9.918174e+08 4.959087e+07 144 184 -3.165375e+08 1.582687e+07 144 185 -1.318906e+08 6.594531e+06 144 186 -1.287252e+09 6.436262e+07 144 190 -1.582687e+08 7.913437e+06 144 191 -1.318906e+08 6.594531e+06 145 145 8.983125e+09 -4.491563e+08 145 146 2.384186e-07 -1.192093e-08 145 151 -4.424986e+09 2.212493e+08 145 152 1.192093e-07 -5.960464e-09 145 181 -3.328845e+07 1.664422e+06 145 182 -1.738727e+08 8.693635e+06 145 187 -2.245781e+09 1.122891e+08 145 188 1.725352e+09 -8.626761e+07 146 146 1.067014e+10 -5.335068e+08 146 151 2.384186e-07 -1.192093e-08 146 152 2.169693e+09 -1.084847e+08 146 181 1.738727e+08 -8.693635e+06 146 182 -3.752381e+09 1.876190e+08 146 187 1.725352e+09 -8.626761e+07 146 188 -2.667534e+09 1.333767e+08 147 147 1.450425e+06 -7.252126e+04 147 153 -1.664422e+05 8.322112e+03 147 183 -2.793852e+05 1.396926e+04 147 189 -3.626063e+05 1.813032e+04 148 148 1.780771e+08 -8.903855e+06 148 149 5.820766e-11 -2.910383e-12 148 150 0.000000e+00 -0.000000e+00 148 154 8.837909e+07 -4.418955e+06 148 155 0.000000e+00 -0.000000e+00 148 180 3.165375e+08 -1.582687e+07 148 184 4.318179e+07 -2.159090e+06 148 185 -3.622348e+04 1.811174e+03 148 186 1.582687e+08 -7.913437e+06 148 190 2.142603e+07 -1.071302e+06 148 191 -3.594484e+05 1.797242e+04 149 149 1.777256e+08 -8.886282e+06 149 150 5.275624e+08 -2.637812e+07 149 154 1.455192e-11 -7.275958e-13 149 155 8.700520e+07 -4.350260e+06 149 180 -1.318906e+08 6.594531e+06 149 184 3.622348e+04 -1.811174e+03 149 185 4.395660e+07 -2.197830e+06 149 186 1.318906e+08 -6.594531e+06 149 190 -3.594484e+05 1.797242e+04 149 191 2.151390e+07 -1.075695e+06 150 150 1.029802e+10 -5.149009e+08 150 154 1.192093e-07 -5.960464e-09 150 155 -8.940697e-08 4.470348e-09 150 156 -5.908699e+08 2.954350e+07 150 160 -1.192093e-07 5.960464e-09 150 161 -5.275624e+08 2.637812e+07 150 180 -1.287252e+09 6.436262e+07 150 184 -1.582687e+08 7.913437e+06 150 185 1.318906e+08 -6.594531e+06 150 186 -1.983635e+09 9.918174e+07 150 190 -6.330749e+08 3.165375e+07 150 191 -4.470348e-08 2.235174e-09 150 192 -1.287252e+09 6.436262e+07 150 196 -1.582687e+08 7.913437e+06 150 197 -1.318906e+08 6.594531e+06 151 151 1.796625e+10 -8.983125e+08 151 152 0.000000e+00 -0.000000e+00 151 157 -4.424986e+09 2.212493e+08 151 158 3.874302e-07 -1.937151e-08 151 181 -2.245781e+09 1.122891e+08 151 182 -1.725352e+09 8.626761e+07 151 187 -6.657689e+07 3.328845e+06 151 188 8.940697e-08 -4.470348e-09 151 193 -2.245781e+09 1.122891e+08 151 194 1.725352e+09 -8.626761e+07 152 152 2.134027e+10 -1.067014e+09 152 157 2.980232e-07 -1.490116e-08 152 158 2.169693e+09 -1.084847e+08 152 181 -1.725352e+09 8.626761e+07 152 182 -2.667534e+09 1.333767e+08 152 187 8.940697e-08 -4.470348e-09 152 188 -7.504762e+09 3.752381e+08 152 193 1.725352e+09 -8.626761e+07 152 194 -2.667534e+09 1.333767e+08 153 153 2.900850e+06 -1.450425e+05 153 159 -1.664422e+05 8.322112e+03 153 183 -3.626063e+05 1.813032e+04 153 189 -5.587704e+05 2.793852e+04 153 195 -3.626063e+05 1.813032e+04 154 154 3.561542e+08 -1.780771e+07 154 155 5.820766e-11 -2.910383e-12 154 156 -2.980232e-08 1.490116e-09 154 160 8.837909e+07 -4.418955e+06 154 161 -8.003553e-11 4.001777e-12 154 180 1.582687e+08 -7.913437e+06 154 184 2.142603e+07 -1.071302e+06 154 185 3.594484e+05 -1.797242e+04 154 186 6.330749e+08 -3.165375e+07 154 190 8.636358e+07 -4.318179e+06 154 191 1.455192e-11 -7.275958e-13 154 192 1.582687e+08 -7.913437e+06 154 196 2.142603e+07 -1.071302e+06 154 197 -3.594484e+05 1.797242e+04 155 155 3.554513e+08 -1.777256e+07 155 156 5.275624e+08 -2.637812e+07 155 160 7.275958e-12 -3.637979e-13 155 161 8.700520e+07 -4.350260e+06 155 180 -1.318906e+08 6.594531e+06 155 184 3.594484e+05 -1.797242e+04 155 185 2.151390e+07 -1.075695e+06 155 186 -1.490116e-08 7.450581e-10 155 190 0.000000e+00 -0.000000e+00 155 191 8.791320e+07 -4.395660e+06 155 192 1.318906e+08 -6.594531e+06 155 196 -3.594484e+05 1.797242e+04 155 197 2.151390e+07 -1.075695e+06 156 156 1.029802e+10 -5.149009e+08 156 160 1.788139e-07 -8.940697e-09 156 161 -8.940697e-08 4.470348e-09 156 162 -5.908699e+08 2.954350e+07 156 166 -1.192093e-07 5.960464e-09 156 167 -5.275624e+08 2.637812e+07 156 186 -1.287252e+09 6.436262e+07 156 190 -1.582687e+08 7.913437e+06 156 191 1.318906e+08 -6.594531e+06 156 192 -1.983635e+09 9.918174e+07 156 196 -6.330749e+08 3.165375e+07 156 197 -4.470348e-08 2.235174e-09 156 198 -1.287252e+09 6.436262e+07 156 202 -1.582687e+08 7.913437e+06 156 203 -1.318906e+08 6.594531e+06 157 157 1.796625e+10 -8.983125e+08 157 158 0.000000e+00 -0.000000e+00 157 163 -4.424986e+09 2.212493e+08 157 164 5.662441e-07 -2.831221e-08 157 187 -2.245781e+09 1.122891e+08 157 188 -1.725352e+09 8.626761e+07 157 193 -6.657689e+07 3.328845e+06 157 194 5.960464e-08 -2.980232e-09 157 199 -2.245781e+09 1.122891e+08 157 200 1.725352e+09 -8.626761e+07 158 158 2.134027e+10 -1.067014e+09 158 163 5.662441e-07 -2.831221e-08 158 164 2.169693e+09 -1.084847e+08 158 187 -1.725352e+09 8.626761e+07 158 188 -2.667534e+09 1.333767e+08 158 193 -1.788139e-07 8.940697e-09 158 194 -7.504762e+09 3.752381e+08 158 199 1.725352e+09 -8.626761e+07 158 200 -2.667534e+09 1.333767e+08 159 159 2.900850e+06 -1.450425e+05 159 165 -1.664422e+05 8.322112e+03 159 189 -3.626063e+05 1.813032e+04 159 195 -5.587704e+05 2.793852e+04 159 201 -3.626063e+05 1.813032e+04 160 160 3.561542e+08 -1.780771e+07 160 161 1.746230e-10 -8.731149e-12 160 162 -2.980232e-08 1.490116e-09 160 166 8.837909e+07 -4.418955e+06 160 167 -1.309672e-10 6.548362e-12 160 186 1.582687e+08 -7.913437e+06 160 190 2.142603e+07 -1.071302e+06 160 191 3.594484e+05 -1.797242e+04 160 192 6.330749e+08 -3.165375e+07 160 196 8.636358e+07 -4.318179e+06 160 197 8.003553e-11 -4.001777e-12 160 198 1.582687e+08 -7.913437e+06 160 202 2.142603e+07 -1.071302e+06 160 203 -3.594484e+05 1.797242e+04 161 161 3.554513e+08 -1.777256e+07 161 162 5.275624e+08 -2.637812e+07 161 166 -8.003553e-11 4.001777e-12 161 167 8.700520e+07 -4.350260e+06 161 186 -1.318906e+08 6.594531e+06 161 190 3.594484e+05 -1.797242e+04 161 191 2.151390e+07 -1.075695e+06 161 192 -1.490116e-08 7.450581e-10 161 196 3.637979e-11 -1.818989e-12 161 197 8.791320e+07 -4.395660e+06 161 198 1.318906e+08 -6.594531e+06 161 202 -3.594484e+05 1.797242e+04 161 203 2.151390e+07 -1.075695e+06 0 0 -3.252857e+09 0.000000e+00 0 6 -1.626429e+09 0.000000e+00 0 12 -1.626429e+09 0.000000e+00 0 18 -8.132143e+08 0.000000e+00 1 1 -3.252857e+09 0.000000e+00 1 2 -2.547374e-23 0.000000e+00 1 7 -1.626429e+09 0.000000e+00 1 8 -6.744929e-24 0.000000e+00 1 13 -1.626429e+09 0.000000e+00 1 14 4.167065e-24 -0.000000e+00 1 19 -8.132143e+08 0.000000e+00 2 2 -3.252857e+09 0.000000e+00 2 7 6.744929e-24 -0.000000e+00 2 8 -1.626429e+09 0.000000e+00 2 13 -4.167065e-24 0.000000e+00 2 14 -1.626429e+09 0.000000e+00 2 20 -8.132143e+08 0.000000e+00 4 4 -6.776786e+05 0.000000e+00 4 10 -3.388393e+05 0.000000e+00 4 16 -3.388393e+05 0.000000e+00 4 22 -1.694196e+05 0.000000e+00 5 5 -6.776786e+05 0.000000e+00 5 11 -3.388393e+05 0.000000e+00 5 17 -3.388393e+05 0.000000e+00 5 23 -1.694196e+05 0.000000e+00 6 6 -6.505714e+09 0.000000e+00 6 12 -8.132143e+08 0.000000e+00 6 18 -3.252857e+09 0.000000e+00 6 24 -1.626429e+09 0.000000e+00 6 30 -8.132143e+08 0.000000e+00 7 7 -6.505714e+09 0.000000e+00 7 8 -5.094747e-23 0.000000e+00 7 13 -8.132143e+08 0.000000e+00 7 19 -3.252857e+09 0.000000e+00 7 20 8.334131e-24 -0.000000e+00 7 25 -1.626429e+09 0.000000e+00 7 26 -6.744929e-24 0.000000e+00 7 31 -8.132143e+08 0.000000e+00 8 8 -6.505714e+09 0.000000e+00 8 14 -8.132143e+08 0.000000e+00 8 19 -8.334131e-24 0.000000e+00 8 20 -3.252857e+09 0.000000e+00 8 25 6.744929e-24 -0.000000e+00 8 26 -1.626429e+09 0.000000e+00 8 32 -8.132143e+08 0.000000e+00 10 10 -1.355357e+06 0.000000e+00 10 16 -1.694196e+05 0.000000e+00 10 22 -6.776786e+05 0.000000e+00 10 28 -3.388393e+05 0.000000e+00 10 34 -1.694196e+05 0.000000e+00 11 11 -1.355357e+06 0.000000e+00 11 17 -1.694196e+05 0.000000e+00 11 23 -6.776786e+05 0.000000e+00 11 29 -3.388393e+05 0.000000e+00 11 35 -1.694196e+05 0.000000e+00 12 12 -6.505714e+09 0.000000e+00 12 18 -3.252857e+09 0.000000e+00 12 72 -1.626429e+09 0.000000e+00 12 78 -8.132143e+08 0.000000e+00 13 13 -6.505714e+09 0.000000e+00 13 14 -1.864002e-23 0.000000e+00 13 19 -3.252857e+09 0.000000e+00 13 73 -1.626429e+09 0.000000e+00 13 74 6.636939e-24 -0.000000e+00 13 79 -8.132143e+08 0.000000e+00 14 14 -6.505714e+09 0.000000e+00 14 20 -3.252857e+09 0.000000e+00 14 73 -6.636939e-24 0.000000e+00 14 74 -1.626429e+09 0.000000e+00 14 80 -8.132143e+08 0.000000e+00 16 16 -1.355357e+06 0.000000e+00 16 22 -6.776786e+05 0.000000e+00 16 76 -3.388393e+05 0.000000e+00 16 82 -1.694196e+05 0.000000e+00 17 17 -1.355357e+06 0.000000e+00 17 23 -6.776786e+05 0.000000e+00 17 77 -3.388393e+05 0.000000e+00 17 83 -1.694196e+05 0.000000e+00 18 18 -1.301143e+10 0.000000e+00 18 24 -8.132143e+08 0.000000e+00 18 30 -3.252857e+09 0.000000e+00 18 72 -8.132143e+08 0.000000e+00 18 78 -3.252857e+09 0.000000e+00 18 84 -8.132143e+08 0.000000e+00 19 19 -1.301143e+10 0.000000e+00 19 20 -3.728003e-23 0.000000e+00 19 25 -8.132143e+08 0.000000e+00 19 31 -3.252857e+09 0.000000e+00 19 73 -8.132143e+08 0.000000e+00 19 79 -3.252857e+09 0.000000e+00 19 80 1.327388e-23 -0.000000e+00 19 85 -8.132143e+08 0.000000e+00 20 20 -1.301143e+10 0.000000e+00 20 26 -8.132143e+08 0.000000e+00 20 32 -3.252857e+09 0.000000e+00 20 74 -8.132143e+08 0.000000e+00 20 79 -1.327388e-23 0.000000e+00 20 80 -3.252857e+09 0.000000e+00 20 86 -8.132143e+08 0.000000e+00 22 22 -2.710714e+06 0.000000e+00 22 28 -1.694196e+05 0.000000e+00 22 34 -6.776786e+05 0.000000e+00 22 76 -1.694196e+05 0.000000e+00 22 82 -6.776786e+05 0.000000e+00 22 88 -1.694196e+05 0.000000e+00 23 23 -2.710714e+06 0.000000e+00 23 29 -1.694196e+05 0.000000e+00 23 35 -6.776786e+05 0.000000e+00 23 77 -1.694196e+05 0.000000e+00 23 83 -6.776786e+05 0.000000e+00 23 89 -1.694196e+05 0.000000e+00 24 24 -6.505714e+09 0.000000e+00 24 30 -3.252857e+09 0.000000e+00 24 36 -1.626429e+09 0.000000e+00 24 42 -8.132143e+08 0.000000e+00 25 25 -6.505714e+09 0.000000e+00 25 26 -5.094747e-23 0.000000e+00 25 31 -3.252857e+09 0.000000e+00 25 32 8.334131e-24 -0.000000e+00 25 37 -1.626429e+09 0.000000e+00 25 38 -6.744929e-24 0.000000e+00 25 43 -8.132143e+08 0.000000e+00 26 26 -6.505714e+09 0.000000e+00 26 31 -8.334131e-24 0.000000e+00 26 32 -3.252857e+09 0.000000e+00 26 37 6.744929e-24 -0.000000e+00 26 38 -1.626429e+09 0.000000e+00 26 44 -8.132143e+08 0.000000e+00 28 28 -1.355357e+06 0.000000e+00 28 34 -6.776786e+05 0.000000e+00 28 40 -3.388393e+05 0.000000e+00 28 46 -1.694196e+05 0.000000e+00 29 29 -1.355357e+06 0.000000e+00 29 35 -6.776786e+05 0.000000e+00 29 41 -3.388393e+05 0.000000e+00 29 47 -1.694196e+05 0.000000e+00 30 30 -1.301143e+10 0.000000e+00 30 36 -8.132143e+08 0.000000e+00 30 42 -3.252857e+09 0.000000e+00 30 78 -8.132143e+08 0.000000e+00 30 84 -3.252857e+09 0.000000e+00 30 90 -8.132143e+08 0.000000e+00 31 31 -1.301143e+10 0.000000e+00 31 32 -3.728003e-23 0.000000e+00 31 37 -8.132143e+08 0.000000e+00 31 43 -3.252857e+09 0.000000e+00 31 79 -8.132143e+08 0.000000e+00 31 85 -3.252857e+09 0.000000e+00 31 86 1.327388e-23 -0.000000e+00 31 91 -8.132143e+08 0.000000e+00 32 32 -1.301143e+10 0.000000e+00 32 38 -8.132143e+08 0.000000e+00 32 44 -3.252857e+09 0.000000e+00 32 80 -8.132143e+08 0.000000e+00 32 85 -1.327388e-23 0.000000e+00 32 86 -3.252857e+09 0.000000e+00 32 92 -8.132143e+08 0.000000e+00 34 34 -2.710714e+06 0.000000e+00 34 40 -1.694196e+05 0.000000e+00 34 46 -6.776786e+05 0.000000e+00 34 82 -1.694196e+05 0.000000e+00 34 88 -6.776786e+05 0.000000e+00 34 94 -1.694196e+05 0.000000e+00 35 35 -2.710714e+06 0.000000e+00 35 41 -1.694196e+05 0.000000e+00 35 47 -6.776786e+05 0.000000e+00 35 83 -1.694196e+05 0.000000e+00 35 89 -6.776786e+05 0.000000e+00 35 95 -1.694196e+05 0.000000e+00 72 72 -6.505714e+09 0.000000e+00 72 78 -3.252857e+09 0.000000e+00 72 108 -1.626429e+09 0.000000e+00 72 114 -8.132143e+08 0.000000e+00 73 73 -6.505714e+09 0.000000e+00 73 74 1.050743e-23 -0.000000e+00 73 79 -3.252857e+09 0.000000e+00 73 109 -1.626429e+09 0.000000e+00 73 115 -8.132143e+08 0.000000e+00 74 74 -6.505714e+09 0.000000e+00 74 80 -3.252857e+09 0.000000e+00 74 110 -1.626429e+09 0.000000e+00 74 116 -8.132143e+08 0.000000e+00 76 76 -1.355357e+06 0.000000e+00 76 82 -6.776786e+05 0.000000e+00 76 112 -3.388393e+05 0.000000e+00 76 118 -1.694196e+05 0.000000e+00 77 77 -1.355357e+06 0.000000e+00 77 83 -6.776786e+05 0.000000e+00 77 113 -3.388393e+05 0.000000e+00 77 119 -1.694196e+05 0.000000e+00 78 78 -1.301143e+10 0.000000e+00 78 84 -3.252857e+09 0.000000e+00 78 108 -8.132143e+08 0.000000e+00 78 114 -3.252857e+09 0.000000e+00 78 120 -8.132143e+08 0.000000e+00 79 79 -1.301143e+10 0.000000e+00 79 80 2.101486e-23 -0.000000e+00 79 85 -3.252857e+09 0.000000e+00 79 109 -8.132143e+08 0.000000e+00 79 115 -3.252857e+09 0.000000e+00 79 121 -8.132143e+08 0.000000e+00 80 80 -1.301143e+10 0.000000e+00 80 86 -3.252857e+09 0.000000e+00 80 110 -8.132143e+08 0.000000e+00 80 116 -3.252857e+09 0.000000e+00 80 122 -8.132143e+08 0.000000e+00 82 82 -2.710714e+06 0.000000e+00 82 88 -6.776786e+05 0.000000e+00 82 112 -1.694196e+05 0.000000e+00 82 118 -6.776786e+05 0.000000e+00 82 124 -1.694196e+05 0.000000e+00 83 83 -2.710714e+06 0.000000e+00 83 89 -6.776786e+05 0.000000e+00 83 113 -1.694196e+05 0.000000e+00 83 119 -6.776786e+05 0.000000e+00 83 125 -1.694196e+05 0.000000e+00 84 84 -1.301143e+10 0.000000e+00 84 90 -3.252857e+09 0.000000e+00 84 114 -8.132143e+08 0.000000e+00 84 120 -3.252857e+09 0.000000e+00 84 126 -8.132143e+08 0.000000e+00 85 85 -1.301143e+10 0.000000e+00 85 86 2.101486e-23 -0.000000e+00 85 91 -3.252857e+09 0.000000e+00 85 115 -8.132143e+08 0.000000e+00 85 121 -3.252857e+09 0.000000e+00 85 127 -8.132143e+08 0.000000e+00 86 86 -1.301143e+10 0.000000e+00 86 92 -3.252857e+09 0.000000e+00 86 116 -8.132143e+08 0.000000e+00 86 122 -3.252857e+09 0.000000e+00 86 128 -8.132143e+08 0.000000e+00 88 88 -2.710714e+06 0.000000e+00 88 94 -6.776786e+05 0.000000e+00 88 118 -1.694196e+05 0.000000e+00 88 124 -6.776786e+05 0.000000e+00 88 130 -1.694196e+05 0.000000e+00 89 89 -2.710714e+06 0.000000e+00 89 95 -6.776786e+05 0.000000e+00 89 119 -1.694196e+05 0.000000e+00 89 125 -6.776786e+05 0.000000e+00 89 131 -1.694196e+05 0.000000e+00 108 108 -6.505714e+09 0.000000e+00 108 114 -3.252857e+09 0.000000e+00 108 144 -1.626429e+09 0.000000e+00 108 150 -8.132143e+08 0.000000e+00 109 109 -6.505714e+09 0.000000e+00 109 110 -8.122739e-24 0.000000e+00 109 115 -3.252857e+09 0.000000e+00 109 145 -1.626429e+09 0.000000e+00 109 146 -6.306821e-24 0.000000e+00 109 151 -8.132143e+08 0.000000e+00 110 110 -6.505714e+09 0.000000e+00 110 116 -3.252857e+09 0.000000e+00 110 145 6.306821e-24 -0.000000e+00 110 146 -1.626429e+09 0.000000e+00 110 152 -8.132143e+08 0.000000e+00 112 112 -1.355357e+06 0.000000e+00 112 118 -6.776786e+05 0.000000e+00 112 148 -3.388393e+05 0.000000e+00 112 154 -1.694196e+05 0.000000e+00 113 113 -1.355357e+06 0.000000e+00 113 119 -6.776786e+05 0.000000e+00 113 149 -3.388393e+05 0.000000e+00 113 155 -1.694196e+05 0.000000e+00 114 114 -1.301143e+10 0.000000e+00 114 120 -3.252857e+09 0.000000e+00 114 144 -8.132143e+08 0.000000e+00 114 150 -3.252857e+09 0.000000e+00 114 156 -8.132143e+08 0.000000e+00 115 115 -1.301143e+10 0.000000e+00 115 116 -1.624548e-23 0.000000e+00 115 121 -3.252857e+09 0.000000e+00 115 145 -8.132143e+08 0.000000e+00 115 151 -3.252857e+09 0.000000e+00 115 152 -1.261364e-23 0.000000e+00 115 157 -8.132143e+08 0.000000e+00 116 116 -1.301143e+10 0.000000e+00 116 122 -3.252857e+09 0.000000e+00 116 146 -8.132143e+08 0.000000e+00 116 151 1.261364e-23 -0.000000e+00 116 152 -3.252857e+09 0.000000e+00 116 158 -8.132143e+08 0.000000e+00 118 118 -2.710714e+06 0.000000e+00 118 124 -6.776786e+05 0.000000e+00 118 148 -1.694196e+05 0.000000e+00 118 154 -6.776786e+05 0.000000e+00 118 160 -1.694196e+05 0.000000e+00 119 119 -2.710714e+06 0.000000e+00 119 125 -6.776786e+05 0.000000e+00 119 149 -1.694196e+05 0.000000e+00 119 155 -6.776786e+05 0.000000e+00 119 161 -1.694196e+05 0.000000e+00 120 120 -1.301143e+10 0.000000e+00 120 126 -3.252857e+09 0.000000e+00 120 150 -8.132143e+08 0.000000e+00 120 156 -3.252857e+09 0.000000e+00 120 162 -8.132143e+08 0.000000e+00 121 121 -1.301143e+10 0.000000e+00 121 122 -1.624548e-23 0.000000e+00 121 127 -3.252857e+09 0.000000e+00 121 151 -8.132143e+08 0.000000e+00 121 157 -3.252857e+09 0.000000e+00 121 158 -1.261364e-23 0.000000e+00 121 163 -8.132143e+08 0.000000e+00 122 122 -1.301143e+10 0.000000e+00 122 128 -3.252857e+09 0.000000e+00 122 152 -8.132143e+08 0.000000e+00 122 157 1.261364e-23 -0.000000e+00 122 158 -3.252857e+09 0.000000e+00 122 164 -8.132143e+08 0.000000e+00 124 124 -2.710714e+06 0.000000e+00 124 130 -6.776786e+05 0.000000e+00 124 154 -1.694196e+05 0.000000e+00 124 160 -6.776786e+05 0.000000e+00 124 166 -1.694196e+05 0.000000e+00 125 125 -2.710714e+06 0.000000e+00 125 131 -6.776786e+05 0.000000e+00 125 155 -1.694196e+05 0.000000e+00 125 161 -6.776786e+05 0.000000e+00 125 167 -1.694196e+05 0.000000e+00 144 144 -6.505714e+09 0.000000e+00 144 150 -3.252857e+09 0.000000e+00 144 180 -1.626429e+09 0.000000e+00 144 186 -8.132143e+08 0.000000e+00 145 145 -6.505714e+09 0.000000e+00 145 146 -1.635507e-23 0.000000e+00 145 151 -3.252857e+09 0.000000e+00 145 181 -1.626429e+09 0.000000e+00 145 187 -8.132143e+08 0.000000e+00 146 146 -6.505714e+09 0.000000e+00 146 152 -3.252857e+09 0.000000e+00 146 182 -1.626429e+09 0.000000e+00 146 188 -8.132143e+08 0.000000e+00 148 148 -1.355357e+06 0.000000e+00 148 154 -6.776786e+05 0.000000e+00 148 184 -3.388393e+05 0.000000e+00 148 190 -1.694196e+05 0.000000e+00 149 149 -1.355357e+06 0.000000e+00 149 155 -6.776786e+05 0.000000e+00 149 185 -3.388393e+05 0.000000e+00 149 191 -1.694196e+05 0.000000e+00 150 150 -1.301143e+10 0.000000e+00 150 156 -3.252857e+09 0.000000e+00 150 180 -8.132143e+08 0.000000e+00 150 186 -3.252857e+09 0.000000e+00 150 192 -8.132143e+08 0.000000e+00 151 151 -1.301143e+10 0.000000e+00 151 152 -3.271014e-23 0.000000e+00 151 157 -3.252857e+09 0.000000e+00 151 181 -8.132143e+08 0.000000e+00 151 187 -3.252857e+09 0.000000e+00 151 193 -8.132143e+08 0.000000e+00 152 152 -1.301143e+10 0.000000e+00 152 158 -3.252857e+09 0.000000e+00 152 182 -8.132143e+08 0.000000e+00 152 188 -3.252857e+09 0.000000e+00 152 194 -8.132143e+08 0.000000e+00 154 154 -2.710714e+06 0.000000e+00 154 160 -6.776786e+05 0.000000e+00 154 184 -1.694196e+05 0.000000e+00 154 190 -6.776786e+05 0.000000e+00 154 196 -1.694196e+05 0.000000e+00 155 155 -2.710714e+06 0.000000e+00 155 161 -6.776786e+05 0.000000e+00 155 185 -1.694196e+05 0.000000e+00 155 191 -6.776786e+05 0.000000e+00 155 197 -1.694196e+05 0.000000e+00 156 156 -1.301143e+10 0.000000e+00 156 162 -3.252857e+09 0.000000e+00 156 186 -8.132143e+08 0.000000e+00 156 192 -3.252857e+09 0.000000e+00 156 198 -8.132143e+08 0.000000e+00 157 157 -1.301143e+10 0.000000e+00 157 158 -3.271014e-23 0.000000e+00 157 163 -3.252857e+09 0.000000e+00 157 187 -8.132143e+08 0.000000e+00 157 193 -3.252857e+09 0.000000e+00 157 199 -8.132143e+08 0.000000e+00 158 158 -1.301143e+10 0.000000e+00 158 164 -3.252857e+09 0.000000e+00 158 188 -8.132143e+08 0.000000e+00 158 194 -3.252857e+09 0.000000e+00 158 200 -8.132143e+08 0.000000e+00 160 160 -2.710714e+06 0.000000e+00 160 166 -6.776786e+05 0.000000e+00 160 190 -1.694196e+05 0.000000e+00 160 196 -6.776786e+05 0.000000e+00 160 202 -1.694196e+05 0.000000e+00 161 161 -2.710714e+06 0.000000e+00 161 167 -6.776786e+05 0.000000e+00 161 191 -1.694196e+05 0.000000e+00 161 197 -6.776786e+05 0.000000e+00 161 203 -1.694196e+05 0.000000e+00 0 22 82 -6.776786e+05 0.000000e+00 22 88 -1.694196e+05 0.000000e+00 23 23 -2.710714e+06 0.000000e+00 23 29 -1.694196e+05 0.000000e+00 23 35 -6.776786e+05 0.000000e+00 23 77 -1.694196e+05 0.000000e+00 23 83 -6.776786e+05 0.000000e+00 23 89 -1.694196e+05 0.000000e+00 24 24 -6.505714e+09 0.000000e+00 24 30 -3.252857e+09 0.000000e+00 24 36 -1.626429e+09 0.000000e+00 24 42 -8.132143e+08 0.000000e+00MPI/drivers/haggar.mtx.3.input010064400020550007177000000663230665164054300175010ustar00clevecompmath00000400000006252 252 803 36 36 5.149009e+09 -2.574505e+08 36 40 -6.330749e+08 3.165375e+07 36 41 2.980232e-08 -1.490116e-09 36 42 -1.983635e+09 9.918174e+07 36 46 -6.330749e+08 3.165375e+07 36 47 4.470348e-08 -2.235174e-09 36 48 -2.954350e+08 1.477175e+07 36 52 -1.582687e+08 7.913437e+06 36 53 -2.637812e+08 1.318906e+07 36 54 -1.287252e+09 6.436262e+07 36 58 -1.582687e+08 7.913437e+06 36 59 -1.318906e+08 6.594531e+06 37 37 8.983125e+09 -4.491563e+08 37 38 4.768372e-07 -2.384186e-08 37 43 -6.657689e+07 3.328845e+06 37 44 -8.642673e-07 4.321337e-08 37 49 -2.212493e+09 1.106246e+08 37 50 1.738727e+08 -8.693635e+06 37 55 -2.245781e+09 1.122891e+08 37 56 1.725352e+09 -8.626761e+07 38 38 1.067014e+10 -5.335068e+08 38 43 -8.046627e-07 4.023314e-08 38 44 -7.504762e+09 3.752381e+08 38 49 -1.738727e+08 8.693635e+06 38 50 1.084847e+09 -5.424234e+07 38 55 1.725352e+09 -8.626761e+07 38 56 -2.667534e+09 1.333767e+08 39 39 1.450425e+06 -7.252126e+04 39 45 -5.587704e+05 2.793852e+04 39 51 -8.322112e+04 4.161056e+03 39 57 -3.626063e+05 1.813032e+04 40 40 1.780771e+08 -8.903855e+06 40 41 -1.164153e-10 5.820766e-12 40 42 6.330749e+08 -3.165375e+07 40 46 8.636358e+07 -4.318179e+06 40 47 1.673470e-10 -8.367351e-12 40 48 -1.582687e+08 7.913437e+06 40 52 4.418955e+07 -2.209477e+06 40 53 3.622348e+04 -1.811174e+03 40 54 1.582687e+08 -7.913437e+06 40 58 2.142603e+07 -1.071302e+06 40 59 -3.594484e+05 1.797242e+04 41 41 1.777256e+08 -8.886282e+06 41 42 -8.940697e-08 4.470348e-09 41 46 1.382432e-10 -6.912160e-12 41 47 8.791320e+07 -4.395660e+06 41 48 2.637812e+08 -1.318906e+07 41 52 -3.622348e+04 1.811174e+03 41 53 4.350260e+07 -2.175130e+06 41 54 1.318906e+08 -6.594531e+06 41 58 -3.594484e+05 1.797242e+04 41 59 2.151390e+07 -1.075695e+06 42 42 1.029802e+10 -5.149009e+08 42 46 2.384186e-07 -1.192093e-08 42 47 -5.960464e-08 2.980232e-09 42 48 -1.287252e+09 6.436262e+07 42 52 1.582687e+08 -7.913437e+06 42 53 -1.318906e+08 6.594531e+06 42 54 -5.908699e+08 2.954350e+07 42 58 2.980232e-08 -1.490116e-09 42 59 -5.275624e+08 2.637812e+07 42 84 -1.287252e+09 6.436262e+07 42 88 -1.582687e+08 7.913437e+06 42 89 1.318906e+08 -6.594531e+06 42 90 -1.983635e+09 9.918174e+07 42 94 -6.330749e+08 3.165375e+07 42 95 1.490116e-08 -7.450581e-10 42 96 -1.287252e+09 6.436262e+07 42 100 -1.582687e+08 7.913437e+06 42 101 -1.318906e+08 6.594531e+06 43 43 1.796625e+10 -8.983125e+08 43 44 2.384186e-07 -1.192093e-08 43 49 -2.245781e+09 1.122891e+08 43 50 -1.725352e+09 8.626761e+07 43 55 -4.424986e+09 2.212493e+08 43 56 -1.788139e-07 8.940697e-09 43 85 -2.245781e+09 1.122891e+08 43 86 -1.725352e+09 8.626761e+07 43 91 -6.657689e+07 3.328845e+06 43 92 5.960464e-08 -2.980232e-09 43 97 -2.245781e+09 1.122891e+08 43 98 1.725352e+09 -8.626761e+07 44 44 2.134027e+10 -1.067014e+09 44 49 -1.725352e+09 8.626761e+07 44 50 -2.667534e+09 1.333767e+08 44 55 -2.086163e-07 1.043081e-08 44 56 2.169693e+09 -1.084847e+08 44 85 -1.725352e+09 8.626761e+07 44 86 -2.667534e+09 1.333767e+08 44 91 -1.490116e-07 7.450581e-09 44 92 -7.504762e+09 3.752381e+08 44 97 1.725352e+09 -8.626761e+07 44 98 -2.667534e+09 1.333767e+08 45 45 2.900850e+06 -1.450425e+05 45 51 -3.626063e+05 1.813032e+04 45 57 -1.664422e+05 8.322112e+03 45 87 -3.626063e+05 1.813032e+04 45 93 -5.587704e+05 2.793852e+04 45 99 -3.626063e+05 1.813032e+04 46 46 3.561542e+08 -1.780771e+07 46 47 0.000000e+00 -0.000000e+00 46 48 -1.582687e+08 7.913437e+06 46 52 2.142603e+07 -1.071302e+06 46 53 3.594484e+05 -1.797242e+04 46 54 -8.940697e-08 4.470348e-09 46 58 8.837909e+07 -4.418955e+06 46 59 2.182787e-11 -1.091394e-12 46 84 1.582687e+08 -7.913437e+06 46 88 2.142603e+07 -1.071302e+06 46 89 3.594484e+05 -1.797242e+04 46 90 6.330749e+08 -3.165375e+07 46 94 8.636358e+07 -4.318179e+06 46 95 5.820766e-11 -2.910383e-12 46 96 1.582687e+08 -7.913437e+06 46 100 2.142603e+07 -1.071302e+06 46 101 -3.594484e+05 1.797242e+04 47 47 3.554513e+08 -1.777256e+07 47 48 1.318906e+08 -6.594531e+06 47 52 3.594484e+05 -1.797242e+04 47 53 2.151390e+07 -1.075695e+06 47 54 5.275624e+08 -2.637812e+07 47 58 4.365575e-11 -2.182787e-12 47 59 8.700520e+07 -4.350260e+06 47 84 -1.318906e+08 6.594531e+06 47 88 3.594484e+05 -1.797242e+04 47 89 2.151390e+07 -1.075695e+06 47 90 -1.490116e-08 7.450581e-10 47 94 -7.275958e-12 3.637979e-13 47 95 8.791320e+07 -4.395660e+06 47 96 1.318906e+08 -6.594531e+06 47 100 -3.594484e+05 1.797242e+04 47 101 2.151390e+07 -1.075695e+06 48 48 5.149009e+09 -2.574505e+08 48 52 -6.330749e+08 3.165375e+07 48 53 2.980232e-08 -1.490116e-09 48 54 -1.983635e+09 9.918174e+07 48 58 -6.330749e+08 3.165375e+07 48 59 4.470348e-08 -2.235174e-09 48 60 -2.954350e+08 1.477175e+07 48 64 -1.582687e+08 7.913437e+06 48 65 -2.637812e+08 1.318906e+07 48 66 -1.287252e+09 6.436262e+07 48 70 -1.582687e+08 7.913437e+06 48 71 -1.318906e+08 6.594531e+06 49 49 8.983125e+09 -4.491563e+08 49 50 9.536743e-07 -4.768372e-08 49 55 -6.657689e+07 3.328845e+06 49 56 -5.662441e-07 2.831221e-08 49 61 -2.212493e+09 1.106246e+08 49 62 1.738727e+08 -8.693635e+06 49 67 -2.245781e+09 1.122891e+08 49 68 1.725352e+09 -8.626761e+07 50 50 1.067014e+10 -5.335068e+08 50 55 -5.364418e-07 2.682209e-08 50 56 -7.504762e+09 3.752381e+08 50 61 -1.738727e+08 8.693635e+06 50 62 1.084847e+09 -5.424234e+07 50 67 1.725352e+09 -8.626761e+07 50 68 -2.667534e+09 1.333767e+08 51 51 1.450425e+06 -7.252126e+04 51 57 -5.587704e+05 2.793852e+04 51 63 -8.322112e+04 4.161056e+03 51 69 -3.626063e+05 1.813032e+04 52 52 1.780771e+08 -8.903855e+06 52 53 -2.328306e-10 1.164153e-11 52 54 6.330749e+08 -3.165375e+07 52 58 8.636358e+07 -4.318179e+06 52 59 1.018634e-10 -5.093170e-12 52 60 -1.582687e+08 7.913437e+06 52 64 4.418955e+07 -2.209477e+06 52 65 3.622348e+04 -1.811174e+03 52 66 1.582687e+08 -7.913437e+06 52 70 2.142603e+07 -1.071302e+06 52 71 -3.594484e+05 1.797242e+04 53 53 1.777256e+08 -8.886282e+06 53 54 -8.940697e-08 4.470348e-09 53 58 9.458745e-11 -4.729372e-12 53 59 8.791320e+07 -4.395660e+06 53 60 2.637812e+08 -1.318906e+07 53 64 -3.622348e+04 1.811174e+03 53 65 4.350260e+07 -2.175130e+06 53 66 1.318906e+08 -6.594531e+06 53 70 -3.594484e+05 1.797242e+04 53 71 2.151390e+07 -1.075695e+06 54 54 1.029802e+10 -5.149009e+08 54 58 1.192093e-07 -5.960464e-09 54 59 -5.960464e-08 2.980232e-09 54 60 -1.287252e+09 6.436262e+07 54 64 1.582687e+08 -7.913437e+06 54 65 -1.318906e+08 6.594531e+06 54 66 -5.908699e+08 2.954350e+07 54 70 -5.960464e-08 2.980232e-09 54 71 -5.275624e+08 2.637812e+07 54 90 -1.287252e+09 6.436262e+07 54 94 -1.582687e+08 7.913437e+06 54 95 1.318906e+08 -6.594531e+06 54 96 -1.983635e+09 9.918174e+07 54 100 -6.330749e+08 3.165375e+07 54 101 1.490116e-08 -7.450581e-10 54 102 -1.287252e+09 6.436262e+07 54 106 -1.582687e+08 7.913437e+06 54 107 -1.318906e+08 6.594531e+06 55 55 1.796625e+10 -8.983125e+08 55 56 9.536743e-07 -4.768372e-08 55 61 -2.245781e+09 1.122891e+08 55 62 -1.725352e+09 8.626761e+07 55 67 -4.424986e+09 2.212493e+08 55 68 1.192093e-07 -5.960464e-09 55 91 -2.245781e+09 1.122891e+08 55 92 -1.725352e+09 8.626761e+07 55 97 -6.657689e+07 3.328845e+06 55 98 1.192093e-07 -5.960464e-09 55 103 -2.245781e+09 1.122891e+08 55 104 1.725352e+09 -8.626761e+07 56 56 2.134027e+10 -1.067014e+09 56 61 -1.725352e+09 8.626761e+07 56 62 -2.667534e+09 1.333767e+08 56 67 5.960464e-08 -2.980232e-09 56 68 2.169693e+09 -1.084847e+08 56 91 -1.725352e+09 8.626761e+07 56 92 -2.667534e+09 1.333767e+08 56 97 -8.940697e-08 4.470348e-09 56 98 -7.504762e+09 3.752381e+08 56 103 1.725352e+09 -8.626761e+07 56 104 -2.667534e+09 1.333767e+08 57 57 2.900850e+06 -1.450425e+05 57 63 -3.626063e+05 1.813032e+04 57 69 -1.664422e+05 8.322112e+03 57 93 -3.626063e+05 1.813032e+04 57 99 -5.587704e+05 2.793852e+04 57 105 -3.626063e+05 1.813032e+04 58 58 3.561542e+08 -1.780771e+07 58 59 -1.164153e-10 5.820766e-12 58 60 -1.582687e+08 7.913437e+06 58 64 2.142603e+07 -1.071302e+06 58 65 3.594484e+05 -1.797242e+04 58 66 -5.960464e-08 2.980232e-09 58 70 8.837909e+07 -4.418955e+06 58 71 -5.093170e-11 2.546585e-12 58 90 1.582687e+08 -7.913437e+06 58 94 2.142603e+07 -1.071302e+06 58 95 3.594484e+05 -1.797242e+04 58 96 6.330749e+08 -3.165375e+07 58 100 8.636358e+07 -4.318179e+06 58 101 0.000000e+00 -0.000000e+00 58 102 1.582687e+08 -7.913437e+06 58 106 2.142603e+07 -1.071302e+06 58 107 -3.594484e+05 1.797242e+04 59 59 3.554513e+08 -1.777256e+07 59 60 1.318906e+08 -6.594531e+06 59 64 3.594484e+05 -1.797242e+04 59 65 2.151390e+07 -1.075695e+06 59 66 5.275624e+08 -2.637812e+07 59 70 0.000000e+00 -0.000000e+00 59 71 8.700520e+07 -4.350260e+06 59 90 -1.318906e+08 6.594531e+06 59 94 3.594484e+05 -1.797242e+04 59 95 2.151390e+07 -1.075695e+06 59 96 -1.490116e-08 7.450581e-10 59 100 -2.182787e-11 1.091394e-12 59 101 8.791320e+07 -4.395660e+06 59 102 1.318906e+08 -6.594531e+06 59 106 -3.594484e+05 1.797242e+04 59 107 2.151390e+07 -1.075695e+06 60 60 2.574505e+09 -1.287252e+08 60 64 -3.165375e+08 1.582687e+07 60 65 2.637812e+08 -1.318906e+07 60 66 -9.918174e+08 4.959087e+07 60 70 -3.165375e+08 1.582687e+07 60 71 1.318906e+08 -6.594531e+06 61 61 4.491563e+09 -2.245781e+08 61 62 1.725352e+09 -8.626761e+07 61 67 -3.328845e+07 1.664422e+06 61 68 1.738727e+08 -8.693635e+06 62 62 5.335068e+09 -2.667534e+08 62 67 -1.738727e+08 8.693635e+06 62 68 -3.752381e+09 1.876190e+08 63 63 7.252126e+05 -3.626063e+04 63 69 -2.793852e+05 1.396926e+04 64 64 8.903855e+07 -4.451927e+06 64 65 -3.594484e+05 1.797242e+04 64 66 3.165375e+08 -1.582687e+07 64 70 4.318179e+07 -2.159090e+06 64 71 3.622348e+04 -1.811174e+03 65 65 8.886282e+07 -4.443141e+06 65 66 1.318906e+08 -6.594531e+06 65 70 -3.622348e+04 1.811174e+03 65 71 4.395660e+07 -2.197830e+06 66 66 5.149009e+09 -2.574505e+08 66 70 5.960464e-08 -2.980232e-09 66 71 5.275624e+08 -2.637812e+07 66 96 -1.287252e+09 6.436262e+07 66 100 -1.582687e+08 7.913437e+06 66 101 1.318906e+08 -6.594531e+06 66 102 -9.918174e+08 4.959087e+07 66 106 -3.165375e+08 1.582687e+07 66 107 1.318906e+08 -6.594531e+06 67 67 8.983125e+09 -4.491563e+08 67 68 4.768372e-07 -2.384186e-08 67 97 -2.245781e+09 1.122891e+08 67 98 -1.725352e+09 8.626761e+07 67 103 -3.328845e+07 1.664422e+06 67 104 1.738727e+08 -8.693635e+06 68 68 1.067014e+10 -5.335068e+08 68 97 -1.725352e+09 8.626761e+07 68 98 -2.667534e+09 1.333767e+08 68 103 -1.738727e+08 8.693635e+06 68 104 -3.752381e+09 1.876190e+08 69 69 1.450425e+06 -7.252126e+04 69 99 -3.626063e+05 1.813032e+04 69 105 -2.793852e+05 1.396926e+04 70 70 1.780771e+08 -8.903855e+06 70 71 -5.820766e-11 2.910383e-12 70 96 1.582687e+08 -7.913437e+06 70 100 2.142603e+07 -1.071302e+06 70 101 3.594484e+05 -1.797242e+04 70 102 3.165375e+08 -1.582687e+07 70 106 4.318179e+07 -2.159090e+06 70 107 3.622348e+04 -1.811174e+03 71 71 1.777256e+08 -8.886282e+06 71 96 -1.318906e+08 6.594531e+06 71 100 3.594484e+05 -1.797242e+04 71 101 2.151390e+07 -1.075695e+06 71 102 1.318906e+08 -6.594531e+06 71 106 -3.622348e+04 1.811174e+03 71 107 4.395660e+07 -2.197830e+06 90 90 1.029802e+10 -5.149009e+08 90 94 2.980232e-07 -1.490116e-08 90 95 -5.960464e-08 2.980232e-09 90 96 -5.908699e+08 2.954350e+07 90 100 2.980232e-08 -1.490116e-09 90 101 -5.275624e+08 2.637812e+07 90 120 -1.287252e+09 6.436262e+07 90 124 -1.582687e+08 7.913437e+06 90 125 1.318906e+08 -6.594531e+06 90 126 -1.983635e+09 9.918174e+07 90 130 -6.330749e+08 3.165375e+07 90 131 2.980232e-08 -1.490116e-09 90 132 -1.287252e+09 6.436262e+07 90 136 -1.582687e+08 7.913437e+06 90 137 -1.318906e+08 6.594531e+06 91 91 1.796625e+10 -8.983125e+08 91 92 -4.768372e-07 2.384186e-08 91 97 -4.424986e+09 2.212493e+08 91 98 -2.980232e-07 1.490116e-08 91 121 -2.245781e+09 1.122891e+08 91 122 -1.725352e+09 8.626761e+07 91 127 -6.657689e+07 3.328845e+06 91 128 -1.192093e-07 5.960464e-09 91 133 -2.245781e+09 1.122891e+08 91 134 1.725352e+09 -8.626761e+07 92 92 2.134027e+10 -1.067014e+09 92 97 -2.384186e-07 1.192093e-08 92 98 2.169693e+09 -1.084847e+08 92 121 -1.725352e+09 8.626761e+07 92 122 -2.667534e+09 1.333767e+08 92 127 1.192093e-07 -5.960464e-09 92 128 -7.504762e+09 3.752381e+08 92 133 1.725352e+09 -8.626761e+07 92 134 -2.667534e+09 1.333767e+08 93 93 2.900850e+06 -1.450425e+05 93 99 -1.664422e+05 8.322112e+03 93 123 -3.626063e+05 1.813032e+04 93 129 -5.587704e+05 2.793852e+04 93 135 -3.626063e+05 1.813032e+04 94 94 3.561542e+08 -1.780771e+07 94 95 -5.820766e-11 2.910383e-12 94 96 -8.940697e-08 4.470348e-09 94 100 8.837909e+07 -4.418955e+06 94 101 5.820766e-11 -2.910383e-12 94 120 1.582687e+08 -7.913437e+06 94 124 2.142603e+07 -1.071302e+06 94 125 3.594484e+05 -1.797242e+04 94 126 6.330749e+08 -3.165375e+07 94 130 8.636358e+07 -4.318179e+06 94 131 7.275958e-12 -3.637979e-13 94 132 1.582687e+08 -7.913437e+06 94 136 2.142603e+07 -1.071302e+06 94 137 -3.594484e+05 1.797242e+04 95 95 3.554513e+08 -1.777256e+07 95 96 5.275624e+08 -2.637812e+07 95 100 5.093170e-11 -2.546585e-12 95 101 8.700520e+07 -4.350260e+06 95 120 -1.318906e+08 6.594531e+06 95 124 3.594484e+05 -1.797242e+04 95 125 2.151390e+07 -1.075695e+06 95 126 -1.490116e-08 7.450581e-10 95 130 2.182787e-11 -1.091394e-12 95 131 8.791320e+07 -4.395660e+06 95 132 1.318906e+08 -6.594531e+06 95 136 -3.594484e+05 1.797242e+04 95 137 2.151390e+07 -1.075695e+06 96 96 1.029802e+10 -5.149009e+08 96 100 5.960464e-08 -2.980232e-09 96 101 -5.960464e-08 2.980232e-09 96 102 -5.908699e+08 2.954350e+07 96 106 -5.960464e-08 2.980232e-09 96 107 -5.275624e+08 2.637812e+07 96 126 -1.287252e+09 6.436262e+07 96 130 -1.582687e+08 7.913437e+06 96 131 1.318906e+08 -6.594531e+06 96 132 -1.983635e+09 9.918174e+07 96 136 -6.330749e+08 3.165375e+07 96 137 2.980232e-08 -1.490116e-09 96 138 -1.287252e+09 6.436262e+07 96 142 -1.582687e+08 7.913437e+06 96 143 -1.318906e+08 6.594531e+06 97 97 1.796625e+10 -8.983125e+08 97 98 -2.384186e-07 1.192093e-08 97 103 -4.424986e+09 2.212493e+08 97 104 -5.960464e-08 2.980232e-09 97 127 -2.245781e+09 1.122891e+08 97 128 -1.725352e+09 8.626761e+07 97 133 -6.657689e+07 3.328845e+06 97 134 -5.960464e-08 2.980232e-09 97 139 -2.245781e+09 1.122891e+08 97 140 1.725352e+09 -8.626761e+07 98 98 2.134027e+10 -1.067014e+09 98 103 0.000000e+00 -0.000000e+00 98 104 2.169693e+09 -1.084847e+08 98 127 -1.725352e+09 8.626761e+07 98 128 -2.667534e+09 1.333767e+08 98 133 2.384186e-07 -1.192093e-08 98 134 -7.504762e+09 3.752381e+08 98 139 1.725352e+09 -8.626761e+07 98 140 -2.667534e+09 1.333767e+08 99 99 2.900850e+06 -1.450425e+05 99 105 -1.664422e+05 8.322112e+03 99 129 -3.626063e+05 1.813032e+04 99 135 -5.587704e+05 2.793852e+04 99 141 -3.626063e+05 1.813032e+04 100 100 3.561542e+08 -1.780771e+07 100 101 -1.746230e-10 8.731149e-12 100 102 -5.960464e-08 2.980232e-09 100 106 8.837909e+07 -4.418955e+06 100 107 -7.275958e-12 3.637979e-13 100 126 1.582687e+08 -7.913437e+06 100 130 2.142603e+07 -1.071302e+06 100 131 3.594484e+05 -1.797242e+04 100 132 6.330749e+08 -3.165375e+07 100 136 8.636358e+07 -4.318179e+06 100 137 -4.365575e-11 2.182787e-12 100 138 1.582687e+08 -7.913437e+06 100 142 2.142603e+07 -1.071302e+06 100 143 -3.594484e+05 1.797242e+04 101 101 3.554513e+08 -1.777256e+07 101 102 5.275624e+08 -2.637812e+07 101 106 2.910383e-11 -1.455192e-12 101 107 8.700520e+07 -4.350260e+06 101 126 -1.318906e+08 6.594531e+06 101 130 3.594484e+05 -1.797242e+04 101 131 2.151390e+07 -1.075695e+06 101 132 -1.490116e-08 7.450581e-10 101 136 -2.182787e-11 1.091394e-12 101 137 8.791320e+07 -4.395660e+06 101 138 1.318906e+08 -6.594531e+06 101 142 -3.594484e+05 1.797242e+04 101 143 2.151390e+07 -1.075695e+06 102 102 5.149009e+09 -2.574505e+08 102 106 0.000000e+00 -0.000000e+00 102 107 5.275624e+08 -2.637812e+07 102 132 -1.287252e+09 6.436262e+07 102 136 -1.582687e+08 7.913437e+06 102 137 1.318906e+08 -6.594531e+06 102 138 -9.918174e+08 4.959087e+07 102 142 -3.165375e+08 1.582687e+07 102 143 1.318906e+08 -6.594531e+06 103 103 8.983125e+09 -4.491563e+08 103 104 -2.384186e-07 1.192093e-08 103 133 -2.245781e+09 1.122891e+08 103 134 -1.725352e+09 8.626761e+07 103 139 -3.328845e+07 1.664422e+06 103 140 1.738727e+08 -8.693635e+06 104 104 1.067014e+10 -5.335068e+08 104 133 -1.725352e+09 8.626761e+07 104 134 -2.667534e+09 1.333767e+08 104 139 -1.738727e+08 8.693635e+06 104 140 -3.752381e+09 1.876190e+08 105 105 1.450425e+06 -7.252126e+04 105 135 -3.626063e+05 1.813032e+04 105 141 -2.793852e+05 1.396926e+04 106 106 1.780771e+08 -8.903855e+06 106 107 -1.746230e-10 8.731149e-12 106 132 1.582687e+08 -7.913437e+06 106 136 2.142603e+07 -1.071302e+06 106 137 3.594484e+05 -1.797242e+04 106 138 3.165375e+08 -1.582687e+07 106 142 4.318179e+07 -2.159090e+06 106 143 3.622348e+04 -1.811174e+03 107 107 1.777256e+08 -8.886282e+06 107 132 -1.318906e+08 6.594531e+06 107 136 3.594484e+05 -1.797242e+04 107 137 2.151390e+07 -1.075695e+06 107 138 1.318906e+08 -6.594531e+06 107 142 -3.622348e+04 1.811174e+03 107 143 4.395660e+07 -2.197830e+06 126 126 1.029802e+10 -5.149009e+08 126 130 2.384186e-07 -1.192093e-08 126 131 -8.940697e-08 4.470348e-09 126 132 -5.908699e+08 2.954350e+07 126 136 2.980232e-08 -1.490116e-09 126 137 -5.275624e+08 2.637812e+07 126 156 -1.287252e+09 6.436262e+07 126 160 -1.582687e+08 7.913437e+06 126 161 1.318906e+08 -6.594531e+06 126 162 -1.983635e+09 9.918174e+07 126 166 -6.330749e+08 3.165375e+07 126 167 1.490116e-08 -7.450581e-10 126 168 -1.287252e+09 6.436262e+07 126 172 -1.582687e+08 7.913437e+06 126 173 -1.318906e+08 6.594531e+06 127 127 1.796625e+10 -8.983125e+08 127 128 -2.384186e-07 1.192093e-08 127 133 -4.424986e+09 2.212493e+08 127 134 -1.192093e-07 5.960464e-09 127 157 -2.245781e+09 1.122891e+08 127 158 -1.725352e+09 8.626761e+07 127 163 -6.657689e+07 3.328845e+06 127 164 -2.980232e-07 1.490116e-08 127 169 -2.245781e+09 1.122891e+08 127 170 1.725352e+09 -8.626761e+07 128 128 2.134027e+10 -1.067014e+09 128 133 -1.788139e-07 8.940697e-09 128 134 2.169693e+09 -1.084847e+08 128 157 -1.725352e+09 8.626761e+07 128 158 -2.667534e+09 1.333767e+08 128 163 -1.490116e-07 7.450581e-09 128 164 -7.504762e+09 3.752381e+08 128 169 1.725352e+09 -8.626761e+07 128 170 -2.667534e+09 1.333767e+08 129 129 2.900850e+06 -1.450425e+05 129 135 -1.664422e+05 8.322112e+03 129 159 -3.626063e+05 1.813032e+04 129 165 -5.587704e+05 2.793852e+04 129 171 -3.626063e+05 1.813032e+04 130 130 3.561542e+08 -1.780771e+07 130 131 -1.164153e-10 5.820766e-12 130 132 -8.940697e-08 4.470348e-09 130 136 8.837909e+07 -4.418955e+06 130 137 3.637979e-11 -1.818989e-12 130 156 1.582687e+08 -7.913437e+06 130 160 2.142603e+07 -1.071302e+06 130 161 3.594484e+05 -1.797242e+04 130 162 6.330749e+08 -3.165375e+07 130 166 8.636358e+07 -4.318179e+06 130 167 8.003553e-11 -4.001777e-12 130 168 1.582687e+08 -7.913437e+06 130 172 2.142603e+07 -1.071302e+06 130 173 -3.594484e+05 1.797242e+04 131 131 3.554513e+08 -1.777256e+07 131 132 5.275624e+08 -2.637812e+07 131 136 7.275958e-11 -3.637979e-12 131 137 8.700520e+07 -4.350260e+06 131 156 -1.318906e+08 6.594531e+06 131 160 3.594484e+05 -1.797242e+04 131 161 2.151390e+07 -1.075695e+06 131 162 -4.470348e-08 2.235174e-09 131 166 3.637979e-11 -1.818989e-12 131 167 8.791320e+07 -4.395660e+06 131 168 1.318906e+08 -6.594531e+06 131 172 -3.594484e+05 1.797242e+04 131 173 2.151390e+07 -1.075695e+06 36 36 -6.505714e+09 0.000000e+00 36 42 -3.252857e+09 0.000000e+00 36 48 -1.626429e+09 0.000000e+00 36 54 -8.132143e+08 0.000000e+00 37 37 -6.505714e+09 0.000000e+00 37 38 -5.094747e-23 0.000000e+00 37 43 -3.252857e+09 0.000000e+00 37 44 8.334131e-24 -0.000000e+00 37 49 -1.626429e+09 0.000000e+00 37 50 -6.744929e-24 0.000000e+00 37 55 -8.132143e+08 0.000000e+00 38 38 -6.505714e+09 0.000000e+00 38 43 -8.334131e-24 0.000000e+00 38 44 -3.252857e+09 0.000000e+00 38 49 6.744929e-24 -0.000000e+00 38 50 -1.626429e+09 0.000000e+00 38 56 -8.132143e+08 0.000000e+00 40 40 -1.355357e+06 0.000000e+00 40 46 -6.776786e+05 0.000000e+00 40 52 -3.388393e+05 0.000000e+00 40 58 -1.694196e+05 0.000000e+00 41 41 -1.355357e+06 0.000000e+00 41 47 -6.776786e+05 0.000000e+00 41 53 -3.388393e+05 0.000000e+00 41 59 -1.694196e+05 0.000000e+00 42 42 -1.301143e+10 0.000000e+00 42 48 -8.132143e+08 0.000000e+00 42 54 -3.252857e+09 0.000000e+00 42 84 -8.132143e+08 0.000000e+00 42 90 -3.252857e+09 0.000000e+00 42 96 -8.132143e+08 0.000000e+00 43 43 -1.301143e+10 0.000000e+00 43 44 -3.728003e-23 0.000000e+00 43 49 -8.132143e+08 0.000000e+00 43 55 -3.252857e+09 0.000000e+00 43 85 -8.132143e+08 0.000000e+00 43 91 -3.252857e+09 0.000000e+00 43 92 1.327388e-23 -0.000000e+00 43 97 -8.132143e+08 0.000000e+00 44 44 -1.301143e+10 0.000000e+00 44 50 -8.132143e+08 0.000000e+00 44 56 -3.252857e+09 0.000000e+00 44 86 -8.132143e+08 0.000000e+00 44 91 -1.327388e-23 0.000000e+00 44 92 -3.252857e+09 0.000000e+00 44 98 -8.132143e+08 0.000000e+00 46 46 -2.710714e+06 0.000000e+00 46 52 -1.694196e+05 0.000000e+00 46 58 -6.776786e+05 0.000000e+00 46 88 -1.694196e+05 0.000000e+00 46 94 -6.776786e+05 0.000000e+00 46 100 -1.694196e+05 0.000000e+00 47 47 -2.710714e+06 0.000000e+00 47 53 -1.694196e+05 0.000000e+00 47 59 -6.776786e+05 0.000000e+00 47 89 -1.694196e+05 0.000000e+00 47 95 -6.776786e+05 0.000000e+00 47 101 -1.694196e+05 0.000000e+00 48 48 -6.505714e+09 0.000000e+00 48 54 -3.252857e+09 0.000000e+00 48 60 -1.626429e+09 0.000000e+00 48 66 -8.132143e+08 0.000000e+00 49 49 -6.505714e+09 0.000000e+00 49 50 -5.080446e-23 0.000000e+00 49 55 -3.252857e+09 0.000000e+00 49 56 4.167065e-24 -0.000000e+00 49 61 -1.626429e+09 0.000000e+00 49 62 -6.675074e-24 0.000000e+00 49 67 -8.132143e+08 0.000000e+00 50 50 -6.505714e+09 0.000000e+00 50 55 -4.167065e-24 0.000000e+00 50 56 -3.252857e+09 0.000000e+00 50 61 6.675074e-24 -0.000000e+00 50 62 -1.626429e+09 0.000000e+00 50 68 -8.132143e+08 0.000000e+00 52 52 -1.355357e+06 0.000000e+00 52 58 -6.776786e+05 0.000000e+00 52 64 -3.388393e+05 0.000000e+00 52 70 -1.694196e+05 0.000000e+00 53 53 -1.355357e+06 0.000000e+00 53 59 -6.776786e+05 0.000000e+00 53 65 -3.388393e+05 0.000000e+00 53 71 -1.694196e+05 0.000000e+00 54 54 -1.301143e+10 0.000000e+00 54 60 -8.132143e+08 0.000000e+00 54 66 -3.252857e+09 0.000000e+00 54 90 -8.132143e+08 0.000000e+00 54 96 -3.252857e+09 0.000000e+00 54 102 -8.132143e+08 0.000000e+00 55 55 -1.301143e+10 0.000000e+00 55 56 -3.621390e-23 0.000000e+00 55 61 -8.132143e+08 0.000000e+00 55 67 -3.252857e+09 0.000000e+00 55 91 -8.132143e+08 0.000000e+00 55 97 -3.252857e+09 0.000000e+00 55 98 1.245219e-23 -0.000000e+00 55 103 -8.132143e+08 0.000000e+00 56 56 -1.301143e+10 0.000000e+00 56 62 -8.132143e+08 0.000000e+00 56 68 -3.252857e+09 0.000000e+00 56 92 -8.132143e+08 0.000000e+00 56 97 -1.245219e-23 0.000000e+00 56 98 -3.252857e+09 0.000000e+00 56 104 -8.132143e+08 0.000000e+00 58 58 -2.710714e+06 0.000000e+00 58 64 -1.694196e+05 0.000000e+00 58 70 -6.776786e+05 0.000000e+00 58 94 -1.694196e+05 0.000000e+00 58 100 -6.776786e+05 0.000000e+00 58 106 -1.694196e+05 0.000000e+00 59 59 -2.710714e+06 0.000000e+00 59 65 -1.694196e+05 0.000000e+00 59 71 -6.776786e+05 0.000000e+00 59 95 -1.694196e+05 0.000000e+00 59 101 -6.776786e+05 0.000000e+00 59 107 -1.694196e+05 0.000000e+00 60 60 -3.252857e+09 0.000000e+00 60 66 -1.626429e+09 0.000000e+00 61 61 -3.252857e+09 0.000000e+00 61 62 -2.533073e-23 0.000000e+00 61 67 -1.626429e+09 0.000000e+00 62 62 -3.252857e+09 0.000000e+00 62 68 -1.626429e+09 0.000000e+00 64 64 -6.776786e+05 0.000000e+00 64 70 -3.388393e+05 0.000000e+00 65 65 -6.776786e+05 0.000000e+00 65 71 -3.388393e+05 0.000000e+00 66 66 -6.505714e+09 0.000000e+00 66 96 -8.132143e+08 0.000000e+00 66 102 -1.626429e+09 0.000000e+00 67 67 -6.505714e+09 0.000000e+00 67 68 -1.757388e-23 0.000000e+00 67 97 -8.132143e+08 0.000000e+00 67 103 -1.626429e+09 0.000000e+00 67 104 5.815252e-24 -0.000000e+00 68 68 -6.505714e+09 0.000000e+00 68 98 -8.132143e+08 0.000000e+00 68 103 -5.815252e-24 0.000000e+00 68 104 -1.626429e+09 0.000000e+00 70 70 -1.355357e+06 0.000000e+00 70 100 -1.694196e+05 0.000000e+00 70 106 -3.388393e+05 0.000000e+00 71 71 -1.355357e+06 0.000000e+00 71 101 -1.694196e+05 0.000000e+00 71 107 -3.388393e+05 0.000000e+00 90 90 -1.301143e+10 0.000000e+00 90 96 -3.252857e+09 0.000000e+00 90 120 -8.132143e+08 0.000000e+00 90 126 -3.252857e+09 0.000000e+00 90 132 -8.132143e+08 0.000000e+00 91 91 -1.301143e+10 0.000000e+00 91 92 2.101486e-23 -0.000000e+00 91 97 -3.252857e+09 0.000000e+00 91 121 -8.132143e+08 0.000000e+00 91 127 -3.252857e+09 0.000000e+00 91 133 -8.132143e+08 0.000000e+00 92 92 -1.301143e+10 0.000000e+00 92 98 -3.252857e+09 0.000000e+00 92 122 -8.132143e+08 0.000000e+00 92 128 -3.252857e+09 0.000000e+00 92 134 -8.132143e+08 0.000000e+00 94 94 -2.710714e+06 0.000000e+00 94 100 -6.776786e+05 0.000000e+00 94 124 -1.694196e+05 0.000000e+00 94 130 -6.776786e+05 0.000000e+00 94 136 -1.694196e+05 0.000000e+00 95 95 -2.710714e+06 0.000000e+00 95 101 -6.776786e+05 0.000000e+00 95 125 -1.694196e+05 0.000000e+00 95 131 -6.776786e+05 0.000000e+00 95 137 -1.694196e+05 0.000000e+00 96 96 -1.301143e+10 0.000000e+00 96 102 -3.252857e+09 0.000000e+00 96 126 -8.132143e+08 0.000000e+00 96 132 -3.252857e+09 0.000000e+00 96 138 -8.132143e+08 0.000000e+00 97 97 -1.301143e+10 0.000000e+00 97 98 1.995563e-23 -0.000000e+00 97 103 -3.252857e+09 0.000000e+00 97 127 -8.132143e+08 0.000000e+00 97 133 -3.252857e+09 0.000000e+00 97 139 -8.132143e+08 0.000000e+00 98 98 -1.301143e+10 0.000000e+00 98 104 -3.252857e+09 0.000000e+00 98 128 -8.132143e+08 0.000000e+00 98 134 -3.252857e+09 0.000000e+00 98 140 -8.132143e+08 0.000000e+00 100 100 -2.710714e+06 0.000000e+00 100 106 -6.776786e+05 0.000000e+00 100 130 -1.694196e+05 0.000000e+00 100 136 -6.776786e+05 0.000000e+00 100 142 -1.694196e+05 0.000000e+00 101 101 -2.710714e+06 0.000000e+00 101 107 -6.776786e+05 0.000000e+00 101 131 -1.694196e+05 0.000000e+00 101 137 -6.776786e+05 0.000000e+00 101 143 -1.694196e+05 0.000000e+00 102 102 -6.505714e+09 0.000000e+00 102 132 -8.132143e+08 0.000000e+00 102 138 -1.626429e+09 0.000000e+00 103 103 -6.505714e+09 0.000000e+00 103 104 9.448202e-24 -0.000000e+00 103 133 -8.132143e+08 0.000000e+00 103 139 -1.626429e+09 0.000000e+00 104 104 -6.505714e+09 0.000000e+00 104 134 -8.132143e+08 0.000000e+00 104 140 -1.626429e+09 0.000000e+00 106 106 -1.355357e+06 0.000000e+00 106 136 -1.694196e+05 0.000000e+00 106 142 -3.388393e+05 0.000000e+00 107 107 -1.355357e+06 0.000000e+00 107 137 -1.694196e+05 0.000000e+00 107 143 -3.388393e+05 0.000000e+00 126 126 -1.301143e+10 0.000000e+00 126 132 -3.252857e+09 0.000000e+00 126 156 -8.132143e+08 0.000000e+00 126 162 -3.252857e+09 0.000000e+00 126 168 -8.132143e+08 0.000000e+00 127 127 -1.301143e+10 0.000000e+00 127 128 -1.624548e-23 0.000000e+00 127 133 -3.252857e+09 0.000000e+00 127 157 -8.132143e+08 0.000000e+00 127 163 -3.252857e+09 0.000000e+00 127 164 -1.261364e-23 0.000000e+00 127 169 -8.132143e+08 0.000000e+00 128 128 -1.301143e+10 0.000000e+00 128 134 -3.252857e+09 0.000000e+00 128 158 -8.132143e+08 0.000000e+00 128 163 1.261364e-23 -0.000000e+00 128 164 -3.252857e+09 0.000000e+00 128 170 -8.132143e+08 0.000000e+00 130 130 -2.710714e+06 0.000000e+00 130 136 -6.776786e+05 0.000000e+00 130 160 -1.694196e+05 0.000000e+00 130 166 -6.776786e+05 0.000000e+00 130 172 -1.694196e+05 0.000000e+00 131 131 -2.710714e+06 0.000000e+00 131 137 -6.776786e+05 0.000000e+00 131 161 -1.694196e+05 0.000000e+00 131 167 -6.776786e+05 0.000000e+00 131 173 -1.694196e+05 0.000000e+00 7e+08 7.913437e+06 126 173 -1.318906e+08 6.594531e+06 127 127 1.796625e+10 -8.983125e+08 127 128 -2.384186e-07 1.192093e-08 127 133 -4.424986e+09 2.212493e+08 127 134 -1.192093e-07 5.960464e-09 127 157 -2.245781e+09 1.122891e+08 127 158 -1.725352e+09 8.626761e+07 127 163 -6.657689e+07 3.32884MPI/drivers/haggar.rhs.0.input010064400020550007177000000045300665164055000174500ustar00clevecompmath00000400000006249 1 3 1 1 4 1 1 5 1 1 6 1 1 7 1 1 8 1 1 9 1 1 10 1 1 11 1 1 12 1 1 13 1 1 14 1 1 15 1 1 16 1 1 17 1 1 18 1 1 19 1 1 20 1 1 21 1 1 22 1 1 23 1 1 24 1 1 25 1 1 26 1 1 27 1 1 28 1 1 29 1 1 30 1 1 31 1 1 32 1 1 33 1 1 34 1 1 35 1 1 36 1 1 37 1 1 38 1 1 39 1 1 40 1 1 41 1 1 42 1 1 43 1 1 44 1 1 45 1 1 46 1 1 47 1 1 48 1 1 49 1 1 50 1 1 51 1 1 52 1 1 53 1 1 54 1 1 55 1 1 56 1 1 57 1 1 58 1 1 59 1 1 60 1 1 61 1 1 62 1 1 63 1 1 64 1 1 65 1 1 66 1 1 67 1 1 68 1 1 69 1 1 70 1 1 71 1 1 72 1 1 73 1 1 74 1 1 75 1 1 76 1 1 77 1 1 78 1 1 79 1 1 80 1 1 81 1 1 82 1 1 83 1 1 84 1 1 85 1 1 86 1 1 87 1 1 88 1 1 89 1 1 90 1 1 91 1 1 92 1 1 93 1 1 94 1 1 95 1 1 96 1 1 97 1 1 98 1 1 99 1 1 100 1 1 101 1 1 102 1 1 103 1 1 104 1 1 105 1 1 106 1 1 107 1 1 108 1 1 109 1 1 110 1 1 111 1 1 112 1 1 113 1 1 114 1 1 115 1 1 116 1 1 117 1 1 118 1 1 119 1 1 120 1 1 121 1 1 122 1 1 123 1 1 124 1 1 125 1 1 126 1 1 127 1 1 128 1 1 129 1 1 130 1 1 131 1 1 132 1 1 133 1 1 134 1 1 135 1 1 136 1 1 137 1 1 138 1 1 139 1 1 140 1 1 141 1 1 142 1 1 143 1 1 144 1 1 145 1 1 146 1 1 147 1 1 148 1 1 149 1 1 150 1 1 151 1 1 152 1 1 153 1 1 154 1 1 155 1 1 156 1 1 157 1 1 158 1 1 159 1 1 160 1 1 161 1 1 162 1 1 163 1 1 164 1 1 165 1 1 166 1 1 167 1 1 168 1 1 169 1 1 170 1 1 171 1 1 172 1 1 173 1 1 174 1 1 175 1 1 176 1 1 177 1 1 178 1 1 179 1 1 180 1 1 181 1 1 182 1 1 183 1 1 184 1 1 185 1 1 186 1 1 187 1 1 188 1 1 189 1 1 190 1 1 191 1 1 192 1 1 193 1 1 194 1 1 195 1 1 196 1 1 197 1 1 198 1 1 199 1 1 200 1 1 201 1 1 202 1 1 203 1 1 204 1 1 205 1 1 206 1 1 207 1 1 208 1 1 209 1 1 210 1 1 211 1 1 212 1 1 213 1 1 214 1 1 215 1 1 216 1 1 217 1 1 218 1 1 219 1 1 220 1 1 221 1 1 222 1 1 223 1 1 224 1 1 225 1 1 226 1 1 227 1 1 228 1 1 229 1 1 230 1 1 231 1 1 232 1 1 233 1 1 234 1 1 235 1 1 236 1 1 237 1 1 238 1 1 239 1 1 240 1 1 241 1 1 242 1 1 243 1 1 244 1 1 245 1 1 246 1 1 247 1 1 248 1 1 249 1 1 250 1 1 251 1 1 MPI/drivers/haggar.rhs.1.input010064400020550007177000000000130665164055400174450ustar00clevecompmath000004000000061 1 0 1 1 MPI/drivers/haggar.rhs.2.input010064400020550007177000000000140665164055700174520ustar00clevecompmath000004000000061 1 1 1 1 MPI/drivers/haggar.rhs.3.input010064400020550007177000000000130665164056400174500ustar00clevecompmath000004000000061 1 2 1 1 MPI/drivers/matrix.0.input010064400020550007177000000000760660022615200167210ustar00clevecompmath000004000000069 9 6 0 0 4.0 0 1 -1.0 0 3 -1.0 1 1 4.0 1 2 -1.0 1 4 -1.0 MPI/drivers/matrix.1.input010064400020550007177000000000640660022616500167230ustar00clevecompmath000004000000069 9 5 2 2 4.0 2 5 -1.0 3 3 4.0 3 4 -1.0 3 6 -1.0 MPI/drivers/matrix.2.input010064400020550007177000000001060660026257200167230ustar00clevecompmath000004000000069 9 7 4 4 4.0 4 5 -1.0 4 7 -1.0 5 5 4.0 5 8 -1.0 6 6 4.0 6 7 -1.0 MPI/drivers/matrix.3.input010064400020550007177000000000420660026260000167130ustar00clevecompmath000004000000069 9 3 7 7 4.0 7 8 -1.0 8 8 4.0 MPI/drivers/patchMatrix.0.input010064400020550007177000000004350657406775200177230ustar00clevecompmath00000400000006 13 13 6 0 0 1.7453333536783853E+08 0 3 -1.7453333536783853E+08 1 1 7.1828074095507547E+07 1 2 4.8483950014467597E+08 1 4 4.8483950014467597E+08 2 2 4.3635555013020830E+09 MPI/drivers/patchMatrix.1.input010064400020550007177000000005100657406777100177170ustar00clevecompmath00000400000006 13 13 7 2 4 2.1817777506510420E+09 3 3 2.5440452273956126E+08 3 10 -7.9871187371722728E+07 4 4 6.3604368324064264E+09 4 11 -1.0153633886971237E+08 4 12 9.9844066555217147E+08 5 5 2.5440452273956126E+08 MPI/drivers/patchMatrix.2.input010064400020550007177000000005100657407000200176750ustar00clevecompmath00000400000006 13 13 7 5 7 -1.7453333536783853E+08 5 10 -7.9871187371722728E+07 6 6 6.3604368324064264E+09 6 8 -4.8483950014467597E+08 6 9 2.1817777506510420E+09 6 11 1.0153633886971237E+08 6 12 9.9844066555217147E+08 MPI/drivers/patchMatrix.3.input010064400020550007177000000005100657407001300177000ustar00clevecompmath00000400000006 13 13 7 7 7 1.7453333536783853E+08 8 8 7.1828074095507547E+07 8 9 -4.8483950014467597E+08 9 9 4.3635555013020830E+09 10 10 1.5974237474344546E+08 11 11 1.3767639168774558E+07 12 12 3.9937626622086864E+09 MPI/drivers/patchMatrix.input010064400020550007177000000022450657406766600175720ustar00clevecompmath00000400000006 13 13 27 0 0 1.7453333536783853E+08 0 3 -1.7453333536783853E+08 1 1 7.1828074095507547E+07 1 2 4.8483950014467597E+08 1 4 4.8483950014467597E+08 2 2 4.3635555013020830E+09 2 4 2.1817777506510420E+09 3 3 2.5440452273956126E+08 3 10 -7.9871187371722728E+07 4 4 6.3604368324064264E+09 4 11 -1.0153633886971237E+08 4 12 9.9844066555217147E+08 5 5 2.5440452273956126E+08 5 7 -1.7453333536783853E+08 5 10 -7.9871187371722728E+07 6 6 6.3604368324064264E+09 6 8 -4.8483950014467597E+08 6 9 2.1817777506510420E+09 6 11 1.0153633886971237E+08 6 12 9.9844066555217147E+08 7 7 1.7453333536783853E+08 8 8 7.1828074095507547E+07 8 9 -4.8483950014467597E+08 9 9 4.3635555013020830E+09 10 10 1.5974237474344546E+08 11 11 1.3767639168774558E+07 12 12 3.9937626622086864E+09 MPI/drivers/patchRhs.0.input010064400020550007177000000002320657407016500171760ustar00clevecompmath00000400000006 4 1 0 .0000000000000000E+00 1 -2.6000000000000000E+04 2 .0000000000000000E+00 3 .0000000000000000E+00 MPI/drivers/patchRhs.1.input010064400020550007177000000001700657407020100171670ustar00clevecompmath00000400000006 3 1 4 .0000000000000000E+00 5 .0000000000000000E+00 6 .0000000000000000E+00 MPI/drivers/patchRhs.2.input010064400020550007177000000001700657407020700171760ustar00clevecompmath00000400000006 3 1 7 .0000000000000000E+00 8 -2.6000000000000000E+04 9 .0000000000000000E+00 MPI/drivers/patchRhs.3.input010064400020550007177000000001700657407021400171750ustar00clevecompmath00000400000006 3 1 10 .0000000000000000E+00 11 .0000000000000000E+00 12 .0000000000000000E+00 MPI/drivers/patchRhs.input010064400020550007177000000007150657407006400170440ustar00clevecompmath00000400000006 13 1 0 .0000000000000000E+00 1 -2.6000000000000000E+04 2 .0000000000000000E+00 3 .0000000000000000E+00 4 .0000000000000000E+00 5 .0000000000000000E+00 6 .0000000000000000E+00 7 .0000000000000000E+00 8 -2.6000000000000000E+04 9 .0000000000000000E+00 10 .0000000000000000E+00 11 .0000000000000000E+00 12 .0000000000000000E+00 MPI/drivers/rhs.0.input010064400020550007177000000000210660026266200162050ustar00clevecompmath000004000000062 1 0 0.0 1 0.0 MPI/drivers/rhs.1.input010064400020550007177000000000210660026267000162050ustar00clevecompmath000004000000062 1 2 0.0 3 0.0 MPI/drivers/rhs.2.input010064400020550007177000000000230655671743300162240ustar00clevecompmath000004000000062 1 4 1.0 5 0.0 MPI/drivers/rhs.3.input010064400020550007177000000000320655671743300162250ustar00clevecompmath000004000000063 1 6 0.0 7 0.0 8 0.0 MPI/drivers/Graph_Bcast4.pg010064400020550007177000000004200663700433300167650ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testGraph_Bcast chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testGraph_Bcast chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testGraph_Bcast chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testGraph_Bcast MPI/drivers/IVL_Bcast4.pg010064400020550007177000000004100663700434000163530ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_Bcast chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_Bcast chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_Bcast chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_Bcast MPI/drivers/IVL_allgather2.pg010064400020550007177000000002120663700434400172640ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather MPI/drivers/IVL_allgather4.pg010064400020550007177000000004240663700435200172720ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather MPI/drivers/IVL_allgather8.pg010064400020550007177000000010500663700436000172710ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVLallgather MPI/drivers/IVL_alltoall2.pg010064400020550007177000000002120663700436400171270ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall MPI/drivers/IVL_alltoall4.pg010064400020550007177000000004240663700437000171330ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall MPI/drivers/IVL_alltoall8.pg010064400020550007177000000010500663700437600171410ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVL_alltoall MPI/drivers/IV_allgather2.pg010064400020550007177000000002100663700440400171430ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather MPI/drivers/IV_allgather4.pg010064400020550007177000000004200663700441000171450ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather MPI/drivers/IV_allgather8.pg010064400020550007177000000010400663700441400171540ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testIVallgather MPI/drivers/MMM2.pg010064400020550007177000000001700663700442200152350ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testMMM chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testMMM MPI/drivers/MMM4.pg010064400020550007177000000003600663700443100152400ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testMMM chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testMMM chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testMMM chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testMMM MPI/drivers/allInOneMPI.2.pg010064400020550007177000000002010663700443500167330ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/allInOneMPI chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/allInOneMPI MPI/drivers/allInOneMPI.4.pg010064400020550007177000000004010663700444000167330ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/allInOneMPI chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/allInOneMPI chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/allInOneMPI chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/allInOneMPI MPI/drivers/gather2.pg010064400020550007177000000001760663700444400160730ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testGather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testGather MPI/drivers/gather4.pg010064400020550007177000000003740663700445100160730ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testGather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testGather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testGather chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testGather MPI/drivers/gridMPI2.pg010064400020550007177000000002000663700445400161010ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testGridMPI chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testGridMPI MPI/drivers/gridMPI4.pg010064400020550007177000000004000663700446200161040ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testGridMPI chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testGridMPI chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testGridMPI chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testGridMPI MPI/drivers/patchAndGo.4.pg010064400020550007177000000004110663700446500167040ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/patchAndGoMPI chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/patchAndGoMPI chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/patchAndGoMPI chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/patchAndGoMPI MPI/drivers/scatterDenseMtx4.pg010064400020550007177000000004400663700447200177330ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testScatterDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testScatterDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testScatterDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testScatterDenseMtx MPI/drivers/scatterInpMtx4.pg010064400020550007177000000004300663700447600174260ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testScatterInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testScatterInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testScatterInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testScatterInpMtx MPI/drivers/splitDenseMtx2.pg010064400020550007177000000002140663700450100174070ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx MPI/drivers/splitDenseMtx3.pg010064400020550007177000000003220663700450300174120ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx MPI/drivers/splitDenseMtx4.pg010064400020550007177000000004300663700450700174170ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx MPI/drivers/splitDenseMtx7.pg010064400020550007177000000007520663700451400174270ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitDenseMtx MPI/drivers/splitInpMtx2.pg010064400020550007177000000002100663700451700171020ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx MPI/drivers/splitInpMtx4.pg010064400020550007177000000004200663700452400171050ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx MPI/drivers/splitInpMtx7.pg010064400020550007177000000007340663700453000171150ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx MPI/drivers/splitInpMtx8.pg010064400020550007177000000010400663700453500171120ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSplitInpMtx MPI/drivers/symbfac2.pg010064400020550007177000000002000663700454100162270ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testSymbFac chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSymbFac MPI/drivers/symbfac4.pg010064400020550007177000000004000663700454400162360ustar00clevecompmath00000400000006chinacat 0 /local/cleve/ARPA/release2.2/MPI/drivers/testSymbFac chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSymbFac chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSymbFac chinacat 1 /local/cleve/ARPA/release2.2/MPI/drivers/testSymbFac MPI/doc/004275500020550007177000000000000665023217200132735ustar00clevecompmath00000400000006MPI/doc/proto.tex.bak010064400020550007177000001146410661616704700157300ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt MPI} methods} \label{section:MPI:proto} \par This section contains brief descriptions including prototypes of all methods found in the {\tt MPI} source directory. \par \subsection{Split and redistribution methods} \label{subsection:MPI:proto:split} \par %======================================================================= In a distributed environment, data must be distributed, and sometimes during a computation, data must be re-distributed. These methods split and redistribute four data objects. \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_MPI_splitByRows ( DenseMtx *mtx, IV *mapIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{DenseMtx_MPI_splitByRows@{\tt DenseMtx\_MPI\_splitByRows()}} This method splits and redistributes the {\tt DenseMtx} object based on the {\tt mapIV} object that maps rows to processes. The messages that will be sent require {\tt nproc} consecutive tags --- the first is the parameter {\tt firsttag}. On return, the {\tt stats[]} vector contains the following information. \par \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par Note, the values in {\tt stats[]} are {\it incremented}, i.e., the {\tt stats[]} vector is not zeroed at the start of the method, and so can be used to accumulated information with multiple calls. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt rowmapIV} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_MPI_split ( InpMtx *inpmtx, IV *mapIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{InpMtx_MPI_split@{\tt InpMtx\_MPI\_split()}} This method splits and redistributes the {\tt InpMtx} object based on the {\tt mapIV} object that maps the {\tt InpMtx} object's vectors (rows, columns or chevrons) to processes. The the vectors are defined by the first coordinate of the {\tt InpMtx} object. For the distributed $LU$, $U^TDU$ and $U^HDU$ factorizations, we use the chevron coordinate type to store the matrix entries. This method will redistribute a matrix by rows if the coordinate type is {\tt 1} (for rows) and {\tt mapIV} is a row map. Similarly, this method will redistribute a matrix by columns if the coordinate type is {\tt 2} (for columns) and {\tt mapIV} is a column map. See the {\tt InpMtx} object for details. The messages that will be sent require {\tt nproc} consecutive tags --- the first is the parameter {\tt firsttag}. On return, the {\tt stats[]} vector contains the following information. \par \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par Note, the values in {\tt stats[]} are {\it incremented}, i.e., the {\tt stats[]} vector is not zeroed at the start of the method, and so can be used to accumulated information with multiple calls. \par \noindent {\it Error checking:} If {\tt firsttag < 0} or {\tt firsttag + nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_MPI_split ( Pencil *pencil, IV *mapIV, int tag, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{Pencil_MPI_split@{\tt Pencil\_MPI\_split()}} This method splits and redistributes the matrix pencil based on the {\tt mapIV} object that maps rows and columns to processes. This is a simple wrapper around the {\tt InpMtx\_MPI\_split()} method. The messages that will be sent require {\tt 2*nproc} consecutive tags --- the first is the parameter {\tt firsttag}. On return, the {\tt stats[]} vector contains the following information. \par \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par Note, the values in {\tt stats[]} are {\it incremented}, i.e., the {\tt stats[]} vector is not zeroed at the start of the method, and so can be used to accumulated information with multiple calls. \par \noindent {\it Error checking:} If {\tt firsttag < 0} or {\tt firsttag + 2*nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_MPI_split ( FrontMtx *frontmtx, SolveMap *solvemap, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_split@{\tt FrontMtx\_MPI\_split()}} Used after the factorization, this method is used instead of the {\tt FrontMtx\_splitUpperMatrices()} and {\tt FrontMtx\_splitLowerMatrices()} methods. The method splits and redistributes the {\tt FrontMtx} object based on the {\tt solvemap} object that maps submatrices to processes. The {\tt firsttag} is the first tag that will be used for all messages. Unfortunately, the number of different tags that are necessary is not known prior to entering this method. On return, the {\tt stats[]} vector contains the following information. \par \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par Note, the values in {\tt stats[]} are {\it incremented}, i.e., the {\tt stats[]} vector is not zeroed at the start of the method, and so can be used to accumulated information with multiple calls. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt rowmapIV} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt firsttag < 0} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Gather and scatter methods} \label{subsection:MPI:proto:gather-scatter} \par %======================================================================= These method gather and scatter/add rows of {\tt DenseMtx} objects. These operations are performed during the distributed matrix-matrix multiply. The gather operation $X_{supp}^q \leftarrow X$ is performed by {\tt DenseMtx\_MPI\_gatherRows()}, while the scatter/add operation $Y^q := Y^q + \sum_r Y_{supp}^r$ is performed by {\tt DenseMtx\_MPI\_scatterAddRows()}. \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_MPI_gatherRows ( DenseMtx *Y, DenseMtx *X, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm) ; \end{verbatim} \index{DenseMtx_MPI_gatherRows@{\tt DenseMtx\_MPI\_gatherRows()}} This method is used to gather rows of {\tt X}, a globally distributed matrix, into {\tt Y}, a local matrix. List $q$ of {\tt sendIVL} contains the local row ids of the local part of {\tt X} that will be sent to processor $q$. List $q$ of {\tt recvIVL} contains the local row ids of {\tt Y} that will be received from processor $q$. \par This method uses tags in the range {\tt [tag,tag+nproc*nproc)}. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method is {\it safe} in the sense that it uses only non-blocking sends and receives, {\tt MPI\_Isend()} and {\tt MPI\_Irecv()}. \par \noindent {\it Error checking:} If {\tt Y}, {\tt X}, {\tt sendIVL} or {\tt recvIVL} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag + nproc*nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_MPI_scatterAddRows ( DenseMtx *Y, DenseMtx *X, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm) ; \end{verbatim} \index{DenseMtx_MPI_scatterAddRows@{\tt DenseMtx\_MPI\_scatterAddRows()}} This method is used to scatter/add rows of {\tt X}, a globally distributed matrix, into {\tt Y}, a local matrix. List $q$ of {\tt sendIVL} contains the local row ids of the local part of {\tt X} that will be sent to processor $q$. List $q$ of {\tt recvIVL} contains the local row ids of {\tt Y} that will be received from processor $q$. \par This method uses tags in the range {\tt [tag,tag+nproc*nproc)}. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method is {\it safe} in the sense that it uses only non-blocking sends and receives, {\tt MPI\_Isend()} and {\tt MPI\_Irecv()}. \par \noindent {\it Error checking:} If {\tt Y}, {\tt X}, {\tt sendIVL} or {\tt recvIVL} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag + nproc*nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Symbolic Factorization methods} \label{subsection:MPI:proto:symbfac} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IVL * SymbFac_MPI_initFromInpMtx ( ETree *etree, IV *frontOwnersIV, InpMtx *inpmtx, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; IVL * SymbFac_MPI_initFromPencil ( ETree *etree, IV *frontOwnersIV, Pencil *pencil, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{SymbFac_MPI_initFromInpMtx@{\tt SymbFac\_MPI\_initFromInpMtx()}} \index{SymbFac_MPI_initFromPencil@{\tt SymbFac\_MPI\_initFromPencil()}} These methods are used in place of the {\tt Symbfac\_initFrom\{InpMtx,Pencil\}()} methods to compute the symbolic factorization. The {\tt ETree} object is assumed to be replicated over the processes. The {\tt InpMtx} and {\tt Pencil} objects are partitioned among the processes. Therefore, to compute the {\tt IVL} object that contains the symbolic factorization is a distributed, cooperative process. At the end of the symbolic factorization, each process will own a portion of the {\tt IVL} object. The {\tt IVL} object is neither replicated nor partitioned (except in trivial cases), but the {\tt IVL} object on each process contains just a portion, usually not much more than what it needs to know for its part of the factorization and solves. \par This method uses tags in the range {\tt [tag,tag+nfront)}. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method is {\it safe} in the sense that it uses only non-blocking sends and receives, {\tt MPI\_Isend()} and {\tt MPI\_Irecv()}. \par \noindent {\it Error checking:} If {\tt etree}, {\tt inpmtx}, {\tt pencil} or {\tt frontOwnersIV} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag + nfront} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Numeric Factorization methods} \label{subsection:MPI:proto:factor} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Chv * FrontMtx_MPI_factorPencil ( FrontMtx *frontmtx, Pencil *pencil, double tau, double droptol, ChvManager *chvmanager, IV *frontOwnersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; Chv * FrontMtx_MPI_factorInpMtx ( FrontMtx *frontmtx, InpMtx *inpmtx, double tau, double droptol, ChvManager *chvmanager, IV *frontOwnersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_factorPencil@{\tt FrontMtx\_MPI\_factorPencil()}} \index{FrontMtx_MPI_factorInpMtx@{\tt FrontMtx\_MPI\_factorInpMtx()}} These methods are used to compute the numeric factorization and are very similar to the multithreaded {\tt FrontMtx\_MT\_factorPencil()} and {\tt FrontMtx\_MT\_factorInpMtx()} methods. All that has been added is the code to send and receive the {\tt Chv} messages. The input {\tt firsttag} parameter is used to tag the messages during the factorization. This method uses tags in the range {\tt [firsttag, firsttag + 3*nfront + 3)}. \par On return, {\tt *perror} holds an error flag. If the factorization completed without any error detected, {\tt *perror} will be negative. Otherwise it holds the id of a front where the factorization failed. Currently, this can happen only if pivoting is not enabled and a zero pivot was detected. \par The return value is a pointer to a list of {\tt Chv} objects that hold entries of the matrix that could not be factored. This value should be {\tt NULL} in all cases. We have left this return behavior as a hook for future implementation of a multi-stage factorization. \par On return, the {\tt cpus[]} vector has the following information. \begin{center} \begin{tabular}{ccl} {\tt cpus[0] } & --- & initialize fronts \\ {\tt cpus[1] } & --- & load original entries \\ {\tt cpus[2] } & --- & update fronts \\ {\tt cpus[3] } & --- & insert aggregate data \\ {\tt cpus[4] } & --- & assemble aggregate data \\ {\tt cpus[5] } & --- & assemble postponed data \\ {\tt cpus[6] } & --- & factor fronts \\ {\tt cpus[7] } & --- & extract postponed data \\ {\tt cpus[8] } & --- & store factor entries \\ {\tt cpus[9] } & --- & post initial receives \\ {\tt cpus[10] } & --- & check for received messages \\ {\tt cpus[11] } & --- & post initial sends \\ {\tt cpus[12] } & --- & check for sent messages \\ \end{tabular} \end{center} On return, the {\tt stats[]} vector has the following information. \begin{center} \begin{tabular}{ccl} {\tt stats[0]} & --- & \# of pivots \\ {\tt stats[1]} & --- & \# of pivot tests \\ {\tt stats[2]} & --- & \# of delayed rows and columns \\ {\tt stats[3]} & --- & \# of entries in D \\ {\tt stats[4]} & --- & \# of entries in L \\ {\tt stats[5]} & --- & \# of entries in U \\ {\tt stats[6]} & --- & \# of aggregate messages sent \\ {\tt stats[7]} & --- & \# of bytes sent in aggregate messages \\ {\tt stats[8]} & --- & \# of aggregate messages received \\ {\tt stats[9]} & --- & \# of bytes received in aggregate messages \\ {\tt stats[10]} & --- & \# of postponed messages sent \\ {\tt stats[11]} & --- & \# of bytes sent in postponed messages \\ {\tt stats[12]} & --- & \# of postponed messages received \\ {\tt stats[13]} & --- & \# of bytes received in postponed messages \\ {\tt stats[14]} & --- & \# of active {\tt Chv} objects (working storage) \\ {\tt stats[15]} & --- & \# of active bytes in working storage \\ {\tt stats[16]} & --- & \# of requested bytes for working storage \end{tabular} \end{center} \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt pencil}, {\tt frontOwnersIV}, {\tt cpus} or {\tt stats} is {\tt NULL}, or if {\tt tau < 1.0} or {\tt droptol < 0.0}, or if {\tt firsttag < 0} or {\tt firsttag + 3*nfront + 2} is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Post-processing methods} \label{subsection:MPI:proto:postprocess} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_MPI_postProcess ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_postProcess@{\tt FrontMtx\_MPI\_postProcess()}} After the factorization is complete, the factor matrices are split into submatrices. This method replaces the serial {\tt FrontMtx\_postProcess()} method. The messages that will be sent require at most {\tt 5*nproc} consecutive tags --- the first is the parameter {\tt firsttag}. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt frontOwnersIV} or {\tt stats} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + 5*nproc}, is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_MPI_permuteUpperAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; void FrontMtx_MPI_permuteLowerAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_permuteUpperAdj@{\tt FrontMtx\_MPI\_permuteUpperAdj()}} \index{FrontMtx_MPI_permuteLowerAdj@{\tt FrontMtx\_MPI\_permuteLowerAdj()}} If pivoting takes place during the factorization, the off diagonal blocks of the factor matrices must be permuted prior to being split into submatrices. To do this, the final rows and columns of the factor matrix must be made known to the different processors. The messages that will be sent require at most {\tt nproc} consecutive tags --- the first is the parameter {\tt firsttag}. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt frontOwnersIV} or {\tt stats} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + nproc}, is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_MPI_allgather ( IV *iv, IV *ownersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{IV_MPI_allgather@{\tt IV\_MPI\_allgather()}} After a factorization with pivoting, the {\tt frontsizesIV} object needs to be made global on each processor. This methods takes the individual entries of an {\tt IV} object whose owners are specified by the {\tt ownersIV} object, and communicates the entries around the processors until the global {\tt IV} object is present on each. The messages that will be sent require at most {\tt nproc} consecutive tags --- the first is the parameter {\tt firsttag}. \par \noindent {\it Error checking:} If {\tt iv}, {\tt ownersIV} or {\tt stats} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + nproc}, is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_MPI_allgather ( IVL *ivl, IV *ownersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{IVL_MPI_allgather@{\tt IVL\_MPI\_allgather()}} When the {\tt FrontMtx} object is split into submatrices, each processor accumulates the structure of the block matrix for the fronts its owns. This structure must be global to all processors before the submatrix map can be computed. This method takes a {\it partitioned} {\tt IVL} object and communicates the entries among the processors until the global {\tt IVL} object is present on each. Which processor owns what lists of the {\tt IVL} object is given by the {\tt ownersIV} object. The messages that will be sent require at most {\tt nproc} consecutive tags --- the first is the parameter {\tt firsttag}. \par \noindent {\it Error checking:} If {\tt ivl}, {\tt ownersIV} or {\tt stats} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + nproc}, is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Numeric Solve methods} \label{subsection:MPI:proto:solve} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_MPI_solve ( FrontMtx *frontmtx, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, SolveMap *solvemap, double cpus[], int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_solve@{\tt FrontMtx\_MPI\_solve()}} This method is used to compute the forward and backsolves. Its structure is very, very similar to the multithreaded {\tt FrontMtx\_MT\_solve()} method. All that has been added is the code to send and receive the {\tt SubMtx} messages. The method uses tags in the range {\tt [firsttag, firsttag + 2*nfront)}. On return, the {\tt cpus[]} vector has the following information. \begin{center} \begin{tabular}{ccl} {\tt cpus[0] } & --- & setup the solves \\ {\tt cpus[1] } & --- & load rhs and store solution \\ {\tt cpus[2] } & --- & forward solve \\ {\tt cpus[3] } & --- & diagonal solve \\ {\tt cpus[4] } & --- & backward solve \\ {\tt cpus[5] } & --- & miscellaneous \end{tabular} \end{center} On return, the following statistics will have been added. \begin{center} \begin{tabular}{ccl} {\tt stats[0]} & --- & \# of solution messages sent \\ {\tt stats[1]} & --- & \# of aggregate messages sent \\ {\tt stats[2]} & --- & \# of solution bytes sent \\ {\tt stats[3]} & --- & \# of aggregate bytes sent \\ {\tt stats[4]} & --- & \# of solution messages received \\ {\tt stats[5]} & --- & \# of aggregate messages received \\ {\tt stats[6]} & --- & \# of solution bytes received \\ {\tt stats[7]} & --- & \# of aggregate bytes received \end{tabular} \end{center} \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt pencil}, {\tt frontOwnersIV}, {\tt cpus} or {\tt stats} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + 2*nfront} is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Matrix-matrix multiply methods} \label{subsection:MPI:proto:mmm} \par The usual sequence of events is as follows. \begin{itemize} \item Set up the data structure via a call to {\tt MatMul\_MPI\_setup()}. \item Convert the local $A^q$ matrix to local indices via a call to {\tt MatMul\_setLocalIndices()}. \item Compute the matrix-matrix multiply with a call to {\tt MatMul\_MPI\_mmm()}. Inside this method, the MPI methods {\tt DenseMtx\_MPI\_gatherRows()} and {\tt DenseMtx\_MPI\_scatterAddRows()} are called, along with a serial {\tt InpMtx} matrix-matrix multiply method. \item Clean up and free data structures via a call to {\tt MatMul\_cleanup().} \item Convert the local $A^q$ matrix to global indices via a call to {\tt MatMul\_setGlobalIndices()}. \end{itemize} \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} MatMulInfo * MatMul_MPI_setup ( InpMtx *A, int symflag, int opflag, IV *XownersIV, IV *YownersIV int stats[], int msglvl, FILE *msgFile, MPI_Comm comm) ; \end{verbatim} \index{MatMul_MPI_setup@{\tt MatMul\_MPI\_setup()}} This method is used to set up and return the {\tt MatMulInfo} data structure that stores the information for the distributed matrix-matrix multiply. The {\tt symflag} parameter specifies the symmetry of the matrix. \begin{itemize} \item 0 ({\tt SPOOLES\_SYMMETRIC}) \item 1 ({\tt SPOOLES\_HERMITIAN}) \item 2 ({\tt SPOOLES\_NONSYMMETRIC}) \end{itemize} The {\tt opflag} parameter specifies what type of operation will be performed. \begin{itemize} \item 0 ({\tt MMM\_WITH\_A}) --- $Y := Y + \alpha A X$ \item 1 ({\tt MMM\_WITH\_AT}) --- $Y := Y + \alpha A^T X$ \item 2 ({\tt MMM\_WITH\_AH}) --- $Y := Y + \alpha A^H X$ \end{itemize} The {\tt XownersIV} object is the map from the rows of $X$ to their owning processors. The {\tt YownersIV} object is the map from the rows of $Y$ to their owning processors. \par On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method calls {\tt makeSendRecvIVLs()}. \par \noindent {\it Error checking:} If {\tt A}, {\tt XownersIV}, {\tt YownersIV} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MatMul_setLocalIndices ( MatMulInfo *info, InpMtx *A ) ; void MatMul_setGlobalIndices ( MatMulInfo *info, InpMtx *A ) ; \end{verbatim} \index{MatMul_setLocalIndices@{\tt MatMul\_setLocalIndices()}} \index{MatMul_setGlobalIndices@{\tt MatMul\_setGlobalIndices()}} The first method maps the indices of {\tt A} (which are assumed to be global) into local indices. The second method maps the indices of {\tt A} (which are assumed to be local) back into global indices. It uses the {\tt XmapIV}, {\tt XsupIV} {\tt YmapIV} and {\tt YsupIV} objects that are contained in the {\tt info} object. These are serial methods, performed independently on each processor. \par \noindent {\it Error checking:} If {\tt info} or {\tt A} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MatMul_MPI_mmm ( MatMulInfo *info, DenseMtx *Yloc, double alpha[], InpMtx *A, DenseMtx *Xloc, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm) ; \end{verbatim} \index{MatMul_MPI_mmm@{\tt MatMul\_MPI\_mmm()}} This method computes a distributed matrix-matrix multiply $Y := Y + \alpha A X$, $Y := Y + \alpha A^T X$ or $Y := Y + \alpha A^H X$, depending on how the {\tt info} object was set up. NOTE: {\tt A} must have local indices, use {\tt MatMul\_setLocalIndices()} to convert from global to local indices. {\tt Xloc} and {\tt Yloc} contain the owned rows of $X$ and $Y$, respectively. \par On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method calls {\tt makeSendRecvIVLs()}. \par \noindent {\it Error checking:} If {\tt info}, {\tt Yloc}, {\tt alpha}, {\tt A}, {\tt Xloc} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MatMul_cleanup ( MatMulInfo *info ) ; \end{verbatim} \index{MatMul_cleanup@{\tt MatMul\_cleanup()}} This method free's the data structures owned by the {\tt info} object, and then free's the object. processor. \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Broadcast methods} \label{subsection:MPI:proto:broadcast} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} ETree * ETree_MPI_Bcast ( ETree *etree, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{ETree_MPI_Bcast@{\tt ETree\_MPI\_Bcast()}} This method is a broadcast method for an {\tt ETree} object. The {\tt root} processor broadcasts its {\tt ETree} object to the other nodes and returns a pointer to its {\tt ETree} object. A node other than {\tt root} free's its {\tt ETree} object (if not {\tt NULL}), receives {\tt root}'s {\tt ETree} object, and returns a pointer to it. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} Graph * Graph_MPI_Bcast ( Graph *etree, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{Graph_MPI_Bcast@{\tt Graph\_MPI\_Bcast()}} This method is a broadcast method for an {\tt Graph} object. The {\tt root} processor broadcasts its {\tt Graph} object to the other nodes and returns a pointer to its {\tt Graph} object. A node other than {\tt root}, clears the data in its Graph object, receives the Graph object from the root and returns a pointer to it. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * IVL_MPI_Bcast ( IVL *etree, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{IVL_MPI_Bcast@{\tt IVL\_MPI\_Bcast()}} This method is a broadcast method for an {\tt IVL} object. The {\tt root} processor broadcasts its {\tt IVL} object to the other nodes and returns a pointer to its {\tt IVL} object. A node other than {\tt root}, clears the data in its IVL object, receives the IVL object from the root and returns a pointer to it. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:MPI:proto:utility} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IVL * InpMtx_MPI_fullAdjacency ( InpMtx *inpmtx, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm ) ; IVL * Pencil_MPI_fullAdjacency ( Pencil *pencil, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{InpMtx_MPI_fullAdjacency@{\tt InpMtx\_MPI\_fullAdjacency()}} \index{Pencil_MPI_fullAdjacency@{\tt Pencil\_MPI\_fullAdjacency()}} These methods are used to return an {\tt IVL} object that contains the full adjacency structure of the graph of the matrix or matrix pencil. The matrix or matrix pencil is distributed among the processes, each process has a {\it local} portion of the matrix or matrix pencil. The returned {\tt IVL} object contains the structure of the global graph. The {\tt stats[]} vector must have at least four fields. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par \noindent {\it Error checking:} If {\tt inpmtx}, {\tt pencil} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ChvList * FrontMtx_MPI_aggregateList ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_aggregateList@{\tt FrontMtx\_MPI\_aggregateList()}} This method is used in place of the {\tt FrontMtx\_aggregateList()} method to initialize the aggregate list object. Since the symbolic factorization data is distributed among the processes, the number of incoming aggregates for a front and the number of different processes contributing to a front --- information necessary to initialize the list object --- must be computed cooperatively. This method uses {\tt tag} as the message tag for all messages communicated during this method. The {\tt stats[]} vector must have at least four fields. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt frontOwnersIV} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * FrontMtx_MPI_colmapIV ( FrontMtx *frontmtx, IV *frontOwnersIV, int msglvl, FILE *msgFile, MPI_Comm comm ) ; IV * FrontMtx_MPI_rowmapIV ( FrontMtx *frontmtx, IV *frontOwnersIV, int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_colmapIV@{\tt FrontMtx\_MPI\_colmapIV()}} \index{FrontMtx_MPI_rowmapIV@{\tt FrontMtx\_MPI\_rowmapIV()}} For a factorization with pivoting, the elimination of some rows and columns may be delayed from the front that initially contains them to an ancestor front. The solution and right hand side entries would therefore need to be redistributed. To do so requires new row and column maps, maps from the row or column to the processor that owns them. These two methods construct that map. The routine uses the {\tt MPI\_Allgather()} and {\tt MPI\_Bcast()} methods, so no unique tag values are needed. \par \noindent {\it Error checking:} None at present. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * IVL_MPI_alltoall ( IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{InpMtx_MPI_alltoall@{\tt InpMtx\_MPI\_alltoall}} This method is used during the setup for matrix-vector multiplies. Each processor has computed the vertices it needs from other processors, these lists are contained in {\tt sendIVL}. On return, {\tt recvIVL} contains the lists of vertices this processor must send to all others. \par This method uses tags in the range {\tt [tag,tag+nproc-1)}. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method is {\it safe} in the sense that it uses only {\tt MPI\_Sendrecv()}. \par \noindent {\it Error checking:} If {\tt sendIVL} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag + nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void * makeSendRecvIVLs ( IV *supportedIV, IV *globalmapIV, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{makeSendRecvIVLs@{\tt makeSendRecvIVLs}} \par The purpose of this method to analyze and organize communication. It was written in support of a distributed matrix-vector multiply but can be used for other applications. \par Each processor has a list of items it "supports" or needs found in the {\tt supportedIV} object. The {\tt globalmapIV} object contains the map from items to owning processors. We need to figure out what items this processor will send to and receive from each other processor. This information is found in the {\tt sendIVL} and {\tt recvIVL} objects. \par On return, list {\tt jproc} of {\tt sendIVL} contains the items owned by this processor and needed by {\tt jproc}. On return, list {\tt jproc} of {\tt recvIVL} contains the items needed by this processor and owned by {\tt jproc}. \par This method initializes the {\tt recvIVL} object, and then calls {\tt IVL\_MPI\_alltoall()} to construct the {\tt sendIVL} object. This method uses tags in the range {\tt [tag,tag+nproc*nproc)}. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method is {\it safe} in the sense that it uses only {\tt MPI\_Sendrecv()}. \par \noindent {\it Error checking:} If {\tt sendIVL} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag + nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int maxTagMPI ( MPI_Comm comm) ; \end{verbatim} \index{maxTagMPI@{\tt maxTagMPI()}} This method returns the maximum tag value for the communicator {\tt comm}. \par \noindent {\it Error checking:} None at present. %----------------------------------------------------------------------- \end{enumerate} \par tMul\_cleanup()}} This method free's the data structures owned by the {\tt info} object, and thMPI/doc/dataStructure.tex010064400020550007177000000067340656757775300167040ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:MPI:dataStructure} \par There is one MPI specific data structure, used in the distributed matrix-matrix multiply. \par \subsection{{\tt MatMulInfo} : Matrix-matrix multiply information object} \label{subsection:MatMulInfo} \par The distributed matrix-matrix multiply is a very complex operation. We want to compute $Y := Y + \alpha A X$, where $Y$, $A$ and $X$ are distributed matrices. Processor $q$ owns the local matrices $Y^q$, $A^q$ and $X^q$. The entries of $A^q$ do not travel among the processors, it is the entries of $X$ and/or the partial entries of the product $\alpha A X$ that are communicated. Each processor performs the local computation $Y_{supp}^q = \alpha A^q X_{supp}^q$, where the rows of $X_{supp}^q$ correspond to the columns of $A^q$ with a nonzero entry, and the rows of $Y_{supp}^q$ correspond to the rows of $A^q$ with a nonzero entry. (Something similar holds for the operations $Y := Y + \alpha A^T X$ and $Y := Y + \alpha A^T X$.) This requires entries of $X$ to be {\it gathered} into $X_{supp}^q$ and the entries of $Y_{supp}^q$ be {\it scatter/added} into $Y$. \par The {\tt MatMulInfo} object stores all the necessary information to make this happen. There is one {\tt MatMulInfo} object per processor. It has the following fields. \begin{itemize} \item {\tt symflag} --- symmetry flag for $A$ \begin{itemize} \item 0 ({\tt SPOOLES\_SYMMETRIC}) -- symmetric matrix \item 1 ({\tt SPOOLES\_HERMITIAN}) -- hermitian matrix \item 2 ({\tt SPOOLES\_NONSYMMETRIC}) -- nonsymmetric matrix \end{itemize} \item {\tt opflag} --- operation flag for the multiply \begin{itemize} \item 0 ({\tt MMM\_WITH\_A}) --- perform $Y := Y + \alpha A X$ \item 1 ({\tt MMM\_WITH\_AT}) --- perform $Y := Y + \alpha A^T X$ \item 2 ({\tt MMM\_WITH\_AH}) --- perform $Y := Y + \alpha A^H X$ \end{itemize} \item {\tt IV *XownedIV} --- list of rows of $X$ that are owned by this processor, these form the rows of $X^q$. \item {\tt IV *XsupIV} --- list of rows of $X$ that are accessed by this processor, these form the rows of $X_{supp}^q$ \item {\tt IV *XmapIV} --- a map from the global ids of the rows of $X_{supp}^q$ to their local ids within $X_{supp}^q$ \item {\tt IVL *XsendIVL} --- list $r$ holds the local row ids of the owned rows of $X^q$ that must be sent from this processor to processor $r$ \item {\tt IVL *XrecvIVL} --- list $r$ holds the local row ids of the supported rows of $X_{supp}^q$ that will be received from processor $r$. \item {\tt IV *YownedIV} --- list of rows of $Y$ that are owned by this processor, these form the rows of $Y^q$. \item {\tt IV *YsupIV} --- list of rows of $Y$ that are updated by this processor, these form the rows of $Y_{supp}^q$ \item {\tt IV *YmapIV} --- a map from the global ids of the rows of $Y_{supp}^q$ to their local ids within $Y_{supp}^q$ \item {\tt IVL *YsendIVL} --- list $r$ holds the local row ids of the supported rows of $Y_{supp}^q$ that must be sent from this processor to processor $r$ \item {\tt IVL *YrecvIVL} --- list $r$ holds the local row ids of the owned rows of $Y^q$ that will be received from processor $r$. \item {\tt DenseMtx *Xsupp} --- a temporary data structure to hold $X_{supp}^q$. \item {\tt DenseMtx *Ysupp} --- a temporary data structure to hold $Y_{supp}^q$. \end{itemize} \par See the methods {\tt MatMul\_MPI\_setup()}, {\tt MatMul\_setLocalIndices()}, {\tt MatMul\_setGlobalIndices()}, {\tt MatMul\_MPI\_mmm()} and {\tt MatMul\_cleanup()} which use the {\tt MatMulInfo} data object. MPI/doc/drivers.tex010064400020550007177000000703570661617772300155160ustar00clevecompmath00000400000006\par \section{Driver programs} \label{section:MPI:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} allInOne msglvl msgFile type symmetryflag pivotingflag seed \end{verbatim} This driver program is an example program for reading in a linear system and right hand side, ordering the matrix, factoring the matrix, and solving the system. Use the script file {\tt do\_AllInOne} for testing. \par The files names for the matrix and right hand side entries are hardcoded. Processor $q$ reads in matrix entries from file $\mbox{\tt matrix.}q\mbox{\tt .input}$ and right hand side entries from file $\mbox{\tt rhs.}q\mbox{\tt .input}$. The format for the matrix files is as follows: \begin{verbatim} neqns neqns nent irow jcol entry ... ... ... \end{verbatim} where {\tt neqns} is the global number of equations and {\tt nent} is the number of entries in this file. There follows {\tt nent} lines, each containing a row index, a column index and one or two floating point numbers, one if real, two if complex. The format for the right hand side file is similar: \begin{verbatim} nrow nrhs irow entry ... entry ... ... ... ... \end{verbatim} where {\tt nrow} is the number of rows in this file and {\tt nrhs} is the number of rigght and sides. There follows {\tt nrow} lines, each containing a row index and either {\tt nrhs} or {\tt 2*nrhs} floating point numbers, the first if real, the second if complex. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter specifies whether the linear system is real ({\tt type} = 1) or complex ({\tt type} = 2). \item The {\tt symmetryflag} parameter specifies whether the matrix is symmetric ({\tt symmetryflag} = 0), Hermitian ({\tt symmetryflag} = 1) or nonsymmetric ({\tt symmetryflag} = 2) \item The {\tt pivotingflag} parameter specifies whether pivoting will be performed during the factorization, yes ({\tt symmetryflag} = 0) or no ({\tt symmetryflag} = 2). The pivot tolerance is hardcoded as {\tt tau = 100.0}. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} patchAndGoMPI msglvl msgFile type symmetryflag patchAndGoFlag fudge toosmall storeids storevalues seed \end{verbatim} This driver program is used to test the ``patch-and-go'' functionality for a factorization without pivoting. When small diagonal pivot elements are found, one of three actions are taken. See the {\tt PatchAndGoInfo} object for more information. \par The program reads in a matrix $A$ and right hand side $B$, generates the graph for $A$ and orders the matrix, factors $A$ and solves the linear system $AX = B$ for $X$. \par The files names for the matrix and right hand side entries are hardcoded. Processor $q$ reads in matrix entries from file $\mbox{\tt patchMatrix.}q\mbox{\tt .input}$ and right hand side entries from file $\mbox{\tt patchRhs.}q\mbox{\tt .input}$. The format for the matrix files is as follows: \begin{verbatim} neqns neqns nent irow jcol entry ... ... ... \end{verbatim} where {\tt neqns} is the global number of equations and {\tt nent} is the number of entries in this file. There follows {\tt nent} lines, each containing a row index, a column index and one or two floating point numbers, one if real, two if complex. The format for the right hand side file is similar: \begin{verbatim} nrow nrhs irow entry ... entry ... ... ... ... \end{verbatim} where {\tt nrow} is the number of rows in this file and {\tt nrhs} is the number of rigght and sides. There follows {\tt nrow} lines, each containing a row index and either {\tt nrhs} or {\tt 2*nrhs} floating point numbers, the first if real, the second if complex. Use the script file {\tt do\_patchAndGo} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter specifies a real or complex linear system. \begin{itemize} \item {\tt type = 1 (SPOOLES\_REAL)} for real, \item {\tt type = 2 (SPOOLES\_COMPLEX)} for complex. \end{itemize} \item The {\tt symmetryflag} parameter specifies the symmetry of the matrix. \begin{itemize} \item {\tt type = 0 (SPOOLES\_SYMMETRIC)} for $A$ real or complex symmetric, \item {\tt type = 1 (SPOOLES\_HERMITIAN)} for $A$ complex Hermitian, \item {\tt type = 2 (SPOOLES\_NONSYMMETRIC)} \end{itemize} for $A$ real or complex nonsymmetric. \item The {\tt patchAndGoFlag} specifies the ``patch-and-go'' strategy. \begin{itemize} \item {\tt patchAndGoFlag = 0} --- if a zero pivot is detected, stop computing the factorization, set the error flag and return. \item {\tt patchAndGoFlag = 1} --- if a small or zero pivot is detected, set the diagonal entry to 1 and the offdiagonal entries to zero. \item {\tt patchAndGoFlag = 2} --- if a small or zero pivot is detected, perturb the diagonal entry. \end{itemize} \item The {\tt fudge} parameter is used to perturb a diagonal entry. \item The {\tt toosmall} parameter is judge when a diagonal entry is small. \item If {\tt storeids = 1}, then the locations where action was taken is stored in an {\tt IV} object. \item If {\tt storevalues = 1}, then the perturbations are stored in an {\tt DV} object. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testGather msglvl msgFile type nrow ncol inc1 inc2 seed \end{verbatim} This driver program test the {\tt DenseMtx\_MPI\_gatherRows()} method. Each processor creates part of a distributed matrix $X$ and fills its entries with entries known to all processors. ($X_{j,k} = j + k*\mbox{nproc}$ if real and $X_{j,k} = j + k*\mbox{nproc} + i*2*(j + k*\mbox{nproc})$) if complex. The mapping from rows of $X$ to processors is random. Each processor then generates a random vector that contains its rows in a local $Y$, which will be filled with the corresponding rows of $X$. The rows of $X$ are then gathered into $Y$, and the local errors are computed. The global error is written to the results file by processor zero. \par Use the script file {\tt do\_gather} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter specifies whether the linear system is real ({\tt type} = 1) or complex ({\tt type} = 2). \item {\tt nrow} is the number of rows in {\tt X}. \item {\tt ncol} is the number of columns in {\tt X}. \item {\tt inc1} is the row increment for {\tt X}. \item {\tt inc2} is the column increment for {\tt X}. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testGraph_Bcast msglvl msgFile type nvtx nitem root seed \end{verbatim} This driver program tests the distributed {\tt Graph\_MPI\_Bcast()} method. Processor {\tt root} generates a random graph of type {\tt type} (see the documentation for the {\tt Graph} object in chapter~\ref{chapter:Graph}) with {\tt nvtx} vertices. The random graph is constructed via an {\tt InpMtx} object using {\tt nitem} edges. Processor {\tt root} then sends its {\tt Graph} object to the other processors. Each processor computes a checksum for its object, and the error are collected on processor 0. Use the script file {\tt do\_Graph\_Bcast} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter specifies the type of the graph, unweighted, weighted vertices, weighted edges, and combinations. \item The {\tt nvtx} parameter specifies the number of vertices in the graph. \item The {\tt nitem} parameter is used to specify the number of edges that form the graph. An upper bound on the number of edges is {\tt nvtx + 2*nitem}. \item {\tt root} is the root processor for the broadcast. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testGridMPI msglvl msgFile n1 n2 n3 maxzeros maxsize seed type symmetryflag sparsityflag pivotingflag tau droptol lookahead nrhs maptype cutoff \end{verbatim} This driver program creates and solves the linear system $AX = Y$ where the structure of $A$ is from a ${\tt n1} \times {\tt n2} \times {\tt n3}$ regular grid operator and is ordered using nested dissection. The front tree is formed allowing {\tt maxzeros} in a front with a maximum of {\tt maxsize} vertices in a non-leaf front. Process {\tt 0} generates the linear system and broadcasts the front tree to the other processes. Using {\tt maptype}, the processes generate the owners map for the factorization in parallel. The $A$, $X$ and $Y$ matrices are then distributed among the processes. The symbolic factorization is then computed in parallel, the front matrix is initialized, and the factorization is computed in parallel. If pivoting has taken place, the solution and right hand side matrices are redistributed as necessary. The matrix is post-processed where it is converted to a submatrix storage format. Each processor computes the identical solve map, and the front matrix is split among the processes. The linear system is then solved in parallel and the error is computed. Use the script file {\tt do\_gridMPI} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt n1} parameter is the number of grid points in the first direction. \item The {\tt n2} parameter is the number of grid points in the second direction. \item The {\tt n3} parameter is the number of grid points in the third direction. \item The {\tt maxzeros} parameter is the maximum number of zero entries allowed in a front. \item The {\tt maxsize} parameter is the maximum number of internal rows and columns allowed in a front. \item The {\tt seed} parameter is a random number seed. \item The {\tt type} parameter specifies whether the linear system is real or complex. Use {\tt 1} for real and {\tt 2} for complex. \item The {\tt symmetryflag} parameter denotes the presence or absence of symmetry. \begin{itemize} \item Use {\tt 0} for a real or complex symmetric matrix $A$. A $(U^T + I)D(I + U)$ factorization is computed. \item Use {\tt 1} for a complex Hermitian matrix $A$. A $(U^H + I)D(I + U)$ factorization is computed. \item Use {\tt 2} for a real or complex nonsymmetric matrix $A$. A $(L + I)D(I + U)$ factorization is computed. \end{itemize} \item The {\tt sparsityflag} parameter denotes a direct or approximate factorization. Valid values are {\tt 0} for a direct factorization and {\tt 1} is for an approximate factorization. \item The {\tt pivotingflag} parameter denotes whether pivoting is to be used in the factorization. Valid values are {\tt 0} for no pivoting and {\tt 1} to enable pivoting. \item The {\tt tau} parameter is used when pivoting is enabled, in which case it is an upper bound on the magnitude of an entry in the triangular factors $L$ and $U$. \item The {\tt droptol} parameter is used when an approximate factorization is requested, in which it is a lower bound on the magnitude of an entry in $L$ and $U$. \item The {\tt lookahead} parameter governs the ``upward--looking'' nature of the factorization. Choosing {\tt lookahead = 0} is usually the most conservative with respect to working storage, while positive values increase the working storage and sometimes decrease the factorization time. \item The {\tt nrhs} parameter is the number of right hand sides. \item The {\tt maptype} parameter is the type of factorization map. \begin{itemize} \item {\tt 1} --- a wrap map via a post-order traversal \item {\tt 2} --- a balanced map via a post-order traversal \item {\tt 3} --- a subtree--subset map \item {\tt 4} --- a domain decomposition map \end{itemize} \item The {\tt cutoff} parameter is used with the domain decomposition map, and specifies the maximum fraction of the vertices to be included into a domain. Try {\tt cutoff} = {\tt 1/nproc} or {\tt 1/(2*nproc)}. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testIV_allgather msglvl msgFile n seed \end{verbatim} This driver program tests the distributed {\tt IV\_MPI\_allgather()} method. Each processor generates the same {\tt owners[]} map and fills an {\tt IV} object with random entries for the entries which it owns. The processors all-gather the entries of the vector so each processor has a copy of the global vector. Each processor computes a checksum of the vector to detect errors. Use the script file {\tt do\_IVallgather} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt n} parameter is the length of the vector. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testIVL_alltoall msglvl msgFile n seed \end{verbatim} This driver program tests the distributed {\tt IVL\_MPI\_alltoall()} method. This is used by the {\tt makeSendRecvIVLs} method when setting up the distributed matrix-matrix multiply. Each processor constructs a ``receive'' {\tt IVL} object with {\tt nproc} lists. List {\tt iproc} contains a set of ids of items that this processor will receive from processor {\tt iproc}. The processors then call {\tt IVL\_MPI\_allgather} to create their ``send'' {\tt IVL} object, where list {\tt iproc} contains a set of ids of items that this processor will send to processor {\tt iproc}. The set of lists in all the ``receive'' {\tt IVL} objects is exactly the same as the set of lists in all the ``send'' objects. This is an ``all-to-all'' scatter/gather operation. Had the lists be stored contiguously or at least in one block of storage, we could have used the {\tt MPI\_Alltoallv()} method. \par Use the script file {\tt do\_IVL\_alltoall} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt n} parameter is an upper bound on list size and element value. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testIVL_allgather msglvl msgFile nlist seed \end{verbatim} This driver program tests the distributed {\tt IVL\_MPI\_allgather()} method. Each processor generates the same {\tt owners[]} map and fills an {\tt IVL} object with random entries for the lists which it owns. The processors all-gather the entries of the {\tt IVL} object so each processor has a copy of the global object. Each processor computes a checksum of the lists to detect errors. Use the script file {\tt do\_IVLallgather} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nlist} parameter is the number of lists. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testIVL_Bcast msglvl msgFile nlist maxlistsize root seed \end{verbatim} This driver program tests the distributed {\tt IVL\_MPI\_Bcast()} method. Processor {\tt root} generates a random {\tt IVL} object with {\tt nlist} lists. The size of each list is bounded above by {\tt maxlistsize}. Processor {\tt root} then sends its {\tt IVL} object to the other processors. Each processor computes a checksum for its object, and the error are collected on processor 0. Use the script file {\tt do\_IVL\_Bcast} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nlist} parameter specifies the number of lists. \item The {\tt maxlist} parameter is an upper bound on the size of each list. \item {\tt root} is the root processor for the broadcast. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testMMM msglvl msgFile nrowA ncolA nentA ncolX coordType inputMode symflag opflag seed real imag \end{verbatim} This driver program tests the distributed matrix-matrix multiply $Y := Y + \alpha A X$, $Y := Y + \alpha A^T X$ or $Y := Y + \alpha A^H X$. Process zero creates $Y$, $A$ and $X$ and computes $Z = Y + \alpha A X$, $Z = Y + \alpha A^T X$ or $Z = Y + \alpha A^H X$. Using random maps, it distributes $A$, $X$ and $Y$ among the other processors. The information structure is created using {\tt MatMul\_MPI\_setup()}. The local matrix $A^q$ is mapped to local coordinates. The matrix-matrix multiply is computed, and then all the $Y^q$ local matrices are gathered onto processor zero into $Y$, which is then compared with $Z$ that was computed using a serial matrix-matrix multiply. The error is written to the message file by processor zero. Use the script file {\tt do\_MMM} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nrowA} parameter is the number of rows in $A$. \item The {\tt ncolA} parameter is the number of columns in $A$. \item The {\tt nentA} parameter is the number of entries to be put into $A$. \item The {\tt nrowX} parameter is the number of rows in $X$. \item The {\tt coordType} parameter defines the coordinate type that will be used during the redistribution. Valid values are {\tt 1} for rows, {\tt 2} for columns and {\tt 3} for chevrons. \item The {\tt inputMode} parameter defines the mode of input. Valid values are {\tt 1} for real entries and {\tt 2} for complex entries. \item The {\tt symflag} parameter specifies whether the matrix is symmetric ({\tt symflag} = 0), Hermitian ({\tt symflag} = 1) or nonsymmetric ({\tt symflag} = 2) \item The {\tt opflag} parameter specifies the type of multiply, {\tt 0} for $Y := Y + \alpha A X$, {\tt 1} for $Y := Y + \alpha A^T X$ or {\tt 2} for $Y := Y + \alpha A^H X$. \item The {\tt seed} parameter is a random number seed. \item The {\tt real} parameter is the real part of the scalar $\alpha$. \item The {\tt imag} parameter is the imaginary part of the scalar $\alpha$, ignored for real entries. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testScatterDenseMtx msglvl msgFile nrow ncol inc1 inc2 seed root \end{verbatim} This driver program exercises the {\tt DenseMtx\_MPI\_splitFromGlobalByRows()} method to split or redistribute by rows a {\tt DenseMtx} dense matrix object. Process {\tt root} generates the {\tt DenseMtx} object. A random map is generated (the same map on all processes) and the object is redistributed using this random map. The local matrices are then gathered into a second global matrix on processor {\tt root} and the two are compared. Use the script file {\tt do\_ScatterDenseMtx} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nrow} parameter is the number of rows for the matrix. \item The {\tt ncol} parameter is the number of columns for the matrix. \item The {\tt inc1} parameter is the row increment for the matrix. Valid values are {\tt 1} for column major and {\tt ncol} for row major. \item The {\tt inc2} parameter is the column increment for the matrix. Valid values are {\tt 1} for row major and {\tt nrow} for column major. \item The {\tt seed} parameter is a random number seed. \item The {\tt root} parameter is the root processor for the scatter and gather. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testScatterInpMtx msglvl msgFile neqns seed coordType inputMode inInpMtxFile root \end{verbatim} This driver program tests the distributed {\tt InpMtx\_MPI\_splitFromGlobal()} method to split a {\tt InpMtx} sparse matrix object. Process {\tt root} reads in the {\tt InpMtx} object. A random map is generated (the same map on all processes) and the object is scattered from processor {\tt root} to the other processors. Use the script file {\tt do\_ScatterInpMtx} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt neqns} parameter is the number of equations for the matrix. \item The {\tt seed} parameter is a random number seed. \item The {\tt coordType} parameter defines the coordinate type that will be used during the redistribution. Valid values are {\tt 1} for rows, {\tt 2} for columns and {\tt 3} for chevrons. \item The {\tt inputMode} parameter defines the mode of input. Valid values are {\tt 0} for indices only, {\tt 1} for real entries and {\tt 2} for complex entries. \item The {\tt inInpMtxFile} parameter is the name of the file that contain the {\tt InpMtx} object. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testSplitDenseMtx msglvl msgFile nrow ncol inc1 inc2 seed \end{verbatim} This driver program tests the distributed {\tt DenseMtx\_MPI\_splitByRows()} method to split or redistribute by rows a {\tt DenseMtx} dense matrix object. Process zero generates the {\tt DenseMtx} object. It is then split among the processes using a wrap map. A random map is generated (the same map on all processes) and the object is redistributed using this random map. Use the script file {\tt do\_SplitDenseMtx} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt nrow} parameter is the number of rows for the matrix. \item The {\tt ncol} parameter is the number of columns for the matrix. \item The {\tt inc1} parameter is the row increment for the matrix. Valid values are {\tt 1} for column major and {\tt ncol} for row major. \item The {\tt inc2} parameter is the column increment for the matrix. Valid values are {\tt 1} for row major and {\tt nrow} for column major. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testSplitInpMtx msglvl msgFile neqns seed coordType inputMode inInpMtxFile \end{verbatim} This driver program tests the distributed {\tt InpMtx\_MPI\_split()} method to split or redistribute a {\tt InpMtx} sparse matrix object. Process zero reads in the {\tt InpMtx} object. It is then split among the processes using a wrap map. A random map is generated (the same map on all processes) and the object is redistributed using this random map. Use the script file {\tt do\_SplitInpMtx} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt neqns} parameter is the number of equations for the matrix. \item The {\tt seed} parameter is a random number seed. \item The {\tt coordType} parameter defines the coordinate type that will be used during the redistribution. Valid values are {\tt 1} for rows, {\tt 2} for columns and {\tt 3} for chevrons. \item The {\tt inputMode} parameter defines the mode of input. Valid values are {\tt 0} for indices only, {\tt 1} for real entries and {\tt 2} for complex entries. \item The {\tt inInpMtxFile} parameter is the name of the file that contain the {\tt InpMtx} object. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testSymbFac msglvl msgFile inGraphFile inETreeFile seed \end{verbatim} This driver program tests the distributed {\tt SymbFac\_MPI\_initFromInpMtx()} method that forms a {\tt IVL} object that contains the necessary parts of a symbolic factorization for each processor. The program reads in the global {\tt Graph} and {\tt ETree} objects. Each processor creates a global {\tt InpMtx} object from the structure of the graph and computes a global symbolic factorization object using the serial {\tt SymbFac\_initFromInpMtx()} method. The processors then compute a map from fronts to processors, and each processor throws away the unowned matrix entries from the {\tt InpMtx} object. The processors then compute their necessary symbolic factorizations in parallel. For a check, they compare the two symbolic factorizations for error. Use the script file {\tt do\_symbfac} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} batim} testMMM msglvl msgFile nrowA ncolA nentA ncolX coordType inputMode symflag opflag seed real imag \end{verbatim} This driver program tests the distributed matrix-matrix multiply $Y := Y + \alpha A X$, $Y := Y + \alpha A^T X$ or $Y := Y + \alpha A^H X$. ProcesMPI/doc/intro.tex010064400020550007177000000022210655671743400151560ustar00clevecompmath00000400000006\chapter{{\tt MPI} directory} \label{chapter:MPI} \par All methods that use MPI constructs are found in this directory. There are a remarkably small number when one considers that the numeric functionality of this library has been extended to a distributed memory system. Most of the necessary data structures exist equally well as a {\it global} object for a serial or multithreaded application or as a {\it distributed} object for a distributed memory application. \par There is very little new numeric code in this directory. The ``chores'' --- what is done and how --- is unchanged from the serial codes. The ``choreography'' --- who does what when --- is unchanged from the multithreaded codes. All that was necessary to add the explicit message passing demanded by the MPI environment. \par All communication is ``safe'', meaning that the programs will complete when using an MPI implementation that conforms to the standard. We use non-blocking communication, i.e., communication calls that are guaranteed to complete, namely {\tt MPI\_Alltoall()}, {\tt MPI\_Sendrecv()}, {\tt MPI\_Bcast()}, {\tt MPI\_Allgather()}, {\tt MPI\_Irecv()} and {\tt MPI\_Isend()}. MPI/doc/main.tex010064400020550007177000000014230665022652100147350ustar00clevecompmath00000400000006% % main TeX file % % \documentstyle[leqno,11pt,twoside]{report} \documentclass[leqno,10pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \newcommand\bnd[1]{\partial{#1}} \newcommand\WHILE{{\bf while}} \newcommand\IF{{\bf if}} \newcommand\END{{\bf end}} \newcommand\ELSE{{\bf else}} \newcommand\THEN{{\bf then}} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt MPI} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt MPI} : {\it DRAFT} \quad \today \hrulefill} \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} pt minus 1 pt \makeindex \begin{document} \newcommand\bnd[1]{\partial{#1}} \newcommand\WHILE{{\bf while}} \newcommand\IF{{\bf if}} \newcommand\END{{\bf end}} \newcommand\ELSE{{\bf else}} \newcommand\THEN{{\bf then}} \pagestyle{myheadMPI/doc/proto.tex010064400020550007177000001262000665022722600151600ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt MPI} methods} \label{section:MPI:proto} \par This section contains brief descriptions including prototypes of all methods found in the {\tt MPI} source directory. \par \subsection{Split and redistribution methods} \label{subsection:MPI:proto:split} \par %======================================================================= In a distributed environment, data must be distributed, and sometimes during a computation, data must be re-distributed. These methods split and redistribute four data objects. \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_MPI_splitByRows ( DenseMtx *mtx, IV *mapIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{DenseMtx_MPI_splitByRows@{\tt DenseMtx\_MPI\_splitByRows()}} This method splits and redistributes the {\tt DenseMtx} object based on the {\tt mapIV} object that maps rows to processes. The messages that will be sent require {\tt nproc} consecutive tags --- the first is the parameter {\tt firsttag}. On return, the {\tt stats[]} vector contains the following information. \par \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par Note, the values in {\tt stats[]} are {\it incremented}, i.e., the {\tt stats[]} vector is not zeroed at the start of the method, and so can be used to accumulated information with multiple calls. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt rowmapIV} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} DenseMtx * DenseMtx_MPI_splitFromGlobalByRows ( DenseMtx *Xglobal, DenseMtx *Xlocal, IV *rowmapIV, int root, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{DenseMtx_MPI_splitFromGlobalByRows@{\tt DenseMtx\_MPI\_splitFromGlobalByRows()}} This method is used when the {\tt Xglobal} {\tt DenseMtx} matrix object is owned by processor {\tt root} and redistributed to the other processors. \par {\tt Xglobal} is pertinent only to processor {\tt root}. If the local matrix {\tt Xlocal} is {\tt NULL}, and if the local matrix will be nonempty, then it is created. If the local matrix is not {\tt NULL}, then it will be returned. The remaining input arguments are the same as for the {\tt DenseMtx\_MPI\_splitByRows()} method. \par \noindent {\it Error checking:} Processor {\tt root} does a fair amount of error checking --- it ensures that {\tt Xglobal} is valid, that {\tt firsttag} is valid, and that the {\tt rowmapIV} object is valid. The return code is broadcast to the other processors. If an error is found, the processors call {\tt MPI\_Finalize()} and exit. %----------------------------------------------------------------------- \item \begin{verbatim} DenseMtx * DenseMtx_MPI_mergeToGlobalByRows ( DenseMtx *Xglobal, DenseMtx *Xlocal, IV *rowmapIV, int root, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{DenseMtx_MPI_mergeToGlobalByRows@{\tt DenseMtx\_MPI\_mergeToGlobalByRows()}} This method is used when the processors own a partitioned {\tt DenseMtx} object and it must be assembled onto the {\tt root} processor. Each processor owns a {\tt Xlocal} matrix (which may be {\tt NULL}). The global matrix will be accumulated in the {\tt Xglobal} object. \par {\tt Xglobal} is pertinent only to processor {\tt root}. If the global matrix {\tt Xglobal} is {\tt NULL}, and if the global matrix will be nonempty, then it is created. If the global matrix is not {\tt NULL}, then it will be returned. The remaining input arguments are the same as for the {\tt DenseMtx\_MPI\_splitByRows()} method. \par \noindent {\it Error checking:} Each processor does a fair amount of error checking --- they ensure that {\tt firsttag} is valid, that the types of the local matrices are identical, and that the number of columns of the local matrices are identical, If there is any error detected by any of the processors, they call {\tt MPI\_Finalize()} and exit. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_MPI_split ( InpMtx *inpmtx, IV *mapIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{InpMtx_MPI_split@{\tt InpMtx\_MPI\_split()}} This method splits and redistributes the {\tt InpMtx} object based on the {\tt mapIV} object that maps the {\tt InpMtx} object's vectors (rows, columns or chevrons) to processes. The the vectors are defined by the first coordinate of the {\tt InpMtx} object. For the distributed $LU$, $U^TDU$ and $U^HDU$ factorizations, we use the chevron coordinate type to store the matrix entries. This method will redistribute a matrix by rows if the coordinate type is {\tt 1} (for rows) and {\tt mapIV} is a row map. Similarly, this method will redistribute a matrix by columns if the coordinate type is {\tt 2} (for columns) and {\tt mapIV} is a column map. See the {\tt InpMtx} object for details. The messages that will be sent require {\tt nproc} consecutive tags --- the first is the parameter {\tt firsttag}. On return, the {\tt stats[]} vector contains the following information. \par \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par Note, the values in {\tt stats[]} are {\it incremented}, i.e., the {\tt stats[]} vector is not zeroed at the start of the method, and so can be used to accumulated information with multiple calls. \par \noindent {\it Error checking:} If {\tt firsttag < 0} or {\tt firsttag + nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} InpMtx * InpMtx_MPI_splitFromGlobal ( InpMtx *Aglobal, InpMtx *Alocal, IV *mapIV, int root, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{InpMtx_MPI_splitFromGlobal@{\tt InpMtx\_MPI\_splitFromGlobal()}} This method is used when the {\tt Aglobal} {\tt InpMtx} matrix object is owned by processor {\tt root} and redistributed to the other processors. \par {\tt Aglobal} is pertinent only to processor {\tt root}. If the local matrix {\tt Alocal} is {\tt NULL}, and if the local matrix will be nonempty, then it is created. If the local matrix is not {\tt NULL}, then it will be returned. The remaining input arguments are the same as for the {\tt InpMtx\_MPI\_split()} method. \par \noindent {\it Error checking:} Processor {\tt root} does a fair amount of error checking --- it ensures that {\tt Aglobal} is valid, that {\tt firsttag} is valid, and that the {\tt mapIV} object is valid. The return code is broadcast to the other processors. If an error is found, the processors call {\tt MPI\_Finalize()} and exit. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_MPI_split ( Pencil *pencil, IV *mapIV, int tag, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{Pencil_MPI_split@{\tt Pencil\_MPI\_split()}} This method splits and redistributes the matrix pencil based on the {\tt mapIV} object that maps rows and columns to processes. This is a simple wrapper around the {\tt InpMtx\_MPI\_split()} method. The messages that will be sent require {\tt 2*nproc} consecutive tags --- the first is the parameter {\tt firsttag}. On return, the {\tt stats[]} vector contains the following information. \par \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par Note, the values in {\tt stats[]} are {\it incremented}, i.e., the {\tt stats[]} vector is not zeroed at the start of the method, and so can be used to accumulated information with multiple calls. \par \noindent {\it Error checking:} If {\tt firsttag < 0} or {\tt firsttag + 2*nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_MPI_split ( FrontMtx *frontmtx, SolveMap *solvemap, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_split@{\tt FrontMtx\_MPI\_split()}} Used after the factorization, this method is used instead of the {\tt FrontMtx\_splitUpperMatrices()} and {\tt FrontMtx\_splitLowerMatrices()} methods. The method splits and redistributes the {\tt FrontMtx} object based on the {\tt solvemap} object that maps submatrices to processes. The {\tt firsttag} is the first tag that will be used for all messages. Unfortunately, the number of different tags that are necessary is not known prior to entering this method. On return, the {\tt stats[]} vector contains the following information. \par \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par Note, the values in {\tt stats[]} are {\it incremented}, i.e., the {\tt stats[]} vector is not zeroed at the start of the method, and so can be used to accumulated information with multiple calls. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt rowmapIV} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt firsttag < 0} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Gather and scatter methods} \label{subsection:MPI:proto:gather-scatter} \par %======================================================================= These method gather and scatter/add rows of {\tt DenseMtx} objects. These operations are performed during the distributed matrix-matrix multiply. The gather operation $X_{supp}^q \leftarrow X$ is performed by {\tt DenseMtx\_MPI\_gatherRows()}, while the scatter/add operation $Y^q := Y^q + \sum_r Y_{supp}^r$ is performed by {\tt DenseMtx\_MPI\_scatterAddRows()}. \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_MPI_gatherRows ( DenseMtx *Y, DenseMtx *X, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm) ; \end{verbatim} \index{DenseMtx_MPI_gatherRows@{\tt DenseMtx\_MPI\_gatherRows()}} This method is used to gather rows of {\tt X}, a globally distributed matrix, into {\tt Y}, a local matrix. List $q$ of {\tt sendIVL} contains the local row ids of the local part of {\tt X} that will be sent to processor $q$. List $q$ of {\tt recvIVL} contains the local row ids of {\tt Y} that will be received from processor $q$. \par This method uses tags in the range {\tt [tag,tag+nproc*nproc)}. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method is {\it safe} in the sense that it uses only non-blocking sends and receives, {\tt MPI\_Isend()} and {\tt MPI\_Irecv()}. \par \noindent {\it Error checking:} If {\tt Y}, {\tt X}, {\tt sendIVL} or {\tt recvIVL} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag + nproc*nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void DenseMtx_MPI_scatterAddRows ( DenseMtx *Y, DenseMtx *X, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm) ; \end{verbatim} \index{DenseMtx_MPI_scatterAddRows@{\tt DenseMtx\_MPI\_scatterAddRows()}} This method is used to scatter/add rows of {\tt X}, a globally distributed matrix, into {\tt Y}, a local matrix. List $q$ of {\tt sendIVL} contains the local row ids of the local part of {\tt X} that will be sent to processor $q$. List $q$ of {\tt recvIVL} contains the local row ids of {\tt Y} that will be received from processor $q$. \par This method uses tags in the range {\tt [tag,tag+nproc*nproc)}. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method is {\it safe} in the sense that it uses only non-blocking sends and receives, {\tt MPI\_Isend()} and {\tt MPI\_Irecv()}. \par \noindent {\it Error checking:} If {\tt Y}, {\tt X}, {\tt sendIVL} or {\tt recvIVL} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag + nproc*nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Symbolic Factorization methods} \label{subsection:MPI:proto:symbfac} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IVL * SymbFac_MPI_initFromInpMtx ( ETree *etree, IV *frontOwnersIV, InpMtx *inpmtx, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; IVL * SymbFac_MPI_initFromPencil ( ETree *etree, IV *frontOwnersIV, Pencil *pencil, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{SymbFac_MPI_initFromInpMtx@{\tt SymbFac\_MPI\_initFromInpMtx()}} \index{SymbFac_MPI_initFromPencil@{\tt SymbFac\_MPI\_initFromPencil()}} These methods are used in place of the {\tt Symbfac\_initFrom\{InpMtx,Pencil\}()} methods to compute the symbolic factorization. The {\tt ETree} object is assumed to be replicated over the processes. The {\tt InpMtx} and {\tt Pencil} objects are partitioned among the processes. Therefore, to compute the {\tt IVL} object that contains the symbolic factorization is a distributed, cooperative process. At the end of the symbolic factorization, each process will own a portion of the {\tt IVL} object. The {\tt IVL} object is neither replicated nor partitioned (except in trivial cases), but the {\tt IVL} object on each process contains just a portion, usually not much more than what it needs to know for its part of the factorization and solves. \par This method uses tags in the range {\tt [tag,tag+nfront)}. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method is {\it safe} in the sense that it uses only non-blocking sends and receives, {\tt MPI\_Isend()} and {\tt MPI\_Irecv()}. \par \noindent {\it Error checking:} If {\tt etree}, {\tt inpmtx}, {\tt pencil} or {\tt frontOwnersIV} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag + nfront} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Numeric Factorization methods} \label{subsection:MPI:proto:factor} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Chv * FrontMtx_MPI_factorPencil ( FrontMtx *frontmtx, Pencil *pencil, double tau, double droptol, ChvManager *chvmanager, IV *frontOwnersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; Chv * FrontMtx_MPI_factorInpMtx ( FrontMtx *frontmtx, InpMtx *inpmtx, double tau, double droptol, ChvManager *chvmanager, IV *frontOwnersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_factorPencil@{\tt FrontMtx\_MPI\_factorPencil()}} \index{FrontMtx_MPI_factorInpMtx@{\tt FrontMtx\_MPI\_factorInpMtx()}} These methods are used to compute the numeric factorization and are very similar to the multithreaded {\tt FrontMtx\_MT\_factorPencil()} and {\tt FrontMtx\_MT\_factorInpMtx()} methods. All that has been added is the code to send and receive the {\tt Chv} messages. The input {\tt firsttag} parameter is used to tag the messages during the factorization. This method uses tags in the range {\tt [firsttag, firsttag + 3*nfront + 3)}. \par On return, {\tt *perror} holds an error flag. If the factorization completed without any error detected, {\tt *perror} will be negative. Otherwise it holds the id of a front where the factorization failed. Currently, this can happen only if pivoting is not enabled and a zero pivot was detected. \par The return value is a pointer to a list of {\tt Chv} objects that hold entries of the matrix that could not be factored. This value should be {\tt NULL} in all cases. We have left this return behavior as a hook for future implementation of a multi-stage factorization. \par On return, the {\tt cpus[]} vector has the following information. \begin{center} \begin{tabular}{ccl} {\tt cpus[0]} & -- & initialize fronts \\ {\tt cpus[1]} & -- & load original entries \\ {\tt cpus[2]} & -- & update fronts \\ {\tt cpus[3]} & -- & insert aggregate data \\ {\tt cpus[4]} & -- & assemble aggregate data \\ {\tt cpus[5]} & -- & assemble postponed data \\ {\tt cpus[6]} & -- & factor fronts \end{tabular} \begin{tabular}{ccl} {\tt cpus[7]} & -- & extract postponed data \\ {\tt cpus[8]} & -- & store factor entries \\ {\tt cpus[9]} & -- & post initial receives \\ {\tt cpus[10]} & -- & check for received messages \\ {\tt cpus[11]} & -- & post initial sends \\ {\tt cpus[12]} & -- & check for sent messages \end{tabular} \end{center} On return, the {\tt stats[]} vector has the following information. \begin{center} \begin{tabular}{ccl} {\tt stats[0]} & --- & \# of pivots \\ {\tt stats[1]} & --- & \# of pivot tests \\ {\tt stats[2]} & --- & \# of delayed rows and columns \\ {\tt stats[3]} & --- & \# of entries in D \\ {\tt stats[4]} & --- & \# of entries in L \\ {\tt stats[5]} & --- & \# of entries in U \\ {\tt stats[6]} & --- & \# of aggregate messages sent \\ {\tt stats[7]} & --- & \# of bytes sent in aggregate messages \\ {\tt stats[8]} & --- & \# of aggregate messages received \\ {\tt stats[9]} & --- & \# of bytes received in aggregate messages \\ {\tt stats[10]} & --- & \# of postponed messages sent \\ {\tt stats[11]} & --- & \# of bytes sent in postponed messages \\ {\tt stats[12]} & --- & \# of postponed messages received \\ {\tt stats[13]} & --- & \# of bytes received in postponed messages \\ {\tt stats[14]} & --- & \# of active {\tt Chv} objects (working storage) \\ {\tt stats[15]} & --- & \# of active bytes in working storage \\ {\tt stats[16]} & --- & \# of requested bytes for working storage \end{tabular} \end{center} \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt pencil}, {\tt frontOwnersIV}, {\tt cpus} or {\tt stats} is {\tt NULL}, or if {\tt tau < 1.0} or {\tt droptol < 0.0}, or if {\tt firsttag < 0} or {\tt firsttag + 3*nfront + 2} is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Post-processing methods} \label{subsection:MPI:proto:postprocess} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_MPI_postProcess ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_postProcess@{\tt FrontMtx\_MPI\_postProcess()}} After the factorization is complete, the factor matrices are split into submatrices. This method replaces the serial {\tt FrontMtx\_postProcess()} method. The messages that will be sent require at most {\tt 5*nproc} consecutive tags --- the first is the parameter {\tt firsttag}. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt frontOwnersIV} or {\tt stats} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + 5*nproc}, is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_MPI_permuteUpperAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; void FrontMtx_MPI_permuteLowerAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_permuteUpperAdj@{\tt FrontMtx\_MPI\_permuteUpperAdj()}} \index{FrontMtx_MPI_permuteLowerAdj@{\tt FrontMtx\_MPI\_permuteLowerAdj()}} If pivoting takes place during the factorization, the off diagonal blocks of the factor matrices must be permuted prior to being split into submatrices. To do this, the final rows and columns of the factor matrix must be made known to the different processors. The messages that will be sent require at most {\tt nproc} consecutive tags --- the first is the parameter {\tt firsttag}. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt frontOwnersIV} or {\tt stats} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + nproc}, is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IV_MPI_allgather ( IV *iv, IV *ownersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{IV_MPI_allgather@{\tt IV\_MPI\_allgather()}} After a factorization with pivoting, the {\tt frontsizesIV} object needs to be made global on each processor. This methods takes the individual entries of an {\tt IV} object whose owners are specified by the {\tt ownersIV} object, and communicates the entries around the processors until the global {\tt IV} object is present on each. The messages that will be sent require at most {\tt nproc} consecutive tags --- the first is the parameter {\tt firsttag}. \par \noindent {\it Error checking:} If {\tt iv}, {\tt ownersIV} or {\tt stats} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + nproc}, is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVL_MPI_allgather ( IVL *ivl, IV *ownersIV, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{IVL_MPI_allgather@{\tt IVL\_MPI\_allgather()}} When the {\tt FrontMtx} object is split into submatrices, each processor accumulates the structure of the block matrix for the fronts its owns. This structure must be global to all processors before the submatrix map can be computed. This method takes a {\it partitioned} {\tt IVL} object and communicates the entries among the processors until the global {\tt IVL} object is present on each. Which processor owns what lists of the {\tt IVL} object is given by the {\tt ownersIV} object. The messages that will be sent require at most {\tt nproc} consecutive tags --- the first is the parameter {\tt firsttag}. \par \noindent {\it Error checking:} If {\tt ivl}, {\tt ownersIV} or {\tt stats} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + nproc}, is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Numeric Solve methods} \label{subsection:MPI:proto:solve} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_MPI_solve ( FrontMtx *frontmtx, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, SolveMap *solvemap, double cpus[], int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_solve@{\tt FrontMtx\_MPI\_solve()}} This method is used to compute the forward and backsolves. Its structure is very, very similar to the multithreaded {\tt FrontMtx\_MT\_solve()} method. All that has been added is the code to send and receive the {\tt SubMtx} messages. The method uses tags in the range {\tt [firsttag, firsttag + 2*nfront)}. On return, the {\tt cpus[]} vector has the following information. \begin{center} \begin{tabular}{ccl} {\tt cpus[0]} & --- & setup the solves \\ {\tt cpus[1]} & --- & load rhs and store solution \\ {\tt cpus[2]} & --- & forward solve \end{tabular} \begin{tabular}{ccl} {\tt cpus[3]} & --- & diagonal solve \\ {\tt cpus[4]} & --- & backward solve \\ {\tt cpus[5]} & --- & miscellaneous \end{tabular} \end{center} On return, the following statistics will have been added. \begin{center} \begin{tabular}{ccl} {\tt stats[0]} & --- & \# of solution messages sent \\ {\tt stats[1]} & --- & \# of aggregate messages sent \\ {\tt stats[2]} & --- & \# of solution bytes sent \\ {\tt stats[3]} & --- & \# of aggregate bytes sent \\ {\tt stats[4]} & --- & \# of solution messages received \\ {\tt stats[5]} & --- & \# of aggregate messages received \\ {\tt stats[6]} & --- & \# of solution bytes received \\ {\tt stats[7]} & --- & \# of aggregate bytes received \end{tabular} \end{center} \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt mtxX}, {\tt mtxB}, {\tt mtxmanager}, {\tt solvemap}, {\tt cpus} or {\tt stats} is {\tt NULL}, or if {\tt firsttag < 0} or {\tt firsttag + 2*nfront} is larger than the largest available tag, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Matrix-matrix multiply methods} \label{subsection:MPI:proto:mmm} \par The usual sequence of events is as follows. \begin{itemize} \item Set up the data structure via a call to {\tt MatMul\_MPI\_setup()}. \item Convert the local $A^q$ matrix to local indices via a call to {\tt MatMul\_setLocalIndices()}. \item Compute the matrix-matrix multiply with a call to {\tt MatMul\_MPI\_mmm()}. Inside this method, the MPI methods {\tt DenseMtx\_MPI\_gatherRows()} and {\tt DenseMtx\_MPI\_scatterAddRows()} are called, along with a serial {\tt InpMtx} matrix-matrix multiply method. \item Clean up and free data structures via a call to {\tt MatMul\_cleanup().} \item Convert the local $A^q$ matrix to global indices via a call to {\tt MatMul\_setGlobalIndices()}. \end{itemize} \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} MatMulInfo * MatMul_MPI_setup ( InpMtx *A, int symflag, int opflag, IV *XownersIV, IV *YownersIV int stats[], int msglvl, FILE *msgFile, MPI_Comm comm) ; \end{verbatim} \index{MatMul_MPI_setup@{\tt MatMul\_MPI\_setup()}} This method is used to set up and return the {\tt MatMulInfo} data structure that stores the information for the distributed matrix-matrix multiply. The {\tt symflag} parameter specifies the symmetry of the matrix. \begin{itemize} \item 0 ({\tt SPOOLES\_SYMMETRIC}) \item 1 ({\tt SPOOLES\_HERMITIAN}) \item 2 ({\tt SPOOLES\_NONSYMMETRIC}) \end{itemize} The {\tt opflag} parameter specifies what type of operation will be performed. \begin{itemize} \item 0 ({\tt MMM\_WITH\_A}) --- $Y := Y + \alpha A X$ \item 1 ({\tt MMM\_WITH\_AT}) --- $Y := Y + \alpha A^T X$ \item 2 ({\tt MMM\_WITH\_AH}) --- $Y := Y + \alpha A^H X$ \end{itemize} The {\tt XownersIV} object is the map from the rows of $X$ to their owning processors. The {\tt YownersIV} object is the map from the rows of $Y$ to their owning processors. \par On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method calls {\tt makeSendRecvIVLs()}. \par \noindent {\it Error checking:} If {\tt A}, {\tt XownersIV}, {\tt YownersIV} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MatMul_setLocalIndices ( MatMulInfo *info, InpMtx *A ) ; void MatMul_setGlobalIndices ( MatMulInfo *info, InpMtx *A ) ; \end{verbatim} \index{MatMul_setLocalIndices@{\tt MatMul\_setLocalIndices()}} \index{MatMul_setGlobalIndices@{\tt MatMul\_setGlobalIndices()}} The first method maps the indices of {\tt A} (which are assumed to be global) into local indices. The second method maps the indices of {\tt A} (which are assumed to be local) back into global indices. It uses the {\tt XmapIV}, {\tt XsupIV} {\tt YmapIV} and {\tt YsupIV} objects that are contained in the {\tt info} object. These are serial methods, performed independently on each processor. \par \noindent {\it Error checking:} If {\tt info} or {\tt A} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MatMul_MPI_mmm ( MatMulInfo *info, DenseMtx *Yloc, double alpha[], InpMtx *A, DenseMtx *Xloc, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm) ; \end{verbatim} \index{MatMul_MPI_mmm@{\tt MatMul\_MPI\_mmm()}} This method computes a distributed matrix-matrix multiply $Y := Y + \alpha A X$, $Y := Y + \alpha A^T X$ or $Y := Y + \alpha A^H X$, depending on how the {\tt info} object was set up. NOTE: {\tt A} must have local indices, use {\tt MatMul\_setLocalIndices()} to convert from global to local indices. {\tt Xloc} and {\tt Yloc} contain the owned rows of $X$ and $Y$, respectively. \par On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method calls {\tt makeSendRecvIVLs()}. \par \noindent {\it Error checking:} If {\tt info}, {\tt Yloc}, {\tt alpha}, {\tt A}, {\tt Xloc} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MatMul_cleanup ( MatMulInfo *info ) ; \end{verbatim} \index{MatMul_cleanup@{\tt MatMul\_cleanup()}} This method free's the data structures owned by the {\tt info} object, and then free's the object. processor. \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Broadcast methods} \label{subsection:MPI:proto:broadcast} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} ETree * ETree_MPI_Bcast ( ETree *etree, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{ETree_MPI_Bcast@{\tt ETree\_MPI\_Bcast()}} This method is a broadcast method for an {\tt ETree} object. The {\tt root} processor broadcasts its {\tt ETree} object to the other nodes and returns a pointer to its {\tt ETree} object. A node other than {\tt root} free's its {\tt ETree} object (if not {\tt NULL}), receives {\tt root}'s {\tt ETree} object, and returns a pointer to it. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} Graph * Graph_MPI_Bcast ( Graph *etree, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{Graph_MPI_Bcast@{\tt Graph\_MPI\_Bcast()}} This method is a broadcast method for an {\tt Graph} object. The {\tt root} processor broadcasts its {\tt Graph} object to the other nodes and returns a pointer to its {\tt Graph} object. A node other than {\tt root}, clears the data in its Graph object, receives the Graph object from the root and returns a pointer to it. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * IVL_MPI_Bcast ( IVL *obj, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{IVL_MPI_Bcast@{\tt IVL\_MPI\_Bcast()}} This method is a broadcast method for an {\tt IVL} object. The {\tt root} processor broadcasts its {\tt IVL} object to the other nodes and returns a pointer to its {\tt IVL} object. A node other than {\tt root}, clears the data in its IVL object, receives the IVL object from the root and returns a pointer to it. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} IV * IV_MPI_Bcast ( IV *obj, int root, int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{IV_MPI_Bcast@{\tt IV\_MPI\_Bcast()}} This method is a broadcast method for an {\tt IV} object. The {\tt root} processor broadcasts its {\tt IV} object to the other nodes and returns a pointer to its {\tt IV} object. A node other than {\tt root}, clears the data in its IV object, receives the IV object from the root and returns a pointer to it. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:MPI:proto:utility} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IVL * InpMtx_MPI_fullAdjacency ( InpMtx *inpmtx, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm ) ; IVL * Pencil_MPI_fullAdjacency ( Pencil *pencil, int stats[], int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{InpMtx_MPI_fullAdjacency@{\tt InpMtx\_MPI\_fullAdjacency()}} \index{Pencil_MPI_fullAdjacency@{\tt Pencil\_MPI\_fullAdjacency()}} These methods are used to return an {\tt IVL} object that contains the full adjacency structure of the graph of the matrix or matrix pencil. The matrix or matrix pencil is distributed among the processes, each process has a {\it local} portion of the matrix or matrix pencil. The returned {\tt IVL} object contains the structure of the global graph. The {\tt stats[]} vector must have at least four fields. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par \noindent {\it Error checking:} If {\tt inpmtx}, {\tt pencil} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ChvList * FrontMtx_MPI_aggregateList ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[], int msglvl, FILE *msgFile, int tag, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_aggregateList@{\tt FrontMtx\_MPI\_aggregateList()}} This method is used in place of the {\tt FrontMtx\_aggregateList()} method to initialize the aggregate list object. Since the symbolic factorization data is distributed among the processes, the number of incoming aggregates for a front and the number of different processes contributing to a front --- information necessary to initialize the list object --- must be computed cooperatively. This method uses {\tt tag} as the message tag for all messages communicated during this method. The {\tt stats[]} vector must have at least four fields. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} \par \noindent {\it Error checking:} If {\tt frontmtx} or {\tt frontOwnersIV} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * FrontMtx_MPI_colmapIV ( FrontMtx *frontmtx, IV *frontOwnersIV, int msglvl, FILE *msgFile, MPI_Comm comm ) ; IV * FrontMtx_MPI_rowmapIV ( FrontMtx *frontmtx, IV *frontOwnersIV, int msglvl, FILE *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{FrontMtx_MPI_colmapIV@{\tt FrontMtx\_MPI\_colmapIV()}} \index{FrontMtx_MPI_rowmapIV@{\tt FrontMtx\_MPI\_rowmapIV()}} For a factorization with pivoting, the elimination of some rows and columns may be delayed from the front that initially contains them to an ancestor front. The solution and right hand side entries would therefore need to be redistributed. To do so requires new row and column maps, maps from the row or column to the processor that owns them. These two methods construct that map. The routine uses the {\tt MPI\_Allgather()} and {\tt MPI\_Bcast()} methods, so no unique tag values are needed. \par \noindent {\it Error checking:} None at present. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * IVL_MPI_alltoall ( IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{InpMtx_MPI_alltoall@{\tt InpMtx\_MPI\_alltoall}} This method is used during the setup for matrix-vector multiplies. Each processor has computed the vertices it needs from other processors, these lists are contained in {\tt sendIVL}. On return, {\tt recvIVL} contains the lists of vertices this processor must send to all others. \par This method uses tags in the range {\tt [tag,tag+nproc-1)}. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method is {\it safe} in the sense that it uses only {\tt MPI\_Sendrecv()}. \par \noindent {\it Error checking:} If {\tt sendIVL} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag + nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void * makeSendRecvIVLs ( IV *supportedIV, IV *globalmapIV, IVL *sendIVL, IVL *recvIVL, int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ; \end{verbatim} \index{makeSendRecvIVLs@{\tt makeSendRecvIVLs}} \par The purpose of this method to analyze and organize communication. It was written in support of a distributed matrix-vector multiply but can be used for other applications. \par Each processor has a list of items it "supports" or needs found in the {\tt supportedIV} object. The {\tt globalmapIV} object contains the map from items to owning processors. We need to figure out what items this processor will send to and receive from each other processor. This information is found in the {\tt sendIVL} and {\tt recvIVL} objects. \par On return, list {\tt jproc} of {\tt sendIVL} contains the items owned by this processor and needed by {\tt jproc}. On return, list {\tt jproc} of {\tt recvIVL} contains the items needed by this processor and owned by {\tt jproc}. \par This method initializes the {\tt recvIVL} object, and then calls {\tt IVL\_MPI\_alltoall()} to construct the {\tt sendIVL} object. This method uses tags in the range {\tt [tag,tag+nproc*nproc)}. On return, the following statistics will have been added. \begin{center} \begin{tabular}{cclcccl} {\tt stats[0]} & --- & \# of messages sent & & {\tt stats[1]} & --- & \# of bytes sent \\ {\tt stats[2]} & --- & \# of messages received & & {\tt stats[3]} & --- & \# of bytes received \end{tabular} \end{center} This method is {\it safe} in the sense that it uses only {\tt MPI\_Sendrecv()}. \par \noindent {\it Error checking:} If {\tt sendIVL} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, or if {\tt tag < 0} or {\tt tag + nproc} is larger than the largest available tag, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int maxTagMPI ( MPI_Comm comm) ; \end{verbatim} \index{maxTagMPI@{\tt maxTagMPI()}} This method returns the maximum tag value for the communicator {\tt comm}. \par \noindent {\it Error checking:} None at present. %----------------------------------------------------------------------- \end{enumerate} \par *msgFile, MPI_Comm comm ) ; \end{verbatim} \index{ETree_MPI_Bcast@{\tt ETree\_MPI\_Bcast()}} This method is a broadcast method for an {\tt ETree} object. The {\tt root} processor broadcasts its {\tt ETree} object to the other nodes and returns a pointer to its {\tt ETree} object. A node other than {\tt root} free's its {\tt ETree} object (if not {\tt NULL}), receives {\tt root}'s {MPI/doc/solve.tex010064400020550007177000000237560655671743400151730ustar00clevecompmath00000400000006\section{{\tt DChvMtx}: Double Precision Chevron Matrix Object} \par Let $A$ be an $n \times n$ matrix to be factored. We are going to allow both row and column permutations as the factorization proceeds, and our pivot blocks may be larger than $1 \times 1$ pivots. After the first step we have $$ A = A_0 = P_0 \left \lbrack \begin{array}{cc} I & 0 \\ {\hat L}_0 & I \end{array} \right \rbrack \left \lbrack \begin{array}{cc} I & 0 \\ 0 & {\hat A}_1 \end{array} \right \rbrack \left \lbrack \begin{array}{cc} {\hat D}_0 & {\hat U}_0 \\ 0 & I \end{array} \right \rbrack Q_0 = P_0 \ L_0 \ A_1 \ U_0 \ Q_0 $$ where $P_0$ is the row permutation matrix, ${\hat D}_0$ is the pivot block, $\displaystyle L_0 = \left \lbrack \begin{array}{cc} I & 0 \\ {\hat L}_0 & I \end{array} \right \rbrack $, $\displaystyle A_1 = \left \lbrack \begin{array}{cc} I & 0 \\ 0 & {\hat A}_1 \end{array} \right \rbrack $, $\displaystyle U_0 = \left \lbrack \begin{array}{cc} {\hat D}_0 & {\hat U}_0 \\ 0 & I \end{array} \right \rbrack $ and $Q_0$ is the column permutation matrix. Now $A_1$ can be factored in the same manner, $$ A_1 = P_1 \left \lbrack \begin{array}{cc} I & 0 \\ {\hat L}_1 & I \end{array} \right \rbrack \left \lbrack \begin{array}{cc} I & 0 \\ 0 & {\hat A}_2 \end{array} \right \rbrack \left \lbrack \begin{array}{cc} {\hat D}_1 & {\hat U}_1 \\ 0 & I \end{array} \right \rbrack Q_1 = P_1 \ L_1 \ A_2 \ U_1 \ Q_1 $$ so we can expand $A_0$ to find $A = P_0 \ L_0 \ P_1 \ L_1 \ A_2 \ U_1 \ Q_1 \ U_0 \ Q_0$. Eventually the factorization proceeds to completion and we have $$ A = (P_0 \ L_0 \ P_1 \ L_1 \ \cdots \ P_k \ L_k) (U_K \ Q_k \ \cdots \ U_1 \ Q_1 \ U_0\ Q_0) $$ Note, $L_0, L_1, \ldots, L_k$ are all lower triangular, for it is the row permutation matrices that are responsible. Note that ${\tilde L}_i = P_i L_i$ is not a lower triangular matrix, but one can solve a linear system involving ${\tilde L}_i$ without any difficulty. A similar statement holds for ${\tilde U}_i = U_i Q_i$, except we have the presence of a block pivot ${\hat D}_i$. \par The key to understanding how we factor and solve linear systems using the {\tt DChvMtx} object is that the permutation matrices $P_i$ and $Q_i$ are held implicitly in ${\tilde L}_i$ and ${\tilde U}_i$, and we solve any linear system with ${\tilde L}_i$ and ${\tilde U}_i$ correctly, even though they are not triangular. We can write $A$ as $$ A = {\tilde L}_0 \ {\tilde L}_1 \ \cdots \ {\tilde L}_k \ {\tilde U}_k \ \cdots \ {\tilde U}_1 \ {\tilde U}_0 $$ and thus $A y = b$ by solving a sequence of linear systems ${\tilde L}_0 \ x^0 = b$, ${\tilde L}_1 \ x^1 = x^0$, $\cdots$, ${\tilde L}_k \ x^k = x^{k-1}$, ${\tilde U}_k \ y^k = x^k$, ${\tilde U}_{k-1} \ y^{k-1} = y^k$, $\cdots$, ${\tilde U}_1 \ y^1 = y^2$, ${\tilde U}_0 \ y = y^1$. % Here is a crucial point: % solving a linear system with ${\tilde L}_i$ requires % information about the row permutation at the $i$-th step, % but does not require any knowledge about the column permutation % at that or any other step. % A similar point holds for systems with ${\tilde U}_i$. \par Let us clarify the process with an example. At the first step we permute a $3 \times 3$ matrix so that the $a_{1,2}$ element is the pivot. \begin{eqnarray*} A & = & \left \lbrack \begin{array}{ccc} a_{0,0} & a_{0,1} & a_{0,2} \\ a_{1,0} & a_{1,1} & a_{1,2} \\ a_{2,0} & a_{2,1} & a_{2,2} \end{array} \right \rbrack = \left \lbrack \begin{array}{ccc} 0 & 1 & 0 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} a_{1,2} & a_{1,0} & a_{1,1} \\ a_{0,2} & a_{0,0} & a_{0,1} \\ a_{2,2} & a_{2,0} & a_{2,1} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 0 & 0 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{array} \right \rbrack \\ & = & \left \lbrack \begin{array}{ccc} 0 & 1 & 0 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ l_{0,2} & 1 & 0 \\ l_{2,2} & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & {\hat a}_{0,0} & {\hat a}_{0,1} \\ 0 & {\hat a}_{2,0} & {\hat a}_{2,1} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} d_{1,2} & u_{1,0} & u_{1,1} \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 0 & 0 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{array} \right \rbrack \\ & = & {\tilde L}_0 \ A_1 \ {\tilde U}_0 = \left \lbrack \begin{array}{ccc} l_{0,2} & 1 & 0 \\ 1 & 0 & 0 \\ l_{2,2} & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & {\hat a}_{0,0} & {\hat a}_{0,1} \\ 0 & {\hat a}_{2,0} & {\hat a}_{2,1} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} u_{1,0} & u_{1,1} & d_{1,2} \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{array} \right \rbrack \end{eqnarray*} We then do the same for $A_1$, using ${\hat a}_{2,1}$ as the pivot. \begin{eqnarray*} A_1 & = & \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & {\hat a}_{0,0} & {\hat a}_{0,1} \\ 0 & {\hat a}_{2,0} & {\hat a}_{2,1} \end{array} \right \rbrack = \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 0 & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & {\hat a}_{2,1} & {\hat a}_{2,0} \\ 0 & {\hat a}_{0,1} & {\hat a}_{0,0} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 0 & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \\ & = & \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 0 & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & l_{0,1} & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & {\hat a}_{2,1} & {\hat a}_{2,0} \\ 0 & {\hat a}_{0,1} & {\hat a}_{0,0} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & d_{2,1} & u_{2,0} \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 0 & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \\ & = & {\tilde L}_1 \ A_2 \ {\tilde U}_1 = \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & l_{0,1} & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & {\tilde a}_{0,0} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & u_{2,0} & d_{2,1} \\ 0 & 1 & 0 \end{array} \right \rbrack \end{eqnarray*} Finally, we have the factorization of $A_2$. $$ A_2 = P_2 \ L_2 \ U_2 \ Q_2 = \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & d_{0,0} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack $$ Written on one line we have the factorization of $A$ given below where ${\tilde L}_2 = I$ is omitted. \begin{eqnarray*} A & = & {\tilde L}_0 \ {\tilde L}_1 \ {\tilde U}_2 \ {\tilde U}_1 \ {\tilde U}_0 \\ & = & \left \lbrack \begin{array}{ccc} l_{0,2} & 1 & 0 \\ 1 & 0 & 0 \\ l_{2,2} & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & l_{0,1} & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & d_{0,0} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & u_{2,0} & d_{2,1} \\ 0 & 1 & 0 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} u_{1,0} & u_{1,1} & d_{1,2} \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{array} \right \rbrack \end{eqnarray*} At best this equation looks awkward, but take heart, it really doesn't describe how we store the entries or use them to solve a linear system. The entries can be logically grouped in terms of chevrons. $$ A^0 = \left \lbrack \begin{array}{ccc} d_{1,2} & u_{1,0} & u_{1,1} \\ l_{0,2} & 0 & 0 \\ l_{2,2} & 0 & 0 \end{array} \right \rbrack, \qquad A^1 = \left \lbrack \begin{array}{ccc} 0 & 0 & 0 \\ 0 & d_{2,1} & u_{2,0} \\ 0 & l_{0,1} & 0 \end{array} \right \rbrack, \qquad A^2 = \left \lbrack \begin{array}{ccc} 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & d_{0,0} \end{array} \right \rbrack, \qquad $$ For each chevron we store the indices of the rows and columns that are nonzero, and the entries in the diagonal, lower triangular and upper triangular block. Note, the row indices and the column indices need not be the same. \par Let us show how we solve a linear system. To solve $A x = b$ we first solve $L y = b$ and then solve $U x = y$ where $L = {\tilde L}_0 {\tilde L}_1 {\tilde L}_2$ and $U = {\tilde U}_2 {\tilde U}_1 {\tilde U}_0$. Note that there are no permutation matrices anywhere. \begin{itemize} \item To solve with ${\tilde L}_0$ we set $y_1 = b_1$, $b_0 := b_0 - l_{0,2} y_1$ and $b_2 := b_2 - l_{2,2} y_1$. \item To solve with ${\tilde L}_1$ we set $y_2 = b_2$ and $b_0 := b_0 - l_{0,1} y_2$. \item To solve with ${\tilde L}_2$ we set $y_0 = b_0$. \item To solve with ${\tilde U}_2$ we set $x_0 = y_0/d_{0,0}$. \item To solve with ${\tilde U}_1$ we set $x_1 = (y_2 - u_{2,0}x_0)/d_{2,1}$. \item To solve with ${\tilde U}_0$ we set $x_2 = (y_1 - u_{1,0}x_0 - u_{1,1} x_1)/d_{1,2}$. \end{itemize} In general, let us write the $k$-th chevron as $$ A^2 = \left \lbrack \begin{array}{cc} D_{\alpha_k,\beta_k} & U_{\alpha_k,\delta_k} \\ L_{\gamma_k,\beta_k} & 0 \end{array} \right \rbrack $$ where $\alpha_k$ and $\gamma_k$ form the row index set and $\beta_k$ and $\delta_k$ form the column index set. Since the pivots partition the rows and columns, we have $$ \gamma_k \cap \bigcup_{i < k} \alpha_i = \emptyset \quad \mbox{and} \quad \delta_k \cap \bigcup_{i < k} \beta_i = \emptyset. $$ The forward solve and backward solve are executed by \begin{center} \begin{minipage}{3 in} \begin{tabbing} XXX\=XXX\=XXX\=\kill for $k = 1, \ldots, \mbox{\# of pivots}$ \\ \> $y_{\alpha_k} = b_{\alpha_k}$ \\ \> $b_{\gamma_k} := b_{\gamma_k} - L_{\gamma_k, \beta_k} y_{\alpha_k}$ \\ end for \\ for $k = \mbox{\# of pivots}, \ldots, 1$ \\ \> $y_{\alpha_k} = b_{\alpha_k}$ \\ \> $x_{\beta_k} := D_{\alpha_k, \beta_k}^{-1} (y_{\alpha_k} - U_{\alpha_k, \delta_k} x_{\delta_k})$ end for \end{tabbing} \end{minipage} \end{center} & 1 \\ 0 & 1 & 0 \MPI/doc/symbfac.tex010064400020550007177000000127570655671743400154660ustar00clevecompmath00000400000006\par \subsection{Distributed Symbolic Factorization} \label{subsection:DChvMtx:symbolic-factorization} \par The symbolic factorization takes very little time when compared to the numeric factorization or a solve, but it can still be necessary to compute it in a distributed manner. For example, consider the case when the entries in the original matrix do not fit on one processor. \par Here is what we assume that can be present on one processor. \begin{enumerate} \item An {\tt ETree} front tree object contains five vectors whose length is the number of fronts (three tree vectors and two vectors to hold the number of internal and external vertices in a front) and one vector whose length is the number of vertices (that maps vertices to fronts). \item An {\tt IV} object that holds the map from a front to its owner. \item A {\tt DInpMtx} object that holds only those entries in the original matrix that will be mapped to fronts owned by the process. \end{enumerate} \par A process does not need to know about every front in the tree, only those that it owns, that it will update during the factorization, and those that it will interact with during the forward and backsolves. We {\it could} design a front tree data structure that holds only information about the fronts that a process needs to know about. However, it is quite likely that the overhead to store the entire front tree on each processor is acceptable. \par It is not so clear that we can afford to store the entire symbolic factorization on the front tree, so we have designed a strategy that each process computes and holds only the indices for the fronts that it needs. Actually, this is not true, for we store a bit more than the bare minimum, as we now explain. \par If a process owns front $J$, then it will compute the factor entries in this front, and will compute updates to all ancestor fronts $K$ such that $\bnd{J} \cap K \ne \emptyset$. Let the set of {\it active} fronts be the active fronts unioned with those fronts that will be updated by an owned front. % Let us call the set of {\it owned} fronts and those fronts that % will be updated by an owned front the {\it set of active fronts}. \par It is not necessarily true that an owned front $J$ will update {\it all} of its ancestors. However, to determine what ancestors of owned fronts will be updated by the owned fronts, we need to know the boundary indices for each front, and that is what we are trying to determine by computing the symbolic factorization. So we settle for a superset that is (hopefully) not too much larger than the active fronts. To use a different term, we will easily find a set of {\it supported fronts} that contains the active fronts. These supported fronts consists of the owned fronts and all ancestors of owned fronts, and we can determine this set just by using the front tree and the owners map vector. \par To compute the factorization, a process will need to have the indices for each of its active fronts, so at the end of the symbolic factorization, each process must contain an {\tt IVL} object that contains the front indices for all supported processors. \par How do we compute the front indices for the supported fronts? There are four steps. \begin{enumerate} \item From the front tree we know the number of internal and number of external indices in each front via the {\tt nodwghts[]} and {\tt bndwghts[]} vectors. So we initialize the {\tt IVL} object that will hold the supported portions of the symbolic factorization. \item For each owned front, we load the internal vertices using the {\tt vtxToFront[]} vector from the front tree. \item For each owned front $J$ we add some of the indices in $\bnd{J}$ by examining the entries in the local {\tt DInpMtx} object. \item Now we need to cooperate with the other processes. First we compute the number of messages that we expect to receive from other processes. There will be one message for each supported but unowned front, and one message for each unsupported front whose parent is owned. We keep track of the number of missing indices for each owned front. When all indices for an owned front are present (after step 2 any root front has this property, and after step 3 all leaf fronts have this property), we put the front into a list of {\it ready} fronts. \begin{tabbing} XXX\=XXX\=XXX\=XXX\=XXX\=\kill \WHILE\ the ready list is not empty or there are messages remaining \\ \> \WHILE\ the ready list is not empty \\ \>\> remove owned front $J$ from the ready list \\ \>\> store $J \cup \bnd{J}$ in the {\tt IVL} object \\ \>\> send $J \cup \bnd{J}$ to all processes that contain $J$ in their support sets \\ \>\> \IF\ the $J$ has a parent $K$ \THEN\ \\ \>\>\> \IF\ $K$ is owned and not complete \THEN\ \\ \>\>\>\> merge $\bnd{J}$ into $K \cup \bnd{K}$ \\ \>\>\>\> \IF\ $K \cup \bnd{K}$ is complete \THEN\ \\ \>\>\>\>\> put $K$ on the ready list \\ \>\>\>\> \END\ \IF \\ \>\>\> \ELSE\ \IF\ $J$ not supported by the owner of $K$ \THEN\ \\ \>\>\>\> send $J \cup \bnd{J}$ to the owner of $K$ \\ \>\>\> \END\ \IF \\ \>\> \END\ \IF\ \\ \> \END\ \WHILE\ \\ \> \WHILE\ there are messages waiting to be received \\ \>\> receive $J \cup \bnd{J}$ \\ \>\> \IF\ $J$ is supported \THEN\ \\ \>\>\> store $J \cup \bnd{J}$ in the {\tt IVL} object \\ \>\> \END\ \IF \\ \>\> \IF\ $J$ has a parent $K$, $K$ is owned and not complete \THEN\ \\ \>\>\> merge $\bnd{J}$ into $K \cup \bnd{K}$ \\ \>\>\> \IF\ $K \cup \bnd{K}$ is complete \THEN\ \\ \>\>\>\> put $K$ on the ready list \\ \>\>\> \END\ \IF \\ \>\> \END\ \IF \\ \> \END\ \WHILE \\ end \WHILE\ \end{tabbing} \end{enumerate} now about every fMPI/doc/main.log010064400020550007177000000126550665022723300147300ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 16 JAN 1999 16:28 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. (intro.tex Chapter 1. ) (dataStructure.tex LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 13. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 13. Overfull \hbox (0.87425pt too wide) in paragraph at lines 30--34 []\OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 MatMulInfo \OT1/cmr/m/n/10 ob-ject store s all the nec-es-sary in-for-ma-tion to make this hap-pen. There is one \OT1/cm tt/m/n/10 MatMulInfo [] LaTeX Font Info: Try loading font information for OMS+cmr on input line 36. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 36. [1 ]) (proto.tex Overfull \hbox (59.838pt too wide) in paragraph at lines 97--1 []\OT1/cmr/m/n/10 See the meth-ods \OT1/cmtt/m/n/10 MatMul[]MPI[]setup()\OT1/cm r/m/n/10 , \OT1/cmtt/m/n/10 MatMul[]setLocalIndices()\OT1/cmr/m/n/10 , \OT1/cmt t/m/n/10 MatMul[]setGlobalIndices()\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 MatMul[]M PI[]mmm() [] [2] [3] Overfull \hbox (31.97972pt too wide) in paragraph at lines 249--256 \OT1/cmr/m/n/10 dis-tributed matrix-matrix mul-ti-ply. The gather op-er-a-tion $\OML/cmm/m/it/10 X[] \OMS/cmsy/m/n/10 \OML/cmm/m/it/10 X$ \OT1/cmr/m/n/10 is per-formed by \OT1/cmtt/m/n/10 DenseMtx[]MPI[]gatherRows()\OT1/cmr/m/n/10 , [] [4] LaTeX Font Info: Try loading font information for OMS+cmtt on input line 352 . LaTeX Font Info: No file OMScmtt.fd. on input line 352. LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined (Font) using `OMS/cmsy/m/n' instead (Font) for symbol `textbraceleft' on input line 352. [5] [6] Overfull \hbox (11.99106pt too wide) in paragraph at lines 517--517 []\OT1/cmtt/m/n/10 void FrontMtx_MPI_permuteUpperAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[],[] [] Overfull \hbox (11.99106pt too wide) in paragraph at lines 517--517 [] \OT1/cmtt/m/n/10 int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ;[] [] Overfull \hbox (11.99106pt too wide) in paragraph at lines 517--517 []\OT1/cmtt/m/n/10 void FrontMtx_MPI_permuteLowerAdj ( FrontMtx *frontmtx, IV *frontOwnersIV, int stats[],[] [] Overfull \hbox (11.99106pt too wide) in paragraph at lines 517--517 [] \OT1/cmtt/m/n/10 int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ;[] [] [7] [8] [9] [10] [11] Overfull \hbox (11.99106pt too wide) in paragraph at lines 981--981 []\OT1/cmtt/m/n/10 void * makeSendRecvIVLs ( IV *supportedIV, IV *globalmapIV, IVL *sendIVL, IVL *recvIVL,[] [] Overfull \hbox (11.99106pt too wide) in paragraph at lines 981--981 [] \OT1/cmtt/m/n/10 int stats[], int msglvl, FILE *msgFile, int firsttag, MPI_Comm comm ) ;[] [] ) (drivers.tex [12] [13] LaTeX Warning: Reference `chapter:Graph' on page 14 undefined on input line 225 . [14] [15] Overfull \hbox (31.23914pt too wide) in paragraph at lines 409--426 []\OT1/cmr/m/n/10 This driver pro-gram tests the dis-tributed \OT1/cmtt/m/n/10 IVL[]MPI[]alltoall() \OT1/cmr/m/n/10 method. This is used by the \OT1/cmtt/m/n/ 10 makeSendRecvIVLs [] [16] [17] [18] [19]) (main.ind [20] [21 ]) (main.aux) LaTeX Font Warning: Some font shapes were not available, defaults substituted. LaTeX Warning: There were undefined references. ) Here is how much of TeX's memory you used: 329 strings out of 10908 3446 string characters out of 72189 52228 words of memory out of 262141 3242 multiletter control sequences out of 9500 8080 words of font info for 31 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 23i,6n,21p,158b,430s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (21 pages, 86648 bytes). MPI/doc/main.idx010064400020550007177000000047250665022723300147320ustar00clevecompmath00000400000006\indexentry{DenseMtx_MPI_splitByRows@{\tt DenseMtx\_MPI\_splitByRows()}}{2} \indexentry{DenseMtx_MPI_splitFromGlobalByRows@{\tt DenseMtx\_MPI\_splitFromGlobalByRows()}}{3} \indexentry{DenseMtx_MPI_mergeToGlobalByRows@{\tt DenseMtx\_MPI\_mergeToGlobalByRows()}}{3} \indexentry{InpMtx_MPI_split@{\tt InpMtx\_MPI\_split()}}{3} \indexentry{InpMtx_MPI_splitFromGlobal@{\tt InpMtx\_MPI\_splitFromGlobal()}}{4} \indexentry{Pencil_MPI_split@{\tt Pencil\_MPI\_split()}}{4} \indexentry{FrontMtx_MPI_split@{\tt FrontMtx\_MPI\_split()}}{4} \indexentry{DenseMtx_MPI_gatherRows@{\tt DenseMtx\_MPI\_gatherRows()}}{5} \indexentry{DenseMtx_MPI_scatterAddRows@{\tt DenseMtx\_MPI\_scatterAddRows()}}{5} \indexentry{SymbFac_MPI_initFromInpMtx@{\tt SymbFac\_MPI\_initFromInpMtx()}}{5} \indexentry{SymbFac_MPI_initFromPencil@{\tt SymbFac\_MPI\_initFromPencil()}}{5} \indexentry{FrontMtx_MPI_factorPencil@{\tt FrontMtx\_MPI\_factorPencil()}}{6} \indexentry{FrontMtx_MPI_factorInpMtx@{\tt FrontMtx\_MPI\_factorInpMtx()}}{6} \indexentry{FrontMtx_MPI_postProcess@{\tt FrontMtx\_MPI\_postProcess()}}{7} \indexentry{FrontMtx_MPI_permuteUpperAdj@{\tt FrontMtx\_MPI\_permuteUpperAdj()}}{7} \indexentry{FrontMtx_MPI_permuteLowerAdj@{\tt FrontMtx\_MPI\_permuteLowerAdj()}}{7} \indexentry{IV_MPI_allgather@{\tt IV\_MPI\_allgather()}}{7} \indexentry{IVL_MPI_allgather@{\tt IVL\_MPI\_allgather()}}{8} \indexentry{FrontMtx_MPI_solve@{\tt FrontMtx\_MPI\_solve()}}{8} \indexentry{MatMul_MPI_setup@{\tt MatMul\_MPI\_setup()}}{9} \indexentry{MatMul_setLocalIndices@{\tt MatMul\_setLocalIndices()}}{9} \indexentry{MatMul_setGlobalIndices@{\tt MatMul\_setGlobalIndices()}}{9} \indexentry{MatMul_MPI_mmm@{\tt MatMul\_MPI\_mmm()}}{10} \indexentry{MatMul_cleanup@{\tt MatMul\_cleanup()}}{10} \indexentry{ETree_MPI_Bcast@{\tt ETree\_MPI\_Bcast()}}{10} \indexentry{Graph_MPI_Bcast@{\tt Graph\_MPI\_Bcast()}}{10} \indexentry{IVL_MPI_Bcast@{\tt IVL\_MPI\_Bcast()}}{10} \indexentry{IV_MPI_Bcast@{\tt IV\_MPI\_Bcast()}}{10} \indexentry{InpMtx_MPI_fullAdjacency@{\tt InpMtx\_MPI\_fullAdjacency()}}{11} \indexentry{Pencil_MPI_fullAdjacency@{\tt Pencil\_MPI\_fullAdjacency()}}{11} \indexentry{FrontMtx_MPI_aggregateList@{\tt FrontMtx\_MPI\_aggregateList()}}{11} \indexentry{FrontMtx_MPI_colmapIV@{\tt FrontMtx\_MPI\_colmapIV()}}{11} \indexentry{FrontMtx_MPI_rowmapIV@{\tt FrontMtx\_MPI\_rowmapIV()}}{11} \indexentry{InpMtx_MPI_alltoall@{\tt InpMtx\_MPI\_alltoall}}{11} \indexentry{makeSendRecvIVLs@{\tt makeSendRecvIVLs}}{12} \indexentry{maxTagMPI@{\tt maxTagMPI()}}{12} MPI/doc/main.aux010064400020550007177000000040530665022723300147350ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt MPI} directory}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:MPI}{{1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{1}} \newlabel{section:MPI:dataStructure}{{1.1}{1}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.1.1}{\tt MatMulInfo} : Matrix-matrix multiply information object}{1}} \newlabel{subsection:MatMulInfo}{{1.1.1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt MPI} methods}{2}} \newlabel{section:MPI:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Split and redistribution methods}{2}} \newlabel{subsection:MPI:proto:split}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Gather and scatter methods}{5}} \newlabel{subsection:MPI:proto:gather-scatter}{{1.2.2}{5}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Symbolic Factorization methods}{5}} \newlabel{subsection:MPI:proto:symbfac}{{1.2.3}{5}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Numeric Factorization methods}{6}} \newlabel{subsection:MPI:proto:factor}{{1.2.4}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Post-processing methods}{7}} \newlabel{subsection:MPI:proto:postprocess}{{1.2.5}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.6}Numeric Solve methods}{8}} \newlabel{subsection:MPI:proto:solve}{{1.2.6}{8}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.7}Matrix-matrix multiply methods}{9}} \newlabel{subsection:MPI:proto:mmm}{{1.2.7}{9}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.8}Broadcast methods}{10}} \newlabel{subsection:MPI:proto:broadcast}{{1.2.8}{10}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.9}Utility methods}{11}} \newlabel{subsection:MPI:proto:utility}{{1.2.9}{11}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs}{12}} \newlabel{section:MPI:drivers}{{1.3}{12}} MPI/doc/makefile010064400020550007177000000000270655671743400150030ustar00clevecompmath00000400000006clean : - rm -f *.dvi MPI/doc/main.ind010064400020550007177000000031100661617127000147040ustar00clevecompmath00000400000006\begin{theindex} \item {\tt DenseMtx\_MPI\_gatherRows()}, 5 \item {\tt DenseMtx\_MPI\_scatterAddRows()}, 6 \item {\tt DenseMtx\_MPI\_splitByRows()}, 3 \item {\tt DenseMtx\_MPI\_splitFromGlobalByRows()}, 3 \indexspace \item {\tt ETree\_MPI\_Bcast()}, 12 \indexspace \item {\tt FrontMtx\_MPI\_aggregateList()}, 13 \item {\tt FrontMtx\_MPI\_colmapIV()}, 13 \item {\tt FrontMtx\_MPI\_factorInpMtx()}, 7 \item {\tt FrontMtx\_MPI\_factorPencil()}, 7 \item {\tt FrontMtx\_MPI\_permuteLowerAdj()}, 8 \item {\tt FrontMtx\_MPI\_permuteUpperAdj()}, 8 \item {\tt FrontMtx\_MPI\_postProcess()}, 8 \item {\tt FrontMtx\_MPI\_rowmapIV()}, 13 \item {\tt FrontMtx\_MPI\_solve()}, 9 \item {\tt FrontMtx\_MPI\_split()}, 5 \indexspace \item {\tt Graph\_MPI\_Bcast()}, 12 \indexspace \item {\tt InpMtx\_MPI\_alltoall}, 13 \item {\tt InpMtx\_MPI\_fullAdjacency()}, 12 \item {\tt InpMtx\_MPI\_split()}, 3 \item {\tt InpMtx\_MPI\_splitFromGlobal()}, 4 \item {\tt IV\_MPI\_allgather()}, 9 \item {\tt IVL\_MPI\_allgather()}, 9 \item {\tt IVL\_MPI\_Bcast()}, 12 \indexspace \item {\tt makeSendRecvIVLs}, 14 \item {\tt MatMul\_cleanup()}, 11 \item {\tt MatMul\_MPI\_mmm()}, 11 \item {\tt MatMul\_MPI\_setup()}, 10 \item {\tt MatMul\_setGlobalIndices()}, 11 \item {\tt MatMul\_setLocalIndices()}, 11 \item {\tt maxTagMPI()}, 14 \indexspace \item {\tt Pencil\_MPI\_fullAdjacency()}, 12 \item {\tt Pencil\_MPI\_split()}, 4 \indexspace \item {\tt SymbFac\_MPI\_initFromInpMtx()}, 6 \item {\tt SymbFac\_MPI\_initFromPencil()}, 6 \end{theindex} MPI/doc/main.ilg010064400020550007177000000004570661617127000147200ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (34 entries accepted, 0 rejected). Sorting entries....done (175 comparisons). Generating output file main.ind....done (59 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. MSMD.h010064400020550007177000000000740653410640200130030ustar00clevecompmath00000400000006#ifndef _MSMD_ #define _MSMD_ #include "MSMD/MSMD.h" #endif MSMD/MSMD.h010064400020550007177000000441550653410611100135500ustar00clevecompmath00000400000006/* MSMD.h */ #include "../cfiles.h" #include "../Graph.h" #include "../IIheap.h" #include "../ETree.h" #include "../IV.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------- typedef definitions as forward references ----------------------------------------- */ typedef struct _MSMD MSMD ; typedef struct _MSMDinfo MSMDinfo ; typedef struct _MSMDstageInfo MSMDstageInfo ; typedef struct _MSMDvtx MSMDvtx ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- MSMD -- multistage constrained minimum degree object nvint -- # of internal vertices nvbnd -- # of boundary vertices nvbnd > 0 --> constrained md used nvbnd == 0 --> unconstrained md used for graph has no boundary heap -- pointer to IIheap object, used as a priority queue incrIP -- increment for new IP structures baseIP -- pointer to base storage for working IP structures freeIP -- pointer to free list of IP structures vertices -- array of Vtx objects ivtmpIV -- IV object to hold a working vector reachIV -- IV object to hold the reach set -------------------------------------------------------------------- */ struct _MSMD { int nvtx ; IIheap *heap ; int incrIP ; IP *baseIP ; IP *freeIP ; MSMDvtx *vertices ; IV ivtmpIV ; IV reachIV ; } ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- the MSMDinfo object contains information for and about a run of the MSMD algorithm. user supplied or default information compressFlag -- flag for initial compression compressFlag / 4 >= 1 --> compress before elimination compressFlag % 4 == 2 --> compress at each elimination step, consider all nodes compressFlag % 4 == 1 --> compress at each elimination step, but only consider 2-adj nodes compressFlag % 4 == 0 --> do not perform any compression default value = 1 prioType -- priority type prioType == 0 --> zero priority for all vertices, i.e., random and independent set elimination prioType == 1 --> true external degree prioType == 2 --> approximate external updates prioType == 3 --> half and half default value = 1 stepType -- definition of nodes in a step when stepType < 1 --> only one node is eliminated at a step, e.g., like QMD from SPARSPAK and YSMP stepType == 1 --> regular multiple elimination of nodes with minimum priority, e.g., GENMMD stepType > 1 --> extended multiple elimination an independent set of nodes is selected for elimination whose degree satisfies minprio <= prio <= stepType*minprio default value = 1 seed -- random number seed msglvl -- message level default value = 0, no statistics msgFile -- message file default value = stdout storage information maxnbytes -- maximum number of bytes nbytes -- present number of bytes information available about the ordering istage -- present stage nstage -- number of stages, supplied by the stages[] vector, an input parameter to the MSMD_order method stageInfo -- pointer to vector of stageInfo objects, nstage + 1 in size --------------------------------------------------------------------- */ struct _MSMDinfo { int compressFlag ; int prioType ; double stepType ; int seed ; int msglvl ; FILE *msgFile ; int maxnbytes ; int nbytes ; int istage ; int nstage ; MSMDstageInfo *stageInfo ; double totalCPU ; } ; /*--------------------------------------------------------------------*/ /* the MSMDstageInfo structure contains statistics about the elimination at a certain stage nstep -- # of elimination steps nfront -- # of fronts welim -- weight of vertices eliminated nfind -- # of front indices nzf -- number of factor entries ops -- number of factor operations nexact2 -- # of 2-adjacent exact updates nexact3 -- # of 3-adjacent exact updates napprox -- # of approximate degree updates ncheck -- number of indistinguishable node checks nindst -- number of indistinguishable nodes found noutmtch -- number of outmatched nodes found */ struct _MSMDstageInfo { int nstep ; int nfront ; int welim ; int nfind ; int nzf ; double ops ; int nexact2 ; int nexact3 ; int napprox ; int ncheck ; int nindst ; int noutmtch ; double cpu ; } ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- this object holds information about a vertex id -- id of the vertex mark -- mark flag, 'O' or 'X' status -- status flag 'L' -- eliminated leaf node 'E' -- eliminated interior node 'O' -- outmatched node 'D' -- vertex is on degree heap 'R' -- vertex is on reach list 'I' -- interior segment 'B' -- boundary segment stage -- stage of node, stage 0 nodes are eliminated first, stage 1 nodes next, etc wght -- weight of the node nadj -- size of adjacency adj -- pointer to adjacency vector when the vertex has not yet been eliminated, adj[nadj] contains the uncovered edges when the vertex has been eliminated, adj[nadj] contains the list of boundary segments bndwght -- weight of boundary, used for a root segment par -- pointer to a parent segment for a root segment, pointer to the root segment of the parent front for a interior segment, pointer to the parent segment in the same front subtrees -- pointer to head of IP list with adjacent subtrees -------------------------------------------------------------------- */ struct _MSMDvtx { int id ; char mark ; char status ; int stage ; int wght ; int nadj ; int *adj ; int bndwght ; MSMDvtx *par ; IP *subtrees ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in MSMDinfo.c ------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor created -- 96feb25, cca ----------------------- */ MSMDinfo * MSMDinfo_new ( void ) ; /* --------------------------- set the default data fields created -- 96feb25, cca --------------------------- */ void MSMDinfo_setDefaultFields( MSMDinfo *info ) ; /* ----------------------- clear the data fields created -- 96feb25, cca ----------------------- */ void MSMDinfo_clearData ( MSMDinfo *info ) ; /* ----------------------- destructor created -- 96feb25, cca ----------------------- */ void MSMDinfo_free ( MSMDinfo *info ) ; /* ------------------------------------ purpose -- print the MSMDinfo object created -- 96feb25, cca ------------------------------------ */ void MSMDinfo_print ( MSMDinfo *info, FILE *fp ) ; /* ----------------------------------------- determine if the MSMDinfo object is valid created -- 96feb25, cca ----------------------------------------- */ int MSMDinfo_isValid ( MSMDinfo *info ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c --------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor created -- 96feb25, cca ----------------------- */ MSMD * MSMD_new ( void ) ; /* --------------------------- set the default data fields created -- 96feb25, cca --------------------------- */ void MSMD_setDefaultFields( MSMD *msmd ) ; /* ----------------------- clear the data fields created -- 96feb25, cca ----------------------- */ void MSMD_clearData ( MSMD *msmd ) ; /* ----------------------- destructor created -- 96feb25, cca ----------------------- */ void MSMD_free ( MSMD *msmd ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in MSMDvtx.c -------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- print a vertex object created -- 96feb25, cca ----------------------- */ void MSMDvtx_print ( MSMDvtx *v, FILE *fp ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in order.c ---------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- purpose -- to order the graph using multi-stage minimum degree g -- Graph object stages -- stage vector for vertices, if NULL then all vertices on stage zero. otherwise vertices with stage istage are eliminated before any vertices with stage > istage working storage is free'd, statistics can be accessed through their variables or printed via the void MSMD_printStats(MSMD*,FILE*) method. created -- 96feb25, cca --------------------------------------------------------------------- */ void MSMD_order ( MSMD *msmd, Graph *g, int stages[], MSMDinfo *info ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in fillPerms.c ------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------- fill the two permutation vectors created -- 96feb24, cca -------------------------------- */ void MSMD_fillPerms ( MSMD *msmd, IV *newToOldIV, IV *oldToNewIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in frontETree.c ----------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ create and return an ETree object that holds the front tree. created -- 96jun23, cca ------------------------------------------------------------ */ ETree * MSMD_frontETree ( MSMD *msmd ) ; /*--------------------------------------------------------------------*/ /* ======================================================================== ===== start of private methods ========================================= ======================================================================== */ /* ------------------------------------------------------------------------ ----- methods found in init.c ----------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------- initialization procedure created -- 96feb25, cca --------------------------------------------------- */ void MSMD_init ( MSMD *msmd, Graph *g, int stages[], MSMDinfo *info ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in clearReachSet.c -------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------- clean the vertices in the reach set for each v in reach set clean subtree list clean edge list end for created -- 95nov08, cca ------------------------------------------------- */ void MSMD_cleanReachSet ( MSMD *msmd, MSMDinfo *info ) ; /* ---------------------------------- clean v's subtree list of children created -- 95nov08, cca ---------------------------------- */ void MSMD_cleanSubtreeList ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) ; /* ---------------------------------------------- for each uncovered (v,w) if v->subtrees \cap w->subtrees != emptyset remove (v,w) from uncovered edges end if end for created -- 95nov08, cca ---------------------------------------------- */ void MSMD_cleanEdgeList ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in eliminate.c ------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- eliminate all nodes in a stage created -- 96feb25, cca --------------------------------------------------------------------- */ void MSMD_eliminateStage ( MSMD *msmd, MSMDinfo *info ) ; /* ------------------------------------------------------ purpose -- to eliminate an independent set of vertices created -- 95feb25, cca ------------------------------------------------------ */ int MSMD_eliminateStep ( MSMD *msmd, MSMDinfo *info ) ; /* ----------------------------------------- purpose -- eliminate vertex v 1) create v's boundary list 2) merge boundary list onto reach list 3) for each vertex in the boundary 3.1) add v to the subtree list created -- 96feb25, cca ----------------------------------------- */ void MSMD_eliminateVtx ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in findInodes.c ----------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- purpose -- to find indistinguishable nodes in the reach set flag = 0 --> return flag = 1 --> check out nodes that are 2-adj flag = 2 --> check out nodes that are both 2-adj and not created -- 96feb15, cca ----------------------------------------------------------- */ void MSMD_findInodes ( MSMD *msmd, MSMDinfo *info ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in update.c --------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------- purpose -- to update vertices in the reach set created -- 96feb25, cca ---------------------------------------------- */ void MSMD_update ( MSMD *msmd, MSMDinfo *info ) ; /* ------------------------------------------------------- purpose -- to compute the exact boundary size of a node adjacent to only two eliminated vertices created -- 96feb25, cca ------------------------------------------------------- */ int MSMD_exactDegree2 ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) ; /* ------------------------------------------------------------ purpose -- to compute the exact boundary size of a node that is not adjacent to only two eliminated vertices created -- 96feb25, cca ------------------------------------------------------------ */ int MSMD_exactDegree3 ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) ; /* -------------------------------------------------------- purpose -- to compute the approximate degree of a vertex created -- 96feb25, cca -------------------------------------------------------- */ int MSMD_approxDegree ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in makeSchurComplement.c -------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------------------- purpose -- if the elimination has halted before all the stages have been eliminated, then create the schur complement graph and the map from the original vertices those in the schur complement graph. schurGraph -- Graph object to contain the schur complement graph VtoPhi -- IV object to contain the map from vertices in V to schur complement vertices in Phi created -- 97feb01, cca ---------------------------------------------------------------- */ void MSMD_makeSchurComplement ( MSMD *msmd, Graph *schurGraph, IV *VtoPhiIV ) ; /*--------------------------------------------------------------------*/ ------- */ int MSMDinfo_isValid ( MSMDinfo *info ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c --------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor MSMD/makefile010064400020550007177000000002230663622364200143370ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean MSMD/src/makefile010064400020550007177000000012760663602645200151370ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = MSMD $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(cleanReachSet.o) \ $(OBJ).a(eliminate.o) \ $(OBJ).a(fillPerms.o) \ $(OBJ).a(findInodes.o) \ $(OBJ).a(frontETree.o) \ $(OBJ).a(init.o) \ $(OBJ).a(makeSchurComplement.o) \ $(OBJ).a(MSMDinfo.o) \ $(OBJ).a(MSMDvtx.o) \ $(OBJ).a(order.o) \ $(OBJ).a(update.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG MSMD/src/makeGlobalLib010064400020550007177000000010540660026107000160250ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = MSMD SRC = basics.c \ cleanReachSet.c \ eliminate.c \ fillPerms.c \ findInodes.c \ frontETree.c \ init.c \ makeSchurComplement.c \ MSMDinfo.c \ MSMDvtx.c \ order.c \ update.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a MSMD/src/MSMDinfo.c010064400020550007177000000124070653410610700152060ustar00clevecompmath00000400000006/* basics.C */ #include "../MSMD.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- constructor created -- 96feb25, cca ----------------------- */ MSMDinfo * MSMDinfo_new ( void ) { MSMDinfo *info ; ALLOCATE(info, struct _MSMDinfo, 1) ; MSMDinfo_setDefaultFields(info) ; return(info) ; } /*--------------------------------------------------------------------*/ /* --------------------------- set the default data fields created -- 96feb25, cca --------------------------- */ void MSMDinfo_setDefaultFields( MSMDinfo *info ) { info->compressFlag = 1 ; info->prioType = 1 ; info->stepType = 1.0 ; info->seed = 0 ; info->msglvl = 0 ; info->msgFile = stdout ; info->maxnbytes = 0 ; info->nbytes = 0 ; info->istage = 0 ; info->nstage = 0 ; info->stageInfo = NULL ; info->totalCPU = 0.0 ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields created -- 96feb25, cca ----------------------- */ void MSMDinfo_clearData ( MSMDinfo *info ) { if ( info->stageInfo != NULL ) { FREE(info->stageInfo ) ; } MSMDinfo_setDefaultFields(info) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- destructor created -- 96feb25, cca ----------------------- */ void MSMDinfo_free ( MSMDinfo *info ) { MSMDinfo_clearData(info) ; FREE(info) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ purpose -- print the MSMDinfo object created -- 96feb25, cca ------------------------------------ */ void MSMDinfo_print ( MSMDinfo *info, FILE *fp ) { int istage ; MSMDstageInfo *stageinfo ; if ( info == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in MSMDinfo_print(%p,%p)" "\n bad input\n", info, fp) ; exit(-1) ; } fprintf(fp, "\n\n MSMDinfo :") ; fprintf(fp, "\n compressFlag = %d : ", info->compressFlag) ; if ( info->compressFlag / 4 >= 1 ) { fprintf(fp, "compress graph, ") ; } switch ( info->compressFlag % 4 ) { case 0 : fprintf(fp, "during elimination do not compress") ; break ; case 1 : fprintf(fp, "during elimination compress 2-adj nodes") ; break ; case 2 : fprintf(fp, "during elimination compress all nodes") ; break ; default : fprintf(fp, "\n unknown type") ; break ; } fprintf(fp, "\n prioType = %d : ", info->prioType) ; switch ( info->prioType ) { case 1 : fprintf(fp, " true updates") ; break ; case 2 : fprintf(fp, " approximate updates") ; break ; case 3 : fprintf(fp, " true updates for 2-adj nodes, others approximate") ; break ; default : fprintf(fp, " unknown type") ; break ; } fprintf(fp, "\n stepType = %f : ", info->stepType) ; if ( info->stepType < 1.0 ) { fprintf(fp, " single elimination") ; } else if ( info->stepType == 1.0 ) { fprintf(fp, " multiple elimination of nodes of mininum degree") ; } else { fprintf(fp, " multiple elimination in range [mindeg, %f*mindeg]", info->stepType) ; } fprintf(fp, "\n msglvl = %d ", info->msglvl) ; fprintf(fp, "\n maxnbytes = %d ", info->maxnbytes) ; fprintf(fp, "\n ordering cpu = %8.3f ", info->totalCPU) ; fprintf(fp, "\n stage information") ; fprintf(fp, "\n\n stage #steps #fronts #weight #frontind nzf ops CPU") ; for ( istage = 0, stageinfo = info->stageInfo ; istage <= info->nstage ; istage++, stageinfo++ ) { fprintf(fp, "\n %3d %5d %6d %7d %9d %10d %12.0f %8.3f", istage, stageinfo->nstep, stageinfo->nfront, stageinfo->welim, stageinfo->nfind, stageinfo->nzf, stageinfo->ops, stageinfo->cpu) ; } fprintf(fp, "\n total %5d %6d %7d %9d %10d %12.0f ", stageinfo->nstep, stageinfo->nfront, stageinfo->welim, stageinfo->nfind, stageinfo->nzf, stageinfo->ops) ; fprintf(fp, "\n\n stage #nexact2 #exact3 #approx #check #indst #outmatched") ; for ( istage = 0, stageinfo = info->stageInfo ; istage <= info->nstage ; istage++, stageinfo++ ) { fprintf(fp, "\n %3d %6d %7d %6d %7d %8d %8d", istage, stageinfo->nexact2, stageinfo->nexact3, stageinfo->napprox, stageinfo->ncheck, stageinfo->nindst, stageinfo->noutmtch) ; } fprintf(fp, "\n total %6d %7d %6d %7d %8d %8d", stageinfo->nexact2, stageinfo->nexact3, stageinfo->napprox, stageinfo->ncheck, stageinfo->nindst, stageinfo->noutmtch) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- determine if the MSMDinfo object is valid created -- 96feb25, cca ----------------------------------------- */ int MSMDinfo_isValid ( MSMDinfo *info ) { int rc ; if ( info == NULL || info->compressFlag < 0 || info->compressFlag == 3 || info->compressFlag > 6 || info->prioType < 1 || info->prioType > 4 ) { rc = 0 ; } else { rc = 1 ; } return(rc) ; } /*--------------------------------------------------------------------*/ MSMD/src/MSMDvtx.c010064400020550007177000000024700654027055300150770ustar00clevecompmath00000400000006/* MSMDvtx.c */ #include "../MSMD.h" /*--------------------------------------------------------------------*/ /* ----------------------- print a vertex object created -- 96feb25, cca ----------------------- */ void MSMDvtx_print ( MSMDvtx *v, FILE *fp ) { int ierr ; /* --------------- check the input --------------- */ if ( v == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in MSMDvtx_print(%p,%p)" "\n bad input\n", v, fp) ; exit(-1) ; } fprintf(fp, "\n vertex %d, weight %d, mark %c, status %c, stage = %d", v->id, v->wght, v->mark, v->status, v->stage) ; switch ( v->status ) { case 'O' : case 'D' : case 'R' : case 'B' : fprintf(fp, "\n edges(%d) :", v->nadj) ; IVfp80(fp, v->nadj, v->adj, 13, &ierr) ; fprintf(fp, "\n subtrees :") ; IP_fp80(fp, v->subtrees, 13) ; break ; case 'L' : case 'E' : fprintf(fp, "\n parent = %d", (v->par == NULL) ? -1 : v->par->id) ; fprintf(fp, "\n bnd(%d), weight = %d :", v->nadj, v->bndwght) ; IVfp80(fp, v->nadj, v->adj, 10, &ierr) ; break ; case 'I' : fprintf(fp, "\n parent = %d", (v->par == NULL) ? -1 : v->par->id) ; break ; default : break ; } return ; } /*--------------------------------------------------------------------*/ MSMD/src/basics.c010064400020550007177000000045030653410610700150340ustar00clevecompmath00000400000006/* basics.c */ #include "../MSMD.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- constructor created -- 96feb25, cca ----------------------- */ MSMD * MSMD_new ( void ) { MSMD *msmd ; ALLOCATE(msmd, struct _MSMD, 1) ; MSMD_setDefaultFields(msmd) ; return(msmd) ; } /*--------------------------------------------------------------------*/ /* --------------------------- set the default data fields created -- 96feb25, cca --------------------------- */ void MSMD_setDefaultFields( MSMD *msmd ) { msmd->nvtx = 0 ; msmd->heap = NULL ; msmd->incrIP = 0 ; msmd->baseIP = NULL ; msmd->freeIP = NULL ; msmd->vertices = NULL ; IV_setDefaultFields(&msmd->ivtmpIV) ; IV_setDefaultFields(&msmd->reachIV) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields created -- 96feb25, cca ----------------------- */ void MSMD_clearData ( MSMD *msmd ) { IP *ip ; MSMDvtx *first, *last, *v ; /* -------------- check the data -------------- */ if ( msmd == NULL ) { fprintf(stderr, "\n fatal error in MSMD_clearData(%p)" "\n bad input\n", msmd) ; exit(-1) ; } if ( msmd->heap != NULL ) { #if MYDEBUG > 0 fprintf(stdout, "\n trying to free the heap") ; fflush(stdout) ; #endif IIheap_free(msmd->heap) ; } if ( msmd->vertices != NULL ) { #if MYDEBUG > 0 fprintf(stdout, "\n trying to free the vertices") ; fflush(stdout) ; #endif first = msmd->vertices ; last = first + msmd->nvtx - 1 ; for ( v = first ; v <= last ; v++ ) { if ( v->status == 'E' && v->adj != NULL ) { IVfree(v->adj) ; } } FREE(msmd->vertices) ; } IV_clearData(&msmd->ivtmpIV) ; IV_clearData(&msmd->reachIV) ; while ( (ip = msmd->baseIP) != NULL ) { msmd->baseIP = ip->next ; IP_free(ip) ; } MSMD_setDefaultFields(msmd) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- destructor created -- 96feb25, cca ----------------------- */ void MSMD_free ( MSMD *msmd ) { MSMD_clearData(msmd) ; FREE(msmd) ; return ; } /*--------------------------------------------------------------------*/ MSMD/src/cleanReachSet.c010064400020550007177000000165430653410610700163000ustar00clevecompmath00000400000006/* cleanReachSet.c */ #include "../MSMD.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------- clean the vertices in the reach set for each v in reach set clean subtree list clean edge list end for created -- 95nov08, cca ------------------------------------------------- */ void MSMD_cleanReachSet ( MSMD *msmd, MSMDinfo *info ) { int k, nreach ; int *reach ; MSMDvtx *v ; /* --------------- check the input --------------- */ if ( msmd == NULL || info == NULL ) { fprintf(stderr, "\n inside MSMD_cleanReachSet(%p,%p)" "\n bad input\n", msmd, info) ; exit(-1) ; } nreach = IV_size(&msmd->reachIV) ; reach = IV_entries(&msmd->reachIV) ; /* nreach = msmd->nreach ; reach = msmd->reach ; */ if ( nreach < 0 || nreach > msmd->nvtx || reach == NULL ) { fprintf(stderr, "\n inside MSMD_cleanReachSet(%p)" "\n nreach = %d, reach = %p, nvtx = %d\n", msmd, nreach, reach, msmd->nvtx) ; exit(-1) ; } if ( info->msglvl >= 5 ) { fprintf(info->msgFile, "\n inside MSMD_cleanReachSet(%p)", msmd) ; fflush(info->msgFile) ; } /* --------------------------------------------------------- clean the subtree lists of the vertices in the reach list --------------------------------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n nreach = %d", nreach) ; for ( k = 0 ; k < nreach ; k++ ) { v = msmd->vertices + reach[k] ; fprintf(stdout, "\n <%d, %c, %c>", v->id, v->status, v->mark) ; } fflush(stdout) ; #endif for ( k = 0 ; k < nreach ; k++ ) { v = msmd->vertices + reach[k] ; #if MYDEBUG > 1 fprintf(stdout, "\n calling MSMD_cleanSubtreeList(%p,%d)", msmd, v->id) ; fflush(stdout) ; #endif MSMD_cleanSubtreeList(msmd, v, info) ; } /* ------------------------------------------------------ clean the edge lists of the vertices in the reach list ------------------------------------------------------ */ for ( k = 0 ; k < nreach ; k++ ) { v = msmd->vertices + reach[k] ; #if MYDEBUG > 1 fprintf(stdout, "\n calling MSMD_cleanEdgeList(%p,%d)", msmd, v->id) ; fflush(stdout) ; #endif MSMD_cleanEdgeList(msmd, v, info) ; } if ( info->msglvl > 3 ) { for ( k = 0 ; k < nreach ; k++ ) { v = msmd->vertices + reach[k] ; MSMDvtx_print(v, info->msgFile) ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- clean v's subtree list of children created -- 95nov08, cca ---------------------------------- */ void MSMD_cleanSubtreeList ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) { int uid ; IP *ip, *nextip, *prev ; MSMDvtx *u ; /* --------------- check the input --------------- */ if ( msmd == NULL || v == NULL || info == NULL ) { fprintf(stderr, "\n inside MSMD_cleanSubtreeList(%p,%p,%p)" "\n bad input\n", msmd, v, info) ; exit(-1) ; } if ( info->msglvl > 4 && info->msgFile != NULL ) { fprintf(info->msgFile, "\n inside MSMD_cleanSubtreeList(%d)", v->id) ; fflush(info->msgFile) ; } /* ---------------------- clean the subtree list ---------------------- */ ip = v->subtrees ; v->subtrees = prev = NULL ; while ( ip != NULL ) { nextip = ip->next ; uid = ip->val ; u = msmd->vertices + uid ; if ( u->par == NULL ) { /* ---------------------------------------------- adjacent subtree is still a root, keep on list ---------------------------------------------- */ if ( prev == NULL ) { v->subtrees = ip ; } else { prev->next = ip ; } prev = ip ; ip->next = NULL ; } else { /* ---------------------------------------------------- adjacent subtree is no longer a root, drop from list ---------------------------------------------------- */ ip->val = -1 ; ip->next = msmd->freeIP ; msmd->freeIP = ip ; } ip = nextip ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- for each uncovered (v,w) if v->subtrees \cap w->subtrees != emptyset remove (v,w) from uncovered edges end if end for created -- 95nov08, cca ---------------------------------------------- */ void MSMD_cleanEdgeList ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) { int i, ierr, j, nedge, wid ; int *edges ; IP *ip1, *ip2 ; MSMDvtx *w ; /* --------------- check the input --------------- */ if ( msmd == NULL || v == NULL || info == NULL ) { fprintf(stderr, "\n inside MSMD_cleanEdgeList(%p,%p,%p)" "\n bad input\n", msmd, v, info) ; exit(-1) ; } /* -------------------------------------------- remove covered edges from the uncovered list -------------------------------------------- */ nedge = v->nadj ; edges = v->adj ; if ( info->msglvl > 5 ) { fprintf(info->msgFile, "\n inside MSMD_cleanEdgeList(%p,%p)" "\n %d's edges :", msmd, v, v->id) ; IVfp80(info->msgFile, nedge, edges, 12, &ierr) ; fflush(info->msgFile) ; } i = 0 ; j = nedge - 1 ; while ( i <= j ) { wid = edges[i] ; w = msmd->vertices + wid ; if ( info->msglvl > 5 ) { fprintf(info->msgFile, "\n <%d,%c>", wid, w->status) ; fflush(info->msgFile) ; } if ( w == v ) { /* -------------------------------- purge v from uncovered edge list -------------------------------- */ edges[i] = edges[j] ; edges[j] = wid ; j-- ; } else { switch ( w->status ) { case 'I' : case 'L' : case 'E' : /* -------------------------------- purge w from uncovered edge list -------------------------------- */ edges[i] = edges[j] ; edges[j] = wid ; j-- ; break ; default : ip1 = v->subtrees ; ip2 = w->subtrees ; if ( info->msglvl > 5 ) { fprintf(info->msgFile, "\n subtree list for %d :", v->id) ; IP_fp80(info->msgFile, ip1, 30) ; fprintf(info->msgFile, "\n subtree list for %d :", w->id) ; IP_fp80(info->msgFile, ip2, 30) ; } while ( ip1 != NULL && ip2 != NULL ) { if ( ip1->val > ip2->val ) { ip1 = ip1->next ; } else if ( ip1->val < ip2->val ) { ip2 = ip2->next ; } else { /* --------------------------------- this edge has been covered, break --------------------------------- */ edges[i] = edges[j] ; edges[j] = wid ; j-- ; break ; } } if ( ip1 == NULL || ip2 == NULL ) { /* ------------------------------- this edge was not covered, keep ------------------------------- */ i++ ; } } } } v->nadj = j + 1 ; if ( info->msglvl > 5 ) { fprintf(info->msgFile, "\n leaving MSMD_cleanEdgeList(%p,%p)" "\n %d's edges :", msmd, v, v->id) ; IVfp80(info->msgFile, v->nadj, edges, 12, &ierr) ; fflush(info->msgFile) ; } return ; } /*--------------------------------------------------------------------*/ --------------------------------------------- */ void MSMD_cleanReachSet ( MSMD *msmd, MSMDinfo *info ) { int k, nreach ; int *reaMSMD/src/eliminate.c010064400020550007177000000413210653410610700155360ustar00clevecompmath00000400000006/* eliminate.c */ #include "../MSMD.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- eliminate all nodes in a stage created -- 96feb25, cca --------------------------------------------------------------------- */ void MSMD_eliminateStage ( MSMD *msmd, MSMDinfo *info ) { int ierr, ii, jj, iv, nelim, nreach, stage, step ; int *reach ; IV *reachIV ; MSMDvtx *v ; /* --------------- check the input --------------- */ if ( msmd == NULL || info == NULL ) { fprintf(stderr, "\n fatal error in MSMD_eliminateStage(%p,%p)" "\n bad input\n", msmd, info) ; exit(-1) ; } stage = info->istage ; /* ----------------------------------------------- load the reach set with all nodes in this stage ----------------------------------------------- */ reachIV = &msmd->reachIV ; IV_setSize(reachIV, 0) ; for ( iv = 0, v = msmd->vertices ; iv < msmd->nvtx ; iv++, v++ ) { if ( v->status != 'I' ) { if ( v->stage == stage ) { IV_push(reachIV, v->id) ; v->status = 'R' ; } else if ( v->stage > stage || v->stage < 0 ) { v->status = 'B' ; } } } if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n after loading reach set") ; IV_fp80(reachIV, info->msgFile, 80, &ierr) ; fflush(info->msgFile) ; } if ( info->seed > 0 ) { IV_shuffle(reachIV, info->seed) ; } if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n reach set at stage %d", stage) ; IV_fp80(reachIV, info->msgFile, 80, &ierr) ; fflush(info->msgFile) ; } /* ------------------------------------ do an initial update of the vertices ------------------------------------ */ MSMD_update(msmd, info) ; if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n\n after initial update") ; fflush(info->msgFile) ; } IV_setSize(reachIV, 0) ; /* ----------- elimination ----------- */ step = 0 ; while ( 1 ) { if ( info->msglvl > 1 ) { fprintf(info->msgFile, "\n\n ##### stage %d, elimination step %d", stage, step) ; fflush(info->msgFile) ; } nelim = MSMD_eliminateStep(msmd, info) ; if ( nelim == 0 ) { break ; } /* ----------------------------------------- for each node in the reach set, clean its subtree list and list of uncovered edges ----------------------------------------- */ if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n calling MSMD_cleanReachSet()") ; fprintf(info->msgFile, "\n reach set") ; IV_fp80(reachIV, info->msgFile, 80, &ierr) ; fflush(info->msgFile) ; } MSMD_cleanReachSet(msmd, info) ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n return from MSMD_cleanReachSet()") ; fflush(info->msgFile) ; } /* ------------------ compress the graph ------------------ */ MSMD_findInodes(msmd, info) ; /* ---------------------------------------------- clean the reach set of indistinguishable nodes and any nodes not on the present stage ---------------------------------------------- */ nreach = IV_size(reachIV) ; reach = IV_entries(reachIV) ; for ( ii = jj = 0 ; ii < nreach ; ii++ ) { if ( reach[ii] < 0 || reach[ii] >= msmd->nvtx ) { fprintf(stderr, "\n fatal error in MSMD_eliminateStage()" "\n reach[%d] = %d", ii, reach[ii]) ; exit(-1) ; } v = msmd->vertices + reach[ii] ; if ( v->status == 'I' ) { continue ; } else if ( v->stage != stage ) { v->status = 'B' ; } else { reach[jj++] = v->id ; } } IV_setSize(reachIV, jj) ; if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n\n after cleaning reach set, nreach = %d", IV_size(reachIV)) ; fprintf(info->msgFile, "\n reach :") ; IV_fp80(reachIV, info->msgFile, 8, &ierr) ; fflush(info->msgFile) ; } /* ---------------------------------- update the nodes on the reach set ---------------------------------- */ MSMD_update(msmd, info) ; if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n\n return from update") ; fflush(info->msgFile) ; } IV_setSize(reachIV, 0) ; /* ------------------------------ increment the elimination step ------------------------------ */ step++ ; } if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n stage %d over, %d steps", stage, step) ; fflush(info->msgFile) ; } /* -------------------------------------- set the number of steps for this stage -------------------------------------- */ info->stageInfo->nstep = step ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to eliminate an independent set of vertices created -- 95feb25, cca ------------------------------------------------------ */ int MSMD_eliminateStep ( MSMD *msmd, MSMDinfo *info ) { int deg, maxdeg, mindeg, ncol, nelim, nrow, vid, weight ; MSMDvtx *v ; /* --------------- check the input --------------- */ if ( msmd == NULL || info == NULL ) { fprintf(stderr, "\n fatal error in MSMD_eliminate(%p,%p)" "\n bad input\n", msmd, info) ; exit(-1) ; } /* -------------------- check for empty heap -------------------- */ if ( msmd->heap->size == 0 ) { return(0) ; } if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n step %d", info->stageInfo->nstep) ; fflush(info->msgFile) ; } /* ---------------------------------------- increase the number of elimination steps ---------------------------------------- */ info->stageInfo->nstep++ ; /* ----------------------------------------- loop while nodes of minimum degree remain ----------------------------------------- */ nelim = weight = 0 ; IIheap_root(msmd->heap, &vid, &mindeg) ; if ( info->stepType <= 1.0 ) { maxdeg = mindeg ; } else { maxdeg = (int) (info->stepType*mindeg) ; } do { IIheap_root(msmd->heap, &vid, °) ; if ( deg > maxdeg ) { break ; } v = msmd->vertices + vid ; /* ------------------------------------------------------------------ increment the weight of this elimination step, remove v from the degree heap and put the vertex on the stack of eliminated vertices ------------------------------------------------------------------ */ if ( info->msglvl > 1 ) { fprintf(info->msgFile, "\n eliminating vertex %d, weight %d, deg %d", vid, v->wght, deg) ; fflush(info->msgFile) ; } info->stageInfo->nfront++ ; info->stageInfo->welim += v->wght ; nelim++ ; weight += v->wght ; IIheap_remove(msmd->heap, vid) ; /* --------------------------------------------------------------- call MSMD_eliminateVtx(v) to update v's adjacency structure and clean the adjacency structures of its adjacent vertices --------------------------------------------------------------- */ MSMD_eliminateVtx(msmd, v, info) ; /* ------------------------------------------ increment the storage and operation counts ------------------------------------------ */ ncol = v->wght ; nrow = v->bndwght ; info->stageInfo->nfind += nrow + ncol ; info->stageInfo->nzf += nrow*ncol + (ncol*(ncol+1))/2 ; info->stageInfo->ops += ((double) ncol*nrow)*((double) nrow+ncol+1) + ((double) ncol)*((double) (ncol+1)) *((double) (2*ncol+1))/6 ; /* fprintf(stdout, "\n nfind = %d, nzf = %d, ops = %.0f", info->stageInfo->nfind, info->stageInfo->nzf, info->stageInfo->ops) ; */ if ( info->stepType < 1.0 ) { /* -------------------------------------------- we are not using multiple elimination, break -------------------------------------------- */ break ; } } while ( msmd->heap->size > 0 ) ; return(nelim) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- eliminate vertex v 1) create v's boundary list 2) merge boundary list onto reach list 3) for each vertex in the boundary 3.1) add v to the subtree list created -- 96feb25, cca ----------------------------------------- */ void MSMD_eliminateVtx ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) { int i, ierr, j, nadj, nbnd, nedge, uid, wid, wght ; int *adj, *bnd, *edges ; IP *ip, *ip2, *prev ; IV *reachIV ; MSMDvtx *u, *w ; /* --------------- check the input --------------- */ if ( msmd == NULL || v == NULL || info == NULL ) { fprintf(stderr, "\n fatal error in MSMD_eliminateVtx(%p,%p,%p)" "\n bad input\n", msmd, v, info) ; exit(-1) ; } adj = IV_entries(&msmd->ivtmpIV) ; reachIV = &msmd->reachIV ; /* ----------------------------- create the boundary set for v ----------------------------- */ v->mark = 'X' ; if ( v->subtrees == NULL ) { /* -------------------------------------------------------- v is a leaf, look at its uncovered edge list, move v and any indistinguishable vertices to the end of the list -------------------------------------------------------- */ if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n vertex %d is a leaf", v->id) ; fflush(info->msgFile) ; } v->status = 'L' ; nedge = v->nadj ; edges = v->adj ; i = 0 ; j = nedge - 1 ; while ( i <= j ) { wid = edges[i] ; w = msmd->vertices + wid ; if ( w == v || w->status == 'I' ) { edges[i] = edges[j] ; edges[j] = wid ; j-- ; } else { w->mark = 'X' ; i++ ; } } v->nadj = j + 1 ; } else { /* ---------------------------------------------------- v is not a leaf, merge its subtrees' boundaries with its uncovered edge list to get the new boundary ---------------------------------------------------- */ if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n vertex %d is not a leaf", v->id) ; fprintf(info->msgFile, "\n vertex %d, subtrees :", v->id) ; IP_fp80(info->msgFile, v->subtrees, 20) ; fflush(info->msgFile) ; } v->status = 'E' ; nadj = 0 ; while ( (ip = v->subtrees) != NULL ) { if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n subtree %d, ip(%p)<%d,%p>", ip->val, ip, ip->val, ip->next) ; fflush(info->msgFile) ; } uid = ip->val ; u = msmd->vertices + uid ; u->par = v ; nbnd = u->nadj ; bnd = u->adj ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n bnd of adj subtree %d :", u->id) ; IVfp80(info->msgFile, nbnd, bnd, 25, &ierr) ; fflush(info->msgFile) ; } for ( i = 0 ; i < nbnd ; i++ ) { wid = bnd[i] ; w = msmd->vertices + wid ; if ( w->mark == 'O' && w->status != 'I' ) { w->mark = 'X' ; adj[nadj++] = wid ; } } if ( u->status == 'E' ) { /* ------------------------------------------ u is not a leaf, free its boundary storage ------------------------------------------ */ IVfree(u->adj) ; info->nbytes -= u->nadj * sizeof(int) ; } u->adj = NULL ; u->nadj = 0 ; /* -------------------------------------- put this IP structure on the free list -------------------------------------- */ v->subtrees = ip->next ; ip->val = -1 ; ip->next = msmd->freeIP ; msmd->freeIP = ip ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n v->subtrees = %p, msmd->freeIP = %p", v->subtrees, msmd->freeIP) ; fflush(info->msgFile) ; } } /* ------------------------------------------------ merge all uncovered edges into the boundary list ------------------------------------------------ */ nedge = v->nadj ; edges = v->adj ; for ( i = 0 ; i < nedge ; i++ ) { wid = edges[i] ; w = msmd->vertices + wid ; if ( w->mark == 'O' && w->status != 'I' ) { w->mark = 'X' ; adj[nadj++] = wid ; } } /* ---------------------------------------------------------- if boundary is not empty, allocate new storage for entries ---------------------------------------------------------- */ v->nadj = nadj ; if ( nadj > 0 ) { v->adj = IVinit(nadj, -1) ; IVcopy(nadj, v->adj, adj) ; info->nbytes += nadj*sizeof(int) ; if ( info->maxnbytes < info->nbytes ) { info->maxnbytes = info->nbytes ; } } else { v->adj = NULL ; } } if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n bnd(%d) :", v->id) ; if ( v->nadj > 0 ) { IVfp80(info->msgFile, v->nadj, v->adj, 17, &ierr) ; } fflush(info->msgFile) ; } /* ---------------------------------------------- for each boundary vertex 1. add v to subtree list 2. put v on reach set if not already there 3. unmark and add weight to boundary weight ---------------------------------------------- */ nbnd = v->nadj ; bnd = v->adj ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n %d's bnd :", v->id) ; IVfp80(info->msgFile, nbnd, bnd, 12, &ierr) ; fflush(info->msgFile) ; } wght = 0 ; for ( i = 0 ; i < nbnd ; i++ ) { wid = bnd[i] ; w = msmd->vertices + wid ; if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n adjacent vertex %d", w->id) ; fflush(info->msgFile) ; } /* ------------------------------- add v to the subtree list for w ------------------------------- */ if ( (ip = msmd->freeIP) == NULL ) { if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n need to get more IP objects") ; fflush(info->msgFile) ; } /* ------------------------------------------------- no more free IP structures, allocate more storage ------------------------------------------------- */ if ( (ip = IP_init(msmd->incrIP, IP_FORWARD)) == NULL ) { fprintf(stderr, "\n fatal error in MSMD_eliminateVtx%p,%p,%p)" "\n unable to allocate more IP objects", msmd, v, info) ; exit(-1) ; } if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n old baseIP = %p", msmd->baseIP) ; fprintf(info->msgFile, "\n new baseIP = %p", ip) ; fflush(info->msgFile) ; } ip->next = msmd->baseIP ; msmd->baseIP = ip ; info->nbytes += msmd->incrIP*sizeof(struct _IP) ; if ( info->maxnbytes < info->nbytes ) { info->maxnbytes = info->nbytes ; } ip = msmd->freeIP = msmd->baseIP + 1 ; if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n all set") ; fflush(info->msgFile) ; } } msmd->freeIP = ip->next ; ip->val = v->id ; ip->next = NULL ; for ( ip2 = w->subtrees, prev = NULL ; ip2 != NULL && ip2->val > ip->val ; ip2 = ip2->next ) { prev = ip2 ; } if ( prev == NULL ) { w->subtrees = ip ; } else { prev->next = ip ; } ip->next = ip2 ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n %d's subtrees :", w->id) ; IP_fp80(info->msgFile, w->subtrees, 15) ; fflush(info->msgFile) ; } /* -------------------------------- add w to reach list if necessary -------------------------------- */ if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n status[%d] = %c", wid, w->status) ; fflush(info->msgFile) ; } switch ( w->status ) { case 'D' : if ( info->msglvl > 4 ) { fprintf(info->msgFile, ", remove from heap") ; fflush(info->msgFile) ; } IIheap_remove(msmd->heap, wid) ; case 'O' : case 'B' : if ( info->msglvl > 4 ) { fprintf(info->msgFile, ", add to reach set, nreach = %d", IV_size(reachIV) + 1) ; fflush(info->msgFile) ; } IV_push(reachIV, wid) ; w->status = 'R' ; case 'R' : break ; case 'I' : break ; default : fprintf(stderr, "\n error in MSMD_eliminateVtx(%p,%p,%p)" "\n status[%d] = '%c'\n", msmd, v, info, wid, w->status) ; fprintf(stderr, "\n msmd->nvtx = %d", msmd->nvtx) ; exit(-1) ; } /* -------------------------------- unmark the boundary vertices and store the weight of the boundary -------------------------------- */ w->mark = 'O' ; wght += w->wght ; } /* ------------------------------------ unmark v and set its boundary weight ------------------------------------ */ v->mark = 'O' ; v->bndwght = wght ; return ; } /*--------------------------------------------------------------------*/ e are not using multiple elimination, break -------------------------------------------- */ break ; } } while ( msmd->heap->size > 0 ) ; return(nelim) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purposeMSMD/src/fillPerms.c010064400020550007177000000111320653410610700155210ustar00clevecompmath00000400000006/* fillPerms.c */ #include "../MSMD.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* -------------------------------- fill the two permutation vectors created -- 96feb24, cca -------------------------------- */ void MSMD_fillPerms ( MSMD *msmd, IV *newToOldIV, IV *oldToNewIV ) { int count, front, iv, nfront, nvtx, pfront, root, vfront, wfront ; int *fch, *head, *link, *newToOld, *oldToNew, *par, *sib, *vToFront ; MSMDvtx *v, *w ; /* --------------- check the input --------------- */ if ( msmd == NULL || (oldToNewIV == NULL && newToOldIV == NULL) ) { fprintf(stderr, "\n fatal error in MSMD_fillPerms(%p,%p,%p)" "\n bad input\n", msmd, newToOldIV, oldToNewIV) ; exit(-1) ; } nvtx = msmd->nvtx ; if ( newToOldIV != NULL ) { if ( IV_size(newToOldIV) < nvtx ) { IV_setSize(newToOldIV, nvtx) ; } newToOld = IV_entries(newToOldIV) ; } else { newToOld = NULL ; } if ( oldToNewIV != NULL ) { if ( IV_size(oldToNewIV) < nvtx ) { IV_setSize(oldToNewIV, nvtx) ; } oldToNew = IV_entries(oldToNewIV) ; } else { oldToNew = NULL ; } /* ------------------------------------------- compute the map from the vertices to fronts ------------------------------------------- */ nfront = 0 ; vToFront = IVinit(nvtx, -1) ; for ( iv = 0, v = msmd->vertices ; iv < nvtx ; iv++, v++ ) { switch ( v->status ) { case 'L' : case 'E' : vToFront[iv] = nfront++ ; break ; default : break ; } } /* ------------------------ allocate working storage ------------------------ */ par = IVinit(nfront, -1) ; fch = IVinit(nfront, -1) ; sib = IVinit(nfront, -1) ; head = IVinit(nfront, -1) ; link = IVinit(nvtx, -1) ; root = -1 ; for ( iv = 0, v = msmd->vertices ; iv < nvtx ; iv++, v++ ) { switch ( v->status ) { case 'I' : w = v ; while ( w->status == 'I' ) { w = w->par ; } wfront = vToFront[w->id] ; link[iv] = head[wfront] ; head[wfront] = iv ; break ; case 'E' : case 'L' : vfront = vToFront[iv] ; link[iv] = head[vfront] ; head[vfront] = iv ; if ( v->par != NULL ) { pfront = vToFront[v->par->id] ; par[vfront] = pfront ; sib[vfront] = fch[pfront] ; fch[pfront] = vfront ; } else { sib[vfront] = root ; root = vfront ; } break ; default : fprintf(stderr, "\n fatal error in MSMD_fillPerms(%p,%p,%p)" "\n v = %d, status = %c", msmd, oldToNew, newToOld, v->id, v->status) ; fprintf(stderr, "\n vertex %d, status %c", v->id, v->status) ; exit(-1) ; } } #if MYDEBUG > 0 { int ierr ; fprintf(stdout, "\n %d fronts, root = %d", nfront, root) ; fprintf(stdout, "\n front par[]") ; IVfp80(stdout, nfront, par, 80, &ierr) ; fprintf(stdout, "\n front fch[]") ; IVfp80(stdout, nfront, fch, 80, &ierr) ; fprintf(stdout, "\n front sib[]") ; IVfp80(stdout, nfront, sib, 80, &ierr) ; fprintf(stdout, "\n head[]") ; IVfp80(stdout, nfront, head, 80, &ierr) ; fprintf(stdout, "\n link[]") ; IVfp80(stdout, nvtx, head, 80, &ierr) ; fflush(stdout) ; } #endif /* ---------------------------------------------------------- do a post-order traversal and fill the permutation vectors ---------------------------------------------------------- */ count = 0 ; front = root ; while ( front != -1 ) { while ( fch[front] != -1 ) { front = fch[front] ; } /* --------------------------- leaf front, number vertices --------------------------- */ for ( iv = head[front] ; iv != -1 ; iv = link[iv] ) { if ( newToOld != NULL ) { newToOld[count] = iv ; } if ( oldToNew != NULL ) { oldToNew[iv] = count++ ; } } /* --------------- find next front --------------- */ while ( sib[front] == -1 && par[front] != -1 ) { front = par[front] ; /* ------------------------------- internal front, number vertices ------------------------------- */ for ( iv = head[front] ; iv != -1 ; iv = link[iv] ) { if ( newToOld != NULL ) { newToOld[count] = iv ; } if ( oldToNew != NULL ) { oldToNew[iv] = count++ ; } } } front = sib[front] ; } /* ------------------------ free the working storage ------------------------ */ IVfree(par) ; IVfree(fch) ; IVfree(sib) ; IVfree(head) ; IVfree(link) ; IVfree(vToFront) ; return ; } /*--------------------------------------------------------------------*/ MSMD/src/findInodes.c010064400020550007177000000227210653410611000156460ustar00clevecompmath00000400000006/* findInodes2.c */ #include "../MSMD.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- to find indistinguishable nodes in the reach set flag = 0 --> return flag = 1 --> check out nodes that are 2-adj flag = 2 --> check out nodes that are both 2-adj and not note: the reach set is not changed. created -- 96feb15, cca modified -- 97feb07, cca very tricky "bug" was : sum += ip->val for subtrees sum += IVsum(nvedge, vedges) for uncovered edges now : sum += ip->val + 1 for subtrees sum += IVsum(nvedge, vedges) + nvedge for uncovered edges checksums were "wrong" due to vertex 0 adding nothing to the checksum. beware 0-indexing. ------------------------------------------------------------------ */ void MSMD_findInodes ( MSMD *msmd, MSMDinfo *info ) { int first, flag, i, ierr, iv, iw, j, k, keepon, nlist, nreach, nvedge, sum, vid, vchk, vcount, wid ; int *chk, *list, *reach, *vedges, *wedges ; IP *ip, *ipv, *ipw, *vsubtrees ; MSMDvtx *v, *w ; /* --------------- check the input --------------- */ if ( msmd == NULL || info == NULL ) { fprintf(stderr, "\n fatal error in MSMD_findInodes(%p,%p)" "\n bad input\n", msmd, info) ; exit(-1) ; } if ( (flag = info->compressFlag % 4) == 0 ) { /* --------------------------------------- no compression requested, simple return --------------------------------------- */ return ; } /* --------------------------------- if the reach set is empty, return --------------------------------- */ if ( (nreach = IV_size(&msmd->reachIV)) == 0 ) { return ; } /* reach = msmd->reach ; */ reach = IV_entries(&msmd->reachIV) ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n inside MSMD_findInodes(%p)" "\n reach(%d) :", msmd, nreach) ; IVfp80(info->msgFile, nreach, reach, 10, &ierr); fflush(info->msgFile) ; } /* ------------------------------------------------------- load the front of the reach set with nodes to be tested ------------------------------------------------------- */ chk = IV_entries(&msmd->ivtmpIV) ; list = reach ; if ( flag == 1 ) { /* ------------------------------------------- work only with nodes adjacent to 2 subtrees ------------------------------------------- */ i = 0 ; j = nreach - 1 ; while ( i <= j ) { vid = list[i] ; v = msmd->vertices + vid ; if ( v->nadj != 0 || (ip = v->subtrees) == NULL || (ip = ip->next) == NULL || ip->next != NULL ) { /* -------------------------------- vertex is not 2-adj, swap to end -------------------------------- */ list[i] = list[j] ; list[j] = vid ; j-- ; } else { /* -------------------------- vertex is 2-adj, keep here -------------------------- */ i++ ; } } nlist = j + 1 ; } else { /* --------------------------------- put all reached nodes in the list --------------------------------- */ nlist = nreach ; } if ( nlist == 0 ) { return ; } /* ----------------------------------------------------- compute the the checksums and count adjacent subtrees for all vertices in the list ----------------------------------------------------- */ for ( k = 0 ; k < nlist ; k++ ) { vid = list[k] ; v = msmd->vertices + vid ; vcount = 0 ; sum = 0 ; if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n vertex %d", vid) ; fflush(info->msgFile) ; } for ( ipv = v->subtrees ; ipv != NULL ; ipv = ipv->next ) { /* ------------------------------------ add adjacent subtree to the checksum ------------------------------------ */ sum += ipv->val + 1 ; if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n adjacent subtree %d, sum = %d", ipv->val, sum) ; fflush(info->msgFile) ; } vcount++ ; } if ( (nvedge = v->nadj) > 0 && (vedges = v->adj) != NULL ) { sum += IVsum(nvedge, vedges) + nvedge ; if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n %d adjacent edges :", nvedge) ; IVfp80(info->msgFile, nvedge, vedges, 20, &ierr) ; fprintf(info->msgFile, " : sum = %d", sum) ; fflush(info->msgFile) ; } IVqsortUp(nvedge, vedges) ; } /* ----------------- save the checksum ----------------- */ chk[k] = sum ; } if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n before sort, list array") ; fflush(info->msgFile) ; IVfp80(info->msgFile, nlist, list, 80, &ierr) ; fflush(info->msgFile) ; fprintf(info->msgFile, "\n chk array") ; fflush(info->msgFile) ; IVfp80(info->msgFile, nlist, chk, 80, &ierr) ; fflush(info->msgFile) ; } /* ----------------------------------------------------- sort the vertices in the reach set by their checksums ----------------------------------------------------- */ IV2qsortUp(nlist, chk, list) ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n after sort, reach array") ; IVfp80(info->msgFile, nlist, list, 80, &ierr) ; fprintf(info->msgFile, "\n chk array") ; IVfp80(info->msgFile, nlist, chk, 80, &ierr) ; fflush(info->msgFile) ; } /* ---------------------------------------- detect and purge indistinguishable nodes ---------------------------------------- */ for ( iv = 0 ; iv < nlist ; iv++ ) { vid = list[iv] ; v = msmd->vertices + vid ; if ( v->status == 'I' ) { /* ----------------------------------------------------- vertex has been found indistinguishable, skip to next ----------------------------------------------------- */ continue ; } /* --------------------------- test against other vertices --------------------------- */ vchk = chk[iv] ; nvedge = v->nadj ; vedges = v->adj ; vsubtrees = v->subtrees ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n checking out v = %d, vchk = %d, status = %c", v->id, vchk, v->status) ; fflush(info->msgFile) ; } /* --------------------------------------------------- check v against all vertices with the same checksum --------------------------------------------------- */ if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n checking out v = %d, status = %d", v->id, v->stage) ; fflush(info->msgFile) ; } first = 1 ; for ( iw = iv + 1 ; iw < nlist && chk[iw] == vchk ; iw++ ) { wid = reach[iw] ; w = msmd->vertices + wid ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n w = %d, status = %c, status = %d", w->id, w->status, w->stage) ; fflush(info->msgFile) ; } if ( w->status == 'I' || v->stage != w->stage || nvedge != w->nadj ) { /* ------------------------------------ w has been found indistinguishable or v and w do not lie on the same stage or edge counts are not the same ------------------------------------ */ continue ; } /* ---------------------------------------- w and v check out so far, check to see if all vertices adjacent to w are marked ---------------------------------------- */ if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n checking %d against %d", wid, vid) ; fflush(info->msgFile) ; } /* --------------------------------------------------------------- check to see if the subtree lists and edge lists are indentical --------------------------------------------------------------- */ info->stageInfo->ncheck++ ; keepon = 1 ; ipv = vsubtrees ; ipw = w->subtrees ; while ( ipv != NULL && ipw != NULL ) { if ( ipv->val != ipw->val ) { keepon = 0 ; break ; } ipv = ipv->next ; ipw = ipw->next ; } if ( keepon == 1 ) { wedges = w->adj ; for ( k = 0 ; k < nvedge ; k++ ) { if ( vedges[k] != wedges[k] ) { keepon = 0 ; break ; } } } if ( keepon == 1 ) { /* --------------------------------------------- w and v are indistinguishable, merge w into v --------------------------------------------- */ if ( info->msglvl > 1 ) { fprintf(info->msgFile, "\n %d absorbs %d, wght = %d, status[%d] = %c", v->id, w->id, w->wght, w->id, w->status) ; fflush(info->msgFile) ; } v->wght += w->wght ; w->wght = 0 ; w->status = 'I' ; w->nadj = 0 ; w->adj = NULL ; w->par = v ; if ( (ipw = w->subtrees) != NULL ) { while ( ipw->next != NULL ) { ipw = ipw->next ; } ipw->next = msmd->freeIP ; msmd->freeIP = ipw ; w->subtrees = NULL ; } info->stageInfo->nindst++ ; } } } if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n MSMD_findInodes(%p), all done checking the nodes", msmd) ; fflush(info->msgFile) ; } return ; } /*--------------------------------------------------------------------*/ ] ; v = msmd->vertices + vid ; vcounMSMD/src/frontETree.c010064400020550007177000000122250653410611000156370ustar00clevecompmath00000400000006/* frontETree.c */ #include "../MSMD.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ create and return an ETree object that holds the front tree. created -- 96jun23, cca ------------------------------------------------------------ */ ETree * MSMD_frontETree ( MSMD *msmd ) { ETree *etree ; int front, iv, nfront, nvtx, root ; int *bndwghts, *fch, *nodwghts, *par, *sib, *vtxToFront ; MSMDvtx *v, *w ; /* --------------- check the input --------------- */ if ( msmd == NULL ) { fprintf(stderr, "\n fatal error in MSMD_frontETree(%p)" "\n bad input\n", msmd) ; exit(-1) ; } nvtx = msmd->nvtx ; /* -------------------------- count the number of fronts -------------------------- */ nfront = 0 ; fch = IVinit(nvtx, -1) ; sib = IVinit(nvtx, -1) ; root = -1 ; for ( iv = 0, v = msmd->vertices ; iv < nvtx ; iv++, v++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n vertex %d, status %c, wght %d", v->id, v->status, v->wght) ; /* MSMDvtx_print(v, stdout) ; */ fflush(stdout) ; #endif switch ( v->status ) { case 'L' : case 'E' : if ( (w = v->par) != NULL ) { sib[v->id] = fch[w->id] ; fch[w->id] = v->id ; } else { sib[v->id] = root ; root = v->id ; } #if MYDEBUG > 0 fprintf(stdout, ", new front %d", nfront) ; fflush(stdout) ; #endif nfront++ ; break ; default : break ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %d fronts", nfront) ; fflush(stdout) ; #endif /* --------------------------- initialize the ETree object --------------------------- */ etree = ETree_new() ; ETree_init1(etree, nfront, nvtx) ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; vtxToFront = IV_entries(etree->vtxToFrontIV) ; /* ---------------------------------------------- fill the vtxToFront[] vector so representative vertices are mapped in a post-order traversal ---------------------------------------------- */ nfront = 0 ; iv = root ; while ( iv != -1 ) { while ( fch[iv] != -1 ) { iv = fch[iv] ; } v = msmd->vertices + iv ; vtxToFront[iv] = nfront++ ; #if MYDEBUG > 0 fprintf(stdout, "\n v = %d, vwght = %d, vtxToFront[%d] = %d", v->id, v->wght, iv, vtxToFront[iv]) ; fflush(stdout) ; #endif while ( sib[iv] == -1 && v->par != NULL ) { v = v->par ; iv = v->id ; vtxToFront[iv] = nfront++ ; #if MYDEBUG > 0 fprintf(stdout, "\n v = %d, vwght = %d, vtxToFront[%d] = %d", v->id, v->wght, iv, vtxToFront[iv]) ; fflush(stdout) ; #endif } iv = sib[iv] ; } IVfree(fch) ; IVfree(sib) ; /* -------------------------------------------------------------- fill in the vertex-to-front map for indistinguishable vertices -------------------------------------------------------------- */ for ( iv = 0, v = msmd->vertices ; iv < nvtx ; iv++, v++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n v %d, wght = %d, status %c", v->id, v->wght, v->status) ; fflush(stdout) ; #endif switch ( v->status ) { case 'I' : #if MYDEBUG > 0 fprintf(stdout, "\n I : v %d", v->id) ; fflush(stdout) ; #endif w = v ; while ( w->par != NULL && w->status == 'I' ) { w = w->par ; #if MYDEBUG > 0 /* fprintf(stdout, " --> %d", w->id) ; */ fprintf(stdout, " %d", w->id) ; fflush(stdout) ; #endif } #if MYDEBUG > 0 fprintf(stdout, ", w %d, status %c", w->id, w->status) ; fflush(stdout) ; #endif switch ( w->status ) { case 'L' : case 'E' : vtxToFront[v->id] = vtxToFront[w->id] ; #if MYDEBUG > 0 fprintf(stdout, "\n I: vtxToFront[%d] = %d", iv, vtxToFront[iv]) ; fflush(stdout) ; #endif break ; default : #if MYDEBUG > 0 fprintf(stdout, "\n wow, v->rootpar = %d, status %c", w->id, w->status) ; fflush(stdout) ; #endif break ; } } } /* ------------------------------------------------------------ now fill in the parent Tree field, node and boundary weights ------------------------------------------------------------ */ par = etree->tree->par ; for ( iv = 0, v = msmd->vertices ; iv < nvtx ; iv++, v++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n v %d, status %c", v->id, v->status) ; fflush(stdout) ; #endif switch ( v->status ) { case 'L' : case 'E' : front = vtxToFront[iv] ; #if MYDEBUG > 0 fprintf(stdout, ", front %d", front) ; fflush(stdout) ; #endif if ( (w = v->par) != NULL ) { par[vtxToFront[v->id]] = vtxToFront[w->id] ; #if MYDEBUG > 0 fprintf(stdout, ", par[%d] = %d", front, par[front]) ; fflush(stdout) ; #endif } bndwghts[front] = v->bndwght ; nodwghts[front] = v->wght ; break ; default : break ; } } /* ------------------------- set the other tree fields ------------------------- */ Tree_setFchSibRoot(etree->tree) ; return(etree) ; } /*--------------------------------------------------------------------*/ MSMD/src/init.c010064400020550007177000000104150653410611000145240ustar00clevecompmath00000400000006/* init.c */ #include "../MSMD.h" #define MYDEBUG 0 #define BE_CAUTIOUS 0 /*--------------------------------------------------------------------*/ /* --------------------------------------------------- initialization procedure created -- 96feb25, cca --------------------------------------------------- */ void MSMD_init ( MSMD *msmd, Graph *g, int stages[], MSMDinfo *info ) { int ierr, ii, iv, nstage, nvtx, stage ; int *vwghts ; MSMDstageInfo *stageInfo ; MSMDvtx *v ; /* -------------------- check the input data -------------------- */ if ( msmd == NULL || g == NULL || info == NULL ) { fprintf(stderr, "\n fatal error in MSMD_init(%p,%p,%p,%p)" "\n bad input\n", msmd, g, stages, info) ; exit(-1) ; } /* --------------------- clear the data fields --------------------- */ MSMD_clearData(msmd) ; /* ---------------------------- store the number of vertices ---------------------------- */ msmd->nvtx = nvtx = g->nvtx ; /* -------------------------- allocate the IIheap object -------------------------- */ msmd->heap = IIheap_new() ; IIheap_init(msmd->heap, nvtx) ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n heap initialized") ; fflush(info->msgFile) ; } info->nbytes += IIheap_sizeOf(msmd->heap) ; /* -------------------------- allocate the IP structures -------------------------- */ msmd->incrIP = nvtx ; msmd->baseIP = IP_init(2*nvtx, IP_FORWARD) ; msmd->freeIP = msmd->baseIP + 1 ; msmd->baseIP->next = NULL ; info->nbytes += nvtx*sizeof(struct _IP) ; /* --------------------- allocate the vertices --------------------- */ ALLOCATE(msmd->vertices, struct _MSMDvtx, nvtx) ; info->nbytes += nvtx*sizeof(struct _MSMDvtx) ; for ( iv = 0, v = msmd->vertices ; iv < nvtx ; iv++, v++ ) { v->id = iv ; v->mark = 'O' ; v->status = 'R' ; v->bndwght = 0 ; v->par = NULL ; v->subtrees = NULL ; Graph_adjAndSize(g, iv, &v->nadj, &v->adj) ; #if BE_CAUTIOUS for ( ii = 0 ; ii < v->nadj ; ii++ ) { if ( v->adj[ii] < 0 || v->adj[ii] > nvtx ) { fprintf(stderr, "\n bad adj, v = %d :", iv) ; IVfp80(stderr, v->nadj, v->adj, 20, &ierr) ; exit(-1) ; } } #endif } if ( (vwghts = g->vwghts) == NULL ) { for ( iv = 0, v = msmd->vertices ; iv < nvtx ; iv++, v++ ) { v->wght = 1 ; } } else { for ( iv = 0, v = msmd->vertices ; iv < nvtx ; iv++, v++ ) { v->wght = vwghts[iv] ; } } if ( stages == NULL ) { for ( iv = 0, v = msmd->vertices ; iv < nvtx ; iv++, v++ ) { v->stage = 0 ; } } else { for ( iv = 0, v = msmd->vertices ; iv < nvtx ; iv++, v++ ) { v->stage = stages[iv] ; } } /* ------------------------- allocate the work vectors ------------------------- */ IV_init1(&msmd->ivtmpIV, nvtx) ; IV_init1(&msmd->reachIV, nvtx) ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n vectors initialized") ; fprintf(info->msgFile, "\n ivtmpIV = %p", &msmd->ivtmpIV) ; IV_writeForHumanEye(&msmd->ivtmpIV, info->msgFile) ; fprintf(info->msgFile, "\n reachIV = %p", &msmd->reachIV) ; IV_writeForHumanEye(&msmd->reachIV, info->msgFile) ; fflush(info->msgFile) ; } info->nbytes += 2*nvtx*sizeof(int) ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n nvtx = %d, nvtx = %d", nvtx, nvtx) ; fflush(info->msgFile) ; } /* --------------------------------------------------------------- set the number of stages and allocate the MSMDinfoStages vector --------------------------------------------------------------- */ nstage = (stages == NULL) ? 0 : IVmax(nvtx, stages, &iv) ; info->nstage = nstage ; ALLOCATE(info->stageInfo, struct _MSMDstageInfo, 3+nstage) ; for ( stage = 0, stageInfo = info->stageInfo ; stage <= 2 + nstage ; stage++, stageInfo++ ) { stageInfo->nstep = 0 ; stageInfo->nfront = 0 ; stageInfo->welim = 0 ; stageInfo->nfind = 0 ; stageInfo->nzf = 0 ; stageInfo->ops = 0.0 ; stageInfo->nexact2 = 0 ; stageInfo->nexact3 = 0 ; stageInfo->napprox = 0 ; stageInfo->ncheck = 0 ; stageInfo->nindst = 0 ; stageInfo->noutmtch = 0 ; } return ; } /*--------------------------------------------------------------------*/ MSMD/src/makeSchurComplement.c010064400020550007177000000152220653410611000175300ustar00clevecompmath00000400000006/* makeSchurComplement.c */ #include "../MSMD.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- if the elimination has halted before all the stages have been eliminated, then create the schur complement graph and the map from the original vertices those in the schur complement graph. schurGraph -- Graph object to contain the schur complement graph VtoPhi -- IV object to contain the map from vertices in V to schur complement vertices in Phi created -- 97feb01, cca ---------------------------------------------------------------- */ void MSMD_makeSchurComplement ( MSMD *msmd, Graph *schurGraph, IV *VtoPhiIV ) { int nedge, nPhi, nvtx, totewght, totvwght ; int *mark, *rep, *VtoPhi, *vwghts ; int count, *list ; int ierr, ii, size, *adj ; int phi, psi, tag ; IP *ip ; IVL *adjIVL ; MSMDvtx *u, *v, *vertices, *vfirst, *vlast, *w ; /* --------------- check the input --------------- */ if ( msmd == NULL || schurGraph == NULL || VtoPhiIV == NULL ) { fprintf(stderr, "\n\n fatal error in MSMD_makeSchurComplement(%p,%p,%p)" "\n bad input\n", msmd, schurGraph, VtoPhiIV) ; exit(-1) ; } vertices = msmd->vertices ; nvtx = msmd->nvtx ; /* ------------------------------------- initialize the V-to-Phi map IV object ------------------------------------- */ IV_clearData(VtoPhiIV) ; IV_setSize(VtoPhiIV, nvtx) ; IV_fill(VtoPhiIV, -2) ; VtoPhi = IV_entries(VtoPhiIV) ; /* --------------------------------------------- count the number of Schur complement vertices --------------------------------------------- */ vfirst = vertices ; vlast = vfirst + nvtx - 1 ; nPhi = 0 ; for ( v = vfirst ; v <= vlast ; v++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n v->id = %d, v->status = %c", v->id, v->status) ; fflush(stdout) ; #endif switch ( v->status ) { case 'L' : case 'E' : case 'I' : break ; case 'B' : VtoPhi[v->id] = nPhi++ ; #if MYDEBUG > 0 fprintf(stdout, ", VtoPhi[%d] = %d", v->id, VtoPhi[v->id]) ; fflush(stdout) ; #endif break ; default : break ; } } #if MYDEBUG > 0 fprintf(stdout, "\n\n nPhi = %d", nPhi) ; fflush(stdout) ; #endif /* ---------------------------------------------------- get the representative vertex id for each Phi vertex ---------------------------------------------------- */ rep = IVinit(nPhi, -1) ; for ( v = vfirst ; v <= vlast ; v++ ) { if ( (phi = VtoPhi[v->id]) >= 0 ) { #if MYDEBUG > 0 fprintf(stdout, "\n rep[%d] = %d", phi, v->id) ; fflush(stdout) ; #endif rep[phi] = v->id ; } } /* ------------------------------------------ set the map for indistinguishable vertices ------------------------------------------ */ for ( v = vfirst ; v <= vlast ; v++ ) { if ( v->status == 'I' ) { w = v ; while ( w->status == 'I' ) { w = w->par ; } #if MYDEBUG > 0 fprintf(stdout, "\n v = %d, status = %c, w = %d, status = %c", v->id, v->status, w->id, w->status) ; fflush(stdout) ; #endif VtoPhi[v->id] = VtoPhi[w->id] ; } } #if MYDEBUG > 0 fprintf(stdout, "\n\n VtoPhi") ; IV_writeForHumanEye(VtoPhiIV, stdout) ; fflush(stdout) ; #endif /* --------------------------- initialize the Graph object --------------------------- */ Graph_clearData(schurGraph) ; Graph_init1(schurGraph, 1, nPhi, 0, 0, IVL_CHUNKED, IVL_CHUNKED) ; adjIVL = schurGraph->adjIVL ; vwghts = schurGraph->vwghts ; #if MYDEBUG > 0 fprintf(stdout, "\n\n schurGraph initialized, nvtx = %d", schurGraph->nvtx) ; fflush(stdout) ; #endif /* ------------------------------- fill the vertex adjacency lists ------------------------------- */ mark = IVinit(nPhi, -1) ; list = IVinit(nPhi, -1) ; nedge = totvwght = totewght = 0 ; for ( phi = 0 ; phi < nPhi ; phi++ ) { /* ----------------------------- get the representative vertex ----------------------------- */ v = vfirst + rep[phi] ; #if MYDEBUG > 0 fprintf(stdout, "\n phi = %d, v = %d", phi, v->id) ; fflush(stdout) ; MSMDvtx_print(v, stdout) ; fflush(stdout) ; #endif count = 0 ; tag = v->id ; /* --------------------------- load self in adjacency list --------------------------- */ mark[phi] = tag ; totewght += v->wght * v->wght ; #if MYDEBUG > 0 fprintf(stdout, "\n mark[%d] = %d", phi, mark[phi]) ; fflush(stdout) ; #endif list[count++] = phi ; /* ---------------------------------------- load boundary lists of adjacent subtrees ---------------------------------------- */ for ( ip = v->subtrees ; ip != NULL ; ip = ip->next ) { u = vertices + ip->val ; size = u->nadj ; adj = u->adj ; #if MYDEBUG > 0 fprintf(stdout, "\n subtree %d :", u->id) ; IVfp80(stdout, size, adj, 15, &ierr) ; fflush(stdout) ; #endif for ( ii = 0 ; ii < size ; ii++ ) { w = vertices + adj[ii] ; #if MYDEBUG > 0 fprintf(stdout, "\n w %d, status %c, psi %d", w->id, w->status, VtoPhi[w->id]) ; fflush(stdout) ; #endif if ( (psi = VtoPhi[w->id]) != -2 && mark[psi] != tag ) { mark[psi] = tag ; #if MYDEBUG > 0 fprintf(stdout, ", mark[%d] = %d", psi, mark[psi]) ; fflush(stdout) ; #endif list[count++] = psi ; totewght += v->wght * w->wght ; } } } /* ---------------------- load adjacent vertices ---------------------- */ size = v->nadj ; adj = v->adj ; for ( ii = 0 ; ii < size ; ii++ ) { w = vertices + adj[ii] ; if ( (psi = VtoPhi[w->id]) != -2 && mark[psi] != tag ) { mark[psi] = tag ; list[count++] = psi ; totewght += v->wght * w->wght ; } } /* --------------------------------------------- sort the list and inform adjacency IVL object --------------------------------------------- */ IVqsortUp(count, list) ; IVL_setList(adjIVL, phi, count, list) ; /* -------------------------------------- set the vertex weight and increment the total vertex weight and edge count -------------------------------------- */ vwghts[phi] = v->wght ; totvwght += v->wght ; nedge += count ; } schurGraph->totvwght = totvwght ; schurGraph->nedges = nedge ; schurGraph->totewght = totewght ; /* ------------------------ free the working storage ------------------------ */ IVfree(list) ; IVfree(mark) ; IVfree(rep) ; return ; } /*--------------------------------------------------------------------*/ ---------------------------------- count the number of Schur complement vertices --------------------------------------------- */ vfirst = vertices ; vlast = vfirst + nvtx - 1 ; nPhi = 0 ; for ( v = vfirst ; v <= vlast ; v++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n v->id = %d, v->status = %c", v->id, v->status) ; fflush(stdout) ; #endif switch ( vMSMD/src/order.c010064400020550007177000000131230653410611000146730ustar00clevecompmath00000400000006/* order.c */ #include "../MSMD.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to order the graph using multi-stage minimum degree g -- Graph object stages -- stage vector for vertices, if NULL then all vertices on stage zero. otherwise vertices with stage istage are eliminated before any vertices with stage > istage working storage is free'd, statistics can be accessed through their variables or printed via the void MSMD_printStats(MSMD*,FILE*) method. created -- 96feb25, cca --------------------------------------------------------------------- */ void MSMD_order ( MSMD *msmd, Graph *g, int stages[], MSMDinfo *info ) { double t0, t1, t2, t3 ; int istage, iv, nstage, nvtx ; IP *ip ; MSMDstageInfo *now, *total ; MSMDvtx *v ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( msmd == NULL || g == NULL || info == NULL ) { fprintf(stderr, "\n fatal error in MSMD_order(%p,%p,%p,%p)" "\n bad input\n", msmd, g, stages, info) ; exit(-1) ; } if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n\n inside MSMD_order()") ; if ( stages != NULL ) { int ierr ; fprintf(info->msgFile, "\n stages[%d]", g->nvtx) ; IVfp80(info->msgFile, g->nvtx, stages, 80, &ierr) ; } fflush(info->msgFile) ; } /* ------------------------------- check the information structure ------------------------------- */ if ( MSMDinfo_isValid(info) != 1 ) { fprintf(stderr, "\n fatal error in MSMD_order(%p,%p,%p,%p)" "\n bad MSMDinfo object\n", msmd, g, stages, info) ; exit(-1) ; } /* --------------------- initialize the object --------------------- */ if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n\n trying to initialize MSMD object ") ; Graph_writeForHumanEye(g, info->msgFile) ; fflush(info->msgFile) ; } MSMD_init(msmd, g, stages, info) ; nvtx = g->nvtx ; nstage = info->nstage ; if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n\n MSMD object initialized, %d stages", nstage) ; fflush(info->msgFile) ; } /* ------------------------------------ load the reach set with all vertices ------------------------------------ */ if ( info->compressFlag / 4 >= 1 ) { /* ------------------ compress the graph ------------------ */ if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n\n initial compression") ; fflush(info->msgFile) ; } IV_setSize(&msmd->reachIV, nvtx) ; IV_ramp(&msmd->reachIV, 0, 1) ; MSMD_findInodes(msmd, info) ; if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n\n %d checked, %d found indistinguishable", info->stageInfo->ncheck, info->stageInfo->nindst) ; fflush(info->msgFile) ; } MSMD_cleanReachSet(msmd, info) ; /* for ( iv = 0, v = msmd->vertices ; iv < nvtx ; iv++, v++ ) { MSMD_cleanEdgeList(msmd, v, info) ; } */ } IV_setSize(&msmd->reachIV, 0) ; /* -------------------- loop over the stages -------------------- */ for ( info->istage = 0 ; info->istage <= nstage ; info->istage++ ) { if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n\n ##### elimination stage %d", info->istage) ; fflush(info->msgFile) ; } /* if ( info->istage == nstage ) { info->msglvl = 5 ; } */ MARKTIME(t1) ; MSMD_eliminateStage(msmd, info) ; MARKTIME(t2) ; info->stageInfo->cpu = t2 - t1 ; info->stageInfo++ ; } /* ------------- final cleanup ------------- */ { MSMDvtx *first, *last, *v ; IV_setSize(&msmd->reachIV, 0) ; first = msmd->vertices ; last = first + nvtx - 1 ; for ( v = first ; v <= last ; v++ ) { switch ( v->status ) { case 'E' : case 'L' : case 'I' : break ; default : IV_push(&msmd->reachIV, v->id) ; break ; } } /* fprintf(stdout, "\n reach set, %d entries", IV_size(&msmd->reachIV)) ; IV_writeForHumanEye(&msmd->reachIV, stdout) ; */ MSMD_findInodes(msmd, info) ; } /* --------------------------------------------------------- make info->stagInfo point back to beginning of the stages --------------------------------------------------------- */ info->stageInfo -= nstage + 1 ; /* ------------------------ get the total statistics ------------------------ */ for ( istage = 0, now = info->stageInfo, total = info->stageInfo + nstage + 1 ; istage <= nstage ; istage++, now++ ) { total->nstep += now->nstep ; total->nfront += now->nfront ; total->welim += now->welim ; total->nfind += now->nfind ; total->nzf += now->nzf ; total->ops += now->ops ; total->nexact2 += now->nexact2 ; total->nexact3 += now->nexact3 ; total->napprox += now->napprox ; total->ncheck += now->ncheck ; total->nindst += now->nindst ; total->noutmtch += now->noutmtch ; } /* ----------------------------------------------------- free some working storage (leave the MSMDvtx objects so the user can extract the permutations and/or ETree ----------------------------------------------------- */ IIheap_free(msmd->heap) ; msmd->heap = NULL ; IV_clearData(&msmd->ivtmpIV) ; IV_clearData(&msmd->reachIV) ; /* while ( (ip = msmd->baseIP) != NULL ) { msmd->baseIP = ip->next ; IP_free(ip) ; } */ MARKTIME(t3) ; info->totalCPU = t3 - t0 ; return ; } /*--------------------------------------------------------------------*/ MSMD/src/update.c010064400020550007177000000343160653410611000150510ustar00clevecompmath00000400000006/* update.c */ #include "../MSMD.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to update vertices in the reach set created -- 96feb25, cca ---------------------------------------------- */ void MSMD_update ( MSMD *msmd, MSMDinfo *info ) { int ii, jj, nreach, vid, wght ; int *reach ; IP *ip ; IV *reachIV ; MSMDvtx *v ; /* --------------- check the input --------------- */ if ( msmd == NULL || info == NULL ) { fprintf(stderr, "\n fatal error in MSMD_update(%p,%p)" "\n bad input\n", msmd, info) ; exit(-1) ; } if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n inside MSMD_update(%p,%p), nreach = %d", msmd, info, IV_size(&msmd->reachIV)) ; fflush(info->msgFile) ; } /* --------------------------------- if the reach set is empty, return --------------------------------- */ reachIV = &msmd->reachIV ; if ( (nreach = IV_size(reachIV)) == 0 ) { return ; } reach = IV_entries(reachIV) ; if ( info->msglvl > 4 ) { for ( ii = 0 ; ii < nreach ; ii++ ) { vid = reach[ii] ; v = msmd->vertices + vid ; MSMDvtx_print(v, info->msgFile) ; } fflush(info->msgFile) ; } /* ---------------------------- switch over the update types ---------------------------- */ if ( info->prioType == 2 ) { /* ------------------- approximate updates ------------------- */ for ( ii = 0 ; ii < nreach ; ii++ ) { vid = reach[ii] ; v = msmd->vertices + vid ; if ( v->status == 'I' ) { /* ------------------------- node is indistinguishable ------------------------- */ continue ; } else if ( v->status == 'R' ) { /* --------------------------------------------- internal node needs approximate degree update --------------------------------------------- */ wght = MSMD_approxDegree(msmd, v, info) ; if ( info->msglvl > 3 ) { fprintf(info->msgFile, "\n inserting %d with priority %d into heap", vid, wght) ; fflush(info->msgFile) ; } IIheap_insert(msmd->heap, vid, wght) ; v->status = 'D' ; } } } else if ( info->prioType == 0 ) { /* -------------------------------------------------------- maximal independent set elimination, set degrees to zero -------------------------------------------------------- */ for ( ii = 0 ; ii < nreach ; ii++ ) { vid = reach[ii] ; v = msmd->vertices + vid ; if ( v->status != 'I' ) { IIheap_insert(msmd->heap, vid, 0) ; v->status = 'D' ; } } } else { /* --------------------------------------------------------- exact or half and half updates, process 2-adj nodes first --------------------------------------------------------- */ for ( ii = 0, jj = 0 ; ii < nreach ; ii++ ) { vid = reach[ii] ; v = msmd->vertices + vid ; if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n v = %d, stage = %d, status = %c", v->id, v->stage, v->status) ; fflush(info->msgFile) ; } if ( v->status == 'R' ) { /* --------------------------------- internal node needs degree update --------------------------------- */ if ( v->nadj == 0 && (ip = v->subtrees) != NULL && (ip = ip->next) != NULL && ip->next == NULL ) { /* -------------------------------------------------------- v is adjacent to two subtrees and has no uncovered edges -------------------------------------------------------- */ if ( info->msglvl > 4 ) { fprintf(info->msgFile, ", 2-adj vertex") ; fflush(info->msgFile) ; } wght = MSMD_exactDegree2(msmd, v, info) ; if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n 2-adj, inserting %d with priority %d into heap", vid, wght) ; fflush(info->msgFile) ; } IIheap_insert(msmd->heap, vid, wght) ; v->status = 'D' ; } else { /* ----------------------------------------- v is adjacent two or more subtrees and/or has uncovered edges, keep in reach list ----------------------------------------- */ reach[jj++] = vid ; } } } nreach = jj ; /* ---------------------------------------------------- second pass, update the remaining nodes in the reach ---------------------------------------------------- */ for ( ii = 0 ; ii < nreach ; ii++ ) { vid = reach[ii] ; v = msmd->vertices + vid ; if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n v = %d, stage = %d, status = %c", v->id, v->stage, v->status) ; fflush(info->msgFile) ; } if ( v->status == 'R' ) { if ( info->prioType == 1 ) { wght = MSMD_exactDegree3(msmd, v, info) ; } else { wght = MSMD_approxDegree(msmd, v, info) ; } if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n 3-adj, inserting %d with priority %d into heap", vid, wght) ; fflush(info->msgFile) ; } IIheap_insert(msmd->heap, vid, wght) ; v->status = 'D' ; } } } /* msmd->nreach = 0 ; */ IV_setSize(reachIV, nreach) ; /* ------------------------------------ optionally print out the degree heap ------------------------------------ */ if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n degree heap") ; IIheap_print(msmd->heap, info->msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to compute the exact boundary size of a node adjacent to only two eliminated vertices created -- 96feb25, cca ------------------------------------------------------- */ int MSMD_exactDegree2 ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) { int bndwght, i, j, usize0, usize1, wid ; int *uadj0, *uadj1 ; MSMDvtx *u0, *u1, *w ; /* --------------- check the input --------------- */ if ( msmd == NULL || v == NULL || info == NULL ) { fprintf(stderr, "\n fatal error in MSMD_exactDegree2(%p,%p,%p)" "\n bad input\n", msmd, v, info) ; exit(-1) ; } if ( v->subtrees == NULL ) { fprintf(stderr, "\n\n 1. error in MSMD_exactDegree2(%p,%p,%p)" "\n v->subtrees == NULL\n", msmd, v, info) ; exit(-1) ; } if ( v->subtrees->next == NULL ) { fprintf(stderr, "\n\n 1. error in MSMD_exactDegree2(%p,%p,%p)" "\n v->subtrees->next == NULL\n", msmd, v, info) ; exit(-1) ; } /* ------------------------------------------------------- this vertex is adjacent to only two eliminated vertices ------------------------------------------------------- */ u0 = msmd->vertices + v->subtrees->val ; usize0 = u0->nadj ; uadj0 = u0->adj ; if ( usize0 == 0 || uadj0 == NULL ) { fprintf(stderr, "\n\n 1. error in MSMD_exactDegree2(%p,%p,%p)" "\n usize0 = %d, uadj0 = %p" "\n bad adjacency list for %d\n ", msmd, v, info, usize0, uadj0, u0->id) ; MSMDvtx_print(u0, stderr) ; exit(-1) ; } u1 = msmd->vertices + v->subtrees->next->val ; usize1 = u1->nadj ; uadj1 = u1->adj ; if ( usize1 == 0 || uadj1 == NULL ) { fprintf(stderr, "\n\n 2. error in MSMD_exactDegree2(%p,%p,%p)" "\n usize1 = %d, uadj1 = %p" "\n bad adjacency list for %d\n ", msmd, v, info, usize1, uadj1, u1->id) ; MSMDvtx_print(u1, stderr) ; exit(-1) ; } /* ----------------------------------------------- mark all nodes adjacent to the first eliminated vertex and add their size to the boundary. ----------------------------------------------- */ v->mark = 'X' ; bndwght = 0 ; i = 0, j = usize0 - 1 ; while ( i <= j ) { wid = uadj0[i] ; w = msmd->vertices + wid ; if ( w->status == 'I' ) { uadj0[i] = uadj0[j] ; uadj0[j] = wid ; j-- ; } else { if ( w->mark != 'X' ) { w->mark = 'X' ; bndwght += w->wght ; if ( info->msglvl > 5 ) { fprintf(info->msgFile, "\n %d : adding %d with weight %d to boundary", u0->id, w->id, w->wght) ; fflush(info->msgFile) ; } } i++ ; } } u0->nadj = j + 1 ; /* --------------------------------------------------- loop over all nodes adjacent to the second eliminated vertex. if a node is marked, it is outmatched by v, else add its size to the boundary. --------------------------------------------------- */ i = 0, j = usize1 - 1 ; while ( i <= j ) { wid = uadj1[i] ; w = msmd->vertices + wid ; if ( w == v ) { i++ ; } else { if ( w->status == 'I' ) { uadj1[i] = uadj1[j] ; uadj1[j] = wid ; j-- ; } else { if ( w->mark != 'X' ) { bndwght += w->wght ; if ( info->msglvl > 5 ) { fprintf(info->msgFile, "\n %d : adding %d with weight %d to boundary", u1->id, w->id, w->wght) ; fflush(info->msgFile) ; } } else if ( w->status == 'R' ) { if ( info->msglvl > 2 ) { fprintf(info->msgFile, "\n %6d is outmatched by %6d", w->id, v->id) ; fflush(info->msgFile) ; } w->status = 'O' ; info->stageInfo->noutmtch++ ; } i++ ; } } } u1->nadj = j + 1 ; /* ------------------------------------------- unmark the nodes in the first adjacency set ------------------------------------------- */ usize0 = u0->nadj ; v->mark = 'O' ; for ( j = 0 ; j < usize0 ; j++ ) { wid = uadj0[j] ; w = msmd->vertices + wid ; w->mark = 'O' ; } /* ------------------------------------- increment the number of exact updates ------------------------------------- */ info->stageInfo->nexact2++ ; return(bndwght) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to compute the exact boundary size of a node that is not adjacent to only two eliminated vertices created -- 96feb25, cca ------------------------------------------------------------ */ int MSMD_exactDegree3 ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) { int bndwght, i, ierr, j, nadj, uid, usize, vsize, wid ; int *adj, *uadj, *vadj ; IP *ip ; MSMDvtx *u, *w ; /* --------------- check the input --------------- */ if ( msmd == NULL || v == NULL || info == NULL ) { fprintf(stderr, "\n fatal error in MSMD_exactDegree3(%p,%p,%p)" "\n bad input\n", msmd, v, info) ; exit(-1) ; } adj = IV_entries(&msmd->ivtmpIV) ; /* --------------------------------- accumulate the boundary set for v --------------------------------- */ v->mark = 'X' ; nadj = 0 ; for ( ip = v->subtrees ; ip != NULL ; ip = ip->next ) { uid = ip->val ; u = msmd->vertices + uid ; usize = u->nadj ; uadj = u->adj ; i = 0, j = usize - 1 ; while ( i <= j ) { wid = uadj[i] ; w = msmd->vertices + wid ; if ( w->status == 'I' ) { uadj[i] = uadj[j] ; uadj[j] = wid ; j-- ; } else { i++ ; if ( w->mark != 'X' ) { w->mark = 'X' ; adj[nadj++] = wid ; } } } u->nadj = j + 1 ; } vsize = v->nadj ; vadj = v->adj ; i = 0, j = vsize - 1 ; while ( i <= j ) { uid = vadj[i] ; u = msmd->vertices + uid ; if ( u->status == 'I' ) { vadj[i] = vadj[j] ; vadj[j] = uid ; j-- ; } else { if ( u->mark != 'X' ) { u->mark = 'X' ; adj[nadj++] = uid ; } i++ ; } } v->nadj = j + 1 ; if ( info->msglvl > 4 ) { fprintf(info->msgFile, "\n vadj(%d) :", v->id) ; IVfp80(info->msgFile, vsize, vadj, 12, &ierr) ; fflush(info->msgFile) ; } /* --------------------------------------------------- the boundary of v is found in the list adj, compute the boundary size and unmark the boundary vertices --------------------------------------------------- */ bndwght = 0 ; for ( i = 0 ; i < nadj ; i++ ) { uid = adj[i] ; u = msmd->vertices + uid ; bndwght += u->wght ; u->mark = 'O' ; } v->mark = 'O' ; /* ------------------------------------- increment the number of exact updates ------------------------------------- */ info->stageInfo->nexact3++ ; return(bndwght) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to compute the approximate degree of a vertex created -- 96feb25, cca -------------------------------------------------------- */ int MSMD_approxDegree ( MSMD *msmd, MSMDvtx *v, MSMDinfo *info ) { int bndwght, i, uid, vsize ; int *vadj ; IP *ip ; MSMDvtx *u ; /* --------------- check the input --------------- */ if ( msmd == NULL || v == NULL || info == NULL ) { fprintf(stderr, "\n fatal error in MSMD_approxDegree(%p,%p,%p)" "\n bad input\n", msmd, v, info) ; exit(-1) ; } /* ------------------------------------------------ accumulate the approximate boundary weight for v ------------------------------------------------ */ bndwght = 0 ; for ( ip = v->subtrees ; ip != NULL ; ip = ip->next ) { bndwght += msmd->vertices[ip->val].bndwght - v->wght ; } vsize = v->nadj ; vadj = v->adj ; for ( i = 0 ; i < vsize ; i++ ) { uid = vadj[i] ; u = msmd->vertices + uid ; if ( u != v && u->status != 'I' ) { bndwght += u->wght ; } } /* ------------------------------------------- increment the number of approximate updates ------------------------------------------- */ info->stageInfo->napprox++ ; return(bndwght) ; } /*--------------------------------------------------------------------*/ v->status = 'D' ; } else { /* ----------------------------------------- v is adjacent two or more subtrees and/or has uncovered edges, keep in reach list ----------------------------------------- */ reach[jj++] = vid ; } MSMD/drivers/do_MMD010075500020550007177000000024110654454611400153430ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inGraphFile = $matrices/$matrix/orig0.graphf set matrix = R2D10000 set inGraphFile = $matrices/$matrix/orig1.graphf set inGraphFile = $matrices/$matrix/orig0.graphf set matrix = BCSSTK16 set inGraphFile = $matrices/$matrix/orig1.graphb set matrices = ../../../matrices set matrix = BCSSTK39 set inGraphFile = $matrices/$matrix/orig1.graphb set msglvl = 1 set msgFile = res2 set msgFile = res.$matrix set msgFile = stdout set compressFlag = 2 set prioType = 1 set stepType = 1 set nseed = 11 set nseed = 11 set nseed = 21 set nseed = 4 set nseed = 1 set frontTreeFile = temp.etreef set frontTreeFile = none set frontTreeFile = $matrices/$matrix/mmd.etreef set oldToNewIVfile = $matrices/$matrix/mmdOldToNew.ivf set oldToNewIVfile = temp.ivf set oldToNewIVfile = none set newToOldIVfile = $matrices/$matrix/newToOld.ivf set newToOldIVfile = none # @ seed = $nseed @ seed = 1 while ( $seed <= $nseed ) echo ' seed = ' $seed orderViaMMD $msglvl $msgFile $inGraphFile \ $seed $compressFlag $prioType $stepType \ $frontTreeFile $oldToNewIVfile $newToOldIVfile @ seed = $seed + 1 end MSMD/drivers/do_MS010075500020550007177000000023530655375220600152530ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inGraphFile = $matrices/$matrix/orig0.graphf set matrices = ../../../matrices set matrix = GRD15x15x127 set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig0.graphb set inDSTreeFile = none set inDSTreeFile = $matrices/$matrix/nd.dstreef set inDSTreeFile = $matrices/$matrix/nd2.dstreef set msglvl = 1 set msgFile = res.$matrix set msgFile = res2 set msgFile = stdout set compressFlag = 2 set prioType = 1 set stepType = 1 set nseed = 4 set nseed = 11 set nseed = 21 set nseed = 11 set nseed = 1 set frontTreeFile = none set frontTreeFile = $matrices/$matrix/ms.etreef set frontTreeFile = $matrices/$matrix/ms2.etreef set oldToNewIVfile = $matrices/$matrix/msOldToNew.ivf set oldToNewIVfile = none set newToOldIVfile = $matrices/$matrix/newToOld.ivf set newToOldIVfile = none # @ seed = $nseed @ seed = 1 while ( $seed <= $nseed ) echo ' seed = ' $seed orderViaMS $msglvl $msgFile $inGraphFile $inDSTreeFile \ $seed $compressFlag $prioType $stepType \ $frontTreeFile $oldToNewIVfile $newToOldIVfile @ seed = $seed + 1 end MSMD/drivers/do_ND010075500020550007177000000023450654517027600152400ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D10000 set matrix = BCSSTK25 set matrix = BCSSTK39 set matrix = BCSSTK30 set matrix = R2D100 set inGraphFile = $matrices/$matrix/orig1.graphf set inGraphFile = $matrices/$matrix/orig1.graphb set inGraphFile = $matrices/$matrix/orig0.graphf set inDSTreeFile = none set inDSTreeFile = $matrices/$matrix/nd.dstreef set msglvl = 1 set msgFile = res.$matrix set msgFile = res2 set msgFile = stdout set compressFlag = 2 set prioType = 1 set stepType = 1 set nseed = 4 set nseed = 11 set nseed = 21 set nseed = 11 set nseed = 1 set frontTreeFile = $matrices/$matrix/nd2.etreef set frontTreeFile = none set frontTreeFile = $matrices/$matrix/nd.etreef set oldToNewIVfile = $matrices/$matrix/ndOldToNew.ivf set oldToNewIVfile = none set newToOldIVfile = $matrices/$matrix/ndNewToOld.ivf set newToOldIVfile = none # @ seed = $nseed @ seed = 1 while ( $seed <= $nseed ) echo ' seed = ' $seed orderViaND $msglvl $msgFile $inGraphFile $inDSTreeFile \ $seed $compressFlag $prioType $stepType \ $frontTreeFile $oldToNewIVfile $newToOldIVfile @ seed = $seed + 1 end MSMD/drivers/do_Stages010075500020550007177000000022050660524223300161460ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inGraphFile = $matrices/$matrix/orig0.graphf set matrices = ../../../matrices set matrix = R10KV set inGraphFile = $matrices/$matrix/orig0.graphb set inIVfile = none set inIVfile = $matrices/$matrix/wirebasket2.ivf set msglvl = 1 set msgFile = res.$matrix set msgFile = res2 set msgFile = stdout set compressFlag = 2 set prioType = 1 set stepType = 1 set nseed = 4 set nseed = 11 set nseed = 11 set nseed = 21 set nseed = 1 set frontTreeFile = $matrices/$matrix/msmd.etreef set frontTreeFile = none set frontTreeFile = $matrices/$matrix/dd.etreef set oldToNewIVfile = $matrices/$matrix/oldToNew.ivf set oldToNewIVfile = none set newToOldIVfile = $matrices/$matrix/newToOld.ivf set newToOldIVfile = none # @ seed = $nseed @ seed = 1 while ( $seed <= $nseed ) echo ' seed = ' $seed orderViaStages $msglvl $msgFile $inGraphFile $inIVfile \ $seed $compressFlag $prioType $stepType \ $frontTreeFile $oldToNewIVfile $newToOldIVfile @ seed = $seed + 1 end MSMD/drivers/makefile010064400020550007177000000012710665314262500160210ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = orderViaMMD \ orderViaMS \ orderViaND \ orderViaStages drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} orderViaStages : orderViaStages.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} orderViaMMD : orderViaMMD.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} orderViaND : orderViaND.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} orderViaMS : orderViaMS.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} MSMD/drivers/orderViaMMD.c010064400020550007177000000166620654027151600166050ustar00clevecompmath00000400000006/* orderViaMMD.c */ #include "../MSMD.h" #include "../../DSTree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------ order a graph using the multiple minimum degree method. we read in (1) a Graph object (2) ordering parameters and output (optionally) (1) and ETree front tree object (2) old-to-new IV object (3) new-to-old IV object created -- 96nov01, cca ------------------------------------------------------------ */ { char *inGraphFileName, *msgFileName, *outETreeFileName, *outNewToOldIVfileName, *outOldToNewIVfileName ; double cpu, ops, t1, t2 ; ETree *etree ; FILE *msgFile ; Graph *g ; int compressFlag, ierr, msglvl, nfind, nvtx, nzf, prioType, rc, seed, stepType ; int *stages ; IV *newToOldIV, *oldToNewIV ; MSMD *msmd ; MSMDinfo *msmdinfo ; if ( argc != 11 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile seed compressFlag prioType" "\n stepType oldToNewIVfile newToOldIVfile frontTreeFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n seed -- random number seed" "\n compressFlag -- compression flag" "\n compressFlag / 4 >= 1 --> compress before elimination" "\n compressFlag %% 4 == 2 --> compress at each elimination step," "\n consider all nodes" "\n compressFlag %% 4 == 1 --> compress at each elimination step," "\n but only consider 2-adj nodes" "\n compressFlag %% 4 == 0 --> do not perform any compression" "\n prioType -- update type" "\n prioType == 1 --> true updates" "\n prioType == 2 --> approximate updates" "\n prioType == 3 --> half and half" "\n prioType == 4 --> maximal independent set" "\n stepType -- degree extent for independent set elimination" "\n when stepType < 1 --> only one node is eliminated at a step," "\n e.g., like QMD from SPARSPAK and YSMP" "\n stepType == 1 --> regular multiple elimination, e.g., GENMMD" "\n stepType > 1 --> extended multiple elimination" "\n an independent set of nodes is selected for elimination" "\n whose degree satisfies mindeg <= degree <= stepType*mindegree" "\n oldToNewIVfile -- file for old-to-new IV object" "\n newToOldIVfile -- file for new-to-old IV object" "\n frontTreeFile -- file for front tree's ETree object" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; msgFileName = argv[2] ; if ( strcmp(msgFileName, "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(msgFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], msgFileName) ; return(-1) ; } inGraphFileName = argv[3] ; seed = atoi(argv[4]) ; compressFlag = atoi(argv[5]) ; prioType = atoi(argv[6]) ; stepType = atoi(argv[7]) ; outETreeFileName = argv[8] ; outOldToNewIVfileName = argv[9] ; outNewToOldIVfileName = argv[10] ; fprintf(msgFile, "\n %s : " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n seed -- %d" "\n compressFlag -- %d" "\n prioType -- %d" "\n stepType -- %d" "\n outETreeFile -- %s" "\n outOldToNewFile -- %s" "\n outNewToOldFile -- %s" "\n", argv[0], msglvl, msgFileName, inGraphFileName, seed, compressFlag, prioType, stepType, outETreeFileName, outOldToNewIVfileName, outNewToOldIVfileName) ; fflush(msgFile) ; /* ------------------------------------------ initialize the MSMDinfo information object ------------------------------------------ */ msmdinfo = MSMDinfo_new() ; msmdinfo->seed = seed ; msmdinfo->compressFlag = compressFlag ; msmdinfo->prioType = prioType ; msmdinfo->stepType = stepType ; msmdinfo->msglvl = msglvl ; msmdinfo->msgFile = msgFile ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; g = Graph_new() ; Graph_setDefaultFields(g) ; if ( (rc = Graph_readFromFile(g, inGraphFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, g, inGraphFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = g->nvtx ; if ( msglvl < 4 ) { Graph_writeStats(g, msgFile) ; fflush(msgFile) ; } else { Graph_writeForHumanEye(g, msgFile) ; fflush(msgFile) ; } /* ------------------------ create the stages vector ------------------------ */ stages = NULL ; /* -------------- order via msmd -------------- */ MARKTIME(t1) ; msmd = MSMD_new() ; MSMD_order(msmd, g, stages, msmdinfo) ; MARKTIME(t2) ; cpu = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : order the graph", cpu) ; fflush(msgFile) ; MSMDinfo_print(msmdinfo, msgFile) ; fflush(msgFile) ; /* ---------------------- extract the front tree ---------------------- */ MARKTIME(t1) ; etree = MSMD_frontETree(msmd) ; nfind = ETree_nFactorIndices(etree) ; nzf = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; ops = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.5f : make the front tree", t2 - t1) ; fprintf(msgFile, "\n FACTOR : %9d indices, %9d entries, %9.0f operations", nfind, nzf, ops) ; if ( msglvl < 3 ) { ETree_writeStats(etree, msgFile) ; fflush(msgFile) ; } else { ETree_writeForHumanEye(etree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n STATSMMD %10d %10.0f %8.3f", nzf, ops, cpu) ; /* ------------------------------------------- write the front tree to a file if requested ------------------------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { ETree_writeToFile(etree, outETreeFileName) ; } /* ----------------------------------------------------------------- generate the permutation vectors and write to a file if requested ----------------------------------------------------------------- */ if ( strcmp(outOldToNewIVfileName, "none") != 0 ) { oldToNewIV = IV_new() ; } else { oldToNewIV = NULL ; } if ( strcmp(outNewToOldIVfileName, "none") != 0 ) { newToOldIV = IV_new() ; } else { newToOldIV = NULL ; } if ( oldToNewIV != NULL || newToOldIV != NULL ) { MSMD_fillPerms(msmd, newToOldIV, oldToNewIV) ; } if ( oldToNewIV != NULL ) { IV_writeToFile(oldToNewIV, outOldToNewIVfileName) ; } if ( newToOldIV != NULL ) { IV_writeToFile(newToOldIV, outNewToOldIVfileName) ; } /* ---------------------------- free all the working storage ---------------------------- */ Graph_free(g) ; MSMD_free(msmd) ; MSMDinfo_free(msmdinfo) ; ETree_free(etree) ; if ( newToOldIV != NULL ) { IV_free(newToOldIV) ; } if ( oldToNewIV != NULL ) { IV_free(oldToNewIV) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ seed, stepType ; int *stages ; IV *newToOldIV, *oldToNewIV ;MSMD/drivers/orderViaMS.c010064400020550007177000000211560654027236300165020ustar00clevecompmath00000400000006/* orderViaMS.c */ #include "../MSMD.h" #include "../../DSTree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------ order a graph using the multisection algorithm. we read in (1) a Graph object (2) a DSTree object (3) ordering parameters and output (optionally) (1) and ETree front tree object (2) old-to-new IV object (3) new-to-old IV object created -- 96nov01, cca ------------------------------------------------------------ */ { char *inGraphFileName, *inDSTreeFileName, *msgFileName, *outETreeFileName, *outNewToOldIVfileName, *outOldToNewIVfileName ; double cpu, ops, t1, t2 ; DSTree *dstree ; ETree *etree ; FILE *msgFile ; Graph *graph ; int compressFlag, ierr, msglvl, nfind, nvtx, nzf, prioType, rc, seed, stepType ; int *stages ; IV *newToOldIV, *oldToNewIV, *stagesIV ; MSMD *msmd ; MSMDinfo *msmdinfo ; if ( argc != 12 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile inDSTreeFile seed " "\n compressFlag prioType stepType oldToNewIVfile " "\n newToOldIVfile frontTreeFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n inDSTreeFile -- input file, must be *.dstreef or *.dstreeb" "\n seed -- random number seed" "\n compressFlag -- compression flag" "\n compressFlag / 4 >= 1 --> compress before elimination" "\n compressFlag %% 4 == 2 --> compress at each elimination step," "\n consider all nodes" "\n compressFlag %% 4 == 1 --> compress at each elimination step," "\n but only consider 2-adj nodes" "\n compressFlag %% 4 == 0 --> do not perform any compression" "\n prioType -- update type" "\n prioType == 1 --> true updates" "\n prioType == 2 --> approximate updates" "\n prioType == 3 --> half and half" "\n prioType == 4 --> maximal independent set" "\n stepType -- degree extent for independent set elimination" "\n when stepType < 1 --> only one node is eliminated at a step," "\n e.g., like QMD from SPARSPAK and YSMP" "\n stepType == 1 --> regular multiple elimination, e.g., GENMMD" "\n stepType > 1 --> extended multiple elimination" "\n an independent set of nodes is selected for elimination" "\n whose degree satisfies mindeg <= degree <= stepType*mindegree" "\n oldToNewIVfile -- file for old-to-new IV object" "\n newToOldIVfile -- file for new-to-old IV object" "\n frontTreeFile -- file for front tree's ETree object" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; msgFileName = argv[2] ; if ( strcmp(msgFileName, "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(msgFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], msgFileName) ; return(-1) ; } inGraphFileName = argv[3] ; inDSTreeFileName = argv[4] ; seed = atoi(argv[5]) ; compressFlag = atoi(argv[6]) ; prioType = atoi(argv[7]) ; stepType = atoi(argv[8]) ; outETreeFileName = argv[9] ; outOldToNewIVfileName = argv[10] ; outNewToOldIVfileName = argv[11] ; fprintf(msgFile, "\n %s : " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n inDSTreeFile -- %s" "\n seed -- %d" "\n compressFlag -- %d" "\n prioType -- %d" "\n stepType -- %d" "\n outETreeFile -- %s" "\n outOldToNewFile -- %s" "\n outNewToOldFile -- %s" "\n", argv[0], msglvl, msgFileName, inGraphFileName, inDSTreeFileName, seed, compressFlag, prioType, stepType, outETreeFileName, outOldToNewIVfileName, outNewToOldIVfileName) ; fflush(msgFile) ; /* ------------------------------------------ initialize the MSMDinfo information object ------------------------------------------ */ msmdinfo = MSMDinfo_new() ; msmdinfo->seed = seed ; msmdinfo->compressFlag = compressFlag ; msmdinfo->prioType = prioType ; msmdinfo->stepType = stepType ; msmdinfo->msglvl = msglvl ; msmdinfo->msgFile = msgFile ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; graph = Graph_new() ; if ( (rc = Graph_readFromFile(graph, inGraphFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = graph->nvtx ; if ( msglvl < 4 ) { Graph_writeStats(graph, msgFile) ; fflush(msgFile) ; } else { Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ------------------------- read in the DSTree object ------------------------- */ dstree = DSTree_new() ; DSTree_setDefaultFields(dstree) ; if ( strcmp(inDSTreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; } else { MARKTIME(t1) ; if ( (rc = DSTree_readFromFile(dstree, inDSTreeFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from DSTree_readFromFile(%p,%s)", rc, dstree, inDSTreeFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in DSTree object from file %s", t2 - t1, inDSTreeFileName) ; } if ( msglvl < 4 ) { DSTree_writeStats(dstree, msgFile) ; fflush(msgFile) ; } else { DSTree_writeForHumanEye(dstree, msgFile) ; fflush(msgFile) ; } /* ------------------------------------- create the multisection stages vector ------------------------------------- */ stagesIV = DSTree_MS2stages(dstree) ; stages = IV_entries(stagesIV) ; /* -------------- order via msmd -------------- */ MARKTIME(t1) ; msmd = MSMD_new() ; MSMD_order(msmd, graph, stages, msmdinfo) ; MARKTIME(t2) ; cpu = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : order the graph", cpu) ; fflush(msgFile) ; MSMDinfo_print(msmdinfo, msgFile) ; fflush(msgFile) ; /* ---------------------- extract the front tree ---------------------- */ MARKTIME(t1) ; etree = MSMD_frontETree(msmd) ; nfind = ETree_nFactorIndices(etree) ; nzf = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; ops = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.5f : make the front tree", t2 - t1) ; fprintf(msgFile, "\n FACTOR : %9d indices, %9d entries, %9.0f operations", nfind, nzf, ops) ; if ( msglvl < 3 ) { ETree_writeStats(etree, msgFile) ; fflush(msgFile) ; } else { ETree_writeForHumanEye(etree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n STATSMS %10d %10.0f %8.3f", nzf, ops, cpu) ; /* ------------------------------------------- write the front tree to a file if requested ------------------------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { ETree_writeToFile(etree, outETreeFileName) ; } /* ----------------------------------------------------------------- generate the permutation vectors and write to a file if requested ----------------------------------------------------------------- */ if ( strcmp(outOldToNewIVfileName, "none") != 0 ) { oldToNewIV = IV_new() ; } else { oldToNewIV = NULL ; } if ( strcmp(outNewToOldIVfileName, "none") != 0 ) { newToOldIV = IV_new() ; } else { newToOldIV = NULL ; } if ( oldToNewIV != NULL || newToOldIV != NULL ) { MSMD_fillPerms(msmd, newToOldIV, oldToNewIV) ; } if ( oldToNewIV != NULL ) { IV_writeToFile(oldToNewIV, outOldToNewIVfileName) ; } if ( newToOldIV != NULL ) { IV_writeToFile(newToOldIV, outNewToOldIVfileName) ; } /* ---------------------------- free all the working storage ---------------------------- */ Graph_free(graph) ; DSTree_free(dstree) ; MSMD_free(msmd) ; MSMDinfo_free(msmdinfo) ; ETree_free(etree) ; IV_free(stagesIV) ; if ( newToOldIV != NULL ) { IV_free(newToOldIV) ; } if ( oldToNewIV != NULL ) { IV_free(oldToNewIV) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ---------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------ order a graph using the multisection algorithm. we read in (1) a Graph object (2) a DSTree object (3) ordering parameters and output (optionally) (1) and ETree front tree object (2) old-to-new IV objeMSMD/drivers/orderViaND.c010064400020550007177000000212020654027256300164560ustar00clevecompmath00000400000006/* orderViaND.c */ #include "../MSMD.h" #include "../../DSTree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------ order a graph using the nested dissection algorithm. we read in (1) a Graph object (2) a DSTree object (3) ordering parameters and output (optionally) (1) and ETree front tree object (2) old-to-new IV object (3) new-to-old IV object created -- 96nov01, cca ------------------------------------------------------------ */ { char *inGraphFileName, *inDSTreeFileName, *msgFileName, *outETreeFileName, *outNewToOldIVfileName, *outOldToNewIVfileName ; double cpu, ops, t1, t2 ; DSTree *dstree ; ETree *etree ; FILE *msgFile ; Graph *graph ; int compressFlag, ierr, msglvl, nfind, nvtx, nzf, prioType, rc, seed, stepType ; int *stages ; IV *newToOldIV, *oldToNewIV, *stagesIV ; MSMD *msmd ; MSMDinfo *msmdinfo ; if ( argc != 12 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile inDSTreeFile seed " "\n compressFlag prioType stepType oldToNewIVfile " "\n newToOldIVfile frontTreeFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n inDSTreeFile -- input file, must be *.dstreef or *.dstreeb" "\n seed -- random number seed" "\n compressFlag -- compression flag" "\n compressFlag / 4 >= 1 --> compress before elimination" "\n compressFlag %% 4 == 2 --> compress at each elimination step," "\n consider all nodes" "\n compressFlag %% 4 == 1 --> compress at each elimination step," "\n but only consider 2-adj nodes" "\n compressFlag %% 4 == 0 --> do not perform any compression" "\n prioType -- update type" "\n prioType == 1 --> true updates" "\n prioType == 2 --> approximate updates" "\n prioType == 3 --> half and half" "\n prioType == 4 --> maximal independent set" "\n stepType -- degree extent for independent set elimination" "\n when stepType < 1 --> only one node is eliminated at a step," "\n e.g., like QMD from SPARSPAK and YSMP" "\n stepType == 1 --> regular multiple elimination, e.g., GENMMD" "\n stepType > 1 --> extended multiple elimination" "\n an independent set of nodes is selected for elimination" "\n whose degree satisfies mindeg <= degree <= stepType*mindegree" "\n oldToNewIVfile -- file for old-to-new IV object" "\n newToOldIVfile -- file for new-to-old IV object" "\n frontTreeFile -- file for front tree's ETree object" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; msgFileName = argv[2] ; if ( strcmp(msgFileName, "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(msgFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], msgFileName) ; return(-1) ; } inGraphFileName = argv[3] ; inDSTreeFileName = argv[4] ; seed = atoi(argv[5]) ; compressFlag = atoi(argv[6]) ; prioType = atoi(argv[7]) ; stepType = atoi(argv[8]) ; outETreeFileName = argv[9] ; outOldToNewIVfileName = argv[10] ; outNewToOldIVfileName = argv[11] ; fprintf(msgFile, "\n %s : " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n inDSTreeFile -- %s" "\n seed -- %d" "\n compressFlag -- %d" "\n prioType -- %d" "\n stepType -- %d" "\n outETreeFile -- %s" "\n outOldToNewFile -- %s" "\n outNewToOldFile -- %s" "\n", argv[0], msglvl, msgFileName, inGraphFileName, inDSTreeFileName, seed, compressFlag, prioType, stepType, outETreeFileName, outOldToNewIVfileName, outNewToOldIVfileName) ; fflush(msgFile) ; /* ------------------------------------------ initialize the MSMDinfo information object ------------------------------------------ */ msmdinfo = MSMDinfo_new() ; msmdinfo->seed = seed ; msmdinfo->compressFlag = compressFlag ; msmdinfo->prioType = prioType ; msmdinfo->stepType = stepType ; msmdinfo->msglvl = msglvl ; msmdinfo->msgFile = msgFile ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; graph = Graph_new() ; if ( (rc = Graph_readFromFile(graph, inGraphFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = graph->nvtx ; if ( msglvl < 4 ) { Graph_writeStats(graph, msgFile) ; fflush(msgFile) ; } else { Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ------------------------- read in the DSTree object ------------------------- */ dstree = DSTree_new() ; DSTree_setDefaultFields(dstree) ; if ( strcmp(inDSTreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; } else { MARKTIME(t1) ; if ( (rc = DSTree_readFromFile(dstree, inDSTreeFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from DSTree_readFromFile(%p,%s)", rc, dstree, inDSTreeFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in DSTree object from file %s", t2 - t1, inDSTreeFileName) ; } if ( msglvl < 4 ) { DSTree_writeStats(dstree, msgFile) ; fflush(msgFile) ; } else { DSTree_writeForHumanEye(dstree, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------ create the nested dissection stages vector ------------------------------------------ */ stagesIV = DSTree_NDstages(dstree) ; stages = IV_entries(stagesIV) ; /* -------------- order via msmd -------------- */ MARKTIME(t1) ; msmd = MSMD_new() ; MSMD_order(msmd, graph, stages, msmdinfo) ; MARKTIME(t2) ; cpu = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : order the graph", cpu) ; fflush(msgFile) ; MSMDinfo_print(msmdinfo, msgFile) ; fflush(msgFile) ; /* ---------------------- extract the front tree ---------------------- */ MARKTIME(t1) ; etree = MSMD_frontETree(msmd) ; nfind = ETree_nFactorIndices(etree) ; nzf = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; ops = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.5f : make the front tree", t2 - t1) ; fprintf(msgFile, "\n FACTOR : %9d indices, %9d entries, %9.0f operations", nfind, nzf, ops) ; if ( msglvl < 3 ) { ETree_writeStats(etree, msgFile) ; fflush(msgFile) ; } else { ETree_writeForHumanEye(etree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n STATSND %10d %10.0f %8.3f", nzf, ops, cpu) ; /* ------------------------------------------- write the front tree to a file if requested ------------------------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { ETree_writeToFile(etree, outETreeFileName) ; } /* ----------------------------------------------------------------- generate the permutation vectors and write to a file if requested ----------------------------------------------------------------- */ if ( strcmp(outOldToNewIVfileName, "none") != 0 ) { oldToNewIV = IV_new() ; } else { oldToNewIV = NULL ; } if ( strcmp(outNewToOldIVfileName, "none") != 0 ) { newToOldIV = IV_new() ; } else { newToOldIV = NULL ; } if ( oldToNewIV != NULL || newToOldIV != NULL ) { MSMD_fillPerms(msmd, newToOldIV, oldToNewIV) ; } if ( oldToNewIV != NULL ) { IV_writeToFile(oldToNewIV, outOldToNewIVfileName) ; } if ( newToOldIV != NULL ) { IV_writeToFile(newToOldIV, outNewToOldIVfileName) ; } /* ---------------------------- free all the working storage ---------------------------- */ Graph_free(graph) ; DSTree_free(dstree) ; MSMD_free(msmd) ; MSMDinfo_free(msmdinfo) ; ETree_free(etree) ; IV_free(stagesIV) ; if ( newToOldIV != NULL ) { IV_free(newToOldIV) ; } if ( oldToNewIV != NULL ) { IV_free(oldToNewIV) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ MSMD/drivers/orderViaStages.c010064400020550007177000000205510654027117000174020ustar00clevecompmath00000400000006/* orderViaStages.c */ #include "../MSMD.h" #include "../../DSTree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------- order a graph using the multi-stage minimum degree algorithm. we read in (1) a Graph object (2) a IV object that contains the stages for the vertices. (3) ordering parameters and output (optionally) (1) and ETree front tree object (2) old-to-new IV object (3) new-to-old IV object created -- 96nov01, cca ------------------------------------------------------------- */ { char *inGraphFileName, *inIVfileName, *msgFileName, *outETreeFileName, *outNewToOldIVfileName, *outOldToNewIVfileName ; double cpu, ops, t1, t2 ; ETree *etree ; FILE *msgFile ; Graph *g ; int compressFlag, ierr, msglvl, nfind, nvtx, nzf, prioType, rc, seed, stepType ; int *stages ; IV *newToOldIV, *oldToNewIV, *stagesIV ; MSMD *msmd ; MSMDinfo *msmdinfo ; if ( argc != 12 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inGraphFile inIVfile seed " "\n compressFlag prioType stepType oldToNewIVfile " "\n newToOldIVfile frontTreeFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n inIVfile -- input file, must be *.ivf or *.ivb" "\n seed -- random number seed" "\n compressFlag -- compression flag" "\n compressFlag / 4 >= 1 --> compress before elimination" "\n compressFlag %% 4 == 2 --> compress at each elimination step," "\n consider all nodes" "\n compressFlag %% 4 == 1 --> compress at each elimination step," "\n but only consider 2-adj nodes" "\n compressFlag %% 4 == 0 --> do not perform any compression" "\n prioType -- update type" "\n prioType == 1 --> true updates" "\n prioType == 2 --> approximate updates" "\n prioType == 3 --> half and half" "\n prioType == 4 --> maximal independent set" "\n stepType -- degree extent for independent set elimination" "\n when stepType < 1 --> only one node is eliminated at a step," "\n e.g., like QMD from SPARSPAK and YSMP" "\n stepType == 1 --> regular multiple elimination, e.g., GENMMD" "\n stepType > 1 --> extended multiple elimination" "\n an independent set of nodes is selected for elimination" "\n whose degree satisfies mindeg <= degree <= stepType*mindegree" "\n oldToNewIVfile -- file for old-to-new IV object" "\n newToOldIVfile -- file for new-to-old IV object" "\n frontTreeFile -- file for front tree's ETree object" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; msgFileName = argv[2] ; if ( strcmp(msgFileName, "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(msgFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], msgFileName) ; return(-1) ; } inGraphFileName = argv[3] ; inIVfileName = argv[4] ; seed = atoi(argv[5]) ; compressFlag = atoi(argv[6]) ; prioType = atoi(argv[7]) ; stepType = atoi(argv[8]) ; outETreeFileName = argv[9] ; outOldToNewIVfileName = argv[10] ; outNewToOldIVfileName = argv[11] ; fprintf(msgFile, "\n %s : " "\n msglvl -- %d" "\n msgFile -- %s" "\n inGraphFile -- %s" "\n inIVfile -- %s" "\n seed -- %d" "\n compressFlag -- %d" "\n prioType -- %d" "\n stepType -- %d" "\n outETreeFile -- %s" "\n outOldToNewFile -- %s" "\n outNewToOldFile -- %s" "\n", argv[0], msglvl, msgFileName, inGraphFileName, inIVfileName, seed, compressFlag, prioType, stepType, outETreeFileName, outOldToNewIVfileName, outNewToOldIVfileName) ; fflush(msgFile) ; /* ------------------------------------------ initialize the MSMDinfo information object ------------------------------------------ */ msmdinfo = MSMDinfo_new() ; msmdinfo->seed = seed ; msmdinfo->compressFlag = compressFlag ; msmdinfo->prioType = prioType ; msmdinfo->stepType = stepType ; msmdinfo->msglvl = msglvl ; msmdinfo->msgFile = msgFile ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; g = Graph_new() ; Graph_setDefaultFields(g) ; if ( (rc = Graph_readFromFile(g, inGraphFileName)) != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, g, inGraphFileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = g->nvtx ; if ( msglvl < 4 ) { Graph_writeStats(g, msgFile) ; fflush(msgFile) ; } else { Graph_writeForHumanEye(g, msgFile) ; fflush(msgFile) ; } /* ------------------------- read in the IV object ------------------------- */ stagesIV = IV_new() ; IV_setDefaultFields(stagesIV) ; if ( strcmp(inIVfileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; } else { MARKTIME(t1) ; if ( (rc = IV_readFromFile(stagesIV, inIVfileName)) != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, stagesIV, inIVfileName) ; exit(-1) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in IV object from file %s", t2 - t1, inIVfileName) ; } if ( msglvl < 4 ) { IV_writeStats(stagesIV, msgFile) ; fflush(msgFile) ; } else { IV_writeForHumanEye(stagesIV, msgFile) ; fflush(msgFile) ; } stages = IV_entries(stagesIV) ; /* -------------- order via msmd -------------- */ MARKTIME(t1) ; msmd = MSMD_new() ; MSMD_order(msmd, g, stages, msmdinfo) ; MARKTIME(t2) ; cpu = t2 - t1 ; fprintf(msgFile, "\n CPU %9.5f : order the graph", cpu) ; fflush(msgFile) ; MSMDinfo_print(msmdinfo, msgFile) ; fflush(msgFile) ; /* ---------------------- extract the front tree ---------------------- */ MARKTIME(t1) ; etree = MSMD_frontETree(msmd) ; nfind = ETree_nFactorIndices(etree) ; nzf = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; ops = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.5f : make the front tree", t2 - t1) ; fprintf(msgFile, "\n FACTOR : %9d indices, %9d entries, %9.0f operations", nfind, nzf, ops) ; if ( msglvl < 3 ) { ETree_writeStats(etree, msgFile) ; fflush(msgFile) ; } else { ETree_writeForHumanEye(etree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n STATS %10d %10.0f %8.3f", nzf, ops, cpu) ; /* ------------------------------------------- write the front tree to a file if requested ------------------------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { ETree_writeToFile(etree, outETreeFileName) ; } /* ----------------------------------------------------------------- generate the permutation vectors and write to a file if requested ----------------------------------------------------------------- */ if ( strcmp(outOldToNewIVfileName, "none") != 0 ) { oldToNewIV = IV_new() ; } else { oldToNewIV = NULL ; } if ( strcmp(outNewToOldIVfileName, "none") != 0 ) { newToOldIV = IV_new() ; } else { newToOldIV = NULL ; } if ( oldToNewIV != NULL || newToOldIV != NULL ) { MSMD_fillPerms(msmd, newToOldIV, oldToNewIV) ; } if ( oldToNewIV != NULL ) { IV_writeToFile(oldToNewIV, outOldToNewIVfileName) ; } if ( newToOldIV != NULL ) { IV_writeToFile(newToOldIV, outNewToOldIVfileName) ; } /* ---------------------------- free all the working storage ---------------------------- */ Graph_free(g) ; MSMD_free(msmd) ; MSMDinfo_free(msmdinfo) ; ETree_free(etree) ; if ( newToOldIV != NULL ) { IV_free(newToOldIV) ; } if ( oldToNewIV != NULL ) { IV_free(oldToNewIV) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(-1) ; } /*--------------------------------------------------------------------*/ MSMD/doc/004275500020550007177000000000000665023217300134075ustar00clevecompmath00000400000006MSMD/doc/dataStructure.tex010064000020550007177000000203410665017643000167550ustar00clevecompmath00000400000006\par \section{Data Structure} \par There are four typed objects. \begin{itemize} \item {\tt MSMD} : the main object. \item {\tt MSMDinfo} : an object that communicate parameter choices from the caller to the {\tt MSMD} object and information and statistics from the {\tt MSMD} object to the caller. \item {\tt MSMDstageInfo} : an object that contains statistics for a stage of elimination, e.g., number of steps, number of vertices eliminated, weight of vertices eliminated, etc. \item {\tt MSMDvtx} : an object that models a vertex. \end{itemize} A user needs to understand the {\tt MSMDinfo} object, so this is where we will start our description. \par %----------------------------------------------------------------------- \par \subsection{{\tt MSMDinfo} : define your algorithm} \par \begin{itemize} \item {\tt int compressFlag} -- define initial and subsequent compressions of the graph. \par We compress a graph using a checksum technique. At some point in the elimination, vertices in the reach set (those adjacent to vertices just eliminated) have a checksum based on their adjacencies computed, and then vertices with the same checksum are compared to see if they are indistinguishable. This operation has a cost, and there are classes of vertices for which there is a large amount of compression, and for other classes there is little. Compression is a powerful tool, but we need a way to control it. \begin{itemize} \item {\tt compressFlag \% 4 == 0} --- do not perform any compression after each elimination step. \item {\tt compressFlag \% 4 == 1} --- after each elimination step, consider only those nodes that are {\it 2-adjacent}, adjacent to two eliminated subtrees and having no uncovered adjacent edges. \item {\tt compressFlag \% 4 == 2} --- after each elimination step, consider all nodes. \item {\tt compressFlag / 4 >= 1} --- compress at stage zero before any elimination. \end{itemize} The default value is {\tt 1}, no initial compression and consider only 2-adjacent nodes after each elimination step. \item {\tt int prioType} --- define the priority to choose a vertex to eliminate. \begin{itemize} \item {\tt prioType == 0} --- zero priority \item {\tt prioType == 1} --- exact external degree for each vertex \item {\tt prioType == 2} --- approximate external degree for each vertex (${\hat d}$ from \cite{ame96-amd}) \item {\tt prioType == 3} --- exact external degree for 2-adjacent vertices, approximate external degree for the others \end{itemize} The default value is {\tt 1}, exact external degree for each vertex. \item {\tt double stepType} --- define the elimination steps. \begin{itemize} \item {\tt stepType == 0} --- only one vertex of minimum priority is eliminated at each step, e.g., as used in SPARSPAK's {\tt GENQMD}, YSMP's ordering, and {\tt AMD} \cite{ame96-amd}. \item {\tt stepType == 1} --- an independent set of vertices of minimum priority is eliminated at each step, e.g., as used in GENMMD, multiple minimum degree. \item {\tt stepType > 1} --- an independent set of vertices is eliminated whose priorities lie between the minimum priority and the minimum priority multiplied by {\tt stepType}. \end{itemize} The default value is {\tt 1}, multiple elimination of vertices with minimum priority. \item {\tt int seed} --- a seed used for a random number generator, this introduces a necessary random element to the ordering. \item {\tt int msglvl} -- message level for statistics, diagnostics and monitoring. The default value is zero, no statistics. Set {\tt msglvl} to one and get elimination monitoring. Increase {\tt msglvl} slowly to get more mostly debug information. \item {\tt FILE *msgFile} -- message file, default is {\tt stdout}. \item {\tt int maxnbytes} -- maximum number of bytes used during the ordering. \item {\tt int nbytes} -- present number of bytes used during the ordering. \item {\tt int istage} -- present stage of elimination. \item {\tt int nstage} -- number of stages of elimination. \item {\tt MSMDstageInfo *stageInfo} -- pointer to vector of {\tt MSMDstageInfo} structures that hold information about each stage of the elimination. \item {\tt double totalCPU} -- total CPU to find the ordering. \end{itemize} %----------------------------------------------------------------------- \par \subsection{{\tt MSMD} : driver object} \par A user need not know anything about the internals of this object, just the methods to initialize it, order the graph, and extract the permutation vectors and/or a front tree. \par \begin{itemize} \item {\tt int nvtx} --- number of internal vertices in the graph. \item {\tt IIheap *heap} -- pointer to a {\tt IIheap} object that maintains the priority queue. \item {\tt IP *baseIP} -- pointer to the base {\tt IP} objects, used to hold subtree lists \item {\tt IP *freeIP} -- pointer to the list of free {\tt IP} objects \item {\tt int incrIP} -- integer that holds the increment factor for the {\tt IP} objects. \item {\tt MSMDvtx *vertices} -- pointer to vector of {\tt MSMDvtx} objects that represent the vertices. \item {\tt IV ivtmpIV} -- {\tt IV} object that holds an integer temporary vector. \item {\tt IV reachIV} -- {\tt IV} object that holds the reach vector. \end{itemize} \par %----------------------------------------------------------------------- \par \subsection{{\tt MSMDstageInfo} : statistics object for a stage of the elimination} \par This object stores information about the elimination process at a stage of the elimination. \par \begin{itemize} \item {\tt int nstep} --- number of elimination steps in this stage \item {\tt int nfront} --- number of fronts created at this stage \item {\tt int welim} --- weight of the vertices eliminated at this stage \item {\tt int nfind} --- number of front indices \item {\tt int nzf} --- number of factor entries (for a Cholesky factorization) \item {\tt double ops} --- number of factor operations (for a Cholesky factorization) \item {\tt int nexact2} --- number of exact degree updates to 2-adjacent vertices \item {\tt int nexact3} --- number of exact degree updates to non-2-adjacent vertices \item {\tt int napprox} --- number of approximate degree updates \item {\tt int ncheck} --- number of comparisons of vertices with the same checksum during the process to find indistinguishable nodes \item {\tt int nindst} --- number of indistinguishable nodes that were detected. \item {\tt int noutmtch} --- number of nodes that were outmatched \item {\tt double cpu} --- elapsed CPU time for this stage of the elimination. \end{itemize} \par %----------------------------------------------------------------------- \par \subsection{{\tt MSMDvtx} : vertex object} \par This object stores information for a vertex during the elimination. \par \begin{itemize} \item {\tt int id} --- id of the vertex, in range {\tt [0,nvtx)} \item {\tt char mark} --- character mark flag, {\tt 'O'} or {\tt 'X'} \item {\tt char status} --- character status of the vertex \begin{itemize} \item {\tt 'L'} -- eliminated leaf vertex \item {\tt 'E'} -- eliminated interior vertex \item {\tt 'O'} -- outmatched vertex \item {\tt 'D'} -- vertex on degree (priority) heap \item {\tt 'R'} -- vertex on reach set \item {\tt 'I'} -- vertex found to be indistinguishable to another \item {\tt 'B'} -- boundary vertex, to be eliminated in another stage \end{itemize} \item {\tt int stage} --- stage of the vertex. Stage 0 nodes are eliminated before stage 1 nodes, etc. \item {\tt int wght} --- weight of the vertex \item {\tt int nadj} --- size of the {\tt adj} vector \item {\tt int *adj} --- for an uneliminated vertex, {\tt adj} points to a list of uncovered adjacent edges; for an eliminated vertex, {\tt adj} points points to a list of its boundary vertices (only valid when the vertex is a leaf of the elimination tree or a root of a subtree of uneliminated vertices). \item {\tt int bndwght} --- for an eliminated vertex, the weight of the vertices on its boundary. \item {\tt MSMDvtx *par} --- for an eliminated vertex, {\tt par} points to its parent vertex in the front tree ({\tt NULL} if the vertex is the root of a subtree). For an indistinguishable vertex, {\tt par} points to its representative vertex (which may have also been found to be indistinguishable to another). \item {\tt IP *subtrees} --- pointer to a list of {\tt IP} objects to store the adjacent subtrees, valid only for uneliminated vertices. \end{itemize} MSMD/doc/intro.tex010064000020550007177000000103360665023074500152610ustar00clevecompmath00000400000006\chapter{{\tt MSMD}: \break {\tt M}ulti-{\tt S}tage {\tt M}inimum {\tt D}egree Object} \par We need an ordering for a sparse matrix. The {\tt MSMD} object will provide one of three orderings: \begin{itemize} \item a minimum degree ordering, or \item a multisection ordering if given with a domain/Schur-complement partition, or \item a nested dissection ordering if given a domain/separator tree. \end{itemize} \par But in what form do we want our ordering? If all we want is a permutation vector, there is a {\tt MSMD} method that will fill them. If we want more information, a method returns the {\tt ETree} object that is a front tree\footnote{ The {\tt ETree} object has the {\tt Tree} object that defines the connectivity of the fronts, knows the internal and external size of each front, and has a map from the vertices to the fronts. } for the ordering. \par The {\tt MSMD object} is complex, at least in its functionality. However, its component methods are simple; one can put them together in different ways to get a wide variety of algorithms. \par There are methods to eliminate a vertex or set of vertices in one of three ways: \begin{itemize} \item a single vertex, or \item a {\it step} of vertices, i.e., an independent set of vertices, or \item a {\it stage} of vertices, i.e., a set of vertices defined in a number of consecutive steps. \end{itemize} How to choose a vertex to eliminate is based on a {\it priority}, currently one of: \begin{itemize} \item external degree, or \item approximate external degree, (${\hat d}$ from \cite{ame96-amd}) and \cite{sparsematlab}, or \item half external and half approximate, (${\tilde d}$ from \cite{ame96-amd}), or \item a constant priority (to induce maximal independent set elimination). \end{itemize} We intend to add more priorities, e.g., approximate deficiency from \cite{ng96-mindefIdaho}, \cite{rot96-mindefIdaho} and \cite{rot98-mindef}. \par Choose a priority, then specify the definition of a {\it step}, how to choose an independent set of vertices to eliminate at a time. Then provide a map from each vertex to the {\it stage} at which it will be eliminated. \par Presently there is one ordering method, {\tt MSMD\_order()}. It orders the vertices by {\it stages}, i.e. vertices in stage $k$ will be ordered before vertices in stage $k+1$. Inside each {\it stage} the vertices are ordered by {\it steps}. At each step an independent set of vertices is eliminated, and the choice is based on their priorities. When the ordering is finished one can extract permutation vectors of a front tree. \par Here are three examples of how stages define an ordering method. (These methods are supported by the present {\tt MSMD} object). \begin{itemize} \item Set the stage of each vertex to be zero and we have a simple minimum degree (priority) ordering. \item Given a domain/Schur complement partition or a domain/separator tree, we can find a multisection ordering by setting the stage of a vertex to be zero if it is a domain or one if it is in a separator. \item Given a domain/separator tree, we can find an incomplete nested dissection ordering by specifying the stage of a vertex to be the level of the separator or domain that contains it. \end{itemize} Here are three slightly more complicated examples. \begin{itemize} \item Order the vertices in the domains, then order the Schur complement graph both by nested dissection and minimum degree, and then splice the better of the two orderings together with the ordering of the domain vertices. \item Apply the above algorithm to the Schur complement graph recursively. \item % By and large, multisection is consistently better than nested % dissection, but there are graphs where the reverse holds, % e.g., 3-d cubes. Since multisection is nothing more than applying minimum degree to the Schur complement graph, randomly permute the graph and apply the minimum degree ordering. Repeat several times and take the best ordering. (Ordering the Schur complement graph is much, much less time consuming than ordering the vertices in the domains.) \end{itemize} Any of these three algorithms is bound to be better than both nested dissection and multisection. The tools are largely written so any of these three algorithms can be prototyped in a small amount of time and effort. MSMD/doc/main.tex010064400020550007177000000010760665065626600150710ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt MSMD} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt MSMD} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} MSMD/doc/main.log010064400020550007177000000146260665017643500150520ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 16 JAN 1999 12:56 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/latex209.def File: latex209.def 1996/05/21 v0.51 Standard LaTeX file Entering LaTeX 2.09 compatibility mode. \footheight=\dimen102 \@maxsep=\dimen103 \@dblmaxsep=\dimen104 \@cla=\count79 \@clb=\count80 \mscount=\count81 (/home/tex/teTeX/texmf/tex/latex/base/tracefnt.sty Package: tracefnt 1996/07/26 v3.0i Standard LaTeX package (font tracing) \tracingfonts=\count82 LaTeX Info: Redefining \selectfont on input line 139. ) \symbold=\mathgroup4 \symsans=\mathgroup5 \symtypewriter=\mathgroup6 \symitalic=\mathgroup7 \symsmallcaps=\mathgroup8 \symslanted=\mathgroup9 LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 306. LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 307. LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 308. LaTeX Font Info: Redeclaring math alphabet \mathit on input line 314. LaTeX Info: Redefining \em on input line 324. (/home/tex/teTeX/texmf/tex/latex/base/latexsym.sty Package: latexsym 1996/11/20 v2.2d Standard LaTeX package (lasy symbols) \symlasy=\mathgroup10 LaTeX Font Info: Overwriting symbol font `lasy' in version `bold' (Font) U/lasy/m/n --> U/lasy/b/n on input line 85. ) LaTeX Font Info: Redeclaring math delimiter \lgroup on input line 388. LaTeX Font Info: Redeclaring math delimiter \rgroup on input line 390. LaTeX Font Info: Redeclaring math delimiter \bracevert on input line 392. (/home/tex/teTeX/texmf/tex/latex/config/latex209.cfg (/home/tex/teTeX/texmf/tex/latex/tools/rawfonts.sty Compatibility mode: package `' requested, but `rawfonts' provided. Package: rawfonts 1994/05/08 Low-level LaTeX 2.09 font compatibility (/home/tex/teTeX/texmf/tex/latex/tools/somedefs.sty Package: somedefs 1994/06/01 Toolkit for optional definitions ) LaTeX Font Info: Try loading font information for U+lasy on input line 36. (/home/tex/teTeX/texmf/tex/latex/base/ulasy.fd File: ulasy.fd 1996/11/20 v2.2dLaTeX symbol font definitions )))) (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size11.clo File: size11.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count83 \c@chapter=\count84 \c@section=\count85 \c@subsection=\count86 \c@subsubsection=\count87 \c@paragraph=\count88 \c@subparagraph=\count89 \c@figure=\count90 \c@table=\count91 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 Compatibility mode: definition of \rm ignored. Compatibility mode: definition of \sf ignored. Compatibility mode: definition of \tt ignored. Compatibility mode: definition of \bf ignored. Compatibility mode: definition of \it ignored. Compatibility mode: definition of \sl ignored. Compatibility mode: definition of \sc ignored. LaTeX Info: Redefining \cal on input line 622. LaTeX Info: Redefining \mit on input line 623. \bibindent=\dimen105 ) \@indexfile=\write3 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. (intro.tex Chapter 1. LaTeX Font Info: Try loading font information for OMS+cmr on input line 8. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10.95> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 8. LaTeX Font Info: External font `cmex10' loaded for size (Font) <10.95> on input line 20. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 20. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 20. LaTeX Font Info: External font `cmex10' loaded for size (Font) <9> on input line 24. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 24. LaTeX Warning: Citation `ame96-amd' on page 1 undefined on input line 49. LaTeX Warning: Citation `sparsematlab' on page 1 undefined on input line 49. LaTeX Warning: Citation `ame96-amd' on page 1 undefined on input line 52. LaTeX Warning: Citation `ng96-mindefIdaho' on page 1 undefined on input line 60 . LaTeX Warning: Citation `rot96-mindefIdaho' on page 1 undefined on input line 6 0. [1 ]) (dataStructure.tex [2] LaTeX Warning: Citation `ame96-amd' on page 3 undefined on input line 71. LaTeX Warning: Citation `ame96-amd' on page 3 undefined on input line 85. [3] [4] [5]) (proto.tex [6] [7] [8] [9] Overfull \hbox (11.7664pt too wide) in paragraph at lines 413--413 []\OT1/cmtt/m/n/10.95 void MSMD_makeSchurComplement ( MSMD *msmd, Graph *schur Graph, IV *VtoPhiIV ) ;[] [] ) (drivers.tex [10] Overfull \hbox (19.63927pt too wide) in paragraph at lines 28--33 \OT1/cmtt/m/n/10.95 *.graphf \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.graphb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 Graph \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 Graph[]readFromFile() [] [11]) (main.ind [12] [13 ]) (main.aux) LaTeX Warning: There were undefined references. ) Here is how much of TeX's memory you used: 615 strings out of 10908 6428 string characters out of 72189 50903 words of memory out of 262141 3466 multiletter control sequences out of 9500 26190 words of font info for 97 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 23i,6n,21p,313b,343s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (13 pages, 37724 bytes). omedefs.sty Package: somedefs 1994/06/01 Toolkit for optional definitions ) LaTeX Font Info: Try loadinMSMD/doc/main.aux010064400020550007177000000050170665017643500150600ustar00clevecompmath00000400000006\relax \citation{ame96-amd} \citation{sparsematlab} \citation{ame96-amd} \citation{ng96-mindefIdaho} \citation{rot96-mindefIdaho} \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt MSMD}: \penalty -\@M {\tt M}ulti-{\tt S}tage {\tt M}inimum {\tt D}egree Object}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{2}} \citation{ame96-amd} \citation{ame96-amd} \@writefile{toc}{\contentsline {subsection}{\numberline {1.1.1}{\tt MSMDinfo} : define your algorithm}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.1.2}{\tt MSMD} : driver object}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.1.3}{\tt MSMDstageInfo} : statistics object for a stage of the elimination}{5}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.1.4}{\tt MSMDvtx} : vertex object}{5}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt MSMDinfo} methods}{6}} \newlabel{section:MSMDinfo:proto}{{1.2}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{6}} \newlabel{subsection:MSMDinfo:proto:basics}{{1.2.1}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Utility methods}{7}} \newlabel{subsection:MSMDinfo:proto:utility}{{1.2.2}{7}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Prototypes and descriptions of {\tt MSMD} methods}{7}} \newlabel{section:MSMD:proto}{{1.3}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.3.1}Basic methods --- public}{7}} \newlabel{subsection:MSMD:proto:basics}{{1.3.1}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.3.2}Initialization methods --- public}{8}} \newlabel{subsection:MSMD:proto:init}{{1.3.2}{8}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.3.3}Ordering methods --- public}{8}} \newlabel{subsection:MSMD:proto:order}{{1.3.3}{8}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.3.4}Extraction methods --- public}{8}} \newlabel{subsection:MSMD:proto:extraction}{{1.3.4}{8}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.3.5}Internal methods --- private}{9}} \newlabel{subsection:MSMD:proto:private}{{1.3.5}{9}} \@writefile{toc}{\contentsline {section}{\numberline {1.4}Prototypes and descriptions of {\tt MSMDvtx} methods}{10}} \newlabel{section:MSMDvtx:proto}{{1.4}{10}} \@writefile{toc}{\contentsline {section}{\numberline {1.5}Driver programs for the {\tt MSMD} object}{11}} \newlabel{section:MSMD:drivers}{{1.5}{11}} MSMD/doc/drivers.tex010064400020550007177000000123500653410611100155740ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt MSMD} object} \label{section:MSMD:drivers} \par This section contains brief descriptions of four driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} orderViaMMD msglvl msgFile inGraphFile seed compressFlag prioType stepType outOldToNewIVfile outNewToOldIVfile outETreeFile \end{verbatim} This driver program orders a graph using the multiple minimum degree algorithm --- exactly which algorithm is controlled by the input parameters. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the output file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt seed} parameter is a random number seed. \item The {\tt compressFlag} parameter controls the compression of the graph (identifying indistinguishable nodes) before and during the elimination process. \begin{itemize} \item {\tt compressFlag / 4 >= 1} --- a compression step is done before elimination. \item {\tt compressFlag \% 4 == 2} --- compress after each elimination step, consider all nodes. \item {\tt compressFlag \% 4 == 1} --- compress after each elimination step, consider only 2-adjacent nodes (the most likely to form indistinguishable nodes). \item {\tt compressFlag \% 4 == 0} --- do no compression. \end{itemize} \item The {\tt prioType} parameter controls the type of priority that is used to choose nodes to eliminate. \begin{itemize} \item {\tt prioType == 1} --- true external degree. \item {\tt prioType == 2} --- approximate external degree. \item {\tt prioType == 3} --- true external degree for 2-adjacent nodes, approximate external degree for the others. \item {\tt prioType == 4} --- priority of each node is zero; this implies random elimination. \end{itemize} \item The {\tt stepType} parameter controls the type of multiple elimination to be done. \begin{itemize} \item {\tt stepType == 0} --- one vertex eliminated at each step, like YSMP, and QMD from SPARSPAK. \item {\tt stepType == 1} --- regular multiple elimination, e.g., GENMMD. \item {\tt stepType > 1} --- vertices whose priority lies between the minimum priority and {\tt stepType} times the minimum priority are eligible for elimination at a step. \end{itemize} \item The {\tt outOldToNewIVfile} parameter is the output file for the {\tt IV} object that contains the old-to-new permutation vector. If {\tt outOldToNewIVfile} is {\tt "none"}, then there is no output, otherwise {\tt outOldToNewIVfile} must be of the form {\tt *.ivf} or {\tt *.ivb}. \item The {\tt outNewToOldIVfile} parameter is the output file for the {\tt IV} object that contains the new-to-old permutation vector. If {\tt outNewToOldIVfile} is {\tt "none"}, then there is no output, otherwise {\tt outNewToOldIVfile} must be of the form {\tt *.ivf} or {\tt *.ivb}. \item The {\tt outETreeFile} parameter is the output file for the {\tt ETree} object that contains the front tree for the ordering. If {\tt outETreeFile} is {\tt "none"}, then there is no output, otherwise {\tt outETreeFile} must be of the form {\tt *.etreef} or {\tt *.etreeb}. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} orderViaND msglvl msgFile inGraphFile inDSTreeFile seed compressFlag prioType stepType outOldToNewIVfile outNewToOldIVfile outETreeFile \end{verbatim} This driver program orders a graph using the incomplete nested dissection algorithm. The stages of elimination are generated by a {\tt DSTree} domain/separator tree object that is read in from the {\tt inDSTreeFile} file. All the other parameters are the same as for the {\tt orderViaMMD} driver program. %----------------------------------------------------------------------- \item \begin{verbatim} orderViaMS msglvl msgFile inGraphFile inDSTreeFile seed compressFlag prioType stepType outOldToNewIVfile outNewToOldIVfile outETreeFile \end{verbatim} This driver program orders a graph using the multisection algorithm. The stages of elimination are generated by a {\tt DSTree} domain/separator tree object that is read in from the {\tt inDSTreeFile} file. All the other parameters are the same as for the {\tt orderViaMMD} driver program. %----------------------------------------------------------------------- \item \begin{verbatim} orderViaStages msglvl msgFile inGraphFile inStagesIVfile seed compressFlag prioType stepType outOldToNewIVfile outNewToOldIVfile outETreeFile \end{verbatim} This driver program orders a graph using the multi-stage minimum degree algorithm. The stages of elimination are found in an {\tt IV} object that is read in from the {\tt inStagesIVfile} file. All the other parameters are the same as for the {\tt orderViaMMD} driver program. %----------------------------------------------------------------------- \end{enumerate} g} parameter controls the compression of the graph (identifying indistinguishable nodes) before and during the elimination process. \begin{itemize} \item {\tt compressFlag / 4 >= 1} --- a compression step is done before elimination. \item {\tt compressFlag \% 4 == 2} --- comprMSMD/doc/proto.tex010064400020550007177000000423400653410611100152630ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt MSMDinfo} methods} \label{section:MSMDinfo:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt MSMDinfo} object. \par \subsection{Basic methods} \label{subsection:MSMDinfo:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} MSMDinfo * MSMDinfo_new ( void ) ; \end{verbatim} \index{MSMDinfo_new@{\tt MSMDinfo\_new()}} This method simply allocates storage for the {\tt MSMDinfo} structure and then sets the default fields by a call to {\tt MSMDinfo\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMDinfo_setDefaultFields ( MSMDinfo *info ) ; \end{verbatim} \index{MSMDinfo_setDefaultFields@{\tt MSMDinfo\_setDefaultFields()}} This method sets the structure's fields to default values. \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMDinfo_clearData ( MSMDinfo *info ) ; \end{verbatim} \index{MSMDinfo_clearData@{\tt MSMDinfo\_clearData()}} This method clears any data owned by the object and then sets the structure's default fields with a call to {\tt MSMDinfo\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMDinfo_free ( MSMDinfo *info ) ; \end{verbatim} \index{MSMDinfo_free@{\tt MSMDinfo\_free()}} This method releases any storage by a call to {\tt MSMDinfo\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. \end{enumerate} %----------------------------------------------------------------------- \par \subsection{Utility methods} \label{subsection:MSMDinfo:proto:utility} \par There are two utility methods, one to print the object, one to check to see if it is valid. \par \begin{enumerate} \item \begin{verbatim} void MSMDinfo_print ( MSMDinfo *info, FILE *fp ) ; \end{verbatim} \index{MSMDinfo_print@{\tt MSMDinfo\_print()}} This method prints out the information to a file. \par \noindent {\it Error checking:} If {\tt info} or {\tt fp} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int MSMDinfo_isValid ( MSMDinfo *info ) ; \end{verbatim} \index{MSMDinfo_isValid@{\tt MSMDinfo\_isValid()}} This method checks that the object is valid. The return value is {\tt 1} for a valid object, {\tt 0} for an invalid object. \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} %======================================================================= \par \section{Prototypes and descriptions of {\tt MSMD} methods} \label{section:MSMD:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt MSMD} object. The methods are loosely classified as {\it public} and {\it private}. Since the C language does not support private methods (with the exception of {\tt static} methods within a file), specifying a method as public or private is advisory. \par \subsection{Basic methods --- public} \label{subsection:MSMD:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} MSMD * MSMD_new ( void ) ; \end{verbatim} \index{MSMD_new@{\tt MSMD\_new()}} This method simply allocates storage for the {\tt MSMD} structure and then sets the default fields by a call to {\tt MSMD\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_setDefaultFields ( MSMD *msmd ) ; \end{verbatim} \index{MSMD_setDefaultFields@{\tt MSMD\_setDefaultFields()}} This method sets the structure's fields to default values. \par \noindent {\it Error checking:} If {\tt msmd} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_clearData ( MSMD *msmd ) ; \end{verbatim} \index{MSMD_clearData@{\tt MSMD\_clearData()}} This method clears any data owned by the object, then sets the structure's default fields with a call to {\tt MSMD\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt msmd} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_free ( MSMD *msmd ) ; \end{verbatim} \index{MSMD_free@{\tt MSMD\_free()}} This method releases any storage by a call to {\tt MSMD\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt msmd} is {\tt NULL}, an error message is printed and the program exits. \end{enumerate} %======================================================================= \par \subsection{Initialization methods --- public} \label{subsection:MSMD:proto:init} \par There is one initialization method. \par \begin{enumerate} \item \begin{verbatim} void MSMD_init ( MSMD *msmd, Graph *graph, int stages[], MSMD *info ) ; \end{verbatim} \index{MSMD_init@{\tt MSMD\_init()}} This method initializes the {\tt MSMD} object prior to an ordering. It is called by {\tt MSMD\_order()} method, and so it is currently a {\it private} method for the object. However, when designing more complicated ordering methods, this object is necessary to set up the data structures. There are two input arguments: {\tt graph} is a pointer to a {\tt Graph} object that holds the adjacency lists and weights of the vertices, and {\tt stages} is a map from each vertex to the stage at which it is to be eliminated. (If {\tt stages == NULL}, then all vertices will be eliminated in one stage, i.e., we order the graph using minimum degree.) Unlike much other ordering software, we do {\bf not} destroy the adjacency structure of the graph --- however we might shuffle the entries in each adjacency list. \par \noindent {\it Error checking:} If {\tt msmd}, {\tt graph} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} %======================================================================= \par \subsection{Ordering methods --- public} \label{subsection:MSMD:proto:order} \par There is currently one ordering method. \par \begin{enumerate} \item \begin{verbatim} void MSMD_order ( MSMD *msmd, Graph *graph, int stages[], MSMD *info ) ; \end{verbatim} \index{MSMD_order@{\tt MSMD\_order()}} This method orders the vertices in the graph and maintains the {\tt MSMDvtx} objects in a suitable representation to generate permutation vectors and/or a front tree. The input is the same as for the {\tt MSMD\_init()} method defined above. \par The method first checks that the input is valid, i.e., that {\tt msmd}, {\tt graph} and {\tt info} are not {\tt NULL} and that the {\tt info} structure is valid by calling {\tt MSMD\_isValid()}. The {\tt msmd} is then initialized by calling {\tt MSMD\_init()}. If called for, the graph is compressed prior to any elimination. The vertices are then eliminated by their stages via calls to {\tt MSMD\_eliminateStage()}. The overall statistics for the elimination are then computed, and then the working storage is then released, save for the {\tt MSMDvtx} structures. \par \noindent {\it Error checking:} If {\tt msmd}, {\tt graph} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. \end{enumerate} %======================================================================= \par \subsection{Extraction methods --- public} \label{subsection:MSMD:proto:extraction} \par There are two methods to extract the ordering. The first fills one or two {\tt IV} objects with the permutation vector(s). The second returns an {\tt ETree} object that holds the front tree for the ordering. \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_fillPerms ( MSMD *msmd, IV *newToOldIV, IV *oldToNewIV ) ; \end{verbatim} \index{MSMD_fillPerms@{\tt MSMD\_fillPerms()}} If {\tt newToOldIV} is not {\tt NULL}, this method fills the {\tt IV} object with the new-to-old permutation of the vertices, resizing the {\tt IV} object if necessary. If {\tt oldToNewIV} is not {\tt NULL}, this method fills the {\tt IV} object with the old-to-new permutation of the vertices, resizing the {\tt IV} object if necessary. \par \noindent {\it Error checking:} If {\tt msmd} is {\tt NULL}, or if {\tt newToOldIV} and {\tt oldToNewIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ETree * MSMD_frontETree ( MSMD *msmd ) ; \end{verbatim} \index{MSMD_frontETree@{\tt MSMD\_frontETree()}} This method constructs and returns a {\tt ETree} object that contains the front tree for the ordering. \par \noindent {\it Error checking:} If {\tt msmd} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} %======================================================================= \par \subsection{Internal methods --- private} \label{subsection:MSMD:proto:private} \par The following methods are used internally to order the graph. the user should never have any cause to call them. \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_eliminateStage ( MSMD *msmd, MSMD *info ) ; \end{verbatim} \index{MSMD_eliminateStage@{\tt MSMD\_eliminateStage()}} This method eliminates the vertices in the present stage. \par \noindent {\it Error checking:} If {\tt msmd} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int MSMD_eliminateStep ( MSMD *msmd, MSMD *info ) ; \end{verbatim} \index{MSMD_eliminateStep@{\tt MSMD\_eliminateStep()}} This method eliminates one {\it step} of vertices, an independent set of vertices. The return value is the weight of the vertices eliminated at this step. \par \noindent {\it Error checking:} If {\tt msmd} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_eliminateVtx ( MSMD *msmd, MSMDvtx *v, MSMD *info ) ; \end{verbatim} \index{MSMD_eliminateVtx@{\tt MSMD\_eliminateVtx()}} This method eliminates vertex {\tt v}. \par \noindent {\it Error checking:} If {\tt msmd}, {\tt v} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_findInodes ( MSMD *msmd, MSMD *info ) ; \end{verbatim} \index{MSMD_findInodes@{\tt MSMD\_findInodes()}} This method examines nodes in the reach set to detect indistinguishability. \begin{itemize} \item If {\tt info->compressFlag \% 4 == 0}, there is a simple return. \item If {\tt info->compressFlag \% 4 == 1}, only 2-adjacent nodes are examined. \item If {\tt info->compressFlag \% 4 == 2}, all nodes are examined. \end{itemize} The order of the nodes in the reach set may be permuted, but any indistinguishable nodes in the reach set are not purged from the reach set. \par \noindent {\it Error checking:} If {\tt msmd} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_cleanReachSet ( MSMD *msmd, MSMD *info ) ; \end{verbatim} \index{MSMD_cleanReachSet@{\tt MSMD\_cleanReachSet()}} This method cleans the nodes in the reach set by calling {\tt MSMD\_cleanSubtreeList()} and {\tt MSMD\_clearEdgeList()}. \par \noindent {\it Error checking:} If {\tt msmd} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_cleanSubtreeList ( MSMD *msmd, MSMDvtx *v, MSMD *info ) ; \end{verbatim} \index{MSMD_cleanSubtreeList@{\tt MSMD\_cleanSubtreeList()}} This method cleans the list of subtrees for vertex {\tt v}, removing any node which is no longer the root of a subtree of eliminated nodes. \par \noindent {\it Error checking:} If {\tt msmd}, {\tt v} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_cleanEdgeList ( MSMD *msmd, MSMDvtx *v, MSMD *info ) ; \end{verbatim} \index{MSMD_cleanEdgeList@{\tt MSMD\_cleanEdgeList()}} This method cleans the list of uncovered edges for vertex {\tt v}, removing any edge {\tt (v,w)} where {\tt v} and {\tt w} share a common adjacent subtree. \par \noindent {\it Error checking:} If {\tt msmd}, {\tt v} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_update ( MSMD *msmd, MSMD *info ) ; \end{verbatim} \index{MSMD_update@{\tt MSMD\_update()}} This method updates the priorities of all nodes in the reach set. \par \noindent {\it Error checking:} If {\tt msmd} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int MSMD_exactDegree2 ( MSMD *msmd, MSMDvtx *v, MSMD *info ) ; \end{verbatim} \index{MSMD_exactDegree2@{\tt MSMD\_exactDegree2()}} This method computes and returns the exact external degree for vertex {\tt v}. \par \noindent {\it Error checking:} If {\tt msmd}, {\tt v} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int MSMD_exactDegree3 ( MSMD *msmd, MSMDvtx *v, MSMD *info ) ; \end{verbatim} \index{MSMD_exactDegree3@{\tt MSMD\_exactDegree3()}} This method computes and returns the exact external degree for vertex {\tt v}. \par \noindent {\it Error checking:} If {\tt msmd}, {\tt v} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int MSMD_approxDegree ( MSMD *msmd, MSMDvtx *v, MSMD *info ) ; \end{verbatim} \index{MSMD_approxDegree@{\tt MSMD\_approxDegree()}} This method computes and returns the approximate external degree for vertex {\tt v}. \par \noindent {\it Error checking:} If {\tt msmd}, {\tt v} or {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void MSMD_makeSchurComplement ( MSMD *msmd, Graph *schurGraph, IV *VtoPhiIV ) ; \end{verbatim} \index{MSMD_makeSchurComplement@{\tt MSMD\_makeSchurComplement()}} This method fills {\tt schurGraph} with the graph of the Schur complement matrix (the fill graph of the uneliminated vertices) and fills {\tt VtoPhiIV} with a map from the vertices of the original graph to the vertices of the Schur complement graph. (The mapped value of an eliminated vertex is {\tt -1}.) \par \noindent {\it Error checking:} If {\tt msmd}, {\tt schurGraph} or {\tt VtoPhiIV} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par %======================================================================= \par \section{Prototypes and descriptions of {\tt MSMDvtx} methods} \label{section:MSMDvtx:proto} \par The {\tt MSMDvtx} object is private so would not normally be accessed by the user. There is one method to print out the object. \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void MSMDvtx_print ( MSMDvtx *v, FILE *fp ) ; \end{verbatim} \index{MSMDvtx_print@{\tt MSMDvtx\_print()}} This method prints a human-readable representation of a vertex, used for debugging. \par \noindent {\it Error checking:} If {\tt v} or {\tt fp} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} %======================================================================= MSMD/doc/main.ind010064400020550007177000000020100654026640200150130ustar00clevecompmath00000400000006\begin{theindex} \item {\tt MSMD\_approxDegree()}, 10 \item {\tt MSMD\_cleanEdgeList()}, 10 \item {\tt MSMD\_cleanReachSet()}, 9 \item {\tt MSMD\_cleanSubtreeList()}, 10 \item {\tt MSMD\_clearData()}, 7 \item {\tt MSMD\_eliminateStage()}, 9 \item {\tt MSMD\_eliminateStep()}, 9 \item {\tt MSMD\_eliminateVtx()}, 9 \item {\tt MSMD\_exactDegree2()}, 10 \item {\tt MSMD\_exactDegree3()}, 10 \item {\tt MSMD\_fillPerms()}, 8 \item {\tt MSMD\_findInodes()}, 9 \item {\tt MSMD\_free()}, 7 \item {\tt MSMD\_frontETree()}, 9 \item {\tt MSMD\_init()}, 8 \item {\tt MSMD\_makeSchurComplement()}, 10 \item {\tt MSMD\_new()}, 7 \item {\tt MSMD\_order()}, 8 \item {\tt MSMD\_setDefaultFields()}, 7 \item {\tt MSMD\_update()}, 10 \item {\tt MSMDinfo\_clearData()}, 6 \item {\tt MSMDinfo\_free()}, 6 \item {\tt MSMDinfo\_isValid()}, 7 \item {\tt MSMDinfo\_new()}, 6 \item {\tt MSMDinfo\_print()}, 7 \item {\tt MSMDinfo\_setDefaultFields()}, 6 \item {\tt MSMDvtx\_print()}, 10 \end{theindex} MSMD/doc/main.idx010064400020550007177000000030570665017643500150510ustar00clevecompmath00000400000006\indexentry{MSMDinfo_new@{\tt MSMDinfo\_new()}}{6} \indexentry{MSMDinfo_setDefaultFields@{\tt MSMDinfo\_setDefaultFields()}}{6} \indexentry{MSMDinfo_clearData@{\tt MSMDinfo\_clearData()}}{6} \indexentry{MSMDinfo_free@{\tt MSMDinfo\_free()}}{6} \indexentry{MSMDinfo_print@{\tt MSMDinfo\_print()}}{7} \indexentry{MSMDinfo_isValid@{\tt MSMDinfo\_isValid()}}{7} \indexentry{MSMD_new@{\tt MSMD\_new()}}{7} \indexentry{MSMD_setDefaultFields@{\tt MSMD\_setDefaultFields()}}{7} \indexentry{MSMD_clearData@{\tt MSMD\_clearData()}}{7} \indexentry{MSMD_free@{\tt MSMD\_free()}}{7} \indexentry{MSMD_init@{\tt MSMD\_init()}}{8} \indexentry{MSMD_order@{\tt MSMD\_order()}}{8} \indexentry{MSMD_fillPerms@{\tt MSMD\_fillPerms()}}{8} \indexentry{MSMD_frontETree@{\tt MSMD\_frontETree()}}{9} \indexentry{MSMD_eliminateStage@{\tt MSMD\_eliminateStage()}}{9} \indexentry{MSMD_eliminateStep@{\tt MSMD\_eliminateStep()}}{9} \indexentry{MSMD_eliminateVtx@{\tt MSMD\_eliminateVtx()}}{9} \indexentry{MSMD_findInodes@{\tt MSMD\_findInodes()}}{9} \indexentry{MSMD_cleanReachSet@{\tt MSMD\_cleanReachSet()}}{9} \indexentry{MSMD_cleanSubtreeList@{\tt MSMD\_cleanSubtreeList()}}{10} \indexentry{MSMD_cleanEdgeList@{\tt MSMD\_cleanEdgeList()}}{10} \indexentry{MSMD_update@{\tt MSMD\_update()}}{10} \indexentry{MSMD_exactDegree2@{\tt MSMD\_exactDegree2()}}{10} \indexentry{MSMD_exactDegree3@{\tt MSMD\_exactDegree3()}}{10} \indexentry{MSMD_approxDegree@{\tt MSMD\_approxDegree()}}{10} \indexentry{MSMD_makeSchurComplement@{\tt MSMD\_makeSchurComplement()}}{10} \indexentry{MSMDvtx_print@{\tt MSMDvtx\_print()}}{10} MSMD/doc/main.ilg010064400020550007177000000004570654026640200150310ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (27 entries accepted, 0 rejected). Sorting entries....done (138 comparisons). Generating output file main.ind....done (31 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. MSMD/doc/makefile010064400020550007177000000000270654276745100151150ustar00clevecompmath00000400000006clean : - rm -f *.dvi MT.h010064400020550007177000000000730656406466700126050ustar00clevecompmath00000400000006#ifndef _MT_ #define _MT_ #include "MT/spoolesMT.h" #endif MT/spoolesMT.h010064400020550007177000000143210657133713000145150ustar00clevecompmath00000400000006/* spoolesMT.h */ #include "../FrontMtx.h" #include "../Lock.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- parallel factorization method for A. all but two input parameters are the same as the serial method. this is a wrapper method around FrontMtx_MT_factorInpMtx(). ownersIV -- pointer to IV object that holds map from fronts to threads lookahead -- lookahead parameter that allows computation at higher levels of the front tree to proceed when lower fronts are not yet finish. use lookahead = 0 to turn off this option. otherwise lookahead ancestors of an active unfinished front can be active. return value -- pointer to the first Chv object in a list that contains postponed data created -- 98may16, cca ------------------------------------------------------------------- */ Chv * FrontMtx_MT_factorInpMtx ( FrontMtx *frontmtx, InpMtx *inpmtx, double tau, double droptol, ChvManager *chvmanager, IV *ownersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile ) ; /* ------------------------------------------------------------------- parallel factorization method for A + sigma*B. all but two input parameters are the same as the FrontMtx_factorPencil method. ownersIV -- pointer to IV object that holds map from fronts to threads lookahead -- lookahead parameter that allows computation at higher levels of the front tree to proceed when lower fronts are not yet finish. use lookahead = 0 to turn off this option. otherwise lookahead ancestors of an active unfinished front can be active. return value -- pointer to the first Chv object in a list that contains postponed data created -- 98may16, cca ------------------------------------------------------------------- */ Chv * FrontMtx_MT_factorPencil ( FrontMtx *frontmtx, Pencil *pencil, double tau, double droptol, ChvManager *chvmanager, IV *ownersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile ) ; /* ---------------------------------------------------- multithreaded solve method for (L + I)D(I + U) X = B or (U^T + I)D(I + U) X = B. created -- 98mar19, cca ---------------------------------------------------- */ void FrontMtx_MT_solve ( FrontMtx *frontmtx, DenseMtx *solmtx, DenseMtx *rhsmtx, SubMtxManager *mtxmanager, SolveMap *solvemap, double cpus[], int msglvl, FILE *msgFile ) ; /* ------------------------------------------------------------ purpose -- compute a QR factorization using multiple threads created -- 98may29, cca ------------------------------------------------------------ */ void FrontMtx_MT_QR_factor ( FrontMtx *frontmtx, InpMtx *mtxA, ChvManager *chvmanager, IV *ownersIV, double cpus[], double *pfacops, int msglvl, FILE *msgFile ) ; /* -------------------------------------------------------- multithreaded version: minimize ||b - Ax||_2 by solving (U^T + I) * D * (I + U) X = A^T * B where A = QR = QD(I + U) by calling FrontMtx_solve() note: if A is square, mtxX and mtxB must not be the same cpus -- vector of cpu time breakdowns cpus[0] -- set up solves cpus[1] -- fetch rhs and store solution cpus[2] -- forward solve cpus[3] -- diagonal solve cpus[4] -- backward solve cpus[5] -- total solve time cpus[6] -- time to compute A^T * B cpus[7] -- total time created -- 98may30, cca -------------------------------------------------------- */ void FrontMtx_MT_QR_solve ( FrontMtx *frontmtx, InpMtx *mtxA, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, SolveMap *solvemap, double cpus[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98may02, cca ---------------------------------------- */ void InpMtx_MT_nonsym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) ; /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98jul09, cca ---------------------------------------- */ void InpMtx_MT_sym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) ; /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98jul09, cca ---------------------------------------- */ void InpMtx_MT_herm_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) ; /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98jul09, cca ---------------------------------------- */ void InpMtx_MT_nonsym_mmm_T ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) ; /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98jul09, cca ---------------------------------------- */ void InpMtx_MT_nonsym_mmm_H ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ MT/makefile010064400020550007177000000002270663622364400141250ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make spoolesMT.a clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean MT/src/makefile010064400020550007177000000007530663602664200147170ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = spoolesMT $(OBJ).a : \ $(OBJ).a(factorMT.o) \ $(OBJ).a(mvm.o) \ $(OBJ).a(QRfactorMT.o) \ $(OBJ).a(QRsolveMT.o) \ $(OBJ).a(solveMT.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG MT/src/makeGlobalLib010064400020550007177000000006260660026110700156120ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = MT SRC = factorMT.c \ mvm.c \ QRfactorMT.c \ QRsolveMT.c \ solveMT.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a MT/src/QRfactorMT.c010064400020550007177000000264630665341027700153530ustar00clevecompmath00000400000006/* QRfactorMT.c */ #include "../spoolesMT.h" #include "../../Ideq.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* ----------------------------- worker method for each thread ----------------------------- */ static void * FrontMtx_QR_workerFactor ( void *arg ) ; /* ---------------------------------------------------------------- this object is used during a threaded factorization mtxA -- InpMtx matrix A rowsIVL -- list[J] contains rows of A to be assembled into front J firstnz -- firstnz[irow] contains first column of first nonzero entry in row ownersIV -- map from fronts to threads frontmtx -- object used to store factorization chvmanager -- object used to manage working Chv objects updlist -- object used to store update Chv objects myid -- thread id facops -- number of factor operations cpus -- double vector to store breakdown of cpu times msglvl -- message level msgFile -- message file created -- 97may30, cca ---------------------------------------------------------------- */ typedef struct _QR_factorData QR_factorData ; struct _QR_factorData { /* ------------------------- global data, not modified ------------------------- */ InpMtx *mtxA ; IVL *rowsIVL ; int *firstnz ; IV *ownersIV ; /* --------------------- shared data, modified --------------------- */ FrontMtx *frontmtx ; ChvManager *chvmanager ; ChvList *updlist ; /* ---------- local data ---------- */ int myid ; double facops ; double cpus[7] ; int msglvl ; FILE *msgFile ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- compute a QR factorization using multiple threads created -- 98may29, cca ------------------------------------------------------------ */ void FrontMtx_MT_QR_factor ( FrontMtx *frontmtx, InpMtx *mtxA, ChvManager *chvmanager, IV *ownersIV, double cpus[], double *pfacops, int msglvl, FILE *msgFile ) { ChvList *updlist ; double t0, t1 ; IVL *rowsIVL ; int ithread, myid, nthread, rc ; int *firstnz ; QR_factorData *data, *dataObjects ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || mtxA == NULL || chvmanager == NULL || ownersIV == NULL || cpus == NULL || pfacops == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_MT_QR_factor()" "\n bad input\n") ; exit(-1) ; } nthread = 1 + IV_max(ownersIV) ; /* ---------------------------------------------------------------- create the update Chv list object create the rowsIVL object, where list(J) = list of rows that are assembled in front J firstnz[irowA] = first column with nonzero element in A(irowA,*) ---------------------------------------------------------------- */ MARKTIME(t0) ; updlist = FrontMtx_postList(frontmtx, ownersIV, LOCK_IN_PROCESS) ; FrontMtx_QR_setup(frontmtx, mtxA, &rowsIVL, &firstnz, msglvl, msgFile) ; MARKTIME(t1) ; cpus[0] = t1 - t0 ; /* ------------------------------------ create and load nthread data objects ------------------------------------ */ ALLOCATE(dataObjects, struct _QR_factorData, nthread) ; for ( myid = 0, data = dataObjects ; myid < nthread ; myid++, data++ ) { data->mtxA = mtxA ; data->rowsIVL = rowsIVL ; data->firstnz = firstnz ; data->ownersIV = ownersIV ; data->frontmtx = frontmtx ; data->chvmanager = chvmanager ; data->updlist = updlist ; data->myid = myid ; DVzero(7, data->cpus) ; data->facops = 0.0 ; data->msglvl = msglvl ; if ( msglvl > 0 ) { char buffer[20] ; sprintf(buffer, "res.%d", myid) ; if ( (data->msgFile = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error in FrontMtx_MT_QR_factor()" "\n unable to open file %s", buffer) ; exit(-1) ; } } else { data->msgFile = NULL ; } } #if THREAD_TYPE == TT_SOLARIS /* ---------------------------------- Solaris threads. (1) set the concurrency (2) create nthread - 1 new threads (3) execute own thread (4) join the threads ---------------------------------- */ thr_setconcurrency(nthread) ; for ( myid = 0, data = dataObjects ; myid < nthread - 1 ; myid++, data++ ) { rc = thr_create(NULL, 0, FrontMtx_QR_workerFactor, data, 0, NULL) ; if ( rc != 0 ) { fprintf(stderr, "\n fatal error, myid = %d, rc = %d from thr_create()", myid, rc) ; exit(-1) ; } } FrontMtx_QR_workerFactor(data) ; for ( myid = 0 ; myid < nthread - 1 ; myid++ ) { thr_join(0, 0, 0) ; } #endif #if THREAD_TYPE == TT_POSIX /* ---------------------------------- POSIX threads. (1) if SGI, set the concurrency (2) create nthread new threads (3) join the threads ---------------------------------- */ { pthread_t *tids ; pthread_attr_t attr ; void *status ; /* --------------------------------------------------------- #### NOTE: for SGI machines, this command must be present #### for the thread scheduling to be efficient. #### this is NOT a POSIX call, but necessary --------------------------------------------------------- pthread_setconcurrency(nthread) ; */ pthread_attr_init(&attr) ; /* pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) ; */ pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS) ; ALLOCATE(tids, pthread_t, nthread) ; for ( myid = 0 ; myid < nthread ; myid++ ) { tids[myid] = 0 ; } for ( myid = 0, data = dataObjects ; myid < nthread ; myid++, data++ ) { rc = pthread_create(&tids[myid], &attr, FrontMtx_QR_workerFactor, data) ; if ( rc != 0 ) { fprintf(stderr, "\n fatal error in FrontMtx_MT_QR_factor()" "\n myid = %d, rc = %d from pthread_create()", myid, rc) ; exit(-1) ; } else if ( msglvl > 2 ) { fprintf(stderr, "\n thread %d created", tids[myid]) ; } } for ( myid = 0 ; myid < nthread ; myid++ ) { pthread_join(tids[myid], &status) ; } FREE(tids) ; pthread_attr_destroy(&attr) ; } #endif /* ---------------------------------------------- fill the cpu vector and factor operation count ---------------------------------------------- */ *pfacops = 0 ; for ( myid = 0, data = dataObjects ; myid < nthread ; myid++, data++ ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n thread %d cpus", myid) ; DVfprintf(msgFile, 7, data->cpus) ; } for ( ithread = 0 ; ithread < 7 ; ithread++ ) { cpus[ithread] += data->cpus[ithread] ; } *pfacops += data->facops ; } /* ------------- free the data ------------- */ ChvList_free(updlist) ; IVL_free(rowsIVL) ; IVfree(firstnz) ; FREE(dataObjects) ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- worker method to factor the matrix created -- 98may29, cca ---------------------------------------------------- */ static void * FrontMtx_QR_workerFactor ( void *arg ) { char *status ; ChvList *updlist ; ChvManager *chvmanager ; double facops, t0, t1 ; double *cpus ; DV workDV ; FILE *msgFile ; FrontMtx *frontmtx ; Ideq *dequeue ; InpMtx *mtxA ; int J, K, myid, neqns, nfront, msglvl ; int *colmap, *firstnz, *nactiveChild, *owners, *par ; IVL *rowsIVL ; QR_factorData *data ; MARKTIME(t0) ; data = (QR_factorData *) arg ; mtxA = data->mtxA ; rowsIVL = data->rowsIVL ; firstnz = data->firstnz ; IV_sizeAndEntries(data->ownersIV, &nfront, &owners) ; frontmtx = data->frontmtx ; chvmanager = data->chvmanager ; updlist = data->updlist ; myid = data->myid ; cpus = data->cpus ; msglvl = data->msglvl ; msgFile = data->msgFile ; par = frontmtx->tree->par ; neqns = FrontMtx_neqns(frontmtx) ; /* -------------------------------------------------------- status[J] = 'F' --> J finished = 'W' --> J waiting to be finished create the Ideq object to handle the bottom-up traversal nactiveChild[K] = # of unfinished children of K, when zero, K can be placed on the dequeue -------------------------------------------------------- */ status = CVinit(nfront, 'F') ; dequeue = FrontMtx_setUpDequeue(frontmtx, owners, myid, status, NULL, 'W', 'F', msglvl, msgFile) ; FrontMtx_loadActiveLeaves(frontmtx, status, 'W', dequeue) ; nactiveChild = FrontMtx_nactiveChild(frontmtx, status, myid) ; colmap = IVinit(neqns, -1) ; DV_setDefaultFields(&workDV) ; facops = 0.0 ; if ( msglvl > 3 ) { fprintf(msgFile, "\n owners") ; IVfprintf(msgFile, nfront, owners) ; fprintf(msgFile, "\n Ideq") ; Ideq_writeForHumanEye(dequeue, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; cpus[0] += t1 - t0 ; /* --------------------------- loop while a path is active --------------------------- */ while ( (J = Ideq_removeFromHead(dequeue)) != -1 ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ### checking out front %d, owner %d", J, owners[J]) ; } if ( owners[J] == myid ) { /* -------------------------------- front J is ready to be processed -------------------------------- */ FrontMtx_QR_factorVisit(frontmtx, J, mtxA, rowsIVL, firstnz, updlist, chvmanager, status, colmap, &workDV, cpus, &facops, msglvl, msgFile) ; if ( status[J] == 'F' ) { /* ------------------------------------------ front J is finished, put parent on dequeue if it exists or all children are finished ------------------------------------------ */ if ( (K = par[J]) != -1 && --nactiveChild[K] == 0 ) { Ideq_insertAtHead(dequeue, K) ; } } else { /* ----------------------------------------------- front J is not complete, put on tail of dequeue ----------------------------------------------- */ Ideq_insertAtTail(dequeue, J) ; } } else { /* ------------------------------------------- front J is not owned, put parent on dequeue if it exists and all children are finished ------------------------------------------- */ if ( (K = par[J]) != -1 && --nactiveChild[K] == 0 ) { Ideq_insertAtHead(dequeue, K) ; } } } data->facops = facops ; /* ------------------------ free the working storage ------------------------ */ CVfree(status) ; Ideq_free(dequeue) ; IVfree(nactiveChild) ; IVfree(colmap) ; DV_clearData(&workDV) ; MARKTIME(t1) ; cpus[6] = t1 - t0 ; cpus[5] = t1 - t0 - cpus[0] - cpus[1] - cpus[2] - cpus[3] - cpus[4] ; return(NULL) ; } /*--------------------------------------------------------------------*/ MT/src/QRsolveMT.c010064400020550007177000000052650657133652700152260ustar00clevecompmath00000400000006/* QRsolveMT.c */ #include "../spoolesMT.h" #include "../../timings.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- multithreaded version: minimize ||b - Ax||_2 by solving (U^T + I) * D * (I + U) X = A^T * B where A = QR = QD(I + U) by calling FrontMtx_solve() note: if A is square, mtxX and mtxB must not be the same cpus -- vector of cpu time breakdowns cpus[0] -- set up solves cpus[1] -- fetch rhs and store solution cpus[2] -- forward solve cpus[3] -- diagonal solve cpus[4] -- backward solve cpus[5] -- total solve time cpus[6] -- time to compute A^T * B cpus[7] -- total time created -- 98may30, cca -------------------------------------------------------- */ void FrontMtx_MT_QR_solve ( FrontMtx *frontmtx, InpMtx *mtxA, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, SolveMap *solvemap, double cpus[], int msglvl, FILE *msgFile ) { double t0, t1, t2 ; double alpha[2] ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( frontmtx == NULL || mtxA == NULL || mtxX == NULL || mtxB == NULL || mtxmanager == NULL || solvemap == NULL || cpus == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_MT_QR_solve()" "\n bad input\n") ; exit(-1) ; } /* --------------------------------- compute X := A^T * B this method is not multithreaded. --------------------------------- */ MARKTIME(t1) ; DenseMtx_zero(mtxX) ; alpha[0] = 1.0 ; alpha[1] = 0.0 ; if ( FRONTMTX_IS_REAL(frontmtx) ) { InpMtx_nonsym_mmm_T(mtxA, mtxX, alpha, mtxB) ; } else if ( FRONTMTX_IS_COMPLEX(frontmtx) ) { InpMtx_nonsym_mmm_H(mtxA, mtxX, alpha, mtxB) ; } MARKTIME(t2) ; cpus[6] = t2 - t1 ; if ( msglvl > 3 ) { fprintf(msgFile, "\n B") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fprintf(msgFile, "\n A^T * B") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /* ----------------------------------- solve (U^T + I) * D * (I + U) Z = X where Z overwrites X this method is multithreaded. ----------------------------------- */ MARKTIME(t1) ; FrontMtx_MT_solve(frontmtx, mtxX, mtxX, mtxmanager, solvemap, cpus, msglvl, msgFile) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n computed mtxX") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } MARKTIME(t2) ; cpus[7] = t2 - t0 ; return ; } /*--------------------------------------------------------------------*/ MT/src/factorMT.c010064400020550007177000000436450665065330300151050ustar00clevecompmath00000400000006/* factorMT.c */ #include "../spoolesMT.h" #include "../../Ideq.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* ----------------------------- worker method for each thread ----------------------------- */ static void * FrontMtx_workerFactor ( void *arg ) ; /* ---------------------------------------------------------------- this object is used during a threaded factorization pencil -- matrix pencil A + sigma * B tau -- upper bound on factor entries when pivoting enabled droptol -- drop tolerance used for sparse fronts ownersIV -- map from fronts to threads lookahead -- parameter used to control computation lookahead 0 --> no lookahead > 0 --> look up a number of levels up the tree frontmtx -- object used to store factorization manager -- object used to manage working Chv objects aggList -- object used to store aggregate data postList -- object used to store postponed data perror -- pointer to external error flag heads -- IP vector to maintain update lists myid -- thread id fronts -- vector of pointers to active fronts stats -- int statistics vector cpus -- double vector to store breakdown of cpu times msglvl -- message level msgFile -- message file created -- 97may30, cca ---------------------------------------------------------------- */ typedef struct _FactorData FactorData ; struct _FactorData { /* ------------------------- global data, not modified ------------------------- */ Pencil *pencil ; double tau ; double droptol ; IV *ownersIV ; int lookahead ; /* --------------------- shared data, modified --------------------- */ FrontMtx *frontmtx ; ChvManager *chvmanager ; ChvList *aggList ; ChvList *postList ; int *perror ; /* ---------- local data ---------- */ int myid ; int stats[10] ; double cpus[20] ; int msglvl ; FILE *msgFile ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- parallel factorization method for A. all but two input parameters are the same as the serial method. this is a wrapper method around FrontMtx_MT_factorInpMtx(). ownersIV -- pointer to IV object that holds map from fronts to threads lookahead -- lookahead parameter that allows computation at higher levels of the front tree to proceed when lower fronts are not yet finish. use lookahead = 0 to turn off this option. otherwise lookahead ancestors of an active unfinished front can be active. return value -- pointer to the first Chv object in a list that contains postponed data created -- 98may16, cca ------------------------------------------------------------------- */ Chv * FrontMtx_MT_factorInpMtx ( FrontMtx *frontmtx, InpMtx *inpmtx, double tau, double droptol, ChvManager *chvmanager, IV *ownersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile ) { Chv *rootchv ; double sigma[2] = {0.0, 0.0} ; Pencil pencil ; Pencil_setDefaultFields(&pencil) ; Pencil_init(&pencil, frontmtx->type, frontmtx->symmetryflag, inpmtx, sigma, NULL) ; rootchv = FrontMtx_MT_factorPencil(frontmtx, &pencil, tau, droptol, chvmanager, ownersIV, lookahead, perror, cpus, stats, msglvl, msgFile) ; return(rootchv) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- parallel factorization method for A + sigma*B. all but two input parameters are the same as the FrontMtx_factorPencil method. ownersIV -- pointer to IV object that holds map from fronts to threads lookahead -- lookahead parameter that allows computation at higher levels of the front tree to proceed when lower fronts are not yet finish. use lookahead = 0 to turn off this option. otherwise lookahead ancestors of an active unfinished front can be active. return value -- pointer to the first Chv object in a list that contains postponed data created -- 98may16, cca ------------------------------------------------------------------- */ Chv * FrontMtx_MT_factorPencil ( FrontMtx *frontmtx, Pencil *pencil, double tau, double droptol, ChvManager *chvmanager, IV *ownersIV, int lookahead, int *perror, double cpus[], int stats[], int msglvl, FILE *msgFile ) { char buffer[20] ; Chv *rootchv ; ChvList *aggList ; ChvList *postList ; double t0, t1, t2 ; FactorData *data, *dataObjects ; FILE *fp ; int ierr, ii, myid, nfront, nthread, rc ; int *owners ; /* -------------- check the data -------------- */ MARKTIME(t0) ; if ( frontmtx == NULL || pencil == NULL || tau < 1.0 || droptol < 0.0 || ownersIV == NULL || lookahead < 0 || cpus == NULL || stats == NULL || msglvl < 0 || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_MT_factorPencil()" "\n frontmtx = %p, pencil = %p" "\n tau = %f, droptol = %f, ownersIV = %p, lookahead = %d" "\n cpus = %p, stats = %p, msglvl = %d, msgFile = %p" "\n bad input\n", frontmtx, pencil, tau, droptol, ownersIV, lookahead, cpus, stats, msglvl, msgFile) ; exit(-1) ; } IV_sizeAndEntries(ownersIV, &nfront, &owners) ; nthread = 1 + IV_max(ownersIV) ; /* -------------------------------------------------------------------- create : (1) a ChvList object to handle the lists of aggregate Chv objects, (2) if pivoting is enabled, a ChvList object to handle the lists of postponed Chv objects. -------------------------------------------------------------------- */ MARKTIME(t1) ; aggList = FrontMtx_aggregateList(frontmtx, ownersIV, 1) ; if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { postList = FrontMtx_postList(frontmtx, ownersIV, 1) ; } else { postList = NULL ; } MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : initialize lists and manager", t2 - t1) ; } /* ------------------ set the error flag ------------------ */ *perror = -1 ; /* ---------------------------------------------------------- create nthread FactorData objects and load with their data ---------------------------------------------------------- */ MARKTIME(t1) ; ALLOCATE(dataObjects, struct _FactorData, nthread) ; for ( myid = 0, data = dataObjects ; myid < nthread ; myid++, data++ ) { data->pencil = pencil ; data->tau = tau ; data->droptol = droptol ; data->ownersIV = ownersIV ; data->lookahead = lookahead ; data->frontmtx = frontmtx ; data->chvmanager = chvmanager ; data->aggList = aggList ; data->postList = postList ; data->perror = perror ; data->myid = myid ; IVzero(10, data->stats) ; DVzero(20, data->cpus) ; data->msglvl = msglvl ; if ( msglvl > 0 ) { sprintf(buffer, "res.%d", myid) ; if ( (fp = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error, unable to open file %s", buffer) ; exit(-1) ; } data->msgFile = fp ; } else { data->msgFile = NULL ; } } MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : initialize data objects", t2 - t1) ; } /* --------------------------- switch over the thread type --------------------------- */ #if THREAD_TYPE == TT_SOLARIS /* --------------- solaris threads --------------- */ MARKTIME(t1) ; thr_setconcurrency(nthread) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : set concurrency time", t2 - t1) ; } MARKTIME(t1) ; for ( myid = 0, data = dataObjects ; myid < nthread - 1 ; myid++, data++ ) { rc = thr_create(NULL, 0, FrontMtx_workerFactor, data, 0, NULL) ; if ( rc != 0 ) { fprintf(stderr, "\n fatal error, myid = %d, rc = %d from thr_create", myid, rc) ; exit(-1) ; } } MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : thread creation time", t2 - t1) ; } MARKTIME(t1) ; FrontMtx_workerFactor(data) ; for ( myid = 0 ; myid < nthread - 1 ; myid++ ) { thr_join(0, 0, 0) ; } MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : thread join time", t2 - t1) ; } #endif #if THREAD_TYPE == TT_POSIX /* ------------- POSIX threads ------------- */ { pthread_t *tids ; pthread_attr_t attr ; void *status ; /* ##### NOTE: for SGI machines, this command must be present ##### for the thread scheduling to be efficient. ##### this is NOT a POSIX call, but SGI needs it anyway pthread_setconcurrency(nthread) ; */ pthread_attr_init(&attr) ; /* pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) ; */ pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS) ; ALLOCATE(tids, pthread_t, nthread) ; MARKTIME(t1) ; for ( myid = 0, data = dataObjects ; myid < nthread ; myid++, data++ ) { /* rc = pthread_create(&tids[myid], &attr, FrontMtx_workerFactor, data) ; */ rc = pthread_create(&tids[myid], NULL, FrontMtx_workerFactor, data) ; if ( rc != 0 ) { fprintf(stderr, "\n fatal error, myid = %d, rc = %d from pthread_create", myid, rc) ; exit(-1) ; } else if ( msglvl > 1 ) { fprintf(stderr, "\n thread %d created", tids[myid]) ; } } MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : thread creation time", t2 - t1) ; } MARKTIME(t1) ; for ( myid = 0 ; myid < nthread ; myid++ ) { pthread_join(tids[myid], &status) ; } MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : thread join time", t2 - t1) ; } FREE(tids) ; pthread_attr_destroy(&attr) ; } #endif /* -------------------------------------------- get a pointer to any postponed root chevrons -------------------------------------------- */ if ( postList != NULL ) { rootchv = ChvList_getList(postList, nfront) ; } else { rootchv = NULL ; } /* ------------------- fill the statistics ------------------- */ for ( myid = 0, data = dataObjects ; myid < nthread ; myid++, data++ ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n thread %d stats", myid) ; IVfp80(msgFile, 10, data->stats, 20, &ierr) ; fprintf(msgFile, "\n thread %d cpus", myid) ; DVfprintf(msgFile, 10, data->cpus) ; } for ( ii = 0 ; ii < 10 ; ii++ ) { stats[ii] += data->stats[ii] ; } for ( ii = 0 ; ii <= 10 ; ii++ ) { cpus[ii] += data->cpus[ii] ; } } stats[3] = frontmtx->nentD ; stats[4] = frontmtx->nentL ; stats[5] = frontmtx->nentU ; stats[6] = frontmtx->nlocks ; stats[7] = aggList->nlocks ; if ( postList != NULL ) { stats[8] = postList->nlocks ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n factorization has finished" "\n %d locks of the front matrix" "\n %d locks of the aggregate list", frontmtx->nlocks, aggList->nlocks) ; if ( postList != NULL ) { fprintf(msgFile, "\n %d locks of the aggregate list", aggList->nlocks) ; } } /* ------------- free the data ------------- */ MARKTIME(t1) ; ChvList_free(aggList) ; if ( postList != NULL ) { ChvList_free(postList) ; } FREE(dataObjects) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : total time", t2 - t1) ; } return(rootchv) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- worker method to factor the matrix created -- 97may30, cca --------------------------------------------- */ static void * FrontMtx_workerFactor ( void *arg ) { char *status ; Chv **fronts ; ChvList *aggList, *postList ; ChvManager *chvmanager ; FactorData *data ; FrontMtx *frontmtx ; Pencil *pencil ; double droptol, tau, t1, t2 ; double *cpus ; DV *workDV ; ETree *frontETree ; FILE *msgFile ; Ideq *deq ; int J, K, lookahead, msglvl, myid, nfront ; int *nactiveChild, *owners, *par, *stats ; IP **heads ; IV *ownersIV, pivotsizesIV ; Tree *tree ; #if THREAD_TYPE == TT_POSIX /* fprintf(stdout, "\n ### inside workerFactor, pthread_self() = %d", pthread_self()) ; fflush(stdout) ; */ #endif /* ------------------------------- extract pointers and dimensions ------------------------------- */ MARKTIME(t1) ; data = (FactorData *) arg ; pencil = data->pencil ; tau = data->tau ; droptol = data->droptol ; msglvl = data->msglvl ; msgFile = data->msgFile ; myid = data->myid ; frontmtx = data->frontmtx ; chvmanager = data->chvmanager ; aggList = data->aggList ; postList = data->postList ; frontETree = frontmtx->frontETree ; tree = ETree_tree(frontETree) ; nfront = ETree_nfront(frontETree) ; par = ETree_par(frontETree) ; lookahead = data->lookahead ; ownersIV = data->ownersIV ; owners = IV_entries(ownersIV) ; stats = data->stats; cpus = data->cpus ; #if THREAD_TYPE == TT_SOLARIS if ( msglvl > 2 ) { fprintf(stdout, "\n ### inside workerFactor, myid = %d, thr_self() = %d", myid, thr_self()) ; fflush(stdout) ; } #endif #if THREAD_TYPE == TT_POSIX if ( msglvl > 2 ) { fprintf(stdout, "\n ### inside workerFactor, myid = %d" ", pthread_self() = %d", myid, pthread_self()) ; fflush(stdout) ; } #endif /* --------------------------------------------------- initialize the heads[] vector for the owned updates --------------------------------------------------- */ heads = FrontMtx_factorSetup(frontmtx, ownersIV, myid, msglvl, msgFile) ; /* ---------------------------------------------------------------- initialize the Ideq object that holds the initial fronts of the active paths, owned fronts with no children that are owned or updates by this thread. status[J] == 'W' --> J belongs to an active path for this thread ---------------------------------------------------------------- */ status = CVinit(nfront, 'F') ; deq = FrontMtx_setUpDequeue(frontmtx, IV_entries(ownersIV), myid, status, heads, 'W', 'F', msglvl, msgFile) ; FrontMtx_loadActiveLeaves(frontmtx, status, 'W', deq) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n status") ; CVfprintf(msgFile, nfront, status) ; fflush(msgFile) ; } /* ----------------------------------------------- initialize the nactiveChild[] vector, nactiveChild[J] measures the number of children that belong to active paths of this thread ----------------------------------------------- */ nactiveChild = FrontMtx_nactiveChild(frontmtx, status, myid) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n nactiveChild") ; IVfprintf(msgFile, nfront, nactiveChild) ; fflush(msgFile) ; } /* ------------------------------ initialize the working storage ------------------------------ */ ALLOCATE(fronts, Chv *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { fronts[J] = NULL ; } IV_setDefaultFields(&pivotsizesIV) ; /* if ( FRONTMTX_IS_PIVOTING(frontmtx) && ( FRONTMTX_IS_SYMMETRIC(frontmtx) || FRONTMTX_IS_HERMITIAN(frontmtx) ) ) { pivotsizesIV = IV_new() ; } else { fprintf(msgFile, "\n no pivotsizesIV needed") ; fflush(msgFile) ; pivotsizesIV = NULL ; } */ workDV = DV_new() ; /* --------------------------- loop while a path is active --------------------------- */ IVzero(10, stats) ; while ( (J = Ideq_removeFromHead(deq)) != -1 ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ### checking out front %d", J) ; fflush(msgFile) ; } FrontMtx_factorVisit(frontmtx, pencil, J, myid, owners, fronts, lookahead, data->tau, data->droptol, status, heads, &pivotsizesIV, workDV, par, data->aggList, data->postList, data->chvmanager, stats, cpus, msglvl, msgFile) ; if ( status[J] == 'E' ) { /* ---------------------------- error encountered at front J ---------------------------- */ *(data->perror) = J ; break ; } else if ( status[J] == 'F' ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n front %d is finished", J) ; fflush(msgFile) ; } if ( (K = par[J]) != -1 && --nactiveChild[K] == 0 ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n adding front %d to dequeue", K) ; fflush(msgFile) ; } Ideq_insertAtHead(deq, K) ; } } else { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n front %d not yet done", J) ; fflush(msgFile) ; } Ideq_insertAtTail(deq, J) ; } if ( *(data->perror) >= 0 ) { /* ------------------------------------ error encountered, break out of loop ------------------------------------ */ break ; } } /* ------------------------ free the working storage ------------------------ */ IV_clearData(&pivotsizesIV) ; if ( workDV != NULL ) { DV_free(workDV) ; } CVfree(status) ; IVfree(nactiveChild) ; IP_free(heads[nfront+1]) ; FREE(heads) ; FREE(fronts) ; Ideq_free(deq) ; MARKTIME(t2) ; cpus[10] = t2 - t1 ; cpus[9] = t2 - t1 - cpus[0] - cpus[1] - cpus[2] - cpus[3] - cpus[4] - cpus[5] - cpus[6] - cpus[7] - cpus[8] ; return(NULL) ; } /*--------------------------------------------------------------------*/ * --------------------------- switch over the thread type ------------------------MT/src/mvm.c010064400020550007177000000301440661172421700141530ustar00clevecompmath00000400000006/* mvm.c */ #include "../spoolesMT.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ #define NONSYM 1 #define SYM 2 #define HERM 3 #define NONSYM_T 4 #define NONSYM_H 5 typedef struct _MTmvmObj MTmvmObj ; struct _MTmvmObj { InpMtx *A ; DenseMtx *Y ; double alpha[2] ; DenseMtx *X ; } ; static MTmvmObj * setup ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread ) ; static void InpMtx_MT_mmm ( int flag, InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) ; static void * worker_nonsym_mmm ( void *arg ) ; static void * worker_sym_mmm ( void *arg ) ; static void * worker_herm_mmm ( void *arg ) ; static void * worker_nonsym_mmm_T ( void *arg ) ; static void * worker_nonsym_mmm_H ( void *arg ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98jul09, cca ---------------------------------------- */ void InpMtx_MT_nonsym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) { /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL || nthread < 1 ) { fprintf(stderr, "\n fatal error in InpMtx_MT_nonsym_mmm(%p,%p,%p,%p,%d)" "\n bad input\n", A, Y, alpha, X, nthread) ; exit(-1) ; } if ( nthread == 1 ) { InpMtx_nonsym_mmm(A, Y, alpha, X) ; } else { InpMtx_MT_mmm(NONSYM, A, Y, alpha, X, nthread, msglvl, msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98jul09, cca ---------------------------------------- */ void InpMtx_MT_sym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) { /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL || nthread < 1 ) { fprintf(stderr, "\n fatal error in InpMtx_MT_sym_mmm(%p,%p,%p,%p,%d)" "\n bad input\n", A, Y, alpha, X, nthread) ; exit(-1) ; } if ( nthread == 1 ) { InpMtx_sym_mmm(A, Y, alpha, X) ; } else { InpMtx_MT_mmm(SYM, A, Y, alpha, X, nthread, msglvl, msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98jul09, cca ---------------------------------------- */ void InpMtx_MT_herm_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) { /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL || nthread < 1 ) { fprintf(stderr, "\n fatal error in InpMtx_MT_herm_mmm(%p,%p,%p,%p,%d)" "\n bad input\n", A, Y, alpha, X, nthread) ; exit(-1) ; } if ( nthread == 1 ) { InpMtx_herm_mmm(A, Y, alpha, X) ; } else { InpMtx_MT_mmm(HERM, A, Y, alpha, X, nthread, msglvl, msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98jul09, cca ---------------------------------------- */ void InpMtx_MT_nonsym_mmm_T ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) { /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL || nthread < 1 ) { fprintf(stderr, "\n fatal error in InpMtx_MT_nonsym_mmm_T(%p,%p,%p,%p,%d)" "\n bad input\n", A, Y, alpha, X, nthread) ; exit(-1) ; } if ( nthread == 1 ) { InpMtx_nonsym_mmm_T(A, Y, alpha, X) ; } else { InpMtx_MT_mmm(NONSYM_T, A, Y, alpha, X, nthread, msglvl, msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to compute Y := Y + alpha*A*X created -- 98jul09, cca ---------------------------------------- */ void InpMtx_MT_nonsym_mmm_H ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) { /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL || nthread < 1 ) { fprintf(stderr, "\n fatal error in InpMtx_MT_nonsym_mmm_H(%p,%p,%p,%p,%d)" "\n bad input\n", A, Y, alpha, X, nthread) ; exit(-1) ; } if ( nthread == 1 ) { InpMtx_nonsym_mmm_H(A, Y, alpha, X) ; } else { InpMtx_MT_mmm(NONSYM_H, A, Y, alpha, X, nthread, msglvl, msgFile) ; } return ; } /*--------------------------------------------------------------------*/ static void InpMtx_MT_mmm ( int flag, InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) { double t1, t2 ; int myid, nent, rc ; MTmvmObj *MTmvmObjs, *obj ; /* ------------------------------- set up the nthread data objects ------------------------------- */ MARKTIME(t1) ; MTmvmObjs = setup(A, Y, alpha, X, nthread) ; MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n %% CPU %8.3f : setup time", t2 - t1) ; } #if THREAD_TYPE == TT_POSIX { pthread_t *tids ; pthread_attr_t attr ; void *status ; /* ##### NOTE: for SGI machines, this command must be present ##### for the thread scheduling to be efficient. ##### this is NOT a POSIX call, but SGI needs it anyway pthread_setconcurrency(nthread) ; */ pthread_attr_init(&attr) ; /* pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) ; */ pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS) ; ALLOCATE(tids, pthread_t, nthread) ; MARKTIME(t1) ; for ( myid = 0, obj = MTmvmObjs ; myid < nthread ; myid++, obj++ ) { switch ( flag ) { case NONSYM : rc = pthread_create(&tids[myid], &attr, worker_nonsym_mmm, obj) ; break ; case SYM : rc = pthread_create(&tids[myid], &attr, worker_sym_mmm, obj) ; break ; case HERM : rc = pthread_create(&tids[myid], &attr, worker_herm_mmm, obj) ; break ; case NONSYM_T : rc = pthread_create(&tids[myid], &attr, worker_nonsym_mmm_T, obj); break ; case NONSYM_H : rc = pthread_create(&tids[myid], &attr, worker_nonsym_mmm_H, obj); break ; } if ( rc != 0 ) { fprintf(stderr, "\n fatal error, myid = %d, rc = %d from pthread_create", myid, rc) ; exit(-1) ; } else if ( msglvl > 2 ) { fprintf(stderr, "\n %% thread %d created", tids[myid]) ; } } MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n %% CPU %8.3f : thread creation time", t2 - t1) ; } MARKTIME(t1) ; for ( myid = 0 ; myid < nthread ; myid++ ) { pthread_join(tids[myid], &status) ; } MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n %% CPU %8.3f : thread join time", t2 - t1) ; } FREE(tids) ; pthread_attr_destroy(&attr) ; } #endif /* ------------------------------------- accumulate the rhs hand side matrices ------------------------------------- */ MARKTIME(t1) ; nent = Y->nrow * Y->ncol ; for ( myid = 1, obj = MTmvmObjs + 1 ; myid < nthread ; myid++, obj++ ) { if ( INPMTX_IS_REAL_ENTRIES(A) ) { DVadd(nent, DenseMtx_entries(Y), DenseMtx_entries(obj->Y)) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { DVadd(2*nent, DenseMtx_entries(Y), DenseMtx_entries(obj->Y)) ; } } MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n %% CPU %8.3f : time to accumulate rhs", t2 - t1) ; } /* --------------------------- release the data structures --------------------------- */ MARKTIME(t1) ; for ( myid = 0, obj = MTmvmObjs ; myid < nthread ; myid++, obj++ ) { InpMtx_free(obj->A) ; if ( myid > 0 ) { DenseMtx_free(obj->Y) ; } } FREE(MTmvmObjs) ; MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n %% CPU %8.3f : time to release and free data", t2 - t1) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- set up the nthread MTmvmObj data structures ------------------------------------------- */ static MTmvmObj * setup ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread ) { double *dvec ; int ithread, nentA, nextra, nlocal, offset ; int *ivec1, *ivec2 ; MTmvmObj *MTmvmObjs, *obj ; /* --------------------------------- allocate nthread MTmvmObj objects --------------------------------- */ ALLOCATE(MTmvmObjs, struct _MTmvmObj, nthread) ; for ( ithread = 0, obj = MTmvmObjs ; ithread < nthread ; ithread++, obj++ ) { obj->A = InpMtx_new() ; if ( ithread == 0 ) { obj->Y = Y ; } else { obj->Y = DenseMtx_new() ; } obj->alpha[0] = alpha[0] ; obj->alpha[1] = alpha[1] ; obj->X = X ; } /* ---------------------------------------- set up and zero the replicated Y objects ---------------------------------------- */ for ( ithread = 0, obj = MTmvmObjs ; ithread < nthread ; ithread++, obj++ ) { if ( ithread > 0 ) { DenseMtx_init(obj->Y, Y->type, Y->rowid, Y->colid, Y->nrow, Y->ncol, Y->inc1, Y->inc2) ; DenseMtx_zero(obj->Y) ; } } /* ------------------------------------- set up the partitioned InpMtx objects ------------------------------------- */ nentA = InpMtx_nent(A) ; nlocal = nentA / nthread ; nextra = nentA % nthread ; ivec1 = InpMtx_ivec1(A) ; ivec2 = InpMtx_ivec2(A) ; if ( INPMTX_IS_REAL_ENTRIES(A) || INPMTX_IS_COMPLEX_ENTRIES(A) ) { dvec = InpMtx_dvec(A) ; } else { dvec = NULL ; } offset = 0 ; for ( ithread = 0, obj = MTmvmObjs ; ithread < nthread ; ithread++, obj++ ) { InpMtx_init(obj->A, A->coordType, A->inputMode, 0, 0) ; obj->A->storageMode = A->storageMode ; if ( ithread < nextra ) { obj->A->nent = nlocal + 1 ; } else { obj->A->nent = nlocal ; } IV_init(&(obj->A->ivec1IV), obj->A->nent, ivec1 + offset) ; IV_init(&(obj->A->ivec2IV), obj->A->nent, ivec2 + offset) ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { DV_init(&(obj->A->dvecDV), obj->A->nent, dvec + offset) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { DV_init(&(obj->A->dvecDV), obj->A->nent, dvec + 2*offset) ; } offset += obj->A->nent ; } return(MTmvmObjs) ; } /*--------------------------------------------------------------------*/ static void * worker_nonsym_mmm ( void *arg ) { MTmvmObj *obj ; obj = (MTmvmObj *) arg ; InpMtx_nonsym_mmm(obj->A, obj->Y, obj->alpha, obj->X) ; return(NULL) ; } /*--------------------------------------------------------------------*/ static void * worker_sym_mmm ( void *arg ) { MTmvmObj *obj ; obj = (MTmvmObj *) arg ; InpMtx_sym_mmm(obj->A, obj->Y, obj->alpha, obj->X) ; return(NULL) ; } /*--------------------------------------------------------------------*/ static void * worker_herm_mmm ( void *arg ) { MTmvmObj *obj ; obj = (MTmvmObj *) arg ; InpMtx_herm_mmm(obj->A, obj->Y, obj->alpha, obj->X) ; return(NULL) ; } /*--------------------------------------------------------------------*/ static void * worker_nonsym_mmm_T ( void *arg ) { MTmvmObj *obj ; obj = (MTmvmObj *) arg ; InpMtx_nonsym_mmm_T(obj->A, obj->Y, obj->alpha, obj->X) ; return(NULL) ; } /*--------------------------------------------------------------------*/ static void * worker_nonsym_mmm_H ( void *arg ) { MTmvmObj *obj ; obj = (MTmvmObj *) arg ; InpMtx_nonsym_mmm_H(obj->A, obj->Y, obj->alpha, obj->X) ; return(NULL) ; } /*--------------------------------------------------------------------*/ -------------------------------- */ void InpMtx_MT_nonsym_mmm_T ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, FILE *msgFile ) { /* --------------- check the input --------------- */ if ( A == NULL || Y == NULL || alpha == NULL || X == NULL || nthread < 1 ) { fprintf(stderr, "\n fatal error in InMT/src/solveMT.c010064400020550007177000000530060661172424100147440ustar00clevecompmath00000400000006/* solveMT.c */ #include "../spoolesMT.h" #include "../../Ideq.h" #include "../../timings.h" #include "../../SolveMap.h" #include "../../SubMtxList.h" /*--------------------------------------------------------------------*/ /* --------------------------------- declarations for static functions --------------------------------- */ static void * FrontMtx_workerSolve ( void *arg ) ; static void setupListObjects ( FrontMtx *frontmtx, SolveMap *solvemap, SubMtxList *forwAggList, SubMtxList *backAggList, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- data structure for each thread global data frontmtx -- FrontMtx object that contains the matrix factorization solmtx -- DenseMtx object, on output it holds the solution rhsmtx -- DenseMtx object, on input it holds the right hand side solvemap -- SolveMap object that holds the map of computations to processes for the forward and backward solve mtxmanager -- SubMtxManager object to manage working storage forwAggList -- SubMtxList to hold aggregate objects during the forward solve backAggList -- SubMtxList to hold aggregate objects during the backward solve p_mtx -- array of pointers to SubMtx objects that point to global solution SubMtx objects for the fronts frontIsDone -- char vector used for synchronization there are three steps to the solve (1) (L + I) Y = B (2) D Z = Y (3) (I + U) X = B frontIsDone[J] = 'N' --> J at step is not yet complete frontIsDone[J] = 'Y' --> J at step is complete lowerIsDone -- vector used for synchronization 'Y' --> forward solve for iproc complete 'N' --> forward solve for iproc not complete diagIsDone -- vector used for synchronization 'Y' --> diagonal solve for iproc complete 'N' --> diagonal solve for iproc not complete upperIsDone -- vector used for synchronization 'Y' --> backward solve for iproc complete 'N' --> backward solve for iproc not complete local data myid -- thread id cpus -- vector to hold cpu breakdown msglvl -- local message level msgFile -- local message file -------------------------------------------------------------------- */ typedef struct _SolveData SolveData ; struct _SolveData { FrontMtx *frontmtx ; DenseMtx *solmtx ; DenseMtx *rhsmtx ; SolveMap *solvemap ; SubMtxManager *mtxmanager ; int myid ; SubMtxList *forwAggList ; SubMtxList *backAggList ; SubMtx **p_mtx ; char *frontIsDone ; char *lowerIsDone ; char *diagIsDone ; char *upperIsDone ; double *cpus ; int msglvl ; FILE *msgFile ; } ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- multithreaded solve method for (L + I)D(I + U) X = B or (U^T + I)D(I + U) X = B. created -- 98mar19, cca ---------------------------------------------------- */ void FrontMtx_MT_solve ( FrontMtx *frontmtx, DenseMtx *solmtx, DenseMtx *rhsmtx, SubMtxManager *mtxmanager, SolveMap *solvemap, double cpus[], int msglvl, FILE *msgFile ) { char buffer[20] ; char *diagIsDone, *frontIsDone, *lowerIsDone, *upperIsDone ; SubMtx **p_mtx ; SubMtxList *backAggList, *forwAggList ; SolveData *data, *dataObjects ; double t1, t2 ; FILE *fp ; int ii, J, myid, nfront, nthread, rc ; /* --------------- check the input --------------- */ if ( frontmtx == NULL || solmtx == NULL || rhsmtx == NULL || mtxmanager == NULL || solvemap == NULL || cpus == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in FrontMtx_MT_solve()" "\n frontmtx = %p, solmtx = %p, rhsmtx = %p, mtxmanager = %p" "\n solvemap = %p, cpus = %p" "\n msglvl = %d, msgFile = %p" "\n\n bad input\n", frontmtx, solmtx, rhsmtx, mtxmanager, solvemap, cpus, msglvl, msgFile) ; exit(-1) ; } MARKTIME(t1) ; nfront = FrontMtx_nfront(frontmtx) ; nthread = SolveMap_nproc(solvemap) ; /* -------------------------------------------------- set up the forward and backward solve list objects -------------------------------------------------- */ backAggList = SubMtxList_new() ; forwAggList = SubMtxList_new() ; setupListObjects(frontmtx, solvemap, forwAggList, backAggList, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n forward aggregate list") ; SubMtxList_writeForHumanEye(forwAggList, msgFile) ; fflush(msgFile) ; } /* --------------------------- allocate the global vectors --------------------------- */ ALLOCATE(p_mtx, struct _SubMtx *, nfront) ; for ( J = 0 ; J < nfront ; J++ ) { p_mtx[J] = NULL ; } frontIsDone = CVinit(nfront, 'N') ; lowerIsDone = CVinit(solvemap->nproc, 'N') ; diagIsDone = CVinit(solvemap->nproc, 'N') ; upperIsDone = CVinit(solvemap->nproc, 'N') ; /* ---------------------------------- allocate the local data structures ---------------------------------- */ ALLOCATE(dataObjects, struct _SolveData, nthread) ; for ( myid = 0, data = dataObjects ; myid < nthread ; myid++, data++ ) { data->frontmtx = frontmtx ; data->solmtx = solmtx ; data->rhsmtx = rhsmtx ; data->solvemap = solvemap ; data->mtxmanager = mtxmanager ; data->myid = myid ; data->forwAggList = forwAggList ; data->backAggList = backAggList ; data->p_mtx = p_mtx ; data->frontIsDone = frontIsDone ; data->lowerIsDone = lowerIsDone ; data->diagIsDone = diagIsDone ; data->upperIsDone = upperIsDone ; data->cpus = cpus ; data->msglvl = msglvl ; if ( msglvl > 0 ) { sprintf(buffer, "solve.res.%d", myid) ; if ( (fp = fopen(buffer, "w")) == NULL ) { fprintf(stderr, "\n fatal error, unable to open file %s", buffer) ; exit(-1) ; } data->msgFile = fp ; } else { data->msgFile = NULL ; } } MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : initialization time", t2 - t1) ; fflush(msgFile) ; } /* -------------------------------------- switch over the type of thread library -------------------------------------- */ #if THREAD_TYPE == TT_SOLARIS /* --------------- solaris threads --------------- */ MARKTIME(t1) ; thr_setconcurrency(nthread) ; MARKTIME(t2) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n CPU %8.3f : set concurrency time", t2 - t1) ; } MARKTIME(t1) ; for ( myid = 0, data = dataObjects ; myid < nthread - 1 ; myid++, data++ ) { rc = thr_create(NULL, 0, FrontMtx_workerSolve, data, 0, NULL) ; if ( rc != 0 ) { fprintf(stderr, "\n fatal error, myid = %d, rc = %d from thr_create", myid, rc) ; exit(-1) ; } } MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : thread creation time", t2 - t1) ; fflush(msgFile) ; } MARKTIME(t1) ; FrontMtx_workerSolve(data) ; for ( myid = 0 ; myid < nthread - 1 ; myid++ ) { thr_join(0, 0, 0) ; } MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : thread join time", t2 - t1) ; fflush(msgFile) ; } #endif #if THREAD_TYPE == TT_POSIX /* ------------- POSIX threads ------------- */ { pthread_attr_t attr ; pthread_t *tids ; void *status ; /* ##### NOTE: for SGI machines, this command must be present ##### for the thread scheduling to be efficient. ##### this is NOT a POSIX call, but SGI needs it anyway pthread_setconcurrency(nthread) ; */ MARKTIME(t1) ; pthread_attr_init(&attr) ; /* pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) ; */ pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS) ; ALLOCATE(tids, pthread_t, nthread) ; for ( myid = 0, data = dataObjects ; myid < nthread ; myid++, data++ ) { rc = pthread_create(&tids[myid], &attr, FrontMtx_workerSolve, data) ; if ( rc != 0 ) { fprintf(stderr, "\n fatal error, myid = %d, rc = %d from pthread_create", myid, rc) ; exit(-1) ; } } MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : thread creation time", t2 - t1) ; fflush(msgFile) ; } MARKTIME(t1) ; for ( myid = 0 ; myid < nthread ; myid++ ) { pthread_join(tids[myid], &status) ; } MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : thread join time", t2 - t1) ; fflush(msgFile) ; } FREE(tids) ; pthread_attr_destroy(&attr) ; } #endif /* --------------------- free the working data --------------------- */ MARKTIME(t1) ; DVzero(8, cpus) ; for ( myid = 0, data = dataObjects ; myid < nthread ; myid++, data++ ) { for ( ii = 0 ; ii < 8 ; ii++ ) { cpus[ii] += data->cpus[ii] ; } } FREE(dataObjects) ; FREE(p_mtx) ; CVfree(frontIsDone) ; CVfree(lowerIsDone) ; CVfree(diagIsDone) ; CVfree(upperIsDone) ; SubMtxList_free(forwAggList) ; SubMtxList_free(backAggList) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : free working data", t2 - t1) ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- worker method to solve the linear system created -- 97jun27, cca ---------------------------------------- */ static void * FrontMtx_workerSolve ( void *arg ) { char *diagIsDone, *frontIsDone, *lowerIsDone, *status, *upperIsDone ; DenseMtx *rhsmtx, *solmtx ; SubMtx **p_agg, **p_mtx ; SubMtxList *backAggList, *forwAggList ; SubMtxManager *mtxmanager ; FrontMtx *frontmtx ; double t0, t1, t2, t3 ; double *cpus ; SolveData *data ; FILE *msgFile ; Ideq *dequeue ; int everybodyDone, iproc, I, J, K, msglvl, myid, nfront, nproc, nrhs ; int *fch, *nactiveChild, *owners, *par, *sib ; IP **heads ; SolveMap *solvemap ; Tree *tree ; /* ------------------------------- extract pointers and dimensions ------------------------------- */ MARKTIME(t0) ; data = (SolveData *) arg ; frontmtx = data->frontmtx ; rhsmtx = data->rhsmtx ; solmtx = data->solmtx ; solvemap = data->solvemap ; mtxmanager = data->mtxmanager ; forwAggList = data->forwAggList ; backAggList = data->backAggList ; p_mtx = data->p_mtx ; frontIsDone = data->frontIsDone ; lowerIsDone = data->lowerIsDone ; diagIsDone = data->diagIsDone ; upperIsDone = data->upperIsDone ; myid = data->myid ; cpus = data->cpus ; msglvl = data->msglvl ; msgFile = data->msgFile ; nfront = frontmtx->nfront ; nproc = solvemap->nproc ; tree = frontmtx->frontETree->tree ; par = tree->par ; fch = tree->fch ; sib = tree->sib ; nrhs = rhsmtx->ncol ; owners = SolveMap_owners(solvemap) ; /* ----------------------------------------------- set up for the forward solve (1) IP lists for the forward solve (2) local status[] vector (3) create the dequeue for the forward solve (4) create the number of active children vector ----------------------------------------------- */ MARKTIME(t1) ; heads = SolveMap_forwardSetup(solvemap, myid, msglvl, msgFile) ; status = CVinit(nfront, 'F') ; dequeue = FrontMtx_setUpDequeue(frontmtx, owners, myid, status, heads, 'W', 'F', msglvl, msgFile) ; FrontMtx_loadActiveLeaves(frontmtx, status, 'W', dequeue) ; nactiveChild = FrontMtx_nactiveChild(frontmtx, status, myid) ; MARKTIME(t2) ; cpus[0] += t2 - t1 ; if ( msglvl > 2 ) { IP *ip ; fprintf(msgFile, "\n\n forward update lists") ; for ( J = 0 ; J < nfront ; J++ ) { if ( heads[J] != NULL ) { fprintf(msgFile, "\n %d : ", J) ; for ( ip = heads[J] ; ip != NULL ; ip = ip->next ) { fprintf(msgFile, " %d", ip->val) ; } } } fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n dequeue set up for forward solve") ; Ideq_writeForHumanEye(dequeue, msgFile) ; fprintf(msgFile, "\n\n nactiveChild") ; IVfprintf(msgFile, nfront, nactiveChild) ; fflush(msgFile) ; } /* ------------------------ load the right hand side ------------------------ */ MARKTIME(t1) ; p_agg = FrontMtx_loadRightHandSide(frontmtx, rhsmtx, owners, myid, mtxmanager, msglvl, msgFile) ; MARKTIME(t2) ; cpus[1] += t2 - t1 ; /* ------------- forward solve ------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n\n thread %d : starting forward solve", myid) ; fflush(stdout) ; #endif MARKTIME(t1) ; while ( (J = Ideq_removeFromHead(dequeue)) != -1 ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ### forward solve, checking out J = %d, status %c", J, status[J]) ; fflush(msgFile) ; } FrontMtx_forwardVisit(frontmtx, J, nrhs, owners, myid, mtxmanager, forwAggList, p_mtx, frontIsDone, heads, p_agg, status, msglvl, msgFile) ; if ( status[J] == 'F' ) { /* ------------------- front J is finished ------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n front J is finished") ; fflush(msgFile) ; } if ( (K = par[J]) != -1 && --nactiveChild[K] == 0 ) { /* ----------------------------------- all children of parent are finished add parent to head of dequeue ----------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, ", placing %d on head of dequeue", K) ; fflush(msgFile) ; } Ideq_insertAtHead(dequeue, K) ; } } else { /* ------------------------------------------------- front J is not finished, place on tail of dequeue ------------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n front J is not finished") ; fflush(msgFile) ; } Ideq_insertAtTail(dequeue, J) ; } } IP_free(heads[nfront+1]) ; FREE(heads) ; IVfree(nactiveChild) ; Ideq_free(dequeue) ; MARKTIME(t2) ; cpus[2] += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n forward solve finished") ; fflush(msgFile) ; } /* ------------------------------------------ all processes wait here until all are done ------------------------------------------ */ lowerIsDone[myid] = 'Y' ; do { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n 1. checking out lowerIsDone[] vector: ") ; fflush(msgFile) ; } everybodyDone = 1 ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( msglvl > 2 ) { fprintf(msgFile, " %c", lowerIsDone[iproc]) ; fflush(msgFile) ; } if ( lowerIsDone[iproc] != 'Y' ) { everybodyDone = 0 ; break ; } } } while ( everybodyDone == 0 ) ; /* --------------------- do the diagonal solve --------------------- */ MARKTIME(t1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( owners[J] == myid ) { FrontMtx_diagonalVisit(frontmtx, J, owners, myid, p_mtx, frontIsDone, p_agg, msglvl, msgFile) ; /* ------------------------------------------------------------ set frontIsDone[J] to 'N' to be ready for the backward solve ------------------------------------------------------------ */ frontIsDone[J] = 'N' ; } } MARKTIME(t2) ; cpus[3] += t2 - t1 ; /* ------------------------------------------ all processes wait here until all are done ------------------------------------------ */ diagIsDone[myid] = 'Y' ; do { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n 2. checking out diagIsDone[] vector: ") ; fflush(msgFile) ; } everybodyDone = 1 ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( msglvl > 2 ) { fprintf(msgFile, " %c", diagIsDone[iproc]) ; fflush(msgFile) ; } if ( diagIsDone[iproc] != 'Y' ) { everybodyDone = 0 ; break ; } } } while ( everybodyDone == 0 ) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n everybody is done") ; fflush(msgFile) ; } /* --------------------------------------------- set up for the backward solve (1) IP lists for the backward solve (2) set up the dequeue for the backward solve --------------------------------------------- */ MARKTIME(t1) ; heads = SolveMap_backwardSetup(solvemap, myid, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n ") ; for ( J = 0 ; J < nfront ; J++ ) { IP *ip ; fprintf(msgFile, "\n %d :", J) ; fflush(msgFile) ; for ( ip = heads[J] ; ip != NULL ; ip = ip->next ) { fprintf(msgFile, " %d", ip->val) ; fflush(msgFile) ; } } } dequeue = FrontMtx_setUpDequeue(frontmtx, owners, myid, status, heads, 'W', 'F', msglvl, msgFile) ; FrontMtx_loadActiveRoots(frontmtx, status, 'W', dequeue) ; MARKTIME(t2) ; cpus[1] += t2 - t1 ; /* -------------- backward solve -------------- */ #if MYDEBUG > 0 fflush(stdout) ; #endif if ( msglvl > 2 ) { fprintf(msgFile, "\n\n thread %d : starting backward solve", myid) ; fflush(msgFile) ; } MARKTIME(t1) ; while ( (J = Ideq_removeFromHead(dequeue)) != -1 ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n\n ### backward solve, checking out J = %d, status %c", J, status[J]) ; fflush(msgFile) ; } FrontMtx_backwardVisit(frontmtx, J, nrhs, owners, myid, mtxmanager, backAggList, p_mtx, frontIsDone, heads, p_agg, status, msglvl, msgFile) ; if ( status[J] == 'F' ) { /* ------------------- front J is finished ------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n front J is finished") ; fflush(msgFile) ; } for ( I = fch[J] ; I != -1 ; I = sib[I] ) { if ( status[I] == 'W' ) { Ideq_insertAtHead(dequeue, I) ; } } } else { /* ------------------------------------------------- front J is not finished, place on tail of dequeue ------------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n front J is not finished") ; fflush(msgFile) ; } Ideq_insertAtTail(dequeue, J) ; } } CVfree(status) ; IP_free(heads[nfront+1]) ; FREE(heads) ; Ideq_free(dequeue) ; MARKTIME(t2) ; cpus[4] += t2 - t1 ; /* ------------------------------------------ all processes wait here until all are done ------------------------------------------ */ upperIsDone[myid] = 'Y' ; do { if ( msglvl > 2 ) { fprintf(msgFile, "\n\n 2. checking out upperIsDone[] vector: ") ; fflush(msgFile) ; } everybodyDone = 1 ; for ( iproc = 0 ; iproc < nproc ; iproc++ ) { if ( msglvl > 2 ) { fprintf(msgFile, " %c", upperIsDone[iproc]) ; fflush(msgFile) ; } if ( upperIsDone[iproc] != 'Y' ) { everybodyDone = 0 ; break ; } } } while ( everybodyDone == 0 ) ; /* -------------------------- store the solution entries -------------------------- */ MARKTIME(t1) ; FrontMtx_storeSolution(frontmtx, owners, myid, mtxmanager, p_mtx, solmtx, msglvl, msgFile) ; MARKTIME(t2) ; cpus[5] += t2 - t1 ; /* ------------------------ free the working storage ------------------------ */ FREE(p_agg) ; return(NULL) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- set up the aggregate list objects for the forward and back solves created -- 98mar20, cca ----------------------------------------------------------------- */ static void setupListObjects ( FrontMtx *frontmtx, SolveMap *solvemap, SubMtxList *forwAggList, SubMtxList *backAggList, int msglvl, FILE *msgFile ) { char *flags ; int J, nfront ; int *aggcounts ; IV *aggcountsIV ; nfront = SolveMap_nfront(solvemap) ; flags = CVinit(nfront, 'N') ; /* ------------------------------------------------------ set up the aggregate list object for the forward solve ------------------------------------------------------ */ aggcountsIV = SolveMap_lowerAggregateIV(solvemap, -1, msglvl, msgFile) ; aggcounts = IV_entries(aggcountsIV) ; for ( J = 0 ; J < nfront ; J++ ) { if ( aggcounts[J] > 1 ) { flags[J] = 'Y' ; } } SubMtxList_init(forwAggList, nfront, aggcounts, 1, flags) ; IV_free(aggcountsIV) ; /* ------------------------------------------------------- set up the aggregate list object for the backward solve ------------------------------------------------------- */ aggcountsIV = SolveMap_upperAggregateIV(solvemap, -1, msglvl, msgFile) ; aggcounts = IV_entries(aggcountsIV) ; for ( J = 0 ; J < nfront ; J++ ) { if ( aggcounts[J] > 1 ) { flags[J] = 'Y' ; } } SubMtxList_init(backAggList, nfront, aggcounts, 1, flags) ; IV_free(aggcountsIV) ; CVfree(flags) ; return ; } /*--------------------------------------------------------------------*/ local status[] vector (3) create the dequeue for the forward solve (4) create the number of active children vector ----------------------------------------------- */ MARKTIME(t1) ; heads = SolveMap_forwardSetup(solvemap, myid, msglvl, msgFile) ; status = CVinit(nfront, 'F') ; dequeue = FrontMtx_setUpDequeue(frontmtx, owners, myid, status, heads, 'W', 'F', msglvl, msgFile) ; FrontMtx_loadActiveLeaves(frontmtx, status, 'W', dequeue) ; nactiveChild = FrontMtx_MT/drivers/do_QRgridMT010075500020550007177000000006470657133652700161550ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res set msgFile = stdout set n1 = 7 set n2 = 7 set n3 = 7 set seed = 10101 set nrhs = 4 set type = 2 set nthread = 2 set maptype = 4 set cutoff = 0.25 foreach n ( 7 ) set n1 = $n set n2 = $n set n3 = 1 set n3 = $n echo $n1 x $n2 x $n3 grid testQRgridMT \ $msglvl $msgFile $n1 $n2 $n3 $seed $nrhs $type \ $nthread $maptype $cutoff end MT/drivers/do_allInOneMT010075500020550007177000000011570657354735600164710ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout # type -- type of entries # 1 -- real entries # 2 -- complex entries set type = 1 # symmetryflag -- type of symmetry in the matrix # 0 -- symmetric # 1 -- hermitian # 2 -- nonsymmetric set symmetryflag = 0 # pivotingflag -- type of pivoting in the factorization # 0 -- no pivoting # 1 -- pivoting set pivotingflag = 0 set matrixFileName = matrix.input set rhsFileName = rhs.input set seed = 10101 set nthread = 4 allInOneMT $msglvl $msgFile $type $symmetryflag $pivotingflag \ $matrixFileName $rhsFileName $seed $nthread MT/drivers/do_factorMT010075500020550007177000000015450657604434700162420ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res3D.64 set msgFile = res3D set msgFile = /local1/ARPA/junk/res.grid.MT set msgFile = stdout set mtxFile = /local1/ARPA/matrices/i4a/i4a.inpmtxb set etreeFile = /local1/ARPA/matrices/i4a/best0.etreef set mtxFile = ../../Matrices/R2D100/orig.inpmtxf set etreeFile = ../../Matrices/R2D100/nd.etreef set seed = 10101 set symmetryflag = 0 set sparsityflag = 0 set pivotingflag = 0 set tau = 5 set droptol = 1.e-10 set nrhs = 4 set nthread = 4 set maptype = 3 set cutoff = 0.25 set lookahead = 0 testFactorMT $msglvl $msgFile $mtxFile $etreeFile \ $seed $symmetryflag $sparsityflag $pivotingflag \ $tau $droptol $nrhs $nthread $maptype $cutoff $lookahead ile = ../../Matrices/R2D100/nd.etreef set seed = 10101 set symmetryflag = 0 set sparsityflag = 0 set pivotingflag = 0 set tau MT/drivers/do_gridMT010075500020550007177000000026170662264352100157010ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res3D.64 set msgFile = res3D set msgFile = /local1/ARPA/junk/res.grid.MT set msgFile = stdout set n1 = 7 set n2 = 7 set n3 = 1 set maxzeros = 1000 set maxzeros = 0 set maxsize = 1000 set maxsize = 64 set seed = 10101 set type = 1 set symmetryflag = 0 set sparsityflag = 0 set pivotingflag = 0 set tau = 5 set droptol = 1.e-10 set nrhs = 4 set nthread = 2 set maptype = 3 set cutoff = 0.25 set lookahead = 0 # foreach n1 ( 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 ) # foreach maxzeros ( 400 800 1600 ) # foreach lookahead ( 0 1 2 3 4 ) # foreach maxsize ( 32 ) # set msgFile = res3D.$maxsize.$maxzeros echo $maxzeros $maxsize # foreach n1 ( 5 7 9 11 13 15 17 19 21 23 25 27 29 31 ) # foreach n1 ( 25 ) # set n2 = $n1 # set n3 = $n1 # foreach sparsityflag ( 0 1 ) # foreach pivotingflag ( 0 1 ) # foreach symmetryflag ( 0 2 ) echo $n1 $n2 $n3 # foreach lookahead ( 0 ) echo lookahead = $lookahead testGridMT $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize \ $seed $type $symmetryflag $sparsityflag $pivotingflag \ $tau $droptol $nrhs $nthread $maptype $cutoff $lookahead # end # end # end # end # end # end # end MT/drivers/do_mmm010075500020550007177000000021760657354544700153160ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 2 set msgFile = res set msgFile = stdout # dataType = 0 --> indices only # dataType = 1 --> real entries # dataType = 2 --> complex entries set dataType = 1 # symflag = 0 --> symmetric # symflag = 1 --> hermitian # symflag = 2 --> nonsymmetric set symflag = 2 # storageMode = 1 --> rows # storageMode = 2 --> columns # storageMode = 3 --> chevrons set storageMode = 1 # transposeflag = 0 --> Y := Y + alpha * A * X # transposeflag = 1 --> Y := Y + alpha * A^H * X, nonsymmetric only # transposeflag = 2 --> Y := Y + alpha * A^T * X, nonsymmetric only set transposeflag = 0 set nrow = 10 set ncol = 10 set nitem = 200 set nrhs = 3 set seed = 10203 set alphaReal = 4.0 set alphaImag = -7.0 set nthread = 2 foreach transposeflag ( 0 ) foreach symflag ( 0 ) foreach dataType ( 1 ) foreach storageMode ( 1 ) testMMM $msglvl $msgFile $dataType $symflag $storageMode \ $transposeflag $nrow $ncol $nitem $nrhs $seed \ $alphaReal $alphaImag $nthread end end end end MT/drivers/do_patchAndGoMT010075500020550007177000000012760657604365500167760ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout # type -- type of entries # 1 -- real entries # 2 -- complex entries set type = 1 # symmetryflag -- type of symmetry in the matrix # 0 -- symmetric # 1 -- hermitian # 2 -- nonsymmetric set symmetryflag = 0 set patchAndGoFlag = 2 set toosmall = 1.e-9 set fudge = 1.e-9 set storeids = 1 set storevalues = 1 set matrixFileName = singularMatrix.input set rhsFileName = singularRhs.input set seed = 10101 set nthread = 4 patchAndGoMT $msglvl $msgFile $type $symmetryflag \ $patchAndGoFlag $toosmall $fudge $storeids $storevalues \ $matrixFileName $rhsFileName $seed $nthread MT/drivers/makefile010064400020550007177000000020260665314263300155770ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../src/spoolesMT.a ../../spooles.a ${THREAD_LIBS} -lm DRIVERS = testMMM \ testGridMT \ testQRgridMT \ allInOneMT \ patchAndGoMT \ testFactorMT libs : cd ../src ; make spoolesMT.a drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} allInOneMT : allInOneMT.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testFactorMT : testFactorMT.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testMMM : testMMM.o libs ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testQRgridMT : testQRgridMT.o libs ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} testGridMT : testGridMT.o libs ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} patchAndGoMT : patchAndGoMT.o libs ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} MT/drivers/allInOneMT.c010064400020550007177000000321400665165541200162070ustar00clevecompmath00000400000006/* allInOneMT.c */ #include "../spoolesMT.h" #include "../../misc.h" #include "../../FrontMtx.h" #include "../../SymbFac.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ------------------------------------------------------------------ all-in-one program to solve A X = Y using a multithreaded factorization and solve (1) read in matrix entries for A and form InpMtx object (2) read in right hand side for Y entries and form DenseMtx object (3) form Graph object, order matrix and form front tree (4) get the permutation, permute the front tree, matrix and right hand side and get the symbolic factorization (5) initialize the front matrix object to hold the factor matrices (6) get the domain-decomposition map from fronts to threads (7) compute the numeric factorization (8) post-process the factor matrices (9) get the map for the parallel solve (10) compute the solution (11) permute the solution into the original ordering created -- 98jun04, cca ------------------------------------------------------------------ */ /*--------------------------------------------------------------------*/ char *matrixFileName, *rhsFileName ; DenseMtx *mtxY, *mtxX ; Chv *rootchv ; ChvManager *chvmanager ; double droptol = 0.0, tau = 100. ; double cpus[10] ; DV *cumopsDV ; ETree *frontETree ; FrontMtx *frontmtx ; FILE *inputFile, *msgFile ; Graph *graph ; InpMtx *mtxA ; int error, ient, irow, jcol, jrhs, jrow, lookahead=0, msglvl, ncol, nedges, nent, neqns, nfront, nrhs, nrow, nthread, pivotingflag, seed, symmetryflag, type ; int *newToOld, *oldToNew ; int stats[20] ; IV *newToOldIV, *oldToNewIV, *ownersIV ; IVL *adjIVL, *symbfacIVL ; SolveMap *solvemap ; SubMtxManager *mtxmanager ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 10 ) { fprintf(stdout, "\n" "\n usage: %s msglvl msgFile type symmetryflag pivotingflag" "\n matrixFileName rhsFileName seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 (SPOOLES_REAL) -- real entries" "\n 2 (SPOOLES_COMPLEX) -- complex entries" "\n symmetryflag -- type of matrix" "\n 0 (SPOOLES_SYMMETRIC) -- symmetric entries" "\n 1 (SPOOLES_HERMITIAN) -- Hermitian entries" "\n 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric entries" "\n pivotingflag -- type of pivoting" "\n 0 (SPOOLES_NO_PIVOTING) -- no pivoting used" "\n 1 (SPOOLES_PIVOTING) -- pivoting used" "\n matrixFileName -- matrix file name, format" "\n nrow ncol nent" "\n irow jcol entry" "\n ..." "\n note: indices are zero based" "\n rhsFileName -- right hand side file name, format" "\n nrow nrhs " "\n ..." "\n jrow entry(jrow,0) ... entry(jrow,nrhs-1)" "\n ..." "\n seed -- random number seed, used for ordering" "\n nthread -- number of threads" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; symmetryflag = atoi(argv[4]) ; pivotingflag = atoi(argv[5]) ; matrixFileName = argv[6] ; rhsFileName = argv[7] ; seed = atoi(argv[8]) ; nthread = atoi(argv[9]) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 1: read the entries from the input file and create the InpMtx object -------------------------------------------- */ inputFile = fopen(matrixFileName, "r") ; fscanf(inputFile, "%d %d %d", &nrow, &ncol, &nent) ; neqns = nrow ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, 0) ; if ( type == SPOOLES_REAL ) { double value ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else { double imag, real ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- STEP 2: read the right hand side matrix Y ----------------------------------------- */ inputFile = fopen(rhsFileName, "r") ; fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxY = DenseMtx_new() ; DenseMtx_init(mtxY, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxY) ; if ( type == SPOOLES_REAL ) { double value ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxY, jrow, jrhs, value) ; } } } else { double imag, real ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxY, jrow, jrhs, real, imag) ; } } } fclose(inputFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n rhs matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- STEP 3 : find a low-fill ordering (1) create the Graph object (2) order the graph using multiple minimum degree ------------------------------------------------- */ graph = Graph_new() ; adjIVL = InpMtx_fullAdjacency(mtxA) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- STEP 4: get the permutation, permute the front tree, permute the matrix and right hand side, and get the symbolic factorization ---------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; oldToNew = IV_entries(oldToNewIV) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; newToOld = IV_entries(newToOldIV) ; ETree_permuteVertices(frontETree, oldToNewIV) ; InpMtx_permute(mtxA, oldToNew, oldToNew) ; if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; DenseMtx_permuteRows(mtxY, oldToNewIV) ; symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n old-to-new permutation vector") ; IV_writeForHumanEye(oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation vector") ; IV_writeForHumanEye(newToOldIV, msgFile) ; fprintf(msgFile, "\n\n front tree after permutation") ; ETree_writeForHumanEye(frontETree, msgFile) ; fprintf(msgFile, "\n\n input matrix after permutation") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fprintf(msgFile, "\n\n right hand side matrix after permutation") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 5: setup the domain decomposition map ------------------------------------------ */ if ( nthread > (nfront = ETree_nfront(frontETree)) ) { nthread = nfront ; } cumopsDV = DV_new() ; DV_init(cumopsDV, nthread, NULL) ; ownersIV = ETree_ddMap(frontETree, type, symmetryflag, cumopsDV, 1./(2.*nthread)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n map from fronts to threads") ; IV_writeForHumanEye(ownersIV, msgFile) ; fprintf(msgFile, "\n\n factor operations for each front") ; DV_writeForHumanEye(cumopsDV, msgFile) ; fflush(msgFile) ; } DV_free(cumopsDV) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 6: initialize the front matrix object ------------------------------------------ */ frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, LOCK_IN_PROCESS, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, pivotingflag, LOCK_IN_PROCESS, 0, NULL, mtxmanager, msglvl, msgFile) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- STEP 7: compute the numeric factorization in parallel ----------------------------------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, LOCK_IN_PROCESS, 1) ; DVfill(10, cpus, 0.0) ; IVfill(20, stats, 0) ; rootchv = FrontMtx_MT_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, ownersIV, lookahead, &error, cpus, stats, msglvl, msgFile) ; ChvManager_free(chvmanager) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } if ( rootchv != NULL ) { fprintf(msgFile, "\n\n matrix found to be singular\n") ; exit(-1) ; } if ( error >= 0 ) { fprintf(msgFile, "\n\n fatal error at front %d", error) ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- STEP 8: post-process the factorization -------------------------------------- */ FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 9: get the solve map object for the parallel solve ------------------------------------------------------- */ solvemap = SolveMap_new() ; SolveMap_ddMap(solvemap, symmetryflag, FrontMtx_upperBlockIVL(frontmtx), FrontMtx_lowerBlockIVL(frontmtx), nthread, ownersIV, FrontMtx_frontTree(frontmtx), seed, msglvl, msgFile) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 10: solve the linear system in parallel -------------------------------------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; FrontMtx_MT_solve(frontmtx, mtxX, mtxY, mtxmanager, solvemap, cpus, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n solution matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- STEP 11: permute the solution into the original ordering -------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------- free memory ----------- */ FrontMtx_free(frontmtx) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxY) ; IV_free(newToOldIV) ; IV_free(oldToNewIV) ; InpMtx_free(mtxA) ; ETree_free(frontETree) ; IVL_free(symbfacIVL) ; SubMtxManager_free(mtxmanager) ; Graph_free(graph) ; SolveMap_free(solvemap) ; IV_free(ownersIV) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ rhsFileName -- right hand side file name, format" "\n nrow nrhs " "\n ..." "\n jrow entry(jrow,0) ... entry(jrow,nrhs-1)" "\n ..." "\n seed -- random number seed, used for ordering" "\n nthread -- number of threads" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } eMT/drivers/patchAndGoMT.c010064400020550007177000000347210663602731000165160ustar00clevecompmath00000400000006/* testPatchAndGoMT.c */ #include "../spoolesMT.h" #include "../../misc.h" #include "../../FrontMtx.h" #include "../../SymbFac.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* -------------------------------------------------- all-in-one program to solve A X = B using a multithreaded factorization and solve We use a patch-and-go strategy for the factorization without pivoting (1) read in matrix entries and form DInpMtx object (2) form Graph object (3) order matrix and form front tree (4) get the permutation, permute the matrix and front tree and get the symbolic factorization (5) compute the numeric factorization (6) read in right hand side entries (7) compute the solution created -- 98jun04, cca -------------------------------------------------- */ /*--------------------------------------------------------------------*/ char *matrixFileName, *rhsFileName ; DenseMtx *mtxB, *mtxX ; Chv *rootchv ; ChvManager *chvmanager ; double fudge, imag, real, tau = 100., toosmall, value ; double cpus[10] ; DV *cumopsDV ; ETree *frontETree ; FrontMtx *frontmtx ; FILE *inputFile, *msgFile ; Graph *graph ; InpMtx *mtxA ; int error, ient, irow, jcol, jrhs, jrow, lookahead, msglvl, ncol, nedges, nent, neqns, nfront, nrhs, nrow, nthread, patchAndGoFlag, seed, storeids, storevalues, symmetryflag, type ; int *newToOld, *oldToNew ; int stats[20] ; IV *newToOldIV, *oldToNewIV, *ownersIV ; IVL *adjIVL, *symbfacIVL ; SolveMap *solvemap ; SubMtxManager *mtxmanager ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 14 ) { fprintf(stdout, "\n" "\n usage: %s msglvl msgFile type symmetryflag patchAndGoFlag" "\n fudge toosmall storeids storevalues" "\n matrixFileName rhsFileName seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 (SPOOLES_REAL) -- real entries" "\n 2 (SPOOLES_COMPLEX) -- complex entries" "\n symmetryflag -- type of matrix" "\n 0 (SPOOLES_SYMMETRIC) -- symmetric entries" "\n 1 (SPOOLES_HERMITIAN) -- Hermitian entries" "\n 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric entries" "\n patchAndGoFlag -- flag for the patch-and-go strategy" "\n 0 -- none, stop factorization" "\n 1 -- optimization strategy" "\n 2 -- structural analysis strategy" "\n fudge -- perturbation parameter" "\n toosmall -- upper bound on a small pivot" "\n storeids -- flag to store ids of small pivots" "\n storevalues -- flag to store perturbations" "\n matrixFileName -- matrix file name, format" "\n nrow ncol nent" "\n irow jcol entry" "\n ..." "\n note: indices are zero based" "\n rhsFileName -- right hand side file name, format" "\n nrow nrhs " "\n ..." "\n jrow entry(jrow,0) ... entry(jrow,nrhs-1)" "\n ..." "\n seed -- random number seed, used for ordering" "\n nthread -- number of threads" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; symmetryflag = atoi(argv[4]) ; patchAndGoFlag = atoi(argv[5]) ; fudge = atof(argv[6]) ; toosmall = atof(argv[7]) ; storeids = atoi(argv[8]) ; storevalues = atoi(argv[9]) ; matrixFileName = argv[10] ; rhsFileName = argv[11] ; seed = atoi(argv[12]) ; nthread = atoi(argv[13]) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 1: read the entries from the input file and create the InpMtx object -------------------------------------------- */ if ( (inputFile = fopen(matrixFileName, "r")) == NULL ) { fprintf(stderr, "\n unable to open file %s", matrixFileName) ; exit(-1) ; } fscanf(inputFile, "%d %d %d", &nrow, &ncol, &nent) ; neqns = nrow ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, 0) ; if ( type == SPOOLES_REAL ) { for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else { for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- STEP 2 : find a low-fill ordering (1) create the Graph object (2) order the graph using multiple minimum degree ------------------------------------------------- */ graph = Graph_new() ; adjIVL = InpMtx_fullAdjacency(mtxA) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- STEP 3: get the permutation, permute the matrix and front tree and get the symbolic factorization ----------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; oldToNew = IV_entries(oldToNewIV) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; newToOld = IV_entries(newToOldIV) ; ETree_permuteVertices(frontETree, oldToNewIV) ; InpMtx_permute(mtxA, oldToNew, oldToNew) ; InpMtx_mapToUpperTriangle(mtxA) ; InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n old-to-new permutation vector") ; IV_writeForHumanEye(oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation vector") ; IV_writeForHumanEye(newToOldIV, msgFile) ; fprintf(msgFile, "\n\n front tree after permutation") ; ETree_writeForHumanEye(frontETree, msgFile) ; fprintf(msgFile, "\n\n input matrix after permutation") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 4: initialize the front matrix object and the PatchAndGoInfo object to handle small pivots ------------------------------------------ */ frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, LOCK_IN_PROCESS, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, LOCK_IN_PROCESS, 0, NULL, mtxmanager, msglvl, msgFile) ; if ( patchAndGoFlag == 1 ) { frontmtx->patchinfo = PatchAndGoInfo_new() ; PatchAndGoInfo_init(frontmtx->patchinfo, 1, toosmall, fudge, storeids, storevalues) ; } else if ( patchAndGoFlag == 2 ) { frontmtx->patchinfo = PatchAndGoInfo_new() ; PatchAndGoInfo_init(frontmtx->patchinfo, 2, toosmall, fudge, storeids, storevalues) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 5: setup the domain decomposition map ------------------------------------------ */ if ( nthread > (nfront = FrontMtx_nfront(frontmtx)) ) { nthread = nfront ; } cumopsDV = DV_new() ; DV_init(cumopsDV, nthread, NULL) ; ownersIV = ETree_ddMap(frontETree, type, symmetryflag, cumopsDV, 1./(2.*nthread)) ; DV_free(cumopsDV) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- STEP 6: compute the numeric factorization in parallel ----------------------------------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, LOCK_IN_PROCESS, 1) ; DVfill(10, cpus, 0.0) ; IVfill(20, stats, 0) ; lookahead = 0 ; rootchv = FrontMtx_MT_factorInpMtx(frontmtx, mtxA, tau, 0.0, chvmanager, ownersIV, lookahead, &error, cpus, stats, msglvl, msgFile) ; if ( patchAndGoFlag == 1 ) { if ( frontmtx->patchinfo->fudgeIV != NULL ) { fprintf(msgFile, "\n small pivots found at these locations") ; IV_writeForHumanEye(frontmtx->patchinfo->fudgeIV, msgFile) ; } PatchAndGoInfo_free(frontmtx->patchinfo) ; } else if ( patchAndGoFlag == 2 ) { if ( frontmtx->patchinfo->fudgeIV != NULL ) { fprintf(msgFile, "\n small pivots found at these locations") ; IV_writeForHumanEye(frontmtx->patchinfo->fudgeIV, msgFile) ; } if ( frontmtx->patchinfo->fudgeDV != NULL ) { fprintf(msgFile, "\n perturbations") ; DV_writeForHumanEye(frontmtx->patchinfo->fudgeDV, msgFile) ; } PatchAndGoInfo_free(frontmtx->patchinfo) ; } ChvManager_free(chvmanager) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } if ( rootchv != NULL ) { fprintf(msgFile, "\n\n matrix found to be singular\n") ; exit(-1) ; } if ( error >= 0 ) { fprintf(msgFile, "\n\n fatal error at front %d\n", error) ; exit(-1) ; } /* -------------------------------------- STEP 7: post-process the factorization -------------------------------------- */ FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- STEP 8: read the right hand side matrix B ----------------------------------------- */ if ( (inputFile = fopen(rhsFileName, "r")) == NULL ) { fprintf(stderr, "\n unable to open file %s", rhsFileName) ; exit(-1) ; } fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxB = DenseMtx_new() ; DenseMtx_init(mtxB, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxB) ; if ( type == SPOOLES_REAL ) { for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxB, jrow, jrhs, value) ; } } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxB, jrow, jrhs, real, imag) ; } } } fclose(inputFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n rhs matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- STEP 9: permute the right hand side into the original ordering -------------------------------------------------------------- */ DenseMtx_permuteRows(mtxB, oldToNewIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n right hand side matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- STEP 10: get the solve map object for the parallel solve -------------------------------------------------------- */ solvemap = SolveMap_new() ; SolveMap_ddMap(solvemap, type, FrontMtx_upperBlockIVL(frontmtx), FrontMtx_lowerBlockIVL(frontmtx), nthread, ownersIV, FrontMtx_frontTree(frontmtx), seed, msglvl, msgFile) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 11: solve the linear system in parallel -------------------------------------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; FrontMtx_MT_solve(frontmtx, mtxX, mtxB, mtxmanager, solvemap, cpus, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n solution matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- STEP 12: permute the solution into the original ordering -------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------- free memory ----------- */ FrontMtx_free(frontmtx) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxB) ; IV_free(newToOldIV) ; IV_free(oldToNewIV) ; InpMtx_free(mtxA) ; ETree_free(frontETree) ; IVL_free(symbfacIVL) ; SubMtxManager_free(mtxmanager) ; Graph_free(graph) ; SolveMap_free(solvemap) ; IV_free(ownersIV) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ "\n\n new-to-old permutation vector") ; IV_wMT/drivers/testFactorMT.c010064400020550007177000000533010661663216200166240ustar00clevecompmath00000400000006/* testFactorMT.c */ #include "../spoolesMT.h" #include "../../FrontMtx.h" #include "../../Drand.h" #include "../../SymbFac.h" #include "../../timings.h" #include "../../misc.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------------- test the factor method for a grid matrix (1) read in an InpMtx object (2) read in an ETree object (3) create a solution matrix object (4) multiply the solution with the matrix to get a right hand side matrix object (5) factor the matrix (6) solve the system created -- 98sep05, cca ----------------------------------------------------- */ { char *etreeFileName, *mtxFileName ; Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxB, *mtxX, *mtxZ ; double one[2] = { 1.0, 0.0 }, cpus[11] ; double cputotal, cutoff, droptol, factorops ; Drand drand ; double nops, tau, t1, t2 ; DV *cumopsDV ; ETree *frontETree ; FILE *msgFile ; FrontMtx *frontmtx ; InpMtx *mtxA ; int error, loc, lookahead, maptype, msglvl, neqns, nrhs, nthread, nzf, pivotingflag, rc, seed, sparsityflag, symmetryflag, type ; int stats[20] ; IV *frontOwnersIV, *newToOldIV, *oldToNewIV ; IVL *symbfacIVL ; SolveMap *solvemap ; SubMtxManager *mtxmanager ; if ( argc != 16 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile mtxFile etreeFile" "\n seed symmetryflag sparsityflag " "\n pivotingflag tau droptol nrhs " "\n nthread maptype cutoff lookahead" "\n msglvl -- message level" "\n msgFile -- message file" "\n mtxFile -- file to read in InpMtx matrix object" "\n etreeFile -- file to read in ETree front tree object" "\n seed -- random number seed" "\n symmetryflag -- symmetry flag" "\n 0 --> symmetric " "\n 1 --> hermitian" "\n 2 --> nonsymmetric" "\n sparsityflag -- sparsity flag" "\n 0 --> store dense fronts" "\n 1 --> store sparse fronts, use droptol to drop entries" "\n pivotingflag -- pivoting flag" "\n 0 --> do not pivot" "\n 1 --> enable pivoting" "\n tau -- upper bound on factor entries" "\n used only with pivoting" "\n droptol -- lower bound on factor entries" "\n used only with sparse fronts" "\n nrhs -- # of right hand sides" "\n nthread -- number of threads" "\n maptype -- type of map from fronts to threads" "\n 1 --> wrap map" "\n 2 --> balanced map via a post-order traversal" "\n 3 --> subtree-subset map" "\n 4 --> domain decomposition map" "\n cutoff -- cutoff used for domain decomposition map" "\n 0 <= cutoff <= 1 used to define the multisector" "\n lookahead -- lookahead for controlling the parallelism" "\n", argv[0]) ; return(-1) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } mtxFileName = argv[3] ; etreeFileName = argv[4] ; seed = atoi(argv[5]) ; symmetryflag = atoi(argv[6]) ; sparsityflag = atoi(argv[7]) ; pivotingflag = atoi(argv[8]) ; tau = atof(argv[9]) ; droptol = atof(argv[10]) ; nrhs = atoi(argv[11]) ; nthread = atoi(argv[12]) ; maptype = atoi(argv[13]) ; cutoff = atof(argv[14]) ; lookahead = atoi(argv[15]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n mtxFileName -- %s" "\n etreeFileName -- %s" "\n seed -- %d" "\n symmetryflag -- %d" "\n sparsityflag -- %d" "\n pivotingflag -- %d" "\n tau -- %e" "\n droptol -- %e" "\n nrhs -- %d" "\n nthread -- %d" "\n maptype -- %d" "\n cutoff -- %f" "\n lookahead -- %d" "\n", argv[0], msglvl, argv[2], mtxFileName, etreeFileName, seed, symmetryflag, sparsityflag, pivotingflag, tau, droptol, nrhs, nthread, maptype, cutoff, lookahead) ; fflush(msgFile) ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ Drand_setDefaultFields(&drand) ; Drand_init(&drand) ; Drand_setSeed(&drand, seed) ; /* Drand_setUniform(&drand, 0.0, 1.0) ; */ Drand_setNormal(&drand, 0.0, 1.0) ; /* ------------------------- read in the InpMtx object ------------------------- */ if ( strcmp(mtxFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } mtxA = InpMtx_new() ; MARKTIME(t1) ; rc = InpMtx_readFromFile(mtxA, mtxFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in mtxA from file %s", t2 - t1, mtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from InpMtx_readFromFile(%p,%s)", rc, mtxA, mtxFileName) ; exit(-1) ; } type = mtxA->inputMode ; neqns = 1 + IVmax(mtxA->nent, InpMtx_ivec1(mtxA), &loc) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after reading InpMtx object from file %s", mtxFileName) ; if ( msglvl == 2 ) { InpMtx_writeStats(mtxA, msgFile) ; } else { InpMtx_writeForHumanEye(mtxA, msgFile) ; } fflush(msgFile) ; } if ( INPMTX_IS_BY_ROWS(mtxA) ) { fprintf(msgFile, "\n matrix coordinate type is rows") ; } else if ( INPMTX_IS_BY_COLUMNS(mtxA) ) { fprintf(msgFile, "\n matrix coordinate type is columns") ; } else if ( INPMTX_IS_BY_CHEVRONS(mtxA) ) { fprintf(msgFile, "\n matrix coordinate type is chevrons") ; } else { fprintf(msgFile, "\n\n, error, bad coordinate type") ; exit(-1) ; } if ( INPMTX_IS_RAW_DATA(mtxA) ) { fprintf(msgFile, "\n matrix storage mode is raw data\n") ; } else if ( INPMTX_IS_SORTED(mtxA) ) { fprintf(msgFile, "\n matrix storage mode is sorted\n") ; } else if ( INPMTX_IS_BY_VECTORS(mtxA) ) { fprintf(msgFile, "\n matrix storage mode is by vectors\n") ; } else { fprintf(msgFile, "\n\n, error, bad storage mode") ; exit(-1) ; } /* -------------------------------------------------------- generate the linear system 1. generate solution matrix and fill with random numbers 2. generate rhs matrix and fill with zeros 3. compute matrix-matrix multiply -------------------------------------------------------- */ MARKTIME(t1) ; mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, -1, neqns, nrhs, 1, neqns) ; DenseMtx_fillRandomEntries(mtxX, &drand) ; mtxB = DenseMtx_new() ; DenseMtx_init(mtxB, type, 1, -1, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxB) ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_mmm(mtxA, mtxB, one, mtxX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_mmm(mtxA, mtxB, one, mtxX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_mmm(mtxA, mtxB, one, mtxX) ; break ; default : break ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set up the solution and rhs ", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n original mtxX") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fprintf(msgFile, "\n\n original mtxB") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(etreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } frontETree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(frontETree, etreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in frontETree from file %s", t2 - t1, etreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, frontETree, etreeFileName) ; exit(-1) ; } ETree_leftJustify(frontETree) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after reading ETree object from file %s", etreeFileName) ; if ( msglvl == 2 ) { ETree_writeStats(frontETree, msgFile) ; } else { ETree_writeForHumanEye(frontETree, msgFile) ; } } fflush(msgFile) ; /* -------------------------------------------------- get the permutations, permute the matrix and the front tree, and compute the symbolic factorization -------------------------------------------------- */ MARKTIME(t1) ; oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : get permutations", t2 - t1) ; MARKTIME(t1) ; ETree_permuteVertices(frontETree, oldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute front tree", t2 - t1) ; MARKTIME(t1) ; InpMtx_permute(mtxA, IV_entries(oldToNewIV), IV_entries(oldToNewIV)) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute mtxA", t2 - t1) ; MARKTIME(t1) ; InpMtx_mapToUpperTriangle(mtxA) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : map to upper triangle", t2 - t1) ; if ( ! INPMTX_IS_BY_CHEVRONS(mtxA) ) { MARKTIME(t1) ; InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : change coordinate type", t2 - t1) ; } if ( INPMTX_IS_RAW_DATA(mtxA) ) { MARKTIME(t1) ; InpMtx_changeStorageMode(mtxA, INPMTX_SORTED) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : sort entries ", t2 - t1) ; } if ( INPMTX_IS_SORTED(mtxA) ) { MARKTIME(t1) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : convert to vectors ", t2 - t1) ; } MARKTIME(t1) ; symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : symbolic factorization", t2 - t1) ; MARKTIME(t1) ; DenseMtx_permuteRows(mtxB, oldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute rhs", t2 - t1) ; /* -------------------------------------------------- initialize the cumulative operations metric object -------------------------------------------------- */ cumopsDV = DV_new() ; DV_init(cumopsDV, nthread, NULL) ; DV_fill(cumopsDV, 0.0) ; /* ------------------------------- create the owners map IV object ------------------------------- */ switch ( maptype ) { case 1 : frontOwnersIV = ETree_wrapMap(frontETree, type, symmetryflag, cumopsDV) ; break ; case 2 : frontOwnersIV = ETree_balancedMap(frontETree, type, symmetryflag, cumopsDV) ; break ; case 3 : frontOwnersIV = ETree_subtreeSubsetMap(frontETree, type, symmetryflag, cumopsDV) ; break ; case 4 : frontOwnersIV = ETree_ddMap(frontETree, type, symmetryflag, cumopsDV, cutoff) ; break ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n totalOps = %.0f", DV_sum(cumopsDV)) ; DVscale(DV_size(cumopsDV), DV_entries(cumopsDV), nthread/DV_sum(cumopsDV)) ; fprintf(msgFile, "\n\n cumopsDV") ; DV_writeForHumanEye(cumopsDV, msgFile) ; } DV_free(cumopsDV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n frontOwnersIV") ; IV_writeForHumanEye(frontOwnersIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------ initialize the FrontMtx object ------------------------------ */ MARKTIME(t1) ; frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, LOCK_IN_PROCESS, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, sparsityflag, pivotingflag, LOCK_IN_PROCESS, 0, NULL, mtxmanager, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : initialize the front matrix", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n nendD = %d, nentL = %d, nentU = %d", frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n front matrix initialized") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; /* ----------------- factor the matrix ----------------- */ nzf = ETree_nFactorEntries(frontETree, symmetryflag) ; factorops = ETree_nFactorOps(frontETree, type, symmetryflag) ; fprintf(msgFile, "\n %d factor entries, %.0f factor ops, %8.3f ratio", nzf, factorops, factorops/nzf) ; IVzero(16, stats) ; DVzero(11, cpus) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, LOCK_IN_PROCESS, 1) ; MARKTIME(t1) ; error = -1 ; rootchv = FrontMtx_MT_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, frontOwnersIV, lookahead, &error, cpus, stats, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : factor matrix, %8.3f mflops", t2 - t1, 1.e-6*factorops/(t2-t1)) ; if ( rootchv != NULL ) { fprintf(msgFile, "\n\n factorization did not complete") ; for ( chv = rootchv ; chv != NULL ; chv = chv->next ) { fprintf(stdout, "\n chv %d, nD = %d, nL = %d, nU = %d", chv->id, chv->nD, chv->nL, chv->nU) ; } } if ( error >= 0 ) { fprintf(msgFile, "\n\n error encountered at front %d\n", error) ; exit(-1) ; } fprintf(msgFile, "\n %8d pivots, %8d pivot tests, %8d delayed rows and columns", stats[0], stats[1], stats[2]) ; if ( frontmtx->rowadjIVL != NULL ) { fprintf(msgFile, "\n %d entries in rowadjIVL", frontmtx->rowadjIVL->tsize) ; } if ( frontmtx->coladjIVL != NULL ) { fprintf(msgFile, ", %d entries in coladjIVL", frontmtx->coladjIVL->tsize) ; } if ( frontmtx->upperblockIVL != NULL ) { fprintf(msgFile, "\n %d fronts, %d entries in upperblockIVL", frontmtx->nfront, frontmtx->upperblockIVL->tsize) ; } if ( frontmtx->lowerblockIVL != NULL ) { fprintf(msgFile, ", %d entries in lowerblockIVL", frontmtx->lowerblockIVL->tsize) ; } fprintf(msgFile, "\n %d entries in D, %d entries in L, %d entries in U", stats[3], stats[4], stats[5]) ; fprintf(msgFile, "\n %d locks", frontmtx->nlocks) ; cputotal = cpus[10] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n manage working storage %8.3f %6.2f" "\n initialize/load fronts %8.3f %6.2f" "\n update fronts %8.3f %6.2f" "\n aggregate insert %8.3f %6.2f" "\n aggregate remove/add %8.3f %6.2f" "\n assemble postponed data %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n extract postponed data %8.3f %6.2f" "\n store factor entries %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[6], 100.*cpus[6]/cputotal, cpus[7], 100.*cpus[7]/cputotal, cpus[8], 100.*cpus[8]/cputotal, cpus[9], 100.*cpus[9]/cputotal, cputotal) ; } SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; ChvManager_writeForHumanEye(chvmanager, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } /* ------------------------------ post-process the factor matrix ------------------------------ */ MARKTIME(t1) ; FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : post-process the matrix", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } fprintf(msgFile, "\n\n after post-processing") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ---------------- solve the system ---------------- */ neqns = mtxB->nrow ; nrhs = mtxB->ncol ; mtxZ = DenseMtx_new() ; DenseMtx_init(mtxZ, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxZ) ; if ( type == SPOOLES_REAL ) { nops = frontmtx->nentD + 2*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 2*frontmtx->nentL ; } else { nops += 2*frontmtx->nentU ; } } else if ( type == SPOOLES_COMPLEX ) { nops = 8*frontmtx->nentD + 8*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 8*frontmtx->nentL ; } else { nops += 8*frontmtx->nentU ; } } nops *= nrhs ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DVzero(6, cpus) ; MARKTIME(t1) ; FrontMtx_solve(frontmtx, mtxZ, mtxB, mtxmanager, cpus, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : solve the system, %.3f mflops", t2 - t1, 1.e-6*nops/(t2 - t1)) ; cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } /* ------------------------------------------------------------- permute the computed solution back into the original ordering ------------------------------------------------------------- */ MARKTIME(t1) ; DenseMtx_permuteRows(mtxZ, newToOldIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute solution", t2 - t1) ; /* ----------------- compute the error ----------------- */ DenseMtx_sub(mtxZ, mtxX) ; fprintf(msgFile, "\n\n maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n after solve") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ---------------------------- solve the system in parallel ---------------------------- */ solvemap = SolveMap_new() ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) && FRONTMTX_IS_PIVOTING(frontmtx) ) { SolveMap_ddMap(solvemap, SPOOLES_NONSYMMETRIC, FrontMtx_upperBlockIVL(frontmtx), FrontMtx_lowerBlockIVL(frontmtx), nthread, frontOwnersIV, frontmtx->tree, seed, msglvl, msgFile) ; } else { SolveMap_ddMap(solvemap, SPOOLES_SYMMETRIC, FrontMtx_upperBlockIVL(frontmtx), NULL, nthread, frontOwnersIV, frontmtx->tree, seed, msglvl, msgFile) ; } fprintf(msgFile, "\n solve map created") ; fflush(msgFile) ; neqns = mtxB->nrow ; nrhs = mtxB->ncol ; DenseMtx_zero(mtxZ) ; if ( type == SPOOLES_REAL ) { nops = frontmtx->nentD + 2*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 2*frontmtx->nentL ; } else { nops += 2*frontmtx->nentU ; } } else if ( type == SPOOLES_COMPLEX ) { nops = 8*frontmtx->nentD + 8*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 8*frontmtx->nentL ; } else { nops += 8*frontmtx->nentU ; } } nops *= nrhs ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DVzero(6, cpus) ; MARKTIME(t1) ; FrontMtx_MT_solve(frontmtx, mtxZ, mtxB, mtxmanager, solvemap, cpus, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : solve the system, %.3f mflops", t2 - t1, 1.e-6*nops/(t2 - t1)) ; cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } /* ------------------------------------------------------------- permute the computed solution back into the original ordering ------------------------------------------------------------- */ MARKTIME(t1) ; DenseMtx_permuteRows(mtxZ, newToOldIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute solution", t2 - t1) ; /* ----------------- compute the error ----------------- */ DenseMtx_sub(mtxZ, mtxX) ; fprintf(msgFile, "\n\n maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n after solve") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ------------------------ free the working storage ------------------------ */ IV_free(oldToNewIV) ; IV_free(newToOldIV) ; IV_free(frontOwnersIV) ; InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxB) ; DenseMtx_free(mtxZ) ; FrontMtx_free(frontmtx) ; ETree_free(frontETree) ; IVL_free(symbfacIVL) ; ChvManager_free(chvmanager) ; SubMtxManager_free(mtxmanager) ; SolveMap_free(solvemap) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ fprintf(msgFile, "\n\n CPU %8.3f : initialize the front matrix", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n nendD = %d, nentL = %d, nentU = %d", frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n front matrix initialized") ; MT/drivers/testGridMT.c010064400020550007177000000404710661663217700163050ustar00clevecompmath00000400000006/* testGridMT.c */ #include "../spoolesMT.h" #include "../../FrontMtx.h" #include "../../SolveMap.h" #include "../../SymbFac.h" #include "../../Drand.h" #include "../../timings.h" #include "../../misc.h" /*--------------------------------------------------------------------*/ /* void mkNDlinsys ( int n1, int n2, int n3, int maxzeros, int maxsize, int type, int symmetryflag, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB ) ; */ /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------------- test the factor method for a grid matrix (1) construct a linear system for a nested dissection ordering on a regular grid (2) create a solution matrix object (3) multiply the solution with the matrix to get a right hand side matrix object (4) factor the matrix (5) solve the system created -- 98may16, cca ----------------------------------------------------- */ { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxB, *mtxX, *mtxZ ; FrontMtx *frontmtx ; InpMtx *mtxA ; SubMtxManager *mtxmanager ; double cputotal, cutoff, droptol, factorops ; double cpus[11] ; Drand drand ; double nops, tau, t1, t2 ; DV *cumopsDV ; ETree *frontETree ; FILE *msgFile ; int error, lookahead, maptype, maxsize, maxzeros, msglvl, neqns, n1, n2, n3, nrhs, nthread, nzf, pivotingflag, seed, sparsityflag, symmetryflag, type ; int stats[16] ; IV *frontOwnersIV ; IVL *symbfacIVL ; SolveMap *solvemap ; if ( argc != 20 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 maxzeros maxsize" "\n seed type symmetryflag sparsityflag pivotingflag " "\n tau droptol nrhs nthread maptype cutoff lookahead" "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- number of grid points in the first direction" "\n n2 -- number of grid points in the second direction" "\n n3 -- number of grid points in the third direction" "\n maxzeros -- max number of zeroes in a front" "\n maxsize -- max number of internal nodes in a front" "\n seed -- random number seed" "\n type -- type of entries" "\n 1 --> real entries" "\n 2 --> complex entries" "\n symmetryflag -- symmetry flag" "\n 0 --> symmetric" "\n 1 --> hermitian" "\n 2 --> nonsymmetric" "\n sparsityflag -- sparsity flag" "\n 0 --> store dense fronts" "\n 1 --> store sparse fronts, use droptol to drop entries" "\n pivotingflag -- pivoting flag" "\n 0 --> do not pivot" "\n 1 --> enable pivoting" "\n tau -- upper bound on factor entries" "\n used only with pivoting" "\n droptol -- lower bound on factor entries" "\n used only with sparse fronts" "\n nrhs -- # of right hand sides" "\n nthread -- number of threads" "\n maptype -- type of map from fronts to threads" "\n 1 --> wrap map" "\n 2 --> balanced map via a post-order traversal" "\n 3 --> subtree-subset map" "\n 4 --> domain decomposition map" "\n cutoff -- cutoff used for domain decomposition map" "\n 0 <= cutoff <= 1 used to define the multisector" "\n lookahead -- lookahead for controlling the parallelism" "\n", argv[0]) ; return(-1) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; n3 = atoi(argv[5]) ; maxzeros = atoi(argv[6]) ; maxsize = atoi(argv[7]) ; seed = atoi(argv[8]) ; type = atoi(argv[9]) ; symmetryflag = atoi(argv[10]) ; sparsityflag = atoi(argv[11]) ; pivotingflag = atoi(argv[12]) ; tau = atof(argv[13]) ; droptol = atof(argv[14]) ; nrhs = atoi(argv[15]) ; nthread = atoi(argv[16]) ; maptype = atoi(argv[17]) ; cutoff = atof(argv[18]) ; lookahead = atoi(argv[19]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n n1 -- %d" "\n n2 -- %d" "\n n3 -- %d" "\n maxzeros -- %d" "\n maxsize -- %d" "\n seed -- %d" "\n type -- %d" "\n symmetryflag -- %d" "\n sparsityflag -- %d" "\n pivotingflag -- %d" "\n tau -- %e" "\n droptol -- %e" "\n nrhs -- %d" "\n nthread -- %d" "\n maptype -- %d" "\n cutoff -- %f" "\n lookahead -- %d" "\n", argv[0], msglvl, argv[2], n1, n2, n3, maxzeros, maxsize, seed, type, symmetryflag, sparsityflag, pivotingflag, tau, droptol, nrhs, nthread, maptype, cutoff, lookahead); fflush(msgFile) ; neqns = n1 * n2 * n3 ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ Drand_setDefaultFields(&drand) ; Drand_init(&drand) ; Drand_setSeed(&drand, seed) ; /* Drand_setUniform(&drand, 0.0, 1.0) ; */ Drand_setNormal(&drand, 0.0, 1.0) ; /* -------------------------- generate the linear system -------------------------- */ mkNDlinsys(n1, n2, n3, maxzeros, maxsize, type, symmetryflag, nrhs, seed, msglvl, msgFile, &frontETree, &symbfacIVL, &mtxA, &mtxX, &mtxB) ; /* -------------------------------------------------- initialize the cumulative operations metric object -------------------------------------------------- */ cumopsDV = DV_new() ; DV_init(cumopsDV, nthread, NULL) ; DV_fill(cumopsDV, 0.0) ; /* ------------------------------- create the owners map IV object ------------------------------- */ switch ( maptype ) { case 1 : frontOwnersIV = ETree_wrapMap(frontETree, type, symmetryflag, cumopsDV) ; break ; case 2 : frontOwnersIV = ETree_balancedMap(frontETree, type, symmetryflag, cumopsDV) ; break ; case 3 : frontOwnersIV = ETree_subtreeSubsetMap(frontETree, type, symmetryflag, cumopsDV) ; break ; case 4 : frontOwnersIV = ETree_ddMap(frontETree, type, symmetryflag, cumopsDV, cutoff) ; break ; } if ( msglvl > 0 ) { fprintf(msgFile, "\n\n totalOps = %.0f", DV_sum(cumopsDV)) ; DVscale(DV_size(cumopsDV), DV_entries(cumopsDV), nthread/DV_sum(cumopsDV)) ; fprintf(msgFile, "\n\n cumopsDV") ; DV_writeForHumanEye(cumopsDV, msgFile) ; } DV_free(cumopsDV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n frontOwnersIV") ; IV_writeForHumanEye(frontOwnersIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------- initialize the FrontMtx object ------------------------------- */ MARKTIME(t1) ; frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, LOCK_IN_PROCESS, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, sparsityflag, pivotingflag, LOCK_IN_PROCESS, 0, NULL, mtxmanager, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the front matrix", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n nentD = %d, nentL = %d, nentU = %d", frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n front matrix initialized") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /* ----------------- factor the matrix ----------------- */ nzf = ETree_nFactorEntries(frontETree, symmetryflag) ; factorops = ETree_nFactorOps(frontETree, type, symmetryflag) ; fprintf(msgFile, "\n %d factor entries, %.0f factor ops, %8.3f ratio", nzf, factorops, factorops/nzf) ; IVzero(16, stats) ; DVzero(11, cpus) ; fprintf(msgFile, "\n\n starting the parallel factor") ; fflush(msgFile) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, LOCK_IN_PROCESS, 1) ; MARKTIME(t1) ; rootchv = FrontMtx_MT_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, frontOwnersIV, lookahead, &error, cpus, stats, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : factor matrix, %8.3f mflops", t2 - t1, 1.e-6*factorops/(t2-t1)) ; if ( rootchv != NULL ) { fprintf(msgFile, "\n\n factorization did not complete") ; for ( chv = rootchv ; chv != NULL ; chv = chv->next ) { fprintf(stdout, "\n chv %d, nD = %d, nL = %d, nU = %d", chv->id, chv->nD, chv->nL, chv->nU) ; } } if ( error >= 0 ) { fprintf(msgFile, "\n\n fatal error encountered at front %d", error) ; exit(-1) ; } fprintf(msgFile, "\n %8d pivots, %8d pivot tests, %8d delayed rows and columns", stats[0], stats[1], stats[2]) ; if ( frontmtx->rowadjIVL != NULL ) { fprintf(msgFile, "\n %d entries in rowadjIVL", frontmtx->rowadjIVL->tsize) ; } if ( frontmtx->coladjIVL != NULL ) { fprintf(msgFile, "\n %d entries in coladjIVL", frontmtx->coladjIVL->tsize) ; } if ( frontmtx->upperblockIVL != NULL ) { fprintf(msgFile, "\n %d fronts, %d entries in upperblockIVL", frontmtx->nfront, frontmtx->upperblockIVL->tsize) ; } if ( frontmtx->lowerblockIVL != NULL ) { fprintf(msgFile, ", %d entries in lowerblockIVL", frontmtx->lowerblockIVL->tsize) ; } fprintf(msgFile, "\n %d entries in D, %d entries in L, %d entries in U", stats[3], stats[4], stats[5]) ; fprintf(msgFile, "\n %d locks", frontmtx->nlocks) ; cputotal = cpus[10] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n manage working storage %8.3f %6.2f" "\n initialize/load fronts %8.3f %6.2f" "\n update fronts %8.3f %6.2f" "\n aggregate insert %8.3f %6.2f" "\n aggregate remove/add %8.3f %6.2f" "\n assemble postponed data %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n extract postponed data %8.3f %6.2f" "\n store factor entries %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[6], 100.*cpus[6]/cputotal, cpus[7], 100.*cpus[7]/cputotal, cpus[8], 100.*cpus[8]/cputotal, cpus[9], 100.*cpus[9]/cputotal, cputotal) ; } SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; ChvManager_writeForHumanEye(chvmanager, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } /* ------------------------------ post-process the factor matrix ------------------------------ */ MARKTIME(t1) ; FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : post-process the matrix", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } fprintf(msgFile, "\n\n after post-processing") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ---------------- solve the system ---------------- */ neqns = mtxB->nrow ; nrhs = mtxB->ncol ; mtxZ = DenseMtx_new() ; DenseMtx_init(mtxZ, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxZ) ; if ( type == SPOOLES_REAL ) { nops = frontmtx->nentD + 2*frontmtx->nentU ; if ( frontmtx->symmetryflag == 2 ) { nops += 2*frontmtx->nentL ; } else { nops += 2*frontmtx->nentU ; } } if ( type == SPOOLES_COMPLEX ) { nops = 8*frontmtx->nentD + 8*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 8*frontmtx->nentL ; } else { nops += 8*frontmtx->nentU ; } } nops *= nrhs ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DVzero(6, cpus) ; MARKTIME(t1) ; FrontMtx_solve(frontmtx, mtxZ, mtxB, mtxmanager, cpus, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : solve the system, %.3f mflops", t2 - t1, 1.e-6*nops/(t2 - t1)) ; cputotal = cpus[5] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DenseMtx_sub(mtxZ, mtxX) ; fprintf(msgFile, "\n\n serial maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n after solve") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* -------------------------------- now solve the system in parallel -------------------------------- */ solvemap = SolveMap_new() ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) && FRONTMTX_IS_PIVOTING(frontmtx) ) { SolveMap_ddMap(solvemap, SPOOLES_NONSYMMETRIC, FrontMtx_upperBlockIVL(frontmtx), FrontMtx_lowerBlockIVL(frontmtx), nthread, frontOwnersIV, frontmtx->tree, seed, msglvl, msgFile) ; } else { SolveMap_ddMap(solvemap, SPOOLES_SYMMETRIC, FrontMtx_upperBlockIVL(frontmtx), NULL, nthread, frontOwnersIV, frontmtx->tree, seed, msglvl, msgFile) ; } fprintf(msgFile, "\n solve map created") ; fflush(msgFile) ; DVzero(6, cpus) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DenseMtx_zero(mtxZ) ; MARKTIME(t1) ; FrontMtx_MT_solve(frontmtx, mtxZ, mtxB, mtxmanager, solvemap, cpus, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : solve the system, %.3f mflops", t2 - t1, 1.e-6*nops/(t2 - t1)) ; cputotal = cpus[5] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DenseMtx_sub(mtxZ, mtxX) ; fprintf(msgFile, "\n\n parallel maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n after solve") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ------------------------ free the working storage ------------------------ */ FrontMtx_free(frontmtx) ; ETree_free(frontETree) ; IV_free(frontOwnersIV) ; IVL_free(symbfacIVL) ; InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxB) ; DenseMtx_free(mtxZ) ; ChvManager_free(chvmanager) ; SubMtxManager_free(mtxmanager) ; SolveMap_free(solvemap) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(0) ; } /*--------------------------------------------------------------------*/ symmetryflag, cumopsDV) ; break ; case 2 : frontOwnersIV = ETree_balancedMap(frontETree, type, symmetryflag, cumopsDV) ; break ; caseMT/drivers/testMMM.c010064400020550007177000000331370657133652600156050ustar00clevecompmath00000400000006/* testMMM.c */ #include "../spoolesMT.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------------ generate a random matrix and test a matrix-matrix multiply method. the output is a matlab file to test correctness. created -- 98jan29, cca -------------------------------------------------------------------- */ { DenseMtx *X, *Y, *Y2 ; double alpha[2] ; double alphaImag, alphaReal, t1, t2 ; double *zvec ; Drand *drand ; int col, dataType, ii, msglvl, ncolA, nitem, nops, nrhs, nrowA, nrowX, nrowY, nthread, row, seed, storageMode, symflag, transposeflag ; int *colids, *rowids ; InpMtx *A ; FILE *msgFile ; if ( argc != 15 ) { fprintf(stdout, "\n\n %% usage : %s msglvl msgFile symflag storageMode " "\n %% nrow ncol nent nrhs seed alphaReal alphaImag nthread" "\n %% msglvl -- message level" "\n %% msgFile -- message file" "\n %% dataType -- type of matrix entries" "\n %% 1 -- real" "\n %% 2 -- complex" "\n %% symflag -- symmetry flag" "\n %% 0 -- symmetric" "\n %% 1 -- hermitian" "\n %% 2 -- nonsymmetric" "\n %% storageMode -- storage mode" "\n %% 1 -- by rows" "\n %% 2 -- by columns" "\n %% 3 -- by chevrons, (requires nrow = ncol)" "\n %% transpose -- transpose flag" "\n %% 0 -- Y := Y + alpha * A * X" "\n %% 1 -- Y := Y + alpha * A^H * X, nonsymmetric only" "\n %% 2 -- Y := Y + alpha * A^T * X, nonsymmetric only" "\n %% nrowA -- number of rows in A" "\n %% ncolA -- number of columns in A" "\n %% nitem -- number of items" "\n %% nrhs -- number of right hand sides" "\n %% seed -- random number seed" "\n %% alphaReal -- y := y + alpha*A*x" "\n %% alphaImag -- y := y + alpha*A*x" "\n %% nthread -- # of threads" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } dataType = atoi(argv[3]) ; symflag = atoi(argv[4]) ; storageMode = atoi(argv[5]) ; transposeflag = atoi(argv[6]) ; nrowA = atoi(argv[7]) ; ncolA = atoi(argv[8]) ; nitem = atoi(argv[9]) ; nrhs = atoi(argv[10]) ; seed = atoi(argv[11]) ; alphaReal = atof(argv[12]) ; alphaImag = atof(argv[13]) ; nthread = atoi(argv[14]) ; fprintf(msgFile, "\n %% %s " "\n %% msglvl -- %d" "\n %% msgFile -- %s" "\n %% dataType -- %d" "\n %% symflag -- %d" "\n %% storageMode -- %d" "\n %% transposeflag -- %d" "\n %% nrowA -- %d" "\n %% ncolA -- %d" "\n %% nitem -- %d" "\n %% nrhs -- %d" "\n %% seed -- %d" "\n %% alphaReal -- %e" "\n %% alphaImag -- %e" "\n %% nthread -- %d" "\n", argv[0], msglvl, argv[2], dataType, symflag, storageMode, transposeflag, nrowA, ncolA, nitem, nrhs, seed, alphaReal, alphaImag, nthread) ; fflush(msgFile) ; if ( dataType != 1 && dataType != 2 ) { fprintf(stderr, "\n invalid value %d for dataType\n", dataType) ; exit(-1) ; } if ( symflag != 0 && symflag != 1 && symflag != 2 ) { fprintf(stderr, "\n invalid value %d for symflag\n", symflag) ; exit(-1) ; } if ( storageMode != 1 && storageMode != 2 && storageMode != 3 ) { fprintf(stderr, "\n invalid value %d for storageMode\n", storageMode) ; exit(-1) ; } if ( transposeflag < 0 || transposeflag > 2 ) { fprintf(stderr, "\n error, transposeflag = %d, must be 0, 1 or 2", transposeflag) ; exit(-1) ; } if ( (transposeflag == 1 && symflag != 2) || (transposeflag == 2 && symflag != 2) ) { fprintf(stderr, "\n error, transposeflag = %d, symflag = %d", transposeflag, symflag) ; exit(-1) ; } if ( transposeflag == 1 && dataType != 2 ) { fprintf(stderr, "\n error, transposeflag = %d, dataType = %d", transposeflag, dataType) ; exit(-1) ; } if ( symflag == 1 && dataType != 2 ) { fprintf(stderr, "\n symflag = 1 (hermitian), dataType != 2 (complex)") ; exit(-1) ; } if ( nrowA <= 0 || ncolA <= 0 || nitem <= 0 ) { fprintf(stderr, "\n invalid value: nrow = %d, ncol = %d, nitem = %d", nrowA, ncolA, nitem) ; exit(-1) ; } if ( symflag < 2 && nrowA != ncolA ) { fprintf(stderr, "\n invalid data: symflag = %d, nrow = %d, ncol = %d", symflag, nrowA, ncolA) ; exit(-1) ; } alpha[0] = alphaReal ; alpha[1] = alphaImag ; /* ---------------------------- initialize the matrix object ---------------------------- */ A = InpMtx_new() ; InpMtx_init(A, storageMode, dataType, 0, 0) ; drand = Drand_new() ; /* ---------------------------------- generate a vector of nitem triples ---------------------------------- */ rowids = IVinit(nitem, -1) ; Drand_setUniform(drand, 0, nrowA) ; Drand_fillIvector(drand, nitem, rowids) ; colids = IVinit(nitem, -1) ; Drand_setUniform(drand, 0, ncolA) ; Drand_fillIvector(drand, nitem, colids) ; Drand_setUniform(drand, 0.0, 1.0) ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { zvec = DVinit(nitem, 0.0) ; Drand_fillDvector(drand, nitem, zvec) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { zvec = ZVinit(nitem, 0.0, 0.0) ; Drand_fillDvector(drand, 2*nitem, zvec) ; } /* ----------------------------------- assemble the entries entry by entry ----------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n A = zeros(%d,%d) ;", nrowA, ncolA) ; } if ( symflag == 1 ) { /* ---------------- hermitian matrix ---------------- */ for ( ii = 0 ; ii < nitem ; ii++ ) { if ( rowids[ii] == colids[ii] ) { zvec[2*ii+1] = 0.0 ; } if ( rowids[ii] <= colids[ii] ) { row = rowids[ii] ; col = colids[ii] ; } else { row = colids[ii] ; col = rowids[ii] ; } InpMtx_inputComplexEntry(A, row, col, zvec[2*ii], zvec[2*ii+1]) ; } } else if ( symflag == 0 ) { /* ---------------- symmetric matrix ---------------- */ if ( INPMTX_IS_REAL_ENTRIES(A) ) { for ( ii = 0 ; ii < nitem ; ii++ ) { if ( rowids[ii] <= colids[ii] ) { row = rowids[ii] ; col = colids[ii] ; } else { row = colids[ii] ; col = rowids[ii] ; } InpMtx_inputRealEntry(A, row, col, zvec[ii]) ; } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { for ( ii = 0 ; ii < nitem ; ii++ ) { if ( rowids[ii] <= colids[ii] ) { row = rowids[ii] ; col = colids[ii] ; } else { row = colids[ii] ; col = rowids[ii] ; } InpMtx_inputComplexEntry(A, row, col, zvec[2*ii], zvec[2*ii+1]) ; } } } else { /* ------------------- nonsymmetric matrix ------------------- */ if ( INPMTX_IS_REAL_ENTRIES(A) ) { for ( ii = 0 ; ii < nitem ; ii++ ) { InpMtx_inputRealEntry(A, rowids[ii], colids[ii], zvec[ii]) ; } } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { for ( ii = 0 ; ii < nitem ; ii++ ) { InpMtx_inputComplexEntry(A, rowids[ii], colids[ii], zvec[2*ii], zvec[2*ii+1]) ; } } } InpMtx_changeStorageMode(A, INPMTX_BY_VECTORS) ; DVfree(zvec) ; if ( symflag == 0 || symflag == 1 ) { if ( INPMTX_IS_REAL_ENTRIES(A) ) { nops = 4*A->nent*nrhs ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { nops = 16*A->nent*nrhs ; } } else { if ( INPMTX_IS_REAL_ENTRIES(A) ) { nops = 2*A->nent*nrhs ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { nops = 8*A->nent*nrhs ; } } if ( msglvl > 1 ) { /* ------------------------------------------- write the assembled matrix to a matlab file ------------------------------------------- */ InpMtx_writeForMatlab(A, "A", msgFile) ; if ( symflag == 0 ) { fprintf(msgFile, "\n for k = 1:%d" "\n for j = k+1:%d" "\n A(j,k) = A(k,j) ;" "\n end" "\n end", nrowA, ncolA) ; } else if ( symflag == 1 ) { fprintf(msgFile, "\n for k = 1:%d" "\n for j = k+1:%d" "\n A(j,k) = ctranspose(A(k,j)) ;" "\n end" "\n end", nrowA, ncolA) ; } } /* ------------------------------- generate dense matrices X and Y ------------------------------- */ if ( transposeflag == 0 ) { nrowX = ncolA ; nrowY = nrowA ; } else { nrowX = nrowA ; nrowY = ncolA ; } X = DenseMtx_new() ; Y = DenseMtx_new() ; Y2 = DenseMtx_new() ; if ( INPMTX_IS_REAL_ENTRIES(A) ) { DenseMtx_init(X, SPOOLES_REAL, 0, 0, nrowX, nrhs, 1, nrowX) ; Drand_fillDvector(drand, nrowX*nrhs, DenseMtx_entries(X)) ; DenseMtx_init(Y, SPOOLES_REAL, 0, 0, nrowY, nrhs, 1, nrowY) ; Drand_fillDvector(drand, nrowY*nrhs, DenseMtx_entries(Y)) ; DenseMtx_init(Y2, SPOOLES_REAL, 0, 0, nrowY, nrhs, 1, nrowY) ; DVcopy(nrowY*nrhs, DenseMtx_entries(Y2), DenseMtx_entries(Y)) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(A) ) { DenseMtx_init(X, SPOOLES_COMPLEX, 0, 0, nrowX, nrhs, 1, nrowX) ; Drand_fillDvector(drand, 2*nrowX*nrhs, DenseMtx_entries(X)) ; DenseMtx_init(Y, SPOOLES_COMPLEX, 0, 0, nrowY, nrhs, 1, nrowY) ; Drand_fillDvector(drand, 2*nrowY*nrhs, DenseMtx_entries(Y)) ; DenseMtx_init(Y2, SPOOLES_COMPLEX, 0, 0, nrowY, nrhs, 1, nrowY) ; DVcopy(2*nrowY*nrhs, DenseMtx_entries(Y2), DenseMtx_entries(Y)) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, nrhs) ; DenseMtx_writeForMatlab(X, "X", msgFile) ; fprintf(msgFile, "\n Y = zeros(%d,%d) ;", nrowY, nrhs) ; DenseMtx_writeForMatlab(Y, "Y", msgFile) ; } /* -------------------------------------------- perform the matrix-matrix multiply in serial -------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n alpha = %20.12e + %20.2e*i;", alpha[0], alpha[1]); fprintf(msgFile, "\n Z = zeros(%d,1) ;", nrowY) ; } if ( transposeflag == 0 ) { MARKTIME(t1) ; if ( symflag == 0 ) { InpMtx_sym_mmm(A, Y, alpha, X) ; } else if ( symflag == 1 ) { InpMtx_herm_mmm(A, Y, alpha, X) ; } else if ( symflag == 2 ) { InpMtx_nonsym_mmm(A, Y, alpha, X) ; } MARKTIME(t2) ; if ( msglvl > 1 ) { DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - Y - alpha*A*X) ") ; fprintf(msgFile, "\n") ; } } else if ( transposeflag == 1 ) { MARKTIME(t1) ; InpMtx_nonsym_mmm_H(A, Y, alpha, X) ; MARKTIME(t2) ; if ( msglvl > 1 ) { DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - Y - alpha*ctranspose(A)*X) ") ; fprintf(msgFile, "\n") ; } } else if ( transposeflag == 2 ) { MARKTIME(t1) ; InpMtx_nonsym_mmm_T(A, Y, alpha, X) ; MARKTIME(t2) ; if ( msglvl > 1 ) { DenseMtx_writeForMatlab(Y, "Z", msgFile) ; fprintf(msgFile, "\n maxerr = max(Z - Y - alpha*transpose(A)*X) ") ; fprintf(msgFile, "\n") ; } } fprintf(msgFile, "\n %% %d ops, %.3f time, %.3f serial mflops", nops, t2 - t1, 1.e-6*nops/(t2 - t1)) ; /* -------------------------------------------------------- perform the matrix-matrix multiply in multithreaded mode -------------------------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n alpha = %20.12e + %20.2e*i;", alpha[0], alpha[1]); fprintf(msgFile, "\n Z = zeros(%d,1) ;", nrowY) ; } if ( transposeflag == 0 ) { MARKTIME(t1) ; if ( symflag == 0 ) { InpMtx_MT_sym_mmm(A, Y2, alpha, X, nthread, msglvl, msgFile) ; } else if ( symflag == 1 ) { InpMtx_MT_herm_mmm(A, Y2, alpha, X, nthread, msglvl, msgFile) ; } else if ( symflag == 2 ) { InpMtx_MT_nonsym_mmm(A, Y2, alpha, X, nthread, msglvl, msgFile) ; } MARKTIME(t2) ; if ( msglvl > 1 ) { DenseMtx_writeForMatlab(Y2, "Z2", msgFile) ; fprintf(msgFile, "\n maxerr2 = max(Z2 - Y - alpha*A*X) ") ; fprintf(msgFile, "\n") ; } } else if ( transposeflag == 1 ) { MARKTIME(t1) ; InpMtx_MT_nonsym_mmm_H(A, Y2, alpha, X, nthread, msglvl, msgFile) ; MARKTIME(t2) ; if ( msglvl > 1 ) { DenseMtx_writeForMatlab(Y2, "Z2", msgFile) ; fprintf(msgFile, "\n maxerr2 = max(Z2 - Y - alpha*ctranspose(A)*X) ") ; fprintf(msgFile, "\n") ; } } else if ( transposeflag == 2 ) { MARKTIME(t1) ; InpMtx_MT_nonsym_mmm_T(A, Y2, alpha, X, nthread, msglvl, msgFile) ; MARKTIME(t2) ; if ( msglvl > 1 ) { DenseMtx_writeForMatlab(Y2, "Z2", msgFile) ; fprintf(msgFile, "\n maxerr2 = max(Z2 - Y - alpha*transpose(A)*X) ") ; fprintf(msgFile, "\n") ; } } fprintf(msgFile, "\n %% %d ops, %.3f time, %.3f MT mflops", nops, t2 - t1, 1.e-6*nops/(t2 - t1)) ; /* ------------------------ free the working storage ------------------------ */ InpMtx_free(A) ; DenseMtx_free(X) ; DenseMtx_free(Y) ; DenseMtx_free(Y2) ; IVfree(rowids) ; IVfree(colids) ; Drand_free(drand) ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ) { fprintf(stderr, "\n invalid value %d for dataType\n", dataType) ; exit(-1) ; } if ( symflag != 0 && symflag != 1 && symflag != 2 ) { fprintf(stderr, "\n invalid value %d for symflag\n", symflag) ; exit(-1) ; } if ( storageMode != 1 && storageMode != 2 && storageMode != 3 ) { fprintf(stderr, "\n invalid value %d for storageMode\n", storageMode) ; exit(-1) ; } if ( transposeflag < 0MT/drivers/testQRgridMT.c010064400020550007177000000316540665165543400166130ustar00clevecompmath00000400000006/* testQRgridMT.c */ #include "../spoolesMT.h" #include "../../FrontMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ void mkNDlinsysQR ( int n1, int n2, int n3, int type, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB) ; /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------- test the QR factor method for a FrontMtx object on an n1 x n2 x n3 grid (1) generate an overdetermined system AX = B (2) factor the matrix (3) solve the systems created -- 98may29, cca --------------------------------------------------- */ { ChvManager *chvmanager ; DenseMtx *mtxB, *mtxX, *mtxZ ; double cputotal, cutoff, factorops ; double cpus[10] ; double nops, t1, t2 ; DV *cumopsDV ; ETree *frontETree ; FILE *msgFile ; FrontMtx *frontmtx ; InpMtx *mtxA ; int maptype, msglvl, neqns, nrhs, nthread, n1, n2, n3, seed, type ; IV *frontOwnersIV ; IVL *symbfacIVL ; SolveMap *solvemap ; SubMtxManager *mtxmanager ; if ( argc != 12 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 seed nrhs type " "\n nthread maptype cutoff" "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- # of points in the first direction" "\n n2 -- # of points in the second direction" "\n n3 -- # of points in the third direction" "\n seed -- random number seed" "\n nrhs -- # of right hand sides" "\n type -- type of linear system" "\n 1 -- real" "\n 2 -- complex" "\n nthread -- number of threads" "\n maptype -- type of map from fronts to threads" "\n 1 --> wrap map" "\n 2 --> balanced map via a post-order traversal" "\n 3 --> subtree-subset map" "\n 4 --> domain decomposition map" "\n cutoff -- cutoff used for domain decomposition map" "\n 0 <= cutoff <= 1 used to define the multisector" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; n3 = atoi(argv[5]) ; seed = atoi(argv[6]) ; nrhs = atoi(argv[7]) ; type = atoi(argv[8]) ; nthread = atoi(argv[8]) ; maptype = atoi(argv[8]) ; cutoff = atoi(argv[8]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n n1 -- %d" "\n n2 -- %d" "\n n3 -- %d" "\n seed -- %d" "\n nrhs -- %d" "\n type -- %d" "\n nthread -- %d" "\n maptype -- %d" "\n cutoff -- %f" "\n", argv[0], msglvl, argv[2], n1, n2, n3, seed, nrhs, type, nthread, maptype, cutoff) ; fflush(msgFile) ; neqns = n1*n2*n3 ; if ( type != SPOOLES_REAL && type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error, type must be real or complex") ; exit(-1) ; } /* ------------------------------------------ generate the A X = B overdetermined system ------------------------------------------ */ mkNDlinsysQR(n1, n2, n3, type, nrhs, seed, msglvl, msgFile, &frontETree, &symbfacIVL, &mtxA, &mtxX, &mtxB) ; fprintf(msgFile, "\n\n %d entries in A", InpMtx_nent(mtxA)) ; /* -------------------------------------------------- initialize the cumulative operations metric object -------------------------------------------------- */ cumopsDV = DV_new() ; DV_init(cumopsDV, nthread, NULL) ; DV_fill(cumopsDV, 0.0) ; /* ------------------------------- create the owners map IV object ------------------------------- */ switch ( maptype ) { case 1 : frontOwnersIV = ETree_wrapMap(frontETree, type, SPOOLES_SYMMETRIC, cumopsDV) ; break ; case 2 : frontOwnersIV = ETree_balancedMap(frontETree, type, SPOOLES_SYMMETRIC, cumopsDV) ; break ; case 3 : frontOwnersIV = ETree_subtreeSubsetMap(frontETree, type, SPOOLES_SYMMETRIC, cumopsDV) ; break ; case 4 : frontOwnersIV = ETree_ddMap(frontETree, type, SPOOLES_SYMMETRIC, cumopsDV, cutoff) ; break ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n totalOps = %.0f", DV_sum(cumopsDV)) ; DVscale(DV_size(cumopsDV), DV_entries(cumopsDV), nthread/DV_sum(cumopsDV)) ; fprintf(msgFile, "\n\n cumopsDV") ; DV_writeForHumanEye(cumopsDV, msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n frontOwnersIV") ; IV_writeForHumanEye(frontOwnersIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------ initialize the FrontMtx object ------------------------------ */ MARKTIME(t1) ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, LOCK_IN_PROCESS, 0) ; frontmtx = FrontMtx_new() ; if ( type == SPOOLES_REAL ) { FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, SPOOLES_SYMMETRIC, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, LOCK_IN_PROCESS, 0, NULL, mtxmanager, msglvl, msgFile) ; } else if ( type == SPOOLES_COMPLEX ) { FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, SPOOLES_HERMITIAN, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, LOCK_IN_PROCESS, 0, NULL, mtxmanager, msglvl, msgFile) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the front matrix", t2 - t1) ; fprintf(msgFile, "\n\n %d entries in D, %d entries in U", frontmtx->nentD, frontmtx->nentU) ; /* ----------------- factor the matrix ----------------- */ DVzero(10, cpus) ; InpMtx_changeCoordType(mtxA, INPMTX_BY_ROWS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, LOCK_IN_PROCESS, 1) ; MARKTIME(t1) ; FrontMtx_MT_QR_factor(frontmtx, mtxA, chvmanager, frontOwnersIV, cpus, &factorops, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : FrontMtx_MT_QR_factor, %.0f ops, %.2f mflops", t2 - t1, factorops, 1.e-6*factorops/(t2-t1)) ; cputotal = cpus[6] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n" "\n CPU %%" "\n setup factorization %8.3f %6.2f" "\n setup fronts %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n store factor %8.3f %6.2f" "\n store update %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f" "\n wall clock time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[6], t2 - t1) ; } fprintf(msgFile, "\n\n ChvManager statistics") ; ChvManager_writeForHumanEye(chvmanager, msgFile) ; /* ------------------------------ post-process the factor matrix ------------------------------ */ MARKTIME(t1) ; FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : post-process the matrix", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n front factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } fprintf(msgFile, "\n\n after post-processing") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ---------------- solve the system ---------------- */ mtxZ = DenseMtx_new() ; DenseMtx_init(mtxZ, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxZ) ; if ( type == SPOOLES_REAL ) { nops = frontmtx->nentD + 2*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 2*frontmtx->nentL ; } else { nops += 2*frontmtx->nentU ; } } else if ( type == SPOOLES_COMPLEX ) { nops = 8*frontmtx->nentD + 8*frontmtx->nentU ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { nops += 8*frontmtx->nentL ; } else { nops += 8*frontmtx->nentU ; } } nops *= nrhs ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DVzero(7, cpus) ; MARKTIME(t1) ; FrontMtx_QR_solve(frontmtx, mtxA, mtxZ, mtxB, mtxmanager, cpus, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : serial solve, %d rhs, %.0f ops, %.3f mflops", t2 - t1, nrhs, nops, 1.e-6*nops/(t2 - t1)) ; cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n" "\n CPU %%" "\n A^TB matrix-matrix multiply %8.3f %6.2f" "\n total solve time %8.3f %6.2f" "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total QR solve time %8.3f", cpus[6], 100.*cpus[6]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n serial solve computed solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } /* ----------------- compute the error ----------------- */ DenseMtx_sub(mtxZ, mtxX) ; fprintf(msgFile, "\n\n serial solve: maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n after serial solve") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* -------------------------------- now solve the system in parallel -------------------------------- */ solvemap = SolveMap_new() ; SolveMap_ddMap(solvemap, SPOOLES_SYMMETRIC, FrontMtx_upperBlockIVL(frontmtx), NULL, nthread, frontOwnersIV, frontmtx->tree, seed, msglvl, msgFile) ; fprintf(msgFile, "\n solve map created") ; fflush(msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n rhs") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DenseMtx_zero(mtxZ) ; MARKTIME(t1) ; FrontMtx_MT_QR_solve(frontmtx, mtxA, mtxZ, mtxB, mtxmanager, solvemap, cpus, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : parallel solve, %d rhs, %.0f ops, %.3f mflops", t2 - t1, nrhs, nops, 1.e-6*nops/(t2 - t1)) ; cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n" "\n CPU %%" "\n A^TB matrix-matrix multiply %8.3f %6.2f" "\n total solve time %8.3f %6.2f" "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total QR solve time %8.3f", cpus[6], 100.*cpus[6]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n computed solution from parallel solve") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } /* ----------------- compute the error ----------------- */ DenseMtx_sub(mtxZ, mtxX) ; fprintf(msgFile, "\n\n parallel solve: maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n after parallel solve") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ------------------------ free the working storage ------------------------ */ InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxZ) ; DenseMtx_free(mtxB) ; FrontMtx_free(frontmtx) ; IVL_free(symbfacIVL) ; ETree_free(frontETree) ; SubMtxManager_free(mtxmanager) ; ChvManager_free(chvmanager) ; DV_free(cumopsDV) ; IV_free(frontOwnersIV) ; SolveMap_free(solvemap) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ sDV) ; break ; case 3 : frontOwnersIV = ETree_subtreeSubsetMap(frontETree, typMT/drivers/matrix.input010064400020550007177000000003070657405015600164640ustar00clevecompmath000004000000069 9 21 0 0 4.0 1 1 4.0 2 2 4.0 3 3 4.0 4 4 4.0 5 5 4.0 6 6 4.0 7 7 4.0 8 8 4.0 0 1 -1.0 1 2 -1.0 3 4 -1.0 4 5 -1.0 6 7 -1.0 7 8 -1.0 0 3 -1.0 1 4 -1.0 2 5 -1.0 3 6 -1.0 4 7 -1.0 5 8 -1.0 MT/drivers/rhs.input010064400020550007177000000001360657603021200157450ustar00clevecompmath000004000000069 2 0 0.0 1.0 1 0.0 0.0 2 0.0 0.0 3 0.0 0.0 4 1.0 0.0 5 0.0 0.0 6 0.0 0.0 7 0.0 0.0 8 0.0 0.0 MT/drivers/singularMatrix.input010064400020550007177000000022450657404765000202010ustar00clevecompmath00000400000006 13 13 27 0 0 1.7453333536783853E+08 0 3 -1.7453333536783853E+08 1 1 7.1828074095507547E+07 1 2 4.8483950014467597E+08 1 4 4.8483950014467597E+08 2 2 4.3635555013020830E+09 2 4 2.1817777506510420E+09 3 3 2.5440452273956126E+08 3 10 -7.9871187371722728E+07 4 4 6.3604368324064264E+09 4 11 -1.0153633886971237E+08 4 12 9.9844066555217147E+08 5 5 2.5440452273956126E+08 5 7 -1.7453333536783853E+08 5 10 -7.9871187371722728E+07 6 6 6.3604368324064264E+09 6 8 -4.8483950014467597E+08 6 9 2.1817777506510420E+09 6 11 1.0153633886971237E+08 6 12 9.9844066555217147E+08 7 7 1.7453333536783853E+08 8 8 7.1828074095507547E+07 8 9 -4.8483950014467597E+08 9 9 4.3635555013020830E+09 10 10 1.5974237474344546E+08 11 11 1.3767639168774558E+07 12 12 3.9937626622086864E+09 MT/drivers/singularRhs.input010064400020550007177000000007150657405024000174560ustar00clevecompmath00000400000006 13 1 0 .0000000000000000E+00 1 -2.6000000000000000E+04 2 .0000000000000000E+00 3 .0000000000000000E+00 4 .0000000000000000E+00 5 .0000000000000000E+00 6 .0000000000000000E+00 7 .0000000000000000E+00 8 -2.6000000000000000E+04 9 .0000000000000000E+00 10 .0000000000000000E+00 11 .0000000000000000E+00 12 .0000000000000000E+00 MT/doc/004275500020550007177000000000000665023217500131715ustar00clevecompmath00000400000006MT/doc/dataStructure.tex010064400020550007177000000003530657133652600165500ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:MT:dataStructure} \par There are no multithreaded specific data structures. See the {\tt Lock} object which is used to hide the particular mutual exclusion device used by a thread library. MT/doc/drivers.tex010064400020550007177000000357760657406261100154070ustar00clevecompmath00000400000006\par \section{Driver programs for the multithreaded functions} \label{section:MT:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} allInOneMT msglvl msgFile type symmetryflag pivotingflag matrixFileName rhsFileName seed nthread \end{verbatim} This driver program reads in a matrix $A$ and right hand side $B$, generates the graph for $A$ and orders the matrix, factors $A$ and solves the linear system $AX = B$ for $X$ using multithreaded factors and solves. Use the script file {\tt do\_gridMT} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter specifies a real or complex linear system. \begin{itemize} \item {\tt type = 1 (SPOOLES\_REAL)} for real, \item {\tt type = 2 (SPOOLES\_COMPLEX)} for complex. \end{itemize} \item The {\tt symmetryflag} parameter specifies the symmetry of the matrix. \begin{itemize} \item {\tt type = 0 (SPOOLES\_SYMMETRIC)} for $A$ real or complex symmetric, \item {\tt type = 1 (SPOOLES\_HERMITIAN)} for $A$ complex Hermitian, \item {\tt type = 2 (SPOOLES\_NONSYMMETRIC)} \end{itemize} for $A$ real or complex nonsymmetric. \item The {\tt pivotingflag} parameter signals whether pivoting for stability will be enabled or not. \begin{itemize} \item If {\tt pivotingflag = 0 (SPOOLES\_NO\_PIVOTING)}, no pivoting will be done. \item If {\tt pivotingflag = 1 (SPOOLES\_PIVOTING)}, pivoting will be done to ensure that all entries in $U$ and $L$ have magnitude less than {\tt tau}. \end{itemize} \item The {\tt matrixFileName} parameter is the name of the files where the matrix entries are read from. The file has the following structure. \begin{verbatim} neqns neqns nent irow jcol entry ... ... ... \end{verbatim} where {\tt neqns} is the global number of equations and {\tt nent} is the number of entries in this file. There follows {\tt nent} lines, each containing a row index, a column index and one or two floating point numbers, one if real, two if complex. \item The {\tt rhsFileName} parameter is the name of the files where the right hand side entries are read from. The file has the following structure. \begin{verbatim} nrow nrhs irow entry ... entry ... ... ... ... \end{verbatim} where {\tt nrow} is the number of rows in this file and {\tt nrhs} is the number of rigght and sides. There follows {\tt nrow} lines, each containing a row index and either {\tt nrhs} or {\tt 2*nrhs} floating point numbers, the first if real, the second if complex. \item The {\tt seed} parameter is a random number seed. \item The {\tt nthread} parameter is the number of threads. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} patchAndGoMT msglvl msgFile type symmetryflag patchAndGoFlag fudge toosmall storeids storevalues matrixFileName rhsFileName seed nthread \end{verbatim} This driver program is used to test the ``patch-and-go'' functionality for a factorization without pivoting. When small diagonal pivot elements are found, one of three actions are taken. See the {\tt PatchAndGoInfo} object for more information. \par The program reads in a matrix $A$ and right hand side $B$, generates the graph for $A$ and orders the matrix, factors $A$ and solves the linear system $AX = B$ for $X$ using multithreaded factors and solves. Use the script file {\tt do\_patchAndGo} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter specifies a real or complex linear system. \begin{itemize} \item {\tt type = 1 (SPOOLES\_REAL)} for real, \item {\tt type = 2 (SPOOLES\_COMPLEX)} for complex. \end{itemize} \item The {\tt symmetryflag} parameter specifies the symmetry of the matrix. \begin{itemize} \item {\tt type = 0 (SPOOLES\_SYMMETRIC)} for $A$ real or complex symmetric, \item {\tt type = 1 (SPOOLES\_HERMITIAN)} for $A$ complex Hermitian, \item {\tt type = 2 (SPOOLES\_NONSYMMETRIC)} \end{itemize} for $A$ real or complex nonsymmetric. \item The {\tt patchAndGoFlag} specifies the ``patch-and-go'' strategy. \begin{itemize} \item {\tt patchAndGoFlag = 0} --- if a zero pivot is detected, stop computing the factorization, set the error flag and return. \item {\tt patchAndGoFlag = 1} --- if a small or zero pivot is detected, set the diagonal entry to 1 and the offdiagonal entries to zero. \item {\tt patchAndGoFlag = 2} --- if a small or zero pivot is detected, perturb the diagonal entry. \end{itemize} \item The {\tt fudge} parameter is used to perturb a diagonal entry. \item The {\tt toosmall} parameter is judge when a diagonal entry is small. \item If {\tt storeids = 1}, then the locations where action was taken is stored in an {\tt IV} object. \item If {\tt storevalues = 1}, then the perturbations are stored in an {\tt DV} object. \item The {\tt matrixFileName} parameter is the name of the files where the matrix entries are read from. The file has the following structure. \begin{verbatim} neqns neqns nent irow jcol entry ... ... ... \end{verbatim} where {\tt neqns} is the global number of equations and {\tt nent} is the number of entries in this file. There follows {\tt nent} lines, each containing a row index, a column index and one or two floating point numbers, one if real, two if complex. \item The {\tt rhsFileName} parameter is the name of the files where the right hand side entries are read from. The file has the following structure. \begin{verbatim} nrow nrhs irow entry ... entry ... ... ... ... \end{verbatim} where {\tt nrow} is the number of rows in this file and {\tt nrhs} is the number of rigght and sides. There follows {\tt nrow} lines, each containing a row index and either {\tt nrhs} or {\tt 2*nrhs} floating point numbers, the first if real, the second if complex. \item The {\tt seed} parameter is a random number seed. \item The {\tt nthread} parameter is the number of threads. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testMMM msglvl msgFile dataType symflag storageMode transpose nrow ncol nitem nrhs seed alphaReal alphaImag nthread \end{verbatim} This driver program generates $A$, a ${\tt nrow} \times {\tt ncol}$ matrix using {\tt nitem} input entries, $X$ and $Y$, ${\tt nrow} \times {\tt nrhs}$ matrices, is filled with random numbers. It then computes $Y + \alpha*A*X$, $Y + \alpha*A^T*X$ or $Y + \alpha*A^H*X$. The program's output is a file which when sent into Matlab, outputs the error in the computation. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt InpMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt dataType} is the type of entries, {\tt 0} for real, {\tt 1} for complex. \item {\tt symflag} is the symmetry flag, {\tt 0} for symmetric, {\tt 1} for Hermitian, {\tt 2} for nonsymmetric. \item {\tt storageMode} is the storage mode for the entries, {\tt 1} for by rows, {\tt 2} for by columns, {\tt 3} for by chevrons. \item {\tt transpose} determines the equation, {\tt 0} for $Y + \alpha*A*X$, {\tt 1} for $Y + \alpha*A^T*X$ or {\tt 2} for $Y + \alpha*A^H*X$. \item {\tt nrowA} is the number of rows in $A$ \item {\tt ncolA} is the number of columns in $A$ \item {\tt nitem} is the number of matrix entries that are assembled into the matrix. \item {\tt nrhs} is the number of columns in $X$ and $Y$. \item The {\tt seed} parameter is a random number seed used to fill the matrix entries with random numbers. \item {\tt alphaReal} and {\tt alphaImag} form the scalar in the multiply. \item {\tt nthread} is the number of threads to use. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testGridMT msglvl msgFile n1 n2 n3 maxzeros maxsize seed type symmetryflag sparsityflag pivotingflag tau droptol nrhs nthread maptype cutoff lookahead \end{verbatim} This driver program tests the serial {\tt FrontMtx\_MT\_factor()} and {\tt FrontMtx\_MT\_solve()} methods for the linear system $AX = B$. The factorization and solve are done in parallel. Use the script file {\tt do\_gridMT} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt n1} is the number of points in the first grid direction. \item {\tt n2} is the number of points in the second grid direction. \item {\tt n3} is the number of points in the third grid direction. \item {\tt maxzeros} is used to merge small fronts together into larger fronts. Look at the {\tt ETree} object for the {\tt ETree\_mergeFronts\{One,All,Any\}()} methods. \item {\tt maxsize} is used to split large fronts into smaller fronts. See the {\tt ETree\_splitFronts()} method. \item The {\tt seed} parameter is a random number seed. \item The {\tt type} parameter specifies a real or complex linear system. \begin{itemize} \item {\tt type = 1 (SPOOLES\_REAL)} for real, \item {\tt type = 2 (SPOOLES\_COMPLEX)} for complex. \end{itemize} \item The {\tt symmetryflag} parameter specifies the symmetry of the matrix. \begin{itemize} \item {\tt type = 0 (SPOOLES\_SYMMETRIC)} for $A$ real or complex symmetric, \item {\tt type = 1 (SPOOLES\_HERMITIAN)} for $A$ complex Hermitian, \item {\tt type = 2 (SPOOLES\_NONSYMMETRIC)} \end{itemize} for $A$ real or complex nonsymmetric. \item The {\tt sparsityflag} parameter signals a direct or approximate factorization. \begin{itemize} \item {\tt sparsityflag = 0 (FRONTMTX\_DENSE\_FRONTS)} implies a direct factorization, the fronts will be stored as dense submatrices. \item {\tt sparsityflag = 1 (FRONTMTX\_SPARSE\_FRONTS)} implies an approximate factorization. The fronts will be stored as sparse submatrices, where the entries in the triangular factors will be subjected to a drop tolerance test --- if the magnitude of an entry is {\tt droptol} or larger, it will be stored, otherwise it will be dropped. \end{itemize} \item The {\tt pivotingflag} parameter signals whether pivoting for stability will be enabled or not. \begin{itemize} \item If {\tt pivotingflag = 0 (SPOOLES\_NO\_PIVOTING)}, no pivoting will be done. \item If {\tt pivotingflag = 1 (SPOOLES\_PIVOTING)}, pivoting will be done to ensure that all entries in $U$ and $L$ have magnitude less than {\tt tau}. \end{itemize} \item The {\tt tau} parameter is an upper bound on the magnitude of the entries in $L$ and $U$ when pivoting is enabled. \item The {\tt droptol} parameter is a lower bound on the magnitude of the entries in $L$ and $U$ when the approximate factorization is enabled. \item The {\tt nrhs} parameter is the number of right hand sides to solve as one block. \item The {\tt nthread} parameter is the number of threads. \item The {\tt maptype} parameter determines the type of map from fronts to processes to be used during the factorization \begin{itemize} \item 1 -- wrap map \item 2 -- balanced map \item 3 -- subtree-subset map \item 4 -- domain decomposition map \item 5 -- improved domain decomposition map \end{itemize} See the {\tt ETree} methods for constructing maps. \item The {\tt cutoff} parameter is used for domain decomposition maps. We try to construct domains (each domain is owned by a single thread) that contain $0 \le {\tt cutoff} \le 1$ of the rows and columns of the matrix. Try to choose {\tt cutoff} to be {\tt 1/nthread} or {\tt 1/(2*nthread)}. \item The {\tt lookahead} parameter controls the degree that a thread will look past a stalled front in order to do some useful work. {\t lookahead = 0} implies a thread will not look ahead, while {\tt lookahead = k} implies a thread will look {\tt k} ancestors up the front tree to find useful work. Bewarned, while a thread is doing useful work further up the tree, the stalled front may be ready, so large values of lookahead can be detrimental to a fast computation. In addition, a positive value of {\tt lookahead} means a larger storage footprint taken by the factorization. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testQRgridMT msglvl msgFile n1 n2 n3 seed nrhs type nthread maptype cutoff \end{verbatim} This driver program tests the serial {\tt FrontMtx\_QR\_factor()} and {\tt FrontMtx\_QR\_solve()} methods for the least squares problem $\min_X \| F - A X \|_F$. The factorization and solve are done in parallel. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt n1} is the number of points in the first grid direction. \item {\tt n2} is the number of points in the second grid direction. \item {\tt n3} is the number of points in the third grid direction. \item The {\tt seed} parameter is a random number seed. \item The {\tt nrhs} parameter is the number of right hand sides to solve as one block. \item The {\tt type} parameter specifies a real or complex linear system. \begin{itemize} \item {\tt type = 1 (SPOOLES\_REAL)} for real, \item {\tt type = 2 (SPOOLES\_COMPLEX)} for complex. \end{itemize} \item The {\tt nthread} parameter is the number of threads. \item The {\tt maptype} parameter determines the type of map from fronts to processes to be used during the factorization \begin{itemize} \item 1 -- wrap map \item 2 -- balanced map \item 3 -- subtree-subset map \item 4 -- domain decomposition map \item 5 -- improved domain decomposition map \end{itemize} See the {\tt ETree} methods for constructing maps. \item The {\tt cutoff} parameter is used for domain decomposition maps. We try to construct domains (each domain is owned by a single thread) that contain $0 \le {\tt cutoff} \le 1$ of the rows and columns of the matrix. Try to choose {\tt cutoff} to be {\tt 1/nthread} or {\tt 1/(2*nthread)}. \end{itemize} %----------------------------------------------------------------------- %----------------------------------------------------------------------- \end{enumerate} --MT/doc/intro.tex010064400020550007177000000065560657133652600150640ustar00clevecompmath00000400000006\chapter{{\tt MT} directory} \label{chapter:MT} \par All methods that use multithreaded function calls are found in this directory. Three functionalities are presently supported: matrix-matrix multiplies, sparse factorizations, and solves. \par The multithreaded methods to compute $Y := Y + \alpha A X$, $Y := Y + \alpha A^T X$ and $Y := Y + \alpha A^H X$ are simple. Their calling sequences are almost identical to their serial counterparts: global data structures for $Y$, $\alpha$, $A$ and $X$ are followed by the number of threads, a message level and file. Thread $q$ accesses part of $A$, part of $X$, and computes its own $Y^q = \alpha A X$ using those entries of $A$ that it is responsible for. This work is done independently by all threads. The global summation $Y := Y + \sum_q Y^q$ is done in serial mode by the calling process. \par This approach is not scalable. A better approach would be to explicitly partition $A$ into local $A^q$ matrices, and use local $X^q$ and $Y^q$ to hold rows of $X$ and $Y$ that have support with $A^q$, as is done with the distributed MPI matrix-matrix multiplies. (With MPI there is added complexity since $X$ and $Y$ are distributed among processors.) \par A matrix-matrix multiply does not exist in isolation. For example, a block shifted eigensolver requires factorizations of $A - \sigma B$ and multiplies using $A$ or $B$. The data structure for the matrix that takes part in the multiply needs to toggle back and for between its forms for the factor and multiply. Managing this in a distributed environment is actually easier than a multithreaded environment, for $A$ and $B$ are already distributed. Our multithreaded factorization expects $A$ and $B$ in global form. Insisting that $A$ and $B$ be partitioned as $A^q$ and $B^q$ matrices is too great a burden for the user that has no need for a multithreaded matrix-matrix multiply. Allowing the $A^q$ matrices to overlap or point into the global $A$ matrix in a persistent fashion is not cleanly possible, but requires changes to the {\tt InpMtx} object. \par In the future we intend to provide a scalable multithreaded matrix-matrix multiply. It requires a more in-depth consideration of the issues involved than we are able to give it at the present time. \par The multithreaded factorizations $A = LU$ and $A = QR$ are very similar to the serial factorizations, in both the calling sequence visible to the user and in the underlying code structure. The only additional parameters in the calling sequence is a map from the fronts to the threads that defines who does what computation, and a {\it lookahead} parameter that allows some ability to control and reduce the idle time during the factorization. Inside the code, the deterministic post-order traversal of the serial factorization is replaced by independent topological traversals of the front tree. It is the list and working storage data structures (the {\tt ChvList}, {\tt ChvManager} and {\tt SubMtxManager} objects) that have locks. {\it What} is done is common code between the serial and multithreaded environments, it is the choreography, i.e., {\it who} does what, that differs. \par Most of these same comments apply to the multithreaded solve methods. The calling sequences between the serial and multithreaded solves differs by one parameter, a {\tt SolveMap} object that maps the submatrices of the factor matrix to the threads that will compute with them. le. Their calling sequences are almost identical to their serial counterparts: global data structures for $Y$, $\alpha$, $A$ and $X$ are followedMT/doc/main.tex010064400020550007177000000014470665065627000146460ustar00clevecompmath00000400000006% % main TeX file % % \documentstyle[leqno,11pt,twoside]{report} \documentclass[leqno,10pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \newcommand\bnd[1]{\partial{#1}} \newcommand\WHILE{{\bf while}} \newcommand\IF{{\bf if}} \newcommand\END{{\bf end}} \newcommand\ELSE{{\bf else}} \newcommand\THEN{{\bf then}} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Multithreaded} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Multithreaded} : {\it DRAFT} \quad \today \hrulefill} \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} MT/doc/proto.tex010064400020550007177000000364470665022537100150670ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt MT} methods} \label{section:MT:proto} \par This section contains brief descriptions including prototypes of all methods found in the {\tt MT} source directory. \par \subsection{Matrix-matrix multiply methods} \label{subsection:MT:proto:mvm} \par There are five methods to multiply a vector times a dense matrix. The first three methods, called {\tt InpMtx\_MT\_nonsym\_mmm*()}, are straightforward, $y := y + \alpha A x$, where $A$ is nonsymmetric, and $\alpha$ is real (if $A$ is real) and complex (if $A$ is complex). The fourth method, {\tt InpMtx\_MT\_sym\_mmm()}, is used when the matrix is real symmetric or complex symmetric, though it is not necessary that only the lower or upper triangular entries are stored. (If one fills the {\tt InpMtx} object with only the entries in the lower triangle of $A$, and then permute the matrix $PAP^T$, the entries will not generally be found in only the lower or upper triangle. However, the code is still correct.) The last method, {\tt InpMtx\_MT\_herm\_mmm()}, is used when the matrix is complex hermitian. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_MT_nonsym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, int msgFile ) ; void InpMtx_MT_sym_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, int msgFile ) ; void InpMtx_MT_herm_mmm ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, int msgFile ) ; \end{verbatim} \index{InpMtx_MT_nonsym_mmm@{\tt InpMtx\_MT\_nonsym\_mmm()}} \index{InpMtx_MT_sym_mmm@{\tt InpMtx\_MT\_sym\_mmm()}} \index{InpMtx_MT_herm_mmm@{\tt InpMtx\_MT\_herm\_mmm()}} These methods compute the matrix-vector product $y := y + \alpha A x$, where $y$ is found in the {\tt Y DenseMtx} object, $\alpha$ is real or complex in {\tt alpha[]}, $A$ is found in the {\tt A Inpmtx} object, and $x$ is found in the {\tt X DenseMtx} object. If any of the input objects are {\tt NULL}, an error message is printed and the program exits. {\tt A}, {\tt X} and {\tt Y} must all be real or all be complex. When {\tt A} is real, then $\alpha$ = {\tt alpha[0]}. When {\tt A} is complex, then $\alpha$ = {\tt alpha[0]} + i* {\tt alpha[1]}. This means that one cannot call the methods with a constant as the third parameter, e.g., {\tt InpMtx\_MT\_nonsym\_mmm(A, Y, 3.22, X, nthread, msglvl, msgFile)}, for this may result in a segmentation violation. The values of $\alpha$ must be loaded into an array of length 1 or 2. The number of threads is specified by the {\tt nthread} parameter; if, {\tt nthread} is {\tt 1}, the serial method is called. The {\tt msglvl} and {\tt msgFile} parameters are used for diagnostics during the creation of the threads' individual data structures. \par \noindent {\it Error checking:} If {\tt A}, {\tt Y} or {\tt X} are {\tt NULL}, or if {\tt coordType} is not {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}, or if {\tt storageMode} is not one of {\tt INPMTX\_RAW\_DATA}, {\tt INPMTX\_SORTED} or {\tt INPMTX\_BY\_VECTORS}, or if {\tt inputMode} is not {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_MT_nonsym_mmm_T ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, int msgFile ) ; \end{verbatim} \index{InpMtx_MT_nonsym_mmm_T@{\tt InpMtx\_MT\_nonsym\_mm\_Tm()}} This method computes the matrix-vector product $y := y + \alpha A^T x$, where $y$ is found in the {\tt Y DenseMtx} object, $\alpha$ is real or complex in {\tt alpha[]}, $A$ is found in the {\tt A Inpmtx} object, and $x$ is found in the {\tt X DenseMtx} object. If any of the input objects are {\tt NULL}, an error message is printed and the program exits. {\tt A}, {\tt X} and {\tt Y} must all be real or all be complex. When {\tt A} is real, then $\alpha$ = {\tt alpha[0]}. When {\tt A} is complex, then $\alpha$ = {\tt alpha[0]} + i* {\tt alpha[1]}. This means that one cannot call the methods with a constant as the third parameter, e.g., {\tt InpMtx\_MT\_nonsym\_mmm(A, Y, 3.22, X, nthread, msglvl, msgFile)}, for this may result in a segmentation violation. The values of $\alpha$ must be loaded into an array of length 1 or 2. The number of threads is specified by the {\tt nthread} parameter; if, {\tt nthread} is {\tt 1}, the serial method is called. The {\tt msglvl} and {\tt msgFile} parameters are used for diagnostics during the creation of the threads' individual data structures. \par \noindent {\it Error checking:} If {\tt A}, {\tt Y} or {\tt X} are {\tt NULL}, or if {\tt coordType} is not {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}, or if {\tt storageMode} is not one of {\tt INPMTX\_RAW\_DATA}, {\tt INPMTX\_SORTED} or {\tt INPMTX\_BY\_VECTORS}, or if {\tt inputMode} is not {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void InpMtx_MT_nonsym_mmm_H ( InpMtx *A, DenseMtx *Y, double alpha[], DenseMtx *X, int nthread, int msglvl, int msgFile ) ; \end{verbatim} \index{InpMtx_MT_nonsym_mmm_H@{\tt InpMtx\_MT\_nonsym\_mmm\_H()}} This method computes the matrix-vector product $y := y + \alpha A^H x$, where $y$ is found in the {\tt Y DenseMtx} object, $\alpha$ is complex in {\tt alpha[]}, $A$ is found in the {\tt A Inpmtx} object, and $x$ is found in the {\tt X DenseMtx} object. If any of the input objects are {\tt NULL}, an error message is printed and the program exits. {\tt A}, {\tt X} and {\tt Y} must all be complex. The number of threads is specified by the {\tt nthread} parameter; if, {\tt nthread} is {\tt 1}, the serial method is called. The {\tt msglvl} and {\tt msgFile} parameters are used for diagnostics during the creation of the threads' individual data structures. \par \noindent {\it Error checking:} If {\tt A}, {\tt Y} or {\tt X} are {\tt NULL}, or if {\tt coordType} is not {\tt INPMTX\_BY\_ROWS}, {\tt INPMTX\_BY\_COLUMNS} or {\tt INPMTX\_BY\_CHEVRONS}, or if {\tt storageMode} is not one of {\tt INPMTX\_RAW\_DATA}, {\tt INPMTX\_SORTED} or {\tt INPMTX\_BY\_VECTORS}, or if {\tt inputMode} is not {\tt SPOOLES\_COMPLEX}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Multithreaded Factorization methods} \label{subsection:FrontMtx:proto:factorMT} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Chv * FrontMtx_MT_factorInpMtx ( FrontMtx *frontmtx, InpMtx *inpmtx, double tau, double droptol, ChvManager *chvmanager, IV *ownersIV, int lookahead, double cpus[], int stats[], int msglvl, FILE *msgFile ) ; Chv * FrontMtx_MT_factorPencil ( FrontMtx *frontmtx, Pencil *pencil, double tau, double droptol, ChvManager *chvmanager, IV *ownersIV, int lookahead, double cpus[], int stats[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_MT_factorInpMtx@{\tt FrontMtx\_MT\_factorInpMtx()}} \index{FrontMtx_MT_factorPencil@{\tt FrontMtx\_MT\_factorPencil()}} These two methods compute a multithreaded factorization for a matrix $A$ (stored in {\tt inpmtx}) or a matrix pencil $A + \sigma B$ (stored in {\tt pencil}). The {\tt tau} parameter is used when pivoting is enabled, each entry in $U$ and $L$ (when nonsymmetric) will have magnitude less than or equal to {\tt tau}. The {\tt droptol} parameter is used when the fronts are stored in a sparse format, each entry in $U$ and $L$ (when nonsymmetric) will have magnitude greater than or equal to {\tt droptol}. The map from fronts to owning processes is found in {\tt ownersIV}. The {\tt lookahead} parameter governs the ``upward--looking'' nature of the computations. Choosing {\tt lookahead = 0} is usually the most conservative with respect to working storage, while positive values increase the working storage and sometimes decrease the factorization time. On return, the {\tt cpus[]} vector is filled with the following information. \begin{itemize} \item {\tt cpus[0]} --- time spent managing working storage. \item {\tt cpus[1]} --- time spent initializing the fronts and loading the original entries. \item {\tt cpus[2]} --- time spent accumulating updates from descendents. \item {\tt cpus[3]} --- time spent inserting aggregate fronts. \item {\tt cpus[4]} --- time spent removing and assembling aggregate fronts. \item {\tt cpus[5]} --- time spent assembling postponed data. \item {\tt cpus[6]} --- time spent to factor the fronts. \item {\tt cpus[7]} --- time spent to extract postponed data. \item {\tt cpus[8]} --- time spent to store the factor entries. \item {\tt cpus[9]} --- miscellaneous time. \end{itemize} On return, the {\tt stats[]} vector is filled with the following information. \begin{itemize} \item {\tt stats[0]} --- number of pivots. \item {\tt stats[1]} --- number of pivot tests. \item {\tt stats[2]} --- number of delayed rows and columns. \item {\tt stats[3]} --- number of entries in $D$. \item {\tt stats[4]} --- number of entries in $L$. \item {\tt stats[5]} --- number of entries in $U$. \item {\tt stats[6]} --- number of locks of the {\tt FrontMtx} object. \item {\tt stats[7]} --- number of locks of aggregate list. \item {\tt stats[8]} --- number of locks of postponed list. \end{itemize} \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt inpmtxA}, {\tt cpus} or {\tt stats} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Multithreaded $QR$ Factorization method} \label{subsection:FrontMtx:proto:factorQR_MT} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void FrontMtx_MT_QR_factor ( FrontMtx *frontmtx, InpMtx *mtxA, ChvManager *chvmanager, IV *ownersIV, double cpus[], double *pfacops, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_MT_QR_factor@{\tt FrontMtx\_MT\_QR\_factor()}} This method computes the $(U^T+I)D(I+U)$ factorization of $A^TA$ if $A$ is real or $(U^H+I)D(I+U)$ factorization of $A^HA$ if $A$ is complex. The {\tt chvmanager} object manages the working storage. The map from fronts to threads is found in {\tt ownersIV}. On return, the {\tt cpus[]} vector is filled as follows. \begin{itemize} \item {\tt cpus[0]} -- time to set up the factorization. \item {\tt cpus[1]} -- time to set up the fronts. \item {\tt cpus[2]} -- time to factor the matrices. \item {\tt cpus[3]} -- time to scale and store the factor entries. \item {\tt cpus[4]} -- time to store the update entries \item {\tt cpus[5]} -- miscellaneous time \item {\tt cpus[6]} -- total time \end{itemize} On return, {\tt *pfacops} contains the number of floating point operations done by the factorization. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt frontJ} or {\tt chvmanager} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Multithreaded Solve method} \label{subsection:FrontMtx:proto:solve-multithreaded} \par \begin{enumerate} %======================================================================= \item \begin{verbatim} void FrontMtx_MT_solve ( FrontMtx *frontmtx, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, SolveMap *solvemap, double cpus[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_MT_solve@{\tt FrontMtx\_MT\_solve()}} This method is used to solve one of three linear systems of equations using a multithreaded solve --- $(U^T + I)D(I + U) X = B$, $(U^H + I)D(I + U) X = B$ or $(L + I)D(I + U) X = B$. Entries of $B$ are {\it read} from {\tt mtxB} and entries of $X$ are written to {\tt mtxX}. Therefore, {\tt mtxX} and {\tt mtxB} can be the same object. (Note, this does not hold true for an MPI factorization with pivoting.) The submatrix manager object manages the working storage. The {\tt solvemap} object contains the map from submatrices to threads. The map from fronts to processes that own them is given in the {\tt ownersIV} object. On return the {\tt cpus[]} vector is filled with the following. The {\tt stats[]} vector is not currently used. \begin{itemize} \item {\tt cpus[0]} --- set up the solves \item {\tt cpus[1]} --- fetch right hand side and store solution \item {\tt cpus[2]} --- forward solve \item {\tt cpus[3]} --- diagonal solve \item {\tt cpus[4]} --- backward solve \item {\tt cpus[5]} --- total time in the method. \end{itemize} \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt rhsmtx}, {\tt mtxmanager}, {\tt solvemap}, {\tt cpus} or {\tt stats} is {\tt NULL}, or if {\tt msglvl} > 0 and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Multithreaded $QR$ Solve method} \label{subsection:FrontMtx:proto:QRsolve-MT} \par \begin{enumerate} %======================================================================= \item \begin{verbatim} void FrontMtx_MT_QR_solve ( FrontMtx *frontmtx, InpMtx *mtxA, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, SolveMap *solvemap, double cpus[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{FrontMtx_MT_QR_solve@{\tt FrontMtx\_MT\_QR\_solve()}} This method is used to minimize $\|B - AX\|_F$, where $A$ is stored in {\tt mtxA}, $B$ is stored in {\tt mtxB}, and $X$ will be stored in {\tt mtxX}. The {\tt frontmtx} object contains a $(U^T+I)D(I+U)$ factorization of $A^TA$ if $A$ is real or $(U^H+I)D(I+U)$ factorization of $A^HA$ if $A$ is complex. We solve the seminormal equations $(U^T+I)D(I+U)X = A^TB$ or $(U^H+I)D(I+U)X = A^HB$ for $X$. On return the {\tt cpus[]} vector is filled with the following. \begin{itemize} \item {\tt cpus[0]} --- set up the solves \item {\tt cpus[1]} --- fetch right hand side and store solution \item {\tt cpus[2]} --- forward solve \item {\tt cpus[3]} --- diagonal solve \item {\tt cpus[4]} --- backward solve \item {\tt cpus[5]} --- total time in the solve method. \item {\tt cpus[6]} --- time to compute $A^TB$ or $A^HB$. \item {\tt cpus[7]} --- total time. \end{itemize} Only the solve is presently done in parallel. \par \noindent {\it Error checking:} If {\tt frontmtx}, {\tt mtxA}, {\tt mtxX}, {\tt mtxB}, {\tt mtxmanager}, {\tt solvemap} or {\tt cpus} is {\tt NULL}, or if {\tt msglvl} > 0 and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %======================================================================= \end{enumerate} MT/doc/solve.tex010064400020550007177000000237560657133652600150620ustar00clevecompmath00000400000006\section{{\tt DChvMtx}: Double Precision Chevron Matrix Object} \par Let $A$ be an $n \times n$ matrix to be factored. We are going to allow both row and column permutations as the factorization proceeds, and our pivot blocks may be larger than $1 \times 1$ pivots. After the first step we have $$ A = A_0 = P_0 \left \lbrack \begin{array}{cc} I & 0 \\ {\hat L}_0 & I \end{array} \right \rbrack \left \lbrack \begin{array}{cc} I & 0 \\ 0 & {\hat A}_1 \end{array} \right \rbrack \left \lbrack \begin{array}{cc} {\hat D}_0 & {\hat U}_0 \\ 0 & I \end{array} \right \rbrack Q_0 = P_0 \ L_0 \ A_1 \ U_0 \ Q_0 $$ where $P_0$ is the row permutation matrix, ${\hat D}_0$ is the pivot block, $\displaystyle L_0 = \left \lbrack \begin{array}{cc} I & 0 \\ {\hat L}_0 & I \end{array} \right \rbrack $, $\displaystyle A_1 = \left \lbrack \begin{array}{cc} I & 0 \\ 0 & {\hat A}_1 \end{array} \right \rbrack $, $\displaystyle U_0 = \left \lbrack \begin{array}{cc} {\hat D}_0 & {\hat U}_0 \\ 0 & I \end{array} \right \rbrack $ and $Q_0$ is the column permutation matrix. Now $A_1$ can be factored in the same manner, $$ A_1 = P_1 \left \lbrack \begin{array}{cc} I & 0 \\ {\hat L}_1 & I \end{array} \right \rbrack \left \lbrack \begin{array}{cc} I & 0 \\ 0 & {\hat A}_2 \end{array} \right \rbrack \left \lbrack \begin{array}{cc} {\hat D}_1 & {\hat U}_1 \\ 0 & I \end{array} \right \rbrack Q_1 = P_1 \ L_1 \ A_2 \ U_1 \ Q_1 $$ so we can expand $A_0$ to find $A = P_0 \ L_0 \ P_1 \ L_1 \ A_2 \ U_1 \ Q_1 \ U_0 \ Q_0$. Eventually the factorization proceeds to completion and we have $$ A = (P_0 \ L_0 \ P_1 \ L_1 \ \cdots \ P_k \ L_k) (U_K \ Q_k \ \cdots \ U_1 \ Q_1 \ U_0\ Q_0) $$ Note, $L_0, L_1, \ldots, L_k$ are all lower triangular, for it is the row permutation matrices that are responsible. Note that ${\tilde L}_i = P_i L_i$ is not a lower triangular matrix, but one can solve a linear system involving ${\tilde L}_i$ without any difficulty. A similar statement holds for ${\tilde U}_i = U_i Q_i$, except we have the presence of a block pivot ${\hat D}_i$. \par The key to understanding how we factor and solve linear systems using the {\tt DChvMtx} object is that the permutation matrices $P_i$ and $Q_i$ are held implicitly in ${\tilde L}_i$ and ${\tilde U}_i$, and we solve any linear system with ${\tilde L}_i$ and ${\tilde U}_i$ correctly, even though they are not triangular. We can write $A$ as $$ A = {\tilde L}_0 \ {\tilde L}_1 \ \cdots \ {\tilde L}_k \ {\tilde U}_k \ \cdots \ {\tilde U}_1 \ {\tilde U}_0 $$ and thus $A y = b$ by solving a sequence of linear systems ${\tilde L}_0 \ x^0 = b$, ${\tilde L}_1 \ x^1 = x^0$, $\cdots$, ${\tilde L}_k \ x^k = x^{k-1}$, ${\tilde U}_k \ y^k = x^k$, ${\tilde U}_{k-1} \ y^{k-1} = y^k$, $\cdots$, ${\tilde U}_1 \ y^1 = y^2$, ${\tilde U}_0 \ y = y^1$. % Here is a crucial point: % solving a linear system with ${\tilde L}_i$ requires % information about the row permutation at the $i$-th step, % but does not require any knowledge about the column permutation % at that or any other step. % A similar point holds for systems with ${\tilde U}_i$. \par Let us clarify the process with an example. At the first step we permute a $3 \times 3$ matrix so that the $a_{1,2}$ element is the pivot. \begin{eqnarray*} A & = & \left \lbrack \begin{array}{ccc} a_{0,0} & a_{0,1} & a_{0,2} \\ a_{1,0} & a_{1,1} & a_{1,2} \\ a_{2,0} & a_{2,1} & a_{2,2} \end{array} \right \rbrack = \left \lbrack \begin{array}{ccc} 0 & 1 & 0 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} a_{1,2} & a_{1,0} & a_{1,1} \\ a_{0,2} & a_{0,0} & a_{0,1} \\ a_{2,2} & a_{2,0} & a_{2,1} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 0 & 0 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{array} \right \rbrack \\ & = & \left \lbrack \begin{array}{ccc} 0 & 1 & 0 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ l_{0,2} & 1 & 0 \\ l_{2,2} & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & {\hat a}_{0,0} & {\hat a}_{0,1} \\ 0 & {\hat a}_{2,0} & {\hat a}_{2,1} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} d_{1,2} & u_{1,0} & u_{1,1} \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 0 & 0 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{array} \right \rbrack \\ & = & {\tilde L}_0 \ A_1 \ {\tilde U}_0 = \left \lbrack \begin{array}{ccc} l_{0,2} & 1 & 0 \\ 1 & 0 & 0 \\ l_{2,2} & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & {\hat a}_{0,0} & {\hat a}_{0,1} \\ 0 & {\hat a}_{2,0} & {\hat a}_{2,1} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} u_{1,0} & u_{1,1} & d_{1,2} \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{array} \right \rbrack \end{eqnarray*} We then do the same for $A_1$, using ${\hat a}_{2,1}$ as the pivot. \begin{eqnarray*} A_1 & = & \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & {\hat a}_{0,0} & {\hat a}_{0,1} \\ 0 & {\hat a}_{2,0} & {\hat a}_{2,1} \end{array} \right \rbrack = \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 0 & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & {\hat a}_{2,1} & {\hat a}_{2,0} \\ 0 & {\hat a}_{0,1} & {\hat a}_{0,0} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 0 & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \\ & = & \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 0 & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & l_{0,1} & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & {\hat a}_{2,1} & {\hat a}_{2,0} \\ 0 & {\hat a}_{0,1} & {\hat a}_{0,0} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & d_{2,1} & u_{2,0} \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 0 & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \\ & = & {\tilde L}_1 \ A_2 \ {\tilde U}_1 = \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & l_{0,1} & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & {\tilde a}_{0,0} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & u_{2,0} & d_{2,1} \\ 0 & 1 & 0 \end{array} \right \rbrack \end{eqnarray*} Finally, we have the factorization of $A_2$. $$ A_2 = P_2 \ L_2 \ U_2 \ Q_2 = \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & d_{0,0} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{array} \right \rbrack $$ Written on one line we have the factorization of $A$ given below where ${\tilde L}_2 = I$ is omitted. \begin{eqnarray*} A & = & {\tilde L}_0 \ {\tilde L}_1 \ {\tilde U}_2 \ {\tilde U}_1 \ {\tilde U}_0 \\ & = & \left \lbrack \begin{array}{ccc} l_{0,2} & 1 & 0 \\ 1 & 0 & 0 \\ l_{2,2} & 0 & 1 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & l_{0,1} & 1 \\ 0 & 1 & 0 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & d_{0,0} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} 1 & 0 & 0 \\ 0 & u_{2,0} & d_{2,1} \\ 0 & 1 & 0 \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} u_{1,0} & u_{1,1} & d_{1,2} \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{array} \right \rbrack \end{eqnarray*} At best this equation looks awkward, but take heart, it really doesn't describe how we store the entries or use them to solve a linear system. The entries can be logically grouped in terms of chevrons. $$ A^0 = \left \lbrack \begin{array}{ccc} d_{1,2} & u_{1,0} & u_{1,1} \\ l_{0,2} & 0 & 0 \\ l_{2,2} & 0 & 0 \end{array} \right \rbrack, \qquad A^1 = \left \lbrack \begin{array}{ccc} 0 & 0 & 0 \\ 0 & d_{2,1} & u_{2,0} \\ 0 & l_{0,1} & 0 \end{array} \right \rbrack, \qquad A^2 = \left \lbrack \begin{array}{ccc} 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & d_{0,0} \end{array} \right \rbrack, \qquad $$ For each chevron we store the indices of the rows and columns that are nonzero, and the entries in the diagonal, lower triangular and upper triangular block. Note, the row indices and the column indices need not be the same. \par Let us show how we solve a linear system. To solve $A x = b$ we first solve $L y = b$ and then solve $U x = y$ where $L = {\tilde L}_0 {\tilde L}_1 {\tilde L}_2$ and $U = {\tilde U}_2 {\tilde U}_1 {\tilde U}_0$. Note that there are no permutation matrices anywhere. \begin{itemize} \item To solve with ${\tilde L}_0$ we set $y_1 = b_1$, $b_0 := b_0 - l_{0,2} y_1$ and $b_2 := b_2 - l_{2,2} y_1$. \item To solve with ${\tilde L}_1$ we set $y_2 = b_2$ and $b_0 := b_0 - l_{0,1} y_2$. \item To solve with ${\tilde L}_2$ we set $y_0 = b_0$. \item To solve with ${\tilde U}_2$ we set $x_0 = y_0/d_{0,0}$. \item To solve with ${\tilde U}_1$ we set $x_1 = (y_2 - u_{2,0}x_0)/d_{2,1}$. \item To solve with ${\tilde U}_0$ we set $x_2 = (y_1 - u_{1,0}x_0 - u_{1,1} x_1)/d_{1,2}$. \end{itemize} In general, let us write the $k$-th chevron as $$ A^2 = \left \lbrack \begin{array}{cc} D_{\alpha_k,\beta_k} & U_{\alpha_k,\delta_k} \\ L_{\gamma_k,\beta_k} & 0 \end{array} \right \rbrack $$ where $\alpha_k$ and $\gamma_k$ form the row index set and $\beta_k$ and $\delta_k$ form the column index set. Since the pivots partition the rows and columns, we have $$ \gamma_k \cap \bigcup_{i < k} \alpha_i = \emptyset \quad \mbox{and} \quad \delta_k \cap \bigcup_{i < k} \beta_i = \emptyset. $$ The forward solve and backward solve are executed by \begin{center} \begin{minipage}{3 in} \begin{tabbing} XXX\=XXX\=XXX\=\kill for $k = 1, \ldots, \mbox{\# of pivots}$ \\ \> $y_{\alpha_k} = b_{\alpha_k}$ \\ \> $b_{\gamma_k} := b_{\gamma_k} - L_{\gamma_k, \beta_k} y_{\alpha_k}$ \\ end for \\ for $k = \mbox{\# of pivots}, \ldots, 1$ \\ \> $y_{\alpha_k} = b_{\alpha_k}$ \\ \> $x_{\beta_k} := D_{\alpha_k, \beta_k}^{-1} (y_{\alpha_k} - U_{\alpha_k, \delta_k} x_{\delta_k})$ end for \end{tabbing} \end{minipage} \end{center} MT/doc/symbfac.tex010064400020550007177000000127570657133652600153550ustar00clevecompmath00000400000006\par \subsection{Distributed Symbolic Factorization} \label{subsection:DChvMtx:symbolic-factorization} \par The symbolic factorization takes very little time when compared to the numeric factorization or a solve, but it can still be necessary to compute it in a distributed manner. For example, consider the case when the entries in the original matrix do not fit on one processor. \par Here is what we assume that can be present on one processor. \begin{enumerate} \item An {\tt ETree} front tree object contains five vectors whose length is the number of fronts (three tree vectors and two vectors to hold the number of internal and external vertices in a front) and one vector whose length is the number of vertices (that maps vertices to fronts). \item An {\tt IV} object that holds the map from a front to its owner. \item A {\tt DInpMtx} object that holds only those entries in the original matrix that will be mapped to fronts owned by the process. \end{enumerate} \par A process does not need to know about every front in the tree, only those that it owns, that it will update during the factorization, and those that it will interact with during the forward and backsolves. We {\it could} design a front tree data structure that holds only information about the fronts that a process needs to know about. However, it is quite likely that the overhead to store the entire front tree on each processor is acceptable. \par It is not so clear that we can afford to store the entire symbolic factorization on the front tree, so we have designed a strategy that each process computes and holds only the indices for the fronts that it needs. Actually, this is not true, for we store a bit more than the bare minimum, as we now explain. \par If a process owns front $J$, then it will compute the factor entries in this front, and will compute updates to all ancestor fronts $K$ such that $\bnd{J} \cap K \ne \emptyset$. Let the set of {\it active} fronts be the active fronts unioned with those fronts that will be updated by an owned front. % Let us call the set of {\it owned} fronts and those fronts that % will be updated by an owned front the {\it set of active fronts}. \par It is not necessarily true that an owned front $J$ will update {\it all} of its ancestors. However, to determine what ancestors of owned fronts will be updated by the owned fronts, we need to know the boundary indices for each front, and that is what we are trying to determine by computing the symbolic factorization. So we settle for a superset that is (hopefully) not too much larger than the active fronts. To use a different term, we will easily find a set of {\it supported fronts} that contains the active fronts. These supported fronts consists of the owned fronts and all ancestors of owned fronts, and we can determine this set just by using the front tree and the owners map vector. \par To compute the factorization, a process will need to have the indices for each of its active fronts, so at the end of the symbolic factorization, each process must contain an {\tt IVL} object that contains the front indices for all supported processors. \par How do we compute the front indices for the supported fronts? There are four steps. \begin{enumerate} \item From the front tree we know the number of internal and number of external indices in each front via the {\tt nodwghts[]} and {\tt bndwghts[]} vectors. So we initialize the {\tt IVL} object that will hold the supported portions of the symbolic factorization. \item For each owned front, we load the internal vertices using the {\tt vtxToFront[]} vector from the front tree. \item For each owned front $J$ we add some of the indices in $\bnd{J}$ by examining the entries in the local {\tt DInpMtx} object. \item Now we need to cooperate with the other processes. First we compute the number of messages that we expect to receive from other processes. There will be one message for each supported but unowned front, and one message for each unsupported front whose parent is owned. We keep track of the number of missing indices for each owned front. When all indices for an owned front are present (after step 2 any root front has this property, and after step 3 all leaf fronts have this property), we put the front into a list of {\it ready} fronts. \begin{tabbing} XXX\=XXX\=XXX\=XXX\=XXX\=\kill \WHILE\ the ready list is not empty or there are messages remaining \\ \> \WHILE\ the ready list is not empty \\ \>\> remove owned front $J$ from the ready list \\ \>\> store $J \cup \bnd{J}$ in the {\tt IVL} object \\ \>\> send $J \cup \bnd{J}$ to all processes that contain $J$ in their support sets \\ \>\> \IF\ the $J$ has a parent $K$ \THEN\ \\ \>\>\> \IF\ $K$ is owned and not complete \THEN\ \\ \>\>\>\> merge $\bnd{J}$ into $K \cup \bnd{K}$ \\ \>\>\>\> \IF\ $K \cup \bnd{K}$ is complete \THEN\ \\ \>\>\>\>\> put $K$ on the ready list \\ \>\>\>\> \END\ \IF \\ \>\>\> \ELSE\ \IF\ $J$ not supported by the owner of $K$ \THEN\ \\ \>\>\>\> send $J \cup \bnd{J}$ to the owner of $K$ \\ \>\>\> \END\ \IF \\ \>\> \END\ \IF\ \\ \> \END\ \WHILE\ \\ \> \WHILE\ there are messages waiting to be received \\ \>\> receive $J \cup \bnd{J}$ \\ \>\> \IF\ $J$ is supported \THEN\ \\ \>\>\> store $J \cup \bnd{J}$ in the {\tt IVL} object \\ \>\> \END\ \IF \\ \>\> \IF\ $J$ has a parent $K$, $K$ is owned and not complete \THEN\ \\ \>\>\> merge $\bnd{J}$ into $K \cup \bnd{K}$ \\ \>\>\> \IF\ $K \cup \bnd{K}$ is complete \THEN\ \\ \>\>\>\> put $K$ on the ready list \\ \>\>\> \END\ \IF \\ \>\> \END\ \IF \\ \> \END\ \WHILE \\ end \WHILE\ \end{tabbing} \end{enumerate} MT/doc/main.log010064400020550007177000000117400665022537500146220ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 16 JAN 1999 16:12 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) \@indexfile=\write3 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 17. LaTeX Font Info: ... okay on input line 17. (intro.tex Chapter 1. LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 9. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 9. ) (dataStructure.tex) (proto.tex [1 ] Overfull \hbox (63.2698pt too wide) in paragraph at lines 11--27 \OT1/cmr/m/n/10 There are five meth-ods to mul-ti-ply a vec-tor times a dense m a-trix. The first three meth-ods, called \OT1/cmtt/m/n/10 InpMtx[]MT[]nonsym[]m mm*()\OT1/cmr/m/n/10 , [] Overfull \hbox (34.11732pt too wide) in paragraph at lines 64--75 \OT1/cmtt/m/n/10 INPMTX[]BY[]CHEVRONS\OT1/cmr/m/n/10 , or if \OT1/cmtt/m/n/10 s torageMode \OT1/cmr/m/n/10 is not one of \OT1/cmtt/m/n/10 INPMTX[]RAW[]DATA\OT1 /cmr/m/n/10 , \OT1/cmtt/m/n/10 INPMTX[]SORTED \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/ 10 INPMTX[]BY[]VECTORS\OT1/cmr/m/n/10 , [] [2] Overfull \hbox (34.11732pt too wide) in paragraph at lines 101--112 \OT1/cmtt/m/n/10 INPMTX[]BY[]CHEVRONS\OT1/cmr/m/n/10 , or if \OT1/cmtt/m/n/10 s torageMode \OT1/cmr/m/n/10 is not one of \OT1/cmtt/m/n/10 INPMTX[]RAW[]DATA\OT1 /cmr/m/n/10 , \OT1/cmtt/m/n/10 INPMTX[]SORTED \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/ 10 INPMTX[]BY[]VECTORS\OT1/cmr/m/n/10 , [] Overfull \hbox (34.11732pt too wide) in paragraph at lines 130--139 \OT1/cmtt/m/n/10 INPMTX[]BY[]CHEVRONS\OT1/cmr/m/n/10 , or if \OT1/cmtt/m/n/10 s torageMode \OT1/cmr/m/n/10 is not one of \OT1/cmtt/m/n/10 INPMTX[]RAW[]DATA\OT1 /cmr/m/n/10 , \OT1/cmtt/m/n/10 INPMTX[]SORTED \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/ 10 INPMTX[]BY[]VECTORS\OT1/cmr/m/n/10 , [] LaTeX Font Info: Try loading font information for OMS+cmr on input line 179. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 179. [3] LaTeX Font Info: External font `cmex10' loaded for size (Font) <12> on input line 230. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 230. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 230. [4]) (drivers.tex [5] [6] [7] LaTeX Font Info: Try loading font information for OMS+cmtt on input line 283 . LaTeX Font Info: No file OMScmtt.fd. on input line 283. LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined (Font) using `OMS/cmsy/m/n' instead (Font) for symbol `textbraceleft' on input line 283. [8] LaTeX Font Info: Try loading font information for OML+cmr on input line 369. (/home/tex/teTeX/texmf/tex/latex/base/omlcmr.fd File: omlcmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OML/cmr/m/n' in size <10> not available (Font) Font shape `OML/cmm/m/it' tried instead on input line 369. [9]) (main.ind [10] [11 ]) (main.aux) LaTeX Font Warning: Some font shapes were not available, defaults substituted. ) Here is how much of TeX's memory you used: 358 strings out of 10908 3706 string characters out of 72189 50228 words of memory out of 262141 3259 multiletter control sequences out of 9500 10349 words of font info for 38 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 23i,4n,21p,161b,427s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (11 pages, 41428 bytes). MT/doc/main.idx010064400020550007177000000012730665022537500146250ustar00clevecompmath00000400000006\indexentry{InpMtx_MT_nonsym_mmm@{\tt InpMtx\_MT\_nonsym\_mmm()}}{2} \indexentry{InpMtx_MT_sym_mmm@{\tt InpMtx\_MT\_sym\_mmm()}}{2} \indexentry{InpMtx_MT_herm_mmm@{\tt InpMtx\_MT\_herm\_mmm()}}{2} \indexentry{InpMtx_MT_nonsym_mmm_T@{\tt InpMtx\_MT\_nonsym\_mm\_Tm()}}{2} \indexentry{InpMtx_MT_nonsym_mmm_H@{\tt InpMtx\_MT\_nonsym\_mmm\_H()}}{3} \indexentry{FrontMtx_MT_factorInpMtx@{\tt FrontMtx\_MT\_factorInpMtx()}}{3} \indexentry{FrontMtx_MT_factorPencil@{\tt FrontMtx\_MT\_factorPencil()}}{3} \indexentry{FrontMtx_MT_QR_factor@{\tt FrontMtx\_MT\_QR\_factor()}}{4} \indexentry{FrontMtx_MT_solve@{\tt FrontMtx\_MT\_solve()}}{4} \indexentry{FrontMtx_MT_QR_solve@{\tt FrontMtx\_MT\_QR\_solve()}}{5} MT/doc/main.aux010064400020550007177000000026150665022537500146370ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt MT} directory}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:MT}{{1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{2}} \newlabel{section:MT:dataStructure}{{1.1}{2}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt MT} methods}{2}} \newlabel{section:MT:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Matrix-matrix multiply methods}{2}} \newlabel{subsection:MT:proto:mvm}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Multithreaded Factorization methods}{3}} \newlabel{subsection:FrontMtx:proto:factorMT}{{1.2.2}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Multithreaded $QR$ Factorization method}{4}} \newlabel{subsection:FrontMtx:proto:factorQR_MT}{{1.2.3}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Multithreaded Solve method}{4}} \newlabel{subsection:FrontMtx:proto:solve-multithreaded}{{1.2.4}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Multithreaded $QR$ Solve method}{5}} \newlabel{subsection:FrontMtx:proto:QRsolve-MT}{{1.2.5}{5}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs for the multithreaded functions}{5}} \newlabel{section:MT:drivers}{{1.3}{5}} MT/doc/main.ind010064400020550007177000000007440662233017500146070ustar00clevecompmath00000400000006\begin{theindex} \item {\tt FrontMtx\_MT\_factorInpMtx()}, 3 \item {\tt FrontMtx\_MT\_factorPencil()}, 3 \item {\tt FrontMtx\_MT\_QR\_factor()}, 4 \item {\tt FrontMtx\_MT\_QR\_solve()}, 5 \item {\tt FrontMtx\_MT\_solve()}, 4 \indexspace \item {\tt InpMtx\_MT\_herm\_mmm()}, 2 \item {\tt InpMtx\_MT\_nonsym\_mmm()}, 2 \item {\tt InpMtx\_MT\_nonsym\_mmm\_H()}, 3 \item {\tt InpMtx\_MT\_nonsym\_mm\_Tm()}, 2 \item {\tt InpMtx\_MT\_sym\_mmm()}, 2 \end{theindex} MT/doc/main.ilg010064400020550007177000000004560662233017500146100ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (10 entries accepted, 0 rejected). Sorting entries....done (35 comparisons). Generating output file main.ind....done (17 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. MT/doc/makefile010064400020550007177000000000270657133652600146720ustar00clevecompmath00000400000006clean : - rm -f *.dvi Network.h010064400020550007177000000001100653410640200136630ustar00clevecompmath00000400000006#ifndef _Network_ #define _Network_ #include "Network/Network.h" #endif Network/Network.h010064400020550007177000000240060653410612400153270ustar00clevecompmath00000400000006/* Network.h */ #include "../cfiles.h" #include "../Ideq.h" /*--------------------------------------------------------------------*/ /* --------------------------------- forward declarations of typedef's --------------------------------- */ typedef struct _Network Network ; typedef struct _Arc Arc ; typedef struct _ArcChunk ArcChunk ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ structure to hold a network. nnode -- number of nodes in the network. the source node is 0, the sink node is nnode - 1 narc -- number of arcs in the network ntrav -- number of arcs that are traversed, used as a measure of complexity inheads -- array of pointers used to point to the first arc in the in list for the nodes outheads -- array of pointers used to point to the first arc in the out list for the nodes chunk -- pointer to the first ArcChunk structure msglvl -- message level, default is 0 msgFile -- message file, default is stdout ------------------------------------------------------------ */ struct _Network { int nnode ; int narc ; int ntrav ; Arc **inheads ; Arc **outheads ; ArcChunk *chunk ; int msglvl ; FILE *msgFile ; } ; /* ---------------------------------------------------------------- arc structure vertices in the arc are (first, second). there is one arc that is linked into the out list for vertex first and the in list for vertex second via the nextOut and nextIn fields, respectively. ---------------------------------------------------------------- */ struct _Arc { int first ; int second ; int capacity ; int flow ; Arc *nextOut ; Arc *nextIn ; } ; /* --------------------------------------------------------------- structure to hold a vector of arcs, used in forming the network when the total number of arcs is not known ahead of time. size -- dimension of base[] array inuse -- number of arc structures in use, next free arc is located at &base[inuse] base -- vector of Arc structures next -- link to the next ArcChunk structure, used to free the storage when finished --------------------------------------------------------------- */ struct _ArcChunk { int size ; int inuse ; Arc *base ; ArcChunk *next ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c -------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------- construct a new instance of the Network object created -- 96jun08, cca -------------------------------------------- */ Network * Network_new ( void ) ; /* --------------------------------------------- set the default fields of the Network object created -- 96jun08, cca --------------------------------------------- */ void Network_setDefaultFields ( Network *network ) ; /* --------------------------------------------- clear the data fields for a Network object created -- 96jun08, cca --------------------------------------------- */ void Network_clearData ( Network *network ) ; /* ------------------------ free the Network object created -- 96jun08, cca ------------------------ */ void Network_free ( Network *network ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------- initialize the Network object nnode -- number of nodes in the network, must be > 2, source node is 0, sink node is nnode - 1 narc -- number of arcs. this value can be zero if the number of arcs is not known at initialization time. storage for the arcs will grow as needed created -- 96jun08, cca ------------------------------------------------------------- */ void Network_init ( Network *network, int nnode, int narc ) ; /* --------------------------------- purpose -- set the message fields created -- 96oct23, cca --------------------------------- */ void Network_setMessageInfo ( Network *network, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in addArc.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------- add an arc to the network created -- 96jun08, cca ------------------------- */ void Network_addArc ( Network *network, int firstNode, int secondNode, int capacity, int flow ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in findAugmentingPath.c -------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------------- find an augmenting path from the source to the sink through node. node -- (source, node) is an arc below capacity delta -- capacity(source, node) - flow(source, node) tag -- tag used to build this traversal tree deq -- dequeue object to handle traversal, out-nodes get put at head of list, in-nodes get put at tail of list tags -- tags vector for the nodes deltas -- flow increment vector for the nodes pred -- predecessor vector for the nodes created -- 96jun08, cca ----------------------------------------------------------------- */ int Network_findAugmentingPath ( Network *network, int node, int delta, int tag, Ideq *deq, int tags[], int deltas[], int pred[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in augmentingPath.c ------------------------------ ------------------------------------------------------------------------ */ /* ---------------------------------------------------------------- given an augmenting path defined by the pred[] vector and delta, the change in flow, augment the path from the source to the sink created -- 86jun08, cca ---------------------------------------------------------------- */ void Network_augmentPath ( Network *network, int delta, int pred[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in findMaxFlow.c --------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------- find the maximum flow of a network created -- 96jun08, cca ---------------------------------- */ void Network_findMaxFlow ( Network *network ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in findMincut.c ---------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------------- mark the nodes 1 or 2 to define a min-cut, where source in X and sink in Y. start the search from the source node. for x in X and y in Y arc (x,y) is in the min-cut when flow(x,y) == capacity(x,y) arc (y,x) is in the min-cut when flow(y,x) == 0 on return, mark[*] is filled with 1 or 2, where the mark[source] = 1 and mark[sink] = 2 created -- 96jun08, cca -------------------------------------------------------------- */ void Network_findMincutFromSource ( Network *network, Ideq *deq, int mark[] ) ; /* -------------------------------------------------------------- mark the nodes 1 or 2 to define a min-cut, where source in X and sink in Y. start the search from the sink node. for x in X and y in Y arc (x,y) is in the min-cut when flow(x,y) == capacity(x,y) arc (y,x) is in the min-cut when flow(y,x) == 0 on return, mark[*] is filled with 1 or 2, where the mark[source] = 1 and mark[sink] = 2 created -- 96jun08, cca -------------------------------------------------------------- */ void Network_findMincutFromSink ( Network *network, Ideq *deq, int mark[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ---------------------------------------- print the network for debugging purposes created -- 96jun08, cca ---------------------------------------- */ void Network_writeForHumanEye ( Network *network, FILE *fp ) ; /* --------------------------------------------------- print the network statistics for debugging purposes created -- 96jun08, cca --------------------------------------------------- */ void Network_writeStats ( Network *network, FILE *fp ) ; /*--------------------------------------------------------------------*/ Network/makefile010064400020550007177000000001410663622364500152320ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean Network/src/makefile010064400020550007177000000011070663602737500160260ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Network $(OBJ).a : \ $(OBJ).a(addArc.o) \ $(OBJ).a(augmentPath.o) \ $(OBJ).a(basics.o) \ $(OBJ).a(findAugmentingPath.o) \ $(OBJ).a(findMaxFlow.o) \ $(OBJ).a(findMincut.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG Network/src/makeGlobalLib010064400020550007177000000007350660026111300167210ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Network SRC = addArc.c \ augmentPath.c \ basics.c \ findAugmentingPath.c \ findMaxFlow.c \ findMincut.c \ init.c \ IO.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Network/src/IO.c010064400020550007177000000031600653410612200147630ustar00clevecompmath00000400000006/* IO.c */ #include "../Network.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------- print the network for debugging purposes created -- 96jun08, cca ---------------------------------------- */ void Network_writeForHumanEye ( Network *network, FILE *fp ) { Arc *arc ; Arc **inheads, **outheads ; int jnode, nnode ; Network_writeStats(network, fp) ; nnode = network->nnode ; inheads = network->inheads ; outheads = network->outheads ; for ( jnode = 0 ; jnode < nnode ; jnode++ ) { fprintf(fp, "\n in list for %d :", jnode) ; fflush(fp) ; for ( arc = inheads[jnode] ; arc != NULL ; arc = arc->nextIn ) { fprintf(fp, " <%d,%d,%d>", arc->first, arc->flow, arc->capacity) ; fflush(fp) ; } fprintf(fp, "\n out list for %d :", jnode) ; fflush(fp) ; for ( arc = outheads[jnode] ; arc != NULL ; arc = arc->nextOut ) { fprintf(fp, " <%d,%d,%d>", arc->second, arc->flow, arc->capacity) ; fflush(fp) ; } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- print the network statistics for debugging purposes created -- 96jun08, cca --------------------------------------------------- */ void Network_writeStats ( Network *network, FILE *fp ) { fprintf(fp, "\n\n Network : %d nodes, %d arcs, %d arc traversals", network->nnode, network->narc, network->ntrav) ; return ; } /*--------------------------------------------------------------------*/ Network/src/addArc.c010064400020550007177000000033330653410612200156340ustar00clevecompmath00000400000006/* addArc.c */ #include "../Network.h" /*--------------------------------------------------------------------*/ /* ------------------------- add an arc to the network created -- 96jun08, cca ------------------------- */ void Network_addArc ( Network *network, int firstNode, int secondNode, int capacity, int flow ) { Arc *arc ; Arc **inheads, **outheads ; ArcChunk *chunk ; int nnode ; /* --------------- check the input --------------- */ if ( network == NULL || (nnode = network->nnode) <= 0 || firstNode < 0 || firstNode >= nnode || secondNode < 0 || secondNode >= nnode || capacity <= 0 || flow < 0 || flow > capacity ) { fprintf(stderr, "\n fatal error in Network_addArc(%p,%d,%d,%d,%d)" "\n bad input\n", network, firstNode, secondNode, capacity, flow) ; if ( network != NULL ) { fprintf(stderr, "\n nnode = %d", nnode) ; } exit(-1) ; } inheads = network->inheads ; outheads = network->outheads ; if ( (chunk = network->chunk) == NULL || chunk->inuse == chunk->size ) { ALLOCATE(chunk, struct _ArcChunk, 1) ; ALLOCATE(chunk->base, struct _Arc, nnode) ; chunk->size = nnode ; chunk->inuse = 0 ; chunk->next = network->chunk ; network->chunk = chunk ; } arc = chunk->base + chunk->inuse++ ; arc->first = firstNode ; arc->second = secondNode ; arc->capacity = capacity ; arc->flow = flow ; arc->nextOut = outheads[firstNode] ; outheads[firstNode] = arc ; arc->nextIn = inheads[secondNode] ; inheads[secondNode] = arc ; network->narc++ ; return ; } /*--------------------------------------------------------------------*/ Network/src/augmentPath.c010064400020550007177000000043060653410612200167340ustar00clevecompmath00000400000006/* augmentPath.c */ #include "../Network.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- given an augmenting path defined by the pred[] vector and delta, the change in flow, augment the path from the source to the sink created -- 86jun08, cca ---------------------------------------------------------------- */ void Network_augmentPath ( Network *network, int delta, int pred[] ) { Arc *arc ; Arc **inheads, **outheads ; FILE *msgFile ; int msglvl, nnode, sink, source, v, w ; /* --------------- check the input --------------- */ if ( network == NULL || (nnode = network->nnode) <= 0 || delta <= 0 || pred == NULL ) { fprintf(stderr, "\n fatal error in Network_augmentPath(%p,%d,%p)" "\n bad input\n", network, delta, pred) ; exit(-1) ; } source = 0 ; sink = nnode - 1 ; inheads = network->inheads ; outheads = network->outheads ; msglvl = network->msglvl ; msgFile = network->msgFile ; /* ----------------------- work back from the sink ----------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n augment path") ; fflush(msgFile) ; } w = sink ; while ( 1 ) { v = pred[w] ; if ( msglvl > 2 ) { fprintf(msgFile, "\n w = %d, v = %d", w, v) ; } for ( arc = inheads[v] ; arc != NULL ; arc = arc->nextIn ) { network->ntrav++ ; if ( arc->first == w ) { arc->flow -= delta ; if ( msglvl > 2 ) { fprintf(msgFile, "\n backward arc(%d,%d), flow = %d", w, v, arc->flow) ; } break ; } } if ( arc == NULL ) { for ( arc = outheads[v] ; arc != NULL ; arc = arc->nextOut ) { network->ntrav++ ; if ( arc->second == w ) { arc->flow += delta ; if ( msglvl > 2 ) { fprintf(msgFile, "\n forward arc(%d,%d), flow = %d", v, w, arc->flow) ; } break ; } } } if ( v == source ) { break ; } w = v ; } return ; } /*--------------------------------------------------------------------*/ Network/src/basics.c010064400020550007177000000045560653410612200157320ustar00clevecompmath00000400000006/* basics.c */ #include "../Network.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------- construct a new instance of the Network object created -- 96jun08, cca -------------------------------------------- */ Network * Network_new ( void ) { Network *network ; ALLOCATE(network, struct _Network, 1) ; Network_setDefaultFields(network) ; return(network) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- set the default fields of the Network object created -- 96jun08, cca --------------------------------------------- */ void Network_setDefaultFields ( Network *network ) { if ( network == NULL ) { fprintf(stderr, "\n fatal error in Network_setDefaultFields(%p)" "\n bad input\n", network) ; exit(-1) ; } network->nnode = 0 ; network->narc = 0 ; network->ntrav = 0 ; network->inheads = NULL ; network->outheads = NULL ; network->chunk = NULL ; network->msglvl = 0 ; network->msgFile = NULL ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- clear the data fields for a Network object created -- 96jun08, cca --------------------------------------------- */ void Network_clearData ( Network *network ) { ArcChunk *chunk ; if ( network == NULL ) { fprintf(stderr, "\n fatal error in Network_clearData(%p)" "\n bad input\n", network) ; exit(-1) ; } if ( network->inheads != NULL ) { FREE(network->inheads) ; } if ( network->outheads != NULL ) { FREE(network->outheads) ; } while ( (chunk = network->chunk) != NULL ) { network->chunk = chunk->next ; FREE(chunk->base) ; FREE(chunk) ; } Network_setDefaultFields(network) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------ free the Network object created -- 96jun08, cca ------------------------ */ void Network_free ( Network *network ) { if ( network == NULL ) { fprintf(stderr, "\n fatal error in Network_free(%p)" "\n bad input\n", network) ; exit(-1) ; } Network_clearData(network) ; FREE(network) ; return ; } /*--------------------------------------------------------------------*/ Network/src/findAugmentingPath.c010064400020550007177000000106440653410612200202350ustar00clevecompmath00000400000006/* findAugmentingPath.c */ #include "../Network.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- find an augmenting path from the source to the sink through node. node -- (source, node) is an arc below capacity delta -- capacity(source, node) - flow(source, node) tag -- tag used to build this traversal tree deq -- dequeue object to handle traversal, out-nodes get put at head of list, in-nodes get put at tail of list tags -- tags vector for the nodes deltas -- flow increment vector for the nodes pred -- predecessor vector for the nodes created -- 96jun08, cca ----------------------------------------------------------------- */ int Network_findAugmentingPath ( Network *network, int node, int delta, int tag, Ideq *deq, int tags[], int deltas[], int pred[] ) { Arc *arc ; Arc **inheads, **outheads ; FILE *msgFile ; int msglvl, nnode, resid, sink, source, v, w ; /* --------------- check the input --------------- */ if ( network == NULL || (nnode = network->nnode) <= 0 || node <= 0 || node >= nnode -1 || deq == NULL || tags == NULL || deltas == NULL || pred == NULL ) { fprintf(stderr, "\n fatal error in Network_findAugmentingPath(%p,%d,%d,%d,%p,%p,%p,%p)" "\n bad input\n", network, node, delta, tag, deq, tags, deltas, pred) ; exit(-1) ; } inheads = network->inheads ; outheads = network->outheads ; msglvl = network->msglvl ; msgFile = network->msgFile ; if ( msglvl > 2 ) { fprintf(msgFile, "\n try to find augmenting path starting at node %d", node) ; fflush(msgFile) ; } /* --------------------------------------- load the dequeue with the seed node and set the tags, pred and delta fields --------------------------------------- */ Ideq_clear(deq) ; Ideq_insertAtHead(deq, node) ; source = 0 ; sink = nnode - 1 ; tags[source] = tags[node] = tag ; deltas[node] = delta ; pred[node] = source ; /* ------------------------------------------ try to find an augmenting path to the sink ------------------------------------------ */ while ( tags[sink] != tag ) { v = Ideq_removeFromHead(deq) ; if ( v < 0 ) { /* ----------------------------------- dequeue is empty, break out of loop ----------------------------------- */ break ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n node %d removed from head of dequeue", v) ; } /* ---------------------- check out the out-arcs ---------------------- */ for ( arc = outheads[v] ; arc != NULL ; arc = arc->nextOut ) { network->ntrav++ ; w = arc->second ; if ( msglvl > 2 ) { fprintf(msgFile, "\n out-arc (%d,%d), flow %d, capacity %d", arc->first, arc->second, arc->flow, arc->capacity) ; } if ( tags[w] != tag && (resid = arc->capacity - arc->flow) > 0 ) { if ( resid > deltas[v] ) { resid = deltas[v] ; } deltas[w] = resid ; if ( msglvl > 2 ) { fprintf(msgFile, ", now a tree arc, delta = %d", deltas[w]) ; } tags[w] = tag ; pred[w] = v ; if ( w == sink ) { return(resid) ; } Ideq_insertAtHead(deq, w) ; } } /* --------------------- check out the in-arcs --------------------- */ for ( arc = inheads[v] ; arc != NULL ; arc = arc->nextIn ) { network->ntrav++ ; w = arc->first ; if ( msglvl > 2 ) { fprintf(msgFile, "\n in-arc (%d,%d), flow %d, capacity %d", arc->first, arc->second, arc->flow, arc->capacity) ; } if ( tags[w] != tag && (resid = arc->flow) > 0 ) { if ( resid > deltas[v] ) { resid = deltas[v] ; } deltas[w] = resid ; if ( msglvl > 2 ) { fprintf(msgFile, ", now a tree arc, delta = %d", deltas[w]) ; } tags[w] = tag ; pred[w] = v ; Ideq_insertAtTail(deq, w) ; } } } /* ---------------------------------------------------- if we got to here the sink was not reached, return 0 ---------------------------------------------------- */ return(0) ; } /*--------------------------------------------------------------------*/ Network/src/findMaxFlow.c010064400020550007177000000041350653410612200166750ustar00clevecompmath00000400000006/* findMaxFlow.c */ #include "../Network.h" /*--------------------------------------------------------------------*/ /* ---------------------------------- find the maximum flow of a network created -- 96jun08, cca ---------------------------------- */ void Network_findMaxFlow ( Network *network ) { Arc *arc ; Arc **inheads, **outheads ; FILE *msgFile ; Ideq *deq ; int delta, msglvl, nnode, source, tag ; int *deltas, *pred, *tags ; /* --------------- check the input --------------- */ if ( network == NULL || (nnode = network->nnode) <= 0 ) { fprintf(stderr, "\n fatal error in findMaxFlow(%p)" "\n bad input\n", network) ; exit(-1) ; } outheads = network->outheads ; inheads = network->inheads ; msglvl = network->msglvl ; msgFile = network->msgFile ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n findMaxFlow :\n") ; } /* ---------------------------------- set up the working data structures ---------------------------------- */ deq = Ideq_new() ; Ideq_resize(deq, nnode) ; pred = IVinit(nnode, -1) ; tags = IVinit(nnode, -1) ; deltas = IVinit(nnode, 0) ; /* ----------------- find the max flow ----------------- */ tag = 0 ; source = 0 ; for ( arc = outheads[source] ; arc != NULL ; arc = arc->nextOut ) { network->ntrav++ ; if ( msglvl > 2 ) { fprintf(msgFile, "\n checking out node %d", arc->second) ; } while ( (delta = arc->capacity - arc->flow) > 0 ) { delta = Network_findAugmentingPath(network, arc->second, delta, tag, deq, tags, deltas, pred) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n delta = %d from findAugmentPath(%d)", delta, arc->second) ; } if ( delta == 0 ) { break ; } Network_augmentPath(network, delta, pred) ; tag++ ; } } /* ------------------------ free the working storage ------------------------ */ Ideq_free(deq) ; IVfree(pred) ; IVfree(tags) ; IVfree(deltas) ; return ; } /*--------------------------------------------------------------------*/ stderr, "\n fatal error in findMaxFlow(%p)" "\n bad input\n", network) ; exit(-1) ; } outheads = network->outheads ; inheads = network->inheads ; msglvl = network->msglvl ; msgFile = network->msgFile ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n findMaxFlow :\n") ; } /* ---------------------------------- set up the working data structures ---------------------------------- */ deq = INetwork/src/findMincut.c010064400020550007177000000150320653410612300165560ustar00clevecompmath00000400000006/* findMincut.c */ #include "../Network.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- mark the nodes 1 or 2 to define a min-cut, where source in X and sink in Y. start the search from the source node. for x in X and y in Y arc (x,y) is in the min-cut when flow(x,y) == capacity(x,y) arc (y,x) is in the min-cut when flow(y,x) == 0 on return, mark[*] is filled with 1 or 2, where the mark[source] = 1 and mark[sink] = 2 created -- 96jun08, cca -------------------------------------------------------------- */ void Network_findMincutFromSource ( Network *network, Ideq *deq, int mark[] ) { Arc *arc ; Arc **inheads, **outheads ; FILE *msgFile ; int msglvl, nnode, source, x, z ; /* --------------- check the input --------------- */ if ( network == NULL || (nnode = network->nnode) <= 0 || deq == NULL || mark == NULL ) { fprintf(stderr, "\n fatal error in Network_findMincutFromSource(%p,%p,%p)" "\n bad input\n", network, deq, mark) ; exit(-1) ; } source = 0 ; inheads = network->inheads ; outheads = network->outheads ; msglvl = network->msglvl ; msgFile = network->msgFile ; if ( msglvl > 2 ) { fprintf(msgFile, "\n Network_findMincutFromSource") ; fflush(msgFile) ; } /* ----------------------------------------------- load all the nodes into Y except for the source ----------------------------------------------- */ IVfill(nnode, mark, 2) ; mark[source] = 1 ; /* --------------------------------------------------------- do a breadth first traversal from the source visit x in X out edge (x,z), add z to X if flow(x,z) < capacity(x,z) in edge (z,x), add z to X if flow(z,x) > 0 --------------------------------------------------------- */ Ideq_clear(deq) ; Ideq_insertAtHead(deq, source) ; while ( (x = Ideq_removeFromHead(deq)) != -1 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n checking out node %d", x) ; fflush(msgFile) ; } for ( arc = outheads[x] ; arc != NULL ; arc = arc->nextOut ) { z = arc->second ; if ( mark[z] != 1 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n out-arc (%d,%d), flow %d, capacity %d", x, z, arc->flow, arc->capacity) ; fflush(msgFile) ; } if ( arc->flow < arc->capacity ) { if ( msglvl > 2 ) { fprintf(msgFile, ", adding %d to X", z) ; fflush(msgFile) ; } Ideq_insertAtTail(deq, z) ; mark[z] = 1 ; } } } for ( arc = inheads[x] ; arc != NULL ; arc = arc->nextIn ) { z = arc->first ; if ( mark[z] != 1 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n in-arc (%d,%d), flow %d", z, x, arc->flow) ; fflush(msgFile) ; } if ( arc->flow > 0 ) { if ( msglvl > 2 ) { fprintf(msgFile, ", adding %d to X", z) ; fflush(msgFile) ; } Ideq_insertAtTail(deq, z) ; mark[z] = 1 ; } } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n leaving FindMincutFromSource") ; fflush(msgFile) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- mark the nodes 1 or 2 to define a min-cut, where source in X and sink in Y. start the search from the sink node. for x in X and y in Y arc (x,y) is in the min-cut when flow(x,y) == capacity(x,y) arc (y,x) is in the min-cut when flow(y,x) == 0 on return, mark[*] is filled with 1 or 2, where the mark[source] = 1 and mark[sink] = 2 created -- 96jun08, cca -------------------------------------------------------------- */ void Network_findMincutFromSink ( Network *network, Ideq *deq, int mark[] ) { Arc *arc ; Arc **inheads, **outheads ; FILE *msgFile ; int msglvl, nnode, sink, x, z ; /* --------------- check the input --------------- */ if ( network == NULL || (nnode = network->nnode) <= 0 || deq == NULL || mark == NULL ) { fprintf(stderr, "\n fatal error in Network_findMincutFromSink(%p,%p,%p)" "\n bad input\n", network, deq, mark) ; exit(-1) ; } sink = nnode - 1 ; inheads = network->inheads ; outheads = network->outheads ; msglvl = network->msglvl ; msgFile = network->msgFile ; if ( msglvl > 2 ) { fprintf(msgFile, "\n Network_findMincutFromSink") ; fflush(msgFile) ; } /* --------------------------------------------- load all the nodes into X except for the sink --------------------------------------------- */ IVfill(nnode, mark, 1) ; mark[sink] = 2 ; /* --------------------------------------------------------- do a breadth first traversal from the sink visit y in Y out edge (x,z), add z to X if flow(x,z) < capacity(x,z) in edge (z,x), add z to X if flow(z,x) > 0 --------------------------------------------------------- */ Ideq_clear(deq) ; Ideq_insertAtHead(deq, sink) ; while ( (x = Ideq_removeFromHead(deq)) != -1 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n checking out node %d", x) ; fflush(msgFile) ; } for ( arc = outheads[x] ; arc != NULL ; arc = arc->nextOut ) { z = arc->second ; if ( mark[z] != 2 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n out-arc (%d,%d), flow %d, capacity %d", x, z, arc->flow, arc->capacity) ; fflush(msgFile) ; } if ( arc->flow > 0 ) { if ( msglvl > 2 ) { fprintf(msgFile, ", adding %d to X", z) ; fflush(msgFile) ; } Ideq_insertAtTail(deq, z) ; mark[z] = 2 ; } } } for ( arc = inheads[x] ; arc != NULL ; arc = arc->nextIn ) { z = arc->first ; if ( mark[z] != 2 ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n in-arc (%d,%d), flow %d", z, x, arc->flow) ; fflush(msgFile) ; } if ( arc->flow < arc->capacity ) { if ( msglvl > 2 ) { fprintf(msgFile, ", adding %d to X", z) ; fflush(msgFile) ; } Ideq_insertAtTail(deq, z) ; mark[z] = 2 ; } } } } return ; } /*--------------------------------------------------------------------*/ Network/src/init.c010064400020550007177000000046620653410612300154300ustar00clevecompmath00000400000006/* init.c */ #include "../Network.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- initialize the Network object nnode -- number of nodes in the network, must be > 2, source node is 0, sink node is nnode - 1 narc -- number of arcs. this value can be zero if the number of arcs is not known at initialization time. storage for the arcs will grow as needed created -- 96jun08, cca ------------------------------------------------------------- */ void Network_init ( Network *network, int nnode, int narc ) { int v ; /* --------------- check the input --------------- */ if ( network == NULL || nnode <= 2 || narc < 0 ) { fprintf(stderr, "\n fatal error in Network_init(%p,%d,%d)" "\n bad input\n", network, nnode, narc) ; exit(-1) ; } /* --------------------- clear the data fields --------------------- */ Network_clearData(network) ; network->nnode = nnode ; /* ------------------- allocate the arrays ------------------- */ ALLOCATE(network->inheads, struct _Arc *, nnode) ; ALLOCATE(network->outheads, struct _Arc *, nnode) ; for ( v = 0 ; v < nnode ; v++ ) { network->inheads[v] = network->outheads[v] = NULL ; } if ( narc > 0 ) { ArcChunk *chunk ; /* ------------------------------- allocate the ArcChunk structure ------------------------------- */ ALLOCATE(chunk, struct _ArcChunk, 1) ; ALLOCATE(chunk->base, struct _Arc, narc) ; chunk->size = narc ; chunk->inuse = 0 ; chunk->next = NULL ; network->chunk = chunk ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------- purpose -- set the message fields created -- 96oct23, cca --------------------------------- */ void Network_setMessageInfo ( Network *network, int msglvl, FILE *msgFile ) { /* -------------- check the data -------------- */ if ( network == NULL ) { fprintf(stderr, "\n fatal error in Network_setMessageInfo(%p,%d,%p)" "\n bad input\n", network, msglvl, msgFile) ; exit(-1) ; } if ( msglvl >= 0 ) { network->msglvl = msglvl ; } if ( msgFile != NULL ) { network->msgFile = msgFile ; } else { network->msgFile = stdout ; } return ; } /*--------------------------------------------------------------------*/ Network/doc/004275500020550007177000000000000654276745100143145ustar00clevecompmath00000400000006Network/doc/dataStructure.tex010064000020550007177000000050430653410612300176410ustar00clevecompmath00000400000006\par \section{Data Structure} \par There are three structures associated with the {\tt Network} object. \begin{itemize} \item {\tt Network} -- the main object \item {\tt Arc} -- a structure that represents an edge in the network. \item {\tt ArcChunk} -- a structure that holds the storage for a number of arcs. Since we do not require the number of arcs to be known in advance when initializing the {\tt Network} object, we allocate chunks of space to hold the arcs as necessary. Each chunks holds space for {\tt nnode} arc structures. \end{itemize} \par The {\tt Network} object has six fields. \begin{itemize} \item {\tt int nnode} --- the number of nodes in the network, including the source (node {0}) and the sink (node {\tt nnode-1}). \item {\tt int narc} --- the number of arcs in the network \item {\tt int ntrav} --- the number of arc traversals that we made to find a max flow. \item {\tt Arc **inheads} --- pointer to a vector of pointers to {\tt Arc}, {\tt inheads[v]} points to the first arc in the in-list for node {\tt v}. \item {\tt Arc **outheads} --- pointer to a vector of pointers to {\tt Arc}, {\tt outheads[v]} points to the first arc in the out-list for node {\tt v}. \item {\tt ArcChunk *chunk} --- pointer to the first {\tt ArcChunk} structure. \item {\tt int msglvl} --- message level for debugging and diagnostics. Setting {\tt msglvl = 0} means no output. \item {\tt FILE *msgFile} --- message file for debugging and diagnostics. \end{itemize} A correctly initialized and nontrivial {\tt Network} object will have positive {\tt nnode} and {\tt narc} values, and non-{\tt NULL} {\tt inheads}, {\tt outheads} and {\tt chunk} fields. \par The {\tt Arc} object has six fields. \begin{itemize} \item {\tt int first} --- the first node in the arc. \item {\tt int second} --- the second node in the arc. \item {\tt int capacity} --- the capacity of the arc. \item {\tt int flow} --- the flow along the arc. \item {\tt Arc *nextOut} --- a pointer to the next {\tt Arc} structure in the out-list for node {\tt first}. \item {\tt Arc *nextIn} --- a pointer to the next {\tt Arc} structure in the in-list for node {\tt second}. \end{itemize} \par The {\tt ArcChunk} object has four fields. \begin{itemize} \item {\tt int size} --- the total number of {\tt Arc} structures in this chunk. \item {\tt int inuse} --- the number of active {\tt Arc} structures in this chunk. \item {\tt Arc *base} --- pointer to the first {\tt Arc} structure in this chunk. \item {\tt ArcChunk *next} --- pointer to the next {\tt ArcChunk} structure in the list of chunks. \end{itemize} Network/doc/intro.tex010064000020550007177000000074710653410612300161510ustar00clevecompmath00000400000006\chapter{{\tt Network}: Simple Max-flow solver} \par First, some background on how the {\tt Network} object is used to find a minimal weight separator. The process is rather complex. \par We are given a partition of the vertices $V$ into three disjoint sets, $B$, $Y$ and $W$, where $Y$ is a ``wide'' separator (i.e., not a minimal separator). We construct a network from this vertex partition, solve a max flow problem on this network, and then find one or more mincuts that correspond to a separator $S \subset Y$ with minimal vertex weight. \par Here are the steps by which the {\tt GPart} object contructs the network. \begin{itemize} \item All nodes in $B$ are collapsed into the source $s$. \item All nodes in $W$ are collapsed into the sink $t$. \item $Y$ is partitioned into four sets: \begin{itemize} \item $Y_B$ are those nodes adjacent to $B$ but not adjacent to $W$. \item $Y_W$ are those nodes adjacent to $W$ but not adjacent to $B$. \item $Y_I$ are those nodes adjacent to neither $W$ nor $B$. \item $Y_{B,W}$ are those nodes adjacent to both $W$ and $B$. \end{itemize} Normally, by construction, $Y_{B,W} = \emptyset$, but the code should work fine otherwise. \item Each $y \in Y_B$ becomes one node $y$ in the network, and the edge $(s,y)$ has capacity $weight(y)$. \item Each $y \in Y_W$ becomes one node $y$ in the network, and the edge $(y,t)$ has capacity $weight(y)$. \item Each $y \in Y_I$ becomes two nodes in the network, $y^-$ and $y^+$. The edge $(y^-,y^+)$ has capacity $weight(y)$. \item An edge $(x,y)$ where $x \in Y_B$ and $y \in Y_B$ is not found in the network. (It is not necessary.) Similarly, an edge $(x,y)$ where $x \in Y_W$ and $y \in Y_W$ is not found in the network. \item An edge $(x,y)$ where $x \in Y_B$ and $y \in Y_I$ becomes two edges, $(x,y^-)$ and $(y^+,x)$, both with infinite capacity. \item An edge $(y,z)$ where $y \in Y_I$ and $z \in Y_W$ becomes two edges, $(y^+,z)$ and $(z,y^-)$, both with infinite capacity. \item An edge $(x,y)$ where $x \in Y_I$ and $y \in Y_I$ becomes two edges, $(x^+,y^-)$ and $(y^+,x^-)$, both with infinite capacity. \end{itemize} \par The {\tt Network} object can be constructed fairly simply. It is initialized by specifying the number of nodes in the network, including the source and sink. Arcs can be added one at a time and it is not necessary to know the total number of arcs ahead of time. To specify an arc one needs to provide the first and second vertices, the capacity and the present flow. \par Once we have constructed the network, we solve the max flow problem in a very simple manner, basically the Ford-Fulkerson algorithm that generates augmenting paths. No doubt this can be improved, and it would be welcome because for large three dimensional finite element graphs, up to sixty per cent of the time is spent smoothing the separators, and most of this time is spent solving a max flow problem. \par However, the network we generate in practice have two special properties: \begin{itemize} \item The networks are very shallow, i.e., the distance from the source to the sink is generally 3-6 in practice. This reduces the potential improvement of a pre-push algorithm. \item The maximum capacity of an edge is small, usually 6-12. Therefore scaling algorithms have little applicability. \end{itemize} Finding a minimal separator gives rise to networks of a special nature and that may require specialized solution techniques. In fact, there is a more straightforward approach that generates a network where each vertex in $Y$ becomes {\it one} node in the network (as opposed to two network nodes for a vertex in $Y_I$). For this special network, all edges have infinite capacity and it is the vertices that have finite capacity. In any case, the {\tt Network} object is but a naive and straightforward implementation of the simplest max flow solution scheme and will no doubt be improved. Network/doc/main.tex010064400020550007177000000010610665065627400157530ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Network} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Network} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} Network/doc/main.log010064400020550007177000000042040654027275700157340ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 12 JUN 1998 11:39 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. [1 ]) (dataStructure.tex [2]) (proto.tex [3] [4] Overfull \hbox (0.26903pt too wide) in paragraph at lines 187--187 [] []\elvtt void Network_findMincutFromSource ( Network *network, Ideq deq, in t mark[]) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. [5] Overfull \hbox (55.59328pt too wide) in paragraph at lines 232--238 []\elvrm This method writes the net-work to a file in a hu-man read-able for-ma t. The method \elvtt Network[]writeStats() \hbox(7.60416+0.91246)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\elvrm T .\elvrm h .\elvrm i .\elvrm s .etc. ) (main.ind [6] [7 ]) (main.aux) ) Here is how much of TeX's memory you used: 203 strings out of 11977 2092 string characters out of 87269 33526 words of memory out of 262141 2140 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,4n,17p,184b,258s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (7 pages, 18636 bytes). Network/doc/main.aux010064400020550007177000000022760654027275700157570ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space Network}: Simple Max-flow solver}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{2}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space Network} methods}{3}} \newlabel{section:Network:proto}{{1.2}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{4}} \newlabel{subsection:Network:proto:basics}{{1.2.1}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initializer methods}{4}} \newlabel{subsection:Network:proto:initializers}{{1.2.2}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{5}} \newlabel{subsection:Network:proto:utilities}{{1.2.3}{5}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}IO methods}{6}} \newlabel{subsection:Network:proto:IO}{{1.2.4}{6}} Network/doc/proto.tex010064400020550007177000000236620653410612300161650ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Network} methods} \label{section:Network:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Network} object. \par \subsection{Basic methods} \label{subsection:Network:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Network * Network_new ( void ) ; \end{verbatim} \index{Network_new@{\tt Network\_new()}} This method simply allocates storage for the {\tt Network} structure and then sets the default fields by a call to {\tt Network\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Network_setDefaultFields ( Network *network ) ; \end{verbatim} \index{Network_setDefaultFields@{\tt Network\_setDefaultFields()}} This method sets the structure's fields to default values. \par \noindent {\it Error checking:} If {\tt network} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Network_clearData ( Network *network ) ; \end{verbatim} \index{Network_clearData@{\tt Network\_clearData()}} This method releases any storage held by the object, e.g., it free's the {\tt inheads} and {\tt outheads} vectors and one by one it releases the storage held in the list of {\tt ArcChunk} structures. It then sets the structure's default fields with a call to {\tt Network\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt network} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Network_free ( Network *network ) ; \end{verbatim} \index{Network_free@{\tt Network\_free()}} Thismethod releases any storage by a call to {\tt Network\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt network} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:Network:proto:initializers} \par There are three initializer methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Network_init ( Network *network, int nnode, int narc ) ; \end{verbatim}\ \index{Network_init@{\tt Network\_init()}} This method initializes an {\tt Network} object given the number of nodes and number of arcs. (The latter may be zero since we allow the storage for the arcs to grow dynamically.) \par \noindent {\it Error checking:} If {\tt network} is {\tt NULL}, or if ${\tt nnode} \le 2$, or if ${\tt narc} < 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Network_setMessageInfo ( Network *network, int msglvl, FILE *msgFile) ; \end{verbatim} \index{Network_setMessageInfo@{\tt Network\_setMessageInfo()}} This method sets the message level and message file pointer for the object. \par \noindent {\it Error checking:} If {\tt network} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Network_addArc ( Network *network, int firstNode, secondNode, int capacity, int flow ) ; \end{verbatim} \index{Network_addArc@{\tt Network\_addArc()}} This method adds an arc from {\tt firstNode} to {\tt secondNode} with flow {\tt flow} and capacity {\tt capacity}. The arc is inserted in the out-list for {\tt firstNode} and the in-list for {\tt secondNode}. \par \noindent {\it Error checking:} If {\tt network} is {\tt NULL}, or if ${\tt nnode} \le 0$, or if ${\tt firstNode} \le 0$, or if ${\tt nnode} \le {\tt firstNode}$, or if ${\tt secondNode} \le 0$, or if ${\tt nnode} \le {\tt secondNode}$, or if ${\tt capacity} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par %======================================================================= \subsection{Utility methods} \label{subsection:Network:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Network_findMaxFlow ( Network *network ) ; \end{verbatim} \index{Network_findMaxFlow@{\tt Network\_findMaxFlow()}} This method finds a maximum flow over the network by repeatedly calling the method to find an augmenting path and then the method to augment the path. It uses an {\tt Ideq} object to maintain a priority dequeue. \par \noindent {\it Error checking:} If {\tt network} is {\tt NULL}, or if ${\tt nnode} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Network_findAugmentingPath ( Network *network, int node, int delta, int tag, Ideq *deq, int tags[], int deltas[], int pres[] ) ; \end{verbatim} \index{Network_findAugmentingPath@{\tt Network\_findAugmentingPath()}} This methods tries to find an augmenting path. If successful, the return value is the additional flow that can flow down the path. The start node is {\tt node}, adjacent to the source and for which the edge {\tt (source, node)} is not saturated. The input parameter {\tt delta} is the difference between the capacity and the flow along this initial edge. The {\tt Ideq} object holds the priority dequeue to store the nodes ids that are visited during the search. The {\tt tags[]} vector is used to tag nodes that have been visited --- if {\tt tags[v] = tag}, then {\tt v} has been visited. The {\tt deltas[v]} value maintains the largest admissible flow in the path from the source to {\tt v}. The {\tt pred[]} vector holds the tree links for the nodes. \par \noindent {\it Error checking:} If {\tt network}, {\tt deq}, {\tt tags}, {\tt deltas} or {\tt pred} is {\tt NULL}, or if ${\tt nnode} \le 0$, or if ${\tt node} \le 0$, or if ${\tt nnode - 1} \le {\tt node}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Network_augmentPath ( Network *network, int delta, int pred[] ) ; \end{verbatim} \index{Network_augmentPath@{\tt Network\_augmentPath()}} This method augments the flow along the path defined by the {\tt pred[]} vector by {\tt delta} units. \par \noindent {\it Error checking:} If {\tt network} or {\tt pred} is {\tt NULL}, or if ${\tt nnode} \le 0$, or if ${\tt delta} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Network_findMincutFromSource ( Network *network, Ideq deq, int mark[]) ; \end{verbatim} \index{Network_findMincutFromSource@{\tt Network\_findMincutFromSource()}} This method finds the min-cut closest to the source by traversing a tree of flow-alternating paths from the source. On return, {\tt mark[v] = 1} if the node {\tt v} is in the component that contains the source. If the node {\tt v} is in the component that contains the sink, then {\tt mark[v] = 2}. \par \noindent {\it Error checking:} If {\tt network}, {\tt deq} or {\tt mark} is {\tt NULL}, or if ${\tt nnode} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Network_findMincutFromSink ( Network *network, Ideq deq, int mark[]) ; \end{verbatim} \index{Network_findMincutFromSink@{\tt Network\_findMincutFromSink()}} This method finds the min-cut closest to the sink by traversing a tree of flow-alternating paths into the sink. On return, {\tt mark[v] = 1} if the node {\tt v} is in the component that contains the source. If the node {\tt v} is in the component that contains the sink, then {\tt mark[v] = 2}. \par \noindent {\it Error checking:} If {\tt network}, {\tt deq} or {\tt mark} is {\tt NULL}, or if ${\tt nnode} \le 0$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:Network:proto:IO} \par There are two IO routines for debugging purposes. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Network_writeForHumanEye ( Network *network, FILE *fp ) ; \end{verbatim} \index{Network_writeForHumanEye@{\tt Network\_writeForHumanEye()}} \par This method writes the network to a file in a human readable format. The method {\tt Network\_writeStats()} is called to write out the header and statistics. Then the in-list and out-lists for the nodes in the network are printed. \par \noindent {\it Error checking:} If {\tt network} or {\tt fp} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Network_writeStats ( Network *network, FILE *fp ) ; \end{verbatim} \index{Network_writeStats@{\tt Network\_writeStats()}} \par This method writes a header and statistics to a file. \par \noindent {\it Error checking:} If {\tt network} or {\tt fp} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} Network/doc/main.ind010064400020550007177000000011300654027275500157160ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Network\_addArc()}, 4 \item {\tt Network\_augmentPath()}, 5 \item {\tt Network\_clearData()}, 4 \item {\tt Network\_findAugmentingPath()}, 5 \item {\tt Network\_findMaxFlow()}, 5 \item {\tt Network\_findMincutFromSink()}, 5 \item {\tt Network\_findMincutFromSource()}, 5 \item {\tt Network\_free()}, 4 \item {\tt Network\_init()}, 4 \item {\tt Network\_new()}, 4 \item {\tt Network\_setDefaultFields()}, 4 \item {\tt Network\_setMessageInfo()}, 4 \item {\tt Network\_writeForHumanEye()}, 6 \item {\tt Network\_writeStats()}, 6 \end{theindex} Network/doc/main.idx010064400020550007177000000016320654027275700157410ustar00clevecompmath00000400000006\indexentry{Network_new@{\tt Network\_new()}}{4} \indexentry{Network_setDefaultFields@{\tt Network\_setDefaultFields()}}{4} \indexentry{Network_clearData@{\tt Network\_clearData()}}{4} \indexentry{Network_free@{\tt Network\_free()}}{4} \indexentry{Network_init@{\tt Network\_init()}}{4} \indexentry{Network_setMessageInfo@{\tt Network\_setMessageInfo()}}{4} \indexentry{Network_addArc@{\tt Network\_addArc()}}{4} \indexentry{Network_findMaxFlow@{\tt Network\_findMaxFlow()}}{5} \indexentry{Network_findAugmentingPath@{\tt Network\_findAugmentingPath()}}{5} \indexentry{Network_augmentPath@{\tt Network\_augmentPath()}}{5} \indexentry{Network_findMincutFromSource@{\tt Network\_findMincutFromSource()}}{5} \indexentry{Network_findMincutFromSink@{\tt Network\_findMincutFromSink()}}{5} \indexentry{Network_writeForHumanEye@{\tt Network\_writeForHumanEye()}}{6} \indexentry{Network_writeStats@{\tt Network\_writeStats()}}{6} Network/doc/main.ilg010064400020550007177000000004560654027275500157310ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (14 entries accepted, 0 rejected). Sorting entries....done (53 comparisons). Generating output file main.ind....done (18 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Network/doc/makefile010064400020550007177000000000270654276745100160060ustar00clevecompmath00000400000006clean : - rm -f *.dvi PatchAndGoInfo.h010064400020550007177000000001440657127527500150450ustar00clevecompmath00000400000006#ifndef _PatchAndGoInfo_ #define _PatchAndGoInfo_ #include "PatchAndGoInfo/PatchAndGoInfo.h" #endif PatchAndGoInfo/PatchAndGoInfo.h010064400020550007177000000073030657130044600176220ustar00clevecompmath00000400000006/* PatchAndGoInfo.h */ #include "../IV.h" #include "../DV.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- this object is used by the Chv object to implement the "patch-and-go" strategies, used in specialized optimization and structural analysis applications. strategy -- type of patch-and-go strategy 1 -- used with optimization matrices if ( |a_{i,i}| <= toosmall ) { set a_{i,i} = 1.0 set offdiagonals = 0.0 } 2 -- used with structural analysis matrices if ( |a_{i,i}| <= fudge ) { set a_{i,i} = fudge * max (1, |a_{i,*}|, |a_{*,i}|) } toosmall -- measure of smallness for diagonal entry fudge -- change factor for diagonal entry fudgeIV -- (optional) stores locations where modifications made fudgeDV -- (optional) stores modifications created -- 98aug26, cca ----------------------------------------------------------------- */ typedef struct _PatchAndGoInfo PatchAndGoInfo ; struct _PatchAndGoInfo { int strategy ; double toosmall ; double fudge ; IV *fudgeIV ; DV *fudgeDV ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor method created -- 98aug26, cca ----------------------- */ PatchAndGoInfo * PatchAndGoInfo_new ( void ) ; /* ----------------------- set the default fields created -- 98aug26, cca ----------------------- */ void PatchAndGoInfo_setDefaultFields ( PatchAndGoInfo *info ) ; /* ----------------------- clear the data fields created -- 98aug26, cca ----------------------- */ void PatchAndGoInfo_clearData ( PatchAndGoInfo *info ) ; /* ----------------------- destructor created -- 98aug26, cca ----------------------- */ void PatchAndGoInfo_free ( PatchAndGoInfo *info ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ purpose -- to initialize the patch-and-go information object strategy -- type of patch-and-go strategy 1 -- used with optimization matrices if ( |a_{i,i}| <= toosmall ) { set a_{i,i} = 1.0 set offdiagonals = 0.0 } 2 -- used with structural analysis matrices if ( |a_{i,i}| <= fudge ) { set a_{i,i} = fudge * max (1, |a_{i,*}|, |a_{*,i}|) } toosmall -- tolerance for first strategy fudge -- fudge factor for second strategy storeids -- if nonzero, the row and column numbers where patches have been applied are stored in an IV object storevalues -- if nonzero and strategy 2, the differences between the old and new diagonal magnitudes will be stored in a DV object created -- 98aug27, cca ------------------------------------------------------------ */ void PatchAndGoInfo_init ( PatchAndGoInfo *info, int strategy, double toosmall, double fudge, int storeids, int storevalues ) ; /*--------------------------------------------------------------------*/ PatchAndGoInfo/makefile010064400020550007177000000001410663622365200163630ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean PatchAndGoInfo/src/makefile010064400020550007177000000006220663602743200171540ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = PatchAndGoInfo $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) $(RANLIB) $(OBJ).a @echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG PatchAndGoInfo/src/makeGlobalLib010064400020550007177000000005500660026111600200520ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = PatchAndGoInfo SRC = basics.c \ init.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a PatchAndGoInfo/src/basics.c010064400020550007177000000037210657105102000170530ustar00clevecompmath00000400000006/* basics.c */ #include "../PatchAndGoInfo.h" /*--------------------------------------------------------------------*/ /* ----------------------- constructor method created -- 98aug26, cca ----------------------- */ PatchAndGoInfo * PatchAndGoInfo_new ( void ) { PatchAndGoInfo *info ; ALLOCATE(info, struct _PatchAndGoInfo, 1) ; PatchAndGoInfo_setDefaultFields(info) ; return(info) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98aug26, cca ----------------------- */ void PatchAndGoInfo_setDefaultFields ( PatchAndGoInfo *info ) { if ( info == NULL ) { fprintf(stderr, "\n fatal error in PatchAndGoInfo_setDefaultFields()" "\n bad input\n") ; exit(-1) ; } info->strategy = -1 ; info->toosmall = 0.0 ; info->fudge = 0.0 ; info->fudgeIV = NULL ; info->fudgeDV = NULL ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields created -- 98aug26, cca ----------------------- */ void PatchAndGoInfo_clearData ( PatchAndGoInfo *info ) { if ( info == NULL ) { fprintf(stderr, "\n fatal error in PatchAndGoInfo_clearData()" "\n bad input\n") ; exit(-1) ; } if ( info->fudgeIV != NULL ) { IV_free(info->fudgeIV) ; } if ( info->fudgeDV != NULL ) { DV_free(info->fudgeDV) ; } PatchAndGoInfo_setDefaultFields(info) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- destructor created -- 98aug26, cca ----------------------- */ void PatchAndGoInfo_free ( PatchAndGoInfo *info ) { if ( info == NULL ) { fprintf(stderr, "\n fatal error in PatchAndGoInfo_free()" "\n bad input\n") ; exit(-1) ; } PatchAndGoInfo_clearData(info) ; FREE(info) ; return ; } /*--------------------------------------------------------------------*/ PatchAndGoInfo/src/init.c010064400020550007177000000035360657130031500165620ustar00clevecompmath00000400000006/* init.c */ #include "../PatchAndGoInfo.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to initialize the patch-and-go information object strategy -- type of patch-and-go strategy 1 -- used with optimization matrices if ( |a_{i,i}| <= toosmall ) { set a_{i,i} = 1.0 set offdiagonals = 0.0 } 2 -- used with structural analysis matrices if ( |a_{i,i}| <= fudge ) { set a_{i,i} = fudge * max (1, |a_{i,*}|, |a_{*,i}|) } toosmall -- tolerance for first strategy fudge -- fudge factor for second strategy storeids -- if nonzero, the row and column numbers where patches have been applied are stored in an IV object storevalues -- if nonzero and strategy 2, the differences between the old and new diagonal magnitudes will be stored in a DV object created -- 98aug27, cca ------------------------------------------------------------ */ void PatchAndGoInfo_init ( PatchAndGoInfo *info, int strategy, double toosmall, double fudge, int storeids, int storevalues ) { /* --------------- check the input --------------- */ if ( info == NULL || strategy < 1 || strategy > 2 || toosmall < 0.0 || fudge < 0.0 ) { fprintf(stderr, "\n fatal error in PatchAndGoInfo_init()" "\n bad input\n") ; exit(-1) ; } PatchAndGoInfo_clearData(info) ; info->strategy = strategy ; info->toosmall = toosmall ; info->fudge = fudge ; if ( storeids != 0 ) { info->fudgeIV = IV_new() ; } if ( strategy == 2 && storevalues != 0 ) { info->fudgeDV = DV_new() ; } return ; } /*--------------------------------------------------------------------*/ PatchAndGoInfo/doc/004275500020550007177000000000000657360567600154535ustar00clevecompmath00000400000006PatchAndGoInfo/doc/dataStructure.tex010064400020550007177000000015670657206367500210270ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:PatchAndGoInfo:dataStructure} \par \par The {\tt PatchAndGoInfo} structure has five fields. \begin{itemize} \item {\tt int strategy} : type of patch-and-go strategy \begin{itemize} \item {\tt 1} --- used with optimization matrices, if $|A_{i,i}| \le \mbox{\tt toosmall}$ then set $A_{i,i} = 1$ and $L_{j,i} = 0$ for $j > i$. \item {\tt 2} --- used with structural analysis matrices, if $|A_{i,i}| \le \mbox{\tt fudge}$ then set $A_{i,i} = \mbox{\tt fudge} \cdot \max\{1, \max_{j>i}\{ |A_{i,j}|, |A_{j,i}| \} \}$ \end{itemize} \item {\tt double toosmall} : cutoff for diagonal entry magnitude \item {\tt double fudge} : pertubation multiplier for modification \item {\tt IV *fudgeIV} : vector to collect locations of perturbations, may be {\tt NULL}. \item {\tt DV *fudgeDV} : vector to collect perturbations, may be {\tt NULL}. \end{itemize} PatchAndGoInfo/doc/main.log010064400020550007177000000116150657206343000170620ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=latex 96.6.20) 29 AUG 1998 13:39 **main (main.tex LaTeX2e <1996/06/01> Hyphenation patterns for english, german, loaded. (/usr/local/lib/texmf/tex/latex2e/base/latex209.def File: latex209.def 1996/05/21 v0.51 Standard LaTeX file Entering LaTeX 2.09 compatibility mode. \footheight=\dimen102 \@maxsep=\dimen103 \@dblmaxsep=\dimen104 \@cla=\count79 \@clb=\count80 \mscount=\count81 (/usr/local/lib/texmf/tex/latex2e/base/tracefnt.sty Package: tracefnt 1996/05/08 v3.0h Standard LaTeX package (font tracing) \tracingfonts=\count82 LaTeX Info: Redefining \selectfont on input line 139. ) \symbold=\mathgroup4 \symsans=\mathgroup5 \symtypewriter=\mathgroup6 \symitalic=\mathgroup7 \symsmallcaps=\mathgroup8 \symslanted=\mathgroup9 LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 307. LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 308. LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 309. LaTeX Font Info: Redeclaring math alphabet \mathit on input line 315. LaTeX Info: Redefining \em on input line 325. (/usr/local/lib/texmf/tex/latex2e/base/latexsym.sty Package: latexsym 1995/11/28 v2.2c Standard LaTeX package (lasy symbols) \symlasy=\mathgroup10 LaTeX Font Info: Overwriting symbol font `lasy' in version `bold' (Font) U/lasy/m/n --> U/lasy/b/n on input line 86. ) LaTeX Font Info: Redeclaring math delimiter \lgroup on input line 389. LaTeX Font Info: Redeclaring math delimiter \rgroup on input line 391. LaTeX Font Info: Redeclaring math delimiter \bracevert on input line 393. ) (/usr/local/lib/texmf/tex/latex2e/base/report.cls Document Class: report 1996/05/26 v1.3r Standard LaTeX document class (/usr/local/lib/texmf/tex/latex2e/base/leqno.clo File: leqno.clo 1996/03/25 v1.1a Standard LaTeX option (left equation numbers) ) (/usr/local/lib/texmf/tex/latex2e/base/size11.clo File: size11.clo 1996/05/26 v1.3r Standard LaTeX file (size option) ) \c@part=\count83 \c@chapter=\count84 \c@section=\count85 \c@subsection=\count86 \c@subsubsection=\count87 \c@paragraph=\count88 \c@subparagraph=\count89 \c@figure=\count90 \c@table=\count91 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 Compatibility mode: definition of \rm ignored. Compatibility mode: definition of \sf ignored. Compatibility mode: definition of \tt ignored. Compatibility mode: definition of \bf ignored. Compatibility mode: definition of \it ignored. Compatibility mode: definition of \sl ignored. Compatibility mode: definition of \sc ignored. LaTeX Info: Redefining \cal on input line 620. LaTeX Info: Redefining \mit on input line 621. \bibindent=\dimen105 ) \@indexfile=\write3 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. (intro.tex Chapter 1. LaTeX Font Info: External font `cmex10' loaded for size (Font) <10.95> on input line 15. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 15. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 15. LaTeX Font Info: Try loading font information for U+lasy on input line 15. (/usr/local/lib/texmf/tex/latex2e/base/Ulasy.fd File: Ulasy.fd 1995/11/28 v2.2cLaTeX symbol font definitions ) [1 ]) (dataStructure.tex LaTeX Font Info: Try loading font information for OML+cmr on input line 25. (/usr/local/lib/texmf/tex/latex2e/base/OMLcmr.fd File: OMLcmr.fd 1996/05/19 v2.4h Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OML/cmr/m/n' in size <10.95> not available (Font) Font shape `OML/cmm/m/it' tried instead on input line 25. ) (proto.tex [2] Overfull \hbox (11.7664pt too wide) in paragraph at lines 80--80 [][]\OT1/cmtt/m/n/10.95 void PatchAndGoInfo_init ( PatchAndGoInfo *info, int s trategy, double toosmall,[] [] ) (main.ind [3] [4 ]) (main.aux) ) Here is how much of TeX's memory you used: 444 strings out of 10922 4657 string characters out of 73125 49119 words of memory out of 262141 3311 multiletter control sequences out of 9500 14802 words of font info for 54 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 24i,7n,22p,228b,219s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (4 pages, 9484 bytes). PatchAndGoInfo/doc/intro.tex010064400020550007177000000054310657206366400173200ustar00clevecompmath00000400000006\chapter{{\tt PatchAndGoInfo}: Pivot Modification Object} \par On occasion, an application will demand specific behavior during a factorization. We have written the {\tt PatchAndGoInfo} object to communicate information to the {\tt Chv} object during a factorization of a front. Most users can ignore this object. However, if a different type of behavior is required, one could extend this object by adding a new strategy to it and modifying the {\tt Chv} methods that factor a front. \par Let us describe two strategies that we presently support. \begin{itemize} \item Primal-dual linear programming may require repeated factorizations of matrices of the form $AD^2A^T$, where $A$ comes from constraint equations and $D$ is a diagonal matrix. As the optimization proceeds, $AD^2A^T$ becomes increasingly ill-conditioned because the entries in $D$ go to zero or infinity. Normally, when a small or zero pivot element is detected, we would either signal an error (if we expected the matrix to be positive definite) or pivot for stability. However, in the primal-dual pivot context, a small or zero element on the diagonal is not a calamity. It signals that the variable associated with the small entry can be ``skipped'' in the solution process. There are several ways to implement this behavior. We have chosen a simple way: the diagonal entry is set to 1.0 and all off-diagonal entries in the corresponding column of $L$ are set to zero. \item In structural analysis, ``multi-point constraints'' are often applied to a linear system. At times, applying these constraints generates a matrix that is essentially singular. The singularity may be benign, as in the following case. $$ \left \lbrack \begin{array}{cc} A_{1,1} & 0 \\ 0 & A_{2,2} \end{array} \right \rbrack \left \lbrack \begin{array}{c} X_1 \\ X_2 \end{array} \right \rbrack = \left \lbrack \begin{array}{c} 0 \\ B_2 \end{array} \right \rbrack $$ If $A_{1,1}$ is singular, the solution $X_1 = 0$ and $X_2 = A_{2,2}^{-1} B_2$ is perfectly acceptable. In other cases, the location of the singularity can be communicated back to the user to supply useful information about the finite element model. One common practice is to not use pivoting, but to check the magnitude of the diagonal entry as a row and column is to be eliminated. If the magnitude is smaller than a user-supplied parameter, the diagonal entry is set to some multiple of the largest offdiagonal entry in that row and column of the front, the location and perturbation is noted, and the factorization proceeds. \end{itemize} \par Other strategies can be added to the {\tt PatchAndGoInfo} object. For example, if a matrix is being factored that is believed to be positive definite, and a negative value is found in a pivot element, one could abort the factorization, or perturb the element so that it is positive. PatchAndGoInfo/doc/main.tex010064400020550007177000000010720665065627600171120ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt PatchAndGoInfo} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt PatchAndGoInfo} : {\it DRAFT} \quad \today \hrulefill} \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} PatchAndGoInfo/doc/proto.tex010064400020550007177000000101230657206340100173070ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt PatchAndGoInfo} methods} \label{section:PatchAndGoInfo:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt PatchAndGoInfo} object. \par \subsection{Basic methods} \label{subsection:PatchAndGoInfo:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} PatchAndGoInfo * PatchAndGoInfo_new ( void ) ; \end{verbatim} \index{PatchAndGoInfo_new@{\tt PatchAndGoInfo\_new()}} This method simply allocates storage for the {\tt PatchAndGoInfo} structure and then sets the default fields by a call to {\tt PatchAndGoInfo\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void PatchAndGoInfo_setDefaultFields ( PatchAndGoInfo *info ) ; \end{verbatim} \index{PatchAndGoInfo_setDefaultFields@{\tt PatchAndGoInfo\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt strategy} = -1, {\tt toosmall} = {\tt fudge} = 0.0, and {\tt fudgeIV} = {\tt fudgeDV} = {\tt NULL} . \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void PatchAndGoInfo_clearData ( PatchAndGoInfo *info ) ; \end{verbatim} \index{PatchAndGoInfo_clearData@{\tt PatchAndGoInfo\_clearData()}} This method clears any data owned by the object. If {\tt fudgeIV} is not {\tt NULL} it is free'd by a call to {\tt IV\_free()}. If {\tt fudgeDV} is not {\tt NULL} it is free'd by a call to {\tt DV\_free()}. The structure's default fields are then set with a call to {\tt PatchAndGoInfo\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void PatchAndGoInfo_free ( PatchAndGoInfo *info ) ; \end{verbatim} \index{PatchAndGoInfo_free@{\tt PatchAndGoInfo\_free()}} This method releases any storage by a call to {\tt PatchAndGoInfo\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:PatchAndGoInfo:proto:initializers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void PatchAndGoInfo_init ( PatchAndGoInfo *info, int strategy, double toosmall, double fudge, int storeids, int storevalues ) ; \end{verbatim} \index{PatchAndGoInfo_init@{\tt PatchAndGoInfo\_init()}} This method initializes the object. Presently, two strategies are supported: {\tt strategy = 1} for optimization matrices and {\tt strategy = 2} for structural analysis matrices. {\tt toosmall} is the cutoff for diagonal entry modification, if an entry has magnitude less than {\tt toosmall} some action is taken. For the second strategy, the {\tt fudge} parameter contributes to the perturbation. When {\tt storeids} is not zero, the {\tt fudgeIV} object is created to accumulate the locations of the perturbations. When {\tt storevalues} is not zero, the {\tt fudgeDV} object is created to accumulate information on the perturbations themselves. \par \noindent {\it Error checking:} If {\tt info} is {\tt NULL} or {\tt strategy} is not 1 or 2, or {\tt toosmall} or {\tt fudge} are less than zero, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} PatchAndGoInfo/doc/main.idx010064400020550007177000000005450657206343000170650ustar00clevecompmath00000400000006\indexentry{PatchAndGoInfo_new@{\tt PatchAndGoInfo\_new()}}{2} \indexentry{PatchAndGoInfo_setDefaultFields@{\tt PatchAndGoInfo\_setDefaultFields()}}{2} \indexentry{PatchAndGoInfo_clearData@{\tt PatchAndGoInfo\_clearData()}}{3} \indexentry{PatchAndGoInfo_free@{\tt PatchAndGoInfo\_free()}}{3} \indexentry{PatchAndGoInfo_init@{\tt PatchAndGoInfo\_init()}}{3} PatchAndGoInfo/doc/main.aux010064400020550007177000000014440657206343000170750ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt PatchAndGoInfo}: Pivot Modification Object}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{2}} \newlabel{section:PatchAndGoInfo:dataStructure}{{1.1}{2}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt PatchAndGoInfo} methods}{2}} \newlabel{section:PatchAndGoInfo:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{2}} \newlabel{subsection:PatchAndGoInfo:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Initializer methods}{3}} \newlabel{subsection:PatchAndGoInfo:proto:initializers}{{1.2.2}{3}} PatchAndGoInfo/doc/main.ind010064400020550007177000000003720657206342100170510ustar00clevecompmath00000400000006\begin{theindex} \item {\tt PatchAndGoInfo\_clearData()}, 3 \item {\tt PatchAndGoInfo\_free()}, 3 \item {\tt PatchAndGoInfo\_init()}, 3 \item {\tt PatchAndGoInfo\_new()}, 2 \item {\tt PatchAndGoInfo\_setDefaultFields()}, 2 \end{theindex} PatchAndGoInfo/doc/main.ilg010064400020550007177000000004540657206342100170530ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (5 entries accepted, 0 rejected). Sorting entries....done (16 comparisons). Generating output file main.ind....done (9 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. PatchAndGoInfo/doc/makefile010064400020550007177000000000270657360562000171320ustar00clevecompmath00000400000006clean : - rm -f *.dvi Pencil.h010064400020550007177000000001040653410641000134460ustar00clevecompmath00000400000006#ifndef _Pencil_ #define _Pencil_ #include "Pencil/Pencil.h" #endif Pencil/Pencil.h010064400020550007177000000207320653410622500146750ustar00clevecompmath00000400000006/* Pencil.h */ #include "../InpMtx.h" #include "../DenseMtx.h" #include "../Drand.h" #include "../SPOOLES.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ this object stores a matrix pencil A + sigma * B created -- 98may02, cca ------------------------------------------------------------------ */ typedef struct _Pencil Pencil ; struct _Pencil { int type ; int symflag ; InpMtx *inpmtxA ; InpMtx *inpmtxB ; double sigma[2] ; } ; #define PENCIL_IS_REAL(pencil) ((pencil)->type == SPOOLES_REAL) #define PENCIL_IS_COMPLEX(pencil) ((pencil)->type == SPOOLES_COMPLEX) #define PENCIL_IS_SYMMETRIC(pencil) \ ((pencil)->symflag == SPOOLES_SYMMETRIC) #define PENCIL_IS_HERMITIAN(pencil) \ ((pencil)->symflag == SPOOLES_HERMITIAN) #define PENCIL_IS_NONSYMMETRIC(pencil) \ ((pencil)->symflag == SPOOLES_NONSYMMETRIC) /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ Pencil * Pencil_new ( void ) ; /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void Pencil_setDefaultFields ( Pencil *pencil ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void Pencil_clearData ( Pencil *pencil ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ Pencil * Pencil_free ( Pencil *pencil ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------- initialize the object created -- 98may02, cca ----------------------- */ void Pencil_init ( Pencil *pencil, int type, int symflag, InpMtx *inpmtxA, double sigma[], InpMtx *inpmtxB ) ; /* -------------------------- change the coordinate type created -- 98may02, cca -------------------------- */ void Pencil_changeCoordType ( Pencil *pencil, int newType ) ; /* ----------------------- change the storage mode created -- 98may02, cca ----------------------- */ void Pencil_changeStorageMode ( Pencil *pencil, int newMode ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in permute.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------- permute the matrix pencil created -- 98may02, cca ------------------------- */ void Pencil_permute ( Pencil *pencil, IV *rowOldToNewIV, IV *colOldToNewIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in mmm.c ------------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------- compute Y := Y + (A + sigma*B)*X created -- 98may02, cca -------------------------------- */ void Pencil_mmm ( Pencil *pencil, DenseMtx *Y, DenseMtx *X ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in setup.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------------------- initialize the matrix pencil A + sigma*B myid -- id of process, used in MPI implementation if myid = 0 then the pencil is loaded with the matrices read from the files else the pencil is loaded with the empty matrices endif symflag -- symmetry flag, PENCIL_SYMMETRIC -- symmetric PENCIL_HERMITIAN -- hermitian PENCIL_NONSYMMETRIC -- nonsymmetric if symmetric or hermitian, drop entries in lower triangle inpmtxAfile -- filename for A sigma -- scaling factor inpmtxBfile -- filename for B randomflag -- random flag, if 1 then fill with random numbers drand -- random number generator msglvl -- message level msgFile -- message file return value -- pointer to a Pencil object created -- 98may02, cca ---------------------------------------------------------------- */ Pencil * Pencil_setup ( int myid, int symflag, char *inpmtxAfile, double sigma[], char *inpmtxBfile, int randomflag, Drand *drand, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------------- sort and compress the pencil's entries created -- 98may02, cca -------------------------------------- */ void Pencil_sortAndCompress ( Pencil *pencil ) ; /* ------------------------------ convert the storage to vectors created -- 98may02, cca ------------------------------ */ void Pencil_convertToVectors ( Pencil *pencil ) ; /* ---------------------------------------------- map entries to the lower triangle, used after a permutation of a symmetric matrix created -- 98may02, cca ---------------------------------------------- */ void Pencil_mapToLowerTriangle ( Pencil *pencil ) ; /* ---------------------------------------------- map entries to the upper triangle, used after a permutation of a symmetric matrix created -- 98may02, cca ---------------------------------------------- */ void Pencil_mapToUpperTriangle ( Pencil *pencil ) ; /* ------------------------------------------------------------- purpose -- to return the full, symmetric adjacency IVL object for the graph of (A + B) + sigma * (A + B)^T created -- 98may02, cca ------------------------------------------------------------- */ IVL * Pencil_fullAdjacency ( Pencil *pencil ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------- purpose -- to read in a Pencil object from a file input -- fn -- filename, must be *.inpmtxb or *.inpmtxf return value -- 1 if success, 0 if failure created -- 98may02, cca -------------------------------------------------- */ int Pencil_readFromFiles ( Pencil *pencil, char *inpmtxAfileName, char *inpmtxBfileName ) ; /* ---------------------------------------------------- purpose -- to write a Pencil object for a human eye return value -- 1 if success, 0 otherwise created -- 98may02, cca ---------------------------------------------------- */ int Pencil_writeForHumanEye ( Pencil *pencil, FILE *fp ) ; /* ------------------------------------------------------------- purpose -- to write out the statistics for the Pencil object return value -- 1 if success, 0 otherwise created -- 98may02, cca ------------------------------------------------------------- */ int Pencil_writeStats ( Pencil *pencil, FILE *fp ) ; /*--------------------------------------------------------------------*/ Pencil/makefile010064400020550007177000000001410663622365400150130ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean Pencil/src/makefile010064400020550007177000000010150663602745600156050ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Pencil $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(mmm.o) \ $(OBJ).a(permute.o) \ $(OBJ).a(setup.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG Pencil/src/makeGlobalLib010064400020550007177000000006550660026112400165050ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Pencil SRC = basics.c \ init.c \ IO.c \ mmm.c \ permute.c \ setup.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Pencil/src/IO.c010064400020550007177000000067270653410622400145630ustar00clevecompmath00000400000006/* IO.c */ #include "../Pencil.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- to read in a Pencil object from a file input -- inpmtxAfileName -- filename for A, must be *.inpmtxb or *.inpmtxf inpmtxBfileName -- filename for B, must be *.inpmtxb or *.inpmtxf return value -- 1 if success, 0 if failure created -- 97jul18, cca ------------------------------------------------------------------- */ int Pencil_readFromFiles ( Pencil *pencil, char *inpmtxAfileName, char *inpmtxBfileName ) { int rc = 1 ; /* --------------- check the input --------------- */ if ( pencil == NULL || inpmtxAfileName == NULL || inpmtxBfileName == NULL ) { fprintf(stderr, "\n error in Pencil_readFromFile(%p,%s,%s)" "\n bad input\n", pencil, inpmtxAfileName, inpmtxBfileName) ; return(0) ; } if ( strcmp(inpmtxAfileName, "none") != 0 ) { rc = InpMtx_readFromFile(pencil->inpmtxA, inpmtxAfileName) ; if ( rc != 1 ) { return(rc) ; } } if ( strcmp(inpmtxBfileName, "none") != 0 ) { rc = InpMtx_readFromFile(pencil->inpmtxB, inpmtxBfileName) ; if ( rc != 1 ) { return(rc) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to write a Pencil object for a human eye return value -- 1 if success, 0 otherwise created -- 97jul18, cca ---------------------------------------------------- */ int Pencil_writeForHumanEye ( Pencil *pencil, FILE *fp ) { if ( pencil == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Pencil_writeForHumanEye(%p,%p)" "\n bad input\n", pencil, fp) ; exit(-1) ; } /* ------------------------ write out the statistics ------------------------ */ Pencil_writeStats(pencil, fp) ; if ( pencil->inpmtxA != NULL ) { fprintf(fp, "\n\n inpmtxA") ; InpMtx_writeForHumanEye(pencil->inpmtxA, fp) ; } if ( pencil->inpmtxB != NULL ) { fprintf(fp, "\n\n inpmtxB") ; InpMtx_writeForHumanEye(pencil->inpmtxB, fp) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- to write out the statistics for the Pencil object return value -- 1 if success, 0 otherwise created -- 97jul18, cca ------------------------------------------------------------- */ int Pencil_writeStats ( Pencil *pencil, FILE *fp ) { /* --------------- check the input --------------- */ if ( pencil == NULL || fp == NULL ) { fprintf(stderr, "\n error in Pencil_writeStats(%p,%p)" "\n bad input\n", pencil, fp) ; exit(-1) ; } fprintf(fp, "\n\n Pencil : matrix pencil object :") ; if ( PENCIL_IS_REAL(pencil) ) { fprintf(fp, " real entries") ; fprintf(fp, "\n sigma = %20.12e ", pencil->sigma[0]) ; } else if ( PENCIL_IS_COMPLEX(pencil) ) { fprintf(fp, " complex entries") ; fprintf(fp, "\n sigma = %20.12e + %20.12e*i", pencil->sigma[0], pencil->sigma[1]) ; } if ( pencil->inpmtxA != NULL ) { fprintf(fp, "\n\n inpmtxA") ; InpMtx_writeStats(pencil->inpmtxA, fp) ; } if ( pencil->inpmtxB != NULL ) { fprintf(fp, "\n\n inpmtxB") ; InpMtx_writeStats(pencil->inpmtxB, fp) ; } return(1) ; } /*--------------------------------------------------------------------*/ Pencil/src/basics.c010064400020550007177000000045320653410622400155100ustar00clevecompmath00000400000006/* basics.c */ #include "../Pencil.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ Pencil * Pencil_new ( void ) { Pencil *pencil ; ALLOCATE(pencil, struct _Pencil, 1) ; Pencil_setDefaultFields(pencil) ; return(pencil) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void Pencil_setDefaultFields ( Pencil *pencil ) { if ( pencil == NULL ) { fprintf(stderr, "\n fatal error in Pencil_setDefaultFields(%p)" "\n bad input", pencil) ; exit(-1) ; } pencil->type = SPOOLES_REAL ; pencil->symflag = SPOOLES_SYMMETRIC ; pencil->sigma[0] = 0.0 ; pencil->sigma[1] = 0.0 ; pencil->inpmtxA = NULL ; pencil->inpmtxB = NULL ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void Pencil_clearData ( Pencil *pencil ) { /* --------------- check the input --------------- */ if ( pencil == NULL ) { fprintf(stderr, "\n fatal error in Pencil_clearData(%p)" "\n bad input\n", pencil) ; exit(-1) ; } /* ----------------- free the matrices ----------------- */ if ( pencil->inpmtxA != NULL ) { InpMtx_free(pencil->inpmtxA) ; } if ( pencil->inpmtxB != NULL ) { InpMtx_free(pencil->inpmtxB) ; } /* ---------------------- set the default fields ---------------------- */ Pencil_setDefaultFields(pencil) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ Pencil * Pencil_free ( Pencil *pencil ) { if ( pencil == NULL ) { fprintf(stderr, "\n fatal error in Pencil_free(%p)" "\n bad input\n", pencil) ; exit(-1) ; } Pencil_clearData(pencil) ; FREE(pencil) ; return(NULL) ; } /*--------------------------------------------------------------------*/ Pencil/src/init.c010064400020550007177000000052100653410622400152010ustar00clevecompmath00000400000006/* init.c */ #include "../Pencil.h" /*--------------------------------------------------------------------*/ /* ----------------------- initialize the object created -- 98may02, cca ----------------------- */ void Pencil_init ( Pencil *pencil, int type, int symflag, InpMtx *inpmtxA, double sigma[], InpMtx *inpmtxB ) { /* --------------- check the input --------------- */ if ( pencil == NULL || sigma == NULL ) { fprintf(stderr, "\n fatal error in Pencil_init(%p,%d,%d,%p,%p,%p)" "\n bad input\n", pencil, type, symflag, inpmtxA, sigma, inpmtxB) ; exit(-1) ; } if ( !(type == SPOOLES_REAL || type == SPOOLES_COMPLEX) ) { fprintf(stderr, "\n fatal error in Pencil_init(%p,%d,%d,%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", pencil, type, symflag, inpmtxA, sigma, inpmtxB, type) ; exit(-1) ; } if ( !(symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN || symflag == SPOOLES_NONSYMMETRIC) ) { fprintf(stderr, "\n fatal error in Pencil_init(%p,%d,%d,%p,%p,%p)" "\n bad symflag %d, must be SPOOLES_SYMMETRIC," "\n SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC\n", pencil, type, symflag, inpmtxA, sigma, inpmtxB, symflag) ; exit(-1) ; } /* ------------------------ clear the data structure ------------------------ */ Pencil_clearData(pencil) ; /* -------------- set the fields -------------- */ pencil->type = type ; pencil->symflag = symflag ; pencil->inpmtxA = inpmtxA ; pencil->sigma[0] = sigma[0] ; pencil->sigma[1] = sigma[1] ; pencil->inpmtxB = inpmtxB ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------- change the coordinate type created -- 98may02, cca -------------------------- */ void Pencil_changeCoordType ( Pencil *pencil, int newType ) { if ( pencil->inpmtxA != NULL ) { InpMtx_changeCoordType(pencil->inpmtxA, newType) ; } if ( pencil->inpmtxB != NULL ) { InpMtx_changeCoordType(pencil->inpmtxB, newType) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------- change the storage mode created -- 98may02, cca ----------------------- */ void Pencil_changeStorageMode ( Pencil *pencil, int newMode ) { if ( pencil->inpmtxA != NULL ) { InpMtx_changeStorageMode(pencil->inpmtxA, newMode) ; } if ( pencil->inpmtxB != NULL ) { InpMtx_changeStorageMode(pencil->inpmtxB, newMode) ; } return ; } /*--------------------------------------------------------------------*/ Pencil/src/mmm.c010064400020550007177000000127060656467412100150450ustar00clevecompmath00000400000006/* mmm.c */ #include "../Pencil.h" /*--------------------------------------------------------------------*/ /* -------------------------------- compute Y := Y + (A + sigma*B)*X created -- 98may02, cca -------------------------------- */ void Pencil_mmm ( Pencil *pencil, DenseMtx *Y, DenseMtx *X ) { int ncolX, ncolY, nrhs, nrow, nrowX, nrowY ; /* --------------- check the input --------------- */ if ( pencil == NULL || Y == NULL || X == NULL ) { fprintf(stderr, "\n fatal error in Pencil_mmm(%p,%p,%p)" "\n bad input\n", pencil, Y, X) ; exit(-1) ; } if ( !(PENCIL_IS_REAL(pencil) || PENCIL_IS_COMPLEX(pencil)) ) { fprintf(stderr, "\n fatal error in Pencil_mmm(%p,%p,%p)" "\n bad type %d for pencil\n", pencil, Y, X, pencil->type) ; exit(-1) ; } if ( !(DENSEMTX_IS_REAL(Y) || DENSEMTX_IS_COMPLEX(Y)) ) { fprintf(stderr, "\n fatal error in Pencil_mmm(%p,%p,%p)" "\n bad type %d for Y\n", pencil, Y, X, Y->type) ; exit(-1) ; } if ( !(DENSEMTX_IS_REAL(X) || DENSEMTX_IS_COMPLEX(X)) ) { fprintf(stderr, "\n fatal error in Pencil_mmm(%p,%p,%p)" "\n bad type %d for X\n", pencil, Y, X, X->type) ; exit(-1) ; } if ( PENCIL_IS_REAL(pencil) && !DENSEMTX_IS_REAL(Y) ) { fprintf(stderr, "\n fatal error in Pencil_mmm(%p,%p,%p)" "\n pencil is real, Y is not\n", pencil, Y, X) ; exit(-1) ; } if ( PENCIL_IS_REAL(pencil) && !DENSEMTX_IS_REAL(X) ) { fprintf(stderr, "\n fatal error in Pencil_mmm(%p,%p,%p)" "\n pencil is real, X is not\n", pencil, Y, X) ; exit(-1) ; } if ( PENCIL_IS_COMPLEX(pencil) && !DENSEMTX_IS_COMPLEX(Y) ) { fprintf(stderr, "\n fatal error in Pencil_mmm(%p,%p,%p)" "\n pencil is complex, Y is not\n", pencil, Y, X) ; exit(-1) ; } if ( PENCIL_IS_COMPLEX(pencil) && !DENSEMTX_IS_COMPLEX(X) ) { fprintf(stderr, "\n fatal error in Pencil_mmm(%p,%p,%p)" "\n pencil is complex, X is not\n", pencil, Y, X) ; exit(-1) ; } DenseMtx_dimensions(Y, &nrowY, &ncolY) ; DenseMtx_dimensions(X, &nrowX, &ncolX) ; if ( nrowY != nrowX || ncolY != ncolX ) { fprintf(stderr, "\n fatal error in Pencil_mmm(%p,%p,%p)" "\n nrowY %d, ncolY %d, nrowX %d, ncolX %d\n", pencil, Y, X, nrowY, ncolY, nrowX, ncolX) ; exit(-1) ; } nrow = nrowY ; nrhs = ncolY ; if ( pencil->inpmtxA == NULL ) { /* ----------------- A is the identity ----------------- */ if ( PENCIL_IS_REAL(pencil) ) { double *x, *y ; int irow, jrhs ; x = DenseMtx_entries(X) ; y = DenseMtx_entries(Y) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( irow = 0 ; irow < nrow ; irow++ ) { y[irow] += x[irow] ; } x += nrow ; y += nrow ; } } else if ( PENCIL_IS_COMPLEX(pencil) ) { double *x, *y ; int irow, jrhs ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( irow = 0 ; irow < nrow ; irow++ ) { y[2*irow] += x[2*irow] ; y[2*irow+1] += x[2*irow+1] ; } x += 2*nrow ; y += 2*nrow ; } } } else { double alpha[2] ; /* ---------------------------------------- A is not the identity, multiply x with A ---------------------------------------- */ alpha[0] = 1.0 ; alpha[1] = 0.0 ; if ( PENCIL_IS_SYMMETRIC(pencil) ) { InpMtx_sym_mmm(pencil->inpmtxA, Y, alpha, X) ; } else if ( PENCIL_IS_HERMITIAN(pencil) ) { InpMtx_herm_mmm(pencil->inpmtxA, Y, alpha, X) ; } else if ( PENCIL_IS_NONSYMMETRIC(pencil) ) { InpMtx_nonsym_mmm(pencil->inpmtxA, Y, alpha, X) ; } } if ( pencil->sigma[0] != 0.0 || pencil->sigma[1] != 0.0 ) { if ( pencil->inpmtxB != NULL ) { /* ----------------------------------------- B is not the identity, add sigma*B*x to y ----------------------------------------- */ if ( PENCIL_IS_SYMMETRIC(pencil) ) { InpMtx_sym_mmm(pencil->inpmtxB, Y, pencil->sigma, X) ; } else if ( PENCIL_IS_HERMITIAN(pencil) ) { InpMtx_herm_mmm(pencil->inpmtxB, Y, pencil->sigma, X) ; } else if ( PENCIL_IS_NONSYMMETRIC(pencil) ) { InpMtx_nonsym_mmm(pencil->inpmtxB, Y, pencil->sigma, X) ; } } else { /* ----------------------------------- B is the identity, add sigma*x to y ----------------------------------- */ if ( PENCIL_IS_REAL(pencil) ) { double sigmareal ; double *x, *y ; int irow, jrhs ; x = DenseMtx_entries(X) ; y = DenseMtx_entries(Y) ; sigmareal = pencil->sigma[0] ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( irow = 0 ; irow < nrow ; irow++ ) { y[irow] += sigmareal*x[irow] ; } x += nrow ; y += nrow ; } } else if ( PENCIL_IS_COMPLEX(pencil) ) { double sigmaimag, sigmareal, ximag, xreal ; double *x, *y ; int irow, jrhs ; x = DenseMtx_entries(X) ; y = DenseMtx_entries(Y) ; sigmareal = pencil->sigma[0] ; sigmaimag = pencil->sigma[1] ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { for ( irow = 0 ; irow < nrow ; irow++ ) { xreal = x[2*irow] ; ximag = x[2*irow+1] ; y[2*irow] += sigmareal*xreal - sigmaimag*ximag ; y[2*irow+1] += sigmareal*ximag + sigmaimag*xreal ; } x += 2*nrow ; y += 2*nrow ; } } } } return ; } /*--------------------------------------------------------------------*/ Pencil/src/permute.c010064400020550007177000000013560653410622400157260ustar00clevecompmath00000400000006/* permute.c */ #include "../Pencil.h" /*--------------------------------------------------------------------*/ /* ------------------------- permute the matrix pencil created -- 98may02, cca ------------------------- */ void Pencil_permute ( Pencil *pencil, IV *rowOldToNewIV, IV *colOldToNewIV ) { if ( pencil->inpmtxA != NULL ) { InpMtx_permute(pencil->inpmtxA, IV_entries(rowOldToNewIV), IV_entries(colOldToNewIV)) ; } if ( pencil->inpmtxB != NULL ) { InpMtx_permute(pencil->inpmtxB, IV_entries(rowOldToNewIV), IV_entries(colOldToNewIV)) ; } return ; } /*--------------------------------------------------------------------*/ Pencil/src/setup.c010064400020550007177000000221070653410622400154020ustar00clevecompmath00000400000006/* setup.c */ #include "../Pencil.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- initialize the matrix pencil A + sigma*B myid -- id of process, used in MPI implementation if myid = 0 then the pencil is loaded with the matrices read from the files else the pencil is loaded with the empty matrices endif symflag -- symmetry flag, SPOOLES_SYMMETRIC -- symmetric SPOOLES_HERMITIAN -- hermitian SPOOLES_NONSYMMETRIC -- nonsymmetric if symmetric or hermitian, drop entries in lower triangle inpmtxAfile -- filename for A sigma -- scaling factor inpmtxBfile -- filename for B randomflag -- random flag, if 1 then fill with random numbers drand -- random number generator msglvl -- message level msgFile -- message file return value -- pointer to a Pencil object created -- 98may02, cca ---------------------------------------------------------------- */ Pencil * Pencil_setup ( int myid, int symflag, char *inpmtxAfile, double sigma[], char *inpmtxBfile, int randomflag, Drand *drand, int msglvl, FILE *msgFile ) { InpMtx *inpmtxA, *inpmtxB ; double t1, t2 ; Pencil *pencil ; int rc ; switch ( symflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n fatal error in Pencil_setup()" "\n bad symflag %d\n", symflag) ; exit(-1) ; break ; } if ( strcmp(inpmtxAfile, "none") != 0 ) { /* -------------------------- read in the InpMtx object -------------------------- */ inpmtxA = InpMtx_new() ; if ( myid == 0 ) { MARKTIME(t1) ; rc = InpMtx_readFromFile(inpmtxA, inpmtxAfile) ; MARKTIME(t2) ; fprintf(msgFile,"\n CPU %8.3f : read in inpmtxA", t2 - t1) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from InpMtx_readFromFile(%p,%s)", rc, inpmtxA, inpmtxAfile) ; exit(-1) ; } if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ){ /* ---------------------------------------------------- symmetric matrix, drop entries in the lower triangle ---------------------------------------------------- */ MARKTIME(t1) ; InpMtx_dropLowerTriangle(inpmtxA) ; InpMtx_changeStorageMode(inpmtxA, 1) ; /* ------------------------------------ sort and compress the matrix entries ------------------------------------ */ InpMtx_sortAndCompress(inpmtxA) ; MARKTIME(t2) ; fprintf(msgFile,"\n CPU %8.3f : initialize inpmtxA", t2 - t1) ; } if ( randomflag == 1 ) { /* ----------------------------------- fill the matrix with random numbers ----------------------------------- */ MARKTIME(t1) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtxA) ) { Drand_fillDvector(drand, inpmtxA->nent, DV_entries(&inpmtxA->dvecDV)) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtxA) ) { Drand_fillDvector(drand, 2*inpmtxA->nent, DV_entries(&inpmtxA->dvecDV)) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : fill inpmtxA with random numbers", t2 - t1) ; } else if ( randomflag == -1 ) { /* ----------------------------- double one entry in magnitude ----------------------------- */ double *dvec = DV_entries(&inpmtxA->dvecDV) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtxA) ) { dvec[0] *= 2 ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtxA) ) { dvec[0] *= 2 ; dvec[1] *= 2 ; } } } /* -------------------------------------- change the coordinate type to chevrons and the storage mode to sorted triples -------------------------------------- */ MARKTIME(t1) ; InpMtx_changeCoordType(inpmtxA, 3) ; InpMtx_changeStorageMode(inpmtxA, 2) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : change inpmtxA to chevrons", t2 - t1) ; } else { inpmtxA = NULL ; } if ( strcmp(inpmtxBfile, "none") != 0 ) { /* -------------------------- read in the InpMtx object -------------------------- */ inpmtxB = InpMtx_new() ; if ( myid == 0 ) { MARKTIME(t1) ; rc = InpMtx_readFromFile(inpmtxB, inpmtxBfile) ; MARKTIME(t2) ; fprintf(msgFile,"\n CPU %8.3f : read in inpmtxB", t2 - t1) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from InpMtx_readFromFile(%p,%s)", rc, inpmtxB, inpmtxBfile) ; exit(-1) ; } if ( symflag == SPOOLES_SYMMETRIC || symflag == SPOOLES_HERMITIAN ){ /* ---------------------------------------------------- symmetric matrix, drop entries in the lower triangle ---------------------------------------------------- */ MARKTIME(t1) ; InpMtx_dropLowerTriangle(inpmtxB) ; InpMtx_changeStorageMode(inpmtxB, 1) ; /* ------------------------------------ sort and compress the matrix entries ------------------------------------ */ InpMtx_sortAndCompress(inpmtxB) ; MARKTIME(t2) ; fprintf(msgFile,"\n CPU %8.3f : initialize inpmtxB", t2 - t1) ; } if ( randomflag == 1 ) { /* ----------------------------------- fill the matrix with random numbers ----------------------------------- */ MARKTIME(t1) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtxA) ) { Drand_fillDvector(drand, inpmtxB->nent, DV_entries(&inpmtxB->dvecDV)) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtxA) ) { Drand_fillDvector(drand, 2*inpmtxB->nent, DV_entries(&inpmtxB->dvecDV)) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : fill inpmtxB with random numbers", t2 - t1) ; } else if ( randomflag == -1 ) { /* ----------------------------- double one entry in magnitude ----------------------------- */ double *dvec = DV_entries(&inpmtxB->dvecDV) ; if ( INPMTX_IS_REAL_ENTRIES(inpmtxA) ) { dvec[0] *= 2 ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtxA) ) { dvec[0] *= 2 ; dvec[1] *= 2 ; } } } /* -------------------------------------- change the coordinate type to chevrons and the storage mode to sorted triples -------------------------------------- */ MARKTIME(t1) ; InpMtx_changeCoordType(inpmtxB, 3) ; InpMtx_changeStorageMode(inpmtxB, 2) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : change inpmtxB to chevrons", t2 - t1) ; } else { inpmtxB = NULL ; } /* ----------------------------- initialize the Pencil object ----------------------------- */ if ( inpmtxA != NULL && inpmtxB != NULL ) { if ( inpmtxA->inputMode != inpmtxB->inputMode ) { fprintf(stderr, "\n fatal error in Pencil_setup()" "\n inpmtxA->inputMode = %d, inpmtxB->inputMode = %d\n", inpmtxA->inputMode, inpmtxB->inputMode) ; exit(-1) ; } if ( INPMTX_IS_REAL_ENTRIES(inpmtxA) ) { pencil = Pencil_new() ; Pencil_init(pencil, SPOOLES_REAL, symflag, inpmtxA, sigma, inpmtxB) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtxA) ) { pencil = Pencil_new() ; Pencil_init(pencil, SPOOLES_COMPLEX, symflag, inpmtxA, sigma, inpmtxB) ; } else { fprintf(stderr, "\n fatal error in Pencil_setup()" "\n inpmtxA->inputMode = %d\n", inpmtxA->inputMode) ; exit(-1) ; } } else if ( inpmtxA != NULL ) { if ( INPMTX_IS_REAL_ENTRIES(inpmtxA) ) { pencil = Pencil_new() ; Pencil_init(pencil, SPOOLES_REAL, symflag, inpmtxA, sigma, inpmtxB) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtxA) ) { pencil = Pencil_new() ; Pencil_init(pencil, SPOOLES_COMPLEX, symflag, inpmtxA, sigma, inpmtxB) ; } else { fprintf(stderr, "\n fatal error in Pencil_setup()" "\n inpmtxA->inputMode = %d\n", inpmtxA->inputMode) ; exit(-1) ; } } else if ( inpmtxB != NULL ) { if ( INPMTX_IS_REAL_ENTRIES(inpmtxB) ) { pencil = Pencil_new() ; Pencil_init(pencil, SPOOLES_REAL, symflag, inpmtxA, sigma, inpmtxB) ; } else if ( INPMTX_IS_COMPLEX_ENTRIES(inpmtxB) ) { pencil = Pencil_new() ; Pencil_init(pencil, SPOOLES_COMPLEX, symflag, inpmtxA, sigma, inpmtxB) ; } else { fprintf(stderr, "\n fatal error in Pencil_setup()" "\n inpmtxB->inputMode = %d\n", inpmtxB->inputMode) ; exit(-1) ; } } return(pencil) ; } /*--------------------------------------------------------------------*/ Pencil/src/util.c010064400020550007177000000064040653633437000152300ustar00clevecompmath00000400000006/* util.c */ #include "../Pencil.h" /*--------------------------------------------------------------------*/ /* -------------------------------------- sort and compress the pencil's entries created -- 98may02, cca -------------------------------------- */ void Pencil_sortAndCompress ( Pencil *pencil ) { if ( pencil->inpmtxA != NULL ) { InpMtx_sortAndCompress(pencil->inpmtxA) ; } if ( pencil->inpmtxB != NULL ) { InpMtx_sortAndCompress(pencil->inpmtxB) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------ convert the storage to vectors created -- 98may02, cca ------------------------------ */ void Pencil_convertToVectors ( Pencil *pencil ) { if ( pencil->inpmtxA != NULL ) { InpMtx_convertToVectors(pencil->inpmtxA) ; } if ( pencil->inpmtxB != NULL ) { InpMtx_convertToVectors(pencil->inpmtxB) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- map entries to the lower triangle, used after a permutation of a symmetric matrix created -- 98may02, cca ---------------------------------------------- */ void Pencil_mapToLowerTriangle ( Pencil *pencil ) { if ( pencil->inpmtxA != NULL ) { InpMtx_mapToLowerTriangle(pencil->inpmtxA) ; } if ( pencil->inpmtxB != NULL ) { InpMtx_mapToLowerTriangle(pencil->inpmtxB) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- map entries to the upper triangle, used after a permutation of a symmetric matrix created -- 98may02, cca ---------------------------------------------- */ void Pencil_mapToUpperTriangle ( Pencil *pencil ) { if ( pencil->inpmtxA != NULL ) { InpMtx_mapToUpperTriangle(pencil->inpmtxA) ; } if ( pencil->inpmtxB != NULL ) { InpMtx_mapToUpperTriangle(pencil->inpmtxB) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- to return the full, symmetric adjacency IVL object for the graph of (A + B) + sigma * (A + B)^T created -- 98may02, cca ------------------------------------------------------------- */ IVL * Pencil_fullAdjacency ( Pencil *pencil ) { IVL *adjIVL ; /* --------------- check the input --------------- */ if ( pencil == NULL ) { fprintf(stderr, "\n fatal error in Pencil_fullAdjacency(%p)" "\n NULL input\n\n", pencil) ; exit(-1) ; } if ( pencil->sigma[0] == 0.0 && pencil->sigma[1] == 0.0 ) { if ( pencil->inpmtxA == NULL ) { fprintf(stderr, "\n fatal error in Pencil_fullAdjacency(%p)" "\n pencil is identity \n\n", pencil) ; exit(-1) ; } else { adjIVL = InpMtx_fullAdjacency(pencil->inpmtxA) ; } } else { if ( pencil->inpmtxB == NULL ) { adjIVL = InpMtx_fullAdjacency(pencil->inpmtxA) ; } else if ( pencil->inpmtxA == NULL ) { adjIVL = InpMtx_fullAdjacency(pencil->inpmtxB) ; } else { adjIVL = InpMtx_fullAdjacency2(pencil->inpmtxA, pencil->inpmtxB); } } return(adjIVL) ; } /*--------------------------------------------------------------------*/ Pencil/doc/004275500020550007177000000000000654276745100140755ustar00clevecompmath00000400000006Pencil/doc/dataStructure.tex010064400020550007177000000017120653633353700174420ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:Pencil:dataStructure} \par \par The {\tt Pencil} structure has the following fields. \begin{itemize} \item {\tt int type} : type of matrix entries, \begin{itemize} \item {\tt SPOOLES\_REAL} for real entries \item {\tt SPOOLES\_COMPLEX} for complex entries \end{itemize} \item {\tt int symflag} : type of symmetry present in the matrices \begin{itemize} \item {\tt SPOOLES\_SYMMETRIC} for real or complex symmetric matrices \item {\tt SPOOLES\_HERMITIAN} for complex Hermitian matrices \item {\tt SPOOLES\_NONSYMMETRIC} for real or complex nonsymmetric matrices \end{itemize} \item {\tt InpMtx *inpmtxA} : pointer to the matrix object for $A$. If {\tt inpmtxA} is {\tt NULL}, then $A$ is the identity matrix. \item {\tt InpMtx *inpmtxB} : pointer to the matrix object for $B$. If {\tt inpmtxB} is {\tt NULL}, then $B$ is the identity matrix. \item {\tt double sigma[2]} : real or complex scalar shift value. \end{itemize} Pencil/doc/intro.tex010064400020550007177000000003510654224450300157300ustar00clevecompmath00000400000006\par \chapter{{\tt Pencil}: Matrix pencil} \par This object stores a matrix pencil $A + \sigma B$. $A$ and $B$ are both stored as {\tt InpMtx} objects. Many of the {\tt Pencil} methods simply call the equivalent {\tt InpMtx} method. Pencil/doc/main.tex010064400020550007177000000011260665065630200155260ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \newcommand{\bnd}{{\partial}} \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Chv} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Chv} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} Pencil/doc/proto.tex010064400020550007177000000240670653633445500157630ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Pencil} methods} \label{section:Pencil:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Pencil} object. \par \subsection{Basic methods} \label{subsection:Pencil:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Pencil * Pencil_new ( void ) ; \end{verbatim} \index{Pencil_new@{\tt Pencil\_new()}} This method simply allocates storage for the {\tt Pencil} structure and then sets the default fields by a call to {\tt Pencil\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_setDefaultFields ( Pencil *pencil ) ; \end{verbatim} \index{Pencil_setDefaultFields@{\tt Pencil\_setDefaultFields()}} The structure's fields are set to default values: {\tt sigma[2] = \{0,0\}}, {\tt type} = {\tt SPOOLES\_REAL}, {\tt symflag} = {\tt SPOOLES\_SYMMETRIC}, and {\tt inpmtxA} = {\tt inpmtxB} = {\tt NULL} . \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_clearData ( Pencil *pencil ) ; \end{verbatim} \index{Pencil_clearData@{\tt Pencil\_clearData()}} This method clears the object and free's any owned data by invoking the {\tt InpMtx\_free()} method for the {\tt inpmtxA} and {\tt inpmtxB} objects. There is a concluding call to {\tt Pencil\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_free ( Pencil *pencil ) ; \end{verbatim} \index{Pencil_free@{\tt Pencil\_free()}} This method releases any storage by a call to {\tt Pencil\_clearData()} and then free the space for {\tt pencil}. \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization methods} \label{subsection:Pencil:proto:initial} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_init( Pencil *pencil, int type, int symflag, InpMtx *inpmtxA, double sigma[], InpMtx *inpmtxB ) ; \end{verbatim} \index{Pencil_init@{\tt Pencil\_init()}} The fields of the pencil object are set to the input parameters. \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:Pencil:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_changeCoordType ( Pencil *pencil, int newType ) ; \end{verbatim} \index{Pencil_changeCoordType@{\tt Pencil\_changeCoordType()}} This method simply calls the {\tt InpMtx\_changeCoordType()} method for each of its two matrices. \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_changeStorageMode ( Pencil *pencil, int newMode ) ; \end{verbatim} \index{Pencil_changeStorageMode@{\tt Pencil\_changeStorageMode()}} This method simply calls the {\tt InpMtx\_changeStorageMode()} method for each of its two matrices. \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_sortAndCompress ( Pencil *pencil ) ; \end{verbatim} \index{Pencil_sortAndCompress@{\tt Pencil\_sortAndCompress()}} This method simply calls the {\tt InpMtx\_sortAndCompress()} method for each of its two matrices. \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_convertToVectors ( Pencil *pencil ) ; \end{verbatim} \index{Pencil_convertToVectors@{\tt Pencil\_convertToVectors()}} This method simply calls the {\tt InpMtx\_sortAndCompress()} method for each of its two matrices. \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_mapToLowerTriangle ( Pencil *pencil ) ; \end{verbatim} \index{Pencil_mapToLowerTriangle@{\tt Pencil\_mapToLowerTriangle()}} This method simply calls the {\tt InpMtx\_mapToLowerTriangle()} method for each of its two matrices. \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_mapToUpperTriangle ( Pencil *pencil ) ; \end{verbatim} \index{Pencil_mapToUpperTriangle@{\tt Pencil\_mapToUpperTriangle()}} This method simply calls the {\tt InpMtx\_mapToUpperTriangle()} method for each of its two matrices. \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_permute ( Pencil *pencil, IV *rowOldToNewIV, IV *colOldToNewIV ) ; \end{verbatim} \index{Pencil_permute@{\tt Pencil\_permute()}} This method simply calls the {\tt InpMtx\_permute()} method for each of its two matrices. \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_mmm ( Pencil *pencil, DenseMtx *Y, DenseMtx *X ) ; \end{verbatim} \index{Pencil_mmm@{\tt Pencil\_mmm()}} This method is used to compute $X = (A + \sigma B)X$. \par \noindent {\it Error checking:} If {\tt pencil}, {\tt X} or {\tt Y} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * Pencil_fullAdjacency ( Pencil *pencil ) ; \end{verbatim} \index{Pencil_fullAdjacency@{\tt Pencil\_fullAdjacency()}} This method returns an IVL object that holds the full adjacency structure of $(A + \sigma B) + (A + \sigma B)^T$. \par \noindent {\it Error checking:} If {\tt pencil} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:Pencil:proto:IO} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Pencil * Pencil_setup ( int myid, int symflag, char *inpmtxAfile, double sigma[], char *inpmtxBfile, int randomflag, Drand *drand, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{Pencil_setup@{\tt Pencil\_setup()}} \par This method is used to read in the matrices from two files and initialize the objects. If the file name is ``none'', then no matrix is read. If {\tt symflag} is {\tt SPOOLES\_SYMMETRIC} or {\tt SPOOLES\_HERMITIAN}, entries in the lower triangle are dropped. If {\tt randomflag} is one, the entries are filled with random numbers using the {\tt Drand} random number generator {\tt drand}. \par {\bf Note:} this method was created for an MPI application. If {\tt myid} is zero, then the files are read in, otherwise just stubs are created for the internal matrix objects. In our MPI drivers, process zero reads in the matrices and then starts the process to distribute them to the other processes. \par \noindent {\it Error checking:} If {\tt pencil} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Pencil_readFromFiles ( Pencil *pencil, char *fnA, char *fnB ) ; \end{verbatim} \index{Pencil_readFromFiles@{\tt Pencil\_readFromFiles()}} \par This method reads the two {\tt InpMtx} objects from two files. If {\tt fnA} is ``{\tt none}'', then $A$ is not read. If {\tt fnB} is ``{\tt none}'', then $B$ is not read. \par \noindent {\it Error checking:} If {\tt pencil} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_writeForHumanEye ( Pencil *pencil, FILE *fp ) ; \end{verbatim} \index{Pencil_writeForHumanEye@{\tt Pencil\_writeForHumanEye()}} \par This method writes a {\tt Pencil} object to a file in an easily readable format. \par \noindent {\it Error checking:} If {\tt pencil} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void Pencil_writeStats ( Pencil *pencil, FILE *fp ) ; \end{verbatim} \index{Pencil_writeStats@{\tt Pencil\_writeStats()}} \par This method writes statistics for {\tt Pencil} object to a file. \par \noindent {\it Error checking:} If {\tt pencil} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} Pencil/doc/makefile010064400020550007177000000000270654276745100155670ustar00clevecompmath00000400000006clean : - rm -f *.dvi Pencil/doc/main.log010064400020550007177000000034640653634332100155130ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 6 JUN 1998 15:46 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) (/usr/local/lib/texmf/tex/generic/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen100 \p@intvaluey=\dimen101 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 2. ) (dataStructure.tex) (proto.tex [1 ] Overfull \hbox (54.03828pt too wide) in paragraph at lines 46--50 \elvrm method for the \elvtt inpmtxA \elvrm and \elvtt inpmtxB \elvrm ob-jects. There is a con-clud-ing call to \elvtt Pencil[]setDefaultFields()\elvrm . \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\elvrm m .\elvrm e .\elvrm t .\elvrm h .\elvrm o .etc. [2] [3]) (main.ind [4] [5 ]) (main.aux) ) Here is how much of TeX's memory you used: 421 strings out of 11977 4261 string characters out of 87269 37715 words of memory out of 262141 2356 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,5n,17p,183b,199s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (5 pages, 11136 bytes). Pencil/doc/main.idx010064400020550007177000000021660653634332100155140ustar00clevecompmath00000400000006\indexentry{Pencil_new@{\tt Pencil\_new()}}{2} \indexentry{Pencil_setDefaultFields@{\tt Pencil\_setDefaultFields()}}{2} \indexentry{Pencil_clearData@{\tt Pencil\_clearData()}}{2} \indexentry{Pencil_free@{\tt Pencil\_free()}}{2} \indexentry{Pencil_init@{\tt Pencil\_init()}}{2} \indexentry{Pencil_changeCoordType@{\tt Pencil\_changeCoordType()}}{2} \indexentry{Pencil_changeStorageMode@{\tt Pencil\_changeStorageMode()}}{2} \indexentry{Pencil_sortAndCompress@{\tt Pencil\_sortAndCompress()}}{3} \indexentry{Pencil_convertToVectors@{\tt Pencil\_convertToVectors()}}{3} \indexentry{Pencil_mapToLowerTriangle@{\tt Pencil\_mapToLowerTriangle()}}{3} \indexentry{Pencil_mapToUpperTriangle@{\tt Pencil\_mapToUpperTriangle()}}{3} \indexentry{Pencil_permute@{\tt Pencil\_permute()}}{3} \indexentry{Pencil_mmm@{\tt Pencil\_mmm()}}{3} \indexentry{Pencil_fullAdjacency@{\tt Pencil\_fullAdjacency()}}{3} \indexentry{Pencil_setup@{\tt Pencil\_setup()}}{3} \indexentry{Pencil_readFromFiles@{\tt Pencil\_readFromFiles()}}{4} \indexentry{Pencil_writeForHumanEye@{\tt Pencil\_writeForHumanEye()}}{4} \indexentry{Pencil_writeStats@{\tt Pencil\_writeStats()}}{4} Pencil/doc/main.aux010064400020550007177000000023540653634332000155230ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space Pencil}: \penalty -\@M Matrix pencil}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:Pencil:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space Pencil} methods}{1}} \newlabel{section:Pencil:proto}{{1.2}{1}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:Pencil:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initialization methods}{2}} \newlabel{subsection:Pencil:proto:initial}{{1.2.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{2}} \newlabel{subsection:Pencil:proto:utilities}{{1.2.3}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}IO methods}{3}} \newlabel{subsection:Pencil:proto:IO}{{1.2.4}{3}} Pencil/doc/main.ind010064400020550007177000000013440653634331600155030ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Pencil\_changeCoordType()}, 2 \item {\tt Pencil\_changeStorageMode()}, 2 \item {\tt Pencil\_clearData()}, 2 \item {\tt Pencil\_convertToVectors()}, 3 \item {\tt Pencil\_free()}, 2 \item {\tt Pencil\_fullAdjacency()}, 3 \item {\tt Pencil\_init()}, 2 \item {\tt Pencil\_mapToLowerTriangle()}, 3 \item {\tt Pencil\_mapToUpperTriangle()}, 3 \item {\tt Pencil\_mmm()}, 3 \item {\tt Pencil\_new()}, 2 \item {\tt Pencil\_permute()}, 3 \item {\tt Pencil\_readFromFiles()}, 4 \item {\tt Pencil\_setDefaultFields()}, 2 \item {\tt Pencil\_setup()}, 3 \item {\tt Pencil\_sortAndCompress()}, 3 \item {\tt Pencil\_writeForHumanEye()}, 4 \item {\tt Pencil\_writeStats()}, 4 \end{theindex} Pencil/doc/main.ilg010064400020550007177000000004560653634331600155070ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (18 entries accepted, 0 rejected). Sorting entries....done (75 comparisons). Generating output file main.ind....done (22 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Perm.h010064400020550007177000000000740653602115000131440ustar00clevecompmath00000400000006#ifndef _Perm_ #define _Perm_ #include "Perm/Perm.h" #endif Perm/Perm.h010064400020550007177000000172200653602102500140510ustar00clevecompmath00000400000006/* Perm.h */ #include "../cfiles.h" #include "../IV.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- the Perm object contains one or two permutation vectors isPresent -- flag to tell which vectors are present 0 --> neither are present 1 --> newToOld is present 2 --> oldToNew is present 3 --> both are present size -- size of the vectors newToOld -- pointer to new-to-old permutation vector oldToNew -- pointer to old-to-new permutation vector created -- 96mar16 --------------------------------------------------------- */ typedef struct _Perm Perm ; struct _Perm { int isPresent ; int size ; int *newToOld ; int *oldToNew ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- method founds in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 96jan05, cca ----------------------- */ Perm * Perm_new ( void ) ; /* ----------------------- set the default fields created -- 96jan05, cca ----------------------- */ void Perm_setDefaultFields ( Perm *perm ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 96jan05, cca -------------------------------------------------- */ void Perm_clearData ( Perm *perm ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 96jan05, cca ------------------------------------------ */ Perm * Perm_free ( Perm *perm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- method founds in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------- initializer created -- 96jan05, cca ----------------------- */ void Perm_initWithTypeAndSize ( Perm *perm, int isPresent, int size ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- method founds in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------------- return the storage taken by this object created -- 96jan05, cca --------------------------------------- */ int Perm_sizeOf ( Perm *perm ) ; /* ---------------------------------------------------------- check that the permutation object does house a permutation return value -- 1 if a true permutation 0 otherwise ---------------------------------------------------------- */ int Perm_checkPerm ( Perm *perm ) ; /* ---------------------------------------- if the old-to-new vector is not present, create it and fill its entries created -- 96mar16, cca ---------------------------------------- */ void Perm_fillOldToNew ( Perm *perm ) ; /* ---------------------------------------- if the new-to-old vector is not present, create it and fill its entries created -- 96mar16, cca ---------------------------------------- */ void Perm_fillNewToOld ( Perm *perm ) ; /* ------------------------------------ if the old-to-new vector is present, release it and free its entries created -- 96mar16, cca ------------------------------------ */ void Perm_releaseOldToNew ( Perm *perm ) ; /* ------------------------------------ if the new-to-old vector is present, release it and free its entries created -- 96mar16, cca ------------------------------------ */ void Perm_releaseNewToOld ( Perm *perm ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- method founds in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------ purpose -- to read in an Perm object from a file input -- fn -- filename, must be *.permb or *.permf return value -- 1 if success, 0 if failure created -- 96jan05, cca ----------------------------------------------- */ int Perm_readFromFile ( Perm *perm, char *fn ) ; /* ------------------------------------------------------ purpose -- to read an Perm object from a formatted file return value -- 1 if success, 0 if failure created -- 96jan05, cca ------------------------------------------------------ */ int Perm_readFromFormattedFile ( Perm *perm, FILE *fp ) ; /* --------------------------------------------------- purpose -- to read an Perm object from a binary file return value -- 1 if success, 0 if failure created -- 96jan05, cca --------------------------------------------------- */ int Perm_readFromBinaryFile ( Perm *perm, FILE *fp ) ; /* ------------------------------------------- purpose -- to write an Perm object to a file input -- fn -- filename *.permb -- binary *.permf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 96jan05, cca ------------------------------------------- */ int Perm_writeToFile ( Perm *perm, char *fn ) ; /* ----------------------------------------------------- purpose -- to write an Perm object to a formatted file return value -- 1 if success, 0 otherwise created -- 96jan05, cca ----------------------------------------------------- */ int Perm_writeToFormattedFile ( Perm *perm, FILE *fp ) ; /* -------------------------------------------------- purpose -- to write an Perm object to a binary file return value -- 1 if success, 0 otherwise created -- 96jan05, cca -------------------------------------------------- */ int Perm_writeToBinaryFile ( Perm *perm, FILE *fp ) ; /* ------------------------------------------------- purpose -- to write an Perm object for a human eye return value -- 1 if success, 0 otherwise created -- 96jan05, cca ------------------------------------------------- */ int Perm_writeForHumanEye ( Perm *perm, FILE *fp ) ; /* --------------------------------------------------------- purpose -- to write out the statistics for the Perm object return value -- 1 if success, 0 otherwise created -- 96jan05, cca --------------------------------------------------------- */ int Perm_writeStats ( Perm *perm, FILE *fp ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- method founds in compress.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------ given a permutation and a vector to map vertices into compressed vertices, create and return a permutation object for the compressed vertices. created -- 96may02, cca ------------------------------------------------ */ Perm * Perm_compress ( Perm *perm, IV *eqmapIV ) ; /*--------------------------------------------------------------------*/ Perm/makefile010064400020550007177000000002230663622366000145020ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean Perm/src/makefile010064400020550007177000000007310663602747500153030ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Perm $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(compress.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG Perm/src/makeGlobalLib010064400020550007177000000006150660026112700161750ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Perm SRC = basics.c \ compress.c \ init.c \ IO.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Perm/src/IO.c010064400020550007177000000403260653602102300142400ustar00clevecompmath00000400000006/* IO.c */ #include "../Perm.h" static const char *suffixb = ".permb" ; static const char *suffixf = ".permf" ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to read in an Perm object from a file input -- fn -- filename, must be *.permb or *.permf return value -- 1 if success, 0 if failure created -- 96jan05, cca ----------------------------------------------- */ int Perm_readFromFile ( Perm *perm, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( perm == NULL || fn == NULL ) { fprintf(stderr, "\n error in Perm_readFromFile(%p,%s), file %s, line %d" "\n bad input\n", perm, fn, __FILE__, __LINE__) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in Perm_readFromFile(%p,%s)" "\n unable to open file %s", perm, fn, fn) ; rc = 0 ; } else { rc = Perm_readFromBinaryFile(perm, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in Perm_readFromFile(%p,%s)" "\n unable to open file %s", perm, fn, fn) ; rc = 0 ; } else { rc = Perm_readFromFormattedFile(perm, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in Perm_readFromFile(%p,%s)" "\n bad Perm file name %s," "\n must end in %s (binary) or %s (formatted)\n", perm, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in Perm_readFromFile(%p,%s)" "\n bad Perm file name %s," "\n must end in %s (binary) or %s (formatted)\n", perm, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to read an Perm object from a formatted file return value -- 1 if success, 0 if failure created -- 96jan05, cca ------------------------------------------------------ */ int Perm_readFromFormattedFile ( Perm *perm, FILE *fp ) { int i, isPresent, j, rc, size ; int itemp[2] ; /* --------------- check the input --------------- */ if ( perm == NULL || fp == NULL ) { fprintf(stderr, "\n error in Perm_readFromFormattedFile(%p,%p)" "\n bad input\n", perm, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ Perm_clearData(perm) ; /* ----------------------------------------------------- read in the two scalar parameters: isPresent and size ----------------------------------------------------- */ if ( (rc = IVfscanf(fp, 2, itemp)) != 2 ) { fprintf(stderr, "\n error in Perm_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", perm, fp, rc, 2) ; return(0) ; } isPresent = itemp[0] ; size = itemp[1] ; if ( isPresent < 1 || isPresent > 3 || size <= 0 ) { fprintf(stderr, "\n error in Perm_readFromFormattedFile(%p,%p)" "\n isPresent = %d, size = %d", perm, fp, isPresent, size) ; return(0) ; } /* --------------------- initialize the object --------------------- */ Perm_initWithTypeAndSize(perm, isPresent, size) ; if ( isPresent == 2 || isPresent == 3 ) { /* ----------------------------------------- read in the old-to-new permutation vector ----------------------------------------- */ int *oldToNew = perm->oldToNew ; if ( (rc = IVfscanf(fp, size, oldToNew)) != size ) { fprintf(stderr, "\n error in Perm_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", perm, fp, rc, size) ; exit(-1) ; } for ( i = 0 ; i < size ; i++ ) { if ( oldToNew[i] == size ) { for ( j = 0 ; j < size ; j++ ) { oldToNew[j]-- ; } break ; } } } if ( isPresent == 1 || isPresent == 3 ) { /* ----------------------------------------- read in the new-to-old permutation vector ----------------------------------------- */ int *newToOld = perm->newToOld ; if ( (rc = IVfscanf(fp, size, newToOld)) != size ) { fprintf(stderr, "\n error in Perm_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", perm, fp, rc, size) ; exit(-1) ; } for ( i = 0 ; i < size ; i++ ) { if ( newToOld[i] == size ) { for ( j = 0 ; j < size ; j++ ) { newToOld[j]-- ; } break ; } } } /* ---------------------------- check the permutation object ---------------------------- */ if ( Perm_checkPerm(perm) != 1 ) { fprintf(stderr, "\n fatal error in Perm_readFromFormattedFile(%p,%p)" "\n permutation is not valid\n", perm, fp) ; exit(-1) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to read an Perm object from a binary file return value -- 1 if success, 0 if failure created -- 96jan05, cca --------------------------------------------------- */ int Perm_readFromBinaryFile ( Perm *perm, FILE *fp ) { int i, isPresent, j, rc, size ; int itemp[2] ; /* --------------- check the input --------------- */ if ( perm == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Perm_readFromBinaryFile(%p,%p)" "\n bad input\n", perm, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ Perm_clearData(perm) ; /* ------------------------------------------------ read in the two scalar parameters: type and size ------------------------------------------------ */ if ( (rc = fread((void *) itemp, sizeof(int), 2, fp)) != 2 ) { fprintf(stderr, "\n error in Perm_readFromBinaryFile(%p,%p)" "\n itemp(2) : %d items of %d read\n", perm, fp, rc, 2) ; return(0) ; } isPresent = itemp[0] ; size = itemp[1] ; if ( isPresent < 1 || isPresent > 3 || size <= 0 ) { fprintf(stderr, "\n error in Perm_readFromBinaryFile(%p,%p)" "\n isPresent = %d, size = %d", perm, fp, isPresent, size) ; return(0) ; } /* --------------------- initialize the object --------------------- */ Perm_initWithTypeAndSize(perm, isPresent, size) ; if ( isPresent == 2 || isPresent == 3 ) { /* ----------------------------------------- read in the old-to-new permutation vector ----------------------------------------- */ int *oldToNew = perm->oldToNew ; if ( (rc = fread(oldToNew, sizeof(int), size, fp)) != size ) { fprintf(stderr, "\n error in Perm_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", perm, fp, rc, size) ; exit(-1) ; } for ( i = 0 ; i < size ; i++ ) { if ( oldToNew[i] == size ) { for ( j = 0 ; j < size ; j++ ) { oldToNew[j]-- ; } break ; } } } if ( isPresent == 1 || isPresent == 3 ) { /* ----------------------------------------- read in the new-to-old permutation vector ----------------------------------------- */ int *newToOld = perm->newToOld ; if ( (rc = fread(newToOld, sizeof(int), size, fp)) != size ) { fprintf(stderr, "\n error in Perm_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", perm, fp, rc, size) ; exit(-1) ; } for ( i = 0 ; i < size ; i++ ) { if ( newToOld[i] == size ) { for ( j = 0 ; j < size ; j++ ) { newToOld[j]-- ; } break ; } } } if ( Perm_checkPerm(perm) != 1 ) { fprintf(stderr, "\n fatal error in Perm_readFromFormattedFile(%p,%p)" "\n permutation is not valid\n", perm, fp) ; exit(-1) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to write an Perm object to a file input -- fn -- filename *.permb -- binary *.permf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 96jan05, cca ------------------------------------------- */ int Perm_writeToFile ( Perm *perm, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( perm == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in Perm_writeToFile(%p,%s)" "\n bad input\n", perm, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in Perm_writeToFile(%p,%s)" "\n unable to open file %s", perm, fn, fn) ; rc = 0 ; } else { rc = Perm_writeToBinaryFile(perm, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in Perm_writeToFile(%p,%s)" "\n unable to open file %s", perm, fn, fn) ; rc = 0 ; } else { rc = Perm_writeToFormattedFile(perm, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in Perm_writeToFile(%p,%s)" "\n unable to open file %s", perm, fn, fn) ; rc = 0 ; } else { rc = Perm_writeForHumanEye(perm, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in Perm_writeToFile(%p,%s)" "\n unable to open file %s", perm, fn, fn) ; rc = 0 ; } else { rc = Perm_writeForHumanEye(perm, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to write an Perm object to a formatted file return value -- 1 if success, 0 otherwise created -- 96jan05, cca ----------------------------------------------------- */ int Perm_writeToFormattedFile ( Perm *perm, FILE *fp ) { int ierr, rc ; /* --------------- check the input --------------- */ if ( perm == NULL || fp == NULL || perm->size <= 0 ) { fprintf(stderr, "\n fatal error in Perm_writeToFormattedFile(%p,%p)" "\n bad input\n", perm, fp) ; exit(-1) ; } /* ----------------------------------- write out the two scalar parameters ----------------------------------- */ rc = fprintf(fp, "\n %d %d", perm->isPresent, perm->size) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Perm_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", perm, fp, rc) ; return(0) ; } if ( perm->isPresent == 2 || perm->isPresent == 3 ) { /* ------------------------------------------- write out the old-to-new permutation vector ------------------------------------------- */ IVfp80(fp, perm->size, perm->oldToNew, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in Perm_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from oldToNew[] IVfp80\n", perm, fp, ierr) ; return(0) ; } } if ( perm->isPresent == 1 || perm->isPresent == 3 ) { /* ------------------------------------------- write out the new-to-old permutation vector ------------------------------------------- */ IVfp80(fp, perm->size, perm->newToOld, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in Perm_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from newToOld[] IVfp80\n", perm, fp, ierr) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to write an Perm object to a binary file return value -- 1 if success, 0 otherwise created -- 96jan05, cca -------------------------------------------------- */ int Perm_writeToBinaryFile ( Perm *perm, FILE *fp ) { int size, rc ; int itemp[3] ; /* --------------- check the input --------------- */ if ( perm == NULL || fp == NULL || (size = perm->size) <= 0 ) { fprintf(stderr, "\n fatal error in Perm_writeToBinaryFile(%p,%p)" "\n bad input\n", perm, fp) ; exit(-1) ; } /* ----------------------------------- write out the two scalar parameters ----------------------------------- */ itemp[0] = perm->isPresent ; itemp[1] = size ; rc = fwrite((void *) itemp, sizeof(int), 2, fp) ; if ( rc != 2 ) { fprintf(stderr, "\n error in Perm_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", perm, fp, rc, 2) ; return(0) ; } if ( perm->isPresent == 2 || perm->isPresent == 3 ) { /* ------------------------------------------- write out the old-to-new permutation vector ------------------------------------------- */ rc = fwrite((void *) perm->oldToNew, sizeof(int), size, fp) ; if ( rc != size ) { fprintf(stderr, "\n error in Perm_writeToBinaryFile(%p,%p)" "\n perm->oldToNew, %d of %d items written\n", perm, fp, rc, size) ; return(0) ; } } if ( perm->isPresent == 1 || perm->isPresent == 3 ) { /* ------------------------------------------- write out the new-to-old permutation vector ------------------------------------------- */ rc = fwrite((void *) perm->newToOld, sizeof(int), size, fp) ; if ( rc != size ) { fprintf(stderr, "\n error in Perm_writeToBinaryFile(%p,%p)" "\n perm->newToOld, %d of %d items written\n", perm, fp, rc, size) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to write an Perm object for a human eye return value -- 1 if success, 0 otherwise created -- 96jan05, cca ------------------------------------------------- */ int Perm_writeForHumanEye ( Perm *perm, FILE *fp ) { int ierr, rc ; if ( perm == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Perm_writeForHumanEye(%p,%p)" "\n bad input\n", perm, fp) ; exit(-1) ; } if ( (rc = Perm_writeStats(perm, fp)) == 0 ) { fprintf(stderr, "\n fatal error in Perm_writeForHumanEye(%p,%p)" "\n rc = %d, return from Perm_writeStats(%p,%p)\n", perm, fp, rc, perm, fp) ; return(0) ; } if ( perm->isPresent == 2 || perm->isPresent == 3 ) { fprintf(fp, "\n\n old-to-new permutation") ; IVfp80(fp, perm->size, perm->oldToNew, 80, &ierr) ; } if ( perm->isPresent == 1 || perm->isPresent == 3 ) { fprintf(fp, "\n\n new-to-old permutation") ; IVfp80(fp, perm->size, perm->newToOld, 80, &ierr) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- to write out the statistics for the Perm object return value -- 1 if success, 0 otherwise created -- 96jan05, cca --------------------------------------------------------- */ int Perm_writeStats ( Perm *perm, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( perm == NULL || fp == NULL ) { fprintf(stderr, "\n error in Perm_writeStats(%p,%p)" "\n bad input\n", perm, fp) ; exit(-1) ; } rc = fprintf(fp, "\n Perm : permutation object :") ; if ( rc < 0 ) { goto IO_error ; } rc = fprintf(fp, "\n isPresent %d, size %d", perm->isPresent, perm->size) ; if ( rc < 0 ) { goto IO_error ; } return(1) ; IO_error : fprintf(stderr, "\n fatal error in Perm_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", perm, fp, rc) ; return(0) ; } /*--------------------------------------------------------------------*/ Perm/src/basics.c010064400020550007177000000041650653602102400151770ustar00clevecompmath00000400000006/* basics.c */ #include "../Perm.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 96jan05, cca ----------------------- */ Perm * Perm_new ( void ) { Perm *perm ; ALLOCATE(perm, struct _Perm, 1) ; Perm_setDefaultFields(perm) ; return(perm) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 96jan05, cca ----------------------- */ void Perm_setDefaultFields ( Perm *perm ) { if ( perm == NULL ) { fprintf(stderr, "\n fatal error in Perm_setDefaultFields(%p)" "\n bad input", perm) ; exit(-1) ; } perm->isPresent = 0 ; perm->size = 0 ; perm->newToOld = NULL ; perm->oldToNew = NULL ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 96jan05, cca -------------------------------------------------- */ void Perm_clearData ( Perm *perm ) { /* --------------- check the input --------------- */ if ( perm == NULL ) { fprintf(stderr, "\n fatal error in Perm_clearData(%p)" "\n bad input\n", perm) ; exit(-1) ; } if ( perm->newToOld != NULL ) { IVfree(perm->newToOld) ; } if ( perm->oldToNew != NULL ) { IVfree(perm->oldToNew) ; } /* ---------------------- set the default fields ---------------------- */ Perm_setDefaultFields(perm) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 96jan05, cca ------------------------------------------ */ Perm * Perm_free ( Perm *perm ) { if ( perm == NULL ) { fprintf(stderr, "\n fatal error in Perm_free(%p)" "\n bad input\n", perm) ; exit(-1) ; } Perm_clearData(perm) ; FREE(perm) ; return(NULL) ; } /*--------------------------------------------------------------------*/ Perm/src/compress.c010064400020550007177000000047720653602102400155720ustar00clevecompmath00000400000006/* compress.c */ #include "../Perm.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------ given a permutation and a vector to map vertices into compressed vertices, create and return a permutation object for the compressed vertices. created -- 96may02, cca ------------------------------------------------ */ Perm * Perm_compress ( Perm *perm, IV *eqmapIV ) { int n, N, v, vcomp, vnew ; int *eqmap, *head, *link, *newToOld, *oldToNew, *vals ; Perm *perm2 ; /* --------------- check the input --------------- */ if ( perm == NULL || (n = perm->size) <= 0 || eqmapIV == NULL || n != IV_size(eqmapIV) || (eqmap = IV_entries(eqmapIV)) == NULL ) { fprintf(stderr, "\n fatal error in Perm_compress(%p,%p)" "\n bad input\n", perm, eqmapIV) ; if ( perm != NULL ) { Perm_writeStats(perm, stderr) ; } if ( eqmapIV != NULL ) { IV_writeStats(eqmapIV, stderr) ; } exit(-1) ; } n = perm->size ; if ( (oldToNew = perm->oldToNew) == NULL ) { Perm_fillOldToNew(perm) ; oldToNew = perm->oldToNew ; } if ( (newToOld = perm->newToOld) == NULL ) { Perm_fillNewToOld(perm) ; newToOld = perm->newToOld ; } /* --------------------------------- create the new permutation object --------------------------------- */ N = 1 + IVmax(n, eqmap, &v) ; perm2 = Perm_new() ; Perm_initWithTypeAndSize(perm2, 3, N) ; /* -------------------------------------------- get the head/link structure for the vertices -------------------------------------------- */ head = IVinit(N, -1) ; link = IVinit(n, -1) ; for ( v = 0 ; v < n ; v++ ) { vcomp = eqmap[v] ; link[v] = head[vcomp] ; head[vcomp] = v ; } /* --------------------------- get the two vectors to sort --------------------------- */ IVramp(N, perm2->newToOld, 0, 1) ; vals = IVinit(N, -1) ; for ( vcomp = 0 ; vcomp < N ; vcomp++ ) { v = head[vcomp] ; vnew = perm->oldToNew[v] ; for ( v = link[v] ; v != -1 ; v = link[v] ) { if ( vnew > perm->oldToNew[v] ) { vnew = perm->oldToNew[v] ; } } vals[vcomp] = vnew ; } IV2qsortUp(N, vals, perm2->newToOld) ; for ( vcomp = 0 ; vcomp < N ; vcomp++ ) { perm2->oldToNew[perm2->newToOld[vcomp]] = vcomp ; } /* --------------------- free the working data --------------------- */ IVfree(head) ; IVfree(link) ; IVfree(vals) ; return(perm2) ; } /*--------------------------------------------------------------------*/ Perm/src/init.c010064400020550007177000000024300653602102400146670ustar00clevecompmath00000400000006/* init.c */ #include "../Perm.h" /*--------------------------------------------------------------------*/ /* ----------------------- initializer created -- 96jan05, cca ----------------------- */ void Perm_initWithTypeAndSize ( Perm *perm, int isPresent, int size ) { /* --------------------- clear the data fields --------------------- */ Perm_clearData(perm) ; /* --------------- check the input --------------- */ if ( isPresent < 1 || isPresent > 3 || size <= 0 ) { fprintf(stderr, "\n\n fatal error in Perm_initWithTypeAndSize(%p,%d,%d)" "\n isPresent = %d, must be 1, 2 or 3" "\n size = %d, must be positive", perm, isPresent, size, isPresent, size) ; exit(-1) ; } perm->isPresent = isPresent ; perm->size = size ; /* ---------------------------------------- allocate storage for permutation vectors ---------------------------------------- */ switch ( isPresent ) { case 1 : perm->newToOld = IVinit(size, -1) ; break ; case 2 : perm->oldToNew = IVinit(size, -1) ; break ; case 3 : perm->oldToNew = IVinit(size, -1) ; perm->newToOld = IVinit(size, -1) ; break ; } return ; } /*--------------------------------------------------------------------*/ Perm/src/util.c010064400020550007177000000131730653602102400147070ustar00clevecompmath00000400000006/* util.c */ #include "../Perm.h" /*--------------------------------------------------------------------*/ /* --------------------------------------- return the storage taken by this object created -- 96jan05, cca --------------------------------------- */ int Perm_sizeOf ( Perm *perm ) { int bytes = sizeof(struct _Perm) ; if ( perm == NULL ) { fprintf(stderr, "\n fatal error in Perm_sizeOf(%p)" "\n bad input\n", perm) ; exit(-1) ; } if ( perm->newToOld != NULL ) { bytes += perm->size * sizeof(int) ; } if ( perm->oldToNew != NULL ) { bytes += perm->size * sizeof(int) ; } return(bytes) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- check that the permutation object does house a permutation return value -- 1 if a true permutation 0 otherwise ---------------------------------------------------------- */ int Perm_checkPerm ( Perm *perm ) { int inew, iold, rc, size ; int *counts, *newToOld, *oldToNew ; /* --------------- check the input --------------- */ if ( perm == NULL || perm->isPresent < 1 || perm->isPresent > 3 || (size = perm->size) <= 0 ) { fprintf(stderr, "\n fatal error in Perm_checkPerm(%p)" "\n bad input\n", perm) ; exit(-1) ; } rc = 1 ; counts = IVinit(size, 0) ; if ( (newToOld = perm->newToOld) != NULL ) { for ( inew = 0 ; inew < size ; inew++ ) { if ( 0 <= (iold = newToOld[inew]) && iold < size ) { counts[iold]++ ; } else { IVfree(counts) ; return(0) ; } } for ( iold = 0 ; iold < size ; iold++ ) { if ( counts[iold] != 1 ) { IVfree(counts) ; return(0) ; } } } if ( (oldToNew = perm->oldToNew) != NULL ) { IVzero(size, counts) ; for ( iold = 0 ; iold < size ; iold++ ) { if ( 0 <= (inew = oldToNew[iold]) && inew < size ) { counts[inew]++ ; } else { IVfree(counts) ; return(0) ; } } for ( inew = 0 ; inew < size ; inew++ ) { if ( counts[inew] != 1 ) { IVfree(counts) ; return(0) ; } } } IVfree(counts) ; return(rc) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- if the old-to-new vector is not present, create it and fill its entries created -- 96mar16, cca ---------------------------------------- */ void Perm_fillOldToNew ( Perm *perm ) { int size ; /* --------------- check the input --------------- */ if ( perm == NULL || perm->isPresent < 1 || perm->isPresent > 3 || (size = perm->size) <= 0 ) { fprintf(stderr, "\n fatal error in Perm_fillOldToNew(%p)" "\n bad input\n", perm) ; exit(-1) ; } if ( perm->isPresent == 1 ) { int inew ; int *newToOld = perm->newToOld ; int *oldToNew = perm->oldToNew = IVinit(size, -1) ; for ( inew = 0 ; inew < size ; inew++ ) { oldToNew[newToOld[inew]] = inew ; } perm->isPresent = 3 ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- if the new-to-old vector is not present, create it and fill its entries created -- 96mar16, cca ---------------------------------------- */ void Perm_fillNewToOld ( Perm *perm ) { int size ; /* --------------- check the input --------------- */ if ( perm == NULL || perm->isPresent < 1 || perm->isPresent > 3 || (size = perm->size) <= 0 ) { fprintf(stderr, "\n fatal error in Perm_fillNewToOld(%p)" "\n bad input\n", perm) ; exit(-1) ; } if ( perm->isPresent == 2 ) { int iold ; int *newToOld = perm->newToOld = IVinit(size, -1) ; int *oldToNew = perm->oldToNew ; for ( iold = 0 ; iold < size ; iold++ ) { newToOld[oldToNew[iold]] = iold ; } perm->isPresent = 3 ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ if the old-to-new vector is present, release it and free its entries created -- 96mar16, cca ------------------------------------ */ void Perm_releaseOldToNew ( Perm *perm ) { int size ; /* --------------- check the input --------------- */ if ( perm == NULL || perm->isPresent < 1 || perm->isPresent > 3 || (size = perm->size) <= 0 ) { fprintf(stderr, "\n fatal error in Perm_fillOldToNew(%p)" "\n bad input\n", perm) ; exit(-1) ; } switch ( perm->isPresent ) { case 1 : break ; case 2 : IVfree(perm->oldToNew) ; perm->isPresent = 0 ; break ; case 3 : IVfree(perm->oldToNew) ; perm->isPresent = 1 ; break ; default : break ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ if the new-to-old vector is present, release it and free its entries created -- 96mar16, cca ------------------------------------ */ void Perm_releaseNewToOld ( Perm *perm ) { int size ; /* --------------- check the input --------------- */ if ( perm == NULL || perm->isPresent < 1 || perm->isPresent > 3 || (size = perm->size) <= 0 ) { fprintf(stderr, "\n fatal error in Perm_fillOldToNew(%p)" "\n bad input\n", perm) ; exit(-1) ; } switch ( perm->isPresent ) { case 1 : IVfree(perm->newToOld) ; perm->isPresent = 0 ; break ; case 2 : break ; case 3 : IVfree(perm->newToOld) ; perm->isPresent = 1 ; break ; default : break ; } return ; } /*--------------------------------------------------------------------*/ Perm/drivers/do_compressPerm010075500020550007177000000005350653602102300175410ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = BCSSTK24 set inPermFile = $matrices/$matrix/mmd0.permf set inMapFile = $matrices/$matrix/eqmap.ivf set outPermFile = none set outPermFile = $matrices/$matrix/mmd1.permf set msglvl = 3 set msgFile = stdout compressPerm $msglvl $msgFile $inPermFile $inMapFile $outPermFile Perm/drivers/do_testIO010075500020550007177000000004060653602102300162660ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inFile = $matrices/$matrix/gem.permf set outFile = $matrices/$matrix/gem.permb set outFile = none set msglvl = 3 set msgFile = stdout testIO $msglvl $msgFile $inFile $outFile Perm/drivers/makefile010064400020550007177000000006370665314263700161740ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testIO compressPerm drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testIO : testIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} compressPerm : compressPerm.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} Perm/drivers/compressPerm.c010064400020550007177000000102500654223332400172760ustar00clevecompmath00000400000006/* compressPerm.c */ #include "../Perm.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------------------- read in a permutation and an equivalence map vector. created the permutation for the compressed graph. created -- 96may02, cca ---------------------------------------------------- */ { char *inIVfileName, *inPermFileName, *outPermFileName ; double t1, t2 ; int msglvl, rc ; IV *eqmapIV ; Perm *perm, *perm2 ; FILE *msgFile ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inPermFile inMapFile outPermFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inPermFile -- input file, must be *.permf or *.permb" "\n inMapFile -- input file, must be *.ivf or *.ivb" "\n outPermFile -- output file, must be *.permf or *.permb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inPermFileName = argv[3] ; inIVfileName = argv[4] ; outPermFileName = argv[5] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inPermFile -- %s" "\n inMapFile -- %s" "\n outPermFile -- %s" "\n", argv[0], msglvl, argv[2], inPermFileName, inIVfileName, outPermFileName) ; fflush(msgFile) ; /* ----------------------- read in the Perm object ----------------------- */ if ( strcmp(inPermFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } perm = Perm_new() ; MARKTIME(t1) ; rc = Perm_readFromFile(perm, inPermFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in perm from file %s", t2 - t1, inPermFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Perm_readFromFile(%p,%s)", rc, perm, inPermFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Perm object from file %s", inPermFileName) ; if ( msglvl > 2 ) { Perm_writeForHumanEye(perm, msgFile) ; } else { Perm_writeStats(perm, msgFile) ; } fflush(msgFile) ; /* ------------------------- read in the IV map object ------------------------- */ if ( strcmp(inIVfileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } eqmapIV = IV_new() ; MARKTIME(t1) ; rc = IV_readFromFile(eqmapIV, inIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in eqmapIV from file %s", t2 - t1, inIVfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, eqmapIV, inIVfileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading IV object from file %s", inIVfileName) ; if ( msglvl > 2 ) { IV_writeForHumanEye(eqmapIV, msgFile) ; } else { IV_writeStats(eqmapIV, msgFile) ; } fflush(msgFile) ; /* ------------------------------------- get the compressed permutation object ------------------------------------- */ perm2 = Perm_compress(perm, eqmapIV) ; fprintf(msgFile, "\n\n compressed Perm object") ; if ( msglvl > 2 ) { Perm_writeForHumanEye(perm2, msgFile) ; } else { Perm_writeStats(perm2, msgFile) ; } /* ------------------------- write out the Perm object ------------------------- */ if ( strcmp(outPermFileName, "none") != 0 ) { MARKTIME(t1) ; rc = Perm_writeToFile(perm2, outPermFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write perm to file %s", t2 - t1, outPermFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Perm_writeToFile(%p,%s)", rc, perm2, outPermFileName) ; } /* ---------------- free the objects ---------------- */ Perm_free(perm) ; IV_free(eqmapIV) ; Perm_free(perm2) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ntf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inPermFileName = argv[3] ; inIVfileName = argv[4] ; outPermFileName = argv[5] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inPermFile -- %s" Perm/drivers/testIO.c010064400020550007177000000055640654223334000160400ustar00clevecompmath00000400000006/* testIO.c */ #include "../Perm.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- test Perm_readFromFile and Perm_writeToFile, useful for translating between formatted *.permf and binary *.permb files. created -- 96may02, cca ------------------------------------------------- */ { char *inPermFileName, *outPermFileName ; double t1, t2 ; int msglvl, rc ; Perm *perm ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.permf or *.permb" "\n outFile -- output file, must be *.permf or *.permb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inPermFileName = argv[3] ; outPermFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inPermFileName, outPermFileName) ; fflush(msgFile) ; /* ----------------------- read in the Perm object ----------------------- */ if ( strcmp(inPermFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } perm = Perm_new() ; MARKTIME(t1) ; rc = Perm_readFromFile(perm, inPermFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in perm from file %s", t2 - t1, inPermFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Perm_readFromFile(%p,%s)", rc, perm, inPermFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Perm object from file %s", inPermFileName) ; if ( msglvl > 2 ) { Perm_writeForHumanEye(perm, msgFile) ; } else { Perm_writeStats(perm, msgFile) ; } fflush(msgFile) ; /* - ------------------------ write out the Perm object - ------------------------ */ if ( strcmp(outPermFileName, "none") != 0 ) { MARKTIME(t1) ; rc = Perm_writeToFile(perm, outPermFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write perm to file %s", t2 - t1, outPermFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Perm_writeToFile(%p,%s)", rc, perm, outPermFileName) ; } /* -------------------- free the Perm object -------------------- */ Perm_free(perm) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Perm/doc/004275500020550007177000000000000654276745100135665ustar00clevecompmath00000400000006Perm/doc/dataStructure.tex010064400020550007177000000015240653602102400171150ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:Perm:dataStructure} \par The {\tt Perm} object can contain two permutation vectors, an {\it old-to-new} and a {\it new-to-old} permutation. One or both may be present in the structure. \par The {\tt Perm} structure has four fields. \begin{itemize} \item {\tt int isPresent} : flag to tell which vectors are present \begin{itemize} \item 0 $\longrightarrow$ neither is present \item 1 $\longrightarrow$ {\tt newToOld} is present, {\tt oldToNew} is not \item 2 $\longrightarrow$ {\tt oldToNew} is present, {\tt newToOld} is not \item 3 $\longrightarrow$ both {\tt newToOld} and {\tt oldToNew} are present \end{itemize} \item {\tt int size} : dimension of the vectors \item {\tt int *newToOld} : pointer to the new-to-old vector \item {\tt int *oldToNew} : pointer to the old-to-new vector \end{itemize} Perm/doc/intro.tex010064400020550007177000000003150653602102400154130ustar00clevecompmath00000400000006\chapter{{\tt Perm}: Permutation Object} \par The {\tt Perm} object is used to store a pair of permutation vectors. The main function of this object is to read and write permutations from and to files. Perm/doc/main.tex010064400020550007177000000010530665065630400152200ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt PERM} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt PERM} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} Perm/doc/proto.tex010064400020550007177000000313210653602102400154240ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Perm} methods} \label{section:Perm:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Perm} object. \par \subsection{Basic methods} \label{subsection:Perm:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Perm * Perm_new ( void ) ; \end{verbatim} \index{Perm_new@{\tt Perm\_new()}} This method simply allocates storage for the {\tt Perm} structure and then sets the default fields by a call to {\tt Perm\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Perm_setDefaultFields ( Perm *perm ) ; \end{verbatim} \index{Perm_setDefaultFields@{\tt Perm\_setDefaultFields()}} This method sets the structure's fields to default values. \par \noindent {\it Error checking:} If {\tt perm} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Perm_clearData ( Perm *perm ) ; \end{verbatim} \index{Perm_clearData@{\tt Perm\_clearData()}} This method clears data owned by the object. If {\tt perm->newToOld} is not {\tt NULL}, its storage is free'd with a call to {\tt IVfree()}. If {\tt perm->oldToNew} is not {\tt NULL}, its storage is free'd with a call to {\tt IVfree()}. The structure's default fields are then set with a call to {\tt Perm\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt perm} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Perm_free ( Perm *perm ) ; \end{verbatim} \index{Perm_free@{\tt Perm\_free()}} This method releases any storage by a call to {\tt Perm\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt perm} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:Perm:proto:initializers} \par There is one initializer method. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Perm_initWithTypeAndSize ( Perm *perm, int isPresent, int size ) ; \end{verbatim} \index{Perm_initWithTypeAndSize@{\tt Perm\_initWithTypeAndSize()}} This method is the primary initializer. It clears any previous data with a call to {\tt Perm\_clearData()}. Then the {\tt isPresent} and {\tt size} fields are set. If {\tt isPresent == 1} then {\tt newToOld} is set with a call to {\tt IVinit()}. If {\tt isPresent == 2} then {\tt oldToNew} is set with a call to {\tt IVinit()}. If {\tt isPresent == 3} then {\tt newToOld} and {\tt newToOld} are set with calls to {\tt IVinit()}. \par \noindent {\it Error checking:} If {\tt perm} is {\tt NULL}, or if {\tt isPresent} is invalid, or if {\tt size <= 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:Perm:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Perm_sizeOf ( Perm *perm ) ; \end{verbatim} \index{Perm_sizeOf@{\tt Perm\_sizeOf()}} This method returns the number of bytes taken by this object. \par \noindent {\it Error checking:} If {\tt perm} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Perm_checkPerm ( Perm *perm ) ; \end{verbatim} \index{Perm_checkPerm@{\tt Perm\_checkPerm()}} This method checks the validity of the {\tt Perm} object. If {\tt oldToNew} is present, it is checked to see that it is a true permutation vector, i.e., a one-one and onto map from {\tt [0,size)} to {\tt [0,size)}, and similarly for {\tt newToOld} if it is present. If the permutation vector(s) are valid, {\tt 1} is returned, otherwise {\tt 0} is returned. \par \noindent {\it Error checking:} If {\tt perm} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Perm_fillOldToNew ( Perm *perm ) ; \end{verbatim} \index{Perm_fillOldToNew@{\tt Perm\_fillOldToNew()}} If {\tt oldToNew} is already present, the function returns. Otherwise, {\tt oldToNew} is initialized with a call to {\tt IVinit()} and has its values set from {\tt newToOld}. \par \noindent {\it Error checking:} If {\tt perm} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Perm_fillNewToOld ( Perm *perm ) ; \end{verbatim} \index{Perm_fillNewToOld@{\tt Perm\_fillNewToOld()}} If {\tt NewToOld} is already present, the function returns. Otherwise, {\tt NewToOld} is initialized with a call to {\tt IVinit()} and has its values set from {\tt oldToNew}. \par \noindent {\it Error checking:} If {\tt perm} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Perm_releaseOldToNew ( Perm *perm ) ; \end{verbatim} \index{Perm_releaseOldToNew@{\tt Perm\_releaseOldToNew()}} If {\tt oldToNew} is not present, the function returns. Otherwise, the storage for {\tt oldToNew} is released with a call to {\tt IVfree()} the {\tt isPresent} field is changed appropriately. \par \noindent {\it Error checking:} If {\tt perm} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Perm_releaseNewToOld ( Perm *perm ) ; \end{verbatim} \index{Perm_releaseNewToOld@{\tt Perm\_releaseNewToOld()}} If {\tt NewToOld} is not present, the function returns. Otherwise, the storage for {\tt NewToOld} is released with a call to {\tt IVfree()} the {\tt isPresent} field is changed appropriately. \par \noindent {\it Error checking:} If {\tt perm} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Perm * Perm_compress ( Perm *perm, IV *eqmapIV ) ; \end{verbatim} \index{Perm_compress@{\tt Perm\_compress()}} This method takes as input a {\tt Perm} object and an equivalence map {\tt IV} object (they must be the same size). The equivalence map is from vertices to indistinguishable vertices in a compressed graph. A second {\tt Perm} object is produced that contains the equivalent permutation on the compressed graph. \par \noindent {\it Error checking:} If {\tt perm} or {\tt eqmapIV} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:Perm:proto:IO} \par There are the usual eight IO routines. The file structure of a {\tt Perm} object is simple: \begin{center} \begin{tabbing} {\tt isPresent} {\tt size} \\ {\tt oldToNew[size]} (if present) \\ {\tt newToOld[size]} (if present) \end{tabbing} \end{center} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Perm_readFromFile ( Perm *perm, char *fn ) ; \end{verbatim} \index{Perm_readFromFile@{\tt Perm\_readFromFile()}} \par This method reads a {\tt Perm} object from a file. It tries to open the file and if it is successful, it then calls {\tt Perm\_readFromFormattedFile()} or {\tt Perm\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt perm} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.permf} (for a formatted file) or {\tt *.permb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int Perm_readFromFormattedFile ( Perm *perm, FILE *fp ) ; \end{verbatim} \index{Perm_readFromFormattedFile@{\tt Perm\_readFromFormattedFile()}} \par This method reads in a {\tt Perm} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. Note, if the permutation vectors are one-based (as for Fortran), they are converted to zero-based vectors. \par \noindent {\it Error checking:} If {\tt perm} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Perm_readFromBinaryFile ( Perm *perm, FILE *fp ) ; \end{verbatim} \index{Perm_readFromBinaryFile@{\tt Perm\_readFromBinaryFile()}} \par This method reads in a {\tt Perm} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. Note, if the permutation vectors are one-based (as for Fortran), they are converted to zero-based vectors. \par \noindent {\it Error checking:} If {\tt perm} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Perm_writeToFile ( Perm *perm, char *fn ) ; \end{verbatim} \index{Perm_writeToFile@{\tt Perm\_writeToFile()}} \par This method writes a {\tt Perm} object to a file. It tries to open the file and if it is successful, it then calls {\tt Perm\_writeFromFormattedFile()} or {\tt Perm\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt perm} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.permf} (for a formatted file) or {\tt *.permb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int Perm_writeToFormattedFile ( Perm *perm, FILE *fp ) ; \end{verbatim} \index{Perm_writeToFormattedFile@{\tt Perm\_writeToFormattedFile()}} \par This method writes out a {\tt Perm} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt perm} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Perm_writeToBinaryFile ( Perm *perm, FILE *fp ) ; \end{verbatim} \index{Perm_writeToBinaryFile@{\tt Perm\_writeToBinaryFile()}} \par This method writes out a {\tt Perm} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt perm} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Perm_writeForHumanEye ( Perm *perm, FILE *fp ) ; \end{verbatim} \index{Perm_writeForHumanEye@{\tt Perm\_writeForHumanEye()}} \par This method writes out a {\tt Perm} object to a file in a human readable format. The method {\tt Perm\_writeStats()} is called to write out the header and statistics. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt perm} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Perm_writeStats ( Perm *perm, FILE *fp ) ; \end{verbatim} \index{Perm_writeStats@{\tt Perm\_writeStats()}} \par This method writes out a header and statistics to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt perm} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} resent, int size ) ; \end{verbatim} \index{Perm_initWithTypeAndSize@{\tt Perm\_initWithTypeAndSize()}} This method is the primary initializer. It clears any previous data with a call to {\tt Perm\_clearData()}. Then the {\tt isPresent} and {\tt size} fields are set. If {\tt isPresent == 1} then {\tt nPerm/doc/main.log010064400020550007177000000037400653602102400151720ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 6 SEP 1997 09:04 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. ) (dataStructure.tex) (proto.tex [1 ] Overfull \hbox (13.06998pt too wide) in paragraph at lines 42--49 \elvrm to \elvtt IVfree()\elvrm . The struc-ture's de-fault fields are then set with a call to \elvtt Perm[]setDefaultFields()\elvrm . \hbox(7.60416+0.91246)x442.37993, glue set - 1.0 .\elvrm t .\elvrm o .\glue 3.65 plus 1.825 minus 1.21666 .\elvtt I .\elvtt V .etc. Overfull \hbox (22.10481pt too wide) in paragraph at lines 80--90 []\elvrm This method is the pri-mary ini-tial-izer. It clears any pre-vi-ous da ta with a call to \elvtt Perm[]clearData()\elvrm . \hbox(7.60416+2.12917)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\elvrm T .\elvrm h .\elvrm i .\elvrm s .etc. [2] [3] [4]) (main.ind [5] [6 ]) (main.aux) ) Here is how much of TeX's memory you used: 204 strings out of 11977 2105 string characters out of 87269 33459 words of memory out of 262141 2141 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,6n,17p,181b,199s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (6 pages, 13512 bytes). Perm/doc/main.aux010064400020550007177000000023250653602102400152040ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space Perm}: Permutation Object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:Perm:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space Perm} methods}{1}} \newlabel{section:Perm:proto}{{1.2}{1}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:Perm:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initializer methods}{2}} \newlabel{subsection:Perm:proto:initializers}{{1.2.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{2}} \newlabel{subsection:Perm:proto:utilities}{{1.2.3}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}IO methods}{3}} \newlabel{subsection:Perm:proto:IO}{{1.2.4}{3}} Perm/doc/main.ind010064400020550007177000000014470653602102400151650ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Perm\_checkPerm()}, 4 \item {\tt Perm\_clearData()}, 3 \item {\tt Perm\_compress()}, 4 \item {\tt Perm\_fillNewToOld()}, 4 \item {\tt Perm\_fillOldToNew()}, 4 \item {\tt Perm\_free()}, 3 \item {\tt Perm\_initWithTypeAndSize()}, 3 \item {\tt Perm\_new()}, 3 \item {\tt Perm\_readFromBinaryFile()}, 5 \item {\tt Perm\_readFromFile()}, 5 \item {\tt Perm\_readFromFormattedFile()}, 5 \item {\tt Perm\_releaseNewToOld()}, 4 \item {\tt Perm\_releaseOldToNew()}, 4 \item {\tt Perm\_setDefaultFields()}, 3 \item {\tt Perm\_sizeOf()}, 3 \item {\tt Perm\_writeForHumanEye()}, 5 \item {\tt Perm\_writeStats()}, 6 \item {\tt Perm\_writeToBinaryFile()}, 5 \item {\tt Perm\_writeToFile()}, 5 \item {\tt Perm\_writeToFormattedFile()}, 5 \end{theindex} Perm/doc/main.idx010064400020550007177000000023360653602102400151750ustar00clevecompmath00000400000006\indexentry{Perm_new@{\tt Perm\_new()}}{2} \indexentry{Perm_setDefaultFields@{\tt Perm\_setDefaultFields()}}{2} \indexentry{Perm_clearData@{\tt Perm\_clearData()}}{2} \indexentry{Perm_free@{\tt Perm\_free()}}{2} \indexentry{Perm_initWithTypeAndSize@{\tt Perm\_initWithTypeAndSize()}}{2} \indexentry{Perm_sizeOf@{\tt Perm\_sizeOf()}}{2} \indexentry{Perm_checkPerm@{\tt Perm\_checkPerm()}}{3} \indexentry{Perm_fillOldToNew@{\tt Perm\_fillOldToNew()}}{3} \indexentry{Perm_fillNewToOld@{\tt Perm\_fillNewToOld()}}{3} \indexentry{Perm_releaseOldToNew@{\tt Perm\_releaseOldToNew()}}{3} \indexentry{Perm_releaseNewToOld@{\tt Perm\_releaseNewToOld()}}{3} \indexentry{Perm_compress@{\tt Perm\_compress()}}{3} \indexentry{Perm_readFromFile@{\tt Perm\_readFromFile()}}{4} \indexentry{Perm_readFromFormattedFile@{\tt Perm\_readFromFormattedFile()}}{4} \indexentry{Perm_readFromBinaryFile@{\tt Perm\_readFromBinaryFile()}}{4} \indexentry{Perm_writeToFile@{\tt Perm\_writeToFile()}}{4} \indexentry{Perm_writeToFormattedFile@{\tt Perm\_writeToFormattedFile()}}{4} \indexentry{Perm_writeToBinaryFile@{\tt Perm\_writeToBinaryFile()}}{4} \indexentry{Perm_writeForHumanEye@{\tt Perm\_writeForHumanEye()}}{4} \indexentry{Perm_writeStats@{\tt Perm\_writeStats()}}{5} Perm/doc/main.ilg010064400020550007177000000004560653602102400151650ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (20 entries accepted, 0 rejected). Sorting entries....done (82 comparisons). Generating output file main.ind....done (24 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Perm/doc/makefile010064400020550007177000000000270654276745100152600ustar00clevecompmath00000400000006clean : - rm -f *.dvi SemiImplMtx/SemiImplMtx.h010064400020550007177000000205010661366534400166750ustar00clevecompmath00000400000006/* SemiImplMtx.h */ #include "../FrontMtx.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- the SemiImplMtx object is used to perform "semi-implicit solves" of the following matrix factorization. A = P [ A11 A12 ] Q = P [ L11 0 ] [ D11 0 ] [ U11 U12 ] Q [ A21 A22 ] [ L21 L22 ] [ 0 D22 ] [ 0 U22 ] where P and Q are chosen by pivoting for stability. the semi-implicit factorization drops L21 and U12, and trades operating with them with multiplies by A21 and A12 and extra solves involving A11. we want to solve [ A11 A12 ] [ X1 ] = [ B1 ] [ A21 A22 ] [ X2 ] = [ B2 ] this can be done explicitly, as 1. solve L11 Y1 = B1 2. solve L22 Y2 = B2 - L21 Y1 3. solve D11 Z1 = Y1 4. solve D22 Z2 = Y2 5. solve U22 X2 = Z2 6. solve U11 X1 = Z1 - U12 X2 or implicitly, as 1. solve L11 D11 U11 T = B1 2. solve L22 D22 U22 X2 = B2 - A21 T 3. solve L11 D11 U11 T = B1 - A12 X2 neqns -- # of equations type -- type of entries 1 (SPOOLES_REAL) -- real entries 2 (SPOOLES_COMPLEX) -- complex entries symmetryflag -- symmetry type 0 (SPOOLES_SYMMETRIC) -- symmetric matrix 1 (SPOOLES_HERMITIAN) -- hermitian matrix 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric matrix ndomeqns -- # of equations in the domains nschureqns -- # of equations in the schur complement domainMtx -- pointer to FrontMtx objec that holds the factorization of A11 schurMtx -- pointer to FrontMtx objec that holds the factorization of A22 - A21 * A11^{-1} * A12 domRowsIV -- vector of global ids of rows of A11 schurRowsIV -- vector of global ids of rows of A22 domColsIV -- vector of global ids of columns of A11 schurColsIV -- vector of global ids of columns of A22 created -- 98sep14 ---------------------------------------------------------------- */ typedef struct _SemiImplMtx SemiImplMtx ; struct _SemiImplMtx { int neqns ; int type ; int symmetryflag ; int ndomeqns ; int nschureqns ; FrontMtx *domainMtx ; FrontMtx *schurMtx ; InpMtx *A21 ; InpMtx *A12 ; IV *domRowsIV ; IV *schurRowsIV ; IV *domColsIV ; IV *schurColsIV ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98oct16, cca ----------------------- */ SemiImplMtx * SemiImplMtx_new ( void ) ; /* ----------------------- set the default fields return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct16, cca ----------------------- */ int SemiImplMtx_setDefaultFields ( SemiImplMtx *mtx ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct16, cca -------------------------------------------------- */ int SemiImplMtx_clearData ( SemiImplMtx *mtx ) ; /* ------------------------------------------ destructor, free's the object and its data return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct16, cca ------------------------------------------ */ int SemiImplMtx_free ( SemiImplMtx *mtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- to initialize the semi-implicit matrix using as input a FrontMtx and a map from fronts to domains (map[J] != 0) or the schur complement (map[J] = 0) return value -- 1 -- normal return -1 -- semimtx is NULL -2 -- frontmtx is NULL -3 -- inpmtx is NULL -4 -- frontmapIV is NULL -5 -- frontmapIV is invalid created -- 98oct17, cca ------------------------------------------------------------------ */ int SemiImplMtx_initFromFrontMtx ( SemiImplMtx *semimtx, FrontMtx *frontmtx, InpMtx *inpmtx, IV *frontmapIV, int msglvl, FILE *msgFile ) ; /* */ int FrontMtx_initFromSubmatrix ( FrontMtx *submtx, FrontMtx *frontmtx, IV *frontidsIV, IV *rowsIV, IV *colsIV, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solve.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------ purpose -- to solve the linear system A X = B using a semi-implicit factorization on return --- cpus[0] -- time to initialize working matrices cpus[1] -- time to load rhs cpus[2] -- time for first solve with domains cpus[3] -- time to compute schur rhs cpus[4] -- time for schur solve cpus[5] -- time to compute domains' rhs cpus[6] -- time for second solve with domains cpus[7] -- time to store solution cpus[8] -- miscellaneous time cpus[9] -- total time return value -- 1 -- normal return -1 -- semimtx is NULL -2 -- mtxX is NULL -3 -- mtxB is NULL -4 -- mtxmanager is NULL -5 -- cpus is NULL created -- 98oct17, cca ------------------------------------------------ */ int SemiImplMtx_solve ( SemiImplMtx *semimtx, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, double cpus[], int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------------------------------- fill a statistics array for a semi-implicit factorization stats[0] -- # of equations stats[1] -- # of equations in the (1,1) block stats[2] -- # of equations in the (2,2) block stats[3] -- # of entries in L11 stats[4] -- # of entries in D11 stats[5] -- # of entries in U11 stats[6] -- # of entries in L22 stats[7] -- # of entries in D22 stats[8] -- # of entries in U22 stats[9] -- # of entries in A12 stats[10] -- # of entries in A21 stats[11] -- total # of matrix entries stats[12] -- # of operations for a solve return value --- 1 -- normal return -1 -- semimtx is NULL -2 -- stats is NULL created -- 98oct22, cca --------------------------------------------------------- */ int SemiImplMtx_stats ( SemiImplMtx *semimtx, int stats[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------- purpose -- to write a SemiImplMtx to a file in a human readable format return values --- 1 -- normal return -1 -- mtx is NULL -2 -- type is invalid -3 -- symmetry flag is invalid -4 -- fp is NULL created -- 98oct16, cca ------------------------------------------- */ int SemiImplMtx_writeForHumanEye ( SemiImplMtx *mtx, FILE *fp ) ; /*--------------------------------------------------------------------*/ f A22 domColsIV -- vector of global ids of columns of A11 schurColsIV -- vector of global ids of columns of A22 created -- 98sep14 ---------------------------------------------SemiImplMtx/makefile010064400020550007177000000002230663622366200160110ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean SemiImplMtx/src/makefile010064400020550007177000000007350663602756300166120ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SemiImplMtx $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(solve.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG SemiImplMtx/src/makeGlobalLib010064400020550007177000000006210662341466400175120ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SemiImplMtx SRC = IO.c \ basics.c \ init.c \ solve.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a SemiImplMtx/src/IO.c010064400020550007177000000063740661170533600155640ustar00clevecompmath00000400000006/* IO.c */ #include "../SemiImplMtx.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to write a SemiImplMtx to a file in a human readable format return values --- 1 -- normal return -1 -- mtx is NULL -2 -- type is invalid -3 -- symmetry flag is invalid -4 -- fp is NULL created -- 98oct16, cca ------------------------------------------- */ int SemiImplMtx_writeForHumanEye ( SemiImplMtx *mtx, FILE *fp ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_writeForHumanEye()" "\n mtx is NULL\n") ; return(-1) ; } switch ( mtx->type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n error in SemiImplMtx_writeForHumanEye()" "\n invalid type %d\n", mtx->type) ; return(-2) ; break ; } switch ( mtx->symmetryflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : case SPOOLES_NONSYMMETRIC : break ; default : fprintf(stderr, "\n error in SemiImplMtx_writeForHumanEye()" "\n invalid symmetry flag %d\n", mtx->symmetryflag) ; return(-3) ; break ; } if ( fp == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_writeForHumanEye()" "\n fp is NULL\n") ; return(-4) ; } fprintf(fp, "\n\n Semi-Implicit Matrix") ; fprintf(fp, "\n %d equations, %d in the domain, %d in the schur complement", mtx->neqns, mtx->ndomeqns, mtx->nschureqns) ; switch ( mtx->type ) { case SPOOLES_REAL : fprintf(fp, "\n real entries") ; break ; case SPOOLES_COMPLEX : fprintf(fp, "\n complex entries") ; break ; } switch ( mtx->symmetryflag ) { case SPOOLES_SYMMETRIC : fprintf(fp, ", symmetric matrix") ; break ; case SPOOLES_HERMITIAN : fprintf(fp, ", Hermitian matrix") ; break ; case SPOOLES_NONSYMMETRIC : fprintf(fp, ", nonsymmetric matrix") ; break ; } if ( mtx->domColsIV != NULL ) { fprintf(fp, "\n\n domain columns") ; IV_writeForHumanEye(mtx->domColsIV, fp) ; } if ( mtx->symmetryflag == SPOOLES_NONSYMMETRIC ) { if ( mtx->domRowsIV != NULL ) { fprintf(fp, "\n\n domain rows") ; IV_writeForHumanEye(mtx->domRowsIV, fp) ; } } if ( mtx->schurColsIV != NULL ) { fprintf(fp, "\n\n schur complement columns") ; IV_writeForHumanEye(mtx->schurColsIV, fp) ; } if ( mtx->symmetryflag == SPOOLES_NONSYMMETRIC ) { if ( mtx->schurRowsIV != NULL ) { fprintf(fp, "\n\n schur complement rows") ; IV_writeForHumanEye(mtx->schurRowsIV, fp) ; } } if ( mtx->domainMtx != NULL ) { fprintf(fp, "\n\n domain FrontMtx object") ; FrontMtx_writeForHumanEye(mtx->domainMtx, fp) ; } if ( mtx->schurMtx != NULL ) { fprintf(fp, "\n\n schur complement FrontMtx object") ; FrontMtx_writeForHumanEye(mtx->schurMtx, fp) ; } if ( mtx->A12 != NULL ) { fprintf(fp, "\n\n original (1,2) matrix") ; InpMtx_writeForHumanEye(mtx->A12, fp) ; } if ( mtx->symmetryflag == SPOOLES_NONSYMMETRIC ) { if ( mtx->A21 != NULL ) { fprintf(fp, "\n\n original (2,1) matrix") ; InpMtx_writeForHumanEye(mtx->A21, fp) ; } } return(1) ; } /*--------------------------------------------------------------------*/ SemiImplMtx/src/basics.c010064400020550007177000000067760661365747700165450ustar00clevecompmath00000400000006/* basics.c */ #include "../SemiImplMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98oct16, cca ----------------------- */ SemiImplMtx * SemiImplMtx_new ( void ) { SemiImplMtx *mtx ; ALLOCATE(mtx, struct _SemiImplMtx, 1) ; SemiImplMtx_setDefaultFields(mtx) ; return(mtx) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct16, cca ----------------------- */ int SemiImplMtx_setDefaultFields ( SemiImplMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SemiImplMtx_setDefaultFields(%p)" "\n bad input", mtx) ; return(-1) ; } mtx->neqns = 0 ; mtx->type = SPOOLES_REAL ; mtx->symmetryflag = SPOOLES_SYMMETRIC ; mtx->ndomeqns = 0 ; mtx->nschureqns = 0 ; mtx->domainMtx = NULL ; mtx->schurMtx = NULL ; mtx->A21 = NULL ; mtx->A12 = NULL ; mtx->domRowsIV = NULL ; mtx->schurRowsIV = NULL ; mtx->domColsIV = NULL ; mtx->schurColsIV = NULL ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct16, cca -------------------------------------------------- */ int SemiImplMtx_clearData ( SemiImplMtx *mtx ) { int ieqn, neqns ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SemiImplMtx_clearData(%p)" "\n bad input\n", mtx) ; return(-1) ; } if ( (neqns = mtx->neqns) <= 0 ) { return(1) ; } if ( mtx->domainMtx != NULL ) { ETree *etree = mtx->domainMtx->frontETree ; IVL *symbfacIVL = mtx->domainMtx->symbfacIVL ; FrontMtx_free(mtx->domainMtx) ; ETree_free(etree) ; IVL_free(symbfacIVL) ; } if ( mtx->schurMtx != NULL ) { ETree *etree = mtx->schurMtx->frontETree ; IVL *symbfacIVL = mtx->schurMtx->symbfacIVL ; FrontMtx_free(mtx->schurMtx) ; ETree_free(etree) ; IVL_free(symbfacIVL) ; } if ( mtx->A12 != NULL ) { InpMtx_free(mtx->A12) ; } if ( mtx->domRowsIV != NULL ) { IV_free(mtx->domRowsIV) ; } if ( mtx->domColsIV != NULL ) { IV_free(mtx->domColsIV) ; } if ( mtx->schurRowsIV != NULL ) { IV_free(mtx->schurRowsIV) ; } if ( mtx->schurColsIV != NULL ) { IV_free(mtx->schurColsIV) ; } if ( mtx->symmetryflag == SPOOLES_NONSYMMETRIC ) { if ( mtx->A21 != NULL ) { InpMtx_free(mtx->A21) ; } } /* ---------------------- set the default fields ---------------------- */ SemiImplMtx_setDefaultFields(mtx) ; return(-1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data return code -- 1 -- normal return -1 -- mtx is NULL created -- 98oct16, cca ------------------------------------------ */ int SemiImplMtx_free ( SemiImplMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SemiImplMtx_free(%p)" "\n bad input\n", mtx) ; return(-1) ; } SemiImplMtx_clearData(mtx) ; FREE(mtx) ; return(1) ; } /*--------------------------------------------------------------------*/ SemiImplMtx/src/init.c010064400020550007177000000554520661365722000162210ustar00clevecompmath00000400000006/* init.c */ #include "../SemiImplMtx.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- to initialize the semi-implicit matrix using as input a FrontMtx and a map from fronts to domains (map[J] != 0) or the schur complement (map[J] = 0) return value -- 1 -- normal return -1 -- semimtx is NULL -2 -- frontmtx is NULL -3 -- inpmtx is NULL -4 -- frontmapIV is NULL -5 -- frontmapIV is invalid -6 -- unable to create domains' front matrix -7 -- unable to create schur complement front matrix created -- 98oct17, cca ------------------------------------------------------------------ */ int SemiImplMtx_initFromFrontMtx ( SemiImplMtx *semimtx, FrontMtx *frontmtx, InpMtx *inpmtx, IV *frontmapIV, int msglvl, FILE *msgFile ) { FrontMtx *domMtx, *schurMtx ; InpMtx *A12, *A21 ; int ii, J, ncol, nfront, nrow, rc, size ; int *cols, *frontmap, *rows ; IV *domColsIV, *domidsIV, *domRowsIV, *schurColsIV, *schuridsIV, *schurRowsIV ; /* -------------- check the data -------------- */ if ( semimtx == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_initFromFrontMtx()" "\n semimtx is NULL\n") ; return(-1) ; } if ( frontmtx == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_initFromFrontMtx()" "\n frontmtx is NULL\n") ; return(-2) ; } if ( inpmtx == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_initFromFrontMtx()" "\n inpmtx is NULL\n") ; return(-3) ; } if ( frontmapIV == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_initFromFrontMtx()" "\n frontmapIV is NULL\n") ; return(-4) ; } nfront = FrontMtx_nfront(frontmtx) ; IV_sizeAndEntries(frontmapIV, &size, &frontmap) ; if ( nfront != size ) { fprintf(stderr, "\n error in SemiImplMtx_initFromFrontMtx()" "\n nfront %d, size of front map %d\n", nfront, size) ; return(-5) ; } domidsIV = IV_new() ; schuridsIV = IV_new() ; for ( J = 0 ; J < nfront ; J++ ) { if ( frontmap[J] == 0 ) { IV_push(schuridsIV, J) ; } else if ( frontmap[J] > 0 ) { IV_push(domidsIV, J) ; } else { fprintf(stderr, "\n error in SemiImplMtx_initFromFrontMtx()" "\n frontmap[%d] = %d, invalid\n", J, frontmap[J]) ; IV_free(domidsIV) ; IV_free(schuridsIV) ; return(-5) ; } } /* ----------------------------------------------------------- clear the data for the semi-implicit matrix and set scalars ----------------------------------------------------------- */ SemiImplMtx_clearData(semimtx) ; semimtx->neqns = frontmtx->neqns ; semimtx->type = frontmtx->type ; semimtx->symmetryflag = frontmtx->symmetryflag ; /* ---------------------------------------------- get the front matrix that contains the domains ---------------------------------------------- */ if ( msglvl > 4 ) { fprintf(msgFile, "\n\n working on domain front matrix") ; fflush(msgFile) ; } domMtx = semimtx->domainMtx = FrontMtx_new() ; domRowsIV = semimtx->domRowsIV = IV_new() ; domColsIV = semimtx->domColsIV = IV_new() ; rc = FrontMtx_initFromSubmatrix(domMtx, frontmtx, domidsIV, domRowsIV, domColsIV, msglvl, msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n error in SemiImplMtx_initFromFrontMtx()" "\n unable to initialize the domains' front matrix" "\n error return = %d\n", rc) ; return(-6) ; } semimtx->ndomeqns = IV_size(domRowsIV) ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n---------------------------------------- ") ; fprintf(msgFile, "\n\n submatrix for domains") ; FrontMtx_writeForHumanEye(domMtx, msgFile) ; fflush(msgFile) ; } if ( msglvl > 4 ) { FrontMtx_writeForMatlab(domMtx, "L11", "D11", "U11", msgFile) ; IV_writeForMatlab(domRowsIV, "domrows", msgFile) ; IV_writeForMatlab(domColsIV, "domcols", msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------- get the front matrix that contains the schur complement ------------------------------------------------------- */ if ( msglvl > 4 ) { fprintf(msgFile, "\n\n working on domain front matrix") ; fflush(msgFile) ; } schurMtx = semimtx->schurMtx = FrontMtx_new() ; schurRowsIV = semimtx->schurRowsIV = IV_new() ; schurColsIV = semimtx->schurColsIV = IV_new() ; rc = FrontMtx_initFromSubmatrix(schurMtx, frontmtx, schuridsIV, schurRowsIV, schurColsIV, msglvl, msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n error in SemiImplMtx_initFromFrontMtx()" "\n unable to initialize the schur complement front matrix" "\n error return = %d\n", rc) ; return(-6) ; } semimtx->nschureqns = IV_size(schurRowsIV) ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n---------------------------------------- ") ; fprintf(msgFile, "\n\n submatrix for schur complement") ; FrontMtx_writeForHumanEye(schurMtx, msgFile) ; fflush(msgFile) ; } if ( msglvl > 4 ) { FrontMtx_writeForMatlab(schurMtx, "L22", "D22", "U22", msgFile) ; IV_writeForMatlab(schurRowsIV, "schurrows", msgFile) ; IV_writeForMatlab(schurColsIV, "schurcols", msgFile) ; fflush(msgFile) ; } /* ------------------------- get the A12 InpMtx object ------------------------- */ A12 = semimtx->A12 = InpMtx_new() ; rc = InpMtx_initFromSubmatrix(A12, inpmtx, domRowsIV, schurColsIV, semimtx->symmetryflag, msglvl, msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n error in SemiImplMtx_initFromFrontMtx()" "\n unable to create A21 matrix" "\n error return = %d\n", rc) ; return(-6) ; } InpMtx_changeCoordType(A12, INPMTX_BY_ROWS) ; InpMtx_changeStorageMode(A12, INPMTX_BY_VECTORS) ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n---------------------------------------- ") ; fprintf(msgFile, "\n\n domRowsIV ") ; IV_writeForHumanEye(domRowsIV, msgFile) ; fprintf(msgFile, "\n\n schurColsIV ") ; IV_writeForHumanEye(schurColsIV, msgFile) ; fprintf(msgFile, "\n\n A12 matrix") ; InpMtx_writeForHumanEye(A12, msgFile) ; fflush(msgFile) ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n\n A12 = zeros(%d,%d) ;", IV_size(domRowsIV), IV_size(schurColsIV)) ; InpMtx_writeForMatlab(A12, "A12", msgFile) ; fflush(msgFile) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* ------------------------- get the A21 InpMtx object ------------------------- */ A21 = semimtx->A21 = InpMtx_new() ; rc = InpMtx_initFromSubmatrix(A21, inpmtx, schurRowsIV, domColsIV, semimtx->symmetryflag, msglvl, msgFile) ; if ( rc != 1 ) { fprintf(stderr, "\n error in SemiImplMtx_initFromFrontMtx()" "\n unable to create A21 matrix" "\n error return = %d\n", rc) ; return(-6) ; } InpMtx_changeCoordType(A21, INPMTX_BY_COLUMNS) ; InpMtx_changeStorageMode(A21, INPMTX_BY_VECTORS) ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n--------------------------------------- ") ; fprintf(msgFile, "\n\n schurRowsIV ") ; IV_writeForHumanEye(schurRowsIV, msgFile) ; fprintf(msgFile, "\n\n domColsIV ") ; IV_writeForHumanEye(domColsIV, msgFile) ; fprintf(msgFile, "\n\n A21 matrix") ; InpMtx_writeForHumanEye(A21, msgFile) ; fflush(msgFile) ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n\n A21 = zeros(%d,%d) ;", IV_size(schurRowsIV), IV_size(domColsIV)) ; InpMtx_writeForMatlab(A21, "A21", msgFile) ; fflush(msgFile) ; } } /* ------------------------ free the working storage ------------------------ */ IV_free(domidsIV) ; IV_free(schuridsIV) ; return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- purpose -- to fill submtx with a submatrix of the front matrix. the fronts that form the submatrix are found in frontidsIV. all information in submtx is local, front #'s are from 0 to one less than the number of fronts in the submatrix, equation #'s are from 0 to one less than the number of rows and columns in the submatrix. the global row and column ids for the submatrix are stored in rowsIV and colsIV on return. return values --- 1 -- normal return -1 -- submtx is NULL -2 -- frontmtx is NULL -3 -- frontmtx is not in 2-D mode -4 -- frontidsIV is NULL -5 -- frontidsIV is invalid -6 -- rowsIV is NULL -7 -- colsIV is NULL -8 -- unable to create front tree -9 -- unable to create symbfacIVL -10 -- unable to create coladjIVL -11 -- unable to create rowadjIVL -12 -- unable to create upperblockIVL -13 -- unable to create lowerblockIVL created -- 98oct17, cca -------------------------------------------------------------------- */ int FrontMtx_initFromSubmatrix ( FrontMtx *submtx, FrontMtx *frontmtx, IV *frontidsIV, IV *rowsIV, IV *colsIV, int msglvl, FILE *msgFile ) { ETree *etreeSub ; int ii, J, Jsub, K, Ksub, ncol, nfront, nfrontSub, neqnSub, nJ, nrow, offset, rc, size, vSub ; int *bndwghts, *colind, *colmap, *cols, *frontSubIds, *list, *nodwghts, *rowind, *rowmap, *rows ; IV *frontsizesIVsub, *vtxIV ; IVL *coladjIVLsub, *lowerblockIVLsub, *rowadjIVLsub, *symbfacIVLsub, *upperblockIVLsub ; SubMtx *mtx ; /* --------------- check the input --------------- */ if ( submtx == NULL ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n submtx is NULL\n") ; return(-1) ; } if ( frontmtx == NULL ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n frontmtx is NULL\n") ; return(-2) ; } if ( ! FRONTMTX_IS_2D_MODE(frontmtx) ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n frontmtx mode is not 2D\n") ; return(-3) ; } if ( frontidsIV == NULL ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n frontidsIV is NULL\n") ; return(-4) ; } nfront = FrontMtx_nfront(frontmtx) ; IV_sizeAndEntries(frontidsIV, &nfrontSub, &frontSubIds) ; if ( nfrontSub < 0 || nfrontSub > nfront ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n invalid frontidsIV" "\n nfrontSub = %d, nfront %d\n", nfrontSub, nfront) ; return(-5) ; } for ( ii = 0 ; ii < nfrontSub ; ii++ ) { if ( (J = frontSubIds[ii]) < 0 || J >= nfront ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n invalid frontidsIV" "\n frontSubIds[%d] = %d, nfront = %d\n", ii, J, nfront) ; return(-5) ; } } if ( rowsIV == NULL ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n rowsIV is NULL\n") ; return(-6) ; } if ( colsIV == NULL ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n colsIV is NULL\n") ; return(-7) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- clear the data for the submatrix and set the scalar values (some inherited from the global matrix) ----------------------------------------------------- */ FrontMtx_clearData(submtx) ; submtx->nfront = nfrontSub ; submtx->type = frontmtx->type ; submtx->symmetryflag = frontmtx->symmetryflag ; submtx->sparsityflag = frontmtx->sparsityflag ; submtx->pivotingflag = frontmtx->pivotingflag ; submtx->dataMode = FRONTMTX_2D_MODE ; /* --------------------------------------------------------------- initialize the front tree for the submatrix. note: on return, vtxIV is filled with the vertices originally in the submatrix, (pivoting may change this), needed to find symbolic factorization IVL object note: at return, the boundary weights are likely to be invalid, since we have no way of knowing what boundary indices for a front are really in the domain. this will be changed after we have the symbolic factorization. --------------------------------------------------------------- */ etreeSub = submtx->frontETree = ETree_new() ; vtxIV = IV_new() ; rc = ETree_initFromSubtree(etreeSub, frontidsIV, frontmtx->frontETree, vtxIV) ; if ( rc != 1 ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n unable to create submatrix's front ETree, rc = %d\n", rc) ; return(-8) ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n\n submatrix ETree") ; ETree_writeForHumanEye(etreeSub, msgFile) ; fprintf(msgFile, "\n\n submatrix original equations") ; IV_writeForHumanEye(vtxIV, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------ set the # of equations (perhap temporarily if pivoting has delayed some rows and columns), and the tree. ------------------------------------------------------ */ submtx->neqns = neqnSub = IV_size(vtxIV) ; submtx->tree = etreeSub->tree ; /* ----------------------------------------------------- initialize the symbolic factorization for the subtree ----------------------------------------------------- */ symbfacIVLsub = submtx->symbfacIVL = IVL_new() ; rc = IVL_initFromSubIVL(symbfacIVLsub, frontmtx->symbfacIVL, frontidsIV, vtxIV) ; if ( rc != 1 ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n unable to create submatrix's symbfac, rc = %d\n", rc) ; return(-9) ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n\n submatrix symbolic factorizatio") ; IVL_writeForHumanEye(symbfacIVLsub, msgFile) ; fflush(msgFile) ; } /* --------------------------------------------- adjust the boundary weights of the front tree --------------------------------------------- */ nodwghts = ETree_nodwghts(etreeSub) ; bndwghts = ETree_bndwghts(etreeSub) ; for ( J = 0 ; J < nfrontSub ; J++ ) { IVL_listAndSize(symbfacIVLsub, J, &size, &list) ; bndwghts[J] = size - nodwghts[J] ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n\n submatrix ETree after bndweight adjustment") ; ETree_writeForHumanEye(etreeSub, msgFile) ; fflush(msgFile) ; } /* ------------------------------------- set the front sizes for the submatrix ------------------------------------- */ frontsizesIVsub = submtx->frontsizesIV = IV_new() ; IV_init(frontsizesIVsub, nfrontSub, NULL) ; IVgather(nfrontSub, IV_entries(frontsizesIVsub), IV_entries(frontmtx->frontsizesIV), IV_entries(frontidsIV)) ; neqnSub = submtx->neqns = IV_sum(frontsizesIVsub) ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n %d equations in submatrix", neqnSub) ; fprintf(msgFile, "\n\n front sizes for submatrix") ; IV_writeForHumanEye(frontsizesIVsub, msgFile) ; fflush(msgFile) ; } /* ------------------------------------------------------------------- fill rowsIV and colsIV with the row and column ids of the submatrix ------------------------------------------------------------------- */ IV_setSize(rowsIV, neqnSub) ; IV_setSize(colsIV, neqnSub) ; rows = IV_entries(rowsIV) ; cols = IV_entries(colsIV) ; for ( Jsub = offset = 0 ; Jsub < nfrontSub ; Jsub++ ) { if ( (nJ = FrontMtx_frontSize(submtx, Jsub)) > 0 ) { J = frontSubIds[Jsub] ; FrontMtx_columnIndices(frontmtx, J, &size, &list) ; IVcopy(nJ, cols + offset, list) ; FrontMtx_rowIndices(frontmtx, J, &size, &list) ; IVcopy(nJ, rows + offset, list) ; offset += nJ ; } } if ( msglvl > 4 ) { fprintf(msgFile, "\n\n row ids for submatrix") ; IV_writeForHumanEye(rowsIV, msgFile) ; fprintf(msgFile, "\n\n column ids for submatrix") ; IV_writeForHumanEye(colsIV, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- get the row and column adjacencies ---------------------------------- */ if ( FRONTMTX_IS_PIVOTING(frontmtx) ) { submtx->neqns = neqnSub ; coladjIVLsub = submtx->coladjIVL = IVL_new() ; rc = IVL_initFromSubIVL(coladjIVLsub, frontmtx->coladjIVL, frontidsIV, colsIV) ; if ( rc != 1 ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n unable to create submatrix's coladjIVL, rc = %d\n", rc) ; return(-10) ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n\n submatrix col adjacency") ; IVL_writeForHumanEye(coladjIVLsub, msgFile) ; fflush(msgFile) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { rowadjIVLsub = submtx->rowadjIVL = IVL_new() ; rc = IVL_initFromSubIVL(rowadjIVLsub, frontmtx->rowadjIVL, frontidsIV, rowsIV) ; if ( rc != 1 ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n unable to create submatrix's rowadjIVL, rc = %d\n", rc) ; return(-11) ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n\n submatrix row adjacency") ; IVL_writeForHumanEye(rowadjIVLsub, msgFile) ; fflush(msgFile) ; } } } IV_free(vtxIV) ; /* ---------------------------------------------- get the rowmap[] and colmap[] vectors, needed to translate indices in the submatrices ---------------------------------------------- */ colmap = IVinit(frontmtx->neqns, -1) ; for ( ii = 0 ; ii < neqnSub ; ii++ ) { colmap[cols[ii]] = ii ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { rowmap = IVinit(frontmtx->neqns, -1) ; for ( ii = 0 ; ii < neqnSub ; ii++ ) { rowmap[rows[ii]] = ii ; } } else { rowmap = colmap ; } /* ----------------------------------------------------------- get the upper and lower block IVL objects for the submatrix ----------------------------------------------------------- */ upperblockIVLsub = submtx->upperblockIVL = IVL_new() ; rc = IVL_initFromSubIVL(upperblockIVLsub, frontmtx->upperblockIVL, frontidsIV, frontidsIV) ; if ( rc != 1 ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n unable to create upperblockIVL, rc = %d\n", rc) ; return(-12) ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n\n upper block adjacency IVL object") ; IVL_writeForHumanEye(upperblockIVLsub, msgFile) ; fflush(msgFile) ; } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { lowerblockIVLsub = submtx->lowerblockIVL = IVL_new() ; rc = IVL_initFromSubIVL(lowerblockIVLsub, frontmtx->lowerblockIVL, frontidsIV, frontidsIV) ; if ( rc != 1 ) { fprintf(stderr, "\n error in FrontMtx_initFromSubmatrix()" "\n unable to create lowerblockIVL, rc = %d\n", rc) ; return(-13) ; } if ( msglvl > 4 ) { fprintf(msgFile, "\n\n lower block adjacency IVL object") ; IVL_writeForHumanEye(lowerblockIVLsub, msgFile) ; fflush(msgFile) ; } } /* ---------------------------------------------------------------- allocate the vector and hash table(s) for the factor submatrices ---------------------------------------------------------------- */ ALLOCATE(submtx->p_mtxDJJ, struct _SubMtx *, nfrontSub) ; for ( J = 0 ; J < nfrontSub ; J++ ) { submtx->p_mtxDJJ[J] = NULL ; } submtx->upperhash = I2Ohash_new() ; I2Ohash_init(submtx->upperhash, nfrontSub, nfrontSub, nfrontSub) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { submtx->lowerhash = I2Ohash_new() ; I2Ohash_init(submtx->lowerhash, nfrontSub, nfrontSub, nfrontSub) ; } /* ----------------------------------------------------------------- remove the diagonal submatrices from the factor matrix and insert into the submatrix object. note: front row and column ids must be changed to their local values, and the row and column indices must be mapped to local indices. ----------------------------------------------------------------- */ for ( Jsub = 0 ; Jsub < nfrontSub ; Jsub++ ) { J = frontSubIds[Jsub] ; if ( (mtx = frontmtx->p_mtxDJJ[J]) != NULL ) { SubMtx_setIds(mtx, Jsub, Jsub) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVgather(ncol, colind, colmap, colind) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVgather(nrow, rowind, rowmap, rowind) ; submtx->p_mtxDJJ[Jsub] = mtx ; frontmtx->p_mtxDJJ[J] = NULL ; submtx->nentD += mtx->nent ; } } /* ---------------------------------------------------------------- remove the upper triangular submatrices from the factor matrix and insert into the submatrix object. note: front row and column ids must be changed to their local values. if the matrix is on the diagonal, i.e., U(J,J), its row and column indices must be mapped to local indices. ---------------------------------------------------------------- */ for ( Jsub = 0 ; Jsub < nfrontSub ; Jsub++ ) { J = frontSubIds[Jsub] ; FrontMtx_upperAdjFronts(submtx, Jsub, &size, &list) ; for ( ii = 0 ; ii < size ; ii++ ) { Ksub = list[ii] ; K = frontSubIds[Ksub] ; if ( 1 == I2Ohash_remove(frontmtx->upperhash, J, K, (void *) &mtx) ) { SubMtx_setIds(mtx, Jsub, Ksub) ; if ( K == J ) { SubMtx_columnIndices(mtx, &ncol, &colind) ; IVgather(ncol, colind, colmap, colind) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVgather(nrow, rowind, rowmap, rowind) ; } I2Ohash_insert(submtx->upperhash, Jsub, Ksub, (void *) mtx) ; submtx->nentU += mtx->nent ; } } } if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { /* ---------------------------------------------------------------- remove the lower triangular submatrices from the factor matrix and insert into the submatrix object. note: front row and column ids must be changed to their local values. if the matrix is on the diagonal, i.e., L(J,J), its row and column indices must be mapped to local indices. ---------------------------------------------------------------- */ for ( Jsub = 0 ; Jsub < nfrontSub ; Jsub++ ) { J = frontSubIds[Jsub] ; FrontMtx_lowerAdjFronts(submtx, Jsub, &size, &list) ; for ( ii = 0 ; ii < size ; ii++ ) { Ksub = list[ii] ; K = frontSubIds[Ksub] ; if ( 1 == I2Ohash_remove(frontmtx->lowerhash, K, J, (void *) &mtx) ) { SubMtx_setIds(mtx, Ksub, Jsub) ; if ( K == J ) { SubMtx_columnIndices(mtx, &ncol, &colind) ; IVgather(ncol, colind, colmap, colind) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVgather(nrow, rowind, rowmap, rowind) ; } I2Ohash_insert(submtx->lowerhash, Ksub, Jsub, (void *) mtx); submtx->nentL += mtx->nent ; } } } } /* ------------------------ free the working storage ------------------------ */ IVfree(colmap) ; if ( FRONTMTX_IS_NONSYMMETRIC(frontmtx) ) { IVfree(rowmap) ; } return(1) ; } /*--------------------------------------------------------------------*/ set the # of equations (perhap temporarily if pivoting has delayed some rows and columns), and the tree. ------------------------------------------------------ */ submtx->neqns = neqnSub = IV_size(vtxIV) SemiImplMtx/src/solve.c010064400020550007177000000204110661366123300163700ustar00clevecompmath00000400000006/* solve.c */ #include "../SemiImplMtx.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to solve the linear system A X = B using a semi-implicit factorization on return --- cpus[0] -- time to initialize working matrices cpus[1] -- time to load rhs cpus[2] -- time for first solve with domains cpus[3] -- time to compute schur rhs cpus[4] -- time for schur solve cpus[5] -- time to compute domains' rhs cpus[6] -- time for second solve with domains cpus[7] -- time to store solution cpus[8] -- miscellaneous time cpus[9] -- total time return value -- 1 -- normal return -1 -- semimtx is NULL -2 -- mtxX is NULL -3 -- mtxB is NULL -4 -- mtxmanager is NULL -5 -- cpus is NULL created -- 98oct17, cca ------------------------------------------------ */ int SemiImplMtx_solve ( SemiImplMtx *semimtx, DenseMtx *mtxX, DenseMtx *mtxB, SubMtxManager *mtxmanager, double cpus[], int msglvl, FILE *msgFile ) { DenseMtx *T1, *T2 ; double t0, t1, t2 ; double alpha[2] = {-1.0, 0.0} ; double localcpus[6] ; int irow, ndomeqns, nrhs, nschureqns ; int *domCols, *domRows, *schurCols, *schurRows ; /* --------------- check the input --------------- */ MARKTIME(t0) ; if ( semimtx == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_solve()" "\n semimtx is NULL\n") ; return(-1) ; } if ( mtxX == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_solve()" "\n mtxX is NULL\n") ; return(-2) ; } if ( mtxB == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_solve()" "\n mtxB is NULL\n") ; return(-3) ; } if ( mtxmanager == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_solve()" "\n mtxmanager is NULL\n") ; return(-4) ; } if ( cpus == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_solve()" "\n cpus is NULL\n") ; return(-5) ; } if ( msglvl > 0 && msgFile == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_solve()" "\n msglvl = %d, msgFile is NULL\n", msglvl) ; return(-6) ; } DVzero(10, cpus) ; nrhs = mtxX->ncol ; if ( msglvl > 4 ) { DenseMtx_writeForMatlab(mtxB, "B", msgFile) ; DenseMtx_writeForMatlab(mtxX, "X", msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- create two DenseMtx objects to store the domain's and schur complement's rhs and solution ------------------------------------------------- */ MARKTIME(t1) ; IV_sizeAndEntries(semimtx->domRowsIV, &ndomeqns, &domRows) ; IV_sizeAndEntries(semimtx->schurRowsIV, &nschureqns, &schurRows) ; T1 = DenseMtx_new() ; DenseMtx_init(T1, mtxX->type, -1, -1, ndomeqns, nrhs, 1, ndomeqns) ; T2 = DenseMtx_new() ; DenseMtx_init(T2, mtxX->type, -1, -1, nschureqns, nrhs, 1, nschureqns) ; MARKTIME(t2) ; cpus[0] = t2 - t1 ; /* --------------------------------------- load T1 with the domains' rhs and load T2 with the schur complement's rhs --------------------------------------- */ MARKTIME(t1) ; for ( irow = 0 ; irow < ndomeqns ; irow++ ) { DenseMtx_copyRow(T1, irow, mtxB, domRows[irow]) ; } for ( irow = 0 ; irow < nschureqns ; irow++ ) { DenseMtx_copyRow(T2, irow, mtxB, schurRows[irow]) ; } MARKTIME(t2) ; cpus[1] = t2 - t1 ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n T1 loaded with B1") ; DenseMtx_writeForHumanEye(T1, msgFile) ; fprintf(msgFile, "\n\n T2 loaded with B2") ; DenseMtx_writeForHumanEye(T2, msgFile) ; fflush(msgFile) ; } if ( msglvl > 4 ) { DenseMtx_writeForMatlab(T1, "B1", msgFile) ; DenseMtx_writeForMatlab(T2, "B2", msgFile) ; fflush(msgFile) ; } /* ------------------------------------ if symmetric then solve (U11^T+I)D11(I+U11) T1 = B1 else if hermitian then solve (U11^H+I)D11(I+U11) T1 = B1 else if nonsymmetric then solve (L11+I)D11(I+U11) T1 = B1 end ------------------------------------ */ MARKTIME(t1) ; DVzero(6, localcpus) ; FrontMtx_solve(semimtx->domainMtx, T1, T1, mtxmanager, localcpus, msglvl, msgFile) ; MARKTIME(t2) ; cpus[2] = t2 - t1 ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n T1 after first solve") ; DenseMtx_writeForHumanEye(T1, msgFile) ; fflush(msgFile) ; } if ( msglvl > 4 ) { DenseMtx_writeForMatlab(T1, "T1", msgFile) ; fflush(msgFile) ; } /* -------------------------------- if symmetric then compute T2 := T2 - A12^T * T1 else if hermitian then compute T2 := T2 - A12^H * T1 else if nonsymmetric then compute T2 := T2 - A21 * T1 end -------------------------------- */ MARKTIME(t1) ; switch ( semimtx->symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_nonsym_mmm_T(semimtx->A12, T2, alpha, T1) ; break ; case SPOOLES_HERMITIAN : InpMtx_nonsym_mmm_H(semimtx->A12, T2, alpha, T1) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_mmm(semimtx->A21, T2, alpha, T1) ; break ; } MARKTIME(t2) ; cpus[3] = t2 - t1 ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n schur rhs") ; DenseMtx_writeForHumanEye(T2, msgFile) ; fflush(msgFile) ; } if ( msglvl > 4 ) { DenseMtx_writeForMatlab(T2, "T2", msgFile) ; fflush(msgFile) ; } /* ------------------------------------ if symmetric then solve (U22^T+I)D22(I+U22) T2 = B2 else if hermitian then solve (U22^H+I)D22(I+U22) T2 = B2 else if nonsymmetric then solve (L22+I)D22(I+U22) T2 = B2 end note: X2 = T2 ------------------------------------ */ MARKTIME(t1) ; DVzero(6, localcpus) ; FrontMtx_solve(semimtx->schurMtx, T2, T2, mtxmanager, localcpus, msglvl, msgFile) ; MARKTIME(t2) ; cpus[4] = t2 - t1 ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n schur solution") ; DenseMtx_writeForHumanEye(T2, msgFile) ; fflush(msgFile) ; } if ( msglvl > 4 ) { DenseMtx_writeForMatlab(T2, "X2", msgFile) ; fflush(msgFile) ; } /* --------------------------- compute T1 := B1 - A21 * T2 --------------------------- */ MARKTIME(t1) ; for ( irow = 0 ; irow < ndomeqns ; irow++ ) { DenseMtx_copyRow(T1, irow, mtxB, domRows[irow]) ; } InpMtx_nonsym_mmm(semimtx->A12, T1, alpha, T2) ; MARKTIME(t2) ; cpus[5] = t2 - t1 ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n domain rhs") ; DenseMtx_writeForHumanEye(T1, msgFile) ; fflush(msgFile) ; } if ( msglvl > 4 ) { DenseMtx_writeForMatlab(T1, "W1", msgFile) ; fflush(msgFile) ; } /* ------------------------------------ if symmetric then solve (U11^T+I)D11(I+U11) X1 = T1 else if hermitian then solve (U11^H+I)D11(I+U11) X1 = T1 else if nonsymmetric then solve (L11+I)D11(I+U11) X1 = T1 end ------------------------------------ */ MARKTIME(t1) ; DVzero(6, localcpus) ; FrontMtx_solve(semimtx->domainMtx, T1, T1, mtxmanager, localcpus, msglvl, msgFile) ; MARKTIME(t2) ; cpus[6] = t2 - t1 ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n domain solution") ; DenseMtx_writeForHumanEye(T1, msgFile) ; fflush(msgFile) ; } if ( msglvl > 4 ) { DenseMtx_writeForMatlab(T1, "X1", msgFile) ; fflush(msgFile) ; } /* ------------------------------------ load mtxX with the domains' solution and the schur complement's solution ------------------------------------ */ MARKTIME(t1) ; IV_sizeAndEntries(semimtx->domColsIV, &ndomeqns, &domCols) ; IV_sizeAndEntries(semimtx->schurColsIV, &nschureqns, &schurCols) ; for ( irow = 0 ; irow < ndomeqns ; irow++ ) { DenseMtx_copyRow(mtxX, domCols[irow], T1, irow) ; } for ( irow = 0 ; irow < nschureqns ; irow++ ) { DenseMtx_copyRow(mtxX, schurCols[irow], T2, irow) ; } MARKTIME(t2) ; cpus[7] = t2 - t1 ; if ( msglvl > 4 ) { DenseMtx_writeForMatlab(mtxX, "Xcomp", msgFile) ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ DenseMtx_free(T1) ; DenseMtx_free(T2) ; MARKTIME(t2) ; cpus[9] = t2 - t0 ; cpus[8] = cpus[9] - cpus[0] - cpus[1] - cpus[2] - cpus[3] - cpus[4] - cpus[5] - cpus[6] - cpus[7] ; /* fprintf(msgFile, "\n solve cpus") ; DVfprintf(msgFile, 10, cpus) ; */ return(1) ; } /*--------------------------------------------------------------------*/ SemiImplMtx/src/util.c010064400020550007177000000055630661371300000162160ustar00clevecompmath00000400000006/* util.c */ #include "../SemiImplMtx.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- fill a statistics array for a semi-implicit factorization stats[0] -- # of equations stats[1] -- # of equations in the (1,1) block stats[2] -- # of equations in the (2,2) block stats[3] -- # of entries in L11 stats[4] -- # of entries in D11 stats[5] -- # of entries in U11 stats[6] -- # of entries in L22 stats[7] -- # of entries in D22 stats[8] -- # of entries in U22 stats[9] -- # of entries in A12 stats[10] -- # of entries in A21 stats[11] -- total # of entries stats[12] -- # of operations for a solve return value --- 1 -- normal return -1 -- semimtx is NULL -2 -- stats is NULL created -- 98oct22, cca --------------------------------------------------------- */ int SemiImplMtx_stats ( SemiImplMtx *semimtx, int stats[] ) { /* --------------- check the input --------------- */ if ( semimtx == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_stats()" "\n semimtx is NULL\n") ; return(-1) ; } if ( stats == NULL ) { fprintf(stderr, "\n error in SemiImplMtx_stats()" "\n stats is NULL\n") ; return(-2) ; } stats[0] = semimtx->neqns ; stats[1] = semimtx->ndomeqns ; stats[2] = semimtx->nschureqns ; if ( semimtx->domainMtx != NULL ) { stats[3] = semimtx->domainMtx->nentL ; stats[4] = semimtx->domainMtx->nentD ; stats[5] = semimtx->domainMtx->nentU ; } else { stats[3] = 0 ; stats[4] = 0 ; stats[5] = 0 ; } if ( semimtx->schurMtx != NULL ) { stats[6] = semimtx->schurMtx->nentL ; stats[7] = semimtx->schurMtx->nentD ; stats[8] = semimtx->schurMtx->nentU ; } else { stats[6] = 0 ; stats[7] = 0 ; stats[8] = 0 ; } if ( semimtx->A12 != NULL ) { stats[9] = semimtx->A12->nent ; } else { stats[9] = 0 ; } if ( semimtx->A21 != NULL ) { stats[10] = semimtx->A21->nent ; } else { stats[10] = 0 ; } stats[11] = stats[3] + stats[4] + stats[5] + stats[6] + stats[7] + stats[8] + stats[9] + stats[10] ; stats[12] = 0.0 ; if ( semimtx->domainMtx != NULL ) { stats[12] += 2*FrontMtx_nSolveOps(semimtx->domainMtx) ; } if ( semimtx->schurMtx != NULL ) { stats[12] += FrontMtx_nSolveOps(semimtx->schurMtx) ; } if ( semimtx->A12 != NULL ) { if ( semimtx->type == SPOOLES_REAL ) { stats[12] += 2*semimtx->A12->nent ; } else if ( semimtx->type == SPOOLES_COMPLEX ) { stats[12] += 8*semimtx->A12->nent ; } } if ( semimtx->A21 != NULL ) { if ( semimtx->type == SPOOLES_REAL ) { stats[12] += 2*semimtx->A21->nent ; } else if ( semimtx->type == SPOOLES_COMPLEX ) { stats[12] += 8*semimtx->A21->nent ; } } return(1) ; } /*--------------------------------------------------------------------*/ SemiImplMtx/drivers/do_grid010075500020550007177000000016230661372117000173210ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res3D.64 set msgFile = res set msgFile = /local1/ARPA/junk/res.grid set msgFile = res.31.grid set msgFile = stdout set msgFile = res.grid set n1 = 31 set n2 = 31 set n3 = 31 set maxzeros = 500 set maxzeros = 250 set maxzeros = 750 set maxzeros = 0 set maxzeros = 1000 set maxsize = 1000 set maxsize = 64 set seed = 10101 set type = 1 set symmetryflag = 0 set sparsityflag = 0 set pivotingflag = 0 set tau = 5 set droptol = 1.e-50 set nrhs = 1 set depth = 1 foreach depth ( 1 2 3 4 5 6 7 8 9 ) echo depth = $depth testGrid $msglvl $msgFile $n1 $n2 $n3 $maxzeros $maxsize \ $seed $type $symmetryflag $sparsityflag $pivotingflag\ $tau $droptol $nrhs $depth end 1000 set maxsize = 1000 set maxsize = 64 set seed = 10101 set type = 1 set symmeSemiImplMtx/drivers/do_simple010075500020550007177000000005500661211754000176620ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inFrontMtxFile = ../../FrontMtx/drivers/temp.frontmtxb set inInpMtxFile = ../../FrontMtx/drivers/temp.inpmtxb set inIVfile = ../../FrontMtx/drivers/frontmap.ivf set msglvl = 3 set msgFile = stdout testSimple $msglvl $msgFile $inFrontMtxFile $inInpMtxFile $inIVfile SemiImplMtx/drivers/makefile010064400020550007177000000006620665314264200174730ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a ${THREAD_LIBS} -lm DRIVERS = testSimple testGrid drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testSimple : testSimple.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} testGrid : testGrid.o ../../spooles.a ${PURIFY} ${CC} $(PURIFY_GCC_VERSION) $@.o -o $@ ${LIBS} SemiImplMtx/drivers/testGrid.c010064400020550007177000000415150661370630200177210ustar00clevecompmath00000400000006/* testGrid.c */ #include "../SemiImplMtx.h" #include "../../Drand.h" #include "../../timings.h" #include "../../misc.h" /*--------------------------------------------------------------------*/ IV * get_frontmapIV ( Tree *tree, int depth ) ; /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------------- test the factor method for a grid matrix (1) construct a linear system for a nested dissection ordering on a regular grid (2) create a solution matrix object (3) multiply the solution with the matrix to get a right hand side matrix object (4) factor the matrix (5) solve the system created -- 98may16, cca ----------------------------------------------------- */ { Chv *chv, *rootchv ; ChvManager *chvmanager ; DenseMtx *mtxB, *mtxX, *mtxZ ; FrontMtx *frontmtx ; InpMtx *mtxA ; SemiImplMtx *semimtx ; SubMtxManager *mtxmanager ; double cputotal, droptol, factorops, initCPU ; double cpus[10] ; Drand drand ; double nsolveops, tau, t1, t2 ; ETree *frontETree ; FILE *msgFile ; int depth, error, maxsize, maxzeros, msglvl, neqns, n1, n2, n3, nrhs, nzf, pivotingflag, rc, seed, sparsityflag, symmetryflag, type, v ; int stats[13] ; int *vtxToFront ; IV *frontmapIV ; IVL *symbfacIVL ; if ( argc != 17 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 maxzeros maxsize" "\n seed type symmetryflag sparsityflag " "\n pivotingflag tau droptol nrhs depth" "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- number of grid points in the first direction" "\n n2 -- number of grid points in the second direction" "\n n3 -- number of grid points in the third direction" "\n maxzeros -- max number of zeroes in a front" "\n maxsize -- max number of internal nodes in a front" "\n seed -- random number seed" "\n type -- type of entries" "\n 1 --> real" "\n 2 --> complex" "\n symmetryflag -- symmetry flag" "\n 0 --> symmetric " "\n 1 --> hermitian" "\n 2 --> nonsymmetric" "\n sparsityflag -- sparsity flag" "\n 0 --> store dense fronts" "\n 1 --> store sparse fronts, use droptol to drop entries" "\n pivotingflag -- pivoting flag" "\n 0 --> do not pivot" "\n 1 --> enable pivoting" "\n tau -- upper bound on factor entries" "\n used only with pivoting" "\n droptol -- lower bound on factor entries" "\n used only with sparse fronts" "\n nrhs -- # of right hand sides" "\n depth -- depth for multisector" "\n", argv[0]) ; return(-1) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; n3 = atoi(argv[5]) ; maxzeros = atoi(argv[6]) ; maxsize = atoi(argv[7]) ; seed = atoi(argv[8]) ; type = atoi(argv[9]) ; symmetryflag = atoi(argv[10]) ; sparsityflag = atoi(argv[11]) ; pivotingflag = atoi(argv[12]) ; tau = atof(argv[13]) ; droptol = atof(argv[14]) ; nrhs = atoi(argv[15]) ; depth = atoi(argv[16]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n n1 -- %d" "\n n2 -- %d" "\n n3 -- %d" "\n maxzeros -- %d" "\n maxsize -- %d" "\n seed -- %d" "\n type -- %d" "\n symmetryflag -- %d" "\n sparsityflag -- %d" "\n pivotingflag -- %d" "\n tau -- %e" "\n droptol -- %e" "\n nrhs -- %d" "\n depth -- %d" "\n", argv[0], msglvl, argv[2], n1, n2, n3, maxzeros, maxsize, seed, type, symmetryflag, sparsityflag, pivotingflag, tau, droptol, nrhs, depth) ; fflush(msgFile) ; neqns = n1 * n2 * n3 ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ Drand_setDefaultFields(&drand) ; Drand_init(&drand) ; Drand_setSeed(&drand, seed) ; /* Drand_setUniform(&drand, 0.0, 1.0) ; */ Drand_setNormal(&drand, 0.0, 1.0) ; /* -------------------------- generate the linear system -------------------------- */ mkNDlinsys(n1, n2, n3, maxzeros, maxsize, type, symmetryflag, nrhs, seed, msglvl, msgFile, &frontETree, &symbfacIVL, &mtxA, &mtxX, &mtxB) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n mtxA") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fprintf(msgFile, "\n mtxX") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fprintf(msgFile, "\n mtxB") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n %% MATLAB file: linear system") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", neqns, neqns) ; fprintf(msgFile, "\n X = zeros(%d,1) ;", neqns) ; fprintf(msgFile, "\n B = zeros(%d,1) ;", neqns) ; InpMtx_writeForMatlab(mtxA, "A", msgFile) ; DenseMtx_writeForMatlab(mtxX, "X", msgFile) ; DenseMtx_writeForMatlab(mtxB, "B", msgFile) ; fflush(msgFile) ; } /* ------------------------------ initialize the FrontMtx object ------------------------------ */ MARKTIME(t1) ; frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, sparsityflag, pivotingflag, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : initialize the front matrix", t2 - t1) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n nendD = %d, nentL = %d, nentU = %d", frontmtx->nentD, frontmtx->nentL, frontmtx->nentU) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n front matrix initialized") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; /* ----------------- factor the matrix ----------------- */ nzf = ETree_nFactorEntries(frontETree, symmetryflag) ; factorops = ETree_nFactorOps(frontETree, type, symmetryflag) ; fprintf(msgFile, "\n %d factor entries, %.0f factor ops, %8.3f ratio", nzf, factorops, factorops/nzf) ; IVzero(6, stats) ; DVzero(9, cpus) ; chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1) ; MARKTIME(t1) ; rootchv = FrontMtx_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, &error, cpus, stats, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : factor matrix, %8.3f mflops", t2 - t1, 1.e-6*factorops/(t2-t1)) ; if ( rootchv != NULL ) { fprintf(msgFile, "\n\n factorization did not complete") ; for ( chv = rootchv ; chv != NULL ; chv = chv->next ) { fprintf(stdout, "\n chv %d, nD = %d, nL = %d, nU = %d", chv->id, chv->nD, chv->nL, chv->nU) ; } } if ( error >= 0 ) { fprintf(msgFile, "\n\n error encountered at front %d\n", error) ; exit(-1) ; } fprintf(msgFile, "\n %8d pivots, %8d pivot tests, %8d delayed rows and columns", stats[0], stats[1], stats[2]) ; if ( frontmtx->rowadjIVL != NULL ) { fprintf(msgFile, "\n %d entries in rowadjIVL", frontmtx->rowadjIVL->tsize) ; } if ( frontmtx->coladjIVL != NULL ) { fprintf(msgFile, ", %d entries in coladjIVL", frontmtx->coladjIVL->tsize) ; } if ( frontmtx->upperblockIVL != NULL ) { fprintf(msgFile, "\n %d fronts, %d entries in upperblockIVL", frontmtx->nfront, frontmtx->upperblockIVL->tsize) ; } if ( frontmtx->lowerblockIVL != NULL ) { fprintf(msgFile, ", %d entries in lowerblockIVL", frontmtx->lowerblockIVL->tsize) ; } fprintf(msgFile, "\n %d entries in D, %d entries in L, %d entries in U", stats[3], stats[4], stats[5]) ; fprintf(msgFile, "\n %d locks", frontmtx->nlocks) ; cputotal = cpus[8] ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n initialize fronts %8.3f %6.2f" "\n load original entries %8.3f %6.2f" "\n update fronts %8.3f %6.2f" "\n assemble postponed data %8.3f %6.2f" "\n factor fronts %8.3f %6.2f" "\n extract postponed data %8.3f %6.2f" "\n store factor entries %8.3f %6.2f" "\n miscellaneous %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[6], 100.*cpus[6]/cputotal, cpus[7], 100.*cpus[7]/cputotal, cputotal) ; } SubMtxManager_writeForHumanEye(mtxmanager, msgFile) ; ChvManager_writeForHumanEye(chvmanager, msgFile) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n %% MATLAB file: front factor matrix") ; FrontMtx_writeForMatlab(frontmtx, "L", "D", "U", msgFile) ; fflush(msgFile) ; } /* ------------------------------ post-process the factor matrix ------------------------------ */ MARKTIME(t1) ; FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : post-process the matrix", t2 - t1) ; if ( msglvl > 4 ) { fprintf(msgFile, "\n\n front factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } fprintf(msgFile, "\n\n after post-processing") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ---------------- solve the system ---------------- */ neqns = mtxB->nrow ; nrhs = mtxB->ncol ; mtxZ = DenseMtx_new() ; DenseMtx_init(mtxZ, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxZ) ; nsolveops = FrontMtx_nSolveOps(frontmtx) ; nsolveops *= nrhs ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n rhs") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(stdout) ; } DVzero(6, cpus) ; MARKTIME(t1) ; FrontMtx_solve(frontmtx, mtxZ, mtxB, mtxmanager, cpus, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : direct solve the system, %.0f ops, %.3f mflops", t2 - t1, nsolveops, 1.e-6*nsolveops/(t2 - t1)) ; cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n set up solves %8.3f %6.2f" "\n load rhs and store solution %8.3f %6.2f" "\n forward solve %8.3f %6.2f" "\n diagonal solve %8.3f %6.2f" "\n backward solve %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cputotal) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } DenseMtx_sub(mtxZ, mtxX) ; fprintf(msgFile, "\n\n maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n after solve") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ------------------------ get the front matrix map ------------------------ */ MARKTIME(t1) ; frontmapIV = get_frontmapIV(frontmtx->tree, depth) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : get the front map", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n frontmapIV") ; IV_writeForHumanEye(frontmapIV, msgFile) ; fflush(msgFile) ; } /* -------------------------------------- create the semi-implicit matrix object -------------------------------------- */ MARKTIME(t1) ; semimtx = SemiImplMtx_new() ; rc = SemiImplMtx_initFromFrontMtx(semimtx, frontmtx, mtxA, frontmapIV, msglvl, msgFile) ; MARKTIME(t2) ; initCPU = t2 - t1 ; fprintf(msgFile, "\n\n CPU %8.3f : initialize the SemiImplMtx", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n Semi-implicit matrix") ; SemiImplMtx_writeForHumanEye(semimtx, msgFile) ; fflush(msgFile) ; } SemiImplMtx_stats(semimtx, stats) ; fprintf(msgFile, "\n stats[11] = %d", stats[11]) ; fprintf(msgFile, "\n %d eqns, %d domain eqns, %d schur eqns" "\n |L11| = %d, |D11| = %d, |U11| = %d" "\n |L22| = %d, |D22| = %d, |U22| = %d" "\n |A12| = %d, |A22| = %d," "\n %d total matrix entries, %d solve operations", stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], stats[6], stats[7], stats[8], stats[9], stats[10], stats[11], stats[12]) ; fprintf(msgFile, "\n STATS2 %2d %8d %8d %10d %10d %10d", depth, stats[1], stats[2], stats[3] + stats[4] + stats[5], stats[6] + stats[7] + stats[8], stats[9] + stats[10]) ; /* ------------------------------------------------------ solve the system using the semi-implicit factorization ------------------------------------------------------ */ DenseMtx_zero(mtxZ) ; nsolveops = 2*FrontMtx_nSolveOps(semimtx->domainMtx) ; nsolveops += FrontMtx_nSolveOps(semimtx->schurMtx) ; nsolveops += 2*semimtx->A12->nent ; if ( symmetryflag == SPOOLES_NONSYMMETRIC ) { nsolveops += 2*semimtx->A21->nent ; } else { nsolveops += 2*semimtx->A12->nent ; } nsolveops *= nrhs ; DVzero(9, cpus) ; MARKTIME(t1) ; rc = SemiImplMtx_solve(semimtx, mtxZ, mtxB, mtxmanager, cpus, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : semi solve the system, %.0f ops, %.3f mflops", t2 - t1, nsolveops, 1.e-6*nsolveops/(t2 - t1)) ; fprintf(msgFile, "\n STATS1 %2d %8.3f %11d %16d %10.3f", depth, initCPU, stats[11], stats[12], t2 - t1) ; cputotal = t2 - t1 ; if ( cputotal > 0.0 ) { fprintf(msgFile, "\n init working matrices %8.3f %6.2f" "\n load rhs %8.3f %6.2f" "\n first solve with domains %8.3f %6.2f" "\n compute schur rhs %8.3f %6.2f" "\n solve with schur complement %8.3f %6.2f" "\n compute domains' rhs %8.3f %6.2f" "\n second solve with domains %8.3f %6.2f" "\n store solution %8.3f %6.2f" "\n miscellaneous time %8.3f %6.2f" "\n total time %8.3f", cpus[0], 100.*cpus[0]/cputotal, cpus[1], 100.*cpus[1]/cputotal, cpus[2], 100.*cpus[2]/cputotal, cpus[3], 100.*cpus[3]/cputotal, cpus[4], 100.*cpus[4]/cputotal, cpus[5], 100.*cpus[5]/cputotal, cpus[6], 100.*cpus[6]/cputotal, cpus[7], 100.*cpus[7]/cputotal, cpus[8], 100.*cpus[8]/cputotal, cputotal) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n computed solution") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } DenseMtx_sub(mtxZ, mtxX) ; fprintf(msgFile, "\n\n maxabs error = %12.4e", DenseMtx_maxabs(mtxZ)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n error") ; DenseMtx_writeForHumanEye(mtxZ, msgFile) ; fflush(stdout) ; } fprintf(msgFile, "\n\n after solve") ; SubMtxManager_writeForHumanEye(frontmtx->manager, msgFile) ; /* ------------------------ free the working storage ------------------------ */ InpMtx_free(mtxA) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxB) ; DenseMtx_free(mtxZ) ; SemiImplMtx_free(semimtx) ; FrontMtx_free(frontmtx) ; ETree_free(frontETree) ; IVL_free(symbfacIVL) ; ChvManager_free(chvmanager) ; SubMtxManager_free(mtxmanager) ; IV_free(frontmapIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ IV * get_frontmapIV ( Tree *tree, int depth ) { int J, K, nfront ; int *fch, *frontmap, *levels, *par, *sib ; IV *frontmapIV ; nfront = tree->n ; par = tree->par ; fch = tree->fch ; sib = tree->sib ; frontmapIV = IV_new() ; IV_init(frontmapIV, nfront, NULL) ; frontmap = levels = IV_entries(frontmapIV) ; for ( J = Tree_preOTfirst(tree) ; J != -1 ; J = Tree_preOTnext(tree, J) ) { if ( (K = par[J]) == -1 ) { levels[J] = 0 ; } else { if ( J == fch[K] && sib[J] == -1 ) { levels[J] = levels[K] ; } else { levels[J] = levels[K] + 1 ; } } } for ( J = 0 ; J < nfront ; J++ ) { if ( levels[J] < depth ) { frontmap[J] = 0 ; } else { frontmap[J] = 1 ; } } return(frontmapIV) ; } /*--------------------------------------------------------------------*/ SemiImplMtx/drivers/testSimple.c010064400020550007177000000120740661214703600202650ustar00clevecompmath00000400000006/* testSimple.c */ #include "../SemiImplMtx.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- (1) read in a FrontMtx from a file, (2) read in an IV object that has the domain/schur complement information for the fronts (3) create the SemiImplMtx object created -- 98oct16, cca ------------------------------------------------- */ { char *inFrontMtxFileName, *inInpMtxFileName, *inIVfileName ; double t1, t2 ; FILE *msgFile ; FrontMtx *frontmtx ; InpMtx *inpmtx ; int msglvl, rc ; IV *frontmapIV ; SemiImplMtx *semimtx ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFrontMtxFile inInpMtxFile inIVfile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFrontMtxFile -- input file, must be *.frontmtxf or *.frontmtxb" "\n inInpMtxFile -- input file, must be *.inpmtxf or *.inpmtxb" "\n inIVfile -- input file, must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inFrontMtxFileName = argv[3] ; inInpMtxFileName = argv[4] ; inIVfileName = argv[5] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFrontMtxFile -- %s" "\n inInpMtxFile -- %s" "\n inIVfile -- %s" "\n", argv[0], msglvl, argv[2], inFrontMtxFileName, inInpMtxFileName, inIVfileName) ; fflush(msgFile) ; /* --------------------------- read in the FrontMtx object --------------------------- */ if ( strcmp(inFrontMtxFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } frontmtx = FrontMtx_new() ; MARKTIME(t1) ; rc = FrontMtx_readFromFile(frontmtx, inFrontMtxFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in frontmtx from file %s", t2 - t1, inFrontMtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from FrontMtx_readFromFile(%p,%s)", rc, frontmtx, inFrontMtxFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading FrontMtx object from file %s", inFrontMtxFileName) ; if ( msglvl > 2 ) { FrontMtx_writeForHumanEye(frontmtx, msgFile) ; } else { FrontMtx_writeStats(frontmtx, msgFile) ; } fflush(msgFile) ; /* --------------------------- read in the InpMtx object --------------------------- */ if ( strcmp(inInpMtxFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } inpmtx = InpMtx_new() ; MARKTIME(t1) ; rc = InpMtx_readFromFile(inpmtx, inInpMtxFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in inpmtx from file %s", t2 - t1, inInpMtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from InpMtx_readFromFile(%p,%s)", rc, inpmtx, inInpMtxFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading InpMtx object from file %s", inInpMtxFileName) ; if ( msglvl > 2 ) { InpMtx_writeForHumanEye(inpmtx, msgFile) ; } else { InpMtx_writeStats(inpmtx, msgFile) ; } fflush(msgFile) ; /* --------------------------------- read in the fronts' map IV object --------------------------------- */ if ( strcmp(inIVfileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } frontmapIV = IV_new() ; MARKTIME(t1) ; rc = IV_readFromFile(frontmapIV, inIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in frontmapIV from file %s", t2 - t1, inIVfileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, frontmapIV, inIVfileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading IV object from file %s", inIVfileName) ; if ( msglvl > 2 ) { IV_writeForHumanEye(frontmapIV, msgFile) ; } else { IV_writeStats(frontmapIV, msgFile) ; } fflush(msgFile) ; /* ------------------------------- create the semi-implicit matrix ------------------------------- */ semimtx = SemiImplMtx_new() ; rc = SemiImplMtx_initFromFrontMtx(semimtx, frontmtx, inpmtx, frontmapIV, msglvl, msgFile) ; fprintf(msgFile, "\n\n Semi-implicit matrix") ; SemiImplMtx_writeForHumanEye(semimtx, msgFile) ; /* ------------------------ free the working storage ------------------------ */ { ETree *etree ; IVL *symbfacIVL ; etree = frontmtx->frontETree ; symbfacIVL = frontmtx->symbfacIVL ; FrontMtx_free(frontmtx) ; ETree_free(etree) ; IVL_free(symbfacIVL) ; } SemiImplMtx_free(semimtx) ; InpMtx_free(inpmtx) ; IV_free(frontmapIV) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ SemiImplMtx/doc/004275500020550007177000000000000662342202100150505ustar00clevecompmath00000400000006SemiImplMtx/doc/makefile010064400020550007177000000000270662235110300165430ustar00clevecompmath00000400000006clean : - rm -f *.dvi SemiImplMtx/doc/dataStructure.tex010064400020550007177000000024670662265271100204420ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:SemiImplMtx:dataStructure} \par \par The {\tt SemiImplMtx} structure has the following fields. \begin{itemize} \item {\tt int neqns} : number of equations. \item {\tt int type} : type of entries, {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. \item {\tt int symmetryflag} : type of matrix symmetry, {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or {\tt SPOOLES\_NONSYMMETRIC}. \item {\tt int ndomeqns} : number of equations in the domains, or (1,1) block. \item {\tt int nschureqns} : number of equations in the Schur complement, or (2,2) block. \item {\tt FrontMtx *domainMtx} : matrix object for $L_{1,1}$, $D_{1,1}$ and $U_{1,1}$. \item {\tt FrontMtx *schurMtx} : matrix object for $L_{2,2}$, $D_{2,2}$ and $U_{2,2}$. \item {\tt InpMtx *A21} : matrix object for ${\widehat A}_{2,1}$. \item {\tt InpMtx *A12} : matrix object for ${\widehat A}_{1,2}$. \item {\tt IV *domRowsIV} : object that holds the global ids of the rows in ${\widehat A}_{1,1}$. \item {\tt IV *schurRowsIV} : object that holds the global ids of the rows in ${\widehat A}_{2,2}$. \item {\tt IV *domColumnsIV} : object that holds the global ids of the columns in ${\widehat A}_{1,1}$. \item {\tt IV *schurColumnsIV} : object that holds the global ids of the columns in ${\widehat A}_{2,2}$. \end{itemize} \par SemiImplMtx/doc/drivers.tex010064400020550007177000000105300662265326100172550ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt SemiImplMtx} object} \label{section:SemiImplMtx:drivers} \par This section contains brief descriptions of the driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testGrid msglvl msgFile n1 n2 n3 maxzeros maxsize seed type symmetryflag sparsityflag pivotingflag tau droptol nrhs depth \end{verbatim} This driver program tests the {\tt SemiImplMtx} creation and solve methods for a matrix from a regular 2-D or 3-D grid. The matrix can be real or complex and is loaded with random entries. The linear system $AX = B$ is solved as follows. \begin{itemize} \item First $A$ is factored, and a {\tt FrontMtx} object is created to hold the factorization. \item The system is solved using the {\tt FrontMtx} object. \item A {\tt SemiImplMtx} matrix object is constructed from the {\tt FrontMtx} object and $A$. \item The system is solved using the {\tt SemiImplMtx} object. \end{itemize} Various statistics and CPU timings are written to the message file to compare the two solution processes. Use the {\tt do\_grid} shell script for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt n1} is the number of grid points in the first direction. \item {\tt n2} is the number of grid points in the second direction. \item {\tt n3} is the number of grid points in the third direction. \item {\tt maxzeros} is the maximum number of zeroes to place into a front. \item {\tt maxsize} is the maximum number of internal rows and columns in a front. \item {\tt type} must be either {\tt SPOOLES\_REAL} or {\tt SPOOLES\_COMPLEX}. \item {\tt symmetryflag} must be either {\tt SPOOLES\_SYMMETRIC}, {\tt SPOOLES\_HERMITIAN} or \item {\tt sparsityflag} must be either {\tt FRONTMTX\_DENSE\_FRONTS} or {\tt FRONTMTX\_SPARSE\_FRONTS}. \item {\tt pivotingflag} must be either {\tt SPOOLES\_PIVOTING}, {\tt SPOOLES\_NO\_PIVOTING} or \item {\tt tau} is used when pivoting is enabled, it is an upper bound on the magnitude of the entries in $L$ and $U$. \item {\tt droptol} is used when an approximate factorization is called for, (i.e., when {\tt sparsityflag} is {\tt FRONTMTX\_SPARSE\_FRONTS}). It is a lower bound on the magnitude of the entries in $L$ and $U$ that are stored and used in computations. \item {\tt nrhs} is the number of right hand sides. \item {\tt depth} is used to specify the schur complement. It is based on separators, not on fronts. (Recall that large separators can be split into smaller fronts for efficiency reasons.) All fronts found in separators lower than {\tt depth} in depth (the top level separator has depth zero) belong in domains. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testSimple msglvl msgFile inFrontMtxFile inInpMtxFile inIVfile \end{verbatim} This driver program is used to construct a {\tt SemiImplMtx} object. It reads in a {\tt FrontMtx} and {\tt InpMtx} from files. It also reads in an {\tt IV} object that specifies whether a front is to be in the domains (the (1,1) block) or the Schur complement (the (2,2) block). It then creates the {\tt SemiImplMtx} object and writes it to the message file. Use the {\tt do\_simple} script file for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt FrontMtx} object is read from the {\tt inFrontMtxFile} file, which must be of the form {\tt *.frontmtxf} or {\tt *.frontmtxb}. \item The {\tt InpMtx} object is read from the {\tt inInpMtxFile} file, which must be of the form {\tt *.inpmtxf} or {\tt *.inpmtxb}. \item The map vector {\tt IV} object is read from the {\tt inIVfile} file, which must be of the form {\tt *.ivf} or {\tt *.ivb}. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} SemiImplMtx/doc/intro.tex010064400020550007177000000046150662265262000167370ustar00clevecompmath00000400000006\chapter{{\tt SemiImplMtx}: Semi-Implicit Factorization} \label{chapter:SemiImplMtx} \par The {\tt SemiImplMtx} object contains a semi-implicit representation of a sparse matrix factorization. Assume that the matrix $A$ has been factored as $PAQ = LDU$, where $L$ is unit lower triangular and $U$ is unit upper triangular. Now consider $PAQ$ (and so $L$, $D$ and $U$) partitioned as follows. $$ {\widehat A} = PAQ = \begin{bmatrix} {\widehat A}_{1,1} & {\widehat A}_{1,2} \\ {\widehat A}_{2,1} & {\widehat A}_{2,2} \end{bmatrix} = \begin{bmatrix} L_{1,1} & 0 \\ L_{2,1} & L_{2,2} \end{bmatrix} \begin{bmatrix} D_{1,1} & 0 \\ 0 & D_{2,2} \end{bmatrix} \begin{bmatrix} U_{1,1} & U_{1,2} \\ 0 & U_{2,2} \end{bmatrix} $$ After some algebra we can arrive at the following identities. $$ L_{2,1} = {\widehat A}_{2,1} D_{1,1}^{-1} \text{\qquad and \qquad} U_{1,2} = D_{1,1}^{-1} {\widehat A}_{1,2} $$ The straightforward solution of $AX = B$ can be done as follows, as we solve the permuted linear system ${\widehat A} {\widehat X} = {\widehat B}$, where ${\widehat X} = Q^T X$ and ${\widehat B} = P B$. \begin{itemize} \item solve $L_{1,1} Y_1 = {\widehat B}_1$. \item solve $L_{2,2} Y_2 = {\widehat B}_2 - L_{2,1} Y_1$. \item solve $D_{1,1} Z_1 = Y_1$. \item solve $D_{2,2} Z_2 = Y_2$. \item solve $U_{2,2} {\widehat X}_2 = Z_2$. \item solve $U_{1,1} {\widehat X}_1 = Z_1 - U_{1,2} Z_2$. \end{itemize} An equivalent process does not requires $L_{2,1}$ and $U_{1,2}$, but instead uses the ${\widehat A}_{1,2}$ and ${\widehat A}_{2,1}$ matrices. \begin{itemize} \item solve $L_{1,1} D_{1,1} U_{1,1} T_1 = {\widehat B}_1$. \item solve $L_{2,2} D_{2,2} U_{2,2} {\widehat X}_2 = {\widehat B}_2 - A_{2,1} T_1$. \item solve $L_{1,1} D_{1,1} U_{1,1} {\widehat X}_1 = {\widehat B}_1 - A_{1,2} {\widehat X}_2$. \end{itemize} In effect, we have traded multiplies with $L_{2,1}$ and $U_{1,2}$ for multiplies with $A_{1,2}$ and $A_{2,1}$ and two extra solves with $D_{1,1}$. In some cases this {\it semi-implicit} procedure (so named because $L_{2,1}$ and $U_{1,2}$ are stored in a semi-implicit form) can pay off --- storage can be saved when the number of entries in $L_{2,1}$ and $U_{1,2}$ are larger than the number of entries in $A_{2,1}$ and $A_{1,2}$. The number of solve operations is reduced by $|L_{2,1}| + |U_{1,2}| - 2|D_{1,1}| -|A_{2,1}| - |A_{1,2}|$, where $|\cdot|$ denotes the number of nonzeroes in a matrix. SemiImplMtx/doc/main.aux010064400020550007177000000026020662265345100165220ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt SemiImplMtx}: Semi-Implicit Factorization}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:SemiImplMtx}{{1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{2}} \newlabel{section:SemiImplMtx:dataStructure}{{1.1}{2}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt SemiImplMtx} methods}{2}} \newlabel{section:SemiImplMtx:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{2}} \newlabel{subsection:SemiImplMtx:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Initialization Methods}{3}} \newlabel{subsection:SemiImplMtx:proto:initializers}{{1.2.2}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Solve Methods}{3}} \newlabel{subsection:SemiImplMtx:proto:solve}{{1.2.3}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Utility methods}{4}} \newlabel{subsection:SemiImplMtx:proto:utility}{{1.2.4}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}IO methods}{4}} \newlabel{subsection:SemiImplMtx:proto:IO}{{1.2.5}{4}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs for the {\tt SemiImplMtx} object}{4}} \newlabel{section:SemiImplMtx:drivers}{{1.3}{4}} SemiImplMtx/doc/main.idx010064400020550007177000000011650662265345100165140ustar00clevecompmath00000400000006\indexentry{SemiImplMtx_new@{\tt SemiImplMtx\_new()}}{2} \indexentry{SemiImplMtx_setDefaultFields@{\tt SemiImplMtx\_setDefaultFields()}}{2} \indexentry{SemiImplMtx_clearData@{\tt SemiImplMtx\_clearData()}}{2} \indexentry{SemiImplMtx_free@{\tt SemiImplMtx\_free()}}{3} \indexentry{SemiImplMtx_initFromFrontMtx@{\tt SemiImplMtx\_initFromFrontMtx()}}{3} \indexentry{FrontMtx_initFromSubMtx@{\tt FrontMtx\_initFromSubMtx()}}{3} \indexentry{SemiImplMtx_solve@{\tt SemiImplMtx\_solve()}}{3} \indexentry{SemiImplMtx_stats@{\tt SemiImplMtx\_stats()}}{4} \indexentry{SemiImplMtx_writeForHumanEye@{\tt SemiImplMtx\_writeForHumanEye()}}{4} SemiImplMtx/doc/main.ilg010064400020550007177000000004550662264712600165060ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (9 entries accepted, 0 rejected). Sorting entries....done (28 comparisons). Generating output file main.ind....done (16 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. SemiImplMtx/doc/main.ind010064400020550007177000000006600662264712600165030ustar00clevecompmath00000400000006\begin{theindex} \item {\tt FrontMtx\_initFromSubMtx()}, 3 \indexspace \item {\tt SemiImplMtx\_clearData()}, 2 \item {\tt SemiImplMtx\_free()}, 3 \item {\tt SemiImplMtx\_initFromFrontMtx()}, 3 \item {\tt SemiImplMtx\_new()}, 2 \item {\tt SemiImplMtx\_setDefaultFields()}, 2 \item {\tt SemiImplMtx\_solve()}, 3 \item {\tt SemiImplMtx\_stats()}, 4 \item {\tt SemiImplMtx\_writeForHumanEye()}, 4 \end{theindex} SemiImplMtx/doc/main.log010064400020550007177000000117510662265345100165130ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 12 NOV 1998 13:46 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size10.clo File: size10.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) (/home/tex/teTeX/texmf/tex/latex/amslatex/amsmath.sty Package: amsmath 1996/11/01 v1.2c AMS math features \@mathmargin=\skip43 (/home/tex/teTeX/texmf/tex/latex/amslatex/amstext.sty Package: amstext 1996/10/28 v1.2b (/home/tex/teTeX/texmf/tex/latex/amslatex/amsgen.sty File: amsgen 1996/10/29 v1.2b \@emptytoks=\toks14 \ex@=\dimen103 )) (/home/tex/teTeX/texmf/tex/latex/amslatex/amsbsy.sty Package: amsbsy 1996/10/28 v1.2b \pmbraise@=\dimen104 ) (/home/tex/teTeX/texmf/tex/latex/amslatex/amsopn.sty Package: amsopn 1996/10/28 v1.2b operator names ) LaTeX Info: Redefining \frac on input line 188. \uproot@=\count88 \leftroot@=\count89 \classnum@=\count90 \DOTSCASE@=\count91 LaTeX Info: Redefining \dots on input line 335. LaTeX Info: Redefining \ldots on input line 418. LaTeX Info: Redefining \cdots on input line 422. \Mathstrutbox@=\box26 \strutbox@=\box27 \big@size=\dimen105 LaTeX Font Info: Redeclaring font encoding OML on input line 500. LaTeX Font Info: Redeclaring font encoding OMS on input line 501. \skewcharcount@=\count92 \familycount@=\count93 \pointcount@=\count94 \accentdimen@=\dimen106 \accentmu@=\count95 \minaw@=\dimen107 \c@MaxMatrixCols=\count96 \dotsspace@=\muskip10 \c@parentequation=\count97 \dspbrk@lvl=\count98 \tag@help=\toks15 \row@=\count99 \column@=\count100 \maxfields@=\count101 \andhelp@=\toks16 \eqnshift@=\dimen108 \alignsep@=\dimen109 \tagshift@=\dimen110 \tagwidth@=\dimen111 \totwidth@=\dimen112 \lineht@=\dimen113 \@envbody=\toks17 \multlinegap=\skip44 \multlinetaggap=\skip45 ) (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen114 \p@intvaluey=\dimen115 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 20. LaTeX Font Info: ... okay on input line 20. (intro.tex Chapter 1. LaTeX Font Info: Try loading font information for OMS+cmr on input line 42. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 42. ) (dataStructure.tex [1 ] Overfull \hbox (59.24767pt too wide) in paragraph at lines 14--18 []\OT1/cmtt/m/n/10 int symmetryflag \OT1/cmr/m/n/10 : type of ma-trix sym-me-tr y, \OT1/cmtt/m/n/10 SPOOLES[]SYMMETRIC\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 SPOOLE S[]HERMITIAN \OT1/cmr/m/n/10 or \OT1/cmtt/m/n/10 SPOOLES[]NONSYMMETRIC\OT1/cmr/ m/n/10 . [] ) (proto.tex Overfull \hbox (7.96838pt too wide) in paragraph at lines 32--41 []\OT1/cmr/m/n/10 This method sets the struc-ture's fields to de-fault val-ues: \OT1/cmtt/m/n/10 neqns \OT1/cmr/m/n/10 = 0, \OT1/cmtt/m/n/10 type \OT1/cmr/m/n /10 = \OT1/cmtt/m/n/10 SPOOLES[]REAL\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 symmetry flag [] [2] [3]) (drivers.tex [4] Overfull \hbox (2.85498pt too wide) in paragraph at lines 111--114 []\OT1/cmr/m/n/10 The \OT1/cmtt/m/n/10 FrontMtx \OT1/cmr/m/n/10 ob-ject is read from the \OT1/cmtt/m/n/10 inFrontMtxFile \OT1/cmr/m/n/10 file, which must be o f the form \OT1/cmtt/m/n/10 *.frontmtxf [] ) (main.ind [5] [6 ]) (main.aux) ) Here is how much of TeX's memory you used: 1053 strings out of 10908 10861 string characters out of 72189 63471 words of memory out of 262141 3944 multiletter control sequences out of 9500 7721 words of font info for 29 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 28i,8n,21p,196b,331s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (6 pages, 21044 bytes). SemiImplMtx/doc/main.tex010064400020550007177000000012340665065630700165310ustar00clevecompmath00000400000006% % main TeX file % % \documentstyle[leqno,11pt,twoside]{report} \documentclass[leqno,10pt,twoside]{report} \usepackage{amsmath} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt SemiImplMtx} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt SemiImplMtx} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} SemiImplMtx/doc/proto.tex010064400020550007177000000237250662265344500167600ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt SemiImplMtx} methods} \label{section:SemiImplMtx:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt SemiImplMtx} object. \par \subsection{Basic methods} \label{subsection:SemiImplMtx:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} SemiImplMtx * SemiImplMtx_new ( void ) ; \end{verbatim} \index{SemiImplMtx_new@{\tt SemiImplMtx\_new()}} This method simply allocates storage for the {\tt SemiImplMtx} structure and then sets the default fields by a call to {\tt SemiImplMtx\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} int SemiImplMtx_setDefaultFields ( SemiImplMtx *mtx ) ; \end{verbatim} \index{SemiImplMtx_setDefaultFields@{\tt SemiImplMtx\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt neqns} = 0, {\tt type} = {\tt SPOOLES\_REAL}, {\tt symmetryflag} = {\tt SPOOLES\_SYMMETRIC}, {\tt ndomeqns} = {\tt nschureqns} = 0, and {\tt domainMtx}, {\tt schurMtx}, {\tt A21}, {\tt A12}, {\tt domRowsIV}, {\tt schurRowsIV}, {\tt domColumnsIV} and {\tt schurColumnsIV} are all set to {\tt NULL}. \par \noindent {\it Return codes:} {\tt 1} means a normal return, {\tt -1} means {\tt mtx} is {\tt NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int SemiImplMtx_clearData ( SemiImplMtx *mtx ) ; \end{verbatim} \index{SemiImplMtx_clearData@{\tt SemiImplMtx\_clearData()}} This method releases all storage held by the object. \par \noindent {\it Return codes:} {\tt 1} means a normal return, {\tt -1} means {\tt mtx} is {\tt NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} int SemiImplMtx_free ( SemiImplMtx *mtx ) ; \end{verbatim} \index{SemiImplMtx_free@{\tt SemiImplMtx\_free()}} This method releases all storage held by the object via a call to {\tt SemiImplMtx\_clearData()}, then free'd the storage for the object. \par \noindent {\it Return codes:} {\tt 1} means a normal return, {\tt -1} means {\tt mtx} is {\tt NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization Methods} \label{subsection:SemiImplMtx:proto:initializers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SemiImplMtx_initFromFrontMtx ( SemiImplMtx *semimtx, FrontMtx *frontmtx, InpMtx *inpmtx, IV *frontmapIV, int msglvl, FILE *msgFile) ; \end{verbatim} \index{SemiImplMtx_initFromFrontMtx@{\tt SemiImplMtx\_initFromFrontMtx()}} This initializer is used after the {\tt FrontMtx} object for the factorization has been computed. The {\tt frontmapIV} object defines which fronts map to domains and which to the Schur complement. If entry {\tt J} of the {\tt frontmapIV} object is zero, then front {\tt J} belongs in the Schur complement, otherwise it belongs to the domains' matrix. The $A_{1,2}$ and $A_{2,1}$ (if nonsymmetric) matrices are extracted from the {\tt InpMtx} object. \par The {\tt semimtx} object removes submatrices from the {\tt frontmtx} object, i.e., after the return of this method, the {\tt frontmtx} no longer owns (and so cannot free) the submatrices from the $(1,1)$ and $(2,2)$ blocks. On return, the {\tt frontmtx} object can safely be free'd without affecting the {\tt semimtx} object. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt semimtx} is {\tt NULL} \\ -2 & {\tt frontmtx} is {\tt NULL} \\ -3 & {\tt inpmtx} is {\tt NULL} \\ \end{tabular} \quad \begin{tabular}{rl} -4 & {\tt frontmapIV} is {\tt NULL} \\ -5 & {\tt frontmapIV} is invalid \\ -6 & unable to create (1,1) front matrix \\ -7 & unable to create (2,2) front matrix \\ \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int FrontMtx_initFromSubMtx ( FrontMtx *submtx, FrontMtx *frontmtx, IV *frontidsIV, IV *rowsIV, IV *colsIV, int msglvl, FILE *msgFile) ; \end{verbatim} \index{FrontMtx_initFromSubMtx@{\tt FrontMtx\_initFromSubMtx()}} This initializer is used to initialize the {\tt submtx} {\tt FrontMtx} object from a global {\tt FrontMtx} object, i.e., to initialize the {\tt domainMtx} and {\tt schurMtx} objects. The fronts of the {\tt frontmtx} that will be included into the {\tt submtx} object are given in the {\tt frontidsIV} vector object. The {\tt submtx} object extracts the submatrices from the {\tt frontmtx} object, i.e., after the return of this method, the {\tt frontmtx} no longer owns (and so cannot free) its submatrices. The {\tt submtx} front matrix has {\it local} numbering, its global row ids are placed in {\tt rowsIV} and its global column ids are placed in {\tt colsIV}. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} ~~1 & normal return \\ ~-1 & {\tt submtx} is {\tt NULL} \\ ~-2 & {\tt frontmtx} is {\tt NULL} \\ ~-3 & {\tt frontmtx} is not in 2-d mode \\ ~-4 & {\tt frontidsIV} is {\tt NULL} \\ ~-5 & {\tt frontidsIV} is invalid \\ ~-6 & {\tt rowsIV} is {\tt NULL} \\ \end{tabular} \quad \begin{tabular}{rl} ~-7 & {\tt colsIV} is {\tt NULL} \\ ~-8 & unable to create the front tree \\ ~-9 & unable to create the symbolic factorization \\ -10 & unable to create the column adjacency \\ -11 & unable to create the row adjacency \\ -12 & unable to create the upper block {\tt IVL} \\ -13 & unable to create the lower block {\tt IVL} \\ \end{tabular} \end{center} \end{enumerate} \par %======================================================================= \par \subsection{Solve Methods} \label{subsection:SemiImplMtx:proto:solve} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SemiImplMtx_solve ( SemiImplMtx *mtx, DenseMtx *X, DenseMtx *B, SubMtxManager *mtxmanager, double cpus[], int msglvl, FILE *msgFile ) ; \end{verbatim} \index{SemiImplMtx_solve@{\tt SemiImplMtx\_solve()}} This methods solves a linear system $(L + I)D(I + U)X = B$, $(U^T + I)D(I + U)X = B$ or $(U^H + I)D(I + U)X = B$, where {\tt X} and {\tt B} are {\tt DenseMtx} objects. {\tt mtxmanager} is an object to handle the working {\tt SubMtx} objects during the solve. One can have {\tt X} and {\tt B} point to the same object, for entries are read from {\tt B} and written to {\tt X}. On return, the {\tt cpus[]} vector contains the following information. \begin{center} \begin{tabular}{rl} {\tt cpus[0]} & initialize working matrices \\ {\tt cpus[1]} & load right hand side \\ {\tt cpus[2]} & first solve with domains \\ {\tt cpus[3]} & compute Schur right hand side \\ {\tt cpus[4]} & Schur solve \end{tabular} \quad \begin{tabular}{rl} {\tt cpus[5]} & compute domains' right hand side \\ {\tt cpus[6]} & second solve with domains \\ {\tt cpus[7]} & store solution \\ {\tt cpus[8]} & miscellaneous time \\ {\tt cpus[9]} & total time \end{tabular} \end{center} \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt mtx} is {\tt NULL} \\ -2 & {\tt X} is {\tt NULL} \\ \end{tabular} \quad \begin{tabular}{rl} -3 & {\tt B} is {\tt NULL} \\ -4 & {\tt mtxmanager} is {\tt NULL} \\ -5 & {\tt cpus} is {\tt NULL} \\ \end{tabular} \end{center} \end{enumerate} \par %======================================================================= \subsection{Utility methods} \label{subsection:SemiImplMtx:proto:utility} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SemiImplMtx_stats ( SemiImplMtx *mtx, int stats[] ) ; \end{verbatim} \index{SemiImplMtx_stats@{\tt SemiImplMtx\_stats()}} This method fills the {\tt stats[]} vector with some statistics. \begin{center} \begin{tabular}[t]{rl} {\tt stats[0]} & \# of equations \\ {\tt stats[1]} & \# of equations in the $(1,1)$ block \\ {\tt stats[2]} & \# of equations in the $(2,2)$ block \\ {\tt stats[3]} & \# of entries in $L_{1,1}$ \\ {\tt stats[4]} & \# of entries in $D_{1,1}$ \\ {\tt stats[5]} & \# of entries in $U_{1,1}$ \\ {\tt stats[6]} & \# of entries in $L_{2,2}$ \\ \end{tabular} \quad \begin{tabular}[t]{rl} {\tt stats[7]} & \# of entries in $D_{2,2}$ \\ {\tt stats[8]} & \# of entries in $U_{2,2}$ \\ {\tt stats[9]} & \# of entries in $A_{1,2}$ \\ {\tt stats[10]} & \# of entries in $A_{2,1}$ \\ {\tt stats[11]} & total \# of entries \\ {\tt stats[12]} & \# of operations for a solve \end{tabular} \end{center} \par \noindent {\it Return values:} \par {\tt 1} for a normal return, {\tt -1} if {\tt mtx} is {\tt NULL}, {\tt -2} if {\tt stats} is {\tt NULL}. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:SemiImplMtx:proto:IO} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SemiImplMtx_writeForHumanEye ( SemiImplMtx *mtx, FILE *fp ) ; \end{verbatim} \index{SemiImplMtx_writeForHumanEye@{\tt SemiImplMtx\_writeForHumanEye()}} \par This method writes out a {\tt SemiImplMtx} object to a file in a human readable format. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt mtx} is {\tt NULL} \\ -2 & {\tt type} is invalid \\ \end{tabular} \quad \begin{tabular}{rl} -3 & {\tt symmetryflag} is invalid \\ -4 & {\tt fp} is {\tt NULL} \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} ===========================================SolveMap.h010064400020550007177000000001140653410640200137640ustar00clevecompmath00000400000006#ifndef _SolveMap_ #define _SolveMap_ #include "SolveMap/SolveMap.h" #endif SolveMap/SolveMap.h010064400020550007177000000343020661663173100155310ustar00clevecompmath00000400000006/* SolveMap.h */ #include "../IVL.h" #include "../Tree.h" #include "../SPOOLES.h" /*--------------------------------------------------------------------*/ typedef struct _SolveMap SolveMap ; struct _SolveMap { int symmetryflag ; int nfront ; int nproc ; int *owners ; int nblockUpper ; int *rowidsUpper ; int *colidsUpper ; int *mapUpper ; int nblockLower ; int *rowidsLower ; int *colidsLower ; int *mapLower ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98mar19, cca ----------------------- */ SolveMap * SolveMap_new ( void ) ; /* ----------------------- set the default fields created -- 98mar19, cca ----------------------- */ void SolveMap_setDefaultFields ( SolveMap *solvemap ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98mar19, cca -------------------------------------------------- */ void SolveMap_clearData ( SolveMap *solvemap ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98mar19, cca ------------------------------------------ */ SolveMap * SolveMap_free ( SolveMap *solvemap ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------- purpose -- to return the symmetry flag of the object created -- 98mar19, cca ---------------------------------------------------- */ int SolveMap_symmetryflag ( SolveMap *solvemap ) ; /* ----------------------------------------- purpose -- to return the number of fronts created -- 98mar19, cca ----------------------------------------- */ int SolveMap_nfront ( SolveMap *solvemap ) ; /* --------------------------------------------- purpose -- to return the number of processors created -- 98mar19, cca --------------------------------------------- */ int SolveMap_nproc ( SolveMap *solvemap ) ; /* ---------------------------------------------------------------- purpose -- to return the number of blocks in the upper adjacency created -- 98mar19, cca ---------------------------------------------------------------- */ int SolveMap_nblockUpper ( SolveMap *solvemap ) ; /* ---------------------------------------------------------------- purpose -- to return the number of blocks in the lower adjacency created -- 98mar19, cca ---------------------------------------------------------------- */ int SolveMap_nblockLower ( SolveMap *solvemap ) ; /* --------------------------------------------------- purpose -- to return a pointer to the owners vector created -- 98mar19, cca ---------------------------------------------------- */ int * SolveMap_owners ( SolveMap *solvemap ) ; /* ---------------------------------------------------- purpose -- to return a pointer to the row ids vector for the upper adjacency structure created -- 98mar19, cca ----------------------------------------------------- */ int * SolveMap_rowidsUpper ( SolveMap *solvemap ) ; /* ------------------------------------------------------- purpose -- to return a pointer to the column ids vector for the upper adjacency structure created -- 98mar19, cca -------------------------------------------------------- */ int * SolveMap_colidsUpper ( SolveMap *solvemap ) ; /* ------------------------------------------------ purpose -- to return a pointer to the map vector for the upper adjacency structure created -- 98mar19, cca ------------------------------------------------- */ int * SolveMap_mapUpper ( SolveMap *solvemap ) ; /* ---------------------------------------------------- purpose -- to return a pointer to the row ids vector for the upper adjacency structure created -- 98mar19, cca ----------------------------------------------------- */ int * SolveMap_rowidsLower ( SolveMap *solvemap ) ; /* ------------------------------------------------------- purpose -- to return a pointer to the column ids vector for the upper adjacency structure created -- 98mar19, cca -------------------------------------------------------- */ int * SolveMap_colidsLower ( SolveMap *solvemap ) ; /* ------------------------------------------------ purpose -- to return a pointer to the map vector for the upper adjacency structure created -- 98mar19, cca ------------------------------------------------- */ int * SolveMap_mapLower ( SolveMap *solvemap ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- set the scalars and allocate the vectors for the object created -- 98mar19, cca ------------------------------------------------------------------ */ void SolveMap_init ( SolveMap *solvemap, int symmetryflag, int nfront, int nproc, int nblockUpper, int nblockLower ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in maps.c ------------------------------------------ ------------------------------------------------------------------------ */ /* -------------------------------------- purpose -- map the off diagonal blocks to processes in a random fashion created -- 98mar19, cca -------------------------------------- */ void SolveMap_randomMap ( SolveMap *solvemap, int symmetryflag, IVL *upperBlockIVL, IVL *lowerBlockIVL, int nproc, IV *ownersIV, int seed, int msglvl, FILE *msgFile ) ; /* ---------------------------------------------- purpose -- map the off diagonal blocks to processes in a domain decomposition fashion created -- 98mar28, cca ---------------------------------------------- */ void SolveMap_ddMap ( SolveMap *solvemap, int symmetryflag, IVL *upperBlockIVL, IVL *lowerBlockIVL, int nproc, IV *ownersIV, Tree *tree, int seed, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in setup.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- purpose -- to set up the linked lists for the forward solve local to process myid created -- 98mar19, cca ----------------------------------------------------------- */ IP ** SolveMap_forwardSetup ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; /* ------------------------------------------------------------ purpose -- to set up the linked lists for the backward solve local to process myid created -- 98mar19, cca ------------------------------------------------------------ */ IP ** SolveMap_backwardSetup ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ---------------------------------------------------- purpose -- return the owner of block (rowid, colid). created -- 98mar19, cca ---------------------------------------------------- */ int SolveMap_owner ( SolveMap *solvemap, int rowid, int colid ) ; /* --------------------------------------------------------------- purpose -- return an IVL object whose list K contains all processes who do not own U(K,K) but own a U(J,K) for some J. if myid == -1 then the entire IVL object is created and returned else only the portion of the IVL object pertinent to myid is created and returned endif created -- 98may24, cca --------------------------------------------------------------- */ IVL * SolveMap_upperSolveIVL ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; /* ----------------------------------------------------- purpose -- return an IV object whose entry J contains the number of all processes who do not own U(J,J) but own a U(J,K) for some J. if myid == -1 then all entries in the vector are filled else all those entries pertinent to myid are filled endif created -- 98mar19, cca ----------------------------------------------------- */ IV * SolveMap_upperAggregateIV ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; /* -------------------------------------------------------- purpose -- return an IV object whose J'th entry contains the number of processes who do not own L(J,J) but own a L(J,I) for some I < J. if myid == -1 then all entries in the vector are filled else all those entries pertinent to myid are filled endif created -- 98mar20, cca -------------------------------------------------------- */ IV * SolveMap_lowerAggregateIV ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; /* ------------------------------------------------------- purpose -- return an IVL object whose list J contains the processes who do not own L(J,J) but own a L(K,J) for some K > J. if myid == -1 then the entire IVL object is created and returned else only the portion of the IVL object pertinent to myid is created and returned endif created -- 98may24, cca ------------------------------------------------------- */ IVL * SolveMap_lowerSolveIVL ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------- purpose -- to read in an SolveMap object from a file input -- fn -- filename, must be *.solvemapb or *.solvemapf return value -- 1 if success, 0 if failure created -- 98apr09, cca ----------------------------------------------------- */ int SolveMap_readFromFile ( SolveMap *solvemap, char *fn ) ; /* ----------------------------------------------------------- purpose -- to read an SolveMap object from a formatted file return value -- 1 if success, 0 if failure created -- 98apr09, cca ----------------------------------------------------------- */ int SolveMap_readFromFormattedFile ( SolveMap *solvemap, FILE *fp ) ; /* --------------------------------------------------- purpose -- to read an SolveMap object from a binary file return value -- 1 if success, 0 if failure created -- 98apr09, cca --------------------------------------------------- */ int SolveMap_readFromBinaryFile ( SolveMap *solvemap, FILE *fp ) ; /* ------------------------------------------------ purpose -- to write an SolveMap object to a file input -- fn -- filename *.solvemapb -- binary *.solvemapf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 98apr09, cca ------------------------------------------------ */ int SolveMap_writeToFile ( SolveMap *solvemap, char *fn ) ; /* ----------------------------------------------------- purpose -- to write an SolveMap object to a formatted file return value -- 1 if success, 0 otherwise created -- 98apr09, cca ----------------------------------------------------- */ int SolveMap_writeToFormattedFile ( SolveMap *solvemap, FILE *fp ) ; /* -------------------------------------------------- purpose -- to write an SolveMap object to a binary file return value -- 1 if success, 0 otherwise created -- 98apr09, cca -------------------------------------------------- */ int SolveMap_writeToBinaryFile ( SolveMap *solvemap, FILE *fp ) ; /* ------------------------------------------------------ purpose -- to write an SolveMap object for a human eye return value -- 1 if success, 0 otherwise created -- 98apr09, cca ------------------------------------------------------ */ int SolveMap_writeForHumanEye ( SolveMap *solvemap, FILE *fp ) ; /* -------------------------------------------------------------- purpose -- to write out the statistics for the SolveMap object return value -- 1 if success, 0 otherwise created -- 98apr09, cca -------------------------------------------------------------- */ int SolveMap_writeStats ( SolveMap *solvemap, FILE *fp ) ; /*--------------------------------------------------------------------*/ ------------------------ purpose -- map the off diagonal blocks to processes in a random fashion created -- 98mar19, cca -------------------------------------- */ void SolveMap_randomMap ( SolveMap *solvemap, int symmetryflag, IVL *upperBlockIVL, IVL *lowerBlockIVLSolveMap/makefile010064400020550007177000000001410663622366500153310ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean SolveMap/src/makefile010064400020550007177000000010200663603023500161020ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SolveMap $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(maps.o) \ $(OBJ).a(setup.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG SolveMap/src/makeGlobalLib010064400020550007177000000006600660026113300170150ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SolveMap SRC = basics.c \ init.c \ instance.c \ IO.c \ maps.c \ setup.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a SolveMap/src/IO.c010064400020550007177000000553440654225325700151060ustar00clevecompmath00000400000006/* IO.c */ #include "../SolveMap.h" static const char *suffixb = ".solvemapb" ; static const char *suffixf = ".solvemapf" ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to read in an SolveMap object from a file input -- fn -- filename, must be *.solvemapb or *.solvemapf return value -- 1 if success, 0 if failure created -- 98apr09, cca ----------------------------------------------------- */ int SolveMap_readFromFile ( SolveMap *solvemap, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( solvemap == NULL || fn == NULL ) { fprintf(stderr, "\n error in SolveMap_readFromFile(%p,%s), file %s, line %d" "\n bad input\n", solvemap, fn, __FILE__, __LINE__) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in SolveMap_readFromFile(%p,%s)" "\n unable to open file %s", solvemap, fn, fn) ; rc = 0 ; } else { rc = SolveMap_readFromBinaryFile(solvemap, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in SolveMap_readFromFile(%p,%s)" "\n unable to open file %s", solvemap, fn, fn) ; rc = 0 ; } else { rc = SolveMap_readFromFormattedFile(solvemap, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in SolveMap_readFromFile(%p,%s)" "\n bad SolveMap file name %s," "\n must end in %s (binary) or %s (formatted)\n", solvemap, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in SolveMap_readFromFile(%p,%s)" "\n bad SolveMap file name %s," "\n must end in %s (binary) or %s (formatted)\n", solvemap, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to read an SolveMap object from a formatted file return value -- 1 if success, 0 if failure created -- 98apr09, cca ----------------------------------------------------------- */ int SolveMap_readFromFormattedFile ( SolveMap *solvemap, FILE *fp ) { int nblockLower, nblockUpper, nfront, nproc, rc, symmetryflag ; int itemp[5] ; /* --------------- check the input --------------- */ if ( solvemap == NULL || fp == NULL ) { fprintf(stderr, "\n error in SolveMap_readFromFormattedFile(%p,%p)" "\n bad input\n", solvemap, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ SolveMap_clearData(solvemap) ; /* ----------------------------------------------------- read in the five scalar parameters symmetryflag, nfront, nproc, nblockUpper, nblockLower ----------------------------------------------------- */ if ( (rc = IVfscanf(fp, 5, itemp)) != 5 ) { fprintf(stderr, "\n error in SolveMap_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, 5) ; return(0) ; } symmetryflag = itemp[0] ; nfront = itemp[1] ; nproc = itemp[2] ; nblockUpper = itemp[3] ; nblockLower = itemp[4] ; /* --------------------- initialize the object --------------------- */ SolveMap_init(solvemap, symmetryflag, nfront, nproc, nblockUpper, nblockLower) ; /* --------------------------- read in the owners[] vector --------------------------- */ if ( (rc = IVfscanf(fp, nfront, solvemap->owners)) != nfront ) { fprintf(stderr, "\n error in SolveMap_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nfront) ; return(0) ; } if ( nblockUpper > 0 ) { /* -------------------------------- read in the rowidsUpper[] vector -------------------------------- */ if ( (rc = IVfscanf(fp, nblockUpper, solvemap->rowidsUpper)) != nblockUpper ) { fprintf(stderr, "\n error in SolveMap_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockUpper) ; return(0) ; } /* -------------------------------- read in the colidsUpper[] vector -------------------------------- */ if ( (rc = IVfscanf(fp, nblockUpper, solvemap->colidsUpper)) != nblockUpper ) { fprintf(stderr, "\n error in SolveMap_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockUpper) ; return(0) ; } /* ----------------------------- read in the mapUpper[] vector ----------------------------- */ if ( (rc = IVfscanf(fp, nblockUpper, solvemap->mapUpper)) != nblockUpper ) { fprintf(stderr, "\n error in SolveMap_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockUpper) ; return(0) ; } } if ( symmetryflag == 2 && nblockLower > 0 ) { /* -------------------------------- read in the rowidsLower[] vector -------------------------------- */ if ( (rc = IVfscanf(fp, nblockLower, solvemap->rowidsLower)) != nblockLower ) { fprintf(stderr, "\n error in SolveMap_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockLower) ; return(0) ; } /* -------------------------------- read in the colidsLower[] vector -------------------------------- */ if ( (rc = IVfscanf(fp, nblockLower, solvemap->colidsLower)) != nblockLower ) { fprintf(stderr, "\n error in SolveMap_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockLower) ; return(0) ; } /* ----------------------------- read in the mapLower[] vector ----------------------------- */ if ( (rc = IVfscanf(fp, nblockLower, solvemap->mapLower)) != nblockLower ) { fprintf(stderr, "\n error in SolveMap_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockLower) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- to read an SolveMap object from a binary file return value -- 1 if success, 0 if failure created -- 98apr09, cca --------------------------------------------------------- */ int SolveMap_readFromBinaryFile ( SolveMap *solvemap, FILE *fp ) { int nblockLower, nblockUpper, nfront, nproc, rc, symmetryflag ; int itemp[5] ; /* --------------- check the input --------------- */ if ( solvemap == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_readFromBinaryFile(%p,%p)" "\n bad input\n", solvemap, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ SolveMap_clearData(solvemap) ; /* ----------------------------------------------------- read in the five scalar parameters symmetryflag, nfront, nproc, nblockUpper, nblockLower ----------------------------------------------------- */ if ( (rc = fread((void *) itemp, sizeof(int), 5, fp)) != 5 ) { fprintf(stderr, "\n error in SolveMap_readFromBinaryFile(%p,%p)" "\n itemp(3) : %d items of %d read\n", solvemap, fp, rc, 5) ; return(0) ; } symmetryflag = itemp[0] ; nfront = itemp[1] ; nproc = itemp[2] ; nblockUpper = itemp[3] ; nblockLower = itemp[4] ; /* --------------------- initialize the object --------------------- */ SolveMap_init(solvemap, symmetryflag, nfront, nproc, nblockUpper, nblockLower) ; /* --------------------------- read in the owners[] vector --------------------------- */ fread((void *) solvemap->owners, sizeof(int), nfront, fp) ; if ( rc != nfront ) { fprintf(stderr, "\n error in SolveMap_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nfront) ; return(0) ; } if ( nblockUpper > 0 ) { /* -------------------------------- read in the rowidsUpper[] vector -------------------------------- */ fread((void *) solvemap->rowidsUpper, sizeof(int), nblockUpper, fp) ; if ( rc != nblockUpper ) { fprintf(stderr, "\n error in SolveMap_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockUpper) ; return(0) ; } /* -------------------------------- read in the colidsUpper[] vector -------------------------------- */ fread((void *) solvemap->colidsUpper, sizeof(int), nblockUpper, fp) ; if ( rc != nblockUpper ) { fprintf(stderr, "\n error in SolveMap_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockUpper) ; return(0) ; } /* ----------------------------- read in the mapUpper[] vector ----------------------------- */ fread((void *) solvemap->mapUpper, sizeof(int), nblockUpper, fp) ; if ( rc != nblockUpper ) { fprintf(stderr, "\n error in SolveMap_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockUpper) ; return(0) ; } } if ( symmetryflag == 2 && nblockLower > 0 ) { /* -------------------------------- read in the rowidsLower[] vector -------------------------------- */ fread((void *) solvemap->rowidsLower, sizeof(int), nblockLower, fp) ; if ( rc != nblockLower ) { fprintf(stderr, "\n error in SolveMap_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockLower) ; return(0) ; } /* -------------------------------- read in the colidsLower[] vector -------------------------------- */ fread((void *) solvemap->colidsLower, sizeof(int), nblockLower, fp) ; if ( rc != nblockLower ) { fprintf(stderr, "\n error in SolveMap_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockLower) ; return(0) ; } /* ----------------------------- read in the mapLower[] vector ----------------------------- */ fread((void *) solvemap->mapLower, sizeof(int), nblockLower, fp) ; if ( rc != nblockLower ) { fprintf(stderr, "\n error in SolveMap_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", solvemap, fp, rc, nblockLower) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to write an SolveMap object to a file input -- fn -- filename *.solvemapb -- binary *.solvemapf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 98apr09, cca ------------------------------------------------ */ int SolveMap_writeToFile ( SolveMap *solvemap, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( solvemap == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_writeToFile(%p,%s)" "\n bad input\n", solvemap, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in SolveMap_writeToFile(%p,%s)" "\n unable to open file %s", solvemap, fn, fn) ; rc = 0 ; } else { rc = SolveMap_writeToBinaryFile(solvemap, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in SolveMap_writeToFile(%p,%s)" "\n unable to open file %s", solvemap, fn, fn) ; rc = 0 ; } else { rc = SolveMap_writeToFormattedFile(solvemap, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in SolveMap_writeToFile(%p,%s)" "\n unable to open file %s", solvemap, fn, fn) ; rc = 0 ; } else { rc = SolveMap_writeForHumanEye(solvemap, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in SolveMap_writeToFile(%p,%s)" "\n unable to open file %s", solvemap, fn, fn) ; rc = 0 ; } else { rc = SolveMap_writeForHumanEye(solvemap, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to write an SolveMap object to a formatted file return value -- 1 if success, 0 otherwise created -- 98apr09, cca ----------------------------------------------------- */ int SolveMap_writeToFormattedFile ( SolveMap *solvemap, FILE *fp ) { int ierr, rc ; /* --------------- check the input --------------- */ if ( solvemap == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_writeToFormattedFile(%p,%p)" "\n bad input\n", solvemap, fp) ; exit(-1) ; } /* ------------------------------------ write out the five scalar parameters ------------------------------------ */ rc = fprintf(fp, "\n %d %d %d %d %d", solvemap->symmetryflag, solvemap->nfront, solvemap->nproc, solvemap->nblockUpper, solvemap->nblockLower) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in SolveMap_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", solvemap, fp, rc) ; return(0) ; } if ( solvemap->nfront > 0 ) { IVfp80(fp, solvemap->nfront, solvemap->owners, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in SolveMap_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from owners[] IVfp80\n", solvemap, fp, ierr) ; return(0) ; } } if ( solvemap->nblockUpper > 0 ) { IVfp80(fp, solvemap->nblockUpper, solvemap->rowidsUpper, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in SolveMap_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from rowidsUpper[] IVfp80\n", solvemap, fp, ierr) ; return(0) ; } IVfp80(fp, solvemap->nblockUpper, solvemap->colidsUpper, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in SolveMap_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from colidsUpper[] IVfp80\n", solvemap, fp, ierr) ; return(0) ; } IVfp80(fp, solvemap->nblockUpper, solvemap->mapUpper, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in SolveMap_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from mapUpper[] IVfp80\n", solvemap, fp, ierr) ; return(0) ; } } if ( solvemap->symmetryflag == 2 && solvemap->nblockLower > 0 ) { IVfp80(fp, solvemap->nblockLower, solvemap->rowidsLower, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in SolveMap_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from rowidsLower[] IVfp80\n", solvemap, fp, ierr) ; return(0) ; } IVfp80(fp, solvemap->nblockLower, solvemap->colidsLower, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in SolveMap_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from colidsLower[] IVfp80\n", solvemap, fp, ierr) ; return(0) ; } IVfp80(fp, solvemap->nblockLower, solvemap->mapLower, 80, &ierr) ; if ( ierr < 0 ) { fprintf(stderr, "\n fatal error in SolveMap_writeToFormattedFile(%p,%p)" "\n ierr = %d, return from mapLower[] IVfp80\n", solvemap, fp, ierr) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to write an SolveMap object to a binary file return value -- 1 if success, 0 otherwise created -- 98apr09, cca -------------------------------------------------- */ int SolveMap_writeToBinaryFile ( SolveMap *solvemap, FILE *fp ) { int rc ; int itemp[5] ; /* --------------- check the input --------------- */ if ( solvemap == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_writeToBinaryFile(%p,%p)" "\n bad input\n", solvemap, fp) ; exit(-1) ; } itemp[0] = solvemap->symmetryflag ; itemp[1] = solvemap->nfront ; itemp[2] = solvemap->nproc ; itemp[2] = solvemap->nblockUpper ; itemp[2] = solvemap->nblockLower ; rc = fwrite((void *) itemp, sizeof(int), 5, fp) ; if ( rc != 5 ) { fprintf(stderr, "\n error in SolveMap_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", solvemap, fp, rc, 5) ; return(0) ; } rc = fwrite((void *) solvemap->owners, sizeof(int), solvemap->nfront, fp) ; if ( rc != solvemap->nfront ) { fprintf(stderr, "\n error in SolveMap_writeToBinaryFile(%p,%p)" "\n owners: %d of %d items written\n", solvemap, fp, rc, solvemap->nfront) ; return(0) ; } if ( solvemap->nblockUpper > 0 ) { rc = fwrite((void *) solvemap->rowidsUpper, sizeof(int), solvemap->nblockUpper, fp) ; if ( rc != solvemap->nfront ) { fprintf(stderr, "\n error in SolveMap_writeToBinaryFile(%p,%p)" "\n owners: %d of %d items written\n", solvemap, fp, rc, solvemap->nblockUpper) ; return(0) ; } rc = fwrite((void *) solvemap->colidsUpper, sizeof(int), solvemap->nblockUpper, fp) ; if ( rc != solvemap->nfront ) { fprintf(stderr, "\n error in SolveMap_writeToBinaryFile(%p,%p)" "\n owners: %d of %d items written\n", solvemap, fp, rc, solvemap->nblockUpper) ; return(0) ; } rc = fwrite((void *) solvemap->mapUpper, sizeof(int), solvemap->nblockUpper, fp) ; if ( rc != solvemap->nfront ) { fprintf(stderr, "\n error in SolveMap_writeToBinaryFile(%p,%p)" "\n owners: %d of %d items written\n", solvemap, fp, rc, solvemap->nblockUpper) ; return(0) ; } } if ( solvemap->symmetryflag == 2 && solvemap->nblockLower > 0 ) { rc = fwrite((void *) solvemap->rowidsLower, sizeof(int), solvemap->nblockLower, fp) ; if ( rc != solvemap->nfront ) { fprintf(stderr, "\n error in SolveMap_writeToBinaryFile(%p,%p)" "\n owners: %d of %d items written\n", solvemap, fp, rc, solvemap->nblockLower) ; return(0) ; } rc = fwrite((void *) solvemap->colidsLower, sizeof(int), solvemap->nblockLower, fp) ; if ( rc != solvemap->nfront ) { fprintf(stderr, "\n error in SolveMap_writeToBinaryFile(%p,%p)" "\n owners: %d of %d items written\n", solvemap, fp, rc, solvemap->nblockLower) ; return(0) ; } rc = fwrite((void *) solvemap->mapLower, sizeof(int), solvemap->nblockLower, fp) ; if ( rc != solvemap->nfront ) { fprintf(stderr, "\n error in SolveMap_writeToBinaryFile(%p,%p)" "\n owners: %d of %d items written\n", solvemap, fp, rc, solvemap->nblockLower) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to write an SolveMap object for a human eye return value -- 1 if success, 0 otherwise created -- 98apr09, cca ------------------------------------------------------ */ int SolveMap_writeForHumanEye ( SolveMap *solvemap, FILE *fp ) { int ierr, kk, rc ; if ( solvemap == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_writeForHumanEye(%p,%p)" "\n bad input\n", solvemap, fp) ; exit(-1) ; } if ( (rc = SolveMap_writeStats(solvemap, fp)) == 0 ) { fprintf(stderr, "\n fatal error in SolveMap_writeForHumanEye(%p,%p)" "\n rc = %d, return from SolveMap_writeStats(%p,%p)\n", solvemap, fp, rc, solvemap, fp) ; return(0) ; } fprintf(fp, "\n\n front owners map") ; IVfp80(fp, solvemap->nfront, solvemap->owners, 80, &ierr) ; if ( solvemap->nblockUpper > 0 ) { fprintf(fp, "\n\n upper block map") ; for ( kk = 0 ; kk < solvemap->nblockUpper ; kk++ ) { fprintf(fp, "\n block(%d,%d) owned by process %d", solvemap->rowidsUpper[kk], solvemap->colidsUpper[kk], solvemap->mapUpper[kk]) ; } } if ( solvemap->symmetryflag == 2 && solvemap->nblockLower > 0 ) { fprintf(fp, "\n\n lower block map") ; for ( kk = 0 ; kk < solvemap->nblockLower ; kk++ ) { fprintf(fp, "\n block(%d,%d) owned by process %d", solvemap->rowidsLower[kk], solvemap->colidsLower[kk], solvemap->mapLower[kk]) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- to write out the statistics for the SolveMap object return value -- 1 if success, 0 otherwise created -- 98apr09, cca -------------------------------------------------------------- */ int SolveMap_writeStats ( SolveMap *solvemap, FILE *fp ) { /* --------------- check the input --------------- */ if ( solvemap == NULL || fp == NULL ) { fprintf(stderr, "\n error in SolveMap_writeStats(%p,%p)" "\n bad input\n", solvemap, fp) ; exit(-1) ; } fprintf(fp, "\n SolveMap : submatrix solve object :") ; if ( solvemap->symmetryflag < 2 ) { fprintf(fp, "\n matrix is symmetric") ; } else { fprintf(fp, "\n matrix is nonsymmetric") ; } fprintf(fp, "\n %d fronts, %d processes, %d upper blocks, %d lower blocks", solvemap->nfront, solvemap->nproc, solvemap->nblockUpper, solvemap->nblockLower) ; return(1) ; } /*--------------------------------------------------------------------*/ } else { rc = SolveMap_writeForHumanEye(solvemap, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in SolveMap_writeToFile(%p,%s)" "\n unable to open file %s", solvemap, fn, fn) ; SolveMap/src/basics.c010064400020550007177000000060740654030625300160300ustar00clevecompmath00000400000006/* basics.c */ #include "../SolveMap.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98mar19, cca ----------------------- */ SolveMap * SolveMap_new ( void ) { SolveMap *solvemap ; ALLOCATE(solvemap, struct _SolveMap, 1) ; SolveMap_setDefaultFields(solvemap) ; return(solvemap) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98mar19, cca ----------------------- */ void SolveMap_setDefaultFields ( SolveMap *solvemap ) { if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_setDefaultFields(%p)" "\n bad input", solvemap) ; exit(-1) ; } solvemap->symmetryflag = SPOOLES_SYMMETRIC ; solvemap->nfront = 0 ; solvemap->nproc = 0 ; solvemap->owners = NULL ; solvemap->nblockUpper = 0 ; solvemap->rowidsUpper = NULL ; solvemap->colidsUpper = NULL ; solvemap->mapUpper = NULL ; solvemap->nblockLower = 0 ; solvemap->rowidsLower = NULL ; solvemap->colidsLower = NULL ; solvemap->mapLower = NULL ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98mar19, cca -------------------------------------------------- */ void SolveMap_clearData ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_clearData(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } /* ----------------------------------------------- free any storage held in the int vector objects ----------------------------------------------- */ if ( solvemap->owners != NULL ) { IVfree(solvemap->owners) ; } if ( solvemap->rowidsUpper != NULL ) { IVfree(solvemap->rowidsUpper) ; } if ( solvemap->colidsUpper != NULL ) { IVfree(solvemap->colidsUpper) ; } if ( solvemap->mapUpper != NULL ) { IVfree(solvemap->mapUpper) ; } if ( solvemap->rowidsLower != NULL ) { IVfree(solvemap->rowidsLower) ; } if ( solvemap->colidsLower != NULL ) { IVfree(solvemap->colidsLower) ; } if ( solvemap->mapLower != NULL ) { IVfree(solvemap->mapLower) ; } /* ---------------------- set the default fields ---------------------- */ SolveMap_setDefaultFields(solvemap) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98mar19, cca ------------------------------------------ */ SolveMap * SolveMap_free ( SolveMap *solvemap ) { if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_free(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } SolveMap_clearData(solvemap) ; FREE(solvemap) ; return(NULL) ; } /*--------------------------------------------------------------------*/ SolveMap/src/init.c010064400020550007177000000035120654030710200155130ustar00clevecompmath00000400000006/* init.c */ #include "../SolveMap.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- set the scalars and allocate the vectors for the object created -- 98mar19, cca ------------------------------------------------------------------ */ void SolveMap_init ( SolveMap *solvemap, int symmetryflag, int nfront, int nproc, int nblockUpper, int nblockLower ) { /* --------------- check the input --------------- */ if ( solvemap == NULL || symmetryflag < 0 || nfront <= 0 || nproc < 0 || nblockUpper < 0 || nblockLower < 0 ) { fprintf(stderr, "\n fatal error in SolveMap_init(%p,%d,%d,%d,%d,%d)" "\n bad input\n", solvemap, symmetryflag, nfront, nproc, nblockUpper, nblockLower) ; exit(-1) ; } /* ---------------- clear the object ---------------- */ SolveMap_clearData(solvemap) ; /* --------------- set the scalars --------------- */ solvemap->symmetryflag = symmetryflag ; solvemap->nfront = nfront ; solvemap->nproc = nproc ; solvemap->nblockUpper = nblockUpper ; solvemap->nblockLower = nblockLower ; /* ------------------------ allocate the data arrays ------------------------ */ solvemap->owners = IVinit(nfront, -1) ; solvemap->rowidsUpper = IVinit(nblockUpper, -1) ; solvemap->colidsUpper = IVinit(nblockUpper, -1) ; solvemap->mapUpper = IVinit(nblockUpper, -1) ; if ( symmetryflag == SPOOLES_NONSYMMETRIC && nblockLower > 0 ) { solvemap->rowidsLower = IVinit(nblockLower, -1) ; solvemap->colidsLower = IVinit(nblockLower, -1) ; solvemap->mapLower = IVinit(nblockLower, -1) ; } return ; } /*--------------------------------------------------------------------*/ SolveMap/src/instance.c010064400020550007177000000162070654030666300163740ustar00clevecompmath00000400000006/* instance.c */ #include "../SolveMap.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to return the symmetry flag of the object created -- 98mar19, cca ---------------------------------------------------- */ int SolveMap_symmetryflag ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_symmetryflag(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->symmetryflag) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to return the number of fronts created -- 98mar19, cca ----------------------------------------- */ int SolveMap_nfront ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_nfront(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->nfront) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to return the number of processors created -- 98mar19, cca --------------------------------------------- */ int SolveMap_nproc ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_nproc(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->nproc) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- to return the number of blocks in the upper adjacency created -- 98mar19, cca ---------------------------------------------------------------- */ int SolveMap_nblockUpper ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_nblockUpper(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->nblockUpper) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- purpose -- to return the number of blocks in the lower adjacency created -- 98mar19, cca ---------------------------------------------------------------- */ int SolveMap_nblockLower ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_nblockLower(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->nblockLower) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to return a pointer to the owners vector created -- 98mar19, cca ---------------------------------------------------- */ int * SolveMap_owners ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_owners(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->owners) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to return a pointer to the row ids vector for the upper adjacency structure created -- 98mar19, cca ----------------------------------------------------- */ int * SolveMap_rowidsUpper ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_rowidsUpper(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->rowidsUpper) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to return a pointer to the column ids vector for the upper adjacency structure created -- 98mar19, cca -------------------------------------------------------- */ int * SolveMap_colidsUpper ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_colidsUpper(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->colidsUpper) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to return a pointer to the map vector for the upper adjacency structure created -- 98mar19, cca ------------------------------------------------- */ int * SolveMap_mapUpper ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_mapUpper(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->mapUpper) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to return a pointer to the row ids vector for the upper adjacency structure created -- 98mar19, cca ----------------------------------------------------- */ int * SolveMap_rowidsLower ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_rowidsLower(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->rowidsLower) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to return a pointer to the column ids vector for the upper adjacency structure created -- 98mar19, cca -------------------------------------------------------- */ int * SolveMap_colidsLower ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_colidsLower(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->colidsLower) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to return a pointer to the map vector for the upper adjacency structure created -- 98mar19, cca ------------------------------------------------- */ int * SolveMap_mapLower ( SolveMap *solvemap ) { /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_mapLower(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } return(solvemap->mapLower) ; } /*--------------------------------------------------------------------*/ SolveMap/src/maps.c010064400020550007177000000272540661663170700155400ustar00clevecompmath00000400000006/* maps.c */ #include "../SolveMap.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- map the off diagonal blocks to processes in a random fashion created -- 98mar19, cca -------------------------------------- */ void SolveMap_randomMap ( SolveMap *solvemap, int symmetryflag, IVL *upperBlockIVL, IVL *lowerBlockIVL, int nproc, IV *ownersIV, int seed, int msglvl, FILE *msgFile ) { Drand drand ; int ii, J, K, loc, nadj, nblockLower, nblockUpper, nfront, proc ; int *adj, *colids, *map, *owners, *rowids ; /* --------------- check the input --------------- */ if ( solvemap == NULL || symmetryflag < 0 || upperBlockIVL == NULL || ownersIV == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_randomMap(%p,%d,%p,%p,%p,%d)" "\n bad input\n", solvemap, symmetryflag, upperBlockIVL, lowerBlockIVL, ownersIV, seed) ; exit(-1) ; } nfront = IV_size(ownersIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n SolveMap_randomMap(): nfront = %d, nproc = %d", nfront, nproc) ; fflush(msgFile) ; } /* ----------------------------------------------------------- count the number of upper blocks that do not include U(J,J) ----------------------------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n upperBlockIVL = %p", upperBlockIVL) ; fflush(msgFile) ; } nblockUpper = 0 ; for ( J = 0 ; J < nfront ; J++ ) { IVL_listAndSize(upperBlockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { if ( adj[ii] > J ) { nblockUpper++ ; } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n nblockUpper = %d", nblockUpper) ; fflush(msgFile) ; } /* ----------------------------------------------------------- count the number of lower blocks that do not include L(J,J) ----------------------------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n lowerBlockIVL = %p", lowerBlockIVL) ; fflush(msgFile) ; } nblockLower = 0 ; if ( lowerBlockIVL != NULL ) { for ( J = 0 ; J < nfront ; J++ ) { IVL_listAndSize(lowerBlockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { if ( adj[ii] > J ) { nblockLower++ ; } } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n nblockLower = %d", nblockLower) ; fflush(msgFile) ; } /* --------------------- initialize the object --------------------- */ SolveMap_init(solvemap, symmetryflag, nfront, nproc, nblockUpper, nblockLower) ; owners = SolveMap_owners(solvemap) ; /* ---------------------- fill the owners vector ---------------------- */ IVcopy(nfront, owners, IV_entries(ownersIV)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n owners") ; IVfprintf(msgFile, nfront, owners) ; fflush(msgFile) ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ Drand_setDefaultFields(&drand) ; Drand_setUniform(&drand, 0, nproc) ; /* ---------------------------------------- map the upper blocks in a random fashion ---------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n mapping upper blocks") ; fflush(msgFile) ; } rowids = SolveMap_rowidsUpper(solvemap) ; colids = SolveMap_colidsUpper(solvemap) ; map = SolveMap_mapUpper(solvemap) ; for ( J = loc = 0 ; J < nfront ; J++ ) { IVL_listAndSize(upperBlockIVL, J, &nadj, &adj) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n J = %d", J) ; fflush(msgFile) ; } for ( ii = 0 ; ii < nadj ; ii++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n K = %d", adj[ii]) ; fflush(msgFile) ; } if ( (K = adj[ii]) > J ) { proc = (int) Drand_value(&drand) ; rowids[loc] = J ; colids[loc] = K ; map[loc] = proc ; if ( msglvl > 2 ) { fprintf(msgFile, ", map[%d] = %d", loc, map[loc]) ; fflush(msgFile) ; } loc++ ; } } } if ( lowerBlockIVL != NULL ) { /* ---------------------------------------- map the lower blocks in a random fashion ---------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n mapping lower blocks") ; fflush(msgFile) ; } rowids = SolveMap_rowidsLower(solvemap) ; colids = SolveMap_colidsLower(solvemap) ; map = SolveMap_mapLower(solvemap) ; for ( J = loc = 0 ; J < nfront ; J++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n J = %d", J) ; fflush(msgFile) ; } IVL_listAndSize(lowerBlockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n K = %d", adj[ii]) ; fflush(msgFile) ; } if ( (K = adj[ii]) > J ) { proc = (int) Drand_value(&drand) ; rowids[loc] = K ; colids[loc] = J ; map[loc] = proc ; if ( msglvl > 2 ) { fprintf(msgFile, ", map[%d] = %d", loc, map[loc]) ; fflush(msgFile) ; } loc++ ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- map the off diagonal blocks to processes in a domain decomposition fashion created -- 98mar28, cca ---------------------------------------------- */ void SolveMap_ddMap ( SolveMap *solvemap, int symmetryflag, IVL *upperBlockIVL, IVL *lowerBlockIVL, int nproc, IV *ownersIV, Tree *tree, int seed, int msglvl, FILE *msgFile ) { char *mark ; Drand drand ; int ii, I, J, K, loc, nadj, nblockLower, nblockUpper, nfront, proc ; int *adj, *colids, *fch, *map, *owners, *rowids, *sib ; /* --------------- check the input --------------- */ if ( solvemap == NULL || symmetryflag < 0 || upperBlockIVL == NULL || ownersIV == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_ddMap(%p,%d,%p,%p,%p,%d)" "\n bad input\n", solvemap, symmetryflag, upperBlockIVL, lowerBlockIVL, ownersIV, seed) ; exit(-1) ; } nfront = IV_size(ownersIV) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n SolveMap_ddMap(): nfront = %d, nproc = %d", nfront, nproc) ; fflush(msgFile) ; } /* ----------------------------------------------------------- count the number of upper blocks that do not include U(J,J) ----------------------------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n upperBlockIVL = %p", upperBlockIVL) ; fflush(msgFile) ; } nblockUpper = 0 ; for ( J = 0 ; J < nfront ; J++ ) { IVL_listAndSize(upperBlockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { if ( adj[ii] > J ) { nblockUpper++ ; } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n nblockUpper = %d", nblockUpper) ; fflush(msgFile) ; } /* ----------------------------------------------------------- count the number of lower blocks that do not include L(J,J) ----------------------------------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n lowerBlockIVL = %p", lowerBlockIVL) ; fflush(msgFile) ; } nblockLower = 0 ; if ( lowerBlockIVL != NULL ) { for ( J = 0 ; J < nfront ; J++ ) { IVL_listAndSize(lowerBlockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { if ( adj[ii] > J ) { nblockLower++ ; } } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n nblockLower = %d", nblockLower) ; fflush(msgFile) ; } /* --------------------- initialize the object --------------------- */ SolveMap_init(solvemap, symmetryflag, nfront, nproc, nblockUpper, nblockLower) ; owners = SolveMap_owners(solvemap) ; /* ---------------------- fill the owners vector ---------------------- */ IVcopy(nfront, owners, IV_entries(ownersIV)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n owners") ; IVfprintf(msgFile, nfront, owners) ; fflush(msgFile) ; } /* ----------------------------------------------------- mark a node J in the tree as 'D' if it is in a domain (owners[J] = owners[I] for all I a descendent of J) and 'S' (for the schur complement) otherwise ----------------------------------------------------- */ mark = CVinit(nfront, 'D') ; fch = tree->fch ; sib = tree->sib ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { for ( I = fch[J] ; I != -1 ; I = sib[I] ) { if ( mark[I] != 'D' || owners[I] != owners[J] ) { mark[J] = 'S' ; break ; } } } /* -------------------------------------- initialize the random number generator -------------------------------------- */ Drand_setDefaultFields(&drand) ; Drand_setUniform(&drand, 0, nproc) ; /* ------------------------------- if J is in a domain map(J,K) to owners[J] else map(J,K) to a random process ------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n mapping upper blocks") ; fflush(msgFile) ; } rowids = SolveMap_rowidsUpper(solvemap) ; colids = SolveMap_colidsUpper(solvemap) ; map = SolveMap_mapUpper(solvemap) ; for ( J = loc = 0 ; J < nfront ; J++ ) { IVL_listAndSize(upperBlockIVL, J, &nadj, &adj) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n J = %d", J) ; fflush(msgFile) ; } for ( ii = 0 ; ii < nadj ; ii++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n K = %d", adj[ii]) ; fflush(msgFile) ; } if ( (K = adj[ii]) > J ) { if ( mark[J] == 'D' ) { proc = owners[J] ; } else { proc = (int) Drand_value(&drand) ; } rowids[loc] = J ; colids[loc] = K ; map[loc] = proc ; if ( msglvl > 2 ) { fprintf(msgFile, ", map[%d] = %d", loc, map[loc]) ; fflush(msgFile) ; } loc++ ; } } } if ( symmetryflag == SPOOLES_NONSYMMETRIC ) { /* ------------------------------- if J is in a domain map(K,J) to owners[J] else map(K,J) to a random process ------------------------------- */ if ( msglvl > 2 ) { fprintf(msgFile, "\n\n mapping lower blocks") ; fflush(msgFile) ; } rowids = SolveMap_rowidsLower(solvemap) ; colids = SolveMap_colidsLower(solvemap) ; map = SolveMap_mapLower(solvemap) ; for ( J = loc = 0 ; J < nfront ; J++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n J = %d", J) ; fflush(msgFile) ; } IVL_listAndSize(lowerBlockIVL, J, &nadj, &adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n K = %d", adj[ii]) ; fflush(msgFile) ; } if ( (K = adj[ii]) > J ) { if ( mark[J] == 'D' ) { proc = owners[J] ; } else { proc = (int) Drand_value(&drand) ; } rowids[loc] = K ; colids[loc] = J ; map[loc] = proc ; if ( msglvl > 2 ) { fprintf(msgFile, ", map[%d] = %d", loc, map[loc]) ; fflush(msgFile) ; } loc++ ; } } } } /* ------------------------ free the working storage ------------------------ */ CVfree(mark) ; return ; } /*--------------------------------------------------------------------*/ adj) ; for ( ii = 0 ; ii < nadj ; ii++ ) { if ( adj[ii] > J ) { nblockUpper++ ; } } } if ( msglvl > 2 ) { fprintf(msgFile, "\n nblockUpper = %d", nblockUpper) ; fflush(msgFile) ; } /* ----------------------------------------------------------- count the number of lower blocks that do not include L(J,SolveMap/src/setup.c010064400020550007177000000146360661642717700157440ustar00clevecompmath00000400000006/* setup.c */ #include "../SolveMap.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to set up the linked lists for the forward solve local to process myid created -- 98mar19, cca ----------------------------------------------------------- */ IP ** SolveMap_forwardSetup ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) { int count, J, K, loc, nblock, nfront ; int *colids, *map, *rowids ; IP *ip, *nextip ; IP **heads ; /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_forwardSetup(%p,%d)" "\n solvemap is NULL\n") ; exit(-1) ; } if ( myid < 0 || myid >= solvemap->nproc ) { fprintf(stderr, "\n fatal error in SolveMap_forwardSetup(%p,%d)" "\n myid %d, solvemap->nproc %d\n", myid, solvemap->nproc) ; exit(-1) ; } if ( solvemap == NULL || myid < 0 || myid >= solvemap->nproc ) { fprintf(stderr, "\n fatal error in SolveMap_forwardSetup(%p,%d)" "\n bad input\n", solvemap, myid) ; exit(-1) ; } nfront = solvemap->nfront ; if ( solvemap->symmetryflag == 2 ) { nblock = solvemap->nblockLower ; map = solvemap->mapLower ; rowids = solvemap->rowidsLower ; colids = solvemap->colidsLower ; } else { nblock = solvemap->nblockUpper ; map = solvemap->mapUpper ; rowids = solvemap->colidsUpper ; colids = solvemap->rowidsUpper ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n inside SolveMap_forwardSetup()") ; fprintf(msgFile, ", %d blocks", nblock) ; fprintf(msgFile, "\n map") ; IVfprintf(msgFile, nblock, map) ; fprintf(msgFile, "\n rowids") ; IVfprintf(msgFile, nblock, rowids) ; fprintf(msgFile, "\n colids") ; IVfprintf(msgFile, nblock, colids) ; fflush(msgFile) ; } /* ---------------------------------------- count the number of necessary IP objects ---------------------------------------- */ for ( loc = count = 0 ; loc < nblock ; loc++ ) { if ( map[loc] == myid ) { count++ ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n count = %d", count) ; fflush(msgFile) ; } /* ---------------------------------------------- allocate the IP objects and vector of pointers ---------------------------------------------- */ ALLOCATE(heads, struct _IP *, nfront + 2) ; for ( J = 0 ; J < nfront ; J++ ) { heads[J] = NULL ; } heads[nfront] = NULL ; if ( count > 0 ) { heads[nfront+1] = IP_init(count, IP_FORWARD) ; } else { heads[nfront+1] = NULL ; } if ( count > 0 ) { /* ---------------- set up the lists ---------------- */ for ( loc = 0, nextip = heads[nfront + 1] ; loc < nblock ; loc++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n map[%d] = %d", loc, map[loc]) ; fflush(msgFile) ; } if ( map[loc] == myid ) { ip = nextip ; nextip = ip->next ; J = colids[loc] ; K = rowids[loc] ; ip->val = J ; ip->next = heads[K] ; heads[K] = ip ; if ( msglvl > 2 ) { fprintf(msgFile, ", linking (K,J) = (%d,%d)" ", heads[%d] = %p", K, J, K, heads[K]) ; fflush(msgFile) ; } } } } return(heads) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to set up the linked lists for the backward solve local to process myid created -- 98mar19, cca ------------------------------------------------------------ */ IP ** SolveMap_backwardSetup ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) { int count, J, K, loc, nblock, nfront ; int *colids, *map, *rowids ; IP *ip, *nextip ; IP **heads ; /* --------------- check the input --------------- */ if ( solvemap == NULL || myid < 0 || myid >= solvemap->nproc ) { fprintf(stderr, "\n fatal error in SolveMap_backwardSetup(%p,%d)" "\n bad input\n", solvemap, myid) ; exit(-1) ; } nfront = solvemap->nfront ; nblock = solvemap->nblockUpper ; map = solvemap->mapUpper ; rowids = solvemap->rowidsUpper ; colids = solvemap->colidsUpper ; if ( msglvl > 2 ) { fprintf(msgFile, "\n nfront %d, nblock %d, map %p, rowids %p, colids %p", nfront, nblock, map, rowids, colids) ; fprintf(msgFile, "\n\n inside SolveMap_backwardSetup()") ; fprintf(msgFile, ", %d blocks", nblock) ; fflush(msgFile) ; fprintf(msgFile, "\n map = %p", map) ; fflush(msgFile) ; IVfprintf(msgFile, nblock, map) ; fflush(msgFile) ; fprintf(msgFile, "\n rowids = %p", rowids) ; fflush(msgFile) ; IVfprintf(msgFile, nblock, rowids) ; fflush(msgFile) ; fprintf(msgFile, "\n colids = %p", colids) ; fflush(msgFile) ; IVfprintf(msgFile, nblock, colids) ; fflush(msgFile) ; } /* ---------------------------------------- count the number of necessary IP objects ---------------------------------------- */ for ( loc = count = 0 ; loc < nblock ; loc++ ) { if ( map[loc] == myid ) { count++ ; } } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n count = %d", count) ; fflush(msgFile) ; } /* ---------------------------------------------- allocate the IP objects and vector of pointers ---------------------------------------------- */ ALLOCATE(heads, struct _IP *, nfront + 2) ; for ( J = 0 ; J < nfront ; J++ ) { heads[J] = NULL ; } heads[nfront] = NULL ; if ( count > 0 ) { heads[nfront+1] = IP_init(count, IP_FORWARD) ; } else { heads[nfront+1] = NULL ; } if ( count > 0 ) { /* ---------------- set up the lists ---------------- */ for ( loc = 0, nextip = heads[nfront + 1] ; loc < nblock ; loc++ ) { if ( msglvl > 2 ) { fprintf(msgFile, "\n map[%d] = %d", loc, map[loc]) ; fflush(msgFile) ; } if ( map[loc] == myid ) { ip = nextip ; nextip = ip->next ; J = rowids[loc] ; K = colids[loc] ; ip->val = K ; ip->next = heads[J] ; heads[J] = ip ; if ( msglvl > 2 ) { fprintf(msgFile, ", linking (J,K) = (%d,%d)" ", heads[%d] = %p", J, K, K, heads[J]) ; fflush(msgFile) ; } } } } return(heads) ; } /*--------------------------------------------------------------------*/ SolveMap/src/util.c010064400020550007177000000357570653410607600155570ustar00clevecompmath00000400000006/* util.c */ #include "../SolveMap.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- return the owner of block (rowid, colid). created -- 98mar19, cca ---------------------------------------------------- */ int SolveMap_owner ( SolveMap *solvemap, int rowid, int colid ) { int ii, loc, J, K, nblock ; int *colids, *rowids, *map ; /* --------------- check the input --------------- */ if ( solvemap == NULL || rowid < 0 || rowid >= solvemap->nfront || colid < 0 || colid >= solvemap->nfront ) { fprintf(stderr, "\n fatal error in SolveMap_owner(%p,%d,%d)" "\n bad input\n", solvemap, rowid, colid) ; exit(-1) ; } if ( rowid == colid ) { /* -------------- diagonal block -------------- */ return(solvemap->owners[rowid]) ; } else if ( rowid > colid && solvemap->symmetryflag > 0 ) { /* --------------------------------- lower block (K,J) = (rowid,colid) --------------------------------- */ nblock = solvemap->nblockLower ; rowids = solvemap->rowidsLower ; colids = solvemap->colidsLower ; map = solvemap->mapLower ; K = rowid ; J = colid ; loc = IVlocateViaBinarySearch(nblock, colids, J) ; if ( loc == -1 ) { return(-1) ; } for ( ii = loc ; ii >= 0 ; ii-- ) { if ( colids[ii] == J && rowids[ii] == K ) { return(map[ii]) ; } } for ( ii = loc + 1 ; ii < nblock ; ii++ ) { if ( colids[ii] == J && rowids[ii] == K ) { return(map[ii]) ; } } } else { /* ----------------- upper block (J,K) ----------------- */ nblock = solvemap->nblockUpper ; rowids = solvemap->rowidsUpper ; colids = solvemap->colidsUpper ; map = solvemap->mapUpper ; if ( rowid > colid ) { J = colid ; K = rowid ; } else { J = rowid ; K = colid ; } loc = IVlocateViaBinarySearch(nblock, rowids, J) ; if ( loc == -1 ) { return(-1) ; } for ( ii = loc ; ii >= 0 ; ii-- ) { if ( rowids[ii] == J && colids[ii] == K ) { return(map[ii]) ; } } for ( ii = loc +1 ; ii < nblock ; ii++ ) { if ( rowids[ii] == J && colids[ii] == K ) { return(map[ii]) ; } } } return(-1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- return an IVL object whose list K contains all processes who do not own U(K,K) but own a U(J,K) for some J. if myid == -1 then the entire IVL object is created and returned else only the portion of the IVL object pertinent to myid is created and returned endif created -- 98may24, cca --------------------------------------------------------------- */ IVL * SolveMap_upperSolveIVL ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) { int count, K, loc, nblock, nfront, nproc, q ; int *colids, *heads, *link, *list, *map, *mark, *owners, *rowids ; IVL *solveIVL ; /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_upperSolveIVL(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } nfront = solvemap->nfront ; nproc = solvemap->nproc ; nblock = solvemap->nblockUpper ; colids = solvemap->colidsUpper ; rowids = solvemap->rowidsUpper ; map = solvemap->mapUpper ; owners = solvemap->owners ; /* ------------------------------------ link the (J,K,map(J,K)) triples by K ------------------------------------ */ heads = IVinit(nfront, -1) ; link = IVinit(nblock, -1) ; for ( loc = 0 ; loc < nblock ; loc++ ) { K = colids[loc] ; link[loc] = heads[K] ; heads[K] = loc ; } list = IVinit(nproc, -1) ; mark = IVinit(nproc, -1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n linked triples by columns of U") ; for ( K = 0 ; K < nfront ; K++ ) { if ( heads[K] != -1 ) { fprintf(msgFile, "\n %d :", K) ; for ( loc = heads[K] ; loc != -1 ; loc = link[loc] ) { fprintf(msgFile, " <%d,%d>", rowids[loc], map[loc]) ; } } } } /* ------------------------------- initialize the solve IVL object ------------------------------- */ solveIVL = IVL_new() ; IVL_init1(solveIVL, IVL_CHUNKED, nfront) ; /* ------------------------------------------------------------- fill the solve IVL object list K contains the process ids that do not own K but use X_K ------------------------------------------------------------- */ for ( K = 0 ; K < nfront ; K++ ) { if ( myid == -1 || owners[K] == myid ) { mark[owners[K]] = K ; count = 0 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n list for %d :", K) ; } for ( loc = heads[K] ; loc != -1 ; loc = link[loc] ) { q = map[loc] ; if ( msglvl > 1 ) { fprintf(msgFile, " <%d,%d>", rowids[loc], q) ; } if ( mark[q] != K ) { mark[q] = K ; list[count++] = q ; if ( msglvl > 1 ) { fprintf(msgFile, "*") ; } } } if ( count > 0 ) { IVqsortUp(count, list) ; IVL_setList(solveIVL, K, count, list) ; } } } /* ------------------------ free the working storage ------------------------ */ IVfree(heads) ; IVfree(link) ; IVfree(list) ; IVfree(mark) ; return(solveIVL) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- return an IV object whose entry J contains the number of all processes who do not own U(J,J) but own a U(J,K) for some J. if myid == -1 then all entries in the vector are filled else all those entries pertinent to myid are filled endif created -- 98mar19, cca ----------------------------------------------------- */ IV * SolveMap_upperAggregateIV ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) { int count, J, loc, nblock, nfront, nproc, q ; int *aggcounts, *colids, *heads, *link, *map, *mark, *owners, *rowids ; IV *aggIV ; /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_upperAggregateIVL(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } nfront = solvemap->nfront ; nproc = solvemap->nproc ; nblock = solvemap->nblockUpper ; colids = solvemap->rowidsUpper ; rowids = solvemap->rowidsUpper ; map = solvemap->mapUpper ; owners = solvemap->owners ; /* ------------------------ initialize the IV object ------------------------ */ aggIV = IV_new() ; IV_init(aggIV, nfront, NULL) ; aggcounts = IV_entries(aggIV) ; IVzero(nfront, aggcounts) ; /* ------------------------------------ link the (J,K,map(J,K)) triples by J ------------------------------------ */ heads = IVinit(nfront, -1) ; link = IVinit(nblock, -1) ; for ( loc = 0 ; loc < nblock ; loc++ ) { J = rowids[loc] ; link[loc] = heads[J] ; heads[J] = loc ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n linked triples by rows of U") ; for ( J = 0 ; J < nfront ; J++ ) { if ( heads[J] != -1 ) { fprintf(msgFile, "\n %d :", J) ; for ( loc = heads[J] ; loc != -1 ; loc = link[loc] ) { fprintf(msgFile, " <%d,%d>", colids[loc], map[loc]) ; } } } } /* ------------------------- fill the aggcounts vector ------------------------- */ mark = IVinit(nproc, -1) ; for ( J = 0 ; J < nfront ; J++ ) { if ( myid == -1 || owners[J] == myid ) { mark[owners[J]] = J ; if ( msglvl > 1 ) { fprintf(msgFile, "\n list for %d :", J) ; } for ( loc = heads[J], count = 0 ; loc != -1 ; loc = link[loc] ) { q = map[loc] ; if ( msglvl > 1 ) { fprintf(msgFile, " <%d,%d>", colids[loc], q) ; } if ( mark[q] != J ) { mark[q] = J ; count++ ; if ( msglvl > 1 ) { fprintf(msgFile, "*") ; } } } aggcounts[J] = count ; } } /* ------------------------ free the working storage ------------------------ */ IVfree(heads) ; IVfree(link) ; IVfree(mark) ; return(aggIV) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- return an IV object whose J'th entry contains the number of processes who do not own L(J,J) but own a L(J,I) for some I < J. if myid == -1 then all entries in the vector are filled else all those entries pertinent to myid are filled endif created -- 98mar20, cca -------------------------------------------------------- */ IV * SolveMap_lowerAggregateIV ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) { int count, J, loc, nblock, nfront, nproc, q ; int *aggcounts, *colids, *heads, *link, *map, *mark, *owners, *rowids ; IV *aggIV ; /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_lowerAggregateIV(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } nfront = solvemap->nfront ; nproc = solvemap->nproc ; if ( solvemap->symmetryflag == SPOOLES_NONSYMMETRIC ) { nblock = solvemap->nblockLower ; colids = solvemap->colidsLower ; rowids = solvemap->rowidsLower ; map = solvemap->mapLower ; } else { nblock = solvemap->nblockUpper ; colids = solvemap->rowidsUpper ; rowids = solvemap->colidsUpper ; map = solvemap->mapUpper ; } owners = solvemap->owners ; /* ------------------------------------ link the (J,I,map(J,I)) triples by J ------------------------------------ */ heads = IVinit(nfront, -1) ; link = IVinit(nblock, -1) ; for ( loc = 0 ; loc < nblock ; loc++ ) { J = rowids[loc] ; link[loc] = heads[J] ; heads[J] = loc ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n linked triples by rows of L or U^T") ; for ( J = 0 ; J < nfront ; J++ ) { if ( heads[J] != -1 ) { fprintf(msgFile, "\n %d :", J) ; for ( loc = heads[J] ; loc != -1 ; loc = link[loc] ) { fprintf(msgFile, " <%d,%d>", colids[loc], map[loc]) ; } } } } mark = IVinit(nproc, -1) ; /* ---------------------------------- initialize the aggregate IV object ---------------------------------- */ aggIV = IV_new() ; IV_init(aggIV, nfront, NULL) ; aggcounts = IV_entries(aggIV) ; IVzero(nfront, aggcounts) ; /* ------------------------------------------------------------- fill the aggregate IV object aggcounts[J] = # of processors besides owner of L_{J,J} that own some L_{J,I} ------------------------------------------------------------- */ for ( J = 0 ; J < nfront ; J++ ) { if ( myid == -1 || owners[J] == myid ) { mark[owners[J]] = J ; if ( msglvl > 1 ) { fprintf(msgFile, "\n list for %d :", J) ; } for ( loc = heads[J], count = 0 ; loc != -1 ; loc = link[loc] ) { q = map[loc] ; if ( msglvl > 1 ) { fprintf(msgFile, " <%d,%d>", colids[loc], q) ; } if ( mark[q] != J ) { mark[q] = J ; count++ ; if ( msglvl > 1 ) { fprintf(msgFile, "*") ; } } } aggcounts[J] = count ; } } /* ------------------------ free the working storage ------------------------ */ IVfree(heads) ; IVfree(link) ; IVfree(mark) ; return(aggIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- return an IVL object whose list J contains the processes who do not own L(J,J) but own a L(K,J) for some K > J. if myid == -1 then the entire IVL object is created and returned else only the portion of the IVL object pertinent to myid is created and returned endif created -- 98may24, cca ------------------------------------------------------- */ IVL * SolveMap_lowerSolveIVL ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) { int count, I, J, loc, nblock, nfront, nproc, q ; int *colids, *heads, *link, *list, *map, *mark, *owners, *rowids ; IVL *solveIVL ; /* --------------- check the input --------------- */ if ( solvemap == NULL ) { fprintf(stderr, "\n fatal error in SolveMap_lowerSolveIVL(%p)" "\n bad input\n", solvemap) ; exit(-1) ; } nfront = solvemap->nfront ; nproc = solvemap->nproc ; if ( solvemap->symmetryflag == SPOOLES_NONSYMMETRIC ) { nblock = solvemap->nblockLower ; rowids = solvemap->rowidsLower ; colids = solvemap->colidsLower ; map = solvemap->mapLower ; } else { nblock = solvemap->nblockUpper ; rowids = solvemap->colidsUpper ; colids = solvemap->rowidsUpper ; map = solvemap->mapUpper ; } owners = solvemap->owners ; /* ------------------------ initialize the IV object ------------------------ */ solveIVL = IVL_new() ; IVL_init1(solveIVL, IVL_CHUNKED, nfront) ; /* ------------------------------------ link the (J,I,map(J,I)) triples by I ------------------------------------ */ heads = IVinit(nfront, -1) ; link = IVinit(nblock, -1) ; for ( loc = 0 ; loc < nblock ; loc++ ) { I = colids[loc] ; link[loc] = heads[I] ; heads[I] = loc ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n linked triples by columns of L or U^T") ; for ( I = 0 ; I < nfront ; I++ ) { if ( heads[I] != -1 ) { fprintf(msgFile, "\n %d :", I) ; for ( loc = heads[I] ; loc != -1 ; loc = link[loc] ) { fprintf(msgFile, " <%d,%d>", rowids[loc], map[loc]) ; } } } } /* ------------------------- fill the solve IVL object ------------------------- */ list = IVinit(nproc, -1) ; mark = IVinit(nproc, -1) ; for ( I = 0 ; I < nfront ; I++ ) { if ( myid == -1 || owners[I] == myid ) { mark[owners[I]] = I ; if ( msglvl > 1 ) { fprintf(msgFile, "\n list for %d :", I) ; } for ( loc = heads[I], count = 0 ; loc != -1 ; loc = link[loc] ) { q = map[loc] ; if ( msglvl > 1 ) { fprintf(msgFile, " <%d,%d>", rowids[loc], q) ; } if ( mark[q] != I ) { mark[q] = I ; list[count++] = q ; if ( msglvl > 1 ) { fprintf(msgFile, "*") ; } } } if ( count > 0 ) { IVqsortUp(count, list) ; IVL_setList(solveIVL, I, count, list) ; } } } /* ------------------------ free the working storage ------------------------ */ IVfree(heads) ; IVfree(link) ; IVfree(mark) ; IVfree(list) ; return(solveIVL) ; } /*--------------------------------------------------------------------*/ } SolveMap/doc/004275500020550007177000000000000662061316500143765ustar00clevecompmath00000400000006SolveMap/doc/dataStructure.tex010064400020550007177000000023760654031157300177540ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:SolveMap:dataStructure} \par The {\tt SolveMap} structure has the following fields. \begin{itemize} \item {\tt int symmetryflag} : symmetry flag \begin{itemize} \item {\tt SPOOLES\_SYMMETRIC} -- symmetric $(U^T + I)D(I + U)$ factorization \item {\tt SPOOLES\_HERMITIAN} -- hermitian $(U^H + I)D(I + U)$ factorization \item {\tt SPOOLES\_NONSYMMETRIC} -- nonsymmetric $(L + I)D(I + U)$ factorization \end{itemize} \item {\tt int nfront} -- number of fronts \item {\tt int nproc} -- number of threads or processes \item {\tt int *owners} -- vector mapping fronts to owning threads or processes \item {\tt int nblockUpper} -- number of submatrices in the upper triangle \item {\tt int *rowidsUpper} -- vector of row ids for the upper triangle \item {\tt int *colidsUpper} -- vector of column ids for the upper triangle \item {\tt int *mapUpper} -- map from submatrices to threads or processes \item {\tt int nblockLower} -- number of submatrices in the lower triangle \item {\tt int *rowidsLower} -- vector of row ids for the lower triangle \item {\tt int *colidsLower} -- vector of column ids for the lower triangle \item {\tt int *mapLower} -- map from submatrices to threads or processes processes \end{itemize} SolveMap/doc/intro.tex010064400020550007177000000014300654031333400162400ustar00clevecompmath00000400000006\chapter{{\tt SolveMap}: Forward and Backsolve Map} \par The {\tt SolveMap} object is to assign submatrix operations to threads or processors in a forward and backsolve. \par A front is {\it owned} by a single process, and this ownership is defined by an {\tt owners[]} vector. If process {\tt myid} owns front {\tt J}, then $L_{{\tt J},{\tt J}}$, $D_{{\tt J},{\tt J}}$ and $U_{{\tt J},{\tt J}}$ are owned by {\tt myid}. The off-diagonal submatrices in the upper block and their owners are stored as triples in three vectors. The {\tt ii}'th submatrix in the upper triangle has row id {\tt rowidsUpper[ii]}, column id {\tt colidsUpper[ii]}, and is owned by thread or process {\tt mapUpper[ii]}. A similar situation holds for the lower triangle when the factorization is nonsymmetric. \par SolveMap/doc/main.tex010064400020550007177000000010620665065631000160400ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt SolveMap} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt SolveMap} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} SolveMap/doc/proto.tex010064400020550007177000000521750661664350700163000ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt SolveMap} methods} \label{section:SolveMap:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt SolveMap} object. \par \subsection{Basic methods} \label{subsection:SolveMap:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} SolveMap * SolveMap_new ( void ) ; \end{verbatim} \index{SolveMap_new@{\tt SolveMap\_new()}} This method simply allocates storage for the {\tt SolveMap} structure and then sets the default fields by a call to {\tt SolveMap\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void SolveMap_setDefaultFields ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_setDefaultFields@{\tt SolveMap\_setDefaultFields()}} This method sets the default fields of the object --- {\tt symmetryflag = SPOOLES\_SYMMETRIC}, {\tt nfront}, {\tt nproc}, {\tt nblockUpper} and {\tt nblockLower} are set to zero, and {\tt owners}, {\tt rowidsUpper}, {\tt colidsUpper}, {\tt mapUpper}, {\tt rowidsLower}, {\tt colidsLower} and {\tt mapLower} are set to {\tt NULL}. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SolveMap_clearData ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_clearData@{\tt SolveMap\_clearData()}} This method clears any data allocated by this object and then sets the default fields with a call to {\tt SolveMap\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SolveMap_free ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_free@{\tt SolveMap\_free()}} This method releases any storage by a call to {\tt SolveMap\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \par \subsection{Instance methods} \label{subsection:SolveMap:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_symmetryflag ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_symmetryflag@{\tt SolveMap\_symmetryflag()}} This method returns {\tt symmetryflag}, the symmetry flag. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_nfront ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_nfront@{\tt SolveMap\_nfront()}} This method returns {\tt nfront}, the number of fronts. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_nproc ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_nproc@{\tt SolveMap\_nproc()}} This method returns {\tt nproc}, the number of threads or processes. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_nblockUpper ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_nblockUpper@{\tt SolveMap\_nblockUpper()}} This method returns {\tt nblockUpper}, the number of off-diagonal submatrices in the upper triangle. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_nblockLower ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_nblockLower@{\tt SolveMap\_nblockLower()}} This method returns {\tt nblockLower}, the number of off-diagonal submatrices in the lower triangle. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * SolveMap_owners ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_owners@{\tt SolveMap\_owners()}} This method returns {\tt owners}, a pointer to the map from fronts to owning threads or processes. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * SolveMap_rowidsUpper ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_rowidsUpper@{\tt SolveMap\_rowidsUpper()}} This method returns {\tt rowidsUpper}, a pointer to the vector of row ids of the submatrices in the upper triangle. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * SolveMap_colidsUpper ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_colidsUpper@{\tt SolveMap\_colidsUpper()}} This method returns {\tt colidsUpper}, a pointer to the vector of column ids of the submatrices in the upper triangle. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * SolveMap_mapUpper ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_mapUpper@{\tt SolveMap\_mapUpper()}} This method returns {\tt mapUpper}, a pointer to the vector that maps the submatrices in the upper triangle to threads or processes. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * SolveMap_rowidsLower ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_rowidsLower@{\tt SolveMap\_rowidsLower()}} This method returns {\tt rowidsLower}, a pointer to the vector of row ids of the submatrices in the lower triangle. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * SolveMap_colidsLower ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_colidsLower@{\tt SolveMap\_colidsLower()}} This method returns {\tt colidsLower}, a pointer to the vector of column ids of the submatrices in the upper triangle. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * SolveMap_mapLower ( SolveMap *solvemap ) ; \end{verbatim} \index{SolveMap_mapLower@{\tt SolveMap\_mapLower()}} This method returns {\tt mapLower}, a pointer to the vector that maps the submatrices in the upper triangle to threads or processes. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization method} \label{subsection:SolveMap:proto:init} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void SolveMap_init ( SolveMap *solvemap, int symmetryflag, int nfront, int nproc, int nblockUpper, nblockLower ) ; \end{verbatim} \index{SolveMap_init@{\tt SolveMap\_init()}} Any previously owned data is cleared via a call to {\tt SolveMap\_clearData()}. The five scalars are then set and the vectors are allocated and initialized. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, or {\tt symmetryflag} is invalid, or {\tt nfront}, {\tt nblockUpper}, {\tt nblockLower} or {\tt nproc} is negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \par \subsection{Map creation methods} \label{subsection:SolveMap:proto:maps} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void SolveMap_randomMap ( SolveMap *solvemap, int symmetryflag, IVL *upperBlockIVL, IVL *lowerBlockIVL, int nproc, IV *ownersIV, int seed, int msglvl, FILE *msgFile) ; \end{verbatim} \index{SolveMap_randomMap@{\tt SolveMap\_randomMap()}} This method maps offdiagonal submatrices to threads or processes in a random fashion. \par \noindent {\it Error checking:} If {\tt solvemap}, {\tt upperBlockIVL} or {\tt ownersIV} is {\tt NULL}, or if {\tt symmetryflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SolveMap_ddMap ( SolveMap *solvemap, int symmetryflag, IVL *upperBlockIVL, IVL *lowerBlockIVL, int nproc, IV *ownersIV, int seed, int msglvl, FILE *msgFile) ; \end{verbatim} \index{SolveMap_ddMap@{\tt SolveMap\_ddMap()}} This method maps offdiagonal submatrices to threads or processes in a domain decomposition fashion. A {\it domain} is a subtree of fronts that are owned by the same thread or process. Furthermore, a domain is {\it maximal}, i.e., the parent of the root domain (if it exists) is owned by a different process. If $J$ belongs to a domain, then for all $K$, $L_{K,J}$ and $U_{J,K}$ are owned by the thread or process that owns the domain. All other submatrices are mapped to threads or processes in a random fashion. \par \noindent {\it Error checking:} If {\tt solvemap}, {\tt upperBlockIVL} or {\tt ownersIV} is {\tt NULL}, or if {\tt symmetryflag} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Solve setup methods} \label{subsection:SolveMap:proto:setup} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IP ** SolveMap_forwardSetup ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; IP ** SolveMap_backwardSetup ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{SolveMap_forwardSetup@{\tt SolveMap\_forwardSetup()}} \index{SolveMap_backwardSetup@{\tt SolveMap\_backwardSetup()}} These two methods return a vector of pointers to {\tt IP} objects that contain the list of submatrices that thread or process {\tt myid} will use during the forward or backward solves. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, or if {\tt myid < 0} or {\tt myid >= solvemap->nproc}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:SolveMap:proto:utilities} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_owners ( SolveMap *solvemap, int rowid, int colid ) ; \end{verbatim} \index{SolveMap_owners@{\tt SolveMap\_owners()}} If {\tt rowid = colid}, this method returns the owner of front {\tt rowid}. Otherwise, this method returns the thread or process of the owner of $L_{{\tt rowid},{\tt colid}}$ if ${\tt rowid} \ge {\tt colid}$ or $U_{{\tt rowid},{\tt colid}}$ if ${\tt rowid} < {\tt colid}$. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * SolveMap_upperSolveIVL ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{SolveMap_upperSolveIVL@{\tt SolveMap\_upperSolveIVL()}} This method returns an IVL object whose list {\tt K} contains all processes that do not own {\tt K} but who own an $U_{\tt J,K}$ for some ${\tt J} < {\tt K}$. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL} then an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * SolveMap_lowerSolveIVL ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{SolveMap_lowerSolveIVL@{\tt SolveMap\_lowerSolveIVL()}} This method returns an IVL object whose list {\tt J} contains all processes that do not own {\tt J} but who own an $L_{\tt K,J}$ for some ${\tt K} > {\tt J}$. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL} then an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * SolveMap_upperAggregateIV ( SolveMap *solvemap, int myid int msglvl, FILE *msgFile ) ; \end{verbatim} \index{SolveMap_upperAggregateIV@{\tt SolveMap\_upperAggregateIV()}} This method returns an {\tt IV} object that contains the aggregate count for a backward solve. If {\tt myid} owns front {\tt J}, then entry {\tt J} of the returned {\tt IV} object contains the number of processes (other than {\tt myid}) that own an $U_{\tt J,K}$ submatrix, and so is the number of incoming aggregate submatrices process {\tt myid} expects for front {\tt J}. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL} or {\tt nlist < 0} then an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * SolveMap_lowerAggregateIV ( SolveMap *solvemap, int myid int msglvl, FILE *msgFile ) ; \end{verbatim} \index{SolveMap_lowerAggregateIV@{\tt SolveMap\_lowerAggregateIV()}} This method returns an {\tt IV} object that contains the aggregate count for a forward solve. If {\tt myid} owns front {\tt J}, then entry {\tt J} of the returned {\tt IV} object contains the number of processes (other than {\tt myid}) that own an $L_{\tt J,I}$ submatrix, (or $U_{\tt I,J}$ submatrix if symmetric or hermitian) and so is the number of incoming aggregate submatrices process {\tt myid} expects for front {\tt J}. \par \noindent {\it Error checking:} If {\tt solvemap} is {\tt NULL} or {\tt nlist < 0} then an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:SolveMap:proto:IO} \par There are the usual eight IO routines. The file structure of a {\tt SolveMap} object is simple: {\tt symmetryflag}, {\tt nfront}, {\tt nproc}, {\tt nblockUpper} and {\tt nblockLower}, followed by {\tt owners[*]}, {\tt rowidsUpper[*]}, {\tt colidsUpper[*]} and {\tt mapidsUpper[*]}, and if {\tt symmetryflag = SPOOLES\_NONSYMMETRIC}, followed by {\tt rowidsLower[*]}, {\tt colidsLower[*]} and {\tt mapidsLower[*]}. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_readFromFile ( SolveMap *solvemap, char *fn ) ; \end{verbatim} \index{SolveMap_readFromFile@{\tt SolveMap\_readFromFile()}} \par This method reads an {\tt SolveMap} object from a file. If the the file can be opened successfully, the method calls {\tt SolveMap\_readFromFormattedFile()} or {\tt SolveMap\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt solvemap} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.solvemapf} (for a formatted file) or {\tt *.solvemapb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_readFromFormattedFile ( SolveMap *solvemap, FILE *fp ) ; \end{verbatim} \index{SolveMap_readFromFormattedFile@{\tt SolveMap\_readFromFormattedFile()}} \par This method reads an {\tt SolveMap} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt solvemap} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_readFromBinaryFile ( SolveMap *solvemap, FILE *fp ) ; \end{verbatim} \index{SolveMap_readFromBinaryFile@{\tt SolveMap\_readFromBinaryFile()}} \par This method reads an {\tt SolveMap} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt solvemap} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_writeToFile ( SolveMap *solvemap, char *fn ) ; \end{verbatim} \index{SolveMap_writeToFile@{\tt SolveMap\_writeToFile()}} \par This method writes an {\tt SolveMap} object to a file. If the the file can be opened successfully, the method calls {\tt SolveMap\_writeFromFormattedFile()} or {\tt SolveMap\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt solvemap} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.solvemapf} (for a formatted file) or {\tt *.solvemapb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_writeToFormattedFile ( SolveMap *solvemap, FILE *fp ) ; \end{verbatim} \index{SolveMap_writeToFormattedFile@{\tt SolveMap\_writeToFormattedFile()}} \par This method writes an {\tt SolveMap} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt solvemap} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_writeToBinaryFile ( SolveMap *solvemap, FILE *fp ) ; \end{verbatim} \index{SolveMap_writeToBinaryFile@{\tt SolveMap\_writeToBinaryFile()}} \par This method writes an {\tt SolveMap} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt solvemap} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_writeForHumanEye ( SolveMap *solvemap, FILE *fp ) ; \end{verbatim} \index{SolveMap_writeForHumanEye@{\tt SolveMap\_writeForHumanEye()}} \par This method writes an {\tt SolveMap} object to a file in an easily readable format. The method {\tt SolveMap\_writeStats()} is called to write out the header and statistics. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt solvemap} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int SolveMap_writeStats ( SolveMap *solvemap, FILE *fp ) ; \end{verbatim} \index{SolveMap_writeStats@{\tt SolveMap\_writeStats()}} \par This method writes some statistics about an {\tt SolveMap} object to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt solvemap} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} * SolveMap_forwardSetup ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; IP ** SolveMap_backwardSetup ( SolveMap *solvemap, int myid, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{SolveMap_forwardSetup@{\tt SolveMap\_forwardSetup()}} \index{SolveMap_backwardSetup@{\tt SolveMap\_backwardSetup()}} These twoSolveMap/doc/main.log010064400020550007177000000150210661664351200160230ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 31 OCT 1998 09:22 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/latex209.def File: latex209.def 1996/05/21 v0.51 Standard LaTeX file Entering LaTeX 2.09 compatibility mode. \footheight=\dimen102 \@maxsep=\dimen103 \@dblmaxsep=\dimen104 \@cla=\count79 \@clb=\count80 \mscount=\count81 (/home/tex/teTeX/texmf/tex/latex/base/tracefnt.sty Package: tracefnt 1996/07/26 v3.0i Standard LaTeX package (font tracing) \tracingfonts=\count82 LaTeX Info: Redefining \selectfont on input line 139. ) \symbold=\mathgroup4 \symsans=\mathgroup5 \symtypewriter=\mathgroup6 \symitalic=\mathgroup7 \symsmallcaps=\mathgroup8 \symslanted=\mathgroup9 LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 306. LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 307. LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 308. LaTeX Font Info: Redeclaring math alphabet \mathit on input line 314. LaTeX Info: Redefining \em on input line 324. (/home/tex/teTeX/texmf/tex/latex/base/latexsym.sty Package: latexsym 1996/11/20 v2.2d Standard LaTeX package (lasy symbols) \symlasy=\mathgroup10 LaTeX Font Info: Overwriting symbol font `lasy' in version `bold' (Font) U/lasy/m/n --> U/lasy/b/n on input line 85. ) LaTeX Font Info: Redeclaring math delimiter \lgroup on input line 388. LaTeX Font Info: Redeclaring math delimiter \rgroup on input line 390. LaTeX Font Info: Redeclaring math delimiter \bracevert on input line 392. (/home/tex/teTeX/texmf/tex/latex/config/latex209.cfg (/home/tex/teTeX/texmf/tex/latex/tools/rawfonts.sty Compatibility mode: package `' requested, but `rawfonts' provided. Package: rawfonts 1994/05/08 Low-level LaTeX 2.09 font compatibility (/home/tex/teTeX/texmf/tex/latex/tools/somedefs.sty Package: somedefs 1994/06/01 Toolkit for optional definitions ) LaTeX Font Info: Try loading font information for U+lasy on input line 36. (/home/tex/teTeX/texmf/tex/latex/base/ulasy.fd File: ulasy.fd 1996/11/20 v2.2dLaTeX symbol font definitions )))) (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size11.clo File: size11.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count83 \c@chapter=\count84 \c@section=\count85 \c@subsection=\count86 \c@subsubsection=\count87 \c@paragraph=\count88 \c@subparagraph=\count89 \c@figure=\count90 \c@table=\count91 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 Compatibility mode: definition of \rm ignored. Compatibility mode: definition of \sf ignored. Compatibility mode: definition of \tt ignored. Compatibility mode: definition of \bf ignored. Compatibility mode: definition of \it ignored. Compatibility mode: definition of \sl ignored. Compatibility mode: definition of \sc ignored. LaTeX Info: Redefining \cal on input line 622. LaTeX Info: Redefining \mit on input line 623. \bibindent=\dimen105 ) \@indexfile=\write3 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 16. LaTeX Font Info: ... okay on input line 16. (intro.tex Chapter 1. LaTeX Font Info: External font `cmex10' loaded for size (Font) <10.95> on input line 9. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 9. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 9. ) (dataStructure.tex LaTeX Font Info: Try loading font information for OMS+cmr on input line 8. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10.95> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 8. [1 ]) (proto.tex [2] [3] Overfull \hbox (6.01772pt too wide) in paragraph at lines 244--244 [] \OT1/cmtt/m/n/10.95 IV *ownersIV, int seed, int ms glvl, FILE *msgFile) ;[] [] [4] [5] Overfull \hbox (12.09367pt too wide) in paragraph at lines 391--404 \OT1/cmr/m/n/10.95 There are the usual eight IO rou-tines. The file struc-ture of a \OT1/cmtt/m/n/10.95 SolveMap \OT1/cmr/m/n/10.95 ob-ject is sim-ple: \OT1/c mtt/m/n/10.95 symmetryflag\OT1/cmr/m/n/10.95 , [] Overfull \hbox (38.8074pt too wide) in paragraph at lines 391--404 \OT1/cmtt/m/n/10.95 nfront\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 nproc\OT1/cm r/m/n/10.95 , \OT1/cmtt/m/n/10.95 nblockUpper \OT1/cmr/m/n/10.95 and \OT1/cmtt/ m/n/10.95 nblockLower\OT1/cmr/m/n/10.95 , fol-lowed by \OT1/cmtt/m/n/10.95 owne rs[*]\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 rowidsUpper[*]\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 colidsUpper[*] [] Overfull \hbox (9.06282pt too wide) in paragraph at lines 391--404 \OT1/cmr/m/n/10.95 and \OT1/cmtt/m/n/10.95 mapidsUpper[*]\OT1/cmr/m/n/10.95 , a nd if \OT1/cmtt/m/n/10.95 symmetryflag = SPOOLES[]NONSYMMETRIC\OT1/cmr/m/n/10.9 5 , fol-lowed by \OT1/cmtt/m/n/10.95 rowidsLower[*]\OT1/cmr/m/n/10.95 , [] Overfull \hbox (2.1913pt too wide) in paragraph at lines 414--420 \OT1/cmr/m/n/10.95 the method calls \OT1/cmtt/m/n/10.95 SolveMap[]readFromForma ttedFile() \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 SolveMap[]readFromBinaryFi le()\OT1/cmr/m/n/10.95 , [] [6]) (main.ind [7] [8 ]) (main.aux) ) Here is how much of TeX's memory you used: 591 strings out of 10908 6152 string characters out of 72189 50903 words of memory out of 262141 3448 multiletter control sequences out of 9500 23452 words of font info for 88 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 22i,5n,21p,313b,383s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (8 pages, 22284 bytes). SolveMap/doc/main.idx010064400020550007177000000043500661664351200160310ustar00clevecompmath00000400000006\indexentry{SolveMap_new@{\tt SolveMap\_new()}}{2} \indexentry{SolveMap_setDefaultFields@{\tt SolveMap\_setDefaultFields()}}{2} \indexentry{SolveMap_clearData@{\tt SolveMap\_clearData()}}{2} \indexentry{SolveMap_free@{\tt SolveMap\_free()}}{2} \indexentry{SolveMap_symmetryflag@{\tt SolveMap\_symmetryflag()}}{2} \indexentry{SolveMap_nfront@{\tt SolveMap\_nfront()}}{3} \indexentry{SolveMap_nproc@{\tt SolveMap\_nproc()}}{3} \indexentry{SolveMap_nblockUpper@{\tt SolveMap\_nblockUpper()}}{3} \indexentry{SolveMap_nblockLower@{\tt SolveMap\_nblockLower()}}{3} \indexentry{SolveMap_owners@{\tt SolveMap\_owners()}}{3} \indexentry{SolveMap_rowidsUpper@{\tt SolveMap\_rowidsUpper()}}{3} \indexentry{SolveMap_colidsUpper@{\tt SolveMap\_colidsUpper()}}{3} \indexentry{SolveMap_mapUpper@{\tt SolveMap\_mapUpper()}}{3} \indexentry{SolveMap_rowidsLower@{\tt SolveMap\_rowidsLower()}}{3} \indexentry{SolveMap_colidsLower@{\tt SolveMap\_colidsLower()}}{4} \indexentry{SolveMap_mapLower@{\tt SolveMap\_mapLower()}}{4} \indexentry{SolveMap_init@{\tt SolveMap\_init()}}{4} \indexentry{SolveMap_randomMap@{\tt SolveMap\_randomMap()}}{4} \indexentry{SolveMap_ddMap@{\tt SolveMap\_ddMap()}}{4} \indexentry{SolveMap_forwardSetup@{\tt SolveMap\_forwardSetup()}}{5} \indexentry{SolveMap_backwardSetup@{\tt SolveMap\_backwardSetup()}}{5} \indexentry{SolveMap_owners@{\tt SolveMap\_owners()}}{5} \indexentry{SolveMap_upperSolveIVL@{\tt SolveMap\_upperSolveIVL()}}{5} \indexentry{SolveMap_lowerSolveIVL@{\tt SolveMap\_lowerSolveIVL()}}{5} \indexentry{SolveMap_upperAggregateIV@{\tt SolveMap\_upperAggregateIV()}}{5} \indexentry{SolveMap_lowerAggregateIV@{\tt SolveMap\_lowerAggregateIV()}}{5} \indexentry{SolveMap_readFromFile@{\tt SolveMap\_readFromFile()}}{6} \indexentry{SolveMap_readFromFormattedFile@{\tt SolveMap\_readFromFormattedFile()}}{6} \indexentry{SolveMap_readFromBinaryFile@{\tt SolveMap\_readFromBinaryFile()}}{6} \indexentry{SolveMap_writeToFile@{\tt SolveMap\_writeToFile()}}{6} \indexentry{SolveMap_writeToFormattedFile@{\tt SolveMap\_writeToFormattedFile()}}{6} \indexentry{SolveMap_writeToBinaryFile@{\tt SolveMap\_writeToBinaryFile()}}{7} \indexentry{SolveMap_writeForHumanEye@{\tt SolveMap\_writeForHumanEye()}}{7} \indexentry{SolveMap_writeStats@{\tt SolveMap\_writeStats()}}{7} }}{3} \indexentry{SolveMap_mapUpper@{\tt SolveMap\_mapUpper()}}{3} \indexentry{SolveMap_rowidsLower@{\tt SolveMap\_rowidsLower()}}{3} \indexentry{SolveMap_colidsLower@{\tt SolveMap\_colidsLower()}}{4} \indexentry{SolveMap_mapLower@{\tt SolveMap\_mapLower()}}{4} \indexentry{SolveMSolveMap/doc/main.aux010064400020550007177000000026710661664351200160460ustar00clevecompmath00000400000006\relax \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt SolveMap}: Forward and Backsolve Map}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{1}} \newlabel{section:SolveMap:dataStructure}{{1.1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt SolveMap} methods}{2}} \newlabel{section:SolveMap:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{2}} \newlabel{subsection:SolveMap:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Instance methods}{2}} \newlabel{subsection:SolveMap:proto:instance}{{1.2.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Initialization method}{4}} \newlabel{subsection:SolveMap:proto:init}{{1.2.3}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Map creation methods}{4}} \newlabel{subsection:SolveMap:proto:maps}{{1.2.4}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Solve setup methods}{5}} \newlabel{subsection:SolveMap:proto:setup}{{1.2.5}{5}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.6}Utility methods}{5}} \newlabel{subsection:SolveMap:proto:utilities}{{1.2.6}{5}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.7}IO methods}{6}} \newlabel{subsection:SolveMap:proto:IO}{{1.2.7}{6}} SolveMap/doc/makefile010064400020550007177000000000270654276745100161030ustar00clevecompmath00000400000006clean : - rm -f *.dvi SolveMap/doc/main.ind010064400020550007177000000025640661664344200160260ustar00clevecompmath00000400000006\begin{theindex} \item {\tt SolveMap\_backwardSetup()}, 5 \item {\tt SolveMap\_clearData()}, 2 \item {\tt SolveMap\_colidsLower()}, 4 \item {\tt SolveMap\_colidsUpper()}, 3 \item {\tt SolveMap\_ddMap()}, 4 \item {\tt SolveMap\_forwardSetup()}, 5 \item {\tt SolveMap\_free()}, 2 \item {\tt SolveMap\_init()}, 4 \item {\tt SolveMap\_lowerAggregateIV()}, 5 \item {\tt SolveMap\_lowerSolveIVL()}, 5 \item {\tt SolveMap\_mapLower()}, 4 \item {\tt SolveMap\_mapUpper()}, 3 \item {\tt SolveMap\_nblockLower()}, 3 \item {\tt SolveMap\_nblockUpper()}, 3 \item {\tt SolveMap\_new()}, 2 \item {\tt SolveMap\_nfront()}, 3 \item {\tt SolveMap\_nproc()}, 3 \item {\tt SolveMap\_owners()}, 3, 5 \item {\tt SolveMap\_randomMap()}, 4 \item {\tt SolveMap\_readFromBinaryFile()}, 6 \item {\tt SolveMap\_readFromFile()}, 6 \item {\tt SolveMap\_readFromFormattedFile()}, 6 \item {\tt SolveMap\_rowidsLower()}, 3 \item {\tt SolveMap\_rowidsUpper()}, 3 \item {\tt SolveMap\_setDefaultFields()}, 2 \item {\tt SolveMap\_symmetryflag()}, 2 \item {\tt SolveMap\_upperAggregateIV()}, 5 \item {\tt SolveMap\_upperSolveIVL()}, 5 \item {\tt SolveMap\_writeForHumanEye()}, 7 \item {\tt SolveMap\_writeStats()}, 7 \item {\tt SolveMap\_writeToBinaryFile()}, 7 \item {\tt SolveMap\_writeToFile()}, 6 \item {\tt SolveMap\_writeToFormattedFile()}, 6 \end{theindex} SolveMap/doc/main.ilg010064400020550007177000000004570661664344200160260ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (34 entries accepted, 0 rejected). Sorting entries....done (174 comparisons). Generating output file main.ind....done (37 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. SubMtx.h010064400020550007177000000001040653410641100134570ustar00clevecompmath00000400000006#ifndef _SubMtx_ #define _SubMtx_ #include "SubMtx/SubMtx.h" #endif SubMtx/SubMtx.h010064400020550007177000000735260661215120500147210ustar00clevecompmath00000400000006/* SubMtx.h */ #include "../cfiles.h" #include "../A2.h" #include "../ZV.h" #include "../DV.h" #include "../SPOOLES.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- structure to hold a block of a block matrix. e.g., the block partition would be by supernodes. type -- type of matrix 1 -- real 2 -- complex mode -- storage mode of matrix 0 -- dense stored by rows 1 -- dense stored by columns 2 -- sparse stored by rows 3 -- sparse stored by columns 4 -- sparse stored by triples 5 -- sparse stored by dense subrows 6 -- sparse stored by dense subcolumns 7 -- diagonal 8 -- block diagonal symmetric (upper part of each block stored by rows) 9 -- block diagonal hermitian (complex only) (upper part of each block stored by rows) rowid -- block row to which this matrix belongs colid -- block column to which this matrix belongs nrow -- number of rows ncol -- number of columns nent -- number of entries entries -- pointer to the entries wrkDV -- DV object that manages workspace next -- pointer to next SubMtx object in a singly linked list created -- 98jan29, cca ----------------------------------------------------------------- */ typedef struct _SubMtx SubMtx ; struct _SubMtx { int type ; int mode ; int rowid ; int colid ; int nrow ; int ncol ; int nent ; double *entries ; DV wrkDV ; SubMtx *next ; } ; /* ------------------------ real/complex type macros ------------------------ */ #define SUBMTX_IS_REAL(chv) ((chv)->type == SPOOLES_REAL) #define SUBMTX_IS_COMPLEX(chv) ((chv)->type == SPOOLES_COMPLEX) /* ------------------- storage mode macros ------------------- */ #define SUBMTX_DENSE_ROWS 0 #define SUBMTX_DENSE_COLUMNS 1 #define SUBMTX_SPARSE_ROWS 2 #define SUBMTX_SPARSE_COLUMNS 3 #define SUBMTX_SPARSE_TRIPLES 4 #define SUBMTX_DENSE_SUBROWS 5 #define SUBMTX_DENSE_SUBCOLUMNS 6 #define SUBMTX_DIAGONAL 7 #define SUBMTX_BLOCK_DIAGONAL_SYM 8 #define SUBMTX_BLOCK_DIAGONAL_HERM 9 #define SUBMTX_IS_DENSE_ROWS(chv) \ ((chv)->mode == SUBMTX_DENSE_ROWS) #define SUBMTX_IS_DENSE_COLUMNS(chv) \ ((chv)->mode == SUBMTX_DENSE_COLUMNS) #define SUBMTX_IS_SPARSE_ROWS(chv) \ ((chv)->mode == SUBMTX_SPARSE_ROWS) #define SUBMTX_IS_SPARSE_COLUMNS(chv) \ ((chv)->mode == SUBMTX_SPARSE_COLUMNS) #define SUBMTX_IS_SPARSE_TRIPLES(chv) \ ((chv)->mode == SUBMTX_SPARSE_TRIPLES) #define SUBMTX_IS_DENSE_SUBROWS(chv) \ ((chv)->mode == SUBMTX_DENSE_SUBROWS) #define SUBMTX_IS_DENSE_SUBCOLUMNS(chv) \ ((chv)->mode == SUBMTX_DENSE_SUBCOLUMNS) #define SUBMTX_IS_DIAGONAL(chv) \ ((chv)->mode == SUBMTX_DIAGONAL) #define SUBMTX_IS_BLOCK_DIAGONAL_SYM(chv) \ ((chv)->mode == SUBMTX_BLOCK_DIAGONAL_SYM) #define SUBMTX_IS_BLOCK_DIAGONAL_HERM(chv) \ ((chv)->mode == SUBMTX_BLOCK_DIAGONAL_HERM) /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98may01, cca ----------------------- */ SubMtx * SubMtx_new ( void ) ; /* ----------------------- set the default fields created -- 98may01, cca ----------------------- */ void SubMtx_setDefaultFields ( SubMtx *mtx ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may01, cca -------------------------------------------------- */ void SubMtx_clearData ( SubMtx *mtx ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98may01, cca ------------------------------------------ */ void SubMtx_free ( SubMtx *mtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------ purpose -- fill *prowid with the row id and *pcolid with the column id created -- 98may01, cca ------------------------------------------ */ void SubMtx_ids ( SubMtx *mtx, int *prowid, int *pcolid ) ; /* ------------------------------------- purpose -- set the row and column ids created -- 98may01, cca ------------------------------------- */ void SubMtx_setIds ( SubMtx *mtx, int rowid, int colid ) ; /* --------------------------------------------------- purpose -- fill *pnrow with the # of rows and *pncol with the # of columns and *pnent with the # of matrix entries created -- 98may01, cca --------------------------------------------------- */ void SubMtx_dimensions ( SubMtx *mtx, int *pnrow, int *pncol, int *pnent ) ; /* ------------------------------------------------------------ purpose -- fill *pnrow with the number of rows if prowind != NULL then fill *prowind with the base location of the row indices endif created -- 98may01, cca ------------------------------------------------------------ */ void SubMtx_rowIndices ( SubMtx *mtx, int *pnrow, int **prowind ) ; /* --------------------------------------------------------------- purpose -- fill *pncol with the number of column if pcolind != NULL then fill *prowind with the base location of the column indices endif created -- 98may01, cca --------------------------------------------------------------- */ void SubMtx_columnIndices ( SubMtx *mtx, int *pncol, int **pcolind ) ; /* --------------------------------- purpose -- for dense storage *pnrow with mtx->nrow *pncol with mtx->ncol *pinc1 with row increment *pinc2 with column increment *pentries with mtx->entries created -- 98may01, cca --------------------------------- */ void SubMtx_denseInfo ( SubMtx *mtx, int *pnrow, int *pncol, int *pinc1, int *pinc2, double **pentries ) ; /* --------------------------------------------- purpose -- for sparse rows, fill *pnrow with # of rows *pnent with # of indices *psizes with sizes[] of rows *pindices with indices[] for column indices *pentries with entries[] for matrix entries created -- 98may01, cca --------------------------------------------- */ void SubMtx_sparseRowsInfo ( SubMtx *mtx, int *pnrow, int *pnent, int **psizes, int **pindices, double **pentries ) ; /* ---------------------------------------------- purpose -- for sparse columns, fill *pncol with # of columns *pnent with # of matrix entries *psizes with sizes[ncol], column sizes *pindices with indices[nent], matrix row ids *pentries with entries[nent], matrix entries created -- 98may01, cca ---------------------------------------------- */ void SubMtx_sparseColumnsInfo ( SubMtx *mtx, int *pncol, int *pnent, int **psizes, int **pindices, double **pentries ) ; /* ---------------------------------------------------- purpose -- for sparse triples, fill *pnent with # of matrix entries *prowids with rowids[nent], row ids of entries *prowids with colids[nent], column ids of entries *pentries with entries[nent], matrix entries created -- 98may01, cca ---------------------------------------------------- */ void SubMtx_sparseTriplesInfo ( SubMtx *mtx, int *pnent, int **prowids, int **pcolids, double **pentries ) ; /* ----------------------------------------------------------- purpose -- for dense subrows, fill *pnrow with # of rows *pnent with # of matrix entries *pfirstlocs with firstlocs[nrow], column of first nonzero *psizes with sizes[nrow], number of nonzero columns *pentries with entries[nent], matrix entries created -- 98may01, cca ----------------------------------------------------------- */ void SubMtx_denseSubrowsInfo ( SubMtx *mtx, int *pnrow, int *pnent, int **pfirstlocs, int **psizes, double **pentries ) ; /* ----------------------------------------------------------- purpose -- for dense subcolumns, fill *pncol with # of columns *pnent with # of matrix entries *pfirstlocs with firstlocs[ncol], row of first nonzero *psizes with sizes[ncol], number of nonzero rows *pentries with entries[nent], matrix entries created -- 98may01, cca ----------------------------------------------------------- */ void SubMtx_denseSubcolumnsInfo ( SubMtx *mtx, int *pncol, int *pnent, int **pfirstlocs, int **psizes, double **pentries ) ; /* ------------------------------------------------ purpose -- for a diagonal matrix, fill *pncol with # of columns *pentries with entries[nent], matrix entries created -- 98may01, cca ------------------------------------------------ */ void SubMtx_diagonalInfo ( SubMtx *mtx, int *pncol, double **pentries ) ; /* ------------------------------------------------------ purpose -- for a block diagonal symmetric matrix, fill *pncol with # of columns *pnent with # of entries *ppivotsizes with pivotsizes[ncol] *pentries with entries[nent], matrix entries created -- 98may01, cca ------------------------------------------------------ */ void SubMtx_blockDiagonalInfo ( SubMtx *mtx, int *pncol, int *pnent, int **ppivotsizes, double **pentries ) ; /* ------------------------------------------------------- purpose -- to find matrix entry (irow,jcol) if present. return value -- if entry (irow,jcol) is not present then *pValue is 0.0 return value is -1 else entry (irow,jcol) is present then *pValue is the matrix entry return value is offset into entries array endif created -- 98may01, cca ------------------------------------------------------- */ int SubMtx_realEntry ( SubMtx *mtx, int irow, int jcol, double *pValue ) ; /* ------------------------------------------------------- purpose -- to find matrix entry (irow,jcol) if present. return value -- if entry (irow,jcol) is not present then *pReal and *pImag are 0.0 return value is -1 else entry (irow,jcol) is present then (*pReal,*pImag) is the matrix entry return value is offset into entries array endif created -- 98may01, cca ------------------------------------------------------- */ int SubMtx_complexEntry ( SubMtx *mtx, int irow, int jcol, double *pReal, double *pImag ) ; /* ------------------------------------------------- purpose -- to return a pointer to the location of matrix entry (irow,jcol) if present. if entry (irow,jcol) is not present then *ppValue is NULL else entry (irow,jcol) is present then *ppValue is the location of the matrix entry endif created -- 98may01, cca ------------------------------------------------- */ void SubMtx_locationOfRealEntry ( SubMtx *mtx, int irow, int jcol, double **ppValue ) ; /* -------------------------------------------------------- purpose -- to return a pointer to the location of matrix entry (irow,jcol) if present. if entry (irow,jcol) is not present then (*ppReal,*ppImag) is (NULL,NULL) else entry (irow,jcol) is present then (*ppReal,*ppImag) is the location of the matrix entry endif created -- 98may01, cca -------------------------------------------------------- */ void SubMtx_locationOfComplexEntry ( SubMtx *mtx, int irow, int jcol, double **ppReal, double **ppImag ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ return the number of bytes needed for an object of this size created -- 98may01, cca ------------------------------------------------------------ */ int SubMtx_nbytesNeeded ( int type, int mode, int nrow, int ncol, int nent ) ; /* ------------------------------------ return the number of bytes in use in the workspace owned by this object created -- 98may01, cca ------------------------------------ */ int SubMtx_nbytesInUse ( SubMtx *mtx ) ; /* ------------------------------------------------------ return a pointer to the workspace owned by this object created -- 98may01, cca ------------------------------------------------------ */ void * SubMtx_workspace ( SubMtx *mtx ) ; /* ---------------------------------------------------------------- return the number of bytes in the workspace owned by this object created -- 98may01, cca ---------------------------------------------------------------- */ int SubMtx_nbytesInWorkspace ( SubMtx *mtx ) ; /* ------------------------------------------------------------- set the number of bytes in the workspace owned by this object created -- 98may01, cca ------------------------------------------------------------- */ void SubMtx_setNbytesInWorkspace ( SubMtx *mtx, int nbytes ) ; /* --------------------------------------- purpose -- set the fields of the object created -- 98may01, cca --------------------------------------- */ void SubMtx_setFields ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent ) ; /* ---------------------------- purpose -- basic initializer created -- 98may01, cca ---------------------------- */ void SubMtx_init ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent ) ; /* --------------------------------------------------------- purpose -- initialize the object from its working storage used when the object is a MPI message created -- 98may01, cca --------------------------------------------------------- */ void SubMtx_initFromBuffer ( SubMtx *mtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in initRandom.c ------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------ purpose -- to initialize a matrix object with random entries and possibly random structure. created -- 98feb16, cca ------------------------------------------------ */ void SubMtx_initRandom ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent, int seed ) ; /* ------------------------------------------------ purpose -- to initialize a matrix object with random entries in the upper triangle strict = 1 --> strict upper triangle created -- 98feb16, cca ------------------------------------------------ */ void SubMtx_initRandomUpperTriangle ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent, int seed, int strict ) ; /* ------------------------------------------------ purpose -- to initialize a matrix object with random entries in the lower triangle strict = 1 --> strict lower triangle created -- 98feb16, cca ------------------------------------------------ */ void SubMtx_initRandomLowerTriangle ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent, int seed, int strict ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in scalevec.c -------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------- purpose -- compute [y0] := A * [x0] created -- 98apr17, cca ----------------------------------- */ void SubMtx_scale1vec ( SubMtx *mtxA, double y0[], double x0[] ) ; /* ------------------------------------- purpose -- compute [y0 y1] := [x0 x1] created -- 98apr17, cca ------------------------------------- */ void SubMtx_scale2vec ( SubMtx *mtxA, double y0[], double y1[], double x0[], double x1[] ) ; /* ----------------------------------------------- purpose -- compute [y0 y1 y2] := A * [x0 x1 x2] created -- 98apr17, cca ----------------------------------------------- */ void SubMtx_scale3vec ( SubMtx *mtxA, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solve.c ----------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------------- purpose -- solve A X = B, where (1) X overwrites B (2) A must be lower or upper triangular, diagonal or block diagonal (3) if A is strict lower or upper triangular, then we solve (I + A) X = B (4) columns(A) = rows(X) (5) rows(A) = rows(B) (6) B has type SUBMTX_DENSE_COLUMNS (7) if A is SUBMTX_DENSE_SUBROWS or SUBMTX_SPARSE_ROWS then A must be strict lower triangular (8) if A is SUBMTX_DENSE_SUBCOLUMNS or SUBMTX_SPARSE_COLUMNS then A must be strict upper triangular (9) A can be SUBMTX_DIAGONAL, SUBMTX_BLOCK_DIAGONAL_SYM or SUBMTX_BLOCK_DIAGONAL_HERM created -- 98may01, cca ----------------------------------------------------------------- */ void SubMtx_solve ( SubMtx *mtxA, SubMtx *mtxB ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solveT.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------------------------- purpose -- solve (A^T + I) X = B, where (1) X overwrites B (2) A must be strict lower or upper triangular (3) columns(A) = rows(X) (4) rows(A) = rows(B) (5) B has type SUBMTX_DENSE_COLUMNS (6) if A is SUBMTX_DENSE_SUBROWS or SUBMTX_SPARSE_ROWS then A must be strict lower triangular (7) if A is SUBMTX_DENSE_SUBCOLUMNS or SUBMTX_SPARSE_COLUMNS then A must be strict upper triangular created -- 98may01, cca ----------------------------------------------------------------- */ void SubMtx_solveT ( SubMtx *mtxA, SubMtx *mtxB ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solveH.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------- purpose -- solve (A^H + I) X = B, where (1) X overwrites B (2) A must be strict lower or upper triangular (2) A, B and X are complex (4) columns(A) = rows(X) (5) rows(A) = rows(B) (6) B has mode SUBMTX_DENSE_COLUMNS (7) if A is SUBMTX_DENSE_SUBROWS or SUBMTX_SPARSE_ROWS then A must be strict lower triangular (8) if A is SUBMTX_DENSE_SUBCOLUMNS or SUBMTX_SPARSE_COLUMNS then A must be strict upper triangular created -- 98may01, cca ------------------------------------------------------------- */ void SubMtx_solveH ( SubMtx *mtxA, SubMtx *mtxB ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solveupd.c -------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------------- purpose -- perform the matrix-matrix multiply Y := Y - A * X used in the forward and backsolves where (1) rows(A) \subseteq rows(Y) (2) rows(A) are local w.r.t. rows(Y) (3) cols(A) \subseteq rows(X) (4) cols(A) are local w.r.t. rows(X) (5) cols(Y) = cols(X) (6) Y and X have mode SUBMTX_DENSE_COLUMNS created -- 98may02, cca ---------------------------------------------------- */ void SubMtx_solveupd ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solveupdT.c ------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------ purpose -- perform the matrix-matrix multiply Y := Y - A^T * X used in the forward and backsolves where (1) rows(A) \subseteq rows(Y) (2) rows(A) are local w.r.t. rows(Y) (3) cols(A) \subseteq rows(X) (4) cols(A) are local w.r.t. rows(X) (5) cols(Y) = cols(X) (6) Y and X have type SUBMTX_DENSE_COLUMNS created -- 98may02, cca ----------------------------------------------------- */ void SubMtx_solveupdT ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in solveupdH.c ------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------ purpose -- perform the matrix-matrix multiply Y := Y - A^H * X used in the forward and backsolves where (1) rows(A) \subseteq rows(Y) (2) rows(A) are local w.r.t. rows(Y) (3) cols(A) \subseteq rows(X) (4) cols(A) are local w.r.t. rows(X) (5) cols(Y) = cols(X) (6) Y and X have type SUBMTX_DENSE_COLUMNS created -- 98may02, cca ----------------------------------------------------- */ void SubMtx_solveupdH ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in sort.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- purpose -- sort the rows of the matrix into ascending order created -- 98mar02, cca ----------------------------------------------------------- */ void SubMtx_sortRowsUp ( SubMtx *mtx ) ; /* -------------------------------------------------------------- purpose -- sort the columns of the matrix into ascending order created -- 98mar02, cca -------------------------------------------------------------- */ void SubMtx_sortColumnsUp ( SubMtx *mtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------- purpose -- to fill rowDV with the entries in row irow of the matrix created -- 98may01, cca ----------------------------------------- */ void SubMtx_fillRowDV ( SubMtx *mtx, int irow, DV *rowDV ) ; /* ----------------------------------------- purpose -- to fill rowZV with the entries in row irow of the matrix created -- 98may01, cca ----------------------------------------- */ void SubMtx_fillRowZV ( SubMtx *mtx, int irow, ZV *rowZV ) ; /* ----------------------------------------- purpose -- to fill colDV with the entries in column icol of the matrix created -- 98may01, cca ----------------------------------------- */ void SubMtx_fillColumnDV ( SubMtx *mtx, int icol, DV *colDV ) ; /* ----------------------------------------- purpose -- to fill colZV with the entries in column icol of the matrix created -- 98may01, cca ----------------------------------------- */ void SubMtx_fillColumnZV ( SubMtx *mtx, int icol, ZV *colZV ) ; /* ------------------------------------------------------ purpose -- return the magnitude of the largest element created -- 98may01, cca ------------------------------------------------------ */ double SubMtx_maxabs ( SubMtx *mtx ) ; /* ----------------------------------------- purpose -- zero the entries in the matrix created -- 98may04, cca ----------------------------------------- */ void SubMtx_zero ( SubMtx *mtx ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------- purpose -- to read in an SubMtx object from a file input -- fn -- filename, must be *.submtxb or *.submtxf return value -- 1 if success, 0 if failure created -- 98feb15, cca -------------------------------------------------- */ int SubMtx_readFromFile ( SubMtx *mtx, char *fn ) ; /* ------------------------------------------------------- purpose -- to read an SubMtx object from a formatted file return value -- 1 if success, 0 if failure created -- 96jun23, cca ------------------------------------------------------- */ int SubMtx_readFromFormattedFile ( SubMtx *mtx, FILE *fp ) ; /* ------------------------------------------------------ purpose -- to read an SubMtx object from a binary file return value -- 1 if success, 0 if failure created -- 96jun23, cca ------------------------------------------------------ */ int SubMtx_readFromBinaryFile ( SubMtx *mtx, FILE *fp ) ; /* ---------------------------------------------- purpose -- to write an SubMtx object to a file input -- fn -- filename *.submtxb -- binary *.submtxf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 96jun23, cca ---------------------------------------------- */ int SubMtx_writeToFile ( SubMtx *mtx, char *fn ) ; /* -------------------------------------------------------- purpose -- to write an SubMtx object to a formatted file return value -- 1 if success, 0 otherwise created -- 96jun23, cca -------------------------------------------------------- */ int SubMtx_writeToFormattedFile ( SubMtx *mtx, FILE *fp ) ; /* ----------------------------------------------------- purpose -- to write an SubMtx object to a binary file return value -- 1 if success, 0 otherwise created -- 96jun23, cca ----------------------------------------------------- */ int SubMtx_writeToBinaryFile ( SubMtx *mtx, FILE *fp ) ; /* ------------------------------------------------------- purpose -- write a SubMtx object in human readable form created -- 98feb07, cca ------------------------------------------------------- */ int SubMtx_writeForHumanEye ( SubMtx *mtx, FILE *fp ) ; /* ------------------------------------------------------------------- purpose -- write the header and scalar quantities for a SubMtx object created -- 98feb07, cca ------------------------------------------------------------------- */ int SubMtx_writeStats ( SubMtx *mtx, FILE *fp ) ; /* -------------------------------------------------- purpose -- write the matrix entries out for matlab created -- 98feb07, cca -------------------------------------------------- */ void SubMtx_writeForMatlab ( SubMtx *mtx, char *mtxname, FILE *fp ) ; /*--------------------------------------------------------------------*/ ROWS then A must be strict lower triangular (7) if A is SUBMTX_DENSE_SUBCOLUMNS or SUBMTX_SPARSE_COLUMNS then A must be strict upper trianSubMtx/makefile010064400020550007177000000002230663622366700150300ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean SubMtx/src/makefile010064400020550007177000000013300663603026000156000ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SubMtx $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(initRandom.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(scalevec.o) \ $(OBJ).a(solve.o) \ $(OBJ).a(solveH.o) \ $(OBJ).a(solveT.o) \ $(OBJ).a(solveupd.o) \ $(OBJ).a(solveupdH.o) \ $(OBJ).a(solveupdT.o) \ $(OBJ).a(sort.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG SubMtx/src/makeGlobalLib010064400020550007177000000010630660026113700165130ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SubMtx SRC = basics.c \ init.c \ initRandom.c \ instance.c \ IO.c \ scalevec.c \ solve.c \ solveH.c \ solveT.c \ solveupd.c \ solveupdH.c \ solveupdT.c \ sort.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a SubMtx/src/IO.c010064400020550007177000001153720654517147300146020ustar00clevecompmath00000400000006/* IO.c */ #include "../SubMtx.h" /*--------------------------------------------------------------------*/ static const char *suffixb = ".submtxb" ; static const char *suffixf = ".submtxf" ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to read in an SubMtx object from a file input -- fn -- filename, must be *.submtxb or *.submtxf return value -- 1 if success, 0 if failure created -- 98feb15, cca -------------------------------------------------- */ int SubMtx_readFromFile ( SubMtx *mtx, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( mtx == NULL || fn == NULL ) { fprintf(stderr, "\n error in SubMtx_readFromFile(%p,%s)" "\n bad input\n", mtx, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in SubMtx_readFromFile(%p,%s)" "\n unable to open file %s", mtx, fn, fn) ; rc = 0 ; } else { rc = SubMtx_readFromBinaryFile(mtx, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in SubMtx_readFromFile(%p,%s)" "\n unable to open file %s", mtx, fn, fn) ; rc = 0 ; } else { rc = SubMtx_readFromFormattedFile(mtx, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in SubMtx_readFromFile(%p,%s)" "\n bad SubMtx file name %s," "\n must end in %s (binary) or %s (formatted)\n", mtx, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in SubMtx_readFromFile(%p,%s)" "\n bad SubMtx file name %s," "\n must end in %s (binary) or %s (formatted)\n", mtx, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to read an SubMtx object from a formatted file return value -- 1 if success, 0 if failure created -- 96jun23, cca ------------------------------------------------------- */ int SubMtx_readFromFormattedFile ( SubMtx *mtx, FILE *fp ) { double *entries ; int inc1, inc2, ncol, nent, nrow, rc ; int itemp[7] ; int *colids, *colind, *firstlocs, *indices, *pivotsizes, *rowids, *rowind, *sizes ; /* --------------- check the input --------------- */ if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n error in SubMtx_readFromFormattedFile(%p,%p)" "\n bad input\n", mtx, fp) ; return(0) ; } SubMtx_clearData(mtx) ; /* ------------------------------- read in the seven scalar fields ------------------------------- */ if ( (rc = IVfscanf(fp, 7, itemp)) != 7 ) { fprintf(stderr, "\n 1. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, 7) ; return(0) ; } /* --------------------- check the matrix type --------------------- */ switch ( itemp[0] ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n error in SubMtx_readFromFormattedFile(%p,%p)" "\n type = %d not supported\n", mtx, fp, itemp[0]) ; return(0) ; } /* --------------------- check the matrix mode --------------------- */ switch ( itemp[1] ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : case SUBMTX_DENSE_SUBROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_DIAGONAL : case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : break ; default : fprintf(stderr, "\n error in SubMtx_readFromFormattedFile(%p,%p)" "\n mode = %d not supported\n", mtx, fp, itemp[1]) ; return(0) ; } /* --------------------- initialize the object --------------------- */ SubMtx_init(mtx, itemp[0], itemp[1], itemp[2], itemp[3], itemp[4], itemp[5], itemp[6]) ; /* --------------------------- read in the rowind[] vector --------------------------- */ SubMtx_rowIndices(mtx, &nrow, &rowind) ; if ( (rc = IVfscanf(fp, nrow, rowind)) != nrow ) { fprintf(stderr, "\n 2. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nrow) ; return(0) ; } /* --------------------------- read in the colind[] vector --------------------------- */ SubMtx_columnIndices(mtx, &ncol, &colind) ; if ( (rc = IVfscanf(fp, ncol, colind)) != ncol ) { fprintf(stderr, "\n 3. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, ncol) ; return(0) ; } /* --------------------------------------------------------------- get pointers and dimensions and read in any integer information --------------------------------------------------------------- */ switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; nent = nrow*ncol ; break ; case SUBMTX_SPARSE_ROWS : SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; if ( (rc = IVfscanf(fp, nrow, sizes)) != nrow ) { fprintf(stderr, "\n 5. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nrow) ; return(0) ; } if ( (rc = IVfscanf(fp, nent, indices)) != nent ) { fprintf(stderr, "\n 6. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nent) ; return(0) ; } break ; case SUBMTX_SPARSE_COLUMNS : SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; if ( (rc = IVfscanf(fp, ncol, sizes)) != ncol ) { fprintf(stderr, "\n 8. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, ncol) ; return(0) ; } if ( (rc = IVfscanf(fp, nent, indices)) != nent ) { fprintf(stderr, "\n 6. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items9of %d read\n", mtx, fp, rc, nent) ; return(0) ; } break ; case SUBMTX_SPARSE_TRIPLES : SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; if ( (rc = IVfscanf(fp, nent, rowids)) != nent ) { fprintf(stderr, "\n 11. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nent) ; return(0) ; } if ( (rc = IVfscanf(fp, nent, colids)) != nent ) { fprintf(stderr, "\n 12. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nent) ; return(0) ; } break ; case SUBMTX_DENSE_SUBROWS : SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; if ( (rc = IVfscanf(fp, nrow, firstlocs)) != nrow ) { fprintf(stderr, "\n 14. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nrow) ; return(0) ; } if ( (rc = IVfscanf(fp, nrow, sizes)) != nrow ) { fprintf(stderr, "\n 15. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nrow) ; return(0) ; } break ; case SUBMTX_DENSE_SUBCOLUMNS : SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; if ( (rc = IVfscanf(fp, ncol, firstlocs)) != ncol ) { fprintf(stderr, "\n 14. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, ncol) ; return(0) ; } if ( (rc = IVfscanf(fp, ncol, sizes)) != ncol ) { fprintf(stderr, "\n 15. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, ncol) ; return(0) ; } break ; case SUBMTX_DIAGONAL : SubMtx_diagonalInfo(mtx, &nent, &entries) ; break ; case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; if ( (rc = IVfscanf(fp, nrow, pivotsizes)) != nrow ) { fprintf(stderr, "\n 16. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nrow) ; return(0) ; } break ; } /* -------------------------- read in the matrix entries -------------------------- */ if ( SUBMTX_IS_REAL(mtx) ) { if ( (rc = DVfscanf(fp, nent, entries)) != nent ) { fprintf(stderr, "\n 4. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nent) ; return(0) ; } } else if ( SUBMTX_IS_COMPLEX(mtx) ) { if ( (rc = DVfscanf(fp, 2*nent, entries)) != 2*nent ) { fprintf(stderr, "\n 4. error in SubMtx_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, 2*nent) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to read an SubMtx object from a binary file return value -- 1 if success, 0 if failure created -- 96jun23, cca ------------------------------------------------------ */ int SubMtx_readFromBinaryFile ( SubMtx *mtx, FILE *fp ) { double *entries ; int inc1, inc2, ncol, nent, nrow, rc ; int itemp[7] ; int *colids, *colind, *firstlocs, *indices, *pivotsizes, *rowids, *rowind, *sizes ; /* --------------- check the input --------------- */ if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n error in SubMtx_readFromBinaryFile(%p,%p)" "\n bad input\n", mtx, fp) ; return(0) ; } SubMtx_clearData(mtx) ; /* ------------------------------- read in the seven scalar fields ------------------------------- */ if ( (rc = fread((void *) itemp, sizeof(int), 7, fp)) != 7 ) { fprintf(stderr, "\n 1. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, 7) ; return(0) ; } /* --------------------- check the matrix type --------------------- */ switch ( itemp[0] ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n error in SubMtx_readFromBinaryFile(%p,%p)" "\n type = %d not supported\n", mtx, fp, itemp[0]) ; return(0) ; } /* --------------------- check the matrix mode --------------------- */ switch ( itemp[1] ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : case SUBMTX_DENSE_SUBROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_DIAGONAL : case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : break ; default : fprintf(stderr, "\n error in SubMtx_readFromBinaryFile(%p,%p)" "\n mode = %d not supported\n", mtx, fp, itemp[1]) ; return(0) ; } /* --------------------- initialize the object --------------------- */ SubMtx_init(mtx, itemp[0], itemp[1], itemp[2], itemp[3], itemp[4], itemp[5], itemp[6]) ; /* --------------------------- read in the rowind[] vector --------------------------- */ SubMtx_rowIndices(mtx, &nrow, &rowind) ; if ( (rc = fread((void *) rowind, sizeof(int), nrow, fp)) != nrow) { fprintf(stderr, "\n 2. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nrow) ; return(0) ; } /* --------------------------- read in the colind[] vector --------------------------- */ SubMtx_columnIndices(mtx, &ncol, &colind) ; if ( (rc = fread((void *) colind, sizeof(int), ncol, fp)) != ncol) { fprintf(stderr, "\n 3. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, ncol) ; return(0) ; } /* --------------------------------------------------------------- get pointers and dimensions and read in any integer information --------------------------------------------------------------- */ switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; nent = nrow*ncol ; break ; case SUBMTX_SPARSE_ROWS : SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; if ( (rc = fread((void *) sizes, sizeof(int), nrow, fp)) != nrow) { fprintf(stderr, "\n 5. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nrow) ; return(0) ; } if ( (rc = fread((void *) indices, sizeof(int), nent, fp)) != nent) { fprintf(stderr, "\n 6. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nent) ; return(0) ; } break ; case SUBMTX_SPARSE_COLUMNS : SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; if ( (rc = fread((void *) sizes, sizeof(int), ncol, fp)) != ncol) { fprintf(stderr, "\n 8. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, ncol) ; return(0) ; } if ( (rc = fread((void *) indices, sizeof(int), nent, fp)) != nent) { fprintf(stderr, "\n 6. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items9of %d read\n", mtx, fp, rc, nent) ; return(0) ; } break ; case SUBMTX_SPARSE_TRIPLES : SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; if ( (rc = fread((void *) rowids, sizeof(int), nent, fp)) != nent) { fprintf(stderr, "\n 11. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nent) ; return(0) ; } if ( (rc = fread((void *) colids, sizeof(int), nent, fp)) != nent) { fprintf(stderr, "\n 12. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nent) ; return(0) ; } break ; case SUBMTX_DENSE_SUBROWS : SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; if ( (rc = fread((void *) firstlocs, sizeof(int), nrow, fp)) != nrow) { fprintf(stderr, "\n 14. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nrow) ; return(0) ; } if ( (rc = fread((void *) sizes, sizeof(int), nrow, fp)) != nrow) { fprintf(stderr, "\n 15. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nrow) ; return(0) ; } break ; case SUBMTX_DENSE_SUBCOLUMNS : SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; if ( (rc = fread((void *) firstlocs, sizeof(int), ncol, fp)) != ncol) { fprintf(stderr, "\n 14. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, ncol) ; return(0) ; } if ( (rc = fread((void *) sizes, sizeof(int), ncol, fp)) != ncol) { fprintf(stderr, "\n 15. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, ncol) ; return(0) ; } break ; case SUBMTX_DIAGONAL : SubMtx_diagonalInfo(mtx, &nent, &entries) ; break ; case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; if ( (rc = fread((void *) pivotsizes, sizeof(int), nrow, fp)) != nrow) { fprintf(stderr, "\n 16. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nrow) ; return(0) ; } break ; } /* -------------------------- read in the matrix entries -------------------------- */ if ( SUBMTX_IS_REAL(mtx) ) { if ( (rc = fread((void *) entries, sizeof(double), nent, fp)) != nent) { fprintf(stderr, "\n 4. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, nent) ; return(0) ; } } else if ( SUBMTX_IS_COMPLEX(mtx) ) { if ( (rc = fread((void *) entries, sizeof(double), 2*nent, fp)) != 2*nent) { fprintf(stderr, "\n 4. error in SubMtx_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", mtx, fp, rc, 2*nent) ; return(0) ; } } return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to write an SubMtx object to a file input -- fn -- filename *.submtxb -- binary *.submtxf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 96jun23, cca ---------------------------------------------- */ int SubMtx_writeToFile ( SubMtx *mtx, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( mtx == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_writeToFile(%p,%s)" "\n bad input\n", mtx, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in SubMtx_writeToFile(%p,%s)" "\n unable to open file %s", mtx, fn, fn) ; rc = 0 ; } else { rc = SubMtx_writeToBinaryFile(mtx, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in SubMtx_writeToFile(%p,%s)" "\n unable to open file %s", mtx, fn, fn) ; rc = 0 ; } else { rc = SubMtx_writeToFormattedFile(mtx, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in SubMtx_writeToFile(%p,%s)" "\n unable to open file %s", mtx, fn, fn) ; rc = 0 ; } else { rc = SubMtx_writeForHumanEye(mtx, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in SubMtx_writeToFile(%p,%s)" "\n unable to open file %s", mtx, fn, fn) ; rc = 0 ; } else { rc = SubMtx_writeForHumanEye(mtx, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to write an SubMtx object to a formatted file return value -- 1 if success, 0 otherwise created -- 96jun23, cca -------------------------------------------------------- */ int SubMtx_writeToFormattedFile ( SubMtx *mtx, FILE *fp ) { double *entries ; int inc1, inc2, ncol, nent, nrow ; int itemp[7] ; int *colids, *colind, *firstlocs, *indices, *pivotsizes, *rowids, *rowind, *sizes ; /* --------------- check the input --------------- */ if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_writeToFormattedFile(%p,%p)" "\n bad input\n", mtx, fp) ; exit(-1) ; } /* --------------------------- write out the scalar values --------------------------- */ itemp[0] = mtx->type ; itemp[1] = mtx->mode ; itemp[2] = mtx->rowid ; itemp[3] = mtx->colid ; itemp[4] = mtx->nrow ; itemp[5] = mtx->ncol ; itemp[6] = mtx->nent ; IVfprintf(fp, 7, itemp) ; /* ------------------------------------ write out the row and column indices ------------------------------------ */ SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVfprintf(fp, nrow, rowind) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVfprintf(fp, ncol, colind) ; /* --------------------------------------------------------------------- get the dimensions and pointers and write out any integer information --------------------------------------------------------------------- */ switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; nent = nrow*ncol ; break ; case SUBMTX_SPARSE_ROWS : SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; IVfprintf(fp, nrow, sizes) ; IVfprintf(fp, nent, indices) ; break ; case SUBMTX_SPARSE_COLUMNS : SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; IVfprintf(fp, ncol, sizes) ; IVfprintf(fp, nent, indices) ; break ; case SUBMTX_SPARSE_TRIPLES : SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; IVfprintf(fp, nent, rowids) ; IVfprintf(fp, nent, colids) ; break ; case SUBMTX_DENSE_SUBROWS : SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; IVfprintf(fp, nrow, firstlocs) ; IVfprintf(fp, nrow, sizes) ; break ; case SUBMTX_DENSE_SUBCOLUMNS : SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; IVfprintf(fp, ncol, firstlocs) ; IVfprintf(fp, ncol, sizes) ; break ; case SUBMTX_DIAGONAL : SubMtx_diagonalInfo(mtx, &nent, &entries) ; break ; case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; IVfprintf(fp, nrow, pivotsizes) ; break ; } /* --------------------- write out the entries --------------------- */ if ( SUBMTX_IS_REAL(mtx) ) { DVfprintf(fp, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { DVfprintf(fp, 2*nent, entries) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to write an SubMtx object to a binary file return value -- 1 if success, 0 otherwise created -- 96jun23, cca ----------------------------------------------------- */ int SubMtx_writeToBinaryFile ( SubMtx *mtx, FILE *fp ) { double *entries ; int inc1, inc2, ncol, nent, nrow, rc ; int itemp[7] ; int *colids, *colind, *firstlocs, *indices, *pivotsizes, *rowids, *rowind, *sizes ; /* --------------- check the input --------------- */ if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_writeToBinaryFile(%p,%p)" "\n bad input\n", mtx, fp) ; exit(-1) ; } /* --------------------------- write out the scalar values --------------------------- */ itemp[0] = mtx->type ; itemp[1] = mtx->mode ; itemp[2] = mtx->rowid ; itemp[3] = mtx->colid ; itemp[4] = mtx->nrow ; itemp[5] = mtx->ncol ; itemp[6] = mtx->nent ; rc = fwrite((void *) itemp, sizeof(int), 7, fp) ; /* ------------------------------------ write out the row and column indices ------------------------------------ */ SubMtx_rowIndices(mtx, &nrow, &rowind) ; rc = fwrite((void *) rowind, sizeof(int), nrow, fp) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; rc = fwrite((void *) colind, sizeof(int), ncol, fp) ; /* --------------------------------------------------------------------- get the dimensions and pointers and write out any integer information --------------------------------------------------------------------- */ switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; nent = nrow*ncol ; break ; case SUBMTX_SPARSE_ROWS : SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; rc = fwrite((void *) sizes, sizeof(int), nrow, fp) ; rc = fwrite((void *) indices, sizeof(int), nent, fp) ; break ; case SUBMTX_SPARSE_COLUMNS : SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; rc = fwrite((void *) sizes, sizeof(int), ncol, fp) ; rc = fwrite((void *) indices, sizeof(int), nent, fp) ; break ; case SUBMTX_SPARSE_TRIPLES : SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; rc = fwrite((void *) rowids, sizeof(int), nent, fp) ; rc = fwrite((void *) colids, sizeof(int), nent, fp) ; break ; case SUBMTX_DENSE_SUBROWS : SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; rc = fwrite((void *) firstlocs, sizeof(int), nrow, fp) ; rc = fwrite((void *) sizes, sizeof(int), nrow, fp) ; break ; case SUBMTX_DENSE_SUBCOLUMNS : SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; rc = fwrite((void *) firstlocs, sizeof(int), ncol, fp) ; rc = fwrite((void *) sizes, sizeof(int), ncol, fp) ; break ; case SUBMTX_DIAGONAL : SubMtx_diagonalInfo(mtx, &nent, &entries) ; break ; case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; rc = fwrite((void *) pivotsizes, sizeof(int), nrow, fp) ; break ; } /* --------------------- write out the entries --------------------- */ if ( SUBMTX_IS_REAL(mtx) ) { rc = fwrite((void *) entries, sizeof(double), nent, fp) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { rc = fwrite((void *) entries, sizeof(double), 2*nent, fp) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- write a SubMtx object in human readable form created -- 98feb07, cca ------------------------------------------------------- */ int SubMtx_writeForHumanEye ( SubMtx *mtx, FILE *fp ) { A2 a2 ; double imag, real ; int ierr, irow, jcol, ncol, nrow ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_writeForHumanEye(%p,%p)" "\n bad input\n", mtx, fp) ; exit(-1) ; } SubMtx_writeStats(mtx, fp) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; fprintf(fp, "\n rowids : ") ; IVfp80(fp, nrow, rowind, 80, &ierr) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; fprintf(fp, "\n colids : ") ; IVfp80(fp, ncol, colind, 80, &ierr) ; A2_setDefaultFields(&a2) ; A2_init(&a2, mtx->type, nrow, ncol, 1, nrow, NULL) ; A2_zero(&a2) ; for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { if ( SUBMTX_IS_REAL(mtx) ) { SubMtx_realEntry(mtx, irow, jcol, &real) ; A2_setRealEntry(&a2, irow, jcol, real) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { SubMtx_complexEntry(mtx, irow, jcol, &real, &imag) ; A2_setComplexEntry(&a2, irow, jcol, real, imag) ; } } } A2_writeForHumanEye(&a2, fp) ; A2_clearData(&a2) ; return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- write the header and scalar quantities for a SubMtx object created -- 98feb07, cca ------------------------------------------------------------------- */ int SubMtx_writeStats ( SubMtx *mtx, FILE *fp ) { /* --------------- check the input --------------- */ if ( mtx == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_writeStats(%p,%p)" "\n bad input\n", mtx, fp) ; exit(-1) ; } fprintf(fp, "\n\n SubMtx object : type %d, (rowid,colid) = (%d,%d)" "\n : %d rows x %d columns, %d entries" "\n : %d bytes in workspace, %d used, base %p", mtx->type, mtx->rowid, mtx->colid, mtx->nrow, mtx->ncol, mtx->nent, SubMtx_nbytesInWorkspace(mtx), SubMtx_nbytesInUse(mtx), SubMtx_workspace(mtx)) ; switch ( mtx->type ) { case SPOOLES_REAL : fprintf(fp, "\n : real entries") ; break ; case SPOOLES_COMPLEX : fprintf(fp, "\n : complex entries") ; break ; default : fprintf(fp, "\n : unknown entries") ; break ; } switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : fprintf(fp, "\n : dense storage via rows") ; break ; case SUBMTX_DENSE_COLUMNS : fprintf(fp, "\n : dense storage via columns") ; break ; case SUBMTX_SPARSE_ROWS : fprintf(fp, "\n : sparse storage via rows") ; break ; case SUBMTX_SPARSE_COLUMNS : fprintf(fp, "\n : sparse storage via columns") ; break ; case SUBMTX_SPARSE_TRIPLES : fprintf(fp, "\n : sparse storage via triples") ; break ; case SUBMTX_DENSE_SUBROWS : fprintf(fp, "\n : sparse storage via dense subrows") ; break ; case SUBMTX_DENSE_SUBCOLUMNS : fprintf(fp, "\n : sparse storage via dense subcolumns") ; break ; case SUBMTX_DIAGONAL : fprintf(fp, "\n : diagonal matrix") ; break ; case SUBMTX_BLOCK_DIAGONAL_SYM : fprintf(fp, "\n : block diagonal symmetric matrix") ; break ; case SUBMTX_BLOCK_DIAGONAL_HERM : fprintf(fp, "\n : block diagonal hermitian matrix") ; break ; default : fprintf(fp, "\n : unknown storage mode") ; break ; } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- write the matrix entries out for matlab created -- 98feb07, cca -------------------------------------------------- */ void SubMtx_writeForMatlab ( SubMtx *mtx, char *mtxname, FILE *fp ) { int ncol, nrow ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( mtx == NULL || mtxname == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_writeForMatlab(%p,%p,%p)" "\n bad input\n", mtx, mtxname, fp) ; exit(-1) ; } SubMtx_rowIndices(mtx, &nrow, &rowind) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; if ( SUBMTX_IS_DENSE_ROWS(mtx) || SUBMTX_IS_DENSE_COLUMNS(mtx) ) { int ij, inc1, inc2, irow, jcol, ncol, nrow ; double *entries ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { ij = irow*inc1 + jcol*inc2 ; if ( SUBMTX_IS_REAL(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e ; ", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[ij]) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[2*ij], entries[2*ij+1]) ; } } } } else if ( SUBMTX_IS_SPARSE_ROWS(mtx) ) { double *entries ; int ii, irow, jcol, nent, nrow, rowsize, *indices, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; for ( irow = 0 ; irow < nrow ; irow++ ) { rowsize = sizes[irow] ; for ( ii = 0 ; ii < rowsize ; ii++ ) { jcol = indices[ii] ; if ( SUBMTX_IS_REAL(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e ;", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[ii]) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[2*ii], entries[2*ii+1]) ; } } indices += rowsize ; if ( SUBMTX_IS_REAL(mtx) ) { entries += rowsize ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { entries += 2*rowsize ; } } } else if ( SUBMTX_IS_SPARSE_COLUMNS(mtx) ) { double *entries ; int colsize, ii, irow, jcol, nent, ncol, *indices, *sizes ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { colsize = sizes[jcol] ; for ( ii = 0 ; ii < colsize ; ii++ ) { irow = indices[ii] ; if ( SUBMTX_IS_REAL(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e ;", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[ii]) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[2*ii], entries[2*ii+1]) ; } } indices += colsize ; if ( SUBMTX_IS_REAL(mtx) ) { entries += colsize ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { entries += 2*colsize ; } } } else if ( SUBMTX_IS_SPARSE_TRIPLES(mtx) ) { double *entries ; int ii, irow, jcol, nent, *colids, *rowids ; SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; for ( ii = 0 ; ii < nent ; ii++ ) { irow = rowids[ii] ; jcol = colids[ii] ; if ( SUBMTX_IS_REAL(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e ;", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[ii]) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[2*ii], entries[2*ii+1]) ; } } } else if ( SUBMTX_IS_DENSE_SUBROWS(mtx) ) { double *entries ; int first, ii, irow, jcol, last, nent, nrow ; int *firstlocs, *sizes ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; for ( irow = 0 ; irow < nrow ; irow++ ) { if ( sizes[irow] > 0 ) { first = firstlocs[irow] ; last = first + sizes[irow] - 1 ; for ( jcol = first, ii = 0 ; jcol <= last ; jcol++, ii++ ) { if ( SUBMTX_IS_REAL(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e ;", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[ii]) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[2*ii], entries[2*ii+1]) ; } } if ( SUBMTX_IS_REAL(mtx) ) { entries += sizes[irow] ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { entries += 2*sizes[irow] ; } } } } else if ( SUBMTX_IS_DENSE_SUBCOLUMNS(mtx) ) { double *entries ; int first, ii, irow, jcol, last, ncol, nent ; int *firstlocs, *sizes ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { if ( sizes[jcol] > 0 ) { first = firstlocs[jcol] ; last = first + sizes[jcol] - 1 ; for ( irow = first, ii = 0 ; irow <= last ; irow++, ii++ ) { if ( SUBMTX_IS_REAL(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e ;", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[ii]); } else if ( SUBMTX_IS_COMPLEX(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", mtxname, rowind[irow] + 1, colind[jcol] + 1, entries[2*ii], entries[2*ii+1]) ; } } if ( SUBMTX_IS_REAL(mtx) ) { entries += sizes[jcol] ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { entries += 2*sizes[jcol] ; } } } } else if ( SUBMTX_IS_DIAGONAL(mtx) ) { double *entries ; int irow, nent ; SubMtx_diagonalInfo(mtx, &nent, &entries) ; for ( irow = 0 ; irow < nent ; irow++ ) { if ( SUBMTX_IS_REAL(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e ;", mtxname, rowind[irow]+1, colind[irow]+1, entries[irow]) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", mtxname, rowind[irow]+1, colind[irow]+1, entries[2*irow], entries[2*irow+1]) ; } } } else if ( SUBMTX_IS_BLOCK_DIAGONAL_SYM(mtx) ) { double *entries ; int ii, ipivot, irow, jj, m, kk, ncol, nent ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &ncol, &nent, &pivotsizes, &entries) ; for ( irow = ipivot = kk = 0 ; irow < ncol ; ipivot++ ) { m = pivotsizes[ipivot] ; for ( ii = 0 ; ii < m ; ii++ ) { for ( jj = ii ; jj < m ; jj++, kk++ ) { if ( SUBMTX_IS_REAL(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e ;", mtxname, rowind[irow+ii]+1, colind[irow+jj]+1, entries[kk]) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", mtxname, rowind[irow + ii]+1, colind[irow+jj]+1, entries[2*kk], entries[2*kk+1]) ; } if ( ii != jj ) { if ( SUBMTX_IS_REAL(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e ;", mtxname, colind[irow + jj]+1, rowind[irow + ii]+1, entries[kk]) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", mtxname, colind[irow + jj]+1, rowind[irow + ii]+1, entries[2*kk], entries[2*kk+1]) ; } } } } irow += m ; } } else if ( SUBMTX_IS_BLOCK_DIAGONAL_HERM(mtx) ) { double *entries ; int ii, ipivot, irow, jj, m, kk, ncol, nent ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &ncol, &nent, &pivotsizes, &entries) ; for ( irow = ipivot = kk = 0 ; irow < ncol ; ipivot++ ) { m = pivotsizes[ipivot] ; for ( ii = 0 ; ii < m ; ii++ ) { for ( jj = ii ; jj < m ; jj++, kk++ ) { fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", mtxname, rowind[irow+ii]+1, colind[irow+jj]+1, entries[2*kk], entries[2*kk+1]) ; if ( ii != jj ) { fprintf(fp, "\n %s(%d,%d) = %20.12e + %20.12e*i;", mtxname, colind[irow+jj]+1, rowind[irow+ii]+1, entries[2*kk], -entries[2*kk+1]) ; } } } irow += m ; } } return ; } /*--------------------------------------------------------------------*/ columns") ; break ; case SUBMTX_SPARSE_TRIPLES : fprintf(fp, "\n : sparse storage via triples") ; break ; case SUBMTX_DENSE_SUBROWS : fprintf(fp, "\n : sparse storage via dense subrows") ; break ; case SUBMTX_DENSE_SUBCOLUMSubMtx/src/basics.c010064400020550007177000000044010653627562400155300ustar00clevecompmath00000400000006/* basics.c */ #include "../SubMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98may01, cca ----------------------- */ SubMtx * SubMtx_new ( void ) { SubMtx *mtx ; ALLOCATE(mtx, struct _SubMtx, 1) ; SubMtx_setDefaultFields(mtx) ; return(mtx) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98may01, cca ----------------------- */ void SubMtx_setDefaultFields ( SubMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_setDefaultFields(%p)" "\n bad input", mtx) ; exit(-1) ; } mtx->type = SPOOLES_REAL ; mtx->mode = SUBMTX_DENSE_COLUMNS ; mtx->rowid = -1 ; mtx->colid = -1 ; mtx->nrow = 0 ; mtx->ncol = 0 ; mtx->nent = 0 ; mtx->next = NULL ; DV_setDefaultFields(&mtx->wrkDV) ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may01, cca -------------------------------------------------- */ void SubMtx_clearData ( SubMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_clearData(%p)" "\n bad input\n", mtx) ; exit(-1) ; } /* ------------------------ free the working storage ------------------------ */ DV_clearData(&mtx->wrkDV) ; /* ---------------------- set the default fields ---------------------- */ SubMtx_setDefaultFields(mtx) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98may01, cca ------------------------------------------ */ void SubMtx_free ( SubMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_free(%p)" "\n bad input\n", mtx) ; exit(-1) ; } SubMtx_clearData(mtx) ; FREE(mtx) ; return ; } /*--------------------------------------------------------------------*/ SubMtx/src/init.c010064400020550007177000000255510653410625100152230ustar00clevecompmath00000400000006/* init.c */ #include "../SubMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ return the number of bytes needed for an object of this size created -- 98may01, cca ------------------------------------------------------------ */ int SubMtx_nbytesNeeded ( int type, int mode, int nrow, int ncol, int nent ) { int nbytes, ndouble, nint ; /* --------------- check the input --------------- */ if ( nrow <= 0 || ncol <= 0 || nent < 0 ) { fprintf(stderr, "\n fatal error in SubMtx_nbytesNeeded(%d,%d,%d,%d,%d)" "\n bad input\n", type, mode, nrow, ncol, nent) ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n fatal error in SubMtx_nbytesNeeded(%d,%d,%d,%d,%d)" "\n bad type\n", type, mode, nrow, ncol, nent) ; exit(-1) ; } switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : case SUBMTX_SPARSE_TRIPLES : case SUBMTX_DENSE_SUBROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_DIAGONAL : case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : break ; default : fprintf(stderr, "\n fatal error in SubMtx_nbytesNeeded(%d,%d,%d,%d,%d)" "\n bad mode\n", type, mode, nrow, ncol, nent) ; exit(-1) ; } /* -------------------------------------------- determine the number of integers and doubles -------------------------------------------- */ nint = 7 + nrow + ncol ; if ( type == SPOOLES_REAL ) { ndouble = nent ; } else if ( type == SPOOLES_COMPLEX ) { ndouble = 2*nent ; } switch ( mode ) { case SUBMTX_SPARSE_ROWS : nint += nrow + nent ; break ; case SUBMTX_SPARSE_COLUMNS : nint += ncol + nent ; break ; case SUBMTX_SPARSE_TRIPLES : nint += 2*nent ; break ; case SUBMTX_DENSE_SUBROWS : nint += 2*nrow ; break ; case SUBMTX_DENSE_SUBCOLUMNS : nint += 2*ncol ; break ; case SUBMTX_DIAGONAL : break ; case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : nint += ncol ; break ; default : break ; } /* ----------------------------- determine the number of bytes ----------------------------- */ if ( sizeof(int) == sizeof(double) ) { nbytes = nint*sizeof(int) + ndouble*sizeof(double) ; } else if ( 2*sizeof(int) == sizeof(double) ) { nbytes = ((nint + 1)/2 + ndouble)*sizeof(double) ; } else { fprintf(stderr, "\n error in SubMtx_nbytesNeeded(%d,%d)" "\n sizeof(int) = %d, sizeof(double) = %d", nrow, ncol, sizeof(int), sizeof(double)) ; exit(-1) ; } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ return the number of bytes in use in the workspace owned by this object created -- 98may01, cca ------------------------------------ */ int SubMtx_nbytesInUse ( SubMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_nbytesInUse(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(sizeof(double)*DV_size(&mtx->wrkDV)) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ return a pointer to the workspace owned by this object created -- 98may01, cca ------------------------------------------------------ */ void * SubMtx_workspace ( SubMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_workspace(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return((void *)DV_entries(&mtx->wrkDV)) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- return the number of bytes in the workspace owned by this object created -- 98may01, cca ---------------------------------------------------------------- */ int SubMtx_nbytesInWorkspace ( SubMtx *mtx ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_nbytesInWorkspace(%p)" "\n bad input\n", mtx) ; exit(-1) ; } return(sizeof(double)*DV_maxsize(&mtx->wrkDV)) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- set the number of bytes in the workspace owned by this object created -- 98may01, cca ------------------------------------------------------------- */ void SubMtx_setNbytesInWorkspace ( SubMtx *mtx, int nbytes ) { if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_setNbytesInWorkspace(%p)" "\n bad input\n", mtx) ; exit(-1) ; } DV_setSize(&mtx->wrkDV, nbytes/sizeof(double)) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- set the fields of the object created -- 98may01, cca --------------------------------------- */ void SubMtx_setFields ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent ) { double *dbuffer ; int nint ; int *ibuffer ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_setFields()" "\n mtx is NULL\n") ; exit(-1) ; } if ( nrow <= 0 ) { fprintf(stderr, "\n fatal error in SubMtx_setFields()" "\n nrow = %d <= 0\n", nrow) ; exit(-1) ; } if ( ncol <= 0 ) { fprintf(stderr, "\n fatal error in SubMtx_setFields()" "\n ncol = %d <= 0\n", ncol) ; exit(-1) ; } if ( nrow <= 0 ) { fprintf(stderr, "\n fatal error in SubMtx_setFields()" "\n nent = %d <= 0\n", nent) ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n fatal error in SubMtx_setFields()" "\n invalid type %d", type) ; exit(-1) ; } switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_DIAGONAL : case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : case SUBMTX_SPARSE_TRIPLES : case SUBMTX_DENSE_SUBROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : break ; default : fprintf(stderr, "\n fatal error in SubMtx_setFields()" "\n invalid mode %d", mode) ; exit(-1) ; } dbuffer = DV_entries(&mtx->wrkDV) ; ibuffer = (int *) dbuffer ; /* --------------------- set the scalar fields --------------------- */ mtx->type = ibuffer[0] = type ; mtx->mode = ibuffer[1] = mode ; mtx->rowid = ibuffer[2] = rowid ; mtx->colid = ibuffer[3] = colid ; mtx->nrow = ibuffer[4] = nrow ; mtx->ncol = ibuffer[5] = ncol ; mtx->nent = ibuffer[6] = nent ; switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_DIAGONAL : nint = 7 + mtx->nrow + mtx->ncol ; break ; case SUBMTX_SPARSE_ROWS : nint = 7 + mtx->nrow + mtx->ncol + mtx->nrow + mtx->nent ; break ; case SUBMTX_SPARSE_COLUMNS : nint = 7 + mtx->nrow + mtx->ncol + mtx->ncol + mtx->nent ; break ; case SUBMTX_SPARSE_TRIPLES : nint = 7 + mtx->nrow + mtx->ncol + mtx->nent + mtx->nent ; break ; case SUBMTX_DENSE_SUBROWS : nint = 7 + mtx->nrow + mtx->ncol + mtx->nrow + mtx->nrow ; break ; case SUBMTX_DENSE_SUBCOLUMNS : nint = 7 + mtx->nrow + mtx->ncol + mtx->ncol + mtx->ncol ; break ; case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : nint = 7 + mtx->nrow + mtx->ncol + mtx->nrow ; break ; } if ( sizeof(int) == sizeof(double) ) { mtx->entries = dbuffer + nint ; } else if ( 2*sizeof(int) == sizeof(double) ) { mtx->entries = dbuffer + (nint+1)/2 ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- purpose -- basic initializer created -- 98may01, cca ---------------------------- */ void SubMtx_init ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent ) { int nbytes ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_init()" "\n mtx is NULL\n") ; exit(-1) ; } if ( nrow <= 0 ) { fprintf(stderr, "\n fatal error in SubMtx_init()" "\n nrow = %d <= 0\n", nrow) ; exit(-1) ; } if ( ncol <= 0 ) { fprintf(stderr, "\n fatal error in SubMtx_init()" "\n ncol = %d <= 0\n", ncol) ; exit(-1) ; } if ( nrow <= 0 ) { fprintf(stderr, "\n fatal error in SubMtx_init()" "\n nent = %d <= 0\n", nent) ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n fatal error in SubMtx_init()" "\n invalid type %d", type) ; exit(-1) ; } switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_DIAGONAL : case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : case SUBMTX_SPARSE_TRIPLES : case SUBMTX_DENSE_SUBROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : break ; default : fprintf(stderr, "\n fatal error in SubMtx_init()" "\n invalid mode %d", mode) ; exit(-1) ; } /* ------------------------------------------------------- get and set the number of bytes needed in the workspace ------------------------------------------------------- */ nbytes = SubMtx_nbytesNeeded(type, mode, nrow, ncol, nent) ; SubMtx_setNbytesInWorkspace(mtx, nbytes) ; DVzero(nbytes/sizeof(double), (double *) SubMtx_workspace(mtx)) ; /* -------------- set the fields -------------- */ SubMtx_setFields(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- initialize the object from its working storage used when the object is a MPI message created -- 98may01, cca --------------------------------------------------------- */ void SubMtx_initFromBuffer ( SubMtx *mtx ) { int *ibuffer ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_initFromBuffer(%p)" "\n bad input\n", mtx) ; exit(-1) ; } ibuffer = (int *) DV_entries(&mtx->wrkDV) ; SubMtx_setFields(mtx, ibuffer[0], ibuffer[1], ibuffer[2], ibuffer[3], ibuffer[4], ibuffer[5], ibuffer[6]) ; return ; } /*--------------------------------------------------------------------*/ SubMtx/src/initRandom.c010064400020550007177000000650320653410625200163630ustar00clevecompmath00000400000006/* initRandom.c */ #include "../../Drand.h" #include "../SubMtx.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to initialize a matrix object with random entries and possibly random structure. created -- 98feb16, cca ------------------------------------------------ */ void SubMtx_initRandom ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent, int seed ) { Drand *drand ; /* --------------- check the input --------------- */ if ( mtx == NULL || type < 1 || type > 2 || mode < 0 || mode > 9 || nrow <= 0 || ncol <= 0 ) { fprintf(stderr, "\n fatal error in SubMtx_initRandom()" "\n bad input\n") ; exit(-1) ; } SubMtx_clearData(mtx) ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; if ( seed > 0 ) { Drand_setSeed(drand, seed) ; } Drand_setUniform(drand, 0, 1) ; /* --------------------------- switch over the matrix mode --------------------------- */ switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { double *entries ; int inc1, inc2 ; /* ---------------------------------------- this case is simple, fill entries vector ---------------------------------------- */ SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nrow*ncol) ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nrow*ncol, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nrow*ncol, entries) ; } } break ; case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : case SUBMTX_SPARSE_TRIPLES : { double *entries ; int ii ; int *colids, *indices, *ivec, *ivec1, *ivec2, *rowids, *sizes ; /* ---------------------------------------------------------- (1) fill ivec[nrow*ncol] with 0, 1, ..., nrow*ncol-1 (2) shuffle ivec[nrow*ncol] (3) set rowids[nent] to be the row id of the entries of ivec[0:nent-1] (4) set colids[nent] to be the column id of the entries of ivec[0:nent-1] (5) for sparse rows and columns, set sizes[] and indices[] ---------------------------------------------------------- */ ivec = IVinit(nrow*ncol, -1) ; IVramp(nrow*ncol, ivec, 0, 1) ; IVshuffle(nrow*ncol, ivec, seed + 3) ; if ( nent > nrow*ncol ) { nent = nrow*ncol ; } rowids = IVinit(nent, -1) ; colids = IVinit(nent, -1) ; for ( ii = 0 ; ii < nent ; ii++ ) { rowids[ii] = ivec[ii] % nrow ; colids[ii] = ivec[ii] / nrow ; } SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; switch ( mode ) { case SUBMTX_SPARSE_ROWS : IV2qsortUp(nent, rowids, colids) ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; IVzero(nrow, sizes) ; for ( ii = 0 ; ii < nent ; ii++ ) { sizes[rowids[ii]]++ ; } IVcopy(nent, indices, colids) ; break ; case SUBMTX_SPARSE_COLUMNS : IV2qsortUp(nent, colids, rowids) ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; IVzero(ncol, sizes) ; for ( ii = 0 ; ii < nent ; ii++ ) { sizes[colids[ii]]++ ; } IVcopy(nent, indices, rowids) ; break ; case SUBMTX_SPARSE_TRIPLES : IV2qsortUp(nent, colids, rowids) ; SubMtx_sparseTriplesInfo(mtx, &nent, &ivec1, &ivec2, &entries) ; IVcopy(nent, ivec1, rowids) ; IVcopy(nent, ivec2, colids) ; break ; } if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } IVfree(ivec) ; IVfree(rowids) ; IVfree(colids) ; } break ; case SUBMTX_DENSE_SUBROWS : { double *entries ; int irow, size, *firstlocs, *ivec1, *ivec2, *sizes ; ivec1 = IVinit(nrow, -1) ; ivec2 = IVinit(nrow, 0) ; Drand_setUniform(drand, 0, ncol) ; Drand_fillIvector(drand, nrow, ivec1) ; Drand_fillIvector(drand, nrow, ivec2) ; for ( irow = nent = 0 ; irow < nrow ; irow++ ) { if ( (size = ivec2[irow] - ivec1[irow] + 1) <= 0 ) { ivec1[irow] = -1 ; ivec2[irow] = 0 ; } else { nent += size ; ivec2[irow] = size ; } } SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; IVcopy(nrow, firstlocs, ivec1) ; IVcopy(nrow, sizes, ivec2) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } IVfree(ivec1) ; IVfree(ivec2) ; } break ; case SUBMTX_DENSE_SUBCOLUMNS : { double *entries ; int jcol, size, *firstlocs, *ivec1, *ivec2, *sizes ; ivec1 = IVinit(ncol, -1) ; ivec2 = IVinit(ncol, -1) ; Drand_setUniform(drand, 0, nrow) ; Drand_fillIvector(drand, ncol, ivec1) ; Drand_fillIvector(drand, ncol, ivec2) ; for ( jcol = nent = 0 ; jcol < ncol ; jcol++ ) { if ( (size = ivec2[jcol] - ivec1[jcol] + 1) <= 0 ) { ivec1[jcol] = -1 ; ivec2[jcol] = 0 ; } else { nent += size ; ivec2[jcol] = size ; } } SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; IVcopy(ncol, firstlocs, ivec1) ; IVcopy(ncol, sizes, ivec2) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } IVfree(ivec1) ; IVfree(ivec2) ; } break ; case SUBMTX_DIAGONAL : { double *entries ; ncol = nrow ; nent = nrow ; SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; SubMtx_diagonalInfo(mtx, &ncol, &entries) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } } break ; case SUBMTX_BLOCK_DIAGONAL_SYM : { double *entries ; int ipivot, irow, m ; int *pivots, *pivotsizes ; ncol = nrow ; pivotsizes = IVinit(nrow, -1) ; Drand_setUniform(drand, 1,3) ; Drand_fillIvector(drand, ncol, pivotsizes) ; for ( ipivot = irow = nent = 0 ; irow < nrow ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( irow + m > nrow ) { m = pivotsizes[ipivot] = nrow - irow ; } nent += (m*(m+1))/2 ; irow += m ; } IVzero(nrow - ipivot, pivotsizes + ipivot) ; SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; SubMtx_blockDiagonalInfo(mtx, &ncol, &nent, &pivots, &entries) ; IVcopy(nrow, pivots, pivotsizes) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } IVfree(pivotsizes) ; } break ; case SUBMTX_BLOCK_DIAGONAL_HERM : { double *entries ; int ipivot, irow, kk, m ; int *pivots, *pivotsizes ; ncol = nrow ; pivotsizes = IVinit(nrow, -1) ; Drand_setUniform(drand, 1,3) ; Drand_fillIvector(drand, ncol, pivotsizes) ; for ( ipivot = irow = nent = 0 ; irow < nrow ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( irow + m > nrow ) { m = pivotsizes[ipivot] = nrow - irow ; } nent += (m*(m+1))/2 ; irow += m ; } IVzero(nrow - ipivot, pivotsizes + ipivot) ; SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; SubMtx_blockDiagonalInfo(mtx, &ncol, &nent, &pivots, &entries) ; IVcopy(nrow, pivots, pivotsizes) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } if ( SUBMTX_IS_COMPLEX(mtx) ) { for ( ipivot = irow = kk = 0 ; irow < nrow ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { entries[2*kk+1] = 0.0 ; kk++ ; } else { entries[2*kk+1] = 0.0 ; entries[2*kk+5] = 0.0 ; kk += 3 ; } irow += m ; } } IVfree(pivotsizes) ; } break ; default : fprintf(stderr, "\n\n %% type %d not yet supported", type) ; exit(0) ; break ; } Drand_free(drand) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to initialize a matrix object with random entries in the upper triangle strict = 1 --> strict upper triangle created -- 98feb16, cca ------------------------------------------------ */ void SubMtx_initRandomUpperTriangle ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent, int seed, int strict ) { Drand *drand ; /* --------------- check the input --------------- */ if ( mtx == NULL || type < 1 || type > 2 || mode < 0 || mode > 9 || nrow <= 0 || ncol <= 0 ) { fprintf(stderr, "\n fatal error in SubMtx_initRandomUpperTriangle()" "\n bad input\n") ; exit(-1) ; } SubMtx_clearData(mtx) ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; if ( seed > 0 ) { Drand_setSeed(drand, seed) ; } Drand_setUniform(drand, 0, 1) ; /* --------------------------- switch over the matrix type --------------------------- */ switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { double *entries ; int ij, inc1, inc2, irow, jcol ; /* ------------------------------------------------------------------- (1) initialize the matrix and fill all entries with random numbers. (2) put zeros in (strict) lower triangle ------------------------------------------------------------------- */ SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nrow*ncol) ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; if ( strict == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol <= irow ; jcol++ ) { ij = irow*inc1 + jcol*inc2 ; entries[ij] = 0.0 ; } } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < irow ; jcol++ ) { ij = irow*inc1 + jcol*inc2 ; entries[ij] = 0.0 ; } } } } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; if ( strict == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol <= irow ; jcol++ ) { ij = irow*inc1 + jcol*inc2 ; entries[2*ij] = entries[2*ij+1] = 0.0 ; } } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < irow ; jcol++ ) { ij = irow*inc1 + jcol*inc2 ; entries[2*ij] = entries[2*ij+1] = 0.0 ; } } } } } break ; case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : { double *entries ; int count, ii, irow, jcol ; int *colids, *indices, *ivec, *rowids, *sizes ; /* ------------------------------------------ fill ivec[*] with upper triangular entries ------------------------------------------ */ ivec = IVinit(nrow*ncol, -1) ; if ( strict == 1 ) { for ( irow = count = 0 ; irow < nrow ; irow++ ) { for ( jcol = irow + 1 ; jcol < ncol ; jcol++ ) { ivec[count++] = irow + jcol*nrow ; } } } else { for ( irow = count = 0 ; irow < nrow ; irow++ ) { for ( jcol = irow ; jcol < ncol ; jcol++ ) { ivec[count++] = irow + jcol*nrow ; } } } IVshuffle(count, ivec, seed) ; if ( nent > count ) { nent = count ; } rowids = IVinit(nent, -1) ; colids = IVinit(nent, -1) ; for ( ii = 0 ; ii < nent ; ii++ ) { rowids[ii] = ivec[ii] % nrow ; colids[ii] = ivec[ii] / nrow ; } SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; if ( mode == SUBMTX_SPARSE_ROWS ) { SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; IVzero(nrow, sizes) ; IV2qsortUp(nent, rowids, colids) ; for ( ii = 0 ; ii < nent ; ii++ ) { sizes[rowids[ii]]++ ; } IVcopy(nent, indices, colids) ; } else { SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; IV2qsortUp(nent, colids, rowids) ; IVzero(ncol, sizes) ; for ( ii = 0 ; ii < nent ; ii++ ) { sizes[colids[ii]]++ ; } IVcopy(nent, indices, rowids) ; } if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } IVfree(ivec) ; IVfree(rowids) ; IVfree(colids) ; } break ; case SUBMTX_DENSE_SUBROWS : { double *entries ; int irow, size ; int *firstlocs, *ivec1, *ivec2, *sizes ; /* ------------------------------------------------------------ fill ivec1[] and ivec2[] with start and end column locations ------------------------------------------------------------ */ ivec1 = IVinit(nrow, -1) ; ivec2 = IVinit(nrow, -1) ; Drand_setUniform(drand, 0, ncol) ; Drand_fillIvector(drand, nrow, ivec1) ; Drand_fillIvector(drand, nrow, ivec2) ; /* ------------------------------------------------- modify ivec1[] to be on or just past the diagonal ------------------------------------------------- */ if ( strict == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { if ( ivec1[irow] <= irow ) { ivec1[irow] = irow + 1 ; } } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { if ( ivec1[irow] < irow ) { ivec1[irow] = irow ; } } } /* ----------------------------------------------------------- set ivec2[] to be the sizes and count the number of entries ----------------------------------------------------------- */ for ( irow = nent = 0 ; irow < nrow ; irow++ ) { if ( (size = ivec2[irow] - ivec1[irow] + 1) <= 0 ) { ivec1[irow] = -1 ; ivec2[irow] = 0 ; } else { nent += size ; ivec2[irow] = size ; } } /* ------------------------------------------------- initialize, set first location, sizes and entries ------------------------------------------------- */ SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; IVcopy(nrow, firstlocs, ivec1) ; IVcopy(nrow, sizes, ivec2) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } IVfree(ivec1) ; IVfree(ivec2) ; } break ; case SUBMTX_DENSE_SUBCOLUMNS : { double *entries ; int jcol, size ; int *firstlocs, *ivec1, *ivec2, *sizes ; /* --------------------------------------------------------- fill ivec1[] and ivec2[] with start and end row locations --------------------------------------------------------- */ ivec1 = IVinit(ncol, -1) ; ivec2 = IVinit(ncol, -1) ; Drand_setUniform(drand, 0, nrow) ; Drand_fillIvector(drand, ncol, ivec1) ; Drand_fillIvector(drand, ncol, ivec2) ; /* ------------------------------------------------- modify ivec2[] to be on or just past the diagonal ------------------------------------------------- */ if ( strict == 1 ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { if ( ivec2[jcol] >= jcol ) { ivec2[jcol] = jcol - 1 ; } } } else { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { if ( ivec2[jcol] > jcol ) { ivec2[jcol] = jcol ; } } } /* ----------------------------------------------------------- set ivec2[] to be the sizes and count the number of entries ----------------------------------------------------------- */ for ( jcol = nent = 0 ; jcol < ncol ; jcol++ ) { if ( (size = ivec2[jcol] - ivec1[jcol] + 1) <= 0 ) { ivec1[jcol] = -1 ; ivec2[jcol] = 0 ; } else { nent += size ; ivec2[jcol] = size ; } } /* ------------------------------------------------- initialize, set first location, sizes and entries ------------------------------------------------- */ SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; IVcopy(nrow, firstlocs, ivec1) ; IVcopy(nrow, sizes, ivec2) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } IVfree(ivec1) ; IVfree(ivec2) ; } break ; default : fprintf(stderr, "\n\n %% type %d not yet supported", type) ; exit(0) ; break ; } /* -------------------------------- free the random number generator -------------------------------- */ Drand_free(drand) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to initialize a matrix object with random entries in the lower triangle strict = 1 --> strict lower triangle created -- 98feb16, cca ------------------------------------------------ */ void SubMtx_initRandomLowerTriangle ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent, int seed, int strict ) { Drand *drand ; int *colind, *rowind ; /* --------------- check the input --------------- */ if ( mtx == NULL || type < 0 || type > 9 || nrow <= 0 || ncol <= 0 ) { fprintf(stderr, "\n fatal error in SubMtx_initRandomLowerTriangle()" "\n bad input\n") ; exit(-1) ; } SubMtx_clearData(mtx) ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; if ( seed > 0 ) { Drand_setSeed(drand, seed) ; } Drand_setUniform(drand, 0, 1) ; /* --------------------------- switch over the matrix type --------------------------- */ switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { double *entries ; int ij, inc1, inc2, irow, jcol ; /* ------------------------------------------------------------------- (1) initialize the matrix and fill all entries with random numbers. (2) put zeros in (strict) upper triangle ------------------------------------------------------------------- */ SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nrow*ncol) ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; if ( strict == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = irow ; jcol < ncol ; jcol++ ) { ij = irow*inc1 + jcol*inc2 ; entries[ij] = 0.0 ; } } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = irow + 1 ; jcol < ncol ; jcol++ ) { ij = irow*inc1 + jcol*inc2 ; entries[ij] = 0.0 ; } } } } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; if ( strict == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = irow ; jcol < ncol ; jcol++ ) { ij = irow*inc1 + jcol*inc2 ; entries[2*ij] = entries[2*ij+1] = 0.0 ; } } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { for ( jcol = irow + 1 ; jcol < ncol ; jcol++ ) { ij = irow*inc1 + jcol*inc2 ; entries[2*ij] = entries[2*ij+1] = 0.0 ; } } } } } break ; case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : { double *entries ; int count, ii, irow, jcol ; int *colids, *indices, *ivec, *rowids, *sizes ; ivec = IVinit(nrow*ncol, -1) ; if ( strict == 1 ) { for ( irow = count = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol < irow ; jcol++ ) { ivec[count++] = irow + jcol*nrow ; } } } else { for ( irow = count = 0 ; irow < nrow ; irow++ ) { for ( jcol = 0 ; jcol <= irow ; jcol++ ) { ivec[count++] = irow + jcol*nrow ; } } } IVshuffle(count, ivec, seed) ; if ( nent > count ) { nent = count ; } rowids = IVinit(nent, -1) ; colids = IVinit(nent, -1) ; for ( ii = 0 ; ii < nent ; ii++ ) { rowids[ii] = ivec[ii] % nrow ; colids[ii] = ivec[ii] / nrow ; } SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; if ( mode == SUBMTX_SPARSE_ROWS ) { SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; IVzero(nrow, sizes) ; IV2qsortUp(nent, rowids, colids) ; for ( ii = 0 ; ii < nent ; ii++ ) { sizes[rowids[ii]]++ ; } IVcopy(nent, indices, colids) ; } else { SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; IV2qsortUp(nent, colids, rowids) ; IVzero(ncol, sizes) ; for ( ii = 0 ; ii < nent ; ii++ ) { sizes[colids[ii]]++ ; } IVcopy(nent, indices, rowids) ; } if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } IVfree(ivec) ; IVfree(rowids) ; IVfree(colids) ; } break ; case SUBMTX_DENSE_SUBROWS : { double *entries ; int irow, size ; int *firstlocs, *ivec1, *ivec2, *sizes ; /* ------------------------------------------------------------ fill ivec1[] and ivec2[] with start and end column locations ------------------------------------------------------------ */ ivec1 = IVinit(nrow, -1) ; ivec2 = IVinit(nrow, -1) ; Drand_setUniform(drand, 0, ncol) ; Drand_fillIvector(drand, nrow, ivec1) ; Drand_fillIvector(drand, nrow, ivec2) ; /* ------------------------------------------------- modify ivec2[] to be on or just past the diagonal ------------------------------------------------- */ if ( strict == 1 ) { for ( irow = 0 ; irow < nrow ; irow++ ) { if ( ivec2[irow] >= irow ) { ivec2[irow] = irow - 1 ; } } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { if ( ivec1[irow] > irow ) { ivec1[irow] = irow ; } } } /* ----------------------------------------------------------- set ivec2[] to be the sizes and count the number of entries ----------------------------------------------------------- */ for ( irow = nent = 0 ; irow < nrow ; irow++ ) { if ( (size = ivec2[irow] - ivec1[irow] + 1) <= 0 ) { ivec1[irow] = -1 ; ivec2[irow] = 0 ; } else { nent += size ; ivec2[irow] = size ; } } SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; IVcopy(nrow, firstlocs, ivec1) ; IVcopy(nrow, sizes, ivec2) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } IVfree(ivec1) ; IVfree(ivec2) ; } break ; case SUBMTX_DENSE_SUBCOLUMNS : { double *entries ; int jcol, size ; int *firstlocs, *ivec1, *ivec2, *sizes ; /* --------------------------------------------------------- fill ivec1[] and ivec2[] with start and end row locations --------------------------------------------------------- */ ivec1 = IVinit(ncol, -1) ; ivec2 = IVinit(ncol, -1) ; Drand_setUniform(drand, 0, nrow) ; Drand_fillIvector(drand, ncol, ivec1) ; Drand_fillIvector(drand, ncol, ivec2) ; /* ------------------------------------------------- modify ivec1[] to be on or just past the diagonal ------------------------------------------------- */ if ( strict == 1 ) { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { if ( ivec1[jcol] <= jcol ) { ivec1[jcol] = jcol + 1 ; } } } else { for ( jcol = 0 ; jcol < ncol ; jcol++ ) { if ( ivec1[jcol] < jcol ) { ivec1[jcol] = jcol ; } } } /* ----------------------------------------------------------- set ivec2[] to be the sizes and count the number of entries ----------------------------------------------------------- */ for ( jcol = nent = 0 ; jcol < ncol ; jcol++ ) { if ( (size = ivec2[jcol] - ivec1[jcol] + 1) <= 0 ) { ivec1[jcol] = -1 ; ivec2[jcol] = 0 ; } else { nent += size ; } } SubMtx_init(mtx, type, mode, rowid, colid, nrow, ncol, nent) ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; IVcopy(ncol, firstlocs, ivec1) ; IVcopy(ncol, sizes, ivec2) ; if ( SUBMTX_IS_REAL(mtx) ) { Drand_fillDvector(drand, nent, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { Drand_fillDvector(drand, 2*nent, entries) ; } IVfree(ivec1) ; IVfree(ivec2) ; } break ; default : fprintf(stderr, "\n\n %% type %d not yet supported", type) ; exit(0) ; break ; } SubMtx_rowIndices(mtx, &nrow, &rowind) ; IVramp(nrow, rowind, 0, 1) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; IVramp(ncol, colind, 0, 1) ; /* -------------------------------- free the random number generator -------------------------------- */ Drand_free(drand) ; return ; } /*--------------------------------------------------------------------*/ e number of entries ----------------------------------------------------------- */ for ( jcol = nent = 0 ; jcol < ncol ; jcol++ ) { if ( (size = ivec2[jcol] - ivec1[jcol] + 1) <= 0 ) { ivec1[jcol] = -1 ; ivec2[jcol] = 0 ; } else { nent += size ; ivec2[jcol] = size ; } } /* ------------------------------------------------- initialize, set first location, sizes and entries ----------------------------------------SubMtx/src/instance.c010064400020550007177000001271600661220455700160700ustar00clevecompmath00000400000006/* instance.c */ #include "../SubMtx.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------ purpose -- fill *prowid with the row id and *pcolid with the column id created -- 98may01, cca ------------------------------------------ */ void SubMtx_ids ( SubMtx *mtx, int *prowid, int *pcolid ) { /* --------------- check the input --------------- */ if ( mtx == NULL || prowid == NULL || pcolid == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_ids(%p,%p,%p)" "\n bad input\n", mtx, prowid, pcolid) ; exit(-1) ; } *prowid = mtx->rowid ; *pcolid = mtx->colid ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- set the row and column ids created -- 98may01, cca ------------------------------------- */ void SubMtx_setIds ( SubMtx *mtx, int rowid, int colid ) { int *buffer ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_ids(%p,%d,%d)" "\n bad input\n", mtx, rowid, colid) ; exit(-1) ; } buffer = (int *) mtx->wrkDV.vec ; buffer[2] = mtx->rowid = rowid ; buffer[3] = mtx->colid = colid ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- fill *pnrow with the # of rows and *pncol with the # of columns and *pnent with the # of matrix entries created -- 98may01, cca --------------------------------------------------- */ void SubMtx_dimensions ( SubMtx *mtx, int *pnrow, int *pncol, int *pnent ) { /* --------------- check the input --------------- */ if ( mtx == NULL || pnrow == NULL || pncol == NULL || pnent == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_ids(%p,%p,%p,%p)" "\n bad input\n", mtx, pnrow, pncol, pnent) ; exit(-1) ; } *pnrow = mtx->nrow ; *pncol = mtx->ncol ; *pnent = mtx->nent ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- fill *pnrow with the number of rows if prowind != NULL then fill *prowind with the base location of the row indices endif created -- 98may01, cca ------------------------------------------------------------ */ void SubMtx_rowIndices ( SubMtx *mtx, int *pnrow, int **prowind ) { *pnrow = mtx->nrow ; if ( prowind != NULL ) { *prowind = (int *) mtx->wrkDV.vec + 7 ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- fill *pncol with the number of column if pcolind != NULL then fill *prowind with the base location of the column indices endif created -- 98may01, cca --------------------------------------------------------------- */ void SubMtx_columnIndices ( SubMtx *mtx, int *pncol, int **pcolind ) { *pncol = mtx->ncol ; if ( pcolind != NULL ) { *pcolind = (int *) mtx->wrkDV.vec + 7 + mtx->nrow ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------- purpose -- for dense storage *pnrow with mtx->nrow *pncol with mtx->ncol *pinc1 with row increment *pinc2 with column increment *pentries with mtx->entries created -- 98may01, cca --------------------------------- */ void SubMtx_denseInfo ( SubMtx *mtx, int *pnrow, int *pncol, int *pinc1, int *pinc2, double **pentries ) { double *dbuffer ; int nint ; /* --------------- check the input --------------- */ if ( mtx == NULL || pnrow == NULL || pncol == NULL || pinc1 == NULL || pinc2 == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_denseInfo(%p,%p,%p,%p,%p,%p)" "\n bad input\n", mtx, pnrow, pncol, pinc1, pinc2, pentries) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtx) || SUBMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_denseInfo(%p,%p,%p,%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, pnrow, pncol, pinc1, pinc2, pentries, mtx->type) ; exit(-1) ; } if ( ! (SUBMTX_IS_DENSE_ROWS(mtx) || SUBMTX_IS_DENSE_COLUMNS(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_denseInfo(%p,%p,%p,%p,%p,%p)" "\n bad mode %d" "\n must be SUBMTX_DENSE_ROWS or SUBMTX_DENSE_COLUMNS\n", mtx, pnrow, pncol, pinc1, pinc2, pentries, mtx->mode) ; exit(-1) ; } *pnrow = mtx->nrow ; *pncol = mtx->ncol ; if ( SUBMTX_IS_DENSE_ROWS(mtx) ) { *pinc1 = mtx->ncol ; *pinc2 = 1 ; } else { *pinc1 = 1 ; *pinc2 = mtx->nrow ; } dbuffer = mtx->wrkDV.vec ; nint = 7 + mtx->nrow + mtx->ncol ; if ( sizeof(int) == sizeof(double) ) { *pentries = dbuffer + nint ; } else if ( 2*sizeof(int) == sizeof(double) ) { *pentries = dbuffer + (nint+1)/2 ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- for sparse rows, fill *pnrow with # of rows *pnent with # of indices *psizes with sizes[] of rows *pindices with indices[] for column indices *pentries with entries[] for matrix entries created -- 98may01, cca --------------------------------------------- */ void SubMtx_sparseRowsInfo ( SubMtx *mtx, int *pnrow, int *pnent, int **psizes, int **pindices, double **pentries ) { double *dbuffer ; int nint ; int *ibuffer ; /* --------------- check the input --------------- */ if ( mtx == NULL || pnrow == NULL || pnent == NULL || psizes == NULL || pindices == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_sparseRowsInfo(%p,%p,%p,%p,%p,%p)" "\n bad input\n", mtx, pnrow, pnent, psizes, pindices, pentries) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtx) || SUBMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_sparseRowsInfo(%p,%p,%p,%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, pnrow, pnent, psizes, pindices, pentries, mtx->type) ; exit(-1) ; } if ( ! SUBMTX_IS_SPARSE_ROWS(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_sparseRowsInfo(%p,%p,%p,%p,%p,%p)" "\n bad mode %d, must be SUBMTX_SPARSE_ROWS\n", mtx, pnrow, pnent, psizes, pindices, pentries, mtx->mode) ; exit(-1) ; } *pnrow = mtx->nrow ; *pnent = mtx->nent ; dbuffer = mtx->wrkDV.vec ; ibuffer = (int *) dbuffer ; nint = 7 + mtx->nrow + mtx->ncol ; *psizes = ibuffer + nint ; nint += mtx->nrow ; *pindices = ibuffer + nint ; nint += mtx->nent ; if ( sizeof(int) == sizeof(double) ) { *pentries = dbuffer + nint ; } else if ( 2*sizeof(int) == sizeof(double) ) { *pentries = dbuffer + (nint+1)/2 ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- for sparse columns, fill *pncol with # of columns *pnent with # of matrix entries *psizes with sizes[ncol], column sizes *pindices with indices[nent], matrix row ids *pentries with entries[nent], matrix entries created -- 98may01, cca ---------------------------------------------- */ void SubMtx_sparseColumnsInfo ( SubMtx *mtx, int *pncol, int *pnent, int **psizes, int **pindices, double **pentries ) { double *dbuffer ; int nint ; int *ibuffer ; /* --------------- check the input --------------- */ if ( mtx == NULL || pncol == NULL || pnent == NULL || psizes == NULL || pindices == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_sparseColumnsInfo(%p,%p,%p,%p,%p,%p)" "\n bad input\n", mtx, pncol, pnent, psizes, pindices, pentries) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtx) || SUBMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_sparseColumnsInfo(%p,%p,%p,%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, pncol, pnent, psizes, pindices, pentries, mtx->type) ; exit(-1) ; } if ( ! SUBMTX_IS_SPARSE_COLUMNS(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_sparseColumnsInfo(%p,%p,%p,%p,%p,%p)" "\n bad mode %d" "\n must be SUBMTX_SPARSE_COLUMNS\n", mtx, pncol, pnent, psizes, pindices, pentries, mtx->mode) ; exit(-1) ; } *pncol = mtx->ncol ; *pnent = mtx->nent ; dbuffer = mtx->wrkDV.vec ; ibuffer = (int *) dbuffer ; nint = 7 + mtx->nrow + mtx->ncol ; *psizes = ibuffer + nint ; nint += mtx->ncol ; *pindices = ibuffer + nint ; nint += mtx->nent ; if ( sizeof(int) == sizeof(double) ) { *pentries = dbuffer + nint ; } else if ( 2*sizeof(int) == sizeof(double) ) { *pentries = dbuffer + (nint+1)/2 ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- for sparse triples, fill *pnent with # of matrix entries *prowids with rowids[nent], row ids of entries *prowids with colids[nent], column ids of entries *pentries with entries[nent], matrix entries created -- 98may01, cca ---------------------------------------------------- */ void SubMtx_sparseTriplesInfo ( SubMtx *mtx, int *pnent, int **prowids, int **pcolids, double **pentries ) { double *dbuffer ; int nint ; int *ibuffer ; /* --------------- check the input --------------- */ if ( mtx == NULL || pnent == NULL || prowids == NULL || pcolids == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_sparseTriplesInfo(%p,%p,%p,%p,%p)" "\n bad input\n", mtx, pnent, prowids, pcolids, pentries) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtx) || SUBMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_sparseTriplesInfo(%p,%p,%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, pnent, prowids, pcolids, pentries, mtx->type) ; exit(-1) ; } if ( ! SUBMTX_IS_SPARSE_TRIPLES(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_sparseTriplesInfo(%p,%p,%p,%p,%p)" "\n bad mode %d" "\n must be SUBMTX_SPARSE_TRIPLES\n", mtx, pnent, prowids, pcolids, pentries, mtx->mode) ; exit(-1) ; } *pnent = mtx->nent ; dbuffer = mtx->wrkDV.vec ; ibuffer = (int *) dbuffer ; nint = 7 + mtx->nrow + mtx->ncol ; *prowids = ibuffer + nint ; nint += mtx->nent ; *pcolids = ibuffer + nint ; nint += mtx->nent ; if ( sizeof(int) == sizeof(double) ) { *pentries = dbuffer + nint ; } else if ( 2*sizeof(int) == sizeof(double) ) { *pentries = dbuffer + (nint+1)/2 ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- for dense subrows, fill *pnrow with # of rows *pnent with # of matrix entries *pfirstlocs with firstlocs[nrow], column of first nonzero *psizes with sizes[nrow], number of nonzero columns *pentries with entries[nent], matrix entries created -- 98may01, cca ----------------------------------------------------------- */ void SubMtx_denseSubrowsInfo ( SubMtx *mtx, int *pnrow, int *pnent, int **pfirstlocs, int **psizes, double **pentries ) { double *dbuffer ; int nint ; int *ibuffer ; /* --------------- check the input --------------- */ if ( mtx == NULL || pnrow == NULL || pnent == NULL || pfirstlocs == NULL || psizes == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_denseSubrowsInfo(%p,%p,%p,%p,%p,%p)" "\n bad input\n", mtx, pnrow, pnent, pfirstlocs, psizes, pentries) ; if ( mtx != NULL ) { SubMtx_writeForHumanEye(mtx, stderr) ; } exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtx) || SUBMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_denseSubrowsInfo(%p,%p,%p,%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, pnrow, pnent, pfirstlocs, psizes, pentries, mtx->type) ; exit(-1) ; } if ( ! SUBMTX_IS_DENSE_SUBROWS(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_denseSubrowsInfo(%p,%p,%p,%p,%p,%p)" "\n bad mode %d" "\n must be SUBMTX_DENSE_SUBROWS\n", mtx, pnrow, pnent, pfirstlocs, psizes, pentries, mtx->mode) ; exit(-1) ; } *pnrow = mtx->nrow ; *pnent = mtx->nent ; dbuffer = mtx->wrkDV.vec ; ibuffer = (int *) dbuffer ; nint = 7 + mtx->nrow + mtx->ncol ; *pfirstlocs = ibuffer + nint ; nint += mtx->nrow ; *psizes = ibuffer + nint ; nint += mtx->nrow ; if ( sizeof(int) == sizeof(double) ) { *pentries = dbuffer + nint ; } else if ( 2*sizeof(int) == sizeof(double) ) { *pentries = dbuffer + (nint+1)/2 ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- for dense subcolumns, fill *pncol with # of columns *pnent with # of matrix entries *pfirstlocs with firstlocs[ncol], row of first nonzero *psizes with sizes[ncol], number of nonzero rows *pentries with entries[nent], matrix entries created -- 98may01, cca ----------------------------------------------------------- */ void SubMtx_denseSubcolumnsInfo ( SubMtx *mtx, int *pncol, int *pnent, int **pfirstlocs, int **psizes, double **pentries ) { double *dbuffer ; int nint ; int *ibuffer ; /* --------------- check the input --------------- */ if ( mtx == NULL || pfirstlocs == NULL || psizes == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_denseSubcolumnsInfo(%p,%p,%p,%p,%p,%p)" "\n bad input\n", mtx, pncol, pnent, pfirstlocs, psizes, pentries) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtx) || SUBMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_denseSubcolumsInfo(%p,%p,%p,%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, pncol, pnent, pfirstlocs, psizes, pentries, mtx->type) ; exit(-1) ; } if ( ! SUBMTX_IS_DENSE_SUBCOLUMNS(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_denseSubcolumnsInfo(%p,%p,%p,%p,%p,%p)" "\n bad mode %d" "\n must be SUBMTX_DENSE_SUBCOLUMNS\n", mtx, pncol, pnent, pfirstlocs, psizes, pentries, mtx->mode) ; exit(-1) ; } *pncol = mtx->ncol ; *pnent = mtx->nent ; dbuffer = mtx->wrkDV.vec ; ibuffer = (int *) dbuffer ; nint = 7 + mtx->nrow + mtx->ncol ; *pfirstlocs = ibuffer + nint ; nint += mtx->ncol ; *psizes = ibuffer + nint ; nint += mtx->ncol ; if ( sizeof(int) == sizeof(double) ) { *pentries = dbuffer + nint ; } else if ( 2*sizeof(int) == sizeof(double) ) { *pentries = dbuffer + (nint+1)/2 ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- for a diagonal matrix, fill *pncol with # of columns *pentries with entries[nent], matrix entries created -- 98may01, cca ------------------------------------------------ */ void SubMtx_diagonalInfo ( SubMtx *mtx, int *pncol, double **pentries ) { double *dbuffer ; int nint ; int *ibuffer ; /* --------------- check the input --------------- */ if ( mtx == NULL || pncol == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_diagonalInfo(%p,%p,%p)" "\n bad input\n", mtx, pncol, pentries) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtx) || SUBMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_diagonalInfo(%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, pncol, pentries, mtx->type) ; exit(-1) ; } if ( ! SUBMTX_IS_DIAGONAL(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_diagonalInfo(%p,%p,%p)" "\n bad mode %d" "\n must be SUBMTX_DIAGONAL\n", mtx, pncol, pentries, mtx->mode) ; exit(-1) ; } *pncol = mtx->ncol ; dbuffer = mtx->wrkDV.vec ; ibuffer = (int *) dbuffer ; nint = 7 + mtx->nrow + mtx->ncol ; if ( sizeof(int) == sizeof(double) ) { *pentries = dbuffer + nint ; } else if ( 2*sizeof(int) == sizeof(double) ) { *pentries = dbuffer + (nint+1)/2 ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- for a block diagonal symmetric matrix, fill *pncol with # of columns *pnent with # of entries *ppivotsizes with pivotsizes[ncol] *pentries with entries[nent], matrix entries created -- 98may01, cca ------------------------------------------------------ */ void SubMtx_blockDiagonalInfo ( SubMtx *mtx, int *pncol, int *pnent, int **ppivotsizes, double **pentries ) { double *dbuffer ; int nint ; int *ibuffer ; /* --------------- check the input --------------- */ if ( mtx == NULL || pncol == NULL || pnent == NULL || ppivotsizes == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_blockDiagonalInfo(%p,%p,%p,%p,%p)" "\n bad input\n", mtx, pncol, pnent, ppivotsizes, pentries) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtx) || SUBMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_blockDiagonalInfo(%p,%p,%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, pncol, pnent, ppivotsizes, pentries, mtx->type) ; exit(-1) ; } if ( ! (SUBMTX_IS_BLOCK_DIAGONAL_SYM(mtx) || SUBMTX_IS_BLOCK_DIAGONAL_HERM(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_blockDiagonalInfo(%p,%p,%p,%p,%p)" "\n bad mode %d" "\n must be SUBMTX_BLOCK_DIAGONAL_SYM or SUBMTX_BLOCK_DIAGONAL_HERM \n", mtx, pncol, pnent, ppivotsizes, pentries, mtx->mode) ; exit(-1) ; } *pncol = mtx->ncol ; *pnent = mtx->nent ; dbuffer = mtx->wrkDV.vec ; ibuffer = (int *) dbuffer ; nint = 7 + 2*mtx->nrow ; *ppivotsizes = ibuffer + nint ; nint += mtx->nrow ; if ( sizeof(int) == sizeof(double) ) { *pentries = dbuffer + nint ; } else if ( 2*sizeof(int) == sizeof(double) ) { *pentries = dbuffer + (nint+1)/2 ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to find matrix entry (irow,jcol) if present. return value -- if entry (irow,jcol) is not present then *pValue is 0.0 return value is -1 else entry (irow,jcol) is present then *pValue is the matrix entry return value is offset into entries array endif created -- 98may01, cca ------------------------------------------------------- */ int SubMtx_realEntry ( SubMtx *mtx, int irow, int jcol, double *pValue ) { /* --------------- check the input --------------- */ if ( mtx == NULL || irow < 0 || irow >= mtx->nrow || jcol < 0 || jcol >= mtx->ncol || pValue == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_realEntry(%p,%d,%d,%p)" "\n bad input\n", mtx, irow, jcol, pValue) ; exit(-1) ; } if ( ! SUBMTX_IS_REAL(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_realEntry(%p,%d,%d,%p)" "\n bad type %d, must be SPOOLES_REAL\n", mtx, irow, jcol, pValue, mtx->type) ; exit(-1) ; } *pValue = 0 ; switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { double *entries ; int inc1, inc2, ncol, nrow, offset ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; if ( irow < 0 || irow >= nrow || jcol < 0 || jcol >= ncol ) { return(-1) ; } offset = irow*inc1 + jcol*inc2 ; *pValue = entries[offset] ; return(offset) ; } break ; case SUBMTX_SPARSE_ROWS : { double *entries ; int ii, jj, nent, nrow, offset, *indices, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; if ( irow < 0 || irow >= nrow ) { return(-1) ; } for ( ii = offset = 0 ; ii < irow ; ii++ ) { offset += sizes[ii] ; } for ( ii = 0, jj = offset ; ii < sizes[irow] ; ii++, jj++ ) { if ( indices[jj] == jcol ) { *pValue = entries[jj] ; return(jj) ; } } return(-1) ; } break ; case SUBMTX_SPARSE_COLUMNS : { double *entries ; int ii, jj, nent, ncol, offset, *indices, *sizes ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; if ( jcol < 0 || jcol >= ncol ) { return(-1) ; } for ( ii = offset = 0 ; ii < jcol ; ii++ ) { offset += sizes[ii] ; } for ( ii = 0, jj = offset ; ii < sizes[jcol] ; ii++, jj++ ) { if ( indices[jj] == irow ) { *pValue = entries[jj] ; return(jj) ; } } return(-1) ; } break ; case SUBMTX_SPARSE_TRIPLES : { double *entries ; int ii, nent, *colids, *rowids ; SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; for ( ii = 0 ; ii < nent ; ii++ ) { if ( irow == rowids[ii] && jcol == colids[ii] ) { *pValue = entries[ii] ; return(ii) ; } } return(-1) ; } break ; case SUBMTX_DENSE_SUBROWS : { double *entries ; int ii, joff, nent, nrow, offset, *firstlocs, *sizes ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; if ( irow < 0 || irow >= nrow || sizes[irow] == 0 ) { return(-1) ; } for ( ii = offset = 0 ; ii < irow ; ii++ ) { offset += sizes[ii] ; } if ( 0 <= (joff = jcol - firstlocs[irow]) && joff < sizes[irow] ) { offset += joff ; *pValue = entries[offset] ; return(offset) ; } return(-1) ; } break ; case SUBMTX_DENSE_SUBCOLUMNS : { double *entries ; int ii, ioff, nent, ncol, offset, *firstlocs, *sizes ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; if ( jcol < 0 || jcol >= ncol || sizes[jcol] == 0 ) { return(-1) ; } for ( ii = offset = 0 ; ii < jcol ; ii++ ) { offset += sizes[ii] ; } if ( 0 <= (ioff = irow - firstlocs[jcol]) && ioff < sizes[jcol] ) { offset += ioff ; *pValue = entries[offset] ; return(offset) ; } return(-1) ; } break ; case SUBMTX_DIAGONAL : { double *entries ; int ncol ; if ( irow < 0 || jcol < 0 || irow != jcol ) { return(-1) ; } SubMtx_diagonalInfo(mtx, &ncol, &entries) ; if ( irow >= ncol || jcol >= ncol ) { return(-1) ; } *pValue = entries[irow] ; return(irow) ; } break ; case SUBMTX_BLOCK_DIAGONAL_SYM : { double *entries ; int ii, ipivot, jrow, kk, m, ncol, nent, size ; int *pivotsizes ; if ( irow < 0 || jcol < 0 ) { return(-1) ; } if ( irow > jcol ) { ii = irow ; irow = jcol ; jcol = ii ; } SubMtx_blockDiagonalInfo(mtx, &ncol, &nent, &pivotsizes, &entries) ; if ( irow >= ncol || jcol >= ncol ) { return(-1) ; } for ( jrow = ipivot = kk = 0 ; jrow <= irow ; ipivot++ ) { size = m = pivotsizes[ipivot] ; for ( ii = 0 ; ii < m ; ii++, jrow++ ) { if ( jrow == irow ) { if ( jcol - irow > m - ii - 1 ) { return(-1) ; } else { kk += jcol - irow ; *pValue = entries[kk] ; return(kk) ; } } else { kk += size-- ; } } } return(kk) ; } break ; case SUBMTX_BLOCK_DIAGONAL_HERM : { double sign ; double *entries ; int ii, ipivot, jrow, kk, m, ncol, nent, size ; int *pivotsizes ; if ( irow < 0 || jcol < 0 ) { return(-1) ; } if ( irow > jcol ) { ii = irow ; irow = jcol ; jcol = ii ; sign = -1.0 ; } else { sign = 1.0 ; } SubMtx_blockDiagonalInfo(mtx, &ncol, &nent, &pivotsizes, &entries) ; if ( irow >= ncol || jcol >= ncol ) { return(-1) ; } for ( jrow = ipivot = kk = 0 ; jrow <= irow ; ipivot++ ) { size = m = pivotsizes[ipivot] ; for ( ii = 0 ; ii < m ; ii++, jrow++ ) { if ( jrow == irow ) { if ( jcol - irow > m - ii - 1 ) { return(-1) ; } else { kk += jcol - irow ; *pValue = entries[kk] ; return(kk) ; } } else { kk += size-- ; } } } return(kk) ; } break ; default : fprintf(stderr, "\n fatal error in SubMtx_realEntry(%p,%d,%d,%p)" "\n bad mode %d", mtx, irow, jcol, pValue, mtx->mode) ; exit(-1) ; break ; } return(-1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to find matrix entry (irow,jcol) if present. return value -- if entry (irow,jcol) is not present then *pReal and *pImag are 0.0 return value is -1 else entry (irow,jcol) is present then (*pReal,*pImag) is the matrix entry return value is offset into entries array endif created -- 98may01, cca ------------------------------------------------------- */ int SubMtx_complexEntry ( SubMtx *mtx, int irow, int jcol, double *pReal, double *pImag ) { /* --------------- check the input --------------- */ if ( mtx == NULL || irow < 0 || irow >= mtx->nrow || jcol < 0 || jcol >= mtx->ncol || pReal == NULL || pImag == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_complexEntry(%p,%d,%d,%p,%p)" "\n bad input\n", mtx, irow, jcol, pReal, pImag) ; exit(-1) ; } if ( ! SUBMTX_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_complexEntry(%p,%d,%d,%p,%p)" "\n bad type %d, must be SPOOLES_COMPLEX\n", mtx, irow, jcol, pReal, pImag, mtx->type) ; exit(-1) ; } *pReal = *pImag = 0 ; switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { double *entries ; int inc1, inc2, ncol, nrow, offset ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; if ( irow < 0 || irow >= nrow || jcol < 0 || jcol >= ncol ) { return(-1) ; } offset = irow*inc1 + jcol*inc2 ; *pReal = entries[2*offset] ; *pImag = entries[2*offset+1] ; return(offset) ; } break ; case SUBMTX_SPARSE_ROWS : { double *entries ; int ii, jj, nent, nrow, offset, *indices, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; if ( irow < 0 || irow >= nrow ) { return(-1) ; } for ( ii = offset = 0 ; ii < irow ; ii++ ) { offset += sizes[ii] ; } for ( ii = 0, jj = offset ; ii < sizes[irow] ; ii++, jj++ ) { if ( indices[jj] == jcol ) { *pReal = entries[2*jj] ; *pImag = entries[2*jj+1] ; return(jj) ; } } return(-1) ; } break ; case SUBMTX_SPARSE_COLUMNS : { double *entries ; int ii, jj, nent, ncol, offset, *indices, *sizes ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; if ( jcol < 0 || jcol >= ncol ) { return(-1) ; } for ( ii = offset = 0 ; ii < jcol ; ii++ ) { offset += sizes[ii] ; } for ( ii = 0, jj = offset ; ii < sizes[jcol] ; ii++, jj++ ) { if ( indices[jj] == irow ) { *pReal = entries[2*jj] ; *pImag = entries[2*jj+1] ; return(jj) ; } } return(-1) ; } break ; case SUBMTX_SPARSE_TRIPLES : { double *entries ; int ii, nent, *colids, *rowids ; SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; for ( ii = 0 ; ii < nent ; ii++ ) { if ( irow == rowids[ii] && jcol == colids[ii] ) { *pReal = entries[2*ii] ; *pImag = entries[2*ii+1] ; return(ii) ; } } return(-1) ; } break ; case SUBMTX_DENSE_SUBROWS : { double *entries ; int ii, joff, nent, nrow, offset, *firstlocs, *sizes ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; if ( irow < 0 || irow >= nrow || sizes[irow] == 0 ) { return(-1) ; } for ( ii = offset = 0 ; ii < irow ; ii++ ) { offset += sizes[ii] ; } if ( 0 <= (joff = jcol - firstlocs[irow]) && joff < sizes[irow] ) { offset += joff ; *pReal = entries[2*offset] ; *pImag = entries[2*offset+1] ; return(offset) ; } return(-1) ; } break ; case SUBMTX_DENSE_SUBCOLUMNS : { double *entries ; int ii, ioff, nent, ncol, offset, *firstlocs, *sizes ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; if ( jcol < 0 || jcol >= ncol || sizes[jcol] == 0 ) { return(-1) ; } for ( ii = offset = 0 ; ii < jcol ; ii++ ) { offset += sizes[ii] ; } if ( 0 <= (ioff = irow - firstlocs[jcol]) && ioff < sizes[jcol] ) { offset += ioff ; *pReal = entries[2*offset] ; *pImag = entries[2*offset+1] ; return(offset) ; } return(-1) ; } break ; case SUBMTX_DIAGONAL : { double *entries ; int ncol ; if ( irow < 0 || jcol < 0 || irow != jcol ) { return(-1) ; } SubMtx_diagonalInfo(mtx, &ncol, &entries) ; if ( irow >= ncol || jcol >= ncol ) { return(-1) ; } *pReal = entries[2*irow] ; *pImag = entries[2*irow+1] ; return(irow) ; } break ; case SUBMTX_BLOCK_DIAGONAL_SYM : { double *entries ; int ii, ipivot, jrow, kk, m, ncol, nent, size ; int *pivotsizes ; if ( irow < 0 || jcol < 0 ) { return(-1) ; } if ( irow > jcol ) { ii = irow ; irow = jcol ; jcol = ii ; } SubMtx_blockDiagonalInfo(mtx, &ncol, &nent, &pivotsizes, &entries) ; if ( irow >= ncol || jcol >= ncol ) { return(-1) ; } for ( jrow = ipivot = kk = 0 ; jrow <= irow ; ipivot++ ) { size = m = pivotsizes[ipivot] ; for ( ii = 0 ; ii < m ; ii++, jrow++ ) { if ( jrow == irow ) { if ( jcol - irow > m - ii - 1 ) { return(-1) ; } else { kk += jcol - irow ; *pReal = entries[2*kk] ; *pImag = entries[2*kk+1] ; return(kk) ; } } else { kk += size-- ; } } } return(kk) ; } break ; case SUBMTX_BLOCK_DIAGONAL_HERM : { double sign ; double *entries ; int ii, ipivot, jrow, kk, m, ncol, nent, size ; int *pivotsizes ; if ( irow < 0 || jcol < 0 ) { return(-1) ; } if ( irow > jcol ) { ii = irow ; irow = jcol ; jcol = ii ; sign = -1.0 ; } else { sign = 1.0 ; } SubMtx_blockDiagonalInfo(mtx, &ncol, &nent, &pivotsizes, &entries) ; if ( irow >= ncol || jcol >= ncol ) { return(-1) ; } for ( jrow = ipivot = kk = 0 ; jrow <= irow ; ipivot++ ) { size = m = pivotsizes[ipivot] ; for ( ii = 0 ; ii < m ; ii++, jrow++ ) { if ( jrow == irow ) { if ( jcol - irow > m - ii - 1 ) { return(-1) ; } else { kk += jcol - irow ; *pReal = entries[2*kk] ; *pImag = sign*entries[2*kk+1] ; return(kk) ; } } else { kk += size-- ; } } } return(kk) ; } break ; default : fprintf(stderr, "\n fatal error in SubMtx_complexEntry(%p,%d,%d,%p,%p)" "\n bad mode %d", mtx, irow, jcol, pReal, pImag, mtx->mode) ; exit(-1) ; break ; } return(-1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to return a pointer to the location of matrix entry (irow,jcol) if present. if entry (irow,jcol) is not present then *ppValue is NULL else entry (irow,jcol) is present then *ppValue is the location of the matrix entry endif created -- 98may01, cca ------------------------------------------------- */ void SubMtx_locationOfRealEntry ( SubMtx *mtx, int irow, int jcol, double **ppValue ) { /* --------------- check the input --------------- */ if ( mtx == NULL || irow < 0 || irow >= mtx->nrow || jcol < 0 || jcol >= mtx->ncol || ppValue == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_locationOfRealEntry(%p,%d,%d,%p)" "\n bad input\n", mtx, irow, jcol, ppValue) ; exit(-1) ; } if ( ! SUBMTX_IS_REAL(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_locationOfRealEntry(%p,%d,%d,%p)" "\n bad type %d, must be SPOOLES_REAL\n", mtx, irow, jcol, ppValue, mtx->type) ; exit(-1) ; } *ppValue = NULL ; switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { double *entries ; int inc1, inc2, ncol, nrow, offset ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; if ( irow >= 0 && irow < nrow && jcol >= 0 && jcol < ncol ) { offset = irow*inc1 + jcol*inc2 ; *ppValue = entries + offset ; } } break ; case SUBMTX_SPARSE_ROWS : { double *entries ; int ii, jj, nent, nrow, offset, *indices, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries); if ( irow >= 0 && irow < nrow ) { for ( ii = offset = 0 ; ii < irow ; ii++ ) { offset += sizes[ii] ; } for ( ii = 0, jj = offset ; ii < sizes[irow] ; ii++, jj++ ) { if ( indices[jj] == jcol ) { *ppValue = entries + jj ; break ; } } } } break ; case SUBMTX_SPARSE_COLUMNS : { double *entries ; int ii, jj, nent, ncol, offset, *indices, *sizes ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; if ( jcol >= 0 && jcol < ncol ) { for ( ii = offset = 0 ; ii < jcol ; ii++ ) { offset += sizes[ii] ; } for ( ii = 0, jj = offset ; ii < sizes[jcol] ; ii++, jj++ ) { if ( indices[jj] == irow ) { *ppValue = entries + jj ; break ; } } } } break ; case SUBMTX_SPARSE_TRIPLES : { double *entries ; int ii, nent, *colids, *rowids ; SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; for ( ii = 0 ; ii < nent ; ii++ ) { if ( irow == rowids[ii] && jcol == colids[ii] ) { *ppValue = entries + ii ; break ; } } } break ; case SUBMTX_DENSE_SUBROWS : { double *entries ; int ii, joff, nent, nrow, offset, *firstlocs, *sizes ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; if ( irow >= 0 && irow < nrow && sizes[irow] != 0 ) { for ( ii = offset = 0 ; ii < irow ; ii++ ) { offset += sizes[ii] ; } if ( 0 <= (joff = jcol - firstlocs[irow]) && joff < sizes[irow] ) { offset += joff ; *ppValue = entries + offset ; break ; } } } break ; case SUBMTX_DENSE_SUBCOLUMNS : { double *entries ; int ii, ioff, nent, ncol, offset, *firstlocs, *sizes ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; if ( jcol >= 0 && jcol < ncol && sizes[jcol] != 0 ) { for ( ii = offset = 0 ; ii < jcol ; ii++ ) { offset += sizes[jcol] ; } if ( 0 <= (ioff = irow - firstlocs[jcol]) && ioff < sizes[jcol] ) { offset += ioff ; *ppValue = entries + offset ; break ; } } } break ; case SUBMTX_DIAGONAL : { double *entries ; int ncol ; if ( irow >= 0 && jcol >= 0 && irow == jcol ) { SubMtx_diagonalInfo(mtx, &ncol, &entries) ; if ( irow < ncol && jcol < ncol ) { *ppValue = entries + irow ; } } } break ; case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : { double *entries ; int ii, ipivot, jrow, kk, m, ncol, nent, size ; int *pivotsizes ; if ( irow >= 0 && jcol >= 0 ) { SubMtx_blockDiagonalInfo(mtx, &ncol, &nent, &pivotsizes, &entries) ; if ( irow < ncol && jcol < ncol ) { for ( jrow = ipivot = kk = 0 ; jrow <= irow ; ipivot++ ) { size = m = pivotsizes[ipivot] ; for ( ii = 0 ; ii < m ; ii++, jrow++ ) { if ( jrow == irow ) { if ( jrow - irow > m - ii ) { kk = -1 ; } else { kk += jrow - irow ; } } else { kk += size-- ; } } } if ( kk != -1 ) { *ppValue = entries + kk ; } } } } break ; default : fprintf(stderr, "\n fatal error in SubMtx_locationOfRealEntry(%p,%d,%d,%p)" "\n bad mode %d", mtx, irow, jcol, ppValue, mtx->mode) ; exit(-1) ; break ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to return a pointer to the location of matrix entry (irow,jcol) if present. if entry (irow,jcol) is not present then (*ppReal,*ppImag) is (NULL,NULL) else entry (irow,jcol) is present then (*ppReal,*ppImag) is the location of the matrix entry endif created -- 98may01, cca -------------------------------------------------------- */ void SubMtx_locationOfComplexEntry ( SubMtx *mtx, int irow, int jcol, double **ppReal, double **ppImag ) { /* --------------- check the input --------------- */ if ( mtx == NULL || irow < 0 || irow >= mtx->nrow || jcol < 0 || jcol >= mtx->ncol || ppReal == NULL || ppImag == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_locationOfComplexEntry(%p,%d,%d,%p,%p)" "\n bad input\n", mtx, irow, jcol, ppReal, ppImag) ; exit(-1) ; } if ( ! SUBMTX_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_locationOfComplexEntry(%p,%d,%d,%p,%p)" "\n bad type %d, must be SPOOLES_COMPLEX\n", mtx, irow, jcol, ppReal, ppImag, mtx->type) ; exit(-1) ; } *ppReal = NULL ; *ppImag = NULL ; switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { double *entries ; int inc1, inc2, ncol, nrow, offset ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; if ( irow >= 0 && irow < nrow && jcol >= 0 && jcol < ncol ) { offset = irow*inc1 + jcol*inc2 ; *ppReal = entries + 2*offset ; *ppImag = entries + 2*offset + 1 ; } } break ; case SUBMTX_SPARSE_ROWS : { double *entries ; int ii, jj, nent, nrow, offset, *indices, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries); if ( irow >= 0 && irow < nrow ) { for ( ii = offset = 0 ; ii < irow ; ii++ ) { offset += sizes[ii] ; } for ( ii = 0, jj = offset ; ii < sizes[irow] ; ii++, jj++ ) { if ( indices[jj] == jcol ) { *ppReal = entries + 2*jj ; *ppImag = entries + 2*jj + 1 ; break ; } } } } break ; case SUBMTX_SPARSE_COLUMNS : { double *entries ; int ii, jj, nent, ncol, offset, *indices, *sizes ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; if ( jcol >= 0 && jcol < ncol ) { for ( ii = offset = 0 ; ii < jcol ; ii++ ) { offset += sizes[ii] ; } for ( ii = 0, jj = offset ; ii < sizes[jcol] ; ii++, jj++ ) { if ( indices[jj] == irow ) { *ppReal = entries + 2*jj ; *ppImag = entries + 2*jj + 1 ; break ; } } } } break ; case SUBMTX_SPARSE_TRIPLES : { double *entries ; int ii, nent, *colids, *rowids ; SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; for ( ii = 0 ; ii < nent ; ii++ ) { if ( irow == rowids[ii] && jcol == colids[ii] ) { *ppReal = entries + 2*ii ; *ppImag = entries + 2*ii + 1 ; break ; } } } break ; case SUBMTX_DENSE_SUBROWS : { double *entries ; int ii, joff, nent, nrow, offset, *firstlocs, *sizes ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; if ( irow >= 0 && irow < nrow && sizes[irow] != 0 ) { for ( ii = offset = 0 ; ii < irow ; ii++ ) { offset += sizes[ii] ; } if ( 0 <= (joff = jcol - firstlocs[irow]) && joff < sizes[irow] ) { offset += joff ; *ppReal = entries + 2*offset ; *ppImag = entries + 2*offset + 1 ; break ; } } } break ; case SUBMTX_DENSE_SUBCOLUMNS : { double *entries ; int ii, ioff, nent, ncol, offset, *firstlocs, *sizes ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; if ( jcol >= 0 && jcol < ncol && sizes[jcol] != 0 ) { for ( ii = offset = 0 ; ii < jcol ; ii++ ) { offset += sizes[jcol] ; } if ( 0 <= (ioff = irow - firstlocs[jcol]) && ioff < sizes[jcol] ) { offset += ioff ; *ppReal = entries + 2*offset ; *ppImag = entries + 2*offset + 1 ; break ; } } } break ; case SUBMTX_DIAGONAL : { double *entries ; int ncol ; if ( irow >= 0 && jcol >= 0 && irow == jcol ) { SubMtx_diagonalInfo(mtx, &ncol, &entries) ; if ( irow < ncol && jcol < ncol ) { *ppReal = entries + 2*irow ; *ppImag = entries + 2*irow + 1 ; } } } break ; case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : { double *entries ; int ii, ipivot, jrow, kk, m, ncol, nent, size ; int *pivotsizes ; if ( irow >= 0 && jcol >= 0 ) { SubMtx_blockDiagonalInfo(mtx, &ncol, &nent, &pivotsizes, &entries) ; if ( irow < ncol && jcol < ncol ) { for ( jrow = ipivot = kk = 0 ; jrow <= irow ; ipivot++ ) { size = m = pivotsizes[ipivot] ; for ( ii = 0 ; ii < m ; ii++, jrow++ ) { if ( jrow == irow ) { if ( jrow - irow > m - ii ) { kk = -1 ; } else { kk += jrow - irow ; } } else { kk += size-- ; } } } if ( kk != -1 ) { *ppReal = entries + 2*kk ; *ppImag = entries + 2*kk + 1 ; } } } } break ; default : fprintf(stderr, "\n fatal error in SubMtx_locationOfComplexEntry(%p,%d,%d,%p,%p)" "\n bad mode %d", mtx, irow, jcol, ppReal, ppImag, mtx->mode) ; exit(-1) ; break ; } return ; } /*--------------------------------------------------------------------*/ ffset ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; if ( irow >= 0 && irow < nrow && jcol >= 0 && jcol < ncol ) { offset = irow*inc1 + jcol*inc2 ; *ppValue = entries + offset ; } } break ; case SUBMTX_SPARSE_ROWS : { double *entries ; int ii, jj, nent, nrow, offset, *indices, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indiSubMtx/src/scalevec.c010064400020550007177000000710610653410625300160440ustar00clevecompmath00000400000006/* scalevec.c */ #include "../SubMtx.h" /*--------------------------------------------------------------------*/ static void diagonal_scale3vec ( SubMtx *mtxA, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[] ) ; static void diagonal_scale2vec ( SubMtx *mtxA, double y0[], double y1[], double x0[], double x1[] ) ; static void diagonal_scale1vec ( SubMtx *mtxA, double y0[], double x0[] ) ; static void block_diagonal_sym_scale3vec ( SubMtx *mtxA, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[] ) ; static void block_diagonal_sym_scale2vec ( SubMtx *mtxA, double y0[], double y1[], double x0[], double x1[] ) ; static void block_diagonal_sym_scale1vec ( SubMtx *mtxA, double y0[], double x0[] ) ; static void block_diagonal_herm_scale3vec ( SubMtx *mtxA, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[] ) ; static void block_diagonal_herm_scale2vec ( SubMtx *mtxA, double y0[], double y1[], double x0[], double x1[] ) ; static void block_diagonal_herm_scale1vec ( SubMtx *mtxA, double y0[], double x0[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- compute [y0] := A * [x0] created -- 98apr17, cca ----------------------------------- */ void SubMtx_scale1vec ( SubMtx *mtxA, double y0[], double x0[] ) { /* --------------- check the input --------------- */ if ( mtxA == NULL || y0 == NULL || x0 == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_scale1vec(%p,%p,%p)" "\n bad input\n", mtxA, y0, x0) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtxA) || SUBMTX_IS_COMPLEX(mtxA)) ) { fprintf(stderr, "\n fatal error in SubMtx_scale1vec(%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtxA, y0, x0, mtxA->type) ; exit(-1) ; } switch ( mtxA->mode ) { case SUBMTX_DIAGONAL : diagonal_scale1vec(mtxA, y0, x0) ; break ; case SUBMTX_BLOCK_DIAGONAL_SYM : block_diagonal_sym_scale1vec(mtxA, y0, x0) ; break ; case SUBMTX_BLOCK_DIAGONAL_HERM : if ( ! SUBMTX_IS_COMPLEX(mtxA) ) { fprintf(stderr, "\n fatal error in SubMtx_scale1vec(%p,%p,%p)" "\n hermitian matrix, type %d is not SPOOLES_COMPLEX\n", mtxA, y0, x0, mtxA->type) ; exit(-1) ; } block_diagonal_herm_scale1vec(mtxA, y0, x0) ; break ; default : fprintf(stderr, "\n fatal error in SubMtx_scale1vec()" "\n matrix mode not supported" "\n must be SUBMTX_DIAGONAL," "\n or SUBMTX_BLOCK_DIAGONAL_SYM" "\n or SUBMTX_BLOCK_DIAGONAL_HERM\n") ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- compute [y0 y1] := [x0 x1] created -- 98apr17, cca ------------------------------------- */ void SubMtx_scale2vec ( SubMtx *mtxA, double y0[], double y1[], double x0[], double x1[] ) { /* --------------- check the input --------------- */ if ( mtxA == NULL || y0 == NULL || y1 == NULL || x0 == NULL || x1 == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_scale2vec(%p,%p,%p,%p,%p)" "\n bad input\n", mtxA, y0, y1, x0, x1) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtxA) || SUBMTX_IS_COMPLEX(mtxA)) ) { fprintf(stderr, "\n fatal error in SubMtx_scale2vec(%p,%p,%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtxA, y0, y1, x0, x1, mtxA->type) ; exit(-1) ; } switch ( mtxA->mode ) { case SUBMTX_DIAGONAL : diagonal_scale2vec(mtxA, y0, y1, x0, x1) ; break ; case SUBMTX_BLOCK_DIAGONAL_SYM : block_diagonal_sym_scale2vec(mtxA, y0, y1, x0, x1) ; break ; case SUBMTX_BLOCK_DIAGONAL_HERM : if ( ! SUBMTX_IS_COMPLEX(mtxA) ) { fprintf(stderr, "\n fatal error in SubMtx_scale2vec(%p,%p,%p,%p,%p)" "\n hermitian matrix, type %d is not SPOOLES_COMPLEX\n", mtxA, y0, y1, x0, x1, mtxA->type) ; exit(-1) ; } block_diagonal_herm_scale2vec(mtxA, y0, y1, x0, x1) ; break ; default : fprintf(stderr, "\n fatal error in SubMtx_scale2vec()" "\n matrix type not supported" "\n must be SUBMTX_DIAGONAL," "\n or SUBMTX_BLOCK_DIAGONAL_SYM" "\n or SUBMTX_BLOCK_DIAGONAL_HERM\n") ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- compute [y0 y1 y2] := A * [x0 x1 x2] created -- 98apr17, cca ----------------------------------------------- */ void SubMtx_scale3vec ( SubMtx *mtxA, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[] ) { /* --------------- check the input --------------- */ if ( mtxA == NULL || y0 == NULL || y1 == NULL || y2 == NULL || x0 == NULL || x1 == NULL || x2 == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_scale3vec(%p,%p,%p,%p,%p,%p,%p)" "\n bad input\n", mtxA, y0, y1, y2, x0, x1, x2) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtxA) || SUBMTX_IS_COMPLEX(mtxA)) ) { fprintf(stderr, "\n fatal error in SubMtx_scale3vec(%p,%p,%p,%p,%p,%p,%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtxA, y0, y1, y2, x0, x1, x2, mtxA->type) ; exit(-1) ; } switch ( mtxA->mode ) { case SUBMTX_DIAGONAL : diagonal_scale3vec(mtxA, y0, y1, y2, x0, x1, x2) ; break ; case SUBMTX_BLOCK_DIAGONAL_SYM : block_diagonal_sym_scale3vec(mtxA, y0, y1, y2, x0, x1, x2) ; break ; case SUBMTX_BLOCK_DIAGONAL_HERM : if ( ! SUBMTX_IS_COMPLEX(mtxA) ) { fprintf(stderr, "\n fatal error in SubMtx_scale3vec(%p,%p,%p,%p,%p,%p,%p)" "\n hermitian matrix, type %d is not SPOOLES_COMPLEX\n", mtxA, y0, y1, y2, x0, x1, x2, mtxA->type) ; exit(-1) ; } block_diagonal_herm_scale3vec(mtxA, y0, y1, y2, x0, x1, x2) ; break ; default : fprintf(stderr, "\n fatal error in SubMtx_scale3vec()" "\n matrix type not supported" "\n must be SUBMTX_DIAGONAL," "\n or SUBMTX_BLOCK_DIAGONAL_SYM" "\n or SUBMTX_BLOCK_DIAGONAL_HERM\n") ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- compute [y0 y1 y2] := A * [x0 x1 x2] where A is diagonal created -- 98apr17, cca ----------------------------------------------- */ static void diagonal_scale3vec ( SubMtx *mtxA, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[] ) { double *entriesA ; int nrowA ; SubMtx_diagonalInfo(mtxA, &nrowA, &entriesA) ; if ( SUBMTX_IS_REAL(mtxA) ) { double a ; int irowA ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { a = entriesA[irowA] ; y0[irowA] = a*x0[irowA] ; y1[irowA] = a*x1[irowA] ; y2[irowA] = a*x2[irowA] ; } } else if ( SUBMTX_IS_COMPLEX(mtxA) ) { double ai, ar, xi0, xi1, xi2, xr0, xr1, xr2 ; int iloc, irowA, rloc ; for ( irowA = rloc = 0, iloc = 1 ; irowA < nrowA ; irowA++, rloc += 2, iloc += 2 ) { xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; xr2 = x2[rloc] ; xi2 = x2[iloc] ; ar = entriesA[rloc] ; ai = entriesA[iloc] ; y0[rloc] = ar*xr0 - ai*xi0 ; y0[iloc] = ar*xi0 + ai*xr0 ; y1[rloc] = ar*xr1 - ai*xi1 ; y1[iloc] = ar*xi1 + ai*xr1 ; y2[rloc] = ar*xr2 - ai*xi2 ; y2[iloc] = ar*xi2 + ai*xr2 ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute [y0 y1] := A * [x0 x1] where A is diagonal created -- 98apr17, cca ----------------------------------------- */ static void diagonal_scale2vec ( SubMtx *mtxA, double y0[], double y1[], double x0[], double x1[] ) { double *entriesA ; int nrowA ; SubMtx_diagonalInfo(mtxA, &nrowA, &entriesA) ; if ( SUBMTX_IS_REAL(mtxA) ) { double a ; int irowA ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { a = entriesA[irowA] ; y0[irowA] = a*x0[irowA] ; y1[irowA] = a*x1[irowA] ; } } else if ( SUBMTX_IS_COMPLEX(mtxA) ) { double ai, ar, xi0, xi1, xr0, xr1 ; int iloc, irowA, rloc ; for ( irowA = rloc = 0, iloc = 1 ; irowA < nrowA ; irowA++, rloc += 2, iloc += 2 ) { xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; ar = entriesA[rloc] ; ai = entriesA[iloc] ; y0[rloc] = ar*xr0 - ai*xi0 ; y0[iloc] = ar*xi0 + ai*xr0 ; y1[rloc] = ar*xr1 - ai*xi1 ; y1[iloc] = ar*xi1 + ai*xr1 ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- compute [y0] := A * [x0] where A is diagonal created -- 98apr17, cca ----------------------------------- */ static void diagonal_scale1vec ( SubMtx *mtxA, double y0[], double x0[] ) { double *entriesA ; int nrowA ; SubMtx_diagonalInfo(mtxA, &nrowA, &entriesA) ; if ( SUBMTX_IS_REAL(mtxA) ) { double a ; int irowA ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { a = entriesA[irowA] ; y0[irowA] = a*x0[irowA] ; } } else if ( SUBMTX_IS_COMPLEX(mtxA) ) { double ai, ar, xi0, xr0 ; int iloc, irowA, rloc ; for ( irowA = rloc = 0, iloc = 1 ; irowA < nrowA ; irowA++, rloc += 2, iloc += 2 ) { xr0 = x0[rloc] ; xi0 = x0[iloc] ; ar = entriesA[rloc] ; ai = entriesA[iloc] ; y0[rloc] = ar*xr0 - ai*xi0 ; y0[iloc] = ar*xi0 + ai*xr0 ; } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- compute [y0 y1 y2] := A * [x0 x1 x2] where A is block diagonal and symmetric created -- 98apr17, cca -------------------------------------------------- */ static void block_diagonal_sym_scale3vec ( SubMtx *mtxA, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[] ) { double *entries ; int nentA, nrowA ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtxA, &nrowA, &nentA, &pivotsizes, &entries) ; if ( SUBMTX_IS_REAL(mtxA) ) { int ipivot, irowA, kk ; for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { double a00, x00, x01, x02 ; a00 = entries[kk] ; x00 = x0[irowA] ; x01 = x1[irowA] ; x02 = x2[irowA] ; y0[irowA] = a00*x00 ; y1[irowA] = a00*x01 ; y2[irowA] = a00*x02 ; kk++, irowA++ ; } else if ( pivotsizes[ipivot] == 2 ) { double a00, a01, a11, x00, x01, x02, x10, x11, x12 ; a00 = entries[kk] ; a01 = entries[kk+1] ; a11 = entries[kk+2] ; x00 = x0[irowA] ; x01 = x1[irowA] ; x02 = x2[irowA] ; x10 = x0[irowA+1] ; x11 = x1[irowA+1] ; x12 = x2[irowA+1] ; y0[irowA] = a00*x00 + a01*x10 ; y1[irowA] = a00*x01 + a01*x11 ; y2[irowA] = a00*x02 + a01*x12 ; y0[irowA+1] = a01*x00 + a11*x10 ; y1[irowA+1] = a01*x01 + a11*x11 ; y2[irowA+1] = a01*x02 + a11*x12 ; kk += 3, irowA += 2 ; } else { fprintf(stderr, "\n fatal error in SubMtx_scale3vec()" "\n pivotsizes[%d] = %d", ipivot, pivotsizes[ipivot]) ; exit(-1) ; } } } else if ( SUBMTX_IS_COMPLEX(mtxA) ) { int iloc, ipivot, irowA, kk, rloc ; for ( irowA = ipivot = kk = rloc = 0, iloc = 1 ; irowA < nrowA ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { double ai00, ar00, xi0, xi1, xi2, xr0, xr1, xr2 ; ar00 = entries[kk] ; ai00 = entries[kk+1] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; xr2 = x2[rloc] ; xi2 = x2[iloc] ; y0[rloc] = ar00*xr0 - ai00*xi0; y0[iloc] = ar00*xi0 + ai00*xr0; y1[rloc] = ar00*xr1 - ai00*xi1; y1[iloc] = ar00*xi1 + ai00*xr1; y2[rloc] = ar00*xr2 - ai00*xi2; y2[iloc] = ar00*xi2 + ai00*xr2; kk += 2, irowA++, rloc += 2, iloc += 2 ; } else if ( pivotsizes[ipivot] == 2 ) { double ai00, ai01, ai11, ar00, ar01, ar11, xi00, xi01, xi02, xi10, xi11, xi12, xr00, xr01, xr02, xr10, xr11, xr12 ; int iloc0, iloc1, rloc0, rloc1 ; ar00 = entries[kk] ; ai00 = entries[kk+1] ; ar01 = entries[kk+2] ; ai01 = entries[kk+3] ; ar11 = entries[kk+4] ; ai11 = entries[kk+5] ; rloc0 = rloc ; iloc0 = iloc ; rloc1 = rloc + 2 ; iloc1 = iloc + 2 ; xr00 = x0[rloc0] ; xi00 = x0[iloc0] ; xr01 = x1[rloc0] ; xi01 = x1[iloc0] ; xr02 = x2[rloc0] ; xi02 = x2[iloc0] ; xr10 = x0[rloc1] ; xi10 = x0[iloc1] ; xr11 = x1[rloc1] ; xi11 = x1[iloc1] ; xr12 = x2[rloc1] ; xi12 = x2[iloc1] ; y0[rloc0] = ar00*xr00 - ai00*xi00 + ar01*xr10 - ai01*xi10 ; y0[iloc0] = ar00*xi00 + ai00*xr00 + ar01*xi10 + ai01*xr10 ; y1[rloc0] = ar00*xr01 - ai00*xi01 + ar01*xr11 - ai01*xi11 ; y1[iloc0] = ar00*xi01 + ai00*xr01 + ar01*xi11 + ai01*xr11 ; y2[rloc0] = ar00*xr02 - ai00*xi02 + ar01*xr12 - ai01*xi12 ; y2[iloc0] = ar00*xi02 + ai00*xr02 + ar01*xi12 + ai01*xr12 ; y0[rloc1] = ar01*xr00 - ai01*xi00 + ar11*xr10 - ai11*xi10 ; y0[iloc1] = ar01*xi00 + ai01*xr00 + ar11*xi10 + ai11*xr10 ; y1[rloc1] = ar01*xr01 - ai01*xi01 + ar11*xr11 - ai11*xi11 ; y1[iloc1] = ar01*xi01 + ai01*xr01 + ar11*xi11 + ai11*xr11 ; y2[rloc1] = ar01*xr02 - ai01*xi02 + ar11*xr12 - ai11*xi12 ; y2[iloc1] = ar01*xi02 + ai01*xr02 + ar11*xi12 + ai11*xr12 ; kk += 6, irowA += 2 ; rloc += 4 ; iloc += 4 ; } else { fprintf(stderr, "\n fatal error in SubMtx_scale3vec()" "\n pivotsizes[%d] = %d", ipivot, pivotsizes[ipivot]) ; exit(-1) ; } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- compute [y0 y1] := A * [x0 x1] where A is block diagonal and symmetric created -- 98apr17, cca -------------------------------------------------- */ static void block_diagonal_sym_scale2vec ( SubMtx *mtxA, double y0[], double y1[], double x0[], double x1[] ) { double *entries ; int nentA, nrowA ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtxA, &nrowA, &nentA, &pivotsizes, &entries) ; if ( SUBMTX_IS_REAL(mtxA) ) { int ipivot, irowA, kk ; for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { double a00, x00, x01 ; a00 = entries[kk] ; x00 = x0[irowA] ; x01 = x1[irowA] ; y0[irowA] = a00*x00 ; y1[irowA] = a00*x01 ; kk++, irowA++ ; } else if ( pivotsizes[ipivot] == 2 ) { double a00, a01, a11, x00, x01, x10, x11 ; a00 = entries[kk] ; a01 = entries[kk+1] ; a11 = entries[kk+2] ; x00 = x0[irowA] ; x01 = x1[irowA] ; x10 = x0[irowA+1] ; x11 = x1[irowA+1] ; y0[irowA] = a00*x00 + a01*x10 ; y1[irowA] = a00*x01 + a01*x11 ; y0[irowA+1] = a01*x00 + a11*x10 ; y1[irowA+1] = a01*x01 + a11*x11 ; kk += 3, irowA += 2 ; } else { fprintf(stderr, "\n fatal error in SubMtx_scale3vec()" "\n pivotsizes[%d] = %d", ipivot, pivotsizes[ipivot]) ; exit(-1) ; } } } else if ( SUBMTX_IS_COMPLEX(mtxA) ) { int iloc, ipivot, irowA, kk, rloc ; for ( irowA = ipivot = kk = rloc = 0, iloc = 1 ; irowA < nrowA ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { double ai00, ar00, xi0, xi1, xr0, xr1 ; ar00 = entries[kk] ; ai00 = entries[kk+1] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; y0[rloc] = ar00*xr0 - ai00*xi0; y0[iloc] = ar00*xi0 + ai00*xr0; y1[rloc] = ar00*xr1 - ai00*xi1; y1[iloc] = ar00*xi1 + ai00*xr1; kk += 2, irowA++, rloc += 2, iloc += 2 ; } else if ( pivotsizes[ipivot] == 2 ) { double ai00, ai01, ai11, ar00, ar01, ar11, xi00, xi01, xi10, xi11, xr00, xr01, xr10, xr11 ; int iloc0, iloc1, rloc0, rloc1 ; ar00 = entries[kk] ; ai00 = entries[kk+1] ; ar01 = entries[kk+2] ; ai01 = entries[kk+3] ; ar11 = entries[kk+4] ; ai11 = entries[kk+5] ; rloc0 = rloc ; iloc0 = iloc ; rloc1 = rloc + 2 ; iloc1 = iloc + 2 ; xr00 = x0[rloc0] ; xi00 = x0[iloc0] ; xr01 = x1[rloc0] ; xi01 = x1[iloc0] ; xr10 = x0[rloc1] ; xi10 = x0[iloc1] ; xr11 = x1[rloc1] ; xi11 = x1[iloc1] ; y0[rloc0] = ar00*xr00 - ai00*xi00 + ar01*xr10 - ai01*xi10 ; y0[iloc0] = ar00*xi00 + ai00*xr00 + ar01*xi10 + ai01*xr10 ; y1[rloc0] = ar00*xr01 - ai00*xi01 + ar01*xr11 - ai01*xi11 ; y1[iloc0] = ar00*xi01 + ai00*xr01 + ar01*xi11 + ai01*xr11 ; y0[rloc1] = ar01*xr00 - ai01*xi00 + ar11*xr10 - ai11*xi10 ; y0[iloc1] = ar01*xi00 + ai01*xr00 + ar11*xi10 + ai11*xr10 ; y1[rloc1] = ar01*xr01 - ai01*xi01 + ar11*xr11 - ai11*xi11 ; y1[iloc1] = ar01*xi01 + ai01*xr01 + ar11*xi11 + ai11*xr11 ; kk += 6, irowA += 2 ; rloc += 4 ; iloc += 4 ; } else { fprintf(stderr, "\n fatal error in SubMtx_scale2vec()" "\n pivotsizes[%d] = %d", ipivot, pivotsizes[ipivot]) ; exit(-1) ; } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- compute [y0] := A * [x0] where A is block diagonal and symmetric created -- 98apr17, cca -------------------------------------------------- */ static void block_diagonal_sym_scale1vec ( SubMtx *mtxA, double y0[], double x0[] ) { double *entries ; int nentA, nrowA ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtxA, &nrowA, &nentA, &pivotsizes, &entries) ; if ( SUBMTX_IS_REAL(mtxA) ) { int ipivot, irowA, kk ; for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { double a00, x00 ; a00 = entries[kk] ; x00 = x0[irowA] ; y0[irowA] = a00*x00 ; kk++, irowA++ ; } else if ( pivotsizes[ipivot] == 2 ) { double a00, a01, a11, x00, x10 ; a00 = entries[kk] ; a01 = entries[kk+1] ; a11 = entries[kk+2] ; x00 = x0[irowA] ; x10 = x0[irowA+1] ; y0[irowA] = a00*x00 + a01*x10 ; y0[irowA+1] = a01*x00 + a11*x10 ; kk += 3, irowA += 2 ; } else { fprintf(stderr, "\n fatal error in SubMtx_scale3vec()" "\n pivotsizes[%d] = %d", ipivot, pivotsizes[ipivot]) ; exit(-1) ; } } } else if ( SUBMTX_IS_COMPLEX(mtxA) ) { int iloc, ipivot, irowA, kk, rloc ; for ( irowA = ipivot = kk = rloc = 0, iloc = 1 ; irowA < nrowA ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { double ai00, ar00, xi0, xr0 ; ar00 = entries[kk] ; ai00 = entries[kk+1] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; y0[rloc] = ar00*xr0 - ai00*xi0; y0[iloc] = ar00*xi0 + ai00*xr0; kk += 2, irowA++, rloc += 2, iloc += 2 ; } else if ( pivotsizes[ipivot] == 2 ) { double ai00, ai01, ai11, ar00, ar01, ar11, xi00, xi10, xr00, xr10 ; int iloc0, iloc1, rloc0, rloc1 ; ar00 = entries[kk] ; ai00 = entries[kk+1] ; ar01 = entries[kk+2] ; ai01 = entries[kk+3] ; ar11 = entries[kk+4] ; ai11 = entries[kk+5] ; rloc0 = rloc ; iloc0 = iloc ; rloc1 = rloc + 2 ; iloc1 = iloc + 2 ; xr00 = x0[rloc0] ; xi00 = x0[iloc0] ; xr10 = x0[rloc1] ; xi10 = x0[iloc1] ; y0[rloc0] = ar00*xr00 - ai00*xi00 + ar01*xr10 - ai01*xi10 ; y0[iloc0] = ar00*xi00 + ai00*xr00 + ar01*xi10 + ai01*xr10 ; y0[rloc1] = ar01*xr00 - ai01*xi00 + ar11*xr10 - ai11*xi10 ; y0[iloc1] = ar01*xi00 + ai01*xr00 + ar11*xi10 + ai11*xr10 ; kk += 6, irowA += 2 ; rloc += 4 ; iloc += 4 ; } else { fprintf(stderr, "\n fatal error in SubMtx_scale1vec()" "\n pivotsizes[%d] = %d", ipivot, pivotsizes[ipivot]) ; exit(-1) ; } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- compute [y0 y1 y2] := A * [x0 x1 x2] where A is block diagonal and hermitian created -- 98apr17, cca -------------------------------------------------- */ static void block_diagonal_herm_scale3vec ( SubMtx *mtxA, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[] ) { double *entries ; int iloc, ipivot, irowA, kk, nentA, nrowA, rloc ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtxA, &nrowA, &nentA, &pivotsizes, &entries) ; for ( irowA = ipivot = kk = rloc = 0, iloc = 1 ; irowA < nrowA ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { double ar00, ai00, xi0, xi1, xi2, xr0, xr1, xr2 ; /* ar00 = entries[kk++] ; ai00 = entries[kk++] ; */ ar00 = entries[kk++] ; ai00 = 0.0 ; kk++ ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; xr2 = x2[rloc] ; xi2 = x2[iloc] ; y0[rloc] = ar00*xr0 ; y0[iloc] = ar00*xi0 ; y1[rloc] = ar00*xr1 ; y1[iloc] = ar00*xi1 ; y2[rloc] = ar00*xr2 ; y2[iloc] = ar00*xi2 ; irowA++, rloc += 2, iloc += 2 ; } else if ( pivotsizes[ipivot] == 2 ) { double ai00, ai01, ai11, ar00, ar01, ar11, xi00, xi01, xi02, xi10, xi11, xi12, xr00, xr01, xr02, xr10, xr11, xr12 ; int iloc0, iloc1, rloc0, rloc1 ; rloc0 = rloc ; iloc0 = iloc ; rloc1 = rloc + 2 ; iloc1 = iloc + 2 ; /* ar00 = entries[kk++] ; ai00 = entries[kk++] ; ar01 = entries[kk++] ; ai01 = entries[kk++] ; ar11 = entries[kk++] ; ai11 = entries[kk++] ; */ ar00 = entries[kk++] ; ai00 = 0.0 ; kk++ ; ar01 = entries[kk++] ; ai01 = entries[kk++] ; ar11 = entries[kk++] ; ai11 = 0.0 ; kk++ ; xr00 = x0[rloc0] ; xi00 = x0[iloc0] ; xr01 = x1[rloc0] ; xi01 = x1[iloc0] ; xr02 = x2[rloc0] ; xi02 = x2[iloc0] ; xr10 = x0[rloc1] ; xi10 = x0[iloc1] ; xr11 = x1[rloc1] ; xi11 = x1[iloc1] ; xr12 = x2[rloc1] ; xi12 = x2[iloc1] ; y0[rloc0] = ar00*xr00 + ar01*xr10 - ai01*xi10 ; y0[iloc0] = ar00*xi00 + ar01*xi10 + ai01*xr10 ; y1[rloc0] = ar00*xr01 + ar01*xr11 - ai01*xi11 ; y1[iloc0] = ar00*xi01 + ar01*xi11 + ai01*xr11 ; y2[rloc0] = ar00*xr02 + ar01*xr12 - ai01*xi12 ; y2[iloc0] = ar00*xi02 + ar01*xi12 + ai01*xr12 ; y0[rloc1] = ar01*xr00 + ai01*xi00 + ar11*xr10 ; y0[iloc1] = ar01*xi00 - ai01*xr00 + ar11*xi10 ; y1[rloc1] = ar01*xr01 + ai01*xi01 + ar11*xr11 ; y1[iloc1] = ar01*xi01 - ai01*xr01 + ar11*xi11 ; y2[rloc1] = ar01*xr02 + ai01*xi02 + ar11*xr12 ; y2[iloc1] = ar01*xi02 - ai01*xr02 + ar11*xi12 ; irowA += 2 ; rloc += 4 ; iloc += 4 ; } else { fprintf(stderr, "\n fatal error in SubMtx_scale3vec()" "\n pivotsizes[%d] = %d", ipivot, pivotsizes[ipivot]) ; exit(-1) ; } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- compute [y0 y1] := A * [x0 x1] where A is block diagonal and hermitian created -- 98apr17, cca -------------------------------------------------- */ static void block_diagonal_herm_scale2vec ( SubMtx *mtxA, double y0[], double y1[], double x0[], double x1[] ) { double *entries ; int iloc, ipivot, irowA, kk, nentA, nrowA, rloc ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtxA, &nrowA, &nentA, &pivotsizes, &entries) ; for ( irowA = ipivot = kk = rloc = 0, iloc = 1 ; irowA < nrowA ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { double ai00, ar00, xi0, xi1, xr0, xr1 ; /* ar00 = entries[kk++] ; ai00 = entries[kk++] ; */ ar00 = entries[kk++] ; ai00 = 0.0 ; kk++ ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; y0[rloc] = ar00*xr0 - ai00*xi0 ; y0[iloc] = ar00*xi0 + ai00*xr0 ; y1[rloc] = ar00*xr1 - ai00*xi1 ; y1[iloc] = ar00*xi1 + ai00*xr1 ; irowA++, rloc += 2, iloc += 2 ; } else if ( pivotsizes[ipivot] == 2 ) { double ai00, ai01, ai11, ar00, ar01, ar11, xi00, xi01, xi10, xi11, xr00, xr01, xr10, xr11 ; int iloc0, iloc1, rloc0, rloc1 ; rloc0 = rloc ; iloc0 = iloc ; rloc1 = rloc + 2 ; iloc1 = iloc + 2 ; /* ar00 = entries[kk++] ; ai00 = entries[kk++] ; ar01 = entries[kk++] ; ai01 = entries[kk++] ; ar11 = entries[kk++] ; ai11 = entries[kk++] ; */ ar00 = entries[kk++] ; ai00 = 0.0 ; kk++ ; ar01 = entries[kk++] ; ai01 = entries[kk++] ; ar11 = entries[kk++] ; ai11 = 0.0 ; kk++ ; xr00 = x0[rloc0] ; xi00 = x0[iloc0] ; xr01 = x1[rloc0] ; xi01 = x1[iloc0] ; xr10 = x0[rloc1] ; xi10 = x0[iloc1] ; xr11 = x1[rloc1] ; xi11 = x1[iloc1] ; y0[rloc0] = ar00*xr00 + ar01*xr10 - ai01*xi10 ; y0[iloc0] = ar00*xi00 + ar01*xi10 + ai01*xr10 ; y1[rloc0] = ar00*xr01 + ar01*xr11 - ai01*xi11 ; y1[iloc0] = ar00*xi01 + ar01*xi11 + ai01*xr11 ; y0[rloc1] = ar01*xr00 + ai01*xi00 + ar11*xr10 ; y0[iloc1] = ar01*xi00 - ai01*xr00 + ar11*xi10 ; y1[rloc1] = ar01*xr01 + ai01*xi01 + ar11*xr11 ; y1[iloc1] = ar01*xi01 - ai01*xr01 + ar11*xi11 ; irowA += 2 ; rloc += 4 ; iloc += 4 ; } else { fprintf(stderr, "\n fatal error in SubMtx_scale2vec()" "\n pivotsizes[%d] = %d", ipivot, pivotsizes[ipivot]) ; exit(-1) ; } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- compute [y0] := A * [x0] where A is block diagonal and hermitian created -- 98apr17, cca -------------------------------------------------- */ static void block_diagonal_herm_scale1vec ( SubMtx *mtxA, double y0[], double x0[] ) { double *entries ; int iloc, ipivot, irowA, kk, nentA, nrowA, rloc ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtxA, &nrowA, &nentA, &pivotsizes, &entries) ; for ( irowA = ipivot = kk = rloc = 0, iloc = 1 ; irowA < nrowA ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { double ai00, ar00, xi0, xr0 ; /* ar00 = entries[kk++] ; ai00 = entries[kk++] ; */ ar00 = entries[kk++] ; ai00 = 0.0 ; kk++ ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; y0[rloc] = ar00*xr0 - ai00*xi0 ; y0[iloc] = ar00*xi0 + ai00*xr0 ; irowA++, rloc += 2, iloc += 2 ; } else if ( pivotsizes[ipivot] == 2 ) { double ai00, ai01, ai11, ar00, ar01, ar11, xi00, xi10, xr00, xr10 ; int iloc0, iloc1, rloc0, rloc1 ; rloc0 = rloc ; iloc0 = iloc ; rloc1 = rloc + 2 ; iloc1 = iloc + 2 ; /* ar00 = entries[kk++] ; ai00 = entries[kk++] ; ar01 = entries[kk++] ; ai01 = entries[kk++] ; ar11 = entries[kk++] ; ai11 = entries[kk++] ; */ ar00 = entries[kk++] ; ai00 = 0.0 ; kk++ ; ar01 = entries[kk++] ; ai01 = entries[kk++] ; ar11 = entries[kk++] ; ai11 = 0.0 ; kk++ ; xr00 = x0[rloc0] ; xi00 = x0[iloc0] ; xr10 = x0[rloc1] ; xi10 = x0[iloc1] ; y0[rloc0] = ar00*xr00 + ar01*xr10 - ai01*xi10 ; y0[iloc0] = ar00*xi00 + ar01*xi10 + ai01*xr10 ; y0[rloc1] = ar01*xr00 + ai01*xi00 + ar11*xr10 ; y0[iloc1] = ar01*xi00 - ai01*xr00 + ar11*xi10 ; irowA += 2 ; rloc += 4 ; iloc += 4 ; } else { fprintf(stderr, "\n fatal error in SubMtx_scale1vec()" "\n pivotsizes[%d] = %d", ipivot, pivotsizes[ipivot]) ; exit(-1) ; } } return ; } /*--------------------------------------------------------------------*/ int ipivot, irowA, kk ; for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { if ( pivotsizes[ipivot] == 1 ) { double a00, x00 ; a00 = entries[kk] ; x00 = x0[irowA] ; y0[irowA] = a00*x00 ; kk++, irowA++ ; } else if ( pivotsizes[ipivot] == 2 ) { double a00, a01, a11, x00, x10 ; a00 = entries[kk] ; a01 = entries[kk+1] ; a11 = entries[kSubMtx/src/solve.c010064400020550007177000001634640653410625200154170ustar00clevecompmath00000400000006/* solve.c */ #include "../SubMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ static void real_solveDenseSubrows ( SubMtx *mtxA, SubMtx *mtxB ) ; static void real_solveDenseSubcolumns ( SubMtx *mtxA, SubMtx *mtxB ) ; static void real_solveSparseRows ( SubMtx *mtxA, SubMtx *mtxB ) ; static void real_solveSparseColumns ( SubMtx *mtxA, SubMtx *mtxB ) ; static void real_solveDiagonal ( SubMtx *mtxA, SubMtx *mtxB ) ; static void real_solveBlockDiagonalSym ( SubMtx *mtxA, SubMtx *mtxB ) ; static void complex_solveDenseSubrows ( SubMtx *mtxA, SubMtx *mtxB ) ; static void complex_solveDenseSubcolumns ( SubMtx *mtxA, SubMtx *mtxB ); static void complex_solveSparseRows ( SubMtx *mtxA, SubMtx *mtxB ) ; static void complex_solveSparseColumns ( SubMtx *mtxA, SubMtx *mtxB ) ; static void complex_solveDiagonal ( SubMtx *mtxA, SubMtx *mtxB ) ; static void complex_solveBlockDiagonalSym ( SubMtx *mtxA, SubMtx *mtxB); static void complex_solveBlockDiagonalHerm (SubMtx *mtxA, SubMtx *mtxB); /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- solve A X = B, where (1) X overwrites B (2) A must be lower or upper triangular, diagonal or block diagonal (3) if A is strict lower or upper triangular, then we solve (I + A) X = B (4) columns(A) = rows(X) (5) rows(A) = rows(B) (6) B has type SUBMTX_DENSE_COLUMNS (7) if A is SUBMTX_DENSE_SUBROWS or SUBMTX_SPARSE_ROWS then A must be strict lower triangular (8) if A is SUBMTX_DENSE_SUBCOLUMNS or SUBMTX_SPARSE_COLUMNS then A must be strict upper triangular (9) A can be SUBMTX_DIAGONAL, SUBMTX_BLOCK_DIAGONAL_SYM or SUBMTX_BLOCK_DIAGONAL_HERM created -- 98may01, cca ----------------------------------------------------------------- */ void SubMtx_solve ( SubMtx *mtxA, SubMtx *mtxB ) { /* --------------- check the input --------------- */ if ( mtxA == NULL || mtxB == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_solve(%p,%p)" "\n bad input\n", mtxA, mtxB) ; exit(-1) ; } if ( ! SUBMTX_IS_DENSE_COLUMNS(mtxB) ) { fprintf(stderr, "\n fatal error in SubMtx_solve(%p,%p)" "\n mtxB has bad type %d\n", mtxA, mtxB, mtxB->type) ; exit(-1) ; } if ( mtxA->nrow != mtxB->nrow ) { fprintf(stderr, "\n fatal error in SubMtx_solve(%p,%p)" "\n mtxA->nrow = %d, mtxB->nrwo = %d\n", mtxA, mtxB, mtxA->nrow, mtxB->nrow) ; exit(-1) ; } /* ------------------------- switch over the type of A ------------------------- */ switch ( mtxA->type ) { case SPOOLES_REAL : /* ------------------------- switch over the mode of A ------------------------- */ switch ( mtxA->mode ) { case SUBMTX_DENSE_SUBROWS : real_solveDenseSubrows(mtxA, mtxB) ; break ; case SUBMTX_SPARSE_ROWS : real_solveSparseRows(mtxA, mtxB) ; break ; case SUBMTX_DENSE_SUBCOLUMNS : real_solveDenseSubcolumns(mtxA, mtxB) ; break ; case SUBMTX_SPARSE_COLUMNS : real_solveSparseColumns(mtxA, mtxB) ; break ; case SUBMTX_DIAGONAL : real_solveDiagonal(mtxA, mtxB) ; break ; case SUBMTX_BLOCK_DIAGONAL_SYM : real_solveBlockDiagonalSym(mtxA, mtxB) ; break ; case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_SPARSE_TRIPLES : default : fprintf(stderr, "\n fatal error in SubMtx_solve(%p,%p)" "\n bad mode %d\n", mtxA, mtxB, mtxA->type) ; exit(-1) ; break ; } break ; case SPOOLES_COMPLEX : /* ------------------------- switch over the mode of A ------------------------- */ switch ( mtxA->mode ) { case SUBMTX_DENSE_SUBROWS : complex_solveDenseSubrows(mtxA, mtxB) ; break ; case SUBMTX_SPARSE_ROWS : complex_solveSparseRows(mtxA, mtxB) ; break ; case SUBMTX_DENSE_SUBCOLUMNS : complex_solveDenseSubcolumns(mtxA, mtxB) ; break ; case SUBMTX_SPARSE_COLUMNS : complex_solveSparseColumns(mtxA, mtxB) ; break ; case SUBMTX_DIAGONAL : complex_solveDiagonal(mtxA, mtxB) ; break ; case SUBMTX_BLOCK_DIAGONAL_SYM : complex_solveBlockDiagonalSym(mtxA, mtxB) ; break ; case SUBMTX_BLOCK_DIAGONAL_HERM : complex_solveBlockDiagonalHerm(mtxA, mtxB) ; break ; case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_SPARSE_TRIPLES : default : fprintf(stderr, "\n fatal error in SubMtx_solve(%p,%p)" "\n bad mode %d\n", mtxA, mtxB, mtxA->type) ; exit(-1) ; break ; } break ; default : fprintf(stderr, "\n fatal error in SubMtx_solve(%p,%p)" "\n bad type %d\n", mtxA, mtxB, mtxA->type) ; exit(-1) ; break ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- solve (A + I) X = B, where (1) A is strictly lower triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ------------------------------------- */ static void real_solveDenseSubrows ( SubMtx *mtxA, SubMtx *mtxB ) { double Aki, sum0, sum1, sum2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int first, ii, inc1, inc2, irowA, jcolB, kk, last, ncolB, nentA, nrowA, nrowB ; int *firstlocsA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_denseSubrowsInfo(mtxA, &nrowA, &nentA, &firstlocsA, &sizesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nentA = %d", nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + nrowB ; colB2 = colB1 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n %% jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", first %d, last %d", first, last) ; fflush(stdout) ; #endif sum0 = sum1 = sum2 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { Aki = entriesA[kk] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% Aki A(%d,%d) = %12.4e", irowA+1, ii+1, Aki) ; fflush(stdout) ; #endif sum0 += Aki * colB0[ii] ; sum1 += Aki * colB1[ii] ; sum2 += Aki * colB2[ii] ; } colB0[irowA] -= sum0 ; colB1[irowA] -= sum1 ; colB2[irowA] -= sum2 ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %% kk = %d", kk) ; fflush(stdout) ; #endif colB0 = colB2 + nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n %% jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; sum0 = sum1 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { Aki = entriesA[kk] ; sum0 += Aki * colB0[ii] ; sum1 += Aki * colB1[ii] ; } colB0[irowA] -= sum0 ; colB1[irowA] -= sum1 ; } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA = %d, kk = %d, sizesA[%d] = %d", irowA, kk, irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, "\n %% first = %d, last = %d", first, last) ; fflush(stdout) ; #endif sum0 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { Aki = entriesA[kk] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% Aki = %12.4e, colB0[%d] = %12.4e", Aki, ii, colB0[ii]) ; fflush(stdout) ; #endif sum0 += Aki * colB0[ii] ; } colB0[irowA] -= sum0 ; #if MYDEBUG > 0 fprintf(stdout, "\n %% colB0[%d] -= %12.4e", irowA, sum0) ; fflush(stdout) ; #endif } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- solve (A + I) X = B, where (1) A is strictly lower triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ------------------------------------- */ static void real_solveSparseRows ( SubMtx *mtxA, SubMtx *mtxB ) { double Aki, sum0, sum1, sum2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int ii, inc1, inc2, irowA, jcolB, jj, kk, ncolB, nentA, nrowA, nrowB, size ; int *indicesA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_sparseRowsInfo(mtxA, &nrowA, &nentA, &sizesA, &indicesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + nrowB ; colB2 = colB1 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { sum0 = sum1 = sum2 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aki = entriesA[kk] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } sum0 += Aki * colB0[jj] ; sum1 += Aki * colB1[jj] ; sum2 += Aki * colB2[jj] ; } colB0[irowA] -= sum0 ; colB1[irowA] -= sum1 ; colB2[irowA] -= sum2 ; } } colB0 = colB2 + nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { sum0 = sum1 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aki = entriesA[kk] ; jj = indicesA[kk] ; sum0 += Aki * colB0[jj] ; sum1 += Aki * colB1[jj] ; } colB0[irowA] -= sum0 ; colB1[irowA] -= sum1 ; } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) >= 0 ) { sum0 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aki = entriesA[kk] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } sum0 += Aki * colB0[jj] ; } colB0[irowA] -= sum0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- solve (I + A) X = B, where (1) A is strictly upper triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ------------------------------------- */ static void real_solveDenseSubcolumns ( SubMtx *mtxA, SubMtx *mtxB ) { double Aji, Bi0, Bi1, Bi2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int colstart, first, inc1, inc2, irowA, jcolB, jj, kk, last, ncolB, nentA, nrowA, nrowB ; int *firstlocsA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_denseSubcolumnsInfo(mtxA, &nrowA, &nentA, &firstlocsA, &sizesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nrowA = %d, ncolA = %d", nrowA, nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + nrowB ; colB2 = colB1 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; Bi0 = colB0[irowA] ; Bi1 = colB1[irowA] ; Bi2 = colB2[irowA] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { Aji = entriesA[kk] ; colB0[jj] -= Aji * Bi0 ; colB1[jj] -= Aji * Bi1 ; colB2[jj] -= Aji * Bi2 ; } } } colB0 = colB2 + nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; Bi0 = colB0[irowA] ; Bi1 = colB1[irowA] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { Aji = entriesA[kk] ; colB0[jj] -= Aji * Bi0 ; colB1[jj] -= Aji * Bi1 ; } } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA = %d, sizesA[%d] = %d", irowA, irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; Bi0 = colB0[irowA] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% first %d, last %d, colstart %d, Bi0 = %12.4e", first, last, colstart, Bi0) ; fflush(stdout) ; #endif for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { Aji = entriesA[kk] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% jj %d, kk %d, Aji %12.4e", jj, kk, Aji) ; fflush(stdout) ; #endif colB0[jj] -= Aji * Bi0 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- solve (I + A) X = B, where (1) A is strictly upper triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ------------------------------------- */ static void real_solveSparseColumns ( SubMtx *mtxA, SubMtx *mtxB ) { double Aji, Bi0, Bi1, Bi2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int colstart, ii, inc1, inc2, jcolA, jcolB, jj, kk, ncolB, nentA, nrowA, nrowB, size ; int *indicesA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_sparseColumnsInfo(mtxA, &nrowA, &nentA, &sizesA, &indicesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nrowA = %d, ncolA = %d", nrowA, nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + nrowB ; colB2 = colB1 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; Bi0 = colB0[jcolA] ; Bi1 = colB1[jcolA] ; Bi2 = colB2[jcolA] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { Aji = entriesA[kk] ; jj = indicesA[kk] ; colB0[jj] -= Aji * Bi0 ; colB1[jj] -= Aji * Bi1 ; colB2[jj] -= Aji * Bi2 ; } } } colB0 = colB2 + nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; Bi0 = colB0[jcolA] ; Bi1 = colB1[jcolA] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { Aji = entriesA[kk] ; jj = indicesA[kk] ; colB0[jj] -= Aji * Bi0 ; colB1[jj] -= Aji * Bi1 ; } } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; Bi0 = colB0[jcolA] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { Aji = entriesA[kk] ; jj = indicesA[kk] ; colB0[jj] -= Aji * Bi0 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- solve A X = B, where (1) A is diagonal (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ----------------------------------- */ static void real_solveDiagonal ( SubMtx *mtxA, SubMtx *mtxB ) { double Aii ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int inc1, inc2, irowA, jcolB, ncolB, nrowA, nrowB ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_diagonalInfo(mtxA, &nrowA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + nrowB ; colB2 = colB1 + nrowB ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { Aii = entriesA[irowA] ; colB0[irowA] /= Aii ; colB1[irowA] /= Aii ; colB2[irowA] /= Aii ; } colB0 = colB2 + nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + nrowB ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { Aii = entriesA[irowA] ; colB0[irowA] /= Aii ; colB1[irowA] /= Aii ; } } else if ( jcolB == ncolB - 1 ) { for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { Aii = entriesA[irowA] ; colB0[irowA] /= Aii ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- solve A X = B, where (1) A is block diagonal symmetric (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ----------------------------------- */ static void real_solveBlockDiagonalSym ( SubMtx *mtxA, SubMtx *mtxB ) { double Aii, Arr, Ars, Ass, recip, t1, t2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int inc1, inc2, ipivot, irowA, jcolB, kk, m, ncolB, nentA, nrowA, nrowB ; int *pivotsizes ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_blockDiagonalInfo(mtxA, &nrowA, &nentA, &pivotsizes, &entriesA); for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m != 1 && m != 2 ) { fprintf(stderr, "\n fatal error in SubMtx_solve(%p,%p)" "\n mtxA is block diagonal symmetric" "\n pivot %d is %d, not supported", mtxA, mtxB, ipivot, m) ; exit(-1) ; } irowA += m ; } SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + nrowB ; colB2 = colB1 + nrowB ; for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { Aii = entriesA[kk++] ; colB0[irowA] /= Aii ; colB1[irowA] /= Aii ; colB2[irowA] /= Aii ; } else if ( m == 2 ) { Arr = entriesA[kk++] ; Ars = entriesA[kk++] ; Ass = entriesA[kk++] ; recip = 1./(Arr*Ass - Ars*Ars) ; t1 = colB0[irowA] ; t2 = colB0[irowA+1] ; colB0[irowA] = recip*( Ass*t1 - Ars*t2) ; colB0[irowA+1] = recip*(-Ars*t1 + Arr*t2) ; t1 = colB1[irowA] ; t2 = colB1[irowA+1] ; colB1[irowA] = recip*( Ass*t1 - Ars*t2) ; colB1[irowA+1] = recip*(-Ars*t1 + Arr*t2) ; t1 = colB2[irowA] ; t2 = colB2[irowA+1] ; colB2[irowA] = recip*( Ass*t1 - Ars*t2) ; colB2[irowA+1] = recip*(-Ars*t1 + Arr*t2) ; } irowA += m ; } colB0 = colB2 + nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + nrowB ; for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { Aii = entriesA[kk++] ; colB0[irowA] /= Aii ; colB1[irowA] /= Aii ; } else if ( m == 2 ) { Arr = entriesA[kk++] ; Ars = entriesA[kk++] ; Ass = entriesA[kk++] ; recip = 1./(Arr*Ass - Ars*Ars) ; t1 = colB0[irowA] ; t2 = colB0[irowA+1] ; colB0[irowA] = recip*( Ass*t1 - Ars*t2) ; colB0[irowA+1] = recip*(-Ars*t1 + Arr*t2) ; t1 = colB1[irowA] ; t2 = colB1[irowA+1] ; colB1[irowA] = recip*( Ass*t1 - Ars*t2) ; colB1[irowA+1] = recip*(-Ars*t1 + Arr*t2) ; } irowA += m ; } } else if ( jcolB == ncolB - 1 ) { for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { Aii = entriesA[kk++] ; colB0[irowA] /= Aii ; } else if ( m == 2 ) { Arr = entriesA[kk++] ; Ars = entriesA[kk++] ; Ass = entriesA[kk++] ; recip = 1./(Arr*Ass - Ars*Ars) ; t1 = colB0[irowA] ; t2 = colB0[irowA+1] ; colB0[irowA] = recip*( Ass*t1 - Ars*t2) ; colB0[irowA+1] = recip*(-Ars*t1 + Arr*t2) ; } irowA += m ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- solve (A + I) X = B, where (1) A is strictly lower triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ------------------------------------- */ static void complex_solveDenseSubrows ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi0, bi1, bi2, br0, br1, br2, isum0, isum1, isum2, rsum0, rsum1, rsum2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int first, ii, iloc, inc1, inc2, irowA, jcolB, kk, last, ncolB, nentA, nrowA, nrowB, rloc ; int *firstlocsA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_denseSubrowsInfo(mtxA, &nrowA, &nentA, &firstlocsA, &sizesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nentA = %d", nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n %% jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", first %d, last %d", first, last) ; fflush(stdout) ; #endif rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; rsum2 = isum2 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { rloc = 2*kk ; iloc = rloc + 1 ; ar = entriesA[rloc] ; ai = entriesA[iloc] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% A(%d,%d) = (%12.4e,%12.4e)", irowA+1, ii+1, ar, ai) ; fflush(stdout) ; #endif rloc = 2*ii ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; rsum1 += ar*br1 - ai*bi1 ; isum1 += ar*bi1 + ai*br1 ; rsum2 += ar*br2 - ai*bi2 ; isum2 += ar*bi2 + ai*br2 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; colB2[rloc] -= rsum2 ; colB2[iloc] -= isum2 ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %% kk = %d", kk) ; fflush(stdout) ; #endif colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n %% jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", first %d, last %d", first, last) ; fflush(stdout) ; #endif rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { rloc = 2*kk ; iloc = rloc + 1 ; ar = entriesA[rloc] ; ai = entriesA[iloc] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% A(%d,%d) = (%12.4e,%12.4e)", irowA+1, ii+1, ar, ai) ; fflush(stdout) ; #endif rloc = 2*ii ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; rsum1 += ar*br1 - ai*bi1 ; isum1 += ar*bi1 + ai*br1 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %% kk = %d", kk) ; fflush(stdout) ; #endif } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", first %d, last %d", first, last) ; fflush(stdout) ; #endif rsum0 = isum0 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { rloc = 2*kk ; iloc = rloc + 1 ; ar = entriesA[rloc] ; ai = entriesA[iloc] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% A(%d,%d) = (%12.4e,%12.4e)", irowA+1, ii+1, ar, ai) ; fflush(stdout) ; #endif rloc = 2*ii ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %% kk = %d", kk) ; fflush(stdout) ; #endif } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- solve (A + I) X = B, where (1) A is strictly lower triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ------------------------------------- */ static void complex_solveSparseRows ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi0, bi1, bi2, br0, br1, br2, isum0, isum1, isum2, rsum0, rsum1, rsum2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int ii, iloc, inc1, inc2, irowA, jcolB, jj, kk, ncolB, nentA, nrowA, nrowB, rloc, size ; int *indicesA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_sparseRowsInfo(mtxA, &nrowA, &nentA, &sizesA, &indicesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; rsum2 = isum2 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { rloc = 2*kk ; iloc = rloc + 1 ; ar = entriesA[rloc] ; ai = entriesA[iloc] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } rloc = 2*jj ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; rsum1 += ar*br1 - ai*bi1 ; isum1 += ar*bi1 + ai*br1 ; rsum2 += ar*br2 - ai*bi2 ; isum2 += ar*bi2 + ai*br2 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; colB2[rloc] -= rsum2 ; colB2[iloc] -= isum2 ; } } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { rloc = 2*kk ; iloc = rloc + 1 ; ar = entriesA[rloc] ; ai = entriesA[iloc] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } rloc = 2*jj ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; rsum1 += ar*br1 - ai*bi1 ; isum1 += ar*bi1 + ai*br1 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { rsum0 = isum0 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { rloc = 2*kk ; iloc = rloc + 1 ; ar = entriesA[rloc] ; ai = entriesA[iloc] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } rloc = 2*jj ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- solve (I + A) X = B, where (1) A is strictly upper triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ------------------------------------- */ static void complex_solveDenseSubcolumns ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi0, bi1, bi2, br0, br1, br2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int colstart, first, iloc, inc1, inc2, irowA, jcolB, jj, kk, last, ncolB, nentA, nrowA, nrowB, rloc ; int *firstlocsA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_denseSubcolumnsInfo(mtxA, &nrowA, &nentA, &firstlocsA, &sizesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nrowA = %d, ncolA = %d", nrowA, nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; rloc = 2*irowA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; colB1[rloc] -= ar*br1 - ai*bi1 ; colB1[iloc] -= ar*bi1 + ai*br1 ; colB2[rloc] -= ar*br2 - ai*bi2 ; colB2[iloc] -= ar*bi2 + ai*br2 ; } } } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; rloc = 2*irowA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; colB1[rloc] -= ar*br1 - ai*bi1 ; colB1[iloc] -= ar*bi1 + ai*br1 ; } } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { /* fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; */ if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; rloc = 2*irowA ; iloc = rloc + 1 ; /* fprintf(stdout, "\n %% first %d, last %d, colstart %d, rloc %d, iloc %d", first, last, colstart, rloc, iloc) ; */ br0 = colB0[rloc] ; bi0 = colB0[iloc] ; /* fprintf(stdout, "\n %% br0 %12.4e, bi0 %12.4e", br0, bi0) ; */ for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; /* fprintf(stdout, "\n %% ar %12.4e, ai %12.4e", ar, ai) ; */ rloc = 2*jj ; iloc = rloc + 1 ; /* fprintf(stdout, "\n %% rloc %d, iloc %d", rloc, iloc) ; */ colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; /* fprintf(stdout, "\n %% colB[%d] = %12.5e, colB[%d] = %12.5e", rloc, colB0[rloc], iloc, colB0[iloc]) ; */ } } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- solve (I + A) X = B, where (1) A is strictly upper triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ------------------------------------- */ static void complex_solveSparseColumns ( SubMtx *mtxA, SubMtx *mtxB ) { double ar, ai, bi0, bi1, bi2, br0, br1, br2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int colstart, ii, iloc, inc1, inc2, jcolA, jcolB, jj, kk, ncolB, nentA, nrowA, nrowB, rloc, size ; int *indicesA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_sparseColumnsInfo(mtxA, &nrowA, &nentA, &sizesA, &indicesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nrowA = %d, ncolA = %d", nrowA, nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; rloc = 2*jcolA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; colB1[rloc] -= ar*br1 - ai*bi1 ; colB1[iloc] -= ar*bi1 + ai*br1 ; colB2[rloc] -= ar*br2 - ai*bi2 ; colB2[iloc] -= ar*bi2 + ai*br2 ; } } } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; rloc = 2*jcolA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; colB1[rloc] -= ar*br1 - ai*bi1 ; colB1[iloc] -= ar*bi1 + ai*br1 ; } } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; rloc = 2*jcolA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- solve A X = B, where (1) A is diagonal (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ----------------------------------- */ static void complex_solveDiagonal ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi, br, ci, cr ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int inc1, inc2, irowA, jcolB, kk, ncolB, nrowA, nrowB ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_diagonalInfo(mtxA, &nrowA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; for ( irowA = kk = 0 ; irowA < nrowA ; irowA++, kk += 2 ) { ar = entriesA[kk] ; ai = entriesA[kk+1] ; Zrecip(ar, ai, &cr, &ci) ; br = colB0[kk] ; bi = colB0[kk+1] ; colB0[kk] = br*cr - bi*ci ; colB0[kk+1] = br*ci + bi*cr ; br = colB1[kk] ; bi = colB1[kk+1] ; colB1[kk] = br*cr - bi*ci ; colB1[kk+1] = br*ci + bi*cr ; br = colB2[kk] ; bi = colB2[kk+1] ; colB2[kk] = br*cr - bi*ci ; colB2[kk+1] = br*ci + bi*cr ; } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; for ( irowA = kk = 0 ; irowA < nrowA ; irowA++, kk += 2 ) { ar = entriesA[kk] ; ai = entriesA[kk+1] ; Zrecip(ar, ai, &cr, &ci) ; br = colB0[kk] ; bi = colB0[kk+1] ; colB0[kk] = br*cr - bi*ci ; colB0[kk+1] = br*ci + bi*cr ; br = colB1[kk] ; bi = colB1[kk+1] ; colB1[kk] = br*cr - bi*ci ; colB1[kk+1] = br*ci + bi*cr ; } } else if ( jcolB == ncolB - 1 ) { for ( irowA = kk = 0 ; irowA < nrowA ; irowA++, kk += 2 ) { ar = entriesA[kk] ; ai = entriesA[kk+1] ; Zrecip(ar, ai, &cr, &ci) ; br = colB0[kk] ; bi = colB0[kk+1] ; colB0[kk] = br*cr - bi*ci ; colB0[kk+1] = br*ci + bi*cr ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- solve A X = B, where (1) A is block diagonal symmetric (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ----------------------------------- */ static void complex_solveBlockDiagonalSym ( SubMtx *mtxA, SubMtx *mtxB ) { double ai00, ai01, ai11, ar00, ar01, ar11, bi0, bi1, bi2, br0, br1, br2, ci00, ci01, ci11, cr00, cr01, cr11 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int inc1, inc2, ipivot, irowA, jcolB, kk, m, ncolB, nentA, nrowA, nrowB ; int *pivotsizes ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_blockDiagonalInfo(mtxA, &nrowA, &nentA, &pivotsizes, &entriesA); for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m != 1 && m != 2 ) { fprintf(stderr, "\n fatal error in SubMtx_solve(%p,%p)" "\n mtxA is block diagonal symmetric" "\n pivot %d is %d, not supported", mtxA, mtxB, ipivot, m) ; exit(-1) ; } irowA += m ; } SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; Zrecip(ar00, ai00, &cr00, &ci00) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; colB0[2*irowA] = br0*cr00 - bi0*ci00 ; colB0[2*irowA+1] = br0*ci00 + bi0*cr00 ; br1 = colB1[2*irowA] ; bi1 = colB1[2*irowA+1] ; colB1[2*irowA] = br1*cr00 - bi1*ci00 ; colB1[2*irowA+1] = br1*ci00 + bi1*cr00 ; br2 = colB2[2*irowA] ; bi2 = colB2[2*irowA+1] ; colB2[2*irowA] = br2*cr00 - bi2*ci00 ; colB2[2*irowA+1] = br2*ci00 + bi2*cr00 ; } else if ( m == 2 ) { ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; ar01 = entriesA[2*kk] ; ai01 = entriesA[2*kk+1] ; kk++ ; ar11 = entriesA[2*kk] ; ai11 = entriesA[2*kk+1] ; kk++ ; Zrecip2(ar00, ai00, ar01, ai01, ar01, ai01, ar11, ai11, &cr00, &ci00, &cr01, &ci01, NULL, NULL, &cr11, &ci11) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; br1 = colB0[2*irowA+2] ; bi1 = colB0[2*irowA+3] ; colB0[2*irowA] = cr00*br0 - ci00*bi0 + cr01*br1 - ci01*bi1 ; colB0[2*irowA+1] = cr00*bi0 + ci00*br0 + cr01*bi1 + ci01*br1 ; colB0[2*irowA+2] = cr01*br0 - ci01*bi0 + cr11*br1 - ci11*bi1 ; colB0[2*irowA+3] = cr01*bi0 + ci01*br0 + cr11*bi1 + ci11*br1 ; br0 = colB1[2*irowA] ; bi0 = colB1[2*irowA+1] ; br1 = colB1[2*irowA+2] ; bi1 = colB1[2*irowA+3] ; colB1[2*irowA] = cr00*br0 - ci00*bi0 + cr01*br1 - ci01*bi1 ; colB1[2*irowA+1] = cr00*bi0 + ci00*br0 + cr01*bi1 + ci01*br1 ; colB1[2*irowA+2] = cr01*br0 - ci01*bi0 + cr11*br1 - ci11*bi1 ; colB1[2*irowA+3] = cr01*bi0 + ci01*br0 + cr11*bi1 + ci11*br1 ; br0 = colB2[2*irowA] ; bi0 = colB2[2*irowA+1] ; br1 = colB2[2*irowA+2] ; bi1 = colB2[2*irowA+3] ; colB2[2*irowA] = cr00*br0 - ci00*bi0 + cr01*br1 - ci01*bi1 ; colB2[2*irowA+1] = cr00*bi0 + ci00*br0 + cr01*bi1 + ci01*br1 ; colB2[2*irowA+2] = cr01*br0 - ci01*bi0 + cr11*br1 - ci11*bi1 ; colB2[2*irowA+3] = cr01*bi0 + ci01*br0 + cr11*bi1 + ci11*br1 ; } irowA += m ; } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; Zrecip(ar00, ai00, &cr00, &ci00) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; colB0[2*irowA] = br0*cr00 - bi0*ci00 ; colB0[2*irowA+1] = br0*ci00 + bi0*cr00 ; br1 = colB1[2*irowA] ; bi1 = colB1[2*irowA+1] ; colB1[2*irowA] = br1*cr00 - bi1*ci00 ; colB1[2*irowA+1] = br1*ci00 + bi1*cr00 ; } else if ( m == 2 ) { ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; ar01 = entriesA[2*kk] ; ai01 = entriesA[2*kk+1] ; kk++ ; ar11 = entriesA[2*kk] ; ai11 = entriesA[2*kk+1] ; kk++ ; Zrecip2(ar00, ai00, ar01, ai01, ar01, ai01, ar11, ai11, &cr00, &ci00, &cr01, &ci01, NULL, NULL, &cr11, &ci11) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; br1 = colB0[2*irowA+2] ; bi1 = colB0[2*irowA+3] ; colB0[2*irowA] = cr00*br0 - ci00*bi0 + cr01*br1 - ci01*bi1 ; colB0[2*irowA+1] = cr00*bi0 + ci00*br0 + cr01*bi1 + ci01*br1 ; colB0[2*irowA+2] = cr01*br0 - ci01*bi0 + cr11*br1 - ci11*bi1 ; colB0[2*irowA+3] = cr01*bi0 + ci01*br0 + cr11*bi1 + ci11*br1 ; br0 = colB1[2*irowA] ; bi0 = colB1[2*irowA+1] ; br1 = colB1[2*irowA+2] ; bi1 = colB1[2*irowA+3] ; colB1[2*irowA] = cr00*br0 - ci00*bi0 + cr01*br1 - ci01*bi1 ; colB1[2*irowA+1] = cr00*bi0 + ci00*br0 + cr01*bi1 + ci01*br1 ; colB1[2*irowA+2] = cr01*br0 - ci01*bi0 + cr11*br1 - ci11*bi1 ; colB1[2*irowA+3] = cr01*bi0 + ci01*br0 + cr11*bi1 + ci11*br1 ; } irowA += m ; } } else if ( jcolB == ncolB - 1 ) { for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; Zrecip(ar00, ai00, &cr00, &ci00) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; colB0[2*irowA] = br0*cr00 - bi0*ci00 ; colB0[2*irowA+1] = br0*ci00 + bi0*cr00 ; } else if ( m == 2 ) { ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; ar01 = entriesA[2*kk] ; ai01 = entriesA[2*kk+1] ; kk++ ; ar11 = entriesA[2*kk] ; ai11 = entriesA[2*kk+1] ; kk++ ; Zrecip2(ar00, ai00, ar01, ai01, ar01, ai01, ar11, ai11, &cr00, &ci00, &cr01, &ci01, NULL, NULL, &cr11, &ci11) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; br1 = colB0[2*irowA+2] ; bi1 = colB0[2*irowA+3] ; colB0[2*irowA] = cr00*br0 - ci00*bi0 + cr01*br1 - ci01*bi1 ; colB0[2*irowA+1] = cr00*bi0 + ci00*br0 + cr01*bi1 + ci01*br1 ; colB0[2*irowA+2] = cr01*br0 - ci01*bi0 + cr11*br1 - ci11*bi1 ; colB0[2*irowA+3] = cr01*bi0 + ci01*br0 + cr11*bi1 + ci11*br1 ; } irowA += m ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- solve A X = B, where (1) A is block diagonal hermitian (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca ----------------------------------- */ static void complex_solveBlockDiagonalHerm ( SubMtx *mtxA, SubMtx *mtxB ) { double ai00, ai01, ai11, ar00, ar01, ar11, bi0, bi1, bi2, br0, br1, br2, ci00, ci01, ci11, cr00, cr01, cr11 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int inc1, inc2, ipivot, irowA, jcolB, kk, m, ncolB, nentA, nrowA, nrowB ; int *pivotsizes ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_blockDiagonalInfo(mtxA, &nrowA, &nentA, &pivotsizes, &entriesA); for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m != 1 && m != 2 ) { fprintf(stderr, "\n fatal error in SubMtx_solve(%p,%p)" "\n mtxA is block diagonal hermitian" "\n pivot %d is %d, not supported", mtxA, mtxB, ipivot, m) ; exit(-1) ; } irowA += m ; } SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { /* ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; */ ar00 = entriesA[2*kk] ; ai00 = 0.0 ; kk++ ; Zrecip(ar00, ai00, &cr00, &ci00) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; colB0[2*irowA] = br0*cr00 ; colB0[2*irowA+1] = bi0*cr00 ; br1 = colB1[2*irowA] ; bi1 = colB1[2*irowA+1] ; colB1[2*irowA] = br1*cr00 ; colB1[2*irowA+1] = bi1*cr00 ; br2 = colB2[2*irowA] ; bi2 = colB2[2*irowA+1] ; colB2[2*irowA] = br2*cr00 ; colB2[2*irowA+1] = bi2*cr00 ; } else if ( m == 2 ) { /* ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; ar01 = entriesA[2*kk] ; ai01 = entriesA[2*kk+1] ; kk++ ; ar11 = entriesA[2*kk] ; ai11 = entriesA[2*kk+1] ; kk++ ; */ ar00 = entriesA[2*kk] ; ai00 = 0.0 ; kk++ ; ar01 = entriesA[2*kk] ; ai01 = entriesA[2*kk+1] ; kk++ ; ar11 = entriesA[2*kk] ; ai11 = 0.0 ; kk++ ; Zrecip2(ar00, ai00, ar01, ai01, ar01, -ai01, ar11, ai11, &cr00, &ci00, &cr01, &ci01, NULL, NULL, &cr11, &ci11) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; br1 = colB0[2*irowA+2] ; bi1 = colB0[2*irowA+3] ; colB0[2*irowA] = cr00*br0 + cr01*br1 - ci01*bi1 ; colB0[2*irowA+1] = cr00*bi0 + cr01*bi1 + ci01*br1 ; colB0[2*irowA+2] = cr01*br0 + ci01*bi0 + cr11*br1 ; colB0[2*irowA+3] = cr01*bi0 - ci01*br0 + cr11*bi1 ; br0 = colB1[2*irowA] ; bi0 = colB1[2*irowA+1] ; br1 = colB1[2*irowA+2] ; bi1 = colB1[2*irowA+3] ; colB1[2*irowA] = cr00*br0 + cr01*br1 - ci01*bi1 ; colB1[2*irowA+1] = cr00*bi0 + cr01*bi1 + ci01*br1 ; colB1[2*irowA+2] = cr01*br0 + ci01*bi0 + cr11*br1 ; colB1[2*irowA+3] = cr01*bi0 - ci01*br0 + cr11*bi1 ; br0 = colB2[2*irowA] ; bi0 = colB2[2*irowA+1] ; br1 = colB2[2*irowA+2] ; bi1 = colB2[2*irowA+3] ; colB2[2*irowA] = cr00*br0 + cr01*br1 - ci01*bi1 ; colB2[2*irowA+1] = cr00*bi0 + cr01*bi1 + ci01*br1 ; colB2[2*irowA+2] = cr01*br0 + ci01*bi0 + cr11*br1 ; colB2[2*irowA+3] = cr01*bi0 - ci01*br0 + cr11*bi1 ; } irowA += m ; } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { /* ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; */ ar00 = entriesA[2*kk] ; ai00 = 0.0 ; kk++ ; Zrecip(ar00, ai00, &cr00, &ci00) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; colB0[2*irowA] = br0*cr00 ; colB0[2*irowA+1] = bi0*cr00 ; br1 = colB1[2*irowA] ; bi1 = colB1[2*irowA+1] ; colB1[2*irowA] = br1*cr00 ; colB1[2*irowA+1] = bi1*cr00 ; } else if ( m == 2 ) { /* ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; ar01 = entriesA[2*kk] ; ai01 = entriesA[2*kk+1] ; kk++ ; ar11 = entriesA[2*kk] ; ai11 = entriesA[2*kk+1] ; kk++ ; */ ar00 = entriesA[2*kk] ; ai00 = 0.0 ; kk++ ; ar01 = entriesA[2*kk] ; ai01 = entriesA[2*kk+1] ; kk++ ; ar11 = entriesA[2*kk] ; ai11 = 0.0 ; kk++ ; Zrecip2(ar00, ai00, ar01, ai01, ar01, -ai01, ar11, ai11, &cr00, &ci00, &cr01, &ci01, NULL, NULL, &cr11, &ci11) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; br1 = colB0[2*irowA+2] ; bi1 = colB0[2*irowA+3] ; colB0[2*irowA] = cr00*br0 + cr01*br1 - ci01*bi1 ; colB0[2*irowA+1] = cr00*bi0 + cr01*bi1 + ci01*br1 ; colB0[2*irowA+2] = cr01*br0 + ci01*bi0 + cr11*br1 ; colB0[2*irowA+3] = cr01*bi0 - ci01*br0 + cr11*bi1 ; br0 = colB1[2*irowA] ; bi0 = colB1[2*irowA+1] ; br1 = colB1[2*irowA+2] ; bi1 = colB1[2*irowA+3] ; colB1[2*irowA] = cr00*br0 + cr01*br1 - ci01*bi1 ; colB1[2*irowA+1] = cr00*bi0 + cr01*bi1 + ci01*br1 ; colB1[2*irowA+2] = cr01*br0 + ci01*bi0 + cr11*br1 ; colB1[2*irowA+3] = cr01*bi0 - ci01*br0 + cr11*bi1 ; } irowA += m ; } } else if ( jcolB == ncolB - 1 ) { for ( irowA = ipivot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { /* ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; */ ar00 = entriesA[2*kk] ; ai00 = 0.0 ; kk++ ; Zrecip(ar00, ai00, &cr00, &ci00) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; colB0[2*irowA] = br0*cr00 ; colB0[2*irowA+1] = bi0*cr00 ; } else if ( m == 2 ) { /* ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; ar01 = entriesA[2*kk] ; ai01 = entriesA[2*kk+1] ; kk++ ; ar11 = entriesA[2*kk] ; ai11 = entriesA[2*kk+1] ; kk++ ; */ ar00 = entriesA[2*kk] ; ai00 = 0.0 ; kk++ ; ar01 = entriesA[2*kk] ; ai01 = entriesA[2*kk+1] ; kk++ ; ar11 = entriesA[2*kk] ; ai11 = 0.0 ; kk++ ; Zrecip2(ar00, ai00, ar01, ai01, ar01, -ai01, ar11, ai11, &cr00, &ci00, &cr01, &ci01, NULL, NULL, &cr11, &ci11) ; br0 = colB0[2*irowA] ; bi0 = colB0[2*irowA+1] ; br1 = colB0[2*irowA+2] ; bi1 = colB0[2*irowA+3] ; colB0[2*irowA] = cr00*br0 + cr01*br1 - ci01*bi1 ; colB0[2*irowA+1] = cr00*bi0 + cr01*bi1 + ci01*br1 ; colB0[2*irowA+2] = cr01*br0 + ci01*bi0 + cr11*br1 ; colB0[2*irowA+3] = cr01*bi0 - ci01*br0 + cr11*bi1 ; } irowA += m ; } } return ; } /*--------------------------------------------------------------------*/ ot = kk = 0 ; irowA < nrowA ; ipivot++ ) { m = pivotsizes[ipivot] ; if ( m == 1 ) { ar00 = entriesA[2*kk] ; ai00 = entriesA[2*kk+1] ; kk++ ; Zrecip(ar00, ai00, &cr00, &ci00) SubMtx/src/solveH.c010064400020550007177000000476640653410625200155320ustar00clevecompmath00000400000006/* solveH.c */ #include "../SubMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ static void solveDenseSubrows ( SubMtx *mtxA, SubMtx *mtxB ) ; static void solveDenseSubcolumns ( SubMtx *mtxA, SubMtx *mtxB ) ; static void solveSparseRows ( SubMtx *mtxA, SubMtx *mtxB ) ; static void solveSparseColumns ( SubMtx *mtxA, SubMtx *mtxB ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- solve (A^H + I) X = B, where (1) X overwrites B (2) A must be strict lower or upper triangular (2) A, B and X are complex (4) columns(A) = rows(X) (5) rows(A) = rows(B) (6) B has mode SUBMTX_DENSE_COLUMNS (7) if A is SUBMTX_DENSE_SUBROWS or SUBMTX_SPARSE_ROWS then A must be strict lower triangular (8) if A is SUBMTX_DENSE_SUBCOLUMNS or SUBMTX_SPARSE_COLUMNS then A must be strict upper triangular created -- 98may01, cca ------------------------------------------------------------- */ void SubMtx_solveH ( SubMtx *mtxA, SubMtx *mtxB ) { /* --------------- check the input --------------- */ if ( mtxA == NULL || mtxB == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_solveH(%p,%p)" "\n bad input\n", mtxA, mtxB) ; exit(-1) ; } if ( ! SUBMTX_IS_COMPLEX(mtxB) ) { fprintf(stderr, "\n fatal error in SubMtx_solveH(%p,%p)" "\n mtxB has bad type %d\n", mtxA, mtxB, mtxB->type) ; exit(-1) ; } if ( ! SUBMTX_IS_DENSE_COLUMNS(mtxB) ) { fprintf(stderr, "\n fatal error in SubMtx_solveH(%p,%p)" "\n mtxB has bad mode %d\n", mtxA, mtxB, mtxB->mode) ; exit(-1) ; } if ( mtxA->nrow != mtxB->nrow ) { fprintf(stderr, "\n fatal error in SubMtx_solveH(%p,%p)" "\n mtxA->nrow = %d, mtxB->nrwo = %d\n", mtxA, mtxB, mtxA->nrow, mtxB->nrow) ; exit(-1) ; } /* ------------------------- switch over the mode of A ------------------------- */ switch ( mtxA->mode ) { case SUBMTX_DENSE_SUBROWS : solveDenseSubrows(mtxA, mtxB) ; break ; case SUBMTX_SPARSE_ROWS : solveSparseRows(mtxA, mtxB) ; break ; case SUBMTX_DENSE_SUBCOLUMNS : solveDenseSubcolumns(mtxA, mtxB) ; break ; case SUBMTX_SPARSE_COLUMNS : solveSparseColumns(mtxA, mtxB) ; break ; default : fprintf(stderr, "\n fatal error in SubMtx_solveH(%p,%p)" "\n bad mode %d\n", mtxA, mtxB, mtxA->mode) ; exit(-1) ; break ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (A^T + I) X = B, where (1) A is strictly upper triangular (2) X overwrites B (B) B has mode SUBMTX_DENSE_COLUMNS created -- 98may01, cca --------------------------------------- */ static void solveDenseSubcolumns ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi0, bi1, bi2, br0, br1, br2, isum0, isum1, isum2, rsum0, rsum1, rsum2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int first, ii, iloc, inc1, inc2, irowA, jcolB, kk, last, ncolB, nentA, nrowA, nrowB, rloc ; int *firstlocsA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_denseSubcolumnsInfo(mtxA, &nrowA, &nentA, &firstlocsA, &sizesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nentA = %d", nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n %% jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", first %d, last %d", first, last) ; fflush(stdout) ; #endif rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; rsum2 = isum2 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% A(%d,%d) = (%12.4e,%12.4e)", irowA+1, ii+1, ar, ai) ; fflush(stdout) ; #endif rloc = 2*ii ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; rsum0 += ar*br0 + ai*bi0 ; isum0 += ar*bi0 - ai*br0 ; rsum1 += ar*br1 + ai*bi1 ; isum1 += ar*bi1 - ai*br1 ; rsum2 += ar*br2 + ai*bi2 ; isum2 += ar*bi2 - ai*br2 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; colB2[rloc] -= rsum2 ; colB2[iloc] -= isum2 ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %% kk = %d", kk) ; fflush(stdout) ; #endif colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", first %d, last %d", first, last) ; fflush(stdout) ; #endif rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% A(%d,%d) = (%12.4e,%12.4e)", irowA+1, ii+1, ar, ai) ; fflush(stdout) ; #endif rloc = 2*ii ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; rsum0 += ar*br0 + ai*bi0 ; isum0 += ar*bi0 - ai*br0 ; rsum1 += ar*br1 + ai*bi1 ; isum1 += ar*bi1 - ai*br1 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% kk = %d", kk) ; fflush(stdout) ; #endif } } else if ( jcolB == ncolB - 1 ) { for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", first %d, last %d", first, last) ; fflush(stdout) ; #endif rsum0 = isum0 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% A(%d,%d) = (%12.4e,%12.4e)", irowA+1, ii+1, ar, ai) ; fflush(stdout) ; #endif rloc = 2*ii ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; rsum0 += ar*br0 + ai*bi0 ; isum0 += ar*bi0 - ai*br0 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% kk = %d", kk) ; fflush(stdout) ; #endif } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (A^T + I) X = B, where (1) A is strictly upper triangular (2) X overwrites B (B) B has mode SUBMTX_DENSE_COLUMNS created -- 98may01, cca --------------------------------------- */ static void solveSparseColumns ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi0, bi1, bi2, br0, br1, br2, isum0, isum1, isum2, rsum0, rsum1, rsum2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int ii, iloc, inc1, inc2, irowA, jcolB, jj, kk, ncolB, nentA, nrowA, nrowB, rloc, size ; int *indicesA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_sparseColumnsInfo(mtxA, &nrowA, &nentA, &sizesA, &indicesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; rsum2 = isum2 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } rloc = 2*jj ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; rsum0 += ar*br0 + ai*bi0 ; isum0 += ar*bi0 - ai*br0 ; rsum1 += ar*br1 + ai*bi1 ; isum1 += ar*bi1 - ai*br1 ; rsum2 += ar*br2 + ai*bi2 ; isum2 += ar*bi2 - ai*br2 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; colB2[rloc] -= rsum2 ; colB2[iloc] -= isum2 ; } } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } rloc = 2*jj ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; rsum0 += ar*br0 + ai*bi0 ; isum0 += ar*bi0 - ai*br0 ; rsum1 += ar*br1 + ai*bi1 ; isum1 += ar*bi1 - ai*br1 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; } } } else if ( jcolB == ncolB - 1 ) { for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { rsum0 = isum0 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } rloc = 2*jj ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; rsum0 += ar*br0 + ai*bi0 ; isum0 += ar*bi0 - ai*br0 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (I + A^T) X = B, where (1) A is strictly lower triangular (2) X overwrites B (B) B has mode SUBMTX_DENSE_COLUMNS created -- 98may01, cca --------------------------------------- */ static void solveDenseSubrows ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi0, bi1, bi2, br0, br1, br2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int colstart, first, iloc, inc1, inc2, irowA, jcolB, jj, kk, last, ncolB, nentA, nrowA, nrowB, rloc ; int *firstlocsA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_denseSubrowsInfo(mtxA, &nrowA, &nentA, &firstlocsA, &sizesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nrowA = %d, ncolA = %d", nrowA, nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; rloc = 2*irowA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 + ai*bi0 ; colB0[iloc] -= ar*bi0 - ai*br0 ; colB1[rloc] -= ar*br1 + ai*bi1 ; colB1[iloc] -= ar*bi1 - ai*br1 ; colB2[rloc] -= ar*br2 + ai*bi2 ; colB2[iloc] -= ar*bi2 - ai*br2 ; } } } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; rloc = 2*irowA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 + ai*bi0 ; colB0[iloc] -= ar*bi0 - ai*br0 ; colB1[rloc] -= ar*br1 + ai*bi1 ; colB1[iloc] -= ar*bi1 - ai*br1 ; } } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; rloc = 2*irowA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 + ai*bi0 ; colB0[iloc] -= ar*bi0 - ai*br0 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (I + A^T) X = B, where (1) A is strictly lower triangular (2) X overwrites B (B) B has mode SUBMTX_DENSE_COLUMNS created -- 98may01, cca --------------------------------------- */ static void solveSparseRows ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi0, bi1, bi2, br0, br1, br2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int colstart, ii, iloc, inc1, inc2, jcolA, jcolB, jj, kk, ncolB, nentA, nrowA, nrowB, rloc, size ; int *indicesA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_sparseRowsInfo(mtxA, &nrowA, &nentA, &sizesA, &indicesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nrowA = %d, ncolA = %d", nrowA, nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; rloc = 2*jcolA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 + ai*bi0 ; colB0[iloc] -= ar*bi0 - ai*br0 ; colB1[rloc] -= ar*br1 + ai*bi1 ; colB1[iloc] -= ar*bi1 - ai*br1 ; colB2[rloc] -= ar*br2 + ai*bi2 ; colB2[iloc] -= ar*bi2 - ai*br2 ; } } } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; rloc = 2*jcolA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 + ai*bi0 ; colB0[iloc] -= ar*bi0 - ai*br0 ; colB1[rloc] -= ar*br1 + ai*bi1 ; colB1[iloc] -= ar*bi1 - ai*br1 ; } } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; rloc = 2*jcolA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 + ai*bi0 ; colB0[iloc] -= ar*bi0 - ai*br0 ; } } } } return ; } /*--------------------------------------------------------------------*/ *bi2 - ai*br2 ; } rloc = 2*irowA ; iloc = rloc + SubMtx/src/solveT.c010064400020550007177000001047540653410625300155410ustar00clevecompmath00000400000006/* solveT.c */ #include "../SubMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ static void real_solveDenseSubrows ( SubMtx *mtxA, SubMtx *mtxB ) ; static void real_solveDenseSubcolumns ( SubMtx *mtxA, SubMtx *mtxB ) ; static void real_solveSparseRows ( SubMtx *mtxA, SubMtx *mtxB ) ; static void real_solveSparseColumns ( SubMtx *mtxA, SubMtx *mtxB ) ; static void complex_solveDenseSubrows ( SubMtx *mtxA, SubMtx *mtxB ) ; static void complex_solveDenseSubcolumns ( SubMtx *mtxA, SubMtx *mtxB ); static void complex_solveSparseRows ( SubMtx *mtxA, SubMtx *mtxB ) ; static void complex_solveSparseColumns ( SubMtx *mtxA, SubMtx *mtxB ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- solve (A^T + I) X = B, where (1) X overwrites B (2) A must be strict lower or upper triangular (3) columns(A) = rows(X) (4) rows(A) = rows(B) (5) B has type SUBMTX_DENSE_COLUMNS (6) if A is SUBMTX_DENSE_SUBROWS or SUBMTX_SPARSE_ROWS then A must be strict lower triangular (7) if A is SUBMTX_DENSE_SUBCOLUMNS or SUBMTX_SPARSE_COLUMNS then A must be strict upper triangular created -- 98may01, cca ----------------------------------------------------------------- */ void SubMtx_solveT ( SubMtx *mtxA, SubMtx *mtxB ) { /* --------------- check the input --------------- */ if ( mtxA == NULL || mtxB == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_solveT(%p,%p)" "\n bad input\n", mtxA, mtxB) ; exit(-1) ; } if ( ! SUBMTX_IS_DENSE_COLUMNS(mtxB) ) { fprintf(stderr, "\n fatal error in SubMtx_solveT(%p,%p)" "\n mtxB has bad type %d\n", mtxA, mtxB, mtxB->type) ; exit(-1) ; } if ( mtxA->nrow != mtxB->nrow ) { fprintf(stderr, "\n fatal error in SubMtx_solveT(%p,%p)" "\n mtxA->nrow = %d, mtxB->nrwo = %d\n", mtxA, mtxB, mtxA->nrow, mtxB->nrow) ; exit(-1) ; } /* ------------------------- switch over the type of A ------------------------- */ switch ( mtxA->type ) { case SPOOLES_REAL : /* ------------------------- switch over the mode of A ------------------------- */ switch ( mtxA->mode ) { case SUBMTX_DENSE_SUBROWS : real_solveDenseSubrows(mtxA, mtxB) ; break ; case SUBMTX_SPARSE_ROWS : real_solveSparseRows(mtxA, mtxB) ; break ; case SUBMTX_DENSE_SUBCOLUMNS : real_solveDenseSubcolumns(mtxA, mtxB) ; break ; case SUBMTX_SPARSE_COLUMNS : real_solveSparseColumns(mtxA, mtxB) ; break ; default : fprintf(stderr, "\n fatal error in SubMtx_solveT(%p,%p)" "\n bad mode %d\n", mtxA, mtxB, mtxA->mode) ; exit(-1) ; break ; } break ; case SPOOLES_COMPLEX : /* ------------------------- switch over the mode of A ------------------------- */ switch ( mtxA->mode ) { case SUBMTX_DENSE_SUBROWS : complex_solveDenseSubrows(mtxA, mtxB) ; break ; case SUBMTX_SPARSE_ROWS : complex_solveSparseRows(mtxA, mtxB) ; break ; case SUBMTX_DENSE_SUBCOLUMNS : complex_solveDenseSubcolumns(mtxA, mtxB) ; break ; case SUBMTX_SPARSE_COLUMNS : complex_solveSparseColumns(mtxA, mtxB) ; break ; default : fprintf(stderr, "\n fatal error in SubMtx_solveT(%p,%p)" "\n bad mode %d\n", mtxA, mtxB, mtxA->mode) ; exit(-1) ; break ; } break ; default : fprintf(stderr, "\n fatal error in SubMtx_solveT(%p,%p)" "\n bad type %d\n", mtxA, mtxB, mtxA->type) ; exit(-1) ; break ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (A^T + I) X = B, where (1) A is strictly upper triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98feb19, cca --------------------------------------- */ static void real_solveDenseSubcolumns ( SubMtx *mtxA, SubMtx *mtxB ) { double Aki, sum0, sum1, sum2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int first, ii, inc1, inc2, irowA, jcolB, kk, last, ncolB, nentA, nrowA, nrowB ; int *firstlocsA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_denseSubcolumnsInfo(mtxA, &nrowA, &nentA, &firstlocsA, &sizesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nentA = %d", nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + nrowB ; colB2 = colB1 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n %% jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", first %d, last %d", first, last) ; fflush(stdout) ; #endif sum0 = sum1 = sum2 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { Aki = entriesA[kk] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% Aki A(%d,%d) = %12.4e", irowA+1, ii+1, Aki) ; fflush(stdout) ; #endif sum0 += Aki * colB0[ii] ; sum1 += Aki * colB1[ii] ; sum2 += Aki * colB2[ii] ; } colB0[irowA] -= sum0 ; colB1[irowA] -= sum1 ; colB2[irowA] -= sum2 ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %% kk = %d", kk) ; fflush(stdout) ; #endif colB0 = colB2 + nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n %% jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; sum0 = sum1 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { Aki = entriesA[kk] ; sum0 += Aki * colB0[ii] ; sum1 += Aki * colB1[ii] ; } colB0[irowA] -= sum0 ; colB1[irowA] -= sum1 ; } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA = %d, kk = %d, sizesA[%d] = %d", irowA, kk, irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, "\n %% first = %d, last = %d", first, last) ; fflush(stdout) ; #endif sum0 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { Aki = entriesA[kk] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% Aki = %12.4e, colB0[%d] = %12.4e", Aki, ii, colB0[ii]) ; fflush(stdout) ; #endif sum0 += Aki * colB0[ii] ; } colB0[irowA] -= sum0 ; #if MYDEBUG > 0 fprintf(stdout, "\n %% colB0[%d] -= %12.4e", irowA, sum0) ; fflush(stdout) ; #endif } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (A^T + I) X = B, where (1) A is strictly upper triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98feb19, cca --------------------------------------- */ static void real_solveSparseColumns ( SubMtx *mtxA, SubMtx *mtxB ) { double Aki, sum0, sum1, sum2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int ii, inc1, inc2, irowA, jcolB, jj, kk, ncolB, nentA, nrowA, nrowB, size ; int *indicesA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_sparseColumnsInfo(mtxA, &nrowA, &nentA, &sizesA, &indicesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + nrowB ; colB2 = colB1 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { sum0 = sum1 = sum2 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aki = entriesA[kk] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } sum0 += Aki * colB0[jj] ; sum1 += Aki * colB1[jj] ; sum2 += Aki * colB2[jj] ; } colB0[irowA] -= sum0 ; colB1[irowA] -= sum1 ; colB2[irowA] -= sum2 ; } } colB0 = colB2 + nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { sum0 = sum1 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aki = entriesA[kk] ; jj = indicesA[kk] ; sum0 += Aki * colB0[jj] ; sum1 += Aki * colB1[jj] ; } colB0[irowA] -= sum0 ; colB1[irowA] -= sum1 ; } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) >= 0 ) { sum0 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aki = entriesA[kk] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } sum0 += Aki * colB0[jj] ; } colB0[irowA] -= sum0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (I + A^T) X = B, where (1) A is strictly lower triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98feb19, cca --------------------------------------- */ static void real_solveDenseSubrows ( SubMtx *mtxA, SubMtx *mtxB ) { double Aji, Bi0, Bi1, Bi2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int colstart, first, inc1, inc2, irowA, jcolB, jj, kk, last, ncolB, nentA, nrowA, nrowB ; int *firstlocsA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_denseSubrowsInfo(mtxA, &nrowA, &nentA, &firstlocsA, &sizesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nrowA = %d, ncolA = %d", nrowA, nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + nrowB ; colB2 = colB1 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; Bi0 = colB0[irowA] ; Bi1 = colB1[irowA] ; Bi2 = colB2[irowA] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { Aji = entriesA[kk] ; colB0[jj] -= Aji * Bi0 ; colB1[jj] -= Aji * Bi1 ; colB2[jj] -= Aji * Bi2 ; } } } colB0 = colB2 + nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; Bi0 = colB0[irowA] ; Bi1 = colB1[irowA] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { Aji = entriesA[kk] ; colB0[jj] -= Aji * Bi0 ; colB1[jj] -= Aji * Bi1 ; } } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA = %d, sizesA[%d] = %d", irowA, irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; Bi0 = colB0[irowA] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% first %d, last %d, colstart %d, Bi0 = %12.4e", first, last, colstart, Bi0) ; fflush(stdout) ; #endif for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { Aji = entriesA[kk] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% jj %d, kk %d, Aji %12.4e", jj, kk, Aji) ; fflush(stdout) ; #endif colB0[jj] -= Aji * Bi0 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (I + A^T) X = B, where (1) A is strictly lower triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98feb19, cca --------------------------------------- */ static void real_solveSparseRows ( SubMtx *mtxA, SubMtx *mtxB ) { double Aji, Bi0, Bi1, Bi2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int colstart, ii, inc1, inc2, jcolA, jcolB, jj, kk, ncolB, nentA, nrowA, nrowB, size ; int *indicesA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_sparseRowsInfo(mtxA, &nrowA, &nentA, &sizesA, &indicesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nrowA = %d, ncolA = %d", nrowA, nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + nrowB ; colB2 = colB1 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; Bi0 = colB0[jcolA] ; Bi1 = colB1[jcolA] ; Bi2 = colB2[jcolA] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { Aji = entriesA[kk] ; jj = indicesA[kk] ; colB0[jj] -= Aji * Bi0 ; colB1[jj] -= Aji * Bi1 ; colB2[jj] -= Aji * Bi2 ; } } } colB0 = colB2 + nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; Bi0 = colB0[jcolA] ; Bi1 = colB1[jcolA] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { Aji = entriesA[kk] ; jj = indicesA[kk] ; colB0[jj] -= Aji * Bi0 ; colB1[jj] -= Aji * Bi1 ; } } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; Bi0 = colB0[jcolA] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { Aji = entriesA[kk] ; jj = indicesA[kk] ; colB0[jj] -= Aji * Bi0 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (A^T + I) X = B, where (1) A is strictly upper triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca --------------------------------------- */ static void complex_solveDenseSubcolumns ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi0, bi1, bi2, br0, br1, br2, isum0, isum1, isum2, rsum0, rsum1, rsum2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int first, ii, iloc, inc1, inc2, irowA, jcolB, kk, last, ncolB, nentA, nrowA, nrowB, rloc ; int *firstlocsA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_denseSubcolumnsInfo(mtxA, &nrowA, &nentA, &firstlocsA, &sizesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nentA = %d", nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n %% jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", first %d, last %d", first, last) ; fflush(stdout) ; #endif rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; rsum2 = isum2 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% A(%d,%d) = (%12.4e,%12.4e)", irowA+1, ii+1, ar, ai) ; fflush(stdout) ; #endif rloc = 2*ii ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; rsum1 += ar*br1 - ai*bi1 ; isum1 += ar*bi1 + ai*br1 ; rsum2 += ar*br2 - ai*bi2 ; isum2 += ar*bi2 + ai*br2 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; colB2[rloc] -= rsum2 ; colB2[iloc] -= isum2 ; } } #if MYDEBUG > 0 fprintf(stdout, "\n %% kk = %d", kk) ; fflush(stdout) ; #endif colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", first %d, last %d", first, last) ; fflush(stdout) ; #endif rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% A(%d,%d) = (%12.4e,%12.4e)", irowA+1, ii+1, ar, ai) ; fflush(stdout) ; #endif rloc = 2*ii ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; rsum1 += ar*br1 - ai*bi1 ; isum1 += ar*bi1 + ai*br1 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% kk = %d", kk) ; fflush(stdout) ; #endif } } else if ( jcolB == ncolB - 1 ) { for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n %% irowA %d, size %d", irowA, sizesA[irowA]) ; fflush(stdout) ; #endif if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; #if MYDEBUG > 0 fprintf(stdout, ", first %d, last %d", first, last) ; fflush(stdout) ; #endif rsum0 = isum0 = 0.0 ; for ( ii = first ; ii <= last ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% A(%d,%d) = (%12.4e,%12.4e)", irowA+1, ii+1, ar, ai) ; fflush(stdout) ; #endif rloc = 2*ii ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% kk = %d", kk) ; fflush(stdout) ; #endif } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (A^T + I) X = B, where (1) A is strictly upper triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca --------------------------------------- */ static void complex_solveSparseColumns ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi0, bi1, bi2, br0, br1, br2, isum0, isum1, isum2, rsum0, rsum1, rsum2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int ii, iloc, inc1, inc2, irowA, jcolB, jj, kk, ncolB, nentA, nrowA, nrowB, rloc, size ; int *indicesA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_sparseColumnsInfo(mtxA, &nrowA, &nentA, &sizesA, &indicesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; rsum2 = isum2 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } rloc = 2*jj ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; rsum1 += ar*br1 - ai*bi1 ; isum1 += ar*bi1 + ai*br1 ; rsum2 += ar*br2 - ai*bi2 ; isum2 += ar*bi2 + ai*br2 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; colB2[rloc] -= rsum2 ; colB2[iloc] -= isum2 ; } } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { rsum0 = isum0 = 0.0 ; rsum1 = isum1 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } rloc = 2*jj ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; rsum1 += ar*br1 - ai*bi1 ; isum1 += ar*bi1 + ai*br1 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; colB1[rloc] -= rsum1 ; colB1[iloc] -= isum1 ; } } } else if ( jcolB == ncolB - 1 ) { for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizesA[irowA]) > 0 ) { rsum0 = isum0 = 0.0 ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; if ( jj < 0 || jj >= irowA ) { fprintf(stderr, "\n fatal error, irowA = %d, kk =%d, ii = %d, jj = %d", irowA, kk, ii, jj) ; exit(-1) ; } rloc = 2*jj ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; rsum0 += ar*br0 - ai*bi0 ; isum0 += ar*bi0 + ai*br0 ; } rloc = 2*irowA ; iloc = rloc + 1 ; colB0[rloc] -= rsum0 ; colB0[iloc] -= isum0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (I + A^T) X = B, where (1) A is strictly lower triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca --------------------------------------- */ static void complex_solveDenseSubrows ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi0, bi1, bi2, br0, br1, br2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int colstart, first, iloc, inc1, inc2, irowA, jcolB, jj, kk, last, ncolB, nentA, nrowA, nrowB, rloc ; int *firstlocsA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_denseSubrowsInfo(mtxA, &nrowA, &nentA, &firstlocsA, &sizesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nrowA = %d, ncolA = %d", nrowA, nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; rloc = 2*irowA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; colB1[rloc] -= ar*br1 - ai*bi1 ; colB1[iloc] -= ar*bi1 + ai*br1 ; colB2[rloc] -= ar*br2 - ai*bi2 ; colB2[iloc] -= ar*bi2 + ai*br2 ; } } } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; rloc = 2*irowA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; colB1[rloc] -= ar*br1 - ai*bi1 ; colB1[iloc] -= ar*bi1 + ai*br1 ; } } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( irowA = nrowA - 1, colstart = nentA ; irowA >= 0 ; irowA-- ) { if ( sizesA[irowA] > 0 ) { first = firstlocsA[irowA] ; last = first + sizesA[irowA] - 1 ; colstart -= last - first + 1 ; rloc = 2*irowA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; for ( jj = first, kk = colstart ; jj <= last ; jj++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- solve (I + A^T) X = B, where (1) A is strictly lower triangular (2) X overwrites B (B) B has type SUBMTX_DENSE_COLUMNS created -- 98may01, cca --------------------------------------- */ static void complex_solveSparseRows ( SubMtx *mtxA, SubMtx *mtxB ) { double ai, ar, bi0, bi1, bi2, br0, br1, br2 ; double *colB0, *colB1, *colB2, *entriesA, *entriesB ; int colstart, ii, iloc, inc1, inc2, jcolA, jcolB, jj, kk, ncolB, nentA, nrowA, nrowB, rloc, size ; int *indicesA, *sizesA ; /* ---------------------------------------------------- extract the pointer and dimensions from two matrices ---------------------------------------------------- */ SubMtx_sparseRowsInfo(mtxA, &nrowA, &nentA, &sizesA, &indicesA, &entriesA) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entriesB) ; #if MYDEBUG > 0 fprintf(stdout, "\n nrowA = %d, ncolA = %d", nrowA, nentA) ; fflush(stdout) ; #endif colB0 = entriesB ; for ( jcolB = 0 ; jcolB < ncolB - 2 ; jcolB += 3 ) { colB1 = colB0 + 2*nrowB ; colB2 = colB1 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; rloc = 2*jcolA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; br2 = colB2[rloc] ; bi2 = colB2[iloc] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; colB1[rloc] -= ar*br1 - ai*bi1 ; colB1[iloc] -= ar*bi1 + ai*br1 ; colB2[rloc] -= ar*br2 - ai*bi2 ; colB2[iloc] -= ar*bi2 + ai*br2 ; } } } colB0 = colB2 + 2*nrowB ; } if ( jcolB == ncolB - 2 ) { colB1 = colB0 + 2*nrowB ; #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; rloc = 2*jcolA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; br1 = colB1[rloc] ; bi1 = colB1[iloc] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; colB1[rloc] -= ar*br1 - ai*bi1 ; colB1[iloc] -= ar*bi1 + ai*br1 ; } } } } else if ( jcolB == ncolB - 1 ) { #if MYDEBUG > 0 fprintf(stdout, "\n jcolB = %d", jcolB) ; fflush(stdout) ; #endif for ( jcolA = nrowA - 1, colstart = nentA ; jcolA >= 0 ; jcolA-- ) { if ( (size = sizesA[jcolA]) > 0 ) { colstart -= size ; rloc = 2*jcolA ; iloc = rloc + 1 ; br0 = colB0[rloc] ; bi0 = colB0[iloc] ; for ( ii = 0, kk = colstart ; ii < size ; ii++, kk++ ) { ar = entriesA[2*kk] ; ai = entriesA[2*kk+1] ; jj = indicesA[kk] ; rloc = 2*jj ; iloc = rloc + 1 ; colB0[rloc] -= ar*br0 - ai*bi0 ; colB0[iloc] -= ar*bi0 + ai*br0 ; } } } } return ; } /*--------------------------------------------------------------------*/ } SubMtx/src/solveupd.c010064400020550007177000002601370653410625200161230ustar00clevecompmath00000400000006/* solveupd.c */ #include "../SubMtx.h" /*--------------------------------------------------------------------*/ static void real_updDenseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void real_updDenseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void real_updSparseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void real_updSparseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void complex_updDenseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void complex_updDenseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void complex_updSparseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void complex_updSparseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- perform the matrix-matrix multiply Y := Y - A * X used in the forward and backsolves where (1) rows(A) \subseteq rows(Y) (2) rows(A) are local w.r.t. rows(Y) (3) cols(A) \subseteq rows(X) (4) cols(A) are local w.r.t. rows(X) (5) cols(Y) = cols(X) (6) Y and X have mode SUBMTX_DENSE_COLUMNS created -- 98may02, cca ---------------------------------------------------- */ void SubMtx_solveupd ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { /* --------------- check the input --------------- */ if ( mtxY == NULL || mtxA == NULL || mtxX == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_solveupd(%p,%p,%p)" "\n bad input\n", mtxY, mtxA, mtxX) ; exit(-1) ; } if ( mtxY->mode != SUBMTX_DENSE_COLUMNS ) { fprintf(stderr, "\n fatal error in SubMtx_solveupd(%p,%p,%p)" "\n Y must have mode SUBMTX_DENSE_COLUMNS\n", mtxY, mtxA, mtxX) ; exit(-1) ; } if ( mtxX->mode != SUBMTX_DENSE_COLUMNS ) { fprintf(stderr, "\n fatal error in SubMtx_solveupd(%p,%p,%p)" "\n X must have mode SUBMTX_DENSE_COLUMNS\n", mtxY, mtxA, mtxX) ; exit(-1) ; } switch ( mtxA->type ) { case SPOOLES_REAL : switch ( mtxA->mode ) { case SUBMTX_DENSE_COLUMNS : real_updDenseColumns(mtxY, mtxA, mtxX) ; break ; case SUBMTX_DENSE_ROWS : real_updDenseRows(mtxY, mtxA, mtxX) ; break ; case SUBMTX_SPARSE_ROWS : real_updSparseRows(mtxY, mtxA, mtxX) ; break ; case SUBMTX_SPARSE_COLUMNS : real_updSparseColumns(mtxY, mtxA, mtxX) ; break ; default : fprintf(stderr, "\n fatal error in SubMtx_solveupd(%p,%p,%p)" "\n unsupported mode %d for A\n", mtxY, mtxA, mtxX, mtxA->mode) ; exit(-1) ; break ; } break ; case SPOOLES_COMPLEX : switch ( mtxA->mode ) { case SUBMTX_DENSE_COLUMNS : complex_updDenseColumns(mtxY, mtxA, mtxX) ; break ; case SUBMTX_DENSE_ROWS : complex_updDenseRows(mtxY, mtxA, mtxX) ; break ; case SUBMTX_SPARSE_ROWS : complex_updSparseRows(mtxY, mtxA, mtxX) ; break ; case SUBMTX_SPARSE_COLUMNS : complex_updSparseColumns(mtxY, mtxA, mtxX) ; break ; default : fprintf(stderr, "\n fatal error in SubMtx_solveupd(%p,%p,%p)" "\n unsupported mode %d for A\n", mtxY, mtxA, mtxX, mtxA->mode) ; SubMtx_writeForHumanEye(mtxA, stderr) ; exit(-1) ; break ; } break ; default : fprintf(stderr, "\n fatal error in SubMtx_solveupd(%p,%p,%p)" "\n unsupported type %d for A\n", mtxY, mtxA, mtxX, mtxA->type) ; exit(-1) ; break ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------- A has dense columns ------------------- */ static void real_updDenseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double Ak0, Ak1, Ak2, x00, x01, x02, x10, x11, x12, x20, x21, x22 ; double *colA0, *colA1, *colA2, *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int icolA, inc1, inc2, irowX, jcolX, krowA, krowY, ncolA, ncolX, ncolY, nrowA, nrowX, nrowY ; int *colindA, *rowindA ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_denseInfo(mtxA, &nrowA, &ncolA, &inc1, &inc2, &entA) ; colX0 = entX ; colY0 = entY ; if ( ncolA != nrowX ) { SubMtx_columnIndices(mtxA, &ncolA, &colindA) ; } else { colindA = NULL ; } if ( nrowA != nrowY ) { SubMtx_rowIndices(mtxA, &nrowA, &rowindA) ; } else { rowindA = NULL ; } for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + nrowX ; colX2 = colX1 + nrowX ; colY1 = colY0 + nrowY ; colY2 = colY1 + nrowY ; colA0 = entA ; for ( icolA = 0 ; icolA < ncolA - 2 ; icolA += 3 ) { colA1 = colA0 + nrowA ; colA2 = colA1 + nrowA ; if ( ncolA == nrowX ) { x00 = colX0[icolA] ; x01 = colX1[icolA] ; x02 = colX2[icolA] ; x10 = colX0[icolA+1] ; x11 = colX1[icolA+1] ; x12 = colX2[icolA+1] ; x20 = colX0[icolA+2] ; x21 = colX1[icolA+2] ; x22 = colX2[icolA+2] ; } else { irowX = colindA[icolA] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; x02 = colX2[irowX] ; irowX = colindA[icolA+1] ; x10 = colX0[irowX] ; x11 = colX1[irowX] ; x12 = colX2[irowX] ; irowX = colindA[icolA+2] ; x20 = colX0[irowX] ; x21 = colX1[irowX] ; x22 = colX2[irowX] ; } if ( nrowY == nrowA ) { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; Ak2 = colA2[krowA] ; colY0[krowA] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; colY1[krowA] -= Ak0 * x01 + Ak1 * x11 + Ak2 * x21 ; colY2[krowA] -= Ak0 * x02 + Ak1 * x12 + Ak2 * x22 ; } } else { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; Ak2 = colA2[krowA] ; krowY = rowindA[krowA] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; colY1[krowY] -= Ak0 * x01 + Ak1 * x11 + Ak2 * x21 ; colY2[krowY] -= Ak0 * x02 + Ak1 * x12 + Ak2 * x22 ; } } colA0 = colA2 + nrowA ; } if ( icolA == ncolA - 2 ) { colA1 = colA0 + nrowA ; if ( ncolA == nrowX ) { x00 = colX0[icolA] ; x01 = colX1[icolA] ; x02 = colX2[icolA] ; x10 = colX0[icolA+1] ; x11 = colX1[icolA+1] ; x12 = colX2[icolA+1] ; } else { irowX = colindA[icolA] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; x02 = colX2[irowX] ; irowX = colindA[icolA+1] ; x10 = colX0[irowX] ; x11 = colX1[irowX] ; x12 = colX2[irowX] ; } if ( nrowY == nrowA ) { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; colY0[krowA] -= Ak0 * x00 + Ak1 * x10 ; colY1[krowA] -= Ak0 * x01 + Ak1 * x11 ; colY2[krowA] -= Ak0 * x02 + Ak1 * x12 ; } } else { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; krowY = rowindA[krowA] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 ; colY1[krowY] -= Ak0 * x01 + Ak1 * x11 ; colY2[krowY] -= Ak0 * x02 + Ak1 * x12 ; } } } else if ( icolA == ncolA - 1 ) { if ( ncolA == nrowX ) { x00 = colX0[icolA] ; x01 = colX1[icolA] ; x02 = colX2[icolA] ; } else { irowX = colindA[icolA] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; x02 = colX2[irowX] ; } if ( nrowY == nrowA ) { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; colY0[krowA] -= Ak0 * x00 ; colY1[krowA] -= Ak0 * x01 ; colY2[krowA] -= Ak0 * x02 ; } } else { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; krowY = rowindA[krowA] ; colY0[krowY] -= Ak0 * x00 ; colY1[krowY] -= Ak0 * x01 ; colY2[krowY] -= Ak0 * x02 ; } } } colX0 = colX2 + nrowX ; colY0 = colY2 + nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + nrowX ; colY1 = colY0 + nrowY ; colA0 = entA ; for ( icolA = 0 ; icolA < ncolA - 2 ; icolA += 3 ) { colA1 = colA0 + nrowA ; colA2 = colA1 + nrowA ; if ( ncolA == nrowX ) { x00 = colX0[icolA] ; x01 = colX1[icolA] ; x10 = colX0[icolA+1] ; x11 = colX1[icolA+1] ; x20 = colX0[icolA+2] ; x21 = colX1[icolA+2] ; } else { irowX = colindA[icolA] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; irowX = colindA[icolA+1] ; x10 = colX0[irowX] ; x11 = colX1[irowX] ; irowX = colindA[icolA+2] ; x20 = colX0[irowX] ; x21 = colX1[irowX] ; } if ( nrowY == nrowA ) { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; Ak2 = colA2[krowA] ; colY0[krowA] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; colY1[krowA] -= Ak0 * x01 + Ak1 * x11 + Ak2 * x21 ; } } else { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; Ak2 = colA2[krowA] ; krowY = rowindA[krowA] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; colY1[krowY] -= Ak0 * x01 + Ak1 * x11 + Ak2 * x21 ; } } colA0 = colA2 + nrowA ; } if ( icolA == ncolA - 2 ) { colA1 = colA0 + nrowA ; if ( ncolA == nrowX ) { x00 = colX0[icolA] ; x01 = colX1[icolA] ; x10 = colX0[icolA+1] ; x11 = colX1[icolA+1] ; } else { irowX = colindA[icolA] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; irowX = colindA[icolA+1] ; x10 = colX0[irowX] ; x11 = colX1[irowX] ; } if ( nrowY == nrowA ) { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; colY0[krowA] -= Ak0 * x00 + Ak1 * x10 ; colY1[krowA] -= Ak0 * x01 + Ak1 * x11 ; } } else { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; krowY = rowindA[krowA] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 ; colY1[krowY] -= Ak0 * x01 + Ak1 * x11 ; } } } else if ( icolA == ncolA - 1 ) { if ( ncolA == nrowX ) { x00 = colX0[icolA] ; x01 = colX1[icolA] ; } else { irowX = colindA[icolA] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; } if ( nrowY == nrowA ) { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; colY0[krowA] -= Ak0 * x00 ; colY1[krowA] -= Ak0 * x01 ; } } else { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; krowY = rowindA[krowA] ; colY0[krowY] -= Ak0 * x00 ; colY1[krowY] -= Ak0 * x01 ; } } } } else if ( jcolX == ncolX - 1 ) { colA0 = entA ; for ( icolA = 0 ; icolA < ncolA - 2 ; icolA += 3 ) { colA1 = colA0 + nrowA ; colA2 = colA1 + nrowA ; if ( ncolA == nrowX ) { x00 = colX0[icolA] ; x10 = colX0[icolA+1] ; x20 = colX0[icolA+2] ; } else { irowX = colindA[icolA] ; x00 = colX0[irowX] ; irowX = colindA[icolA+1] ; x10 = colX0[irowX] ; irowX = colindA[icolA+2] ; x20 = colX0[irowX] ; } if ( nrowY == nrowA ) { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; Ak2 = colA2[krowA] ; colY0[krowA] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; } } else { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; Ak2 = colA2[krowA] ; krowY = rowindA[krowA] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; } } colA0 = colA2 + nrowA ; } if ( icolA == ncolA - 2 ) { colA1 = colA0 + nrowA ; if ( ncolA == nrowX ) { x00 = colX0[icolA] ; x10 = colX0[icolA+1] ; } else { irowX = colindA[icolA] ; x00 = colX0[irowX] ; irowX = colindA[icolA+1] ; x10 = colX0[irowX] ; } if ( nrowY == nrowA ) { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; colY0[krowA] -= Ak0 * x00 + Ak1 * x10 ; } } else { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; Ak1 = colA1[krowA] ; krowY = rowindA[krowA] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 ; } } } else if ( icolA == ncolA - 1 ) { if ( ncolA == nrowX ) { x00 = colX0[icolA] ; } else { irowX = colindA[icolA] ; x00 = colX0[irowX] ; } if ( nrowY == nrowA ) { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; colY0[krowA] -= Ak0 * x00 ; } } else { for ( krowA = 0 ; krowA < nrowA ; krowA++ ) { Ak0 = colA0[krowA] ; krowY = rowindA[krowA] ; colY0[krowY] -= Ak0 * x00 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------- A has dense rows ---------------- */ static void real_updDenseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *rowA0, *rowA1, *rowA2, *entA, *entX, *entY ; int inc1, inc2, irowA, irowY, jcolX, kcolA, krowX, ncolA, ncolX, ncolY, nrowA, nrowX, nrowY ; int *colindA, *rowindA ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_denseInfo(mtxA, &nrowA, &ncolA, &inc1, &inc2, &entA) ; if ( ncolA != nrowX ) { SubMtx_columnIndices(mtxA, &ncolA, &colindA) ; } else { colindA = NULL ; } if ( nrowA != nrowY ) { SubMtx_rowIndices(mtxA, &nrowA, &rowindA) ; } else { rowindA = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + nrowX ; colX2 = colX1 + nrowX ; colY1 = colY0 + nrowY ; colY2 = colY1 + nrowY ; rowA0 = entA ; for ( irowA = 0 ; irowA < nrowA - 2 ; irowA += 3 ) { double A0k, A1k, A2k, Xk0, Xk1, Xk2 ; double sum00, sum01, sum02, sum10, sum11, sum12, sum20, sum21, sum22 ; sum00 = sum01 = sum02 = sum10 = sum11 = sum12 = sum20 = sum21 = sum22 = 0.0 ; rowA1 = rowA0 + ncolA ; rowA2 = rowA1 + ncolA ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; A2k = rowA2[kcolA] ; Xk0 = colX0[kcolA] ; Xk1 = colX1[kcolA] ; Xk2 = colX2[kcolA] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum12 += A1k * Xk2 ; sum20 += A2k * Xk0 ; sum21 += A2k * Xk1 ; sum22 += A2k * Xk2 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; A2k = rowA2[kcolA] ; krowX = colindA[kcolA] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; Xk2 = colX2[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum12 += A1k * Xk2 ; sum20 += A2k * Xk0 ; sum21 += A2k * Xk1 ; sum22 += A2k * Xk2 ; } } if ( nrowY == nrowA ) { colY0[irowA] -= sum00 ; colY1[irowA] -= sum01 ; colY2[irowA] -= sum02 ; colY0[irowA+1] -= sum10 ; colY1[irowA+1] -= sum11 ; colY2[irowA+1] -= sum12 ; colY0[irowA+2] -= sum20 ; colY1[irowA+2] -= sum21 ; colY2[irowA+2] -= sum22 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; colY2[irowY] -= sum02 ; irowY = rowindA[irowA+1] ; colY0[irowY] -= sum10 ; colY1[irowY] -= sum11 ; colY2[irowY] -= sum12 ; irowY = rowindA[irowA+2] ; colY0[irowY] -= sum20 ; colY1[irowY] -= sum21 ; colY2[irowY] -= sum22 ; } rowA0 = rowA2 + ncolA ; } if ( irowA == nrowA - 2 ) { double A0k, A1k, Xk0, Xk1, Xk2 ; double sum00, sum01, sum02, sum10, sum11, sum12 ; sum00 = sum01 = sum02 = sum10 = sum11 = sum12 = 0.0 ; rowA1 = rowA0 + ncolA ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; Xk0 = colX0[kcolA] ; Xk1 = colX1[kcolA] ; Xk2 = colX2[kcolA] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum12 += A1k * Xk2 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; krowX = colindA[kcolA] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; Xk2 = colX2[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum12 += A1k * Xk2 ; } } if ( nrowY == nrowA ) { colY0[irowA] -= sum00 ; colY1[irowA] -= sum01 ; colY2[irowA] -= sum02 ; colY0[irowA+1] -= sum10 ; colY1[irowA+1] -= sum11 ; colY2[irowA+1] -= sum12 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; colY2[irowY] -= sum02 ; irowY = rowindA[irowA+1] ; colY0[irowY] -= sum10 ; colY1[irowY] -= sum11 ; colY2[irowY] -= sum12 ; } } else if ( irowA == nrowA - 1 ) { double A0k, Xk0, Xk1, Xk2 ; double sum00, sum01, sum02 ; sum00 = sum01 = sum02 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; Xk0 = colX0[kcolA] ; Xk1 = colX1[kcolA] ; Xk2 = colX2[kcolA] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; krowX = colindA[kcolA] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; Xk2 = colX2[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; } } if ( nrowY == nrowA ) { colY0[irowA] -= sum00 ; colY1[irowA] -= sum01 ; colY2[irowA] -= sum02 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; colY2[irowY] -= sum02 ; } } colX0 = colX2 + nrowX ; colY0 = colY2 + nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + nrowX ; colY1 = colY0 + nrowY ; rowA0 = entA ; for ( irowA = 0 ; irowA < nrowA - 2 ; irowA += 3 ) { double A0k, A1k, A2k, Xk0, Xk1 ; double sum00, sum01, sum10, sum11, sum20, sum21 ; sum00 = sum01 = sum10 = sum11 = sum20 = sum21 = 0.0 ; rowA1 = rowA0 + ncolA ; rowA2 = rowA1 + ncolA ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; A2k = rowA2[kcolA] ; Xk0 = colX0[kcolA] ; Xk1 = colX1[kcolA] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum20 += A2k * Xk0 ; sum21 += A2k * Xk1 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; A2k = rowA2[kcolA] ; krowX = colindA[kcolA] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum20 += A2k * Xk0 ; sum21 += A2k * Xk1 ; } } if ( nrowY == nrowA ) { colY0[irowA] -= sum00 ; colY1[irowA] -= sum01 ; colY0[irowA+1] -= sum10 ; colY1[irowA+1] -= sum11 ; colY0[irowA+2] -= sum20 ; colY1[irowA+2] -= sum21 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; irowY = rowindA[irowA+1] ; colY0[irowY] -= sum10 ; colY1[irowY] -= sum11 ; irowY = rowindA[irowA+2] ; colY0[irowY] -= sum20 ; colY1[irowY] -= sum21 ; } rowA0 = rowA2 + ncolA ; } if ( irowA == nrowA - 2 ) { double A0k, A1k, Xk0, Xk1 ; double sum00, sum01, sum10, sum11 ; sum00 = sum01 = sum10 = sum11 = 0.0 ; rowA1 = rowA0 + ncolA ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; Xk0 = colX0[kcolA] ; Xk1 = colX1[kcolA] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; krowX = colindA[kcolA] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; } } if ( nrowY == nrowA ) { colY0[irowA] -= sum00 ; colY1[irowA] -= sum01 ; colY0[irowA+1] -= sum10 ; colY1[irowA+1] -= sum11 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; irowY = rowindA[irowA+1] ; colY0[irowY] -= sum10 ; colY1[irowY] -= sum11 ; } } else if ( irowA == nrowA - 1 ) { double A0k, Xk0, Xk1 ; double sum00, sum01 ; sum00 = sum01 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; Xk0 = colX0[kcolA] ; Xk1 = colX1[kcolA] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; krowX = colindA[kcolA] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; } } if ( nrowY == nrowA ) { colY0[irowA] -= sum00 ; colY1[irowA] -= sum01 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; } } } else if ( jcolX == ncolX - 1 ) { rowA0 = entA ; for ( irowA = 0 ; irowA < nrowA - 2 ; irowA += 3 ) { double A0k, A1k, A2k, Xk0 ; double sum00, sum10, sum20 ; sum00 = sum10 = sum20 = 0.0 ; rowA1 = rowA0 + ncolA ; rowA2 = rowA1 + ncolA ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; A2k = rowA2[kcolA] ; Xk0 = colX0[kcolA] ; sum00 += A0k * Xk0 ; sum10 += A1k * Xk0 ; sum20 += A2k * Xk0 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; A2k = rowA2[kcolA] ; krowX = colindA[kcolA] ; Xk0 = colX0[krowX] ; sum00 += A0k * Xk0 ; sum10 += A1k * Xk0 ; sum20 += A2k * Xk0 ; } } if ( nrowY == nrowA ) { colY0[irowA] -= sum00 ; colY0[irowA+1] -= sum10 ; colY0[irowA+2] -= sum20 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum00 ; irowY = rowindA[irowA+1] ; colY0[irowY] -= sum10 ; irowY = rowindA[irowA+2] ; colY0[irowY] -= sum20 ; } rowA0 = rowA2 + ncolA ; } if ( irowA == nrowA - 2 ) { double A0k, A1k, Xk0 ; double sum00, sum10 ; sum00 = sum10 = 0.0 ; rowA1 = rowA0 + ncolA ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; Xk0 = colX0[kcolA] ; sum00 += A0k * Xk0 ; sum10 += A1k * Xk0 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; A1k = rowA1[kcolA] ; krowX = colindA[kcolA] ; Xk0 = colX0[krowX] ; sum00 += A0k * Xk0 ; sum10 += A1k * Xk0 ; } } if ( nrowY == nrowA ) { colY0[irowA] -= sum00 ; colY0[irowA+1] -= sum10 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum00 ; irowY = rowindA[irowA+1] ; colY0[irowY] -= sum10 ; } } else if ( irowA == nrowA - 1 ) { double A0k, Xk0 ; double sum00 ; sum00 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; Xk0 = colX0[kcolA] ; sum00 += A0k * Xk0 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { A0k = rowA0[kcolA] ; krowX = colindA[kcolA] ; Xk0 = colX0[krowX] ; sum00 += A0k * Xk0 ; } } if ( nrowY == nrowA ) { colY0[irowA] -= sum00 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum00 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------- A has sparse rows ----------------- */ static void real_updSparseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double Aik, sum0, sum1, sum2 ; double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int ii, inc1, inc2, irowA, irowY, jcolX, kk, krowX, ncolA, ncolX, ncolY, nentA, nrowA, nrowX, nrowY, size ; int *colindA, *indices, *rowindA, *sizes ; /* fprintf(stdout, "\n UPDATE_SPARSE_ROWS(%d,%d)", mtxA->rowid, mtxA->colid) ; */ SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_sparseRowsInfo(mtxA, &nrowA, &nentA, &sizes, &indices, &entA) ; if ( (ncolA = mtxA->ncol) != nrowX ) { SubMtx_columnIndices(mtxA, &ncolA, &colindA) ; } else { colindA = NULL ; } if ( nrowA != nrowY ) { SubMtx_rowIndices(mtxA, &nrowA, &rowindA) ; } else { rowindA = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + nrowX ; colX2 = colX1 + nrowX ; colY1 = colY0 + nrowY ; colY2 = colY1 + nrowY ; for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizes[irowA]) > 0 ) { sum0 = sum1 = sum2 = 0.0 ; if ( ncolA == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = indices[kk] ; sum0 += Aik * colX0[krowX] ; sum1 += Aik * colX1[krowX] ; sum2 += Aik * colX2[krowX] ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = colindA[indices[kk]] ; sum0 += Aik * colX0[krowX] ; sum1 += Aik * colX1[krowX] ; sum2 += Aik * colX2[krowX] ; } } if ( nrowA == nrowY ) { colY0[irowA] -= sum0 ; colY1[irowA] -= sum1 ; colY2[irowA] -= sum2 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum0 ; colY1[irowY] -= sum1 ; colY2[irowY] -= sum2 ; } } } colX0 = colX2 + nrowX ; colY0 = colY2 + nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + nrowX ; colY1 = colY0 + nrowY ; for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizes[irowA]) > 0 ) { sum0 = sum1 = 0.0 ; if ( ncolA == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = indices[kk] ; sum0 += Aik * colX0[krowX] ; sum1 += Aik * colX1[krowX] ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = colindA[indices[kk]] ; sum0 += Aik * colX0[krowX] ; sum1 += Aik * colX1[krowX] ; } } if ( nrowA == nrowY ) { colY0[irowA] -= sum0 ; colY1[irowA] -= sum1 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum0 ; colY1[irowY] -= sum1 ; } } } } else if ( jcolX == ncolX - 1 ) { for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizes[irowA]) > 0 ) { sum0 = 0.0 ; if ( ncolA == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = indices[kk] ; sum0 += Aik * colX0[krowX] ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = colindA[indices[kk]] ; sum0 += Aik * colX0[krowX] ; } } if ( nrowA == nrowY ) { colY0[irowA] -= sum0 ; } else { irowY = rowindA[irowA] ; colY0[irowY] -= sum0 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------- A has sparse columns -------------------- */ static void real_updSparseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double Aij, Xj0, Xj1, Xj2 ; double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int ii, inc1, inc2, irowY, jcolA, jcolX, jrowX, kk, ncolA, ncolX, ncolY, nentA, nrowA, nrowX, nrowY, size ; int *colindA, *indices, *rowindA, *sizes ; /* fprintf(stdout, "\n UPDATE_SPARSE_COLUMNS(%d,%d)", mtxA->rowid, mtxA->colid) ; */ SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_sparseColumnsInfo(mtxA, &ncolA, &nentA, &sizes, &indices, &entA) ; if ( ncolA != nrowX ) { SubMtx_columnIndices(mtxA, &ncolA, &colindA) ; } else { colindA = NULL ; } if ( (nrowA = mtxA->nrow) != nrowY ) { SubMtx_rowIndices(mtxA, &nrowA, &rowindA) ; } else { rowindA = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + nrowX ; colX2 = colX1 + nrowX ; colY1 = colY0 + nrowY ; colY2 = colY1 + nrowY ; for ( jcolA = kk = 0 ; jcolA < ncolA ; jcolA++ ) { if ( (size = sizes[jcolA]) > 0 ) { if ( ncolA == nrowX ) { jrowX = jcolA ; } else { jrowX = colindA[jcolA] ; } Xj0 = colX0[jrowX] ; Xj1 = colX1[jrowX] ; Xj2 = colX2[jrowX] ; if ( nrowA == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = indices[kk] ; colY0[irowY] -= Aij * Xj0 ; colY1[irowY] -= Aij * Xj1 ; colY2[irowY] -= Aij * Xj2 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = rowindA[indices[kk]] ; colY0[irowY] -= Aij * Xj0 ; colY1[irowY] -= Aij * Xj1 ; colY2[irowY] -= Aij * Xj2 ; } } } } colX0 = colX2 + nrowX ; colY0 = colY2 + nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + nrowX ; colY1 = colY0 + nrowY ; for ( jcolA = kk = 0 ; jcolA < ncolA ; jcolA++ ) { if ( (size = sizes[jcolA]) > 0 ) { if ( ncolA == nrowX ) { jrowX = jcolA ; } else { jrowX = colindA[jcolA] ; } Xj0 = colX0[jrowX] ; Xj1 = colX1[jrowX] ; if ( nrowA == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = indices[kk] ; colY0[irowY] -= Aij * Xj0 ; colY1[irowY] -= Aij * Xj1 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = rowindA[indices[kk]] ; colY0[irowY] -= Aij * Xj0 ; colY1[irowY] -= Aij * Xj1 ; } } } } } else if ( jcolX == ncolX - 1 ) { for ( jcolA = kk = 0 ; jcolA < ncolA ; jcolA++ ) { if ( (size = sizes[jcolA]) > 0 ) { if ( ncolA == nrowX ) { jrowX = jcolA ; } else { jrowX = colindA[jcolA] ; } Xj0 = colX0[jrowX] ; if ( nrowA == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = indices[kk] ; colY0[irowY] -= Aij * Xj0 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = rowindA[indices[kk]] ; colY0[irowY] -= Aij * Xj0 ; } } } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------- A has dense columns ------------------- */ static void complex_updDenseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double ai0, ai1, ai2, ar0, ar1, ar2, xi00, xi01, xi02, xi10, xi11, xi12, xi20, xi21, xi22, xr00, xr01, xr02, xr10, xr11, xr12, xr20, xr21, xr22 ; double *colA0, *colA1, *colA2, *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int icolA, iloc, inc1, inc2, iyloc, jcolX, krowA, krowY, ncolA, ncolX, ncolY, nrowA, nrowX, nrowY, rloc, ryloc ; int *colindA, *rowindA ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_denseInfo(mtxA, &nrowA, &ncolA, &inc1, &inc2, &entA) ; colX0 = entX ; colY0 = entY ; if ( ncolA != nrowX ) { SubMtx_columnIndices(mtxA, &ncolA, &colindA) ; } else { colindA = NULL ; } if ( nrowA != nrowY ) { SubMtx_rowIndices(mtxA, &nrowA, &rowindA) ; } else { rowindA = NULL ; } for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; colA0 = entA ; for ( icolA = 0 ; icolA < ncolA - 2 ; icolA += 3 ) { colA1 = colA0 + 2*nrowA ; colA2 = colA1 + 2*nrowA ; if ( ncolA == nrowX ) { rloc = 2*icolA ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc += 2, iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc += 2, iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } else { rloc = 2*colindA[icolA] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc = 2*colindA[icolA+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc = 2*colindA[icolA+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } if ( nrowY == nrowA ) { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; ar2 = colA2[rloc] ; ai2 = colA2[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 + ar2*xr21 - ai2*xi21 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 + ar2*xi21 + ai2*xr21 ; colY2[rloc] -= ar0*xr02 - ai0*xi02 + ar1*xr12 - ai1*xi12 + ar2*xr22 - ai2*xi22 ; colY2[iloc] -= ar0*xi02 + ai0*xr02 + ar1*xi12 + ai1*xr12 + ar2*xi22 + ai2*xr22 ; } } else { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; ar2 = colA2[rloc] ; ai2 = colA2[iloc] ; krowY = rowindA[krowA] ; ryloc = 2*rowindA[krowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iyloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; colY1[ryloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 + ar2*xr21 - ai2*xi21 ; colY1[iyloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 + ar2*xi21 + ai2*xr21 ; colY2[ryloc] -= ar0*xr02 - ai0*xi02 + ar1*xr12 - ai1*xi12 + ar2*xr22 - ai2*xi22 ; colY2[iyloc] -= ar0*xi02 + ai0*xr02 + ar1*xi12 + ai1*xr12 + ar2*xi22 + ai2*xr22 ; } } colA0 = colA2 + 2*nrowA ; } if ( icolA == ncolA - 2 ) { colA1 = colA0 + 2*nrowA ; if ( ncolA == nrowX ) { rloc = 2*icolA ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc += 2, iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; } else { rloc = 2*colindA[icolA] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc = 2*colindA[icolA+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; } if ( nrowY == nrowA ) { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 ; colY2[rloc] -= ar0*xr02 - ai0*xi02 + ar1*xr12 - ai1*xi12 ; colY2[iloc] -= ar0*xi02 + ai0*xr02 + ar1*xi12 + ai1*xr12 ; } } else { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; krowY = rowindA[krowA] ; ryloc = 2*rowindA[krowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iyloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; colY1[ryloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 ; colY1[iyloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 ; colY2[ryloc] -= ar0*xr02 - ai0*xi02 + ar1*xr12 - ai1*xi12 ; colY2[iyloc] -= ar0*xi02 + ai0*xr02 + ar1*xi12 + ai1*xr12 ; } } } else if ( icolA == ncolA - 1 ) { if ( ncolA == nrowX ) { rloc = 2*icolA ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; } else { rloc = 2*colindA[icolA] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; } if ( nrowY == nrowA ) { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 ; colY2[rloc] -= ar0*xr02 - ai0*xi02 ; colY2[iloc] -= ar0*xi02 + ai0*xr02 ; } } else { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; krowY = rowindA[krowA] ; ryloc = 2*rowindA[krowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= ar0*xr00 - ai0*xi00 ; colY0[iyloc] -= ar0*xi00 + ai0*xr00 ; colY1[ryloc] -= ar0*xr01 - ai0*xi01 ; colY1[iyloc] -= ar0*xi01 + ai0*xr01 ; colY2[ryloc] -= ar0*xr02 - ai0*xi02 ; colY2[iyloc] -= ar0*xi02 + ai0*xr02 ; } } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colA0 = entA ; for ( icolA = 0 ; icolA < ncolA - 2 ; icolA += 3 ) { colA1 = colA0 + 2*nrowA ; colA2 = colA1 + 2*nrowA ; if ( ncolA == nrowX ) { rloc = 2*icolA ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc += 2, iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc += 2, iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } else { rloc = 2*colindA[icolA] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc = 2*colindA[icolA+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc = 2*colindA[icolA+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } if ( nrowY == nrowA ) { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; ar2 = colA2[rloc] ; ai2 = colA2[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 + ar2*xr21 - ai2*xi21 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 + ar2*xi21 + ai2*xr21 ; } } else { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; ar2 = colA2[rloc] ; ai2 = colA2[iloc] ; krowY = rowindA[krowA] ; ryloc = 2*rowindA[krowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iyloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; colY1[ryloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 + ar2*xr21 - ai2*xi21 ; colY1[iyloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 + ar2*xi21 + ai2*xr21 ; } } colA0 = colA2 + 2*nrowA ; } if ( icolA == ncolA - 2 ) { colA1 = colA0 + 2*nrowA ; if ( ncolA == nrowX ) { rloc = 2*icolA ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc += 2, iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; } else { rloc = 2*colindA[icolA] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc = 2*colindA[icolA+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; } if ( nrowY == nrowA ) { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 ; } } else { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; krowY = rowindA[krowA] ; ryloc = 2*rowindA[krowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iyloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; colY1[ryloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 ; colY1[iyloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 ; } } } else if ( icolA == ncolA - 1 ) { if ( ncolA == nrowX ) { rloc = 2*icolA ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; } else { rloc = 2*colindA[icolA] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; } if ( nrowY == nrowA ) { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 ; } } else { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; krowY = rowindA[krowA] ; ryloc = 2*rowindA[krowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= ar0*xr00 - ai0*xi00 ; colY0[iyloc] -= ar0*xi00 + ai0*xr00 ; colY1[ryloc] -= ar0*xr01 - ai0*xi01 ; colY1[iyloc] -= ar0*xi01 + ai0*xr01 ; } } } } else if ( jcolX == ncolX - 1 ) { colA0 = entA ; for ( icolA = 0 ; icolA < ncolA - 2 ; icolA += 3 ) { colA1 = colA0 + 2*nrowA ; colA2 = colA1 + 2*nrowA ; if ( ncolA == nrowX ) { rloc = 2*icolA ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc += 2, iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc += 2, iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } else { rloc = 2*colindA[icolA] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc = 2*colindA[icolA+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc = 2*colindA[icolA+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } if ( nrowY == nrowA ) { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; ar2 = colA2[rloc] ; ai2 = colA2[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; } } else { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; ar2 = colA2[rloc] ; ai2 = colA2[iloc] ; krowY = rowindA[krowA] ; ryloc = 2*rowindA[krowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iyloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; } } colA0 = colA2 + 2*nrowA ; } if ( icolA == ncolA - 2 ) { colA1 = colA0 + 2*nrowA ; if ( ncolA == nrowX ) { rloc = 2*icolA ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc += 2, iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; } else { rloc = 2*colindA[icolA] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc = 2*colindA[icolA+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; } if ( nrowY == nrowA ) { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; } } else { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; ar1 = colA1[rloc] ; ai1 = colA1[iloc] ; krowY = rowindA[krowA] ; ryloc = 2*rowindA[krowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iyloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; } } } else if ( icolA == ncolA - 1 ) { if ( ncolA == nrowX ) { rloc = 2*icolA ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; } else { rloc = 2*colindA[icolA] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; } if ( nrowY == nrowA ) { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 ; } } else { for ( krowA = 0, rloc = 0, iloc = 1 ; krowA < nrowA ; krowA++, rloc += 2, iloc += 2 ) { ar0 = colA0[rloc] ; ai0 = colA0[iloc] ; krowY = rowindA[krowA] ; ryloc = 2*rowindA[krowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= ar0*xr00 - ai0*xi00 ; colY0[iyloc] -= ar0*xi00 + ai0*xr00 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------- A has dense rows ---------------- */ static void complex_updDenseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *rowA0, *rowA1, *rowA2, *entA, *entX, *entY ; int inc1, inc2, irowA, jcolX, kcolA, ncolA, ncolX, ncolY, nrowA, nrowX, nrowY ; int *colindA, *rowindA ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_denseInfo(mtxA, &nrowA, &ncolA, &inc1, &inc2, &entA) ; if ( ncolA != nrowX ) { SubMtx_columnIndices(mtxA, &ncolA, &colindA) ; } else { colindA = NULL ; } if ( nrowA != nrowY ) { SubMtx_rowIndices(mtxA, &nrowA, &rowindA) ; } else { rowindA = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; rowA0 = entA ; for ( irowA = 0 ; irowA < nrowA - 2 ; irowA += 3 ) { double ai0, ai1, ai2, ar0, ar1, ar2, xi0, xi1, xi2, xr0, xr1, xr2, isum00, isum01, isum02, isum10, isum11, isum12, isum20, isum21, isum22, rsum00, rsum01, rsum02, rsum10, rsum11, rsum12, rsum20, rsum21, rsum22 ; int ialoc, iloc, ixloc, iyloc, raloc, rloc, rxloc, ryloc ; rowA1 = rowA0 + 2*ncolA ; rowA2 = rowA1 + 2*ncolA ; isum00 = isum01 = isum02 = isum10 = isum11 = isum12 = isum20 = isum21 = isum22 = 0.0 ; rsum00 = rsum01 = rsum02 = rsum10 = rsum11 = rsum12 = rsum20 = rsum21 = rsum22 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { rloc = 2*kcolA ; iloc = rloc + 1 ; ar0 = rowA0[rloc] ; ai0 = rowA0[iloc] ; ar1 = rowA1[rloc] ; ai1 = rowA1[iloc] ; ar2 = rowA2[rloc] ; ai2 = rowA2[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum12 += ar1*xr2 - ai1*xi2 ; isum12 += ar1*xi2 + ai1*xr2 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; rsum21 += ar2*xr1 - ai2*xi1 ; isum21 += ar2*xi1 + ai2*xr1 ; rsum22 += ar2*xr2 - ai2*xi2 ; isum22 += ar2*xi2 + ai2*xr2 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { raloc = 2*kcolA ; ialoc = raloc + 1 ; ar0 = rowA0[raloc] ; ai0 = rowA0[ialoc] ; ar1 = rowA1[raloc] ; ai1 = rowA1[ialoc] ; ar2 = rowA2[raloc] ; ai2 = rowA2[ialoc] ; rxloc = 2*colindA[kcolA] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; xr2 = colX2[rxloc] ; xi2 = colX2[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum12 += ar1*xr2 - ai1*xi2 ; isum12 += ar1*xi2 + ai1*xr2 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; rsum21 += ar2*xr1 - ai2*xi1 ; isum21 += ar2*xi1 + ai2*xr1 ; rsum22 += ar2*xr2 - ai2*xi2 ; isum22 += ar2*xi2 + ai2*xr2 ; } } if ( nrowY == nrowA ) { ryloc = 2*irowA ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; colY2[ryloc] -= rsum02 ; colY2[iyloc] -= isum02 ; ryloc += 2, iyloc += 2 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; colY1[ryloc] -= rsum11 ; colY1[iyloc] -= isum11 ; colY2[ryloc] -= rsum12 ; colY2[iyloc] -= isum12 ; ryloc += 2, iyloc += 2 ; colY0[ryloc] -= rsum20 ; colY0[iyloc] -= isum20 ; colY1[ryloc] -= rsum21 ; colY1[iyloc] -= isum21 ; colY2[ryloc] -= rsum22 ; colY2[iyloc] -= isum22 ; } else { ryloc = 2*rowindA[irowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; colY2[ryloc] -= rsum02 ; colY2[iyloc] -= isum02 ; ryloc = 2*rowindA[irowA+1] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; colY1[ryloc] -= rsum11 ; colY1[iyloc] -= isum11 ; colY2[ryloc] -= rsum12 ; colY2[iyloc] -= isum12 ; ryloc = 2*rowindA[irowA+2] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum20 ; colY0[iyloc] -= isum20 ; colY1[ryloc] -= rsum21 ; colY1[iyloc] -= isum21 ; colY2[ryloc] -= rsum22 ; colY2[iyloc] -= isum22 ; } rowA0 = rowA2 + 2*ncolA ; } if ( irowA == nrowA - 2 ) { double ai0, ai1, ar0, ar1, xi0, xi1, xi2, xr0, xr1, xr2, isum00, isum01, isum02, isum10, isum11, isum12, rsum00, rsum01, rsum02, rsum10, rsum11, rsum12 ; int ialoc, iloc, ixloc, iyloc, raloc, rloc, rxloc, ryloc ; rowA1 = rowA0 + 2*ncolA ; isum00 = isum01 = isum02 = isum10 = isum11 = isum12 = 0.0 ; rsum00 = rsum01 = rsum02 = rsum10 = rsum11 = rsum12 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { rloc = 2*kcolA ; iloc = rloc + 1 ; ar0 = rowA0[rloc] ; ai0 = rowA0[iloc] ; ar1 = rowA1[rloc] ; ai1 = rowA1[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum12 += ar1*xr2 - ai1*xi2 ; isum12 += ar1*xi2 + ai1*xr2 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { raloc = 2*kcolA ; ialoc = raloc + 1 ; ar0 = rowA0[raloc] ; ai0 = rowA0[ialoc] ; ar1 = rowA1[raloc] ; ai1 = rowA1[ialoc] ; rxloc = 2*colindA[kcolA] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; xr2 = colX2[rxloc] ; xi2 = colX2[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum12 += ar1*xr2 - ai1*xi2 ; isum12 += ar1*xi2 + ai1*xr2 ; } } if ( nrowY == nrowA ) { ryloc = 2*irowA ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; colY2[ryloc] -= rsum02 ; colY2[iyloc] -= isum02 ; ryloc += 2, iyloc += 2 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; colY1[ryloc] -= rsum11 ; colY1[iyloc] -= isum11 ; colY2[ryloc] -= rsum12 ; colY2[iyloc] -= isum12 ; } else { ryloc = 2*rowindA[irowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; colY2[ryloc] -= rsum02 ; colY2[iyloc] -= isum02 ; ryloc = 2*rowindA[irowA+1] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; colY1[ryloc] -= rsum11 ; colY1[iyloc] -= isum11 ; colY2[ryloc] -= rsum12 ; colY2[iyloc] -= isum12 ; } } else if ( irowA == nrowA - 1 ) { double ai0, ar0, xi0, xi1, xi2, xr0, xr1, xr2, isum00, isum01, isum02, rsum00, rsum01, rsum02 ; int ialoc, iloc, ixloc, iyloc, raloc, rloc, rxloc, ryloc ; isum00 = isum01 = isum02 = rsum00 = rsum01 = rsum02 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { rloc = 2*kcolA ; iloc = rloc + 1 ; ar0 = rowA0[rloc] ; ai0 = rowA0[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { raloc = 2*kcolA ; ialoc = raloc + 1 ; ar0 = rowA0[raloc] ; ai0 = rowA0[ialoc] ; rxloc = 2*colindA[kcolA] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; xr2 = colX2[rxloc] ; xi2 = colX2[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; } } if ( nrowY == nrowA ) { ryloc = 2*irowA ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; colY2[ryloc] -= rsum02 ; colY2[iyloc] -= isum02 ; } else { ryloc = 2*rowindA[irowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; colY2[ryloc] -= rsum02 ; colY2[iyloc] -= isum02 ; } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; rowA0 = entA ; for ( irowA = 0 ; irowA < nrowA - 2 ; irowA += 3 ) { double ai0, ai1, ai2, ar0, ar1, ar2, xi0, xi1, xr0, xr1, isum00, isum01, isum10, isum11, isum20, isum21, rsum00, rsum01, rsum10, rsum11, rsum20, rsum21 ; int ialoc, iloc, ixloc, iyloc, raloc, rloc, rxloc, ryloc ; rowA1 = rowA0 + 2*ncolA ; rowA2 = rowA1 + 2*ncolA ; isum00 = isum01 = isum10 = isum11 = isum20 = isum21 = 0.0 ; rsum00 = rsum01 = rsum10 = rsum11 = rsum20 = rsum21 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { rloc = 2*kcolA ; iloc = rloc + 1 ; ar0 = rowA0[rloc] ; ai0 = rowA0[iloc] ; ar1 = rowA1[rloc] ; ai1 = rowA1[iloc] ; ar2 = rowA2[rloc] ; ai2 = rowA2[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; rsum21 += ar2*xr1 - ai2*xi1 ; isum21 += ar2*xi1 + ai2*xr1 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { raloc = 2*kcolA ; ialoc = raloc + 1 ; ar0 = rowA0[raloc] ; ai0 = rowA0[ialoc] ; ar1 = rowA1[raloc] ; ai1 = rowA1[ialoc] ; ar2 = rowA2[raloc] ; ai2 = rowA2[ialoc] ; rxloc = 2*colindA[kcolA] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; rsum21 += ar2*xr1 - ai2*xi1 ; isum21 += ar2*xi1 + ai2*xr1 ; } } if ( nrowY == nrowA ) { ryloc = 2*irowA ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; ryloc += 2, iyloc += 2 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; colY1[ryloc] -= rsum11 ; colY1[iyloc] -= isum11 ; ryloc += 2, iyloc += 2 ; colY0[ryloc] -= rsum20 ; colY0[iyloc] -= isum20 ; colY1[ryloc] -= rsum21 ; colY1[iyloc] -= isum21 ; } else { ryloc = 2*rowindA[irowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; ryloc = 2*rowindA[irowA+1] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; colY1[ryloc] -= rsum11 ; colY1[iyloc] -= isum11 ; ryloc = 2*rowindA[irowA+2] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum20 ; colY0[iyloc] -= isum20 ; colY1[ryloc] -= rsum21 ; colY1[iyloc] -= isum21 ; } rowA0 = rowA2 + 2*ncolA ; } if ( irowA == nrowA - 2 ) { double ai0, ai1, ar0, ar1, xi0, xi1, xr0, xr1, isum00, isum01, isum10, isum11, rsum00, rsum01, rsum10, rsum11 ; int ialoc, iloc, ixloc, iyloc, raloc, rloc, rxloc, ryloc ; rowA1 = rowA0 + 2*ncolA ; isum00 = isum01 = isum10 = isum11 = 0.0 ; rsum00 = rsum01 = rsum10 = rsum11 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { rloc = 2*kcolA ; iloc = rloc + 1 ; ar0 = rowA0[rloc] ; ai0 = rowA0[iloc] ; ar1 = rowA1[rloc] ; ai1 = rowA1[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { raloc = 2*kcolA ; ialoc = raloc + 1 ; ar0 = rowA0[raloc] ; ai0 = rowA0[ialoc] ; ar1 = rowA1[raloc] ; ai1 = rowA1[ialoc] ; rxloc = 2*colindA[kcolA] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; } } if ( nrowY == nrowA ) { ryloc = 2*irowA ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; ryloc += 2, iyloc += 2 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; colY1[ryloc] -= rsum11 ; colY1[iyloc] -= isum11 ; } else { ryloc = 2*rowindA[irowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; ryloc = 2*rowindA[irowA+1] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; colY1[ryloc] -= rsum11 ; colY1[iyloc] -= isum11 ; } rowA0 = rowA2 + 2*ncolA ; } else if ( irowA == nrowA - 1 ) { double ai0, ar0, xi0, xi1, xr0, xr1, isum00, isum01, rsum00, rsum01 ; int ialoc, iloc, ixloc, iyloc, raloc, rloc, rxloc, ryloc ; isum00 = isum01 = 0.0 ; rsum00 = rsum01 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { rloc = 2*kcolA ; iloc = rloc + 1 ; ar0 = rowA0[rloc] ; ai0 = rowA0[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { raloc = 2*kcolA ; ialoc = raloc + 1 ; ar0 = rowA0[raloc] ; ai0 = rowA0[ialoc] ; rxloc = 2*colindA[kcolA] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; } } if ( nrowY == nrowA ) { ryloc = 2*irowA ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; } else { ryloc = 2*rowindA[irowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; colY1[ryloc] -= rsum01 ; colY1[iyloc] -= isum01 ; } } } else if ( jcolX == ncolX - 1 ) { rowA0 = entA ; for ( irowA = 0 ; irowA < nrowA - 2 ; irowA += 3 ) { double ai0, ai1, ai2, ar0, ar1, ar2, xi0, xr0, isum00, isum10, isum20, rsum00, rsum10, rsum20 ; int ialoc, iloc, ixloc, iyloc, raloc, rloc, rxloc, ryloc ; rowA1 = rowA0 + 2*ncolA ; rowA2 = rowA1 + 2*ncolA ; isum00 = isum10 = isum20 = 0.0 ; rsum00 = rsum10 = rsum20 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { rloc = 2*kcolA ; iloc = rloc + 1 ; ar0 = rowA0[rloc] ; ai0 = rowA0[iloc] ; ar1 = rowA1[rloc] ; ai1 = rowA1[iloc] ; ar2 = rowA2[rloc] ; ai2 = rowA2[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { raloc = 2*kcolA ; ialoc = raloc + 1 ; ar0 = rowA0[raloc] ; ai0 = rowA0[ialoc] ; ar1 = rowA1[raloc] ; ai1 = rowA1[ialoc] ; ar2 = rowA2[raloc] ; ai2 = rowA2[ialoc] ; rxloc = 2*colindA[kcolA] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; } } if ( nrowY == nrowA ) { ryloc = 2*irowA ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; ryloc += 2, iyloc += 2 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; ryloc += 2, iyloc += 2 ; colY0[ryloc] -= rsum20 ; colY0[iyloc] -= isum20 ; } else { ryloc = 2*rowindA[irowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; ryloc = 2*rowindA[irowA+1] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; ryloc = 2*rowindA[irowA+2] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum20 ; colY0[iyloc] -= isum20 ; } rowA0 = rowA2 + 2*ncolA ; } if ( irowA == nrowA - 2 ) { double ai0, ai1, ar0, ar1, xi0, xr0, isum00, isum10, rsum00, rsum10 ; int ialoc, iloc, ixloc, iyloc, raloc, rloc, rxloc, ryloc ; rowA1 = rowA0 + 2*ncolA ; isum00 = isum10 = 0.0 ; rsum00 = rsum10 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { rloc = 2*kcolA ; iloc = rloc + 1 ; ar0 = rowA0[rloc] ; ai0 = rowA0[iloc] ; ar1 = rowA1[rloc] ; ai1 = rowA1[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { raloc = 2*kcolA ; ialoc = raloc + 1 ; ar0 = rowA0[raloc] ; ai0 = rowA0[ialoc] ; ar1 = rowA1[raloc] ; ai1 = rowA1[ialoc] ; rxloc = 2*colindA[kcolA] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; } } if ( nrowY == nrowA ) { ryloc = 2*irowA ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; ryloc += 2, iyloc += 2 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; } else { ryloc = 2*rowindA[irowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; ryloc = 2*rowindA[irowA+1] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum10 ; colY0[iyloc] -= isum10 ; } } else if ( irowA == nrowA - 1 ) { double ai0, ar0, xi0, xr0, isum00, rsum00 ; int ialoc, iloc, ixloc, iyloc, raloc, rloc, rxloc, ryloc ; isum00 = 0.0 ; rsum00 = 0.0 ; if ( ncolA == nrowX ) { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { rloc = 2*kcolA ; iloc = rloc + 1 ; ar0 = rowA0[rloc] ; ai0 = rowA0[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; } } else { for ( kcolA = 0 ; kcolA < ncolA ; kcolA++ ) { raloc = 2*kcolA ; ialoc = raloc + 1 ; ar0 = rowA0[raloc] ; ai0 = rowA0[ialoc] ; rxloc = 2*colindA[kcolA] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; } } if ( nrowY == nrowA ) { ryloc = 2*irowA ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; } else { ryloc = 2*rowindA[irowA] ; iyloc = ryloc + 1 ; colY0[ryloc] -= rsum00 ; colY0[iyloc] -= isum00 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------- A has sparse rows ----------------- */ static void complex_updSparseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double ai, ar, xi0, isum0, isum1, isum2, xi1, xi2, xr0, xr1, xr2, rsum0, rsum1, rsum2 ; double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int ii, iloc, inc1, inc2, irowA, jcolX, kk, krowX, ncolA, ncolX, ncolY, nentA, nrowA, nrowX, nrowY, rloc, size ; int *colindA, *indices, *rowindA, *sizes ; /* fprintf(stdout, "\n UPDATE_SPARSE_ROWS(%d,%d)", mtxA->rowid, mtxA->colid) ; */ SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_sparseRowsInfo(mtxA, &nrowA, &nentA, &sizes, &indices, &entA) ; if ( (ncolA = mtxA->ncol) != nrowX ) { SubMtx_columnIndices(mtxA, &ncolA, &colindA) ; } else { colindA = NULL ; } if ( nrowA != nrowY ) { SubMtx_rowIndices(mtxA, &nrowA, &rowindA) ; } else { rowindA = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizes[irowA]) > 0 ) { isum0 = isum1 = isum2 = rsum0 = rsum1 = rsum2 = 0.0 ; if ( ncolA == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; krowX = indices[kk] ; xr0 = colX0[2*krowX] ; xi0 = colX0[2*krowX+1] ; xr1 = colX1[2*krowX] ; xi1 = colX1[2*krowX+1] ; xr2 = colX2[2*krowX] ; xi2 = colX2[2*krowX+1] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; rsum1 += ar*xr1 - ai*xi1 ; isum1 += ar*xi1 + ai*xr1 ; rsum2 += ar*xr2 - ai*xi2 ; isum2 += ar*xi2 + ai*xr2 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; krowX = colindA[indices[kk]] ; xr0 = colX0[2*krowX] ; xi0 = colX0[2*krowX+1] ; xr1 = colX1[2*krowX] ; xi1 = colX1[2*krowX+1] ; xr2 = colX2[2*krowX] ; xi2 = colX2[2*krowX+1] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; rsum1 += ar*xr1 - ai*xi1 ; isum1 += ar*xi1 + ai*xr1 ; rsum2 += ar*xr2 - ai*xi2 ; isum2 += ar*xi2 + ai*xr2 ; } } if ( nrowA == nrowY ) { rloc = 2*irowA ; iloc = rloc + 1 ; } else { rloc = 2*rowindA[irowA] ; iloc = rloc + 1 ; } colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; colY1[rloc] -= rsum1 ; colY1[iloc] -= isum1 ; colY2[rloc] -= rsum2 ; colY2[iloc] -= isum2 ; } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizes[irowA]) > 0 ) { isum0 = isum1 = rsum0 = rsum1 = 0.0 ; if ( ncolA == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; krowX = indices[kk] ; xr0 = colX0[2*krowX] ; xi0 = colX0[2*krowX+1] ; xr1 = colX1[2*krowX] ; xi1 = colX1[2*krowX+1] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; rsum1 += ar*xr1 - ai*xi1 ; isum1 += ar*xi1 + ai*xr1 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; krowX = colindA[indices[kk]] ; xr0 = colX0[2*krowX] ; xi0 = colX0[2*krowX+1] ; xr1 = colX1[2*krowX] ; xi1 = colX1[2*krowX+1] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; rsum1 += ar*xr1 - ai*xi1 ; isum1 += ar*xi1 + ai*xr1 ; } } if ( nrowA == nrowY ) { rloc = 2*irowA ; iloc = rloc + 1 ; } else { rloc = 2*rowindA[irowA] ; iloc = rloc + 1 ; } colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; colY1[rloc] -= rsum1 ; colY1[iloc] -= isum1 ; } } } else if ( jcolX == ncolX - 1 ) { for ( irowA = kk = 0 ; irowA < nrowA ; irowA++ ) { if ( (size = sizes[irowA]) > 0 ) { isum0 = rsum0 = 0.0 ; if ( ncolA == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; krowX = indices[kk] ; xr0 = colX0[2*krowX] ; xi0 = colX0[2*krowX+1] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; krowX = colindA[indices[kk]] ; xr0 = colX0[2*krowX] ; xi0 = colX0[2*krowX+1] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; } } if ( nrowA == nrowY ) { rloc = 2*irowA ; iloc = rloc + 1 ; } else { rloc = 2*rowindA[irowA] ; iloc = rloc + 1 ; } colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------- A has sparse columns -------------------- */ static void complex_updSparseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double ai, ar, xi0, xi1, xi2, xr0, xr1, xr2 ; double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int ii, iloc, inc1, inc2, jcolA, jcolX, jrowX, kk, ncolA, ncolX, ncolY, nentA, nrowA, nrowX, nrowY, rloc, size ; int *colindA, *indices, *rowindA, *sizes ; /* fprintf(stdout, "\n UPDATE_SPARSE_COLUMNS(%d,%d)", mtxA->rowid, mtxA->colid) ; */ SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_sparseColumnsInfo(mtxA, &ncolA, &nentA, &sizes, &indices, &entA) ; if ( ncolA != nrowX ) { SubMtx_columnIndices(mtxA, &ncolA, &colindA) ; } else { colindA = NULL ; } if ( (nrowA = mtxA->nrow) != nrowY ) { SubMtx_rowIndices(mtxA, &nrowA, &rowindA) ; } else { rowindA = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; for ( jcolA = kk = 0 ; jcolA < ncolA ; jcolA++ ) { if ( (size = sizes[jcolA]) > 0 ) { if ( ncolA == nrowX ) { jrowX = jcolA ; } else { jrowX = colindA[jcolA] ; } rloc = 2*jrowX ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; if ( nrowA == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; colY1[rloc] -= ar*xr1 - ai*xi1 ; colY1[iloc] -= ar*xi1 + ai*xr1 ; colY2[rloc] -= ar*xr2 - ai*xi2 ; colY2[iloc] -= ar*xi2 + ai*xr2 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*rowindA[indices[kk]] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; colY1[rloc] -= ar*xr1 - ai*xi1 ; colY1[iloc] -= ar*xi1 + ai*xr1 ; colY2[rloc] -= ar*xr2 - ai*xi2 ; colY2[iloc] -= ar*xi2 + ai*xr2 ; } } } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; for ( jcolA = kk = 0 ; jcolA < ncolA ; jcolA++ ) { if ( (size = sizes[jcolA]) > 0 ) { if ( ncolA == nrowX ) { jrowX = jcolA ; } else { jrowX = colindA[jcolA] ; } rloc = 2*jrowX ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; if ( nrowA == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; colY1[rloc] -= ar*xr1 - ai*xi1 ; colY1[iloc] -= ar*xi1 + ai*xr1 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*rowindA[indices[kk]] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; colY1[rloc] -= ar*xr1 - ai*xi1 ; colY1[iloc] -= ar*xi1 + ai*xr1 ; } } } } } else if ( jcolX == ncolX - 1 ) { for ( jcolA = kk = 0 ; jcolA < ncolA ; jcolA++ ) { if ( (size = sizes[jcolA]) > 0 ) { if ( ncolA == nrowX ) { jrowX = jcolA ; } else { jrowX = colindA[jcolA] ; } rloc = 2*jrowX ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; if ( nrowA == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*rowindA[indices[kk]] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; } } } } } return ; } /*--------------------------------------------------------------------*/ *entA, *entX, *entY ; int ii, iloc, inc1, inc2, irowA, jcolX, kk, krowX, ncolA, ncolX, ncolY, nentA, nrowA, nrowX, nrowY, rloc, size ; int *colindA, *indices, *rowindA, *sizes ; /* fprintf(stdout, "\n UPDATE_SPARSE_ROWS(%d,%d)", mtxA->rowid, mtxA->colid) ; */ SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx/src/solveupdH.c010064400020550007177000001672400653410625300162350ustar00clevecompmath00000400000006/* solveupdH.c */ #include "../SubMtx.h" /*--------------------------------------------------------------------*/ static void complex_updDenseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void complex_updDenseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void complex_updSparseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void complex_updSparseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- perform the matrix-matrix multiply Y := Y - A^H * X used in the forward and backsolves where (1) rows(A) \subseteq rows(Y) (2) rows(A) are local w.r.t. rows(Y) (3) cols(A) \subseteq rows(X) (4) cols(A) are local w.r.t. rows(X) (5) cols(Y) = cols(X) (6) Y and X have mode SUBMTX_DENSE_COLUMNS created -- 98may02, cca ----------------------------------------------------- */ void SubMtx_solveupdH ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { /* --------------- check the input --------------- */ if ( mtxY == NULL || mtxA == NULL || mtxX == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_solveupdH(%p,%p,%p)" "\n bad input\n", mtxY, mtxA, mtxX) ; exit(-1) ; } if ( mtxA->type != SPOOLES_COMPLEX ) { fprintf(stderr, "\n fatal error in SubMtx_solveupdH(%p,%p,%p)" "\n Y has type %d, must be SPOOLES_COMPLEX\n", mtxY, mtxA, mtxX, mtxA->type) ; exit(-1) ; } if ( ! SUBMTX_IS_DENSE_COLUMNS(mtxY) ) { fprintf(stderr, "\n fatal error in SubMtx_solveupdH(%p,%p,%p)" "\n Y must have mode SUBMTX_DENSE_COLUMNS\n", mtxY, mtxA, mtxX) ; exit(-1) ; } if ( ! SUBMTX_IS_DENSE_COLUMNS(mtxX) ) { fprintf(stderr, "\n fatal error in SubMtx_solveupdH(%p,%p,%p)" "\n X must have mode SUBMTX_DENSE_COLUMNS\n", mtxY, mtxA, mtxX) ; exit(-1) ; } switch ( mtxA->mode ) { case SUBMTX_DENSE_COLUMNS : complex_updDenseColumns(mtxY, mtxA, mtxX) ; break ; case SUBMTX_DENSE_ROWS : complex_updDenseRows(mtxY, mtxA, mtxX) ; break ; case SUBMTX_SPARSE_ROWS : complex_updSparseRows(mtxY, mtxA, mtxX) ; break ; case SUBMTX_SPARSE_COLUMNS : complex_updSparseColumns(mtxY, mtxA, mtxX) ; break ; default : fprintf(stderr, "\n fatal error in SubMtx_solveupdH(%p,%p,%p)" "\n unsupported mode %d for A\n", mtxY, mtxA, mtxX, mtxA->mode) ; SubMtx_writeForHumanEye(mtxA, stderr) ; exit(-1) ; break ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------- A has dense rows ---------------- */ static void complex_updDenseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double ai0, ai1, ai2, ar0, ar1, ar2, xi00, xi01, xi02, xi10, xi11, xi12, xi20, xi21, xi22, xr00, xr01, xr02, xr10, xr11, xr12, xr20, xr21, xr22 ; double *colAT0, *colAT1, *colAT2, *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int icolAT, ialoc, iloc, inc1, inc2, jcolX, krowAT, ncolAT, ncolX, ncolY, nrowAT, nrowX, nrowY, raloc, rloc ; int *colindAT, *rowindAT ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_denseInfo(mtxA, &ncolAT, &nrowAT, &inc1, &inc2, &entA) ; colX0 = entX ; colY0 = entY ; if ( ncolAT != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( nrowAT != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; colAT0 = entA ; for ( icolAT = 0 ; icolAT < ncolAT - 2 ; icolAT += 3 ) { colAT1 = colAT0 + 2*nrowAT ; colAT2 = colAT1 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; ar2 = colAT2[rloc] ; ai2 = colAT2[iloc] ; colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 + ar2*xr20 + ai2*xi20 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 + ar2*xi20 - ai2*xr20 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 + ar1*xr11 + ai1*xi11 + ar2*xr21 + ai2*xi21 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 + ar1*xi11 - ai1*xr11 + ar2*xi21 - ai2*xr21 ; colY2[rloc] -= ar0*xr02 + ai0*xi02 + ar1*xr12 + ai1*xi12 + ar2*xr22 + ai2*xi22 ; colY2[iloc] -= ar0*xi02 - ai0*xr02 + ar1*xi12 - ai1*xr12 + ar2*xi22 - ai2*xr22 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; ar2 = colAT2[raloc] ; ai2 = colAT2[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 + ar2*xr20 + ai2*xi20 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 + ar2*xi20 - ai2*xr20 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 + ar1*xr11 + ai1*xi11 + ar2*xr21 + ai2*xi21 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 + ar1*xi11 - ai1*xr11 + ar2*xi21 - ai2*xr21 ; colY2[rloc] -= ar0*xr02 + ai0*xi02 + ar1*xr12 + ai1*xi12 + ar2*xr22 + ai2*xi22 ; colY2[iloc] -= ar0*xi02 - ai0*xr02 + ar1*xi12 - ai1*xr12 + ar2*xi22 - ai2*xr22 ; } } colAT0 = colAT2 + 2*nrowAT ; } if ( icolAT == ncolAT - 2 ) { colAT1 = colAT0 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 + ar1*xr11 + ai1*xi11 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 + ar1*xi11 - ai1*xr11 ; colY2[rloc] -= ar0*xr02 + ai0*xi02 + ar1*xr12 + ai1*xi12 ; colY2[iloc] -= ar0*xi02 - ai0*xr02 + ar1*xi12 - ai1*xr12 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 + ar1*xr11 + ai1*xi11 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 + ar1*xi11 - ai1*xr11 ; colY2[rloc] -= ar0*xr02 + ai0*xi02 + ar1*xr12 + ai1*xi12 ; colY2[iloc] -= ar0*xi02 - ai0*xr02 + ar1*xi12 - ai1*xr12 ; } } } else if ( icolAT == ncolAT - 1 ) { if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; colY0[rloc] -= ar0*xr00 + ai0*xi00 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 ; colY2[rloc] -= ar0*xr02 + ai0*xi02 ; colY2[iloc] -= ar0*xi02 - ai0*xr02 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 + ai0*xi00 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 ; colY2[rloc] -= ar0*xr02 + ai0*xi02 ; colY2[iloc] -= ar0*xi02 - ai0*xr02 ; } } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } /* fprintf(stdout, "\n %% jcolX = %d", jcolX) ; */ if ( jcolX == ncolX - 2 ) { colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colAT0 = entA ; for ( icolAT = 0 ; icolAT < ncolAT - 2 ; icolAT += 3 ) { colAT1 = colAT0 + 2*nrowAT ; colAT2 = colAT1 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; ar2 = colAT2[rloc] ; ai2 = colAT2[iloc] ; colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 + ar2*xr20 + ai2*xi20 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 + ar2*xi20 - ai2*xr20 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 + ar1*xr11 + ai1*xi11 + ar2*xr21 + ai2*xi21 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 + ar1*xi11 - ai1*xr11 + ar2*xi21 - ai2*xr21 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; ar2 = colAT2[raloc] ; ai2 = colAT2[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 + ar2*xr20 + ai2*xi20 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 + ar2*xi20 - ai2*xr20 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 + ar1*xr11 + ai1*xi11 + ar2*xr21 + ai2*xi21 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 + ar1*xi11 - ai1*xr11 + ar2*xi21 - ai2*xr21 ; } } colAT0 = colAT2 + 2*nrowAT ; } if ( icolAT == ncolAT - 2 ) { colAT1 = colAT0 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 + ar1*xr11 + ai1*xi11 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 + ar1*xi11 - ai1*xr11 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 + ar1*xr11 + ai1*xi11 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 + ar1*xi11 - ai1*xr11 ; } } } else if ( icolAT == ncolAT - 1 ) { if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; colY0[rloc] -= ar0*xr00 + ai0*xi00 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 + ai0*xi00 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 ; colY1[rloc] -= ar0*xr01 + ai0*xi01 ; colY1[iloc] -= ar0*xi01 - ai0*xr01 ; } } } } else if ( jcolX == ncolX - 1 ) { colAT0 = entA ; for ( icolAT = 0 ; icolAT < ncolAT - 2 ; icolAT += 3 ) { /* fprintf(stdout, "\n %% icolAT = %d", icolAT) ; */ colAT1 = colAT0 + 2*nrowAT ; colAT2 = colAT1 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } /* fprintf(stdout, "\n %% x00 = (%12.4e,%12.4e)", xr00, xi00) ; fprintf(stdout, "\n %% x10 = (%12.4e,%12.4e)", xr10, xi10) ; fprintf(stdout, "\n %% x20 = (%12.4e,%12.4e)", xr20, xi20) ; */ if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; ar2 = colAT2[rloc] ; ai2 = colAT2[iloc] ; /* fprintf(stdout, "\n %% rloc = %d, iloc = %d", rloc, iloc) ; fprintf(stdout, "\n %% a0 = (%12.4e,%12.4e)", ar0, ai0) ; fprintf(stdout, "\n %% a1 = (%12.4e,%12.4e)", ar1, ai1) ; fprintf(stdout, "\n %% a2 = (%12.4e,%12.4e)", ar2, ai2) ; */ colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 + ar2*xr20 + ai2*xi20 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 + ar2*xi20 - ai2*xr20 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; ar2 = colAT2[raloc] ; ai2 = colAT2[ialoc] ; /* fprintf(stdout, "\n %% raloc = %d, ialoc = %d", raloc, ialoc) ; fprintf(stdout, "\n %% a0 = (%12.4e,%12.4e)", ar0, ai0) ; fprintf(stdout, "\n %% a1 = (%12.4e,%12.4e)", ar1, ai1) ; fprintf(stdout, "\n %% a2 = (%12.4e,%12.4e)", ar2, ai2) ; */ rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; /* fprintf(stdout, "\n %% rloc = %d, iloc = %d", rloc, iloc) ; */ colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 + ar2*xr20 + ai2*xi20 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 + ar2*xi20 - ai2*xr20 ; } } colAT0 = colAT2 + 2*nrowAT ; } if ( icolAT == ncolAT - 2 ) { colAT1 = colAT0 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 + ai0*xi00 + ar1*xr10 + ai1*xi10 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 + ar1*xi10 - ai1*xr10 ; } } } else if ( icolAT == ncolAT - 1 ) { if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; colY0[rloc] -= ar0*xr00 + ai0*xi00 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 + ai0*xi00 ; colY0[iloc] -= ar0*xi00 - ai0*xr00 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------- A has dense columns ------------------- */ static void complex_updDenseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *rowAT0, *rowAT1, *rowAT2, *entA, *entX, *entY ; int inc1, inc2, irowAT, jcolX, kcolAT, ncolAT, ncolX, ncolY, nrowAT, nrowX, nrowY ; int *colindAT, *rowindAT ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_denseInfo(mtxA, &ncolAT, &nrowAT, &inc1, &inc2, &entA) ; if ( ncolAT != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( nrowAT != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; rowAT0 = entA ; for ( irowAT = 0 ; irowAT < nrowAT - 2 ; irowAT += 3 ) { double ai0, ai1, ai2, ar0, ar1, ar2, isum00, isum01, isum02, isum10, isum11, isum12, isum20, isum21, isum22, rsum00, rsum01, rsum02, rsum10, rsum11, rsum12, rsum20, rsum21, rsum22, xi0, xi1, xi2, xr0, xr1, xr2 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = isum02 = isum10 = isum11 = isum12 = isum20 = isum21 = isum22 = 0.0 ; rsum00 = rsum01 = rsum02 = rsum10 = rsum11 = rsum12 = rsum20 = rsum21 = rsum22 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; rowAT2 = rowAT1 + 2*ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; ar2 = rowAT2[rloc] ; ai2 = rowAT2[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; rsum02 += ar0*xr2 + ai0*xi2 ; isum02 += ar0*xi2 - ai0*xr2 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; rsum11 += ar1*xr1 + ai1*xi1 ; isum11 += ar1*xi1 - ai1*xr1 ; rsum12 += ar1*xr2 + ai1*xi2 ; isum12 += ar1*xi2 - ai1*xr2 ; rsum20 += ar2*xr0 + ai2*xi0 ; isum20 += ar2*xi0 - ai2*xr0 ; rsum21 += ar2*xr1 + ai2*xi1 ; isum21 += ar2*xi1 - ai2*xr1 ; rsum22 += ar2*xr2 + ai2*xi2 ; isum22 += ar2*xi2 - ai2*xr2 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; ar2 = rowAT2[raloc] ; ai2 = rowAT2[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; xr2 = colX2[rxloc] ; xi2 = colX2[ixloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; rsum02 += ar0*xr2 + ai0*xi2 ; isum02 += ar0*xi2 - ai0*xr2 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; rsum11 += ar1*xr1 + ai1*xi1 ; isum11 += ar1*xi1 - ai1*xr1 ; rsum12 += ar1*xr2 + ai1*xi2 ; isum12 += ar1*xi2 - ai1*xr2 ; rsum20 += ar2*xr0 + ai2*xi0 ; isum20 += ar2*xi0 - ai2*xr0 ; rsum21 += ar2*xr1 + ai2*xi1 ; isum21 += ar2*xi1 - ai2*xr1 ; rsum22 += ar2*xr2 + ai2*xi2 ; isum22 += ar2*xi2 - ai2*xr2 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; colY2[rloc] -= rsum12 ; colY2[iloc] -= isum12 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; colY1[rloc] -= rsum21 ; colY1[iloc] -= isum21 ; colY2[rloc] -= rsum22 ; colY2[iloc] -= isum22 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; colY2[rloc] -= rsum12 ; colY2[iloc] -= isum12 ; rloc = 2*rowindAT[irowAT+2] ; iloc = rloc + 1 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; colY1[rloc] -= rsum21 ; colY1[iloc] -= isum21 ; colY2[rloc] -= rsum22 ; colY2[iloc] -= isum22 ; } rowAT0 = rowAT2 + 2*ncolAT ; } if ( irowAT == nrowAT - 2 ) { double ai0, ai1, ar0, ar1, isum00, isum01, isum02, isum10, isum11, isum12, rsum00, rsum01, rsum02, rsum10, rsum11, rsum12, xi0, xi1, xi2, xr0, xr1, xr2 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = isum02 = isum10 = isum11 = isum12 = 0.0 ; rsum00 = rsum01 = rsum02 = rsum10 = rsum11 = rsum12 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; rsum02 += ar0*xr2 + ai0*xi2 ; isum02 += ar0*xi2 - ai0*xr2 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; rsum11 += ar1*xr1 + ai1*xi1 ; isum11 += ar1*xi1 - ai1*xr1 ; rsum12 += ar1*xr2 + ai1*xi2 ; isum12 += ar1*xi2 - ai1*xr2 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; xr2 = colX2[rxloc] ; xi2 = colX2[ixloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; rsum02 += ar0*xr2 + ai0*xi2 ; isum02 += ar0*xi2 - ai0*xr2 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; rsum11 += ar1*xr1 + ai1*xi1 ; isum11 += ar1*xi1 - ai1*xr1 ; rsum12 += ar1*xr2 + ai1*xi2 ; isum12 += ar1*xi2 - ai1*xr2 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; colY2[rloc] -= rsum12 ; colY2[iloc] -= isum12 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; colY2[rloc] -= rsum12 ; colY2[iloc] -= isum12 ; } } else if ( irowAT == nrowAT - 1 ) { double ai0, ar0, isum00, isum01, isum02, rsum00, rsum01, rsum02, xi0, xi1, xi2, xr0, xr1, xr2 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = isum02 = 0.0 ; rsum00 = rsum01 = rsum02 = 0.0 ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; rsum02 += ar0*xr2 + ai0*xi2 ; isum02 += ar0*xi2 - ai0*xr2 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; xr2 = colX2[rxloc] ; xi2 = colX2[ixloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; rsum02 += ar0*xr2 + ai0*xi2 ; isum02 += ar0*xi2 - ai0*xr2 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; rowAT0 = entA ; for ( irowAT = 0 ; irowAT < nrowAT - 2 ; irowAT += 3 ) { double ai0, ai1, ai2, ar0, ar1, ar2, isum00, isum01, isum10, isum11, isum20, isum21, rsum00, rsum01, rsum10, rsum11, rsum20, rsum21, xi0, xi1, xr0, xr1 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = isum10 = isum11 = isum20 = isum21 = 0.0 ; rsum00 = rsum01 = rsum10 = rsum11 = rsum20 = rsum21 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; rowAT2 = rowAT1 + 2*ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; ar2 = rowAT2[rloc] ; ai2 = rowAT2[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; rsum11 += ar1*xr1 + ai1*xi1 ; isum11 += ar1*xi1 - ai1*xr1 ; rsum20 += ar2*xr0 + ai2*xi0 ; isum20 += ar2*xi0 - ai2*xr0 ; rsum21 += ar2*xr1 + ai2*xi1 ; isum21 += ar2*xi1 - ai2*xr1 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; ar2 = rowAT2[raloc] ; ai2 = rowAT2[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; rsum11 += ar1*xr1 + ai1*xi1 ; isum11 += ar1*xi1 - ai1*xr1 ; rsum20 += ar2*xr0 + ai2*xi0 ; isum20 += ar2*xi0 - ai2*xr0 ; rsum21 += ar2*xr1 + ai2*xi1 ; isum21 += ar2*xi1 - ai2*xr1 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; colY1[rloc] -= rsum21 ; colY1[iloc] -= isum21 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; rloc = 2*rowindAT[irowAT+2] ; iloc = rloc + 1 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; colY1[rloc] -= rsum21 ; colY1[iloc] -= isum21 ; } rowAT0 = rowAT2 + 2*ncolAT ; } if ( irowAT == nrowAT - 2 ) { double ai0, ai1, ar0, ar1, isum00, isum01, isum10, isum11, rsum00, rsum01, rsum10, rsum11, xi0, xi1, xr0, xr1 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = isum10 = isum11 = 0.0 ; rsum00 = rsum01 = rsum10 = rsum11 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; rsum11 += ar1*xr1 + ai1*xi1 ; isum11 += ar1*xi1 - ai1*xr1 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; rsum11 += ar1*xr1 + ai1*xi1 ; isum11 += ar1*xi1 - ai1*xr1 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; } } else if ( irowAT == nrowAT - 1 ) { double ai0, ar0, isum00, isum01, rsum00, rsum01, xi0, xi1, xr0, xr1 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = 0.0 ; rsum00 = rsum01 = 0.0 ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum01 += ar0*xr1 + ai0*xi1 ; isum01 += ar0*xi1 - ai0*xr1 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; } } } else if ( jcolX == ncolX - 1 ) { rowAT0 = entA ; for ( irowAT = 0 ; irowAT < nrowAT - 2 ; irowAT += 3 ) { double ai0, ai1, ai2, ar0, ar1, ar2, isum00, isum10, isum20, rsum00, rsum10, rsum20, xi0, xr0 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum10 = isum20 = 0.0 ; rsum00 = rsum10 = rsum20 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; rowAT2 = rowAT1 + 2*ncolAT ; /* fprintf(stdout, "\n %% irowAT %d", irowAT) ; */ if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; /* fprintf(stdout, "\n %% rloc %d, iloc %d", rloc, iloc) ; */ ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; ar2 = rowAT2[rloc] ; ai2 = rowAT2[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; /* fprintf(stdout, "\n %% a0 = (%12.4e,%12.4e)", ar0, ai0) ; fprintf(stdout, "\n %% a1 = (%12.4e,%12.4e)", ar1, ai1) ; fprintf(stdout, "\n %% a2 = (%12.4e,%12.4e)", ar2, ai2) ; fprintf(stdout, "\n %% x0 = (%12.4e,%12.4e)", xr0, xi0) ; */ rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; rsum20 += ar2*xr0 + ai2*xi0 ; isum20 += ar2*xi0 - ai2*xr0 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; ar2 = rowAT2[raloc] ; ai2 = rowAT2[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; rsum20 += ar2*xr0 + ai2*xi0 ; isum20 += ar2*xi0 - ai2*xr0 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; rloc = 2*rowindAT[irowAT+2] ; iloc = rloc + 1 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; } rowAT0 = rowAT2 + 2*ncolAT ; } if ( irowAT == nrowAT - 2 ) { double ai0, ai1, ar0, ar1, isum00, isum10, rsum00, rsum10, xi0, xr0 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum10 = 0.0 ; rsum00 = rsum10 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; rsum10 += ar1*xr0 + ai1*xi0 ; isum10 += ar1*xi0 - ai1*xr0 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; } } else if ( irowAT == nrowAT - 1 ) { double ai0, ar0, isum00, rsum00, xi0, xr0 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = 0.0 ; rsum00 = 0.0 ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; rsum00 += ar0*xr0 + ai0*xi0 ; isum00 += ar0*xi0 - ai0*xr0 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------- A has sparse columns -------------------- */ static void complex_updSparseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int ii, iloc, inc1, inc2, irowAT, jcolX, kk, ncolAT, ncolX, ncolY, nentA, nrowAT, nrowX, nrowY, rloc, size ; int *colindAT, *indices, *rowindAT, *sizes ; /* fprintf(stdout, "\n UPDATE_SPARSE_ROWS(%d,%d)", mtxA->rowid, mtxA->colid) ; */ SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_sparseColumnsInfo(mtxA, &nrowAT, &nentA, &sizes, &indices, &entA) ; if ( (ncolAT = mtxA->nrow) != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( (nrowAT = mtxA->ncol) != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { double ai, ar, isum0, isum1, isum2, rsum0, rsum1, rsum2, xi0, xi1, xi2, xr0, xr1, xr2 ; colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; for ( irowAT = kk = 0 ; irowAT < nrowAT ; irowAT++ ) { if ( (size = sizes[irowAT]) > 0 ) { isum0 = isum1 = isum2 = rsum0 = rsum1 = rsum2 = 0.0 ; if ( ncolAT == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum0 += ar*xr0 + ai*xi0 ; isum0 += ar*xi0 - ai*xr0 ; rsum1 += ar*xr1 + ai*xi1 ; isum1 += ar*xi1 - ai*xr1 ; rsum2 += ar*xr2 + ai*xi2 ; isum2 += ar*xi2 - ai*xr2 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*colindAT[indices[kk]] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum0 += ar*xr0 + ai*xi0 ; isum0 += ar*xi0 - ai*xr0 ; rsum1 += ar*xr1 + ai*xi1 ; isum1 += ar*xi1 - ai*xr1 ; rsum2 += ar*xr2 + ai*xi2 ; isum2 += ar*xi2 - ai*xr2 ; } } if ( nrowAT == nrowY ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; colY1[rloc] -= rsum1 ; colY1[iloc] -= isum1 ; colY2[rloc] -= rsum2 ; colY2[iloc] -= isum2 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; colY1[rloc] -= rsum1 ; colY1[iloc] -= isum1 ; colY2[rloc] -= rsum2 ; colY2[iloc] -= isum2 ; } } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } if ( jcolX == ncolX - 2 ) { double ai, ar, isum0, isum1, rsum0, rsum1, xi0, xi1, xr0, xr1 ; colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; for ( irowAT = kk = 0 ; irowAT < nrowAT ; irowAT++ ) { if ( (size = sizes[irowAT]) > 0 ) { isum0 = isum1 = rsum0 = rsum1 = 0.0 ; if ( ncolAT == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum0 += ar*xr0 + ai*xi0 ; isum0 += ar*xi0 - ai*xr0 ; rsum1 += ar*xr1 + ai*xi1 ; isum1 += ar*xi1 - ai*xr1 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*colindAT[indices[kk]] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum0 += ar*xr0 + ai*xi0 ; isum0 += ar*xi0 - ai*xr0 ; rsum1 += ar*xr1 + ai*xi1 ; isum1 += ar*xi1 - ai*xr1 ; } } if ( nrowAT == nrowY ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; colY1[rloc] -= rsum1 ; colY1[iloc] -= isum1 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; colY1[rloc] -= rsum1 ; colY1[iloc] -= isum1 ; } } } } else if ( jcolX == ncolX - 1 ) { double ai, ar, isum0, rsum0, xi0, xr0 ; for ( irowAT = kk = 0 ; irowAT < nrowAT ; irowAT++ ) { if ( (size = sizes[irowAT]) > 0 ) { isum0 = rsum0 = 0.0 ; if ( ncolAT == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; rsum0 += ar*xr0 + ai*xi0 ; isum0 += ar*xi0 - ai*xr0 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*colindAT[indices[kk]] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; rsum0 += ar*xr0 + ai*xi0 ; isum0 += ar*xi0 - ai*xr0 ; } } if ( nrowAT == nrowY ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------- A has sparse rows ----------------- */ static void complex_updSparseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int ii, inc1, inc2, jcolAT, jcolX, jrowX, kk, ncolAT, ncolX, ncolY, nentA, nrowAT, nrowX, nrowY, size ; int *colindAT, *indices, *rowindAT, *sizes ; /* fprintf(stdout, "\n UPDATE_SPARSE_COLUMNS(%d,%d)", mtxA->rowid, mtxA->colid) ; */ SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_sparseRowsInfo(mtxA, &ncolAT, &nentA, &sizes, &indices, &entA) ; if ( (ncolAT = mtxA->nrow) != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( (nrowAT = mtxA->ncol) != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { double ai, ar, xi0, xi1, xi2, xr0, xr1, xr2 ; int iloc, rloc ; colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; for ( jcolAT = kk = 0 ; jcolAT < ncolAT ; jcolAT++ ) { if ( (size = sizes[jcolAT]) > 0 ) { if ( ncolAT == nrowX ) { jrowX = jcolAT ; } else { jrowX = colindAT[jcolAT] ; } rloc = 2*jrowX ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; if ( nrowAT == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 + ai*xi0 ; colY0[iloc] -= ar*xi0 - ai*xr0 ; colY1[rloc] -= ar*xr1 + ai*xi1 ; colY1[iloc] -= ar*xi1 - ai*xr1 ; colY2[rloc] -= ar*xr2 + ai*xi2 ; colY2[iloc] -= ar*xi2 - ai*xr2 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*rowindAT[indices[kk]] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 + ai*xi0 ; colY0[iloc] -= ar*xi0 - ai*xr0 ; colY1[rloc] -= ar*xr1 + ai*xi1 ; colY1[iloc] -= ar*xi1 - ai*xr1 ; colY2[rloc] -= ar*xr2 + ai*xi2 ; colY2[iloc] -= ar*xi2 - ai*xr2 ; } } } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } if ( jcolX == ncolX - 2 ) { double ai, ar, xi0, xi1, xr0, xr1 ; int iloc, rloc ; colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; for ( jcolAT = kk = 0 ; jcolAT < ncolAT ; jcolAT++ ) { if ( (size = sizes[jcolAT]) > 0 ) { if ( ncolAT == nrowX ) { jrowX = jcolAT ; } else { jrowX = colindAT[jcolAT] ; } rloc = 2*jrowX ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; if ( nrowAT == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 + ai*xi0 ; colY0[iloc] -= ar*xi0 - ai*xr0 ; colY1[rloc] -= ar*xr1 + ai*xi1 ; colY1[iloc] -= ar*xi1 - ai*xr1 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*rowindAT[indices[kk]] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 + ai*xi0 ; colY0[iloc] -= ar*xi0 - ai*xr0 ; colY1[rloc] -= ar*xr1 + ai*xi1 ; colY1[iloc] -= ar*xi1 - ai*xr1 ; } } } } } else if ( jcolX == ncolX - 1 ) { double ai, ar, xi0, xr0 ; int iloc, rloc ; for ( jcolAT = kk = 0 ; jcolAT < ncolAT ; jcolAT++ ) { if ( (size = sizes[jcolAT]) > 0 ) { if ( ncolAT == nrowX ) { jrowX = jcolAT ; } else { jrowX = colindAT[jcolAT] ; } rloc = 2*jrowX ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; if ( nrowAT == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 + ai*xi0 ; colY0[iloc] -= ar*xi0 - ai*xr0 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*rowindAT[indices[kk]] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 + ai*xi0 ; colY0[iloc] -= ar*xi0 - ai*xr0 ; } } } } } return ; } /*--------------------------------------------------------------------*/ rsum0, rsum1, rsum2, xi0, xi1, xi2, xr0, xr1, xr2 ; colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; for ( irowAT = kk = 0 ; irowAT < nrowAT ; irowAT++ ) { if ( (size = sizes[irowAT]) > 0 ) { isum0 = isum1 = isum2 = rsum0 = rsum1 = rsum2 = 0.0 ; SubMtx/src/solveupdT.c010064400020550007177000002711070653410625200162460ustar00clevecompmath00000400000006/* solveupdT.c */ #include "../SubMtx.h" /*--------------------------------------------------------------------*/ static void real_updDenseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void real_updDenseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void real_updSparseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void real_updSparseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void complex_updDenseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void complex_updDenseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void complex_updSparseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; static void complex_updSparseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- perform the matrix-matrix multiply Y := Y - A^T * X used in the forward and backsolves where (1) rows(A) \subseteq rows(Y) (2) rows(A) are local w.r.t. rows(Y) (3) cols(A) \subseteq rows(X) (4) cols(A) are local w.r.t. rows(X) (5) cols(Y) = cols(X) (6) Y and X have type SUBMTX_DENSE_COLUMNS created -- 98may02, cca ----------------------------------------------------- */ void SubMtx_solveupdT ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { /* --------------- check the input --------------- */ if ( mtxY == NULL || mtxA == NULL || mtxX == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_solveupdT(%p,%p,%p)" "\n bad input\n", mtxY, mtxA, mtxX) ; exit(-1) ; } if ( ! SUBMTX_IS_DENSE_COLUMNS(mtxY) ) { fprintf(stderr, "\n fatal error in SubMtx_solveupdT(%p,%p,%p)" "\n Y must have mode SUBMTX_DENSE_COLUMNS\n", mtxY, mtxA, mtxX) ; exit(-1) ; } if ( ! SUBMTX_IS_DENSE_COLUMNS(mtxX) ) { fprintf(stderr, "\n fatal error in SubMtx_solveupdT(%p,%p,%p)" "\n X must have mode SUBMTX_DENSE_COLUMNS\n", mtxY, mtxA, mtxX) ; exit(-1) ; } switch ( mtxA->type ) { case SPOOLES_REAL : switch ( mtxA->mode ) { case SUBMTX_DENSE_COLUMNS : real_updDenseColumns(mtxY, mtxA, mtxX) ; break ; case SUBMTX_DENSE_ROWS : real_updDenseRows(mtxY, mtxA, mtxX) ; break ; case SUBMTX_SPARSE_ROWS : real_updSparseRows(mtxY, mtxA, mtxX) ; break ; case SUBMTX_SPARSE_COLUMNS : real_updSparseColumns(mtxY, mtxA, mtxX) ; break ; default : fprintf(stderr, "\n fatal error in SubMtx_solveupdT(%p,%p,%p)" "\n unsupported mode %d for A\n", mtxY, mtxA, mtxX, mtxA->mode) ; exit(-1) ; break ; } break ; case SPOOLES_COMPLEX : switch ( mtxA->mode ) { case SUBMTX_DENSE_COLUMNS : complex_updDenseColumns(mtxY, mtxA, mtxX) ; break ; case SUBMTX_DENSE_ROWS : complex_updDenseRows(mtxY, mtxA, mtxX) ; break ; case SUBMTX_SPARSE_ROWS : complex_updSparseRows(mtxY, mtxA, mtxX) ; break ; case SUBMTX_SPARSE_COLUMNS : complex_updSparseColumns(mtxY, mtxA, mtxX) ; break ; default : fprintf(stderr, "\n fatal error in SubMtx_solveupdT(%p,%p,%p)" "\n unsupported mode %d for A\n", mtxY, mtxA, mtxX, mtxA->mode) ; exit(-1) ; break ; } break ; default : fprintf(stderr, "\n fatal error in SubMtx_solveupdT(%p,%p,%p)" "\n unsupported type %d for A\n", mtxY, mtxA, mtxX, mtxA->type) ; exit(-1) ; break ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------- A has dense rows ---------------- */ static void real_updDenseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double Ak0, Ak1, Ak2, x00, x01, x02, x10, x11, x12, x20, x21, x22 ; double *colAT0, *colAT1, *colAT2, *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int icolAT, inc1, inc2, irowX, jcolX, krowAT, krowY, ncolAT, ncolX, ncolY, nrowAT, nrowX, nrowY ; int *colindAT, *rowindAT ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_denseInfo(mtxA, &ncolAT, &nrowAT, &inc1, &inc2, &entA) ; colX0 = entX ; colY0 = entY ; if ( ncolAT != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( nrowAT != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + nrowX ; colX2 = colX1 + nrowX ; colY1 = colY0 + nrowY ; colY2 = colY1 + nrowY ; colAT0 = entA ; for ( icolAT = 0 ; icolAT < ncolAT - 2 ; icolAT += 3 ) { colAT1 = colAT0 + nrowAT ; colAT2 = colAT1 + nrowAT ; if ( ncolAT == nrowX ) { x00 = colX0[icolAT] ; x01 = colX1[icolAT] ; x02 = colX2[icolAT] ; x10 = colX0[icolAT+1] ; x11 = colX1[icolAT+1] ; x12 = colX2[icolAT+1] ; x20 = colX0[icolAT+2] ; x21 = colX1[icolAT+2] ; x22 = colX2[icolAT+2] ; } else { irowX = colindAT[icolAT] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; x02 = colX2[irowX] ; irowX = colindAT[icolAT+1] ; x10 = colX0[irowX] ; x11 = colX1[irowX] ; x12 = colX2[irowX] ; irowX = colindAT[icolAT+2] ; x20 = colX0[irowX] ; x21 = colX1[irowX] ; x22 = colX2[irowX] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; Ak2 = colAT2[krowAT] ; colY0[krowAT] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; colY1[krowAT] -= Ak0 * x01 + Ak1 * x11 + Ak2 * x21 ; colY2[krowAT] -= Ak0 * x02 + Ak1 * x12 + Ak2 * x22 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; Ak2 = colAT2[krowAT] ; krowY = rowindAT[krowAT] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; colY1[krowY] -= Ak0 * x01 + Ak1 * x11 + Ak2 * x21 ; colY2[krowY] -= Ak0 * x02 + Ak1 * x12 + Ak2 * x22 ; } } colAT0 = colAT2 + nrowAT ; } if ( icolAT == ncolAT - 2 ) { colAT1 = colAT0 + nrowAT ; if ( ncolAT == nrowX ) { x00 = colX0[icolAT] ; x01 = colX1[icolAT] ; x02 = colX2[icolAT] ; x10 = colX0[icolAT+1] ; x11 = colX1[icolAT+1] ; x12 = colX2[icolAT+1] ; } else { irowX = colindAT[icolAT] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; x02 = colX2[irowX] ; irowX = colindAT[icolAT+1] ; x10 = colX0[irowX] ; x11 = colX1[irowX] ; x12 = colX2[irowX] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; colY0[krowAT] -= Ak0 * x00 + Ak1 * x10 ; colY1[krowAT] -= Ak0 * x01 + Ak1 * x11 ; colY2[krowAT] -= Ak0 * x02 + Ak1 * x12 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; krowY = rowindAT[krowAT] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 ; colY1[krowY] -= Ak0 * x01 + Ak1 * x11 ; colY2[krowY] -= Ak0 * x02 + Ak1 * x12 ; } } } else if ( icolAT == ncolAT - 1 ) { if ( ncolAT == nrowX ) { x00 = colX0[icolAT] ; x01 = colX1[icolAT] ; x02 = colX2[icolAT] ; } else { irowX = colindAT[icolAT] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; x02 = colX2[irowX] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; colY0[krowAT] -= Ak0 * x00 ; colY1[krowAT] -= Ak0 * x01 ; colY2[krowAT] -= Ak0 * x02 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; krowY = rowindAT[krowAT] ; colY0[krowY] -= Ak0 * x00 ; colY1[krowY] -= Ak0 * x01 ; colY2[krowY] -= Ak0 * x02 ; } } } colX0 = colX2 + nrowX ; colY0 = colY2 + nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + nrowX ; colY1 = colY0 + nrowY ; colAT0 = entA ; for ( icolAT = 0 ; icolAT < ncolAT - 2 ; icolAT += 3 ) { colAT1 = colAT0 + nrowAT ; colAT2 = colAT1 + nrowAT ; if ( ncolAT == nrowX ) { x00 = colX0[icolAT] ; x01 = colX1[icolAT] ; x10 = colX0[icolAT+1] ; x11 = colX1[icolAT+1] ; x20 = colX0[icolAT+2] ; x21 = colX1[icolAT+2] ; } else { irowX = colindAT[icolAT] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; irowX = colindAT[icolAT+1] ; x10 = colX0[irowX] ; x11 = colX1[irowX] ; irowX = colindAT[icolAT+2] ; x20 = colX0[irowX] ; x21 = colX1[irowX] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; Ak2 = colAT2[krowAT] ; colY0[krowAT] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; colY1[krowAT] -= Ak0 * x01 + Ak1 * x11 + Ak2 * x21 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; Ak2 = colAT2[krowAT] ; krowY = rowindAT[krowAT] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; colY1[krowY] -= Ak0 * x01 + Ak1 * x11 + Ak2 * x21 ; } } colAT0 = colAT2 + nrowAT ; } if ( icolAT == ncolAT - 2 ) { colAT1 = colAT0 + nrowAT ; if ( ncolAT == nrowX ) { x00 = colX0[icolAT] ; x01 = colX1[icolAT] ; x10 = colX0[icolAT+1] ; x11 = colX1[icolAT+1] ; } else { irowX = colindAT[icolAT] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; irowX = colindAT[icolAT+1] ; x10 = colX0[irowX] ; x11 = colX1[irowX] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; colY0[krowAT] -= Ak0 * x00 + Ak1 * x10 ; colY1[krowAT] -= Ak0 * x01 + Ak1 * x11 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; krowY = rowindAT[krowAT] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 ; colY1[krowY] -= Ak0 * x01 + Ak1 * x11 ; } } } else if ( icolAT == ncolAT - 1 ) { if ( ncolAT == nrowX ) { x00 = colX0[icolAT] ; x01 = colX1[icolAT] ; } else { irowX = colindAT[icolAT] ; x00 = colX0[irowX] ; x01 = colX1[irowX] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; colY0[krowAT] -= Ak0 * x00 ; colY1[krowAT] -= Ak0 * x01 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; krowY = rowindAT[krowAT] ; colY0[krowY] -= Ak0 * x00 ; colY1[krowY] -= Ak0 * x01 ; } } } } else if ( jcolX == ncolX - 1 ) { colAT0 = entA ; for ( icolAT = 0 ; icolAT < ncolAT - 2 ; icolAT += 3 ) { colAT1 = colAT0 + nrowAT ; colAT2 = colAT1 + nrowAT ; if ( ncolAT == nrowX ) { x00 = colX0[icolAT] ; x10 = colX0[icolAT+1] ; x20 = colX0[icolAT+2] ; } else { irowX = colindAT[icolAT] ; x00 = colX0[irowX] ; irowX = colindAT[icolAT+1] ; x10 = colX0[irowX] ; irowX = colindAT[icolAT+2] ; x20 = colX0[irowX] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; Ak2 = colAT2[krowAT] ; colY0[krowAT] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; Ak2 = colAT2[krowAT] ; krowY = rowindAT[krowAT] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 + Ak2 * x20 ; } } colAT0 = colAT2 + nrowAT ; } if ( icolAT == ncolAT - 2 ) { colAT1 = colAT0 + nrowAT ; if ( ncolAT == nrowX ) { x00 = colX0[icolAT] ; x10 = colX0[icolAT+1] ; } else { irowX = colindAT[icolAT] ; x00 = colX0[irowX] ; irowX = colindAT[icolAT+1] ; x10 = colX0[irowX] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; colY0[krowAT] -= Ak0 * x00 + Ak1 * x10 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; Ak1 = colAT1[krowAT] ; krowY = rowindAT[krowAT] ; colY0[krowY] -= Ak0 * x00 + Ak1 * x10 ; } } } else if ( icolAT == ncolAT - 1 ) { if ( ncolAT == nrowX ) { x00 = colX0[icolAT] ; } else { irowX = colindAT[icolAT] ; x00 = colX0[irowX] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; colY0[krowAT] -= Ak0 * x00 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { Ak0 = colAT0[krowAT] ; krowY = rowindAT[krowAT] ; colY0[krowY] -= Ak0 * x00 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------- A has dense rows ---------------- */ static void real_updDenseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *rowAT0, *rowAT1, *rowAT2, *entA, *entX, *entY ; int inc1, inc2, irowAT, irowY, jcolX, kcolAT, krowX, ncolAT, ncolX, ncolY, nrowAT, nrowX, nrowY ; int *colindAT, *rowindAT ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_denseInfo(mtxA, &ncolAT, &nrowAT, &inc1, &inc2, &entA) ; if ( ncolAT != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( nrowAT != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + nrowX ; colX2 = colX1 + nrowX ; colY1 = colY0 + nrowY ; colY2 = colY1 + nrowY ; rowAT0 = entA ; for ( irowAT = 0 ; irowAT < nrowAT - 2 ; irowAT += 3 ) { double A0k, A1k, A2k, Xk0, Xk1, Xk2 ; double sum00, sum01, sum02, sum10, sum11, sum12, sum20, sum21, sum22 ; sum00 = sum01 = sum02 = sum10 = sum11 = sum12 = sum20 = sum21 = sum22 = 0.0 ; rowAT1 = rowAT0 + ncolAT ; rowAT2 = rowAT1 + ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; A2k = rowAT2[kcolAT] ; Xk0 = colX0[kcolAT] ; Xk1 = colX1[kcolAT] ; Xk2 = colX2[kcolAT] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum12 += A1k * Xk2 ; sum20 += A2k * Xk0 ; sum21 += A2k * Xk1 ; sum22 += A2k * Xk2 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; A2k = rowAT2[kcolAT] ; krowX = colindAT[kcolAT] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; Xk2 = colX2[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum12 += A1k * Xk2 ; sum20 += A2k * Xk0 ; sum21 += A2k * Xk1 ; sum22 += A2k * Xk2 ; } } if ( nrowY == nrowAT ) { colY0[irowAT] -= sum00 ; colY1[irowAT] -= sum01 ; colY2[irowAT] -= sum02 ; colY0[irowAT+1] -= sum10 ; colY1[irowAT+1] -= sum11 ; colY2[irowAT+1] -= sum12 ; colY0[irowAT+2] -= sum20 ; colY1[irowAT+2] -= sum21 ; colY2[irowAT+2] -= sum22 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; colY2[irowY] -= sum02 ; irowY = rowindAT[irowAT+1] ; colY0[irowY] -= sum10 ; colY1[irowY] -= sum11 ; colY2[irowY] -= sum12 ; irowY = rowindAT[irowAT+2] ; colY0[irowY] -= sum20 ; colY1[irowY] -= sum21 ; colY2[irowY] -= sum22 ; } rowAT0 = rowAT2 + ncolAT ; } if ( irowAT == nrowAT - 2 ) { double A0k, A1k, Xk0, Xk1, Xk2 ; double sum00, sum01, sum02, sum10, sum11, sum12 ; sum00 = sum01 = sum02 = sum10 = sum11 = sum12 = 0.0 ; rowAT1 = rowAT0 + ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; Xk0 = colX0[kcolAT] ; Xk1 = colX1[kcolAT] ; Xk2 = colX2[kcolAT] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum12 += A1k * Xk2 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; krowX = colindAT[kcolAT] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; Xk2 = colX2[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum12 += A1k * Xk2 ; } } if ( nrowY == nrowAT ) { colY0[irowAT] -= sum00 ; colY1[irowAT] -= sum01 ; colY2[irowAT] -= sum02 ; colY0[irowAT+1] -= sum10 ; colY1[irowAT+1] -= sum11 ; colY2[irowAT+1] -= sum12 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; colY2[irowY] -= sum02 ; irowY = rowindAT[irowAT+1] ; colY0[irowY] -= sum10 ; colY1[irowY] -= sum11 ; colY2[irowY] -= sum12 ; } } else if ( irowAT == nrowAT - 1 ) { double A0k, Xk0, Xk1, Xk2 ; double sum00, sum01, sum02 ; sum00 = sum01 = sum02 = 0.0 ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; Xk0 = colX0[kcolAT] ; Xk1 = colX1[kcolAT] ; Xk2 = colX2[kcolAT] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; krowX = colindAT[kcolAT] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; Xk2 = colX2[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum02 += A0k * Xk2 ; } } if ( nrowY == nrowAT ) { colY0[irowAT] -= sum00 ; colY1[irowAT] -= sum01 ; colY2[irowAT] -= sum02 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; colY2[irowY] -= sum02 ; } } colX0 = colX2 + nrowX ; colY0 = colY2 + nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + nrowX ; colY1 = colY0 + nrowY ; rowAT0 = entA ; for ( irowAT = 0 ; irowAT < nrowAT - 2 ; irowAT += 3 ) { double A0k, A1k, A2k, Xk0, Xk1 ; double sum00, sum01, sum10, sum11, sum20, sum21 ; sum00 = sum01 = sum10 = sum11 = sum20 = sum21 = 0.0 ; rowAT1 = rowAT0 + ncolAT ; rowAT2 = rowAT1 + ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; A2k = rowAT2[kcolAT] ; Xk0 = colX0[kcolAT] ; Xk1 = colX1[kcolAT] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum20 += A2k * Xk0 ; sum21 += A2k * Xk1 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; A2k = rowAT2[kcolAT] ; krowX = colindAT[kcolAT] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; sum20 += A2k * Xk0 ; sum21 += A2k * Xk1 ; } } if ( nrowY == nrowAT ) { colY0[irowAT] -= sum00 ; colY1[irowAT] -= sum01 ; colY0[irowAT+1] -= sum10 ; colY1[irowAT+1] -= sum11 ; colY0[irowAT+2] -= sum20 ; colY1[irowAT+2] -= sum21 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; irowY = rowindAT[irowAT+1] ; colY0[irowY] -= sum10 ; colY1[irowY] -= sum11 ; irowY = rowindAT[irowAT+2] ; colY0[irowY] -= sum20 ; colY1[irowY] -= sum21 ; } rowAT0 = rowAT2 + ncolAT ; } if ( irowAT == nrowAT - 2 ) { double A0k, A1k, Xk0, Xk1 ; double sum00, sum01, sum10, sum11 ; sum00 = sum01 = sum10 = sum11 = 0.0 ; rowAT1 = rowAT0 + ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; Xk0 = colX0[kcolAT] ; Xk1 = colX1[kcolAT] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; krowX = colindAT[kcolAT] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; sum10 += A1k * Xk0 ; sum11 += A1k * Xk1 ; } } if ( nrowY == nrowAT ) { colY0[irowAT] -= sum00 ; colY1[irowAT] -= sum01 ; colY0[irowAT+1] -= sum10 ; colY1[irowAT+1] -= sum11 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; irowY = rowindAT[irowAT+1] ; colY0[irowY] -= sum10 ; colY1[irowY] -= sum11 ; } } else if ( irowAT == nrowAT - 1 ) { double A0k, Xk0, Xk1 ; double sum00, sum01 ; sum00 = sum01 = 0.0 ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; Xk0 = colX0[kcolAT] ; Xk1 = colX1[kcolAT] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; krowX = colindAT[kcolAT] ; Xk0 = colX0[krowX] ; Xk1 = colX1[krowX] ; sum00 += A0k * Xk0 ; sum01 += A0k * Xk1 ; } } if ( nrowY == nrowAT ) { colY0[irowAT] -= sum00 ; colY1[irowAT] -= sum01 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum00 ; colY1[irowY] -= sum01 ; } } } else if ( jcolX == ncolX - 1 ) { rowAT0 = entA ; for ( irowAT = 0 ; irowAT < nrowAT - 2 ; irowAT += 3 ) { double A0k, A1k, A2k, Xk0 ; double sum00, sum10, sum20 ; sum00 = sum10 = sum20 = 0.0 ; rowAT1 = rowAT0 + ncolAT ; rowAT2 = rowAT1 + ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; A2k = rowAT2[kcolAT] ; Xk0 = colX0[kcolAT] ; sum00 += A0k * Xk0 ; sum10 += A1k * Xk0 ; sum20 += A2k * Xk0 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; A2k = rowAT2[kcolAT] ; krowX = colindAT[kcolAT] ; Xk0 = colX0[krowX] ; sum00 += A0k * Xk0 ; sum10 += A1k * Xk0 ; sum20 += A2k * Xk0 ; } } if ( nrowY == nrowAT ) { colY0[irowAT] -= sum00 ; colY0[irowAT+1] -= sum10 ; colY0[irowAT+2] -= sum20 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum00 ; irowY = rowindAT[irowAT+1] ; colY0[irowY] -= sum10 ; irowY = rowindAT[irowAT+2] ; colY0[irowY] -= sum20 ; } rowAT0 = rowAT2 + ncolAT ; } if ( irowAT == nrowAT - 2 ) { double A0k, A1k, Xk0 ; double sum00, sum10 ; sum00 = sum10 = 0.0 ; rowAT1 = rowAT0 + ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; Xk0 = colX0[kcolAT] ; sum00 += A0k * Xk0 ; sum10 += A1k * Xk0 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; A1k = rowAT1[kcolAT] ; krowX = colindAT[kcolAT] ; Xk0 = colX0[krowX] ; sum00 += A0k * Xk0 ; sum10 += A1k * Xk0 ; } } if ( nrowY == nrowAT ) { colY0[irowAT] -= sum00 ; colY0[irowAT+1] -= sum10 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum00 ; irowY = rowindAT[irowAT+1] ; colY0[irowY] -= sum10 ; } } else if ( irowAT == nrowAT - 1 ) { double A0k, Xk0 ; double sum00 ; sum00 = 0.0 ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; Xk0 = colX0[kcolAT] ; sum00 += A0k * Xk0 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { A0k = rowAT0[kcolAT] ; krowX = colindAT[kcolAT] ; Xk0 = colX0[krowX] ; sum00 += A0k * Xk0 ; } } if ( nrowY == nrowAT ) { colY0[irowAT] -= sum00 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum00 ; } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------- A has sparse columns -------------------- */ static void real_updSparseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double Aik, sum0, sum1, sum2 ; double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int ii, inc1, inc2, irowAT, irowY, jcolX, kk, krowX, ncolAT, ncolX, ncolY, nentA, nrowAT, nrowX, nrowY, size ; int *colindAT, *indices, *rowindAT, *sizes ; /* fprintf(stdout, "\n UPDATE_SPARSE_ROWS(%d,%d)", mtxA->rowid, mtxA->colid) ; */ SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_sparseColumnsInfo(mtxA, &nrowAT, &nentA, &sizes, &indices, &entA) ; if ( (ncolAT = mtxA->nrow) != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( (nrowAT = mtxA->ncol) != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + nrowX ; colX2 = colX1 + nrowX ; colY1 = colY0 + nrowY ; colY2 = colY1 + nrowY ; for ( irowAT = kk = 0 ; irowAT < nrowAT ; irowAT++ ) { if ( (size = sizes[irowAT]) > 0 ) { sum0 = sum1 = sum2 = 0.0 ; if ( ncolAT == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = indices[kk] ; sum0 += Aik * colX0[krowX] ; sum1 += Aik * colX1[krowX] ; sum2 += Aik * colX2[krowX] ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = colindAT[indices[kk]] ; sum0 += Aik * colX0[krowX] ; sum1 += Aik * colX1[krowX] ; sum2 += Aik * colX2[krowX] ; } } if ( nrowAT == nrowY ) { colY0[irowAT] -= sum0 ; colY1[irowAT] -= sum1 ; colY2[irowAT] -= sum2 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum0 ; colY1[irowY] -= sum1 ; colY2[irowY] -= sum2 ; } } } colX0 = colX2 + nrowX ; colY0 = colY2 + nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + nrowX ; colY1 = colY0 + nrowY ; for ( irowAT = kk = 0 ; irowAT < nrowAT ; irowAT++ ) { if ( (size = sizes[irowAT]) > 0 ) { sum0 = sum1 = 0.0 ; if ( ncolAT == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = indices[kk] ; sum0 += Aik * colX0[krowX] ; sum1 += Aik * colX1[krowX] ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = colindAT[indices[kk]] ; sum0 += Aik * colX0[krowX] ; sum1 += Aik * colX1[krowX] ; } } if ( nrowAT == nrowY ) { colY0[irowAT] -= sum0 ; colY1[irowAT] -= sum1 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum0 ; colY1[irowY] -= sum1 ; } } } } else if ( jcolX == ncolX - 1 ) { for ( irowAT = kk = 0 ; irowAT < nrowAT ; irowAT++ ) { if ( (size = sizes[irowAT]) > 0 ) { sum0 = 0.0 ; if ( ncolAT == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = indices[kk] ; sum0 += Aik * colX0[krowX] ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aik = entA[kk] ; krowX = colindAT[indices[kk]] ; sum0 += Aik * colX0[krowX] ; } } if ( nrowAT == nrowY ) { colY0[irowAT] -= sum0 ; } else { irowY = rowindAT[irowAT] ; colY0[irowY] -= sum0 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------- A has sparse rows ----------------- */ static void real_updSparseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double Aij, Xj0, Xj1, Xj2 ; double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int ii, inc1, inc2, irowY, jcolAT, jcolX, jrowX, kk, ncolAT, ncolX, ncolY, nentA, nrowAT, nrowX, nrowY, size ; int *colindAT, *indices, *rowindAT, *sizes ; /* fprintf(stdout, "\n UPDATE_SPARSE_COLUMNS(%d,%d)", mtxA->rowid, mtxA->colid) ; */ SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_sparseRowsInfo(mtxA, &ncolAT, &nentA, &sizes, &indices, &entA) ; if ( (ncolAT = mtxA->nrow) != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( (nrowAT = mtxA->ncol) != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + nrowX ; colX2 = colX1 + nrowX ; colY1 = colY0 + nrowY ; colY2 = colY1 + nrowY ; for ( jcolAT = kk = 0 ; jcolAT < ncolAT ; jcolAT++ ) { if ( (size = sizes[jcolAT]) > 0 ) { if ( ncolAT == nrowX ) { jrowX = jcolAT ; } else { jrowX = colindAT[jcolAT] ; } Xj0 = colX0[jrowX] ; Xj1 = colX1[jrowX] ; Xj2 = colX2[jrowX] ; if ( nrowAT == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = indices[kk] ; colY0[irowY] -= Aij * Xj0 ; colY1[irowY] -= Aij * Xj1 ; colY2[irowY] -= Aij * Xj2 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = rowindAT[indices[kk]] ; colY0[irowY] -= Aij * Xj0 ; colY1[irowY] -= Aij * Xj1 ; colY2[irowY] -= Aij * Xj2 ; } } } } colX0 = colX2 + nrowX ; colY0 = colY2 + nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + nrowX ; colY1 = colY0 + nrowY ; for ( jcolAT = kk = 0 ; jcolAT < ncolAT ; jcolAT++ ) { if ( (size = sizes[jcolAT]) > 0 ) { if ( ncolAT == nrowX ) { jrowX = jcolAT ; } else { jrowX = colindAT[jcolAT] ; } Xj0 = colX0[jrowX] ; Xj1 = colX1[jrowX] ; if ( nrowAT == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = indices[kk] ; colY0[irowY] -= Aij * Xj0 ; colY1[irowY] -= Aij * Xj1 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = rowindAT[indices[kk]] ; colY0[irowY] -= Aij * Xj0 ; colY1[irowY] -= Aij * Xj1 ; } } } } } else if ( jcolX == ncolX - 1 ) { for ( jcolAT = kk = 0 ; jcolAT < ncolAT ; jcolAT++ ) { if ( (size = sizes[jcolAT]) > 0 ) { if ( ncolAT == nrowX ) { jrowX = jcolAT ; } else { jrowX = colindAT[jcolAT] ; } Xj0 = colX0[jrowX] ; if ( nrowAT == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = indices[kk] ; colY0[irowY] -= Aij * Xj0 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { Aij = entA[kk] ; irowY = rowindAT[indices[kk]] ; colY0[irowY] -= Aij * Xj0 ; } } } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------- A has dense rows ---------------- */ static void complex_updDenseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double ai0, ai1, ai2, ar0, ar1, ar2, xi00, xi01, xi02, xi10, xi11, xi12, xi20, xi21, xi22, xr00, xr01, xr02, xr10, xr11, xr12, xr20, xr21, xr22 ; double *colAT0, *colAT1, *colAT2, *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int icolAT, ialoc, iloc, inc1, inc2, jcolX, krowAT, ncolAT, ncolX, ncolY, nrowAT, nrowX, nrowY, raloc, rloc ; int *colindAT, *rowindAT ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_denseInfo(mtxA, &ncolAT, &nrowAT, &inc1, &inc2, &entA) ; colX0 = entX ; colY0 = entY ; if ( ncolAT != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( nrowAT != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; colAT0 = entA ; for ( icolAT = 0 ; icolAT < ncolAT - 2 ; icolAT += 3 ) { colAT1 = colAT0 + 2*nrowAT ; colAT2 = colAT1 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; ar2 = colAT2[rloc] ; ai2 = colAT2[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 + ar2*xr21 - ai2*xi21 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 + ar2*xi21 + ai2*xr21 ; colY2[rloc] -= ar0*xr02 - ai0*xi02 + ar1*xr12 - ai1*xi12 + ar2*xr22 - ai2*xi22 ; colY2[iloc] -= ar0*xi02 + ai0*xr02 + ar1*xi12 + ai1*xr12 + ar2*xi22 + ai2*xr22 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; ar2 = colAT2[raloc] ; ai2 = colAT2[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 + ar2*xr21 - ai2*xi21 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 + ar2*xi21 + ai2*xr21 ; colY2[rloc] -= ar0*xr02 - ai0*xi02 + ar1*xr12 - ai1*xi12 + ar2*xr22 - ai2*xi22 ; colY2[iloc] -= ar0*xi02 + ai0*xr02 + ar1*xi12 + ai1*xr12 + ar2*xi22 + ai2*xr22 ; } } colAT0 = colAT2 + 2*nrowAT ; } if ( icolAT == ncolAT - 2 ) { colAT1 = colAT0 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 ; colY2[rloc] -= ar0*xr02 - ai0*xi02 + ar1*xr12 - ai1*xi12 ; colY2[iloc] -= ar0*xi02 + ai0*xr02 + ar1*xi12 + ai1*xr12 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 ; colY2[rloc] -= ar0*xr02 - ai0*xi02 + ar1*xr12 - ai1*xi12 ; colY2[iloc] -= ar0*xi02 + ai0*xr02 + ar1*xi12 + ai1*xr12 ; } } } else if ( icolAT == ncolAT - 1 ) { if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; xr02 = colX2[rloc] ; xi02 = colX2[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; xr12 = colX2[rloc] ; xi12 = colX2[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; xr22 = colX2[rloc] ; xi22 = colX2[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 ; colY2[rloc] -= ar0*xr02 - ai0*xi02 ; colY2[iloc] -= ar0*xi02 + ai0*xr02 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 - ai0*xi00 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 ; colY2[rloc] -= ar0*xr02 - ai0*xi02 ; colY2[iloc] -= ar0*xi02 + ai0*xr02 ; } } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } /* fprintf(stdout, "\n %% jcolX = %d", jcolX) ; */ if ( jcolX == ncolX - 2 ) { colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colAT0 = entA ; for ( icolAT = 0 ; icolAT < ncolAT - 2 ; icolAT += 3 ) { colAT1 = colAT0 + 2*nrowAT ; colAT2 = colAT1 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; ar2 = colAT2[rloc] ; ai2 = colAT2[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 + ar2*xr21 - ai2*xi21 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 + ar2*xi21 + ai2*xr21 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; ar2 = colAT2[raloc] ; ai2 = colAT2[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 + ar2*xr21 - ai2*xi21 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 + ar2*xi21 + ai2*xr21 ; } } colAT0 = colAT2 + 2*nrowAT ; } if ( icolAT == ncolAT - 2 ) { colAT1 = colAT0 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 + ar1*xr11 - ai1*xi11 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 + ar1*xi11 + ai1*xr11 ; } } } else if ( icolAT == ncolAT - 1 ) { if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; xr01 = colX1[rloc] ; xi01 = colX1[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; xr11 = colX1[rloc] ; xi11 = colX1[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; xr21 = colX1[rloc] ; xi21 = colX1[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 - ai0*xi00 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 ; colY1[rloc] -= ar0*xr01 - ai0*xi01 ; colY1[iloc] -= ar0*xi01 + ai0*xr01 ; } } } } else if ( jcolX == ncolX - 1 ) { colAT0 = entA ; for ( icolAT = 0 ; icolAT < ncolAT - 2 ; icolAT += 3 ) { /* fprintf(stdout, "\n %% icolAT = %d", icolAT) ; */ colAT1 = colAT0 + 2*nrowAT ; colAT2 = colAT1 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } /* fprintf(stdout, "\n %% x00 = (%12.4e,%12.4e)", xr00, xi00) ; fprintf(stdout, "\n %% x10 = (%12.4e,%12.4e)", xr10, xi10) ; fprintf(stdout, "\n %% x20 = (%12.4e,%12.4e)", xr20, xi20) ; */ if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; ar2 = colAT2[rloc] ; ai2 = colAT2[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; ar2 = colAT2[raloc] ; ai2 = colAT2[ialoc] ; /* fprintf(stdout, "\n %% raloc = %d, ialoc = %d", raloc, ialoc) ; fprintf(stdout, "\n %% a0 = (%12.4e,%12.4e)", ar0, ai0) ; fprintf(stdout, "\n %% a1 = (%12.4e,%12.4e)", ar1, ai1) ; fprintf(stdout, "\n %% a2 = (%12.4e,%12.4e)", ar2, ai2) ; */ rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; /* fprintf(stdout, "\n %% rloc = %d, iloc = %d", rloc, iloc) ; */ colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 + ar2*xr20 - ai2*xi20 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 + ar2*xi20 + ai2*xr20 ; } } colAT0 = colAT2 + 2*nrowAT ; } if ( icolAT == ncolAT - 2 ) { colAT1 = colAT0 + 2*nrowAT ; if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; ar1 = colAT1[rloc] ; ai1 = colAT1[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; ar1 = colAT1[raloc] ; ai1 = colAT1[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 - ai0*xi00 + ar1*xr10 - ai1*xi10 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 + ar1*xi10 + ai1*xr10 ; } } } else if ( icolAT == ncolAT - 1 ) { if ( ncolAT == nrowX ) { rloc = 2*icolAT ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc += 2 ; iloc += 2 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } else { rloc = 2*colindAT[icolAT] ; iloc = rloc + 1 ; xr00 = colX0[rloc] ; xi00 = colX0[iloc] ; rloc = 2*colindAT[icolAT+1] ; iloc = rloc + 1 ; xr10 = colX0[rloc] ; xi10 = colX0[iloc] ; rloc = 2*colindAT[icolAT+2] ; iloc = rloc + 1 ; xr20 = colX0[rloc] ; xi20 = colX0[iloc] ; } if ( nrowY == nrowAT ) { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { rloc = 2*krowAT ; iloc = rloc + 1 ; ar0 = colAT0[rloc] ; ai0 = colAT0[iloc] ; colY0[rloc] -= ar0*xr00 - ai0*xi00 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 ; } } else { for ( krowAT = 0 ; krowAT < nrowAT ; krowAT++ ) { raloc = 2*krowAT ; ialoc = raloc + 1 ; ar0 = colAT0[raloc] ; ai0 = colAT0[ialoc] ; rloc = 2*rowindAT[krowAT] ; iloc = rloc + 1 ; colY0[rloc] -= ar0*xr00 - ai0*xi00 ; colY0[iloc] -= ar0*xi00 + ai0*xr00 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------- A has dense rows ---------------- */ static void complex_updDenseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *rowAT0, *rowAT1, *rowAT2, *entA, *entX, *entY ; int inc1, inc2, irowAT, jcolX, kcolAT, ncolAT, ncolX, ncolY, nrowAT, nrowX, nrowY ; int *colindAT, *rowindAT ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_denseInfo(mtxA, &ncolAT, &nrowAT, &inc1, &inc2, &entA) ; if ( ncolAT != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( nrowAT != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; rowAT0 = entA ; for ( irowAT = 0 ; irowAT < nrowAT - 2 ; irowAT += 3 ) { double ai0, ai1, ai2, ar0, ar1, ar2, isum00, isum01, isum02, isum10, isum11, isum12, isum20, isum21, isum22, rsum00, rsum01, rsum02, rsum10, rsum11, rsum12, rsum20, rsum21, rsum22, xi0, xi1, xi2, xr0, xr1, xr2 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = isum02 = isum10 = isum11 = isum12 = isum20 = isum21 = isum22 = 0.0 ; rsum00 = rsum01 = rsum02 = rsum10 = rsum11 = rsum12 = rsum20 = rsum21 = rsum22 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; rowAT2 = rowAT1 + 2*ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; ar2 = rowAT2[rloc] ; ai2 = rowAT2[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum12 += ar1*xr2 - ai1*xi2 ; isum12 += ar1*xi2 + ai1*xr2 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; rsum21 += ar2*xr1 - ai2*xi1 ; isum21 += ar2*xi1 + ai2*xr1 ; rsum22 += ar2*xr2 - ai2*xi2 ; isum22 += ar2*xi2 + ai2*xr2 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; ar2 = rowAT2[raloc] ; ai2 = rowAT2[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; xr2 = colX2[rxloc] ; xi2 = colX2[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum12 += ar1*xr2 - ai1*xi2 ; isum12 += ar1*xi2 + ai1*xr2 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; rsum21 += ar2*xr1 - ai2*xi1 ; isum21 += ar2*xi1 + ai2*xr1 ; rsum22 += ar2*xr2 - ai2*xi2 ; isum22 += ar2*xi2 + ai2*xr2 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; colY2[rloc] -= rsum12 ; colY2[iloc] -= isum12 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; colY1[rloc] -= rsum21 ; colY1[iloc] -= isum21 ; colY2[rloc] -= rsum22 ; colY2[iloc] -= isum22 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; colY2[rloc] -= rsum12 ; colY2[iloc] -= isum12 ; rloc = 2*rowindAT[irowAT+2] ; iloc = rloc + 1 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; colY1[rloc] -= rsum21 ; colY1[iloc] -= isum21 ; colY2[rloc] -= rsum22 ; colY2[iloc] -= isum22 ; } rowAT0 = rowAT2 + 2*ncolAT ; } if ( irowAT == nrowAT - 2 ) { double ai0, ai1, ar0, ar1, isum00, isum01, isum02, isum10, isum11, isum12, rsum00, rsum01, rsum02, rsum10, rsum11, rsum12, xi0, xi1, xi2, xr0, xr1, xr2 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = isum02 = isum10 = isum11 = isum12 = 0.0 ; rsum00 = rsum01 = rsum02 = rsum10 = rsum11 = rsum12 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum12 += ar1*xr2 - ai1*xi2 ; isum12 += ar1*xi2 + ai1*xr2 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; xr2 = colX2[rxloc] ; xi2 = colX2[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum12 += ar1*xr2 - ai1*xi2 ; isum12 += ar1*xi2 + ai1*xr2 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; colY2[rloc] -= rsum12 ; colY2[iloc] -= isum12 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; colY2[rloc] -= rsum12 ; colY2[iloc] -= isum12 ; } } else if ( irowAT == nrowAT - 1 ) { double ai0, ar0, isum00, isum01, isum02, rsum00, rsum01, rsum02, xi0, xi1, xi2, xr0, xr1, xr2 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = isum02 = 0.0 ; rsum00 = rsum01 = rsum02 = 0.0 ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; xr2 = colX2[rxloc] ; xi2 = colX2[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum02 += ar0*xr2 - ai0*xi2 ; isum02 += ar0*xi2 + ai0*xr2 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; colY2[rloc] -= rsum02 ; colY2[iloc] -= isum02 ; } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } if ( jcolX == ncolX - 2 ) { colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; rowAT0 = entA ; for ( irowAT = 0 ; irowAT < nrowAT - 2 ; irowAT += 3 ) { double ai0, ai1, ai2, ar0, ar1, ar2, isum00, isum01, isum10, isum11, isum20, isum21, rsum00, rsum01, rsum10, rsum11, rsum20, rsum21, xi0, xi1, xr0, xr1 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = isum10 = isum11 = isum20 = isum21 = 0.0 ; rsum00 = rsum01 = rsum10 = rsum11 = rsum20 = rsum21 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; rowAT2 = rowAT1 + 2*ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; ar2 = rowAT2[rloc] ; ai2 = rowAT2[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; rsum21 += ar2*xr1 - ai2*xi1 ; isum21 += ar2*xi1 + ai2*xr1 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; ar2 = rowAT2[raloc] ; ai2 = rowAT2[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; rsum21 += ar2*xr1 - ai2*xi1 ; isum21 += ar2*xi1 + ai2*xr1 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; colY1[rloc] -= rsum21 ; colY1[iloc] -= isum21 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; rloc = 2*rowindAT[irowAT+2] ; iloc = rloc + 1 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; colY1[rloc] -= rsum21 ; colY1[iloc] -= isum21 ; } rowAT0 = rowAT2 + 2*ncolAT ; } if ( irowAT == nrowAT - 2 ) { double ai0, ai1, ar0, ar1, isum00, isum01, isum10, isum11, rsum00, rsum01, rsum10, rsum11, xi0, xi1, xr0, xr1 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = isum10 = isum11 = 0.0 ; rsum00 = rsum01 = rsum10 = rsum11 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum11 += ar1*xr1 - ai1*xi1 ; isum11 += ar1*xi1 + ai1*xr1 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; colY1[rloc] -= rsum11 ; colY1[iloc] -= isum11 ; } } else if ( irowAT == nrowAT - 1 ) { double ai0, ar0, isum00, isum01, rsum00, rsum01, xi0, xi1, xr0, xr1 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum01 = 0.0 ; rsum00 = rsum01 = 0.0 ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; xr1 = colX1[rxloc] ; xi1 = colX1[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum01 += ar0*xr1 - ai0*xi1 ; isum01 += ar0*xi1 + ai0*xr1 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; colY1[rloc] -= rsum01 ; colY1[iloc] -= isum01 ; } } } else if ( jcolX == ncolX - 1 ) { rowAT0 = entA ; for ( irowAT = 0 ; irowAT < nrowAT - 2 ; irowAT += 3 ) { double ai0, ai1, ai2, ar0, ar1, ar2, isum00, isum10, isum20, rsum00, rsum10, rsum20, xi0, xr0 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum10 = isum20 = 0.0 ; rsum00 = rsum10 = rsum20 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; rowAT2 = rowAT1 + 2*ncolAT ; /* fprintf(stdout, "\n %% irowAT %d", irowAT) ; */ if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; /* fprintf(stdout, "\n %% rloc %d, iloc %d", rloc, iloc) ; */ ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; ar2 = rowAT2[rloc] ; ai2 = rowAT2[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; /* fprintf(stdout, "\n %% a0 = (%12.4e,%12.4e)", ar0, ai0) ; fprintf(stdout, "\n %% a1 = (%12.4e,%12.4e)", ar1, ai1) ; fprintf(stdout, "\n %% a2 = (%12.4e,%12.4e)", ar2, ai2) ; fprintf(stdout, "\n %% x0 = (%12.4e,%12.4e)", xr0, xi0) ; */ rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; ar2 = rowAT2[raloc] ; ai2 = rowAT2[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; rsum20 += ar2*xr0 - ai2*xi0 ; isum20 += ar2*xi0 + ai2*xr0 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; rloc = 2*rowindAT[irowAT+2] ; iloc = rloc + 1 ; colY0[rloc] -= rsum20 ; colY0[iloc] -= isum20 ; } rowAT0 = rowAT2 + 2*ncolAT ; } if ( irowAT == nrowAT - 2 ) { double ai0, ai1, ar0, ar1, isum00, isum10, rsum00, rsum10, xi0, xr0 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = isum10 = 0.0 ; rsum00 = rsum10 = 0.0 ; rowAT1 = rowAT0 + 2*ncolAT ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; ar1 = rowAT1[rloc] ; ai1 = rowAT1[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; ar1 = rowAT1[raloc] ; ai1 = rowAT1[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; rsum10 += ar1*xr0 - ai1*xi0 ; isum10 += ar1*xi0 + ai1*xr0 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; rloc+= 2 ; iloc += 2 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; rloc = 2*rowindAT[irowAT+1] ; iloc = rloc + 1 ; colY0[rloc] -= rsum10 ; colY0[iloc] -= isum10 ; } } else if ( irowAT == nrowAT - 1 ) { double ai0, ar0, isum00, rsum00, xi0, xr0 ; int ialoc, iloc, ixloc, raloc, rloc, rxloc ; isum00 = 0.0 ; rsum00 = 0.0 ; if ( ncolAT == nrowX ) { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { rloc = 2*kcolAT ; iloc = rloc + 1 ; ar0 = rowAT0[rloc] ; ai0 = rowAT0[iloc] ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; } } else { for ( kcolAT = 0 ; kcolAT < ncolAT ; kcolAT++ ) { raloc = 2*kcolAT ; ialoc = raloc + 1 ; ar0 = rowAT0[raloc] ; ai0 = rowAT0[ialoc] ; rxloc = 2*colindAT[kcolAT] ; ixloc = rxloc + 1 ; xr0 = colX0[rxloc] ; xi0 = colX0[ixloc] ; rsum00 += ar0*xr0 - ai0*xi0 ; isum00 += ar0*xi0 + ai0*xr0 ; } } if ( nrowY == nrowAT ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum00 ; colY0[iloc] -= isum00 ; } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------- A has sparse columns -------------------- */ static void complex_updSparseColumns ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int ii, iloc, inc1, inc2, irowAT, jcolX, kk, ncolAT, ncolX, ncolY, nentA, nrowAT, nrowX, nrowY, rloc, size ; int *colindAT, *indices, *rowindAT, *sizes ; /* fprintf(stdout, "\n UPDATE_SPARSE_ROWS(%d,%d)", mtxA->rowid, mtxA->colid) ; */ SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_sparseColumnsInfo(mtxA, &nrowAT, &nentA, &sizes, &indices, &entA) ; if ( (ncolAT = mtxA->nrow) != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( (nrowAT = mtxA->ncol) != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { double ai, ar, isum0, isum1, isum2, rsum0, rsum1, rsum2, xi0, xi1, xi2, xr0, xr1, xr2 ; colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; for ( irowAT = kk = 0 ; irowAT < nrowAT ; irowAT++ ) { if ( (size = sizes[irowAT]) > 0 ) { isum0 = isum1 = isum2 = rsum0 = rsum1 = rsum2 = 0.0 ; if ( ncolAT == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; rsum1 += ar*xr1 - ai*xi1 ; isum1 += ar*xi1 + ai*xr1 ; rsum2 += ar*xr2 - ai*xi2 ; isum2 += ar*xi2 + ai*xr2 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*colindAT[indices[kk]] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; rsum1 += ar*xr1 - ai*xi1 ; isum1 += ar*xi1 + ai*xr1 ; rsum2 += ar*xr2 - ai*xi2 ; isum2 += ar*xi2 + ai*xr2 ; } } if ( nrowAT == nrowY ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; colY1[rloc] -= rsum1 ; colY1[iloc] -= isum1 ; colY2[rloc] -= rsum2 ; colY2[iloc] -= isum2 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; colY1[rloc] -= rsum1 ; colY1[iloc] -= isum1 ; colY2[rloc] -= rsum2 ; colY2[iloc] -= isum2 ; } } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } if ( jcolX == ncolX - 2 ) { double ai, ar, isum0, isum1, rsum0, rsum1, xi0, xi1, xr0, xr1 ; colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; for ( irowAT = kk = 0 ; irowAT < nrowAT ; irowAT++ ) { if ( (size = sizes[irowAT]) > 0 ) { isum0 = isum1 = rsum0 = rsum1 = 0.0 ; if ( ncolAT == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; rsum1 += ar*xr1 - ai*xi1 ; isum1 += ar*xi1 + ai*xr1 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*colindAT[indices[kk]] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; rsum1 += ar*xr1 - ai*xi1 ; isum1 += ar*xi1 + ai*xr1 ; } } if ( nrowAT == nrowY ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; colY1[rloc] -= rsum1 ; colY1[iloc] -= isum1 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; colY1[rloc] -= rsum1 ; colY1[iloc] -= isum1 ; } } } } else if ( jcolX == ncolX - 1 ) { double ai, ar, isum0, rsum0, xi0, xr0 ; for ( irowAT = kk = 0 ; irowAT < nrowAT ; irowAT++ ) { if ( (size = sizes[irowAT]) > 0 ) { isum0 = rsum0 = 0.0 ; if ( ncolAT == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*colindAT[indices[kk]] ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; rsum0 += ar*xr0 - ai*xi0 ; isum0 += ar*xi0 + ai*xr0 ; } } if ( nrowAT == nrowY ) { rloc = 2*irowAT ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; } else { rloc = 2*rowindAT[irowAT] ; iloc = rloc + 1 ; colY0[rloc] -= rsum0 ; colY0[iloc] -= isum0 ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------- A has sparse rows ----------------- */ static void complex_updSparseRows ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) { double *colX0, *colX1, *colX2, *colY0, *colY1, *colY2, *entA, *entX, *entY ; int ii, inc1, inc2, jcolAT, jcolX, jrowX, kk, ncolAT, ncolX, ncolY, nentA, nrowAT, nrowX, nrowY, size ; int *colindAT, *indices, *rowindAT, *sizes ; /* fprintf(stdout, "\n UPDATE_SPARSE_COLUMNS(%d,%d)", mtxA->rowid, mtxA->colid) ; */ SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; SubMtx_sparseRowsInfo(mtxA, &ncolAT, &nentA, &sizes, &indices, &entA) ; if ( (ncolAT = mtxA->nrow) != nrowX ) { SubMtx_rowIndices(mtxA, &ncolAT, &colindAT) ; } else { colindAT = NULL ; } if ( (nrowAT = mtxA->ncol) != nrowY ) { SubMtx_columnIndices(mtxA, &nrowAT, &rowindAT) ; } else { rowindAT = NULL ; } colX0 = entX ; colY0 = entY ; for ( jcolX = 0 ; jcolX < ncolX - 2 ; jcolX += 3 ) { double ai, ar, xi0, xi1, xi2, xr0, xr1, xr2 ; int iloc, rloc ; colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; for ( jcolAT = kk = 0 ; jcolAT < ncolAT ; jcolAT++ ) { if ( (size = sizes[jcolAT]) > 0 ) { if ( ncolAT == nrowX ) { jrowX = jcolAT ; } else { jrowX = colindAT[jcolAT] ; } rloc = 2*jrowX ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; xr2 = colX2[rloc] ; xi2 = colX2[iloc] ; if ( nrowAT == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; colY1[rloc] -= ar*xr1 - ai*xi1 ; colY1[iloc] -= ar*xi1 + ai*xr1 ; colY2[rloc] -= ar*xr2 - ai*xi2 ; colY2[iloc] -= ar*xi2 + ai*xr2 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*rowindAT[indices[kk]] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; colY1[rloc] -= ar*xr1 - ai*xi1 ; colY1[iloc] -= ar*xi1 + ai*xr1 ; colY2[rloc] -= ar*xr2 - ai*xi2 ; colY2[iloc] -= ar*xi2 + ai*xr2 ; } } } } colX0 = colX2 + 2*nrowX ; colY0 = colY2 + 2*nrowY ; } if ( jcolX == ncolX - 2 ) { double ai, ar, xi0, xi1, xr0, xr1 ; int iloc, rloc ; colX1 = colX0 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; for ( jcolAT = kk = 0 ; jcolAT < ncolAT ; jcolAT++ ) { if ( (size = sizes[jcolAT]) > 0 ) { if ( ncolAT == nrowX ) { jrowX = jcolAT ; } else { jrowX = colindAT[jcolAT] ; } rloc = 2*jrowX ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; xr1 = colX1[rloc] ; xi1 = colX1[iloc] ; if ( nrowAT == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; colY1[rloc] -= ar*xr1 - ai*xi1 ; colY1[iloc] -= ar*xi1 + ai*xr1 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*rowindAT[indices[kk]] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; colY1[rloc] -= ar*xr1 - ai*xi1 ; colY1[iloc] -= ar*xi1 + ai*xr1 ; } } } } } else if ( jcolX == ncolX - 1 ) { double ai, ar, xi0, xr0 ; int iloc, rloc ; for ( jcolAT = kk = 0 ; jcolAT < ncolAT ; jcolAT++ ) { if ( (size = sizes[jcolAT]) > 0 ) { if ( ncolAT == nrowX ) { jrowX = jcolAT ; } else { jrowX = colindAT[jcolAT] ; } rloc = 2*jrowX ; iloc = rloc + 1 ; xr0 = colX0[rloc] ; xi0 = colX0[iloc] ; if ( nrowAT == nrowY ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*indices[kk] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; } } else { for ( ii = 0 ; ii < size ; ii++, kk++ ) { ar = entA[2*kk] ; ai = entA[2*kk+1] ; rloc = 2*rowindAT[indices[kk]] ; iloc = rloc + 1 ; colY0[rloc] -= ar*xr0 - ai*xi0 ; colY0[iloc] -= ar*xi0 + ai*xr0 ; } } } } } return ; } /*--------------------------------------------------------------------*/ rsum0, rsum1, rsum2, xi0, xi1, xi2, xr0, xr1, xr2 ; colX1 = colX0 + 2*nrowX ; colX2 = colX1 + 2*nrowX ; colY1 = colY0 + 2*nrowY ; colY2 = colY1 + 2*nrowY ; for ( irowAT = kk = 0 ; irowAT < nrowAT ; irowAT++ ) { if ( (size = sizes[irowAT]) > 0 ) { isum0 = isum1 = isum2 = rsum0 = rsum1 = rsum2 = 0.0 ; if ( ncolAT == nrowX ) { for ( ii = 0 ; ii < size ; ii++, kk++ ) { SubMtx/src/sort.c010064400020550007177000000210560653410625200152440ustar00clevecompmath00000400000006/* sort.c */ #include "../SubMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- sort the rows of the matrix into ascending order created -- 98mar02, cca ----------------------------------------------------------- */ void SubMtx_sortRowsUp ( SubMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_sortRowsUp(%p)" "\n bad input\n", mtx) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtx) || SUBMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_sortRowsUp(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, mtx->type) ; exit(-1) ; } switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { A2 a2 ; double *entries ; int inc1, inc2, ncol, nrow ; int *rowind ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; A2_setDefaultFields(&a2) ; A2_init(&a2, mtx->type, nrow, ncol, inc1, inc2, entries) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; A2_sortRowsUp(&a2, nrow, rowind) ; } break ; case SUBMTX_SPARSE_ROWS : { double *entries ; int ii, irow, jrow, kk, nent, nrow, offset, rowid, size ; int *indices, *ivtemp, *rowind, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries); SubMtx_rowIndices(mtx, &nrow, &rowind) ; /* ---------------------------------------------------------------- get a companion vector and fill with the row id's of the entries ---------------------------------------------------------------- */ ivtemp = IVinit(nent, -1) ; for ( irow = kk = 0 ; irow < nrow ; irow++ ) { rowid = rowind[irow] ; size = sizes[irow] ; #if MYDEBUG > 0 fprintf(stdout, "\n rowid %d, size %d, kk %d", rowid, size, kk) ; fflush(stdout) ; #endif for ( ii = 0 ; ii < size ; ii++, kk++ ) { ivtemp[kk] = rowid ; } } #if MYDEBUG > 0 fprintf(stdout, "\n ivtemp[%d]", nent) ; IVfprintf(stdout, nent, ivtemp) ; fflush(stdout) ; #endif /* ----------------------------------------------------------- zero the sizes vector, sort the (rowid,colid,entry) triples into ascending order of rowids, and sort the row indices ----------------------------------------------------------- */ IVzero(nrow, sizes) ; if ( SUBMTX_IS_REAL(mtx) ) { IV2DVqsortUp(nent, ivtemp, indices, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { IV2ZVqsortUp(nent, ivtemp, indices, entries) ; } #if MYDEBUG > 0 fprintf(stdout, "\n after sort, ivtemp[%d]", nent) ; IVfprintf(stdout, nent, ivtemp) ; fflush(stdout) ; #endif IVqsortUp(nrow, rowind) ; #if MYDEBUG > 0 fprintf(stdout, "\n after sort, rowind") ; IVfprintf(stdout, nrow, rowind) ; fflush(stdout) ; #endif /* ---------------------------------------------------------------- sort each row in ascending order and fill the sizes[nrow] vector ---------------------------------------------------------------- */ rowid = ivtemp[0] ; jrow = offset = 0 ; kk = size = 1 ; while ( kk < nent ) { if ( ivtemp[kk] == rowid ) { size++ ; } else { while ( rowid != rowind[jrow] ) { #if MYDEBUG > 0 fprintf(stdout, "\n rowid %d, rowind[%d] %d", rowid, jrow, rowind[jrow]) ; fflush(stdout) ; #endif jrow++ ; } sizes[jrow] = size ; if ( SUBMTX_IS_REAL(mtx) ) { IVDVqsortUp(size, indices + offset, entries + offset) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { IVZVqsortUp(size, indices + offset, entries + 2*offset) ; } rowid = ivtemp[kk] ; jrow++ ; offset += size ; size = 1 ; } kk++ ; } while ( rowid != rowind[jrow] ) { #if MYDEBUG > 0 fprintf(stdout, "\n rowid %d, rowind[%d] %d", rowid, jrow, rowind[jrow]) ; fflush(stdout) ; #endif jrow++ ; } sizes[jrow] = size ; if ( SUBMTX_IS_REAL(mtx) ) { IVDVqsortUp(size, indices + offset, entries + offset) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { IVZVqsortUp(size, indices + offset, entries + 2*offset) ; } IVfree(ivtemp) ; } break ; default : fprintf(stderr, "\n fatal error in SubMtx_sortRowsUp(%p)" "\n bad type = %d", mtx, mtx->type) ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- purpose -- sort the columns of the matrix into ascending order created -- 98mar02, cca -------------------------------------------------------------- */ void SubMtx_sortColumnsUp ( SubMtx *mtx ) { switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { A2 a2 ; double *entries ; int inc1, inc2, ncol, nrow ; int *colind ; A2_setDefaultFields(&a2) ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; A2_init(&a2, mtx->type, nrow, ncol, inc1, inc2, entries) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; A2_sortColumnsUp(&a2, ncol, colind) ; } break ; case SUBMTX_SPARSE_COLUMNS : { double *entries ; int colid, ii, jcol, kk, ncol, nent, offset, size ; int *colind, *indices, *ivtemp, *sizes ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; /* ------------------------------------------------------------------- get a companion vector and fill with the column id's of the entries ------------------------------------------------------------------- */ ivtemp = IVinit(nent, -1) ; for ( jcol = kk = 0 ; jcol < ncol ; jcol++ ) { colid = colind[jcol] ; size = sizes[jcol] ; for ( ii = 0 ; ii < size ; ii++, kk++ ) { ivtemp[kk] = colid ; } } #if MYDEBUG > 0 fprintf(stdout, "\n ivtemp[%d]", nent) ; IVfprintf(stdout, nent, ivtemp) ; fflush(stdout) ; #endif /* ----------------------------------------------------------- zero the sizes vector, sort the (colid,rowid,entry) triples into ascending order of colids, and sort the column indices ----------------------------------------------------------- */ IVzero(ncol, sizes) ; if ( SUBMTX_IS_REAL(mtx) ) { IV2DVqsortUp(nent, ivtemp, indices, entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { IV2ZVqsortUp(nent, ivtemp, indices, entries) ; } #if MYDEBUG > 0 fprintf(stdout, "\n after sort, ivtemp[%d]", nent) ; IVfprintf(stdout, nent, ivtemp) ; fflush(stdout) ; #endif IVqsortUp(ncol, colind) ; #if MYDEBUG > 0 fprintf(stdout, "\n after sort, colind") ; IVfprintf(stdout, ncol, colind) ; fflush(stdout) ; #endif /* ------------------------------------------------------------------- sort each column in ascending order and fill the sizes[ncol] vector ------------------------------------------------------------------- */ colid = ivtemp[0] ; jcol = offset = 0 ; kk = size = 1 ; while ( kk < nent ) { if ( ivtemp[kk] == colid ) { size++ ; } else { while ( colid != colind[jcol] ) { #if MYDEBUG > 0 fprintf(stdout, "\n colid %d, colind[%d] %d", colid, jcol, colind[jcol]) ; fflush(stdout) ; #endif jcol++ ; } sizes[jcol] = size ; if ( SUBMTX_IS_REAL(mtx) ) { IVDVqsortUp(size, indices + offset, entries + offset) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { IVZVqsortUp(size, indices + offset, entries + 2*offset) ; } colid = ivtemp[kk] ; jcol++ ; offset += size ; size = 1 ; } kk++ ; } while ( colid != colind[jcol] ) { #if MYDEBUG > 0 fprintf(stdout, "\n colid %d, colind[%d] %d", colid, jcol, colind[jcol]) ; fflush(stdout) ; #endif jcol++ ; } sizes[jcol] = size ; if ( SUBMTX_IS_REAL(mtx) ) { IVDVqsortUp(size, indices + offset, entries + offset) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { IVZVqsortUp(size, indices + offset, entries + 2*offset) ; } IVfree(ivtemp) ; } break ; default : fprintf(stderr, "\n fatal error in SubMtx_sortColumnsUp(%p)" "\n bad type = %d", mtx, mtx->type) ; SubMtx_writeForHumanEye(mtx, stderr) ; exit(-1) ; } return ; } /*--------------------------------------------------------------------*/ dout) ; #endif jrow++ ; } sizes[jrow] = size ; if ( SUBMTX_IS_REAL(mtx) ) { IVDVqsortUp(size, indices + offset, entries + offset) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { IVZVqsortUp(size, indices + offset, entries + 2*offset) ; } IVfree(ivtemp) ; } break ; default : fprintf(stderr, "\n fatal error in SubMtx_sortRowsUp(%p)" "\n bad type = %d", mtx, mtx->type) ; exit(-1) ; } return ; } /*-------------------SubMtx/src/util.c010064400020550007177000000742300653410625200152340ustar00clevecompmath00000400000006/* util.c */ #include "../SubMtx.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to fill rowDV with the entries in row irow of the matrix created -- 98may01, cca ----------------------------------------- */ void SubMtx_fillRowDV ( SubMtx *mtx, int irow, DV *rowDV ) { double *rowvec ; /* --------------- check the input --------------- */ if ( mtx == NULL || irow < 0 || rowDV == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_fillRowDV(%p,%d,%p)" "\n bad input\n", mtx, irow, rowDV) ; exit(-1) ; } if ( ! SUBMTX_IS_REAL(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_fillRowDV(%p,%d,%p)" "\n type = %d, must be SPOOLES_REAL\n", mtx, irow, rowDV, mtx->type) ; exit(-1) ; } DV_setSize(rowDV, mtx->ncol) ; rowvec = DV_entries(rowDV) ; DVzero(mtx->ncol, rowvec) ; /* -------------------------------------- switch over the different matrix types -------------------------------------- */ switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { double *entries ; int inc1, inc2, jcol, loc, ncol, nrow ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { loc = irow*inc1 + jcol*inc2 ; rowvec[jcol] = entries[loc] ; } } break ; case SUBMTX_SPARSE_ROWS : { double *entries ; int ii, jrow, kk, nent, nrow, offset ; int *indices, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; for ( jrow = offset = 0 ; jrow < irow ; jrow++ ) { offset += sizes[jrow] ; } for ( ii = 0, kk = offset ; ii < sizes[irow] ; ii++, kk++ ) { rowvec[indices[kk]] = entries[kk] ; } } break ; case SUBMTX_SPARSE_COLUMNS : { double *entries ; int ii, jcol, kk, nent, ncol, offset ; int *indices, *sizes ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; for ( jcol = offset = 0 ; jcol < ncol ; jcol++ ) { for ( ii = 0, kk = offset ; ii < sizes[jcol] ; ii++, kk++ ) { if ( indices[kk] == irow ) { rowvec[jcol] = entries[kk] ; break ; } } offset += sizes[jcol] ; } } break ; case SUBMTX_SPARSE_TRIPLES : { double *entries ; int ii, nent ; int *colids, *rowids ; SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; for ( ii = 0 ; ii < nent ; ii++ ) { if ( rowids[ii] == irow ) { rowvec[colids[ii]] = entries[ii] ; } } } break ; case SUBMTX_DENSE_SUBROWS : { double *entries ; int first, ii, jrow, kk, last, nent, nrow, offset ; int *firstlocs, *sizes ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% entries(%d) :", nent) ; DVfprintf(stdout, nent, entries) ; #endif for ( jrow = offset = 0 ; jrow < irow ; jrow++ ) { offset += sizes[jrow] ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% irow = %d, offset = %d", irow, offset) ; fprintf(stdout, "\n %% first = %d, size = %d", firstlocs[irow], sizes[irow]) ; #endif if ( sizes[irow] > 0 ) { first = firstlocs[irow] ; last = first + sizes[irow] - 1 ; for ( kk = first, ii = offset ; kk <= last ; kk++, ii++ ) { rowvec[kk] = entries[ii] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% rowvec[%d] = entries[%d]", kk, ii) ; #endif } } } break ; case SUBMTX_DENSE_SUBCOLUMNS : { double *entries ; int first, jcol, last, loc, nent, ncol, offset ; int *firstlocs, *sizes ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; for ( jcol = offset = 0 ; jcol < ncol ; jcol++ ) { if ( sizes[jcol] > 0 ) { first = firstlocs[jcol] ; last = first + sizes[jcol] - 1 ; if ( first <= irow && irow <= last ) { loc = offset + irow - first ; rowvec[jcol] = entries[loc] ; } offset += sizes[jcol] ; } } } break ; case SUBMTX_DIAGONAL : { double *entries ; int nent ; SubMtx_diagonalInfo(mtx, &nent, &entries) ; rowvec[irow] = entries[irow] ; } break ; case SUBMTX_BLOCK_DIAGONAL_SYM : { double *entries ; int ii, ipivot, jrow, kk, m, nrow, nent, stride ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; for ( jrow = ipivot = kk = 0 ; jrow <= irow ; ipivot++ ) { m = pivotsizes[ipivot] ; /* fprintf(stdout, "\n jrow %d, m %d, kk %d", jrow, m, kk) ; fflush(stdout) ; */ if ( jrow <= irow && irow < jrow + m ) { stride = m - 1 ; kk += irow - jrow ; /* fprintf(stdout, "\n 0. kk %d, stride %d", kk, stride) ; fflush(stdout) ; */ for ( ii = jrow ; ii <= irow ; ii++ ) { /* fprintf(stdout, "\n 1. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ rowvec[ii] = entries[kk] ; kk += stride-- ; } for ( ; ii < jrow + m ; ii++ ) { /* fprintf(stdout, "\n 2. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ rowvec[ii] = entries[kk] ; kk++ ; } } else { kk += (m*(m+1))/2 ; } jrow += m ; } } break ; case SUBMTX_BLOCK_DIAGONAL_HERM : { double *entries ; int ii, ipivot, jrow, kk, m, nrow, nent, stride ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; for ( jrow = ipivot = kk = 0 ; jrow <= irow ; ipivot++ ) { m = pivotsizes[ipivot] ; /* fprintf(stdout, "\n jrow %d, m %d, kk %d", jrow, m, kk) ; fflush(stdout) ; */ if ( jrow <= irow && irow < jrow + m ) { stride = m - 1 ; kk += irow - jrow ; /* fprintf(stdout, "\n 0. kk %d, stride %d", kk, stride) ; fflush(stdout) ; */ for ( ii = jrow ; ii < irow ; ii++ ) { /* fprintf(stdout, "\n 1. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ rowvec[ii] = entries[kk] ; kk += stride-- ; } for ( ; ii < jrow + m ; ii++ ) { /* fprintf(stdout, "\n 2. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ rowvec[ii] = entries[kk] ; kk++ ; } } else { kk += (m*(m+1))/2 ; } jrow += m ; } } break ; default : break ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to fill rowZV with the entries in row irow of the matrix created -- 98may01, cca ----------------------------------------- */ void SubMtx_fillRowZV ( SubMtx *mtx, int irow, ZV *rowZV ) { double *rowvec ; /* --------------- check the input --------------- */ if ( mtx == NULL || irow < 0 || rowZV == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_fillRowZV(%p,%d,%p)" "\n bad input\n", mtx, irow, rowZV) ; exit(-1) ; } if ( ! SUBMTX_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_fillRowZV(%p,%d,%p)" "\n type = %d, must be SPOOLES_COMPLEX\n", mtx, irow, rowZV, mtx->type) ; exit(-1) ; } ZV_setSize(rowZV, mtx->ncol) ; rowvec = ZV_entries(rowZV) ; DVzero(2*mtx->ncol, rowvec) ; /* -------------------------------------- switch over the different matrix types -------------------------------------- */ switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { double *entries ; int inc1, inc2, jcol, loc, ncol, nrow ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { loc = irow*inc1 + jcol*inc2 ; rowvec[2*jcol] = entries[2*loc] ; rowvec[2*jcol+1] = entries[2*loc+1] ; } } break ; case SUBMTX_SPARSE_ROWS : { double *entries ; int ii, jrow, kk, nent, nrow, offset ; int *indices, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; for ( jrow = offset = 0 ; jrow < irow ; jrow++ ) { offset += sizes[jrow] ; } for ( ii = 0, kk = offset ; ii < sizes[irow] ; ii++, kk++ ) { rowvec[2*indices[kk]] = entries[2*kk] ; rowvec[2*indices[kk]+1] = entries[2*kk+1] ; } } break ; case SUBMTX_SPARSE_COLUMNS : { double *entries ; int ii, jcol, kk, nent, ncol, offset ; int *indices, *sizes ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; for ( jcol = offset = 0 ; jcol < ncol ; jcol++ ) { for ( ii = 0, kk = offset ; ii < sizes[jcol] ; ii++, kk++ ) { if ( indices[kk] == irow ) { rowvec[2*jcol] = entries[2*kk] ; rowvec[2*jcol+1] = entries[2*kk+1] ; break ; } } offset += sizes[jcol] ; } } break ; case SUBMTX_SPARSE_TRIPLES : { double *entries ; int ii, nent ; int *colids, *rowids ; SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; for ( ii = 0 ; ii < nent ; ii++ ) { if ( rowids[ii] == irow ) { rowvec[2*colids[ii]] = entries[2*ii] ; rowvec[2*colids[ii]+1] = entries[2*ii+1] ; } } } break ; case SUBMTX_DENSE_SUBROWS : { double *entries ; int first, ii, jrow, kk, last, nent, nrow, offset ; int *firstlocs, *sizes ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% entries(%d) :", nent) ; ZVfprintf(stdout, nent, entries) ; #endif for ( jrow = offset = 0 ; jrow < irow ; jrow++ ) { offset += sizes[jrow] ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% irow = %d, offset = %d", irow, offset) ; fprintf(stdout, "\n %% first = %d, size = %d", firstlocs[irow], sizes[irow]) ; #endif if ( sizes[irow] > 0 ) { first = firstlocs[irow] ; last = first + sizes[irow] - 1 ; for ( kk = first, ii = offset ; kk <= last ; kk++, ii++ ) { rowvec[2*kk] = entries[2*ii] ; rowvec[2*kk+1] = entries[2*ii+1] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% rowvec[%d] = entries[%d]", kk, ii) ; #endif } } } break ; case SUBMTX_DENSE_SUBCOLUMNS : { double *entries ; int first, jcol, last, loc, nent, ncol, offset ; int *firstlocs, *sizes ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; for ( jcol = offset = 0 ; jcol < ncol ; jcol++ ) { if ( sizes[jcol] > 0 ) { first = firstlocs[jcol] ; last = first + sizes[jcol] - 1 ; if ( first <= irow && irow <= last ) { loc = offset + irow - first ; rowvec[2*jcol] = entries[2*loc] ; rowvec[2*jcol+1] = entries[2*loc+1] ; } offset += sizes[jcol] ; } } } break ; case SUBMTX_DIAGONAL : { double *entries ; int nent ; SubMtx_diagonalInfo(mtx, &nent, &entries) ; rowvec[2*irow] = entries[2*irow] ; rowvec[2*irow+1] = entries[2*irow+1] ; } break ; case SUBMTX_BLOCK_DIAGONAL_SYM : { double *entries ; int ii, ipivot, jrow, kk, m, nrow, nent, stride ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; for ( jrow = ipivot = kk = 0 ; jrow <= irow ; ipivot++ ) { m = pivotsizes[ipivot] ; /* fprintf(stdout, "\n jrow %d, m %d, kk %d", jrow, m, kk) ; fflush(stdout) ; */ if ( jrow <= irow && irow < jrow + m ) { stride = m - 1 ; kk += irow - jrow ; /* fprintf(stdout, "\n 0. kk %d, stride %d", kk, stride) ; fflush(stdout) ; */ for ( ii = jrow ; ii <= irow ; ii++ ) { /* fprintf(stdout, "\n 1. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ rowvec[2*ii] = entries[2*kk] ; rowvec[2*ii+1] = entries[2*kk+1] ; kk += stride-- ; } for ( ; ii < jrow + m ; ii++ ) { /* fprintf(stdout, "\n 2. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ rowvec[2*ii] = entries[2*kk] ; rowvec[2*ii+1] = entries[2*kk+1] ; kk++ ; } } else { kk += (m*(m+1))/2 ; } jrow += m ; } } break ; case SUBMTX_BLOCK_DIAGONAL_HERM : { double *entries ; int ii, ipivot, jrow, kk, m, nrow, nent, stride ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; for ( jrow = ipivot = kk = 0 ; jrow <= irow ; ipivot++ ) { m = pivotsizes[ipivot] ; /* fprintf(stdout, "\n jrow %d, m %d, kk %d", jrow, m, kk) ; fflush(stdout) ; */ if ( jrow <= irow && irow < jrow + m ) { stride = m - 1 ; kk += irow - jrow ; /* fprintf(stdout, "\n 0. kk %d, stride %d", kk, stride) ; fflush(stdout) ; */ for ( ii = jrow ; ii < irow ; ii++ ) { /* fprintf(stdout, "\n 1. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ rowvec[2*ii] = entries[2*kk] ; rowvec[2*ii+1] = -entries[2*kk+1] ; kk += stride-- ; } for ( ; ii < jrow + m ; ii++ ) { /* fprintf(stdout, "\n 2. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ rowvec[2*ii] = entries[2*kk] ; rowvec[2*ii+1] = entries[2*kk+1] ; kk++ ; } } else { kk += (m*(m+1))/2 ; } jrow += m ; } } break ; default : break ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to fill colDV with the entries in column icol of the matrix created -- 98may01, cca ----------------------------------------- */ void SubMtx_fillColumnDV ( SubMtx *mtx, int icol, DV *colDV ) { double *colvec ; /* --------------- check the input --------------- */ if ( mtx == NULL || icol < 0 || colDV == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_fillColumnDV(%p,%d,%p)" "\n bad input\n", mtx, icol, colDV) ; exit(-1) ; } if ( ! SUBMTX_IS_REAL(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_fillColumnDV(%p,%d,%p)" "\n bad type %d, must be SPOOLES_REAL\n", mtx, icol, colDV, mtx->type) ; exit(-1) ; } DV_setSize(colDV, mtx->nrow) ; colvec = DV_entries(colDV) ; DVzero(mtx->nrow, colvec) ; /* -------------------------------------- switch over the different matrix types -------------------------------------- */ switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { double *entries ; int inc1, inc2, jrow, loc, ncol, nrow ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; for ( jrow = 0 ; jrow < nrow ; jrow++ ) { loc = jrow*inc1 + icol*inc2 ; colvec[jrow] = entries[loc] ; } } break ; case SUBMTX_SPARSE_COLUMNS : { double *entries ; int ii, jcol, kk, ncol, nent, offset ; int *indices, *sizes ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; for ( jcol = offset = 0 ; jcol < icol ; jcol++ ) { offset += sizes[jcol] ; } for ( ii = 0, kk = offset ; ii < sizes[icol] ; ii++, kk++ ) { colvec[indices[kk]] = entries[kk] ; } } break ; case SUBMTX_SPARSE_ROWS : { double *entries ; int ii, jrow, kk, nent, nrow, offset ; int *indices, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; for ( jrow = offset = 0 ; jrow < nrow ; jrow++ ) { for ( ii = 0, kk = offset ; ii < sizes[jrow] ; ii++, kk++ ) { if ( indices[kk] == icol ) { colvec[jrow] = entries[kk] ; break ; } } offset += sizes[jrow] ; } } break ; case SUBMTX_SPARSE_TRIPLES : { double *entries ; int ii, nent ; int *colids, *rowids ; SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; for ( ii = 0 ; ii < nent ; ii++ ) { if ( colids[ii] == icol ) { colvec[rowids[ii]] = entries[ii] ; } } } break ; case SUBMTX_DENSE_SUBCOLUMNS : { double *entries ; int first, ii, jcol, kk, last, ncol, nent, offset ; int *firstlocs, *sizes ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% entries(%d) :", nent) ; DVfprintf(stdout, nent, entries) ; #endif for ( jcol = offset = 0 ; jcol < icol ; jcol++ ) { offset += sizes[jcol] ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% icol = %d, offset = %d", icol, offset) ; fprintf(stdout, "\n %% first = %d, size = %d", firstlocs[icol], sizes[icol]) ; #endif if ( sizes[icol] > 0 ) { first = firstlocs[icol] ; last = first + sizes[icol] - 1 ; for ( kk = first, ii = offset ; kk <= last ; kk++, ii++ ) { colvec[kk] = entries[ii] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% colvec[%d] = entries[%d]", kk, ii) ; #endif } } } break ; case SUBMTX_DENSE_SUBROWS : { double *entries ; int first, jrow, last, loc, nent, nrow, offset ; int *firstlocs, *sizes ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; for ( jrow = offset = 0 ; jrow < nrow ; jrow++ ) { if ( sizes[jrow] > 0 ) { first = firstlocs[jrow] ; last = first + sizes[jrow] - 1 ; if ( first <= icol && icol <= last ) { loc = offset + icol - first ; colvec[jrow] = entries[loc] ; } offset += sizes[jrow] ; } } } break ; case SUBMTX_DIAGONAL : { double *entries ; int nent ; SubMtx_diagonalInfo(mtx, &nent, &entries) ; colvec[icol] = entries[icol] ; } break ; case SUBMTX_BLOCK_DIAGONAL_SYM : { double *entries ; int ii, ipivot, jcol, kk, m, nrow, nent, stride ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; for ( jcol = ipivot = kk = 0 ; jcol <= icol ; ipivot++ ) { m = pivotsizes[ipivot] ; /* fprintf(stdout, "\n jrow %d, m %d, kk %d", jrow, m, kk) ; fflush(stdout) ; */ if ( jcol <= icol && icol < jcol + m ) { stride = m - 1 ; kk += icol - jcol ; /* fprintf(stdout, "\n 0. kk %d, stride %d", kk, stride) ; fflush(stdout) ; */ for ( ii = jcol ; ii <= icol ; ii++ ) { /* fprintf(stdout, "\n 1. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ colvec[ii] = entries[kk] ; kk += stride-- ; } for ( ; ii < jcol + m ; ii++ ) { /* fprintf(stdout, "\n 2. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ colvec[ii] = entries[kk] ; kk++ ; } } else { kk += (m*(m+1))/2 ; } jcol += m ; } } break ; case SUBMTX_BLOCK_DIAGONAL_HERM : { double *entries ; int ii, ipivot, jcol, kk, m, nrow, nent, stride ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; for ( jcol = ipivot = kk = 0 ; jcol <= icol ; ipivot++ ) { m = pivotsizes[ipivot] ; /* fprintf(stdout, "\n jrow %d, m %d, kk %d", jrow, m, kk) ; fflush(stdout) ; */ if ( jcol <= icol && icol < jcol + m ) { stride = m - 1 ; kk += icol - jcol ; /* fprintf(stdout, "\n 0. kk %d, stride %d", kk, stride) ; fflush(stdout) ; */ for ( ii = jcol ; ii <= icol ; ii++ ) { /* fprintf(stdout, "\n 1. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ colvec[ii] = entries[kk] ; kk += stride-- ; } for ( ; ii < jcol + m ; ii++ ) { /* fprintf(stdout, "\n 2. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ colvec[ii] = entries[kk] ; kk++ ; } } else { kk += (m*(m+1))/2 ; } jcol += m ; } } break ; default : break ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to fill colZV with the entries in column icol of the matrix created -- 98may01, cca ----------------------------------------- */ void SubMtx_fillColumnZV ( SubMtx *mtx, int icol, ZV *colZV ) { double *colvec ; /* --------------- check the input --------------- */ if ( mtx == NULL || icol < 0 || colZV == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_fillColumnZV(%p,%d,%p)" "\n bad input\n", mtx, icol, colZV) ; exit(-1) ; } if ( ! SUBMTX_IS_COMPLEX(mtx) ) { fprintf(stderr, "\n fatal error in SubMtx_fillColumnZV(%p,%d,%p)" "\n bad type %d, must be SPOOLES_COMPLEX\n", mtx, icol, colZV, mtx->type) ; exit(-1) ; } ZV_setSize(colZV, mtx->nrow) ; colvec = ZV_entries(colZV) ; DVzero(2*mtx->nrow, colvec) ; /* -------------------------------------- switch over the different matrix types -------------------------------------- */ switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { double *entries ; int inc1, inc2, jrow, loc, ncol, nrow ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; for ( jrow = 0 ; jrow < nrow ; jrow++ ) { loc = jrow*inc1 + icol*inc2 ; colvec[2*jrow] = entries[2*loc] ; colvec[2*jrow+1] = entries[2*loc+1] ; } } break ; case SUBMTX_SPARSE_COLUMNS : { double *entries ; int ii, jcol, kk, ncol, nent, offset ; int *indices, *sizes ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; for ( jcol = offset = 0 ; jcol < icol ; jcol++ ) { offset += sizes[jcol] ; } for ( ii = 0, kk = offset ; ii < sizes[icol] ; ii++, kk++ ) { colvec[2*indices[kk]] = entries[2*kk] ; colvec[2*indices[kk]+1] = entries[2*kk+1] ; } } break ; case SUBMTX_SPARSE_ROWS : { double *entries ; int ii, jrow, kk, nent, nrow, offset ; int *indices, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; for ( jrow = offset = 0 ; jrow < nrow ; jrow++ ) { for ( ii = 0, kk = offset ; ii < sizes[jrow] ; ii++, kk++ ) { if ( indices[kk] == icol ) { colvec[2*jrow] = entries[2*kk] ; colvec[2*jrow+1] = entries[2*kk+1] ; break ; } } offset += sizes[jrow] ; } } break ; case SUBMTX_SPARSE_TRIPLES : { double *entries ; int ii, nent ; int *colids, *rowids ; SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; for ( ii = 0 ; ii < nent ; ii++ ) { if ( colids[ii] == icol ) { colvec[2*rowids[ii]] = entries[2*ii] ; colvec[2*rowids[ii]+1] = entries[2*ii+1] ; } } } break ; case SUBMTX_DENSE_SUBCOLUMNS : { double *entries ; int first, ii, jcol, kk, last, ncol, nent, offset ; int *firstlocs, *sizes ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; #if MYDEBUG > 0 fprintf(stdout, "\n %% entries(%d) :", nent) ; ZVfprintf(stdout, nent, entries) ; #endif for ( jcol = offset = 0 ; jcol < icol ; jcol++ ) { offset += sizes[jcol] ; } #if MYDEBUG > 0 fprintf(stdout, "\n %% icol = %d, offset = %d", icol, offset) ; fprintf(stdout, "\n %% first = %d, size = %d", firstlocs[icol], sizes[icol]) ; #endif if ( sizes[icol] > 0 ) { first = firstlocs[icol] ; last = first + sizes[icol] - 1 ; for ( kk = first, ii = offset ; kk <= last ; kk++, ii++ ) { colvec[2*kk] = entries[2*ii] ; colvec[2*kk+1] = entries[2*ii+1] ; #if MYDEBUG > 0 fprintf(stdout, "\n %% colvec[%d] = entries[%d]", kk, ii) ; #endif } } } break ; case SUBMTX_DENSE_SUBROWS : { double *entries ; int first, jrow, last, loc, nent, nrow, offset ; int *firstlocs, *sizes ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; for ( jrow = offset = 0 ; jrow < nrow ; jrow++ ) { if ( sizes[jrow] > 0 ) { first = firstlocs[jrow] ; last = first + sizes[jrow] - 1 ; if ( first <= icol && icol <= last ) { loc = offset + icol - first ; colvec[2*jrow] = entries[2*loc] ; colvec[2*jrow+1] = entries[2*loc+1] ; } offset += sizes[jrow] ; } } } break ; case SUBMTX_DIAGONAL : { double *entries ; int nent ; SubMtx_diagonalInfo(mtx, &nent, &entries) ; colvec[2*icol] = entries[2*icol] ; colvec[2*icol+1] = entries[2*icol+1] ; } break ; case SUBMTX_BLOCK_DIAGONAL_SYM : { double *entries ; int ii, ipivot, jcol, kk, m, nrow, nent, stride ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; for ( jcol = ipivot = kk = 0 ; jcol <= icol ; ipivot++ ) { m = pivotsizes[ipivot] ; /* fprintf(stdout, "\n jrow %d, m %d, kk %d", jrow, m, kk) ; fflush(stdout) ; */ if ( jcol <= icol && icol < jcol + m ) { stride = m - 1 ; kk += icol - jcol ; /* fprintf(stdout, "\n 0. kk %d, stride %d", kk, stride) ; fflush(stdout) ; */ for ( ii = jcol ; ii <= icol ; ii++ ) { /* fprintf(stdout, "\n 1. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ colvec[2*ii] = entries[2*kk] ; colvec[2*ii+1] = entries[2*kk+1] ; kk += stride-- ; } for ( ; ii < jcol + m ; ii++ ) { /* fprintf(stdout, "\n 2. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ colvec[2*ii] = entries[2*kk] ; colvec[2*ii+1] = entries[2*kk+1] ; kk++ ; } } else { kk += (m*(m+1))/2 ; } jcol += m ; } } break ; case SUBMTX_BLOCK_DIAGONAL_HERM : { double *entries ; int ii, ipivot, jcol, kk, m, nrow, nent, stride ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; for ( jcol = ipivot = kk = 0 ; jcol <= icol ; ipivot++ ) { m = pivotsizes[ipivot] ; /* fprintf(stdout, "\n jrow %d, m %d, kk %d", jrow, m, kk) ; fflush(stdout) ; */ if ( jcol <= icol && icol < jcol + m ) { stride = m - 1 ; kk += icol - jcol ; /* fprintf(stdout, "\n 0. kk %d, stride %d", kk, stride) ; fflush(stdout) ; */ for ( ii = jcol ; ii <= icol ; ii++ ) { /* fprintf(stdout, "\n 1. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ colvec[2*ii] = entries[2*kk] ; colvec[2*ii+1] = entries[2*kk+1] ; kk += stride-- ; } for ( ; ii < jcol + m ; ii++ ) { /* fprintf(stdout, "\n 2. ii %d, kk %d", ii, kk) ; fflush(stdout) ; */ colvec[2*ii] = entries[2*kk] ; colvec[2*ii+1] = -entries[2*kk+1] ; kk++ ; } } else { kk += (m*(m+1))/2 ; } jcol += m ; } } break ; default : break ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- return the magnitude of the largest element created -- 98may01, cca ------------------------------------------------------ */ double SubMtx_maxabs ( SubMtx *mtx ) { double maxabs ; double *entries ; int loc, nent ; /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_maxabs(%p)" "\n bad input\n", mtx) ; exit(-1) ; } if ( ! (SUBMTX_IS_REAL(mtx) || SUBMTX_IS_COMPLEX(mtx)) ) { fprintf(stderr, "\n fatal error in SubMtx_maxabs(%p)" "\n bad type %d, must be SPOOLES_REAL or SPOOLES_COMPLEX\n", mtx, mtx->type) ; exit(-1) ; } /* -------------------------------------- switch over the different matrix types -------------------------------------- */ switch ( mtx->mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : { int inc1, inc2, ncol, nrow ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &entries) ; nent = nrow*ncol ; } break ; case SUBMTX_SPARSE_COLUMNS : { int ncol ; int *indices, *sizes ; SubMtx_sparseColumnsInfo(mtx, &ncol, &nent, &sizes, &indices, &entries) ; } break ; case SUBMTX_SPARSE_ROWS : { int nrow ; int *indices, *sizes ; SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; } break ; case SUBMTX_SPARSE_TRIPLES : { int *colids, *rowids ; SubMtx_sparseTriplesInfo(mtx, &nent, &rowids, &colids, &entries) ; } break ; case SUBMTX_DENSE_SUBCOLUMNS : { int ncol ; int *firstlocs, *sizes ; SubMtx_denseSubcolumnsInfo(mtx, &ncol, &nent, &firstlocs, &sizes, &entries) ; } break ; case SUBMTX_DENSE_SUBROWS : { int nrow ; int *firstlocs, *sizes ; SubMtx_denseSubrowsInfo(mtx, &nrow, &nent, &firstlocs, &sizes, &entries) ; } break ; case SUBMTX_DIAGONAL : { SubMtx_diagonalInfo(mtx, &nent, &entries) ; } break ; case SUBMTX_BLOCK_DIAGONAL_SYM : { int nrow ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; } break ; case SUBMTX_BLOCK_DIAGONAL_HERM : { int nrow ; int *pivotsizes ; SubMtx_blockDiagonalInfo(mtx, &nrow, &nent, &pivotsizes, &entries) ; } break ; default : break ; } if ( SUBMTX_IS_REAL(mtx) ) { maxabs = DVmaxabs(nent, entries, &loc) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { maxabs = ZVmaxabs(nent, entries) ; } return(maxabs) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- zero the entries in the matrix created -- 98may04, cca ----------------------------------------- */ void SubMtx_zero ( SubMtx *mtx ) { /* --------------- check the input --------------- */ if ( mtx == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_zero(%p)" "\n bad input\n", mtx) ; exit(-1) ; } if ( SUBMTX_IS_REAL(mtx) ) { DVzero(mtx->nent, mtx->entries) ; } else if ( SUBMTX_IS_COMPLEX(mtx) ) { DVzero(2*mtx->nent, mtx->entries) ; } return ; } /*--------------------------------------------------------------------*/ bMtx *mtx, int icol, ZV *colZV ) { double *colvec ; /* --------------- check the input --------------- */ if ( mtx == NULL || icol < 0 || colZV == NULL ) { fprintf(stderr, "\n fatal error in SubMtx_fillColumnZV(%p,%d,%p)" "\n bad input\n", mtx, icol, colZV) ; exit(-1) ; } if ( ! SUBMTX_IS_COMPLEX(mtx) ) { fprSubMtx/drivers/do_scalevec010075500020550007177000000004560653410625600172020ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = res set msgFile = stdout # type = 1 (real) or 2 (complex) set type = 2 # mode = 7, 8 or 9 (complex only) set mode = 9 set nrow = 10 set seed = 76661 test_scalevec \ $msglvl $msgFile $type $mode $nrow $seed SubMtx/drivers/do_solve010075500020550007177000000005640653410625500165440ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 5 set msgFile = res set msgFile = stdout # type = 1 (real), 2 (complex) set type = 2 # mode = 2, 3, 5, 6, 7, 8, 9 (complex only) set mode = 9 set nrowA = 15 set nentA = 100 set ncolB = 8 set seed = 376666 test_solve \ $msglvl $msgFile $type $mode $nrowA $nentA $ncolB $seed exit SubMtx/drivers/do_solveH010075500020550007177000000005230653410625600166500ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = res set msgFile = stdout # type = 2 (complex) set type = 2 # mode = 2, 3, 5, 6 set mode = 6 set nrowA = 15 set nentA = 100 set ncolB = 6 set seed = 376666 test_solveH \ $msglvl $msgFile $type $mode $nrowA $nentA $ncolB $seed exit SubMtx/drivers/do_solveT010075500020550007177000000005370653410625600166710ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 2 set msgFile = res set msgFile = stdout # type = 1 (real) or (2) complex set type = 1 # mode = 2, 3, 5, 6 set mode = 6 set nrowA = 15 set nentA = 100 set ncolB = 8 set seed = 376666 test_solveT \ $msglvl $msgFile $type $mode $nrowA $nentA $ncolB $seed exit SubMtx/drivers/do_solveupd010075500020550007177000000046730653410625500172620ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 1 set msgFile = res set msgFile = stdout set type = 1 set mode = 1 set nrowY = 25 set ncolY = 11 set nrowA = $nrowY set nrowA = 23 set ncolA = 13 set nentA = 9 set nrowX = $ncolA set nrowX = 15 set seed = 666666 # set m = 17 # set n = 13 # set c = 10 # @ a = $m - 0 # @ b = $c - 0 # set nrowY = $m # set ncolY = $n # set nrowA = $a # set ncolA = $b # set nrowX = $c foreach type ( 1 2 ) # # loop over the cases # foreach mode ( 0 1 2 3 ) # # first subcase: # rows Y = # rows A and # cols A = # rows X # set nrowY = 25 ; set ncolY = 15 set nrowA = 25 ; set ncolA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) set nrowA = $nrowY foreach ncolA ( 10 11 12 ) set nrowX = $ncolA @ nentA = $nrowA * $ncolA - 1 test_solveupd \ $msglvl $msgFile $type $mode \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end # # second subcase: # rows Y = # rows A and # cols A != # rows X # set nrowY = 25 ; set ncolY = 15 set nrowA = 25 ; set ncolA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) set nrowA = $nrowY foreach ncolA ( 10 11 12 ) set nrowX = 15 @ nentA = $nrowA * $ncolA - 1 test_solveupd \ $msglvl $msgFile $type $mode \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end # # first subcase: # rows Y != # rows A and # cols A = # rows X # set nrowY = 25 ; set ncolY = 15 set nrowA = 25 ; set ncolA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) foreach nrowA ( 10 11 12 ) foreach ncolA ( 10 11 12 ) set nrowX = $ncolA @ nentA = $nrowA * $ncolA - 1 test_solveupd \ $msglvl $msgFile $type $mode \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end end # # second subcase: # rows Y != # rows A and # cols A != # rows X # set nrowY = 25 ; set ncolY = 15 set nrowA = 25 ; set ncolA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) foreach nrowA ( 10 11 12 ) foreach ncolA ( 10 11 12 ) set nrowX = 15 @ nentA = $nrowA * $ncolA - 1 test_solveupd \ $msglvl $msgFile $type $mode \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end end end end SubMtx/drivers/do_solveupdH010075500020550007177000000045550653410625600173720ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 1 set msgFile = res set msgFile = stdout set type = 0 set nrowY = 25 set ncolY = 1 set nrowA = $nrowY set nrowA = 10 set ncolA = 10 set nentA = 9 set nrowX = $ncolA set nrowX = 11 set seed = 666666 # @ nentA = $nrowA * $ncolA - 1 # test_solveupdH \ # $msglvl $msgFile $type \ # $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed # # exit # loop over the cases # foreach type ( 1 2 3 0 ) # # first subcase: # rows Y = # cols A and # rows A = # rows X # set nrowY = 25 ; set ncolY = 15 set ncolA = 25 ; set nrowA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) set ncolA = $nrowY foreach nrowA ( 10 11 12 ) set nrowX = $nrowA @ nentA = $nrowA * $ncolA - 1 test_solveupdH \ $msglvl $msgFile $type \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end # # second subcase: # rows Y = # cols A and # rows A != # rows X # set nrowY = 25 ; set ncolY = 15 set ncolA = 25 ; set nrowA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) set ncolA = $nrowY foreach nrowA ( 10 11 12 ) set nrowX = 15 @ nentA = $nrowA * $ncolA - 1 test_solveupdH \ $msglvl $msgFile $type \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end # # third subcase: # rows Y != # cols A and # nrows A = # rows X # set nrowY = 25 ; set ncolY = 15 set ncolA = 25 ; set nrowA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) foreach ncolA ( 10 11 12 ) foreach nrowA ( 10 11 12 ) set nrowX = $nrowA @ nentA = $nrowA * $ncolA - 1 test_solveupdH \ $msglvl $msgFile $type \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end end # # fourth subcase: # rows Y != # cols A and # rows A != # rows X # set nrowY = 25 ; set ncolY = 15 set ncolA = 25 ; set nrowA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) foreach ncolA ( 10 11 12 ) foreach nrowA ( 10 11 12 ) set nrowX = 15 @ nentA = $nrowA * $ncolA - 1 test_solveupdH \ $msglvl $msgFile $type \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end end end SubMtx/drivers/do_solveupdT010075500020550007177000000046720653410625500174050ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 1 set msgFile = res set msgFile = stdout set type = 1 set mode = 0 set nrowY = 25 set ncolY = 10 set nrowA = $nrowY set nrowA = 11 set ncolA = 10 set nentA = 9 set nrowX = $ncolA set nrowX = 11 set seed = 666666 # @ nentA = $nrowA * $ncolA - 1 # test_solveupdT \ # $msglvl $msgFile $type $mode \ # $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed # # exit # loop over the cases # foreach type ( 1 2 ) foreach mode ( 0 1 2 3 ) # # first subcase: # rows Y = # cols A and # rows A = # rows X # set nrowY = 25 ; set ncolY = 15 set ncolA = 25 ; set nrowA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) set ncolA = $nrowY foreach nrowA ( 10 11 12 ) set nrowX = $nrowA @ nentA = $nrowA * $ncolA - 1 test_solveupdT \ $msglvl $msgFile $type $mode \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end # # second subcase: # rows Y = # cols A and # rows A != # rows X # set nrowY = 25 ; set ncolY = 15 set ncolA = 25 ; set nrowA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) set ncolA = $nrowY foreach nrowA ( 10 11 12 ) set nrowX = 15 @ nentA = $nrowA * $ncolA - 1 test_solveupdT \ $msglvl $msgFile $type $mode \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end # # third subcase: # rows Y != # cols A and # nrows A = # rows X # set nrowY = 25 ; set ncolY = 15 set ncolA = 25 ; set nrowA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) foreach ncolA ( 10 11 12 ) foreach nrowA ( 10 11 12 ) set nrowX = $nrowA @ nentA = $nrowA * $ncolA - 1 test_solveupdT \ $msglvl $msgFile $type $mode \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end end # # fourth subcase: # rows Y != # cols A and # rows A != # rows X # set nrowY = 25 ; set ncolY = 15 set ncolA = 25 ; set nrowA = 10 set nrowX = 10 ; foreach ncolY ( 10 11 12 ) foreach ncolA ( 10 11 12 ) foreach nrowA ( 10 11 12 ) set nrowX = 15 @ nentA = $nrowA * $ncolA - 1 test_solveupdT \ $msglvl $msgFile $type $mode \ $nrowY $ncolY $nrowA $ncolA $nentA $nrowX $seed end end end end end SubMtx/drivers/do_sort010075500020550007177000000005370654517120000163750ustar00clevecompmath00000400000006#! /bin/csh -f # set msglvl = 5 set msgFile = res set msgFile = stdout # type = 1 (real), 2 (complex set type = 2 # mode = 0, 1, 2, 3 set mode = 1 set nrowA = 8 set ncolA = 3 set nentA = 10 set seed = 666666 test_sort \ $msglvl $msgFile $type $mode \ $nrowA $ncolA $nentA $seed exit SubMtx/drivers/do_testIO010075500020550007177000000004710654517042600166230ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 3 set msgFile = res.serial set msgFile = stdout set inFile = B.submtxf set outFile = temp.submtxb set outFile = B.res set outFile = B2.submtxf set matlabFile = sol.m set matlabFile = none testIO $msglvl $msgFile $inFile $outFile $matlabFile SubMtx/drivers/makefile010064400020550007177000000025000665314265300165000ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testIO \ test_scalevec \ test_solve \ test_solveH \ test_solveT \ test_solveupd \ test_solveupdH \ test_solveupdT \ test_sort drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testIO : testIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} test_scalevec : test_scalevec.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} test_solve : test_solve.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} test_solveH : test_solveH.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} test_solveT : test_solveT.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} test_solveupd : test_solveupd.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} test_solveupdH : test_solveupdH.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} test_solveupdT : test_solveupdT.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} test_sort : test_sort.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} SubMtx/drivers/testIO.c010064400020550007177000000114250654223353700163600ustar00clevecompmath00000400000006/* testIO.c */ #include "../SubMtx.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------ test SubMtx_readFromFile and SubMtx_writeToFile, useful for translating between formatted *.submtxf and binary *.submtxb files. created -- 98may04, cca ------------------------------------------------------ */ { char *inSubMtxFileName, *matlabFileName, *outSubMtxFileName ; double t1, t2 ; int msglvl, rc ; SubMtx *mtx ; FILE *fp, *msgFile ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile matlabFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.dmtxf or *.dmtxb" "\n outFile -- output file, must be *.dmtxf or *.dmtxb" "\n matlabFile -- output file, must be *.m" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inSubMtxFileName = argv[3] ; outSubMtxFileName = argv[4] ; matlabFileName = argv[5] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n matlabFile -- %s" "\n", argv[0], msglvl, argv[2], inSubMtxFileName, outSubMtxFileName, matlabFileName) ; fflush(msgFile) ; /* ---------------------------- read in the SubMtx object ---------------------------- */ if ( strcmp(inSubMtxFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } mtx = SubMtx_new() ; MARKTIME(t1) ; rc = SubMtx_readFromFile(mtx, inSubMtxFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in dmtx from file %s", t2 - t1, inSubMtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from SubMtx_readFromFile(%p,%s)", rc, mtx, inSubMtxFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading SubMtx object from file %s", inSubMtxFileName) ; fflush(msgFile) ; if ( msglvl > 2 ) { SubMtx_writeForHumanEye(mtx, msgFile) ; } else { SubMtx_writeStats(mtx, msgFile) ; } fflush(msgFile) ; /* ---------------------------------------------- hack to convert from row major to column major ---------------------------------------------- */ /* { SubMtx *mtx2 ; double *ent1, *ent2, *pXij, *pYij ; int *colind, *colind2, *rowind, *rowind2 ; int inc1, inc2, irow, jcol, ncol, nrow ; mtx2 = SubMtx_new() ; SubMtx_init(mtx2, DMTX_DENSE_COLUMNS, 0, 0, mtx->nrow, mtx->ncol, mtx->nent) ; SubMtx_denseInfo(mtx, &nrow, &ncol, &inc1, &inc2, &ent1) ; SubMtx_denseInfo(mtx2, &nrow, &ncol, &inc1, &inc2, &ent2) ; SubMtx_rowIndices(mtx, &nrow, &rowind) ; SubMtx_rowIndices(mtx2, &nrow, &rowind2) ; IVcopy(nrow, rowind2, rowind) ; SubMtx_columnIndices(mtx, &ncol, &colind) ; SubMtx_columnIndices(mtx2, &ncol, &colind2) ; IVcopy(ncol, colind2, colind) ; for ( jcol = 0 ; jcol < ncol ; jcol++ ) { for ( irow = 0 ; irow < nrow ; irow++ ) { pXij = SubMtx_locationOfEntry(mtx, irow, jcol) ; pYij = SubMtx_locationOfEntry(mtx2, irow, jcol) ; *pYij = *pXij ; } } SubMtx_free(mtx) ; mtx = mtx2 ; } */ /* ---------------------------- write out the SubMtx object ---------------------------- */ if ( strcmp(outSubMtxFileName, "none") != 0 ) { MARKTIME(t1) ; rc = SubMtx_writeToFile(mtx, outSubMtxFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write mtx to file %s", t2 - t1, outSubMtxFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from SubMtx_writeToFile(%p,%s)", rc, mtx, outSubMtxFileName) ; } /* ---------------------------------------------- write out the SubMtx object to a matlab file ---------------------------------------------- */ if ( strcmp(matlabFileName, "none") != 0 ) { if ( (fp = fopen(matlabFileName, "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], matlabFileName) ; return(-1) ; } MARKTIME(t1) ; SubMtx_writeForMatlab(mtx, "rhs", fp) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write mtx to file %s", t2 - t1, matlabFileName) ; } /* ------------------------- free the SubMtx object ------------------------- */ SubMtx_free(mtx) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ SubMtx/drivers/test_scalevec.c010064400020550007177000000210450654223355500177740ustar00clevecompmath00000400000006/* test_scalevec.c */ #include "../SubMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------ test the SubMtx_scale{1,2,3}vec() methods. created -- 98may02, cca ------------------------------------------ */ { SubMtx *mtxA ; double t1, t2 ; double *x0, *x1, *x2, *y0, *y1, *y2 ; Drand *drand ; DV *xdv0, *xdv1, *xdv2, *ydv0, *ydv1, *ydv2 ; ZV *xzv0, *xzv1, *xzv2, *yzv0, *yzv1, *yzv2 ; FILE *msgFile ; int mode, msglvl, nrowA, seed, type ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type nrowA seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of matrix A" "\n 1 -- real" "\n 2 -- complex" "\n mode -- mode of matrix A" "\n 7 -- diagonal" "\n 8 -- block diagonal symmetric" "\n 9 -- block diagonal hermitian (complex only)" "\n nrowA -- # of rows in matrix A" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; mode = atoi(argv[4]) ; nrowA = atoi(argv[5]) ; seed = atoi(argv[6]) ; fprintf(msgFile, "\n %% %s:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% mode = %d" "\n %% nrowA = %d" "\n %% seed = %d", argv[0], msglvl, argv[2], type, mode, nrowA, seed) ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nrowA <= 0 ) { fprintf(stderr, "\n invalid input\n") ; exit(-1) ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ---------------------------- initialize the X ZV objects ---------------------------- */ MARKTIME(t1) ; if ( type == SPOOLES_REAL ) { xdv0 = DV_new() ; DV_init(xdv0, nrowA, NULL) ; x0 = DV_entries(xdv0) ; Drand_fillDvector(drand, nrowA, x0) ; xdv1 = DV_new() ; DV_init(xdv1, nrowA, NULL) ; x1 = DV_entries(xdv1) ; Drand_fillDvector(drand, nrowA, x1) ; xdv2 = DV_new() ; DV_init(xdv2, nrowA, NULL) ; x2 = DV_entries(xdv2) ; Drand_fillDvector(drand, nrowA, x2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize X ZV objects", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% X DV objects") ; fprintf(msgFile, "\n X0 = zeros(%d,1) ;", nrowA) ; DV_writeForMatlab(xdv0, "X0", msgFile) ; fprintf(msgFile, "\n X1 = zeros(%d,1) ;", nrowA) ; DV_writeForMatlab(xdv1, "X1", msgFile) ; fprintf(msgFile, "\n X2 = zeros(%d,1) ;", nrowA) ; DV_writeForMatlab(xdv2, "X2", msgFile) ; fflush(msgFile) ; } } else if ( type == SPOOLES_COMPLEX ) { xzv0 = ZV_new() ; ZV_init(xzv0, nrowA, NULL) ; x0 = ZV_entries(xzv0) ; Drand_fillDvector(drand, 2*nrowA, x0) ; xzv1 = ZV_new() ; ZV_init(xzv1, nrowA, NULL) ; x1 = ZV_entries(xzv1) ; Drand_fillDvector(drand, 2*nrowA, x1) ; xzv2 = ZV_new() ; ZV_init(xzv2, nrowA, NULL) ; x2 = ZV_entries(xzv2) ; Drand_fillDvector(drand, 2*nrowA, x2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize X ZV objects", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% X ZV objects") ; fprintf(msgFile, "\n X0 = zeros(%d,1) ;", nrowA) ; ZV_writeForMatlab(xzv0, "X0", msgFile) ; fprintf(msgFile, "\n X1 = zeros(%d,1) ;", nrowA) ; ZV_writeForMatlab(xzv1, "X1", msgFile) ; fprintf(msgFile, "\n X2 = zeros(%d,1) ;", nrowA) ; ZV_writeForMatlab(xzv2, "X2", msgFile) ; fflush(msgFile) ; } } /* --------------------------------- initialize the Y DV or ZV objects --------------------------------- */ MARKTIME(t1) ; if ( type == SPOOLES_REAL ) { ydv0 = DV_new() ; DV_init(ydv0, nrowA, NULL) ; y0 = DV_entries(ydv0) ; ydv1 = DV_new() ; DV_init(ydv1, nrowA, NULL) ; y1 = DV_entries(ydv1) ; ydv2 = DV_new() ; DV_init(ydv2, nrowA, NULL) ; y2 = DV_entries(ydv2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize Y DV objects", t2 - t1) ; } else if ( type == SPOOLES_COMPLEX ) { yzv0 = ZV_new() ; ZV_init(yzv0, nrowA, NULL) ; y0 = ZV_entries(yzv0) ; yzv1 = ZV_new() ; ZV_init(yzv1, nrowA, NULL) ; y1 = ZV_entries(yzv1) ; yzv2 = ZV_new() ; ZV_init(yzv2, nrowA, NULL) ; y2 = ZV_entries(yzv2) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize Y ZV objects", t2 - t1) ; } /* ----------------------------------- initialize the A matrix SubMtx object ----------------------------------- */ seed++ ; mtxA = SubMtx_new() ; switch ( mode ) { case SUBMTX_DIAGONAL : case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : SubMtx_initRandom(mtxA, type, mode, 0, 0, nrowA, nrowA, 0, seed) ; break ; default : fprintf(stderr, "\n fatal error in test_solve" "\n invalid mode = %d", mode) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% A SubMtx object") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowA, nrowA) ; SubMtx_writeForMatlab(mtxA, "A", msgFile) ; fflush(msgFile) ; } /* ------------------- compute Y0 = A * X0 ------------------- */ if ( type == SPOOLES_REAL ) { DVzero(nrowA, y0) ; } else if ( type == SPOOLES_COMPLEX ) { DVzero(2*nrowA, y0) ; } SubMtx_scale1vec(mtxA, y0, x0) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n Z0 = zeros(%d,1) ;", nrowA) ; if ( type == SPOOLES_REAL ) { DV_writeForMatlab(ydv0, "Z0", msgFile) ; } else if ( type == SPOOLES_COMPLEX ) { ZV_writeForMatlab(yzv0, "Z0", msgFile) ; } fprintf(msgFile, "\n err0 = Z0 - A*X0 ;") ; fprintf(msgFile, "\n error0 = max(abs(err0))") ; fflush(msgFile) ; } if ( type == SPOOLES_REAL ) { DVzero(nrowA, y0) ; DVzero(nrowA, y1) ; } else if ( type == SPOOLES_COMPLEX ) { DVzero(2*nrowA, y0) ; DVzero(2*nrowA, y1) ; } SubMtx_scale2vec(mtxA, y0, y1, x0, x1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n Z0 = zeros(%d,1) ;", nrowA) ; fprintf(msgFile, "\n\n Z1 = zeros(%d,1) ;", nrowA) ; if ( type == SPOOLES_REAL ) { DV_writeForMatlab(ydv0, "Z0", msgFile) ; DV_writeForMatlab(ydv1, "Z1", msgFile) ; } else if ( type == SPOOLES_COMPLEX ) { ZV_writeForMatlab(yzv0, "Z0", msgFile) ; ZV_writeForMatlab(yzv1, "Z1", msgFile) ; } fprintf(msgFile, "\n err1 = [Z0 Z1] - A*[X0 X1] ;") ; fprintf(msgFile, "\n error1 = max(abs(err1))") ; fflush(msgFile) ; } if ( type == SPOOLES_REAL ) { DVzero(nrowA, y0) ; DVzero(nrowA, y1) ; DVzero(nrowA, y2) ; } else if ( type == SPOOLES_COMPLEX ) { DVzero(2*nrowA, y0) ; DVzero(2*nrowA, y1) ; DVzero(2*nrowA, y2) ; } SubMtx_scale3vec(mtxA, y0, y1, y2, x0, x1, x2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n Z0 = zeros(%d,1) ;", nrowA) ; fprintf(msgFile, "\n\n Z1 = zeros(%d,1) ;", nrowA) ; fprintf(msgFile, "\n\n Z2 = zeros(%d,1) ;", nrowA) ; if ( type == SPOOLES_REAL ) { DV_writeForMatlab(ydv0, "Z0", msgFile) ; DV_writeForMatlab(ydv1, "Z1", msgFile) ; DV_writeForMatlab(ydv2, "Z2", msgFile) ; } else if ( type == SPOOLES_COMPLEX ) { ZV_writeForMatlab(yzv0, "Z0", msgFile) ; ZV_writeForMatlab(yzv1, "Z1", msgFile) ; ZV_writeForMatlab(yzv2, "Z2", msgFile) ; } fprintf(msgFile, "\n err2 = [Z0 Z1 Z2] - A*[X0 X1 X2] ;") ; fprintf(msgFile, "\n error3 = max(abs(err2))") ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ SubMtx_free(mtxA) ; if ( type == SPOOLES_REAL ) { DV_free(xdv0) ; DV_free(xdv1) ; DV_free(xdv2) ; DV_free(ydv0) ; DV_free(ydv1) ; DV_free(ydv2) ; } else if ( type == SPOOLES_COMPLEX ) { ZV_free(xzv0) ; ZV_free(xzv1) ; ZV_free(xzv2) ; ZV_free(yzv0) ; ZV_free(yzv1) ; ZV_free(yzv2) ; } Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ SubMtx/drivers/test_solve.c010064400020550007177000000257630654223357400173530ustar00clevecompmath00000400000006/* test_solve.c */ #include "../SubMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------- test the SubMtx_solve() method. created -- 98apr15, cca ----------------------------- */ { SubMtx *mtxA, *mtxB, *mtxX ; double idot, rdot, t1, t2 ; double *entB, *entX ; Drand *drand ; FILE *msgFile ; int inc1, inc2, mode, msglvl, ncolA, nentA, nrowA, ncolB, nrowB, ncolX, nrowX, seed, type ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type mode nrowA nentA ncolB seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of matrix A" "\n 1 -- real" "\n 2 -- complex" "\n mode -- mode of matrix A" "\n 2 -- sparse stored by rows" "\n 3 -- sparse stored by columns" "\n 5 -- sparse stored by subrows" "\n 6 -- sparse stored by subcolumns" "\n 7 -- diagonal" "\n 8 -- block diagonal symmetric" "\n 9 -- block diagonal hermitian" "\n nrowA -- # of rows in matrix A" "\n nentA -- # of entries in matrix A" "\n ncolB -- # of columns in matrix B" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; mode = atoi(argv[4]) ; nrowA = atoi(argv[5]) ; nentA = atoi(argv[6]) ; ncolB = atoi(argv[7]) ; seed = atoi(argv[8]) ; fprintf(msgFile, "\n %% %s:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% mode = %d" "\n %% nrowA = %d" "\n %% nentA = %d" "\n %% ncolB = %d" "\n %% seed = %d", argv[0], msglvl, argv[2], type, mode, nrowA, nentA, ncolB, seed) ; ncolA = nrowA ; nrowB = nrowA ; nrowX = nrowA ; ncolX = ncolB ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nrowA <= 0 || nentA <= 0 || ncolB <= 0 ) { fprintf(stderr, "\n invalid input\n") ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : case SUBMTX_DIAGONAL : case SUBMTX_BLOCK_DIAGONAL_SYM : break ; default : fprintf(stderr, "\n invalid mode %d\n", mode) ; exit(-1) ; } break ; case SPOOLES_COMPLEX : switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : case SUBMTX_DIAGONAL : case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : break ; default : fprintf(stderr, "\n invalid mode %d\n", mode) ; exit(-1) ; } break ; default : fprintf(stderr, "\n invalid type %d\n", type) ; exit(-1) ; break ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ------------------------------ initialize the X SubMtx object ------------------------------ */ MARKTIME(t1) ; mtxX = SubMtx_new() ; SubMtx_initRandom(mtxX, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowX, ncolX, nrowX*ncolX, ++seed) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize X SubMtx object", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% X SubMtx object") ; fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, ncolX) ; SubMtx_writeForMatlab(mtxX, "X", msgFile) ; fflush(msgFile) ; } /* ------------------------------ initialize the B SubMtx object ------------------------------ */ MARKTIME(t1) ; mtxB = SubMtx_new() ; SubMtx_init(mtxB, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowB, ncolB, nrowB*ncolB) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entB) ; switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : if ( SUBMTX_IS_REAL(mtxX) ) { DVcopy(nrowB*ncolB, entB, entX) ; } else if ( SUBMTX_IS_COMPLEX(mtxX) ) { ZVcopy(nrowB*ncolB, entB, entX) ; } break ; default : if ( SUBMTX_IS_REAL(mtxX) ) { DVzero(nrowB*ncolB, entB) ; } else if ( SUBMTX_IS_COMPLEX(mtxX) ) { DVzero(2*nrowB*ncolB, entB) ; } break ; } MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize B SubMtx object", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% B SubMtx object") ; fprintf(msgFile, "\n B = zeros(%d,%d) ;", nrowB, ncolB) ; SubMtx_writeForMatlab(mtxB, "B", msgFile) ; fflush(msgFile) ; } /* ------------------------------------- initialize the A matrix SubMtx object ------------------------------------- */ seed++ ; mtxA = SubMtx_new() ; switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : SubMtx_initRandomLowerTriangle(mtxA, type, mode, 0, 0, nrowA, ncolA, nentA, seed, 1) ; break ; case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : SubMtx_initRandomUpperTriangle(mtxA, type, mode, 0, 0, nrowA, ncolA, nentA, seed, 1) ; break ; case SUBMTX_DIAGONAL : case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : SubMtx_initRandom(mtxA, type, mode, 0, 0, nrowA, ncolA, nentA, seed) ; break ; default : fprintf(stderr, "\n fatal error in test_solve" "\n invalid mode = %d", mode) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% A SubMtx object") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowA, ncolA) ; SubMtx_writeForMatlab(mtxA, "A", msgFile) ; fflush(msgFile) ; } /* -------------------------------------------------------- compute B = A * X (for diagonal and block diagonal) or B = (I + A) * X (for lower and upper triangular) -------------------------------------------------------- */ if ( SUBMTX_IS_REAL(mtxA) ) { DV *colDV, *rowDV ; double value, *colX, *rowA, *pBij, *pXij ; int irowA, jcolX ; colDV = DV_new() ; DV_init(colDV, nrowA, NULL) ; colX = DV_entries(colDV) ; rowDV = DV_new() ; DV_init(rowDV, nrowA, NULL) ; rowA = DV_entries(rowDV) ; for ( jcolX = 0 ; jcolX < ncolB ; jcolX++ ) { SubMtx_fillColumnDV(mtxX, jcolX, colDV) ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { SubMtx_fillRowDV(mtxA, irowA, rowDV) ; SubMtx_locationOfRealEntry(mtxX, irowA, jcolX, &pXij) ; SubMtx_locationOfRealEntry(mtxB, irowA, jcolX, &pBij) ; value = DVdot(nrowA, rowA, colX) ; switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : *pBij = *pXij + value ; break ; case SUBMTX_DIAGONAL : case SUBMTX_BLOCK_DIAGONAL_SYM : *pBij = value ; break ; } } } DV_free(colDV) ; DV_free(rowDV) ; } else if ( SUBMTX_IS_COMPLEX(mtxA) ) { ZV *colZV, *rowZV ; double *colX, *rowA, *pBIij, *pBRij, *pXIij, *pXRij ; int irowA, jcolX ; colZV = ZV_new() ; ZV_init(colZV, nrowA, NULL) ; colX = ZV_entries(colZV) ; rowZV = ZV_new() ; ZV_init(rowZV, nrowA, NULL) ; rowA = ZV_entries(rowZV) ; for ( jcolX = 0 ; jcolX < ncolB ; jcolX++ ) { SubMtx_fillColumnZV(mtxX, jcolX, colZV) ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { SubMtx_fillRowZV(mtxA, irowA, rowZV) ; SubMtx_locationOfComplexEntry(mtxX, irowA, jcolX, &pXRij, &pXIij) ; SubMtx_locationOfComplexEntry(mtxB, irowA, jcolX, &pBRij, &pBIij) ; ZVdotU(nrowA, rowA, colX, &rdot, &idot) ; switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : *pBRij = *pXRij + rdot ; *pBIij = *pXIij + idot ; break ; case SUBMTX_DIAGONAL : case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : *pBRij = rdot ; *pBIij = idot ; break ; } } } ZV_free(colZV) ; ZV_free(rowZV) ; } /* ---------------------- print out the matrices ---------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% X SubMtx object") ; fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, ncolX) ; SubMtx_writeForMatlab(mtxX, "X", msgFile) ; fprintf(msgFile, "\n\n %% A SubMtx object") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowA, ncolA) ; SubMtx_writeForMatlab(mtxA, "A", msgFile) ; fprintf(msgFile, "\n\n %% B SubMtx object") ; fprintf(msgFile, "\n B = zeros(%d,%d) ;", nrowB, ncolB) ; SubMtx_writeForMatlab(mtxB, "B", msgFile) ; fflush(msgFile) ; } /* ----------------- check with matlab ----------------- */ if ( msglvl > 1 ) { switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : fprintf(msgFile, "\n\n emtx = abs(B - X - A*X) ;" "\n\n condA = cond(eye(%d,%d) + A)" "\n\n maxabsZ = max(max(abs(emtx))) ", nrowA, nrowA) ; fflush(msgFile) ; break ; case SUBMTX_DIAGONAL : case SUBMTX_BLOCK_DIAGONAL_SYM : case SUBMTX_BLOCK_DIAGONAL_HERM : fprintf(msgFile, "\n\n emtx = abs(B - A*X) ;" "\n\n condA = cond(A)" "\n\n maxabsZ = max(max(abs(emtx))) ") ; fflush(msgFile) ; break ; } } /* ---------------------------------------- compute the solve DY = B or (I + A)Y = B ---------------------------------------- */ SubMtx_solve(mtxA, mtxB) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Y SubMtx object") ; fprintf(msgFile, "\n Y = zeros(%d,%d) ;", nrowB, ncolB) ; SubMtx_writeForMatlab(mtxB, "Y", msgFile) ; fprintf(msgFile, "\n\n %% solerror = abs(Y - X) ;" "\n\n solerror = abs(Y - X) ;" "\n\n maxabserror = max(max(solerror)) ") ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ SubMtx_free(mtxA) ; SubMtx_free(mtxX) ; SubMtx_free(mtxB) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ SubMtx/drivers/test_solveH.c010064400020550007177000000201560654223360700174470ustar00clevecompmath00000400000006/* test_solveH.c */ #include "../SubMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------- test the SubMtx_solveH() method. created -- 98may01, cca -------------------------------- */ { SubMtx *mtxA, *mtxB, *mtxX ; double idot, rdot, t1, t2 ; double *entX ; Drand *drand ; FILE *msgFile ; int inc1, inc2, mode, msglvl, ncolA, nentA, nrowA, ncolB, nrowB, ncolX, nrowX, seed, type ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type mode nrowA nentA ncolB seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of matrix A" "\n 1 -- real" "\n 2 -- complex" "\n mode -- mode of matrix A" "\n 2 -- sparse stored by rows" "\n 3 -- sparse stored by columns" "\n 5 -- sparse stored by subrows" "\n 6 -- sparse stored by subcolumns" "\n nrowA -- # of rows in matrix A" "\n nentA -- # of entries in matrix A" "\n ncolB -- # of columns in matrix B" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; mode = atoi(argv[4]) ; nrowA = atoi(argv[5]) ; nentA = atoi(argv[6]) ; ncolB = atoi(argv[7]) ; seed = atoi(argv[8]) ; fprintf(msgFile, "\n %% %s:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% mode = %d" "\n %% nrowA = %d" "\n %% nentA = %d" "\n %% ncolB = %d" "\n %% seed = %d", argv[0], msglvl, argv[2], type, mode, nrowA, nentA, ncolB, seed) ; ncolA = nrowA ; nrowB = nrowA ; nrowX = nrowA ; ncolX = ncolB ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nrowA <= 0 || nentA <= 0 || ncolB <= 0 ) { fprintf(stderr, "\n invalid input\n") ; exit(-1) ; } switch ( type ) { case SPOOLES_COMPLEX : switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : break ; default : fprintf(stderr, "\n invalid mode %d\n", mode) ; exit(-1) ; } break ; default : fprintf(stderr, "\n invalid type %d\n", type) ; exit(-1) ; break ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ------------------------------ initialize the X SubMtx object ------------------------------ */ MARKTIME(t1) ; mtxX = SubMtx_new() ; SubMtx_initRandom(mtxX, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowX, ncolX, nrowX*ncolX, ++seed) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize X SubMtx object", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% X SubMtx object") ; fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, ncolX) ; SubMtx_writeForMatlab(mtxX, "X", msgFile) ; fflush(msgFile) ; } /* ------------------------------ initialize the B SubMtx object ------------------------------ */ MARKTIME(t1) ; mtxB = SubMtx_new() ; SubMtx_init(mtxB, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowB, ncolB, nrowB*ncolB) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize B SubMtx object", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% B SubMtx object") ; fprintf(msgFile, "\n B = zeros(%d,%d) ;", nrowB, ncolB) ; SubMtx_writeForMatlab(mtxB, "B", msgFile) ; fflush(msgFile) ; } /* ------------------------------------- initialize the A matrix SubMtx object ------------------------------------- */ seed++ ; mtxA = SubMtx_new() ; switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : SubMtx_initRandomLowerTriangle(mtxA, type, mode, 0, 0, nrowA, ncolA, nentA, seed, 1) ; break ; case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : SubMtx_initRandomUpperTriangle(mtxA, type, mode, 0, 0, nrowA, ncolA, nentA, seed, 1) ; break ; default : fprintf(stderr, "\n fatal error in test_solve" "\n invalid mode = %d", mode) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% A SubMtx object") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowA, ncolA) ; SubMtx_writeForMatlab(mtxA, "A", msgFile) ; fflush(msgFile) ; } /* ---------------------------------------------------------- compute B = (I + A^H) * X (for lower and upper triangular) ---------------------------------------------------------- */ fprintf(msgFile, "\n %% mtxA->type = %d, mtxA->mode = %d", mtxA->type, mtxA->mode) ; if ( SUBMTX_IS_COMPLEX(mtxA) ) { ZV *colZV, *rowZV ; double *colX, *rowA, *pBIij, *pBRij, *pXIij, *pXRij ; int irowA, jcolX ; colZV = ZV_new() ; ZV_init(colZV, nrowA, NULL) ; colX = ZV_entries(colZV) ; rowZV = ZV_new() ; ZV_init(rowZV, nrowA, NULL) ; rowA = ZV_entries(rowZV) ; for ( jcolX = 0 ; jcolX < ncolB ; jcolX++ ) { SubMtx_fillColumnZV(mtxX, jcolX, colZV) ; fprintf(msgFile, "\n %% column %d of X", jcolX) ; ZV_writeForMatlab(colZV, "colZ", msgFile) ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { SubMtx_fillColumnZV(mtxA, irowA, rowZV) ; fprintf(msgFile, "\n %% row %d of A", irowA) ; ZV_writeForMatlab(rowZV, "rowZ", msgFile) ; SubMtx_locationOfComplexEntry(mtxX, irowA, jcolX, &pXRij, &pXIij) ; SubMtx_locationOfComplexEntry(mtxB, irowA, jcolX, &pBRij, &pBIij) ; ZVdotC(nrowA, rowA, colX, &rdot, &idot) ; fprintf(msgFile, "\n %% dot = %20.12e + %20.12e*i", rdot, idot) ; ZV_writeForMatlab(rowZV, "rowZ", msgFile) ; *pBRij = *pXRij + rdot ; *pBIij = *pXIij + idot ; } } ZV_free(colZV) ; ZV_free(rowZV) ; } /* ---------------------- print out the matrices ---------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% X SubMtx object") ; fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, ncolX) ; SubMtx_writeForMatlab(mtxX, "X", msgFile) ; fprintf(msgFile, "\n\n %% A SubMtx object") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowA, ncolA) ; SubMtx_writeForMatlab(mtxA, "A", msgFile) ; fprintf(msgFile, "\n\n %% B SubMtx object") ; fprintf(msgFile, "\n B = zeros(%d,%d) ;", nrowB, ncolB) ; SubMtx_writeForMatlab(mtxB, "B", msgFile) ; fflush(msgFile) ; } /* ----------------- check with matlab ----------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n emtx = abs(B - X - ctranspose(A)*X) ;" "\n\n condA = cond(eye(%d,%d) + ctranspose(A))" "\n\n maxabsZ = max(max(abs(emtx))) ", nrowA, nrowA) ; fflush(msgFile) ; } /* -------------------------------- compute the solve (I + A^H)Y = B -------------------------------- */ SubMtx_solveH(mtxA, mtxB) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Y SubMtx object") ; fprintf(msgFile, "\n Y = zeros(%d,%d) ;", nrowB, ncolB) ; SubMtx_writeForMatlab(mtxB, "Y", msgFile) ; fprintf(msgFile, "\n\n %% solerror = abs(Y - X) ;" "\n\n solerror = abs(Y - X) ;" "\n\n maxabserror = max(max(solerror)) ") ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ SubMtx_free(mtxA) ; SubMtx_free(mtxX) ; SubMtx_free(mtxB) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ SubMtx/drivers/test_solveT.c010064400020550007177000000216750654223362400174710ustar00clevecompmath00000400000006/* test_solveT.c */ #include "../SubMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------- test the SubMtx_solveT() method. created -- 98may01, cca -------------------------------- */ { SubMtx *mtxA, *mtxB, *mtxX ; double idot, rdot, t1, t2 ; double *entB, *entX ; Drand *drand ; FILE *msgFile ; int inc1, inc2, mode, msglvl, ncolA, nentA, nrowA, ncolB, nrowB, ncolX, nrowX, seed, type ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type mode nrowA nentA ncolB seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of matrix A" "\n 1 -- real" "\n 2 -- complex" "\n mode -- mode of matrix A" "\n 2 -- sparse stored by rows" "\n 3 -- sparse stored by columns" "\n 5 -- sparse stored by subrows" "\n 6 -- sparse stored by subcolumns" "\n nrowA -- # of rows in matrix A" "\n nentA -- # of entries in matrix A" "\n ncolB -- # of columns in matrix B" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; mode = atoi(argv[4]) ; nrowA = atoi(argv[5]) ; nentA = atoi(argv[6]) ; ncolB = atoi(argv[7]) ; seed = atoi(argv[8]) ; fprintf(msgFile, "\n %% %s:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% mode = %d" "\n %% nrowA = %d" "\n %% nentA = %d" "\n %% ncolB = %d" "\n %% seed = %d", argv[0], msglvl, argv[2], type, mode, nrowA, nentA, ncolB, seed) ; ncolA = nrowA ; nrowB = nrowA ; nrowX = nrowA ; ncolX = ncolB ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nrowA <= 0 || nentA <= 0 || ncolB <= 0 ) { fprintf(stderr, "\n invalid input\n") ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : break ; default : fprintf(stderr, "\n invalid mode %d\n", mode) ; exit(-1) ; } break ; case SPOOLES_COMPLEX : switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : break ; default : fprintf(stderr, "\n invalid mode %d\n", mode) ; exit(-1) ; } break ; default : fprintf(stderr, "\n invalid type %d\n", type) ; exit(-1) ; break ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ------------------------------ initialize the X SubMtx object ------------------------------ */ MARKTIME(t1) ; mtxX = SubMtx_new() ; SubMtx_initRandom(mtxX, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowX, ncolX, nrowX*ncolX, ++seed) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize X SubMtx object", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% X SubMtx object") ; fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, ncolX) ; SubMtx_writeForMatlab(mtxX, "X", msgFile) ; fflush(msgFile) ; } /* ------------------------------ initialize the B SubMtx object ------------------------------ */ MARKTIME(t1) ; mtxB = SubMtx_new() ; SubMtx_init(mtxB, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowB, ncolB, nrowB*ncolB) ; SubMtx_denseInfo(mtxB, &nrowB, &ncolB, &inc1, &inc2, &entB) ; if ( SUBMTX_IS_REAL(mtxX) ) { DVcopy(nrowB*ncolB, entB, entX) ; } else if ( SUBMTX_IS_COMPLEX(mtxX) ) { ZVcopy(nrowB*ncolB, entB, entX) ; } MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize B SubMtx object", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% B SubMtx object") ; fprintf(msgFile, "\n B = zeros(%d,%d) ;", nrowB, ncolB) ; SubMtx_writeForMatlab(mtxB, "B", msgFile) ; fflush(msgFile) ; } /* ------------------------------------- initialize the A matrix SubMtx object ------------------------------------- */ seed++ ; mtxA = SubMtx_new() ; switch ( mode ) { case SUBMTX_DENSE_SUBROWS : case SUBMTX_SPARSE_ROWS : SubMtx_initRandomLowerTriangle(mtxA, type, mode, 0, 0, nrowA, ncolA, nentA, seed, 1) ; break ; case SUBMTX_DENSE_SUBCOLUMNS : case SUBMTX_SPARSE_COLUMNS : SubMtx_initRandomUpperTriangle(mtxA, type, mode, 0, 0, nrowA, ncolA, nentA, seed, 1) ; break ; default : fprintf(stderr, "\n fatal error in test_solve" "\n invalid mode = %d", mode) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% A SubMtx object") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowA, ncolA) ; SubMtx_writeForMatlab(mtxA, "A", msgFile) ; fflush(msgFile) ; } /* ---------------------------------------------------------- compute B = (I + A^T) * X (for lower and upper triangular) ---------------------------------------------------------- */ if ( SUBMTX_IS_REAL(mtxA) ) { DV *colDV, *rowDV ; double *colX, *rowA, *pBij, *pXij ; int irowA, jcolX ; colDV = DV_new() ; DV_init(colDV, nrowA, NULL) ; colX = DV_entries(colDV) ; rowDV = DV_new() ; DV_init(rowDV, nrowA, NULL) ; rowA = DV_entries(rowDV) ; for ( jcolX = 0 ; jcolX < ncolB ; jcolX++ ) { SubMtx_fillColumnDV(mtxX, jcolX, colDV) ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { SubMtx_fillColumnDV(mtxA, irowA, rowDV) ; SubMtx_locationOfRealEntry(mtxX, irowA, jcolX, &pXij) ; SubMtx_locationOfRealEntry(mtxB, irowA, jcolX, &pBij) ; *pBij = *pXij + DVdot(nrowA, rowA, colX) ; } } DV_free(colDV) ; DV_free(rowDV) ; } else if ( SUBMTX_IS_COMPLEX(mtxA) ) { ZV *colZV, *rowZV ; double *colX, *rowA, *pBIij, *pBRij, *pXIij, *pXRij ; int irowA, jcolX ; colZV = ZV_new() ; ZV_init(colZV, nrowA, NULL) ; colX = ZV_entries(colZV) ; rowZV = ZV_new() ; ZV_init(rowZV, nrowA, NULL) ; rowA = ZV_entries(rowZV) ; for ( jcolX = 0 ; jcolX < ncolB ; jcolX++ ) { SubMtx_fillColumnZV(mtxX, jcolX, colZV) ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { SubMtx_fillColumnZV(mtxA, irowA, rowZV) ; SubMtx_locationOfComplexEntry(mtxX, irowA, jcolX, &pXRij, &pXIij) ; SubMtx_locationOfComplexEntry(mtxB, irowA, jcolX, &pBRij, &pBIij) ; ZVdotU(nrowA, rowA, colX, &rdot, &idot) ; *pBRij = *pXRij + rdot ; *pBIij = *pXIij + idot ; } } ZV_free(colZV) ; ZV_free(rowZV) ; } /* ---------------------- print out the matrices ---------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% X SubMtx object") ; fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, ncolX) ; SubMtx_writeForMatlab(mtxX, "X", msgFile) ; fprintf(msgFile, "\n\n %% A SubMtx object") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowA, ncolA) ; SubMtx_writeForMatlab(mtxA, "A", msgFile) ; fprintf(msgFile, "\n\n %% B SubMtx object") ; fprintf(msgFile, "\n B = zeros(%d,%d) ;", nrowB, ncolB) ; SubMtx_writeForMatlab(mtxB, "B", msgFile) ; fflush(msgFile) ; } /* ----------------- check with matlab ----------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n emtx = abs(B - X - transpose(A)*X) ;" "\n\n condA = cond(eye(%d,%d) + transpose(A))" "\n\n maxabsZ = max(max(abs(emtx))) ", nrowA, nrowA) ; fflush(msgFile) ; } /* -------------------------------- compute the solve (I + A^T)Y = B -------------------------------- */ SubMtx_solveT(mtxA, mtxB) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Y SubMtx object") ; fprintf(msgFile, "\n Y = zeros(%d,%d) ;", nrowB, ncolB) ; SubMtx_writeForMatlab(mtxB, "Y", msgFile) ; fprintf(msgFile, "\n\n %% solerror = abs(Y - X) ;" "\n\n solerror = abs(Y - X) ;" "\n\n maxabserror = max(max(solerror)) ") ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ SubMtx_free(mtxA) ; SubMtx_free(mtxX) ; SubMtx_free(mtxB) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ SubMtx/drivers/test_solveupd.c010064400020550007177000000242740654223377500200630ustar00clevecompmath00000400000006/* test_solveupd.c */ #include "../SubMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------- test the SubMtx_solveupd() method. created -- 98may02, cca ---------------------------------- */ { SubMtx *mtxA, *mtxX, *mtxY ; double ops, t1, t2 ; double *entX, *entY ; Drand *drand ; FILE *msgFile ; int inc1, inc2, irowA, jcolX, mode, msglvl, ncolA, nentA, nrowA, ncolX, nrowX, ncolY, nrowY, seed, type ; int *colindA, *ivec, *rowindA ; if ( argc != 12 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type mode" "\n nrowY ncolY nrowA ncolA nentA nrowX seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of matrix A" "\n 1 -- real" "\n 2 -- complex" "\n mode -- mode of matrix A" "\n 0 -- dense stored by rows" "\n 1 -- dense stored by columns" "\n 2 -- sparse stored by rows" "\n 3 -- sparse stored by columns" "\n nrowY -- # of rows in vector Y" "\n ncolY -- # of columns in vector Y" "\n nrowA -- # of rows in matrix A" "\n ncolA -- # of columns in matrix A" "\n nentA -- # of entries in matrix A" "\n nrowX -- # of rows in matrix X" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; mode = atoi(argv[4]) ; nrowY = atoi(argv[5]) ; ncolY = atoi(argv[6]) ; nrowA = atoi(argv[7]) ; ncolA = atoi(argv[8]) ; nentA = atoi(argv[9]) ; nrowX = atoi(argv[10]) ; seed = atoi(argv[11]) ; fprintf(msgFile, "\n %% %s:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% mode = %d" "\n %% nrowY = %d" "\n %% ncolY = %d" "\n %% nrowA = %d" "\n %% ncolA = %d" "\n %% nentA = %d" "\n %% nrowX = %d" "\n %% seed = %d", argv[0], msglvl, argv[2], type, mode, nrowY, ncolY, nrowA, ncolA, nentA, nrowX, seed) ; ncolX = ncolY ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nrowA <= 0 || nrowA > nrowY || ncolA <= 0 || ncolA > nrowX || nentA > nrowA*ncolA || nrowX <= 0 ) { fprintf(stderr, "\n invalid input\n") ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n invalid type %d\n", type) ; exit(-1) ; } switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : break ; default : fprintf(stderr, "\n invalid mode %d\n", mode) ; exit(-1) ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ------------------------------ initialize the X SubMtx object ------------------------------ */ MARKTIME(t1) ; mtxX = SubMtx_new() ; SubMtx_init(mtxX, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowX, ncolX, nrowX*ncolX) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; if ( SUBMTX_IS_REAL(mtxX) ) { Drand_fillDvector(drand, nrowX*ncolX, entX) ; } else if ( SUBMTX_IS_COMPLEX(mtxX) ) { Drand_fillDvector(drand, 2*nrowX*ncolX, entX) ; } MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize X SubMtx object", t2 - t1) ; /* ------------------------------ initialize the Y SubMtx object ------------------------------ */ MARKTIME(t1) ; mtxY = SubMtx_new() ; SubMtx_init(mtxY, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowY, ncolY, nrowY*ncolY) ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; if ( SUBMTX_IS_REAL(mtxX) ) { Drand_fillDvector(drand, nrowY*ncolY, entY) ; DVzero(nrowY*ncolY, entY) ; } else if ( SUBMTX_IS_COMPLEX(mtxX) ) { Drand_fillDvector(drand, 2*nrowY*ncolY, entY) ; DVzero(2*nrowY*ncolY, entY) ; } MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize Y SubMtx object", t2 - t1) ; /* ------------------------------------- initialize the A matrix SubMtx object ------------------------------------- */ mtxA = SubMtx_new() ; SubMtx_initRandom(mtxA, type, mode, 0, 0, nrowA, ncolA, nentA, seed) ; /* ------------------------- load the row indices of A ------------------------- */ SubMtx_rowIndices(mtxA, &nrowA, &rowindA) ; ivec = IVinit(nrowY, -1) ; IVramp(nrowY, ivec, 0, 1) ; IVshuffle(nrowY, ivec, seed+1) ; IVcopy(nrowA, rowindA, ivec) ; IVqsortUp(nrowA, rowindA) ; IVfree(ivec) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n %% row indices of A") ; IVfprintf(msgFile, nrowA, rowindA) ; fflush(msgFile) ; } /* ---------------------------- load the column indices of A ---------------------------- */ SubMtx_columnIndices(mtxA, &ncolA, &colindA) ; ivec = IVinit(nrowX, -1) ; IVramp(nrowX, ivec, 0, 1) ; IVshuffle(nrowX, ivec, seed+2) ; IVcopy(ncolA, colindA, ivec) ; IVqsortUp(ncolA, colindA) ; IVfree(ivec) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n %% column indices of A") ; IVfprintf(msgFile, ncolA, colindA) ; fflush(msgFile) ; } /* ---------------------------------- compute the matrix-matrix multiply ---------------------------------- */ if ( type == SPOOLES_REAL ) { double *colX, *pYij, *rowA ; double sum ; DV *colDV, *rowDV ; int ii ; ops = 2*nrowA*ncolA*ncolX ; colDV = DV_new() ; DV_init(colDV, nrowX, NULL) ; colX = DV_entries(colDV) ; rowDV = DV_new() ; DV_init(rowDV, ncolA, NULL) ; rowA = DV_entries(rowDV) ; for ( jcolX = 0 ; jcolX < ncolX ; jcolX++ ) { SubMtx_fillColumnDV(mtxX, jcolX, colDV) ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { SubMtx_fillRowDV(mtxA, irowA, rowDV) ; if ( ncolA == nrowX ) { for ( ii = 0, sum = 0.0 ; ii < ncolA ; ii++ ) { sum += rowA[ii] * colX[ii] ; } } else { for ( ii = 0, sum = 0.0 ; ii < ncolA ; ii++ ) { sum += rowA[ii] * colX[colindA[ii]] ; } } if ( nrowA == nrowY ) { SubMtx_locationOfRealEntry(mtxY, irowA, jcolX, &pYij) ; } else { SubMtx_locationOfRealEntry(mtxY, rowindA[irowA], jcolX, &pYij) ; } *pYij = sum ; } } DV_free(colDV) ; DV_free(rowDV) ; } else if ( type == SPOOLES_COMPLEX ) { double *colX, *pYIij, *pYRij, *rowA ; double idot, rdot ; ZV *colZV, *rowZV ; ops = 8*nrowA*ncolA*ncolX ; colZV = ZV_new() ; ZV_init(colZV, nrowX, NULL) ; colX = ZV_entries(colZV) ; rowZV = ZV_new() ; ZV_init(rowZV, ncolA, NULL) ; rowA = ZV_entries(rowZV) ; for ( jcolX = 0 ; jcolX < ncolX ; jcolX++ ) { SubMtx_fillColumnZV(mtxX, jcolX, colZV) ; for ( irowA = 0 ; irowA < nrowA ; irowA++ ) { SubMtx_fillRowZV(mtxA, irowA, rowZV) ; if ( ncolA == nrowX ) { ZVdotU(ncolA, colX, rowA, &rdot, &idot) ; } else { ZVdotiU(ncolA, colX, colindA, rowA, &rdot, &idot) ; } if ( nrowA == nrowY ) { SubMtx_locationOfComplexEntry(mtxY, irowA, jcolX, &pYRij, &pYIij) ; } else { SubMtx_locationOfComplexEntry(mtxY, rowindA[irowA], jcolX, &pYRij, &pYIij) ; } *pYRij = rdot ; *pYIij = idot ; } } ZV_free(colZV) ; ZV_free(rowZV) ; } MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to compute m-m, %.3f mflops", t2 - t1, ops*1.e-6/(t2 - t1)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Z SubMtx object") ; fprintf(msgFile, "\n Z = zeros(%d,%d) ;", nrowY, ncolY) ; SubMtx_writeForMatlab(mtxY, "Z", msgFile) ; fflush(msgFile) ; } /* ---------------------- print out the matrices ---------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Y SubMtx object") ; fprintf(msgFile, "\n Y = zeros(%d,%d) ;", nrowY, ncolY) ; SubMtx_writeForMatlab(mtxY, "Y", msgFile) ; fprintf(msgFile, "\n\n %% A SubMtx object") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowY, nrowX) ; SubMtx_writeForMatlab(mtxA, "A", msgFile) ; fprintf(msgFile, "\n\n %% X SubMtx object") ; fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, ncolY) ; SubMtx_writeForMatlab(mtxX, "X", msgFile) ; fflush(msgFile) ; } /* ----------------- check with matlab ----------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n emtx = abs(Y - A*X) ;" "\n\n maxabs = max(max(emtx)) ") ; fflush(msgFile) ; } /* ------------------------------- compute the update Y := Y - A*X (Y should now be zero) ------------------------------- */ SubMtx_solveupd(mtxY, mtxA, mtxX) ; /* ---------------------- print out the Y matrix ---------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Z SubMtx object") ; fprintf(msgFile, "\n Z = zeros(%d,%d) ;", nrowY, ncolY) ; SubMtx_writeForMatlab(mtxY, "Z", msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n RES %4d %4d %4d %4d %4d %4d %4d %4d %12.4e", type, mode, nrowY, ncolY, nrowA, ncolA, nrowX, ncolX, SubMtx_maxabs(mtxY)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n emtx = abs(Z) ;" "\n\n maxerr = max(max(emtx)) ") ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ SubMtx_free(mtxA) ; SubMtx_free(mtxX) ; SubMtx_free(mtxY) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ SubMtx/drivers/test_solveupdH.c010064400020550007177000000214060654223366000201560ustar00clevecompmath00000400000006/* test_solveupdH.c */ #include "../SubMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------- test the SubMtx_solveupdH() method. created -- 98may02, cca --------------------------------- */ { SubMtx *mtxA, *mtxX, *mtxY ; double idot, ops, rdot, t1, t2 ; double *colX, *entX, *entY, *pYIij, *pYRij, *rowAT ; Drand *drand ; ZV *colZV, *rowZV ; FILE *msgFile ; int inc1, inc2, irowAT, jcolX, mode, msglvl, ncolA, ncolAT, nentA, nrowA, nrowAT, ncolX, nrowX, ncolY, nrowY, seed, type ; int *colindA, *ivec, *rowindA ; if ( argc != 11 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile mode " "\n nrowY ncolY nrowA ncolA nentA nrowX seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n mode -- mode of matrix A" "\n 0 -- dense stored by rows" "\n 1 -- dense stored by columns" "\n 2 -- sparse stored by rows" "\n 3 -- sparse stored by columns" "\n nrowY -- # of rows in vector Y" "\n ncolY -- # of columns in vector Y" "\n nrowA -- # of rows in matrix A" "\n ncolA -- # of columns in matrix A" "\n nentA -- # of entries in matrix A" "\n nrowX -- # of rows in matrix X" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = SPOOLES_COMPLEX ; mode = atoi(argv[3]) ; nrowY = atoi(argv[4]) ; ncolY = atoi(argv[5]) ; nrowA = atoi(argv[6]) ; ncolA = atoi(argv[7]) ; nentA = atoi(argv[8]) ; nrowX = atoi(argv[9]) ; seed = atoi(argv[10]) ; fprintf(msgFile, "\n %% %s:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% mode = %d" "\n %% nrowY = %d" "\n %% ncolY = %d" "\n %% nrowA = %d" "\n %% ncolA = %d" "\n %% nentA = %d" "\n %% nrowX = %d" "\n %% seed = %d", argv[0], msglvl, argv[2], type, mode, nrowY, ncolY, nrowA, ncolA, nentA, nrowX, seed) ; ncolX = ncolY ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nrowA <= 0 || nrowA > nrowX || ncolA <= 0 || ncolA > nrowY || nentA > nrowA*ncolA || nrowX <= 0 ) { fprintf(stderr, "\n invalid input\n") ; exit(-1) ; } switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : break ; default : fprintf(stderr, "\n invalid mode %d\n", mode) ; exit(-1) ; break ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ---------------------------- initialize the X SubMtx object ---------------------------- */ MARKTIME(t1) ; mtxX = SubMtx_new() ; SubMtx_init(mtxX, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowX, ncolX, nrowX*ncolX) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; Drand_fillDvector(drand, 2*nrowX*ncolX, entX) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize X SubMtx object", t2 - t1) ; /* ---------------------------- initialize the Y SubMtx object ---------------------------- */ MARKTIME(t1) ; mtxY = SubMtx_new() ; SubMtx_init(mtxY, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowY, ncolY, nrowY*ncolY) ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; Drand_fillDvector(drand, 2*nrowY*ncolY, entY) ; DVzero(2*nrowY*ncolY, entY) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize Y SubMtx object", t2 - t1) ; /* ----------------------------------- initialize the A matrix SubMtx object ----------------------------------- */ mtxA = SubMtx_new() ; switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : SubMtx_initRandom(mtxA, type, mode, 0, 0, nrowA, ncolA, nentA, seed); break ; default : fprintf(stderr, "\n fatal error in test_solveupdH" "\n unsupported type %d for A\n", type) ; exit(-1) ; } /* ------------------------- load the row indices of A ------------------------- */ SubMtx_rowIndices(mtxA, &nrowA, &rowindA) ; ivec = IVinit(nrowX, -1) ; IVramp(nrowX, ivec, 0, 1) ; IVshuffle(nrowX, ivec, seed+1) ; IVcopy(nrowA, rowindA, ivec) ; IVqsortUp(nrowA, rowindA) ; IVfree(ivec) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %% row indices of A") ; IVfprintf(msgFile, nrowA, rowindA) ; fflush(msgFile) ; } /* ---------------------------- load the column indices of A ---------------------------- */ SubMtx_columnIndices(mtxA, &ncolA, &colindA) ; ivec = IVinit(nrowY, -1) ; IVramp(nrowY, ivec, 0, 1) ; IVshuffle(nrowY, ivec, seed+2) ; IVcopy(ncolA, colindA, ivec) ; IVqsortUp(ncolA, colindA) ; IVfree(ivec) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n %% column indices of A") ; IVfprintf(msgFile, ncolA, colindA) ; fflush(msgFile) ; } /* ---------------------------------- compute the matrix-matrix multiply ---------------------------------- */ nrowAT = ncolA ; ncolAT = nrowA ; ops = 2*nrowA*ncolA*ncolX ; colZV = ZV_new() ; ZV_init(colZV, nrowX, NULL) ; colX = ZV_entries(colZV) ; rowZV = ZV_new() ; ZV_init(rowZV, ncolAT, NULL) ; rowAT = ZV_entries(rowZV) ; for ( jcolX = 0 ; jcolX < ncolX ; jcolX++ ) { SubMtx_fillColumnZV(mtxX, jcolX, colZV) ; for ( irowAT = 0 ; irowAT < nrowAT ; irowAT++ ) { SubMtx_fillColumnZV(mtxA, irowAT, rowZV) ; if ( ncolAT == nrowX ) { ZVdotC(nrowA, rowAT, colX, &rdot, &idot) ; } else { ZVdotiC(nrowA, colX, rowindA, rowAT, &rdot, &idot) ; idot = -idot ; } if ( nrowAT == nrowY ) { SubMtx_locationOfComplexEntry(mtxY, irowAT, jcolX, &pYRij, &pYIij) ; } else { SubMtx_locationOfComplexEntry(mtxY, colindA[irowAT], jcolX, &pYRij, &pYIij) ; } *pYRij = rdot ; *pYIij = idot ; } } ZV_free(colZV) ; ZV_free(rowZV) ; MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to compute m-m, %.3f mflops", t2 - t1, ops*1.e-6/(t2 - t1)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Z SubMtx object") ; fprintf(msgFile, "\n Z = zeros(%d,%d) ;", nrowY, ncolY) ; SubMtx_writeForMatlab(mtxY, "Z", msgFile) ; fflush(msgFile) ; } /* ---------------------- print out the matrices ---------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Y SubMtx object") ; fprintf(msgFile, "\n Y = zeros(%d,%d) ;", nrowY, ncolY) ; SubMtx_writeForMatlab(mtxY, "Y", msgFile) ; fprintf(msgFile, "\n\n %% A SubMtx object") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowX, nrowY) ; SubMtx_writeForMatlab(mtxA, "A", msgFile) ; fprintf(msgFile, "\n\n %% X SubMtx object") ; fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, ncolY) ; SubMtx_writeForMatlab(mtxX, "X", msgFile) ; fflush(msgFile) ; } /* ----------------- check with matlab ----------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n emtx = abs(Y - ctranspose(A)*X) ;" "\n\n maxabs = max(max(emtx)) ") ; fflush(msgFile) ; } /* --------------------------------- compute the update Y := Y - A^H*X (Y should now be zero) --------------------------------- */ SubMtx_solveupdH(mtxY, mtxA, mtxX) ; /* ---------------------- print out the Y matrix ---------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Y SubMtx object") ; fprintf(msgFile, "\n Z = zeros(%d,%d) ;", nrowY, ncolY) ; SubMtx_writeForMatlab(mtxY, "Z", msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n %% RES %4d %4d %4d %4d %4d %4d %4d %4d %12.4e", type, mode, nrowY, ncolY, nrowA, ncolA, nrowX, ncolX, SubMtx_maxabs(mtxY)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n emtx = abs(Z) ;" "\n\n maxerr = max(max(emtx)) ") ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ SubMtx_free(mtxA) ; SubMtx_free(mtxX) ; SubMtx_free(mtxY) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ SubMtx/drivers/test_solveupdT.c010064400020550007177000000243570654223370100201760ustar00clevecompmath00000400000006/* test_solveupdT.c */ #include "../SubMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------- test the SubMtx_solveupdT() method. created -- 98may02, cca ----------------------------------- */ { SubMtx *mtxA, *mtxX, *mtxY ; double ops, t1, t2 ; double *entX, *entY ; Drand *drand ; FILE *msgFile ; int inc1, inc2, mode, msglvl, ncolA, ncolAT, nentA, nrowA, nrowAT, ncolX, nrowX, ncolY, nrowY, seed, type ; int *colindA, *ivec, *rowindA ; if ( argc != 12 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type mode" "\n nrowY ncolY nrowA ncolA nentA nrowX seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of matrix A" "\n 1 -- real" "\n 2 -- complex" "\n mode -- mode of matrix A" "\n 0 -- dense stored by rows" "\n 1 -- dense stored by columns" "\n 2 -- sparse stored by rows" "\n 3 -- sparse stored by columns" "\n nrowY -- # of rows in vector Y" "\n ncolY -- # of columns in vector Y" "\n nrowA -- # of rows in matrix A" "\n ncolA -- # of columns in matrix A" "\n nentA -- # of entries in matrix A" "\n nrowX -- # of rows in matrix X" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; mode = atoi(argv[4]) ; nrowY = atoi(argv[5]) ; ncolY = atoi(argv[6]) ; nrowA = atoi(argv[7]) ; ncolA = atoi(argv[8]) ; nentA = atoi(argv[9]) ; nrowX = atoi(argv[10]) ; seed = atoi(argv[11]) ; fprintf(msgFile, "\n %% %s:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% mode = %d" "\n %% nrowY = %d" "\n %% ncolY = %d" "\n %% nrowA = %d" "\n %% ncolA = %d" "\n %% nentA = %d" "\n %% nrowX = %d" "\n %% seed = %d", argv[0], msglvl, argv[2], type, mode, nrowY, ncolY, nrowA, ncolA, nentA, nrowX, seed) ; ncolX = ncolY ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( type < 0 || type > 6 || nrowA <= 0 || nrowA > nrowX || ncolA <= 0 || ncolA > nrowY || nentA > nrowA*ncolA || nrowX <= 0 ) { fprintf(stderr, "\n invalid input\n") ; exit(-1) ; } switch ( type ) { case SPOOLES_REAL : case SPOOLES_COMPLEX : break ; default : fprintf(stderr, "\n invalid type %d\n", type) ; exit(-1) ; } switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_DENSE_COLUMNS : case SUBMTX_SPARSE_ROWS : case SUBMTX_SPARSE_COLUMNS : break ; default : fprintf(stderr, "\n invalid mode %d\n", mode) ; exit(-1) ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ---------------------------- initialize the X SubMtx object ---------------------------- */ MARKTIME(t1) ; mtxX = SubMtx_new() ; SubMtx_init(mtxX, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowX, ncolX, nrowX*ncolX) ; SubMtx_denseInfo(mtxX, &nrowX, &ncolX, &inc1, &inc2, &entX) ; if ( SUBMTX_IS_REAL(mtxX) ) { Drand_fillDvector(drand, nrowX*ncolX, entX) ; } else if ( SUBMTX_IS_COMPLEX(mtxX) ) { Drand_fillDvector(drand, 2*nrowX*ncolX, entX) ; } MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize X SubMtx object", t2 - t1) ; /* ---------------------------- initialize the Y SubMtx object ---------------------------- */ MARKTIME(t1) ; mtxY = SubMtx_new() ; SubMtx_init(mtxY, type, SUBMTX_DENSE_COLUMNS, 0, 0, nrowY, ncolY, nrowY*ncolY) ; SubMtx_denseInfo(mtxY, &nrowY, &ncolY, &inc1, &inc2, &entY) ; if ( SUBMTX_IS_REAL(mtxX) ) { DVzero(nrowY*ncolY, entY) ; } else if ( SUBMTX_IS_COMPLEX(mtxX) ) { DVzero(2*nrowY*ncolY, entY) ; } MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to initialize Y SubMtx object", t2 - t1) ; /* ----------------------------------- initialize the A matrix SubMtx object ----------------------------------- */ mtxA = SubMtx_new() ; SubMtx_initRandom(mtxA, type, mode, 0, 0, nrowA, ncolA, nentA, seed) ; /* ------------------------- load the row indices of A ------------------------- */ SubMtx_rowIndices(mtxA, &nrowA, &rowindA) ; ivec = IVinit(nrowX, -1) ; IVramp(nrowX, ivec, 0, 1) ; IVshuffle(nrowX, ivec, seed+1) ; IVcopy(nrowA, rowindA, ivec) ; IVqsortUp(nrowA, rowindA) ; IVfree(ivec) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %% row indices of A") ; IVfprintf(msgFile, nrowA, rowindA) ; fflush(msgFile) ; } /* ---------------------------- load the column indices of A ---------------------------- */ SubMtx_columnIndices(mtxA, &ncolA, &colindA) ; ivec = IVinit(nrowY, -1) ; IVramp(nrowY, ivec, 0, 1) ; IVshuffle(nrowY, ivec, seed+2) ; IVcopy(ncolA, colindA, ivec) ; IVqsortUp(ncolA, colindA) ; IVfree(ivec) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %% column indices of A") ; IVfprintf(msgFile, ncolA, colindA) ; fflush(msgFile) ; } /* ---------------------------------- compute the matrix-matrix multiply ---------------------------------- */ nrowAT = ncolA ; ncolAT = nrowA ; if ( type == SPOOLES_REAL ) { double *colX, *pYij, *rowAT ; double sum ; DV *colDV, *rowDV ; int ii, irowAT, jcolX ; ops = 2*nrowA*ncolA*ncolX ; colDV = DV_new() ; DV_init(colDV, nrowX, NULL) ; colX = DV_entries(colDV) ; rowDV = DV_new() ; DV_init(rowDV, ncolAT, NULL) ; rowAT = DV_entries(rowDV) ; for ( jcolX = 0 ; jcolX < ncolX ; jcolX++ ) { SubMtx_fillColumnDV(mtxX, jcolX, colDV) ; for ( irowAT = 0 ; irowAT < nrowAT ; irowAT++ ) { SubMtx_fillColumnDV(mtxA, irowAT, rowDV) ; if ( ncolAT == nrowX ) { for ( ii = 0, sum = 0.0 ; ii < ncolAT ; ii++ ) { sum += rowAT[ii] * colX[ii] ; } } else { for ( ii = 0, sum = 0.0 ; ii < ncolAT ; ii++ ) { sum += rowAT[ii] * colX[rowindA[ii]] ; } } if ( nrowAT == nrowY ) { SubMtx_locationOfRealEntry(mtxY, irowAT, jcolX, &pYij) ; } else { SubMtx_locationOfRealEntry(mtxY, colindA[irowAT], jcolX, &pYij) ; } *pYij = sum ; } } DV_free(colDV) ; DV_free(rowDV) ; } else if ( type == SPOOLES_COMPLEX ) { double *colX, *pYIij, *pYRij, *rowAT ; double idot, rdot ; ZV *colZV, *rowZV ; int irowAT, jcolX ; ops = 8*nrowA*ncolA*ncolX ; colZV = ZV_new() ; ZV_init(colZV, nrowX, NULL) ; colX = ZV_entries(colZV) ; rowZV = ZV_new() ; ZV_init(rowZV, ncolAT, NULL) ; rowAT = ZV_entries(rowZV) ; for ( jcolX = 0 ; jcolX < ncolX ; jcolX++ ) { SubMtx_fillColumnZV(mtxX, jcolX, colZV) ; for ( irowAT = 0 ; irowAT < nrowAT ; irowAT++ ) { SubMtx_fillColumnZV(mtxA, irowAT, rowZV) ; if ( ncolAT == nrowX ) { ZVdotU(nrowA, colX, rowAT, &rdot, &idot) ; } else { ZVdotiU(nrowA, colX, rowindA, rowAT, &rdot, &idot) ; } if ( nrowAT == nrowY ) { SubMtx_locationOfComplexEntry(mtxY, irowAT, jcolX, &pYRij, &pYIij) ; } else { SubMtx_locationOfComplexEntry(mtxY, colindA[irowAT], jcolX, &pYRij, &pYIij) ; } *pYRij = rdot ; *pYIij = idot ; } } ZV_free(colZV) ; ZV_free(rowZV) ; } MARKTIME(t2) ; fprintf(msgFile, "\n %% CPU : %.3f to compute m-m, %.3f mflops", t2 - t1, ops*1.e-6/(t2 - t1)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Z SubMtx object") ; fprintf(msgFile, "\n Z = zeros(%d,%d) ;", nrowY, ncolY) ; SubMtx_writeForMatlab(mtxY, "Z", msgFile) ; fflush(msgFile) ; } /* ---------------------- print out the matrices ---------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Y SubMtx object") ; fprintf(msgFile, "\n Y = zeros(%d,%d) ;", nrowY, ncolY) ; SubMtx_writeForMatlab(mtxY, "Y", msgFile) ; fprintf(msgFile, "\n\n %% A SubMtx object") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowX, nrowY) ; SubMtx_writeForMatlab(mtxA, "A", msgFile) ; fprintf(msgFile, "\n\n %% X SubMtx object") ; fprintf(msgFile, "\n X = zeros(%d,%d) ;", nrowX, ncolY) ; SubMtx_writeForMatlab(mtxX, "X", msgFile) ; fflush(msgFile) ; } /* ----------------- check with matlab ----------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n emtx = abs(Y - transpose(A)*X) ;" "\n\n maxabs = max(max(emtx)) ") ; fflush(msgFile) ; } /* ------------------------------- compute the update Y := Y - A*X (Y should now be zero) ------------------------------- */ SubMtx_solveupdT(mtxY, mtxA, mtxX) ; /* ---------------------- print out the Y matrix ---------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% Y SubMtx object") ; fprintf(msgFile, "\n Z = zeros(%d,%d) ;", nrowY, ncolY) ; SubMtx_writeForMatlab(mtxY, "Z", msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n %% RES %4d %4d %4d %4d %4d %4d %4d %4d %12.4e", type, mode, nrowY, ncolY, nrowA, ncolA, nrowX, ncolX, SubMtx_maxabs(mtxY)) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n emtx = abs(Z) ;" "\n\n maxerr = max(max(emtx)) ") ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ SubMtx_free(mtxA) ; SubMtx_free(mtxX) ; SubMtx_free(mtxY) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ SubMtx/drivers/test_sort.c010064400020550007177000000112500654517055100171720ustar00clevecompmath00000400000006/* test_sort.c */ #include "../SubMtx.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------- test the sort methods. created -- 98apr15, cca ----------------------- */ { SubMtx *mtxA ; double t1, t2 ; Drand *drand ; FILE *msgFile ; int mode, msglvl, ncolA, nentA, nrowA, seed, type ; int *colind, *ivtemp, *rowind ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile type mode " "\n nrowA ncolA nentA seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 -- real" "\n 2 -- complex" "\n mode -- type of matrix A" "\n 0 -- dense stored by rows" "\n 1 -- dense stored by columns" "\n 2 -- sparse stored by rows" "\n 3 -- sparse stored by columns" "\n nrowA -- # of rows in matrix A" "\n ncolA -- # of columns in matrix A" "\n nentA -- # of entries in matrix A" "\n seed -- random number seed" "\n", argv[0]) ; return(0) ; } if ( (msglvl = atoi(argv[1])) < 0 ) { fprintf(stderr, "\n message level must be positive\n") ; exit(-1) ; } if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; mode = atoi(argv[4]) ; nrowA = atoi(argv[5]) ; ncolA = atoi(argv[6]) ; nentA = atoi(argv[7]) ; seed = atoi(argv[8]) ; fprintf(msgFile, "\n %% %s:" "\n %% msglvl = %d" "\n %% msgFile = %s" "\n %% type = %d" "\n %% mode = %d" "\n %% nrowA = %d" "\n %% ncolA = %d" "\n %% nentA = %d" "\n %% seed = %d", argv[0], msglvl, argv[2], type, mode, nrowA, ncolA, nentA, seed) ; /* ----------------------------- check for errors in the input ----------------------------- */ if ( nrowA <= 0 || ncolA <= 0 || nentA > nrowA*ncolA ) { fprintf(stderr, "\n invalid input\n") ; exit(-1) ; } /* -------------------------------------- initialize the random number generator -------------------------------------- */ drand = Drand_new() ; Drand_init(drand) ; Drand_setSeed(drand, seed) ; Drand_setNormal(drand, 0.0, 1.0) ; /* ----------------------------------- initialize the A matrix SubMtx object ----------------------------------- */ mtxA = SubMtx_new() ; SubMtx_initRandom(mtxA, type, mode, 0, 0, nrowA, ncolA, nentA, seed) ; SubMtx_rowIndices(mtxA, &nrowA, &rowind) ; ivtemp = IVinit(nrowA + 5, -1) ; IVramp(nrowA + 5, ivtemp, 0, 1) ; IVshuffle(nrowA + 5, ivtemp, ++seed) ; IVcopy(nrowA, rowind, ivtemp) ; IVfree(ivtemp) ; SubMtx_columnIndices(mtxA, &ncolA, &colind) ; ivtemp = IVinit(ncolA + 5, -1) ; IVramp(ncolA + 5, ivtemp, 0, 1) ; IVshuffle(ncolA + 5, ivtemp, ++seed) ; IVcopy(ncolA, colind, ivtemp) ; IVfree(ivtemp) ; SubMtx_writeToFile(mtxA, "temp.submtxb") ; SubMtx_writeToFile(mtxA, "temp.submtxf") ; /* -------------------- print out the matrix -------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% A SubMtx object") ; fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowA+5, ncolA+5) ; SubMtx_writeForMatlab(mtxA, "A", msgFile) ; fflush(msgFile) ; } switch ( mode ) { case SUBMTX_DENSE_ROWS : case SUBMTX_SPARSE_ROWS : /* -------------------------------- sort the rows in ascending order -------------------------------- */ SubMtx_sortRowsUp(mtxA) ; break ; } switch ( mode ) { case SUBMTX_DENSE_COLUMNS : case SUBMTX_SPARSE_COLUMNS : /* ----------------------------------- sort the columns in ascending order ----------------------------------- */ SubMtx_sortColumnsUp(mtxA) ; break ; } /* -------------------------- print out the matrix again -------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n %% B SubMtx object") ; fprintf(msgFile, "\n B = zeros(%d,%d) ;", nrowA+5, ncolA+5) ; SubMtx_writeForMatlab(mtxA, "B", msgFile) ; fflush(msgFile) ; } /* ----------------- check with matlab ----------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n maxabs = max(max(abs(A - B))) ") ; fflush(msgFile) ; } /* ------------------------ free the working storage ------------------------ */ SubMtx_free(mtxA) ; Drand_free(drand) ; fprintf(msgFile, "\n") ; return(1) ; } /*--------------------------------------------------------------------*/ SubMtx/drivers/temp.submtxb010064400020550007177000000007100663603040500173440ustar00clevecompmath00000400000006 ?^<-8?b7i9?ƘW?=7?  ?mcj"?][?ޒMq?غl!?V0est?]g?΍#IC?˞uWIF?솙ea?奤\?Dˉu?na|?5?֏{S?譑B?GS|9]p?]h_?-1W?C?J?~?o7bG?^tj?|T?ƥ?Xî,?^U?@g"SubMtx/drivers/temp.submtxf010064400020550007177000000012550663603040500173550ustar00clevecompmath00000400000006 2 1 0 0 8 3 24 4 8 1 6 3 0 11 10 0 4 5 4.2767e-01 5.5522e-01 1.7654e-01 6.9497e-01 5.3290e-01 7.9460e-01 1.5910e-01 4.7771e-01 3.8641e-01 9.4802e-01 4.5838e-01 1.2987e-02 5.7315e-02 8.1200e-01 1.7099e-01 5.5606e-01 8.3822e-02 7.0509e-01 5.4442e-01 1.0106e-01 2.2178e-01 3.0841e-01 5.5303e-01 4.4999e-01 6.3793e-01 5.3892e-01 3.0898e-01 2.3868e-01 2.1578e-01 8.9143e-01 8.4053e-01 6.9588e-01 4.4425e-01 1.3758e-01 6.5119e-01 7.7119e-01 5.3996e-01 2.3246e-01 6.3058e-01 3.1205e-01 2.1031e-01 4.4433e-01 8.6699e-01 5.9204e-01 1.8579e-01 2.0846e-02 3.3388e-01 8.0662e-02SubMtx/doc/004275500020550007177000000000000654276751400141055ustar00clevecompmath00000400000006SubMtx/doc/dataStructure.tex010064400020550007177000000062230653626347100174530ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:SubMtx:dataStructure} \par \par The {\tt SubMtx} structure has the following fields. \begin{itemize} \item {\tt int type} : type of entries. \begin{itemize} \item {\tt SPOOLES\_REAL} : double precision real entries. \item {\tt SPOOLES\_COMPLEX} : double precision complex entries. \end{itemize} \item {\tt int mode} : storage mode. \begin{itemize} \item {\tt SUBMTX\_DENSE\_ROWS} : dense, storage by rows. \item {\tt SUBMTX\_DENSE\_COLUMNS} : dense, storage by columns. \item {\tt SUBMTX\_SPARSE\_ROWS} : sparse, storage by rows. \item {\tt SUBMTX\_SPARSE\_COLUMNS} : sparse, storage by columns. \item {\tt SUBMTX\_SPARSE\_TRIPLES} : sparse, storage by $(i,j,a_{i,j})$ triples. \item {\tt SUBMTX\_DENSE\_SUBROWS} : sparse, storage by dense subrows. \item {\tt SUBMTX\_DENSE\_SUBCOLUMNS} : sparse, storage by dense subcolumns. \item {\tt SUBMTX\_DIAGONAL} : a diagonal matrix. \item {\tt SUBMTX\_BLOCK\_DIAGONAL\_SYM} : a symmetric block diagonal matrix with $1 \times 1$ and $2 \times 2$ blocks. \item {\tt SUBMTX\_BLOCK\_DIAGONAL\_HERM} : a hermitian block diagonal matrix with $1 \times 1$ and $2 \times 2$ blocks. \end{itemize} \item {\tt int rowid} : object's row id, default value is {\tt -1}. \item {\tt int colid} : object's column id, default value is {\tt -1}. \item {\tt int nrow} : number of rows \item {\tt int ncol} : number of columns \item {\tt int nent} : number of stored matrix entries. \item {\tt DV wrkDV} : object that manages the owned working storage. \item {\tt SubMtx *next} : link to a next object in a singly linked list. \end{itemize} \par One can query the type of the object using these simple macros. \begin{itemize} \item {\tt SUBMTX\_IS\_REAL(mtx)} is {\tt 1} if {\tt mtx} has real entries and {\tt 0} otherwise. \item {\tt SUBMTX\_IS\_COMPLEX(mtx)} is {\tt 1} if {\tt mtx} has complex entries and {\tt 0} otherwise. \item {\tt SUBMTX\_IS\_DENSE\_ROWS(mtx)} is {\tt 1} if {\tt mtx} has dense rows as its storage format, and {\tt 0} otherwise. \item {\tt SUBMTX\_IS\_DENSE\_COLUMNS(mtx)} is {\tt 1} if {\tt mtx} has dense columns as its storage format, and {\tt 0} otherwise. \item {\tt SUBMTX\_IS\_SPARSE\_ROWS(mtx)} is {\tt 1} if {\tt mtx} has sparse rows as its storage format, and {\tt 0} otherwise. \item {\tt SUBMTX\_IS\_SPARSE\_COLUMNS(mtx)} is {\tt 1} if {\tt mtx} has sparse columns as its storage format, and {\tt 0} otherwise. \item {\tt SUBMTX\_IS\_SPARSE\_TRIPLES(mtx)} is {\tt 1} if {\tt mtx} has sparse triples as its storage format, {\tt 0} otherwise. \item {\tt SUBMTX\_IS\_DENSE\_SUBROWS(mtx)} is {\tt 1} if {\tt mtx} has dense subrows as its storage format, {\tt 0} otherwise. \item {\tt SUBMTX\_IS\_DENSE\_SUBCOLUMNS(mtx)} is {\tt 1} if {\tt mtx} has dense subcolumns as its storage format, {\tt 0} otherwise. \item {\tt SUBMTX\_IS\_DIAGONAL(mtx)} is {\tt 1} if {\tt mtx} is diagonal, {\tt 0} otherwise. \item {\tt SUBMTX\_IS\_BLOCK\_DIAGONAL\_SYM(mtx)} is {\tt 1} if {\tt mtx} is block diagonal and symmetric, {\tt 0} otherwise. \item {\tt SUBMTX\_IS\_BLOCK\_DIAGONAL\_HERM(mtx)} is {\tt 1} if {\tt mtx} is block diagonal and hermitian, {\tt 0} otherwise. \end{itemize} times 2$ blocks. \end{itemize} \item {\tt int rowid} : object's row id, default value is {\tt -1}. \item {\tt int colid} : object's column id, default value is {\tt -1}. \item {\tt int nrow} : number of rows \item {\tt int ncol} : number of columns \item {\tt int nent} : number of stored matrix entries. \item {\tt DV wrkDV} : object that manages the owned workSubMtx/doc/intro.tex010064400020550007177000000115210653410625300157410ustar00clevecompmath00000400000006\par \chapter{{\tt SubMtx}: Submatrix object} \par The {\tt SubMtx} object was created to hold the data for and operate with a submatrix of a sparse matrix. The entries in a submatrix can be either double precision real or complex. \par For example, the lower and upper triangular matrices $L$ and $U$ that are created during the factorization are stored as submatrices, e.g., $L_{I,I}$ and $L_{J,I}$ where $I$ and $J$ are index sets. To be more precise, $I$ and $J$ are index sets associated with fronts {\tt I} and {\tt J}. We do not necessarily represent $L_{J,I}$, because some of the rows in the submatrix may be zero. Instead we keep $L_{\bnd{I}\cap J,I}$, where $\bnd{I} \cap J$ are precisely those rows that may have nonzeros. The situation is similar for $U$ where we keep $U_{I,\bnd{I}\cap J}$. \par The submatrices for $L$ and $U$ may be dense or sparse. (A direct factorization typically generates dense submatrices while a drop tolerance factorization produces sparse submatrices.) We also use {\tt SubMtx} objects to represent submatrices of the $D$ matrix, where $D$ is either diagonal or has $1 \times 1$ and $2 \times 2$ blocks on its diagonal. In the latter case, we support $D_{I,I}$ to be either real symmetric, complex symmetric or complex Hermitian. \par The {\tt SubMtx} object has the following attributes. \begin{itemize} \item A {\tt SubMtx} object has a row id and column id to identify itself within the context of a larger block matrix. \item Each row and column of the block matrix corresponds to a certain index set. A {\tt SubMtx} object associated with block row {\tt J} and block column {I} has row indices $J$ and column indices $I$. \item Matrix entries stored in one of the following ways. \begin{itemize} \item dense by rows, i.e., dense and row major \item dense by columns, i.e., dense and column major \item sparse using dense subrows \item sparse using dense subcolumns \item sparse using sparse rows \item sparse using sparse columns \item sparse using $(i,j,a_{i,j})$ triples \item a diagonal matrix \item a block diagonal symmetric matrix where the blocks are $1 \times 1$ or $2 \times 2$, used in the symmetric indefinite factorization. \item a block diagonal Hermitian matrix where the blocks are $1 \times 1$ or $2 \times 2$, used in the hermitian indefinite factorization. \end{itemize} \item The {\tt SubMtx} object can be self-contained, in the sense that its structure contains a {\tt DV} object that manages a contiguous vector of workspace that is used to store all information about the {\tt SubMtx} object --- its scalar parameters, any integer index or dimension information, and all matrix entries. In a distributed environment, this allows a {\tt SubMtx} object to be sent between processors as one message, no copying to an internal buffer is needed, nor any custom data type needs to be defined as for MPI. In an out-of-core environment, a {\tt SubMtx} object can be read from or written to a file by a single operation. \end{itemize} \par The {\tt SubMtx} object is a superset of the {\tt DenseMtx} object in terms of data structure and functionality. If we were working in a language that supports inheritance, {\tt SubMtx} would be an abstract class and {\tt DenseMtx} would be a subclass where entries would be stored by dense rows or columns. At some point in the future we may deprecate the {\tt DenseMtx} object in this library, replacing it with the {\tt SubMtx} object. \par Because the {\tt SubMtx} object wears so many hats, i.e., it supports nine different storage formats, it has to be flexible in how it responds to its environment. For example, how we access the data is different depending on which storage format. Instead of accessing structure fields directly, e.g., let {\tt mtx->entries} point to the start of the matrix entries, we follow a convention that {\it instance} methods return information. For example, the function call \begin{verbatim} SubMtx_columnIndices(mtx, &nrow, &rowind) ; \end{verbatim} is an instance method that fills {\tt nrow} with the number of rows and {\tt rowind} with the first location of the row indices. A more complex example is for the sparse storage by rows format, \begin{verbatim} SubMtx_sparseRowsInfo(mtx, &nrow, &nent, &sizes, &indices, &entries) ; \end{verbatim} where the number of rows and entries are returned in {\tt nrow} and {\tt nent}, the number of nonzero entries in each row is contained in {\tt sizes[]}, and the column indices and nonzero entries are found in {\tt indices[]} and {\tt entries[]}, respectively. This convention of using instance methods to return information is better than using explicit structure fields. For example, if we want to extend the object by allowing another storage format, we do not need to increase the size of the structure at all --- it is only necessary to provide one or more instance methods to return the new information. SubMtx/doc/main.tex010064400020550007177000000011570665065631200155430ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \newcommand{\bnd}{{\partial}} \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt SubMtx} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt SubMtx} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} SubMtx/doc/proto.tex010064400020550007177000001154650661215127300157640ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt SubMtx} methods} \label{section:SubMtx:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt SubMtx} object. \par \subsection{Basic methods} \label{subsection:SubMtx:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} SubMtx * SubMtx_new ( void ) ; \end{verbatim} \index{SubMtx_new@{\tt SubMtx\_new()}} This method simply allocates storage for the {\tt SubMtx} structure and then sets the default fields by a call to {\tt SubMtx\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_setDefaultFields ( SubMtx *mtx ) ; \end{verbatim} \index{SubMtx_setDefaultFields@{\tt SubMtx\_setDefaultFields()}} The structure's fields are set to default values: {\tt type} = {\tt SPOOLES\_REAL}, {\tt mode} = {\tt DENSEMTX\_DENSE\_COLUMNS}, {\tt rowid} = {\tt colid} = {\tt -1}, {\tt type} = {\tt nrow} = {\tt ncol} = {\tt nent} = 0 and {\tt next} = {\tt NULL} . The {\tt wrkDV} object has its default fields set via a call to {\tt DV\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_clearData ( SubMtx *mtx ) ; \end{verbatim} \index{SubMtx_clearData@{\tt SubMtx\_clearData()}} This method clears the object and free's any owned data by invoking the {\tt \_clearData()} methods for its internal {\tt DV} object. There is a concluding call to {\tt SubMtx\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_free ( SubMtx *mtx ) ; \end{verbatim} \index{SubMtx_free@{\tt SubMtx\_free()}} This method releases any storage by a call to {\tt SubMtx\_clearData()} and then frees the space for {\tt mtx}. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:SubMtx:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_ids ( SubMtx *mtx, int *prowid, int *pcolid ) ; \end{verbatim} \index{SubMtx_ids@{\tt SubMtx\_ids()}} This method fills {\tt *prowid} with the row id and {\tt *pcolid} with the column id of the object. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt prowid} or {\tt pcolid} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_setIds ( SubMtx *mtx, int rowid, int colid ) ; \end{verbatim} \index{SubMtx_setIds@{\tt SubMtx\_setIds()}} This method sets the row and column id's of the matrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_dimensions ( SubMtx *mtx, int *pnrow, int *pncol, int *pnent ) ; \end{verbatim} \index{SubMtx_dimensions@{\tt SubMtx\_dimensions()}} This method fills {\tt *pnrow}, {\tt *pncol} and {\tt *pnent} with the number of rows, columns and matrix entries, respectively. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pnrow} or {\tt pncol} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_rowIndices ( SubMtx *mtx, int *pnrow, **prowind ) ; \end{verbatim} \index{SubMtx_rowIndices@{\tt SubMtx\_rowIndices()}} This method fills {\tt *pnrow} with the number of rows. If {\tt prowind} is not {\tt NULL}, {\tt *prowind} is filled with a pointer to the row indices. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt pnrow} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_columnIndices ( SubMtx *mtx, int *pncol, **colind ) ; \end{verbatim} \index{SubMtx_columnIndices@{\tt SubMtx\_columnIndices()}} This method fills {\tt *pncol} with the number of columns. If {\tt pcolind} is not {\tt NULL}, {\tt *pcolind} is filled with a pointer to the column indices. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pncol} or {\tt pcolind} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_denseInfo ( SubMtx *mtx, int *pnrow, int *pncol, int *pinc1, int *pinc2, double **pentries ) ; \end{verbatim} \index{SubMtx_denseInfo@{\tt SubMtx\_denseInfo()}} This method is used when the storage mode is dense rows or columns. It fills {\tt *pnrow} with the number of rows, {\tt *pncol} with the number of columns, {\tt *pinc1} with the row increment, {\tt *pinc2} with the column increment, and {\tt *pentries} with the base address of entries vector. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pnrow}, {\tt pncol}, {\tt pinc1}, {\tt pinc2} or {\tt pentries} is {\tt NULL}, or if the matrix type is not {\tt SUBMTX\_DENSE\_ROWS} or {\tt SUBMTX\_DENSE\_COLUMNS}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_sparseRowsInfo ( SubMtx *mtx, int *pnrow, int *pnent, int **psizes, int **pindices, double **pentries ) ; \end{verbatim} \index{SubMtx_sparseRowsInfo@{\tt SubMtx\_sparseRowsInfo()}} This method is used when the storage mode is sparse rows. It fills {\tt *pnrow} with the number of rows, {\tt *pnent} with the number of matrix entries, {\tt *psizes} with the base address of the {\tt sizes[nrow]} vector that contains the number of entries in each row, {\tt *indices} with the base address of the {\tt indices[nent]} vector that contains the column index for each entry, and {\tt *pentries} with the base address of {\tt entries[nent]} vector. The indices and entries for the rows are stored contiguously. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pnrow}, {\tt pnent}, {\tt psizes}, {\tt pindices} or {\tt pentries} is {\tt NULL}, or if the matrix type is not {\tt SUBMTX\_SPARSE\_ROWS}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_sparseColumnsInfo ( SubMtx *mtx, int *pncol, int *pnent, int **psizes, int **pindices, double **pentries ) ; \end{verbatim} \index{SubMtx_sparseColumnsInfo@{\tt SubMtx\_sparseColumnsInfo()}} This method is used when the storage mode is sparse columns. It fills {\tt *pncol} with the number of columns, {\tt *pnent} with the number of matrix entries, {\tt *psizes} with the base address of the {\tt sizes[ncol]} vector that contains the number of entries in each column, {\tt *indices} with the base address of the {\tt indices[nent]} vector that contains the row index for each entry, and {\tt *pentries} with the base address of {\tt entries[nent]} vector. The indices and entries for the columns are stored contiguously. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pncol}, {\tt pnent}, {\tt psizes}, {\tt pindices} or {\tt pentries} is {\tt NULL}, or if the matrix type is not {\tt SUBMTX\_SPARSE\_COLUMNS}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_sparseTriplesInfo ( SubMtx *mtx, int *pnent, int **prowids, int **pcolids, double **pentries ) ; \end{verbatim} \index{SubMtx_sparseTriplesInfo@{\tt SubMtx\_sparseTriplesInfo()}} This method is used when the storage mode is sparse triples. It fills {\tt *pnent} with the number of matrix entries, {\tt *prowids} with the base address of the {\tt rowids[nent]} vector that contains the row id of each entry, {\tt *pcolids} with the base address of the {\tt colids[nent]} vector that contains the column id of each entry, and {\tt *pentries} with the base address of {\tt entries[nent]} vector. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pnent}, {\tt prowids}, {\tt pcolids} or {\tt pentries} is {\tt NULL}, or if the matrix type is not {\tt SUBMTX\_SPARSE\_TRIPLES}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_denseSubrowsInfo ( SubMtx *mtx, int *pnrow, int *pnent, int **pfirstlocs, int **plastlocs, double **pentries ) ; \end{verbatim} \index{SubMtx_denseSubrowsInfo@{\tt SubMtx\_denseSubrowsInfo()}} This method is used when the storage mode is dense subrows. It fills {\tt *pnrow} with the number of rows, {\tt *pnent} with the number of matrix entries, {\tt *pfirstlocs} with the base address of the {\tt firstlocs[nrow]} vector, {\tt *plastlocs} with the base address of the {\tt lastlocs[nrow]} vector, and {\tt *pentries} with the base address of {\tt entries[nent]} vector. For row {\tt irow}, the nonzero entries are found in columns {\tt [firstlocs[irow],lastlocs[irow]]} when $\mbox{\tt firstlocs[irow]} \ge 0$ and $\mbox{\tt firstlocs[irow]} \le \mbox{\tt lastlocs[irow]}$. The entries for the rows are stored contiguously. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pnrow}, {\tt pnent}, {\tt pfirstlocs}, {\tt plastlocs} or {\tt pentries} is {\tt NULL}, or if the matrix type is not {\tt SUBMTX\_DENSE\_SUBROWS}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_denseSubcolumnsInfo ( SubMtx *mtx, int *pncol, int *pnent, int **pfirstlocs, int **plastlocs, double **pentries ) ; \end{verbatim} \index{SubMtx_denseSubcolumnsInfo@{\tt SubMtx\_denseSubcolumnsInfo()}} This method is used when the storage mode is dense subcolumns. It fills {\tt *pncol} with the number of columns, {\tt *pnent} with the number of matrix entries, {\tt *pfirstlocs} with the base address of the {\tt firstlocs[ncol]} vector, {\tt *plastlocs} with the base address of the {\tt lastlocs[ncol]} vector, and {\tt *pentries} with the base address of {\tt entries[nent]} vector. For column {\tt jcol}, the nonzero entries are found in rows {\tt [firstlocs[jcol],lastlocs[jcol]]} when $\mbox{\tt firstlocs[jcol]} \ge 0$ and $\mbox{\tt firstlocs[jcol]} \le \mbox{\tt lastlocs[jcol]}$. The entries for the columns are stored contiguously. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pnrow}, {\tt pnent}, {\tt pfirstlocs}, {\tt plastlocs} or {\tt pentries} is {\tt NULL}, or if the matrix type is not {\tt SUBMTX\_DENSE\_SUBCOLUMNS}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_diagonalInfo ( SubMtx *mtx, int *pncol, double **pentries ) ; \end{verbatim} \index{SubMtx_diagonalInfo@{\tt SubMtx\_diagonalInfo()}} This method is used when the storage mode is diagonal. It fills {\tt *pncol} with the number of columns and {\tt *pentries} with the base address of {\tt entries[]} vector. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pncol} or {\tt pentries} is {\tt NULL}, or if the matrix type is not {\tt SUBMTX\_DIAGONAL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_blockDiagonalInfo ( SubMtx *mtx, int *pncol, int *pnent, int **ppivotsizes, double **pentries ) ; \end{verbatim} \index{SubMtx_blockDiagonalInfo@{\tt SubMtx\_blockDiagonalInfo()}} This method is used when the storage mode is block diagonal. It fills {\tt *pncol} with the number of columns, {\tt *pnent} with the number of entries, {\tt *ppivotsizes} with the base address of the pivot sizes vector, and {\tt *pentries} with the base address of {\tt entries[]} vector. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pncol}, {\tt pnent}, {\tt ppivotsizes} or {\tt pentries} is {\tt NULL}, or if the matrix type is not {\tt SUBMTX\_BLOCK\_DIAGONAL\_SYM}, or {\tt SUBMTX\_BLOCK\_DIAGONAL\_HERM}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_realEntry ( SubMtx *mtx, int irow, int jcol, double *pValue ) ; \end{verbatim} \index{SubMtx_realEntry@{\tt SubMtx\_realEntry()}} This method fill {\tt *pValue} with the entry in row {\tt irow} and column{\tt jcol}. Note, {\tt irow} and {\tt jcol} are {\it local} indices, i.e., $0 \le \mbox{\tt irow} \le \mbox{\tt nrow}$ and $0 \le \mbox{\tt jcol} \le \mbox{\tt ncol}$. If the {\tt (irow,jcol)} entry is present, the return value is the offset from the start of the {\tt entries} vector. Otherwise, -1 is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt pValue} is {\tt NULL}, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_complexEntry ( SubMtx *mtx, int irow, int jcol, double *pReal, double *pImag ) ; \end{verbatim} \index{SubMtx_complexEntry@{\tt SubMtx\_complesEntry()}} This method fill {\tt *pReal} with the real part and {\tt *pImag} with the imaginary part of the the entry in row {\tt irow} and column{\tt jcol}. Note, {\tt irow} and {\tt jcol} are {\it local} indices, i.e., $0 \le \mbox{\tt irow} \le \mbox{\tt nrow}$ and $0 \le \mbox{\tt jcol} \le \mbox{\tt ncol}$. If the {\tt (irow,jcol)} entry is present, the return value is the offset from the start of the {\tt entries} vector. (The offset is in terms of complex entries, not double entries.) Otherwise, -1 is returned. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt pReal} or {\tt pImag} is {\tt NULL}, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_locationOfRealEntry ( SubMtx *mtx, int irow, int jcol, double **ppValue ) ; \end{verbatim} \index{SubMtx_locationOfRealEntry@{\tt SubMtx\_locationOfRealEntry()}} If the {\tt (irow,jcol)} entry is present, this method fills {\tt *ppValue} with a pointer to the entry in row {\tt irow} and column{\tt jcol}. Otherwise, {\tt *ppValue} is set to {\tt NULL}. Note, {\tt irow} and {\tt jcol} are {\it local} indices, i.e., $0 \le \mbox{\tt irow} \le \mbox{\tt nrow}$ and $0 \le \mbox{\tt jcol} \le \mbox{\tt ncol}$. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt ppValue} is {\tt NULL}, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_locationOfComplexEntry ( SubMtx *mtx, int irow, int jcol, double **ppReal, double **ppImag ) ; \end{verbatim} \index{SubMtx_locationOfComplexEntry@{\tt SubMtx\_locationOfComplexEntry()}} If the {\tt (irow,jcol)} entry is present, this method fills {\tt *ppReal} with a pointer to the real part and {\tt *ppImag} with a pointer to the imaginary part of the the entry in row {\tt irow} and column{\tt jcol}. Otherwise, {\tt *ppImag} and {\tt *ppReal} are set to {\tt NULL}. Note, {\tt irow} and {\tt jcol} are {\it local} indices, i.e., $0 \le \mbox{\tt irow} \le \mbox{\tt nrow}$ and $0 \le \mbox{\tt jcol} \le \mbox{\tt ncol}$. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt ppReal} or {\tt ppImag} is {\tt NULL}, or if {\tt irow} or {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization methods} \label{subsection:SubMtx:proto:initial} \par There are three initializer methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_init( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent ) ; \end{verbatim} \index{SubMtx_init@{\tt SubMtx\_init()}} This is the initializer method used when the {\tt SubMtx} object is to use its workspace to store indices and entries. The number of bytes required in the workspace is computed, the workspace is resized if necessary, the scalar fields are set, and the row and column indices are set to {\tt [0,nrow)} and {\tt [0,ncol)}, respectively. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if {\tt nrow}, {\tt ncol}, {\tt inc1} or {\tt inc2} is less than or equal to zero, or if neither {\tt inc1} nor {\tt inc2} are {\tt 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_initFromBuffer ( SubMtx *mtx ) ; \end{verbatim} \index{SubMtx_initFromBuffer@{\tt SubMtx\_initFromBuffer()}} This method initializes the object using information present in the workspace buffer. This method is used to initialize the {\tt SubMtx} object when it has been received as an MPI message. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_initRandom ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent, int seed ) ; \end{verbatim} \index{SubMtx_initRandom@{\tt SubMtx\_initRandom()}} This is used to initialize an object to have random entries and (possibly) random structure. The object is first initialized via a call to {\tt SubMtx\_init()}. Its matrix entries are then filled with random numbers. If the matrix is sparse, its sparsity pattern is sparse and random, using {\tt nent} when applicable. The row and column indices are ascending starting from zero. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if {\tt nrow}, {\tt ncol}, {\tt inc1} or {\tt inc2} is less than or equal to zero, or if neither {\tt inc1} nor {\tt inc2} are {\tt 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_initRandomLowerTriangle ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent, int seed, int strict ) ; void SubMtx_initRandomUpperTriangle ( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent, int seed, int strict ) ; \end{verbatim} \index{SubMtx_initRandomLowerTriangle@{\tt SubMtx\_initRandomLowerTriangle()}} \index{SubMtx_initRandomUpperTriangle@{\tt SubMtx\_initRandomUpperTriangle()}} This is used to initialize an object to have random entries and (possibly) random structure. The matrix type may not be diagonal, block diagonal, or triples. If {\tt strict = 1}, the matrix will be strict lower or upper triangular. The object is first initialized via a call to {\tt SubMtx\_init()}. Its matrix entries are then filled with random numbers. If the matrix is sparse, its sparsity pattern is sparse and random, using {\tt nent} when applicable. The row and column indices are ascending starting from zero. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if {\tt nrow}, {\tt ncol}, {\tt inc1} or {\tt inc2} is less than or equal to zero, or if neither {\tt inc1} nor {\tt inc2} are {\tt 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Vector scaling methods} \label{subsection:SubMtx:proto:scale} \par These methods are used during the factorization when we compute products of the form $-U^TDU$, $-U^HDU$ and $-LDU$. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_scale1vec ( SubMtx *mtxD, double y0[], double x0[] ) ; void SubMtx_scale2vec ( SubMtx *mtxD, double y0[], double y1[], double x0[], double x1[] ) ; void SubMtx_scale3vec ( SubMtx *mtxD, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[] \end{verbatim} \index{SubMtx_scale1vec@{\tt SubMtx\_scale1vec()}} \index{SubMtx_scale2vec@{\tt SubMtx\_scale2vec()}} \index{SubMtx_scale3vec@{\tt SubMtx\_scale3vec()}} These methods compute one of the following $$ y_0 = D x_0, \qquad \left \lbrack \begin{array}{cc} y_0 & y_1 \end{array} \right \rbrack = D \left \lbrack \begin{array}{cc} x_0 & x_1 \end{array} \right \rbrack \qquad \mbox{or} \qquad \left \lbrack \begin{array}{ccc} y_0 & y_1 & y2 \end{array} \right \rbrack = D \left \lbrack \begin{array}{ccc} x_0 & x_1 & x2 \end{array} \right \rbrack $$ where $D$ is stored in the {\tt SubMtx} object {\tt mtxD}, and the $y_0$, $y_1$, $y_2$, $x_0$, $x_1$ and $x_2$ vectors are stored as simple real or complex vectors. This method is only used when {\tt mtxD} is diagonal or block diagonal (symmetric or Hermitian). \par \noindent {\it Error checking:} If {\tt mtxD}, {\tt y0}, {\tt y1}, {\tt y2}, {\tt x0}, {\tt x1} or {\tt x2} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Solve methods} \label{subsection:SubMtx:proto:solve} \par These methods are used during the forward and backward solves. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_solve ( SubMtx *mtxA, SubMtx *mtxB ) ; \end{verbatim} \index{SubMtx_solve@{\tt SubMtx\_solve()}} This method is used to solve $(I + A)X = B$ (if $A$ is strict lower or upper triangular) or $AX = B$ (if $A$ is diagonal or block diagonal). The solution $X$ overwrites $B$, and {\tt mtxB} must have dense columns. If $A$ is strict lower triangular, then {\tt mtxA} must have dense subrows or sparse rows. If $A$ is strict upper triangular, then {\tt mtxA} must have dense subcolumns or sparse columns. \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_solveH ( SubMtx *mtxA, SubMtx *mtxB ) ; \end{verbatim} \index{SubMtx_solveH@{\tt SubMtx\_solveH()}} This method is used to solve $(I + A^H)X = B$, where $A$ is strict lower or upper triangular. The solution $X$ overwrites $B$, and {\tt mtxB} must have dense columns. If $A$ is strict lower triangular, then {\tt mtxA} must have dense subrows or sparse rows. If $A$ is strict upper triangular, then {\tt mtxA} must have dense subcolumns or sparse columns. \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_solveT ( SubMtx *mtxA, SubMtx *mtxB ) ; \end{verbatim} \index{SubMtx_solveT@{\tt SubMtx\_solveT()}} This method is used to solve $(I + A^T)X = B$, where $A$ is strict lower or upper triangular. The solution $X$ overwrites $B$, and {\tt mtxB} must have dense columns. If $A$ is strict lower triangular, then {\tt mtxA} must have dense subrows or sparse rows. If $A$ is strict upper triangular, then {\tt mtxA} must have dense subcolumns or sparse columns. \par \noindent {\it Error checking:} If {\tt mtxA} or {\tt mtxB} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_solveupd ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; \end{verbatim} \index{SubMtx_solveupd@{\tt SubMtx\_solveupd()}} This method is used to update $Y := Y - A * X$, where $A$ has dense or sparse rows or columns. {\tt mtxY} and {\tt mtxX} must have dense columns. \par \noindent {\it Error checking:} If {\tt mtxY}, {\tt mtxA} or {\tt mtxX} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_solveupdH ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; \end{verbatim} \index{SubMtx_solveupdH@{\tt SubMtx\_solveupdH()}} This method is used to update $Y := Y - A^H * X$, where $A$ has dense or sparse rows or columns. {\tt mtxY} and {\tt mtxX} must have dense columns. \par \noindent {\it Error checking:} If {\tt mtxY}, {\tt mtxA} or {\tt mtxX} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_solveupdT ( SubMtx *mtxY, SubMtx *mtxA, SubMtx *mtxX ) ; \end{verbatim} \index{SubMtx_solveupdT@{\tt SubMtx\_solveupdT()}} This method is used to update $Y := Y - A^T * X$, where $A$ has dense or sparse rows or columns. {\tt mtxY} and {\tt mtxX} must have dense columns. \par \noindent {\it Error checking:} If {\tt mtxY}, {\tt mtxA} or {\tt mtxX} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:SubMtx:proto:utility} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_nbytesNeeded ( int type, int mode, int nrow, int ncol, int nent ) ; \end{verbatim} \index{SubMtx_nbytesNeeded@{\tt SubMtx\_nbytesNeeded()}} \par This method returns the number of bytes required to store the object's information in its buffer. \par \noindent {\it Error checking:} If {\tt nrow} or {\tt ncol} is less than or equal to zero, or if {\tt nent} is less than to zero, or if {\tt type} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_nbytesInUse ( SubMtx *mtx ) ; \end{verbatim} \index{SubMtx_nbytesInUse@{\tt SubMtx\_nbytesInUse()}} \par This method returns the actual number of bytes that are used in the workspace owned by this object. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_nbytesInWorkspace ( SubMtx *mtx ) ; \end{verbatim} \index{SubMtx_nbytesInWorkspace@{\tt SubMtx\_nbytesInWorkspace()}} \par This method returns the number of bytes in the workspace owned by this object. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_setNbytesInWorkspace ( SubMtx *mtx, int nbytes ) ; \end{verbatim} \index{SubMtx_setNbytesInWorkspace@{\tt SubMtx\_setNbytesInWorkspace()}} \par This method sets the number of bytes in the workspace of this object. If {\tt nbytes} is less than the present number of bytes, the workspace is not resized. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void * SubMtx_workspace ( SubMtx *mtx ) ; \end{verbatim} \index{SubMtx_workspace@{\tt SubMtx\_workspace()}} This method returns a pointer to the base address of the workspace. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_setFields( SubMtx *mtx, int type, int mode, int rowid, int colid, int nrow, int ncol, int nent ) ; \end{verbatim} \index{SubMtx_setFields@{\tt SubMtx\_setFields()}} This method sets the scalar fields. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, or if {\tt nrow}, {\tt ncol}, {\tt nent} is less than or equal to zero, or if {\tt type} or {\tt mode} is invalid, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_sortRowsUp ( SubMtx *mtx ) ; \end{verbatim} \index{SubMtx_sortRowsUp@{\tt SubMtx\_sortRowsUp()}} This method sort the rows so the row ids are in ascending order. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_sortColumnsUp ( SubMtx *mtx ) ; \end{verbatim} \index{SubMtx_sortColumnsUp@{\tt SubMtx\_sortColumnsUp()}} This method sort the rows so the column ids are in ascending order. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_fillRowDV ( SubMtx *mtx, int irow, DV *rowDV ) ; \end{verbatim} \index{SubMtx_fillRowDV@{\tt SubMtx\_fillRowDV()}} This method is used for real submatrices. It copies the entries in row {\tt irow} of the {\tt mtx} object into the {\tt rowDV} vector object. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt rowDV} is {\tt NULL}, or if {\tt irow} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_fillColumnDV ( SubMtx *mtx, int jcol, DV *rowDV ) ; \end{verbatim} \index{SubMtx_fillColumnDV@{\tt SubMtx\_fillColumnDV()}} This method is used for real submatrices. It copies the entries in column {\tt jcol} of the {\tt mtx} object into the {\tt colDV} vector object. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt colDV} is {\tt NULL}, or if {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_fillRowZV ( SubMtx *mtx, int irow, ZV *rowZV ) ; \end{verbatim} \index{SubMtx_fillRowZV@{\tt SubMtx\_fillRowZV()}} This method is used for complex submatrices. It copies the entries in row {\tt irow} of the {\tt mtx} object into the {\tt rowZV} vector object. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt rowZV} is {\tt NULL}, or if {\tt irow} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_fillColumnZV ( SubMtx *mtx, int jcol, ZV *rowZV ) ; \end{verbatim} \index{SubMtx_fillColumnZV@{\tt SubMtx\_fillColumnZV()}} This method is used for complex submatrices. It copies the entries in column {\tt jcol} of the {\tt mtx} object into the {\tt colZV} vector object. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt colZV} is {\tt NULL}, or if {\tt jcol} is out of range, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double SubMtx_maxabs ( SubMtx *mtx ) ; \end{verbatim} \index{SubMtx_maxabs@{\tt SubMtx\_maxabs()}} This method returns the magnitude of the element in the matrix with the largest magnitude. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_zero ( SubMtx *mtx ) ; \end{verbatim} \index{SubMtx_zero@{\tt SubMtx\_zero()}} This method zeros the entries of the submatrix. \par \noindent {\it Error checking:} If {\tt mtx} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:SubMtx:proto:IO} \par The file structure of a {\tt SubMtx} object is exactly that of its internal workspace buffer. See the source code for more details. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_readFromFile ( SubMtx *mtx, char *fn ) ; \end{verbatim} \index{SubMtx_readFromFile@{\tt SubMtx\_readFromFile()}} \par This method reads a {\tt SubMtx} object from a file. It tries to open the file and if it is successful, it then calls {\tt SubMtx\_readFromFormattedFile()} or {\tt SubMtx\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.mtxf} (for a formatted file) or {\tt *.mtxb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_readFromFormattedFile ( SubMtx *mtx, FILE *fp ) ; \end{verbatim} \index{SubMtx_readFromFormattedFile@{\tt SubMtx\_readFromFormattedFile()}} \par This method reads in a {\tt SubMtx} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. Note, if the mtxutation vectors are one-based (as for Fortran), they are converted to zero-based vectors. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_readFromBinaryFile ( SubMtx *mtx, FILE *fp ) ; \end{verbatim} \index{SubMtx_readFromBinaryFile@{\tt SubMtx\_readFromBinaryFile()}} \par This method reads in a {\tt SubMtx} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. Note, if the mtxutation vectors are one-based (as for Fortran), they are converted to zero-based vectors. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_writeToFile ( SubMtx *mtx, char *fn ) ; \end{verbatim} \index{SubMtx_writeToFile@{\tt SubMtx\_writeToFile()}} \par This method writes a {\tt SubMtx} object to a file. It tries to open the file and if it is successful, it then calls {\tt SubMtx\_writeFromFormattedFile()} or {\tt SubMtx\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.mtxf} (for a formatted file) or {\tt *.mtxb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_writeToFormattedFile ( SubMtx *mtx, FILE *fp ) ; \end{verbatim} \index{SubMtx_writeToFormattedFile@{\tt SubMtx\_writeToFormattedFile()}} \par This method writes out a {\tt SubMtx} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_writeToBinaryFile ( SubMtx *mtx, FILE *fp ) ; \end{verbatim} \index{SubMtx_writeToBinaryFile@{\tt SubMtx\_writeToBinaryFile()}} \par This method writes out a {\tt SubMtx} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_writeForHumanEye ( SubMtx *mtx, FILE *fp ) ; \end{verbatim} \index{SubMtx_writeForHumanEye@{\tt SubMtx\_writeForHumanEye()}} \par This method writes out a {\tt SubMtx} object to a file in a human readable format. The method {\tt SubMtx\_writeStats()} is called to write out the header and statistics. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtx_writeStats ( SubMtx *mtx, FILE *fp ) ; \end{verbatim} \index{SubMtx_writeStats@{\tt SubMtx\_writeStats()}} \par This method writes out a header and statistics to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt mtx} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtx_writeForMatlab ( SubMtx *mtx, char *mtxname, FILE *fp ) ; \end{verbatim} \index{SubMtx_writeForMatlab@{\tt SubMtx\_writeForMatlab()}} \par This method writes out a {\tt SubMtx} object to a file in a Matlab format. A sample line is \begin{verbatim} a(10,5) = -1.550328201511e-01 + 1.848033378871e+00*i ; \end{verbatim} for complex matrices, or \begin{verbatim} a(10,5) = -1.550328201511e-01 ; \end{verbatim} for real matrices, where mtxname = {\tt "a"}. The matrix indices come from the {\tt rowind[]} and {\tt colind[]} vectors, and are incremented by one to follow the Matlab and FORTRAN convention. \par \noindent {\it Error checking:} If {\tt mtx}, {\tt mtxname} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} checking:} If {\tt mtx} is {\tt NULL}, or if {\tt nrow}, {\tt ncol}, {\tt nent} is less than or equal to zero, or if {\tt type} or {\tt mode} is invalid, an error message is printed and the program exitSubMtx/doc/main.log010064400020550007177000000162720653634366500155370ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 6 JUN 1998 15:50 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) (/usr/local/lib/texmf/tex/generic/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen100 \p@intvaluey=\dimen101 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 2. [1 ]) (dataStructure.tex [2] [3]) (proto.tex Overfull \hbox (47.69849pt too wide) in paragraph at lines 32--40 []\elvrm The struc-ture's fields are set to de-fault val-ues: \elvtt type \elvr m = \elvtt SPOOLES[]REAL\elvrm , \elvtt mode \elvrm = \elvtt DENSEMTX[]DENSE[]C OLUMNS\elvrm , \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\elvrm T .\elvrm h .\elvrm e .\glue 3.65 plus 1.825 minus 1.21666 .etc. [4] Overfull \hbox (6.01772pt too wide) in paragraph at lines 147--147 [] \elvtt int **psizes, int **pindices, double **pen tries ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\penalty 10000 .\glue 5.74869 .\penalty 10000 .etc. Overfull \hbox (0.26903pt too wide) in paragraph at lines 169--169 [] \elvtt int **psizes, int **pindices, double **pent ries ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\penalty 10000 .\glue 5.74869 .\penalty 10000 .etc. [5] [6] Overfull \hbox (9.03377pt too wide) in paragraph at lines 268--274 \elvit Error check-ing: \elvrm If \elvtt mtx\elvrm , \elvtt pncol \elvrm or \el vtt pentries \elvrm is \elvtt NULL\elvrm , or if the ma-trix type is not \elvtt SUBMTX[]DIAGONAL\elvrm , \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\elvit E .\elvit r .\elvit r .\kern-0.55968 .\elvit o .etc. [7] Overfull \hbox (11.7664pt too wide) in paragraph at lines 416--416 [] []\elvtt void SubMtx_initRandom ( SubMtx *mtx, int type, int mode, int rowi d, int colid,[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. Overfull \hbox (11.7664pt too wide) in paragraph at lines 438--438 [] \elvtt int rowid, int colid, int nrow, int ncol, int nent, int seed, int strict ) ;[] \hbox(7.60416+1.52081)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\penalty 10000 .\glue 5.74869 .\penalty 10000 .etc. Overfull \hbox (11.7664pt too wide) in paragraph at lines 438--438 [] \elvtt int rowid, int colid, int nrow, int ncol, int nent, int seed, int strict ) ;[] \hbox(7.60416+1.52081)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\penalty 10000 .\glue 5.74869 .\penalty 10000 .etc. [8] [9] Overfull \hbox (6.01772pt too wide) in paragraph at lines 621--621 [] []\elvtt int SubMtx_nbytesNeeded ( int type, int mode, int nrow, int ncol, int nent ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. [10] [11] [12]) (drivers.tex [13] Overfull \hbox (42.63402pt too wide) in paragraph at lines 26--31 \elvtt *.submtxf \elvrm or \elvtt *.submtxb\elvrm . The \elvtt SubMtx \elvrm ob -ject is read from the file via the \elvtt SubMtx[]readFromFile() \hbox(7.60416+2.12917)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt s .\elvtt u .\elvtt b .etc. Overfull \hbox (38.37576pt too wide) in paragraph at lines 31--35 \elvtt *.submtxf \elvrm or \elvtt *.submtxb\elvrm . The \elvtt SubMtx \elvrm ob -ject is writ-ten to the file via the \elvtt SubMtx[]writeToFile() \hbox(7.60416+2.12917)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt s .\elvtt u .\elvtt b .etc. Overfull \hbox (11.1399pt too wide) in paragraph at lines 60--65 [] []\elvrm The \elvtt mode \elvrm pa-ram-e-ter must be one of 7 (\elvtt SUBMTX []DIAGONAL\elvrm ), 8 (\elvtt SUBMTX[]BLOCK[]DIAGONAL[]SYM\elvrm ) \hbox(8.2125+2.73749)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm T .etc. [14] Overfull \hbox (8.43288pt too wide) in paragraph at lines 97--106 [] []\elvrm The \elvtt mode \elvrm pa-ram-e-ter must be one of 2 (\elvtt SUBMTX []SPARSE[]ROWS\elvrm ), 3 (\elvtt SUBMTX[]SPARSE[]COLUMNS\elvrm ), \hbox(8.2125+2.73749)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm T .etc. Overfull \hbox (8.43288pt too wide) in paragraph at lines 142--148 [] []\elvrm The \elvtt mode \elvrm pa-ram-e-ter must be one of 2 (\elvtt SUBMTX []SPARSE[]ROWS\elvrm ), 3 (\elvtt SUBMTX[]SPARSE[]COLUMNS\elvrm ), \hbox(8.2125+2.73749)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm T .etc. [15] Overfull \hbox (8.43288pt too wide) in paragraph at lines 185--191 [] []\elvrm The \elvtt mode \elvrm pa-ram-e-ter must be one of 2 (\elvtt SUBMTX []SPARSE[]ROWS\elvrm ), 3 (\elvtt SUBMTX[]SPARSE[]COLUMNS\elvrm ), \hbox(8.2125+2.73749)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm T .etc. [16] [17]) (main.ind [18] [19 ]) (main.aux) ) Here is how much of TeX's memory you used: 428 strings out of 11977 4401 string characters out of 87269 39119 words of memory out of 262141 2360 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 14i,6n,17p,183b,260s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (19 pages, 65852 bytes). SubMtx/doc/main.idx010064400020550007177000000072320653634366500155360ustar00clevecompmath00000400000006\indexentry{SubMtx_new@{\tt SubMtx\_new()}}{4} \indexentry{SubMtx_setDefaultFields@{\tt SubMtx\_setDefaultFields()}}{4} \indexentry{SubMtx_clearData@{\tt SubMtx\_clearData()}}{4} \indexentry{SubMtx_free@{\tt SubMtx\_free()}}{4} \indexentry{SubMtx_ids@{\tt SubMtx\_ids()}}{5} \indexentry{SubMtx_dimensions@{\tt SubMtx\_dimensions()}}{5} \indexentry{SubMtx_rowIndices@{\tt SubMtx\_rowIndices()}}{5} \indexentry{SubMtx_columnIndices@{\tt SubMtx\_columnIndices()}}{5} \indexentry{SubMtx_denseInfo@{\tt SubMtx\_denseInfo()}}{5} \indexentry{SubMtx_sparseRowsInfo@{\tt SubMtx\_sparseRowsInfo()}}{5} \indexentry{SubMtx_sparseColumnsInfo@{\tt SubMtx\_sparseColumnsInfo()}}{6} \indexentry{SubMtx_sparseTriplesInfo@{\tt SubMtx\_sparseTriplesInfo()}}{6} \indexentry{SubMtx_denseSubrowsInfo@{\tt SubMtx\_denseSubrowsInfo()}}{6} \indexentry{SubMtx_denseSubcolumnsInfo@{\tt SubMtx\_denseSubcolumnsInfo()}}{6} \indexentry{SubMtx_diagonalInfo@{\tt SubMtx\_diagonalInfo()}}{7} \indexentry{SubMtx_blockDiagonalInfo@{\tt SubMtx\_blockDiagonalInfo()}}{7} \indexentry{SubMtx_realEntry@{\tt SubMtx\_realEntry()}}{7} \indexentry{SubMtx_complexEntry@{\tt SubMtx\_complesEntry()}}{7} \indexentry{SubMtx_locationOfRealEntry@{\tt SubMtx\_locationOfRealEntry()}}{7} \indexentry{SubMtx_locationOfComplexEntry@{\tt SubMtx\_locationOfComplexEntry()}}{8} \indexentry{SubMtx_init@{\tt SubMtx\_init()}}{8} \indexentry{SubMtx_initFromBuffer@{\tt SubMtx\_initFromBuffer()}}{8} \indexentry{SubMtx_initRandom@{\tt SubMtx\_initRandom()}}{8} \indexentry{SubMtx_initRandomLowerTriangle@{\tt SubMtx\_initRandomLowerTriangle()}}{8} \indexentry{SubMtx_initRandomUpperTriangle@{\tt SubMtx\_initRandomUpperTriangle()}}{8} \indexentry{SubMtx_scale1vec@{\tt SubMtx\_scale1vec()}}{9} \indexentry{SubMtx_scale2vec@{\tt SubMtx\_scale2vec()}}{9} \indexentry{SubMtx_scale3vec@{\tt SubMtx\_scale3vec()}}{9} \indexentry{SubMtx_solve@{\tt SubMtx\_solve()}}{9} \indexentry{SubMtx_solveH@{\tt SubMtx\_solveH()}}{9} \indexentry{SubMtx_solveT@{\tt SubMtx\_solveT()}}{10} \indexentry{SubMtx_solveupd@{\tt SubMtx\_solveupd()}}{10} \indexentry{SubMtx_solveupdH@{\tt SubMtx\_solveupdH()}}{10} \indexentry{SubMtx_solveupdT@{\tt SubMtx\_solveupdT()}}{10} \indexentry{SubMtx_nbytesNeeded@{\tt SubMtx\_nbytesNeeded()}}{10} \indexentry{SubMtx_nbytesInUse@{\tt SubMtx\_nbytesInUse()}}{10} \indexentry{SubMtx_nbytesInWorkspace@{\tt SubMtx\_nbytesInWorkspace()}}{10} \indexentry{SubMtx_setNbytesInWorkspace@{\tt SubMtx\_setNbytesInWorkspace()}}{11} \indexentry{SubMtx_workspace@{\tt SubMtx\_workspace()}}{11} \indexentry{SubMtx_setFields@{\tt SubMtx\_setFields()}}{11} \indexentry{SubMtx_sortRowsUp@{\tt SubMtx\_sortRowsUp()}}{11} \indexentry{SubMtx_sortColumnsUp@{\tt SubMtx\_sortColumnsUp()}}{11} \indexentry{SubMtx_fillRowDV@{\tt SubMtx\_fillRowDV()}}{11} \indexentry{SubMtx_fillColumnDV@{\tt SubMtx\_fillColumnDV()}}{11} \indexentry{SubMtx_fillRowZV@{\tt SubMtx\_fillRowZV()}}{11} \indexentry{SubMtx_fillColumnZV@{\tt SubMtx\_fillColumnZV()}}{12} \indexentry{SubMtx_maxabs@{\tt SubMtx\_maxabs()}}{12} \indexentry{SubMtx_zero@{\tt SubMtx\_zero()}}{12} \indexentry{SubMtx_readFromFile@{\tt SubMtx\_readFromFile()}}{12} \indexentry{SubMtx_readFromFormattedFile@{\tt SubMtx\_readFromFormattedFile()}}{12} \indexentry{SubMtx_readFromBinaryFile@{\tt SubMtx\_readFromBinaryFile()}}{12} \indexentry{SubMtx_writeToFile@{\tt SubMtx\_writeToFile()}}{12} \indexentry{SubMtx_writeToFormattedFile@{\tt SubMtx\_writeToFormattedFile()}}{13} \indexentry{SubMtx_writeToBinaryFile@{\tt SubMtx\_writeToBinaryFile()}}{13} \indexentry{SubMtx_writeForHumanEye@{\tt SubMtx\_writeForHumanEye()}}{13} \indexentry{SubMtx_writeStats@{\tt SubMtx\_writeStats()}}{13} \indexentry{SubMtx_writeForMatlab@{\tt SubMtx\_writeForMatlab()}}{13} SubMtx\_clearData()}}{4} \indexentry{SubMtx_free@{\tt SubMtx\_free()}}{4} \indexentry{SubMtx_ids@{\tt SubMtx\_ids()}}{5} \indexentry{SubMtx_dimensions@{\tt SubMtx\_dimensions()}}{5} \indexentry{SubMtx_rowIndices@{\tt SubMtx\_rowIndices()}}{5} \indexentry{SubMtx_columnIndices@{\tt SubMtx\_columnIndices()}}{5} \indexentry{SubMtx_denseInfo@{\tt SubMtx\_denseISubMtx/doc/main.aux010064400020550007177000000036260653634366500155520ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space SubMtx}: Submatrix object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{2}} \newlabel{section:SubMtx:dataStructure}{{1.1}{2}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space SubMtx} methods}{4}} \newlabel{section:SubMtx:proto}{{1.2}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{4}} \newlabel{subsection:SubMtx:proto:basics}{{1.2.1}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Instance methods}{5}} \newlabel{subsection:SubMtx:proto:instance}{{1.2.2}{5}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Initialization methods}{8}} \newlabel{subsection:SubMtx:proto:initial}{{1.2.3}{8}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}Vector scaling methods}{9}} \newlabel{subsection:SubMtx:proto:scale}{{1.2.4}{9}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.5}Solve methods}{9}} \newlabel{subsection:SubMtx:proto:solve}{{1.2.5}{9}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.6}Utility methods}{10}} \newlabel{subsection:SubMtx:proto:utility}{{1.2.6}{10}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.7}IO methods}{12}} \newlabel{subsection:SubMtx:proto:IO}{{1.2.7}{12}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs for the {\string\ptt\space SubMtx object}}{14}} \newlabel{section:SubMtx:drivers}{{1.3}{14}} SubMtx/doc/main.ind010064400020550007177000000044500653634366100155170ustar00clevecompmath00000400000006\begin{theindex} \item {\tt SubMtx\_blockDiagonalInfo()}, 7 \item {\tt SubMtx\_clearData()}, 4 \item {\tt SubMtx\_columnIndices()}, 5 \item {\tt SubMtx\_complesEntry()}, 7 \item {\tt SubMtx\_denseInfo()}, 5 \item {\tt SubMtx\_denseSubcolumnsInfo()}, 6 \item {\tt SubMtx\_denseSubrowsInfo()}, 6 \item {\tt SubMtx\_diagonalInfo()}, 7 \item {\tt SubMtx\_dimensions()}, 5 \item {\tt SubMtx\_fillColumnDV()}, 11 \item {\tt SubMtx\_fillColumnZV()}, 12 \item {\tt SubMtx\_fillRowDV()}, 11 \item {\tt SubMtx\_fillRowZV()}, 11 \item {\tt SubMtx\_free()}, 4 \item {\tt SubMtx\_ids()}, 5 \item {\tt SubMtx\_init()}, 8 \item {\tt SubMtx\_initFromBuffer()}, 8 \item {\tt SubMtx\_initRandom()}, 8 \item {\tt SubMtx\_initRandomLowerTriangle()}, 8 \item {\tt SubMtx\_initRandomUpperTriangle()}, 8 \item {\tt SubMtx\_locationOfComplexEntry()}, 8 \item {\tt SubMtx\_locationOfRealEntry()}, 7 \item {\tt SubMtx\_maxabs()}, 12 \item {\tt SubMtx\_nbytesInUse()}, 10 \item {\tt SubMtx\_nbytesInWorkspace()}, 10 \item {\tt SubMtx\_nbytesNeeded()}, 10 \item {\tt SubMtx\_new()}, 4 \item {\tt SubMtx\_readFromBinaryFile()}, 12 \item {\tt SubMtx\_readFromFile()}, 12 \item {\tt SubMtx\_readFromFormattedFile()}, 12 \item {\tt SubMtx\_realEntry()}, 7 \item {\tt SubMtx\_rowIndices()}, 5 \item {\tt SubMtx\_scale1vec()}, 9 \item {\tt SubMtx\_scale2vec()}, 9 \item {\tt SubMtx\_scale3vec()}, 9 \item {\tt SubMtx\_setDefaultFields()}, 4 \item {\tt SubMtx\_setFields()}, 11 \item {\tt SubMtx\_setNbytesInWorkspace()}, 11 \item {\tt SubMtx\_solve()}, 9 \item {\tt SubMtx\_solveH()}, 9 \item {\tt SubMtx\_solveT()}, 10 \item {\tt SubMtx\_solveupd()}, 10 \item {\tt SubMtx\_solveupdH()}, 10 \item {\tt SubMtx\_solveupdT()}, 10 \item {\tt SubMtx\_sortColumnsUp()}, 11 \item {\tt SubMtx\_sortRowsUp()}, 11 \item {\tt SubMtx\_sparseColumnsInfo()}, 6 \item {\tt SubMtx\_sparseRowsInfo()}, 5 \item {\tt SubMtx\_sparseTriplesInfo()}, 6 \item {\tt SubMtx\_workspace()}, 11 \item {\tt SubMtx\_writeForHumanEye()}, 13 \item {\tt SubMtx\_writeForMatlab()}, 13 \item {\tt SubMtx\_writeStats()}, 13 \item {\tt SubMtx\_writeToBinaryFile()}, 13 \item {\tt SubMtx\_writeToFile()}, 12 \item {\tt SubMtx\_writeToFormattedFile()}, 13 \item {\tt SubMtx\_zero()}, 12 \end{theindex} SubMtx/doc/main.ilg010064400020550007177000000004570653634366100155230ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (57 entries accepted, 0 rejected). Sorting entries....done (339 comparisons). Generating output file main.ind....done (61 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. SubMtx/doc/makefile010064400020550007177000000000270654276751400155770ustar00clevecompmath00000400000006clean : - rm -f *.dvi SubMtx/doc/drivers.tex010064400020550007177000000325500653627022700162760ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt SubMtx object}} \label{section:SubMtx:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program reads in a {\tt SubMtx} object from {\tt inFile} and writes out the object to {\tt outFile} \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt SubMtx} object is written to the message file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the input file for the {\tt SubMtx} object. It must be of the form {\tt *.submtxf} or {\tt *.submtxb}. The {\tt SubMtx} object is read from the file via the {\tt SubMtx\_readFromFile()} method. \item The {\tt outFile} parameter is the output file for the {\tt SubMtx} object. It must be of the form {\tt *.submtxf} or {\tt *.submtxb}. The {\tt SubMtx} object is written to the file via the {\tt SubMtx\_writeToFile()} method. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_scalevec msglvl msgFile type mode nrowA seed \end{verbatim} This driver program tests the {\tt SubMtx\_scalevec\{1,2,3\}()} methods. Use the script file {\tt do\_scalevec} for testing. When the output file is loaded into matlab, the last lines to the screen contain the errors. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter must be one of 1 ({\tt SPOOLES\_REAL}) or 2 ({\tt SPOOLES\_COMPLEX}). \item The {\tt mode} parameter must be one of 7 ({\tt SUBMTX\_DIAGONAL}), 8 ({\tt SUBMTX\_BLOCK\_DIAGONAL\_SYM}) or 9 ({\tt SUBMTX\_BLOCK\_DIAGONAL\_HERM}). \item The {\tt nrowA} parameter is the number of rows in the matrix. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_solve msglvl msgFile type mode nrowA nentA ncolB seed \end{verbatim} This driver program tests the {\tt SubMtx\_solve()} method which tests the solve $AX = B$ when $A$ is diagonal or block diagonal, and $(I + A)X = B$ otherwise ($A$ is strict upper or lower triangular). Use the script file {\tt do\_solve} for testing. When the output file is loaded into matlab, the last lines to the screen contain the errors. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter must be one of 1 ({\tt SPOOLES\_REAL}) or 2 ({\tt SPOOLES\_COMPLEX}). \item The {\tt mode} parameter must be one of 2 ({\tt SUBMTX\_SPARSE\_ROWS}), 3 ({\tt SUBMTX\_SPARSE\_COLUMNS}), 5 ({\tt SUBMTX\_DENSE\_SUBROWS}), 6 ({\tt SUBMTX\_DENSE\_SUBCOLUMNS}), 7 ({\tt SUBMTX\_DIAGONAL}), \break 8 ({\tt SUBMTX\_BLOCK\_DIAGONAL\_SYM}) or 9 ({\tt SUBMTX\_BLOCK\_DIAGONAL\_HERM}). \item The {\tt nrowA} parameter is the number of rows in the matrix. \item The {\tt nentA} parameter is the number of nonzero entries in the submatrix, when appropriate. \item The {\tt ncolB} parameter is the number of columns in $B$. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_solveH msglvl msgFile type mode nrowA nentA ncolB seed \end{verbatim} This driver program tests the {\tt SubMtx\_solve()} method which tests the solve $(I + A^H)X = B$ when $A$ is strict upper or lower triangular and has dense subrows, dense subcolumns, sparse rows, or sparse columns. Use the script file {\tt do\_solveH} for testing. When the output file is loaded into matlab, the last lines to the screen contain the errors. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter must be 2 ({\tt SPOOLES\_COMPLEX}). \item The {\tt mode} parameter must be one of 2 ({\tt SUBMTX\_SPARSE\_ROWS}), 3 ({\tt SUBMTX\_SPARSE\_COLUMNS}), 5 ({\tt SUBMTX\_DENSE\_SUBROWS}) or 6 ({\tt SUBMTX\_DENSE\_SUBCOLUMNS}). \item The {\tt nrowA} parameter is the number of rows in the matrix. \item The {\tt nentA} parameter is the number of nonzero entries in the submatrix, when appropriate. \item The {\tt ncolB} parameter is the number of columns in $B$. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_solveT msglvl msgFile type mode nrowA nentA ncolB seed \end{verbatim} This driver program tests the {\tt SubMtx\_solve()} method which tests the solve $(I + A^T)X = B$ when $A$ is strict upper or lower triangular and has dense subrows, dense subcolumns, sparse rows, or sparse columns. Use the script file {\tt do\_solveT} for testing. When the output file is loaded into matlab, the last lines to the screen contain the errors. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter must be one of 1 ({\tt SPOOLES\_REAL}) or 2 ({\tt SPOOLES\_COMPLEX}). \item The {\tt mode} parameter must be one of 2 ({\tt SUBMTX\_SPARSE\_ROWS}), 3 ({\tt SUBMTX\_SPARSE\_COLUMNS}), 5 ({\tt SUBMTX\_DENSE\_SUBROWS}) or 6 ({\tt SUBMTX\_DENSE\_SUBCOLUMNS}). \item The {\tt nrowA} parameter is the number of rows in the matrix. \item The {\tt nentA} parameter is the number of nonzero entries in the submatrix, when appropriate. \item The {\tt ncolB} parameter is the number of columns in $B$. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_solveupd msglvl msgFile type mode nrowA nentA ncolB seed \end{verbatim} This driver program tests the {\tt SubMtx\_solveupd()} method which tests the update $Y := Y - A * X$, used in the forward solve. $X$ and $Y$ have dense columns, and $A$ has dense rows or columns or sparse rows or columns. Use the script file {\tt do\_solveupd} for testing. When the output file is loaded into matlab, the last lines to the screen contain the errors. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter must be one of 1 ({\tt SPOOLES\_REAL}) or 2 ({\tt SPOOLES\_COMPLEX}). \item The {\tt mode} parameter must be one of 0 ({\tt SUBMTX\_DENSE\_ROWS}), 1 ({\tt SUBMTX\_DENSE\_COLUMNS}), 2 ({\tt SUBMTX\_SPARSE\_ROWS}) or 3 ({\tt SUBMTX\_SPARSE\_COLUMNS}). \item The {\tt nrowY} parameter is the number of rows in $Y$. \item The {\tt ncolY} parameter is the number of columns in $Y$. \item The {\tt nrowA} parameter is the number of rows in $A$, ${\tt nrowA} \le {\tt nrowY}$. \item The {\tt ncolA} parameter is the number of columns in $A$, ${\tt ncolA} \le {\tt nrowX}$. \item The {\tt nentA} parameter is the number of nonzero entries in the submatrix, when appropriate. \item The {\tt nrowX} parameter is the number of rows in $X$, ${\tt nrowA} \le {\tt nrowY}$. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_solveupdH msglvl msgFile type mode nrowA nentA ncolB seed \end{verbatim} This driver program tests the {\tt SubMtx\_solveupd()} method which tests the update $Y := Y - A^H * X$, used in the forward solve of a hermitian factorization. $X$ and $Y$ have dense columns, and $A$ has dense rows or columns or sparse rows or columns. Use the script file {\tt do\_solveupdH} for testing. When the output file is loaded into matlab, the last lines to the screen contain the errors. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter must be 2 ({\tt SPOOLES\_COMPLEX}). \item The {\tt mode} parameter must be one of 0 ({\tt SUBMTX\_DENSE\_ROWS}), 1 ({\tt SUBMTX\_DENSE\_COLUMNS}), 2 ({\tt SUBMTX\_SPARSE\_ROWS}) or 3 ({\tt SUBMTX\_SPARSE\_COLUMNS}). \item The {\tt nrowY} parameter is the number of rows in $Y$. \item The {\tt ncolY} parameter is the number of columns in $Y$. \item The {\tt nrowA} parameter is the number of rows in $A$, ${\tt nrowA} \le {\tt nrowY}$. \item The {\tt ncolA} parameter is the number of columns in $A$, ${\tt ncolA} \le {\tt nrowX}$. \item The {\tt nentA} parameter is the number of nonzero entries in the submatrix, when appropriate. \item The {\tt nrowX} parameter is the number of rows in $X$, ${\tt nrowA} \le {\tt nrowY}$. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_solveupdT msglvl msgFile type mode nrowA nentA ncolB seed \end{verbatim} This driver program tests the {\tt SubMtx\_solveupd()} method which tests the update $Y := Y - A^T * X$, used in the forward solve of a symmetric factorization. $X$ and $Y$ have dense columns, and $A$ has dense rows or columns or sparse rows or columns. Use the script file {\tt do\_solveupdT} for testing. When the output file is loaded into matlab, the last lines to the screen contain the errors. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter must be one of 1 ({\tt SPOOLES\_REAL}) or 2 ({\tt SPOOLES\_COMPLEX}). \item The {\tt mode} parameter must be one of 0 ({\tt SUBMTX\_DENSE\_ROWS}), 1 ({\tt SUBMTX\_DENSE\_COLUMNS}), 2 ({\tt SUBMTX\_SPARSE\_ROWS}) or 3 ({\tt SUBMTX\_SPARSE\_COLUMNS}). \item The {\tt nrowY} parameter is the number of rows in $Y$. \item The {\tt ncolY} parameter is the number of columns in $Y$. \item The {\tt nrowA} parameter is the number of rows in $A$, ${\tt nrowA} \le {\tt nrowY}$. \item The {\tt ncolA} parameter is the number of columns in $A$, ${\tt ncolA} \le {\tt nrowX}$. \item The {\tt nentA} parameter is the number of nonzero entries in the submatrix, when appropriate. \item The {\tt nrowX} parameter is the number of rows in $X$, ${\tt nrowA} \le {\tt nrowY}$. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_sort msglvl msgFile type mode nrowA ncolA nentA seed \end{verbatim} This driver program tests the {\tt SubMtx\_sortRowsUp()} and {\tt SubMtx\_sortColumnsUp()} methods. Use the script file {\tt do\_sort} for testing. When the output file is loaded into matlab, the last lines to the screen contain the errors. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter must be one of 1 ({\tt SPOOLES\_REAL}) or 2 ({\tt SPOOLES\_COMPLEX}). \item The {\tt mode} parameter must be one of 0 ({\tt SUBMTX\_DENSE\_ROWS}), 1 ({\tt SUBMTX\_DENSE\_COLUMNS}), 2 ({\tt SUBMTX\_SPARSE\_ROWS}) or 3 ({\tt SUBMTX\_SPARSE\_COLUMNS}). \item The {\tt nrowA} parameter is the number of rows in $A$. \item The {\tt ncolA} parameter is the number of columns in $A$. \item The {\tt nentA} parameter is the number of nonzero entries in the submatrix, when appropriate. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} ode} parameter must be one of 2 ({\tt SUBMTX\_SPARSE\_ROWS}), 3 ({\tt SUBMTX\_SPARSE\_COLUMNS}), 5 ({\tt SUBMTX\_DENSE\_SUBROWS}), 6 ({\tt SUBMTX\_DENSESubMtxList.h010064400020550007177000000001240653410641100143150ustar00clevecompmath00000400000006#ifndef _SubMtxList_ #define _SubMtxList_ #include "SubMtxList/SubMtxList.h" #endif SubMtxList/SubMtxList.h010064400020550007177000000132620653410625700164120ustar00clevecompmath00000400000006/* SubMtxList.h */ #include "../SubMtx.h" #include "../Lock.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- this object handles a list of lists of SubMtx objects nlist -- # of lists heads -- heads[ilist] contains a pointer to the first SubMtx object in list ilist counts -- when not-NULL, counts[ilist] contains the remaining number of objects to be added to list ilist before it is complete lock -- mutex object, can be NULL flags -- when not NULL, a vector to specify when a list needs to be locked before adding an object to it. flags[ilist] = 'N' --> no need to lock flags[ilist] = 'Y' --> must lock nlocks -- number of times the list was locked -------------------------------------------------------------------- */ typedef struct _SubMtxList SubMtxList ; struct _SubMtxList { int nlist ; SubMtx **heads ; int *counts ; Lock *lock ; char *flags ; int nlocks ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ SubMtxList * SubMtxList_new ( void ) ; /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void SubMtxList_setDefaultFields ( SubMtxList *list ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void SubMtxList_clearData ( SubMtxList *list ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ void SubMtxList_free ( SubMtxList *list ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- basic initializer nlist -- number of lists to be held by this object counts -- vector that contains number of items expected for each list. counts == NULL --> unknown number of items expected counts != NULL --> known number of items expected lockflag -- flag to specify lock status lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize only threads in this process. lockflag = 2 --> mutex lock is allocated and it can synchronize threads in this and other processes. flags -- vector to specify whether to lock individual lists flags == NULL --> none or all lists must be locked, use lockflag to determine flags[ilist] = 'N' --> no need to lock list ilist flags[ilist] = 'Y' --> must lock list ilist created -- 98may02, cca ------------------------------------------------------------------ */ void SubMtxList_init ( SubMtxList *list, int nlist, int counts[], int lockflag, char flags[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98may02, cca ---------------------------------------- */ void SubMtxList_writeForHumanEye ( SubMtxList *list, FILE *fp ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------- return 1 if list ilist is not empty return 0 if list ilist is empty created -- 98may02, cca ----------------------------------- */ int SubMtxList_isListNonempty ( SubMtxList *list, int ilist ) ; /* --------------------------------------------------------- return 1 if the count for list ilist is zero return 0 if the count for list ilist is greater than zero created -- 98may02, cca --------------------------------------------------------- */ int SubMtxList_isCountZero ( SubMtxList *list, int ilist ) ; /* ---------------------------- add and object to list ilist created -- 98may02, cca ---------------------------- */ void SubMtxList_addObjectToList ( SubMtxList *list, SubMtx *obj, int ilist ) ; /* ------------------------------------ return pointer to head of list ilist and set head to NULL created -- 98may02, cca ------------------------------------ */ SubMtx * SubMtxList_getList ( SubMtxList *list, int ilist ) ; /*--------------------------------------------------------------------*/ SubMtxList/makefile010064400020550007177000000001410663622367100156560ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean SubMtxList/src/makefile010064400020550007177000000007030663603042300164400ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SubMtxList $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG SubMtxList/src/makeGlobalLib010064400020550007177000000006000660026114100173360ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SubMtxList SRC = basics.c \ init.c \ IO.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a SubMtxList/src/IO.c010064400020550007177000000035060653410625700154250ustar00clevecompmath00000400000006/* IO.c */ #include "../SubMtxList.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98may02, cca ---------------------------------------- */ void SubMtxList_writeForHumanEye ( SubMtxList *list, FILE *fp ) { SubMtx *mtx ; int ilist ; /* --------------- check the input --------------- */ if ( list == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in SubMtxList_writeForHumanEye(%p,%p)" "\n bad input\n", list, fp) ; exit(-1) ; } fprintf(fp, "\n SubMtxList object at address %p" "\n %d lists, %d locks" "\n heads %p, counts %p, flags %p", list, list->nlist, list->nlocks, list->heads, list->counts, list->flags) ; for ( ilist = 0 ; ilist < list->nlist ; ilist++ ) { fprintf(fp, "\n list %d : ", ilist) ; if ( list->heads == NULL ) { fprintf(fp, " head NULL") ; } else { fprintf(fp, " head %p", list->heads[ilist]) ; } if ( list->counts == NULL ) { fprintf(fp, ", counts NULL") ; } else { fprintf(fp, ", counts %d", list->counts[ilist]) ; } if ( list->flags == NULL ) { fprintf(fp, ", flags NULL") ; } else { fprintf(fp, ", flags %c", list->flags[ilist]) ; } } for ( ilist = 0 ; ilist < list->nlist ; ilist++ ) { if ( (mtx = list->heads[ilist]) != NULL ) { fprintf(fp, "\n list %d :", ilist) ; while ( mtx != NULL ) { fprintf(fp, "\n mtx (%d,%d), nbytes %d", mtx->rowid, mtx->colid, SubMtx_nbytesInWorkspace(mtx)) ; mtx = mtx->next ; } } } return ; } /*--------------------------------------------------------------------*/ SubMtxList/src/basics.c010064400020550007177000000047730653410625700163710ustar00clevecompmath00000400000006/* basics.c */ #include "../SubMtxList.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ SubMtxList * SubMtxList_new ( void ) { SubMtxList *list ; ALLOCATE(list, struct _SubMtxList, 1) ; SubMtxList_setDefaultFields(list) ; return(list) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void SubMtxList_setDefaultFields ( SubMtxList *list ) { if ( list == NULL ) { fprintf(stderr, "\n fatal error in SubMtxList_setDefaultFields(%p)" "\n bad input", list) ; exit(-1) ; } list->nlist = 0 ; list->heads = NULL ; list->counts = NULL ; list->lock = NULL ; list->flags = NULL ; list->nlocks = 0 ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void SubMtxList_clearData ( SubMtxList *list ) { /* --------------- check the input --------------- */ if ( list == NULL ) { fprintf(stderr, "\n fatal error in SubMtxList_clearData(%p)" "\n bad input\n", list) ; exit(-1) ; } /* ------------- free the data ------------- */ if ( list->heads != NULL ) { FREE(list->heads) ; } if ( list->counts != NULL ) { IVfree(list->counts) ; } if ( list->flags != NULL ) { CVfree(list->flags) ; } if ( list->lock != NULL ) { /* ------------------------- destroy and free the lock ------------------------- */ Lock_free(list->lock) ; } /* ---------------------- set the default fields ---------------------- */ SubMtxList_setDefaultFields(list) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ void SubMtxList_free ( SubMtxList *list ) { if ( list == NULL ) { fprintf(stderr, "\n fatal error in SubMtxList_free(%p)" "\n bad input\n", list) ; exit(-1) ; } SubMtxList_clearData(list) ; FREE(list) ; return ; } /*--------------------------------------------------------------------*/ SubMtxList/src/init.c010064400020550007177000000053770653410625700160710ustar00clevecompmath00000400000006/* init.c */ #include "../SubMtxList.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- basic initializer nlist -- number of lists to be held by this object counts -- vector that contains number of items expected for each list. counts == NULL --> unknown number of items expected counts != NULL --> known number of items expected lockflag -- flag to specify lock status lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize only threads in this process. lockflag = 2 --> mutex lock is allocated and it can synchronize only threads in this and other processes. flags -- vector to specify whether to lock individual lists flags == NULL --> none or all lists must be locked, use lockflag to determine flags[ilist] = 'N' --> no need to lock list ilist flags[ilist] = 'Y' --> must lock list ilist created -- 98may02, cca ------------------------------------------------------------------ */ void SubMtxList_init ( SubMtxList *list, int nlist, int counts[], int lockflag, char flags[] ) { int ilist ; /* --------------- check the input --------------- */ if ( list == NULL || nlist <= 0 || lockflag < 0 || lockflag > 2 ) { fprintf(stderr, "\n fatal error in SubMtxList_init(%p,%d,%p,%d,%p)" "\n bad input\n", list, nlist, counts, lockflag, flags) ; exit(-1) ; } /* -------------- clear all data -------------- */ SubMtxList_clearData(list) ; /* ------------------------------------------------------- set the number of lists and allocate the heads[] vector ------------------------------------------------------- */ list->nlist = nlist ; ALLOCATE(list->heads, struct _SubMtx *, nlist) ; for ( ilist = 0 ; ilist < nlist ; ilist++ ) { list->heads[ilist] = NULL ; } if ( counts != NULL ) { /* ------------------------------------- allocate and fill the counts[] vector ------------------------------------- */ list->counts = IVinit(nlist, 0) ; IVcopy(nlist, list->counts, counts) ; } if ( lockflag > 0 ) { /* ----------------- allocate the lock ----------------- */ list->lock = Lock_new() ; Lock_init(list->lock, lockflag) ; } if ( flags != NULL ) { /* ------------------------------------ allocate and fill the flags[] vector ------------------------------------ */ list->flags = CVinit(nlist, 'N') ; CVcopy(nlist, list->flags, flags) ; } return ; } /*--------------------------------------------------------------------*/ nlist, int counts[], int lockflag, char flags[] ) { int ilist ; /* --------------- check the input --------------- */ if ( list == NULL || nlist <= 0 || lockflag < 0 || lockflag > 2 ) { fprintf(stderSubMtxList/src/util.c010064400020550007177000000116050653410625700160720ustar00clevecompmath00000400000006/* util.c */ #include "../SubMtxList.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------- return 1 if list ilist is not empty return 0 if list ilist is empty created -- 98may02, cca ----------------------------------- */ int SubMtxList_isListNonempty ( SubMtxList *list, int ilist ) { /* --------------- check the input --------------- */ if ( list == NULL || ilist < 0 || ilist >= list->nlist ) { fprintf(stderr, "\n fatal error in SubMtxList_isListNonempty(%p,%d)" "\n bad input\n", list, ilist) ; } return(list->heads[ilist] != NULL) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- return 1 if the count for list ilist is zero return 0 if the count for list ilist is greater than zero created -- 98may02, cca --------------------------------------------------------- */ int SubMtxList_isCountZero ( SubMtxList *list, int ilist ) { /* --------------- check the input --------------- */ if ( list == NULL || ilist < 0 || ilist >= list->nlist ) { fprintf(stderr, "\n fatal error in SubMtxList_isCountZero(%p,%d)" "\n bad input\n", list, ilist) ; } if ( list->counts == NULL ) { return(1) ; } else { return(list->counts[ilist] == 0) ; } } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- add an object to the list and decrement the count. note, an object can be NULL. created -- 98may02, cca -------------------------------------------------- */ void SubMtxList_addObjectToList ( SubMtxList *list, SubMtx *mtx, int ilist ) { /* --------------- check the input --------------- */ if ( list == NULL || ilist < 0 || ilist >= list->nlist ) { fprintf(stderr, "\n fatal error in SubMtxList_addObjectToList(%p,%p,%d)" "\n bad input\n", list, mtx, ilist) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n SubMtxList %p : adding mtx %p to list %d", list, mtx, ilist) ; fflush(stdout) ; #endif if ( list->lock != NULL && (list->flags == NULL || list->flags[ilist] == 'Y' ) ) { /* -------------------------------------------------- we must lock the list to (possibly) add the object and decrement the list's count -------------------------------------------------- */ Lock_lock(list->lock) ; if ( mtx != NULL ) { mtx->next = list->heads[ilist] ; list->heads[ilist] = mtx ; } if ( list->counts != NULL ) { list->counts[ilist]-- ; } list->nlocks++ ; Lock_unlock(list->lock) ; } else { /* --------------------------------------------- no need to lock the list, just (possibly) add the object and decrement the list's count --------------------------------------------- */ if ( mtx != NULL ) { mtx->next = list->heads[ilist] ; list->heads[ilist] = mtx ; } if ( list->counts != NULL ) { list->counts[ilist]-- ; } } #if MYDEBUG > 0 fprintf(stdout, "\n SubMtxList %p : heads[%d] = %p, counts[%d] = %d", list, ilist, list->heads[ilist], ilist, list->counts[ilist]) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ return pointer to head of list ilist and set head to NULL created -- 98may02, cca ------------------------------------ */ SubMtx * SubMtxList_getList ( SubMtxList *list, int ilist ) { SubMtx *mtx ; /* --------------- check the input --------------- */ if ( list == NULL || ilist < 0 || ilist >= list->nlist ) { fprintf(stderr, "\n fatal error in SubMtxList_getList(%p,%d)" "\n bad input\n", list, ilist) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n SubMtxList %p : get list %d", list, ilist) ; fflush(stdout) ; #endif if ( list->heads[ilist] != NULL ) { if ( list->lock == NULL || (list->flags != NULL && list->flags[ilist] == 'N') || (list->counts != NULL && list->counts[ilist] == 0) ) { /* ------------------------ no need to lock the list ------------------------ */ mtx = list->heads[ilist] ; list->heads[ilist] = NULL ; } else { /* ---------------------------------------------------- we must lock the list to return the head of the list ---------------------------------------------------- */ Lock_lock(list->lock) ; mtx = list->heads[ilist] ; list->heads[ilist] = NULL ; list->nlocks++ ; Lock_unlock(list->lock) ; } } else { mtx = NULL ; } #if MYDEBUG > 0 fprintf(stdout, "\n SubMtxList %p : mtx %p", list, mtx) ; fflush(stdout) ; #endif return(mtx) ; } /*--------------------------------------------------------------------*/ SubMtxList/doc/004275500020550007177000000000000654276751400147415ustar00clevecompmath00000400000006SubMtxList/doc/dataStructure.tex010064400020550007177000000013470653624253700203110ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:SubMtxList:dataStructure} \par \par The {\tt SubMtxList} structure has the following fields. \begin{itemize} \item {\tt int nlist} : number of lists. \item {\tt SubMtx **heads} : vector of pointers to the heads of the list of {\tt SubMtx} objects. \item {\tt int *counts} : vector of incoming counts for the lists. \item {\tt Lock *lock} : mutual exclusion lock. \item {\tt char *flags} : vector of lock flags for the lists. If {\tt flags[ilist] == 'N'}, the list does not need to be locked. If {\tt flags[ilist] == 'Y'}, the list does need to be locked. Used only when {\tt lock} is not {\tt NULL}. \item {\tt int nlocks} : total number of locks made on the mutual exclusion lock. \end{itemize} SubMtxList/doc/intro.tex010064400020550007177000000052660653624403100166050ustar00clevecompmath00000400000006\par \chapter{{\tt SubMtxList}: {\tt SubMtx} list object } \par This object was created to handle a list of lists of {\tt SubMtx} objects during a matrix solve. Its form and function is very close to the {\tt ChvList} object that handles lists of lists of {\tt Chv} objects during the factorization. \par Here are the main properties. \begin{enumerate} \item There are a fixed number of lists, set when the {\tt SubMtxList} object is initialized. \item For each list there is an expected count, the number of times an object will be added to the list. (Note, a {\tt NULL} object can be added to the list. In this case, nothing is added to the list, but its count is decremented.) \item There is one lock for all the lists, but each list can be flagged as necessary to lock or not necessary to lock before an insertion, count decrement, or an extraction is made to the list. \end{enumerate} \par The {\tt SubMtxList} object manages a number of lists that may require handling critical sections of code. For example, one thread may want to add an object to a particular list while another thread is removing objects. The critical sections are hidden inside the {\tt SubMtxList} object. Our solve code do not know about any mutual exclusion locks that govern access to the lists. \par There are four functions of the {\tt SubMtxList} object. \begin{itemize} \item Is the incoming count for a list nonzero? \item Is a list nonempty? \item Add an object to a list (possibly a {\tt NULL} object) and decrement the incoming count. \item Remove a subset of objects from a list. \end{itemize} The first two operations are queries, and can be done without locking the list. The third operation needs a lock only when two or more threads will be inserting objects into the list. The fourth operation requires a lock only when one thread will add an object while another thread removes the object and the incoming count is not yet zero. \par Having a lock associated with a {\tt SubMtxList} object is optional, for example, it is not needed during a serial factorization nor a MPI solve. In the latter case there is one {\tt SubMtxList} per process. For a multithreaded solve there is one {\tt SubMtxList} object that is shared by all threads. The mutual exclusion lock that is (optionally) embedded in the {\tt SubMtxList} object is a {\tt Lock} object from this library. It is inside the {\tt Lock} object that we have a mutual exclusion lock. Presently we support the Solaris and POSIX thread packages. Porting the multithreaded codes to another platform should be simple if the POSIX thread package is present. Another type of thread package will require some modifications to the {\tt Lock} object, but none to the {\tt SubMtxList} objects. \par SubMtxList/doc/main.aux010064400020550007177000000024260653624446600164020ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space SubMtxList}: {\string\ptt\space SubMtx} list object }{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{2}} \newlabel{section:SubMtxList:dataStructure}{{1.1}{2}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space SubMtxList} methods}{2}} \newlabel{section:SubMtxList:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:SubMtxList:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initialization methods}{3}} \newlabel{subsection:SubMtxList:proto:initial}{{1.2.2}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{3}} \newlabel{subsection:SubMtxList:proto:utility}{{1.2.3}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}IO methods}{4}} \newlabel{subsection:SubMtxList:proto:IO}{{1.2.4}{4}} SubMtxList/doc/main.idx010064400020550007177000000012600653624446600163640ustar00clevecompmath00000400000006\indexentry{SubMtxList_new@{\tt SubMtxList\_new()}}{2} \indexentry{SubMtxList_setDefaultFields@{\tt SubMtxList\_setDefaultFields()}}{2} \indexentry{SubMtxList_clearData@{\tt SubMtxList\_clearData()}}{3} \indexentry{SubMtxList_free@{\tt SubMtxList\_free()}}{3} \indexentry{SubMtxList_init@{\tt SubMtxList\_init()}}{3} \indexentry{SubMtxList_isListNonempty@{\tt SubMtxList\_isListNonempty()}}{3} \indexentry{SubMtxList_isCountZero@{\tt SubMtxList\_isCountZero()}}{3} \indexentry{SubMtxList_getList@{\tt SubMtxList\_getList()}}{4} \indexentry{SubMtxList_addObjectToList@{\tt SubMtxList\_addObjectToList()}}{4} \indexentry{SubMtxList_writeForHumanEye@{\tt SubMtxList\_writeForHumanEye()}}{4} SubMtxList/doc/main.ilg010064400020550007177000000004560653624263500163550ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (10 entries accepted, 0 rejected). Sorting entries....done (36 comparisons). Generating output file main.ind....done (14 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. SubMtxList/doc/main.ind010064400020550007177000000007050653624263500163510ustar00clevecompmath00000400000006\begin{theindex} \item {\tt SubMtxList\_addObjectToList()}, 4 \item {\tt SubMtxList\_clearData()}, 3 \item {\tt SubMtxList\_free()}, 3 \item {\tt SubMtxList\_getList()}, 4 \item {\tt SubMtxList\_init()}, 3 \item {\tt SubMtxList\_isCountZero()}, 3 \item {\tt SubMtxList\_isListNonempty()}, 3 \item {\tt SubMtxList\_new()}, 2 \item {\tt SubMtxList\_setDefaultFields()}, 2 \item {\tt SubMtxList\_writeForHumanEye()}, 4 \end{theindex} SubMtxList/doc/main.log010064400020550007177000000030620653624446600163630ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 6 JUN 1998 06:50 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) (/usr/local/lib/texmf/tex/generic/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen100 \p@intvaluey=\dimen101 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 2. LaTeX Warning: No \tt typeface in this size, using \rm on input line 2. [1 ]) (dataStructure.tex) (proto.tex [2] [3]) (main.ind [4] [5 ]) (main.aux) ) Here is how much of TeX's memory you used: 421 strings out of 11977 4283 string characters out of 87269 36819 words of memory out of 262141 2356 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,4n,17p,187b,199s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (5 pages, 11700 bytes). t=lplain 94.11.14) 6 JUN 1998 06:50 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/SubMtxList/doc/main.tex010064400020550007177000000011440665065631400163750ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \newcommand{\bnd}{{\partial}} \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt SubMtxList} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt SubMtxList} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} SubMtxList/doc/proto.tex010064400020550007177000000170410653624260300166120ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt SubMtxList} methods} \label{section:SubMtxList:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt SubMtxList} object. \par \subsection{Basic methods} \label{subsection:SubMtxList:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} SubMtxList * SubMtxList_new ( void ) ; \end{verbatim} \index{SubMtxList_new@{\tt SubMtxList\_new()}} This method simply allocates storage for the {\tt SubMtxList} structure and then sets the default fields by a call to {\tt SubMtxList\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxList_setDefaultFields ( SubMtxList *list ) ; \end{verbatim} \index{SubMtxList_setDefaultFields@{\tt SubMtxList\_setDefaultFields()}} The structure's fields are set to default values: {\tt nlist} and {\tt nlocks} set to zero, and {\tt heads}, {\tt counts}, {\tt lock} and {\tt flags} are set to {\tt NULL} . \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxList_clearData ( SubMtxList *list ) ; \end{verbatim} \index{SubMtxList_clearData@{\tt SubMtxList\_clearData()}} This method clears the object and free's any owned data by calling {\tt SubMtx\_free()} for each object on the free list. If {\tt heads} is not {\tt NULL}, it is free'd. If {\tt counts} is not {\tt NULL}, it is free'd via a call to {\tt IVfree()}. If {\tt flags} is not {\tt NULL}, it is free'd via a call to {\tt CVfree()}. If the lock is not {\tt NULL}, it is destroyed via a call to {\tt mutex\_destroy()} and then free'd. There is a concluding call to {\tt SubMtxList\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxList_free ( SubMtxList *list ) ; \end{verbatim} \index{SubMtxList_free@{\tt SubMtxList\_free()}} This method releases any storage by a call to {\tt SubMtxList\_clearData()} and then free the space for {\tt list}. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization methods} \label{subsection:SubMtxList:proto:initial} \par There are three initializer methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxList_init( SubMtxList *list, int nlist, int counts[], int lockflag, char flags[] ) ; \end{verbatim} \index{SubMtxList_init@{\tt SubMtxList\_init()}} Any data is cleared via a call to {\tt SubMtxList\_clearData()}. The number of lists is set and the {\tt heads[]} vector is initialized. If {\tt counts} is not {\tt NULL}, the object's {\tt counts[]} vector is allocated and filled with the incoming entries. If {\tt lockflag} is zero, the lock is not initialized. If {\tt lockflag} is {\tt 1}, the lock is initialized to be able to synchronize threads with the calling process. If {\tt lockflag} is {\tt 2}, the lock is initialized to be able to synchronize threads across processes. If {\tt flags} is not {\tt NULL}, the object's {\tt flags[]} vector is allocated and filled with the incoming entries. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, or if ${\tt nlist} \le 0$, or if {\tt lockflag} is not in {\tt [0,2]}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:SubMtxList:proto:utility} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtxList_isListNonempty ( SubMtxList *list, int ilist ) ; \end{verbatim} \index{SubMtxList_isListNonempty@{\tt SubMtxList\_isListNonempty()}} \par If list {\tt ilist} is empty, the method returns 0. Otherwise, the method returns 1. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, or if {\tt ilist} is not in the range {\tt [0,nlist)}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int SubMtxList_isCountZero ( SubMtxList *list, int ilist ) ; \end{verbatim} \index{SubMtxList_isCountZero@{\tt SubMtxList\_isCountZero()}} \par If {\tt counts} is {\tt NULL}, or if {\tt counts[ilist]} equal to zero, the method returns 1. Otherwise, the method returns 0. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, or if {\tt ilist} is not in the range {\tt [0,nlist)}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} SubMtx * SubMtxList_getList ( SubMtxList *list, int ilist ) ; \end{verbatim} \index{SubMtxList_getList@{\tt SubMtxList\_getList()}} \par If list {\tt ilist} is empty, the method returns {\tt NULL}. Otherwise, if the list needs to be locked, the lock is locked. The head of the list is saved to a pointer and then the head is set to {\tt NULL}. If the list was locked, the number of locks is incremented and the lock unlocked. The saved pointer is returned. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, or if {\tt ilist} is not in the range {\tt [0,nlist)}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxList_addObjectToList ( SubMtxList *list, SubMtx *mtx, int ilist ) ; \end{verbatim} \index{SubMtxList_addObjectToList@{\tt SubMtxList\_addObjectToList()}} \par If the list needs to be locked, the lock is locked. If {\tt mtx} is not {\tt NULL}, it is added to the head of the list. If {\tt counts} is not {\tt NULL}, then {\tt counts[ilist]} is decremented. If the lock was locked, the number of locks is incremented and it is now unlocked. \par \noindent {\it Error checking:} If {\tt list} is {\tt NULL}, or if {\tt ilist} is not in the range {\tt [0,nlist)}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:SubMtxList:proto:IO} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxList_writeForHumanEye ( SubMtxList *list, FILE *fp ) ; \end{verbatim} \index{SubMtxList_writeForHumanEye@{\tt SubMtxList\_writeForHumanEye()}} \par This method write the list to a file in user readable form. \par \noindent {\it Error checking:} If {\tt list} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} riptions of {\tt SubMtxList} methods} \label{section:SubMtxList:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt SubMtxList} object. \par \subsection{Basic methods} \label{subsection:SubMtxList:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %===================================================SubMtxList/doc/makefile010064400020550007177000000000270654276751400164330ustar00clevecompmath00000400000006clean : - rm -f *.dvi SubMtxManager.h010064400020550007177000000001400653410641100147520ustar00clevecompmath00000400000006#ifndef _SubMtxManager_ #define _SubMtxManager_ #include "SubMtxManager/SubMtxManager.h" #endif SubMtxManager/SubMtxManager.h010064400020550007177000000106420653410626000175010ustar00clevecompmath00000400000006/* SubMtxManager.h */ #include "../SubMtx.h" #include "../Lock.h" /*--------------------------------------------------------------------*/ /* */ typedef struct _SubMtxManager SubMtxManager ; struct _SubMtxManager { SubMtx *head ; Lock *lock ; int mode ; int nactive ; int nbytesactive ; int nbytesrequested ; int nbytesalloc ; int nrequests ; int nreleases ; int nlocks ; int nunlocks ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ SubMtxManager * SubMtxManager_new ( void ) ; /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void SubMtxManager_setDefaultFields ( SubMtxManager *manager ) ; /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void SubMtxManager_clearData ( SubMtxManager *manager ) ; /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ void SubMtxManager_free ( SubMtxManager *manager ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------------------------------------- simple initializer lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize omly threads in this process. lockflag = 2 --> mutex lock is allocated and it can synchronize omly threads in this and other processes. mode = 0 --> free object and storage on release mode = 1 --> recycle object and storage on release created -- 98may02, cca --------------------------------------------------------------- */ void SubMtxManager_init ( SubMtxManager *manager, int lockflag, int mode ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------------- return a pointer to a SubMtx object that has been initialized with the input parameters created -- 98may02, cca ----------------------------------------------- */ SubMtx * SubMtxManager_newObjectOfSizeNbytes ( SubMtxManager *manager, int nbytesNeeded ) ; /* ---------------------------- release a SubMtx instance created -- 98may02, cca ---------------------------- */ void SubMtxManager_releaseObject ( SubMtxManager *manager, SubMtx *mtx ) ; /* ----------------------------------- release a list of SubMtx objects created -- 98may02, cca ----------------------------------- */ void SubMtxManager_releaseListOfObjects ( SubMtxManager *manager, SubMtx *head ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98may02, cca ---------------------------------------- */ void SubMtxManager_writeForHumanEye ( SubMtxManager *manager, FILE *fp ) ; /*--------------------------------------------------------------------*/ SubMtxManager/makefile010064400020550007177000000001410663622367200163160ustar00clevecompmath00000400000006all_drivers : lib : cd src ; make makeLib clean : cd src ; make clean cd doc ; make clean SubMtxManager/src/makefile010064400020550007177000000007060663603044500171060ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SubMtxManager $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG SubMtxManager/src/makeGlobalLib010064400020550007177000000006030660026114500200040ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SubMtxManager SRC = basics.c \ init.c \ IO.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a SubMtxManager/src/IO.c010064400020550007177000000025670653625571600161010ustar00clevecompmath00000400000006/* IO.c */ #include "../SubMtxManager.h" /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to write the object to a file in human readable form created -- 98may02, cca ---------------------------------------- */ void SubMtxManager_writeForHumanEye ( SubMtxManager *manager, FILE *fp ) { SubMtx *mtx ; /* --------------- check the input --------------- */ if ( manager == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in SubMtxManager_writeForHumanEye(%p,%p)" "\n bad input\n", manager, fp) ; exit(-1) ; } fprintf(fp, "\n\n SubMtxManager object at address %p" "\n %d active objects, %d bytes active" "\n %d total bytes requested, %d total bytes allocated " "\n %d requests, %d releases, %d locks, %d unlocks", manager, manager->nactive, manager->nbytesactive, manager->nbytesrequested, manager->nbytesalloc, manager->nrequests, manager->nreleases, manager->nlocks, manager->nunlocks) ; /* for ( mtx = manager->head ; mtx != NULL ; mtx = mtx->next ) { fprintf(fp, "\n mtx (%d,%d), nbytes %d", mtx->rowid, mtx->colid, SubMtx_nbytesInWorkspace(mtx)) ; } */ return ; } /*--------------------------------------------------------------------*/ SubMtxManager/src/basics.c010064400020550007177000000055000653625473500170240ustar00clevecompmath00000400000006/* basics.c */ #include "../SubMtxManager.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 98may02, cca ----------------------- */ SubMtxManager * SubMtxManager_new ( void ) { SubMtxManager *manager ; ALLOCATE(manager, struct _SubMtxManager, 1) ; SubMtxManager_setDefaultFields(manager) ; return(manager) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98may02, cca ----------------------- */ void SubMtxManager_setDefaultFields ( SubMtxManager *manager ) { if ( manager == NULL ) { fprintf(stderr, "\n fatal error in SubMtxManager_setDefaultFields(%p)" "\n bad input", manager) ; exit(-1) ; } manager->head = NULL ; manager->lock = NULL ; manager->mode = 0 ; manager->nactive = 0 ; manager->nbytesactive = 0 ; manager->nbytesrequested = 0 ; manager->nbytesalloc = 0 ; manager->nrequests = 0 ; manager->nreleases = 0 ; manager->nlocks = 0 ; manager->nunlocks = 0 ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- clear the data fields, releasing allocated storage created -- 98may02, cca -------------------------------------------------- */ void SubMtxManager_clearData ( SubMtxManager *manager ) { SubMtx *mtx ; /* --------------- check the input --------------- */ if ( manager == NULL ) { fprintf(stderr, "\n fatal error in SubMtxManager_clearData(%p)" "\n bad input\n", manager) ; exit(-1) ; } /* ------------------------ free the working storage ------------------------ */ while ( (mtx = manager->head) != NULL ) { manager->head = mtx->next ; SubMtx_free(mtx) ; } if ( manager->lock != NULL ) { /* ------------------------- destroy and free the lock ------------------------- */ Lock_free(manager->lock) ; } /* ---------------------- set the default fields ---------------------- */ SubMtxManager_setDefaultFields(manager) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ destructor, free's the object and its data created -- 98may02, cca ------------------------------------------ */ void SubMtxManager_free ( SubMtxManager *manager ) { if ( manager == NULL ) { fprintf(stderr, "\n fatal error in SubMtxManager_free(%p)" "\n bad input\n", manager) ; exit(-1) ; } SubMtxManager_clearData(manager) ; FREE(manager) ; return ; } /*--------------------------------------------------------------------*/ SubMtxManager/src/init.c010064400020550007177000000032660653625505200165230ustar00clevecompmath00000400000006/* init.c */ #include "../SubMtxManager.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- simple initializer lockflag = 0 --> mutex lock is not allocated or initialized lockflag = 1 --> mutex lock is allocated and it can synchronize omly threads in this process. lockflag = 2 --> mutex lock is allocated and it can synchronize omly threads in this and other processes. mode = 0 --> free object and storage on release mode = 1 --> recycle object and storage on release created -- 98may02, cca --------------------------------------------------------------- */ void SubMtxManager_init ( SubMtxManager *manager, int lockflag, int mode ) { /* --------------- check the input --------------- */ if ( manager == NULL || lockflag < 0 || lockflag > 2 || mode < 0 || mode > 1 ) { fprintf(stderr, "\n fatal error in SubMtxManager_init(%p,%d,%d)" "\n bad input\n", manager, lockflag, mode) ; exit(-1) ; } /* -------------------------------------------------- clear any previous data and set the default fields -------------------------------------------------- */ SubMtxManager_clearData(manager) ; if ( lockflag != 0 ) { /* --------------------------- initialize the mutex object --------------------------- */ manager->lock = Lock_new() ; Lock_init(manager->lock, lockflag) ; } /* ------------ set the mode ------------ */ manager->mode = mode ; return ; } /*--------------------------------------------------------------------*/ SubMtxManager/src/util.c010064400020550007177000000234340653625563300165410ustar00clevecompmath00000400000006/* util.c */ #include "../SubMtxManager.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------- return a pointer to a SubMtx object that has been initialized with the input parameters created -- 98may02, cca ----------------------------------------------- */ SubMtx * SubMtxManager_newObjectOfSizeNbytes ( SubMtxManager *manager, int nbytesNeeded ) { SubMtx *mtx, *prev ; int nbytesAvailable, newinstance ; /* --------------- check the input --------------- */ if ( manager == NULL || nbytesNeeded <= 0 ) { fprintf(stderr, "\n fatal error in SubMtxMananger_newObjectOfSizeNbytes(%p,%d)" "\n bad input\n", manager, nbytesNeeded) ; exit(-1) ; } #if MYDEBUG > 1 fprintf(stdout, "\n\n new mtx request, nbytes needed = %d", nbytesNeeded) ; fflush(stdout) ; #endif if ( manager->lock != NULL ) { /* ----------------------------------------------- lock the lock, get exclusive access to the list ----------------------------------------------- */ Lock_lock(manager->lock) ; #if MYDEBUG > 1 fprintf(stdout, "\n manager: lock is locked") ; fflush(stdout) ; #endif manager->nlocks++ ; #if MYDEBUG > 1 fprintf(stdout, "\n %d locks so far", manager->nlocks) ; fflush(stdout) ; #endif } /* --------------------------------------------------------- find a SubMtx object with the required number of bytes --------------------------------------------------------- */ for ( mtx = manager->head, prev = NULL ; mtx != NULL ; mtx = mtx->next ) { nbytesAvailable = SubMtx_nbytesInWorkspace(mtx) ; #if MYDEBUG > 1 fprintf(stdout, "\n free mtx %p, nbytes = %d", mtx, nbytesAvailable) ; fflush(stdout) ; #endif if ( nbytesNeeded <= nbytesAvailable ) { break ; } prev = mtx ; } if ( mtx != NULL ) { /* --------------------------------------- suitable object found, remove from list --------------------------------------- */ #if MYDEBUG > 1 fprintf(stdout, "\n mtx = %p, %d nbytes available", mtx, nbytesAvailable) ; fflush(stdout) ; #endif if ( prev == NULL ) { manager->head = mtx->next ; } else { prev->next = mtx->next ; } newinstance = 0 ; } else { /* ------------------------------------------------------------------ no suitable object found, create new instance and allocate storage ------------------------------------------------------------------ */ mtx = SubMtx_new() ; #if MYDEBUG > 1 fprintf(stdout, "\n no suitable object found, new mtx = %p, bytes = %d", mtx, nbytesNeeded) ; fflush(stdout) ; #endif newinstance = 1 ; DV_setSize(&mtx->wrkDV, nbytesNeeded/sizeof(double)) ; } if ( newinstance == 1 ) { manager->nbytesalloc += SubMtx_nbytesInWorkspace(mtx) ; } manager->nactive++ ; manager->nbytesactive += SubMtx_nbytesInWorkspace(mtx) ; manager->nbytesrequested += nbytesNeeded ; #if MYDEBUG > 1 fprintf(stdout, "\n %d bytes active, %d bytes requested", manager->nbytesactive, manager->nbytesrequested) ; #endif manager->nrequests++ ; if ( manager->lock != NULL ) { /* ----------------------------------------------------- unlock the lock, release exclusive access to the list ----------------------------------------------------- */ manager->nunlocks++ ; #if MYDEBUG > 1 fprintf(stdout, "\n manager: unlocking, %d unlocks so far", manager->nunlocks) ; fflush(stdout) ; #endif Lock_unlock(manager->lock) ; } return(mtx) ; } /*--------------------------------------------------------------------*/ /* ---------------------------- release a SubMtx instance created -- 98may02, cca ---------------------------- */ void SubMtxManager_releaseObject ( SubMtxManager *manager, SubMtx *mtx1 ) { SubMtx *mtx2, *prev ; int nbytes1, nbytes2 ; /* --------------- check the input --------------- */ if ( manager == NULL || mtx1 == NULL ) { fprintf(stderr, "\n fatal error in SubMtxManager_releaseObject(%p,%p)" "\n bad input\n", manager, mtx1) ; exit(-1) ; } if ( manager->lock != NULL ) { /* ----------------------------------------------- lock the lock, get exclusive access to the list ----------------------------------------------- */ Lock_lock(manager->lock) ; manager->nlocks++ ; #if MYDEBUG > 1 fprintf(stdout, "\n\n manager : locking in releaseObject, %d locks", manager->nlocks) ; fflush(stdout) ; #endif } manager->nreleases++ ; manager->nbytesactive -= SubMtx_nbytesInWorkspace(mtx1) ; manager->nactive-- ; if ( manager->mode == 0 ) { /* --------------- release storage --------------- */ SubMtx_free(mtx1) ; } else { /* -------------------------------------------------------- find a place in the list where the SubMtx objects are sorted in ascending order of the size of their workspace -------------------------------------------------------- */ nbytes1 = SubMtx_nbytesInWorkspace(mtx1) ; #if MYDEBUG > 1 fprintf(stdout, "\n\n trying to release mtx %p with %d bytes", mtx1, nbytes1) ; #endif for ( mtx2 = manager->head, prev = NULL ; mtx2 != NULL ; mtx2 = mtx2->next ) { nbytes2 = SubMtx_nbytesInWorkspace(mtx2) ; #if MYDEBUG > 1 fprintf(stdout, "\n list mtx %p with %d bytes", mtx2, nbytes2) ; #endif if ( nbytes2 >= nbytes1 ) { break ; } prev = mtx2 ; } if ( prev == NULL ) { manager->head = mtx1 ; #if MYDEBUG > 1 fprintf(stdout, "\n manager->head = %p", mtx1) ; #endif } else { prev->next = mtx1 ; #if MYDEBUG > 1 fprintf(stdout, "\n %p->next = %p", prev, mtx1) ; #endif } mtx1->next = mtx2 ; #if MYDEBUG > 1 fprintf(stdout, "\n %p->next = %p", mtx1, mtx2) ; #endif } if ( manager->lock != NULL ) { /* ----------------------------------------------------- unlock the lock, release exclusive access to the list ----------------------------------------------------- */ manager->nunlocks++ ; #if MYDEBUG > 1 fprintf(stdout, "\n manager : unlocking in releaseObject, %d unlocks", manager->nunlocks) ; fflush(stdout) ; #endif Lock_unlock(manager->lock) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- release a list of SubMtx objects created -- 98may02, cca ----------------------------------- */ void SubMtxManager_releaseListOfObjects ( SubMtxManager *manager, SubMtx *head ) { SubMtx *mtx1, *mtx2, *prev ; int nbytes1, nbytes2 ; /* --------------- check the input --------------- */ if ( manager == NULL || head == NULL ) { fprintf(stderr, "\n fatal error in SubMtxManager_releaseListOfObjects(%p,%p)" "\n bad input\n", manager, head) ; exit(-1) ; } if ( manager->lock != NULL ) { /* ----------------------------------------------- lock the lock, get exclusive access to the list ----------------------------------------------- */ Lock_lock(manager->lock) ; manager->nlocks++ ; #if MYDEBUG > 1 fprintf(stdout, "\n\n manager : locking in releaseListOfObjects, %d locks", manager->nlocks) ; fflush(stdout) ; #endif } if ( manager->mode == 0 ) { /* --------------- release storage --------------- */ while ( (mtx1 = head) != NULL ) { head = head->next ; manager->nbytesactive -= SubMtx_nbytesInWorkspace(mtx1) ; manager->nactive-- ; manager->nreleases++ ; SubMtx_free(mtx1) ; } } else { /* ------------------- recycle the objects ------------------- */ while ( head != NULL ) { mtx1 = head ; head = mtx1->next ; /* -------------------------------------------------------- find a place in the list where the SubMtx objects are sorted in ascending order of the size of their workspace -------------------------------------------------------- */ nbytes1 = SubMtx_nbytesInWorkspace(mtx1) ; #if MYDEBUG > 1 fprintf(stdout, "\n\n trying to release mtx %p with %d bytes", mtx1, nbytes1) ; #endif for ( mtx2 = manager->head, prev = NULL ; mtx2 != NULL ; mtx2 = mtx2->next ) { nbytes2 = SubMtx_nbytesInWorkspace(mtx2) ; #if MYDEBUG > 1 fprintf(stdout, "\n list mtx %p with %d bytes", mtx2, nbytes2) ; #endif if ( nbytes2 >= nbytes1 ) { break ; } prev = mtx2 ; } if ( prev == NULL ) { manager->head = mtx1 ; #if MYDEBUG > 1 fprintf(stdout, "\n manager->head = %p", mtx1) ; #endif } else { prev->next = mtx1 ; #if MYDEBUG > 1 fprintf(stdout, "\n %p->next = %p", prev, mtx1) ; #endif } mtx1->next = mtx2 ; #if MYDEBUG > 1 fprintf(stdout, "\n %p->next = %p", mtx1, mtx2) ; #endif manager->nbytesactive -= SubMtx_nbytesInWorkspace(mtx1) ; manager->nactive-- ; manager->nreleases++ ; #if MYDEBUG > 1 fprintf(stdout, "\n # releases = %d", manager->nreleases) ; for ( mtx1 = manager->head ; mtx1 != NULL ; mtx1 = mtx1->next ) { fprintf(stdout, "\n mtx (%d,%d), nbytes %d", mtx1->rowid, mtx1->colid, SubMtx_nbytesInWorkspace(mtx1)) ; } #endif } } if ( manager->lock != NULL ) { /* ----------------------------------------------------- unlock the lock, release exclusive access to the list ----------------------------------------------------- */ manager->nunlocks++ ; #if MYDEBUG > 1 fprintf(stdout, "\n manager : unlocking in releaseListOfObjects, %d unlocks", manager->nunlocks) ; fflush(stdout) ; #endif Lock_unlock(manager->lock) ; } return ; } /*--------------------------------------------------------------------*/ SubMtxManager/doc/004275500020550007177000000000000654276751400154005ustar00clevecompmath00000400000006SubMtxManager/doc/dataStructure.tex010064400020550007177000000022730653625024700207440ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:SubMtxManager:dataStructure} \par \par The {\tt SubMtxManager} structure has the following fields. \begin{itemize} \item {\tt SubMtx *head} : head of the free list of {\tt SubMtx} objects. \item {\tt Lock *lock} : mutual exclusion lock. \item {\tt int mode} : behavior mode. When {\tt mode = 0}, the object calls {\tt SubMtx\_new()} and {\tt SubMtx\_free()} to create and release objects. When {\tt mode = 1}, the object recycles the objects. \item {\tt int nactive} : number of active {\tt SubMtx} objects. \item {\tt int nbytesactive} : number of bytes in the active {\tt SubMtx} objects. \item {\tt int nbytesrequested} : total number of bytes in the requested {\tt SubMtx} objects. \item {\tt int nbytesalloc} : total number of bytes that were actually allocated in the workspace of the {\tt SubMtx} objects. \item {\tt int nrequests} : total number of requests for {\tt SubMtx} objects. \item {\tt int nreleases} : total number of releases of {\tt SubMtx} objects. \item {\tt int nlocks} : total number of locks made on the mutual exclusion lock. \item {\tt int nunlocks} : total number of unlocks made on the mutual exclusion lock. \end{itemize} SubMtxManager/doc/intro.tex010064400020550007177000000073350653625700600172510ustar00clevecompmath00000400000006\par \chapter{{\tt SubMtxManager}: {\tt SubMtx} object manager} \par This object was created to manage a number of instances of {\tt SubMtx} double precision matrix objects. Its form and functionality is almost identical to that of the {\tt ChvManager} object. \par % During the forward and backsolves of a linear system $A X = B$, % where the solution $X$ and the right hand side $B$ may be matrices % as opposed to a single vector, the multifrontal approach to solvng % the systems does not make much use of the global $X$ and $B$ data % structures. % Rather there are a number of smaller dense matrices, % e.g., $B_{J,*}$, $B_{\bnd{J},*}$ and $X_{J \cup \bnd{J},*}$, % where $J$ and $\bnd{J}$ are row index sets, % that are active during the solves. % \par % These temporary matrices reside in one address space, whether it be % a serial or multithreaded computation. % It is necessary to {\it recycle} the instances, i.e., when the % useful scope of one object is over, we can use the object for % another instance. % \par The {\tt SubMtxManager} object is very simple. It has two functions. \begin{itemize} \item When asked for a {\tt SubMtx} object of a certain size, it returns one. \item When given a {\tt SubMtx} object (or a list of objects connected via their {\tt next} fields) that is (are) no longer necessary for the calling program, it takes some action with it (them). \end{itemize} There are presently two {\it modes} of behavior : the first is a wrapper around calls to {\tt SubMtx\_new()} and {\tt SubMtx\_free()} (which contain calls to {\tt malloc()} and {\tt free()}), the second can {\it recycle} instances to be used later. \par Both behaviors are appropriate in certain circumstances. When one needs a large number of objects (though not all at the same time) whose workspace requirements are roughly equal, recycling the objects can be cost effective. On the other hand, consider a scenario which arises in the factorization of {\tt FrontMtx} objects. At first one needs a moderate number of large {\tt SubMtx} objects which store the $U_{J,\bnd{J}}$ and $L_{\bnd{J},J}$ submatrices. We then replace them with a larger number of smaller objects that store the $U_{J,K}$ and $L_{K,J}$ matrices. In this case recycling is {\it not} cost-effective for the large objects are recycled as smaller objects and much of their workspace is inactive and therefore wasted. The total storage footprint can be almost twice as large as necessary. \par Our recycling mode is a very simple implementation. The manager object maintains a free list of objects, sorting in ascending order of the number of bytes in their workspace. When asked for an object with a certain amount of workspace, the manager performs a linear search of the list and returns the first object that has sufficient space. If no such object exists, i.e., if the list is empty or there is no object large enough, the manager allocates a new {\tt SubMtx} object, initializes it with sufficient work space, and returns a pointer to the object. When a {\tt SubMtx} object is no longer necessary, it is {\it released} to the manager object, which then inserts it into the free list. A list of {\tt SubMtx} objects can be released in one call. \par One can specify whether the object is to be locked via a mutual exclusion lock. This is not necessary for a serial or MPI factorization or solve (where there is one {\tt SubMtxManager} object for each processor), but it is necessary for in a multithreaded environment. \par Each manager object keeps track of certain statistics, % e.g., the number of active {\tt SubMtx} objects, the number of bytes in their workspaces, the total number of bytes requested, the number of requests for a {\tt SubMtx} objects, the number of releases, and the number of locks and unlocks. SubMtxManager/doc/main.aux010064400020550007177000000024600653625067100170320ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space SubMtxManager}: {\string\ptt\space SubMtx} object manager}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{2}} \newlabel{section:SubMtxManager:dataStructure}{{1.1}{2}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space SubMtxManager} methods}{2}} \newlabel{section:SubMtxManager:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:SubMtxManager:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Initialization methods}{3}} \newlabel{subsection:SubMtxManager:proto:initial}{{1.2.2}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Utility methods}{3}} \newlabel{subsection:SubMtxManager:proto:utility}{{1.2.3}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}IO methods}{4}} \newlabel{subsection:SubMtxManager:proto:IO}{{1.2.4}{4}} SubMtxManager/doc/main.idx010064400020550007177000000013030653625067100170140ustar00clevecompmath00000400000006\indexentry{SubMtxManager_new@{\tt SubMtxManager\_new()}}{2} \indexentry{SubMtxManager_setDefaultFields@{\tt SubMtxManager\_setDefaultFields()}}{3} \indexentry{SubMtxManager_clearData@{\tt SubMtxManager\_clearData()}}{3} \indexentry{SubMtxManager_free@{\tt SubMtxManager\_free()}}{3} \indexentry{SubMtxManager_init@{\tt SubMtxManager\_init()}}{3} \indexentry{SubMtxManager_newObjectOfSizeNbytes@{\tt SubMtxManager\_newObjectOfSizeNbytes()}}{3} \indexentry{SubMtxManager_releaseObject@{\tt SubMtxManager\_releaseObject()}}{3} \indexentry{SubMtxManager_releaseListOfObjects@{\tt SubMtxManager\_releaseListOfObjects()}}{4} \indexentry{SubMtxManager_writeForHumanEye@{\tt SubMtxManager\_writeForHumanEye()}}{4} SubMtxManager/doc/main.ilg010064400020550007177000000004550653625066600170160ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (9 entries accepted, 0 rejected). Sorting entries....done (26 comparisons). Generating output file main.ind....done (13 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. SubMtxManager/doc/main.ind010064400020550007177000000007070653625066600170150ustar00clevecompmath00000400000006\begin{theindex} \item {\tt SubMtxManager\_clearData()}, 3 \item {\tt SubMtxManager\_free()}, 3 \item {\tt SubMtxManager\_init()}, 3 \item {\tt SubMtxManager\_new()}, 2 \item {\tt SubMtxManager\_newObjectOfSizeNbytes()}, 3 \item {\tt SubMtxManager\_releaseListOfObjects()}, 4 \item {\tt SubMtxManager\_releaseObject()}, 3 \item {\tt SubMtxManager\_setDefaultFields()}, 3 \item {\tt SubMtxManager\_writeForHumanEye()}, 4 \end{theindex} SubMtxManager/doc/main.log010064400020550007177000000062730653625067100170240ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 6 JUN 1998 07:27 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) (/usr/local/lib/texmf/tex/generic/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen100 \p@intvaluey=\dimen101 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 2. LaTeX Warning: No \tt typeface in this size, using \rm on input line 2. [1 ]) (dataStructure.tex Overfull \hbox (8.41794pt too wide) in paragraph at lines 14--19 [] []\elvtt int mode \elvrm : be-hav-ior mode. When \elvtt mode = 0\elvrm , the ob-ject calls \elvtt SubMtx[]new() \elvrm and \elvtt SubMtx[]free() \hbox(7.60416+2.12917)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(4.86667+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvtt i .etc. ) (proto.tex Overfull \hbox (14.44592pt too wide) in paragraph at lines 33--44 []\elvrm The struc-ture's fields are set to de-fault val-ues: \elvtt mode\elvrm , \elvtt nactive\elvrm , \elvtt nbytesactive\elvrm , \elvtt nbytesrequested\el vrm , \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\elvrm T .\elvrm h .\elvrm e .\glue 3.65 plus 1.825 minus 1.21666 .etc. [2] Overfull \hbox (34.76115pt too wide) in paragraph at lines 141--141 [] []\elvtt void SubMtxManager_releaseListOfObjects ( SubMtxManager *manager, SubMtx *first ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. [3]) (main.ind [4] Overfull \hbox (4.90767pt too wide) in paragraph at lines 7--8 []\elvtt SubMtxManager[]newObjectOfSizeNbytes()\elvrm , 3 \hbox(7.60416+2.43333)x217.37749, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\elvtt S .\elvtt u .\elvtt b .\elvtt M .etc. [5 ]) (main.aux) ) Here is how much of TeX's memory you used: 421 strings out of 11977 4301 string characters out of 87269 37024 words of memory out of 262141 2356 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 14i,5n,17p,192b,199s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (5 pages, 11492 bytes). SubMtxManager/doc/main.tex010064400020550007177000000011520665065631700170360ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \newcommand{\bnd}{{\partial}} \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt SubMtxManager} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt SubMtxManager} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input main.ind \end{document} SubMtxManager/doc/proto.tex010064400020550007177000000150060653625723300172550ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt SubMtxManager} methods} \label{section:SubMtxManager:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt SubMtxManager} object. \par \subsection{Basic methods} \label{subsection:SubMtxManager:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} SubMtxManager * SubMtxManager_new ( void ) ; \end{verbatim} \index{SubMtxManager_new@{\tt SubMtxManager\_new()}} This method simply allocates storage for the {\tt SubMtxManager} structure and then sets the default fields by a call to {\tt SubMtxManager\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxManager_setDefaultFields ( SubMtxManager *manager ) ; \end{verbatim} \index{SubMtxManager_setDefaultFields@{\tt SubMtxManager\_setDefaultFields()}} The structure's fields are set to default values: {\tt mode}, {\tt nactive}, {\tt nbytesactive}, {\tt nbytesrequested}, {\tt nbytesalloc}, {\tt nrequests}, {\tt nreleases}, {\tt nlocks} and {\tt nunlocks} are set to zero, and {\tt head} and {\tt lock} are set to {\tt NULL} . \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxManager_clearData ( SubMtxManager *manager ) ; \end{verbatim} \index{SubMtxManager_clearData@{\tt SubMtxManager\_clearData()}} This method clears the object and free's any owned data by calling {\tt SubMtx\_free()} for each object on the free list. If the lock is not {\tt NULL}, it is destroyed via a call to {\tt mutex\_destroy()} and then free'd. There is a concluding call to {\tt SubMtxManager\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxManager_free ( SubMtxManager *manager ) ; \end{verbatim} \index{SubMtxManager_free@{\tt SubMtxManager\_free()}} This method releases any storage by a call to {\tt SubMtxManager\_clearData()} and then free the space for {\tt manager}. \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initialization methods} \label{subsection:SubMtxManager:proto:initial} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxManager_init( SubMtxManager *manager, int lockflag, int mode ) ; \end{verbatim} \index{SubMtxManager_init@{\tt SubMtxManager\_init()}} Any data is cleared via a call to {\tt SubMtxManager\_clearData()}. If {\tt lockflag} is zero, the lock is not initialized. If {\tt lockflag} is {\tt 1}, the lock is initialized to be able to synchronize threads with the calling process. If {\tt lockflag} is {\tt 2}, the lock is initialized to be able to synchronize threads across processes. The behavior mode is set to {\tt mode}. \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, or if {\tt lockflag} is not in {\tt [0,2]}, or if {\tt mode} is not in {\tt [0,1]}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:SubMtxManager:proto:utility} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} SubMtx * SubMtxManager_newObjectOfSizeNbytes ( SubMtxManager *manager, int nbytesNeeded ) ; \end{verbatim} \index{SubMtxManager_newObjectOfSizeNbytes@{\tt SubMtxManager\_newObjectOfSizeNbytes()}} \par This method returns a pointer to a {\tt SubMtx} object that has at least {\tt nbytesNeeded} bytes in its workspace. \par \noindent {\it Error checking:} If {\tt manager} is {\tt NULL}, or if ${\tt nbytesNeeded} \le 0$, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxManager_releaseObject ( SubMtxManager *manager, SubMtx *mtx ) ; \end{verbatim} \index{SubMtxManager_releaseObject@{\tt SubMtxManager\_releaseObject()}} \par This method releases the {\tt mtx} instance, either free'ing it (if {\tt mode = 0}), or returning it to the free list (if {\tt mode = 1}). \par \noindent {\it Error checking:} If {\tt manager} or {\tt mtx} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxManager_releaseListOfObjects ( SubMtxManager *manager, SubMtx *first ) ; \end{verbatim} \index{SubMtxManager_releaseListOfObjects@{\tt SubMtxManager\_releaseListOfObjects()}} \par This method releases a list of {\tt SubMtx} objects whose head is {\tt first}, either free'ing them (if {\tt mode = 0}), or returning them to the free list (if {\tt mode = 1}). \par \noindent {\it Error checking:} If {\tt manager} or {\tt head} is {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:SubMtxManager:proto:IO} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void SubMtxManager_writeForHumanEye ( SubMtxManager *manager, FILE *fp ) ; \end{verbatim} \index{SubMtxManager_writeForHumanEye@{\tt SubMtxManager\_writeForHumanEye()}} \par This method writes a {\tt SubMtxManager} object to a file in an easily readable format. \par \noindent {\it Error checking:} If {\tt manager} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} \par SubMtxManager/doc/makefile010064400020550007177000000000270654276751400170720ustar00clevecompmath00000400000006clean : - rm -f *.dvi SymbFac.h010064400020550007177000000001100653410640300135570ustar00clevecompmath00000400000006#ifndef _SymbFac_ #define _SymbFac_ #include "SymbFac/SymbFac.h" #endif SymbFac/SymbFac.h010064400020550007177000000026040653410613100151130ustar00clevecompmath00000400000006/* SymbFac.h */ #include "../ETree.h" #include "../Graph.h" #include "../InpMtx.h" #include "../Pencil.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- using one graph, create and return an IVL object that contains a symbolic factorization. created -- 97aug29, cca ----------------------------------------------------------- */ IVL * SymbFac_initFromGraph ( ETree *etree, Graph *graph ) ; /* ------------------------------------------------------- purpose -- create and return an IVL object that contains a symbolic factorization. note: we assume that both the ETree and DInpMtx objects are in their final permutation created -- 97mar15, cca ------------------------------------------------------- */ IVL * SymbFac_initFromInpMtx ( ETree *etree, InpMtx *inpmtx ) ; /* ----------------------------------------------------- compute the symbolic factorization of a matrix pencil note: we assume that both the ETree and Pencil objects are in their final permutation created -- 98may04, cca ----------------------------------------------------- */ IVL * SymbFac_initFromPencil ( ETree *etree, Pencil *pencil ) ; /*--------------------------------------------------------------------*/ SymbFac/makefile010064400020550007177000000002230663622367400151300ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean SymbFac/src/makefile010064400020550007177000000005670663603046600157250ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SymbFac $(OBJ).a : \ $(OBJ).a(symbfac.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG SymbFac/src/makeGlobalLib010064400020550007177000000005230660026115000166100ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = SymbFac SRC = symbfac.o OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a SymbFac/src/symbfac.c010064400020550007177000000450470657603120400160110ustar00clevecompmath00000400000006/* symbfac.c */ #include "../SymbFac.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- using one graph, create and return an IVL object that contains a symbolic factorization. created -- 97aug29, cca ----------------------------------------------------------- */ IVL * SymbFac_initFromGraph ( ETree *etree, Graph *graph ) { int bndweight, count, first, front, ierr, ii, intweight, I, J, last, nfromchildren, nint, nfront, nvtx, size, v, w ; int *adj, *bndwghts, *fch, *head, *indices, *keys, *link, *marker, *nodwghts, *sib, *vwghts, *vtxToFront ; IVL *frontToVtxIVL ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 || graph == NULL || graph->nvtx != nvtx ) { fprintf(stderr, "\n fatal error in SymbFac_fromGraph(%p,%p)" "\n bad input\n", etree, graph) ; if ( etree != NULL ) { ETree_writeStats(etree, stderr) ; } if ( graph != NULL ) { Graph_writeStats(graph, stderr) ; } exit(-1) ; } vwghts = graph->vwghts ; /* ---------------------------------------------- initialize the IVL object to hold the symbolic factorization and set up the work vectors ---------------------------------------------- */ frontToVtxIVL = IVL_new() ; IVL_init1(frontToVtxIVL, IVL_CHUNKED, nfront) ; marker = IVinit(nvtx, -1) ; keys = IVinit(nvtx, -1) ; indices = IVinit(nvtx, -1) ; head = IVinit(nfront, -1) ; link = IVinit(nvtx, -1) ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; vtxToFront = IV_entries(etree->vtxToFrontIV) ; for ( v = 0 ; v < nvtx ; v++ ) { front = vtxToFront[v] ; link[v] = head[front] ; head[front] = v ; } tree = etree->tree ; fch = tree->fch ; sib = tree->sib ; /* -------------------- loop over the fronts -------------------- */ for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n checking out front %d", J) ; #endif count = 0 ; /* ----------------------------------- load and mark the internal vertices ----------------------------------- */ intweight = 0 ; for ( v = head[J] ; v != -1 ; v = link[v] ) { marker[v] = J ; indices[count++] = v ; intweight += (vwghts != NULL) ? vwghts[v] : 1 ; } nint = count ; #if MYDEBUG > 0 fprintf(stdout, "\n internal : ") ; IVfp80(stdout, count, indices, 12, &ierr) ; #endif /* -------------------------------------------------------- load vertices from the boundaries of the children fronts -------------------------------------------------------- */ bndweight = 0 ; for ( I = fch[J] ; I != -1 ; I = sib[I] ) { IVL_listAndSize(frontToVtxIVL, I, &size, &adj) ; for ( ii = size - 1 ; ii >= 0 ; ii-- ) { v = adj[ii] ; if ( vtxToFront[v] > J ) { if ( marker[v] != J ) { marker[v] = J ; indices[count++] = v ; bndweight += (vwghts != NULL) ? vwghts[v] : 1 ; } } else { break ; } } } nfromchildren = count - nint ; #if MYDEBUG > 0 fprintf(stdout, "\n from children : ") ; IVfp80(stdout, count - nint, indices + nint, 17, &ierr) ; #endif /* --------------------------------------------------------------- load unmarked edges that are adjacent to vertices in this front --------------------------------------------------------------- */ for ( v = head[J] ; v != -1 ; v = link[v] ) { Graph_adjAndSize(graph, v, &size, &adj) ; for ( ii = 0 ; ii < size ; ii++ ) { w = adj[ii] ; if ( w < nvtx && vtxToFront[w] > J && marker[w] != J ) { marker[w] = J ; indices[count++] = w ; bndweight += (vwghts != NULL) ? vwghts[w] : 1 ; } } } #if MYDEBUG > 0 fprintf(stdout, "\n from original edges : ") ; IVfp80(stdout, count - nint - nfromchildren, indices + nint + nfromchildren, 23, &ierr) ; #endif /* --------------------------------- set the node and boundary weights --------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n front %d, nint %d, count %d, intweight %d, bndweight %d", J, nint, count, intweight, bndweight) ; #endif nodwghts[J] = intweight ; bndwghts[J] = bndweight ; /* ---------------------------------------------------- sort the vertices in ascending order of their fronts ---------------------------------------------------- */ for ( ii = 0 ; ii < count ; ii++ ) { v = indices[ii] ; keys[ii] = vtxToFront[v] ; } IV2qsortUp(count, keys, indices) ; #if MYDEBUG > 0 fprintf(stdout, "\n indices sorted by fronts") ; IVfp80(stdout, count, indices, 25, &ierr) ; #endif /* ----------------------------------------------------- sort the indices in ascending order within each front ----------------------------------------------------- */ front = J ; first = 0 ; ii = 1 ; while ( ii < count ) { v = indices[ii] ; if ( vtxToFront[v] != front ) { last = ii - 1 ; if ( (size = last - first + 1) > 1 ) { IVqsortUp(size, indices + first) ; } first = ii ; front = vtxToFront[v] ; } ii++ ; } last = count - 1 ; if ( (size = last - first + 1) > 1 ) { IVqsortUp(size, indices + first) ; } #if MYDEBUG > 0 fprintf(stdout, "\n indices sorted inside fronts") ; IVfp80(stdout, count, indices, 25, &ierr) ; #endif /* ----------------- store the indices ----------------- */ IVL_setList(frontToVtxIVL, J, count, indices) ; } /* ------------------------ free the working storage ------------------------ */ IVfree(indices) ; IVfree(marker) ; IVfree(keys) ; IVfree(head) ; IVfree(link) ; return(frontToVtxIVL) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- create and return an IVL object that contains a symbolic factorization. note: we assume that both the ETree and InpMtx objects are in their final permutation created -- 97mar15, cca ------------------------------------------------------- */ IVL * SymbFac_initFromInpMtx ( ETree *etree, InpMtx *inpmtx ) { int count, front, ierr, ii, I, J, nfromchildren, nint, nfront, nvector, nvtx, size, v, w ; int *adj, *bndwghts, *fch, *head, *indices, *keys, *link, *marker, *nodwghts, *sib, *vtxToFront ; IVL *frontToVtxIVL ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 || inpmtx == NULL ) { fprintf(stderr, "\n fatal error in Symbfac_initFromInpMtx(%p,%p)" "\n bad input\n", etree, inpmtx) ; if ( etree != NULL ) { ETree_writeStats(etree, stderr) ; } if ( inpmtx != NULL ) { InpMtx_writeStats(inpmtx, stderr) ; } exit(-1) ; } /* ------------------------------------------ check the coordinate type and storage mode ------------------------------------------ */ if ( ! INPMTX_IS_BY_CHEVRONS(inpmtx) ) { fprintf(stderr, "\n fatal error in Symbfac_initFromInpMtx()" "\n bad input, coordType %d, must be INPMTX_BY_CHEVRONS\n", InpMtx_coordType(inpmtx)) ; exit(-1) ; } if ( ! INPMTX_IS_BY_VECTORS(inpmtx) ) { fprintf(stderr, "\n fatal error in Symbfac_initFromInpMtx()" "\n bad input, storageMode %d, must be INPMTX_BY_VECTORS\n", InpMtx_storageMode(inpmtx)) ; exit(-1) ; } nvector = InpMtx_nvector(inpmtx) ; #if MYDEBUG > 0 fprintf(stdout, "\n nvector = %d", nvector) ; fflush(stdout) ; #endif /* ---------------------------------------------- initialize the IVL object to hold the symbolic factorization and set up the work vectors ---------------------------------------------- */ frontToVtxIVL = IVL_new() ; IVL_init1(frontToVtxIVL, IVL_CHUNKED, nfront) ; marker = IVinit(nvtx, -1) ; keys = IVinit(nvtx, -1) ; indices = IVinit(nvtx, -1) ; head = IVinit(nfront, -1) ; link = IVinit(nvtx, -1) ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; vtxToFront = IV_entries(etree->vtxToFrontIV) ; for ( v = 0 ; v < nvtx ; v++ ) { front = vtxToFront[v] ; link[v] = head[front] ; head[front] = v ; } tree = etree->tree ; fch = tree->fch ; sib = tree->sib ; /* -------------------- loop over the fronts -------------------- */ for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n checking out front %d", J) ; #endif count = 0 ; /* ----------------------------------- load and mark the internal vertices ----------------------------------- */ for ( v = head[J] ; v != -1 ; v = link[v] ) { marker[v] = J ; indices[count++] = v ; } nint = count ; #if MYDEBUG > 0 fprintf(stdout, "\n internal : ") ; IVfp80(stdout, count, indices, 12, &ierr) ; #endif /* -------------------------------------------------------- load vertices from the boundaries of the children fronts -------------------------------------------------------- */ for ( I = fch[J] ; I != -1 ; I = sib[I] ) { IVL_listAndSize(frontToVtxIVL, I, &size, &adj) ; for ( ii = size - 1 ; ii >= 0 ; ii-- ) { v = adj[ii] ; if ( vtxToFront[v] > J ) { if ( marker[v] != J ) { marker[v] = J ; indices[count++] = v ; } } else { break ; } } } nfromchildren = count - nint ; #if MYDEBUG > 0 fprintf(stdout, "\n from children : ") ; IVfp80(stdout, count - nint, indices + nint, 17, &ierr) ; #endif /* --------------------------------------------------------------- load unmarked edges that are adjacent to vertices in this front --------------------------------------------------------------- */ for ( v = head[J] ; v != -1 ; v = link[v] ) { if ( v < nvector ) { InpMtx_vector(inpmtx, v, &size, &adj) ; for ( ii = 0 ; ii < size ; ii++ ) { if ( adj[ii] >= 0 ) { w = v + adj[ii] ; } else { w = v - adj[ii] ; } if ( vtxToFront[w] > J && marker[w] != J ) { marker[w] = J ; indices[count++] = w ; } } } } #if MYDEBUG > 0 fprintf(stdout, "\n from original edges : ") ; IVfp80(stdout, count - nint - nfromchildren, indices + nint + nfromchildren, 23, &ierr) ; #endif /* --------------------------------- set the node and boundary weights --------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n front %d, nint %d, count %d", J, nint, count) ; #endif nodwghts[J] = nint ; bndwghts[J] = count - nint ; /* ------------------------------------ sort the vertices in ascending order ------------------------------------ */ IVqsortUp(count, indices) ; #if MYDEBUG > 0 fprintf(stdout, "\n indices sorted ") ; IVfp80(stdout, count, indices, 25, &ierr) ; #endif /* ----------------- store the indices ----------------- */ IVL_setList(frontToVtxIVL, J, count, indices) ; } /* ------------------------ free the working storage ------------------------ */ IVfree(indices) ; IVfree(marker) ; IVfree(keys) ; IVfree(head) ; IVfree(link) ; return(frontToVtxIVL) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- compute the symbolic factorization of a matrix pencil note: we assume that both the ETree and Pencil objects are in their final permutation created -- 98may04, cca ----------------------------------------------------- */ IVL * SymbFac_initFromPencil ( ETree *etree, Pencil *pencil ) { InpMtx *inpmtxA, *inpmtxB ; int count, front, ierr, ii, I, J, nfromchildren, nint, nfront, nvectorA, nvectorB, nvtx, size, v, w ; int *adj, *bndwghts, *fch, *head, *indices, *keys, *link, *marker, *nodwghts, *sib, *vtxToFront ; IVL *frontToVtxIVL ; Tree *tree ; /* --------------- check the input --------------- */ if ( etree == NULL || (nfront = etree->nfront) <= 0 || (nvtx = etree->nvtx) <= 0 || pencil == NULL ) { fprintf(stderr, "\n fatal error in SymbFac_initFromPencil(%p,%p)" "\n bad input\n", etree, pencil) ; if ( etree != NULL ) { ETree_writeStats(etree, stderr) ; } if ( pencil != NULL ) { Pencil_writeStats(pencil, stderr) ; } exit(-1) ; } inpmtxA = pencil->inpmtxA ; inpmtxB = pencil->inpmtxB ; /* ------------------------------------------ check the coordinate type and storage mode ------------------------------------------ */ if ( inpmtxA != NULL ) { if ( ! INPMTX_IS_BY_CHEVRONS(inpmtxA) ) { fprintf(stderr, "\n fatal error in Symbfac_initFromPencil()" "\n bad input, coordType %d, must be INPMTX_BY_CHEVRONS\n", InpMtx_coordType(inpmtxA)) ; exit(-1) ; } if ( ! INPMTX_IS_BY_VECTORS(inpmtxA) ) { fprintf(stderr, "\n fatal error in Symbfac_initFromPencil()" "\n bad input, storageMode %d, must be INPMTX_BY_VECTORS\n", InpMtx_storageMode(inpmtxA)) ; exit(-1) ; } nvectorA = InpMtx_nvector(inpmtxA) ; } else { nvectorA = 0 ; } if ( inpmtxB != NULL ) { if ( ! INPMTX_IS_BY_CHEVRONS(inpmtxB) ) { fprintf(stderr, "\n fatal error in Symbfac_initFromPencil()" "\n bad input, coordType %d, must be INPMTX_BY_CHEVRONS\n", InpMtx_coordType(inpmtxB)) ; exit(-1) ; } if ( ! INPMTX_IS_BY_VECTORS(inpmtxB) ) { fprintf(stderr, "\n fatal error in Symbfac_initFromPencil()" "\n bad input, storageMode %d, must be INPMTX_BY_VECTORS\n", InpMtx_storageMode(inpmtxB)) ; exit(-1) ; } nvectorB = InpMtx_nvector(inpmtxB) ; } else { nvectorB = 0 ; } #if MYDEBUG > 0 fprintf(stdout, "\n nvectorA = %d", nvectorA) ; fprintf(stdout, "\n nvectorB = %d", nvectorB) ; fflush(stdout) ; #endif /* ---------------------------------------------- initialize the IVL object to hold the symbolic factorization and set up the work vectors ---------------------------------------------- */ frontToVtxIVL = IVL_new() ; IVL_init1(frontToVtxIVL, IVL_CHUNKED, nfront) ; marker = IVinit(nvtx, -1) ; keys = IVinit(nvtx, -1) ; indices = IVinit(nvtx, -1) ; head = IVinit(nfront, -1) ; link = IVinit(nvtx, -1) ; nodwghts = IV_entries(etree->nodwghtsIV) ; bndwghts = IV_entries(etree->bndwghtsIV) ; vtxToFront = IV_entries(etree->vtxToFrontIV) ; for ( v = 0 ; v < nvtx ; v++ ) { front = vtxToFront[v] ; link[v] = head[front] ; head[front] = v ; } tree = etree->tree ; fch = tree->fch ; sib = tree->sib ; /* -------------------- loop over the fronts -------------------- */ for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n checking out front %d", J) ; #endif count = 0 ; /* ----------------------------------- load and mark the internal vertices ----------------------------------- */ for ( v = head[J] ; v != -1 ; v = link[v] ) { marker[v] = J ; indices[count++] = v ; } nint = count ; #if MYDEBUG > 0 fprintf(stdout, "\n internal : ") ; IVfp80(stdout, count, indices, 12, &ierr) ; #endif /* -------------------------------------------------------- load vertices from the boundaries of the children fronts -------------------------------------------------------- */ for ( I = fch[J] ; I != -1 ; I = sib[I] ) { IVL_listAndSize(frontToVtxIVL, I, &size, &adj) ; for ( ii = size - 1 ; ii >= 0 ; ii-- ) { v = adj[ii] ; if ( vtxToFront[v] > J ) { if ( marker[v] != J ) { marker[v] = J ; indices[count++] = v ; } } else { break ; } } } nfromchildren = count - nint ; #if MYDEBUG > 0 fprintf(stdout, "\n from children : ") ; IVfp80(stdout, count - nint, indices + nint, 17, &ierr) ; #endif /* --------------------------------------------------------------- load unmarked edges that are adjacent to vertices in this front --------------------------------------------------------------- */ for ( v = head[J] ; v != -1 ; v = link[v] ) { if ( inpmtxA != NULL ) { InpMtx_vector(inpmtxA, v, &size, &adj) ; for ( ii = 0 ; ii < size ; ii++ ) { if ( adj[ii] >= 0 ) { w = v + adj[ii] ; } else { w = v - adj[ii] ; } if ( vtxToFront[w] > J && marker[w] != J ) { marker[w] = J ; indices[count++] = w ; } } } if ( inpmtxB != NULL ) { InpMtx_vector(inpmtxB, v, &size, &adj) ; for ( ii = 0 ; ii < size ; ii++ ) { if ( adj[ii] >= 0 ) { w = v + adj[ii] ; } else { w = v - adj[ii] ; } if ( vtxToFront[w] > J && marker[w] != J ) { marker[w] = J ; indices[count++] = w ; } } } } #if MYDEBUG > 0 fprintf(stdout, "\n from original edges : ") ; IVfp80(stdout, count - nint - nfromchildren, indices + nint + nfromchildren, 23, &ierr) ; #endif /* --------------------------------- set the node and boundary weights --------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n front %d, nint %d, count %d", J, nint, count) ; #endif nodwghts[J] = nint ; bndwghts[J] = count - nint ; /* ------------------------------------ sort the vertices in ascending order ------------------------------------ */ IVqsortUp(count, indices) ; #if MYDEBUG > 0 fprintf(stdout, "\n indices sorted ") ; IVfp80(stdout, count, indices, 25, &ierr) ; #endif /* ----------------- store the indices ----------------- */ IVL_setList(frontToVtxIVL, J, count, indices) ; } /* ------------------------ free the working storage ------------------------ */ IVfree(indices) ; IVfree(marker) ; IVfree(keys) ; IVfree(head) ; IVfree(link) ; return(frontToVtxIVL) ; } /*--------------------------------------------------------------------*/ link[v] = head[front] ; head[front] = v ; } tree = etree->tree ; fch = tree->fch ; sib = tree->sib ; /* -------------------- loop over the fronts -------------------- */ for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { #if MYDEBUG > 0 fprintf(stdout, "\n\n checking out front %d", J) ; #endif count = 0 ; /* ----------------------------------- load and mark the internal vertices -----------------SymbFac/drivers/do_testSymbfacGraph010075500020550007177000000024070663430067100207610ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set matrices = ../../../matrices set matrix = GRD7x7 set matrix = R2D100 set matrix = GRD31x31x31 set matrix = BCSSTK35 set inETreeFile = /local1/ARPA/matrices/i4a/best0.etreef set inETreeFile = /local1/ARPA/matrices/i4a/best1.etreef set inETreeFile = $matrices/$matrix/nd.etreef set inETreeFile = $matrices/$matrix/stk35.etreef set inGraphFile = /local1/ARPA/matrices/i4a/orig0.graphb set inGraphFile = /local1/ARPA/matrices/i4a/orig1.graphb set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig0.graphb set outETreeFile = $matrices/$matrix/nd.etreef set outETreeFile = $matrices/$matrix/ndnew.etreeb set outETreeFile = none set outIVfile = $matrices/$matrix/oldToNew.ivf set outIVfile = none set outIVLfile = /local1/ARPA/matrices/i4a/symb0.ivlb set outIVLfile = /local1/ARPA/matrices/i4a/symb1.ivlb set outIVLfile = /local1/ARPA/matrices/i4a/symb1.ivlf set outIVLfile = $matrices/$matrix/symbfac.ivlb set outIVLfile = none set outIVLfile = $matrices/$matrix/symbfac.txt set msglvl = 1 set msgFile = stdout testSymbfacGraph $msglvl $msgFile \ $inETreeFile $inGraphFile $outETreeFile $outIVfile $outIVLfile SymbFac/drivers/do_testSymbfacInpMtx010075500020550007177000000012250657431237600211440ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D100 set inETreeFile = $matrices/$matrix/nd.etreef set inETreeFile = /local1/ARPA/matrices/i4a/best0.etreef set inInpMtxFile = $matrices/$matrix/orig.dinpmtxf set inInpMtxFile = /local1/ARPA/matrices/i4a/i4a.inpmtxb set outETreeFile = $matrices/$matrix/nd.etreef set outETreeFile = none set outIVfile = $matrices/$matrix/oldToNew.ivf set outIVfile = none set outIVLfile = $matrices/$matrix/symbfac.ivlf set outIVLfile = none set msglvl = 1 set msgFile = stdout testSymbfacInpMtx $msglvl $msgFile \ $inETreeFile $inInpMtxFile $outETreeFile $outIVfile $outIVLfile SymbFac/drivers/makefile010064400020550007177000000007300665314265700166110ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testSymbfacInpMtx \ testSymbfacGraph drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testSymbfacGraph : testSymbfacGraph.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testSymbfacInpMtx : testSymbfacInpMtx.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} SymbFac/drivers/testSymbfacGraph.c010064400020550007177000000237540663430234400205240ustar00clevecompmath00000400000006/* testSymbfacGraph.c */ #include "../SymbFac.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------------------- (1) read in an ETree object. (2) get the old-to-new vertex permutation. (3) permute the vtx-to-front map. (4) get the symbolic factorization IVL object. (5) permute the ETree object. (6) optionally write the permuted ETree object to a file (7) optionally write the old-to-new IV object to a file (8) optionally write the symbolic factorization IV object to a file created -- 96oct03, cca --------------------------------------------------------------- */ { char *inETreeFileName, *inGraphFileName, *outETreeFileName, *outIVfileName, *outIVLfileName ; double nfops1, t1, t2 ; Graph *graph ; int msglvl, nfent1, nfind1, nleaves1, nnode1, rc ; IV *vtxOldToNewIV ; IVL *symbfacIVL ; ETree *etree ; FILE *msgFile ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile inGraphFile outETreeFile" "\n outIVfile outIVLfile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n outETreeFile -- output file, must be *.etreef or *.etreeb" "\n outIVfile -- output file for oldToNew vector," "\n must be *.ivf or *.ivb" "\n outIVLfile -- output file for symbolic factorization object" "\n must be *.ivlf or *.ivlb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; inGraphFileName = argv[4] ; outETreeFileName = argv[5] ; outIVfileName = argv[6] ; outIVLfileName = argv[7] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n inGraphFile -- %s" "\n outETreeFile -- %s" "\n outIVfile -- %s" "\n outIVLfile -- %s" "\n", argv[0], msglvl, argv[2], inETreeFileName, inGraphFileName, outETreeFileName, outIVfileName, outIVLfileName) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } /* ETree_leftJustify(etree) ; */ fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { /* int front, nfront, nvtx, v ; int *head, *link, *vtxToFront ; nfront = etree->nfront ; nvtx = etree->nvtx ; head = IVinit(nfront, -1) ; link = IVinit(nvtx, -1) ; vtxToFront = IV_entries(etree->vtxToFrontIV) ; for ( v = nvtx - 1 ; v >= 0 ; v-- ) { front = vtxToFront[v] ; link[v] = head[front] ; head[front] = v ; } for ( front = 0 ; front < nfront ; front++ ) { fprintf(msgFile, "\n front %3d :", front) ; for ( v = head[front] ; v != -1 ; v = link[v] ) { fprintf(msgFile, " %d", v) ; } } IVfree(head) ; IVfree(link) ; */ ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* ---------------------- compute the statistics ---------------------- */ nnode1 = etree->tree->n ; nfind1 = ETree_nFactorIndices(etree) ; nfent1 = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; nfops1 = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; nleaves1 = Tree_nleaves(etree->tree) ; fprintf(stdout, "\n root front %d has %d vertices", etree->tree->root, etree->nodwghtsIV->vec[etree->tree->root]) ; /* ----------------------------- get the permutation IV object ----------------------------- */ vtxOldToNewIV = ETree_oldToNewVtxPerm(etree) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n vertex old-to-new IV object") ; IV_writeForHumanEye(vtxOldToNewIV, msgFile) ; } else { fprintf(msgFile, "\n\n vertex old-to-new IV object") ; IV_writeStats(vtxOldToNewIV, msgFile) ; } fflush(msgFile) ; IV_writeToFile(vtxOldToNewIV, "oldToNew.ivf") ; /* ---------------------------------- optionally write out the IV object ---------------------------------- */ if ( strcmp(outIVfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(vtxOldToNewIV, outIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write vtxOldToNewIV to file %s", t2 - t1, outIVfileName) ; } /* -------------------------------------------- create the symbolic factorization IVL object -------------------------------------------- */ MARKTIME(t1) ; symbfacIVL = SymbFac_initFromGraph(etree, graph) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : compute the symbolic factorization", t2 - t1) ; fprintf(msgFile, "\n\n symbolic factorization IVL object in old ordering") ; if ( msglvl > 2 ) { IVL_writeForHumanEye(symbfacIVL, msgFile) ; } else { IVL_writeStats(symbfacIVL, msgFile) ; } fflush(msgFile) ; MARKTIME(t1) ; IVL_overwrite(symbfacIVL, vtxOldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : permute symbfac", t2 - t1) ; fprintf(msgFile, "\n\n symbolic factorization IVL object after overwrite") ; if ( msglvl > 2 ) { IVL_writeForHumanEye(symbfacIVL, msgFile) ; } else { IVL_writeStats(symbfacIVL, msgFile) ; } fflush(msgFile) ; MARKTIME(t1) ; IVL_sortUp(symbfacIVL) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort up", t2 - t1) ; fprintf(msgFile, "\n\n symbolic factorization IVL object in new ordering") ; if ( msglvl > 2 ) { IVL_writeForHumanEye(symbfacIVL, msgFile) ; } else { IVL_writeStats(symbfacIVL, msgFile) ; } fflush(msgFile) ; /* ---------------------------------------- permute the vertices in the ETree object ---------------------------------------- */ fprintf(msgFile, "\n\n before permuting the vertices") ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } fflush(msgFile) ; MARKTIME(t1) ; ETree_permuteVertices(etree, vtxOldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : permute vertices in ETree", t2 - t1) ; fprintf(msgFile, "\n\n after permuting the vertices") ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } fflush(msgFile) ; /* ------------------------------------- optionally write out the ETree object ------------------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { MARKTIME(t1) ; rc = ETree_writeToFile(etree, outETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write etree to file %s", t2 - t1, outETreeFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_writeToFile(%p,%s)", rc, etree, outETreeFileName) ; } /* ----------------------------------- optionally write out the IVL object ----------------------------------- */ if ( strcmp(outIVLfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IVL_writeToFile(symbfacIVL, outIVLfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write symbfac IVL to file %s", t2 - t1, outIVLfileName) ; } /* { int count, ii, J, nfront, nvtx, sizeJ, v, w ; int *head, *indJ, *link, *vtxToFront ; nvtx = graph->nvtx ; nfront = etree->nfront ; head = IVinit(nfront, -1) ; link = IVinit(nvtx, -1) ; vtxToFront = ETree_vtxToFront(etree) ; for ( v = nvtx - 1 ; v >= 0 ; v-- ) { J = vtxToFront[v] ; link[v] = head[J] ; head[J] = v ; } fprintf(msgFile, "\n /adjncy [") ; for ( J = 0 ; J < nfront ; J++ ) { IVL_listAndSize(symbfacIVL, J, &sizeJ, &indJ) ; for ( v = head[J] ; v != -1 ; v = link[v] ) { fprintf(msgFile, "\n [") ; for ( ii = 0 ; ii < sizeJ ; ii++ ) { w = indJ[ii] ; if ( v <= w ) { fprintf(msgFile, " %d", w) ; } } fprintf(msgFile, " ]") ; } } fprintf(msgFile, "\n ] def") ; fprintf(msgFile, "\n /fsinfo [") ; for ( J = 0 ; J < nfront ; J++ ) { fprintf(msgFile, "\n [ %d", head[J]) ; for ( v = head[J], count = 0 ; v != -1 ; v = link[v] ) { count++ ; } fprintf(msgFile, " %d ]", count) ; } fprintf(msgFile, "\n ] def") ; } */ /* ---------------- free the objects ---------------- */ ETree_free(etree) ; Graph_free(graph) ; IV_free(vtxOldToNewIV) ; IVL_free(symbfacIVL) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ SymbFac/drivers/testSymbfacInpMtx.c010064400020550007177000000253260657431610300207000ustar00clevecompmath00000400000006/* testSymbfacInpMtx.c */ #include "../SymbFac.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* --------------------------------------------------------------- (1) read in an ETree object. (2) permute the ETree object (3) read in a InpMtx object. (4) permute the InpMtx object (5) get the symbolic factorization IVL object. (6) optionally write the old-to-new IV object to a file created -- 96oct03, cca --------------------------------------------------------------- */ { char *inETreeFileName, *inInpMtxFileName, *outETreeFileName, *outIVfileName, *outIVLfileName ; double nfops1, t1, t2 ; InpMtx *inpmtx ; int msglvl, nfent1, nfind1, nleaves1, nnode1, rc ; IV *vtxOldToNewIV ; IVL *symbfacIVL ; ETree *etree ; FILE *msgFile ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile inInpMtxFile outETreeFile" "\n outIVfile outIVLfile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n inInpMtxFile -- input file, must be *.inpmtxf or *.inpmtxb" "\n outETreeFile -- output file, must be *.etreef or *.etreeb" "\n outIVfile -- output file for oldToNew vector," "\n must be *.ivf or *.ivb" "\n outIVLfile -- output file for symbolic factorization object" "\n must be *.ivlf or *.ivlb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; inInpMtxFileName = argv[4] ; outETreeFileName = argv[5] ; outIVfileName = argv[6] ; outIVLfileName = argv[7] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n inInpMtxFile -- %s" "\n outETreeFile -- %s" "\n outIVfile -- %s" "\n outIVLfile -- %s" "\n", argv[0], msglvl, argv[2], inETreeFileName, inInpMtxFileName, outETreeFileName, outIVfileName, outIVLfileName) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } ETree_leftJustify(etree) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl == 2 ) { ETree_writeStats(etree, msgFile) ; } else { ETree_writeForHumanEye(etree, msgFile) ; } } fflush(msgFile) ; /* ---------------------- compute the statistics ---------------------- */ MARKTIME(t1) ; nnode1 = etree->tree->n ; nfind1 = ETree_nFactorIndices(etree) ; nfent1 = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; nfops1 = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; nleaves1 = Tree_nleaves(etree->tree) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : compute statistics", t2 - t1) ; fprintf(msgFile, "\n %d nodes, %d indices, %d entries, %.0f ops, %d leaves", nnode1, nfind1, nfent1, nfops1, nleaves1) ; fflush(msgFile) ; /* ----------------------------- get the permutation IV object ----------------------------- */ MARKTIME(t1) ; vtxOldToNewIV = ETree_oldToNewVtxPerm(etree) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : get permutation", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n vertex old-to-new IV object") ; if ( msglvl == 2 ) { IV_writeStats(vtxOldToNewIV, msgFile) ; } else { IV_writeForHumanEye(vtxOldToNewIV, msgFile) ; } fflush(msgFile) ; } /* ---------------------------------------- permute the vertices in the ETree object ---------------------------------------- */ if ( msglvl > 1 ) { fprintf(msgFile, "\n\n before permuting the vertex map") ; if ( msglvl == 2 ) { ETree_writeStats(etree, msgFile) ; } else { ETree_writeForHumanEye(etree, msgFile) ; } fflush(msgFile) ; } MARKTIME(t1) ; ETree_permuteVertices(etree, vtxOldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : permute ETree", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after permuting the vertex map") ; if ( msglvl == 2 ) { ETree_writeStats(etree, msgFile) ; } else { ETree_writeForHumanEye(etree, msgFile) ; } fflush(msgFile) ; } /* ------------------------- read in the InpMtx object ------------------------- */ if ( strcmp(inInpMtxFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } inpmtx = InpMtx_new() ; MARKTIME(t1) ; rc = InpMtx_readFromFile(inpmtx, inInpMtxFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in inpmtx from file %s", t2 - t1, inInpMtxFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from InpMtx_readFromFile(%p,%s)", rc, inpmtx, inInpMtxFileName) ; exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after reading InpMtx object from file %s", inInpMtxFileName) ; if ( msglvl == 2 ) { InpMtx_writeStats(inpmtx, msgFile) ; } else { InpMtx_writeForHumanEye(inpmtx, msgFile) ; } fflush(msgFile) ; } if ( INPMTX_IS_BY_ROWS(inpmtx) ) { fprintf(msgFile, "\n matrix coordinate type is rows") ; } else if ( INPMTX_IS_BY_COLUMNS(inpmtx) ) { fprintf(msgFile, "\n matrix coordinate type is columns") ; } else if ( INPMTX_IS_BY_CHEVRONS(inpmtx) ) { fprintf(msgFile, "\n matrix coordinate type is chevrons") ; } else { fprintf(msgFile, "\n\n, error, bad coordinate type") ; exit(-1) ; } if ( INPMTX_IS_RAW_DATA(inpmtx) ) { fprintf(msgFile, "\n matrix storage mode is raw data\n") ; } else if ( INPMTX_IS_SORTED(inpmtx) ) { fprintf(msgFile, "\n matrix storage mode is sorted\n") ; } else if ( INPMTX_IS_BY_VECTORS(inpmtx) ) { fprintf(msgFile, "\n matrix storage mode is by vectors\n") ; } else { fprintf(msgFile, "\n\n, error, bad storage mode") ; exit(-1) ; } /* -------------------------- permute the InpMtx object -------------------------- */ MARKTIME(t1) ; InpMtx_permute(inpmtx, IV_entries(vtxOldToNewIV), IV_entries(vtxOldToNewIV)) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : permute the matrix", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after permuting InpMtx object") ; if ( msglvl == 2 ) { InpMtx_writeStats(inpmtx, msgFile) ; } else { InpMtx_writeForHumanEye(inpmtx, msgFile) ; } fflush(msgFile) ; } /* --------------------------------- map entries to the upper triangle --------------------------------- */ MARKTIME(t1) ; InpMtx_mapToUpperTriangle(inpmtx) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : map to upper triangle", t2 - t1) ; /* ----------------------------------------------------- change coordinate type and storage mode, if necessary ----------------------------------------------------- */ if ( ! INPMTX_IS_BY_CHEVRONS(inpmtx) ) { MARKTIME(t1) ; InpMtx_changeCoordType(inpmtx, INPMTX_BY_CHEVRONS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : change coordinate type", t2 - t1) ; } if ( INPMTX_IS_RAW_DATA(inpmtx) ) { MARKTIME(t1) ; InpMtx_changeStorageMode(inpmtx, INPMTX_SORTED) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort entries ", t2 - t1) ; } if ( INPMTX_IS_SORTED(inpmtx) ) { MARKTIME(t1) ; InpMtx_changeStorageMode(inpmtx, INPMTX_BY_VECTORS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : convert to vectors ", t2 - t1) ; } /* -------------------------------------------- create the symbolic factorization IVL object -------------------------------------------- */ MARKTIME(t1) ; symbfacIVL = SymbFac_initFromInpMtx(etree, inpmtx) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : compute the symbolic factorization", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n symbolic factorization IVL object") ; if ( msglvl == 2 ) { IVL_writeStats(symbfacIVL, msgFile) ; } else { IVL_writeForHumanEye(symbfacIVL, msgFile) ; } fflush(msgFile) ; } /* -------------------------- compute the new statistics -------------------------- */ MARKTIME(t1) ; nnode1 = etree->tree->n ; nfind1 = ETree_nFactorIndices(etree) ; nfent1 = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; nfops1 = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; nleaves1 = Tree_nleaves(etree->tree) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : compute statistics", t2 - t1) ; fprintf(msgFile, "\n %d nodes, %d indices, %d entries, %.0f ops, %d leaves", nnode1, nfind1, nfent1, nfops1, nleaves1) ; fflush(msgFile) ; /* ------------------------------------- optionally write out the ETree object ------------------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { MARKTIME(t1) ; rc = ETree_writeToFile(etree, outETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write etree to file %s", t2 - t1, outETreeFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_writeToFile(%p,%s)", rc, etree, outETreeFileName) ; } /* ---------------------------------------------- optionally write out the permutation IV object ---------------------------------------------- */ if ( strcmp(outIVfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IV_writeToFile(vtxOldToNewIV, outIVfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write permutation IV to file %s", t2 - t1, outIVfileName) ; } /* ----------------------------------- optionally write out the IVL object ----------------------------------- */ if ( strcmp(outIVLfileName, "none") != 0 ) { MARKTIME(t1) ; rc = IVL_writeToFile(symbfacIVL, outIVLfileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write symbfac IVL to file %s", t2 - t1, outIVLfileName) ; } /* ---------------- free the objects ---------------- */ ETree_free(etree) ; InpMtx_free(inpmtx) ; IV_free(vtxOldToNewIV) ; IVL_free(symbfacIVL) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ SymbFac/doc/004275500020550007177000000000000654276751400142075ustar00clevecompmath00000400000006SymbFac/doc/dataStructure.tex010064000020550007177000000001560653410613000175320ustar00clevecompmath00000400000006\par \section{Data Structure} \par There is no {\tt struct} or data associated with the {\tt SymbFac} object. SymbFac/doc/main.log010064400020550007177000000052000653553112100156070ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 4 JUN 1998 07:42 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. ) (dataStructure.tex) (proto.tex [1 ] Overfull \hbox (3.55602pt too wide) in paragraph at lines 31--39 \elvit Error check-ing: \elvrm If \elvtt etree \elvrm or \elvtt graph \elvrm is \elvtt NULL\elvrm , or if $[] \elvmi < \elvrm 1$, or if $[] \elvmi < \elvrm 1$ , or if $[] \elvsy 6\elvrm = \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\elvit E .\elvit r .\elvit r .\kern-0.55968 .\elvit o .etc. ) (drivers.tex [2] Overfull \hbox (19.63927pt too wide) in paragraph at lines 31--37 \elvtt *.etreef \elvrm or \elvtt *.etreeb\elvrm . The \elvtt ETree \elvrm ob-je ct is read from the file via the \elvtt ETree[]readFromFile() \hbox(7.60416+2.12917)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt e .\elvtt t .\elvtt r .etc. Overfull \hbox (19.63927pt too wide) in paragraph at lines 96--102 \elvtt *.etreef \elvrm or \elvtt *.etreeb\elvrm . The \elvtt ETree \elvrm ob-je ct is read from the file via the \elvtt ETree[]readFromFile() \hbox(7.60416+2.12917)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt e .\elvtt t .\elvtt r .etc. Overfull \hbox (19.63927pt too wide) in paragraph at lines 102--108 \elvtt *.graphf \elvrm or \elvtt *.graphb\elvrm . The \elvtt Graph \elvrm ob-je ct is read from the file via the \elvtt Graph[]readFromFile() \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\elvtt * .\elvtt . .\elvtt g .\elvtt r .\elvtt a .etc. [3]) (main.ind [4] [5 ]) (main.aux) ) Here is how much of TeX's memory you used: 206 strings out of 11977 2059 string characters out of 87269 33471 words of memory out of 262141 2140 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,4n,17p,184b,262s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (5 pages, 12288 bytes). SymbFac/doc/intro.tex010064000020550007177000000036340657603136000160470ustar00clevecompmath00000400000006\chapter{{\tt SymbFac}: Symbolic Factorization} \label{chapter:SymbFac} \par This object is really a collection of methods --- there is no {\tt struct} associated with it, and therefore no data. The reason for its existence is that a symbolic factorization can be produced using an {\tt ETree} object and one of several different inputs, e.g., a {\tt Graph} object, a {\tt InpMtx} object, and a {\tt Pencil} object. Possibly there could be others, all that is necessary is to be able to communicate the nonzero structure of a chevron. \par The symbolic factorization methods used to belong to the {\tt ETree} object. It was a natural location for this functionality. We first generated a symbolic factorization using a {\tt Graph} object as input, and since the {\tt ETree} object used a {\tt Graph} object to initialize itself, this was acceptable. Then we started to bypass the {\tt Graph} object and use a {\tt InpMtx} object as input, and this forced the {\it vision} of the {\tt ETree} object (the other objects it must know about) to grow. By the time we started using the {\tt Pencil} matrix pencil object to find the symbolic factorization, we knew things were out of hand. By creating a new object to handle the symbolic factorization, we can remove the {\tt InpMtx} and {\tt Pencil} objects from the vision of the ETree object. \par The symbolic factorization is stored in an {\tt IVL} object. The vertices in $J \cup \bnd{J}$ are stored in the {\tt J}'th list and can be accessed via a call to \begin{verbatim} IVL_listAndSize(symbfacIVL, J, &size, &indices) ; \end{verbatim} where on return, the {\tt int} vector {\tt indices[size]} contains the vertices. \par {\bf NOTE:} The {\tt SymbFac\_initFromInpMtx()} and {\tt SymbFac\_initFromPencil()} methods have been changed slightly to make them more efficient. The {\tt InpMtx} objects that are input are now required to have chevron coordinate type and storage mode must be by vectors. SymbFac/doc/main.tex010064400020550007177000000011520665065632100156400ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \newcommand{\bnd}[1]{{\partial{#1}}} \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt SymbFac} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt SymbFac} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} SymbFac/doc/proto.tex010064400020550007177000000072100657603151700160610ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt SymbFac} methods} \label{subsection:SymbFac:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt SymbFac} object. \par \subsection{Symbolic factorization methods} \label{subsection:SymbFac:proto:symbfac} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IVL * SymbFac_initFromGraph ( ETree *etree, Graph *graph ) ; \end{verbatim} \index{SymbFac_initFromGraph@{\tt SymbFac\_initFromGraph()}} This symbolic factorization method takes a {\tt Graph} object as input. This method constructs an {\tt IVL} object that contains one list per front. List {\tt ilist} contains the internal and external vertices for front {\tt ilist}. If the input {\tt graph} is a compressed graph, then the lists of compressed vertices make little sense; they must be converted to original vertices. To do this, see the {\tt IVL\_expand()} method. The {\tt nodwghtsIV} and {\tt bndwghtsIV} objects for the {\tt ETree} object are updated using information from the symbolic factorization. \par \noindent {\it Error checking:} If {\tt etree} or {\tt graph} is {\tt NULL}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, or if $\mbox{\tt graph->nvtx} \ne {\tt nvtx}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * SymbFac_initFromInpMtx ( ETree *etree, InpMtx *inpmtx ) ; \end{verbatim} \index{SymbFac_initFromInpMtx@{\tt SymbFac\_initFromInpMtx()}} This symbolic factorization method takes a {\tt InpMtx} object as input. This method constructs an {\tt IVL} object that contains one list per front. List {\tt ilist} contains the internal and external vertices for front {\tt ilist}. We assume that both the {\tt ETree} and {\tt InpMtx} objects have had been permuted into their final ordering. The {\tt nodwghtsIV} and {\tt bndwghtsIV} objects for the {\tt ETree} object are updated using information from the symbolic factorization. \par \noindent {\it Error checking:} If {\tt etree} or {\tt inpmtx} is {\tt NULL}, or if the coordinate type of {\tt inpmtx} is not {\tt INPMTX\_BY\_CHEVRONS}, or if the storage mode of {\tt inpmtx} is not {\tt INPMTX\_BY\_VECTORS}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IVL * SymbFac_initFromPencil ( ETree *etree, Pencil *pencil ) ; \end{verbatim} \index{Symbfac_initFromPencil@{\tt Symbfac\_initFromPencil()}} This first symbolic factorization method takes a {\tt Pencil} object as input and is used to compute the symbolic factorization for a matrix pencil $A - \sigma B$. This method constructs an {\tt IVL} object that contains one list per front. List {\tt ilist} contains the internal and external vertices for front {\tt ilist}. We assume that both the {\tt ETree} and {\tt InpMtx} objects have had been permuted into their final ordering. The {\tt nodwghtsIV} and {\tt bndwghtsIV} objects for the {\tt ETree} object are updated using information from the symbolic factorization. \par \noindent {\it Error checking:} If {\tt etree} or {\tt inpmtxA} is {\tt NULL}, or if the coordinate type of either internal {\tt InpMtx} objects is not {\tt INPMTX\_BY\_CHEVRONS}, or if the storage mode of either internal {\tt InpMtx} objects is not {\tt INPMTX\_BY\_VECTORS}, or if ${\tt nfront} < 1$, or if ${\tt nvtx} < 1$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} ethod constructs an {\tt IVL} object that contains one list per front. List {\tt ilist} contains the internal and external vertices for front {\tt ilist}. If the input {\tt graph} is a compressed graph, then the lists of compressed vertices make little sense; they must be converted to original vertices. To do this, see the {\tt IVL\_expand()} method. The {\tt nodwghtsIV} aSymbFac/doc/main.idx010064400020550007177000000003230653553112100156130ustar00clevecompmath00000400000006\indexentry{SymbFac_initFromGraph@{\tt SymbFac\_initFromGraph()}}{2} \indexentry{SymbFac_initFromInpMtx@{\tt SymbFac\_initFromInpMtx()}}{2} \indexentry{Symbfac_initFromPencil@{\tt Symbfac\_initFromPencil()}}{2} SymbFac/doc/main.aux010064400020550007177000000016320653553112100156300ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space SymbFac}: Symbolic Factorization}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \newlabel{chapter:SymbFac}{{1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space SymbFac} methods}{1}} \newlabel{subsection:SymbFac:proto}{{1.2}{1}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Symbolic factorization methods}{2}} \newlabel{subsection:SymbFac:proto:symbfac}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs }{2}} \newlabel{section:SymbFac:drivers}{{1.3}{2}} SymbFac/doc/main.ind010064400020550007177000000002420653553111600156050ustar00clevecompmath00000400000006\begin{theindex} \item {\tt SymbFac\_initFromGraph()}, 2 \item {\tt SymbFac\_initFromInpMtx()}, 2 \item {\tt Symbfac\_initFromPencil()}, 2 \end{theindex} SymbFac/doc/main.ilg010064400020550007177000000004530653553111600156120ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (3 entries accepted, 0 rejected). Sorting entries....done (4 comparisons). Generating output file main.ind....done (7 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. SymbFac/doc/drivers.tex010064400020550007177000000126660653553111100163750ustar00clevecompmath00000400000006\par \section{Driver programs } \label{section:SymbFac:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testSymbFacInpMtx msglvl msgFile inETreeFile inDInpMtxFile outETreeFile outIVfile outIVLfile \end{verbatim} This driver program reads in an {\tt ETree} object and a {\tt InpMtx} object and computes the symbolic factorization. The {\tt ETree} object is updated (the front sizes and boundary sizes may change) and is optionally written out to {\tt outETreeFile}. The old-to-new {\tt IV} object is optionally written to {\tt outIVfile}. The {\tt IVL} object that contains the symbolic factorization is optionally written to {\tt outIVLfile}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt inInpMtxFile} parameter is the input file for the {\tt InpMtx} object. It must be of the form {\tt *.inpmtxf} or {\tt *.inpmtxb}. The {\tt InpMtx} object is read from the file via the {\tt InpMtx\_readFromFile()} method. \item The {\tt outETreeFile} parameter is the output file for the {\tt ETree} object. If {\tt outETreeFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt outETreeFile} is of the form {\tt *.etreef}), or a binary file (if {\tt outETreeFile} is of the form {\tt *.etreeb}). \item The {\tt outIVfile} parameter is the output file for the vertex-to-front map {\tt IV} object. If {\tt outIVfile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the object to a formatted file (if {\tt outIVfile} is of the form {\tt *.ivf}), or a binary file (if {\tt outIVfile} is of the form {\tt *.ivb}). \item The {\tt outIVLfile} parameter is the output file for the symbolic factorization {\tt IVL} object. If {\tt outIVLfile} is {\tt none} then the {\tt IVL} object is not written to a file. Otherwise, the {\tt IVL\_writeToFile()} method is called to write the object to a formatted file (if {\tt outIVLfile} is of the form {\tt *.ivlf}), or a binary file (if {\tt outIVLfile} is of the form {\tt *.ivlb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testSymbFacGraph msglvl msgFile inETreeFile inGraphFile outETreeFile outIVfile outIVLfile \end{verbatim} This driver program reads in an {\tt ETree} object and a {\tt Graph} object and computes the symbolic factorization. The {\tt ETree} object is updated (the front sizes and boundary sizes may change) and is optionally written out to {\tt outETreeFile}. The old-to-new {\tt IV} object is optionally written to {\tt outIVfile}. The {\tt IVL} object that contains the symbolic factorization is optionally written to {\tt outIVLfile}. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt outETreeFile} parameter is the output file for the {\tt ETree} object. If {\tt outETreeFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt outETreeFile} is of the form {\tt *.etreef}), or a binary file (if {\tt outETreeFile} is of the form {\tt *.etreeb}). \item The {\tt outIVfile} parameter is the output file for the vertex-to-front map {\tt IV} object. If {\tt outIVfile} is {\tt none} then the {\tt IV} object is not written to a file. Otherwise, the {\tt IV\_writeToFile()} method is called to write the object to a formatted file (if {\tt outIVfile} is of the form {\tt *.ivf}), or a binary file (if {\tt outIVfile} is of the form {\tt *.ivb}). \item The {\tt outIVLfile} parameter is the output file for the symbolic factorization {\tt IVL} object. If {\tt outIVLfile} is {\tt none} then the {\tt IVL} object is not written to a file. Otherwise, the {\tt IVL\_writeToFile()} method is called to write the object to a formatted file (if {\tt outIVLfile} is of the form {\tt *.ivlf}), or a binary file (if {\tt outIVLfile} is of the form {\tt *.ivlb}). \end{itemize} %----------------------------------------------------------------------- \end{enumerate} {\tt *.inpmtxf} or {\tt *.inpmtxb}. The {\tt InpMtx} object is read from tSymbFac/doc/makefile010064400020550007177000000000270654276751400157010ustar00clevecompmath00000400000006clean : - rm -f *.dvi Tree.h010064400020550007177000000000740653410640100131410ustar00clevecompmath00000400000006#ifndef _Tree_ #define _Tree_ #include "Tree/Tree.h" #endif Tree/Tree.h010064400020550007177000000575570665245401000140650ustar00clevecompmath00000400000006/* Tree.h */ #include "../cfiles.h" #include "../IV.h" #include "../DV.h" /*--------------------------------------------------------------------*/ /* ----------------------- simple tree object created -- 95nov15, cca ----------------------- */ typedef struct _Tree Tree ; struct _Tree { int n ; int root ; int *par ; int *fch ; int *sib ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- purpose -- create and return a new Tree object created -- 95nov15, cca ----------------------------------------------- */ Tree * Tree_new ( void ) ; /* ------------------------------------------------------ purpose -- set the default fields for the Tree object created -- 95nov15, cca ------------------------------------------------------ */ void Tree_setDefaultFields ( Tree *tree ) ; /* -------------------------------- purpose -- clear the data fields created -- 95nov15, cca -------------------------------- */ void Tree_clearData ( Tree *tree ) ; /* -------------------------------- purpose -- free the Tree object created -- 95nov15, cca -------------------------------- */ void Tree_free ( Tree *tree ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------- purpose -- return the number of nodes in the tree created -- 98jun12, cca ------------------------------------------------- */ int Tree_nnodes ( Tree *tree ) ; /* -------------------------------------- purpose -- return the root of the tree created -- 98jun12, cca -------------------------------------- */ int Tree_root ( Tree *tree ) ; /* ------------------------------------------------ purpose -- return a pointer to the parent vector created -- 98jun12, cca ------------------------------------------------ */ int * Tree_par ( Tree *tree ) ; /* ----------------------------------------------------- purpose -- return a pointer to the first child vector created -- 98jun12, cca ----------------------------------------------------- */ int * Tree_fch ( Tree *tree ) ; /* ------------------------------------------------- purpose -- return a pointer to the sibling vector created -- 98jun12, cca ------------------------------------------------- */ int * Tree_sib ( Tree *tree ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------- simplest constructor created -- 95nov15, cca ----------------------- */ void Tree_init1 ( Tree *tree, int size ) ; /* -------------------------------- initialize given a parent vector created -- 95nov15, cca -------------------------------- */ void Tree_init2 ( Tree *tree, int size, int par[] ) ; /* --------------------------------- initialize given the tree vectors created -- 95nov15, cca --------------------------------- */ void Tree_init3 ( Tree *tree, int size, int par[], int fch[], int sib[] ) ; /* ------------------------------------ set the fch[], sib[] and root fields created -- 95nov15, cca ------------------------------------ */ void Tree_setFchSibRoot ( Tree *tree ) ; /* ----------------------- set the root field created -- 95nov15, cca ----------------------- */ void Tree_setRoot ( Tree *tree ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in maximizeGain.c ---------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------- purpose -- given a gain value assigned to each node, find a set of nodes, no two in a child-ancestor relationship, that maximizes the total gain. this problem arises in finding the optimal domain/schur complement partition for a semi-implicit factorization. created -- 98jun20, cca ------------------------------------------------------- */ IV * Tree_maximizeGainIV ( Tree *tree, IV *gainIV, int *ptotalgain, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in subtree.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------- purpose -- to initialize subtree with the subtree of tree using nodes in nodeidsIV return values --- 1 -- normal return -1 -- subtree is NULL -2 -- nodeidsIV is NULL -3 -- tree is NULL -4 -- nodeidsIV is invalid created -- 98oct15, cca ------------------------------------------------- */ int Tree_initFromSubtree ( Tree *subtree, IV *nodeidsIV, Tree *tree ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------- return the first vertex in a post-order traversal created -- 95nov15, cca ------------------------------------------------- */ int Tree_postOTfirst ( Tree *tree ) ; /* ---------------------------------------------------------- return the vertex that follows v in a post-order traversal ---------------------------------------------------------- */ int Tree_postOTnext ( Tree *tree, int v ) ; /* ------------------------------------------------ return the first vertex in a pre-order traversal created -- 95nov15, cca ------------------------------------------------ */ int Tree_preOTfirst ( Tree *tree ) ; /* --------------------------------------------------------- return the vertex that follows v in a pre-order traversal created -- 95nov15, cca --------------------------------------------------------- */ int Tree_preOTnext ( Tree *tree, int v ) ; /* --------------------------------------- return the number of leaves in the tree created -- 95nov15, cca --------------------------------------- */ int Tree_nleaves ( Tree *tree ) ; /* ----------------------------------------------- return the number of roots of the tree (forest) created -- 95nov15, cca ----------------------------------------------- */ int Tree_nroots ( Tree *tree ) ; /* ----------------------------------------- return the number of children of a vertex created -- 95nov15, cca ----------------------------------------- */ int Tree_nchild ( Tree *tree, int v ) ; /* ------------------------------------------- this method returns an IV object that holds the number of children for the tree nodes. created -- 96dec18, cca ------------------------------------------- */ IV * Tree_nchildIV ( Tree *tree ) ; /* ----------------------------- return the height of the tree created -- 96aug23, cca ----------------------------- */ int Tree_height ( Tree *tree ) ; /* ------------------------------------------------------------- return the maximum number of children of any node in the tree created -- 96sep05, cca ------------------------------------------------------------- */ int Tree_maxNchild ( Tree *tree ) ; /* --------------------------------------------- return the number of bytes used by the object --------------------------------------------- */ int Tree_sizeOf ( Tree *tree ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in metrics.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------ create and return a subtree metric IV object input : vmetricIV -- a metric defined on the vertices return : tmetricIV -- a metric defined on the subtrees created -- 96jun23, cca ------------------------------------------------------ */ IV * Tree_setSubtreeImetric ( Tree *tree, IV *vmetricIV ) ; /* ------------------------------------------------------ create and return a subtree metric DV object input : vmetricDV -- a metric defined on the vertices return : tmetricDV -- a metric defined on the subtrees created -- 96jun23, cca ------------------------------------------------------ */ DV * Tree_setSubtreeDmetric ( Tree *tree, DV *vmetricDV ) ; /* ------------------------------------------------------------ create and return a depth metric IV object input : vmetricIV -- a metric defined on the vertices output : dmetric[] -- a depth metric defined on the vertices dmetric[u] = vmetric[u] + dmetric[par[u]] if par[u] != -1 = vmetric[u] if par[u] == -1 created -- 96jun23, cca ------------------------------------------------------------ */ IV * Tree_setDepthImetric ( Tree *tree, IV *vmetricIV ) ; /* ------------------------------------------------------------ create and return a depth metric DV object input : vmetricDV -- a metric defined on the vertices output : dmetric[] -- a depth metric defined on the vertices dmetric[u] = vmetric[u] + dmetric[par[u]] if par[u] != -1 = vmetric[u] if par[u] == -1 created -- 96jun23, cca ------------------------------------------------------------ */ DV * Tree_setDepthDmetric ( Tree *tree, DV *vmetricDV ) ; /* ------------------------------------------------------------------ create and return a height metric IV object input : vmetricIV -- a metric defined on the vertices output : dmetricIV -- a depth metric defined on the vertices hmetric[v] = vmetric[v] + max{p(u) = v} hmetric[u] if fch[v] != -1 = vmetric[v] if fch[v] == -1 created -- 96jun23, cca ------------------------------------------------------------------ */ IV * Tree_setHeightImetric ( Tree *tree, IV *vmetricIV ) ; /* ------------------------------------------------------------------ create and return a height metric DV object input : vmetricDV -- a metric defined on the vertices output : dmetricDV -- a depth metric defined on the vertices hmetric[v] = vmetric[v] + max{p(u) = v} hmetric[u] if fch[v] != -1 = vmetric[v] if fch[v] == -1 created -- 96jun23, cca ------------------------------------------------------------------ */ DV * Tree_setHeightDmetric ( Tree *tree, DV *vmetricDV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in justify.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ left-justify a tree by subtree size children are linked in ascending order of their subtree size created -- 95nov15, cca ------------------------------------------------------------ */ void Tree_leftJustify ( Tree *tree ) ; /* ------------------------------------------------------ left-justify a tree by a metric children are linked in ascending order of their metric created -- 96jun23, cca ------------------------------------------------------ */ void Tree_leftJustifyI ( Tree *tree, IV *metricIV ) ; /* ------------------------------------------------------ left-justify a tree by a metric children are linked in ascending order of their metric created -- 96jun23, cca ------------------------------------------------------ */ void Tree_leftJustifyD ( Tree *tree, DV *metricDV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in perms.c ----------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------- fill the new-to-old permutation vector created -- 95nov15, cca -------------------------------------- */ void Tree_fillNewToOldPerm ( Tree *tree, int newToOld[] ) ; /* -------------------------------------- fill the old-to-new permutation vector created -- 95nov15, cca -------------------------------------- */ void Tree_fillOldToNewPerm ( Tree *tree, int oldToNew[] ) ; /* ------------------------------------------------------ fill the new-to-old and old-to-new permutation vectors created -- 95nov15, cca ------------------------------------------------------ */ void Tree_fillBothPerms ( Tree *tree, int newToOld[], int oldToNew[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------ purpose -- to read in an Tree object from a file input -- fn -- filename, must be *.treeb or *.treef return value -- 1 if success, 0 if failure created -- 95nov15, cca ------------------------------------------------ */ int Tree_readFromFile ( Tree *tree, char *fn ) ; /* ------------------------------------------------------- purpose -- to read an Tree object from a formatted file return value -- 1 if success, 0 if failure created -- 95nov15, cca ------------------------------------------------------- */ int Tree_readFromFormattedFile ( Tree *tree, FILE *fp ) ; /* --------------------------------------------------- purpose -- to read an Tree object from a binary file return value -- 1 if success, 0 if failure created -- 95nov15, cca --------------------------------------------------- */ int Tree_readFromBinaryFile ( Tree *tree, FILE *fp ) ; /* -------------------------------------------- purpose -- to write an Tree object to a file input -- fn -- filename *.treeb -- binary *.treef -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95nov15, cca -------------------------------------------- */ int Tree_writeToFile ( Tree *tree, char *fn ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to write an Tree object to a formatted file return value -- 1 if success, 0 otherwise created -- 95nov15, cca ------------------------------------------------------ */ int Tree_writeToFormattedFile ( Tree *tree, FILE *fp ) ; /* --------------------------------------------------- purpose -- to write an Tree object to a binary file return value -- 1 if success, 0 otherwise created -- 95nov15, cca --------------------------------------------------- */ int Tree_writeToBinaryFile ( Tree *tree, FILE *fp ) ; /* -------------------------------------------------- purpose -- to write an Tree object for a human eye return value -- 1 if success, 0 otherwise created -- 95nov15, cca -------------------------------------------------- */ int Tree_writeForHumanEye ( Tree *tree, FILE *fp ) ; /* ---------------------------------------------------------- purpose -- to write out the statistics for the Tree object return value -- 1 if success, 0 otherwise created -- 95nov15, cca ---------------------------------------------------------- */ int Tree_writeStats ( Tree *tree, FILE *fp ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in compress.c -------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------- create and return an IV object that contains the map from vertices to fundamental chains. return value -- # of fundamental chains created -- 96jun23, cca ------------------------------------------- */ IV * Tree_fundChainMap ( Tree *tree ) ; /* ----------------------------------------------------------------- compress a tree based on a map from old vertices to new vertices. the restriction on the map is that the set {u | map[u] = U} must be connected for all U. created -- 95nov15, cca modified -- 96jan04, cca bug fixed, N computed incorrectly modified -- 96jun23, cca in calling sequence, int map[] converted to IV *mapIV ----------------------------------------------------------------- */ Tree * Tree_compress ( Tree *tree, IV *mapIV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in permute.c --------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- return a permuted tree created -- 96jan04, cca ----------------------- */ Tree * Tree_permute ( Tree *tree, int newToOld[], int oldToNew[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in setBoxes.c -------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------- purpose -- fill boxes arrays for display of a tree vmetric[] -- vector of metric on the nodes tmetric[] -- vector of metric on the subtrees xmin, xmax, ymin, ymax -- bounds on box for root west[], east[], south[], north[] -- vector to hold bounds for the nodes in the tree return value -- 1 --> success 2 --> no success, maxnchild > 3 created -- 96dec20, cca ------------------------------------------------------------- */ int Tree_setBoxesII ( Tree *tree, int vmetric[], int tmetric[], double xmin, double xmax, double ymin, double ymax, double west[], double east[], double south[], double north[] ) ; /* ------------------------------------------------------------- purpose -- fill boxes arrays for display of a tree vmetric[] -- vector of metric on the nodes tmetric[] -- vector of metric on the subtrees xmin, xmax, ymin, ymax -- bounds on box for root west[], east[], south[], north[] -- vector to hold bounds for the nodes in the tree return value -- 1 --> success 2 --> no success, maxnchild > 3 created -- 96dec20, cca ------------------------------------------------------------- */ int Tree_setBoxesDD ( Tree *tree, double vmetric[], double tmetric[], double xmin, double xmax, double ymin, double ymax, double west[], double east[], double south[], double north[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in getCoords.c ------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------ purpose -- to get simple x[] and y[] coordinates for the tree vertices return values -- 1 -- normal return -1 -- tree is NULL -2 -- heightflag is invalid -3 -- coordflag is invalid -4 -- xDV is NULL -5 -- yDV is NULL created -- 99jan07, cca ------------------------------------------------ */ int Tree_getSimpleCoords ( Tree *tree, char heightflag, char coordflag, DV *xDV, DV *yDV ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in draw.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ purpose -- to write an EPS file with a picture of a tree. each node can have its own radius and label filename -- name of the file to be written xDV -- x coordinates yDV -- y coordinates rscale -- scaling factor for radius of nodes radiusDV -- radius of nodes, if NULL then radius = 1 labelflag -- flag to specify whether labels are to be drawn 1 -- draw labels otherwise -- do not draw labels fontscale -- scaling factor for font labelsIV -- IV object that contains the labels of the nodes. if NULL then the node ids are used bbox[] -- bounding box for figure bbox[0] -- x_min bbox[1] -- y_min bbox[2] -- x_max bbox[3] -- y_max frame[] -- frame to hold tree frame[0] -- x_min frame[1] -- y_min frame[2] -- x_max frame[3] -- y_max bounds[] -- bounds for local coordinates if bounds is NULL then the tree fills the frame. note, this is a nonlinear process when the nodes have non-constant radii, and may not converge when the maximum radius is large when compared to the frame. if the process does not converge, a message is printed and the program exits. else bounds[0] -- xi_min bounds[1] -- eta_min bounds[2] -- xi_max bounds[3] -- eta_max endif recommendations, bbox[] = { 0, 0, 500, 200 } for tall skinny trees { 0, 0, 500, 500 } for wide trees frame[0] = bbox[0] + 10 frame[1] = bbox[1] + 10 frame[2] = bbox[2] - 10 frame[3] = bbox[3] - 10 return value 1 -- normal return -1 -- tree is NULL -2 -- filename is NULL -3 -- xDV is NULL -4 -- yDV is NULL -5 -- rscale is negative -6 -- fontscale is negative -7 -- bbox is NULL -8 -- frame is NULL created -- 99jan07, cca ------------------------------------------------------------ */ int Tree_drawToEPS ( Tree *tree, char *filename, DV *xDV, DV *yDV, double rscale, DV *radiusDV, int labelflag, double fontscale, IV *labelsIV, double bbox[], double frame[], double bounds[] ) ; /*--------------------------------------------------------------------*/ ee, int newToOld[], int oldToNew[] ) ; /*--------------------------------------------------------------------*/ /* ------------------Tree/makefile010064400020550007177000000002230663622370000144710ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean Tree/src/makefile010064400020550007177000000012560665243627600153030ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Tree $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(compress.o) \ $(OBJ).a(draw.o) \ $(OBJ).a(getCoords.o) \ $(OBJ).a(init.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(justify.o) \ $(OBJ).a(maximizeGain.o) \ $(OBJ).a(metrics.o) \ $(OBJ).a(perms.o) \ $(OBJ).a(permute.o) \ $(OBJ).a(subtree.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG \ $(OBJ).a(draw.o) \ $(OBJ).a(getCoords.o) \ $(OBJ).a(init.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(justify.o) \ $(OBJ).a(maximizeGain.o) \ $(OBJ).a(metrics.o) \ $(OBJ).a(perms.o) \ $(OBJ).a(permute.o) \ $(OBJ).a(subtree.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now Tree/src/makeGlobalLib010064400020550007177000000010200660026115300161570ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Tree SRC = basics.c \ compress.c \ drawTree.c \ init.c \ instance.c \ IO.c \ justify.c \ maximizeGain.c \ metrics.c \ perms.c \ permute.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Tree/src/IO.c010064400020550007177000000317670653410605700142560ustar00clevecompmath00000400000006/* IO.c */ #include "../Tree.h" static const char *suffixb = ".treeb" ; static const char *suffixf = ".treef" ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to read in an Tree object from a file input -- fn -- filename, must be *.treeb or *.treef return value -- 1 if success, 0 if failure created -- 95nov15, cca ------------------------------------------------ */ int Tree_readFromFile ( Tree *tree, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( tree == NULL || fn == NULL ) { fprintf(stderr, "\n error in Tree_readFromFile(%p,%s)" "\n bad input\n", tree, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in Tree_readFromFile(%p,%s)" "\n unable to open file %s", tree, fn, fn) ; rc = 0 ; } else { rc = Tree_readFromBinaryFile(tree, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in Tree_readFromFile(%p,%s)" "\n unable to open file %s", tree, fn, fn) ; rc = 0 ; } else { rc = Tree_readFromFormattedFile(tree, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in Tree_readFromFile(%p,%s)" "\n bad Tree file name %s," "\n must end in %s (binary) or %s (formatted)\n", tree, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in Tree_readFromFile(%p,%s)" "\n bad Tree file name %s," "\n must end in %s (binary) or %s (formatted)\n", tree, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to read an Tree object from a formatted file return value -- 1 if success, 0 if failure created -- 95nov15, cca ------------------------------------------------------- */ int Tree_readFromFormattedFile ( Tree *tree, FILE *fp ) { int rc ; int itemp[2] ; /* --------------- check the input --------------- */ if ( tree == NULL || fp == NULL ) { fprintf(stderr, "\n error in Tree_readFromFormattedFile(%p,%p)" "\n bad input\n", tree, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ Tree_clearData(tree) ; /* --------------------------------- read in the two scalar parameters number of nodes and the root --------------------------------- */ if ( (rc = IVfscanf(fp, 2, itemp)) != 2 ) { fprintf(stderr, "\n error in Tree_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", tree, fp, rc, 2) ; return(0) ; } /* --------------------- initialize the object --------------------- */ Tree_init1(tree, itemp[0]) ; tree->root = itemp[1] ; /* ----------------------- now read in the indices ----------------------- */ if ( (rc = IVfscanf(fp, tree->n, tree->par)) != tree->n ) { fprintf(stderr, "\n par: error in Tree_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", tree, fp, rc, tree->n) ; return(0) ; } if ( (rc = IVfscanf(fp, tree->n, tree->fch)) != tree->n ) { fprintf(stderr, "\n fch: error in Tree_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", tree, fp, rc, tree->n) ; return(0) ; } if ( (rc = IVfscanf(fp, tree->n, tree->sib)) != tree->n ) { fprintf(stderr, "\n sib: error in Tree_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", tree, fp, rc, tree->n) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to read an Tree object from a binary file return value -- 1 if success, 0 if failure created -- 95nov15, cca ---------------------------------------------------- */ int Tree_readFromBinaryFile ( Tree *tree, FILE *fp ) { int rc ; int itemp[2] ; /* --------------- check the input --------------- */ if ( tree == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Tree_readFromBinaryFile(%p,%p)" "\n bad input\n", tree, fp) ; return(0) ; } /* --------------------- clear the data fields --------------------- */ Tree_clearData(tree) ; /* --------------------------------- read in the two scalar parameters number of nodes and the root --------------------------------- */ if ( (rc = fread((void *) itemp, sizeof(int), 2, fp)) != 2 ) { fprintf(stderr, "\n error in Tree_readFromBinaryFile(%p,%p)" "\n itemp(2) : %d items of %d read\n", tree, fp, rc, 2) ; return(0) ; } /* --------------------- initialize the object --------------------- */ Tree_init1(tree, itemp[0]) ; tree->root = itemp[1] ; /* ------------------- read in the vectors ------------------- */ if ( (rc = fread((void *) tree->par, sizeof(int), tree->n, fp)) != tree->n ) { fprintf(stderr, "\n par : error in Tree_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", tree, fp, rc, tree->n) ; return(0) ; } if ( (rc = fread((void *) tree->fch, sizeof(int), tree->n, fp)) != tree->n ) { fprintf(stderr, "\n fch : error in Tree_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", tree, fp, rc, tree->n) ; return(0) ; } if ( (rc = fread((void *) tree->sib, sizeof(int), tree->n, fp)) != tree->n ) { fprintf(stderr, "\n sib : error in Tree_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", tree, fp, rc, tree->n) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to write an Tree object to a file input -- fn -- filename *.treeb -- binary *.treef -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 95nov15, cca -------------------------------------------- */ int Tree_writeToFile ( Tree *tree, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( tree == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in Tree_writeToFile(%p,%s)" "\n bad input\n", tree, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in Tree_writeToFile(%p,%s)" "\n unable to open file %s", tree, fn, fn) ; rc = 0 ; } else { rc = Tree_writeToBinaryFile(tree, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in Tree_writeToFile(%p,%s)" "\n unable to open file %s", tree, fn, fn) ; rc = 0 ; } else { rc = Tree_writeToFormattedFile(tree, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in Tree_writeToFile(%p,%s)" "\n unable to open file %s", tree, fn, fn) ; rc = 0 ; } else { rc = Tree_writeForHumanEye(tree, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in Tree_writeToFile(%p,%s)" "\n unable to open file %s", tree, fn, fn) ; rc = 0 ; } else { rc = Tree_writeForHumanEye(tree, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to write an Tree object to a formatted file return value -- 1 if success, 0 otherwise created -- 95nov15, cca ------------------------------------------------------ */ int Tree_writeToFormattedFile ( Tree *tree, FILE *fp ) { int ierr, rc ; /* --------------- check the input --------------- */ if ( tree == NULL || fp == NULL || tree->n <= 0 ) { fprintf(stderr, "\n fatal error in Tree_writeToFormattedFile(%p,%p)" "\n bad input\n", tree, fp) ; exit(-1) ; } /* ------------------------------------- write out the two scalar parameters ------------------------------------- */ rc = fprintf(fp, "\n %d %d", tree->n, tree->root) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Tree_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", tree, fp, rc) ; return(0) ; } /* --------------------- write out the vectors --------------------- */ IVfp80(fp, tree->n, tree->par, 80, &ierr) ; IVfp80(fp, tree->n, tree->fch, 80, &ierr) ; IVfp80(fp, tree->n, tree->sib, 80, &ierr) ; return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to write an Tree object to a binary file return value -- 1 if success, 0 otherwise created -- 95nov15, cca --------------------------------------------------- */ int Tree_writeToBinaryFile ( Tree *tree, FILE *fp ) { int rc ; int itemp[2] ; /* --------------- check the input --------------- */ if ( tree == NULL || fp == NULL || tree->n <= 0 ) { fprintf(stderr, "\n fatal error in Tree_writeToBinaryFile(%p,%p)" "\n bad input\n", tree, fp) ; exit(-1) ; } itemp[0] = tree->n ; itemp[1] = tree->root ; rc = fwrite((void *) itemp, sizeof(int), 2, fp) ; if ( rc != 2 ) { fprintf(stderr, "\n error in Tree_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", tree, fp, rc, 2) ; return(0) ; } rc = fwrite((void *) tree->par, sizeof(int), tree->n, fp) ; if ( rc != tree->n ) { fprintf(stderr, "\n error in Tree_writeToBinaryFile(%p,%p)" "\n tree->par, %d of %d items written\n", tree, fp, rc, tree->n) ; return(0) ; } rc = fwrite((void *) tree->fch, sizeof(int), tree->n, fp) ; if ( rc != tree->n ) { fprintf(stderr, "\n error in Tree_writeToBinaryFile(%p,%p)" "\n tree->fch, %d of %d items written\n", tree, fp, rc, tree->n) ; return(0) ; } rc = fwrite((void *) tree->sib, sizeof(int), tree->n, fp) ; if ( rc != tree->n ) { fprintf(stderr, "\n error in Tree_writeToBinaryFile(%p,%p)" "\n tree->sib, %d of %d items written\n", tree, fp, rc, tree->n) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to write an Tree object for a human eye return value -- 1 if success, 0 otherwise created -- 95nov15, cca -------------------------------------------------- */ int Tree_writeForHumanEye ( Tree *tree, FILE *fp ) { int rc, v ; if ( tree == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in Tree_writeForHumanEye(%p,%p)" "\n bad input\n", tree, fp) ; exit(-1) ; } if ( (rc = Tree_writeStats(tree, fp)) == 0 ) { fprintf(stderr, "\n fatal error in Tree_writeForHumanEye(%p,%p)" "\n rc = %d, return from Tree_writeStats(%p,%p)\n", tree, fp, rc, tree, fp) ; return(0) ; } fprintf(fp, "\n vertex parent fchild sibling") ; for ( v = 0 ; v < tree->n ; v++ ) { fprintf(fp, "\n %5d %9d %9d %9d :", v, tree->par[v], tree->fch[v], tree->sib[v]) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- purpose -- to write out the statistics for the Tree object return value -- 1 if success, 0 otherwise created -- 95nov15, cca ---------------------------------------------------------- */ int Tree_writeStats ( Tree *tree, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( tree == NULL || fp == NULL ) { fprintf(stderr, "\n error in Tree_writeStats(%p,%p)" "\n bad input\n", tree, fp) ; exit(-1) ; } rc = fprintf(fp, "\n Tree : tree object, %d vertices, root = %d, takes %d bytes", tree->n, tree->root, Tree_sizeOf(tree)) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in Tree_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", tree, fp, rc) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ ems of %dTree/src/basics.c010064400020550007177000000055470653410605700152100ustar00clevecompmath00000400000006/* basics.c */ #include "../Tree.h" #define MYTRACE 0 #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- create and return a new Tree object created -- 95nov15, cca ----------------------------------------------- */ Tree * Tree_new ( void ) { Tree *tree ; #if MYTRACE > 0 fprintf(stdout, "\n just inside Tree_new()") ; fflush(stdout) ; #endif ALLOCATE(tree, struct _Tree, 1) ; Tree_setDefaultFields(tree) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving Tree_new()") ; fflush(stdout) ; #endif return(tree) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- set the default fields for the Tree object created -- 95nov15, cca ------------------------------------------------------ */ void Tree_setDefaultFields ( Tree *tree ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside Tree_setDefaultFields(%)", g) ; fflush(stdout) ; #endif if ( tree == NULL ) { fprintf(stderr, "\n fatal error in Tree_setDefaultFields(%p)" "\n tree is NULL\n", tree) ; exit(-1) ; } tree->n = 0 ; tree->root = -1 ; tree->par = NULL ; tree->fch = NULL ; tree->sib = NULL ; #if MYTRACE > 0 fprintf(stdout, "\n leaving Tree_setDefaultFields(%)", tree) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- clear the data fields created -- 95nov15, cca -------------------------------- */ void Tree_clearData ( Tree *tree ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside Tree_clearData(%)", tree) ; fflush(stdout) ; #endif if ( tree == NULL ) { fprintf(stderr, "\n fatal error in Tree_clearData(%p)" "\n tree is NULL\n", tree) ; exit(-1) ; } if ( tree->par != NULL ) { IVfree(tree->par) ; } if ( tree->fch != NULL ) { IVfree(tree->fch) ; } if ( tree->sib != NULL ) { IVfree(tree->sib) ; } Tree_setDefaultFields(tree) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving Tree_clearData(%)", tree) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- free the Tree object created -- 95nov15, cca -------------------------------- */ void Tree_free ( Tree *tree ) { #if MYTRACE > 0 fprintf(stdout, "\n just inside Tree_free(%)", tree) ; fflush(stdout) ; #endif if ( tree == NULL ) { fprintf(stderr, "\n fatal error in Tree_free(%p)" "\n tree is NULL\n", tree) ; exit(-1) ; } Tree_clearData(tree) ; FREE(tree) ; #if MYTRACE > 0 fprintf(stdout, "\n leaving Tree_free(%)", tree) ; fflush(stdout) ; #endif return ; } /*--------------------------------------------------------------------*/ Tree/src/compress.c010064400020550007177000000067200653410605700155710ustar00clevecompmath00000400000006/* compress.c */ #include "../Tree.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------- create and return an IV object that contains the map from vertices to fundamental chains. return value -- # of fundamental chains created -- 96jun23, cca ------------------------------------------- */ IV * Tree_fundChainMap ( Tree *tree ) { int nfc, u, v ; int *map ; IV *mapIV ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n <= 0 ) { fprintf(stderr, "\n fatal error in Tree_fundChainMap(%p)" "\n bad input\n", tree) ; exit(-1) ; } mapIV = IV_new() ; IV_init(mapIV, tree->n, NULL) ; map = IV_entries(mapIV) ; for ( v = Tree_postOTfirst(tree), nfc = 0 ; v != -1 ; v = Tree_postOTnext(tree, v) ) { if ( (u = tree->fch[v]) == -1 || tree->sib[u] != -1 ) { /* -------------------- v starts a new chain -------------------- */ map[v] = nfc++ ; } else { /* ----------------------------------------------- v belongs in the same chain as its only child u ----------------------------------------------- */ map[v] = map[u] ; } } return(mapIV) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- compress a tree based on a map from old vertices to new vertices. the restriction on the map is that the set {u | map[u] = U} must be connected for all U. created -- 95nov15, cca modified -- 96jan04, cca bug fixed, N computed incorrectly modified -- 96jun23, cca in calling sequence, int map[] converted to IV *mapIV ----------------------------------------------------------------- */ Tree * Tree_compress ( Tree *tree, IV *mapIV ) { int n, N, u, U, v, V ; int *head, *link, *map ; Tree *tree2 ; /* --------------- check the input --------------- */ if ( tree == NULL || (n = tree->n) <= 0 || mapIV == NULL || n != IV_size(mapIV) || (map = IV_entries(mapIV)) == NULL ) { fprintf(stderr, "\n fatal error in Tree_compress(%p,%p)" "\n bad input\n", tree, mapIV) ; exit(-1) ; } /* ----------------------- initialize the new tree ----------------------- */ N = 1 + IV_max(mapIV) ; tree2 = Tree_new() ; Tree_init1(tree2, N) ; /* ----------------------------------------------------------- get the head/link construct to map old nodes into new nodes ----------------------------------------------------------- */ head = IVinit(N, -1) ; link = IVinit(n, -1) ; for ( v = 0 ; v < n ; v++ ) { if ( (V = map[v]) < 0 || V >= N ) { fprintf(stderr, "\n fatal error in Tree_compress(%p,%p)" "\n map[%d] = %d, N = %d\n", tree, map, v, V, N) ; exit(-1) ; } link[v] = head[V] ; head[V] = v ; } /* --------------------- fill the tree vectors --------------------- */ for ( U = 0 ; U < N ; U++ ) { for ( u = head[U] ; u != -1 ; u = link[u] ) { if ( (v = tree->par[u]) == -1 ) { tree2->par[U] = -1 ; break ; } else if ( (V = map[v]) != U ) { tree2->par[U] = V ; break ; } } } Tree_setFchSibRoot(tree2) ; /* ------------------------ free the working storage ------------------------ */ IVfree(head) ; IVfree(link) ; return(tree2) ; } /*--------------------------------------------------------------------*/ Tree/src/draw.c010064400020550007177000000313460665245434500147040ustar00clevecompmath00000400000006/* draw.c */ #include "../Tree.h" #define MYDEBUG 1 /*--------------------------------------------------------------------*/ static void findLocalCoords ( int n, double x[], double xloc[], double rscale, double radius[], double xmin, double xmax ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to write an EPS file with a picture of a tree. each node can have its own radius and label filename -- name of the file to be written xDV -- x coordinates yDV -- y coordinates rscale -- scaling factor for radius of nodes radiusDV -- radius of nodes, if NULL then radius = 1 labelflag -- flag to specify whether labels are to be drawn 1 -- draw labels otherwise -- do not draw labels fontscale -- scaling factor for font labelsIV -- IV object that contains the labels of the nodes. if NULL then the node ids are used bbox[] -- bounding box for figure bbox[0] -- x_min bbox[1] -- y_min bbox[2] -- x_max bbox[3] -- y_max frame[] -- frame to hold tree frame[0] -- x_min frame[1] -- y_min frame[2] -- x_max frame[3] -- y_max bounds[] -- bounds for local coordinates if bounds is NULL then the tree fills the frame. note, this is a nonlinear process when the nodes have non-constant radii, and may not converge when the maximum radius is large when compared to the frame. if the process does not converge, a message is printed and the program exits. else bounds[0] -- xi_min bounds[1] -- eta_min bounds[2] -- xi_max bounds[3] -- eta_max endif recommendations, bbox[] = { 0, 0, 500, 200 } for tall skinny trees { 0, 0, 500, 500 } for wide trees frame[0] = bbox[0] + 10 frame[1] = bbox[1] + 10 frame[2] = bbox[2] - 10 frame[3] = bbox[3] - 10 return value 1 -- normal return -1 -- tree is NULL -2 -- filename is NULL -3 -- xDV is NULL -4 -- yDV is NULL -5 -- rscale is negative -6 -- fontscale is negative -7 -- bbox is NULL -8 -- frame is NULL created -- 99jan07, cca ------------------------------------------------------------ */ int Tree_drawToEPS ( Tree *tree, char *filename, DV *xDV, DV *yDV, double rscale, DV *radiusDV, int labelflag, double fontscale, IV *labelsIV, double bbox[], double frame[], double bounds[] ) { double etamax, etamin, ximax, ximin, xmax, xmin, xrmax, xrmin, xscale, ymax, ymin, yrmax, yrmin, yscale ; double *radius, *x, *xloc, *y, *yloc ; FILE *fp ; int count, J, K, n ; int *fch, *par, *sib ; /* --------------- check the input --------------- */ if ( tree == NULL ) { fprintf(stderr, "\n error in Tree_drawToEPS()" "\n tree is NULL\n") ; return(-1) ; } if ( filename == NULL ) { fprintf(stderr, "\n error in Tree_drawToEPS()" "\n filename is NULL\n") ; return(-2) ; } if ( xDV == NULL ) { fprintf(stderr, "\n error in Tree_drawToEPS()" "\n xDV is NULL\n") ; return(-3) ; } if ( yDV == NULL ) { fprintf(stderr, "\n error in Tree_drawToEPS()" "\n yDV is NULL\n") ; return(-4) ; } if ( rscale < 0.0 ) { fprintf(stderr, "\n error in Tree_drawToEPS()" "\n rscale is negative\n") ; return(-5) ; } if ( fontscale < 0.0 ) { fprintf(stderr, "\n error in Tree_drawToEPS()" "\n fontscale is negative\n") ; return(-6) ; } if ( bbox == NULL ) { fprintf(stderr, "\n error in Tree_drawToEPS()" "\n bbox is NULL\n") ; return(-7) ; } if ( frame == NULL ) { fprintf(stderr, "\n error in Tree_drawToEPS()" "\n frame is NULL\n") ; return(-8) ; } n = tree->n ; par = tree->par ; fch = tree->fch ; sib = tree->sib ; x = DV_entries(xDV) ; y = DV_entries(yDV) ; if ( radiusDV != NULL ) { radius = DV_entries(radiusDV) ; } else { radius = NULL ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n x") ; DVfprintf(stdout, n, x) ; fprintf(stdout, "\n\n y") ; DVfprintf(stdout, n, y) ; if ( radius != NULL ) { fprintf(stdout, "\n\n radius") ; DVfprintf(stdout, n, radius) ; } #endif xloc = DVinit(n, 0.0) ; yloc = DVinit(n, 0.0) ; if ( bounds != NULL ) { /* ------------------------------------------ get the local coordinates w.r.t the bounds ------------------------------------------ */ double etamax, etamin, ximax, ximin, xmax, xmin, xoff, xscale, ymax, ymin, yoff, yscale ; xmin = frame[0] ; xmax = frame[2] ; ximin = bounds[0] ; ximax = bounds[2] ; xoff = (xmin*ximax - xmax*ximin)/(ximax - ximin) ; xscale = (xmax - xmin)/(ximax - ximin) ; for ( J = 0 ; J < n ; J++ ) { xloc[J] = xoff + xscale*x[J] ; } ymin = frame[1] ; ymax = frame[3] ; etamin = bounds[1] ; etamax = bounds[3] ; yoff = (ymin*etamax - ymax*etamin)/(etamax - etamin) ; yscale = (ymax - ymin)/(etamax - etamin) ; for ( J = 0 ; J < n ; J++ ) { yloc[J] = yoff + yscale*y[J] ; } } else { /* ----------------------------------------- scale x[] and y[] to fit within the frame ----------------------------------------- */ xmin = frame[0] ; ymin = frame[1] ; xmax = frame[2] ; ymax = frame[3] ; #if MYDEBUG > 0 fprintf(stdout, "\n\n xmin = %.3g, xmax = %.3g", xmin, xmax) ; #endif findLocalCoords(n, x, xloc, rscale, radius, xmin, xmax) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n ymin = %.3g, ymax = %.3g", ymin, ymax) ; #endif findLocalCoords(n, y, yloc, rscale, radius, ymin, ymax) ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n xloc") ; DVfprintf(stdout, n, xloc) ; #endif #if MYDEBUG > 0 fprintf(stdout, "\n\n yloc") ; DVfprintf(stdout, n, yloc) ; #endif /* ------------- open the file ------------- */ if ( (fp = fopen(filename, "w")) == NULL ) { fprintf(stderr, "\n unable to open file %s", filename) ; exit(-1) ; } /* ---------------------------- print the header information ---------------------------- */ fprintf(fp, "%%!PS-Adobe-2.0 EPSF-1.2" "\n%%%%BoundingBox: %.3g %.3g %.3g %.3g", bbox[0], bbox[1], bbox[2], bbox[3]) ; fprintf(fp, "\n /CSH {" "\n %%" "\n %% center show a string" "\n %%" "\n %% stack" "\n %% string str" "\n %%" "\n dup stringwidth pop 2 div neg 0 rmoveto" "\n show" "\n } def") ; fprintf(fp, "\n /ML {" "\n %%" "\n %% moveto lineto" "\n %%" "\n %% stack" "\n %% x0 y0 x1 y1" "\n %%" "\n moveto lineto" "\n } def") ; fprintf(fp, "\n /FC {" "\n %%" "\n %% draw filled circle" "\n %%" "\n %% stack" "\n %% x y r" "\n %%" "\n newpath 2 index 1 index add 2 index moveto 0 360 arc fill" "\n } def") ; fprintf(fp, "\n /OC {" "\n %%" "\n %% draw open circle" "\n %%" "\n %% stack" "\n %% x y r" "\n %%" "\n newpath 2 index 1 index add 2 index moveto 0 360 arc stroke" "\n } def") ; fprintf(fp, "\n /rscale %.3f def", rscale) ; fprintf(fp, "\n /fontscale %.3f def", fontscale) ; /* -------------- draw the edges -------------- */ fprintf(fp, "\n %.3g %.3g %.3g %.3g rectclip", frame[0], frame[1], frame[2] - frame[0], frame[3] - frame[1]) ; par = tree->par ; count = 0 ; for ( J = 0 ; J < n ; J++ ) { if ( (K = par[J]) != -1 ) { if ( count == 0 ) { fprintf(fp, "\n newpath") ; } fprintf(fp, "\n %.3g %.3g %.3g %.3g ML", xloc[J], yloc[J], xloc[K], yloc[K]) ; count++ ; if ( count == 100 ) { fprintf(fp, "\n stroke") ; count = 0 ; } } } if ( count > 0 ) { fprintf(fp, "\n stroke") ; } /* ------------------------- draw the nodes and labels ------------------------- */ fprintf(fp, "\n\n gsave") ; if ( labelflag == 1 ) { fprintf(fp, "\n /Helvetica-Bold findfont fontscale scalefont setfont") ; } if ( radius == NULL ) { for ( J = 0 ; J < n ; J++ ) { fprintf(fp, "\n 1.0 setgray") ; fprintf(fp, " %.3g %.3g %.3g FC", xloc[J], yloc[J], rscale) ; fprintf(fp, "\n 0.0 setgray") ; fprintf(fp, " %.3g %.3g %.3g OC", xloc[J], yloc[J], rscale) ; if ( labelflag == 1 ) { fprintf(fp, "\n %.3g %.3g moveto ", xloc[J], yloc[J] - 0.5*rscale) ; if ( labelsIV != NULL ) { fprintf(fp, " (%d) CSH", IV_entry(labelsIV, J)) ; } else { fprintf(fp, " (%d) CSH", J) ; } } } } else { for ( J = 0 ; J < n ; J++ ) { fprintf(fp, "\n 1.0 setgray") ; fprintf(fp, " %.3g %.3g %.3g FC", xloc[J], yloc[J], rscale*radius[J]) ; fprintf(fp, "\n 0.0 setgray") ; fprintf(fp, " %.3g %.3g %.3g OC", xloc[J], yloc[J], rscale*radius[J]) ; if ( labelflag == 1 ) { fprintf(fp, "\n %.3g %.3g %.3g sub moveto ", xloc[J], yloc[J], 0.25*fontscale) ; if ( labelsIV != NULL ) { fprintf(fp, " (%d) CSH", IV_entry(labelsIV, J)) ; } else { fprintf(fp, " (%d) CSH", J) ; } } } } fprintf(fp, "\n\n grestore") ; fprintf(fp, "\n %.3g %.3g %.3g %.3g rectstroke", frame[0], frame[1], frame[2] - frame[0], frame[3] - frame[1]) ; fprintf(fp, "\n\n showpage") ; return(1) ; } /*--------------------------------------------------------------------*/ static void findLocalCoords ( int n, double x[], double xloc[], double rscale, double radius[], double xmin, double xmax ) { int J, Jmax, Jmin ; double b1, b2, locwidth, width, ximax, ximin, xlocmax, xlocmin, xoff, xscale ; width = xmax - xmin ; ximin = DVmin(n, x, &J) ; ximax = DVmax(n, x, &J) ; #if MYDEBUG > 0 fprintf(stdout, "\n ximin %f, ximax %f", ximin, ximax) ; #endif if ( ximax == ximin ) { DVfill(n, xloc, 0.5*(xmax+xmin)) ; return ; } xscale = width/(ximax - ximin) ; #if MYDEBUG > 0 fprintf(stdout, "\n initial xscale %f", xscale) ; #endif for ( J = 0 ; J < n ; J++ ) { xloc[J] = xmin + xscale*(x[J] - ximin) ; } while ( 1 ) { if ( radius == NULL ) { xlocmin = xloc[0] - rscale ; xlocmax = xloc[0] + rscale ; Jmin = Jmax = 0 ; for ( J = 0 ; J < n ; J++ ) { if ( xlocmin > xloc[J] - rscale ) { xlocmin = xloc[J] - rscale ; Jmin = J ; } if ( xlocmax < xloc[J] + rscale ) { xlocmax = xloc[J] + rscale ; Jmax = J ; } } } else { xlocmin = xloc[0] - rscale*radius[0] ; xlocmax = xloc[0] + rscale*radius[0] ; Jmin = Jmax = 0 ; for ( J = 0 ; J < n ; J++ ) { if ( xlocmin > xloc[J] - rscale*radius[J] ) { xlocmin = xloc[J] - rscale*radius[J] ; Jmin = J ; } if ( xlocmax < xloc[J] + rscale*radius[J] ) { xlocmax = xloc[J] + rscale*radius[J] ; Jmax = J ; } } } #if MYDEBUG > 0 fprintf(stdout, "\n\n Jmin = %d, Jmax = %d", Jmin, Jmax) ; fprintf(stdout, "\n xlocmin %f, xlocmax %f", xlocmin, xlocmax) ; #endif if ( Jmin == Jmax ) { DVfill(n, xloc, (xmin + xmax)/2) ; #if MYDEBUG > 0 fprintf(stdout, "\n leaving") ; #endif break ; } else { locwidth = xlocmax - xlocmin ; #if MYDEBUG > 0 fprintf(stdout, "\n width %f, locwidth %f", width, locwidth) ; #endif if ( locwidth > 1.01*width || locwidth < 0.99*width ) { if ( radius == NULL ) { b1 = xmin + rscale ; b2 = xmax - rscale ; } else { b1 = xmin + rscale*radius[Jmin] ; b2 = xmax - rscale*radius[Jmax] ; } if ( b1 > b2 ) { fprintf(stderr, "\n\n error in Tree_drawEPS()" "\n nonlinear process is unable to converge" "\n reduce radius scaling factor\n") ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n 1. x[%d] = %f, x[%d] = %f", Jmin, x[Jmin], Jmax, x[Jmax]) ; fprintf(stdout, "\n 1. b1 = %f, b2 = %f", b1, b2) ; #endif xscale = (b2 - b1)/(x[Jmax] - x[Jmin]) ; xoff = -(b2*x[Jmin] - b1*x[Jmax])/(x[Jmax] - x[Jmin]) ; #if MYDEBUG > 0 fprintf(stdout, "\n 1. xscale = %f, xoff = %f", xscale, xoff) ; #endif for ( J = 0 ; J < n ; J++ ) { xloc[J] = xoff + xscale*x[J] ; } } else { break ; } } } return ; } /*--------------------------------------------------------------------*/ ox[1], bbox[2], bbox[3]) ; fprintf(fp, "\n /CSH {" "\n %%" "\n %% center show a string" "\n %%" "\n %% stack" "\n %% string str" "\n %%" "\n dup stringwidth pop 2 div neg 0 rmoveto" "\n show" "\n Tree/src/getCoords.c010064400020550007177000000072300665245402100156620ustar00clevecompmath00000400000006/* getCoords.c */ #include "../Tree.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to get simple x[] and y[] coordinates for the tree vertices return values -- 1 -- normal return -1 -- tree is NULL -2 -- heightflag is invalid -3 -- coordflag is invalid -4 -- xDV is NULL -5 -- yDV is NULL created -- 99jan07, cca ------------------------------------------------ */ int Tree_getSimpleCoords ( Tree *tree, char heightflag, char coordflag, DV *xDV, DV *yDV ) { double *x, *y ; int count, I, J, n, nleaves ; int *fch, *par, *sib ; /* --------------- check the input --------------- */ if ( tree == NULL ) { fprintf(stderr, "\n error in Tree_getSimpleCoords()" "\n tree is NULL\n") ; return(-1) ; } if ( heightflag != 'D' && heightflag != 'H' ) { fprintf(stderr, "\n error in Tree_getSimpleCoords()" "\n invalid heightflag = %c\n", heightflag) ; return(-2) ; } if ( coordflag != 'C' && coordflag != 'P' ) { fprintf(stderr, "\n error in Tree_getSimpleCoords()" "\n invalid coordflag = %c\n", coordflag) ; return(-3) ; } if ( xDV == NULL ) { fprintf(stderr, "\n error in Tree_getSimpleCoords()" "\n xDV is NULL\n") ; return(-4) ; } if ( yDV == NULL ) { fprintf(stderr, "\n error in Tree_getSimpleCoords()" "\n yDV is NULL\n") ; return(-5) ; } n = tree->n ; par = tree->par ; fch = tree->fch ; sib = tree->sib ; DV_setSize(xDV, n) ; DV_setSize(yDV, n) ; x = DV_entries(xDV) ; y = DV_entries(yDV) ; switch ( heightflag ) { case 'D' : { int J, K, maxdepth ; for ( J = Tree_preOTfirst(tree), maxdepth = 0 ; J != -1 ; J = Tree_preOTnext(tree, J) ) { if ( (K = par[J]) == -1 ) { y[J] = 0.0 ; } else { y[J] = y[K] + 1.0 ; } if ( maxdepth < y[J] ) { maxdepth = y[J] ; } } if ( coordflag == 'C' ) { for ( J = 0 ; J < n ; J++ ) { y[J] = maxdepth - y[J] ; } } } break ; case 'H' : { int height, I, J, maxheight ; for ( J = Tree_postOTfirst(tree), maxheight = 0 ; J != -1 ; J = Tree_postOTnext(tree, J) ) { if ( (I = fch[J]) == -1 ) { y[J] = 0.0 ; } else { height = y[I] ; for ( I = sib[I] ; I != -1 ; I = sib[I] ) { if ( height < y[I] ) { height = y[I] ; } } y[J] = height + 1.0 ; } if ( maxheight < y[J] ) { maxheight = y[J] ; } } if ( coordflag == 'P' ) { for ( J = 0 ; J < n ; J++ ) { y[J] = maxheight - y[J] ; } } } break ; default : break ; } #if MYDEBUG > 0 fprintf(stdout, "\n\n y") ; DV_writeForHumanEye(yDV, stdout) ; #endif DV_zero(xDV) ; nleaves = 0 ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { if ( fch[J] == -1 ) { x[J] = nleaves++ ; } else { for ( I = fch[J], count = 0 ; I != -1 ; I = sib[I] ) { x[J] += x[I] ; count++ ; } x[J] /= count ; } } if ( coordflag == 'C' ) { for ( J = 0 ; J < n ; J++ ) { x[J] = x[J] / nleaves ; } } else { double r, theta ; for ( J = 0 ; J < n ; J++ ) { theta = 6.283185 * x[J] / nleaves ; r = y[J] ; x[J] = r * cos(theta) ; y[J] = r * sin(theta) ; } } #if MYDEBUG > 0 fprintf(stdout, "\n\n x") ; DV_writeForHumanEye(xDV, stdout) ; #endif return(1) ; } /*--------------------------------------------------------------------*/ double *x, *y ; int count, I, J, n, nleaves ; int *fch, *par, *sib ; /* --------------- check the input --------------- */ if ( tree == NULL ) { fprintf(stderr, "\n error in Tree_getSimpleCoords()" "\n tree is NULL\n") ; return(-1) ; } if ( heightflag != 'D' && heightflag != 'H' ) { fprintf(stderr, "\n error in Tree_Tree/src/init.c010064400020550007177000000111510653410605700146730ustar00clevecompmath00000400000006/* init.c */ #include "../Tree.h" /*--------------------------------------------------------------------*/ /* ----------------------- simplest constructor created -- 95nov15, cca ----------------------- */ void Tree_init1 ( Tree *tree, int size ) { /* --------------- check the input --------------- */ if ( tree == NULL || size < 0 ) { fprintf(stderr, "\n fatal error in Tree_init1(%p,%d)" "\n bad input\n", tree, size) ; exit(-1) ; } /* ----------------------- clear any previous data ----------------------- */ Tree_clearData(tree) ; /* ----------------------------------------------- set size field and initialize the three vectors ----------------------------------------------- */ tree->n = size ; if ( size > 0 ) { tree->par = IVinit(size, -1) ; tree->fch = IVinit(size, -1) ; tree->sib = IVinit(size, -1) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------- initialize given a parent vector created -- 95nov15, cca -------------------------------- */ void Tree_init2 ( Tree *tree, int size, int par[] ) { /* --------------- check the input --------------- */ if ( tree == NULL || size <= 0 || par == NULL ) { fprintf(stderr, "\n fatal error in Tree_init2(%p,%d,%p)" "\n bad input\n", tree, size, par) ; exit(-1) ; } /* ---------------------------- first use simple initializer ---------------------------- */ Tree_init1(tree, size) ; /* ------------------ copy parent vector ------------------ */ IVcopy(size, tree->par, par) ; /* ------------------------- set fch[], sib[] and root ------------------------- */ Tree_setFchSibRoot(tree) ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------- initialize given the tree vectors created -- 95nov15, cca --------------------------------- */ void Tree_init3 ( Tree *tree, int size, int par[], int fch[], int sib[] ) { /* --------------- check the input --------------- */ if ( tree == NULL || size <= 0 || par == NULL || fch == NULL || sib == NULL ) { fprintf(stderr, "\n fatal error in Tree_init3(%p,%d,%p,%p,%p)" "\n bad input\n", tree, size, par, fch, sib) ; exit(-1) ; } /* ---------------------------- first use simple initializer ---------------------------- */ Tree_init1(tree, size) ; /* ---------------------- copy the three vectors ---------------------- */ IVcopy(size, tree->par, par) ; IVcopy(size, tree->fch, fch) ; IVcopy(size, tree->sib, sib) ; /* -------- set root -------- */ Tree_setRoot(tree) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ set the fch[], sib[] and root fields created -- 95nov15, cca ------------------------------------ */ void Tree_setFchSibRoot ( Tree *tree ) { int n, root, u, v ; int *fch, *par, *sib ; /* --------------- check the input --------------- if ( tree == NULL || (n = tree->n) < 1 ) { */ if ( tree == NULL ) { fprintf(stderr, "\n fatal error in Tree_setFchSibRoot(%p)" "\n bad input\n", tree) ; exit(-1) ; } if ( (n = tree->n) < 1 ) { return ; } par = tree->par ; fch = tree->fch ; sib = tree->sib ; /* --------------------- initialize the fields --------------------- */ IVfill(n, tree->fch, -1) ; IVfill(n, tree->sib, -1) ; root = -1 ; /* -------------- set the fields -------------- for ( u = 0 ; u < n ; u++ ) { */ for ( u = n - 1 ; u >= 0 ; u-- ) { if ( (v = par[u]) != -1 ) { sib[u] = fch[v] ; fch[v] = u ; } else { sib[u] = root ; root = u ; } } tree->root = root ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the root field created -- 95nov15, cca ----------------------- */ void Tree_setRoot ( Tree *tree ) { int n, root, u ; int *par, *sib ; /* --------------- check the input --------------- */ if ( tree == NULL || (n = tree->n) < 1 ) { fprintf(stderr, "\n fatal error in Tree_setRoot(%p)" "\n bad input\n", tree) ; exit(-1) ; } n = tree->n ; par = tree->par ; sib = tree->sib ; root = -1 ; /* -------------- set the fields -------------- */ for ( u = 0 ; u < n ; u++ ) { if ( par[u] == -1 ) { sib[u] = root ; root = u ; } } tree->root = root ; return ; } /*--------------------------------------------------------------------*/ Tree/src/instance.c010064400020550007177000000051620654031412400155320ustar00clevecompmath00000400000006/* instance.c */ #include "../Tree.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- return the number of nodes in the tree created -- 98jun12, cca ------------------------------------------------- */ int Tree_nnodes ( Tree *tree ) { /* --------------- check the input --------------- */ if ( tree == NULL ) { fprintf(stderr, "\n fatal error in Tree_nnodes(%p)" "\n bad input\n", tree) ; exit(-1) ; } return(tree->n) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- purpose -- return the root of the tree created -- 98jun12, cca -------------------------------------- */ int Tree_root ( Tree *tree ) { /* --------------- check the input --------------- */ if ( tree == NULL ) { fprintf(stderr, "\n fatal error in Tree_root(%p)" "\n bad input\n", tree) ; exit(-1) ; } return(tree->root) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- return a pointer to the parent vector created -- 98jun12, cca ------------------------------------------------ */ int * Tree_par ( Tree *tree ) { /* --------------- check the input --------------- */ if ( tree == NULL ) { fprintf(stderr, "\n fatal error in Tree_par(%p)" "\n bad input\n", tree) ; exit(-1) ; } return(tree->par) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- return a pointer to the first child vector created -- 98jun12, cca ----------------------------------------------------- */ int * Tree_fch ( Tree *tree ) { /* --------------- check the input --------------- */ if ( tree == NULL ) { fprintf(stderr, "\n fatal error in Tree_fch(%p)" "\n bad input\n", tree) ; exit(-1) ; } return(tree->fch) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- return a pointer to the sibling vector created -- 98jun12, cca ------------------------------------------------- */ int * Tree_sib ( Tree *tree ) { /* --------------- check the input --------------- */ if ( tree == NULL ) { fprintf(stderr, "\n fatal error in Tree_sib(%p)" "\n bad input\n", tree) ; exit(-1) ; } return(tree->sib) ; } /*--------------------------------------------------------------------*/ Tree/src/justify.c010064400020550007177000000117230653410605700154320ustar00clevecompmath00000400000006/* justify.c */ #include "../Tree.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ left-justify a tree by subtree size children are linked in ascending order of their subtree size created -- 96jun23, cca ------------------------------------------------------------ */ void Tree_leftJustify ( Tree *tree ) { IV *tmetricIV, *vmetricIV ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 ) { fprintf(stderr, "\n fatal error in Tree_leftJustify(%p)" "\n bad input\n", tree) ; exit(-1) ; } /* ------------------------------------------------------------------ set the subtree size metric, left justify and free working storage ------------------------------------------------------------------ */ vmetricIV = IV_new() ; IV_init(vmetricIV, tree->n, NULL) ; IV_fill(vmetricIV, 1) ; tmetricIV = Tree_setSubtreeImetric(tree, vmetricIV) ; Tree_leftJustifyI(tree, tmetricIV) ; IV_free(vmetricIV) ; IV_free(tmetricIV) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ left-justify a tree by a metric children are linked in ascending order of their metric created -- 96jun23, cca ------------------------------------------------------ */ void Tree_leftJustifyI ( Tree *tree, IV *metricIV ) { int i, j, k, n, nexti, prev ; int *fch, *metric, *par, *sib ; /* --------------- check the input --------------- */ if ( tree == NULL || (n = tree->n) <= 0 || metricIV == NULL || n != IV_size(metricIV) || (metric = IV_entries(metricIV)) == NULL ) { fprintf(stderr, "\n fatal error in Tree_leftJustifyI(%p,%p)" "\n bad input\n", tree, metricIV) ; exit(-1) ; } par = tree->par ; fch = tree->fch ; sib = tree->sib ; /* ---------------------------------------------------- sort all children in decreasing order of metric size ---------------------------------------------------- */ for ( k = 0 ; k < n ; k++ ) { for ( i = fch[k], fch[k] = -1 ; i != -1 ; i = nexti ) { nexti = sib[i] ; for ( j = fch[k], prev = -1 ; j != -1 ; j = sib[j] ) { if ( metric[j] < metric[i] ) { break ; } prev = j ; } if ( prev == -1 ) { fch[k] = i ; } else { sib[prev] = i ; } sib[i] = j ; } } /* --------------------------------------------- sort roots in decreasing order of metric size --------------------------------------------- */ for ( i = tree->root, tree->root = -1, prev = -1 ; i != -1 ; i = nexti ) { nexti = sib[i] ; for ( j = tree->root, prev = -1 ; j != -1 ; j = sib[j] ) { if ( metric[j] < metric[i] ) { break ; } prev = j ; } if ( prev == -1 ) { tree->root = i ; } else { sib[prev] = i ; } sib[i] = j ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ left-justify a tree by a metric children are linked in ascending order of their metric created -- 96jun23, cca ------------------------------------------------------ */ void Tree_leftJustifyD ( Tree *tree, DV *metricDV ) { int i, j, k, n, nexti, prev ; int *fch, *par, *sib ; double *metric ; /* --------------- check the input --------------- */ if ( tree == NULL || (n = tree->n) <= 0 || metricDV == NULL || n != DV_size(metricDV) || (metric = DV_entries(metricDV)) == NULL ) { fprintf(stderr, "\n fatal error in Tree_leftJustifyD(%p,%p)" "\n bad input\n", tree, metricDV) ; exit(-1) ; } par = tree->par ; fch = tree->fch ; sib = tree->sib ; /* ---------------------------------------------------- sort all children in decreasing order of metric size ---------------------------------------------------- */ for ( k = 0 ; k < n ; k++ ) { for ( i = fch[k], fch[k] = -1 ; i != -1 ; i = nexti ) { nexti = sib[i] ; for ( j = fch[k], prev = -1 ; j != -1 ; j = sib[j] ) { if ( metric[j] < metric[i] ) { break ; } prev = j ; } if ( prev == -1 ) { fch[k] = i ; } else { sib[prev] = i ; } sib[i] = j ; } } /* --------------------------------------------- sort roots in decreasing order of metric size --------------------------------------------- */ for ( i = tree->root, tree->root = -1, prev = -1 ; i != -1 ; i = nexti ) { nexti = sib[i] ; for ( j = tree->root, prev = -1 ; j != -1 ; j = sib[j] ) { if ( metric[j] < metric[i] ) { break ; } prev = j ; } if ( prev == -1 ) { tree->root = i ; } else { sib[prev] = i ; } sib[i] = j ; } return ; } /*--------------------------------------------------------------------*/ Tree/src/maximizeGain.c010064400020550007177000000062420654303156600163610ustar00clevecompmath00000400000006/* maximizeGain.c */ #include "../Tree.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- given a gain value assigned to each node, find a set of nodes, no two in a child-ancestor relationship, that maximizes the total gain. this problem arises in finding the optimal domain/schur complement partition for a semi-implicit factorization. created -- 98jun20, cca ------------------------------------------------------- */ IV * Tree_maximizeGainIV ( Tree *tree, IV *gainIV, int *ptotalgain, int msglvl, FILE *msgFile ) { char *mark ; int I, J, K, n, ndom, sum, totalgain ; int *compids, *fch, *gain, *par, *sib, *subtreeGain ; IV *compidsIV ; /* --------------- check the input --------------- */ if ( tree == NULL || gainIV == NULL || ptotalgain == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in Tree_maximizeGainIV()" "\n bad input\n") ; exit(-1) ; } n = tree->n ; par = tree->par ; fch = tree->fch ; sib = tree->sib ; if ( n != IV_size(gainIV) ) { fprintf(stderr, "\n fatal error in Tree_maximizeGainIV()" "\n tree size = %d, gain size = %d", tree->n, IV_size(gainIV)) ; exit(-1) ; } gain = IV_entries(gainIV) ; /* -------------------------------------------------- compute the subtree gains and mark candidate roots -------------------------------------------------- */ mark = CVinit(n, 'N') ; subtreeGain = IVinit(n, 0) ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { if ( fch[J] == -1 ) { mark[J] = 'R' ; subtreeGain[J] = gain[J] ; } else { for ( I = fch[J], sum = 0 ; I != -1 ; I = sib[I] ) { sum += subtreeGain[I] ; } if ( gain[J] >= sum ) { subtreeGain[J] = gain[J] ; mark[J] = 'R' ; } else { subtreeGain[J] = sum ; } } } /* ---------------------- compute the total gain ---------------------- */ for ( J = tree->root, totalgain = 0 ; J != -1 ; J = sib[J] ) { totalgain += subtreeGain[J] ; } *ptotalgain = totalgain ; /* ---------------------------------------------- create and initialize the component ids vector ---------------------------------------------- */ compidsIV = IV_new() ; IV_init(compidsIV, n, NULL) ; IV_fill(compidsIV, 0) ; compids = IV_entries(compidsIV) ; /* ---------------------------------------------- fix the component ids of the nodes in the tree ---------------------------------------------- */ for ( J = Tree_preOTfirst(tree), ndom = 0 ; J != -1 ; J = Tree_preOTnext(tree, J) ) { if ( mark[J] == 'R' ) { if ( (K = par[J]) != -1 && compids[K] != 0 ) { compids[J] = compids[K] ; } else { compids[J] = ++ndom ; } } else if ( (K = par[J]) != -1 ) { compids[J] = compids[K] ; } } /* ------------------------ free the working storage ------------------------ */ IVfree(subtreeGain) ; CVfree(mark) ; return(compidsIV) ; } /*--------------------------------------------------------------------*/ Tree/src/metrics.c010064400020550007177000000177620653410605700154140ustar00clevecompmath00000400000006/* metrics.c */ #include "../Tree.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ create and return a subtree metric IV object input : vmetricIV -- a metric defined on the vertices return : tmetricIV -- a metric defined on the subtrees created -- 96jun23, cca ------------------------------------------------------ */ IV * Tree_setSubtreeImetric ( Tree *tree, IV *vmetricIV ) { int u, v ; int *tmetric, *vmetric ; IV *tmetricIV ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n <= 0 || vmetricIV == NULL || tree->n != IV_size(vmetricIV) || (vmetric = IV_entries(vmetricIV)) == NULL ) { fprintf(stderr, "\n fatal error in Tree_setSubtreeImetric(%p,%p)" "\n bad input\n", tree, vmetricIV) ; exit(-1) ; } tmetricIV = IV_new() ; IV_init(tmetricIV, tree->n, NULL) ; tmetric = IV_entries(tmetricIV) ; for ( v = Tree_postOTfirst(tree) ; v != -1 ; v = Tree_postOTnext(tree, v) ) { tmetric[v] = vmetric[v] ; for ( u = tree->fch[v] ; u != -1 ; u = tree->sib[u] ) { tmetric[v] += tmetric[u] ; } } return(tmetricIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ create and return a subtree metric DV object input : vmetricDV -- a metric defined on the vertices return : tmetricDV -- a metric defined on the subtrees created -- 96jun23, cca ------------------------------------------------------ */ DV * Tree_setSubtreeDmetric ( Tree *tree, DV *vmetricDV ) { int u, v ; double *tmetric, *vmetric ; DV *tmetricDV ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n <= 0 || vmetricDV == NULL || tree->n != DV_size(vmetricDV) || (vmetric = DV_entries(vmetricDV)) == NULL ) { fprintf(stderr, "\n fatal error in Tree_setSubtreeImetric(%p,%p)" "\n bad input\n", tree, vmetricDV) ; exit(-1) ; } tmetricDV = DV_new() ; DV_init(tmetricDV, tree->n, NULL) ; tmetric = DV_entries(tmetricDV) ; for ( v = Tree_postOTfirst(tree) ; v != -1 ; v = Tree_postOTnext(tree, v) ) { tmetric[v] = vmetric[v] ; for ( u = tree->fch[v] ; u != -1 ; u = tree->sib[u] ) { tmetric[v] += tmetric[u] ; } } return(tmetricDV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ create and return a depth metric IV object input : vmetricIV -- a metric defined on the vertices output : dmetricIV -- a depth metric defined on the vertices dmetric[u] = vmetric[u] + dmetric[par[u]] if par[u] != -1 = vmetric[u] if par[u] == -1 created -- 96jun23, cca ------------------------------------------------------------ */ IV * Tree_setDepthImetric ( Tree *tree, IV *vmetricIV ) { int u, v ; int *dmetric, *vmetric ; IV *dmetricIV ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 || vmetricIV == NULL || tree->n != IV_size(vmetricIV) || (vmetric = IV_entries(vmetricIV)) == NULL ) { fprintf(stderr, "\n fatal error in Tree_setDepthImetric(%p,%p)" "\n bad input\n", tree, vmetricIV) ; exit(-1) ; } dmetricIV = IV_new() ; IV_init(dmetricIV, tree->n, NULL) ; dmetric = IV_entries(dmetricIV) ; for ( u = Tree_preOTfirst(tree) ; u != -1 ; u = Tree_preOTnext(tree, u) ) { dmetric[u] = vmetric[u] ; if ( (v = tree->par[u]) != -1 ) { dmetric[u] += dmetric[v] ; } } return(dmetricIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ create and return a depth metric DV object input : vmetricDV -- a metric defined on the vertices output : dmetricDV -- a depth metric defined on the vertices dmetric[u] = vmetric[u] + dmetric[par[u]] if par[u] != -1 = vmetric[u] if par[u] == -1 created -- 96jun23, cca ------------------------------------------------------------ */ DV * Tree_setDepthDmetric ( Tree *tree, DV *vmetricDV ) { int u, v ; double *dmetric, *vmetric ; DV *dmetricDV ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 || vmetricDV == NULL || tree->n != DV_size(vmetricDV) || (vmetric = DV_entries(vmetricDV)) == NULL ) { fprintf(stderr, "\n fatal error in Tree_setDepthDmetric(%p,%p)" "\n bad input\n", tree, vmetricDV) ; exit(-1) ; } dmetricDV = DV_new() ; DV_init(dmetricDV, tree->n, NULL) ; dmetric = DV_entries(dmetricDV) ; for ( u = Tree_preOTfirst(tree) ; u != -1 ; u = Tree_preOTnext(tree, u) ) { dmetric[u] = vmetric[u] ; if ( (v = tree->par[u]) != -1 ) { dmetric[u] += dmetric[v] ; } } return(dmetricDV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ create and return a height metric IV object input : vmetricIV -- a metric defined on the vertices output : dmetricIV -- a depth metric defined on the vertices hmetric[v] = vmetric[v] + max{p(u) = v} hmetric[u] if fch[v] != -1 = vmetric[v] if fch[v] == -1 created -- 96jun23, cca ------------------------------------------------------------------ */ IV * Tree_setHeightImetric ( Tree *tree, IV *vmetricIV ) { int u, v, val ; int *hmetric, *vmetric ; IV *hmetricIV ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 || vmetricIV == NULL || tree->n != IV_size(vmetricIV) || (vmetric = IV_entries(vmetricIV)) == NULL ) { fprintf(stderr, "\n fatal error in Tree_setHeightImetric(%p,%p)" "\n bad input\n", tree, vmetricIV) ; if ( tree != NULL ) { Tree_writeForHumanEye(tree, stderr) ; } if ( vmetricIV != NULL ) { IV_writeForHumanEye(vmetricIV, stderr) ; } exit(-1) ; } hmetricIV = IV_new() ; IV_init(hmetricIV, tree->n, NULL) ; hmetric = IV_entries(hmetricIV) ; for ( v = Tree_postOTfirst(tree) ; v != -1 ; v = Tree_postOTnext(tree, v) ) { for ( u = tree->fch[v], val = 0 ; u != -1 ; u = tree->sib[u] ) { if ( val < hmetric[u] ) { val = hmetric[u] ; } } hmetric[v] = val + vmetric[v] ; } return(hmetricIV) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ create and return a height metric DV object input : vmetricDV -- a metric defined on the vertices output : dmetricDV -- a depth metric defined on the vertices hmetric[v] = vmetric[v] + max{p(u) = v} hmetric[u] if fch[v] != -1 = vmetric[v] if fch[v] == -1 created -- 96jun23, cca ------------------------------------------------------------------ */ DV * Tree_setHeightDmetric ( Tree *tree, DV *vmetricDV ) { int u, v, val ; double *hmetric, *vmetric ; DV *hmetricDV ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 || vmetricDV == NULL || tree->n != DV_size(vmetricDV) || (vmetric = DV_entries(vmetricDV)) == NULL ) { fprintf(stderr, "\n fatal error in Tree_setHeightDmetric(%p,%p)" "\n bad input\n", tree, vmetricDV) ; exit(-1) ; } hmetricDV = DV_new() ; DV_init(hmetricDV, tree->n, NULL) ; hmetric = DV_entries(hmetricDV) ; for ( v = Tree_postOTfirst(tree) ; v != -1 ; v = Tree_postOTnext(tree, v) ) { for ( u = tree->fch[v], val = 0 ; u != -1 ; u = tree->sib[u] ) { if ( val < hmetric[u] ) { val = hmetric[u] ; } } hmetric[v] = val + vmetric[v] ; } return(hmetricDV) ; } /*--------------------------------------------------------------------*/ Tree/src/perms.c010064400020550007177000000054070653410606000150570ustar00clevecompmath00000400000006/* perms.c */ #include "../Tree.h" /*--------------------------------------------------------------------*/ /* -------------------------------------- fill the new-to-old permutation vector created -- 95nov15, cca -------------------------------------- */ void Tree_fillNewToOldPerm ( Tree *tree, int newToOld[] ) { int i, v ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 || newToOld == NULL ) { fprintf(stderr, "\n fatal error in Tree_fillNewToOldPerm(%p,%p)" "\n bad input\n", tree, newToOld) ; exit(-1) ; } /* ----------------------------------------------- post-order traversal to fill permutation vector ----------------------------------------------- */ for ( v = Tree_postOTfirst(tree), i = 0 ; v != -1 ; v = Tree_postOTnext(tree, v) ) { newToOld[i++] = v ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- fill the old-to-new permutation vector created -- 95nov15, cca -------------------------------------- */ void Tree_fillOldToNewPerm ( Tree *tree, int oldToNew[] ) { int i, v ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 || oldToNew == NULL ) { fprintf(stderr, "\n fatal error in Tree_fillOldToNewPerm(%p,%p)" "\n bad input\n", tree, oldToNew) ; exit(-1) ; } /* ----------------------------------------------- post-order traversal to fill permutation vector ----------------------------------------------- */ for ( v = Tree_postOTfirst(tree), i = 0 ; v != -1 ; v = Tree_postOTnext(tree, v) ) { oldToNew[v] = i++ ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ fill the new-to-old and old-to-new permutation vectors created -- 95nov15, cca ------------------------------------------------------ */ void Tree_fillBothPerms ( Tree *tree, int newToOld[], int oldToNew[] ) { int i, v ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 || newToOld == NULL || oldToNew == NULL ) { fprintf(stderr, "\n fatal error in Tree_fillBothPerms(%p,%p,%p)" "\n bad input\n", tree, newToOld, oldToNew) ; exit(-1) ; } /* ------------------------------------------------ post-order traversal to fill permutation vectors ------------------------------------------------ */ for ( v = Tree_postOTfirst(tree), i = 0 ; v != -1 ; v = Tree_postOTnext(tree, v) ) { newToOld[i] = v ; oldToNew[v] = i++ ; } return ; } /*--------------------------------------------------------------------*/ ee == NULL || tree->n < 1 || oldToNew == NULL ) { fprintf(stderr, "\n fatal error in Tree_fillOldToNewPerm(%p,%p)" "\n bad input\n", tree, oldToNew) ; exit(-1) ; } /* ----------------------------------------------- post-order Tree/src/permute.c010064400020550007177000000025040653410606000154050ustar00clevecompmath00000400000006/* permute.c */ #include "../Tree.h" /*--------------------------------------------------------------------*/ /* ----------------------- return a permuted tree created -- 96jan04, cca ----------------------- */ Tree * Tree_permute ( Tree *tree, int newToOld[], int oldToNew[] ) { int n, u_old, v_new, v_old, w_old ; Tree *tree2 ; /* --------------- check the input --------------- */ if ( tree == NULL || (n = tree->n) <= 0 || newToOld == NULL || oldToNew == NULL ) { fprintf(stderr, "\n fatal error in Tree_permute(%p,%p,%p)" "\n bad input\n", tree, newToOld, oldToNew) ; exit(-1) ; } /* ----------------- create a new tree ----------------- */ tree2 = Tree_new() ; Tree_init1(tree2, n) ; /* --------------- fill the fields --------------- */ for ( v_new = 0 ; v_new < n ; v_new++ ) { v_old = newToOld[v_new] ; if ( (w_old = tree->par[v_old]) != -1 ) { tree2->par[v_new] = oldToNew[w_old] ; } if ( (u_old = tree->fch[v_old]) != -1 ) { tree2->fch[v_new] = oldToNew[u_old] ; } if ( (u_old = tree->sib[v_old]) != -1 ) { tree2->sib[v_new] = oldToNew[u_old] ; } } if ( tree->root != -1 ) { tree2->root = oldToNew[tree->root] ; } return(tree2) ; } /*--------------------------------------------------------------------*/ Tree/src/subtree.c010064400020550007177000000051270663603013700154050ustar00clevecompmath00000400000006/* subtree.c */ #include "../Tree.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to initialize subtree with the subtree of tree using nodes in nodeidsIV return values --- 1 -- normal return -1 -- subtree is NULL -2 -- nodeidsIV is NULL -3 -- tree is NULL -4 -- nodeidsIV is invalid created -- 98oct15, cca ------------------------------------------------- */ int Tree_initFromSubtree ( Tree *subtree, IV *nodeidsIV, Tree *tree ) { int J, Jsub, K, Ksub, nnodeInSubtree, nnodeInTree ; int *localmap, *par, *parsub, *subtreeNodes ; /* --------------- check the input --------------- */ if ( subtree == NULL ) { fprintf(stderr, "\n\n error in Tree_initFromSubtree()" "\n subtree is NULL\n") ; return(-1) ; } if ( nodeidsIV == NULL ) { fprintf(stderr, "\n\n error in Tree_initFromSubtree()" "\n nodeidsIV is NULL\n") ; return(-2) ; } if ( tree == NULL ) { fprintf(stderr, "\n\n error in Tree_initFromSubtree()" "\n tree is NULL\n") ; return(-3) ; } nnodeInTree = Tree_nnodes(tree) ; IV_sizeAndEntries(nodeidsIV, &nnodeInSubtree, &subtreeNodes) ; if ( nnodeInSubtree < 0 || nnodeInSubtree >= nnodeInTree ) { fprintf(stderr, "\n\n error in Tree_initFromSubtree()" "\n nnodeInTree = %d, nnodeInSubtree = %d\n", nnodeInTree, nnodeInSubtree) ; return(-4) ; } for ( Jsub = 0 ; Jsub < nnodeInSubtree ; Jsub++ ) { J = subtreeNodes[Jsub] ; if ( J < 0 || J >= nnodeInTree ) { fprintf(stderr, "\n\n error in Tree_initFromSubtree()" "\n nnodeInTree = %d, subtreeNodes[%d] = %d\n", nnodeInTree, Jsub, subtreeNodes[Jsub]) ; return(-4) ; } } par = Tree_par(tree) ; /* ---------------------------- create a global-to-local map ---------------------------- */ localmap = IVinit(nnodeInTree, -1) ; for ( Jsub = 0 ; Jsub < nnodeInSubtree ; Jsub++ ) { localmap[subtreeNodes[Jsub]] = Jsub ; } /* ---------------------- initialize the subtree ---------------------- */ Tree_init1(subtree, nnodeInSubtree) ; parsub = Tree_par(subtree) ; for ( Jsub = 0 ; Jsub < nnodeInSubtree ; Jsub++ ) { J = subtreeNodes[Jsub] ; if ( (K = par[J]) != -1 && (Ksub = localmap[K]) != -1 ) { parsub[Jsub] = Ksub ; } } Tree_setFchSibRoot(subtree) ; /* ------------------------ free the working storage ------------------------ */ IVfree(localmap) ; return(1) ; } /*--------------------------------------------------------------------*/ Tree/src/util.c010064400020550007177000000207570654031517600147220ustar00clevecompmath00000400000006/* util.c */ #include "../Tree.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------- return the first vertex in a post-order traversal created -- 95nov15, cca ------------------------------------------------- */ int Tree_postOTfirst ( Tree *tree ) { int v ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 ) { fprintf(stderr, "\n fatal error in Tree_postOTfirst(%p)" "\n bad input\n", tree) ; exit(-1) ; } /* ---------------------- find the leftmost leaf ---------------------- */ if ( (v = tree->root) != -1 ) { while ( tree->fch[v] != -1 ) { v = tree->fch[v] ; } } return(v) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- return the vertex that follows v in a post-order traversal ---------------------------------------------------------- */ int Tree_postOTnext ( Tree *tree, int v ) { /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 || v < 0 || v >= tree->n ) { fprintf(stderr, "\n fatal error in Tree_postOTnext(%p,%d)" "\n bad input\n", tree, v) ; exit(-1) ; } /* --------------------------------------------------- find leftmost leaf of sibling (if exists) or parent --------------------------------------------------- */ if ( tree->sib[v] != -1 ) { v = tree->sib[v] ; while ( tree->fch[v] != -1 ) { v = tree->fch[v] ; } } else { v = tree->par[v] ; } return(v) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ return the first vertex in a pre-order traversal created -- 95nov15, cca ------------------------------------------------ */ int Tree_preOTfirst ( Tree *tree ) { /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 ) { fprintf(stderr, "\n fatal error in Tree_preOTfirst(%p)" "\n bad input\n", tree) ; exit(-1) ; } return(tree->root) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- return the vertex that follows v in a pre-order traversal created -- 95nov15, cca --------------------------------------------------------- */ int Tree_preOTnext ( Tree *tree, int v ) { /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 || v < 0 || v >= tree->n ) { fprintf(stderr, "\n fatal error in Tree_preOTnext(%p,%d)" "\n bad input\n", tree, v) ; exit(-1) ; } /* ------------------------------------- find the next vertex in the traversal ------------------------------------- */ if ( tree->fch[v] != -1 ) { v = tree->fch[v] ; } else { while ( tree->sib[v] == -1 && tree->par[v] != -1 ) { v = tree->par[v] ; } v = tree->sib[v] ; } return(v) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- return the number of leaves in the tree created -- 95nov15, cca --------------------------------------- */ int Tree_nleaves ( Tree *tree ) { int nleaf, v ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 ) { fprintf(stderr, "\n fatal error in Tree_nleaves(%p)" "\n bad input\n", tree) ; exit(-1) ; } nleaf = 0 ; for ( v = 0 ; v < tree->n ; v++ ) { if ( tree->fch[v] == -1 ) { nleaf++ ; } } return(nleaf) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- return the number of roots of the tree (forest) created -- 95nov15, cca ----------------------------------------------- */ int Tree_nroots ( Tree *tree ) { int nroot, v ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 ) { fprintf(stderr, "\n fatal error in Tree_nroots(%p)" "\n bad input\n", tree) ; exit(-1) ; } nroot = 0 ; for ( v = 0 ; v < tree->n ;v++ ) { if ( tree->par[v] == -1 ) { nroot++ ; } } return(nroot) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- return the number of children of a vertex created -- 95nov15, cca modified -- 96jan07, cca v checked to be valid ----------------------------------------- */ int Tree_nchild ( Tree *tree, int v ) { int nchild, w ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 ) { fprintf(stderr, "\n fatal error in Tree_nchild(%p,%d)" "\n bad input\n", tree, v) ; exit(-1) ; } if ( v < 0 || v >= tree->n ) { fprintf(stderr, "\n fatal error in Tree_nchild(%p,%d)" "\n v = %d, size = %d\n", tree, v, v, tree->n) ; exit(-1) ; } nchild = 0 ; for ( w = tree->fch[v] ; w != -1 ; w = tree->sib[w] ) { nchild++ ; } return(nchild) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- this method returns an IV object that holds the number of children for the tree nodes. created -- 96dec18, cca ------------------------------------------- */ IV * Tree_nchildIV ( Tree *tree ) { int n, v, w ; int *nchild, *par ; IV *nchildIV ; /* --------------- check the input --------------- */ if ( tree == NULL || (n = tree->n) < 1 ) { fprintf(stderr, "\n fatal error in Tree_nchildIV(%p)" "\n bad input\n", tree) ; exit(-1) ; } nchildIV = IV_new() ; IV_init(nchildIV, n, NULL) ; IV_fill(nchildIV, 0) ; par = tree->par ; nchild = IV_entries(nchildIV) ; for ( v = 0 ; v < n ; v++ ) { if ( (w = par[v]) != -1 ) { nchild[w]++ ; } } return(nchildIV) ; } /*--------------------------------------------------------------------*/ /* ----------------------------- return the height of the tree created -- 96aug23, cca ----------------------------- */ int Tree_height ( Tree *tree ) { int u, v, vheight ; int *heights ; /* --------------- check the input --------------- */ if ( tree == NULL || tree->n < 1 ) { fprintf(stderr, "\n fatal error in Tree_height(%p)" "\n bad input\n", tree) ; exit(-1) ; } heights = IVinit(tree->n, 1) ; for ( v = Tree_postOTfirst(tree) ; v != -1 ; v = Tree_postOTnext(tree, v) ) { if ( (u = tree->fch[v]) == -1 ) { vheight = 1 ; } else { vheight = heights[u] ; for ( u = tree->sib[u] ; u != -1 ; u = tree->sib[u] ) { if ( vheight < heights[u] ) { vheight = heights[u] ; } } vheight++ ; } heights[v] = vheight ; } v = tree->root ; vheight = heights[v] ; for ( v = tree->sib[v] ; v != -1 ; v = tree->sib[v] ) { if ( vheight < heights[v] ) { vheight = heights[v] ; } } IVfree(heights) ; return(vheight) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- return the maximum number of children of any node in the tree created -- 96sep05, cca ------------------------------------------------------------- */ int Tree_maxNchild ( Tree *tree ) { int maxnchild, n, nchild, u, v ; int *fch, *sib ; /* --------------- check the input --------------- */ if ( tree == NULL ) { fprintf(stderr, "\n fatal error in Tree_maxNchild(%p)" "\n bad input\n", tree) ; exit(-1) ; } n = tree->n ; fch = tree->fch ; sib = tree->sib ; maxnchild = 0 ; for ( v = 0 ; v < n ; v++ ) { for ( u = fch[v], nchild = 0 ; u != -1 ; u = sib[u] ) { nchild++ ; } if ( maxnchild < nchild ) { maxnchild = nchild ; } } return(maxnchild) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- return the number of bytes used by the object --------------------------------------------- */ int Tree_sizeOf ( Tree *tree ) { int nbytes ; /* --------------- check the input --------------- */ if ( tree == NULL ) { fprintf(stderr, "\n fatal error in Tree_sizeOf(%p)" "\n bad input\n", tree) ; exit(-1) ; } nbytes = sizeof(struct _Tree) + 3*tree->n*sizeof(int) ; return(nbytes) ; } /*--------------------------------------------------------------------*/ Tree/drivers/do_drawTree010075500020550007177000000035150665243302200166410ustar00clevecompmath00000400000006#! /bin/csh -f set Matrices = ../../Matrices set matrix = R2D100 set matrices = ../../../matrices set matrix = GRD15x15x127 set matrices = /local1/ARPA/matrices set matrix = i4a set inTreeFile = $matrices/$matrix/nd.treef set inTreeFile = $matrices/$matrix/ms.treef set inTreeFile = jim.treef set inTreeFile = /local1/ARPA/matrices/i4a/best0.treef set inTreeFile = /local1/ARPA/matrices/SFTC1/best0.treef set inTreeFile = bcell2.treef set inTreeFile = stk35.treef set inTreeFile = ms.treef set inTreeFile = haggar.treef set inTreeFile = mmd.treef set inTreeFile = nd.treef set inTreeFile = $Matrices/R2D100/nd.treef set inTagsFile = $matrices/$matrix/ndowners.ivf set inTagsFile = jim.ivf set inTagsFile = bcell2.ivf set inTagsFile = owners.ivf set inTagsFile = haggar.ivf set inTagsFile = none set outEPSfile = ndtree.eps set outEPSfile = mstree.eps set outEPSfile = jim.eps set outEPSfile = jimowners.eps set outEPSfile = i4a.eps set outEPSfile = sftc1.eps set outEPSfile = bcell2.eps set outEPSfile = stk35.eps set outEPSfile = nd.eps set outEPSfile = ms.eps set outEPSfile = mmd.eps set outEPSfile = haggar2.eps set outEPSfile = temp.eps set msglvl = 1 set msgFile = stdout set heightFlag = D set heightFlag = H set coordFlag = C set coordFlag = P set radius = 12.5 set radius = 10 set radius = 3 set radius = 6 set bbox = ' 0 0 300 200 ' set rect = ' 20 20 280 180 ' set bbox = ' 0 0 600 300 ' set rect = ' 20 20 580 280 ' set bbox = ' 0 0 400 400 ' set rect = ' 20 20 380 380 ' set bbox = ' 0 0 600 600 ' set rect = ' 20 20 580 580 ' set fontsize = 8 set tagsflag = 1 drawTree $msglvl $msgFile \ $inTreeFile \ $inTagsFile \ $outEPSfile \ $heightFlag \ $coordFlag \ $radius \ $bbox $rect \ $fontsize \ $tagsflag Tree/drivers/makefile010064400020550007177000000004600665314266200161600ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = drawTree drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} drawTree : drawTree.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} Tree/drivers/drawTree.c010064400020550007177000000137020665245543200164050ustar00clevecompmath00000400000006/* drawTree.c */ #include "../Tree.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------- draw the tree created -- 99jan23, cca ---------------------------------------- */ { char coordflag, heightflag ; char *inTagsFileName, *inTreeFileName, *outEPSfileName ; double fontsize, radius, t1, t2 ; double bbox[4], frame[4] ; DV *xDV, *yDV ; int ierr, msglvl, rc, tagsflag ; IV *tagsIV ; Tree *tree ; FILE *msgFile ; if ( argc != 19 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inTreeFile inTagsFile outEPSfile " "\n heightflag coordflag radius bbox[4] frame[4] tagflag fontsize" "\n msglvl -- message level" "\n msgFile -- message file" "\n inTreeFile -- input file, must be *.treef or *.treeb" "\n inTagsFile -- input file, must be *.ivf or *.ivb or none" "\n outEPSfile -- output file" "\n heightflag -- height flag" "\n 'D' -- use depth metric" "\n 'H' -- use height metric" "\n coordflag -- coordinate flag" "\n 'C' -- use (x,y) Cartesian coordinates" "\n 'P' -- use (r,theta) polar coordinates" "\n radius -- radius of node" "\n bbox[4] -- bounding box" "\n frame[4] -- frame for plot" "\n fontsize -- size of fonts (in points)" "\n tagflag -- if 1, draw labels, otherwise, do not" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inTreeFileName = argv[3] ; inTagsFileName = argv[4] ; outEPSfileName = argv[5] ; heightflag = argv[6][0] ; coordflag = argv[7][0] ; radius = atof(argv[8]) ; bbox[0] = atof(argv[9]) ; bbox[1] = atof(argv[10]) ; bbox[2] = atof(argv[11]) ; bbox[3] = atof(argv[12]) ; frame[0] = atof(argv[13]) ; frame[1] = atof(argv[14]) ; frame[2] = atof(argv[15]) ; frame[3] = atof(argv[16]) ; fontsize = atof(argv[17]) ; tagsflag = atoi(argv[18]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inTreeFile -- %s" "\n inTagsFile -- %s" "\n outEPSfile -- %s" "\n heightflag -- %c" "\n coordflag -- %d" "\n radius -- %.3g" "\n bbox -- %.3g %.3g %.3g %.3g" "\n frame -- %.3g %.3g %.3g %.3g" "\n fontsize -- %.3g" "\n", argv[0], msglvl, argv[2], inTreeFileName, inTagsFileName, outEPSfileName, heightflag, coordflag, radius, bbox[0], bbox[1], bbox[2], bbox[3], frame[0], frame[1], frame[2], frame[3], fontsize, tagsflag) ; fflush(msgFile) ; /* ------------------------ read in the Tree object ------------------------ */ if ( strcmp(inTreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } tree = Tree_new() ; MARKTIME(t1) ; rc = Tree_readFromFile(tree, inTreeFileName) ; /* Tree_setFchSibRoot(tree) ; */ Tree_leftJustify(tree) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in tree from file %s", t2 - t1, inTreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Tree_readFromFile(%p,%s)", rc, tree, inTreeFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Tree object from file %s", inTreeFileName) ; if ( msglvl > 2 ) { Tree_writeForHumanEye(tree, msgFile) ; } else { Tree_writeStats(tree, msgFile) ; } fflush(msgFile) ; if ( Tree_maxNchild(tree) > 2 ) { fprintf(msgFile, "\n\n maximum number of children = %d", Tree_maxNchild(tree)) ; } if ( strcmp(inTagsFileName, "none") != 0 ) { /* -------------------------- read in the tags IV object -------------------------- */ tagsIV = IV_new() ; MARKTIME(t1) ; rc = IV_readFromFile(tagsIV, inTagsFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in tagsIV from file %s", t2 - t1, inTagsFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, tagsIV, inTagsFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading IV object from file %s", inTagsFileName) ; if ( msglvl > 2 ) { IV_writeForHumanEye(tagsIV, msgFile) ; } else { IV_writeStats(tagsIV, msgFile) ; } fflush(msgFile) ; if ( IV_size(tagsIV) != tree->n ) { fprintf(stderr, "\n fatal error, IV_size(tagsIV) = %d, tree->n = %d", IV_size(tagsIV), tree->n) ; exit(-1) ; } } else { tagsIV = NULL ; } /* ------------------------------- get the coordinates of the tree ------------------------------- */ xDV = DV_new() ; yDV = DV_new() ; rc = Tree_getSimpleCoords(tree, heightflag, coordflag, xDV, yDV) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from Tree_getSimpleCoords()",rc); exit(-1) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n x-coordinates") ; DV_writeForHumanEye(xDV, msgFile) ; fprintf(msgFile, "\n\n y-coordinates") ; DV_writeForHumanEye(yDV, msgFile) ; fflush(msgFile) ; } /* ------------- draw the Tree ------------- */ rc = Tree_drawToEPS(tree, outEPSfileName, xDV, yDV, radius, NULL, tagsflag, fontsize, tagsIV, bbox, frame, NULL) ; if ( rc != 1 ) { fprintf(stderr, "\n error return %d from Tree_drawToEPSfile()", rc) ; exit(-1) ; } /* --------------------- free the Tree object --------------------- */ Tree_free(tree) ; if ( tagsIV != NULL ) { IV_free(tagsIV) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ Tree/doc/004275500020550007177000000000000665315072600135545ustar00clevecompmath00000400000006Tree/doc/R2D400DP.eps010064400020550007177000000111600653410606000153040ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 400 400 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def 20 20 380 380 rectstroke newpath 380 218 334 237 ML 370 268 334 237 ML 334 237 275 263 ML 378 337 323 332 ML 324 380 323 332 ML 323 332 267 320 ML 247 368 267 320 ML 267 320 275 263 ML 275 263 212 256 ML 189 372 171 330 ML 133 360 171 330 ML 171 330 156 283 ML 84.5 332 99.5 289 ML 48.8 292 99.5 289 ML 99.5 289 156 283 ML 156 283 212 256 ML 212 256 204 218 ML 30 243 71.6 218 ML 30 192 71.6 218 ML 71.6 218 122 190 ML 48.8 144 107 139 ML 54.6 75.3 107 88.1 ML 115 40.4 107 88.1 ML 107 88.1 107 139 ML 107 139 122 190 ML 122 190 191 181 ML 189 63.3 226 103 ML 258 30 275 75.9 ML 324 55.6 275 75.9 ML 275 75.9 226 103 ML 226 103 255 155 ML 343 123 320 162 ML 370 167 320 162 ML 320 162 255 155 ML 255 155 191 181 ML 191 181 204 218 ML stroke gsave /Helvetica-Bold findfont 12.5 scalefont setfont 1.0 setgray 380 218 10 FC 0.0 setgray 380 218 10 OC 380 213 moveto (0) CSH 1.0 setgray 370 268 10 FC 0.0 setgray 370 268 10 OC 370 263 moveto (1) CSH 1.0 setgray 334 237 10 FC 0.0 setgray 334 237 10 OC 334 232 moveto (2) CSH 1.0 setgray 378 337 10 FC 0.0 setgray 378 337 10 OC 378 332 moveto (3) CSH 1.0 setgray 324 380 10 FC 0.0 setgray 324 380 10 OC 324 375 moveto (4) CSH 1.0 setgray 323 332 10 FC 0.0 setgray 323 332 10 OC 323 327 moveto (5) CSH 1.0 setgray 247 368 10 FC 0.0 setgray 247 368 10 OC 247 363 moveto (6) CSH 1.0 setgray 267 320 10 FC 0.0 setgray 267 320 10 OC 267 315 moveto (7) CSH 1.0 setgray 275 263 10 FC 0.0 setgray 275 263 10 OC 275 258 moveto (8) CSH 1.0 setgray 189 372 10 FC 0.0 setgray 189 372 10 OC 189 367 moveto (9) CSH 1.0 setgray 133 360 10 FC 0.0 setgray 133 360 10 OC 133 355 moveto (10) CSH 1.0 setgray 171 330 10 FC 0.0 setgray 171 330 10 OC 171 325 moveto (11) CSH 1.0 setgray 84.5 332 10 FC 0.0 setgray 84.5 332 10 OC 84.5 327 moveto (12) CSH 1.0 setgray 48.8 292 10 FC 0.0 setgray 48.8 292 10 OC 48.8 287 moveto (13) CSH 1.0 setgray 99.5 289 10 FC 0.0 setgray 99.5 289 10 OC 99.5 284 moveto (14) CSH 1.0 setgray 156 283 10 FC 0.0 setgray 156 283 10 OC 156 278 moveto (15) CSH 1.0 setgray 212 256 10 FC 0.0 setgray 212 256 10 OC 212 251 moveto (16) CSH 1.0 setgray 30 243 10 FC 0.0 setgray 30 243 10 OC 30 238 moveto (17) CSH 1.0 setgray 30 192 10 FC 0.0 setgray 30 192 10 OC 30 187 moveto (18) CSH 1.0 setgray 71.6 218 10 FC 0.0 setgray 71.6 218 10 OC 71.6 213 moveto (19) CSH 1.0 setgray 48.8 144 10 FC 0.0 setgray 48.8 144 10 OC 48.8 139 moveto (20) CSH 1.0 setgray 54.6 75.3 10 FC 0.0 setgray 54.6 75.3 10 OC 54.6 70.3 moveto (21) CSH 1.0 setgray 115 40.4 10 FC 0.0 setgray 115 40.4 10 OC 115 35.4 moveto (22) CSH 1.0 setgray 107 88.1 10 FC 0.0 setgray 107 88.1 10 OC 107 83.1 moveto (23) CSH 1.0 setgray 107 139 10 FC 0.0 setgray 107 139 10 OC 107 134 moveto (24) CSH 1.0 setgray 122 190 10 FC 0.0 setgray 122 190 10 OC 122 185 moveto (25) CSH 1.0 setgray 189 63.3 10 FC 0.0 setgray 189 63.3 10 OC 189 58.3 moveto (26) CSH 1.0 setgray 258 30 10 FC 0.0 setgray 258 30 10 OC 258 25 moveto (27) CSH 1.0 setgray 324 55.6 10 FC 0.0 setgray 324 55.6 10 OC 324 50.6 moveto (28) CSH 1.0 setgray 275 75.9 10 FC 0.0 setgray 275 75.9 10 OC 275 70.9 moveto (29) CSH 1.0 setgray 226 103 10 FC 0.0 setgray 226 103 10 OC 226 98.2 moveto (30) CSH 1.0 setgray 343 123 10 FC 0.0 setgray 343 123 10 OC 343 118 moveto (31) CSH 1.0 setgray 370 167 10 FC 0.0 setgray 370 167 10 OC 370 162 moveto (32) CSH 1.0 setgray 320 162 10 FC 0.0 setgray 320 162 10 OC 320 157 moveto (33) CSH 1.0 setgray 255 155 10 FC 0.0 setgray 255 155 10 OC 255 150 moveto (34) CSH 1.0 setgray 191 181 10 FC 0.0 setgray 191 181 10 OC 191 176 moveto (35) CSH 1.0 setgray 204 218 10 FC 0.0 setgray 204 218 10 OC 204 213 moveto (36) CSH grestore showpage 237 10 OC 334 232 moveto (2) CSH 1.0 setgray 378 337 10 FC 0.0 setgray 378 337 10 OC 378 332 moveto (3) CSH 1.0 setgray 324 380 10 FC 0.0 setgray 324 380 10 OC 324 375 moveto (4) CSH 1.0 setgray 323 332 10 FC 0.0 setgray 323 332 10 OC 323 327 moveto (5) CSH 1.0 setgray 247 368 10 FC 0.0 setgray 247 368 10 OC 247 363 moveto (6) CSH 1.0 setgraTree/doc/main.ind010064400020550007177000000036310665243537100151730ustar00clevecompmath00000400000006\begin{theindex} \item {\tt Tree\_clearData()}, 2 \item {\tt Tree\_compress()}, 7 \item {\tt Tree\_drawToEPS()}, 8 \item {\tt Tree\_fch()}, 3 \item {\tt Tree\_fillBothPerms()}, 8 \item {\tt Tree\_fillNewToOldPerm()}, 8 \item {\tt Tree\_fillOldToNewPerm()}, 8 \item {\tt Tree\_free()}, 2 \item {\tt Tree\_fundChainMap()}, 7 \item {\tt Tree\_getSimpleCoords()}, 8 \item {\tt Tree\_height()}, 5 \item {\tt Tree\_init1()}, 3 \item {\tt Tree\_init2()}, 3 \item {\tt Tree\_init3()}, 3 \item {\tt Tree\_initFromSubtree()}, 3 \item {\tt Tree\_leftJustify()}, 7 \item {\tt Tree\_leftJustifyD()}, 7 \item {\tt Tree\_leftJustifyI()}, 7 \item {\tt Tree\_maximizeGainIV()}, 5 \item {\tt Tree\_maxNchild()}, 5 \item {\tt Tree\_nchild()}, 5 \item {\tt Tree\_nchildIV()}, 5 \item {\tt Tree\_new()}, 2 \item {\tt Tree\_nleaves()}, 5 \item {\tt Tree\_nnodes()}, 2 \item {\tt Tree\_nroots()}, 5 \item {\tt Tree\_par()}, 2 \item {\tt Tree\_permute()}, 8 \item {\tt Tree\_postOTfirst()}, 4 \item {\tt Tree\_postOTnext()}, 4 \item {\tt Tree\_preOTfirst()}, 4 \item {\tt Tree\_preOTnext()}, 4 \item {\tt Tree\_readFromBinaryFile()}, 9 \item {\tt Tree\_readFromFile()}, 9 \item {\tt Tree\_readFromFormattedFile()}, 9 \item {\tt Tree\_root()}, 2 \item {\tt Tree\_setDefaultFields()}, 2 \item {\tt Tree\_setDepthDmetric()}, 6 \item {\tt Tree\_setDepthImetric()}, 6 \item {\tt Tree\_setFchSibRoot()}, 4 \item {\tt Tree\_setHeightDmetric()}, 6 \item {\tt Tree\_setHeightImetric()}, 6 \item {\tt Tree\_setRoot()}, 4 \item {\tt Tree\_setSubtreeDmetric()}, 6 \item {\tt Tree\_setSubtreeImetric()}, 6 \item {\tt Tree\_sib()}, 3 \item {\tt Tree\_sizeOf()}, 4 \item {\tt Tree\_writeForHumanEye()}, 10 \item {\tt Tree\_writeStats()}, 10 \item {\tt Tree\_writeToBinaryFile()}, 10 \item {\tt Tree\_writeToFile()}, 9 \item {\tt Tree\_writeToFormattedFile()}, 10 \end{theindex} Tree/doc/dataStructure.tex010064000020550007177000000021660653410606000171120ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:Tree:dataStructure} \par The {\tt Tree} object has a very simple data structure. The value {\tt -1} is used to denote a null pointer for the parent, first child and sibling fields. \begin{itemize} \item {\tt int n} : size of the tree \item {\tt int root} : root of the tree, in range {\tt [0,n-1]}, in the range {\tt [-1,n-1]} \item {\tt int *par} : pointer to parent vector, size {\tt n}, entries in the range {\tt [-1,n-1]} \item {\tt int *fch} : pointer to first child vector, size {\tt n}, entries in the range {\tt [-1,n-1]} \item {\tt int *sib} : pointer to sibling vector, size {\tt n}, entries in the range {\tt [-1,n-1]} \end{itemize} The user should rarely if ever change these five fields. In particular, throughout the code we assume that the {\tt Tree} object was correctly initialized using one of the three initializer methods. Inside almost every method we check to ensure $n > 0$. If $n > 0$ then we assume that the structure was intialized correctly and that the {\tt par}, {\tt fch} and {\tt sib} fields point to storage that was allocated by the initializer method. Tree/doc/intro.tex010064000020550007177000000021570653410606000154130ustar00clevecompmath00000400000006\chapter{{\tt Tree}: A Tree Object} \par The {\tt Tree} object has very simple functionality, it represents the graph of a {\it tree} data structure of fixed size. (In reality, it is a ``forest'' object, for the graph need not be connected.) Trees are used throughout sparse matrix computations. The elimination tree \cite{liu90-etree} is the most common example, though assembly trees \cite{duf83-multifrontal}, element merge trees \cite{eis76-elementModel} and front trees are also common. \par The {\tt Tree} object is very simple --- there is a size, a root, and parent, first child and sibling vectors. No information is stored for a node except for its tree connections. For an elimination tree, each vertex needs to know the number of ancestors adjacent in the factor graph. For a front tree, each front needs to know the dimensions of the front matrix. This extra information cannot be stored in the {\tt Tree} object. See the {\tt ETree} object in Chapter~\ref{chapter:ETree}; each {\tt ETree} object contains a {\tt Tree} object. (In a language that supports inheritance, {\tt ETree} could be a subclass of {\tt Tree}.) \par Tree/doc/main.aux010064000020550007177000000052010665243601100151750ustar00clevecompmath00000400000006\relax \citation{liu90-etree} \citation{duf83-multifrontal} \citation{eis76-elementModel} \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt Tree}: A Tree Object}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Data Structure}{1}} \newlabel{section:Tree:dataStructure}{{1.1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Prototypes and descriptions of {\tt Tree} methods}{2}} \newlabel{section:Tree:proto}{{1.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.1}Basic methods}{2}} \newlabel{subsection:Tree:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.2}Instance methods}{2}} \newlabel{subsection:Tree:proto:instance}{{1.2.2}{2}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.3}Initializer methods}{3}} \newlabel{subsection:Tree:proto:initializers}{{1.2.3}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.4}Utility methods}{4}} \newlabel{subsection:Tree:proto:utilities}{{1.2.4}{4}} \citation{liu91-generalizedEnvelope} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.5}Metrics methods}{6}} \newlabel{subsection:Tree:proto:metrics}{{1.2.5}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.6}Compression methods}{7}} \newlabel{subsection:Tree:proto:compression}{{1.2.6}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.7}Justification methods}{7}} \newlabel{subsection:Tree:proto:justify}{{1.2.7}{7}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.8}Permutation methods}{8}} \newlabel{subsection:Tree:proto:permutation}{{1.2.8}{8}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.9}Drawing method}{8}} \newlabel{subsection:Tree:proto:drawing}{{1.2.9}{8}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.2.10}IO methods}{9}} \newlabel{subsection:Tree:proto:IO}{{1.2.10}{9}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}Driver programs for the {\tt Tree} object}{10}} \newlabel{section:Tree:drivers}{{1.3}{10}} \@writefile{lof}{\contentsline {figure}{\numberline {1.1}{\ignorespaces {\sc R2D100}: domain/separator tree, on the left {\tt heightflag = 'H'} and {\tt coordflag = 'C'}, on the right {\tt heightflag = 'D'} and {\tt coordflag = 'C'}.}}{11}} \newlabel{fig-R2D100-tree-HC}{{1.1}{11}} \@writefile{lof}{\contentsline {figure}{\numberline {1.2}{\ignorespaces {\sc R2D100}: domain/separator tree, on the left {\tt heightflag = 'H'} and {\tt coordflag = 'P'}, on the right {\tt heightflag = 'D'} and {\tt coordflag = 'P'}.}}{12}} \newlabel{fig-R2D100-tree-HP}{{1.2}{12}} Tree/doc/main.log010064000020550007177000000111660665243601100151700ustar00clevecompmath00000400000006This is TeX, Version 3.14159 (C version 6.1) (format=latex 97.4.4) 23 JAN 1999 13:15 **main (main.tex LaTeX2e <1996/12/01> patch level 1 Babel and hyphenation patterns for english, german, loaded. (/home/tex/teTeX/texmf/tex/latex/base/report.cls Document Class: report 1996/10/31 v1.3u Standard LaTeX document class (/home/tex/teTeX/texmf/tex/latex/base/leqno.clo File: leqno.clo 1996/07/26 v1.1b Standard LaTeX option (left equation numbers) ) (/home/tex/teTeX/texmf/tex/latex/base/size11.clo File: size11.clo 1996/10/31 v1.3u Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) (/home/tex/teTeX/texmf/tex/generic/local/psfig/psfig.tex \@unused=\write3 \ps@stream=\read1 \p@intvaluex=\dimen103 \p@intvaluey=\dimen104 psfig/tex 1.10-dvips ) \@indexfile=\write4 Writing index file main.idx (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. (intro.tex Chapter 1. LaTeX Warning: Citation `liu90-etree' on page 1 undefined on input line 8. LaTeX Warning: Citation `duf83-multifrontal' on page 1 undefined on input line 9. LaTeX Warning: Citation `eis76-elementModel' on page 1 undefined on input line 10. LaTeX Warning: Reference `chapter:ETree' on page 1 undefined on input line 21. ) (dataStructure.tex LaTeX Font Info: Try loading font information for OMS+cmr on input line 10. (/home/tex/teTeX/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1997/01/14 v2.5a Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10.95> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 10. LaTeX Font Info: External font `cmex10' loaded for size (Font) <10.95> on input line 28. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 28. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 28. ) (proto.tex [1 ] [2] Overfull \hbox (16.3256pt too wide) in paragraph at lines 138--143 []\OT1/cmr/m/n/10.95 This is the ba-sic ini-tial-izer method. Any pre-vi-ous da ta is cleared with a call to \OT1/cmtt/m/n/10.95 Tree[]clearData()\OT1/cmr/m/n/ 10.95 . [] [3] [4] [5] LaTeX Font Info: Try loading font information for OMS+cmtt on input line 420 . LaTeX Font Info: No file OMScmtt.fd. on input line 420. LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined (Font) using `OMS/cmsy/m/n' instead (Font) for symbol `textbraceleft' on input line 420. LaTeX Warning: Citation `liu91-generalizedEnvelope' on page 6 undefined on inpu t line 472. [6] [7] Overfull \hbox (23.26378pt too wide) in paragraph at lines 660--660 []\OT1/cmtt/m/n/10.95 int Tree_drawToEPS ( Tree *tree, FILE *filename, DV *xDV , DV *yDV, double rscale,[] [] [8] [9]) (drivers.tex [10] psfig: searching ../../Tree/doc/R2D100HC.eps for bounding box psfig: including ../../Tree/doc/R2D100HC.eps psfig: searching ../../Tree/doc/R2D100DC.eps for bounding box psfig: including ../../Tree/doc/R2D100DC.eps psfig: searching ../../Tree/doc/R2D100HP.eps for bounding box psfig: including ../../Tree/doc/R2D100HP.eps psfig: searching ../../Tree/doc/R2D100DP.eps for bounding box psfig: including ../../Tree/doc/R2D100DP.eps ) (main.ind [11] [12] [13 ]) (main.aux) LaTeX Font Warning: Some font shapes were not available, defaults substituted. LaTeX Warning: There were undefined references. ) Here is how much of TeX's memory you used: 582 strings out of 10908 6101 string characters out of 72189 52826 words of memory out of 262141 3463 multiletter control sequences out of 9500 10615 words of font info for 38 fonts, out of 150000 for 255 14 hyphenation exceptions out of 607 22i,6n,22p,274b,342s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (13 pages, 37688 bytes). Tree/doc/main.tex010064400020550007177000000011140665065632400152140ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \input psfig \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Tree} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Tree} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} Tree/doc/proto.tex010064400020550007177000001007120665245541500154370ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Tree} methods} \label{section:Tree:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Tree} object. \par \subsection{Basic methods} \label{subsection:Tree:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Tree * Tree_new ( void ) ; \end{verbatim} \index{Tree_new@{\tt Tree\_new()}} This method simply allocates storage for the {\tt Tree} structure and then sets the default fields by a call to {\tt Tree\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_setDefaultFields ( Tree *tree ) ; \end{verbatim} \index{Tree_setDefaultFields@{\tt Tree\_setDefaultFields()}} This method sets the structure's fields to default values: {\tt n} is zero, {\tt root} is {\tt -1}, and {\tt par}, {\tt fch} and {\tt sib} are all {\tt NULL}. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_clearData ( Tree *tree ) ; \end{verbatim} \index{Tree_clearData@{\tt Tree\_clearData()}} This method releases any storage held by the parent, first child and sibling vectors, then sets the structure's default fields with a call to {\tt Tree\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_free ( Tree *tree ) ; \end{verbatim} \index{Tree_free@{\tt Tree\_free()}} This method releases any storage by a call to {\tt Tree\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:Tree:proto:instance} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_nnodes ( Tree *tree ) ; \end{verbatim} \index{Tree_nnodes@{\tt Tree\_nnodes()}} This method returns the number of nodes in the tree. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_root ( Tree *tree ) ; \end{verbatim} \index{Tree_root@{\tt Tree\_root()}} This method returns the root of the tree. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * Tree_par ( Tree *tree ) ; \end{verbatim} \index{Tree_par@{\tt Tree\_par()}} This method returns a pointer to the parent vector. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * Tree_fch ( Tree *tree ) ; \end{verbatim} \index{Tree_fch@{\tt Tree\_fch()}} This method returns a pointer to the first child vector. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int * Tree_sib ( Tree *tree ) ; \end{verbatim} \index{Tree_sib@{\tt Tree\_sib()}} This method returns a pointer to the sibling vector. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:Tree:proto:initializers} \par There are three initializers and two helper functions to set the dimensions of the tree, allocate the three vectors, and fill the information. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_init1 ( Tree *tree, int size ) ; \end{verbatim} \index{Tree_init1@{\tt Tree\_init1()}} This is the basic initializer method. Any previous data is cleared with a call to {\tt Tree\_clearData()}. The size is set and storage allocated for the three tree vectors using {\tt IVinit()}. All entries in the three vectors are set to {\tt -1}. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL} or {\tt size} is negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_init2 ( Tree *tree, int size, int par[] ) ; \end{verbatim} \index{Tree_init2@{\tt Tree\_init2()}} The simple initializer {\tt Tree\_init1()} is called and the entries in {\tt par[]} are copied into the parent vector. The helper method {\tt Tree\_setFchSibRoot()} is then called to set the other fields. \par \noindent {\it Error checking:} If {\tt tree} or {\tt par} is {\tt NULL}, or if {\tt size} is negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_init3 ( Tree *tree, int size, int par[], int fch[], int sib[] ) ; \end{verbatim} \index{Tree_init3@{\tt Tree\_init3()}} The simple initializer {\tt Tree\_init1()} is called and the entries in {\tt par[]}, {\tt fch[]} and {\tt sib[]} are copied into their respective vectors. The helper method {\tt Tree\_setRoot()} is then called to set the root field. \par \noindent {\it Error checking:} If {\tt tree}, {\tt par}, {\tt fch} or {\tt sib} is {\tt NULL}, or if {\tt size} is negative, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_initFromSubtree ( Tree *subtree, IV *nodeidsIV, Tree *tree ) ; \end{verbatim} \index{Tree_initFromSubtree@{\tt Tree\_initFromSubtree()}} The {\tt subtree} object is initialized from the {\tt tree} object, the nodes that are included are those found in {\tt nodeidsIV}. A parent-child link in the subtree means that the two nodes have a parent-child link in the tree. \par \noindent {\it Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt subtree} is {\tt NULL} \\ -2 & {\tt nodeidsIV} is {\tt NULL} \\ \end{tabular} \quad \begin{tabular}{rl} -3 & {\tt tree} is {\tt NULL} \\ -4 & {\tt nodeidsIV} is invalid \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_setFchSibRoot ( Tree *tree ) ; \end{verbatim} \index{Tree_setFchSibRoot@{\tt Tree\_setFchSibRoot()}} The root and the entries in the {\tt fch[]} and {\tt sib[]} vectors are set using the entries in the {\tt par[]} vector. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_setRoot ( Tree *tree ) ; \end{verbatim} \index{Tree_setRoot@{\tt Tree\_setRoot()}} The vertices that are roots in the tree are linked by their {\tt sib[]} field and the root of the tree is set to the head of the list. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:Tree:proto:utilities} \par The utility methods return the number of bytes taken by the object, aid in performing pre-order and post-order traversals, and return statistics about the tree (e.g., the number of roots or leaves in the tree, or the number of children of a node in the tree). This functionality can be easily had by direct manipulation or inquiry of the object, but these methods insulate the user from the internals and allow us to change and improve the internals if necessary. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_sizeOf ( Tree *tree ) ; \end{verbatim} \index{Tree_sizeOf@{\tt Tree\_sizeOf()}} This method returns the number of bytes taken by this object. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_postOTfirst ( Tree *tree ) ; \end{verbatim} \index{Tree_postOTfirst@{\tt Tree\_postOTfirst()}} This method returns the first node in a post-order traversal. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, or if {\tt tree->n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_postOTnext ( Tree *tree, int v ) ; \end{verbatim} \index{Tree_postOTnext@{\tt Tree\_postOTnext()}} This method returns the node that follows {\tt v} in a post-order traversal. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, or if {\tt tree->n < 1} or {\tt v} is not in {\tt [0,tree->n-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_preOTfirst ( Tree *tree ) ; \end{verbatim} \index{Tree_preOTfirst@{\tt Tree\_preOTfirst()}} This method returns the first node in a pre-order traversal. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, or if {\tt tree->n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_preOTnext ( Tree *tree, int v ) ; \end{verbatim} \index{Tree_preOTnext@{\tt Tree\_preOTnext()}} This method returns the node that follows {\tt v} in a pre-order traversal. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, or if {\tt tree->n < 1}, or {\tt v} is not in {\tt [0,tree->n-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_nleaves ( Tree *tree ) ; \end{verbatim} \index{Tree_nleaves@{\tt Tree\_nleaves()}} This method returns the number of leaves of the tree. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, or if {\tt tree->n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_nroots ( Tree *tree ) ; \end{verbatim} \index{Tree_nroots@{\tt Tree\_nroots()}} This method returns the number of roots of the tree (really a forest). \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, or if {\tt tree->n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_nchild ( Tree *tree, int v ) ; \end{verbatim} \index{Tree_nchild@{\tt Tree\_nchild()}} This method returns the number of children of {\tt v}. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, or if {\tt tree->n < 1}, or {\tt v} is not in {\tt [0,tree->n-1]}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * Tree_nchildIV ( Tree *tree ) ; \end{verbatim} \index{Tree_nchildIV@{\tt Tree\_nchildIV()}} This method creates an {\tt IV} object that holds the number of children for each of the nodes, i.e., entry {\tt v} of the returned {\tt IV} object contains the number of children of node {\tt v}. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, or if {\tt tree->n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_maxNchild ( Tree *tree ) ; \end{verbatim} \index{Tree_maxNchild@{\tt Tree\_maxNchild()}} This method returns the maximum number of children of any vertex. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, or if {\tt tree->n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_height ( Tree *tree ) ; \end{verbatim} \index{Tree_height@{\tt Tree\_height()}} This method returns the height of the tree. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, or if {\tt tree->n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * Tree_maximizeGainIV ( Tree *tree, IV *gainIV, int *ptotalgain, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{Tree_maximizeGainIV@{\tt Tree\_maximizeGainIV()}} Given a gain value assigned to each node, find a set of nodes, no two in a child-ancestor relationship, that maximizes the total gain. This problem arises in finding the optimal domain/Schur complement partition for a semi-implicit factorization. \par \noindent {\it Error checking:} If {\tt tree}, {\tt gainIV} or {\tt ptotalgain} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \subsection{Metrics methods} \label{subsection:Tree:proto:metrics} \par Many operations need to know some {\it metric} defined on the nodes in a tree. Here are three examples: the height of a node (the minimum distance from a descendant leaf), the depth of a node (the distance from its root ancestor), or the weight associated with a subtree rooted at a node. Of course, a weight could be associated with each node, so the height or depth becomes the weight of the nodes on the path. \par Metrics can be {\tt int} or {\tt double}. Because of the limitations of C, we need two separate methods for each of the height, depth and subtree functions. Each pair of methods differs only in the type of the vector object argument. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IV * Tree_setSubtreeImetric ( Tree *tree, IV *vmetricIV ) ; DV * Tree_setSubtreeDmetric ( Tree *tree, DV *vmetricDV ) ; \end{verbatim} \index{Tree_setSubtreeImetric@{\tt Tree\_setSubtreeImetric()}} \index{Tree_setSubtreeDmetric@{\tt Tree\_setSubtreeDmetric()}} These methods create and return {\tt IV} or {\tt DV} objects that contain subtree metrics using as input an {\tt IV} or {\tt DV} object that contains the metric for each of the nodes. If {\tt tmetric[]} is the vector in the returned {\tt IV} or {\tt DV} object, then \begin{verbatim} tmetric[v] = vmetric[v] + sum_{par[u] = v} tmetric[u]. \end{verbatim} \par \noindent {\it Error checking:} If {\tt tree} or {\tt vmetric\{I,D\}V} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * Tree_setDepthImetric ( Tree *tree, IV * vmetricIV ) ; DV * Tree_setDepthDmetric ( Tree *tree, DV * vmetricDV ) ; \end{verbatim} \index{Tree_setDepthImetric@{\tt Tree\_setDepthImetric()}} \index{Tree_setDepthDmetric@{\tt Tree\_setDepthDmetric()}} These methods create and return {\tt IV} or {\tt DV} objects that contain depth metrics using as input an {\tt IV} or {\tt DV} object that contains the metric for each of the nodes. If {\tt dmetric[]} is the vector in the returned {\tt IV} or {\tt DV} object, then \begin{verbatim} dmetric[v] = vmetric[v] if par[v] == -1 = vmetric[v] + dmetric[par[v]] if par[v] != -1 \end{verbatim} \par \noindent {\it Error checking:} If {\tt tree} or {\tt vmetric\{I,D\}V} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} IV * Tree_setHeightImetric ( Tree *tree, IV * vmetricIV ) ; DV * Tree_setHeightDmetric ( Tree *tree, DV * vmetricDV ) ; \end{verbatim} \index{Tree_setHeightImetric@{\tt Tree\_setHeightImetric()}} \index{Tree_setHeightDmetric@{\tt Tree\_setHeightDmetric()}} These methods create and return {\tt IV} or {\tt DV} objects that contain height metrics using as input an {\tt IV} or {\tt DV} object that contains the metric for each of the nodes. If {\tt hmetric[]} is the vector in the returned {\tt IV} or {\tt DV} object, then \begin{verbatim} hmetric[v] = vmetric[v] if fch[v] == -1 = vmetric[v] + max_{par[u] = v} hmetric[par[v]] \end{verbatim} \par \noindent {\it Error checking:} If {\tt tree} or {\tt vmetric\{I,D\}V} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Compression methods} \label{subsection:Tree:proto:compression} \par Frequently a tree will need to be compressed in some manner. Elimination trees usually have long chains of nodes at the higher levels, where each chain of nodes corresponds to a supernode. Liu's generalized row envelope methods partition the vertices by longest chains \cite{liu91-generalizedEnvelope}. In both cases, we can construct a map from each node to a set of nodes to define a smaller, more compact tree. Given such a map, we construct the smaller tree. \par A fundamental chain is a set of nodes $v_1, \ldots, v_m$ such that (1) $v_1$ is a leaf or has two or more children, (2) $v_{i+1}$ is the parent of $v_i$ for $1 \le i < m$, and (3) $v_m$ is either a root or has a sibling. The set of fundamental chains is uniquely defined. In the context of elimination trees, a fundamental chain is very close to a fundamental supernode, and in many cases, fundamental chains can be used to contruct the fronts with little added fill and factor operations. %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IV * Tree_fundChainMap ( Tree *tree ) ; \end{verbatim} \index{Tree_fundChainMap@{\tt Tree\_fundChainMap()}} This method creates and returns an {\tt IV} object that contains the map a vertex to the fundamental chain to which it belongs, i.e., {\tt map[v]} contains the id of the fundamental chain that contains {\tt v}. If {\tt u} is a descendant of {\tt v}, then {\tt map[u] <= map[v]}. The number of fundamental chains is returned. \par \noindent {\it Error checking:} If {\tt tree} is {\tt NULL}, or if {\tt n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Tree * Tree_compress ( Tree *tree, IV *mapIV ) ; \end{verbatim} \index{Tree_compress@{\tt Tree\_compress()}} This method creates and returns a new {\tt Tree} object formed by compressing {\tt tree} using the {\tt mapIV} object. The compressed tree is constructed and returned. \par \noindent {\it Error checking:} If {\tt tree} or {\tt mapIV} is {\tt NULL}, or if {\tt n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Justification methods} \label{subsection:Tree:proto:justify} \par Given a tree, how should the children of a node be ordered? This ``justification'' can have a large impact in the working storage for the front tree in the multifrontal algorithm. Justification also is useful when displaying trees. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_leftJustify ( Tree *tree ) ; \end{verbatim} \index{Tree_leftJustify@{\tt Tree\_leftJustify()}} This method justifies the tree, reordering the children of each node as necessary. If {\tt u} and {\tt v} are siblings, and {\tt u} comes before {\tt v} in a post-order traversal, then the size of the subtree rooted at {\tt u} is as large or larger than the size of the subtree rooted at {\tt v}. \par \noindent {\it Error checking:} If {\tt tree} or {\tt map} is {\tt NULL}, or if {\tt n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_leftJustifyI ( Tree *tree, IV *metricIV ) ; void Tree_leftJustifyD ( Tree *tree, DV *metricIV ) ; \end{verbatim} \index{Tree_leftJustifyI@{\tt Tree\_leftJustifyI()}} \index{Tree_leftJustifyD@{\tt Tree\_leftJustifyD()}} This method justifies the tree, reordering the children of each node as necessary. If {\tt u} and {\tt v} are siblings, and {\tt u} comes before {\tt v} in a post-order traversal, then the weight of the subtree rooted at {\tt u} is as large or larger than the weight of the subtree rooted at {\tt v}. \par \noindent {\it Error checking:} If {\tt tree} or {\tt metricIV} is {\tt NULL}, or if {\tt n < 1}, or if {\tt n} is not the size of {\tt metricIV}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Permutation methods} \label{subsection:Tree:proto:permutation} \par Often we need to extract a permutation from a tree, e.g., a post-order traversal of an elimination tree gives an ordering for a sparse matrix. On other occasions, we need to permute a tree, i.e. re-label the nodes. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_fillNewToOldPerm ( Tree *tree, int newToOld[] ) ; void Tree_fillOldToNewPerm ( Tree *tree, int oldToNew[] ) ; void Tree_fillBothPerms ( Tree *tree, int newToOld[], int oldToNew[] ) ; \end{verbatim} \index{Tree_fillNewToOldPerm@{\tt Tree\_fillNewToOldPerm()}} \index{Tree_fillOldToNewPerm@{\tt Tree\_fillOldToNewPerm()}} \index{Tree_fillBothPerms@{\tt Tree\_fillBothPerms()}} If {\tt tree} is {\tt NULL}, {\tt tree->n < 1} or a permutation vector is {\tt NULL}, an error message is printed and the program exits. Otherwise, the permutation vector(s) is (are) filled with the ordering of the nodes in a post-order traversal. \par \noindent {\it Error checking:} If {\tt tree} or a permutation vector is {\tt NULL}, or if {\tt n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} Tree * Tree_permute ( Tree *tree, int newToOld[], int oldToNew[] ) ; \end{verbatim} \index{Tree_permute@{\tt Tree\_permute()}} A new tree is created with the same connectivity as the old but the nodes are relabeled. \par \noindent {\it Error checking:} If {\tt tree}, {\tt newToOld} or {\tt oldToNew} is {\tt NULL}, or if {\tt tree->n < 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Drawing method} \label{subsection:Tree:proto:drawing} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_getSimpleCoords ( Tree *tree, char heightflag, int coordflag, DV *xDV, DV *yDV) ; \end{verbatim} \index{Tree_getSimpleCoords@{\tt Tree\_getSimpleCoords()}} This method fills the {\tt xDV} and {\tt yDV} vector objects with coordinates of the nodes in the tree. When {\tt coordflag = 'C'}, we create Cartesian coordinates, where the leaves are at the bottom and the root(s) at the top. When {\tt coordflag = 'P'}, we create polar coordinates, where the leaves are found on the outside and the root(s) in the center. The height of a node is the distance from the bottom for Cartesian coordinates, and the distance from the outermost circle for polar coordinates. When {\tt heightflag = 'H'}, the height of a node is one unit more than that of its highest child. When {\tt heightflag = 'D'}, the height of a node is one unit less than that of its parent. \par \noindent {\tt Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt tree} is {\tt NULL} \\ -2 & {\tt heightflag} is invalid \end{tabular} \quad \begin{tabular}{rl} -3 & {\tt coordflag} is invalid \\ -3 & {\tt xDV} is {\tt NULL} \\ -4 & {\tt yDV} is {\tt NULL} \end{tabular} \end{center} %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_drawToEPS ( Tree *tree, FILE *filename, DV *xDV, DV *yDV, double rscale, DV *radiusDV, int labelflag, double fontscale, IV *labelsIV, double bbox[], double frame[], double bounds[] ) ; \end{verbatim} \index{Tree_drawToEPS@{\tt Tree\_drawToEPS()}} This method draws a tree. The coordinates of the nodes are found in the {\tt xDV} and {\tt yDV} vectors. \par The nodes will have circles of constant radius (if {\tt radiusDV} is {\tt NULL}) or each circle can have a different radius found in {\tt radiusDV} when {\tt radiusDV} is not {\tt NULL}. The value {\tt rscale} is used to scale all the radii. (If {\tt radiusDV} is {\tt NULL}, then all radii are equal to one point --- there are 72 points to the inch.) \par If {\tt labelflag = 1}, the nodes will have a numeric label. If {\tt labelsIV} is {\tt NULL}, then the label will be the node id. Otherwise, the labels are taken from the {\tt labelsIV} vector. The size of the fonts for the labels is found in {\tt fontscale}, e.g., {\tt fontscale = 10} implies using a 10 point font. {\tt bbox[4]} and {\tt frame[4]} define the bounding box and frame, respectively. \par If {\tt bounds[]} is {\tt NULL}, the tree is sized to fit inside the frame. Note, when the radii of the nodes are non-constant, determining the local coordinates is a non-linear process that may not converge for a large radius with respect to the frame. If this occurs, an error message is printed and the program exits. If {\tt bounds[]} is not {\tt NULL}, then the nodes are mapped to local coordinates within the frame. This is useful when we have two or more trees that need a common reference frame. (See the {\tt testFS} driver program in the {\tt ETree/drivers} directory.) \par See the {\tt drawTree} driver program in the next section. \par \noindent {\tt Return codes:} \begin{center} \begin{tabular}{rl} 1 & normal return \\ -1 & {\tt tree} is {\tt NULL} \\ -2 & {\tt filename} is {\tt NULL} \\ -3 & {\tt xDV} is {\tt NULL} \\ -4 & {\tt yDV} is {\tt NULL} \end{tabular} \quad \begin{tabular}{rl} -5 & {\tt rscale} is negative \\ -6 & {\tt fontscale} is negative \\ -7 & {\tt bbox} is {\tt NULL} \\ -8 & {\tt frame} is {\tt NULL} \end{tabular} \end{center} %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:Tree:proto:IO} \par There are the usual eight IO routines. The file structure of a tree object is simple: {\tt size}, {\tt root}, {\tt par[size]}, {\tt fch[size]} and {\tt sib[size]}. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_readFromFile ( Tree *tree, char *fn ) ; \end{verbatim} \index{Tree_readFromFile@{\tt Tree\_readFromFile()}} \par This method reads in a {\tt Perm} object from a file. It tries to open the file and if it is successful, it then calls {\tt Tree\_readFromFormattedFile()} or {\tt Tree\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt tree} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.treef} (for a formatted file) or {\tt *.treeb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_readFromFormattedFile ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_readFromFormattedFile@{\tt Tree\_readFromFormattedFile()}} \par This method reads in a {\tt Perm} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt tree} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_readFromBinaryFile ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_readFromBinaryFile@{\tt Tree\_readFromBinaryFile()}} \par This method reads in a {\tt Perm} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt tree} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_writeToFile ( Tree *tree, char *fn ) ; \end{verbatim} \index{Tree_writeToFile@{\tt Tree\_writeToFile()}} \par This method writes a {\tt Perm} object to a file. It tries to open the file and if it is successful, it then calls {\tt Tree\_writeFromFormattedFile()} or {\tt Tree\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt tree} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.treef} (for a formatted file) or {\tt *.treeb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_writeToFormattedFile ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_writeToFormattedFile@{\tt Tree\_writeToFormattedFile()}} \par This method writes a {\tt Perm} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt tree} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_writeToBinaryFile ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_writeToBinaryFile@{\tt Tree\_writeToBinaryFile()}} \par This method writes a {\tt Perm} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt tree} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_writeForHumanEye ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_writeForHumanEye@{\tt Tree\_writeForHumanEye()}} \par This method writes a {\tt Perm} object to a file in a human readable format. The method {\tt Tree\_writeStats()} is called to write out the header and statistics. Then the parent, first child and sibling values are printed out in three columns. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt tree} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_writeStats ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_writeStats@{\tt Tree\_writeStats()}} \par This method writes the header and statistics to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt tree} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} dToNewPerm@{\tt Tree\_fillOldToNewPerm()}} \index{TreeTree/doc/main.idx010064400020550007177000000057360665243601100152050ustar00clevecompmath00000400000006\indexentry{Tree_new@{\tt Tree\_new()}}{2} \indexentry{Tree_setDefaultFields@{\tt Tree\_setDefaultFields()}}{2} \indexentry{Tree_clearData@{\tt Tree\_clearData()}}{2} \indexentry{Tree_free@{\tt Tree\_free()}}{2} \indexentry{Tree_nnodes@{\tt Tree\_nnodes()}}{2} \indexentry{Tree_root@{\tt Tree\_root()}}{2} \indexentry{Tree_par@{\tt Tree\_par()}}{2} \indexentry{Tree_fch@{\tt Tree\_fch()}}{3} \indexentry{Tree_sib@{\tt Tree\_sib()}}{3} \indexentry{Tree_init1@{\tt Tree\_init1()}}{3} \indexentry{Tree_init2@{\tt Tree\_init2()}}{3} \indexentry{Tree_init3@{\tt Tree\_init3()}}{3} \indexentry{Tree_initFromSubtree@{\tt Tree\_initFromSubtree()}}{3} \indexentry{Tree_setFchSibRoot@{\tt Tree\_setFchSibRoot()}}{4} \indexentry{Tree_setRoot@{\tt Tree\_setRoot()}}{4} \indexentry{Tree_sizeOf@{\tt Tree\_sizeOf()}}{4} \indexentry{Tree_postOTfirst@{\tt Tree\_postOTfirst()}}{4} \indexentry{Tree_postOTnext@{\tt Tree\_postOTnext()}}{4} \indexentry{Tree_preOTfirst@{\tt Tree\_preOTfirst()}}{4} \indexentry{Tree_preOTnext@{\tt Tree\_preOTnext()}}{4} \indexentry{Tree_nleaves@{\tt Tree\_nleaves()}}{5} \indexentry{Tree_nroots@{\tt Tree\_nroots()}}{5} \indexentry{Tree_nchild@{\tt Tree\_nchild()}}{5} \indexentry{Tree_nchildIV@{\tt Tree\_nchildIV()}}{5} \indexentry{Tree_maxNchild@{\tt Tree\_maxNchild()}}{5} \indexentry{Tree_height@{\tt Tree\_height()}}{5} \indexentry{Tree_maximizeGainIV@{\tt Tree\_maximizeGainIV()}}{5} \indexentry{Tree_setSubtreeImetric@{\tt Tree\_setSubtreeImetric()}}{6} \indexentry{Tree_setSubtreeDmetric@{\tt Tree\_setSubtreeDmetric()}}{6} \indexentry{Tree_setDepthImetric@{\tt Tree\_setDepthImetric()}}{6} \indexentry{Tree_setDepthDmetric@{\tt Tree\_setDepthDmetric()}}{6} \indexentry{Tree_setHeightImetric@{\tt Tree\_setHeightImetric()}}{6} \indexentry{Tree_setHeightDmetric@{\tt Tree\_setHeightDmetric()}}{6} \indexentry{Tree_fundChainMap@{\tt Tree\_fundChainMap()}}{7} \indexentry{Tree_compress@{\tt Tree\_compress()}}{7} \indexentry{Tree_leftJustify@{\tt Tree\_leftJustify()}}{7} \indexentry{Tree_leftJustifyI@{\tt Tree\_leftJustifyI()}}{7} \indexentry{Tree_leftJustifyD@{\tt Tree\_leftJustifyD()}}{7} \indexentry{Tree_fillNewToOldPerm@{\tt Tree\_fillNewToOldPerm()}}{8} \indexentry{Tree_fillOldToNewPerm@{\tt Tree\_fillOldToNewPerm()}}{8} \indexentry{Tree_fillBothPerms@{\tt Tree\_fillBothPerms()}}{8} \indexentry{Tree_permute@{\tt Tree\_permute()}}{8} \indexentry{Tree_getSimpleCoords@{\tt Tree\_getSimpleCoords()}}{8} \indexentry{Tree_drawToEPS@{\tt Tree\_drawToEPS()}}{8} \indexentry{Tree_readFromFile@{\tt Tree\_readFromFile()}}{9} \indexentry{Tree_readFromFormattedFile@{\tt Tree\_readFromFormattedFile()}}{9} \indexentry{Tree_readFromBinaryFile@{\tt Tree\_readFromBinaryFile()}}{9} \indexentry{Tree_writeToFile@{\tt Tree\_writeToFile()}}{9} \indexentry{Tree_writeToFormattedFile@{\tt Tree\_writeToFormattedFile()}}{10} \indexentry{Tree_writeToBinaryFile@{\tt Tree\_writeToBinaryFile()}}{10} \indexentry{Tree_writeForHumanEye@{\tt Tree\_writeForHumanEye()}}{10} \indexentry{Tree_writeStats@{\tt Tree\_writeStats()}}{10} Tree/doc/proto.tex.bak010064400020550007177000000556670653410606100162020ustar00clevecompmath00000400000006\par \subsection{Prototypes and descriptions of {\tt Tree} methods} \label{subsection:Tree:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Tree} object. \par \subsubsection{Basic methods} \label{subsubsection:Tree:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} Tree * Tree_new ( void ) ; \end{verbatim} \index{Tree_new@{\tt Tree\_new()}} This method simply allocates storage for the {\tt Tree} structure and then sets the default fields by a call to {\tt Tree\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_setDefaultFields ( Tree *tree ) ; \end{verbatim} \index{Tree_setDefaultFields@{\tt Tree\_setDefaultFields()}} This method checks to see whether {\tt tree} is {\tt NULL}. If so, an error message is printed and the program exits. Otherwise, the structure's fields are set to default values: {\tt n} is zero, {\tt root} is {\tt -1}, and {\tt par}, {\tt fch} and {\tt sib} are all {\tt NULL}. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_clearData ( Tree *tree ) ; \end{verbatim} \index{Tree_clearData@{\tt Tree\_clearData()}} This method checks to see whether {\tt tree} is {\tt NULL}. If so, an error message is printed and the program exits. Otherwise, it releases any storage held by the parent, first child and sibling vectors, then sets the structure's default fields with a call to {\tt Tree\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_free ( Tree *tree ) ; \end{verbatim} \index{Tree_free@{\tt Tree\_free()}} This method checks to see whether {\tt tree} is {\tt NULL}. If so, an error message is printed and the program exits. Otherwise, it releases any storage by a call to {\tt Tree\_clearData()} then free's the storage for the structure with a call to {\tt free()}. %----------------------------------------------------------------------- \end{enumerate} \subsubsection{IO methods} \label{subsubsection:Tree:proto:IO} \par There are the usual eight IO routines. The file structure of a tree object is simple: {\tt size}, {\tt root}, {\tt par[size]}, {\tt fch[size]} and {\tt sib[size]}. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_readFromFile ( Tree *tree, char *fn ) ; \end{verbatim} \index{Tree_readFromFile@{\tt Tree\_readFromFile()}} \par If {\tt tree} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.treef} (for a formatted file) or {\tt *.treeb} (for a binary file), an error message is printed and the method returns zero. Otherwise, it tries to open the file and if it is successful, it then calls {\tt Tree\_readFromFormattedFile()} or {\tt Tree\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_readFormattedFile ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_readFormattedFile@{\tt Tree\_readFormattedFile()}} \par If {\tt tree} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. Otherwise, the data is read in from the file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_readBinaryFile ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_readBinaryFile@{\tt Tree\_readBinaryFile()}} \par If {\tt tree} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. Otherwise, the data is read in from the file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_writeToFile ( Tree *tree, char *fn ) ; \end{verbatim} \index{Tree_writeToFile@{\tt Tree\_writeToFile()}} \par If {\tt tree} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.treef} (for a formatted file) or {\tt *.treeb} (for a binary file), an error message is printed and the method returns zero. Otherwise, it tries to open the file and if it is successful, it then calls {\tt Tree\_writeFromFormattedFile()} or {\tt Tree\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_writeFormattedFile ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_writeFormattedFile@{\tt Tree\_writeFormattedFile()}} \par If {\tt tree} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. Otherwise, the data is written to the file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_writeBinaryFile ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_writeBinaryFile@{\tt Tree\_writeBinaryFile()}} \par If {\tt tree} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. Otherwise, the data is written to the file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_writeForHumanEye ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_writeForHumanEye@{\tt Tree\_writeForHumanEye()}} \par If {\tt tree} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. Otherwise, the method {\tt Tree\_writeStats()} is called to write out the header and statistics. Then the parent, first child and sibling values are printed out in three columns. The value {\tt 1} is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_writeStats ( Tree *tree, FILE *fp ) ; \end{verbatim} \index{Tree_writeStats@{\tt Tree\_writeStats()}} \par If {\tt tree} or {\tt fp} are {\tt NULL} an error message is printed and zero is returned. Otherwise, the header and statistics are written. The value {\tt 1} is returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsubsection{Initializer methods} \label{subsubsection:Tree:proto:initializers} \par There are three initializers and two helper functions to set the dimensions of the tree, allocate the three vectors, and fill the information. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_init1 ( Tree *tree, int size ) ; \end{verbatim} \index{Tree_init1@{\tt Tree\_init1()}} If {\tt tree} is {\tt NULL} or {\tt size} is negative, an error message is printed and the program exits. It then clears any previous data with a call to {\tt Tree\_clearData()}, sets the size and allocates storage for the three tree vectors using {\tt IVinit()}. All entries in the three vectors are set to {\tt -1}. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_init2 ( Tree *tree, int size, int par[] ) ; \end{verbatim} \index{Tree_init2@{\tt Tree\_init2()}} If {\tt tree} is {\tt NULL} or {\tt size} is negative, an error message is printed and the program exits. Otherwise, the simple initializer {\tt Tree\_init1()} is called and the entries in {\tt par[]} are copied into the parent vector. The helper method {\tt Tree\_setFchSibRoot()} is then called to set the other fields. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_init3 ( Tree *tree, int size, int par[], int fch[], int sib[] ) ; \end{verbatim} \index{Tree_init3@{\tt Tree\_init3()}} If {\tt tree} is {\tt NULL} or {\tt size} is negative, an error message is printed and the program exits. Otherwise, the simple initializer {\tt Tree\_init1()} is called and the entries in {\tt par[]}, {\tt fch[]} and {\tt sib[]} are copied into their respective vectors. The helper method {\tt Tree\_setRoot()} is then called to set the root field. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_setFchSibRoot ( Tree *tree ) ; \end{verbatim} \index{Tree_setFchSibRoot@{\tt Tree\_setFchSibRoot()}} If {\tt tree} is {\tt NULL} or {\tt tree->n < 1}, an error message is printed and the program exits. Otherwise, the root and the entries in the {\tt fch[]} and {\tt sib[]} vectors are set using the entries in the {\tt par[]} vector. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_setRoot ( Tree *tree ) ; \end{verbatim} \index{Tree_setRoot@{\tt Tree\_setRoot()}} If {\tt tree} is {\tt NULL} or {\tt tree->n < 1}, an error message is printed and the program exits. Otherwise, the vertices that are roots in the tree are linked by their {\tt sib[]} field and the root of the tree is set to the head of the list. %----------------------------------------------------------------------- \end{enumerate} \par \subsubsection{Utility methods} \label{subsubsection:Tree:proto:utilities} \par The utility methods return the number of bytes taken by the object, aid in performing pre-order and post-order traversals, and return statistics about the tree (e.g., the number of roots or leaves in the tree, or the number of children of a node in the tree). This functionality can be easily had by direct manipulation or inquiry of the object, but these methods insulate the user from the internals and allow us to change and improve the internals if necessary. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_sizeOf ( Tree *tree ) ; \end{verbatim} \index{Tree_sizeOf@{\tt Tree\_sizeOf()}} If {\tt tree} is {\tt NULL}, an error message is printed and the program exits. Otherwise, the number of bytes taken by this object is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_postOTfirst ( Tree *tree ) ; \end{verbatim} \index{Tree_postOTfirst@{\tt Tree\_postOTfirst()}} If {\tt tree} is {\tt NULL} or {\tt tree->n < 1}, an error message is printed and the program exits. Otherwise, the first node in a post-order traversal is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_postOTnext ( Tree *tree, int v ) ; \end{verbatim} \index{Tree_postOTnext@{\tt Tree\_postOTnext()}} If {\tt tree} is {\tt NULL}, {\tt tree->n < 1} or {\tt v} is not in {\tt [0,tree->n-1]}, an error message is printed and the program exits. Otherwise, the node that follows {\tt v} in a post-order traversal is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_preOTfirst ( Tree *tree ) ; \end{verbatim} \index{Tree_preOTfirst@{\tt Tree\_preOTfirst()}} If {\tt tree} is {\tt NULL} or {\tt tree->n < 1}, an error message is printed and the program exits. Otherwise, the first node in a pre-order traversal is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_preOTnext ( Tree *tree, int v ) ; \end{verbatim} \index{Tree_preOTnext@{\tt Tree\_preOTnext()}} If {\tt tree} is {\tt NULL}, {\tt tree->n < 1} or {\tt v} is not in {\tt [0,tree->n-1]}, an error message is printed and the program exits. Otherwise, the node that follows {\tt v} in a pre-order traversal is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_nleaves ( Tree *tree ) ; \end{verbatim} \index{Tree_nleaves@{\tt Tree\_nleaves()}} If {\tt tree} is {\tt NULL} or {\tt tree->n < 1}, an error message is printed and the program exits. Otherwise, the number of leaves of the tree is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_nroots ( Tree *tree ) ; \end{verbatim} \index{Tree_nroots@{\tt Tree\_nroots()}} If {\tt tree} is {\tt NULL} or {\tt tree->n < 1}, an error message is printed and the program exits. Otherwise, the number of roots of the tree (really a forest) is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_nchild ( Tree *tree, int v ) ; \end{verbatim} \index{Tree_nchild@{\tt Tree\_nchild()}} If {\tt tree} is {\tt NULL} or {\tt tree->n < 1}, an error message is printed and the program exits. Otherwise, the number of children of {\tt v} is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_maxNchild ( Tree *tree ) ; \end{verbatim} \index{Tree_maxNchild@{\tt Tree\_maxNchild()}} If {\tt tree} is {\tt NULL} or {\tt tree->n < 1}, an error message is printed and the program exits. Otherwise, the maximum number of children of any vertex is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_height ( Tree *tree ) ; \end{verbatim} \index{Tree_height@{\tt Tree\_height()}} If {\tt tree} is {\tt NULL} or {\tt tree->n < 1}, an error message is printed and the program exits. Otherwise, the height of the tree is returned. %----------------------------------------------------------------------- \end{enumerate} \subsubsection{Metrics methods} \label{subsubsection:Tree:proto:metrics} \par Many operations need to know some {\it metric} defined on the nodes in a tree. Here are three examples: the height of a node (the minimum distance from a descendant leaf), the depth of a node (the distance from its root ancestor), or the weight associated with a subtree rooted at a node. Of course, a weight could be associated with each node, so the height or depth becomes the weight of the nodes on the path. \par Metrics can be {\tt int}, {\tt float} or {\tt double}. Because of the limitations of C, we need three separate methods for each of the height, depth and subtree functions. Each trio of methods differs only in the type of the vector argument. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_setSubtreeImetric ( Tree *tree, int vmetric[], int tmetric[] ) ; void Tree_setSubtreeFmetric ( Tree *tree, float vmetric[], float tmetric[] ) ; void Tree_setSubtreeDmetric ( Tree *tree, double vmetric[], double tmetric[] ) ; \end{verbatim} \index{Tree_setSubtreeImetric@{\tt Tree\_setSubtreeImetric()}} \index{Tree_setSubtreeFmetric@{\tt Tree\_setSubtreeFmetric()}} \index{Tree_setSubtreeDmetric@{\tt Tree\_setSubtreeDmetric()}} If {\tt tree}, {\tt vmetric} or {\tt tmetric} are {\tt NULL} or if {\tt tree->n < 1}, an error message is printed and the program exits. The vector {\tt vmetric[]} contains weights for each node. On return, {\tt tmetric[v]} contains the weight of the subtree rooted at {\tt v}. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_setDepthImetric ( Tree *tree, int vmetric[], int dmetric[] ) ; void Tree_setDepthFmetric ( Tree *tree, float vmetric[], float dmetric[] ) ; void Tree_setDepthDmetric ( Tree *tree, double vmetric[], double dmetric[] ) ; \end{verbatim} \index{Tree_setDepthImetric@{\tt Tree\_setDepthImetric()}} \index{Tree_setDepthFmetric@{\tt Tree\_setDepthFmetric()}} \index{Tree_setDepthDmetric@{\tt Tree\_setDepthDmetric()}} If {\tt tree}, {\tt vmetric} or {\tt dmetric} are {\tt NULL} or if {\tt tree->n < 1}, an error message is printed and the program exits. The vector {\tt vmetric[]} contains weights for each node. On return, {\tt dmetric[v]} contains the depth of {\tt v} measured as the weight of nodes on the path from {\tt v} to its root. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_setHeightImetric ( Tree *tree, int vmetric[], int hmetric[] ) ; void Tree_setHeightFmetric ( Tree *tree, float vmetric[], float hmetric[] ) ; void Tree_setHeightDmetric ( Tree *tree, double vmetric[], double hmetric[] ) ; \end{verbatim} \index{Tree_setHeightImetric@{\tt Tree\_setHeightImetric()}} \index{Tree_setHeightFmetric@{\tt Tree\_setHeightFmetric()}} \index{Tree_setHeightDmetric@{\tt Tree\_setHeightDmetric()}} If {\tt tree}, {\tt vmetric} or {\tt hmetric} are {\tt NULL} or if {\tt tree->n < 1}, an error message is printed and the program exits. The vector {\tt vmetric[]} contains weights for each node. On return, {\tt hmetric[v]} contains the height of {\tt v} measured as the minimum path weight from {\tt v} to one of its descendant leaves. %----------------------------------------------------------------------- \end{enumerate} \par \subsubsection{Compression methods} \label{subsubsection:Tree:proto:compression} \par Frequently a tree will need to be compressed in some manner. Elimination trees usually have long chains of nodes at the higher levels, where each chain of nodes corresponds to a supernode. Liu's generalized row envelope methods partition the vertices by longest chains \cite{liu91-generalizedEnvelope}. In both cases, we can construct a map from each node to a set of nodes to define a smaller, more compact tree. Given such a map, we construct the smaller tree. \par A fundamental chain is a set of nodes $v_1, \ldots, v_m$ such that (1) $v_1$ is a leaf or has two or more children, (2) $v_{i+1}$ is the parent of $v_i$ for $1 \le i < m$, and (3) $v_m$ is either a root or has a sibling. The set of fundamental chains is uniquely defined. In the context of elimination trees, a fundamental chain is very close to a fundamental supernode, and in many cases, fundamental chains can be used to contruct the fronts with little added fill and factor operations. %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int Tree_fundChainMap ( Tree *tree, int map[] ) ; \end{verbatim} \index{Tree_fundChainMap@{\tt Tree\_fundChainMap()}} If {\tt tree} is {\tt NULL}, {\tt tree->n < 1} or if {\tt map} is {\tt NULL}, an error message is printed and the program exits. On return, {\tt map[v]} contains the id of the fundamental chain that contains {\tt v}. If {\tt u} is a descendant of {\tt v}, then {\tt map[u] <= map[v]}. The number of fundamental chains is returned. %----------------------------------------------------------------------- \item \begin{verbatim} Tree * Tree_compress ( Tree *tree, int map[] ) ; \end{verbatim} \index{Tree_compress@{\tt Tree\_compress()}} If {\tt tree} is {\tt NULL}, {\tt tree->n < 1} or if {\tt map} is {\tt NULL}, an error message is printed and the program exits. The compressed tree is constructed and returned. %----------------------------------------------------------------------- \end{enumerate} \par \subsubsection{Justification methods} \label{subsubsection:Tree:proto:justify} \par Given a tree, how should the children of a node be ordered? This ``justification'' can have a large impact in the working storage for the front tree in the multifrontal algorithm. Justification also is useful when displaying trees. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_leftJustify ( Tree *tree ) ; \end{verbatim} \index{Tree_leftJustify@{\tt Tree\_leftJustify()}} If {\tt tree} is {\tt NULL} or {\tt tree->n < 1}, an error message is printed and the program exits. Otherwise, if {\tt u} and {\tt v} are siblings, and {\tt u} comes before {\tt v} in a post-order traversal, then the size of the subtree rooted at {\tt u} is as large or larger than the size of the subtree rooted at {\tt v}. %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_leftJustifyI ( Tree *tree, int metric[] ) ; void Tree_leftJustifyF ( Tree *tree, float metric[] ) ; void Tree_leftJustifyD ( Tree *tree, double metric[] ) ; \end{verbatim} \index{Tree_leftJustifyI@{\tt Tree\_leftJustifyI()}} \index{Tree_leftJustifyF@{\tt Tree\_leftJustifyF()}} \index{Tree_leftJustifyD@{\tt Tree\_leftJustifyD()}} If {\tt tree} is {\tt NULL}, {\tt tree->n < 1} or {\tt metric} is {\tt NULL}, an error message is printed and the program exits. Otherwise, if {\tt u} and {\tt v} are siblings, and {\tt u} comes before {\tt v} in a post-order traversal, then the weight of the subtree rooted at {\tt u} is as large or larger than the weight of the subtree rooted at {\tt v}. %----------------------------------------------------------------------- \end{enumerate} \par \subsubsection{Permutation methods} \label{subsubsection:Tree:proto:permutation} \par Often we need to extract a permutation from a tree, e.g., a post-order traversal of an elimination tree gives an ordering for a sparse matrix. On other occasions, we need to permute a tree, i.e. re-label the nodes. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void Tree_fillNewToOldPerm ( Tree *tree, int newToOld[] ) ; void Tree_fillOldToNewPerm ( Tree *tree, int oldToNew[] ) ; void Tree_fillBothPerms ( Tree *tree, int newToOld[], int oldToNew[] ) ; \end{verbatim} \index{Tree_fillNewToOldPerm@{\tt Tree\_fillNewToOldPerm()}} \index{Tree_fillOldToNewPerm@{\tt Tree\_fillOldToNewPerm()}} \index{Tree_fillBothPerms@{\tt Tree\_fillBothPerms()}} If {\tt tree} is {\tt NULL}, {\tt tree->n < 1} or a permutation vector is {\tt NULL}, an error message is printed and the program exits. Otherwise, the permutation vector(s) is (are) filled with the ordering of the nodes in a post-order traversal. %----------------------------------------------------------------------- \item \begin{verbatim} Tree * Tree_permute ( Tree *tree, int newToOld[], int oldToNew[] ) ; \end{verbatim} \index{Tree_permute@{\tt Tree\_permute()}} If {\tt tree} is {\tt NULL}, {\tt tree->n < 1} or a permutation vector is {\tt NULL}, an error message is printed and the program exits. Otherwise, a new tree is created with the same connectivity as the old but the nodes are relabeled. %----------------------------------------------------------------------- \end{enumerate} -------------------------------------------------------- \item \begin{verTree/doc/main.ilg010064400020550007177000000004570665243537100151770ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (52 entries accepted, 0 rejected). Sorting entries....done (304 comparisons). Generating output file main.ind....done (56 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Tree/doc/drivers.tex010064400020550007177000000070440665243607600157600ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt Tree} object} \label{section:Tree:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} drawTree msglvl msgFile inTreeFile inTagsFile outEPSfile heightflag coordflag radius bbox[4] frame[4] tagflag fontsize \end{verbatim} This driver program reads in a {\tt Tree} file and optionally a tags {\tt IV} file and creates an EPS file with a simple picture of a tree. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the output file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inTreeFile} parameter is the input file for the {\tt Tree} object. It must be of the form {\tt *.treef} or {\tt *.treeb}. The {\tt Tree} object is read from the file via the {\tt Tree\_readFromFile()} method. \item The {\tt inTagsFile} parameter is the input file for the {\tt IV} vector object than holds the tags for the nodes. It must be of the form {\tt *.ivf} or {\tt *.ivb} or {\tt none}. The {\tt IV} object is read from the file via the {\tt IV\_readFromFile()} method. \item The {\tt outEPSfile} parameter is name of the encapsulated Postscript file to be written. \item The {\tt heightflag} parameter is {\tt 'D'} to use a depth metric, (i.e., parent and child are in adjacent levels), and {\tt 'H'} to use a height metric (i.e., a leaf is on the outermost level). \item The {\tt coordflag} parameter is {\tt 'C'} to put the tree in a Cartesian coordinate system and {\tt 'P'} for a polar coordinate system. \item The {\tt radius} parameter is the radius of each node in the tree. \item The {\tt bbox} parameter a sequence of four numbers that form the bounding box: lower left $x$ value, lower left $y$ value, width and height. \item The {\tt frame} parameter a sequence of four numbers that form the frame of the plot within the bounding box: lower left $x$ value, lower left $y$ value, width and height. \item When {\tt tagflag = 1}, tags are drawn on the nodes. If {\tt tagsFile} is {\tt NULL}, then node ids will be drawn on the nodes. Otherwise, node ids will be taken from the {\tt tagsIV} object. \item The {\tt fontsize} parameter is the size of the font to be used to draw the node labels. \end{itemize} Use the {\tt doDraw} script file as an example. Four plots of a tree for the {\tt R2D100} matrix ordered by nested dissection are found below. %----------------------------------------------------------------------- \end{enumerate} \par \begin{figure}[htbp] \caption{{\sc R2D100}: domain/separator tree. On the left {\tt heightflag = 'H'} and {\tt coordflag = 'C'}, on the right {\tt heightflag = 'D'} and {\tt coordflag = 'C'}.} \label{fig-R2D100-tree-HC} \begin{center} \mbox{ \psfig{file=../../Tree/doc/R2D100HC.eps,height=3.00in,width=3.00in} } \mbox{ \psfig{file=../../Tree/doc/R2D100DC.eps,height=3.00in,width=3.00in} } \end{center} \end{figure} \par \begin{figure}[htbp] \caption{{\sc R2D100}: domain/separator tree. On the left {\tt heightflag = 'H'} and {\tt coordflag = 'P'}, on the right {\tt heightflag = 'D'} and {\tt coordflag = 'P'}.} \label{fig-R2D100-tree-HP} \begin{center} \mbox{ \psfig{file=../../Tree/doc/R2D100HP.eps,height=3.00in,width=3.00in} } \mbox{ \psfig{file=../../Tree/doc/R2D100DP.eps,height=3.00in,width=3.00in} } \end{center} \end{figure} Tree/doc/R2D400DC.eps010064400020550007177000000163520653410606100153000ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 500 200 /CSH { % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def 10 10 480 180 rectstroke newpath 18 50.4 moveto 30.8 82.8 lineto 43.7 50.4 moveto 30.8 82.8 lineto 30.8 82.8 moveto 66.1 115 lineto 69.3 18 moveto 82.2 50.4 lineto 95 18 moveto 82.2 50.4 lineto 82.2 50.4 moveto 101 82.8 lineto 121 50.4 moveto 101 82.8 lineto 101 82.8 moveto 66.1 115 lineto 66.1 115 moveto 125 148 lineto 146 50.4 moveto 159 82.8 lineto 172 50.4 moveto 159 82.8 lineto 159 82.8 moveto 185 115 lineto 198 50.4 moveto 210 82.8 lineto 223 50.4 moveto 210 82.8 lineto 210 82.8 moveto 185 115 lineto 185 115 moveto 125 148 lineto 125 148 moveto 243 180 lineto 249 50.4 moveto 262 82.8 lineto 275 50.4 moveto 262 82.8 lineto 262 82.8 moveto 291 115 lineto 300 50.4 moveto 320 82.8 lineto 326 18 moveto 339 50.4 lineto 352 18 moveto 339 50.4 lineto 339 50.4 moveto 320 82.8 lineto 320 82.8 moveto 291 115 lineto 291 115 moveto 361 148 lineto 377 50.4 moveto 397 82.8 lineto 403 18 moveto 416 50.4 lineto 429 18 moveto 416 50.4 lineto 416 50.4 moveto 397 82.8 lineto 397 82.8 moveto 432 115 lineto 454 50.4 moveto 467 82.8 lineto 480 50.4 moveto 467 82.8 lineto 467 82.8 moveto 432 115 lineto 432 115 moveto 361 148 lineto 361 148 moveto 243 180 lineto stroke gsave /Helvetica-Bold findfont 10 scalefont setfont 1.0 setgray newpath 26 50.4 moveto 18 50.4 8 0 360 arc fill 0.0 setgray newpath 26 50.4 moveto 18 50.4 8 0 360 arc stroke 18 46.4 moveto (0) CSH 1.0 setgray newpath 51.7 50.4 moveto 43.7 50.4 8 0 360 arc fill 0.0 setgray newpath 51.7 50.4 moveto 43.7 50.4 8 0 360 arc stroke 43.7 46.4 moveto (1) CSH 1.0 setgray newpath 38.8 82.8 moveto 30.8 82.8 8 0 360 arc fill 0.0 setgray newpath 38.8 82.8 moveto 30.8 82.8 8 0 360 arc stroke 30.8 78.8 moveto (2) CSH 1.0 setgray newpath 77.3 18 moveto 69.3 18 8 0 360 arc fill 0.0 setgray newpath 77.3 18 moveto 69.3 18 8 0 360 arc stroke 69.3 14 moveto (3) CSH 1.0 setgray newpath 103 18 moveto 95 18 8 0 360 arc fill 0.0 setgray newpath 103 18 moveto 95 18 8 0 360 arc stroke 95 14 moveto (4) CSH 1.0 setgray newpath 90.2 50.4 moveto 82.2 50.4 8 0 360 arc fill 0.0 setgray newpath 90.2 50.4 moveto 82.2 50.4 8 0 360 arc stroke 82.2 46.4 moveto (5) CSH 1.0 setgray newpath 129 50.4 moveto 121 50.4 8 0 360 arc fill 0.0 setgray newpath 129 50.4 moveto 121 50.4 8 0 360 arc stroke 121 46.4 moveto (6) CSH 1.0 setgray newpath 109 82.8 moveto 101 82.8 8 0 360 arc fill 0.0 setgray newpath 109 82.8 moveto 101 82.8 8 0 360 arc stroke 101 78.8 moveto (7) CSH 1.0 setgray newpath 74.1 115 moveto 66.1 115 8 0 360 arc fill 0.0 setgray newpath 74.1 115 moveto 66.1 115 8 0 360 arc stroke 66.1 111 moveto (8) CSH 1.0 setgray newpath 154 50.4 moveto 146 50.4 8 0 360 arc fill 0.0 setgray newpath 154 50.4 moveto 146 50.4 8 0 360 arc stroke 146 46.4 moveto (9) CSH 1.0 setgray newpath 180 50.4 moveto 172 50.4 8 0 360 arc fill 0.0 setgray newpath 180 50.4 moveto 172 50.4 8 0 360 arc stroke 172 46.4 moveto (10) CSH 1.0 setgray newpath 167 82.8 moveto 159 82.8 8 0 360 arc fill 0.0 setgray newpath 167 82.8 moveto 159 82.8 8 0 360 arc stroke 159 78.8 moveto (11) CSH 1.0 setgray newpath 206 50.4 moveto 198 50.4 8 0 360 arc fill 0.0 setgray newpath 206 50.4 moveto 198 50.4 8 0 360 arc stroke 198 46.4 moveto (12) CSH 1.0 setgray newpath 231 50.4 moveto 223 50.4 8 0 360 arc fill 0.0 setgray newpath 231 50.4 moveto 223 50.4 8 0 360 arc stroke 223 46.4 moveto (13) CSH 1.0 setgray newpath 218 82.8 moveto 210 82.8 8 0 360 arc fill 0.0 setgray newpath 218 82.8 moveto 210 82.8 8 0 360 arc stroke 210 78.8 moveto (14) CSH 1.0 setgray newpath 193 115 moveto 185 115 8 0 360 arc fill 0.0 setgray newpath 193 115 moveto 185 115 8 0 360 arc stroke 185 111 moveto (15) CSH 1.0 setgray newpath 133 148 moveto 125 148 8 0 360 arc fill 0.0 setgray newpath 133 148 moveto 125 148 8 0 360 arc stroke 125 144 moveto (16) CSH 1.0 setgray newpath 257 50.4 moveto 249 50.4 8 0 360 arc fill 0.0 setgray newpath 257 50.4 moveto 249 50.4 8 0 360 arc stroke 249 46.4 moveto (17) CSH 1.0 setgray newpath 283 50.4 moveto 275 50.4 8 0 360 arc fill 0.0 setgray newpath 283 50.4 moveto 275 50.4 8 0 360 arc stroke 275 46.4 moveto (18) CSH 1.0 setgray newpath 270 82.8 moveto 262 82.8 8 0 360 arc fill 0.0 setgray newpath 270 82.8 moveto 262 82.8 8 0 360 arc stroke 262 78.8 moveto (19) CSH 1.0 setgray newpath 308 50.4 moveto 300 50.4 8 0 360 arc fill 0.0 setgray newpath 308 50.4 moveto 300 50.4 8 0 360 arc stroke 300 46.4 moveto (20) CSH 1.0 setgray newpath 334 18 moveto 326 18 8 0 360 arc fill 0.0 setgray newpath 334 18 moveto 326 18 8 0 360 arc stroke 326 14 moveto (21) CSH 1.0 setgray newpath 360 18 moveto 352 18 8 0 360 arc fill 0.0 setgray newpath 360 18 moveto 352 18 8 0 360 arc stroke 352 14 moveto (22) CSH 1.0 setgray newpath 347 50.4 moveto 339 50.4 8 0 360 arc fill 0.0 setgray newpath 347 50.4 moveto 339 50.4 8 0 360 arc stroke 339 46.4 moveto (23) CSH 1.0 setgray newpath 328 82.8 moveto 320 82.8 8 0 360 arc fill 0.0 setgray newpath 328 82.8 moveto 320 82.8 8 0 360 arc stroke 320 78.8 moveto (24) CSH 1.0 setgray newpath 299 115 moveto 291 115 8 0 360 arc fill 0.0 setgray newpath 299 115 moveto 291 115 8 0 360 arc stroke 291 111 moveto (25) CSH 1.0 setgray newpath 385 50.4 moveto 377 50.4 8 0 360 arc fill 0.0 setgray newpath 385 50.4 moveto 377 50.4 8 0 360 arc stroke 377 46.4 moveto (26) CSH 1.0 setgray newpath 411 18 moveto 403 18 8 0 360 arc fill 0.0 setgray newpath 411 18 moveto 403 18 8 0 360 arc stroke 403 14 moveto (27) CSH 1.0 setgray newpath 437 18 moveto 429 18 8 0 360 arc fill 0.0 setgray newpath 437 18 moveto 429 18 8 0 360 arc stroke 429 14 moveto (28) CSH 1.0 setgray newpath 424 50.4 moveto 416 50.4 8 0 360 arc fill 0.0 setgray newpath 424 50.4 moveto 416 50.4 8 0 360 arc stroke 416 46.4 moveto (29) CSH 1.0 setgray newpath 405 82.8 moveto 397 82.8 8 0 360 arc fill 0.0 setgray newpath 405 82.8 moveto 397 82.8 8 0 360 arc stroke 397 78.8 moveto (30) CSH 1.0 setgray newpath 462 50.4 moveto 454 50.4 8 0 360 arc fill 0.0 setgray newpath 462 50.4 moveto 454 50.4 8 0 360 arc stroke 454 46.4 moveto (31) CSH 1.0 setgray newpath 488 50.4 moveto 480 50.4 8 0 360 arc fill 0.0 setgray newpath 488 50.4 moveto 480 50.4 8 0 360 arc stroke 480 46.4 moveto (32) CSH 1.0 setgray newpath 475 82.8 moveto 467 82.8 8 0 360 arc fill 0.0 setgray newpath 475 82.8 moveto 467 82.8 8 0 360 arc stroke 467 78.8 moveto (33) CSH 1.0 setgray newpath 440 115 moveto 432 115 8 0 360 arc fill 0.0 setgray newpath 440 115 moveto 432 115 8 0 360 arc stroke 432 111 moveto (34) CSH 1.0 setgray newpath 369 148 moveto 361 148 8 0 360 arc fill 0.0 setgray newpath 369 148 moveto 361 148 8 0 360 arc stroke 361 144 moveto (35) CSH 1.0 setgray newpath 251 180 moveto 243 180 8 0 360 arc fill 0.0 setgray newpath 251 180 moveto 243 180 8 0 360 arc stroke 243 176 moveto (36) CSH grestore1.0 setgray newpath 90.2 50.4 moveto 82.2 50.4 8 0 360 arc fill 0.0 setgray newpath 90.2 50.4 moveto 82.2 50.4 8 0 360 arc stroke 82.2 46.4 moveto (5) CSH 1.0 setgray newpath 129 50.4 moveto 121 50.4 8 0 360 arc fill 0.0 setgray newpath 129 50.4 moveto 121 50.4 8Tree/doc/R2D400HC.eps010064400020550007177000000107400653410606100152770ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 500 200 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def 10 10 480 180 rectstroke newpath 18 18 30.8 50.4 ML 43.7 18 30.8 50.4 ML 30.8 50.4 66.1 115 ML 69.3 18 82.2 50.4 ML 95 18 82.2 50.4 ML 82.2 50.4 101 82.8 ML 121 18 101 82.8 ML 101 82.8 66.1 115 ML 66.1 115 125 148 ML 146 18 159 50.4 ML 172 18 159 50.4 ML 159 50.4 185 82.8 ML 198 18 210 50.4 ML 223 18 210 50.4 ML 210 50.4 185 82.8 ML 185 82.8 125 148 ML 125 148 243 180 ML 249 18 262 50.4 ML 275 18 262 50.4 ML 262 50.4 291 115 ML 300 18 320 82.8 ML 326 18 339 50.4 ML 352 18 339 50.4 ML 339 50.4 320 82.8 ML 320 82.8 291 115 ML 291 115 361 148 ML 377 18 397 82.8 ML 403 18 416 50.4 ML 429 18 416 50.4 ML 416 50.4 397 82.8 ML 397 82.8 432 115 ML 454 18 467 50.4 ML 480 18 467 50.4 ML 467 50.4 432 115 ML 432 115 361 148 ML 361 148 243 180 ML stroke gsave /Helvetica-Bold findfont 10 scalefont setfont 1.0 setgray 18 18 8 FC 0.0 setgray 18 18 8 OC 18 14 moveto (0) CSH 1.0 setgray 43.7 18 8 FC 0.0 setgray 43.7 18 8 OC 43.7 14 moveto (1) CSH 1.0 setgray 30.8 50.4 8 FC 0.0 setgray 30.8 50.4 8 OC 30.8 46.4 moveto (2) CSH 1.0 setgray 69.3 18 8 FC 0.0 setgray 69.3 18 8 OC 69.3 14 moveto (3) CSH 1.0 setgray 95 18 8 FC 0.0 setgray 95 18 8 OC 95 14 moveto (4) CSH 1.0 setgray 82.2 50.4 8 FC 0.0 setgray 82.2 50.4 8 OC 82.2 46.4 moveto (5) CSH 1.0 setgray 121 18 8 FC 0.0 setgray 121 18 8 OC 121 14 moveto (6) CSH 1.0 setgray 101 82.8 8 FC 0.0 setgray 101 82.8 8 OC 101 78.8 moveto (7) CSH 1.0 setgray 66.1 115 8 FC 0.0 setgray 66.1 115 8 OC 66.1 111 moveto (8) CSH 1.0 setgray 146 18 8 FC 0.0 setgray 146 18 8 OC 146 14 moveto (9) CSH 1.0 setgray 172 18 8 FC 0.0 setgray 172 18 8 OC 172 14 moveto (10) CSH 1.0 setgray 159 50.4 8 FC 0.0 setgray 159 50.4 8 OC 159 46.4 moveto (11) CSH 1.0 setgray 198 18 8 FC 0.0 setgray 198 18 8 OC 198 14 moveto (12) CSH 1.0 setgray 223 18 8 FC 0.0 setgray 223 18 8 OC 223 14 moveto (13) CSH 1.0 setgray 210 50.4 8 FC 0.0 setgray 210 50.4 8 OC 210 46.4 moveto (14) CSH 1.0 setgray 185 82.8 8 FC 0.0 setgray 185 82.8 8 OC 185 78.8 moveto (15) CSH 1.0 setgray 125 148 8 FC 0.0 setgray 125 148 8 OC 125 144 moveto (16) CSH 1.0 setgray 249 18 8 FC 0.0 setgray 249 18 8 OC 249 14 moveto (17) CSH 1.0 setgray 275 18 8 FC 0.0 setgray 275 18 8 OC 275 14 moveto (18) CSH 1.0 setgray 262 50.4 8 FC 0.0 setgray 262 50.4 8 OC 262 46.4 moveto (19) CSH 1.0 setgray 300 18 8 FC 0.0 setgray 300 18 8 OC 300 14 moveto (20) CSH 1.0 setgray 326 18 8 FC 0.0 setgray 326 18 8 OC 326 14 moveto (21) CSH 1.0 setgray 352 18 8 FC 0.0 setgray 352 18 8 OC 352 14 moveto (22) CSH 1.0 setgray 339 50.4 8 FC 0.0 setgray 339 50.4 8 OC 339 46.4 moveto (23) CSH 1.0 setgray 320 82.8 8 FC 0.0 setgray 320 82.8 8 OC 320 78.8 moveto (24) CSH 1.0 setgray 291 115 8 FC 0.0 setgray 291 115 8 OC 291 111 moveto (25) CSH 1.0 setgray 377 18 8 FC 0.0 setgray 377 18 8 OC 377 14 moveto (26) CSH 1.0 setgray 403 18 8 FC 0.0 setgray 403 18 8 OC 403 14 moveto (27) CSH 1.0 setgray 429 18 8 FC 0.0 setgray 429 18 8 OC 429 14 moveto (28) CSH 1.0 setgray 416 50.4 8 FC 0.0 setgray 416 50.4 8 OC 416 46.4 moveto (29) CSH 1.0 setgray 397 82.8 8 FC 0.0 setgray 397 82.8 8 OC 397 78.8 moveto (30) CSH 1.0 setgray 454 18 8 FC 0.0 setgray 454 18 8 OC 454 14 moveto (31) CSH 1.0 setgray 480 18 8 FC 0.0 setgray 480 18 8 OC 480 14 moveto (32) CSH 1.0 setgray 467 50.4 8 FC 0.0 setgray 467 50.4 8 OC 467 46.4 moveto (33) CSH 1.0 setgray 432 115 8 FC 0.0 setgray 432 115 8 OC 432 111 moveto (34) CSH 1.0 setgray 361 148 8 FC 0.0 setgray 361 148 8 OC 361 144 moveto (35) CSH 1.0 setgray 243 180 8 FC 0.0 setgray 243 180 8 OC 243 176 moveto (36) CSH grestore showpageTree/doc/R2D400HP.eps010064400020550007177000000111540653410606100153140ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 400 400 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def 20 20 380 380 rectstroke newpath 380 205 343 228 ML 370 262 343 228 ML 343 228 261 246 ML 343 313 299 308 ML 300 352 299 308 ML 299 308 254 298 ML 247 375 254 298 ML 254 298 261 246 ML 261 246 210 240 ML 189 380 169 341 ML 133 366 169 341 ML 169 341 146 293 ML 84.5 334 92.6 291 ML 48.8 289 92.6 291 ML 92.6 291 146 293 ML 146 293 210 240 ML 210 240 204 205 ML 30 234 62.8 205 ML 30 176 62.8 205 ML 62.8 205 138 179 ML 48.8 121 126 134 ML 84.5 75.8 127 87.4 ML 133 44.2 127 87.4 ML 127 87.4 126 134 ML 126 134 138 179 ML 138 179 194 171 ML 189 30 221 101 ML 247 34.8 260 76.4 ML 300 58 260 76.4 ML 260 76.4 221 101 ML 221 101 245 148 ML 343 97.1 328 138 ML 370 148 328 138 ML 328 138 245 148 ML 245 148 194 171 ML 194 171 204 205 ML stroke gsave /Helvetica-Bold findfont 12.5 scalefont setfont 1.0 setgray 380 205 10 FC 0.0 setgray 380 205 10 OC 380 200 moveto (0) CSH 1.0 setgray 370 262 10 FC 0.0 setgray 370 262 10 OC 370 257 moveto (1) CSH 1.0 setgray 343 228 10 FC 0.0 setgray 343 228 10 OC 343 223 moveto (2) CSH 1.0 setgray 343 313 10 FC 0.0 setgray 343 313 10 OC 343 308 moveto (3) CSH 1.0 setgray 300 352 10 FC 0.0 setgray 300 352 10 OC 300 347 moveto (4) CSH 1.0 setgray 299 308 10 FC 0.0 setgray 299 308 10 OC 299 303 moveto (5) CSH 1.0 setgray 247 375 10 FC 0.0 setgray 247 375 10 OC 247 370 moveto (6) CSH 1.0 setgray 254 298 10 FC 0.0 setgray 254 298 10 OC 254 293 moveto (7) CSH 1.0 setgray 261 246 10 FC 0.0 setgray 261 246 10 OC 261 241 moveto (8) CSH 1.0 setgray 189 380 10 FC 0.0 setgray 189 380 10 OC 189 375 moveto (9) CSH 1.0 setgray 133 366 10 FC 0.0 setgray 133 366 10 OC 133 361 moveto (10) CSH 1.0 setgray 169 341 10 FC 0.0 setgray 169 341 10 OC 169 336 moveto (11) CSH 1.0 setgray 84.5 334 10 FC 0.0 setgray 84.5 334 10 OC 84.5 329 moveto (12) CSH 1.0 setgray 48.8 289 10 FC 0.0 setgray 48.8 289 10 OC 48.8 284 moveto (13) CSH 1.0 setgray 92.6 291 10 FC 0.0 setgray 92.6 291 10 OC 92.6 286 moveto (14) CSH 1.0 setgray 146 293 10 FC 0.0 setgray 146 293 10 OC 146 288 moveto (15) CSH 1.0 setgray 210 240 10 FC 0.0 setgray 210 240 10 OC 210 235 moveto (16) CSH 1.0 setgray 30 234 10 FC 0.0 setgray 30 234 10 OC 30 229 moveto (17) CSH 1.0 setgray 30 176 10 FC 0.0 setgray 30 176 10 OC 30 171 moveto (18) CSH 1.0 setgray 62.8 205 10 FC 0.0 setgray 62.8 205 10 OC 62.8 200 moveto (19) CSH 1.0 setgray 48.8 121 10 FC 0.0 setgray 48.8 121 10 OC 48.8 116 moveto (20) CSH 1.0 setgray 84.5 75.8 10 FC 0.0 setgray 84.5 75.8 10 OC 84.5 70.8 moveto (21) CSH 1.0 setgray 133 44.2 10 FC 0.0 setgray 133 44.2 10 OC 133 39.2 moveto (22) CSH 1.0 setgray 127 87.4 10 FC 0.0 setgray 127 87.4 10 OC 127 82.4 moveto (23) CSH 1.0 setgray 126 134 10 FC 0.0 setgray 126 134 10 OC 126 129 moveto (24) CSH 1.0 setgray 138 179 10 FC 0.0 setgray 138 179 10 OC 138 174 moveto (25) CSH 1.0 setgray 189 30 10 FC 0.0 setgray 189 30 10 OC 189 25 moveto (26) CSH 1.0 setgray 247 34.8 10 FC 0.0 setgray 247 34.8 10 OC 247 29.8 moveto (27) CSH 1.0 setgray 300 58 10 FC 0.0 setgray 300 58 10 OC 300 53 moveto (28) CSH 1.0 setgray 260 76.4 10 FC 0.0 setgray 260 76.4 10 OC 260 71.4 moveto (29) CSH 1.0 setgray 221 101 10 FC 0.0 setgray 221 101 10 OC 221 96.1 moveto (30) CSH 1.0 setgray 343 97.1 10 FC 0.0 setgray 343 97.1 10 OC 343 92.1 moveto (31) CSH 1.0 setgray 370 148 10 FC 0.0 setgray 370 148 10 OC 370 143 moveto (32) CSH 1.0 setgray 328 138 10 FC 0.0 setgray 328 138 10 OC 328 133 moveto (33) CSH 1.0 setgray 245 148 10 FC 0.0 setgray 245 148 10 OC 245 143 moveto (34) CSH 1.0 setgray 194 171 10 FC 0.0 setgray 194 171 10 OC 194 166 moveto (35) CSH 1.0 setgray 204 205 10 FC 0.0 setgray 204 205 10 OC 204 200 moveto (36) CSH grestore showpageTree/doc/makefile010064400020550007177000000000270654276751400152540ustar00clevecompmath00000400000006clean : - rm -f *.dvi Tree/doc/R2D100DP.eps010064400020550007177000000242670665243252200153230ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 600 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def /rscale 6.000 def /fontscale 8.000 def 20 20 560 560 rectclip newpath 440 81.8 418 111 ML 418 111 395 140 ML 395 140 344 151 ML 299 26 297 62.9 ML 297 62.9 321 104 ML 361 77.7 321 104 ML 321 104 344 151 ML 344 151 328 184 ML 328 184 332 232 ML 421 241 379 236 ML 432 180 402 201 ML 402 201 379 236 ML 379 236 332 232 ML 332 232 277 248 ML 81.7 188 105 230 ML 62.3 251 105 230 ML 105 230 140 241 ML 140 241 170 276 ML 26 323 62.3 318 ML 62.3 318 98.6 312 ML 98.6 312 135 307 ML 135 307 170 276 ML 170 276 220 243 ML 248 140 232 184 ML 152 60 143 111 ML 64.8 83 91.8 108 ML 91.8 108 143 111 ML 143 111 166 140 ML 166 140 189 169 ML 189 169 232 184 ML 232 184 220 243 ML 220 243 277 248 ML 277 248 280 284 ML 509 574 486 545 ML 486 545 463 516 ML 463 516 440 487 ML 440 487 418 458 ML 418 458 395 429 ML 395 429 372 400 ML 372 400 349 371 ML 349 371 339 328 ML 462 410 432 389 ML 432 389 402 368 ML 402 368 383 325 ML 574 284 537 284 ML 537 284 501 284 ML 501 284 464 284 ML 464 284 425 307 ML 456 339 425 307 ML 425 307 383 325 ML 383 325 339 328 ML 339 328 288 321 ML 297 506 294 469 ML 294 469 313 429 ML 361 491 347 457 ML 347 457 313 429 ML 313 429 272 395 ML 231 501 239 465 ML 239 465 227 422 ML 188 445 227 422 ML 227 422 272 395 ML 272 395 243 349 ML 81.7 381 115 365 ML 115 365 148 349 ML 148 349 189 347 ML 119 436 146 410 ML 146 410 173 385 ML 173 385 189 347 ML 189 347 243 349 ML 243 349 288 321 ML 288 321 280 284 ML stroke gsave /Helvetica-Bold findfont fontscale scalefont setfont 1.0 setgray 440 81.8 rscale FC 0.0 setgray 440 81.8 rscale OC 440 81.8 rscale 2 div sub moveto (0) CSH 1.0 setgray 418 111 rscale FC 0.0 setgray 418 111 rscale OC 418 111 rscale 2 div sub moveto (1) CSH 1.0 setgray 395 140 rscale FC 0.0 setgray 395 140 rscale OC 395 140 rscale 2 div sub moveto (2) CSH 1.0 setgray 299 26 rscale FC 0.0 setgray 299 26 rscale OC 299 26 rscale 2 div sub moveto (3) CSH 1.0 setgray 297 62.9 rscale FC 0.0 setgray 297 62.9 rscale OC 297 62.9 rscale 2 div sub moveto (4) CSH 1.0 setgray 361 77.7 rscale FC 0.0 setgray 361 77.7 rscale OC 361 77.7 rscale 2 div sub moveto (5) CSH 1.0 setgray 321 104 rscale FC 0.0 setgray 321 104 rscale OC 321 104 rscale 2 div sub moveto (6) CSH 1.0 setgray 344 151 rscale FC 0.0 setgray 344 151 rscale OC 344 151 rscale 2 div sub moveto (7) CSH 1.0 setgray 328 184 rscale FC 0.0 setgray 328 184 rscale OC 328 184 rscale 2 div sub moveto (8) CSH 1.0 setgray 421 241 rscale FC 0.0 setgray 421 241 rscale OC 421 241 rscale 2 div sub moveto (9) CSH 1.0 setgray 432 180 rscale FC 0.0 setgray 432 180 rscale OC 432 180 rscale 2 div sub moveto (10) CSH 1.0 setgray 402 201 rscale FC 0.0 setgray 402 201 rscale OC 402 201 rscale 2 div sub moveto (11) CSH 1.0 setgray 379 236 rscale FC 0.0 setgray 379 236 rscale OC 379 236 rscale 2 div sub moveto (12) CSH 1.0 setgray 332 232 rscale FC 0.0 setgray 332 232 rscale OC 332 232 rscale 2 div sub moveto (13) CSH 1.0 setgray 81.7 188 rscale FC 0.0 setgray 81.7 188 rscale OC 81.7 188 rscale 2 div sub moveto (14) CSH 1.0 setgray 62.3 251 rscale FC 0.0 setgray 62.3 251 rscale OC 62.3 251 rscale 2 div sub moveto (15) CSH 1.0 setgray 105 230 rscale FC 0.0 setgray 105 230 rscale OC 105 230 rscale 2 div sub moveto (16) CSH 1.0 setgray 140 241 rscale FC 0.0 setgray 140 241 rscale OC 140 241 rscale 2 div sub moveto (17) CSH 1.0 setgray 26 323 rscale FC 0.0 setgray 26 323 rscale OC 26 323 rscale 2 div sub moveto (18) CSH 1.0 setgray 62.3 318 rscale FC 0.0 setgray 62.3 318 rscale OC 62.3 318 rscale 2 div sub moveto (19) CSH 1.0 setgray 98.6 312 rscale FC 0.0 setgray 98.6 312 rscale OC 98.6 312 rscale 2 div sub moveto (20) CSH 1.0 setgray 135 307 rscale FC 0.0 setgray 135 307 rscale OC 135 307 rscale 2 div sub moveto (21) CSH 1.0 setgray 170 276 rscale FC 0.0 setgray 170 276 rscale OC 170 276 rscale 2 div sub moveto (22) CSH 1.0 setgray 248 140 rscale FC 0.0 setgray 248 140 rscale OC 248 140 rscale 2 div sub moveto (23) CSH 1.0 setgray 152 60 rscale FC 0.0 setgray 152 60 rscale OC 152 60 rscale 2 div sub moveto (24) CSH 1.0 setgray 64.8 83 rscale FC 0.0 setgray 64.8 83 rscale OC 64.8 83 rscale 2 div sub moveto (25) CSH 1.0 setgray 91.8 108 rscale FC 0.0 setgray 91.8 108 rscale OC 91.8 108 rscale 2 div sub moveto (26) CSH 1.0 setgray 143 111 rscale FC 0.0 setgray 143 111 rscale OC 143 111 rscale 2 div sub moveto (27) CSH 1.0 setgray 166 140 rscale FC 0.0 setgray 166 140 rscale OC 166 140 rscale 2 div sub moveto (28) CSH 1.0 setgray 189 169 rscale FC 0.0 setgray 189 169 rscale OC 189 169 rscale 2 div sub moveto (29) CSH 1.0 setgray 232 184 rscale FC 0.0 setgray 232 184 rscale OC 232 184 rscale 2 div sub moveto (30) CSH 1.0 setgray 220 243 rscale FC 0.0 setgray 220 243 rscale OC 220 243 rscale 2 div sub moveto (31) CSH 1.0 setgray 277 248 rscale FC 0.0 setgray 277 248 rscale OC 277 248 rscale 2 div sub moveto (32) CSH 1.0 setgray 509 574 rscale FC 0.0 setgray 509 574 rscale OC 509 574 rscale 2 div sub moveto (33) CSH 1.0 setgray 486 545 rscale FC 0.0 setgray 486 545 rscale OC 486 545 rscale 2 div sub moveto (34) CSH 1.0 setgray 463 516 rscale FC 0.0 setgray 463 516 rscale OC 463 516 rscale 2 div sub moveto (35) CSH 1.0 setgray 440 487 rscale FC 0.0 setgray 440 487 rscale OC 440 487 rscale 2 div sub moveto (36) CSH 1.0 setgray 418 458 rscale FC 0.0 setgray 418 458 rscale OC 418 458 rscale 2 div sub moveto (37) CSH 1.0 setgray 395 429 rscale FC 0.0 setgray 395 429 rscale OC 395 429 rscale 2 div sub moveto (38) CSH 1.0 setgray 372 400 rscale FC 0.0 setgray 372 400 rscale OC 372 400 rscale 2 div sub moveto (39) CSH 1.0 setgray 349 371 rscale FC 0.0 setgray 349 371 rscale OC 349 371 rscale 2 div sub moveto (40) CSH 1.0 setgray 462 410 rscale FC 0.0 setgray 462 410 rscale OC 462 410 rscale 2 div sub moveto (41) CSH 1.0 setgray 432 389 rscale FC 0.0 setgray 432 389 rscale OC 432 389 rscale 2 div sub moveto (42) CSH 1.0 setgray 402 368 rscale FC 0.0 setgray 402 368 rscale OC 402 368 rscale 2 div sub moveto (43) CSH 1.0 setgray 574 284 rscale FC 0.0 setgray 574 284 rscale OC 574 284 rscale 2 div sub moveto (44) CSH 1.0 setgray 537 284 rscale FC 0.0 setgray 537 284 rscale OC 537 284 rscale 2 div sub moveto (45) CSH 1.0 setgray 501 284 rscale FC 0.0 setgray 501 284 rscale OC 501 284 rscale 2 div sub moveto (46) CSH 1.0 setgray 464 284 rscale FC 0.0 setgray 464 284 rscale OC 464 284 rscale 2 div sub moveto (47) CSH 1.0 setgray 456 339 rscale FC 0.0 setgray 456 339 rscale OC 456 339 rscale 2 div sub moveto (48) CSH 1.0 setgray 425 307 rscale FC 0.0 setgray 425 307 rscale OC 425 307 rscale 2 div sub moveto (49) CSH 1.0 setgray 383 325 rscale FC 0.0 setgray 383 325 rscale OC 383 325 rscale 2 div sub moveto (50) CSH 1.0 setgray 339 328 rscale FC 0.0 setgray 339 328 rscale OC 339 328 rscale 2 div sub moveto (51) CSH 1.0 setgray 297 506 rscale FC 0.0 setgray 297 506 rscale OC 297 506 rscale 2 div sub moveto (52) CSH 1.0 setgray 294 469 rscale FC 0.0 setgray 294 469 rscale OC 294 469 rscale 2 div sub moveto (53) CSH 1.0 setgray 361 491 rscale FC 0.0 setgray 361 491 rscale OC 361 491 rscale 2 div sub moveto (54) CSH 1.0 setgray 347 457 rscale FC 0.0 setgray 347 457 rscale OC 347 457 rscale 2 div sub moveto (55) CSH 1.0 setgray 313 429 rscale FC 0.0 setgray 313 429 rscale OC 313 429 rscale 2 div sub moveto (56) CSH 1.0 setgray 231 501 rscale FC 0.0 setgray 231 501 rscale OC 231 501 rscale 2 div sub moveto (57) CSH 1.0 setgray 239 465 rscale FC 0.0 setgray 239 465 rscale OC 239 465 rscale 2 div sub moveto (58) CSH 1.0 setgray 188 445 rscale FC 0.0 setgray 188 445 rscale OC 188 445 rscale 2 div sub moveto (59) CSH 1.0 setgray 227 422 rscale FC 0.0 setgray 227 422 rscale OC 227 422 rscale 2 div sub moveto (60) CSH 1.0 setgray 272 395 rscale FC 0.0 setgray 272 395 rscale OC 272 395 rscale 2 div sub moveto (61) CSH 1.0 setgray 81.7 381 rscale FC 0.0 setgray 81.7 381 rscale OC 81.7 381 rscale 2 div sub moveto (62) CSH 1.0 setgray 115 365 rscale FC 0.0 setgray 115 365 rscale OC 115 365 rscale 2 div sub moveto (63) CSH 1.0 setgray 148 349 rscale FC 0.0 setgray 148 349 rscale OC 148 349 rscale 2 div sub moveto (64) CSH 1.0 setgray 119 436 rscale FC 0.0 setgray 119 436 rscale OC 119 436 rscale 2 div sub moveto (65) CSH 1.0 setgray 146 410 rscale FC 0.0 setgray 146 410 rscale OC 146 410 rscale 2 div sub moveto (66) CSH 1.0 setgray 173 385 rscale FC 0.0 setgray 173 385 rscale OC 173 385 rscale 2 div sub moveto (67) CSH 1.0 setgray 189 347 rscale FC 0.0 setgray 189 347 rscale OC 189 347 rscale 2 div sub moveto (68) CSH 1.0 setgray 243 349 rscale FC 0.0 setgray 243 349 rscale OC 243 349 rscale 2 div sub moveto (69) CSH 1.0 setgray 288 321 rscale FC 0.0 setgray 288 321 rscale OC 288 321 rscale 2 div sub moveto (70) CSH 1.0 setgray 280 284 rscale FC 0.0 setgray 280 284 rscale OC 280 284 rscale 2 div sub moveto (71) CSH grestore 20 20 560 560 rectstroke showpage 170 276 rscale 2 div sub moveto (22) CSH 1.0 setgray 248 140 rscale FC 0.0 setgray 248 140 rscale OC 248 140 rscale 2 div sub moveto (23) CSH 1.0 setgray 152 60 rscale FC 0.0 setgray 152 60 rscale OC 152 60 rscale 2 div sub moveto (24) CSH 1.0 setgray 64.8 83 rscale FC 0.0 setgray 64.8 83 rscTree/doc/R2D100DC.eps010064400020550007177000000242550665243275000153060ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 600 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def /rscale 6.000 def /fontscale 8.000 def 20 20 560 560 rectclip newpath 519 190 519 245 ML 519 245 519 300 ML 519 300 499 355 ML 464 190 464 245 ML 464 245 478 300 ML 492 245 478 300 ML 478 300 499 355 ML 499 355 499 410 ML 499 410 529 464 ML 574 355 560 410 ML 547 300 547 355 ML 547 355 560 410 ML 560 410 529 464 ML 529 464 449 519 ML 355 245 341 300 ML 327 245 341 300 ML 341 300 341 355 ML 341 355 321 410 ML 300 190 300 245 ML 300 245 300 300 ML 300 300 300 355 ML 300 355 321 410 ML 321 410 368 464 ML 437 355 416 410 ML 410 190 396 245 ML 382 136 382 190 ML 382 190 396 245 ML 396 245 396 300 ML 396 300 396 355 ML 396 355 416 410 ML 416 410 368 464 ML 368 464 449 519 ML 449 519 300 574 ML 108 26 108 80.8 ML 108 80.8 108 136 ML 108 136 108 190 ML 108 190 108 245 ML 108 245 108 300 ML 108 300 108 355 ML 108 355 108 410 ML 108 410 84.2 464 ML 80.8 245 80.8 300 ML 80.8 300 80.8 355 ML 80.8 355 60.2 410 ML 26 136 26 190 ML 26 190 26 245 ML 26 245 26 300 ML 26 300 39.7 355 ML 53.4 300 39.7 355 ML 39.7 355 60.2 410 ML 60.2 410 84.2 464 ML 84.2 464 151 519 ML 163 245 163 300 ML 163 300 149 355 ML 136 245 136 300 ML 136 300 149 355 ML 149 355 177 410 ML 190 245 190 300 ML 190 300 204 355 ML 218 300 204 355 ML 204 355 177 410 ML 177 410 218 464 ML 273 245 273 300 ML 273 300 273 355 ML 273 355 259 410 ML 245 245 245 300 ML 245 300 245 355 ML 245 355 259 410 ML 259 410 218 464 ML 218 464 151 519 ML 151 519 300 574 ML stroke gsave /Helvetica-Bold findfont fontscale scalefont setfont 1.0 setgray 519 190 rscale FC 0.0 setgray 519 190 rscale OC 519 190 rscale 2 div sub moveto (0) CSH 1.0 setgray 519 245 rscale FC 0.0 setgray 519 245 rscale OC 519 245 rscale 2 div sub moveto (1) CSH 1.0 setgray 519 300 rscale FC 0.0 setgray 519 300 rscale OC 519 300 rscale 2 div sub moveto (2) CSH 1.0 setgray 464 190 rscale FC 0.0 setgray 464 190 rscale OC 464 190 rscale 2 div sub moveto (3) CSH 1.0 setgray 464 245 rscale FC 0.0 setgray 464 245 rscale OC 464 245 rscale 2 div sub moveto (4) CSH 1.0 setgray 492 245 rscale FC 0.0 setgray 492 245 rscale OC 492 245 rscale 2 div sub moveto (5) CSH 1.0 setgray 478 300 rscale FC 0.0 setgray 478 300 rscale OC 478 300 rscale 2 div sub moveto (6) CSH 1.0 setgray 499 355 rscale FC 0.0 setgray 499 355 rscale OC 499 355 rscale 2 div sub moveto (7) CSH 1.0 setgray 499 410 rscale FC 0.0 setgray 499 410 rscale OC 499 410 rscale 2 div sub moveto (8) CSH 1.0 setgray 574 355 rscale FC 0.0 setgray 574 355 rscale OC 574 355 rscale 2 div sub moveto (9) CSH 1.0 setgray 547 300 rscale FC 0.0 setgray 547 300 rscale OC 547 300 rscale 2 div sub moveto (10) CSH 1.0 setgray 547 355 rscale FC 0.0 setgray 547 355 rscale OC 547 355 rscale 2 div sub moveto (11) CSH 1.0 setgray 560 410 rscale FC 0.0 setgray 560 410 rscale OC 560 410 rscale 2 div sub moveto (12) CSH 1.0 setgray 529 464 rscale FC 0.0 setgray 529 464 rscale OC 529 464 rscale 2 div sub moveto (13) CSH 1.0 setgray 355 245 rscale FC 0.0 setgray 355 245 rscale OC 355 245 rscale 2 div sub moveto (14) CSH 1.0 setgray 327 245 rscale FC 0.0 setgray 327 245 rscale OC 327 245 rscale 2 div sub moveto (15) CSH 1.0 setgray 341 300 rscale FC 0.0 setgray 341 300 rscale OC 341 300 rscale 2 div sub moveto (16) CSH 1.0 setgray 341 355 rscale FC 0.0 setgray 341 355 rscale OC 341 355 rscale 2 div sub moveto (17) CSH 1.0 setgray 300 190 rscale FC 0.0 setgray 300 190 rscale OC 300 190 rscale 2 div sub moveto (18) CSH 1.0 setgray 300 245 rscale FC 0.0 setgray 300 245 rscale OC 300 245 rscale 2 div sub moveto (19) CSH 1.0 setgray 300 300 rscale FC 0.0 setgray 300 300 rscale OC 300 300 rscale 2 div sub moveto (20) CSH 1.0 setgray 300 355 rscale FC 0.0 setgray 300 355 rscale OC 300 355 rscale 2 div sub moveto (21) CSH 1.0 setgray 321 410 rscale FC 0.0 setgray 321 410 rscale OC 321 410 rscale 2 div sub moveto (22) CSH 1.0 setgray 437 355 rscale FC 0.0 setgray 437 355 rscale OC 437 355 rscale 2 div sub moveto (23) CSH 1.0 setgray 410 190 rscale FC 0.0 setgray 410 190 rscale OC 410 190 rscale 2 div sub moveto (24) CSH 1.0 setgray 382 136 rscale FC 0.0 setgray 382 136 rscale OC 382 136 rscale 2 div sub moveto (25) CSH 1.0 setgray 382 190 rscale FC 0.0 setgray 382 190 rscale OC 382 190 rscale 2 div sub moveto (26) CSH 1.0 setgray 396 245 rscale FC 0.0 setgray 396 245 rscale OC 396 245 rscale 2 div sub moveto (27) CSH 1.0 setgray 396 300 rscale FC 0.0 setgray 396 300 rscale OC 396 300 rscale 2 div sub moveto (28) CSH 1.0 setgray 396 355 rscale FC 0.0 setgray 396 355 rscale OC 396 355 rscale 2 div sub moveto (29) CSH 1.0 setgray 416 410 rscale FC 0.0 setgray 416 410 rscale OC 416 410 rscale 2 div sub moveto (30) CSH 1.0 setgray 368 464 rscale FC 0.0 setgray 368 464 rscale OC 368 464 rscale 2 div sub moveto (31) CSH 1.0 setgray 449 519 rscale FC 0.0 setgray 449 519 rscale OC 449 519 rscale 2 div sub moveto (32) CSH 1.0 setgray 108 26 rscale FC 0.0 setgray 108 26 rscale OC 108 26 rscale 2 div sub moveto (33) CSH 1.0 setgray 108 80.8 rscale FC 0.0 setgray 108 80.8 rscale OC 108 80.8 rscale 2 div sub moveto (34) CSH 1.0 setgray 108 136 rscale FC 0.0 setgray 108 136 rscale OC 108 136 rscale 2 div sub moveto (35) CSH 1.0 setgray 108 190 rscale FC 0.0 setgray 108 190 rscale OC 108 190 rscale 2 div sub moveto (36) CSH 1.0 setgray 108 245 rscale FC 0.0 setgray 108 245 rscale OC 108 245 rscale 2 div sub moveto (37) CSH 1.0 setgray 108 300 rscale FC 0.0 setgray 108 300 rscale OC 108 300 rscale 2 div sub moveto (38) CSH 1.0 setgray 108 355 rscale FC 0.0 setgray 108 355 rscale OC 108 355 rscale 2 div sub moveto (39) CSH 1.0 setgray 108 410 rscale FC 0.0 setgray 108 410 rscale OC 108 410 rscale 2 div sub moveto (40) CSH 1.0 setgray 80.8 245 rscale FC 0.0 setgray 80.8 245 rscale OC 80.8 245 rscale 2 div sub moveto (41) CSH 1.0 setgray 80.8 300 rscale FC 0.0 setgray 80.8 300 rscale OC 80.8 300 rscale 2 div sub moveto (42) CSH 1.0 setgray 80.8 355 rscale FC 0.0 setgray 80.8 355 rscale OC 80.8 355 rscale 2 div sub moveto (43) CSH 1.0 setgray 26 136 rscale FC 0.0 setgray 26 136 rscale OC 26 136 rscale 2 div sub moveto (44) CSH 1.0 setgray 26 190 rscale FC 0.0 setgray 26 190 rscale OC 26 190 rscale 2 div sub moveto (45) CSH 1.0 setgray 26 245 rscale FC 0.0 setgray 26 245 rscale OC 26 245 rscale 2 div sub moveto (46) CSH 1.0 setgray 26 300 rscale FC 0.0 setgray 26 300 rscale OC 26 300 rscale 2 div sub moveto (47) CSH 1.0 setgray 53.4 300 rscale FC 0.0 setgray 53.4 300 rscale OC 53.4 300 rscale 2 div sub moveto (48) CSH 1.0 setgray 39.7 355 rscale FC 0.0 setgray 39.7 355 rscale OC 39.7 355 rscale 2 div sub moveto (49) CSH 1.0 setgray 60.2 410 rscale FC 0.0 setgray 60.2 410 rscale OC 60.2 410 rscale 2 div sub moveto (50) CSH 1.0 setgray 84.2 464 rscale FC 0.0 setgray 84.2 464 rscale OC 84.2 464 rscale 2 div sub moveto (51) CSH 1.0 setgray 163 245 rscale FC 0.0 setgray 163 245 rscale OC 163 245 rscale 2 div sub moveto (52) CSH 1.0 setgray 163 300 rscale FC 0.0 setgray 163 300 rscale OC 163 300 rscale 2 div sub moveto (53) CSH 1.0 setgray 136 245 rscale FC 0.0 setgray 136 245 rscale OC 136 245 rscale 2 div sub moveto (54) CSH 1.0 setgray 136 300 rscale FC 0.0 setgray 136 300 rscale OC 136 300 rscale 2 div sub moveto (55) CSH 1.0 setgray 149 355 rscale FC 0.0 setgray 149 355 rscale OC 149 355 rscale 2 div sub moveto (56) CSH 1.0 setgray 190 245 rscale FC 0.0 setgray 190 245 rscale OC 190 245 rscale 2 div sub moveto (57) CSH 1.0 setgray 190 300 rscale FC 0.0 setgray 190 300 rscale OC 190 300 rscale 2 div sub moveto (58) CSH 1.0 setgray 218 300 rscale FC 0.0 setgray 218 300 rscale OC 218 300 rscale 2 div sub moveto (59) CSH 1.0 setgray 204 355 rscale FC 0.0 setgray 204 355 rscale OC 204 355 rscale 2 div sub moveto (60) CSH 1.0 setgray 177 410 rscale FC 0.0 setgray 177 410 rscale OC 177 410 rscale 2 div sub moveto (61) CSH 1.0 setgray 273 245 rscale FC 0.0 setgray 273 245 rscale OC 273 245 rscale 2 div sub moveto (62) CSH 1.0 setgray 273 300 rscale FC 0.0 setgray 273 300 rscale OC 273 300 rscale 2 div sub moveto (63) CSH 1.0 setgray 273 355 rscale FC 0.0 setgray 273 355 rscale OC 273 355 rscale 2 div sub moveto (64) CSH 1.0 setgray 245 245 rscale FC 0.0 setgray 245 245 rscale OC 245 245 rscale 2 div sub moveto (65) CSH 1.0 setgray 245 300 rscale FC 0.0 setgray 245 300 rscale OC 245 300 rscale 2 div sub moveto (66) CSH 1.0 setgray 245 355 rscale FC 0.0 setgray 245 355 rscale OC 245 355 rscale 2 div sub moveto (67) CSH 1.0 setgray 259 410 rscale FC 0.0 setgray 259 410 rscale OC 259 410 rscale 2 div sub moveto (68) CSH 1.0 setgray 218 464 rscale FC 0.0 setgray 218 464 rscale OC 218 464 rscale 2 div sub moveto (69) CSH 1.0 setgray 151 519 rscale FC 0.0 setgray 151 519 rscale OC 151 519 rscale 2 div sub moveto (70) CSH 1.0 setgray 300 574 rscale FC 0.0 setgray 300 574 rscale OC 300 574 rscale 2 div sub moveto (71) CSH grestore 20 20 560 560 rectstroke showpageTree/doc/R2D100HC.eps010064400020550007177000000242370665243300000152770ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 600 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def /rscale 6.000 def /fontscale 8.000 def 20 20 560 560 rectclip newpath 519 26 519 80.8 ML 519 80.8 519 136 ML 519 136 499 190 ML 464 26 464 80.8 ML 464 80.8 478 136 ML 492 26 478 136 ML 478 136 499 190 ML 499 190 499 245 ML 499 245 529 300 ML 574 26 560 136 ML 547 26 547 80.8 ML 547 80.8 560 136 ML 560 136 529 300 ML 529 300 449 410 ML 355 26 341 80.8 ML 327 26 341 80.8 ML 341 80.8 341 136 ML 341 136 321 245 ML 300 26 300 80.8 ML 300 80.8 300 136 ML 300 136 300 190 ML 300 190 321 245 ML 321 245 368 355 ML 437 26 416 300 ML 410 26 396 136 ML 382 26 382 80.8 ML 382 80.8 396 136 ML 396 136 396 190 ML 396 190 396 245 ML 396 245 416 300 ML 416 300 368 355 ML 368 355 449 410 ML 449 410 300 574 ML 108 26 108 80.8 ML 108 80.8 108 136 ML 108 136 108 190 ML 108 190 108 245 ML 108 245 108 300 ML 108 300 108 355 ML 108 355 108 410 ML 108 410 84.2 464 ML 80.8 26 80.8 80.8 ML 80.8 80.8 80.8 136 ML 80.8 136 60.2 300 ML 26 26 26 80.8 ML 26 80.8 26 136 ML 26 136 26 190 ML 26 190 39.7 245 ML 53.4 26 39.7 245 ML 39.7 245 60.2 300 ML 60.2 300 84.2 464 ML 84.2 464 151 519 ML 163 26 163 80.8 ML 163 80.8 149 136 ML 136 26 136 80.8 ML 136 80.8 149 136 ML 149 136 177 190 ML 190 26 190 80.8 ML 190 80.8 204 136 ML 218 26 204 136 ML 204 136 177 190 ML 177 190 218 245 ML 273 26 273 80.8 ML 273 80.8 273 136 ML 273 136 259 190 ML 245 26 245 80.8 ML 245 80.8 245 136 ML 245 136 259 190 ML 259 190 218 245 ML 218 245 151 519 ML 151 519 300 574 ML stroke gsave /Helvetica-Bold findfont fontscale scalefont setfont 1.0 setgray 519 26 rscale FC 0.0 setgray 519 26 rscale OC 519 26 rscale 2 div sub moveto (0) CSH 1.0 setgray 519 80.8 rscale FC 0.0 setgray 519 80.8 rscale OC 519 80.8 rscale 2 div sub moveto (1) CSH 1.0 setgray 519 136 rscale FC 0.0 setgray 519 136 rscale OC 519 136 rscale 2 div sub moveto (2) CSH 1.0 setgray 464 26 rscale FC 0.0 setgray 464 26 rscale OC 464 26 rscale 2 div sub moveto (3) CSH 1.0 setgray 464 80.8 rscale FC 0.0 setgray 464 80.8 rscale OC 464 80.8 rscale 2 div sub moveto (4) CSH 1.0 setgray 492 26 rscale FC 0.0 setgray 492 26 rscale OC 492 26 rscale 2 div sub moveto (5) CSH 1.0 setgray 478 136 rscale FC 0.0 setgray 478 136 rscale OC 478 136 rscale 2 div sub moveto (6) CSH 1.0 setgray 499 190 rscale FC 0.0 setgray 499 190 rscale OC 499 190 rscale 2 div sub moveto (7) CSH 1.0 setgray 499 245 rscale FC 0.0 setgray 499 245 rscale OC 499 245 rscale 2 div sub moveto (8) CSH 1.0 setgray 574 26 rscale FC 0.0 setgray 574 26 rscale OC 574 26 rscale 2 div sub moveto (9) CSH 1.0 setgray 547 26 rscale FC 0.0 setgray 547 26 rscale OC 547 26 rscale 2 div sub moveto (10) CSH 1.0 setgray 547 80.8 rscale FC 0.0 setgray 547 80.8 rscale OC 547 80.8 rscale 2 div sub moveto (11) CSH 1.0 setgray 560 136 rscale FC 0.0 setgray 560 136 rscale OC 560 136 rscale 2 div sub moveto (12) CSH 1.0 setgray 529 300 rscale FC 0.0 setgray 529 300 rscale OC 529 300 rscale 2 div sub moveto (13) CSH 1.0 setgray 355 26 rscale FC 0.0 setgray 355 26 rscale OC 355 26 rscale 2 div sub moveto (14) CSH 1.0 setgray 327 26 rscale FC 0.0 setgray 327 26 rscale OC 327 26 rscale 2 div sub moveto (15) CSH 1.0 setgray 341 80.8 rscale FC 0.0 setgray 341 80.8 rscale OC 341 80.8 rscale 2 div sub moveto (16) CSH 1.0 setgray 341 136 rscale FC 0.0 setgray 341 136 rscale OC 341 136 rscale 2 div sub moveto (17) CSH 1.0 setgray 300 26 rscale FC 0.0 setgray 300 26 rscale OC 300 26 rscale 2 div sub moveto (18) CSH 1.0 setgray 300 80.8 rscale FC 0.0 setgray 300 80.8 rscale OC 300 80.8 rscale 2 div sub moveto (19) CSH 1.0 setgray 300 136 rscale FC 0.0 setgray 300 136 rscale OC 300 136 rscale 2 div sub moveto (20) CSH 1.0 setgray 300 190 rscale FC 0.0 setgray 300 190 rscale OC 300 190 rscale 2 div sub moveto (21) CSH 1.0 setgray 321 245 rscale FC 0.0 setgray 321 245 rscale OC 321 245 rscale 2 div sub moveto (22) CSH 1.0 setgray 437 26 rscale FC 0.0 setgray 437 26 rscale OC 437 26 rscale 2 div sub moveto (23) CSH 1.0 setgray 410 26 rscale FC 0.0 setgray 410 26 rscale OC 410 26 rscale 2 div sub moveto (24) CSH 1.0 setgray 382 26 rscale FC 0.0 setgray 382 26 rscale OC 382 26 rscale 2 div sub moveto (25) CSH 1.0 setgray 382 80.8 rscale FC 0.0 setgray 382 80.8 rscale OC 382 80.8 rscale 2 div sub moveto (26) CSH 1.0 setgray 396 136 rscale FC 0.0 setgray 396 136 rscale OC 396 136 rscale 2 div sub moveto (27) CSH 1.0 setgray 396 190 rscale FC 0.0 setgray 396 190 rscale OC 396 190 rscale 2 div sub moveto (28) CSH 1.0 setgray 396 245 rscale FC 0.0 setgray 396 245 rscale OC 396 245 rscale 2 div sub moveto (29) CSH 1.0 setgray 416 300 rscale FC 0.0 setgray 416 300 rscale OC 416 300 rscale 2 div sub moveto (30) CSH 1.0 setgray 368 355 rscale FC 0.0 setgray 368 355 rscale OC 368 355 rscale 2 div sub moveto (31) CSH 1.0 setgray 449 410 rscale FC 0.0 setgray 449 410 rscale OC 449 410 rscale 2 div sub moveto (32) CSH 1.0 setgray 108 26 rscale FC 0.0 setgray 108 26 rscale OC 108 26 rscale 2 div sub moveto (33) CSH 1.0 setgray 108 80.8 rscale FC 0.0 setgray 108 80.8 rscale OC 108 80.8 rscale 2 div sub moveto (34) CSH 1.0 setgray 108 136 rscale FC 0.0 setgray 108 136 rscale OC 108 136 rscale 2 div sub moveto (35) CSH 1.0 setgray 108 190 rscale FC 0.0 setgray 108 190 rscale OC 108 190 rscale 2 div sub moveto (36) CSH 1.0 setgray 108 245 rscale FC 0.0 setgray 108 245 rscale OC 108 245 rscale 2 div sub moveto (37) CSH 1.0 setgray 108 300 rscale FC 0.0 setgray 108 300 rscale OC 108 300 rscale 2 div sub moveto (38) CSH 1.0 setgray 108 355 rscale FC 0.0 setgray 108 355 rscale OC 108 355 rscale 2 div sub moveto (39) CSH 1.0 setgray 108 410 rscale FC 0.0 setgray 108 410 rscale OC 108 410 rscale 2 div sub moveto (40) CSH 1.0 setgray 80.8 26 rscale FC 0.0 setgray 80.8 26 rscale OC 80.8 26 rscale 2 div sub moveto (41) CSH 1.0 setgray 80.8 80.8 rscale FC 0.0 setgray 80.8 80.8 rscale OC 80.8 80.8 rscale 2 div sub moveto (42) CSH 1.0 setgray 80.8 136 rscale FC 0.0 setgray 80.8 136 rscale OC 80.8 136 rscale 2 div sub moveto (43) CSH 1.0 setgray 26 26 rscale FC 0.0 setgray 26 26 rscale OC 26 26 rscale 2 div sub moveto (44) CSH 1.0 setgray 26 80.8 rscale FC 0.0 setgray 26 80.8 rscale OC 26 80.8 rscale 2 div sub moveto (45) CSH 1.0 setgray 26 136 rscale FC 0.0 setgray 26 136 rscale OC 26 136 rscale 2 div sub moveto (46) CSH 1.0 setgray 26 190 rscale FC 0.0 setgray 26 190 rscale OC 26 190 rscale 2 div sub moveto (47) CSH 1.0 setgray 53.4 26 rscale FC 0.0 setgray 53.4 26 rscale OC 53.4 26 rscale 2 div sub moveto (48) CSH 1.0 setgray 39.7 245 rscale FC 0.0 setgray 39.7 245 rscale OC 39.7 245 rscale 2 div sub moveto (49) CSH 1.0 setgray 60.2 300 rscale FC 0.0 setgray 60.2 300 rscale OC 60.2 300 rscale 2 div sub moveto (50) CSH 1.0 setgray 84.2 464 rscale FC 0.0 setgray 84.2 464 rscale OC 84.2 464 rscale 2 div sub moveto (51) CSH 1.0 setgray 163 26 rscale FC 0.0 setgray 163 26 rscale OC 163 26 rscale 2 div sub moveto (52) CSH 1.0 setgray 163 80.8 rscale FC 0.0 setgray 163 80.8 rscale OC 163 80.8 rscale 2 div sub moveto (53) CSH 1.0 setgray 136 26 rscale FC 0.0 setgray 136 26 rscale OC 136 26 rscale 2 div sub moveto (54) CSH 1.0 setgray 136 80.8 rscale FC 0.0 setgray 136 80.8 rscale OC 136 80.8 rscale 2 div sub moveto (55) CSH 1.0 setgray 149 136 rscale FC 0.0 setgray 149 136 rscale OC 149 136 rscale 2 div sub moveto (56) CSH 1.0 setgray 190 26 rscale FC 0.0 setgray 190 26 rscale OC 190 26 rscale 2 div sub moveto (57) CSH 1.0 setgray 190 80.8 rscale FC 0.0 setgray 190 80.8 rscale OC 190 80.8 rscale 2 div sub moveto (58) CSH 1.0 setgray 218 26 rscale FC 0.0 setgray 218 26 rscale OC 218 26 rscale 2 div sub moveto (59) CSH 1.0 setgray 204 136 rscale FC 0.0 setgray 204 136 rscale OC 204 136 rscale 2 div sub moveto (60) CSH 1.0 setgray 177 190 rscale FC 0.0 setgray 177 190 rscale OC 177 190 rscale 2 div sub moveto (61) CSH 1.0 setgray 273 26 rscale FC 0.0 setgray 273 26 rscale OC 273 26 rscale 2 div sub moveto (62) CSH 1.0 setgray 273 80.8 rscale FC 0.0 setgray 273 80.8 rscale OC 273 80.8 rscale 2 div sub moveto (63) CSH 1.0 setgray 273 136 rscale FC 0.0 setgray 273 136 rscale OC 273 136 rscale 2 div sub moveto (64) CSH 1.0 setgray 245 26 rscale FC 0.0 setgray 245 26 rscale OC 245 26 rscale 2 div sub moveto (65) CSH 1.0 setgray 245 80.8 rscale FC 0.0 setgray 245 80.8 rscale OC 245 80.8 rscale 2 div sub moveto (66) CSH 1.0 setgray 245 136 rscale FC 0.0 setgray 245 136 rscale OC 245 136 rscale 2 div sub moveto (67) CSH 1.0 setgray 259 190 rscale FC 0.0 setgray 259 190 rscale OC 259 190 rscale 2 div sub moveto (68) CSH 1.0 setgray 218 245 rscale FC 0.0 setgray 218 245 rscale OC 218 245 rscale 2 div sub moveto (69) CSH 1.0 setgray 151 519 rscale FC 0.0 setgray 151 519 rscale OC 151 519 rscale 2 div sub moveto (70) CSH 1.0 setgray 300 574 rscale FC 0.0 setgray 300 574 rscale OC 300 574 rscale 2 div sub moveto (71) CSH grestore 20 20 560 560 rectstroke showpageTree/doc/R2D100HP.eps010064400020550007177000000243070665243302400153200ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0 0 600 600 /CSH { % % center show a string % % stack % string str % dup stringwidth pop 2 div neg 0 rmoveto show } def /ML { % % moveto lineto % % stack % x0 y0 x1 y1 % moveto lineto } def /FC { % % draw filled circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc fill } def /OC { % % draw open circle % % stack % x y r % newpath 2 index 1 index add 2 index moveto 0 360 arc stroke } def /rscale 6.000 def /fontscale 8.000 def 20 20 560 560 rectclip newpath 470 85.2 453 107 ML 453 107 436 128 ML 436 128 382 127 ML 319 26 317 53.4 ML 317 53.4 348 85.7 ML 399 44.2 348 85.7 ML 348 85.7 382 127 ML 382 127 370 151 ML 370 151 396 203 ML 562 219 497 205 ML 526 145 503 161 ML 503 161 497 205 ML 497 205 396 203 ML 396 203 291 218 ML 50.2 181 61.5 227 ML 26 259 61.5 227 ML 61.5 227 87.8 235 ML 87.8 235 134 288 ML 26 341 53.2 337 ML 53.2 337 80.5 333 ML 80.5 333 108 329 ML 108 329 134 288 ML 134 288 207 238 ML 237 32.1 239 176 ML 161 62 161 128 ML 96.5 113 117 132 ML 117 132 161 128 ML 161 128 178 150 ML 178 150 195 171 ML 195 171 239 176 ML 239 176 207 238 ML 207 238 291 218 ML 291 218 298 300 ML 470 515 453 493 ML 453 493 436 472 ML 436 472 419 450 ML 419 450 402 429 ML 402 429 384 407 ML 384 407 367 386 ML 367 386 350 364 ML 350 364 343 333 ML 526 455 503 439 ML 503 439 481 424 ML 481 424 427 350 ML 574 300 546 300 ML 546 300 519 300 ML 519 300 491 300 ML 491 300 462 325 ML 562 381 462 325 ML 462 325 427 350 ML 427 350 343 333 ML 343 333 304 327 ML 319 574 317 547 ML 317 547 348 514 ML 399 556 389 530 ML 389 530 348 514 ML 348 514 284 492 ML 237 568 243 541 ML 243 541 218 505 ML 161 538 218 505 ML 218 505 284 492 ML 284 492 216 443 ML 50.2 419 75 407 ML 75 407 99.9 395 ML 99.9 395 139 408 ML 96.5 487 117 468 ML 117 468 137 450 ML 137 450 139 408 ML 139 408 216 443 ML 216 443 304 327 ML 304 327 298 300 ML stroke gsave /Helvetica-Bold findfont fontscale scalefont setfont 1.0 setgray 470 85.2 rscale FC 0.0 setgray 470 85.2 rscale OC 470 85.2 rscale 2 div sub moveto (0) CSH 1.0 setgray 453 107 rscale FC 0.0 setgray 453 107 rscale OC 453 107 rscale 2 div sub moveto (1) CSH 1.0 setgray 436 128 rscale FC 0.0 setgray 436 128 rscale OC 436 128 rscale 2 div sub moveto (2) CSH 1.0 setgray 319 26 rscale FC 0.0 setgray 319 26 rscale OC 319 26 rscale 2 div sub moveto (3) CSH 1.0 setgray 317 53.4 rscale FC 0.0 setgray 317 53.4 rscale OC 317 53.4 rscale 2 div sub moveto (4) CSH 1.0 setgray 399 44.2 rscale FC 0.0 setgray 399 44.2 rscale OC 399 44.2 rscale 2 div sub moveto (5) CSH 1.0 setgray 348 85.7 rscale FC 0.0 setgray 348 85.7 rscale OC 348 85.7 rscale 2 div sub moveto (6) CSH 1.0 setgray 382 127 rscale FC 0.0 setgray 382 127 rscale OC 382 127 rscale 2 div sub moveto (7) CSH 1.0 setgray 370 151 rscale FC 0.0 setgray 370 151 rscale OC 370 151 rscale 2 div sub moveto (8) CSH 1.0 setgray 562 219 rscale FC 0.0 setgray 562 219 rscale OC 562 219 rscale 2 div sub moveto (9) CSH 1.0 setgray 526 145 rscale FC 0.0 setgray 526 145 rscale OC 526 145 rscale 2 div sub moveto (10) CSH 1.0 setgray 503 161 rscale FC 0.0 setgray 503 161 rscale OC 503 161 rscale 2 div sub moveto (11) CSH 1.0 setgray 497 205 rscale FC 0.0 setgray 497 205 rscale OC 497 205 rscale 2 div sub moveto (12) CSH 1.0 setgray 396 203 rscale FC 0.0 setgray 396 203 rscale OC 396 203 rscale 2 div sub moveto (13) CSH 1.0 setgray 50.2 181 rscale FC 0.0 setgray 50.2 181 rscale OC 50.2 181 rscale 2 div sub moveto (14) CSH 1.0 setgray 26 259 rscale FC 0.0 setgray 26 259 rscale OC 26 259 rscale 2 div sub moveto (15) CSH 1.0 setgray 61.5 227 rscale FC 0.0 setgray 61.5 227 rscale OC 61.5 227 rscale 2 div sub moveto (16) CSH 1.0 setgray 87.8 235 rscale FC 0.0 setgray 87.8 235 rscale OC 87.8 235 rscale 2 div sub moveto (17) CSH 1.0 setgray 26 341 rscale FC 0.0 setgray 26 341 rscale OC 26 341 rscale 2 div sub moveto (18) CSH 1.0 setgray 53.2 337 rscale FC 0.0 setgray 53.2 337 rscale OC 53.2 337 rscale 2 div sub moveto (19) CSH 1.0 setgray 80.5 333 rscale FC 0.0 setgray 80.5 333 rscale OC 80.5 333 rscale 2 div sub moveto (20) CSH 1.0 setgray 108 329 rscale FC 0.0 setgray 108 329 rscale OC 108 329 rscale 2 div sub moveto (21) CSH 1.0 setgray 134 288 rscale FC 0.0 setgray 134 288 rscale OC 134 288 rscale 2 div sub moveto (22) CSH 1.0 setgray 237 32.1 rscale FC 0.0 setgray 237 32.1 rscale OC 237 32.1 rscale 2 div sub moveto (23) CSH 1.0 setgray 161 62 rscale FC 0.0 setgray 161 62 rscale OC 161 62 rscale 2 div sub moveto (24) CSH 1.0 setgray 96.5 113 rscale FC 0.0 setgray 96.5 113 rscale OC 96.5 113 rscale 2 div sub moveto (25) CSH 1.0 setgray 117 132 rscale FC 0.0 setgray 117 132 rscale OC 117 132 rscale 2 div sub moveto (26) CSH 1.0 setgray 161 128 rscale FC 0.0 setgray 161 128 rscale OC 161 128 rscale 2 div sub moveto (27) CSH 1.0 setgray 178 150 rscale FC 0.0 setgray 178 150 rscale OC 178 150 rscale 2 div sub moveto (28) CSH 1.0 setgray 195 171 rscale FC 0.0 setgray 195 171 rscale OC 195 171 rscale 2 div sub moveto (29) CSH 1.0 setgray 239 176 rscale FC 0.0 setgray 239 176 rscale OC 239 176 rscale 2 div sub moveto (30) CSH 1.0 setgray 207 238 rscale FC 0.0 setgray 207 238 rscale OC 207 238 rscale 2 div sub moveto (31) CSH 1.0 setgray 291 218 rscale FC 0.0 setgray 291 218 rscale OC 291 218 rscale 2 div sub moveto (32) CSH 1.0 setgray 470 515 rscale FC 0.0 setgray 470 515 rscale OC 470 515 rscale 2 div sub moveto (33) CSH 1.0 setgray 453 493 rscale FC 0.0 setgray 453 493 rscale OC 453 493 rscale 2 div sub moveto (34) CSH 1.0 setgray 436 472 rscale FC 0.0 setgray 436 472 rscale OC 436 472 rscale 2 div sub moveto (35) CSH 1.0 setgray 419 450 rscale FC 0.0 setgray 419 450 rscale OC 419 450 rscale 2 div sub moveto (36) CSH 1.0 setgray 402 429 rscale FC 0.0 setgray 402 429 rscale OC 402 429 rscale 2 div sub moveto (37) CSH 1.0 setgray 384 407 rscale FC 0.0 setgray 384 407 rscale OC 384 407 rscale 2 div sub moveto (38) CSH 1.0 setgray 367 386 rscale FC 0.0 setgray 367 386 rscale OC 367 386 rscale 2 div sub moveto (39) CSH 1.0 setgray 350 364 rscale FC 0.0 setgray 350 364 rscale OC 350 364 rscale 2 div sub moveto (40) CSH 1.0 setgray 526 455 rscale FC 0.0 setgray 526 455 rscale OC 526 455 rscale 2 div sub moveto (41) CSH 1.0 setgray 503 439 rscale FC 0.0 setgray 503 439 rscale OC 503 439 rscale 2 div sub moveto (42) CSH 1.0 setgray 481 424 rscale FC 0.0 setgray 481 424 rscale OC 481 424 rscale 2 div sub moveto (43) CSH 1.0 setgray 574 300 rscale FC 0.0 setgray 574 300 rscale OC 574 300 rscale 2 div sub moveto (44) CSH 1.0 setgray 546 300 rscale FC 0.0 setgray 546 300 rscale OC 546 300 rscale 2 div sub moveto (45) CSH 1.0 setgray 519 300 rscale FC 0.0 setgray 519 300 rscale OC 519 300 rscale 2 div sub moveto (46) CSH 1.0 setgray 491 300 rscale FC 0.0 setgray 491 300 rscale OC 491 300 rscale 2 div sub moveto (47) CSH 1.0 setgray 562 381 rscale FC 0.0 setgray 562 381 rscale OC 562 381 rscale 2 div sub moveto (48) CSH 1.0 setgray 462 325 rscale FC 0.0 setgray 462 325 rscale OC 462 325 rscale 2 div sub moveto (49) CSH 1.0 setgray 427 350 rscale FC 0.0 setgray 427 350 rscale OC 427 350 rscale 2 div sub moveto (50) CSH 1.0 setgray 343 333 rscale FC 0.0 setgray 343 333 rscale OC 343 333 rscale 2 div sub moveto (51) CSH 1.0 setgray 319 574 rscale FC 0.0 setgray 319 574 rscale OC 319 574 rscale 2 div sub moveto (52) CSH 1.0 setgray 317 547 rscale FC 0.0 setgray 317 547 rscale OC 317 547 rscale 2 div sub moveto (53) CSH 1.0 setgray 399 556 rscale FC 0.0 setgray 399 556 rscale OC 399 556 rscale 2 div sub moveto (54) CSH 1.0 setgray 389 530 rscale FC 0.0 setgray 389 530 rscale OC 389 530 rscale 2 div sub moveto (55) CSH 1.0 setgray 348 514 rscale FC 0.0 setgray 348 514 rscale OC 348 514 rscale 2 div sub moveto (56) CSH 1.0 setgray 237 568 rscale FC 0.0 setgray 237 568 rscale OC 237 568 rscale 2 div sub moveto (57) CSH 1.0 setgray 243 541 rscale FC 0.0 setgray 243 541 rscale OC 243 541 rscale 2 div sub moveto (58) CSH 1.0 setgray 161 538 rscale FC 0.0 setgray 161 538 rscale OC 161 538 rscale 2 div sub moveto (59) CSH 1.0 setgray 218 505 rscale FC 0.0 setgray 218 505 rscale OC 218 505 rscale 2 div sub moveto (60) CSH 1.0 setgray 284 492 rscale FC 0.0 setgray 284 492 rscale OC 284 492 rscale 2 div sub moveto (61) CSH 1.0 setgray 50.2 419 rscale FC 0.0 setgray 50.2 419 rscale OC 50.2 419 rscale 2 div sub moveto (62) CSH 1.0 setgray 75 407 rscale FC 0.0 setgray 75 407 rscale OC 75 407 rscale 2 div sub moveto (63) CSH 1.0 setgray 99.9 395 rscale FC 0.0 setgray 99.9 395 rscale OC 99.9 395 rscale 2 div sub moveto (64) CSH 1.0 setgray 96.5 487 rscale FC 0.0 setgray 96.5 487 rscale OC 96.5 487 rscale 2 div sub moveto (65) CSH 1.0 setgray 117 468 rscale FC 0.0 setgray 117 468 rscale OC 117 468 rscale 2 div sub moveto (66) CSH 1.0 setgray 137 450 rscale FC 0.0 setgray 137 450 rscale OC 137 450 rscale 2 div sub moveto (67) CSH 1.0 setgray 139 408 rscale FC 0.0 setgray 139 408 rscale OC 139 408 rscale 2 div sub moveto (68) CSH 1.0 setgray 216 443 rscale FC 0.0 setgray 216 443 rscale OC 216 443 rscale 2 div sub moveto (69) CSH 1.0 setgray 304 327 rscale FC 0.0 setgray 304 327 rscale OC 304 327 rscale 2 div sub moveto (70) CSH 1.0 setgray 298 300 rscale FC 0.0 setgray 298 300 rscale OC 298 300 rscale 2 div sub moveto (71) CSH grestore 20 20 560 560 rectstroke showpageUtilities.h010064400020550007177000000001200653410636600142170ustar00clevecompmath00000400000006#ifndef _Utilities_ #define _Utilities_ #include "Utilities/Utilities.h" #endif Utilities/CV.h010064400020550007177000000232100653410575400145340ustar00clevecompmath00000400000006/* CV.h */ /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- prototype definitions for character vectors. note, our use of character vectors is different from strings. most of their application is as marking vectors. ------------------------------------------------------------- */ /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- allocate a char array with size entries and fill with value c return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------- */ char * CVinit ( int size, char c ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- allocate a char array with size entries return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------- */ char * CVinit2 ( int size ) ; /*--------------------------------------------------------------------*/ /* ------------------------------- purpose -- to copy y[*] := x[*] created -- 95sep22, cca ------------------------------- */ void CVcopy ( int size, char y[], char x[] ) ; /*--------------------------------------------------------------------*/ /* ---------------------------- purpose -- to fill y[*] := c created -- 95sep22, cca ---------------------------- */ void CVfill ( int size, char y[], char c ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to print out a char vector the vector starts on a new line and takes 80 characters per line created -- 95sep22, cca ------------------------------------- */ void CVfprintf ( FILE *fp, int size, char y[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- to write out a char vector with eighty column lines input -- fp -- file pointer, must be formatted and write access size -- length of the vector y[] -- char vector column -- present column pierr -- pointer to int to hold return value, should be 1 if any print was successful, if fprintf() failed, then ierr = -1 return value -- present column created -- 95sep22, cca ------------------------------------------------------------------ */ int CVfp80 ( FILE *fp, int size, char y[], int column, int *pierr ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to release storage for a character vector, note, should have been created using CVinit created -- 95sep22, cca ------------------------------------------------------ */ void CVfree ( char y[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to read in a char vector return value -- number of characters read created -- 95sep22, cca ----------------------------------------- */ int CVfscanf ( FILE *fp, int size, char y[] ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^T [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU33 ( int n, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^T [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU32 ( int n, double y0[], double y1[], double y2[], double x0[], double x1[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^T [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU31 ( int n, double y0[], double y1[], double y2[], double x0[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^T [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU23 ( int n, double y0[], double y1[], double x0[], double x1[], double x2[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^T [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU22 ( int n, double y0[], double y1[], double x0[], double x1[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^T [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU21 ( int n, double y0[], double y1[], double x0[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^T [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU13 ( int n, double y0[], double x0[], double x1[], double x2[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^T [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU12 ( int n, double y0[], double x0[], double x1[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^T [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU11 ( int n, double y0[], double x0[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^H [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC33 ( int n, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^H [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC32 ( int n, double y0[], double y1[], double y2[], double x0[], double x1[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^H [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC31 ( int n, double y0[], double y1[], double y2[], double x0[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^H [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC23 ( int n, double y0[], double y1[], double x0[], double x1[], double x2[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^H [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC22 ( int n, double y0[], double y1[], double x0[], double x1[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^H [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC21 ( int n, double y0[], double y1[], double x0[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^H [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC13 ( int n, double y0[], double x0[], double x1[], double x2[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^H [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC12 ( int n, double y0[], double x0[], double x1[], double sums[] ) ; /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^H [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC11 ( int n, double y0[], double x0[], double sums[] ) ; /*--------------------------------------------------------------------*/ Utilities/DLIST.h010064400020550007177000000052070653562055100151070ustar00clevecompmath00000400000006#ifndef _DLIST_ #define _DLIST_ /* ------------------------------------------------------------------- doubly linked list macros. all double linked list structures have the two prev and next fields struct delem { whatever other fields struct delem *prev, *next ; } ; all lists have a sentinel element which is the head of the list. when an element is not in a list, its link(s) point to itself example : allocate a set of doubly linked list elements and insert into a list struct delem Head, *head, *elems ; head = &Head ; head->prev = head->next = head ; ALLOCATE(elems, struct delem, nelem, test) ; for ( ielem = 0, elem = elems ; ielem < nelem ; ielem++, elem++) { elem->prev = elem->next = elem ; DLIST_TAIL_INSERT(head, elem) ; } DLIST_DELETE -- delete an element from a doubly linked list DLIST_TAIL_INSERT -- insert an element into a doubly linked list at the tail of the list DLIST_HEAD_INSERT -- insert an element into a doubly linked list at the head of the list DLIST_SWAP_HEADS -- swaps the heads of two doubly linked lists DLIST_MERGE -- merges two doubly linked lists ------------------------------------------------------------------- */ #define DLIST_DELETE(elem) \ (elem)->prev->next = (elem)->next ; \ (elem)->next->prev = (elem)->prev ; \ (elem)->prev = (elem)->next = (elem) ; #define DLIST_TAIL_INSERT(head, elem) \ ((elem)->prev = (head)->prev)->next = (elem) ; \ ((head)->prev = elem)->next = (head) ; #define DLIST_HEAD_INSERT(head, elem) \ ((elem)->next = (head)->next)->prev = (elem) ; \ ((head)->next = elem)->prev = (head) ; #define DLIST_SWAP_HEADS(head1, head2, type) \ if ( (head1)->next == head1 ) { \ if ( (head2)->next != head2 ) { \ ((head1)->next = (head2)->next)->prev \ = ((head1)->prev = (head2)->prev)->next = head1 ; \ (head2)->prev = (head2)->next = head2 ; } } \ else if ( (head2)->next == head2 ) { \ ((head2)->next = (head1)->next)->prev \ = ((head2)->prev = (head1)->prev)->next = head2 ; \ (head1)->prev = (head1)->next = head1 ; } \ else { \ type *temp = head1->next ; \ ((head1)->next = (head2)->next)->prev = head1 ; \ ((head2)->next = temp)->prev = head2 ; \ temp = head1->prev ; \ ((head1)->prev = (head2)->prev)->next = head1 ; \ ((head2)->prev = temp)->next = head2 ; } #define DLIST_MERGE(head1, head2) \ if ( (head2)->next != head2 ) { \ ((head2)->next->prev = (head1)->prev)->next = (head2)->next ; \ ((head1)->prev = (head2)->prev)->next = head1 ; \ (head2)->prev = (head2)->next = head2 ; } #endif Utilities/DV.h010064400020550007177000000424430653410575400145460ustar00clevecompmath00000400000006/* DV.h */ /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to compute y[*] := y[*] + x[*] created -- 95sep22, cca ----------------------------------------- */ void DVadd ( int size, double y[], double x[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to compute y[*] := y[*] + alpha * x[*] created -- 95sep22, cca ------------------------------------------------- */ void DVaxpy ( int size, double y[], double alpha, double x[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to compute y[index[*]] := y[index[*]] + alpha * x[*] created -- 95sep22, cca --------------------------------------------------------------- */ void DVaxpyi ( int size, double y[], int index[], double alpha, double x[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------- purpose -- to copy y[*] := x[*] created -- 95sep22, cca ------------------------------- */ void DVcopy ( int size, double y[], double x[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- given the pair of arrays (x1[],y1[]), create a pair of arrays (x2[],y2[]) whose entries are pairwise chosen from (x1[],y1[]) and whose distribution is an approximation. return value -- the size of the (x2[],y2[]) arrays created -- 95sep22, cca ------------------------------------------------------- */ int DVcompress ( int size1, double x1[], double y1[], int size2, double x2[], double y2[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy sum{y[*] * x[*]} created -- 95sep22, cca ----------------------------------- */ double DVdot ( int size, double y[], double x[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to perform a indexed dot product sum = sum_k y[index[k]]*x[k] where y and x are real created -- 98may02, cca -------------------------------------------- */ double DVdoti ( int size, double y[], int index[], double x[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to fill a double vector with a value created -- 95sep22, cca ----------------------------------------------- */ void DVfill ( int size, double y[], double dval ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to print out a double vector created -- 95sep22, cca ----------------------------------------- */ void DVfprintf ( FILE *fp, int size, double dvec[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to free storage taken by a double vector. note : dvec[] must have been returned by DVinit. created -- 95sep22, cca ----------------------------------------------------------- */ void DVfree ( double dvec[] ) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to read in a double vector return value -- # of entries read created -- 95sep22, cca -------------------------------------------- */ int DVfscanf ( FILE *fp, int size, double y[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- to gather y[*] = x[index[*]] created -- 95sep22, cca --------------------------------------- */ void DVgather ( int size, double y[], double x[], int index[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- to gather add y[*] += x[index[*]] and zero x[index[*]] created -- 95sep22, cca ----------------------------------------------------------------- */ void DVgatherAddZero ( int size, double y[], double x[], int index[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to gather y[*] = x[index[*]] and zero x[*] created -- 95sep22, cca ----------------------------------------------------- */ void DVgatherZero ( int size, double y[], double x[], int index[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- allocate a double array with size entries and fill with value dval return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------------- */ double * DVinit ( int size, double dval ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- allocate a double array with size entries return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------------- */ double * DVinit2 ( int size ) ; /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[index[*]] := y[*] created -- 95sep22, cca ------------------------------ */ void DVinvPerm ( int size, double y[], int index[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to return the first entry of maximum value, *ploc contains its index created -- 95sep22, cca ------------------------------------------------------ */ double DVmax ( int size, double y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of maximum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ double DVmaxabs ( int size, double y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to return the first entry of minimum value, *ploc contains its index created -- 95sep22, cca ------------------------------------------------------ */ double DVmin ( int size, double y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of minimum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ double DVminabs ( int size, double y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[*] := y[index[*]] created -- 95sep22, cca ------------------------------ */ void DVperm ( int size, double y[], int index[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to fill a double vector with a ramp function created -- 95sep22, cca ------------------------------------------------------- */ void DVramp ( int size, double y[], double start, double inc ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to compute y[*] := y[*] - x[*] created -- 95sep22, cca ----------------------------------------- */ void DVsub ( int size, double y[], double x[] ) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to scale a double vector by alpha created -- 95sep22, cca -------------------------------------------- */ void DVscale ( int size, double y[], double alpha ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to scatter y[index[*]] = x[*] created -- 95sep22, cca ---------------------------------------- */ void DVscatter ( int size, double y[], int index[], double x[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to scatter add y[index[*]] += x[*] created -- 96aug17, cca --------------------------------------------- */ void DVscatterAdd ( int size, double y[], int index[], double x[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to scatter add y[index[*]] += x[*] and zero x[*] created -- 95sep22, cca ----------------------------------------------------------- */ void DVscatterAddZero ( int size, double y[], int index[], double x[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to scatter y[index[*]] = x[*] and zero x[*] created -- 95sep22, cca ----------------------------------------------------- */ void DVscatterZero ( int size, double y[], int index[], double x[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to return the sum of a double vector created -- 95sep22, cca ----------------------------------------------- */ double DVsum ( int size, double y[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to return the sum of the absolute values of the entries in a double vector created -- 95sep22, cca --------------------------------------------------- */ double DVsumabs ( int size, double y[] ) ; /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- to swap y[*] and x[*] created -- 95sep22, cca -------------------------------- */ void DVswap ( int size, double y[], double x[] ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------- purpose -- to zero a double vector created -- 95sep22, cca ---------------------------------- */ void DVzero ( int size, double y[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to permute an integer vector, procedure uses srand48() and drand48() input -- size -- size of the vector y -- vector to be permuted seed -- seed for the random number generator if seed <= 0, simple return created -- 95sep22, cca ------------------------------------------------- */ void DVshuffle ( int size, double y[], int seed ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to scale a double vector by a 2x2 matrix [ x ] := [ a b ] [ x ] [ y ] [ c d ] [ y ] created -- 98jan23, cca --------------------------------------------------- */ void DVscale2 ( int size, double x[], double y[], double a, double b, double c, double d ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to perform a axpy with two vectors z := z + a*x + b*y where y and x are double vectors created -- 98jan23, cca -------------------------------------------- */ void DVaxpy2 ( int size, double z[], double a, double x[], double b, double y[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row0[*] * col2[*] sums[3] = row1[*] * col0[*] sums[4] = row1[*] * col1[*] sums[5] = row1[*] * col2[*] sums[6] = row2[*] * col0[*] sums[7] = row2[*] * col1[*] sums[8] = row2[*] * col2[*] created -- 98may02, cca ----------------------------------------- */ void DVdot33 ( int n, double row0[], double row1[], double row2[], double col0[], double col1[], double col2[], double sums[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row0[*] * col2[*] sums[3] = row1[*] * col0[*] sums[4] = row1[*] * col1[*] sums[5] = row1[*] * col2[*] created -- 98may02, cca ----------------------------------------- */ void DVdot23 ( int n, double row0[], double row1[], double col0[], double col1[], double col2[], double sums[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row0[*] * col2[*] created -- 98may02, cca ----------------------------------------- */ void DVdot13 ( int n, double row0[], double col0[], double col1[], double col2[], double sums[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row1[*] * col0[*] sums[3] = row1[*] * col1[*] sums[4] = row2[*] * col0[*] sums[5] = row2[*] * col1[*] created -- 98may02, cca ----------------------------------------- */ void DVdot32 ( int n, double row0[], double row1[], double row2[], double col0[], double col1[], double sums[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row1[*] * col0[*] sums[3] = row1[*] * col1[*] created -- 98may02, cca ----------------------------------------- */ void DVdot22 ( int n, double row0[], double row1[], double col0[], double col1[], double sums[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] created -- 98may02, cca ----------------------------------------- */ void DVdot12 ( int n, double row0[], double col0[], double col1[], double sums[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row1[*] * col0[*] sums[2] = row2[*] * col0[*] created -- 98may02, cca ----------------------------------------- */ void DVdot31 ( int n, double row0[], double row1[], double row2[], double col0[], double sums[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[2] = row1[*] * col0[*] created -- 98may02, cca ----------------------------------------- */ void DVdot21 ( int n, double row0[], double row1[], double col0[], double sums[] ) ; /* ----------------------------------------- purpose -- compute a single dot product sums[0] = row0[*] * col0[*] created -- 98may02, cca ----------------------------------------- */ void DVdot11 ( int n, double row0[], double col0[], double sums[] ) ; *ploc contains its index created -- 95sep22, cca ------------------------------------------------------ */ double DVmin ( int size, double y[], int *ploc ) ; /*--------------------------Utilities/DVsort.h010064400020550007177000000150010653410575400154440ustar00clevecompmath00000400000006/* DVsort.h */ /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- The insert and quick sort methods in this file are based on Jon L. Bentley and M. Douglas McIlroy, "Engineering a sort function", Software -- Practice and Experience, vol 23(11), 1249-1265, November 1993. This quick sort method uses 1) a median of three medians to find a split value, and 2) split-end partitioning to handle many elements equal to the split value. ----------------------------------------------------------- */ /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- sort an array of doubles into ascending order using insert sort created -- 95nov25, cca ---------------------------------------------------------------- */ void DVisortUp ( int n, double dvec[] ) ; /* ----------------------------------------------------------------- sort an array of doubles into descending order using insert sort created -- 95sep29, cca ----------------------------------------------------------------- */ void DVisortDown ( int n, double dvec[] ) ; /* ------------------------------------------ use insert sort to sort a pair or arrays. on output the first is in ascending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 2 3 5 8 9 dvec2[] = 4 3 1 2 5 created -- 95nov25, cca ------------------------------------------ */ void DV2isortUp ( int n, double dvec1[], double dvec2[] ) ; /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 9 8 5 3 2 dvec2[] = 5 2 1 3 4 created -- 95sep29, cca ------------------------------------------- */ void DV2isortDown ( int n, double dvec1[], double dvec2[] ) ; /* --------------------------------------------------------------- sort an array of doubles into ascending order using quick sort created -- 95nov25, cca --------------------------------------------------------------- */ void DVqsortUp ( int n, double dvec[] ) ; /* ---------------------------------------------------------------- sort an array of doubles into descending order using quick sort created -- 95sep29, cca ---------------------------------------------------------------- */ void DVqsortDown ( int n, double dvec[] ) ; /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 2 3 5 8 9 dvec2[] = 4 3 1 2 5 created -- 95sep29, cca ------------------------------------------ */ void DV2qsortUp ( int n, double dvec1[], double dvec2[] ) ; /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 9 8 5 3 2 dvec2[] = 5 2 1 3 4 created -- 95sep29, cca ------------------------------------------- */ void DV2qsortDown ( int n, double dvec1[], double dvec2[] ) ; /* ---------------------------------------------------- return 1 if elements in array are in ascending order return 0 otherwise created -- 95nov25, cca ---------------------------------------------------- */ int DVisascending ( int n, double dvec[] ) ; /* ----------------------------------------------------- return 1 if elements in array are in descending order return 0 otherwise created -- 95sep29, cca ----------------------------------------------------- */ int DVisdescending ( int n, double dvec[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------ use insert sort to sort a pair of arrays. on output the first is in ascending order. dvec[] is the array of keys ivec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 97apr03, cca ------------------------------------------ */ void DVIVisortUp ( int n, double dvec[], int ivec[] ) ; /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 95sep29, cca ------------------------------------------- */ void DVIVisortDown ( int n, double dvec[], int ivec[] ) ; /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 97apr03, cca ------------------------------------------ */ void DVIVqsortUp ( int n, double dvec[], int ivec[] ) ; /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 97apr03, cca ------------------------------------------- */ void DVIVqsortDown ( int n, double dvec[], int ivec[] ) ; /*--------------------------------------------------------------------*/ Utilities/FV.h010064400020550007177000000271670653410575400145560ustar00clevecompmath00000400000006/* FV.h */ /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to compute y[*] := y[*] + x[*] created -- 95sep22, cca ----------------------------------------- */ void FVadd ( int size, float y[], float x[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to compute y[*] := y[*] + alpha * x[*] created -- 95sep22, cca ------------------------------------------------- */ void FVaxpy ( int size, float y[], float alpha, float x[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to compute y[index[*]] := y[index[*]] + alpha * x[*] created -- 95sep22, cca --------------------------------------------------------------- */ void FVaxpyi ( int size, float y[], int index[], float alpha, float x[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------- purpose -- to copy y[*] := x[*] created -- 95sep22, cca ------------------------------- */ void FVcopy ( int size, float y[], float x[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- given the pair of arrays (x1[],y1[]), create a pair of arrays (x2[],y2[]) whose entries are pairwise chosen from (x1[],y1[]) and whose distribution is an approximation. return value -- the size of the (x2[],y2[]) arrays created -- 95sep22, cca ------------------------------------------------------- */ int FVcompress ( int size1, float x1[], float y1[], int size2, float x2[], float y2[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy sum{y[*] * x[*]} created -- 95sep22, cca ----------------------------------- */ float FVdot ( int size, float y[], float x[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to fill a float vector with a value created -- 95sep22, cca ----------------------------------------------- */ void FVfill ( int size, float y[], float dval ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to print out a float vector created -- 95sep22, cca ----------------------------------------- */ void FVfprintf ( FILE *fp, int size, float y[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to free storage taken by a float vector. note : y[] must have been returned by FVinit. created -- 95sep22, cca ----------------------------------------------------------- */ void FVfree ( float y[] ) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to read in a float vector return value -- # of entries read created -- 95sep22, cca -------------------------------------------- */ int FVfscanf ( FILE *fp, int size, float y[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- to gather y[*] = x[index[*]] created -- 95sep22, cca --------------------------------------- */ void FVgather ( int size, float y[], float x[], int index[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- to gather add y[*] += x[index[*]] and zero x[index[*]] created -- 95sep22, cca ----------------------------------------------------------------- */ void FVgatherAddZero ( int size, float y[], float x[], int index[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to gather y[*] = x[index[*]] and zero x[*] created -- 95sep22, cca ----------------------------------------------------- */ void FVgatherZero ( int size, float y[], float x[], int index[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- allocate a float array with size entries and fill with value dval return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------------- */ float * FVinit ( int size, float dval ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- allocate a float array with size entries return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------------- */ float * FVinit2 ( int size ) ; /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[index[*]] := y[*] created -- 95sep22, cca ------------------------------ */ void FVinvPerm ( int size, float y[], int index[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to return the first entry of maximum value, *ploc contains its index created -- 95sep22, cca ------------------------------------------------------ */ float FVmax ( int size, float y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of maximum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ float FVmaxabs ( int size, float y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to return the first entry of minimum value, *ploc contains its index created -- 95sep22, cca ------------------------------------------------------ */ float FVmin ( int size, float y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of minimum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ float FVminabs ( int size, float y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[*] := y[index[*]] created -- 95sep22, cca ------------------------------ */ void FVperm ( int size, float y[], int index[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to fill a float vector with a ramp function created -- 95sep22, cca ------------------------------------------------------- */ void FVramp ( int size, float y[], float start, float inc ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to compute y[*] := y[*] - x[*] created -- 95sep22, cca ----------------------------------------- */ void FVsub ( int size, float y[], float x[] ) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to scale a float vector by alpha created -- 95sep22, cca -------------------------------------------- */ void FVscale ( int size, float y[], float alpha ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to scatter y[index[*]] = x[*] created -- 95sep22, cca ---------------------------------------- */ void FVscatter ( int size, float y[], int index[], float x[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to scatter add y[index[*]] += x[*] and zero x[*] created -- 95sep22, cca ----------------------------------------------------------- */ void FVscatterAddZero ( int size, float y[], int index[], float x[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to scatter y[index[*]] = x[*] and zero x[*] created -- 95sep22, cca ----------------------------------------------------- */ void FVscatterZero ( int size, float y[], int index[], float x[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to return the sum of a float vector created -- 95sep22, cca ----------------------------------------------- */ float FVsum ( int size, float y[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to return the sum of the absolute values of the entries in a float vector created -- 95sep22, cca --------------------------------------------------- */ float FVsumabs ( int size, float y[] ) ; /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- to swap y[*] and x[*] created -- 95sep22, cca -------------------------------- */ void FVswap ( int size, float y[], float x[] ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------- purpose -- to zero a float vector created -- 95sep22, cca ---------------------------------- */ void FVzero ( int size, float y[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to permute an integer vector, procedure uses srand48() and drand48() input -- size -- size of the vector y -- vector to be permuted seed -- seed for the random number generator if seed <= 0, simple return created -- 95sep22, cca ------------------------------------------------- */ void FVshuffle ( int size, float y[], int seed ) ; /*--------------------------------------------------------------------*/ rwise chosen from (x1[],y1[]) and whose distribution is an approximation. return value -- the size of the (x2[],y2[]) arrays created -- 95sep22, cca ------------------------------------------------------- */ int FVcompress ( int size1, float x1[], float y1[], int size2, float x2[], float y2[] ) ; /*----------------------------Utilities/FileType.h010064400020550007177000000003540653410575400157510ustar00clevecompmath00000400000006/* FileType.h */ /* -------------------- FileType definitions -------------------- */ typedef enum _FileType { humanReadable = 1 , formatted = 2 , binary = 3 } FileType ; Utilities/I2OP.h010064400020550007177000000036250653410575500147460ustar00clevecompmath00000400000006/* I2OP.h */ /*--------------------------------------------------------------------*/ typedef struct _I2OP I2OP ; struct _I2OP { int value0 ; int value1 ; void *value2 ; I2OP *next ; } ; #define I2OP_NULL 0 #define I2OP_FORWARD 1 #define I2OP_BACKWARD 2 /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- initializer. create and return an array of n I2OP structures. the structures are linked in one of three ways. flag = 0 (I2OP_NULL) --> ip->next = NULL flag = 1 (I2OP_FORWARD) --> ip->next = successor in list flag = 2 (I2OP_BACKWARD) --> ip->next = predecessor in list created -- 98feb06, cca --------------------------------------------------------- */ I2OP * I2OP_init ( int n, int flag ) ; /* --------------------------------------------------------- initializer. create and return an array of n I2OP structures. the structures are linked in one of three ways. flag = 0 (I2OP_NULL) --> ip->next = NULL flag = 1 (I2OP_FORWARD) --> ip->next = successor in list flag = 2 (I2OP_BACKWARD) --> ip->next = predecessor in list created -- 98feb06, cca --------------------------------------------------------- */ void I2OP_initStorage ( int n, int flag, I2OP *base ) ; /* ----------------------------------------------- free the storage for an array of I2OP structures, must have been allocated by I2OP_init created -- 98feb06, cca ----------------------------------------------- */ void I2OP_free ( I2OP *ip ) ; /* ---------------------------------- purpose -- to print out a I2OP list created -- 98feb06, cca ---------------------------------- */ void I2OP_fprintf ( FILE *fp, I2OP *elem ) ; /*--------------------------------------------------------------------*/ Utilities/IP.h010064400020550007177000000070530653410575400145430ustar00clevecompmath00000400000006/* IP.h */ /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- the IP structure contains an Int field and an IP* field. it is the simplest singly linked list element, useful at times. --------------------------------------------------------------- */ typedef struct _IP IP ; struct _IP { int val ; IP *next ; } ; /*--------------------------------------------------------------------*/ #define IP_NULL 0 #define IP_FORWARD 1 #define IP_BACKWARD 2 /*--------------------------------------------------------------------*/ /* --------------------------------- purpose -- to print out a IP list created -- 95sep22, cca --------------------------------- */ void IP_fprintf ( FILE *fp, IP *ip ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- to write out an integer list with eighty column lines input -- fp -- file pointer, must be formatted and write access ip -- head of list column -- present column return value -- present column created -- 95sep22, cca ------------------------------------------------------------------ */ int IP_fp80 ( FILE *fp, IP *ip, int column ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- initializer. create and return an array of n IP structures. the structures are linked in one of three ways. flag = 0 (IP_NULL) --> ip->next = NULL flag = 1 (IP_FORWARD) --> ip->next = successor in list flag = 2 (IP_BACKWARD) --> ip->next = predecessor in list created -- 95sep22, cca --------------------------------------------------------- */ IP * IP_init ( int n, int flag ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------- free the storage for an array of IP structures, must have been allocated by IP_init created -- 95sep22, cca ----------------------------------------------- */ void IP_free ( IP *ip ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------- merge two lists in ascending order created -- 95sep22, cca ---------------------------------- */ IP * IP_mergeUp ( IP *ip1, IP *ip2 ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to sort a singly linked list in ascending order using a radix sort created -- 95sep22, cca --------------------------------------------- */ IP * IP_radixSortUp ( IP *ip ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to sort a singly linked list in descending order using a radix sort created -- 95sep22, cca ---------------------------------------------- */ IP * IP_radixSortDown ( IP *ip ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------- sort a list in ascending order using merge sort created -- 95sep22, cca ----------------------------------------------- */ IP * IP_mergeSortUp ( IP *ip0 ) ; /*--------------------------------------------------------------------*/ Utilities/IV.h010064400020550007177000000223550653410575400145530ustar00clevecompmath00000400000006/* IV.h */ /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- given the pair of arrays (x1[],y1[]), create a pair of arrays (x2[],y2[]) whose entries are pairwise chosen from (x1[],y1[]) and whose distribution is an approximation. return value -- the size of the (x2[],y2[]) arrays ------------------------------------------------------- */ int IVcompress ( int size1, int x1[], int y1[], int size2, int x2[], int y2[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------- purpose -- to copy y[*] := x[*] ------------------------------- */ void IVcopy ( int size, int y[], int x[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to fill a int vector with a value ----------------------------------------------- */ void IVfill ( int size, int y[], int ival ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------ purpose -- to print out a int vector ------------------------------------ */ void IVfprintf ( FILE *fp, int size, int y[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- to write out an integer vector with eighty column lines input -- fp -- file pointer, must be formatted and write access size -- length of the vector y -- integer vector column -- present column pierr -- pointer to int to hold return value, should be 1 if any print was successful, if fprintf() failed, then ierr = -1 return value -- present column created -- 95sep22, cca mods -- 95sep29, cca added ierr argument to handle error returns from fprintf() ------------------------------------------------------------------- */ int IVfp80 ( FILE *fp, int size, int y[], int column, int *pierr ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- purpose -- to free the storage taken by an integer vector. note : ivec must have been returned by IVinit ---------------------------------------------------------- */ void IVfree ( int y[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to read in an int vector ----------------------------------- */ int IVfscanf ( FILE *fp, int size, int y[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- to gather y[*] = x[index[*]] --------------------------------------- */ void IVgather ( int size, int y[], int x[], int index[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- allocate a int array with size entries and fill with value dval return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------- */ int * IVinit ( int size, int ival ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- allocate a int array with size entries return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------- */ int * IVinit2 ( int size ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- allocate an int array and fill with the inverse of y[]. note, y[] must be a permutation vector. created : 95sep22, cca ------------------------------------------------------------- */ int * IVinverse ( int size, int y[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[index[*]] := y[*] ------------------------------ */ void IVinvPerm ( int size, int y[], int index[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to return the first entry of maximum size, *ploc contains its index ----------------------------------------------------- */ int IVmax ( int size, int y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of maximum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ int IVmaxabs ( int size, int y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to return the first entry of minimum value, *ploc contains its index created -- 95sep22, cca ------------------------------------------------------ */ int IVmin ( int size, int y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of minimum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ int IVminabs ( int size, int y[], int *ploc ) ; /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[*] := y[index[*]] ------------------------------ */ void IVperm ( int size, int y[], int index[] ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to fill a int vector with a ramp function ---------------------------------------------------- */ void IVramp ( int size, int y[], int start, int inc ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to scatter y[index[*]] = x[*] ---------------------------------------- */ void IVscatter ( int size, int y[], int index[], int x[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to return the sum of a int vector ----------------------------------------------- */ int IVsum ( int size, int y[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to return the sum of the absolute values of the entries in an int vector --------------------------------------------------- */ int IVsumabs ( int size, int y[] ) ; /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- to swap y[*] and x[*] -------------------------------- */ void IVswap ( int size, int y[], int x[] ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------- purpose -- to zero a int vector ---------------------------------- */ void IVzero ( int size, int y[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to permute an integer vector, procedure uses srand48() and drand48() input -- size -- size of the vector ivec -- vector to be permuted seed -- seed for the random number generator if seed <= 0, simple return ------------------------------------------------- */ void IVshuffle ( int size, int y[], int seed ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ locate an instance of target in the vector ivec[size]. we assume that ivec[] is sorted in ascending order so we can use binary search to locate target. return value -- -1 -- if target not found in ivec[] loc -- where target = ivec[loc] created -- 96may27, cca ------------------------------------------------------ */ int IVlocateViaBinarySearch ( int size, int ivec[], int target ) ; /*--------------------------------------------------------------------*/ Utilities/IVsort.h010064400020550007177000000247360653410575400154700ustar00clevecompmath00000400000006/* IVsort.h */ /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- sort an array of integers into ascending order using insert sort created -- 95sep28, cca ---------------------------------------------------------------- */ void IVisortUp ( int n, int ivec[] ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- sort an array of integers into ascending order using insert sort created -- 95sep29, cca ---------------------------------------------------------------- */ void IVisortDown ( int n, int ivec[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- sort an array of integers into ascending order using quick sort created -- 95sep28, cca --------------------------------------------------------------- */ void IVqsortUp ( int n, int ivec[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- sort an array of integers into descending order using quick sort created -- 95sep29, cca --------------------------------------------------------------- */ void IVqsortDown ( int n, int ivec[] ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- return 1 if elements in array are in ascending order return 0 otherwise created -- 95sep28, cca ---------------------------------------------------- */ int IVisascending ( int n, int ivec[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- return 1 if elements in array are in descending order return 0 otherwise created -- 95sep29, cca ----------------------------------------------------- */ int IVisdescending ( int n, int ivec[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------ use insert sort to sort a pair of arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 4 3 1 2 5 created -- 95sep28, cca ------------------------------------------ */ void IV2isortUp ( int n, int ivec1[], int ivec2[] ) ; /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 9 8 5 3 2 ivec2[] = 5 2 1 3 4 created -- 95sep29, cca ------------------------------------------- */ void IV2isortDown ( int n, int ivec1[], int ivec2[] ) ; /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 4 3 1 2 5 created -- 95sep29, cca ------------------------------------------ */ void IV2qsortUp ( int n, int ivec1[], int ivec2[] ) ; /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 9 8 5 3 2 ivec2[] = 5 2 1 3 4 created -- 95sep29, cca ------------------------------------------- */ void IV2qsortDown ( int n, int ivec1[], int ivec2[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------ use insert sort to sort a pair of arrays. on output the first is in ascending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 2 3 5 8 9 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 95sep28, cca ------------------------------------------ */ void IVDVisortUp ( int n, int ivec[], double dvec[] ) ; /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 9 8 5 3 2 dvec[] = 5.0 2.0 1.0 3.0 4.0 created -- 95sep29, cca ------------------------------------------- */ void IVDVisortDown ( int n, int ivec[], double dvec[] ) ; /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 2 3 5 8 9 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 95sep29, cca ------------------------------------------ */ void IVDVqsortUp ( int n, int ivec[], double dvec[] ) ; /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 9 8 5 3 2 dvec[] = 5.0 2.0 1.0 3.0 4.0 created -- 95sep29, cca ------------------------------------------- */ void IVDVqsortDown ( int n, int ivec[], double dvec[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------ use insert sort to sort a trio of arrays. on output the first is in ascending order. ivec[] is the array of keys dvec[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 95sep28, cca ------------------------------------------ */ void IV2DVisortUp ( int n, int ivec1[], int ivec2[], double dvec[] ) ; /* ------------------------------------------- use insert sort to sort a trio or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 95sep29, cca ------------------------------------------- */ void IV2DVisortDown ( int n, int ivec1[], int ivec2[], double dvec[] ) ; /* ------------------------------------------ use quick sort to sort a trio or arrays. on output the first is in ascending order. ivec[] is the array of keys dvec[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 95sep29, cca ------------------------------------------ */ void IV2DVqsortUp ( int n, int ivec1[], int ivec2[], double dvec[] ) ; /* ------------------------------------------- use quick sort to sort a trio or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 95sep29, cca ------------------------------------------- */ void IV2DVqsortDown ( int n, int ivec1[], int ivec2[], double dvec[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------ sort the entries in ivec[] into ascending order, then compress out the duplicates return value -- # of compressed entries created -- 97dec18, cca ------------------------------------------------ */ int IVsortUpAndCompress ( int n, int ivec[] ) ; /* ------------------------------------------------ sort the entries in ivec[] into ascending order, using dvec[] as a companion vector. then compress out the duplicates integer keys, summing the double values return value -- # of compressed entries created -- 97dec18, cca ------------------------------------------------ */ int IVDVsortUpAndCompress ( int n, int ivec[], double dvec[] ) ; /* ----------------------------------------------------------------- sort the entries in ivec1[] and ivec2[] into lexicographic order, then compress out the duplicates return value -- # of compressed entries created -- 97dec18, cca ----------------------------------------------------------------- */ int IV2sortUpAndCompress ( int n, int ivec1[], int ivec2[] ) ; /* -------------------------------------------------------------------- sort the entries in ivec1[] and ivec2[] into lexicographic order, using dvec[] as a companion vector. then compress out the duplicates and sum the same values of dvec[] return value -- # of compressed entries created -- 97dec18, cca -------------------------------------------------------------------- */ int IV2DVsortUpAndCompress ( int n, int ivec1[], int ivec2[], double dvec[] ) ; /*--------------------------------------------------------------------*/ Utilities/MM.h010064400020550007177000000043470653410575400145470ustar00clevecompmath00000400000006/* memory.h */ /*====================================================================*/ /* ------------------------------------------------------- flag to turn on the memory functions debugging commands ------------------------------------------------------- */ #define MEMORY_DEBUG 0 /* ---------------------------------------------------------- my memory allocation function ptr -- variable to be given the address of the memory type -- type of data, can be a struct count -- number of data elements proc -- procedure name for error message e.g., int *indices ; double *entries ; struct elem *elems ALLOCATE(indices, int, nindices) ; ALLOCATE(entries, int, nrow*ncol) ; ALLOCATE(elems, struct elem, nelem) ; created -- 95sep22, cca ---------------------------------------------------------- */ #define ALLOCATE(ptr, type, count) \ if ( (count) > 0 ) { \ if ( (ptr = (type *)malloc((unsigned long)((count)*sizeof(type)))) \ == NULL ) {\ fprintf(stderr, \ "\n ALLOCATE failure : bytes %d, line %d, file %s", \ (count)*sizeof(type), __LINE__, __FILE__) ; \ exit(-1) ; } \ else if ( MEMORY_DEBUG > 0 ) { \ fprintf(stderr, \ "\n ALLOCATE : address %p, bytes %d, line %d, file %s", \ ptr, (count)*sizeof(type), __LINE__, __FILE__) ; } } \ else if ( (count) == 0 ) { \ ptr = NULL ; } \ else { \ fprintf(stderr, \ "\n ALLOCATE error : bytes %d, line %d, file %s", \ (count)*sizeof(type), __LINE__, __FILE__) ; \ exit(-1) ; } /* -------------------------------------------------------- my function to free memory, all it does is check to see if the pointer is NULL, calls system routine if not NULL -------------------------------------------------------- */ #if MEMORY_DEBUG > 0 #define FREE(ptr) \ if ( (ptr) != NULL ) { \ fprintf(stderr, "\n FREE, line %d, file %s : address %p", \ __LINE__, __FILE__, ptr) ; \ free((char *) (ptr)) ; \ (ptr) = NULL ; } #else #define FREE(ptr) \ if ( (ptr) != NULL ) { \ free((char *) (ptr)) ; \ (ptr) = NULL ; } #endif /*====================================================================*/ Utilities/ND.h010064400020550007177000000004370653410575400145330ustar00clevecompmath00000400000006/* ND0.h */ void ND0 ( int n1, int n2, int n3, int new_to_old[], int west, int east, int south, int north, int bottom, int top ) ; void fp2DGrid ( int n1, int n2, int ivec[], FILE *fp ) ; void fp3DGrid ( int n1, int n2, int n3, int ivec[], FILE *fp ) ; Utilities/PCV.h010064400020550007177000000025620653410575400146630ustar00clevecompmath00000400000006/* PCV.h */ /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to free a pointer to char vector must have been created by PCVinit created -- 95sep22, cca -------------------------------------------- */ void PCVfree ( char **p_cvec ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to allocate and initialize to NULL a vector of pointer to char created -- 95sep22, cca --------------------------------------------- */ char ** PCVinit ( int size ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to set up a pointer vector created -- 95sep22, cca ------------------------------------- */ void PCVsetup ( int length, int sizes[], char cvec[], char *p_cvec[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy a pointer vector created -- 95sep22, cca ----------------------------------- */ void PCVcopy ( int length, char *p_cvec1[], char *p_cvec2[] ) ; /*--------------------------------------------------------------------*/ Utilities/PDV.h010064400020550007177000000026160653410575400146640ustar00clevecompmath00000400000006/* PDV.h */ /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to free a pointer to double vector must have been created by PDVinit created -- 95sep22, cca --------------------------------------------- */ void PDVfree ( double **p_dvec ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to allocate and initialize to NULL a vector of pointer to double created -- 95sep22, cca --------------------------------------------- */ double ** PDVinit ( int size ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to set up a pointer vector created -- 95sep22, cca ------------------------------------- */ void PDVsetup ( int length, int sizes[], double dvec[], double *p_dvec[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy a pointer vector created -- 95sep22, cca ----------------------------------- */ void PDVcopy ( int length, double *p_dvec1[], double *p_dvec2[] ) ; /*--------------------------------------------------------------------*/ Utilities/PFV.h010064400020550007177000000026030653410575500146630ustar00clevecompmath00000400000006/* PFV.h */ /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to free a pointer to float vector must have been created by PFVinit created -- 95sep22, cca --------------------------------------------- */ void PFVfree ( float **p_fvec ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to allocate and initialize to NULL a vector of pointer to float created -- 95sep22, cca --------------------------------------------- */ float ** PFVinit ( int size ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to set up a pointer vector created -- 95sep22, cca ------------------------------------- */ void PFVsetup ( int length, int sizes[], float fvec[], float *p_fvec[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy a pointer vector created -- 95sep22, cca ----------------------------------- */ void PFVcopy ( int length, float *p_fvec1[], float *p_fvec2[] ) ; /*--------------------------------------------------------------------*/ Utilities/PIV.h010064400020550007177000000025470653410575500146750ustar00clevecompmath00000400000006/* PIV.h */ /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to free a pointer to int vector must have been created by PIVinit created -- 95sep22, cca -------------------------------------------- */ void PIVfree ( int **p_ivec ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to allocate and initialize to NULL a vector of pointer to int created -- 95sep22, cca --------------------------------------------- */ int ** PIVinit ( int size ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to set up a pointer vector created -- 95sep22, cca ------------------------------------- */ void PIVsetup ( int length, int sizes[], int ivec[], int *p_ivec[] ) ; /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy a pointer vector created -- 95sep22, cca ----------------------------------- */ void PIVcopy ( int length, int *p_ivec1[], int *p_ivec2[] ) ; /*--------------------------------------------------------------------*/ Utilities/Utilities.h010064400020550007177000000015620663405661700162110ustar00clevecompmath00000400000006#ifndef _UTILITIES_ /* -------------------------------- these files are not yet included -------------------------------- */ #define _UTILITIES_ /* ---------------- standard C files ---------------- */ #include #include #include #include /* ----------------------------- memory management header file ----------------------------- */ #include "MM.h" /* ------------------------------ doubly linked list macros file ------------------------------ */ #include "DLIST.h" /* ------------ vector files ------------ */ #include "CV.h" #include "DV.h" #include "FV.h" #include "IV.h" #include "PCV.h" #include "PDV.h" #include "PFV.h" #include "PIV.h" #include "IP.h" #include "I2OP.h" #include "newsort.h" #include "mdot.h" #include "util.h" #include "ZV.h" #include "iohb.h" #include "axpy.h" #endif Utilities/ZV.h010064400020550007177000000166320653410575500145760ustar00clevecompmath00000400000006/* ZV.h */ /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to return the absolute value of (areal,aimag) created -- 98jan24, cca -------------------------------------------------------- */ double Zabs ( double real, double imag ) ; /* --------------------------------------------------- purpose -- given (areal,aimag), compute (breal,bimag) = 1/(areal,aimag), put breal into *pbreal put bimag into *pbimag created -- 98jan23, cca --------------------------------------------------- */ int Zrecip ( double areal, double aimag, double *preal, double *pimag ) ; /* --------------------------------------------------------------------- given [ (areal,aimag) (breal,bimag) ] [ (creal,cimag) (dreal,dimag) ] compute [ (ereal,eimag) (freal,fimag) ] [ (greal,gimag) (hreal,himag) ] where I = [ (areal,aimag) (breal,bimag) ] * [ (ereal,eimag) (freal,fimag) ] [ (creal,cimag) (dreal,dimag) ] [ (greal,gimag) (hreal,himag) ] note, any of {pereal, peimag, pfreal, pfimag, pgreal, pgimag, phreal, phimag} can be NULL. if not NULL, their value is filled. this is useful when the input matrix is symmetric or hermitian. created -- 98jan23, cca --------------------------------------------------------------------- */ int Zrecip2 ( double areal, double aimag, double breal, double bimag, double creal, double cimag, double dreal, double dimag, double *pereal, double *peimag, double *pfreal, double *pfimag, double *pgreal, double *pgimag, double *phreal, double *phimag ) ; /* ------------------------------------------------ purpose -- to allocate, initialize and return a complex vector x[] n -- length of the complex vector (2*n double's) x[ii] = (real, imag) for 0 <= ii < n created -- 98jan23, cca ------------------------------------------------ */ double * ZVinit ( int n, double real, double imag ) ; /* ------------------------------------------- purpose -- to perform a complex dot product (*prdot,*pidot) = y^T x where y and x are complex created -- 98apr15, cca ------------------------------------------- */ void ZVdotU ( int size, double y[], double x[], double *prdot, double *pidot ) ; /* ------------------------------------------------------ purpose -- to perform a conjugated complex dot product (*prdot,*pidot) = conjugate(y^T) x where y and x are complex created -- 98apr15, cca ------------------------------------------------------ */ void ZVdotC ( int size, double y[], double x[], double *prdot, double *pidot ) ; /* --------------------------------------------------- purpose -- to perform a indexed complex dot product (*prdot,*pidot) = sum_k y[index[k]]*x[k] where y and x are complex created -- 98apr15, cca --------------------------------------------------- */ void ZVdotiU ( int size, double y[], int index[], double x[], double *prdot, double *pidot ) ; /* ------------------------------------------------------------- purpose -- to perform a indexed conjugate complex dot product (*prdot,*pidot) = sum_k conjugate(y[index[k]])*x[k] where y and x are complex created -- 98apr15, cca ------------------------------------------------------------- */ void ZVdotiC ( int size, double y[], int index[], double x[], double *prdot, double *pidot ) ; /* ------------------------------------ purpose -- to perform a complex axpy y := y + (areal, aimag) * x where y and x are complex created -- 98jan22, cca ------------------------------------ */ void ZVaxpy ( int size, double y[], double areal, double aimag, double x[] ) ; /* ----------------------------------------------------- purpose -- to perform a complex axpy with two vectors z := z + (areal, aimag)*x + (breal, bimag)*y where y and x are complex created -- 98jan23, cca ---------------------------------------------------- */ void ZVaxpy2 ( int size, double z[], double areal, double aimag, double x[], double breal, double bimag, double y[] ) ; /* ------------------------------------------------------------ purpose -- to scale a double complex vector by (xreal,ximag) y := y * (areal, aimag) created -- 98jan22, cca ------------------------------------------------------------ */ void ZVscale ( int size, double y[], double areal, double aimag ) ; /* ------------------------------------------------------------ purpose -- to scale a double complex vector by a 2x2 matrix [ y0 ] := [ d00 d01 ] [ y0 ] [ y1 ] [ d10 d11 ] [ y1 ] created -- 98jan23, cca ------------------------------------------------------------ */ void ZVscale2 ( int size, double y0[], double y1[], double d00r, double d00i, double d01r, double d01i, double d10r, double d10i, double d11r, double d11i ) ; /* ----------------------------------------------- purpose --- to print a complex vector to a file created -- 98jan23, cca ----------------------------------------------- */ void ZVfprintf ( FILE *fp, int size, double y[] ) ; /* ---------------------------------- return the minimum absolute value of the entries in a complex vector created -- 98jan23, cca ---------------------------------- */ double ZVminabs ( int size, double x[] ) ; /* ---------------------------------- return the maximum absolute value of the entries in a complex vector created -- 98jan23, cca ---------------------------------- */ double ZVmaxabs ( int size, double x[] ) ; /* ---------------------------------- copy a complex vector into another y[] := x[] created -- 98jan23, cca ---------------------------------- */ void ZVcopy ( int size, double y[], double x[] ) ; /* -------------------------------------- subtract a complex vector from another y[] := x[] created -- 98may25, cca -------------------------------------- */ void ZVsub ( int size, double y[], double x[] ) ; /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- to gather y[*] = x[index[*]] created -- 98apr15, cca --------------------------------------- */ void ZVgather ( int size, double y[], double x[], int index[] ) ; /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to scatter y[index[*]] = x[*] created -- 98apr15, cca ---------------------------------------- */ void ZVscatter ( int size, double y[], int index[], double x[] ) ; /* ----------------------------- purpose -- to zero the vector y := 0 where y is complex created -- 98apr25, cca ----------------------------- */ void ZVzero ( int size, double y[] ) ; /*--------------------------------------------------------------------*/ ------- */ int Zrecip2 ( double areal, double aimag, double breal, double bimag, doubleUtilities/axpy.h010064400020550007177000000151770663404545300152220ustar00clevecompmath00000400000006/* axpy.h */ /* ----------------------------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] + alpha[2] * x2[] y1[] = y1[] + alpha[3] * x0[] + alpha[4] * x1[] + alpha[5] * x2[] y2[] = y2[] + alpha[6] * x0[] + alpha[7] * x1[] + alpha[8] * x2[] created -- 98dec10, cca ----------------------------------------------------------------- */ void DVaxpy33 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[], double x1[], double x2[] ) ; /* ----------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] y1[] = y1[] + alpha[2] * x0[] + alpha[3] * x1[] y2[] = y2[] + alpha[4] * x0[] + alpha[5] * x1[] created -- 98dec10, cca ----------------------------------------------- */ void DVaxpy32 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[], double x1[] ) ; /* ----------------------------- y0[] = y0[] + alpha[0] * x0[] y1[] = y1[] + alpha[1] * x0[] y2[] = y2[] + alpha[2] * x0[] created -- 98dec10, cca ----------------------------- */ void DVaxpy31 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[] ) ; /* ----------------------------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] + alpha[2] * x2[] y1[] = y1[] + alpha[3] * x0[] + alpha[4] * x1[] + alpha[5] * x2[] created -- 98dec10, cca ----------------------------------------------------------------- */ void DVaxpy23 ( int n, double y0[], double y1[], double alpha[], double x0[], double x1[], double x2[] ) ; /* ----------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] y1[] = y1[] + alpha[2] * x0[] + alpha[3] * x1[] created -- 98dec10, cca ----------------------------------------------- */ void DVaxpy22 ( int n, double y0[], double y1[], double alpha[], double x0[], double x1[] ) ; /* ----------------------------- y0[] = y0[] + alpha[0] * x0[] y1[] = y1[] + alpha[1] * x0[] created -- 98dec10, cca ----------------------------- */ void DVaxpy21 ( int n, double y0[], double y1[], double alpha[], double x0[] ) ; /* ----------------------------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] + alpha[2] * x2[] created -- 98dec10, cca ----------------------------------------------------------------- */ void DVaxpy13 ( int n, double y0[], double alpha[], double x0[], double x1[], double x2[] ) ; /* ----------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] created -- 98dec10, cca ----------------------------------------------- */ void DVaxpy12 ( int n, double y0[], double alpha[], double x0[], double x1[] ) ; /* ----------------------------- y0[] = y0[] + alpha[0] * x0[] created -- 98dec10, cca ----------------------------- */ void DVaxpy11 ( int n, double y0[], double alpha[], double x0[] ) ; /* ----------------------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] + alpha[4:5] * x2[] y1[] = y1[] + alpha[6:7] * x0[] + alpha[8:9] * x1[] + alpha[10:11] * x2[] y2[] = y2[] + alpha[12:13] * x0[] + alpha[14:15] * x1[] + alpha[16:17] * x2[] created -- 98dec10, cca ----------------------------------------------------------------- */ void ZVaxpy33 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[], double x1[], double x2[] ) ; /* ----------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] y1[] = y1[] + alpha[4:5] * x0[] + alpha[6:7] * x1[] y2[] = y2[] + alpha[8:9] * x0[] + alpha[10:11] * x1[] created -- 98dec10, cca ----------------------------------------------------- */ void ZVaxpy32 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[], double x1[] ) ; /* ------------------------------- y0[] = y0[] + alpha[0:1] * x0[] y1[] = y1[] + alpha[2:3] * x0[] y2[] = y2[] + alpha[4:5] * x0[] created -- 98dec10, cca ------------------------------- */ void ZVaxpy31 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[] ) ; /* ----------------------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] + alpha[4:5] * x2[] y1[] = y1[] + alpha[6:7] * x0[] + alpha[8:9] * x1[] + alpha[10:11] * x2[] created -- 98dec10, cca ----------------------------------------------------------------- */ void ZVaxpy23 ( int n, double y0[], double y1[], double alpha[], double x0[], double x1[], double x2[] ) ; /* ----------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] y1[] = y1[] + alpha[4:5] * x0[] + alpha[6:7] * x1[] created -- 98dec10, cca ----------------------------------------------------- */ void ZVaxpy22 ( int n, double y0[], double y1[], double alpha[], double x0[], double x1[] ) ; /* ------------------------------- y0[] = y0[] + alpha[0:1] * x0[] y1[] = y1[] + alpha[2:3] * x0[] created -- 98dec10, cca ------------------------------- */ void ZVaxpy21 ( int n, double y0[], double y1[], double alpha[], double x0[] ) ; /* --------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] + alpha[4:5] * x2[] created -- 98dec10, cca --------------------------------------------------- */ void ZVaxpy13 ( int n, double y0[], double alpha[], double x0[], double x1[], double x2[] ) ; /* ----------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] created -- 98dec10, cca ----------------------------------------------------- */ void ZVaxpy12 ( int n, double y0[], double alpha[], double x0[], double x1[] ) ; /* ------------------------------- y0[] = y0[] + alpha[0:1] * x0[] created -- 98dec10, cca ------------------------------- */ void ZVaxpy11 ( int n, double y0[], double alpha[], double x0[] ) ; Utilities/iohb.h010064400020550007177000000061420660023651400151430ustar00clevecompmath00000400000006/* iohb.h */ /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- prototypes from the Harwell-Boeing IO routines from Karen Remington at NIST. http://math.nist.gov/mcsd/Staff/KRemington/harwell_io/harwell_io.html --------------------------------------------------------------------- */ int readHB_info ( const char *filename, int *M, int *N, int *nz, char **Type, int *Nrhs ) ; int readHB_header ( FILE* in_file, char* Title, char* Key, char* Type, int* Nrow, int* Ncol, int* Nnzero, int* Nrhs, char* Ptrfmt, char* Indfmt, char* Valfmt, char* Rhsfmt, int* Ptrcrd, int* Indcrd, int* Valcrd, int* Rhscrd, char *Rhstype ) ; int readHB_newmat_double ( const char *filename, int *M, int *N, int *nz, int **colptr, int **rowind, double **val ) ; int readHB_mat_double ( const char *filename, int *colptr, int *rowind, double *val ) ; int readHB_aux_double ( const char *filename, const char AuxType, double b[] ) ; int readHB_newaux_double ( const char *filename, const char AuxType, double **b ) ; int writeHB_mat_double ( const char *filename, int M, int N, int nz, const int colptr[], const int rowind[], const double val[], int Nrhs, const double rhs[], const double guess[], const double exact[], const char *Title, const char *Key, const char *Type, char *Ptrfmt, char *Indfmt, char *Valfmt, char *Rhsfmt, const char *Rhstype ) ; int readHB_mat_char ( const char *filename, int colptr[], int rowind[], char val[], char *Valfmt ) ; int readHB_newmat_char ( const char *filename, int *M, int *N, int *nonzeros, int **colptr, int **rowind, char **val, char **Valfmt ) ; int readHB_aux_char ( const char *filename, const char AuxType, char b[] ) ; int readHB_newaux_char ( const char *filename, const char AuxType, char **b, char **Rhsfmt ) ; int writeHB_mat_char ( const char *filename, int M, int N, int nz, const int colptr[], const int rowind[], const char val[], int Nrhs, const char rhs[], const char guess[], const char exact[], const char *Title, const char *Key, const char *Type, char *Ptrfmt, char *Indfmt, char *Valfmt, char *Rhsfmt, const char *Rhstype ) ; /*--------------------------------------------------------------------*/ Utilities/mdot.h010064400020550007177000000100760653410575500151760ustar00clevecompmath00000400000006/* mdot.h */ /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row0[*] * col2[*] sums[3] = row1[*] * col0[*] sums[4] = row1[*] * col1[*] sums[5] = row1[*] * col2[*] sums[6] = row2[*] * col0[*] sums[7] = row2[*] * col1[*] sums[8] = row2[*] * col2[*] created -- 96oct20, cca ----------------------------------------- */ void mdot3x3 ( double sums[], int n, double row0[], double row1[], double row2[], double col0[], double col1[], double col2[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row0[*] * col2[*] sums[3] = row1[*] * col0[*] sums[4] = row1[*] * col1[*] sums[5] = row1[*] * col2[*] created -- 96oct20, cca ----------------------------------------- */ void mdot2x3 ( double sums[], int n, double row0[], double row1[], double col0[], double col1[], double col2[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row0[*] * col2[*] created -- 96oct20, cca ----------------------------------------- */ void mdot1x3 ( double sums[], int n, double row0[], double col0[], double col1[], double col2[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row1[*] * col0[*] sums[3] = row1[*] * col1[*] sums[4] = row2[*] * col0[*] sums[5] = row2[*] * col1[*] created -- 96oct20, cca ----------------------------------------- */ void mdot3x2 ( double sums[], int n, double row0[], double row1[], double row2[], double col0[], double col1[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[3] = row1[*] * col0[*] sums[4] = row1[*] * col1[*] created -- 96oct20, cca ----------------------------------------- */ void mdot2x2 ( double sums[], int n, double row0[], double row1[], double col0[], double col1[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] created -- 96oct20, cca ----------------------------------------- */ void mdot1x2 ( double sums[], int n, double row0[], double col0[], double col1[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row1[*] * col0[*] sums[2] = row2[*] * col0[*] created -- 96oct20, cca ----------------------------------------- */ void mdot3x1 ( double sums[], int n, double row0[], double row1[], double row2[], double col0[] ) ; /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row1[*] * col0[*] created -- 96oct20, cca ----------------------------------------- */ void mdot2x1 ( double sums[], int n, double row0[], double row1[], double col0[] ) ; /* ----------------------------------------- purpose -- compute a dot product sums[0] = row0[*] * col0[*] created -- 96oct20, cca ----------------------------------------- */ void mdot1x1 ( double sums[], int n, double row0[], double col0[] ) ; /*--------------------------------------------------------------------*/ Utilities/misc.h010064400020550007177000000126610653410575500151700ustar00clevecompmath00000400000006/* misc.h.c */ /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to print out a list of entries input -- length -- number of entries entries -- entries array fp -- file pointer ----------------------------------------- */ void fp_dvec ( int length, double entries[], FILE *fp ) ; /* ----------------------------------------- purpose -- to print out a list of entries input -- id -- id of the entries length -- number of entries entries -- entries array fp -- file pointer ----------------------------------------- */ void fp_entries ( int id, int length, double entries[], FILE *fp ) ; /* ------------------------------------------------------------------ purpose -- to write out an integer vector with eighty column lines input -- length -- length of the vector ivec -- integer vector column -- present column fp -- file pointer, must be formatted and write access return value -- present column ------------------------------------------------------------------ */ int fp_i80 ( int length, int ivec[], int column, FILE *fp ) ; /* ------------------------------------------------------------------ purpose -- to print out a list of entries given by an indexed list input -- id -- id of the entries length -- number of entries indices -- indexed list entries -- entries array fp -- file pointer ------------------------------------------------------------------ */ void fp_i_entries ( int id, int length, int indices[], double entries[], FILE *fp ) ; /* ------------------------------------------------------------------ purpose -- to print out a list of entries given by an indexed list print indices[index[*]] input -- id -- id of the entries length -- number of entries indices -- indices index -- index array fp -- file pointer ------------------------------------------------------------------ */ void fp_i_indices ( int id, int length, int indices[], int index[], FILE *fp ) ; /* ----------------------------------------- purpose -- to print out a list of indices input -- id -- id of the indices length -- number of indices indices -- index array fp -- file pointer ----------------------------------------- */ void fp_indices ( int id, int length, int indices[], FILE *fp ) ; /* ----------------------------------------- purpose -- to print out an integer vector input -- length -- number of indices indices -- index array fp -- file pointer ----------------------------------------- */ void fp_ivec ( int length, int indices[], FILE *fp ) ; /* ----------------------------------------- purpose -- to print out a long vector input -- length -- number of indices l_indices -- index array fp -- file pointer ----------------------------------------- */ void fp_lvec ( int length, long l_indices[], FILE *fp ) ; /* ------------------------------------------ purpose -- to print out a character vector input -- length -- number of indices l_indices -- index array fp -- file pointer ------------------------------------------ */ void fp_cvec ( int length, char cvec[], FILE *fp ) ; /*--------------------------------------------------------------------*/ void ND0 ( int n1, int n2, int n3, int new_to_old[], int west, int east, int south, int north, int bottom, int top ) ; void fp2DGrid ( int n1, int n2, int ivec[], FILE *fp ) ; void fp3DGrid ( int n1, int n2, int n3, int ivec[], FILE *fp ) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to sort int/double vectors in ascending order using a bubble sort algorithm -------------------------------------------------------- */ void IDbbsortUp ( int size, int ivec[], double dvec[] ) ; /* --------------------------------------------------------- purpose -- to sort int/double vectors in descending order using a bubble sort algorithm --------------------------------------------------------- */ void IDbbsortDown ( int size, int ivec[], double dvec[] ) ; /* -------------------------------------------------------- purpose -- to sort int/double vectors in ascending order using a bubble sort algorithm -------------------------------------------------------- */ void IDDbbsortUp ( int size, int ivec[], double dvec1[], double dvec2[] ) ; /* --------------------------------------------------------- purpose -- to sort int/double vectors in descending order using a bubble sort algorithm --------------------------------------------------------- */ void IDDbbsortDown ( int size, int ivec[], double dvec1[], double dvec2[] ) ; /*--------------------------------------------------------------------*/ Utilities/newsort.h010064400020550007177000000554640653410575500157460ustar00clevecompmath00000400000006/* newsort.h.c */ /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- return 1 if elements in array are in ascending order return 0 otherwise created -- 98jan28, cca ---------------------------------------------------- */ int IVisascending ( int n, int ivec[] ) ; /* ----------------------------------------------------- return 1 if elements in array are in descending order return 0 otherwise created -- 98jan28, cca ----------------------------------------------------- */ int IVisdescending ( int n, int ivec[] ) ; /* ---------------------------------------------------- return 1 if elements in array are in ascending order return 0 otherwise created -- 98jan28, cca ---------------------------------------------------- */ int DVisascending ( int n, double dvec[] ) ; /* ----------------------------------------------------- return 1 if elements in array are in descending order return 0 otherwise created -- 98jan28, cca ----------------------------------------------------- */ int DVisdescending ( int n, double dvec[] ) ; /*==== INSERT SORT METHODS ======================================*/ /* ---------------------------------------------------------------- sort an array of integers into ascending order using insert sort created -- 98jan28, cca ---------------------------------------------------------------- */ void IVisortUp ( int n, int ivec[] ) ; /* ------------------------------------------ use insert sort to sort a pair or arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 4 3 1 2 5 created -- 98jan28, cca ------------------------------------------ */ void IV2isortUp ( int n, int ivec1[], int ivec2[] ) ; /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 9 8 5 3 2 ivec2[] = 5 2 1 3 4 created -- 98jan28, cca ------------------------------------------- */ void IV2isortDown ( int n, int ivec1[], int ivec2[] ) ; /* ------------------------------------------ use insert sort to sort a pair of arrays. on output the first is in ascending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 2 3 5 8 9 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------ */ void IVDVisortUp ( int n, int ivec[], double dvec[] ) ; /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 9 8 5 3 2 dvec[] = 5.0 2.0 1.0 3.0 4.0 created -- 98jan28, cca ------------------------------------------- */ void IVDVisortDown ( int n, int ivec[], double dvec[] ) ; /* ----------------------------------------------------------------- sort an array of integers into descending order using insert sort created -- 98jan28, cca ----------------------------------------------------------------- */ void IVisortDown ( int n, int ivec[] ) ; /* ------------------------------------------ use insert sort to sort a trio of arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is a companion array dvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------ */ void IV2DVisortUp ( int n, int ivec1[], int ivec2[], double dvec[] ) ; /* ------------------------------------------- use insert sort to sort a trio or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is a companion array dvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------- */ void IV2DVisortDown ( int n, int ivec1[], int ivec2[], double dvec[] ) ; /* ------------------------------------------------------------- use insert sort to sort a pair of arrays. on output the first is in ascending order. ivec[] is the array of keys zvec[] is the companion array of complex example, ivec[] = 5 8 3 2 9 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec[] = 2 3 5 8 9 zvec[] = (4.0,4.5) (3.0,3.5) (1.0,1.5) (2.0,2.5) (5.0,5.5) created -- 98jan28, cca ------------------------------------------------------------- */ void IVZVisortUp ( int n, int ivec[], double zvec[] ) ; /* ------------------------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys zvec[] is the companion array example, ivec[] = 5 8 3 2 9 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec[] = 9 8 5 3 2 zvec[] = (5.0,5.5) (2.0,2.5) (1.0,1.5) (3.0,3.5) (4.0,4.5) created -- 98jan28, cca ------------------------------------------------------------- */ void IVZVisortDown ( int n, int ivec[], double zvec[] ) ; /* -------------------------------------------------------------- use insert sort to sort a trio of arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is a companion array zvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 zvec[] = (4.0,4.5) (3.0,3.5) (1.0,1.5) (2.0,2.5) (5.0,5.5) created -- 98jan28, cca -------------------------------------------------------------- */ void IV2ZVisortUp ( int n, int ivec1[], int ivec2[], double zvec[] ) ; /* -------------------------------------------------------------- use insert sort to sort a trio or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is a companion array zvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec1[] = 9 8 5 3 2 ivec2[] = 5 7 6 8 9 zvec[] = (5.0,5.5) (2.0,2.5) (1.0,1.5) (4.0,4.5) (4.0,4.5) created -- 98jan28, cca -------------------------------------------------------------- */ void IV2ZVisortDown ( int n, int ivec1[], int ivec2[], double zvec[] ) ; /* ---------------------------------------------------------------- sort an array of doubles into ascending order using insert sort created -- 98jan28, cca ---------------------------------------------------------------- */ void DVisortUp ( int n, double dvec[] ) ; /* ----------------------------------------------------------------- sort an array of doubles into descending order using insert sort created -- 98jan28, cca ----------------------------------------------------------------- */ void DVisortDown ( int n, double dvec[] ) ; /* ------------------------------------------ use insert sort to sort a pair or arrays. on output the first is in ascending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 2 3 5 8 9 dvec2[] = 4 3 1 2 5 created -- 98jan28, cca ------------------------------------------ */ void DV2isortUp ( int n, double dvec1[], double dvec2[] ) ; /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 9 8 5 3 2 dvec2[] = 5 2 1 3 4 created -- 98jan28, cca ------------------------------------------- */ void DV2isortDown ( int n, double dvec1[], double dvec2[] ) ; /* ------------------------------------------ use insert sort to sort a pair of arrays. on output the first is in ascending order. dvec[] is the array of keys ivec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 98jan28, cca ------------------------------------------ */ void DVIVisortUp ( int n, double dvec[], int ivec[] ) ; /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 98jan28, cca ------------------------------------------- */ void DVIVisortDown ( int n, double dvec[], int ivec[] ) ; /*==== QUICKSORT METHODS ========================================*/ /* --------------------------------------------------------------- sort an array of integers into ascending order using quick sort created -- 98jan28, cca --------------------------------------------------------------- */ void IVqsortUp ( int n, int ivec[] ) ; /* ---------------------------------------------------------------- sort an array of integers into descending order using quick sort created -- 98jan28, cca ---------------------------------------------------------------- */ void IVqsortDown ( int n, int ivec[] ) ; /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 4 3 1 2 5 created -- 98jan28, cca ------------------------------------------ */ void IV2qsortUp ( int n, int ivec1[], int ivec2[] ) ; /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 9 8 5 3 2 ivec2[] = 5 2 1 3 4 created -- 98jan28, cca ------------------------------------------- */ void IV2qsortDown ( int n, int ivec1[], int ivec2[] ) ; /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 2 3 5 8 9 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------ */ void IVDVqsortUp ( int n, int ivec[], double dvec[] ) ; /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 9 8 5 3 2 dvec[] = 5.0 2.0 1.0 3.0 4.0 created -- 98jan28, cca ------------------------------------------- */ void IVDVqsortDown ( int n, int ivec[], double dvec[] ) ; /* ------------------------------------------ use quick sort to sort a trio or arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is a companion array dvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------ */ void IV2DVqsortUp ( int n, int ivec1[], int ivec2[], double dvec[] ) ; /* ------------------------------------------- use quick sort to sort a trio or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is a companion array dvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------- */ void IV2DVqsortDown ( int n, int ivec1[], int ivec2[], double dvec[] ) ; /* ------------------------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in ascending order. ivec[] is the array of keys zvec[] is the companion array example, ivec[] = 5 8 3 2 9 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec[] = 2 3 5 8 9 zvec[] = (4.0,4.5) (3.0,3.5) (1.0,1.5) (2.0,2.5) (5.0,5.5) created -- 98jan28, cca ------------------------------------------------------------- */ void IVZVqsortUp ( int n, int ivec[], double zvec[] ) ; /* ------------------------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys zvec[] is the companion array example, ivec[] = 5 8 3 2 9 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec[] = 9 8 5 3 2 zvec[] = (5.0,5.5) (2.0,2.5) (1.0,1.5) (3.0,3.5) (4.0,4.5) created -- 98jan28, cca ------------------------------------------------------------- */ void IVZVqsortDown ( int n, int ivec[], double zvec[] ) ; /* -------------------------------------------------------------- use quick sort to sort a trio or arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is a companion array zvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 zvec[] = (4.0,4.5) (3.0,3.5) (1.0,1.5) (2.0,2.5) (5.0,5.5) created -- 98jan28, cca -------------------------------------------------------------- */ void IV2ZVqsortUp ( int n, int ivec1[], int ivec2[], double zvec[] ) ; /* -------------------------------------------------------------- use quick sort to sort a trio or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is a companion array zvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec1[] = 9 8 5 3 2 ivec2[] = 5 7 6 8 9 zvec[] = (5.0,5.5) (2.0,2.5) (1.0,1.5) (4.0,4.5) (4.0,4.5) created -- 98jan28, cca -------------------------------------------------------------- */ void IV2ZVqsortDown ( int n, int ivec1[], int ivec2[], double zvec[] ) ; /* --------------------------------------------------------------- sort an array of doubles into ascending order using quick sort created -- 98jan28, cca --------------------------------------------------------------- */ void DVqsortUp ( int n, double dvec[] ) ; /* ---------------------------------------------------------------- sort an array of doubles into descending order using quick sort created -- 98jan28, cca ---------------------------------------------------------------- */ void DVqsortDown ( int n, double dvec[] ) ; /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 2 3 5 8 9 dvec2[] = 4 3 1 2 5 created -- 98jan28, cca ------------------------------------------ */ void DV2qsortUp ( int n, double dvec1[], double dvec2[] ) ; /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 9 8 5 3 2 dvec2[] = 5 2 1 3 4 created -- 98jan28, cca ------------------------------------------- */ void DV2qsortDown ( int n, double dvec1[], double dvec2[] ) ; /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 98jan28, cca ------------------------------------------ */ void DVIVqsortUp ( int n, double dvec[], int ivec[] ) ; /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 98jan28, cca ------------------------------------------- */ void DVIVqsortDown ( int n, double dvec[], int ivec[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------ sort the entries in ivec[] into ascending order, then compress out the duplicates return value -- # of compressed entries created -- 97dec18, cca ------------------------------------------------ */ int IVsortUpAndCompress ( int n, int ivec[] ) ; /* ------------------------------------------------ sort the entries in ivec[] into ascending order, using dvec[] as a companion vector. then compress out the duplicates integer keys, summing the double values return value -- # of compressed entries created -- 97dec18, cca ------------------------------------------------ */ int IVDVsortUpAndCompress ( int n, int ivec[], double dvec[] ) ; /* ------------------------------------------------ sort the entries in ivec[] into ascending order, using zvec[] as a complex companion vector. then compress out the duplicates integer keys, summing the complex values return value -- # of compressed entries created -- 98jan28, cca ------------------------------------------------ */ int IVZVsortUpAndCompress ( int n, int ivec[], double zvec[] ) ; /* ----------------------------------------------------------------- sort the entries in ivec1[] and ivec2[] into lexicographic order, then compress out the duplicates return value -- # of compressed entries created -- 97dec18, cca ----------------------------------------------------------------- */ int IV2sortUpAndCompress ( int n, int ivec1[], int ivec2[] ) ; /* -------------------------------------------------------------------- sort the entries in ivec1[] and ivec2[] into lexicographic order, using dvec[] as a companion vector. then compress out the duplicates and sum the same values of dvec[] return value -- # of compressed entries created -- 97dec18, cca -------------------------------------------------------------------- */ int IV2DVsortUpAndCompress ( int n, int ivec1[], int ivec2[], double dvec[] ) ; /* -------------------------------------------------------------------- sort the entries in ivec1[] and ivec2[] into lexicographic order, using zvec[] as a companion vector. then compress out the duplicates and sum the same values of zvec[] return value -- # of compressed entries created -- 98jan28, cca -------------------------------------------------------------------- */ int IV2ZVsortUpAndCompress ( int n, int ivec1[], int ivec2[], double zvec[] ) ; /*--------------------------------------------------------------------*/ se quick sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 Utilities/util.h010064400020550007177000000020350653410575500152040ustar00clevecompmath00000400000006/* util.h */ /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- sort and count observations of two integers. input nobs -- # of observations x[] -- vector of first components of observations y[] -- vector of second components of observations output pndistinct -- pointer to hold # of distinct observations pxdistinct -- pointer to hold first components of the distinct observations pydistinct -- pointer to hold second components of the distinct observations pcounts -- pointer to hold counts of the distinct observations created -- 95sep30, cca -------------------------------------------------------------------- */ void IV2sortAndCount ( int nobs, int x[], int y[], int *pndistinct, int **pxdistinct, int **pydistinct, int **pcounts ) ; /*--------------------------------------------------------------------*/ Utilities/makefile010064400020550007177000000002230663622370100155460ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean Utilities/src/makefile010064400020550007177000000012450663602032600163400ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Utilities $(OBJ).a : \ $(OBJ).a(axpy.o) \ $(OBJ).a(CV.o) \ $(OBJ).a(DV.o) \ $(OBJ).a(FV.o) \ $(OBJ).a(IV.o) \ $(OBJ).a(PCV.o) \ $(OBJ).a(PDV.o) \ $(OBJ).a(PFV.o) \ $(OBJ).a(PIV.o) \ $(OBJ).a(IP.o) \ $(OBJ).a(I2OP.o) \ $(OBJ).a(iohb.o) \ $(OBJ).a(newsort.o) \ $(OBJ).a(sortAndCompress.o) \ $(OBJ).a(ZV.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG Utilities/src/makeGlobalLib010064400020550007177000000010230660026115700172420ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = Utilities SRC = CV.c \ DV.c \ FV.c \ IV.c \ PCV.c \ PDV.c \ PFV.c \ PIV.c \ IP.c \ I2OP.c \ iohb.c \ newsort.c \ sortAndCompress.c \ ZV.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a Utilities/src/CV.c010064400020550007177000000126120653410575100153170ustar00clevecompmath00000400000006/* CV.c */ #include "../Utilities.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- allocate a char array with size entries and fill with value c return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------- */ char * CVinit ( int size, char c ) { char *y ; if ( size <= 0 ) { y = NULL ; } else { y = CVinit2(size) ; CVfill(size, y, c) ; } return(y) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- allocate a char array with size entries return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------- */ char * CVinit2 ( int size ) { char *y ; if ( size <= 0 ) { y = NULL ; } else { ALLOCATE(y, char, size) ; } return(y) ; } /*--------------------------------------------------------------------*/ /* ------------------------------- purpose -- to copy y[*] := x[*] created -- 95sep22, cca ------------------------------- */ void CVcopy ( int size, char y[], char x[] ) { if ( size <= 0 ) { return ; } else if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in CVcopy, size = %d, y = %p, x = %p\n", size, y, x) ; exit(0) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = x[i] ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------- purpose -- to fill y[*] := c created -- 95sep22, cca ---------------------------- */ void CVfill ( int size, char y[], char c ) { if ( size <= 0 ) { return ; } else if ( y == NULL ) { fprintf(stderr, "\n fatal error in CVfill, size = %d, y = %p\n", size, y) ; exit(0) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = c ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to print out a char vector the vector starts on a new line and takes 80 characters per line created -- 95sep22, cca ------------------------------------- */ void CVfprintf ( FILE *fp, int size, char y[] ) { if ( fp != NULL && size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in CVfprintf, fp = %p, size = %d, y = %p\n", fp, size, y) ; exit(0) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { if ( i % 80 == 0 ) fprintf(fp, "\n") ; fprintf(fp, "%c", y[i]) ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- to write out a char vector with eighty column lines input -- fp -- file pointer, must be formatted and write access size -- length of the vector y[] -- char vector column -- present column pierr -- pointer to int to hold return value, should be 1 if any print was successful, if fprintf() failed, then ierr = -1 return value -- present column created -- 95sep22, cca ------------------------------------------------------------------ */ int CVfp80 ( FILE *fp, int size, char y[], int column, int *pierr ) { *pierr = 1 ; if ( fp != NULL && size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in CVfp80" "\n fp = %p, size = %d, y = %p, column = %d\n", fp, size, y, column) ; exit(0) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { if ( ++column >= 80 ) { fprintf(fp, "\n") ; column = 0 ; } if ( (*pierr = fprintf(fp, " %c", y[i])) < 0 ) { /* -------------------- error with fprintf() -------------------- */ break ; } } } } return(column) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to release storage for a character vector, note, should have been created using CVinit created -- 95sep22, cca ------------------------------------------------------ */ void CVfree ( char y[] ) { if ( y != NULL ) { FREE(y) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to read in a char vector return value -- number of characters read created -- 95sep22, cca ----------------------------------------- */ int CVfscanf ( FILE *fp, int size, char y[] ) { int i = 0 ; if ( fp != NULL && size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in CVfscanf" "\n fp = %p, size = %d, y = %p\n", fp, size, y) ; exit(0) ; } else { for ( i = 0 ; i < size ; i++ ) { if ( fscanf(fp, "%c", y + i) != 1 ) { break ; } } } } return(i) ; } /*--------------------------------------------------------------------*/ Utilities/src/DV.c010064400020550007177000001174570653554021600153350ustar00clevecompmath00000400000006/* DV.c */ #include "../Utilities.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to compute y[*] := y[*] + x[*] created -- 95sep22, cca ----------------------------------------- */ void DVadd ( int size, double y[], double x[] ) { if ( size <= 0 ) { return ; } else if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in DVadd" "\n invalid input, size = %d, y = %p, x = %p\n", size, y, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] += x[i] ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to compute y[*] := y[*] + alpha * x[*] created -- 95sep22, cca ------------------------------------------------- */ void DVaxpy ( int size, double y[], double alpha, double x[] ) { if ( size < 0 || alpha == 0.0 ) { return ; } else if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in DVaxpy" "\n invalid input, size = %d, y = %p, alpha = %f, x = %p\n", size, y, alpha, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] += alpha * x[i] ; } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to compute y[index[*]] := y[index[*]] + alpha * x[*] created -- 95sep22, cca --------------------------------------------------------------- */ void DVaxpyi ( int size, double y[], int index[], double alpha, double x[] ) { if ( size <= 0 || alpha == 0.0 ) { return ; } else if ( y == NULL || index == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in DVaxpyi, invalid input" "\n size = %d, y = %p, index = %p, alpha = %f, x = %p", size, y, index, alpha, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] += alpha * x[i] ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------- purpose -- to copy y[*] := x[*] created -- 95sep22, cca ------------------------------- */ void DVcopy ( int size, double y[], double x[] ) { if ( size <= 0 ) { return ; } else if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in DVcopy, invalid input" "\n size = %d, y = %p, x = %p\n", size, y, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = x[i] ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- given the pair of arrays (x1[],y1[]), create a pair of arrays (x2[],y2[]) whose entries are pairwise chosen from (x1[],y1[]) and whose distribution is an approximation. return value -- the size of the (x2[],y2[]) arrays created -- 95sep22, cca ------------------------------------------------------- */ int DVcompress ( int size1, double x1[], double y1[], int size2, double x2[], double y2[] ) { double delta, dx, dy, path, totalPath ; double *ds ; int i, j ; /* -------------------- check the input data -------------------- */ if ( size1 <= 0 || size2 <= 0 ) { return(0) ; } else if ( x1 == NULL || y1 == NULL || x2 == NULL || y2 == NULL ) { fprintf(stderr, "\n fatal error in DVcompress, invalid data" "\n size1 = %d, x1 = %p, y1 = %p" "\n size2 = %d, x2 = %p, y2 = %p", size1, x1, y1, size2, x2, y2) ; exit(-1) ; } /* ---------------------------------------- compute the path length and its segments ---------------------------------------- */ ds = DVinit(size1, 0.0) ; for ( j = 1 ; j < size1 ; j++ ) { dx = x1[j] - x1[j-1] ; dy = y1[j] - y1[j-1] ; ds[j-1] = sqrt(dx*dx + dy*dy) ; } totalPath = DVsum(size1, ds) ; delta = totalPath / (size2-2) ; #if MYDEBUG > 0 fprintf(stdout, "\n totalPath = %12.4e, delta = %12.4e, ds", totalPath, delta) ; DVfprintf(stdout, size1, ds) ; #endif /* --------------------- fill the second array --------------------- */ i = 0 ; x2[i] = x1[i] ; y2[i] = y1[i] ; i++ ; path = 0. ; for ( j = 1 ; j < size1 - 1 ; j++ ) { path += ds[j-1] ; #if MYDEBUG > 0 fprintf(stdout, "\n j %d, path %12.4e", j, path) ; #endif if ( path >= delta ) { #if MYDEBUG > 0 fprintf(stdout, ", accepted") ; #endif x2[i] = x1[j] ; y2[i] = y1[j] ; i++ ; path = 0. ; } } x2[i] = x1[size1-1] ; y2[i] = y1[size1-1] ; i++ ; /* ------------------------ free the working storage ------------------------ */ DVfree(ds) ; return(i) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy sum{y[*] * x[*]} created -- 95sep22, cca ----------------------------------- */ double DVdot ( int size, double y[], double x[] ) { double sum = 0.0 ; if ( size > 0 ) { if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in DVdot, invalid data" "\n size = %d, y = %p, x = %p\n", size, y, x) ; exit(-1) ; } else { int i ; for ( i = 0, sum = 0. ; i < size ; i++ ) { sum += y[i] * x[i] ; } } } return(sum) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to perform a indexed dot product sum = sum_k y[index[k]]*x[k] where y and x are real created -- 98may02, cca -------------------------------------------- */ double DVdoti ( int size, double y[], int index[], double x[] ) { double sum ; int ii ; if ( size < 0 || y == NULL || index == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in DVdoti(%d,%p,%p,%p)" "\n bad input\n", size, y, index, x) ; exit(-1) ; } for ( ii = 0, sum = 0.0 ; ii < size ; ii++ ) { sum += y[index[ii]] * x[ii] ; } return(sum) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to fill a double vector with a value created -- 95sep22, cca ----------------------------------------------- */ void DVfill ( int size, double y[], double dval ) { if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVfill, invalid data" "\n size = %d, y = %p, dval = %f\n", size, y, dval) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = dval ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to print out a double vector created -- 95sep22, cca ----------------------------------------- */ void DVfprintf ( FILE *fp, int size, double y[] ) { if ( fp != NULL && size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVfprintf, invalid input" "\n fp = %p, size = %d, y = %p\n", fp, size, y) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { if ( i % 6 == 0 ) fprintf(fp, "\n ") ; fprintf(fp, "%12.4e", y[i]) ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to free storage taken by a double vector. note : y[] must have been returned by DVinit. created -- 95sep22, cca ----------------------------------------------------------- */ void DVfree ( double y[] ) { if ( y != NULL ) { FREE(y) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to read in a double vector return value -- # of entries read created -- 95sep22, cca -------------------------------------------- */ int DVfscanf ( FILE *fp, int size, double y[] ) { int i = 0, rc ; if ( fp != NULL && size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVfscanf, invalid input" "\n fp = %p, size = %d, y = %p\n", fp, size, y) ; exit(-1) ; } for ( i = 0 ; i < size ; i++ ) { if ( fscanf(fp, " %le", y + i) != 1 ) { break ; } } } return(i) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- to gather y[*] = x[index[*]] created -- 95sep22, cca --------------------------------------- */ void DVgather ( int size, double y[], double x[], int index[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in DVgather, invalid input" "\n size = %d, y = %p, x = %p, index = %p\n", size, y, x, index) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = x[index[i]] ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- to gather add y[*] += x[index[*]] and zero x[index[*]] created -- 95sep22, cca ----------------------------------------------------------------- */ void DVgatherAddZero ( int size, double y[], double x[], int index[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in DVgatherAddZero, invalid input" "\n size = %d, y = %p, x = %p, index = %p\n", size, y, x, index) ; exit(-1) ; } else { int i, j ; for ( i = 0 ; i < size ; i++ ) { j = index[i] ; y[i] += x[j] ; x[j] = 0.0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to gather y[*] = x[index[*]] and zero x[*] created -- 95sep22, cca ----------------------------------------------------- */ void DVgatherZero ( int size, double y[], double x[], int index[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in DVgatherZero, invalid input" "\n size = %d, y = %p, x = %p, index = %p\n", size, y, x, index) ; exit(-1) ; } else { int i, j ; for ( i = 0 ; i < size ; i++ ) { j = index[i] ; y[i] = x[j] ; x[j] = 0.0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- allocate a double array with size entries and fill with value dval return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------------- */ double * DVinit ( int size, double dval ) { double *y = NULL ; if ( size > 0 ) { y = DVinit2(size) ; DVfill(size, y, dval) ; } return(y) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- allocate a double array with size entries return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------------- */ double * DVinit2 ( int size ) { double *y = NULL ; if ( size > 0 ) { ALLOCATE(y, double, size) ; } return(y) ; } /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[index[*]] := y[*] created -- 95sep22, cca ------------------------------ */ void DVinvPerm ( int size, double y[], int index[] ) { if ( size > 0 ) { if ( y == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in DVinvPerm, invalid data" "\n size = %d, y = %p, index = %p", size, y, index) ; exit(-1) ; } else { double *x ; int i ; x = DVinit2(size) ; DVcopy(size, x, y) ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] = x[i] ; } DVfree(x) ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to return the first entry of maximum value, *ploc contains its index created -- 95sep22, cca ------------------------------------------------------ */ double DVmax ( int size, double y[], int *ploc ) { double maxval = 0.0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVmax, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i ; maxval = y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { if ( maxval < y[i] ) { maxval = y[i] ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(maxval) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of maximum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ double DVmaxabs ( int size, double y[], int *ploc ) { double maxval = 0.0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVmaxabs, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i ; double val ; maxval = (y[0] >= 0.0) ? y[0] : -y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { val = (y[i] >= 0.0) ? y[i] : -y[i] ; if ( maxval < val ) { maxval = val ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(maxval) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to return the first entry of minimum value, *ploc contains its index created -- 95sep22, cca ------------------------------------------------------ */ double DVmin ( int size, double y[], int *ploc ) { double minval = 0.0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVmin, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i ; minval = y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { if ( minval > y[i] ) { minval = y[i] ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(minval) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of minimum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ double DVminabs ( int size, double y[], int *ploc ) { double minval = 0.0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVminabs, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i ; double val ; minval = (y[0] >= 0.0) ? y[0] : -y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { val = (y[i] >= 0.0) ? y[i] : -y[i] ; if ( minval > val ) { minval = val ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(minval) ; } /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[*] := y[index[*]] created -- 95sep22, cca ------------------------------ */ void DVperm ( int size, double y[], int index[] ) { if ( size > 0 ) { if ( y == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in DVperm, invalid data" "\n size = %d, y = %p, index = %p\n", size, y, index) ; exit(-1) ; } else { double *x ; int i ; x = DVinit2(size) ; DVcopy(size, x, y) ; for ( i = 0 ; i < size ; i++ ) { y[i] = x[index[i]] ; } DVfree(x) ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to fill a double vector with a ramp function created -- 95sep22, cca ------------------------------------------------------- */ void DVramp ( int size, double y[], double start, double inc ) { if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVramp, invalid input" "\n size = %d, y = %p, start = %f, inc = %f\n", size, y, start, inc) ; exit(-1) ; } else { int i ; double val ; for ( i = 0, val = start ; i < size ; i++, val += inc ) { y[i] = val ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to compute y[*] := y[*] - x[*] created -- 95sep22, cca ----------------------------------------- */ void DVsub ( int size, double y[], double x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in DVsub, invalid input" "\n size = %d, y = %p, x = %p", size, y, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] -= x[i] ; } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to scale a double vector by alpha created -- 95sep22, cca -------------------------------------------- */ void DVscale ( int size, double y[], double alpha ) { if ( size > 0 && alpha != 1.0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVscale, invalid data" "\n size = %d, y = %p, alpha = %f\n", size, y, alpha) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] *= alpha ; } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to scatter y[index[*]] = x[*] created -- 95sep22, cca ---------------------------------------- */ void DVscatter ( int size, double y[], int index[], double x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in DVscatter, invalid data" "\n size = %d, y = %p, index = %p, x = %p\n", size, y, index, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] = x[i] ; } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to scatter add y[index[*]] += x[*] created -- 96aug17, cca --------------------------------------------- */ void DVscatterAdd ( int size, double y[], int index[], double x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in DVscatterAdd, invalid data" "\n size = %d, y = %p, index = %p, x = %p\n", size, y, index, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] += x[i] ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to scatter add y[index[*]] += x[*] and zero x[*] created -- 95sep22, cca ----------------------------------------------------------- */ void DVscatterAddZero ( int size, double y[], int index[], double x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in DVscatterAddZero, invalid data" "\n size = %d, y = %p, index = %p, x = %p\n", size, y, index, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] += x[i] ; x[i] = 0.0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to scatter y[index[*]] = x[*] and zero x[*] created -- 95sep22, cca ----------------------------------------------------- */ void DVscatterZero ( int size, double y[], int index[], double x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in DVscatterZero, invalid data" "\n size = %d, y = %p, index = %p, x = %p\n", size, y, index, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] = x[i] ; x[i] = 0.0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to return the sum of a double vector created -- 95sep22, cca ----------------------------------------------- */ double DVsum ( int size, double y[] ) { double sum = 0.0 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVsum, invalid data" "\n size = %d, y = %p\n", size, y) ; exit(-1) ; } else { int i ; for ( i = 0, sum = 0. ; i < size ; i++ ) { sum += y[i] ; } } } return(sum) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to return the sum of the absolute values of the entries in a double vector created -- 95sep22, cca --------------------------------------------------- */ double DVsumabs ( int size, double y[] ) { double sum = 0.0 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVsumabs, invalid data" "\n size = %d, y = %p\n", size, y) ; exit(-1) ; } else { int i ; for ( i = 0, sum = 0. ; i < size ; i++ ) { sum += ((y[i] >= 0.0) ? y[i] : -y[i]) ; } } } return(sum) ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- to swap y[*] and x[*] created -- 95sep22, cca -------------------------------- */ void DVswap ( int size, double y[], double x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in DVswap, invalid data" "\n size = %d, y = %p, x = %p", size, y, x) ; exit(-1) ; } else { double temp ; int i ; for ( i = 0 ; i < size ; i++ ) { temp = x[i] ; x[i] = y[i] ; y[i] = temp ; } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- purpose -- to zero a double vector created -- 95sep22, cca ---------------------------------- */ void DVzero ( int size, double y[] ) { if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVzero, invalid data" "\n size = %d, y = %p\n", size, y) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = 0. ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to permute an integer vector, procedure uses the Drand object input -- size -- size of the vector y -- vector to be permuted seed -- seed for the random number generator if seed <= 0, simple return created -- 95sep22, cca ------------------------------------------------- */ void DVshuffle ( int size, double y[], int seed ) { if ( size > 0 || seed <= 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in DVshuffle, invalid data" "\n size = %d, y = %p, seed = %d\n", size, y, seed) ; exit(-1) ; } else { Drand drand ; double temp ; int i, j ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; for ( i = 0 ; i < size ; i++ ) { j = (int) (size * Drand_value(&drand)) ; temp = y[i] ; y[i] = y[j] ; y[j] = temp ; } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to scale a double vector by a 2x2 matrix [ x ] := [ a b ] [ x ] [ y ] [ c d ] [ y ] created -- 98jan23, cca --------------------------------------------------- */ void DVscale2 ( int size, double x[], double y[], double a, double b, double c, double d ) { double xi, yi ; int ii ; if ( size < 0 || x == NULL || y == NULL ) { fprintf(stderr, "\n fatal error in DVscale2(%d,%p,%p,...)" "\n bad input\n", size, x, y) ; exit(-1) ; } for ( ii = 0 ; ii < size ; ii++ ) { xi = x[ii] ; yi = y[ii] ; x[ii] = a*xi + b*yi ; y[ii] = c*xi + d*yi ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to perform a axpy with two vectors z := z + a*x + b*y where y and x are double vectors created -- 98jan23, cca -------------------------------------------- */ void DVaxpy2 ( int size, double z[], double a, double x[], double b, double y[] ) { double xi, yi ; int ii ; if ( size < 0 || y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in DVaxpy2()" "\n bad input\n") ; exit(-1) ; } for ( ii = 0 ; ii < size ; ii++ ) { xi = x[ii] ; yi = y[ii] ; z[ii] += a*xi + b*yi ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row0[*] * col2[*] sums[3] = row1[*] * col0[*] sums[4] = row1[*] * col1[*] sums[5] = row1[*] * col2[*] sums[6] = row2[*] * col0[*] sums[7] = row2[*] * col1[*] sums[8] = row2[*] * col2[*] created -- 98may02, cca ----------------------------------------- */ void DVdot33 ( int n, double row0[], double row1[], double row2[], double col0[], double col1[], double col2[], double sums[] ) { register double s00, s01, s02, s10, s11, s12, s20, s21, s22 ; register int i ; /* --------------- check the input --------------- */ if ( sums == NULL || row0 == NULL || row1 == NULL || row2 == NULL || col0 == NULL || col1 == NULL || col2 == NULL ) { fprintf(stderr, "\n fatal error in DVdot33(%d,%p,%p,%p,%p,%p,%p,%p)" "\n bad input\n", n, row0, row1, row2, col0, col1, col2, sums) ; exit(-1) ; } /* -------------------------- compute the 9 dot products -------------------------- */ s00 = s01 = s02 = s10 = s11 = s12 = s20 = s21 = s22 = 0.0 ; for ( i = 0 ; i < n ; i++ ) { register double r0i, r1i, r2i, c0i, c1i, c2i ; r0i = row0[i] ; r1i = row1[i] ; r2i = row2[i] ; c0i = col0[i] ; c1i = col1[i] ; c2i = col2[i] ; s00 += r0i*c0i ; s01 += r0i*c1i ; s02 += r0i*c2i ; s10 += r1i*c0i ; s11 += r1i*c1i ; s12 += r1i*c2i ; s20 += r2i*c0i ; s21 += r2i*c1i ; s22 += r2i*c2i ; } /* ---------------------- store the dot products ---------------------- */ sums[0] = s00 ; sums[1] = s01 ; sums[2] = s02 ; sums[3] = s10 ; sums[4] = s11 ; sums[5] = s12 ; sums[6] = s20 ; sums[7] = s21 ; sums[8] = s22 ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row0[*] * col2[*] sums[3] = row1[*] * col0[*] sums[4] = row1[*] * col1[*] sums[5] = row1[*] * col2[*] created -- 98may02, cca ----------------------------------------- */ void DVdot23 ( int n, double row0[], double row1[], double col0[], double col1[], double col2[], double sums[] ) { register double s00, s01, s02, s10, s11, s12 ; register int i ; /* --------------- check the input --------------- */ if ( sums == NULL || row0 == NULL || row1 == NULL || col0 == NULL || col1 == NULL || col2 == NULL ) { fprintf(stderr, "\n fatal error in DVdot23(%d,%p,%p,%p,%p,%p,%p)" "\n bad input\n", n, row0, row1, col0, col1, col2, sums) ; exit(-1) ; } /* -------------------------- compute the 6 dot products -------------------------- */ s00 = s01 = s02 = s10 = s11 = s12 = 0.0 ; for ( i = 0 ; i < n ; i++ ) { register double r0i, r1i, c0i, c1i, c2i ; r0i = row0[i] ; r1i = row1[i] ; c0i = col0[i] ; c1i = col1[i] ; c2i = col2[i] ; s00 += r0i*c0i ; s01 += r0i*c1i ; s02 += r0i*c2i ; s10 += r1i*c0i ; s11 += r1i*c1i ; s12 += r1i*c2i ; } /* ---------------------- store the dot products ---------------------- */ sums[0] = s00 ; sums[1] = s01 ; sums[2] = s02 ; sums[3] = s10 ; sums[4] = s11 ; sums[5] = s12 ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row0[*] * col2[*] created -- 98may02, cca ----------------------------------------- */ void DVdot13 ( int n, double row0[], double col0[], double col1[], double col2[], double sums[] ) { register double s00, s01, s02 ; register int i ; /* --------------- check the input --------------- */ if ( sums == NULL || row0 == NULL || col0 == NULL || col1 == NULL || col2 == NULL ) { fprintf(stderr, "\n fatal error in DVdot13(%d,%p,%p,%p,%p,%p)" "\n bad input\n", n, row0, col0, col1, col2, sums) ; exit(-1) ; } /* -------------------------- compute the 3 dot products -------------------------- */ s00 = s01 = s02 = 0.0 ; for ( i = 0 ; i < n ; i++ ) { register double r0i, c0i, c1i, c2i ; r0i = row0[i] ; c0i = col0[i] ; c1i = col1[i] ; c2i = col2[i] ; s00 += r0i*c0i ; s01 += r0i*c1i ; s02 += r0i*c2i ; } /* ---------------------- store the dot products ---------------------- */ sums[0] = s00 ; sums[1] = s01 ; sums[2] = s02 ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row1[*] * col0[*] sums[3] = row1[*] * col1[*] sums[4] = row2[*] * col0[*] sums[5] = row2[*] * col1[*] created -- 98may02, cca ----------------------------------------- */ void DVdot32 ( int n, double row0[], double row1[], double row2[], double col0[], double col1[], double sums[] ) { register double s00, s01, s10, s11, s20, s21 ; register int i ; /* --------------- check the input --------------- */ if ( sums == NULL || row0 == NULL || row1 == NULL || row2 == NULL || col0 == NULL || col1 == NULL ) { fprintf(stderr, "\n fatal error in DVdot32(%d,%p,%p,%p,%p,%p,%p)" "\n bad input\n", n, row0, row1, row2, col0, col1, sums) ; exit(-1) ; } /* -------------------------- compute the 6 dot products -------------------------- */ s00 = s01 = s10 = s11 = s20 = s21 = 0.0 ; for ( i = 0 ; i < n ; i++ ) { register double r0i, r1i, r2i, c0i, c1i ; r0i = row0[i] ; r1i = row1[i] ; r2i = row2[i] ; c0i = col0[i] ; c1i = col1[i] ; s00 += r0i*c0i ; s01 += r0i*c1i ; s10 += r1i*c0i ; s11 += r1i*c1i ; s20 += r2i*c0i ; s21 += r2i*c1i ; } /* ---------------------- store the dot products ---------------------- */ sums[0] = s00 ; sums[1] = s01 ; sums[2] = s10 ; sums[3] = s11 ; sums[4] = s20 ; sums[5] = s21 ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] sums[2] = row1[*] * col0[*] sums[3] = row1[*] * col1[*] created -- 98may02, cca ----------------------------------------- */ void DVdot22 ( int n, double row0[], double row1[], double col0[], double col1[], double sums[] ) { register double s00, s01, s10, s11 ; register int i ; /* --------------- check the input --------------- */ if ( sums == NULL || row0 == NULL || row1 == NULL || col0 == NULL || col1 == NULL ) { fprintf(stderr, "\n fatal error in DVdot22(%d,%p,%p,%p,%p,%p)" "\n bad input\n", n, row0, row1, col0, col1, sums) ; exit(-1) ; } /* -------------------------- compute the 4 dot products -------------------------- */ s00 = s01 = s10 = s11 = 0.0 ; for ( i = 0 ; i < n ; i++ ) { register double r0i, r1i, c0i, c1i ; r0i = row0[i] ; r1i = row1[i] ; c0i = col0[i] ; c1i = col1[i] ; s00 += r0i*c0i ; s01 += r0i*c1i ; s10 += r1i*c0i ; s11 += r1i*c1i ; } /* ---------------------- store the dot products ---------------------- */ sums[0] = s00 ; sums[1] = s01 ; sums[2] = s10 ; sums[3] = s11 ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row0[*] * col1[*] created -- 98may02, cca ----------------------------------------- */ void DVdot12 ( int n, double row0[], double col0[], double col1[], double sums[] ) { register double s00, s01 ; register int i ; /* --------------- check the input --------------- */ if ( sums == NULL || row0 == NULL || col0 == NULL || col1 == NULL ) { fprintf(stderr, "\n fatal error in DVdot12(%d,%p,%p,%p,%p)" "\n bad input\n", n, row0, col0, col1, sums) ; exit(-1) ; } /* -------------------------- compute the 2 dot products -------------------------- */ s00 = s01 = 0.0 ; for ( i = 0 ; i < n ; i++ ) { register double r0i, c0i, c1i ; r0i = row0[i] ; c0i = col0[i] ; c1i = col1[i] ; s00 += r0i*c0i ; s01 += r0i*c1i ; } /* ---------------------- store the dot products ---------------------- */ sums[0] = s00 ; sums[1] = s01 ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[1] = row1[*] * col0[*] sums[2] = row2[*] * col0[*] created -- 98may02, cca ----------------------------------------- */ void DVdot31 ( int n, double row0[], double row1[], double row2[], double col0[], double sums[] ) { register double s00, s10, s20 ; register int i ; /* --------------- check the input --------------- */ if ( sums == NULL || row0 == NULL || row1 == NULL || row2 == NULL || col0 == NULL ) { fprintf(stderr, "\n fatal error in DVdot31(%d,%p,%p,%p,%p,%p)" "\n bad input\n", n, row0, row1, row2, col0, sums) ; exit(-1) ; } /* -------------------------- compute the 3 dot products -------------------------- */ s00 = s10 = s20 = 0.0 ; for ( i = 0 ; i < n ; i++ ) { register double r0i, r1i, r2i, c0i ; r0i = row0[i] ; r1i = row1[i] ; r2i = row2[i] ; c0i = col0[i] ; s00 += r0i*c0i ; s10 += r1i*c0i ; s20 += r2i*c0i ; } /* ---------------------- store the dot products ---------------------- */ sums[0] = s00 ; sums[1] = s10 ; sums[2] = s20 ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute a multiple dot product sums[0] = row0[*] * col0[*] sums[2] = row1[*] * col0[*] created -- 98may02, cca ----------------------------------------- */ void DVdot21 ( int n, double row0[], double row1[], double col0[], double sums[] ) { register double s00, s10 ; register int i ; /* --------------- check the input --------------- */ if ( sums == NULL || row0 == NULL || row1 == NULL || col0 == NULL ) { fprintf(stderr, "\n fatal error in DVdot21(%d,%p,%p,%p,%p)" "\n bad input\n", n, row0, row1, col0, sums) ; exit(-1) ; } /* -------------------------- compute the 2 dot products -------------------------- */ s00 = s10 = 0.0 ; for ( i = 0 ; i < n ; i++ ) { register double r0i, r1i, c0i ; r0i = row0[i] ; r1i = row1[i] ; c0i = col0[i] ; s00 += r0i*c0i ; s10 += r1i*c0i ; } /* ---------------------- store the dot products ---------------------- */ sums[0] = s00 ; sums[1] = s10 ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- compute a single dot product sums[0] = row0[*] * col0[*] created -- 98may02, cca ----------------------------------------- */ void DVdot11 ( int n, double row0[], double col0[], double sums[] ) { register double s00 ; register int i ; /* --------------- check the input --------------- */ if ( sums == NULL || row0 == NULL || col0 == NULL ) { fprintf(stderr, "\n fatal error in DVdot11(%d,%p,%p,%p)" "\n bad input\n", n, row0, col0, sums) ; exit(-1) ; } /* ------------------------- compute the 1 dot product ------------------------- */ s00 = 0.0 ; for ( i = 0 ; i < n ; i++ ) { register double r0i, c0i ; r0i = row0[i] ; c0i = col0[i] ; s00 += r0i*c0i ; } /* ---------------------- store the dot products ---------------------- */ sums[0] = s00 ; return ; } /*--------------------------------------------------------------------*/ double col1[], double col2[], double sums[] ) { register double s00, s01, s02, s10, s11, s12 ; register int i ; /* --------------- check the input --------------- */ if ( sums =Utilities/src/FV.c010064400020550007177000000611130653410575100153220ustar00clevecompmath00000400000006/* FV.c */ #include "../Utilities.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to compute y[*] := y[*] + x[*] created -- 95sep22, cca ----------------------------------------- */ void FVadd ( int size, float y[], float x[] ) { if ( size <= 0 ) { return ; } else if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in FVadd" "\n invalid input, size = %d, y = %p, x = %p\n", size, y, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] += x[i] ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to compute y[*] := y[*] + alpha * x[*] created -- 95sep22, cca ------------------------------------------------- */ void FVaxpy ( int size, float y[], float alpha, float x[] ) { if ( size < 0 || alpha == 0.0 ) { return ; } else if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in FVaxpy" "\n invalid input, size = %d, y = %p, alpha = %f, x = %p\n", size, y, alpha, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] += alpha * x[i] ; } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to compute y[index[*]] := y[index[*]] + alpha * x[*] created -- 95sep22, cca --------------------------------------------------------------- */ void FVaxpyi ( int size, float y[], int index[], float alpha, float x[] ) { if ( size <= 0 || alpha == 0.0 ) { return ; } else if ( y == NULL || index == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in FVaxpyi, invalid input" "\n size = %d, y = %p, index = %p, alpha = %f, x = %p", size, y, index, alpha, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] += alpha * x[i] ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------- purpose -- to copy y[*] := x[*] created -- 95sep22, cca ------------------------------- */ void FVcopy ( int size, float y[], float x[] ) { if ( size <= 0 ) { return ; } else if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in FVcopy, invalid input" "\n size = %d, y = %p, x = %p\n", size, y, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = x[i] ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- given the pair of arrays (x1[],y1[]), create a pair of arrays (x2[],y2[]) whose entries are pairwise chosen from (x1[],y1[]) and whose distribution is an approximation. return value -- the size of the (x2[],y2[]) arrays created -- 95sep22, cca ------------------------------------------------------- */ int FVcompress ( int size1, float x1[], float y1[], int size2, float x2[], float y2[] ) { float delta, dx, dy, path, totalPath ; float *ds ; int i, j ; /* -------------------- check the input data -------------------- */ if ( size1 <= 0 || size2 <= 0 ) { return(0) ; } else if ( x1 == NULL || y1 == NULL || x2 == NULL || y2 == NULL ) { fprintf(stderr, "\n fatal error in FVcompress, invalid data" "\n size1 = %d, x1 = %p, y1 = %p" "\n size2 = %d, x2 = %p, y2 = %p", size1, x1, y1, size2, x2, y2) ; exit(-1) ; } /* ---------------------------------------- compute the path length and its segments ---------------------------------------- */ ds = FVinit(size1, 0.0) ; for ( j = 1 ; j < size1 ; j++ ) { dx = x1[j] - x1[j-1] ; dy = y1[j] - y1[j-1] ; ds[j-1] = sqrt(dx*dx + dy*dy) ; } totalPath = FVsum(size1, ds) ; delta = totalPath / (size2-2) ; #if MYDEBUG > 0 fprintf(stdout, "\n totalPath = %12.4e, delta = %12.4e, ds", totalPath, delta) ; FVfprintf(stdout, size1, ds) ; #endif /* --------------------- fill the second array --------------------- */ i = 0 ; x2[i] = x1[i] ; y2[i] = y1[i] ; i++ ; path = 0. ; for ( j = 1 ; j < size1 - 1 ; j++ ) { path += ds[j-1] ; #if MYDEBUG > 0 fprintf(stdout, "\n j %d, path %12.4e", j, path) ; #endif if ( path >= delta ) { #if MYDEBUG > 0 fprintf(stdout, ", accepted") ; #endif x2[i] = x1[j] ; y2[i] = y1[j] ; i++ ; path = 0. ; } } x2[i] = x1[size1-1] ; y2[i] = y1[size1-1] ; i++ ; /* ------------------------ free the working storage ------------------------ */ FVfree(ds) ; return(i) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy sum{y[*] * x[*]} created -- 95sep22, cca ----------------------------------- */ float FVdot ( int size, float y[], float x[] ) { float sum = 0.0 ; if ( size > 0 ) { if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in FVdot, invalid data" "\n size = %d, y = %p, x = %p\n", size, y, x) ; exit(-1) ; } else { int i ; for ( i = 0, sum = 0. ; i < size ; i++ ) { sum += y[i] * x[i] ; } } } return(sum) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to fill a float vector with a value created -- 95sep22, cca ----------------------------------------------- */ void FVfill ( int size, float y[], float dval ) { if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVfill, invalid data" "\n size = %d, y = %p, dval = %f\n", size, y, dval) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = dval ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to print out a float vector created -- 95sep22, cca ----------------------------------------- */ void FVfprintf ( FILE *fp, int size, float y[] ) { if ( fp != NULL && size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVfprintf, invalid input" "\n fp = %p, size = %d, y = %p\n", fp, size, y) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { if ( i % 6 == 0 ) fprintf(fp, "\n ") ; fprintf(fp, "%12.4e", y[i]) ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to free storage taken by a float vector. note : y[] must have been returned by FVinit. created -- 95sep22, cca ----------------------------------------------------------- */ void FVfree ( float y[] ) { if ( y != NULL ) { FREE(y) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to read in a float vector return value -- # of entries read created -- 95sep22, cca -------------------------------------------- */ int FVfscanf ( FILE *fp, int size, float y[] ) { int i = 0, rc ; if ( fp != NULL && size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVfscanf, invalid input" "\n fp = %p, size = %d, y = %p\n", fp, size, y) ; exit(-1) ; } else { for ( i = 0 ; i < size ; i++ ) { if ( (rc = fscanf(fp, " %f", y + i)) != 1 ) { fprintf(stderr, "\n fatal error in FVfscanf(%p,%d,%p), rc = %d", fp, size, y, rc) ; break ; } } } } return(i) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- to gather y[*] = x[index[*]] created -- 95sep22, cca --------------------------------------- */ void FVgather ( int size, float y[], float x[], int index[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in FVgather, invalid input" "\n size = %d, y = %p, x = %p, index = %p\n", size, y, x, index) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = x[index[i]] ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- purpose -- to gather add y[*] += x[index[*]] and zero x[index[*]] created -- 95sep22, cca ----------------------------------------------------------------- */ void FVgatherAddZero ( int size, float y[], float x[], int index[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in FVgatherAddZero, invalid input" "\n size = %d, y = %p, x = %p, index = %p\n", size, y, x, index) ; exit(-1) ; } else { int i, j ; for ( i = 0 ; i < size ; i++ ) { j = index[i] ; y[i] += x[j] ; x[j] = 0.0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to gather y[*] = x[index[*]] and zero x[*] created -- 95sep22, cca ----------------------------------------------------- */ void FVgatherZero ( int size, float y[], float x[], int index[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in FVgatherZero, invalid input" "\n size = %d, y = %p, x = %p, index = %p\n", size, y, x, index) ; exit(-1) ; } else { int i, j ; for ( i = 0 ; i < size ; i++ ) { j = index[i] ; y[i] = x[j] ; x[j] = 0.0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- allocate a float array with size entries and fill with value dval return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------------- */ float * FVinit ( int size, float dval ) { float *y = NULL ; if ( size > 0 ) { y = FVinit2(size) ; FVfill(size, y, dval) ; } return(y) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- allocate a float array with size entries return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------------- */ float * FVinit2 ( int size ) { float *y = NULL ; if ( size > 0 ) { ALLOCATE(y, float, size) ; } return(y) ; } /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[index[*]] := y[*] created -- 95sep22, cca ------------------------------ */ void FVinvPerm ( int size, float y[], int index[] ) { if ( size > 0 ) { if ( y == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in FVinvPerm, invalid data" "\n size = %d, y = %p, index = %p", size, y, index) ; exit(-1) ; } else { float *x ; int i ; x = FVinit2(size) ; FVcopy(size, x, y) ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] = x[i] ; } FVfree(x) ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to return the first entry of maximum value, *ploc contains its index created -- 95sep22, cca ------------------------------------------------------ */ float FVmax ( int size, float y[], int *ploc ) { float maxval = 0.0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVmax, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i ; maxval = y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { if ( maxval < y[i] ) { maxval = y[i] ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(maxval) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of maximum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ float FVmaxabs ( int size, float y[], int *ploc ) { float maxval = 0.0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVmaxabs, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i ; float val ; maxval = (y[0] >= 0.0) ? y[0] : -y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { val = (y[i] >= 0.0) ? y[i] : -y[i] ; if ( maxval < val ) { maxval = val ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(maxval) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to return the first entry of minimum value, *ploc contains its index created -- 95sep22, cca ------------------------------------------------------ */ float FVmin ( int size, float y[], int *ploc ) { float minval = 0.0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVmin, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i ; minval = y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { if ( minval > y[i] ) { minval = y[i] ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(minval) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of minimum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ float FVminabs ( int size, float y[], int *ploc ) { float minval = 0.0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVminabs, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i ; float val ; minval = (y[0] >= 0.0) ? y[0] : -y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { val = (y[i] >= 0.0) ? y[i] : -y[i] ; if ( minval > val ) { minval = val ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(minval) ; } /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[*] := y[index[*]] created -- 95sep22, cca ------------------------------ */ void FVperm ( int size, float y[], int index[] ) { if ( size > 0 ) { if ( y == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in FVperm, invalid data" "\n size = %d, y = %p, index = %p\n", size, y, index) ; exit(-1) ; } else { float *x ; int i ; x = FVinit2(size) ; FVcopy(size, x, y) ; for ( i = 0 ; i < size ; i++ ) { y[i] = x[index[i]] ; } FVfree(x) ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to fill a float vector with a ramp function created -- 95sep22, cca ------------------------------------------------------- */ void FVramp ( int size, float y[], float start, float inc ) { if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVramp, invalid input" "\n size = %d, y = %p, start = %f, inc = %f\n", size, y, start, inc) ; exit(-1) ; } else { int i ; float val ; for ( i = 0, val = start ; i < size ; i++, val += inc ) { y[i] = val ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- purpose -- to compute y[*] := y[*] - x[*] created -- 95sep22, cca ----------------------------------------- */ void FVsub ( int size, float y[], float x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in FVsub, invalid input" "\n size = %d, y = %p, x = %p", size, y, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] -= x[i] ; } } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to scale a float vector by alpha created -- 95sep22, cca -------------------------------------------- */ void FVscale ( int size, float y[], float alpha ) { if ( size > 0 && alpha != 1.0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVscale, invalid data" "\n size = %d, y = %p, alpha = %f\n", size, y, alpha) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] *= alpha ; } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to scatter y[index[*]] = x[*] created -- 95sep22, cca ---------------------------------------- */ void FVscatter ( int size, float y[], int index[], float x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in FVscatter, invalid data" "\n size = %d, y = %p, index = %p, x = %p\n", size, y, index, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] = x[i] ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- purpose -- to scatter add y[index[*]] += x[*] and zero x[*] created -- 95sep22, cca ----------------------------------------------------------- */ void FVscatterAddZero ( int size, float y[], int index[], float x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in FVscatterAddZero, invalid data" "\n size = %d, y = %p, index = %p, x = %p\n", size, y, index, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] += x[i] ; x[i] = 0.0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to scatter y[index[*]] = x[*] and zero x[*] created -- 95sep22, cca ----------------------------------------------------- */ void FVscatterZero ( int size, float y[], int index[], float x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in FVscatterZero, invalid data" "\n size = %d, y = %p, index = %p, x = %p\n", size, y, index, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] = x[i] ; x[i] = 0.0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to return the sum of a float vector created -- 95sep22, cca ----------------------------------------------- */ float FVsum ( int size, float y[] ) { float sum = 0.0 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVsum, invalid data" "\n size = %d, y = %p\n", size, y) ; exit(-1) ; } else { int i ; for ( i = 0, sum = 0. ; i < size ; i++ ) { sum += y[i] ; } } } return(sum) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to return the sum of the absolute values of the entries in a float vector created -- 95sep22, cca --------------------------------------------------- */ float FVsumabs ( int size, float y[] ) { float sum = 0.0 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVsumabs, invalid data" "\n size = %d, y = %p\n", size, y) ; exit(-1) ; } else { int i ; for ( i = 0, sum = 0. ; i < size ; i++ ) { sum += ((y[i] >= 0.0) ? y[i] : -y[i]) ; } } } return(sum) ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- to swap y[*] and x[*] created -- 95sep22, cca -------------------------------- */ void FVswap ( int size, float y[], float x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in FVswap, invalid data" "\n size = %d, y = %p, x = %p", size, y, x) ; exit(-1) ; } else { float temp ; int i ; for ( i = 0 ; i < size ; i++ ) { temp = x[i] ; x[i] = y[i] ; y[i] = temp ; } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- purpose -- to zero a float vector created -- 95sep22, cca ---------------------------------- */ void FVzero ( int size, float y[] ) { if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVzero, invalid data" "\n size = %d, y = %p\n", size, y) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = 0. ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to permute an integer vector, procedure uses the Drand object input -- size -- size of the vector y -- vector to be permuted seed -- seed for the random number generator if seed <= 0, simple return created -- 95sep22, cca ------------------------------------------------- */ void FVshuffle ( int size, float y[], int seed ) { if ( size > 0 || seed <= 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in FVshuffle, invalid data" "\n size = %d, y = %p, seed = %d\n", size, y, seed) ; exit(-1) ; } else { float temp ; int i, j ; Drand drand ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; for ( i = 0 ; i < size ; i++ ) { j = (int) (size * Drand_value(&drand)) ; temp = y[i] ; y[i] = y[j] ; y[j] = temp ; } } } return ; } /*--------------------------------------------------------------------*/ "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i ; minval = y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { if ( minval > y[i] ) { minval = y[i] ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(minval) ; } /*----------------------------------------------------------------Utilities/src/I2OP.c010064400020550007177000000110460653410575300155220ustar00clevecompmath00000400000006/* I2OP.c */ #include "../Utilities.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- initializer. create and return an array of n I2OP structures. the structures are linked in one of three ways. flag = 0 (I2OP_NULL) --> ip->next = NULL flag = 1 (I2OP_FORWARD) --> ip->next = successor in list flag = 2 (I2OP_BACKWARD) --> ip->next = predecessor in list created -- 98feb06, cca --------------------------------------------------------- */ I2OP * I2OP_init ( int n, int flag ) { I2OP *base ; /* --------------- check the input --------------- */ if ( n <= 0 || flag < I2OP_NULL || flag > I2OP_BACKWARD ) { fprintf(stderr, "\n fatal error in I2OP_init(%d,%d)" "\n bad input\n", n, flag) ; exit(-1) ; } /* -------------------- allocate the storage -------------------- */ ALLOCATE(base, struct _I2OP, n) ; /* ----------------------- initialize the elements ----------------------- */ I2OP_initStorage(n, flag, base) ; return(base) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- initializer. create and return an array of n I2OP structures. the structures are linked in one of three ways. flag = 0 (I2OP_NULL) --> ip->next = NULL flag = 1 (I2OP_FORWARD) --> ip->next = successor in list flag = 2 (I2OP_BACKWARD) --> ip->next = predecessor in list created -- 98feb06, cca --------------------------------------------------------- */ void I2OP_initStorage ( int n, int flag, I2OP *base ) { I2OP *elem, *firstelem, *lastelem ; /* --------------- check the input --------------- */ if ( n <= 0 || flag < I2OP_NULL || flag > I2OP_BACKWARD || base == NULL ) { fprintf(stderr, "\n fatal error in I2OP_initStorage(%d,%d,%p)" "\n bad input\n", n, flag, base) ; exit(-1) ; } #if MYDEBUG > 0 fprintf(stdout, "\n inside I2OP_initStorage(%d, %d, %p)", n, flag, base) ; #endif /* ----------------------- initialize the elements ----------------------- */ firstelem = base ; lastelem = firstelem + n - 1 ; #if MYDEBUG > 0 fprintf(stdout, "\n firstelem %p, lastelem %p", firstelem, lastelem) ; #endif switch ( flag ) { case I2OP_FORWARD : for ( elem = firstelem ; elem < lastelem ; elem++ ) { elem->value0 = elem->value1 = -1 ; elem->value2 = NULL ; elem->next = elem + 1 ; #if MYDEBUG > 0 fprintf(stdout, "\n elem %p, value0 %d, value1 %d, value2 %p, next %p", elem, elem->value0, elem->value1, elem->value2, elem->next) ; #endif } lastelem->value0 = lastelem->value1 = -1 ; lastelem->value2 = NULL ; lastelem->next = NULL ; #if MYDEBUG > 0 fprintf(stdout, "\n elem %p, value0 %d, value1 %d, value2 %p, next %p", lastelem, lastelem->value0, lastelem->value1, lastelem->value2, lastelem->next) ; #endif break ; case I2OP_BACKWARD : for ( elem = firstelem + 1 ; elem <= lastelem ; elem++ ) { elem->value0 = elem->value1 = -1 ; elem->value2 = NULL ; elem->next = elem - 1 ; } firstelem->value0 = firstelem->value1 = -1 ; firstelem->value2 = NULL ; firstelem->next = NULL ; break ; case I2OP_NULL : for ( elem = firstelem ; elem <= lastelem ; elem++ ) { elem->value0 = elem->value1 = -1 ; elem->value2 = NULL ; elem->next = NULL ; } break ; default : break ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- free the storage for an array of I2OP structures, must have been allocated by I2OP_init created -- 98feb06, cca ----------------------------------------------- */ void I2OP_free ( I2OP *ip ) { if ( ip != NULL ) { FREE(ip) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- purpose -- to print out a I2OP list created -- 98feb06, cca ---------------------------------- */ void I2OP_fprintf ( FILE *fp, I2OP *elem ) { if ( fp != NULL && elem != NULL ) { int i = 0 ; while ( elem != NULL ) { if ( i % 4 == 0 ) fprintf(fp, "\n ") ; fprintf(fp, " <%4d,%4d,%p>", elem->value0, elem->value1, elem->value2) ; elem = elem->next ; i++ ; } } return ; } /*--------------------------------------------------------------------*/ -------------------------------- */ I2OP * I2OP_init ( int n, int flag ) { I2OP *base ; /* --------------- check the input --------------- */ if ( n <= 0 || flag < I2OP_NULL || flag > I2OP_BACKWARD ) { fprintf(stderr, "\n fatal error in I2OP_init(%d,%d)" "\n bad input\n", n, flag) ; exit(-1) ; } /* -------------------- allocate the storage -------------------- */ ALLOCATE(base, struct _I2OP, n) ; /* -----------------Utilities/src/IP.c010064400020550007177000000306130653410575100153200ustar00clevecompmath00000400000006/* IP.c */ #include "../Utilities.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* --------------------------------- purpose -- to print out a IP list created -- 95sep22, cca --------------------------------- */ void IP_fprintf ( FILE *fp, IP *ip ) { if ( fp != NULL && ip != NULL ) { int i = 0 ; while ( ip != NULL ) { if ( i % 16 == 0 ) fprintf(fp, "\n ") ; fprintf(fp, " %4d", ip->val) ; ip = ip->next ; i++ ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- to write out an integer list with eighty column lines input -- fp -- file pointer, must be formatted and write access ip -- head of list column -- present column return value -- present column created -- 95sep22, cca ------------------------------------------------------------------ */ int IP_fp80 ( FILE *fp, IP *ip, int column ) { if ( fp != NULL && ip != NULL ) { int inum, nchar, pow ; while ( ip != NULL ) { inum = ip->val ; if ( inum < 0 ) { inum = -inum ; nchar = 3 ; } else { nchar = 2 ; } for ( pow = 10 ; inum >= pow ; pow *= 10 ) { nchar++ ; } if ( (column += nchar) >= 80 ) { fprintf(fp, "\n") ; column = nchar ; } fprintf(fp, " %d", ip->val) ; ip = ip->next ; } } return(column) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- initializer. create and return an array of n IP structures. the structures are linked in one of three ways. flag = 0 (IP_NULL) --> ip->next = NULL flag = 1 (IP_FORWARD) --> ip->next = successor in list flag = 2 (IP_BACKWARD) --> ip->next = predecessor in list created -- 95sep22, cca --------------------------------------------------------- */ IP * IP_init ( int n, int flag ) { IP *base = NULL ; if ( n > 0 ) { if ( flag != IP_NULL && flag != IP_FORWARD && flag != IP_BACKWARD ) { fprintf(stderr, "\n fatal error in IPinit, invalid data" "\n n = %d, flag = %d" "\n flag must be 0 (IP_NULL), 1 (IP_FORWARD) or 2(IP_BACKWARD)\n", n, flag) ; exit(-1) ; } else { int i ; IP *head, *ip, *tail ; ALLOCATE(base, struct _IP, n) ; switch ( flag ) { case IP_FORWARD : head = NULL ; for ( i = n - 1, ip = base + i ; i >= 0 ; i--, ip-- ) { ip->next = head ; ip->val = 0 ; head = ip ; } break ; case IP_BACKWARD : head = tail = base + n - 1 ; head->val = 0 ; for ( i = n - 2, ip = head + i ; i >= 0 ; i--, ip-- ) { tail->next = ip ; ip->val = 0 ; } tail->next = NULL ; break ; case IP_NULL : for ( i = 0, ip = base ; i < n ; i++, ip++ ) { ip->val = 0 ; ip->next = NULL ; } break ; } } } return(base) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- free the storage for an array of IP structures, must have been allocated by IP_init created -- 95sep22, cca ----------------------------------------------- */ void IP_free ( IP *ip ) { if ( ip != NULL ) { FREE(ip) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- merge two lists in ascending order created -- 95sep22, cca ---------------------------------- */ IP * IP_mergeUp ( IP *ip1, IP *ip2 ) { IP *head, *tail ; /* ------------------- check for NULL list ------------------- */ if ( ip1 == NULL ) { head = ip2 ; } else if ( ip2 == NULL ) { head = ip1 ; } else { /* ------------------------------------------ neither list is NULL, assign first element ------------------------------------------ */ if ( ip2->val < ip1->val ) { head = tail = ip2 ; ip2 = ip2->next ; } else { head = tail = ip1 ; ip1 = ip1->next ; } /* -------------------------------------- merge the lists until one is exhausted -------------------------------------- */ while ( ip1 != NULL && ip2 != NULL ) { if ( ip2->val < ip1->val ) { tail->next = ip2 ; tail = ip2 ; ip2 = ip2->next ; } else { tail->next = ip1 ; tail = ip1 ; ip1 = ip1->next ; } } /* ---------------------------------- add the remaining list to the tail ---------------------------------- */ if ( ip1 == NULL ) { tail->next = ip2 ; } else { tail->next = ip1 ; } } return(head) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to sort a singly linked list in ascending order using a radix sort created -- 95sep22, cca --------------------------------------------- */ IP * IP_radixSortUp ( IP *ip ) { int b1, b2, d, dneg, dpos, i, j, negmin, posmax ; IP *head, *next, *tail ; IP *poshead, *neghead, *zerohead ; IP *postail, *negtail, *zerotail ; #define BASE 10 IP *heads[BASE], *tails[BASE] ; /* -------------------------------------------------------- split the list into negative, zero and positive sublists -------------------------------------------------------- */ poshead = postail = neghead = negtail = zerohead = NULL ; zerotail = NULL ; posmax = negmin = 0 ; while ( ip != NULL ) { next = ip->next ; if ( ip->val > 0 ) { ip->next = poshead, poshead = ip ; if ( posmax < ip->val ) { posmax = ip->val ; } } else if ( ip->val < 0 ) { ip->next = neghead, neghead = ip ; if ( negmin > ip->val ) { negmin = ip->val ; } } else { if ( zerohead == NULL ) { zerotail = ip ; } ip->next = zerohead, zerohead = ip ; } ip = next ; } #if MYDEBUG > 0 fprintf(stdout, "\n positive list :") ; IP_fp80(stdout, poshead, 16) ; fprintf(stdout, "\n zero list :") ; IP_fp80(stdout, zerohead, 16) ; fprintf(stdout, "\n negative list :") ; IP_fp80(stdout, neghead, 16) ; fflush(stdout) ; #endif /* --------------- find the limits --------------- */ dpos = 0 ; while ( posmax > 0 ) { dpos++ ; posmax /= 10 ; } negmin = - negmin ; dneg = 0 ; while ( negmin > 0 ) { dneg++ ; negmin /= 10 ; } if ( dpos > dneg ) { d = dpos ; } else { d = dneg ; } #if MYDEBUG > 0 fprintf(stdout, "\n dneg %d, dpos %d, d %d", dneg, dpos, d) ; fflush(stdout) ; #endif /* ---------------------- sort the positive list ---------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n sorting the positive list") ; #endif for ( i = 0 ; i < BASE ; i++ ) { heads[i] = tails[i] = NULL ; } b1 = 1 ; for ( i = 0 ; i < dpos ; i++ ) { b2 = BASE * b1 ; ip = poshead ; poshead = NULL ; #if MYDEBUG > 0 fprintf(stdout, "\n b1 %d, b2 %d", b1, b2) ; #endif while ( ip != NULL ) { next = ip->next ; j = (ip->val % b2) / b1 ; #if MYDEBUG > 0 fprintf(stdout, "\n ip->val %d, j %d", ip->val, j) ; #endif if ( heads[j] == NULL ) { heads[j] = ip ; } else { tails[j]->next = ip ; } tails[j] = ip ; ip = next ; } for ( j = 0 ; j < BASE ; j++ ) { if ( heads[j] != NULL ) { if ( poshead == NULL ) { poshead = heads[j] ; } else { postail->next = heads[j] ; } postail = tails[j] ; heads[j] = tails[j] = NULL ; } } postail->next = NULL ; b1 = b2 ; } #if MYDEBUG > 0 fprintf(stdout, "\n positive list") ; IP_fprintf(stdout, poshead) ; #endif /* ---------------------- sort the negative list ---------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n sorting the negative list") ; #endif b1 = 1 ; for ( i = 0 ; i < dneg ; i++ ) { b2 = BASE * b1 ; #if MYDEBUG > 0 fprintf(stdout, "\n b1 %d, b2 %d", b1, b2) ; #endif ip = neghead ; neghead = NULL ; while ( ip != NULL ) { next = ip->next ; j = ((-ip->val) % b2) / b1 ; #if MYDEBUG > 0 fprintf(stdout, "\n ip->val %d, j %d", ip->val, j) ; #endif if ( heads[j] == NULL ) { heads[j] = ip ; } else { tails[j]->next = ip ; } tails[j] = ip ; ip = next ; } for ( j = 0 ; j < BASE ; j++ ) { if ( heads[j] != NULL ) { if ( neghead == NULL ) { neghead = heads[j] ; } else { negtail->next = heads[j] ; } negtail = tails[j] ; heads[j] = tails[j] = NULL ; } } negtail->next = NULL ; b1 = b2 ; } #if MYDEBUG > 0 fprintf(stdout, "\n negative list") ; IP_fprintf(stdout, neghead) ; #endif /* --------------------------- concatenate the three lists --------------------------- */ head = tail = ip = neghead ; while ( ip != NULL ) { next = ip->next ; ip->next = head ; head = ip ; ip = next ; } if ( tail != NULL ) { tail->next = NULL ; } #if MYDEBUG > 0 fprintf(stdout, "\n 1. head = %p, tail = %p", head, tail) ; #endif if ( zerohead != NULL ) { if ( tail != NULL ) { tail->next = zerohead ; } else { head = zerohead ; } tail = zerotail ; } if ( tail != NULL ) { tail->next = NULL ; } #if MYDEBUG > 0 fprintf(stdout, "\n 2. head = %p, tail = %p", head, tail) ; #endif if ( poshead != NULL ) { if ( tail != NULL ) { tail->next = poshead ; } else { head = poshead ; } tail = postail ; } if ( tail != NULL ) { tail->next = NULL ; } #if MYDEBUG > 0 fprintf(stdout, "\n 3. head = %p, tail = %p", head, tail) ; IP_fprintf(stdout, head) ; #endif return(head) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to sort a singly linked list in descending order using a radix sort created -- 95sep22, cca ---------------------------------------------- */ IP * IP_radixSortDown ( IP *ip ) { IP *ip1 = NULL ; if ( ip != NULL ) { IP *ip0 ; for ( ip0 = ip ; ip0 != NULL ; ip0 = ip0->next ) { ip0->val = -ip0->val ; } ip1 = IP_radixSortUp(ip) ; for ( ip0 = ip1 ; ip0 != NULL ; ip0 = ip0->next ) { ip0->val = -ip0->val ; } } return(ip1) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- sort a list in ascending order using merge sort created -- 95sep22, cca ----------------------------------------------- */ IP * IP_mergeSortUp ( IP *ip0 ) { int i, m, m1 ; IP *ip, *ip1, *ip2, *prev ; /* ---------------------------------------- count the number of elements in the list ---------------------------------------- */ #if MYDEBUG > 0 fprintf(stdout, "\n inside IP_mergeSortUp :") ; IP_fp80(stdout, ip0, 25) ; fflush(stdout) ; #endif for ( ip = ip0, m = 0 ; ip != NULL ; ip = ip->next ) { m++ ; } if ( m <= 1 ) { return(ip0) ; } else { m1 = m / 2 ; #if MYDEBUG > 0 fprintf(stdout, "\n m = %d, m1 = %d, m2 = %d", m, m1, m-m1) ; fflush(stdout) ; #endif for ( i = 1, ip = ip0, prev = NULL ; i < m1 ; i++ ) { prev = ip ; ip = ip->next ; } ip2 = ip->next ; ip->next = NULL ; ip1 = ip0 ; #if MYDEBUG > 0 fprintf(stdout, "\n calling IP_mergeSortUp :") ; IP_fp80(stdout, ip1, 13) ; fflush(stdout) ; #endif ip1 = IP_mergeSortUp(ip1) ; #if MYDEBUG > 0 fprintf(stdout, "\n return from IP_mergeSortUp :") ; IP_fp80(stdout, ip1, 13) ; fprintf(stdout, "\n calling IPmergeSortUp :") ; IP_fp80(stdout, ip2, 13) ; #endif ip2 = IP_mergeSortUp(ip2) ; #if MYDEBUG > 0 fprintf(stdout, "\n return from IP_mergeSortUp :") ; IP_fp80(stdout, ip2, 13) ; fprintf(stdout, "\n calling IP_mergeUp :") ; fprintf(stdout, "\n first list") ; IP_fp80(stdout, ip1, 13) ; fprintf(stdout, "\n second list") ; IP_fp80(stdout, ip2, 13) ; #endif ip = IP_mergeUp(ip1, ip2) ; #if MYDEBUG > 0 fprintf(stdout, "\n return from IP_mergeUp, sorted list : ") ; IP_fp80(stdout, ip, 40) ; fflush(stdout) ; #endif return(ip) ; } } /*--------------------------------------------------------------------*/ ------------------- check for NULL list ------------------- */ if ( ip1 == NULL ) { head = ip2 ; } else ifUtilities/src/IV.c010064400020550007177000000517040656440174400153360ustar00clevecompmath00000400000006/* IV.c */ #include "../Utilities.h" #include "../../Drand.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- given the pair of arrays (x1[],y1[]), create a pair of arrays (x2[],y2[]) whose entries are pairwise chosen from (x1[],y1[]) and whose distribution is an approximation. return value -- the size of the (x2[],y2[]) arrays created -- 95sep22, cca ------------------------------------------------------- */ int IVcompress ( int size1, int x1[], int y1[], int size2, int x2[], int y2[] ) { double delta, dx, dy, path, totalPath ; double *ds ; int i, j ; /* -------------------- check the input data -------------------- */ if ( size1 <= 0 || size2 <= 0 ) { return(0) ; } else if ( x1 == NULL || y1 == NULL || x2 == NULL || y2 == NULL ) { fprintf(stderr, "\n fatal error in IVcompress, invalid data" "\n size1 = %d, x1 = %p, y1 = %p" "\n size2 = %d, x2 = %p, y2 = %p\n", size1, x1, y1, size2, x2, y2) ; exit(-1) ; } /* ---------------------------------------- compute the path length and its segments ---------------------------------------- */ ds = DVinit(size1, 0.0) ; for ( j = 1 ; j < size1 ; j++ ) { dx = x1[j] - x1[j-1] ; dy = y1[j] - y1[j-1] ; ds[j-1] = sqrt((double) (dx*dx + dy*dy)) ; } totalPath = DVsum(size1, ds) ; delta = totalPath / (size2-2) ; #if MYDEBUG > 0 fprintf(stdout, "\n totalPath = %12.4e, delta = %12.4e, ds", totalPath, delta) ; DVfprintf(stdout, size1, ds) ; #endif /* --------------------- fill the second array --------------------- */ i = 0 ; x2[i] = x1[i] ; y2[i] = y1[i] ; i++ ; path = 0. ; for ( j = 1 ; j < size1 - 1 ; j++ ) { path += ds[j-1] ; #if MYDEBUG > 0 fprintf(stdout, "\n j %d, path %12.4e", j, path) ; #endif if ( path >= delta ) { #if MYDEBUG > 0 fprintf(stdout, ", accepted") ; #endif x2[i] = x1[j] ; y2[i] = y1[j] ; i++ ; path = 0. ; } } x2[i] = x1[size1-1] ; y2[i] = y1[size1-1] ; i++ ; /* ------------------------ free the working storage ------------------------ */ DVfree(ds) ; return(i) ; } /*--------------------------------------------------------------------*/ /* ------------------------------- purpose -- to copy y[*] := x[*] created -- 95sep22, cca ------------------------------- */ void IVcopy ( int size, int y[], int x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in IVcopy, invalid data" "\n size = %d, y = %p, x = %p", size, y, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = x[i] ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to fill a int vector with a value created -- 95sep22, cca ----------------------------------------------- */ void IVfill ( int size, int y[], int ival ) { if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVfill, invalid data" "\n size = %d, y = %p, ival = %d\n", size, y, ival) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = ival ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ purpose -- to print out a int vector created -- 95sep22, cca ------------------------------------ */ void IVfprintf ( FILE *fp, int size, int y[] ) { if ( fp != NULL && size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVfprintf, invalid data" "\n fp = %p, size = %d, y = %p\n", fp, size, y) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { if ( i % 16 == 0 ) fprintf(fp, "\n") ; fprintf(fp, " %4d", y[i]) ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------- purpose -- to write out an integer vector with eighty column lines input -- fp -- file pointer, must be formatted and write access size -- length of the vector y -- integer vector column -- present column pierr -- pointer to int to hold return value, should be 1 if any print was successful, if fprintf() failed, then ierr = -1 return value -- present column created -- 95sep22, cca mods -- 95sep29, cca added ierr argument to handle error returns from fprintf() ------------------------------------------------------------------- */ int IVfp80 ( FILE *fp, int size, int y[], int column, int *pierr ) { *pierr = 1 ; if ( fp != NULL && size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVfp80, invalid input" "\n fp = %p, size = %d, y = %p, column = %d\n", fp, size, y, column) ; exit(-1) ; } else { int i, inum, nchar ; for ( i = 0 ; i < size ; i++ ) { inum = y[i] ; if ( inum < 0 ) { inum = -inum ; nchar = 2 ; } else if ( inum == 0 ) { nchar = 2 ; } else { nchar = 1 ; } while ( inum > 0 ) { nchar++ ; inum /= 10 ; } if ( (column += nchar) >= 80 ) { fprintf(fp, "\n") ; column = nchar ; } if ( (*pierr = fprintf(fp, " %d", y[i])) < 0 ) { /* -------------------- error with fprintf() -------------------- */ break ; } } } } return(column) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------- purpose -- to free the storage taken by an integer vector. note : y must have been returned by IVinit created -- 95sep22, cca ---------------------------------------------------------- */ void IVfree ( int y[] ) { if ( y != NULL ) { FREE(y) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to read in an int vector created -- 95sep22, cca ----------------------------------- */ int IVfscanf ( FILE *fp, int size, int y[] ) { int i = 0 ; if ( fp != NULL && size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVfscanf, invalid data" "\n fp = %p, size = %d, y = %p\n", fp, size, y) ; exit(-1) ; } else { for ( i = 0 ; i < size ; i++ ) { if ( fscanf(fp, " %d", y + i) != 1 ) { break ; } } } } return(i) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- to gather y[*] = x[index[*]] created -- 95sep22, cca --------------------------------------- */ void IVgather ( int size, int y[], int x[], int index[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in IVgather, invalid data" "\n size = %d, y = %p, x = %p, index = %p\n", size, y, x, index) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = x[index[i]] ; } } } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- allocate a int array with size entries and fill with value ival return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------- */ int * IVinit ( int size, int ival ) { int *y = NULL ; if ( size > 0 ) { y = IVinit2(size) ; IVfill(size, y, ival) ; } return(y) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- allocate a int array with size entries return value -- a pointer to the start of the array created : 95sep22, cca --------------------------------------------------- */ int * IVinit2 ( int size ) { int *y = NULL ; if ( size > 0 ) { ALLOCATE(y, int, size) ; } return(y) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- allocate an int array and fill with the inverse of y[]. note, y[] must be a permutation vector. created : 95sep22, cca ------------------------------------------------------------- */ int * IVinverse ( int size, int y[] ) { int *x = NULL ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVinverse, invalid data" "\n size = %d, y = %p\n", size, y) ; exit(-1) ; } else { int i, j ; x = IVinit(size, -1) ; for ( i = 0 ; i < size ; i++ ) { j = y[i] ; if ( j < 0 || j >= size || x[j] != -1 ) { fprintf(stderr, "\n fatal error in IVinverse" "\n y[%d] = %d, value out-of-range or repeated", i, j) ; exit(-1) ; } x[j] = i ; } } } return(x) ; } /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[index[*]] := y[*] created -- 95sep22, cca ------------------------------ */ void IVinvPerm ( int size, int y[], int index[] ) { if ( size > 0 ) { if ( y == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in IVinvPerm, invalid data" "\n size = %d, y = %p, index = %p\n", size, y, index) ; exit(-1) ; } else { int *x ; int i ; x = IVinit2(size) ; IVcopy(size, x, y) ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] = x[i] ; } IVfree(x) ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to return the first entry of maximum size, *ploc contains its index created -- 95sep22, cca ----------------------------------------------------- */ int IVmax ( int size, int y[], int *ploc ) { int maxval = 0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVmax, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i ; maxval = y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { if ( maxval < y[i] ) { maxval = y[i] ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(maxval) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of maximum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ int IVmaxabs ( int size, int y[], int *ploc ) { int maxval = 0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVmaxabs, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i, val ; maxval = (y[0] >= 0) ? y[0] : -y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { val = (y[i] >= 0) ? y[i] : -y[i] ; if ( maxval < val ) { maxval = val ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(maxval) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to return the first entry of minimum value, *ploc contains its index created -- 95sep22, cca ------------------------------------------------------ */ int IVmin ( int size, int y[], int *ploc ) { int minval = 0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVmin, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i ; minval = y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { if ( minval > y[i] ) { minval = y[i] ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(minval) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- purpose -- to return the first entry of minimum absolute value, *ploc contains its index created -- 95sep22, cca --------------------------------------------------------------- */ int IVminabs ( int size, int y[], int *ploc ) { int minval = 0 ; int loc = -1 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVminabs, invalid data" "\n size = %d, y = %p, ploc = %p\n", size, y, ploc) ; exit(-1) ; } else { int i, val ; minval = (y[0] >= 0) ? y[0] : -y[0] ; loc = 0 ; for ( i = 1 ; i < size ; i++ ) { val = (y[i] >= 0) ? y[i] : -y[i] ; if ( minval > val ) { minval = val ; loc = i ; } } *ploc = loc ; } } *ploc = loc ; return(minval) ; } /*--------------------------------------------------------------------*/ /* ------------------------------ purpose -- to permute a vector y[*] := y[index[*]] created -- 95sep22, cca ------------------------------ */ void IVperm ( int size, int y[], int index[] ) { if ( size > 0 ) { if ( y == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in IVperm, invalid data" "\n size = %d, y = %p, index = %p\n", size, y, index) ; exit(-1) ; } else { int *x ; int i ; x = IVinit2(size) ; IVcopy(size, x, y) ; for ( i = 0 ; i < size ; i++ ) { y[i] = x[index[i]] ; } IVfree(x) ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- purpose -- to fill a int vector with a ramp function created -- 95sep22, cca ---------------------------------------------------- */ void IVramp ( int size, int y[], int start, int inc ) { if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVramp, invalid data" "\n size = %d, y = %p, start = %d, inc = %d\n", size, y, start, inc) ; exit(-1) ; } else { int i, j ; for ( i = 0, j = start ; i < size ; i++, j += inc ) { y[i] = j ; } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to scatter y[index[*]] = x[*] created -- 95sep22, cca ---------------------------------------- */ void IVscatter ( int size, int y[], int index[], int x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in IVscatter, invalid data" "\n size = %d, y = %p, index = %p, x = %p\n", size, y, index, x) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[index[i]] = x[i] ; } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose -- to return the sum of a int vector created -- 95sep22, cca ----------------------------------------------- */ int IVsum ( int size, int y[] ) { int sum = 0 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVsum, invalid data" "\n size = %d, y = %p\n", size, y) ; exit(-1) ; } else { int i ; for ( i = 0, sum = 0 ; i < size ; i++ ) { sum += y[i] ; } } } return(sum) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to return the sum of the absolute values of the entries in an int vector created -- 95sep22, cca --------------------------------------------------- */ int IVsumabs ( int size, int y[] ) { int sum = 0 ; if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVsumabs, invalid data" "\n size = %d, y = %p\n", size, y) ; exit(-1) ; } else { int i, sum ; for ( i = 0, sum = 0 ; i < size ; i++ ) { sum += ((y[i] >= 0) ? y[i] : -y[i]) ; } } } return(sum) ; } /*--------------------------------------------------------------------*/ /* -------------------------------- purpose -- to swap y[*] and x[*] created -- 95sep22, cca -------------------------------- */ void IVswap ( int size, int y[], int x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in IVswap, invalid data" "\n size = %d, y = %p, x = %p\n", size, y, x) ; exit(-1) ; } else { int i, temp ; for ( i = 0 ; i < size ; i++ ) { temp = x[i] ; x[i] = y[i] ; y[i] = temp ; } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- purpose -- to zero a int vector created -- 95sep22, cca ---------------------------------- */ void IVzero ( int size, int y[] ) { if ( size > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVzero, invalid data" "\n size = %d, y = %p\n", size, y) ; exit(-1) ; } else { int i ; for ( i = 0 ; i < size ; i++ ) { y[i] = 0 ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to permute an integer vector, procedure uses the Drand object input -- size -- size of the vector y -- vector to be permuted seed -- seed for the random number generator if seed <= 0, simple return created -- 95sep22, cca ------------------------------------------------- */ void IVshuffle ( int size, int y[], int seed ) { if ( size > 0 && seed > 0 ) { if ( y == NULL ) { fprintf(stderr, "\n fatal error in IVshuffle, invalid data" "\n size = %d, y = %p, seed = %d\n", size, y, seed) ; exit(-1) ; } else { int i, j, temp ; double value ; Drand drand ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0.0, 1.0) ; for ( i = 0 ; i < size ; i++ ) { value = Drand_value(&drand) ; j = (int) (size * value) ; temp = y[i] ; y[i] = y[j] ; y[j] = temp ; } } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ locate an instance of target in the vector ivec[size]. we assume that ivec[] is sorted in ascending order so we can use binary search to locate target. return value -- -1 -- if target not found in ivec[] loc -- where target = ivec[loc] created -- 96may27, cca ------------------------------------------------------ */ int IVlocateViaBinarySearch ( int size, int ivec[], int target ) { int left, mid, right ; if ( size <= 0 || ivec == NULL ) { return(-1) ; } left = 0 ; right = size - 1 ; if ( target < ivec[left] || ivec[right] < target ) { return(-1) ; } else if ( target == ivec[left] ) { return(left) ; } else if ( target == ivec[right] ) { return(right) ; } else { while ( right > left + 1 ) { mid = (left + right)/2 ; if ( target < ivec[mid] ) { right = mid ; } else if ( target > ivec[mid] ) { left = mid ; } else { return(mid) ; } } } return(-1) ; } /*--------------------------------------------------------------------*/ oc) ; exit(-1) ; } else { int i ; mUtilities/src/PCV.c010064400020550007177000000050070653410575200154400ustar00clevecompmath00000400000006/* PCV.c */ #include "../Utilities.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to free a pointer to char vector must have been created by PCVinit created -- 95sep22, cca -------------------------------------------- */ void PCVfree ( char **p_cvec ) { if ( p_cvec != NULL ) { FREE(p_cvec) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to allocate and initialize to NULL a vector of pointer to char created -- 95sep22, cca --------------------------------------------- */ char ** PCVinit ( int size ) { char **p_cvec = NULL ; if ( size > 0 ) { int i ; ALLOCATE(p_cvec, char *, size) ; for ( i = 0 ; i < size ; i++ ) { p_cvec[i] = NULL ; } } return(p_cvec) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to set up a pointer vector created -- 95sep22, cca ------------------------------------- */ void PCVsetup ( int length, int sizes[], char cvec[], char *p_cvec[] ) { if ( length > 0 ) { if ( sizes == NULL || cvec == NULL || p_cvec == NULL ) { fprintf(stderr, "\n fatal error in PCVsetup, invalid data" "\n length = %d, sizes = %p, cvec = %p, p_cvec = %p\n", length, sizes, cvec, p_cvec) ; exit(-1) ; } else { int j ; for ( j = 0 ; j < length ; j++ ) { if ( sizes[j] > 0 ) { p_cvec[j] = cvec ; cvec += sizes[j] ; } else { p_cvec[j] = NULL ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy a pointer vector created -- 95sep22, cca ----------------------------------- */ void PCVcopy ( int length, char *p_cvec1[], char *p_cvec2[] ) { if ( length > 0 ) { if ( p_cvec1 == NULL || p_cvec2 == NULL ) { fprintf(stdout, "\n fatal error in PCVcopy, invalid data" "\n length = %d, p_cvec1 = %p, p_cvec2 = %p\n", length, p_cvec1, p_cvec2) ; exit(-1) ; } else { int j ; for ( j = 0 ; j < length ; j++ ) { p_cvec1[j] = p_cvec2[j] ; } } } return ; } /*--------------------------------------------------------------------*/ Utilities/src/PDV.c010064400020550007177000000050430653410575200154410ustar00clevecompmath00000400000006/* PDV.c */ #include "../Utilities.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to free a pointer to double vector must have been created by PDVinit created -- 95sep22, cca --------------------------------------------- */ void PDVfree ( double **p_dvec ) { if ( p_dvec != NULL ) { FREE(p_dvec) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to allocate and initialize to NULL a vector of pointer to double created -- 95sep22, cca --------------------------------------------- */ double ** PDVinit ( int size ) { double **p_dvec = NULL ; if ( size > 0 ) { int i ; ALLOCATE(p_dvec, double *, size) ; for ( i = 0 ; i < size ; i++ ) { p_dvec[i] = NULL ; } } return(p_dvec) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to set up a pointer vector created -- 95sep22, cca ------------------------------------- */ void PDVsetup ( int length, int sizes[], double dvec[], double *p_dvec[] ) { if ( length > 0 ) { if ( sizes == NULL || dvec == NULL || p_dvec == NULL ) { fprintf(stderr, "\n fatal error in PDVsetup, invalid data" "\n length = %d, sizes = %p, dvec = %p, p_dvec = %p\n", length, sizes, dvec, p_dvec) ; exit(-1) ; } else { int j ; for ( j = 0 ; j < length ; j++ ) { if ( sizes[j] > 0 ) { p_dvec[j] = dvec ; dvec += sizes[j] ; } else { p_dvec[j] = NULL ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy a pointer vector created -- 95sep22, cca ----------------------------------- */ void PDVcopy ( int length, double *p_dvec1[], double *p_dvec2[] ) { if ( length > 0 ) { if ( p_dvec1 == NULL || p_dvec2 == NULL ) { fprintf(stdout, "\n fatal error in PDVcopy, invalid data" "\n length = %d, p_dvec1 = %p, p_dvec2 = %p\n", length, p_dvec1, p_dvec2) ; exit(-1) ; } else { int j ; for ( j = 0 ; j < length ; j++ ) { p_dvec1[j] = p_dvec2[j] ; } } } return ; } /*--------------------------------------------------------------------*/ Utilities/src/PFV.c010064400020550007177000000050240653410575200154420ustar00clevecompmath00000400000006/* PFV.c */ #include "../Utilities.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to free a pointer to float vector must have been created by PFVinit created -- 95sep22, cca -------------------------------------------- */ void PFVfree ( float **p_fvec ) { if ( p_fvec != NULL ) { FREE(p_fvec) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to allocate and initialize to NULL a vector of pointer to float created -- 95sep22, cca --------------------------------------------- */ float ** PFVinit ( int size ) { float **p_fvec = NULL ; if ( size > 0 ) { int i ; ALLOCATE(p_fvec, float *, size) ; for ( i = 0 ; i < size ; i++ ) { p_fvec[i] = NULL ; } } return(p_fvec) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to set up a pointer vector created -- 95sep22, cca ------------------------------------- */ void PFVsetup ( int length, int sizes[], float fvec[], float *p_fvec[] ) { if ( length > 0 ) { if ( sizes == NULL || fvec == NULL || p_fvec == NULL ) { fprintf(stderr, "\n fatal error in PFVsetup, invalid data" "\n length = %d, sizes = %p, fvec = %p, p_fvec = %p\n", length, sizes, fvec, p_fvec) ; exit(-1) ; } else { int j ; for ( j = 0 ; j < length ; j++ ) { if ( sizes[j] > 0 ) { p_fvec[j] = fvec ; fvec += sizes[j] ; } else { p_fvec[j] = NULL ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy a pointer vector created -- 95sep22, cca ----------------------------------- */ void PFVcopy ( int length, float *p_fvec1[], float *p_fvec2[] ) { if ( length > 0 ) { if ( p_fvec1 == NULL || p_fvec2 == NULL ) { fprintf(stdout, "\n fatal error in PFVcopy, invalid data" "\n length = %d, p_fvec1 = %p, p_fvec2 = %p\n", length, p_fvec1, p_fvec2) ; exit(-1) ; } else { int j ; for ( j = 0 ; j < length ; j++ ) { p_fvec1[j] = p_fvec2[j] ; } } } return ; } /*--------------------------------------------------------------------*/ Utilities/src/PIV.c010064400020550007177000000047720653410575200154560ustar00clevecompmath00000400000006/* PIV.c */ #include "../Utilities.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------- purpose -- to free a pointer to int vector must have been created by PIVinit created -- 95sep22, cca -------------------------------------------- */ void PIVfree ( int **p_ivec ) { if ( p_ivec != NULL ) { FREE(p_ivec) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------- purpose -- to allocate and initialize to NULL a vector of pointer to int created -- 95sep22, cca --------------------------------------------- */ int ** PIVinit ( int size ) { int **p_ivec = NULL ; if ( size > 0 ) { int i ; ALLOCATE(p_ivec, int *, size) ; for ( i = 0 ; i < size ; i++ ) { p_ivec[i] = NULL ; } } return(p_ivec) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------- purpose -- to set up a pointer vector created -- 95sep22, cca ------------------------------------- */ void PIVsetup ( int length, int sizes[], int ivec[], int *p_ivec[] ) { if ( length > 0 ) { if ( sizes == NULL || ivec == NULL || p_ivec == NULL ) { fprintf(stderr, "\n fatal error in PIVsetup, invalid data" "\n length = %d, sizes = %p, ivec = %p, p_ivec = %p\n", length, sizes, ivec, p_ivec) ; exit(-1) ; } else { int j ; for ( j = 0 ; j < length ; j++ ) { if ( sizes[j] > 0 ) { p_ivec[j] = ivec ; ivec += sizes[j] ; } else { p_ivec[j] = NULL ; } } } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- purpose -- to copy a pointer vector created -- 95sep22, cca ----------------------------------- */ void PIVcopy ( int length, int *p_ivec1[], int *p_ivec2[] ) { if ( length > 0 ) { if ( p_ivec1 == NULL || p_ivec2 == NULL ) { fprintf(stdout, "\n fatal error in PIVcopy, invalid data" "\n length = %d, p_ivec1 = %p, p_ivec2 = %p\n", length, p_ivec1, p_ivec2) ; exit(-1) ; } else { int j ; for ( j = 0 ; j < length ; j++ ) { p_ivec1[j] = p_ivec2[j] ; } } } return ; } /*--------------------------------------------------------------------*/ Utilities/src/ZV.c010064400020550007177000001203650653410575200153540ustar00clevecompmath00000400000006/* ZV.c */ #include "../Utilities.h" /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- to return the absolute value of (areal,aimag) created -- 98jan24, cca -------------------------------------------------------- */ double Zabs ( double real, double imag ) { double abs, val ; if ( real == 0.0 ) { abs = fabs(imag) ; } else if ( imag == 0.0 ) { abs = fabs(real) ; } else if ( real >= imag ) { val = imag/real ; abs = fabs(real)*sqrt(1 + val*val) ; } else { val = real/imag ; abs = fabs(imag)*sqrt(1 + val*val) ; } return(abs) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- given (areal,aimag), compute (breal,bimag) = 1/(areal,aimag), put breal into *pbreal put bimag into *pbimag created -- 98jan23, cca --------------------------------------------------- */ int Zrecip ( double areal, double aimag, double *pbreal, double *pbimag ) { double bimag, breal, fac ; if ( areal == 0.0 && aimag == 0.0 ) { return(0) ; } if ( fabs(areal) >= fabs(aimag) ) { fac = aimag/areal ; breal = 1./(areal + fac*aimag) ; bimag = -fac * breal ; } else { fac = areal/aimag ; bimag = -1./(aimag + fac*areal) ; breal = -fac * bimag ; } *pbreal = breal ; *pbimag = bimag ; return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- given [ (areal,aimag) (breal,bimag) ] [ (creal,cimag) (dreal,dimag) ] compute [ (ereal,eimag) (freal,fimag) ] [ (greal,gimag) (hreal,himag) ] where I = [ (areal,aimag) (breal,bimag) ] * [ (ereal,eimag) (freal,fimag) ] [ (creal,cimag) (dreal,dimag) ] [ (greal,gimag) (hreal,himag) ] note, any of {pereal, peimag, pfreal, pfimag, pgreal, pgimag, phreal, phimag} can be NULL. if not NULL, their value is filled. this is useful when the input matrix is symmetric or hermitian. created -- 98jan23, cca --------------------------------------------------------------------- */ int Zrecip2 ( double areal, double aimag, double breal, double bimag, double creal, double cimag, double dreal, double dimag, double *pereal, double *peimag, double *pfreal, double *pfimag, double *pgreal, double *pgimag, double *phreal, double *phimag ) { double xreal, ximag, yreal, yimag ; /* ------------------------------- step one, compute x = a*d - b*c ------------------------------- */ xreal = areal*dreal - aimag*dimag - breal*creal + bimag*cimag ; ximag = areal*dimag + aimag*dreal - breal*cimag - bimag*creal ; /* ------------------------- step two, compute y = 1/x ------------------------- */ Zrecip(xreal, ximag, &yreal, &yimag) ; /* ----------------------- step three, [ e f ] = y * [ d -b ] [ g h ] [ -c a ] ----------------------- */ if ( pereal != NULL ) { *pereal = dreal*yreal - dimag*yimag ; } if ( peimag != NULL ) { *peimag = dreal*yimag + dimag*yreal ; } if ( pfreal != NULL ) { *pfreal = -breal*yreal + bimag*yimag ; } if ( pfimag != NULL ) { *pfimag = -breal*yimag - bimag*yreal ; } if ( pgreal != NULL ) { *pgreal = -creal*yreal + cimag*yimag ; } if ( pgimag != NULL ) { *pgimag = -creal*yimag - cimag*yreal ; } if ( phreal != NULL ) { *phreal = areal*yreal - aimag*yimag ; } if ( phimag != NULL ) { *phimag = areal*yimag + aimag*yreal ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to allocate, initialize and return a complex vector x[] n -- length of the complex vector (2*n double's) x[ii] = (real, imag) for 0 <= ii < n created -- 98jan23, cca ------------------------------------------------ */ double * ZVinit ( int n, double real, double imag ) { double *x ; int ii, jj ; if ( n <= 0 ) { fprintf(stderr, "\n fatal error in ZVinit(%d,%f,%f)" "\n bad input\n", n, real, imag) ; exit(-1) ; } ALLOCATE(x, double, 2*n) ; for ( ii = jj = 0 ; ii < n ; ii++, jj += 2 ) { x[jj] = real ; x[jj+1] = imag ; } return(x) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to perform a complex dot product (*prdot,*pidot) = y^T x where y and x are complex created -- 98apr15, cca ------------------------------------------- */ void ZVdotU ( int size, double y[], double x[], double *prdot, double *pidot ) { double isum, rsum, ximag, xreal, yimag, yreal ; int ii, jj ; if ( size < 0 || y == NULL || x == NULL || prdot == NULL || pidot == NULL ) { fprintf(stderr, "\n fatal error in ZVdotU(%d,%p,%p,%p,%p)" "\n bad input\n", size, y, x, prdot, pidot) ; exit(-1) ; } isum = rsum = 0.0 ; for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { xreal = x[jj] ; ximag = x[jj+1] ; yreal = y[jj] ; yimag = y[jj+1] ; rsum += xreal*yreal - ximag*yimag ; isum += xreal*yimag + ximag*yreal ; } *prdot = rsum ; *pidot = isum ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------ purpose -- to perform a conjugated complex dot product (*prdot,*pidot) = (conjugate(y))^T x = y^H x where y and x are complex created -- 98apr15, cca ------------------------------------------------------ */ void ZVdotC ( int size, double y[], double x[], double *prdot, double *pidot ) { double isum, rsum, ximag, xreal, yimag, yreal ; int ii, jj ; if ( size < 0 || y == NULL || x == NULL || prdot == NULL || pidot == NULL ) { fprintf(stderr, "\n fatal error in ZVdotC(%d,%p,%p,%p,%p)" "\n bad input\n", size, y, x, prdot, pidot) ; exit(-1) ; } isum = rsum = 0.0 ; for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { xreal = x[jj] ; ximag = x[jj+1] ; yreal = y[jj] ; yimag = y[jj+1] ; rsum += xreal*yreal + ximag*yimag ; isum += - xreal*yimag + ximag*yreal ; } *prdot = rsum ; *pidot = isum ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to perform a indexed complex dot product (*prdot,*pidot) = sum_k y[index[k]]*x[k] where y and x are complex created -- 98apr15, cca --------------------------------------------------- */ void ZVdotiU ( int size, double y[], int index[], double x[], double *prdot, double *pidot ) { double isum, rsum, ximag, xreal, yimag, yreal ; int ii, jj ; if ( size < 0 || y == NULL || index == NULL || x == NULL || prdot == NULL || pidot == NULL ) { fprintf(stderr, "\n fatal error in ZVdotiU(%d,%p,%p,%p,%p,%p)" "\n bad input\n", size, y, index, x, prdot, pidot) ; exit(-1) ; } isum = rsum = 0.0 ; for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { /* fprintf(stdout, "\n %% ii = %d, jj = %d, kk = %d", ii, jj, index[ii]) ; fflush(stdout) ; */ xreal = x[jj] ; ximag = x[jj+1] ; yreal = y[2*index[ii]] ; yimag = y[2*index[ii]+1] ; rsum += xreal*yreal - ximag*yimag ; isum += xreal*yimag + ximag*yreal ; } *prdot = rsum ; *pidot = isum ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- purpose -- to perform a indexed conjugate complex dot product (*prdot,*pidot) = sum_k conjugate(y[index[k]])*x[k] where y and x are complex created -- 98apr15, cca ------------------------------------------------------------- */ void ZVdotiC ( int size, double y[], int index[], double x[], double *prdot, double *pidot ) { double isum, rsum, ximag, xreal, yimag, yreal ; int ii, jj ; if ( size < 0 || y == NULL || index == NULL || x == NULL || prdot == NULL || pidot == NULL ) { fprintf(stderr, "\n fatal error in ZVdotiU(%d,%p,%p,%p,%p,%p)" "\n bad input\n", size, y, index, x, prdot, pidot) ; exit(-1) ; } isum = rsum = 0.0 ; for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { xreal = x[jj] ; ximag = x[jj+1] ; yreal = y[2*index[ii]] ; yimag = y[2*index[ii]+1] ; rsum += xreal*yreal + ximag*yimag ; isum += - xreal*yimag + ximag*yreal ; } *prdot = rsum ; *pidot = isum ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------ purpose -- to perform a complex axpy y := y + (areal, aimag) * x where y and x are complex created -- 98jan22, cca ------------------------------------ */ void ZVaxpy ( int size, double y[], double areal, double aimag, double x[] ) { double ximag, xreal ; int ii, jj ; if ( size < 0 || y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in ZVaxpy(%d,%p,%f,%f,%p)" "\n bad input\n", size, y, areal, aimag, x) ; exit(-1) ; } for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { xreal = x[jj] ; ximag = x[jj+1] ; /* fprintf(stdout, "\n ii = %d, xreal = %20.12e, ximag = %20.12e", ii, xreal, ximag) ; fprintf(stdout, "\n before yreal = %20.12e, yimag = %20.12e", y[jj], y[jj+1]) ; */ y[jj] += areal*xreal - aimag*ximag ; y[jj+1] += areal*ximag + aimag*xreal ; /* fprintf(stdout, "\n after yreal = %20.12e, yimag = %20.12e", y[jj], y[jj+1]) ; */ } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to scale a double complex vector by (xreal,ximag) y := y * (areal, aimag) created -- 98jan22, cca ------------------------------------------------------------ */ void ZVscale ( int size, double y[], double areal, double aimag ) { double yimag, yreal ; int ii, jj ; if ( size < 0 || y == NULL ) { fprintf(stderr, "\n fatal error in ZVscale(%d,%p,%f,%f)" "\n bad input\n", size, y, areal, aimag) ; exit(-1) ; } for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { yreal = y[jj] ; yimag = y[jj+1] ; y[jj] = areal*yreal - aimag*yimag ; y[jj+1] = areal*yimag + aimag*yreal ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- purpose --- to print a complex vector to a file created -- 98jan23, cca ----------------------------------------------- */ void ZVfprintf ( FILE *fp, int size, double y[] ) { int ii, jj ; if ( size < 0 || y == NULL ) { fprintf(stderr, "\n fatal error in ZVfprintf(%p,%d,%p)" "\n bad input\n", fp, size, y) ; exit(-1) ; } for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { /* if ( ii % 2 == 0 ) { fprintf(fp, "\n") ; } */ fprintf(fp, "\n < %12.4e, %12.4e >", y[jj], y[jj+1]) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- return the minimum absolute value of the entries in a complex vector created -- 98jan23, cca ---------------------------------- */ double ZVminabs ( int size, double x[] ) { double abs, imag, minabs, real, val ; int ii, jj ; if ( size < 0 || x == NULL ) { fprintf(stderr, "\n fatal error in ZVminabs(%d,%p)" "\n bad input\n", size, x) ; exit(-1) ; } minabs = 0.0 ; for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { real = fabs(x[jj]) ; imag = fabs(x[jj+1]) ; /* fprintf(stdout, "\n i = %d, <%12.4e, %12.4e>", ii, real, imag) ; */ if ( real == 0.0 ) { abs = imag ; } else if ( imag == 0.0 ) { abs = real ; } else if ( real >= imag ) { val = imag/real ; abs = real*sqrt(1 + val*val) ; } else { val = real/imag ; abs = imag*sqrt(1 + val*val) ; } /* fprintf(stdout, " abs = %12.4e", abs) ; */ if ( ii == 0 || minabs > abs ) { minabs = abs ; } } /* fprintf(stdout, "\n minabs = %12.4e", minabs) ; */ return(minabs) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- return the maximum absolute value of the entries in a complex vector created -- 98jan23, cca ---------------------------------- */ double ZVmaxabs ( int size, double x[] ) { double abs, imag, maxabs, real, val ; int ii, jj ; if ( size < 0 || x == NULL ) { fprintf(stderr, "\n fatal error in ZVmaxabs(%d,%p)" "\n bad input\n", size, x) ; exit(-1) ; } maxabs = 0.0 ; for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { real = fabs(x[jj]) ; imag = fabs(x[jj+1]) ; /* fprintf(stdout, "\n i = %d, <%12.4e, %12.4e>", ii, real, imag) ; */ if ( real == 0.0 ) { abs = imag ; } else if ( imag == 0.0 ) { abs = real ; } else if ( real >= imag ) { val = imag/real ; abs = real*sqrt(1 + val*val) ; } else { val = real/imag ; abs = imag*sqrt(1 + val*val) ; } /* fprintf(stdout, " abs = %12.4e", abs) ; */ if ( ii == 0 || maxabs < abs ) { maxabs = abs ; } } /* fprintf(stdout, "\n maxabs = %12.4e", maxabs) ; */ return(maxabs) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- copy a complex vector into another y[] := x[] created -- 98jan23, cca ---------------------------------- */ void ZVcopy ( int size, double y[], double x[] ) { int ii, jj ; if ( size < 0 || y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in ZVcopy(%d,%p,%p)" "\n bad input\n", size, y, x) ; exit(-1) ; } for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { y[jj] = x[jj] ; y[jj+1] = x[jj+1] ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- subtract a complex vector from another y[] := y[] - x[] created -- 98may25, cca -------------------------------------- */ void ZVsub ( int size, double y[], double x[] ) { int ii, jj ; if ( size < 0 || y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in ZVsub(%d,%p,%p)" "\n bad input\n", size, y, x) ; exit(-1) ; } for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { y[jj] -= x[jj] ; y[jj+1] -= x[jj+1] ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to perform a complex axpy with two vectors z := z + (areal, aimag)*x + (breal, bimag)*y where y and x are complex created -- 98jan23, cca ---------------------------------------------------- */ void ZVaxpy2 ( int size, double z[], double areal, double aimag, double x[], double breal, double bimag, double y[] ) { double ximag, xreal, yimag, yreal ; int ii, jj ; if ( size < 0 || y == NULL || x == NULL ) { fprintf(stderr, "\n fatal error in ZVaxpy(%d,%p,%f,%f,%p)" "\n bad input\n", size, y, areal, aimag, x) ; exit(-1) ; } for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { xreal = x[jj] ; ximag = x[jj+1] ; yreal = y[jj] ; yimag = y[jj+1] ; /* fprintf(stdout, "\n ii = %d, xreal = %20.12e, ximag = %20.12e", ii, xreal, ximag) ; fprintf(stdout, "\n yreal = %20.12e, yimag = %20.12e", y[jj], y[jj+1]) ; fprintf(stdout, "\n before zreal = %20.12e, zimag = %20.12e", z[jj], z[jj+1]) ; */ z[jj] += areal*xreal - aimag*ximag + breal*yreal - bimag*yimag ; z[jj+1] += areal*ximag + aimag*xreal + breal*yimag + bimag*yreal ; /* fprintf(stdout, "\n after zreal = %20.12e, zimag = %20.12e", z[jj], z[jj+1]) ; */ } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- to scale a double complex vector by a 2x2 matrix [ x ] := [ a b ] [ x ] [ y ] [ c d ] [ y ] created -- 98jan23, cca ------------------------------------------------------------ */ void ZVscale2 ( int size, double x[], double y[], double areal, double aimag, double breal, double bimag, double creal, double cimag, double dreal, double dimag ) { double ximag, xreal, yimag, yreal ; int ii, jj ; if ( size < 0 || x == NULL || y == NULL ) { fprintf(stderr, "\n fatal error in ZVscale2(%d,%p,%p,...)" "\n bad input\n", size, x, y) ; exit(-1) ; } for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { xreal = x[jj] ; ximag = x[jj+1] ; yreal = y[jj] ; yimag = y[jj+1] ; x[jj] = areal*xreal - aimag*ximag + breal*yreal - bimag*yimag ; x[jj+1] = areal*ximag + aimag*xreal + breal*yimag + bimag*yreal ; y[jj] = creal*xreal - cimag*ximag + dreal*yreal - dimag*yimag ; y[jj+1] = creal*ximag + cimag*xreal + dreal*yimag + dimag*yreal ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------- purpose -- to gather y[*] = x[index[*]] created -- 98apr15, cca --------------------------------------- */ void ZVgather ( int size, double y[], double x[], int index[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in ZVgather, invalid input" "\n size = %d, y = %p, x = %p, index = %p\n", size, y, x, index) ; exit(-1) ; } else { int i, j, k ; for ( i = j = 0 ; i < size ; i++, j += 2 ) { k = 2*index[i] ; y[j] = x[k] ; y[j+1] = x[k+1] ; } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- purpose -- to scatter y[index[*]] = x[*] created -- 98apr15, cca ---------------------------------------- */ void ZVscatter ( int size, double y[], int index[], double x[] ) { if ( size > 0 ) { if ( y == NULL || x == NULL || index == NULL ) { fprintf(stderr, "\n fatal error in ZVscatter, invalid data" "\n size = %d, y = %p, index = %p, x = %p\n", size, y, index, x) ; exit(-1) ; } else { int i, j, k ; for ( i = j = 0 ; i < size ; i++, j += 2 ) { k = 2*index[i] ; y[k] = x[j] ; y[k+1] = x[j+1] ; } } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^T [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU33 ( int n, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[], double sums[] ) { double i00, i01, i02, i10, i11, i12, i20, i21, i22, r00, r01, r02, r10, r11, r12, r20, r21, r22, xi0, xi1, xi2, xr0, xr1, xr2, yi0, yi1, yi2, yr0, yr1, yr2 ; int ii, iloc, rloc ; i00 = i01 = i02 = i10 = i11 = i12 = i20 = i21 = i22 = r00 = r01 = r02 = r10 = r11 = r12 = r20 = r21 = r22 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; yr2 = y2[rloc] ; yi2 = y2[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; xr2 = x2[rloc] ; xi2 = x2[iloc] ; r00 += yr0*xr0 - yi0*xi0 ; i00 += yr0*xi0 + yi0*xr0 ; r01 += yr0*xr1 - yi0*xi1 ; i01 += yr0*xi1 + yi0*xr1 ; r02 += yr0*xr2 - yi0*xi2 ; i02 += yr0*xi2 + yi0*xr2 ; r10 += yr1*xr0 - yi1*xi0 ; i10 += yr1*xi0 + yi1*xr0 ; r11 += yr1*xr1 - yi1*xi1 ; i11 += yr1*xi1 + yi1*xr1 ; r12 += yr1*xr2 - yi1*xi2 ; i12 += yr1*xi2 + yi1*xr2 ; r20 += yr2*xr0 - yi2*xi0 ; i20 += yr2*xi0 + yi2*xr0 ; r21 += yr2*xr1 - yi2*xi1 ; i21 += yr2*xi1 + yi2*xr1 ; r22 += yr2*xr2 - yi2*xi2 ; i22 += yr2*xi2 + yi2*xr2 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; sums[ 4] = r02 ; sums[ 5] = i02 ; sums[ 6] = r10 ; sums[ 7] = i10 ; sums[ 8] = r11 ; sums[ 9] = i11 ; sums[10] = r12 ; sums[11] = i12 ; sums[12] = r20 ; sums[13] = i20 ; sums[14] = r21 ; sums[15] = i21 ; sums[16] = r22 ; sums[17] = i22 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^T [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU32 ( int n, double y0[], double y1[], double y2[], double x0[], double x1[], double sums[] ) { double i00, i01, i10, i11, i20, i21, r00, r01, r10, r11, r20, r21, xi0, xi1, xr0, xr1, yi0, yi1, yi2, yr0, yr1, yr2 ; int ii, iloc, rloc ; i00 = i01 = i10 = i11 = i20 = i21 = r00 = r01 = r10 = r11 = r20 = r21 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; yr2 = y2[rloc] ; yi2 = y2[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; r00 += yr0*xr0 - yi0*xi0 ; i00 += yr0*xi0 + yi0*xr0 ; r01 += yr0*xr1 - yi0*xi1 ; i01 += yr0*xi1 + yi0*xr1 ; r10 += yr1*xr0 - yi1*xi0 ; i10 += yr1*xi0 + yi1*xr0 ; r11 += yr1*xr1 - yi1*xi1 ; i11 += yr1*xi1 + yi1*xr1 ; r20 += yr2*xr0 - yi2*xi0 ; i20 += yr2*xi0 + yi2*xr0 ; r21 += yr2*xr1 - yi2*xi1 ; i21 += yr2*xi1 + yi2*xr1 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; sums[ 4] = r10 ; sums[ 5] = i10 ; sums[ 6] = r11 ; sums[ 7] = i11 ; sums[ 8] = r20 ; sums[ 9] = i20 ; sums[10] = r21 ; sums[11] = i21 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^T [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU31 ( int n, double y0[], double y1[], double y2[], double x0[], double sums[] ) { double i00, i10, i20, r00, r10, r20, xi0, xr0, yi0, yi1, yi2, yr0, yr1, yr2 ; int ii, iloc, rloc ; i00 = i10 = i20 = r00 = r10 = r20 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; yr2 = y2[rloc] ; yi2 = y2[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; r00 += yr0*xr0 - yi0*xi0 ; i00 += yr0*xi0 + yi0*xr0 ; r10 += yr1*xr0 - yi1*xi0 ; i10 += yr1*xi0 + yi1*xr0 ; r20 += yr2*xr0 - yi2*xi0 ; i20 += yr2*xi0 + yi2*xr0 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r10 ; sums[ 3] = i10 ; sums[ 4] = r20 ; sums[ 5] = i20 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^T [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU23 ( int n, double y0[], double y1[], double x0[], double x1[], double x2[], double sums[] ) { double i00, i01, i02, i10, i11, i12, r00, r01, r02, r10, r11, r12, xi0, xi1, xi2, xr0, xr1, xr2, yi0, yi1, yr0, yr1 ; int ii, iloc, rloc ; i00 = i01 = i02 = i10 = i11 = i12 = r00 = r01 = r02 = r10 = r11 = r12 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; xr2 = x2[rloc] ; xi2 = x2[iloc] ; r00 += yr0*xr0 - yi0*xi0 ; i00 += yr0*xi0 + yi0*xr0 ; r01 += yr0*xr1 - yi0*xi1 ; i01 += yr0*xi1 + yi0*xr1 ; r02 += yr0*xr2 - yi0*xi2 ; i02 += yr0*xi2 + yi0*xr2 ; r10 += yr1*xr0 - yi1*xi0 ; i10 += yr1*xi0 + yi1*xr0 ; r11 += yr1*xr1 - yi1*xi1 ; i11 += yr1*xi1 + yi1*xr1 ; r12 += yr1*xr2 - yi1*xi2 ; i12 += yr1*xi2 + yi1*xr2 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; sums[ 4] = r02 ; sums[ 5] = i02 ; sums[ 6] = r10 ; sums[ 7] = i10 ; sums[ 8] = r11 ; sums[ 9] = i11 ; sums[10] = r12 ; sums[11] = i12 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^T [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU22 ( int n, double y0[], double y1[], double x0[], double x1[], double sums[] ) { double i00, i01, i10, i11, r00, r01, r10, r11, xi0, xi1, xr0, xr1, yi0, yi1, yr0, yr1 ; int ii, iloc, rloc ; i00 = i01 = i10 = i11 = r00 = r01 = r10 = r11 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; r00 += yr0*xr0 - yi0*xi0 ; i00 += yr0*xi0 + yi0*xr0 ; r01 += yr0*xr1 - yi0*xi1 ; i01 += yr0*xi1 + yi0*xr1 ; r10 += yr1*xr0 - yi1*xi0 ; i10 += yr1*xi0 + yi1*xr0 ; r11 += yr1*xr1 - yi1*xi1 ; i11 += yr1*xi1 + yi1*xr1 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; sums[ 4] = r10 ; sums[ 5] = i10 ; sums[ 6] = r11 ; sums[ 7] = i11 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^T [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU21 ( int n, double y0[], double y1[], double x0[], double sums[] ) { double i00, i10, r00, r10, xi0, xr0, yi0, yi1, yr0, yr1 ; int ii, iloc, rloc ; i00 = i10 = r00 = r10 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; r00 += yr0*xr0 - yi0*xi0 ; i00 += yr0*xi0 + yi0*xr0 ; r10 += yr1*xr0 - yi1*xi0 ; i10 += yr1*xi0 + yi1*xr0 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r10 ; sums[ 3] = i10 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^T [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU13 ( int n, double y0[], double x0[], double x1[], double x2[], double sums[] ) { double i00, i01, i02, r00, r01, r02, xi0, xi1, xi2, xr0, xr1, xr2, yi0, yr0 ; int ii, iloc, rloc ; i00 = i01 = i02 = r00 = r01 = r02 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; xr2 = x2[rloc] ; xi2 = x2[iloc] ; r00 += yr0*xr0 - yi0*xi0 ; i00 += yr0*xi0 + yi0*xr0 ; r01 += yr0*xr1 - yi0*xi1 ; i01 += yr0*xi1 + yi0*xr1 ; r02 += yr0*xr2 - yi0*xi2 ; i02 += yr0*xi2 + yi0*xr2 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; sums[ 4] = r02 ; sums[ 5] = i02 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^T [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU12 ( int n, double y0[], double x0[], double x1[], double sums[] ) { double i00, i01, r00, r01, xi0, xi1, xr0, xr1, yi0, yr0 ; int ii, iloc, rloc ; i00 = i01 = r00 = r01 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; r00 += yr0*xr0 - yi0*xi0 ; i00 += yr0*xi0 + yi0*xr0 ; r01 += yr0*xr1 - yi0*xi1 ; i01 += yr0*xi1 + yi0*xr1 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^T [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotU11 ( int n, double y0[], double x0[], double sums[] ) { double i00, r00, xi0, xr0, yi0, yr0 ; int ii, iloc, rloc ; i00 = r00 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; r00 += yr0*xr0 - yi0*xi0 ; i00 += yr0*xi0 + yi0*xr0 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^H [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC33 ( int n, double y0[], double y1[], double y2[], double x0[], double x1[], double x2[], double sums[] ) { double i00, i01, i02, i10, i11, i12, i20, i21, i22, r00, r01, r02, r10, r11, r12, r20, r21, r22, xi0, xi1, xi2, xr0, xr1, xr2, yi0, yi1, yi2, yr0, yr1, yr2 ; int ii, iloc, rloc ; i00 = i01 = i02 = i10 = i11 = i12 = i20 = i21 = i22 = r00 = r01 = r02 = r10 = r11 = r12 = r20 = r21 = r22 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; yr2 = y2[rloc] ; yi2 = y2[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; xr2 = x2[rloc] ; xi2 = x2[iloc] ; r00 += yr0*xr0 + yi0*xi0 ; i00 += yr0*xi0 - yi0*xr0 ; r01 += yr0*xr1 + yi0*xi1 ; i01 += yr0*xi1 - yi0*xr1 ; r02 += yr0*xr2 + yi0*xi2 ; i02 += yr0*xi2 - yi0*xr2 ; r10 += yr1*xr0 + yi1*xi0 ; i10 += yr1*xi0 - yi1*xr0 ; r11 += yr1*xr1 + yi1*xi1 ; i11 += yr1*xi1 - yi1*xr1 ; r12 += yr1*xr2 + yi1*xi2 ; i12 += yr1*xi2 - yi1*xr2 ; r20 += yr2*xr0 + yi2*xi0 ; i20 += yr2*xi0 - yi2*xr0 ; r21 += yr2*xr1 + yi2*xi1 ; i21 += yr2*xi1 - yi2*xr1 ; r22 += yr2*xr2 + yi2*xi2 ; i22 += yr2*xi2 - yi2*xr2 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; sums[ 4] = r02 ; sums[ 5] = i02 ; sums[ 6] = r10 ; sums[ 7] = i10 ; sums[ 8] = r11 ; sums[ 9] = i11 ; sums[10] = r12 ; sums[11] = i12 ; sums[12] = r20 ; sums[13] = i20 ; sums[14] = r21 ; sums[15] = i21 ; sums[16] = r22 ; sums[17] = i22 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^H [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC32 ( int n, double y0[], double y1[], double y2[], double x0[], double x1[], double sums[] ) { double i00, i01, i10, i11, i20, i21, r00, r01, r10, r11, r20, r21, xi0, xi1, xr0, xr1, yi0, yi1, yi2, yr0, yr1, yr2 ; int ii, iloc, rloc ; i00 = i01 = i10 = i11 = i20 = i21 = r00 = r01 = r10 = r11 = r20 = r21 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; yr2 = y2[rloc] ; yi2 = y2[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; r00 += yr0*xr0 + yi0*xi0 ; i00 += yr0*xi0 - yi0*xr0 ; r01 += yr0*xr1 + yi0*xi1 ; i01 += yr0*xi1 - yi0*xr1 ; r10 += yr1*xr0 + yi1*xi0 ; i10 += yr1*xi0 - yi1*xr0 ; r11 += yr1*xr1 + yi1*xi1 ; i11 += yr1*xi1 - yi1*xr1 ; r20 += yr2*xr0 + yi2*xi0 ; i20 += yr2*xi0 - yi2*xr0 ; r21 += yr2*xr1 + yi2*xi1 ; i21 += yr2*xi1 - yi2*xr1 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; sums[ 4] = r10 ; sums[ 5] = i10 ; sums[ 6] = r11 ; sums[ 7] = i11 ; sums[ 8] = r20 ; sums[ 9] = i20 ; sums[10] = r21 ; sums[11] = i21 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 y2 ]^H [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC31 ( int n, double y0[], double y1[], double y2[], double x0[], double sums[] ) { double i00, i10, i20, r00, r10, r20, xi0, xr0, yi0, yi1, yi2, yr0, yr1, yr2 ; int ii, iloc, rloc ; i00 = i10 = i20 = r00 = r10 = r20 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; yr2 = y2[rloc] ; yi2 = y2[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; r00 += yr0*xr0 + yi0*xi0 ; i00 += yr0*xi0 - yi0*xr0 ; r10 += yr1*xr0 + yi1*xi0 ; i10 += yr1*xi0 - yi1*xr0 ; r20 += yr2*xr0 + yi2*xi0 ; i20 += yr2*xi0 - yi2*xr0 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r10 ; sums[ 3] = i10 ; sums[ 4] = r20 ; sums[ 5] = i20 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^H [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC23 ( int n, double y0[], double y1[], double x0[], double x1[], double x2[], double sums[] ) { double i00, i01, i02, i10, i11, i12, r00, r01, r02, r10, r11, r12, xi0, xi1, xi2, xr0, xr1, xr2, yi0, yi1, yr0, yr1 ; int ii, iloc, rloc ; i00 = i01 = i02 = i10 = i11 = i12 = r00 = r01 = r02 = r10 = r11 = r12 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; xr2 = x2[rloc] ; xi2 = x2[iloc] ; r00 += yr0*xr0 + yi0*xi0 ; i00 += yr0*xi0 - yi0*xr0 ; r01 += yr0*xr1 + yi0*xi1 ; i01 += yr0*xi1 - yi0*xr1 ; r02 += yr0*xr2 + yi0*xi2 ; i02 += yr0*xi2 - yi0*xr2 ; r10 += yr1*xr0 + yi1*xi0 ; i10 += yr1*xi0 - yi1*xr0 ; r11 += yr1*xr1 + yi1*xi1 ; i11 += yr1*xi1 - yi1*xr1 ; r12 += yr1*xr2 + yi1*xi2 ; i12 += yr1*xi2 - yi1*xr2 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; sums[ 4] = r02 ; sums[ 5] = i02 ; sums[ 6] = r10 ; sums[ 7] = i10 ; sums[ 8] = r11 ; sums[ 9] = i11 ; sums[10] = r12 ; sums[11] = i12 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^H [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC22 ( int n, double y0[], double y1[], double x0[], double x1[], double sums[] ) { double i00, i01, i10, i11, r00, r01, r10, r11, xi0, xi1, xr0, xr1, yi0, yi1, yr0, yr1 ; int ii, iloc, rloc ; i00 = i01 = i10 = i11 = r00 = r01 = r10 = r11 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; r00 += yr0*xr0 + yi0*xi0 ; i00 += yr0*xi0 - yi0*xr0 ; r01 += yr0*xr1 + yi0*xi1 ; i01 += yr0*xi1 - yi0*xr1 ; r10 += yr1*xr0 + yi1*xi0 ; i10 += yr1*xi0 - yi1*xr0 ; r11 += yr1*xr1 + yi1*xi1 ; i11 += yr1*xi1 - yi1*xr1 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; sums[ 4] = r10 ; sums[ 5] = i10 ; sums[ 6] = r11 ; sums[ 7] = i11 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 y1 ]^H [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC21 ( int n, double y0[], double y1[], double x0[], double sums[] ) { double i00, i10, r00, r10, xi0, xr0, yi0, yi1, yr0, yr1 ; int ii, iloc, rloc ; i00 = i10 = r00 = r10 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; yr1 = y1[rloc] ; yi1 = y1[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; r00 += yr0*xr0 + yi0*xi0 ; i00 += yr0*xi0 - yi0*xr0 ; r10 += yr1*xr0 + yi1*xi0 ; i10 += yr1*xi0 - yi1*xr0 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r10 ; sums[ 3] = i10 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^H [ x0 x1 x2] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC13 ( int n, double y0[], double x0[], double x1[], double x2[], double sums[] ) { double i00, i01, i02, r00, r01, r02, xi0, xi1, xi2, xr0, xr1, xr2, yi0, yr0 ; int ii, iloc, rloc ; i00 = i01 = i02 = r00 = r01 = r02 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; xr2 = x2[rloc] ; xi2 = x2[iloc] ; r00 += yr0*xr0 + yi0*xi0 ; i00 += yr0*xi0 - yi0*xr0 ; r01 += yr0*xr1 + yi0*xi1 ; i01 += yr0*xi1 - yi0*xr1 ; r02 += yr0*xr2 + yi0*xi2 ; i02 += yr0*xi2 - yi0*xr2 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; sums[ 4] = r02 ; sums[ 5] = i02 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^H [ x0 x1 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC12 ( int n, double y0[], double x0[], double x1[], double sums[] ) { double i00, i01, r00, r01, xi0, xi1, xr0, xr1, yi0, yr0 ; int ii, iloc, rloc ; i00 = i01 = r00 = r01 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; xr1 = x1[rloc] ; xi1 = x1[iloc] ; r00 += yr0*xr0 + yi0*xi0 ; i00 += yr0*xi0 - yi0*xr0 ; r01 += yr0*xr1 + yi0*xi1 ; i01 += yr0*xi1 - yi0*xr1 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; sums[ 2] = r01 ; sums[ 3] = i01 ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the multiple dot product [ y0 ]^H [ x0 ] created -- 98apr17, cca ---------------------------------------------- */ void ZVdotC11 ( int n, double y0[], double x0[], double sums[] ) { double i00, r00, xi0, xr0, yi0, yr0 ; int ii, iloc, rloc ; i00 = r00 = 0.0 ; for ( ii = rloc = 0, iloc = 1 ; ii < n ; ii++, rloc += 2, iloc += 2 ) { yr0 = y0[rloc] ; yi0 = y0[iloc] ; xr0 = x0[rloc] ; xi0 = x0[iloc] ; r00 += yr0*xr0 + yi0*xi0 ; i00 += yr0*xi0 - yi0*xr0 ; } sums[ 0] = r00 ; sums[ 1] = i00 ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------------- purpose -- to zero the vector y := 0 where y is complex created -- 98apr25, cca ----------------------------- */ void ZVzero ( int size, double y[] ) { int ii, jj ; if ( size < 0 || y == NULL ) { fprintf(stderr, "\n fatal error in ZVzero(%d,%p)" "\n bad input\n", size, y) ; exit(-1) ; } for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { y[jj] = y[jj+1] = 0.0 ; } return ; } /*--------------------------------------------------------------------*/ r0*xi0 - yi0*xr0 ; r01 += yr0*xr1 + yi0*xi1 ; i01 += yr0*xi1 - yi0*xr1 ; r02 += yr0*xr2 + yi0*xi2 ; i02 += yr0*xi2 - yi0*xr2 ; r10 += yr1*xr0 + yi1*xi0 ; i10 += yr1*xi0 - yi1*xr0 ; r11 += yr1*xr1 + yi1*xi1 ; i11 += yr1*xi1 - yi1*xr1 ; r12 += yr1*xr2 + Utilities/src/axpy.c010064400020550007177000000433660663602035400160000ustar00clevecompmath00000400000006/* axpy.c */ #include "../Utilities.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] + alpha[2] * x2[] y1[] = y1[] + alpha[3] * x0[] + alpha[4] * x1[] + alpha[5] * x2[] y2[] = y2[] + alpha[6] * x0[] + alpha[7] * x1[] + alpha[8] * x2[] created -- 98dec10, cca ----------------------------------------------------------------- */ void DVaxpy33 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[], double x1[], double x2[] ) { register double a00, a01, a02, a10, a11, a12, a20, a21, a22 ; register double x0i, x1i, x2i ; int ii ; a00 = alpha[0] ; a01 = alpha[1] ; a02 = alpha[2] ; a10 = alpha[3] ; a11 = alpha[4] ; a12 = alpha[5] ; a20 = alpha[6] ; a21 = alpha[7] ; a22 = alpha[8] ; for ( ii = 0 ; ii < n ; ii++ ) { x0i = x0[ii] ; x1i = x1[ii] ; x2i = x2[ii] ; y0[ii] += a00*x0i + a01*x1i + a02*x2i ; y1[ii] += a10*x0i + a11*x1i + a12*x2i ; y2[ii] += a20*x0i + a21*x1i + a22*x2i ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] y1[] = y1[] + alpha[2] * x0[] + alpha[3] * x1[] y2[] = y2[] + alpha[4] * x0[] + alpha[5] * x1[] created -- 98dec10, cca ----------------------------------------------- */ void DVaxpy32 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[], double x1[] ) { register double a00, a01, a10, a11, a20, a21 ; register double x0i, x1i ; int ii ; a00 = alpha[0] ; a01 = alpha[1] ; a10 = alpha[2] ; a11 = alpha[3] ; a20 = alpha[4] ; a21 = alpha[5] ; for ( ii = 0 ; ii < n ; ii++ ) { x0i = x0[ii] ; x1i = x1[ii] ; y0[ii] += a00*x0i + a01*x1i ; y1[ii] += a10*x0i + a11*x1i ; y2[ii] += a20*x0i + a21*x1i ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------- y0[] = y0[] + alpha[0] * x0[] y1[] = y1[] + alpha[1] * x0[] y2[] = y2[] + alpha[2] * x0[] created -- 98dec10, cca ----------------------------- */ void DVaxpy31 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[] ) { register double a00, a10, a20 ; register double x0i ; int ii ; a00 = alpha[0] ; a10 = alpha[1] ; a20 = alpha[2] ; for ( ii = 0 ; ii < n ; ii++ ) { x0i = x0[ii] ; y0[ii] += a00*x0i ; y1[ii] += a10*x0i ; y2[ii] += a20*x0i ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] + alpha[2] * x2[] y1[] = y1[] + alpha[3] * x0[] + alpha[4] * x1[] + alpha[5] * x2[] created -- 98dec10, cca ----------------------------------------------------------------- */ void DVaxpy23 ( int n, double y0[], double y1[], double alpha[], double x0[], double x1[], double x2[] ) { register double a00, a01, a02, a10, a11, a12 ; register double x0i, x1i, x2i ; int ii ; a00 = alpha[0] ; a01 = alpha[1] ; a02 = alpha[2] ; a10 = alpha[3] ; a11 = alpha[4] ; a12 = alpha[5] ; for ( ii = 0 ; ii < n ; ii++ ) { x0i = x0[ii] ; x1i = x1[ii] ; x2i = x2[ii] ; y0[ii] += a00*x0i + a01*x1i + a02*x2i ; y1[ii] += a10*x0i + a11*x1i + a12*x2i ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] y1[] = y1[] + alpha[2] * x0[] + alpha[3] * x1[] created -- 98dec10, cca ----------------------------------------------- */ void DVaxpy22 ( int n, double y0[], double y1[], double alpha[], double x0[], double x1[] ) { register double a00, a01, a10, a11 ; register double x0i, x1i ; int ii ; a00 = alpha[0] ; a01 = alpha[1] ; a10 = alpha[2] ; a11 = alpha[3] ; for ( ii = 0 ; ii < n ; ii++ ) { x0i = x0[ii] ; x1i = x1[ii] ; y0[ii] += a00*x0i + a01*x1i ; y1[ii] += a10*x0i + a11*x1i ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------- y0[] = y0[] + alpha[0] * x0[] y1[] = y1[] + alpha[1] * x0[] created -- 98dec10, cca ----------------------------- */ void DVaxpy21 ( int n, double y0[], double y1[], double alpha[], double x0[] ) { register double a00, a10 ; register double x0i ; int ii ; a00 = alpha[0] ; a10 = alpha[1] ; for ( ii = 0 ; ii < n ; ii++ ) { x0i = x0[ii] ; y0[ii] += a00*x0i ; y1[ii] += a10*x0i ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] + alpha[2] * x2[] created -- 98dec10, cca ----------------------------------------------------------------- */ void DVaxpy13 ( int n, double y0[], double alpha[], double x0[], double x1[], double x2[] ) { register double a00, a01, a02 ; register double x0i, x1i, x2i ; int ii ; a00 = alpha[0] ; a01 = alpha[1] ; a02 = alpha[2] ; for ( ii = 0 ; ii < n ; ii++ ) { x0i = x0[ii] ; x1i = x1[ii] ; x2i = x2[ii] ; y0[ii] += a00*x0i + a01*x1i + a02*x2i ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------- y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] created -- 98dec10, cca ----------------------------------------------- */ void DVaxpy12 ( int n, double y0[], double alpha[], double x0[], double x1[] ) { register double a00, a01 ; register double x0i, x1i ; int ii ; a00 = alpha[0] ; a01 = alpha[1] ; for ( ii = 0 ; ii < n ; ii++ ) { x0i = x0[ii] ; x1i = x1[ii] ; y0[ii] += a00*x0i + a01*x1i ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------- y0[] = y0[] + alpha[0] * x0[] created -- 98dec10, cca ----------------------------- */ void DVaxpy11 ( int n, double y0[], double alpha[], double x0[] ) { register double a00 ; register double x0i ; int ii ; a00 = alpha[0] ; for ( ii = 0 ; ii < n ; ii++ ) { x0i = x0[ii] ; y0[ii] += a00*x0i ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] + alpha[4:5] * x2[] y1[] = y1[] + alpha[6:7] * x0[] + alpha[8:9] * x1[] + alpha[10:11] * x2[] y2[] = y2[] + alpha[12:13] * x0[] + alpha[14:15] * x1[] + alpha[16:17] * x2[] created -- 98dec10, cca ----------------------------------------------------------------- */ void ZVaxpy33 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[], double x1[], double x2[] ) { register double ar00, ar01, ar02, ar10, ar11, ar12, ar20, ar21, ar22 ; register double ai00, ai01, ai02, ai10, ai11, ai12, ai20, ai21, ai22 ; register double xr0i, xr1i, xr2i ; register double xi0i, xi1i, xi2i ; int ii ; ar00 = alpha[ 0] ; ai00 = alpha[ 1] ; ar01 = alpha[ 2] ; ai01 = alpha[ 3] ; ar02 = alpha[ 4] ; ai02 = alpha[ 5] ; ar10 = alpha[ 6] ; ai10 = alpha[ 7] ; ar11 = alpha[ 8] ; ai11 = alpha[ 9] ; ar12 = alpha[10] ; ai12 = alpha[11] ; ar20 = alpha[12] ; ai20 = alpha[13] ; ar21 = alpha[14] ; ai21 = alpha[15] ; ar22 = alpha[16] ; ai22 = alpha[17] ; for ( ii = 0 ; ii < n ; ii++ ) { xr0i = x0[2*ii] ; xi0i = x0[2*ii+1] ; xr1i = x1[2*ii] ; xi1i = x1[2*ii+1] ; xr2i = x2[2*ii] ; xi2i = x2[2*ii+1] ; y0[2*ii] += (ar00*xr0i - ai00*xi0i) + (ar01*xr1i - ai01*xi1i) + (ar02*xr2i - ai02*xi2i) ; y0[2*ii+1] += (ar00*xi0i + ai00*xr0i) + (ar01*xi1i + ai01*xr1i) + (ar02*xi2i + ai02*xr2i) ; y1[2*ii] += (ar10*xr0i - ai10*xi0i) + (ar11*xr1i - ai11*xi1i) + (ar12*xr2i - ai12*xi2i) ; y1[2*ii+1] += (ar10*xi0i + ai10*xr0i) + (ar11*xi1i + ai11*xr1i) + (ar12*xi2i + ai12*xr2i) ; y2[2*ii] += (ar20*xr0i - ai20*xi0i) + (ar21*xr1i - ai21*xi1i) + (ar22*xr2i - ai22*xi2i) ; y2[2*ii+1] += (ar20*xi0i + ai20*xr0i) + (ar21*xi1i + ai21*xr1i) + (ar22*xi2i + ai22*xr2i) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] y1[] = y1[] + alpha[4:5] * x0[] + alpha[6:7] * x1[] y2[] = y2[] + alpha[8:9] * x0[] + alpha[10:11] * x1[] created -- 98dec10, cca ----------------------------------------------------- */ void ZVaxpy32 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[], double x1[] ) { register double ar00, ar01, ar10, ar11, ar20, ar21 ; register double ai00, ai01, ai10, ai11, ai20, ai21 ; register double xr0i, xr1i ; register double xi0i, xi1i ; int ii ; ar00 = alpha[ 0] ; ai00 = alpha[ 1] ; ar01 = alpha[ 2] ; ai01 = alpha[ 3] ; ar10 = alpha[ 4] ; ai10 = alpha[ 5] ; ar11 = alpha[ 6] ; ai11 = alpha[ 7] ; ar20 = alpha[ 8] ; ai20 = alpha[ 9] ; ar21 = alpha[10] ; ai21 = alpha[11] ; for ( ii = 0 ; ii < n ; ii++ ) { xr0i = x0[2*ii] ; xi0i = x0[2*ii+1] ; xr1i = x1[2*ii] ; xi1i = x1[2*ii+1] ; y0[2*ii] += (ar00*xr0i - ai00*xi0i) + (ar01*xr1i - ai01*xi1i) ; y0[2*ii+1] += (ar00*xi0i + ai00*xr0i) + (ar01*xi1i + ai01*xr1i) ; y1[2*ii] += (ar10*xr0i - ai10*xi0i) + (ar11*xr1i - ai11*xi1i) ; y1[2*ii+1] += (ar10*xi0i + ai10*xr0i) + (ar11*xi1i + ai11*xr1i) ; y2[2*ii] += (ar20*xr0i - ai20*xi0i) + (ar21*xr1i - ai21*xi1i) ; y2[2*ii+1] += (ar20*xi0i + ai20*xr0i) + (ar21*xi1i + ai21*xr1i) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------- y0[] = y0[] + alpha[0:1] * x0[] y1[] = y1[] + alpha[2:3] * x0[] y2[] = y2[] + alpha[4:5] * x0[] created -- 98dec10, cca ------------------------------- */ void ZVaxpy31 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[] ) { register double ar00, ar10, ar20 ; register double ai00, ai10, ai20 ; register double xr0i ; register double xi0i ; int ii ; ar00 = alpha[ 0] ; ai00 = alpha[ 1] ; ar10 = alpha[ 2] ; ai10 = alpha[ 3] ; ar20 = alpha[ 4] ; ai20 = alpha[ 5] ; for ( ii = 0 ; ii < n ; ii++ ) { xr0i = x0[2*ii] ; xi0i = x0[2*ii+1] ; y0[2*ii] += (ar00*xr0i - ai00*xi0i) ; y0[2*ii+1] += (ar00*xi0i + ai00*xr0i) ; y1[2*ii] += (ar10*xr0i - ai10*xi0i) ; y1[2*ii+1] += (ar10*xi0i + ai10*xr0i) ; y2[2*ii] += (ar20*xr0i - ai20*xi0i) ; y2[2*ii+1] += (ar20*xi0i + ai20*xr0i) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] + alpha[4:5] * x2[] y1[] = y1[] + alpha[6:7] * x0[] + alpha[8:9] * x1[] + alpha[10:11] * x2[] created -- 98dec10, cca ----------------------------------------------------------------- */ void ZVaxpy23 ( int n, double y0[], double y1[], double alpha[], double x0[], double x1[], double x2[] ) { register double ar00, ar01, ar02, ar10, ar11, ar12 ; register double ai00, ai01, ai02, ai10, ai11, ai12 ; register double xr0i, xr1i, xr2i ; register double xi0i, xi1i, xi2i ; int ii ; ar00 = alpha[ 0] ; ai00 = alpha[ 1] ; ar01 = alpha[ 2] ; ai01 = alpha[ 3] ; ar02 = alpha[ 4] ; ai02 = alpha[ 5] ; ar10 = alpha[ 6] ; ai10 = alpha[ 7] ; ar11 = alpha[ 8] ; ai11 = alpha[ 9] ; ar12 = alpha[10] ; ai12 = alpha[11] ; for ( ii = 0 ; ii < n ; ii++ ) { xr0i = x0[2*ii] ; xi0i = x0[2*ii+1] ; xr1i = x1[2*ii] ; xi1i = x1[2*ii+1] ; xr2i = x2[2*ii] ; xi2i = x2[2*ii+1] ; y0[2*ii] += (ar00*xr0i - ai00*xi0i) + (ar01*xr1i - ai01*xi1i) + (ar02*xr2i - ai02*xi2i) ; y0[2*ii+1] += (ar00*xi0i + ai00*xr0i) + (ar01*xi1i + ai01*xr1i) + (ar02*xi2i + ai02*xr2i) ; y1[2*ii] += (ar10*xr0i - ai10*xi0i) + (ar11*xr1i - ai11*xi1i) + (ar12*xr2i - ai12*xi2i) ; y1[2*ii+1] += (ar10*xi0i + ai10*xr0i) + (ar11*xi1i + ai11*xr1i) + (ar12*xi2i + ai12*xr2i) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] y1[] = y1[] + alpha[4:5] * x0[] + alpha[6:7] * x1[] created -- 98dec10, cca ----------------------------------------------------- */ void ZVaxpy22 ( int n, double y0[], double y1[], double alpha[], double x0[], double x1[] ) { register double ar00, ar01, ar10, ar11 ; register double ai00, ai01, ai10, ai11 ; register double xr0i, xr1i ; register double xi0i, xi1i ; int ii ; ar00 = alpha[ 0] ; ai00 = alpha[ 1] ; ar01 = alpha[ 2] ; ai01 = alpha[ 3] ; ar10 = alpha[ 4] ; ai10 = alpha[ 5] ; ar11 = alpha[ 6] ; ai11 = alpha[ 7] ; for ( ii = 0 ; ii < n ; ii++ ) { xr0i = x0[2*ii] ; xi0i = x0[2*ii+1] ; xr1i = x1[2*ii] ; xi1i = x1[2*ii+1] ; y0[2*ii] += (ar00*xr0i - ai00*xi0i) + (ar01*xr1i - ai01*xi1i) ; y0[2*ii+1] += (ar00*xi0i + ai00*xr0i) + (ar01*xi1i + ai01*xr1i) ; y1[2*ii] += (ar10*xr0i - ai10*xi0i) + (ar11*xr1i - ai11*xi1i) ; y1[2*ii+1] += (ar10*xi0i + ai10*xr0i) + (ar11*xi1i + ai11*xr1i) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------- y0[] = y0[] + alpha[0:1] * x0[] y1[] = y1[] + alpha[2:3] * x0[] created -- 98dec10, cca ------------------------------- */ void ZVaxpy21 ( int n, double y0[], double y1[], double alpha[], double x0[] ) { register double ar00, ar10 ; register double ai00, ai10 ; register double xr0i ; register double xi0i ; int ii ; ar00 = alpha[ 0] ; ai00 = alpha[ 1] ; ar10 = alpha[ 2] ; ai10 = alpha[ 3] ; for ( ii = 0 ; ii < n ; ii++ ) { xr0i = x0[2*ii] ; xi0i = x0[2*ii+1] ; y0[2*ii] += (ar00*xr0i - ai00*xi0i) ; y0[2*ii+1] += (ar00*xi0i + ai00*xr0i) ; y1[2*ii] += (ar10*xr0i - ai10*xi0i) ; y1[2*ii+1] += (ar10*xi0i + ai10*xr0i) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] + alpha[4:5] * x2[] created -- 98dec10, cca --------------------------------------------------- */ void ZVaxpy13 ( int n, double y0[], double alpha[], double x0[], double x1[], double x2[] ) { register double ar00, ar01, ar02 ; register double ai00, ai01, ai02 ; register double xr0i, xr1i, xr2i ; register double xi0i, xi1i, xi2i ; int ii ; ar00 = alpha[ 0] ; ai00 = alpha[ 1] ; ar01 = alpha[ 2] ; ai01 = alpha[ 3] ; ar02 = alpha[ 4] ; ai02 = alpha[ 5] ; for ( ii = 0 ; ii < n ; ii++ ) { xr0i = x0[2*ii] ; xi0i = x0[2*ii+1] ; xr1i = x1[2*ii] ; xi1i = x1[2*ii+1] ; xr2i = x2[2*ii] ; xi2i = x2[2*ii+1] ; y0[2*ii] += (ar00*xr0i - ai00*xi0i) + (ar01*xr1i - ai01*xi1i) + (ar02*xr2i - ai02*xi2i) ; y0[2*ii+1] += (ar00*xi0i + ai00*xr0i) + (ar01*xi1i + ai01*xr1i) + (ar02*xi2i + ai02*xr2i) ; } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] created -- 98dec10, cca ----------------------------------------------------- */ void ZVaxpy12 ( int n, double y0[], double alpha[], double x0[], double x1[] ) { register double ar00, ar01 ; register double ai00, ai01 ; register double xr0i, xr1i ; register double xi0i, xi1i ; int ii ; ar00 = alpha[ 0] ; ai00 = alpha[ 1] ; ar01 = alpha[ 2] ; ai01 = alpha[ 3] ; for ( ii = 0 ; ii < n ; ii++ ) { xr0i = x0[2*ii] ; xi0i = x0[2*ii+1] ; xr1i = x1[2*ii] ; xi1i = x1[2*ii+1] ; y0[2*ii] += (ar00*xr0i - ai00*xi0i) + (ar01*xr1i - ai01*xi1i) ; y0[2*ii+1] += (ar00*xi0i + ai00*xr0i) + (ar01*xi1i + ai01*xr1i) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------- y0[] = y0[] + alpha[0:1] * x0[] created -- 98dec10, cca ------------------------------- */ void ZVaxpy11 ( int n, double y0[], double alpha[], double x0[] ) { register double ar00 ; register double ai00 ; register double xr0i ; register double xi0i ; int ii ; ar00 = alpha[ 0] ; ai00 = alpha[ 1] ; for ( ii = 0 ; ii < n ; ii++ ) { xr0i = x0[2*ii] ; xi0i = x0[2*ii+1] ; y0[2*ii] += (ar00*xr0i - ai00*xi0i) ; y0[2*ii+1] += (ar00*xi0i + ai00*xr0i) ; } return ; } /*--------------------------------------------------------------------*/ *xr2i) ; y1[2*ii] += (ar10*xr0i - ai10*xi0i) + (ar11*xr1i - ai11*xi1i) + (ar12*xr2i - ai12*xi2i) ; y1[2*ii+1] += (ar10*xi0i + ai10*xr0i) + (ar11*xi1i + ai11*xr1i) + (ar12*xi2i + ai12*xr2i) ; y2Utilities/src/iohb.c010064400020550007177000001755130660074045100157360ustar00clevecompmath00000400000006/* Fri Aug 15 16:29:47 EDT 1997 Harwell-Boeing File I/O in C V. 1.0 National Institute of Standards and Technology, MD. K.A. Remington ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ NOTICE Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted provided that the above copyright notice appear in all copies and that both the copyright notice and this permission notice appear in supporting documentation. Neither the Author nor the Institution (National Institute of Standards and Technology) make any representations about the suitability of this software for any purpose. This software is provided "as is" without expressed or implied warranty. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --------------------- INTERFACE DESCRIPTION --------------------- --------------- QUERY FUNCTIONS --------------- FUNCTION: int readHB_info(const char *filename, int *M, int *N, int *nz, char **Type, int *Nrhs) DESCRIPTION: The readHB_info function opens and reads the header information from the specified Harwell-Boeing file, and reports back the number of rows and columns in the stored matrix (M and N), the number of nonzeros in the matrix (nz), the 3-character matrix type(Type), and the number of right-hand-sides stored along with the matrix (Nrhs). This function is designed to retrieve basic size information which can be used to allocate arrays. FUNCTION: int readHB_header(FILE* in_file, char* Title, char* Key, char* Type, int* Nrow, int* Ncol, int* Nnzero, int* Nrhs, char* Ptrfmt, char* Indfmt, char* Valfmt, char* Rhsfmt, int* Ptrcrd, int* Indcrd, int* Valcrd, int* Rhscrd, char *Rhstype) DESCRIPTION: More detailed than the readHB_info function, readHB_header() reads from the specified Harwell-Boeing file all of the header information. ------------------------------ DOUBLE PRECISION I/O FUNCTIONS ------------------------------ FUNCTION: int readHB_newmat_double(const char *filename, int *M, int *N, *int nz, int **colptr, int **rowind, double**val) int readHB_mat_double(const char *filename, int *colptr, int *rowind, double*val) DESCRIPTION: This function opens and reads the specified file, interpreting its contents as a sparse matrix stored in the Harwell/Boeing standard format. (See readHB_aux_double to read auxillary vectors.) -- Values are interpreted as double precision numbers. -- The "mat" function uses _pre-allocated_ vectors to hold the index and nonzero value information. The "newmat" function allocates vectors to hold the index and nonzero value information, and returns pointers to these vectors along with matrix dimension and number of nonzeros. FUNCTION: int readHB_aux_double(const char* filename, const char AuxType, double b[]) int readHB_newaux_double(const char* filename, const char AuxType, double** b) DESCRIPTION: This function opens and reads from the specified file auxillary vector(s). The char argument Auxtype determines which type of auxillary vector(s) will be read (if present in the file). AuxType = 'F' right-hand-side AuxType = 'G' initial estimate (Guess) AuxType = 'X' eXact solution If Nrhs > 1, all of the Nrhs vectors of the given type are read and stored in column-major order in the vector b. The "newaux" function allocates a vector to hold the values retrieved. The "mat" function uses a _pre-allocated_ vector to hold the values. FUNCTION: int writeHB_mat_double(const char* filename, int M, int N, int nz, const int colptr[], const int rowind[], const double val[], int Nrhs, const double rhs[], const double guess[], const double exact[], const char* Title, const char* Key, const char* Type, char* Ptrfmt, char* Indfmt, char* Valfmt, char* Rhsfmt, const char* Rhstype) DESCRIPTION: The writeHB_mat_double function opens the named file and writes the specified matrix and optional auxillary vector(s) to that file in Harwell-Boeing format. The format arguments (Ptrfmt,Indfmt,Valfmt, and Rhsfmt) are character strings specifying "Fortran-style" output formats -- as they would appear in a Harwell-Boeing file. They are used to produce output which is as close as possible to what would be produced by Fortran code, but note that "D" and "P" edit descriptors are not supported. If NULL, the following defaults will be used: Ptrfmt = Indfmt = "(8I10)" Valfmt = Rhsfmt = "(4E20.13)" ----------------------- CHARACTER I/O FUNCTIONS ----------------------- FUNCTION: int readHB_mat_char(const char* filename, int colptr[], int rowind[], char val[], char* Valfmt) int readHB_newmat_char(const char* filename, int* M, int* N, int* nonzeros, int** colptr, int** rowind, char** val, char** Valfmt) DESCRIPTION: This function opens and reads the specified file, interpreting its contents as a sparse matrix stored in the Harwell/Boeing standard format. (See readHB_aux_char to read auxillary vectors.) -- Values are interpreted as char strings. -- (Used to translate exact values from the file into a new storage format.) The "mat" function uses _pre-allocated_ arrays to hold the index and nonzero value information. The "newmat" function allocates char arrays to hold the index and nonzero value information, and returns pointers to these arrays along with matrix dimension and number of nonzeros. FUNCTION: int readHB_aux_char(const char* filename, const char AuxType, char b[]) int readHB_newaux_char(const char* filename, const char AuxType, char** b, char** Rhsfmt) DESCRIPTION: This function opens and reads from the specified file auxillary vector(s). The char argument Auxtype determines which type of auxillary vector(s) will be read (if present in the file). AuxType = 'F' right-hand-side AuxType = 'G' initial estimate (Guess) AuxType = 'X' eXact solution If Nrhs > 1, all of the Nrhs vectors of the given type are read and stored in column-major order in the vector b. The "newaux" function allocates a character array to hold the values retrieved. The "mat" function uses a _pre-allocated_ array to hold the values. FUNCTION: int writeHB_mat_char(const char* filename, int M, int N, int nz, const int colptr[], const int rowind[], const char val[], int Nrhs, const char rhs[], const char guess[], const char exact[], const char* Title, const char* Key, const char* Type, char* Ptrfmt, char* Indfmt, char* Valfmt, char* Rhsfmt, const char* Rhstype) DESCRIPTION: The writeHB_mat_char function opens the named file and writes the specified matrix and optional auxillary vector(s) to that file in Harwell-Boeing format. The format arguments (Ptrfmt,Indfmt,Valfmt, and Rhsfmt) are character strings specifying "Fortran-style" output formats -- as they would appear in a Harwell-Boeing file. Valfmt and Rhsfmt must accurately represent the character representation of the values stored in val[] and rhs[]. If NULL, the following defaults will be used for the integer vectors: Ptrfmt = Indfmt = "(8I10)" Valfmt = Rhsfmt = "(4E20.13)" */ /*---------------------------------------------------------------------*/ /* If zero-based indexing is desired, _SP_base should be set to 0 */ /* This will cause indices read from H-B files to be decremented by 1 */ /* and indices written to H-B files to be incremented by 1 */ /* <<< Standard usage is _SP_base = 1 >>> */ #ifndef _SP_base #define _SP_base 1 #endif /*---------------------------------------------------------------------*/ #include "../Utilities.h" static int ParseIfmt(char* fmt, int* perline, int* width) ; static int ParseRfmt(char* fmt, int* perline, int* width, int* prec, int* flag) ; static char* substr(const char* S, const int pos, const int len); static void upcase(char* S); static void IOHBTerminate(char* message); int readHB_info(const char* filename, int* M, int* N, int* nz, char** Type, int* Nrhs) { /****************************************************************************/ /* The readHB_info function opens and reads the header information from */ /* the specified Harwell-Boeing file, and reports back the number of rows */ /* and columns in the stored matrix (M and N), the number of nonzeros in */ /* the matrix (nz), and the number of right-hand-sides stored along with */ /* the matrix (Nrhs). */ /* */ /* For a description of the Harwell Boeing standard, see: */ /* Duff, et al., ACM TOMS Vol.15, No.1, March 1989 */ /* */ /* ---------- */ /* **CAVEAT** */ /* ---------- */ /* ** If the input file does not adhere to the H/B format, the ** */ /* ** results will be unpredictable. ** */ /* */ /****************************************************************************/ FILE *in_file; int Ptrcrd, Indcrd, Valcrd, Rhscrd; int Nrow, Ncol, Nnzero; char *mat_type; char Title[73], Key[9], Rhstype[4]; char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21]; /* mat_type = (char *) malloc(4); */ mat_type = CVinit(4, '\0') ; if ( mat_type == NULL ) IOHBTerminate("Insufficient memory for mat_typen"); if ( (in_file = fopen( filename, "r")) == NULL ) { fprintf(stderr,"Error: Cannot open file: %s\n",filename); return 0; } readHB_header(in_file, Title, Key, mat_type, &Nrow, &Ncol, &Nnzero, Nrhs, Ptrfmt, Indfmt, Valfmt, Rhsfmt, &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype); fclose(in_file); *Type = mat_type; *(*Type+3) = (char) NULL; *M = Nrow; *N = Ncol; *nz = Nnzero; if (Rhscrd == 0) {*Nrhs = 0;} /* In verbose mode, print some of the header information: */ /* if (verbose == 1) { printf("Reading from Harwell-Boeing file %s (verbose on)...\n",filename); printf(" Title: %s\n",Title); printf(" Key: %s\n",Key); printf(" The stored matrix is %i by %i with %i nonzeros.\n", *M, *N, *nz ); printf(" %i right-hand--side(s) stored.\n",*Nrhs); } */ return 1; } int readHB_header(FILE* in_file, char* Title, char* Key, char* Type, int* Nrow, int* Ncol, int* Nnzero, int* Nrhs, char* Ptrfmt, char* Indfmt, char* Valfmt, char* Rhsfmt, int* Ptrcrd, int* Indcrd, int* Valcrd, int* Rhscrd, char *Rhstype) { /*************************************************************************/ /* Read header information from the named H/B file... */ /*************************************************************************/ int Totcrd,Neltvl,Nrhsix; char line[BUFSIZ]; /* First line: */ fgets(line, BUFSIZ, in_file); if ( sscanf(line,"%*s") < 0 ) IOHBTerminate("iohb.c: Null (or blank) first line of HB file.\n"); (void) sscanf(line, "%72c%8[^\n]", Title, Key); *(Key+8) = (char) NULL; *(Title+72) = (char) NULL; /* Second line: */ fgets(line, BUFSIZ, in_file); if ( sscanf(line,"%*s") < 0 ) IOHBTerminate("iohb.c: Null (or blank) second line of HB file.\n"); if ( sscanf(line,"%i",&Totcrd) != 1) Totcrd = 0; if ( sscanf(line,"%*i%i",Ptrcrd) != 1) *Ptrcrd = 0; if ( sscanf(line,"%*i%*i%i",Indcrd) != 1) *Indcrd = 0; if ( sscanf(line,"%*i%*i%*i%i",Valcrd) != 1) *Valcrd = 0; if ( sscanf(line,"%*i%*i%*i%*i%i",Rhscrd) != 1) *Rhscrd = 0; /* Third line: */ fgets(line, BUFSIZ, in_file); if ( sscanf(line,"%*s") < 0 ) IOHBTerminate("iohb.c: Null (or blank) third line of HB file.\n"); if ( sscanf(line, "%3c", Type) != 1) IOHBTerminate("iohb.c: Invalid Type info, line 3 of Harwell-Boeing file.\n"); upcase(Type); if ( sscanf(line,"%*3c%i",Nrow) != 1) *Nrow = 0 ; if ( sscanf(line,"%*3c%*i%i",Ncol) != 1) *Ncol = 0 ; if ( sscanf(line,"%*3c%*i%*i%i",Nnzero) != 1) *Nnzero = 0 ; if ( sscanf(line,"%*3c%*i%*i%*i%i",&Neltvl) != 1) Neltvl = 0 ; /* Fourth line: */ fgets(line, BUFSIZ, in_file); if ( sscanf(line,"%*s") < 0 ) IOHBTerminate("iohb.c: Null (or blank) fourth line of HB file.\n"); if ( sscanf(line, "%16c",Ptrfmt) != 1) IOHBTerminate("iohb.c: Invalid format info, line 4 of Harwell-Boeing file.\n"); if ( sscanf(line, "%*16c%16c",Indfmt) != 1) IOHBTerminate("iohb.c: Invalid format info, line 4 of Harwell-Boeing file.\n"); if ( sscanf(line, "%*16c%*16c%20c",Valfmt) != 1) IOHBTerminate("iohb.c: Invalid format info, line 4 of Harwell-Boeing file.\n"); sscanf(line, "%*16c%*16c%*20c%20c",Rhsfmt); *(Ptrfmt+16) = (char) NULL; *(Indfmt+16) = (char) NULL; *(Valfmt+20) = (char) NULL; *(Rhsfmt+20) = (char) NULL; /* (Optional) Fifth line: */ if (*Rhscrd != 0 ) { fgets(line, BUFSIZ, in_file); if ( sscanf(line,"%*s") < 0 ) IOHBTerminate("iohb.c: Null (or blank) fifth line of HB file.\n"); if ( sscanf(line, "%3c", Rhstype) != 1) IOHBTerminate("iohb.c: Invalid RHS type information, line 5 of Harwell-Boeing file.\n"); if ( sscanf(line, "%*3c%i", Nrhs) != 1) *Nrhs = 0; if ( sscanf(line, "%*3c%*i%i", &Nrhsix) != 1) Nrhsix = 0; } return 1; } int readHB_mat_double(const char* filename, int colptr[], int rowind[], double val[]) { /****************************************************************************/ /* This function opens and reads the specified file, interpreting its */ /* contents as a sparse matrix stored in the Harwell/Boeing standard */ /* format and creating compressed column storage scheme vectors to hold */ /* the index and nonzero value information. */ /* */ /* ---------- */ /* **CAVEAT** */ /* ---------- */ /* Parsing real formats from Fortran is tricky, and this file reader */ /* does not claim to be foolproof. It has been tested for cases when */ /* the real values are printed consistently and evenly spaced on each */ /* line, with Fixed (F), and Exponential (E or D) formats. */ /* */ /* ** If the input file does not adhere to the H/B format, the ** */ /* ** results will be unpredictable. ** */ /* */ /****************************************************************************/ FILE *in_file; int i,j,ind,col,offset,count,last,Nrhs; int Ptrcrd, Indcrd, Valcrd, Rhscrd; int Nrow, Ncol, Nnzero, Nentries; int Ptrperline, Ptrwidth, Indperline, Indwidth; int Valperline, Valwidth, Valprec; int Valflag; /* Indicates 'E','D', or 'F' float format */ char* ThisElement; /* char Title[73], Key[8], Type[4], Rhstype[4]; char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21]; */ char *Title = CVinit(73, '\0') ; char *Key = CVinit(9, '\0') ; char *Type = CVinit(4, '\0') ; char *Rhstype = CVinit(4, '\0') ; char *Ptrfmt = CVinit(17, '\0') ; char *Indfmt = CVinit(17, '\0') ; char *Valfmt = CVinit(21, '\0') ; char *Rhsfmt = CVinit(21, '\0') ; char line[BUFSIZ]; if ( (in_file = fopen( filename, "r")) == NULL ) { fprintf(stderr,"Error: Cannot open file: %s\n",filename); return 0; } readHB_header(in_file, Title, Key, Type, &Nrow, &Ncol, &Nnzero, &Nrhs, Ptrfmt, Indfmt, Valfmt, Rhsfmt, &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype); /* Parse the array input formats from Line 3 of HB file */ ParseIfmt(Ptrfmt,&Ptrperline,&Ptrwidth); /* fprintf(stdout, "\n Ptrfmt = %s" "\n Ptrperline = %d" "\n Ptrwidth = %d", Ptrfmt, Ptrperline, Ptrwidth) ; */ ParseIfmt(Indfmt,&Indperline,&Indwidth); /* fprintf(stdout, "\n Indfmt = %s" "\n Indperline = %d" "\n Indwidth = %d", Indfmt, Indperline, Indwidth) ; */ if ( Type[0] != 'P' ) { /* Skip if pattern only */ ParseRfmt(Valfmt,&Valperline,&Valwidth,&Valprec,&Valflag); /* fprintf(stdout, "\n Valfmt = %s" "\n Valperline = %d" "\n Valwidth = %d" "\n Valprec = %d" "\n Valflag = %c", Valfmt, Valperline, Valwidth, Valprec, Valflag) ; */ } /* Read column pointer array: */ offset = 1-_SP_base; /* if base 0 storage is declared (via macro definition), */ /* then storage entries are offset by 1 */ ThisElement = (char *) malloc(Ptrwidth+1); if ( ThisElement == NULL ) IOHBTerminate("Insufficient memory for ThisElement."); *(ThisElement+Ptrwidth) = (char) NULL; count=0; for (i=0;i Ncol) break; strncpy(ThisElement,line+col,Ptrwidth); /* ThisElement = substr(line,col,Ptrwidth); */ colptr[count] = atoi(ThisElement)-offset; count++; col += Ptrwidth; } } free(ThisElement); /* Read row index array: */ ThisElement = (char *) malloc(Indwidth+1); if ( ThisElement == NULL ) IOHBTerminate("Insufficient memory for ThisElement."); *(ThisElement+Indwidth) = (char) NULL; count = 0; for (i=0;i=0;j--) { ThisElement[j] = ThisElement[j-1]; if ( ThisElement[j] == '+' || ThisElement[j] == '-' ) { ThisElement[j-1] = Valflag; break; } } } val[count] = atof(ThisElement); count++; col += Valwidth; } } free(ThisElement); } /* ------------------------- free the character arrays ------------------------- */ CVfree(Title) ; CVfree(Key) ; CVfree(Type) ; CVfree(Rhstype) ; CVfree(Ptrfmt) ; CVfree(Indfmt) ; CVfree(Valfmt) ; CVfree(Rhsfmt) ; fclose(in_file); return 1; } int readHB_newmat_double(const char* filename, int* M, int* N, int* nonzeros, int** colptr, int** rowind, double** val) { int Nrhs; char *Type; readHB_info(filename, M, N, nonzeros, &Type, &Nrhs); *colptr = (int *)malloc((*N+1)*sizeof(int)); if ( *colptr == NULL ) IOHBTerminate("Insufficient memory for colptr.\n"); *rowind = (int *)malloc(*nonzeros*sizeof(int)); if ( *rowind == NULL ) IOHBTerminate("Insufficient memory for rowind.\n"); if ( Type[0] == 'C' ) { /* fprintf(stderr, "Warning: Reading complex data from HB file %s.\n",filename); fprintf(stderr, " Real and imaginary parts will be interlaced in val[].\n"); */ /* Malloc enough space for real AND imaginary parts of val[] */ *val = (double *)malloc(*nonzeros*sizeof(double)*2); if ( *val == NULL ) IOHBTerminate("Insufficient memory for val.\n"); } else { if ( Type[0] != 'P' ) { /* Malloc enough space for real array val[] */ *val = (double *)malloc(*nonzeros*sizeof(double)); if ( *val == NULL ) IOHBTerminate("Insufficient memory for val.\n"); } } /* No val[] space needed if pattern only */ return readHB_mat_double(filename, *colptr, *rowind, *val); } int readHB_aux_double(const char* filename, const char AuxType, double b[]) { /****************************************************************************/ /* This function opens and reads the specified file, placing auxillary */ /* vector(s) of the given type (if available) in b. */ /* Return value is the number of vectors successfully read. */ /* */ /* AuxType = 'F' full right-hand-side vector(s) */ /* AuxType = 'G' initial Guess vector(s) */ /* AuxType = 'X' eXact solution vector(s) */ /* */ /* ---------- */ /* **CAVEAT** */ /* ---------- */ /* Parsing real formats from Fortran is tricky, and this file reader */ /* does not claim to be foolproof. It has been tested for cases when */ /* the real values are printed consistently and evenly spaced on each */ /* line, with Fixed (F), and Exponential (E or D) formats. */ /* */ /* ** If the input file does not adhere to the H/B format, the ** */ /* ** results will be unpredictable. ** */ /* */ /****************************************************************************/ FILE *in_file; int i,j,n,maxcol,start,stride,col,last,linel; int Ptrcrd, Indcrd, Valcrd, Rhscrd; int Nrow, Ncol, Nnzero, Nentries; int Nrhs, nvecs, rhsi; int Rhsperline, Rhswidth, Rhsprec; int Rhsflag; char *ThisElement; char Title[73], Key[9], Type[4], Rhstype[4]; char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21]; char line[BUFSIZ]; if ((in_file = fopen( filename, "r")) == NULL) { fprintf(stderr,"Error: Cannot open file: %s\n",filename); return 0; } readHB_header(in_file, Title, Key, Type, &Nrow, &Ncol, &Nnzero, &Nrhs, Ptrfmt, Indfmt, Valfmt, Rhsfmt, &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype); if (Nrhs <= 0) { fprintf(stderr, "Warn: Attempt to read auxillary vector(s) when none are present.\n"); return 0; } if (Rhstype[0] != 'F' ) { fprintf(stderr,"Warn: Attempt to read auxillary vector(s) which are not stored in Full form.\n"); fprintf(stderr," Rhs must be specified as full. \n"); return 0; } /* If reading complex data, allow for interleaved real and imaginary values. */ if ( Type[0] == 'C' ) { Nentries = 2*Nrow; } else { Nentries = Nrow; } nvecs = 1; if ( Rhstype[1] == 'G' ) nvecs++; if ( Rhstype[2] == 'X' ) nvecs++; if ( AuxType == 'G' && Rhstype[1] != 'G' ) { fprintf(stderr, "Warn: Attempt to read auxillary Guess vector(s) when none are present.\n"); return 0; } if ( AuxType == 'X' && Rhstype[2] != 'X' ) { fprintf(stderr, "Warn: Attempt to read auxillary eXact solution vector(s) when none are present.\n"); return 0; } ParseRfmt(Rhsfmt, &Rhsperline, &Rhswidth, &Rhsprec,&Rhsflag); maxcol = Rhsperline*Rhswidth; /* Lines to skip before starting to read RHS values... */ n = Ptrcrd + Indcrd + Valcrd; for (i = 0; i < n; i++) fgets(line, BUFSIZ, in_file); /* start - number of initial aux vector entries to skip */ /* to reach first vector requested */ /* stride - number of aux vector entries to skip between */ /* requested vectors */ if ( AuxType == 'F' ) start = 0; else if ( AuxType == 'G' ) start = Nentries; else start = (nvecs-1)*Nentries; stride = (nvecs-1)*Nentries; fgets(line, BUFSIZ, in_file); linel= strchr(line,'\n')-line; col = 0; /* Skip to initial offset */ for (i=0;i= ( maxcol= ( maxcol=0;j--) { ThisElement[j] = ThisElement[j-1]; if ( ThisElement[j] == '+' || ThisElement[j] == '-' ) { ThisElement[j-1] = Rhsflag; break; } } } b[i] = atof(ThisElement); col += Rhswidth; } /* Skip any interleaved Guess/eXact vectors */ for (i=0;i= ( maxcol 0 ) { if ( Rhsfmt == NULL ) Rhsfmt = Valfmt; ParseRfmt(Rhsfmt,&Rhsperline,&Rhswidth,&Rhsprec, &Rhsflag); if (Rhsflag == 'F') sprintf(rformat,"%% %d.%df",Rhswidth,Rhsprec); else sprintf(rformat,"%% %d.%dE",Rhswidth,Rhsprec); if (Rhsflag == 'D') *strchr(Rhsfmt,'D') = 'E'; rhscrd = nrhsentries/Rhsperline; if ( nrhsentries%Rhsperline != 0) rhscrd++; if ( Rhstype[1] == 'G' ) rhscrd+=rhscrd; if ( Rhstype[2] == 'X' ) rhscrd+=rhscrd; rhscrd*=Nrhs; } else rhscrd = 0; totcrd = 4+ptrcrd+indcrd+valcrd+rhscrd; /* Print header information: */ fprintf(out_file,"%-72s%-8s\n%14d%14d%14d%14d%14d\n",Title, Key, totcrd, ptrcrd, indcrd, valcrd, rhscrd); fprintf(out_file,"%3s%11s%14d%14d%14d\n",Type," ", M, N, nz); fprintf(out_file,"%-16s%-16s%-20s", Ptrfmt, Indfmt, Valfmt); if ( Nrhs != 0 ) { /* Print Rhsfmt on fourth line and */ /* optional fifth header line for auxillary vector information: */ fprintf(out_file,"%-20s\n%-14s%d\n",Rhsfmt,Rhstype,Nrhs); } else fprintf(out_file,"\n"); offset = 1-_SP_base; /* if base 0 storage is declared (via macro definition), */ /* then storage entries are offset by 1 */ /* Print column pointers: */ for (i=0;i 0 ) { for (i=0;i Ncol) break; strncpy(ThisElement,line+col,Ptrwidth); /*ThisElement = substr(line,col,Ptrwidth);*/ colptr[count] = atoi(ThisElement)-offset; count++; col += Ptrwidth; } } free(ThisElement); /* Read row index array: */ ThisElement = (char *) malloc(Indwidth+1); if ( ThisElement == NULL ) IOHBTerminate("Insufficient memory for ThisElement."); *(ThisElement+Indwidth) = (char) NULL; count = 0; for (i=0;i=0;j--) { ThisElement[j] = ThisElement[j-1]; if ( ThisElement[j] == '+' || ThisElement[j] == '-' ) { ThisElement[j-1] = Valflag; break; } } } count++; col += Valwidth; } } } return 1; } int readHB_newmat_char(const char* filename, int* M, int* N, int* nonzeros, int** colptr, int** rowind, char** val, char** Valfmt) { FILE *in_file; int Nrhs; int Ptrcrd, Indcrd, Valcrd, Rhscrd; int Valperline, Valwidth, Valprec; int Valflag; /* Indicates 'E','D', or 'F' float format */ char Title[73], Key[9], Type[4], Rhstype[4]; char Ptrfmt[17], Indfmt[17], Rhsfmt[21]; if ((in_file = fopen( filename, "r")) == NULL) { fprintf(stderr,"Error: Cannot open file: %s\n",filename); return 0; } *Valfmt = (char *)malloc(21*sizeof(char)); if ( *Valfmt == NULL ) IOHBTerminate("Insufficient memory for Valfmt."); readHB_header(in_file, Title, Key, Type, M, N, nonzeros, &Nrhs, Ptrfmt, Indfmt, (*Valfmt), Rhsfmt, &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype); fclose(in_file); ParseRfmt(*Valfmt,&Valperline,&Valwidth,&Valprec,&Valflag); *colptr = (int *)malloc((*N+1)*sizeof(int)); if ( *colptr == NULL ) IOHBTerminate("Insufficient memory for colptr.\n"); *rowind = (int *)malloc(*nonzeros*sizeof(int)); if ( *rowind == NULL ) IOHBTerminate("Insufficient memory for rowind.\n"); if ( Type[0] == 'C' ) { /* fprintf(stderr, "Warning: Reading complex data from HB file %s.\n",filename); fprintf(stderr, " Real and imaginary parts will be interlaced in val[].\n"); */ /* Malloc enough space for real AND imaginary parts of val[] */ *val = (char *)malloc(*nonzeros*Valwidth*sizeof(char)*2); if ( *val == NULL ) IOHBTerminate("Insufficient memory for val.\n"); } else { if ( Type[0] != 'P' ) { /* Malloc enough space for real array val[] */ *val = (char *)malloc(*nonzeros*Valwidth*sizeof(char)); if ( *val == NULL ) IOHBTerminate("Insufficient memory for val.\n"); } } /* No val[] space needed if pattern only */ return readHB_mat_char(filename, *colptr, *rowind, *val, *Valfmt); } int readHB_aux_char(const char* filename, const char AuxType, char b[]) { /****************************************************************************/ /* This function opens and reads the specified file, placing auxilary */ /* vector(s) of the given type (if available) in b : */ /* Return value is the number of vectors successfully read. */ /* */ /* AuxType = 'F' full right-hand-side vector(s) */ /* AuxType = 'G' initial Guess vector(s) */ /* AuxType = 'X' eXact solution vector(s) */ /* */ /* ---------- */ /* **CAVEAT** */ /* ---------- */ /* Parsing real formats from Fortran is tricky, and this file reader */ /* does not claim to be foolproof. It has been tested for cases when */ /* the real values are printed consistently and evenly spaced on each */ /* line, with Fixed (F), and Exponential (E or D) formats. */ /* */ /* ** If the input file does not adhere to the H/B format, the ** */ /* ** results will be unpredictable. ** */ /* */ /****************************************************************************/ FILE *in_file; int i,j,n,maxcol,start,stride,col,last,linel,nvecs,rhsi; int Nrow, Ncol, Nnzero, Nentries,Nrhs; int Ptrcrd, Indcrd, Valcrd, Rhscrd; int Rhsperline, Rhswidth, Rhsprec; int Rhsflag; char Title[73], Key[9], Type[4], Rhstype[4]; char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21]; char line[BUFSIZ]; char *ThisElement; if ((in_file = fopen( filename, "r")) == NULL) { fprintf(stderr,"Error: Cannot open file: %s\n",filename); return 0; } readHB_header(in_file, Title, Key, Type, &Nrow, &Ncol, &Nnzero, &Nrhs, Ptrfmt, Indfmt, Valfmt, Rhsfmt, &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype); if (Nrhs <= 0) { fprintf(stderr, "Warn: Attempt to read auxillary vector(s) when none are present.\n"); return 0; } if (Rhstype[0] != 'F' ) { fprintf(stderr,"Warn: Attempt to read auxillary vector(s) which are not stored in Full form.\n"); fprintf(stderr," Rhs must be specified as full. \n"); return 0; } /* If reading complex data, allow for interleaved real and imaginary values. */ if ( Type[0] == 'C' ) { Nentries = 2*Nrow; } else { Nentries = Nrow; } nvecs = 1; if ( Rhstype[1] == 'G' ) nvecs++; if ( Rhstype[2] == 'X' ) nvecs++; if ( AuxType == 'G' && Rhstype[1] != 'G' ) { fprintf(stderr, "Warn: Attempt to read auxillary Guess vector(s) when none are present.\n"); return 0; } if ( AuxType == 'X' && Rhstype[2] != 'X' ) { fprintf(stderr, "Warn: Attempt to read auxillary eXact solution vector(s) when none are present.\n"); return 0; } ParseRfmt(Rhsfmt, &Rhsperline, &Rhswidth, &Rhsprec,&Rhsflag); maxcol = Rhsperline*Rhswidth; /* Lines to skip before starting to read RHS values... */ n = Ptrcrd + Indcrd + Valcrd; for (i = 0; i < n; i++) fgets(line, BUFSIZ, in_file); /* start - number of initial aux vector entries to skip */ /* to reach first vector requested */ /* stride - number of aux vector entries to skip between */ /* requested vectors */ if ( AuxType == 'F' ) start = 0; else if ( AuxType == 'G' ) start = Nentries; else start = (nvecs-1)*Nentries; stride = (nvecs-1)*Nentries; fgets(line, BUFSIZ, in_file); linel= strchr(line,'\n')-line; if ( sscanf(line,"%*s") < 0 ) IOHBTerminate("iohb.c: Null (or blank) line in auxillary vector data region of HB file.\n"); col = 0; /* Skip to initial offset */ for (i=0;i= ( maxcol= ( maxcol=0;j--) { ThisElement[j] = ThisElement[j-1]; if ( ThisElement[j] == '+' || ThisElement[j] == '-' ) { ThisElement[j-1] = Rhsflag; break; } } } col += Rhswidth; } b+=Nentries*Rhswidth; /* Skip any interleaved Guess/eXact vectors */ for (i=0;i= ( maxcol 0 ) { if ( Rhsfmt == NULL ) Rhsfmt = Valfmt; ParseRfmt(Rhsfmt,&Rhsperline,&Rhswidth,&Rhsprec, &Rhsflag); sprintf(rformat,"%%%ds",Rhswidth); rhscrd = nrhsentries/Rhsperline; if ( nrhsentries%Rhsperline != 0) rhscrd++; if ( Rhstype[1] == 'G' ) rhscrd+=rhscrd; if ( Rhstype[2] == 'X' ) rhscrd+=rhscrd; rhscrd*=Nrhs; } else rhscrd = 0; totcrd = 4+ptrcrd+indcrd+valcrd+rhscrd; /* Print header information: */ fprintf(out_file,"%-72s%-8s\n%14d%14d%14d%14d%14d\n",Title, Key, totcrd, ptrcrd, indcrd, valcrd, rhscrd); fprintf(out_file,"%3s%11s%14d%14d%14d\n",Type," ", M, N, nz); fprintf(out_file,"%-16s%-16s%-20s", Ptrfmt, Indfmt, Valfmt); if ( Nrhs != 0 ) { /* Print Rhsfmt on fourth line and */ /* optional fifth header line for auxillary vector information: */ fprintf(out_file,"%-20s\n%-14s%d\n",Rhsfmt,Rhstype,Nrhs); } else fprintf(out_file,"\n"); offset = 1-_SP_base; /* if base 0 storage is declared (via macro definition), */ /* then storage entries are offset by 1 */ /* Print column pointers: */ for (i=0;i 0 ) { for (j=0;j static void upcase(char* S) { /* Convert S to uppercase */ int i,len; len = strlen(S); for (i=0;i< len;i++) S[i] = toupper(S[i]); } static void IOHBTerminate(char* message) { fprintf(stderr,message); exit(1); } /* For a description of the Harwell Boeing standard, see: */ /* Duff, et al., ACM TOMS Vol.15, No.1, March 1989 */ /* Utilities/src/newsort.c010064400020550007177000001453030653556130600165170ustar00clevecompmath00000400000006/* IVsort.c */ #include "../Utilities.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- The insert and quick sort methods in this file are based on Jon L. Bentley and M. Douglas McIlroy, "Engineering a sort function", Software -- Practice and Experience, vol 23(11), 1249-1265, November 1993. This quick sort method uses 1) a median of three medians to find a split value, and 2) split-end partitioning to handle many elements equal to the split value. ----------------------------------------------------------- */ /*--------------------------------------------------------------------*/ /* --------------------------------------- macros to make swapping elements easier --------------------------------------- */ #define I_SWAP(a,b) { \ itemp = ivec[(a)] ; \ ivec[(a)] = ivec[(b)] ; \ ivec[(b)] = itemp ; } #define I2_SWAP(a,b) { \ itemp = ivec1[(a)] ; \ ivec1[(a)] = ivec1[(b)] ; \ ivec1[(b)] = itemp ; \ itemp = ivec2[(a)] ; \ ivec2[(a)] = ivec2[(b)] ; \ ivec2[(b)] = itemp ; } #define ID_SWAP(a,b) { \ itemp = ivec[(a)] ; \ ivec[(a)] = ivec[(b)] ; \ ivec[(b)] = itemp ; \ dtemp = dvec[(a)] ; \ dvec[(a)] = dvec[(b)] ; \ dvec[(b)] = dtemp ; } #define I2D_SWAP(a,b) { \ itemp = ivec1[(a)] ; \ ivec1[(a)] = ivec1[(b)] ; \ ivec1[(b)] = itemp ; \ itemp = ivec2[(a)] ; \ ivec2[(a)] = ivec2[(b)] ; \ ivec2[(b)] = itemp ; \ dtemp = dvec[(a)] ; \ dvec[(a)] = dvec[(b)] ; \ dvec[(b)] = dtemp ; } #define IZ_SWAP(a,b) { \ itemp = ivec[(a)] ; \ ivec[(a)] = ivec[(b)] ; \ ivec[(b)] = itemp ; \ dtemp = zvec[2*(a)] ; \ zvec[2*(a)] = zvec[2*(b)] ; \ zvec[2*(b)] = dtemp ; \ dtemp = zvec[2*(a)+1] ; \ zvec[2*(a)+1] = zvec[2*(b)+1] ; \ zvec[2*(b)+1] = dtemp ; } #define I2Z_SWAP(a,b) { \ itemp = ivec1[(a)] ; \ ivec1[(a)] = ivec1[(b)] ; \ ivec1[(b)] = itemp ; \ itemp = ivec2[(a)] ; \ ivec2[(a)] = ivec2[(b)] ; \ ivec2[(b)] = itemp ; \ dtemp = zvec[2*(a)] ; \ zvec[2*(a)] = zvec[2*(b)] ; \ zvec[2*(b)] = dtemp ; \ dtemp = zvec[2*(a)+1] ; \ zvec[2*(a)+1] = zvec[2*(b)+1] ; \ zvec[2*(b)+1] = dtemp ; \ } #define D_SWAP(a,b) { \ dtemp = dvec[(a)] ; \ dvec[(a)] = dvec[(b)] ; \ dvec[(b)] = dtemp ; } #define D2_SWAP(a,b) { \ dtemp = dvec1[(a)] ; \ dvec1[(a)] = dvec1[(b)] ; \ dvec1[(b)] = dtemp ; \ dtemp = dvec2[(a)] ; \ dvec2[(a)] = dvec2[(b)] ; \ dvec2[(b)] = dtemp ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- static methods to choose partitions ----------------------------------- */ /* ---------------------------------------------------- static function, return the median of three integers ---------------------------------------------------- */ static int Imedian3 ( int i, int j, int k, int a[] ) { if ( a[i] < a[j] ) { /* a[i] < a[j] */ if ( a[j] < a[k] ) { /* a[i] < a[j] < a[k] */ return(j) ; } else if ( a[i] < a[k] ) { /* a[i] < a[k] <= a[j] */ return(k) ; } else { /* a[k] <= a[i] < a[j] */ return(i) ; } } else { /* a[j] <= a[i] */ if ( a[i] < a[k] ) { /* a[j] <= a[i] < a[k] */ return(i) ; } else if ( a[j] < a[k] ) { /* a[j] < a[k] <= a[i] */ return(k) ; } else { /* a[k] <= a[j] <= a[i] */ return(j) ; } } } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- static function, returns an approximation to the median value of a vector if n < 7 then returns a[n/2] else if n < 40 then returns median(a[0], a[n/2], a[n-1]) else returns median( median(a[0], a[s], a[2s]) median(a[n/2-s], a[n/2], a[n/2+s]) median(a[n-1-2s], a[n-1-s], a[n-1]) ) where s = n / 8 endif created -- 98jan28, cca --------------------------------------------------------- */ static int Icentervalue ( int n, int a[] ) { int i, j, k, s ; j = n / 2 ; if ( n > 7 ) { i = 0 ; k = n - 1 ; if ( n >= 40 ) { s = n / 8 ; i = Imedian3(i, i+s, i+s+s, a) ; j = Imedian3(j-s, j, j+s, a) ; k = Imedian3(k-s-s, k-s, k, a) ; } j = Imedian3(i, j, k, a) ; } return(a[j]) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- static function, return the median of three doubles ---------------------------------------------------- */ static int Dmedian3 ( int i, int j, int k, double a[] ) { if ( a[i] < a[j] ) { /* a[i] < a[j] */ if ( a[j] < a[k] ) { /* a[i] < a[j] < a[k] */ return(j) ; } else if ( a[i] < a[k] ) { /* a[i] < a[k] <= a[j] */ return(k) ; } else { /* a[k] <= a[i] < a[j] */ return(i) ; } } else { /* a[j] <= a[i] */ if ( a[i] < a[k] ) { /* a[j] <= a[i] < a[k] */ return(i) ; } else if ( a[j] < a[k] ) { /* a[j] < a[k] <= a[i] */ return(k) ; } else { /* a[k] <= a[j] <= a[i] */ return(j) ; } } } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- static function, returns an approximation to the median value of a vector if n < 7 then returns a[n/2] else if n < 40 then returns median(a[0], a[n/2], a[n-1]) else returns median( median(a[0], a[s], a[2s]) median(a[n/2-s], a[n/2], a[n/2+s]) median(a[n-1-2s], a[n-1-s], a[n-1]) ) where s = n / 8 endif created -- 98jan28, cca --------------------------------------------------------- */ static double Dcentervalue ( int n, double a[] ) { int i, j, k, s ; j = n / 2 ; if ( n > 7 ) { i = 0 ; k = n - 1 ; if ( n >= 40 ) { s = n / 8 ; i = Dmedian3(i, i+s, i+s+s, a) ; j = Dmedian3(j-s, j, j+s, a) ; k = Dmedian3(k-s-s, k-s, k, a) ; } j = Dmedian3(i, j, k, a) ; } return(a[j]) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------- methods to check if the int vector is in ascending or descending order ----------------------------------- */ /* ---------------------------------------------------- return 1 if elements in array are in ascending order return 0 otherwise created -- 98jan28, cca ---------------------------------------------------- */ int IVisascending ( int n, int ivec[] ) { if ( n <= 0 ) { return(0) ; } else if ( n == 1 ) { return(1) ; } else { int i ; for ( i = 1 ; i < n ; i++ ) { if ( ivec[i-1] > ivec[i] ) { return(0) ; } } return(1) ; } } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- return 1 if elements in array are in descending order return 0 otherwise created -- 98jan28, cca ----------------------------------------------------- */ int IVisdescending ( int n, int ivec[] ) { if ( n <= 0 ) { return(0) ; } else if ( n == 1 ) { return(1) ; } else { int i ; for ( i = 1 ; i < n ; i++ ) { if ( ivec[i-1] < ivec[i] ) { return(0) ; } } return(1) ; } } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- return 1 if elements in array are in ascending order return 0 otherwise created -- 98jan28, cca ---------------------------------------------------- */ int DVisascending ( int n, double dvec[] ) { if ( n <= 0 ) { return(0) ; } else if ( n == 1 ) { return(1) ; } else { int i ; for ( i = 1 ; i < n ; i++ ) { if ( dvec[i-1] > dvec[i] ) { return(0) ; } } return(1) ; } } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- return 1 if elements in array are in descending order return 0 otherwise created -- 98jan28, cca ----------------------------------------------------- */ int DVisdescending ( int n, double dvec[] ) { if ( n <= 0 ) { return(0) ; } else if ( n == 1 ) { return(1) ; } else { int i ; for ( i = 1 ; i < n ; i++ ) { if ( dvec[i-1] < dvec[i] ) { return(0) ; } } return(1) ; } } /*==== INSERT SORT METHODS ======================================*/ /* ---------------------------------------------------------------- sort an array of integers into ascending order using insert sort created -- 98jan28, cca ---------------------------------------------------------------- */ void IVisortUp ( int n, int ivec[] ) { int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec[j-1] > ivec[j] ; j-- ) { I_SWAP(j-1,j) ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- sort an array of integers into descending order using insert sort created -- 98jan28, cca ----------------------------------------------------------------- */ void IVisortDown ( int n, int ivec[] ) { int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec[j-1] < ivec[j] ; j-- ) { I_SWAP(j-1,j) ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ use insert sort to sort a pair or arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 4 3 1 2 5 created -- 98jan28, cca ------------------------------------------ */ void IV2isortUp ( int n, int ivec1[], int ivec2[] ) { int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec1[j-1] > ivec1[j] ; j-- ) { I2_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 9 8 5 3 2 ivec2[] = 5 2 1 3 4 created -- 98jan28, cca ------------------------------------------- */ void IV2isortDown ( int n, int ivec1[], int ivec2[] ) { int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec1[j-1] < ivec1[j] ; j-- ) { I2_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ use insert sort to sort a pair of arrays. on output the first is in ascending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 2 3 5 8 9 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------ */ void IVDVisortUp ( int n, int ivec[], double dvec[] ) { double dtemp ; int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec[j-1] > ivec[j] ; j-- ) { ID_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 9 8 5 3 2 dvec[] = 5.0 2.0 1.0 3.0 4.0 created -- 98jan28, cca ------------------------------------------- */ void IVDVisortDown ( int n, int ivec[], double dvec[] ) { double dtemp ; int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec[j-1] < ivec[j] ; j-- ) { ID_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ use insert sort to sort a trio of arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is a companion array dvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------ */ void IV2DVisortUp ( int n, int ivec1[], int ivec2[], double dvec[] ) { double dtemp ; int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec1[j-1] > ivec1[j] ; j-- ) { I2D_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- use insert sort to sort a trio or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is a companion array dvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------- */ void IV2DVisortDown ( int n, int ivec1[], int ivec2[], double dvec[] ) { double dtemp ; int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec1[j-1] < ivec1[j] ; j-- ) { I2D_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- use insert sort to sort a pair of arrays. on output the first is in ascending order. ivec[] is the array of keys zvec[] is the companion array of complex example, ivec[] = 5 8 3 2 9 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec[] = 2 3 5 8 9 zvec[] = (4.0,4.5) (3.0,3.5) (1.0,1.5) (2.0,2.5) (5.0,5.5) created -- 98jan28, cca ------------------------------------------------------------- */ void IVZVisortUp ( int n, int ivec[], double zvec[] ) { double dtemp ; int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec[j-1] > ivec[j] ; j-- ) { IZ_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys zvec[] is the companion array example, ivec[] = 5 8 3 2 9 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec[] = 9 8 5 3 2 zvec[] = (5.0,5.5) (2.0,2.5) (1.0,1.5) (3.0,3.5) (4.0,4.5) created -- 98jan28, cca ------------------------------------------------------------- */ void IVZVisortDown ( int n, int ivec[], double zvec[] ) { double dtemp ; int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec[j-1] < ivec[j] ; j-- ) { IZ_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- use insert sort to sort a trio of arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is a companion array zvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 zvec[] = (4.0,4.5) (3.0,3.5) (1.0,1.5) (2.0,2.5) (5.0,5.5) created -- 98jan28, cca -------------------------------------------------------------- */ void IV2ZVisortUp ( int n, int ivec1[], int ivec2[], double zvec[] ) { double dtemp ; int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec1[j-1] > ivec1[j] ; j-- ) { I2Z_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- use insert sort to sort a trio or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is a companion array zvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec1[] = 9 8 5 3 2 ivec2[] = 5 7 6 8 9 zvec[] = (5.0,5.5) (2.0,2.5) (1.0,1.5) (4.0,4.5) (4.0,4.5) created -- 98jan28, cca -------------------------------------------------------------- */ void IV2ZVisortDown ( int n, int ivec1[], int ivec2[], double zvec[] ) { double dtemp ; int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && ivec1[j-1] < ivec1[j] ; j-- ) { I2Z_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- sort an array of doubles into ascending order using insert sort created -- 98jan28, cca ---------------------------------------------------------------- */ void DVisortUp ( int n, double dvec[] ) { double dtemp ; int i, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && dvec[j-1] > dvec[j] ; j-- ) { D_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- sort an array of doubles into descending order using insert sort created -- 98jan28, cca ----------------------------------------------------------------- */ void DVisortDown ( int n, double dvec[] ) { double dtemp ; int i, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && dvec[j-1] < dvec[j] ; j-- ) { D_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ use insert sort to sort a pair or arrays. on output the first is in ascending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 2 3 5 8 9 dvec2[] = 4 3 1 2 5 created -- 98jan28, cca ------------------------------------------ */ void DV2isortUp ( int n, double dvec1[], double dvec2[] ) { double dtemp ; int i, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && dvec1[j-1] > dvec1[j] ; j-- ) { D2_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 9 8 5 3 2 dvec2[] = 5 2 1 3 4 created -- 98jan28, cca ------------------------------------------- */ void DV2isortDown ( int n, double dvec1[], double dvec2[] ) { double dtemp ; int i, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && dvec1[j-1] < dvec1[j] ; j-- ) { D2_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ use insert sort to sort a pair of arrays. on output the first is in ascending order. dvec[] is the array of keys ivec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 98jan28, cca ------------------------------------------ */ void DVIVisortUp ( int n, double dvec[], int ivec[] ) { double dtemp ; int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && dvec[j-1] > dvec[j] ; j-- ) { ID_SWAP(j-1,j) } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- use insert sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 98jan28, cca ------------------------------------------- */ void DVIVisortDown ( int n, double dvec[], int ivec[] ) { double dtemp ; int i, itemp, j ; for ( i = 1 ; i < n ; i++ ) { for ( j = i ; j > 0 && dvec[j-1] < dvec[j] ; j-- ) { ID_SWAP(j-1,j) } } return ; } /*==== QUICKSORT METHODS ========================================*/ /* --------------------------------------------------------------- sort an array of integers into ascending order using quick sort created -- 98jan28, cca --------------------------------------------------------------- */ void IVqsortUp ( int n, int ivec[] ) { int a, b, c, d, itemp, l, h, s, v ; if ( n <= 10 ) { IVisortUp(n, ivec) ; } else { v = Icentervalue(n, ivec) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec[b] <= v ) { if ( ivec[b] == v ) { I_SWAP(a,b) ; a++ ; } b++ ; } while ( c >= b && ivec[c] >= v ) { if ( ivec[c] == v ) { I_SWAP(c,d) ; d-- ; } c-- ; } if ( b > c ) { break ; } I_SWAP(b,c) ; b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { I_SWAP(l,h) ; l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { I_SWAP(l,h) ; l++ ; h++ ; } IVqsortUp(b - a, ivec) ; IVqsortUp(d - c, ivec + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- sort an array of integers into descending order using quick sort created -- 98jan28, cca ---------------------------------------------------------------- */ void IVqsortDown ( int n, int ivec[] ) { int a, b, c, d, itemp, l, h, s, v ; if ( n <= 10 ) { IVisortDown(n, ivec) ; } else { v = Icentervalue(n, ivec) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec[b] >= v ) { if ( ivec[b] == v ) { I_SWAP(a,b) ; a++ ; } b++ ; } while ( c >= b && ivec[c] <= v ) { if ( ivec[c] == v ) { I_SWAP(c,d) ; d-- ; } c-- ; } if ( b > c ) { break ; } I_SWAP(b,c) ; b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { I_SWAP(l,h) ; l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { I_SWAP(l,h) ; l++ ; h++ ; } IVqsortDown(b - a, ivec) ; IVqsortDown(d - c, ivec + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 4 3 1 2 5 created -- 98jan28, cca ------------------------------------------ */ void IV2qsortUp ( int n, int ivec1[], int ivec2[] ) { int a, b, c, d, itemp, l, h, s, v ; if ( n <= 10 ) { IV2isortUp(n, ivec1, ivec2) ; } else { v = Icentervalue(n, ivec1) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec1[b] <= v ) { if ( ivec1[b] == v ) { I2_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && ivec1[c] >= v ) { if ( ivec1[c] == v ) { I2_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } I2_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { I2_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { I2_SWAP(l,h) l++ ; h++ ; } IV2qsortUp(b - a, ivec1, ivec2) ; IV2qsortUp(d - c, ivec1 + n - (d - c), ivec2 + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is the companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 1 2 3 4 5 becomes ivec1[] = 9 8 5 3 2 ivec2[] = 5 2 1 3 4 created -- 98jan28, cca ------------------------------------------- */ void IV2qsortDown ( int n, int ivec1[], int ivec2[] ) { int a, b, c, d, itemp, l, h, s, v ; if ( n <= 10 ) { IV2isortDown(n, ivec1, ivec2) ; } else { v = Icentervalue(n, ivec1) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec1[b] >= v ) { if ( ivec1[b] == v ) { I2_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && ivec1[c] <= v ) { if ( ivec1[c] == v ) { I2_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } I2_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { I2_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { I2_SWAP(l,h) l++ ; h++ ; } IV2qsortDown(b - a, ivec1, ivec2) ; IV2qsortDown(d - c, ivec1 + n - (d - c), ivec2 + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 2 3 5 8 9 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------ */ void IVDVqsortUp ( int n, int ivec[], double dvec[] ) { double dtemp ; int a, b, c, d, itemp, l, h, s, v ; if ( n <= 10 ) { IVDVisortUp(n, ivec, dvec) ; } else { v = Icentervalue(n, ivec) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec[b] <= v ) { if ( ivec[b] == v ) { ID_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && ivec[c] >= v ) { if ( ivec[c] == v ) { ID_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } ID_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { ID_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { ID_SWAP(l,h) l++ ; h++ ; } IVDVqsortUp(b - a, ivec, dvec) ; IVDVqsortUp(d - c, ivec + n - (d - c), dvec + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 5 8 3 2 9 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec[] = 9 8 5 3 2 dvec[] = 5.0 2.0 1.0 3.0 4.0 created -- 98jan28, cca ------------------------------------------- */ void IVDVqsortDown ( int n, int ivec[], double dvec[] ) { double dtemp ; int a, b, c, d, itemp, l, h, s, v ; if ( n <= 10 ) { IVDVisortDown(n, ivec, dvec) ; } else { v = Icentervalue(n, ivec) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec[b] >= v ) { if ( ivec[b] == v ) { ID_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && ivec[c] <= v ) { if ( ivec[c] == v ) { ID_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } ID_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { ID_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { ID_SWAP(l,h) l++ ; h++ ; } IVDVqsortDown(b - a, ivec, dvec) ; IVDVqsortDown(d - c, ivec + n - (d - c), dvec + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ use quick sort to sort a trio or arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is a companion array dvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------ */ void IV2DVqsortUp ( int n, int ivec1[], int ivec2[], double dvec[] ) { double dtemp ; int a, b, c, d, itemp, l, h, s, v ; if ( n <= 10 ) { IV2DVisortUp(n, ivec1, ivec2, dvec) ; } else { v = Icentervalue(n, ivec1) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec1[b] <= v ) { if ( ivec1[b] == v ) { I2D_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && ivec1[c] >= v ) { if ( ivec1[c] == v ) { I2D_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } I2D_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { I2D_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { I2D_SWAP(l,h) l++ ; h++ ; } IV2DVqsortUp(b - a, ivec1, ivec2, dvec) ; IV2DVqsortUp(d - c, ivec1 + n - (d - c), ivec2 + n - (d - c), dvec + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- use quick sort to sort a trio or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is a companion array dvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 dvec[] = 1.0 2.0 3.0 4.0 5.0 becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 dvec[] = 4.0 3.0 1.0 2.0 5.0 created -- 98jan28, cca ------------------------------------------- */ void IV2DVqsortDown ( int n, int ivec1[], int ivec2[], double dvec[] ) { double dtemp ; int a, b, c, d, itemp, l, h, s, v ; if ( n <= 10 ) { IV2DVisortDown(n, ivec1, ivec2, dvec) ; } else { v = Icentervalue(n, ivec1) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec1[b] >= v ) { if ( ivec1[b] == v ) { I2D_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && ivec1[c] <= v ) { if ( ivec1[c] == v ) { I2D_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } I2D_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { I2D_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { I2D_SWAP(l,h) l++ ; h++ ; } IV2DVqsortDown(b - a, ivec1, ivec2, dvec) ; IV2DVqsortDown(d - c, ivec1 + n - (d - c), ivec2 + n - (d - c), dvec + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in ascending order. ivec[] is the array of keys zvec[] is the companion array example, ivec[] = 5 8 3 2 9 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec[] = 2 3 5 8 9 zvec[] = (4.0,4.5) (3.0,3.5) (1.0,1.5) (2.0,2.5) (5.0,5.5) created -- 98jan28, cca ------------------------------------------------------------- */ void IVZVqsortUp ( int n, int ivec[], double zvec[] ) { double dtemp ; int a, b, c, d, itemp, l, h, s, v ; if ( n <= 10 ) { IVZVisortUp(n, ivec, zvec) ; } else { v = Icentervalue(n, ivec) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec[b] <= v ) { if ( ivec[b] == v ) { IZ_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && ivec[c] >= v ) { if ( ivec[c] == v ) { IZ_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } IZ_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { IZ_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { IZ_SWAP(l,h) l++ ; h++ ; } IVZVqsortUp(b - a, ivec, zvec) ; IVZVqsortUp(d - c, ivec + n - (d - c), zvec + 2*(n - (d - c))) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys zvec[] is the companion array example, ivec[] = 5 8 3 2 9 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec[] = 9 8 5 3 2 zvec[] = (5.0,5.5) (2.0,2.5) (1.0,1.5) (3.0,3.5) (4.0,4.5) created -- 98jan28, cca ------------------------------------------------------------- */ void IVZVqsortDown ( int n, int ivec[], double zvec[] ) { double dtemp ; int a, b, c, d, itemp, l, h, s, v ; if ( n <= 10 ) { IVZVisortDown(n, ivec, zvec) ; } else { v = Icentervalue(n, ivec) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec[b] >= v ) { if ( ivec[b] == v ) { IZ_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && ivec[c] <= v ) { if ( ivec[c] == v ) { IZ_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } IZ_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { IZ_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { IZ_SWAP(l,h) l++ ; h++ ; } IVZVqsortDown(b - a, ivec, zvec) ; IVZVqsortDown(d - c, ivec + n - (d - c), zvec + 2*(n - (d - c))) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- use quick sort to sort a trio or arrays. on output the first is in ascending order. ivec1[] is the array of keys ivec2[] is a companion array zvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec1[] = 2 3 5 8 9 ivec2[] = 9 8 6 7 5 zvec[] = (4.0,4.5) (3.0,3.5) (1.0,1.5) (2.0,2.5) (5.0,5.5) created -- 98jan28, cca -------------------------------------------------------------- */ void IV2ZVqsortUp ( int n, int ivec1[], int ivec2[], double zvec[] ) { double dtemp ; int a, b, c, d, itemp, l, h, s, v ; if ( n <= 10 ) { IV2ZVisortUp(n, ivec1, ivec2, zvec) ; } else { v = Icentervalue(n, ivec1) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec1[b] <= v ) { if ( ivec1[b] == v ) { I2Z_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && ivec1[c] >= v ) { if ( ivec1[c] == v ) { I2Z_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } I2Z_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { I2Z_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { I2Z_SWAP(l,h) l++ ; h++ ; } IV2ZVqsortUp(b - a, ivec1, ivec2, zvec) ; IV2ZVqsortUp(d - c, ivec1 + n - (d - c), ivec2 + n - (d - c), zvec + 2*(n - (d - c))) ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------- use quick sort to sort a trio or arrays. on output the first is in descending order. ivec1[] is the array of keys ivec2[] is a companion array zvec[] is a companion array example, ivec1[] = 5 8 3 2 9 ivec2[] = 6 7 8 9 5 zvec[] = (1.0,1.5) (2.0,2.5) (3.0,3.5) (4.0,4.5) (5.0,5.5) becomes ivec1[] = 9 8 5 3 2 ivec2[] = 5 7 6 8 9 zvec[] = (5.0,5.5) (2.0,2.5) (1.0,1.5) (4.0,4.5) (4.0,4.5) created -- 98jan28, cca -------------------------------------------------------------- */ void IV2ZVqsortDown ( int n, int ivec1[], int ivec2[], double zvec[] ) { double dtemp ; int a, b, c, d, itemp, l, h, s, v ; if ( n <= 0 ) { IV2ZVisortDown(n, ivec1, ivec2, zvec) ; } else { v = Icentervalue(n, ivec1) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && ivec1[b] >= v ) { if ( ivec1[b] == v ) { I2Z_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && ivec1[c] <= v ) { if ( ivec1[c] == v ) { I2Z_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } I2Z_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { I2Z_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { I2Z_SWAP(l,h) l++ ; h++ ; } IV2ZVqsortDown(b - a, ivec1, ivec2, zvec) ; IV2ZVqsortDown(d - c, ivec1 + n - (d - c), ivec2 + n - (d - c), zvec + 2*(n - (d - c))) ; } return ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- sort an array of doubles into ascending order using quick sort created -- 98jan28, cca --------------------------------------------------------------- */ void DVqsortUp ( int n, double dvec[] ) { double dtemp, v ; int a, b, c, d, l, h, s ; if ( n <= 10 ) { DVisortUp(n, dvec) ; } else { v = Dcentervalue(n, dvec) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && dvec[b] <= v ) { if ( dvec[b] == v ) { D_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && dvec[c] >= v ) { if ( dvec[c] == v ) { D_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } D_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { D_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { D_SWAP(l,h) l++ ; h++ ; } DVqsortUp(b - a, dvec) ; DVqsortUp(d - c, dvec + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------------------- sort an array of doubles into descending order using quick sort created -- 98jan28, cca ---------------------------------------------------------------- */ void DVqsortDown ( int n, double dvec[] ) { double dtemp, v ; int a, b, c, d, l, h, s ; if ( n <= 10 ) { DVisortDown(n, dvec) ; } else { v = Dcentervalue(n, dvec) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && dvec[b] >= v ) { if ( dvec[b] == v ) { D_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && dvec[c] <= v ) { if ( dvec[c] == v ) { D_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } D_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { D_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { D_SWAP(l,h) l++ ; h++ ; } DVqsortDown(b - a, dvec) ; DVqsortDown(d - c, dvec + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 2 3 5 8 9 dvec2[] = 4 3 1 2 5 created -- 98jan28, cca ------------------------------------------ */ void DV2qsortUp ( int n, double dvec1[], double dvec2[] ) { double dtemp, v ; int a, b, c, d, l, h, s ; if ( n <= 10 ) { DV2isortUp(n, dvec1, dvec2) ; } else { v = Dcentervalue(n, dvec1) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && dvec1[b] <= v ) { if ( dvec1[b] == v ) { D2_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && dvec1[c] >= v ) { if ( dvec1[c] == v ) { D2_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } D2_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { D2_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { D2_SWAP(l,h) l++ ; h++ ; } DV2qsortUp(b - a, dvec1, dvec2) ; DV2qsortUp(d - c, dvec1 + n - (d - c), dvec2 + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. dvec1[] is the array of keys dvec2[] is the companion array example, dvec1[] = 5 8 3 2 9 dvec2[] = 1 2 3 4 5 becomes dvec1[] = 9 8 5 3 2 dvec2[] = 5 2 1 3 4 created -- 98jan28, cca ------------------------------------------- */ void DV2qsortDown ( int n, double dvec1[], double dvec2[] ) { double dtemp, v ; int a, b, c, d, l, h, s ; if ( n <= 10 ) { DV2isortDown(n, dvec1, dvec2) ; } else { v = Dcentervalue(n, dvec1) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && dvec1[b] >= v ) { if ( dvec1[b] == v ) { D2_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && dvec1[c] <= v ) { if ( dvec1[c] == v ) { D2_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } D2_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { D2_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { D2_SWAP(l,h) l++ ; h++ ; } DV2qsortDown(b - a, dvec1, dvec2) ; DV2qsortDown(d - c, dvec1 + n - (d - c), dvec2 + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ use quick sort to sort a pair or arrays. on output the first is in ascending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 98jan28, cca ------------------------------------------ */ void DVIVqsortUp ( int n, double dvec[], int ivec[] ) { double dtemp, v ; int a, b, c, d, itemp, l, h, s ; if ( n <= 10 ) { DVIVisortUp(n, dvec, ivec) ; } else { v = Dcentervalue(n, dvec) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && dvec[b] <= v ) { if ( dvec[b] == v ) { ID_SWAP(a,b) ; a++ ; } b++ ; } while ( c >= b && dvec[c] >= v ) { if ( dvec[c] == v ) { ID_SWAP(c,d) ; d-- ; } c-- ; } if ( b > c ) { break ; } ID_SWAP(b,c) ; b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { ID_SWAP(l,h) ; l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { ID_SWAP(l,h) ; l++ ; h++ ; } DVIVqsortUp(b - a, dvec, ivec) ; DVIVqsortUp(d - c, dvec + n - (d - c), ivec + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- use quick sort to sort a pair or arrays. on output the first is in descending order. ivec[] is the array of keys dvec[] is the companion array example, ivec[] = 4 2 7 5 6 dvec[] = 5.0 8.0 3.0 2.0 9.0 becomes ivec[] = 5 7 4 2 6 dvec[] = 2.0 3.0 5.0 8.0 9.0 created -- 98jan28, cca ------------------------------------------- */ void DVIVqsortDown ( int n, double dvec[], int ivec[] ) { double dtemp, v ; int a, b, c, d, itemp, l, h, s ; if ( n <= 10 ) { DVIVisortDown(n, dvec, ivec) ; } else { v = Dcentervalue(n, dvec) ; a = b = 0 ; c = d = n - 1 ; for ( ; ; ) { while ( b <= c && dvec[b] >= v ) { if ( dvec[b] == v ) { ID_SWAP(a,b) a++ ; } b++ ; } while ( c >= b && dvec[c] <= v ) { if ( dvec[c] == v ) { ID_SWAP(c,d) d-- ; } c-- ; } if ( b > c ) { break ; } ID_SWAP(b,c) b++ ; c-- ; } s = (a <= b - a) ? a : b - a ; for ( l = 0, h = b - s ; s != 0 ; s-- ) { ID_SWAP(l,h) l++ ; h++ ; } s = ((d - c) <= (n - 1 - d)) ? (d - c) : ( n - 1 - d) ; for ( l = b, h = n - s ; s != 0 ; s-- ) { ID_SWAP(l,h) l++ ; h++ ; } DVIVqsortDown(b - a, dvec, ivec) ; DVIVqsortDown(d - c, dvec + n - (d - c), ivec + n - (d - c)) ; } return ; } /*--------------------------------------------------------------------*/ -- 98jan28, cca -------------------------------------------------------------- */ void IV2ZVqsortDown ( int n, int ivec1[], int ivec2[], double zvec[] ) { double dtemp ; int a, b, c, d, itemp, l, h, s, v ; if ( n <= 0 ) { IV2ZVisortDown(n, ivec1, ivec2, zvec) ; } else { Utilities/src/sortAndCompress.c010064400020550007177000000266450653556211000201450ustar00clevecompmath00000400000006/* sortutil.c */ #include "../Utilities.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------ sort the entries in ivec[] into ascending order, then compress out the duplicates return value -- # of compressed entries created -- 97dec18, cca ------------------------------------------------ */ int IVsortUpAndCompress ( int n, int ivec[] ) { int first, ierr, ii, key ; /* --------------- check the input --------------- */ if ( n < 0 || ivec == NULL ) { fprintf(stderr, "\n fatal error in IVsortAndCompress(%d,%p)" "\n bad input, n = %d, ivec = %p", n, ivec, n, ivec) ; exit(-1) ; } if ( n == 0 ) { return(0) ; } /* ---------------------------------- sort the vector in ascending order ---------------------------------- */ IVqsortUp(n, ivec) ; #if MYDEBUG > 0 fprintf(stdout, "\n ivec[] after sort up") ; IVfp80(stdout, n, ivec, 80, &ierr) ; #endif /* -------------------- purge the duplicates -------------------- */ first = 1 ; key = ivec[0] ; #if MYDEBUG > 0 fprintf(stdout, "\n first = %d, key = %d, ivec[%d] = %d", first, key, 0, ivec[0]) ; #endif for ( ii = 1 ; ii < n ; ii++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n first = %d, key = %d, ivec[%d] = %d", first, key, 0, ivec[0]) ; #endif if ( key != ivec[ii] ) { #if MYDEBUG > 0 fprintf(stdout, "\n setting ivec[%d] = %d", first, ivec[ii]) ; #endif ivec[first++] = key = ivec[ii] ; } } return(first) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ sort the entries in ivec[] into ascending order, using dvec[] as a companion vector. then compress out the duplicates integer keys, summing the double values return value -- # of compressed entries created -- 97dec18, cca ------------------------------------------------ */ int IVDVsortUpAndCompress ( int n, int ivec[], double dvec[] ) { int first, ierr, ii, key ; /* --------------- check the input --------------- */ if ( n < 0 || ivec == NULL || dvec == NULL) { fprintf(stderr, "\n fatal error in IVDVsortAndCompress(%d,%p,%p)" "\n bad input, n = %d, ivec = %p, dvec = %p", n, ivec, dvec, n, ivec, dvec) ; exit(-1) ; } if ( n == 0 ) { return(0) ; } /* --------------------------------- sort ivec[] in ascending order with dvec[] as a companion vector --------------------------------- */ IVDVqsortUp(n, ivec, dvec) ; #if MYDEBUG > 0 fprintf(stdout, "\n ivec[] after sort up") ; IVfp80(stdout, n, ivec, 80, &ierr) ; fprintf(stdout, "\n dvec[] after sort up") ; DVfprintf(stdout, n, dvec) ; #endif first = 1 ; key = ivec[0] ; #if MYDEBUG > 0 fprintf(stdout, "\n first = %d, key = %d, ivec[%d] = %d", first, key, 0, ivec[0]) ; #endif for ( ii = 1 ; ii < n ; ii++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n first = %d, key = %d, ivec[%d] = %d", first, key, 0, ivec[0]) ; #endif if ( key == ivec[ii] ) { dvec[first-1] += dvec[ii] ; } else if ( key != ivec[ii] ) { #if MYDEBUG > 0 fprintf(stdout, "\n setting ivec[%d] = %d", first, ivec[ii]) ; #endif ivec[first] = key = ivec[ii] ; dvec[first] = dvec[ii] ; first++ ; } } return(first) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ sort the entries in ivec[] into ascending order, using zvec[] as a complex companion vector. then compress out the duplicates integer keys, summing the complex values return value -- # of compressed entries created -- 98jan28, cca ------------------------------------------------ */ int IVZVsortUpAndCompress ( int n, int ivec[], double zvec[] ) { int first, ierr, ii, key ; /* --------------- check the input --------------- */ if ( n < 0 || ivec == NULL || zvec == NULL) { fprintf(stderr, "\n fatal error in IVZVsortAndCompress(%d,%p,%p)" "\n bad input, n = %d, ivec = %p, zvec = %p", n, ivec, zvec, n, ivec, zvec) ; exit(-1) ; } if ( n == 0 ) { return(0) ; } /* --------------------------------- sort ivec[] in ascending order with zvec[] as a companion vector --------------------------------- */ IVZVqsortUp(n, ivec, zvec) ; #if MYDEBUG > 0 fprintf(stdout, "\n ivec[] after sort up") ; IVfp80(stdout, n, ivec, 80, &ierr) ; fprintf(stdout, "\n zvec[] after sort up") ; DVfprintf(stdout, 2*n, zvec) ; #endif first = 1 ; key = ivec[0] ; #if MYDEBUG > 0 fprintf(stdout, "\n first = %d, key = %d, ivec[%d] = %d", first, key, 0, ivec[0]) ; #endif for ( ii = 1 ; ii < n ; ii++ ) { #if MYDEBUG > 0 fprintf(stdout, "\n first = %d, key = %d, ivec[%d] = %d", first, key, 0, ivec[0]) ; #endif if ( key == ivec[ii] ) { zvec[2*(first-1)] += zvec[2*ii] ; zvec[2*(first-1)+1] += zvec[2*ii+1] ; } else if ( key != ivec[ii] ) { #if MYDEBUG > 0 fprintf(stdout, "\n setting ivec[%d] = %d", first, ivec[ii]) ; #endif ivec[first] = key = ivec[ii] ; zvec[2*first] = zvec[2*ii] ; zvec[2*first+1] = zvec[2*ii+1] ; first++ ; } } return(first) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------------- sort the entries in ivec1[] and ivec2[] into lexicographic order, then compress out the duplicates return value -- # of compressed entries created -- 97dec18, cca ----------------------------------------------------------------- */ int IV2sortUpAndCompress ( int n, int ivec1[], int ivec2[] ) { int first, ierr, ii, key, length, start ; /* --------------- check the input --------------- */ if ( n < 0 || ivec1 == NULL || ivec2 == NULL) { fprintf(stderr, "\n fatal error in IV2sortAndCompress(%d,%p,%p)" "\n bad input, n = %d, ivec1 = %p, ivec2 = %p", n, ivec1, ivec2, n, ivec1, ivec2) ; exit(-1) ; } if ( n == 0 ) { return(0) ; } /* ------------------------------------------------------------------ sort ivec1[] in ascending order with ivec2[] as a companion vector ------------------------------------------------------------------ */ IV2qsortUp(n, ivec1, ivec2) ; #if MYDEBUG > 0 fprintf(stdout, "\n ivec1[] after sort up") ; IVfp80(stdout, n, ivec1, 80, &ierr) ; fprintf(stdout, "\n ivec2[] after sort up") ; IVfp80(stdout, n, ivec2, 80, &ierr) ; #endif first = start = 0 ; key = ivec1[0] ; for ( ii = 1 ; ii < n ; ii++ ) { if ( key != ivec1[ii] ) { length = IVsortUpAndCompress(ii - start, ivec2 + start) ; IVfill(length, ivec1 + first, key) ; IVcopy(length, ivec2 + first, ivec2 + start) ; start = ii ; first += length ; key = ivec1[ii] ; } } length = IVsortUpAndCompress(n - start, ivec2 + start) ; IVfill(length, ivec1 + first, key) ; IVcopy(length, ivec2 + first, ivec2 + start) ; first += length ; return(first) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- sort the entries in ivec1[] and ivec2[] into lexicographic order, using dvec[] as a companion vector. then compress out the duplicates and sum the same values of dvec[] return value -- # of compressed entries created -- 97dec18, cca -------------------------------------------------------------------- */ int IV2DVsortUpAndCompress ( int n, int ivec1[], int ivec2[], double dvec[] ) { int first, ierr, ii, key, length, start ; /* --------------- check the input --------------- */ if ( n < 0 || ivec1 == NULL || ivec2 == NULL || dvec == NULL ) { fprintf(stderr, "\n fatal error in IV2DVsortAndCompress(%d,%p,%p,%p)" "\n bad input, n = %d, ivec1 = %p, ivec2 = %p, dvec = %p", n, ivec1, ivec2, dvec, n, ivec1, ivec2, dvec) ; exit(-1) ; } if ( n == 0 ) { return(0) ; } /* --------------------------------------- sort ivec1[] in ascending order with ivec2[] and dvec[] as companion vectors --------------------------------------- */ IV2DVqsortUp(n, ivec1, ivec2, dvec) ; #if MYDEBUG > 0 fprintf(stdout, "\n ivec1[] after sort up") ; IVfp80(stdout, n, ivec1, 80, &ierr) ; fprintf(stdout, "\n ivec2[] after sort up") ; IVfp80(stdout, n, ivec2, 80, &ierr) ; fprintf(stdout, "\n dvec[] after sort up") ; DVfprintf(stdout, n, dvec) ; #endif first = start = 0 ; key = ivec1[0] ; for ( ii = 1 ; ii < n ; ii++ ) { if ( key != ivec1[ii] ) { length = IVDVsortUpAndCompress(ii - start, ivec2 + start, dvec + start) ; IVfill(length, ivec1 + first, key) ; IVcopy(length, ivec2 + first, ivec2 + start) ; DVcopy(length, dvec + first, dvec + start) ; start = ii ; first += length ; key = ivec1[ii] ; } } length = IVDVsortUpAndCompress(n - start, ivec2 + start, dvec + start) ; IVfill(length, ivec1 + first, key) ; IVcopy(length, ivec2 + first, ivec2 + start) ; DVcopy(length, dvec + first, dvec + start) ; first += length ; return(first) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------------------- sort the entries in ivec1[] and ivec2[] into lexicographic order, using zvec[] as a companion vector. then compress out the duplicates and sum the same values of zvec[] return value -- # of compressed entries created -- 98jan28, cca -------------------------------------------------------------------- */ int IV2ZVsortUpAndCompress ( int n, int ivec1[], int ivec2[], double zvec[] ) { int first, ierr, ii, key, length, start ; /* --------------- check the input --------------- */ if ( n < 0 || ivec1 == NULL || ivec2 == NULL || zvec == NULL ) { fprintf(stderr, "\n fatal error in IV2ZVsortAndCompress(%d,%p,%p,%p)" "\n bad input, n = %d, ivec1 = %p, ivec2 = %p, zvec = %p", n, ivec1, ivec2, zvec, n, ivec1, ivec2, zvec) ; exit(-1) ; } if ( n == 0 ) { return(0) ; } /* --------------------------------------- sort ivec1[] in ascending order with ivec2[] and zvec[] as companion vectors --------------------------------------- */ IV2ZVqsortUp(n, ivec1, ivec2, zvec) ; #if MYDEBUG > 0 fprintf(stdout, "\n\n after IV2ZVqsortUp") ; for ( ii = 0 ; ii < n ; ii++ ) { fprintf(stdout, "\n < %12d, %12d, %12.4e, %12.4e >", ivec1[ii], ivec2[ii], zvec[2*ii], zvec[2*ii+1]) ; } #endif first = start = 0 ; key = ivec1[0] ; for ( ii = 1 ; ii < n ; ii++ ) { if ( key != ivec1[ii] ) { length = IVZVsortUpAndCompress(ii - start, ivec2 + start, zvec + 2*start) ; IVfill(length, ivec1 + first, key) ; IVcopy(length, ivec2 + first, ivec2 + start) ; DVcopy(2*length, zvec + 2*first, zvec + 2*start) ; start = ii ; first += length ; key = ivec1[ii] ; } } length = IVZVsortUpAndCompress(n - start, ivec2 + start, zvec + 2*start) ; IVfill(length, ivec1 + first, key) ; IVcopy(length, ivec2 + first, ivec2 + start) ; DVcopy(2*length, zvec + 2*first, zvec + 2*start) ; first += length ; return(first) ; } /*--------------------------------------------------------------------*/ ----------------------- sort the entries in ivec1[] and ivec2[] into lexicographic orderUtilities/drivers/do_test_sort010075500020550007177000000006250663603073500201730ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res set msgFile = stdout set target = IV set sortType = QU set n = 100 set nrange = 9999999 set mod = 9999999 set seed = 10101 foreach target ( IV IV2 IVDV IV2DV IVZV IV2ZV DV DVIV DV2 ) # foreach sortType ( IU ID QU QD ) foreach sortType ( QU QD ) test_sort $msglvl $msgFile $target $sortType $n $nrange $mod $seed end end Utilities/drivers/do_test_sortUpAndCompress010075500020550007177000000004560653560177000226420ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = res set msgFile = stdout set target = IV set n = 100 set nrange = 9999999 set mod = 9999999 set seed = 10101 foreach target ( IV IV2 IVDV IV2DV IVZV IV2ZV ) test_sortUpAndCompress $msglvl $msgFile $target $n $nrange $mod $seed end Utilities/drivers/makefile010064400020550007177000000007110665314266600172370ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = test_sort test_sortUpAndCompress drivers : ${DRIVERS} clean : - rm -f $.a *.o ${DRIVERS} test_sort : test_sort.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} test_sortUpAndCompress : test_sortUpAndCompress.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} Utilities/drivers/test_sort.c010064400020550007177000000620470653410575100177330ustar00clevecompmath00000400000006/* test_sort.c */ #include "../Utilities.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------------ purpose -- to test the sort routines created -- 98jan28, cca usage : test_sort msglvl msgFile target sortType n range mod seed msglvl -- message level msglvl == 1 --> just timings msglvl > 1 --> vector(s) before and after sort msgFile -- message file target -- domain of sort IV -- int vector sorts IV2 -- (int,int) vector sorts IVDV -- (int,double) vector sorts IV2DV -- (int,int,double) vector sorts IVZV -- (int,complex) vector sorts IV2ZV -- (int,int,complex) vector sorts DV -- double vector sorts DV2 -- (double,double) vector sorts DVIV -- (double,int) vector sorts sortType -- type of sort IU -- ascending insert sort ID -- descending insert sort QU -- asscending quick sort QD -- descending quick sort n -- length of vector(s) range -- entries are in [1, range] mod -- entries in vectors are uniform(0,n-1) % mod seed -- seed for random number generator ------------------------------------------------------------------ */ { char *sortType, *target ; double t1, t2 ; Drand drand ; FILE *msgFile ; int i, ierr, msglvl, mod, n, range, rc, seed ; if ( argc != 9 ) { fprintf(stdout, "\n usage : %s msglvl msgFile target sortType n range mod seed" "\n msglvl -- message level" "\n msglvl == 1 --> just timings" "\n msglvl > 1 --> vector(s) before and after sort" "\n msgFile -- message file" "\n target -- domain of sort" "\n IV -- int vector sorts" "\n IV2 -- (int,int) vector sorts" "\n IVDV -- (int,double) vector sorts" "\n IV2DV -- (int,int,double) vector sorts" "\n IVZV -- (int,complex) vector sorts" "\n IV2ZV -- (int,int,complex) vector sorts" "\n DV -- double vector sorts" "\n DV2 -- (double,double) vector sorts" "\n DVIV -- (double,int) vector sorts" "\n sortType -- type of sort" "\n IU -- ascending insert sort" "\n ID -- descending insert sort" "\n QU -- asscending quick sort" "\n QD -- descending quick sort" "\n n -- length of vector(s)" "\n range -- entries in vectors are uniform(1,range) %% mod" "\n mod -- entries in vectors are uniform(1,range) %% mod" "\n seed -- seed for random number generator" "\n", argv[0]) ; exit(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp("stdout", argv[2]) == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; exit(-1) ; } target = argv[3] ; sortType = argv[4] ; n = atoi(argv[5]) ; range = atoi(argv[6]) ; mod = atoi(argv[7]) ; seed = atoi(argv[8]) ; fprintf(msgFile, "\n\n ### target = %s, sortType = %s, n = %d", target, sortType, n) ; /* ------------------------- switch over the sort type ------------------------- */ Drand_setDefaultFields(&drand) ; if ( strcmp(target, "IV") == 0 ) { /* ------ IVsort ------ */ int *ivec1 ; ivec1 = IVinit2(n) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 1, range+1) ; Drand_fillIvector(&drand, n, ivec1) ; for ( i = 0 ; i < n ; i++ ) { ivec1[i] = ivec1[i] % mod ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n IVsort") ; fprintf(msgFile, "\n initial vector") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n ") ; fflush(msgFile) ; } if ( strcmp(sortType, "IU") == 0 ) { MARKTIME(t1) ; IVisortUp(n, ivec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d integers via IVisortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "ID") == 0 ) { MARKTIME(t1) ; IVisortDown(n, ivec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d integers via IVisortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } if ( strcmp(sortType, "QU") == 0 ) { MARKTIME(t1) ; IVqsortUp(n, ivec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d integers via IVqsortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "QD") == 0 ) { MARKTIME(t1) ; IVqsortDown(n, ivec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d integers via IVqsortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } if ( rc == 0 ) { fprintf(msgFile, "\n vector not sorted correctly") ; } else { fprintf(msgFile, "\n vector sorted correctly") ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted vector") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n ") ; } } else if ( strcmp(target, "IV2") == 0 ) { /* ------- IV2sort ------- */ double sig1, sig2 ; int *ivec1, *ivec2 ; ivec1 = IVinit2(n) ; ivec2 = IVinit2(n) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 1, range+1) ; Drand_fillIvector(&drand, n, ivec1) ; Drand_fillIvector(&drand, n, ivec2) ; for ( i = 0 ; i < n ; i++ ) { ivec1[i] = ivec1[i] % mod ; ivec2[i] = ivec2[i] % mod ; } for ( i = 0, sig1 = 0.0 ; i < n ; i++ ) { sig1 += ivec1[i]*ivec2[i] ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n IV2sort, sig1 = %12.4e", sig1) ; fprintf(msgFile, "\n initial ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n initial ivec2") ; IVfp80(msgFile, n, ivec2, 80, &ierr) ; fprintf(msgFile, "\n ") ; fflush(msgFile) ; } if ( strcmp(sortType, "IU") == 0 ) { MARKTIME(t1) ; IV2isortUp(n, ivec1, ivec2) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d integers via IV2isortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "ID") == 0 ) { MARKTIME(t1) ; IV2isortDown(n, ivec1, ivec2) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d integers via IV2isortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } if ( strcmp(sortType, "QU") == 0 ) { MARKTIME(t1) ; IV2qsortUp(n, ivec1, ivec2) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d integers via IV2qsortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "QD") == 0 ) { MARKTIME(t1) ; IV2qsortDown(n, ivec1, ivec2) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d integers via IV2qsortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } for ( i = 0, sig2 = 0.0 ; i < n ; i++ ) { sig2 += ivec1[i]*ivec2[i] ; } if ( rc == 0 ) { fprintf(msgFile, "\n vector not sorted correctly") ; } else { fprintf(msgFile, "\n vector sorted correctly") ; } fprintf(msgFile, "\n sig1 = %12.4e, sig2 = %12.4e, error/sig1 = %12.4e\n", sig1, sig2, (sig1 - sig2)/sig1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n companion ivec2") ; IVfp80(msgFile, n, ivec2, 80, &ierr) ; fprintf(msgFile, "\n ") ; } } else if ( strcmp(target, "IVDV") == 0 ) { /* -------- IVDVsort -------- */ double sig1, sig2 ; double *dvec ; int *ivec1 ; ivec1 = IVinit2(n) ; dvec = DVinit2(n) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 1, range+1) ; Drand_fillIvector(&drand, n, ivec1) ; Drand_setUniform(&drand, 0.0, 1.0) ; Drand_fillDvector(&drand, n, dvec) ; for ( i = 0 ; i < n ; i++ ) { ivec1[i] = ivec1[i] % mod ; } for ( i = 0, sig1 = 0.0 ; i < n ; i++ ) { sig1 += ivec1[i]*dvec[i] ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n IVDVsort, sig1 = %12.4e", sig1) ; fprintf(msgFile, "\n initial ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n initial dvec") ; DVfprintf(msgFile, n, dvec) ; fprintf(msgFile, "\n ") ; fflush(msgFile) ; } if ( strcmp(sortType, "IU") == 0 ) { MARKTIME(t1) ; IVDVisortUp(n, ivec1, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IVDVisortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "ID") == 0 ) { MARKTIME(t1) ; IVDVisortDown(n, ivec1, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IVDVisortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } if ( strcmp(sortType, "QU") == 0 ) { MARKTIME(t1) ; IVDVqsortUp(n, ivec1, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IVDVqsortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "QD") == 0 ) { MARKTIME(t1) ; IVDVqsortDown(n, ivec1, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IVDVqsortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } for ( i = 0, sig2 = 0.0 ; i < n ; i++ ) { sig2 += ivec1[i]*dvec[i] ; } if ( rc == 0 ) { fprintf(msgFile, "\n vector not sorted correctly") ; } else { fprintf(msgFile, "\n vector sorted correctly") ; } fprintf(msgFile, "\n sig1 = %12.4e, sig2 = %12.4e, error/sig1 = %12.4e\n", sig1, sig2, (sig1 - sig2)/sig1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n companion dvec") ; DVfprintf(msgFile, n, dvec) ; fprintf(msgFile, "\n ") ; } } else if ( strcmp(target, "IV2DV") == 0 ) { /* --------- IV2DVsort --------- */ double sig1, sig2 ; double *dvec ; int *ivec1, *ivec2 ; ivec1 = IVinit2(n) ; ivec2 = IVinit2(n) ; dvec = DVinit2(n) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 1, range+1) ; Drand_fillIvector(&drand, n, ivec1) ; Drand_fillIvector(&drand, n, ivec2) ; Drand_setUniform(&drand, 0.0, 1.0) ; Drand_fillDvector(&drand, n, dvec) ; for ( i = 0 ; i < n ; i++ ) { ivec1[i] = ivec1[i] % mod ; ivec2[i] = ivec2[i] % mod ; } for ( i = 0, sig1 = 0.0 ; i < n ; i++ ) { sig1 += ivec1[i]*ivec2[i]*dvec[i] ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n IV2DVsort, sig1 = %12.4e", sig1) ; fprintf(msgFile, "\n initial ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n initial ivec2") ; IVfp80(msgFile, n, ivec2, 80, &ierr) ; fprintf(msgFile, "\n initial dvec") ; DVfprintf(msgFile, n, dvec) ; fprintf(msgFile, "\n ") ; fflush(msgFile) ; } if ( strcmp(sortType, "IU") == 0 ) { MARKTIME(t1) ; IV2DVisortUp(n, ivec1, ivec2, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IV2DVisortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "ID") == 0 ) { MARKTIME(t1) ; IV2DVisortDown(n, ivec1, ivec2, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IV2DVisortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } if ( strcmp(sortType, "QU") == 0 ) { MARKTIME(t1) ; IV2DVqsortUp(n, ivec1, ivec2, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IV2DVqsortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "QD") == 0 ) { MARKTIME(t1) ; IV2DVqsortDown(n, ivec1, ivec2, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IV2DVqsortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } for ( i = 0, sig2 = 0.0 ; i < n ; i++ ) { sig2 += ivec1[i]*ivec2[i]*dvec[i] ; } if ( rc == 0 ) { fprintf(msgFile, "\n vector not sorted correctly") ; } else { fprintf(msgFile, "\n vector sorted correctly") ; } fprintf(msgFile, "\n sig1 = %12.4e, sig2 = %12.4e, error/sig1 = %12.4e\n", sig1, sig2, (sig1 - sig2)/sig1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n companion ivec2") ; IVfp80(msgFile, n, ivec2, 80, &ierr) ; fprintf(msgFile, "\n companion dvec") ; DVfprintf(msgFile, n, dvec) ; fprintf(msgFile, "\n ") ; } } else if ( strcmp(target, "IVZV") == 0 ) { /* -------- IVZVsort -------- */ double sig1, sig2 ; double *dvec ; int *ivec1 ; ivec1 = IVinit2(n) ; dvec = DVinit2(2*n) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 1, range+1) ; Drand_fillIvector(&drand, n, ivec1) ; Drand_setUniform(&drand, 0.0, 1.0) ; Drand_fillDvector(&drand, 2*n, dvec) ; for ( i = 0 ; i < n ; i++ ) { ivec1[i] = ivec1[i] % mod ; } for ( i = 0, sig1 = 0.0 ; i < n ; i++ ) { sig1 += ivec1[i]*dvec[2*i]*dvec[2*i+1] ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n IVZVsort, sig1 = %12.4e", sig1) ; fprintf(msgFile, "\n initial ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n initial dvec") ; DVfprintf(msgFile, 2*n, dvec) ; fprintf(msgFile, "\n ") ; fflush(msgFile) ; } if ( strcmp(sortType, "IU") == 0 ) { MARKTIME(t1) ; IVZVisortUp(n, ivec1, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IVZVisortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "ID") == 0 ) { MARKTIME(t1) ; IVZVisortDown(n, ivec1, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IVZVisortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } if ( strcmp(sortType, "QU") == 0 ) { MARKTIME(t1) ; IVZVqsortUp(n, ivec1, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IVZVqsortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "QD") == 0 ) { MARKTIME(t1) ; IVZVqsortDown(n, ivec1, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IVZVqsortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } for ( i = 0, sig2 = 0.0 ; i < n ; i++ ) { sig2 += ivec1[i]*dvec[2*i]*dvec[2*i+1] ; } if ( rc == 0 ) { fprintf(msgFile, "\n vector not sorted correctly") ; } else { fprintf(msgFile, "\n vector sorted correctly") ; } fprintf(msgFile, "\n sig1 = %12.4e, sig2 = %12.4e, error/sig1 = %12.4e\n", sig1, sig2, (sig1 - sig2)/sig1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n companion dvec") ; DVfprintf(msgFile, 2*n, dvec) ; fprintf(msgFile, "\n ") ; } } else if ( strcmp(target, "IV2ZV") == 0 ) { /* --------- IV2ZVsort --------- */ double sig1, sig2 ; double *dvec ; int *ivec1, *ivec2 ; ivec1 = IVinit2(n) ; ivec2 = IVinit2(n) ; dvec = DVinit2(2*n) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 1, range+1) ; Drand_fillIvector(&drand, n, ivec1) ; Drand_fillIvector(&drand, n, ivec2) ; Drand_setUniform(&drand, 0.0, 1.0) ; Drand_fillDvector(&drand, 2*n, dvec) ; for ( i = 0 ; i < n ; i++ ) { ivec1[i] = ivec1[i] % mod ; ivec2[i] = ivec2[i] % mod ; } for ( i = 0, sig1 = 0.0 ; i < n ; i++ ) { sig1 += ivec1[i]*ivec2[i]*dvec[2*i]*dvec[2*i+1] ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n IV2ZVsort, sig1 = %12.4e", sig1) ; fprintf(msgFile, "\n initial ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n initial ivec2") ; IVfp80(msgFile, n, ivec2, 80, &ierr) ; fprintf(msgFile, "\n initial dvec") ; DVfprintf(msgFile, 2*n, dvec) ; fprintf(msgFile, "\n ") ; fflush(msgFile) ; } if ( strcmp(sortType, "IU") == 0 ) { MARKTIME(t1) ; IV2ZVisortUp(n, ivec1, ivec2, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IV2ZVisortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "ID") == 0 ) { MARKTIME(t1) ; IV2ZVisortDown(n, ivec1, ivec2, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IV2ZVisortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } if ( strcmp(sortType, "QU") == 0 ) { MARKTIME(t1) ; IV2ZVqsortUp(n, ivec1, ivec2, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IV2ZVqsortUp\n", t2 - t1, n) ; rc = IVisascending(n, ivec1) ; } else if ( strcmp(sortType, "QD") == 0 ) { MARKTIME(t1) ; IV2ZVqsortDown(n, ivec1, ivec2, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via IV2ZVqsortDown\n", t2 - t1, n) ; rc = IVisdescending(n, ivec1) ; } for ( i = 0, sig2 = 0.0 ; i < n ; i++ ) { sig2 += ivec1[i]*ivec2[i]*dvec[2*i]*dvec[2*i+1] ; } if ( rc == 0 ) { fprintf(msgFile, "\n vector not sorted correctly") ; } else { fprintf(msgFile, "\n vector sorted correctly") ; } fprintf(msgFile, "\n sig1 = %12.4e, sig2 = %12.4e, error/sig1 = %12.4e\n", sig1, sig2, (sig1 - sig2)/sig1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n companion ivec2") ; IVfp80(msgFile, n, ivec2, 80, &ierr) ; fprintf(msgFile, "\n companion dvec") ; DVfprintf(msgFile, 2*n, dvec) ; fprintf(msgFile, "\n ") ; } } else if ( strcmp(target, "DV") == 0 ) { /* ------ DVsort ------ */ double *dvec ; dvec = DVinit2(n) ; Drand_setSeed(&drand, seed) ; Drand_fillDvector(&drand, n, dvec) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n DVsort") ; fprintf(msgFile, "\n initial vector") ; DVfprintf(msgFile, n, dvec) ; fprintf(msgFile, "\n ") ; fflush(msgFile) ; } if ( strcmp(sortType, "IU") == 0 ) { MARKTIME(t1) ; DVisortUp(n, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via DVisortUp\n", t2 - t1, n) ; rc = DVisascending(n, dvec) ; } else if ( strcmp(sortType, "ID") == 0 ) { MARKTIME(t1) ; DVisortDown(n, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via DVisortDown\n", t2 - t1, n) ; rc = DVisdescending(n, dvec) ; } if ( strcmp(sortType, "QU") == 0 ) { MARKTIME(t1) ; DVqsortUp(n, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via DVqsortUp\n", t2 - t1, n) ; rc = DVisascending(n, dvec) ; } else if ( strcmp(sortType, "QD") == 0 ) { MARKTIME(t1) ; DVqsortDown(n, dvec) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via DVqsortDown\n", t2 - t1, n) ; rc = DVisdescending(n, dvec) ; } if ( rc == 0 ) { fprintf(msgFile, "\n vector not sorted correctly") ; } else { fprintf(msgFile, "\n vector sorted correctly") ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted vector") ; DVfprintf(msgFile, n, dvec) ; fprintf(msgFile, "\n ") ; } } else if ( strcmp(target, "DVIV") == 0 ) { /* ------- DVIVsort ------- */ double sig1, sig2 ; double *dvec ; int *ivec1 ; ivec1 = IVinit2(n) ; dvec = DVinit2(n) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 1, range+1) ; Drand_fillIvector(&drand, n, ivec1) ; Drand_setUniform(&drand, 0, 1) ; Drand_fillDvector(&drand, n, dvec) ; for ( i = 0 ; i < n ; i++ ) { ivec1[i] = ivec1[i] % mod ; } for ( i = 0, sig1 = 0.0 ; i < n ; i++ ) { sig1 += ivec1[i]*dvec[i] ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n DVIVsort, sig1 = %12.4e", sig1) ; fprintf(msgFile, "\n initial ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n initial dvec") ; DVfprintf(msgFile, n, dvec) ; fprintf(msgFile, "\n ") ; fflush(msgFile) ; } if ( strcmp(sortType, "IU") == 0 ) { MARKTIME(t1) ; DVIVisortUp(n, dvec, ivec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via DVIVisortUp\n", t2 - t1, n) ; rc = DVisascending(n, dvec) ; } else if ( strcmp(sortType, "ID") == 0 ) { MARKTIME(t1) ; DVIVisortDown(n, dvec, ivec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d integers via DVIVisortDown\n", t2 - t1, n) ; rc = DVisdescending(n, dvec) ; } if ( strcmp(sortType, "QU") == 0 ) { MARKTIME(t1) ; DVIVqsortUp(n, dvec, ivec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d integers via DVIVqsortUp\n", t2 - t1, n) ; rc = DVisascending(n, dvec) ; } else if ( strcmp(sortType, "QD") == 0 ) { MARKTIME(t1) ; DVIVqsortDown(n, dvec, ivec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d integers via DVIVqsortDown\n", t2 - t1, n) ; rc = DVisdescending(n, dvec) ; } for ( i = 0, sig2 = 0.0 ; i < n ; i++ ) { sig2 += ivec1[i]*dvec[i] ; } if ( rc == 0 ) { fprintf(msgFile, "\n vector not sorted correctly") ; } else { fprintf(msgFile, "\n vector sorted correctly") ; } fprintf(msgFile, "\n sig1 = %12.4e, sig2 = %12.4e, error/sig1 = %12.4e\n", sig1, sig2, (sig1 - sig2)/sig1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted dvec") ; DVfprintf(msgFile, n, dvec) ; fprintf(msgFile, "\n companion ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n ") ; } } else if ( strcmp(target, "DV2") == 0 ) { /* ------- DV2sort ------- */ double sig1, sig2 ; double *dvec1, *dvec2 ; dvec1 = DVinit2(n) ; dvec2 = DVinit2(n) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0, 1) ; Drand_fillDvector(&drand, n, dvec1) ; Drand_fillDvector(&drand, n, dvec2) ; for ( i = 0, sig1 = 0.0 ; i < n ; i++ ) { sig1 += dvec1[i]*dvec2[i] ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n DV2sort, sig1 = %12.4e", sig1) ; fprintf(msgFile, "\n initial dvec1") ; DVfprintf(msgFile, n, dvec2) ; fprintf(msgFile, "\n initial dvec2") ; DVfprintf(msgFile, n, dvec2) ; fprintf(msgFile, "\n ") ; fflush(msgFile) ; } if ( strcmp(sortType, "IU") == 0 ) { MARKTIME(t1) ; DV2isortUp(n, dvec1, dvec2) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via DV2isortUp\n", t2 - t1, n) ; rc = DVisascending(n, dvec1) ; } else if ( strcmp(sortType, "ID") == 0 ) { MARKTIME(t1) ; DV2isortDown(n, dvec1, dvec2) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via DV2isortDown\n", t2 - t1, n) ; rc = DVisdescending(n, dvec1) ; } if ( strcmp(sortType, "QU") == 0 ) { MARKTIME(t1) ; DV2qsortUp(n, dvec1, dvec2) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via DV2qsortUp\n", t2 - t1, n) ; rc = DVisascending(n, dvec1) ; } else if ( strcmp(sortType, "QD") == 0 ) { MARKTIME(t1) ; DV2qsortDown(n, dvec1, dvec2) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : sort %d via DV2qsortDown\n", t2 - t1, n) ; rc = DVisdescending(n, dvec1) ; } for ( i = 0, sig2 = 0.0 ; i < n ; i++ ) { sig2 += dvec1[i]*dvec2[i] ; } if ( rc == 0 ) { fprintf(msgFile, "\n vector not sorted correctly") ; } else { fprintf(msgFile, "\n vector sorted correctly") ; } fprintf(msgFile, "\n sig1 = %12.4e, sig2 = %12.4e, error/sig1 = %12.4e\n", sig1, sig2, (sig1 - sig2)/sig1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted dvec1") ; DVfprintf(msgFile, n, dvec1) ; fprintf(msgFile, "\n companion ivec2") ; DVfprintf(msgFile, n, dvec2) ; fprintf(msgFile, "\n ") ; } } exit(0) ; } /*--------------------------------------------------------------------*/ = 0.0 ; i < n ; i++ ) { sig2 += ivec1[i]*dvec[2*i]*dvec[2*i+1] ; } if ( rc == 0 ) { fprintf(msgFile, "\n vector not sorted correctly") ; } else { fprintf(msgFile, "\n vector sorted correctly") ; } fprintf(msgFile, "\n sig1 = %12.4e, sig2 = %12.4e, error/sig1 = %12.4e\n", sig1, sig2, (sig1 - sig2)/sig1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted ivec1") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ;Utilities/drivers/test_sortUpAndCompress.c010064400020550007177000000334540653560112500223740ustar00clevecompmath00000400000006/* test_sortAndCompress.c */ #include "../Utilities.h" #include "../../Drand.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------------------ purpose -- to test the sort routines created -- 98jan28, cca usage : test_sortAndCompress msglvl msgFile target n range mod seed msglvl -- message level msglvl == 1 --> just timings msglvl > 1 --> vector(s) before and after sort msgFile -- message file target -- domain of sort IV -- int vector sorts IV2 -- (int,int) vector sorts IVDV -- (int,double) vector sorts IV2DV -- (int,int,double) vector sorts IVZV -- (int,complex) vector sorts IV2ZV -- (int,int,complex) vector sorts n -- length of vector(s) range -- entries are in [1, range] mod -- entries in vectors are uniform(0,n-1) % mod seed -- seed for random number generator ------------------------------------------------------------------ */ { char *target ; double t1, t2 ; Drand drand ; FILE *msgFile ; int i, ierr, ii, key1, key2, jj, msglvl, mod, n, nnew, range, rc, seed ; if ( argc != 8 ) { fprintf(stdout, "\n usage : %s msglvl msgFile target n range mod seed" "\n msglvl -- message level" "\n msglvl == 1 --> just timings" "\n msglvl > 1 --> vector(s) before and after sort" "\n msgFile -- message file" "\n target -- domain of sort" "\n IV -- int vector sorts" "\n IV2 -- (int,int) vector sorts" "\n IVDV -- (int,double) vector sorts" "\n IV2DV -- (int,int,double) vector sorts" "\n IVZV -- (int,complex) vector sorts" "\n IV2ZV -- (int,int,complex) vector sorts" "\n DV -- double vector sorts" "\n DV2 -- (double,double) vector sorts" "\n DVIV -- (double,int) vector sorts" "\n n -- length of vector(s)" "\n range -- entries in vectors are uniform(1,range) %% mod" "\n mod -- entries in vectors are uniform(1,range) %% mod" "\n seed -- seed for random number generator" "\n", argv[0]) ; exit(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp("stdout", argv[2]) == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n unable to open file %s\n", argv[2]) ; exit(-1) ; } target = argv[3] ; n = atoi(argv[4]) ; range = atoi(argv[5]) ; mod = atoi(argv[6]) ; seed = atoi(argv[7]) ; fprintf(msgFile, "\n\n ### target = %s, n = %d", target, n) ; /* ------------------------- switch over the sort type ------------------------- */ Drand_setDefaultFields(&drand) ; if ( strcmp(target, "IV") == 0 ) { /* ------------------- IVsortUpAndCompress ------------------- */ int *ivec1 ; ivec1 = IVinit2(n) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 1, range+1) ; Drand_fillIvector(&drand, n, ivec1) ; for ( i = 0 ; i < n ; i++ ) { ivec1[i] = ivec1[i] % mod ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n IVsortAndCompress") ; fprintf(msgFile, "\n initial vector") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n ") ; fflush(msgFile) ; } MARKTIME(t1) ; nnew = IVsortUpAndCompress(n, ivec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : time to sort and compress %d entries", t2 - t1, n) ; fprintf(msgFile, "\n %d entries in compressed vector", nnew) ; rc = IVisascending(n, ivec1) ; if ( rc == 0 ) { fprintf(msgFile, "\n vector not sorted correctly") ; } else { fprintf(msgFile, "\n vector sorted correctly") ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n sorted vector") ; IVfp80(msgFile, n, ivec1, 80, &ierr) ; fprintf(msgFile, "\n ") ; } } else if ( strcmp(target, "IV2") == 0 ) { /* -------------------- IV2sortUpAndCompress -------------------- */ int *ivec1, *ivec2, *ivec3, *ivec4 ; Drand_setDefaultFields(&drand) ; ivec1 = IVinit2(n) ; ivec2 = IVinit2(n) ; ivec3 = IVinit2(n) ; ivec4 = IVinit2(n) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0, n-1) ; Drand_fillIvector(&drand, n, ivec1) ; Drand_fillIvector(&drand, n, ivec2) ; for ( ii = 0 ; ii < n ; ii++ ) { ivec1[ii] = ivec1[ii] % mod ; ivec2[ii] = ivec2[ii] % mod ; ivec3[ii] = ivec1[ii] ; ivec4[ii] = ivec2[ii] ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n %d initial pairs", n) ; for ( ii = 0 ; ii < n ; ii++ ) { fprintf(msgFile, "\n < %12d, %12d >", ivec1[ii], ivec2[ii]) ; } fflush(msgFile) ; } MARKTIME(t1) ; nnew = IV2sortUpAndCompress(n, ivec1, ivec2) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : IV2sortUpAndCompress", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d sorted and compressed pairs", nnew) ; for ( ii = 0 ; ii < nnew ; ii++ ) { fprintf(msgFile, "\n < %12d, %12d >", ivec1[ii], ivec2[ii]) ; } fflush(msgFile) ; } for ( ii = 0 ; ii < n ; ii++ ) { key1 = ivec3[ii] ; key2 = ivec4[ii] ; for ( jj = 0 ; jj < nnew ; jj++ ) { if ( key1 == ivec1[jj] && key2 == ivec2[jj] ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n <%d,%d> found in entry %d", key1, key2, jj) ; } break ; } } if ( jj == nnew ) { fprintf(msgFile, "\n error, <%d,%d> not found in compressed list", key1, key2) ; } } } else if ( strcmp(target, "IVDV") == 0 ) { /* --------------------- IVDVsortUpAndCompress --------------------- */ int *ivec1 = IVinit2(n) ; int *ivec2 = IVinit2(n) ; double *dvec1 = DVinit2(n) ; double *dvec2 = DVinit2(n) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0, n-1) ; Drand_fillIvector(&drand, n, ivec1) ; DVfill(n, dvec1, 1.0) ; Drand_fillDvector(&drand, n, dvec1) ; IVcopy(n, ivec2, ivec1) ; DVcopy(n, dvec2, dvec1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d initial pairs", n) ; for ( ii = 0 ; ii < n ; ii++ ) { fprintf(msgFile, "\n < %12d, %12.4e >", ivec1[ii], dvec1[ii]) ; } fflush(msgFile) ; } MARKTIME(t1) ; nnew = IVDVsortUpAndCompress(n, ivec1, dvec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : IVDVsortUpAndCompress time", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d final pairs", nnew) ; for ( ii = 0 ; ii < nnew ; ii++ ) { fprintf(msgFile, "\n < %12d, %12.4e >", ivec1[ii], dvec1[ii]) ; } fflush(msgFile) ; } for ( ii = 0 ; ii < n ; ii++ ) { key1 = ivec2[ii] ; for ( jj = 0 ; jj < nnew ; jj++ ) { if ( key1 == ivec1[jj] ) { dvec1[jj] -= dvec2[ii] ; break ; } } if ( jj == nnew ) { fprintf(msgFile, "\n pair < %d,%f> not found", ivec2[ii], dvec2[ii]) ; } } fprintf(msgFile, "\n error norm = %12.4e", DVmaxabs(nnew, dvec1, &ii)) ; fprintf(msgFile, "\n dvec1[]") ; DVfprintf(msgFile, nnew, dvec1) ; } else if ( strcmp(target, "IV2DV") == 0 ) { /* ---------------------- IV2DVsortUpAndCompress ---------------------- */ int *ivec1 = IVinit2(n) ; int *ivec2 = IVinit2(n) ; int *ivec3 = IVinit2(n) ; int *ivec4 = IVinit2(n) ; double *dvec1 = DVinit2(n) ; double *dvec2 = DVinit2(n) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0, n-1) ; Drand_fillIvector(&drand, n, ivec1) ; Drand_fillIvector(&drand, n, ivec2) ; Drand_setUniform(&drand, 0, 1) ; Drand_fillDvector(&drand, n, dvec1) ; for ( ii = 0 ; ii < n ; ii++ ) { ivec1[ii] = ivec1[ii] % mod ; ivec2[ii] = ivec2[ii] % mod ; } IVcopy(n, ivec3, ivec1) ; IVcopy(n, ivec4, ivec2) ; DVcopy(n, dvec2, dvec1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d initial triples", n) ; for ( ii = 0 ; ii < n ; ii++ ) { fprintf(msgFile, "\n < %12d, %12d, %12.4e >", ivec1[ii], ivec2[ii], dvec1[ii]) ; } fflush(msgFile) ; } MARKTIME(t1) ; nnew = IV2DVsortUpAndCompress(n, ivec1, ivec2, dvec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : IV2DVsortUpAndCompress, n = %d, nnew = %d", t2 - t1, n, nnew) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d sorted and compressed triples", nnew) ; for ( ii = 0 ; ii < nnew ; ii++ ) { fprintf(msgFile, "\n < %12d, %12d, %12.4e >", ivec1[ii], ivec2[ii], dvec1[ii]) ; } fflush(msgFile) ; } for ( ii = 0 ; ii < n ; ii++ ) { key1 = ivec3[ii] ; key2 = ivec4[ii] ; for ( jj = 0 ; jj < nnew ; jj++ ) { if ( key1 == ivec1[jj] && key2 == ivec2[jj] ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n <%d,%d> found in entry %d", key1, key2, jj) ; } dvec1[jj] -= dvec2[ii] ; break ; } } if ( jj == nnew ) { fprintf(msgFile, "\n error, <%d,%d> not found in compressed list", key1, key2) ; } } fprintf(msgFile, "\n max error = %12.4e\n", DVmaxabs(nnew, dvec1, &ii)) ; if ( msglvl > 1 ) { DVfprintf(msgFile, nnew, dvec1) ; } } else if ( strcmp(target, "IV2ZV") == 0 ) { /* ---------------------- IV2ZVsortUpAndCompress ---------------------- */ int *ivec1 = IVinit2(n) ; int *ivec2 = IVinit2(n) ; int *ivec3 = IVinit2(n) ; int *ivec4 = IVinit2(n) ; double *dvec1 = DVinit2(2*n) ; double *dvec2 = DVinit2(2*n) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0, n-1) ; Drand_fillIvector(&drand, n, ivec1) ; Drand_fillIvector(&drand, n, ivec2) ; Drand_setUniform(&drand, 0, 1) ; Drand_fillDvector(&drand, 2*n, dvec1) ; for ( ii = 0 ; ii < n ; ii++ ) { ivec1[ii] = ivec1[ii] % mod ; ivec2[ii] = ivec2[ii] % mod ; } IVcopy(n, ivec3, ivec1) ; IVcopy(n, ivec4, ivec2) ; DVcopy(2*n, dvec2, dvec1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d initial triples", n) ; for ( ii = 0 ; ii < n ; ii++ ) { fprintf(msgFile, "\n < %12d, %12d, %12.4e, %12.4e >", ivec1[ii], ivec2[ii], dvec1[2*ii], dvec1[2*ii+1]) ; } fflush(msgFile) ; } MARKTIME(t1) ; nnew = IV2ZVsortUpAndCompress(n, ivec1, ivec2, dvec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : IV2ZVsortUpAndCompress, n = %d, nnew = %d", t2 - t1, n, nnew) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d sorted and compressed triples", nnew) ; for ( ii = 0 ; ii < nnew ; ii++ ) { fprintf(msgFile, "\n < %12d, %12d, %12.4e, %12.4e >", ivec1[ii], ivec2[ii], dvec1[2*ii], dvec1[2*ii+1]) ; } fflush(msgFile) ; } for ( ii = 0 ; ii < n ; ii++ ) { key1 = ivec3[ii] ; key2 = ivec4[ii] ; for ( jj = 0 ; jj < nnew ; jj++ ) { if ( key1 == ivec1[jj] && key2 == ivec2[jj] ) { if ( msglvl > 1 ) { fprintf(msgFile, "\n <%d,%d> found in entry %d", key1, key2, jj) ; } dvec1[2*jj] -= dvec2[2*ii] ; dvec1[2*jj+1] -= dvec2[2*ii+1] ; break ; } } if ( jj == nnew ) { fprintf(msgFile, "\n error, <%d,%d> not found in compressed list", key1, key2) ; } } fprintf(msgFile, "\n max error = %12.4e\n", DVmaxabs(2*nnew, dvec1, &ii)) ; if ( msglvl > 1 ) { DVfprintf(msgFile, 2*nnew, dvec1) ; } } else if ( strcmp(target, "IVZV") == 0 ) { /* --------------------- IVZVsortUpAndCompress --------------------- */ int *ivec1 = IVinit2(n) ; int *ivec2 = IVinit2(n) ; double *dvec1 = DVinit2(2*n) ; double *dvec2 = DVinit2(2*n) ; Drand_setDefaultFields(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, 0, n-1) ; Drand_fillIvector(&drand, n, ivec1) ; DVfill(n, dvec1, 1.0) ; Drand_fillDvector(&drand, 2*n, dvec1) ; IVcopy(n, ivec2, ivec1) ; DVcopy(2*n, dvec2, dvec1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d initial pairs", n) ; for ( ii = 0 ; ii < n ; ii++ ) { fprintf(msgFile, "\n < %12d, %12.4e, %12.4e >", ivec1[ii], dvec1[2*ii], dvec1[2*ii+1]) ; } fflush(msgFile) ; } MARKTIME(t1) ; nnew = IVZVsortUpAndCompress(n, ivec1, dvec1) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : IVZVsortUpAndCompress time", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n %d final pairs", nnew) ; for ( ii = 0 ; ii < nnew ; ii++ ) { fprintf(msgFile, "\n < %12d, %12.4e, %12.4e >", ivec1[ii], dvec1[2*ii], dvec1[2*ii+1]) ; } fflush(msgFile) ; } for ( ii = 0 ; ii < n ; ii++ ) { key1 = ivec2[ii] ; for ( jj = 0 ; jj < nnew ; jj++ ) { if ( key1 == ivec1[jj] ) { dvec1[2*jj] -= dvec2[2*ii] ; dvec1[2*jj+1] -= dvec2[2*ii+1] ; break ; } } if ( jj == nnew ) { fprintf(msgFile, "\n pair < %d,%f,%f> not found", ivec2[ii], dvec2[2*ii], dvec2[2*ii+1]) ; } } fprintf(msgFile, "\n error norm = %12.4e", DVmaxabs(2*nnew, dvec1, &ii)) ; fprintf(msgFile, "\n dvec1[]") ; DVfprintf(msgFile, 2*nnew, dvec1) ; } exit(0) ; } /*--------------------------------------------------------------------*/ Utilities/doc/004275500020550007177000000000000661616703000146235ustar00clevecompmath00000400000006Utilities/doc/dataStructure.tex010064000020550007177000000013320653560403700201700ustar00clevecompmath00000400000006\par \section{Data Structures} \label{section:Utilities:dataStructure} \par There are two data structures used in singly linked lists. \begin{itemize} \item {\tt IP}: a singly linked list element with an {\tt int} data field. \par \hspace{0.5 in} \begin{minipage}{2.5 in} \begin{verbatim} typedef struct _IP IP ; struct _IP { int val ; IP *next ; } ; \end{verbatim} \end{minipage} \item {\tt I2OP}: a singly linked list element with two {\tt int} and one {\tt void *} data fields. \par \hspace{0.5 in} \begin{minipage}{2.5 in} \begin{verbatim} typedef struct _I2OP I2OP ; struct _I2OP { int value0 ; int value1 ; void *value2 ; I2OP *next ; } ; \end{verbatim} \end{minipage} \end{itemize} Utilities/doc/intro.tex010064000020550007177000000016560653557602700165110ustar00clevecompmath00000400000006\chapter{{\tt Utilities } directory } \label{chapter:Utilities} \par The {\tt Utilities} directory contains a multitude of routines that manipulate vectors: {\tt char}, {\tt int}, {\tt float}, {\tt double} and {\tt double} vectors that are used to contain double precision complex entries. There are a variety of routines to sort vectors with and without companion vectors. Our sort routines are based on \cite{bent93-sort}, a quicksort algorithm that uses the ``nither'' function (a median of three medians) to select the partition element, and tripartite partitioning. \par Aside from vector routines, the {\tt Utilities} directory contains some methods used to manipulate elements in singly linked lists. The {\tt IP} structure (an {\tt int} data element and a pointer) is used by several objects to manage singly linked lists. The {\tt I2OP} structure (two {\tt int} and one {\tt void *} data elements) is used in a two-keyed hash table. Utilities/doc/main.tex010064400020550007177000000011030665065632600162700ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Utilities} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Utilities} : {\it DRAFT} \quad \today \hrulefill} \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} Utilities/doc/proto.tex010064400020550007177000000022250654224022600165010ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt Utilities} methods} \label{section:Utilities:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt Utilities} directory. \par % % use when latex'ing from release2.0/Utilities/doc % % \input ../Utilities/doc/CV.tex % \input ../Utilities/doc/DV.tex % \input ../Utilities/doc/ZV.tex % \input ../Utilities/doc/IV.tex % \input ../Utilities/doc/FV.tex % \input ../Utilities/doc/PCV.tex % \input ../Utilities/doc/PDV.tex % \input ../Utilities/doc/PIV.tex % \input ../Utilities/doc/PFV.tex % \input ../Utilities/doc/sort.tex % \input ../Utilities/doc/IP.tex % \input ../Utilities/doc/I2OP.tex % % use when latex'ing from release2.0/ReferenceManual/doc % \input ../../Utilities/doc/CV.tex \input ../../Utilities/doc/DV.tex \input ../../Utilities/doc/ZV.tex \input ../../Utilities/doc/IV.tex \input ../../Utilities/doc/FV.tex \input ../../Utilities/doc/PCV.tex \input ../../Utilities/doc/PDV.tex \input ../../Utilities/doc/PIV.tex \input ../../Utilities/doc/PFV.tex \input ../../Utilities/doc/sort.tex \input ../../Utilities/doc/IP.tex \input ../../Utilities/doc/I2OP.tex Utilities/doc/main.log010064400020550007177000000177770653560376700163040ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 4 JUN 1998 13:47 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. LaTeX Warning: Citation `bent93-sort' on page 1 undefined on input line 9. ) (dataStructure.tex) (proto.tex (../../Utilities/doc/CV.tex [1 ]) (../../Utilities/doc/DV.tex [2] Overfull \hbox (35.5438pt too wide) in paragraph at lines 132--154 [][] \hbox(51.7376+46.2626)x442.37993 .\hbox(0.0+0.0)x0.0 .\hbox(51.7376+46.2626)x477.92372 ..\mathon ..\vbox(51.7376+46.2626)x477.92372 ...\hbox(19.23752+13.42921)x477.92372 [] ...\glue(\lineskip) 0.0 ...\hbox(19.23752+13.42921)x477.92372 [] ...\glue(\lineskip) 0.0 ...\hbox(19.23752+13.42921)x477.92372 [] ..\mathoff .\penalty 10000 .\glue(\parfillskip) 0.0 plus 1.0fil .\glue(\rightskip) 0.0 [3] Overfull \hbox (35.5438pt too wide) in paragraph at lines 201--217 [][] \hbox(35.40422+29.92924)x442.37993 .\hbox(0.0+0.0)x0.0 .\hbox(35.40422+29.92924)x477.92372 ..\mathon ..\vbox(35.40422+29.92924)x477.92372 ...\hbox(19.23752+13.42921)x477.92372 [] ...\glue(\lineskip) 0.0 ...\hbox(19.23752+13.42921)x477.92372 [] ..\mathoff .\penalty 10000 .\glue(\parfillskip) 0.0 plus 1.0fil .\glue(\rightskip) 0.0 [4] Overfull \hbox (35.5438pt too wide) in paragraph at lines 258--268 [][] \hbox(19.07086+13.59587)x442.37993 .\hbox(0.0+0.0)x0.0 .\hbox(19.07086+13.59587)x477.92372 ..\mathon ..\vbox(19.07086+13.59587)x477.92372 ...\hbox(19.23752+13.42921)x477.92372 [] ..\mathoff .\penalty 10000 .\glue(\parfillskip) 0.0 plus 1.0fil .\glue(\rightskip) 0.0 [5] [6]) (../../Utilities/doc/ZV.tex [7] Overfull \hbox (0.26903pt too wide) in paragraph at lines 62--62 [] \elvtt double *pereal, double *peimag, double *pfreal, double *pfimag,[] \hbox(6.69167+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\penalty 10000 .\glue 5.74869 .\penalty 10000 .etc. Overfull \hbox (17.51509pt too wide) in paragraph at lines 62--62 [] \elvtt double *pgreal, double *pgimag, double *phreal, double *phimag ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\penalty 10000 .\glue 5.74869 .\penalty 10000 .etc. Overfull \hbox (7.11615pt too wide) in paragraph at lines 90--96 []\elvrm This method adds a scaled mul-ti-ple of \elvtt n \elvrm en-tries from \elvtt x[] \elvrm into \elvtt y[]\elvrm , i.e., \elvtt y[i] += (areal,aimag) \hbox(7.60416+2.43333)x442.37993, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\elvrm T .\elvrm h .\elvrm i .\elvrm s .etc. Overfull \hbox (0.26903pt too wide) in paragraph at lines 118--118 [] []\elvtt void ZVdotU ( int n, double y[], double x[], double *prdot, double *pidot ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. Overfull \hbox (0.26903pt too wide) in paragraph at lines 127--127 [] []\elvtt void ZVdotC ( int n, double y[], double x[], double *prdot, double *pidot ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 13.99168fil [] ..etc. .\penalty 0 .etc. [8] [9] [10] [11] [12]) (../../Utilities/doc/IV.tex [13] [14] [15]) (../../Utilities/doc/FV.tex [16] [17]) (../../Utilities/doc/PCV.tex [18]) (../../Utilities/doc/PDV.tex) (../../Utilities/doc/PIV.tex) (../../Utilities/doc/PFV.tex [19]) (../../Utilities/doc/sort.tex [20] [21] [22] Overfull \hbox (11.7664pt too wide) in paragraph at lines 318--318 [] []\elvtt int IV2DVsortUpAndCompress ( int n, int ivec1[], int ivec2[], doub le dvec[] ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. Overfull \hbox (11.7664pt too wide) in paragraph at lines 335--335 [] []\elvtt int IV2ZVsortUpAndCompress ( int n, int ivec1[], int ivec2[], doub le dvec[] ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. ) (../../Utilities/doc/IP.tex [23] Overfull \hbox (4.46968pt too wide) in paragraph at lines 39--43 [] []\elvrm If \elvtt flag = 1\elvrm , the el-e-ments are linked in a for-ward man-ner, i.e., \elvtt ips[i].next = &ips[i+1] \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm I .etc. Overfull \hbox (13.2601pt too wide) in paragraph at lines 43--46 [] []\elvrm If \elvtt flag = 2\elvrm , the el-e-ments are linked in a back-ward man-ner, i.e., \elvtt ips[i].next = &ips[i-1] \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm I .etc. ) (../../Utilities/doc/I2OP.tex [24] Overfull \hbox (11.40714pt too wide) in paragraph at lines 46--50 [] []\elvrm If \elvtt flag = I2OP[]BACKWARD\elvrm , the el-e-ments are linked i n a back-ward man-ner, i.e., \elvtt ips[i].next \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm I .etc. Overfull \hbox (11.40714pt too wide) in paragraph at lines 73--77 [] []\elvrm If \elvtt flag = I2OP[]BACKWARD\elvrm , the el-e-ments are linked i n a back-ward man-ner, i.e., \elvtt ips[i].next \hbox(7.60416+2.43333)x418.2899, glue set - 1.0 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(4.86667+0.0)x0.0 ..\glue 0.0 ..\glue -18.61502 ..\glue -5.475 ..\hbox(4.86667+0.0)x18.61502, glue set 18.61502fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(4.86667+0.0)x0.0, glue set - 5.475fil [] ..\glue 5.475 .\penalty 0 .\elvrm I .etc. )) (drivers.tex [25] [26]) (main.ind [27] [28 ] [29] [30]) (main.aux) ) Here is how much of TeX's memory you used: 270 strings out of 11977 3272 string characters out of 87269 35940 words of memory out of 262141 2156 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 14i,8n,17p,224b,306s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (30 pages, 86888 bytes). Utilities/doc/main.aux010064400020550007177000000077210653560376700163040ustar00clevecompmath00000400000006\relax \citation{bent93-sort} \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space Utilities } directory }{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \newlabel{chapter:Utilities}{{1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:Utilities:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space Utilities} methods}{2}} \newlabel{section:Utilities:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}{\string\ptt\space CV} : {\string\ptt\space char} vector methods}{2}} \newlabel{subsection:Utilities:proto:CV}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}{\string\ptt\space DV} : {\string\ptt\space double} vector methods}{2}} \newlabel{subsection:Utilities:proto:DV}{{1.2.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}{\string\ptt\space ZV} : {\string\ptt\space double complex } vector methods}{7}} \newlabel{subsection:Utilities:proto:ZV}{{1.2.3}{7}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}{\string\ptt\space IV} : {\string\ptt\space int} vector methods}{14}} \newlabel{subsection:Utilities:proto:IV}{{1.2.4}{14}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.5}{\string\ptt\space FV} : {\string\ptt\space float} vector methods}{16}} \newlabel{subsection:Utilities:proto:FV}{{1.2.5}{16}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.6}{\string\ptt\space PCV} : {\string\ptt\space char *} vector methods}{18}} \newlabel{subsection:Utilities:proto:PCV}{{1.2.6}{18}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.7}{\string\ptt\space PDV} : {\string\ptt\space double *} vector methods}{19}} \newlabel{subsection:Utilities:proto:PDV}{{1.2.7}{19}} \@writefile{toc}{\string\contentsline\space {subsubsection}{{\string\ptt\space PIV} : {\string\ptt\space int *} vector methods}{19}} \newlabel{subsubsection:Utilities:proto:PIV}{{1.2.7}{19}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.8}{\string\ptt\space PFV} : {\string\ptt\space float *} vector methods}{20}} \newlabel{subsection:Utilities:proto:PFV}{{1.2.8}{20}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.9}Sorting routines}{20}} \newlabel{subsection:Utilities:proto:sort}{{1.2.9}{20}} \@writefile{toc}{\string\contentsline\space {subsubsection}{Validation routines}{20}} \newlabel{subsubsection:Utilities:proto:sort:validate}{{1.2.9}{20}} \@writefile{toc}{\string\contentsline\space {subsubsection}{Insert sort routines}{20}} \newlabel{subsubsection:Utilities:proto:sort:insert}{{1.2.9}{20}} \@writefile{toc}{\string\contentsline\space {subsubsection}{Quicksort routines}{21}} \newlabel{subsubsection:Utilities:proto:sort:quicksort}{{1.2.9}{21}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.10}Sort and compress routines}{22}} \newlabel{subsection:Utilities:proto:sortAndCompress}{{1.2.10}{22}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.11}{\string\ptt\space IP} : {\string\ptt\space (int,pointer)} singly linked-list methods}{24}} \newlabel{subsection:Utilities:proto:IP}{{1.2.11}{24}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.12}{\string\ptt\space I2OP} : {\string\ptt\space (int,int, void*, pointer)} singly linked-list methods}{25}} \newlabel{subsection:Utilities:proto:I2OP}{{1.2.12}{25}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs }{26}} \newlabel{section:Utilities:drivers}{{1.3}{26}} Utilities/doc/CV.tex010064400020550007177000000061320653410575300156550ustar00clevecompmath00000400000006\par \subsection{{\tt CV} : {\tt char} vector methods} \label{subsection:Utilities:proto:CV} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} char * CVinit ( int n, char c ) ; \end{verbatim} \index{CVinit@{\tt CVinit()}} This is the allocator and initializer method for {\tt char} vectors. Storage for an array with size {\tt n} is found and each entry is filled with character {\tt c}. A pointer to the array is returned. %----------------------------------------------------------------------- \item \begin{verbatim} char * CVinit2 ( int n ) ; \end{verbatim} \index{CVinit2@{\tt CVinit2()}} This is an allocator method for {\tt char} vectors. Storage for an array with size {\tt n} is found. A pointer to the array is returned. Note, on return, there will likely be garbage in the array. %----------------------------------------------------------------------- \item \begin{verbatim} void CVfree ( char cvec[] ) ; \end{verbatim} \index{CVfree@{\tt CVfree()}} This method releases the storage taken by {\tt cvec[]}. %----------------------------------------------------------------------- \item \begin{verbatim} void CVcopy ( int n, char y[], char x[] ) ; \end{verbatim} \index{CVcopy@{\tt CVcopy()}} This method copies {\tt n} entries from {\tt x[]} to {\tt y[]}, i.e., {\tt y[i] = x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void CVfill ( int n, char y[], char c ) ; \end{verbatim} \index{CVfill@{\tt CVfill()}} This method fills {\tt n} entries in {\tt y[]} with the character {\tt c}, i.e., {\tt y[i] = c} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void CVfprintf ( FILE *fp, int n, char y[] ) ; \end{verbatim} \index{CVfprintf@{\tt CVfprintf()}} This method prints {\tt n} entries in {\tt y[]} to file {\tt fp}. The format is new line followed by lines of eighty columns of single characters. %----------------------------------------------------------------------- \item \begin{verbatim} int CVfp80 ( FILE *fp, int n, char y[], int column, int *pierr ) ; \end{verbatim} \index{CVfp80@{\tt CVfp80()}} This method prints {\tt n} entries in {\tt y[]} to file {\tt fp}. The method splices vectors together or naturally breaks the large vectors into lines. The {\tt column} value is the present location, one can add $(80 - \mbox{\tt column})$ more characters before having to form a new line. The number of the present character in the line is returned. If {\tt *pierr < 0}, an IO error has occured. %----------------------------------------------------------------------- \item \begin{verbatim} int CVfscanf ( FILE *fp, int n, char y[] ) ; \end{verbatim} \index{CVfscanf@{\tt CVfscanf()}} This method scans in characters from file {\tt fp} and places them in the array {\tt y[]}. It tries to read in {\tt n} characters, and returns the number that were actually read. %----------------------------------------------------------------------- \end{enumerate} Utilities/doc/IV.tex010064400020550007177000000215140653554225500156670ustar00clevecompmath00000400000006\par \subsection{{\tt IV} : {\tt int} vector methods} \label{subsection:Utilities:proto:IV} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int * IVinit ( int n, int val ) ; \end{verbatim} \index{IVinit@{\tt IVinit()}} This is the allocator and initializer method for {\tt int} vectors. Storage for an array with size {\tt n} is found and each entry is filled with {\tt val}. A pointer to the array is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int * IVinit2 ( int n ) ; \end{verbatim} \index{IVinit2@{\tt IVinit2()}} This is an allocator method for {\tt int} vectors. Storage for an array with size {\tt n} is found. A pointer to the array is returned. Note, on return, there will likely be garbage in the array. %----------------------------------------------------------------------- \item \begin{verbatim} void IVfree ( int vec[] ) ; \end{verbatim} \index{IVfree@{\tt IVfree()}} This method releases the storage taken by {\tt vec[]}. %----------------------------------------------------------------------- \item \begin{verbatim} void IVfprintf ( FILE *fp, int n, int y[] ) ; \end{verbatim} \index{IVfprintf@{\tt IVfprintf()}} This method prints {\tt n} entries in {\tt y[]} to file {\tt fp}. The format is new line followed by lines of five {\tt int}'s in {\tt " \%4d"} format. %----------------------------------------------------------------------- \item \begin{verbatim} int IVfp80 ( FILE *fp, int n, int y[], int column, int *pierr ) ; \end{verbatim} \index{IVfp80@{\tt IVfp80()}} This method prints {\tt n} entries in {\tt y[]} to file {\tt fp}. The method splices vectors together or naturally breaks the large vectors into lines. The {\tt column} value is the present location. If the printed value of an array entry will not fit within the eighty columns of the present line, a newline character is written and the value starts a new line. The number of the present column in the line is returned. If {\tt *pierr < 0}, an IO error has occured. %----------------------------------------------------------------------- \item \begin{verbatim} int IVfscanf ( FILE *fp, int n, int y[] ) ; \end{verbatim} \index{IVfscanf@{\tt IVfscanf()}} This method scans in {\tt int}'s from file {\tt fp} and places them in the array {\tt y[]}. It tries to read in {\tt n} {\tt int}'s, and returns the number that were actually read. %----------------------------------------------------------------------- \item \begin{verbatim} void IVcompress ( int n1, int x1[], int y1[], int n2, int x2[], int y2[] ) ; \end{verbatim} \index{IVcompress@{\tt IVcompress()}} Given a pair of arrays {\tt x1[n1]} and {\tt y1[n1]}, fill {\tt x2[n2]} and {\tt y2[n2]} with a subset of the {\tt (x1[j],y1[j]} entries whose distribution is an approximation. %----------------------------------------------------------------------- \item \begin{verbatim} void IVcopy ( int n, int y[], int x[] ) ; \end{verbatim} \index{IVcopy@{\tt IVcopy()}} This method copies {\tt n} entries from {\tt x[]} to {\tt y[]}, i.e., {\tt y[i] = x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void IVfill ( int n, int y[], int val ) ; \end{verbatim} \index{IVfill@{\tt IVfill()}} This method fills {\tt n} entries in {\tt y[]} with {\tt val}, i.e., {\tt y[i] = val} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void IVgather ( int n, int y[], int x[], int index[] ) ; \end{verbatim} \index{IVgather@{\tt IVgather()}} {\tt y[i] = x[index[i]]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} int * IVinverse ( int n, int y[] ) ; \end{verbatim} \index{IVinverse@{\tt IVinverse()}} This method allocates and returns a vector of size {\tt n} that it is the inverse of {\tt y[]}, a permutation vector. The new vector {\tt x[]} has the property that {\tt x[y[i]] = y[x[i]] = i}; If {\tt y[]} is not truly a permutation vector, an error message will be printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void IVinvPerm ( int n, int y[], int index[] ) ; \end{verbatim} \index{IVinvPerm@{\tt IVinvPerm()}} This method permutes the vector y as follows. i.e., {\tt y[index[i]] := y[i]}. See {\tt IVperm()} for a similar function. %----------------------------------------------------------------------- \item \begin{verbatim} int IVlocateViaBinarySearch ( int n, int y[], int target ) ; \end{verbatim} \index{IVlocateViaBinarySearch@{\tt IVlocateViaBinarySearch()}} The {\tt n} entries of {\tt y[]} must be in nondecreasing order. If {\tt target} is found in {\tt y[]}, this method returns a location where {\tt target} is found. If {\tt target} is not in {\tt y[]}, {\tt -1} is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int IVmax ( int n, int y[], int *ploc ) ; \end{verbatim} \index{IVmax@{\tt IVmax()}} This method returns the maximum entry in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} int IVmaxabs ( int n, int y[], int *ploc ) ; \end{verbatim} \index{IVmaxabs@{\tt IVmaxabs()}} This method returns the maximum magnitude of entries in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} int IVmin ( int n, int y[], int *ploc ) ; \end{verbatim} \index{IVmin@{\tt IVmin()}} This method returns the minimum entry in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} int IVminabs ( int n, int y[], int *ploc ) ; \end{verbatim} \index{IVminabs@{\tt IVminabs()}} This method returns the minimum magnitude of entries in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} void IVperm ( int n, int y[], int index[] ) ; \end{verbatim} \index{IVperm@{\tt IVperm()}} This method permutes the vector y as follows. i.e., {\tt y[i] := y[index[i]]}. See {\tt IVinvPerm()} for a similar function. %----------------------------------------------------------------------- \item \begin{verbatim} void IVramp ( int n, int y[], int start, int inc ) ; \end{verbatim} \index{IVramp@{\tt IVramp()}} This method fills {\tt n} entries in {\tt y[]} with values {\tt start}, {\tt start + inc}, {\tt start + 2*inc}, {\tt start + 3*inc}, etc. %----------------------------------------------------------------------- \item \begin{verbatim} void IVscatter ( int n, int y[], int index[], int x[] ) ; \end{verbatim} \index{IVscatter@{\tt IVscatter()}} This method scatters {\tt n} entries of {\tt x[]} into {\tt y[]} as follows, {\tt y[index[i]] = x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} int IVsum ( int n, int y[] ) ; \end{verbatim} \index{IVsum@{\tt IVsum()}} This method returns the sum of the first {\tt n} entries in the vector {\tt x[]}, i.e., return $\sum_{\tt i = 0}^{\tt n-1} {\tt x[i]}$. %----------------------------------------------------------------------- \item \begin{verbatim} int IVsumabs ( int n, int y[] ) ; \end{verbatim} \index{IVsumabs@{\tt IVsumabs()}} This method returns the sum of the absolute values of the first {\tt n} entries in the vector {\tt x[]}, i.e., return $\sum_{\tt i = 0}^{\tt n-1} {\tt abs(x[i])}$. %----------------------------------------------------------------------- \item \begin{verbatim} void IVswap ( int n, int y[], int x[] ) ; \end{verbatim} \index{IVswap@{\tt IVswap()}} This method swaps the {\tt x[]} and {\tt y[]} vectors as follows. i.e., {\tt y[i] := x[i]} and {\tt x[i] := y[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void IVzero ( int n, int y[] ) ; \end{verbatim} \index{IVzero@{\tt IVzero()}} This method zeroes {\tt n} entries in {\tt y[]}, i.e., {\tt y[i] = 0} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void IVshuffle ( int n, int y[], int seed ) ; \end{verbatim} \index{IVshuffle@{\tt IVshuffle()}} This method shuffles the first {\tt n} entries in {\tt y[]}. The value {\tt seed} is the seed to a random number generator, and one can get repeatable behavior by repeating {\tt seed}. %----------------------------------------------------------------------- \end{enumerate} int}'s from file {\tt fp} and places them in the array {\tt y[]}. It tries to read in {\tt n} {\tt int}'s, and returns the number that were actually read. %-----------------------Utilities/doc/DV.tex010064400020550007177000000547130665016734600156730ustar00clevecompmath00000400000006\par \subsection{{\tt DV} : {\tt double} vector methods} \label{subsection:Utilities:proto:DV} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} double * DVinit ( int n, double val ) ; \end{verbatim} \index{DVinit@{\tt DVinit()}} This is the allocator and initializer method for {\tt double} vectors. Storage for an array with size {\tt n} is found and each entry is filled with {\tt val}. A pointer to the array is returned. %----------------------------------------------------------------------- \item \begin{verbatim} double * DVinit2 ( int n ) ; \end{verbatim} \index{DVinit2@{\tt DVinit2()}} This is an allocator method for {\tt double} vectors. Storage for an array with size {\tt n} is found. A pointer to the array is returned. Note, on return, there will likely be garbage in the array. %----------------------------------------------------------------------- \item \begin{verbatim} void DVfree ( int vec[] ) ; \end{verbatim} \index{DVfree@{\tt DVfree()}} This method releases the storage taken by {\tt vec[]}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVfprintf ( FILE *fp, int n, double y[] ) ; \end{verbatim} \index{DVfprintf@{\tt DVfprintf()}} This method prints {\tt n} entries in {\tt y[]} to file {\tt fp}. The format is new line followed by lines of six {\tt double}'s in {\tt "\%12.4e"} format. %----------------------------------------------------------------------- \item \begin{verbatim} int DVfscanf ( FILE *fp, int n, double y[] ) ; \end{verbatim} \index{DVfscanf@{\tt DVfscanf()}} This method scans in {\tt double}'s from file {\tt fp} and places them in the array {\tt y[]}. It tries to read in {\tt n} {\tt double}'s, and returns the number that were actually read. %----------------------------------------------------------------------- \item \begin{verbatim} void DVadd ( int n, double y[], double x[] ) ; \end{verbatim} \index{DVadd@{\tt DVadd()}} This method adds {\tt n} entries from {\tt x[]} to {\tt y[]}, i.e., {\tt y[i] += x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpy ( int n, double y[], double alpha, double x[] ) ; \end{verbatim} \index{DVaxpy@{\tt DVaxpy()}} This method adds a scaled multiple of {\tt n} entries from {\tt x[]} into {\tt y[]}, i.e., {\tt y[i] += alpha * x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpy2 ( int n, double z[], double a, double x[], double b, double y[] ) ; \end{verbatim} \index{DVaxpy@{\tt DVaxpy()}} This method adds a scaled multiple of two vectors {\tt x[]} and {\tt y[]} to another vector {\tt z[]}, i.e., i.e., {\tt z[i] += a * x[i] + b * y[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpy33 ( int n, double y0[], double y1[], double y2[], double alpha, double x0[], double x1[], double x2[] ) ; \end{verbatim} \index{DVaxpy33@{\tt DVaxpy33()}} This method computes this computation. \begin{verbatim} y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] + alpha[2] * x2[] y1[] = y1[] + alpha[3] * x0[] + alpha[4] * x1[] + alpha[5] * x2[] y2[] = y2[] + alpha[6] * x0[] + alpha[7] * x1[] + alpha[8] * x2[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpy32 ( int n, double y0[], double y1[], double y2[], double alpha, double x0[], double x1[] ) ; \end{verbatim} \index{DVaxpy32@{\tt DVaxpy32()}} This method computes this computation. \begin{verbatim} y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] y1[] = y1[] + alpha[2] * x0[] + alpha[3] * x1[] y2[] = y2[] + alpha[4] * x0[] + alpha[5] * x1[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpy31 ( int n, double y0[], double y1[], double y2[], double alpha, double x0[], double x1[] ) ; \end{verbatim} \index{DVaxpy31@{\tt DVaxpy31()}} This method computes this computation. \begin{verbatim} y0[] = y0[] + alpha[0] * x0[] y1[] = y1[] + alpha[1] * x0[] y2[] = y2[] + alpha[2] * x0[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpy23 ( int n, double y0[], double y1[], double alpha, double x0[], double x1[], double x2[] ) ; \end{verbatim} \index{DVaxpy23@{\tt DVaxpy23()}} This method computes this computation. \begin{verbatim} y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] + alpha[2] * x2[] y1[] = y1[] + alpha[3] * x0[] + alpha[4] * x1[] + alpha[5] * x2[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpy22 ( int n, double y0[], double y1[], double alpha, double x0[], double x1[] ) ; \end{verbatim} \index{DVaxpy22@{\tt DVaxpy22()}} This method computes this computation. \begin{verbatim} y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] y1[] = y1[] + alpha[2] * x0[] + alpha[3] * x1[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpy21 ( int n, double y0[], double y1[], double alpha, double x0[] ) ; \end{verbatim} \index{DVaxpy21@{\tt DVaxpy21()}} This method computes this computation. \begin{verbatim} y0[] = y0[] + alpha[0] * x0[] y1[] = y1[] + alpha[1] * x0[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpy13 ( int n, double y0[], double alpha, double x0[], double x1[], double x2[] ) ; \end{verbatim} \index{DVaxpy13@{\tt DVaxpy13()}} This method computes this computation. \begin{verbatim} y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] + alpha[2] * x2[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpy12 ( int n, double y0[], double alpha, double x0[], double x1[] ) ; \end{verbatim} \index{DVaxpy12@{\tt DVaxpy12()}} This method computes this computation. \begin{verbatim} y0[] = y0[] + alpha[0] * x0[] + alpha[1] * x1[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpy11 ( int n, double y0[], double alpha, double x0[] ) ; \end{verbatim} \index{DVaxpy11@{\tt DVaxpy11()}} This method computes this computation. \begin{verbatim} y0[] = y0[] + alpha[0] * x0[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void DVaxpyi ( int n, double y[], int index[], double alpha, double x[] ) ; \end{verbatim} \index{DVaxpyi@{\tt DVaxpyi()}} This method scatteradds a scaled multiple of {\tt n} entries from {\tt x[]} into {\tt y[]}, i.e., {\tt y[index[i]] += alpha * x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVcompress ( int n1, double x1[], double y1[], int n2, double x2[], double y2[] ) ; \end{verbatim} \index{DVcompress@{\tt DVcompress()}} Given a pair of arrays {\tt x1[n1]} and {\tt y1[n1]}, fill {\tt x2[n2]} and {\tt y2[n2]} with a subset of the {\tt (x1[j],y1[j]} entries whose distribution is an approximation. %----------------------------------------------------------------------- \item \begin{verbatim} void DVcopy ( int n, double y[], double x[] ) ; \end{verbatim} \index{DVcopy@{\tt DVcopy()}} This method copies {\tt n} entries from {\tt x[]} to {\tt y[]}, i.e., {\tt y[i] = x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} int DVdot ( int n, double y[], double x[] ) ; \end{verbatim} \index{DVdot@{\tt DVdot()}} This method returns the dot product of the vector {\tt x[]} and {\tt y[]}, i.e., return $\sum_{\tt i = 0}^{\tt n-1} ({\tt x[i] * y[i]})$. %----------------------------------------------------------------------- \item \begin{verbatim} int DVdot33 ( int n, double row0[], double row1[], double row2[], double col0[], double col1[], double col2[], double sums[] ) ; \end{verbatim} \index{DVdot33@{\tt DVdot33()}} This method computes nine dot products. \par \begin{tabular}{lll} $\displaystyle{\tt sums[0]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ & $\displaystyle{\tt sums[2]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col2[i]}$ \\ $\displaystyle{\tt sums[3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ & $\displaystyle{\tt sums[4]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col1[i]}$ & $\displaystyle{\tt sums[5]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col2[i]}$ \\ $\displaystyle{\tt sums[6]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col0[i]}$ & $\displaystyle{\tt sums[7]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col1[i]}$ & $\displaystyle{\tt sums[8]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col2[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int DVdot32 ( int n, double row0[], double row1[], double row2[], double col0[], double col1[], double sums[] ) ; \end{verbatim} \index{DVdot32@{\tt DVdot32()}} This method computes six dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ \\ $\displaystyle{\tt sums[2]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ & $\displaystyle{\tt sums[3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col1[i]}$ \\ $\displaystyle{\tt sums[4]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col0[i]}$ & $\displaystyle{\tt sums[5]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col1[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int DVdot31 ( int n, double row0[], double row1[], double row2[], double col0[], double sums[] ) ; \end{verbatim} \index{DVdot31@{\tt DVdot31()}} This method computes three dot products. \par \begin{tabular}{l} $\displaystyle{\tt sums[0]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ \\ $\displaystyle{\tt sums[1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ \\ $\displaystyle{\tt sums[2]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col0[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int DVdot23 ( int n, double row0[], double row1[], double col0[], double col1[], double col2[], double sums[] ) ; \end{verbatim} \index{DVdot23@{\tt DVdot23()}} This method computes six dot products. \par \begin{tabular}{lll} $\displaystyle{\tt sums[0]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ & $\displaystyle{\tt sums[2]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col2[i]}$ \\ $\displaystyle{\tt sums[3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ & $\displaystyle{\tt sums[4]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col1[i]}$ & $\displaystyle{\tt sums[5]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col2[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int DVdot22 ( int n, double row0[], double row1[], double col0[], double col1[], double sums[] ) ; \end{verbatim} \index{DVdot22@{\tt DVdot22()}} This method computes four dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ \\ $\displaystyle{\tt sums[2]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ & $\displaystyle{\tt sums[3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col1[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int DVdot21 ( int n, double row0[], double row1[], double col0[], double sums[] ) ; \end{verbatim} \index{DVdot21@{\tt DVdot21()}} This method computes two dot products. \par \begin{tabular}{l} $\displaystyle{\tt sums[0]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ \\ $\displaystyle{\tt sums[1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int DVdot13 ( int n, double row0[], double col0[], double col1[], double col2[], double sums[] ) ; \end{verbatim} \index{DVdot13@{\tt DVdot13()}} This method computes six dot products. \par \begin{tabular}{lll} $\displaystyle{\tt sums[0]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ & $\displaystyle{\tt sums[2]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col2[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int DVdot12 ( int n, double row0[], double row1[], double col0[], double col1[], double sums[] ) ; \end{verbatim} \index{DVdot12@{\tt DVdot12()}} This method computes two dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int DVdot11 ( int n, double row0[], double col0[], double sums[] ) ; \end{verbatim} \index{DVdot11@{\tt DVdot11()}} This method computes one dot product. \par \begin{tabular}{l} $\displaystyle{\tt sums[0]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int DVdoti ( int n, double y[], int index[], double x[] ) ; \end{verbatim} \index{DVdoti@{\tt DVdoti()}} This method returns the indexed dot product $\displaystyle \sum_{{\tt i=0}}^{{\tt n-1}} {\tt y[index[i]] * x[i]}$. %----------------------------------------------------------------------- \item \begin{verbatim} void DVfill ( int n, double y[], double val ) ; \end{verbatim} \index{DVfill@{\tt DVfill()}} This method fills {\tt n} entries in {\tt y[]} with {\tt val}, i.e., {\tt y[i] = val} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVgather ( int n, double y[], double x[], int index[] ) ; \end{verbatim} \index{DVgather@{\tt DVgather()}} {\tt y[i] = x[index[i]]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVgatherAddZero ( int n, double y[], double x[], int index[] ) ; \end{verbatim} \index{DVgatherAddZero@{\tt DVgatherAddZero()}} {\tt y[i] += x[index[i]]} and {\tt x[index[i]] = 0} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVgatherZero ( int n, double y[], double x[], int index[] ) ; \end{verbatim} \index{DVgatherZero@{\tt DVgatherZero()}} {\tt y[i] = x[index[i]]} and {\tt x[index[i]] = 0} %----------------------------------------------------------------------- \item \begin{verbatim} void DVinvPerm ( int n, double y[], int index[] ) ; \end{verbatim} \index{DVinvPerm@{\tt DVinvPerm()}} This method permutes the vector y as follows. i.e., {\tt y[index[i]] := y[i]}. See {\tt DVperm()} for a similar function. %----------------------------------------------------------------------- \item \begin{verbatim} double DVmax ( int n, double y[], int *ploc ) ; \end{verbatim} \index{DVmax@{\tt DVmax()}} This method returns the maximum entry in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} double DVmaxabs ( int n, double y[], int *ploc ) ; \end{verbatim} \index{DVmaxabs@{\tt DVmaxabs()}} This method returns the maximum magnitude of entries in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} double DVmin ( int n, double y[], int *ploc ) ; \end{verbatim} \index{DVmin@{\tt DVmin()}} This method returns the minimum entry in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} double DVminabs ( int n, double y[], int *ploc ) ; \end{verbatim} \index{DVminabs@{\tt DVminabs()}} This method returns the minimum magnitude of entries in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVperm ( int n, double y[], int index[] ) ; \end{verbatim} \index{DVperm@{\tt DVperm()}} This method permutes the vector y as follows. i.e., {\tt y[i] := y[index[i]]}. See {\tt DVinvPerm()} for a similar function. %----------------------------------------------------------------------- \item \begin{verbatim} void DVramp ( int n, double y[], double start, double inc ) ; \end{verbatim} \index{DVramp@{\tt DVramp()}} This method fills {\tt n} entries in {\tt y[]} with values {\tt start}, {\tt start + inc}, {\tt start + 2*inc}, {\tt start + 3*inc}, etc. %----------------------------------------------------------------------- \item \begin{verbatim} void DVscale ( int n, double y[], double alpha ) ; \end{verbatim} \index{DVscale@{\tt DVscale()}} This method scales a vector {\tt y[]} by {\tt alpha}, i.e., {\tt y[i] *= alpha}. for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVscale2 ( int n, double x[], double y[], double a, double b, double c, double d ) ; \end{verbatim} \index{DVscale@{\tt DVscale()}} This method scales two vectors {\tt y[]} by a $2 \times 2$ matrix, i.e., $$ \left \lbrack \begin{array}{ccc} {\tt x[0]} & \ldots & {\tt x[n-1]} \\ {\tt y[0]} & \ldots & {\tt y[n-1]} \end{array} \right \rbrack := \left \lbrack \begin{array}{cc} {\tt a} & {\tt b} \\ {\tt c} & {\tt d} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} {\tt x[0]} & \ldots & {\tt x[n-1]} \\ {\tt y[0]} & \ldots & {\tt y[n-1]} \end{array} \right \rbrack. $$ %----------------------------------------------------------------------- \item \begin{verbatim} void DVscatter ( int n, double y[], int index[], double x[] ) ; \end{verbatim} \index{DVscatter@{\tt DVscatter()}} This method scatters {\tt n} entries of {\tt x[]} into {\tt y[]} as follows, {\tt y[index[i]] = x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVscatterAdd ( int n, double y[], int index[], double x[] ) ; \end{verbatim} \index{DVscatterAdd@{\tt DVscatterAdd()}} This method scatters/adds {\tt n} entries of {\tt x[]} into {\tt y[]} as follows, {\tt y[index[i]] += x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVscatterAddZero ( int n, double y[], int index[], double x[] ) ; \end{verbatim} \index{DVscatterAddZero@{\tt DVscatterAddZero()}} This method scatters/adds {\tt n} entries of {\tt x[]} into {\tt y[]} as follows, {\tt y[index[i]] += x[i]} for {\tt 0 <= i < n}, and then zeros the entries in {\tt x[*]}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVscatterZero ( int n, double y[], int index[], double x[] ) ; \end{verbatim} \index{DVscatterZero@{\tt DVscatterZero()}} This method scatters {\tt n} entries of {\tt x[]} into {\tt y[]} as follows, {\tt y[index[i]] = x[i]} for {\tt 0 <= i < n} and then zeros the entries in {\tt x[*]}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVsub ( int n, double y[], double x[] ) ; \end{verbatim} \index{DVsub@{\tt DVsub()}} This method subtracts {\tt n} entries from {\tt x[]} to {\tt y[]}, i.e., {\tt y[i] -= x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} double DVsum ( int n, double y[] ) ; \end{verbatim} \index{DVsum@{\tt DVsum()}} This method returns the sum of the first {\tt n} entries in the vector {\tt x[]}, i.e., return $\sum_{\tt i = 0}^{\tt n-1} {\tt x[i]}$. %----------------------------------------------------------------------- \item \begin{verbatim} double DVsumabs ( int n, double y[] ) ; \end{verbatim} \index{DVsumabs@{\tt DVsumabs()}} This method returns the sum of the absolute values of the first {\tt n} entries in the vector {\tt x[]}, i.e., return $\sum_{\tt i = 0}^{\tt n-1} {\tt abs(x[i])}$. %----------------------------------------------------------------------- \item \begin{verbatim} void DVswap ( int n, double y[], double x[] ) ; \end{verbatim} \index{DVswap@{\tt DVswap()}} This method swaps the {\tt x[]} and {\tt y[]} vectors as follows. i.e., {\tt y[i] := x[i]} and {\tt x[i] := y[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVzero ( int n, double y[] ) ; \end{verbatim} \index{DVzero@{\tt DVzero()}} This method zeroes {\tt n} entries in {\tt y[]}, i.e., {\tt y[i] = 0} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void DVshuffle ( int n, double y[], int seed ) ; \end{verbatim} \index{DVshuffle@{\tt DVshuffle()}} This method shuffles the first {\tt n} entries in {\tt y[]}. The value {\tt seed} is the seed to a random number generator, and one can get repeatable behavior by repeating {\tt seed}. %----------------------------------------------------------------------- \end{enumerate} atim} int DVdot21 ( int n, double row0[], double row1Utilities/doc/FV.tex010064400020550007177000000247700653554237000156710ustar00clevecompmath00000400000006\par \subsection{{\tt FV} : {\tt float} vector methods} \label{subsection:Utilities:proto:FV} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} float * FVinit ( int n, float val ) ; \end{verbatim} \index{FVinit@{\tt FVinit()}} This is the allocator and initializer method for {\tt float} vectors. Storage for an array with size {\tt n} is found and each entry is filled with {\tt val}. A pointer to the array is returned. %----------------------------------------------------------------------- \item \begin{verbatim} float * FVinit2 ( int n ) ; \end{verbatim} \index{FVinit2@{\tt FVinit2()}} This is an allocator method for {\tt float} vectors. Storage for an array with size {\tt n} is found. A pointer to the array is returned. Note, on return, there will likely be garbage in the array. %----------------------------------------------------------------------- \item \begin{verbatim} void FVfree ( int vec[] ) ; \end{verbatim} \index{FVfree@{\tt FVfree()}} This method releases the storage taken by {\tt vec[]}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVfprintf ( FILE *fp, int n, float y[] ) ; \end{verbatim} \index{FVfprintf@{\tt FVfprintf()}} This method prints {\tt n} entries in {\tt y[]} to file {\tt fp}. The format is new line followed by lines of six {\tt float}'s in {\tt " \%12.4e"} format. %----------------------------------------------------------------------- \item \begin{verbatim} int FVfscanf ( FILE *fp, int n, float y[] ) ; \end{verbatim} \index{FVfscanf@{\tt FVfscanf()}} This method scans in {\tt float}'s from file {\tt fp} and places them in the array {\tt y[]}. It tries to read in {\tt n} {\tt float}'s, and returns the number that were actually read. %----------------------------------------------------------------------- \item \begin{verbatim} void FVadd ( int n, float y[], float x[] ) ; \end{verbatim} \index{FVadd@{\tt FVadd()}} This method adds {\tt n} entries from {\tt x[]} to {\tt y[]}, i.e., {\tt y[i] += x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVaxpy ( int n, float y[], float alpha, float x[] ) ; \end{verbatim} \index{FVaxpy@{\tt FVaxpy()}} This method adds a scaled multiple of {\tt n} entries from {\tt x[]} into {\tt y[]}, i.e., {\tt y[i] += alpha * x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVaxpyi ( int n, float y[], int index[], float alpha, float x[] ) ; \end{verbatim} \index{FVaxpyi@{\tt FVaxpyi()}} This method scatteradds a scaled multiple of {\tt n} entries from {\tt x[]} into {\tt y[]}, i.e., {\tt y[index[i]] += alpha * x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVcompress ( int n1, double x1[], double y1[], int n2, double x2[], double y2[] ) ; \end{verbatim} \index{FVcompress@{\tt FVcompress()}} Given a pair of arrays {\tt x1[n1]} and {\tt y1[n1]}, fill {\tt x2[n2]} and {\tt y2[n2]} with a subset of the {\tt (x1[j],y1[j]} entries whose distribution is an approximation. %----------------------------------------------------------------------- \item \begin{verbatim} void FVcopy ( int n, float y[], float x[] ) ; \end{verbatim} \index{FVcopy@{\tt FVcopy()}} This method copies {\tt n} entries from {\tt x[]} to {\tt y[]}, i.e., {\tt y[i] = x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} float FVdot ( int n, float y[], float x[] ) ; \end{verbatim} \index{FVdot@{\tt FVdot()}} This method returns the dot product of the vector {\tt x[]} and {\tt y[]}, i.e., return $\sum_{\tt i = 0}^{\tt n-1} ({\tt x[i]*y[i]})$. %----------------------------------------------------------------------- \item \begin{verbatim} void FVfill ( int n, float y[], float val ) ; \end{verbatim} \index{FVfill@{\tt FVfill()}} This method fills {\tt n} entries in {\tt y[]} with {\tt val}, i.e., {\tt y[i] = val} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVgather ( int n, float y[], float x[], int index[] ) ; \end{verbatim} \index{FVgather@{\tt FVgather()}} {\tt y[i] = x[index[i]]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVgatherAddZero ( int n, float y[], float x[], int index[] ) ; \end{verbatim} \index{FVgatherAddZero@{\tt FVgatherAddZero()}} {\tt y[i] += x[index[i]]} and {\tt x[index[i]] = 0} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVgatherZero ( int n, float y[], float x[], int index[] ) ; \end{verbatim} \index{FVgatherZero@{\tt FVgatherZero()}} {\tt y[i] = x[index[i]]} and {\tt x[index[i]] = 0} %----------------------------------------------------------------------- \item \begin{verbatim} void FVinvPerm ( int n, float y[], int index[] ) ; \end{verbatim} \index{FVinvPerm@{\tt FVinvPerm()}} This method permutes the vector y as follows. i.e., {\tt y[index[i]] := y[i]}. See {\tt FVperm()} for a similar function. %----------------------------------------------------------------------- \item \begin{verbatim} float FVmax ( int n, float y[], int *ploc ) ; \end{verbatim} \index{FVmax@{\tt FVmax()}} This method returns the maximum entry in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} float FVmaxabs ( int n, float y[], int *ploc ) ; \end{verbatim} \index{FVmaxabs@{\tt FVmaxabs()}} This method returns the maximum magnitude of entries in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} float FVmin ( int n, float y[], int *ploc ) ; \end{verbatim} \index{FVmin@{\tt FVmin()}} This method returns the minimum entry in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} float FVminabs ( int n, float y[], int *ploc ) ; \end{verbatim} \index{FVminabs@{\tt FVminabs()}} This method returns the minimum magnitude of entries in {\tt y[0:n-1]} and puts the first location where it was found into the address {\tt ploc}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVperm ( int n, float y[], int index[] ) ; \end{verbatim} \index{FVperm@{\tt FVperm()}} This method permutes the vector y as follows. i.e., {\tt y[i] := y[index[i]]}. See {\tt FVinvPerm()} for a similar function. %----------------------------------------------------------------------- \item \begin{verbatim} void FVramp ( int n, float y[], float start, float inc ) ; \end{verbatim} \index{FVramp@{\tt FVramp()}} This method fills {\tt n} entries in {\tt y[]} with values {\tt start}, {\tt start + inc}, {\tt start + 2*inc}, {\tt start + 3*inc}, etc. %----------------------------------------------------------------------- \item \begin{verbatim} void FVscale ( int n, float y[], float alpha ) ; \end{verbatim} \index{FVscale@{\tt FVscale()}} This method scales a vector {\tt y[]} by {\tt alpha}, i.e., {\tt y[i] *= alpha}. for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVscatter ( int n, float y[], int index[], float x[] ) ; \end{verbatim} \index{FVscatter@{\tt FVscatter()}} This method scatters {\tt n} entries of {\tt x[]} into {\tt y[]} as follows, {\tt y[index[i]] = x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVscatterAddZero ( int n, float y[], int index[], float x[] ) ; \end{verbatim} \index{FVscatterAddZero@{\tt FVscatterAddZero()}} This method scatters/adds {\tt n} entries of {\tt x[]} into {\tt y[]} as follows, {\tt y[index[i]] += x[i]} and {\tt x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVscatterZero ( int n, float y[], int index[], float x[] ) ; \end{verbatim} \index{FVscatterZero@{\tt FVscatterZero()}} This method scatters {\tt n} entries of {\tt x[]} into {\tt y[]} as follows, {\tt y[index[i]] = x[i]} and {\tt x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVsub ( int n, float y[], float x[] ) ; \end{verbatim} \index{FVsub@{\tt FVsub()}} This method subtracts {\tt n} entries from {\tt x[]} to {\tt y[]}, i.e., {\tt y[i] -= x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} float FVsum ( int n, float y[] ) ; \end{verbatim} \index{FVsum@{\tt FVsum()}} This method returns the sum of the first {\tt n} entries in the vector {\tt x[]}, i.e., return $\sum_{\tt i = 0}^{\tt n-1} {\tt x[i]}$. %----------------------------------------------------------------------- \item \begin{verbatim} float FVsumabs ( int n, float y[] ) ; \end{verbatim} \index{FVsumabs@{\tt FVsumabs()}} This method returns the sum of the absolute values of the first {\tt n} entries in the vector {\tt x[]}, i.e., return $\sum_{\tt i = 0}^{\tt n-1} {\tt abs(x[i])}$. %----------------------------------------------------------------------- \item \begin{verbatim} void FVswap ( int n, float y[], float x[] ) ; \end{verbatim} \index{FVswap@{\tt FVswap()}} This method swaps the {\tt x[]} and {\tt y[]} vectors as follows. i.e., {\tt y[i] := x[i]} and {\tt x[i] := y[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVzero ( int n, float y[] ) ; \end{verbatim} \index{FVzero@{\tt FVzero()}} This method zeroes {\tt n} entries in {\tt y[]}, i.e., {\tt y[i] = 0} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void FVshuffle ( int n, float y[], int seed ) ; \end{verbatim} \index{FVshuffle@{\tt FVshuffle()}} This method shuffles the first {\tt n} entries in {\tt y[]}. The value {\tt seed} is the seed to a random number generator, and one can get repeatable behavior by repeating {\tt seed}. %----------------------------------------------------------------------- \end{enumerate} Utilities/doc/PCV.tex010064400020550007177000000031230653410575300157720ustar00clevecompmath00000400000006\par \subsection{{\tt PCV} : {\tt char *} vector methods} \label{subsection:Utilities:proto:PCV} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} char ** PCVinit ( int n ) ; \end{verbatim} \index{PCVinit@{\tt PCVinit()}} This is the allocator and initializer method for {\tt char*} vectors. Storage for an array with size {\tt n} is found and each entry is filled with {\tt NULL}. A pointer to the array is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void PCVfree ( char **p_vec ) ; \end{verbatim} \index{PCVfree@{\tt PCVfree()}} This method releases the storage taken by {\tt p\_vec[]}. %----------------------------------------------------------------------- \item \begin{verbatim} void PCVcopy ( int n, char *p_y[], char *p_x[] ) ; \end{verbatim} \index{PCVcopy@{\tt PCVcopy()}} This method copies {\tt n} entries from {\tt p\_x[]} to {\tt p\_y[]}, i.e., {\tt p\_y[i] = p\_x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void PCVsetup ( int n, int sizes[], char vec[], char *p_vec[] ) ; \end{verbatim} \index{PCVsetup@{\tt PCVsetup()}} This method sets the entries of {\tt p\_vec[]} as pointers into {\tt vec[]} given by the {\tt sizes[]} vector, i.e., {\tt p\_vec[0] = vec}, and {\tt p\_vec[i] = p\_vec[i-1] + sizes[i-1]} for {\tt 0 < i < n}. %----------------------------------------------------------------------- \end{enumerate} Utilities/doc/PDV.tex010064400020550007177000000031430653410575300157750ustar00clevecompmath00000400000006\par \subsection{{\tt PDV} : {\tt double *} vector methods} \label{subsection:Utilities:proto:PDV} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} double ** PDVinit ( int n ) ; \end{verbatim} \index{PDVinit@{\tt PDVinit()}} This is the allocator and initializer method for {\tt double*} vectors. Storage for an array with size {\tt n} is found and each entry is filled with {\tt NULL}. A pointer to the array is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void PDVfree ( double **p_vec ) ; \end{verbatim} \index{PDVfree@{\tt PDVfree()}} This method releases the storage taken by {\tt p\_vec[]}. %----------------------------------------------------------------------- \item \begin{verbatim} void PDVcopy ( int n, double *p_y[], double *p_x[] ) ; \end{verbatim} \index{PDVcopy@{\tt PDVcopy()}} This method copies {\tt n} entries from {\tt p\_x[]} to {\tt p\_y[]}, i.e., {\tt p\_y[i] = p\_x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void PDVsetup ( int n, int sizes[], double vec[], double *p_vec[] ) ; \end{verbatim} \index{PDVsetup@{\tt PDVsetup()}} This method sets the entries of {\tt p\_vec[]} as pointers into {\tt vec[]} given by the {\tt sizes[]} vector, i.e., {\tt p\_vec[0] = vec}, and {\tt p\_vec[i] = p\_vec[i-1] + sizes[i-1]} for {\tt 0 < i < n}. %----------------------------------------------------------------------- \end{enumerate} Utilities/doc/PIV.tex010064400020550007177000000031210653410575400157770ustar00clevecompmath00000400000006\par \subsubsection{{\tt PIV} : {\tt int *} vector methods} \label{subsubsection:Utilities:proto:PIV} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ** PIVinit ( int n ) ; \end{verbatim} \index{PIVinit@{\tt PIVinit()}} This is the allocator and initializer method for {\tt int*} vectors. Storage for an array with size {\tt n} is found and each entry is filled with {\tt NULL}. A pointer to the array is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void PIVfree ( int **p_vec ) ; \end{verbatim} \index{PIVfree@{\tt PIVfree()}} This method releases the storage taken by {\tt p\_vec[]}. %----------------------------------------------------------------------- \item \begin{verbatim} void PIVcopy ( int n, int *p_y[], int *p_x[] ) ; \end{verbatim} \index{PIVcopy@{\tt PIVcopy()}} This method copies {\tt n} entries from {\tt p\_x[]} to {\tt p\_y[]}, i.e., {\tt p\_y[i] = p\_x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void PIVsetup ( int n, int sizes[], int vec[], int *p_vec[] ) ; \end{verbatim} \index{PIVsetup@{\tt PIVsetup()}} This method sets the entries of {\tt p\_vec[]} as pointers into {\tt vec[]} given by the {\tt sizes[]} vector, i.e., {\tt p\_vec[0] = vec}, and {\tt p\_vec[i] = p\_vec[i-1] + sizes[i-1]} for {\tt 0 < i < n}. %----------------------------------------------------------------------- \end{enumerate} Utilities/doc/PFV.tex010064400020550007177000000031330653410575400157770ustar00clevecompmath00000400000006\par \subsection{{\tt PFV} : {\tt float *} vector methods} \label{subsection:Utilities:proto:PFV} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} float ** PFVinit ( int n ) ; \end{verbatim} \index{PFVinit@{\tt PFVinit()}} This is the allocator and initializer method for {\tt float*} vectors. Storage for an array with size {\tt n} is found and each entry is filled with {\tt NULL}. A pointer to the array is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void PFVfree ( float **p_vec ) ; \end{verbatim} \index{PFVfree@{\tt PFVfree()}} This method releases the storage taken by {\tt p\_vec[]}. %----------------------------------------------------------------------- \item \begin{verbatim} void PFVcopy ( int n, float *p_y[], float *p_x[] ) ; \end{verbatim} \index{PFVcopy@{\tt PFVcopy()}} This method copies {\tt n} entries from {\tt p\_x[]} to {\tt p\_y[]}, i.e., {\tt p\_y[i] = p\_x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void PFVsetup ( int n, int sizes[], float vec[], float *p_vec[] ) ; \end{verbatim} \index{PFVsetup@{\tt PFVsetup()}} This method sets the entries of {\tt p\_vec[]} as pointers into {\tt vec[]} given by the {\tt sizes[]} vector, i.e., {\tt p\_vec[0] = vec}, and {\tt p\_vec[i] = p\_vec[i-1] + sizes[i-1]} for {\tt 0 < i < n}. %----------------------------------------------------------------------- \end{enumerate} Utilities/doc/sort.tex010064400020550007177000000347720653556221400163470ustar00clevecompmath00000400000006\par \subsection{Sorting routines} \label{subsection:Utilities:proto:sort} \par \subsubsection{Validation routines} \label{subsubsection:Utilities:proto:sort:validate} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int IVisascending ( int n, int ivec[] ) ; int IVisdescending ( int n, int ivec[] ) ; \end{verbatim} \index{IVisascending@{\tt IVisascending()}} \index{IVisdescending@{\tt IVisdescending()}} These methods returns {\tt 1} if the array {\tt ivec[]} is in ascending or descending order and returns {\tt 0} otherwise. %----------------------------------------------------------------------- \item \begin{verbatim} int DVisascending ( int n, double dvec[] ) ; int DVisdescending ( int n, double dvec[] ) ; \end{verbatim} \index{DVisascending@{\tt DVisascending()}} \index{DVisdescending@{\tt DVisdescending()}} These methods returns {\tt 1} if the array {\tt dvec[]} is in ascending or descending order and returns {\tt 0} otherwise. %----------------------------------------------------------------------- \end{enumerate} \par \subsubsection{Insert sort routines} \label{subsubsection:Utilities:proto:sort:insert} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void IVisortUp ( int n, int ivec[] ) ; void IVisortDown ( int n, int ivec[] ) ; \end{verbatim} \index{IVisortUp@{\tt IVisortUp()}} \index{IVisortDown@{\tt IVisortDown()}} These methods sort an {\tt int} array into ascending or descending order using an insertion sort. %----------------------------------------------------------------------- \item \begin{verbatim} void IV2isortUp ( int n, int ivec1[], int ivec2[] ) ; void IV2isortDown ( int n, int ivec1[], int ivec2[] ) ; \end{verbatim} \index{IV2isortUp@{\tt IV2isortUp()}} \index{IV2isortDown@{\tt IV2isortDown()}} These methods sort the array {\tt ivec1[]} into ascending or descending order using an insertion sort and permutes the {\tt int} companion array {\tt ivec2[]} in the same fashion. %----------------------------------------------------------------------- \item \begin{verbatim} void IVDVisortUp ( int n, int ivec[], double dvec[] ) ; void IVDVisortDown ( int n, int ivec[], double dvec[] ) ; \end{verbatim} \index{IVDVisortUp@{\tt IVDVisortUp()}} \index{IVDVisortDown@{\tt IVDVisortDown()}} This sorts the array {\tt ivec[]} into ascending or descending order using an insertion sort and permutes the companion array {\tt dvec[]} in the same fashion. %----------------------------------------------------------------------- \item \begin{verbatim} void IV2DVisortUp ( int n, int ivec1[], int ivec2[], double dvec[] ) ; void IV2DVisortDown ( int n, int ivec1[], int ivec2[], double dvec[] ) ; \end{verbatim} \index{IV2DVisortUp@{\tt IV2DVisortUp()}} \index{IV2DVisortDown@{\tt IV2DVisortDown()}} These methods sort the array {\tt ivec1[]} into ascending or descending order using an insertion sort and permutes the {\tt int} and {\tt double} companion array {\tt ivec2[]} and {\tt dvec[]} in the same fashion. %----------------------------------------------------------------------- \item \begin{verbatim} void IVZVisortUp ( int n, int ivec[], double dvec[] ) ; void IVZVisortDown ( int n, int ivec[], double dvec[] ) ; \end{verbatim} \index{IVZVisortUp@{\tt IVZVisortUp()}} \index{IVZVisortDown@{\tt IVZVisortDown()}} This sorts the array {\tt ivec[]} into ascending or descending order using an insertion sort and permutes the double precision complex companion array {\tt dvec[]} in the same fashion. %----------------------------------------------------------------------- \item \begin{verbatim} void IV2ZVisortUp ( int n, int ivec1[], int ivec2[], double dvec[] ) ; void IV2ZVisortDown ( int n, int ivec1[], int ivec2[], double dvec[] ) ; \end{verbatim} \index{IV2ZVisortUp@{\tt IV2ZVisortUp()}} \index{IV2ZVisortDown@{\tt IV2ZVisortDown()}} These methods sort the array {\tt ivec1[]} into ascending or descending order using an insertion sort and permutes the companion arrays {\tt ivec2[]} and {\tt dvec[]} in the same fashion. The {\tt dvec[]} array is double precision complex. %----------------------------------------------------------------------- \item \begin{verbatim} void DVisortUp ( int n, double dvec[] ) ; void DVisortDown ( int n, double dvec[] ) ; \end{verbatim} \index{DVisortUp@{\tt DVisortUp()}} \index{DVisortDown@{\tt DVisortDown()}} These methods sort a {\tt double} array into ascending or descending order using an insertion sort. %----------------------------------------------------------------------- \item \begin{verbatim} void DV2isortUp ( int n, double dvec1[], double dvec2[] ) ; void DV2isortDown ( int n, double dvec1[], double dvec2[] ) ; \end{verbatim} \index{DV2isortUp@{\tt DV2isortUp()}} \index{DV2isortDown@{\tt DV2isortDown()}} These methods sort the array {\tt dvec1[]} into ascending or descending order using an insertion sort and permutes the companion array {\tt dvec2[]} in the same fashion. %----------------------------------------------------------------------- \item \begin{verbatim} void DVIVisortUp ( int n, double dvec[], int ivec[] ) ; void DVIVisortDown ( int n, double dvec[], int ivec[] ) ; \end{verbatim} \index{DVIVisortUp@{\tt DVIVisortUp()}} \index{DVIVisortDown@{\tt DVIVisortDown()}} These methods sort the array {\tt dvec[]} into ascending or descending order using an insertion sort and permutes the companion array {\tt ivec[]} in the same fashion. %----------------------------------------------------------------------- \end{enumerate} \par \subsubsection{Quicksort routines} \label{subsubsection:Utilities:proto:sort:quicksort} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void IVqsortUp ( int n, int ivec[] ) ; void IVqsortDown ( int n, int ivec[] ) ; \end{verbatim} \index{IVqsortUp@{\tt IVqsortUp()}} \index{IVqsortDown@{\tt IVqsortDown()}} These methods sort an {\tt int} array into ascending or descending order using a quick sort. %----------------------------------------------------------------------- \item \begin{verbatim} void IV2qsortUp ( int n, int ivec1[], int ivec2[] ) ; void IV2qsortDown ( int n, int ivec1[], int ivec2[] ) ; \end{verbatim} \index{IV2qsortUp@{\tt IV2qsortUp()}} \index{IV2qsortDown@{\tt IV2qsortDown()}} These methods sort the array {\tt ivec1[]} into ascending or descending order using a quick sort and permutes the companion array {\tt ivec2[]} in the same fashion. %----------------------------------------------------------------------- \item \begin{verbatim} void IVDVqsortUp ( int n, int ivec[], double dvec[] ) ; void IVDVqsortDown ( int n, int ivec[], double dvec[] ) ; \end{verbatim} \index{IVDVqsortUp@{\tt IVDVqsortUp()}} \index{IVDVqsortDown@{\tt IVDVqsortDown()}} These methods sort the array {\tt ivec[]} into ascending or descending order using a quick sort and permutes the companion array {\tt dvec[]} in the same fashion. %----------------------------------------------------------------------- \item \begin{verbatim} void IV2DVqsortUp ( int n, int ivec1[], int ivec2[], double dvec[] ) ; void IV2DVqsortDown ( int n, int ivec1[], int ivec2[], double dvec[] ) ; \end{verbatim} \index{IV2DVqsortUp@{\tt IV2DVqsortUp()}} \index{IV2DVqsortDown@{\tt IV2DVqsortDown()}} These methods sort the array {\tt ivec1[]} into ascending or descending order using a quick sort and permutes the companion arrays {\tt ivec2[]} and {\tt dvec[]} in the same fashion. %----------------------------------------------------------------------- \item \begin{verbatim} void IVZVqsortUp ( int n, int ivec[], double dvec[] ) ; void IVZVqsortDown ( int n, int ivec[], double dvec[] ) ; \end{verbatim} \index{IVZVqsortUp@{\tt IVZVqsortUp()}} \index{IVZVqsortDown@{\tt IVZVqsortDown()}} These methods sort the array {\tt ivec[]} into ascending or descending order using a quick sort and permutes the double precision complex companion array {\tt dvec[]} in the same fashion. %----------------------------------------------------------------------- \item \begin{verbatim} void IV2ZVqsortUp ( int n, int ivec1[], int ivec2[], double dvec[] ) ; void IV2ZVqsortDown ( int n, int ivec1[], int ivec2[], double dvec[] ) ; \end{verbatim} \index{IV2ZVqsortUp@{\tt IV2ZVqsortUp()}} \index{IV2ZVqsortDown@{\tt IV2ZVqsortDown()}} These methods sort the array {\tt ivec1[]} into ascending or descending order using a quick sort and permutes the companion arrays {\tt ivec2[]} and {\tt dvec[]} in the same fashion. The {\tt dvec[]} array is double precision complex. %----------------------------------------------------------------------- \item \begin{verbatim} void DVqsortUp ( int n, double dvec[] ) ; void DVqsortDown ( int n, double dvec[] ) ; \end{verbatim} \index{DVqsortUp@{\tt DVqsortUp()}} \index{DVqsortDown@{\tt DVqsortDown()}} Thes methods sort a {\tt double} array into ascending or descending order using a quick sort. %----------------------------------------------------------------------- \item \begin{verbatim} void DV2qsortUp ( int n, double dvec1[], double dvec2[] ) ; void DV2qsortDown ( int n, double dvec1[], double dvec2[] ) ; \end{verbatim} \index{DV2qsortUp@{\tt DV2qsortUp()}} \index{DV2qsortDown@{\tt DV2qsortDown()}} These methods sort the array {\tt dvec1[]} into ascending or descending order using a quick sort and permutes the companion array {\tt dvec2[]} in the same fashion. %----------------------------------------------------------------------- \item \begin{verbatim} void DVIVqsortUp ( int n, double dvec[], int ivec[] ) ; void DVIVqsortDown ( int n, double dvec[], int ivec[] ) ; \end{verbatim} \index{DVIVqsortUp@{\tt DVIVqsortUp()}} \index{DVIVqsortDown@{\tt DVIVqsortDown()}} These methods sort the array {\tt dvec[]} into ascending or descending order using a quick sort and permutes the companion array {\tt ivec[]} in the same fashion. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Sort and compress routines} \label{subsection:Utilities:proto:sortAndCompress} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int IVsortUpAndCompress ( int n, int ivec[] ) ; \end{verbatim} \index{IVsortUpAndCompress@{\tt IVsortUpAndCompress()}} This method sorts {\tt ivec[]} into ascending order, and removes (compresses) any duplicate entries. The return value is the number of unique entries stored in the leading locations of the vector {\tt ivec[]}. \par \noindent {\it Error checking:} If {\tt n < 0} or {\tt ivec} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IVDVsortUpAndCompress ( int n, int ivec[], double dvec[] ) ; \end{verbatim} \index{IVDVsortUpAndCompress@{\tt IVDVsortUpAndCompress()}} This method sorts {\tt ivec[]} into ascending order with {\tt dvec[]} as a companion vector. It then compresses the pairs, adding the {\tt dvec[]} entries together when their {\tt ivec[]} values are identical. The return value is the number of unique entries stored in the leading locations of the vectors {\tt ivec[]} and {\tt dvec[]}. \par \noindent {\it Error checking:} If {\tt n < 0}, or if {\tt ivec} or {\tt dvec} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IVZVsortUpAndCompress ( int n, int ivec[], double dvec[] ) ; \end{verbatim} \index{IVZVsortUpAndCompress@{\tt IVZVsortUpAndCompress()}} This method sorts {\tt ivec[]} into ascending order with the double precision complex {\tt dvec[]} companion vector. It then compresses the pairs, adding the complex {\tt dvec[]} entries together when their {\tt ivec[]} values are identical. The return value is the number of unique entries stored in the leading locations of the vectors {\tt ivec[]} and {\tt dvec[]}. \par \noindent {\it Error checking:} If {\tt n < 0}, or if {\tt ivec} or {\tt dvec} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV2sortUpAndCompress ( int n, int ivec1[], int ivec2[] ) ; \end{verbatim} \index{IV2sortUpAndCompress@{\tt IV2sortUpAndCompress()}} This method sorts {\tt ivec1[]} into ascending order with {\tt ivec2[]} as a companion vector. It then compresses the pairs, dropping all but one of identical pairs. The return value is the number of unique entries stored in the leading locations of the vectors {\tt ivec1[]} and {\tt ivec2[]}. \par \noindent {\it Error checking:} If {\tt n < 0}, or if {\tt ivec1} or {\tt ivec2} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV2DVsortUpAndCompress ( int n, int ivec1[], int ivec2[], double dvec[] ) ; \end{verbatim} \index{IV2DVsortUpAndCompress@{\tt IV2DVsortUpAndCompress()}} This method sorts {\tt ivec1[]} into ascending order with {\tt ivec2[]} and {\tt dvec[]} as companion vectors. It then compresses the pairs, summing the {\tt dvec[]} entries for identical {\tt (ivec1[], ivec2[])} pairs. The return value is the number of unique entries stored in the leading locations of the vectors {\tt ivec1[]}, {\tt ivec2[]} and {\tt dvec[]}. \par \noindent {\it Error checking:} If {\tt n < 0}, or if {\tt ivec1}, {\tt ivec2} or {\tt dvec} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int IV2ZVsortUpAndCompress ( int n, int ivec1[], int ivec2[], double dvec[] ) ; \end{verbatim} \index{IV2ZVsortUpAndCompress@{\tt IV2ZVsortUpAndCompress()}} This method sorts {\tt ivec1[]} into ascending order with {\tt ivec2[]} and the double precision {\tt dvec[]} as companion vectors. It then compresses the pairs, summing the complex {\tt dvec[]} entries for identical {\tt (ivec1[], ivec2[])} pairs. The return value is the number of unique entries stored in the leading locations of the vectors {\tt ivec1[]}, {\tt ivec2[]} and {\tt dvec[]}. \par \noindent {\it Error checking:} If {\tt n < 0}, or if {\tt ivec1}, {\tt ivec2} or {\tt dvec} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} hods sUtilities/doc/IP.tex010064400020550007177000000065240656763322700156720ustar00clevecompmath00000400000006\par \subsection{{\tt IP} : {\tt (int, pointer)} singly linked-list methods} \label{subsection:Utilities:proto:IP} \par \hspace{0.5 in} \begin{minipage}{2.5 in} \begin{verbatim} typedef struct _IP IP ; struct _IP { int val ; IP *next ; } ; \end{verbatim} \end{minipage} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} IP * IP_init ( int n, int flag ) ; \end{verbatim} \index{IP_init@{\tt IP\_init()}} This is the allocator and initializer method for a vector of {\tt (int,pointer)} structures. Storage for an array with size {\tt n} is found. A pointer to an array {\tt ips[]} is returned with {\tt ips[i].val = 0} for {\tt 0 <= i < n}. The {\tt flag} parameter determines how the {\tt next} field is filled. \begin{itemize} \item If {\tt flag = 0}, the elements are not linked, i.e., {\tt ips[i].next = NULL} for {\tt 0 <= i < n}. \item If {\tt flag = 1}, the elements are linked in a forward manner, i.e., {\tt ips[i].next = \&ips[i+1]} for {\tt 0 <= i < n-1} and {\tt ips[n-1].next = NULL}. \item If {\tt flag = 2}, the elements are linked in a backward manner, i.e., {\tt ips[i].next = \&ips[i-1]} for {\tt 0 < i < n} and {\tt ips[0].next = NULL}. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} void IP_free ( IP *ip ) ; \end{verbatim} \index{IP_free@{\tt IP\_free()}} This method releases the storage based at {\tt *ip}. %----------------------------------------------------------------------- \item \begin{verbatim} void IP_fprintf ( FILE *fp, IP *ip ) ; \end{verbatim} \index{IP_fprintf@{\tt IP\_fprintf()}} This method prints the singly linked list that starts with {\tt ip}. %----------------------------------------------------------------------- \item \begin{verbatim} int IP_fp80 ( FILE *fp, int n, int y[], int column, int *pierr ) ; \end{verbatim} \index{IP_fp80@{\tt IP\_fp80()}} This method prints the singly linked list that starts with {\tt ip}. See {\tt IVfp80()} for a description of how the entries are placed on a line. %----------------------------------------------------------------------- \item \begin{verbatim} IP * IP_mergeUp ( IP *ip1, IP *ip2 ) ; \end{verbatim} \index{IP_mergeUp@{\tt IP\_mergeUp()}} This method merges two singly linked lists into one. If the two lists are in ascending order, the new list is also in ascending order. The head of the new list is returned. %----------------------------------------------------------------------- \item \begin{verbatim} IP * IP_mergeSortUp ( IP *ip ) ; \end{verbatim} \index{IP_mergeSortUp@{\tt IP\_mergeSortUp()}} This method sorts a list into ascending order using a merge sort. %----------------------------------------------------------------------- \item \begin{verbatim} IP * IP_radixSortUp ( IP *ip ) ; \end{verbatim} \index{IP_radixSortUp@{\tt IP\_radixSortUp()}} This method sorts a list into ascending order using a radix sort. %----------------------------------------------------------------------- \item \begin{verbatim} IP * IP_radixSortDown ( IP *ip ) ; \end{verbatim} \index{IP_radixSortDown@{\tt IP\_radixSortDown()}} This method sorts a list into descending order using a radix sort. %----------------------------------------------------------------------- \end{enumerate} Utilities/doc/main.ind010064400020550007177000000146550653560365200162560ustar00clevecompmath00000400000006\begin{theindex} \item {\tt CVcopy()}, 2 \item {\tt CVfill()}, 2 \item {\tt CVfp80()}, 2 \item {\tt CVfprintf()}, 2 \item {\tt CVfree()}, 2 \item {\tt CVfscanf()}, 2 \item {\tt CVinit()}, 2 \item {\tt CVinit2()}, 2 \indexspace \item {\tt DV2isortDown()}, 21 \item {\tt DV2isortUp()}, 21 \item {\tt DV2qsortDown()}, 22 \item {\tt DV2qsortUp()}, 22 \item {\tt DVadd()}, 3 \item {\tt DVaxpy()}, 3 \item {\tt DVaxpyi()}, 3 \item {\tt DVcompress()}, 3 \item {\tt DVcopy()}, 3 \item {\tt DVdot()}, 3 \item {\tt DVdot11()}, 5 \item {\tt DVdot12()}, 5 \item {\tt DVdot13()}, 5 \item {\tt DVdot21()}, 5 \item {\tt DVdot22()}, 4 \item {\tt DVdot23()}, 4 \item {\tt DVdot31()}, 4 \item {\tt DVdot32()}, 4 \item {\tt DVdot33()}, 3 \item {\tt DVdoti()}, 5 \item {\tt DVfill()}, 5 \item {\tt DVfprintf()}, 3 \item {\tt DVfree()}, 3 \item {\tt DVfscanf()}, 3 \item {\tt DVgather()}, 5 \item {\tt DVgatherAddZero()}, 5 \item {\tt DVgatherZero()}, 6 \item {\tt DVinit()}, 2 \item {\tt DVinit2()}, 3 \item {\tt DVinvPerm()}, 6 \item {\tt DVisascending()}, 20 \item {\tt DVisdescending()}, 20 \item {\tt DVisortDown()}, 21 \item {\tt DVisortUp()}, 21 \item {\tt DVIVisortDown()}, 21 \item {\tt DVIVisortUp()}, 21 \item {\tt DVIVqsortDown()}, 22 \item {\tt DVIVqsortUp()}, 22 \item {\tt DVmax()}, 6 \item {\tt DVmaxabs()}, 6 \item {\tt DVmin()}, 6 \item {\tt DVminabs()}, 6 \item {\tt DVperm()}, 6 \item {\tt DVqsortDown()}, 22 \item {\tt DVqsortUp()}, 22 \item {\tt DVramp()}, 6 \item {\tt DVscale()}, 6 \item {\tt DVscatter()}, 6 \item {\tt DVscatterAdd()}, 7 \item {\tt DVscatterAddZero()}, 7 \item {\tt DVscatterZero()}, 7 \item {\tt DVshuffle()}, 7 \item {\tt DVsub()}, 7 \item {\tt DVsum()}, 7 \item {\tt DVsumabs()}, 7 \item {\tt DVswap()}, 7 \item {\tt DVzero()}, 7 \indexspace \item {\tt FVadd()}, 16 \item {\tt FVaxpy()}, 16 \item {\tt FVaxpyi()}, 16 \item {\tt FVcompress()}, 16 \item {\tt FVcopy()}, 17 \item {\tt FVdot()}, 17 \item {\tt FVfill()}, 17 \item {\tt FVfprintf()}, 16 \item {\tt FVfree()}, 16 \item {\tt FVfscanf()}, 16 \item {\tt FVgather()}, 17 \item {\tt FVgatherAddZero()}, 17 \item {\tt FVgatherZero()}, 17 \item {\tt FVinit()}, 16 \item {\tt FVinit2()}, 16 \item {\tt FVinvPerm()}, 17 \item {\tt FVmax()}, 17 \item {\tt FVmaxabs()}, 17 \item {\tt FVmin()}, 17 \item {\tt FVminabs()}, 17 \item {\tt FVperm()}, 17 \item {\tt FVramp()}, 17 \item {\tt FVscale()}, 18 \item {\tt FVscatter()}, 18 \item {\tt FVscatterAddZero()}, 18 \item {\tt FVscatterZero()}, 18 \item {\tt FVshuffle()}, 18 \item {\tt FVsub()}, 18 \item {\tt FVsum()}, 18 \item {\tt FVsumabs()}, 18 \item {\tt FVswap()}, 18 \item {\tt FVzero()}, 18 \indexspace \item {\tt I2OP\_fprintf()}, 25 \item {\tt I2OP\_free()}, 25 \item {\tt I2OP\_init()}, 25 \item {\tt I2OP\_initStorage()}, 25 \item {\tt IP\_fp80()}, 24, 25 \item {\tt IP\_fprintf()}, 24 \item {\tt IP\_free()}, 24 \item {\tt IP\_init()}, 24 \item {\tt IP\_mergeSortUp()}, 24 \item {\tt IP\_mergeUp()}, 24 \item {\tt IP\_radixSortDown()}, 24 \item {\tt IP\_radixSortUp()}, 24 \item {\tt IV2DVisortDown()}, 21 \item {\tt IV2DVisortUp()}, 21 \item {\tt IV2DVqsortDown()}, 22 \item {\tt IV2DVqsortUp()}, 22 \item {\tt IV2DVsortUpAndCompress()}, 23 \item {\tt IV2isortDown()}, 20 \item {\tt IV2isortUp()}, 20 \item {\tt IV2qsortDown()}, 21 \item {\tt IV2qsortUp()}, 21 \item {\tt IV2sortUpAndCompress()}, 23 \item {\tt IV2ZVisortDown()}, 21 \item {\tt IV2ZVisortUp()}, 21 \item {\tt IV2ZVqsortDown()}, 22 \item {\tt IV2ZVqsortUp()}, 22 \item {\tt IV2ZVsortUpAndCompress()}, 23 \item {\tt IVcompress()}, 14 \item {\tt IVcopy()}, 14 \item {\tt IVDVisortDown()}, 20 \item {\tt IVDVisortUp()}, 20 \item {\tt IVDVqsortDown()}, 22 \item {\tt IVDVqsortUp()}, 22 \item {\tt IVDVsortUpAndCompress()}, 23 \item {\tt IVfill()}, 14 \item {\tt IVfp80()}, 14 \item {\tt IVfprintf()}, 14 \item {\tt IVfree()}, 14 \item {\tt IVfscanf()}, 14 \item {\tt IVgather()}, 14 \item {\tt IVinit()}, 14 \item {\tt IVinit2()}, 14 \item {\tt IVinverse()}, 14 \item {\tt IVinvPerm()}, 15 \item {\tt IVisascending()}, 20 \item {\tt IVisdescending()}, 20 \item {\tt IVisortDown()}, 20 \item {\tt IVisortUp()}, 20 \item {\tt IVlocateViaBinarySearch()}, 15 \item {\tt IVmax()}, 15 \item {\tt IVmaxabs()}, 15 \item {\tt IVmin()}, 15 \item {\tt IVminabs()}, 15 \item {\tt IVperm()}, 15 \item {\tt IVqsortDown()}, 21 \item {\tt IVqsortUp()}, 21 \item {\tt IVramp()}, 15 \item {\tt IVscatter()}, 15 \item {\tt IVshuffle()}, 16 \item {\tt IVsortUpAndCompress()}, 22 \item {\tt IVsum()}, 15 \item {\tt IVsumabs()}, 15 \item {\tt IVswap()}, 15 \item {\tt IVzero()}, 16 \item {\tt IVZVisortDown()}, 21 \item {\tt IVZVisortUp()}, 21 \item {\tt IVZVqsortDown()}, 22 \item {\tt IVZVqsortUp()}, 22 \item {\tt IVZVsortUpAndCompress()}, 23 \indexspace \item {\tt PCVcopy()}, 19 \item {\tt PCVfree()}, 18 \item {\tt PCVinit()}, 18 \item {\tt PCVsetup()}, 19 \item {\tt PDVcopy()}, 19 \item {\tt PDVfree()}, 19 \item {\tt PDVinit()}, 19 \item {\tt PDVsetup()}, 19 \item {\tt PFVcopy()}, 20 \item {\tt PFVfree()}, 20 \item {\tt PFVinit()}, 20 \item {\tt PFVsetup()}, 20 \item {\tt PIVcopy()}, 19 \item {\tt PIVfree()}, 19 \item {\tt PIVinit()}, 19 \item {\tt PIVsetup()}, 19 \indexspace \item {\tt Zabs()}, 8 \item {\tt Zrecip()}, 8 \item {\tt Zrecip2()}, 8 \item {\tt ZVaxpy()}, 8 \item {\tt ZVcopy()}, 8 \item {\tt ZVdotC()}, 8 \item {\tt ZVdotC11()}, 13 \item {\tt ZVdotC12()}, 13 \item {\tt ZVdotC13()}, 12 \item {\tt ZVdotC21()}, 12 \item {\tt ZVdotC22()}, 12 \item {\tt ZVdotC23()}, 12 \item {\tt ZVdotC31()}, 11 \item {\tt ZVdotC32()}, 11 \item {\tt ZVdotC33()}, 11 \item {\tt ZVdotiC()}, 9 \item {\tt ZVdotiU()}, 8 \item {\tt ZVdotU()}, 8 \item {\tt ZVdotU11()}, 11 \item {\tt ZVdotU12()}, 11 \item {\tt ZVdotU13()}, 10 \item {\tt ZVdotU21()}, 10 \item {\tt ZVdotU22()}, 10 \item {\tt ZVdotU23()}, 10 \item {\tt ZVdotU31()}, 9 \item {\tt ZVdotU32()}, 9 \item {\tt ZVdotU33()}, 9 \item {\tt ZVfprintf()}, 8 \item {\tt ZVgather()}, 13 \item {\tt ZVinit()}, 7 \item {\tt ZVmaxabs()}, 13 \item {\tt ZVminabs()}, 13 \item {\tt ZVscale()}, 13 \item {\tt ZVscatter()}, 13 \item {\tt ZVsub()}, 13 \item {\tt ZVzero()}, 13 \end{theindex} \item {\tt FVperm()}, 17 \item {\tt FVramp()}, 17 \item {\tt FVscale()}, 18 Utilities/doc/main.idx010064400020550007177000000232440653560376700162710ustar00clevecompmath00000400000006\indexentry{CVinit@{\tt CVinit()}}{2} \indexentry{CVinit2@{\tt CVinit2()}}{2} \indexentry{CVfree@{\tt CVfree()}}{2} \indexentry{CVcopy@{\tt CVcopy()}}{2} \indexentry{CVfill@{\tt CVfill()}}{2} \indexentry{CVfprintf@{\tt CVfprintf()}}{2} \indexentry{CVfp80@{\tt CVfp80()}}{2} \indexentry{CVfscanf@{\tt CVfscanf()}}{2} \indexentry{DVinit@{\tt DVinit()}}{2} \indexentry{DVinit2@{\tt DVinit2()}}{3} \indexentry{DVfree@{\tt DVfree()}}{3} \indexentry{DVfprintf@{\tt DVfprintf()}}{3} \indexentry{DVfscanf@{\tt DVfscanf()}}{3} \indexentry{DVadd@{\tt DVadd()}}{3} \indexentry{DVaxpy@{\tt DVaxpy()}}{3} \indexentry{DVaxpy@{\tt DVaxpy()}}{3} \indexentry{DVaxpyi@{\tt DVaxpyi()}}{3} \indexentry{DVcompress@{\tt DVcompress()}}{3} \indexentry{DVcopy@{\tt DVcopy()}}{3} \indexentry{DVdot@{\tt DVdot()}}{3} \indexentry{DVdot33@{\tt DVdot33()}}{3} \indexentry{DVdot32@{\tt DVdot32()}}{4} \indexentry{DVdot31@{\tt DVdot31()}}{4} \indexentry{DVdot23@{\tt DVdot23()}}{4} \indexentry{DVdot22@{\tt DVdot22()}}{4} \indexentry{DVdot21@{\tt DVdot21()}}{5} \indexentry{DVdot13@{\tt DVdot13()}}{5} \indexentry{DVdot12@{\tt DVdot12()}}{5} \indexentry{DVdot11@{\tt DVdot11()}}{5} \indexentry{DVdoti@{\tt DVdoti()}}{5} \indexentry{DVfill@{\tt DVfill()}}{5} \indexentry{DVgather@{\tt DVgather()}}{5} \indexentry{DVgatherAddZero@{\tt DVgatherAddZero()}}{5} \indexentry{DVgatherZero@{\tt DVgatherZero()}}{6} \indexentry{DVinvPerm@{\tt DVinvPerm()}}{6} \indexentry{DVmax@{\tt DVmax()}}{6} \indexentry{DVmaxabs@{\tt DVmaxabs()}}{6} \indexentry{DVmin@{\tt DVmin()}}{6} \indexentry{DVminabs@{\tt DVminabs()}}{6} \indexentry{DVperm@{\tt DVperm()}}{6} \indexentry{DVramp@{\tt DVramp()}}{6} \indexentry{DVscale@{\tt DVscale()}}{6} \indexentry{DVscale@{\tt DVscale()}}{6} \indexentry{DVscatter@{\tt DVscatter()}}{6} \indexentry{DVscatterAdd@{\tt DVscatterAdd()}}{7} \indexentry{DVscatterAddZero@{\tt DVscatterAddZero()}}{7} \indexentry{DVscatterZero@{\tt DVscatterZero()}}{7} \indexentry{DVsub@{\tt DVsub()}}{7} \indexentry{DVsum@{\tt DVsum()}}{7} \indexentry{DVsumabs@{\tt DVsumabs()}}{7} \indexentry{DVswap@{\tt DVswap()}}{7} \indexentry{DVzero@{\tt DVzero()}}{7} \indexentry{DVshuffle@{\tt DVshuffle()}}{7} \indexentry{ZVinit@{\tt ZVinit()}}{7} \indexentry{ZVfprintf@{\tt ZVfprintf()}}{8} \indexentry{Zabs@{\tt Zabs()}}{8} \indexentry{Zrecip@{\tt Zrecip()}}{8} \indexentry{Zrecip2@{\tt Zrecip2()}}{8} \indexentry{ZVaxpy@{\tt ZVaxpy()}}{8} \indexentry{ZVaxpy@{\tt ZVaxpy()}}{8} \indexentry{ZVcopy@{\tt ZVcopy()}}{8} \indexentry{ZVdotU@{\tt ZVdotU()}}{8} \indexentry{ZVdotC@{\tt ZVdotC()}}{8} \indexentry{ZVdotiU@{\tt ZVdotiU()}}{8} \indexentry{ZVdotiC@{\tt ZVdotiC()}}{9} \indexentry{ZVdotU33@{\tt ZVdotU33()}}{9} \indexentry{ZVdotU32@{\tt ZVdotU32()}}{9} \indexentry{ZVdotU31@{\tt ZVdotU31()}}{9} \indexentry{ZVdotU23@{\tt ZVdotU23()}}{10} \indexentry{ZVdotU22@{\tt ZVdotU22()}}{10} \indexentry{ZVdotU21@{\tt ZVdotU21()}}{10} \indexentry{ZVdotU13@{\tt ZVdotU13()}}{10} \indexentry{ZVdotU12@{\tt ZVdotU12()}}{11} \indexentry{ZVdotU11@{\tt ZVdotU11()}}{11} \indexentry{ZVdotC33@{\tt ZVdotC33()}}{11} \indexentry{ZVdotC32@{\tt ZVdotC32()}}{11} \indexentry{ZVdotC31@{\tt ZVdotC31()}}{11} \indexentry{ZVdotC23@{\tt ZVdotC23()}}{12} \indexentry{ZVdotC22@{\tt ZVdotC22()}}{12} \indexentry{ZVdotC21@{\tt ZVdotC21()}}{12} \indexentry{ZVdotC13@{\tt ZVdotC13()}}{12} \indexentry{ZVdotC12@{\tt ZVdotC12()}}{13} \indexentry{ZVdotC11@{\tt ZVdotC11()}}{13} \indexentry{ZVgather@{\tt ZVgather()}}{13} \indexentry{ZVmaxabs@{\tt ZVmaxabs()}}{13} \indexentry{ZVminabs@{\tt ZVminabs()}}{13} \indexentry{ZVscale@{\tt ZVscale()}}{13} \indexentry{ZVscale@{\tt ZVscale()}}{13} \indexentry{ZVscatter@{\tt ZVscatter()}}{13} \indexentry{ZVsub@{\tt ZVsub()}}{13} \indexentry{ZVzero@{\tt ZVzero()}}{13} \indexentry{IVinit@{\tt IVinit()}}{14} \indexentry{IVinit2@{\tt IVinit2()}}{14} \indexentry{IVfree@{\tt IVfree()}}{14} \indexentry{IVfprintf@{\tt IVfprintf()}}{14} \indexentry{IVfp80@{\tt IVfp80()}}{14} \indexentry{IVfscanf@{\tt IVfscanf()}}{14} \indexentry{IVcompress@{\tt IVcompress()}}{14} \indexentry{IVcopy@{\tt IVcopy()}}{14} \indexentry{IVfill@{\tt IVfill()}}{14} \indexentry{IVgather@{\tt IVgather()}}{14} \indexentry{IVinverse@{\tt IVinverse()}}{14} \indexentry{IVinvPerm@{\tt IVinvPerm()}}{15} \indexentry{IVlocateViaBinarySearch@{\tt IVlocateViaBinarySearch()}}{15} \indexentry{IVmax@{\tt IVmax()}}{15} \indexentry{IVmaxabs@{\tt IVmaxabs()}}{15} \indexentry{IVmin@{\tt IVmin()}}{15} \indexentry{IVminabs@{\tt IVminabs()}}{15} \indexentry{IVperm@{\tt IVperm()}}{15} \indexentry{IVramp@{\tt IVramp()}}{15} \indexentry{IVscatter@{\tt IVscatter()}}{15} \indexentry{IVsum@{\tt IVsum()}}{15} \indexentry{IVsumabs@{\tt IVsumabs()}}{15} \indexentry{IVswap@{\tt IVswap()}}{15} \indexentry{IVzero@{\tt IVzero()}}{16} \indexentry{IVshuffle@{\tt IVshuffle()}}{16} \indexentry{FVinit@{\tt FVinit()}}{16} \indexentry{FVinit2@{\tt FVinit2()}}{16} \indexentry{FVfree@{\tt FVfree()}}{16} \indexentry{FVfprintf@{\tt FVfprintf()}}{16} \indexentry{FVfscanf@{\tt FVfscanf()}}{16} \indexentry{FVadd@{\tt FVadd()}}{16} \indexentry{FVaxpy@{\tt FVaxpy()}}{16} \indexentry{FVaxpyi@{\tt FVaxpyi()}}{16} \indexentry{FVcompress@{\tt FVcompress()}}{16} \indexentry{FVcopy@{\tt FVcopy()}}{17} \indexentry{FVdot@{\tt FVdot()}}{17} \indexentry{FVfill@{\tt FVfill()}}{17} \indexentry{FVgather@{\tt FVgather()}}{17} \indexentry{FVgatherAddZero@{\tt FVgatherAddZero()}}{17} \indexentry{FVgatherZero@{\tt FVgatherZero()}}{17} \indexentry{FVinvPerm@{\tt FVinvPerm()}}{17} \indexentry{FVmax@{\tt FVmax()}}{17} \indexentry{FVmaxabs@{\tt FVmaxabs()}}{17} \indexentry{FVmin@{\tt FVmin()}}{17} \indexentry{FVminabs@{\tt FVminabs()}}{17} \indexentry{FVperm@{\tt FVperm()}}{17} \indexentry{FVramp@{\tt FVramp()}}{17} \indexentry{FVscale@{\tt FVscale()}}{18} \indexentry{FVscatter@{\tt FVscatter()}}{18} \indexentry{FVscatterAddZero@{\tt FVscatterAddZero()}}{18} \indexentry{FVscatterZero@{\tt FVscatterZero()}}{18} \indexentry{FVsub@{\tt FVsub()}}{18} \indexentry{FVsum@{\tt FVsum()}}{18} \indexentry{FVsumabs@{\tt FVsumabs()}}{18} \indexentry{FVswap@{\tt FVswap()}}{18} \indexentry{FVzero@{\tt FVzero()}}{18} \indexentry{FVshuffle@{\tt FVshuffle()}}{18} \indexentry{PCVinit@{\tt PCVinit()}}{18} \indexentry{PCVfree@{\tt PCVfree()}}{18} \indexentry{PCVcopy@{\tt PCVcopy()}}{19} \indexentry{PCVsetup@{\tt PCVsetup()}}{19} \indexentry{PDVinit@{\tt PDVinit()}}{19} \indexentry{PDVfree@{\tt PDVfree()}}{19} \indexentry{PDVcopy@{\tt PDVcopy()}}{19} \indexentry{PDVsetup@{\tt PDVsetup()}}{19} \indexentry{PIVinit@{\tt PIVinit()}}{19} \indexentry{PIVfree@{\tt PIVfree()}}{19} \indexentry{PIVcopy@{\tt PIVcopy()}}{19} \indexentry{PIVsetup@{\tt PIVsetup()}}{19} \indexentry{PFVinit@{\tt PFVinit()}}{20} \indexentry{PFVfree@{\tt PFVfree()}}{20} \indexentry{PFVcopy@{\tt PFVcopy()}}{20} \indexentry{PFVsetup@{\tt PFVsetup()}}{20} \indexentry{IVisascending@{\tt IVisascending()}}{20} \indexentry{IVisdescending@{\tt IVisdescending()}}{20} \indexentry{DVisascending@{\tt DVisascending()}}{20} \indexentry{DVisdescending@{\tt DVisdescending()}}{20} \indexentry{IVisortUp@{\tt IVisortUp()}}{20} \indexentry{IVisortDown@{\tt IVisortDown()}}{20} \indexentry{IV2isortUp@{\tt IV2isortUp()}}{20} \indexentry{IV2isortDown@{\tt IV2isortDown()}}{20} \indexentry{IVDVisortUp@{\tt IVDVisortUp()}}{20} \indexentry{IVDVisortDown@{\tt IVDVisortDown()}}{20} \indexentry{IV2DVisortUp@{\tt IV2DVisortUp()}}{21} \indexentry{IV2DVisortDown@{\tt IV2DVisortDown()}}{21} \indexentry{IVZVisortUp@{\tt IVZVisortUp()}}{21} \indexentry{IVZVisortDown@{\tt IVZVisortDown()}}{21} \indexentry{IV2ZVisortUp@{\tt IV2ZVisortUp()}}{21} \indexentry{IV2ZVisortDown@{\tt IV2ZVisortDown()}}{21} \indexentry{DVisortUp@{\tt DVisortUp()}}{21} \indexentry{DVisortDown@{\tt DVisortDown()}}{21} \indexentry{DV2isortUp@{\tt DV2isortUp()}}{21} \indexentry{DV2isortDown@{\tt DV2isortDown()}}{21} \indexentry{DVIVisortUp@{\tt DVIVisortUp()}}{21} \indexentry{DVIVisortDown@{\tt DVIVisortDown()}}{21} \indexentry{IVqsortUp@{\tt IVqsortUp()}}{21} \indexentry{IVqsortDown@{\tt IVqsortDown()}}{21} \indexentry{IV2qsortUp@{\tt IV2qsortUp()}}{21} \indexentry{IV2qsortDown@{\tt IV2qsortDown()}}{21} \indexentry{IVDVqsortUp@{\tt IVDVqsortUp()}}{22} \indexentry{IVDVqsortDown@{\tt IVDVqsortDown()}}{22} \indexentry{IV2DVqsortUp@{\tt IV2DVqsortUp()}}{22} \indexentry{IV2DVqsortDown@{\tt IV2DVqsortDown()}}{22} \indexentry{IVZVqsortUp@{\tt IVZVqsortUp()}}{22} \indexentry{IVZVqsortDown@{\tt IVZVqsortDown()}}{22} \indexentry{IV2ZVqsortUp@{\tt IV2ZVqsortUp()}}{22} \indexentry{IV2ZVqsortDown@{\tt IV2ZVqsortDown()}}{22} \indexentry{DVqsortUp@{\tt DVqsortUp()}}{22} \indexentry{DVqsortDown@{\tt DVqsortDown()}}{22} \indexentry{DV2qsortUp@{\tt DV2qsortUp()}}{22} \indexentry{DV2qsortDown@{\tt DV2qsortDown()}}{22} \indexentry{DVIVqsortUp@{\tt DVIVqsortUp()}}{22} \indexentry{DVIVqsortDown@{\tt DVIVqsortDown()}}{22} \indexentry{IVsortUpAndCompress@{\tt IVsortUpAndCompress()}}{22} \indexentry{IVDVsortUpAndCompress@{\tt IVDVsortUpAndCompress()}}{23} \indexentry{IVZVsortUpAndCompress@{\tt IVZVsortUpAndCompress()}}{23} \indexentry{IV2sortUpAndCompress@{\tt IV2sortUpAndCompress()}}{23} \indexentry{IV2DVsortUpAndCompress@{\tt IV2DVsortUpAndCompress()}}{23} \indexentry{IV2ZVsortUpAndCompress@{\tt IV2ZVsortUpAndCompress()}}{23} \indexentry{IP_init@{\tt IP\_init()}}{24} \indexentry{IP_free@{\tt IP\_free()}}{24} \indexentry{IP_fprintf@{\tt IP\_fprintf()}}{24} \indexentry{IP_fp80@{\tt IP\_fp80()}}{24} \indexentry{IP_mergeUp@{\tt IP\_mergeUp()}}{24} \indexentry{IP_mergeSortUp@{\tt IP\_mergeSortUp()}}{24} \indexentry{IP_radixSortUp@{\tt IP\_radixSortUp()}}{24} \indexentry{IP_radixSortDown@{\tt IP\_radixSortDown()}}{24} \indexentry{I2OP_init@{\tt I2OP\_init()}}{25} \indexentry{I2OP_initStorage@{\tt I2OP\_initStorage()}}{25} \indexentry{I2OP_free@{\tt I2OP\_free()}}{25} \indexentry{I2OP_fprintf@{\tt I2OP\_fprintf()}}{25} \indexentry{IP_fp80@{\tt IP\_fp80()}}{25} try{ZVdotU31@{\tt ZVdotU31()}}{9} \indexentry{ZVdotU23@{\tt ZVdotU23()}}{10} \indexentry{ZVdotU22@{\tt ZVdotU22()}}{10} \indexentry{ZVdotU21@{\tt ZVdotU21()}}{10} \indexentry{ZVdotU13@{\tt ZVdotU13()}}{10} \indexentry{ZVdotU12@{\tt ZVdotU12()}}{11} \indexentry{ZVdotU11@{\tt ZVdotU11()}}{11} \indexentry{ZVdotC33@{\tt ZVdotC33()}}{11} \indexentry{ZUtilities/doc/main.ilg010064400020550007177000000004630653560365200162470ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (223 entries accepted, 0 rejected). Sorting entries.....done (1851 comparisons). Generating output file main.ind....done (237 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. Utilities/doc/makefile010064400020550007177000000000270654276751400163300ustar00clevecompmath00000400000006clean : - rm -f *.dvi Utilities/doc/I2OP.tex010064400020550007177000000055760665016612100160640ustar00clevecompmath00000400000006\par \subsection{{\tt I2OP} : {\tt (int, int, void*, pointer)} singly linked-list methods} \label{subsection:Utilities:proto:I2OP} \par \hspace{0.5 in} \begin{minipage}{2.5 in} \begin{verbatim} typedef struct _I2OP I2OP ; struct _I2OP { int value0 ; int value1 ; void value2 ; I2OP *next ; } ; \end{verbatim} \end{minipage} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} I2OP * I2OP_init ( int n, int flag ) ; \end{verbatim} \index{I2OP_init@{\tt I2OP\_init()}} This is the allocator and initializer method for a vector of {\tt I2OP} structures. Storage for an array with size {\tt n} is found. A pointer to an array {\tt ips[]} is returned with {\tt ips[i].val = 0} for {\tt 0 <= i < n}. The {\tt flag} parameter determines how the {\tt next} field is filled. \begin{itemize} \item If {\tt flag = I2OP\_NULL}, the elements are not linked, i.e., {\tt ips[i].next = NULL} for {\tt 0 <= i < n}. \item If {\tt flag = I2OP\_FORWARD}, the elements are linked in a forward manner, i.e., {\tt ips[i].next = \&ips[i+1]} for {\tt 0 <= i < n-1} and {\tt ips[n-1].next = NULL}. \item If {\tt flag = I2OP\_BACKWARD}, the elements are linked in a backward manner, i.e., {\tt ips[i].next = \&ips[i-1]} for {\tt 0 < i < n} and {\tt ips[0].next = NULL}. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} I2OP * I2OP_initStorage ( int n, int flag, I2OP *base ) ; \end{verbatim} \index{I2OP_initStorage@{\tt I2OP\_initStorage()}} This is an initializer method for a vector of {\tt I2OP} structures. We set {\tt base[i].value0 = base[i].value1 = -1}. The {\tt flag} parameter determines how the {\tt next} field is filled. \begin{itemize} \item If {\tt flag = I2OP\_NULL}, the elements are not linked, i.e., {\tt ips[i].next = NULL} for {\tt 0 <= i < n}. \item If {\tt flag = I2OP\_FORWARD}, the elements are linked in a forward manner, i.e., {\tt ips[i].next = \&ips[i+1]} for {\tt 0 <= i < n-1} and {\tt ips[n-1].next = NULL}. \item If {\tt flag = I2OP\_BACKWARD}, the elements are linked in a backward manner, i.e., {\tt ips[i].next = \&ips[i-1]} for {\tt 0 < i < n} and {\tt ips[0].next = NULL}. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} void I2OP_free ( I2OP *i2op ) ; \end{verbatim} \index{I2OP_free@{\tt I2OP\_free()}} This method releases the storage based at {\tt *i2op}. %----------------------------------------------------------------------- \item \begin{verbatim} void I2OP_fprintf ( FILE *fp, I2OP *i2op ) ; \end{verbatim} \index{I2OP_fprintf@{\tt I2OP\_fprintf()}} This method prints the singly linked list that starts with {\tt i2op}. %----------------------------------------------------------------------- \end{enumerate} Utilities/doc/ZV.tex010064400020550007177000000627360665016772400157250ustar00clevecompmath00000400000006\par \subsection{{\tt ZV} : {\tt double complex } vector methods} \label{subsection:Utilities:proto:ZV} \par A double precision complex vector of length {\tt n} is simply a double precision vector of length {\tt 2n}. There is a separate {\tt ZVinit()} allocator and initializer method, since it requires a real and imaginary part to fill the vector. However, there is no {\tt ZVinit2()} method (which allocates without initializing the entries) nor a {\tt ZVfree()} method to free the entries; the {\tt DVinit2()} and {\tt DVfree()} methods can be used. Similarly, there is no {\tt ZVfscanf()} method, instead the {\tt DVfscanf()} method can be used. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} double * ZVinit ( int n, double real, double imag ) ; \end{verbatim} \index{ZVinit@{\tt ZVinit()}} This is the allocator and initializer method for {\tt double complex} vectors. Storage for an array with size {\tt n} is found and each entry is filled with {\tt (real,imag)}. A pointer to the array is returned. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVfprintf ( FILE *fp, int n, double y[] ) ; \end{verbatim} \index{ZVfprintf@{\tt ZVfprintf()}} This method prints {\tt n} entries in {\tt y[]} to file {\tt fp}. The format is new line followed by {\tt "< \%12.4e, \%12.4e >"} format. %----------------------------------------------------------------------- \item \begin{verbatim} double Zabs ( double real, double imag ) ; \end{verbatim} \index{Zabs@{\tt Zabs()}} This method returns the magnitude of {\tt (real,imag)}. %----------------------------------------------------------------------- \item \begin{verbatim} int Zrecip ( double areal, double aimag, double *pbreal, double *pbimag ) ; \end{verbatim} \index{Zrecip@{\tt Zrecip()}} This method fills {\tt *pbreal} and {\tt *pbimag} with the real and imaginary parts of the reciprocal of {\tt (areal,aimag)}. The return value is {\tt 0} if {\tt areal} and {\tt aimag} are zero, otherwise the return value is {\tt 1}. %----------------------------------------------------------------------- \item \begin{verbatim} int Zrecip2 ( double areal, double aimag, double breal, double bimag, double creal, double cimag, double dreal, double dimag, double *pereal, double *peimag, double *pfreal, double *pfimag, double *pgreal, double *pgimag, double *phreal, double *phimag ) ; \end{verbatim} \index{Zrecip2@{\tt Zrecip2()}} This method computes $ \displaystyle \left \lbrack \begin{array}{cc} e & f \\ g & h \end{array} \right \rbrack = \left \lbrack \begin{array}{cc} a & b \\ c & d \end{array} \right \rbrack^{-1} $. If {\tt pereal} is not {\tt NULL}, then {\tt *pereal} is loaded with the real part of $e$. If {\tt peimag} is not {\tt NULL}, then {\tt *peimag} is loaded with the imaginary part of $e$. Similarly for $f$, $g$ and $h$. The return value is {\tt 0} if $2 \times 2$ matrix is singular, otherwise the return value is {\tt 1}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVaxpy ( int n, double y[], double areal, double aimag, double x[] ) ; \end{verbatim} \index{ZVaxpy@{\tt ZVaxpy()}} This method adds a scaled multiple of {\tt n} entries from {\tt x[]} into {\tt y[]}, i.e., {\tt y[i] += (areal,aimag) * x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVaxpy2 ( int n, double z[], double areal, double aimag, double x[], double breal, double bimag, double y[] ) ; \end{verbatim} \index{ZVaxpy@{\tt ZVaxpy()}} This method adds a scaled multiple of two vectors {\tt x[]} and {\tt y[]} to another vector {\tt z[]}, i.e., i.e., {\tt z[i] += (areal,aimag) * x[i] + (breal,bimag) * y[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVaxpy33 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[], double x1[], double x2[] ) ; \end{verbatim} \index{ZVaxpy33@{\tt ZVaxpy33()}} This method computes the following. \begin{verbatim} y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] + alpha[4:5] * x2[] y1[] = y1[] + alpha[6:7] * x0[] + alpha[8:9] * x1[] + alpha[10:11] * x2[] y2[] = y2[] + alpha[12:13] * x0[] + alpha[14:15] * x1[] + alpha[16:17] * x2[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void ZVaxpy32 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[], double x1[] ) ; \end{verbatim} \index{ZVaxpy32@{\tt ZVaxpy32()}} This method computes the following. \begin{verbatim} y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] y1[] = y1[] + alpha[4:5] * x0[] + alpha[6:7] * x1[] y2[] = y2[] + alpha[8:9] * x0[] + alpha[10:11] * x1[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void ZVaxpy31 ( int n, double y0[], double y1[], double y2[], double alpha[], double x0[] ) ; \end{verbatim} \index{ZVaxpy31@{\tt ZVaxpy31()}} This method computes the following. \begin{verbatim} y0[] = y0[] + alpha[0:1] * x0[] y1[] = y1[] + alpha[2:3] * x0[] y2[] = y2[] + alpha[4:5] * x0[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void ZVaxpy23 ( int n, double y0[], double y1[], double alpha[], double x0[], double x1[], double x2[] ) ; \end{verbatim} \index{ZVaxpy23@{\tt ZVaxpy23()}} This method computes the following. \begin{verbatim} y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] + alpha[4:5] * x2[] y1[] = y1[] + alpha[6:7] * x0[] + alpha[8:9] * x1[] + alpha[10:11] * x2[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void ZVaxpy22 ( int n, double y0[], double y1[], double alpha[], double x0[], double x1[] ) ; \end{verbatim} \index{ZVaxpy22@{\tt ZVaxpy22()}} This method computes the following. \begin{verbatim} y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] y1[] = y1[] + alpha[4:5] * x0[] + alpha[6:7] * x1[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void ZVaxpy21 ( int n, double y0[], double y1[], double alpha[], double x0[] ) ; \end{verbatim} \index{ZVaxpy21@{\tt ZVaxpy21()}} This method computes the following. \begin{verbatim} y0[] = y0[] + alpha[0:1] * x0[] y1[] = y1[] + alpha[2:3] * x0[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void ZVaxpy13 ( int n, double y0[], double alpha[], double x0[], double x1[], double x2[] ) ; \end{verbatim} \index{ZVaxpy13@{\tt ZVaxpy13()}} This method computes the following. \begin{verbatim} y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] + alpha[4:5] * x2[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void ZVaxpy12 ( int n, double y0[], double alpha[], double x0[], double x1[] ) ; \end{verbatim} \index{ZVaxpy12@{\tt ZVaxpy12()}} This method computes the following. \begin{verbatim} y0[] = y0[] + alpha[0:1] * x0[] + alpha[2:3] * x1[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void ZVaxpy11 ( int n, double y0[], double alpha[], double x0[] ) ; \end{verbatim} \index{ZVaxpy11@{\tt ZVaxpy11()}} This method computes the following. \begin{verbatim} y0[] = y0[] + alpha[0:1] * x0[] \end{verbatim} %----------------------------------------------------------------------- \item \begin{verbatim} void ZVcopy ( int n, double y[], double x[] ) ; \end{verbatim} \index{ZVcopy@{\tt ZVcopy()}} This method copies {\tt n} entries from {\tt x[]} to {\tt y[]}, i.e., {\tt y[i] = x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVdotU ( int n, double y[], double x[], double *prdot, double *pidot ) ; \end{verbatim} \index{ZVdotU@{\tt ZVdotU()}} This method fills {\tt *prdot} and {\tt *pidot} with the real and imaginary part of ${\tt y}^T{\tt x}$, the dot product of the vector {\tt x[]} and {\tt y[]}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVdotC ( int n, double y[], double x[], double *prdot, double *pidot ) ; \end{verbatim} \index{ZVdotC@{\tt ZVdotC()}} This method fills {\tt *prdot} and {\tt *pidot} with the real and imaginary part of ${\tt y}^H{\tt x}$, the dot product of the vector {\tt x[]} and {\tt y[]}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVdotiU ( int n, double y[], int index[], double x[], double *prdot, double *pidot ) ; \end{verbatim} \index{ZVdotiU@{\tt ZVdotiU()}} This method fills {\tt *prdot} and {\tt *pidot} with the real and imaginary parts of the indexed dot product $\displaystyle \sum_{{\tt i=0}}^{{\tt n-1}} {\tt y[index[i]] * x[i]}$. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVdotiC ( int n, double y[], int index[], double x[], double *prdot, double *pidot ) ; \end{verbatim} \index{ZVdotiC@{\tt ZVdotiC()}} This method fills {\tt *prdot} and {\tt *pidot} with the real and imaginary parts of the indexed dot product $\displaystyle \sum_{{\tt i=0}}^{{\tt n-1}} \overline{\tt y[index[i]]} * {\tt x[i]}$. %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotU33 ( int n, double row0[], double row1[], double row2[], double col0[], double col1[], double col2[], double sums[] ) ; \end{verbatim} \index{ZVdotU33@{\tt ZVdotU33()}} This method computes nine dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0;1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col2[i]}$ & $\displaystyle{\tt sums[6:7]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ \\ $\displaystyle{\tt sums[8:9]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col1[i]}$ & $\displaystyle{\tt sums[10:11]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col2[i]}$ \\ $\displaystyle{\tt sums[12:13]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col0[i]}$ & $\displaystyle{\tt sums[14:15]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col1[i]}$ \\ $\displaystyle{\tt sums[16:17]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col2[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotU32 ( int n, double row0[], double row1[], double row2[], double col0[], double col1[], double sums[] ) ; \end{verbatim} \index{ZVdotU32@{\tt ZVdotU32()}} This method computes six dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ & $\displaystyle{\tt sums[6:7]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col1[i]}$ \\ $\displaystyle{\tt sums[8:9]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col0[i]}$ & $\displaystyle{\tt sums[10:11]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col1[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotU31 ( int n, double row0[], double row1[], double row2[], double col0[], double sums[] ) ; \end{verbatim} \index{ZVdotU31@{\tt ZVdotU31()}} This method computes three dot products. \par \begin{tabular}{l} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ \\ $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row2[i] * col0[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotU23 ( int n, double row0[], double row1[], double col0[], double col1[], double col2[], double sums[] ) ; \end{verbatim} \index{ZVdotU23@{\tt ZVdotU23()}} This method computes six dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col2[i]}$ & $\displaystyle{\tt sums[6:7]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ \\ $\displaystyle{\tt sums[8:9]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col1[i]}$ & $\displaystyle{\tt sums[10:11]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col2[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotU22 ( int n, double row0[], double row1[], double col0[], double col1[], double sums[] ) ; \end{verbatim} \index{ZVdotU22@{\tt ZVdotU22()}} This method computes four dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ & $\displaystyle{\tt sums[6:7]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col1[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotU21 ( int n, double row0[], double row1[], double col0[], double sums[] ) ; \end{verbatim} \index{ZVdotU21@{\tt ZVdotU21()}} This method computes two dot products. \par \begin{tabular}{l} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ \\ $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row1[i] * col0[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotU13 ( int n, double row0[], double col0[], double col1[], double col2[], double sums[] ) ; \end{verbatim} \index{ZVdotU13@{\tt ZVdotU13()}} This method computes six dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col2[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotU12 ( int n, double row0[], double row1[], double col0[], double col1[], double sums[] ) ; \end{verbatim} \index{ZVdotU12@{\tt ZVdotU12()}} This method computes two dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col1[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotU11 ( int n, double row0[], double col0[], double sums[] ) ; \end{verbatim} \index{ZVdotU11@{\tt ZVdotU11()}} This method computes one dot product. \par \begin{tabular}{l} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} {\tt row0[i] * col0[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotC33 ( int n, double row0[], double row1[], double row2[], double col0[], double col1[], double col2[], double sums[] ) ; \end{verbatim} \index{ZVdotC33@{\tt ZVdotC33()}} This method computes nine dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0;1]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col1[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col2[i]}$ & $\displaystyle{\tt sums[6:7]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col0[i]}$ \\ $\displaystyle{\tt sums[8:9]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col1[i]}$ & $\displaystyle{\tt sums[10:11]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col2[i]}$ \\ $\displaystyle{\tt sums[12:13]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row2[i]} * {\tt col0[i]}$ & $\displaystyle{\tt sums[14:15]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row2[i]} * {\tt col1[i]}$ \\ $\displaystyle{\tt sums[16:17]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row2[i]} * {\tt col2[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotC32 ( int n, double row0[], double row1[], double row2[], double col0[], double col1[], double sums[] ) ; \end{verbatim} \index{ZVdotC32@{\tt ZVdotC32()}} This method computes six dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col1[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col0[i]}$ & $\displaystyle{\tt sums[6:7]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col1[i]}$ \\ $\displaystyle{\tt sums[8:9]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row2[i]} * {\tt col0[i]}$ & $\displaystyle{\tt sums[10:11]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row2[i]} * {\tt col1[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotC31 ( int n, double row0[], double row1[], double row2[], double col0[], double sums[] ) ; \end{verbatim} \index{ZVdotC31@{\tt ZVdotC31()}} This method computes three dot products. \par \begin{tabular}{l} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col0[i]}$ \\ $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col0[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row2[i]} * {\tt col0[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotC23 ( int n, double row0[], double row1[], double col0[], double col1[], double col2[], double sums[] ) ; \end{verbatim} \index{ZVdotC23@{\tt ZVdotC23()}} This method computes six dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col1[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col2[i]}$ & $\displaystyle{\tt sums[6:7]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col0[i]}$ \\ $\displaystyle{\tt sums[8:9]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col1[i]}$ & $\displaystyle{\tt sums[10:11]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col2[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotC22 ( int n, double row0[], double row1[], double col0[], double col1[], double sums[] ) ; \end{verbatim} \index{ZVdotC22@{\tt ZVdotC22()}} This method computes four dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col1[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col0[i]}$ & $\displaystyle{\tt sums[6:7]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col1[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotC21 ( int n, double row0[], double row1[], double col0[], double sums[] ) ; \end{verbatim} \index{ZVdotC21@{\tt ZVdotC21()}} This method computes two dot products. \par \begin{tabular}{l} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col0[i]}$ \\ $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row1[i]} * {\tt col0[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotC13 ( int n, double row0[], double col0[], double col1[], double col2[], double sums[] ) ; \end{verbatim} \index{ZVdotC13@{\tt ZVdotC13()}} This method computes six dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col1[i]}$ \\ $\displaystyle{\tt sums[4:5]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col2[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotC12 ( int n, double row0[], double row1[], double col0[], double col1[], double sums[] ) ; \end{verbatim} \index{ZVdotC12@{\tt ZVdotC12()}} This method computes two dot products. \par \begin{tabular}{ll} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col0[i]}$ & $\displaystyle{\tt sums[2:3]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col1[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} int ZVdotC11 ( int n, double row0[], double col0[], double sums[] ) ; \end{verbatim} \index{ZVdotC11@{\tt ZVdotC11()}} This method computes one dot product. \par \begin{tabular}{l} $\displaystyle{\tt sums[0:1]} = \sum_{\tt i = 0}^{\tt n-1} \overline{\tt row0[i]} * {\tt col0[i]}$ \end{tabular} %----------------------------------------------------------------------- \item \begin{verbatim} void ZVgather ( int n, double y[], double x[], int index[] ) ; \end{verbatim} \index{ZVgather@{\tt ZVgather()}} {\tt y[i] = x[index[i]]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} double ZVmaxabs ( int n, double y[] ) ; \end{verbatim} \index{ZVmaxabs@{\tt ZVmaxabs()}} This method returns the maximum magnitude of entries in {\tt y[0:n-1]}. %----------------------------------------------------------------------- \item \begin{verbatim} double ZVminabs ( int n, double y[] ) ; \end{verbatim} \index{ZVminabs@{\tt ZVminabs()}} This method returns the minimum magnitude of entries in {\tt y[0:n-1]}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVscale ( int n, double y[], double areal, double aimag ) ; \end{verbatim} \index{ZVscale@{\tt ZVscale()}} This method scales a vector {\tt y[]} by {\tt (areal,aimag)}, i.e., {\tt y[i] *= (areal,aimag)}. for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVscale2 ( int n, double x[], double y[], double areal, double aimag, double breal, double bimag, double creal, double cimag, double dreal, double dimag ) ; \end{verbatim} \index{ZVscale@{\tt ZVscale()}} This method scales two vectors {\tt y[]} by a $2 \times 2$ matrix, i.e., $$ \left \lbrack \begin{array}{ccc} {\tt x[0]} & \ldots & {\tt x[n-1]} \\ {\tt y[0]} & \ldots & {\tt y[n-1]} \end{array} \right \rbrack := \left \lbrack \begin{array}{cc} {\tt (areal,aimag)} & {\tt (breal,bimag)} \\ {\tt (creal,cimag)} & {\tt (dreal,dimag)} \end{array} \right \rbrack \left \lbrack \begin{array}{ccc} {\tt x[0]} & \ldots & {\tt x[n-1]} \\ {\tt y[0]} & \ldots & {\tt y[n-1]} \end{array} \right \rbrack. $$ %----------------------------------------------------------------------- \item \begin{verbatim} void ZVscatter ( int n, double y[], int index[], double x[] ) ; \end{verbatim} \index{ZVscatter@{\tt ZVscatter()}} This method scatters {\tt n} entries of {\tt x[]} into {\tt y[]} as follows, {\tt y[index[i]] = x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVsub ( int n, double y[], double x[] ) ; \end{verbatim} \index{ZVsub@{\tt ZVsub()}} This method subtracts {\tt n} entries from {\tt x[]} to {\tt y[]}, i.e., {\tt y[i] -= x[i]} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZVzero ( int n, double y[] ) ; \end{verbatim} \index{ZVzero@{\tt ZVzero()}} This method zeroes {\tt n} entries in {\tt y[]}, i.e., {\tt y[i] = 0} for {\tt 0 <= i < n}. %----------------------------------------------------------------------- \end{enumerate} }{ll} $\displaystyle{\tt sums[0:1]Utilities/doc/drivers.tex010064400020550007177000000062530653560376100170320ustar00clevecompmath00000400000006\par \section{Driver programs } \label{section:Utilities:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} test_sort msglvl msgFile target sortType n range mod seed \end{verbatim} This driver program tests the sort methods. Use the script file {\tt do\_test\_sort} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt target} parameter denotes the type of vector(s) to be sorted. \begin{itemize} \item {\tt IV} --- {\tt int} vector sort \item {\tt IV2} --- {(\tt int, int)} vector sort \item {\tt IVDV} --- {(\tt int, double)} vector sort \item {\tt IV2DV} --- {(\tt int, int, double)} vector sort \item {\tt IVZV} --- {(\tt int, complex)} vector sort \item {\tt IV2ZV} --- {(\tt int, int, complex)} vector sort \item {\tt DV} --- {\tt double} vector sort \item {\tt DV2} --- {(\tt double, double)} vector sort \item {\tt DVIV} --- {(\tt double, int)} vector sort \end{itemize} \item The {\tt sortType} parameter denotes the type of sort. \begin{itemize} \item {\tt IU} --- ascending insert sort \item {\tt ID} --- descending insert sort \item {\tt QU} --- ascending quick sort \item {\tt QD} --- descending quick sort \end{itemize} \item The {\tt n} parameter is the length of the vector(s). \item Integer entries are of the form {\tt k} mod {\tt mod}, where {\tt k} in {\tt [0,range]}. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} test_sortUpAndCompress msglvl msgFile target n range mod seed \end{verbatim} This driver program tests the ``sort in ascending order and compress'' methods. Use the script file {\tt do\_test\_sortUpAndCompress} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt target} parameter denotes the type of vector(s) to be sorted. \begin{itemize} \item {\tt IV} --- {\tt int} vector sort \item {\tt IV2} --- {(\tt int, int)} vector sort \item {\tt IVDV} --- {(\tt int, double)} vector sort \item {\tt IV2DV} --- {(\tt int, int, double)} vector sort \item {\tt IVZV} --- {(\tt int, complex)} vector sort \item {\tt IV2ZV} --- {(\tt int, int, complex)} vector sort \end{itemize} \item The {\tt n} parameter is the length of the vector(s). \item Integer entries are of the form {\tt k} mod {\tt mod}, where {\tt k} in {\tt [0,range]}. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} ZV.h010064400020550007177000000000640653410636700126130ustar00clevecompmath00000400000006#ifndef _ZV_ #define _ZV_ #include "ZV/ZV.h" #endif ZV/ZV.h010064400020550007177000000266540653510657700131730ustar00clevecompmath00000400000006/* ZV.h */ #include "../DV.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- ZV -- double complex vector object size -- size of the vector maxsize -- maximum size of the vector owned -- owner flag when == 1, storage pointed to by entries has been allocated here and can be free'd. when == 0, storage pointed to by entries has not been allocated here and cannot be free'd. vec -- pointer to base address --------------------------------------------------------- */ typedef struct _ZV ZV ; struct _ZV { int size ; int maxsize ; int owned ; double *vec ; } ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in basics.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------- constructor method created -- 98jan22, cca ----------------------- */ ZV * ZV_new ( void ) ; /* ----------------------- set the default fields created -- 98jan22, cca ----------------------- */ void ZV_setDefaultFields ( ZV *zv ) ; /* ----------------------- clear the data fields created -- 98jan22, cca ----------------------- */ void ZV_clearData ( ZV *zv ) ; /* ----------------------- destructor created -- 98jan22, cca ----------------------- */ void ZV_free ( ZV *zv ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in init.c ------------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------------------- simplest initialization method data is cleared if entries != NULL the object does not own the entries, it just points to the entries base address else if size > 0 the object will own the entries, it allocates a vector of 2*size doubles's. else nothing happens endif created -- 98jan22, cca --------------------------------------------- */ void ZV_init ( ZV *zv, int size, double *entries ) ; /* ------------------------- basic initializion method created -- 98jan22, cca ------------------------- */ void ZV_init1 ( ZV *zv, int size ) ; /* ------------------------- total initializion method created -- 98jan22, cca ------------------------- */ void ZV_init2 ( ZV *zv, int size, int maxsize, int owned, double *vec ) ; /* ---------------------------------- set the maximum size of the vector created -- 98jan22, cca ---------------------------------- */ void ZV_setMaxsize ( ZV *zv, int newmaxsize ) ; /* -------------------------- set the size of the vector created -- 98jan22, cca -------------------------- */ void ZV_setSize ( ZV *zv, int newsize ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in instance.c -------------------------------------- ------------------------------------------------------------------------ */ /* ----------------------------------------------- return 1 if the entries are owned by the object return 0 otherwise created -- 98jan22, cca ----------------------------------------------- */ int ZV_owned ( ZV *dv ) ; /* ----------------------- return the vector size created -- 98jan22, cca ----------------------- */ int ZV_maxsize ( ZV *dv ) ; /* ----------------------- return the vector size created -- 98jan22, cca ----------------------- */ int ZV_size ( ZV *dv ) ; /* ------------------------------------------------- return the loc'th entry of a vector. created -- 98jan22, cca ------------------------------------------------- */ void ZV_entry ( ZV *dv, int loc, double *pReal, double *pImag ) ; /* ------------------------------------------------- return pointers to the loc'th entry of a vector. created -- 98jan22, cca ------------------------------------------------- */ void ZV_pointersToEntry ( ZV *dv, int loc, double **ppReal, double **ppImag ) ; /* ---------------------------------------------- return a pointer to the object's entries array created -- 98jan22, cca ---------------------------------------------- */ double * ZV_entries ( ZV *dv ) ; /* -------------------------------------------- fill *psize with the vector's size and *pentries with the address of the vector created -- 98jan22, cca -------------------------------------------- */ void ZV_sizeAndEntries ( ZV *dv, int *psize, double **pentries ) ; /* --------------------------- set and entry in the vector created -- 98jan22, cca --------------------------- */ void ZV_setEntry ( ZV *dv, int loc, double real, double imag ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in util.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ----------------------------------------------------------- shift the base of the entries and adjust the dimensions note: this is a dangerous operation because the zv->vec does not point to the base of the entries any longer, and thus if the object owns its entries and it is called to resize them or to free them, malloc and free will choke. USE WITH CAUTION! created -- 98jan22, cca ----------------------------------------------------------- */ void ZV_shiftBase ( ZV *zv, int offset ) ; /* -------------------------------------- push an entry onto the list created -- 95oct06, cca -------------------------------------- */ void ZV_push ( ZV *zv, double real, double imag ) ; /* --------------------------- minimum and maximum entries created -- 95oct06, cca --------------------------- */ double ZV_minabs ( ZV *zv ) ; /* ---------------------------------------------- return the number of bytes taken by the object created -- 95oct06, cca ---------------------------------------------- */ int ZV_sizeOf ( ZV *zv ) ; /* -------------------------- fill a vector with a value created -- 96jun22, cca -------------------------- */ void ZV_fill ( ZV *zv, double real, double imag ) ; /* ------------------------ fill a vector with zeros created -- 98jun02, cca ------------------------ */ void ZV_zero ( ZV *zv ) ; /* -------------------------------------- copy entries from zv2 into zv1. note: this is a "mapped" copy, zv1 and zv2 need not be the same size. created -- 96aug31, cca -------------------------------------- */ void ZV_copy ( ZV *zv1, ZV *zv2 ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in profile.c --------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ to fill xDV and yDV with a log10 profile of the magnitudes of the entries in the ZV object. tausmall and tau big provide cutoffs within which to examine the entries. pnzero, pnsmall and pnbig are addresses to hold the number of entries zero, smaller than tausmall and larger than taubig, respectively. created -- 97feb14, cca ------------------------------------------------------------------ */ void ZV_log10profile ( ZV *zv, int npts, DV *xDV, DV *yDV, double tausmall, double taubig, int *pnzero, int *pnsmall, int *pnbig ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods found in IO.c -------------------------------------------- ------------------------------------------------------------------------ */ /* ---------------------------------------------- purpose -- to read in an ZV object from a file input -- fn -- filename, must be *.zvb or *.zvf return value -- 1 if success, 0 if failure created -- 98jan22, cca ---------------------------------------------- */ int ZV_readFromFile ( ZV *zv, char *fn ) ; /* ----------------------------------------------------- purpose -- to read an ZV object from a formatted file return value -- 1 if success, 0 if failure created -- 98jan22, cca ----------------------------------------------------- */ int ZV_readFromFormattedFile ( ZV *zv, FILE *fp ) ; /* --------------------------------------------------- purpose -- to read an ZV object from a binary file return value -- 1 if success, 0 if failure created -- 98jan22, cca --------------------------------------------------- */ int ZV_readFromBinaryFile ( ZV *zv, FILE *fp ) ; /* ------------------------------------------- purpose -- to write an ZV object to a file input -- fn -- filename *.zvb -- binary *.zvf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 98jan22, cca ------------------------------------------- */ int ZV_writeToFile ( ZV *zv, char *fn ) ; /* ----------------------------------------------------- purpose -- to write an ZV object to a formatted file return value -- 1 if success, 0 otherwise created -- 98jan22, cca ----------------------------------------------------- */ int ZV_writeToFormattedFile ( ZV *zv, FILE *fp ) ; /* -------------------------------------------------- purpose -- to write an ZV object to a binary file return value -- 1 if success, 0 otherwise created -- 98jan22, cca -------------------------------------------------- */ int ZV_writeToBinaryFile ( ZV *zv, FILE *fp ) ; /* ------------------------------------------------- purpose -- to write an ZV object for a human eye return value -- 1 if success, 0 otherwise created -- 98jan22, cca ------------------------------------------------- */ int ZV_writeForHumanEye ( ZV *zv, FILE *fp ) ; /* --------------------------------------------------------- purpose -- to write out the statistics for the ZV object return value -- 1 if success, 0 otherwise created -- 98jan22, cca --------------------------------------------------------- */ int ZV_writeStats ( ZV *zv, FILE *fp ) ; /* -------------------------------------------------- purpose -- write the vector entries out for matlab created -- 98apr15, cca -------------------------------------------------- */ void ZV_writeForMatlab ( ZV *zv, char *vecname, FILE *fp ) ; /*--------------------------------------------------------------------*/ ZV_clearData ( ZV *zv ) ; /* ----------------------- destructor creZV/makefile010064400020550007177000000002230663622370300141340ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean ZV/src/makefile010064400020550007177000000007630663603076000147330ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = ZV $(OBJ).a : \ $(OBJ).a(basics.o) \ $(OBJ).a(init.o) \ $(OBJ).a(instance.o) \ $(OBJ).a(IO.o) \ $(OBJ).a(profile.o) \ $(OBJ).a(util.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG ZV/src/makeGlobalLib010064400020550007177000000006350660026116200156320ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = ZV SRC = basics.c \ init.c \ instance.c \ IO.c \ profile.c \ util.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a ZV/src/IO.c010064400020550007177000000275320660552267300137160ustar00clevecompmath00000400000006/* IO.c */ #include "../ZV.h" static const char *suffixb = ".zvb" ; static const char *suffixf = ".zvf" ; /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to read in an ZV object from a file input -- fn -- filename, must be *.zvb or *.zvf return value -- 1 if success, 0 if failure created -- 98jan22, cca ---------------------------------------------- */ int ZV_readFromFile ( ZV *zv, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( zv == NULL || fn == NULL ) { fprintf(stderr, "\n error in ZV_readFromFile(%p,%s)" "\n bad input\n", zv, fn) ; return(0) ; } /* ------------- read the file ------------- */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "rb")) == NULL ) { fprintf(stderr, "\n error in ZV_readFromFile(%p,%s)" "\n unable to open file %s", zv, fn, fn) ; rc = 0 ; } else { rc = ZV_readFromBinaryFile(zv, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "r")) == NULL ) { fprintf(stderr, "\n error in ZV_readFromFile(%p,%s)" "\n unable to open file %s", zv, fn, fn) ; rc = 0 ; } else { rc = ZV_readFromFormattedFile(zv, fp) ; fclose(fp) ; } } else { fprintf(stderr, "\n error in ZV_readFromFile(%p,%s)" "\n bad ZV file name %s," "\n must end in %s (binary) or %s (formatted)\n", zv, fn, fn, suffixb, suffixf) ; rc = 0 ; } } else { fprintf(stderr, "\n error in ZV_readFromFile(%p,%s)" "\n bad ZV file name %s," "\n must end in %s (binary) or %s (formatted)\n", zv, fn, fn, suffixb, suffixf) ; rc = 0 ; } return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to read an ZV object from a formatted file return value -- 1 if success, 0 if failure created -- 98jan22, cca ----------------------------------------------------- */ int ZV_readFromFormattedFile ( ZV *zv, FILE *fp ) { int rc, size ; /* --------------- check the input --------------- */ if ( zv == NULL || fp == NULL ) { fprintf(stderr, "\n error in ZV_readFromFormattedFile(%p,%p)" "\n bad input\n", zv, fp) ; return(0) ; } ZV_clearData(zv) ; /* ------------------------------ read in the size of the vector ------------------------------ */ if ( (rc = fscanf(fp, "%d", &size)) != 1 ) { fprintf(stderr, "\n error in ZV_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", zv, fp, rc, 1) ; return(0) ; } /* --------------------- initialize the object --------------------- */ ZV_init(zv, size, NULL) ; /* ------------------------ read in the vec[] vector ------------------------ */ if ( (rc = DVfscanf(fp, 2*size, ZV_entries(zv))) != 2*size ) { fprintf(stderr, "\n error in ZV_readFromFormattedFile(%p,%p)" "\n %d items of %d read\n", zv, fp, rc, 2*size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------- purpose -- to read an ZV object from a binary file return value -- 1 if success, 0 if failure created -- 98jan22, cca --------------------------------------------------- */ int ZV_readFromBinaryFile ( ZV *zv, FILE *fp ) { int rc, size ; /* --------------- check the input --------------- */ if ( zv == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in ZV_readFromBinaryFile(%p,%p)" "\n bad input\n", zv, fp) ; return(0) ; } ZV_clearData(zv) ; /* ------------------------------ read in the size of the vector ------------------------------ */ if ( (rc = fread((void *) &size, sizeof(int), 1, fp)) != 1 ) { fprintf(stderr, "\n error in ZV_readFromBinaryFile(%p,%p)" "\n itemp(3) : %d items of %d read\n", zv, fp, rc, 1) ; return(0) ; } /* --------------------- initialize the object --------------------- */ ZV_init(zv, size, NULL) ; /* ------------------------ read in the vec[] vector ------------------------ */ if ( (rc = fread((void *) ZV_entries(zv), sizeof(double), 2*size, fp)) != 2*size ) { fprintf(stderr, "\n error in ZV_readFromBinaryFile(%p,%p)" "\n %d items of %d read\n", zv, fp, rc, 2*size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------- purpose -- to write an ZV object to a file input -- fn -- filename *.zvb -- binary *.zvf -- formatted anything else -- for human eye return value -- 1 if success, 0 otherwise created -- 98jan22, cca ------------------------------------------- */ int ZV_writeToFile ( ZV *zv, char *fn ) { FILE *fp ; int fnlength, rc, sulength ; /* --------------- check the input --------------- */ if ( zv == NULL || fn == NULL ) { fprintf(stderr, "\n fatal error in ZV_writeToFile(%p,%s)" "\n bad input\n", zv, fn) ; } /* ------------------ write out the file ------------------ */ fnlength = strlen(fn) ; sulength = strlen(suffixb) ; if ( fnlength > sulength ) { if ( strcmp(&fn[fnlength-sulength], suffixb) == 0 ) { if ( (fp = fopen(fn, "wb")) == NULL ) { fprintf(stderr, "\n error in ZV_writeToFile(%p,%s)" "\n unable to open file %s", zv, fn, fn) ; rc = 0 ; } else { rc = ZV_writeToBinaryFile(zv, fp) ; fclose(fp) ; } } else if ( strcmp(&fn[fnlength-sulength], suffixf) == 0 ) { if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "\n error in ZV_writeToFile(%p,%s)" "\n unable to open file %s", zv, fn, fn) ; rc = 0 ; } else { rc = ZV_writeToFormattedFile(zv, fp) ; fclose(fp) ; } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in ZV_writeToFile(%p,%s)" "\n unable to open file %s", zv, fn, fn) ; rc = 0 ; } else { rc = ZV_writeForHumanEye(zv, fp) ; fclose(fp) ; } } } else { if ( (fp = fopen(fn, "a")) == NULL ) { fprintf(stderr, "\n error in ZV_writeToFile(%p,%s)" "\n unable to open file %s", zv, fn, fn) ; rc = 0 ; } else { rc = ZV_writeForHumanEye(zv, fp) ; fclose(fp) ; } } return(rc) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to write an ZV object to a formatted file return value -- 1 if success, 0 otherwise created -- 98jan22, cca ----------------------------------------------------- */ int ZV_writeToFormattedFile ( ZV *zv, FILE *fp ) { int rc, size ; /* --------------- check the input --------------- */ if ( zv == NULL || fp == NULL || zv->size <= 0 ) { fprintf(stderr, "\n fatal error in ZV_writeToFormattedFile(%p,%p)" "\n bad input\n", zv, fp) ; fprintf(stderr, "\n zv->size = %d", zv->size) ; exit(-1) ; } /* ------------------------------------- write out the size of the vector ------------------------------------- */ size = ZV_size(zv) ; rc = fprintf(fp, "\n %d", size) ; if ( rc < 0 ) { fprintf(stderr, "\n fatal error in ZV_writeToFormattedFile(%p,%p)" "\n rc = %d, return from first fprintf\n", zv, fp, rc) ; return(0) ; } if ( size > 0 ) { DVfprintf(fp, 2*size, ZV_entries(zv)) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- to write an ZV object to a binary file return value -- 1 if success, 0 otherwise created -- 98jan22, cca -------------------------------------------------- */ int ZV_writeToBinaryFile ( ZV *zv, FILE *fp ) { int rc, size ; /* --------------- check the input --------------- */ if ( zv == NULL || fp == NULL || zv->size <= 0 ) { fprintf(stderr, "\n fatal error in ZV_writeToBinaryFile(%p,%p)" "\n bad input\n", zv, fp) ; exit(-1) ; } size = ZV_size(zv) ; rc = fwrite((void *) &size, sizeof(int), 1, fp) ; if ( rc != 1 ) { fprintf(stderr, "\n error in ZV_writeToBinaryFile(%p,%p)" "\n %d of %d scalar items written\n", zv, fp, rc, 1) ; return(0) ; } rc = fwrite((void *) ZV_entries(zv), sizeof(double), 2*size, fp) ; if ( rc != 2*size ) { fprintf(stderr, "\n error in ZV_writeToBinaryFile(%p,%p)" "\n %d of %d items written\n", zv, fp, rc, 2*size) ; return(0) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- purpose -- to write an ZV object for a human eye return value -- 1 if success, 0 otherwise created -- 98jan22, cca ------------------------------------------------- */ int ZV_writeForHumanEye ( ZV *zv, FILE *fp ) { double *vec ; int ii, jj, rc, size ; if ( zv == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in ZV_writeForHumanEye(%p,%p)" "\n bad input\n", zv, fp) ; exit(-1) ; } if ( (rc = ZV_writeStats(zv, fp)) == 0 ) { fprintf(stderr, "\n fatal error in ZV_writeForHumanEye(%p,%p)" "\n rc = %d, return from ZV_writeStats(%p,%p)\n", zv, fp, rc, zv, fp) ; return(0) ; } size = ZV_size(zv) ; vec = ZV_entries(zv) ; for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { if ( ii % 2 == 0 ) { fprintf(fp, "\n") ; } fprintf(fp, " < %12.4e, %12.4e >", vec[jj], vec[jj+1]) ; } return(1) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- purpose -- to write out the statistics for the ZV object return value -- 1 if success, 0 otherwise created -- 98jan22, cca --------------------------------------------------------- */ int ZV_writeStats ( ZV *zv, FILE *fp ) { int rc ; /* --------------- check the input --------------- */ if ( zv == NULL || fp == NULL ) { fprintf(stderr, "\n error in ZV_writeStats(%p,%p)" "\n bad input\n", zv, fp) ; exit(-1) ; } rc = fprintf(fp, "\n ZV : double complex vector object : ") ; if ( rc < 0 ) { goto IO_error ; } rc = fprintf(fp, " size = %d, maxsize = %d, owned = %d", zv->size, zv->maxsize, zv->owned) ; if ( rc < 0 ) { goto IO_error ; } return(1) ; IO_error : fprintf(stderr, "\n fatal error in ZV_writeStats(%p,%p)" "\n rc = %d, return from fprintf\n", zv, fp, rc) ; return(0) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------- purpose -- write the vector entries out for matlab created -- 98apr15, cca -------------------------------------------------- */ void ZV_writeForMatlab ( ZV *zv, char *vecname, FILE *fp ) { int ii, jj, size ; double *z ; /* --------------- check the input --------------- */ if ( zv == NULL || vecname == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in ZV_writeForMatlab(%p,%p,%p)" "\n bad input\n", zv, vecname, fp) ; exit(-1) ; } ZV_sizeAndEntries(zv, &size, &z) ; for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { fprintf(fp, "\n %s(%d) = %24.16e + %24.16e*i;", vecname, ii + 1, z[jj], z[jj+1]) ; } return ; } /*--------------------------------------------------------------------*/ ZV/src/basics.c010064400020550007177000000032410653410576000146350ustar00clevecompmath00000400000006/* basics.C */ #include "../ZV.h" /*--------------------------------------------------------------------*/ /* ----------------------- constructor method created -- 98jan22, cca ----------------------- */ ZV * ZV_new ( void ) { ZV *zv ; ALLOCATE(zv, struct _ZV, 1) ; ZV_setDefaultFields(zv) ; return(zv) ; } /*--------------------------------------------------------------------*/ /* ----------------------- set the default fields created -- 98jan22, cca ----------------------- */ void ZV_setDefaultFields ( ZV *zv ) { if ( zv == NULL ) { fprintf(stderr, "\n fatal error in ZV_setDefaultFields(%p)" "\n bad input\n", zv) ; exit(-1) ; } zv->size = 0 ; zv->maxsize = 0 ; zv->owned = 0 ; zv->vec = NULL ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- clear the data fields created -- 98jan22, cca ----------------------- */ void ZV_clearData ( ZV *zv ) { if ( zv == NULL ) { fprintf(stderr, "\n fatal error in ZV_clearData(%p)" "\n bad input\n", zv) ; exit(-1) ; } if ( zv->vec != NULL && zv->owned == 1 ) { DVfree(zv->vec) ; } ZV_setDefaultFields(zv) ; return ; } /*--------------------------------------------------------------------*/ /* ----------------------- destructor created -- 98jan22, cca ----------------------- */ void ZV_free ( ZV *zv ) { if ( zv == NULL ) { fprintf(stderr, "\n fatal error in ZV_free(%p)" "\n bad input\n", zv) ; exit(-1) ; } ZV_clearData(zv) ; FREE(zv) ; return ; } /*--------------------------------------------------------------------*/ ZV/src/init.c010064400020550007177000000141100653410576000143310ustar00clevecompmath00000400000006/* init.C */ #include "../ZV.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------- simplest initialization method data is cleared if entries != NULL the object does not own the entries, it just points to the entries base address else if size > 0 the object will own the entries, it allocates a vector of 2*size doubles's. else nothing happens endif created -- 98jan22, cca --------------------------------------------- */ void ZV_init ( ZV *zv, int size, double *entries ) { if ( zv == NULL || size < 0 ) { fprintf(stderr, "\n fatal error in ZV_init(%p,%d,%p)" "\n bad input\n", zv, size, entries) ; exit(-1) ; } /* -------------- clear any data -------------- */ ZV_clearData(zv) ; /* ----------------------------- set the size and maximum size ----------------------------- */ zv->maxsize = zv->size = size ; /* ------------------------- set vector and owner flag ------------------------- */ if ( entries != NULL ) { zv->owned = 0 ; zv->vec = entries ; } else if ( size > 0 ) { zv->owned = 1 ; zv->vec = DVinit(2*size, 0.0) ; } return ; } /*--------------------------------------------------------------------*/ /* ------------------------- basic initializion method created -- 98jan22, cca ------------------------- */ void ZV_init1 ( ZV *zv, int size ) { ZV_init(zv, size, NULL) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------- total initializion method created -- 98jan22, cca ------------------------- */ void ZV_init2 ( ZV *zv, int size, int maxsize, int owned, double *vec ) { /* --------------- check the input --------------- */ if ( zv == NULL ) { fprintf(stderr, "\n fatal error in ZV_init2(%p,%d,%d,%d,%p)" "\n bad input\n", zv, size, maxsize, owned, vec) ; exit(-1) ; } if ( size < 0 || maxsize < size ) { fprintf(stderr, "\n fatal error in ZV_init2(%p,%d,%d,%d,%p)" "\n size = %d, maxsize = %d \n", zv, size, maxsize, owned, vec, size, maxsize) ; exit(-1) ; } if ( owned < 0 || 1 < owned ) { fprintf(stderr, "\n fatal error in ZV_init2(%p,%d,%d,%d,%p)" "\n owned = %d\n", zv, size, maxsize, owned, vec, owned) ; exit(-1) ; } if ( owned == 1 && vec == NULL ) { fprintf(stderr, "\n fatal error in ZV_init2(%p,%d,%d,%d,%p)" "\n owned = %d and vec = %p", zv, size, maxsize, owned, vec, owned, vec) ; exit(-1) ; } /* -------------- clear any data -------------- */ ZV_clearData(zv) ; if ( vec == NULL ) { /* ---------------------------------------------- no entries input, use the simplest initializer ---------------------------------------------- */ ZV_init(zv, size, NULL) ; } else { /* --------------------------------- entries are input, set the fields --------------------------------- */ zv->size = size ; zv->maxsize = maxsize ; zv->owned = owned ; zv->vec = vec ; } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------- set the maximum size of the vector created -- 98jan22, cca ---------------------------------- */ void ZV_setMaxsize ( ZV *zv, int newmaxsize ) { /* --------------- check the input --------------- */ if ( zv == NULL || newmaxsize < 0 ) { fprintf(stderr, "\n fatal error in ZV_setMaxsize(%p,%d)" "\n bad input\n", zv, newmaxsize) ; exit(-1) ; } if ( zv->maxsize > 0 && zv->owned == 0 ) { fprintf(stderr, "\n fatal error in ZV_setMaxsize(%p,%d)" "\n zv->maxsize = %d, zv->owned = %d\n", zv, newmaxsize, zv->maxsize, zv->owned) ; exit(-1) ; } if ( zv->maxsize != newmaxsize ) { /* ----------------------------------- allocate new storage for the vector ----------------------------------- */ double *vec = DVinit(2*newmaxsize, 0.0) ; if ( zv->size > 0 ) { /* --------------------------------- copy old entries into new entries --------------------------------- */ if ( zv->vec == NULL ) { fprintf(stderr, "\n fatal error in ZV_setMaxsize(%p,%d)" "\n zv->size = %d, zv->vec is NULL\n", zv, newmaxsize, zv->size) ; exit(-1) ; } if ( zv->size <= newmaxsize ) { DVcopy(2*zv->size, vec, zv->vec) ; } else { /* ----------------------- note, data is truncated ----------------------- */ DVcopy(2*newmaxsize, vec, zv->vec) ; zv->size = newmaxsize ; } } if ( zv->vec != NULL ) { /* ---------------- free old entries ---------------- */ DVfree(zv->vec) ; } /* ---------- set fields ---------- */ zv->maxsize = newmaxsize ; zv->owned = 1 ; zv->vec = vec ; } return ; } /*--------------------------------------------------------------------*/ /* -------------------------- set the size of the vector created -- 98jan22, cca -------------------------- */ void ZV_setSize ( ZV *zv, int newsize ) { /* --------------- check the input --------------- */ if ( zv == NULL || newsize < 0 ) { fprintf(stderr, "\n fatal error in ZV_setSize(%p,%d)" "\n bad input\n", zv, newsize) ; exit(-1) ; } if ( 0 < zv->maxsize && zv->maxsize < newsize && zv->owned == 0 ) { fprintf(stderr, "\n fatal error in ZV_setSize(%p,%d)" "\n zv->maxsize = %d, newsize = %d, zv->owned = %d\n", zv, newsize, zv->maxsize, newsize, zv->owned) ; exit(-1) ; } if ( zv->maxsize < newsize ) { /* ------------------------------------------------------------- new size requested is more than maxsize, set new maximum size ------------------------------------------------------------- */ ZV_setMaxsize(zv, newsize) ; } zv->size = newsize ; return ; } /*--------------------------------------------------------------------*/ ZV/src/instance.c010064400020550007177000000115520653410576000152010ustar00clevecompmath00000400000006/* instance.c */ #include "../ZV.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------- return 1 if the entries are owned by the object return 0 otherwise created -- 98jan22, cca ----------------------------------------------- */ int ZV_owned ( ZV *dv ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in ZV_owned(%p)" "\n bad input\n", dv) ; exit(-1) ; } return(dv->owned) ; } /*--------------------------------------------------------------------*/ /* ----------------------- return the vector size created -- 98jan22, cca ----------------------- */ int ZV_maxsize ( ZV *dv ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in ZV_maxsize(%p)" "\n bad input\n", dv) ; exit(-1) ; } return(dv->maxsize) ; } /*--------------------------------------------------------------------*/ /* ----------------------- return the vector size created -- 98jan22, cca ----------------------- */ int ZV_size ( ZV *dv ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in ZV_size(%p)" "\n bad input\n", dv) ; exit(-1) ; } return(dv->size) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- return the loc'th entry of a vector. created -- 98jan22, cca ------------------------------------------------- */ void ZV_entry ( ZV *dv, int loc, double *pReal, double *pImag ) { if ( dv == NULL || pReal == NULL || pImag == NULL ) { fprintf(stderr, "\n fatal error in ZV_entry(%p,%d,%p,%p)" "\n bad input\n", dv, loc, pReal, pImag) ; exit(-1) ; } if ( loc < 0 || loc >= dv->size || dv->vec == NULL ) { fprintf(stderr, "\n fatal error in ZV_entry(%p,%d,%p,%p)" "\n bad state: size = %d, vec = %p\n", dv, loc, pReal, pImag, dv->size, dv->vec) ; exit(-1) ; } *pReal = dv->vec[2*loc] ; *pImag = dv->vec[2*loc+1] ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- return pointers to the loc'th entry of a vector. created -- 98jan22, cca ------------------------------------------------- */ void ZV_pointersToEntry ( ZV *dv, int loc, double **ppReal, double **ppImag ) { if ( dv == NULL || ppReal == NULL || ppImag == NULL ) { fprintf(stderr, "\n fatal error in ZV_pointersToEntry(%p,%d,%p,%p)" "\n bad input\n", dv, loc, ppReal, ppImag) ; exit(-1) ; } if ( loc < 0 || loc >= dv->size || dv->vec == NULL ) { fprintf(stderr, "\n fatal error in ZV_pointersToEntry(%p,%d,%p,%p)" "\n bad state: size = %d, vec = %p\n", dv, loc, ppReal, ppImag, dv->size, dv->vec) ; exit(-1) ; } *ppReal = &dv->vec[2*loc] ; *ppImag = &dv->vec[2*loc+1] ; return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return a pointer to the object's entries array created -- 98jan22, cca ---------------------------------------------- */ double * ZV_entries ( ZV *dv ) { if ( dv == NULL ) { fprintf(stderr, "\n fatal error in ZV_entries(%p)" "\n bad input\n", dv) ; exit(-1) ; } return(dv->vec) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------- fill *psize with the vector's size and *pentries with the address of the vector created -- 98jan22, cca -------------------------------------------- */ void ZV_sizeAndEntries ( ZV *dv, int *psize, double **pentries ) { if ( dv == NULL || psize == NULL || pentries == NULL ) { fprintf(stderr, "\n fatal error in ZV_sizeAndEntries(%p,%p,%p)" "\n bad input\n", dv, psize, pentries) ; exit(-1) ; } *psize = dv->size ; *pentries = dv->vec ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------- set and entry in the vector created -- 98jan22, cca --------------------------- */ void ZV_setEntry ( ZV *dv, int loc, double real, double imag ) { /* --------------- check the input --------------- */ if ( dv == NULL || loc < 0 ) { fprintf(stderr, "\n fatal error in ZV_setEntry(%p,%d,%f,%f)" "\n bad input\n", dv, loc, real, imag) ; exit(-1) ; } if ( loc >= dv->maxsize ) { int newmaxsize = (int) 1.25*dv->maxsize ; if ( newmaxsize < 10 ) { newmaxsize = 10 ; } if ( loc >= newmaxsize ) { newmaxsize = loc + 1 ; } ZV_setMaxsize(dv, newmaxsize) ; } if ( loc >= dv->size ) { dv->size = loc + 1 ; } dv->vec[2*loc] = real ; dv->vec[2*loc+1] = imag ; return ; } /*--------------------------------------------------------------------*/ tate: size = %d, vec = %p\n", dv, loc, pReal, pImag, dv->size, dv->vec) ; exit(-1) ; } *pReal = dv->vec[2*loc] ; *pImag = dv->vec[2*loc+ZV/src/profile.c010064400020550007177000000077700653410576000150440ustar00clevecompmath00000400000006/* profile */ #include "../ZV.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ to fill xDV and yDV with a log10 profile of the magnitudes of the entries in the ZV object. tausmall and tau big provide cutoffs within which to examine the entries. pnzero, pnsmall and pnbig are addresses to hold the number of entries zero, smaller than tausmall and larger than taubig, respectively. created -- 97feb14, cca ------------------------------------------------------------------ */ void ZV_log10profile ( ZV *zv, int npts, DV *xDV, DV *yDV, double tausmall, double taubig, int *pnzero, int *pnsmall, int *pnbig ) { double deltaVal, imag, maxval, minval, real, val ; double *zvec, *sums, *x, *y ; int ii, ipt, jj, nbig, nsmall, nzero, size ; /* --------------- check the input --------------- */ if ( zv == NULL || npts <= 0 || xDV == NULL || yDV == NULL || tausmall < 0.0 || taubig < 0.0 || tausmall > taubig || pnzero == NULL || pnsmall == NULL || pnbig == NULL ) { fprintf(stderr, "\n fatal error in ZV_log10profile(%p,%d,%p,%p,%f,%f,%p,%p,%p)" "\n bad input\n", zv, npts, xDV, yDV, tausmall, taubig, pnzero, pnsmall, pnbig) ; exit(-1) ; } /* ------------------------------------- find the largest and smallest entries in the range [tausmall, taubig] ------------------------------------- */ nbig = nsmall = nzero = 0 ; minval = maxval = 0.0 ; ZV_sizeAndEntries(zv, &size, &zvec) ; for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { real = fabs(zvec[jj]) ; imag = fabs(zvec[jj+1]) ; if ( real == 0.0 ) { val = imag ; } else if ( imag == 0.0 ) { val = real ; } else if ( real >= imag ) { val = imag/real ; val = real*sqrt(1 + val*val) ; } else { val = real/imag ; val = imag*sqrt(1 + val*val) ; } if ( val == 0.0 ) { nzero++ ; } else if ( val <= tausmall ) { nsmall++ ; } else if ( val >= taubig ) { nbig++ ; } else { if ( minval == 0.0 || minval > val ) { minval = val ; } if ( maxval < val ) { maxval = val ; } } } *pnzero = nzero ; *pnsmall = nsmall ; *pnbig = nbig ; #if MYDEBUG > 0 fprintf(stdout, "\n nzero = %d, minval = %e, nsmall = %d, maxval = %e, nbig = %d", nzero, minval, nsmall, maxval, nbig) ; #endif /* ------------------ set up the buckets ------------------ */ DV_setSize(xDV, npts) ; DV_setSize(yDV, npts) ; x = DV_entries(xDV) ; y = DV_entries(yDV) ; sums = DVinit(npts, 0.0) ; minval = log10(minval) ; maxval = log10(maxval) ; /* minval = log10(tausmall) ; maxval = log10(taubig) ; */ deltaVal = (maxval - minval)/(npts - 1) ; DVfill(npts, x, 0.0) ; DVfill(npts, y, 0.0) ; /* -------------------------------- fill the sums and counts vectors -------------------------------- */ for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { real = fabs(zvec[jj]) ; imag = fabs(zvec[jj+1]) ; if ( real == 0.0 ) { val = imag ; } else if ( imag == 0.0 ) { val = real ; } else if ( real >= imag ) { val = imag/real ; val = real*sqrt(1 + val*val) ; } else { val = real/imag ; val = imag*sqrt(1 + val*val) ; } if ( tausmall < val && val < taubig ) { ipt = (log10(val) - minval) / deltaVal ; sums[ipt] += val ; y[ipt]++ ; } } #if MYDEBUG > 0 fprintf(stdout, "\n sum(y) = %.0f", DV_sum(yDV)) ; #endif /* --------------------------- set the x-coordinate vector --------------------------- */ for ( ipt = 0 ; ipt < npts ; ipt++ ) { if ( sums[ipt] == 0.0 ) { x[ipt] = minval + ipt*deltaVal ; } else { x[ipt] = log10(sums[ipt]/y[ipt]) ; } } /* ------------------------ free the working storage ------------------------ */ DVfree(sums) ; return ; } /*--------------------------------------------------------------------*/ ZV/src/util.c010064400020550007177000000123260665017076700143620ustar00clevecompmath00000400000006/* basics.C */ #include "../ZV.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------------- shift the base of the entries and adjust the dimensions note: this is a dangerous operation because the zv->vec does not point to the base of the entries any longer, and thus if the object owns its entries and it is called to resize them or to free them, malloc and free will choke. USE WITH CAUTION! created -- 98jan22, cca ----------------------------------------------------------- */ void ZV_shiftBase ( ZV *zv, int offset ) { if ( zv == NULL ) { fprintf(stderr, "\n fatal error in ZV_shiftBase(%p,%d)" "\n bad input\n", zv, offset) ; exit(-1) ; } zv->vec += 2*offset ; zv->maxsize -= offset ; zv->size -= offset ; return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- push an entry onto the list created -- 95oct06, cca -------------------------------------- */ void ZV_push ( ZV *zv, double real, double imag ) { if ( zv == NULL ) { fprintf(stderr, "\n fatal error in ZV_push(%p,%f,%f)" "\n bad input\n", zv, real, imag) ; exit(-1) ; } if ( zv->size == zv->maxsize ) { if ( zv->maxsize > 0 ) { ZV_setMaxsize(zv, 2*zv->maxsize) ; } else { ZV_setMaxsize(zv, 10) ; } } zv->vec[2*zv->size] = real ; zv->vec[2*zv->size+1] = real ; zv->size++ ; return ; } /*--------------------------------------------------------------------*/ /* --------------------------- minimum and maximum entries created -- 95oct06, cca --------------------------- */ double ZV_minabs ( ZV *zv ) { if ( zv == NULL || zv->size <= 0 || zv->vec == NULL ) { fprintf(stderr, "\n fatal error in ZV_minabs(%p), size = %d, vec = %p", zv, zv->size, zv->vec) ; exit(-1) ; } return(ZVminabs(zv->size, zv->vec)) ; } double ZV_maxabs ( ZV *zv ) { if ( zv == NULL || zv->size <= 0 || zv->vec == NULL ) { fprintf(stderr, "\n fatal error in ZV_maxabs(%p), size = %d, vec = %p", zv, zv->size, zv->vec) ; exit(-1) ; } return(ZVmaxabs(zv->size, zv->vec)) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95oct06, cca ---------------------------------------------- */ int ZV_sizeOf ( ZV *zv ) { int nbytes ; if ( zv == NULL ) { fprintf(stderr, "\n fatal error in ZV_sizeOf(%p)" "\n bad input \n", zv) ; exit(-1) ; } nbytes = sizeof(struct _ZV) ; if ( zv->owned == 1 ) { nbytes += 2*zv->maxsize*sizeof(double) ; } return(nbytes) ; } /*--------------------------------------------------------------------*/ /* -------------------------- fill a vector with a value created -- 96jun22, cca -------------------------- */ void ZV_fill ( ZV *zv, double real, double imag ) { double *vec ; int ii, jj, size ; /* --------------- check the input --------------- */ if ( zv == NULL ) { fprintf(stderr, "\n fatal error in ZV_fill(%p,%f,%f)" "\n bad input\n", zv, real, imag) ; exit(-1) ; } if ( (size = zv->size) > 0 ) { if ( (vec = zv->vec) == NULL ) { fprintf(stderr, "\n fatal error in ZV_fill(%p,%f,%f)" "\n vec = NULL\n", zv, real, imag) ; exit(-1) ; } for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { vec[jj] = real ; vec[jj+1] = imag ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------ fill a vector with zeros created -- 98jun02, cca ------------------------ */ void ZV_zero ( ZV *zv ) { double *vec ; int ii, jj, size ; /* --------------- check the input --------------- */ if ( zv == NULL ) { fprintf(stderr, "\n fatal error in ZV_zero(%p)" "\n bad input\n", zv) ; exit(-1) ; } if ( (size = zv->size) > 0 ) { if ( (vec = zv->vec) == NULL ) { fprintf(stderr, "\n fatal error in ZV_zero(%p)" "\n vec = NULL\n", zv) ; exit(-1) ; } for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { vec[jj] = 0.0 ; vec[jj+1] = 0.0 ; } } return ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- copy entries from zv2 into zv1. note: this is a "mapped" copy, zv1 and zv2 need not be the same size. created -- 96aug31, cca -------------------------------------- */ void ZV_copy ( ZV *zv1, ZV *zv2 ) { int ii, jj, size ; double *vec1, *vec2 ; /* --------------- check the input --------------- */ if ( zv1 == NULL || zv2 == NULL ) { fprintf(stderr, "\n fatal error in ZV_copy(%p,%p)" "\n bad input\n", zv1, zv2) ; exit(-1) ; } size = zv1->size ; if ( size > zv2->size ) { size = zv2->size ; } vec1 = zv1->vec ; vec2 = zv2->vec ; for ( ii = jj = 0 ; ii < size ; ii++, jj += 2 ) { vec1[jj] = vec2[jj] ; vec1[jj+1] = vec2[jj+1] ; } return ; } /*--------------------------------------------------------------------*/ axabs(zv->size, zv->vec)) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- return the number of bytes taken by the object created -- 95oct06, cca ---------------------------------------------- */ int ZV_sizZV/drivers/makefile010064400020550007177000000004510665314267200156210ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm DRIVERS = testIO drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} testIO : testIO.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} ZV/drivers/testIO.c010064400020550007177000000054370653506365400155060ustar00clevecompmath00000400000006/* testIO.c */ #include "../ZV.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------------- test ZV_readFromFile and ZV_writeToFile, useful for translating between formatted *.zvf and binary *.zvb files. created -- 98jun02, cca ---------------------------------------------- */ { char *inZVFileName, *outZVFileName ; double t1, t2 ; int msglvl, rc ; ZV *zvobj ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inFile outFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n inFile -- input file, must be *.zvf or *.zvb" "\n outFile -- output file, must be *.zvf or *.zvb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inZVFileName = argv[3] ; outZVFileName = argv[4] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inFile -- %s" "\n outFile -- %s" "\n", argv[0], msglvl, argv[2], inZVFileName, outZVFileName) ; fflush(msgFile) ; /* --------------------- read in the ZV object --------------------- */ if ( strcmp(inZVFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } zvobj = ZV_new() ; MARKTIME(t1) ; rc = ZV_readFromFile(zvobj, inZVFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in iv from file %s", t2 - t1, inZVFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ZV_readFromFile(%p,%s)", rc, zvobj, inZVFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading ZV object from file %s", inZVFileName) ; if ( msglvl > 2 ) { ZV_writeForHumanEye(zvobj, msgFile) ; } else { ZV_writeStats(zvobj, msgFile) ; } fflush(msgFile) ; /* ----------------------- write out the ZV object ----------------------- */ if ( strcmp(outZVFileName, "none") != 0 ) { MARKTIME(t1) ; rc = ZV_writeToFile(zvobj, outZVFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : write iv to file %s", t2 - t1, outZVFileName) ; } if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ZV_writeToFile(%p,%s)", rc, zvobj, outZVFileName) ; } /* ------------------ free the ZV object ------------------ */ ZV_free(zvobj) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ ZV/doc/004275500020550007177000000000000654276751500132235ustar00clevecompmath00000400000006ZV/doc/dataStructure.tex010064400020550007177000000016010653510676100165600ustar00clevecompmath00000400000006\par \section{Data Structure} \label{section:ZV:dataStructure} \par \par The {\tt ZV} structure has three fields. \begin{itemize} \item {\tt int size} : present size of the vector. \item {\tt int maxsize} : maximum size of the vector. \item {\tt int owned} : owner flag for the data. When {\tt owned = 1}, storage for {\tt owned} {\tt double}'s has been allocated by this object and can be free'd by the object. When {\tt owned == 0} but {\tt size > 0 }, this object points to entries that have been allocated elsewhere, and these entries will not be free'd by this object. \item {\tt double *vec} : pointer to the base address of the {\it double} vector \end{itemize} The {\tt size}, {\tt maxsize}, {\tt nowned} and {\tt vec} fields need never be accessed directly --- see the {\tt ZV\_size()}, {\tt ZV\_maxsize()}, {\tt ZV\_owned()}, {\tt ZV\_entries()}, {\tt ZV\_sizeAndEntries()} methods. ZV/doc/intro.tex010064400020550007177000000037570653510677400151030ustar00clevecompmath00000400000006\chapter{{\tt ZV}: Double Complex Vector Object} \par The {\tt ZV} object is a wrapper around a {\tt double} precision complex vector. In Fortran's LINPACK and LAPACK libraries, a leading {\tt Z} denotes double precision complex, and we have followed this convention. The driving force for its creation of this object is more convenience than performance. There are three cases that led to its development. \begin{itemize} \item Often a method will create a vector (allocate storage for and fill the entries) whose size is not known before the method call. Instead of having a pointer to {\tt int} and a pointer to {\tt double*} in the calling sequence, we can return a pointer to an {\tt ZV} object that contains the newly created vector and its size. \item In many cases we need a persistent {\tt double} vector object, and file IO is simplified if we have an object to deal with. The filename is of the form {\tt *.zvf} for a formatted file or {\tt *.zvb} for a binary file. \item Prototyping can go much faster with this object as opposed to working with an {\tt double} array. Consider the case when one wants to accumulate a list of doubles, but one doesn't know how large the list will be. The method {\tt ZV\_setSize()} can be used to set the size of the vector to zero. Another method {\tt ZV\_push()} appends an element to the vector, growing the storage if necessary. \item Sometimes an object needs to change its size, i.e., vectors need to grow or shrink. It is easier and more robust to tell an {\tt ZV} object to resize itself (see the {\tt ZV\_setSize()} and {\tt ZV\_setMaxsize()} methods) than it is to duplicate code to work on an {\tt double} vector. \end{itemize} One must choose where to use this object. There is a substantial performance penalty for doing the simplest operations, and so when we need to manipulate an {\tt double} vector inside a loop, we extract out the size and pointer to the base array from the {\tt ZV} object. On the other hand, the convenience makes it a widely used object. \par ZV/doc/main.tex010064400020550007177000000010720665065633000146540ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt ZV} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt ZV} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input dataStructure.tex \input proto.tex \input drivers.tex \input main.ind \end{document} ZV/doc/main.ind010064400020550007177000000022030653510777000146240ustar00clevecompmath00000400000006\begin{theindex} \item {\tt ZV\_clearData()}, 2 \item {\tt ZV\_copy()}, 5 \item {\tt ZV\_entries()}, 3 \item {\tt ZV\_entry()}, 3 \item {\tt ZV\_fill()}, 5 \item {\tt ZV\_free()}, 2 \item {\tt ZV\_init()}, 4 \item {\tt ZV\_init1()}, 4 \item {\tt ZV\_init2()}, 4 \item {\tt ZV\_log10profile()}, 6 \item {\tt ZV\_maxabs()}, 5 \item {\tt ZV\_size()}, 3 \item {\tt ZV\_minabs()}, 5 \item {\tt ZV\_new()}, 2 \item {\tt ZV\_owned()}, 3 \item {\tt ZV\_pointersToEntry()}, 3 \item {\tt ZV\_push()}, 5 \item {\tt ZV\_readFromBinaryFile()}, 6 \item {\tt ZV\_readFromFile()}, 6 \item {\tt ZV\_readFromFormattedFile()}, 6 \item {\tt ZV\_setDefaultFields()}, 2 \item {\tt ZV\_setEntry()}, 4 \item {\tt ZV\_setMaxsize()}, 4 \item {\tt ZV\_setSize()}, 4 \item {\tt ZV\_shiftBase()}, 5 \item {\tt ZV\_size()}, 3 \item {\tt ZV\_sizeAndEntries()}, 3 \item {\tt ZV\_sizeOf()}, 5 \item {\tt ZV\_writeForHumanEye()}, 7 \item {\tt ZV\_writeStats()}, 7 \item {\tt ZV\_writeToBinaryFile()}, 7 \item {\tt ZV\_writeToFile()}, 6 \item {\tt ZV\_writeToFormattedFile()}, 6 \item {\tt ZV\_zero()}, 5 \end{theindex} ZV/doc/main.log010064400020550007177000000042130653510777300146410ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 2 JUN 1998 16:51 **main (main.tex LaTeX Version 2.09 <25 March 1992> (/usr/local/lib/texmf/tex/latex209/report.sty Standard Document Style `report' <14 Jan 92>. (/usr/local/lib/texmf/tex/latex209/rep11.sty) \descriptionmargin=\dimen99 \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 (/usr/local/lib/texmf/tex/latex209/titlepag.sty Document Style Option `titlepage' -- Released 16 June 1991. )) (/usr/local/lib/texmf/tex/latex209/leqno.sty Document style option `leqno' - released 29 Sep 1991 ) \@indexfile=\write3 Writing index file main.idx (main.aux) (intro.tex Chapter 1. LaTeX Warning: No \tt typeface in this size, using \rm on input line 1. ) (dataStructure.tex [1 ]) (proto.tex [2] Overfull \hbox (11.7664pt too wide) in paragraph at lines 133--133 [] []\elvtt void ZV_pointersToEntry ( ZV *zv, int loc, double **ppReal, double **ppImag ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\glue 0.0 .\hbox(7.05666+0.0)x0.0 ..\glue 0.0 ..\glue 0.0 ..\glue -21.90005 ..\glue -5.475 ..\hbox(7.05666+0.0)x21.90005, glue set 21.90005fil ...\glue 0.0 plus 1.0fil minus 1.0fil ...\hbox(7.05666+0.0)x0.0, glue set - 8.51668fil [] ..etc. .\penalty 0 .etc. [3] [4] Overfull \hbox (11.7664pt too wide) in paragraph at lines 372--372 [] \elvtt double taubig, int *pnzero, int *pnsmall, int *pnbig ) ;[] \hbox(7.60416+2.43333)x469.75499 .\glue(\leftskip) 27.37506 .\hbox(0.0+0.0)x0.0 .\penalty 10000 .\glue 5.74869 .\penalty 10000 .etc. [5] [6]) (drivers.tex) (main.ind [7] [8 ]) (main.aux) ) Here is how much of TeX's memory you used: 209 strings out of 11977 2165 string characters out of 87269 33563 words of memory out of 262141 2143 multiletter control sequences out of 9500 19780 words of font info for 75 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 13i,5n,17p,179b,260s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (8 pages, 24536 bytes). ZV/doc/main.aux010064400020550007177000000030510653510777300146540ustar00clevecompmath00000400000006\relax \@writefile{toc}{\string\contentsline\space {chapter}{\string\numberline\space {1}{\string\ptt\space ZV}: Double Complex Vector Object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:ZV:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions of {\string\ptt\space ZV} methods}{2}} \newlabel{section:ZV:proto}{{1.2}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.1}Basic methods}{2}} \newlabel{subsection:ZV:proto:basics}{{1.2.1}{2}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.2}Instance methods}{3}} \newlabel{subsection:ZV:proto:Instance}{{1.2.2}{3}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.3}Initializer methods}{4}} \newlabel{subsection:ZV:proto:initializers}{{1.2.3}{4}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.4}Utility methods}{5}} \newlabel{subsection:ZV:proto:utilities}{{1.2.4}{5}} \@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {1.2.5}IO methods}{6}} \newlabel{subsection:ZV:proto:IO}{{1.2.5}{6}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.3}Driver programs for the {\string\ptt\space ZV object}}{7}} \newlabel{section:ZV:drivers}{{1.3}{7}} line\space {chapter}{\string\numberline\space {1}{\string\ptt\space ZV}: Double Complex Vector Object}{1}} \@writefile{lof}{\string\addvspace\space {10\p@ }} \@writefile{lot}{\string\addvspace\space {10\p@ }} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.1}Data Structure}{1}} \newlabel{section:ZV:dataStructure}{{1.1}{1}} \@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1.2}Prototypes and descriptions ZV/doc/main.idx010064400020550007177000000033070653510777300146470ustar00clevecompmath00000400000006\indexentry{ZV_new@{\tt ZV\_new()}}{2} \indexentry{ZV_setDefaultFields@{\tt ZV\_setDefaultFields()}}{2} \indexentry{ZV_clearData@{\tt ZV\_clearData()}}{2} \indexentry{ZV_free@{\tt ZV\_free()}}{2} \indexentry{ZV_owned@{\tt ZV\_owned()}}{3} \indexentry{ZV_size@{\tt ZV\_size()}}{3} \indexentry{ZV_maxsize@{\tt ZV\_size()}}{3} \indexentry{ZV_entry@{\tt ZV\_entry()}}{3} \indexentry{ZV_pointersToEntry@{\tt ZV\_pointersToEntry()}}{3} \indexentry{ZV_entries@{\tt ZV\_entries()}}{3} \indexentry{ZV_sizeAndEntries@{\tt ZV\_sizeAndEntries()}}{3} \indexentry{ZV_setEntry@{\tt ZV\_setEntry()}}{4} \indexentry{ZV_init@{\tt ZV\_init()}}{4} \indexentry{ZV_init1@{\tt ZV\_init1()}}{4} \indexentry{ZV_init2@{\tt ZV\_init2()}}{4} \indexentry{ZV_setMaxsize@{\tt ZV\_setMaxsize()}}{4} \indexentry{ZV_setSize@{\tt ZV\_setSize()}}{4} \indexentry{ZV_shiftBase@{\tt ZV\_shiftBase()}}{5} \indexentry{ZV_push@{\tt ZV\_push()}}{5} \indexentry{ZV_minabs@{\tt ZV\_minabs()}}{5} \indexentry{ZV_maxabs@{\tt ZV\_maxabs()}}{5} \indexentry{ZV_sizeOf@{\tt ZV\_sizeOf()}}{5} \indexentry{ZV_fill@{\tt ZV\_fill()}}{5} \indexentry{ZV_zero@{\tt ZV\_zero()}}{5} \indexentry{ZV_copy@{\tt ZV\_copy()}}{5} \indexentry{ZV_log10profile@{\tt ZV\_log10profile()}}{6} \indexentry{ZV_readFromFile@{\tt ZV\_readFromFile()}}{6} \indexentry{ZV_readFromFormattedFile@{\tt ZV\_readFromFormattedFile()}}{6} \indexentry{ZV_readFromBinaryFile@{\tt ZV\_readFromBinaryFile()}}{6} \indexentry{ZV_writeToFile@{\tt ZV\_writeToFile()}}{6} \indexentry{ZV_writeToFormattedFile@{\tt ZV\_writeToFormattedFile()}}{6} \indexentry{ZV_writeToBinaryFile@{\tt ZV\_writeToBinaryFile()}}{7} \indexentry{ZV_writeForHumanEye@{\tt ZV\_writeForHumanEye()}}{7} \indexentry{ZV_writeStats@{\tt ZV\_writeStats()}}{7} ZV/doc/proto.tex010064400020550007177000000513160665017063600151010ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of {\tt ZV} methods} \label{section:ZV:proto} \par This section contains brief descriptions including prototypes of all methods that belong to the {\tt ZV} object. \par \subsection{Basic methods} \label{subsection:ZV:proto:basics} \par As usual, there are four basic methods to support object creation, setting default fields, clearing any allocated data, and free'ing the object. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} ZV * ZV_new ( void ) ; \end{verbatim} \index{ZV_new@{\tt ZV\_new()}} This method simply allocates storage for the {\tt ZV} structure and then sets the default fields by a call to {\tt ZV\_setDefaultFields()}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_setDefaultFields ( ZV *zv ) ; \end{verbatim} \index{ZV_setDefaultFields@{\tt ZV\_setDefaultFields()}} This method sets the default fields of the object, {\tt size = maxsize = owned = 0} and {\tt vec = NULL}. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_clearData ( ZV *zv ) ; \end{verbatim} \index{ZV_clearData@{\tt ZV\_clearData()}} This method releases any data owned by the object. If {\tt vec} is not {\tt NULL} and {\tt owned = 1}, then the storage for {\tt vec} is free'd by a call to {\tt ZVfree()}. The structure's default fields are then set with a call to {\tt ZV\_setDefaultFields()}. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_free ( ZV *zv ) ; \end{verbatim} \index{ZV_free@{\tt ZV\_free()}} This method releases any storage by a call to {\tt ZV\_clearData()} then free's the storage for the structure with a call to {\tt free()}. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Instance methods} \label{subsection:ZV:proto:Instance} \par These method allow access to information in the data fields without explicitly following pointers. There is overhead involved with these method due to the function call and error checking inside the methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_owned ( ZV *zv ) ; \end{verbatim} \index{ZV_owned@{\tt ZV\_owned()}} This method returns the value of {\tt owned}. If {\tt owned > 0}, then the object owns the data pointed to by {\tt vec} and will free this data with a call to {\tt ZVfree()} when its data is cleared by a call to {\tt ZV\_free()} or {\tt ZV\_clearData()}. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_size ( ZV *zv ) ; \end{verbatim} \index{ZV_size@{\tt ZV\_size()}} This method returns the value of {\tt size}, the present size of the vector. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_maxsize ( ZV *zv ) ; \end{verbatim} \index{ZV_maxsize@{\tt ZV\_size()}} This method returns the value of {\tt size}, the maximum size of the vector. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_entry ( ZV *zv, int loc, double *pReal, double *pImag ) ; \end{verbatim} \index{ZV_entry@{\tt ZV\_entry()}} This method fills {\tt *pReal} with the real part and {\tt *pImag} with the imaginary part of the {\tt loc}'th entry in the vector. If {\tt loc < 0} or {\tt loc >= size}, i.e., if the location is out of range, we return {\tt 0.0}. This design {\tt feature} is handy when a list terminates with a {\tt 0.0} value. \par \noindent {\it Error checking:} If {\tt zv}, {\tt pReal} or {\tt pImag} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_pointersToEntry ( ZV *zv, int loc, double **ppReal, double **ppImag ) ; \end{verbatim} \index{ZV_pointersToEntry@{\tt ZV\_pointersToEntry()}} This method fills {\tt **ppReal} with a pointer to the real part and {\tt **ppImag} with a pointer to the imaginary part of the {\tt loc}'th entry in the vector. If {\tt loc < 0} or {\tt loc >= size}, i.e., if the location is out of range, we return {\tt 0.0}. This design {\tt feature} is handy when a list terminates with a {\tt 0.0} value. \par \noindent {\it Error checking:} If {\tt zv}, {\tt pReal} or {\tt pImag} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double * ZV_entries ( ZV *zv ) ; \end{verbatim} \index{ZV_entries@{\tt ZV\_entries()}} This method returns {\tt vec}, a pointer to the base address of the vector. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_sizeAndEntries ( ZV *zv, int *psize, double **pentries ) ; \end{verbatim} \index{ZV_sizeAndEntries@{\tt ZV\_sizeAndEntries()}} This method fills {\tt *psize} with the size of the vector and {\tt **pentries} with the base address of the vector. \par \noindent {\it Error checking:} If {\tt zv}, {\tt psize} or {\tt pentries} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_setEntry ( ZV *zv, int loc, double real, double imag ) ; \end{verbatim} \index{ZV_setEntry@{\tt ZV\_setEntry()}} This method sets the {\tt loc}'th entry of the vector to {\tt (real,imag)}. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL} or {\tt loc < 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Initializer methods} \label{subsection:ZV:proto:initializers} \par There are three initializer methods. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_init ( ZV *zv, int size, double *entries ) ; \end{verbatim} \index{ZV_init@{\tt ZV\_init()}} This method initializes the object given a size for the vector and a possible pointer to the vectors' storage. Any previous data is cleared with a call to {\tt ZV\_clearData()}. If {\tt entries != NULL} then the {\tt vec} field is set to {\tt entries}, the {\tt size} and {\tt maxsize} fields are set to {\tt size}, and {\tt owned} is set to zero because the object does not own the entries. If {\tt entries} is {\tt NULL} and {\tt size > 0} then a vector is allocated by the object, and the object owns this storage. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL} or {\tt size < 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_init1 ( ZV *zv, int size ) ; \end{verbatim} \index{ZV_init1@{\tt ZV\_init1()}} This method initializes the object given a size size for the vector via a call to {\tt ZV\_init()}. \par \noindent {\it Error checking:} Error checking is done with the call to {\t ZV\_init()}. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_init2 ( ZV *zv, int size, int maxsize, int owned, double *vec ) ; \end{verbatim} \index{ZV_init2@{\tt ZV\_init2()}} This is the total initialization method. The data is cleared with a call to {\tt ZV\_clearData()}. If {\tt vec} is {\tt NULL}, the object is initialized via a call to {\tt ZV\_init1()}. Otherwise, the objects remaining fields are set to the input parameters. and if {\tt owned} is not {\tt 1}, the data is not owned, so the object cannot grow. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL}, or if {\tt size < 0}, or if {\tt maxsize < size}, or if {\tt owned} is not equal to {\tt 0} or {\tt 1}, of if { \tt owned = 1} and {\tt vec = NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_setMaxsize ( ZV *zv, int newmaxsize ) ; \end{verbatim} \index{ZV_setMaxsize@{\tt ZV\_setMaxsize()}} This method sets the maximum size of the vector. If {\tt maxsize}, the present maximum size of the vector, is not equal to {\tt newmaxsize}, then new storage is allocated. Only {\tt size} entries of the old data are copied into the new storage, so if {\tt size > newmaxsize} then data will be lost. The {\tt size} field is set to the minimum of {\tt size} and {\tt newmaxsize}. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL} or {\tt newmaxsize < 0}, or if {\tt 0 < maxsize} and {\tt owned == 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_setSize ( ZV *zv, int newsize ) ; \end{verbatim} \index{ZV_setSize@{\tt ZV\_setSize()}} This method sets the size of the vector. If {\tt newsize > maxsize}, the length of the vector is increased with a call to {\tt ZV\_setMaxsize()}. The {\tt size} field is set to {\tt newsize}. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL}, or {\tt newsize < 0}, or if {\tt 0 < maxsize < newsize} and {\tt owned = 0}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{Utility methods} \label{subsection:ZV:proto:utilities} \par \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_shiftBase ( ZV *zv, int offset ) ; \end{verbatim} \index{ZV_shiftBase@{\tt ZV\_shiftBase()}} This method shifts the base entries of the vector and decrements the present size and maximum size of the vector by {\tt offset}. This is a dangerous method to use because the state of the vector is lost, namely {\tt vec}, the base of the entries, is corrupted. If the object owns its entries and {\tt ZV\_free()}, {\tt ZV\_setSize()} or {\tt ZV\_setMaxsize()} is called before the base has been shifted back to its original position, a segmentation violation will likely result. This is a very useful method, but use with caution. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_push ( ZV *zv, double val ) ; \end{verbatim} \index{ZV_push@{\tt ZV\_push()}} This method pushes an entry onto the vector. If the vector is full, i.e., if {\tt size == maxsize - 1}, then the size of the vector is doubled if possible. If the storage cannot grow, i.e., if the object does not own its storage, an error message is printed and the program exits. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} double ZV_minabs ( ZV *zv ) ; double ZV_maxabs ( ZV *zv ) ; \end{verbatim} \index{ZV_minabs@{\tt ZV\_minabs()}} \index{ZV_maxabs@{\tt ZV\_maxabs()}} This method simply returns the minimum and maximum magnitudes of entries in the vector. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL}, {\tt size <= 0} or if {\tt vec == NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_sizeOf ( ZV *zv ) ; \end{verbatim} \index{ZV_sizeOf@{\tt ZV\_sizeOf()}} This method returns the number of bytes taken by the object. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL} an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_fill ( ZV *zv, double real, double imag ) ; \end{verbatim} \index{ZV_fill@{\tt ZV\_fill()}} This method fills the vector with a scalar value. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_zero ( ZV *zv ) ; \end{verbatim} \index{ZV_zero@{\tt ZV\_zero()}} This method fills the vector with zeros. \par \noindent {\it Error checking:} If {\tt zv} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_copy ( ZV *zv1, ZV *zv2 ) ; \end{verbatim} \index{ZV_copy@{\tt ZV\_copy()}} This method fills the {\tt zv1} object with entries in the {\tt iv2} object. Note, this is a {\it mapped} copy, {\tt zv1} and {\tt zv2} need not have the same size. The number of entries that are copied is the smaller of the two sizes. \par \noindent {\it Error checking:} If {\tt zv1} or {\tt zv2} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void ZV_log10profile ( ZV *zv, int npts, DV *xDV, DV *yDV, double tausmall, double taubig, int *pnzero, int *pnsmall, int *pnbig ) ; \end{verbatim} \index{ZV_log10profile@{\tt ZV\_log10profile()}} This method scans the entries in the {\tt ZV} object and fills {\tt xDV} and {\tt yDV} with data that allows a simple $\log_{10}$ distribution plot. Only entries whose magnitudes lie in the range {\tt [tausmall, taubig]} contribute to the distribution. The number of entries whose magnitudes are zero, smaller than {\tt tausmall}, or larger than {\tt taubig} are placed into {\tt pnzero}, {\tt *pnsmall} and {\tt *pnbig}, respectively. On return, the size of the {\tt xDV} and {\tt yDV} objects is {\tt npts}. \par \noindent {\it Error checking:} If {\tt zv}, {\tt xDV}, {\tt yDV}, {\tt pnsmall} or {\tt pnbig} are {\tt NULL}, or if ${\tt npts} \le 0$, or if ${\tt taubig} < 0.0$ or if ${\tt tausmall} > {\tt taubig}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par \subsection{IO methods} \label{subsection:ZV:proto:IO} \par There are the usual eight IO routines. The file structure of a {\tt ZV} object is simple: the first entry is {\tt size}, followed by the {\tt size} entries found in {\tt vec[]}. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_readFromFile ( ZV *zv, char *fn ) ; \end{verbatim} \index{ZV_readFromFile@{\tt ZV\_readFromFile()}} \par This method reads a {\tt ZV} object from a file. It tries to open the file and if it is successful, it then calls {\tt ZV\_readFromFormattedFile()} or {\tt ZV\_readFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt zv} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.zvf} (for a formatted file) or {\tt *.zvb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_readFromFormattedFile ( ZV *zv, FILE *fp ) ; \end{verbatim} \index{ZV_readFromFormattedFile@{\tt ZV\_readFromFormattedFile()}} \par This method reads in a {\tt ZV} object from a formatted file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fscanf}, zero is returned. \par \noindent {\it Error checking:} If {\tt zv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_readFromBinaryFile ( ZV *zv, FILE *fp ) ; \end{verbatim} \index{ZV_readFromBinaryFile@{\tt ZV\_readFromBinaryFile()}} \par This method reads in a {\tt ZV} object from a binary file. If there are no errors in reading the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fread}, zero is returned. \par \noindent {\it Error checking:} If {\tt zv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_writeToFile ( ZV *zv, char *fn ) ; \end{verbatim} \index{ZV_writeToFile@{\tt ZV\_writeToFile()}} \par This method writes a {\tt ZV} object from a file. It tries to open the file and if it is successful, it then calls {\tt ZV\_writeFromFormattedFile()} or {\tt ZV\_writeFromBinaryFile()}, closes the file and returns the value returned from the called routine. \par \noindent {\it Error checking:} If {\tt zv} or {\tt fn} are {\tt NULL}, or if {\tt fn} is not of the form {\tt *.zvf} (for a formatted file) or {\tt *.zvb} (for a binary file), an error message is printed and the method returns zero. %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_writeToFormattedFile ( ZV *zv, FILE *fp ) ; \end{verbatim} \index{ZV_writeToFormattedFile@{\tt ZV\_writeToFormattedFile()}} \par This method writes a {\tt ZV} object to a formatted file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fprintf}, zero is returned. \par \noindent {\it Error checking:} If {\tt zv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_writeToBinaryFile ( ZV *zv, FILE *fp ) ; \end{verbatim} \index{ZV_writeToBinaryFile@{\tt ZV\_writeToBinaryFile()}} \par This method writes a {\tt ZV} object to a binary file. If there are no errors in writing the data, the value {\tt 1} is returned. If an IO error is encountered from {\tt fwrite}, zero is returned. \par \noindent {\it Error checking:} If {\tt zv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_writeForHumanEye ( ZV *zv, FILE *fp ) ; \end{verbatim} \index{ZV_writeForHumanEye@{\tt ZV\_writeForHumanEye()}} \par This method writes a {\tt ZV} object to a file in a human readable format. is called to write out the header and statistics. The entries of the vector then follow in eighty column format using the {\tt ZVfprintf()} method. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt zv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_writeStats ( ZV *zv, FILE *fp ) ; \end{verbatim} \index{ZV_writeStats@{\tt ZV\_writeStats()}} \par This method writes the header and statistics to a file. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt zv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \item \begin{verbatim} int ZV_writeForMatlab ( ZV *zv, char *name, FILE *fp ) ; \end{verbatim} \index{ZV_writeForMatlab@{\tt ZV\_writeForMatlab()}} \par This method writes the entries of the vector to a file suitable to be read by Matlab. The character string {\tt name} is the name of the vector, e.g, if {\tt name = "A"}, then we have lines of the form \begin{verbatim} A(1) = 1.000000000000e0 + 2.000000000000e0*i; A(2) = 3.463738459493e0 + 2.728482384840e0*i; \end{verbatim} for each entry in the vector. Note, the output indexing is 1-based, not 0-based. The value {\tt 1} is returned. \par \noindent {\it Error checking:} If {\tt zv} or {\tt fp} are {\tt NULL}, an error message is printed and zero is returned. %----------------------------------------------------------------------- \end{enumerate} offset}. This is a dangerous method to use because the state of the vector is lost, namely {\tt vec}, the base of the entries, is corrupted. If the object owns its entries and {\tt ZV\_free()}, {\tt ZV\_setSize()} or {\tt ZV\_setMaxsize()} is called before the base has been shifted back to its originalZV/doc/main.ilg010064400020550007177000000004570653510777000146360ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (34 entries accepted, 0 rejected). Sorting entries....done (177 comparisons). Generating output file main.ind....done (38 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. ZV/doc/drivers.tex010064400020550007177000000030270653506372300154100ustar00clevecompmath00000400000006\par \section{Driver programs for the {\tt ZV object}} \label{section:ZV:drivers} \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testIO msglvl msgFile inFile outFile \end{verbatim} This driver program tests the {\tt ZV} IO methods, and is useful for translating between the formatted {\tt *.zvf} and binary {\tt *.zvb} files. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inFile} parameter is the name of the file from which to read in the object. {\tt inFile} must be of the form {\tt *.zvf} for a formatted file or {\tt *.zvb} for a binary file. \item The {\tt outFile} parameter is the name of the file to which to write out the object. If {\tt outfile} is of the form {\tt *.zvf}, the object is written to a formatted file. If {\tt outfile} is of the form {\tt *.zvb}, the object is written to a binary file. When {\tt outFile} is {\it not} {\tt "none"}, the object is written to the file in a human readable format. When {\tt outFile} is {\tt "none"}, the object is not written out. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} ZV/doc/makefile010064400020550007177000000000270654276751500147150ustar00clevecompmath00000400000006clean : - rm -f *.dvi misc.h010064400020550007177000000000740653561651700132140ustar00clevecompmath00000400000006#ifndef _misc_ #define _misc_ #include "misc/misc.h" #endif misc/misc.h010064400020550007177000000341520660023733000141340ustar00clevecompmath00000400000006/* misc.h */ #include "../cfiles.h" #include "../DenseMtx.h" #include "../InpMtx.h" #include "../ETree.h" #include "../Coords.h" #include "../Graph.h" #include "../MSMD.h" #include "../GPart.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods in ND.c -------------------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ purpose -- main procedure. if the input region is 1 x 1 x 1, the node is put into the permutation vector. otherwise the region is split into three pieces, two subregions and a separator, and recursive calls are made to order the subregions input -- n1 -- number of points in the first direction n2 -- number of points in the second direction n3 -- number of points in the third direction new_to_old -- pointer to the permutation vector west -- west coordinate east -- east coordinate south -- south coordinate north -- north coordinate bottom -- bottom coordinate top -- top coordinate created -- 95nov15, cca ------------------------------------------------------------ */ void mkNDperm ( int n1, int n2, int n3, int new_to_old[], int west, int east, int south, int north, int bottom, int top ) ; /* ----------------------------------------------------- purpose -- to print a vector on a 2-d grid input -- n1 -- number of points in the first direction n2 -- number of points in the second direction ivec -- integer vector to be printed in %4d format fp -- file pointer created -- 95nov16, cca ----------------------------------------------------- */ void fp2DGrid ( int n1, int n2, int ivec[], FILE *fp ) ; /* ----------------------------------------------------- purpose -- to print a vector on a 3-d grid input -- n1 -- number of points in the first direction n2 -- number of points in the second direction n3 -- number of points in the third direction ivec -- integer vector to be printed in %4d format fp -- file pointer created -- 95nov16, cca ----------------------------------------------------- */ void fp3DGrid ( int n1, int n2, int n3, int ivec[], FILE *fp ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods in localND.c --------------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------ compute an old-to-new ordering for local nested dissection in two dimensions n1 -- number of grid points in first direction n2 -- number of grid points in second direction p1 -- number of domains in first direction p2 -- number of domains in second direction dsizes1 -- domain sizes in first direction, size p1 if NULL, then we construct our own dsizes2 -- domain sizes in second direction, size p2 if NULL, then we construct our own oldToNew -- old-to-new permutation vector note : the following must hold n1 > 0, n2 >0, n1 >= 2*p1 - 1, n2 >= 2*p2 - 1, p2 > 1 sum(dsizes1) = n1 - p1 + 1 and sum(dsizes2) = n2 - p2 + 1 created -- 95nov16, cca ------------------------------------------------------------ */ void localND2D ( int n1, int n2, int p1, int p2, int dsizes1[], int dsizes2[], int oldToNew[] ) ; /* ------------------------------------------------------------ compute an old-to-new ordering for local nested dissection in three dimensions n1 -- number of grid points in first direction n2 -- number of grid points in second direction n3 -- number of grid points in third direction p1 -- number of domains in first direction p2 -- number of domains in second direction p3 -- number of domains in third direction dsizes1 -- domain sizes in first direction, size p1 if NULL, then we construct our own dsizes2 -- domain sizes in second direction, size p2 if NULL, then we construct our own dsizes3 -- domain sizes in third direction, size p3 if NULL, then we construct our own oldToNew -- old-to-new permutation vector note : the following must hold n1 > 0, n2 >0, n3 > 0, n1 >= 2*p1 - 1, n2 >= 2*p2 - 1, n3 >= 2*p3 - 1, p3 > 1 sum(dsizes1) = n1 - p1 + 1, sum(dsizes2) = n2 - p2 + 1 sum(dsizes3) = n3 - p3 + 1 created -- 95nov16, cca ------------------------------------------------------------ */ void localND3D ( int n1, int n2, int n3, int p1, int p2, int p3, int dsizes1[], int dsizes2[], int dsizes3[], int oldToNew[] ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods in orderViaBestOfNDandMS.c ------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- return an ETree object for the better of a nested dissection and multisection orderings graph -- graph to order maxdomainsize -- used to control the incomplete nested dissection process. any subgraph whose weight is less than maxdomainsize is not split further. maxzeros -- maximum number of zero entries allowed in a front maxsize -- maximum number of internal columns in a front seed -- random number seed msglvl -- message level 1 -- timings and statistics 2 -- more timings and statistics 3 -- lots of output msgFile -- message file created -- 98aug26, cca ------------------------------------------------------------------ */ ETree * orderViaBestOfNDandMS ( Graph *graph, int maxdomainsize, int maxzeros, int maxsize, int seed, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods in orderViaND.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- return an ETree object for a nested dissection ordering graph -- graph to order maxdomainsize -- used to control the incomplete nested dissection process. any subgraph whose weight is less than maxdomainsize is not split further. seed -- random number seed msglvl -- message level, 0 --> no output, 1 --> timings msgFile -- message file created -- 97nov06, cca ------------------------------------------------------------------ */ ETree * orderViaND ( Graph *graph, int maxdomainsize, int seed, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods in orderViaMS.c ------------------------------------------ ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------ purpose -- return an ETree object for a multisection ordering graph -- graph to order maxdomainsize -- used to control the incomplete nested dissection process. any subgraph whose weight is less than maxdomainsize is not split further. seed -- random number seed msglvl -- message level, 0 --> no output, 1 --> timings msgFile -- message file created -- 97nov06, cca ------------------------------------------------------------------ */ ETree * orderViaMS ( Graph *graph, int maxdomainsize, int seed, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods in orderViaMMD.c ----------------------------------------- ------------------------------------------------------------------------ */ /* -------------------------------------------------------- purpose -- return an ETree object for a multiple minimum degree ordering graph -- graph to order seed -- random number seed msglvl -- message level, 0 --> no output, 1 --> timings msgFile -- message file created -- 97nov08, cca -------------------------------------------------------- */ ETree * orderViaMMD ( Graph *graph, int seed, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods in drawGraphEPS.c ---------------------------------------- ------------------------------------------------------------------------ */ /* ------------------------------------------------- draw a graph to an EPS file (1) read a Graph object (2) read a Coords object (3) read an IV object that contains a tag vector. if (v,w) is an edge in the graph and tags[v] == tags[w] then draw edge (v,w) (4) bbox[4] is the bounding box for the plot. bbox = { xsw, ysw, xne, yne } try bbox = { 0, 0, 500, 500 } because coordinates are measured in points, 72 points per inch. (5) rect[4] contains the frame for the plot. to put a 20 point margin around the plot, rect[0] = bbox[0] + 20 rect[1] = bbox[1] + 20 rect[2] = bbox[2] - 20 rect[3] = bbox[3] - 20 created -- 98apr11, cca ------------------------------------------------- */ void drawGraphEPS ( Graph *graph, Coords *coords, IV *tagsIV, double bbox[], double rect[], double linewidth1, double linewidth2, double radius, char *epsFileName, int msglvl, FILE *msgFile ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods in mkNDlinsys.c ------------------------------------------ ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- purpose -- to create a linear system A*X = B for a nested dissection ordering of a 2-d or 3-d regular grid input -- n1 -- # of nodes in first direction n2 -- # of nodes in second direction n3 -- # of nodes in third direction maxzeros -- relaxation factor for fronts, maximum number of zero entries in a front maxsize -- split parameter for large fronts, maximum number of internal vertices in a front type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides seed -- seed for random number generator msglvl -- message level msgFile -- message file output -- pfrontETree -- to be filled with address of front tree psymbfacIVL -- to be filled with address of symbolic factorization pmtxA -- to be filled with address of matrix object A pmtxX -- to be filled with address of matrix object X pmtxB -- to be filled with address of matrix object B created -- 98may16, cca --------------------------------------------------------------------- */ void mkNDlinsys ( int n1, int n2, int n3, int maxzeros, int maxsize, int type, int symmetryflag, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------------ ----- methods in mkNDlinsysQR.c ---------------------------------------- ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- purpose -- to create an overdetermined linear system A*X = B for a nested dissection ordering of a 2-d or 3-d regular grid input -- n1 -- # of nodes in first direction n2 -- # of nodes in second direction n3 -- # of nodes in third direction type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX nrhs -- number of right hand sides seed -- seed for random number generator msglvl -- message level msgFile -- message file output -- pfrontETree -- to be filled with address of front tree psymbfacIVL -- to be filled with address of symbolic factorization pmtxA -- to be filled with address of matrix object A pmtxX -- to be filled with address of matrix object X pmtxB -- to be filled with address of matrix object B created -- 98may29, cca --------------------------------------------------------------------- */ void mkNDlinsysQR ( int n1, int n2, int n3, int type, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB ) ; /*--------------------------------------------------------------------*/ size p3 if NULL, then we construct our own oldToNew -- old-to-new permutation vector note : the following must hold n1 > 0, n2 >0, n3 > 0, n1 >= 2*p1 - 1, n2 >= 2*p2 - 1, n3 >= 2*p3 - 1, p3 > 1 sum(dsizes1) = n1 - p1 + 1, sum(dsizes2) = n2 - p2 + 1 sum(dsizes3) = n3 - p3 + 1 created -- 95nov16, cca -----------------------------------------------------misc/makefile010064400020550007177000000002230663622372100145300ustar00clevecompmath00000400000006all_drivers : cd drivers ; make drivers lib : cd src ; make makeLib clean : cd src ; make clean cd drivers ; make clean cd doc ; make clean misc/src/makefile010064400020550007177000000012500663603103400153120ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = misc $(OBJ).a : \ $(OBJ).a(drawGraphEPS.o) \ $(OBJ).a(fpgrids.o) \ $(OBJ).a(localND.o) \ $(OBJ).a(ND.o) \ $(OBJ).a(ND2.o) \ $(OBJ).a(mkNDlinsys.o) \ $(OBJ).a(mkNDlinsysQR.o) \ $(OBJ).a(orderViaBestOfNDandMS.o) \ $(OBJ).a(orderViaMMD.o) \ $(OBJ).a(orderViaMS.o) \ $(OBJ).a(orderViaND.o) @ $(RANLIB) $(OBJ).a @ echo $(OBJ).a is now up-to-date clean : - rm -f *.a *.o makeLib : perl ../../makeLib > makeG make -f makeG rm -f makeG updateLib : perl ../../updLib > makeG make -f makeG rm -f makeG misc/src/makeGlobalLib010064400020550007177000000010400660026117000162140ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- OBJ = misc SRC = drawGraphEPS.c \ fpgrids.c \ localND.c \ ND.c \ ND2.c \ mkNDlinsys.c \ mkNDlinsysQR.c \ orderViaBestOfNDandMS.c \ orderViaMMD.c \ orderViaMS.c \ orderViaND.c OBJ_FILES = ${SRC:.c=.o} .c.o : $(PURIFY) $(CC) -c $(CFLAGS) $*.c -o $(OBJ)_$*.o ../../spooles.a : ${OBJ_FILES} $(AR) $(ARFLAGS) ../../spooles.a $(OBJ)_*.o rm -f $(OBJ)_*.o $(RANLIB) ../../spooles.a misc/src/ND.c010064400020550007177000000231200653410634500142640ustar00clevecompmath00000400000006/* ND.c */ #include "../misc.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- this file contains procedures to create a nested dissection permutation in one, two or three dimensions. --------------------------------------------------------------- */ #define DEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------- static procedures ----------------- */ static void SplitX ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) ; static void SplitY ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) ; static void SplitZ ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) ; static int WhichCut ( int west, int east, int south, int north, int bottom, int top ) ; static int MidPoint ( int left, int right, int glob_center ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- main procedure. if the input region is 1 x 1 x 1, the node is put into the permutation vector. otherwise the region is split into three pieces, two subregions and a separator, and recursive calls are made to order the subregions input -- n1 -- number of points in the first direction n2 -- number of points in the second direction n3 -- number of points in the third direction newToOld -- pointer to the permutation vector west -- west coordinate east -- east coordinate south -- south coordinate north -- north coordinate bottom -- bottom coordinate top -- top coordinate created -- 95nov15, cca ------------------------------------------------------------ */ void mkNDperm ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) { if ( n1 <= 0 || n2 <= 0 || n3 <= 0 || newToOld == NULL || west < 0 || east >= n1 || south < 0 || north >= n2 || bottom < 0 || top >= n3 ) { fprintf(stderr, "\n fatal error in mkNDperm(%d,%d,%d,%p,%d,%d,%d,%d,%d,%d)" "\n bad input data\n", n1, n2, n3, newToOld, west, east, south, north, bottom, top) ; exit(-1) ; } if ( west == east && south == north && bottom == top ) { # if DEBUG > 0 fprintf(stdout, "\n ND : ordering %d", west + south * n1 + bottom * n1 * n2) ; # endif newToOld[0] = west + south * n1 + bottom * n1 * n2 ; } else { switch ( WhichCut(west, east, south, north, bottom, top) ) { case 1 : # if DEBUG > 0 fprintf(stdout, "\n ND : calling Split9X") ; # endif SplitX(n1, n2, n3, newToOld, west, east, south, north, bottom, top) ; break ; case 2 : # if DEBUG > 0 fprintf(stdout, "\n ND : calling Split9Y") ; # endif SplitY(n1, n2, n3, newToOld, west, east, south, north, bottom, top) ; break ; case 3 : # if DEBUG > 0 fprintf(stdout, "\n ND : calling Split9Z") ; # endif SplitZ(n1, n2, n3, newToOld, west, east, south, north, bottom, top) ; break ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to decide which way to partition a subregion created -- 95nov16, cca ------------------------------------------------------- */ static int WhichCut ( int west, int east, int south, int north, int bottom, int top ) { int d1, d2, d3 ; d1 = east - west + 1 ; d2 = north - south + 1 ; d3 = top - bottom + 1 ; #if DEBUG > 0 fprintf(stdout, "\n WhichCut : (d1,d2,d3) = (%d,%d,%d)", d1,d2,d3) ; #endif if ( d1 > d2 && d1 > d3 ) { return(1) ; } else if ( d2 > d1 && d2 > d3 ) { return(2) ; } else if ( d3 > d1 && d3 > d2 ) { return(3) ; } else if ( d1 == d2 && d1 > d3 ) { return(1) ; } else if ( d1 == d3 && d1 > d2 ) { return(1) ; } else if ( d2 == d3 && d2 > d1 ) { return(2) ; } else { return(3) ; } } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to split a subregion with a Y-Z plane ------------------------------------------------ */ static void SplitX ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) { int east1, east2, j, k, k1, k2, k3, m, m1, west1, west2 ; m1 = MidPoint(west, east, n1/2) ; west1 = west ; east1 = m1 - 1 ; west2 = m1 + 1 ; east2 = east ; k1 = 0 ; k2 = k1 + (m1 - west) * (north - south + 1) * (top - bottom + 1) ; k3 = k2 + (east - m1) * (north - south + 1) * (top - bottom + 1) ; if ( m1 > west ) { # if DEBUG > 0 fprintf(stdout, "\n SplitX : 1. calling ND") ; # endif mkNDperm(n1, n2, n3, newToOld + k1, west1, east1, south, north, bottom, top) ; } if ( east > m1 ) { # if DEBUG > 0 fprintf(stdout, "\n SplitX : 2. calling ND") ; # endif mkNDperm(n1, n2, n3, newToOld + k2, west2, east2, south, north, bottom, top) ; } # if DEBUG > 0 fprintf(stdout, "\n SplitX : 3. calling ND") ; fprintf(stdout, "\n m1 = %d, south = %d, north = %d", m1, south, north) ; # endif m = k3 ; for ( k = bottom ; k <= top ; k++ ) { for ( j = south ; j <= north ; j++ ) { newToOld[m++] = m1 + j * n1 + k * n1 * n2 ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to split a subregion with a X-Z plane created -- 95nov16, cca ------------------------------------------------ */ static void SplitY ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) { int i, k, k1, k2, k3, m, m1, north1, north2, south1, south2 ; m1 = MidPoint(south, north, n2/2) ; south1 = south ; north1 = m1 - 1 ; south2 = m1 + 1 ; north2 = north ; k1 = 0 ; k2 = k1 + (m1 - south) * (east - west + 1) * (top - bottom + 1) ; k3 = k2 + (north - m1) * (east - west + 1) * (top - bottom + 1) ; if ( m1 > south ) { # if DEBUG > 0 fprintf(stdout, "\n SplitY : calling ND(%d:%d,%d:%d,%d:%d)", west, east, south1, north1, bottom, top) ; # endif mkNDperm(n1, n2, n3, newToOld + k1, west, east, south1, north1, bottom, top) ; } if ( north > m1 ) { # if DEBUG > 0 fprintf(stdout, "\n SplitY : calling ND(%d:%d,%d:%d,%d:%d)", west, east, south2, north2, bottom, top) ; # endif mkNDperm(n1, n2, n3, newToOld + k2, west, east, south2, north2, bottom, top) ; } # if DEBUG > 0 fprintf(stdout, "\n SplitY : ordering (%d:%d,%d:%d,%d:%d)", west, east, m1, m1, bottom, top) ; # endif m = k3 ; for ( k = bottom ; k <= top ; k++ ) { for ( i = west ; i <= east ; i++ ) { # if DEBUG > 0 fprintf(stdout, "\n SplitY : newToOld[%d] = %d", m, i + m1 * n1 + k * n1 * n2) ; # endif newToOld[m++] = i + m1 * n1 + k * n1 * n2 ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to split a subregion with a X-Y plane created -- 95nov16, cca ------------------------------------------------ */ static void SplitZ ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) { int bottom1, bottom2, i, j, k1, k2, k3, m, m1, top1, top2 ; m1 = MidPoint(bottom, top, n2/2) ; bottom1 = bottom ; top1 = m1 - 1 ; bottom2 = m1 + 1 ; top2 = top ; k1 = 0 ; k2 = k1 + (m1 - bottom) * (east - west + 1) * (north - south + 1) ; k3 = k2 + (top - m1) * (east - west + 1) * (north - south + 1) ; if ( m1 > bottom ) { # if DEBUG > 0 fprintf(stdout, "\n SplitZ : 1. calling ND") ; # endif mkNDperm(n1, n2, n3, newToOld + k1, west, east, south, north, bottom1, top1) ; } if ( top > m1 ) { # if DEBUG > 0 fprintf(stdout, "\n SplitZ : 2. calling ND") ; # endif mkNDperm(n1, n2, n3, newToOld + k2, west, east, south, north, bottom2, top2) ; } # if DEBUG > 0 fprintf(stdout, "\n SplitZ : 3. calling ND") ; # endif m = k3 ; for ( j = south ; j <= north ; j++ ) { for ( i = west ; i <= east ; i++ ) { newToOld[m++] = i + j * n1 + m1 * n1 * n2 ; } } return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the midpoint of a region input -- left -- left coordinate right -- right coordinate glob_center -- glob_center coordinate ---------------------------------------------- */ static int MidPoint ( int left, int right, int glob_center ) { int mid ; mid = (left + right)/2 ; if ( (left + right) % 2 == 0 ) { return(mid) ; } else if ( mid >= glob_center ) { return(mid) ; } else { return(mid+1) ; } } /*--------------------------------------------------------------------*/ misc/src/ND2.c010064400020550007177000000301400653410634500143460ustar00clevecompmath00000400000006/* ND2.c */ #include "../misc.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- this file contains procedures to create a nested dissection permutation in one, two or three dimensions. note, all separators are double wide created -- 96feb01, cca --------------------------------------------------------------- */ #define DEBUG 0 /*--------------------------------------------------------------------*/ /* ----------------- static procedures ----------------- */ static void SplitX ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) ; static void SplitY ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) ; static void SplitZ ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) ; static int WhichCut ( int west, int east, int south, int north, int bottom, int top ) ; static int MidPoint ( int left, int right, int glob_center ) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ purpose -- main procedure. if the input region is m1 x m2 x m3, where 0 < m1, m2, m3 < 2, then the node is put into the permutation vector. otherwise the region is split into three pieces, two subregions and a separator, and recursive calls are made to order the subregions input -- n1 -- number of points in the first direction n2 -- number of points in the second direction n3 -- number of points in the third direction newToOld -- pointer to the permutation vector west -- west coordinate east -- east coordinate south -- south coordinate north -- north coordinate bottom -- bottom coordinate top -- top coordinate created -- 95nov15, cca ------------------------------------------------------------ */ void mkNDperm2 ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) { int count, i, j, k ; if ( n1 <= 0 || n2 <= 0 || n3 <= 0 || newToOld == NULL || west < 0 || east >= n1 || south < 0 || north >= n2 || bottom < 0 || top >= n3 ) { fprintf(stderr, "\n fatal error in mkND2perm(%d,%d,%d,%p,%d,%d,%d,%d,%d,%d)" "\n bad input data\n", n1, n2, n3, newToOld, west, east, south, north, bottom, top) ; exit(-1) ; } if ( east - west <= 1 && north - south <= 1 && top - bottom <= 1 ) { count = 0 ; for ( i = west ; i <= east ; i++ ) { for ( j = south ; j <= north ; j++ ) { for ( k = bottom ; k <= top ; k++ ) { # if DEBUG > 0 fprintf(stdout, "\n ND : ordering %d", i + j * n1 + k * n1 * n2) ; # endif newToOld[count++] = i + j * n1 + k * n1 * n2 ; } } } } else { switch ( WhichCut(west, east, south, north, bottom, top) ) { case 1 : # if DEBUG > 0 fprintf(stdout, "\n ND : calling SplitX(%d,%d,%d,%d,%d,%d)", west, east, south, north, bottom, top) ; # endif SplitX(n1, n2, n3, newToOld, west, east, south, north, bottom, top) ; break ; case 2 : # if DEBUG > 0 fprintf(stdout, "\n ND : calling SplitY(%d,%d,%d,%d,%d,%d)", west, east, south, north, bottom, top) ; # endif SplitY(n1, n2, n3, newToOld, west, east, south, north, bottom, top) ; break ; case 3 : # if DEBUG > 0 fprintf(stdout, "\n ND : calling SplitZ(%d,%d,%d,%d,%d,%d)", west, east, south, north, bottom, top) ; # endif SplitZ(n1, n2, n3, newToOld, west, east, south, north, bottom, top) ; break ; } } return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- purpose -- to decide which way to partition a subregion created -- 95nov16, cca ------------------------------------------------------- */ static int WhichCut ( int west, int east, int south, int north, int bottom, int top ) { int d1, d2, d3 ; d1 = east - west + 1 ; d2 = north - south + 1 ; d3 = top - bottom + 1 ; #if DEBUG > 0 fprintf(stdout, "\n WhichCut : (d1,d2,d3) = (%d,%d,%d)", d1,d2,d3) ; #endif if ( d1 > d2 && d1 > d3 ) { return(1) ; } else if ( d2 > d1 && d2 > d3 ) { return(2) ; } else if ( d3 > d1 && d3 > d2 ) { return(3) ; } else if ( d1 == d2 && d1 > d3 ) { return(1) ; } else if ( d1 == d3 && d1 > d2 ) { return(1) ; } else if ( d2 == d3 && d2 > d1 ) { return(2) ; } else { return(3) ; } } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to split a subregion with a Y-Z plane ------------------------------------------------ */ static void SplitX ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) { int depth, east1, east2, height, j, k, k1, k2, k3, m, mid, west1, west2, width1, width2 ; # if DEBUG > 0 fprintf(stdout, "\n inside SplitX(%d:%d,%d:%d,%d:%d)", west, east, south, north, bottom, top) ; # endif mid = MidPoint(west, east, n1/2) ; west1 = west ; east1 = mid - 1 ; west2 = mid + 2 ; east2 = east ; width1 = east1 - west1 + 1 ; width2 = east2 - west2 + 1 ; height = north - south + 1 ; depth = top - bottom + 1 ; k1 = 0 ; k2 = k1 + width1 * height * depth ; k3 = k2 + width2 * height * depth ; if ( width1 > 0 ) { # if DEBUG > 0 fprintf(stdout, "\n SplitX : 1. calling ND(%d,%d,%d,%d,%d,%d", west1, east1, south, north, bottom, top) ; # endif mkNDperm2(n1, n2, n3, newToOld + k1, west1, east1, south, north, bottom, top) ; } if ( width2 > 0 ) { # if DEBUG > 0 fprintf(stdout, "\n SplitX : 2. calling ND(%d,%d,%d,%d,%d,%d", west2, east2, south, north, bottom, top) ; # endif mkNDperm2(n1, n2, n3, newToOld + k2, west2, east2, south, north, bottom, top) ; } m = k3 ; for ( k = bottom ; k <= top ; k++ ) { for ( j = south ; j <= north ; j++ ) { # if DEBUG > 0 fprintf(stdout, "\n newToOld[%d] = %d", m, mid + j * n1 + k * n1 * n2) ; fprintf(stdout, "\n newToOld[%d] = %d", m+1, mid + 1 + j * n1 + k * n1 * n2) ; # endif newToOld[m++] = mid + j * n1 + k * n1 * n2 ; newToOld[m++] = mid + 1 + j * n1 + k * n1 * n2 ; } } # if DEBUG > 0 fprintf(stdout, "\n leaving SplitX(%d:%d,%d:%d,%d:%d)", west, east, south, north, bottom, top) ; # endif return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to split a subregion with a X-Z plane created -- 95nov16, cca ------------------------------------------------ */ static void SplitY ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) { int depth, height1, height2, i, k, k1, k2, k3, m, mid, north1, north2, south1, south2, width ; # if DEBUG > 0 fprintf(stdout, "\n inside SplitY(%d:%d,%d:%d,%d:%d)", west, east, south, north, bottom, top) ; # endif mid = MidPoint(south, north, n2/2) ; south1 = south ; north1 = mid - 1 ; south2 = mid + 2 ; north2 = north ; # if DEBUG > 0 fprintf(stdout, "\n mid = %d, south1 = %d, north1 = %d, south2 = %d, north2 = %d", mid, south1, north1, south2, north2) ; # endif width = east - west + 1 ; height1 = north1 - south1 + 1 ; height2 = north2 - south2 + 1 ; depth = top - bottom + 1 ; k1 = 0 ; k2 = k1 + width * height1 * depth ; k3 = k2 + width * height2 * depth ; if ( height1 > 0 ) { # if DEBUG > 0 fprintf(stdout, "\n SplitY : calling ND(%d:%d,%d:%d,%d:%d)", west, east, south1, north1, bottom, top) ; # endif mkNDperm2(n1, n2, n3, newToOld + k1, west, east, south1, north1, bottom, top) ; } if ( height2 > 0 ) { # if DEBUG > 0 fprintf(stdout, "\n SplitY : calling ND(%d:%d,%d:%d,%d:%d)", west, east, south2, north2, bottom, top) ; # endif mkNDperm2(n1, n2, n3, newToOld + k2, west, east, south2, north2, bottom, top) ; } m = k3 ; for ( k = bottom ; k <= top ; k++ ) { for ( i = west ; i <= east ; i++ ) { # if DEBUG > 0 fprintf(stdout, "\n SplitY : newToOld[%d] = %d", m, i + mid * n1 + k * n1 * n2) ; fprintf(stdout, "\n SplitY : newToOld[%d] = %d", m+1, i + (mid + 1) * n1 + k * n1 * n2) ; # endif newToOld[m++] = i + mid*n1 + k*n1*n2 ; newToOld[m++] = i + (mid + 1)*n1 + k*n1*n2 ; } } # if DEBUG > 0 fprintf(stdout, "\n leaving SplitY(%d:%d,%d:%d,%d:%d)", west, east, south, north, bottom, top) ; # endif return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------ purpose -- to split a subregion with a X-Y plane created -- 95nov16, cca ------------------------------------------------ */ static void SplitZ ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) { int bottom1, bottom2, depth1, depth2, height, i, j, k1, k2, k3, m, mid, top1, top2, width ; # if DEBUG > 0 fprintf(stdout, "\n inside SplitZ(%d:%d,%d:%d,%d:%d)", west, east, south, north, bottom, top) ; # endif mid = MidPoint(bottom, top, n2/2) ; bottom1 = bottom ; top1 = mid - 1 ; bottom2 = mid + 2 ; top2 = top ; width = east - west + 1 ; height = north - south + 1 ; depth1 = top1 - bottom1 + 1 ; depth2 = top2 - bottom2 + 1 ; k1 = 0 ; k2 = k1 + width * height * depth1 ; k3 = k2 + width * height * depth2 ; if ( depth1 > 0 ) { # if DEBUG > 0 fprintf(stdout, "\n SplitZ : 1. calling ND(%d:%d,%d:%d,%d:%d)", west, east, south, north, bottom1, top1) ; # endif mkNDperm2(n1, n2, n3, newToOld + k1, west, east, south, north, bottom1, top1) ; } if ( depth2 > 0 ) { # if DEBUG > 0 fprintf(stdout, "\n SplitZ : 2. calling ND(%d:%d,%d:%d,%d:%d)", west, east, south, north, bottom2, top2) ; # endif mkNDperm2(n1, n2, n3, newToOld + k2, west, east, south, north, bottom2, top2) ; } m = k3 ; for ( j = south ; j <= north ; j++ ) { for ( i = west ; i <= east ; i++ ) { # if DEBUG > 0 fprintf(stdout, "\n newToOld[%d] = %d", m, i + j*n1 + mid*n1*n2) ; fprintf(stdout, "\n newToOld[%d] = %d", m+1, i + j*n1 + (mid+1)*n1*n2) ; # endif newToOld[m++] = i + j*n1 + mid*n1*n2 ; newToOld[m++] = i + j*n1 + (mid + 1)*n1*n2 ; } } # if DEBUG > 0 fprintf(stdout, "\n leaving SplitZ(%d:%d,%d:%d,%d:%d)", west, east, south, north, bottom, top) ; # endif return ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------- purpose -- to compute the midpoint of a region input -- left -- left coordinate right -- right coordinate glob_center -- glob_center coordinate ---------------------------------------------- */ static int MidPoint ( int left, int right, int glob_center ) { int mid ; /* mid = (left + right)/2 ; if ( (left + right) % 2 == 0 ) { return(mid) ; } else if ( mid >= glob_center ) { return(mid) ; } else { return(mid+1) ; } */ mid = left + (right - left - 1)/2 ; return(mid) ; } /*--------------------------------------------------------------------*/ e north -- north coordinate bottom -- bottom coordinate top -- top coordinate created -- 95nov15, cca ------------------------------------------------------------ */ void mkNDperm2 ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) { int count, i, j, k ; ifmisc/src/drawGraphEPS.c010064400020550007177000000227140660026341300162540ustar00clevecompmath00000400000006/* drawGraphEPS.c */ #include "../../Graph.h" #include "../../Coords.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* ------------------------------------------------- draw a graph to an EPS file (1) read a Graph object (2) read a Coords object (3) read an IV object that contains a tag vector. if (v,w) is an edge in the graph and tags[v] == tags[w] then draw edge (v,w) (4) bbox[4] is the bounding box for the plot. bbox = { xsw, ysw, xne, yne } try bbox = { 0, 0, 500, 500 } because coordinates are measured in points, 72 points per inch. (5) rect[4] contains the frame for the plot. to put a 20 point margin around the plot, rect[0] = bbox[0] + 20 rect[1] = bbox[1] + 20 rect[2] = bbox[2] - 20 rect[3] = bbox[3] - 20 created -- 98apr11, cca ------------------------------------------------- */ void drawGraphEPS ( Graph *graph, Coords *coords, IV *tagsIV, double bbox[], double rect[], double linewidth1, double linewidth2, double radius, char *epsFileName, int msglvl, FILE *msgFile ) { double a, b, d, height, offset, width, xmax, xmin, xsize, xv, xw, x0, x1, ymax, ymin, ysize, yv, yw, y0, y1 ; FILE *epsFile ; int ii, nedge, nvtx, v, vsize, w ; int *tags, *vadj ; nvtx = graph->nvtx ; if ( tagsIV == NULL ) { tags = NULL ; } else { tags = IV_entries(tagsIV) ; } /* ----------------- open the EPS file ----------------- */ if ( strcmp(epsFileName, "stdout") == 0 ) { epsFile = stdout ; } else if ( (epsFile = fopen(epsFileName, "w")) == NULL ) { fprintf(stderr, "\n fatal error in drawGraphEPS" "\n unable to open file %s\n", epsFileName) ; return ; } /* ----------------------------------- write the preamble for the EPS file ----------------------------------- */ fprintf(epsFile, "%%!PS-Adobe-2.0 EPSF-1.2" "\n%%%%BoundingBox: %.1f %.1f %.1f %.1f", bbox[0], bbox[1], bbox[2], bbox[3]) ; fprintf(epsFile, "\n /radius %.3f def" "\n /Helvetica findfont %.3f scalefont setfont" "\n /M {moveto} def" "\n /L {lineto} def" "\n /ACF { %% stack : x y radius" "\n newpath 0 360 arc closepath fill " "\n } def" "\n /str 6 string def" "\n /drawLabel { %% x y label radius" "\n /radius exch def" "\n /label exch def" "\n /y exch def" "\n /x exch def" "\n gsave" "\n 1.0 setgray" "\n x radius add y moveto" "\n x y radius 0 360 arc" "\n fill" "\n 0.0 setgray" "\n x radius add y moveto" "\n x y radius 0 360 arc" "\n stroke" "\n x y moveto" "\n label stringwidth pop 2 div neg radius 2 div neg rmoveto" "\n label show" "\n grestore" "\n } def ", radius, 1.25*radius) ; /* --------------------------------------- determine the transformation parameters --------------------------------------- */ xmin = Coords_min(coords, 1) ; xmax = Coords_max(coords, 1) ; ymin = Coords_min(coords, 2) ; ymax = Coords_max(coords, 2) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n xmin = %.3g, xmax = %.3g, ymin = %.3g, ymax = %.3g", xmin, xmax, ymin, ymax) ; } xsize = xmax - xmin ; ysize = ymax - ymin ; width = rect[2] - rect[0] ; height = rect[3] - rect[1] ; if ( msglvl > 2 ) { fprintf(msgFile, "\n xsize = %.3g, ysize = %.3g, width = %.3g, height = %.3g", xsize, ysize, width, height) ; } if ( ysize * width <= xsize * height ) { a = width / xsize ; b = rect[0] ; offset = (rect[3] - rect[1] - a * ysize)/2 ; d = rect[1] + offset - a * ymin ; } else { a = height / ysize ; d = rect[1] ; offset = (rect[2] - rect[0] - a * xsize)/2 ; b = rect[0] + offset - a * xmin ; } if ( ysize * width <= xsize * height ) { a = width / xsize ; } else { a = height / ysize ; } b = 0.5*(rect[2] + rect[0] - a*(xmin + xmax)) ; d = 0.5*(rect[3] + rect[1] - a*(ymin + ymax)) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n width = %.3g, height = %.3g", width, height) ; fprintf(msgFile, "\n xsize = %.3g, ysize = %.3g", xsize, ysize) ; fprintf(msgFile, "\n xmin = %.3g, xmax = %.3g, ymin = %.3g, ymax = %.3g", xmin, xmax, ymin, ymax) ; fprintf(msgFile, "\n a = %.3g, b = %.3g, d = %.3g", a, b, d) ; } if ( tags == NULL ) { /* -------------------------------- no component ids, draw the edges -------------------------------- */ fprintf(epsFile, "\n gsave" "\n %.3f setlinewidth" "\n 0.0 setgray", linewidth1) ; nedge = 0 ; for ( v = 0 ; v < nvtx ; v++ ) { Graph_adjAndSize(graph, v, &vsize, &vadj) ; xv = Coords_value(coords, 1, v) ; yv = Coords_value(coords, 2, v) ; x0 = a * xv + b ; y0 = a * yv + d ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < v ) { xw = Coords_value(coords, 1, w) ; yw = Coords_value(coords, 2, w) ; x1 = a * xw + b ; y1 = a * yw + d ; if ( nedge % 100 == 0 ) { fprintf(epsFile, "\n newpath") ; } fprintf(epsFile, "\n %.3g %.3g M %.3g %.3g L", x0, y0, x1, y1) ; if ( ++nedge % 100 == 0 ) { fprintf(epsFile, "\n stroke") ; } } } } if ( nedge % 100 != 0 ) { fprintf(epsFile, "\n stroke") ; } fprintf(epsFile, "\n grestore") ; fprintf(epsFile, "\n gsave" "\n 0.1 setlinewidth" "\n 0.0 setgray") ; if ( radius > 0.0 ) { /* ----------------- draw the vertices ----------------- */ for ( v = 0 ; v < nvtx ; v++ ) { xv = Coords_value(coords, 1, v) ; yv = Coords_value(coords, 2, v) ; x0 = a * xv + b ; y0 = a * yv + d ; fprintf(epsFile, "\n %.3f %.3f () radius drawLabel", x0, y0) ; } } fprintf(epsFile, "\n grestore") ; } else { /* ----------------------------------------- component ids are present, draw the edges between vertices in the same component ----------------------------------------- */ fprintf(epsFile, "\n gsave" "\n %.3f setlinewidth" "\n 0.0 setgray", linewidth1) ; nedge = 0 ; for ( v = 0 ; v < nvtx ; v++ ) { if ( tags[v] >= 0 ) { Graph_adjAndSize(graph, v, &vsize, &vadj) ; xv = Coords_value(coords, 1, v) ; yv = Coords_value(coords, 2, v) ; x0 = a * xv + b ; y0 = a * yv + d ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < v && tags[w] == tags[v] ) { xw = Coords_value(coords, 1, w) ; yw = Coords_value(coords, 2, w) ; x1 = a * xw + b ; y1 = a * yw + d ; if ( nedge % 100 == 0 ) { fprintf(epsFile, "\n newpath") ; } fprintf(epsFile, "\n %.3g %.3g M %.3g %.3g L", x0, y0, x1, y1) ; if ( ++nedge % 100 == 0 ) { fprintf(epsFile, "\n stroke") ; } } } } } if ( nedge % 100 != 0 ) { fprintf(epsFile, "\n stroke") ; } fprintf(epsFile, "\n grestore") ; fprintf(epsFile, "\n gsave" "\n %.3f setlinewidth" "\n 0.0 setgray", linewidth2) ; nedge = 0 ; for ( v = 0 ; v < nvtx ; v++ ) { if ( tags[v] >= 0 ) { Graph_adjAndSize(graph, v, &vsize, &vadj) ; xv = Coords_value(coords, 1, v) ; yv = Coords_value(coords, 2, v) ; x0 = a * xv + b ; y0 = a * yv + d ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( w < v && tags[w] != tags[v] && tags[w] >= 0 ) { xw = Coords_value(coords, 1, w) ; yw = Coords_value(coords, 2, w) ; x1 = a * xw + b ; y1 = a * yw + d ; if ( nedge % 100 == 0 ) { fprintf(epsFile, "\n newpath") ; } fprintf(epsFile, "\n %.3g %.3g M %.3g %.3g L", x0, y0, x1, y1) ; if ( ++nedge % 100 == 0 ) { fprintf(epsFile, "\n stroke") ; } } } } } if ( nedge % 100 != 0 ) { fprintf(epsFile, "\n stroke") ; } fprintf(epsFile, "\n grestore") ; fprintf(epsFile, "\n gsave" "\n 0.1 setlinewidth" "\n 0.0 setgray") ; if ( radius > 0.0 ) { /* ----------------- draw the vertices ----------------- */ for ( v = 0 ; v < nvtx ; v++ ) { if ( tags[v] >= 0 ) { xv = Coords_value(coords, 1, v) ; yv = Coords_value(coords, 2, v) ; x0 = a * xv + b ; y0 = a * yv + d ; fprintf(epsFile, "\n %.3f %.3f (%d) radius drawLabel", x0, y0, tags[v]) ; } } } fprintf(epsFile, "\n grestore") ; } fprintf(epsFile, "\n showpage") ; /* ---------------------------- close the file if not stdout ---------------------------- */ if ( strcmp(epsFileName, "stdout") != 0 ) { fclose(epsFile) ; } return ; } /*--------------------------------------------------------------------*/ exch def" "\n /x exch def" "\n gsmisc/src/fpgrids.c010064400020550007177000000036760653410634500154370ustar00clevecompmath00000400000006/* fpgrids.c */ #include "../misc.h" /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to print a vector on a 2-d grid input -- n1 -- number of points in the first direction n2 -- number of points in the second direction ivec -- integer vector to be printed in %4d format fp -- file pointer created -- 95nov16, cca ----------------------------------------------------- */ void fp2DGrid ( int n1, int n2, int ivec[], FILE *fp ) { int i, j ; if ( n1 <= 0 || n2 <= 0 || ivec == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in fp2DGrid(%d,%d,%p,%p)" "\n bad input\n", n1, n2, ivec, fp) ; exit(-1) ; } for ( j = n2 - 1 ; j >= 0 ; j-- ) { fprintf(fp, "\n") ; for ( i = 0 ; i < n1 ; i++ ) { fprintf(fp, "%4d", ivec[i + j*n1]) ; } } return ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- purpose -- to print a vector on a 3-d grid input -- n1 -- number of points in the first direction n2 -- number of points in the second direction n3 -- number of points in the third direction ivec -- integer vector to be printed in %4d format fp -- file pointer created -- 95nov16, cca ----------------------------------------------------- */ void fp3DGrid ( int n1, int n2, int n3, int ivec[], FILE *fp ) { int k ; if ( n1 <= 0 || n2 <= 0 || n3 <= 0 || ivec == NULL || fp == NULL ) { fprintf(stderr, "\n fatal error in fp3DGrid(%d,%d,%d,%p,%p)" "\n bad input\n", n1, n2, n3, ivec, fp) ; exit(-1) ; } for ( k = 0 ; k < n3 ; k++ ) { fprintf(fp, "\n") ; fp2DGrid(n1, n2, ivec + k*n1*n2, fp) ; } return ; } /*--------------------------------------------------------------------*/ misc/src/localND.c010064400020550007177000000514110653410634500153030ustar00clevecompmath00000400000006/* LocalND.c */ #include "../misc.h" #define MYDEBUG 0 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ compute an old-to-new ordering for local nested dissection in two dimensions n1 -- number of grid points in first direction n2 -- number of grid points in second direction p1 -- number of domains in first direction p2 -- number of domains in second direction dsizes1 -- domain sizes in first direction, size p1 if NULL, then we construct our own dsizes2 -- domain sizes in second direction, size p2 if NULL, then we construct our own oldToNew -- old-to-new permutation vector note : the following must hold n1 > 0, n2 >0, n1 >= 2*p1 - 1, n2 >= 2*p2 - 1, p2 > 1 sum(dsizes1) = n1 - p1 + 1 and sum(dsizes2) = n2 - p2 + 1 created -- 95nov16, cca ------------------------------------------------------------ */ void localND2D ( int n1, int n2, int p1, int p2, int dsizes1[], int dsizes2[], int oldToNew[] ) { int i, idom, ij, isw, j, jdom, jsw, length1, length2, m, m1, m2, msize, now, nvtx ; int *length1s, *length2s, *isws, *jsws, *temp ; /* --------------- check the input --------------- */ if ( n1 <= 0 || n2 <= 0 || 2*p1 - 1 > n1 || 2*p2 - 1 > n2 || oldToNew == NULL ) { fprintf(stderr, "\n fatal error in localND2D(%d,%d,%d,%d,%p,%p,%p)" "\n bad input\n", n1, n2, p1, p2, dsizes1, dsizes2, oldToNew) ; exit(-1) ; } if ( p2 <= 1 ) { fprintf(stderr, "\n fatal error in localND2D(%d,%d,%d,%d,%p,%p,%p)" "\n p2 = %d, must be > 1", n1, n2, p1, p2, dsizes1, dsizes2, oldToNew, p2) ; exit(-1) ; } if ( dsizes1 != NULL && IVsum(p1, dsizes1) != n1 - p1 + 1 ) { fprintf(stderr, "\n fatal error in localND2D(%d,%d,%d,%d,%p,%p,%p)" "\n IVsum(p1, dsizes1) = %d != %d = n1 - p1 + 1 ", n1, n2, p1, p2, dsizes1, dsizes2, oldToNew, IVsum(p1, dsizes1), n1 - p1 + 1) ; return ; } if ( dsizes1 != NULL && IVmin(p1, dsizes1, &i) <= 0 ) { fprintf(stderr, "\n fatal error in localND2D(%d,%d,%d,%d,%p,%p,%p)" "\n IVmin(p1, dsizes1) = %d must be > 0", n1, n2, p1, p2, dsizes1, dsizes2, oldToNew, IVmin(p1, dsizes1, &i)) ; return ; } if ( dsizes2 != NULL && IVsum(p2, dsizes2) != n2 - p2 + 1 ) { fprintf(stderr, "\n fatal error in localND2D(%d,%d,%d,%d,%p,%p,%p)" "\n IVsum(p2, dsizes2) = %d != %d = n2 - p2 + 1 ", n1, n2, p1, p2, dsizes1, dsizes2, oldToNew, IVsum(p2, dsizes2), n2 - p2 + 1) ; return ; } if ( dsizes2 != NULL && IVmin(p2, dsizes2, &i) <= 0 ) { fprintf(stderr, "\n fatal error in localND2D(%d,%d,%d,%d,%p,%p,%p)" "\n IVmin(p2, dsizes2) = %d must be > 0", n1, n2, p1, p2, dsizes1, dsizes2, oldToNew, IVmin(p2, dsizes2, &i)) ; return ; } nvtx = n1*n2 ; /* ---------------------------------- construct the domain sizes vectors ---------------------------------- */ if ( dsizes1 == NULL ) { length1s = IVinit(p1, 0) ; length1 = (n1 - p1 + 1) / p1 ; m1 = (n1 - p1 + 1) % p1 ; for ( i = 0 ; i < m1 ; i++ ) { length1s[i] = length1 + 1 ; } for ( ; i < p1 ; i++ ) { length1s[i] = length1 ; } } else { length1s = dsizes1 ; } if ( dsizes2 == NULL ) { length2s = IVinit(p2, 0) ; length2 = (n2 - p2 + 1) / p2 ; m2 = (n2 - p2 + 1) % p2 ; for ( i = 0 ; i < m2 ; i++ ) { length2s[i] = length2 + 1 ; } for ( ; i < p2 ; i++ ) { length2s[i] = length2 ; } } else { length2s = dsizes2 ; } #if MYDEBUG > 0 fprintf(stdout, "\n inside localND2D") ; fprintf(stdout, "\n n1 = %d, n2 = %d, p1 = %d, p2 = %d", n1, n2, p1, p2) ; fprintf(stdout, "\n length1s[%d] = ", p1) ; IVfp80(stdout, p1, length1s, 12) ; fprintf(stdout, "\n length2s[%d] = ", p2) ; IVfp80(stdout, p2, length2s, 12) ; #endif /* --------------------------------------- determine the first and last domain ids and the array of southwest points --------------------------------------- */ isws = IVinit(p1, -1) ; for ( idom = 0, isw = 0 ; idom < p1 ; idom++ ) { isws[idom] = isw ; isw += length1s[idom] + 1 ; } jsws = IVinit(p2, -1) ; for ( jdom = 0, jsw = 0 ; jdom < p2 ; jdom++ ) { jsws[jdom] = jsw ; jsw += length2s[jdom] + 1 ; } #if MYDEBUG > 1 fprintf(stdout, "\n isws[%d] = ", p1) ; IVfp80(stdout, p1, isws, 12) ; fprintf(stdout, "\n jsws[%d] = ", p2) ; IVfp80(stdout, p2, jsws, 12) ; #endif /* ---------------------------------------------------------------- create a temporary permutation vector for the domains' orderings ---------------------------------------------------------------- */ msize = IVmax(p1, length1s, &i) * IVmax(p2, length2s, &i) ; temp = IVinit(msize, -1) ; /* ------------------------ fill in the domain nodes ------------------------ */ now = 0 ; for ( jdom = 0; jdom < p2 ; jdom++ ) { jsw = jsws[jdom] ; length2 = length2s[jdom] ; for ( idom = 0 ; idom < p1 ; idom++ ) { length1 = length1s[idom] ; isw = isws[idom] ; mkNDperm(length1, length2, 1, temp, 0, length1-1, 0, length2-1, 0, 0) ; for ( m = 0 ; m < length1*length2 ; m++ ) { ij = temp[m] ; i = isw + (ij % length1) ; j = jsw + (ij / length1) ; ij = i + j*n1 ; oldToNew[ij] = now++ ; } } } #if MYDEBUG > 2 fprintf(stdout, "\n old-to-new after domains are numbered") ; fp2DGrid(n1, n2, oldToNew, stdout) ; #endif /* --------------------------------- fill in the lower separator nodes --------------------------------- */ for ( jdom = 0 ; jdom < (p2/2) ; jdom++ ) { jsw = jsws[jdom] ; length2 = length2s[jdom] ; for ( idom = 0 ; idom < p1 ; idom++ ) { isw = isws[idom] ; length1 = length1s[idom] ; if ( isw > 0 ) { i = isw - 1 ; for ( j = jsw ; j <= jsw + length2 - 1 ; j++ ) { ij = i + j*n1 ; oldToNew[ij] = now++ ; } } if ( isw > 0 && jsw > 0 ) { i = isw - 1 ; j = jsw - 1 ; ij = i + j*n1 ; oldToNew[ij] = now++ ; } if ( jsw > 0 ) { j = jsw - 1 ; for ( i = isw ; i <= isw + length1 - 1 ; i++ ) { ij = i + j*n1 ; oldToNew[ij] = now++ ; } } } } #if MYDEBUG > 2 fprintf(stdout, "\n after the lower separators filled in") ; fp2DGrid(n1, n2, oldToNew, stdout) ; #endif /* --------------------------------- fill in the upper separator nodes --------------------------------- */ for ( jdom = p2 - 1 ; jdom >= (p2/2) ; jdom-- ) { jsw = jsws[jdom] ; length2 = length2s[jdom] ; for ( idom = p1 - 1 ; idom >= 0 ; idom-- ) { isw = isws[idom] ; length1 = length1s[idom] ; if ( isw + length1 < n1 ) { i = isw + length1 ; for ( j = jsw ; j <= jsw + length2 - 1 ; j++ ) { ij = i + j*n1 ; oldToNew[ij] = now++ ; } } if ( isw + length1 < n1 && jsw + length2 < n2 ) { i = isw + length1 ; j = jsw + length2 ; ij = i + j*n1 ; oldToNew[ij] = now++ ; } if ( jsw + length2 < n2 ) { j = jsw + length2 ; for ( i = isw ; i <= isw + length1 - 1 ; i++ ) { ij = i + j*n1 ; oldToNew[ij] = now++ ; } } } } #if MYDEBUG > 2 fprintf(stdout, "\n after the upper separators filled in") ; fp2DGrid(n1, n2, oldToNew, stdout) ; #endif /* ------------------------------- fill in the top level separator ------------------------------- */ m1 = p2 / 2 ; for ( jdom = 0, j = 0 ; jdom < m1 ; jdom++ ) { j += length2s[jdom] + 1 ; } j-- ; for ( i = 0 ; i < n1 ; i++ ) { ij = i + j*n1 ; oldToNew[ij] = now++ ; } /* ------------------------ free the working storage ------------------------ */ if ( dsizes1 == NULL ) { IVfree(length1s) ; } if ( dsizes2 == NULL ) { IVfree(length2s) ; } IVfree(isws) ; IVfree(jsws) ; IVfree(temp) ; return ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------ compute an old-to-new ordering for local nested dissection in three dimensions n1 -- number of grid points in first direction n2 -- number of grid points in second direction n3 -- number of grid points in third direction p1 -- number of domains in first direction p2 -- number of domains in second direction p3 -- number of domains in third direction dsizes1 -- domain sizes in first direction, size p1 if NULL, then we construct our own dsizes2 -- domain sizes in second direction, size p2 if NULL, then we construct our own dsizes3 -- domain sizes in third direction, size p3 if NULL, then we construct our own oldToNew -- old-to-new permutation vector note : the following must hold n1 > 0, n2 >0, n3 > 0, n1 >= 2*p1 - 1, n2 >= 2*p2 - 1, n3 >= 2*p3 - 1, p3 > 1 sum(dsizes1) = n1 - p1 + 1, sum(dsizes2) = n2 - p2 + 1 sum(dsizes3) = n3 - p3 + 1 created -- 95nov16, cca ------------------------------------------------------------ */ void localND3D ( int n1, int n2, int n3, int p1, int p2, int p3, int dsizes1[], int dsizes2[], int dsizes3[], int oldToNew[] ) { int i, idom, ijk, isw, j, jdom, jsw, k, kdom, ksw, length1, length2, length3, m, m1, m2, m3, msize, now, nvtx ; int *length1s, *length2s, *length3s, *isws, *jsws, *ksws, *temp ; /* --------------- check the input --------------- */ if ( n1 <= 0 || n2 <= 0 || n3 <= 0 || 2*p1 - 1 > n1 || 2*p2 - 1 > n2 || 2*p3 - 1 > n3 ) { fprintf(stderr, "\n error in input data") ; return ; } if ( p3 <= 1 ) { fprintf(stderr, "\n p3 must be > 1") ; return ; } if ( oldToNew == NULL ) { fprintf(stderr, "\n oldToNew = NULL") ; return ; } if ( dsizes1 != NULL && IVsum(p1, dsizes1) != n1 - p1 + 1 ) { fprintf(stderr, "\n IVsum(p1, dsizes1) != n1 - p1 + 1 ") ; return ; } if ( dsizes2 != NULL && IVsum(p2, dsizes2) != n2 - p2 + 1 ) { fprintf(stderr, "\n IVsum(p2, dsizes2) != n2 - p2 + 1 ") ; return ; } if ( dsizes3 != NULL && IVsum(p3, dsizes3) != n3 - p3 + 1 ) { fprintf(stderr, "\n IVsum(p3, dsizes3) != n3 - p3 + 1 ") ; return ; } if ( dsizes1 != NULL && IVmin(p1, dsizes1, &i) <= 0 ) { fprintf(stderr, "\n IVmin(p1, dsizes1) must be > 0") ; return ; } if ( dsizes2 != NULL && IVmin(p2, dsizes2, &i) <= 0 ) { fprintf(stderr, "\n IVmin(p2, dsizes2) must be > 0") ; return ; } if ( dsizes3 != NULL && IVmin(p3, dsizes3, &i) <= 0 ) { fprintf(stderr, "\n IVmin(p3, dsizes3) must be > 0") ; return ; } nvtx = n1*n2*n3 ; /* ---------------------------------- construct the domain sizes vectors ---------------------------------- */ if ( dsizes1 == NULL ) { length1s = IVinit(p1, 0) ; length1 = (n1 - p1 + 1) / p1 ; m1 = (n1 - p1 + 1) % p1 ; for ( i = 0 ; i < m1 ; i++ ) { length1s[i] = length1 + 1 ; } for ( ; i < p1 ; i++ ) { length1s[i] = length1 ; } } else { length1s = dsizes1 ; } if ( dsizes2 == NULL ) { length2s = IVinit(p2, 0) ; length2 = (n2 - p2 + 1) / p2 ; m2 = (n2 - p2 + 1) % p2 ; for ( i = 0 ; i < m2 ; i++ ) { length2s[i] = length2 + 1 ; } for ( ; i < p2 ; i++ ) { length2s[i] = length2 ; } } else { length2s = dsizes2 ; } if ( dsizes3 == NULL ) { length3s = IVinit(p3, 0) ; length3 = (n3 - p3 + 1) / p3 ; m3 = (n3 - p3 + 1) % p3 ; for ( i = 0 ; i < m3 ; i++ ) { length3s[i] = length3 + 1 ; } for ( ; i < p3 ; i++ ) { length3s[i] = length3 ; } } else { length3s = dsizes3 ; } #if MYDEBUG > 0 fprintf(stdout, "\n inside localND3D") ; fprintf(stdout, "\n n1 = %d, n2 = %d, n3 = %d, p1 = %d, p2 = %dm p3 = %d", n1, n2, n3, p1, p2, p3) ; fprintf(stdout, "\n length1s[%d] = ", p1) ; IVfp80(stdout, p1, length1s, 12) ; fprintf(stdout, "\n length2s[%d] = ", p2) ; IVfp80(stdout, p2, length2s, 12) ; fprintf(stdout, "\n length3s[%d] = ", p3) ; IVfp80(stdout, p3, length3s, 13) ; #endif /* --------------------------------------- determine the first and last domain ids and the array of southwest points --------------------------------------- */ isws = IVinit(p1, -1) ; for ( idom = 0, isw = 0 ; idom < p1 ; idom++ ) { isws[idom] = isw ; isw += length1s[idom] + 1 ; } jsws = IVinit(p2, -1) ; for ( jdom = 0, jsw = 0 ; jdom < p2 ; jdom++ ) { jsws[jdom] = jsw ; jsw += length2s[jdom] + 1 ; } ksws = IVinit(p3, -1) ; for ( kdom = 0, ksw = 0 ; kdom < p3 ; kdom++ ) { ksws[kdom] = ksw ; ksw += length3s[kdom] + 1 ; } #if MYDEBUG > 1 fprintf(stdout, "\n isws[%d] = ", p1) ; IVfp80(stdout, p1, isws, 12) ; fprintf(stdout, "\n jsws[%d] = ", p2) ; IVfp80(stdout, p2, jsws, 12) ; fprintf(stdout, "\n ksws[%d] = ", p3) ; IVfp80(stdout, p3, ksws, 12) ; #endif /* ---------------------------------------------------------------- create a temporary permutation vector for the domains' orderings ---------------------------------------------------------------- */ msize = IVmax(p1, length1s, &i) * IVmax(p2, length2s, &i) * IVmax(p3, length3s, &k) ; temp = IVinit(msize, -1) ; /* ------------------------ fill in the domain nodes ------------------------ */ now = 0 ; for ( kdom = 0 ; kdom < p3 ; kdom++ ) { ksw = ksws[kdom] ; length3 = length3s[kdom] ; for ( jdom = 0 ; jdom < p2 ; jdom++ ) { jsw = jsws[jdom] ; length2 = length2s[jdom] ; for ( idom = 0 ; idom < p1 ; idom++ ) { isw = isws[idom] ; length1 = length1s[idom] ; /* fprintf(stdout, "\n domain (%d,%d,%d), size %d x %d x %d", idom, jdom, kdom, length1, length2, length3) ; fprintf(stdout, "\n (isw, jsw, ksw) = (%d, %d, %d)", isw, jsw, ksw) ; */ mkNDperm(length1, length2, length3, temp, 0, length1-1, 0, length2-1, 0, length3-1) ; for ( m = 0 ; m < length1*length2*length3 ; m++ ) { ijk = temp[m] ; /* fprintf(stdout, "\n m = %d, ijk = %d", m, ijk) ; */ k = ksw + ijk / (length1*length2) ; ijk = ijk % (length1*length2) ; j = jsw + ijk / length1 ; i = isw + ijk % length1 ; /* fprintf(stdout, ", (i, j, k) = (%d, %d, %d)", i, j, k) ; */ ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } } } #if MYDEBUG > 2 fprintf(stdout, "\n old-to-new after domains are numbered") ; fp3DGrid(n1, n2, n3, oldToNew, stdout) ; #endif /* --------------------------------- fill in the lower separator nodes --------------------------------- */ for ( kdom = 0 ; kdom < (p3/2) ; kdom++ ) { ksw = ksws[kdom] ; length3 = length3s[kdom] ; for ( jdom = 0 ; jdom < p2 ; jdom++ ) { jsw = jsws[jdom] ; length2 = length2s[jdom] ; for ( idom = 0 ; idom < p1 ; idom++ ) { isw = isws[idom] ; length1 = length1s[idom] ; /* ------- 3 faces ------- */ if ( isw > 0 ) { i = isw - 1 ; for ( j = jsw ; j <= jsw + length2 - 1 ; j++ ) { for ( k = ksw ; k <= ksw + length3 - 1 ; k++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } } if ( jsw > 0 ) { j = jsw - 1 ; for ( i = isw ; i <= isw + length1 - 1 ; i++ ) { for ( k = ksw ; k <= ksw + length3 - 1 ; k++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } } if ( ksw > 0 ) { k = ksw - 1 ; for ( j = jsw ; j <= jsw + length2 - 1 ; j++ ) { for ( i = isw ; i <= isw + length1 - 1 ; i++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } } /* ----------- three edges ----------- */ if ( isw > 0 && jsw > 0 ) { i = isw - 1 ; j = jsw - 1 ; for ( k = ksw ; k <= ksw + length3 - 1 ; k++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } if ( isw > 0 && ksw > 0 ) { i = isw - 1 ; k = ksw - 1 ; for ( j = jsw ; j <= jsw + length2 - 1 ; j++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } if ( jsw > 0 && ksw > 0 ) { j = jsw - 1 ; k = ksw - 1 ; for ( i = isw ; i <= isw + length1 - 1 ; i++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } /* ---------------- one corner point ---------------- */ if ( isw > 0 && jsw > 0 && ksw > 0 ) { i = isw - 1 ; j = jsw - 1 ; k = ksw - 1 ; ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } } } #if MYDEBUG > 2 fprintf(stdout, "\n after the lower separators filled in") ; fp2DGrid(n1, n2, oldToNew, stdout) ; #endif /* --------------------------------- fill in the upper separator nodes --------------------------------- */ for ( kdom = p3 - 1 ; kdom >= (p3/2) ; kdom-- ) { ksw = ksws[kdom] ; length3 = length3s[kdom] ; for ( jdom = p2 - 1 ; jdom >= 0 ; jdom-- ) { jsw = jsws[jdom] ; length2 = length2s[jdom] ; for ( idom = p1 - 1 ; idom >= 0 ; idom-- ) { isw = isws[idom] ; length1 = length1s[idom] ; /* ------- 3 faces ------- */ if ( isw + length1 < n1 ) { i = isw + length1 ; for ( j = jsw ; j <= jsw + length2 - 1 ; j++ ) { for ( k = ksw ; k <= ksw + length3 - 1 ; k++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } } if ( jsw + length2 < n2 ) { j = jsw + length2 ; for ( i = isw ; i <= isw + length1 - 1 ; i++ ) { for ( k = ksw ; k <= ksw + length3 - 1 ; k++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } } if ( ksw + length3 < n3 ) { k = ksw + length3 ; for ( j = jsw ; j <= jsw + length2 - 1 ; j++ ) { for ( i = isw ; i <= isw + length1 - 1 ; i++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } } /* ----------- three edges ----------- */ if ( isw + length1 < n1 && jsw + length2 < n2 ) { i = isw + length1 ; j = jsw + length2 ; for ( k = ksw ; k <= ksw + length3 - 1 ; k++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } if ( isw + length1 < n1 && ksw + length3 < n3 ) { i = isw + length1 ; k = ksw + length3 ; for ( j = jsw ; j <= jsw + length2 - 1 ; j++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } if ( jsw + length2 < n2 && ksw + length3 < n3 ) { j = jsw + length2 ; k = ksw + length3 ; for ( i = isw ; i <= isw + length1 - 1 ; i++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } /* ---------------- one corner point ---------------- */ if ( isw + length1 < n1 && jsw + length2 < n2 && ksw + length3 < n3 ) { i = isw + length1 ; j = jsw + length2 ; k = ksw + length3 ; ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } } } #if MYDEBUG > 2 fprintf(stdout, "\n after the upper separators filled in") ; fp2DGrid(n1, n2, oldToNew, stdout) ; #endif /* ------------------------------- fill in the top level separator ------------------------------- */ m1 = p3 / 2 ; for ( kdom = 0, k = 0 ; kdom < m1 ; kdom++ ) { k += length3s[kdom] + 1 ; } k-- ; for ( j = 0 ; j < n2 ; j++ ) { for ( i = 0 ; i < n1 ; i++ ) { ijk = i + j*n1 + k*n1*n2 ; oldToNew[ijk] = now++ ; } } /* ------------------------ free the working storage ------------------------ */ if ( dsizes1 == NULL ) { IVfree(length1s) ; } if ( dsizes2 == NULL ) { IVfree(length2s) ; } if ( dsizes3 == NULL ) { IVfree(length3s) ; } IVfree(isws) ; IVfree(jsws) ; IVfree(ksws) ; IVfree(temp) ; return ; } /*--------------------------------------------------------------------*/ rn ; } nvtx = n1*n2*n3 ; /* ---------------------------------- construct the domain sizes vectors ---------------------------------- */ if ( dsizes1 == NULL ) { length1s = IVinit(p1, 0) ; length1 = (n1 - p1 + 1) / p1 ; m1 = (n1 misc/src/mkNDlinsys.c010064400020550007177000000341510665065205100160630ustar00clevecompmath00000400000006/* mkNDlinsys.c */ #include "../../FrontMtx.h" #include "../../Drand.h" #include "../../SymbFac.h" #include "../../timings.h" #include "../../misc.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to create a linear system A*X = B for a nested dissection ordering of a 2-d or 3-d regular grid input -- n1 -- # of nodes in first direction n2 -- # of nodes in second direction n3 -- # of nodes in third direction maxzeros -- relaxation factor for fronts, maximum number of zero entries in a front maxsize -- split parameter for large fronts, maximum number of internal vertices in a front type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX symmetryflag -- symmetry of the matrix SPOOLES_SYMMETRIC, SPOOLES_HERMITIAN or SPOOLES_NONSYMMETRIC nrhs -- number of right hand sides seed -- seed for random number generator msglvl -- message level msgFile -- message file output -- pfrontETree -- to be filled with address of front tree psymbfacIVL -- to be filled with address of symbolic factorization pmtxA -- to be filled with address of matrix object A pmtxX -- to be filled with address of matrix object X pmtxB -- to be filled with address of matrix object B created -- 98may16, cca --------------------------------------------------------------------- */ void mkNDlinsys ( int n1, int n2, int n3, int maxzeros, int maxsize, int type, int symmetryflag, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB ) { DenseMtx *mtxB, *mtxX ; InpMtx *mtxA ; double one[2] = {1.0, 0.0} ; double *dvec ; Drand drand ; double t1, t2 ; ETree *etree, *etree2, *frontETree ; Graph *graph ; int ient, ii, nent, neqns, nrow, v, vsize, w ; int *ivec1, *ivec2, *newToOld, *oldToNew, *rowind, *vadj ; IV *nzerosIV, *oldToNewIV ; IVL *adjIVL, *symbfacIVL ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ Drand_setDefaultFields(&drand) ; Drand_init(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setUniform(&drand, -1.0, 1.0) ; /* -------------------------------- get the grid adjacency structure -------------------------------- */ neqns = n1 * n2 * n3 ; MARKTIME(t1) ; if ( n1 == 1 ) { adjIVL = IVL_make9P(n2, n3, 1) ; } else if ( n2 == 1 ) { adjIVL = IVL_make9P(n1, n3, 1) ; } else if ( n3 == 1 ) { adjIVL = IVL_make9P(n1, n2, 1) ; } else { adjIVL = IVL_make27P(n1, n2, n3, 1) ; } graph = Graph_new() ; Graph_init2(graph, 0, neqns, 0, adjIVL->tsize, neqns, adjIVL->tsize, adjIVL, NULL, NULL) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : create the grid graph", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n grid graph") ; Graph_writeForHumanEye(graph, msgFile) ; } /* --------------------------------------------- make the nested dissection permutation vector --------------------------------------------- */ MARKTIME(t1) ; newToOld = IVinit(neqns, -1) ; oldToNew = IVinit(neqns, -1) ; mkNDperm(n1, n2, n3, newToOld, 0, n1-1, 0, n2-1, 0, n3-1) ; for ( ii = 0 ; ii < neqns ; ii++ ) { oldToNew[newToOld[ii]] = ii ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : make the nested dissection ordering", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n oldToNew") ; IVfprintf(msgFile, neqns, oldToNew) ; } /* ---------------------------------- create the elimination tree object ---------------------------------- */ MARKTIME(t1) ; etree = ETree_new() ; ETree_initFromGraphWithPerms(etree, graph, newToOld, oldToNew) ; IVfree(newToOld) ; IVfree(oldToNew) ; nzerosIV = IV_new() ; IV_init(nzerosIV, neqns, NULL) ; IV_fill(nzerosIV, 0) ; etree2 = ETree_mergeFrontsOne(etree, 0, nzerosIV) ; ETree_free(etree) ; etree = etree2 ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n elimination tree") ; ETree_writeForHumanEye(etree, msgFile) ; } etree2 = ETree_mergeFrontsOne(etree, maxzeros, nzerosIV) ; ETree_free(etree) ; etree = etree2 ; etree2 = ETree_mergeFrontsAll(etree, maxzeros, nzerosIV) ; IV_free(nzerosIV) ; ETree_free(etree) ; etree = etree2 ; frontETree = ETree_splitFronts(etree, NULL, maxsize, 0) ; ETree_free(etree) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front tree") ; ETree_writeForHumanEye(frontETree, msgFile) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : create the front tree", t2 - t1) ; /* -------------------------------------- permute the vertices in the front tree -------------------------------------- */ MARKTIME(t1) ; oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; oldToNew = IV_entries(oldToNewIV) ; ETree_permuteVertices(frontETree, oldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute the front tree", t2 - t1) ; /* ------------------------ set up the InpMtx object ------------------------ */ MARKTIME(t1) ; mtxA = InpMtx_new() ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : case SPOOLES_HERMITIAN : nent = (adjIVL->tsize - neqns)/2 + neqns ; break ; case SPOOLES_NONSYMMETRIC : nent = adjIVL->tsize ; break ; default : fprintf(stderr, "\n fatal error in mkNDlinsys()" "\n invalid symmetryflag %d\n", symmetryflag) ; exit(-1) ; break ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n neqns = %d, nent = %d", neqns, nent) ; } InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, 0) ; ivec1 = InpMtx_ivec1(mtxA) ; ivec2 = InpMtx_ivec2(mtxA) ; dvec = InpMtx_dvec(mtxA) ; if ( type == SPOOLES_REAL ) { Drand_fillDvector(&drand, nent, dvec) ; } else if ( type == SPOOLES_COMPLEX ) { Drand_fillDvector(&drand, 2*nent, dvec) ; } switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : for ( v = 0, ient = 0 ; v < neqns ; v++ ) { IVL_listAndSize(adjIVL, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { if ( vadj[ii] >= v ) { ivec1[ient] = v ; ivec2[ient] = vadj[ii] ; ient++ ; } } } /* ----------------------------- code for a laplacian operator ----------------------------- */ /* if ( n1 == 1 || n2 == 1 || n3 == 1 ) { for ( ii = 0 ; ii < ient ; ii++ ) { if ( ivec1[ii] == ivec2[ii] ) { dvec[ii] = 8.0 ; } else { dvec[ii] = -1.0 ; } } } else { for ( ii = 0 ; ii < ient ; ii++ ) { if ( ivec1[ii] == ivec2[ii] ) { dvec[ii] = 27.0 ; } else { dvec[ii] = -1.0 ; } } } */ break ; case SPOOLES_HERMITIAN : for ( v = 0, ient = 0 ; v < neqns ; v++ ) { IVL_listAndSize(adjIVL, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { if ( (w = vadj[ii]) == v ) { ivec1[ient] = v ; ivec2[ient] = w ; dvec[2*ient+1] = 0.0 ; ient++ ; } else if ( w > v ) { ivec1[ient] = v ; ivec2[ient] = w ; ient++ ; } } } break ; case SPOOLES_NONSYMMETRIC : for ( v = 0, ient = 0 ; v < neqns ; v++ ) { IVL_listAndSize(adjIVL, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++, ient++ ) { ivec1[ient] = v ; ivec2[ient] = vadj[ii] ; } } break ; } InpMtx_setNent(mtxA, nent) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n raw matrix object") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; } InpMtx_sortAndCompress(mtxA) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n original mtxA") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set up the InpMtxA object", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n %% start MATLAB FILE") ; InpMtx_writeForMatlab(mtxA, "A", msgFile) ; if ( symmetryflag == SPOOLES_SYMMETRIC ) { fprintf(msgFile, "\n neqns = %d ; " "\n for ii = 1:neqns " "\n for j = ii+1:neqns " "\n A(j,ii) = A(ii,j) ;" "\n end" "\n end", neqns) ; } else if ( symmetryflag == SPOOLES_HERMITIAN ) { fprintf(msgFile, "\n neqns = %d ; " "\n for ii = 1:neqns " "\n for j = i+1:neqns " "\n A(j,ii) = ctranspose(A(ii,j)) ;" "\n end" "\n end", neqns) ; } fflush(msgFile) ; fprintf(msgFile, "\n %% end MATLAB FILE") ; } /* -------------------------------------------------------- generate the linear system 1. generate solution matrix and fill with random numbers 2. generate rhs matrix and fill with zeros 3. compute matrix-matrix multiply -------------------------------------------------------- */ MARKTIME(t1) ; mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, -1, neqns, nrhs, 1, neqns) ; DenseMtx_fillRandomEntries(mtxX, &drand) ; mtxB = DenseMtx_new() ; DenseMtx_init(mtxB, type, 1, -1, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxB) ; switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_sym_mmm(mtxA, mtxB, one, mtxX) ; break ; case SPOOLES_HERMITIAN : InpMtx_herm_mmm(mtxA, mtxB, one, mtxX) ; break ; case SPOOLES_NONSYMMETRIC : InpMtx_nonsym_mmm(mtxA, mtxB, one, mtxX) ; break ; default : break ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : set up the solution and rhs ", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n original mtxX") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fprintf(msgFile, "\n\n original mtxB") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% start MATLAB FILE") ; DenseMtx_writeForMatlab(mtxX, "X", msgFile) ; DenseMtx_writeForMatlab(mtxB, "B", msgFile) ; fprintf(msgFile, "\n %% end MATLAB FILE") ; fflush(msgFile) ; } /* ------------------------------------------------------ permute the matrix into the nested dissection ordering ------------------------------------------------------ */ MARKTIME(t1) ; InpMtx_permute(mtxA, oldToNew, oldToNew) ; /* ------------------------------------------------ map entries into the upper triangle if necessary ------------------------------------------------ */ switch ( symmetryflag ) { case SPOOLES_SYMMETRIC : InpMtx_mapToUpperTriangle(mtxA) ; break ; case SPOOLES_HERMITIAN : InpMtx_mapToUpperTriangleH(mtxA) ; break ; case SPOOLES_NONSYMMETRIC : break ; default : break ; } InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute the matrix", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted mtxA") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% start MATLAB FILE") ; InpMtx_writeForMatlab(mtxA, "Anew", msgFile) ; if ( symmetryflag == SPOOLES_SYMMETRIC ) { fprintf(msgFile, "\n neqns = %d ; " "\n for ii = 1:neqns " "\n for j = ii+1:neqns " "\n Anew(j,ii) = Anew(ii,j) ;" "\n end" "\n end", neqns) ; } else if ( symmetryflag == SPOOLES_HERMITIAN ) { fprintf(msgFile, "\n neqns = %d ; " "\n for ii = 1:neqns " "\n for j = ii+1:neqns " "\n Anew(j,ii) = ctranspose(Anew(ii,j)) ;" "\n end" "\n end", neqns) ; } fprintf(msgFile, "\n %% end MATLAB FILE") ; } /* ---------------------------------------- permute the solution and right hand side ---------------------------------------- */ MARKTIME(t1) ; DenseMtx_rowIndices(mtxX, &nrow, &rowind) ; IVcopy(nrow, rowind, oldToNew) ; DenseMtx_sort(mtxX) ; DenseMtx_rowIndices(mtxB, &nrow, &rowind) ; IVcopy(nrow, rowind, oldToNew) ; DenseMtx_sort(mtxB) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute the solution and rhs", t2 - t1) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n permuted mtxX") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fprintf(msgFile, "\n\n permuted mtxB") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n %% start MATLAB FILE") ; DenseMtx_writeForMatlab(mtxX, "Xnew", msgFile) ; DenseMtx_writeForMatlab(mtxB, "Bnew", msgFile) ; fprintf(msgFile, "\n %% end MATLAB FILE") ; } /* -------------------------------------------- create the symbolic factorization IVL object -------------------------------------------- */ MARKTIME(t1) ; symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : compute the symbolic factorization", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n symbolic factorization IVL object") ; if ( msglvl == 2 ) { IVL_writeStats(symbfacIVL, msgFile) ; } else { IVL_writeForHumanEye(symbfacIVL, msgFile) ; } fflush(msgFile) ; } /* -------------------------------------- convert the matrix storage to chevrons -------------------------------------- */ MARKTIME(t1) ; InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : convert to chevron vectors ", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n InpMtx object ") ; if ( msglvl == 2 ) { InpMtx_writeStats(mtxA, msgFile) ; } else if ( msglvl > 3 ) { InpMtx_writeForHumanEye(mtxA, msgFile) ; } } /* ----------------------- set the output pointers ----------------------- */ *pfrontETree = frontETree ; *psymbfacIVL = symbfacIVL ; *pmtxA = mtxA ; *pmtxX = mtxX ; *pmtxB = mtxB ; /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; IV_free(oldToNewIV) ; return ; } /*--------------------------------------------------------------------*/ ETree_mergeFrontsOne(etree, 0, nzerosIV) ; ETree_free(etree) ; etree = etree2 ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n elimination tree") ; ETree_writeForHumanEye(etree, msgFile) ; } etree2 = ETree_mergeFrontsOne(etree, maxzeros, nzerosIV) ; ETree_free(etree) ; etree = etree2 ; etree2 = ETree_mergeFrontsAll(etree, maxzeros, nzerosIV) ; IV_free(nzerosIV) ; ETree_free(etree) ; etree = etree2 ; frmisc/src/mkNDlinsysQR.c010064400020550007177000000247570657600665600163540ustar00clevecompmath00000400000006/* mkNDlinsysQR.c */ #include "../../FrontMtx.h" #include "../../EGraph.h" #include "../../SymbFac.h" #include "../../Drand.h" #include "../../misc.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------------- purpose -- to create an overdetermined linear system A*X = B for a nested dissection ordering of a 2-d or 3-d regular grid input -- n1 -- # of nodes in first direction n2 -- # of nodes in second direction n3 -- # of nodes in third direction type -- type of entries SPOOLES_REAL or SPOOLES_COMPLEX nrhs -- number of right hand sides seed -- seed for random number generator msglvl -- message level msgFile -- message file output -- pfrontETree -- to be filled with address of front tree psymbfacIVL -- to be filled with address of symbolic factorization pmtxA -- to be filled with address of matrix object A pmtxX -- to be filled with address of matrix object X pmtxB -- to be filled with address of matrix object B created -- 98may29, cca --------------------------------------------------------------------- */ void mkNDlinsysQR ( int n1, int n2, int n3, int type, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB ) { DenseMtx *mtxB, *mtxX ; double one[2] = {1.0, 0.0} ; Drand drand ; double t1, t2 ; double *entries ; EGraph *egraph ; ETree *etree, *frontETree ; Graph *graph ; InpMtx *mtxA ; int ielem, ii, irow, jrow, mrow, ndim, nelem, nentA, neqns, nfront, nrowA, size ; int *indices, *newToOld, *oldToNew ; IV *nzerosIV, *oldToNewIV ; IVL *adjIVL, *symbfacIVL ; /* -------------------------------------- initialize the random number generator -------------------------------------- */ Drand_setDefaultFields(&drand) ; Drand_init(&drand) ; Drand_setSeed(&drand, seed) ; Drand_setNormal(&drand, 0.0, 1.0) ; /* ----------------------------------------------------- get the grid adjacency structure and set up the graph ----------------------------------------------------- */ neqns = n1*n2*n3 ; MARKTIME(t1) ; if ( (n1 == 1 && n2 == 1) || (n1 == 1 && n3 == 1) || (n1 == 2 && n3 == 1) ) { fprintf(stderr, "\n fatal error in mkNDlinsysQR" "\n n1 = %d, n2 = %d, n3 = %d\n", n1, n2, n3) ; exit(-1) ; } if ( n1 == 1 ) { adjIVL = IVL_make9P(n2, n3, 1) ; ndim = 2 ; } else if ( n2 == 1 ) { adjIVL = IVL_make9P(n1, n3, 1) ; ndim = 2 ; } else if ( n3 == 1 ) { adjIVL = IVL_make9P(n1, n2, 1) ; ndim = 2 ; } else { adjIVL = IVL_make27P(n1, n2, n3, 1) ; ndim = 3 ; } graph = Graph_new() ; Graph_init2(graph, 0, neqns, 0, adjIVL->tsize, neqns, adjIVL->tsize, adjIVL, NULL, NULL) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : create the grid graph", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n grid graph") ; Graph_writeForHumanEye(graph, msgFile) ; } /* --------------------------------------------- make the nested dissection permutation vector --------------------------------------------- */ MARKTIME(t1) ; newToOld = IVinit(neqns, -1) ; oldToNew = IVinit(neqns, -1) ; mkNDperm(n1, n2, n3, newToOld, 0, n1-1, 0, n2-1, 0, n3-1) ; for ( ii = 0 ; ii < neqns ; ii++ ) { oldToNew[newToOld[ii]] = ii ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : make the nested dissection ordering", t2 - t1) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n oldToNew") ; IVfprintf(msgFile, neqns, oldToNew) ; } /* ---------------------------------- create the elimination tree object ---------------------------------- */ MARKTIME(t1) ; etree = ETree_new() ; ETree_initFromGraphWithPerms(etree, graph, newToOld, oldToNew) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n elimination tree") ; ETree_writeForHumanEye(etree, msgFile) ; } nzerosIV = IV_new() ; IV_init(nzerosIV, neqns, NULL) ; IV_fill(nzerosIV, 0) ; frontETree = ETree_mergeFrontsOne(etree, 0, nzerosIV) ; IV_free(nzerosIV) ; IVfree(newToOld) ; IVfree(oldToNew) ; ETree_free(etree) ; nfront = frontETree->nfront ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front tree") ; ETree_writeForHumanEye(frontETree, msgFile) ; } MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : create the front tree", t2 - t1) ; /* -------------------------------------------- create the symbolic factorization IVL object -------------------------------------------- */ MARKTIME(t1) ; symbfacIVL = SymbFac_initFromGraph(frontETree, graph) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : compute the symbolic factorization", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n symbolic factorization IVL object in original ordering") ; if ( msglvl == 2 ) { IVL_writeStats(symbfacIVL, msgFile) ; } else { IVL_writeForHumanEye(symbfacIVL, msgFile) ; } fflush(msgFile) ; } /* -------------------------------------- permute the vertices in the front tree -------------------------------------- */ MARKTIME(t1) ; oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; oldToNew = IV_entries(oldToNewIV) ; ETree_permuteVertices(frontETree, oldToNewIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute the front tree", t2 - t1) ; /* ------------------------------------------------------ convert the symbolic factorization to the new ordering ------------------------------------------------------ */ IVL_overwrite(symbfacIVL, oldToNewIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n overwritten symbolic factorization IVL object ") ; if ( msglvl == 2 ) { IVL_writeStats(symbfacIVL, msgFile) ; } else { IVL_writeForHumanEye(symbfacIVL, msgFile) ; } fflush(msgFile) ; } IVL_sortUp(symbfacIVL) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n sorted symbolic factorization IVL object ") ; if ( msglvl == 2 ) { IVL_writeStats(symbfacIVL, msgFile) ; } else { IVL_writeForHumanEye(symbfacIVL, msgFile) ; } fflush(msgFile) ; } /* -------------------------------- create the natural factor matrix -------------------------------- */ MARKTIME(t1) ; if ( ndim == 2 ) { if ( n1 == 1 ) { egraph = EGraph_make9P(n2, n3, 1) ; nelem = (n2-1)*(n3-1) ; } else if ( n2 == 1 ) { egraph = EGraph_make9P(n1, n3, 1) ; nelem = (n1-1)*(n3-1) ; } else if ( n3 == 1 ) { egraph = EGraph_make9P(n1, n2, 1) ; nelem = (n1-1)*(n2-1) ; } mrow = 4 ; } else { egraph = EGraph_make27P(n1, n2, n3, 1) ; mrow = 8 ; nelem = (n1-1)*(n2-1)*(n3-1) ; } nrowA = mrow*nelem ; if ( type == SPOOLES_REAL ) { entries = DVinit(mrow, 0.0) ; } else if ( type == SPOOLES_COMPLEX ) { entries = DVinit(2*mrow, 0.0) ; } nentA = mrow*nrowA ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : create egraph ", t2 - t1) ; if ( msglvl > 2 ) { EGraph_writeForHumanEye(egraph, msgFile) ; fflush(msgFile) ; } MARKTIME(t1) ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nentA, nrowA) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : initialize the InpMtx object", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n InpMtx after initialization") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; } for ( ielem = 0, jrow = 0 ; ielem < nelem ; ielem++ ) { IVL_listAndSize(egraph->adjIVL, ielem, &size, &indices) ; for ( irow = 0 ; irow < mrow ; irow++, jrow++ ) { if ( type == SPOOLES_REAL ) { Drand_fillDvector(&drand, size, entries) ; InpMtx_inputRealRow(mtxA, jrow, size, indices, entries) ; } else if ( type == SPOOLES_COMPLEX ) { Drand_fillDvector(&drand, 2*size, entries) ; InpMtx_inputComplexRow(mtxA, jrow, size, indices, entries) ; } } } DVfree(entries) ; EGraph_free(egraph) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n natural factor matrix") ; if ( msglvl == 2 ) { InpMtx_writeStats(mtxA, msgFile) ; } else { InpMtx_writeForHumanEye(mtxA, msgFile) ; } fflush(msgFile) ; } /* ------------------------------------------------------------- permute the InpMtx object into the nested dissection ordering ------------------------------------------------------------- */ MARKTIME(t1) ; InpMtx_permute(mtxA, NULL, IV_entries(oldToNewIV)) ; InpMtx_changeCoordType(mtxA, INPMTX_BY_ROWS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : permute inpmtx ", t2 - t1) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n after permute InpMtx object ") ; if ( msglvl == 2 ) { InpMtx_writeStats(mtxA, msgFile) ; } else { InpMtx_writeForHumanEye(mtxA, msgFile) ; } } if ( msglvl > 5 ) { fprintf(msgFile, "\n A = zeros(%d,%d) ;", nrowA, neqns) ; InpMtx_writeForMatlab(mtxA, "A", msgFile) ; } /* -------------------------------------------------------- generate the linear system 1. generate solution matrix and fill with random numbers 2. generate rhs matrix and fill with zeros 3. compute matrix-matrix multiply -------------------------------------------------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, -1, neqns, nrhs, 1, neqns) ; DenseMtx_fillRandomEntries(mtxX, &drand) ; mtxB = DenseMtx_new() ; DenseMtx_init(mtxB, type, 1, -1, nrowA, nrhs, 1, nrowA) ; DenseMtx_zero(mtxB) ; InpMtx_nonsym_mmm(mtxA, mtxB, one, mtxX) ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n mtxX") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fprintf(msgFile, "\n\n mtxB") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } if ( msglvl > 5 ) { fprintf(msgFile, "\n X = zeros(%d,%d) ;", mtxX->nrow, mtxX->ncol) ; DenseMtx_writeForMatlab(mtxX, "X", msgFile) ; fprintf(msgFile, "\n B = zeros(%d,%d) ;", mtxB->nrow, mtxB->ncol) ; DenseMtx_writeForMatlab(mtxB, "B", msgFile) ; } /* ----------------------- set the output pointers ----------------------- */ *pfrontETree = frontETree ; *psymbfacIVL = symbfacIVL ; *pmtxA = mtxA ; *pmtxX = mtxX ; *pmtxB = mtxB ; /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; IV_free(oldToNewIV) ; return ; } /*--------------------------------------------------------------------*/ RKTIME(t1) ; if (misc/src/orderViaBestOfNDandMS.c010064400020550007177000000243720660103005200200020ustar00clevecompmath00000400000006/* orderViaBestOfNDandMS.c */ #include "../misc.h" #include "../../timings.h" /* --------------------------------------------------------------------- COMPRESS_FRACTION --- if # coarse graph vertices < COMPRESS_FRACTION * # of vertices then use the compressed graph endif --------------------------------------------------------------------- */ #define COMPRESS_FRACTION 0.75 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- return an ETree object for the better of a nested dissection and multisection orderings graph -- graph to order maxdomainsize -- used to control the incomplete nested dissection process. any subgraph whose weight is less than maxdomainsize is not split further. maxzeros -- maximum number of zero entries allowed in a front maxsize -- maximum number of internal columns in a front seed -- random number seed msglvl -- message level 1 -- timings and statistics 2 -- more timings and statistics 3 -- lots of output msgFile -- message file created -- 98aug26, cca ------------------------------------------------------------------ */ ETree * orderViaBestOfNDandMS ( Graph *graph, int maxdomainsize, int maxzeros, int maxsize, int seed, int msglvl, FILE *msgFile ) { double compressCPU, dstreeCPU, eqmapCPU, miscCPU, msCPU, msnzf, msops, ndCPU, ndops, ndnzf, nzf, ops, totalCPU, transformCPU, t0, t1, t2, t3 ; DSTree *dstree ; ETree *etree, *etree2, *etreeMS, *etreeND ; int nfront, msnfront, msnind, ndnfront, ndnind, nind, nvtx, Nvtx ; IV *eqmapIV, *stagesIV ; /* --------------- check the input --------------- */ if ( graph == NULL ) { fprintf(stderr, "\n fatal error in orderViaBestOfNDandMS()" "\n graph is NULL\n") ; exit(-1) ; } if ( maxdomainsize <= 0 ) { fprintf(stderr, "\n fatal error in orderViaBestOfNDandMS()" "\n maxdomainsize %d\n", maxdomainsize) ; exit(-1) ; } if ( maxzeros < 0 ) { fprintf(stderr, "\n fatal error in orderViaBestOfNDandMS()" "\n maxzeros %d\n", maxzeros) ; exit(-1) ; } if ( maxsize <= 0 ) { fprintf(stderr, "\n fatal error in orderViaBestOfNDandMS()" "\n maxsize %d\n", maxsize) ; exit(-1) ; } if ( (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in orderViaBestOfNDandMS()" "\n msglvl %d, msgFile %p\n", msglvl, msgFile) ; exit(-1) ; } MARKTIME(t0) ; /* ------------------------------ compress the graph if worth it ------------------------------ */ nvtx = graph->nvtx ; MARKTIME(t1) ; eqmapIV = Graph_equivMap(graph) ; MARKTIME(t2) ; eqmapCPU = t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : get equivalence map", t2 - t1) ; fflush(msgFile) ; } Nvtx = 1 + IV_max(eqmapIV) ; if ( Nvtx <= COMPRESS_FRACTION * nvtx ) { MARKTIME(t1) ; graph = Graph_compress2(graph, eqmapIV, 1) ; MARKTIME(t2) ; compressCPU = t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : compress graph", t2 - t1) ; fflush(msgFile) ; } } else { compressCPU = 0.0 ; IV_free(eqmapIV) ; eqmapIV = NULL ; } MARKTIME(t1) ; IVL_sortUp(graph->adjIVL) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : sort adjacency", t2 - t1) ; fflush(msgFile) ; } /* ----------------------------- get the domain separator tree ----------------------------- */ MARKTIME(t1) ; { GPart *gpart ; DDsepInfo *info ; info = DDsepInfo_new() ; info->seed = seed ; info->maxcompweight = maxdomainsize ; info->alpha = 0.1 ; gpart = GPart_new() ; GPart_init(gpart, graph) ; GPart_setMessageInfo(gpart, msglvl, msgFile) ; dstree = GPart_RBviaDDsep(gpart, info) ; DSTree_renumberViaPostOT(dstree) ; if ( msglvl > 1 ) { DDsepInfo_writeCpuTimes(info, msgFile) ; } DDsepInfo_free(info) ; GPart_free(gpart) ; } MARKTIME(t2) ; dstreeCPU = t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : construct domain/separator tree", t2 - t1) ; fflush(msgFile) ; } /* ------------------------------------------- get the stages vector for nested dissection ------------------------------------------- */ MARKTIME(t1) ; stagesIV = DSTree_NDstages(dstree) ; MARKTIME(t2) ; ndCPU = t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : get stages for ND", t2 - t1) ; fflush(msgFile) ; } /* --------------------------------------------- order the vertices and extract the front tree --------------------------------------------- */ MARKTIME(t2) ; { MSMDinfo *info ; MSMD *msmd ; MARKTIME(t1) ; info = MSMDinfo_new() ; info->seed = seed ; info->compressFlag = 2 ; info->msglvl = msglvl ; info->msgFile = msgFile ; msmd = MSMD_new() ; MSMD_order(msmd, graph, IV_entries(stagesIV), info) ; etreeND = MSMD_frontETree(msmd) ; MARKTIME(t2) ; ndCPU += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : get tree for ND", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 1 ) { fprintf(msgFile, "\n\n Nested Dissection information") ; MSMDinfo_print(info, msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Nested Dissection tree") ; ETree_writeForHumanEye(etreeND, msgFile) ; } MARKTIME(t1) ; MSMDinfo_free(info) ; MSMD_free(msmd) ; IV_free(stagesIV) ; MARKTIME(t2) ; ndCPU += t2 - t1 ; } /* -------------------------------------- get the stages vector for multisection -------------------------------------- */ MARKTIME(t1) ; stagesIV = DSTree_MS2stages(dstree) ; MARKTIME(t2) ; msCPU = t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : get stages for MS", t2 - t1) ; fflush(msgFile) ; } /* --------------------------------------------- order the vertices and extract the front tree --------------------------------------------- */ { MSMDinfo *info ; MSMD *msmd ; MARKTIME(t1) ; info = MSMDinfo_new() ; info->seed = seed ; info->compressFlag = 2 ; info->msglvl = msglvl ; info->msgFile = msgFile ; msmd = MSMD_new() ; MSMD_order(msmd, graph, IV_entries(stagesIV), info) ; etreeMS = MSMD_frontETree(msmd) ; MARKTIME(t2) ; msCPU += t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : get tree for ND", t2 - t1) ; fflush(msgFile) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n Multisection information") ; MSMDinfo_print(info, msgFile) ; } if ( msglvl > 3 ) { fprintf(msgFile, "\n\n Multisection tree") ; ETree_writeForHumanEye(etreeMS, msgFile) ; } MARKTIME(t1) ; MSMDinfo_free(info) ; MSMD_free(msmd) ; IV_free(stagesIV) ; MARKTIME(t2) ; msCPU += t2 - t1 ; } /* -------------------------------------- keep the better of the two front trees -------------------------------------- */ ndnfront = ETree_nfront(etreeND) ; msnfront = ETree_nfront(etreeMS) ; ndnind = ETree_nFactorIndices(etreeND) ; msnind = ETree_nFactorIndices(etreeMS) ; ndnzf = ETree_nFactorEntries(etreeND, SPOOLES_SYMMETRIC) ; msnzf = ETree_nFactorEntries(etreeMS, SPOOLES_SYMMETRIC) ; ndops = ETree_nFactorOps(etreeND, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; msops = ETree_nFactorOps(etreeMS, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; if ( ndops <= msops ) { etree = etreeND ; ETree_free(etreeMS) ; } else { etree = etreeMS ; ETree_free(etreeND) ; } /* ------------------------ transform the front tree ------------------------ */ MARKTIME(t1) ; etree = ETree_transform(etree, graph->vwghts, maxzeros, maxsize, seed); MARKTIME(t2) ; transformCPU = t2 - t1 ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : transform tree", t2 - t1) ; fflush(msgFile) ; } nfront = ETree_nfront(etree) ; nind = ETree_nFactorIndices(etree) ; nzf = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; ops = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n real symmetric : final ops %.0f", ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; fflush(msgFile) ; } /* ------------------------------------------------- expand the front tree if the graph was compressed ------------------------------------------------- */ if ( eqmapIV != NULL ) { etree2 = ETree_expand(etree, eqmapIV) ; ETree_free(etree) ; etree = etree2 ; Graph_free(graph) ; IV_free(eqmapIV) ; } else { IVL_sortUp(graph->adjIVL) ; } DSTree_free(dstree) ; MARKTIME(t3) ; /* ------------------------ print out the statistics ------------------------ */ if ( msglvl >= 1 ) { fprintf(msgFile, "\n\n----------------------------------------" "\n\n Order the graph via best of ND and MS") ; fprintf(msgFile, "\n\n # fronts # indices # entries # ops" "\n nested dissection %7d %10d %12.0f %12.0f" "\n multisection %7d %10d %12.0f %12.0f" "\n final ordering %7d %10d %12.0f %12.0f", ndnfront, ndnind, ndnzf, ndops, msnfront, msnind, msnzf, msops, nfront, nind, nzf, ops) ; totalCPU = t3 - t0 ; miscCPU = totalCPU - (eqmapCPU + compressCPU + dstreeCPU + ndCPU + msCPU + transformCPU) ; if ( totalCPU > 0.0 ) { fprintf(msgFile, "\n\n CPU breakdown CPU %%" "\n make equivalence map %8.3f %6.2f" "\n compress graph %8.3f %6.2f" "\n construct domain/separator tree %8.3f %6.2f" "\n evaluate nested dissection %8.3f %6.2f" "\n evaluate multisection %8.3f %6.2f" "\n transform final tree %8.3f %6.2f" "\n miscellaneous time %8.3f %6.2f" "\n total time %8.3f", eqmapCPU, 100.*eqmapCPU/totalCPU, compressCPU, 100.*compressCPU/totalCPU, dstreeCPU, 100.*dstreeCPU/totalCPU, ndCPU, 100.*ndCPU/totalCPU, msCPU, 100.*msCPU/totalCPU, transformCPU, 100.*transformCPU/totalCPU, miscCPU, 100.*miscCPU/totalCPU, totalCPU) ; } fprintf(msgFile, "\n\n----------------------------------------") ; } return(etree) ; } /*--------------------------------------------------------------------*/ eqmapIV = NULL ; } MARKTIME(t1) ; IVL_sortUp(graph->adjIVL) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : sort adjacency", t2 - t1) ; fflush(msgFile) ; } /* ----------------------------- get the domain separator tree ----misc/src/orderViaMMD.c010064400020550007177000000062760660026121600161020ustar00clevecompmath00000400000006/* orderViaMMD.c */ #include "../misc.h" #include "../../timings.h" /* --------------------------------------------------------------------- COMPRESS_FRACTION --- if # coarse graph vertices < COMPRESS_FRACTION * # of vertices then use the compressed graph endif --------------------------------------------------------------------- */ #define COMPRESS_FRACTION 0.75 /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- purpose -- return an ETree object for a multiple minimum degree ordering graph -- graph to order seed -- random number seed msglvl -- message level, 0 --> no output, 1 --> timings msgFile -- message file created -- 97nov08, cca -------------------------------------------------------- */ ETree * orderViaMMD ( Graph *graph, int seed, int msglvl, FILE *msgFile ) { double t1, t2 ; ETree *etree ; int nvtx, Nvtx ; IV *eqmapIV ; /* --------------- check the input --------------- */ if ( graph == NULL || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in orderViaMMD(%p,%d,%d,%p)" "\n bad input\n", graph, seed, msglvl, msgFile) ; exit(-1) ; } /* ------------------------------ compress the graph if worth it ------------------------------ */ nvtx = graph->nvtx ; MARKTIME(t1) ; eqmapIV = Graph_equivMap(graph) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : get equivalence map", t2 - t1) ; fflush(msgFile) ; } Nvtx = 1 + IV_max(eqmapIV) ; if ( Nvtx <= COMPRESS_FRACTION * nvtx ) { MARKTIME(t1) ; graph = Graph_compress2(graph, eqmapIV, 1) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : compress graph", t2 - t1) ; fflush(msgFile) ; } } else { IV_free(eqmapIV) ; eqmapIV = NULL ; } MARKTIME(t1) ; IVL_sortUp(graph->adjIVL) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : sort adjacency", t2 - t1) ; fflush(msgFile) ; } /* --------------------------------------------- order the vertices and extract the front tree --------------------------------------------- */ { MSMDinfo *info ; MSMD *msmd ; info = MSMDinfo_new() ; info->seed = seed ; info->compressFlag = 2 ; info->msglvl = msglvl ; info->msgFile = msgFile ; msmd = MSMD_new() ; MSMD_order(msmd, graph, NULL, info) ; etree = MSMD_frontETree(msmd) ; if ( msglvl > 1 ) { MSMDinfo_print(info, msgFile) ; } MSMDinfo_free(info) ; MSMD_free(msmd) ; } /* ------------------------------------------------- expand the front tree if the graph was compressed ------------------------------------------------- */ if ( eqmapIV != NULL ) { ETree *etree2 = ETree_expand(etree, eqmapIV) ; ETree_free(etree) ; etree = etree2 ; Graph_free(graph) ; IV_free(eqmapIV) ; } else { MARKTIME(t1) ; IVL_sortUp(graph->adjIVL) ; MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : sort adjacency", t2 - t1) ; fflush(msgFile) ; } } return(etree) ; } /*--------------------------------------------------------------------*/ misc/src/orderViaMS.c010064400020550007177000000101640653410634600160030ustar00clevecompmath00000400000006/* orderViaMS.c */ #include "../misc.h" #include "../../timings.h" /* --------------------------------------------------------------------- COMPRESS_FRACTION --- if # coarse graph vertices < COMPRESS_FRACTION * # of vertices then use the compressed graph endif --------------------------------------------------------------------- */ #define COMPRESS_FRACTION 0.75 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- return an ETree object for a multisection ordering graph -- graph to order maxdomainsize -- used to control the incomplete nested dissection process. any subgraph whose weight is less than maxdomainsize is not split further. seed -- random number seed msglvl -- message level, 0 --> no output, 1 --> timings msgFile -- message file created -- 97nov06, cca ------------------------------------------------------------------ */ ETree * orderViaMS ( Graph *graph, int maxdomainsize, int seed, int msglvl, FILE *msgFile ) { double t1, t2 ; DSTree *dstree ; ETree *etree ; int nvtx, Nvtx ; IV *eqmapIV, *stagesIV ; /* --------------- check the input --------------- */ if ( graph == NULL || maxdomainsize <= 0 || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in orderViaMS(%p,%d,%d,%d,%p)" "\n bad input\n", graph, maxdomainsize, seed, msglvl, msgFile) ; exit(-1) ; } /* ------------------------------ compress the graph if worth it ------------------------------ */ nvtx = graph->nvtx ; MARKTIME(t1) ; eqmapIV = Graph_equivMap(graph) ; MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n CPU %8.3f : get equivalence map", t2 - t1) ; fflush(msgFile) ; } Nvtx = 1 + IV_max(eqmapIV) ; if ( Nvtx <= COMPRESS_FRACTION * nvtx ) { MARKTIME(t1) ; graph = Graph_compress2(graph, eqmapIV, 1) ; MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n CPU %8.3f : compress graph", t2 - t1) ; fflush(msgFile) ; } } else { IV_free(eqmapIV) ; eqmapIV = NULL ; } MARKTIME(t1) ; IVL_sortUp(graph->adjIVL) ; MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n CPU %8.3f : sort adjacency", t2 - t1) ; fflush(msgFile) ; } /* ----------------------------- get the domain separator tree ----------------------------- */ { GPart *gpart ; DDsepInfo *info ; info = DDsepInfo_new() ; info->seed = seed ; info->maxcompweight = maxdomainsize ; gpart = GPart_new() ; GPart_init(gpart, graph) ; GPart_setMessageInfo(gpart, msglvl, msgFile) ; dstree = GPart_RBviaDDsep(gpart, info) ; DSTree_renumberViaPostOT(dstree) ; if ( msglvl > 0 ) { DDsepInfo_writeCpuTimes(info, msgFile) ; } DDsepInfo_free(info) ; GPart_free(gpart) ; } /* --------------------- get the stages vector --------------------- */ stagesIV = DSTree_MS2stages(dstree) ; DSTree_free(dstree) ; /* --------------------------------------------- order the vertices and extract the front tree --------------------------------------------- */ { MSMDinfo *info ; MSMD *msmd ; info = MSMDinfo_new() ; info->seed = seed ; info->compressFlag = 2 ; info->msglvl = msglvl ; info->msgFile = msgFile ; msmd = MSMD_new() ; MSMD_order(msmd, graph, IV_entries(stagesIV), info) ; etree = MSMD_frontETree(msmd) ; if ( msglvl > 0 ) { MSMDinfo_print(info, msgFile) ; } MSMDinfo_free(info) ; MSMD_free(msmd) ; IV_free(stagesIV) ; } /* ------------------------------------------------- expand the front tree if the graph was compressed ------------------------------------------------- */ if ( eqmapIV != NULL ) { ETree *etree2 = ETree_expand(etree, eqmapIV) ; ETree_free(etree) ; etree = etree2 ; Graph_free(graph) ; IV_free(eqmapIV) ; } else { MARKTIME(t1) ; IVL_sortUp(graph->adjIVL) ; MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n CPU %8.3f : sort adjacency", t2 - t1) ; fflush(msgFile) ; } } return(etree) ; } /*--------------------------------------------------------------------*/ misc/src/orderViaND.c010064400020550007177000000102250653410634600157630ustar00clevecompmath00000400000006/* orderViaND.c */ #include "../misc.h" #include "../../timings.h" /* --------------------------------------------------------------------- COMPRESS_FRACTION --- if # coarse graph vertices < COMPRESS_FRACTION * # of vertices then use the compressed graph endif --------------------------------------------------------------------- */ #define COMPRESS_FRACTION 0.75 /*--------------------------------------------------------------------*/ /* ------------------------------------------------------------------ purpose -- return an ETree object for a nested dissection ordering graph -- graph to order maxdomainsize -- used to control the incomplete nested dissection process. any subgraph whose weight is less than maxdomainsize is not split further. seed -- random number seed msglvl -- message level, 0 --> no output, 1 --> timings msgFile -- message file created -- 97nov06, cca ------------------------------------------------------------------ */ ETree * orderViaND ( Graph *graph, int maxdomainsize, int seed, int msglvl, FILE *msgFile ) { double t1, t2 ; DSTree *dstree ; ETree *etree ; int nvtx, Nvtx ; IV *eqmapIV, *stagesIV ; /* --------------- check the input --------------- */ if ( graph == NULL || maxdomainsize <= 0 || (msglvl > 0 && msgFile == NULL) ) { fprintf(stderr, "\n fatal error in orderViaND(%p,%d,%d,%d,%p)" "\n bad input\n", graph, maxdomainsize, seed, msglvl, msgFile) ; exit(-1) ; } /* ------------------------------ compress the graph if worth it ------------------------------ */ nvtx = graph->nvtx ; MARKTIME(t1) ; eqmapIV = Graph_equivMap(graph) ; MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n CPU %8.3f : get equivalence map", t2 - t1) ; fflush(msgFile) ; } Nvtx = 1 + IV_max(eqmapIV) ; if ( Nvtx <= COMPRESS_FRACTION * nvtx ) { MARKTIME(t1) ; graph = Graph_compress2(graph, eqmapIV, 1) ; MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n CPU %8.3f : compress graph", t2 - t1) ; fflush(msgFile) ; } } else { IV_free(eqmapIV) ; eqmapIV = NULL ; } MARKTIME(t1) ; IVL_sortUp(graph->adjIVL) ; MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n CPU %8.3f : sort adjacency", t2 - t1) ; fflush(msgFile) ; } /* ----------------------------- get the domain separator tree ----------------------------- */ { GPart *gpart ; DDsepInfo *info ; info = DDsepInfo_new() ; info->seed = seed ; info->maxcompweight = maxdomainsize ; info->alpha = 0.1 ; gpart = GPart_new() ; GPart_init(gpart, graph) ; GPart_setMessageInfo(gpart, msglvl, msgFile) ; dstree = GPart_RBviaDDsep(gpart, info) ; DSTree_renumberViaPostOT(dstree) ; if ( msglvl > 0 ) { DDsepInfo_writeCpuTimes(info, msgFile) ; } DDsepInfo_free(info) ; GPart_free(gpart) ; } /* --------------------- get the stages vector --------------------- */ stagesIV = DSTree_NDstages(dstree) ; DSTree_free(dstree) ; /* --------------------------------------------- order the vertices and extract the front tree --------------------------------------------- */ { MSMDinfo *info ; MSMD *msmd ; info = MSMDinfo_new() ; info->seed = seed ; info->compressFlag = 2 ; info->msglvl = msglvl ; info->msgFile = msgFile ; msmd = MSMD_new() ; MSMD_order(msmd, graph, IV_entries(stagesIV), info) ; etree = MSMD_frontETree(msmd) ; if ( msglvl > 0 ) { MSMDinfo_print(info, msgFile) ; } MSMDinfo_free(info) ; MSMD_free(msmd) ; IV_free(stagesIV) ; } /* ------------------------------------------------- expand the front tree if the graph was compressed ------------------------------------------------- */ if ( eqmapIV != NULL ) { ETree *etree2 = ETree_expand(etree, eqmapIV) ; ETree_free(etree) ; etree = etree2 ; Graph_free(graph) ; IV_free(eqmapIV) ; } else { MARKTIME(t1) ; IVL_sortUp(graph->adjIVL) ; MARKTIME(t2) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n CPU %8.3f : sort adjacency", t2 - t1) ; fflush(msgFile) ; } } return(etree) ; } /*--------------------------------------------------------------------*/ misc/drivers/do_QRallInOne010075500020550007177000000004610664673476000171010ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout # type -- type of entries # 1 -- real entries # 2 -- complex entries set type = 1 set matrixFileName = qr.matrix.input set rhsFileName = qr.rhs.input set seed = 10101 QRallInOne $msglvl $msgFile $type $matrixFileName $rhsFileName $seed misc/drivers/do_allInOne010075500020550007177000000020370665164505300166270ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout # type -- type of entries # 1 -- real entries # 2 -- complex entries set type = 2 # symmetryflag -- type of symmetry in the matrix # 0 -- symmetric # 1 -- hermitian # 2 -- nonsymmetric set symmetryflag = 0 # pivotingflag -- type of pivoting in the factorization # 0 -- no pivoting # 1 -- pivoting set pivotingflag = 0 set matrixFileName = complex.sym.mtx.input set matrixFileName = complex.herm.mtx.input set matrixFileName = complex.nonsym.mtx.input set matrixFileName = matrix.input set matrixFileName = haggar.matrix.input set rhsFileName = complex.herm.rhs.input set rhsFileName = complex.nonsym.rhs.input set rhsFileName = rhs.input set rhsFileName = haggar.rhs.input set msgFile = complex.sym.sol.output set msgFile = complex.herm.sol.output set msgFile = complex.nonsym.sol.output set msgFile = real.sym.sol.output set msgFile = haggar.output set seed = 10101 allInOne $msglvl $msgFile $type $symmetryflag $pivotingflag \ $matrixFileName $rhsFileName $seed = 1 set msgFile = stdout # type -- type of entries # 1 -- real entries # 2 -- complex entries set type = 2 # symmetryflag -- type of symmetry in the matrix # 0 -- symmetric # 1 -- hermitian # 2 -- nonsymmetric set symmetryflag = 0 # pivotingflag -- type of pivoting in the factorization # 0 -- no pivoting # 1 -- pivoting set pivotingflag = 0 set matrixFileName = complex.sym.mtx.input set matrixFileName = complex.herm.mtx.input set matrixFileName = complex.nmisc/drivers/do_draw010075500020550007177000000022510663207500100160460ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../../matrices set matrices = ../../Matrices set matrix = R2D100 set inGraphFile = $matrices/$matrix/orig.graphb set inGraphFile = $matrices/$matrix/orig0.graphf set msglvl = 1 set msgFile = stdout set inCoordsFile = temp1.coordsf set inCoordsFile = $matrices/$matrix/grid.coordsf set inTagsFile = $matrices/$matrix/fishnet.ivf set outEPSfile = R2D100fishnet.eps set inTagsFile = none set outEPSfile = R2D100notags.eps set inTagsFile = $matrices/$matrix/unit.ivf set inTagsFile = none set inTagsFile = $matrices/$matrix/ndOldToNew.ivf set outEPSfile = temp1.eps set outEPSfile = R2D100perm.eps set linewidth1 = 1 set linewidth1 = 3 set linewidth1 = .1 set linewidth2 = .1 set bbox = ' 0 0 400 400 ' set rect = ' 10 10 380 380 ' set bbox = ' 0 0 600 600 ' set rect = ' 20 20 580 580 ' set bbox = ' 0 0 600 600 ' set rect = ' 50 50 500 500 ' set bbox = ' 0 0 300 300 ' set rect = ' 10 10 280 280 ' set radius = 4 set radius = 7 set radius = 2.5 set radius = 5 drawGraph $msglvl $msgFile $inGraphFile $inCoordsFile $inTagsFile \ $outEPSfile $linewidth1 $linewidth2 $bbox $rect $radius misc/drivers/do_orderViaBestOfNDandMS010075500020550007177000000024170664515233100211460ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrix = R2D10000 set inGraphFile = $matrices/$matrix/orig0.graphf set matrices = ../../../matrices set matrix = GRD7x7 set matrix = BCSSTK17 set matrix = R10KV set matrix = R3D13824 set matrix = TRI10 set matrix = BCSSTK24 set matrix = BCSSTK30 set matrix = MN12 set inGraphFile = ../../InpMtx/drivers/temp.graphf set inGraphFile = /local1/ARPA/matrices/i4a/orig1.graphb set inGraphFile = $matrices/$matrix/orig0.graphb set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig1.graphb set msglvl = 1 set msgFile = res.MS.$matrix set msgFile = res.i4a set msgFile = stdout set outETreeFile = ms.etreef set outETreeFile = none set outETreeFile = $matrices/$matrix/best0.etreef set maxzeros = 0 set maxzeros = 1000 set maxsize = 1000000 set maxsize = 64 set maxdomainsize = 1 set maxdomainsize = 500 set maxdomainsize = 1 set maxdomainsize = 100 set seed = 10101 set seed = 101012 set nseed = 1 while ( $nseed > 0 ) testOrderViaBestOfNDandMS \ $msglvl $msgFile $inGraphFile $maxdomainsize $maxzeros \ $maxsize $seed $outETreeFile @ seed = $seed + 1 @ nseed = $nseed - 1 end misc/drivers/do_orderViaMMD010075500020550007177000000020460664516335100172360ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrices = /local1/ARPA/matrices set matrices = ../../../matrices set matrix = R2D100 set matrix = BCSSTK16 set matrix = R3D13824 set matrix = R2D10000 set matrix = i4a set matrix = MN12 set matrix = BCSSTK39 set matrix = GRD15x15x127 set inGraphFile = $matrices/$matrix/orig1.graphf set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig1.graphb set inGraphFile = $matrices/$matrix/orig0.graphb set msglvl = 1 set msgFile = stdout set outETreeFile = mmd.etreef set outETreeFile = none set outETreeFile = $matrices/$matrix/mmd.etreef set maxsize = 64 set maxzeros = 0 set maxzeros = 1000 set seed = 10101 set seed = 10103 set nseed = 3 while ( $nseed > 0 ) testOrderViaMMD \ $msglvl $msgFile $inGraphFile \ $maxsize $maxzeros $seed $outETreeFile @ seed = $seed + 1 @ nseed = $nseed - 1 ../../ETree/drivers/testHeight $msglvl $msgFile $outETreeFile end misc/drivers/do_orderViaMS010075500020550007177000000020450664516306000171340ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrices = /local1/ARPA/matrices set matrices = ../../../matrices set matrix = R3D13824 set matrix = R2D10000 set matrix = i4a set matrix = MN12 set matrix = GRD15x15x127 set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig1.graphf set inGraphFile = $matrices/$matrix/orig1.graphb set inGraphFile = $matrices/$matrix/orig0.graphb set msglvl = 1 set msgFile = res.MS.$matrix set msgFile = stdout set outETreeFile = ms.etreef set outETreeFile = none set outETreeFile = $matrices/$matrix/ms.etreef set maxdomainsize = 100 set maxsize = 64 set maxzeros = 0 set maxzeros = 1000 set seed = 10102 set seed = 10101 set nseed = 3 while ( $nseed > 0 ) testOrderViaMS \ $msglvl $msgFile $inGraphFile \ $maxdomainsize $maxsize $maxzeros $seed $outETreeFile @ seed = $seed + 1 @ nseed = $nseed - 1 ../../ETree/drivers/testHeight $msglvl $msgFile $outETreeFile end misc/drivers/do_orderViaND010075500020550007177000000025100664520673100171160ustar00clevecompmath00000400000006#! /bin/csh -f set matrices = ../../Matrices set matrices = ../../../matrices set matrices = /local1/ARPA/matrices set matrix = R2D100 set matrix = R3D13824 set matrix = R2D10000 set matrix = MN12 set matrix = BCSSTK39 set matrix = GRD15x15x127 set matrix = i4a set inGraphFile = /local1/ARPA/matrices/i4a/orig1.graphb set inGraphFile = ../../../matrices/R10KV/orig0.graphb set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig1.graphb set inGraphFile = $matrices/$matrix/orig0.graphb set msglvl = 1 set msgFile = res.ND.$matrix set msgFile = stdout set outETreeFile = nd.etreef set outETreeFile = /local1/ARPA/matrices/i4a/nd.etreeb set outETreeFile = ../../../matrices/R10KV/nd.etreef set outETreeFile = none set outETreeFile = $matrices/$matrix/nd.etreef set maxdomainsize = 10 set maxdomainsize = 500 set maxdomainsize = 1 set maxdomainsize = 100 set maxsize = 64 set maxsize = 1000000 set maxzeros = 1000 set maxzeros = 0 set seed = 10102 set seed = 10101 set nseed = 1 while ( $nseed > 0 ) testOrderViaND \ $msglvl $msgFile $inGraphFile \ $maxdomainsize $maxsize $maxzeros $seed $outETreeFile @ seed = $seed + 1 @ nseed = $nseed - 1 ../../ETree/drivers/testHeight $msglvl $msgFile $outETreeFile end ocal1/ARPA/matrices/i4a/orig1.graphb set inGraphFile = ../../../matrices/R10KV/orig0.graphb set inGraphFile = $matrices/$matrix/orig0.graphf set inGraphFile = $matrices/$matrix/orig1.gmisc/drivers/do_patchAndGo010075500020550007177000000012400657406460300171310ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout # type -- type of entries # 1 -- real entries # 2 -- complex entries set type = 1 # symmetryflag -- type of symmetry in the matrix # 0 -- symmetric # 1 -- hermitian # 2 -- nonsymmetric set symmetryflag = 0 set patchAndGoFlag = 2 set toosmall = 1.e-9 set fudge = 1.e-9 set storeids = 1 set storevalues = 1 set matrixFileName = singularMatrix.input set rhsFileName = singularRhs.input set seed = 10101 patchAndGo $msglvl $msgFile $type $symmetryflag \ $patchAndGoFlag $toosmall $fudge $storeids $storevalues \ $matrixFileName $rhsFileName $seed misc/drivers/do_testNDperm010075500020550007177000000002720653410634100172020ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 3 set msgFile = stdout set n1 = 7 set n2 = 7 set n3 = 1 set permFile = temp.permf set permFile = none testNDperm $msglvl $msgFile $n1 $n2 $n3 $permFile misc/drivers/do_testOptPart010075500020550007177000000005600654304170700174120ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 5 set msgFile = stdout set matrices = ../../Matrices set matrix = R2D100 set inGraphFile = $matrices/$matrix/orig0.graphf set inETreeFile = $matrices/$matrix/nd.etreef set outMapFile = none set alpha = 1 set seed = 10101 testOptPart \ $msglvl $msgFile $inETreeFile $inGraphFile $alpha $outMapFile misc/drivers/do_testSemi010075500020550007177000000005450654177052700167300ustar00clevecompmath00000400000006#! /bin/csh -f set msglvl = 1 set msgFile = stdout set matrices = ../../Matrices set matrix = R2D100 set inGraphFile = $matrices/$matrix/orig0.graphf set inETreeFile = $matrices/$matrix/nd.etreef set inMapFile = $matrices/$matrix/ndms.ivf set seed = 10101 testSemi \ $msglvl $msgFile $inGraphFile $inETreeFile $inMapFile misc/drivers/makefile010064400020550007177000000030320665314271000162040ustar00clevecompmath00000400000006include ../../Make.inc #----------------------------------------------------------------------- LIBS = ../../spooles.a -lm LIBS = ../../spooles.a -lpthread -lm DRIVERS = allInOne drawGraph patchAndGo QRallInOne testOrderViaND \ testOrderViaMS testOrderViaMMD testNDperm testSemi \ testOptPart testOrderViaBestOfNDandMS drivers : ${DRIVERS} clean : - rm -f *.a *.o ${DRIVERS} allInOne : allInOne.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} patchAndGo : patchAndGo.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} QRallInOne : QRallInOne.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} drawGraph : drawGraph.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testNDperm : testNDperm.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testOptPart : testOptPart.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testOrderViaBestOfNDandMS : testOrderViaBestOfNDandMS.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testOrderViaMMD : testOrderViaMMD.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testOrderViaMS : testOrderViaMS.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testOrderViaND : testOrderViaND.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} testSemi : testSemi.o ../../spooles.a ${PURIFY} ${CC} $@.o -o $@ $(PURIFY_GCC_VERSION) ${LIBS} misc/drivers/QRallInOne.c010064400020550007177000000240300664673477100166350ustar00clevecompmath00000400000006/* QRallInOne.c */ #include "../../misc.h" #include "../../FrontMtx.h" #include "../../SymbFac.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* -------------------------------------------------- QR all-in-one program (1) read in matrix entries and form InpMtx object of A and A^TA (2) form Graph object of A^TA (3) order matrix and form front tree (4) get the permutation, permute the matrix and front tree and get the symbolic factorization (5) compute the numeric factorization (6) read in right hand side entries (7) compute the solution created -- 98jun11, cca -------------------------------------------------- */ /*--------------------------------------------------------------------*/ char *matrixFileName, *rhsFileName ; ChvManager *chvmanager ; DenseMtx *mtxB, *mtxX ; double facops, imag, real, value ; double cpus[10] ; ETree *frontETree ; FILE *inputFile, *msgFile ; FrontMtx *frontmtx ; Graph *graph ; int ient, irow, jcol, jrhs, jrow, msglvl, neqns, nedges, nent, nrhs, nrow, seed, type ; InpMtx *mtxA ; IV *newToOldIV, *oldToNewIV ; IVL *adjIVL, *symbfacIVL ; SubMtxManager *mtxmanager ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 7 ) { fprintf(stdout, "\n usage: %s msglvl msgFile type matrixFileName rhsFileName seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 (SPOOLES_REAL) -- real entries" "\n 2 (SPOOLES_COMPLEX) -- complex entries" "\n matrixFileName -- matrix file name, format" "\n nrow ncol nent" "\n irow jcol entry" "\n ..." "\n note: indices are zero based" "\n rhsFileName -- right hand side file name, format" "\n nrow " "\n entry[0]" "\n ..." "\n entry[nrow-1]" "\n seed -- random number seed, used for ordering" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; matrixFileName = argv[4] ; rhsFileName = argv[5] ; seed = atoi(argv[6]) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 1: read the entries from the input file and create the InpMtx object of A -------------------------------------------- */ inputFile = fopen(matrixFileName, "r") ; fscanf(inputFile, "%d %d %d", &nrow, &neqns, &nent) ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, 0) ; if ( type == SPOOLES_REAL ) { for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else { for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------- STEP 2: read the right hand side entries ---------------------------------------- */ inputFile = fopen(rhsFileName, "r") ; fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxB = DenseMtx_new() ; DenseMtx_init(mtxB, type, 0, 0, nrow, nrhs, 1, nrow) ; DenseMtx_zero(mtxB) ; if ( type == SPOOLES_REAL ) { for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxB, jrow, jrhs, value) ; } } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxB, jrow, jrhs, real, imag) ; } } } fclose(inputFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n rhs matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- STEP 3 : find a low-fill ordering (1) create the Graph object for A^TA or A^HA (2) order the graph using multiple minimum degree ------------------------------------------------- */ graph = Graph_new() ; adjIVL = InpMtx_adjForATA(mtxA) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n graph of A^T A") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- STEP 4: get the permutation, permute the matrix and front tree and get the symbolic factorization ----------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; InpMtx_permute(mtxA, NULL, IV_entries(oldToNewIV)) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; symbfacIVL = SymbFac_initFromGraph(frontETree, graph) ; IVL_overwrite(symbfacIVL, oldToNewIV) ; IVL_sortUp(symbfacIVL) ; ETree_permuteVertices(frontETree, oldToNewIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n old-to-new permutation vector") ; IV_writeForHumanEye(oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation vector") ; IV_writeForHumanEye(newToOldIV, msgFile) ; fprintf(msgFile, "\n\n front tree after permutation") ; ETree_writeForHumanEye(frontETree, msgFile) ; fprintf(msgFile, "\n\n input matrix after permutation") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 5: initialize the front matrix object ------------------------------------------ */ frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; if ( type == SPOOLES_REAL ) { FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, SPOOLES_SYMMETRIC, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; } else { FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, SPOOLES_HERMITIAN, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- STEP 6: compute the numeric factorization ----------------------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1) ; DVzero(10, cpus) ; facops = 0.0 ; FrontMtx_QR_factor(frontmtx, mtxA, chvmanager, cpus, &facops, msglvl, msgFile) ; ChvManager_free(chvmanager) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix") ; fprintf(msgFile, "\n facops = %9.2f", facops) ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- STEP 7: post-process the factorization -------------------------------------- */ FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------- STEP 8: solve the linear system ------------------------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; FrontMtx_QR_solve(frontmtx, mtxA, mtxX, mtxB, mtxmanager, cpus, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n solution matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 9: permute the solution into the original ordering ------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------ free the working storage ------------------------ */ InpMtx_free(mtxA) ; FrontMtx_free(frontmtx) ; Graph_free(graph) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxB) ; ETree_free(frontETree) ; IV_free(newToOldIV) ; IV_free(oldToNewIV) ; IVL_free(symbfacIVL) ; SubMtxManager_free(mtxmanager) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ misc/drivers/allInOne.c010064400020550007177000000270000665164567500163720ustar00clevecompmath00000400000006/* allInOne.c */ #include "../../misc.h" #include "../../FrontMtx.h" #include "../../SymbFac.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* ------------------------------------------------------------------ all-in-one program to solve A X = Y (1) read in matrix entries for A and form InpMtx object (2) read in right hand side for Y entries and form DenseMtx object (3) form Graph object, order matrix and form front tree (4) get the permutation, permute the front tree, matrix and right hand side and get the symbolic factorization (5) initialize the front matrix object to hold the factor matrices (6) compute the numeric factorization (7) post-process the factor matrices (8) compute the solution (9) permute the solution into the original ordering created -- 98jun04, cca ------------------------------------------------------------------ */ /*--------------------------------------------------------------------*/ char *matrixFileName, *rhsFileName ; DenseMtx *mtxY, *mtxX ; Chv *rootchv ; ChvManager *chvmanager ; SubMtxManager *mtxmanager ; FrontMtx *frontmtx ; InpMtx *mtxA ; double droptol = 0.0, tau = 100. ; double cpus[10] ; ETree *frontETree ; FILE *inputFile, *msgFile ; Graph *graph ; int error, ient, irow, jcol, jrhs, jrow, msglvl, ncol, nedges, nent, neqns, nrhs, nrow, pivotingflag, seed, symmetryflag, type ; int *newToOld, *oldToNew ; int stats[20] ; IV *newToOldIV, *oldToNewIV ; IVL *adjIVL, *symbfacIVL ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 9 ) { fprintf(stdout, "\n" "\n usage: %s msglvl msgFile type symmetryflag pivotingflag" "\n matrixFileName rhsFileName seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 (SPOOLES_REAL) -- real entries" "\n 2 (SPOOLES_COMPLEX) -- complex entries" "\n symmetryflag -- type of matrix" "\n 0 (SPOOLES_SYMMETRIC) -- symmetric entries" "\n 1 (SPOOLES_HERMITIAN) -- Hermitian entries" "\n 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric entries" "\n pivotingflag -- type of pivoting" "\n 0 (SPOOLES_NO_PIVOTING) -- no pivoting used" "\n 1 (SPOOLES_PIVOTING) -- pivoting used" "\n matrixFileName -- matrix file name, format" "\n nrow ncol nent" "\n irow jcol entry" "\n ..." "\n note: indices are zero based" "\n rhsFileName -- right hand side file name, format" "\n nrow nrhs " "\n ..." "\n jrow entry(jrow,0) ... entry(jrow,nrhs-1)" "\n ..." "\n seed -- random number seed, used for ordering" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; symmetryflag = atoi(argv[4]) ; pivotingflag = atoi(argv[5]) ; matrixFileName = argv[6] ; rhsFileName = argv[7] ; seed = atoi(argv[8]) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 1: read the entries from the input file and create the InpMtx object -------------------------------------------- */ inputFile = fopen(matrixFileName, "r") ; fscanf(inputFile, "%d %d %d", &nrow, &ncol, &nent) ; neqns = nrow ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, neqns) ; if ( type == SPOOLES_REAL ) { double value ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else { double imag, real ; for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } InpMtx_writeForMatlab(mtxA, "A", msgFile) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------- STEP 2: read the right hand side matrix Y ----------------------------------------- */ inputFile = fopen(rhsFileName, "r") ; fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxY = DenseMtx_new() ; DenseMtx_init(mtxY, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxY) ; if ( type == SPOOLES_REAL ) { double value ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxY, jrow, jrhs, value) ; } } } else { double imag, real ; for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxY, jrow, jrhs, real, imag) ; } } } fclose(inputFile) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n rhs matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fflush(msgFile) ; } DenseMtx_writeForMatlab(mtxY, "b", msgFile) ; /*--------------------------------------------------------------------*/ /* ------------------------------------------------- STEP 3 : find a low-fill ordering (1) create the Graph object (2) order the graph using multiple minimum degree ------------------------------------------------- */ graph = Graph_new() ; adjIVL = InpMtx_fullAdjacency(mtxA) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ---------------------------------------------------- STEP 4: get the permutation, permute the front tree, permute the matrix and right hand side, and get the symbolic factorization ---------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; oldToNew = IV_entries(oldToNewIV) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; newToOld = IV_entries(newToOldIV) ; ETree_permuteVertices(frontETree, oldToNewIV) ; InpMtx_permute(mtxA, oldToNew, oldToNew) ; if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA) ; } InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; DenseMtx_permuteRows(mtxY, oldToNewIV) ; symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n old-to-new permutation vector") ; IV_writeForHumanEye(oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation vector") ; IV_writeForHumanEye(newToOldIV, msgFile) ; fprintf(msgFile, "\n\n front tree after permutation") ; ETree_writeForHumanEye(frontETree, msgFile) ; fprintf(msgFile, "\n\n input matrix after permutation") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fprintf(msgFile, "\n\n right hand side matrix after permutation") ; DenseMtx_writeForHumanEye(mtxY, msgFile) ; fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } Tree_writeToFile(frontETree->tree, "haggar.treef") ; /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 5: initialize the front matrix object ------------------------------------------ */ frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, pivotingflag, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; /*--------------------------------------------------------------------*/ /* ----------------------------------------- STEP 6: compute the numeric factorization ----------------------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1) ; DVfill(10, cpus, 0.0) ; IVfill(20, stats, 0) ; rootchv = FrontMtx_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, &error, cpus, stats, msglvl, msgFile) ; ChvManager_free(chvmanager) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } if ( rootchv != NULL ) { fprintf(msgFile, "\n\n matrix found to be singular\n") ; exit(-1) ; } if ( error >= 0 ) { fprintf(msgFile, "\n\n error encountered at front %d", error) ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- STEP 7: post-process the factorization -------------------------------------- */ FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------- STEP 8: solve the linear system ------------------------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; FrontMtx_solve(frontmtx, mtxX, mtxY, mtxmanager, cpus, 3, msgFile) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n solution matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------------- STEP 9: permute the solution into the original ordering ------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV) ; if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } DenseMtx_writeForMatlab(mtxX, "x", msgFile) ; /*--------------------------------------------------------------------*/ /* ----------- free memory ----------- */ FrontMtx_free(frontmtx) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxY) ; IV_free(newToOldIV) ; IV_free(oldToNewIV) ; InpMtx_free(mtxA) ; ETree_free(frontETree) ; IVL_free(symbfacIVL) ; SubMtxManager_free(mtxmanager) ; Graph_free(graph) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ misc/drivers/drawGraph.c010064400020550007177000000140340654177231300165770ustar00clevecompmath00000400000006/* drawGraph.c */ #include "../misc.h" #include "../../Graph.h" #include "../../Coords.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------- draw a graph. (1) read a Graph object (2) read a Coords object (3) read an IV object that contains a tag vector. if (v,w) is an edge in the graph and tags[v] == tags[w] then draw edge (v,w) (4) bbox[4] is the bounding box for the plot. bbox = { xsw, ysw, xne, yne } try bbox = { 0, 0, 500, 500 } because coordinates are measured in points, 72 points per inch. (5) rect[4] contains the frame for the plot. to put a 20 point margin around the plot, rect[0] = bbox[0] + 20 rect[1] = bbox[1] + 20 rect[2] = bbox[2] - 20 rect[3] = bbox[3] - 20 created -- 96jun06, cca ------------------------------------------------- */ { char *fnCoords, *fnEPS, *fnGraph, *fnTagsIV ; Coords *coords ; double linewidth1, linewidth2, radius, t1, t2 ; double bbox[4], rect[4] ; int msglvl, nvtx, rc ; IV *tagsIV ; Graph *graph ; FILE *msgFile ; if ( argc != 18 ) { fprintf(stdout, "\n\n usage : drawGraph msglvl msgFile GraphFile CoordsFile" "\n tagsIVfile epsFile bbox[4] rect[4] radius" "\n msglvl -- message level" "\n msgFile -- message file" "\n GraphFile -- input graph file, must be *.graphf or *.graphb" "\n CoordsFile -- input Coords file, must be *.coordsf or *.coordsb" "\n tagsIVfile -- input IV file, must be *.ivf or *.ivb" "\n contains the component ids" "\n epsFile -- output postscript file, must be *.eps" "\n linewidth1 -- line width for edges connecting vertices" "\n in the same component" "\n linewidth2 -- line width for edges connecting vertices" "\n in the same component" "\n bbox[4] -- bounding box for drawing" "\n rect[4] -- rectangle to contain graph" "\n radius -- radius for vertex circle" "\n") ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } fnGraph = argv[3] ; fnCoords = argv[4] ; fnTagsIV = argv[5] ; fnEPS = argv[6] ; linewidth1 = atof(argv[7]) ; linewidth2 = atof(argv[8]) ; bbox[0] = atof(argv[9]) ; bbox[1] = atof(argv[10]) ; bbox[2] = atof(argv[11]) ; bbox[3] = atof(argv[12]) ; rect[0] = atof(argv[13]) ; rect[1] = atof(argv[14]) ; rect[2] = atof(argv[15]) ; rect[3] = atof(argv[16]) ; radius = atof(argv[17]) ; fprintf(msgFile, "\n drawGraph " "\n msglvl -- %d" "\n msgFile -- %s" "\n GraphFile -- %s" "\n CoordsFile -- %s" "\n tagsIVfile -- %s" "\n epsFile -- %s" "\n linewidth1 -- %f" "\n linewidth2 -- %f" "\n bbox[4] = { %f, %f, %f, %f }" "\n rect[4] = { %f, %f, %f, %f }" "\n radius -- %f" "\n", msglvl, argv[2], fnGraph, fnCoords, fnTagsIV, fnEPS, linewidth1, linewidth2, bbox[0], bbox[1], bbox[2], bbox[3], rect[0], rect[1], rect[2], rect[3], radius) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ graph = Graph_new() ; if ( strcmp(fnGraph, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; rc = Graph_readFromFile(graph, fnGraph) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, fnGraph) ; nvtx = graph->nvtx ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, fnGraph) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading Graph object from file %s", argv[3]) ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ------------------------- read in the Coords object ------------------------- */ if ( strcmp(fnCoords, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; coords = Coords_new() ; rc = Coords_readFromFile(coords, fnCoords) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in coords from file %s", t2 - t1, fnCoords) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Coords_readFromFile(%p,%s)", rc, coords, fnCoords) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading Coords object from file %s", argv[3]) ; Coords_writeForHumanEye(coords, msgFile) ; fflush(msgFile) ; } /* --------------------- read in the IV object --------------------- */ if ( strcmp(fnTagsIV, "none") == 0 ) { tagsIV = NULL ; } else { MARKTIME(t1) ; tagsIV = IV_new() ; rc = IV_readFromFile(tagsIV, fnTagsIV) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in tagsIV from file %s", t2 - t1, fnTagsIV) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, tagsIV, fnTagsIV) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading IV object from file %s", argv[3]) ; IV_writeForHumanEye(tagsIV, msgFile) ; fflush(msgFile) ; } } fprintf(msgFile, "\n getting ready to call drawGraphEPS") ; fflush(msgFile) ; /* -------------- draw the graph -------------- */ drawGraphEPS(graph, coords, tagsIV, bbox, rect, linewidth1, linewidth2, radius, fnEPS, msglvl, msgFile) ; /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; Coords_free(coords) ; if ( tagsIV != NULL ) { IV_free(tagsIV) ; } fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ misc/drivers/mallocTime.c010064400020550007177000000062030657435426000167500ustar00clevecompmath00000400000006#include #include "../../IV.h" #include "../../Utilities.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ /* --------------------------------------------------------------- this program tries to get some idea of the malloc()/free() characteristics of a machine and operating system. it was written to try and understand the initialization times for the FrontMtx object for the i4a matrix with 99192 rows and columns. the program reads in a vector that contains the byte counts for the factor submatrices. depending on the input parameters, the program allocates the storage and then free'ing the storage. zeroflag -- 0 --> do not zero the storage otherwise --> zero the storage sortflag -- 0 --> do not sort the byte counts in ascending order otherwise --> sort the byte counts in ascending order created -- 98sep05, cca --------------------------------------------------------------- */ int main ( int argc, char *argv[] ) { double t1, t2 ; double *dvec ; double **pdvecs ; int item, nitem, sortflag, sum, zeroflag ; int *nbytes ; IV *nbytesIV ; if ( argc != 3 ) { fprintf(stdout, "\n usage : a.out zeroflag sortflag ") ; return(1) ; } zeroflag = atoi(argv[1]) ; sortflag = atoi(argv[2]) ; if ( zeroflag == 0 ) { fprintf(stdout, "\n storage not zero'd") ; } else { fprintf(stdout, "\n storage zero'd") ; } if ( sortflag == 0 ) { fprintf(stdout, "\n byte counts not sorted") ; } else { fprintf(stdout, "\n byte counts sorted") ; } /* ------------------------------------------------- read in the vector that contains the bytes counts for the SubMtx objects from the i4a matrix ------------------------------------------------- */ nbytesIV = IV_new() ; IV_readFromFile(nbytesIV, "nbytes.ivf") ; IV_sizeAndEntries(nbytesIV, &nitem, &nbytes) ; sum = IV_sum(nbytesIV) ; fprintf(stdout, "\n %d items read in, sum = %d", nitem, sum) ; fflush(stdout) ; if ( sortflag != 0 ) { IVqsortUp(nitem, nbytes) ; } /* ------------------------------------ now time the malloc()'s and free()'s ------------------------------------ */ pdvecs = PDVinit(nitem) ; if ( zeroflag == 0 ) { MARKTIME(t1) ; for ( item = 0 ; item < nitem ; item++ ) { pdvecs[item] = DVinit2(nbytes[item]/sizeof(double)) ; } MARKTIME(t2) ; fprintf(stdout, "\n CPU %10.5f for DVinit2", t2 - t1) ; MARKTIME(t1) ; for ( item = 0 ; item < nitem ; item++ ) { DVfree(pdvecs[item]) ; } MARKTIME(t2) ; fprintf(stdout, "\n CPU %10.5f for DVfree", t2 - t1) ; } else { MARKTIME(t1) ; for ( item = 0 ; item < nitem ; item++ ) { pdvecs[item] = DVinit(nbytes[item]/sizeof(double), 0.0) ; } MARKTIME(t2) ; fprintf(stdout, "\n CPU %10.5f for DVinit", t2 - t1) ; MARKTIME(t1) ; for ( item = 0 ; item < nitem ; item++ ) { DVfree(pdvecs[item]) ; } MARKTIME(t2) ; fprintf(stdout, "\n CPU %10.5f for DVfree", t2 - t1) ; } fprintf(stdout, "\n") ; fflush(stdout) ; return(1) ; } /*--------------------------------------------------------------------*/ tflag, sum, zeroflag ; int *nbytes ; IV *nbytesIV ; if ( argc != 3 ) { fprintf(stdout, "\n usage : a.out zeroflag sortflag ") ; return(1) ; } zeroflag = atoi(argv[1]) ; sortflag = atoi(argv[2]) ; if ( zeroflag == 0 ) { fprintf(stdout, "\n storage not zero'd") ; } else { fprintf(stdout, "\n storage zero'd") ; } if ( sortflag == 0 ) { fprintf(stdout, "\nmisc/drivers/patchAndGo.c010064400020550007177000000306440657627025100166770ustar00clevecompmath00000400000006/* allInOne.c */ #include "../../misc.h" #include "../../FrontMtx.h" #include "../../SymbFac.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { /* -------------------------------------------------- all-in-one program to solve A X = B We use a patch-and-go strategy for the factorization without pivoting (1) read in matrix entries and form DInpMtx object (2) form Graph object (3) order matrix and form front tree (4) get the permutation, permute the matrix and front tree and get the symbolic factorization (5) compute the numeric factorization (6) read in right hand side entries (7) compute the solution created -- 98jun04, cca -------------------------------------------------- */ /*--------------------------------------------------------------------*/ char *matrixFileName, *rhsFileName ; DenseMtx *mtxB, *mtxX ; double fudge, toosmall ; Chv *rootchv ; ChvManager *chvmanager ; SubMtxManager *mtxmanager ; FrontMtx *frontmtx ; InpMtx *mtxA ; double imag, real, tau = 100., value ; double cpus[10] ; ETree *frontETree ; FILE *inputFile, *msgFile ; Graph *graph ; int error, ient, irow, jcol, jrhs, jrow, msglvl, ncol, nedges, nent, neqns, nrhs, nrow, patchAndGoFlag, seed, storeids, storevalues, symmetryflag, type ; int *newToOld, *oldToNew ; int stats[20] ; IV *newToOldIV, *oldToNewIV ; IVL *adjIVL, *symbfacIVL ; /*--------------------------------------------------------------------*/ /* -------------------- get input parameters -------------------- */ if ( argc != 13 ) { fprintf(stdout, "\n" "\n usage: %s msglvl msgFile type symmetryflag " "\n patchAndGoFlag fudge toosmall storeids storevalues" "\n matrixFileName rhsFileName seed" "\n msglvl -- message level" "\n msgFile -- message file" "\n type -- type of entries" "\n 1 (SPOOLES_REAL) -- real entries" "\n 2 (SPOOLES_COMPLEX) -- complex entries" "\n symmetryflag -- type of matrix" "\n 0 (SPOOLES_SYMMETRIC) -- symmetric entries" "\n 1 (SPOOLES_HERMITIAN) -- Hermitian entries" "\n 2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric entries" "\n matrixFileName -- matrix file name, format" "\n nrow ncol nent" "\n irow jcol entry" "\n ..." "\n note: indices are zero based" "\n rhsFileName -- right hand side file name, format" "\n nrow nrhs " "\n ..." "\n jrow entry(jrow,0) ... entry(jrow,nrhs-1)" "\n ..." "\n seed -- random number seed, used for ordering" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } type = atoi(argv[3]) ; symmetryflag = atoi(argv[4]) ; patchAndGoFlag = atoi(argv[5]) ; fudge = atof(argv[6]) ; toosmall = atof(argv[7]) ; storeids = atoi(argv[8]) ; storevalues = atoi(argv[9]) ; matrixFileName = argv[10] ; rhsFileName = argv[11] ; seed = atoi(argv[12]) ; /*--------------------------------------------------------------------*/ /* -------------------------------------------- STEP 1: read the entries from the input file and create the InpMtx object -------------------------------------------- */ inputFile = fopen(matrixFileName, "r") ; fscanf(inputFile, "%d %d %d", &nrow, &ncol, &nent) ; neqns = nrow ; mtxA = InpMtx_new() ; InpMtx_init(mtxA, INPMTX_BY_ROWS, type, nent, 0) ; if ( type == SPOOLES_REAL ) { for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le", &irow, &jcol, &value) ; InpMtx_inputRealEntry(mtxA, irow, jcol, value) ; } } else { for ( ient = 0 ; ient < nent ; ient++ ) { fscanf(inputFile, "%d %d %le %le", &irow, &jcol, &real, &imag) ; InpMtx_inputComplexEntry(mtxA, irow, jcol, real, imag) ; } } fclose(inputFile) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n input matrix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------------- STEP 2 : find a low-fill ordering (1) create the Graph object (2) order the graph using multiple minimum degree ------------------------------------------------- */ graph = Graph_new() ; adjIVL = InpMtx_fullAdjacency(mtxA) ; nedges = IVL_tsize(adjIVL) ; Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n graph of the input matrix") ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n front tree from ordering") ; ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------------------- STEP 3: get the permutation, permute the matrix and front tree and get the symbolic factorization ----------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree) ; oldToNew = IV_entries(oldToNewIV) ; newToOldIV = ETree_newToOldVtxPerm(frontETree) ; newToOld = IV_entries(newToOldIV) ; ETree_permuteVertices(frontETree, oldToNewIV) ; InpMtx_permute(mtxA, oldToNew, oldToNew) ; InpMtx_mapToUpperTriangle(mtxA) ; InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS) ; InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS) ; symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n old-to-new permutation vector") ; IV_writeForHumanEye(oldToNewIV, msgFile) ; fprintf(msgFile, "\n\n new-to-old permutation vector") ; IV_writeForHumanEye(newToOldIV, msgFile) ; fprintf(msgFile, "\n\n front tree after permutation") ; ETree_writeForHumanEye(frontETree, msgFile) ; fprintf(msgFile, "\n\n input matrix after permutation") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------------------ STEP 4: initialize the front matrix object ------------------------------------------ */ frontmtx = FrontMtx_new() ; mtxmanager = SubMtxManager_new() ; SubMtxManager_init(mtxmanager, NO_LOCK, 0) ; FrontMtx_init(frontmtx, frontETree, symbfacIVL, type, symmetryflag, FRONTMTX_DENSE_FRONTS, SPOOLES_NO_PIVOTING, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile) ; if ( patchAndGoFlag == 1 ) { frontmtx->patchinfo = PatchAndGoInfo_new() ; PatchAndGoInfo_init(frontmtx->patchinfo, 1, toosmall, fudge, storeids, storevalues) ; } else if ( patchAndGoFlag == 2 ) { frontmtx->patchinfo = PatchAndGoInfo_new() ; PatchAndGoInfo_init(frontmtx->patchinfo, 2, toosmall, fudge, storeids, storevalues) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- STEP 5: compute the numeric factorization ----------------------------------------- */ chvmanager = ChvManager_new() ; ChvManager_init(chvmanager, NO_LOCK, 1) ; DVfill(10, cpus, 0.0) ; IVfill(20, stats, 0) ; rootchv = FrontMtx_factorInpMtx(frontmtx, mtxA, tau, 0.0, chvmanager, &error, cpus, stats, msglvl, msgFile) ; ChvManager_free(chvmanager) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } if ( patchAndGoFlag == 1 ) { if ( frontmtx->patchinfo->fudgeIV != NULL ) { fprintf(msgFile, "\n small pivots found at these locations") ; IV_writeForHumanEye(frontmtx->patchinfo->fudgeIV, msgFile) ; } PatchAndGoInfo_free(frontmtx->patchinfo) ; } else if ( patchAndGoFlag == 2 ) { if ( frontmtx->patchinfo->fudgeIV != NULL ) { fprintf(msgFile, "\n small pivots found at these locations") ; IV_writeForHumanEye(frontmtx->patchinfo->fudgeIV, msgFile) ; } if ( frontmtx->patchinfo->fudgeDV != NULL ) { fprintf(msgFile, "\n perturbations") ; DV_writeForHumanEye(frontmtx->patchinfo->fudgeDV, msgFile) ; } PatchAndGoInfo_free(frontmtx->patchinfo) ; } if ( rootchv != NULL ) { fprintf(msgFile, "\n\n matrix found to be singular\n") ; exit(-1) ; } if ( error >= 0 ) { fprintf(msgFile, "\n\n error encountered at front %d", error) ; exit(-1) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------- STEP 6: post-process the factorization -------------------------------------- */ FrontMtx_postProcess(frontmtx, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n factor matrix after post-processing") ; FrontMtx_writeForHumanEye(frontmtx, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------------------------------------- STEP 7: read the right hand side matrix B ----------------------------------------- */ inputFile = fopen(rhsFileName, "r") ; fscanf(inputFile, "%d %d", &nrow, &nrhs) ; mtxB = DenseMtx_new() ; DenseMtx_init(mtxB, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxB) ; if ( type == SPOOLES_REAL ) { for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le", &value) ; DenseMtx_setRealEntry(mtxB, jrow, jrhs, value) ; } } } else { for ( irow = 0 ; irow < nrow ; irow++ ) { fscanf(inputFile, "%d", &jrow) ; for ( jrhs = 0 ; jrhs < nrhs ; jrhs++ ) { fscanf(inputFile, "%le %le", &real, &imag) ; DenseMtx_setComplexEntry(mtxB, jrow, jrhs, real, imag) ; } } } fclose(inputFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n rhs matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* --------------------------------------------------------- STEP 8: permute the right hand side into the new ordering --------------------------------------------------------- */ DenseMtx_permuteRows(mtxB, oldToNewIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n right hand side matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxB, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ------------------------------- STEP 9: solve the linear system ------------------------------- */ mtxX = DenseMtx_new() ; DenseMtx_init(mtxX, type, 0, 0, neqns, nrhs, 1, neqns) ; DenseMtx_zero(mtxX) ; FrontMtx_solve(frontmtx, mtxX, mtxB, mtxmanager, cpus, msglvl, msgFile) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n solution matrix in new ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* -------------------------------------------------------- STEP 10: permute the solution into the original ordering -------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n\n solution matrix in original ordering") ; DenseMtx_writeForHumanEye(mtxX, msgFile) ; fflush(msgFile) ; } /*--------------------------------------------------------------------*/ /* ----------- free memory ----------- */ FrontMtx_free(frontmtx) ; DenseMtx_free(mtxX) ; DenseMtx_free(mtxB) ; IV_free(newToOldIV) ; IV_free(oldToNewIV) ; InpMtx_free(mtxA) ; ETree_free(frontETree) ; IVL_free(symbfacIVL) ; SubMtxManager_free(mtxmanager) ; Graph_free(graph) ; /*--------------------------------------------------------------------*/ return(1) ; } /*--------------------------------------------------------------------*/ rix") ; InpMtx_writeForHumanEye(mtxA, msgFile) ; fflush(msgFile) ; } /*---------------misc/drivers/testMemory.c010064400020550007177000000062550661164173200170340ustar00clevecompmath00000400000006/* testMemory.c */ #include "../misc.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------- test the memory subsystem created -- 98oct16, cca ---------------------------------------- */ { char **p_chunks ; double t1, t2 ; double *cpus ; int chunksize, ichunk, jchunk, msglvl, nchunk ; FILE *msgFile ; if ( argc != 5 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile nchunk chunksize" "\n msglvl -- message level" "\n msgFile -- message file" "\n nchunk -- # of chunks" "\n chunksize -- size of each chunk in bytes" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } nchunk = atoi(argv[3]) ; chunksize = atoi(argv[4]) ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n nchunk -- %d" "\n chunksize -- %d" "\n", argv[0], msglvl, argv[2], nchunk, chunksize) ; fflush(msgFile) ; /* --------------------------------------- allocate the pointers and cpus[] arrays --------------------------------------- */ p_chunks = (char **) malloc(nchunk*sizeof(char *)) ; if ( p_chunks == NULL ) { fprintf(msgFile, "\n unable to allocate p_chunks") ; fflush(msgFile) ; return(-1) ; } cpus = (double *) malloc(2*nchunk*sizeof(double)) ; if ( cpus == NULL ) { fprintf(msgFile, "\n unable to allocate cpus") ; fflush(msgFile) ; return(-1) ; } for ( ichunk = 0 ; ichunk < nchunk ; ichunk++ ) { p_chunks[ichunk] = NULL ; cpus[2*ichunk] = cpus[2*ichunk+1] = 0.0 ; } /* ------------------- allocate the chunks ------------------- */ for ( ichunk = 0 ; ichunk < nchunk ; ichunk++ ) { MARKTIME(t1) ; p_chunks[ichunk] = (char *) malloc(chunksize * sizeof(char)) ; MARKTIME(t2) ; cpus[2*ichunk] = t2 - t1 ; if ( p_chunks[ichunk] == NULL ) { fprintf(msgFile, "\n unable to allocate p_chunks[%d]", ichunk) ; fflush(msgFile) ; break ; } } fprintf(msgFile, "\n\n %d chunks of size %d bytes allocated", ichunk, chunksize) ; fprintf(msgFile, "\n %d total bytes allocated", ichunk*chunksize) ; /* ------------------------ free the working storage ------------------------ */ for ( jchunk = 0 ; jchunk < ichunk ; jchunk++ ) { MARKTIME(t1) ; free(p_chunks[jchunk]) ; MARKTIME(t2) ; cpus[2*jchunk+1] = t2 - t1 ; } /* -------------------- print the statistics -------------------- */ fprintf(msgFile, "\n CPU TIME " "\n chunk malloc free") ; for ( jchunk = 0 ; jchunk < ichunk ; jchunk++ ) { fprintf(msgFile, "\n %8d %8.4f %8.4f", ichunk, cpus[2*ichunk], cpus[2*ichunk+1]) ; } free(p_chunks) ; free(cpus) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ misc/drivers/testNDperm.c010064400020550007177000000046150654176064600167570ustar00clevecompmath00000400000006/* testNDperm.c */ #include "../misc.h" #include "../../Graph.h" #include "../../Perm.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------------- generate a nested dissection permutation object for a n1 x n2 x n3 regular grid. created -- 96feb01, cca ----------------------------------------------- */ { Perm *perm ; FILE *msgFile ; int j, msglvl, n1, n2, n3, nvtx ; int *newToOld, *oldToNew, *temp ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile n1 n2 n3 permFile" "\n generate separators" "\n msglvl -- message level" "\n msgFile -- message file" "\n n1 -- number of points in first direction" "\n n2 -- number of points in second direction" "\n n3 -- number of points in third direction" "\n permFile -- file to contain the Perm structure" "\n", argv[0]) ; return(1) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n error in test4, file %s, line %d" "\n unable to open file %s", __FILE__, __LINE__, argv[2]) ; exit(-1) ; } n1 = atoi(argv[3]) ; n2 = atoi(argv[4]) ; n3 = atoi(argv[5]) ; /* ----------------------------- create the permutation object ----------------------------- */ nvtx = n1 * n2 * n3 ; perm = Perm_new() ; Perm_initWithTypeAndSize(perm, 3, nvtx) ; newToOld = perm->newToOld ; oldToNew = perm->oldToNew ; /* --------------------- call the nd procedure --------------------- */ mkNDperm(n1, n2, n3, newToOld, 0, n1-1, 0, n2-1, 0, n3-1) ; /* ----------------------------------------- fill in the new-to-old permutation vector ----------------------------------------- */ for ( j = 0 ; j < nvtx ; j++ ) { perm->oldToNew[perm->newToOld[j]] = j ; } if ( msglvl > 2 ) { Perm_writeForHumanEye(perm, msgFile) ; } /* ---------------------------------------- write the permutation vector to its file ---------------------------------------- */ if ( strcmp("none", argv[6]) != 0 ) { Perm_writeToFile(perm, argv[6]) ; } /* ------------------------ free the working storage ------------------------ */ Perm_free(perm) ; return(1) ; } /*--------------------------------------------------------------------*/ misc/drivers/testOptPart.c010064400020550007177000000213150654304141100171370ustar00clevecompmath00000400000006/* testOptPart.c */ #include "../../SymbFac.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ------------------------------------------------------ (1) read in an ETree object. (2) read in an Graph object. (3) find the optimal domain/schur complement partition for a semi-implicit factorization created -- 96oct03, cca ------------------------------------------------------ */ { char *inETreeFileName, *inGraphFileName, *outIVfileName ; double alpha, nA21, nfent1, nfops1, nL11, nL22, nPhi, nV, t1, t2 ; Graph *graph ; int ii, inside, J, K, msglvl, nfind1, nfront, nJ, nleaves1, nnode1, nvtx, rc, sizeJ, totalgain, vsize, v, w ; int *adjJ, *compids, *nodwghts, *vadj, *vtxToFront, *vwghts ; IV *compidsIV ; IVL *symbfacIVL ; ETree *etree ; FILE *msgFile ; Tree *tree ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETreeFile inGraphFile alpha" "\n outIVfile " "\n msglvl -- message level" "\n msgFile -- message file" "\n inETreeFile -- input file, must be *.etreef or *.etreeb" "\n inGraphFile -- input file, must be *.graphf or *.graphb" "\n alpha -- weight parameter" "\n alpha = 0 --> minimize storage" "\n alpha = 1 --> minimize solve ops" "\n outIVfile -- output file for oldToNew vector," "\n must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inETreeFileName = argv[3] ; inGraphFileName = argv[4] ; alpha = atof(argv[5]) ; outIVfileName = argv[6] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n inETreeFile -- %s" "\n inGraphFile -- %s" "\n alpha -- %f" "\n outIVfile -- %s" "\n", argv[0], msglvl, argv[2], inETreeFileName, inGraphFileName, alpha, outIVfileName) ; fflush(msgFile) ; /* ------------------------ read in the ETree object ------------------------ */ if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } etree = ETree_new() ; MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } ETree_leftJustify(etree) ; fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(etree, msgFile) ; } else { ETree_writeStats(etree, msgFile) ; } fflush(msgFile) ; nfront = ETree_nfront(etree) ; tree = ETree_tree(etree) ; nodwghts = ETree_nodwghts(etree) ; vtxToFront = ETree_vtxToFront(etree) ; /* ------------------------ read in the Graph object ------------------------ */ if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } graph = Graph_new() ; MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; nvtx = graph->nvtx ; vwghts = graph->vwghts ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; if ( msglvl > 2 ) { Graph_writeForHumanEye(graph, msgFile) ; } else { Graph_writeStats(graph, msgFile) ; } fflush(msgFile) ; /* ---------------------- compute the statistics ---------------------- */ nnode1 = etree->tree->n ; nfind1 = ETree_nFactorIndices(etree) ; nfent1 = ETree_nFactorEntries(etree, SPOOLES_SYMMETRIC) ; nfops1 = ETree_nFactorOps(etree, SPOOLES_REAL, SPOOLES_SYMMETRIC) ; nleaves1 = Tree_nleaves(etree->tree) ; fprintf(stdout, "\n root front %d has %d vertices", etree->tree->root, etree->nodwghtsIV->vec[etree->tree->root]) ; /* --------------------------------- create the symbolic factorization --------------------------------- */ symbfacIVL = SymbFac_initFromGraph(etree, graph) ; if ( msglvl > 2 ) { IVL_writeForHumanEye(symbfacIVL, msgFile) ; } else { IVL_writeStats(symbfacIVL, msgFile) ; } fflush(msgFile) ; /* -------------------------- find the optimal partition -------------------------- */ compidsIV = ETree_optPart(etree, graph, symbfacIVL, alpha, &totalgain, msglvl, msgFile) ; if ( msglvl > 2 ) { IV_writeForHumanEye(compidsIV, msgFile) ; } else { IV_writeStats(compidsIV, msgFile) ; } fflush(msgFile) ; compids = IV_entries(compidsIV) ; /* ------------------------------------------------------ compute the number of vertices in the schur complement ------------------------------------------------------ */ for ( J = 0, nPhi = nV = 0. ; J < nfront ; J++ ) { if ( compids[J] == 0 ) { nPhi += nodwghts[J] ; } nV += nodwghts[J] ; } /* -------------------------------------------- compute the number of entries in L11 and L22 -------------------------------------------- */ nL11 = nL22 = 0 ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { nJ = nodwghts[J] ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front %d, nJ = %d", J, nJ) ; } IVL_listAndSize(symbfacIVL, J, &sizeJ, &adjJ) ; for ( ii = 0, inside = 0 ; ii < sizeJ ; ii++ ) { w = adjJ[ii] ; K = vtxToFront[w] ; if ( msglvl > 3 ) { fprintf(msgFile, "\n w = %d, K = %d", w, K) ; } if ( K > J && compids[K] == compids[J] ) { inside += (vwghts == NULL) ? 1 : vwghts[w] ; if ( msglvl > 3 ) { fprintf(msgFile, ", inside") ; } } } if ( compids[J] != 0 ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n inside = %d, adding %d to L11", inside, nJ*nJ + 2*nJ*inside) ; } nL11 += (nJ*(nJ+1))/2 + nJ*inside ; } else { if ( msglvl > 3 ) { fprintf(msgFile, "\n inside = %d, adding %d to L22", inside, (nJ*(nJ+1))/2 + nJ*inside) ; } nL22 += (nJ*(nJ+1))/2 + nJ*inside ; } } if ( msglvl > 0 ) { fprintf(msgFile, "\n |L| = %.0f, |L11| = %.0f, |L22| = %.0f", nfent1, nL11, nL22) ; } /* ------------------------------------ compute the number of entries in A21 ------------------------------------ */ nA21 = 0 ; if ( vwghts != NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { J = vtxToFront[v] ; if ( compids[J] != 0 ) { Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; K = vtxToFront[w] ; if ( compids[K] == 0 ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n A21 : v = %d, w = %d", v, w) ; } nA21 += vwghts[v] * vwghts[w] ; } } } } } else { for ( v = 0 ; v < nvtx ; v++ ) { J = vtxToFront[v] ; if ( compids[J] != 0 ) { Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; K = vtxToFront[w] ; if ( compids[K] == 0 ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n A21 : v = %d, w = %d", v, w) ; } nA21++ ; } } } } } if ( msglvl > 0 ) { fprintf(msgFile, "\n |L| = %.0f, |L11| = %.0f, |L22| = %.0f, |A21| = %.0f", nfent1, nL11, nL22, nA21) ; fprintf(msgFile, "\n storage: explicit = %.0f, semi-implicit = %.0f, ratio = %.3f" "\n opcount: explicit = %.0f, semi-implicit = %.0f, ratio = %.3f", nfent1, nL11 + nA21 + nL22, nfent1/(nL11 + nA21 + nL22), 2*nfent1, 4*nL11 + 2*nA21 + 2*nL22, 2*nfent1/(4*nL11 + 2*nA21 + 2*nL22)) ; fprintf(msgFile, "\n ratios %8.3f %8.3f %8.3f", nPhi/nV, nfent1/(nL11 + nA21 + nL22), 2*nfent1/(4*nL11 + 2*nA21 + 2*nL22)) ; } /* ---------------- free the objects ---------------- */ ETree_free(etree) ; Graph_free(graph) ; IVL_free(symbfacIVL) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ , nnode1, nvtx, rc, sizeJ, totalgain, vsize, v, w ; int *adjJ, *compids, *nodwghts, *vadj, *vtxToFront, *vwghts ; IV *compidsIV ; IVL *symbfacIVL ; ETree *etree ; FILE *msgFile ; Tree *tree ; if ( argc != 7 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile inETremisc/drivers/testOrderViaBestOfNDandMS.c010064400020550007177000000105700657427436300215540ustar00clevecompmath00000400000006/* testOrderViaBestOfNDandMS.c */ #include "../misc.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* -------------------------------------- order a graph via the best of a nested dissection and a multisection ordering created -- 98aug26, cca -------------------------------------- */ { char *inGraphFileName, *outETreeFileName ; double cputotal, t1, t2 ; ETree *frontETree ; int maxdomainsize, maxsize, maxzeros, msglvl, nvtx, rc, seed ; Graph *graph ; FILE *msgFile ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile GraphFile maxdomainsize " "\n maxzeros maxsize seed ETreeFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n GraphFile -- input graph file, must be *.graphf or *.graphb" "\n maxdomainsize -- maximum size for a subgraph not to be split" "\n maxzeros -- maximum # of zeros in a front" "\n maxsize -- maximum # of internal columns in a front" "\n seed -- random number seed" "\n ETreeFile -- output ETree file, must be *.etreef or *.etreeb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; maxdomainsize = atoi(argv[4]) ; maxzeros = atoi(argv[5]) ; maxsize = atoi(argv[6]) ; seed = atoi(argv[7]) ; outETreeFileName = argv[8] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n GraphFile -- %s" "\n maxdomainsize -- %d" "\n maxzeros -- %d" "\n maxsize -- %d" "\n seed -- %d" "\n ETreeFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, maxdomainsize, maxzeros, maxsize, seed, outETreeFileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ graph = Graph_new() ; if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = graph->nvtx ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* -------------------------------------------------------- order the graph using nested dissection and multisection -------------------------------------------------------- */ MARKTIME(t1) ; frontETree = orderViaBestOfNDandMS(graph, maxdomainsize, maxzeros, maxsize, seed, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %8.3f : order the graph via best of ND and MS", t2 - t1) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n\n %d fronts, %d indices, %d entries, %.0f operations", frontETree->nfront, ETree_nFactorIndices(frontETree), ETree_nFactorEntries(frontETree, SPOOLES_SYMMETRIC), ETree_nFactorOps(frontETree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; /* ------------------------------------- optionally write out the ETree object ------------------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { fprintf(msgFile, "\n\n writing out ETree to file %s", outETreeFileName) ; MARKTIME(t1) ; ETree_writeToFile(frontETree, outETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %8.3f : write front tree to file %s", t2 - t1, outETreeFileName) ; } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; ETree_free(frontETree) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ misc/drivers/testOrderViaMMD.c010064400020550007177000000106120664516103700176270ustar00clevecompmath00000400000006/* testOrderViaMMD.c */ #include "../misc.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------------------- order a graph via a multiple minimum degree ordering created -- 97nov08, cca ---------------------------------------------------- */ { char *inGraphFileName, *outETreeFileName ; double t1, t2 ; ETree *frontETree ; int maxsize, maxzeros, msglvl, nvtx, rc, seed ; Graph *graph ; FILE *msgFile ; if ( argc != 8 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile GraphFile " "\n maxsize maxzeros seed ETreeFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n GraphFile -- input graph file, must be *.graphf or *.graphb" "\n maxzeros -- maximum # of zeros in a front" "\n maxsize -- maximum # of internal columns in a front" "\n seed -- random number seed" "\n ETreeFile -- output ETree file, must be *.etreef or *.etreeb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; maxsize = atoi(argv[4]) ; maxzeros = atoi(argv[5]) ; seed = atoi(argv[6]) ; outETreeFileName = argv[7] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n GraphFile -- %s" "\n maxsize -- %d" "\n maxzeros -- %d" "\n seed -- %d" "\n ETreeFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, maxsize, maxzeros, seed, outETreeFileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ graph = Graph_new() ; if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = graph->nvtx ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ------------------------------------ order the graph using minimum degree ------------------------------------ */ MARKTIME(t1) ; frontETree = orderViaMMD(graph, seed, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.2f : order the graph via MMD", t2 - t1) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n\n %d fronts, %d indices, %d entries, %.0f operations", frontETree->nfront, ETree_nFactorIndices(frontETree), ETree_nFactorEntries(frontETree, SPOOLES_SYMMETRIC), ETree_nFactorOps(frontETree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; /* ------------------ transform the tree ------------------ */ MARKTIME(t1) ; frontETree = ETree_transform(frontETree, graph->vwghts, maxzeros, maxsize, seed); MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : transform tree", t2 - t1) ; fflush(msgFile) ; } fprintf(msgFile, "\n\n %d fronts, %d indices, %d entries, %.0f operations", frontETree->nfront, ETree_nFactorIndices(frontETree), ETree_nFactorEntries(frontETree, SPOOLES_SYMMETRIC), ETree_nFactorOps(frontETree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; /* ------------------------------------ optionally write the ETree to a file ------------------------------------ */ if ( strcmp(outETreeFileName, "none") != 0 ) { ETree_writeToFile(frontETree, outETreeFileName) ; } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; ETree_free(frontETree) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ maxsize -- maximum # of internal columns in a front" "\n seed -- random number seed" "\n ETreeFmisc/drivers/testOrderViaMS.c010064400020550007177000000110100664515631000175200ustar00clevecompmath00000400000006/* testOrderViaMS.c */ #include "../misc.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ----------------------------------------- order a graph via a multisection ordering created -- 97nov06, cca ----------------------------------------- */ { char *inGraphFileName, *outETreeFileName ; double t1, t2 ; ETree *frontETree ; int maxdomainsize, maxsize, maxzeros, msglvl, nvtx, rc, seed ; Graph *graph ; FILE *msgFile ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile GraphFile " "\n maxdomainsize maxsize maxzeros seed ETreeFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n GraphFile -- input graph file, must be *.graphf or *.graphb" "\n maxdomainsize -- maximum size for a subgraph not to be split" "\n maxzeros -- maximum # of zeros in a front" "\n maxsize -- maximum # of internal columns in a front" "\n seed -- random number seed" "\n ETreeFile -- output ETree file, must be *.etreef or *.etreeb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; maxdomainsize = atoi(argv[4]) ; maxsize = atoi(argv[5]) ; maxzeros = atoi(argv[6]) ; seed = atoi(argv[7]) ; outETreeFileName = argv[8] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n GraphFile -- %s" "\n maxdomainsize -- %d" "\n maxsize -- %d" "\n maxzeros -- %d" "\n seed -- %d" "\n ETreeFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, maxdomainsize, maxsize, maxzeros, seed, outETreeFileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ graph = Graph_new() ; if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = graph->nvtx ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ---------------------------------- order the graph using multisection ---------------------------------- */ MARKTIME(t1) ; frontETree = orderViaMS(graph, maxdomainsize, seed, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.2f : order the graph via MS", t2 - t1) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n\n %d fronts, %d indices, %d entries, %.0f operations", frontETree->nfront, ETree_nFactorIndices(frontETree), ETree_nFactorEntries(frontETree, SPOOLES_SYMMETRIC), ETree_nFactorOps(frontETree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; /* ------------------ transform the tree ------------------ */ MARKTIME(t1) ; frontETree = ETree_transform(frontETree, graph->vwghts, maxzeros, maxsize, seed); MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : transform tree", t2 - t1) ; fflush(msgFile) ; } fprintf(msgFile, "\n\n %d fronts, %d indices, %d entries, %.0f operations", frontETree->nfront, ETree_nFactorIndices(frontETree), ETree_nFactorEntries(frontETree, SPOOLES_SYMMETRIC), ETree_nFactorOps(frontETree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; /* -------------------------- write the object to a file -------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { ETree_writeToFile(frontETree, outETreeFileName) ; } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; ETree_free(frontETree) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ misc/drivers/testOrderViaND.c010064400020550007177000000110440664516077500175230ustar00clevecompmath00000400000006/* testOrderViaND.c */ #include "../misc.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------------- order a graph via a nested dissection ordering created -- 97nov06, cca ---------------------------------------------- */ { char *inGraphFileName, *outETreeFileName ; double t1, t2 ; ETree *frontETree ; int maxdomainsize, maxsize, maxzeros, msglvl, nvtx, rc, seed ; Graph *graph ; FILE *msgFile ; if ( argc != 9 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile GraphFile " "\n maxdomainsize maxsize maxzeros seed ETreeFile" "\n msglvl -- message level" "\n msgFile -- message file" "\n GraphFile -- input graph file, must be *.graphf or *.graphb" "\n maxdomainsize -- maximum size for a subgraph not to be split" "\n maxzeros -- maximum # of zeros in a front" "\n maxsize -- maximum # of internal columns in a front" "\n seed -- random number seed" "\n ETreeFile -- output ETree file, must be *.etreef or *.etreeb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; maxdomainsize = atoi(argv[4]) ; maxsize = atoi(argv[5]) ; maxzeros = atoi(argv[6]) ; seed = atoi(argv[7]) ; outETreeFileName = argv[8] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n GraphFile -- %s" "\n maxdomainsize -- %d" "\n maxsize -- %d" "\n maxzeros -- %d" "\n seed -- %d" "\n ETreeFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, maxdomainsize, maxsize, maxzeros, seed, outETreeFileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ graph = Graph_new() ; if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = graph->nvtx ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* --------------------------------------- order the graph using nested dissection --------------------------------------- */ MARKTIME(t1) ; frontETree = orderViaND(graph, maxdomainsize, seed, msglvl, msgFile) ; MARKTIME(t2) ; fprintf(msgFile, "\n\n CPU %9.2f : order the graph via ND", t2 - t1) ; if ( msglvl > 2 ) { ETree_writeForHumanEye(frontETree, msgFile) ; fflush(msgFile) ; } fprintf(msgFile, "\n\n %d fronts, %d indices, %d entries, %.0f operations", frontETree->nfront, ETree_nFactorIndices(frontETree), ETree_nFactorEntries(frontETree, SPOOLES_SYMMETRIC), ETree_nFactorOps(frontETree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; /* ------------------ transform the tree ------------------ */ MARKTIME(t1) ; frontETree = ETree_transform(frontETree, graph->vwghts, maxzeros, maxsize, seed); MARKTIME(t2) ; if ( msglvl > 1 ) { fprintf(msgFile, "\n CPU %8.3f : transform tree", t2 - t1) ; fflush(msgFile) ; } fprintf(msgFile, "\n\n %d fronts, %d indices, %d entries, %.0f operations", frontETree->nfront, ETree_nFactorIndices(frontETree), ETree_nFactorEntries(frontETree, SPOOLES_SYMMETRIC), ETree_nFactorOps(frontETree, SPOOLES_REAL, SPOOLES_SYMMETRIC)) ; /* -------------------------- write the object to a file -------------------------- */ if ( strcmp(outETreeFileName, "none") != 0 ) { ETree_writeToFile(frontETree, outETreeFileName) ; } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; ETree_free(frontETree) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ maxzeros = atoi(argv[6]) ; seed = atoi(argv[7]) ; outETreeFileName = argv[8] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n GraphFile -- %s" "\n maxdomainsize -- %d" "\n maxsize -- %d" "\n maxzeros -- %d" "\n seed -- %d" "\n ETreeFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, maxdomisc/drivers/testSemi.c010064400020550007177000000207570654176777000165010ustar00clevecompmath00000400000006/* testSemi.c */ #include "../misc.h" #include "../../SymbFac.h" #include "../../timings.h" /*--------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) /* ---------------------------------------- get statistics for a semi-implicit solve created -- 97dec11, cca ---------------------------------------- */ { char *inGraphFileName, *inETreeFileName, *inMapFileName ; double nA21, nL, nL11, nL22, nPhi, nV, t1, t2 ; ETree *etree ; int ii, inside, J, K, msglvl, nfront, nJ, nvtx, rc, sizeJ, v, vsize, w ; int *adjJ, *frontmap, *map, *nodwghts, *vadj, *vtxToFront, *vwghts ; IV *mapIV ; IVL *symbfacIVL ; Graph *graph ; FILE *msgFile ; Tree *tree ; if ( argc != 6 ) { fprintf(stdout, "\n\n usage : %s msglvl msgFile GraphFile ETreeFile mapFile " "\n msglvl -- message level" "\n msgFile -- message file" "\n GraphFile -- input graph file, must be *.graphf or *.graphb" "\n ETreeFile -- input ETree file, must be *.etreef or *.etreeb" "\n mapFile -- input map IV file, must be *.ivf or *.ivb" "\n", argv[0]) ; return(0) ; } msglvl = atoi(argv[1]) ; if ( strcmp(argv[2], "stdout") == 0 ) { msgFile = stdout ; } else if ( (msgFile = fopen(argv[2], "a")) == NULL ) { fprintf(stderr, "\n fatal error in %s" "\n unable to open file %s\n", argv[0], argv[2]) ; return(-1) ; } inGraphFileName = argv[3] ; inETreeFileName = argv[4] ; inMapFileName = argv[5] ; fprintf(msgFile, "\n %s " "\n msglvl -- %d" "\n msgFile -- %s" "\n GraphFile -- %s" "\n ETreeFile -- %s" "\n mapFile -- %s" "\n", argv[0], msglvl, argv[2], inGraphFileName, inETreeFileName, inMapFileName) ; fflush(msgFile) ; /* ------------------------ read in the Graph object ------------------------ */ graph = Graph_new() ; if ( strcmp(inGraphFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; rc = Graph_readFromFile(graph, inGraphFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in graph from file %s", t2 - t1, inGraphFileName) ; nvtx = graph->nvtx ; vwghts = graph->vwghts ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from Graph_readFromFile(%p,%s)", rc, graph, inGraphFileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading Graph object from file %s", inGraphFileName) ; Graph_writeForHumanEye(graph, msgFile) ; fflush(msgFile) ; } /* ------------------------ read in the ETree object ------------------------ */ etree = ETree_new() ; if ( strcmp(inETreeFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; rc = ETree_readFromFile(etree, inETreeFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in etree from file %s", t2 - t1, inETreeFileName) ; nfront = ETree_nfront(etree) ; tree = ETree_tree(etree) ; vtxToFront = ETree_vtxToFront(etree) ; nodwghts = ETree_nodwghts(etree) ; nL = ETree_nFactorEntries(etree, 2) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from ETree_readFromFile(%p,%s)", rc, etree, inETreeFileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading ETree object from file %s", inETreeFileName) ; ETree_writeForHumanEye(etree, msgFile) ; fflush(msgFile) ; } /* ------------------------- read in the map IV object ------------------------- */ mapIV = IV_new() ; if ( strcmp(inMapFileName, "none") == 0 ) { fprintf(msgFile, "\n no file to read from") ; exit(0) ; } MARKTIME(t1) ; rc = IV_readFromFile(mapIV, inMapFileName) ; MARKTIME(t2) ; fprintf(msgFile, "\n CPU %9.5f : read in mapIV from file %s", t2 - t1, inMapFileName) ; map = IV_entries(mapIV) ; if ( rc != 1 ) { fprintf(msgFile, "\n return value %d from IV_readFromFile(%p,%s)", rc, mapIV, inMapFileName) ; exit(-1) ; } if ( msglvl > 2 ) { fprintf(msgFile, "\n\n after reading IV object from file %s", inMapFileName) ; IV_writeForHumanEye(mapIV, msgFile) ; fflush(msgFile) ; } nV = nPhi = 0 ; if ( vwghts == NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { nV++ ; if ( map[v] == 0 ) { nPhi++ ; } } } else { for ( v = 0 ; v < nvtx ; v++ ) { nV += vwghts[v] ; if ( map[v] == 0 ) { nPhi += vwghts[v] ; } } } fprintf(msgFile, "\n nPhi = %.0f, nV = %.0f", nPhi, nV) ; /* ------------------------- get the frontmap[] vector ------------------------- */ frontmap = IVinit(nfront, -1) ; for ( v = 0 ; v < nvtx ; v++ ) { J = vtxToFront[v] ; if ( frontmap[J] == -1 ) { frontmap[J] = map[v] ; } else if ( frontmap[J] != map[v] ) { fprintf(msgFile, "\n\n error, frontmap[%d] = %d, map[%d] = %d", J, frontmap[J], v, map[v]) ; } } /* ---------------------------------- compute the symbolic factorization ---------------------------------- */ symbfacIVL = SymbFac_initFromGraph(etree, graph) ; if ( msglvl > 2 ) { fprintf(msgFile, "\n\n symbolic factorization") ; IVL_writeForHumanEye(symbfacIVL, msgFile) ; fflush(msgFile) ; } /* -------------------------------------------- compute the number of entries in L11 and L22 -------------------------------------------- */ nL11 = nL22 = 0 ; for ( J = Tree_postOTfirst(tree) ; J != -1 ; J = Tree_postOTnext(tree, J) ) { nJ = nodwghts[J] ; if ( msglvl > 3 ) { fprintf(msgFile, "\n\n front %d, nJ = %d", J, nJ) ; } IVL_listAndSize(symbfacIVL, J, &sizeJ, &adjJ) ; for ( ii = 0, inside = 0 ; ii < sizeJ ; ii++ ) { w = adjJ[ii] ; K = vtxToFront[w] ; if ( msglvl > 3 ) { fprintf(msgFile, "\n w = %d, K = %d", w, K) ; } if ( K > J && frontmap[K] == frontmap[J] ) { inside += (vwghts == NULL) ? 1 : vwghts[w] ; if ( msglvl > 3 ) { fprintf(msgFile, ", inside") ; } } } if ( frontmap[J] != 0 ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n inside = %d, adding %d to L11", inside, nJ*nJ + 2*nJ*inside) ; } nL11 += nJ*nJ + 2*nJ*inside ; } else { if ( msglvl > 3 ) { fprintf(msgFile, "\n inside = %d, adding %d to L22", inside, nJ*nJ + 2*nJ*inside) ; } nL22 += nJ*nJ + 2*nJ*inside ; } } if ( msglvl > 0 ) { fprintf(msgFile, "\n |L| = %.0f, |L11| = %.0f, |L22| = %.0f", nL, nL11, nL22) ; } /* ------------------------------------ compute the number of entries in A21 ------------------------------------ */ nA21 = 0 ; if ( vwghts != NULL ) { for ( v = 0 ; v < nvtx ; v++ ) { if ( map[v] == 0 ) { Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( map[v] != map[w] ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n A21 : v = %d, w = %d", v, w) ; } nA21 += vwghts[v] * vwghts[w] ; } } } } } else { for ( v = 0 ; v < nvtx ; v++ ) { if ( map[v] == 0 ) { Graph_adjAndSize(graph, v, &vsize, &vadj) ; for ( ii = 0 ; ii < vsize ; ii++ ) { w = vadj[ii] ; if ( map[v] != map[w] ) { if ( msglvl > 3 ) { fprintf(msgFile, "\n A21 : v = %d, w = %d", v, w) ; } nA21++ ; } } } } } if ( msglvl > 0 ) { fprintf(msgFile, "\n |L| = %.0f, |L11| = %.0f, |L22| = %.0f, |A21| = %.0f", nL, nL11, nL22, nA21) ; fprintf(msgFile, "\n storage: explicit = %.0f, semi-implicit = %.0f, ratio = %.3f" "\n opcount: explicit = %.0f, semi-implicit = %.0f, ratio = %.3f", nL, nL11 + nA21 + nL22, nL/(nL11 + nA21 + nL22), 2*nL, 4*nL11 + 2*nA21 + 2*nL22, 2*nL/(4*nL11 + 2*nA21 + 2*nL22)) ; fprintf(msgFile, "\n ratios %8.3f %8.3f %8.3f", nPhi/nV, nL/(nL11 + nA21 + nL22), 2*nL/(4*nL11 + 2*nA21 + 2*nL22)) ; } /* ------------------------ free the working storage ------------------------ */ Graph_free(graph) ; ETree_free(etree) ; IV_free(mapIV) ; IVL_free(symbfacIVL) ; IVfree(frontmap) ; fprintf(msgFile, "\n") ; fclose(msgFile) ; return(1) ; } /*--------------------------------------------------------------------*/ *.graphf or *.grmisc/drivers/complex.herm.mtx.input010064400020550007177000000031040662057333600210030ustar00clevecompmath00000400000006 9 9 29 0 0 9.2205056705246591e-01 0.0000000000000000e+00 0 2 -9.2324541857273346e-01 4.1801836645769019e-01 0 6 -4.4919564350584040e-01 -5.8500069134172927e-01 0 7 -7.2245146073790933e-01 -4.4006942604011912e-01 1 1 -4.6379027628441039e-01 0.0000000000000000e+00 1 2 9.7447762863272835e-02 3.3662318513401357e-01 1 7 7.6968457336686003e-02 9.0204641673431984e-01 1 8 6.9413884356701816e-01 7.4699119408347259e-01 2 2 8.0720991064461067e-01 0.0000000000000000e+00 2 6 -8.1644490286606208e-01 9.6605963637822700e-02 2 7 -4.1487932403792749e-01 3.1026316870579929e-01 2 8 -8.8362012156644387e-01 6.5745090920633054e-01 3 3 -4.0774471762511000e-01 0.0000000000000000e+00 3 5 6.8342517180887041e-01 -4.6969974875658682e-02 3 6 2.8661767363664792e-01 -3.3372698601651640e-01 3 7 -4.4782492940552487e-01 4.6389144679101779e-01 4 4 3.5718735929621648e-01 0.0000000000000000e+00 4 5 5.2526926512265937e-01 -3.3577777610212145e-01 4 7 -5.0877856288392920e-01 3.1986884129645843e-01 4 8 9.0476402915313026e-01 -2.1516340658482602e-01 5 5 6.0203005008984101e-01 0.0000000000000000e+00 5 6 5.4799463394076753e-01 2.8166398729264686e-01 5 7 -7.1176010672916123e-02 -2.0518754070668521e-01 5 8 -8.1255174803868802e-01 -9.0277316362397664e-02 6 6 -2.9132091987984166e-01 0.0000000000000000e+00 6 7 3.9912080062798605e-01 8.6533507823640554e-01 7 7 -5.9259824332355082e-01 0.0000000000000000e+00 7 8 -5.5664914395435583e-01 -2.0266504782556050e-01 8 8 -4.4787040356033647e-02 0.0000000000000000e+00 misc/drivers/complex.herm.rhs.input010064400020550007177000000007540662057335300207760ustar00clevecompmath00000400000006 9 1 0 6.1382691845614656e-01 2.0282222378257910e+00 1 2.2507715310179705e-01 -2.8691568524677724e-01 2 3.1077386235871440e-01 -2.9900265484263289e-01 3 1.9749313365717891e-01 -6.3479154732771481e-01 4 7.7426309489963152e-01 6.4166053116256472e-01 5 -1.6216166229981583e+00 -8.5550695245542041e-01 6 3.0270552825633318e-01 -4.4925636236595523e-01 7 9.5349391136560535e-01 -2.5670817590010991e-01 8 -1.2548960676925902e-02 1.6364733721553857e+00 misc/drivers/complex.nonsym.mtx.input010064400020550007177000000052170662057352500214020ustar00clevecompmath00000400000006 9 9 49 7 0 -5.0877856288392920e-01 -3.1986884129645843e-01 6 0 -2.9132091987984166e-01 -1.8339328774643571e-01 2 0 9.7447762863272835e-02 -3.3662318513401357e-01 0 0 9.2205056705246591e-01 -1.3469012288779969e-01 0 2 -9.2324541857273346e-01 4.1801836645769019e-01 0 6 -4.4919564350584040e-01 -5.8500069134172927e-01 0 7 -7.2245146073790933e-01 -4.4006942604011912e-01 8 1 -1.6716921292682319e-01 6.4522909226104375e-02 7 1 -4.4787040356033647e-02 -6.1938959623133560e-01 2 1 7.6968457336686003e-02 -9.0204641673431984e-01 1 1 -8.9700983802128409e-01 8.8966188981256478e-01 1 2 4.4473264031218096e-01 1.0430845891415097e-01 1 7 5.4774666463884825e-01 7.0702596246134797e-01 1 8 7.7814512101110789e-01 -9.7332738979385613e-01 8 2 -7.3125844595812628e-01 3.1146566172809398e-01 7 2 5.2526926512265937e-01 3.3577777610212145e-01 6 2 3.9912080062798605e-01 8.6533507823640554e-01 2 2 -5.9259824332355082e-01 9.5078193154952695e-02 2 6 -8.8362012156644387e-01 6.5745090920633054e-01 2 7 -7.1176010672916123e-02 2.0518754070668521e-01 2 8 -5.5664914395435583e-01 -2.0266504782556050e-01 7 3 -8.1255174803868802e-01 -9.0277316362397664e-02 6 3 -8.1644490286606208e-01 -9.6605963637822700e-02 5 3 -6.2620038270346479e-01 -8.4382739510635307e-01 3 3 6.8342517180887041e-01 -4.6969974875658682e-02 3 5 -4.1487932403792749e-01 3.1026316870579929e-01 3 6 -4.4782492940552487e-01 4.6389144679101779e-01 3 7 8.0720991064461067e-01 -5.5942665438692352e-01 8 4 -8.8834789419061089e-01 9.6832156614741915e-01 7 4 3.5718735929621648e-01 1.4306403005516266e-01 5 4 -1.6552069926134283e-01 -3.3513481704818993e-01 4 4 6.3915270582213024e-02 3.0082191646558365e-01 4 5 9.9934099146350497e-01 8.4333973689185338e-01 4 7 -3.5313870153240379e-01 5.2129874625727224e-01 4 8 3.7375205977304149e-01 -2.4072505136096356e-01 8 5 9.5504191619277123e-01 8.9895133832975471e-01 7 5 6.9413884356701816e-01 7.4699119408347259e-01 6 5 -4.0774471762511000e-01 1.8488079435884375e-01 5 5 -4.1379170220917771e-01 -8.2290794744490436e-01 5 6 -4.3750432608084178e-01 -7.5485602680722352e-02 5 7 -3.2856607107823532e-01 3.2834239718928182e-01 5 8 -9.7925066865808652e-01 -4.6334018483008987e-01 7 6 6.0203005008984101e-01 -1.9418064388695855e-01 6 6 2.8661767363664792e-01 3.3372698601651640e-01 6 7 5.4799463394076753e-01 -2.8166398729264686e-01 8 7 -5.0143675395386489e-01 8.6979509654109521e-01 7 7 -4.6379027628441039e-01 4.9808814904535770e-01 7 8 9.0476402915313026e-01 2.1516340658482602e-01 8 8 -2.2100579262966868e-01 6.9939559439598842e-01 misc/drivers/complex.nonsym.rhs.input010064400020550007177000000007540662057354500213710ustar00clevecompmath00000400000006 9 1 0 -1.2499048215313713e+00 -4.1059893307406736e-01 1 1.4408501746136642e+00 2.0809143353590087e-01 2 -1.4138015604481582e-01 5.2648846780755998e-01 3 1.9523441988412410e-01 3.6238838006227164e-01 4 1.2321244919350183e+00 4.5462243198752517e-01 5 -5.2047391330226289e-01 -8.5434905572840836e-01 6 -1.2225815661283985e+00 2.2349535900424761e-01 7 -4.2647638140957117e-01 1.2975261762229022e+00 8 1.0999710925115909e+00 -9.3848704584390341e-01 misc/drivers/complex.sym.mtx.input010064400020550007177000000031030662057224100206510ustar00clevecompmath00000400000006 9 9 29 0 0 9.2205056705246591e-01 -1.3469012288779969e-01 0 2 -9.2324541857273346e-01 4.1801836645769019e-01 0 6 -4.4919564350584040e-01 -5.8500069134172927e-01 0 7 -7.2245146073790933e-01 -4.4006942604011912e-01 1 1 -4.6379027628441039e-01 4.9808814904535770e-01 1 2 9.7447762863272835e-02 -3.3662318513401357e-01 1 7 7.6968457336686003e-02 -9.0204641673431984e-01 1 8 6.9413884356701816e-01 7.4699119408347259e-01 2 2 8.0720991064461067e-01 -5.5942665438692352e-01 2 6 -8.1644490286606208e-01 -9.6605963637822700e-02 2 7 -4.1487932403792749e-01 3.1026316870579929e-01 2 8 -8.8362012156644387e-01 6.5745090920633054e-01 3 3 -4.0774471762511000e-01 1.8488079435884375e-01 3 5 6.8342517180887041e-01 -4.6969974875658682e-02 3 6 2.8661767363664792e-01 3.3372698601651640e-01 3 7 -4.4782492940552487e-01 4.6389144679101779e-01 4 4 3.5718735929621648e-01 1.4306403005516266e-01 4 5 5.2526926512265937e-01 3.3577777610212145e-01 4 7 -5.0877856288392920e-01 -3.1986884129645843e-01 4 8 9.0476402915313026e-01 2.1516340658482602e-01 5 5 6.0203005008984101e-01 -1.9418064388695855e-01 5 6 5.4799463394076753e-01 -2.8166398729264686e-01 5 7 -7.1176010672916123e-02 2.0518754070668521e-01 5 8 -8.1255174803868802e-01 -9.0277316362397664e-02 6 6 -2.9132091987984166e-01 -1.8339328774643571e-01 6 7 3.9912080062798605e-01 8.6533507823640554e-01 7 7 -5.9259824332355082e-01 9.5078193154952695e-02 7 8 -5.5664914395435583e-01 -2.0266504782556050e-01 8 8 -4.4787040356033647e-02 -6.1938959623133560e-01 misc/drivers/complex.sym.rhs.input010064400020550007177000000007540662057256600206600ustar00clevecompmath00000400000006 9 1 0 6.0365975335482047e-01 2.0871497492695634e+00 1 -1.2168061497205205e+00 1.9798432474411563e+00 2 -2.4951155819794524e-01 -3.1229685187277145e-01 3 7.0000487701716019e-01 -1.1134970362720562e+00 4 2.7137772133264548e-01 1.2643479742056583e+00 5 -1.9410571605814380e+00 -8.4160443589093714e-01 6 5.9634988468129119e-02 1.7746525105068911e-01 7 2.5975021324930418e+00 -1.6101019486827275e+00 8 1.1032678554224224e+00 1.8443373533552232e+00 misc/drivers/haggar.matrix.input010064400020550007177000003322470665164020700203400ustar00clevecompmath00000400000006252 252 3191 132 132 1.029802e+10 -5.149009e+08 132 136 1.192093e-07 -5.960464e-09 132 137 -1.490116e-07 7.450581e-09 132 138 -5.908699e+08 2.954350e+07 132 142 -5.960464e-08 2.980232e-09 132 143 -5.275624e+08 2.637812e+07 132 162 -1.287252e+09 6.436262e+07 132 166 -1.582687e+08 7.913437e+06 132 167 1.318906e+08 -6.594531e+06 132 168 -1.983635e+09 9.918174e+07 132 172 -6.330749e+08 3.165375e+07 132 173 1.490116e-08 -7.450581e-10 132 174 -1.287252e+09 6.436262e+07 132 178 -1.582687e+08 7.913437e+06 132 179 -1.318906e+08 6.594531e+06 133 133 1.796625e+10 -8.983125e+08 133 134 2.384186e-07 -1.192093e-08 133 139 -4.424986e+09 2.212493e+08 133 140 2.384186e-07 -1.192093e-08 133 163 -2.245781e+09 1.122891e+08 133 164 -1.725352e+09 8.626761e+07 133 169 -6.657689e+07 3.328845e+06 133 170 2.980232e-08 -1.490116e-09 133 175 -2.245781e+09 1.122891e+08 133 176 1.725352e+09 -8.626761e+07 134 134 2.134027e+10 -1.067014e+09 134 139 5.960464e-08 -2.980232e-09 134 140 2.169693e+09 -1.084847e+08 134 163 -1.725352e+09 8.626761e+07 134 164 -2.667534e+09 1.333767e+08 134 169 -5.960464e-08 2.980232e-09 134 170 -7.504762e+09 3.752381e+08 134 175 1.725352e+09 -8.626761e+07 134 176 -2.667534e+09 1.333767e+08 135 135 2.900850e+06 -1.450425e+05 135 141 -1.664422e+05 8.322112e+03 135 165 -3.626063e+05 1.813032e+04 135 171 -5.587704e+05 2.793852e+04 135 177 -3.626063e+05 1.813032e+04 136 136 3.561542e+08 -1.780771e+07 136 137 -1.746230e-10 8.731149e-12 136 138 -8.940697e-08 4.470348e-09 136 142 8.837909e+07 -4.418955e+06 136 143 -3.637979e-11 1.818989e-12 136 162 1.582687e+08 -7.913437e+06 136 166 2.142603e+07 -1.071302e+06 136 167 3.594484e+05 -1.797242e+04 136 168 6.330749e+08 -3.165375e+07 136 172 8.636358e+07 -4.318179e+06 136 173 2.910383e-11 -1.455192e-12 136 174 1.582687e+08 -7.913437e+06 136 178 2.142603e+07 -1.071302e+06 136 179 -3.594484e+05 1.797242e+04 137 137 3.554513e+08 -1.777256e+07 137 138 5.275624e+08 -2.637812e+07 137 142 -2.182787e-11 1.091394e-12 137 143 8.700520e+07 -4.350260e+06 137 162 -1.318906e+08 6.594531e+06 137 166 3.594484e+05 -1.797242e+04 137 167 2.151390e+07 -1.075695e+06 137 168 -2.980232e-08 1.490116e-09 137 172 -1.455192e-11 7.275958e-13 137 173 8.791320e+07 -4.395660e+06 137 174 1.318906e+08 -6.594531e+06 137 178 -3.594484e+05 1.797242e+04 137 179 2.151390e+07 -1.075695e+06 138 138 5.149009e+09 -2.574505e+08 138 142 5.960464e-08 -2.980232e-09 138 143 5.275624e+08 -2.637812e+07 138 168 -1.287252e+09 6.436262e+07 138 172 -1.582687e+08 7.913437e+06 138 173 1.318906e+08 -6.594531e+06 138 174 -9.918174e+08 4.959087e+07 138 178 -3.165375e+08 1.582687e+07 138 179 1.318906e+08 -6.594531e+06 139 139 8.983125e+09 -4.491563e+08 139 140 -2.384186e-07 1.192093e-08 139 169 -2.245781e+09 1.122891e+08 139 170 -1.725352e+09 8.626761e+07 139 175 -3.328845e+07 1.664422e+06 139 176 1.738727e+08 -8.693635e+06 140 140 1.067014e+10 -5.335068e+08 140 169 -1.725352e+09 8.626761e+07 140 170 -2.667534e+09 1.333767e+08 140 175 -1.738727e+08 8.693635e+06 140 176 -3.752381e+09 1.876190e+08 141 141 1.450425e+06 -7.252126e+04 141 171 -3.626063e+05 1.813032e+04 141 177 -2.793852e+05 1.396926e+04 142 142 1.780771e+08 -8.903855e+06 142 143 0.000000e+00 -0.000000e+00 142 168 1.582687e+08 -7.913437e+06 142 172 2.142603e+07 -1.071302e+06 142 173 3.594484e+05 -1.797242e+04 142 174 3.165375e+08 -1.582687e+07 142 178 4.318179e+07 -2.159090e+06 142 179 3.622348e+04 -1.811174e+03 143 143 1.777256e+08 -8.886282e+06 143 168 -1.318906e+08 6.594531e+06 143 172 3.594484e+05 -1.797242e+04 143 173 2.151390e+07 -1.075695e+06 143 174 1.318906e+08 -6.594531e+06 143 178 -3.622348e+04 1.811174e+03 143 179 4.395660e+07 -2.197830e+06 168 168 1.029802e+10 -5.149009e+08 168 172 1.192093e-07 -5.960464e-09 168 173 -8.940697e-08 4.470348e-09 168 174 -5.908699e+08 2.954350e+07 168 178 -5.960464e-08 2.980232e-09 168 179 -5.275624e+08 2.637812e+07 168 198 -1.287252e+09 6.436262e+07 168 202 -1.582687e+08 7.913437e+06 168 203 1.318906e+08 -6.594531e+06 168 204 -1.983635e+09 9.918174e+07 168 208 -6.330749e+08 3.165375e+07 168 209 -2.980232e-08 1.490116e-09 168 210 -1.287252e+09 6.436262e+07 168 214 -1.582687e+08 7.913437e+06 168 215 -1.318906e+08 6.594531e+06 169 169 1.796625e+10 -8.983125e+08 169 170 2.384186e-07 -1.192093e-08 169 175 -4.424986e+09 2.212493e+08 169 176 2.980232e-08 -1.490116e-09 169 199 -2.245781e+09 1.122891e+08 169 200 -1.725352e+09 8.626761e+07 169 205 -6.657689e+07 3.328845e+06 169 206 2.682209e-07 -1.341105e-08 169 211 -2.245781e+09 1.122891e+08 169 212 1.725352e+09 -8.626761e+07 170 170 2.134027e+10 -1.067014e+09 170 175 -5.960464e-08 2.980232e-09 170 176 2.169693e+09 -1.084847e+08 170 199 -1.725352e+09 8.626761e+07 170 200 -2.667534e+09 1.333767e+08 170 205 1.192093e-07 -5.960464e-09 170 206 -7.504762e+09 3.752381e+08 170 211 1.725352e+09 -8.626761e+07 170 212 -2.667534e+09 1.333767e+08 171 171 2.900850e+06 -1.450425e+05 171 177 -1.664422e+05 8.322112e+03 171 201 -3.626063e+05 1.813032e+04 171 207 -5.587704e+05 2.793852e+04 171 213 -3.626063e+05 1.813032e+04 172 172 3.561542e+08 -1.780771e+07 172 173 0.000000e+00 -0.000000e+00 172 174 -5.960464e-08 2.980232e-09 172 178 8.837909e+07 -4.418955e+06 172 179 -1.455192e-11 7.275958e-13 172 198 1.582687e+08 -7.913437e+06 172 202 2.142603e+07 -1.071302e+06 172 203 3.594484e+05 -1.797242e+04 172 204 6.330749e+08 -3.165375e+07 172 208 8.636358e+07 -4.318179e+06 172 209 -2.182787e-11 1.091394e-12 172 210 1.582687e+08 -7.913437e+06 172 214 2.142603e+07 -1.071302e+06 172 215 -3.594484e+05 1.797242e+04 173 173 3.554513e+08 -1.777256e+07 173 174 5.275624e+08 -2.637812e+07 173 178 5.093170e-11 -2.546585e-12 173 179 8.700520e+07 -4.350260e+06 173 198 -1.318906e+08 6.594531e+06 173 202 3.594484e+05 -1.797242e+04 173 203 2.151390e+07 -1.075695e+06 173 204 -1.490116e-08 7.450581e-10 173 208 -2.910383e-11 1.455192e-12 173 209 8.791320e+07 -4.395660e+06 173 210 1.318906e+08 -6.594531e+06 173 214 -3.594484e+05 1.797242e+04 173 215 2.151390e+07 -1.075695e+06 174 174 5.149009e+09 -2.574505e+08 174 178 5.960464e-08 -2.980232e-09 174 179 5.275624e+08 -2.637812e+07 174 204 -1.287252e+09 6.436262e+07 174 208 -1.582687e+08 7.913437e+06 174 209 1.318906e+08 -6.594531e+06 174 210 -9.918174e+08 4.959087e+07 174 214 -3.165375e+08 1.582687e+07 174 215 1.318906e+08 -6.594531e+06 175 175 8.983125e+09 -4.491563e+08 175 176 -2.384186e-07 1.192093e-08 175 205 -2.245781e+09 1.122891e+08 175 206 -1.725352e+09 8.626761e+07 175 211 -3.328845e+07 1.664422e+06 175 212 1.738727e+08 -8.693635e+06 176 176 1.067014e+10 -5.335068e+08 176 205 -1.725352e+09 8.626761e+07 176 206 -2.667534e+09 1.333767e+08 176 211 -1.738727e+08 8.693635e+06 176 212 -3.752381e+09 1.876190e+08 177 177 1.450425e+06 -7.252126e+04 177 207 -3.626063e+05 1.813032e+04 177 213 -2.793852e+05 1.396926e+04 178 178 1.780771e+08 -8.903855e+06 178 179 -5.820766e-11 2.910383e-12 178 204 1.582687e+08 -7.913437e+06 178 208 2.142603e+07 -1.071302e+06 178 209 3.594484e+05 -1.797242e+04 178 210 3.165375e+08 -1.582687e+07 178 214 4.318179e+07 -2.159090e+06 178 215 3.622348e+04 -1.811174e+03 179 179 1.777256e+08 -8.886282e+06 179 204 -1.318906e+08 6.594531e+06 179 208 3.594484e+05 -1.797242e+04 179 209 2.151390e+07 -1.075695e+06 179 210 1.318906e+08 -6.594531e+06 179 214 -3.622348e+04 1.811174e+03 179 215 4.395660e+07 -2.197830e+06 204 204 1.029802e+10 -5.149009e+08 204 208 1.192093e-07 -5.960464e-09 204 209 0.000000e+00 -0.000000e+00 204 210 -5.908699e+08 2.954350e+07 204 214 -5.960464e-08 2.980232e-09 204 215 -5.275624e+08 2.637812e+07 204 234 -1.287252e+09 6.436262e+07 204 238 -1.582687e+08 7.913437e+06 204 239 1.318906e+08 -6.594531e+06 204 240 -1.983635e+09 9.918174e+07 204 244 -6.330749e+08 3.165375e+07 204 245 0.000000e+00 -0.000000e+00 204 246 -1.287252e+09 6.436262e+07 204 250 -1.582687e+08 7.913437e+06 204 251 -1.318906e+08 6.594531e+06 205 205 1.796625e+10 -8.983125e+08 205 206 0.000000e+00 -0.000000e+00 205 211 -4.424986e+09 2.212493e+08 205 212 2.086163e-07 -1.043081e-08 205 235 -2.245781e+09 1.122891e+08 205 236 -1.725352e+09 8.626761e+07 205 241 -6.657689e+07 3.328845e+06 205 242 -2.086163e-07 1.043081e-08 205 247 -2.245781e+09 1.122891e+08 205 248 1.725352e+09 -8.626761e+07 206 206 2.134027e+10 -1.067014e+09 206 211 0.000000e+00 -0.000000e+00 206 212 2.169693e+09 -1.084847e+08 206 235 -1.725352e+09 8.626761e+07 206 236 -2.667534e+09 1.333767e+08 206 241 -4.768372e-07 2.384186e-08 206 242 -7.504762e+09 3.752381e+08 206 247 1.725352e+09 -8.626761e+07 206 248 -2.667534e+09 1.333767e+08 207 207 2.900850e+06 -1.450425e+05 207 213 -1.664422e+05 8.322112e+03 207 237 -3.626063e+05 1.813032e+04 207 243 -5.587704e+05 2.793852e+04 207 249 -3.626063e+05 1.813032e+04 208 208 3.561542e+08 -1.780771e+07 208 209 5.820766e-11 -2.910383e-12 208 210 -5.960464e-08 2.980232e-09 208 214 8.837909e+07 -4.418955e+06 208 215 -7.275958e-12 3.637979e-13 208 234 1.582687e+08 -7.913437e+06 208 238 2.142603e+07 -1.071302e+06 208 239 3.594484e+05 -1.797242e+04 208 240 6.330749e+08 -3.165375e+07 208 244 8.636358e+07 -4.318179e+06 208 245 7.275958e-12 -3.637979e-13 208 246 1.582687e+08 -7.913437e+06 208 250 2.142603e+07 -1.071302e+06 208 251 -3.594484e+05 1.797242e+04 209 209 3.554513e+08 -1.777256e+07 209 210 5.275624e+08 -2.637812e+07 209 214 3.637979e-11 -1.818989e-12 209 215 8.700520e+07 -4.350260e+06 209 234 -1.318906e+08 6.594531e+06 209 238 3.594484e+05 -1.797242e+04 209 239 2.151390e+07 -1.075695e+06 209 240 -4.470348e-08 2.235174e-09 209 244 6.548362e-11 -3.274181e-12 209 245 8.791320e+07 -4.395660e+06 209 246 1.318906e+08 -6.594531e+06 209 250 -3.594484e+05 1.797242e+04 209 251 2.151390e+07 -1.075695e+06 210 210 5.149009e+09 -2.574505e+08 210 214 5.960464e-08 -2.980232e-09 210 215 5.275624e+08 -2.637812e+07 210 240 -1.287252e+09 6.436262e+07 210 244 -1.582687e+08 7.913437e+06 210 245 1.318906e+08 -6.594531e+06 210 246 -9.918174e+08 4.959087e+07 210 250 -3.165375e+08 1.582687e+07 210 251 1.318906e+08 -6.594531e+06 211 211 8.983125e+09 -4.491563e+08 211 212 -2.384186e-07 1.192093e-08 211 241 -2.245781e+09 1.122891e+08 211 242 -1.725352e+09 8.626761e+07 211 247 -3.328845e+07 1.664422e+06 211 248 1.738727e+08 -8.693635e+06 212 212 1.067014e+10 -5.335068e+08 212 241 -1.725352e+09 8.626761e+07 212 242 -2.667534e+09 1.333767e+08 212 247 -1.738727e+08 8.693635e+06 212 248 -3.752381e+09 1.876190e+08 213 213 1.450425e+06 -7.252126e+04 213 243 -3.626063e+05 1.813032e+04 213 249 -2.793852e+05 1.396926e+04 214 214 1.780771e+08 -8.903855e+06 214 215 -5.820766e-11 2.910383e-12 214 240 1.582687e+08 -7.913437e+06 214 244 2.142603e+07 -1.071302e+06 214 245 3.594484e+05 -1.797242e+04 214 246 3.165375e+08 -1.582687e+07 214 250 4.318179e+07 -2.159090e+06 214 251 3.622348e+04 -1.811174e+03 215 215 1.777256e+08 -8.886282e+06 215 240 -1.318906e+08 6.594531e+06 215 244 3.594484e+05 -1.797242e+04 215 245 2.151390e+07 -1.075695e+06 215 246 1.318906e+08 -6.594531e+06 215 250 -3.622348e+04 1.811174e+03 215 251 4.395660e+07 -2.197830e+06 240 240 5.149009e+09 -2.574505e+08 240 244 6.330749e+08 -3.165375e+07 240 245 -1.192093e-07 5.960464e-09 240 246 -2.954350e+08 1.477175e+07 240 250 1.582687e+08 -7.913437e+06 240 251 -2.637812e+08 1.318906e+07 241 241 8.983125e+09 -4.491563e+08 241 242 4.768372e-07 -2.384186e-08 241 247 -2.212493e+09 1.106246e+08 241 248 -1.738727e+08 8.693635e+06 242 242 1.067014e+10 -5.335068e+08 242 247 1.738727e+08 -8.693635e+06 242 248 1.084847e+09 -5.424234e+07 243 243 1.450425e+06 -7.252126e+04 243 249 -8.322112e+04 4.161056e+03 244 244 1.780771e+08 -8.903855e+06 244 245 -5.820766e-11 2.910383e-12 244 246 1.582687e+08 -7.913437e+06 244 250 4.418955e+07 -2.209477e+06 244 251 -3.622348e+04 1.811174e+03 245 245 1.777256e+08 -8.886282e+06 245 246 2.637812e+08 -1.318906e+07 245 250 3.622348e+04 -1.811174e+03 245 251 4.350260e+07 -2.175130e+06 246 246 2.574505e+09 -1.287252e+08 246 250 3.165375e+08 -1.582687e+07 246 251 2.637812e+08 -1.318906e+07 247 247 4.491563e+09 -2.245781e+08 247 248 -1.725352e+09 8.626761e+07 248 248 5.335068e+09 -2.667534e+08 249 249 7.252126e+05 -3.626063e+04 250 250 8.903855e+07 -4.451927e+06 250 251 3.594484e+05 -1.797242e+04 251 251 8.886282e+07 -4.443141e+06 132 132 -1.301143e+10 0.000000e+00 132 138 -3.252857e+09 0.000000e+00 132 162 -8.132143e+08 0.000000e+00 132 168 -3.252857e+09 0.000000e+00 132 174 -8.132143e+08 0.000000e+00 133 133 -1.301143e+10 0.000000e+00 133 134 -1.624548e-23 0.000000e+00 133 139 -3.252857e+09 0.000000e+00 133 163 -8.132143e+08 0.000000e+00 133 169 -3.252857e+09 0.000000e+00 133 170 -6.306821e-24 0.000000e+00 133 175 -8.132143e+08 0.000000e+00 134 134 -1.301143e+10 0.000000e+00 134 140 -3.252857e+09 0.000000e+00 134 164 -8.132143e+08 0.000000e+00 134 169 6.306821e-24 -0.000000e+00 134 170 -3.252857e+09 0.000000e+00 134 176 -8.132143e+08 0.000000e+00 136 136 -2.710714e+06 0.000000e+00 136 142 -6.776786e+05 0.000000e+00 136 166 -1.694196e+05 0.000000e+00 136 172 -6.776786e+05 0.000000e+00 136 178 -1.694196e+05 0.000000e+00 137 137 -2.710714e+06 0.000000e+00 137 143 -6.776786e+05 0.000000e+00 137 167 -1.694196e+05 0.000000e+00 137 173 -6.776786e+05 0.000000e+00 137 179 -1.694196e+05 0.000000e+00 138 138 -6.505714e+09 0.000000e+00 138 168 -8.132143e+08 0.000000e+00 138 174 -1.626429e+09 0.000000e+00 139 139 -6.505714e+09 0.000000e+00 139 140 -8.122739e-24 0.000000e+00 139 169 -8.132143e+08 0.000000e+00 139 175 -1.626429e+09 0.000000e+00 140 140 -6.505714e+09 0.000000e+00 140 170 -8.132143e+08 0.000000e+00 140 176 -1.626429e+09 0.000000e+00 142 142 -1.355357e+06 0.000000e+00 142 172 -1.694196e+05 0.000000e+00 142 178 -3.388393e+05 0.000000e+00 143 143 -1.355357e+06 0.000000e+00 143 173 -1.694196e+05 0.000000e+00 143 179 -3.388393e+05 0.000000e+00 168 168 -1.301143e+10 0.000000e+00 168 174 -3.252857e+09 0.000000e+00 168 198 -8.132143e+08 0.000000e+00 168 204 -3.252857e+09 0.000000e+00 168 210 -8.132143e+08 0.000000e+00 169 169 -1.301143e+10 0.000000e+00 169 170 -3.228433e-23 0.000000e+00 169 175 -3.252857e+09 0.000000e+00 169 199 -8.132143e+08 0.000000e+00 169 205 -3.252857e+09 0.000000e+00 169 211 -8.132143e+08 0.000000e+00 170 170 -1.301143e+10 0.000000e+00 170 176 -3.252857e+09 0.000000e+00 170 200 -8.132143e+08 0.000000e+00 170 206 -3.252857e+09 0.000000e+00 170 212 -8.132143e+08 0.000000e+00 172 172 -2.710714e+06 0.000000e+00 172 178 -6.776786e+05 0.000000e+00 172 202 -1.694196e+05 0.000000e+00 172 208 -6.776786e+05 0.000000e+00 172 214 -1.694196e+05 0.000000e+00 173 173 -2.710714e+06 0.000000e+00 173 179 -6.776786e+05 0.000000e+00 173 203 -1.694196e+05 0.000000e+00 173 209 -6.776786e+05 0.000000e+00 173 215 -1.694196e+05 0.000000e+00 174 174 -6.505714e+09 0.000000e+00 174 204 -8.132143e+08 0.000000e+00 174 210 -1.626429e+09 0.000000e+00 175 175 -6.505714e+09 0.000000e+00 175 176 -1.592926e-23 0.000000e+00 175 205 -8.132143e+08 0.000000e+00 175 211 -1.626429e+09 0.000000e+00 176 176 -6.505714e+09 0.000000e+00 176 206 -8.132143e+08 0.000000e+00 176 212 -1.626429e+09 0.000000e+00 178 178 -1.355357e+06 0.000000e+00 178 208 -1.694196e+05 0.000000e+00 178 214 -3.388393e+05 0.000000e+00 179 179 -1.355357e+06 0.000000e+00 179 209 -1.694196e+05 0.000000e+00 179 215 -3.388393e+05 0.000000e+00 204 204 -1.301143e+10 0.000000e+00 204 210 -3.252857e+09 0.000000e+00 204 234 -8.132143e+08 0.000000e+00 204 240 -3.252857e+09 0.000000e+00 204 246 -8.132143e+08 0.000000e+00 205 205 -1.301143e+10 0.000000e+00 205 211 -3.252857e+09 0.000000e+00 205 235 -8.132143e+08 0.000000e+00 205 241 -3.252857e+09 0.000000e+00 205 247 -8.132143e+08 0.000000e+00 206 206 -1.301143e+10 0.000000e+00 206 212 -3.252857e+09 0.000000e+00 206 236 -8.132143e+08 0.000000e+00 206 242 -3.252857e+09 0.000000e+00 206 248 -8.132143e+08 0.000000e+00 208 208 -2.710714e+06 0.000000e+00 208 214 -6.776786e+05 0.000000e+00 208 238 -1.694196e+05 0.000000e+00 208 244 -6.776786e+05 0.000000e+00 208 250 -1.694196e+05 0.000000e+00 209 209 -2.710714e+06 0.000000e+00 209 215 -6.776786e+05 0.000000e+00 209 239 -1.694196e+05 0.000000e+00 209 245 -6.776786e+05 0.000000e+00 209 251 -1.694196e+05 0.000000e+00 210 210 -6.505714e+09 0.000000e+00 210 240 -8.132143e+08 0.000000e+00 210 246 -1.626429e+09 0.000000e+00 211 211 -6.505714e+09 0.000000e+00 211 241 -8.132143e+08 0.000000e+00 211 247 -1.626429e+09 0.000000e+00 212 212 -6.505714e+09 0.000000e+00 212 242 -8.132143e+08 0.000000e+00 212 248 -1.626429e+09 0.000000e+00 214 214 -1.355357e+06 0.000000e+00 214 244 -1.694196e+05 0.000000e+00 214 250 -3.388393e+05 0.000000e+00 215 215 -1.355357e+06 0.000000e+00 215 245 -1.694196e+05 0.000000e+00 215 251 -3.388393e+05 0.000000e+00 240 240 -6.505714e+09 0.000000e+00 240 246 -1.626429e+09 0.000000e+00 241 241 -6.505714e+09 0.000000e+00 241 247 -1.626429e+09 0.000000e+00 242 242 -6.505714e+09 0.000000e+00 242 248 -1.626429e+09 0.000000e+00 244 244 -1.355357e+06 0.000000e+00 244 250 -3.388393e+05 0.000000e+00 245 245 -1.355357e+06 0.000000e+00 245 251 -3.388393e+05 0.000000e+00 246 246 -3.252857e+09 0.000000e+00 247 247 -3.252857e+09 0.000000e+00 248 248 -3.252857e+09 0.000000e+00 250 250 -6.776786e+05 0.000000e+00 251 251 -6.776786e+05 0.000000e+0 162 162 1.029802e+10 -5.149009e+08 162 166 2.384186e-07 -1.192093e-08 162 167 -8.940697e-08 4.470348e-09 162 168 -5.908699e+08 2.954350e+07 162 172 2.980232e-08 -1.490116e-09 162 173 -5.275624e+08 2.637812e+07 162 192 -1.287252e+09 6.436262e+07 162 196 -1.582687e+08 7.913437e+06 162 197 1.318906e+08 -6.594531e+06 162 198 -1.983635e+09 9.918174e+07 162 202 -6.330749e+08 3.165375e+07 162 203 -4.470348e-08 2.235174e-09 162 204 -1.287252e+09 6.436262e+07 162 208 -1.582687e+08 7.913437e+06 162 209 -1.318906e+08 6.594531e+06 163 163 1.796625e+10 -8.983125e+08 163 164 4.768372e-07 -2.384186e-08 163 169 -4.424986e+09 2.212493e+08 163 170 -1.788139e-07 8.940697e-09 163 193 -2.245781e+09 1.122891e+08 163 194 -1.725352e+09 8.626761e+07 163 199 -6.657689e+07 3.328845e+06 163 200 2.384186e-07 -1.192093e-08 163 205 -2.245781e+09 1.122891e+08 163 206 1.725352e+09 -8.626761e+07 164 164 2.134027e+10 -1.067014e+09 164 169 -5.960464e-08 2.980232e-09 164 170 2.169693e+09 -1.084847e+08 164 193 -1.725352e+09 8.626761e+07 164 194 -2.667534e+09 1.333767e+08 164 199 -2.980232e-08 1.490116e-09 164 200 -7.504762e+09 3.752381e+08 164 205 1.725352e+09 -8.626761e+07 164 206 -2.667534e+09 1.333767e+08 165 165 2.900850e+06 -1.450425e+05 165 171 -1.664422e+05 8.322112e+03 165 195 -3.626063e+05 1.813032e+04 165 201 -5.587704e+05 2.793852e+04 165 207 -3.626063e+05 1.813032e+04 166 166 3.561542e+08 -1.780771e+07 166 167 1.746230e-10 -8.731149e-12 166 168 -5.960464e-08 2.980232e-09 166 172 8.837909e+07 -4.418955e+06 166 173 2.910383e-11 -1.455192e-12 166 192 1.582687e+08 -7.913437e+06 166 196 2.142603e+07 -1.071302e+06 166 197 3.594484e+05 -1.797242e+04 166 198 6.330749e+08 -3.165375e+07 166 202 8.636358e+07 -4.318179e+06 166 203 5.820766e-11 -2.910383e-12 166 204 1.582687e+08 -7.913437e+06 166 208 2.142603e+07 -1.071302e+06 166 209 -3.594484e+05 1.797242e+04 167 167 3.554513e+08 -1.777256e+07 167 168 5.275624e+08 -2.637812e+07 167 172 8.731149e-11 -4.365575e-12 167 173 8.700520e+07 -4.350260e+06 167 192 -1.318906e+08 6.594531e+06 167 196 3.594484e+05 -1.797242e+04 167 197 2.151390e+07 -1.075695e+06 167 198 -1.490116e-08 7.450581e-10 167 202 0.000000e+00 -0.000000e+00 167 203 8.791320e+07 -4.395660e+06 167 204 1.318906e+08 -6.594531e+06 167 208 -3.594484e+05 1.797242e+04 167 209 2.151390e+07 -1.075695e+06 180 180 5.149009e+09 -2.574505e+08 180 184 5.960464e-08 -2.980232e-09 180 185 -5.275624e+08 2.637812e+07 180 186 -5.908699e+08 2.954350e+07 180 190 0.000000e+00 -0.000000e+00 180 191 -5.275624e+08 2.637812e+07 180 216 -9.918174e+08 4.959087e+07 180 220 -3.165375e+08 1.582687e+07 180 221 -1.318906e+08 6.594531e+06 180 222 -1.287252e+09 6.436262e+07 180 226 -1.582687e+08 7.913437e+06 180 227 -1.318906e+08 6.594531e+06 181 181 8.983125e+09 -4.491563e+08 181 182 -2.384186e-07 1.192093e-08 181 187 -4.424986e+09 2.212493e+08 181 188 2.980232e-08 -1.490116e-09 181 217 -3.328845e+07 1.664422e+06 181 218 -1.738727e+08 8.693635e+06 181 223 -2.245781e+09 1.122891e+08 181 224 1.725352e+09 -8.626761e+07 182 182 1.067014e+10 -5.335068e+08 182 187 5.960464e-08 -2.980232e-09 182 188 2.169693e+09 -1.084847e+08 182 217 1.738727e+08 -8.693635e+06 182 218 -3.752381e+09 1.876190e+08 182 223 1.725352e+09 -8.626761e+07 182 224 -2.667534e+09 1.333767e+08 183 183 1.450425e+06 -7.252126e+04 183 189 -1.664422e+05 8.322112e+03 183 219 -2.793852e+05 1.396926e+04 183 225 -3.626063e+05 1.813032e+04 184 184 1.780771e+08 -8.903855e+06 184 185 0.000000e+00 -0.000000e+00 184 186 0.000000e+00 -0.000000e+00 184 190 8.837909e+07 -4.418955e+06 184 191 7.275958e-12 -3.637979e-13 184 216 3.165375e+08 -1.582687e+07 184 220 4.318179e+07 -2.159090e+06 184 221 -3.622348e+04 1.811174e+03 184 222 1.582687e+08 -7.913437e+06 184 226 2.142603e+07 -1.071302e+06 184 227 -3.594484e+05 1.797242e+04 185 185 1.777256e+08 -8.886282e+06 185 186 5.275624e+08 -2.637812e+07 185 190 1.455192e-11 -7.275958e-13 185 191 8.700520e+07 -4.350260e+06 185 216 -1.318906e+08 6.594531e+06 185 220 3.622348e+04 -1.811174e+03 185 221 4.395660e+07 -2.197830e+06 185 222 1.318906e+08 -6.594531e+06 185 226 -3.594484e+05 1.797242e+04 185 227 2.151390e+07 -1.075695e+06 186 186 1.029802e+10 -5.149009e+08 186 190 1.788139e-07 -8.940697e-09 186 191 -2.980232e-08 1.490116e-09 186 192 -5.908699e+08 2.954350e+07 186 196 -5.960464e-08 2.980232e-09 186 197 -5.275624e+08 2.637812e+07 186 216 -1.287252e+09 6.436262e+07 186 220 -1.582687e+08 7.913437e+06 186 221 1.318906e+08 -6.594531e+06 186 222 -1.983635e+09 9.918174e+07 186 226 -6.330749e+08 3.165375e+07 186 227 0.000000e+00 -0.000000e+00 186 228 -1.287252e+09 6.436262e+07 186 232 -1.582687e+08 7.913437e+06 186 233 -1.318906e+08 6.594531e+06 187 187 1.796625e+10 -8.983125e+08 187 188 -2.384186e-07 1.192093e-08 187 193 -4.424986e+09 2.212493e+08 187 194 1.788139e-07 -8.940697e-09 187 217 -2.245781e+09 1.122891e+08 187 218 -1.725352e+09 8.626761e+07 187 223 -6.657689e+07 3.328845e+06 187 224 -2.682209e-07 1.341105e-08 187 229 -2.245781e+09 1.122891e+08 187 230 1.725352e+09 -8.626761e+07 188 188 2.134027e+10 -1.067014e+09 188 193 1.192093e-07 -5.960464e-09 188 194 2.169693e+09 -1.084847e+08 188 217 -1.725352e+09 8.626761e+07 188 218 -2.667534e+09 1.333767e+08 188 223 -3.874302e-07 1.937151e-08 188 224 -7.504762e+09 3.752381e+08 188 229 1.725352e+09 -8.626761e+07 188 230 -2.667534e+09 1.333767e+08 189 189 2.900850e+06 -1.450425e+05 189 195 -1.664422e+05 8.322112e+03 189 219 -3.626063e+05 1.813032e+04 189 225 -5.587704e+05 2.793852e+04 189 231 -3.626063e+05 1.813032e+04 190 190 3.561542e+08 -1.780771e+07 190 191 0.000000e+00 -0.000000e+00 190 192 -2.980232e-08 1.490116e-09 190 196 8.837909e+07 -4.418955e+06 190 197 -5.093170e-11 2.546585e-12 190 216 1.582687e+08 -7.913437e+06 190 220 2.142603e+07 -1.071302e+06 190 221 3.594484e+05 -1.797242e+04 190 222 6.330749e+08 -3.165375e+07 190 226 8.636358e+07 -4.318179e+06 190 227 7.275958e-12 -3.637979e-13 190 228 1.582687e+08 -7.913437e+06 190 232 2.142603e+07 -1.071302e+06 190 233 -3.594484e+05 1.797242e+04 191 191 3.554513e+08 -1.777256e+07 191 192 5.275624e+08 -2.637812e+07 191 196 -2.910383e-11 1.455192e-12 191 197 8.700520e+07 -4.350260e+06 191 216 -1.318906e+08 6.594531e+06 191 220 3.594484e+05 -1.797242e+04 191 221 2.151390e+07 -1.075695e+06 191 222 -4.470348e-08 2.235174e-09 191 226 5.820766e-11 -2.910383e-12 191 227 8.791320e+07 -4.395660e+06 191 228 1.318906e+08 -6.594531e+06 191 232 -3.594484e+05 1.797242e+04 191 233 2.151390e+07 -1.075695e+06 192 192 1.029802e+10 -5.149009e+08 192 196 2.384186e-07 -1.192093e-08 192 197 -2.980232e-08 1.490116e-09 192 198 -5.908699e+08 2.954350e+07 192 202 -1.192093e-07 5.960464e-09 192 203 -5.275624e+08 2.637812e+07 192 222 -1.287252e+09 6.436262e+07 192 226 -1.582687e+08 7.913437e+06 192 227 1.318906e+08 -6.594531e+06 192 228 -1.983635e+09 9.918174e+07 192 232 -6.330749e+08 3.165375e+07 192 233 0.000000e+00 -0.000000e+00 192 234 -1.287252e+09 6.436262e+07 192 238 -1.582687e+08 7.913437e+06 192 239 -1.318906e+08 6.594531e+06 193 193 1.796625e+10 -8.983125e+08 193 194 -7.152557e-07 3.576279e-08 193 199 -4.424986e+09 2.212493e+08 193 200 4.172325e-07 -2.086163e-08 193 223 -2.245781e+09 1.122891e+08 193 224 -1.725352e+09 8.626761e+07 193 229 -6.657689e+07 3.328845e+06 193 230 -2.384186e-07 1.192093e-08 193 235 -2.245781e+09 1.122891e+08 193 236 1.725352e+09 -8.626761e+07 194 194 2.134027e+10 -1.067014e+09 194 199 5.364418e-07 -2.682209e-08 194 200 2.169693e+09 -1.084847e+08 194 223 -1.725352e+09 8.626761e+07 194 224 -2.667534e+09 1.333767e+08 194 229 -5.960464e-07 2.980232e-08 194 230 -7.504762e+09 3.752381e+08 194 235 1.725352e+09 -8.626761e+07 194 236 -2.667534e+09 1.333767e+08 195 195 2.900850e+06 -1.450425e+05 195 201 -1.664422e+05 8.322112e+03 195 225 -3.626063e+05 1.813032e+04 195 231 -5.587704e+05 2.793852e+04 195 237 -3.626063e+05 1.813032e+04 196 196 3.561542e+08 -1.780771e+07 196 197 5.820766e-11 -2.910383e-12 196 198 -2.980232e-08 1.490116e-09 196 202 8.837909e+07 -4.418955e+06 196 203 -9.458745e-11 4.729372e-12 196 222 1.582687e+08 -7.913437e+06 196 226 2.142603e+07 -1.071302e+06 196 227 3.594484e+05 -1.797242e+04 196 228 6.330749e+08 -3.165375e+07 196 232 8.636358e+07 -4.318179e+06 196 233 7.275958e-11 -3.637979e-12 196 234 1.582687e+08 -7.913437e+06 196 238 2.142603e+07 -1.071302e+06 196 239 -3.594484e+05 1.797242e+04 197 197 3.554513e+08 -1.777256e+07 197 198 5.275624e+08 -2.637812e+07 197 202 -1.018634e-10 5.093170e-12 197 203 8.700520e+07 -4.350260e+06 197 222 -1.318906e+08 6.594531e+06 197 226 3.594484e+05 -1.797242e+04 197 227 2.151390e+07 -1.075695e+06 197 228 -4.470348e-08 2.235174e-09 197 232 6.548362e-11 -3.274181e-12 197 233 8.791320e+07 -4.395660e+06 197 234 1.318906e+08 -6.594531e+06 197 238 -3.594484e+05 1.797242e+04 197 239 2.151390e+07 -1.075695e+06 198 198 1.029802e+10 -5.149009e+08 198 202 2.980232e-07 -1.490116e-08 198 203 -2.980232e-08 1.490116e-09 198 204 -5.908699e+08 2.954350e+07 198 208 2.980232e-08 -1.490116e-09 198 209 -5.275624e+08 2.637812e+07 198 228 -1.287252e+09 6.436262e+07 198 232 -1.582687e+08 7.913437e+06 198 233 1.318906e+08 -6.594531e+06 198 234 -1.983635e+09 9.918174e+07 198 238 -6.330749e+08 3.165375e+07 198 239 0.000000e+00 -0.000000e+00 198 240 -1.287252e+09 6.436262e+07 198 244 -1.582687e+08 7.913437e+06 198 245 -1.318906e+08 6.594531e+06 199 199 1.796625e+10 -8.983125e+08 199 200 -2.384186e-07 1.192093e-08 199 205 -4.424986e+09 2.212493e+08 199 206 -2.086163e-07 1.043081e-08 199 229 -2.245781e+09 1.122891e+08 199 230 -1.725352e+09 8.626761e+07 199 235 -6.657689e+07 3.328845e+06 199 236 -2.086163e-07 1.043081e-08 199 241 -2.245781e+09 1.122891e+08 199 242 1.725352e+09 -8.626761e+07 200 200 2.134027e+10 -1.067014e+09 200 205 -2.086163e-07 1.043081e-08 200 206 2.169693e+09 -1.084847e+08 200 229 -1.725352e+09 8.626761e+07 200 230 -2.667534e+09 1.333767e+08 200 235 -3.874302e-07 1.937151e-08 200 236 -7.504762e+09 3.752381e+08 200 241 1.725352e+09 -8.626761e+07 200 242 -2.667534e+09 1.333767e+08 201 201 2.900850e+06 -1.450425e+05 201 207 -1.664422e+05 8.322112e+03 201 231 -3.626063e+05 1.813032e+04 201 237 -5.587704e+05 2.793852e+04 201 243 -3.626063e+05 1.813032e+04 202 202 3.561542e+08 -1.780771e+07 202 203 1.746230e-10 -8.731149e-12 202 204 -5.960464e-08 2.980232e-09 202 208 8.837909e+07 -4.418955e+06 202 209 6.548362e-11 -3.274181e-12 202 228 1.582687e+08 -7.913437e+06 202 232 2.142603e+07 -1.071302e+06 202 233 3.594484e+05 -1.797242e+04 202 234 6.330749e+08 -3.165375e+07 202 238 8.636358e+07 -4.318179e+06 202 239 5.820766e-11 -2.910383e-12 202 240 1.582687e+08 -7.913437e+06 202 244 2.142603e+07 -1.071302e+06 202 245 -3.594484e+05 1.797242e+04 203 203 3.554513e+08 -1.777256e+07 203 204 5.275624e+08 -2.637812e+07 203 208 7.275958e-11 -3.637979e-12 203 209 8.700520e+07 -4.350260e+06 203 228 -1.318906e+08 6.594531e+06 203 232 3.594484e+05 -1.797242e+04 203 233 2.151390e+07 -1.075695e+06 203 234 -4.470348e-08 2.235174e-09 203 238 2.182787e-11 -1.091394e-12 203 239 8.791320e+07 -4.395660e+06 203 240 1.318906e+08 -6.594531e+06 203 244 -3.594484e+05 1.797242e+04 203 245 2.151390e+07 -1.075695e+06 216 216 2.574505e+09 -1.287252e+08 216 220 3.165375e+08 -1.582687e+07 216 221 -2.637812e+08 1.318906e+07 216 222 -2.954350e+08 1.477175e+07 216 226 1.582687e+08 -7.913437e+06 216 227 -2.637812e+08 1.318906e+07 217 217 4.491563e+09 -2.245781e+08 217 218 1.725352e+09 -8.626761e+07 217 223 -2.212493e+09 1.106246e+08 217 224 -1.738727e+08 8.693635e+06 218 218 5.335068e+09 -2.667534e+08 218 223 1.738727e+08 -8.693635e+06 218 224 1.084847e+09 -5.424234e+07 219 219 7.252126e+05 -3.626063e+04 219 225 -8.322112e+04 4.161056e+03 220 220 8.903855e+07 -4.451927e+06 220 221 -3.594484e+05 1.797242e+04 220 222 1.582687e+08 -7.913437e+06 220 226 4.418955e+07 -2.209477e+06 220 227 -3.622348e+04 1.811174e+03 221 221 8.886282e+07 -4.443141e+06 221 222 2.637812e+08 -1.318906e+07 221 226 3.622348e+04 -1.811174e+03 221 227 4.350260e+07 -2.175130e+06 222 222 5.149009e+09 -2.574505e+08 222 226 6.330749e+08 -3.165375e+07 222 227 0.000000e+00 -0.000000e+00 222 228 -2.954350e+08 1.477175e+07 222 232 1.582687e+08 -7.913437e+06 222 233 -2.637812e+08 1.318906e+07 223 223 8.983125e+09 -4.491563e+08 223 224 2.384186e-07 -1.192093e-08 223 229 -2.212493e+09 1.106246e+08 223 230 -1.738727e+08 8.693635e+06 224 224 1.067014e+10 -5.335068e+08 224 229 1.738727e+08 -8.693635e+06 224 230 1.084847e+09 -5.424234e+07 225 225 1.450425e+06 -7.252126e+04 225 231 -8.322112e+04 4.161056e+03 226 226 1.780771e+08 -8.903855e+06 226 227 5.820766e-11 -2.910383e-12 226 228 1.582687e+08 -7.913437e+06 226 232 4.418955e+07 -2.209477e+06 226 233 -3.622348e+04 1.811174e+03 227 227 1.777256e+08 -8.886282e+06 227 228 2.637812e+08 -1.318906e+07 227 232 3.622348e+04 -1.811174e+03 227 233 4.350260e+07 -2.175130e+06 228 228 5.149009e+09 -2.574505e+08 228 232 6.330749e+08 -3.165375e+07 228 233 0.000000e+00 -0.000000e+00 228 234 -2.954350e+08 1.477175e+07 228 238 1.582687e+08 -7.913437e+06 228 239 -2.637812e+08 1.318906e+07 229 229 8.983125e+09 -4.491563e+08 229 230 -4.768372e-07 2.384186e-08 229 235 -2.212493e+09 1.106246e+08 229 236 -1.738727e+08 8.693635e+06 230 230 1.067014e+10 -5.335068e+08 230 235 1.738727e+08 -8.693635e+06 230 236 1.084847e+09 -5.424234e+07 231 231 1.450425e+06 -7.252126e+04 231 237 -8.322112e+04 4.161056e+03 232 232 1.780771e+08 -8.903855e+06 232 233 0.000000e+00 -0.000000e+00 232 234 1.582687e+08 -7.913437e+06 232 238 4.418955e+07 -2.209477e+06 232 239 -3.622348e+04 1.811174e+03 233 233 1.777256e+08 -8.886282e+06 233 234 2.637812e+08 -1.318906e+07 233 238 3.622348e+04 -1.811174e+03 233 239 4.350260e+07 -2.175130e+06 234 234 5.149009e+09 -2.574505e+08 234 238 6.330749e+08 -3.165375e+07 234 239 0.000000e+00 -0.000000e+00 234 240 -2.954350e+08 1.477175e+07 234 244 1.582687e+08 -7.913437e+06 234 245 -2.637812e+08 1.318906e+07 235 235 8.983125e+09 -4.491563e+08 235 236 0.000000e+00 -0.000000e+00 235 241 -2.212493e+09 1.106246e+08 235 242 -1.738727e+08 8.693635e+06 236 236 1.067014e+10 -5.335068e+08 236 241 1.738727e+08 -8.693635e+06 236 242 1.084847e+09 -5.424234e+07 237 237 1.450425e+06 -7.252126e+04 237 243 -8.322112e+04 4.161056e+03 238 238 1.780771e+08 -8.903855e+06 238 239 0.000000e+00 -0.000000e+00 238 240 1.582687e+08 -7.913437e+06 238 244 4.418955e+07 -2.209477e+06 238 245 -3.622348e+04 1.811174e+03 239 239 1.777256e+08 -8.886282e+06 239 240 2.637812e+08 -1.318906e+07 239 244 3.622348e+04 -1.811174e+03 239 245 4.350260e+07 -2.175130e+06 162 162 -1.301143e+10 0.000000e+00 162 168 -3.252857e+09 0.000000e+00 162 192 -8.132143e+08 0.000000e+00 162 198 -3.252857e+09 0.000000e+00 162 204 -8.132143e+08 0.000000e+00 163 163 -1.301143e+10 0.000000e+00 163 164 -3.271014e-23 0.000000e+00 163 169 -3.252857e+09 0.000000e+00 163 193 -8.132143e+08 0.000000e+00 163 199 -3.252857e+09 0.000000e+00 163 205 -8.132143e+08 0.000000e+00 164 164 -1.301143e+10 0.000000e+00 164 170 -3.252857e+09 0.000000e+00 164 194 -8.132143e+08 0.000000e+00 164 200 -3.252857e+09 0.000000e+00 164 206 -8.132143e+08 0.000000e+00 166 166 -2.710714e+06 0.000000e+00 166 172 -6.776786e+05 0.000000e+00 166 196 -1.694196e+05 0.000000e+00 166 202 -6.776786e+05 0.000000e+00 166 208 -1.694196e+05 0.000000e+00 167 167 -2.710714e+06 0.000000e+00 167 173 -6.776786e+05 0.000000e+00 167 197 -1.694196e+05 0.000000e+00 167 203 -6.776786e+05 0.000000e+00 167 209 -1.694196e+05 0.000000e+00 180 180 -6.505714e+09 0.000000e+00 180 186 -3.252857e+09 0.000000e+00 180 216 -1.626429e+09 0.000000e+00 180 222 -8.132143e+08 0.000000e+00 181 181 -6.505714e+09 0.000000e+00 181 187 -3.252857e+09 0.000000e+00 181 217 -1.626429e+09 0.000000e+00 181 223 -8.132143e+08 0.000000e+00 182 182 -6.505714e+09 0.000000e+00 182 188 -3.252857e+09 0.000000e+00 182 218 -1.626429e+09 0.000000e+00 182 224 -8.132143e+08 0.000000e+00 184 184 -1.355357e+06 0.000000e+00 184 190 -6.776786e+05 0.000000e+00 184 220 -3.388393e+05 0.000000e+00 184 226 -1.694196e+05 0.000000e+00 185 185 -1.355357e+06 0.000000e+00 185 191 -6.776786e+05 0.000000e+00 185 221 -3.388393e+05 0.000000e+00 185 227 -1.694196e+05 0.000000e+00 186 186 -1.301143e+10 0.000000e+00 186 192 -3.252857e+09 0.000000e+00 186 216 -8.132143e+08 0.000000e+00 186 222 -3.252857e+09 0.000000e+00 186 228 -8.132143e+08 0.000000e+00 187 187 -1.301143e+10 0.000000e+00 187 193 -3.252857e+09 0.000000e+00 187 217 -8.132143e+08 0.000000e+00 187 223 -3.252857e+09 0.000000e+00 187 229 -8.132143e+08 0.000000e+00 188 188 -1.301143e+10 0.000000e+00 188 194 -3.252857e+09 0.000000e+00 188 218 -8.132143e+08 0.000000e+00 188 224 -3.252857e+09 0.000000e+00 188 230 -8.132143e+08 0.000000e+00 190 190 -2.710714e+06 0.000000e+00 190 196 -6.776786e+05 0.000000e+00 190 220 -1.694196e+05 0.000000e+00 190 226 -6.776786e+05 0.000000e+00 190 232 -1.694196e+05 0.000000e+00 191 191 -2.710714e+06 0.000000e+00 191 197 -6.776786e+05 0.000000e+00 191 221 -1.694196e+05 0.000000e+00 191 227 -6.776786e+05 0.000000e+00 191 233 -1.694196e+05 0.000000e+00 192 192 -1.301143e+10 0.000000e+00 192 198 -3.252857e+09 0.000000e+00 192 222 -8.132143e+08 0.000000e+00 192 228 -3.252857e+09 0.000000e+00 192 234 -8.132143e+08 0.000000e+00 193 193 -1.301143e+10 0.000000e+00 193 199 -3.252857e+09 0.000000e+00 193 223 -8.132143e+08 0.000000e+00 193 229 -3.252857e+09 0.000000e+00 193 235 -8.132143e+08 0.000000e+00 194 194 -1.301143e+10 0.000000e+00 194 200 -3.252857e+09 0.000000e+00 194 224 -8.132143e+08 0.000000e+00 194 230 -3.252857e+09 0.000000e+00 194 236 -8.132143e+08 0.000000e+00 196 196 -2.710714e+06 0.000000e+00 196 202 -6.776786e+05 0.000000e+00 196 226 -1.694196e+05 0.000000e+00 196 232 -6.776786e+05 0.000000e+00 196 238 -1.694196e+05 0.000000e+00 197 197 -2.710714e+06 0.000000e+00 197 203 -6.776786e+05 0.000000e+00 197 227 -1.694196e+05 0.000000e+00 197 233 -6.776786e+05 0.000000e+00 197 239 -1.694196e+05 0.000000e+00 198 198 -1.301143e+10 0.000000e+00 198 204 -3.252857e+09 0.000000e+00 198 228 -8.132143e+08 0.000000e+00 198 234 -3.252857e+09 0.000000e+00 198 240 -8.132143e+08 0.000000e+00 199 199 -1.301143e+10 0.000000e+00 199 205 -3.252857e+09 0.000000e+00 199 229 -8.132143e+08 0.000000e+00 199 235 -3.252857e+09 0.000000e+00 199 241 -8.132143e+08 0.000000e+00 200 200 -1.301143e+10 0.000000e+00 200 206 -3.252857e+09 0.000000e+00 200 230 -8.132143e+08 0.000000e+00 200 236 -3.252857e+09 0.000000e+00 200 242 -8.132143e+08 0.000000e+00 202 202 -2.710714e+06 0.000000e+00 202 208 -6.776786e+05 0.000000e+00 202 232 -1.694196e+05 0.000000e+00 202 238 -6.776786e+05 0.000000e+00 202 244 -1.694196e+05 0.000000e+00 203 203 -2.710714e+06 0.000000e+00 203 209 -6.776786e+05 0.000000e+00 203 233 -1.694196e+05 0.000000e+00 203 239 -6.776786e+05 0.000000e+00 203 245 -1.694196e+05 0.000000e+00 216 216 -3.252857e+09 0.000000e+00 216 222 -1.626429e+09 0.000000e+00 217 217 -3.252857e+09 0.000000e+00 217 223 -1.626429e+09 0.000000e+00 218 218 -3.252857e+09 0.000000e+00 218 224 -1.626429e+09 0.000000e+00 220 220 -6.776786e+05 0.000000e+00 220 226 -3.388393e+05 0.000000e+00 221 221 -6.776786e+05 0.000000e+00 221 227 -3.388393e+05 0.000000e+00 222 222 -6.505714e+09 0.000000e+00 222 228 -1.626429e+09 0.000000e+00 223 223 -6.505714e+09 0.000000e+00 223 229 -1.626429e+09 0.000000e+00 224 224 -6.505714e+09 0.000000e+00 224 230 -1.626429e+09 0.000000e+00 226 226 -1.355357e+06 0.000000e+00 226 232 -3.388393e+05 0.000000e+00 227 227 -1.355357e+06 0.000000e+00 227 233 -3.388393e+05 0.000000e+00 228 228 -6.505714e+09 0.000000e+00 228 234 -1.626429e+09 0.000000e+00 229 229 -6.505714e+09 0.000000e+00 229 235 -1.626429e+09 0.000000e+00 230 230 -6.505714e+09 0.000000e+00 230 236 -1.626429e+09 0.000000e+00 232 232 -1.355357e+06 0.000000e+00 232 238 -3.388393e+05 0.000000e+00 233 233 -1.355357e+06 0.000000e+00 233 239 -3.388393e+05 0.000000e+00 234 234 -6.505714e+09 0.000000e+00 234 240 -1.626429e+09 0.000000e+00 235 235 -6.505714e+09 0.000000e+00 235 241 -1.626429e+09 0.000000e+00 236 236 -6.505714e+09 0.000000e+00 236 242 -1.626429e+09 0.000000e+00 238 238 -1.355357e+06 0.000000e+00 238 244 -3.388393e+05 0.000000e+00 239 239 -1.355357e+06 0.000000e+00 239 245 -3.388393e+05 0.000000e+0 0 0 2.574505e+09 -1.287252e+08 0 4 -3.165375e+08 1.582687e+07 0 5 -2.637812e+08 1.318906e+07 0 6 -2.954350e+08 1.477175e+07 0 10 -1.582687e+08 7.913437e+06 0 11 -2.637812e+08 1.318906e+07 0 12 -9.918174e+08 4.959087e+07 0 16 -3.165375e+08 1.582687e+07 0 17 -1.318906e+08 6.594531e+06 0 18 -1.287252e+09 6.436262e+07 0 22 -1.582687e+08 7.913437e+06 0 23 -1.318906e+08 6.594531e+06 1 1 4.491563e+09 -2.245781e+08 1 2 -1.725352e+09 8.626761e+07 1 7 -2.212493e+09 1.106246e+08 1 8 1.738727e+08 -8.693635e+06 1 13 -3.328845e+07 1.664422e+06 1 14 -1.738727e+08 8.693635e+06 1 19 -2.245781e+09 1.122891e+08 1 20 1.725352e+09 -8.626761e+07 2 2 5.335068e+09 -2.667534e+08 2 7 -1.738727e+08 8.693635e+06 2 8 1.084847e+09 -5.424234e+07 2 13 1.738727e+08 -8.693635e+06 2 14 -3.752381e+09 1.876190e+08 2 19 1.725352e+09 -8.626761e+07 2 20 -2.667534e+09 1.333767e+08 3 3 7.252126e+05 -3.626063e+04 3 9 -8.322112e+04 4.161056e+03 3 15 -2.793852e+05 1.396926e+04 3 21 -3.626063e+05 1.813032e+04 4 4 8.903855e+07 -4.451927e+06 4 5 3.594484e+05 -1.797242e+04 4 6 -1.582687e+08 7.913437e+06 4 10 4.418955e+07 -2.209477e+06 4 11 3.622348e+04 -1.811174e+03 4 12 3.165375e+08 -1.582687e+07 4 16 4.318179e+07 -2.159090e+06 4 17 -3.622348e+04 1.811174e+03 4 18 1.582687e+08 -7.913437e+06 4 22 2.142603e+07 -1.071302e+06 4 23 -3.594484e+05 1.797242e+04 5 5 8.886282e+07 -4.443141e+06 5 6 2.637812e+08 -1.318906e+07 5 10 -3.622348e+04 1.811174e+03 5 11 4.350260e+07 -2.175130e+06 5 12 -1.318906e+08 6.594531e+06 5 16 3.622348e+04 -1.811174e+03 5 17 4.395660e+07 -2.197830e+06 5 18 1.318906e+08 -6.594531e+06 5 22 -3.594484e+05 1.797242e+04 5 23 2.151390e+07 -1.075695e+06 6 6 5.149009e+09 -2.574505e+08 6 10 -6.330749e+08 3.165375e+07 6 11 2.980232e-08 -1.490116e-09 6 12 -1.287252e+09 6.436262e+07 6 16 -1.582687e+08 7.913437e+06 6 17 1.318906e+08 -6.594531e+06 6 18 -1.983635e+09 9.918174e+07 6 22 -6.330749e+08 3.165375e+07 6 23 4.470348e-08 -2.235174e-09 6 24 -2.954350e+08 1.477175e+07 6 28 -1.582687e+08 7.913437e+06 6 29 -2.637812e+08 1.318906e+07 6 30 -1.287252e+09 6.436262e+07 6 34 -1.582687e+08 7.913437e+06 6 35 -1.318906e+08 6.594531e+06 7 7 8.983125e+09 -4.491563e+08 7 8 7.152557e-07 -3.576279e-08 7 13 -2.245781e+09 1.122891e+08 7 14 -1.725352e+09 8.626761e+07 7 19 -6.657689e+07 3.328845e+06 7 20 -6.854534e-07 3.427267e-08 7 25 -2.212493e+09 1.106246e+08 7 26 1.738727e+08 -8.693635e+06 7 31 -2.245781e+09 1.122891e+08 7 32 1.725352e+09 -8.626761e+07 8 8 1.067014e+10 -5.335068e+08 8 13 -1.725352e+09 8.626761e+07 8 14 -2.667534e+09 1.333767e+08 8 19 -6.258488e-07 3.129244e-08 8 20 -7.504762e+09 3.752381e+08 8 25 -1.738727e+08 8.693635e+06 8 26 1.084847e+09 -5.424234e+07 8 31 1.725352e+09 -8.626761e+07 8 32 -2.667534e+09 1.333767e+08 9 9 1.450425e+06 -7.252126e+04 9 15 -3.626063e+05 1.813032e+04 9 21 -5.587704e+05 2.793852e+04 9 27 -8.322112e+04 4.161056e+03 9 33 -3.626063e+05 1.813032e+04 10 10 1.780771e+08 -8.903855e+06 10 11 -1.746230e-10 8.731149e-12 10 12 1.582687e+08 -7.913437e+06 10 16 2.142603e+07 -1.071302e+06 10 17 3.594484e+05 -1.797242e+04 10 18 6.330749e+08 -3.165375e+07 10 22 8.636358e+07 -4.318179e+06 10 23 1.382432e-10 -6.912160e-12 10 24 -1.582687e+08 7.913437e+06 10 28 4.418955e+07 -2.209477e+06 10 29 3.622348e+04 -1.811174e+03 10 30 1.582687e+08 -7.913437e+06 10 34 2.142603e+07 -1.071302e+06 10 35 -3.594484e+05 1.797242e+04 11 11 1.777256e+08 -8.886282e+06 11 12 -1.318906e+08 6.594531e+06 11 16 3.594484e+05 -1.797242e+04 11 17 2.151390e+07 -1.075695e+06 11 18 -8.940697e-08 4.470348e-09 11 22 1.455192e-10 -7.275958e-12 11 23 8.791320e+07 -4.395660e+06 11 24 2.637812e+08 -1.318906e+07 11 28 -3.622348e+04 1.811174e+03 11 29 4.350260e+07 -2.175130e+06 11 30 1.318906e+08 -6.594531e+06 11 34 -3.594484e+05 1.797242e+04 11 35 2.151390e+07 -1.075695e+06 12 12 5.149009e+09 -2.574505e+08 12 16 0.000000e+00 -0.000000e+00 12 17 -5.275624e+08 2.637812e+07 12 18 -5.908699e+08 2.954350e+07 12 22 0.000000e+00 -0.000000e+00 12 23 -5.275624e+08 2.637812e+07 12 72 -9.918174e+08 4.959087e+07 12 76 -3.165375e+08 1.582687e+07 12 77 -1.318906e+08 6.594531e+06 12 78 -1.287252e+09 6.436262e+07 12 82 -1.582687e+08 7.913437e+06 12 83 -1.318906e+08 6.594531e+06 13 13 8.983125e+09 -4.491563e+08 13 14 2.384186e-07 -1.192093e-08 13 19 -4.424986e+09 2.212493e+08 13 20 5.960464e-08 -2.980232e-09 13 73 -3.328845e+07 1.664422e+06 13 74 -1.738727e+08 8.693635e+06 13 79 -2.245781e+09 1.122891e+08 13 80 1.725352e+09 -8.626761e+07 14 14 1.067014e+10 -5.335068e+08 14 19 5.960464e-08 -2.980232e-09 14 20 2.169693e+09 -1.084847e+08 14 73 1.738727e+08 -8.693635e+06 14 74 -3.752381e+09 1.876190e+08 14 79 1.725352e+09 -8.626761e+07 14 80 -2.667534e+09 1.333767e+08 15 15 1.450425e+06 -7.252126e+04 15 21 -1.664422e+05 8.322112e+03 15 75 -2.793852e+05 1.396926e+04 15 81 -3.626063e+05 1.813032e+04 16 16 1.780771e+08 -8.903855e+06 16 17 -1.164153e-10 5.820766e-12 16 18 -2.980232e-08 1.490116e-09 16 22 8.837909e+07 -4.418955e+06 16 23 -3.637979e-11 1.818989e-12 16 72 3.165375e+08 -1.582687e+07 16 76 4.318179e+07 -2.159090e+06 16 77 -3.622348e+04 1.811174e+03 16 78 1.582687e+08 -7.913437e+06 16 82 2.142603e+07 -1.071302e+06 16 83 -3.594484e+05 1.797242e+04 17 17 1.777256e+08 -8.886282e+06 17 18 5.275624e+08 -2.637812e+07 17 22 -2.910383e-11 1.455192e-12 17 23 8.700520e+07 -4.350260e+06 17 72 -1.318906e+08 6.594531e+06 17 76 3.622348e+04 -1.811174e+03 17 77 4.395660e+07 -2.197830e+06 17 78 1.318906e+08 -6.594531e+06 17 82 -3.594484e+05 1.797242e+04 17 83 2.151390e+07 -1.075695e+06 18 18 1.029802e+10 -5.149009e+08 18 22 5.960464e-08 -2.980232e-09 18 23 -5.960464e-08 2.980232e-09 18 24 -1.287252e+09 6.436262e+07 18 28 1.582687e+08 -7.913437e+06 18 29 -1.318906e+08 6.594531e+06 18 30 -5.908699e+08 2.954350e+07 18 34 -1.192093e-07 5.960464e-09 18 35 -5.275624e+08 2.637812e+07 18 72 -1.287252e+09 6.436262e+07 18 76 -1.582687e+08 7.913437e+06 18 77 1.318906e+08 -6.594531e+06 18 78 -1.983635e+09 9.918174e+07 18 82 -6.330749e+08 3.165375e+07 18 83 1.490116e-08 -7.450581e-10 18 84 -1.287252e+09 6.436262e+07 18 88 -1.582687e+08 7.913437e+06 18 89 -1.318906e+08 6.594531e+06 19 19 1.796625e+10 -8.983125e+08 19 20 9.536743e-07 -4.768372e-08 19 25 -2.245781e+09 1.122891e+08 19 26 -1.725352e+09 8.626761e+07 19 31 -4.424986e+09 2.212493e+08 19 32 3.576279e-07 -1.788139e-08 19 73 -2.245781e+09 1.122891e+08 19 74 -1.725352e+09 8.626761e+07 19 79 -6.657689e+07 3.328845e+06 19 80 -5.960464e-08 2.980232e-09 19 85 -2.245781e+09 1.122891e+08 19 86 1.725352e+09 -8.626761e+07 20 20 2.134027e+10 -1.067014e+09 20 25 -1.725352e+09 8.626761e+07 20 26 -2.667534e+09 1.333767e+08 20 31 4.768372e-07 -2.384186e-08 20 32 2.169693e+09 -1.084847e+08 20 73 -1.725352e+09 8.626761e+07 20 74 -2.667534e+09 1.333767e+08 20 79 -2.682209e-07 1.341105e-08 20 80 -7.504762e+09 3.752381e+08 20 85 1.725352e+09 -8.626761e+07 20 86 -2.667534e+09 1.333767e+08 21 21 2.900850e+06 -1.450425e+05 21 27 -3.626063e+05 1.813032e+04 21 33 -1.664422e+05 8.322112e+03 21 75 -3.626063e+05 1.813032e+04 21 81 -5.587704e+05 2.793852e+04 21 87 -3.626063e+05 1.813032e+04 22 22 3.561542e+08 -1.780771e+07 22 23 0.000000e+00 -0.000000e+00 22 24 -1.582687e+08 7.913437e+06 22 28 2.142603e+07 -1.071302e+06 22 29 3.594484e+05 -1.797242e+04 22 30 -2.980232e-08 1.490116e-09 22 34 8.837909e+07 -4.418955e+06 22 35 -1.236913e-10 6.184564e-12 22 72 1.582687e+08 -7.913437e+06 22 76 2.142603e+07 -1.071302e+06 22 77 3.594484e+05 -1.797242e+04 22 78 6.330749e+08 -3.165375e+07 22 82 8.636358e+07 -4.318179e+06 22 83 5.820766e-11 -2.910383e-12 22 84 1.582687e+08 -7.913437e+06 22 88 2.142603e+07 -1.071302e+06 22 89 -3.594484e+05 1.797242e+04 23 23 3.554513e+08 -1.777256e+07 23 24 1.318906e+08 -6.594531e+06 23 28 3.594484e+05 -1.797242e+04 23 29 2.151390e+07 -1.075695e+06 23 30 5.275624e+08 -2.637812e+07 23 34 -1.018634e-10 5.093170e-12 23 35 8.700520e+07 -4.350260e+06 23 72 -1.318906e+08 6.594531e+06 23 76 3.594484e+05 -1.797242e+04 23 77 2.151390e+07 -1.075695e+06 23 78 -1.490116e-08 7.450581e-10 23 82 2.910383e-11 -1.455192e-12 23 83 8.791320e+07 -4.395660e+06 23 84 1.318906e+08 -6.594531e+06 23 88 -3.594484e+05 1.797242e+04 23 89 2.151390e+07 -1.075695e+06 24 24 5.149009e+09 -2.574505e+08 24 28 -6.330749e+08 3.165375e+07 24 29 2.980232e-08 -1.490116e-09 24 30 -1.983635e+09 9.918174e+07 24 34 -6.330749e+08 3.165375e+07 24 35 4.470348e-08 -2.235174e-09 24 36 -2.954350e+08 1.477175e+07 24 40 -1.582687e+08 7.913437e+06 24 41 -2.637812e+08 1.318906e+07 24 42 -1.287252e+09 6.436262e+07 24 46 -1.582687e+08 7.913437e+06 24 47 -1.318906e+08 6.594531e+06 25 25 8.983125e+09 -4.491563e+08 25 26 2.384186e-07 -1.192093e-08 25 31 -6.657689e+07 3.328845e+06 25 32 -8.940697e-07 4.470348e-08 25 37 -2.212493e+09 1.106246e+08 25 38 1.738727e+08 -8.693635e+06 25 43 -2.245781e+09 1.122891e+08 25 44 1.725352e+09 -8.626761e+07 26 26 1.067014e+10 -5.335068e+08 26 31 -8.642673e-07 4.321337e-08 26 32 -7.504762e+09 3.752381e+08 26 37 -1.738727e+08 8.693635e+06 26 38 1.084847e+09 -5.424234e+07 26 43 1.725352e+09 -8.626761e+07 26 44 -2.667534e+09 1.333767e+08 27 27 1.450425e+06 -7.252126e+04 27 33 -5.587704e+05 2.793852e+04 27 39 -8.322112e+04 4.161056e+03 27 45 -3.626063e+05 1.813032e+04 28 28 1.780771e+08 -8.903855e+06 28 29 -5.820766e-11 2.910383e-12 28 30 6.330749e+08 -3.165375e+07 28 34 8.636358e+07 -4.318179e+06 28 35 2.037268e-10 -1.018634e-11 28 36 -1.582687e+08 7.913437e+06 28 40 4.418955e+07 -2.209477e+06 28 41 3.622348e+04 -1.811174e+03 28 42 1.582687e+08 -7.913437e+06 28 46 2.142603e+07 -1.071302e+06 28 47 -3.594484e+05 1.797242e+04 29 29 1.777256e+08 -8.886282e+06 29 30 -8.940697e-08 4.470348e-09 29 34 1.527951e-10 -7.639755e-12 29 35 8.791320e+07 -4.395660e+06 29 36 2.637812e+08 -1.318906e+07 29 40 -3.622348e+04 1.811174e+03 29 41 4.350260e+07 -2.175130e+06 29 42 1.318906e+08 -6.594531e+06 29 46 -3.594484e+05 1.797242e+04 29 47 2.151390e+07 -1.075695e+06 30 30 1.029802e+10 -5.149009e+08 30 34 1.788139e-07 -8.940697e-09 30 35 -5.960464e-08 2.980232e-09 30 36 -1.287252e+09 6.436262e+07 30 40 1.582687e+08 -7.913437e+06 30 41 -1.318906e+08 6.594531e+06 30 42 -5.908699e+08 2.954350e+07 30 46 -1.490116e-07 7.450581e-09 30 47 -5.275624e+08 2.637812e+07 30 78 -1.287252e+09 6.436262e+07 30 82 -1.582687e+08 7.913437e+06 30 83 1.318906e+08 -6.594531e+06 30 84 -1.983635e+09 9.918174e+07 30 88 -6.330749e+08 3.165375e+07 30 89 1.490116e-08 -7.450581e-10 30 90 -1.287252e+09 6.436262e+07 30 94 -1.582687e+08 7.913437e+06 30 95 -1.318906e+08 6.594531e+06 31 31 1.796625e+10 -8.983125e+08 31 32 -2.384186e-07 1.192093e-08 31 37 -2.245781e+09 1.122891e+08 31 38 -1.725352e+09 8.626761e+07 31 43 -4.424986e+09 2.212493e+08 31 44 6.258488e-07 -3.129244e-08 31 79 -2.245781e+09 1.122891e+08 31 80 -1.725352e+09 8.626761e+07 31 85 -6.657689e+07 3.328845e+06 31 86 -1.192093e-07 5.960464e-09 31 91 -2.245781e+09 1.122891e+08 31 92 1.725352e+09 -8.626761e+07 32 32 2.134027e+10 -1.067014e+09 32 37 -1.725352e+09 8.626761e+07 32 38 -2.667534e+09 1.333767e+08 32 43 5.364418e-07 -2.682209e-08 32 44 2.169693e+09 -1.084847e+08 32 79 -1.725352e+09 8.626761e+07 32 80 -2.667534e+09 1.333767e+08 32 85 -3.278255e-07 1.639128e-08 32 86 -7.504762e+09 3.752381e+08 32 91 1.725352e+09 -8.626761e+07 32 92 -2.667534e+09 1.333767e+08 33 33 2.900850e+06 -1.450425e+05 33 39 -3.626063e+05 1.813032e+04 33 45 -1.664422e+05 8.322112e+03 33 81 -3.626063e+05 1.813032e+04 33 87 -5.587704e+05 2.793852e+04 33 93 -3.626063e+05 1.813032e+04 34 34 3.561542e+08 -1.780771e+07 34 35 1.164153e-10 -5.820766e-12 34 36 -1.582687e+08 7.913437e+06 34 40 2.142603e+07 -1.071302e+06 34 41 3.594484e+05 -1.797242e+04 34 42 -2.980232e-08 1.490116e-09 34 46 8.837909e+07 -4.418955e+06 34 47 -1.673470e-10 8.367351e-12 34 78 1.582687e+08 -7.913437e+06 34 82 2.142603e+07 -1.071302e+06 34 83 3.594484e+05 -1.797242e+04 34 84 6.330749e+08 -3.165375e+07 34 88 8.636358e+07 -4.318179e+06 34 89 1.018634e-10 -5.093170e-12 34 90 1.582687e+08 -7.913437e+06 34 94 2.142603e+07 -1.071302e+06 34 95 -3.594484e+05 1.797242e+04 35 35 3.554513e+08 -1.777256e+07 35 36 1.318906e+08 -6.594531e+06 35 40 3.594484e+05 -1.797242e+04 35 41 2.151390e+07 -1.075695e+06 35 42 5.275624e+08 -2.637812e+07 35 46 -1.600711e-10 8.003553e-12 35 47 8.700520e+07 -4.350260e+06 35 78 -1.318906e+08 6.594531e+06 35 82 3.594484e+05 -1.797242e+04 35 83 2.151390e+07 -1.075695e+06 35 84 -1.490116e-08 7.450581e-10 35 88 3.637979e-11 -1.818989e-12 35 89 8.791320e+07 -4.395660e+06 35 90 1.318906e+08 -6.594531e+06 35 94 -3.594484e+05 1.797242e+04 35 95 2.151390e+07 -1.075695e+06 72 72 5.149009e+09 -2.574505e+08 72 76 0.000000e+00 -0.000000e+00 72 77 -5.275624e+08 2.637812e+07 72 78 -5.908699e+08 2.954350e+07 72 82 0.000000e+00 -0.000000e+00 72 83 -5.275624e+08 2.637812e+07 72 108 -9.918174e+08 4.959087e+07 72 112 -3.165375e+08 1.582687e+07 72 113 -1.318906e+08 6.594531e+06 72 114 -1.287252e+09 6.436262e+07 72 118 -1.582687e+08 7.913437e+06 72 119 -1.318906e+08 6.594531e+06 73 73 8.983125e+09 -4.491563e+08 73 74 0.000000e+00 -0.000000e+00 73 79 -4.424986e+09 2.212493e+08 73 80 -5.960464e-08 2.980232e-09 73 109 -3.328845e+07 1.664422e+06 73 110 -1.738727e+08 8.693635e+06 73 115 -2.245781e+09 1.122891e+08 73 116 1.725352e+09 -8.626761e+07 74 74 1.067014e+10 -5.335068e+08 74 79 8.940697e-08 -4.470348e-09 74 80 2.169693e+09 -1.084847e+08 74 109 1.738727e+08 -8.693635e+06 74 110 -3.752381e+09 1.876190e+08 74 115 1.725352e+09 -8.626761e+07 74 116 -2.667534e+09 1.333767e+08 75 75 1.450425e+06 -7.252126e+04 75 81 -1.664422e+05 8.322112e+03 75 111 -2.793852e+05 1.396926e+04 75 117 -3.626063e+05 1.813032e+04 76 76 1.780771e+08 -8.903855e+06 76 77 0.000000e+00 -0.000000e+00 76 78 -2.980232e-08 1.490116e-09 76 82 8.837909e+07 -4.418955e+06 76 83 0.000000e+00 -0.000000e+00 76 108 3.165375e+08 -1.582687e+07 76 112 4.318179e+07 -2.159090e+06 76 113 -3.622348e+04 1.811174e+03 76 114 1.582687e+08 -7.913437e+06 76 118 2.142603e+07 -1.071302e+06 76 119 -3.594484e+05 1.797242e+04 77 77 1.777256e+08 -8.886282e+06 77 78 5.275624e+08 -2.637812e+07 77 82 3.637979e-11 -1.818989e-12 77 83 8.700520e+07 -4.350260e+06 77 108 -1.318906e+08 6.594531e+06 77 112 3.622348e+04 -1.811174e+03 77 113 4.395660e+07 -2.197830e+06 77 114 1.318906e+08 -6.594531e+06 77 118 -3.594484e+05 1.797242e+04 77 119 2.151390e+07 -1.075695e+06 78 78 1.029802e+10 -5.149009e+08 78 82 5.960464e-08 -2.980232e-09 78 83 -5.960464e-08 2.980232e-09 78 84 -5.908699e+08 2.954350e+07 78 88 -1.192093e-07 5.960464e-09 78 89 -5.275624e+08 2.637812e+07 78 108 -1.287252e+09 6.436262e+07 78 112 -1.582687e+08 7.913437e+06 78 113 1.318906e+08 -6.594531e+06 78 114 -1.983635e+09 9.918174e+07 78 118 -6.330749e+08 3.165375e+07 78 119 2.980232e-08 -1.490116e-09 78 120 -1.287252e+09 6.436262e+07 78 124 -1.582687e+08 7.913437e+06 78 125 -1.318906e+08 6.594531e+06 79 79 1.796625e+10 -8.983125e+08 79 80 -2.384186e-07 1.192093e-08 79 85 -4.424986e+09 2.212493e+08 79 86 1.788139e-07 -8.940697e-09 79 109 -2.245781e+09 1.122891e+08 79 110 -1.725352e+09 8.626761e+07 79 115 -6.657689e+07 3.328845e+06 79 116 -2.384186e-07 1.192093e-08 79 121 -2.245781e+09 1.122891e+08 79 122 1.725352e+09 -8.626761e+07 80 80 2.134027e+10 -1.067014e+09 80 85 2.384186e-07 -1.192093e-08 80 86 2.169693e+09 -1.084847e+08 80 109 -1.725352e+09 8.626761e+07 80 110 -2.667534e+09 1.333767e+08 80 115 5.960464e-08 -2.980232e-09 80 116 -7.504762e+09 3.752381e+08 80 121 1.725352e+09 -8.626761e+07 80 122 -2.667534e+09 1.333767e+08 81 81 2.900850e+06 -1.450425e+05 81 87 -1.664422e+05 8.322112e+03 81 111 -3.626063e+05 1.813032e+04 81 117 -5.587704e+05 2.793852e+04 81 123 -3.626063e+05 1.813032e+04 82 82 3.561542e+08 -1.780771e+07 82 83 -5.820766e-11 2.910383e-12 82 84 -2.980232e-08 1.490116e-09 82 88 8.837909e+07 -4.418955e+06 82 89 -5.093170e-11 2.546585e-12 82 108 1.582687e+08 -7.913437e+06 82 112 2.142603e+07 -1.071302e+06 82 113 3.594484e+05 -1.797242e+04 82 114 6.330749e+08 -3.165375e+07 82 118 8.636358e+07 -4.318179e+06 82 119 0.000000e+00 -0.000000e+00 82 120 1.582687e+08 -7.913437e+06 82 124 2.142603e+07 -1.071302e+06 82 125 -3.594484e+05 1.797242e+04 83 83 3.554513e+08 -1.777256e+07 83 84 5.275624e+08 -2.637812e+07 83 88 -2.910383e-11 1.455192e-12 83 89 8.700520e+07 -4.350260e+06 83 108 -1.318906e+08 6.594531e+06 83 112 3.594484e+05 -1.797242e+04 83 113 2.151390e+07 -1.075695e+06 83 114 -1.490116e-08 7.450581e-10 83 118 2.910383e-11 -1.455192e-12 83 119 8.791320e+07 -4.395660e+06 83 120 1.318906e+08 -6.594531e+06 83 124 -3.594484e+05 1.797242e+04 83 125 2.151390e+07 -1.075695e+06 84 84 1.029802e+10 -5.149009e+08 84 88 1.788139e-07 -8.940697e-09 84 89 -5.960464e-08 2.980232e-09 84 90 -5.908699e+08 2.954350e+07 84 94 -1.192093e-07 5.960464e-09 84 95 -5.275624e+08 2.637812e+07 84 114 -1.287252e+09 6.436262e+07 84 118 -1.582687e+08 7.913437e+06 84 119 1.318906e+08 -6.594531e+06 84 120 -1.983635e+09 9.918174e+07 84 124 -6.330749e+08 3.165375e+07 84 125 2.980232e-08 -1.490116e-09 84 126 -1.287252e+09 6.436262e+07 84 130 -1.582687e+08 7.913437e+06 84 131 -1.318906e+08 6.594531e+06 85 85 1.796625e+10 -8.983125e+08 85 86 -1.192093e-06 5.960464e-08 85 91 -4.424986e+09 2.212493e+08 85 92 4.768372e-07 -2.384186e-08 85 115 -2.245781e+09 1.122891e+08 85 116 -1.725352e+09 8.626761e+07 85 121 -6.657689e+07 3.328845e+06 85 122 -2.682209e-07 1.341105e-08 85 127 -2.245781e+09 1.122891e+08 85 128 1.725352e+09 -8.626761e+07 86 86 2.134027e+10 -1.067014e+09 86 91 5.066395e-07 -2.533197e-08 86 92 2.169693e+09 -1.084847e+08 86 115 -1.725352e+09 8.626761e+07 86 116 -2.667534e+09 1.333767e+08 86 121 0.000000e+00 -0.000000e+00 86 122 -7.504762e+09 3.752381e+08 86 127 1.725352e+09 -8.626761e+07 86 128 -2.667534e+09 1.333767e+08 87 87 2.900850e+06 -1.450425e+05 87 93 -1.664422e+05 8.322112e+03 87 117 -3.626063e+05 1.813032e+04 87 123 -5.587704e+05 2.793852e+04 87 129 -3.626063e+05 1.813032e+04 88 88 3.561542e+08 -1.780771e+07 88 89 5.820766e-11 -2.910383e-12 88 90 -2.980232e-08 1.490116e-09 88 94 8.837909e+07 -4.418955e+06 88 95 -1.018634e-10 5.093170e-12 88 114 1.582687e+08 -7.913437e+06 88 118 2.142603e+07 -1.071302e+06 88 119 3.594484e+05 -1.797242e+04 88 120 6.330749e+08 -3.165375e+07 88 124 8.636358e+07 -4.318179e+06 88 125 7.275958e-12 -3.637979e-13 88 126 1.582687e+08 -7.913437e+06 88 130 2.142603e+07 -1.071302e+06 88 131 -3.594484e+05 1.797242e+04 89 89 3.554513e+08 -1.777256e+07 89 90 5.275624e+08 -2.637812e+07 89 94 -8.731149e-11 4.365575e-12 89 95 8.700520e+07 -4.350260e+06 89 114 -1.318906e+08 6.594531e+06 89 118 3.594484e+05 -1.797242e+04 89 119 2.151390e+07 -1.075695e+06 89 120 -1.490116e-08 7.450581e-10 89 124 3.637979e-11 -1.818989e-12 89 125 8.791320e+07 -4.395660e+06 89 126 1.318906e+08 -6.594531e+06 89 130 -3.594484e+05 1.797242e+04 89 131 2.151390e+07 -1.075695e+06 108 108 5.149009e+09 -2.574505e+08 108 112 0.000000e+00 -0.000000e+00 108 113 -5.275624e+08 2.637812e+07 108 114 -5.908699e+08 2.954350e+07 108 118 0.000000e+00 -0.000000e+00 108 119 -5.275624e+08 2.637812e+07 108 144 -9.918174e+08 4.959087e+07 108 148 -3.165375e+08 1.582687e+07 108 149 -1.318906e+08 6.594531e+06 108 150 -1.287252e+09 6.436262e+07 108 154 -1.582687e+08 7.913437e+06 108 155 -1.318906e+08 6.594531e+06 109 109 8.983125e+09 -4.491563e+08 109 110 2.384186e-07 -1.192093e-08 109 115 -4.424986e+09 2.212493e+08 109 116 1.788139e-07 -8.940697e-09 109 145 -3.328845e+07 1.664422e+06 109 146 -1.738727e+08 8.693635e+06 109 151 -2.245781e+09 1.122891e+08 109 152 1.725352e+09 -8.626761e+07 110 110 1.067014e+10 -5.335068e+08 110 115 8.940697e-08 -4.470348e-09 110 116 2.169693e+09 -1.084847e+08 110 145 1.738727e+08 -8.693635e+06 110 146 -3.752381e+09 1.876190e+08 110 151 1.725352e+09 -8.626761e+07 110 152 -2.667534e+09 1.333767e+08 111 111 1.450425e+06 -7.252126e+04 111 117 -1.664422e+05 8.322112e+03 111 147 -2.793852e+05 1.396926e+04 111 153 -3.626063e+05 1.813032e+04 112 112 1.780771e+08 -8.903855e+06 112 113 -5.820766e-11 2.910383e-12 112 114 0.000000e+00 -0.000000e+00 112 118 8.837909e+07 -4.418955e+06 112 119 -2.910383e-11 1.455192e-12 112 144 3.165375e+08 -1.582687e+07 112 148 4.318179e+07 -2.159090e+06 112 149 -3.622348e+04 1.811174e+03 112 150 1.582687e+08 -7.913437e+06 112 154 2.142603e+07 -1.071302e+06 112 155 -3.594484e+05 1.797242e+04 113 113 1.777256e+08 -8.886282e+06 113 114 5.275624e+08 -2.637812e+07 113 118 -1.455192e-11 7.275958e-13 113 119 8.700520e+07 -4.350260e+06 113 144 -1.318906e+08 6.594531e+06 113 148 3.622348e+04 -1.811174e+03 113 149 4.395660e+07 -2.197830e+06 113 150 1.318906e+08 -6.594531e+06 113 154 -3.594484e+05 1.797242e+04 113 155 2.151390e+07 -1.075695e+06 114 114 1.029802e+10 -5.149009e+08 114 118 5.960464e-08 -2.980232e-09 114 119 -8.940697e-08 4.470348e-09 114 120 -5.908699e+08 2.954350e+07 114 124 -1.192093e-07 5.960464e-09 114 125 -5.275624e+08 2.637812e+07 114 144 -1.287252e+09 6.436262e+07 114 148 -1.582687e+08 7.913437e+06 114 149 1.318906e+08 -6.594531e+06 114 150 -1.983635e+09 9.918174e+07 114 154 -6.330749e+08 3.165375e+07 114 155 1.490116e-08 -7.450581e-10 114 156 -1.287252e+09 6.436262e+07 114 160 -1.582687e+08 7.913437e+06 114 161 -1.318906e+08 6.594531e+06 115 115 1.796625e+10 -8.983125e+08 115 116 0.000000e+00 -0.000000e+00 115 121 -4.424986e+09 2.212493e+08 115 122 3.874302e-07 -1.937151e-08 115 145 -2.245781e+09 1.122891e+08 115 146 -1.725352e+09 8.626761e+07 115 151 -6.657689e+07 3.328845e+06 115 152 -1.788139e-07 8.940697e-09 115 157 -2.245781e+09 1.122891e+08 115 158 1.725352e+09 -8.626761e+07 116 116 2.134027e+10 -1.067014e+09 116 121 1.788139e-07 -8.940697e-09 116 122 2.169693e+09 -1.084847e+08 116 145 -1.725352e+09 8.626761e+07 116 146 -2.667534e+09 1.333767e+08 116 151 -2.682209e-07 1.341105e-08 116 152 -7.504762e+09 3.752381e+08 116 157 1.725352e+09 -8.626761e+07 116 158 -2.667534e+09 1.333767e+08 117 117 2.900850e+06 -1.450425e+05 117 123 -1.664422e+05 8.322112e+03 117 147 -3.626063e+05 1.813032e+04 117 153 -5.587704e+05 2.793852e+04 117 159 -3.626063e+05 1.813032e+04 118 118 3.561542e+08 -1.780771e+07 118 119 -1.164153e-10 5.820766e-12 118 120 -5.960464e-08 2.980232e-09 118 124 8.837909e+07 -4.418955e+06 118 125 -5.820766e-11 2.910383e-12 118 144 1.582687e+08 -7.913437e+06 118 148 2.142603e+07 -1.071302e+06 118 149 3.594484e+05 -1.797242e+04 118 150 6.330749e+08 -3.165375e+07 118 154 8.636358e+07 -4.318179e+06 118 155 5.820766e-11 -2.910383e-12 118 156 1.582687e+08 -7.913437e+06 118 160 2.142603e+07 -1.071302e+06 118 161 -3.594484e+05 1.797242e+04 119 119 3.554513e+08 -1.777256e+07 119 120 5.275624e+08 -2.637812e+07 119 124 -5.820766e-11 2.910383e-12 119 125 8.700520e+07 -4.350260e+06 119 144 -1.318906e+08 6.594531e+06 119 148 3.594484e+05 -1.797242e+04 119 149 2.151390e+07 -1.075695e+06 119 150 -4.470348e-08 2.235174e-09 119 154 5.820766e-11 -2.910383e-12 119 155 8.791320e+07 -4.395660e+06 119 156 1.318906e+08 -6.594531e+06 119 160 -3.594484e+05 1.797242e+04 119 161 2.151390e+07 -1.075695e+06 120 120 1.029802e+10 -5.149009e+08 120 124 1.788139e-07 -8.940697e-09 120 125 -8.940697e-08 4.470348e-09 120 126 -5.908699e+08 2.954350e+07 120 130 -1.490116e-07 7.450581e-09 120 131 -5.275624e+08 2.637812e+07 120 150 -1.287252e+09 6.436262e+07 120 154 -1.582687e+08 7.913437e+06 120 155 1.318906e+08 -6.594531e+06 120 156 -1.983635e+09 9.918174e+07 120 160 -6.330749e+08 3.165375e+07 120 161 1.490116e-08 -7.450581e-10 120 162 -1.287252e+09 6.436262e+07 120 166 -1.582687e+08 7.913437e+06 120 167 -1.318906e+08 6.594531e+06 121 121 1.796625e+10 -8.983125e+08 121 122 -7.152557e-07 3.576279e-08 121 127 -4.424986e+09 2.212493e+08 121 128 5.960464e-07 -2.980232e-08 121 151 -2.245781e+09 1.122891e+08 121 152 -1.725352e+09 8.626761e+07 121 157 -6.657689e+07 3.328845e+06 121 158 -2.682209e-07 1.341105e-08 121 163 -2.245781e+09 1.122891e+08 121 164 1.725352e+09 -8.626761e+07 122 122 2.134027e+10 -1.067014e+09 122 127 5.960464e-07 -2.980232e-08 122 128 2.169693e+09 -1.084847e+08 122 151 -1.725352e+09 8.626761e+07 122 152 -2.667534e+09 1.333767e+08 122 157 -3.874302e-07 1.937151e-08 122 158 -7.504762e+09 3.752381e+08 122 163 1.725352e+09 -8.626761e+07 122 164 -2.667534e+09 1.333767e+08 123 123 2.900850e+06 -1.450425e+05 123 129 -1.664422e+05 8.322112e+03 123 153 -3.626063e+05 1.813032e+04 123 159 -5.587704e+05 2.793852e+04 123 165 -3.626063e+05 1.813032e+04 124 124 3.561542e+08 -1.780771e+07 124 125 5.820766e-11 -2.910383e-12 124 126 -2.980232e-08 1.490116e-09 124 130 8.837909e+07 -4.418955e+06 124 131 -1.018634e-10 5.093170e-12 124 150 1.582687e+08 -7.913437e+06 124 154 2.142603e+07 -1.071302e+06 124 155 3.594484e+05 -1.797242e+04 124 156 6.330749e+08 -3.165375e+07 124 160 8.636358e+07 -4.318179e+06 124 161 9.458745e-11 -4.729372e-12 124 162 1.582687e+08 -7.913437e+06 124 166 2.142603e+07 -1.071302e+06 124 167 -3.594484e+05 1.797242e+04 125 125 3.554513e+08 -1.777256e+07 125 126 5.275624e+08 -2.637812e+07 125 130 -8.731149e-11 4.365575e-12 125 131 8.700520e+07 -4.350260e+06 125 150 -1.318906e+08 6.594531e+06 125 154 3.594484e+05 -1.797242e+04 125 155 2.151390e+07 -1.075695e+06 125 156 -4.470348e-08 2.235174e-09 125 160 6.548362e-11 -3.274181e-12 125 161 8.791320e+07 -4.395660e+06 125 162 1.318906e+08 -6.594531e+06 125 166 -3.594484e+05 1.797242e+04 125 167 2.151390e+07 -1.075695e+06 144 144 5.149009e+09 -2.574505e+08 144 148 0.000000e+00 -0.000000e+00 144 149 -5.275624e+08 2.637812e+07 144 150 -5.908699e+08 2.954350e+07 144 154 0.000000e+00 -0.000000e+00 144 155 -5.275624e+08 2.637812e+07 144 180 -9.918174e+08 4.959087e+07 144 184 -3.165375e+08 1.582687e+07 144 185 -1.318906e+08 6.594531e+06 144 186 -1.287252e+09 6.436262e+07 144 190 -1.582687e+08 7.913437e+06 144 191 -1.318906e+08 6.594531e+06 145 145 8.983125e+09 -4.491563e+08 145 146 2.384186e-07 -1.192093e-08 145 151 -4.424986e+09 2.212493e+08 145 152 1.192093e-07 -5.960464e-09 145 181 -3.328845e+07 1.664422e+06 145 182 -1.738727e+08 8.693635e+06 145 187 -2.245781e+09 1.122891e+08 145 188 1.725352e+09 -8.626761e+07 146 146 1.067014e+10 -5.335068e+08 146 151 2.384186e-07 -1.192093e-08 146 152 2.169693e+09 -1.084847e+08 146 181 1.738727e+08 -8.693635e+06 146 182 -3.752381e+09 1.876190e+08 146 187 1.725352e+09 -8.626761e+07 146 188 -2.667534e+09 1.333767e+08 147 147 1.450425e+06 -7.252126e+04 147 153 -1.664422e+05 8.322112e+03 147 183 -2.793852e+05 1.396926e+04 147 189 -3.626063e+05 1.813032e+04 148 148 1.780771e+08 -8.903855e+06 148 149 5.820766e-11 -2.910383e-12 148 150 0.000000e+00 -0.000000e+00 148 154 8.837909e+07 -4.418955e+06 148 155 0.000000e+00 -0.000000e+00 148 180 3.165375e+08 -1.582687e+07 148 184 4.318179e+07 -2.159090e+06 148 185 -3.622348e+04 1.811174e+03 148 186 1.582687e+08 -7.913437e+06 148 190 2.142603e+07 -1.071302e+06 148 191 -3.594484e+05 1.797242e+04 149 149 1.777256e+08 -8.886282e+06 149 150 5.275624e+08 -2.637812e+07 149 154 1.455192e-11 -7.275958e-13 149 155 8.700520e+07 -4.350260e+06 149 180 -1.318906e+08 6.594531e+06 149 184 3.622348e+04 -1.811174e+03 149 185 4.395660e+07 -2.197830e+06 149 186 1.318906e+08 -6.594531e+06 149 190 -3.594484e+05 1.797242e+04 149 191 2.151390e+07 -1.075695e+06 150 150 1.029802e+10 -5.149009e+08 150 154 1.192093e-07 -5.960464e-09 150 155 -8.940697e-08 4.470348e-09 150 156 -5.908699e+08 2.954350e+07 150 160 -1.192093e-07 5.960464e-09 150 161 -5.275624e+08 2.637812e+07 150 180 -1.287252e+09 6.436262e+07 150 184 -1.582687e+08 7.913437e+06 150 185 1.318906e+08 -6.594531e+06 150 186 -1.983635e+09 9.918174e+07 150 190 -6.330749e+08 3.165375e+07 150 191 -4.470348e-08 2.235174e-09 150 192 -1.287252e+09 6.436262e+07 150 196 -1.582687e+08 7.913437e+06 150 197 -1.318906e+08 6.594531e+06 151 151 1.796625e+10 -8.983125e+08 151 152 0.000000e+00 -0.000000e+00 151 157 -4.424986e+09 2.212493e+08 151 158 3.874302e-07 -1.937151e-08 151 181 -2.245781e+09 1.122891e+08 151 182 -1.725352e+09 8.626761e+07 151 187 -6.657689e+07 3.328845e+06 151 188 8.940697e-08 -4.470348e-09 151 193 -2.245781e+09 1.122891e+08 151 194 1.725352e+09 -8.626761e+07 152 152 2.134027e+10 -1.067014e+09 152 157 2.980232e-07 -1.490116e-08 152 158 2.169693e+09 -1.084847e+08 152 181 -1.725352e+09 8.626761e+07 152 182 -2.667534e+09 1.333767e+08 152 187 8.940697e-08 -4.470348e-09 152 188 -7.504762e+09 3.752381e+08 152 193 1.725352e+09 -8.626761e+07 152 194 -2.667534e+09 1.333767e+08 153 153 2.900850e+06 -1.450425e+05 153 159 -1.664422e+05 8.322112e+03 153 183 -3.626063e+05 1.813032e+04 153 189 -5.587704e+05 2.793852e+04 153 195 -3.626063e+05 1.813032e+04 154 154 3.561542e+08 -1.780771e+07 154 155 5.820766e-11 -2.910383e-12 154 156 -2.980232e-08 1.490116e-09 154 160 8.837909e+07 -4.418955e+06 154 161 -8.003553e-11 4.001777e-12 154 180 1.582687e+08 -7.913437e+06 154 184 2.142603e+07 -1.071302e+06 154 185 3.594484e+05 -1.797242e+04 154 186 6.330749e+08 -3.165375e+07 154 190 8.636358e+07 -4.318179e+06 154 191 1.455192e-11 -7.275958e-13 154 192 1.582687e+08 -7.913437e+06 154 196 2.142603e+07 -1.071302e+06 154 197 -3.594484e+05 1.797242e+04 155 155 3.554513e+08 -1.777256e+07 155 156 5.275624e+08 -2.637812e+07 155 160 7.275958e-12 -3.637979e-13 155 161 8.700520e+07 -4.350260e+06 155 180 -1.318906e+08 6.594531e+06 155 184 3.594484e+05 -1.797242e+04 155 185 2.151390e+07 -1.075695e+06 155 186 -1.490116e-08 7.450581e-10 155 190 0.000000e+00 -0.000000e+00 155 191 8.791320e+07 -4.395660e+06 155 192 1.318906e+08 -6.594531e+06 155 196 -3.594484e+05 1.797242e+04 155 197 2.151390e+07 -1.075695e+06 156 156 1.029802e+10 -5.149009e+08 156 160 1.788139e-07 -8.940697e-09 156 161 -8.940697e-08 4.470348e-09 156 162 -5.908699e+08 2.954350e+07 156 166 -1.192093e-07 5.960464e-09 156 167 -5.275624e+08 2.637812e+07 156 186 -1.287252e+09 6.436262e+07 156 190 -1.582687e+08 7.913437e+06 156 191 1.318906e+08 -6.594531e+06 156 192 -1.983635e+09 9.918174e+07 156 196 -6.330749e+08 3.165375e+07 156 197 -4.470348e-08 2.235174e-09 156 198 -1.287252e+09 6.436262e+07 156 202 -1.582687e+08 7.913437e+06 156 203 -1.318906e+08 6.594531e+06 157 157 1.796625e+10 -8.983125e+08 157 158 0.000000e+00 -0.000000e+00 157 163 -4.424986e+09 2.212493e+08 157 164 5.662441e-07 -2.831221e-08 157 187 -2.245781e+09 1.122891e+08 157 188 -1.725352e+09 8.626761e+07 157 193 -6.657689e+07 3.328845e+06 157 194 5.960464e-08 -2.980232e-09 157 199 -2.245781e+09 1.122891e+08 157 200 1.725352e+09 -8.626761e+07 158 158 2.134027e+10 -1.067014e+09 158 163 5.662441e-07 -2.831221e-08 158 164 2.169693e+09 -1.084847e+08 158 187 -1.725352e+09 8.626761e+07 158 188 -2.667534e+09 1.333767e+08 158 193 -1.788139e-07 8.940697e-09 158 194 -7.504762e+09 3.752381e+08 158 199 1.725352e+09 -8.626761e+07 158 200 -2.667534e+09 1.333767e+08 159 159 2.900850e+06 -1.450425e+05 159 165 -1.664422e+05 8.322112e+03 159 189 -3.626063e+05 1.813032e+04 159 195 -5.587704e+05 2.793852e+04 159 201 -3.626063e+05 1.813032e+04 160 160 3.561542e+08 -1.780771e+07 160 161 1.746230e-10 -8.731149e-12 160 162 -2.980232e-08 1.490116e-09 160 166 8.837909e+07 -4.418955e+06 160 167 -1.309672e-10 6.548362e-12 160 186 1.582687e+08 -7.913437e+06 160 190 2.142603e+07 -1.071302e+06 160 191 3.594484e+05 -1.797242e+04 160 192 6.330749e+08 -3.165375e+07 160 196 8.636358e+07 -4.318179e+06 160 197 8.003553e-11 -4.001777e-12 160 198 1.582687e+08 -7.913437e+06 160 202 2.142603e+07 -1.071302e+06 160 203 -3.594484e+05 1.797242e+04 161 161 3.554513e+08 -1.777256e+07 161 162 5.275624e+08 -2.637812e+07 161 166 -8.003553e-11 4.001777e-12 161 167 8.700520e+07 -4.350260e+06 161 186 -1.318906e+08 6.594531e+06 161 190 3.594484e+05 -1.797242e+04 161 191 2.151390e+07 -1.075695e+06 161 192 -1.490116e-08 7.450581e-10 161 196 3.637979e-11 -1.818989e-12 161 197 8.791320e+07 -4.395660e+06 161 198 1.318906e+08 -6.594531e+06 161 202 -3.594484e+05 1.797242e+04 161 203 2.151390e+07 -1.075695e+06 0 0 -3.252857e+09 0.000000e+00 0 6 -1.626429e+09 0.000000e+00 0 12 -1.626429e+09 0.000000e+00 0 18 -8.132143e+08 0.000000e+00 1 1 -3.252857e+09 0.000000e+00 1 2 -2.547374e-23 0.000000e+00 1 7 -1.626429e+09 0.000000e+00 1 8 -6.744929e-24 0.000000e+00 1 13 -1.626429e+09 0.000000e+00 1 14 4.167065e-24 -0.000000e+00 1 19 -8.132143e+08 0.000000e+00 2 2 -3.252857e+09 0.000000e+00 2 7 6.744929e-24 -0.000000e+00 2 8 -1.626429e+09 0.000000e+00 2 13 -4.167065e-24 0.000000e+00 2 14 -1.626429e+09 0.000000e+00 2 20 -8.132143e+08 0.000000e+00 4 4 -6.776786e+05 0.000000e+00 4 10 -3.388393e+05 0.000000e+00 4 16 -3.388393e+05 0.000000e+00 4 22 -1.694196e+05 0.000000e+00 5 5 -6.776786e+05 0.000000e+00 5 11 -3.388393e+05 0.000000e+00 5 17 -3.388393e+05 0.000000e+00 5 23 -1.694196e+05 0.000000e+00 6 6 -6.505714e+09 0.000000e+00 6 12 -8.132143e+08 0.000000e+00 6 18 -3.252857e+09 0.000000e+00 6 24 -1.626429e+09 0.000000e+00 6 30 -8.132143e+08 0.000000e+00 7 7 -6.505714e+09 0.000000e+00 7 8 -5.094747e-23 0.000000e+00 7 13 -8.132143e+08 0.000000e+00 7 19 -3.252857e+09 0.000000e+00 7 20 8.334131e-24 -0.000000e+00 7 25 -1.626429e+09 0.000000e+00 7 26 -6.744929e-24 0.000000e+00 7 31 -8.132143e+08 0.000000e+00 8 8 -6.505714e+09 0.000000e+00 8 14 -8.132143e+08 0.000000e+00 8 19 -8.334131e-24 0.000000e+00 8 20 -3.252857e+09 0.000000e+00 8 25 6.744929e-24 -0.000000e+00 8 26 -1.626429e+09 0.000000e+00 8 32 -8.132143e+08 0.000000e+00 10 10 -1.355357e+06 0.000000e+00 10 16 -1.694196e+05 0.000000e+00 10 22 -6.776786e+05 0.000000e+00 10 28 -3.388393e+05 0.000000e+00 10 34 -1.694196e+05 0.000000e+00 11 11 -1.355357e+06 0.000000e+00 11 17 -1.694196e+05 0.000000e+00 11 23 -6.776786e+05 0.000000e+00 11 29 -3.388393e+05 0.000000e+00 11 35 -1.694196e+05 0.000000e+00 12 12 -6.505714e+09 0.000000e+00 12 18 -3.252857e+09 0.000000e+00 12 72 -1.626429e+09 0.000000e+00 12 78 -8.132143e+08 0.000000e+00 13 13 -6.505714e+09 0.000000e+00 13 14 -1.864002e-23 0.000000e+00 13 19 -3.252857e+09 0.000000e+00 13 73 -1.626429e+09 0.000000e+00 13 74 6.636939e-24 -0.000000e+00 13 79 -8.132143e+08 0.000000e+00 14 14 -6.505714e+09 0.000000e+00 14 20 -3.252857e+09 0.000000e+00 14 73 -6.636939e-24 0.000000e+00 14 74 -1.626429e+09 0.000000e+00 14 80 -8.132143e+08 0.000000e+00 16 16 -1.355357e+06 0.000000e+00 16 22 -6.776786e+05 0.000000e+00 16 76 -3.388393e+05 0.000000e+00 16 82 -1.694196e+05 0.000000e+00 17 17 -1.355357e+06 0.000000e+00 17 23 -6.776786e+05 0.000000e+00 17 77 -3.388393e+05 0.000000e+00 17 83 -1.694196e+05 0.000000e+00 18 18 -1.301143e+10 0.000000e+00 18 24 -8.132143e+08 0.000000e+00 18 30 -3.252857e+09 0.000000e+00 18 72 -8.132143e+08 0.000000e+00 18 78 -3.252857e+09 0.000000e+00 18 84 -8.132143e+08 0.000000e+00 19 19 -1.301143e+10 0.000000e+00 19 20 -3.728003e-23 0.000000e+00 19 25 -8.132143e+08 0.000000e+00 19 31 -3.252857e+09 0.000000e+00 19 73 -8.132143e+08 0.000000e+00 19 79 -3.252857e+09 0.000000e+00 19 80 1.327388e-23 -0.000000e+00 19 85 -8.132143e+08 0.000000e+00 20 20 -1.301143e+10 0.000000e+00 20 26 -8.132143e+08 0.000000e+00 20 32 -3.252857e+09 0.000000e+00 20 74 -8.132143e+08 0.000000e+00 20 79 -1.327388e-23 0.000000e+00 20 80 -3.252857e+09 0.000000e+00 20 86 -8.132143e+08 0.000000e+00 22 22 -2.710714e+06 0.000000e+00 22 28 -1.694196e+05 0.000000e+00 22 34 -6.776786e+05 0.000000e+00 22 76 -1.694196e+05 0.000000e+00 22 82 -6.776786e+05 0.000000e+00 22 88 -1.694196e+05 0.000000e+00 23 23 -2.710714e+06 0.000000e+00 23 29 -1.694196e+05 0.000000e+00 23 35 -6.776786e+05 0.000000e+00 23 77 -1.694196e+05 0.000000e+00 23 83 -6.776786e+05 0.000000e+00 23 89 -1.694196e+05 0.000000e+00 24 24 -6.505714e+09 0.000000e+00 24 30 -3.252857e+09 0.000000e+00 24 36 -1.626429e+09 0.000000e+00 24 42 -8.132143e+08 0.000000e+00 25 25 -6.505714e+09 0.000000e+00 25 26 -5.094747e-23 0.000000e+00 25 31 -3.252857e+09 0.000000e+00 25 32 8.334131e-24 -0.000000e+00 25 37 -1.626429e+09 0.000000e+00 25 38 -6.744929e-24 0.000000e+00 25 43 -8.132143e+08 0.000000e+00 26 26 -6.505714e+09 0.000000e+00 26 31 -8.334131e-24 0.000000e+00 26 32 -3.252857e+09 0.000000e+00 26 37 6.744929e-24 -0.000000e+00 26 38 -1.626429e+09 0.000000e+00 26 44 -8.132143e+08 0.000000e+00 28 28 -1.355357e+06 0.000000e+00 28 34 -6.776786e+05 0.000000e+00 28 40 -3.388393e+05 0.000000e+00 28 46 -1.694196e+05 0.000000e+00 29 29 -1.355357e+06 0.000000e+00 29 35 -6.776786e+05 0.000000e+00 29 41 -3.388393e+05 0.000000e+00 29 47 -1.694196e+05 0.000000e+00 30 30 -1.301143e+10 0.000000e+00 30 36 -8.132143e+08 0.000000e+00 30 42 -3.252857e+09 0.000000e+00 30 78 -8.132143e+08 0.000000e+00 30 84 -3.252857e+09 0.000000e+00 30 90 -8.132143e+08 0.000000e+00 31 31 -1.301143e+10 0.000000e+00 31 32 -3.728003e-23 0.000000e+00 31 37 -8.132143e+08 0.000000e+00 31 43 -3.252857e+09 0.000000e+00 31 79 -8.132143e+08 0.000000e+00 31 85 -3.252857e+09 0.000000e+00 31 86 1.327388e-23 -0.000000e+00 31 91 -8.132143e+08 0.000000e+00 32 32 -1.301143e+10 0.000000e+00 32 38 -8.132143e+08 0.000000e+00 32 44 -3.252857e+09 0.000000e+00 32 80 -8.132143e+08 0.000000e+00 32 85 -1.327388e-23 0.000000e+00 32 86 -3.252857e+09 0.000000e+00 32 92 -8.132143e+08 0.000000e+00 34 34 -2.710714e+06 0.000000e+00 34 40 -1.694196e+05 0.000000e+00 34 46 -6.776786e+05 0.000000e+00 34 82 -1.694196e+05 0.000000e+00 34 88 -6.776786e+05 0.000000e+00 34 94 -1.694196e+05 0.000000e+00 35 35 -2.710714e+06 0.000000e+00 35 41 -1.694196e+05 0.000000e+00 35 47 -6.776786e+05 0.000000e+00 35 83 -1.694196e+05 0.000000e+00 35 89 -6.776786e+05 0.000000e+00 35 95 -1.694196e+05 0.000000e+00 72 72 -6.505714e+09 0.000000e+00 72 78 -3.252857e+09 0.000000e+00 72 108 -1.626429e+09 0.000000e+00 72 114 -8.132143e+08 0.000000e+00 73 73 -6.505714e+09 0.000000e+00 73 74 1.050743e-23 -0.000000e+00 73 79 -3.252857e+09 0.000000e+00 73 109 -1.626429e+09 0.000000e+00 73 115 -8.132143e+08 0.000000e+00 74 74 -6.505714e+09 0.000000e+00 74 80 -3.252857e+09 0.000000e+00 74 110 -1.626429e+09 0.000000e+00 74 116 -8.132143e+08 0.000000e+00 76 76 -1.355357e+06 0.000000e+00 76 82 -6.776786e+05 0.000000e+00 76 112 -3.388393e+05 0.000000e+00 76 118 -1.694196e+05 0.000000e+00 77 77 -1.355357e+06 0.000000e+00 77 83 -6.776786e+05 0.000000e+00 77 113 -3.388393e+05 0.000000e+00 77 119 -1.694196e+05 0.000000e+00 78 78 -1.301143e+10 0.000000e+00 78 84 -3.252857e+09 0.000000e+00 78 108 -8.132143e+08 0.000000e+00 78 114 -3.252857e+09 0.000000e+00 78 120 -8.132143e+08 0.000000e+00 79 79 -1.301143e+10 0.000000e+00 79 80 2.101486e-23 -0.000000e+00 79 85 -3.252857e+09 0.000000e+00 79 109 -8.132143e+08 0.000000e+00 79 115 -3.252857e+09 0.000000e+00 79 121 -8.132143e+08 0.000000e+00 80 80 -1.301143e+10 0.000000e+00 80 86 -3.252857e+09 0.000000e+00 80 110 -8.132143e+08 0.000000e+00 80 116 -3.252857e+09 0.000000e+00 80 122 -8.132143e+08 0.000000e+00 82 82 -2.710714e+06 0.000000e+00 82 88 -6.776786e+05 0.000000e+00 82 112 -1.694196e+05 0.000000e+00 82 118 -6.776786e+05 0.000000e+00 82 124 -1.694196e+05 0.000000e+00 83 83 -2.710714e+06 0.000000e+00 83 89 -6.776786e+05 0.000000e+00 83 113 -1.694196e+05 0.000000e+00 83 119 -6.776786e+05 0.000000e+00 83 125 -1.694196e+05 0.000000e+00 84 84 -1.301143e+10 0.000000e+00 84 90 -3.252857e+09 0.000000e+00 84 114 -8.132143e+08 0.000000e+00 84 120 -3.252857e+09 0.000000e+00 84 126 -8.132143e+08 0.000000e+00 85 85 -1.301143e+10 0.000000e+00 85 86 2.101486e-23 -0.000000e+00 85 91 -3.252857e+09 0.000000e+00 85 115 -8.132143e+08 0.000000e+00 85 121 -3.252857e+09 0.000000e+00 85 127 -8.132143e+08 0.000000e+00 86 86 -1.301143e+10 0.000000e+00 86 92 -3.252857e+09 0.000000e+00 86 116 -8.132143e+08 0.000000e+00 86 122 -3.252857e+09 0.000000e+00 86 128 -8.132143e+08 0.000000e+00 88 88 -2.710714e+06 0.000000e+00 88 94 -6.776786e+05 0.000000e+00 88 118 -1.694196e+05 0.000000e+00 88 124 -6.776786e+05 0.000000e+00 88 130 -1.694196e+05 0.000000e+00 89 89 -2.710714e+06 0.000000e+00 89 95 -6.776786e+05 0.000000e+00 89 119 -1.694196e+05 0.000000e+00 89 125 -6.776786e+05 0.000000e+00 89 131 -1.694196e+05 0.000000e+00 108 108 -6.505714e+09 0.000000e+00 108 114 -3.252857e+09 0.000000e+00 108 144 -1.626429e+09 0.000000e+00 108 150 -8.132143e+08 0.000000e+00 109 109 -6.505714e+09 0.000000e+00 109 110 -8.122739e-24 0.000000e+00 109 115 -3.252857e+09 0.000000e+00 109 145 -1.626429e+09 0.000000e+00 109 146 -6.306821e-24 0.000000e+00 109 151 -8.132143e+08 0.000000e+00 110 110 -6.505714e+09 0.000000e+00 110 116 -3.252857e+09 0.000000e+00 110 145 6.306821e-24 -0.000000e+00 110 146 -1.626429e+09 0.000000e+00 110 152 -8.132143e+08 0.000000e+00 112 112 -1.355357e+06 0.000000e+00 112 118 -6.776786e+05 0.000000e+00 112 148 -3.388393e+05 0.000000e+00 112 154 -1.694196e+05 0.000000e+00 113 113 -1.355357e+06 0.000000e+00 113 119 -6.776786e+05 0.000000e+00 113 149 -3.388393e+05 0.000000e+00 113 155 -1.694196e+05 0.000000e+00 114 114 -1.301143e+10 0.000000e+00 114 120 -3.252857e+09 0.000000e+00 114 144 -8.132143e+08 0.000000e+00 114 150 -3.252857e+09 0.000000e+00 114 156 -8.132143e+08 0.000000e+00 115 115 -1.301143e+10 0.000000e+00 115 116 -1.624548e-23 0.000000e+00 115 121 -3.252857e+09 0.000000e+00 115 145 -8.132143e+08 0.000000e+00 115 151 -3.252857e+09 0.000000e+00 115 152 -1.261364e-23 0.000000e+00 115 157 -8.132143e+08 0.000000e+00 116 116 -1.301143e+10 0.000000e+00 116 122 -3.252857e+09 0.000000e+00 116 146 -8.132143e+08 0.000000e+00 116 151 1.261364e-23 -0.000000e+00 116 152 -3.252857e+09 0.000000e+00 116 158 -8.132143e+08 0.000000e+00 118 118 -2.710714e+06 0.000000e+00 118 124 -6.776786e+05 0.000000e+00 118 148 -1.694196e+05 0.000000e+00 118 154 -6.776786e+05 0.000000e+00 118 160 -1.694196e+05 0.000000e+00 119 119 -2.710714e+06 0.000000e+00 119 125 -6.776786e+05 0.000000e+00 119 149 -1.694196e+05 0.000000e+00 119 155 -6.776786e+05 0.000000e+00 119 161 -1.694196e+05 0.000000e+00 120 120 -1.301143e+10 0.000000e+00 120 126 -3.252857e+09 0.000000e+00 120 150 -8.132143e+08 0.000000e+00 120 156 -3.252857e+09 0.000000e+00 120 162 -8.132143e+08 0.000000e+00 121 121 -1.301143e+10 0.000000e+00 121 122 -1.624548e-23 0.000000e+00 121 127 -3.252857e+09 0.000000e+00 121 151 -8.132143e+08 0.000000e+00 121 157 -3.252857e+09 0.000000e+00 121 158 -1.261364e-23 0.000000e+00 121 163 -8.132143e+08 0.000000e+00 122 122 -1.301143e+10 0.000000e+00 122 128 -3.252857e+09 0.000000e+00 122 152 -8.132143e+08 0.000000e+00 122 157 1.261364e-23 -0.000000e+00 122 158 -3.252857e+09 0.000000e+00 122 164 -8.132143e+08 0.000000e+00 124 124 -2.710714e+06 0.000000e+00 124 130 -6.776786e+05 0.000000e+00 124 154 -1.694196e+05 0.000000e+00 124 160 -6.776786e+05 0.000000e+00 124 166 -1.694196e+05 0.000000e+00 125 125 -2.710714e+06 0.000000e+00 125 131 -6.776786e+05 0.000000e+00 125 155 -1.694196e+05 0.000000e+00 125 161 -6.776786e+05 0.000000e+00 125 167 -1.694196e+05 0.000000e+00 144 144 -6.505714e+09 0.000000e+00 144 150 -3.252857e+09 0.000000e+00 144 180 -1.626429e+09 0.000000e+00 144 186 -8.132143e+08 0.000000e+00 145 145 -6.505714e+09 0.000000e+00 145 146 -1.635507e-23 0.000000e+00 145 151 -3.252857e+09 0.000000e+00 145 181 -1.626429e+09 0.000000e+00 145 187 -8.132143e+08 0.000000e+00 146 146 -6.505714e+09 0.000000e+00 146 152 -3.252857e+09 0.000000e+00 146 182 -1.626429e+09 0.000000e+00 146 188 -8.132143e+08 0.000000e+00 148 148 -1.355357e+06 0.000000e+00 148 154 -6.776786e+05 0.000000e+00 148 184 -3.388393e+05 0.000000e+00 148 190 -1.694196e+05 0.000000e+00 149 149 -1.355357e+06 0.000000e+00 149 155 -6.776786e+05 0.000000e+00 149 185 -3.388393e+05 0.000000e+00 149 191 -1.694196e+05 0.000000e+00 150 150 -1.301143e+10 0.000000e+00 150 156 -3.252857e+09 0.000000e+00 150 180 -8.132143e+08 0.000000e+00 150 186 -3.252857e+09 0.000000e+00 150 192 -8.132143e+08 0.000000e+00 151 151 -1.301143e+10 0.000000e+00 151 152 -3.271014e-23 0.000000e+00 151 157 -3.252857e+09 0.000000e+00 151 181 -8.132143e+08 0.000000e+00 151 187 -3.252857e+09 0.000000e+00 151 193 -8.132143e+08 0.000000e+00 152 152 -1.301143e+10 0.000000e+00 152 158 -3.252857e+09 0.000000e+00 152 182 -8.132143e+08 0.000000e+00 152 188 -3.252857e+09 0.000000e+00 152 194 -8.132143e+08 0.000000e+00 154 154 -2.710714e+06 0.000000e+00 154 160 -6.776786e+05 0.000000e+00 154 184 -1.694196e+05 0.000000e+00 154 190 -6.776786e+05 0.000000e+00 154 196 -1.694196e+05 0.000000e+00 155 155 -2.710714e+06 0.000000e+00 155 161 -6.776786e+05 0.000000e+00 155 185 -1.694196e+05 0.000000e+00 155 191 -6.776786e+05 0.000000e+00 155 197 -1.694196e+05 0.000000e+00 156 156 -1.301143e+10 0.000000e+00 156 162 -3.252857e+09 0.000000e+00 156 186 -8.132143e+08 0.000000e+00 156 192 -3.252857e+09 0.000000e+00 156 198 -8.132143e+08 0.000000e+00 157 157 -1.301143e+10 0.000000e+00 157 158 -3.271014e-23 0.000000e+00 157 163 -3.252857e+09 0.000000e+00 157 187 -8.132143e+08 0.000000e+00 157 193 -3.252857e+09 0.000000e+00 157 199 -8.132143e+08 0.000000e+00 158 158 -1.301143e+10 0.000000e+00 158 164 -3.252857e+09 0.000000e+00 158 188 -8.132143e+08 0.000000e+00 158 194 -3.252857e+09 0.000000e+00 158 200 -8.132143e+08 0.000000e+00 160 160 -2.710714e+06 0.000000e+00 160 166 -6.776786e+05 0.000000e+00 160 190 -1.694196e+05 0.000000e+00 160 196 -6.776786e+05 0.000000e+00 160 202 -1.694196e+05 0.000000e+00 161 161 -2.710714e+06 0.000000e+00 161 167 -6.776786e+05 0.000000e+00 161 191 -1.694196e+05 0.000000e+00 161 197 -6.776786e+05 0.000000e+00 161 203 -1.694196e+05 0.000000e+0 36 36 5.149009e+09 -2.574505e+08 36 40 -6.330749e+08 3.165375e+07 36 41 2.980232e-08 -1.490116e-09 36 42 -1.983635e+09 9.918174e+07 36 46 -6.330749e+08 3.165375e+07 36 47 4.470348e-08 -2.235174e-09 36 48 -2.954350e+08 1.477175e+07 36 52 -1.582687e+08 7.913437e+06 36 53 -2.637812e+08 1.318906e+07 36 54 -1.287252e+09 6.436262e+07 36 58 -1.582687e+08 7.913437e+06 36 59 -1.318906e+08 6.594531e+06 37 37 8.983125e+09 -4.491563e+08 37 38 4.768372e-07 -2.384186e-08 37 43 -6.657689e+07 3.328845e+06 37 44 -8.642673e-07 4.321337e-08 37 49 -2.212493e+09 1.106246e+08 37 50 1.738727e+08 -8.693635e+06 37 55 -2.245781e+09 1.122891e+08 37 56 1.725352e+09 -8.626761e+07 38 38 1.067014e+10 -5.335068e+08 38 43 -8.046627e-07 4.023314e-08 38 44 -7.504762e+09 3.752381e+08 38 49 -1.738727e+08 8.693635e+06 38 50 1.084847e+09 -5.424234e+07 38 55 1.725352e+09 -8.626761e+07 38 56 -2.667534e+09 1.333767e+08 39 39 1.450425e+06 -7.252126e+04 39 45 -5.587704e+05 2.793852e+04 39 51 -8.322112e+04 4.161056e+03 39 57 -3.626063e+05 1.813032e+04 40 40 1.780771e+08 -8.903855e+06 40 41 -1.164153e-10 5.820766e-12 40 42 6.330749e+08 -3.165375e+07 40 46 8.636358e+07 -4.318179e+06 40 47 1.673470e-10 -8.367351e-12 40 48 -1.582687e+08 7.913437e+06 40 52 4.418955e+07 -2.209477e+06 40 53 3.622348e+04 -1.811174e+03 40 54 1.582687e+08 -7.913437e+06 40 58 2.142603e+07 -1.071302e+06 40 59 -3.594484e+05 1.797242e+04 41 41 1.777256e+08 -8.886282e+06 41 42 -8.940697e-08 4.470348e-09 41 46 1.382432e-10 -6.912160e-12 41 47 8.791320e+07 -4.395660e+06 41 48 2.637812e+08 -1.318906e+07 41 52 -3.622348e+04 1.811174e+03 41 53 4.350260e+07 -2.175130e+06 41 54 1.318906e+08 -6.594531e+06 41 58 -3.594484e+05 1.797242e+04 41 59 2.151390e+07 -1.075695e+06 42 42 1.029802e+10 -5.149009e+08 42 46 2.384186e-07 -1.192093e-08 42 47 -5.960464e-08 2.980232e-09 42 48 -1.287252e+09 6.436262e+07 42 52 1.582687e+08 -7.913437e+06 42 53 -1.318906e+08 6.594531e+06 42 54 -5.908699e+08 2.954350e+07 42 58 2.980232e-08 -1.490116e-09 42 59 -5.275624e+08 2.637812e+07 42 84 -1.287252e+09 6.436262e+07 42 88 -1.582687e+08 7.913437e+06 42 89 1.318906e+08 -6.594531e+06 42 90 -1.983635e+09 9.918174e+07 42 94 -6.330749e+08 3.165375e+07 42 95 1.490116e-08 -7.450581e-10 42 96 -1.287252e+09 6.436262e+07 42 100 -1.582687e+08 7.913437e+06 42 101 -1.318906e+08 6.594531e+06 43 43 1.796625e+10 -8.983125e+08 43 44 2.384186e-07 -1.192093e-08 43 49 -2.245781e+09 1.122891e+08 43 50 -1.725352e+09 8.626761e+07 43 55 -4.424986e+09 2.212493e+08 43 56 -1.788139e-07 8.940697e-09 43 85 -2.245781e+09 1.122891e+08 43 86 -1.725352e+09 8.626761e+07 43 91 -6.657689e+07 3.328845e+06 43 92 5.960464e-08 -2.980232e-09 43 97 -2.245781e+09 1.122891e+08 43 98 1.725352e+09 -8.626761e+07 44 44 2.134027e+10 -1.067014e+09 44 49 -1.725352e+09 8.626761e+07 44 50 -2.667534e+09 1.333767e+08 44 55 -2.086163e-07 1.043081e-08 44 56 2.169693e+09 -1.084847e+08 44 85 -1.725352e+09 8.626761e+07 44 86 -2.667534e+09 1.333767e+08 44 91 -1.490116e-07 7.450581e-09 44 92 -7.504762e+09 3.752381e+08 44 97 1.725352e+09 -8.626761e+07 44 98 -2.667534e+09 1.333767e+08 45 45 2.900850e+06 -1.450425e+05 45 51 -3.626063e+05 1.813032e+04 45 57 -1.664422e+05 8.322112e+03 45 87 -3.626063e+05 1.813032e+04 45 93 -5.587704e+05 2.793852e+04 45 99 -3.626063e+05 1.813032e+04 46 46 3.561542e+08 -1.780771e+07 46 47 0.000000e+00 -0.000000e+00 46 48 -1.582687e+08 7.913437e+06 46 52 2.142603e+07 -1.071302e+06 46 53 3.594484e+05 -1.797242e+04 46 54 -8.940697e-08 4.470348e-09 46 58 8.837909e+07 -4.418955e+06 46 59 2.182787e-11 -1.091394e-12 46 84 1.582687e+08 -7.913437e+06 46 88 2.142603e+07 -1.071302e+06 46 89 3.594484e+05 -1.797242e+04 46 90 6.330749e+08 -3.165375e+07 46 94 8.636358e+07 -4.318179e+06 46 95 5.820766e-11 -2.910383e-12 46 96 1.582687e+08 -7.913437e+06 46 100 2.142603e+07 -1.071302e+06 46 101 -3.594484e+05 1.797242e+04 47 47 3.554513e+08 -1.777256e+07 47 48 1.318906e+08 -6.594531e+06 47 52 3.594484e+05 -1.797242e+04 47 53 2.151390e+07 -1.075695e+06 47 54 5.275624e+08 -2.637812e+07 47 58 4.365575e-11 -2.182787e-12 47 59 8.700520e+07 -4.350260e+06 47 84 -1.318906e+08 6.594531e+06 47 88 3.594484e+05 -1.797242e+04 47 89 2.151390e+07 -1.075695e+06 47 90 -1.490116e-08 7.450581e-10 47 94 -7.275958e-12 3.637979e-13 47 95 8.791320e+07 -4.395660e+06 47 96 1.318906e+08 -6.594531e+06 47 100 -3.594484e+05 1.797242e+04 47 101 2.151390e+07 -1.075695e+06 48 48 5.149009e+09 -2.574505e+08 48 52 -6.330749e+08 3.165375e+07 48 53 2.980232e-08 -1.490116e-09 48 54 -1.983635e+09 9.918174e+07 48 58 -6.330749e+08 3.165375e+07 48 59 4.470348e-08 -2.235174e-09 48 60 -2.954350e+08 1.477175e+07 48 64 -1.582687e+08 7.913437e+06 48 65 -2.637812e+08 1.318906e+07 48 66 -1.287252e+09 6.436262e+07 48 70 -1.582687e+08 7.913437e+06 48 71 -1.318906e+08 6.594531e+06 49 49 8.983125e+09 -4.491563e+08 49 50 9.536743e-07 -4.768372e-08 49 55 -6.657689e+07 3.328845e+06 49 56 -5.662441e-07 2.831221e-08 49 61 -2.212493e+09 1.106246e+08 49 62 1.738727e+08 -8.693635e+06 49 67 -2.245781e+09 1.122891e+08 49 68 1.725352e+09 -8.626761e+07 50 50 1.067014e+10 -5.335068e+08 50 55 -5.364418e-07 2.682209e-08 50 56 -7.504762e+09 3.752381e+08 50 61 -1.738727e+08 8.693635e+06 50 62 1.084847e+09 -5.424234e+07 50 67 1.725352e+09 -8.626761e+07 50 68 -2.667534e+09 1.333767e+08 51 51 1.450425e+06 -7.252126e+04 51 57 -5.587704e+05 2.793852e+04 51 63 -8.322112e+04 4.161056e+03 51 69 -3.626063e+05 1.813032e+04 52 52 1.780771e+08 -8.903855e+06 52 53 -2.328306e-10 1.164153e-11 52 54 6.330749e+08 -3.165375e+07 52 58 8.636358e+07 -4.318179e+06 52 59 1.018634e-10 -5.093170e-12 52 60 -1.582687e+08 7.913437e+06 52 64 4.418955e+07 -2.209477e+06 52 65 3.622348e+04 -1.811174e+03 52 66 1.582687e+08 -7.913437e+06 52 70 2.142603e+07 -1.071302e+06 52 71 -3.594484e+05 1.797242e+04 53 53 1.777256e+08 -8.886282e+06 53 54 -8.940697e-08 4.470348e-09 53 58 9.458745e-11 -4.729372e-12 53 59 8.791320e+07 -4.395660e+06 53 60 2.637812e+08 -1.318906e+07 53 64 -3.622348e+04 1.811174e+03 53 65 4.350260e+07 -2.175130e+06 53 66 1.318906e+08 -6.594531e+06 53 70 -3.594484e+05 1.797242e+04 53 71 2.151390e+07 -1.075695e+06 54 54 1.029802e+10 -5.149009e+08 54 58 1.192093e-07 -5.960464e-09 54 59 -5.960464e-08 2.980232e-09 54 60 -1.287252e+09 6.436262e+07 54 64 1.582687e+08 -7.913437e+06 54 65 -1.318906e+08 6.594531e+06 54 66 -5.908699e+08 2.954350e+07 54 70 -5.960464e-08 2.980232e-09 54 71 -5.275624e+08 2.637812e+07 54 90 -1.287252e+09 6.436262e+07 54 94 -1.582687e+08 7.913437e+06 54 95 1.318906e+08 -6.594531e+06 54 96 -1.983635e+09 9.918174e+07 54 100 -6.330749e+08 3.165375e+07 54 101 1.490116e-08 -7.450581e-10 54 102 -1.287252e+09 6.436262e+07 54 106 -1.582687e+08 7.913437e+06 54 107 -1.318906e+08 6.594531e+06 55 55 1.796625e+10 -8.983125e+08 55 56 9.536743e-07 -4.768372e-08 55 61 -2.245781e+09 1.122891e+08 55 62 -1.725352e+09 8.626761e+07 55 67 -4.424986e+09 2.212493e+08 55 68 1.192093e-07 -5.960464e-09 55 91 -2.245781e+09 1.122891e+08 55 92 -1.725352e+09 8.626761e+07 55 97 -6.657689e+07 3.328845e+06 55 98 1.192093e-07 -5.960464e-09 55 103 -2.245781e+09 1.122891e+08 55 104 1.725352e+09 -8.626761e+07 56 56 2.134027e+10 -1.067014e+09 56 61 -1.725352e+09 8.626761e+07 56 62 -2.667534e+09 1.333767e+08 56 67 5.960464e-08 -2.980232e-09 56 68 2.169693e+09 -1.084847e+08 56 91 -1.725352e+09 8.626761e+07 56 92 -2.667534e+09 1.333767e+08 56 97 -8.940697e-08 4.470348e-09 56 98 -7.504762e+09 3.752381e+08 56 103 1.725352e+09 -8.626761e+07 56 104 -2.667534e+09 1.333767e+08 57 57 2.900850e+06 -1.450425e+05 57 63 -3.626063e+05 1.813032e+04 57 69 -1.664422e+05 8.322112e+03 57 93 -3.626063e+05 1.813032e+04 57 99 -5.587704e+05 2.793852e+04 57 105 -3.626063e+05 1.813032e+04 58 58 3.561542e+08 -1.780771e+07 58 59 -1.164153e-10 5.820766e-12 58 60 -1.582687e+08 7.913437e+06 58 64 2.142603e+07 -1.071302e+06 58 65 3.594484e+05 -1.797242e+04 58 66 -5.960464e-08 2.980232e-09 58 70 8.837909e+07 -4.418955e+06 58 71 -5.093170e-11 2.546585e-12 58 90 1.582687e+08 -7.913437e+06 58 94 2.142603e+07 -1.071302e+06 58 95 3.594484e+05 -1.797242e+04 58 96 6.330749e+08 -3.165375e+07 58 100 8.636358e+07 -4.318179e+06 58 101 0.000000e+00 -0.000000e+00 58 102 1.582687e+08 -7.913437e+06 58 106 2.142603e+07 -1.071302e+06 58 107 -3.594484e+05 1.797242e+04 59 59 3.554513e+08 -1.777256e+07 59 60 1.318906e+08 -6.594531e+06 59 64 3.594484e+05 -1.797242e+04 59 65 2.151390e+07 -1.075695e+06 59 66 5.275624e+08 -2.637812e+07 59 70 0.000000e+00 -0.000000e+00 59 71 8.700520e+07 -4.350260e+06 59 90 -1.318906e+08 6.594531e+06 59 94 3.594484e+05 -1.797242e+04 59 95 2.151390e+07 -1.075695e+06 59 96 -1.490116e-08 7.450581e-10 59 100 -2.182787e-11 1.091394e-12 59 101 8.791320e+07 -4.395660e+06 59 102 1.318906e+08 -6.594531e+06 59 106 -3.594484e+05 1.797242e+04 59 107 2.151390e+07 -1.075695e+06 60 60 2.574505e+09 -1.287252e+08 60 64 -3.165375e+08 1.582687e+07 60 65 2.637812e+08 -1.318906e+07 60 66 -9.918174e+08 4.959087e+07 60 70 -3.165375e+08 1.582687e+07 60 71 1.318906e+08 -6.594531e+06 61 61 4.491563e+09 -2.245781e+08 61 62 1.725352e+09 -8.626761e+07 61 67 -3.328845e+07 1.664422e+06 61 68 1.738727e+08 -8.693635e+06 62 62 5.335068e+09 -2.667534e+08 62 67 -1.738727e+08 8.693635e+06 62 68 -3.752381e+09 1.876190e+08 63 63 7.252126e+05 -3.626063e+04 63 69 -2.793852e+05 1.396926e+04 64 64 8.903855e+07 -4.451927e+06 64 65 -3.594484e+05 1.797242e+04 64 66 3.165375e+08 -1.582687e+07 64 70 4.318179e+07 -2.159090e+06 64 71 3.622348e+04 -1.811174e+03 65 65 8.886282e+07 -4.443141e+06 65 66 1.318906e+08 -6.594531e+06 65 70 -3.622348e+04 1.811174e+03 65 71 4.395660e+07 -2.197830e+06 66 66 5.149009e+09 -2.574505e+08 66 70 5.960464e-08 -2.980232e-09 66 71 5.275624e+08 -2.637812e+07 66 96 -1.287252e+09 6.436262e+07 66 100 -1.582687e+08 7.913437e+06 66 101 1.318906e+08 -6.594531e+06 66 102 -9.918174e+08 4.959087e+07 66 106 -3.165375e+08 1.582687e+07 66 107 1.318906e+08 -6.594531e+06 67 67 8.983125e+09 -4.491563e+08 67 68 4.768372e-07 -2.384186e-08 67 97 -2.245781e+09 1.122891e+08 67 98 -1.725352e+09 8.626761e+07 67 103 -3.328845e+07 1.664422e+06 67 104 1.738727e+08 -8.693635e+06 68 68 1.067014e+10 -5.335068e+08 68 97 -1.725352e+09 8.626761e+07 68 98 -2.667534e+09 1.333767e+08 68 103 -1.738727e+08 8.693635e+06 68 104 -3.752381e+09 1.876190e+08 69 69 1.450425e+06 -7.252126e+04 69 99 -3.626063e+05 1.813032e+04 69 105 -2.793852e+05 1.396926e+04 70 70 1.780771e+08 -8.903855e+06 70 71 -5.820766e-11 2.910383e-12 70 96 1.582687e+08 -7.913437e+06 70 100 2.142603e+07 -1.071302e+06 70 101 3.594484e+05 -1.797242e+04 70 102 3.165375e+08 -1.582687e+07 70 106 4.318179e+07 -2.159090e+06 70 107 3.622348e+04 -1.811174e+03 71 71 1.777256e+08 -8.886282e+06 71 96 -1.318906e+08 6.594531e+06 71 100 3.594484e+05 -1.797242e+04 71 101 2.151390e+07 -1.075695e+06 71 102 1.318906e+08 -6.594531e+06 71 106 -3.622348e+04 1.811174e+03 71 107 4.395660e+07 -2.197830e+06 90 90 1.029802e+10 -5.149009e+08 90 94 2.980232e-07 -1.490116e-08 90 95 -5.960464e-08 2.980232e-09 90 96 -5.908699e+08 2.954350e+07 90 100 2.980232e-08 -1.490116e-09 90 101 -5.275624e+08 2.637812e+07 90 120 -1.287252e+09 6.436262e+07 90 124 -1.582687e+08 7.913437e+06 90 125 1.318906e+08 -6.594531e+06 90 126 -1.983635e+09 9.918174e+07 90 130 -6.330749e+08 3.165375e+07 90 131 2.980232e-08 -1.490116e-09 90 132 -1.287252e+09 6.436262e+07 90 136 -1.582687e+08 7.913437e+06 90 137 -1.318906e+08 6.594531e+06 91 91 1.796625e+10 -8.983125e+08 91 92 -4.768372e-07 2.384186e-08 91 97 -4.424986e+09 2.212493e+08 91 98 -2.980232e-07 1.490116e-08 91 121 -2.245781e+09 1.122891e+08 91 122 -1.725352e+09 8.626761e+07 91 127 -6.657689e+07 3.328845e+06 91 128 -1.192093e-07 5.960464e-09 91 133 -2.245781e+09 1.122891e+08 91 134 1.725352e+09 -8.626761e+07 92 92 2.134027e+10 -1.067014e+09 92 97 -2.384186e-07 1.192093e-08 92 98 2.169693e+09 -1.084847e+08 92 121 -1.725352e+09 8.626761e+07 92 122 -2.667534e+09 1.333767e+08 92 127 1.192093e-07 -5.960464e-09 92 128 -7.504762e+09 3.752381e+08 92 133 1.725352e+09 -8.626761e+07 92 134 -2.667534e+09 1.333767e+08 93 93 2.900850e+06 -1.450425e+05 93 99 -1.664422e+05 8.322112e+03 93 123 -3.626063e+05 1.813032e+04 93 129 -5.587704e+05 2.793852e+04 93 135 -3.626063e+05 1.813032e+04 94 94 3.561542e+08 -1.780771e+07 94 95 -5.820766e-11 2.910383e-12 94 96 -8.940697e-08 4.470348e-09 94 100 8.837909e+07 -4.418955e+06 94 101 5.820766e-11 -2.910383e-12 94 120 1.582687e+08 -7.913437e+06 94 124 2.142603e+07 -1.071302e+06 94 125 3.594484e+05 -1.797242e+04 94 126 6.330749e+08 -3.165375e+07 94 130 8.636358e+07 -4.318179e+06 94 131 7.275958e-12 -3.637979e-13 94 132 1.582687e+08 -7.913437e+06 94 136 2.142603e+07 -1.071302e+06 94 137 -3.594484e+05 1.797242e+04 95 95 3.554513e+08 -1.777256e+07 95 96 5.275624e+08 -2.637812e+07 95 100 5.093170e-11 -2.546585e-12 95 101 8.700520e+07 -4.350260e+06 95 120 -1.318906e+08 6.594531e+06 95 124 3.594484e+05 -1.797242e+04 95 125 2.151390e+07 -1.075695e+06 95 126 -1.490116e-08 7.450581e-10 95 130 2.182787e-11 -1.091394e-12 95 131 8.791320e+07 -4.395660e+06 95 132 1.318906e+08 -6.594531e+06 95 136 -3.594484e+05 1.797242e+04 95 137 2.151390e+07 -1.075695e+06 96 96 1.029802e+10 -5.149009e+08 96 100 5.960464e-08 -2.980232e-09 96 101 -5.960464e-08 2.980232e-09 96 102 -5.908699e+08 2.954350e+07 96 106 -5.960464e-08 2.980232e-09 96 107 -5.275624e+08 2.637812e+07 96 126 -1.287252e+09 6.436262e+07 96 130 -1.582687e+08 7.913437e+06 96 131 1.318906e+08 -6.594531e+06 96 132 -1.983635e+09 9.918174e+07 96 136 -6.330749e+08 3.165375e+07 96 137 2.980232e-08 -1.490116e-09 96 138 -1.287252e+09 6.436262e+07 96 142 -1.582687e+08 7.913437e+06 96 143 -1.318906e+08 6.594531e+06 97 97 1.796625e+10 -8.983125e+08 97 98 -2.384186e-07 1.192093e-08 97 103 -4.424986e+09 2.212493e+08 97 104 -5.960464e-08 2.980232e-09 97 127 -2.245781e+09 1.122891e+08 97 128 -1.725352e+09 8.626761e+07 97 133 -6.657689e+07 3.328845e+06 97 134 -5.960464e-08 2.980232e-09 97 139 -2.245781e+09 1.122891e+08 97 140 1.725352e+09 -8.626761e+07 98 98 2.134027e+10 -1.067014e+09 98 103 0.000000e+00 -0.000000e+00 98 104 2.169693e+09 -1.084847e+08 98 127 -1.725352e+09 8.626761e+07 98 128 -2.667534e+09 1.333767e+08 98 133 2.384186e-07 -1.192093e-08 98 134 -7.504762e+09 3.752381e+08 98 139 1.725352e+09 -8.626761e+07 98 140 -2.667534e+09 1.333767e+08 99 99 2.900850e+06 -1.450425e+05 99 105 -1.664422e+05 8.322112e+03 99 129 -3.626063e+05 1.813032e+04 99 135 -5.587704e+05 2.793852e+04 99 141 -3.626063e+05 1.813032e+04 100 100 3.561542e+08 -1.780771e+07 100 101 -1.746230e-10 8.731149e-12 100 102 -5.960464e-08 2.980232e-09 100 106 8.837909e+07 -4.418955e+06 100 107 -7.275958e-12 3.637979e-13 100 126 1.582687e+08 -7.913437e+06 100 130 2.142603e+07 -1.071302e+06 100 131 3.594484e+05 -1.797242e+04 100 132 6.330749e+08 -3.165375e+07 100 136 8.636358e+07 -4.318179e+06 100 137 -4.365575e-11 2.182787e-12 100 138 1.582687e+08 -7.913437e+06 100 142 2.142603e+07 -1.071302e+06 100 143 -3.594484e+05 1.797242e+04 101 101 3.554513e+08 -1.777256e+07 101 102 5.275624e+08 -2.637812e+07 101 106 2.910383e-11 -1.455192e-12 101 107 8.700520e+07 -4.350260e+06 101 126 -1.318906e+08 6.594531e+06 101 130 3.594484e+05 -1.797242e+04 101 131 2.151390e+07 -1.075695e+06 101 132 -1.490116e-08 7.450581e-10 101 136 -2.182787e-11 1.091394e-12 101 137 8.791320e+07 -4.395660e+06 101 138 1.318906e+08 -6.594531e+06 101 142 -3.594484e+05 1.797242e+04 101 143 2.151390e+07 -1.075695e+06 102 102 5.149009e+09 -2.574505e+08 102 106 0.000000e+00 -0.000000e+00 102 107 5.275624e+08 -2.637812e+07 102 132 -1.287252e+09 6.436262e+07 102 136 -1.582687e+08 7.913437e+06 102 137 1.318906e+08 -6.594531e+06 102 138 -9.918174e+08 4.959087e+07 102 142 -3.165375e+08 1.582687e+07 102 143 1.318906e+08 -6.594531e+06 103 103 8.983125e+09 -4.491563e+08 103 104 -2.384186e-07 1.192093e-08 103 133 -2.245781e+09 1.122891e+08 103 134 -1.725352e+09 8.626761e+07 103 139 -3.328845e+07 1.664422e+06 103 140 1.738727e+08 -8.693635e+06 104 104 1.067014e+10 -5.335068e+08 104 133 -1.725352e+09 8.626761e+07 104 134 -2.667534e+09 1.333767e+08 104 139 -1.738727e+08 8.693635e+06 104 140 -3.752381e+09 1.876190e+08 105 105 1.450425e+06 -7.252126e+04 105 135 -3.626063e+05 1.813032e+04 105 141 -2.793852e+05 1.396926e+04 106 106 1.780771e+08 -8.903855e+06 106 107 -1.746230e-10 8.731149e-12 106 132 1.582687e+08 -7.913437e+06 106 136 2.142603e+07 -1.071302e+06 106 137 3.594484e+05 -1.797242e+04 106 138 3.165375e+08 -1.582687e+07 106 142 4.318179e+07 -2.159090e+06 106 143 3.622348e+04 -1.811174e+03 107 107 1.777256e+08 -8.886282e+06 107 132 -1.318906e+08 6.594531e+06 107 136 3.594484e+05 -1.797242e+04 107 137 2.151390e+07 -1.075695e+06 107 138 1.318906e+08 -6.594531e+06 107 142 -3.622348e+04 1.811174e+03 107 143 4.395660e+07 -2.197830e+06 126 126 1.029802e+10 -5.149009e+08 126 130 2.384186e-07 -1.192093e-08 126 131 -8.940697e-08 4.470348e-09 126 132 -5.908699e+08 2.954350e+07 126 136 2.980232e-08 -1.490116e-09 126 137 -5.275624e+08 2.637812e+07 126 156 -1.287252e+09 6.436262e+07 126 160 -1.582687e+08 7.913437e+06 126 161 1.318906e+08 -6.594531e+06 126 162 -1.983635e+09 9.918174e+07 126 166 -6.330749e+08 3.165375e+07 126 167 1.490116e-08 -7.450581e-10 126 168 -1.287252e+09 6.436262e+07 126 172 -1.582687e+08 7.913437e+06 126 173 -1.318906e+08 6.594531e+06 127 127 1.796625e+10 -8.983125e+08 127 128 -2.384186e-07 1.192093e-08 127 133 -4.424986e+09 2.212493e+08 127 134 -1.192093e-07 5.960464e-09 127 157 -2.245781e+09 1.122891e+08 127 158 -1.725352e+09 8.626761e+07 127 163 -6.657689e+07 3.328845e+06 127 164 -2.980232e-07 1.490116e-08 127 169 -2.245781e+09 1.122891e+08 127 170 1.725352e+09 -8.626761e+07 128 128 2.134027e+10 -1.067014e+09 128 133 -1.788139e-07 8.940697e-09 128 134 2.169693e+09 -1.084847e+08 128 157 -1.725352e+09 8.626761e+07 128 158 -2.667534e+09 1.333767e+08 128 163 -1.490116e-07 7.450581e-09 128 164 -7.504762e+09 3.752381e+08 128 169 1.725352e+09 -8.626761e+07 128 170 -2.667534e+09 1.333767e+08 129 129 2.900850e+06 -1.450425e+05 129 135 -1.664422e+05 8.322112e+03 129 159 -3.626063e+05 1.813032e+04 129 165 -5.587704e+05 2.793852e+04 129 171 -3.626063e+05 1.813032e+04 130 130 3.561542e+08 -1.780771e+07 130 131 -1.164153e-10 5.820766e-12 130 132 -8.940697e-08 4.470348e-09 130 136 8.837909e+07 -4.418955e+06 130 137 3.637979e-11 -1.818989e-12 130 156 1.582687e+08 -7.913437e+06 130 160 2.142603e+07 -1.071302e+06 130 161 3.594484e+05 -1.797242e+04 130 162 6.330749e+08 -3.165375e+07 130 166 8.636358e+07 -4.318179e+06 130 167 8.003553e-11 -4.001777e-12 130 168 1.582687e+08 -7.913437e+06 130 172 2.142603e+07 -1.071302e+06 130 173 -3.594484e+05 1.797242e+04 131 131 3.554513e+08 -1.777256e+07 131 132 5.275624e+08 -2.637812e+07 131 136 7.275958e-11 -3.637979e-12 131 137 8.700520e+07 -4.350260e+06 131 156 -1.318906e+08 6.594531e+06 131 160 3.594484e+05 -1.797242e+04 131 161 2.151390e+07 -1.075695e+06 131 162 -4.470348e-08 2.235174e-09 131 166 3.637979e-11 -1.818989e-12 131 167 8.791320e+07 -4.395660e+06 131 168 1.318906e+08 -6.594531e+06 131 172 -3.594484e+05 1.797242e+04 131 173 2.151390e+07 -1.075695e+06 36 36 -6.505714e+09 0.000000e+00 36 42 -3.252857e+09 0.000000e+00 36 48 -1.626429e+09 0.000000e+00 36 54 -8.132143e+08 0.000000e+00 37 37 -6.505714e+09 0.000000e+00 37 38 -5.094747e-23 0.000000e+00 37 43 -3.252857e+09 0.000000e+00 37 44 8.334131e-24 -0.000000e+00 37 49 -1.626429e+09 0.000000e+00 37 50 -6.744929e-24 0.000000e+00 37 55 -8.132143e+08 0.000000e+00 38 38 -6.505714e+09 0.000000e+00 38 43 -8.334131e-24 0.000000e+00 38 44 -3.252857e+09 0.000000e+00 38 49 6.744929e-24 -0.000000e+00 38 50 -1.626429e+09 0.000000e+00 38 56 -8.132143e+08 0.000000e+00 40 40 -1.355357e+06 0.000000e+00 40 46 -6.776786e+05 0.000000e+00 40 52 -3.388393e+05 0.000000e+00 40 58 -1.694196e+05 0.000000e+00 41 41 -1.355357e+06 0.000000e+00 41 47 -6.776786e+05 0.000000e+00 41 53 -3.388393e+05 0.000000e+00 41 59 -1.694196e+05 0.000000e+00 42 42 -1.301143e+10 0.000000e+00 42 48 -8.132143e+08 0.000000e+00 42 54 -3.252857e+09 0.000000e+00 42 84 -8.132143e+08 0.000000e+00 42 90 -3.252857e+09 0.000000e+00 42 96 -8.132143e+08 0.000000e+00 43 43 -1.301143e+10 0.000000e+00 43 44 -3.728003e-23 0.000000e+00 43 49 -8.132143e+08 0.000000e+00 43 55 -3.252857e+09 0.000000e+00 43 85 -8.132143e+08 0.000000e+00 43 91 -3.252857e+09 0.000000e+00 43 92 1.327388e-23 -0.000000e+00 43 97 -8.132143e+08 0.000000e+00 44 44 -1.301143e+10 0.000000e+00 44 50 -8.132143e+08 0.000000e+00 44 56 -3.252857e+09 0.000000e+00 44 86 -8.132143e+08 0.000000e+00 44 91 -1.327388e-23 0.000000e+00 44 92 -3.252857e+09 0.000000e+00 44 98 -8.132143e+08 0.000000e+00 46 46 -2.710714e+06 0.000000e+00 46 52 -1.694196e+05 0.000000e+00 46 58 -6.776786e+05 0.000000e+00 46 88 -1.694196e+05 0.000000e+00 46 94 -6.776786e+05 0.000000e+00 46 100 -1.694196e+05 0.000000e+00 47 47 -2.710714e+06 0.000000e+00 47 53 -1.694196e+05 0.000000e+00 47 59 -6.776786e+05 0.000000e+00 47 89 -1.694196e+05 0.000000e+00 47 95 -6.776786e+05 0.000000e+00 47 101 -1.694196e+05 0.000000e+00 48 48 -6.505714e+09 0.000000e+00 48 54 -3.252857e+09 0.000000e+00 48 60 -1.626429e+09 0.000000e+00 48 66 -8.132143e+08 0.000000e+00 49 49 -6.505714e+09 0.000000e+00 49 50 -5.080446e-23 0.000000e+00 49 55 -3.252857e+09 0.000000e+00 49 56 4.167065e-24 -0.000000e+00 49 61 -1.626429e+09 0.000000e+00 49 62 -6.675074e-24 0.000000e+00 49 67 -8.132143e+08 0.000000e+00 50 50 -6.505714e+09 0.000000e+00 50 55 -4.167065e-24 0.000000e+00 50 56 -3.252857e+09 0.000000e+00 50 61 6.675074e-24 -0.000000e+00 50 62 -1.626429e+09 0.000000e+00 50 68 -8.132143e+08 0.000000e+00 52 52 -1.355357e+06 0.000000e+00 52 58 -6.776786e+05 0.000000e+00 52 64 -3.388393e+05 0.000000e+00 52 70 -1.694196e+05 0.000000e+00 53 53 -1.355357e+06 0.000000e+00 53 59 -6.776786e+05 0.000000e+00 53 65 -3.388393e+05 0.000000e+00 53 71 -1.694196e+05 0.000000e+00 54 54 -1.301143e+10 0.000000e+00 54 60 -8.132143e+08 0.000000e+00 54 66 -3.252857e+09 0.000000e+00 54 90 -8.132143e+08 0.000000e+00 54 96 -3.252857e+09 0.000000e+00 54 102 -8.132143e+08 0.000000e+00 55 55 -1.301143e+10 0.000000e+00 55 56 -3.621390e-23 0.000000e+00 55 61 -8.132143e+08 0.000000e+00 55 67 -3.252857e+09 0.000000e+00 55 91 -8.132143e+08 0.000000e+00 55 97 -3.252857e+09 0.000000e+00 55 98 1.245219e-23 -0.000000e+00 55 103 -8.132143e+08 0.000000e+00 56 56 -1.301143e+10 0.000000e+00 56 62 -8.132143e+08 0.000000e+00 56 68 -3.252857e+09 0.000000e+00 56 92 -8.132143e+08 0.000000e+00 56 97 -1.245219e-23 0.000000e+00 56 98 -3.252857e+09 0.000000e+00 56 104 -8.132143e+08 0.000000e+00 58 58 -2.710714e+06 0.000000e+00 58 64 -1.694196e+05 0.000000e+00 58 70 -6.776786e+05 0.000000e+00 58 94 -1.694196e+05 0.000000e+00 58 100 -6.776786e+05 0.000000e+00 58 106 -1.694196e+05 0.000000e+00 59 59 -2.710714e+06 0.000000e+00 59 65 -1.694196e+05 0.000000e+00 59 71 -6.776786e+05 0.000000e+00 59 95 -1.694196e+05 0.000000e+00 59 101 -6.776786e+05 0.000000e+00 59 107 -1.694196e+05 0.000000e+00 60 60 -3.252857e+09 0.000000e+00 60 66 -1.626429e+09 0.000000e+00 61 61 -3.252857e+09 0.000000e+00 61 62 -2.533073e-23 0.000000e+00 61 67 -1.626429e+09 0.000000e+00 62 62 -3.252857e+09 0.000000e+00 62 68 -1.626429e+09 0.000000e+00 64 64 -6.776786e+05 0.000000e+00 64 70 -3.388393e+05 0.000000e+00 65 65 -6.776786e+05 0.000000e+00 65 71 -3.388393e+05 0.000000e+00 66 66 -6.505714e+09 0.000000e+00 66 96 -8.132143e+08 0.000000e+00 66 102 -1.626429e+09 0.000000e+00 67 67 -6.505714e+09 0.000000e+00 67 68 -1.757388e-23 0.000000e+00 67 97 -8.132143e+08 0.000000e+00 67 103 -1.626429e+09 0.000000e+00 67 104 5.815252e-24 -0.000000e+00 68 68 -6.505714e+09 0.000000e+00 68 98 -8.132143e+08 0.000000e+00 68 103 -5.815252e-24 0.000000e+00 68 104 -1.626429e+09 0.000000e+00 70 70 -1.355357e+06 0.000000e+00 70 100 -1.694196e+05 0.000000e+00 70 106 -3.388393e+05 0.000000e+00 71 71 -1.355357e+06 0.000000e+00 71 101 -1.694196e+05 0.000000e+00 71 107 -3.388393e+05 0.000000e+00 90 90 -1.301143e+10 0.000000e+00 90 96 -3.252857e+09 0.000000e+00 90 120 -8.132143e+08 0.000000e+00 90 126 -3.252857e+09 0.000000e+00 90 132 -8.132143e+08 0.000000e+00 91 91 -1.301143e+10 0.000000e+00 91 92 2.101486e-23 -0.000000e+00 91 97 -3.252857e+09 0.000000e+00 91 121 -8.132143e+08 0.000000e+00 91 127 -3.252857e+09 0.000000e+00 91 133 -8.132143e+08 0.000000e+00 92 92 -1.301143e+10 0.000000e+00 92 98 -3.252857e+09 0.000000e+00 92 122 -8.132143e+08 0.000000e+00 92 128 -3.252857e+09 0.000000e+00 92 134 -8.132143e+08 0.000000e+00 94 94 -2.710714e+06 0.000000e+00 94 100 -6.776786e+05 0.000000e+00 94 124 -1.694196e+05 0.000000e+00 94 130 -6.776786e+05 0.000000e+00 94 136 -1.694196e+05 0.000000e+00 95 95 -2.710714e+06 0.000000e+00 95 101 -6.776786e+05 0.000000e+00 95 125 -1.694196e+05 0.000000e+00 95 131 -6.776786e+05 0.000000e+00 95 137 -1.694196e+05 0.000000e+00 96 96 -1.301143e+10 0.000000e+00 96 102 -3.252857e+09 0.000000e+00 96 126 -8.132143e+08 0.000000e+00 96 132 -3.252857e+09 0.000000e+00 96 138 -8.132143e+08 0.000000e+00 97 97 -1.301143e+10 0.000000e+00 97 98 1.995563e-23 -0.000000e+00 97 103 -3.252857e+09 0.000000e+00 97 127 -8.132143e+08 0.000000e+00 97 133 -3.252857e+09 0.000000e+00 97 139 -8.132143e+08 0.000000e+00 98 98 -1.301143e+10 0.000000e+00 98 104 -3.252857e+09 0.000000e+00 98 128 -8.132143e+08 0.000000e+00 98 134 -3.252857e+09 0.000000e+00 98 140 -8.132143e+08 0.000000e+00 100 100 -2.710714e+06 0.000000e+00 100 106 -6.776786e+05 0.000000e+00 100 130 -1.694196e+05 0.000000e+00 100 136 -6.776786e+05 0.000000e+00 100 142 -1.694196e+05 0.000000e+00 101 101 -2.710714e+06 0.000000e+00 101 107 -6.776786e+05 0.000000e+00 101 131 -1.694196e+05 0.000000e+00 101 137 -6.776786e+05 0.000000e+00 101 143 -1.694196e+05 0.000000e+00 102 102 -6.505714e+09 0.000000e+00 102 132 -8.132143e+08 0.000000e+00 102 138 -1.626429e+09 0.000000e+00 103 103 -6.505714e+09 0.000000e+00 103 104 9.448202e-24 -0.000000e+00 103 133 -8.132143e+08 0.000000e+00 103 139 -1.626429e+09 0.000000e+00 104 104 -6.505714e+09 0.000000e+00 104 134 -8.132143e+08 0.000000e+00 104 140 -1.626429e+09 0.000000e+00 106 106 -1.355357e+06 0.000000e+00 106 136 -1.694196e+05 0.000000e+00 106 142 -3.388393e+05 0.000000e+00 107 107 -1.355357e+06 0.000000e+00 107 137 -1.694196e+05 0.000000e+00 107 143 -3.388393e+05 0.000000e+00 126 126 -1.301143e+10 0.000000e+00 126 132 -3.252857e+09 0.000000e+00 126 156 -8.132143e+08 0.000000e+00 126 162 -3.252857e+09 0.000000e+00 126 168 -8.132143e+08 0.000000e+00 127 127 -1.301143e+10 0.000000e+00 127 128 -1.624548e-23 0.000000e+00 127 133 -3.252857e+09 0.000000e+00 127 157 -8.132143e+08 0.000000e+00 127 163 -3.252857e+09 0.000000e+00 127 164 -1.261364e-23 0.000000e+00 127 169 -8.132143e+08 0.000000e+00 128 128 -1.301143e+10 0.000000e+00 128 134 -3.252857e+09 0.000000e+00 128 158 -8.132143e+08 0.000000e+00 128 163 1.261364e-23 -0.000000e+00 128 164 -3.252857e+09 0.000000e+00 128 170 -8.132143e+08 0.000000e+00 130 130 -2.710714e+06 0.000000e+00 130 136 -6.776786e+05 0.000000e+00 130 160 -1.694196e+05 0.000000e+00 130 166 -6.776786e+05 0.000000e+00 130 172 -1.694196e+05 0.000000e+00 131 131 -2.710714e+06 0.000000e+00 131 137 -6.776786e+05 0.000000e+00 131 161 -1.694196e+05 0.000000e+00 131 167 -6.776786e+05 0.000000e+00 131 173 -1.694196e+05 0.000000e+0 87e+08 7.913437e+06 126 173 -1.318906e+08 6.594531e+06 127 127 1.796625e+10 -8.983125e+08 127 128 -2.384186e-07 1.192093e-08 127 133 -4.424986e+09 2.212493e+08 127 134 -1.192093e-07 5.960464e-09 127 157 -2.245781e+09 1.122891e+08 127 158 -1.725352e+09 8.626761e+07 127 163 -6.657689e+07 3.328845e+06 127 164 -2.980232e-07 1.490116e-08 misc/drivers/haggar.mtx.0.input010064400020550007177000000413670665164010600200000ustar00clevecompmath00000400000006 252 252 487 132 132 1.029802e+10 -5.149009e+08 132 136 1.192093e-07 -5.960464e-09 132 137 -1.490116e-07 7.450581e-09 132 138 -5.908699e+08 2.954350e+07 132 142 -5.960464e-08 2.980232e-09 132 143 -5.275624e+08 2.637812e+07 132 162 -1.287252e+09 6.436262e+07 132 166 -1.582687e+08 7.913437e+06 132 167 1.318906e+08 -6.594531e+06 132 168 -1.983635e+09 9.918174e+07 132 172 -6.330749e+08 3.165375e+07 132 173 1.490116e-08 -7.450581e-10 132 174 -1.287252e+09 6.436262e+07 132 178 -1.582687e+08 7.913437e+06 132 179 -1.318906e+08 6.594531e+06 133 133 1.796625e+10 -8.983125e+08 133 134 2.384186e-07 -1.192093e-08 133 139 -4.424986e+09 2.212493e+08 133 140 2.384186e-07 -1.192093e-08 133 163 -2.245781e+09 1.122891e+08 133 164 -1.725352e+09 8.626761e+07 133 169 -6.657689e+07 3.328845e+06 133 170 2.980232e-08 -1.490116e-09 133 175 -2.245781e+09 1.122891e+08 133 176 1.725352e+09 -8.626761e+07 134 134 2.134027e+10 -1.067014e+09 134 139 5.960464e-08 -2.980232e-09 134 140 2.169693e+09 -1.084847e+08 134 163 -1.725352e+09 8.626761e+07 134 164 -2.667534e+09 1.333767e+08 134 169 -5.960464e-08 2.980232e-09 134 170 -7.504762e+09 3.752381e+08 134 175 1.725352e+09 -8.626761e+07 134 176 -2.667534e+09 1.333767e+08 135 135 2.900850e+06 -1.450425e+05 135 141 -1.664422e+05 8.322112e+03 135 165 -3.626063e+05 1.813032e+04 135 171 -5.587704e+05 2.793852e+04 135 177 -3.626063e+05 1.813032e+04 136 136 3.561542e+08 -1.780771e+07 136 137 -1.746230e-10 8.731149e-12 136 138 -8.940697e-08 4.470348e-09 136 142 8.837909e+07 -4.418955e+06 136 143 -3.637979e-11 1.818989e-12 136 162 1.582687e+08 -7.913437e+06 136 166 2.142603e+07 -1.071302e+06 136 167 3.594484e+05 -1.797242e+04 136 168 6.330749e+08 -3.165375e+07 136 172 8.636358e+07 -4.318179e+06 136 173 2.910383e-11 -1.455192e-12 136 174 1.582687e+08 -7.913437e+06 136 178 2.142603e+07 -1.071302e+06 136 179 -3.594484e+05 1.797242e+04 137 137 3.554513e+08 -1.777256e+07 137 138 5.275624e+08 -2.637812e+07 137 142 -2.182787e-11 1.091394e-12 137 143 8.700520e+07 -4.350260e+06 137 162 -1.318906e+08 6.594531e+06 137 166 3.594484e+05 -1.797242e+04 137 167 2.151390e+07 -1.075695e+06 137 168 -2.980232e-08 1.490116e-09 137 172 -1.455192e-11 7.275958e-13 137 173 8.791320e+07 -4.395660e+06 137 174 1.318906e+08 -6.594531e+06 137 178 -3.594484e+05 1.797242e+04 137 179 2.151390e+07 -1.075695e+06 138 138 5.149009e+09 -2.574505e+08 138 142 5.960464e-08 -2.980232e-09 138 143 5.275624e+08 -2.637812e+07 138 168 -1.287252e+09 6.436262e+07 138 172 -1.582687e+08 7.913437e+06 138 173 1.318906e+08 -6.594531e+06 138 174 -9.918174e+08 4.959087e+07 138 178 -3.165375e+08 1.582687e+07 138 179 1.318906e+08 -6.594531e+06 139 139 8.983125e+09 -4.491563e+08 139 140 -2.384186e-07 1.192093e-08 139 169 -2.245781e+09 1.122891e+08 139 170 -1.725352e+09 8.626761e+07 139 175 -3.328845e+07 1.664422e+06 139 176 1.738727e+08 -8.693635e+06 140 140 1.067014e+10 -5.335068e+08 140 169 -1.725352e+09 8.626761e+07 140 170 -2.667534e+09 1.333767e+08 140 175 -1.738727e+08 8.693635e+06 140 176 -3.752381e+09 1.876190e+08 141 141 1.450425e+06 -7.252126e+04 141 171 -3.626063e+05 1.813032e+04 141 177 -2.793852e+05 1.396926e+04 142 142 1.780771e+08 -8.903855e+06 142 143 0.000000e+00 -0.000000e+00 142 168 1.582687e+08 -7.913437e+06 142 172 2.142603e+07 -1.071302e+06 142 173 3.594484e+05 -1.797242e+04 142 174 3.165375e+08 -1.582687e+07 142 178 4.318179e+07 -2.159090e+06 142 179 3.622348e+04 -1.811174e+03 143 143 1.777256e+08 -8.886282e+06 143 168 -1.318906e+08 6.594531e+06 143 172 3.594484e+05 -1.797242e+04 143 173 2.151390e+07 -1.075695e+06 143 174 1.318906e+08 -6.594531e+06 143 178 -3.622348e+04 1.811174e+03 143 179 4.395660e+07 -2.197830e+06 168 168 1.029802e+10 -5.149009e+08 168 172 1.192093e-07 -5.960464e-09 168 173 -8.940697e-08 4.470348e-09 168 174 -5.908699e+08 2.954350e+07 168 178 -5.960464e-08 2.980232e-09 168 179 -5.275624e+08 2.637812e+07 168 198 -1.287252e+09 6.436262e+07 168 202 -1.582687e+08 7.913437e+06 168 203 1.318906e+08 -6.594531e+06 168 204 -1.983635e+09 9.918174e+07 168 208 -6.330749e+08 3.165375e+07 168 209 -2.980232e-08 1.490116e-09 168 210 -1.287252e+09 6.436262e+07 168 214 -1.582687e+08 7.913437e+06 168 215 -1.318906e+08 6.594531e+06 169 169 1.796625e+10 -8.983125e+08 169 170 2.384186e-07 -1.192093e-08 169 175 -4.424986e+09 2.212493e+08 169 176 2.980232e-08 -1.490116e-09 169 199 -2.245781e+09 1.122891e+08 169 200 -1.725352e+09 8.626761e+07 169 205 -6.657689e+07 3.328845e+06 169 206 2.682209e-07 -1.341105e-08 169 211 -2.245781e+09 1.122891e+08 169 212 1.725352e+09 -8.626761e+07 170 170 2.134027e+10 -1.067014e+09 170 175 -5.960464e-08 2.980232e-09 170 176 2.169693e+09 -1.084847e+08 170 199 -1.725352e+09 8.626761e+07 170 200 -2.667534e+09 1.333767e+08 170 205 1.192093e-07 -5.960464e-09 170 206 -7.504762e+09 3.752381e+08 170 211 1.725352e+09 -8.626761e+07 170 212 -2.667534e+09 1.333767e+08 171 171 2.900850e+06 -1.450425e+05 171 177 -1.664422e+05 8.322112e+03 171 201 -3.626063e+05 1.813032e+04 171 207 -5.587704e+05 2.793852e+04 171 213 -3.626063e+05 1.813032e+04 172 172 3.561542e+08 -1.780771e+07 172 173 0.000000e+00 -0.000000e+00 172 174 -5.960464e-08 2.980232e-09 172 178 8.837909e+07 -4.418955e+06 172 179 -1.455192e-11 7.275958e-13 172 198 1.582687e+08 -7.913437e+06 172 202 2.142603e+07 -1.071302e+06 172 203 3.594484e+05 -1.797242e+04 172 204 6.330749e+08 -3.165375e+07 172 208 8.636358e+07 -4.318179e+06 172 209 -2.182787e-11 1.091394e-12 172 210 1.582687e+08 -7.913437e+06 172 214 2.142603e+07 -1.071302e+06 172 215 -3.594484e+05 1.797242e+04 173 173 3.554513e+08 -1.777256e+07 173 174 5.275624e+08 -2.637812e+07 173 178 5.093170e-11 -2.546585e-12 173 179 8.700520e+07 -4.350260e+06 173 198 -1.318906e+08 6.594531e+06 173 202 3.594484e+05 -1.797242e+04 173 203 2.151390e+07 -1.075695e+06 173 204 -1.490116e-08 7.450581e-10 173 208 -2.910383e-11 1.455192e-12 173 209 8.791320e+07 -4.395660e+06 173 210 1.318906e+08 -6.594531e+06 173 214 -3.594484e+05 1.797242e+04 173 215 2.151390e+07 -1.075695e+06 174 174 5.149009e+09 -2.574505e+08 174 178 5.960464e-08 -2.980232e-09 174 179 5.275624e+08 -2.637812e+07 174 204 -1.287252e+09 6.436262e+07 174 208 -1.582687e+08 7.913437e+06 174 209 1.318906e+08 -6.594531e+06 174 210 -9.918174e+08 4.959087e+07 174 214 -3.165375e+08 1.582687e+07 174 215 1.318906e+08 -6.594531e+06 175 175 8.983125e+09 -4.491563e+08 175 176 -2.384186e-07 1.192093e-08 175 205 -2.245781e+09 1.122891e+08 175 206 -1.725352e+09 8.626761e+07 175 211 -3.328845e+07 1.664422e+06 175 212 1.738727e+08 -8.693635e+06 176 176 1.067014e+10 -5.335068e+08 176 205 -1.725352e+09 8.626761e+07 176 206 -2.667534e+09 1.333767e+08 176 211 -1.738727e+08 8.693635e+06 176 212 -3.752381e+09 1.876190e+08 177 177 1.450425e+06 -7.252126e+04 177 207 -3.626063e+05 1.813032e+04 177 213 -2.793852e+05 1.396926e+04 178 178 1.780771e+08 -8.903855e+06 178 179 -5.820766e-11 2.910383e-12 178 204 1.582687e+08 -7.913437e+06 178 208 2.142603e+07 -1.071302e+06 178 209 3.594484e+05 -1.797242e+04 178 210 3.165375e+08 -1.582687e+07 178 214 4.318179e+07 -2.159090e+06 178 215 3.622348e+04 -1.811174e+03 179 179 1.777256e+08 -8.886282e+06 179 204 -1.318906e+08 6.594531e+06 179 208 3.594484e+05 -1.797242e+04 179 209 2.151390e+07 -1.075695e+06 179 210 1.318906e+08 -6.594531e+06 179 214 -3.622348e+04 1.811174e+03 179 215 4.395660e+07 -2.197830e+06 204 204 1.029802e+10 -5.149009e+08 204 208 1.192093e-07 -5.960464e-09 204 209 0.000000e+00 -0.000000e+00 204 210 -5.908699e+08 2.954350e+07 204 214 -5.960464e-08 2.980232e-09 204 215 -5.275624e+08 2.637812e+07 204 234 -1.287252e+09 6.436262e+07 204 238 -1.582687e+08 7.913437e+06 204 239 1.318906e+08 -6.594531e+06 204 240 -1.983635e+09 9.918174e+07 204 244 -6.330749e+08 3.165375e+07 204 245 0.000000e+00 -0.000000e+00 204 246 -1.287252e+09 6.436262e+07 204 250 -1.582687e+08 7.913437e+06 204 251 -1.318906e+08 6.594531e+06 205 205 1.796625e+10 -8.983125e+08 205 206 0.000000e+00 -0.000000e+00 205 211 -4.424986e+09 2.212493e+08 205 212 2.086163e-07 -1.043081e-08 205 235 -2.245781e+09 1.122891e+08 205 236 -1.725352e+09 8.626761e+07 205 241 -6.657689e+07 3.328845e+06 205 242 -2.086163e-07 1.043081e-08 205 247 -2.245781e+09 1.122891e+08 205 248 1.725352e+09 -8.626761e+07 206 206 2.134027e+10 -1.067014e+09 206 211 0.000000e+00 -0.000000e+00 206 212 2.169693e+09 -1.084847e+08 206 235 -1.725352e+09 8.626761e+07 206 236 -2.667534e+09 1.333767e+08 206 241 -4.768372e-07 2.384186e-08 206 242 -7.504762e+09 3.752381e+08 206 247 1.725352e+09 -8.626761e+07 206 248 -2.667534e+09 1.333767e+08 207 207 2.900850e+06 -1.450425e+05 207 213 -1.664422e+05 8.322112e+03 207 237 -3.626063e+05 1.813032e+04 207 243 -5.587704e+05 2.793852e+04 207 249 -3.626063e+05 1.813032e+04 208 208 3.561542e+08 -1.780771e+07 208 209 5.820766e-11 -2.910383e-12 208 210 -5.960464e-08 2.980232e-09 208 214 8.837909e+07 -4.418955e+06 208 215 -7.275958e-12 3.637979e-13 208 234 1.582687e+08 -7.913437e+06 208 238 2.142603e+07 -1.071302e+06 208 239 3.594484e+05 -1.797242e+04 208 240 6.330749e+08 -3.165375e+07 208 244 8.636358e+07 -4.318179e+06 208 245 7.275958e-12 -3.637979e-13 208 246 1.582687e+08 -7.913437e+06 208 250 2.142603e+07 -1.071302e+06 208 251 -3.594484e+05 1.797242e+04 209 209 3.554513e+08 -1.777256e+07 209 210 5.275624e+08 -2.637812e+07 209 214 3.637979e-11 -1.818989e-12 209 215 8.700520e+07 -4.350260e+06 209 234 -1.318906e+08 6.594531e+06 209 238 3.594484e+05 -1.797242e+04 209 239 2.151390e+07 -1.075695e+06 209 240 -4.470348e-08 2.235174e-09 209 244 6.548362e-11 -3.274181e-12 209 245 8.791320e+07 -4.395660e+06 209 246 1.318906e+08 -6.594531e+06 209 250 -3.594484e+05 1.797242e+04 209 251 2.151390e+07 -1.075695e+06 210 210 5.149009e+09 -2.574505e+08 210 214 5.960464e-08 -2.980232e-09 210 215 5.275624e+08 -2.637812e+07 210 240 -1.287252e+09 6.436262e+07 210 244 -1.582687e+08 7.913437e+06 210 245 1.318906e+08 -6.594531e+06 210 246 -9.918174e+08 4.959087e+07 210 250 -3.165375e+08 1.582687e+07 210 251 1.318906e+08 -6.594531e+06 211 211 8.983125e+09 -4.491563e+08 211 212 -2.384186e-07 1.192093e-08 211 241 -2.245781e+09 1.122891e+08 211 242 -1.725352e+09 8.626761e+07 211 247 -3.328845e+07 1.664422e+06 211 248 1.738727e+08 -8.693635e+06 212 212 1.067014e+10 -5.335068e+08 212 241 -1.725352e+09 8.626761e+07 212 242 -2.667534e+09 1.333767e+08 212 247 -1.738727e+08 8.693635e+06 212 248 -3.752381e+09 1.876190e+08 213 213 1.450425e+06 -7.252126e+04 213 243 -3.626063e+05 1.813032e+04 213 249 -2.793852e+05 1.396926e+04 214 214 1.780771e+08 -8.903855e+06 214 215 -5.820766e-11 2.910383e-12 214 240 1.582687e+08 -7.913437e+06 214 244 2.142603e+07 -1.071302e+06 214 245 3.594484e+05 -1.797242e+04 214 246 3.165375e+08 -1.582687e+07 214 250 4.318179e+07 -2.159090e+06 214 251 3.622348e+04 -1.811174e+03 215 215 1.777256e+08 -8.886282e+06 215 240 -1.318906e+08 6.594531e+06 215 244 3.594484e+05 -1.797242e+04 215 245 2.151390e+07 -1.075695e+06 215 246 1.318906e+08 -6.594531e+06 215 250 -3.622348e+04 1.811174e+03 215 251 4.395660e+07 -2.197830e+06 240 240 5.149009e+09 -2.574505e+08 240 244 6.330749e+08 -3.165375e+07 240 245 -1.192093e-07 5.960464e-09 240 246 -2.954350e+08 1.477175e+07 240 250 1.582687e+08 -7.913437e+06 240 251 -2.637812e+08 1.318906e+07 241 241 8.983125e+09 -4.491563e+08 241 242 4.768372e-07 -2.384186e-08 241 247 -2.212493e+09 1.106246e+08 241 248 -1.738727e+08 8.693635e+06 242 242 1.067014e+10 -5.335068e+08 242 247 1.738727e+08 -8.693635e+06 242 248 1.084847e+09 -5.424234e+07 243 243 1.450425e+06 -7.252126e+04 243 249 -8.322112e+04 4.161056e+03 244 244 1.780771e+08 -8.903855e+06 244 245 -5.820766e-11 2.910383e-12 244 246 1.582687e+08 -7.913437e+06 244 250 4.418955e+07 -2.209477e+06 244 251 -3.622348e+04 1.811174e+03 245 245 1.777256e+08 -8.886282e+06 245 246 2.637812e+08 -1.318906e+07 245 250 3.622348e+04 -1.811174e+03 245 251 4.350260e+07 -2.175130e+06 246 246 2.574505e+09 -1.287252e+08 246 250 3.165375e+08 -1.582687e+07 246 251 2.637812e+08 -1.318906e+07 247 247 4.491563e+09 -2.245781e+08 247 248 -1.725352e+09 8.626761e+07 248 248 5.335068e+09 -2.667534e+08 249 249 7.252126e+05 -3.626063e+04 250 250 8.903855e+07 -4.451927e+06 250 251 3.594484e+05 -1.797242e+04 251 251 8.886282e+07 -4.443141e+06 132 132 -1.301143e+10 0.000000e+00 132 138 -3.252857e+09 0.000000e+00 132 162 -8.132143e+08 0.000000e+00 132 168 -3.252857e+09 0.000000e+00 132 174 -8.132143e+08 0.000000e+00 133 133 -1.301143e+10 0.000000e+00 133 134 -1.624548e-23 0.000000e+00 133 139 -3.252857e+09 0.000000e+00 133 163 -8.132143e+08 0.000000e+00 133 169 -3.252857e+09 0.000000e+00 133 170 -6.306821e-24 0.000000e+00 133 175 -8.132143e+08 0.000000e+00 134 134 -1.301143e+10 0.000000e+00 134 140 -3.252857e+09 0.000000e+00 134 164 -8.132143e+08 0.000000e+00 134 169 6.306821e-24 -0.000000e+00 134 170 -3.252857e+09 0.000000e+00 134 176 -8.132143e+08 0.000000e+00 136 136 -2.710714e+06 0.000000e+00 136 142 -6.776786e+05 0.000000e+00 136 166 -1.694196e+05 0.000000e+00 136 172 -6.776786e+05 0.000000e+00 136 178 -1.694196e+05 0.000000e+00 137 137 -2.710714e+06 0.000000e+00 137 143 -6.776786e+05 0.000000e+00 137 167 -1.694196e+05 0.000000e+00 137 173 -6.776786e+05 0.000000e+00 137 179 -1.694196e+05 0.000000e+00 138 138 -6.505714e+09 0.000000e+00 138 168 -8.132143e+08 0.000000e+00 138 174 -1.626429e+09 0.000000e+00 139 139 -6.505714e+09 0.000000e+00 139 140 -8.122739e-24 0.000000e+00 139 169 -8.132143e+08 0.000000e+00 139 175 -1.626429e+09 0.000000e+00 140 140 -6.505714e+09 0.000000e+00 140 170 -8.132143e+08 0.000000e+00 140 176 -1.626429e+09 0.000000e+00 142 142 -1.355357e+06 0.000000e+00 142 172 -1.694196e+05 0.000000e+00 142 178 -3.388393e+05 0.000000e+00 143 143 -1.355357e+06 0.000000e+00 143 173 -1.694196e+05 0.000000e+00 143 179 -3.388393e+05 0.000000e+00 168 168 -1.301143e+10 0.000000e+00 168 174 -3.252857e+09 0.000000e+00 168 198 -8.132143e+08 0.000000e+00 168 204 -3.252857e+09 0.000000e+00 168 210 -8.132143e+08 0.000000e+00 169 169 -1.301143e+10 0.000000e+00 169 170 -3.228433e-23 0.000000e+00 169 175 -3.252857e+09 0.000000e+00 169 199 -8.132143e+08 0.000000e+00 169 205 -3.252857e+09 0.000000e+00 169 211 -8.132143e+08 0.000000e+00 170 170 -1.301143e+10 0.000000e+00 170 176 -3.252857e+09 0.000000e+00 170 200 -8.132143e+08 0.000000e+00 170 206 -3.252857e+09 0.000000e+00 170 212 -8.132143e+08 0.000000e+00 172 172 -2.710714e+06 0.000000e+00 172 178 -6.776786e+05 0.000000e+00 172 202 -1.694196e+05 0.000000e+00 172 208 -6.776786e+05 0.000000e+00 172 214 -1.694196e+05 0.000000e+00 173 173 -2.710714e+06 0.000000e+00 173 179 -6.776786e+05 0.000000e+00 173 203 -1.694196e+05 0.000000e+00 173 209 -6.776786e+05 0.000000e+00 173 215 -1.694196e+05 0.000000e+00 174 174 -6.505714e+09 0.000000e+00 174 204 -8.132143e+08 0.000000e+00 174 210 -1.626429e+09 0.000000e+00 175 175 -6.505714e+09 0.000000e+00 175 176 -1.592926e-23 0.000000e+00 175 205 -8.132143e+08 0.000000e+00 175 211 -1.626429e+09 0.000000e+00 176 176 -6.505714e+09 0.000000e+00 176 206 -8.132143e+08 0.000000e+00 176 212 -1.626429e+09 0.000000e+00 178 178 -1.355357e+06 0.000000e+00 178 208 -1.694196e+05 0.000000e+00 178 214 -3.388393e+05 0.000000e+00 179 179 -1.355357e+06 0.000000e+00 179 209 -1.694196e+05 0.000000e+00 179 215 -3.388393e+05 0.000000e+00 204 204 -1.301143e+10 0.000000e+00 204 210 -3.252857e+09 0.000000e+00 204 234 -8.132143e+08 0.000000e+00 204 240 -3.252857e+09 0.000000e+00 204 246 -8.132143e+08 0.000000e+00 205 205 -1.301143e+10 0.000000e+00 205 211 -3.252857e+09 0.000000e+00 205 235 -8.132143e+08 0.000000e+00 205 241 -3.252857e+09 0.000000e+00 205 247 -8.132143e+08 0.000000e+00 206 206 -1.301143e+10 0.000000e+00 206 212 -3.252857e+09 0.000000e+00 206 236 -8.132143e+08 0.000000e+00 206 242 -3.252857e+09 0.000000e+00 206 248 -8.132143e+08 0.000000e+00 208 208 -2.710714e+06 0.000000e+00 208 214 -6.776786e+05 0.000000e+00 208 238 -1.694196e+05 0.000000e+00 208 244 -6.776786e+05 0.000000e+00 208 250 -1.694196e+05 0.000000e+00 209 209 -2.710714e+06 0.000000e+00 209 215 -6.776786e+05 0.000000e+00 209 239 -1.694196e+05 0.000000e+00 209 245 -6.776786e+05 0.000000e+00 209 251 -1.694196e+05 0.000000e+00 210 210 -6.505714e+09 0.000000e+00 210 240 -8.132143e+08 0.000000e+00 210 246 -1.626429e+09 0.000000e+00 211 211 -6.505714e+09 0.000000e+00 211 241 -8.132143e+08 0.000000e+00 211 247 -1.626429e+09 0.000000e+00 212 212 -6.505714e+09 0.000000e+00 212 242 -8.132143e+08 0.000000e+00 212 248 -1.626429e+09 0.000000e+00 214 214 -1.355357e+06 0.000000e+00 214 244 -1.694196e+05 0.000000e+00 214 250 -3.388393e+05 0.000000e+00 215 215 -1.355357e+06 0.000000e+00 215 245 -1.694196e+05 0.000000e+00 215 251 -3.388393e+05 0.000000e+00 240 240 -6.505714e+09 0.000000e+00 240 246 -1.626429e+09 0.000000e+00 241 241 -6.505714e+09 0.000000e+00 241 247 -1.626429e+09 0.000000e+00 242 242 -6.505714e+09 0.000000e+00 242 248 -1.626429e+09 0.000000e+00 244 244 -1.355357e+06 0.000000e+00 244 250 -3.388393e+05 0.000000e+00 245 245 -1.355357e+06 0.000000e+00 245 251 -3.388393e+05 0.000000e+00 246 246 -3.252857e+09 0.000000e+00 247 247 -3.252857e+09 0.000000e+00 248 248 -3.252857e+09 0.000000e+00 250 250 -6.776786e+05 0.000000e+00 251 251 -6.776786e+05 0.000000e+0misc/drivers/haggar.mtx.1.input010064400020550007177000000502400665164010600177670ustar00clevecompmath00000400000006 252 252 573 162 162 1.029802e+10 -5.149009e+08 162 166 2.384186e-07 -1.192093e-08 162 167 -8.940697e-08 4.470348e-09 162 168 -5.908699e+08 2.954350e+07 162 172 2.980232e-08 -1.490116e-09 162 173 -5.275624e+08 2.637812e+07 162 192 -1.287252e+09 6.436262e+07 162 196 -1.582687e+08 7.913437e+06 162 197 1.318906e+08 -6.594531e+06 162 198 -1.983635e+09 9.918174e+07 162 202 -6.330749e+08 3.165375e+07 162 203 -4.470348e-08 2.235174e-09 162 204 -1.287252e+09 6.436262e+07 162 208 -1.582687e+08 7.913437e+06 162 209 -1.318906e+08 6.594531e+06 163 163 1.796625e+10 -8.983125e+08 163 164 4.768372e-07 -2.384186e-08 163 169 -4.424986e+09 2.212493e+08 163 170 -1.788139e-07 8.940697e-09 163 193 -2.245781e+09 1.122891e+08 163 194 -1.725352e+09 8.626761e+07 163 199 -6.657689e+07 3.328845e+06 163 200 2.384186e-07 -1.192093e-08 163 205 -2.245781e+09 1.122891e+08 163 206 1.725352e+09 -8.626761e+07 164 164 2.134027e+10 -1.067014e+09 164 169 -5.960464e-08 2.980232e-09 164 170 2.169693e+09 -1.084847e+08 164 193 -1.725352e+09 8.626761e+07 164 194 -2.667534e+09 1.333767e+08 164 199 -2.980232e-08 1.490116e-09 164 200 -7.504762e+09 3.752381e+08 164 205 1.725352e+09 -8.626761e+07 164 206 -2.667534e+09 1.333767e+08 165 165 2.900850e+06 -1.450425e+05 165 171 -1.664422e+05 8.322112e+03 165 195 -3.626063e+05 1.813032e+04 165 201 -5.587704e+05 2.793852e+04 165 207 -3.626063e+05 1.813032e+04 166 166 3.561542e+08 -1.780771e+07 166 167 1.746230e-10 -8.731149e-12 166 168 -5.960464e-08 2.980232e-09 166 172 8.837909e+07 -4.418955e+06 166 173 2.910383e-11 -1.455192e-12 166 192 1.582687e+08 -7.913437e+06 166 196 2.142603e+07 -1.071302e+06 166 197 3.594484e+05 -1.797242e+04 166 198 6.330749e+08 -3.165375e+07 166 202 8.636358e+07 -4.318179e+06 166 203 5.820766e-11 -2.910383e-12 166 204 1.582687e+08 -7.913437e+06 166 208 2.142603e+07 -1.071302e+06 166 209 -3.594484e+05 1.797242e+04 167 167 3.554513e+08 -1.777256e+07 167 168 5.275624e+08 -2.637812e+07 167 172 8.731149e-11 -4.365575e-12 167 173 8.700520e+07 -4.350260e+06 167 192 -1.318906e+08 6.594531e+06 167 196 3.594484e+05 -1.797242e+04 167 197 2.151390e+07 -1.075695e+06 167 198 -1.490116e-08 7.450581e-10 167 202 0.000000e+00 -0.000000e+00 167 203 8.791320e+07 -4.395660e+06 167 204 1.318906e+08 -6.594531e+06 167 208 -3.594484e+05 1.797242e+04 167 209 2.151390e+07 -1.075695e+06 180 180 5.149009e+09 -2.574505e+08 180 184 5.960464e-08 -2.980232e-09 180 185 -5.275624e+08 2.637812e+07 180 186 -5.908699e+08 2.954350e+07 180 190 0.000000e+00 -0.000000e+00 180 191 -5.275624e+08 2.637812e+07 180 216 -9.918174e+08 4.959087e+07 180 220 -3.165375e+08 1.582687e+07 180 221 -1.318906e+08 6.594531e+06 180 222 -1.287252e+09 6.436262e+07 180 226 -1.582687e+08 7.913437e+06 180 227 -1.318906e+08 6.594531e+06 181 181 8.983125e+09 -4.491563e+08 181 182 -2.384186e-07 1.192093e-08 181 187 -4.424986e+09 2.212493e+08 181 188 2.980232e-08 -1.490116e-09 181 217 -3.328845e+07 1.664422e+06 181 218 -1.738727e+08 8.693635e+06 181 223 -2.245781e+09 1.122891e+08 181 224 1.725352e+09 -8.626761e+07 182 182 1.067014e+10 -5.335068e+08 182 187 5.960464e-08 -2.980232e-09 182 188 2.169693e+09 -1.084847e+08 182 217 1.738727e+08 -8.693635e+06 182 218 -3.752381e+09 1.876190e+08 182 223 1.725352e+09 -8.626761e+07 182 224 -2.667534e+09 1.333767e+08 183 183 1.450425e+06 -7.252126e+04 183 189 -1.664422e+05 8.322112e+03 183 219 -2.793852e+05 1.396926e+04 183 225 -3.626063e+05 1.813032e+04 184 184 1.780771e+08 -8.903855e+06 184 185 0.000000e+00 -0.000000e+00 184 186 0.000000e+00 -0.000000e+00 184 190 8.837909e+07 -4.418955e+06 184 191 7.275958e-12 -3.637979e-13 184 216 3.165375e+08 -1.582687e+07 184 220 4.318179e+07 -2.159090e+06 184 221 -3.622348e+04 1.811174e+03 184 222 1.582687e+08 -7.913437e+06 184 226 2.142603e+07 -1.071302e+06 184 227 -3.594484e+05 1.797242e+04 185 185 1.777256e+08 -8.886282e+06 185 186 5.275624e+08 -2.637812e+07 185 190 1.455192e-11 -7.275958e-13 185 191 8.700520e+07 -4.350260e+06 185 216 -1.318906e+08 6.594531e+06 185 220 3.622348e+04 -1.811174e+03 185 221 4.395660e+07 -2.197830e+06 185 222 1.318906e+08 -6.594531e+06 185 226 -3.594484e+05 1.797242e+04 185 227 2.151390e+07 -1.075695e+06 186 186 1.029802e+10 -5.149009e+08 186 190 1.788139e-07 -8.940697e-09 186 191 -2.980232e-08 1.490116e-09 186 192 -5.908699e+08 2.954350e+07 186 196 -5.960464e-08 2.980232e-09 186 197 -5.275624e+08 2.637812e+07 186 216 -1.287252e+09 6.436262e+07 186 220 -1.582687e+08 7.913437e+06 186 221 1.318906e+08 -6.594531e+06 186 222 -1.983635e+09 9.918174e+07 186 226 -6.330749e+08 3.165375e+07 186 227 0.000000e+00 -0.000000e+00 186 228 -1.287252e+09 6.436262e+07 186 232 -1.582687e+08 7.913437e+06 186 233 -1.318906e+08 6.594531e+06 187 187 1.796625e+10 -8.983125e+08 187 188 -2.384186e-07 1.192093e-08 187 193 -4.424986e+09 2.212493e+08 187 194 1.788139e-07 -8.940697e-09 187 217 -2.245781e+09 1.122891e+08 187 218 -1.725352e+09 8.626761e+07 187 223 -6.657689e+07 3.328845e+06 187 224 -2.682209e-07 1.341105e-08 187 229 -2.245781e+09 1.122891e+08 187 230 1.725352e+09 -8.626761e+07 188 188 2.134027e+10 -1.067014e+09 188 193 1.192093e-07 -5.960464e-09 188 194 2.169693e+09 -1.084847e+08 188 217 -1.725352e+09 8.626761e+07 188 218 -2.667534e+09 1.333767e+08 188 223 -3.874302e-07 1.937151e-08 188 224 -7.504762e+09 3.752381e+08 188 229 1.725352e+09 -8.626761e+07 188 230 -2.667534e+09 1.333767e+08 189 189 2.900850e+06 -1.450425e+05 189 195 -1.664422e+05 8.322112e+03 189 219 -3.626063e+05 1.813032e+04 189 225 -5.587704e+05 2.793852e+04 189 231 -3.626063e+05 1.813032e+04 190 190 3.561542e+08 -1.780771e+07 190 191 0.000000e+00 -0.000000e+00 190 192 -2.980232e-08 1.490116e-09 190 196 8.837909e+07 -4.418955e+06 190 197 -5.093170e-11 2.546585e-12 190 216 1.582687e+08 -7.913437e+06 190 220 2.142603e+07 -1.071302e+06 190 221 3.594484e+05 -1.797242e+04 190 222 6.330749e+08 -3.165375e+07 190 226 8.636358e+07 -4.318179e+06 190 227 7.275958e-12 -3.637979e-13 190 228 1.582687e+08 -7.913437e+06 190 232 2.142603e+07 -1.071302e+06 190 233 -3.594484e+05 1.797242e+04 191 191 3.554513e+08 -1.777256e+07 191 192 5.275624e+08 -2.637812e+07 191 196 -2.910383e-11 1.455192e-12 191 197 8.700520e+07 -4.350260e+06 191 216 -1.318906e+08 6.594531e+06 191 220 3.594484e+05 -1.797242e+04 191 221 2.151390e+07 -1.075695e+06 191 222 -4.470348e-08 2.235174e-09 191 226 5.820766e-11 -2.910383e-12 191 227 8.791320e+07 -4.395660e+06 191 228 1.318906e+08 -6.594531e+06 191 232 -3.594484e+05 1.797242e+04 191 233 2.151390e+07 -1.075695e+06 192 192 1.029802e+10 -5.149009e+08 192 196 2.384186e-07 -1.192093e-08 192 197 -2.980232e-08 1.490116e-09 192 198 -5.908699e+08 2.954350e+07 192 202 -1.192093e-07 5.960464e-09 192 203 -5.275624e+08 2.637812e+07 192 222 -1.287252e+09 6.436262e+07 192 226 -1.582687e+08 7.913437e+06 192 227 1.318906e+08 -6.594531e+06 192 228 -1.983635e+09 9.918174e+07 192 232 -6.330749e+08 3.165375e+07 192 233 0.000000e+00 -0.000000e+00 192 234 -1.287252e+09 6.436262e+07 192 238 -1.582687e+08 7.913437e+06 192 239 -1.318906e+08 6.594531e+06 193 193 1.796625e+10 -8.983125e+08 193 194 -7.152557e-07 3.576279e-08 193 199 -4.424986e+09 2.212493e+08 193 200 4.172325e-07 -2.086163e-08 193 223 -2.245781e+09 1.122891e+08 193 224 -1.725352e+09 8.626761e+07 193 229 -6.657689e+07 3.328845e+06 193 230 -2.384186e-07 1.192093e-08 193 235 -2.245781e+09 1.122891e+08 193 236 1.725352e+09 -8.626761e+07 194 194 2.134027e+10 -1.067014e+09 194 199 5.364418e-07 -2.682209e-08 194 200 2.169693e+09 -1.084847e+08 194 223 -1.725352e+09 8.626761e+07 194 224 -2.667534e+09 1.333767e+08 194 229 -5.960464e-07 2.980232e-08 194 230 -7.504762e+09 3.752381e+08 194 235 1.725352e+09 -8.626761e+07 194 236 -2.667534e+09 1.333767e+08 195 195 2.900850e+06 -1.450425e+05 195 201 -1.664422e+05 8.322112e+03 195 225 -3.626063e+05 1.813032e+04 195 231 -5.587704e+05 2.793852e+04 195 237 -3.626063e+05 1.813032e+04 196 196 3.561542e+08 -1.780771e+07 196 197 5.820766e-11 -2.910383e-12 196 198 -2.980232e-08 1.490116e-09 196 202 8.837909e+07 -4.418955e+06 196 203 -9.458745e-11 4.729372e-12 196 222 1.582687e+08 -7.913437e+06 196 226 2.142603e+07 -1.071302e+06 196 227 3.594484e+05 -1.797242e+04 196 228 6.330749e+08 -3.165375e+07 196 232 8.636358e+07 -4.318179e+06 196 233 7.275958e-11 -3.637979e-12 196 234 1.582687e+08 -7.913437e+06 196 238 2.142603e+07 -1.071302e+06 196 239 -3.594484e+05 1.797242e+04 197 197 3.554513e+08 -1.777256e+07 197 198 5.275624e+08 -2.637812e+07 197 202 -1.018634e-10 5.093170e-12 197 203 8.700520e+07 -4.350260e+06 197 222 -1.318906e+08 6.594531e+06 197 226 3.594484e+05 -1.797242e+04 197 227 2.151390e+07 -1.075695e+06 197 228 -4.470348e-08 2.235174e-09 197 232 6.548362e-11 -3.274181e-12 197 233 8.791320e+07 -4.395660e+06 197 234 1.318906e+08 -6.594531e+06 197 238 -3.594484e+05 1.797242e+04 197 239 2.151390e+07 -1.075695e+06 198 198 1.029802e+10 -5.149009e+08 198 202 2.980232e-07 -1.490116e-08 198 203 -2.980232e-08 1.490116e-09 198 204 -5.908699e+08 2.954350e+07 198 208 2.980232e-08 -1.490116e-09 198 209 -5.275624e+08 2.637812e+07 198 228 -1.287252e+09 6.436262e+07 198 232 -1.582687e+08 7.913437e+06 198 233 1.318906e+08 -6.594531e+06 198 234 -1.983635e+09 9.918174e+07 198 238 -6.330749e+08 3.165375e+07 198 239 0.000000e+00 -0.000000e+00 198 240 -1.287252e+09 6.436262e+07 198 244 -1.582687e+08 7.913437e+06 198 245 -1.318906e+08 6.594531e+06 199 199 1.796625e+10 -8.983125e+08 199 200 -2.384186e-07 1.192093e-08 199 205 -4.424986e+09 2.212493e+08 199 206 -2.086163e-07 1.043081e-08 199 229 -2.245781e+09 1.122891e+08 199 230 -1.725352e+09 8.626761e+07 199 235 -6.657689e+07 3.328845e+06 199 236 -2.086163e-07 1.043081e-08 199 241 -2.245781e+09 1.122891e+08 199 242 1.725352e+09 -8.626761e+07 200 200 2.134027e+10 -1.067014e+09 200 205 -2.086163e-07 1.043081e-08 200 206 2.169693e+09 -1.084847e+08 200 229 -1.725352e+09 8.626761e+07 200 230 -2.667534e+09 1.333767e+08 200 235 -3.874302e-07 1.937151e-08 200 236 -7.504762e+09 3.752381e+08 200 241 1.725352e+09 -8.626761e+07 200 242 -2.667534e+09 1.333767e+08 201 201 2.900850e+06 -1.450425e+05 201 207 -1.664422e+05 8.322112e+03 201 231 -3.626063e+05 1.813032e+04 201 237 -5.587704e+05 2.793852e+04 201 243 -3.626063e+05 1.813032e+04 202 202 3.561542e+08 -1.780771e+07 202 203 1.746230e-10 -8.731149e-12 202 204 -5.960464e-08 2.980232e-09 202 208 8.837909e+07 -4.418955e+06 202 209 6.548362e-11 -3.274181e-12 202 228 1.582687e+08 -7.913437e+06 202 232 2.142603e+07 -1.071302e+06 202 233 3.594484e+05 -1.797242e+04 202 234 6.330749e+08 -3.165375e+07 202 238 8.636358e+07 -4.318179e+06 202 239 5.820766e-11 -2.910383e-12 202 240 1.582687e+08 -7.913437e+06 202 244 2.142603e+07 -1.071302e+06 202 245 -3.594484e+05 1.797242e+04 203 203 3.554513e+08 -1.777256e+07 203 204 5.275624e+08 -2.637812e+07 203 208 7.275958e-11 -3.637979e-12 203 209 8.700520e+07 -4.350260e+06 203 228 -1.318906e+08 6.594531e+06 203 232 3.594484e+05 -1.797242e+04 203 233 2.151390e+07 -1.075695e+06 203 234 -4.470348e-08 2.235174e-09 203 238 2.182787e-11 -1.091394e-12 203 239 8.791320e+07 -4.395660e+06 203 240 1.318906e+08 -6.594531e+06 203 244 -3.594484e+05 1.797242e+04 203 245 2.151390e+07 -1.075695e+06 216 216 2.574505e+09 -1.287252e+08 216 220 3.165375e+08 -1.582687e+07 216 221 -2.637812e+08 1.318906e+07 216 222 -2.954350e+08 1.477175e+07 216 226 1.582687e+08 -7.913437e+06 216 227 -2.637812e+08 1.318906e+07 217 217 4.491563e+09 -2.245781e+08 217 218 1.725352e+09 -8.626761e+07 217 223 -2.212493e+09 1.106246e+08 217 224 -1.738727e+08 8.693635e+06 218 218 5.335068e+09 -2.667534e+08 218 223 1.738727e+08 -8.693635e+06 218 224 1.084847e+09 -5.424234e+07 219 219 7.252126e+05 -3.626063e+04 219 225 -8.322112e+04 4.161056e+03 220 220 8.903855e+07 -4.451927e+06 220 221 -3.594484e+05 1.797242e+04 220 222 1.582687e+08 -7.913437e+06 220 226 4.418955e+07 -2.209477e+06 220 227 -3.622348e+04 1.811174e+03 221 221 8.886282e+07 -4.443141e+06 221 222 2.637812e+08 -1.318906e+07 221 226 3.622348e+04 -1.811174e+03 221 227 4.350260e+07 -2.175130e+06 222 222 5.149009e+09 -2.574505e+08 222 226 6.330749e+08 -3.165375e+07 222 227 0.000000e+00 -0.000000e+00 222 228 -2.954350e+08 1.477175e+07 222 232 1.582687e+08 -7.913437e+06 222 233 -2.637812e+08 1.318906e+07 223 223 8.983125e+09 -4.491563e+08 223 224 2.384186e-07 -1.192093e-08 223 229 -2.212493e+09 1.106246e+08 223 230 -1.738727e+08 8.693635e+06 224 224 1.067014e+10 -5.335068e+08 224 229 1.738727e+08 -8.693635e+06 224 230 1.084847e+09 -5.424234e+07 225 225 1.450425e+06 -7.252126e+04 225 231 -8.322112e+04 4.161056e+03 226 226 1.780771e+08 -8.903855e+06 226 227 5.820766e-11 -2.910383e-12 226 228 1.582687e+08 -7.913437e+06 226 232 4.418955e+07 -2.209477e+06 226 233 -3.622348e+04 1.811174e+03 227 227 1.777256e+08 -8.886282e+06 227 228 2.637812e+08 -1.318906e+07 227 232 3.622348e+04 -1.811174e+03 227 233 4.350260e+07 -2.175130e+06 228 228 5.149009e+09 -2.574505e+08 228 232 6.330749e+08 -3.165375e+07 228 233 0.000000e+00 -0.000000e+00 228 234 -2.954350e+08 1.477175e+07 228 238 1.582687e+08 -7.913437e+06 228 239 -2.637812e+08 1.318906e+07 229 229 8.983125e+09 -4.491563e+08 229 230 -4.768372e-07 2.384186e-08 229 235 -2.212493e+09 1.106246e+08 229 236 -1.738727e+08 8.693635e+06 230 230 1.067014e+10 -5.335068e+08 230 235 1.738727e+08 -8.693635e+06 230 236 1.084847e+09 -5.424234e+07 231 231 1.450425e+06 -7.252126e+04 231 237 -8.322112e+04 4.161056e+03 232 232 1.780771e+08 -8.903855e+06 232 233 0.000000e+00 -0.000000e+00 232 234 1.582687e+08 -7.913437e+06 232 238 4.418955e+07 -2.209477e+06 232 239 -3.622348e+04 1.811174e+03 233 233 1.777256e+08 -8.886282e+06 233 234 2.637812e+08 -1.318906e+07 233 238 3.622348e+04 -1.811174e+03 233 239 4.350260e+07 -2.175130e+06 234 234 5.149009e+09 -2.574505e+08 234 238 6.330749e+08 -3.165375e+07 234 239 0.000000e+00 -0.000000e+00 234 240 -2.954350e+08 1.477175e+07 234 244 1.582687e+08 -7.913437e+06 234 245 -2.637812e+08 1.318906e+07 235 235 8.983125e+09 -4.491563e+08 235 236 0.000000e+00 -0.000000e+00 235 241 -2.212493e+09 1.106246e+08 235 242 -1.738727e+08 8.693635e+06 236 236 1.067014e+10 -5.335068e+08 236 241 1.738727e+08 -8.693635e+06 236 242 1.084847e+09 -5.424234e+07 237 237 1.450425e+06 -7.252126e+04 237 243 -8.322112e+04 4.161056e+03 238 238 1.780771e+08 -8.903855e+06 238 239 0.000000e+00 -0.000000e+00 238 240 1.582687e+08 -7.913437e+06 238 244 4.418955e+07 -2.209477e+06 238 245 -3.622348e+04 1.811174e+03 239 239 1.777256e+08 -8.886282e+06 239 240 2.637812e+08 -1.318906e+07 239 244 3.622348e+04 -1.811174e+03 239 245 4.350260e+07 -2.175130e+06 162 162 -1.301143e+10 0.000000e+00 162 168 -3.252857e+09 0.000000e+00 162 192 -8.132143e+08 0.000000e+00 162 198 -3.252857e+09 0.000000e+00 162 204 -8.132143e+08 0.000000e+00 163 163 -1.301143e+10 0.000000e+00 163 164 -3.271014e-23 0.000000e+00 163 169 -3.252857e+09 0.000000e+00 163 193 -8.132143e+08 0.000000e+00 163 199 -3.252857e+09 0.000000e+00 163 205 -8.132143e+08 0.000000e+00 164 164 -1.301143e+10 0.000000e+00 164 170 -3.252857e+09 0.000000e+00 164 194 -8.132143e+08 0.000000e+00 164 200 -3.252857e+09 0.000000e+00 164 206 -8.132143e+08 0.000000e+00 166 166 -2.710714e+06 0.000000e+00 166 172 -6.776786e+05 0.000000e+00 166 196 -1.694196e+05 0.000000e+00 166 202 -6.776786e+05 0.000000e+00 166 208 -1.694196e+05 0.000000e+00 167 167 -2.710714e+06 0.000000e+00 167 173 -6.776786e+05 0.000000e+00 167 197 -1.694196e+05 0.000000e+00 167 203 -6.776786e+05 0.000000e+00 167 209 -1.694196e+05 0.000000e+00 180 180 -6.505714e+09 0.000000e+00 180 186 -3.252857e+09 0.000000e+00 180 216 -1.626429e+09 0.000000e+00 180 222 -8.132143e+08 0.000000e+00 181 181 -6.505714e+09 0.000000e+00 181 187 -3.252857e+09 0.000000e+00 181 217 -1.626429e+09 0.000000e+00 181 223 -8.132143e+08 0.000000e+00 182 182 -6.505714e+09 0.000000e+00 182 188 -3.252857e+09 0.000000e+00 182 218 -1.626429e+09 0.000000e+00 182 224 -8.132143e+08 0.000000e+00 184 184 -1.355357e+06 0.000000e+00 184 190 -6.776786e+05 0.000000e+00 184 220 -3.388393e+05 0.000000e+00 184 226 -1.694196e+05 0.000000e+00 185 185 -1.355357e+06 0.000000e+00 185 191 -6.776786e+05 0.000000e+00 185 221 -3.388393e+05 0.000000e+00 185 227 -1.694196e+05 0.000000e+00 186 186 -1.301143e+10 0.000000e+00 186 192 -3.252857e+09 0.000000e+00 186 216 -8.132143e+08 0.000000e+00 186 222 -3.252857e+09 0.000000e+00 186 228 -8.132143e+08 0.000000e+00 187 187 -1.301143e+10 0.000000e+00 187 193 -3.252857e+09 0.000000e+00 187 217 -8.132143e+08 0.000000e+00 187 223 -3.252857e+09 0.000000e+00 187 229 -8.132143e+08 0.000000e+00 188 188 -1.301143e+10 0.000000e+00 188 194 -3.252857e+09 0.000000e+00 188 218 -8.132143e+08 0.000000e+00 188 224 -3.252857e+09 0.000000e+00 188 230 -8.132143e+08 0.000000e+00 190 190 -2.710714e+06 0.000000e+00 190 196 -6.776786e+05 0.000000e+00 190 220 -1.694196e+05 0.000000e+00 190 226 -6.776786e+05 0.000000e+00 190 232 -1.694196e+05 0.000000e+00 191 191 -2.710714e+06 0.000000e+00 191 197 -6.776786e+05 0.000000e+00 191 221 -1.694196e+05 0.000000e+00 191 227 -6.776786e+05 0.000000e+00 191 233 -1.694196e+05 0.000000e+00 192 192 -1.301143e+10 0.000000e+00 192 198 -3.252857e+09 0.000000e+00 192 222 -8.132143e+08 0.000000e+00 192 228 -3.252857e+09 0.000000e+00 192 234 -8.132143e+08 0.000000e+00 193 193 -1.301143e+10 0.000000e+00 193 199 -3.252857e+09 0.000000e+00 193 223 -8.132143e+08 0.000000e+00 193 229 -3.252857e+09 0.000000e+00 193 235 -8.132143e+08 0.000000e+00 194 194 -1.301143e+10 0.000000e+00 194 200 -3.252857e+09 0.000000e+00 194 224 -8.132143e+08 0.000000e+00 194 230 -3.252857e+09 0.000000e+00 194 236 -8.132143e+08 0.000000e+00 196 196 -2.710714e+06 0.000000e+00 196 202 -6.776786e+05 0.000000e+00 196 226 -1.694196e+05 0.000000e+00 196 232 -6.776786e+05 0.000000e+00 196 238 -1.694196e+05 0.000000e+00 197 197 -2.710714e+06 0.000000e+00 197 203 -6.776786e+05 0.000000e+00 197 227 -1.694196e+05 0.000000e+00 197 233 -6.776786e+05 0.000000e+00 197 239 -1.694196e+05 0.000000e+00 198 198 -1.301143e+10 0.000000e+00 198 204 -3.252857e+09 0.000000e+00 198 228 -8.132143e+08 0.000000e+00 198 234 -3.252857e+09 0.000000e+00 198 240 -8.132143e+08 0.000000e+00 199 199 -1.301143e+10 0.000000e+00 199 205 -3.252857e+09 0.000000e+00 199 229 -8.132143e+08 0.000000e+00 199 235 -3.252857e+09 0.000000e+00 199 241 -8.132143e+08 0.000000e+00 200 200 -1.301143e+10 0.000000e+00 200 206 -3.252857e+09 0.000000e+00 200 230 -8.132143e+08 0.000000e+00 200 236 -3.252857e+09 0.000000e+00 200 242 -8.132143e+08 0.000000e+00 202 202 -2.710714e+06 0.000000e+00 202 208 -6.776786e+05 0.000000e+00 202 232 -1.694196e+05 0.000000e+00 202 238 -6.776786e+05 0.000000e+00 202 244 -1.694196e+05 0.000000e+00 203 203 -2.710714e+06 0.000000e+00 203 209 -6.776786e+05 0.000000e+00 203 233 -1.694196e+05 0.000000e+00 203 239 -6.776786e+05 0.000000e+00 203 245 -1.694196e+05 0.000000e+00 216 216 -3.252857e+09 0.000000e+00 216 222 -1.626429e+09 0.000000e+00 217 217 -3.252857e+09 0.000000e+00 217 223 -1.626429e+09 0.000000e+00 218 218 -3.252857e+09 0.000000e+00 218 224 -1.626429e+09 0.000000e+00 220 220 -6.776786e+05 0.000000e+00 220 226 -3.388393e+05 0.000000e+00 221 221 -6.776786e+05 0.000000e+00 221 227 -3.388393e+05 0.000000e+00 222 222 -6.505714e+09 0.000000e+00 222 228 -1.626429e+09 0.000000e+00 223 223 -6.505714e+09 0.000000e+00 223 229 -1.626429e+09 0.000000e+00 224 224 -6.505714e+09 0.000000e+00 224 230 -1.626429e+09 0.000000e+00 226 226 -1.355357e+06 0.000000e+00 226 232 -3.388393e+05 0.000000e+00 227 227 -1.355357e+06 0.000000e+00 227 233 -3.388393e+05 0.000000e+00 228 228 -6.505714e+09 0.000000e+00 228 234 -1.626429e+09 0.000000e+00 229 229 -6.505714e+09 0.000000e+00 229 235 -1.626429e+09 0.000000e+00 230 230 -6.505714e+09 0.000000e+00 230 236 -1.626429e+09 0.000000e+00 232 232 -1.355357e+06 0.000000e+00 232 238 -3.388393e+05 0.000000e+00 233 233 -1.355357e+06 0.000000e+00 233 239 -3.388393e+05 0.000000e+00 234 234 -6.505714e+09 0.000000e+00 234 240 -1.626429e+09 0.000000e+00 235 235 -6.505714e+09 0.000000e+00 235 241 -1.626429e+09 0.000000e+00 236 236 -6.505714e+09 0.000000e+00 236 242 -1.626429e+09 0.000000e+00 238 238 -1.355357e+06 0.000000e+00 238 244 -3.388393e+05 0.000000e+00 239 239 -1.355357e+06 0.000000e+00 239 245 -3.388393e+05 0.000000e+0e+05 1.813032e+04 202 202 3.561542e+08 -1.780771e+07 202 203 1.746230e-10 -8.731149e-12 202 204 -5.960464e-08 2.980232e-09 202 208 8.837909e+07 -4.418955e+06 202 209 6.548362e-11 -3.274181e-12 202 228 1.582687e+08 -7.913437e+06 202 232 2.142603e+07 -1.071302e+06 202 233 3.594484e+05 -1.797242e+04 202 234 6.330749e+08 -3.165375e+07 202 238 8misc/drivers/haggar.mtx.2.input010064400020550007177000001321460665164010600177760ustar00clevecompmath00000400000006 252 252 1328 0 0 2.574505e+09 -1.287252e+08 0 4 -3.165375e+08 1.582687e+07 0 5 -2.637812e+08 1.318906e+07 0 6 -2.954350e+08 1.477175e+07 0 10 -1.582687e+08 7.913437e+06 0 11 -2.637812e+08 1.318906e+07 0 12 -9.918174e+08 4.959087e+07 0 16 -3.165375e+08 1.582687e+07 0 17 -1.318906e+08 6.594531e+06 0 18 -1.287252e+09 6.436262e+07 0 22 -1.582687e+08 7.913437e+06 0 23 -1.318906e+08 6.594531e+06 1 1 4.491563e+09 -2.245781e+08 1 2 -1.725352e+09 8.626761e+07 1 7 -2.212493e+09 1.106246e+08 1 8 1.738727e+08 -8.693635e+06 1 13 -3.328845e+07 1.664422e+06 1 14 -1.738727e+08 8.693635e+06 1 19 -2.245781e+09 1.122891e+08 1 20 1.725352e+09 -8.626761e+07 2 2 5.335068e+09 -2.667534e+08 2 7 -1.738727e+08 8.693635e+06 2 8 1.084847e+09 -5.424234e+07 2 13 1.738727e+08 -8.693635e+06 2 14 -3.752381e+09 1.876190e+08 2 19 1.725352e+09 -8.626761e+07 2 20 -2.667534e+09 1.333767e+08 3 3 7.252126e+05 -3.626063e+04 3 9 -8.322112e+04 4.161056e+03 3 15 -2.793852e+05 1.396926e+04 3 21 -3.626063e+05 1.813032e+04 4 4 8.903855e+07 -4.451927e+06 4 5 3.594484e+05 -1.797242e+04 4 6 -1.582687e+08 7.913437e+06 4 10 4.418955e+07 -2.209477e+06 4 11 3.622348e+04 -1.811174e+03 4 12 3.165375e+08 -1.582687e+07 4 16 4.318179e+07 -2.159090e+06 4 17 -3.622348e+04 1.811174e+03 4 18 1.582687e+08 -7.913437e+06 4 22 2.142603e+07 -1.071302e+06 4 23 -3.594484e+05 1.797242e+04 5 5 8.886282e+07 -4.443141e+06 5 6 2.637812e+08 -1.318906e+07 5 10 -3.622348e+04 1.811174e+03 5 11 4.350260e+07 -2.175130e+06 5 12 -1.318906e+08 6.594531e+06 5 16 3.622348e+04 -1.811174e+03 5 17 4.395660e+07 -2.197830e+06 5 18 1.318906e+08 -6.594531e+06 5 22 -3.594484e+05 1.797242e+04 5 23 2.151390e+07 -1.075695e+06 6 6 5.149009e+09 -2.574505e+08 6 10 -6.330749e+08 3.165375e+07 6 11 2.980232e-08 -1.490116e-09 6 12 -1.287252e+09 6.436262e+07 6 16 -1.582687e+08 7.913437e+06 6 17 1.318906e+08 -6.594531e+06 6 18 -1.983635e+09 9.918174e+07 6 22 -6.330749e+08 3.165375e+07 6 23 4.470348e-08 -2.235174e-09 6 24 -2.954350e+08 1.477175e+07 6 28 -1.582687e+08 7.913437e+06 6 29 -2.637812e+08 1.318906e+07 6 30 -1.287252e+09 6.436262e+07 6 34 -1.582687e+08 7.913437e+06 6 35 -1.318906e+08 6.594531e+06 7 7 8.983125e+09 -4.491563e+08 7 8 7.152557e-07 -3.576279e-08 7 13 -2.245781e+09 1.122891e+08 7 14 -1.725352e+09 8.626761e+07 7 19 -6.657689e+07 3.328845e+06 7 20 -6.854534e-07 3.427267e-08 7 25 -2.212493e+09 1.106246e+08 7 26 1.738727e+08 -8.693635e+06 7 31 -2.245781e+09 1.122891e+08 7 32 1.725352e+09 -8.626761e+07 8 8 1.067014e+10 -5.335068e+08 8 13 -1.725352e+09 8.626761e+07 8 14 -2.667534e+09 1.333767e+08 8 19 -6.258488e-07 3.129244e-08 8 20 -7.504762e+09 3.752381e+08 8 25 -1.738727e+08 8.693635e+06 8 26 1.084847e+09 -5.424234e+07 8 31 1.725352e+09 -8.626761e+07 8 32 -2.667534e+09 1.333767e+08 9 9 1.450425e+06 -7.252126e+04 9 15 -3.626063e+05 1.813032e+04 9 21 -5.587704e+05 2.793852e+04 9 27 -8.322112e+04 4.161056e+03 9 33 -3.626063e+05 1.813032e+04 10 10 1.780771e+08 -8.903855e+06 10 11 -1.746230e-10 8.731149e-12 10 12 1.582687e+08 -7.913437e+06 10 16 2.142603e+07 -1.071302e+06 10 17 3.594484e+05 -1.797242e+04 10 18 6.330749e+08 -3.165375e+07 10 22 8.636358e+07 -4.318179e+06 10 23 1.382432e-10 -6.912160e-12 10 24 -1.582687e+08 7.913437e+06 10 28 4.418955e+07 -2.209477e+06 10 29 3.622348e+04 -1.811174e+03 10 30 1.582687e+08 -7.913437e+06 10 34 2.142603e+07 -1.071302e+06 10 35 -3.594484e+05 1.797242e+04 11 11 1.777256e+08 -8.886282e+06 11 12 -1.318906e+08 6.594531e+06 11 16 3.594484e+05 -1.797242e+04 11 17 2.151390e+07 -1.075695e+06 11 18 -8.940697e-08 4.470348e-09 11 22 1.455192e-10 -7.275958e-12 11 23 8.791320e+07 -4.395660e+06 11 24 2.637812e+08 -1.318906e+07 11 28 -3.622348e+04 1.811174e+03 11 29 4.350260e+07 -2.175130e+06 11 30 1.318906e+08 -6.594531e+06 11 34 -3.594484e+05 1.797242e+04 11 35 2.151390e+07 -1.075695e+06 12 12 5.149009e+09 -2.574505e+08 12 16 0.000000e+00 -0.000000e+00 12 17 -5.275624e+08 2.637812e+07 12 18 -5.908699e+08 2.954350e+07 12 22 0.000000e+00 -0.000000e+00 12 23 -5.275624e+08 2.637812e+07 12 72 -9.918174e+08 4.959087e+07 12 76 -3.165375e+08 1.582687e+07 12 77 -1.318906e+08 6.594531e+06 12 78 -1.287252e+09 6.436262e+07 12 82 -1.582687e+08 7.913437e+06 12 83 -1.318906e+08 6.594531e+06 13 13 8.983125e+09 -4.491563e+08 13 14 2.384186e-07 -1.192093e-08 13 19 -4.424986e+09 2.212493e+08 13 20 5.960464e-08 -2.980232e-09 13 73 -3.328845e+07 1.664422e+06 13 74 -1.738727e+08 8.693635e+06 13 79 -2.245781e+09 1.122891e+08 13 80 1.725352e+09 -8.626761e+07 14 14 1.067014e+10 -5.335068e+08 14 19 5.960464e-08 -2.980232e-09 14 20 2.169693e+09 -1.084847e+08 14 73 1.738727e+08 -8.693635e+06 14 74 -3.752381e+09 1.876190e+08 14 79 1.725352e+09 -8.626761e+07 14 80 -2.667534e+09 1.333767e+08 15 15 1.450425e+06 -7.252126e+04 15 21 -1.664422e+05 8.322112e+03 15 75 -2.793852e+05 1.396926e+04 15 81 -3.626063e+05 1.813032e+04 16 16 1.780771e+08 -8.903855e+06 16 17 -1.164153e-10 5.820766e-12 16 18 -2.980232e-08 1.490116e-09 16 22 8.837909e+07 -4.418955e+06 16 23 -3.637979e-11 1.818989e-12 16 72 3.165375e+08 -1.582687e+07 16 76 4.318179e+07 -2.159090e+06 16 77 -3.622348e+04 1.811174e+03 16 78 1.582687e+08 -7.913437e+06 16 82 2.142603e+07 -1.071302e+06 16 83 -3.594484e+05 1.797242e+04 17 17 1.777256e+08 -8.886282e+06 17 18 5.275624e+08 -2.637812e+07 17 22 -2.910383e-11 1.455192e-12 17 23 8.700520e+07 -4.350260e+06 17 72 -1.318906e+08 6.594531e+06 17 76 3.622348e+04 -1.811174e+03 17 77 4.395660e+07 -2.197830e+06 17 78 1.318906e+08 -6.594531e+06 17 82 -3.594484e+05 1.797242e+04 17 83 2.151390e+07 -1.075695e+06 18 18 1.029802e+10 -5.149009e+08 18 22 5.960464e-08 -2.980232e-09 18 23 -5.960464e-08 2.980232e-09 18 24 -1.287252e+09 6.436262e+07 18 28 1.582687e+08 -7.913437e+06 18 29 -1.318906e+08 6.594531e+06 18 30 -5.908699e+08 2.954350e+07 18 34 -1.192093e-07 5.960464e-09 18 35 -5.275624e+08 2.637812e+07 18 72 -1.287252e+09 6.436262e+07 18 76 -1.582687e+08 7.913437e+06 18 77 1.318906e+08 -6.594531e+06 18 78 -1.983635e+09 9.918174e+07 18 82 -6.330749e+08 3.165375e+07 18 83 1.490116e-08 -7.450581e-10 18 84 -1.287252e+09 6.436262e+07 18 88 -1.582687e+08 7.913437e+06 18 89 -1.318906e+08 6.594531e+06 19 19 1.796625e+10 -8.983125e+08 19 20 9.536743e-07 -4.768372e-08 19 25 -2.245781e+09 1.122891e+08 19 26 -1.725352e+09 8.626761e+07 19 31 -4.424986e+09 2.212493e+08 19 32 3.576279e-07 -1.788139e-08 19 73 -2.245781e+09 1.122891e+08 19 74 -1.725352e+09 8.626761e+07 19 79 -6.657689e+07 3.328845e+06 19 80 -5.960464e-08 2.980232e-09 19 85 -2.245781e+09 1.122891e+08 19 86 1.725352e+09 -8.626761e+07 20 20 2.134027e+10 -1.067014e+09 20 25 -1.725352e+09 8.626761e+07 20 26 -2.667534e+09 1.333767e+08 20 31 4.768372e-07 -2.384186e-08 20 32 2.169693e+09 -1.084847e+08 20 73 -1.725352e+09 8.626761e+07 20 74 -2.667534e+09 1.333767e+08 20 79 -2.682209e-07 1.341105e-08 20 80 -7.504762e+09 3.752381e+08 20 85 1.725352e+09 -8.626761e+07 20 86 -2.667534e+09 1.333767e+08 21 21 2.900850e+06 -1.450425e+05 21 27 -3.626063e+05 1.813032e+04 21 33 -1.664422e+05 8.322112e+03 21 75 -3.626063e+05 1.813032e+04 21 81 -5.587704e+05 2.793852e+04 21 87 -3.626063e+05 1.813032e+04 22 22 3.561542e+08 -1.780771e+07 22 23 0.000000e+00 -0.000000e+00 22 24 -1.582687e+08 7.913437e+06 22 28 2.142603e+07 -1.071302e+06 22 29 3.594484e+05 -1.797242e+04 22 30 -2.980232e-08 1.490116e-09 22 34 8.837909e+07 -4.418955e+06 22 35 -1.236913e-10 6.184564e-12 22 72 1.582687e+08 -7.913437e+06 22 76 2.142603e+07 -1.071302e+06 22 77 3.594484e+05 -1.797242e+04 22 78 6.330749e+08 -3.165375e+07 22 82 8.636358e+07 -4.318179e+06 22 83 5.820766e-11 -2.910383e-12 22 84 1.582687e+08 -7.913437e+06 22 88 2.142603e+07 -1.071302e+06 22 89 -3.594484e+05 1.797242e+04 23 23 3.554513e+08 -1.777256e+07 23 24 1.318906e+08 -6.594531e+06 23 28 3.594484e+05 -1.797242e+04 23 29 2.151390e+07 -1.075695e+06 23 30 5.275624e+08 -2.637812e+07 23 34 -1.018634e-10 5.093170e-12 23 35 8.700520e+07 -4.350260e+06 23 72 -1.318906e+08 6.594531e+06 23 76 3.594484e+05 -1.797242e+04 23 77 2.151390e+07 -1.075695e+06 23 78 -1.490116e-08 7.450581e-10 23 82 2.910383e-11 -1.455192e-12 23 83 8.791320e+07 -4.395660e+06 23 84 1.318906e+08 -6.594531e+06 23 88 -3.594484e+05 1.797242e+04 23 89 2.151390e+07 -1.075695e+06 24 24 5.149009e+09 -2.574505e+08 24 28 -6.330749e+08 3.165375e+07 24 29 2.980232e-08 -1.490116e-09 24 30 -1.983635e+09 9.918174e+07 24 34 -6.330749e+08 3.165375e+07 24 35 4.470348e-08 -2.235174e-09 24 36 -2.954350e+08 1.477175e+07 24 40 -1.582687e+08 7.913437e+06 24 41 -2.637812e+08 1.318906e+07 24 42 -1.287252e+09 6.436262e+07 24 46 -1.582687e+08 7.913437e+06 24 47 -1.318906e+08 6.594531e+06 25 25 8.983125e+09 -4.491563e+08 25 26 2.384186e-07 -1.192093e-08 25 31 -6.657689e+07 3.328845e+06 25 32 -8.940697e-07 4.470348e-08 25 37 -2.212493e+09 1.106246e+08 25 38 1.738727e+08 -8.693635e+06 25 43 -2.245781e+09 1.122891e+08 25 44 1.725352e+09 -8.626761e+07 26 26 1.067014e+10 -5.335068e+08 26 31 -8.642673e-07 4.321337e-08 26 32 -7.504762e+09 3.752381e+08 26 37 -1.738727e+08 8.693635e+06 26 38 1.084847e+09 -5.424234e+07 26 43 1.725352e+09 -8.626761e+07 26 44 -2.667534e+09 1.333767e+08 27 27 1.450425e+06 -7.252126e+04 27 33 -5.587704e+05 2.793852e+04 27 39 -8.322112e+04 4.161056e+03 27 45 -3.626063e+05 1.813032e+04 28 28 1.780771e+08 -8.903855e+06 28 29 -5.820766e-11 2.910383e-12 28 30 6.330749e+08 -3.165375e+07 28 34 8.636358e+07 -4.318179e+06 28 35 2.037268e-10 -1.018634e-11 28 36 -1.582687e+08 7.913437e+06 28 40 4.418955e+07 -2.209477e+06 28 41 3.622348e+04 -1.811174e+03 28 42 1.582687e+08 -7.913437e+06 28 46 2.142603e+07 -1.071302e+06 28 47 -3.594484e+05 1.797242e+04 29 29 1.777256e+08 -8.886282e+06 29 30 -8.940697e-08 4.470348e-09 29 34 1.527951e-10 -7.639755e-12 29 35 8.791320e+07 -4.395660e+06 29 36 2.637812e+08 -1.318906e+07 29 40 -3.622348e+04 1.811174e+03 29 41 4.350260e+07 -2.175130e+06 29 42 1.318906e+08 -6.594531e+06 29 46 -3.594484e+05 1.797242e+04 29 47 2.151390e+07 -1.075695e+06 30 30 1.029802e+10 -5.149009e+08 30 34 1.788139e-07 -8.940697e-09 30 35 -5.960464e-08 2.980232e-09 30 36 -1.287252e+09 6.436262e+07 30 40 1.582687e+08 -7.913437e+06 30 41 -1.318906e+08 6.594531e+06 30 42 -5.908699e+08 2.954350e+07 30 46 -1.490116e-07 7.450581e-09 30 47 -5.275624e+08 2.637812e+07 30 78 -1.287252e+09 6.436262e+07 30 82 -1.582687e+08 7.913437e+06 30 83 1.318906e+08 -6.594531e+06 30 84 -1.983635e+09 9.918174e+07 30 88 -6.330749e+08 3.165375e+07 30 89 1.490116e-08 -7.450581e-10 30 90 -1.287252e+09 6.436262e+07 30 94 -1.582687e+08 7.913437e+06 30 95 -1.318906e+08 6.594531e+06 31 31 1.796625e+10 -8.983125e+08 31 32 -2.384186e-07 1.192093e-08 31 37 -2.245781e+09 1.122891e+08 31 38 -1.725352e+09 8.626761e+07 31 43 -4.424986e+09 2.212493e+08 31 44 6.258488e-07 -3.129244e-08 31 79 -2.245781e+09 1.122891e+08 31 80 -1.725352e+09 8.626761e+07 31 85 -6.657689e+07 3.328845e+06 31 86 -1.192093e-07 5.960464e-09 31 91 -2.245781e+09 1.122891e+08 31 92 1.725352e+09 -8.626761e+07 32 32 2.134027e+10 -1.067014e+09 32 37 -1.725352e+09 8.626761e+07 32 38 -2.667534e+09 1.333767e+08 32 43 5.364418e-07 -2.682209e-08 32 44 2.169693e+09 -1.084847e+08 32 79 -1.725352e+09 8.626761e+07 32 80 -2.667534e+09 1.333767e+08 32 85 -3.278255e-07 1.639128e-08 32 86 -7.504762e+09 3.752381e+08 32 91 1.725352e+09 -8.626761e+07 32 92 -2.667534e+09 1.333767e+08 33 33 2.900850e+06 -1.450425e+05 33 39 -3.626063e+05 1.813032e+04 33 45 -1.664422e+05 8.322112e+03 33 81 -3.626063e+05 1.813032e+04 33 87 -5.587704e+05 2.793852e+04 33 93 -3.626063e+05 1.813032e+04 34 34 3.561542e+08 -1.780771e+07 34 35 1.164153e-10 -5.820766e-12 34 36 -1.582687e+08 7.913437e+06 34 40 2.142603e+07 -1.071302e+06 34 41 3.594484e+05 -1.797242e+04 34 42 -2.980232e-08 1.490116e-09 34 46 8.837909e+07 -4.418955e+06 34 47 -1.673470e-10 8.367351e-12 34 78 1.582687e+08 -7.913437e+06 34 82 2.142603e+07 -1.071302e+06 34 83 3.594484e+05 -1.797242e+04 34 84 6.330749e+08 -3.165375e+07 34 88 8.636358e+07 -4.318179e+06 34 89 1.018634e-10 -5.093170e-12 34 90 1.582687e+08 -7.913437e+06 34 94 2.142603e+07 -1.071302e+06 34 95 -3.594484e+05 1.797242e+04 35 35 3.554513e+08 -1.777256e+07 35 36 1.318906e+08 -6.594531e+06 35 40 3.594484e+05 -1.797242e+04 35 41 2.151390e+07 -1.075695e+06 35 42 5.275624e+08 -2.637812e+07 35 46 -1.600711e-10 8.003553e-12 35 47 8.700520e+07 -4.350260e+06 35 78 -1.318906e+08 6.594531e+06 35 82 3.594484e+05 -1.797242e+04 35 83 2.151390e+07 -1.075695e+06 35 84 -1.490116e-08 7.450581e-10 35 88 3.637979e-11 -1.818989e-12 35 89 8.791320e+07 -4.395660e+06 35 90 1.318906e+08 -6.594531e+06 35 94 -3.594484e+05 1.797242e+04 35 95 2.151390e+07 -1.075695e+06 72 72 5.149009e+09 -2.574505e+08 72 76 0.000000e+00 -0.000000e+00 72 77 -5.275624e+08 2.637812e+07 72 78 -5.908699e+08 2.954350e+07 72 82 0.000000e+00 -0.000000e+00 72 83 -5.275624e+08 2.637812e+07 72 108 -9.918174e+08 4.959087e+07 72 112 -3.165375e+08 1.582687e+07 72 113 -1.318906e+08 6.594531e+06 72 114 -1.287252e+09 6.436262e+07 72 118 -1.582687e+08 7.913437e+06 72 119 -1.318906e+08 6.594531e+06 73 73 8.983125e+09 -4.491563e+08 73 74 0.000000e+00 -0.000000e+00 73 79 -4.424986e+09 2.212493e+08 73 80 -5.960464e-08 2.980232e-09 73 109 -3.328845e+07 1.664422e+06 73 110 -1.738727e+08 8.693635e+06 73 115 -2.245781e+09 1.122891e+08 73 116 1.725352e+09 -8.626761e+07 74 74 1.067014e+10 -5.335068e+08 74 79 8.940697e-08 -4.470348e-09 74 80 2.169693e+09 -1.084847e+08 74 109 1.738727e+08 -8.693635e+06 74 110 -3.752381e+09 1.876190e+08 74 115 1.725352e+09 -8.626761e+07 74 116 -2.667534e+09 1.333767e+08 75 75 1.450425e+06 -7.252126e+04 75 81 -1.664422e+05 8.322112e+03 75 111 -2.793852e+05 1.396926e+04 75 117 -3.626063e+05 1.813032e+04 76 76 1.780771e+08 -8.903855e+06 76 77 0.000000e+00 -0.000000e+00 76 78 -2.980232e-08 1.490116e-09 76 82 8.837909e+07 -4.418955e+06 76 83 0.000000e+00 -0.000000e+00 76 108 3.165375e+08 -1.582687e+07 76 112 4.318179e+07 -2.159090e+06 76 113 -3.622348e+04 1.811174e+03 76 114 1.582687e+08 -7.913437e+06 76 118 2.142603e+07 -1.071302e+06 76 119 -3.594484e+05 1.797242e+04 77 77 1.777256e+08 -8.886282e+06 77 78 5.275624e+08 -2.637812e+07 77 82 3.637979e-11 -1.818989e-12 77 83 8.700520e+07 -4.350260e+06 77 108 -1.318906e+08 6.594531e+06 77 112 3.622348e+04 -1.811174e+03 77 113 4.395660e+07 -2.197830e+06 77 114 1.318906e+08 -6.594531e+06 77 118 -3.594484e+05 1.797242e+04 77 119 2.151390e+07 -1.075695e+06 78 78 1.029802e+10 -5.149009e+08 78 82 5.960464e-08 -2.980232e-09 78 83 -5.960464e-08 2.980232e-09 78 84 -5.908699e+08 2.954350e+07 78 88 -1.192093e-07 5.960464e-09 78 89 -5.275624e+08 2.637812e+07 78 108 -1.287252e+09 6.436262e+07 78 112 -1.582687e+08 7.913437e+06 78 113 1.318906e+08 -6.594531e+06 78 114 -1.983635e+09 9.918174e+07 78 118 -6.330749e+08 3.165375e+07 78 119 2.980232e-08 -1.490116e-09 78 120 -1.287252e+09 6.436262e+07 78 124 -1.582687e+08 7.913437e+06 78 125 -1.318906e+08 6.594531e+06 79 79 1.796625e+10 -8.983125e+08 79 80 -2.384186e-07 1.192093e-08 79 85 -4.424986e+09 2.212493e+08 79 86 1.788139e-07 -8.940697e-09 79 109 -2.245781e+09 1.122891e+08 79 110 -1.725352e+09 8.626761e+07 79 115 -6.657689e+07 3.328845e+06 79 116 -2.384186e-07 1.192093e-08 79 121 -2.245781e+09 1.122891e+08 79 122 1.725352e+09 -8.626761e+07 80 80 2.134027e+10 -1.067014e+09 80 85 2.384186e-07 -1.192093e-08 80 86 2.169693e+09 -1.084847e+08 80 109 -1.725352e+09 8.626761e+07 80 110 -2.667534e+09 1.333767e+08 80 115 5.960464e-08 -2.980232e-09 80 116 -7.504762e+09 3.752381e+08 80 121 1.725352e+09 -8.626761e+07 80 122 -2.667534e+09 1.333767e+08 81 81 2.900850e+06 -1.450425e+05 81 87 -1.664422e+05 8.322112e+03 81 111 -3.626063e+05 1.813032e+04 81 117 -5.587704e+05 2.793852e+04 81 123 -3.626063e+05 1.813032e+04 82 82 3.561542e+08 -1.780771e+07 82 83 -5.820766e-11 2.910383e-12 82 84 -2.980232e-08 1.490116e-09 82 88 8.837909e+07 -4.418955e+06 82 89 -5.093170e-11 2.546585e-12 82 108 1.582687e+08 -7.913437e+06 82 112 2.142603e+07 -1.071302e+06 82 113 3.594484e+05 -1.797242e+04 82 114 6.330749e+08 -3.165375e+07 82 118 8.636358e+07 -4.318179e+06 82 119 0.000000e+00 -0.000000e+00 82 120 1.582687e+08 -7.913437e+06 82 124 2.142603e+07 -1.071302e+06 82 125 -3.594484e+05 1.797242e+04 83 83 3.554513e+08 -1.777256e+07 83 84 5.275624e+08 -2.637812e+07 83 88 -2.910383e-11 1.455192e-12 83 89 8.700520e+07 -4.350260e+06 83 108 -1.318906e+08 6.594531e+06 83 112 3.594484e+05 -1.797242e+04 83 113 2.151390e+07 -1.075695e+06 83 114 -1.490116e-08 7.450581e-10 83 118 2.910383e-11 -1.455192e-12 83 119 8.791320e+07 -4.395660e+06 83 120 1.318906e+08 -6.594531e+06 83 124 -3.594484e+05 1.797242e+04 83 125 2.151390e+07 -1.075695e+06 84 84 1.029802e+10 -5.149009e+08 84 88 1.788139e-07 -8.940697e-09 84 89 -5.960464e-08 2.980232e-09 84 90 -5.908699e+08 2.954350e+07 84 94 -1.192093e-07 5.960464e-09 84 95 -5.275624e+08 2.637812e+07 84 114 -1.287252e+09 6.436262e+07 84 118 -1.582687e+08 7.913437e+06 84 119 1.318906e+08 -6.594531e+06 84 120 -1.983635e+09 9.918174e+07 84 124 -6.330749e+08 3.165375e+07 84 125 2.980232e-08 -1.490116e-09 84 126 -1.287252e+09 6.436262e+07 84 130 -1.582687e+08 7.913437e+06 84 131 -1.318906e+08 6.594531e+06 85 85 1.796625e+10 -8.983125e+08 85 86 -1.192093e-06 5.960464e-08 85 91 -4.424986e+09 2.212493e+08 85 92 4.768372e-07 -2.384186e-08 85 115 -2.245781e+09 1.122891e+08 85 116 -1.725352e+09 8.626761e+07 85 121 -6.657689e+07 3.328845e+06 85 122 -2.682209e-07 1.341105e-08 85 127 -2.245781e+09 1.122891e+08 85 128 1.725352e+09 -8.626761e+07 86 86 2.134027e+10 -1.067014e+09 86 91 5.066395e-07 -2.533197e-08 86 92 2.169693e+09 -1.084847e+08 86 115 -1.725352e+09 8.626761e+07 86 116 -2.667534e+09 1.333767e+08 86 121 0.000000e+00 -0.000000e+00 86 122 -7.504762e+09 3.752381e+08 86 127 1.725352e+09 -8.626761e+07 86 128 -2.667534e+09 1.333767e+08 87 87 2.900850e+06 -1.450425e+05 87 93 -1.664422e+05 8.322112e+03 87 117 -3.626063e+05 1.813032e+04 87 123 -5.587704e+05 2.793852e+04 87 129 -3.626063e+05 1.813032e+04 88 88 3.561542e+08 -1.780771e+07 88 89 5.820766e-11 -2.910383e-12 88 90 -2.980232e-08 1.490116e-09 88 94 8.837909e+07 -4.418955e+06 88 95 -1.018634e-10 5.093170e-12 88 114 1.582687e+08 -7.913437e+06 88 118 2.142603e+07 -1.071302e+06 88 119 3.594484e+05 -1.797242e+04 88 120 6.330749e+08 -3.165375e+07 88 124 8.636358e+07 -4.318179e+06 88 125 7.275958e-12 -3.637979e-13 88 126 1.582687e+08 -7.913437e+06 88 130 2.142603e+07 -1.071302e+06 88 131 -3.594484e+05 1.797242e+04 89 89 3.554513e+08 -1.777256e+07 89 90 5.275624e+08 -2.637812e+07 89 94 -8.731149e-11 4.365575e-12 89 95 8.700520e+07 -4.350260e+06 89 114 -1.318906e+08 6.594531e+06 89 118 3.594484e+05 -1.797242e+04 89 119 2.151390e+07 -1.075695e+06 89 120 -1.490116e-08 7.450581e-10 89 124 3.637979e-11 -1.818989e-12 89 125 8.791320e+07 -4.395660e+06 89 126 1.318906e+08 -6.594531e+06 89 130 -3.594484e+05 1.797242e+04 89 131 2.151390e+07 -1.075695e+06 108 108 5.149009e+09 -2.574505e+08 108 112 0.000000e+00 -0.000000e+00 108 113 -5.275624e+08 2.637812e+07 108 114 -5.908699e+08 2.954350e+07 108 118 0.000000e+00 -0.000000e+00 108 119 -5.275624e+08 2.637812e+07 108 144 -9.918174e+08 4.959087e+07 108 148 -3.165375e+08 1.582687e+07 108 149 -1.318906e+08 6.594531e+06 108 150 -1.287252e+09 6.436262e+07 108 154 -1.582687e+08 7.913437e+06 108 155 -1.318906e+08 6.594531e+06 109 109 8.983125e+09 -4.491563e+08 109 110 2.384186e-07 -1.192093e-08 109 115 -4.424986e+09 2.212493e+08 109 116 1.788139e-07 -8.940697e-09 109 145 -3.328845e+07 1.664422e+06 109 146 -1.738727e+08 8.693635e+06 109 151 -2.245781e+09 1.122891e+08 109 152 1.725352e+09 -8.626761e+07 110 110 1.067014e+10 -5.335068e+08 110 115 8.940697e-08 -4.470348e-09 110 116 2.169693e+09 -1.084847e+08 110 145 1.738727e+08 -8.693635e+06 110 146 -3.752381e+09 1.876190e+08 110 151 1.725352e+09 -8.626761e+07 110 152 -2.667534e+09 1.333767e+08 111 111 1.450425e+06 -7.252126e+04 111 117 -1.664422e+05 8.322112e+03 111 147 -2.793852e+05 1.396926e+04 111 153 -3.626063e+05 1.813032e+04 112 112 1.780771e+08 -8.903855e+06 112 113 -5.820766e-11 2.910383e-12 112 114 0.000000e+00 -0.000000e+00 112 118 8.837909e+07 -4.418955e+06 112 119 -2.910383e-11 1.455192e-12 112 144 3.165375e+08 -1.582687e+07 112 148 4.318179e+07 -2.159090e+06 112 149 -3.622348e+04 1.811174e+03 112 150 1.582687e+08 -7.913437e+06 112 154 2.142603e+07 -1.071302e+06 112 155 -3.594484e+05 1.797242e+04 113 113 1.777256e+08 -8.886282e+06 113 114 5.275624e+08 -2.637812e+07 113 118 -1.455192e-11 7.275958e-13 113 119 8.700520e+07 -4.350260e+06 113 144 -1.318906e+08 6.594531e+06 113 148 3.622348e+04 -1.811174e+03 113 149 4.395660e+07 -2.197830e+06 113 150 1.318906e+08 -6.594531e+06 113 154 -3.594484e+05 1.797242e+04 113 155 2.151390e+07 -1.075695e+06 114 114 1.029802e+10 -5.149009e+08 114 118 5.960464e-08 -2.980232e-09 114 119 -8.940697e-08 4.470348e-09 114 120 -5.908699e+08 2.954350e+07 114 124 -1.192093e-07 5.960464e-09 114 125 -5.275624e+08 2.637812e+07 114 144 -1.287252e+09 6.436262e+07 114 148 -1.582687e+08 7.913437e+06 114 149 1.318906e+08 -6.594531e+06 114 150 -1.983635e+09 9.918174e+07 114 154 -6.330749e+08 3.165375e+07 114 155 1.490116e-08 -7.450581e-10 114 156 -1.287252e+09 6.436262e+07 114 160 -1.582687e+08 7.913437e+06 114 161 -1.318906e+08 6.594531e+06 115 115 1.796625e+10 -8.983125e+08 115 116 0.000000e+00 -0.000000e+00 115 121 -4.424986e+09 2.212493e+08 115 122 3.874302e-07 -1.937151e-08 115 145 -2.245781e+09 1.122891e+08 115 146 -1.725352e+09 8.626761e+07 115 151 -6.657689e+07 3.328845e+06 115 152 -1.788139e-07 8.940697e-09 115 157 -2.245781e+09 1.122891e+08 115 158 1.725352e+09 -8.626761e+07 116 116 2.134027e+10 -1.067014e+09 116 121 1.788139e-07 -8.940697e-09 116 122 2.169693e+09 -1.084847e+08 116 145 -1.725352e+09 8.626761e+07 116 146 -2.667534e+09 1.333767e+08 116 151 -2.682209e-07 1.341105e-08 116 152 -7.504762e+09 3.752381e+08 116 157 1.725352e+09 -8.626761e+07 116 158 -2.667534e+09 1.333767e+08 117 117 2.900850e+06 -1.450425e+05 117 123 -1.664422e+05 8.322112e+03 117 147 -3.626063e+05 1.813032e+04 117 153 -5.587704e+05 2.793852e+04 117 159 -3.626063e+05 1.813032e+04 118 118 3.561542e+08 -1.780771e+07 118 119 -1.164153e-10 5.820766e-12 118 120 -5.960464e-08 2.980232e-09 118 124 8.837909e+07 -4.418955e+06 118 125 -5.820766e-11 2.910383e-12 118 144 1.582687e+08 -7.913437e+06 118 148 2.142603e+07 -1.071302e+06 118 149 3.594484e+05 -1.797242e+04 118 150 6.330749e+08 -3.165375e+07 118 154 8.636358e+07 -4.318179e+06 118 155 5.820766e-11 -2.910383e-12 118 156 1.582687e+08 -7.913437e+06 118 160 2.142603e+07 -1.071302e+06 118 161 -3.594484e+05 1.797242e+04 119 119 3.554513e+08 -1.777256e+07 119 120 5.275624e+08 -2.637812e+07 119 124 -5.820766e-11 2.910383e-12 119 125 8.700520e+07 -4.350260e+06 119 144 -1.318906e+08 6.594531e+06 119 148 3.594484e+05 -1.797242e+04 119 149 2.151390e+07 -1.075695e+06 119 150 -4.470348e-08 2.235174e-09 119 154 5.820766e-11 -2.910383e-12 119 155 8.791320e+07 -4.395660e+06 119 156 1.318906e+08 -6.594531e+06 119 160 -3.594484e+05 1.797242e+04 119 161 2.151390e+07 -1.075695e+06 120 120 1.029802e+10 -5.149009e+08 120 124 1.788139e-07 -8.940697e-09 120 125 -8.940697e-08 4.470348e-09 120 126 -5.908699e+08 2.954350e+07 120 130 -1.490116e-07 7.450581e-09 120 131 -5.275624e+08 2.637812e+07 120 150 -1.287252e+09 6.436262e+07 120 154 -1.582687e+08 7.913437e+06 120 155 1.318906e+08 -6.594531e+06 120 156 -1.983635e+09 9.918174e+07 120 160 -6.330749e+08 3.165375e+07 120 161 1.490116e-08 -7.450581e-10 120 162 -1.287252e+09 6.436262e+07 120 166 -1.582687e+08 7.913437e+06 120 167 -1.318906e+08 6.594531e+06 121 121 1.796625e+10 -8.983125e+08 121 122 -7.152557e-07 3.576279e-08 121 127 -4.424986e+09 2.212493e+08 121 128 5.960464e-07 -2.980232e-08 121 151 -2.245781e+09 1.122891e+08 121 152 -1.725352e+09 8.626761e+07 121 157 -6.657689e+07 3.328845e+06 121 158 -2.682209e-07 1.341105e-08 121 163 -2.245781e+09 1.122891e+08 121 164 1.725352e+09 -8.626761e+07 122 122 2.134027e+10 -1.067014e+09 122 127 5.960464e-07 -2.980232e-08 122 128 2.169693e+09 -1.084847e+08 122 151 -1.725352e+09 8.626761e+07 122 152 -2.667534e+09 1.333767e+08 122 157 -3.874302e-07 1.937151e-08 122 158 -7.504762e+09 3.752381e+08 122 163 1.725352e+09 -8.626761e+07 122 164 -2.667534e+09 1.333767e+08 123 123 2.900850e+06 -1.450425e+05 123 129 -1.664422e+05 8.322112e+03 123 153 -3.626063e+05 1.813032e+04 123 159 -5.587704e+05 2.793852e+04 123 165 -3.626063e+05 1.813032e+04 124 124 3.561542e+08 -1.780771e+07 124 125 5.820766e-11 -2.910383e-12 124 126 -2.980232e-08 1.490116e-09 124 130 8.837909e+07 -4.418955e+06 124 131 -1.018634e-10 5.093170e-12 124 150 1.582687e+08 -7.913437e+06 124 154 2.142603e+07 -1.071302e+06 124 155 3.594484e+05 -1.797242e+04 124 156 6.330749e+08 -3.165375e+07 124 160 8.636358e+07 -4.318179e+06 124 161 9.458745e-11 -4.729372e-12 124 162 1.582687e+08 -7.913437e+06 124 166 2.142603e+07 -1.071302e+06 124 167 -3.594484e+05 1.797242e+04 125 125 3.554513e+08 -1.777256e+07 125 126 5.275624e+08 -2.637812e+07 125 130 -8.731149e-11 4.365575e-12 125 131 8.700520e+07 -4.350260e+06 125 150 -1.318906e+08 6.594531e+06 125 154 3.594484e+05 -1.797242e+04 125 155 2.151390e+07 -1.075695e+06 125 156 -4.470348e-08 2.235174e-09 125 160 6.548362e-11 -3.274181e-12 125 161 8.791320e+07 -4.395660e+06 125 162 1.318906e+08 -6.594531e+06 125 166 -3.594484e+05 1.797242e+04 125 167 2.151390e+07 -1.075695e+06 144 144 5.149009e+09 -2.574505e+08 144 148 0.000000e+00 -0.000000e+00 144 149 -5.275624e+08 2.637812e+07 144 150 -5.908699e+08 2.954350e+07 144 154 0.000000e+00 -0.000000e+00 144 155 -5.275624e+08 2.637812e+07 144 180 -9.918174e+08 4.959087e+07 144 184 -3.165375e+08 1.582687e+07 144 185 -1.318906e+08 6.594531e+06 144 186 -1.287252e+09 6.436262e+07 144 190 -1.582687e+08 7.913437e+06 144 191 -1.318906e+08 6.594531e+06 145 145 8.983125e+09 -4.491563e+08 145 146 2.384186e-07 -1.192093e-08 145 151 -4.424986e+09 2.212493e+08 145 152 1.192093e-07 -5.960464e-09 145 181 -3.328845e+07 1.664422e+06 145 182 -1.738727e+08 8.693635e+06 145 187 -2.245781e+09 1.122891e+08 145 188 1.725352e+09 -8.626761e+07 146 146 1.067014e+10 -5.335068e+08 146 151 2.384186e-07 -1.192093e-08 146 152 2.169693e+09 -1.084847e+08 146 181 1.738727e+08 -8.693635e+06 146 182 -3.752381e+09 1.876190e+08 146 187 1.725352e+09 -8.626761e+07 146 188 -2.667534e+09 1.333767e+08 147 147 1.450425e+06 -7.252126e+04 147 153 -1.664422e+05 8.322112e+03 147 183 -2.793852e+05 1.396926e+04 147 189 -3.626063e+05 1.813032e+04 148 148 1.780771e+08 -8.903855e+06 148 149 5.820766e-11 -2.910383e-12 148 150 0.000000e+00 -0.000000e+00 148 154 8.837909e+07 -4.418955e+06 148 155 0.000000e+00 -0.000000e+00 148 180 3.165375e+08 -1.582687e+07 148 184 4.318179e+07 -2.159090e+06 148 185 -3.622348e+04 1.811174e+03 148 186 1.582687e+08 -7.913437e+06 148 190 2.142603e+07 -1.071302e+06 148 191 -3.594484e+05 1.797242e+04 149 149 1.777256e+08 -8.886282e+06 149 150 5.275624e+08 -2.637812e+07 149 154 1.455192e-11 -7.275958e-13 149 155 8.700520e+07 -4.350260e+06 149 180 -1.318906e+08 6.594531e+06 149 184 3.622348e+04 -1.811174e+03 149 185 4.395660e+07 -2.197830e+06 149 186 1.318906e+08 -6.594531e+06 149 190 -3.594484e+05 1.797242e+04 149 191 2.151390e+07 -1.075695e+06 150 150 1.029802e+10 -5.149009e+08 150 154 1.192093e-07 -5.960464e-09 150 155 -8.940697e-08 4.470348e-09 150 156 -5.908699e+08 2.954350e+07 150 160 -1.192093e-07 5.960464e-09 150 161 -5.275624e+08 2.637812e+07 150 180 -1.287252e+09 6.436262e+07 150 184 -1.582687e+08 7.913437e+06 150 185 1.318906e+08 -6.594531e+06 150 186 -1.983635e+09 9.918174e+07 150 190 -6.330749e+08 3.165375e+07 150 191 -4.470348e-08 2.235174e-09 150 192 -1.287252e+09 6.436262e+07 150 196 -1.582687e+08 7.913437e+06 150 197 -1.318906e+08 6.594531e+06 151 151 1.796625e+10 -8.983125e+08 151 152 0.000000e+00 -0.000000e+00 151 157 -4.424986e+09 2.212493e+08 151 158 3.874302e-07 -1.937151e-08 151 181 -2.245781e+09 1.122891e+08 151 182 -1.725352e+09 8.626761e+07 151 187 -6.657689e+07 3.328845e+06 151 188 8.940697e-08 -4.470348e-09 151 193 -2.245781e+09 1.122891e+08 151 194 1.725352e+09 -8.626761e+07 152 152 2.134027e+10 -1.067014e+09 152 157 2.980232e-07 -1.490116e-08 152 158 2.169693e+09 -1.084847e+08 152 181 -1.725352e+09 8.626761e+07 152 182 -2.667534e+09 1.333767e+08 152 187 8.940697e-08 -4.470348e-09 152 188 -7.504762e+09 3.752381e+08 152 193 1.725352e+09 -8.626761e+07 152 194 -2.667534e+09 1.333767e+08 153 153 2.900850e+06 -1.450425e+05 153 159 -1.664422e+05 8.322112e+03 153 183 -3.626063e+05 1.813032e+04 153 189 -5.587704e+05 2.793852e+04 153 195 -3.626063e+05 1.813032e+04 154 154 3.561542e+08 -1.780771e+07 154 155 5.820766e-11 -2.910383e-12 154 156 -2.980232e-08 1.490116e-09 154 160 8.837909e+07 -4.418955e+06 154 161 -8.003553e-11 4.001777e-12 154 180 1.582687e+08 -7.913437e+06 154 184 2.142603e+07 -1.071302e+06 154 185 3.594484e+05 -1.797242e+04 154 186 6.330749e+08 -3.165375e+07 154 190 8.636358e+07 -4.318179e+06 154 191 1.455192e-11 -7.275958e-13 154 192 1.582687e+08 -7.913437e+06 154 196 2.142603e+07 -1.071302e+06 154 197 -3.594484e+05 1.797242e+04 155 155 3.554513e+08 -1.777256e+07 155 156 5.275624e+08 -2.637812e+07 155 160 7.275958e-12 -3.637979e-13 155 161 8.700520e+07 -4.350260e+06 155 180 -1.318906e+08 6.594531e+06 155 184 3.594484e+05 -1.797242e+04 155 185 2.151390e+07 -1.075695e+06 155 186 -1.490116e-08 7.450581e-10 155 190 0.000000e+00 -0.000000e+00 155 191 8.791320e+07 -4.395660e+06 155 192 1.318906e+08 -6.594531e+06 155 196 -3.594484e+05 1.797242e+04 155 197 2.151390e+07 -1.075695e+06 156 156 1.029802e+10 -5.149009e+08 156 160 1.788139e-07 -8.940697e-09 156 161 -8.940697e-08 4.470348e-09 156 162 -5.908699e+08 2.954350e+07 156 166 -1.192093e-07 5.960464e-09 156 167 -5.275624e+08 2.637812e+07 156 186 -1.287252e+09 6.436262e+07 156 190 -1.582687e+08 7.913437e+06 156 191 1.318906e+08 -6.594531e+06 156 192 -1.983635e+09 9.918174e+07 156 196 -6.330749e+08 3.165375e+07 156 197 -4.470348e-08 2.235174e-09 156 198 -1.287252e+09 6.436262e+07 156 202 -1.582687e+08 7.913437e+06 156 203 -1.318906e+08 6.594531e+06 157 157 1.796625e+10 -8.983125e+08 157 158 0.000000e+00 -0.000000e+00 157 163 -4.424986e+09 2.212493e+08 157 164 5.662441e-07 -2.831221e-08 157 187 -2.245781e+09 1.122891e+08 157 188 -1.725352e+09 8.626761e+07 157 193 -6.657689e+07 3.328845e+06 157 194 5.960464e-08 -2.980232e-09 157 199 -2.245781e+09 1.122891e+08 157 200 1.725352e+09 -8.626761e+07 158 158 2.134027e+10 -1.067014e+09 158 163 5.662441e-07 -2.831221e-08 158 164 2.169693e+09 -1.084847e+08 158 187 -1.725352e+09 8.626761e+07 158 188 -2.667534e+09 1.333767e+08 158 193 -1.788139e-07 8.940697e-09 158 194 -7.504762e+09 3.752381e+08 158 199 1.725352e+09 -8.626761e+07 158 200 -2.667534e+09 1.333767e+08 159 159 2.900850e+06 -1.450425e+05 159 165 -1.664422e+05 8.322112e+03 159 189 -3.626063e+05 1.813032e+04 159 195 -5.587704e+05 2.793852e+04 159 201 -3.626063e+05 1.813032e+04 160 160 3.561542e+08 -1.780771e+07 160 161 1.746230e-10 -8.731149e-12 160 162 -2.980232e-08 1.490116e-09 160 166 8.837909e+07 -4.418955e+06 160 167 -1.309672e-10 6.548362e-12 160 186 1.582687e+08 -7.913437e+06 160 190 2.142603e+07 -1.071302e+06 160 191 3.594484e+05 -1.797242e+04 160 192 6.330749e+08 -3.165375e+07 160 196 8.636358e+07 -4.318179e+06 160 197 8.003553e-11 -4.001777e-12 160 198 1.582687e+08 -7.913437e+06 160 202 2.142603e+07 -1.071302e+06 160 203 -3.594484e+05 1.797242e+04 161 161 3.554513e+08 -1.777256e+07 161 162 5.275624e+08 -2.637812e+07 161 166 -8.003553e-11 4.001777e-12 161 167 8.700520e+07 -4.350260e+06 161 186 -1.318906e+08 6.594531e+06 161 190 3.594484e+05 -1.797242e+04 161 191 2.151390e+07 -1.075695e+06 161 192 -1.490116e-08 7.450581e-10 161 196 3.637979e-11 -1.818989e-12 161 197 8.791320e+07 -4.395660e+06 161 198 1.318906e+08 -6.594531e+06 161 202 -3.594484e+05 1.797242e+04 161 203 2.151390e+07 -1.075695e+06 0 0 -3.252857e+09 0.000000e+00 0 6 -1.626429e+09 0.000000e+00 0 12 -1.626429e+09 0.000000e+00 0 18 -8.132143e+08 0.000000e+00 1 1 -3.252857e+09 0.000000e+00 1 2 -2.547374e-23 0.000000e+00 1 7 -1.626429e+09 0.000000e+00 1 8 -6.744929e-24 0.000000e+00 1 13 -1.626429e+09 0.000000e+00 1 14 4.167065e-24 -0.000000e+00 1 19 -8.132143e+08 0.000000e+00 2 2 -3.252857e+09 0.000000e+00 2 7 6.744929e-24 -0.000000e+00 2 8 -1.626429e+09 0.000000e+00 2 13 -4.167065e-24 0.000000e+00 2 14 -1.626429e+09 0.000000e+00 2 20 -8.132143e+08 0.000000e+00 4 4 -6.776786e+05 0.000000e+00 4 10 -3.388393e+05 0.000000e+00 4 16 -3.388393e+05 0.000000e+00 4 22 -1.694196e+05 0.000000e+00 5 5 -6.776786e+05 0.000000e+00 5 11 -3.388393e+05 0.000000e+00 5 17 -3.388393e+05 0.000000e+00 5 23 -1.694196e+05 0.000000e+00 6 6 -6.505714e+09 0.000000e+00 6 12 -8.132143e+08 0.000000e+00 6 18 -3.252857e+09 0.000000e+00 6 24 -1.626429e+09 0.000000e+00 6 30 -8.132143e+08 0.000000e+00 7 7 -6.505714e+09 0.000000e+00 7 8 -5.094747e-23 0.000000e+00 7 13 -8.132143e+08 0.000000e+00 7 19 -3.252857e+09 0.000000e+00 7 20 8.334131e-24 -0.000000e+00 7 25 -1.626429e+09 0.000000e+00 7 26 -6.744929e-24 0.000000e+00 7 31 -8.132143e+08 0.000000e+00 8 8 -6.505714e+09 0.000000e+00 8 14 -8.132143e+08 0.000000e+00 8 19 -8.334131e-24 0.000000e+00 8 20 -3.252857e+09 0.000000e+00 8 25 6.744929e-24 -0.000000e+00 8 26 -1.626429e+09 0.000000e+00 8 32 -8.132143e+08 0.000000e+00 10 10 -1.355357e+06 0.000000e+00 10 16 -1.694196e+05 0.000000e+00 10 22 -6.776786e+05 0.000000e+00 10 28 -3.388393e+05 0.000000e+00 10 34 -1.694196e+05 0.000000e+00 11 11 -1.355357e+06 0.000000e+00 11 17 -1.694196e+05 0.000000e+00 11 23 -6.776786e+05 0.000000e+00 11 29 -3.388393e+05 0.000000e+00 11 35 -1.694196e+05 0.000000e+00 12 12 -6.505714e+09 0.000000e+00 12 18 -3.252857e+09 0.000000e+00 12 72 -1.626429e+09 0.000000e+00 12 78 -8.132143e+08 0.000000e+00 13 13 -6.505714e+09 0.000000e+00 13 14 -1.864002e-23 0.000000e+00 13 19 -3.252857e+09 0.000000e+00 13 73 -1.626429e+09 0.000000e+00 13 74 6.636939e-24 -0.000000e+00 13 79 -8.132143e+08 0.000000e+00 14 14 -6.505714e+09 0.000000e+00 14 20 -3.252857e+09 0.000000e+00 14 73 -6.636939e-24 0.000000e+00 14 74 -1.626429e+09 0.000000e+00 14 80 -8.132143e+08 0.000000e+00 16 16 -1.355357e+06 0.000000e+00 16 22 -6.776786e+05 0.000000e+00 16 76 -3.388393e+05 0.000000e+00 16 82 -1.694196e+05 0.000000e+00 17 17 -1.355357e+06 0.000000e+00 17 23 -6.776786e+05 0.000000e+00 17 77 -3.388393e+05 0.000000e+00 17 83 -1.694196e+05 0.000000e+00 18 18 -1.301143e+10 0.000000e+00 18 24 -8.132143e+08 0.000000e+00 18 30 -3.252857e+09 0.000000e+00 18 72 -8.132143e+08 0.000000e+00 18 78 -3.252857e+09 0.000000e+00 18 84 -8.132143e+08 0.000000e+00 19 19 -1.301143e+10 0.000000e+00 19 20 -3.728003e-23 0.000000e+00 19 25 -8.132143e+08 0.000000e+00 19 31 -3.252857e+09 0.000000e+00 19 73 -8.132143e+08 0.000000e+00 19 79 -3.252857e+09 0.000000e+00 19 80 1.327388e-23 -0.000000e+00 19 85 -8.132143e+08 0.000000e+00 20 20 -1.301143e+10 0.000000e+00 20 26 -8.132143e+08 0.000000e+00 20 32 -3.252857e+09 0.000000e+00 20 74 -8.132143e+08 0.000000e+00 20 79 -1.327388e-23 0.000000e+00 20 80 -3.252857e+09 0.000000e+00 20 86 -8.132143e+08 0.000000e+00 22 22 -2.710714e+06 0.000000e+00 22 28 -1.694196e+05 0.000000e+00 22 34 -6.776786e+05 0.000000e+00 22 76 -1.694196e+05 0.000000e+00 22 82 -6.776786e+05 0.000000e+00 22 88 -1.694196e+05 0.000000e+00 23 23 -2.710714e+06 0.000000e+00 23 29 -1.694196e+05 0.000000e+00 23 35 -6.776786e+05 0.000000e+00 23 77 -1.694196e+05 0.000000e+00 23 83 -6.776786e+05 0.000000e+00 23 89 -1.694196e+05 0.000000e+00 24 24 -6.505714e+09 0.000000e+00 24 30 -3.252857e+09 0.000000e+00 24 36 -1.626429e+09 0.000000e+00 24 42 -8.132143e+08 0.000000e+00 25 25 -6.505714e+09 0.000000e+00 25 26 -5.094747e-23 0.000000e+00 25 31 -3.252857e+09 0.000000e+00 25 32 8.334131e-24 -0.000000e+00 25 37 -1.626429e+09 0.000000e+00 25 38 -6.744929e-24 0.000000e+00 25 43 -8.132143e+08 0.000000e+00 26 26 -6.505714e+09 0.000000e+00 26 31 -8.334131e-24 0.000000e+00 26 32 -3.252857e+09 0.000000e+00 26 37 6.744929e-24 -0.000000e+00 26 38 -1.626429e+09 0.000000e+00 26 44 -8.132143e+08 0.000000e+00 28 28 -1.355357e+06 0.000000e+00 28 34 -6.776786e+05 0.000000e+00 28 40 -3.388393e+05 0.000000e+00 28 46 -1.694196e+05 0.000000e+00 29 29 -1.355357e+06 0.000000e+00 29 35 -6.776786e+05 0.000000e+00 29 41 -3.388393e+05 0.000000e+00 29 47 -1.694196e+05 0.000000e+00 30 30 -1.301143e+10 0.000000e+00 30 36 -8.132143e+08 0.000000e+00 30 42 -3.252857e+09 0.000000e+00 30 78 -8.132143e+08 0.000000e+00 30 84 -3.252857e+09 0.000000e+00 30 90 -8.132143e+08 0.000000e+00 31 31 -1.301143e+10 0.000000e+00 31 32 -3.728003e-23 0.000000e+00 31 37 -8.132143e+08 0.000000e+00 31 43 -3.252857e+09 0.000000e+00 31 79 -8.132143e+08 0.000000e+00 31 85 -3.252857e+09 0.000000e+00 31 86 1.327388e-23 -0.000000e+00 31 91 -8.132143e+08 0.000000e+00 32 32 -1.301143e+10 0.000000e+00 32 38 -8.132143e+08 0.000000e+00 32 44 -3.252857e+09 0.000000e+00 32 80 -8.132143e+08 0.000000e+00 32 85 -1.327388e-23 0.000000e+00 32 86 -3.252857e+09 0.000000e+00 32 92 -8.132143e+08 0.000000e+00 34 34 -2.710714e+06 0.000000e+00 34 40 -1.694196e+05 0.000000e+00 34 46 -6.776786e+05 0.000000e+00 34 82 -1.694196e+05 0.000000e+00 34 88 -6.776786e+05 0.000000e+00 34 94 -1.694196e+05 0.000000e+00 35 35 -2.710714e+06 0.000000e+00 35 41 -1.694196e+05 0.000000e+00 35 47 -6.776786e+05 0.000000e+00 35 83 -1.694196e+05 0.000000e+00 35 89 -6.776786e+05 0.000000e+00 35 95 -1.694196e+05 0.000000e+00 72 72 -6.505714e+09 0.000000e+00 72 78 -3.252857e+09 0.000000e+00 72 108 -1.626429e+09 0.000000e+00 72 114 -8.132143e+08 0.000000e+00 73 73 -6.505714e+09 0.000000e+00 73 74 1.050743e-23 -0.000000e+00 73 79 -3.252857e+09 0.000000e+00 73 109 -1.626429e+09 0.000000e+00 73 115 -8.132143e+08 0.000000e+00 74 74 -6.505714e+09 0.000000e+00 74 80 -3.252857e+09 0.000000e+00 74 110 -1.626429e+09 0.000000e+00 74 116 -8.132143e+08 0.000000e+00 76 76 -1.355357e+06 0.000000e+00 76 82 -6.776786e+05 0.000000e+00 76 112 -3.388393e+05 0.000000e+00 76 118 -1.694196e+05 0.000000e+00 77 77 -1.355357e+06 0.000000e+00 77 83 -6.776786e+05 0.000000e+00 77 113 -3.388393e+05 0.000000e+00 77 119 -1.694196e+05 0.000000e+00 78 78 -1.301143e+10 0.000000e+00 78 84 -3.252857e+09 0.000000e+00 78 108 -8.132143e+08 0.000000e+00 78 114 -3.252857e+09 0.000000e+00 78 120 -8.132143e+08 0.000000e+00 79 79 -1.301143e+10 0.000000e+00 79 80 2.101486e-23 -0.000000e+00 79 85 -3.252857e+09 0.000000e+00 79 109 -8.132143e+08 0.000000e+00 79 115 -3.252857e+09 0.000000e+00 79 121 -8.132143e+08 0.000000e+00 80 80 -1.301143e+10 0.000000e+00 80 86 -3.252857e+09 0.000000e+00 80 110 -8.132143e+08 0.000000e+00 80 116 -3.252857e+09 0.000000e+00 80 122 -8.132143e+08 0.000000e+00 82 82 -2.710714e+06 0.000000e+00 82 88 -6.776786e+05 0.000000e+00 82 112 -1.694196e+05 0.000000e+00 82 118 -6.776786e+05 0.000000e+00 82 124 -1.694196e+05 0.000000e+00 83 83 -2.710714e+06 0.000000e+00 83 89 -6.776786e+05 0.000000e+00 83 113 -1.694196e+05 0.000000e+00 83 119 -6.776786e+05 0.000000e+00 83 125 -1.694196e+05 0.000000e+00 84 84 -1.301143e+10 0.000000e+00 84 90 -3.252857e+09 0.000000e+00 84 114 -8.132143e+08 0.000000e+00 84 120 -3.252857e+09 0.000000e+00 84 126 -8.132143e+08 0.000000e+00 85 85 -1.301143e+10 0.000000e+00 85 86 2.101486e-23 -0.000000e+00 85 91 -3.252857e+09 0.000000e+00 85 115 -8.132143e+08 0.000000e+00 85 121 -3.252857e+09 0.000000e+00 85 127 -8.132143e+08 0.000000e+00 86 86 -1.301143e+10 0.000000e+00 86 92 -3.252857e+09 0.000000e+00 86 116 -8.132143e+08 0.000000e+00 86 122 -3.252857e+09 0.000000e+00 86 128 -8.132143e+08 0.000000e+00 88 88 -2.710714e+06 0.000000e+00 88 94 -6.776786e+05 0.000000e+00 88 118 -1.694196e+05 0.000000e+00 88 124 -6.776786e+05 0.000000e+00 88 130 -1.694196e+05 0.000000e+00 89 89 -2.710714e+06 0.000000e+00 89 95 -6.776786e+05 0.000000e+00 89 119 -1.694196e+05 0.000000e+00 89 125 -6.776786e+05 0.000000e+00 89 131 -1.694196e+05 0.000000e+00 108 108 -6.505714e+09 0.000000e+00 108 114 -3.252857e+09 0.000000e+00 108 144 -1.626429e+09 0.000000e+00 108 150 -8.132143e+08 0.000000e+00 109 109 -6.505714e+09 0.000000e+00 109 110 -8.122739e-24 0.000000e+00 109 115 -3.252857e+09 0.000000e+00 109 145 -1.626429e+09 0.000000e+00 109 146 -6.306821e-24 0.000000e+00 109 151 -8.132143e+08 0.000000e+00 110 110 -6.505714e+09 0.000000e+00 110 116 -3.252857e+09 0.000000e+00 110 145 6.306821e-24 -0.000000e+00 110 146 -1.626429e+09 0.000000e+00 110 152 -8.132143e+08 0.000000e+00 112 112 -1.355357e+06 0.000000e+00 112 118 -6.776786e+05 0.000000e+00 112 148 -3.388393e+05 0.000000e+00 112 154 -1.694196e+05 0.000000e+00 113 113 -1.355357e+06 0.000000e+00 113 119 -6.776786e+05 0.000000e+00 113 149 -3.388393e+05 0.000000e+00 113 155 -1.694196e+05 0.000000e+00 114 114 -1.301143e+10 0.000000e+00 114 120 -3.252857e+09 0.000000e+00 114 144 -8.132143e+08 0.000000e+00 114 150 -3.252857e+09 0.000000e+00 114 156 -8.132143e+08 0.000000e+00 115 115 -1.301143e+10 0.000000e+00 115 116 -1.624548e-23 0.000000e+00 115 121 -3.252857e+09 0.000000e+00 115 145 -8.132143e+08 0.000000e+00 115 151 -3.252857e+09 0.000000e+00 115 152 -1.261364e-23 0.000000e+00 115 157 -8.132143e+08 0.000000e+00 116 116 -1.301143e+10 0.000000e+00 116 122 -3.252857e+09 0.000000e+00 116 146 -8.132143e+08 0.000000e+00 116 151 1.261364e-23 -0.000000e+00 116 152 -3.252857e+09 0.000000e+00 116 158 -8.132143e+08 0.000000e+00 118 118 -2.710714e+06 0.000000e+00 118 124 -6.776786e+05 0.000000e+00 118 148 -1.694196e+05 0.000000e+00 118 154 -6.776786e+05 0.000000e+00 118 160 -1.694196e+05 0.000000e+00 119 119 -2.710714e+06 0.000000e+00 119 125 -6.776786e+05 0.000000e+00 119 149 -1.694196e+05 0.000000e+00 119 155 -6.776786e+05 0.000000e+00 119 161 -1.694196e+05 0.000000e+00 120 120 -1.301143e+10 0.000000e+00 120 126 -3.252857e+09 0.000000e+00 120 150 -8.132143e+08 0.000000e+00 120 156 -3.252857e+09 0.000000e+00 120 162 -8.132143e+08 0.000000e+00 121 121 -1.301143e+10 0.000000e+00 121 122 -1.624548e-23 0.000000e+00 121 127 -3.252857e+09 0.000000e+00 121 151 -8.132143e+08 0.000000e+00 121 157 -3.252857e+09 0.000000e+00 121 158 -1.261364e-23 0.000000e+00 121 163 -8.132143e+08 0.000000e+00 122 122 -1.301143e+10 0.000000e+00 122 128 -3.252857e+09 0.000000e+00 122 152 -8.132143e+08 0.000000e+00 122 157 1.261364e-23 -0.000000e+00 122 158 -3.252857e+09 0.000000e+00 122 164 -8.132143e+08 0.000000e+00 124 124 -2.710714e+06 0.000000e+00 124 130 -6.776786e+05 0.000000e+00 124 154 -1.694196e+05 0.000000e+00 124 160 -6.776786e+05 0.000000e+00 124 166 -1.694196e+05 0.000000e+00 125 125 -2.710714e+06 0.000000e+00 125 131 -6.776786e+05 0.000000e+00 125 155 -1.694196e+05 0.000000e+00 125 161 -6.776786e+05 0.000000e+00 125 167 -1.694196e+05 0.000000e+00 144 144 -6.505714e+09 0.000000e+00 144 150 -3.252857e+09 0.000000e+00 144 180 -1.626429e+09 0.000000e+00 144 186 -8.132143e+08 0.000000e+00 145 145 -6.505714e+09 0.000000e+00 145 146 -1.635507e-23 0.000000e+00 145 151 -3.252857e+09 0.000000e+00 145 181 -1.626429e+09 0.000000e+00 145 187 -8.132143e+08 0.000000e+00 146 146 -6.505714e+09 0.000000e+00 146 152 -3.252857e+09 0.000000e+00 146 182 -1.626429e+09 0.000000e+00 146 188 -8.132143e+08 0.000000e+00 148 148 -1.355357e+06 0.000000e+00 148 154 -6.776786e+05 0.000000e+00 148 184 -3.388393e+05 0.000000e+00 148 190 -1.694196e+05 0.000000e+00 149 149 -1.355357e+06 0.000000e+00 149 155 -6.776786e+05 0.000000e+00 149 185 -3.388393e+05 0.000000e+00 149 191 -1.694196e+05 0.000000e+00 150 150 -1.301143e+10 0.000000e+00 150 156 -3.252857e+09 0.000000e+00 150 180 -8.132143e+08 0.000000e+00 150 186 -3.252857e+09 0.000000e+00 150 192 -8.132143e+08 0.000000e+00 151 151 -1.301143e+10 0.000000e+00 151 152 -3.271014e-23 0.000000e+00 151 157 -3.252857e+09 0.000000e+00 151 181 -8.132143e+08 0.000000e+00 151 187 -3.252857e+09 0.000000e+00 151 193 -8.132143e+08 0.000000e+00 152 152 -1.301143e+10 0.000000e+00 152 158 -3.252857e+09 0.000000e+00 152 182 -8.132143e+08 0.000000e+00 152 188 -3.252857e+09 0.000000e+00 152 194 -8.132143e+08 0.000000e+00 154 154 -2.710714e+06 0.000000e+00 154 160 -6.776786e+05 0.000000e+00 154 184 -1.694196e+05 0.000000e+00 154 190 -6.776786e+05 0.000000e+00 154 196 -1.694196e+05 0.000000e+00 155 155 -2.710714e+06 0.000000e+00 155 161 -6.776786e+05 0.000000e+00 155 185 -1.694196e+05 0.000000e+00 155 191 -6.776786e+05 0.000000e+00 155 197 -1.694196e+05 0.000000e+00 156 156 -1.301143e+10 0.000000e+00 156 162 -3.252857e+09 0.000000e+00 156 186 -8.132143e+08 0.000000e+00 156 192 -3.252857e+09 0.000000e+00 156 198 -8.132143e+08 0.000000e+00 157 157 -1.301143e+10 0.000000e+00 157 158 -3.271014e-23 0.000000e+00 157 163 -3.252857e+09 0.000000e+00 157 187 -8.132143e+08 0.000000e+00 157 193 -3.252857e+09 0.000000e+00 157 199 -8.132143e+08 0.000000e+00 158 158 -1.301143e+10 0.000000e+00 158 164 -3.252857e+09 0.000000e+00 158 188 -8.132143e+08 0.000000e+00 158 194 -3.252857e+09 0.000000e+00 158 200 -8.132143e+08 0.000000e+00 160 160 -2.710714e+06 0.000000e+00 160 166 -6.776786e+05 0.000000e+00 160 190 -1.694196e+05 0.000000e+00 160 196 -6.776786e+05 0.000000e+00 160 202 -1.694196e+05 0.000000e+00 161 161 -2.710714e+06 0.000000e+00 161 167 -6.776786e+05 0.000000e+00 161 191 -1.694196e+05 0.000000e+00 161 197 -6.776786e+05 0.000000e+00 161 203 -1.694196e+05 0.000000e+0+00 22 82 -6.776786e+05 0.000000e+00 22 88 -1.694196e+05 0.000000e+00 23 23 -2.710714e+06 0.000000e+00 23 29 -1.694196e+05 0.000000e+00 23 35 -6.776786e+05 0.000000e+00 23 77 -1.694196e+05 0.000000e+00 23 83 -6.776786e+05 0.000000e+00 23 89 -1.694196e+05 0.000000e+00 24 24 -6.505714e+09 0.000000e+00 24 30 -3.252857e+09 0.000000e+00 24 36 -1.626429e+09 0.000000e+00 24 42 -8.132143e+08 0.000000e+0misc/drivers/haggar.mtx.3.input010064400020550007177000000663220665164010600200010ustar00clevecompmath00000400000006 252 252 803 36 36 5.149009e+09 -2.574505e+08 36 40 -6.330749e+08 3.165375e+07 36 41 2.980232e-08 -1.490116e-09 36 42 -1.983635e+09 9.918174e+07 36 46 -6.330749e+08 3.165375e+07 36 47 4.470348e-08 -2.235174e-09 36 48 -2.954350e+08 1.477175e+07 36 52 -1.582687e+08 7.913437e+06 36 53 -2.637812e+08 1.318906e+07 36 54 -1.287252e+09 6.436262e+07 36 58 -1.582687e+08 7.913437e+06 36 59 -1.318906e+08 6.594531e+06 37 37 8.983125e+09 -4.491563e+08 37 38 4.768372e-07 -2.384186e-08 37 43 -6.657689e+07 3.328845e+06 37 44 -8.642673e-07 4.321337e-08 37 49 -2.212493e+09 1.106246e+08 37 50 1.738727e+08 -8.693635e+06 37 55 -2.245781e+09 1.122891e+08 37 56 1.725352e+09 -8.626761e+07 38 38 1.067014e+10 -5.335068e+08 38 43 -8.046627e-07 4.023314e-08 38 44 -7.504762e+09 3.752381e+08 38 49 -1.738727e+08 8.693635e+06 38 50 1.084847e+09 -5.424234e+07 38 55 1.725352e+09 -8.626761e+07 38 56 -2.667534e+09 1.333767e+08 39 39 1.450425e+06 -7.252126e+04 39 45 -5.587704e+05 2.793852e+04 39 51 -8.322112e+04 4.161056e+03 39 57 -3.626063e+05 1.813032e+04 40 40 1.780771e+08 -8.903855e+06 40 41 -1.164153e-10 5.820766e-12 40 42 6.330749e+08 -3.165375e+07 40 46 8.636358e+07 -4.318179e+06 40 47 1.673470e-10 -8.367351e-12 40 48 -1.582687e+08 7.913437e+06 40 52 4.418955e+07 -2.209477e+06 40 53 3.622348e+04 -1.811174e+03 40 54 1.582687e+08 -7.913437e+06 40 58 2.142603e+07 -1.071302e+06 40 59 -3.594484e+05 1.797242e+04 41 41 1.777256e+08 -8.886282e+06 41 42 -8.940697e-08 4.470348e-09 41 46 1.382432e-10 -6.912160e-12 41 47 8.791320e+07 -4.395660e+06 41 48 2.637812e+08 -1.318906e+07 41 52 -3.622348e+04 1.811174e+03 41 53 4.350260e+07 -2.175130e+06 41 54 1.318906e+08 -6.594531e+06 41 58 -3.594484e+05 1.797242e+04 41 59 2.151390e+07 -1.075695e+06 42 42 1.029802e+10 -5.149009e+08 42 46 2.384186e-07 -1.192093e-08 42 47 -5.960464e-08 2.980232e-09 42 48 -1.287252e+09 6.436262e+07 42 52 1.582687e+08 -7.913437e+06 42 53 -1.318906e+08 6.594531e+06 42 54 -5.908699e+08 2.954350e+07 42 58 2.980232e-08 -1.490116e-09 42 59 -5.275624e+08 2.637812e+07 42 84 -1.287252e+09 6.436262e+07 42 88 -1.582687e+08 7.913437e+06 42 89 1.318906e+08 -6.594531e+06 42 90 -1.983635e+09 9.918174e+07 42 94 -6.330749e+08 3.165375e+07 42 95 1.490116e-08 -7.450581e-10 42 96 -1.287252e+09 6.436262e+07 42 100 -1.582687e+08 7.913437e+06 42 101 -1.318906e+08 6.594531e+06 43 43 1.796625e+10 -8.983125e+08 43 44 2.384186e-07 -1.192093e-08 43 49 -2.245781e+09 1.122891e+08 43 50 -1.725352e+09 8.626761e+07 43 55 -4.424986e+09 2.212493e+08 43 56 -1.788139e-07 8.940697e-09 43 85 -2.245781e+09 1.122891e+08 43 86 -1.725352e+09 8.626761e+07 43 91 -6.657689e+07 3.328845e+06 43 92 5.960464e-08 -2.980232e-09 43 97 -2.245781e+09 1.122891e+08 43 98 1.725352e+09 -8.626761e+07 44 44 2.134027e+10 -1.067014e+09 44 49 -1.725352e+09 8.626761e+07 44 50 -2.667534e+09 1.333767e+08 44 55 -2.086163e-07 1.043081e-08 44 56 2.169693e+09 -1.084847e+08 44 85 -1.725352e+09 8.626761e+07 44 86 -2.667534e+09 1.333767e+08 44 91 -1.490116e-07 7.450581e-09 44 92 -7.504762e+09 3.752381e+08 44 97 1.725352e+09 -8.626761e+07 44 98 -2.667534e+09 1.333767e+08 45 45 2.900850e+06 -1.450425e+05 45 51 -3.626063e+05 1.813032e+04 45 57 -1.664422e+05 8.322112e+03 45 87 -3.626063e+05 1.813032e+04 45 93 -5.587704e+05 2.793852e+04 45 99 -3.626063e+05 1.813032e+04 46 46 3.561542e+08 -1.780771e+07 46 47 0.000000e+00 -0.000000e+00 46 48 -1.582687e+08 7.913437e+06 46 52 2.142603e+07 -1.071302e+06 46 53 3.594484e+05 -1.797242e+04 46 54 -8.940697e-08 4.470348e-09 46 58 8.837909e+07 -4.418955e+06 46 59 2.182787e-11 -1.091394e-12 46 84 1.582687e+08 -7.913437e+06 46 88 2.142603e+07 -1.071302e+06 46 89 3.594484e+05 -1.797242e+04 46 90 6.330749e+08 -3.165375e+07 46 94 8.636358e+07 -4.318179e+06 46 95 5.820766e-11 -2.910383e-12 46 96 1.582687e+08 -7.913437e+06 46 100 2.142603e+07 -1.071302e+06 46 101 -3.594484e+05 1.797242e+04 47 47 3.554513e+08 -1.777256e+07 47 48 1.318906e+08 -6.594531e+06 47 52 3.594484e+05 -1.797242e+04 47 53 2.151390e+07 -1.075695e+06 47 54 5.275624e+08 -2.637812e+07 47 58 4.365575e-11 -2.182787e-12 47 59 8.700520e+07 -4.350260e+06 47 84 -1.318906e+08 6.594531e+06 47 88 3.594484e+05 -1.797242e+04 47 89 2.151390e+07 -1.075695e+06 47 90 -1.490116e-08 7.450581e-10 47 94 -7.275958e-12 3.637979e-13 47 95 8.791320e+07 -4.395660e+06 47 96 1.318906e+08 -6.594531e+06 47 100 -3.594484e+05 1.797242e+04 47 101 2.151390e+07 -1.075695e+06 48 48 5.149009e+09 -2.574505e+08 48 52 -6.330749e+08 3.165375e+07 48 53 2.980232e-08 -1.490116e-09 48 54 -1.983635e+09 9.918174e+07 48 58 -6.330749e+08 3.165375e+07 48 59 4.470348e-08 -2.235174e-09 48 60 -2.954350e+08 1.477175e+07 48 64 -1.582687e+08 7.913437e+06 48 65 -2.637812e+08 1.318906e+07 48 66 -1.287252e+09 6.436262e+07 48 70 -1.582687e+08 7.913437e+06 48 71 -1.318906e+08 6.594531e+06 49 49 8.983125e+09 -4.491563e+08 49 50 9.536743e-07 -4.768372e-08 49 55 -6.657689e+07 3.328845e+06 49 56 -5.662441e-07 2.831221e-08 49 61 -2.212493e+09 1.106246e+08 49 62 1.738727e+08 -8.693635e+06 49 67 -2.245781e+09 1.122891e+08 49 68 1.725352e+09 -8.626761e+07 50 50 1.067014e+10 -5.335068e+08 50 55 -5.364418e-07 2.682209e-08 50 56 -7.504762e+09 3.752381e+08 50 61 -1.738727e+08 8.693635e+06 50 62 1.084847e+09 -5.424234e+07 50 67 1.725352e+09 -8.626761e+07 50 68 -2.667534e+09 1.333767e+08 51 51 1.450425e+06 -7.252126e+04 51 57 -5.587704e+05 2.793852e+04 51 63 -8.322112e+04 4.161056e+03 51 69 -3.626063e+05 1.813032e+04 52 52 1.780771e+08 -8.903855e+06 52 53 -2.328306e-10 1.164153e-11 52 54 6.330749e+08 -3.165375e+07 52 58 8.636358e+07 -4.318179e+06 52 59 1.018634e-10 -5.093170e-12 52 60 -1.582687e+08 7.913437e+06 52 64 4.418955e+07 -2.209477e+06 52 65 3.622348e+04 -1.811174e+03 52 66 1.582687e+08 -7.913437e+06 52 70 2.142603e+07 -1.071302e+06 52 71 -3.594484e+05 1.797242e+04 53 53 1.777256e+08 -8.886282e+06 53 54 -8.940697e-08 4.470348e-09 53 58 9.458745e-11 -4.729372e-12 53 59 8.791320e+07 -4.395660e+06 53 60 2.637812e+08 -1.318906e+07 53 64 -3.622348e+04 1.811174e+03 53 65 4.350260e+07 -2.175130e+06 53 66 1.318906e+08 -6.594531e+06 53 70 -3.594484e+05 1.797242e+04 53 71 2.151390e+07 -1.075695e+06 54 54 1.029802e+10 -5.149009e+08 54 58 1.192093e-07 -5.960464e-09 54 59 -5.960464e-08 2.980232e-09 54 60 -1.287252e+09 6.436262e+07 54 64 1.582687e+08 -7.913437e+06 54 65 -1.318906e+08 6.594531e+06 54 66 -5.908699e+08 2.954350e+07 54 70 -5.960464e-08 2.980232e-09 54 71 -5.275624e+08 2.637812e+07 54 90 -1.287252e+09 6.436262e+07 54 94 -1.582687e+08 7.913437e+06 54 95 1.318906e+08 -6.594531e+06 54 96 -1.983635e+09 9.918174e+07 54 100 -6.330749e+08 3.165375e+07 54 101 1.490116e-08 -7.450581e-10 54 102 -1.287252e+09 6.436262e+07 54 106 -1.582687e+08 7.913437e+06 54 107 -1.318906e+08 6.594531e+06 55 55 1.796625e+10 -8.983125e+08 55 56 9.536743e-07 -4.768372e-08 55 61 -2.245781e+09 1.122891e+08 55 62 -1.725352e+09 8.626761e+07 55 67 -4.424986e+09 2.212493e+08 55 68 1.192093e-07 -5.960464e-09 55 91 -2.245781e+09 1.122891e+08 55 92 -1.725352e+09 8.626761e+07 55 97 -6.657689e+07 3.328845e+06 55 98 1.192093e-07 -5.960464e-09 55 103 -2.245781e+09 1.122891e+08 55 104 1.725352e+09 -8.626761e+07 56 56 2.134027e+10 -1.067014e+09 56 61 -1.725352e+09 8.626761e+07 56 62 -2.667534e+09 1.333767e+08 56 67 5.960464e-08 -2.980232e-09 56 68 2.169693e+09 -1.084847e+08 56 91 -1.725352e+09 8.626761e+07 56 92 -2.667534e+09 1.333767e+08 56 97 -8.940697e-08 4.470348e-09 56 98 -7.504762e+09 3.752381e+08 56 103 1.725352e+09 -8.626761e+07 56 104 -2.667534e+09 1.333767e+08 57 57 2.900850e+06 -1.450425e+05 57 63 -3.626063e+05 1.813032e+04 57 69 -1.664422e+05 8.322112e+03 57 93 -3.626063e+05 1.813032e+04 57 99 -5.587704e+05 2.793852e+04 57 105 -3.626063e+05 1.813032e+04 58 58 3.561542e+08 -1.780771e+07 58 59 -1.164153e-10 5.820766e-12 58 60 -1.582687e+08 7.913437e+06 58 64 2.142603e+07 -1.071302e+06 58 65 3.594484e+05 -1.797242e+04 58 66 -5.960464e-08 2.980232e-09 58 70 8.837909e+07 -4.418955e+06 58 71 -5.093170e-11 2.546585e-12 58 90 1.582687e+08 -7.913437e+06 58 94 2.142603e+07 -1.071302e+06 58 95 3.594484e+05 -1.797242e+04 58 96 6.330749e+08 -3.165375e+07 58 100 8.636358e+07 -4.318179e+06 58 101 0.000000e+00 -0.000000e+00 58 102 1.582687e+08 -7.913437e+06 58 106 2.142603e+07 -1.071302e+06 58 107 -3.594484e+05 1.797242e+04 59 59 3.554513e+08 -1.777256e+07 59 60 1.318906e+08 -6.594531e+06 59 64 3.594484e+05 -1.797242e+04 59 65 2.151390e+07 -1.075695e+06 59 66 5.275624e+08 -2.637812e+07 59 70 0.000000e+00 -0.000000e+00 59 71 8.700520e+07 -4.350260e+06 59 90 -1.318906e+08 6.594531e+06 59 94 3.594484e+05 -1.797242e+04 59 95 2.151390e+07 -1.075695e+06 59 96 -1.490116e-08 7.450581e-10 59 100 -2.182787e-11 1.091394e-12 59 101 8.791320e+07 -4.395660e+06 59 102 1.318906e+08 -6.594531e+06 59 106 -3.594484e+05 1.797242e+04 59 107 2.151390e+07 -1.075695e+06 60 60 2.574505e+09 -1.287252e+08 60 64 -3.165375e+08 1.582687e+07 60 65 2.637812e+08 -1.318906e+07 60 66 -9.918174e+08 4.959087e+07 60 70 -3.165375e+08 1.582687e+07 60 71 1.318906e+08 -6.594531e+06 61 61 4.491563e+09 -2.245781e+08 61 62 1.725352e+09 -8.626761e+07 61 67 -3.328845e+07 1.664422e+06 61 68 1.738727e+08 -8.693635e+06 62 62 5.335068e+09 -2.667534e+08 62 67 -1.738727e+08 8.693635e+06 62 68 -3.752381e+09 1.876190e+08 63 63 7.252126e+05 -3.626063e+04 63 69 -2.793852e+05 1.396926e+04 64 64 8.903855e+07 -4.451927e+06 64 65 -3.594484e+05 1.797242e+04 64 66 3.165375e+08 -1.582687e+07 64 70 4.318179e+07 -2.159090e+06 64 71 3.622348e+04 -1.811174e+03 65 65 8.886282e+07 -4.443141e+06 65 66 1.318906e+08 -6.594531e+06 65 70 -3.622348e+04 1.811174e+03 65 71 4.395660e+07 -2.197830e+06 66 66 5.149009e+09 -2.574505e+08 66 70 5.960464e-08 -2.980232e-09 66 71 5.275624e+08 -2.637812e+07 66 96 -1.287252e+09 6.436262e+07 66 100 -1.582687e+08 7.913437e+06 66 101 1.318906e+08 -6.594531e+06 66 102 -9.918174e+08 4.959087e+07 66 106 -3.165375e+08 1.582687e+07 66 107 1.318906e+08 -6.594531e+06 67 67 8.983125e+09 -4.491563e+08 67 68 4.768372e-07 -2.384186e-08 67 97 -2.245781e+09 1.122891e+08 67 98 -1.725352e+09 8.626761e+07 67 103 -3.328845e+07 1.664422e+06 67 104 1.738727e+08 -8.693635e+06 68 68 1.067014e+10 -5.335068e+08 68 97 -1.725352e+09 8.626761e+07 68 98 -2.667534e+09 1.333767e+08 68 103 -1.738727e+08 8.693635e+06 68 104 -3.752381e+09 1.876190e+08 69 69 1.450425e+06 -7.252126e+04 69 99 -3.626063e+05 1.813032e+04 69 105 -2.793852e+05 1.396926e+04 70 70 1.780771e+08 -8.903855e+06 70 71 -5.820766e-11 2.910383e-12 70 96 1.582687e+08 -7.913437e+06 70 100 2.142603e+07 -1.071302e+06 70 101 3.594484e+05 -1.797242e+04 70 102 3.165375e+08 -1.582687e+07 70 106 4.318179e+07 -2.159090e+06 70 107 3.622348e+04 -1.811174e+03 71 71 1.777256e+08 -8.886282e+06 71 96 -1.318906e+08 6.594531e+06 71 100 3.594484e+05 -1.797242e+04 71 101 2.151390e+07 -1.075695e+06 71 102 1.318906e+08 -6.594531e+06 71 106 -3.622348e+04 1.811174e+03 71 107 4.395660e+07 -2.197830e+06 90 90 1.029802e+10 -5.149009e+08 90 94 2.980232e-07 -1.490116e-08 90 95 -5.960464e-08 2.980232e-09 90 96 -5.908699e+08 2.954350e+07 90 100 2.980232e-08 -1.490116e-09 90 101 -5.275624e+08 2.637812e+07 90 120 -1.287252e+09 6.436262e+07 90 124 -1.582687e+08 7.913437e+06 90 125 1.318906e+08 -6.594531e+06 90 126 -1.983635e+09 9.918174e+07 90 130 -6.330749e+08 3.165375e+07 90 131 2.980232e-08 -1.490116e-09 90 132 -1.287252e+09 6.436262e+07 90 136 -1.582687e+08 7.913437e+06 90 137 -1.318906e+08 6.594531e+06 91 91 1.796625e+10 -8.983125e+08 91 92 -4.768372e-07 2.384186e-08 91 97 -4.424986e+09 2.212493e+08 91 98 -2.980232e-07 1.490116e-08 91 121 -2.245781e+09 1.122891e+08 91 122 -1.725352e+09 8.626761e+07 91 127 -6.657689e+07 3.328845e+06 91 128 -1.192093e-07 5.960464e-09 91 133 -2.245781e+09 1.122891e+08 91 134 1.725352e+09 -8.626761e+07 92 92 2.134027e+10 -1.067014e+09 92 97 -2.384186e-07 1.192093e-08 92 98 2.169693e+09 -1.084847e+08 92 121 -1.725352e+09 8.626761e+07 92 122 -2.667534e+09 1.333767e+08 92 127 1.192093e-07 -5.960464e-09 92 128 -7.504762e+09 3.752381e+08 92 133 1.725352e+09 -8.626761e+07 92 134 -2.667534e+09 1.333767e+08 93 93 2.900850e+06 -1.450425e+05 93 99 -1.664422e+05 8.322112e+03 93 123 -3.626063e+05 1.813032e+04 93 129 -5.587704e+05 2.793852e+04 93 135 -3.626063e+05 1.813032e+04 94 94 3.561542e+08 -1.780771e+07 94 95 -5.820766e-11 2.910383e-12 94 96 -8.940697e-08 4.470348e-09 94 100 8.837909e+07 -4.418955e+06 94 101 5.820766e-11 -2.910383e-12 94 120 1.582687e+08 -7.913437e+06 94 124 2.142603e+07 -1.071302e+06 94 125 3.594484e+05 -1.797242e+04 94 126 6.330749e+08 -3.165375e+07 94 130 8.636358e+07 -4.318179e+06 94 131 7.275958e-12 -3.637979e-13 94 132 1.582687e+08 -7.913437e+06 94 136 2.142603e+07 -1.071302e+06 94 137 -3.594484e+05 1.797242e+04 95 95 3.554513e+08 -1.777256e+07 95 96 5.275624e+08 -2.637812e+07 95 100 5.093170e-11 -2.546585e-12 95 101 8.700520e+07 -4.350260e+06 95 120 -1.318906e+08 6.594531e+06 95 124 3.594484e+05 -1.797242e+04 95 125 2.151390e+07 -1.075695e+06 95 126 -1.490116e-08 7.450581e-10 95 130 2.182787e-11 -1.091394e-12 95 131 8.791320e+07 -4.395660e+06 95 132 1.318906e+08 -6.594531e+06 95 136 -3.594484e+05 1.797242e+04 95 137 2.151390e+07 -1.075695e+06 96 96 1.029802e+10 -5.149009e+08 96 100 5.960464e-08 -2.980232e-09 96 101 -5.960464e-08 2.980232e-09 96 102 -5.908699e+08 2.954350e+07 96 106 -5.960464e-08 2.980232e-09 96 107 -5.275624e+08 2.637812e+07 96 126 -1.287252e+09 6.436262e+07 96 130 -1.582687e+08 7.913437e+06 96 131 1.318906e+08 -6.594531e+06 96 132 -1.983635e+09 9.918174e+07 96 136 -6.330749e+08 3.165375e+07 96 137 2.980232e-08 -1.490116e-09 96 138 -1.287252e+09 6.436262e+07 96 142 -1.582687e+08 7.913437e+06 96 143 -1.318906e+08 6.594531e+06 97 97 1.796625e+10 -8.983125e+08 97 98 -2.384186e-07 1.192093e-08 97 103 -4.424986e+09 2.212493e+08 97 104 -5.960464e-08 2.980232e-09 97 127 -2.245781e+09 1.122891e+08 97 128 -1.725352e+09 8.626761e+07 97 133 -6.657689e+07 3.328845e+06 97 134 -5.960464e-08 2.980232e-09 97 139 -2.245781e+09 1.122891e+08 97 140 1.725352e+09 -8.626761e+07 98 98 2.134027e+10 -1.067014e+09 98 103 0.000000e+00 -0.000000e+00 98 104 2.169693e+09 -1.084847e+08 98 127 -1.725352e+09 8.626761e+07 98 128 -2.667534e+09 1.333767e+08 98 133 2.384186e-07 -1.192093e-08 98 134 -7.504762e+09 3.752381e+08 98 139 1.725352e+09 -8.626761e+07 98 140 -2.667534e+09 1.333767e+08 99 99 2.900850e+06 -1.450425e+05 99 105 -1.664422e+05 8.322112e+03 99 129 -3.626063e+05 1.813032e+04 99 135 -5.587704e+05 2.793852e+04 99 141 -3.626063e+05 1.813032e+04 100 100 3.561542e+08 -1.780771e+07 100 101 -1.746230e-10 8.731149e-12 100 102 -5.960464e-08 2.980232e-09 100 106 8.837909e+07 -4.418955e+06 100 107 -7.275958e-12 3.637979e-13 100 126 1.582687e+08 -7.913437e+06 100 130 2.142603e+07 -1.071302e+06 100 131 3.594484e+05 -1.797242e+04 100 132 6.330749e+08 -3.165375e+07 100 136 8.636358e+07 -4.318179e+06 100 137 -4.365575e-11 2.182787e-12 100 138 1.582687e+08 -7.913437e+06 100 142 2.142603e+07 -1.071302e+06 100 143 -3.594484e+05 1.797242e+04 101 101 3.554513e+08 -1.777256e+07 101 102 5.275624e+08 -2.637812e+07 101 106 2.910383e-11 -1.455192e-12 101 107 8.700520e+07 -4.350260e+06 101 126 -1.318906e+08 6.594531e+06 101 130 3.594484e+05 -1.797242e+04 101 131 2.151390e+07 -1.075695e+06 101 132 -1.490116e-08 7.450581e-10 101 136 -2.182787e-11 1.091394e-12 101 137 8.791320e+07 -4.395660e+06 101 138 1.318906e+08 -6.594531e+06 101 142 -3.594484e+05 1.797242e+04 101 143 2.151390e+07 -1.075695e+06 102 102 5.149009e+09 -2.574505e+08 102 106 0.000000e+00 -0.000000e+00 102 107 5.275624e+08 -2.637812e+07 102 132 -1.287252e+09 6.436262e+07 102 136 -1.582687e+08 7.913437e+06 102 137 1.318906e+08 -6.594531e+06 102 138 -9.918174e+08 4.959087e+07 102 142 -3.165375e+08 1.582687e+07 102 143 1.318906e+08 -6.594531e+06 103 103 8.983125e+09 -4.491563e+08 103 104 -2.384186e-07 1.192093e-08 103 133 -2.245781e+09 1.122891e+08 103 134 -1.725352e+09 8.626761e+07 103 139 -3.328845e+07 1.664422e+06 103 140 1.738727e+08 -8.693635e+06 104 104 1.067014e+10 -5.335068e+08 104 133 -1.725352e+09 8.626761e+07 104 134 -2.667534e+09 1.333767e+08 104 139 -1.738727e+08 8.693635e+06 104 140 -3.752381e+09 1.876190e+08 105 105 1.450425e+06 -7.252126e+04 105 135 -3.626063e+05 1.813032e+04 105 141 -2.793852e+05 1.396926e+04 106 106 1.780771e+08 -8.903855e+06 106 107 -1.746230e-10 8.731149e-12 106 132 1.582687e+08 -7.913437e+06 106 136 2.142603e+07 -1.071302e+06 106 137 3.594484e+05 -1.797242e+04 106 138 3.165375e+08 -1.582687e+07 106 142 4.318179e+07 -2.159090e+06 106 143 3.622348e+04 -1.811174e+03 107 107 1.777256e+08 -8.886282e+06 107 132 -1.318906e+08 6.594531e+06 107 136 3.594484e+05 -1.797242e+04 107 137 2.151390e+07 -1.075695e+06 107 138 1.318906e+08 -6.594531e+06 107 142 -3.622348e+04 1.811174e+03 107 143 4.395660e+07 -2.197830e+06 126 126 1.029802e+10 -5.149009e+08 126 130 2.384186e-07 -1.192093e-08 126 131 -8.940697e-08 4.470348e-09 126 132 -5.908699e+08 2.954350e+07 126 136 2.980232e-08 -1.490116e-09 126 137 -5.275624e+08 2.637812e+07 126 156 -1.287252e+09 6.436262e+07 126 160 -1.582687e+08 7.913437e+06 126 161 1.318906e+08 -6.594531e+06 126 162 -1.983635e+09 9.918174e+07 126 166 -6.330749e+08 3.165375e+07 126 167 1.490116e-08 -7.450581e-10 126 168 -1.287252e+09 6.436262e+07 126 172 -1.582687e+08 7.913437e+06 126 173 -1.318906e+08 6.594531e+06 127 127 1.796625e+10 -8.983125e+08 127 128 -2.384186e-07 1.192093e-08 127 133 -4.424986e+09 2.212493e+08 127 134 -1.192093e-07 5.960464e-09 127 157 -2.245781e+09 1.122891e+08 127 158 -1.725352e+09 8.626761e+07 127 163 -6.657689e+07 3.328845e+06 127 164 -2.980232e-07 1.490116e-08 127 169 -2.245781e+09 1.122891e+08 127 170 1.725352e+09 -8.626761e+07 128 128 2.134027e+10 -1.067014e+09 128 133 -1.788139e-07 8.940697e-09 128 134 2.169693e+09 -1.084847e+08 128 157 -1.725352e+09 8.626761e+07 128 158 -2.667534e+09 1.333767e+08 128 163 -1.490116e-07 7.450581e-09 128 164 -7.504762e+09 3.752381e+08 128 169 1.725352e+09 -8.626761e+07 128 170 -2.667534e+09 1.333767e+08 129 129 2.900850e+06 -1.450425e+05 129 135 -1.664422e+05 8.322112e+03 129 159 -3.626063e+05 1.813032e+04 129 165 -5.587704e+05 2.793852e+04 129 171 -3.626063e+05 1.813032e+04 130 130 3.561542e+08 -1.780771e+07 130 131 -1.164153e-10 5.820766e-12 130 132 -8.940697e-08 4.470348e-09 130 136 8.837909e+07 -4.418955e+06 130 137 3.637979e-11 -1.818989e-12 130 156 1.582687e+08 -7.913437e+06 130 160 2.142603e+07 -1.071302e+06 130 161 3.594484e+05 -1.797242e+04 130 162 6.330749e+08 -3.165375e+07 130 166 8.636358e+07 -4.318179e+06 130 167 8.003553e-11 -4.001777e-12 130 168 1.582687e+08 -7.913437e+06 130 172 2.142603e+07 -1.071302e+06 130 173 -3.594484e+05 1.797242e+04 131 131 3.554513e+08 -1.777256e+07 131 132 5.275624e+08 -2.637812e+07 131 136 7.275958e-11 -3.637979e-12 131 137 8.700520e+07 -4.350260e+06 131 156 -1.318906e+08 6.594531e+06 131 160 3.594484e+05 -1.797242e+04 131 161 2.151390e+07 -1.075695e+06 131 162 -4.470348e-08 2.235174e-09 131 166 3.637979e-11 -1.818989e-12 131 167 8.791320e+07 -4.395660e+06 131 168 1.318906e+08 -6.594531e+06 131 172 -3.594484e+05 1.797242e+04 131 173 2.151390e+07 -1.075695e+06 36 36 -6.505714e+09 0.000000e+00 36 42 -3.252857e+09 0.000000e+00 36 48 -1.626429e+09 0.000000e+00 36 54 -8.132143e+08 0.000000e+00 37 37 -6.505714e+09 0.000000e+00 37 38 -5.094747e-23 0.000000e+00 37 43 -3.252857e+09 0.000000e+00 37 44 8.334131e-24 -0.000000e+00 37 49 -1.626429e+09 0.000000e+00 37 50 -6.744929e-24 0.000000e+00 37 55 -8.132143e+08 0.000000e+00 38 38 -6.505714e+09 0.000000e+00 38 43 -8.334131e-24 0.000000e+00 38 44 -3.252857e+09 0.000000e+00 38 49 6.744929e-24 -0.000000e+00 38 50 -1.626429e+09 0.000000e+00 38 56 -8.132143e+08 0.000000e+00 40 40 -1.355357e+06 0.000000e+00 40 46 -6.776786e+05 0.000000e+00 40 52 -3.388393e+05 0.000000e+00 40 58 -1.694196e+05 0.000000e+00 41 41 -1.355357e+06 0.000000e+00 41 47 -6.776786e+05 0.000000e+00 41 53 -3.388393e+05 0.000000e+00 41 59 -1.694196e+05 0.000000e+00 42 42 -1.301143e+10 0.000000e+00 42 48 -8.132143e+08 0.000000e+00 42 54 -3.252857e+09 0.000000e+00 42 84 -8.132143e+08 0.000000e+00 42 90 -3.252857e+09 0.000000e+00 42 96 -8.132143e+08 0.000000e+00 43 43 -1.301143e+10 0.000000e+00 43 44 -3.728003e-23 0.000000e+00 43 49 -8.132143e+08 0.000000e+00 43 55 -3.252857e+09 0.000000e+00 43 85 -8.132143e+08 0.000000e+00 43 91 -3.252857e+09 0.000000e+00 43 92 1.327388e-23 -0.000000e+00 43 97 -8.132143e+08 0.000000e+00 44 44 -1.301143e+10 0.000000e+00 44 50 -8.132143e+08 0.000000e+00 44 56 -3.252857e+09 0.000000e+00 44 86 -8.132143e+08 0.000000e+00 44 91 -1.327388e-23 0.000000e+00 44 92 -3.252857e+09 0.000000e+00 44 98 -8.132143e+08 0.000000e+00 46 46 -2.710714e+06 0.000000e+00 46 52 -1.694196e+05 0.000000e+00 46 58 -6.776786e+05 0.000000e+00 46 88 -1.694196e+05 0.000000e+00 46 94 -6.776786e+05 0.000000e+00 46 100 -1.694196e+05 0.000000e+00 47 47 -2.710714e+06 0.000000e+00 47 53 -1.694196e+05 0.000000e+00 47 59 -6.776786e+05 0.000000e+00 47 89 -1.694196e+05 0.000000e+00 47 95 -6.776786e+05 0.000000e+00 47 101 -1.694196e+05 0.000000e+00 48 48 -6.505714e+09 0.000000e+00 48 54 -3.252857e+09 0.000000e+00 48 60 -1.626429e+09 0.000000e+00 48 66 -8.132143e+08 0.000000e+00 49 49 -6.505714e+09 0.000000e+00 49 50 -5.080446e-23 0.000000e+00 49 55 -3.252857e+09 0.000000e+00 49 56 4.167065e-24 -0.000000e+00 49 61 -1.626429e+09 0.000000e+00 49 62 -6.675074e-24 0.000000e+00 49 67 -8.132143e+08 0.000000e+00 50 50 -6.505714e+09 0.000000e+00 50 55 -4.167065e-24 0.000000e+00 50 56 -3.252857e+09 0.000000e+00 50 61 6.675074e-24 -0.000000e+00 50 62 -1.626429e+09 0.000000e+00 50 68 -8.132143e+08 0.000000e+00 52 52 -1.355357e+06 0.000000e+00 52 58 -6.776786e+05 0.000000e+00 52 64 -3.388393e+05 0.000000e+00 52 70 -1.694196e+05 0.000000e+00 53 53 -1.355357e+06 0.000000e+00 53 59 -6.776786e+05 0.000000e+00 53 65 -3.388393e+05 0.000000e+00 53 71 -1.694196e+05 0.000000e+00 54 54 -1.301143e+10 0.000000e+00 54 60 -8.132143e+08 0.000000e+00 54 66 -3.252857e+09 0.000000e+00 54 90 -8.132143e+08 0.000000e+00 54 96 -3.252857e+09 0.000000e+00 54 102 -8.132143e+08 0.000000e+00 55 55 -1.301143e+10 0.000000e+00 55 56 -3.621390e-23 0.000000e+00 55 61 -8.132143e+08 0.000000e+00 55 67 -3.252857e+09 0.000000e+00 55 91 -8.132143e+08 0.000000e+00 55 97 -3.252857e+09 0.000000e+00 55 98 1.245219e-23 -0.000000e+00 55 103 -8.132143e+08 0.000000e+00 56 56 -1.301143e+10 0.000000e+00 56 62 -8.132143e+08 0.000000e+00 56 68 -3.252857e+09 0.000000e+00 56 92 -8.132143e+08 0.000000e+00 56 97 -1.245219e-23 0.000000e+00 56 98 -3.252857e+09 0.000000e+00 56 104 -8.132143e+08 0.000000e+00 58 58 -2.710714e+06 0.000000e+00 58 64 -1.694196e+05 0.000000e+00 58 70 -6.776786e+05 0.000000e+00 58 94 -1.694196e+05 0.000000e+00 58 100 -6.776786e+05 0.000000e+00 58 106 -1.694196e+05 0.000000e+00 59 59 -2.710714e+06 0.000000e+00 59 65 -1.694196e+05 0.000000e+00 59 71 -6.776786e+05 0.000000e+00 59 95 -1.694196e+05 0.000000e+00 59 101 -6.776786e+05 0.000000e+00 59 107 -1.694196e+05 0.000000e+00 60 60 -3.252857e+09 0.000000e+00 60 66 -1.626429e+09 0.000000e+00 61 61 -3.252857e+09 0.000000e+00 61 62 -2.533073e-23 0.000000e+00 61 67 -1.626429e+09 0.000000e+00 62 62 -3.252857e+09 0.000000e+00 62 68 -1.626429e+09 0.000000e+00 64 64 -6.776786e+05 0.000000e+00 64 70 -3.388393e+05 0.000000e+00 65 65 -6.776786e+05 0.000000e+00 65 71 -3.388393e+05 0.000000e+00 66 66 -6.505714e+09 0.000000e+00 66 96 -8.132143e+08 0.000000e+00 66 102 -1.626429e+09 0.000000e+00 67 67 -6.505714e+09 0.000000e+00 67 68 -1.757388e-23 0.000000e+00 67 97 -8.132143e+08 0.000000e+00 67 103 -1.626429e+09 0.000000e+00 67 104 5.815252e-24 -0.000000e+00 68 68 -6.505714e+09 0.000000e+00 68 98 -8.132143e+08 0.000000e+00 68 103 -5.815252e-24 0.000000e+00 68 104 -1.626429e+09 0.000000e+00 70 70 -1.355357e+06 0.000000e+00 70 100 -1.694196e+05 0.000000e+00 70 106 -3.388393e+05 0.000000e+00 71 71 -1.355357e+06 0.000000e+00 71 101 -1.694196e+05 0.000000e+00 71 107 -3.388393e+05 0.000000e+00 90 90 -1.301143e+10 0.000000e+00 90 96 -3.252857e+09 0.000000e+00 90 120 -8.132143e+08 0.000000e+00 90 126 -3.252857e+09 0.000000e+00 90 132 -8.132143e+08 0.000000e+00 91 91 -1.301143e+10 0.000000e+00 91 92 2.101486e-23 -0.000000e+00 91 97 -3.252857e+09 0.000000e+00 91 121 -8.132143e+08 0.000000e+00 91 127 -3.252857e+09 0.000000e+00 91 133 -8.132143e+08 0.000000e+00 92 92 -1.301143e+10 0.000000e+00 92 98 -3.252857e+09 0.000000e+00 92 122 -8.132143e+08 0.000000e+00 92 128 -3.252857e+09 0.000000e+00 92 134 -8.132143e+08 0.000000e+00 94 94 -2.710714e+06 0.000000e+00 94 100 -6.776786e+05 0.000000e+00 94 124 -1.694196e+05 0.000000e+00 94 130 -6.776786e+05 0.000000e+00 94 136 -1.694196e+05 0.000000e+00 95 95 -2.710714e+06 0.000000e+00 95 101 -6.776786e+05 0.000000e+00 95 125 -1.694196e+05 0.000000e+00 95 131 -6.776786e+05 0.000000e+00 95 137 -1.694196e+05 0.000000e+00 96 96 -1.301143e+10 0.000000e+00 96 102 -3.252857e+09 0.000000e+00 96 126 -8.132143e+08 0.000000e+00 96 132 -3.252857e+09 0.000000e+00 96 138 -8.132143e+08 0.000000e+00 97 97 -1.301143e+10 0.000000e+00 97 98 1.995563e-23 -0.000000e+00 97 103 -3.252857e+09 0.000000e+00 97 127 -8.132143e+08 0.000000e+00 97 133 -3.252857e+09 0.000000e+00 97 139 -8.132143e+08 0.000000e+00 98 98 -1.301143e+10 0.000000e+00 98 104 -3.252857e+09 0.000000e+00 98 128 -8.132143e+08 0.000000e+00 98 134 -3.252857e+09 0.000000e+00 98 140 -8.132143e+08 0.000000e+00 100 100 -2.710714e+06 0.000000e+00 100 106 -6.776786e+05 0.000000e+00 100 130 -1.694196e+05 0.000000e+00 100 136 -6.776786e+05 0.000000e+00 100 142 -1.694196e+05 0.000000e+00 101 101 -2.710714e+06 0.000000e+00 101 107 -6.776786e+05 0.000000e+00 101 131 -1.694196e+05 0.000000e+00 101 137 -6.776786e+05 0.000000e+00 101 143 -1.694196e+05 0.000000e+00 102 102 -6.505714e+09 0.000000e+00 102 132 -8.132143e+08 0.000000e+00 102 138 -1.626429e+09 0.000000e+00 103 103 -6.505714e+09 0.000000e+00 103 104 9.448202e-24 -0.000000e+00 103 133 -8.132143e+08 0.000000e+00 103 139 -1.626429e+09 0.000000e+00 104 104 -6.505714e+09 0.000000e+00 104 134 -8.132143e+08 0.000000e+00 104 140 -1.626429e+09 0.000000e+00 106 106 -1.355357e+06 0.000000e+00 106 136 -1.694196e+05 0.000000e+00 106 142 -3.388393e+05 0.000000e+00 107 107 -1.355357e+06 0.000000e+00 107 137 -1.694196e+05 0.000000e+00 107 143 -3.388393e+05 0.000000e+00 126 126 -1.301143e+10 0.000000e+00 126 132 -3.252857e+09 0.000000e+00 126 156 -8.132143e+08 0.000000e+00 126 162 -3.252857e+09 0.000000e+00 126 168 -8.132143e+08 0.000000e+00 127 127 -1.301143e+10 0.000000e+00 127 128 -1.624548e-23 0.000000e+00 127 133 -3.252857e+09 0.000000e+00 127 157 -8.132143e+08 0.000000e+00 127 163 -3.252857e+09 0.000000e+00 127 164 -1.261364e-23 0.000000e+00 127 169 -8.132143e+08 0.000000e+00 128 128 -1.301143e+10 0.000000e+00 128 134 -3.252857e+09 0.000000e+00 128 158 -8.132143e+08 0.000000e+00 128 163 1.261364e-23 -0.000000e+00 128 164 -3.252857e+09 0.000000e+00 128 170 -8.132143e+08 0.000000e+00 130 130 -2.710714e+06 0.000000e+00 130 136 -6.776786e+05 0.000000e+00 130 160 -1.694196e+05 0.000000e+00 130 166 -6.776786e+05 0.000000e+00 130 172 -1.694196e+05 0.000000e+00 131 131 -2.710714e+06 0.000000e+00 131 137 -6.776786e+05 0.000000e+00 131 161 -1.694196e+05 0.000000e+00 131 167 -6.776786e+05 0.000000e+00 131 173 -1.694196e+05 0.000000e+0687e+08 7.913437e+06 126 173 -1.318906e+08 6.594531e+06 127 127 1.796625e+10 -8.983125e+08 127 128 -2.384186e-07 1.192093e-08 127 133 -4.424986e+09 2.212493e+08 127 134 -1.192093e-07 5.960464e-09 127 157 -2.245781e+09 1.122891e+08 127 158 -1.725352e+09 8.626761e+07 127 163 -6.657689e+07 3.3288misc/drivers/haggar.rhs.0.input010064400020550007177000000045270665164010600177610ustar00clevecompmath00000400000006 249 1 3 1 1 4 1 1 5 1 1 6 1 1 7 1 1 8 1 1 9 1 1 10 1 1 11 1 1 12 1 1 13 1 1 14 1 1 15 1 1 16 1 1 17 1 1 18 1 1 19 1 1 20 1 1 21 1 1 22 1 1 23 1 1 24 1 1 25 1 1 26 1 1 27 1 1 28 1 1 29 1 1 30 1 1 31 1 1 32 1 1 33 1 1 34 1 1 35 1 1 36 1 1 37 1 1 38 1 1 39 1 1 40 1 1 41 1 1 42 1 1 43 1 1 44 1 1 45 1 1 46 1 1 47 1 1 48 1 1 49 1 1 50 1 1 51 1 1 52 1 1 53 1 1 54 1 1 55 1 1 56 1 1 57 1 1 58 1 1 59 1 1 60 1 1 61 1 1 62 1 1 63 1 1 64 1 1 65 1 1 66 1 1 67 1 1 68 1 1 69 1 1 70 1 1 71 1 1 72 1 1 73 1 1 74 1 1 75 1 1 76 1 1 77 1 1 78 1 1 79 1 1 80 1 1 81 1 1 82 1 1 83 1 1 84 1 1 85 1 1 86 1 1 87 1 1 88 1 1 89 1 1 90 1 1 91 1 1 92 1 1 93 1 1 94 1 1 95 1 1 96 1 1 97 1 1 98 1 1 99 1 1 100 1 1 101 1 1 102 1 1 103 1 1 104 1 1 105 1 1 106 1 1 107 1 1 108 1 1 109 1 1 110 1 1 111 1 1 112 1 1 113 1 1 114 1 1 115 1 1 116 1 1 117 1 1 118 1 1 119 1 1 120 1 1 121 1 1 122 1 1 123 1 1 124 1 1 125 1 1 126 1 1 127 1 1 128 1 1 129 1 1 130 1 1 131 1 1 132 1 1 133 1 1 134 1 1 135 1 1 136 1 1 137 1 1 138 1 1 139 1 1 140 1 1 141 1 1 142 1 1 143 1 1 144 1 1 145 1 1 146 1 1 147 1 1 148 1 1 149 1 1 150 1 1 151 1 1 152 1 1 153 1 1 154 1 1 155 1 1 156 1 1 157 1 1 158 1 1 159 1 1 160 1 1 161 1 1 162 1 1 163 1 1 164 1 1 165 1 1 166 1 1 167 1 1 168 1 1 169 1 1 170 1 1 171 1 1 172 1 1 173 1 1 174 1 1 175 1 1 176 1 1 177 1 1 178 1 1 179 1 1 180 1 1 181 1 1 182 1 1 183 1 1 184 1 1 185 1 1 186 1 1 187 1 1 188 1 1 189 1 1 190 1 1 191 1 1 192 1 1 193 1 1 194 1 1 195 1 1 196 1 1 197 1 1 198 1 1 199 1 1 200 1 1 201 1 1 202 1 1 203 1 1 204 1 1 205 1 1 206 1 1 207 1 1 208 1 1 209 1 1 210 1 1 211 1 1 212 1 1 213 1 1 214 1 1 215 1 1 216 1 1 217 1 1 218 1 1 219 1 1 220 1 1 221 1 1 222 1 1 223 1 1 224 1 1 225 1 1 226 1 1 227 1 1 228 1 1 229 1 1 230 1 1 231 1 1 232 1 1 233 1 1 234 1 1 235 1 1 236 1 1 237 1 1 238 1 1 239 1 1 240 1 1 241 1 1 242 1 1 243 1 1 244 1 1 245 1 1 246 1 1 247 1 1 248 1 1 249 1 1 250 1 1 251 1 misc/drivers/haggar.rhs.1.input010064400020550007177000000000120665164010600177430ustar00clevecompmath00000400000006 1 1 0 1 misc/drivers/haggar.rhs.2.input010064400020550007177000000000130665164010600177450ustar00clevecompmath00000400000006 1 1 1 1 misc/drivers/haggar.rhs.3.input010064400020550007177000000000120665164010600177450ustar00clevecompmath00000400000006 1 1 2 1 misc/drivers/haggar.rhs.input010064400020550007177000000045520665164417200176300ustar00clevecompmath00000400000006252 1 3 1 1 4 1 1 5 1 1 6 1 1 7 1 1 8 1 1 9 1 1 10 1 1 11 1 1 12 1 1 13 1 1 14 1 1 15 1 1 16 1 1 17 1 1 18 1 1 19 1 1 20 1 1 21 1 1 22 1 1 23 1 1 24 1 1 25 1 1 26 1 1 27 1 1 28 1 1 29 1 1 30 1 1 31 1 1 32 1 1 33 1 1 34 1 1 35 1 1 36 1 1 37 1 1 38 1 1 39 1 1 40 1 1 41 1 1 42 1 1 43 1 1 44 1 1 45 1 1 46 1 1 47 1 1 48 1 1 49 1 1 50 1 1 51 1 1 52 1 1 53 1 1 54 1 1 55 1 1 56 1 1 57 1 1 58 1 1 59 1 1 60 1 1 61 1 1 62 1 1 63 1 1 64 1 1 65 1 1 66 1 1 67 1 1 68 1 1 69 1 1 70 1 1 71 1 1 72 1 1 73 1 1 74 1 1 75 1 1 76 1 1 77 1 1 78 1 1 79 1 1 80 1 1 81 1 1 82 1 1 83 1 1 84 1 1 85 1 1 86 1 1 87 1 1 88 1 1 89 1 1 90 1 1 91 1 1 92 1 1 93 1 1 94 1 1 95 1 1 96 1 1 97 1 1 98 1 1 99 1 1 100 1 1 101 1 1 102 1 1 103 1 1 104 1 1 105 1 1 106 1 1 107 1 1 108 1 1 109 1 1 110 1 1 111 1 1 112 1 1 113 1 1 114 1 1 115 1 1 116 1 1 117 1 1 118 1 1 119 1 1 120 1 1 121 1 1 122 1 1 123 1 1 124 1 1 125 1 1 126 1 1 127 1 1 128 1 1 129 1 1 130 1 1 131 1 1 132 1 1 133 1 1 134 1 1 135 1 1 136 1 1 137 1 1 138 1 1 139 1 1 140 1 1 141 1 1 142 1 1 143 1 1 144 1 1 145 1 1 146 1 1 147 1 1 148 1 1 149 1 1 150 1 1 151 1 1 152 1 1 153 1 1 154 1 1 155 1 1 156 1 1 157 1 1 158 1 1 159 1 1 160 1 1 161 1 1 162 1 1 163 1 1 164 1 1 165 1 1 166 1 1 167 1 1 168 1 1 169 1 1 170 1 1 171 1 1 172 1 1 173 1 1 174 1 1 175 1 1 176 1 1 177 1 1 178 1 1 179 1 1 180 1 1 181 1 1 182 1 1 183 1 1 184 1 1 185 1 1 186 1 1 187 1 1 188 1 1 189 1 1 190 1 1 191 1 1 192 1 1 193 1 1 194 1 1 195 1 1 196 1 1 197 1 1 198 1 1 199 1 1 200 1 1 201 1 1 202 1 1 203 1 1 204 1 1 205 1 1 206 1 1 207 1 1 208 1 1 209 1 1 210 1 1 211 1 1 212 1 1 213 1 1 214 1 1 215 1 1 216 1 1 217 1 1 218 1 1 219 1 1 220 1 1 221 1 1 222 1 1 223 1 1 224 1 1 225 1 1 226 1 1 227 1 1 228 1 1 229 1 1 230 1 1 231 1 1 232 1 1 233 1 1 234 1 1 235 1 1 236 1 1 237 1 1 238 1 1 239 1 1 240 1 1 241 1 1 242 1 1 243 1 1 244 1 1 245 1 1 246 1 1 247 1 1 248 1 1 249 1 1 250 1 1 251 1 1 0 1 1 1 1 1 2 1 1 misc/drivers/matrix.input010064400020550007177000000003070657406322300170760ustar00clevecompmath000004000000069 9 21 0 0 4.0 1 1 4.0 2 2 4.0 3 3 4.0 4 4 4.0 5 5 4.0 6 6 4.0 7 7 4.0 8 8 4.0 0 1 -1.0 1 2 -1.0 3 4 -1.0 4 5 -1.0 6 7 -1.0 7 8 -1.0 0 3 -1.0 1 4 -1.0 2 5 -1.0 3 6 -1.0 4 7 -1.0 5 8 -1.0 misc/drivers/qr.matrix.input010064400020550007177000000002270654255126500175230ustar00clevecompmath000004000000068 6 18 0 1 1.0 0 3 2.0 1 2 3.0 1 3 1.0 1 5 1.0 2 0 1.0 2 2 2.0 3 0 3.0 3 2 4.0 3 4 2.0 4 3 1.0 5 1 2.0 5 4 3.0 5 5 1.0 6 0 2.0 6 3 3.0 7 1 1.0 7 4 3.0 misc/drivers/qr.rhs.input010064400020550007177000000000640654255127600170140ustar00clevecompmath000004000000068 1 0 3.0 1 5.0 2 3.0 3 9.0 4 1.0 5 6.0 6 5.0 7 4.0 misc/drivers/rhs.input010064400020550007177000000005320662033754500163710ustar00clevecompmath000004000000069 9 0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 3 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 4 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 5 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 6 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 7 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 8 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 misc/drivers/singularMatrix.input010064400020550007177000000022450657106073000206030ustar00clevecompmath00000400000006 13 13 27 0 0 1.7453333536783853E+08 0 3 -1.7453333536783853E+08 1 1 7.1828074095507547E+07 1 2 4.8483950014467597E+08 1 4 4.8483950014467597E+08 2 2 4.3635555013020830E+09 2 4 2.1817777506510420E+09 3 3 2.5440452273956126E+08 3 10 -7.9871187371722728E+07 4 4 6.3604368324064264E+09 4 11 -1.0153633886971237E+08 4 12 9.9844066555217147E+08 5 5 2.5440452273956126E+08 5 7 -1.7453333536783853E+08 5 10 -7.9871187371722728E+07 6 6 6.3604368324064264E+09 6 8 -4.8483950014467597E+08 6 9 2.1817777506510420E+09 6 11 1.0153633886971237E+08 6 12 9.9844066555217147E+08 7 7 1.7453333536783853E+08 8 8 7.1828074095507547E+07 8 9 -4.8483950014467597E+08 9 9 4.3635555013020830E+09 10 10 1.5974237474344546E+08 11 11 1.3767639168774558E+07 12 12 3.9937626622086864E+09 misc/drivers/singularRhs.input010064400020550007177000000007150657106104400200720ustar00clevecompmath00000400000006 13 1 0 .0000000000000000E+00 1 -2.6000000000000000E+04 2 .0000000000000000E+00 3 .0000000000000000E+00 4 .0000000000000000E+00 5 .0000000000000000E+00 6 .0000000000000000E+00 7 .0000000000000000E+00 8 -2.6000000000000000E+04 9 .0000000000000000E+00 10 .0000000000000000E+00 11 .0000000000000000E+00 12 .0000000000000000E+00 misc/doc/004275500020550007177000000000000657600505600136075ustar00clevecompmath00000400000006misc/doc/R2D100fishnet.eps010064400020550007177000000266640653410634600165200ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 600.0 600.0 /radius 10.000 def /Helvetica findfont 12.500 scalefont setfont /M {moveto} def /L {lineto} def /ACF { % stack : x y radius newpath 0 360 arc closepath fill } def /str 6 string def /drawLabel { % x y label radius /radius exch def /label exch def /y exch def /x exch def gsave 1.0 setgray x radius add y moveto x y radius 0 360 arc fill 0.0 setgray x radius add y moveto x y radius 0 360 arc stroke x y moveto label stringwidth pop 2 div neg radius 2 div neg rmoveto label show grestore } def gsave 3.000 setlinewidth 0.0 setgray newpath 82.2 20 M 20 20 L 269 20 M 207 20 L 331 20 M 269 20 L 393 20 M 331 20 L 456 20 M 393 20 L 518 20 M 456 20 L 580 20 M 518 20 L 82.2 580 M 20 580 L 144 580 M 82.2 580 L 207 580 M 144 580 L 269 580 M 207 580 L 331 580 M 269 580 L 393 580 M 331 580 L 518 580 M 456 580 L 20 82.2 M 20 20 L 20 82.2 M 82.2 20 L 20 144 M 20 82.2 L 20 207 M 20 144 L 20 269 M 20 207 L 20 331 M 20 269 L 20 393 M 20 331 L 20 518 M 20 580 L 20 518 M 82.2 580 L 580 82.2 M 518 20 L 580 82.2 M 580 20 L 580 144 M 580 82.2 L 580 331 M 580 269 L 580 393 M 580 331 L 580 456 M 580 393 L 580 518 M 518 580 L 510 90 M 456 20 L 510 90 M 518 20 L 510 90 M 580 82.2 L 510 90 M 580 144 L 90 230 M 20 207 L 90 230 M 20 269 L 370 510 M 456 580 L 195 195 M 90 230 L 55 335 M 20 331 L 55 335 M 20 393 L 335 55 M 269 20 L 335 55 M 331 20 L 335 55 M 393 20 L 125 545 M 82.2 580 L 125 545 M 144 580 L 125 545 M 20 518 L 405 265 M 300 300 L 265 125 M 335 55 L 545 405 M 580 393 L 545 405 M 580 456 L 143 72.5 M 82.2 20 L 423 353 M 405 265 L 72.5 283 M 20 269 L 72.5 283 M 20 331 L 72.5 283 M 90 230 L 72.5 283 M 55 335 L 213 423 M 160 440 L 213 423 M 283 493 L 493 143 M 580 207 L 493 143 M 440 160 L 107 317 M 90 230 L 107 317 M 55 335 L 107 317 M 72.5 283 L 527 457 M 580 456 L 527 457 M 475 475 L 527 457 M 545 405 L 177 107 M 247 177 L 457 387 M 475 475 L 457 387 M 545 405 L 457 387 M 423 353 L 457 387 M 527 457 L 317 247 M 300 300 L 317 247 M 405 265 L 169 361 M 230 370 L 449 81.3 M 393 20 L 449 81.3 M 456 20 L 449 81.3 M 510 90 L 309 501 M 331 580 L 309 501 M 283 493 L 98.7 151 M 90 230 L 519 291 M 580 269 L 519 291 M 580 331 L 63.7 466 M 20 456 L 344 186 M 317 247 L 484 326 M 405 265 L 484 326 M 457 387 L 484 326 M 519 291 L 274 256 M 300 300 L 274 256 M 317 247 L 134 396 M 169 361 L 414 116 M 393 20 L 414 116 M 335 55 L 414 116 M 449 81.3 L 151 169 M 90 230 L 151 169 M 195 195 L 151 169 M 98.7 151 L 431 449 M 475 475 L 431 449 M 457 387 L 431 449 M 379 431 L 291 309 M 300 300 L stroke newpath 291 309 M 274 256 L 221 519 M 144 580 L 221 519 M 207 580 L 221 519 M 269 580 L 221 519 M 160 440 L 221 519 M 125 545 L 221 519 M 283 493 L 221 519 M 213 423 L 501 239 M 580 269 L 501 239 M 405 265 L 501 239 M 519 291 L 501 239 M 484 326 L 81.3 98.7 M 82.2 20 L 81.3 98.7 M 20 82.2 L 81.3 98.7 M 20 144 L 81.3 98.7 M 143 72.5 L 81.3 98.7 M 98.7 151 L 361 379 M 300 300 L 361 379 M 405 265 L 361 379 M 423 353 L 361 379 M 379 431 L 361 379 M 291 309 L 256 63.7 M 207 20 L 256 63.7 M 269 20 L 256 63.7 M 335 55 L 256 63.7 M 265 125 L 536 344 M 580 331 L 536 344 M 580 393 L 536 344 M 545 405 L 536 344 M 457 387 L 536 344 M 519 291 L 536 344 M 484 326 L 116 484 M 20 518 L 116 484 M 160 440 L 116 484 M 125 545 L 116 484 M 221 519 L 396 204 M 405 265 L 396 204 M 317 247 L 396 204 M 344 186 L 396 204 M 501 239 L 186 274 M 90 230 L 186 274 M 195 195 L 186 274 M 107 317 L 243 269 M 247 177 L 103 409 M 63.7 466 L 103 409 M 134 396 L 383 129 M 440 160 L 383 129 M 326 134 L 313 199 M 247 177 L 313 199 M 326 134 L 173 59.4 M 144 20 L 173 59.4 M 177 107 L 453 339 M 405 265 L 453 339 M 423 353 L 453 339 M 457 387 L 453 339 M 484 326 L 138 94.4 M 143 72.5 L 138 94.4 M 98.7 151 L 138 94.4 M 151 169 L 138 94.4 M 81.3 98.7 L 418 374 M 423 353 L 418 374 M 457 387 L 418 374 M 379 431 L 418 374 M 431 449 L 418 374 M 361 379 L 278 514 M 269 580 L 278 514 M 331 580 L 278 514 M 283 493 L 278 514 M 309 501 L 278 514 M 221 519 L 208 304 M 230 370 L 208 304 M 169 361 L 208 304 M 243 269 L 68.1 164 M 20 144 L 68.1 164 M 20 207 L 68.1 164 M 90 230 L 68.1 164 M 98.7 151 L 68.1 164 M 81.3 98.7 L 348 444 M 230 370 L 348 444 M 370 510 L stroke grestore gsave 0.100 setlinewidth 0.0 setgray newpath 144 20 M 82.2 20 L 207 20 M 144 20 L 456 580 M 393 580 L 580 580 M 518 580 L 20 456 M 20 393 L 20 518 M 20 456 L 580 207 M 580 144 L 580 269 M 580 207 L 580 518 M 580 580 L 580 518 M 580 456 L 370 510 M 331 580 L 370 510 M 393 580 L 475 475 M 456 580 L 475 475 M 518 580 L 475 475 M 580 518 L 475 475 M 370 510 L 143 72.5 M 144 20 L 213 423 M 230 370 L 493 143 M 580 144 L 493 143 M 510 90 L 247 177 M 195 195 L 247 177 M 265 125 L 527 457 M 580 518 L 177 107 M 195 195 L 177 107 M 265 125 L 177 107 M 143 72.5 L 169 361 M 160 440 L 169 361 M 213 423 L 169 361 M 107 317 L 449 81.3 M 440 160 L 449 81.3 M 493 143 L 309 501 M 370 510 L 379 431 M 370 510 L 63.7 466 M 20 393 L 63.7 466 M 20 518 L 274 256 M 247 177 L 134 396 M 160 440 L 134 396 M 107 317 L 414 116 M 440 160 L 151 169 M 177 107 L 431 449 M 370 510 L 291 309 M 230 370 L 501 239 M 580 207 L 501 239 M 440 160 L 501 239 M 493 143 L 361 379 M 230 370 L 256 63.7 M 177 107 L 116 484 M 63.7 466 L 396 204 M 440 160 L 326 134 M 335 55 L 326 134 M 265 125 L 326 134 M 344 186 L 186 274 M 169 361 L 243 269 M 195 195 L 243 269 M 274 256 L 243 269 M 291 309 L 243 269 M 186 274 L 103 409 M 20 393 L 103 409 M 160 440 L 103 409 M 55 335 L 103 409 M 107 317 L 103 409 M 116 484 L 383 129 M 335 55 L 383 129 M 344 186 L 383 129 M 414 116 L 383 129 M 396 204 L 313 199 M 265 125 L 313 199 M 317 247 L 313 199 M 344 186 L 313 199 M 274 256 L 173 59.4 M 207 20 L 173 59.4 M 143 72.5 L 173 59.4 M 256 63.7 L 138 94.4 M 177 107 L 208 304 M 291 309 L 208 304 M 186 274 L 348 444 M 283 493 L 348 444 M 213 423 L 348 444 M 309 501 L 348 444 M 379 431 L 348 444 M 361 379 L stroke grestore gsave 0.1 setlinewidth 0.0 setgray 20.000 20.000 (2) radius drawLabel 82.222 20.000 (2) radius drawLabel 144.444 20.000 (0) radius drawLabel 206.667 20.000 (4) radius drawLabel 268.889 20.000 (4) radius drawLabel 331.111 20.000 (4) radius drawLabel 393.333 20.000 (4) radius drawLabel 455.556 20.000 (4) radius drawLabel 517.778 20.000 (4) radius drawLabel 580.000 20.000 (4) radius drawLabel 20.000 580.000 (3) radius drawLabel 82.222 580.000 (3) radius drawLabel 144.444 580.000 (3) radius drawLabel 206.667 580.000 (3) radius drawLabel 268.889 580.000 (3) radius drawLabel 331.111 580.000 (3) radius drawLabel 393.333 580.000 (3) radius drawLabel 455.556 580.000 (0) radius drawLabel 517.778 580.000 (0) radius drawLabel 580.000 580.000 (5) radius drawLabel 20.000 82.222 (2) radius drawLabel 20.000 144.444 (2) radius drawLabel 20.000 206.667 (2) radius drawLabel 20.000 268.889 (2) radius drawLabel 20.000 331.111 (2) radius drawLabel 20.000 393.333 (2) radius drawLabel 20.000 455.556 (0) radius drawLabel 20.000 517.778 (3) radius drawLabel 580.000 82.222 (4) radius drawLabel 580.000 144.444 (4) radius drawLabel 580.000 206.667 (0) radius drawLabel 580.000 268.889 (1) radius drawLabel 580.000 331.111 (1) radius drawLabel 580.000 393.333 (1) radius drawLabel 580.000 455.556 (1) radius drawLabel 580.000 517.778 (0) radius drawLabel 300.000 300.000 (1) radius drawLabel 160.000 440.000 (3) radius drawLabel 440.000 160.000 (0) radius drawLabel 230.000 370.000 (0) radius drawLabel 510.000 90.000 (4) radius drawLabel 90.000 230.000 (2) radius drawLabel 370.000 510.000 (0) radius drawLabel 195.000 195.000 (2) radius drawLabel 475.000 475.000 (1) radius drawLabel 55.000 335.000 (2) radius drawLabel 335.000 55.000 (4) radius drawLabel 125.000 545.000 (3) radius drawLabel 405.000 265.000 (1) radius drawLabel 265.000 125.000 (4) radius drawLabel 545.000 405.000 (1) radius drawLabel 282.503 492.503 (3) radius drawLabel 142.503 72.500 (2) radius drawLabel 422.503 352.503 (1) radius drawLabel 72.500 282.503 (2) radius drawLabel 212.503 422.503 (3) radius drawLabel 492.503 142.503 (0) radius drawLabel 107.497 317.497 (2) radius drawLabel 247.497 177.497 (0) radius drawLabel 527.497 457.497 (1) radius drawLabel 177.497 107.497 (0) radius drawLabel 457.497 387.497 (1) radius drawLabel 317.497 247.497 (1) radius drawLabel 168.748 361.252 (0) radius drawLabel 448.748 81.250 (4) radius drawLabel 308.748 501.252 (3) radius drawLabel 98.748 151.252 (2) radius drawLabel 378.748 431.252 (1) radius drawLabel 518.748 291.252 (1) radius drawLabel 63.750 466.252 (0) radius drawLabel 343.748 186.252 (1) radius drawLabel 483.748 326.252 (1) radius drawLabel 273.748 256.252 (1) radius drawLabel 133.748 396.252 (0) radius drawLabel 413.748 116.252 (4) radius drawLabel 151.252 168.748 (2) radius drawLabel 431.252 448.748 (1) radius drawLabel 291.252 308.748 (1) radius drawLabel 221.252 518.748 (3) radius drawLabel 501.252 238.748 (1) radius drawLabel 81.250 98.748 (2) radius drawLabel 361.252 378.748 (1) radius drawLabel 256.252 63.750 (4) radius drawLabel 536.252 343.748 (1) radius drawLabel 116.252 483.748 (3) radius drawLabel 396.252 203.748 (1) radius drawLabel 326.252 133.748 (0) radius drawLabel 186.252 273.748 (2) radius drawLabel 243.123 269.374 (0) radius drawLabel 103.123 409.374 (0) radius drawLabel 383.123 129.374 (0) radius drawLabel 313.123 199.374 (0) radius drawLabel 173.123 59.375 (0) radius drawLabel 453.123 339.374 (1) radius drawLabel 138.123 94.374 (2) radius drawLabel 418.123 374.374 (1) radius drawLabel 278.123 514.374 (3) radius drawLabel 208.123 304.374 (0) radius drawLabel 68.125 164.374 (2) radius drawLabel 348.123 444.374 (0) radius drawLabel grestore showpage269 580 L 221 519 M 160 440 L 221 519 M 125 545 L 221 5misc/doc/drivers.tex010064400020550007177000000544420657406563000160150ustar00clevecompmath00000400000006\par \section{Driver programs found in the {\tt Misc} directory} \label{section:Misc:drivers} \par This section contains brief descriptions of the driver programs. \par %======================================================================= \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} testNDperm msglvl msgFile n1 n2 n3 outPermFile \end{verbatim} This driver program generates a {\tt Perm} object that contains a nested dissection ordering for a {\tt n1 x n2 x n3} regular grid. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt Perm} object is written to the output file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt n1} is the number of points in the first direction. \item {\tt n2} is the number of points in the second direction. \item {\tt n3} is the number of points in the third direction. \item The {\tt outPermFile} parameter is the output file for the {\tt Perm} object. If {\tt outPermFile} is {\tt none} then the {\tt Perm} object is not written to a file. Otherwise, the {\tt Perm\_writeToFile()} method is called to write the object to a formatted file (if {\tt outPermFile} is of the form {\tt *.permf}), or a binary file (if {\tt outPermFile} is of the form {\tt *.permb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testOrderViaMMD msglvl msgFile GraphFile seed ETreeFile \end{verbatim} This program reads in a {\tt Graph} object from a file and computes a multiple minimum degree ordering of the graph. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt Perm} object is written to the output file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt seed} parameter is a random number seed. \item The {\tt ETreeFile} parameter is the output file for the {\tt ETree} object. If {\tt ETreeFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt ETreeFile} is of the form {\tt *.etreef}), or a binary file (if {\tt ETreeFile} is of the form {\tt *.etreeb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testOrderViaND msglvl msgFile GraphFile maxdomainsize seed ETreeFile \end{verbatim} This program reads in a {\tt Graph} object from a file and computes a generalized nested dissection ordering of the graph. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt Perm} object is written to the output file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt maxdomainsize} parameter governs the partition of a graph. If a subgraph has more than {\tt maxdomainsize} vertices, it is split. \item The {\tt seed} parameter is a random number seed. \item The {\tt ETreeFile} parameter is the output file for the {\tt ETree} object. If {\tt ETreeFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt ETreeFile} is of the form {\tt *.etreef}), or a binary file (if {\tt ETreeFile} is of the form {\tt *.etreeb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} testOrderViaMS msglvl msgFile GraphFile maxdomainsize seed ETreeFile \end{verbatim} This program reads in a {\tt Graph} object from a file and computes a multisection ordering of the graph. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt Perm} object is written to the output file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt maxdomainsize} parameter governs the partition of a graph. If a subgraph has more than {\tt maxdomainsize} vertices, it is split. \item The {\tt seed} parameter is a random number seed. \item The {\tt ETreeFile} parameter is the output file for the {\tt ETree} object. If {\tt ETreeFile} is {\tt none} then the {\tt ETree} object is not written to a file. Otherwise, the {\tt ETree\_writeToFile()} method is called to write the object to a formatted file (if {\tt ETreeFile} is of the form {\tt *.etreef}), or a binary file (if {\tt ETreeFile} is of the form {\tt *.etreeb}). \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} drawGraph msglvl msgFile inGraphFile inCoordsFile inTagsIVfile outEPSfile linewidth1 linewidth2 bbox[4] rect[4] radius \end{verbatim} This driver program generates a Encapsulated Postscript file {\tt outEPSfile} of a 2-D graph using a {\tt Graph} object, a {\tt Coords} object and a tags {\tt IV} object that contains the component ids of the vertices. \par See the {\tt doDraw} script file in this directory for an example calling sequence. \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means that all objects are written to the output file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt inGraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt inCoordsFile} parameter is the input file for the {\tt Coords} object. It must be of the form {\tt *.coordsf} or {\tt *.coordsb}. The {\tt Coords} object is read from the file via the {\tt Coords\_readFromFile()} method. \item The {\tt inTagsIVfile} parameter is the input file for the tags {\tt IV} object. It must be of the form {\tt 'none'}, {\tt *.ivf} or {\tt *.ivb}. The {\tt IV} object is read from the file via the {\tt IV\_readFromFile()} method. \item The {\tt outEPSfile} parameter is the output file for the Encapsulated Postscript file. \item The {\tt linewidth1} parameter governs the linewidth of edges between vertices in the same component. \item The {\tt linewidth2} parameter governs the linewidth of edges between vertices in different components. \item The {\tt bbox[4]} array is the bounding box for the plot. In Postscript the coordinates are in {\it points}, where there are 72 points per inch. For example, a bounding box of {\tt 0 0 200 300} will create a plot whose size is 2.78 inches by 4.17 inches. \item The {\tt rect[4]} array is the enclosing rectangle for the plot. To put a 20 point margin around the plot, set {\tt rect[0] = bbox[0] + 20}, {\tt rect[1] = bbox[1] + 20}, {\tt rect[2] = bbox[2] - 20} and {\tt rect[3] = bbox[3] - 20}. \item The {\tt radius} parameter governs the size of the filled circle that is centered on each vertex. The dimension is in points. \end{itemize} See Figure~\ref{fig-R2D100} for a plot of the graph of {\tt R2D100}, a randomly triangulated grid with 100 vertices with {\tt linewidth1 = 3}. Figure~\ref{fig-R2D100-fishnet} illustrates a domain decomposition obtained from the fishnet algorithm of Chapter~\ref{chapter:GPart:intro} with {\tt linewidth1 = 3} and {\tt linewidth2 = 0.1}. \par \begin{figure}[htbp] \caption{{\sc R2D100}} \label{fig-R2D100} \begin{center} \mbox{ % \psfig{file=R2D100notags.eps,height=4.00in,width=4.00in} \psfig{file=../../misc/doc/R2D100notags.eps,height=4.00in,width=4.00in} } \end{center} \end{figure} \par \begin{figure}[htbp] \caption{{\sc R2D100: fishnet domain decomposition}} \label{fig-R2D100-fishnet} \begin{center} \mbox{ % \psfig{file=R2D100fishnet.eps,height=4.00in,width=4.00in} \psfig{file=../../misc/doc/R2D100fishnet.eps,height=4.00in,width=4.00in} } \end{center} \end{figure} %----------------------------------------------------------------------- \item \begin{verbatim} testSemi msglvl msgFile GraphFile ETreeFile mapFile \end{verbatim} This program is used to compute the effect of using a semi-implicit factorization to solve $$ AX = \left \lbrack \begin{array}{cc} A_{0,0} & A_{0,1} \cr A_{1,0} & A_{1,1} \end{array} \right \rbrack \left \lbrack \begin{array}{c} X_0 \cr X_1 \end{array} \right \rbrack = \left \lbrack \begin{array}{c} B_0 \cr B_1 \end{array} \right \rbrack = B. $$ $A$ is factored as $$ \left \lbrack \begin{array}{cc} A_{0,0} & A_{0,1} \cr A_{1,0} & A_{1,1} \end{array} \right \rbrack = \left \lbrack \begin{array}{cc} L_{0,0} & 0 \cr L_{1,0} & L_{1,1} \end{array} \right \rbrack \left \lbrack \begin{array}{cc} U_{0,0} & U_{0,1} \cr 0 & U_{1,1} \end{array} \right \rbrack, $$ and to solve $AX = B$, we do the following steps. \begin{itemize} \item solve $L_{0,0} Y_0 = B_0$ \item solve $L_{1,1} U_{1,1} X_1 = B_1 - L_{1,0} Y_0$ \item solve $U_{0,0} X_0 = Y_0 - U_{0,1} X_1$ \end{itemize} An alternative factorization is $$ A = \left \lbrack \begin{array}{cc} L_{0,0} & 0 \cr A_{1,0}U_{0,0}^{-1} & L_{1,1} \end{array} \right \rbrack \left \lbrack \begin{array}{cc} U_{0,0} & L_{0,0}^{-1}U_{0,1} \cr 0 & U_{1,1} \end{array} \right \rbrack. $$ To solve $AX = B$, we do the following {\it semi-implicit solve}. \begin{itemize} \item solve $L_{0,0} U_{0,0} Z_0 = B_0$ \item solve $L_{1,1} U_{1,1} X_1 = B_1 - A_{1,0} Z_0$ \item solve $L_{0,0} U_{0,0} X_0 = B_0 - A_{0,1} X_1$ \end{itemize} When we compare the semi-implicit solve against the explicit solve, we see that the former needs $A_{0,1}$ and $A_{1,0}$ but not $L_{1,0}$ or $A_{0,1}$. and executes two solves with $L_{0,0}$ and $U_{0,0}$ (instead of one) and performs a matrix-matrix multiply with $A_{0,1}$ and $A_{1,0}$ instead of $L_{1,0}$ and $U_{0,1}$. In situations where the numbers of entries in $L_{1,0}$ and $U_{0,1}$ are much larger than those in $A_{1,0}$ and $A_{0,1}$, and the numbers of entries in $L_{0,0}$ and $U_{0,0}$ are not too large, the semi-implicit factorization can be more efficient. \par This program reads in three objects: a {\tt Graph} object, an {\tt ETree} object to specify the ordering, and an {\tt IV} map object that tells which vertices are in the which blocks of the matrix. The map from vertices to blocks follows the same convention as the {\it component map} from the {\tt GPart} object. If {\tt map[v] = 0}, then vertex {\tt v} belongs to the Schur complement $(1,1)$ block. Otherwise, {\tt v} belongs to a domain (the domain number is {\tt map[v]}) and so belongs to the $(0,0)$ block. The output of the program gives statistics for storage and operation count for the two types of solves. For example, \begin{verbatim} storage: explicit = 1404, semi-implicit = 1063, ratio = 1.321 opcount: explicit = 2808, semi-implicit = 2742, ratio = 1.024 \end{verbatim} is the output using the {\tt do\_testSemi} driver program for the {\tt R2D100} matrix. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt GraphFile} parameter is the input file for the {\tt Graph} object. It must be of the form {\tt *.graphf} or {\tt *.graphb}. The {\tt Graph} object is read from the file via the {\tt Graph\_readFromFile()} method. \item The {\tt ETreeFile} parameter is the input file for the {\tt ETree} object. It must be of the form {\tt *.etreef} or {\tt *.etreeb}. The {\tt ETree} object is read from the file via the {\tt ETree\_readFromFile()} method. \item The {\tt mapFile} parameter is the input file for the map {\tt IV} object. It must be of the form {\tt *.ivf} or {\tt *.ivb}. The {\tt IV} object is read from the file via the {\tt IV\_readFromFile()} method. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} allInOne msglvl msgFile type symmetryflag pivotingflag matrixFileName rhsFileName seed \end{verbatim} This {\it all-in-one} driver program is an example that tests the serial $U^TDU$, $U^HDU$ or $LU$ factorization and solve. Matrix entries are read in from a file, and then the matrix is assembled and factored. The right hand side entries are read in from a file, and the system is solved. Three input parameters specify the type of system (real or complex), the type of factorization (symmetric, Hermitian or nonsymmetric) and whether pivoting is to be used for numerical stability. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt Perm} object is written to the output file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt type} is the type of entries \begin{itemize} \item {\tt 1} --- ({\tt SPOOLES\_REAL}) for real entries \item {\tt 2} --- ({\tt SPOOLES\_COMPLEX}) for complex entries \end{itemize} \item {\tt symmetryflag} defines the factorization \begin{itemize} \item {\tt 0} --- ({\tt SPOOLES\_SYMMETRIC}) for a real or complex $U^TDU$ factorization \item {\tt 1} --- ({\tt SPOOLES\_SYMMETRIC}) for a complex $U^HDU$ factorization \item {\tt 2} --- ({\tt SPOOLES\_SYMMETRIC}) for a real or complex $LU$ factorization \end{itemize} \item {\tt pivotingflag} defines pivoting or not for numerical stability \begin{itemize} \item {\tt 0} --- ({\tt SPOOLES\_NO\_PIVOTING}) for no pivoting \item {\tt 1} --- ({\tt SPOOLES\_PIVOTING}) for pivoting \end{itemize} Note, the code has a pivoting threshold {\tt tau = 100} hardwired into the code. \item The {\tt matrixFileName} parameter is the name of the input file for the matrix entries. For a real matrix, this file must have the following form. \begin{verbatim} nrow ncol nent ... irow jcol value ... \end{verbatim} where the first line has the number of rows, columns and entries. (Note, for this driver program {\tt nrow} must be equal to {\tt ncol} since we are factoring a square matrix.) Each of the {\tt nent} following lines contain one nonzero entry. For a complex matrix, the file has this structure. \begin{verbatim} nrow ncol nent ... irow jcol real_value imag_value ... \end{verbatim} For both real and complex entries, the entries need not be disjoint, i.e., entries with the same {\tt irow} and {\tt jcol} values are {\it summed}. \item The {\tt rhsFileName} parameter is the name of the input file for the right hand side matrix. It has the following structure \begin{verbatim} nrow nrhs ... irow value_0 value_1 ... value_\{nrhs-1\} ... \end{verbatim} Note, {\tt nrow} need not be the number of equations, here it is the number of nonzero right hand side entries. This allows us to input sparse right hand sides without specifying the zeroes. In contrast to the input for the matrix entries, the nonzero rows {\it must} be unique. The right hand side entries are not assembled into a dense matrix object, but placed into the object. \item {\tt seed} is a random number seed used for the ordering process. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} patchAndGo msglvl msgFile type symmetryflag patchAndGoFlag fudge toosmall storeids storevalues matrixFileName rhsFileName seed \end{verbatim} This driver program is used to test the ``patch-and-go'' functionality for a factorization without pivoting. When small diagonal pivot elements are found, one of three actions are taken. See the {\tt PatchAndGoInfo} object for more information. \par The program reads in a matrix $A$ and right hand side $B$, generates the graph for $A$ and orders the matrix, factors $A$ and solves the linear system $AX = B$ for $X$ using multithreaded factors and solves. Use the script file {\tt do\_patchAndGo} for testing. \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output. Use {\tt msglvl = 1} for just timing output. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt type} parameter specifies a real or complex linear system. \begin{itemize} \item {\tt type = 1 (SPOOLES\_REAL)} for real, \item {\tt type = 2 (SPOOLES\_COMPLEX)} for complex. \end{itemize} \item The {\tt symmetryflag} parameter specifies the symmetry of the matrix. \begin{itemize} \item {\tt type = 0 (SPOOLES\_SYMMETRIC)} for $A$ real or complex symmetric, \item {\tt type = 1 (SPOOLES\_HERMITIAN)} for $A$ complex Hermitian, \item {\tt type = 2 (SPOOLES\_NONSYMMETRIC)} \end{itemize} for $A$ real or complex nonsymmetric. \item The {\tt patchAndGoFlag} specifies the ``patch-and-go'' strategy. \begin{itemize} \item {\tt patchAndGoFlag = 0} --- if a zero pivot is detected, stop computing the factorization, set the error flag and return. \item {\tt patchAndGoFlag = 1} --- if a small or zero pivot is detected, set the diagonal entry to 1 and the offdiagonal entries to zero. \item {\tt patchAndGoFlag = 2} --- if a small or zero pivot is detected, perturb the diagonal entry. \end{itemize} \item The {\tt fudge} parameter is used to perturb a diagonal entry. \item The {\tt toosmall} parameter is judge when a diagonal entry is small. \item If {\tt storeids = 1}, then the locations where action was taken is stored in an {\tt IV} object. \item If {\tt storevalues = 1}, then the perturbations are stored in an {\tt DV} object. \item The {\tt matrixFileName} parameter is the name of the files where the matrix entries are read from. The file has the following structure. \begin{verbatim} neqns neqns nent irow jcol entry ... ... ... \end{verbatim} where {\tt neqns} is the global number of equations and {\tt nent} is the number of entries in this file. There follows {\tt nent} lines, each containing a row index, a column index and one or two floating point numbers, one if real, two if complex. \item The {\tt rhsFileName} parameter is the name of the files where the right hand side entries are read from. The file has the following structure. \begin{verbatim} nrow nrhs irow entry ... entry ... ... ... ... \end{verbatim} where {\tt nrow} is the number of rows in this file and {\tt nrhs} is the number of rigght and sides. There follows {\tt nrow} lines, each containing a row index and either {\tt nrhs} or {\tt 2*nrhs} floating point numbers, the first if real, the second if complex. \item The {\tt seed} parameter is a random number seed. \end{itemize} %----------------------------------------------------------------------- \item \begin{verbatim} QRallInOne msglvl msgFile type matrixFileName rhsFileName seed \end{verbatim} This {\it all-in-one} driver program is an example that tests the serial $QR$ factorization and solve. Matrix entries are read in from a file, and then the matrix is assembled and factored. The right hand side entries are read in from a file, and the system is solved. One input parameter specifies the type of system (real or complex). \par \begin{itemize} \item The {\tt msglvl} parameter determines the amount of output --- taking {\tt msglvl >= 3} means the {\tt Perm} object is written to the output file. \item The {\tt msgFile} parameter determines the message file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item {\tt type} is the type of entries \begin{itemize} \item {\tt 1} --- ({\tt SPOOLES\_REAL}) for real entries \item {\tt 2} --- ({\tt SPOOLES\_COMPLEX}) for complex entries \end{itemize} \item The {\tt matrixFileName} parameter is the name of the input file for the matrix entries. For a real matrix, this file must have the following form. \begin{verbatim} nrow ncol nent ... irow jcol value ... \end{verbatim} where the first line has the number of rows, columns and entries. Each of the {\tt nent} following lines contain one nonzero entry. For a complex matrix, the file has this structure. \begin{verbatim} nrow nrhs nent ... irow jcol real_value imag_value ... \end{verbatim} For both real and complex entries, the entries need not be disjoint, i.e., entries with the same {\tt irow} and {\tt jcol} values are {\it summed}. \item The {\tt rhsFileName} parameter is the name of the input file for the right hand side matrix. It has the following structure \begin{verbatim} nrow nrhs ... irow value_0 value_1 ... value_\{nrhs-1\} ... \end{verbatim} Note, {\tt nrow} need not be the number of equations, here it is the number of nonzero right hand side entries. This allows us to input sparse right hand sides without specifying the zeroes. In contrast to the input for the matrix entries, the nonzero rows {\it must} be unique. The right hand side entries are not assembled into a dense matrix object, but placed into the object. \item {\tt seed} is a random number seed used for the ordering process. \end{itemize} %----------------------------------------------------------------------- \end{enumerate} essage file --- if {\tt msgFile} is {\tt stdout}, then the message file is {\it stdout}, otherwise a file is opened with {\it append} status to receive any output data. \item The {\tt GraphFile} parameter is the input filemisc/doc/intro.tex010064400020550007177000000011700654057140100154470ustar00clevecompmath00000400000006\par \chapter{{\tt Misc} directory} \label{chapter:Misc} \par This directory contains a number of miscellaneous functions and driver programs that don't really fit anywhere else. There are functions to generate nested dissection orderings on regular 2-D and 3-D grids --- the usual nested dissection, with double wide separators, and local nested dissection \cite{bha93-localND}. There are wrapper methods for minimum degree, nested dissection and multisection orderings for general graphs. There is also a driver program to produce a postscript file for a 2-D graph, very useful for visualizing graph partitionings and orderings. misc/doc/main.tex010064400020550007177000000010630665065633600152560ustar00clevecompmath00000400000006% % main TeX file % \documentclass[leqno,11pt,twoside]{report} \textwidth 6.5 in \textheight 8.5 in \oddsidemargin 0.0 in \evensidemargin 0.0 in \topmargin 0.0 in \baselineskip 20 pt \parskip 3 pt plus 1 pt minus 1 pt \makeindex \input psfig \begin{document} \pagestyle{myheadings} \markboth {\quad \hrulefill \quad {\tt Misc} : {\it DRAFT} \today \quad \hrulefill} {\quad \hrulefill \quad {\tt Misc} : {\it DRAFT} \quad \today \hrulefill} \par \input intro.tex \input proto.tex \input drivers.tex \input main.ind \end{document} misc/doc/proto.tex010064400020550007177000000433240665023152300154660ustar00clevecompmath00000400000006\par \section{Prototypes and descriptions of methods in the {\tt Misc} directory} \label{section:Misc:proto} \par This section contains brief descriptions including prototypes of all methods in the {\tt Misc} directory. \par %======================================================================= \subsection{Theoretical nested dissection methods} \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void mkNDperm ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) ; \end{verbatim} \index{mkNDperm@{\tt mkNDperm()}} This method this vector fills a permutation vector with the nested dissection new-to-old ordering of the vertices for the subgrid defined by nodes whose coordinates lie in \begin{verbatim} [west, east] x [south, north] x [bottom, top]. \end{verbatim} The method calls itself recursively. To find the permutation for an {\tt n1 x n2 x n3} grid, call \begin{verbatim} mkNDperm(n1, n2, n3, newToOld, 0, n1-1, 0, n2-1, 0, n3-1) ; \end{verbatim} from a driver program. \par \noindent {\it Error checking:} If {\tt n1}, {\tt n2} or {\tt n3} are less than or equal to zero, or if {\tt newToOld} is {\tt NULL}, or if {\tt west}, {\tt south} or {\tt bottom} are less than or equal to zero, of if ${\tt east} \ge {\tt n1}$, of if ${\tt north} \ge {\tt n2}$, of if ${\tt top} \ge {\tt n3}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void mkNDperm2 ( int n1, int n2, int n3, int newToOld[], int west, int east, int south, int north, int bottom, int top ) ; \end{verbatim} \index{mkNDperm2@{\tt mkNDperm2()}} This method this vector fills a permutation vector with the nested dissection new-to-old ordering of the vertices for the subgrid defined by nodes whose coordinates lie in \begin{verbatim} [west, east] x [south, north] x [bottom, top]. \end{verbatim} There is one important difference between this method and {\tt mkNDperm()} above; this method finds {\it double-wide} separators, necessary for an operator with more than nearest neighbor grid point coupling. The method calls itself recursively. To find the permutation for an {\tt n1 x n2 x n3} grid, call \begin{verbatim} mkNDperm(n1, n2, n3, newToOld, 0, n1-1, 0, n2-1, 0, n3-1) ; \end{verbatim} from a driver program. \par \noindent {\it Error checking:} If {\tt n1}, {\tt n2} or {\tt n3} are less than or equal to zero, or if {\tt newToOld} is {\tt NULL}, or if {\tt west}, {\tt south} or {\tt bottom} are less than or equal to zero, of if ${\tt east} \ge {\tt n1}$, of if ${\tt north} \ge {\tt n2}$, of if ${\tt top} \ge {\tt n3}$, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void localND2D ( int n1, int n2, int p1, int p2, int dsizes1[], int dsizes2[], int oldToNew[] ) ; \end{verbatim} \index{localND2D@{\tt localND2D()}} This method finds a local nested dissection ordering \cite{bha93-localND} for an {\tt n1 x n2} 2-D grid. There are {\tt p1 x p2} domains in the grid. The {\tt dsizes1[]} and {\tt dsizes2[]} vectors are optional; they allow the user to explicitly input domain sizes. If {\tt dsizes1[]} and {\tt dsizes2[]} are not {\tt NULL}, the {\tt q = q1 + q2*p1}'th domain contains a {\tt dsizes1[q1] x dsizes2[q2]} subgrid of points. \par \noindent {\it Error checking:} If {\tt n1} or {\tt n2} are less than or equal to zero, or if {\tt p1} or {\tt p2} are less than or equal to zero, or if $2{\tt p1} - 1 > {\tt n1}$, or if $2{\tt p2} - 1 > {\tt n2}$, or if {\tt oldToNew} is {\tt NULL}, or if {\tt dsizes1[]} and {\tt dsizes2[]} are not {\tt NULL} but have invalid entries (all entries must be positive, entries in {\tt dsizes1[]} must sum to {\tt n1 - p1 + 1}, and entries in {\tt dsizes2[]} must sum to {\tt n2 - p2 + 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void localND3D ( int n1, int n2, int n3, int p1, int p2, int p3, int dsizes1[], int dsizes2[], int dsizes3[], int oldToNew[] ) ; \end{verbatim} \index{localND3D@{\tt localND3D()}} This method finds a local nested dissection ordering \cite{bha93-localND} for an {\tt n1 x n2 x n3} 3-D grid. There are {\tt p1 x p2 x p3} domains in the grid. The {\tt q}'th domain contains a {\tt dsizes1[q] x dsizes2[q] x dsizes3[q]} subgrid of points. The {\tt dsizes1[]}, {\tt dsizes2[]} and {\tt dsizes3[]} vectors are optional; they allow the user to explicitly input domain sizes. If {\tt dsizes1[]}, {\tt dsizes2[]} and {\tt dsizes3[]} are not {\tt NULL}, the {\tt q = q1 + q2*p1+ q3*p1*p2}'th domain contains a {\tt dsizes1[q1] x dsizes2[q2] x disizes3[q3]} subgrid of points. \par \noindent {\it Error checking:} If {\tt n1}, {\tt n2} or {\tt n3} are less than or equal to zero, or if {\tt p1}, {\tt p2} or {\tt p3} are less than or equal to zero, or if $2{\tt p1} - 1 > {\tt n1}$, or if $2{\tt p2} - 1 > {\tt n2}$, or if $2{\tt p3} - 1 > {\tt n3}$, or if {\tt oldToNew} is {\tt NULL}, or if {\tt dsizes1[]}, {\tt disizes2[]} and {\tt dsizes3[]} are not {\tt NULL} but have invalid entries (all entries must be positive, entries in {\tt dsizes1[]} must sum to {\tt n1 - p1 + 1}, entries in {\tt dsizes2[]} must sum to {\tt n2 - p2 + 1}, and entries in {\tt dsizes3[]} must sum to {\tt n3 - p3 + 1}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void fp2DGrid ( int n1, int n2, int ivec[], FILE *fp ) ; \end{verbatim} \index{fp2DGrid@{\tt fp2DGrid()}} This method writes the {\tt ivec[]} vector onto an {\tt n1 x n2} grid to file {\tt fp}. This is useful to visualize an ordering or a metric on a grid. \par \noindent {\it Error checking:} If {\tt n1} or {\tt n2} are less than or equal to zero, or if {\tt ivec} or {\tt fp} are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} void fp3DGrid ( int n1, int n2, int n3, int ivec[], FILE *fp ) ; \end{verbatim} \index{fp3DGrid@{\tt fp3DGrid()}} This method writes the {\tt ivec[]} vector onto an {\tt n1 x n2 x n3} grid to file {\tt fp}. This is useful to visualize an ordering or a metric on a grid. \par \noindent {\it Error checking:} If {\tt n1}, {\tt n2} or {\tt n3} are less than or equal to zero, or if {\tt ivec} or {\tt fp} are {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par %======================================================================= \subsection{Multiple minimum degree, Nested dissection and multisection wrapper methods} \par There are three simple methods to find minimum degree, nested dissection and multisection orderings. In addition, there is one method that finds the better of two methods -- nested dissection and multisection. (Much of the work to find either nested dissection or multisection is identical, so this method takes little more time than either of the two separately.) \par To properly specify these methods there are many parameters --- these three wrapper methods insulate the user from all but one or two of the parameters. As a result, the quality of the ordering may not be as good as can be found by using non-default settings of the parameters. \par One wrapper method computes a minimum degree ordering --- the only input parameter is a random number seed. Two wrappers methods compute the nested dissection and multisection orderings --- in addition to a random number seed there is a upper bound on the subgraph size used during the graph partition. This is the most sensitive of the parameters. \par The user interested in more customized orderings should consult the chapters on the the {\tt GPart}, {\tt DSTree} and {\tt MSMD} objects that perform the three steps of the ordering process: perform an incomplete nested dissection of the graph, construct the map from vertices to stages in which they will be eliminated, and perform the multi-stage minimum degree ordering. The driver programs in the {\tt GPart} and {\tt MSMD} directories fully exercise the graph partition and ordering strategies by giving the user access to all input parameters. \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} ETree * orderViaMMD ( Graph *graph, int seed, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{orderViaMMD@{\tt orderViaMMD()}} This method returns a front tree {\tt ETree} object for a multiple minimum degree ordering of the graph {\tt graph}. The {\tt seed} parameter is a random number seed. The {\tt msglvl} and {\tt msgFile} parameters govern the diagnostics output. Use {\tt msglvl = 0} for no output, {\tt msglvl = 1} for timings and scalar statistics, and use {\tt msglvl > 1} with care, for it can generate huge amounts of output. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ETree * orderViaND ( Graph *graph, int maxdomainsize, int seed, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{orderViaND@{\tt orderViaND()}} This method returns a front tree {\tt ETree} object for a nested dissection ordering of the graph {\tt graph}. If a subgraph has more vertices than the {\tt maxdomainsize} parameter, it is split. The {\tt seed} parameter is a random number seed. The {\tt msglvl} and {\tt msgFile} parameters govern the diagnostics output. Use {\tt msglvl = 0} for no output, {\tt msglvl = 1} for timings and scalar statistics, and use {\tt msglvl > 1} with care, for it can generate huge amounts of output. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, or if ${\tt maxdomainsize} \le 0$, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ETree * orderViaMS ( Graph *graph, int maxdomainsize, int seed, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{orderViaMS@{\tt orderViaMS()}} This method returns a front tree {\tt ETree} object for a multisection ordering of the graph {\tt graph}. If a subgraph has more vertices than the {\tt maxdomainsize} parameter, it is split. The {\tt seed} parameter is a random number seed. The {\tt msglvl} and {\tt msgFile} parameters govern the diagnostics output. Use {\tt msglvl = 0} for no output, {\tt msglvl = 1} for timings and scalar statistics, and use {\tt msglvl > 1} with care, for it can generate huge amounts of output. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, or if ${\tt maxdomainsize} \le 0$, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \item \begin{verbatim} ETree * orderViaBestOfNDandMS ( Graph *graph, int maxdomainsize, int maxzeros, int maxsize, int seed, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{orderViaBestOfNDandMS@{\tt orderViaBestOfNDandMS()}} This method returns a front tree {\tt ETree} object for a better of two orderings, a nested dissection and multisection ordering. If a subgraph has more vertices than the {\tt maxdomainsize} parameter, it is split. The {\tt seed} parameter is a random number seed. This method also transforms the front tree using the {\tt maxzeros} and {\tt maxsize} parameters. See the {\tt ETree\_transform()} method in Section~\ref{subsection:ETree:proto:transformation}. The {\tt msglvl} and {\tt msgFile} parameters govern the diagnostics output. Use {\tt msglvl = 0} for no output, {\tt msglvl = 1} for timings and scalar statistics, and use {\tt msglvl > 1} with care, for it can generate huge amounts of output. \par \noindent {\it Error checking:} If {\tt graph} is {\tt NULL}, or if ${\tt maxdomainsize} \le 0$, or if {\tt msglvl > 0} and {\tt msgFile} is {\tt NULL}, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par %======================================================================= \subsection{Graph drawing method} \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void drawGraphEPS ( Graph *graph, Coords *coords, IV *tagsIV, double bbox[4], double rect[4], double linewidth1, double linewidth2, double radius, char *epsFileName, int msglvl, FILE *msgFile ) ; \end{verbatim} \index{drawGraphEPS@{\tt drawGraphEPS()}} This method is used to create an EPS (Encapsulated Postscript) file that contains a picture of a graph in two dimensions. We use this to visualize separators and domain decompositions, mostly of regular grids and triangulations of a planar region. \par The {\tt graph} object defines the connectivity of the vertices. The {\tt coords} object defines the locations of the vertices. The {\tt tagsIV} object is used to define whether or not an edge is drawn between two vertices adjacent in the graph. When {\tt tagsIV} is not {\tt NULL}, if there is an edge {\tt (u,v)} in the graph and {\tt tags[u] = tags[v]}, then the edge with width {\tt linewidth1} is drawn. For edges {\tt (u,v)} in the graph and {\tt tags[u] != tags[v]}, then the edge with width {\tt linewidth2} is drawn, assuming ${\tt linewidth2} > 0$. If {\tt tagsIV} is {\tt NULL}, than all edges are drawn with width {\tt linewidth1}. Each vertex is draw with a filled circle with radius {\tt radius}. \par The graph and its {\tt Coords} object occupy a certain area in 2-D space. We try to plot the graph inside the area defined by the {\tt rect[]} array in such a manner that the relative scales are preserved (the graph is not stretched in either the $x$ or $y$ direction) and that the larger of the width and height of the graph fills the area defined by the {\tt rect[]} rectangle. {\it Note}: hacking postscript is {\it not} an area of expertise of either author. Some Postscript viewers give us messages that we are not obeying the format conventions (this we do not doubt), but we have never failed to view or print one of these files. \par \noindent {\it Error checking:} If the method is unable to open the file, an error message is printed and the program exits. %----------------------------------------------------------------------- \end{enumerate} \par %======================================================================= \subsection{Linear system construction} \par Our driver programs test linear systems where the matrices come from regular grids using nested dissection orderings. There are two methods that generate linear systems of this form along with the front tree and symbolic factorization. \par \begin{enumerate} %----------------------------------------------------------------------- \item \begin{verbatim} void mkNDlinsys ( int n1, int n2, int n3, int maxzeros, int maxsize, int type, int symmetryflag, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB ) ; \end{verbatim} \index{mkNDlinsys@{\tt mkNDlinsys()}} This method creates a linear system $AX = B$ for a ${\tt n1} \times {\tt n2} \times {\tt n3}$ grid. The entries in $A$ and $X$ are random numbers, $B$ is computed as the product of $A$ with $X$. $A$ can be real ({\tt type = 1}) or complex ({\tt type = 2}), and can be symmetric ({\tt symmetryflag = 0}), Hermitian ({\tt symmetryflag = 1}) or nonsymmetric ({\tt symmetryflag = 2}). The number of columns of $X$ is given by {\tt nrhs}. The linear system is ordered using theoretical nested dissection, and the front tree is transformed using the {\tt maxzeros} and {\tt maxsize} parameters. The addresses of the front tree, symbolic factorization, and three matrix objects are returned in the last five arguments of the calling sequence. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \item \begin{verbatim} void mkNDlinsysQR ( int n1, int n2, int n3, int type, int nrhs, int seed, int msglvl, FILE *msgFile, ETree **pfrontETree, IVL **psymbfacIVL, InpMtx **pmtxA, DenseMtx **pmtxX, DenseMtx **pmtxB ) ; \end{verbatim} \index{mkNDlinsysQR@{\tt mkNDlinsysQR()}} This method creates a linear system $AX = B$ for a natural factor formulation of a ${\tt n1} \times {\tt n2} \times {\tt n3}$ grid. If {\tt n1}, {\tt n2} and {\tt n3} are all greater than 1, the grid is formed of linear hexahedral elements and the matrix $A$ has {\tt 8*n1*n2*n3} rows. If one of {\tt n1}, {\tt n2} and {\tt n3} is equal to 1, the grid is formed of linear quadrilateral elements and the matrix $A$ has {\tt 4*n1*n2*n3} rows. The entries in $A$ and $X$ are random numbers, $B$ is computed as the product of $A$ with $X$. $A$ can be real ({\tt type = 1}) or complex ({\tt type = 2}). The number of columns of $X$ is given by {\tt nrhs}. The linear system is ordered using theoretical nested dissection, and the front tree is transformed using the {\tt maxzeros} and {\tt maxsize} parameters. The addresses of the front tree, symbolic factorization, and three matrix objects are returned in the last five arguments of the calling sequence. \par \noindent {\it Error checking:} None presently. %----------------------------------------------------------------------- \end{enumerate} upper bound on the subgraph size used during the graph partition. This is the most sensitive of the parameters. \par The user interested in more customized orderings should consult the chapters on the the {\tt GPart}, {\tt DSTree} and {\tt MSMD} objects that perform the three steps of the orderingmisc/doc/main.log010064400020550007177000000157210657406567200152470ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=latex 96.6.20) 4 SEP 1998 15:37 **main (main.tex LaTeX2e <1996/06/01> Hyphenation patterns for english, german, loaded. (/usr/local/lib/texmf/tex/latex2e/base/latex209.def File: latex209.def 1996/05/21 v0.51 Standard LaTeX file Entering LaTeX 2.09 compatibility mode. \footheight=\dimen102 \@maxsep=\dimen103 \@dblmaxsep=\dimen104 \@cla=\count79 \@clb=\count80 \mscount=\count81 (/usr/local/lib/texmf/tex/latex2e/base/tracefnt.sty Package: tracefnt 1996/05/08 v3.0h Standard LaTeX package (font tracing) \tracingfonts=\count82 LaTeX Info: Redefining \selectfont on input line 139. ) \symbold=\mathgroup4 \symsans=\mathgroup5 \symtypewriter=\mathgroup6 \symitalic=\mathgroup7 \symsmallcaps=\mathgroup8 \symslanted=\mathgroup9 LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 307. LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 308. LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 309. LaTeX Font Info: Redeclaring math alphabet \mathit on input line 315. LaTeX Info: Redefining \em on input line 325. (/usr/local/lib/texmf/tex/latex2e/base/latexsym.sty Package: latexsym 1995/11/28 v2.2c Standard LaTeX package (lasy symbols) \symlasy=\mathgroup10 LaTeX Font Info: Overwriting symbol font `lasy' in version `bold' (Font) U/lasy/m/n --> U/lasy/b/n on input line 86. ) LaTeX Font Info: Redeclaring math delimiter \lgroup on input line 389. LaTeX Font Info: Redeclaring math delimiter \rgroup on input line 391. LaTeX Font Info: Redeclaring math delimiter \bracevert on input line 393. ) (/usr/local/lib/texmf/tex/latex2e/base/report.cls Document Class: report 1996/05/26 v1.3r Standard LaTeX document class (/usr/local/lib/texmf/tex/latex2e/base/leqno.clo File: leqno.clo 1996/03/25 v1.1a Standard LaTeX option (left equation numbers) ) (/usr/local/lib/texmf/tex/latex2e/base/size11.clo File: size11.clo 1996/05/26 v1.3r Standard LaTeX file (size option) ) \c@part=\count83 \c@chapter=\count84 \c@section=\count85 \c@subsection=\count86 \c@subsubsection=\count87 \c@paragraph=\count88 \c@subparagraph=\count89 \c@figure=\count90 \c@table=\count91 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 Compatibility mode: definition of \rm ignored. Compatibility mode: definition of \sf ignored. Compatibility mode: definition of \tt ignored. Compatibility mode: definition of \bf ignored. Compatibility mode: definition of \it ignored. Compatibility mode: definition of \sl ignored. Compatibility mode: definition of \sc ignored. LaTeX Info: Redefining \cal on input line 620. LaTeX Info: Redefining \mit on input line 621. \bibindent=\dimen105 ) \@indexfile=\write3 Writing index file main.idx (/usr/local/lib/texmf/tex/generic/psfig/psfig.tex \@unused=\write4 \ps@stream=\read1 \p@intvaluex=\dimen106 \p@intvaluey=\dimen107 psfig/tex 1.10-dvips ) (main.aux) LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 18. LaTeX Font Info: ... okay on input line 18. (intro.tex Chapter 1. LaTeX Warning: Citation `bha93-localND' on page 1 undefined on input line 10. ) (proto.tex LaTeX Font Info: External font `cmex10' loaded for size (Font) <10.95> on input line 37. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 37. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 37. LaTeX Font Info: Try loading font information for U+lasy on input line 37. (/usr/local/lib/texmf/tex/latex2e/base/Ulasy.fd File: Ulasy.fd 1995/11/28 v2.2cLaTeX symbol font definitions ) [1 ] LaTeX Warning: Citation `bha93-localND' on page 2 undefined on input line 82. LaTeX Warning: Citation `bha93-localND' on page 2 undefined on input line 110. [2] [3] [4]) (drivers.tex [5] Overfull \hbox (19.63927pt too wide) in paragraph at lines 63--68 \OT1/cmtt/m/n/10.95 *.graphf \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.graphb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 Graph \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 Graph[]readFromFile() [] Overfull \hbox (19.63927pt too wide) in paragraph at lines 99--104 \OT1/cmtt/m/n/10.95 *.graphf \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.graphb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 Graph \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 Graph[]readFromFile() [] [6] Overfull \hbox (19.63927pt too wide) in paragraph at lines 139--144 \OT1/cmtt/m/n/10.95 *.graphf \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.graphb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 Graph \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 Graph[]readFromFile() [] Overfull \hbox (19.63927pt too wide) in paragraph at lines 184--189 \OT1/cmtt/m/n/10.95 *.graphf \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.graphb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 Graph \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 Graph[]readFromFile() [] [7] LaTeX Warning: Reference `chapter:GPart:intro' on page 8 undefined on input lin e 231. psfig: searching ../../misc/doc/R2D100notags.eps for bounding box psfig: including ../../misc/doc/R2D100notags.eps psfig: searching ../../misc/doc/R2D100fishnet.eps for bounding box psfig: including ../../misc/doc/R2D100fishnet.eps [8] [9] [10] Overfull \hbox (19.63927pt too wide) in paragraph at lines 361--366 \OT1/cmtt/m/n/10.95 *.graphf \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.graphb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 Graph \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 Graph[]readFromFile() [] Overfull \hbox (19.63927pt too wide) in paragraph at lines 366--371 \OT1/cmtt/m/n/10.95 *.etreef \OT1/cmr/m/n/10.95 or \OT1/cmtt/m/n/10.95 *.etreeb \OT1/cmr/m/n/10.95 . The \OT1/cmtt/m/n/10.95 ETree \OT1/cmr/m/n/10.95 ob-ject i s read from the file via the \OT1/cmtt/m/n/10.95 ETree[]readFromFile() [] [11] [12] [13] [14]) (main.ind [15] [16 ]) (main.aux) LaTeX Warning: There were undefined references. ) Here is how much of TeX's memory you used: 658 strings out of 10922 6676 string characters out of 73125 55494 words of memory out of 262141 3516 multiletter control sequences out of 9500 14802 words of font info for 54 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 23i,7n,22p,194b,417s stack positions out of 300i,40n,60p,3000b,4000s Output written on main.dvi (16 pages, 45708 bytes). misc/doc/main.aux010064400020550007177000000024530657406567200152610ustar00clevecompmath00000400000006\relax \citation{bha93-localND} \@writefile{toc}{\contentsline {chapter}{\numberline {1}{\tt Misc} directory}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chapter:Misc}{{1}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Prototypes and descriptions of methods in the {\tt Misc} directory}{1}} \newlabel{section:Misc:proto}{{1.1}{1}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.1.1}Theoretical nested dissection methods}{1}} \citation{bha93-localND} \citation{bha93-localND} \@writefile{toc}{\contentsline {subsection}{\numberline {1.1.2}Multiple minimum degree, Nested dissection and multisection wrapper methods}{3}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.1.3}Graph drawing method}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {1.1.4}Linear system construction}{5}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Driver programs found in the {\tt Misc} directory}{5}} \newlabel{section:Misc:drivers}{{1.2}{5}} \@writefile{lof}{\contentsline {figure}{\numberline {1.1}{\ignorespaces {\sc R2D100}}}{9}} \newlabel{fig-R2D100}{{1.1}{9}} \@writefile{lof}{\contentsline {figure}{\numberline {1.2}{\ignorespaces {\sc R2D100: fishnet domain decomposition}}}{10}} \newlabel{fig-R2D100-fishnet}{{1.2}{10}} misc/doc/drivers.log010064400020550007177000000011750653410634600157650ustar00clevecompmath00000400000006This is TeX, Version 3.1415 (C version 6.1) (format=lplain 94.11.14) 15 NOV 1996 12:00 **drivers (drivers.tex LaTeX Version 2.09 <25 March 1992> ! Undefined control sequence. l.2 \subsection {Driver programs found in the {\tt Misc} directory} ? x Here is how much of TeX's memory you used: 3 strings out of 11977 29 string characters out of 87269 23017 words of memory out of 262141 1977 multiletter control sequences out of 9500 18996 words of font info for 72 fonts, out of 100000 for 255 14 hyphenation exceptions out of 607 4i,0n,1p,74b,7s stack positions out of 300i,40n,60p,3000b,4000s No pages of output. misc/doc/main.ind010064400020550007177000000007060657406550300152260ustar00clevecompmath00000400000006\begin{theindex} \item {\tt drawGraphEPS()}, 4 \indexspace \item {\tt fp2DGrid()}, 3 \item {\tt fp3DGrid()}, 3 \indexspace \item {\tt localND2D()}, 2 \item {\tt localND3D()}, 2 \indexspace \item {\tt mkNDlinsys()}, 5 \item {\tt mkNDlinsysQR()}, 5 \item {\tt mkNDperm()}, 1 \item {\tt mkNDperm2()}, 2 \indexspace \item {\tt orderViaMMD()}, 3 \item {\tt orderViaMS()}, 4 \item {\tt orderViaND()}, 3 \end{theindex} misc/doc/main.idx010064400020550007177000000010400657406567200152370ustar00clevecompmath00000400000006\indexentry{mkNDperm@{\tt mkNDperm()}}{1} \indexentry{mkNDperm2@{\tt mkNDperm2()}}{2} \indexentry{localND2D@{\tt localND2D()}}{2} \indexentry{localND3D@{\tt localND3D()}}{2} \indexentry{fp2DGrid@{\tt fp2DGrid()}}{3} \indexentry{fp3DGrid@{\tt fp3DGrid()}}{3} \indexentry{orderViaMMD@{\tt orderViaMMD()}}{3} \indexentry{orderViaND@{\tt orderViaND()}}{3} \indexentry{orderViaMS@{\tt orderViaMS()}}{4} \indexentry{drawGraphEPS@{\tt drawGraphEPS()}}{4} \indexentry{mkNDlinsys@{\tt mkNDlinsys()}}{5} \indexentry{mkNDlinsysQR@{\tt mkNDlinsysQR()}}{5} misc/doc/main.ilg010064400020550007177000000004560657406550300152310ustar00clevecompmath00000400000006This is makeindex, portable version 2.12 [26-May-1993]. Scanning input file main.idx....done (12 entries accepted, 0 rejected). Sorting entries....done (47 comparisons). Generating output file main.ind....done (28 lines written, 0 warnings). Output written in main.ind. Transcript written in main.ilg. misc/doc/R2D100notags.eps010064400020550007177000000264320653410634700163450ustar00clevecompmath00000400000006%!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: 0.0 0.0 600.0 600.0 /radius 10.000 def /Helvetica findfont 12.500 scalefont setfont /M {moveto} def /L {lineto} def /ACF { % stack : x y radius newpath 0 360 arc closepath fill } def /str 6 string def /drawLabel { % x y label radius /radius exch def /label exch def /y exch def /x exch def gsave 1.0 setgray x radius add y moveto x y radius 0 360 arc fill 0.0 setgray x radius add y moveto x y radius 0 360 arc stroke x y moveto label stringwidth pop 2 div neg radius 2 div neg rmoveto label show grestore } def gsave 3.000 setlinewidth 0.0 setgray newpath 82.2 20 M 20 20 L 144 20 M 82.2 20 L 207 20 M 144 20 L 269 20 M 207 20 L 331 20 M 269 20 L 393 20 M 331 20 L 456 20 M 393 20 L 518 20 M 456 20 L 580 20 M 518 20 L 82.2 580 M 20 580 L 144 580 M 82.2 580 L 207 580 M 144 580 L 269 580 M 207 580 L 331 580 M 269 580 L 393 580 M 331 580 L 456 580 M 393 580 L 518 580 M 456 580 L 580 580 M 518 580 L 20 82.2 M 20 20 L 20 82.2 M 82.2 20 L 20 144 M 20 82.2 L 20 207 M 20 144 L 20 269 M 20 207 L 20 331 M 20 269 L 20 393 M 20 331 L 20 456 M 20 393 L 20 518 M 20 580 L 20 518 M 82.2 580 L 20 518 M 20 456 L 580 82.2 M 518 20 L 580 82.2 M 580 20 L 580 144 M 580 82.2 L 580 207 M 580 144 L 580 269 M 580 207 L 580 331 M 580 269 L 580 393 M 580 331 L 580 456 M 580 393 L 580 518 M 518 580 L 580 518 M 580 580 L 580 518 M 580 456 L 510 90 M 456 20 L 510 90 M 518 20 L 510 90 M 580 82.2 L 510 90 M 580 144 L 90 230 M 20 207 L 90 230 M 20 269 L 370 510 M 331 580 L 370 510 M 393 580 L 370 510 M 456 580 L 195 195 M 90 230 L 475 475 M 456 580 L 475 475 M 518 580 L 475 475 M 580 518 L 475 475 M 370 510 L 55 335 M 20 331 L 55 335 M 20 393 L 335 55 M 269 20 L 335 55 M 331 20 L 335 55 M 393 20 L 125 545 M 82.2 580 L 125 545 M 144 580 L 125 545 M 20 518 L 405 265 M 300 300 L 265 125 M 335 55 L 545 405 M 580 393 L 545 405 M 580 456 L 143 72.5 M 82.2 20 L 143 72.5 M 144 20 L 423 353 M 405 265 L 72.5 283 M 20 269 L 72.5 283 M 20 331 L 72.5 283 M 90 230 L 72.5 283 M 55 335 L 213 423 M 160 440 L 213 423 M 230 370 L 213 423 M 283 493 L 493 143 M 580 144 L 493 143 M 580 207 L 493 143 M 440 160 L 493 143 M 510 90 L 107 317 M 90 230 L 107 317 M 55 335 L 107 317 M 72.5 283 L 247 177 M 195 195 L 247 177 M 265 125 L 527 457 M 580 456 L 527 457 M 580 518 L 527 457 M 475 475 L 527 457 M 545 405 L 177 107 M 195 195 L 177 107 M 265 125 L 177 107 M 143 72.5 L 177 107 M 247 177 L 457 387 M 475 475 L 457 387 M 545 405 L 457 387 M 423 353 L 457 387 M 527 457 L 317 247 M 300 300 L 317 247 M 405 265 L 169 361 M 160 440 L stroke newpath 169 361 M 230 370 L 169 361 M 213 423 L 169 361 M 107 317 L 449 81.3 M 393 20 L 449 81.3 M 456 20 L 449 81.3 M 440 160 L 449 81.3 M 510 90 L 449 81.3 M 493 143 L 309 501 M 331 580 L 309 501 M 370 510 L 309 501 M 283 493 L 98.7 151 M 90 230 L 379 431 M 370 510 L 519 291 M 580 269 L 519 291 M 580 331 L 63.7 466 M 20 393 L 63.7 466 M 20 456 L 63.7 466 M 20 518 L 344 186 M 317 247 L 484 326 M 405 265 L 484 326 M 457 387 L 484 326 M 519 291 L 274 256 M 300 300 L 274 256 M 247 177 L 274 256 M 317 247 L 134 396 M 160 440 L 134 396 M 107 317 L 134 396 M 169 361 L 414 116 M 393 20 L 414 116 M 440 160 L 414 116 M 335 55 L 414 116 M 449 81.3 L 151 169 M 90 230 L 151 169 M 195 195 L 151 169 M 177 107 L 151 169 M 98.7 151 L 431 449 M 370 510 L 431 449 M 475 475 L 431 449 M 457 387 L 431 449 M 379 431 L 291 309 M 300 300 L 291 309 M 230 370 L 291 309 M 274 256 L 221 519 M 144 580 L 221 519 M 207 580 L 221 519 M 269 580 L 221 519 M 160 440 L 221 519 M 125 545 L 221 519 M 283 493 L 221 519 M 213 423 L 501 239 M 580 207 L 501 239 M 580 269 L 501 239 M 440 160 L 501 239 M 405 265 L 501 239 M 493 143 L 501 239 M 519 291 L 501 239 M 484 326 L 81.3 98.7 M 82.2 20 L 81.3 98.7 M 20 82.2 L 81.3 98.7 M 20 144 L 81.3 98.7 M 143 72.5 L 81.3 98.7 M 98.7 151 L 361 379 M 300 300 L 361 379 M 230 370 L 361 379 M 405 265 L 361 379 M 423 353 L 361 379 M 379 431 L 361 379 M 291 309 L 256 63.7 M 207 20 L 256 63.7 M 269 20 L 256 63.7 M 335 55 L 256 63.7 M 265 125 L 256 63.7 M 177 107 L 536 344 M 580 331 L 536 344 M 580 393 L 536 344 M 545 405 L 536 344 M 457 387 L 536 344 M 519 291 L 536 344 M 484 326 L 116 484 M 20 518 L 116 484 M 160 440 L 116 484 M 125 545 L 116 484 M 63.7 466 L 116 484 M 221 519 L 396 204 M 440 160 L 396 204 M 405 265 L 396 204 M 317 247 L 396 204 M 344 186 L 396 204 M 501 239 L 326 134 M 335 55 L 326 134 M 265 125 L 326 134 M 344 186 L 186 274 M 90 230 L 186 274 M 195 195 L 186 274 M 107 317 L 186 274 M 169 361 L 243 269 M 195 195 L 243 269 M 247 177 L 243 269 M 274 256 L 243 269 M 291 309 L stroke newpath 243 269 M 186 274 L 103 409 M 20 393 L 103 409 M 160 440 L 103 409 M 55 335 L 103 409 M 107 317 L 103 409 M 63.7 466 L 103 409 M 134 396 L 103 409 M 116 484 L 383 129 M 440 160 L 383 129 M 335 55 L 383 129 M 344 186 L 383 129 M 414 116 L 383 129 M 396 204 L 383 129 M 326 134 L 313 199 M 265 125 L 313 199 M 247 177 L 313 199 M 317 247 L 313 199 M 344 186 L 313 199 M 274 256 L 313 199 M 326 134 L 173 59.4 M 144 20 L 173 59.4 M 207 20 L 173 59.4 M 143 72.5 L 173 59.4 M 177 107 L 173 59.4 M 256 63.7 L 453 339 M 405 265 L 453 339 M 423 353 L 453 339 M 457 387 L 453 339 M 484 326 L 138 94.4 M 143 72.5 L 138 94.4 M 177 107 L 138 94.4 M 98.7 151 L 138 94.4 M 151 169 L 138 94.4 M 81.3 98.7 L 418 374 M 423 353 L 418 374 M 457 387 L 418 374 M 379 431 L 418 374 M 431 449 L 418 374 M 361 379 L 278 514 M 269 580 L 278 514 M 331 580 L 278 514 M 283 493 L 278 514 M 309 501 L 278 514 M 221 519 L 208 304 M 230 370 L 208 304 M 169 361 L 208 304 M 291 309 L 208 304 M 186 274 L 208 304 M 243 269 L 68.1 164 M 20 144 L 68.1 164 M 20 207 L 68.1 164 M 90 230 L 68.1 164 M 98.7 151 L 68.1 164 M 81.3 98.7 L 348 444 M 230 370 L 348 444 M 370 510 L 348 444 M 283 493 L 348 444 M 213 423 L 348 444 M 309 501 L 348 444 M 379 431 L 348 444 M 361 379 L stroke grestore gsave 0.1 setlinewidth 0.0 setgray 20.000 20.000 () radius drawLabel 82.222 20.000 () radius drawLabel 144.444 20.000 () radius drawLabel 206.667 20.000 () radius drawLabel 268.889 20.000 () radius drawLabel 331.111 20.000 () radius drawLabel 393.333 20.000 () radius drawLabel 455.556 20.000 () radius drawLabel 517.778 20.000 () radius drawLabel 580.000 20.000 () radius drawLabel 20.000 580.000 () radius drawLabel 82.222 580.000 () radius drawLabel 144.444 580.000 () radius drawLabel 206.667 580.000 () radius drawLabel 268.889 580.000 () radius drawLabel 331.111 580.000 () radius drawLabel 393.333 580.000 () radius drawLabel 455.556 580.000 () radius drawLabel 517.778 580.000 () radius drawLabel 580.000 580.000 () radius drawLabel 20.000 82.222 () radius drawLabel 20.000 144.444 () radius drawLabel 20.000 206.667 () radius drawLabel 20.000 268.889 () radius drawLabel 20.000 331.111 () radius drawLabel 20.000 393.333 () radius drawLabel 20.000 455.556 () radius drawLabel 20.000 517.778 () radius drawLabel 580.000 82.222 () radius drawLabel 580.000 144.444 () radius drawLabel 580.000 206.667 () radius drawLabel 580.000 268.889 () radius drawLabel 580.000 331.111 () radius drawLabel 580.000 393.333 () radius drawLabel 580.000 455.556 () radius drawLabel 580.000 517.778 () radius drawLabel 300.000 300.000 () radius drawLabel 160.000 440.000 () radius drawLabel 440.000 160.000 () radius drawLabel 230.000 370.000 () radius drawLabel 510.000 90.000 () radius drawLabel 90.000 230.000 () radius drawLabel 370.000 510.000 () radius drawLabel 195.000 195.000 () radius drawLabel 475.000 475.000 () radius drawLabel 55.000 335.000 () radius drawLabel 335.000 55.000 () radius drawLabel 125.000 545.000 () radius drawLabel 405.000 265.000 () radius drawLabel 265.000 125.000 () radius drawLabel 545.000 405.000 () radius drawLabel 282.503 492.503 () radius drawLabel 142.503 72.500 () radius drawLabel 422.503 352.503 () radius drawLabel 72.500 282.503 () radius drawLabel 212.503 422.503 () radius drawLabel 492.503 142.503 () radius drawLabel 107.497 317.497 () radius drawLabel 247.497 177.497 () radius drawLabel 527.497 457.497 () radius drawLabel 177.497 107.497 () radius drawLabel 457.497 387.497 () radius drawLabel 317.497 247.497 () radius drawLabel 168.748 361.252 () radius drawLabel 448.748 81.250 () radius drawLabel 308.748 501.252 () radius drawLabel 98.748 151.252 () radius drawLabel 378.748 431.252 () radius drawLabel 518.748 291.252 () radius drawLabel 63.750 466.252 () radius drawLabel 343.748 186.252 () radius drawLabel 483.748 326.252 () radius drawLabel 273.748 256.252 () radius drawLabel 133.748 396.252 () radius drawLabel 413.748 116.252 () radius drawLabel 151.252 168.748 () radius drawLabel 431.252 448.748 () radius drawLabel 291.252 308.748 () radius drawLabel 221.252 518.748 () radius drawLabel 501.252 238.748 () radius drawLabel 81.250 98.748 () radius drawLabel 361.252 378.748 () radius drawLabel 256.252 63.750 () radius drawLabel 536.252 343.748 () radius drawLabel 116.252 483.748 () radius drawLabel 396.252 203.748 () radius drawLabel 326.252 133.748 () radius drawLabel 186.252 273.748 () radius drawLabel 243.123 269.374 () radius drawLabel 103.123 409.374 () radius drawLabel 383.123 129.374 () radius drawLabel 313.123 199.374 () radius drawLabel 173.123 59.375 () radius drawLabel 453.123 339.374 () radius drawLabel 138.123 94.374 () radius drawLabel 418.123 374.374 () radius drawLabel 278.123 514.374 () radius drawLabel 208.123 304.374 () radius drawLabel 68.125 164.374 () radius drawLabel 348.123 444.374 () radius drawLabel grestore showpage 431 449 M 370 510 L 431 449 M 475 475 L 431 449 M 457 387 L 431 449 M 379 431 L 291 309 M 300 300 L 291 309 M 230 370 L 291 309 M 274 256 L 221 519 M 144 580 L 221 519 misc/doc/makefile010064400020550007177000000000270654276751500153110ustar00clevecompmath00000400000006clean : - rm -f *.dvi Matrices/004275500020550007177000000000000654525676400136705ustar00clevecompmath00000400000006Matrices/R2D100/004275500020550007177000000000000665315042500144635ustar00clevecompmath00000400000006Matrices/R2D100/ndms.ivf.gz010064400020550007177000000001170654275627700165610ustar00clevecompmath00000400000006>4ndms.ivfR040R0T0b a!CtQtq.$c06@A5E tM013Matrices/R2D100/grid.coordsf.gz010064400020550007177000000010750653602324600174060ustar00clevecompmath00000400000006&x5grid.coordsf}K 9ȼ,"+eЧ|(ߟ?|_ʡJj C^Y_rze镕++WVN^Y9rzeEP9T UCP+ ʡJj +zVFKcݦLCq[nG>P"@kd'~`WYvfsuq}YYalCyX%;@FPnG:#Q',{,nXKϺ2jMl0J2t&a^NlbݵTb(@V!gq,<0UL}S8&:<ɢpuܰf.fґ2_e J$+"/-e4R&K2Rø6Ƞu[,U vX#@;hv%eoH[) %cp(Matrices/R2D100/nd.etreef.gz010064400020550007177000000007470654275627700167200ustar00clevecompmath00000400000006܋5nd.etreefTٍ0 Ol`X{"Yi90 <G;7Ds4h5;s1`55O:R@Ox/ĉlC8D$#ȊΌvdzg'QR|ңL,drsC۟)h2=, xbTֿ@? d MG:]Q%h4 |v{^lkxWO=Cs5qU%S}k[ezc|]W9Rs F\b2f1k'7]{UtJc{sGrͫ_}'g{<]GLw:~1b9Uڞb#/{&TIFbU `m[|$/2JE]X 2u@:F-',ϙU!{Q&ǽC~1NY@@fzMatrices/R2D100/unit.ivf.gz010064400020550007177000000002600654275627700165760ustar00clevecompmath00000400000006܋5unit.ivf9A |Q'v7J%    LJ 9 PA޻<|a'H&X}) ,!|_Fr*jj޷Ѣ:颛zcgIfY+`-a}Ɖs.knND^DMatrices/R2D100/nd.dstreef.gz010064400020550007177000000004310654275627700170700ustar00clevecompmath0000040000000654nd.dstreef]R[! @%f؝]I'Yu˻™6p&"0Sd*o.E eyY,"W. .7|,w|_Rֹ;pjx}(QV5ec$sPJB+\l*MsIg3 h{cx6B}>l~.7H$0mב,:tmRFE_0j*F< X;M9b2=> 9~)<f !g8Matrices/R2D100/unitp1.ivf.gz010064400020550007177000000002630654275627700170420ustar00clevecompmath000004000000064unitp1.ivfйaA 1I6Ȇ} C%(Q!F8DD&b# ,dC.yTREjj?pą^|tEnz襏yI&,c~MPQy&!xKsySx|VG_&H)0gOSvS'? <#Mޖ)IsɦUN6Eyf\8Og>ɦC8wlÜl:囓Mffٔv.bG紹<ӳN.Ea|y'+sɥv' KsNu }/̐'Ж7~])O?~}.HCgM]ΨVg5Hc4&[2M=jtB]8UDojlO>ꧾKQ{6^:aXєFllڕ`ڌ9z|/{[~'El'4:gM42M fU9,>FfCO_7"%}{b/s=yOf4gҚ~?H0>jxQv_(fw*V&#x壵/D;{Ե9M͐}o?nM8iZ_3V)B;:iJN|~J Afd#H iy<tievnV5^qDۚrY1Fs{f=z9$ :7voMg`0z dMOEtWVvwϘgˉh8*-0k8 -Cl?~P} ?/H̻EZ2y]pbZ/Ziz3:VC,G\*w;#>>%E NCk >PƳOǚ-Gu.W CjYt\sV%q'ye3F:)G,rX~t:lxUg4˩w+چI@Yi\;g[Fh!ZFuX\ _<66R5]"ojs6 3=׈nYᾋ\yȻ){e^+'OWQ/l}X-FW@;D6Ն TO9fm4ܢ=u{* mBeNApM]1iZ C /\<3)x9,(pDT^ M8u(tVoܕD'}48s1hN'M1&;0fbmzkEa*;7^4MYk#x2c\x Hjg4hL3`:{OGېL3}`wjȤN^~ ߖ1lՐYL|QW$#$V[SFQ{ܸC+=|o!rA&t_axTD|prp4uGvkXw1KqꑁPMWM#4MJ/_|{.*Ss..0z U4RvplxJK率DQz޽k9gʥy;/ E=BЉ`]A0#μ*@YMݚrp-g Xݧ m%}hj]StbS9=Y;lK"9Ht.߮+W|=Dj~#੮v>=wQ+~XYyrf܃[|ckByͣdTQc}FpaM^KռZhiupʻV! _n=#ջW |(~;t?X0jIwsp̄}`0Ys'Mߵ$n*OWX:3g`H|^+z'VSurWΉV_{W;VX/\+#o'}Uԟʙ 9qJ+#$rk=4)jvqWF 9ؙ5nq+ٜYWk|Zܹ{{>øO{\2ܫZ_bnz,Matrices/R2D100/mmd.etreef.gz010064400020550007177000000007500654275627700170660ustar00clevecompmath000004000000062=3mmd.etreef}TQr \3*jy Ab3Z^cai.65k8璃rfͫ~YO^hḟyH%mB 'eVH5 HK,eX"㴜Ʃ]E_S%c,JǷ@³Ǩ(U ܾVHM7y /PW?s>Vh!Zs/yMEcco7@+5v/?.ܲR:3^sF?Bkw;GK)>Ը&W+d8XRxwa_<>|& 8Mj[M^ N*yI fps $_rݩΥ<7K X19qh4@ A NUC?Ep&g1d7#)u7W?H^&Matrices/R2D100/ndOldToNew.ivf.gz010064400020550007177000000002670663207465300176320ustar00clevecompmath00000400000006yh6ndOldToNew.ivf @L_,nHc9qw҈!rɣzTq c)8`j ]<_ZhhVa ][@JzXǂ~% bK4EFÕ629TB/)e]#6׏p%U5jL}\~`*Matrices/R2D100/ndowners.ivf.gz010064400020550007177000000001020654275627700174510ustar00clevecompmath00000400000006)Ӓ4ndowners.ivfR07R0  0 B 8! CRMatrices/R2D100/orig0.graphf.gz010064400020550007177000000013670654275627700173330ustar00clevecompmath00000400000006܋5orig0.graphfUUY !`_%@LMX$Y&G7B#wZDGyH~͟\cc3? cxf8&=78͖om1[x\?05/%xWZ^kiՎh8yr\ͣ_3Rq1s)cP:=".8}29,ƭE\v[e[f7|E?7@@Pr],Sm=̨-d#[;qTͳ B0?h{tZ$յvۻV^Xs~U*Tj:z^}@c7yb +o?@Tyƕ x[dkRˉfO /˴2JAfzH\m]UOK ~Q$#gl44XX;.>COvg@)^:H_ Nm P6;I !Matrices/R2D100/ndstages.ivf.gz010064400020550007177000000001610654275627700174270ustar00clevecompmath000004000000064ndstages.ivf= !C TCRn&j(>jHNpc%[SN;ן@$zgWMϛy߲~q5~?a~xx.agy׳,`/;y@]_m){“%PY-[/=6AN[LOվ|Z+ 5{^% xzr']c{<^rC=(w拥 o(ΐ}r&`JϠoQPPbAbi=>,6pc Bd hB hKo$wv+}rh!5Xh`؎l W*l V<_)P iKi]LK"JaUrj t1`Elޕq4Рs ȹբK@#+V#/S !VFLw WIlANxk&~:WGЬ72Sy1"IZK( ĸČq٘*P#L:рA2Μt. Xdys.PMnv]2|ڒG#P?N̏չ}Э8!E* ~&5-#ӥ(hA ' 鰉cuy)^zJ)JhkHP:$fHrQΞ=BhUQc %Matrices/R2D100/ndnew.etreeb.gz010064400020550007177000000007350663210753400174050ustar00clevecompmath00000400000006\h6ndnew.etreebR@ C)r'x㭈]vZ:7N+""% 2 y1~T8(sV4X`ӯu95טGϰ 6`48 8ɸp n5Gp 78d02sV''dur&Ng:)NHNNϬN[No9kh?ihթ3GAzQ{'Y:"{oH{wG7?j\{1A\\i)WQJQȳCƔxB'S{6t;lߍeO?c{ySj{wS" SJw Z韋P3$־HJIƇi\UFuNj݈>@;'d?c^DCQw&(LMatrices/R2D400/004275500020550007177000000000000653602324600144665ustar00clevecompmath00000400000006Matrices/R2D400/grid.coordsf.gz010064400020550007177000000050750653602324600174150ustar00clevecompmath00000400000006_|2grid.coordsf}ZIC)_ 1 RJ؁wv>@?+)__?)}>|(?Qy'ڞh'h~D剖'Zh{':_藮 藮~*_ 藮~*_ ޺譫޺譫޺譫޺譫޺ 跮Ե?Q~DO=DOԤO#Kݓm]i+־X`rj6 ےdԔZ*6^Uj偑Q[NPݙI`EU`i~17 4ri3{U6Ϝm.)V'BQՉxM}^E~v@.j&K-=fqvy6as@Kb$fp49={k.PN#mcw~N2mѶ'arXoyfSm3M`+09VwtuH#8q<'O)l]HQ)6p2zw‰8p(%H#VEp\uOlcAI#/#c_@^6jOlKKUOxpjgA,5ض45z,@Xi)vu=oHM-WY\c&leG9c:4H|ܢe2=٣m hnȯ4DlD>i)_2'"d-;~&y2 ٫*1HIjZcm+4;bY4=lkv2F6q"(W1 /AA^F>GGFf'/Pđ=OƑʁ|*%_S*p ɧ 0x$uUG̱*R9k / dɀP_M$p'/_ a+4C> -B5oOrs ]M>#MqR2$btN>y6,ƝU2\Gdj٤eWyld,S$>#8~牪ц\ymP5r0=ǜ3jP͜l.s-##jgIms(\ǽkVy2";|UEӥq$cWle Lign28c>vgWwدY;5'}N[ bpuUm+{9ςyJ@hNuJc#[j,h`'Ԑ%O6/.!-SyBGj,h'Ԡ$O6?AI>!R ' [J|ipOO8׀&41",TnjOOFq'Sʟ|24'/(jԀ&vMRCfp]Шi舔Uz8JR@9%5}9X6CϽbէ6J͒muF[ꐯN7fg ge M\J{tD.k૳D_7&ص$#uCW4u ]"y6=`~V4ydHlCGwv}bT(X8R"/nӕJ|`#ᏟnLZFDH8,EK|e\"#VVȧ]'C^lrJw|tjN/]Y@~y8Y"ś=4O%_< UmX[G_-DO)e۞ۯ;2m^NfY #kS5*򓀟;q5iq |O`vctsJmڥFz&Y[Mg6.R&{:NWF$Uc^ͦ)Ӎh[VNn=VCm+ӝr߇Nws㗋-KjȾJ)y m[mJ8y]9+وCڇ)@^d.vsőRJq`!u֧w+bcd#őV1Cy&U%/S-aw^wî4߹q78[ibKPSUO2G̝|1q?d溉}ιO9_}@`_?ה6_땻/ktU {GݗFQ{mkK3޴`쭖֣jYy=(\+]:U`i'_t%߫u+޶hnYI3 _oh^;Da[(LúkF_\u\N%~j񰪱LWMܻKѯF^hBuGv9xGP{ȳlW9BXY*Үެ@ZhS܎@VYQX'Ox)5jrwO}9:>Ի{y!׏?Vpn-ߛ/OY -˴fS*oʼ]+ճk؏޵$=H|h_{f4;ޗ|P~Tu-zW=5fϙK9|O02x~^mTO'Fe@rZ~]әq*2o4Q*>13*>W&jo9>wӖ}Bs]>Ph>wliw͢(1?1Vge~1|®хOhtUi5 >.>хnM>aQkj9 -z.c{&mObB#"Ql}޷6K9"I5&x[Xm1'4z&݃]OhDJ1|߬>3l_E}bt j?c5`{̬v&4O}ƨ=1f {Pvr; "4:F?rZT\6v w382e3;M)mnrG 6 @O9??2"0 m5ґ`E 3xٰ`($ωF{t jk[61'b(qdW[yBR~ 6wAfBF_8mbZ.X4֑E5ó vY!kK3dٲdxV϶*0plx5[BDzGe}΅GB^. B-*nB@쇛IN(ni5_!FNHߓf6GyH=U-fRУ<'ޜ\jG%zv5b3AZx}4`=LJr#Sr ,0 "oq1Kb#bNRj$M%3a[r0/YUG6ׅ% ~A`JvĂ 7VQ{x|hݱ۟J>=N * h˶&kXU(gjN(|h`ZV;jo8]ZX$> a"sh^8˷\BDq ‚K{ L_ny6= vz0/~"=CW> ЃZX@xSA}' 3[r ({CJE6(iˮo;ȫBc}ݱ6oJN8ƪo ׋}mH8C-711)^bw j"+'`(ePrҏ3sF/}DmmҧWnN`T6SH5 b`Z%SRZm"e%pgΉaEq.O%kVu,$,3\Պarr) {>SaC&7i'3N'9ǩ.L t);\FjUԥ2$⍊ fK!9ZCK!K*e;!݋&ŸLjk#@iC-Ρ*b Ng_Nt,Ǣ&8a>U݌ <究7K|;HJHl_O1)@4<SpI #~HbcVdvMb?>+;+ ]&t?A$L/׻ADd Y]gd.2tBB"Q mygCX2{2`JOn#*K$$AAoHT BRxp9rBoI 侟ސ"2z]~k8l;(%;&`|GM3BuD[z0䫿BzȤ:rxF{Sr] 4\R'tDɯ̚l7IYI]2MD\{;[}2=J#@6Nkb:FPR2&JlF4z4?PHӯzK" ax\_dtVpaYb2qX oonѫ>^ݐt3^"e;!Nw?Yt^m8#nR#uJ`/I{9aMQuv$[0q$I0Xakӳy<@_yCk-xbbt"P~P+g3Hb{dEzڏyg5xs;s[g4x2e&{Fcetm2]?goWu]ցgq/apxӇAж]I* cȘ%a.~I_B'|cv<{ưo;iQcOg녬 ~xy(?VY&Ó#|yzϑI{vK- yޒHUGiA^`fEm`5-F1)M4۪He_U8>`*Matrices/R2D10000/004275500020550007177000000000000663677706700146455ustar00clevecompmath00000400000006Matrices/R2D10000/grid.coordsf.gz010064400020550007177000002151020653602324700175450ustar00clevecompmath00000400000006&x5grid.coordsfQ%n{+Y ߥ\2YpDR#4 @Rs~8f4X`ܚVVn`?</`Lnf`OAnk=ds?^܂1r+?oZr+f+7?SS `Lnf`Uϒڿ[0&7Zne?\쿖[L.9{cr3V齤r+f+7?<%/`Lnf`Yr f_˭|Ank=4~y܂1r+3~{3F쿕lY܂1r+{u?--?XVVn`si-?Y/`Lnf?܂1r+{i)<Řkg;kr+f+7?柚:.^nk=:k*Řk=2䧤?cr3VI}\'1r+{ѓ|P΃Xk=Fswνr F3VUeKr+fFzRn Nnoo̓`'2X;ɺ b[Nr꿖[1)owGۧ>O3ěR~h9{K|lk5Zn¯ f3Oȁ?#G>~ `~bo_˭lB XKȄ`r+?θ܂y-X_ˍ"kOQLsG" ??W~{,-I)u/`~rD쿖[ٞr癟[0ߜasADIR_E[E^Xs_ErE^7 Ǖͩ_˭lOeO6D1VasoVn̽Oz":u/"o=-/֣@_ GcWl9>V?2~oeoZn|_;4BX; .z_;G-=ZnrӯrAZneoZn|_\У;?z_j S|~6qWeF<-=)D쿖["iyr+;rcmnKP|vp_F[)`窀ᠿ3١$..lvo8ô褣/ء$0%HBg4JHOʽqvu6}~t hs#{|?y3Zd`3ZE0?9jYEKWp5*꫘|`t=e`V``Vq Ak'\ i.'9Z >ɶVϓmrV3lU+ ml4pog, j=-\iųlUqfhOOJŧUlU|!Ɔ i{Z϶?ζxxUyfGcb2[՟vjRY~ت^-XVI|1[6vKM6:UZz.`7fh#[L?ղm{Zl{Bh;!{|Ď!t`g;m'$1{ Dl?3,m_ٔ]7ou4Mc_;* M_b <{45/AKĭJBw)1ML_b|}5(&1yMbN>u4-JIhY%-׿6Q_ :6h_ * Cja׳r*~ЁȭÖ[d\:bhrˋ{ÏVsz3V%cK"A'it 5Dy/v@Xgs5ѩIsd>iCNJ'YOt9IC';ghOD{3Oڋ?iC2~ i_{">xuȞ7/>Ȟ7/l}2נbduȞQMLjh2y9hA<2yYRRK vKFL? ngt*8vngt*ħ'*:)->tC?SIRbZ}O#Rsjw~*)0RAWS}dCw3ytDt{-FOMCAn}`2du4M'* MzU2>drdhZھTYbb9 J<#guP_ω+3$(]m/} 栿ՠdy|ad5UF_~Hbw];_%b#wWMDXo\ /ߘAyd8'~VCVI A$oRR3S}[1{l2rEBE [{G1nu4)Jb> Y+{`m:mud[P$[ƢDtR;ڮu+{n׺un̶ -7׻{C VZ%TvbeLh:*q[:7dGs\ncm=myȶHbT`.ˋ7lNj tUfd _~-[M-t}G6郎nd>p;*';w+q~}ї*JbߑZߡeZMߡEZ{<; O] 'pwIs$:$$LχY38>eO`|>|(a gLEy31pTSQ.gLEyJ1@qT_SQgLEya1qTSQfLi*̘0c*TϿf?0KsX La;)50+sXÌWa i15ԥ0 sX ca !J;v\WֹzWm}B믑[$vv(d ~e+g߷$v Tv|ܧdQ̶Hb*` ؽfA'vI,vr柛y֯Y{w-:z'sVQ|/N(};;*-{9IVIS}o;s1l;l;#h3ȶHb[@޷?rGNmgdI:y6v2]7LN[러_;JbحVEn:&=mI,21;m0_in'1W-@F['-@$\Ѐ}'`_g./gі$$[FG%go^\'|;#h۠moĎ!sؙUNĶ܋v|t yslWvbA]^fdJ̨x6RNth~@&.eQ͛E5o,%,c޼yBO0D y:QikG\}ڑ-l}F:F:>nv.@仔lv.m%OҧAב\rӬ濎>a;|AsK07[NX9[NjRzmRAd }E֎|Ve֎2|e|f:QyfrAkjt.:LJq6HjVЌlu0?`d//|rM//|rM/\3˸}Kq}Kq'>9[DafD03;@*}8fVSV'pꀛX>6K;>$4w JJf- IwwW$0{1JrBѼlM2WjӼ#T*U R҆lVI*II3 Lf}$g$DUdKZG2A%@x%S*t^淎>!kGAf}BS ؚ1hS t).%!g$aL?;h3V!%?bMB%e%6*)DG- JbʌKGHÌKGKÌ!I3)+5̌O(_3̌QJJMyaf4dRb 3!s^:NJ9Hya2dwRXN$|w<0{;)g,kːIb(4^|J9Ha2dS⟯z'f/Cv>7|0{)7!;RUS} 3 ːO黾(>^|JR__5h$|UgfFC(j|032G)W1噆ѐ9J)u(_3̌QJCyaf4dRZ$IiKQf ٝxf%ofFC?=FCh\Aʷ3!N4;סwa2d%O\'Oj;0{94ʷ!;wa2#of/C.(= YEYa2Cl_f/C.(=7wkYQ3FːIO};^Nzs5ev04^|{z, 0{i>(>̌\~zhҮo̷2zgU:Vwa2drߥ0>^|z&ﻫfSa5gSvg T*Ϳ(3̌({rAě4 )>̌*|*_ ˔ofFC?GChQ} T2bz'fFc T׼SO'7+;sʬD_ "\24ls$bxիm ~eѦW'{1ֵ nZͽ{͹'HlJvs ؝Rv=tUcvw~f -"xK"^K>Ds&v ttiND;]Λ{fngWZ}[ϩ$vf OvI(x̞A%Ig *Nڶ6v }$- \2ڶ\d[W$E7k ةayA'Yi*.j <w5N GI`TvM.̖t$vy[OrB>S:0fWFUGIk:f/2m@'xHga}-`zԕƾmnmWu\5` _i@'EG=A9A'/^-y9]̶c6 _IҞ`x̘ ~e=mseEr f`sd fde$d1^$1CK ,amf#IWIdWk\'|U:ڦ퀻:;]N`gfCFv$$vhi̾ [- -ߒvv4CpE;Wϩ 3ۮl~NϽΪ-@Vs3v лgm2Z^.y{|Ot윁oE+--Iі褩$޹d =YglsٶIhsb!"nv}ݟ}m3Ia3O7[Ζ6vɭ_~K&ٖ󉎶5*嶫$kvcdcPc]y"*r:Qnj:Qײ/vy}ۉ0 ȖVR%?7C^,,yΘ7@'7@'Xy"AנlH¿l0N'̖8* U&N>}dpM/;MKBn!NB C^@-4qL/QVn:Qn:Qь\ݮ_ ۥl [̈;?wd@뀭T@'ޚ@'ޚg-+ayo@ހ(53i[JD[\V-NZ>urp'M'v;H ອ4qN$\n+'gvY%!w}]}VI|Ƌ}B~Ƌl ϸk!odz1<"lk{spKfKׄ? 4}"vz}3\lsNVaj[Yuno}02LmĒ;v*%`A:yUXjt$Rc>+m}oh;X rE;z;Հ}=+o 0!5Zz F]̶Hbˀ]N`3`3z :i̶HbQfv^zjJij{EVٶIhrm6`_Oxm3ɫWIU[VW^n'[ )!W{5`Kϣ2(]%W :* n}xڪ$d5hیm Ķ܀}` lKtf[b8nEGyUp]Vmk.[Gv2I̽ryحvcA'ҿt+hR[[Auڪ$d~d]-2|vΈ]We9Ivtr$&Y+jA܊_g3֞t}TsyDsy+vfdA'8j>O⴫*^ȖQ_չwH-ɥƫ8"Љf~Uuڷw* ٷwX d 'ABvAR‰3:J *W >ۉ6Vx36vb"P"I طf$5`k8*^]L\vn ͳRmB=< !,7sgTP:Ѡ!LӌJK"y/~}Vce7̼#ϼluM{qV׼:Qܼ:Q!5ʪ84{"_qhD.K.$Zg!`-طkP\-ʼn_G]^C O GJx]KjF-ݨĹY%KWfL7`kxk!hjƢ}B0l)C->ą9ayJ>Q;GS L=>G3O)ЉGgRuں*qۺkP^^V"l]2Y%' O-L[|)9R0qx?f4dœq ֝@'`66Љ:mH-q[;//{:jJ0f5%뻔"),1kDrNPpI/h*>u+í= A+ȣ\9'|қ {npFoԕ3bTBnQl|dFSQ$>c-VaLr 7Af4<ȁુT 7yzdFSÃAu-moRe*y%w)zKd]S)̓$MjL1r*A5<(Ⳋ4Tzd]SᶃBncMSL XA5y;(J4Q8g<(_bYT𠐅*zd/S'VuMe  MjLE -muM 7A2;(hkYTp|T@*zKd]S9B徧ћT oR\g|Kd]SAŃ\GΦ*]A3?:bA64?ȽP יh9Hłm* kU rAN_T],Ѧ/VQ יHuKłm*  ݿUY rANqUT2Ѧ,ԾkC9Hw@ 3]q A!njqP,ԾޟX2FF}VQ 3k@5njug 2AnW^ gKQSì\nXLMr*]A5:(k bQS n}cLmrסA55:]_= AQS \vcLm =ẉNcMM*rS߉ יJTHGS G TH r8r_FMe*NT꠲>O_FM*vNT|ꠒohS]J\g*sP?QMy*AA3 :py`dS餃W|be/c DT>qL*㫁49bR;qL4*㶊49v2U>1:Sc OhhSJI=nA38hSnA35:Mv|$TP5H\gjtPi#נIuT*v{sf4598[6bԘ砢VnO|*DkcM4ipkc᝗4iϿ%p~[}_K/$$" ( դ[xtL/4P@/4^nip$rKC[_ L5Tl_ L5TÔ_ l S~-25 j~-2DC[u^jkcᕩ^jkcaJ `e61<~ӫ^I5O/4 &k^jzyɐn!&C^jʧyzy&J̦25u A/oQJ>q6UE.O\'T]L *]`kcJ>9HyA.P.}ӠJ>sIi[d.VQ.}綊t7_iT]LϹb*ѿUYgAO8PuH}꫁,CU_iTeQ*-UFPE}뒪,`w:>:}CjTeQV*̦FtC!њ*|R0}>:e4Ͽ5O􉛯y\VQ2}鳊*LTLjeM*>}R0}髁*P7V._nʢ>r;HUAORuH}Ͽdԧy.:>WYEU*'}5PuH}髁CS_Zeڡ=zԘ UԇnOޣ&`N᳊:Ih*ꀡi&&w@}'4;_[04M$4¿%u'CG|R MM$4]u u_CRPoMMpF}4II _I'ס>8D_zijA >&IڡDkziyi&nO\樂'6:Ihg,u෯ꀡuCپP' gN:`hwꀡjUIB>cDf6g{dSaio'IBnOݞP : HSoS' MYE4g,u04*_ HӨ|P' Mr[E4mu0 HSo|P' Mr A4ȭu04* HӨ|b' fS/tB4XSȝMݎ5uB]5QuB]5= u;tXRfMfw;H]vO$|Pc}k4C]*v/VQc}PPf}64S ק4u>y"xԬh}MAVO|EQI>˿u_[>CYOx3V%C>ԭ^NBiAy6kkh=غEnح=u;nK>vkO]*vO}bcfSyy?hF]*v}Rc}贈4k1_i$>yBݎo껬O}hMib?]:uCq*}w/AyT齃:~Q(7 ͜M|';c[:dȞߣgabIf!f u;1{=TtfKAω~j|GJGP+_?+`VvY*V5m){جx|Of]{*@g|N" v.~=_N^5tryԗ/jp`k^G(-뤨$3Vҁz (7 (I|0.j.Y-~lCdp[y9v;]@'YG[zLحfv..7:c EN[VJbG$`rKa?{gIc@:I'uۥ˫ﮛ'umYT[YʕٯOmm=d?SvvW-I| tr$/ΛmՖ~ukGE'Dyɿdg`?=`_ 5:yty^hMYs噬3vsٳ{lBYrN wvvI.̞UDߣgIRIf@ߛ;aigSvfڪ:i̞U[U'W/O ٳJ :y,Um՞86Wf dVuT;ށKN 7mfbH*I;+ty^+YmDžKevjn_Ikp_--|+牎&7A>e|s׎r5O+[9'; LJ[6qunpIe|gr|jTՠK砸^r n݃.AM:`>MJI|Vc M _ * \z=%Dܺ]}hr =QIMAn?luAG3qjY%B->cuPWDpC|VpXqՠ)_^%PAqMjq;(n'nu4f$Y%NɃ!>cqxP`ƿJqaD5/Ⱦ%rPXm*A X#ᖃB.%sPBn!$rP٭g "pAj* }5HH0A XGۥ3Љ~r9[.-惜AM&׉JBo)M>u49|E ר;:58rvH}G%!*qt[%ncu49i˫$Bw#σ\R{Sܭ\rEVI(A|[bM* 6*9(DsP0}|h (QI(lӀa3g[q{9kgr7AN׷8rJSI}J/}J GMNZ_i* K( W0A|_ :TrϻE@Ayh;(PYGS­JBI:=!_^}Vhr_UIIk^B9i}K w*Nq_pS퉤5Ʌd>$)@*I88(dAGS8WJbn׵:s-NﭜJjn}CCIl*U:\l* RqߕWTwu7[ wvv̶+MQȶ+rO=k/A^ww'A|=Z{oxK2KI1}]+_y[M?xf$gYދk/}'"~Rb]1OtyoY$ҘݳH2K1;5`̞/T'djٶ.V~VfJd,^IY-,U&OlsPNRIfRf˭jO΢W+%@G⬬RR/`7f ꪓlqN`:{?֭淂of7ѳ3*r:v9v~]@'MG,IVIlҟ̾v܊N=߸N^%~VCRÌE콞/hC|egfϚYSմ^7t}o5uy ]̞5xޣw奅J2B3W`rAN̞5T'ٳm׵9x&f\=kL=kLN^EՀԀ]3UOGfϚ^{L{-dz [yH'̶WJ2z6!$5 k]ݙm 5ϻvO`>)mV˶(l$uR j_ #ݵ˯VX'YGF.q\;j+4rkun}2{|-ٳ[3;%`{YsTuR=kNeѳʼuYy믬)` Wع g: ȞuoU6Kx+쭻ͪ「 jp:a]EL%;}w`f[tr3"lr[U[x_ ̶T=NJ2 1] :y5Z>* ] ]nqdt1y"Nz_vttU<7A^#}h($Rݞh <.%}>O=#@AqsIt4}q9(B>u4)}$ds 3 q6y".BruT <WAG>(VSGSxJBA6:L=(_^|Vh UI(B\K"«>TrvA}r_Nt4F]'r8!R.B9$F}hrTIșkG96}M==k^G׼JBw׷8r4`砎Xq94#!tg&kP%!GkP\<9R}tK5(uTrANq[nJsH::zfX'M%0;]ev/ITP/>cm %M7+J2n*;3{_٘m~Eߊo'/N_vѶ7 N"~X2/f|k@'Jb\kk(Zͳ~k5m0di]$m'S`=` ؝v$fitR#3?b5#ovgeӐmGmĜ}o\j :ymsɳNUٯ4Kõȶ:|;$+%}7`7fۉtmuIJ1A cSok"wbe_N(ncπ  vҭgy朗Hkp$g;#ge eqmaĂ';%`{vfA'v-Y:{~{k>WI?udF*5`S[sqSvamٶNڙ=3[;l XhL V"]8B(^{!02;OKfJb/'vr:-U'̶K#%X)A.`ؽҀ}3{v-Sf:[{TݶWf=+R %`_=`*rK׵_ʇv I,dm$[5\uf'fBF[ $(xaݙmIb'5fՂn̶ÅrNQ2c;/f1GF4IVIz6I"wwױK2n҉]DzrdۮN̶K-3."nf֔=n9+;3rDdm'"].; @'5N.f[ qsϪqZu)Og{5]ٳ]27,-V-:`]Wٹܳ=3F:i̞ߒs2{╝.[ur3{^T'}E}Ww~@'5N.fϣNE.):OVއLFmY$r58+f2In6ՂN2N՘]v~K7͈hmFN[v:v.6!$$?Fsv[ד~e![Oyd^n5`=z3%l:)z^ʾKaTG?wBIfde[ͱʬguHM%Iz^${cE7 z[mAB-'8;u`f[tr3B"qcv?IN6em?_$T.`kq?u\iF%}΃)bV\/pmWdhv+9`-S@F/lAoT$fVv:E7큌; Hbg䀝{va=y̶'/{E˙.~z-& l7$h uEdC@'-:yRa}?Vv/Z;36>*W룒ۀ]2{ wl N -&TzF;3Ϛ<;ml4D{܃]WGͥ f5@'JbՇ婪kXdE^mXdۦ!Xe=` ؝fA'ٶ NȂr+_"yWmU6eh;|$N̿2?+}e#vvnʾMYU;͈h;* Hb];l۾@'vEo{Bl:(RBP}Vh ~wWBήo *rv}K[GS`ݭ gm;TyP8kߡʃ_ 52B_,rSk5Wj`kAnMZwDE~rJy"AzY$% ;(ykiT_ :hמÉ%PA7t4jPI(y[ܞH 4*׷Jr{P*I9(]-&%`j;|$RJR{Jp JAt4%JSI(]g$03VJ𣑭)WJB)n%젔 ^vPr[dM#nUJ{#i=4ă|VhJP*I,<(׼$-JGS‹*I<(-)=4ۃ\':$HA >%qT{PRM /vTzPly(xЃ gCHNt4=p$<;уAyVx :vTIyxЃ!_;'@g:n}Atȳƒ *ɭJBO \'oyw:&|A/|Vǃ_=ՠ鑉't=q{"zk^G׷JBϋ~Ƀڑ=t}GG#y?< AO8}ejW<:虥Jyv3Kt4=&e'nAhzvP%gľvqAψ}V4jXW(D%PײZHײS |HBNl |w)`k`滓N4ݥD ">O$E栰M!g_;* }'>O$$:|RI(_GR ">t4}ƪ$XwI$[I;(BGS[I];(9׼'k^RJs[)$3@JJ+ jє&+M%<'"sPrI9(퉎TEJY%I/%R|5hJJN9(5(H5נ8:* %D|JA)vt47QI(-GXJ[ARdJђsP*oI9(wM $Ϳ牤hͿq>OTzR> ypЃ8U:۹$L'-%'n$Gnu4=t&I=t#zfG'ӭǤn5I}lyus.׉<:詘[t ׼<:Ayvu<_:TIqyyuF'犾u4=t{ЃO>AOO}5hzA%C>A|ʳ$En}TzJcg<>yMO|$ g<>AXy}7_ :JSIњRGkKCϹNAO|wUIy|I`>t4=KP׷<"?DGӳV[xg*y}s\:jPIAXyD~ЃfntE sw1Vfn5j>O4qBS5qAi[:: bbG'4C mNk E'yNh 6_$6s4uѠ<6uIbmkڞxt[EbmԨ 7"S|^[h)>-4}iW( M1ݞPXs$/4r>)> 7}P|^[h5Oym糊}wA@>bWhkDtBlm諁nf(\ߚesBc?-}5PGh*mkﮔ_m}w*ms20!Aֈo e`jCB ejj/t Rƫ/C4 kjCBRFt;4ejCB_zBCB'M@LZ9r Aʉ&H@':AHס7gAP> @9ZWk/_ŔM|SN2s'IoIo;A5 hzӤ ӛ&m䳊4i'IZ&}-y}vL苳1ס7dڶ iҖ`>M6'Co9zӤ- \,3g'# f@BU&U[#7ڤWI&MYEoͥ;+}5WJ7ڞ4z?]MH}/'4!uЛTm곊kWXj7ژWֶm -yPm*ؿ+@K^_ TAJ gUen!*vL5[{)ͯ"SMm~_j hiTAY: ڠ׎>ALs5쇮'g۞b|؆sl̊jQ4bI#3N .eaA\e6D'0X쓢*JD?dhL@N eӵIOvGIh#CqHoyR b+ty̆lqDIh3P۶ 1t^6mtN(߮e!i>)iPE6@Y+`C~T XZ:| |KAr,)`C:lȁ@'_5{QN w˲JF!ѲrCe5!CՄ쓲;-;(`CelJ5S7?>P6;3[Z۩r*/f(uٝv ؐ9jw Yv tvBip;u!?3(Qx뒲sؐoۀ  1z`ۓِnِnGad(ގ>9;%`[Kx tz-& k8㚧w3N%l]J@(ɇ%9]Q_ u\J`lx?olxoDە 'azv P N΂]@ ;qJ 9УG9У3C-ge'b-R6tt ]>-( t0 t' !m4fCI[PGYu2Cެvg+'WBQ׃z'Jl޼5a~rˀ }mt=mt0zed6}'k ?Կ.z#AnAouXKtfm{E rԙ݌#Onqb6t%`k3 D\Pd`/ ׺/ofCw#v/F}>`com6,RDFwY%EWnu5h3>ul-oVl->`Yf`%fkQ֢Gd:`L>Ӏ7Љ? O޴KI7B\ud#²3&@ l-:cN1.ͷ.\gqAo}9YZRx)=-n<}B Zx)!r3O)Љ+1Qn-T=c=Z{F}BYEZϘn3@'ZF|Ƣhy3[KO$Z;'my>3-->5[<@'Z&"37㸟k^#O(;O3o&`k)7 tE(Љ|6:P؞EmtAoAGzJ-k}:Po-ml-m(:n'4yxgE{.[K {?Px"3Gҷ@y Zxk:r3_3Љ+yZ2{^֒3?(=s[0 Z`{'ȑNt#:r\ƽ9}$mq=ajJ>6 GMzd&ς^joMv4F?&f ڙ}R/YDxsPJPGY'u; m]>-O<+cN:ҳ1,l<+5N#ndz40l< }N:v:s5O=[yEln*d,M쓺"`kAy ZlwΓ8tchon}g@Gys n& Z>w東@'ZlwhݙʭgvP(A>Bʈlg6V3+Љy{Ao:) ?Fkm֢7vt2.s.[.".}BW['}kIwRNĖ" DG1(Iil-i{CZt ='#ΓZDuF;fkE %Wg(:[r23*D \[T\%e)<8nb81ۇe:M'|];*%`l-y2v}BOC oNRgs>l-:}a@a C EkO)`ky +d5O(;[R&Im)*K{U,:z6R$ eďN@9nOĖrӛDwۗgwOsf9PZ@~@!g-1E$ `Ao3V@'Z~@:3|(60Y DL5Q P/(/SɿR@z+Č>3x2[nx1Oh1@#w \d]6@'dƋh |3|3GVI(<|8(<8(m<8(MJBy>Ay>Av>Z [%t;aAv_ʣ|T6%% jєA%?׉<8(-;JAt hJoPy sP*y|sPښAM)qncUJ5/Js{"JXj_}':%I>A\':QI(<=(`?=(e緎vTJw[%ϫJ}G@緎v D.KnAhz[%\>AϹ|ևevt4=Z󵣒%]$aO]8⠧Kn!AϢ$%r =򕖁|hzB%FgK-JXthJt$RJR sPGS[)wP[)fwPA n5u4%=wغr:[6VGS"XҼ]R4o:Rm_;Rpp:* jByJBy%*єR%g H)1#ezG$;iA)w#_;:QI(}g:(}緔:(!GK}}$b"eغHAɾoMĮo}VI}J}5hJfP iRrRdvߋA$vP *vP *RGSҬAR}].oњv:Ҏ4A>A>Aؾt4yjPI(׼T<(k<(׼}'* %@f%@F4jє.A%$^nqPoipP :R}ߑ%@בf%@F4є.3V%$e_ Ҋ$e_iҊti_:R˫$H;9(pJ v& nJ;vPriBsPr4ipsPbM)n!TJ$9(-J$9(-J )׎JBؚ\lNyVRTI(Ag8(Ag 9(wI}$Jt3VN_GGS4D}VI˚D]Ҳ栔O_ :I}$Y^NYGS[{HK#R}VhJ_AVhz"wMQJw !\Jw49(-nYsj>A|hz"kG%dgK;ʃi-.JqhJq$RF֢TI(%}-Ļ1A_"ZtHЃ|HЃRhJ[sPwͿ2&_G&єT_G7:{A>(ubi|P?h`H`K[}VhJPjƾ JZ,BGS[i|Ѓ ȹԢ 7[HE­JB|Ve` WTz0C>ckR>ՠy4:z|>+1˅|VJ>E}e>p ֧>?lm)" =}$8;)[?mSB$CHB|Vu`%׷gQn!TjaJja;yn5u45Py׷f-5oIa6%k5ja 5ZMM Y$_ lmJ^,1?bFδY%OuN7+$! 0`㛹l}3wnds:'F31[ͬl}fpmF;M^qdlzBA$@'yBl}xڟ@'hzDDNHm(>7L:ӓl ߊ$n@@l}0==gN E:QIf "YaOm0a6=~oyl-0ol0lzo6:ӣ]-eG&ؚxdSG6 7#Ef#Љ4@'Z.mf5fky% wu:z:YZkfTmfl-63hI1D˥\ЧZr悞)l*8sXMe#g.h a tE&gk-29oGW~=l-9#ȦҎDlhSșETqff:"33#Љ%)%Rnfމf& ̄A6՛<[ fQ-73hUY)fg6vqf:wLDchYc#1[.[Kf6@'Z8Z8ZBnf`"kkd݋M:s gFڙ@'gFMMfvP;Qnm1rkKlj.2Ȧ". pefc:*d,ސme潡eͼ7 {yμlm(4i[ {Zm4iNЌbr⺔3<7dS}C65_8fV.ӆ3Jm1iԆu Hþθa![tv!3.VC䘎=fk [̦(M WfPɭvf $ڙ>Ȧ9 lj3[3*Љ7Jjfk+y2]DGxj޼Pnj4o^[C͛WmS5o^NM;goMG֚}Mҿk wzrUۚMsPnjAk>lmokhw8h%fDpw vzMs(`k% w`h tr$Iʭ_g4W[({Eo/XUlm;o(7Q@'wF hyR_m܅Tumm0ۚ+z-1De65>曦6V[͛3du5y%$$Hz{(}`f[ fEj~fL=63c ٖ$-c f A~2v!f$ tRt|jAVksIMFIŕ.:c${씁ݘm 2ڒ8m骠r7f}|5ewfZFvuIMإz;1{,o=hTz:Go7_#mr vzv.̶y"m#HbK0첽%ZMdE_FC9D;%`;`R $FDG7~~OV3`?[ د0\"ɬDNlsgNʖ!-n?wf٧N#̊. إ;1Κl;k$}n5<팼9'g{={>~K2͒3L-욁ݘ-%C=NҖwΪ3ӼحAfKG|:y΀/D;7/f'窓:)*ɬ^}u0-:[ 7##ccS ع3 +gsIѳ9뤩$:;Vmz`ӶJ470ۂ2zVg*ONre|0{z#g[y}_)I" tU;$[eB[ul }0{U'ٳ̛.i.w~Haٳ(3{Sg} -:}f3UFϪ6gH2G֠<\:2$`_6&@'Nucoe зwej;j2YU]7Q|]f{}`wf[UY'Y%Rפ깍=jm'=k\S"ɬM;t`.:ze$df}׭ۓ(be:ycc { _9@NUYM%ի}mN}nwׯU:l)'+ٖm(jY$™ftzZfwNYϬ쾽 _VE ))gUyIQIf5|f_kval N,Ud_%jdMlHE;E;Ԁݙm.$1۶t`(l{3{ !=-`_عz;3[̶3lo$V˶UyXV g3YسQ[Y[wv~=Y_WNf"g{ZҒ˽?X* n|Ocl:|{ɧ?9gg _9kN5YM%Rvڪ~)\gVfLFĶH2k< :-In\{?u:c_=\V5Yurە lY3uUY<٪9{{gs:aeMl;($8Kv}3ێl;Nuڎ{CbvF~ ȶǻII%t`"&IctrmVVjX[X7-# rO gvN.YSuu:i*ɬաy YVϱ̶5Y'J"E\ص:yt:ygԭ u>24ߪ2 ܬծddoI쓡]v̖"^a#ɣX"Cfuw*gkRO^gnvD)VlK8褨$Re]Zͺ >=GϊĞߒK ؽW)?{gczIalL:[uVm|~ou|6f%UIflg. l)(Y{F, )fV6|[ {j\vRnSع0Re[NlKCIfuf[ ggvzzd=/ˬ+*Sv7`?̶ :yZrUYYuf߬u>ɻ̾)uhS{7,J̮+N}3{>Qfϧ:5w7ްc,D=N쒀zPtu0:I*ɬQg}ǰYr Հ+l2z-'d[gv[ndc{uYGDuҙm)dַgvsN ؝$fCtrmYuq5~:cKWaL#ĞfDEs vflGA'}{ɷΪҔW댽 -%(l $pQ'`kv}"uf[ tRɵtE׳ֵWUm^ dV 'ͳ0n6$3{>yY)oq98nѳ<$$>[SAlK'ɭ˫]mU V]s/olsYس~[YmO3qA.3ۮ\*ɬ>.[=}.aENIgE EYM}v3{W$f[P$ի37ZaO"wf,=n{n{K"%&Kvt=NJ23UX|~=bj+{(,YPuҙ=Nڹ֬Y8[u͏-ٖY'gVb']ElUvjWY~嬒:):Z,+M%bEKal~JH=_퉎UY'J2)3V` ؅̞oًV1kܪq־]Cf[f.d[֞Hb99t`_=` د`+SmInNJbG}=lj|]=#{?# F*l;8$(ʦʬؖH\}}RZk/vQm5gVboIfX{6T}vglu:I̞~޹jx.ew:cϪn̞ TU'ٳď wNدFkK~:):zuf*ɬG}ݪΓsC~/'̞#umJdfv"ɬ윀m9IgA'mWfYڔmG=ijNJ"s 'l1tf'$[U9LA[u~*Fm5;W`ld{:i*ɬҊiVvf}= NJ2#37`3` RZkyrQ9dNzo+d˛Jf[67 _s"`+ S}3r*A'ٖS :@eAsAy);-5SF[--Nj wu쒈[N:w$~ٞ}W}]2.MhpiudEot}2d~oILQ(4x4`wf$1{oP^j59=e g S]}-'ٟD]@'I%gGj{dc})bΚ+$vvfW6f[$-0{\u32ڲmoĎ!9=~Vϋ@'ftzռb5yU\cWhov۾3{g'ݪ9V 1+z14N̶)!mb"ۦHb!`;a-XɆN*m]c*~[+~恒?YQI_kvݘm(IfLb}%ʾ\l;hr=SkEN{_iY6l;(N]tӺqإ]5O6'A!X'` eTzh V:)*El:Rbv 'blȪIL';wn7͹:)̶ 3B5hA^Qg_ܙA9?VQ|onZbv~mmkgAoٝ*֎3e뻌c]|:6HbՀ]W(`? U:mnɰ&}c~mS:gh"{}K266]g6f z:):ڂȁNnĖ\~={:WRIl욀=;1{Vtf'Oe98~d,C"wcemtȶHbyӊ*Ru`_̞?ɣL&7:OGvٳ|){qgm_"e$Ӈ|3l;\N%0 {q|θtr׹ٖ*8"UE΀]; 3_7-tRWmk\] Ţ.lD)vI̧ lA'v\q9x^Mɸ|jyY~=ڌ:,$W@Җ7{vN #ɭ~znTYBNu"Ҁ]3r[ ؙٳ1{>}[٦a,dZK\lٌvmZEc݀][.%;}u`{fY\m!,{9ɣtƁKϱO|׉qӽ>(M2&$DvONofGfG\3sn~m4=8~{(ļD{ 嶸3g3-:ISIWqc( mnzP~fw"΃2R$V_ :VI(egU-)>clMՠ)WJBi>5gl&jx*]<9(mzsX{fVF%_;* =r f`-: Tg:ghuTzvfշ>F]jEugYՉ>$@W l}* -JB ξq~[R]q{[R]':]'* %$?w_ɐ>Nb$_[IZU&N)!w`d`k[lMu)׭JBnOJk:$#ȷjw)nOTJOw &`kzlMw hJS)+[{S>𵣣a_.հy#>* Y%盭I9 }=oI( w.PlMDGS$* 5glIt4%JSI(g lM[ο6v#K24RU^EnMU/ӥ:a]Se4%UI(}5Xun`k"kPGS"_Cn!lMvsުoMy)qkPziؚ{%hJA%e{X>(k5-JRZ6M _)Pw'w)`kw'hrii}PJKi~PJKi}~PXM оHҎ}'f;[BGSrR* iAu!Aɾv5AuTJ -J&-JU))JBn٤)An5Aɾnt4%TI(]破l?(]破l?(q׎p_;* %%f|hi{P:48]N$N׷>()UP*i(->(bi}Pb* FF%є(vP%_QAO \'Ҳg oi~PϪԔ>zV&jє(A% 9ۓ~>Lp lJq 1z{$8{ 5%)JB),n35ŭ}&\_JR* jB_G&tu7lxI(E)Pؚ,kGGS"K<~DnM98 "&єTkG%dH`&C׹iAM)uTJl]JV_i+[SU}є뻔JBɾn!N`k[~%CbN|'-*'Uηу[M*ܞljg >On`3u鱆N`_ :jPIqv+[ǸE.mO蹋m~JD%C.I>򵓁O|]hzk^%_;.cV>Ræ6_fEj8k-6tRkakSzCBaf砎>Uj[\ͻ:I̶ 5HȝIRkdfEѶ!۬Hb^> $g+z_y 짟̶𭌶T'd[Q 9`vmASmHNJb[5Vkۆu2cm~=-m>d726` = zSYX_W dyEv~+;Հ=lۤA'7:};~taKqr܍v%A]D~v*DG%(IQI,Ia}JkN]-UF)dd0Ձݯ]ofo aȶDe3F]`c/}Sj"}?WJc3}Ѷ-UM_%` lhrm'IȾ{Q]KݙmmAd[~Hb}{蔝moIg#N,D-dlt=E|:&=-`mGcodDIl/l 'f㰲ь8l;h 9#ێ"z>ff A'z{鬒Xb“j^q\80ے^dL>g<{.S=$>vx= twfゲ g.l;$3fGm8(@'|@'E%#No[98W˗Ƚ󉎶gQױcmon%`&NbISI,ɭ0;լ>,Ք}3֥8dW$D]`3`_' m]NnfIocni˝XK'Ony/m.mdf['1}_{4c褩$&1==fll2zur$^m'd䛯ZF"w_YulsܜtbNĂ'] m`'fE֠Z<*82a `4fa =MBXDtHbn`+ɭ-褨$TC-rS&Wnu5hs.#D Iju1f.mә=9.gb8(;1i2ȶ;HbN=ʮ5`f۽t]{dt(s[.6eY{ئU%` 6%du:I*ɬxes0n̶람Y'I%}oVjO':n^N :f޿zjxr̷\_lsJh#ۜ"ݢДv(eomb}]jra_̶mWF3NJb.}u`*kvc4?m--}k r}@N6GK> ,:`c=f8(a^A'z{ ɹiC?8._6'Uo"e2ǡHmIc@'Rnb՚܅إ֜lsdh;$"ۜd"v:=ofk tRm)83;= [⼘S:\3wy$.=.X|;3ێP2ڂl*sGԚ~@//l;.$^ إ^l;ND%1ۘng':4-$qD- ׊fL1B~l 'N8WX~qf5f-T'7go#`?9`7k ttI"$3@ƶzWՠ-ٳQ[ |z;3|3?c}~xtI5XSW &f=민R7kةam1 ĂFkȝz!MrNmY2B+|dk5KN_ia@'EGO-t2FN=){܍SWvge}hxEl:w f;1۲>@'ٳ)kO}qy$ uRb-͕lS"ȷ%Pv{4LͽVI2;ft)1ܺ2\ȶy"&`W W:/hs:q S4a$d/6 -Hrl;. ;=x!kpUvvG<민je+`ˑf;t>{*ތͮD<6>f?̞^i}" 0]2maA=]:6W 褟0N {Kvlg9S}ͪ J$PbtĮ5W9Է-\/RN̶ IF[`3VEr얁};mKtU <̾6a.`a7f[BFMI qb@'5:$iا_^ݞqxXfָ fO[n{$3{l$ʾm@'E%17t}݅c({Co;6g'eSrk -1ݘme7VT'"r=.]mn=sr=ooIf7}yTsquUv}tmyX0{\]q%QlS PB[{PnېWZ*I tTsOgVƍ.3q{-!5$mEZ=&;:I̶.s͘v9+aTsܭf cRvؤ=wn`c]EYY#r=U)mHF 69Es1r*.DGC2IWI=Y.ʮmA`ne_̶ Dc4\gN+Rs@'ٶA'\N=Ow\ۓ=v=g.ifce]=_%1gg~2ۊeXɆ^$33ݥgQ5/mw#ۖHb*`ةva|f-*yxݘ=G۞-.Whf+y;t=V8 } p7p;词Ya`W2i.{i~eP6=3J.'=WeEOW8Itr$vcϮnORrun*ɬ3 lCNgTzP^T`jNםElCh |",N~}%I9 tUs6f_+>5'e?̞o 1 Ӛ7HbNݚHbNqN̶3\%qO%vGt]E>.of6 g3B$1L.+멼QnmtҘmt2)}Aa -,-҄Y-\u2n̾o`[;KlKf tT^r?m\r_5=(w7l6m,-(ؖrzngn؍df[Q$0NaveqG]Oe6)-l3"s6f:-ɥXFU.\WII]zf_̞]lUJSI!)3`؍ٖ(:̶$ I{ʾ1XٝȒ3uRTsq}=<{EoL?@'J22"r?$ :vYF.%`_ƣ+G+$>.3)L̶lZd'T}̶#$1ێP3^2̪qt7U 3kdOd]m@.{\=+o=G_wƶX ;2^lsh!\"]Qv9`#-gA%1wZ(U[˃f}΢:a@3{ {IUSlۋA'ٶNs2K|zUvc2ȶHbw}`_5`zTԖj!}?C[WMkf+ t$vDne`wf$fI,u3{qJTlsh#\")?w@fCtRkK%ucT'>/'6Ǹ#*X/`J[e'f;tҙmnIFv;]ٙf em:YZ I=_/a۱/ؽ ى=l8<0Vj2vmKdEH$M~ۉO $m.@']%1uf5aҘ]> \Wdfy>\[q, v,6恒 ByDˀ}` lAlA ɽ]vn lMGC_ljK~evZ.C5`?؍hEA'wUĥ_> Ϊq/le9'm0\0wn+'4Im (QIfu3Ε~=Mvu֞Il[ vzv;]mnls$8s=-']JAVj>sg AkgMU/q0x}f/$28{Vg$2E,w`A:%;tKVj-"/׭:aIdK*Om _rW~~G댿2ʣj0/ש2-??suKJ%_rXK_ce[*[8ؿ |d} :[Rvo}[|'0'>;η/ t癎k$aN;Ώ/*痼0g84GN8Y%G}*Gٿr[:ɉ/_rA'qizf֫Գq~>ɽUI>>sO`:s7A8:)%[F䖯T ցKNo_rA'ާKkyD8?vފ$zEa` :%tQ8G;uw_rU/y70~a$L[(5K/pߋ[[^//Ƞ_rE/y֤sǍLq>-WI>`9Γ0Ĺ*痬qyf3Γ0VGd$_3 8{YGdF$8z󑋭8_KLt`_2e[vH%+zZ aݮI)̦/*,8ø;^/*'κn _2_ś_2сK;ɠo"<<:v¿{C Uު$_z38YG:$_KqSrK0'oNNo_A'q.JL.;aTؤ8$_z+ q>>uVI>Qe}+o}[.|~[/9;`:RE8INM/qpva8{yk}_W~~/ _\_W~~ˠ:L[IOy|~ X}{|~msFU| :sUoy]ٿh'e-rEoy%'ؿۃN~y)?0>o;Ώ/(-üD0g;G/*tV+|{;"|dKsQG}-Eo%oؿăN~ɷzaVWIz3Φ-*L qpva 2e[f%Tvѽ Eo"[;ɠ:K'u}qy=N-Wqy+?ٳ8o}6fϦoI[v$-v.ЛQG tU[;'EY[r+bYd=%뤨$fvSwlȠGurqS9<]ڸ<3=z"!Y{d\avs.`wfTIbl#/BN3]*I=3'WWnoT ة;_g;3{~$gxllINl]=ޣ-%MI7)OKG[(IM%f*\~m~mͨ$vC؃rؙ4ft>I&kM׸e+9ɚmѠu[{fT$gEK`_̶#>NJ2n0뾙}]z;Y\UYB$`WO%@'N2:h>J}Q_b'f9v BEw;U`%`K~nm@'JbG윳۝ZSvcSm~dIZkvZ۽b}yIMN6A~5y$u"wmNR} =i H23:]2m؉ٶ.Ϸtɣ'̾Z.egfۺ|b>f<*]vd>egvNWtIVImTʛ{ͮ|] :z! o%b=teftr3{6U\e|V,n̶䭿;W`+` gxK5cjU<Ύ7=(]<-ls׭ռ݁=. 7<($$Iwf5lsh#"]v]_wcM\DG%?Isl5Q1Ƕvoȶ$2ڎf+|{I+==gSz~2{oewfmWum[o'`iU'\ص;g/gK0bB$Ϙ=gwZegf۹ tҘmg6dl}-c'WS;qX;7eqPlY&w&9/Y:a6\cU=b5 8q|]j\_߾ufQdvIfAfӰˊެ B:%ISIf@fӂǍ$ ]ulv*l13e;~^̶c$1{U' ncO9KG8/N2g#h3ȶHb;ѷN{k AfC5:t@'5N31;UkvѶ_vZv9If B lN:g+WIPd~ך2Lgl; vIf 6f+ױy4=:NECSkD7+g38 ?ovjN%`,r6lc=NnĜAcWBǚDl[fJ=M[s %1gPWv> tUsvf8oۂy1ӫnJ6Uoٳ_ٳ['{ޒ"y?- ٳ ށNJ2k3Ku2;+z;Ch[ȞT'Dgs?kvglc3:yT٭܃E4(7 -l!͍ls6$\5}5`̶02If}e׳0狝=ݺѶ=]oĮ캢=.G~= WK侠󷌞- X'uw wvd`gfO1{:U!~ۣX:+JRuoft~'` N:4ļ]Vlٳn.6`vJn̞.U'ٳv XmN9.402~ -h+(;u`;`$&Omb:Uff({\F[ٍvvEpEZ}}]kdlg[F>س [DSIIuW h=ͽ%(`]=[Nnfoy}=Ee|dVvb,Nc |w`t¶J2©fo+7_$vU\8Tك*8wnfѳ roI"RPn.诵gl*:̞MeU')~|.mAc̞-hU'ٳZ{ `?5`z::iNJb;N̞Mh~Ƙ0 %1/m_tlYͳʧ?']a˟0bm/eLyl|f ة'3QuRtLmGI/f(.=6ߣ6(3(`إ;1|l;,|IwbnJ)<~m*}0ۖHbhg3eLz:ڎ NJb^],BRʾm_GFwatļD{9*f-*Ia-*8v(w~\~˝mn/mdK$DV7*S0ۜM!@'O/vl5\o a~rQvNt]ۑm[u2NU̾lj%0 hs :I*a QnWvE7-&l;p$4Ysr!L%g+1VrCia/}c+V;A!l;V$v 8);10y2U''Eg(wJuin>ӛR="l{~'/fctRkE1{܍} ,aWv>vANJB5qPvgܹ®LNU}9ۚRm|Pۏgܱ23If#vwm~Jt DQIԙ][],~mYFF?-52` PnN6 :6k:]rve?NmYF۞qVw3D 褩$v9=Lak^(ڡуR`P:"c_h;dž퉝*>O',[>}3Ll$f6ӀW] _:=ɥء>/\Shc}ϛ}1{yV 4.X'.o;u`̶{10Bg2{:}ewf۽XF۽v/I+z{C$%A: zVrK2U'-w:X(MV]3- *фl $,̮gVvFWvmb ܇W:Jb﹁}ݪmWfmW6wsb)'3.2DȶHbǾT`K40ۮנ uQI[wRD Ueۆ`HĂd`Kl@'7mIhv%{\r?.*r7f5UFAv^Eqkv+Z77VKG!1IVIҕΓN.6S-_l"}vJ5`ٶiN m+? 868f̶t-c"Dn۠_umwkwjL٥gfolhs_"."9 vK;* :I̞W,k?rqsU;ۊ3=RAm^R*w`?W فN\Pf[treVD~}Mͥ&M z{鬒؅6` Pns3;1nlsJN9Yp,M:r7ERv!9\v A נ&7n! A >҄ w[M >* 9BH[n}eA :$n!yA._Ҿ [iq%߭&˭5(Erב%3:Љ"9Ƚ_G%![ir~9%kGn_I׎9RG{<C|Hy!>uA:'vT Y< ,jJc'>UA_;* C|H!>c5A-M: QI(dỔ49(d"O|wU%AiBsPX49(kGGS׎JBrנ9(T_GZw hJ冒PX[[2v;(m Dv;P׼M:( k^8w4p:liz3T 6ƪ$#\r6|hrKTIA _r_~MQ_* 9$~K+׃ߝU, krS׼D=)HՃܾu4ݞ$(p J3܃uaA! נpi{P破D=(sPڭ񵣣)DkG%@JiX{P ̭4=($BGSϭJBQU҄ רXi~W&G4ܗ KHՠI+3߿l?ș{?=Չ&׿Ҙ Ϫ[NdM@'I%!k $6V9_m ̶Vܮ.I]v@eW&[\nlu)YGݭJBa5)[vt4O|$Tv?Kn)rڋ[ml;C$T l-s[tT׎JBe7[ZvÿU4h*3V%`ki _i'HbM@B$T¿YA)H_ȭ)|Vh*v3V%VwOKU`kqIt4.]h 'g[*v'=M1l>o`R\`qh*\kG%>J;7[KSD̶KFS_i* %Ye |vbK_ :/WAK)49eek[dMګ$Te%{[ $jT|WJB_|"sY}m!jxD*+_y|+UZgUY|5h*A%7u2ۓl-vp_^=QI מޥQ6ΏmQ4M>}$ҿe>oـ>}hzLsP%'-l}kfec_:4*VIKo G ~>v;x¯>Ҹɗ>ɯdhzA%n .3jH'̶Љ_p{r nٞS !{T'ZmJB)|͟ւZ׼nOT*hRglwtaK_ 4ZK<9e49Tg:lS-ȭ|S>sWrp`1CD*9[TޠJ||:En-_ȭn\:fBt45*򕦒P{E큾־mYFS3!_i _oZd`k _Ḯtt\)w[Z-u45PX')lmsp\0M_6VFSCY_;$6fu .cϯB=+~6OY5.+yϪq/P}5hjA%< kPGS\:7D.U[.P}߹.ek;T/u4ZJRU'Po`kCY''yMmsݞ$@bk;'}ol[ JBm[>ֶt-O`k<_ #[,&>O jE:Z:eg8U*;=N.̶:mǜE{T%rW(w.܍v<(@DszvM^Zró?4L Ϫt # lQ$Uo`;`@'@'=&M~%fVh* s>0dJ[NTz2z~ -tm RZﴠywfS;-v$H:=`W %{CokmW@'I%b[zE s0:D-*Ĝo{e TvfNNz2{Jz=tlh;Q#ۢo I}:_9$YkU|qT|}WYu[MPW;WR6mI+-C$ [gvYi$dԔ]mٶi$x v-me7Gv\ԱӡܩS.rzD 8tmfI$m؝f:@'ױQbv-8?!lK}vCv'4`{Eo7.ҎfN9񬓦-#{sN-mk>J)g>Vz٦Zmr.xf_7MYl ߈C=ﱇ"{\/Uߝٶd)m"ON|NǗgv?WJ?-MG ɭj<[O:Os0r#Qm I{dv.̶ :mIF٭em$v2 1>uy>W;!ݵɺ|mx]; zaUI`aInN̶53N"myÄ=*8 ;3N2ڶ\di]$UO 1/]V~@'N.fit2urC=W N6vѶmM$ir[s;gs3ی$1یdXfBTK~ƁP؍Ѷm:3-譎Hls6hNJbobqwz=ol Rh@l MYEwF}}V4;:^v3/[ٞ~mm^n3`'7뉾dd3A&f:sve'kTM=Y[ثQ=UlO }x-hםbwa Hk[mOS~=6{ 5{3njhrg;(eig>1cG[[,ͭK,*`'ػ2ۜPd0ۜPd7;;]mSʾx4fp-ػ9+J3kR @OS}&ffMy+t6%6H%ؙٶ؁&ٶ؁&v]jW bdmƥ]m!6`ɳmzFL&",ʫw)+G;O쾊3=A-b9%Xbf'7,mM*mMfSQL>=?ؒtwir{&K ع08C^%vU={SY?]ZWvf(mD}Xbkn#잀m@{*K,mWWY,i̶im'OӛQK"`wev̶+Ф2/'gާ^٭{1~dim'+!_2;o`+Wڱ|M4̶ 49N(9-֙ƙnB\$翸g ~ͱںmKl@Hgb̶94̶4ǯ@v9+Y}cegf+!oT>Rvmʫ{Q=fWܫH_چ%1v^3`lw~m4)gEv;=*~ViaOf^-|R,WKc케$_}ϖIZ[2)8z N-36 Gh7hmb&fﱕ=dvM_M"dORM K e!f l:Mz 4j4jlnn5Hn ' wk@&1v.3.d?7PM!p"`^M 44Yf{ʋg=vOYI퇩 "bs%v'K`҂&Rvϙٹeeof]jTk祖vh0@lMhwIui?)svW');m ,-m s21n@>M.C~ zbiv.YW0m$ێJ=v^EҢ'M@` szX%<8ob$Ķ-EoOoFk@AsRvVeme7f#m"PKl أ{]'͹M @j2Z+hݵv9l z6 ̶uĖŀ]6G 3{1Al KHƎ-_S{%fY/shkOuɚ,2{`l[Al[vA},oj]wfa>UȶQĦҀ}\ge_uVfuNB5r/>Hcτl!#|>30|6d0|6Ф2r>fAK_]4̶Wim#U,% `?{z5+W|ٸWzK=Sbway+h@,H[&g%9djkLMZbS`({cmֶ` Ħ}اkols@ls@vVI1ƾgs{K ,5XfFӔ{ `vہ GZEXIVK ="| arl=e,GnIeb.2軆MZФ@I *2iF_9izҟc'[`Of%OaE&u&fޖXfv]ً2ꚙm3bEz y;3M49]9H;}:6ls<%&ky5]m7`N&㬊.(ٳOegfnlbM#`|69W泝N_<}-9v~fH;}YL)zCmXEKvYhb}Wm+Zb1~Jn;g#{]c6KkMDVM}U;:whsvFMVz&zBO띀6O ٞm9[hV,w`Of9GI>ەW6/ٞ]5)`,Is+1۫&}Tg%zsٴO?z{O`ٯL"fߖ4MlOzɑg+L~ejldf{`L̮ ge$bgjVGjgWn'uw{_ſ*-ٞ;+왁W. ؕٞ-&q%z(EggWM=jj~w;ilφz?yMf=gӸ|qOqUDs,=黵Ef 3-Ȍ:{ع{3۳ͪ&WK'U>waUwBgUM*=sjzn ع잁]޵}E335Cg1>xatcWam>ȶKsz1/`[A/HެwJ}w*4vTl7Q5]e_gS̞[`֤hk.2bW3=wjRk=-}0=oF_軵m3/`[ޤjkHӿc_wh@oݘj/U?=w[ܧ@/Y節XHܨ"g9}0=+}f{>wk C--1)`ldf{(jRr֕bvJߙ5.ɜM`{va]{_==O59yz8Wd[)>+`l{#&Ф%ڧ2{\I̮W)|l;vl;K0b5374WΣ&]U~FWao?ag~?=3E=F~ alTf{&rդ쳓TlٯZa"Ulzkv{tb?WGliqg%)`w=Wbʢҙ]FoW_ $*ͯB%viY`Gv߁&Y[hgӣW_cbb첀}:&gvaMڻ1mK0^!Wilإd%1OdZ7;Фo$3ۦjd]y3ڝƀKeѤ1۳W[?{Zb#-`qlIeg"WMjn~%:w^wfg~WMأՀ]/]OZCh,{]E*sU-Z`_0s,-GZ[T-H, }B_wwg̶ 4Y*i2l3|;6B, =XbU$`fhRmAlYqwO߱l^nB3c-܀}Wfg WM.u4v<;aUV;/WikXt잁};flφ fui5˻rʔ1of{wk FgV}Oի&wص@d>z>U;.}A'ij_u-hgjVvfgSVM=S3: ]2俚ԉv wbg~+9d{f%vv~؍ٞ-\59Ф%WZ_2۳&ٞ]5#`Q^lIfgWsmǽ_e~FBߒٞ+Ad{ַ%v<v;g`Wf{nZd0ު%m'n-եÎ+ֹzYҥ%MY5ǪIagSVW)~UwK;BU^Ag~6ٞ&w ص@cMZ/=BfTU };j_5 lbgWM8>ɐyz菉ٙٞRߖ؍{ }ՁcU }46K׫7=vG?Amm(=j2w%6]Ul @}ُz}p Anm>ޖ ا+}:3+6XMZb?bnwɃƎwee7f۠z4׼ϵX-OW ا+{2ۻ2hl&w="v9W™.xlgnmw0O5. {{0Ǫ&ٞV5i0;z쵷=_ꝙUhn-`N'z) YIVKl_|z=ٽ>_^({?C~cm>۳0n첀kؕv fMXboRk.3{l{&M* Xbz)b?ѿ+ɣєmWIWf}|aR}7f_AمmAhlb=_99WĖ5Ki5+0ۆE6;xL3` ^M.d%<8.w+b^OB_X+={n3%15`/f{Fo$3,yn4f}ifTlϠfC~cAG ,_(kR/ЬPKu*x:GW9_m6[K^}6=mhRyn*c}0,b-ztU;w`W@YDAl[A3s>K~c-_Eok˻̶!(XgK,]2 &Acƿ~Uev UȶKZ[WC-b 2h`v_+@\/c KR:~ljcX;Rʿ}\Zȿ˜(08ޭ)r%W5f׫w,*OeNTlK&5}'s`\QM*@5T{\kC>N+U[Ayb h]3wbyԠIfȪi}f﫜WofG-D?WMί챀=󥵙h hgIr/o&k?{e8{d!XM _k1"3@MZb;ǽSv݉uTvf;6Y,}L{}ce/f[T*hm{d1>k>jA[C.9vl& @_o'wثW%[Ivh2{)+eeofC% {v-hVvfQMmyjJ<ۙ{QӃof۴$-^Hmр}z,kf׶WM.5ۻ>);azW9jkmWbM<l{O`Wf{j2m :jq<= ޭmBE%@읁}}<]AfۂTTlz}<fS`RM*]L|5~4eum'Pڋbsw-ҟuE'/&>Ф/d1sw%ӭƿ^.j]l}?f#'=ˢ*XbiswUtOKjvgf!mrD?9[bSR ؇ځm hrc&9Ϛ[gX^xٶ4%vq쀽+m!M=jfp̟?N5Ǚfp̗3yٕցM#)sz^5s^E&@m 4jt˙f[ٛHk}M2m#M@LW z@-3۫#muj.ǵel̶g.MZb9]gV#GY.*qd]%?&Kc_9 |q̂^E쳺c˯י9h\Vӛ=eIls|=Xbd`Wf[h2uU2{r3;lE#۫b&ǛavK>fmY//sj֍vCH6VVMm?#'c;ؽ{Հ&M*=X_ovF̶~"mh#ۃ߳M`;w`W@8Mw&C-*v?}|&}¯YZC~o;W>?KاK s&9U1πUvg*;3ۇj[5i9`iI}3){3'_B_;!/qAy<.'g@&̶YZ_Xb`ns^=[A3&-hR}W>+lsBM\ }fOժəJz|9v>.|22>},Yb[5r06`َ1x>۱P.`Clդ281>dfBٕv fXb?Q!o)nm]&Zl zؙ֕!ۺXb@/*g:F,1⁾Ψ3w k@m@ O[.b3Xw8cyf "P,i}yJE,Հ'{4.cMZbw0+Ue%f{1ۮ!NX ح;3}l39ly&^{=m7{^mbEwnO6؍vh^bvOKLIng{$_Nkh${=bE[{ TKlq:ϵ(>.z=&d{8}K~ikMMqPﳫ˺J:a=:a7f{8/s\|gg*,`f{]<^ Z]m +~d"-X C=рmK#hrTI>*,^Fg̶`im-PB,%7` \vycma,`& 1`u=Sva{El;$MZmf!z%: fF/<z࿽jـ]O:3̻PA'qz[bDlwfv=#aWf{'Л'zT[>5{Ivh2OQ.dvuu'̶3ii/Xߖx2.f Qxy1.@l漢֙P-л>п̶EU5)̶I ,ybƒ֞2kk\YpR lgA28k"71n >ϙM-ψgv߾Oe&,nqO[f{2R{Ņ%;N ث%܁}7`IUK(v6o֠lT TP[v5N.y+B v fh2 lɄ] 0}:-O,8` ^vK̶ :B_ROC~W<]mhZdG_3ڭOܱXh>qH6.$2qǂٚǝ- |畩&Hnk쬷>ע'"l&2p0`k&wp0D5?kډؚTw09mbkR! |<핗HD&JM;+5+55﹑FFvIؒwWj'E_)nM7ݚc Td'HG7hҨMj-~hIW&5Dxfb&lMD@Jߍ";AߍlMdz?Y @M*&TǯR!&I=q$ ޿t ?~?GZWw?~˚h‹%^xd&HlM^@:BvT'5EGzlMU[{ k ]l>9XMᑌݚf#gLC$Hƀ<1`krdDLx$cHlMu⑺ٚF#u 1G"Q?Yr}~(d'(J>[)OB{mw˓l)KHE Sz¯yP,gǂ2[ ghR_S;AyD?24% = +ǚhQB Z8У;yI C?[4GLXʰ]tG ߡ#.NP=fg)w&C[BhR lf/);,%|'|'W֢m~@_=V+D+DKCvk$8P)+!hGR,f _J~Zң&З!I-DSYX4lM烍ٚW"^ލd_~v IlMȁ&ϑM4V %I>&%IGt?9N cX1<*D^x T&lM;ٚot$~ӄN,`&t@M7{&o$F5Hvk IEv)@_Zb @*4Ѥ~&/; jbGvT'~:MOt$5Zhb4Ѥ+15ΚT+Ll}ㅞg^xX嬙T6&xkDGclM3[N8cs5ǜlMr&f#k%^9s$ X@/PM# KMue)Z~45ˏfM4ˏ&xTja&lMrѴ@EvT>5GlMoˁ&ȣM4a.e8?m~:n)NPoo~ l-&ZoM؜h6 ěo Zw^[˰}ֶ 4bs>Web'(GiQCirJ[ہ;ݴqY q9"qEm\2Eh1[Q)Qf-d0n!;AM?% Z,O"ӭ@--}%lA)wyP]4?Pfk%l-whwB~h}'֪`Ir}@ N /@_D +`kFyhEyhE:%.Ag-Q,% }%AvOFR avr86vr8w Zƽʁ)%kLofx=M0U}2[ 8far4mm ?P擄v'(dz%41DC||7A)b]G .:`ka5El-@-@-'ZNt1ZRf|-IPfV)f'(gxWj@Iͥ[z n!H=v zY~+h)Ws?כ&&"m=+mmF Z[[.[ &NP7?PDȩK?Z@Ӑm~+hZdKEl)rR[>r~h\=Z m3;A_c; Z Z?P }xE+3k?y<)sә:۵1oiĶ&x&v}91oФ@EAb27LF>S};{3o'1o=a{Kvmh4?6ФhkcMZŻ{I!v'l֥vbE3;'`׆|+(ۏY<߽\=mCq~5gع2]mk֤%v6svA8w>.KG(^[toK,,`c~/D[YXRK챱ewл?З=j/ۋ%3݁rnOllOTf{]{z:>>\)Zf:Ʒ6@Zm~C~#j.s9+=R5)ڦ$d %F2(Za"Ulzkv{tb?WGliqg%)`w=WbȐ ˆPC#i Matrices/R2D10000/orig.inpmtxf.gz010064400020550007177000010300260654276372200176150ustar00clevecompmath000004000000065orig.inpmtxfkz#*z X sHGId;_"/_?~~}?qHG~}GQc?0gG?xX/~#H>W_G?^x#i>{>>?>⯏#(_G?룾?dm8?ٿ|#e_oG1ۻ#G?^گ#(Q$D>PI^QhBt!;[w"(~I,D9>OҎB 9^'"(HBd <'Uv>Ib}OD!Y~&DbHB#UT%]8{'!Q:^{#U j֎J'fa9I~EzD?O2No%"I,D9RI>єB3I"Hg(BT#74~?'I;Y фd #B߁OB!U4!o,pD" A=U~7^{߁OHBd% 5+G#]A{w= .^G%8{юJ3^^w#(HOd!~]o <+I,D| фGwLgWJ#$M~{_OJ$%uw7U;IO!UD!YB'&D?'A(D,DOҎB 9^' JD! *UD|b zy =A$HGd% .^єGASA(De%U~]!o.~ET" ϠfE*D|!}D|" (gP*DS 1*^wr# ||D*ў]7^BB$%fE*D;O2xgID9U!!8??F#J߁_EU)'r%fs9Y kFU))$b:#<+I;(JT%Ԭ 1ůHNd)(NT'hZ+1x !($"(HOwDQ*]qk#(NFd#8M~b%"*g%M j֕v3p,',9(Ow+M *z #w\xEr"kORJ4)YWb:y>bp"jON <Չv~݈D]|"H,)(RPDS+1^9O+Y~J4#]|b:wՃ^rD#$وbD8:4j-^&HF3(FT#]|1sJ'U$':գ:~΅Wt'fa= *و~F4#&ht%G |`D4" وD}W4%w`GD<$ (B'xES 1x5{DT"QI~EV(QMXTD<$)(RPDsca:4uziGt"=2]Dİ-""Dt .(N3 ,RX~N"\D$]DALڎ~tNڎpDe' .h)$FSNoKF j/#yO(JT)YS+1̼"(\lD*єRPaq"<ш$~ىDfUDWcIV% .^F'D5Ao:c:$HB6Q)$G4#lR(DR"+Q($*фd׹B'HBd!:ף)ѥfCיA kΪFR"+AoJWT% .^1x~hD2"SI(FT-Y31*^z#]|"Cu^*G5IOҍz*΅W'$ɈDy_QhRWѝviwnV#8΅W$'$ʼnzgbGyWPP_U}&}M^ ԯiܫ]m ,oK8Qfl ,ƯI Vm , Vl ,L~OB]na1| =lRda1UMI_ਉaAo@ IZਉlRTW5i&}&w7&i&IQ^դzgAo$o+`;$K`ŧp}v z/{`'-pԓS ,V&3x_y? f| J>هߠYx?@ ]9#,p;`{,G{K f:(`%Qb$@Z$%uix?Ƹ"+_#\K :_R$&a_2 -ҕ~. N$1XFtP/^ͧ_4]Z`ᒨNd zihzgAhYI5%4z W` l5 A3$uH@X>M{} b`K :_R$ ,V&>COJG>F÷4={ W`i a1$ u)*ii6ܫ  _ D+H>yzat pW3 >ц{%* է1X@7HW+t T0SlWi>{uBSikT z|S%ͧ`Ål@w>|uuOaR8j EcA V*|G=)>bBf| J>هU OcR~ yBh"`钬.T ~aqu*i6ܫT>i3>|ҿ|wE`Rh8lRդJS̰)n{L f.*rILI7cnf$0hL2*6ә]j%0XN4Ii6)&JMi!34$^o ]Tc3]%D+I&Y3-&դ1XN7xR Idҝd%0bRM tQ#H`ORL%E{]/i%  NI $էI`PҜliɇo'hd3(>JO_'ÅF 'J`7ŧJ`OWL rԋ:÷4d`է-pԓ3w: ߐ -N7HxE^ͧA*w V*}GMd½%͆{K + :^$ ,KE^8~ o8'U {=+]m0rIU^Kq pI\w%J5%4Kxi@P/U6i$`OQLO^gTT ]T\=/6xR\*먑4{]4 CzjLGM$½I5i @ VjAӦ f.*tIX|ttjAh >|FsL6)O^wOZh&t*eI>^jҸW&iLT0SlWi>{uB3_ T z|bRUW3&c~AsAP^4$QŤpfMG(Bhf2H&y&IU^ͤF!pa1$ 4/xdO_'ÅF 'J`OVL%U{. J^&lRt4 ̴k }6$682٤`I3f+ {I{}6 };1.x48]l0xIR^o('jt6 -N7D!@Lwa}C_-ԋfE40$`ŧ.pԓ ,$>Q3M>ن{÷_4rtC>V?_h $G=T&Wpiz'_Rt4 ̴_2T4^$ ,KE"_R8zIcR~ }.4P/}6i$`咪6ný M|0m5f5F=LFxR{eF|ܧaAG`R8I6)ii6ܫ ~mg D+HJsG{K f/*j%$_RT^{OG{;hL%Q{.%3m]cIin 3MY`Uit(а&0Ө4fZ4F;LƐ4m`I4I+idrVfT`Xxa1dU|O^ͤ t% F0ӢQ5f5M*iЈ3E`M߂ocN3_ -[05Ң@3Q[xda1|MdRtfH@L`&t| X J5-+CQX-p51u$J@XLHD.p;`~-l#\OὧiРT+h1.^4Y^l0xIR^o('Z~W }-0 Qg7d+5)>{UTc#\O{e{OA V*0\h~QOO<|T̴t5\hc}x 8G{K f.*q=@xiqLS%ͧ`Åq EGmlR8j4 u*xR= Q#JA V*|G=.4n@X >Q{| fZ| j>݇6,h V*}GMKE^8~ +'U1 {E=+]m0rIU^Mk&"MI^ਉbRUW3&c~~L :^$ ,KE^8~ o3'U?/^lK ]% ,;E"\8tIfRr }>/6xsIP^KfMIeҝ ,;:Dޯ4OY'դI`P`CjI>|;QI V.cvqj?>$2XNbRMXmͤ +K $٧H`OSLϰVo'xG$`7HvIgRq˫WAa1~CZ-ܫ\Rm0vIW^;h pIQ{| fZ| j>݇osⰠ#0X@I $էI`PҠlɇU6 %|i|: 6xJd̴\RUW3&c~AsAP^4m$QŤpvIL4N*`%Qb$@Z$7T+5i`.ҼzE8}:̴4}㞦TT zR|%H_ ,KE"]8S8I/p; H8IIU^ͤ ~AzѸgLGM½I7   _4$^6ný i||f} dQOO;Htq4y uI*i)6ܫ4>Vix3.4CT zLfZLIcҝn2$4`;$K`Ť4+CEFT^KbRUW3&c~ASAP^4[Wa~C[-kܓhdR!.p@X8j~ wмeAh"`钬.T G-0n^4T'`%E{]} f} #qOcA V*P|G=i>p/ $}= Wuviqҿ<1{.7Z½74Gp^4U ,o @{oh* 9WDu*i6ܫt6,h V*}G=>bin2,yDL0dMxhb4+&CLGPLOL%E{]/i%iz"@X>I{@Zoཧný 4DQ٤pjLGM s$-pD@Z$%mF'U >ViptIL%U{.4n@X >Q{| fZ| f.*pӂzьyE^'mէ1X@ bIST0lW.o D+HMU/i6id`ij"H@XHD,p;xi>b)TW?F+E"^8|IaRzI^ͧ_4Y`ᒨN>Y{].%"1G. V.ὧb ,v!#`'pS|Ҡt+.4X>''@XL>Y{]| j>݇<,hB V*}G=>"Q/i N wbIST ,oh @{/QbQ [Wa~C[-k| 7Z ½7̴4} l.ὧ#]%34udHbapa1$ u)*ii6ܫ '2X@ ͧK` i6+d>Vi5>JXhO^gVfýpṶ k.cY÷4zףÂ5L J&٤,pD5i*~ɐEZeFdI2*i6ܫtޯ:,h V*}G=>bi3T4]T$a1_R -QKxy? ~W/^lK f| <NAI V*}G=>bj< zR|%Å:4D|4TQdP/ I\ਉdUW1&m&P^4QK2jKg&1v <)hWu$I@X̗HD-p;g,p4y$`4 qiͅWz'^T#k̴j4~df5F>LFhi 4Qm@Z$%qKG=)>{| f:<P OI+d`է-pԓ3wF( >I3>ņ{UӹW7.4P T z|T| ot* FdtT ̴tޯOAcALI2 VSLfL 'ݠ H`'~tcP|* 0 CghO^gVfý%OJA{/I%"Q/i N7*u=V.6i`%]⸃ HD$.p;`&Ň=tg8פa1D u*i6ܫtE V*/I V/)ܫT`g,p'@X>I{} fZ} >%D1 &q&IV^Ť&Cz`8j"dULI['gb T0SL~Tfâ~ՠMlRTW5i&}&EQ^-KxZ&{]M Wâ`I4I#u5i&_k s&фk$|*T̴]U@I &I@ {P?C^k.uE8HKG/) VQ}jKxp̅ztvEL%Y{].%"1\hۀ. ,*n>]3.4ZP/=\h} KjK6']WD4]U*n>]3.4rZP/;=IbҝlR$0j|xh5.4ET u2&_4Tv&Âg@cL0dMxh &bjH= :^$ ,K$gF>= |2&ŧ2X@ da1D 4d`;դI`dXМyN{ҝ`%0dM T&>C[MA0aJ&u1&_43tq! ~h$LT| 'ݠ#@X>I{} fZ} &ÂƗ5L :duJ`ͤI7h1i4I&JI=^7nՆ 2{M 32Ť`I7Cp&Ʉ&bRͤ~!h 5}:̴4`;Âf`$$+>bi3T4mxEs3͗uI@X엌H/hh1i4I&JwILI{;h1qF&u6)6i`%Ciع"@Z$7$+ȗ8){O{/H"/I N0XF{o*p IbQ [Waq|M8jp >ɇo i5(>J'ͤpi4D`٧,pԓ0Ӯ1hLFHi(TU}ܫ_2hR|ړNF4YT&u5i&{uaA:D/'eI9^WfḚq{L 2٤`I3PfXශ&фF;S8IiϐVӰT0hL2*F   ! (&U{5n284EA2 5Q.vI_w 8I%b1*ܫt>Vy(4Tx+>idra4 u*xR>< f} >ŧrj|: TpԓpI\w%J5OeR8pgbU0bRMt!'y D+I&Y3-&դ1XN7xR Idҝd%Ť~$M&`EL2bRMxh&iT0SlWi>|ACpACO*|G=I>bU0BI#JA) V*P}G=>JA0cҐ$|G=)>b3*kX(d8j"$MI]ਉfUװ ,pD4I*+QͤpaAAXਉhTW6)&u&IW^ÂQ$pS.^fK?SiJCЈ_4!k >hC{Р!4f?$ .6k(Ќa$ 2Ť`I7  :$/dI=^7n;h.P^KtI>HKG=i>h4:3 &$1XN6)i5i&Jw LI4I VMfZM 2?wȽO{K 4̴_2T4\$ ,KE"_R8zIcR~ }.4P/6i2>4y W>yXxt'$ 4`;ͤK`Â*`;Q٤pj|: pԓ ,&,.>U3m>݆{ eTva l5 kA3>Ɇ{e* fͧ3X4=''@XL>Y{]| f| .4yбi3>JOY'է@X>COJAc:tIfRr 4y WdIi"`'pSL*4. D$fbRtt 9ʀ)h٤~0%LzXeEÔL4I%"Q/i Nwo ?ZWe} dQդp3\w,T zR|%Å,4D|4fKXYˣ_. 4D`;٤H`դt+4L3 &$1XN6)i5i&JwHLFH%"Q/i Np` 4]A!{OA) V*PM ~j|$L:d/dI;^wa4xN&لF#jdX{ dI<^'lEL5ii7 4<`OTLO^ŧ~8c}xfQOO:}4M,88IIU^ͤ_y!Ad4I>JO]'ͧ@X.G{| f| *>էqf}xVLfMIfҝbR%0fMxWx>F1 i4I&JO]'ͧ@Xw'J`OVLO^ͧ𱚇E1 5M &Ť.pD3*kXQ$plRLG=i>pi? bSU0mp?>|`} dQOO;}z4$}4`; du0&{%lRէit: ԋh8j"UMI_ਉaA3 &E{Uf8jbX hýOƠ4+&[M3A0I#k~рbP} tq ~l򇤑5xhChH#M ԋ h8j"UMI_w4g;T#\M'3X@1fM ' :$/ dI=^7nՇ {M M2Ť`I7H{MI^Yu3&{  :$/dI=^7n{M 2Ť`OWL ԋ蓸W2>JO['g"A{} f} >ͤ3Xpab0*+dQդpn2\h_4Tv&ÂHL0dMxh&{ME)B&u2&_4ETvi藌zƋ+jKF{OG{K f:H4(`%Qb$@Z$%ui>};h2zQOO<|T̴t5,h2 5M fMIeR8pjbU0SmWpqUi$pdMGMT½ɰ GM½I6) 5QM >ÅgDÔA V|S%0fMxVAALI2 VS|tޯ6h2hLxh̒)&{L W 48u4I&_4zn&]7~4'dMF=LFxR6dI\ਉdUW>{5ÛI7h0i4I&JwILIÂ`'-pԓlR$0jL: ht' էI`PҘl ɇi0(>JO_'Å& 'J`OVLO^ͧZ JOZ'٤H`դt+.4<''@Z$%y)T+h>J M38pIdRt =>U/i6idw]h"H@XHD,p;դ`ɰ c2$`IL%U{.4m@Z$%qId+(.^ +xI:HKGS/i VMGIBh4H&y&IQk EáA0 5L_4j4 ]!CF9>&hCIIQLO^g m2$`I69Mu7<dI<^'lEL5in2,x*4GxN&ن{jt+ ;t.^bK _2$wF+E"^8|IaRz =K݇> < DQOO9X} <)9zt|2&ŧ2X@ dHa1D |i(Z½ϰt'D |i(z]TcU<+^l0lRL*4.  D$fbRtt tXEAI V*}G=&M3&Â3ߓ(&ESAi V*}Gѐ ,F$>E3>͆{uρ5 OdR8IO^0mW>|tfPMGMtBh3&q&IVLO^ͧkXмT z}$gIi6ԋ&** S2ŧ.pD3*kXц{%{O#Ai V*}G^4pU ,&,jýOOÂ&1`'-pԓS ,V&vaAWt'D |i(z|B#_'`'pS}XYΠ' MuaDta1 ui*i6ԋfE*'3X餘T|{͏J5%|COJG^4y$>i3(>JO_'Å 'J@XL&Y{*Mu>Vp΅zhwEL%Y{].%"1n(?qo D+Hd}ܫ^l03lW >!$`ŧ.p;`} p|xc(&{L q W D|NbR} tQ?pa1$ u)*ii6ܫ Q'J`OVLO^ͧZE V*}G=>bi3T$D+H>yzat p?*i6+d>V{1>JXƏO8}:̴^T03lI yWu$I`٤T+i&]34+݉&I3&Ť2XN3鰠 0XN$-p;`վ@X_@#Z#\ߐ - d`է-pԓ3w: $ riԤ_//>!2XI{K ~C;HKGAJ5%4|z W1&m&P^4mQ$pbRMGMtBh~43M٤,Uiz(А'먑4{]44t>&>" faDta1 ui*i6ԋ6WH&{].%"1=I3ߐ$}&CaRzf.*q́|:duJ@XlHĸFN$2XFAr4̴_2T4]$}&~CbR|fZ@Zi`k.H$'`٧p|BBal|IO\''@X,>U{| f:R{.O^6nýa&IR^٤h&]{ DL^GdtT ̴tސnj$0hL2*6n»I7hj4i4Iy.U-]c(4&$q}G=>bj< f} >Ňip2ht}ԋƥ+ f/I*i)&4x WdIiι"`%Ib@Z$O;Ht!' D+I&Y3-&դ1XN7xRa< #~Q.^foP>C=JMi,3*4k_?Gb`>b`>b`>i`>b`>34udH"MWHD$-pԓSդp3\x4jQ$pS}xh6>_|~ҿЀ8IIO^Wf·4Q 7$~ь|E6qYu*xR= (&U{5n284EA2 5QL j&݇> $$a1_R -QKxy?MW/^lK ]% ,+ pI\w%J5%{Uv {O3L0dM *դ`ɰdI<^'lEcL5iP^4BQ'K`OULO^Å(O+4LDt&ń'fÅ&4DLIYਉjTW74(='$J`$+ݩ&M3&¯|ҝ`%0dM T&vaA3R=>N0i2&JwILP{4FZਉ|I9HT&vaPiVӸ uxa1d zihzgAKI5%4x W`oHbIST0lW.<[U OdR8IO^0mW>|`Q/^n;hSLO^'ӐgPMGMth3&q&IVLO^ͧkXT z}$gIiB4&JwILI5i VM.p$'`٧pjLGM Mp$-pD(J'Mp4o)@X >Q{| fZ| j>݇˰9#0X@I $էI`PlQɇU I]ਉ%Â&/dI:^gbEL3aA ;'1X@) gHwi*iI&{ebRͤ 5h1hLxh)&{L W 4u4IJ'Ej4+>c~Q#@X>I{} fZ} &ÂƗ5L J&٤,pD5i*ܫ TpD0*+idQOO;}&FdtT u*P#0X@I $էI`PV0T0lW)>|ҼrE^ohιƞ+ :}C>^½I7 2h1*xI/)zI[w%+U9 {<+]m0rIU^Kq kpI\w%J5%4z WdIi$"`I2ὧPu3&_i0Bh."`钬.T ͤpaA3AXਉ$0lRL*4~.4D*`'p}܄KTfLpa1$ u)*ii6ܫ ͘U4LfZLIcR38 =$٧pjLGM 4@h8j"UMI_ਉa~TWQ#IpQLt5,IXਉhTW6)&u&IW^"&I{eI V*0\G= >{L ~QM U~4I<^'QtR5 _ ?5Dta1_Rդ~ծ1,:Dޯ4I9^Wfպư?`Mxz&{]M Wb`I4I#u5i&_k @g`MJ٤@Z$%m T+#\/^lK ]% ,;h؀Ho Vj.L7 hԤ_;h R^K:]% ,KE]8qMPg'X.^býOὧ!apiq+ |C=8i40^1l4T -N7#MWd̴|C J 8IO^6ný M|l} dr&̈́aB3qIw%qId+(>JO_-^F{ xI:8PW@Xl_g"M_'@XL_Tz|B_'`%Y{]| ]% ,;hB߀|fLIaҝj$0n2,hbj:*iI6i`է` a1^ -QKjKxP @X&I3>ņ{Uv <)=Wu$I@X̗HD-p;g,p2Pb$&K@̤܂`t_'1KExcf/)P?3`3XΰY/i0&JwILI3 V3,h fLIbҝlR$0zIS^gV`t'd ̴\RU.aqX<@h6&i&IQ^դ4*P/k IZਉlRTW5i&}& LI4I VMfZMIgҝaA_0pIT^KrI=HKG3_iƼ"`7HD)zI['gbA#H`ORLO^էtM mߓIO\''@X,>U{| f:\hn^4=yD>Vi2>JO['g`i2&|Ҭ%LT/ ' VaD$f?4V4`Åƪ$HD`&Ň1T`Јxa1d u*i6k(4D`٧,pԓ ,v!#`'pS|X!Ϡt+.4=''@XL>Yg7T+5i`gؼzUu4~aq4hDQ٤pjLGM Mb/<ܫ\RMjd`i*iI6+٦͠t+4z`fMGMdQt44[`;$K`Ť4+&COJSA0 VLfZLIcҝ3w FdýOGn OgRBsz|%0bRMt!' D+IYh1>JX~xL hLGM½OkX$T z}4νưic{L M2٤`I3)BfX谁D |i(z]TcxxR8IO^7d,4чo'h1>JO['g" @A{} f} >͇U H_'.pԓ ,*n>]{=/%". N2XFF/qI잠a1^ -QO%m +4]A{iptIL%U{.4:n@X &Q3M>ن{ӸW3 5\ht^4hDQ٤pjLGM 3$-pD6)*ܫ4QÂAEGi Z½7tÅƿ`OTLO^Ť4+j.45P/=+]m0rIU^KqpI\w%J5%4z WdIi "`'pS|xi4h>J`Mxh`C(_4it >x4 4!id½@5ii!34e$$+&E3&ͤ3Xΰa/i0&JwILI3 V3,h fLIbҝlR$0jL: ht'kʽ@|_h |{O3FcF?T  4cm4MI#s,P4ߧLԋN I\ਉdUW1&m&P^tmLG=I>bU0Bi$`%Y{]| fL|B~^g.JOZ'٧@X>M{M=CjxNd zihzgT#\{O{K fZ/i*~ɐsI8HKG/) VQ/Oͧ_3 >3Mdu1&itq'H`OR^٤h&]{ c8j"$MI]ਉfUװh?&a&IR^٤hHĸ,p;`-٧j42~$'j:F) gHwh*iI6+ʽI V3\hۀ|+W"3D1XFdpBӟ hK fZ| j>݇>  ObRS8IiϐVfLX9M&zat p9M3 >ц{%* oէ1X@  tbIST0lW.U I\ਉdUWѨM3&Â3ߓ(&lRt4 ̴ iOLfLIaIhJwA)/i0iŤ2XN3鰠A 0XN4Ii6)&JwFkA?C?$QWM 0h.cF?DfbýOBgyRpIdRtT ̴tyCN :$/:՗)&{L W to$~yG{K f/*j:"H@XHD,p;է-p;kO@4Jx W$`咪nt O6 -ᒸQO%y)T+4n=8p&$s,P4F^Mk ~~(L5JYhTUFkA?C?$QWMs3.^4\l0xIR^KzI;HKGACJ5%4yd{ OcR38<I{ OaR8IaOjA f!J@L`U@X08АwIa1}C^wI=|ό//sMOn^dK ^$ ,K4 4$`;ŤJ`ͤ~}d fMIfҝbR%0fMxWVAALO^٧~h|: )pԓ ,&,.>U3m>݆{ E=XY $+>eTv&Â4OxN&ل+ ]%ÅFGu$J`$+ݩ&M3&Â3ߓ(&lRt4 u*xR< #Qŧ2XN3鰠 0XN4I%"Q/i NO@4DQOO9X} |B3G}O^٤\RW5i&}&V ԋf+h8j"G-o^ hR!.p@X8j~ _@5JM5ep ]ⰠRzd/^'ӠiP}t!' ~hLGM½I7   (&U{5n284+EA2 5QL j&d,p4^T#^C45z W`ͧpB='1X@) gHw]iL*i$`%Eb@Z$%cޠ DhI_W3kߑ{ zA3_ ,KE"]8ܫ^l0~PV,zE/I|IYw%J5%iдBh>4mdQOO;M i D+I&Y3-&ՇFN3/4|zz}S$է`gP/W=4$`ŧ.pԓ ,fa1\ -钼QK*jKxi5.4V='>q$|aT ~iW4up;`4M9SoLH;<)_ ,F$>E3>͆{K F+ :^$ ,KE^8~ o8'UA {f=+]mW>4tQ) P/K=+_RLTfÅS4D|NjP} tQ? ,F$>E3>͆{u¿Khr5>JO^'ŧ@Xl>]{=\h\ULO^'JAi V*}GPFdtT ̴t5<:_IxI^$+ը4|kAf.*dmW1&m>cޠ!`;$I`٤T+i&]3wL>Q{.%". θ?>F:tʗ̴^T!4^ ,KE"_R8zIcR~ }.40`Ϥo VjR.L74 h݇ $0|IQ^Kn2T^$.pD2*ܫT`g,p4z'I`I1ܫ4QÂYEAZ|*T̴]Ua1\ -钼QK*jKxi6.4T z|S% ,KEbA:hD`;٤H`դt+4q3 &$1XN6)jLxh4m`I4M&u5i6ܫ pD0*+d`է-pԓ3w' &Ʉ;hf)>u&IW^C"`'-pԓS ,V&>CO~LOk|2 QK:j;h"}+^l0|IQ^K~8"\88I)IS^K. a1$ u6)&|F3aQ~LxJЈI{} MKpP4Q#id ̴T`;dHIۏI0 VLfZLIcҝn2$$D+I&Y3-&դ1XN7xcL"$,jt |@G}IfҝbR%0fMxVAA^GfbýOܫ M0O*|G=I>b5}.{OÈA V*P|G=i>Cpԓ ,KI{W<ܫ_2l4xE#Gὧ9GͤpaAAXਉhTW6)&u&IW^Â!Q$`%Eb@Z$%cޠ`{<ܫTQO%cޠ`{<ܫ\RmW>U{| f:\hb^4yDĽI) VSMf}i3`'`Ť~ј%MF(`EӓL2bRMxhf&[MA0I&u1&_43y ׸) 4\UW>|[HL5in2,:G2$`I6Gu7f8tIfRSTz2<M.O^'jýOkX\T z}$gIi"`I2c bRͤ~š@sA8^GdE3L1fMxPA `I2FͧK` M3 i0>|[HӍA6) 5QM &Â5L f| *>Շ&;?۟/4xz}S$է`"/ o2ZW+Ո$|ܫ\Rm0vIW^0mW>{t <) a$2XNO^7nc{M d2Ť`I7JC1p&Ʉf2bRͤ~@CA8^GdEL/h6n2l4]T$&SLtޯ:h"0XFϙh:prIL%]{=/%". N2XFF6q`oH+6t+6Xh$`&4}C JMi!34S$^o>S2XI3>Æz|xi5H>JO]'ͧ@Z$4>ਉ`UW2>JO['g" A{} f} >͇U ̅|ҝ`%0dM T&vaCh&JwILI5i VM]`t']8j\R -ͤK`ÂT`'-pԓS ,V&>COJӦG^4^z$>Vi4(>JO_'ãҸa1D u*i6ܫtQ P/<i@X8j~ _@ qHp EbQ [׸8 4\U,a\R -ͤK`Â&=`&4}C^Ej4 5r^4D$FѨiOJG^4y$^8j EA0 5L *>ՇF/3/4yz}S$է`gP/Jh $٧H`%Mg7/4yz}E"_R8zIcR~ }.4tP/*7Z½%{ݿa@Z|hNߐ -N7TU/i6  t#MuWDu|iq܂֯iw-k| "|_$~_T !Wp5Cghw3kߑ{ ԯGK@ 1\衂$'K`OULO^Å?!z $+>eTva Ex>VATzLf: :=~`T z}$gI`K :_R$է`gP/zH#DMOfRS8I ^KtI>HKG. V1L4z{ W$`a^ -N7mNwl -N7WU@X엌H/h",p;`٧,pԓ ,v!1#`'pS|fQT`X&фNlRդ~x)3,h^o'6?61I 2$.pD2*ܫTQd({ 4F^I kʽ@{t&4qI#kU.6t+6Hۗ+6d+)64+6ǷX8x~|R`a1~MbRl._S8jvXht^ F{,pu~iq2h S&j$ u)*ii6ܫ ~^tЌiLGM$½I5i 5M H&Y{j8j EA0 N \R88y͕?i0&JOY'է@X>C[~| f} >ŧrj|: ;jK">/)6i@X08꿤[W U,aT u*p?6+}N&٧0X@i ],?>A{} f} >͇M.^'D&ŧ2XFvqj?4^T٧`էp~ɰK :$>{(&{L W $`I2Yu36kx =hM'1X@) 4 ̴ z.Qƿ?d"VftgX4D`;٤H`դt+4L{.IV^Ťk $EcL0XF ~^Å E3MduJ@XlHĸN$2XFF(r4̴_2T4B]$ ,KE"_R8I-pԓ3 -9ꊰQKjKxipvIL4)`%Qb$@Z$%uit+zE6i$`%Eb@Z$8E=QR&id ULI[ਉn2T͏$.pD2*iJ']c(мy~|ҝ`%0dM T&vaCht>_4J^lW`էp3\x~4J`'/pԓS ,6..4 *`'`钬jt l5 tA3>Ɇ{e* oͧ3XpaG= >bSU0mp˃UdOZw%J5%|;AAo'H4[ >'qd} TQO8F(piqF/STz}.t$'`٧p|:&Å&3ߓ QOO>X|ttgAh>|'/) V:M3XdX@hn3&i&IQ^դt+4m`I4K&vi&COJCA0 V*|G=)>bBf| J>هU OcR1$Y2A#JpdMG-Po^ qOG-n^dP -N74.64m@Zo+^l0 Eg74+5` h τo Vj.L7 !7#53 Du$K@X,HD/pE3/I6i`%Mbd@Z|AcG8HKG/) VQ/ὧ٣_ M4LD`٧,pԓ ,v!#P/ %|{OG{K f/*j%"/) N1XF]LIYਉ$g= |2&ŧ2X@ da1D u*i6ܫtWJsAI V*}G=>bjJ= f} >ŇU>=IgRqϢMT zR|%ÅFG4D|NИhP} tQ?H ,F$>E34u*xR= 1#Mŧ2X@ da1D u*i6ܫt>V#0X@I $էI`PJ=ap} *>U-]c(d&Q#1X$ ui*i6ԋF6m'3X@ Å&`OTLO^ŧJsA7  <dHY,pԓ ,v!)#`'pS|gf-T`AV>@ $ŧJ`OWL Xԋ,*Y٧0X@i Nwo'>[W^.6i`%]⸃F HD$.p;`{<ܫ_2lIMpWu$I@L,p;` JOZ-ܫ|CU^ͤ AzјhLGS. V.ܫ W4^T"a4 G>= K dQOO;/_ {EXw%J5%4z 0 ]gxF~RpI^$]4{ W` a1^ -Q Kxipqi$`%Yb@Z$I8\h :D4dU|4.tC4{z}S$է`gP/s=O^$d+(>uKGM p>Q3M>ن{*݇Of=G=>b)T03lͦMI^ਉbRUW3&c~A3AP^4O$QŤpfMG&=BhH&JwILI74 4$`ŧ.pԓÅ'u$J`OVLO^ͧڇ Ja&IEj}-=݇a8IIO^WvaCh>{ETz|B_'`'pS}XǠIBGX''@X>E{]} f} #JcAUdI=^7nޯ@A8^GdESL1fMxP `I2H\RTt+5Iif'H@L$-p;`]ˣ_4~Y`ᒨNd zihzgAT#\{OA V*P|G=i>J#ĿmW{҅47kqucMvp_MČtD95skpI2&1ޡ.; pCL5pDj7QaSהmkNKC:6ݧx{7z _M>¿HWWx7{w_ү߽SVv1]ywĞuW|{w~}:wFo5(u^NbS'F?X#ۼ׹4ux߿UFu颳}4G\ܯ{;Niwͽ댗_g{{$ezw tw+ܿ8ۻoԯ]˻Y_{w緇N:=Dn:,tyn:?#ub}#{MrG˧/Nߝ^_I-Uzw #w|w*>& ;"Lݬ%tM^6i_(OJ?ïiLʯn-_?ݕ[ t8R_y7zQ|@>qwJrCrOj1 ]ݍΤ܈ۼF@i=Z~t E_C3WL?nFֻ?fNըϻk~E7%{k}M^?tFQ}w|>  % Zk [@GI[s@7Z蹢wYw K~e߿Cn^?&t Sj:B }sgaww@J+!xw+٘o\?=݅RBF ^?#Flӓ&:}b= pWi4t3<7,-O𺏥]Hݍ_ ג_{ b[~څO΋?=`O$z) henu|{p)wwZ7;g:O{n4 nڻ.O vނzNwג|zßr=需FoTݯ/~d래>tEJӾx:Ɲ~:UxaN2ק_.^Ik}&Ut#u[_3orM%u_=4uBZMm?-~ZjGS2;\4Lg|i:}}z@﷝M,?1~PB)~z_}74 o蝏>_1+ O@iW>|}Z.vVawJWpzF}W :ss^K;~`ލߟ|:k[k}I _#Wy?4.4t@WOl{wt^}:FK|ڿy#]K| }igγ9[M%ݺpيNT]GtgHwԳ+]i7[|J_iC|3pqgWkif=֘{_|Y#']Ӛ&>z}G:Y4Ct^MᑻϞuz}y4W}_%#.{F:eO;j#sZ1d@^&q>}6;3zhӘ䫎ُ.%irO?x|rB7.]iOk4O蛦u/4|5))k 7MM*^|_ә.i{ sïOgzݘiJ?87stǏDtοnnLWjGzݓA4uO}zzeع.IO~~zY]n9y軥tun0%Ow?]+=5&i^wȕ}э+7kI^0Ocy{Unkzѕnӎ]Rvtrn~IW)Ot6 ]{y?_Qww bfϗWxU _uD7<܍$iǏD~%];s]|#l{ =ō;>.A_tj~'r]`cNj?_m#ݔ~mG 8|K FOO\7lO=OO|=ijm-ϧ#?/ė~ӵSx>-nYDwOcz8?=?y'}v0w{[i#N_n퇻=[w|%>YylܗiL7xZӕgu:P ӞQnnSʝWS~{wg4w#]l/nϭ驥M/tNuKHsN:x&~ț]#:A=VtYhnW:ݽ=MjЙ8ݷ)?=ϙޱݎ.L-NtwIlW=*Dfn߈1k枞@z~>?=,y?_ݏ.=c*OT^{7|*{T~D:}ԓ}{z\i!}+|9⯐豖om̶(^iJɐ1ghn{ھ[Umw[=Őu?{{˻Ӓvӗv3/?Ч']8{:gni@~VVS:; 4f+zQߤ44=9;)ͻ31zjˬ.|z!<u0_zu4/Pczz?FEMf#NQ%~*?N7zv-$~FO8zغ1?MMhoןrzߏ32|~?AG ?̏I=7m4YR MqA+zDOez=a=*?i~?9E 4ߵsLK):=1*=P+tNtS[Jτ/?<7zޢf~l7zd/*)]ФNO4zеDz1'#=b@OkI!g_~g.N[9JO5zTӓ~[.F$}tF듍2oy}/czof_򇞼O$^Iw\n<'3@FГ*=:;еcSAzB)=NKyCTh}8*EtRL>Iؐ&ғo,mOD=7S_=w~1Ct2=(dO>AgK.So߫˵_.S߬oѕYט_[[LKg.uD/S9Aj_/t=J<.^TE/R =|V xjK/tݛ/G_wz$sT%96j_/tm:u'h0M;eS鹖JG=MK觕~ rW ]ο;=F[Ci_/teJV_6FK"Vg*tȧ2^U鉨JFG/xыk=\x~e~Lt9|{N/ }蛥qܬ ]S`Swy:;*ra~?\Do_FSnwtyDod:Nz5K.?B[HOӣҝ.%At@מw23$ӓy?BGhhu U@aitϋY"iX4>H"^Cwt 4Ƅ~J/t'JMj+U~ȼͩt'ʯ i#oD~F+t~)Dc g~t0z+DsZK:$跿=읮hDQ?F:oXvߎ3r@9gJC*]4oHc: b駵?؊oS|`|A>AP=~tϘ Et=mAwazӫ/%$ N/GynK( קݗ~=93G':tE=#?^M-3 nO8E4|;C2ctCoBX]FP9.Qe0>y?T8䘮#tC(K|?:E|VzN*Bы_S{SFϱt 6ZJ٨_@|?:KzV:| Jv7zuh Ӯ;D@?k?A'|tMG::_s0sѽZC>StF?L] PtV~~?/٢?AwmЃ |IO^>=tAwč܎.AYlKo=χ OtO\s3?HwthoSɯ^H3{ Q9:){Dc|=^|"~I.k^ ޯs[gtY#;e}1`;5jBn- C E+<* ETParY*%IPjh2;+WҌ{6{{NËRIR(HA(^7Fg17?<:._K1"| ^:K)bוF{j@[YV?"媰,AT׈hvԿo#Wy˫1$mJn\XDDğop]kBMhuRYWb[9Ny ,@ȑ6mYajrKN%T4nQlYƌTRS UH U+ ٶ=dgpy="7ΣvǥG"{H Ri?#8zn7n\n/zCWX2rK*Y6j8"'%v~0Iy7Rzڅ}![ |ؖүnMNz\:ŷ"8ǥ^{Hۡ ЃqI @稉!$ %MkRƤG!g[[9P` }qp#2w8d"#}a;SvB/H +Ra#@(Ji#+HgԄa@Qo2 {! ?N"Rè- 9wN0׭b4iMYthEv#ޠ72Wά>WRwg^ zóś'ͯ}s\|זhHҗZ" k>.Lk(-. TӖOx(/b+ŀ;J=T^tD)ps;7X5^[ȇf R Z*a-|Az | 2mє4 |^"TVKk.c{ .D!/}`UχR=.(dP=„T Px , I4ljb=]f8 _(r M`)p('ċv SNX,v  χ\Im@(v͋r.[Z I@eI8e<ڼJUD߉ "*\00^TdPFZtjaZ,w|:AlC:&LSE jr'N\Ḯ~K4X]fȶ@d3M>NCE ɾlX^qĢ@ 6͠Wˡ/Q E"'>.N>L$+7X&$ɩh}f e sQ\caEn۟c̓9M(ª("fR[L'JhsE(NK:(3elbE#=wC) 2 y%;;@9-+TsR;Ћ6נeكBeN/$Ba:M?R"u\>>l pD dJ+pݛ×*T.28tTUheCe v!EZ])R 6!E,c1_@~q\UXAYSk?(_Ž7]nAI0̖P Xy$ø[K_bROhoJF_͹HΙֳ VNH+7z`UkRJ pn,slm1ɹARP YVR ۚԏ,+7%c}j {ޅb\q7kF:4b0kk>^\8Gfmlk=nl+ƣITB=[qv&C4@:Y6]˽< s0Y6mj[`g2.J.,kjVz:,SrkneL58DZx۲ T9 |W)ۑc7,nyH·l 7(~[{  6cNA,PѩMZ楙`NY/i9;nH~Q^ Jr`v$/3Tj w|x" ܭQT o6S{{' ͩS7D =2>A%aݢdHAYu,&;/14 ~*]?9Du9pt3rp#_T1{c9>=@F&FЉ>2c*,#%~ڙبBȈGJLѪoFFK4?64 Ot+6|!BrEh,aX"yMJt% ;M) a&tέ&U 봟t31:99p̩X&FFIh0>y+;O/> EZnnMR<z' $pשIȫR^| \TCvh m ݓ§)Y0.aO]T+b E"Pgg}2 %xu:),n(ՂЭub:l'j&Zl]' %雛eGfm4ᨩX5X4@GxӶmI\ptI3-J=3_C$GocBJ3K%Ѝ!TGT`Rص5% 8W3td2d+0 U~N[_[A9)͇p+yLR3YH/hxvФdh0¢ԉM*e#BOLGS{I/ZhҝA[bNkh"ŠKOt>*,2e7Pxʽ˫{`NTJ/WIxH%5鞍R`/%T%q5 4&tM$KIM IsKo@' ׆$TΟl74}En$߂ZI %Kdr0'I3{CDK#8y>&9֖Y_W/~@P7w A+6@&@՜2IrM U0q}yD*`<_.Kir Er#{ 6)}>衔TQ\iPвI!$;O2!*٤[rLiU&9E[ހ('oT9uGvueNJA&fşqaJd9#8'+~`#L5gDVo' >ؤeKj=d b=8⦜ldei c@ 2TO(pYj|RX&9Sl|s BKTT ۰=uEd%HW(K*R#Xkn:мLOMosZs԰2Cc&lqC@IOſ&X^Eu, 9NWNocs EӮe$c@\rlbrs?n@,镠}e&#p-^rB"z3b汙a:FORb汅F- )%ˈƙqx?iӒ]i!aPP& WUi\~ wM%t BQl:tKy'QCOzF))j8PX]9ߊT.^@9C^fj_V :PL xSv;^2:]e:dW7m(7я  r=] hxXh%#*D |etmÔ=Pd6@8TXwLX8-{5Rg JZK[SLug+ F3āS+d-ØF^^c-,,YM'mcN)ZpRkx+:.zQz0qkpZ'-IT:6mS5|Z=0tr=F!Ux0 G&BR2Bgl|Ҟn0wGMCGRmVل( 3~uM $)L{e&7bcL :Kmr/6p`6`FaB{Sm[_bܔ;jVĪ7 o60:oWEE6m]@ 򯑬 MAhswgeE8^fģ܆% Lm`s?ijû@3ynK#듺ӴSGWfRqXRZq&0t,cPkzzmE2_gTrmO f3Rr@hZg`KRWs.<g&H 'ץ3 :TqX҇= ~DqgvTTi9O7Q|YLa# FedRr(=pyy0YDgz `6G ^l mC |ͭ;9 m]C rmW/2 jMƻ<|4U.`|in1Ͽ,46MT^&zrhׁC:#C3&(uJtս.,47Ћn5@ [wJfX1T=_e. QbT'#LTDTAɸZ]UCYr=i~kcg\IĪ {{Yj<:HdU|%Wmg\JZ{jE5lX56j3J-PhmP6Msrڬ.C9E:$ѫ@L@ĘR }6dRdXL w#(:쩩f6t¨df3^'!,$CAK=1qS3fz#l-JP^Ma;n @a^[qJ73li٨l=`a/צzuO~T$ԣӤ}@<ԩɼN]hN?SLnUt0ƞ5EpŖ?Mk%砏qSʼnk y ]ZL"YL)w?.}AÊIVzMwz%b)MָҢNh ji12QbP^6.!$w&(zg3U0ҡ)kKP^3%93d,cu=~:NG禱أRRY(DŽC; u Y!^E&-D0αTp:~ի#ܗvwAZpT/wP.bVnZ߭ @q\ K & V{&(͍pm9>FlղnnıÍ8r0ϸ7\Y{ "3m쉮R\jk>zP1'S^;稌RBlLQ֜R9Ss(y1V &a/)TY"t&BceH!7s5>Hd P,91v eBUR_k/9,!_r!G_4eӵj)Zjv#Ib§3J},`[<眔#iGt)i/lVZ]Դߞ^4Rg qgiՖ [cz!.*OGf,ء =vi . 2(aA"B{Jk|R5Qjg먂}*%v%HbMEGgEkLk}J85&ЃnM0Chs>tc:{|QRQB!X@|gS"fp">tʘx=}fXCn/w'Q랭&9K(`9^VDk 7#I[*0W2J2+Jp|"˜(ߐӇiJ̣OJ{ MK"f#hC!S-5X qv2%e.D% PcurLxmZ PRKk$(̸&1o>EuZgnUhaXs<}>MRޝ7o˃ЏGo k"grG4AS"w!\-Ev@\F6H6K80D:UI L؞y`6La@[ATaCgE & /AsxTޅ8t^AEN)mr{TW.EUꨦ(?rpNP)MTAooK-5IHiIs$Ч b65Pu^$zD~F'yMZJvͅXeK,w48!o縦^zu#<(CAdUbPW6ci)|UU9#j/hUT7)~KW-d0ph9*"_ "l:o-yβP H#Q8z"rk)nJx̳ZSBT! 9Ҷ^R(Ulh"+ 3 lCer#˯ jNϾLR_DSܫE? zF,-E I4TYXYi<,Ւ=~g$Tq"0"-8LqTUieזٿQUerB`'Trx< jѫ7UzD1X6Ui_Gb_])h9Q,]R`)@(h QIMh5uʨ\ 7Put(` cw+ \8B\J\]ng1p fⓗ[Dv}Pl.R6^`dȤloI<(sYy;EB*6)Z06&hD5z6Ք׋֥,O*xb_`Ok} +h -j,BXuK_]?LX.,~W]x@ OZ,O?xv$Ԝfd!2jmIv&V|nWdoݴUtQts9I'L)K OTLжRZh&n fh"-Ӓj ;S ;8oG<'T0_ղI ^7.z8j&[x{[2asDcѵy3le1dZm+{^zx:qn9ĭx[W-6>Oyk,8 $Ou矺?8e9r10eyμ&;N e;d+jܧQ7f zD5M SLw:1$RQ%R}Ȍ((`rsX;0'JHA|. ]FT|r̿3S2<<]w =8rXK-+WKv)Y9-v7VE[u1Hө5U(d낪A4VpkF؈4[ꓵR$|=W5V˵wfhz!uOQb؄3nJyMewacϪ]V9SC5OǩUIjseх:4]ty(IF)|-NX*i o+W5K ;󯦮 Pm0} Eڻ${nѫZFI3eCX-7O)yb3Ix dMe+:~]I鬤d+.jsZdhܧEU֜bi-eC|E֚gIAЦftBEW+cob;\774YOHe0^# pP>-^^]3x[|HMgY"ݔɛI1U&P.M~0Nޡ+-lCfܺKn[~.[epܖ9WySnpܠS>f#`gqrGoEul.$}02 - (s-գ5Frwrio"v5zKsp[ 6n\EF{ˈBLsw+bf׽- ?2 c%adY~+fp*j㴊!zZI,\§;`bCeiw1yW<ᠴISP\-@"L`$܋h}  &z3i^r{k2vV^6 h %=r}m%ŸF.Ltdi CFWO]qn/jzc:ϖvV_펈X7侣V.o--+o1FS]llJ20G:msMzK9H&`K`LwygsԴ&l/lS5~l ]d3LإU^FĢWdcdw9z;'b+ M[a?L?Dx'pSəUezZIfJljJ{")_puH\3ILh_|EخK&7DXjiApv奜Du!q$hB],l((%B#4ҍ:k~% ֦j&"ۅT %WjvOդof{ !%vMsj~zSxeSU vlf0.+ߛOs A3v֯J\3ۥehN֕uLZWU!ՌnMAy DZM\3SOY1b|XhK/ U5Q V#DHvQ~ζ<+cCTxvUeݫh2gnZeM/e$Gxz`$T:i?[Q#=rꩢЊ)[5u{3b2ksˠñIך̨7DƄ+t|tXT?jǼ2xjuQRD*32@g'7Te~@6sS)f R(m͞>zh]B$=,6Ǡ8VhvZ4C (A\帚8P=jE\ҁ[Hm ' ޱe-ԝDl@|Kaf\Ϧ>|K6XԍR-"Q ScG3uS [yohbeBʁK`62.#4X0\\ͽaC 'G#c^ VT̀:ڰ]b[euAxA7kYOJW-A]卬0i:^K)/EEӁ;!XK-oX]ª`q8D$L/Fqs~Ijڀ]ew#L JR]hlvr}47rk 6;qzXix΀ANW(uŪ3f? ձSQbXpgdcq d\[Od]]N~-7oN15mKro&N1P 6o86FPb]޺8.f"r޼ Y_ WOoeezzw+Sූqv&(SH|n-C(RמxZ*[e(sVM}_&ʥ-3[>#.)-UF>ʡ>5.C9`xi#U@wׄL\H)QL&*:2fS}̘x9w] 0hM!6=, 6ds$$jۍRiDvObONEiaRbڝ2n&qhv%C3huZqDK/ _\\}6A}NٱIުt M ^mD (5MViҥ )M +ڞ74V\d{ڛcQA@F;!Q}8riLXWfHWdRj7s4lj/!2<:44-zU% =k` &76aK+* b1<n77ř sYMqd8yT~G L!%?";Vsah2ߔ]x+{+w STjCi3uLaѪ*2 1jFW ,sA2tRcᬦT[dVPV *Y! ?S|kaES>{H*Dpe3R ? !qТ>c/ǍB Ũ꾺L$7 DC \pzs|=X'+fKG\{8~Η.ŔAN3S3T ?=B|N]NE iϸGsC_|Ō3mb+P6r8F\8S>~Z"ZØȅ[ON8MpMqm:D1*-kտQmf,kLVQ=] @&UlM`M#)g^'` p#x?κ*% D ʆn* L @e&&H&*ҩbJ])LgUۊW1ChZ~mPU3422U: }ϔGkAtD~ '7}-ACۦӵG꽬֒Go/ nBǝZCrJyM5IPw&_;.fu !I|u_n(b7ZƟPi +?G+* @hcjnlPa~C4av43f[^N!rnf5,-|eBeF8SNv⾙V2 4g2⫈Se,8ζsWn@Bk(EoCj40>͌"Wĥ\`X1!,k:|iX R1JqFVOI'gZ+EPnmSi UVWAfZK;ʛ$cf~eMkŶ4Mɨ53c/[Ӻq=i9?we05%vS( JBUd\ZeUuQIbkH'7$bE$ ߙ.&:!*'1K]i>svQ꼐0/)WJgcE& :0f!2Y4-a Du'{G4zieӔvSC}԰ky0M;tmʰ#v:tڭ2Blt}cO? MtX8D#.ZXCI4]s^ U5Wq.Bshz[Hq܆N3וIrՊ8ɰ!4z:y&s^^7WRxuՓD/}+ ye<|҉ 1>Otm s13 QDv`' aon touw5r/_eYYzjnRVV&m{ yK_q(dž{[`e\ 2S f $FT]5Lwa1RHu}jlGtvG] -C`.3] A9q\&qVpN31TCf \ELQe MwJb<6_Ӈ_VR.aJtUb~*1-;8&!Dvupp88 }oB~7+ yěyc.˼i/|tٗga≱LZ4M23m%[{b$L/ʢQa|1.L0 .hQL\MaWte! jMh\#hm"aM+@mC^bfCcTaflO7/` A2xr{ٞnb֨g%7{º|E-N8n@&1HA7 Q04г5hac_9$Ȃ&Sm} Wz]|íYnPKÐOvsi/PT8LCRgM%-${Oȳy䂄2/͟Tk /XW^CM$;+~#̫HbRvj5\E/L5Rw`mXӳ0X#%@ג ru jn˹Q"̓oTC*ƟL-Wl^յ}7f=2^1iMVldeHVqe9_dsePYzs ;_|E>A%:Q/T6毟c^{tY#3ʔCd!{WOv?<ْ Y)&pF͜{{ffw&?ǃa0H)3be餙]S3Y4D|y<94߹#BUIt,:4_jr}Ks"ƼH uvit׫E<R4}]N?t@, MY]KQI@}dn1.^lۙE $[uRĖj$xR煉'USƴkrjND>ΪBcGMӰc5a/w2Y긭RP,/K.WeAPiXҞşqp }81tF? cT5dFsab 6dڝ>fB_nDG^f'g72shv ]Mh#H;rWY:S{r`σȰ|'<ٙ&#,3&J?dzok_iN@kA۩@raT 5*ITNU;_^pk۩pq SN՛;_Vݘ}mg*Op-L*,V w;5]a^4]^4Ŝ])tIčXW> >ݤ @tBn&s `N(N-}.M7zym(@rJ_p>%yaߡ_X7K̫穣qf]Npou_/O,|MQ=͡ }}Ut'j\Buar%9ܾf7jzDMw݃H,9(WDӽ˙NsdG+숩ZzbeWXU4ry+Ǖc?[eW :INO V{Ky{JTRy)@]\gވn}z2*B` %9N FZ(3,i >yffÁIDn +Z'$6> Nֱ.J3ϧCoPQH ްP ס!SƑ/ϑְ7g%/[r}[I9tWٚvq7^5]aV2 noךNs}bi)Fڼv\Dwٚ>K%?cmz:jz=Լz'3%ϯ+ ռ:ު:\)D} ξFe:MԱ1@*5QSmG? l"$3Z;W0S 0W-dތYƚ;uE ^Z'̼a;EԜbVG[?_VFܾhva6,΍ːA-/[狮0NHY/GaRv_fYdRǐ,_Tt.`ˆ2hl/<$Tp \ {_1nz}q| 8 nطXR}!O=x&rE>%/9CM'rWr=ĠʻZNP~ypp_\rEuF[i{qtbvG^<2$Gt4'Lh%Xd2EIi,|'ssidJ|qͷDe5+8߳24Gݹ̧lޕ+H#'C`IN4+8bDԺe F=2ɘroAS)5*lL#eaY4|[$ӄJQ)oX~i— <nӑb͘8Tl q*싿*u]k MocVABY]7}űl pŒ]4X~3 EJʳLPVG;pM[[D!*SZـ^8GdY;0YzX#~An"u[O*OS~Pc >\|;%U65!n_ZC6KzNT3YmKƝKPDWwZjܖK$s(CR4jos7q}LdDe>_i(Lk6OY8 c{%ECA(bYpenX2@1>Qʅi ֢o+A ONy0|q6,z H]xв͢S AD=ު``X8m[T V 37\2(Yh?-Y/jM{ײe2K6[/, hݿ>:dw 42Oq]" F0eN+w#H_1R4f-A~xrYVO"=DŽW>Ét8R1s]yHMn S;_Af94vgm*GGӷ@ϓ5}u3M?8!pI0|WU @ TKʙiˋ $\=]>NG*?,|+ݍЖ1:?l6~Y: 0?=(7\4{4Ft~ʃbXi{7"4'Śir|9/f=L$:Cw}%:S0ӰifHW_˄e O 0693a LMU,"^:5Ĥ-l靡pe:hO^KȓqW\ʢRtxeǛt`z|)_?Fd|BS,񩌴D{LOԬik] ;Rވ#:ϼc w̽'jFtQNH.[Fw7FF#L$Fr ?4w=s6`*9\ɫHfN7G^ws[?pqܛpPujax8A 7?\wq`6z5~>8 4㒊tyKTJ^ qKf`R1m11ǕT-}[8'22P2$@M̤bT-#em>bOB:uy\iLPۍ(~L\+Z0a0 F"QL#[\7ɩ\JCBy|TfiatxSg i~83_!U;Nu+INiТn\%:٤%`~-qe^McWuWD^!}/;u5%@88鏣g9Lьk2 JA Mь2BO41Z!҉.D5JrQzo%b XIUҵ5p˫ݎ'ýhGIWkjɈ/:&i;v{ޞ ^ ˃+#WMoёӰ܅%N3t%$$0. #uLcx2mx)z与 !ϢGOf$~f'V-~{-Ӎ "TZQN޻5L#>ëq[OAA8^>m /t}EBe"4mRw6+M`٥ a폾KW"kgayD@n<[4 a̝s$ tMo})u ϗT,Ez_b h;Dn[@jRKhv([&[wQh4UPD*w3,(g]snR^]J&fmq +U/zIs:ynZ#|K2ݰ-1hoc6;LIоCFc/p U 7fc.cyn Ѳ,X9sS؋ -]/7 8ݟdʝ' \qh_7;>ӳBh2ԑȇ#NCn(?DZ ouA*8Pnp ?aaМҮ>{C%p:gHwӱKĪ.80R-WеgO;p]Ag?~+2}RJ~wj$by&Awr$J@32 wG d;_+]E܄3Sd-կyIѮ3(ߕ>G?OEFw3*̛^SfJ?O |Jq!JI)s+ L蕭A?G02NGIs+(WV0oy:dZ,Xr:JL"+HΕ7e9}hۥĸj + t0V@C+kFkEh'` [p5Kp,  7؁ϕ7OoWA}ԇ5*KbQ#N@j#}gs=r n@(2jZfUT2z m y?vk"ǃt􄓦a 7hQϟ /-71H6>4j N~b*캂47O碪d?d5|ǟHBefnESZ\囗Magw*7/#7,q71}"3 ba9A@*o!fYҧ-n/p"}l5N-ul)|b>_V6sjc3~cZlN*ooY|Mkj ϟPMg72A k vTZ*A? k  n%" jԮN+_A(3jmDUҾ̢f+ 7|2ZզAзK0HQ5Z eHeB)âp%0\9 QE&|Ѳe=*،^&JunV WzFBKcc>4ja?i<2[2:IjZ[:ϊ}/T=.$H1=)B/Nxna/yI>@w)WO ^ 2l,[|mZLVJn^Hnh6K t OT%tTPU#ph.maCWs Mo-E󑔁.+dx/\ru>VrQ[NV[~#"kR9V}@%?1`>TAD.阳W0ڇ-E)N<9>fkkv"Ϝ:)dN"}g3wisϟb~#x+`F nӻ9 xf镵bzvD5Me3p 92F wv8сSiѭ@fHr▚V=nWzxoۀ׼$u+ Mޥ5$I[^2~Lm35HmtUU@KV}>iT?{UîHNMi[j[iؿ};@A|Z(X\;8ʳO~T#>vϳXԐ*mCyּ茹3G޽vy7m{nf<5>?iܙFҜr3HS&[{'ܨq{CCՁvLל#톟,xaŋ/@7Ч8M{(ߦ4$J Pc~2܇r *Ȏu9&PORj~ӧ ЂZctӧ ІEjά>J]r"~/rY)PX>p*wڅ bhRHUSkptW) Rc"+X`S"fLZ%g,[DB]RLVR-b(ӢJ}sVS(YUPѢJ"f`FmJ dWR>$LimYQ:6dn|̗|[ݕS ܞdס]#Dm̤Xv/Gߚ>|r4?u .:Uw3 >PaJEa bKf+}[i Ts[F(>7˦%yůiIT^:6YӒ^?=k4T.*= T}oQ)2qBʵOM9jIQ˾DOXK/" rׁ],w '} beWub:ۯyc= ls,wUI-4@gv =dؚowf=ul6$zcof> Ōry˔U2ҳBUJM]]tPԮչ`HBxUv&ƟywllON5[*OA_dSTxmÏ̚\ m`% KD6oZ2&VHIү Ws:kLT*jWt:LWERsGWuLk t܄Njhsc^}Au5ﴹj.FQC^יym⟁ n+bSp0LT@2d/TK_դd܋t B2WY+>lI󬪂9W?ۿ%="*05*6\J?t8̳=d._cDi2K:4Oқxc0KESƔcF&UEq|gK/ٕ_EKӤr~AKN1?j 5|eBe ԑrHd!QB2UW)6Y`C2@31d+^῍y!\z@)MpJ X8id}39oE8Intw%.3C`gֺW3O`Csna;h/M}IIg1#1XGshLbkGø`0ۛXS 夢I0Dx^,VO.;1 QZ5u8d^Vca>x mWgѼK#gZ: 8p6ь>)r[I算rcE&ueLhw_1Les]d|o:6ۻɏ^n )L;1<4`]]ç Y2W櫫YTM겿i75U˭?h7|C,soO̗cKYrzf|'Zqٚ2C;5=Zcaֺ'juZpo "=)єUyf{ @\5dV<B|ۻT/Yԓi=kޟ~h>Oڍ ~7)oV!Wɟځ|_!GwolCk/;kDx}J1brH} {02q&"p[9JwL ,-3?_a G`j73;ߪi"<4N!&4Xz9&nlgM!Fۼm݃iz_#ȍqˍe~Ȑ*A 9ՌkS%i$0{w+s`jQC+DvV ]TLQ1lOR (:#%Sد9ÉT~0X}F2K$j0) mVQ1{̊{P;,0)NɺBx aԈf%M7G,]r]f+8fGQ $OmVKіhi*.һesU.Ff^| {%&`K?6BdnJqQpad̔w!Fu4%Û 6͌L~|;m247bhcE)*̤b0@ 9U2SgiisDIbX&C@hTn%>hh$ A%'HXyZILSX% 0yXN[?=s_AOS'C]Gs>>\QMhn<{v@A,3Xi'Stc#.>?KkSs$ Fh)7ޯ!:v֜cfs {[K,&{hD˖7/-(I)$Yloyc҈6 zOvwkybfUw `hxi_ڹ%<6 ã1)rn09WHm211W8}*vRŤh> fx싃'?KQXep}̤# ٧ m&2A/4hN{FL o(6v]H8{O1.ȣԍ@): o( 28ԢhQ\o|[Q>^#GR7~ӾI.v ~jۓL;bn*W?B.\&_/..:Sϰ]a9q/:J8|"9.FS2xB Ǣ[I g%'M͵4Tx\V躠;*9id4$>sY;:tKҍLx&i$3τ2 |tũ˼vڀ;c˵S͊ qQ4,_&|.̥_L;mWJQFvr uTww}𿉆ڨ;mj7QL4o(&=`1h7~C]IY5+M=4G;ݜteƎ`+9KwXlfJcg++sq vϒ͞3ăW^h@\e 義bbon ǟ7GWYI^+Mk{"YΩc% 4'SMuJWuPbt|suA)ATPIovW%}3 }"7[gSGox A]ĨvaXtʦs@y79ْ9m 82?ɚX1ՈJ>IFKOI@{efJ>nRs&Lن+WGFV6cҟo9IAcT]Jo̤V?;l+zDKEENHk+ z VqmLtn/hH)fݙ\ 1ٸ=\ih(1I2ҲT"#U-&\{hDq@?+Ϧ#P>Q^IP>4t^I$EUܵHű*Cq?5~TU(nZA;m֩*Cqd*wĻr]I0G^OlP1$[d+-ᇣ`2[Gjf],*3V`j>F:uf-U5ԧfj(QB~ ޿"UD6r@^u=-f&7uƼ&Z_!_[HR:=l<֬Usr:yqqϛQTWE/ r~|^)@~.ʋz3̌N{▭1:&HhXg:e~Q.C(Y&ف.Q76˞xEu6 `ɞxol=+}X?IM3>g]MDN>x+ǭ yx(|Q /q9nP4b'iŇ) CmFN-ߢۢGJ@7y+)i?@}}2~tQi2~z݇죿B쳥f+Oμ*_֑důhAjN8:0EV/[ȓcru Oetw3s͌^cM1AcL4 }J L 8: 3lQh)Eb(WQt%IT—OJf[꜑wS Dcuoj|x Ka-7b u> pBEyvP݄Kjj̀D%X"/riNw }e4H#q-0W@ k&"f"zFc(܁]xo3Fl Y3{:}Ɖ 4֚ͥ[Eh'eiF- U}:4';Jʣ?A'ŔC&gXHIRz20adTgXL{sxrͦ+>OqFbfp#cȺb3M 3xT16oaĐ% or@"XD[#42h|ɳ=؞p6F.G)I@6nvFƳ}3 0Ma3 TFuXojG5&93F͞vkL.:+nX)b6E)<9=љf7,헫gdodžvÖʎؔuf#lSjm%ˮɎ拾bMx& \9)Y;2oK1,(Y72-{=&nя?|GONnъ;CcV)}r8nU+EZ:0[r{*ofJ|Q R6ZV!Q7R6pT1Kr8}x“ґQn.LӬz i)}^1NȅF2d&<!9Jٍ!{z8Ud1gUG! cZC+ 3AkD u?'\_=o!p 0a ^ć(ԙG'kr0@>ϼ&!.1M/~Ӿ (Ly9J[(AF嘒4KPeÂLaXHlD|MJBrXz~gaz5K/f#>v)/&2!(KdR^ ˣ(Ə]Ka~4Kq, Щf m4ه|t6j3#_TzyG{)GQE9+T$TQ߸(;}Y=k8F1 hv}놴r 4 E0|KIfS$ݘ7:xH)Z c?g*󛤥=M"<- O{ȱy8b4^9AZf9c)1Ab2Ѹa_2peУ/"z: ]xo;,/@wXi "^,t}"rNM+ W.1)N;3x p\g;5Vl :F2:yIPؖ[*%y@l}ׁhϪ ?FO@Bs\0dpc[ƔpeUGPRm_{[-Pw6~aX~ep+в-ڜ(OO <ƴ6]ا2M3βjp޽Ly2Ͳ-r]93`^A @ V>0Q#. S>y\^=g|6ܪ|MҜ+`:dLJiMF|7d:utiuXM^+"#Ӱ "VE臷!a$toڞ[Mg@0!>`Zђh3 %|:nOkY$6C&Xʹ.Z44-tO3Wx XDPN[t/adwBj (D&i^Y!..wz;1j1XmwZf4'i>8WanʺB=ŋNp+I%r!BoX<خ0f|xQdYزO>CQ2A0[#iNь;9]zd rPd.7W̑mՌ$ӎ\tA9yC ncA"|P]D[S btLVF]cW"V3dK6hL.ĕebtD ,/JDD9 ˻c\f=P-3c0h\v-E;`'vo~G5GǓirXw,; N3a7\-$ ?2b͈y%b.V c!/2i["\ \{Ɣ HAy]A a=aJ\z󁑞[ZwN>4mJӓIKG@r^ӄ;e q|ܾ0Ak$\Nr\CWAFrgrb@nCb\b`AOBZ- |zx3="Uy'8vFDͥ!aIۘv >WȲމ,~뒰-|އwd>ˀp]O%,; F[+ =XqŸeK0g5 f9ݾk54,\5Uakc 3zƫ+H4'?^5\I|Fװ5~bbSطϸ|X׮NwL)+z!~mLykfQwT--\3.#c o?m$GWlX$˦#փ6' iqQEHYi ƛek-[*hqDE7́bB6N!)QlLe'63)Ho1vǾcN^/@p³nwbaAAYfxe\;)S%aaƾ '#,/;$ `'iPoae}I 3JI;Nkݝ@BWt{wr}03wXoqV1W<g鶁0h*[{+oϨ}cy|ҿb3aou!rQ'а9oոf;&1fB 8V+)#xQIgH3$MLot]ZPVD=kv&vUKZgrW Y =kyaA>&ZZ2S>/KM6Y(.&nqP,})eOE@teQIdtS\-!S=y).*4St\5ҵ8R?%B72L4 QL$?_?ϩ/Rc,IRS,-FIX\]ٓT&,5H0n?LEދbq9h:d&o5A5r"#][)J.gУm)k#+[ڋ:k<:@6^ǙC r?lu**eU/Qnզ\Ńw?hpN;dXS>pL{Qr< |̡5@8؛[GVC-˝#c*1rȝ#cA-9.٦嗵*ͧR׏4yixx]9om^Smoۀ) $|{?+ Nq9$gA_%Þ P">^#O4U9̰^!ISrrܑ˪jq$QSX);ӏzem!'cF5 ҿX2']C|'yͲ!g#^*Uo½ +e1JI];|RF)؅+mm])MO#fՃwy)oj(jRM-ysojeB3ڗ'|꾺Gə )z]D/zmBw;*Z5Ic#{CB7r&淑C^ߕ_WHBK2{(TG.B E#K -Cp46.kZ_i2?`g_'EXz~@kߏu/ =ԝ1(&e_&Q :ғDZew,hs\DEjsѤFRU٤%|qq.h7u$mF4pѬ\{9c+3O~>Y(-:ں'dE,jyNRehV:S˼,`ؙwԪ)OOrZU@.V`ӞPH3jdpr\:tIi L6dX9Yԯx7U9*G;3<a_Qosfz~C?y~R[ <#+AOWycJ7x- RLܜqe-\ʥ3O?޹ Ž1' 3T{mKyX$ܷK7Z+.TL 1XƶlvL,7)U]|P1}=w)U1T&ϊ©&@ rT$3Yu˖م,cZ#3uXXw&kjWV_C4M,~\]uXb$*geewY_ú;[ןtFy5?(/IVAf>(P";`|-;vuC=\i [q8kMy1l<4z%oowlt3LlS_ & X#hՔEA:^QV0_iYe]ɩ3f;cc@ e xL.w4sb\oDaU dT﫩;][$ R:\*c R}4IO:F,kN,C Ҽn.fK<4 +-#fgn5[E;cTE5:`IoXo]%RMXgYY -lzR/7 jnyR2pk^Ӵ7 Y؜UNf-0{u bg]@GKi৪ˊ,ԋtߎ5T+K *{"| ~dMlEZm]?N:>}_D V׫.ȈއCQ6w+gwezBWq#shʸ3 Z9zWI70*S_u64ʉaӿ_g19k΅^UIT /CY'w>U}U[*iq*+|yL)0FV6+s.@~>ݜ#=:IcH==%(>T6nQD} * ˇ܁>e ;/.6ODža#oD >֨4-w2C.=ju eMLa@>v2td,oMO+Kv2,q*˒=up]&f5Xa8fS VVQqiӄNSZ]x) C-$HbbJj\JzBu\:.!?[$ J )贍KBN7 UYɠk\)+a(W.nqb-& ˏԖ Зj8e=0{9]t:L&tWҔ $H$7 "}ad"&Ch)C`j-9 |/2ڎV>dBWd>D"&(hC)RnVCbHKQҪ(z޴ӪAZj+9%[Db[pj`#QT:Lf\GvS[1pI~׎<fR2\%?2024W/ͳҞJYJ>^X\]yG}F45L SUӺBՖ/*FǭARI Xׇ)E "tichS5]7'X4f< F-|4Z0٦ƌ'sR/WD*:þuK&˨)7tFN+H3 ] 4@|%Jhg%j7Avd3| $ř,EjwϤ&SoJJO4 zs\El=Q|vZGLc7Ty4 kZm܌ZZl0cqs 0Z:Tn%s5/>$T;m(KΙ9)wN91 p*Y]+YXK` $` l ^B<0mֶX_Ds/#|z6>~+$|ё#13:l?z6%^aGq㎎(v&-!p`%HkUnDZ\KƁBd&oSOј]ֳrG+0޼h.mHWz֣'TmMrGc26X;~:֣:B]Q/D*_܃F+e\֞#ge0ԓ/^IPYt}VJKέ:Οio]z) 5kp7Y)5p*LYS7@~T k!;!0MKkv%`< =# Vr ˿Axj.5v\蹇$i4 W]C5F_}׼,Zfk4!A!8!͵g 5 KQ[ v%Sòp2)J„P[=y8J|jCr(ue 5r|U2*Z,!O9@zÅErz:1þ* 85WaB{46H\+#ng2[Α{j>tCg-Z5~#庇[>k=ns.D:|OrԢ ]5VsL/3K8R/7KYEߤe#Kms pw5s]_|;.M2Vu鸭Qij5=(iZm:+Q&ev*G"¿s܎ "S,WĚaԔ ZkS0Չ }RA4 NilI٠4]>N?J)q+"*z_.msU s>j/߶ εE`,ܶdiCK_a]v=+˺s \[EZf`~>,̦ pm]u0b\Ç1%N1.ԛ3*WQF-͌a`HdUp= j{2*8^}vF20kNWLpf6젬>f8[ uzP `#'\'=X].K<%θqx$9f!~ m1P2)/l׃BOOMF oDR`s.fC2Tʦbanv}uUZ{ikBCEW~:+A_0(Ze[:$n?^[Mwl~Ǵz;[&,C;*[}?͇+Dzݳ)o3Y+=W4-|L'ueOmĞm?{y~TtuaLQp2b_3zoCUѤS܄m#cZZ1p3FkBcƱOM-F w20‰bxNam*o swj ˀ̯7c3[Vw8p5Ydܷc1D U;QOdLțfFlƘk' fj>T3f؋v-Ξs+{AQOW?x2.xz2Jx?4+ UqզWa~ɋMfiN5=tBdQcroTqV8CA{`ɡ-_6J2./{TlI4G/::ߺ.Yz.:?Brdt35)Oi o%z  lՑ@LO;˯ąVr-2=t>em$0#Z} Hݬ5.TOe00Ka[J^:r},MV[n֢}8"*{YkL? -7CnXC bH0f35׀$v+!k65'RbmU8l(3jsxKUCHuf`rmhz#мM~b5l15g<ϑ{v'WI3KwrxnՋ3=y'e.r={uY9%ϩ}^,9R]:+HKr,LK%td/lVDnN]iؽN޺kjx}(ɗGХEV;T0$'sbdK3'2rbh]NhI R1Vr久,1?1V2٧f'cdȉ!Ѷop,jdJ>_oK=؉Sln?MHtqo1dakk$pkQI.-&<3xl~{rl/ʰ| ev#-[' jv3Hs=~]v7-k3A& XIH *w `toRrmUCpZח8ˠnWx/Lg@ )М--p\.gKg-=.2(&Nx<lT;͖K]0dVR.fޥ2\J4;7rgg43(Q3h?≗Ε.C23eu2?>1Zަzl 8 7xMX:Uz g|,k݋f]-qamp{u+b8J֐N%ictܠۉ$A ڰ1~ 5c@3HZ'0{n0tG&15;[s0|ս郯&NZsûQ?ڞwa>k(t×EO=^i6 cP_e^A6yթY9j%Sm0P2f9B=u;Df1"#  q얫kѦl"zyWX 5?b3OF?$o& ^JZRf1; 4pnq@o͑iG RS3h讂:w/%z< #׏g)6y(>ikA%4HԀˇjVWke ˘Nknb4!բ.1/PC!ק xlM:Q'>.i_UiWKȣҹϯ oFqY7ʻ}^wMH/͐;&mdܱ6h#(MW Kf,<+%XNWJ殰rEd2CJf\4d5pGd*-z<1H'&h-k`fx  vӆ]yRVhH!Z*}JYmCw sР FVw@t/ R+K3 }>U>=)mýTNPE>8 J'>YVҿ}ù^}mnG GM7ĩjN%\O3Ŏ^/bV^tOǬ>N8`z",~R͂S/PL L01$1}51b&20U&s7~|sq)o{w$:Up4-=96Tiu3B:O<T>%9I`bHL`[^{K yx]IYEبF;c^k.s 5KO̥\LK׈=#vgs[ӣvF,Jﱛ_M_͜YP6Bo/X:E nK,<);ra R&oXHXSlUpHSə'[b' { t=>Q 5}TB5*ʘʪt;uGX#6T9 }K"%1٘j4%1Q3%1X qɞs.0eunWycT}Ȍp5]9f4*s2x~r5XUTQ7{6h[n쩦 :B[,x x6B->ˇw!Q}.X: |^8p]:1Qw/ym>ctR`zKG`\O(n|r47T4Kx5o}:::s W71OB WzlN8h}zb U%&ʠ^1eIX9@BpEgLy] 0Y!ڒ@ӴOe6,?+D:֝bafBKS`:MqE͘[>(E>YW9&(~Xx;0YWMa5Z.U"8bDތfD# >lƴfd75r\w8#hBϏTOc"%(Xڱ'cbqVxrԣ+Ȥ JUa5;/2Ҡtll(] Yq٭0&=`g f(2'}no/,bƅqK7+[JK 1hlcG)3PwIMX2wr)ݙ#iw_捼qiSX%VbQa,Bˁ)P cqlhc6˶a( 4X>GePw{fIէ(PƊ0?0ϯ(P:S{H]P\ksԋCŇfl06,cfꬾ'"*l$ƦOd>OÍys|4O+UhPQWPFH6|)V+UP#Esi񘮎doIO6tT%*\r81kUF9K?r _u]W!N?߀A73uʳ`mՇ8HKm m+ve3?!fƄDOWT((~Ȳ -u%J֘)=0.Lc&dEK34@? ˆ"5g3~7f`sh05ҖpAɑ]gp6rΚgc5ct\mM)ٖMpב^WV/D S"4::mm}tD 2V͆E5+5ڲ+zUbwx]Yq^<0yh; K1M_<#K!KשW*.48 ]obWzVny[ 9:>۷*r oUN2yŞahq9nmU :q|7ݥ^: q5#5dK H[5idVӎ^Sಲ0huݒʉ ⻥0$r;عҀ1(QE+4a5c=],|K>_Ij82ϲF@`ۚn:FSv^vs {&z->:=^7hk*co9ac|Ϊo=7ٌbM+G쯺^0*&9gֆBZr5|I,ˡ`lgv4|Y굝V0H`: T dvo[y49|5ZXvl:M%"7\m2iʖRE<Ӽi|#t@=嵯 iw=zS[?{xyhJ ycA1e 2ut5~zdq V^3]a8bWQ|g a|+dnXW\B(e! c_L DผVy)+Yc2w%-9:E38`eXkbƺhԡnlՃ[< "܈W@1\͇ ]ل JBwҊƱhl ^~<}]v@bC$OG@xanrajh>0,:Tg6xy+ОQDSU(TҋPTհvOErLEΦ5c6 v>wL0nC.Է?롬+o?W@ښ`5U pYزOx+sq,S wV~ϾwSh8/}y8 ׵C=jk7t@c/'@j*̖j_G_#jJ~N84MU&Ŗo{31FU{_65+R Т{᳼;GAvgy7YǪYvf.(V4_6|K0|C?.QYe}r=}0ee0$(,Szgy2k8- -}^F$&Д +j%͔pRKI K YP0"-:Z}|?r xi{K'0fVy_Zz&v-pXjQ?<V*|ayIڙ~V 9g[c&ٹ/vA&4x=\w ^D(̷9FxcY F 'l-12ù\(tORD儈2N o~bM_n'Doz47-RLVfs^,Rmգÿ@=&;Dk!t/I@;;,.e+Š;<:,Eܦ+c=N'Lex͊+mj\4w:*\5EzĚpg=ԉ; ~IOLaw%ۈӓzWC7ސ'{'w=e3Cz!4(:g>CuQ6s#0~mmg(UÍ.TOh2t6<'B:wjudY? &+v p }ã6rЇT8\*.O?nK>Sh &é 8yh>jvBȹ G=^Dg_ d?*pt]ԂH*Xs \uJ~=Yɘ?@3/Kz@cLjc!?"#Y'^.ʌb>TpR(yA%ƓRECN'8xR&CCIJģi+r7gߌPa5Mf((M -hԌ <s80hToJ˗}yTS%z 5ޑ59Kuat[(c:j)\?9팤*ٽstxlI]ôTNxF-Rq /5I$.{{bɠ?EvsO_WV䱝=I ˫8{`ȲPLG2]l _8yu#n +gl]ӑ2ɾ5f:Ȼ,+pj PM5E@޵q_q0mt&tuwpO[RgHW]s} >4'!itRV:A1Fsxڣ:m\{uM5ٳq&ʍfyԙk,&F0֨g1Szmo? Y;pSRBk; "[ָa$EPm;mf()Nϲm**N?_aA}`a #Oo߫ ä\Tg,clMAA_ˎ [m<0 M0תaZgX@ySc!avR;L}#`y(ϒS!)$L^qbZ4 ] @R*~NX[kh PZ*-g[CU:ˆͩK;gf3 {Jm~/n&x\_QI`gWs'!IW ,Cz1E]6*D3N3B(Je@/FT7;kbKErv0A6&T1ئtP{z)'#K]E{13TՀI&7@ĺ2jQ[b ^23GHV[C*7{W9^rZW\WyeE8ڋ7XpJxs Y-F bZ[{ JjЋ7S5+,$ǒU7fxH-֖GO,Җ+STo^2܇k_.Ӭ3- (ieԱ۔~u;U1UO~;!׍zt£W oz8U)6S͡n-.&[+'̣+.KU2ml҃wy+U®]{ۣj%b/iIq{|iKIyz!JDڋ{EqyM atb #' @,lR/<=k W밳f@ѥB>i54GP.>sJ,0:ٵ{%k(t麫y3Mi|n6i)B#cZ#CS #j F:tkVJO O{Db #, p:sOO!LgvA§PHJ-/bsMGj!(u=.cF d,w 5)ڛEa%@.8 k, Aa֓F씓+u"ڂަpJ-答L/Y5g2d6[w̒u|z QSt|JQ(cϽegY>p{5HtYv#9E\IpZ""$?}Nde$׆˄g"~b&xe*7S{\nרn<1jʼ]TbϏ飇&摯/cp\΀c2yLj,◿ Ur^ng_F4}oHKRܻzd!c޵[iLԗgXRsT6͙p"li65 g@)۹kLjwܪ`4yMّ_zn؆75:{Lݍ7Ufkr$7>&a9)'\ʰi5UMSP{DZBpRFJyՠpWŽ[?egxxǏKy|>W4&֟1@E+kWbꍩ%a_>N^v*C>M*UJA(fo*^LGphr ´,٧]8TU>|]x҇RviA@!}+%hľtOӂ7jR'ZuuU1C!G͓@Pc5N=,vkvkj15ku[Lu\ ޔ4*u\t[xHDoؼ!iYI ;G4MS!V ϥrh6P ޟn7%j0nV:a$jqZTv=. ?Jlq9㮮||be="K%^Nc>3Ugqtd2^SvOԹJN:wr} 紎]77³;R8vǹSrp]qpPK`o@h*^uXZ;L5mKKkߟ* 1&%d`u3}}4Q6x= z4Q:x;JF(M)џJR'_IDI9Ov3hBlLhdJ$)=$%?&GCHO"+5+oѐE2d i$:Y)wJ2hnM,1x%&JҿA5ccdG#dcfI7@0/*NO?$hs#wt=f}tu=|sp*˾h/0{ sa NצRvN;.-YqC\ M_ ЬʔT4f+p|/i#A^Kr6c/铜 s V[# #0p.}Xwua'k)Jj 7tӰl`]ŇS{&V1]tpK7X4P_&Wǘ9J?%!Ub+} [104+=k:xS z&d "Lsrd~7y`i!5΢>;2.*%aڙ@W#M+F> G#:LWJ8Hm>V/KϪJ|ݕ{(dz[Abwb]Vi@C.< Qll$r")Ȯ=FCV$Ȯ=e]9a4_yֱ3v1/ JF!,/-e)Aq71*e;ї~W5<%URiMCؙ}H).ޑnVx{G*n͇KϽ;Rp!D;[pDgbsߑkįXΊ$]H3sۆ<\mhNlGIn ؒ$Mq3 @}4_& +z M#ژj(m4ƳQ)8C+6zR 8C+6.-lln{ ,ݧtm-^O)b?v{}Yxs$w]ש?4<)\ކ$KӼ^%#!LNVL]TJ)%8`L/+WD.<%)@yb۳Z@эEk:eB+dy--sm F;)M kCS1n7J?#74fѐ"S6AC8q%/hp$T<)o :Cf;v" 6tІZ˜4 uA%Shgf;6γL|VQ%BadlU/ʑA[wNgŏrin|_iͽuR0M=·F#S؏oe΂sR=+"qH!GȘWܮ0 #p(bݪ!vEZ18B$y/5: sC 5s3(G2U4dͣI/nʲnRSv.Mu?NAGS/χq/^ϣyûqýv|GXo 16e*.p[l RRm|["i!o]j䫡(ԁS۔D~rg=œqx%u`R՜f? ㉝G9Ue&aRF嵒6 UO!M1yu"\a߁+_bZcRcJůCi9G]:<7'2oSNJ H.>J"PmS7Ε3# L =~ğ)^ rN?Ie2~ğIeIVog1(IKK|D $4$.5+Q9Tނ^0R6s9c [L fD'o1MzKw˻{-A$*쒀{SwmxkU܄n(v(vU&[LV;؛jAU{sHɝn͸2i-/Hg\qD3ݘ u#҇x:#dYis^%#j S]"k(``J C\hw@fT97ܯ0iLhf@5L~pT滲fq|:`Ҫ5;Gj 8NFM+8lVSq*gthVS;XN8lTgzzMjR,TbQdv=Y~ꂑ:c5YiGOWZ4F,5WX՝7n/5f7JA v:ljQ ECk|dWk.((R5[W-!Ju* ۿRֶ@/3H,=;׸`.*(Tf!#gQsQ(InmEDԮvO 52c;jWNYO X[LOYںQ̖-/ο2xye+X۹WfU~9;YsMI*1^S}>l:QKCifQ%H60 DzMeRkjOD2բzpw9՞ze7t% /_J#2b9(j7;].KQ-.|jW+Em74*1oI//0Ab1Y7 #k_2Ieݧۢ+c')|{,QGQ~k>B&)V~,.GQ>F?W؞Ņh@P#Y\͏IN3kxTMz$dq$!IE;k)=cDm!'L{rjDx4پ1/j:P@ٞ-6f,)xQ;]KY9)(a͗+e)oQ8I>iOPD\y-Ky™8kʶ6Kb%mvVފY^R&@]ߚ׫92PR*xVڱ^Rbs``LH&vp`Kfxa!4dvYԑ^G긬Q$@W] aI ki{x3Yf6咼 %Ǫ.4uiFq&8JzMݾ<'. COﭔUՀ`z[  ^¦~ɂ87^iQIZU$.dx>E85Ҝhefi5tzS"1bZL#+TY,t~ܠ*/+:\P|g}YBUc UYd!-JzG4NTPDi+8DU窎o(Zjoʲ?QK+:؅"U.`8>Jßi`8{b9>#Kq H[=3g#Ү+M ?KRA跍`7ڈ7Cƀ~bUgd7.W1x#Gpxȃ,Sx~{]sh|;ykmb&h };ykmZShlFPml!Lߘtۼ]ȮL拘ɻ~b`y=F=l]am*`ΖtG-kOOܙ0RCdjo$SH4. [ڰު[>37Өs{+;>(?䵜4nEۻB%le1B+,Ͻ|Ɯ&,.d=S k{kG#eX[LacJ'e o a1i;ޢrc3ͰlZ?KbrΉvVH4m[TF} :7n}On?âWQ՛}M̴a)CP6An2H0akeueϑy2f yk/,EAҟᗅ"KgYR%kqf]~Y2%o,r~/Eum5ڢq\TO[4mt߶hbಜeq әf`ဴJ׿mMW^rD1pTn71 "!( 7Um10I7!7uJe87?WY.YxU0h3z6Vf}{}.ٸ)lա٥s(e4i5ft\"YSF~M.Qd fЪ%i4 Zmru9&_5yZ|dn]tA98.o]Gmw` _7yJ߶^*p=%u]5^ݣ2[׵KLsZ&Z9K#lԦ$RI.V-Wi404K5ѣ+6JQzV4]C?*[Q)]('yQHQQv5usau).>kfSX5|J?i'>ˮK?j֢|$ADcߺG%ԾC7m54Z (~GDkZk$]E&fE(AQ%XâZʠ "Rb][,Px,n5lݘ&5VPymE'[@4lM$d3Ѵ IQ:֣0 ΰ:kX) IfU lq /,ÚRAw𖮬La,LwǾp&Zp݀yfXV{kG!Q,}o`mf*,G= 0T>5? P^Ӻn NŨS ƊdQPdaZwBl\ZH7|WfiÍa0!+66!ۂknB"d!zGh:(.g< @CYp2V \KlüdzNiʡ-gӧO(:1 a)v +xP$L LٔfUEjM0UÛZRuLMP0~|| , + 0U3>_QES<Ф,)*rs@LSay_.>(etFMyD7OnIH**XJ(cb,5e-'i@$MFIsW=ڱ{s(*ݒ́Y;vPcX]ʙ]2kQGM3jǾʫK5K88)DvQRWvCd;l'u #1=Y@1.sgDݴ0 ia~Xfe2hN'! L3!eF(d8`Ù: .fJ *E $Sc!eӮB8d:7 14#ECXu\HOCӸ1#?yx_xݾqĭ*kʞebzPDL~j3dڴN:=N |UoK&S4"d44q :d泱4_=.O`i Mw jCw VqTE`ŧa^q@Mهuh3 x+_,.< }!օbtѼ*73L*%NG۪r3x *k(A6ܚ֔ot7eP5Żm)kmM )bMaWflmH5Żm(+`|(w9*(.Uw T?Ryͨe]D!Xŵ0pxyPMnWZ.kyV1O,j|ԡvZp`=5J] ?C'B]vtxf0"!2l4z' ad7р \0.[TH BK"èn/P   r9S9kRaɝBpfI ٷn G٢boӉVez)G$wFI3@dIH5R>1g3a T_W ho͙fMoZ6Gb_t:Ś=tHl4)>zVs9/ԏ[f#u 63MU AA\4i`*~q`& y08[FqW%~5 m32Im@x)KS2c}dtrkp)d ݡ2큛YWX!K[ouZ4m*9"LWf" -G5U>_х,;4?aJ;c 0dܡ)O+he^ϼlJw@=grC|鸱͟c QbpR̂p;56|0`K@f،[(k  ၭ=cyhƱCm4H}|A'%6&KpbVjuɨ$EVF(ZPQiPVM6ӅThРtX~K?Ba5msZy.mtkQ_meNSf$C]ćܙ j {lA)IHhI9Ss5bRO߫D~lCzKEȀ(.;aD^)Fb/g_ 3>|Bˀ'pad-y' x^ N1:(& #C $Փ N$S1=2Ua&[wGӤT( `?r5]r46j"ۭKi(A vW5iȆ~x}QP֌PnUW&ΨBdPTXkj}TгtePCd}4K)8l[)*3%3"kH폲,%L5O'@F1J]O]3V*#5b2JGc9^JRxC#c40SJ̴^7n2+ZC5Xle$mX`kLݷ#h Q̰y?2pNcSQW+c婡LSZQL"@S9ܴ֝]!ZM@TְLB6R@bhR b(h̖8r&)0°mp"Lw Q̺2ėL3)73p+J]sCdKn 4&GW 9F:(C]P-hzH<:qN+z=t`e X%v#WRc+!L쌭P$Q{CT۩ G;3Ӧg2$` :TPOQ3&X&IjB2+N:D,C-"Piľt : k5f/F)t *!Ji6.b9/æ /ҝ[lPGrإn],l hlMsJVtŒ8ek:Tj[;=)  f 5f,LM?/*>4hvF"| ߤ Ԅ][@7UA9D˃@*XG!OƩ_ښt퇗7A?iwӔ)[S2APws)$6Pq׌R_ZJ}aɖ(>͋[ Hi!"W[s !ɗMsIq@F=) n^gERS<7:Gf[ʜڣl;6$5m^9gf9yHoimffpx5 Qf7@ Jă<iՂHL0t㫼(WJS;Mʴr/>QӖIC}:j^ ;#JۧSI~uPCnmntSHvuP=nҳ\:NjAY^q)fܪoReT};&R*f5nc43)nۘ 0 L;il)ۙ L:oK{Mw7fj/Lc{}55z44jsktqSkkt^e﮹ڜ75cRz0,nDzi]BJzhWWm6N Taq; 辔hōmHDR40+m?JS#X4;59{﷤?;ThɋNJfAE`x lp̢2#t:`pIei;N4C{qqYbKehZժyP#[+׀QKh֪}OVzjKjk%PBGjAcB*mNj F_kj:x)O:tݦS4FQ]&_8>6]یXВϝQAzV0HT-ðҔV:Рvƥ0ʰ_&҂VJv4Wl\*\3] 0zxرHm`7*C C,AI݆v[dLӴ ~ͨ]Kvhn#Ie4㲽嚮ݪMI{*nhR/O+:ۙ\Z|Z Wb 0#Q^O²6/Z<# 9hC.tsV]+H< %EMawT.(o@F-#ޕ9ybШXy06a^Q֐,QD84M#́6kلהc3сkc$0< L#=M6OW0g`<8WY,gF'-_X-@T4;Nc4J~{* $)e|,P#3,zTuhJHخ([nS h:G3r<+3]OG*fAShicFHY^_!޴;" nk$Vܭd=&qN;韚zεC%WL5ɍj1;OMrW`+ics [mW.[|ٮ~$?#p`cgvsjڀT/՘ j%Ej 9t ӵʦJL hAJUoSǡu= ^e^L*z yǕ2C Ͼ+J"Z+@2vNnGh!:eW 5␦KZi̼0j  +XE($sYTAmJALA aT7>GrD ZX*a~ 6뤔Q`%5=.V([b_s^(9 2XRs'@(P @rInBh~InFs'KwJwFuRݬOQW!]kV=Fsyάʪy(Z9TrY6ꗔKTc_: T{ִm6zj.Sќ " WJ$eP/a#0?te{Ö=,.WόAn }і C`j5`ґ WRFpb(fDPήÒi<7 8wS[(CVjIYx^vURlh{(SpU9yEP@lU= aEԢ`jv+9}5si&PsqbR.tq wuif1HXpf+\]!"f>S')U"a,uV\!3 v1zW̙Ezh'?'%)4goӨŚW09V]ծ*N2HEXdLX!V{@ oRµ*C ĝ+jt](x?Ȳ*C$S5oqI[vӚAs/ \E9 #rn Im9"_j17%%sVЂy4)ԴUEbbumqW%\rr9dK܀͂3rO눪$10$8pn b:%ZùXQlMlvn.!QȒ\mFD4ufZ6txjUeo| 8jKB[@XGSz(jʪ\GmQS=jE_iqmVA[GwJ]i,mg%;xrL6,x Cm#>`2>ftt.4A^Д"} ulX!P5uVPRM֏Oy;AGmwoF%g1>7M dP\FzZDZ+S*U.[ݺ+ґA/]h#e>jqZuE˦TRMXGxHe ҍnFh*ٖpҍnFdhh +XLC=PBTi+jlP@ x+1EUDaӢ[f`tv1ع̠M\3;}qYahC& u!5$GbUs[6(!tUPʎC!U|/q_Wm+ aCT?.O$$;ݐulD (m\+-SeZ WHNT qaT9fN7N ߦ`Ev*KpL sT=|F"%ȳyuz*]'p Au/)O[[Uh aA2aָby[ž<-vS˼cdR3a8zڵ&V#3y{K)e6JG42;i DJSoǍ`C*ZÜ%M`{{ʐGk-[bz7[]FWmͣ.^Mj,%tVCl29q :^0[ =vC53 P`vyg49p2:+Nn ;38ȉw[XfZ~E T[9^kWh$E㋝v9gDNCԇ"'yEW]OkKkCc\xWn]u#5/E.n& ;iyz+ȓYvҷ{u g\:-LցyesJCK6W;iE;q _9';3n>_`Ҫބof8}3Q~xfcWqku SL4 HDZZY1 SyS!5?y^֬2S\GY/.h#ۄ𳚗 D\%dY i6CVlF:itNHgG6z5&ˮZ\&&3V5]G[_C4:NL-d]f&fJ&Y9R0Q(5^W6ӓG ѷ6sA:#CR u~ƋP糙jIրD^isdp$n; 0ئŋB/ivL&NKbŋBolc0/gvXpeԐ gZNsl(ބ@eR^wG3`fmM3_QMB6G.XN豉=hH}%'g&ni3󝎛^5z8Z߉/#yK@8S{ F]QxWf 93Wln {M}3F^zS6݊pAWL.^{۟ ^˴+7Wt/_9 }k'ws+/ e`) !Y>#gg|]y94T 䞳KzTt?;1ZS0Cjө84>?+hD!H"usʹrz:59j'T&`MɌւhd4GV3'G9"]rZэƄX7+X-EGCbݴwNCxlib\ 8:lj3F/ݻ V.#Mmz"YRcߩM7tsCjĀZ>1i\2m=݈d'pޒ 勼%oKY⯴!-m6V&+ >)sdeASԳOźVs*Ђ3m(M9֕ntV1w0 6 c4Kɔj0L?k M?-Mx&<ة!Ri:t%&#SK Bo'sErt.7o'Y 3@&Hd]B*ojwuA'Nby\(4SG Z L/^^ׇ-?Xy۷fGȱ*UyׅɭˢP~$PaL\9Vv1%W}&9^C{㇉H}<Ҧ1loO=Gj!q+6=}?c rlVJXfC}'zt+$gjCV#N0s\aUt*=5F:rD.]P8mq0\k<+K:8X{zfx4Py#ڿK`ͳ%`i %@ӾhK`ͻhjO|n+ ?M3ωb厲w_H,L/\_WȦ9y >!WpȦi9rlȐ-NBwE×Y'ݑ{D,>{S>i*?)[&d<O&NL{T8/²԰g~W(:NN%+4~]ؘ1)e7"HWHuaV?²鬢 /d^m0dq(u3/V}qD9_=Sm0`Lж=m8@9G`¸I^}t%~C zNa^#2 hbڃcV9V?WC]]ǚ $tDZ34S40]h+ "4Ak"`8#apAXT 32j;vˮP4 N)!H$nap0y?j,0鐸?!L<'Sy)]CV/zud/Z\iʚ+/A#)if~ŽN*sY9ؿhZ `CkL+u uEc+ +uK )x̊;UyӔqGf^)*]'k4Z-s^2rTDnixDY.¡"Nx)dΥ%4@;3E@,3N%NVml.cj8u46g$2|#2=BMQaf]4ncrM}_k!d-e_Xw6k^.Eluq#}" mM߻"GECۚ%7/`N;N峄ILaT>{$ӑ0+Q8o(jBh5S8`*j57.P|F*X!r(Y{;S1 թYdJXNaULIrf}uKN˨kp/c>L_9rb֏US_9aB_i2}ynd, yv!4Td‘5}?뾲N6MY& f1 <-CzBodٲG9=diLL:##–], ̈́\'+QJͮ-W׊Z&jB; ٽ^*,xw o-*d`hpL2Q*h+T-{gMSapjrKu]5=Pvr<+[5GRq.Q*GN+6EV%Dˑ/W Zpi}ZT9 dq]KO˥/oSW4W9sϘl'ϧ#r :Rqz+傿z\~W7(-~u3\|C~z9o7:ўJ,HZpدnȂ`Mc]%Զ~ut hPVs4,5Z#]VR)A5T?/Y@A1m@L|_z@$:-Q5^@O VbS{# *&*4קcZ&Q֪ItCe% e57aKrgʗUrЇhsĞ8] kPCAݻs{fpv5AENNٟg浚ɠ*Yղceή0fgN/̫a/s\nV(s4Y;sma]ty\cNW|E$)fcp>m-8*flHɨf])1 f.m6}FrTuz4}Fr1?bG\gZ򀸳TC[[tФj6i!do=ل^1?_i?lB/M9ĚfR_UC-Eغ6V }8laT+H` Ŷ/6z )~2ⰝKY:G>t ɘڭ7sx>Jq巶X!MT "*L/]DWUa0`0P/N,oE3 x!wͭ+#L-(1]C[}qB }8gpB\/aR޷V#Ւ/pKkul~X%[!?!,ۗ^lvJ֓yM߬Lolsΰdvcdk=ln;RI? d{q.ӎ.Hm- y z.Î A\m-z; :N7C:l'N6jµ,ӣBeb\p֧#:uάK2}넷^=9XR,L:g֥3\ȸr؜2N% _m-[)Gڅӥh[nApZNْlxck8в'=;b_fGVo O0[MSNps&2ᱭsҌl7D:\µl\6Hh ײ^A :V&h ײu,/OM-uQL߉h.܌afBMӚ{qh%VL':65 Y747DPqGi:njs8Q.WMxq,ɘ;mtmy+f;-ӿPa6]5,5|Y1lG3&tΥ2mј .)YvJJv{ثZUeDS'iw wlg\vqPRXS6Te+m4. U>Fm(O0(ba] RT6qÌuﰲW,e@g[U :RĀrABgY -T͢z-ȑZwdAV'aIwX4L _@y6̉H`)1˜E:UFQ.9q[V7lω4p9dݵs,06&bh&|`NZͪ8 3pV/!4s9;WDt*xta Oic姐oŹMo9}?tNYn%гtV1r7Y,{9S^᧥ 7EJP$3Lw[}Cʠ3R7CMb: Sf3}ꄖe6(jzK"&72NSѵ7+ƘJkʄFIkW>0+I'Y'ྪaga`k fb*-hW(BLIUT(XNg*i& ŀ|/L72E/_oI#h&iJ CQ?TE"aD.M:yBZ\'4!]Qf= $5;V~0Y^P >0Ѿ.\gm ŮCˋj(ʰzE&ZBݙ0!me0+s|f1-jFtchM̧K}]>xWBdͷ nwMȟ*vr>׼>ʉX35`VTP5_%=xjX,Q9;o mwIwQkR8##+ &P0ЖIE;@.‹&@ˤYih8K+s(,] q!oq=zXr`C:šY, c S{Q?Fʩɝ7\beoY[|M؇vy ]I V3o|ZNll'RPnKKl޾t%'%ނuC6l4 ԙ m3Z]ES- po\y؃a4t侱:;NNۉet84NM{F.cТ!M+7*DOm y\JK5d` 0m%D47#OL՗%{d7 $5wa%d7Ssӑo2ߜ}gt 6gAݐX9D^*4Ex·/K`؁~]gI/F6Y^s&|UYA?x]8k@nWO9#iN4Dqt$'t?֔f&jqY$Ʋ^̪|Ot+6apEIӟw['L(}ipf2؉'HAcų\niG*-#SZ;ִpV(i:yvY5?B$7Fd fnʃhb(% dLK61YMo'|GQ b>A`_L$D4qYf}lly"D;z+oŏ-JVHkY6rM{Ԅqp^vlFMQ o(fAayLb9W$ jt)xz3ˤͮ8Pk,[zxa5C1d7Q7c ۴rwHdJyg{HhW-$?2)z!9ΒN306GPn$&BKFY;Jhç9ѴHrB? o[1G]TXSZ%MgnJnۄ^LG+ġbR] դQwq9@nu`n<1+t'3UԦӧ'L=50yր6ԅహa$ FJCNzHFKQ~JSƾ>ǎvc㥂k^GIpi]}G@ =_Jf pmzuMŵ6c4cyOz㢩[ |=0-C.[vALIH`j z÷|L3c'iOMIs;@7?S9v9GsiCұI ϝt^xv i#XZjS_C4t,>VSӰ`_4h~XirX\TR3u>g9`@;,>:nͤ3`kM#:!-B#tq39:!I㞗bqѦ.mE,>f(`&Ԓ)ۥtUt a+dwR! _E%6nm A"huNOo:aeA( j7><3|{}y^r aCݗf1ѕ&9UL!-8W@Q@$6`tJ<`Ox)9<F:_yp?FF+ V+W::Vgj_ gj8D^|e<ӽ‡_gf4(+U*T>3h` +s6~eUEfm ºy ^yT J gI ay!W~Qi4ni-C4&Ro{UiAy.@حE6*zG5R Wz x3Zlh/ vFKPIE@CElnBnzwͽ1YCC(R#6M;i݋P E>4b}6L=Ikckpw11zwz0e>2}e@~ aGcNfٓIfnҌ Vȩ3֞t {38zt&R>יFQm4⛑ֱ1-uOUGj8 [*'&ڢNiOsBͮJ[ۡ1ܪcÄM8F?"L( mӹR10<,2rɢj#~ xa`lWVn;⦄OzvbUJSmF5΁7_WO+nf3mp4.r5'U?{ wq_Ʉ65Hv:vQTt9gE/1㦱c,F(尰TM Ȉ0`FtVV#-`NI oUҐ˻E|K r`nl`@?p6(էL땲K=/ReEXZI;PZ*e&_@K%jĒW2KT#əa I2pT,cf} 4FH! 5!}f(ΖroyM͗oF|hH EU33p,eUI2P{[v3WEHE !㊡MkU`a6╘98~ĕ9O<⊎MWа*3!Kt YΦiՂqVΦoCabdlzEY2#2q6xdfD#GGi&1rDdGTL^$oAo,ao%G< 6rYa3X~ֽBiI fUS00i`N6U3O咁PW3蘸V-<m2YH/9mMWtGlSL*UA@qL˜ vURҼ!>}L|ꍉM|V`Rm=((L>=4OJ%Og ^9)+=-SQ/ \?-\DՠRRNCމ~Xo?Q=NC PCƩ V4, ,LrMD( f1k <Θ'xDq&ѲP0B{4"\TKi4#-O"'s b,Àę׋5XJ-gN_3. Pr履+%޵˸á U:BɤA 9hOuedj=noROroJz3Og3z;۪sCZM=o.^UTIaI" ԁS\WZ\t/SU2ozCf\ O|T@9(ԧ m1Wm*q?Iu + D0o©*ALlF tLFb^dPC_2`Rqg6<yua uT˹KHIeh`T5{V;пjȃZtd _(銨Zۆv -)Ӛ3Ҭ2Tm'w^"KӇMmK t$^Ј;r3 =p85ޠ小*X@*YI7ǵgº p8D2UBS0LphKYd`~/Dmʩw`$#%@]ro8j0YE;gҹ~$0Ys{7f'4w <k&%U%N+*/(KPSq4wy _#˒ mwɽՖ G*>aӎob/,P592NB3 #XթYH7f5bS "f_11jɋ ʎ$Ω\~P 2l{lUP%X29V/1&V!H)K_t{VpNBPNqu@$l,@|>(N B4ӌ_)MZiM-jh=Xh `a BRmiUPX"C_Vq@ j:my]p'`9mfsJw߼9304?k(-sd]'ic-C}uX[lҵ?IŬdmc0XuF ׎UrJ;Fx2ݔa4_3ǓX󦔸 hslty<|NxvtZ^nvȣ 8&JVeIeoE>}7U|IT~%4bOhǛ!kݯ;',MHCD`СW dseHf3^{-T<ƞvROXƍP4VX@ҤQR \l|e9C_%XfzCwlƶJP,24U<4{r#iG+-RV ԴL̀Pi:=ju(ʡJC7p[ˆT't\Ý"&9<'tRSl'3 <ۘ۩?e* -Nx[<-*&t-Nyd[P?wOO1(Т:di ]r'"Auȷ 5,242( j UفM%.ч0,y:A~CT)JWsfU#aH]\2j~f[FE Jlmkn|T[ptږ[nQ󡷵<*}ȨZu5?"u-'͔@N{Ie 1ܸF:y+2jK96w3%.t EUAқB0G[^q̚4kFKیd]CS4Z_:fMw^3mh*Iı"IJ5njЌ-?≛%R?~pĭ.^CAuگ9K1r5fK:ps`!%1vd@j9o7Y ^S pKX+}J pKQӪ]N)Gv098 [%RH&ܮѣ}&ϡyl;ǚgB ZY@U+nCMS']FchKL@.[ӏZ2T?6kIE0!T__> 7Ǽu-<\ֵ$oht>nIǍ60Hv)iؚ~M@Q ~{~lThQ]TJ'c޺߷ǻu7S}t6h۟x&$2u>C;ǚkGs#~ѷ5iܨ{(ArZs{37-nof^S82kXC.k/WF&&ćr1!niv+j} tOp/7aBx.72:|<̇>ijS^r!FbS _[Wqd+ԥU`_+'? tfS5= M/VssLPOZRsbhJ 5ec[i5-%F̨4P;fpT`t6(|S+ݔn 5ųMΞS_i(T]C܈c]U{R ڕ q-WiSvxy̥LȫhFߜ8rc&g8i ;ˉf/n8ܒ4"+R}θƚ+Q+EU\#W#=_;m2qϩ]2A-MQX7P'qr5YOhg?t}}oghZjz EsJ˩N);UͰQ-`~J+J;pYӰ)J ʴ:Zc?š+N,#b(3':?z=؍:laT]!3:;OZ,+UYퟝ0U@8*ߑEa𖳦:hڒy$suEajo=dSrS=M~ H4t%doW]ͥ%;.W]yUH4K7l>OݬN@ 2Pn<3 ^/[3Oz3U CUTO3| UR=kw&lAh5|fe"C_?4>p'VuCVe&3]=VȴAHۡYKf~^i-|37g-ts67tZ>S<~Fz NZS}FZdcJo[6_>#zo˃YLjyfV>EO~>2:hNog>yF>M[HUb_TW6 i ﯄Qw_٨dt_OfuFqO&fTK];W J(|u3{qQ-ܫٻNUVb;ՙ׍) ;(V"iB#lP[?USp4Pj$ Kݢ .nW.S^ҨXo$JK86WKK`wЇ<͌xpJbm \~ׁiKͳE;)e #݃[Bpo}rM_;גWrCc/9V?;nӢLęلY&%`3ӯY(3Yˆ>?m7X#ѳ+%iIr2@[+rdĿd2R{zOyL[RPݯwnԻ Ir8yFƄ:e&6ir$ >ir# v+:}"2pֹl$2}}23:jWp3FmIQVc5#ggCm&'&J+ރ *fAa똾&]>oyZyZ3WF[>LLWg}/dj-`xIvؾ"2 o<WvMrx}HLL[7IM)|sB=~DU~3B5I?WO2ɚPXXb ^g)3vN PnYH3sc' a›MyDېmY!cpv[XxI#9_y`\E>|mM"!Lh|ne8<6&~\m`?6cMVC1yh ΛEe:cT+ {tuJ[f*1t3CúԶ}d/to:Җg{HIdhim Xf!d؋"P[:ȑf\s\4ݻF3#/U c~ >fFHFcf8hat/?3Y]dIXJI"3ãk' (LX3w6DNp͞^/yZDhf݉| ̛X> 2jDhNx%-ކٙA N>Ŏ|(p;aK+kRNZ}\ oI-iLn  r9mNxpP6+~^8#StmМ0 N%gC闖Fa^z>ЀCR>i%at KufS0VM-Bb? ed/;ݟ:kıf TgQT>ˀGZfƨឧP&_c 5md>tX(ŧKE fH#;" 5\^#,oR98{>ē14%O ۂ:5ǯ1moYq;=s{-)fa*=pPF\Ŧ(@+&ѵ0x8y"]湕D^A7-se>INQ"%Pujs7/ U  K{ =KYz:Ch63z笆8#^K >0Ʌ…Kdž+uhICX\Z4I8ا_*m«T/P`Z@L1|7k~NS{聑b9M=@曃UML"n,'-l 9֒\{%v9?nﭠR!.kc=0JFqԒJc3jzc%c =A:dsL6|,P“NX>&Rr>)KHkMy^\?f{<|E,.%w$܀Lxȓ?yХ?}<[諗 ~PPN@? xJ(!AH ɶ$ƉH k& r557y*uMSrzzk h};T@ZR%S9}&mY57`򘞖[Q%K|, 8z3Q!RSΎ"9JTv!_a˨1kn_zplC2莍}7`ttgEG҄ ߖqGw"kq4tcr[0W4|AʀoCztGAk ?jgD+i2HgU/p@Rc: - ~f2lǽ&$&+N~$$3k8U.tVqـcˋqHd3yԎG:z(X"s]٩MS 42xc62M;6&u!+lc~ldSCg_d38Z7 St@&x#̬t]WN0C&A 1:ģDC=ڹ|56" CU]g*7H|M8hϘ0t}2`=Mt':+OI P38?0 i̹hfBLNݭ0 ^ j{fYG`LW]ZeCs\iڍgArI5CU^.D4FnLQ3g eFx֠TNt`!Ľ6|(i6 m[A+me4Orp_]iNZ7GFj {i'st#o7y:g?!Ԓ O)W0V&mCI2y 5L2U?8œ^1*1a=>(WXИ%ș 20XWGޡøbW#g.$}[=˺W4YwVJۯBsD,E mVp|%gˊ>4N A 6+~P5i)QNY.v JH_s݋G &_2HDSR$Ƽ/ya)7Aŋ]S.Ҽ ,rcL=-%߃@L{n;1!Ta$A_T(aD_|GnOd$;#}Ud*gԢ# mT3R'=4}Bl8F4(=!Xb/tjhWiP!=d/ƿ3B90mϸMH;oR*uG_ +8ak;13╪ѝR\ %EvHP^Ŝ"ΘZF/i|]{y6:qQ$zg1%ffh#\\$J5bWbTb]s(KD?Á\h\%HK-whuyL,r#d |[>Lpmo*PV#sK?28cɺi0FF\a GapŹKU؈Ika8BXMHx/۟0T(tZ83> G8Z vwj`΍#;w޼osł2i|y>&l0߹AV#c6p L2[ItsڙJ -8nߌs5[`FRχ64 Ja(%]CaְK0yD# -Zaji`w3b-?QFӨ~Q3u$9|Ϡ gP};(itcf`m2 o;wߛv/ndAF7EhfmRì-ӷw5̿f5UC ۜFK.2[ҀNHk9d: <ވgɣN<.\M@jk7Nќ+%r.bkrN/bǰҶȫ,0,_ntפ4HUaU J|kсny_?L8`Un]M$\rK6m;Э+,}LMKH4۾3 %*\ֳ{SP״bgȳhf`>L|HJezޯSZPMp%NRy='0>R&jx.9虮%.Cp46Ta(ښS:4[/B;iLχxGI%_d=N )/6&l/mECY[䎫*!.*`Z7趵6⭶b,3itVl>#D.S>ݞ w)kgdž]ڀJiߝ-waF Zi?p+neөt'@qv $hfGi^ǰ^4B i83~q,#}8ϻ 6( [lry/KTؙͪG٨lWʨM?Ʀcӏ4HP}%g1Qd\lniǯueqjzDLDUL<&PuiǯTVҏWvy~QB<ިSʦwT_6֝#ˤY?roח_d9-qX69ty}wno>;yAo.;'ypˋOnW$6 SۀXB*@,|+5]Bf-Vz$%dCSM[H9*ۘi(ZbȔVQWY՜%MQQw6Ua%$7U0<<%%(p_2z)D˚5 IȖ˫\s0o}^PDzJSMuAD`{29,}y[n FW粳ʕ1\ LSw:!hbҦxX=eljơNb103X!C`U6C,0Pˌo&?΍Q\1G9y,FV0ϖ1 . <$`uҡ7+xH@Ɜ0ߖ1K].C:'iV@0:':F.Ǹ: ^y~UV7@3߄LzK>Ly8bAWYg9TSpƴ۫M0겍?bP7ΆN3){'GIXrxɼ?e7 CIDž Dxz~y8_~tna9e7 ]AC qͮōKCe _ڀEΙj(cjV<\aeNIyT. OMˣGUN^fIVoTnA`Y3uwi02`/WcC)ki[g5+MN[ҙۿ8Yn*%{}*o n楕$d;mNrq3.}e:"=.vJJ%l5?3zBЙBNV{:øIA% a[-j¸_C]A{#׷1qp͒|r?qtK>߾˕ri]r:Seoi 5wklPJSijUf4C Q|f2ۗG+M|Ly:2$zbwؖ*#]MPWM+lU~LX;8JX[z>`d.JM_LgV+C&B^Sjg|Ye/Ɩ0R`g߹8*'m4x̣j*0Oc@ág}"?ǜ&iO&u1Pj|#?(,hOTWHԬL;OaXf28c.U[_YAẍj+y0! Cf~աx=;Q! y|s9ѿ3T n|ƼƓVkӊFfd߃tENfqIVTp2Iy2Ӹc+(sƐ=LȨ[ Z Dehpg#2[Vɡcv2HhˋሆC1ξ(HmUX2yڰd,x&.e&.8VYdLq,G:%z:jUŀ(RK f%:m#`<˒R7ki_ݡ3dr DN((:,K|,>d"ήI< xDtsf* b.1#( Wk=+c F4p-ccG +<jQSm%T3 ' 8BCRp ԁ%LP5L 4Rsj iJg jr,KZe=ɋxm|Ʃo -8~"²~{jkܱ)f˄ǯHߦo:=ahZ)+MomgӐvx_mZq6\j?733N_*ݜ. VIw$9G V9l=6 |/Fb|Rz4ߴ@na)p&ֻ L_(=zƳ]+dޭsx2vs92zS廹rZu]|ipս.KJb,M;.=AAlUi 4j鏘цL-TIx({Ws+?XU56~$fV!fT/'4˭ʏt2擒X.FV+/@A5=z>ьUi. i^+L+' ZJ."z1|g /SO(+k] ֯rV{bֹɣ Lp j[w,^Kz0ݱ* {Qי >nZ]̻.3u h&M`>2NV Ynђ-BIJ`![˽l?>d f^S0:-!ƎwfXy7szY Y t?>^ i tpqS`}OjF)ps LO |tNj/֊v6Ò{$uK~|~2x)=xw_`r<@^FO5Ou/3'GLы>zKpN^f{iQk8YNdd%B!ZHBxzӔrfѵQَ!#eYaK [f!a4U/fp9 1~Wx;'hѨbQ?)hĮ]q 6*a.Q8ŤvBtGZj/=R$)t|vQ9yB*+BB h^: Ct/E/U"}θ .츰q J -:KjLpTH4UU/]QbHе@ya3|v KUF- Te-%s{Wrv%!| <yl:Sj4]9fLI$=`ӥ f%0[IO7:mt#KfЏ0 tkLHmɌqvO*H}ϱ̱{2.fF6If1HWp|8r}ШtqpPK ;h_Xڳ;tW9F$(*Fsj7RRoDne Ac>=WW β1X n~IJCFU^5/H1o,e: 6??PN͛:,(j*J+TsqTmh~jH,a ZŒ~XM3Бy$;q@Z<`,fYhB2c5yd5SoGv&sQ9;m3vimf9!`Nz2:`-Z쏝i-u ;dO `W`UP,|Z74)v2Hȸ/  p72TȠoFUS4Buɪ&A8Ѩ"],\hWhcKV Ҵe?˱Y쌃Lg+:DʬH 8yvbu=`2q["8eM]ӛgmcÙWAVj Oli6؊R./BMa+S>"!>*Ԑ+킱C)mguRRh<'EșHI_tڹ:{):C=;|Aͩ{`b"L]TN]<ùSR.a&S&̛}(eҳnNElՁéH1Mmҹ-@Tqx(Pt$ jR4.kɸmfKg.ݩkwɢb b??D23ő#PK1,RCgEn'ESؽipɪU@ >p;LphՀ&DZTgUcd1 ۪QƱH禸XH7?Bvu*2E,h XwTHr0%Su:FG/UJ( 5 ..$&bdXdZJa!  比q!?cv5 Ë"RCx4 ,/59ҕ03`QU&0GLwM@ 6 PIz+E cZl #X=$V{UO(鴔xa[=xG/*T&w1oWl7e-@mjq\ 9qCz<{(PSg4y<,-N DUwJn? CܭjFNO%BQ6mh0ר&1; HZ/$T[p?WlBKS.6An#2`!mE9.C݀bbB]5.1,2f&,6+5 -)`Bo%M|͓[%3ʫCS^+&8ML s¼A:-=e?M^?[[/)b :+aWFv3f}8b.mǤ\uk~ԂTg2H{c qiQ8Sfz>[ Mz1e<,+tQg02/=ы_?7G?[W!陊cTZa4zfr5 e L/j?}ɬ}?nӧ8}./G-[xgako-.ә7ۏbc6kQu:l黸LkvI{_V43J*}2ߖZ_u(֧I|Wl eE_ps6 K('Ev-5 3ĭiɳ)EA)lЧ}GWOOflzh$l6zmjρFCE_#&U/zOWNtH+0\y"+bKhG ӧ7,'xuTqF=$!Vo-"aCD5ݍ179 W8j3-9^@P/T[m8J@P /-gyE6Qޓ*ɍxRˣ\EbeMT.FDF u!"tR.&]tk[Hx(׶{pJ}8WۂLtEj[Xӕ}y3bжxmt*.) y`Nж:#'2 wßQ,-P5v[9@8l2ߕEDKKՒ7L)lSZ3 Bԕ{K5T[81~Um1F_c$ٞ vG, zm k5MR7ᾪ!#k5R?u⾰t.I6[^ Stl1TػdX_ 52q Zf^a fjӣEEõnɾLAzC~$7ˮAkp\(d6' `]^d;bݿ >EJoxe|\kC]TYE?c{U_sEkҤOEF4=lGJ26_U<4~2.M8:`[fšDXAbOZu\4&G"yFGZS?#En%y>4%9eݘnL+InPBâ'%Ē /䂎Ls`6B]wc1sIАgOҳס'sʑ {Efr v3WOP^YJg!!bd;vۓai*7g趐lo?'&sKzi?oo< @MCG UaҜ&5#ElJv9r]iwGaAciGW8yZ1tAFLm4StLbYLݨ7Q\7E&?8m|-e) ,=',:͉aݙ>0N{bhw.z)wQ R66)0~.W,]fffYjS w7@S'TJg4AuD@f5:(@u mMQfHV݀tI} 2Sb'6jI-'/S/[A컝i);\]џF=nQTmG1ˍ6-MF~=r5MmSAm^^ >R.}Y܎^L4JʄTK_+WүlN )9hWi3MMkf 6&ؕo9Iδ9\,NSN>ٺ3I4|д:LnXrvRm;ԱB$Wdi;>Z[Y졧G]g ~ӌM]E@pӾ]fL4ִԇSHK)VJo)XuզhL_)2L>/I$T*G -եQEޑ(#{ןژ]((:o{2]Gq9HokQS2 yZ=.))T}(%͛}+PIWR2w}+HIWR׋ NA>՞ޙ)|%XJ 0HQf7mHH'=j ?_(U,7V+1(= ʨ%Cdl>1YP145f* ~Rc N$;2΄ $QxMLOIsi&bf7L2VvfL ]2`20&'j?a E WƽT[^p-Tٟ Ka rŀW=d6!n<6,k3Q蒗E`{7`L\Rj*&O%R"xEV4aSهu%|E,wr.f6,u9Q-T,Ea: /-S_Cpn=Z8@fE몊;UP,gu`1 l kop$?AXнA _}\0k ,L Q9 ~wQ]8BV0 E?[++'`M详jj`9d؋[0GVaUY J~4 rAW; đ`2?nm#HV)#/NA <̣d/1(j:Ãmw&rR+Lm+(%?|* 8U"8gifJcEO<Ugu \Z|@d]IA `]vuyЍ$aɿgZ$,@g)ڟ?L]Vt$]2qOhʣ˾k*s>Al*_͇ӜG=>T P1ڌIv9RÕ W! @*Q}oVb m; K9+6!<#y3FՎ;eO+S\ oif> C~*"V{Ub\^_9.4yrGT11l<7w7igc$թG&V11m<]_8F4L墷pxVs6Gv E.4=~ywemfǏ<H.]N6?pfl3W4p@n+wg+Њ]+_y8@Ք (8vєϐ?ikyFJd11>؄a|MK!?}OdvESsLMT 4GsEG¾P;䩼7z&]F~I~S+[na>Ob sp5ގRmNm 3yY$ 1rb_pK7Fy =8^aFDE.sҼ'׆rNPᖎS#2ݓqr_x/ `xH0ꓒa:}1a*%!:}1m k,6vL޾@ Cχ4RӴz> /#da>FM.^N&E[^~Mp_X5mof;%ݮkӪ+*EdATQJ*2"-}ktCY5*oo_F-S7U.f Ehw?dJOb 1͢pF9P(CdsL-N 2mzh(,ݓfH+sDzԣ;1]+>_I/kF7f,sXҬknlԺq  *h`tWdxx]>K r6zײO5:kX\[I5TtR5/.5NEZ"Oy! ? ێA$qJ.JI֣>{KH> 0 si[vXLO`ki܅exРͤa 5l-ݻQGP@]0+練C6T\͟2KZz1В Ec>U20)8EUA!'f8a{x#UA!YgS {n?wE:06!ʄ]5<,N06 yV;Mrah=#:X6ڤMVOy]qCs38ligm' &bbtRǝ*o͸aFNBsSoH9)l ;:քXMF)"~Mhy8S cJKn,ЍX@WU iX@%y'_?t 3#X3q`& I">As`X}()Q̡XU)o#Z53jl0( >쪀\016PeW.x6*ftLX'zF^є"07lI yp-'Ji3nI3)̩;k-5r&5Dw gӐ[ tI juoZ)Zw7i<':ZW%*g4# <2urDfV ȬI:8gb4 <2N]iHÚїcfJqQ&,oM'GD}sY2:fdJ~Ā`fVCߨ2r+]q^tzfqWh'аfB\U=4Ghm"j>zX[갔נ͌c#2ys?K/*L Zc {Cc0dTec&Kg~KlKvZ''4cBѧ \OV+BkR? i~Eg2T4N3{ir4XCѧ%PBA[Wh˟: uhsMU;)C|urI "<֬4g<(6?LXvrzIkO2If[ #\iHIRnW3 h i,M/M0o?&}zq8ݼu(^Sb(Nr <5:gp\9l3?P>%O2b.aW>h e>`O߿4P_O<]޼<͍C Z/gfXUŰ:߾\tրY;7͡9f=8oHpnXa@Z=LĬZ$S[9 C4 S (CWU9uRQ 6Ư[ڻS4!S#͵m-;Y5Z!H9JXrSmNG4T`;kۤL U{wG)%y4# N%rh?$NPYiGaݻSMI:4̶;ƫ^oY{dr4^ݩY42##0[t-HC V[|S"Mը~@3]/uZvaO> NaZzCrfH_*b*DkR+OHuinx4T̟q4qAo] pK}FbH7h6ӄMNE=\߄t^z:q^I_&ݸy# ts-_Wоv̀P\%`52AU1`\;ݸcY}msB/wE`ࣣ(" [v%dsK\x?TBm8@yRI^pLa*Uk9#Vr6E̫`q 6FDo]W(P/ʕik0K؀EP_2Y 2QE@RX^Pv^BH7tboVY1@; Փ\9!3]t-{Gj!3v:wXp%[!2)`TD7.L~M&KHSN%4%!,T\|5 ~FT&Tvhڼ$$"XJx;O]fAVsr:1nDmh'0Ѓ^ V~ xR0lL#zXs@+x3wK9R92犭)> Jk_vryZ$!#]ָ;DGt, ۡH)4,u;YݲvRG$KNuڡDѽum;,2v]IHU Ivd]ގkɟΦ w0DTz2;3Z64s5 ݡf !?m"Ϫ -DDZ}<͙8ёEŘF*":,Ơ& rި8-[)n1!XpHAFH~+l=(F#dsjPDSTeXq#6}X~ktIgvtJgI4SU8Kd .6NUU,.ԩzՆd=7(?ɍ)k>?Z4`؟brC2b$CD<5ܐ'7)#NWD_Q*/b2kqx[ADHiQ28MM:Tyt2AZ`Z?uSrUT5PQT>r*ಡ |^ȩP) PQvUo*4-xI>BШ*7F^dP.J+9Ai E9x2ɳdR&@_]r~W:!tT<oL2t½< jJ9NQWd ЁS]jX"nv*TքTl1f ?+._ua 1@CLY`fL$eLbWl@w[T!0_o۪ڷԒ԰8FJ[Z jIdsΆIs+[L_RwJuؚRIW2Syfȋ?~|hЕz _<O ~Q^|:Uw+*{QzZN-k!Ft-Hu ~HYT!T@;qV=[ŨZ|GO# 8iL޳:)*B杶FEtEɴ(V+?ixOϥZ)_ kRRT#  v[Ixxhx=ru0bʰ49]J?:ewUjT.5!kU3VR0ZVֶaa]XȎ=W(FwkK^Gr%3w*\z'hr4R/-jl H i}j`#^-5lrua4 %[;=(Fnm@Ɉk 8, (MB\F'%nJ_}+TSZ8䦔O4 ]kR(.o>".6` R3Ym@)L>CPbRLo+IH@JsV` t0 knV40m,4mvl+YGAf[d8_!'87.zKސkpL36^G9Iаy`wăƷh"n'&vx\?־5 1 s#2v8Mz+ r: aGn3꺦JȄ2ҮS ߦC;\S7b*@r&XXc(vd,*S9gG 6,MHG|ipwHy-gC:vZ|QVvTiF#::=!yJX^cЯ(wR?}0Ye 8;3şQ=ޠ@$'E&ƳKu3k xvRAM U=A#p n 5}(n~/=[pl4,-h ?J[Ю_& tCI7'Va %ݔN飕k p=Tv3 [DuSAMVv B%U9X\0 BuyAJInMnѹj!0Ex !|] \T.P-3[uVf Р (KPT sp\裈쬆閤 ź„J=[UL25B[3+)\ $VV&E$`[f+"H@j1Y: V-06QEjZ>Kִ|h +أaZ>[)ց[![gc@"5CJ%a`@. K P*Tq/%]0Ղ1Q=1f%{ 5r')KaW(9_#[m֛ I( P]#^O(uk5FY Qr) T,%KVC)r8,`SP=q~6#6jGBtVdF&׫ Zj >PӪv 3%gU]'ӤH qfH[ڷV"F~PJڭ"S\gR/7ϑ[QƗ[bp*#;Nx~0N XxNmC6``E-|Zt !LP .M]MA'jU4-{QZ.+|ܫ'CŁgX q K+]'[ RmܕBmɁ_K1ZR6ް~ *zS7QHIO(Ь₪,y2=&:|3#tz_xT' (uT9nlT}>`g7i2U}_]Bda=r}l d O$2SթdA_m ` i4rYzEXGag(xI.[e 46R*X%7F@ѠQq((iGJ\Cв H(sLo!k )+OCr XZ!9;% ӬL ."EX]1E*/r6'tpII\ .ER65Wnp@ prZ;A1P$er2KP1Ir%(VeLU U} @TIMOf{*RNPq lhUpB&N~IwtjHGkDhn$$~Q)/ƉB-^*Y״9e.Bڼ*Uz&ֻ&!d2EhX^&] "+t4jUq>Z3XNV)Gˣ%3Y_qB( hl+%) kܼH1 Lт0@LQsLTg+ ƊH*E#(WlZHǏ*9VDxQXaA/@[h+LdlN2U\'=oM!xVU2`CxvȻX}[D ,搇5UO5JCi-Mz;oP.fgB؛wVۡTЖwƝvw_kcbhaNQꇘ7m6ȩLj:juK'q*8?.\.NWy %ޝ" QX qm ?%哫"UfV)c`!ĐJ~FN۫T5;= \C&# [0Jy1X%sf Gk̙!ǂ#5J#M%cA<1?ȱps:d ptSlnFO` jC_VHF̛>a0o&%GP'*WBEJPzdz u4@Wʨ6 dXjh8 d*Q }qrzQQas  pWWG^L^b8`Ȥ:d 0 Y~ .(GxZMZ;;ˉ oLK;vXqd Fc+)Q9G!;*Ke_܋Zl8ر4)VƬߡ=VI9w\KOO^{ VhM,\ˡDW;Uߎ Ē* 5ձw$kKOS8zm)ZcKo\Ɉ8)K-jDTԵ>tm3Gv+tW/8D-mzqC`uUVeu7:KMZ#h&po~S؍&n{үbфm롰Kl[Q[FL6)hK F5U_&; 4 |dF0^:CŔY-P˞iMѬT?jBt!_a:@XmvEcZ[2 .ѷ\QQ %\@a,K,#\I+}B e,}]A4HfDh.~]$LsRjVkpF2uLZ? ƴXd![}E!^:`,Z}I+G>hv~ 64E #Ankh8h =F6FPxE'D:ahhDD"e?P⦸cu:2eXGFS1<L_UEVi WDJBB`:02\CϦW~ IᡋFW<_QCv`hd^$d7dlh<7"Bժ- 4g4'_(EBN䳊^eץRl,`RGo>rvAydVsMj7<e)πT@y,%3¥LQ,%US&'hՔ P6j*sҕY ҚޑB̀ьLںM9*GbLJFwl"R3u02UTdpOWJx}T deR3Ġaߩ8r)aw™x ^EmͪAttX f8J6$Agg9alvt_E$PrR&@ю q>S !s129u^'`g- s;0d.F/[knR~#7D;XˢG(ΝhyTT2Bd;vZZ zjB(V(piV2|9o#-Ԙ`N ٪zl@! TCV*H:#ß"؛p iIJ`ܫ$AL!P(XڐE2O G X&!ƽz6Tښy6T2 E1 +OLm(TY5{P ?U Y[`agFOhF<\UN1ڎgNSbHm^ԎzQX3-FQ4E+xV`P-0l< % ~w '*t''<#*K {P]iTiѹ.z"b"xW"z^2L= "\|džxcl%R(PʋDC{hoJ״R|_PțD={h{OIqd²!W(.p )geu:}80&J%J2gWSЅQ$JXH-u"U76u.dB3V)7SmSIt?ez1US0|:N^P%{1|c|$cTh*jP+AV蚡""0%2B cԀ8S -2@TһɫմG8-KtB :RVO5:%)2jlm*L*YGpOU % &360a7=٪ [^C@ lU6`\9 )fdY<^3*$lITý{yZ2< ـIcQݚFvoYϞ/rV/<wދI3 v AmTWދGo$ـ[H&[ܲNFޫ[@{`Ɩ@Rȫ3g"goWXݥۻ tRdv(z0hvƥSٖ@Dn_&f嶳i6-NK)3U+ |㗵kd9|+T}5X_Te4C&L:î< {hbQ` C6mCUA7Y ͡ЍgR[sQss.?Rޡr$ wW|vp̉b0*U\h)U;47 E60|SVwjuMA)[qlC pô!KBh%vXP P{(MT+ 7HAtOT+("/-YcG(g8+t$;C" [+ I񣪌b@;T[NV_+G-'(بy~gJwAs=z9mZJ8ѸsAT~(rZ%pVV"F|d%䤖Fפwn"N}&䦖F&ODUԂWY |*J"*e4?tVݡ A]TGeAgt6+3(ّW"E{*2/ zU6UNx*XBo3iS$t l މ(G'(u\:&/&UmuHmchk-W-uF.TCbouMn**:mr@ٿAw z*xF|WCR|p@Ml< /:rV a">-Μzʹ@|ĭj Z3\a뱲̩?VPw򃄞+J|*~FH `&!Q/S,@ EƴtscG[G'ZÝ}䞯1/kjs,]Q"H;3يDcրp1 *Fbre -7qUjxMd]'DJm%y{"*GE 3cEt%ֆ pJO"tg`Oݪ:pAU} >,TP_(RZƠX^8ZszuJ%0asDX ìQ&CMETSi&GTir:]([SyP!SF^RQόFgLwDIBEUhNVO$_$h[?e&lBw3!OTR"-Z^B]Sm[Q E j+{PwT*"Hճh]-"QAfZەC'oUGH_jda> k5A81DaăTگwuԈ@JYɷUTc䋪BHکuh6enfuugp,?{(ɇnNДRlhN2AcFYtjY }tGY\M#3dF %&Dj Oe(Q¤vUN3=/ϲet5* u 6e K׹zpT[(ONF} 3h> \@Np%UBnCv+h:G`u{W4#k#`2|UBA~P"z/N[#{GJfNMQAȠEC!7S*nJK"aBnOkAPgݲU@jѡkW)!oj;NB{,%G EwTY(BT!އ&%܇wU_y0u"@~:`*t򉵫" vW-*[Ign^:֮B)O'N ;NxaB _0Z/MmW I<6EWBV`e|fm0WdbYaGq6pCѱbB-RJnZP@Py X!O aN eLG]!Plɴ 9(W'"茘9'͞ ~(y fADY7^œd m=OvNsȅR&Y'`#;\~CI_HSxU'83G60v𬀼u`T:0@evQVX&g#mcR2 %8i$sǕ.(\aT +"@Si R1* PRů5F~-T5DU`A@Jbgm0O-TB'eMdW 1(lUuSX P5٬-`9Г&@drX+dL:X*YP4o X8 R1T6:d q%ꓲM䰆Y)B[8&d"XC5,E  BjHЏ.k/˩jqS:pR'>NkQeVd15zsehwZ-=4;yCpqoɻzZ]=V4Oal#mkn>[{ 0lJ-_hRqBuHt׆PyEbHՁPRhRatwGu#.h2ծBbsх]Q$h&3n&S= #V{j*VOj/v+f7}w7z YTstv6 XTH ~t噰jz ؈eZ?=O&Bzr\3c65!7 *$f̝d1"~s쁰1 ^? (雂iqNnNC R A]qSuGpgjWm V.\|. A+-aD;!KA;>UmH;?hѹ >&QdRʗY @ j9*̡Q 3A>h~r[+ _2CG*\0'QۡqM.[4Qn3!3d]#9}0 (?]'X); V 퐃 09cю4T5r _iL.hX!A/x/e}hJA*S0ca4ЯyV͓x/!*blzUz!Bx5_y\"DTIq?@Ηߖ\4; Y٫F_43rPY2W T~ ԇNVךCkV(x<@[|rFR.zb2䄴 #`)iC LLdR];RJ։}PHDzaI(PF Q'&HyxVgd֎ A%?bE{Y #j*BowF0- Q Ԣur@'=J!}ETX%%OQJ& +B4[1-gnoESl,t5VJGDx4ENH}$bϬ)3Ixhpk:uf.o o{V:@9eֳ&IGxw4tzTE[C6$2,P&TMb+'~hrgP}]LZsF:G~!$%TA)t9b2Dλž⨈)o^J-CQ-~ST8zSj1JȎnʘqUk]CKQV"6zPVAP"DkTn^Jih8dMуSAGt,2F!h7-ψf LhFz"6zpVOc0 ],h%MZ \Dj pKt Nhc$D"SuJ{!(Nhdoݻ;,M-OU @W5dRóiC ʻ<,qI2CJ>!UG!*ܝBҨ`9*3 ϫCb吓D=[{p |pN Kڸg,uCe7PWfj\g Q5G9£[MO@u,rL 2K0<0T,&F(fVc( 4&I&>2@%7 JGT1Ibz̈́DZB r ȓ'1w\mʗˆA\X)H!c8%\ QFAF[n" |Erf,CmHN0_7`IW6T[Ԁ;2+R@4"7ڞVS{D;Z+層kk*} /(A2mL<]$RDdUbۦjxVJST Tj[F%MRSr,d[GM}n3Gn&@*3mH'7@;~ #7-$7>ͻm r4i0e͊{UlCxoE{"D|k @MXӶr 4%X6څ4Wf lGQ%ytGBh$ #T<]@Ofzmzt26͈P9e|blJLP)27]]!T7UUɁ#$#Ct8h;"j01FUŹ áDFSI4 m"oYQ2>0r@p&N)RٔQׅI^N tY+%+|=y! j%-ZaCH a7Ǿ9\B{iFүE)$@7PCQ>CfJ&ǭZzeeb2edr V+OpQ~-y2OO0pgvsWԅZr%ʢf{r6bYY }dQoҕUɺJȷ{h; r?#UTꊈmhF%*""jK Z?!3 $% ꊈ(l9hF?*4zu+irկ n@a@Z ͱ-BuQJ x䌷eU/hUe"K\?aMGEQׁu,q>QWtWYCE'k<$RTސsY\aSQpK]hԫ7 վHpvCpJzMDѹ(tɕ9C!=z3fl OrLT0J@wʕF(7 \&pٔe+l]4e*jȌ6@ЧTDECv[d(U< :dBSeK 80{8l҄U] ]҉PHLmeBϢQd"WViҍ8/VzK&Wh4N(H>4RAӂG*P7% Tc썽4J-v$3%fX "SMӭ:UFS'RѿJ[*y IOIGJ^(Nu35zV4#*G ;9O9 4/w \Y\aDFAƦSiydxe7[i'yF.M+HRKj'p8 (ꔤM1T/B$&$M=|;9Ǜ\'gXT'wvrnnNM駬BA8IlI#SJqN:KU\|5SqIM/D*)(PAA`p ( 4p~rMk)*xI{Jޫ. z~6NFI[Rl NᛊS%$§1}':AT*V_('0d:Z7_hxSVՅRH#8*dKRz/Z5ô&Qfi4jh : \$2=-&QDg?CN2=h%'V|xےf]woX8ω) SDuwb%?K¼Uy_ֺV24h_wYgfqEejEn&x%{qӓHtgIh4'y_])UmuYEQuЍE^Pa+h_ʈFEXj?2(Z,)2V|4]MzEFJ 6]hkmVz5ڭ?5]}U0Jh,VWzKFyNT$VL^F}#G_jJ֠[m{:*(/lo!fcI76`󦵎4;2f"w#:r;`E(:ZbeR- 9t"[\Kl*P& #_Dkkӫ>$edwm[Gż5}`z2LMVYW OVgd%?(e8N50IY4@Gꃝ؏VHo֘?ꃎU}0}H!B#5 .> nuq`*Dڋj#H+GeL425$*$pC1V5^t}\z)0aP>hVIQK/Tn$~ w8'5tgNkLi]w"Xc9EBCթUmg@AxQ|?5^>=uM6G]uX*Gi5|u9+˛6ʺ)VWDcF/QiB/B(@1#!jԆTKXMG9'vżo<DU~F#ɱIf[ ٌR6DrS8T+%T0#M:QBE`%5.`8j -ىz!'Iر|(G:QF qx!(cѹGj.VR̨8B9)0&h"rJs̝U TVȸ}^Bi]N T#}_%eg_{ 7zBڔ^ 8aMBb :IƏDݾEuFxyY̦j`BfLU5ꜙ(k A\+{RhU .q%ݕ\%–Â)Â6RSR©N7Vx8!B(pJzb^t "ZI@UB"cgd*w>M(3u*p |2,ʥOBΈlQ6ؒ&ة&z ;8huj`TV &r[PW · vVёJSXF]c]bu'U[4})%+:DF:@nu]V v6vqըG ݘ5W^PnHJM8qJ uҨ cp" 8%鬉T%FU# X<ĝ]EժXL^QE 0*mWh]u#f *վ$,ڍ +Th6T>1(WUIDHr:MsP5lANf0ľDBfR(`0n7b="n\6Bqׂ+Rpy#j*1bĎeQ2(*-Iy XY1h! vT%j<2"Ly \Q Yr |k9Sׂ:Rt6AK|u?NE_UIHK"0Sn*lUYo*YǻQ@^I Mecd2݈)^8ݓC^:ʫt\LU6'  UanP#e ` FTfҮeX}Y#תrl諏 +J8X¹5ch3,DPW}{\?zAAUܗT-B56TS} ^!Oa+wrȈ0>;YPI9eތHUewVyyFL'e4j4RM l`R|MY676~0Y6㓝GO@,<&y17aBk.<%ko„ `b2~fqcr&S#G肃)/tB4d%^1#ČșLA͐FdҁY|耻!Z2 (,K&L >rIiX 4"!,d!)H`$oҮӓ^,Lϔ5pLBj5EYI4#g mLݴHӄf,̕lM+yI\Oes %%ǒr!s8(шi'JKR)B JJ̉O.|!h[Q)!o"q*]*+r@7(g)Ufq2)_TEЃMϔ 7B: rm؝TяI(WZoGzb2XU9QTH+X:b9bT*y@uv $2_ak/uڒQ @:s -PϾc\o dF%}(c/Ya[UdIg-䴕 0%Qj x=\F0lbu#2d%QjLoFd w"È\udƊ,Ȉ(n 71FH qI"WCy99rIMV`HeT䒨 "0Ndݜ5(:N;+jvsi)QguO8Z7#OEPԲC?qC;ꣁUQUn._rd΋VqU*ZC9NKr3FUu^ 2.bΪI8o.cBqQL ^|ʊm}E:}}3,r,UT؋e-ݘ Vo5zcӍz:x|XrI(TUI݌r1+w9rn-FTyQi}xYnD>'$1|qYA N4뢨r7(I#Ndjm=jșꇯrE['{5!jY];:j񮝈 FjݱôHXӗu10.RLV3bM["'Lլadeĺ`B[h4YI ׁ7M\e]S ; pqX'vWHN>de\ʠ rzZCWMԙ.ԁ6zol:7 *Vqs .hy;] @nк< Zn``o4|6\6ignjK LW@5΄5_wiut :m-`K3ʅYnH9;4 zW}cZKWhʄaGX窆fvŔ[0:&U,| JzOֹ7$3%LI$j:ntf(8Q[Q PWzmӀZdO;)4@*wh=OkLW9@3"D DDm5*_9Tu_JUHp-WE):mWSaP.u)tBH: 6ӻ(1Ԭ?A_ZoVQ=_5w%b(suYF>SqFnȵ?tz)) Y/-!l~!kH$NRXL$갟 h070k"hCSpIXLo ]x4*\rӤ Kn( ^o+$I+yaMbaalJx{=ޭDi݈2>thbR62زͻI U&kY?(EHF_6ب E0MM(r B6OS]vЩ A(i t†" W='SD)2CB8οvꝉ6NO:SՁ֍{L!1E+MA.2L;V _xe$!ί~E6Tij R֘y**W$H&6ڥySB 8-! " RT9jtԯ|x#XqVR;^k;L먥6jH^_P[ctEtx$t+9Ь'uDLu(} #KЄ@Tӑ eQd:Vyyfc$P'Rs#a_)u..3-"@j? ?ASpUt<Ub!4S5o<4Cf;v I9# ^P*1)h|vg2$}($Q!!CHͲJ`$` ]"P%`W0]h@#S#,W JE}PStukt,CMbr=U2@\T‹ILv!MS f*E_4HQuU(Be:aTºcdIF ˒n1 OzE*]T1 QBZ7nCyRth)Ш"/RMіB`O4Wb@h+L62nZGM+`qad>$ TJVC݀ I%T*˫J;AOGa? AHPQ9!cJ0`ȃ'CՋ47CZYkcx j %aL%?T$H#MN +a4Gd`B QT mC*2pk6D6" Nc" %^^ d<-;NIu&yDhkmId%8& *M2x@(heZC~fVl,oH\47FR]n![K5ԧT=HSg ^6`+V褭#Cit̍@I< ut (>`ogY>W &+.hsRPa1am*upNe:dTNebm9&ud/ӆ$ϰpR0)f;459ɐ&#$pB"OT_=apDF,y™W/Z/V)Zw#ፊ )ydi6aQh$ <۹Bu!T_JTPc\q}'{d:Te_s'~:«RRr&?C{M Xޫ7rd:L9%$ظNAfdg V8VÈO) e`Xw6e`E̼x-ꃙ(!cO-Y<)c/@ω.&F lK7 Ah9PN.BU!d)wqb~RZ |{Nkf9G "8OfOgd83 "V HjJ@H*ۄNۨyFhBd*et*Q])CSeobէݤpSgj0F/z.c*v|  $N-XS@k.n0TKd~7Lm>tG\IA)DŽ!C i8%2` s'H- u7>ML#, +{7~xMUNC&_RL&M5q3}edC6g}KӔMlMߣ=cD |fn}"&T9ʀ%$ܠ3 8} #m4UUh"*4{ LSS~2a\6!mbzb [{:* JW.->*EŨ$An,UnV{+G% qd0pn-^Hq_RM\!(޲Q8%N:΄ܭܣz vSwj:$ݣqj1]e>cTeA!uwd<\=*IPAYdd02&:80@EΧJz^?l|SGuw ~3WZ!'\=;H(#Xلr,5z/,P9zK= <D{C3%+iL]qycS9 ag 13"@aH.$DOJͳ8M: ܒ԰[[D9bY7_2`c(O-jb,"Uu@r&mr>+NJcW+i> #Mhx: EyZn c\K(bӈgC+LcQUtRh殚,5* `]\9%!H/YT># 1mWzdT*赛 _%զ\]?h~!A_%&yx>?| 傰FM½ L>ognlI_LC`KqxoY(.evA C6nG1[K}Ò&RS7-Ƅo)cR/Z+پu' 3t+پ]ZS RF.$BBW[A_S5@234DA*O/ Q4i 3pCƬFnrx.e! )fCEZ&I*4XL ;F)4"SYQ+]5U"5qAor,(jH{rIE S6Lu#JvU#~|&jWI#3QbS#+쿞Lr*D_&<] :mE&8S +&BM "Z*݄% Ӣ.[`T*4A"gh>+٘Jt [/) Vb1k ۢ)?wVzHdW)*:JJZ=iUJ`ܘ!t&E (7($]PI>.p~n4lLnB 禠> ^h^Ln4=)R_AP6i",fAL ~m(8~rR3%mҞZ\g($4SKm l1%J @hEBbBT'V0!j´ (%#!Dq0e˝0€89rfdf˕89 ;`pߢ9䀚N,L -2+O6%H`U]A5L`|5 -J PmtT3ʉ͊v<'TBiU*͊drifXF|dv(S}nIsfZ|@n;D,uT*Xi3uT 9MTcA/ #uT"AK ku|;Z7%iJ#u >CȔB>$I堻2wQ5ބ|bDn R(C-\?Qtp*o-THRd,ʃ ʠGB\((#&qnYeiHUATr?%!1iSILDR":cwn#S5ШDR9(Ҁk$1IJ;g JMUd7IxWTE7Ƥĝ%֤&-bS8T$Gt7* w w*t e]a!C0- 7#$LB(zu`2(C&u\| t4hKvhqKaduthuML's ^|)篍g :̩X$t )A,F_awI '/lQ~D"K [E!K 淍[E iUp2m6PAE iE:G$tK" )iE9+ [#I+)/~Փ27VS_>5qqRZK汫Am%L00s(>R,V!ߧ|]k)^"\y̪gFۣ|S.U$d BdQY$\\5Y7&؂a| >Fv',h .^V"89!H+NVj:EC)*ujd3 ˅hvB8Gf2y* m ! $àƊj&1fڶ?$Nh5Ga$lR3Ӈ>CA*&3=ȑI\ ~M'©鎎L_P>e #1*Jä+Jlvm90xUk+dꐟpI*iW0ϖjpm\ @V>aTDP]('| a+:Ev2 a"+NPEvrjA0(Ɋ'*f%\ +OI0)-1YC)S#{X}JدWF|, @>A-} ѓMR .Z-_?Q.Viʍ2U:rg=,l S*^ @!pl Sl2\ dgrW//ZOȇ *^C+O ٬r~JL ET t UVf_ъ4 ND AԻ+Ti(YK N>A քu2IczUk mRE:Fv[GU iZ1Mʢ6q)3JFAk6&q?θvSk69}KDeFV5Ó%'q85θ*,9Aӧ 0 CF\u:m$L͎M7ũe YW;44:nv 'n[^_M2՝ވY-[~ʎ&0_%kY(ȏ#ӹԵ2zl6W= ͣmjݿm rxLݿaUoꖋb:F`-lԥxjcDe^iO]ovy]/(ԭfKҼW!l)#Ok%}0<пb }0[a W0,0xLL匴+] dž4$*zhԕҝ#gaV^j2u' >bnP'm44bn(꓎*n՜3 ֍t2IXS2/̃iz2ɡI+[92E]=Sb}bSselVXOGr4[D:orX8u\\)c ;TZ2qN[NvTHK[=W넲P|-pFF܄'f(L+ ܈*>Dn\պk1[[=S`DQ0 >D  bjwL`6L~,j,=fHj}ͩ2lMP}1i,2mkt EٵcF(0E=#Akt;Uu}XD'X G]b:C& ohҌ'GkF%W úƒdٜftZ=´w+4\`i_Wejԓ) wi_Ok\>!XOϨ@B%X}܏U|+dɂ/rZ LbiF1qdIUiDy:]}U꙱Sz|xwQiKz3N &ү*=Āۯ)ڪ/wn a- ,A\KQCJ3[*娂2]5&y^Ctu#w2f UXgᘇ֜vaz~WA+ʰLt8%y+L9 n~hWA+ LTduA$ ~2>~b]O4)!".IoM +MTYnh&OjxXfzrT [ ʓBWf<%ru"{3Mj=Ma-kN hDozPlQFA;.H%Hq "@aZ!T'>`;2Uh k t*{UFY6D ?yoEPʃ{7ơ_(7*Ie(˲>D%!(1* 5n`J{JBNp D1!I I$;xt0fx#^ >xR #]՘!W`  p%(bT TLbtA]TTNdב%I *T]Ee]ϛ c$PM?ى<:W .E'JTPҕs &A{9|Mhk^tNa^`gU2(nLqd!/uVX;Xh ֶd`'Aϕ9jMȍv7 r4a E<82:ք9ܭDL%rHЧ9yzJ(:R\l-Df$ kکmV]WY:dUspF-dBҸPQO$V#-ڃ;/|\tz;'Y4 &I|M;p^K Z@ +\{CRRpcj(D;c18D:P3RM5ҎM ]p‹vǜQՇnrK}u!%TS'/tʩI 9 v-nyt)Ga|hS~?r\ |Vqg26~?} r ky@'*~8ad:`Zx_%bn/}#MGG_vSS@5G z@I)x #r*xW|hd麑T+"9r)#NA88BiF\(@4@Ĥ2r6 QW ]Ro pwYcuNNs2Qr4eIv$ nq>y?GC<č:†|8Ix+gC'cؠ"ySX!ȗ8rea'%MlFi\&>ō _yiJޏoyIM.rͲkĘsU$5MZeJA(R'0(e$脫Yhn '8PQ4 $&TǗpzϗv9EFG~Q5F}_d_C?7E/ko4u|L""u}(.쯯_]'~^Y#$fq;ahר>S嵬Yq;s51͜kDPVH2m l͕'H1~skN>KYKdF~Zn=fWkk׳5fqm $o\{\!Xz|d;X3w`nkҵ5kI}655 }cbEki=gZ[7\#]WGZk6zB{\δK)kcFYwx %Idc}=Wv_Z{J~6Lm ܩ)tZLLemUX"ϵw!)OiwfmlŲ}}yVvuʜa띮7-yBMJi$wZvu>U׌j.~Cθovoo[3Ƌ;pg}nkst}ɴ͔.yu4!,znrk/j/AܥǩG9CYl:uu`ʸ}*)|skoiP{Yq_a~͈{&$n aۈ)WVĺw}6hn$ce} d 沸E~֮v=967,BRvyݨ㺧g\gbNd|C%[5;n>u=8_+2ME{Co;~8ruO9{3E춪dr[~n͕7/}yƻe{FSq+X.ڈOjL~LeoCrKw}UOe?f7C_cWգC~W|qsXz²gfYN)^q}߽yk:S9Ы3*F| eܳ^v|^9Z~ qr;qϓqq{@W:r@yDԡ8fDl1-Ɔ5SQo_+/:!!Ӳ栕 uy=/|뵷.n:UUhA}v'[gF/83bG]^Lyۭm.rk}ʉݱD{Ee5WgTط|fNJ7/k_rld|5;#Tze~j>5cv9=g/9k,!o]ַ'Ϸ g֣z5m\qb>8Y[펏)ܾϔO!v+31Sy@qZ'V1O[p\Ϣe#Lc ~1ʲ˷ر@ܕOul\{݌[z|,~|vZ< [bwEn䞑Eg:>SU~A/HG54?24_lA?Fr3gV #io\w1 dۺIݬ_'uΆIg^חo{w1;nD ٽۖxzVmH{֌1S]Pˀz$&E}&gS ne}vXubI99H<,L|[pOK>SFw]3:wmsK«l'Sr&]sOwo7~Gz+ bd9,˵5Sv՚wk=<*9kC W5;*kJuK=êvmMiýlA.sJx񚗟4}3=IP9'n1|vq;=smXשGws=g)fdVPg@k¼]~/[r,q^ܞ9#CU}ߙUx}}Z1Үag^VAuw+~;{̸xԼ3kD$^-7dKr𘩾W9xN80-߼rJ(Db:#ru:o!́Yylf=;3H˓/}TY+QvSc䜦K֔uUe3^+_^vPE=cv1q#a>p)VJǒ~'՟G YO^)OF'ܝ*#E+R;n_>bRlpDшe҅sTci;rG 3W6$B{q3\4_bnEkFwծ%yƪ蹔p@3~Taw֍~L~9;b ;ߚwL:F%sWX[+^32;k;WU:jb~zem}ۮR>L}Qwo쨯XNZl~EF벿O˚?6Xk˾Tvʻ,x1wuw!#Q<GώYwGS1 '2{U?yijґgen()3r :.sX q3NDǞ!뮏j1m bؙյ]]Ok^:~rӻ7kSm}Yqcy.wqwQ]MG&=u>vl}l&ݽgk+>qvo5{"~k{dOIZ5!; K {G7]>#.#Ԏ|U7}W0"yw9M!Ͱ{|L񴓎f! [fJ-TRYEZܫώ|r3uaSc|U#v^gRY9P3~u{Hɺ[Zoga7 7N7tEh֏uW^*mTո&?{3Rp}A쾃5SC0}G@Qʘc]׶}_OG/9<ͭ;ygtz`sa5Pkcofgh6U;нUUXڜרa[f? Che7],{w֨ G>~](i<;.Kw}<GMݱ|-_¢;[gK{[IٙtYW]#5׸mj1ZY{)mRZnĝM{\>Fm$1W<^-liw0brF@6v(a;96N43sc b޼kǼ3D**Zg}WJ`Baw<Ŷ3Vqlf3GSwo#s.ōHw35{3OUϢ5 }wEGz]LggueRK)bH{teO:\gxG>^f<ӎڮ/ԍ8fgXmUv)z|J]m##fLV|lz˚T73{v}msChRUn?"N缘^Tnd(֧yDe9ncvvnL{=F 'p?nkhz|vnۃ@{>߫oxogaqD⭼s1׷o{G@ πZ+m}c!ܷ(y q8z1ٻ!`g*-wtON*;Pο;f,]\`o1I˻7jg90>>[]ڐ2'wq:Ͻ##ܲ/;z.Qm>W<v~1:k5y+[\Ug$@̻?mzz5;^قݫuX$ͽfᳳ>bicL}=36Ƨɼ;sڨ~rCu}]툨s>Sb$QfE s$N˞ws4nO|^Atӽ5r徢~"ZO=gwjmF|{-j툆k<6\NLR!+Pu~0͐w_;UQ_01S܅_|<}^ozߜQ>_zm ^MZ{v6D3HH};qyWE<|ˏk?#3H*&hَm}~Ͽ5}/_k7?=7#U#|?bT_(GX^YmzͬikoTls~NAhu3OZ{'z˦{(3#͖Mʜ}wlvnKNe0Q8>ūz K=T!mZNa+}ݠtϞo7w`\v^= J}Q m6҇k#:}l,T'Oyv<7*3Qm+޻h'g삟]]p6:1ZGAQ~}1limwfzo>Y*__ُFw79.? !]~'wcn>ەW_=w[w_EڀjiwxF:/C[Hpt|fy0N 7^~4ڐ۩,?YXYyyxb߳>;u9oZZYZcL)nlWg=wf}/HJZVl9Hus ò9[V+nMuo$|ѲfG?#`$T8mΑr'x䳓v]JÑt ɋ[{+w|Ā[8>wf>zTuoFտq$U 6&K7apS[+%RY^D2-;Ԟyר=',^?:ŸXQUtf?Xݵ9pSk wOWțۺǭT$օyRWTd+ܭ'}iN=?pvΖtH;ņ{왊V^>c #ɯg=~c+skJ|Kg(=^ٵsX|L}Cй؜-$}1}/_=xsf-IGT=.fny/=[1ny޵u*<}w:߃3eJXޡkv|ૄhv},52߾9Opͫ7kY1']g`>GOYu~߅Og98zJ/D GSץy_y~f3qvo\YjRZQ☳3̃7,}1Q8lQcmfW3}]zO#'qڅ=κDGJ5}c!H_ qKkJ|sz^QaK_yGO̳?zeCyGO׹ۜȏg:]ϝx!w=ϙ:O{;x^^lYIolz/+\(x[ocg]UxKwGe}+{|C_3knջ߮sTn}㐋W`wrλ\L{{|_ղFk?>;NWFec$c+G=n=>zGOYu|9Ȏe1qISf׭Q՚&+:G4=bʛwjF[X-uσ})u /lYzNOg~g~?weƕTx.gq=9­85K{n#gYZb[ [vޤq=y8aSUnbhtXnwAMz loyz](埴=xƳO94⚅TzwcNgpc<'X=Y|: X{_On[&yՐ|mbLaV\ը黣:=zgGlH[9^7ٽR 4nO<'Q݃}vT|oGG]wpNvgSL|k5j ^=8ȷZw_~F?=Rͽ[_:vC0=zb=F5g'iyώzӃ}v7vF5~4}{s0bi 1%h{{TyIeI657>Y̮áVwb'Zˏ ˇ#&6/u_MU )-*[ōs4)~Q]v6޻>;]Qmѿ.mH}óiLwřpw Hqu~uԻ27wGX?]u{be?陕hTvAN0{a Gշ[|kyº[葆gvvi=mސs3MBvUQ3;q=XWk_Z9zn.oxlzEay_x }>Fzfh5:!7{ۇYY؂'F^0c}ώj|e~bUCvez7FzκWϭF|x#4).<9%1ǻ`[9D<4~ ָ2]ۣFYVLHuߜ3ǺQo;mվgk{+zSMMXqUĩNFi4oN;V<7qt}_3|˷p>滿;fM\)1:wLX ];-rGZcз*W9ot3}mǿ͉l.J۷H~^`g~F8"׽^yq0ڕtMG=xZ3}ƳO!O'SDŽ=Wx.̳x'0'd;x i_bfeȈ4_+KS/hґC>mToqg]={6Q?^x plS iB>=':=3ZіѨb(G:Ҋ?E~iqt}>֍]3ͫr{O/q*{6ʓq ]懶ձ;s_DW`?+O|>o#nIeGF b}d]v9{ᯞfy_yyXI+e+0?[?~wF|~u>|{gv?c3P#,+>n ֽ]=y*ΧB{čieQ>a+56u/Oox ])G/o)]W󑒺;9wE~զWփxƘxBoWbt`\5΍{pzuK7*~?k{$j*Ο3~FH]M+V:i}63YG!,OQͪqdTv5ʨl 2&}}e?~] ~v߿ z.Gl:6q$d- g=Rc#ͼ[Ik kVo睧+eXk{9m}.ohBOI=¶4M#x;Ϳ>^Ϳ>vw\qق(^jשJ]ʌ{s;R:GLRynFϾY:۟~FH9>tS(hm4=-˟OF}o6gkQ~ve?|~sTǿw^YǚR?<xbsT[9#u-7GⅸvԷڹ[ɨw4`);~-Uj,=v0y=k?բGoomG=r9{ab}eL^sye>ގj+Q]m=xgG=^,LGz\Awd.`$}cb 3='Xa~,bT•?~ڛzI5%ĸSwcz猰[?ÇNȊ<>^39fo 2u ~gpGޮYuj1FC5OyUԍ<xqu|{<' HOI:qt)f}c]糳LIkO(fQfXXvoשJ{n% =4o^?-Ϟqs"i~y_y]0?19* 19aU|,ndČF-3E'}z=٬3 gdOV;Iq3qX Z=?z/x=vO<'۷{?+?+?+_Y?x7ԸPb+qzxFg~FGʥ`JpePfsݹSgl$iJOEŚ=G8vɦfnHz:)V6􌏟Ox?RGbN۹Tkzd aC͟3z4wk=ͲF3YF[3Tݭ*?i0RoueXb$8Ǚs.͞󌞋}e{\r\kŶxi3zΝA/.t7Wu3}uTOk?>;+~4ՃYُFw׿.Bf;k@yZ|稗ݏ%QN=RY:8vOFmAus9ٺzR+Y?q+~FYj~4Z:G w.H)m$UnwEg^6l>~ޑ*8Í#bBt.;C2+6 *tbzaGڷS'ƳO 0m@ֱq͂z]"ݷԃg<;s?']gY1 ylzd뷎L;`Hj>=^+1}YGx HO'::}s8-攮jRMլ}^[Bl˛߈846gtzs[EuzV/.Mi$_)XOx ssޜ}ujgG5D|W?鞽nt;N};ޟg'X,u/sgdӃuC%?ޥT>}x ~?;uw[&]zuٿf\Y݋Wj'6tW{6Qf >GOGzb?N?NTʮƴH]`T0* V}g`yGx N⟴Nf}~+R)cW!BZ Rf;!-g{u9qVWsO݃g<,>z¿|ni˛-oPÌqyzۧ{?"Go+kQ|?鉕hTˌ~{[˧?>/tϕ/<=Bo6 ]>lşGO筓*-LG\|nrrz:"s;[-&m_YT/O`>xs0i] o~ƳO;3ޝ]׊`=Nz#ިwm5ʨj+~4[Q}v nJkybSSVNhci%]zuilzGoώj|e;|be?i.1@0x}k֝Mru%kocskg^^u69WaX-Zƣ|\o5x]m,#ouz黣wm>Yvi]=-&m:61h{_q}v۪|_uY߿^f? ]wkmfw%FKy[m,>w]peC^K~T׸2YGow|eT[YُF5g삟]xsZ#2ޗOy uty~5:H396Uϑs6wFs=cio>9ꜹn$*'ޙѺWFwy:+﫷UV֣ͮQvj>;yQuzb,ŗt,K5L"ǩΗk^w~uT*k?Qͪ|_n+_]YE߷;yz'ɱ̊O՜6z8xfRbXU=knp<+l3qފWE%+uߥeϟvgC'*Y|ێ?1uY'e!{rUZ6Z!ILř8qdɨw,muaz 23+Ѩ/ ?Gfqh6%}K|}T[ָ2}Go kUvq1.v'.WSGx o~ƫ'UjQW^b͠0o Wwwllk[hC_ew RfEH9]Au;,Ŧ~F8OpOCQ<=soG34l''-xg`,>z?uYJx;YM㫯d9ϥrW/csi;]QY>g 07gf9P| G;g,WVf?H.5Tcwz*9o.m-RRoF-x=j ǢFqO' ;U96uc=}z?mtZJ|UFꫣz#޿ i3H?#Oc"1bPW.iF]ȗz4f2 !mvVCӫ %tdž?0]zj~#ԏHƍmu>FZɨ?=zgGgkQQ l77uqH#w1U)+9,^o͛/<ᮺ=xƳOX̯'5'fNuFi}OmOzfU6PO9ZiW=b0B{Dʛu}i6Ϟ;6Hm=ؽ'Ϙ/nn{\xףv2=O:Z1WVve2Ȼi1}aTOF\ϣ}vTgkQKr~ߥbݛk{nߝ#|E<Gew65u3G6b#>WnNлdZo۪;.ԸWZ`=Vޣ%o 9}۷^~zg<{v3oTR]/!/?bEypGV u⛒Su'aZYV%C-O3}›u,>z½NOg~g~lh5wmlY]xFz:b|/U,u[ގj'ks><  nsţ2C&Q k?ƳO/O']g7S(1mK;o&c!%7$2yuY3Y=vZy3%ף>/]'xʽ~<7awQmvQ=xgGGk ~w|7f6g$qle6^-gޕA?{Q>=3wϬG޾+Ѩv}{삟] z_]Sޞn=mZ^(Ri~Fgi#>ڧ#u7Tb)f3W=>Sӈ=q,=nu567G5_e'Ӄ}vTd}F2?i䰙PziyuUpZnCYQ)mgV,ǵkmgq{ nqU.޲,-U3+-Du#:-#־(5tA>S}qBh֯8aw/5z]#Cr%i֯ge,Y8{Iڻ;5j<|}nhv ƥV2;wL{Obq|xnX=u/E~Kg4/+UWBKY%b뷟`g<;|gv|>u:W\KoNg-ƹvX6uߞ1;y_y~fo4;=y:ǝ#x=O<']ϟѓ-̳?z|HGѮW<ם9)M!1iw}i6ϞʣjC'xPvUfp4wğT];zv:bR;k|ƯS [[ dntMը6OF]o;}_lgkQ<z{b^?g삿c\w::ow/QZɨwmu z 2ϮG޹o~s˻.?T E˫^_|OfcXԽ.5|lLiB\l כ=.aVl.jHwXRUL}|;õ|r}qRKmGwG]^}v7{Fs=@VvQ swF2]ᴾk&;M?[<'w w,u8;+)J>jyYs̷֏Jj~rΛeIxνN%#]b;׬JxƳOkyf?_NʺِB;{].:]a2-`t'ܙx f GOnOg3wu-|"ZOأιO;٪ o]V{9迏?j"t}wSXl~>Qo>;_F.Э6i Odɑ@d:_o}Ϳ>F*|Ͽoϊ߽5g_#sΛ8oqn|$ݕٯqdY?n+|fe? Ŋ3$3.q&*j!/T뭆9F#o?gf( ؘw:QKs}áQz½ :::S -6Jʱ[.}9~s\3-a/k-:,ck@zFZ#~*=ŴV UݣڊqdԕYo;WϢ/OVK oPK.gDUwҫ/3ِ嗮w׎H5ōK/W}zTy'W.W.p^)BnOF5?s'Z>;E@WFc'VQ흾Pċͽ]$3;u?-TZ'IVޏt=!pԚZ~Hc>VzmL{icl5FVd}VgVgş[v8rSf&sW?ZC{x_8gas3T77MR͗P7_B|Z]}]M_{oNYK1e!g#xҨκGQ[طǗIF:tYWO,R5Cf <;>Ӏx.Cz<=~*9=g+PlșcG(w^kP8} [}$;GSPx'?|Itc:uς+}S{<#d7gAw|_cgRT?:wEZ]Mf2UwOq;m_3 $eE^Lئ\ ;T_g(\* Jbu,GOEx&׷V犯$~k@o&l>@Wڽ,$4{zG:ZB}{b"Xj Rݑ R3l-dd,Zi/xֈd_Q~}6;чBZύI65ݼ/WܹߘwQ'6,j߃OtpiFG==#Ԏt}-+XV„k9™|eY&|z QW_8;IS*^x^K#xtðUsmLr3Cm34vzaWI}&=Vj Ekƨ_]E;Z#Z[.B~6m|TƵ%5z- ֏ Ѭ$CNDA.yP-3Qێ@':YԁeDt+-2#~o~}V }H+ƖxXj+|<kx;}i4Yg j R<׬@u*F!e?R==G>lQ{r0YW+ڬ`FGݧ4ZA|DsRo/;A9pA:Ӆ+W ϨDŽ1:=j0'%a.ydOU?;.re=x&%t` cVB,$/d#ڥȑZc]~&i$cV«fq$XzzOx•tQʭ˜ '5J͎ӫw{gxF 2ѹf1{/D0O#?=TToϙ+S*b=k}v'λmފj_> 6ރ-rK| B}:Ӳ!1 AK[I(k!%ΐ"u.T2'VW hbG~f-YvՇVc~lB9iA{鱄Ș"~38cvKOKOKOKO?DO "o)&xabTO4rRt{#aV@d$:PDlH;`#0`V,qШH6$ ϓƧD>F-"hmF=̨кu% La~bs&Ax\}ڳw}gH%u߯StHtq.6t]Q[<pBB2=SQU}4LFE׼ucu{I<_~ɭ1Hhoem|)׭9 ԾޛwQ)+u}L':c=B77׿fI3>-"ɻ"mno]̑Yc9PMzO3VG XgC+Ŋ} [FLq8OZ6i*Q4#tc3ʛ5jT(qq[tH%'0x8HWû i4Ytp9g4{ڣ7ߗF]V`YoDrM)pɸFQ7|f K:<6;ݞE΢{\AʄfPr}VQODwiKNL9Ȣu %f%0s9=B@xF2^$Ǭ*z+$7xGs jT'{E\9aKo{?BNGw,;jht:Yv*;T>_jᆵe |]yEʘ;+^@2af'ژF2f%w73# m7 os=p{%-3sͫ-]=Iҧ^i4¾ojմHz:M_t֧?xӛߢ9= ^C6"Kx/# yU}HƬdSk軫1q)?MFD /^jX1Oċ6w1wmFo)yp;gGm~h> jy)Q̞LV2u42jQ|{b6pgO F;ڬLWP2#6KkVwіW4UG"ƺ*IǝܴK &0Fjd2"ǧɺq<%W&C,syR=P4D=MԶ>,gZ/)W3Gmkf1MԞe2,jG:1*r ތ0ԇ]>lGV >[}ԶF;J\WP&j?Q|_53Ci46"l|T|"y kOIO{E410 9Y`+EH'5\KlC4$GfOgک紭$dE'ByS+BuRV0J8ʁyxZ?7϶i!#[AC~/zH|~' }oȘO@ KYJŐ潑 $`> B8b9^j{2ENȐe\R[e+"1;Ɠ ՐO]=GavD/h6~&~z"onoݣ"g -^ 20nIuZB=+fܠ:]v3y}vmLc2.3ENxݹ+Ҟ-s,oGoC9̫Ɲ`~f2F-H/[ȵ#: p2sS Y)S>b Gem¢TzX1lQ"! 6{#2$sn,$,=]V8:XHZ-!wҍLZ?Ȼ"n VMf\HW%e Oa 9iE-&P^ϑ j݌fP4#}_]a@2P~n~udPϬ:jC:Auq\t T((l'cF~o[ $>Ө*K1 lY) e=MzB2_ Ɯ[bVKt*>IȨ4&'2yC/A\>ec$DELI*daSkjᾃlQtp X/Zvm.2N6lNKmd2f%Y =:1# KO3z`y-823=Lnz8r Y% uxa$]6rG,29>眘:zթʸ ,jC[H.J",Hw tNd"X]/oU˻"+Ҿ]Y+1g2܏~7ྃR?m!YWUQ= '}\x㾎SI QnXY|[|7TwT/G|.ʧkfʞHiuKVsO!U_H CNDۣ{䆣Hf^nUxq)r&sdȘ2f%4Y,=-=-=-=4=Xav}1fBq&N@VsYs4YԦ3 EaHw7OactxGDd<ylt\)r8AmT"y=Q1'[F2>xz@?KEas$L{L‰hiwQ `-R]H?Ҹ1(a7 WKTxeڐjg; ̩{I_Vв?<|·wQ*nyk|0YԶ j[3g4{̻K.+XV7Zf'X;$~ml @V@^fwȘsh2f%{ΉY,=(=yBlZf9c uX[؋$2f%S,$4uf_'a/kc=%UOcV[j;[֓Gו+,LG a\}ؓ>|rHf16IJ{7ٙT+drIrkNAk?BuX 2cdexd~o\O%ussv&4ڐ Gmvߘ jӌfP|}ia}_ lX֥T"`~`~ k9w8vS gXHwlyL ྃJ!wQeF;lOQf4{bbw׿fe^1q9ʧyR~gWF$8HڤG9F_v'K}d*RʻNp@7fk~K_Z2gz+k\<:BRH&鎊w㝝-\U?JS˺qeW!u/HWP"j+ٸ $8IhcɘO|OO & Zh33Zӡqwev>}ˊ??JrD󙖭e4ϳ83,'t># fftSOV3 ,3:}I>+YE!]Dޚݚ:;!- q]l5ku)p̽(_Tw(wERLUx#!ˑX aֺ7<'EF2f%<,$,=,=![uu]鄟~zS}&U2f%Ue cV³{)/{_f7u% vo{]zUߪ''1)[1˙glhsQ\`WzZA/Hkәci̦KHoCW|dC՚3sbe Y(6KkyNP"⾣΢Z]~;y+VpiZV𳬠{15;8%`g}$F7PE?ԞףF=.=v>1_- wP~FIo ƨEGi^EpŘꡄ ٺCfY]vv! jd 뻻t}V˜X FQWZ3w输Hɘ4(j&֙, &,[-qϠݜpAm^h;S%~e'pU8(*8;2ݖ qИҧ ;8`R^wO'ٽ?`a4R3i6Div3Ssؙ ׍L-D<#d&s^ tcwegڹLikvkvkvkvkvkvWu2ӪwQvO$A&ރ9 QɋNR vi4Y83*wg?v ٜʳо>Wvը%5'%x 9%9m-_1'i$L4zwt" +k6kOdJh91+^'f䁹_2bw6tYOQ}h}<:~y缏#47ײ{V6e_y^,b#/+o"ױð1I ̾W,o{#%V}i4YԎt+ iFGҨ ,+৭DUwc[szUn0YW+b=g: l{)W i<ݷƭijM,s|NBkC+Ϟ8b&Mwu%<-3jZ{3efzZQkf$$gRJHT계ul3loL# .}G(Q0LbHWrwƬdB$v,#V9BпrV_We8-bKY[SȣѨ$iCDB[F2f%/z{.Uy*ٞstڂfa0SRkD\nUfЊ;wg93>jZEmy+4up9ᆵe |$aptTfTV>Fk]6P?s n cVBYIY,=-=-=-=}W=$yN="l(j4Q"!zFQƗ@9!8_JvB]}E{΢=vӉfP{tJ+sz)s|Ҁ%Qo01^gv{YFVyb%}/bg9>9G}~w5TJ mҏZ#rV$sԦ'}΢LWP{,:g`x=PTouk(l@CTIvl!a<9rE1DG[8Iߙ1"n]pAmwjhgQ۩Luh |<2-`zj v v?6/;7i7rҎy[ =ȅB}HT:z)r]TtgWWC#g%a>ID<'O#ebGOl" 񍄖W={u흙wӲYzV}{za9Nj.jF;fE*EzxZڑ> 8t3S[YOd*=%HjF³Y [\w8d)߯Jl|8I }vz\ebKO?VOk/{a>Eu~ssil[>mgOgo>44oPyWt.b`_%6cјg;(z\10TTtgABBɧq˳M_wRiܦp{UG'j>d7H}$%^Ζv?3I/AZN7\H3"u`Xg>860['͆-ͲҁO3P}hwP2,j:Ԟ1#Lh}_$[=CLOH슱W9[~`OA:jũ7P]`4,j;s *EkO7׿an>pMkCg8kD)oGb=wQI}PZB>um:B,S'ͺxO4 QP0 25Rry#f=|0Y jeۉgj^ HukT'js =j)>jEʉQ ~!#G;;gGY:Am͞>[}P{Ҩ=Y^C#oYDvtW[꿋elwFB{w#~}HFe6nSHiKzY=GݼO3 ~ cVBő~^,=נ *$rqX!{?7#Nd|&Gfo,fs] 0{]BNAb ֫0k`?H~o{Bn׸-ɭ2JVtCmc"cԈvәB߅"Pٸ/)cœ0haN?c ׷ ;+$ %W}]'TJt<]JHR[,3԰* ]ԦhgQhz+_j_}o g FwyڀD|~ʫ}Ԟe2,j?o*K*Z[WΌ(6JEf/C5׿n'ovy8 תlǢR&Tx2>_>Ip-@+҃:a&l|$㚄ݑ.iYzP8o33g;ڣ΢v= jZf4{ڭZV`Yd$:{l6QFb}`~SOBZH i!}%R]Z ~Gb^N9> ((sEmᾃt΢؉6+#,$r+\BZH\8$W? bʎ"4+JFzHXc-w Es ~R޼ WLW@Br+"BR dGf&h ^j)l!OE%?;Ϫ2U*+>HP"{jZ}0ISd |f{}EڥϥMr+BZH_k;K\s@*GΪN$G΁3:}$9RVdLP}臲]἞H[o)Dw+k4#Cӳ+ Ŝ~/5q,+#Km Ҩϴ #XL#z` cr*ZCBTcq#SqzYg'Hf4R}ft/~]brW'P;D`Uzԣ~9f GnNL>iF6KK_q,Ypl L$oX}q+qs8"}֞f2l-|!q7wBe.U}8r CAVnEHϼ(=K2 #F-[oJOimRZ.;}FEmvtC`"P$k֛|{?[BZH i!}!k[n_g-}^z xOL%7G ^-Rƫ&ɴp#;; KS@}5sq7P4}? %bjx@EIPG#q1+)lK90=vjv ڐZ gGm6>,j6iFG.Ҩ+%q]#Dobڭ㾃ڐFE}2OtpYfP_.j;pn%"Z>]C3vJU]$P ^0Cja!-$BR NΔkT.V\] .3Tf ǓP-XCHTEv* -3\se|j1ׅ?jIbFd9|*I k|Vݳxk U,5A_H??#ͽ6"UBEX(3\h_ ]<]p]Y"{"VwP CQ9דUG: )y.g3CU]/cƱCja]v8,jәH~oW޶F =pڐ>R29 i$cVB̉YIXzYz*Ypw?ARkL.;W5zrBjlރ tOX H2KZ0XƬ40p)=5U!3B^uhSJABw=&MzA Npw6ZOp5(`_Rߋn:1# ͧӟ0:1;chvF 0sQ{\zk 浄=q/=z¬4?<|_ĄQ)F]u17m1G)m"ۿ?vPmߝ,%`$㚄HO{kƨ ؤ'llj*g=]g7OPO3i{I$z6dJh{HƬb'Esbd5`^W##G[! +oJPrH;ffffff'5:[;-1Ó[EƤdԪi+J;zwK]XƬʘоY=E/#HFHoɒGmdTF]ԾF;jwQ{||BGOVf[ϻ{O.<鳔#q;ճy"7W.V U*kϵ{G'ylq|Qgyb}GQjL8֯D.|!ΨldΪ9H'`Xf;;_B#yk7<݋A5*wBT[UFJ$+^Eѳ=9Ӆ&ROi4oa?2%2?j<%ʳA89ZvԇLc2֧$s0aq'I`9Nݛlk w/c=GmqhgQwx+mv3=Bm绻K{Λkt+!i ][f.>2RrQ)N'O΢\AmHg:&4{ڭZV`YWX^|cb<ס'd"@urrPP= s/ NGX8}:p}-ք,Ɩltkob⬠;:eBQ}B>Hq.곍G`-kLeO}n[ [ c#3f+R؀S>H$OlzF*y u+g`{!-~R$@<\y{Y6'BZH i!$K|'a \ HԳ7 cO,8!E8^h8* C~US}8FMqv9aiENj'_}2f%4=dJh,-En*T^Wz=m~[>w7O5jVyײzo>zby?'Ogۚyi,E=^z˅9ޥ X^]LV͑vO,{ӻÚ6\H i!-E*1Ⴉ+כ'x׼FX-,?q&BLB?K dJhH38Xzz=S^)Oz5dSUYNXAǾ]ԮjCvLoӨ*@|zįP6DFT\ Fe0OXphL_Tu2#'J6.{%N~BZH !B+c]3w,c_M31^l;sgzN$⅏uMO=[h_ә/G9bUmwH>˘Т#Z4dfG~fB&8z If$|+0{GrSysb.GyPu0Zb&<k/}:bq`C8&9l'o$s ͞F2f%<,$Mb{ }@ p'݂Q }wP^~11+9'fq$awyX(_]#!׷%^*9ҍvG{ uvHȣB]f#T5^G1n{jWw4Yo2f%;|{xTTCRf4#݌P[Qqk4Y K"/0h Zihr&TE_o<#Ta{_ ,+ +sVHrQ}i4Y>j >Y#9cei?#}X!$e=2Z>C}EJhgQ{DWP[Vv(x_31.<pX$?NlŧL p9gHFU,z2*ϒ]QwND[SsoE~ Ak!Qs >dJh6>3# ~ޘKCp<e?:hRS )b<={$wQ۽ᾃ4,jNtZoj#DH&њHR;o@?N':>}tA_:vGDՂ߱D>> CZun<; By!-1R]8b"ߛX3nW FMܱZ $cH2-q$U>]}YZ=tg$%Amc jE}ڹPE)dJgY ifKOla$1}R=U䯁uE:GDwC{Fl$5/4#wP0,j jOhҨ {V̉P n`ǚ\ݲ-<ߒ@|V >[ f Ͷ"epQ;Xa{3(̌sW11gHX0}-Ǣ2f%lG&,~8+n ԫ"o 1ƅ9qTpFH?'T߂ג-jܘT6$5&ާ1RݛQzU/gF$Gu}=iGĚJ+ު[UJl>-DtW ܏ ADb֓ d6&/$i$cVBHƬvʟ~!oe^nB[WEhgQrcHĜT5Mr|1>yX׺8 0}9d<=ڝHݝCcBZH 7!9ýRXX9} i!*3L1'`bB9[qҹ'\tːdvG =(Pt3<"yO8yoOu%+=}>c~ә:w{Op] NWg,#{g=>mM描F;Js\Am;ŒfPf4{`YVڍi?(yWտ~V9z6 H'U1I1V>'EW^$,jGHYU}"4c}̡6{vvupft>*՗>rH{F|t4hCcs͇/eh;d/>R3׏mНL3ތ]qQg*|kr6^JaX)tحSPECG) F;oNtp}'4{fw}i _ԓ3 #=Usk!K E+H|6Sx^7!X[~zȯH 5^/႓ުoi=#DŽCҩB Z*"=AxB6<(t9$ fjZj jhgQ{f0Y>#b42یd;>A7 go8'g9̓skE7ȾyQ9ㆳH&zwy/*ݷt0E}6{j 3:(xɩAsF+`!Hxh93ȫ^` *BlgTx9E#ʦ9i+)Hwjۥvm@FDpQ;΄$2rر'G_ $RNu,ٙ._l&Q? {n!(ߝOi/LxSCͣwp!"<7a(wP38O;$HpБ&Qۻ#wP F;w7#6K6V7Rfk|l5m+g+N΢= Μ3=Bt}-+XV k jRrא=!S1lLُQDLs΍L.}td򖬴dɼ*|`{ #3dD-QaP >J5x.c=KMv5,j}tpbb5{oo/YCŭµ6wOOe茉gV=ÚO1V{Z?D{E^1Rr`ĸCfwt֦@fsu!l1{HKdo^x;;}}{s<=xEg%3Qgsw@6LV)? mVg:h 뫽;{ɧm~n>3罧=ӿM`#&>J-m6,sd;0Mkt髕 3vEe-mBsژF2f%]jbG!JgCF=&&D͓Z1t{ zS#U5=v#~p@=ev.W,7nkBZH i!}!cqƉRsKN"jҖJP,n\a#˹u곳d{OR=K #Ǣr|̖ɘ2UHx> EaR#!HUƫY6@u1a~EZdA275)ذ_TU䌀ݕҾ^tBI˫\#ȞY ]\&r%_Ƿ3# KO{=9ghŐ%jSvn4j;Սwu%ݵW=ݵ'G(&fm%'` zrhFB,$=a?̑Jwi4׷r{h 9 Uj-@'-~NɈZẈ݋#ҳvyܯH.ά(ۻ)>#So; d>E}~wnˑV=_DWPqLs=BmZHVzu<}w;^1 35:)HQ3!duPt> ++ 4H/9x_$9#u@*J݁2g,yR[Am jTv}΢63\Aq ]a$].֓jo-&U5Vn'mR1Ex%2J]aR&ԓƗ}I'(ܧ";K⪣ZsEk>WZw71+3Ix,f#sV>@jlXH iTI1e}|z(wW7γ4H.?Bg`%C:jG$P : JnM~F{n4YԆtGG$gFrSuɚ_TxGGl~kgOHTBzz{<:Rbڭޑ[ u;n[Br i!-;;48&v>QURn64ݧݳ縛ߢN7H ZczGs/zD^`mvg:ؙaf)7@jox'^~Z?fwilj}vTzF2m\y~Z?K77gO#-p-mly%`N~J6^½[T3] =U&-q$6̆^S %KF;%t'GE':Oj`{3V5r;,<&R8s!z~YjC=j%e}dT%Z ,t#J<_xuLR-;9g 3Bmc"wPn>,jۃtpIF5m3-"!bg,o]J:ӖKc>+2EK'Jp߈H|A#8_Rtkt wTϯHw&?-y8րs !W]Pٻ.NG)!͞^GI; 2%3++Z2u{Zb UGmy=jE} f4{JHޗF.VP$ +ع(;E>YT6,G|GAmV0#ԦkYe_a-G3@#ǍCw^ [S =!|Wi^ǔ(Y9JRj% m^"zk]V}sPĿ 1ǑG0l7yqPbw&n2RC-[crqi\dJhHƬWԓXB8GVyh0:l mDg7--1?5=jNPjݑnfPk l~T,Y^}^]O+ Hį:G>#U$cVB &fq$aiiig)')™%NB=bWa{!H7ƨo*ԹE#hL ~? ؁c$w:0XмÑY 7{S=P>#Dxt0c.e>ԓ"|Y4.3bw[T%_vlQmk2$T7!=|QC3XƬȘYO䨿L^}Cu_U \&`8,s$cVB{w38?Shlrәg)$cVBӸW㓬9c5*kHOUZtVŬ2_# `cc:wo=gx>'Dw>#3{c8e-?XG9+a76R=MB>'wǚt} F~K]̰4aTqg[dThi,9PwTzy i!-HH5TWW1+ddBŠ`݁)p VO!l8'Exh'pA(dVyK֗; Ia:" /QEC e'֑j3qh.]+T;kJ}pl3wTJf^ޜ3g}vkDΎE6np^n:$<1ftٝ1;]iel^t_; mI@ƬEOHBY,=-=-=-=4=!988Fk^PB>k>j`.j'4{t7ײll5&ɹE,7E $^i2ΰ rpt;klΩ'-pAmH΢ww+MhnFG=; b''VHGs$U}"ʭ/ 7λѻ@Ƭf_L`ZyFR%gvZK$t:lOcyWZAS^gKc咅< Ix'/W&POsI|s{&_V3N mHu Drr)rs*=hovu7OwwR5w'#g~}ɘ̙YIhYe-}l-审 '] CuJQhIgOdJ@Ƭg<v$NϰYDFUw yċ+?[H i!-߁dtZU8.#oym O j1jܬCwT;Xﷵ9>y`ypvo>Dmznoa4YԦ3\AcRKuv D֐. [B?\R|6,R^u!nz~o9F[JžJANl[P\l< iBGy}iԖ!t}o[`YﴂD􏨡8snwlQ?9FE-':x~_-dN!.fT7LQ`P1*=, /1מE+>Ӯj:<"y']W<;HnLQ' X^',ھ`}/EXM~K2#W+/[AR\*MwrE|!# `eM]*>NYS^ a%&kc){4!au% W T#j 㾃ڐFE>݉6=hӌfP_.ciK+nDanj ;VphgQt+tGn w ]BQi̷Vps+8G{3ve$%˪sA)?SէYD?[dk:-&3Egd|-oC*q w>F"EiQIv z_ճOC'l'3" c2G- H)p /G:çP@y=?Q0b ߀zw#qf .832V>-$# gJ/ѐ{;˫1(7jZ sN*Yw`g焻.*_G;-g:#=B$7׿fB=:nxwqM{}|ְy5jnGCWz|R]Se){Ȏ/`&ғuob Y -A# tRk5=_בR&jEEs\Az*/̛ocbK[kZf+DϚ]H[HWcyG2g쌵CmŒ0(`>I| Z@s wQA@UdS] P >:~Ehtp-=BkQ5+]AeQTWz<e~:CkA+֩GL3/ƐJO[ad8F:}%&6Y;#U9(;>d_Pw#wE+ b"5K8G2f%n$cVB_ &fГM% ?AnzޜUG#Amc"GT= ë 94m%4?p68XβĢ p?\OeF{2xw$/ 3_G8kˡ!wP>gV0fw+ht7׿g.W=>Ⱦ=6&Gn3}͒Y~hgQ= :~Y`Y/#>{-ɟ`b¿g-x?g/&켥޽ƄV݂t4@櫑L#lc [ vyFfC,a7ۊQQ; Ey+ IF1"$, C+3úWJ.cVYnZafG(}}{._%ΪoeUs/h-@F4Т#:.2fLǜ3&y\G:'; g$ddLSh-#zۀ'V0ᾃڐFEz:T9kt3=B7ײe ZA+pUFoGR~&KHzk}J~ <ga j JqRfh ȍeGPN#R|Ko$]T#BٖHuFW}wPhP-GHѫð\%>IJ,3d]9E$?{ש({5UT^Cg_| F߷XcH!3c 0uKj FE;P{FbR-R3f,Ҏd}_<ϙk-RCcRi ?K@DT'm̄ &0RF!CWElÆ hus_ F&Ka]9xVEm1hgQۘtpLhj?5ym;A{Q*(8s^tn"X@r[3gdIn#8!HBXW=º(c.9ΰvX-tjt8C㾃hm=g{`Y\OULkzQ%J}H|G]O1tEjEq4Y~}cPOFIa@#>K}wUkAݜpgMg(Pd;HתDPNUdf'\d X9P.Jl,yuu3\ j19e~ud-;y ˁwbHi?=Uͦ̑D8&baѳwP:^T}ȱ[8"=e 8] 3#2f%4ő?=cBCq8p<dxfhH@BZF2f%YIhcOӞ~ FmXt>LSݘ=V9#D̗΢ҩu;h[n g?!HP/SQ[F>'YHƬ&fq$O |c f'=mERӉӫY 2Si&~4d=o*@FI^W?>o9E2IOkexFH{%1|vTMW-(r>`yya&;uRـ|}Ħq[hwGJݮ%i$cV³eUmZQ믬|gJ0P}vǘfP&4{lQVZqFa$ .Z0Cw[uJԆ4,jv67 YH{a]# 3\Yg6St^ׅXx%qeW˼,s4YԾ3ht40ݦ=X)rQ!j }DHjwQZp+ f4{=֛߳7OH+Z}Sj׸-kٞv{:Оdq4;=9,j_ Ntp#MhQ}`YP.e=P2!$31r<(b.-+j,oAu t%41[u&y=H/vȆn2V _Q;yqnU_Yx3#D3kNH5>#adJh~,$y=2]2 5Sޛds3G=#ju';)P<! Dit.'.bZ1VrҲC0C p$2eIn_ˌ5Z7똞4,1/imL !#{EźbuFkOH{J#.kl@]8&f$WpK IxH6 'Unʡs O̡иhgQ DWPZ0#4*{_W"TX%H;*̝I3#*J.H³Y &fq$YJ=AU5{ Z^(@yի0eheX:$ճE5u8 )!:_˧H{~w'bH(>Ë^{6ں}F,da >mDi?mvѭ1Ji-AbLjT9g]ĜZR%9-}Ry\`]:MY³vgyW#yIcSUO1y;GwןZPsz@ƬfO38dHk#IF)~.W"v&>丿Gөoxilӡa Z!{ #9d[1ojX3xݏK€uC^urt6Ĵ.6Og5g'|ۭKQil}Z?"wvنt?qdʜSѽ=E:(Ǿ_㨬B¸o1qԦ'ݟsSQ2,j[FEmz:f3=BR e `~Q ݍܷ;m1l& l{7f 6fbS~@B/Ș$`bKOUOPȫu|#wпǼkHbdоY 01# KO?MO+\t .:eIn{ˌ#Ɉ4'Hg'ș7:LϷ$ȟ^ 'Hj; v':*6k#|_ ,+kge mfAݽŭUGgLfT%*{tǟNtp kIYu6T6-SRkt|:GEQ\Amѐ1}_߳ >"$H1+vDقx3edwkFnsf:Ix櫌Y M2g~{ΘS]}'^֡3 Wm|G,SEүƣ|8PM-s1j_cCE`iwƛuıT ɩ8j:Y-f `8g_WޙyGu I6tZΐV"ȘX(6=#H1t\νg,EF2f%4=HB9'fz[iR{$"!, .8=sG>Ih],rw\>aޕG+2@z=8{]FyWxvejvls\AmzA:Z>&IwJO6p,p>i$ˬsKa9v t,տ&٥"EsԶ5TǃU~@\ c]!pY C퉲DǐX{6s{t0DU޿)En!-~VT(eҩ,bi>&.Gux+Sni$a3g@UD~"n'}z|Nշwɮyv)}F &0_qRz]ryWcVZ4N$@޵\7pSxWpL> dJhHƎg3;>2F>lT3wy85=АF2f%tOHBY,=}W=UњQIϕ *G5yY=f$/x cVB?)NHSA ݕ2Yg18o!-;FX((8wEx38P>HH6JL+R,!5gJucZHא&~ݣB '9? ;+ݙ.F_st€U g59꞉/Ar\R/H- 6whUo~{=7Rɽ yHD;]I2:>`W-CɶPPe*Q4ڔSe'ᚑ4>q,l!<*kfjC?YDLY0T.-H2ѥ#W^ gb3j6j=gjUV',;KH"ցjTi } Z&.,lBZH_dTX ]`:&zL\'wPIpAm1hgQҙj/[d{慎&LUeO]S)r;YR _G΄OCIw϶}zSrk;qKɓMxWԯCBXO75ܞc=9򊔰g(Wו΋,#cyiT[ :ByW5Likvkv飑|-9U,~*YG}#R=J?Oe|.t#TJ?QP%+:%| cVgzY.=XOpJ.%Xyv6-m(2f%4Y z:ő'VICv3+AKҒ/6FgK%g3~AbяḪ;V0Z@̿oťIɸ&! 8kTyy<|;LWSڞgGmhݝ`zfB@*3f2Kat4>PwwPۘFEmt+tw7#_Oe |Ll۹2LF6)?<>F;t+س:Ґn{LEKƾGW:kV uC]ft.YH5 j@x! U} #9$-3 "3k,zWǒ{d{~_m<㑽ϐ"PwPϻT% 3nΡ"it'GT]#HwPׂ FE{ˉ>TLF&>f?yL i4t.cNgHxxM1%D2ގ̡pA{`ϷQ|BGm-4j[ bsgYde>Il>KXJMGPV >[}6hgQNtp/ Or )qŨO jLXwd%+ A΢qՁc~F9av=!Y/JQ_)UO%QL@ l):{h{HIwtc+(O Zp!΀Tzv)N3ߋOIZDSgc>~c%}΢$UX1+H_rw}]/!e7 i!5u Wx3hs\il >^ͧxp?Q=+ZN᱂z;>e|}\H=FX2K{)gddDZgɻ"zH; 8G+9#%!{]]sݻnc4Ytp'4{JҨ`΃N$jd2sRaB VYWڎ;goڽL}~5,j_3Otp}-3=Bm;ŒfP{6`Y0ŎP+\WmAr[61M/=yfW#Zy }UPCu|6 @pf,s4u$̂\\Mb:y$wUEusfR$9Gqz)c%[7=l3=3,gcm3\kӌfPҌfPt}=VQVT&GKί3jᾃlQ{T{0YwQO# ch7;"n@?]w|'gi-tقBZH sS F1wNDW❧|wilUVu֫ou99ʋT >gj /&:Fe-D22'A{jw }J<ƾOs&am`!l_[ΠG=j4,jәv{jXo/ڢFw sR= rcZW:+s i!1+rOO?ӁV+-kZ{#TΓꈢ40sCnLܺҞ<}U]=}7_gT9Xe YF)RT-H^%xihHE*'㾃vhgQr+ f4{= v{ Vٺ1˙3b{>u7< i1m ܱ؃>( >E|JC0lwQgwn0Y `֧K.+hHt/ݹ8~w6Q룄7ݭ/xj,(Nc=>7g$ &Hmc\vK9gyW5=ɻ"mno]W_p FNsvNZƨU˨zqRXͻWT<^D^S}{\OfO1;=&\\!r /KnL򬿟,Cd[-g)M)QHՏ=9 22f%1H֓e?JoC,']:V,uIz||bGژff]#1s՚4i<;HZ7'62f%h,$)=<#we&l[ܢF! x*tc  KǶ1xXƬ6=kYe'Gi!JgVw Z_"ur7;ZsU[(SROFJx`i&fΧ[;̱9ㅑ[S^tOXw@D&IX~@8^| R8Cf4f$,=]VF^= 'ũ9@8L{tO>I kFHNCtn _ۃ#wsH ׽by. S3Aqwa/7<7> c[fΐ0B,pׇ}{b΢LWPIAPB=ҋDmצ&󻻏`LWP O`uYe L4G+m!xN:UaNa625m!i%|)[E1SoHj+>vsв9R,]J` aݫpqw}<,6%0YݲA0̵tA- ';#aX&$%KU ^G@(Qbsqׇ}{΢LWP&4{mҨ?fo,ǺVy/H0i5 YVBHoRψX|NmNs~>{ͧ])*Zkݒ$`C~K f=!E/he7*]`Y ,E *vh!^. >B2|IO~iTW i!aF,ט'Ge}Qz(1@\ ytOnE۸+"N!RI#]] dz18:prFwP.EshNDWPf4{_=s-wz_xtFXyq7ܵ}!-FvrH`B~8vi@);OgJwݗO>"En꘥b2ՄB!{eVa =Og=ͧg{Z?ioL'+Cع|;P}cB? ԶKg$Ԇ gzHػ w҉,,8W 1iUHwiJYH? }k1=UHnת+ŷZk{3,BZH +0U\Ÿ_Ϭ1 i!c5uCf ?zƩz=wN@=o8Y:@$]F=8 ߍ+ sky#ΉdbTOC=y_Wv87HQ=QeJ@Y kbG~0'S693V*{;וn#K{݁+٭g8>'ySٲU[fj+{ݑR&%`!ɂ}ҟMU2]3yWDޣ SzM@9ehzq=rjI7Z>F;hgQ{dDWPg?#fOwײe p#T'u[Yʸ4 c)Rrh7V]LwV [Vea^g)$d>={sFz>|}ii={}lˋ lq^ۂ -8'Hr> W5~.{i|ik5^}=}q܏ ꁬW5>O4vhgQIq4YnO':vk{Ш>SnjGԘ2 Rí dK=]b-:a9uyTNd3R=đvI7O#q1+Ug8gd1933v x񅫟?2Tz;K+[R3rwjڠ\ԪwqouA)\lL[=nw#yXm kyaX!X1aL<8@ [ %S'>Frì& EBZHv7^r+|Э }pZH i!-EY*WcOGfTY磌'<c~ybw϶O//fؗ/z$OИE4BϢb&G }`OWO#/kϹkuQhzualy`-9.9λSd(7oJ4Y -1(mc/;EJYesE/>x 63VνYمofJ%k &;Fg@ He3xa8^qcn煋{>]#7P Κ|"Pm]@%ɒݘ"Y\\9./d,=Na# ^$YbArh?AzǟG$һP#A8'SYf M)P5D`.ZW4BZH %|D)H}".MYH i!-EXcȾ l 3$R@9cT7nwQ{F`->~+}v':w=Bm/XABNoM11q qNc;:(H_BBW[cǶ}EL=rua)=FY5A ➈[Ξo'\ͧ-Ah LWPZp+=&6#Ԗq}V>Eͼ߸].m6*q$cVB@ƟѸ׋Qq;lY:t v8֨'V^1*duNB2f%tO)ݠ'#ƽ *]lO (\B[UF2f%<,$b _LtW#${/:*|nՃR#3=X;MB2Vf縟j^i|>_ ~7P_.g^jNt\u?GCf>8fēI38A\E01+HƬ~n^eS7X߹>sV[KRW7ӕ,HO`Q:s0%|%g/}5uF02f%1d哽3qfc돲Kbɉ+JNIfSNd^גy~5lM$yhpe q#ٿ"Y2cXvFșN7gb)Jlz9#$gnH ãe-@fi427=У~qQt8(wwwzE[CУX__˓B[ZrD#̤2eu]=Sl=kgyu f|&p!- 6")}'~om 9'竐k{%: TX2yJryN:BN:4_{-޿"a/ A6YXU<ޞ4j(%|#Qr6F;9Otp{dBJhTمF;z/8ĝYc[y7[ 4XƬdJhS=ä  Z=rHy~LG33NtimG8wEry=g7Mtؓ!6 Uߎ{6^r@W_D=`{/67SuQc)|*!VdJhVp4z&Hm ۞smS3%1j9>j[UFE\A}9}_ ,++)y:qsr$ yeR1 y{rpAw΢\AfP{Q{`Yx/q`6LQz?SuÞ ![Y% ՞Mx`(A]=QM| |hv A($>b(V(6he#"_B>;~m- ܫ!;W k}uhG\"45a;t mq|އ=H_$^P@J(^l);ڭs0>3BFFL`T8+3R}/1Rτ.VqDmI{HVT >g =k ^F>f0t{,jw':8FoYX-L9E~GÀz{=F52pͽ<\X+[g* oΤLiϳ UZ22T $tcT??a*gPw}vyg: @TVK3T<; ܩ^ǏྃjwQw7,j Ntp{==Bm`Yk <)=<[Kgy=^#Ԧq}0E\AmݙfP e ~`אQEpRm!Ȧ@ZĤm6tQ0r4NJ@\x0cգx>IwPq?Glg=blyĩD@X&(4F"%&ΞL#?Ȼ"gȻ"aΈ{/Oсi–TGAEDϨieFwQF;oqE}"ҜfP{L8 eGm~v˜j3ᆵ b2H>8XtĽtYx7 '7R6Bj |7e-Dad\}fCx!xgXJ'.)G"tG8 .j_ǝJF8Zgʺ$|B힘) Y,ሶU7;*15TtIkJcn,8&cJ;xᷰ;=>QmhqcGec8_N<S)΍>j75lQʄfP{YAuVjZ7 (OB-ugD~MB*f13Ŭ;*X~™ J ܒ`v9|eWgdxߵ^z6݄$.G;O΢v71no% gluRޔXGtŰ_[fzsg Xb_ #V8F},w9xOU3 o {{ތvHub=*mvg:t+]kZA:dn}l[ BZH z!m=EFՔ* 7InIƬ41+-82jsE$G8$Qpy΢ULWPģO;*rv>IuNdh>ɻ U)VwK&s+ȉg@=(ўqeޗ 9lhd|}gX &M}3gV Z]ꯏ+: v+,+XV{x+>ɲN: aa/|+evH>CmHjE':t+h}_;ػ^-GߔH µF$;ybi3 9GmV@9/X>#$*U3щ=e_H;fJGfO*_G;DWP WR }}SYudWZel nA ^j$cVB̙YIXzYzB8#EżoOt&5s.IOH_ ݼCWν"wca ٥2aR~=VP ս%О={? `ez/Z^v\*ʞ@t|dQP=^TaCqZO\;F\Qr?~&{Ñ_P2DZlG=$+>Y <3# OO9*cܞ5fɹiF|># ifKOEO$ ؿ-31WP #df 3wTD~ǚޑ~}ڣ!yϢvDWP:Pۉ}Tm9$FkSju6I;XoiaYy: sŪhsRWḣ3 }vz *rnRk0e<ɀMdă6sh5Xq`5BZH U3d0DoO- 6tsڐ̌rF"BF*Q{7*GYG\ri.PLs*fo{MZ{_ɣ63yW5L+|C gOQ)~OAvxTYOQۘFE?ٟ Zp)N$UhK~Ugq|6'9͑ghPhUvӍeJhHƬ_zrGYtrn9nՍt׆XhhYQ4]|>h[3Yoq =KQȹ=WX-\Wm6%R}ɶeQ6^%RSbs@ĝV\ ?qop]6+it?wEZ>wEwb)9T΃I;G'Ym,$몷O$>[l_!^L $C0s-BZH i!}-GIr޼!oǧ {FJRs\9 rCB\J";ILdyw6&&qs@u}ΰK(SqL?YvyNc.ЪGw jw^T^$+\TKrN%OgYʡ9{@ h$!%ilݧD}ilC~<|zi|iwj{ }rmԺuA⋐ $`:{^-1<䉧1/rƥfF* K{#MaԐt9$l7zbe/o{!\\#hq8J^ E; 1*W4,jC:>_=B1ﴂzzr.xfJ\S=⩚"$5w$cVBw,$y=a/_]Γؗ7|}wiG$W>PwQt],ش"|j&NF ae]|:?3S̨\2熛8.9{*`X5>j< F;=hgQr+-0#fw׿aKw$pDf;~h/p_PT6Z9$/lG&>3$)dy=}qir9%K[or\{5r8:wi-uڪ{# 1+y38пY,=-=-=-==!sdzؽhA_udJx0$<|KO?KO)gTÉ).ħz W%4=dJhcő:]Wzl^Ec"SO2t1eHV3Oc}ֈG)Vlfʕ<͹ KR8GĭݹDΡ4|=RNpqc$8r=j>KQV>PH}bN0"I `<X%>pAo6vQ}W\pRyᥫ /7DO-33Bj$MϪ[)Ozb  :/Փ &HhHƬ dJh,VH;3Rsq}|!1=~kr2[9T rc5DIȎ[-6vW2}@9QЉDzHO#ēe-'B:MW+t+c3gڬ<.hFwOI漗3u1(o4w U3g)5f[S=+"YwQƭbe$4T[v=:c C *IeڼGE/':8FMFVwLjzo`eᾃfG6+vDWPy}kV`ۮM'j!G9q׵uTK!~-CT޿U{ifwrugP KXq3j˞09H7O9j[hPbG@9tS7/fH޳'e5cƲ$>4!HrwwN!Mx' Jh~HƬww># z:S2٩ݧ$ ^(?sKzjP}F; 6}_{bPX\z~"`vİݟ{w S8yt޴I1\6|R L>_!2IW@0}QBH^Eh +`ܼb|L̜$9[fgO*i{MO㸝O2r i} 縓,^8v[ 1jZv*g:ڐf4{ڐf4{ڬ[4#`FPkDC+Gɋz} n0Yfg:cVGmͼ,+XV;Ӓ܏cVr-yv*wDB0_TI~~_x:toy>g̺=/v]~dߞ7*Ԩfm=C]1uEn@B[RPV@D$G+1Jg[=BZHn* n$Wj]TYJx\3),z,RQ]F7'Pc . K!PwO,.["c -M`=sZyi! N6F>N} hHn({~n4vGMG{sAƫU F (x+ߌV\qo= zrJ BNHu?+Q,)e+HwOg)ٶ}Z?K=~@7:q!/'&[YJb2{N}_G;Ntpݷ j 6{N+M(~v^H"ŨgV3g@Ƴhvw) w /GI둓VⅴBB몮JR9m!J6Bd E _01+ifG =yca~'rW7zpS7ZB]h zӆUU-7k]O$AjFEޜ'==f$4=HS=g'> 7*!Y mɘ>O)*s|&kGYmSTmS_l:=bc=`ë aVBQBVn'f| nv,G2f%Hz SX"Cu}O@YH wS5l;Dg%A~_,d|8&;'v p[>j0EqEWPۙsFGjUn JlQ:[s3 +gǕħs? j"wPhݍF;h^oe |`ށLd9o+a=>1BZH#wrozLc2ݧlZG ]5- Zp"_W=J DQu{QH q3 }ͮz\PXWXIsZRǑb()n+WLhM#릎\lpMt<5^gdF#=ց$@L=8eKdvHr!im!-Z'QH\8[˹G1ѿkԄ̽*֓ŧ/+F0Nz C$wP汎F;3\AQ 6{5+[(o'"@"şBwлy=3ݢ= +8wW.y. !pLɯv;6/l溺=& T_*vgS\оY =hbGw71逸ǑCt\a:{~v= QKa%Y+!ήzn~b %)Ƿ֐vڐf΢>}~Õ)K"4w{sgӎh/=+M;ݍF;3֑L'R٣yn:m~6kG`L|G3IH$"gژ"A163yW}aݖ 2*A֬t,& )m WZN\ U[bamד~-,˱9?k3\W v36C1rJY}Pn;V8wf`2tp;="+ a2ANh1pgFIz'3VKxA c*Y,-`f"nnwYݱ&z RAWw2̄A-YEz`):]H'^Ҿ}DE Kpo<{Q1ٜXgՄR 8֟Ijo-Kr49#w!-[ xۑ7ut+BZH i!}-vĹX( J6YJvN&m" dJhH#z cbQO:V4]*sO$HOj3Hƣ\=9,>8?ٱ)QOn^X%U^d*4!{ihO:ƼH$[0'3~k9ىY fʘ=Y.=ՕؤId$ sKC4?*r#jǶ{q?ͰQ~`T{&#W%ysD P~12H?fN[_\#UXKyyZ }-!zrۭeh+3瓽I65l"cVB̙YIY,=-=-=-=]zžBSj<Uɗg8sF*[y & ݭ5ߙA*9펉Rq[=dKp4XBmpAw΢>Q jMhH|_ ,+j+@8cɑ}߱c`9g pAm~hDWP=hEhf4{XFR)I.V2 ].JM2f%n Ύ22rJKfϴ#=b9vD4b!_?}jMC=!Hf7ǵZ3LnQEOs,SɘYI3zBR,1|&bNJB~Ar,.jhgQ)ks\Amc:~;\UdQGdix}2EzD|]dw71+ǑY mbJOGo%8Gqp=cH[bU6XruE#c-U y|1ޕ[㙄g=Y k y)oz_]ǝe'.A iu9ok$&dInV0#Hr O>444^W1c߫->겂ek+@Eu J?fvsO1@' 2hVpNtp0f4{J-׿`X@U0(a0*=*_K?kT6c>ygjLj&WN] s^1X_Ɗ0Z7-N%j2-.楸"K j;;vr0Y5[aAHEx]s̓<,r|ǚJ8صw}1zgU5Q?1*2 I]#sv^F֏yO#^D2f%5sfKO?KOW&. y%SHFzpآ-d ݽ }"=̇a kDcuQ18o{3D9*-7՗qM[>ߞYb,tr,l]Tv>+z: nv0Y΂ ~Ov i! orI"Q=gFmZ8~k~eJh'ꑌ6S:!(ewұ]P7u%Mh -43# =`bKOKOKOGOc3*bQ¾ YLRuI%2?]B,cVB_2f%H$ژ迮\|uU*4[d;=ZdiU)xfCFڜ%QSo'l:Ā\jv>y`&νN3ՌdJh43# KO?KO~w-Bn"߷ۍY/7 HX)W0>+iDikvkvkvkvkv?ovXJ!nnT5X-=YʠO.S'=)nt{cQef,нY==Ⴝ"!6N'մ +ҺȻ"?Ū9W@v>\t6s=.j;#F;]A?HWIe$sd%`u(㫯ԋ=*LW>Vm^[c+@f]ae^Emk&ᾃׂhgQtpu- ;++ؔGHoA^w" F>n1tR|Dg@[Hב0rFOm9Km&f)w2eT*R9 k$cVBCő'ʑ&^9v[ʋN,]^l3rpAEhgQ{DWP|BG^j}_4U-\|]IYy%6KXƬ_01+,1Ubv| d3e*dձc 1ݷ'v F+j;m;kv9tpiFGt}i {R\21@# $/V=`~-wg}g$ `G&ơ uUCž}r6/Rw$#DYu,[ڹ! jZf4{jwQ+x/;pB]S;8"HfEe a*~S!_Y MO38݇,S<8 AɀW֯4H}Vq:3*gQ+RtYbȜ;G ) 묿; +Oa+VlSgf E8n۔rձQ-$)?i-;6Iͼ#TyNE%WDŽV"]}9mm^΢s| 癶u\:z XNA#!o\YIuվ~^o>ڛOge}8޽&H=qȾBZHigZK;| {9D>3Šj 3b%u6'G$T{mLBZH 0BB;HGOB2A>^F[TT ү$rAxߣ1*B̮U4ڛ=ZqQSc?U IXǞᯢk˖E^ t*\6$'$qpo,{!s}I컔b\k8h7hyO jw΢SWPg8{'Q]Q wqB=@`W K ,)5gm~]*[~W^ug W2Lmc=.iQ~9# )pvaRPU& ; yW:#Oq3 SOxr [P@ 06yǨ[G4,Gmk7A {0v`JS~ϠhgQۘxp h ]NO_Y䵻uɂgjy~{ zX/,Bj0zSp;vR1&e[#TTZ'ƘF("Y/U3iL ? ;$PH^g8jB̙YY|%v=˺.dnd!sd33 #%Q͙B]T֟^F;4,j7?A0TװJ,ҵ4!gA4k" l@z1GRWݣ"oLҭGZ'Yۉ ^TuHgcPXH i!-D [)NwΚVke~Stb= c|31K*#-53ŧ'ȪJToYFA[FoԷp8ƧY MOX*j sښJ~ҡJArM6Oe yS"c=>BO{:!$n|H9P!Օpm,nY ]И43ŧŧ|Ͼ) 5R.lQgGmHg]%K [R0oXQ16G\8+ݥ?x@X3䭪_״LR_+aG1 }R7I>nw$7LXGțW=c 7Cxz3X u#]b_Pmn>&hb6ࡱ,X,W/Hj__T婆prHd"Ba^\QS݀,b:3# MWI=r F^ ERa'UhgQxpZ*Ǔʔ1j"9#;H&Bm}'-8QXH AcB`EtцʃEEL׽ S, jnIհ=CmZ4~,hgQ{ J]&3=B}}Wm&cN mLd~kR >K}TEvK #[ݗǽ L->"QB*rL1W"=^gj׵ј4GԴ'y綐. 񅴐v;Kw~#)35BZH W#9F`^[3퐟-Suj ԦF{ ;s Y!#?Fl)fhwsXdub]v{J, |x̯'EG:Pr ו%X*W,mhvg'RB&0DǞ"YK&{t jE>\A wGz-)XR+~+'?НΠ-ˮ 2VKJ3E=;wZEaN UH*57,OLchgs<X rIUQq`r;\;M-PWAS(2ޢ8ngԾ+&ٳ5:,BcB1Os퉺\m^`ᩒU[UA|[}TTTxGhz8 [v}GhgQϧ}NxpnnAT H,LE\r~}$IYA&rd/ķP% wx֨xHN_$@u{|{B> 8>GLB<+)m~< W ߻$c.Olʈ,ƧY =fbOߋO{R;UsR\I*]9y_Hأ ͞D+k{\l"|[GT'=W-[׻{1&mEm7<.0SV*{6PǹH޷[Us2v5S^ߍddzCHV`)U^f!-$'ǔ%Iʗ'6o8YH i!-D'zdbtgU }U˲Jv7gFʨ;'zM'cEʂyywZwRu!mWJ`UH^b|ϪÐFmHU3.-cݽ=f9POݾ˛ry_&f~5JnGԺfO{HܜSh7($d?7gB5KD\H )VZ[)DɞRa6@"}^*tb[=&JƤw^v0U5Y͡ifs7t># 4Gaiiiiħ=O5EHEuoKZNzf骉qT)u}QQ3 t߽Ҙ5YQsvO]yO-=S 54mMm=KVzth]d[5 g4sP.n.5Cڝ>r[6$[Oe-Xel{6zLyCfhQ~Y0oDZg^1-ro"ǫztl}vM:$FѢSTLA'FU8~9szWW3zkvkvkvrv 5V z00~kw;H)bTzz **!?>z7ڭ *EQ&'<8>#us4j̻HzBl:V3jT<25zml܏^NzGb.S ^*'u7F<8h,.88_*o.J'=+Q}SLYl C7hOPލ=~GmkGhgQe>I 8eU }6v^I=,4zfAƗ> R; ndvy0V5:Jع߃c0BHΘvQ:t \`Ih:&3=B}o)kH_le )m:,H;̶ʸ5l*l!8}1"q]v1α&kK]b}$1+g3:̵RZްs$J3_W9 i!iR-ҵW"Wײ6*]^tYeb57OPF{KivB=rnf$DP #v|%H'1`/ i2g>0Tl+ =)D}$)ȱ\o&"wMmx{j- jhgQ}7,j xp3=B뵤`Is~j/gĜ'Rp̡vnGMWjo#j,WvvHhGO{MŨB\7e<"G0y較/HWβtZHWbu; |YU\.+ݲ]hf\"˵6>R,5O7^C@zdCm! ǎwgN+3:9O]fffff77;i$b:m)hTJ1\n+{f[Pz,g>¿ŧeG\ՔQ piz³An>>jy[TLPmETR dF}l;Ys]KܗlV][Hh ɾpuFE9jvrKwEW;|V^_o{Dͯpk-"Z*w^X>Zߖk!Qo%t0F=O^ gax:EE#}b.rZUŦW֨gJ]vYWT|^d;2Vftr9pfU>_oZ|_?V F@wQ0,*y1Kƾ&_X9#T[%K6)^K N)x5:ޡ[#H5g,u:$( ::s6ZӻBY@gم`7џ3zijMךݚݚWϮ`Blޅ@㳅zM;S遑{S5 +^Ur*WQU{F v[[{7;2b i^IwzLe+^-hnL{Ts־,3EBrFf[WiQn #tN;kXks^4chj,K}.kݖeMǫ|Ww}]9_Q 1[ ɱGg=O(ܬ_w**%+eM['XL5 6&ƏQ%ɣY w2~<?gi9G wzf*Y{&sRRH)Xuۏ3b [.d^;u_ޕ8jS>Y}.s*W_(oK}sߗ v.p 䧃zzC]6hgQgWPSji<>jUvF;_Nx^P('l!G"[JaHIE^-8dWʆt0pa طQm,C u,`kƉqxoxUl?lLkt"s`* DY_Ra^x[`L%K⼲G-0?GmQK{ gEj-U؋P{׀ooKtlk徥9 IPkeEmhgQFEmWP_eGݾ^'̤}rc$帞7)z_(J'&cVxVݢ(%o`y,y)t̀,gBY|%mM*k,[tWz$lՇIގP_%.*vYWPMp*wkI%_/>G9}On'kJMpH H# ИАffqD[X|Z|Z|Z|:SFۃ>QJH^Yi kdȿ}1(a&Zi{7 ߄ˌΩjkvkvP{;>pIQcA5SĚj*3<*V]6/Ϣ$!WտHK:>|ϭ2G4ZlTBJV# g/4p]ȓ(˱#)N1fhRxg1[Nf|JznpkNDe F*tfG<,jӟFEmtƃ+mf8{-뵤`IP U25{тT i!Y21hɲ[(Ij-,-^RL):Q݌ZU[2Rx֣qN]֢qDa36J-=;MmUgz*⸁jTj9¯2>R+bBek׺-"6%0swRX MlZ[ӽ햺`i̾0fUmxWPlC0z` Xmo~6_oۛݯdz'>a80BTX5fν5˖ct&]fĨ=PUg@y!T5/(fwB򏟳(G#v;mzL)6q<뀺;qho~Rqԫ8~eZd̂f9~SL{ M.k'vS n$3[ao-vSf(~Ui>{o; [H=6g΋ I:H>trM|^*lOG1+zCZէ"9(vkmݯ3uEd7g-Ic2$+^;}n,w "A6v뾃΢6WPg8{tw)Y_TD1~yg^BY#/"UM'8ևB qVŕG{b4{ Uܵ@Gͷ{yF/-Lv[1[IHF;W7Ùž뙭./`Lyi?}ԍjXPNZ_2[ x$:FāT!b+81K8JvD[O\aCT>;I.m㋮wԌLfz glXBl)FK,!xUߌ@ߗ -"W >{G9ugWsǜcCTӹ4,jvRg<Χrs,)XRR_H5Mf [U1gŹסC]֋Tk*EoRhј@t}G~ϧLȪcVa ,õc FP^C|e>$douvH?d_jah|[trkB0k4Gi#a9Ǘ0CGUzzھkā jj' i4YԶ[xpmq qTzNE׫;w#X(cX Gk>DU1G·V8uDC35ZZG$9d'  9 jwi4Y~ j7{y^{ HƓ Hy/k +0&NAm"~t΢vWP gP]/컻HߐvAJw:i7jJ<^( yt36h8~dg/:G{ hS-fTmgKE_X[.w2~Ihϻ>j[;-f݄]$@<>8 7j[U"W>nY lfGffw 3 s,QKW>jznhgQzƒGT?VeSk=#".8#RyKBFzgYy͐, ^gQTt磌D'3>"R~kn`V٠WȌ>;$Quz%t!-)m vf,{^@d_]oJ<#6ݯm}/s%Nz܀"̽sZ[/ү@Zbɪs{C|dFV`_-mLId{$>~XC04Hk3JoN,֧P+R)rwḌt?R`w={PۦZt_T-dQ3cƒApA]X{MA]$)wCfmZW}? 8 ~7ʕ)gf?1K,)$e j!G“9M䍦f7Ǜ1vޕ!Maiiiiiiii3>C5>M1k/2[J1 PzQCW8▛GܵM/CM2Ww_ZV"}v8F0?~=)4ŧŧŧŧŧŧO5{N՘Z 'W (HShѻ+)+O:)VCeW/ILoBX,U5Ϩ-p?A8 K5RI6T \V0~5$LjQ`ݾukm%9:mH9ArǜOFLAWuB¯3&AIm|}h߀M0"F=oԘAħ+iw=RΣYz=X3:ZBM=;햺ZKg&}+ot<zz\):}RBZH`(Mg*2֤)`? j jGEmc:1*6|z׾+*v5\lD]׸ w{KΙEa<&t4 d3dLj1/:KjYN҈,)EB1^>S8H@o΢>6jnn^UEh_$"zE\X !1KJFA']QwQdF;$WPyƒ+Rj'HAFjucwrc1zsNW9;"*-UKּ զSm 0ʋ\N% 3du;}Kd3E.ظgԶv jEm2>,jv;xGt[+.GPwmWwӣ-.)ל9|+Re?h3[9*jӢ .O΢vWP/)b|ZU,G2qQfWܠ'=nL 8p+2{]`gK(u=>Sh41K݈,iůS؊6B ƾ_j!fK@Igm+FC_UQh 7Qg1zy1K[eQ2 \ kfKS*`s;?~$s4Y.'<}==Bmtw4&ʾ>xI /)[rL)X͙.,}ӆb28|FHceZq4 1]իRdпeF~+Ԛ;wRA/u/|UJdM5k}gˉ9|w)Eհ6FԘ_P"BzF%0pTdgPeu'SeY ^yڍ72Xr]A_T*.jF;\A\Am gP\%K |-{*7'cP }MUãz7VsM9ryCԮF;}='IBZHx7CxEBs=BĎHռc$ v8Σf|%K@l+*FyݞYW~؃rYjy[ Ƅ;JcU㵳&sxrR{eTqGLXoYϴI:0Q5i~b O7qLGfosKX ^)H_7Z.!2IsU}^nNv Ha%C>e 86.jvOP;EmHg|אٺE<3mj?=;u^*$.l)Ag6ú$O\ ͧ9K>'`]HJ3[b88Nvo`>? E]Fo(RU}cC%ZO[Kq?A}O'<[z-)XRWJ#:J)ĐʮBB|[  $S>$k_0$v(*Iۜp?AF΢6vOgPZR`IY:Ab%q FX}sْ8w EATi; q:(l~068&[@>֢Y 6عiyZ^q`:;G}wQڍF;K@νCbN`$qf(m'MvY >}.7KiR=e06JAj&c?Mm8Rq|F+s{kE 6j gP[UD;=1)p,~,OQF;ڽ΢!v@ Zw|c>U7u_O/=o57$NP.]Vո˨#_E}]]jw=BvZR;HAqd׌IwdazN :p?AmZ4~ڬhgQ 6뵤`I_)TC=s+ +hXtyP6y"yTx6uW DMHf vs)[ךXN9[.Vr6kdZ8~kmZc_=yJ,pAe1^ ^GY[]{WVޱ摝TyZy9kcSfjpD:R; ]Z!|3ڙDOS@˝gSw2µ8Ω5jmL Ǎ'~.jWQG9yJ׺9s/hTHEޫ,#txz~)zDϧ؋]x⋞P:ֽ/tNp?A}^F8U+98{%\/Bt0^Y #8~aO߁O)޸{I,dSx-l{&돩IjwxF]%"zZ!{%xf|J{;h\g-ņpz~u*ڜRqئYy-"]|7fzg(4MlDc;yTx|=k[]֐ulǙ%%^u}uY O#}73OJu;AyQr;,Cz1,jC:~ j 6zR9yy9e za*1}yˎ|ߚBC[P7[X-5,j3\A|*-IzmagE s7; QGe+;&OP>;)jH"w5agyerһH>jwϤR/ȹZsdˀg ]K0(=V"{ڋ|x|CHԸ {Cr ;w >jΙ RؤO qwQ>jXOxp'C9$X!*L"*A6pw R&D,nϵ,(+gFCI=tZPiXH i!M!Esӿm?v Pըi#T7h#/F-\*qԶ[6hgQYpƒ+=#n\/ڤzRJSCl?uHXqJe2]V'F)::(9шsfBL&w>y[AὟnL/&ewԜp?Ame4Yvs jMpz-)uRYTR0*xvO1rRyG\RgI: YR`$6kH.==nhԂK @)΂=Ǐל TH{;OeK/0'P9?5'{0Y:;t kQ抗LOշQiFmRpw[)1~VHj 5zyLQ?s0Y;.Q:C7ST {J}-Wܘ<Ш&m+dh}u ,D"4y)qf)-▒Zɛ˱Q i!- C-\OPlu{DbS-DYyE22U1=q[F8A6^iPc:H-l/z#01KtiiGC[K汖P=׺G*H(21K8Awͮj+U^cϻ,+Buo.[w"H*T?Z86=:Da/bŽJxDkd jXQ/z9=__!?/ 7)z_(J'&cVxVݢ(%o`y,y)t̀,gBY|%mM*k,[tWz$lՇIގP_%.*vYWPMp*wkI%_/>G9}On'kJMpH H# ИАffqD[X|Z|Z|Z|:SFۃ>QJH^Yi kdȿ}1(a&Zi{7 ߄ˌΩjkvkvP{;>pIQcA5SĚj*3<*V]6/Ϣ$!WտHK:>|ϭ2G4ZlTBJV# g/4p]ȓ(˱#)N1fhRxg1[Nf|JznpkNDe F*tfG<,jӟFEmtƃ+mf8{-Matrices/R2D10000/nd.etreef.gz010064400020550007177000001622010653602324700170350ustar00clevecompmath00000400000006&x5nd.etreefi䪮(rw-'Uu9@H[맶5{,'ğ4ː~Oa 9O(?a:y<ڭ?9'f+?i7~E>ySOn\·+ԟ:O2ب6΋ZiEmԟVT֩kzrğqrP0iq_g eG8SgsW ~ ' Cc{e [J7/g'$kO5!Xؙ3'f#߰s _Yo~Pv֛< :Nړ/fo_1ژf~Vb=zf=:`0h=b昜ggīZה6Ρ;Gw=_f1Ro68;՟/fC#^i3'ЏIDsqNg͆+S߬W9b I1_v`~8gF42+)?/l7gH/߰S_+Ϳs?;$a΀4{vfʳSEyv%9B1{ELCsT_?j;;"46{%7ΊsovQFw̍zfeV)={3^ɳ7_91+2SN)t~e.7O]f)eΔ2;9ޭ|Y;gO+e.×9UʤWevEߟ* (ym@Ϗ_&*#2;Ŷ/.40~ΙPu^ε_ y t7YbgG6g@K;.aVr9f1Y7<5=IEf uK_87#Q#K:iuk3L(N|6JM;U/1F+uNZ`f/ت2Ra`8*a~t7jK/ߘ[yr~:%7yy;9ļ\oV=bۤWmJfwD8ENt?~|Wb]uho\Yq~7h3ڜ*96sEhWV؞fw~6;f_}f=b48+Ni0⁩ȹ؎VwN'"fo>DpܳI2S/Mllہ}~gO)}vJwEN(*H;ǧs&FLa?ocϹ3@Yq<*ǻ ۧNwNبGnGJS^φKwvĔg9W:2{qze iߘ0ZXRffŀCfs7zŷ98A9򬍜4Iؘ_zDfcv˘]bɏU)Y1sbVbs;o={汹#W֘dn6NJ5rKoѽ-=GbL'0@EV%5,;J2 I`PE1.ϒE: pdniOY#1GW`(si~DYE!1Yob_[]Hj[ g=?hYgԣt}RC]oЖ5As"Fc\BW"|vk5O@gHITdVXU,zzp ЭY2> NlEYU4"ؙK A-&څv2ž 3fyuz.K.@8h `9DgG6kO^R*qmjk. $@Q =sZ M.T7%t}p&z.݊Yz0YpIN{KVЭ`?hz.iLPVcg(R:M\A-ՁZK*X @(-i6tKgTK}\/NBǸ{ `G("OP[t/ [*p t('-NİE f@A.o{q.ii=0_Dc%+ͭB6d f=0] un4H׏w1V=.Ю.#iFϥMXՀ:SN׳5lŰc^Ye(UJeGMNp Wse.A"P^[ܤՖZE",]U鬮sYT-^]Y]AP,.N."P^ \%"P^[]g4A6'f.. 3WA{! -Ei{ QY[ڪ# `Y03]ghA7:t "j+e f2ԡ3S/VHw a! His5t8^k-P^E=Ϥ] a/*(t3,TY- 2זV{<{N>6p.8F͂vAVVTe[~A֖Ku,.ṘVУ@y&w/ f=*?Uc-fyE ^ּ Y'4 H ^ y{2?ֵ]ŨMREZgz&}UBd NRZfmb9glyS_2{>AVQVdn{Yɋx}0 |%fwAsx(omq,6JߋNUs1.E<ߢl!^W]Lm2Mm*DzmAB<6W[t=*t=flVcwQ^c_#<Pڊx]IEW =O/y.VX]Fy KQe\BcV'I-AV-[[D\B/FFyk+*j8&P*%z P^p:VWew $/ad_6uK7a孭 ]!/>=6;uz<ū (/%]Kw bu^/ؔ䗈Q€z^< ;E=o[LϧT]z,wѶH/b {+e=UkKre]nXV['!D}3U[\TomUSV[zjk; be&~l]d]UryL=Td}{t1ʳ)\#/::tbx y"tXz~@ g93q\|RyЫ&e*޶*֬ߪX`P^[E^˧[0K`w (/Ev:tNYU VKxv<*. .ec.w*8gfiNJRB̞ d,a@V]|zi@y K3Lz\.H[tp"޷8hIfcL=&%$.c֝x0{@xzDZ u.ދ6mUT:s U .umU:@ЯmK@y (oUY]1ʛrƖgvۻ Kxs tP^4/⭂KV< *_^K3]^[EҺWRe=Up `(^(omUE6^]]RoBRG\.gv<69vum>;#t/hz V%t͂*z/Gk nn{)vk+U y .ah (/a0[E[-xA&U( @WrN* zߢi&oUYaM7$LE_Qlx^K ykK'VK].P8*}mBoh`wQP+äKv  1博T'b_¤[KKX%0K@yl E =P ؗh-yAบ@pKX%LȪsB nRkݏ@fs̺ N0IoLjx (Ϸ&Jݤ)?(]Q-Xb[` %Yz}m)ư+^Ļ.xlFy+܅_((gu`VKͭKDc NxU- <6(؄^(/]0*t oqTm(ME {<Kѡ[11K@yk08y^CJz]K@Xgu3(*CawB†"ICXP+‰ 'Ng|)Љ4r])"(0 &uzԖx(Ϸc v(JdEujA Y孭RI%1-y]]M蹈b3hnR[Q.ū!V H^(c}gouzZh\B+sEUru=S򥮷-NuZpW y$o|/r6:Mؚ-EP7a *wvio6Eĉq\h-%m2(oQmQگ:%iU[\Aˆ2c]]@ykBڪ x͠x^Э@yڌ=*[Ur !sB2x/e,Dxrg.9˘e2P:VW+H^ˀxY r-^>Á6e@U(NXe j^[ß0v}/f=^c\2]]pOۡ+\Rxf\kWvvA<(2P;[m &=]NJEمN\c9)敂^^p{R++:Q+\t=VyS*]cRH-o\,m}]Y2fw$/e _u/_ vBBEe,2Vy(/e2[v vAⅉ+,~+=QY@,(/O[u+DLAlK`pڌQo%a|/Xg@yk4C[3ۂVY7zh*.JE_TE򲢡yQi¡).oqzw?lYa$ (wW4EJ-_+͋z}(Az.y⹀2ofeֱĿ6˿6d [[\K e l\Q;Nwmq n)֋NЙ\,.Q<Oǿ6e ~1e;kKE_7EB})^ni[eE2Vy/[[yTm=!JM]?}07˂̀xЉ[u@ykz|928{KAVQ1:/孭O+= {uf=]@y ']]ϤϋE/T*Tˠv._yXe |˂rAzIJUHTj[vC]Fwx(϶2^(om57#$/˿6e2^(omueKW⭢mX tm7zۢ2Fye\xh .Q(Y@pm\UDxP,M{A=P^ytzoGm4(ڢ2keouR.=b z*RX\+Wu9W]p,r@UUQc}bbi!h.FyNV@ X]+-x(om]d*? v5GmctbW@VK>u/,T-=/vj 5MQ =r/5cuzz[5w/Ct0P^+-NX(dboU\gYA%Y! ˰+G\W@H:aUjF7杲%Ux<ߢ Fy$w@&uzkXՖ([TFӏ+8PUh P\iԣ}V/ςKdzaCIyV7C <޶ ހxE) (At[碠A *v(` ڂ^(ݲ~>Ӑ'T^j+Yz۪:1VHyNW ]*b*LzU媚.{KǗU[֖t=P*#H^׮Ͳ uD_ڒ5rul(5芪>3~zR}Hpi *XU:CP2/x@8$j7 !eG*]. P^4 ;V[l())H*UTp] J`όu'0Q=z kڂ*)3]PS/ڢokh}TjVvb*2,( e[-\+XW0󭠦J2nX6⒨B&ޢ]*g๔C(GvW U[VfU(EE^ԷʚAcW[)_j`W3p%vQJ yR29V#S>S ڵM< |WڊzBm}KzIoV`*x:+U@Ut&S'+TXET$o4-U!5d4L[ɷ)XݥD$b"킳ƍjSLWE%"7x )Fy}imo=ACKN3fՠYt=P^(oJRjAkPf-rkѭ@y(bW1ʫ[*t<5\z]*[Yo{Bz|bW W ]WAVwA: v@y(BYƔN,ﭶ v[-GՅ]oz^[ yUV VAPF4{"~DeLbd>" UޏSM Y*HCҞ`iv~dW|*6TePf 9J|J5ʪ@H1vq> ? N/EP%NWf 6 㭛)Hzb ݐbdW$n(+"6o)+B**.!mݯ^cϤXLpŦi֐_*.%#uH"2p5 G'AՊm*!Ҵ/tP1Bi)QXC,>B%-:Il8= @DgʊC(UHE/R( QVT$G/TDۊ]aB.(^BXDhrV_A+nrP_\񇌢(Ш )pT^r 䓋C"X7:bXNIrI?Rryޒ#~n8QyluLv܀p5_gtsU$"oIdfv[HdT; fonXckv(Y2$)ZLea SdO]uEG28G[zGlGdSQV@BzAm#?[*jRU)H5RutR:ڮtxV)}ntܬ~Z_P?HrR ϡj[8т, <ܧ7 t#Lˋ69GیIcanFSP{MS-r\*l^fC6aqv9aqNi!7Xf$=~#v3uuҚhq@w m&b~7 % s i}nD5t7^t/mzV<xɻQyCFP54۪vl6»-hp4l5p{ һQ'5/} , !s9Ibk@$]%Jx ^x UlT#HE GB%"ɆOɟbCG-|Yـ5@P\F\%f^ ſC=w$JEi%B^ kJC^^#q^axaV@A$J k{-^i|C.C  7pc{ 7 QÙdhBC4:B߀$PCL^uS0}t8D.D`21B H8 3͐qex/3 #ςA9uAHrpq9 /9,nZyE g pßs90 ~F%t@5Rt@LrtH'Ჯmh%B,ʆ򵱭I x@Cv27hȄ . Ryȇ@=\\0Yx&3#`I#oG-1֛;-ym#c(kX}_8g(W<;29!io_dCmǞhCm'o_ק,#>Mq#9Dd_9q  Kd5^v#·8F$d'|2߾VWvx?̾C!ڧ!'xYw;/)'Wrw;wF@:{Bu%ʝ]Gi6:ABޒ|v%pZr}VI}=uX 榾JخCͫk%k?}Sp9HUh!Snؚ+7tvrr$$W&gľ*Ew2rvu9]Hy_2ߞYouJ[^74 ӭ?/I,n@=ΐnG膝 }#΍~߲!S-<1s#&%%yݕdmEЏ2%){S1)ý'ɹ[-5AImnGܚzJj0QTVadﱓ!{l+YmD1f_ɰ\ !f볘7뽆1WnG&nJ8zwWN:խ"[^r;wXNraW8{6rjrێ[`Z% ~+')'zS7b4s3X,d2n,s{W4ӓY|$`7(vðnv2ȃ yv[q"CT8\ǻߝLPU NO-,$ =O[aGuqr1[^pi\' *"z($n;JܝÖ˲l~e^+NZxe^f ~' [o`:br5a훳ː"vU3vK歝tJhI翈MIۭ#%ݞ{-r[WD2dݫ*m:$Dg[[f3=S :2Ҟ+3=]nFxm#raO(ޤr3N[i’h{l>o'Gr#ŐΉ_KBҶS;%%}bp%˂p(*E>no)W3kV;ښgoiWKMw-_(qNm2*ku:-]NΑ0 \.Ke)9Mcg~YZhgGD7D$/wF' >{fEEvxs$^k<+^Œ{V$DϻF$*w=᯦<+S|Kev{m 0xK0͞ɜ;|-󺜉DKtZۋrBv|Xfkvx[uKټ{uXúq4]/qNlٙux2ɞׅǍe>Cc#㖍YG|sgb$9H}]JǯU3{8ԡDw9+>k_ˁyIlGIXwʯ[~e;-S:T܏ t~&<'["e QdIL2H;}eOeɓEq|MNS3 ˗8 oU gTyV3CU-A Qkxn93"3tw{F3K$w(8Ir#5'~@َ ̾CY{cc;v%<֎J܇$x:^-ex}57H`_B vğ*jCAk>͚k{$0Qbc짆%1^OB=1U?fɋ~V~&GrǓeي_We'JTRlG$IW~IO1?J!%Eiy;R r,)x/E3˖v|{9.GN幒3ef3b-ɰS6c[ǯWkfߧq-Oe~O*I'`խ|· kK#l;{B$^7ry36؎t,?K޹n18ɂu$Lvn ej;!3k_ rێ?-_c.Iv&`N,:2X_1_]G@2'ﺢg AJK_]0e^ra@f,=ϯ*hg1NVrߗeC=+=#O0H6K%͖wݞ~;$G6 -FKj$z XH>2o{pW^ 4_g^arګ'A KuK=2-\_*yÍ0lDYymg}}Mʫ|*tu|o{4d#=4DJ|Ͼ/k$2e޵=j{$c ,"\vX]4~Xu)3&RڹnuWsg&'PW;;5PTJ׎ Kk)J7Itux ]I@v*{=}jd,ĹV)Ѯ%ӏ "SN\˖ÐJ7J*׎[e7Ș~9GjdDr6!;#+΍#z&꬀+%UIk>\[)\{ɇT(ޯouG`e49o;Ƭ`ɠ"_rZUv=hL:⽦;]$۾Pe#^'/oimp;Im_:i}19 m=/& JfhVWwV(kJ^];o:ST$;.EN6Vn\No!C=| vʿ)2& '+ ! "wD,[Z;by@k6ogRϾngcn-us`f-׬A W}VnIfA"Ԯ>3Zfe#XjY4N +0#캸~s3H9dW%&Yn/"T-}:CԱ`td@~Md3Z9*Ut:IBc=`f oڡmN4΀dCrW9,պ:CpYw 僆dАvغ 9^= #oI^u.[חO Bv׿$wUmgw!UG0a<`G[W;2&q]* =G-qOj;^N[[_UǷ>&dvi]a}(1yY|HjC`R6+d"}̤(YH7s$\G7K!H(}zttMUqTW0vQ*%#;`4F}1z FuEwk̵[TW^[7W.YcCȣ(Ҭu|K!j%f9CnC퐽`r~V!3fK TH]/K!P;|"` jG-/Q|J/f 7W@׍+kgJȣܢvbR(Y.Y©J:CRJS@ xǷl 3)x) f E9J)j!==䞫dx_%ݬw;iVGKy?Ծ'I}Y(@'q'G:vYN퐷KNohb.4s*)JiGlu2tjg_%\pxb|v*#RrP,!HXW.N;o8uœ; {SGfseݴ*rnQ8Q0y&4BBla96>k/5__SR]5KV2{)n2Ϭ%XZMɷtvěXIs1>RhSSat37Ք38:l>)3-c=(`'Y:4[I2rˏGxKisI@eŴtrbnI1W{utq /RG`/pܗizv/?rULJqҕ{ [Ky~K^iqLq`rVl:ݷQnb5V=NJՠ'MXQ?3TZ[/KWzJ;o) 奴/KKi%WagrU$ s4~drPjeN>iѱV-W3X>Uo0V5ڑcRL y8o%qo3זȪ~T ?v:{>IPՍ`|TL?Hԯ9$o)$uY @r=U؉#_+-f\7XG J3靥(YRo)"Wo!H\Oo{!U㔇Q·>SAZ&Ho85RAȈ2E^79o!d3:C,/oow8^ߒ:N8H3,v<{BB,5_xT zTzhmwܒHNyp´㷜╷iR記w,:N4^cwɿ{%@?k~ z+%o=0{=T?Jp8X$*c[sv Q[؁&/z_ $I OpVISQ>OD~ϓy =ꩯu ILOVvkق9b& ]BDہg0]XJx4BczDĉXR[Gr̟=X|y'sA:EP!O(JSM@XoI9Y''ýu<[{݉· >~~o{O߀2(:I=tKS:+dpYo ö^9ۻp6+ ,]Xkb: zÑimVT)5G_iGo~P<<"ݲ'ajۃ̸Á, .:aK{22!硺7v2L!yÏld 5$I彑8ڂ\oCey3qNBhΐ -FcǨ!L$%a.~ ,0^[ dBB >?ʔdH˟r@ 'rX@x (Rb_…-ME X5IuD:2%lY7#q0亐D(d!t%<)g(IKbAgPcRzs2Ѓln*ZRFЇP6Pr3BiyH@#|HatWk$qg@ }ePÛwkŃqHUG4Te_ m!d~pǰtE]FpP?P7fPR}C+ (?PC>Yn0M\Ra@z (4"^@> Uis41DyN"731`< yڋ{עxB7ڣ?Z rW ooCh+<{pҀehFR1P ȑcn*0) -F; 0Ck9C Ϛrw.OXL{ Bf~'ށ_zm3",bF>FcxV#qpǙ3"Q>A"hD2=TF_g<}J#RiD*1JHƠ,wS8髐L#f |4wKĈMb W3.A-a cV7J6V: ~ڦ]_xRӈ0"ㆻbsD ;YYMc>D‰Ň22)8[]}]hc~'s#7~cوrٟE/M.e{'8!'q0̋5`}$D>3U&BB45@ro}Uzg0M,y5 k3DOGOf*ƮDD҈a]D9)ڛZ1SpƇqK"UߓGW~FN#rflmg:З#MU}rpc; ΈMUR?4IPRF4+cI蟀$(|=9q54>TV(x4z`$(|h Mc/-T˗rF ~69HkDoW+|OY%ÿ/ [Yx;5z8d.qHoD:/m[{,U3qۋfoj4])m!VqccqqOBbk|qܤA<>s"Xsn:9r*K`ɵ2m#\6чu'Az"AܸKzka J6 9=%&9'N>ޤ҄1k ORYj pŸ.RM(\SO}NDMhVӑTSPB{ӑ$,Zl"v Я&؄W]BTNX&iƃxg/iABvMnLm$׃& 64FPR$TI"@PBMV3n_9 pK|<ئ25:KH)OP&<6aG.뿘&ҡ4VU-s"Ѯ&nzU1&6ږP&@I(qI9{hP{o,քjU:5ʹHo꾔MJ55%NnӱM8 )~05MGL$d kzlzD.jGr5:5i IGM*!&DҔ?^knt8imwʛqzU%#/M洩)Rd>lEdE-ՖCNmM ҩx6`zhbjzg粒'El*Ƨ726O5=$5!_ O L`" T?1] xPæ#Aʹٿ`t 96|M5}Ț:S>qKx%ڄ6!&Nca=Ti\)lzX&W bOj'> I6k ՗osl>od'kƹ=(<lrt\h(No:m_-Ozbq>7YWMǛ]A"Lr5I'K[ 8&Db|䣤?]NM>1<'f1M4ZMHi̲TkO?';u}C2dAAݶ7f5#ft٥֌N6J<QI˞tm=_&#΂6:19Ff-k7&s]R͈+A.9(Z3*]Bx? k"D&4?$*N43n8*5-F`$#5l^yoWEiv#nڛ73}xFdhW3IsSq_o$^Ns  C$~5+}q&m&K&nJL]7쾘9;&'d DOEF$Odvӌ웏̛ɦͦU->|KZϜ9DGn4kxo>ĭ3LZ|%=/Tovjt.J7uХfәz Ls&ܱohF$Xg\?]b2>Y4דcY'>NUʚ iKovq35m=\E3dF=`InMtv]9oRznϓ8;]̊@[ͭ&`]W V&dՌ667sI$ɝc5KJ.C擯ըgj.9sHX(v>^O p>^ٳ&%nڈg~9,ov?1x>UweFF}M4.?ԧ!s̪(5׃Q ysUe(j0ڋ쮨/Ԍ*<R35#f៛⎮4}BJ8 Uʖ{7]R #&%;eN-4Zt(8‘Z| *ԂZ̓u6x"\H5{w%jA.-G<҂XCU:$(/KI$ףx hQ Ђ"-.3$!tΤT}EQЬ#rҤN͟;( f1`\Ky(+鴜<{"%$w*QˑQ 2kĪjϢ@DG..CժGbjo(U BUe7Τ^@ {m^/׋Z/O7o^o_Ib[nKt6t?z +z!z4s刭Z/7R"VҊugz< V OQ~Mv2@lȠ"֠ԷMĬᄷ޷"֠$)C}/xpVF@jEVh_kxj7!D4mj}"V^kho k >wJ6v%mEb$$zWkXztweNi9+jՊ,-ޕhfXVd͊|YfWf>)UՊnotlMM_:bt+.0ҊnOp;X]ZQV|֔>*+be\Uщ#v5Go{M*k1eTӯսU+bl%~nMVUw^y:zbV[#C kJKažK]Z'R|>4u/)r3/"<=kJVR:/a\T'_^gq|dqAѺּzts()n%Yq`SPS+nkZcyV?c iT&ѵwt>ڀx)/J§Q:JZ;[\vϡO?ފpu5k=*[D՗S]׺VT]z/[;WTo;RK52y;Uj=5a[\iA)RV #jmqOuQԷ"ZVD/+jꞧ)ҮX$bXΔ̆i~=W~;c~_|_F_0oGӳ/F_Jm"?}{+q"1%?}PۇfMk[K|(˱ߟ^2joNäLV5~->C??[ÿo7k~h佹/u/_9/-T ӊc>sTˊO|o_۱OrPx7~Nqm{m6-~svcԿg3?ޛO_?9&:_JkNRz;s~?=^q>}ȍ%?}tOI?:w??~{/_MH/X!we-ӫ햤/}k$}oUQ-_I(GIR(-|?3˿Xܫ7F[.`}ϷwR5g(|:EB h'F~!y;/xMl̼]0͋\7~[6FV§uTz'ޒer~ʆoS}"Ih/mrӍ`mAZU{V_owzCnD'B3 作RHY CLj.|ޚl^[ bAL;~yiwIG-olxBDJ*9d ۗZjWz"<݁Cgd\url%Һon~!m I?pWWJtzn: 534]o^֚V%h۠cgynS~va=a8Y폚)kih!V{Pkм%|M+cnbO+ ml!~l_@$Q>^*!r^i ~`OX(>ӣ)ޅ$^/{ts2RU{|Z#ZFꞷ}M/j":W/V%'lL]L ρPVS&e7Ob'?8,Pړz"SFFs=fe7fYBtKwY=PwNC R~ikkVMW7v"u,KE!|p1h(Ft3 @Pau9#)z"v{SF_`cR~^65 ˬW[$NwQgn/[;}7nLlfE.ޛΈ=%~iZwhƸI7z|>_$NqwhYVe>_oT}T/jS!w3ouX:m ]E7{&sƱѱ// ;%EFa1R]]dwNg O/x7 75 ZHis;5vsZi ݺpa5VqH^=@%mjV꽨Qg/.z3|v7]Lٞk ƞ3B~OԵ~kzY;Pv^PFtZSy}]:/Sq=A[CTY2@ϒC} ,>/&xu`y^;ۍe_Ik<  3gn3e2 %,q@6ճgq{ Z0'!?Z.nԷUY [?Rndg<_Ek3kؼ~VEV.*i+Ϛ%"{Ò'yX}/7 {ѐT>ٺ| f]#ZJu̒^5X"ũg-P2^/4˷f۪};/.&=n?QZ 2N#Qknݗxl: n1%ƶ/B}aԽ-[EoSŽno{gȃh]Z% #Rlq/b;^iyi-+e׍ QmΜ \.ƞDq-kgCz!  ;sަnjJŇI84lF2CkuEק_ u *8kZ];ciO 5퐐;$΁k.u({핶(ԟ5}zphD~`bIu~\*?bkN&%ZG=%hCZ< ϖ[9Cέ"4!e\r}ug~o+R24U;aͤ$-:/8Yv\zg¶5Q}!iQֺy]\fau%[7:6=D[Ml\ۡ{-XOV-E?kvLrRbG : b+8؊=4zxo\( F/<\]?H$ӎ#f s7EwV. ড:>f^G_}{j(yCЁ-Z.=r?nzzHm6 6tu)s.q:L8>^޳Hm).G]盦!z$h7]aza6Z7<ǚ:x;o:ȵ{>,StSa89=Ǡ 'c}pouV- 3ccN"3S8ZmpinI 1eI.=*T8a;wxKӞкBʾ^/zf4ꈶ^j>p]تCPL?"OŤq#'ek1rqgַmM3Jem544:'pHYN);Q[Eʖ]Ϡm? ͺ fS9YCz-8RsS9moW{dY^;C"!D/v ËkTz>awDU/iwj`(^cGtwjqΤZ 0#Afeθm*}Ej-$m"I9fDZjؽz/.@y5.ՂT-yS ӘEt/Y/[7iߋ)+:a_h]H9;,uÎ;r,4Nv?nh!7ajuA:껱;ϯQr#U J@k-FT Pux0.xIg)w MyuMYS~ ܗ0ߴN1k]\vŇfY8cn3%N &iIR@ش\/myg66g~%[0H?H/~ۂ#/:Q rDzUfVޠpؿm1~,Zk?y׵W9n9'MrEg>~`!>B` 7H:&MCD6/c62_,!&,5ԛOzx(pa[n~Fp4N0Y9aR9 Kt,U2+.dī6]]&x+A%mw6gE佻a BN?}5X a|ܼY=BTymƩw{};/c-bBΪ?c`[(/gק&-\oY3,$=H+}Iv䟻EV7yYw%-zFd8)0x3c-lܾ҃GYCxr4Fa/2'/&>.cڽr,nz`&{Cnfvo`+q#oF^oCe SY^gmwE~mfq[0OYXo\0&s;lpҚ]cp#>Hf۬wqgtyMK]&w'|0X=p73eDi3pKH+1) ^+X6y',㫴'+j|=(;0ߐv _ðMm@VI7Ʊա\վ> 9myJ$(nhꢰOdE뮻Y^0uw#`os4ĥWl2Ы5zz˶S~n|oY?.,-;yiA:ϝ@YzWHJu}^gAڬlhwճ&wCw+Zl9~7߷ݰѦww_>1עT짳Yry<@_T%{Mf=ȚƁnAY#mneQ |~7#o֍l%G~ح-ҰxN |TE,߹c @qZݧ 1?̦k?[d9cCy'dV ǘU/s ȍ@13=S/BKKtA4hgE.27Iprw4<ȝs̓c;{eRzθ)>g B^:*sx0U8l/ɴ^ FN>HQN1GAHLi @?c:_gL#x}3gh*ji)14 U$J)\,G3:\<\ FccԃNz}X/bX.q17WѱčYWѵn2AE|P]/:2ѿ7aB " ̵y sam>Wp΅.C!57)P++2sƇcHb9X.3xqK!U1$Y4*kǤ5Ani{1 bf%B05IxCspW%G{t 1ٳ6+.gF`JI{B|܉F2 jYT/ lZWzAs T_gHZT9T^ I#ݖ!%&yE`(@5Q*qo#>ڀC${00Fa,r{饔r$xP3(D%Py}WFzu҂ `簦c!K#Kd+5 FKL>+,M֗ 6ޟ)M \pᙇc5.z8b9 rH5-GM,|kzDZy$t!" ɤxP!PہAz!Rci Ϊ7*w[X(i C&? S%pd{BY۬FLIf5ĕif<[LKN5LcSW И0H{*#shL63W}8VH,@t62)VsE._4€mLPM,l gP&I18eIGYSysXmK `fXmY2Az6 9E ;W v"SXdqѯ} k} h81Ha'|'-N-%j &|{6F44) z]L4x %o6~dbX$L Id.GB|X!'@gE>l%t[,h8#H6UzxJX|nu~"5$:2 sb P$aъ>0`L(; T[gbuЙ@ygT1Gw7K}ĉ 01=+.xP4R| h2\2%֋ػӣI$RrK%+;]pqD Gjί E-!2 TC0,oafHd}dq˶o ~iNWsȬh-}n#whK| p=Fdx2)SBCtVq\}3 2C`џ4(=Ce5| Zp$y1]K.pyKWT i{Q 7ʞ"s%I cI$NFʇ] 3/ \q\F # ZfYZB 1` L\F_ΛFT A$E<-A!Bd&K !"k'tn] D!2pWfV: oBY <KC2*/0]L"\/\m> \|;Tە|0 Q/q”r7/o*P'/ $*xPxH<8UV&DOY%hIF0_pAZu,]H0T6*j @$u0EwGߓ6u?F&+t ʅo2IӣJ,.%!`e47Y13 0"Qa$Ly d3/lʑȍsc<^4C:s\0Y{IdW*Գ@D*$˄)' Ɍa_ u6:.M A,N"qQk$Or-&$GŠ 4_l7BCNB_|QD& aݐq>i[E@y~4n`,n`<c{+sL[H=i vԡw-Jjw~Hbi9 s+X+B +,DK=!^1]std<F֪ a7k\P͹,JU&=Z샤%ŗ7,~~0z$gVG,\AM)E'VZdBIAv()ZBpX8Z"2 㹢!+hx9Qg#a0^z $٥=A_֤LeZ_q1|hDn<PBFi޳eKR6 =!i #"1$4;6璠SbA.lx}A)1,}9F1$HFH.6.`Vdɲ>رVFAV`B,+ZCj*ace2t,P<[lJ܂@#RY$#l|dc&7dsApK@&+M%E M2> B;EŤX[ b\&Ӂ kݤo5u+a‹2 ½p-;Jh@PY豘 =0;AGG9AL{+9".9JBNhofe3HY y@eiW6΋!GE\I&VdCo 5ST4߿1"FU@ @C&KR IBH kJ.xkZȉE9 SP@+K_JOS.GÂ+) *b[tɀl.<,yxmZ8*Gej~)102&p4_'v3zpfb2F o-wдD.ʪTJW;yLU]6]}CR 1~-SI1(GB_ 3bEpF-y-~k~dKmA 4XBY،\™ʣvH HH˶艠d  MGPjI]J/NC^*pY򼬬y퇑dKV-M#]IQPBd,@]ۃذH-/[.U˒h%f3p@A?'n)Zo*c'7&{%eԳeC\LŚeL>'Yk;7#;rbcUr ʗJ "'ߨ*2*/ /?3؜xAΐOƥ'X1m尼]|nf}ڶ8DyK;a 686;!2Q;K2¹J,`D*b/[9r 2b*D:,TSzs(d08SYS*.k0AHVFL cTn =hYV2YÂzG1CxlE%[`߂PB Ø\_ K~pV4X׬%5pKbى6 'eIr⿐1c0RNLdeT" ~YCӥ&}@;)ìK+ (j4iI _#w]!1ˑxaIDdϔ(m`Jo]bxT""` "4P$a.P\nBzpeS.vqj]ׅڱ  !\ .HmF.]sHwR8(x n2| *<} ΩРǞ3}k?i8n }SOլ LL 9<`[H/'S=<$Hά V 'DĜeO5 cK'f= }d n@`dnY*@*%l QTsрzP[L$Ff0`"rކ!\2ۈ3l欩w0W{BHJr21Kr1 - &75獑H#M|٘ ,,mnZ\Ge)߰&n=0dbF 1OFrL^)RGd|MFBONKօDc[.6!8c,-Vט_k($L*hRL%1wԩv/2}ˤ9 7cbN7T* o#XB5$=RChF3eڠXdFd6,3w>EUt %n2)S V:Z5Z , e#:CR!f3N'KasI$:a`wc p4D i8{jM`/+ޙX&Lσ.2X)I~|HGr)~Qn`:b3 fkXL Xa AF1bH1W6d5\"/E^Z)j_`Y6K:f%9<@"R<!jn4Y%} rsbޞ Ðe\-ιnfԢ@Etqh` IAO^cn -YHm B!iQ(茂0rدJeSޞ 4,9gL@\4170Lbd۶Nɐ JrSeI3UBRG|^=4/*}>΂ 3>;#ɢVJB @p,oJrgԲ#P Qr_ $)Nl!.#I D\ _rCe]yjȉ-QA.)saX$C9 )CêҊ'Y'ƻ7$ED2;F6W(/(K +ci{W*b8Y(ʍ@R1•+~d XX); ._4xL49& R\?1P*ޙe&InAQlc[" N |d 2rc7ԯgeA}p+ I6Td%..f[,3!s*PlLyyᗬ40NdvKZ)Uǖ,$)ʥ\t<@:.wT;ѥx bd%j[&5 hTxPYuE8l&4 9RbEq,6sV#$b L?9e K:ёl+ΖHt T CJ ,k"RX,h!Y[T'DlCE&!)_/B|K )E|B&R%bO02˕2LFΚ_k0{(EiS5yf`k]iJЋr# AoVIXI:·]Ap"3(]> fA ;3HYi"Τ!L.p!X]*.}!?T偑O k[%#B_q%.s/~(5I`(BzUd6u/FҳB frR$LքJ` pH:?pWULE8mb_9,Mt!" g@#!XA!KZ*B [Uedfdh$i48:&%*<,QŶ$Ka mGJlER0b,k}fdڑ\f?0YeT_ҝ22 n.f@6p˅(_+v[+^T浊L U|C,gb!`]uQB+uHYadJlTuEKv $$IcDQwb=n^^׌OMab!(PC)=ߤaKwTںҰ LyY- V{u2h|,-f i8`?& HA LWt9O9X΂)-&/ո eyC+j25W{iэ]hQu Q ,\M仯XO,LhO ep*Ow84"b4BmXe7.tBz- cț+pJњ0HTT0CSevt@Qj%^qXD7v Ԥm-d|TYN\yk&ƲlbR˼Q @9%UE4æ"'yO(Gc ,e!sJ3aƬ5&Mn K`:@\x<_<O. ERz*+$e9#!7uY@=$*TnLx ]ꍼUҠ@墉iJa6" 4BzQQw{Ag̽)lǬ|7W#\IE\*\lͯ3PWXX()*Xm%@X*m4aBKbǵhF=YJ8*f唬]`2@ aUbv-'G!3a6|hFNjI5\Fq~W4_HxffXm!>?մ B 8([lWȠOise>TpѾ U4c}2`ާ(f]Xo1QX3+ Y/$(*CAXLt{, . c!ռN//׏aT$dqFWF0W"E:C!=E$BX k8X lPe6x$K^ɲa7;p:K_ ,fu>&/HɊ,wt#`4%2Cѽ;,ak-@rbEamz DGTEe#W#lqԬZ4XbVAě,~PdpH|-ivCKxSJYJHRyIO%=40pQO *qϓ,j !`R)_TMJu"p8Ijp9,h:bU6gu¢]a2>] K1:z=h/(qra%M}̽xd&!:beJ딀wu>Zs) KR~ EJ`+1,>2@B QMN _"Hn˙ᥘk>].Un!Ў*f%+FB˃,R ޽ OҠ[:r9/ s>SlZ4Fz-3wD|W-/JFUVj Pl4|W^+͎\xX,Qn h1]X0\]S\9 AP1*y>u0f|K $8N\X5G0> mBIx]$h0=eܾ$] )h <ƅU6f] d]ܕᓊ=$QwT,[W> *, 1+ g.% PgS,MʂsihXVCB2BbN*| xU0i%RVh],WUMZxXI&OQkrkYEPbESbS4`:]bH\&RHv*$r1c 7.4ݲ{w0$*F<1WiCĶ*m)WNZ40VɂYJ?JBH8(K!`Jܰіb]0܎K)?v)k^l6O&Xou((DžtZhŕfy8E%G J%*Mlhwݿl"p-s 3dmhO#sTdNg+)z/ B"l+<R}.HqL`eUHv B H)˜s)kf#IN3,C&e͜L͔E7pRMai6(=QL9&Jˬ8e_zu) lq72(Ԓ"vhpbtt)(IcP޳&>jf)WI `"0ޑ嫚e䁄+| '%L2Uc>LRl\akҗ ~_ԗʸr,s M(fYblBj4- +vjfYXX-Ogy6QՍ;JS9D}dv2UU4tA s$39): 20t >Ko"(HoE1j$j\xKXKn%+1d8qT+"Klad5d7;$E: ]a˥")1,e1:6~E~]0*1 I֛\{xid ̭riSIX$e+Rځ1HWB6)iV$1X$fk)9PIc2Z$ԷQB,$Zp!zja:_Rv7*9QaXaAQf)5V8Y,Ep 官bIRY[d|lgV.L#VK)3g3 jD=BM&܆%(\ 4U.hoS`l&%SWM3Lܗu7u0}elJ)| R(~ +;颴ʋ|g&n"oeeZd@FLٗ c(lڥUUḀXBt-Ud¸EcPfBEOM)5 >gSH!cfQgMoU+ReF.wLYy/p jI6#·hVrJ@LK #*+wPfd= Oh7uHb ?ʔ8EWܮ3QG`DA1xRdܣX%ʰaIU16W s8L2No 9b/2]ʤ$.W>q7E}EzjO Wʕ'{DU~a4Ӫ&[ܱ& 9*dP}*5pJ& ˊŇE8a]e\1(Bv_Lw4$ S6>*o^>TF޾,'8~;l?eAQ(,#X 0.3`ʮ0(d8d%1أ^@p hi3KQeArSmV_+pV>ۉV9 3y+͙<.oϫI mo sOLYxɻR*n&^2ijp2pCF8e+S2W1Q1@JZ(~bEiQeX1|͜K>XliLS v/ɲi9Tم)bJpHRAPjMhZV.Y(Jv'kjRN~ ÙP#󍤴bq1 R@aY5b0qKҧsQdGǘP>3 ?Lzõ-y* 9\U/c>"T d(zFpr9ɟIϺTt & LR ۂm#S2iօĻQ\)o~9-lyy`KWȎ4VQjYvK\ZbK&@i]t2#˔HdȲ-1w,R,W\6_ccXNn'ا+V¹m)޳˗H,sb]tyizOekei/.L`j:Z΂jvg))5qn>&T7eIYF:e5Th/oo&ЭC/Y<}q5ASzMwSaJDfgw f:skc"*Z Ȏ)M X\G6Edrp /Sq溎;)=H0~fح.Qly $|IdYl29s-n+-PQ{8{\TF0^BD$:֝,l.*ZC7 IVbyÒؖ)Ǩ~Cq4T^#qeЫ#['Ë+u ϱT]ߜ't.RR<:gߤI֢EqYpj27e3oR/}Ѩ}C"POScyN.~^joPM0LMfzgPdJ-95;E]oņ5wb7UЈ&`'j9]w7I-'x>a BDdҎHݢb 0IeiRsLzY \Ӗb'Q:mT#7d. 4ݜvDƒyI?^ȾRdq͖#N}ɇnNk] rW782Q^ υzsj&d|o6*4M"ɀ/7as%3g|:] `<: Α!no6̻&};u2\(GP4ns GBPgѭ-].s)$P#l'RH6٥Lϯ}K=JbC5S:<{*C8pu_ja4k/AU,oiUT#1TuB1CWEw{8s+BײA[{=E+k))11Uc>D;W Vʼ3?~Ɵc ŷ+ʰljLI,kr^ܐ-)Wb\30+Q RVK_ΆweZUzW'0uPa:SàDG@IjYqzRx*FA{͙G܁tD;Y;u~MS Py%ᤝyǚ4S.LuBj a*I5U&1<؊Gp}$wL̨;~"N*1nWVYe+6*%[4ׯ"sXIȭq WØ: !>G 0$MUr|sVD0M3hΓ 8(AJAO2B+v~ _77|^Ģ^Q$U",aY y5ZN.-_7^x98VvDsT\ׇْ/ckT *4j)->QORz(PBA8ahF֢`|6%~q?sJr^)Y &QK!';uA!?syMgc:qLvWUOY՝on=II4xvn%70!ctD2opߗf jVľ p.3Ǭz_hɑ:%RVy3z\rd+%kZoy\P]TEqx2_-0t!^u0մTqjv<(Na8\[թ ԸVC;:p\0 WOgd>wCÎq(\$LHL硧yƼ*EM)=pq-3'+TSZK4|)'q^,:ڬt]6DN"se9$ӂ=Z+ӈĹ5iPl]?մ B 8([lWȠOise>TpѾ U4c}2`ާ(f]Xo1QX3+ Y/$(*CAXLt{, . c!ռN//׏aT$dqFWF0W"E:C!=E$BX k8X lPe6x$K^I?euύ]/ \1u|u;;n=z/icksHzq5X^G{.GjujǺP;4ہ͎|kŎbo.EL.|{]h5^M8.v +\x|XuN<)WXxee1t`8.k^X/6+.:|lxq^Zj]_0Ey .>\?cuJY^Fׁ#xt9_+f:n.zSc_DkgǴ=  qa c Xi|ZU3kf~f c] Ǣ5q*==ξ.6>V;|\fkvet`[ݷ,dx3q]fJ{n>鬒Uo ھ ,vXSdY5ruF_ǂ<ǂfGk5E> ]q}pg-E6tqg{gs >:V}jlU;54o?h\X;}uZ_8Vd\َs:`xn-*z ГcuXSE ŬѱWu)|yG|X[2}kQxXWSq#='Xwk +."Nyziz^]S.Qsg#Pi|C-UW+=^O@J<;rmpm" /E+W8jC?j3OgU\o]rч嫕O?3xMCM-맶\g4,獵2_+@fMq:B/`sMLLiwQ'ed+ZT5O ɗfܲ5[ Poj>@zC#`AگF<{6+47_/}V;"NָvL].lE_ 0}O=<ćxGOD~Vj㾆񂅁 ֺ~7bB>諙4n$߻$@<皜!៟x ϻ:goaCxX-SO|,\ bB&z23ͥ_ez.Y `| E>^@īnƬDFw e4H8yhztݤuMjhZԊEґ2Cjߪ\Ogʟ7p'׺W$6]ղu5rJX{(bkEGы O,U.֐4c,-=ǐmZH2v֘m2W88$"Vr l3A~84M V.F|,X@0 {o!h 5v[4l[W{ [KjܟI$釧ňcU'bX52$ 1I>.+{a잿oOܝEa+NO\્a?/>\>dDO*Â/0#>QcP oiT>d҂#h;%Ow.}@TfbA]q/ nc: Y!nijeu$6γIZOs6f *1 B5@&z0WA*~_,b?@w |(W}c3/MB}cO׾t͟'Q͖|BY߆}MRɷ.;x5_-4tC}ZT[vѕ xz_O+O)unE\ej'/+vۅ{UhGX/-|nojv<֠] r4cX-Ƿvl^N&y/XHcmg3wzi>bțeS擶;'z c;|4uEsdnk+G߻sV=~ϗ >c4{B>ʾKnl<퇷@ Ɉ Ō~£CϥYsc5kϫmUjN6LĖ[F>X%gs7=fZeӿ)M0@n>.o*~Yv.>n_Sv]59֚mno&xW4 \FT{#V6&{Wvp=k޾c )[_[[5 ոtGeMYI̘7ԹA;&r@ۗ7Y1KcvtY2.; Mzqƒ0>B:PwSnhX"p֝7ę}QO: 6Dq}thx]Lt%bX^ؿr'Cy Ig} n-oxP: &.Q.R[%pH iR3ܪ$6/KոET6Qoc[r!Ȼq7(6_^S/f\04׺t`Bv9{/;nN/}-3 zo}\v7\ Ƚ|vv>k9?vL/\mk% *kF}3؜]=/.\ 4S\X}1Ŕɛfuϖn׶E$L`rWm#P`%cU!ܻD}w aYgknKoꖸ,[3r;?D0ܿ*jW[ meP=ټ* cMVwȷ;m>j.ښO]]8ًClz")$t4"uZu:^p6f"PAay;}ާc>:_?zkd[?%٩I{{> 6L '1N#NOd*uq!ib4vWquq:>:K졷qvߧtRsj;-t6JQ?B Yi{fJ>hl !L !0;MF|0  UZ.'(@D ZoɜXB Qlb PgvCzZS0PM?Z" D}  iZh]'bC1DZDq v)!);( -!geH~b$kjJaC~_/ CXp2QXH!vU `,"H8@շU!:d.5]PgzB[$c! ,k$,uS0xD#Ccd2@`73oJV*!U~h2+hBh+!\6tZwf1_N?0,$f$hW* :?LjRt3J㤺 TVi4 u2\(y(N B Y?bde")V#Kd x iTqǃbc07cX.Mw1=wJѕ쉼V16#+>Vn h-XёY֕.hЍ yڢe;O+bY$1ZñMfRn?%z1r" !]kS~5Ҡbz^4:x^ѡUn*$P`&B4,t,>z^}Ǭaur'ft}HLai[yft,;G<:ayf" X`ݢ ez0CagOְ@X`Yx}08%`H$rRKueՙC,Hp᛫074 w-nͥ/w@b\,hOЇ !䔇/Fyn]LX^#21 !H'*Bͬ,zZd8V暙fY0XV*FiാIj :5ѱ1 *lҙл%- 7S|-s1TE]!!hm@Yx zszFw8kl \J-`NQnV.`w[,C8 e7<(Q_P1 0jg ŵ]rPwUrqk_퀼/ 0HhH -rxU%@ʂ.H6DEwĂ&8#n-4"'FwѼz TJàf9 U#U]I>8FL776-p 7qU vDey0 ?9G*r*&Fgpdz;+e_ӅijNΐ8Ͳ[V$:2Ml>+8sxIL#3'+ z~*D .GL&F "_j^+Anųt[rb Ƨ9 V;m#ғKjf3# Q(+>Lv! DPXcH̔6ef нFs֐dCXo5PTq!Xp_CVJ)sÑ!75`mC#BƬ [0ڀL[%4<p c"("*lmVYF@eee]{CYt/âkkF!)ڑ FkUK(TUh̰cCrM3ov]f>ۉ &o$< 7=12| "^KdݡaCri$gp *ὈO=J׬ mQ9($q/m6 D[V1tXgY"aKSY+H8+2YWd *tlA3B7~Y!l~v]ZxctZ#n^_> -wadPs.ḃ~i_79<[D_xrGn `_ZU9)~ *0IJ b7#!>Ʌkiq2& Q@q21ovvb;ͅG-Bp-/'#rwxǕ^7 }8t]Ā2dRG"܌6uhǑ9M.X룐 ֪C!C25=HHaC@p ,J vd:zV0?7cC@@{bjI'9),A'wcrTS!Iq,~!iA:Mֆqo^bx[l6F)BnTkڡJܦQMܟ¨xŅiNsCz(YO0˜!±r>v6-HSw8,[^p m@H2Qnq-D"&}7[XGi $ۨX5js"$ 5l<%7-_Giaz`:$y\"Zt`.)KQLIvO0fP.qIz-n^ !j/7?F2 ;)Y#a/>O뒉SlCd%B&>ѮʠޢF|kB׎솪Y\.s"92fyMW3HJ|3C9[Ե'mU EO)kwVzOq/][l@:Sxh=1 'g)HIśNӗ'cEq ,`$]PWl{nB7=\7mQo,Ik)SBuL#Fj<^mƸZ%ml7:]ƞbui6rb|_:])t0QxA@вxIHڀ(8+ #I1ň].wMC&cjfTp.!VW4I+!Q(`G8J4M-X"3#E2r,eґI^&b>!VsqQSD}zR?kO|Fצ؇[9(C1NB+FXyHBFn#p&jVyM>C z}"ZAOiwzu#$z=ldں ])G#Z-Դ@[(׵pz5A#ٍX;>H],RDŽTŕEE1=fYLCn-bޚ#󐙇~L5|2srSryM^4 iDg)_Diӫʜ1Q}RwL&%̟}C,a.Ѳ:ԥݟgZLDq-#=q҆)ɬy4AJhW]$\ξg11]fb wY!e],1+ʒ8]ǽɸpgĽꪵlxq6:nG;OP0p4Q]ehtD'2@F!O7~۫vGIV,YDa[+4VV"䈖c0+1.w 9 5_"oH @wղ$~m>|ҝBbwy 8'a2D0 ~^Kv=^.SV* ,(5Ҋ!L^RӯJMWn~בyTV`dD8LPVd,iTAe ljmrigdBToD?I2%ԝclW%I7NAtN-ۦb+'zѢ֩V\/zr yC :#E<ѓGr(nKn61RdN ;,2m>r@ѪwwȲ\XH2; =!7Vk?+2;)ǃ$5InOQ, sd&ˆ!ߵl [6$ 74fxu+hEܿSM #*trz+E\&}xeB4vDg#z#<(St'0ge gsT$Ro(سQQ)t 0w zC|: d5i"$a󽲛 z+<m @> $'|x~ƖytTͲUmhQȲ5YK褙~7X.z/,ȍs_IIzH<q#T*,q( 1`-W6 F_FY̅v_itŧe+y*J6wad)ЇTT>7*U=$37MZ2%ë}Q:J_Q[.x0AjGdgo\W*ݘD4^N|1"|$>J? W%-X^/jXbt}LwP8v*EB^%lvq, lwWXEڢBlkß<.@hwd#^[Ԝl]%\/]vytz>"W+H'3gIG0B|h0#m%-[DPD쿶f8v0qJk>*= ‡]pAfؾnW(}-å8" #.\ɛ_n+(,iuYlbZVg `F0|M.{wTcNޘ'69񈋫We`:Uy|? ?,bGU) +/R"K*҆tQSDVi<*v_`kd[nHFi IT-);-PUqHM̱N&,eL-rx?46Ool?/G'Ya2jga/qN\L;gs0K s侒{G,yl3RH{͠cSOxqY\^+{JsKbtߨTa~mRK^GRmZSWاQZwY^'25yLV>_+CӦ9XXxy`Z(g2/E4/>"!V_ɴMa4^̙T 4;3ҪBZQ+f#]BxT:J{mi'(@ OZ`Q_^/r/rne.Ź=(㦬xX`{ªYyhcG5elDvN,J2 kU` ,W%ˬjbD{^[jYM;KMH]~(p;9WЬF'."]r =xb:G5d!llz2%$4gYAKz{_\۷~6-d%k'$z6ze-:KKl 83¥9I4} ^E˖DAUUTCQV0&2\HEQ29'_lJ6.kʵL/c5@֠Cb%2[$PX(*䨘Fi5{KzWL+Fᴸ+N]ڞ]a%k?W$cDQ]%m[ k8rtpiTt]pг{Ua]?׾Lж27*8OZȵ5|,\o/;*CQ(E[MP10KAΰQ Tq4NޒtW^ Mvؖto;kCS/~xנrԷ|g _-/YsԶ}f"h{gNJ9k|ƈDa5LwwxMݹ4a|o҃ ~SD@nzh坍{2h\rv_u;cGCzHfۥ] Uͺv>[0YfPyje$2VBSŝF4]\+݌YBRVU*tVr-$bqjT2WƫöG8p[AT_,_w%FwiTg9nɆ(8ˁ \:s-2)ߪu0Q].[Jq*< =##y.Ģ-y gӹȝ>5w\ ~c 'sSUvm=i^0^L}Ǽ(vnbz 8T{zZ1,5RX|tޤZ2LT9w@$,=L_p1))-eQȟˇ Gޑ gQ"mA׫1x9//e ߅W0Tl! I7SR3M!ʟy'|v< y7.'"e5|&J6]>D-»B_wmX+>e{3*LV!1Q^jxyE~-pFֶQ~' ;Iy[{kUW;́HXg%u;qXiY*#) /q@;\ #HAU#YB%pMatrices/R2D10000/orig0.graphf.gz010064400020550007177000004551160653602324700174630ustar00clevecompmath00000400000006&x5orig0.graphf[8dX9Η"Y}gNWwss}t__-_m<ݿq`R?o/_ϟ:u=T={~`}۷{w_X\ٞ?q9gR;Zۏϴ=/bQvƯ|>uWS_Ny{ҞCgc~#=szCqsǿ>g8;.רuoh;%+Wo_ԧK̻d^/?K?^o8bgvO}<^oߌ?/Ox {}z5im|s%\Y|z˿?7iݚeor\e淫ӵ֏wujוޓףہgl }?X۫E|{xbӣx7ߦ_c~Ʒ~[_K^ۮ$mz;N>E?-y~i~-?σy%ۏi6دRF|p?'ʟo/yp{+_}\O S>-{|yy;΋},."gm|8>^?&mn~ؿ__Wm/ߊ?͵^_|i-8;‿ͱ'>oo3Ӽ@:b'/U^Om}w6y]O/ot_yƟ_$"z(~/ϧd?O^|]ſ,[oqe/˿1_~u 3=Y4'pߧ)2s||m}~*Giוw=vs?MO.<: ӣߞwyM>V8)ܿ<~s??5FtEj;(>࿜ۯkO6t|ރ?Gq>~_yO{w}?nu~F|ӓǿ;߭꿜x~OSgƿE=͟G^O߄_?}Qv/kOW|[渂V|{}(z?#ߏ{_pŝ GFxaky~&͏9(Lc' n~?y0~/vƏ#=`|+}ϗF' p:Jyr׷SϏ(svɏ[gynu0~>ݡa'[>?qn8f wHoßKh|ϖwO>'n|Soky{kOߧůߞ_/p?~^VQYnK~(~?ܽs`ߐ_)_=Y;w5uvrCKsw^~?vw>rW'LOlU߆~'/?Gǿ'aǿBe}͟.c_3!~wm?m Ϗݥe/^yߏ=Qſm5~6Y/|{yMx;''Hπ?5?Kǜ:Y~%:Ƿ| ED>ı!}fW| N~oG+s;^r3\߮nokЧI} o0s?^3L}yl{2?OYv_m6?q>ۻ\?LiZY~v?&'?͟ޏ X?+Hqg_ߧ_&} uނ$?~A?sϓϚſp+/gşO?v%8s+?.FWXsF<>)ďռ c;}~w{W}ߞw׻D6&y1)_?fu[Vv_a}{֏λ}eO+!Q>͟<[~4׿103voT룉ש>bsNw=8=Q|3~h']m{̔yw9?2[^_<g,3ߞ.)@bÝ.׿րOڍ<~^?3O06U?[?}~oK6?m:yp?_og!W/Ҷe8zJ}1Um+7ATWs,#1<*_jCs8#Z Pr/`n)wk>b4bV;I3Fjqx1P޾r+:FJ_| #ecy_JArqWs;1b]õrZ.ap. v4cv`1Rپfq^ ^~| c&^#_^[~h|~icc5ZkL-mcρ85P~rz#O5bRNsC9>j`7G`هy1sc2 >~|pm_l=F!mŸ#:\+1s{1b5~7~ZcvqFٟ: qFLc¿wl)ơrm#Q0-y_jfwsW0mc'OVvccaT~1ڐR 4r _@1F!f'ߧy0+GQܯ|_~D p~`181d9%7;z}`8N yۿsc@Gz21~,v;G =d|騉e:Gms*1:Ɗ1Vr P 52 ~?Cr <۾F8 Pc=vĵp #HhoW?FrMFrߧZGhi/G3mOZ `;GN۞:wCsGҝ#2~1T:5*kõ5>yϖccPF_<Oɝ#o$vH~gm5Iio̖?qcC}d$y9Jb11Ⱦ:P)+fp7+7L}º&1z_fb1jLl{L ;׾9ycrSi_'~18c+yMl}ekTzFpi_*ǐp,'.o̱y1Ӿcǐpi}{15w!plKr >e7oiIG> Iޡ4UV%ccԶc^#bJט+c0n}NržX4Q>LhsBћ~ 6}mO&އiנA>VOf%bﺆO\h7l_W)[?2w} wD@wĸ-3͎1v$ˏ8tމyfǐismLGLesDlRܗbGu =!gbĶ;``aFޗJF$L߷mk\C}_gpS 1p95l{&Rm.1d;˄rkLHm4<{P=Ɯ:}^8~W%!vJYFȹT#8H1^C^9cvs &@ݙlO="'1<>O?Q=k% 89\&j1ZsٙHNİǐ+ [y!@c_xyȞl yG~ fV?vZv=/ʓ9;9^&!:Ϗ{|cr c"":cLVY-c5 ǰ1dَs8@l2ssH81e9=vs#iQ Αzڮ>wM[01t!fi894>]o PK AAE.ػM?89^ay!%ޡ)-KEя8$k"MpU(@p09T lo砅{ \~wK1Ka2+.Fc @ egɱcq J{T(ľҺ,&0#~r_?$JvUDcLZ3+ JD߻yxe?vB2f`ܹG_;Fο \_L.u CM/sزk331DvCF簥 Lj۾İ]׆t[tY:7FZ,pANY^1ra4,5d#AZbsBeđ 0$6yəmP0*f;sќOIN9Q]KŊ~Dl!9r ݓcEƕӯ,,&͍Za΢LKG`%3ć\(J/;ScbSg1:=iVwvMUS 5IXo-q'/Pz[x׹_:XRs˔fʾrI`OC&Ą8KPIPIQpp?%Pm,HaQ>Y?3DJ[Yn6>\|CH1Ɉh¨{uj8?+ZN*T@%ϗrBm|U u+ZΥԸK:H*K\6| ,@[RrͻD6`)>e->? ZY}v~ pSzg+2_ Ul0AX6+I? n7`!$cBlgIaT"4kôbb88sVˆ'HL<+.g/3y['|qټZ^KyӨ^>sk>DEЇZMV2DCA_%›"GlCD/Z竀37g_ULHj2w̓|aP:8Y`b=gb$nbXr#b/y3Crd"NvyrOOs?*pؖ-*S||3wn<'(l[ij~ "آȋ_A&\Vm.UnĄ]0gXܩL=bdgn1]jJ0Xn&~P6BM3>S$woa7h~Ȁϰ2o;,oZoI!a]" o8hag}M &ᒺ)T6Qad?x9_<"E󤕼$NZ Y&0_^g]yEuƲǠ0Y42RAL6Wf_尖VIH'?5Qbpb-z(D)#xa; 4A$Ep\neNRK,zNYa5Nلj4vb"Z?odKYy4 c etYb45d{Z_6dI1؋שR=Į`9Vǰ. >zbx!Rpm}+WaG;{GّDsk̡81,_n%#(d2]>0`/M-wI.><Ž=L3Nj@Hl?GJ'JB/9޳$BBTT7ɉ;)\gGb@qيrcHlHPelCԼ)#)0H8(uv") (K. VP^x#+gg?L/v.ThBDZ<6!vz_ID)Geu?:BE\NrH(m G0Hj@YbFɍ\l5b=9ǹjAl+p5@S ~`{^jJruh "'7Y0J)˘"b'JlU9Viz3C"()E84G!yj~maIx Tp?dl\Qa5!+ܬ2KY66j&4tjOI'q?6U12fGmIYZ˥|FAގjXN.\:%yd1l& 4qI @gԡI62-yM&s9`7 }rp%2w8d"-}:ZReWEjbǭ!N7P+"h. DӆOXA U^DYdKa^W@A>Kބ9i[`U>C)PZatߺ46/ƍXzI$lj?i"r=Rvp$@~!R&L!+`)ph >r8@MpCy Fr3QAyMA $J Hn{Ȕp(ȖHd!kh%`f \!lVn;KGx?OmXW =FF|i^!G :XF߂NӦC`^hhF;tDX^F#sa6 ȗ:! /QcuI#*[@R}p2N͎8}m):DŋՖX${d[jS|{9trtHlfDuMpt.2EfЎ&Ѵʆ =iM k,wSL[؛hr@hgwǷJ/>S0ޟgm`|]nFHЉފ6!1%̈́b]ԾR/hKF!_Hhֳ oW_++$J> mɘsٸҍlcaR`>P mB  \7% R%W xtVPث "ys#g]n֔tH>cq׀w4F5YIf"92k4X`NasȢRڷ J_,Y =*[f;f V K6nhK`'n$oA&* C5'E :^u8:J["|RχkMTS! D'%)'02! ώBA+7 A,[!yf4y GhP$)kF~ sXڦ$ʃUɎ; d%% &卡8OFLJ?&4 Ot#!HHJS,9'i ~Z))=X$%93$GnJF/V qA<;GꌐJHeX$"Y+A/ 0b]IjđكQL*߻/iCNCL,d/h&:dN aR+:6>H X6 S%V JJ躻F$K @zH&wah@i*)T3? u < gy|o~)$bL'KIdOf=&-gdʤ,N:#G׻<"C6r!9З5ЄPջL?$JS8f@*6l("vEZ>2KNMRܞ]LNG_ 4Kz'HHn{vY9 } c@~79ƆB"z2b2&Aa8F+(1}B, )!͈ęrx?iV]i bPDQO&vY򎓧sâ: XquݴB"!~-RLؒCOrJ*)jXP1aͬݶpZhf91?eL^<- 0J9] m8[h2̤N8>lY8LVBvGMr*cn*dž{|N,T$ߔpMbkQ,_m4I^LNpE~-0v/60X9Zb(Tw8YMI2{GP,_h>cPZ$|5.7I-̕R'y>I8'Ükl^deۇLNQ/rmdN1:)V5[wZV5Z&h(E{j{Sҋ9EigZXpv!iH'-,Ū{hcltFz8/ZՉy9L#N ĖQTfw |!"B1CuB6_t$:ohՋ7T9*pBhp yMIe;)MD%3t(,YCXԂ;&[$֛X'=;b76.d`HuX$ɰzёMZWW ?Í&UV4sCC䆟ays!/dTAX'd]QК<ɾճHD*ewb]7"e3aHԚZ.m8NLҾo:~Z^&- }PZ#ؒYYK♁ҨImV N50mXp鋺= |OdQ iρ|b(zOx#aG!=:Po`jA]V,Nըۼ 0ܼD}l,qz`6o=_ Zd6&5U8d`amsgaB4یnIƻܕ4I.`dc=4E'FjI5΢'˯gлKc֘Dj`yӵE׾ס~CMq8ߨxOV= 0ݒ;P,6Ê$Y^4*tIԏ۠OS*DULG@HjN#PuSo9CN'2 osl+Xeae.KGfCI ^맙 u)q2b4'bڈNJCEW6(,ꍸ в8C9MZ$=QYW+/+w2!=l" ɤ%ɐ|G:}6L(2ȩf6TBG2Z'!,$͆:{el,-49ܢ6{“í'u%n}+ k?fU/wOxdք/M5&f2Q 6ԛ}#qEx݌ߓ=EU[nɼV]HN.|&7*CbCX{?A:KVb|(^%r,q9n(qu!=/ cw^#@Ȏ,}&>C7ΰjHm*$F}aڬzMvz%bT)M-ѸNH d7\  ((v `zеq1XɛHʦv6UuE  D)c >8 `rՠiqq+Hi+!ғ^0/ e">Fg)n\݇W HlTXQʕ eڡ1<Vf"K~Ƥ9xyI]ӳʲCPOA.ѩ& qu7,у3hԨYҿnj@CҢ}- zV՟J7y6VԚfqfhb$Bk$|)D -g9X.r/AbF_ H#YG^+R\RL()bw'%Ǐ,4He!{WF.K*D&|}[*`QEI+z",HLeWrT79+ k{ERO|Ev# dS O۔צXɎl56%YqsPm@bf6 XAbe6%P`B֎l t>UIoU VBx=ٲ&p@Ia5A-k’(jkYZ|v/mg˚8jA'&(ɍpQ?p,5WڔAd>OvۢZc^j-(Q']^;hA=d ؘޥsKkCo<=FfRRj8ER+9>9!RjFn4{ZΨ(KBZo1v4 $d t$4P>4LQv0]2*w9X<$f!Tf@ G5HO(o4YY+ڑVȴU)i.Ll Bi2UϞ6CkDPvh9{_ZeC֘ܥ6Tf,D۴dg:5Y%ÆL2Jcꪱ5B>Fj=,;VSڰON2Ir-N 16I!Yf>!Y A"rjhļ\dW]Bdɭ[{|0QQBiiD, R𾪴l>Wue8qciN@\ۘx=3yfc 4yU<!X03R랩& 3,K؄sp3Y#ɽl#ܴ$IdqZtрڽ $C@!4//BDh]P7yPt2uyij䩇R eO'R7$6B@@OHn/5"eqp%?x\.@AXb87322aؔ2g$(eX V4`IPq˒Iby/.JԸ4s3TUrFkOiP5 Kyހ-ݡ.Ϫ}.n dKENSS<7g͇ܲp8yur0ߖҷluu0S HF_k18gE1#_ho#٩疳$"GLe Jr8? ԸM*dk8NU#7R2-Rs4>ɭh5m(сbdM C^Sk>zOhQ_~MU6/c`ddSk>:c)=b)@F8 QN$L؞y`ta"$J"Q̀zM/nr(4gJ=Ηw!rX"w!8W&hm섋CuRD;X)We-=)Ѥ4$؋FQSb&5PUJޒnK ;OhZglaUh˃iJbJ::<8B={ Qƴh?Γ-YZрHaSG%EGG4sT em0nj2e*hat>M*j]K1Mh5 c0{y6(XGEU0Vʜ)wpHꃱ@LfFS4:ی*vR+htx cј2i()+$a9E+< }RtIc[ ͖qḧzu%#[Kfq;la/@W0ɤ~TZcYy[TdR`TD 2gR]~9ºWfZv Xkk| +h \4=6c)ªɺUC71^L+6B[k\E?٫BLy lV41v$9@IC0ddm< Fu8`MMUK-8:+LZF3'HRH.fԦ*vxJG&bJ.6H6zBof-R-ItMf'|`y68bSA|U :%zƟڸ|yLmUʨ+E ͠(-QHYhIó~MϋEi9 EݚM8)iqSa9XN-eE93<=4TWXrSUCtQ؍^mYZ}Uϐ7r Z>{ȬzJz,j^Ey y%m@m*ۃfI_@rCwQ-9;7Vuufrr5jKsWpviA"ͺ)XcmUwu/Mk7Uj([co - E0M4fi`'oLNU6kǰ U #SыKMVۤo.U4^TsNbm߶CCx|zkL)Lz{tOX(\-@m5E3pUG[U`b\L8  Yߧ~jX/Ě!ar6dNKtsM.q^Y( Smb\RjW[Hm!Zlxư/m!0gb6fVG&s?4 {D Nj$j` tljTizkXjr׻ȄghF gdcKq u 8gd]O]Lm.lSv708iS753_=q6 5`LO lm$4t "kS5כ\7/ӪOzV~\G0ъ$s'A,~KSByPN-OC/!*}1+УҴ Y^mˤ`KGDP1]XC" 团-v94PzϊdP(!elƫ!:RYƦûJ io=@v14Cv]nsVABn?;]ymDVO=7vv:jSQjF#schjGooQJcTmn f+aml6B3P)oh^c\Mwfç-EhXG]F>ʡ%>.v( hMkb8xuM(ʂlGPcId(QrXm :ҳoFTfԋy|YrTCާZwMk%hS m=u YSNŊ잤Ğ6Cp։C5647NY`l%/ _\}6AuN3c/:6DmSHC:ebuhiR(u#O;J$czlP̃FvxوoӜhnd:hieU4:Ξ,u ws13>Iqq.2)YސJD^R.7Xc=&Neue#$;!@ e;i$Q?BgIԽlk"+K軬,ikl..ݎbݣWp ,;,ڦUJIPoٖR!f{rVTN8@XgjTVyahÄn .X'|b:8Ї1C ٝJAKN2 [pQ5:h ci+=$tdjg}4L|^BTɺi[d(M\=5l>=5Ih19,tH\ Kfߴ8Q1i=n G9.0Oߚh$Mզ p-+BYJPn$0_U֘ ='aJ͢b8 ,Z ?C u45#KY Bi*p&fe-\oY2yNEi"Y_Dᚯc_ }+viÄIrް۸@d5ӆ .'ۃu2ɦe ^tO94doe)dZM]c-T$o/5.](ɻd6Si4'RsDbɛ>DU.}(XoRn wj SнvRz r*OR FKPEҘ}S'ɆR4u5g\ܣy @Û9-n1ppBrJ cy3wXFW\f؛}SE+D95m.)WB}rqiKlC(FdomS_K5腫԰)QўFpL,n3PU 0( x?ʺvJ*SmFX(I6tT$zbB9`ϊ*k_(UtK(n!)[~J̧M $-K6WySk~j*-K#|5j("?01H}.s98ZrVHd͡I8]_X$*,am]k} HT́ڙ ]HLIu*C<Ԛ%"NzRT]º1e@/ kJ[.6Rfc )0e*zjC0i!(Z8Nv>&裗K[*Мi.K/,\RLX8w Z^!<^E)",tL4zqJ9:Nk-&$vEJ31ikAt?]%8H#k %g:WA^$v$ MBʼn r79IƖ|Cz֮mɊ[+6z$&WaBr!=JSa*fLm6EVBRgj.$BY$xI`mIbkw7bŖI7꜂ث=ɏƠ3/u"L!af; aC@%AlmUA("0wӳ֎Ґ\PpVS40yk!SMDA7cQ7!%nvx0hKz艷^}g b& zqŗ r+$zqWPh R1kzqW0Dy:dmaUKu.dzeɓz5wSN宂DGRhdwKdTkzCr f\cT 84-ٹ ٝK+o"'MǗ ɉ&)\3pR9dU-TwmNr<~>ZC'y6/+hO1~"k܌Ɩ=M&o r/8=]OAT^e|B(Zp(P V|w*2go}8XI؟ꢰC9Hߣؚe.k䪱R7<@raE!JдrFJOmiA(}>16a5h`ḁ'Wu# PAŽK'. dNZI&ݐaåWu hdmh+C_-k_-KF*}f ۥ]=X%wܬ«Ma'ZA ߌmo^F_y3CS]Yx-nTth4,Ջ$ФBi _vuRnCI_慈%M*Ưp-ܾJ3C+Y/at&Kn6Zw8AdGYs6-Pau&<f}Pz6m]6b^{vYVK2>HTWHLyong#W=A* v8Yǜz7*պDM-wHܢ^`KO.k:QΑE%`KLȏիBRqa<.j҄U1r(᧦b?[*d\E'1;j0SL\Ȯ-:ՕgPu5{I|惨:oXQX0 Nkl NNTT[4=, AtBV8MX)Z&AtVV8MX8'G3]UNV;SUH` xjLթ*o*K)czӈb ,{ DKHݼGX9>|.ޓ^PdRa[Bf4p$kBuKëB` - lmd:^k9 B6sULpa^x*9Mah*M%iJj?Su'"IDIoS~:@ NQR8P( qi`1KQU*]fRdXƉ_/jvYVvx_'j޶Y]ACm5g۬*rBCYgh"*fҘ9,MU3ŪöTQ5EVG3i453dRSG͎}יGpj5+޻< ΰkzVMFloCRbƳYq5WT)JH?9i ]J< )rːx3dS!VJ d2VjváTéFHF{Tvk$"ᢦUdΥf 0<͔\M*I"Uf$ DZ<?72 m뭞21 =y=ÎeW){.gM݊KʞD " K z1TjJ-VKjȓP '{e%kݲ' x1\Ʌj카bPߕt`>O*[UiJD<iJV%#3AiZRώnfhgue#z@-E+;jU1$3+{)ޞe> [ե$ ⰞqRK);zB+Yf᪬ {}YWI(V8qV>s䒒6RVQaS{4dQ6p ;˼;I3يV)3v(Yh?GI8nuWrVP _f jɦPgBy,vM!H pÝbkNq%m)Q]6N찓aFECK Uy9y BձHB7Y:tq"e'㠋A?)jwkiV;ĢGd0Ԑ |֛Hic >9Uw"w%C x v oZojn 79䇾K7p;*vU8;b"F^¤L_%js[S &W/ˬpƙa3?e}]`oNu3x@'YbZ.^z4wrtOI*V¿gi}綜AgD 9i`߉bKKo?{BVxp#K2[$B9܈TZ )cjB"H7Xz*_DHkeOv- 3I ZoRUq]G7Hۑߴ,ü\*H(7kBM_eofc 8E5ȽI*ӥ*Nq a*$NAپsْV\SVߴC,ـ^6WHDB/-e{}BףK/-ao{g䏧tCSz蟵~r-BDmן RW3$K?4| ђzNܔYmJM0z]Iqp  ԡfIV{|ӵw2Z'K Tf?$R##3ӭ؄Ge((HF$p+/a"&>_6)[(ST{^R7E# aZTu ()*9)ᦖ oRib":ƨ/`ƙn5{5zp#\2YH? Y/jE"R{װeRKW6R/$ Hٿ>*Dv~.:*STGH>t٧ Po!,#`KpD^vtDzn ӄWȇ! !18Nx HC'JEN~-T6yDz2t9N7˦Φ̵n8G?8un z)%9hi akwѫ]Hz"G4Gx 4>b;f`:\,,4of!دpO:v[޽k1dBnX紊u/uyK]+ݵ,%.U{mն(+}i߳t\Hᵢ%}ߵ oʃz=wM[VBO(wdtͶy-ڄ L3^BɆľ$whH-SS=w;xnEb ba%D'CJu~=Dh$^B{2EQ΢Rxeu:=>RNuߔKȴ%>hӁu rwt"KۻZw7u?w^mFi =_nj՛؉o?[1R"myߊʀiQ气M>ﰔ6nf<ͽ}}ukýv}%VQaR4{$IT5Y#&UmQ fTUf3JA<K7[@_-6'~Ԗb'q$'JyI7Z+Sw˫ZYsžsy#\w~14]7^^ >Ûu'C9xk[=D?"N%* Ms8u%A*/ x иnI4aҦ4m1is/cҦoۢZIu<.^3 JLڴ㦅W]%̓hA@<48vc' M ?*)l/tah*MĦSdو^蒂&9[I(3ʷ`Lx'Ӑ{4~vt'Mf0)y&9]F:ا*,-Ycݒ[_vheWVdVH Hd`14QujTHėto%bh 5=ٓjk\U w>[G>eW{M}yVOI_dM, Rw Լ]aE&=bYGXD|.R%a Kd,wII`F2p5'pZy(Rp5}'Y=y-$MŦ=5iW +u=5Q"wF|w43h97m=q[52hD)gHtw/p4-(,hlȨB۳+ u`_vѢ7kE֔}aD,fOE޹Q漘nӃ1K i:޸.3Ƙ%4WYrRa? v)A vXSdEJ`PA aMNA &/L ,'JBf|rUj)0""sUp>qƲғ3mk0ֻPT79GEF"R\)EԩD;aPP'xE ELxFSxqa9Szj37/v)=DNmxvnNik̞=/.ޅ"{^\|̥l!]^pE 'f6&$uOhPwcQ`ə䶄>R%!;C!Bf2òx{ηarA;Fb(YZFg+%؉1Z,K=Vuj Cw;JPHIJ4fuz4)GBےwZ#5$.WNq3[2[IJx,py]ؗ/EubN$ʕtbc [O4Ss]jwQb'j:!bvjv(6 e>G0ϖ&T+.(dIA gU.zIKpb@V!.Tb*v|Sd5+vߩG͊_2"BsIH5IWEMvg* $@+]u_䜳 J0BC"F8dQ+`߀g2튂EWHOd}N[:%bT@u$7|$gUF[:,d̉MWTtٿQ8/{ QiMD*6˒`* :i)<:Ke05aEצBh%WX-p!jqD(l )7[hMV2餐K6_ݚ=‘~\r0IRrWy>@\d%tgG^ sKX*P7הMͦ;_&5_hTnn&dN& L:mbq\ D3NQJaVtPLYT6šZȕYj /7sST,Azvj vHm"~DH]ıtmƎ*c8a?6[FVQ)S(aLxkH:ABx#xGMmB=+[*+XXq'&R@n,C-|1w"JɪSe(ϯl bRAY5-Tmu#?Xt)& `UЖȉ S WfNdrC 9UxyB rx #qbhM'KZʶ*~eڭud>,iNOj Of.MrVIr;d*ϒ~!k`P#R3)v#$ A_۳ ~Vuny;2f/c/TܵbM˲2q0jYu?5+%{Uڔhn[+ \00" :\eX!u7eTzf9:~uuo.pǔVE35~FjG@Y+^*{ЕYֱ*_LI{-Hi Mb/Ȥ[bmP>i# *Chg nP#qdh^XfJ`J&\Gsn`=ei:zŰR'UBBi񬄲D)y&zhE=Mj<R'Q̪BD%REaʂPX/%쒼nN R}Khw-ɐu/ Gw¶XKm{LE/)Me--ٱfGGS rio \ĎhZv*ț ̺:[iv?7сΌu$nӡ$C2?-qDWbFO']BKl!4HC\sA00&^Vl~RPi$ e{;\WӢ4|=La:19MPot/0z_ZGy~_.2{'~5+t-V[aDoۚÈ~5-O7zZ^D[>rb(ͳ0wkC|]h|K[J "+HΉ)E.{XzAONq$,bjh:X3Jqm(J_&,B%X l@[OAoW`AsT5*K`Q%N@ZI,He? ..6Ʊ6:maFGA6W܆iy]㞈1p\=4{!-y?yt_a,8yNKqQ hNp)u?DWqQ iN +/ϭOIɚjm߂wޞ[%ZI]뇚mUeL\?\o7Q"iHV)}QЛKj]ÜozlȖc7t.dV)Ƕ;-:/e>go,xV)[M7ۂ,퇸)@eAJ۳jE xZe5TԂ ~mAATK3&BZ퓬п(<ڈ9K‹7賹n ;h65>{ Caܴ'+fc'R+gfMV-?z^OtC&}e e{?;ش^F&Juwm14԰cЭi>;zkZk'g?EAbek[f_x3:殖*$H0-):*Gݭ9"|(Tƣ6_}lC𤑱bcѱu4,GQkѫ-7W,RibAhihв*yC Zp20|EOٔy+&&G19h^oG; NWXcc j-jf.h~7֦`28&" Wh5Ь6iEYRv~$F?}\\jgUٵ2p8gOO<*jstBAA/x|y)FGڣj4 |Qn鑪3H/[!yklU*VTk\*I;Pj0o $X}6dIYY°:)Fz eSqZ'n+)JH*SUЫ*| XդPϛczsC|.i α~Ƅo,"5M`;Ww ԕ! "sX24od 2CÛn :zya\8e6 D(DCNH=$nU[Qvf%A!h.CzW$eFhxW+ :@уV%|mJд]В> ݢi"r%vEjTj RJQJ(w !c|(Wpb{ VG4h&7 ͻt0J[!jvC)[zhkWz!p\lSlͨ7  mǧr[yHx[.}r˂lg)p\V>zCrB6._ȏur˥SnYď]nq-wv-_;k:N<6E3^&;RZvuIxgI',(7|%H5fN7(k1|RPmn[l:lTeN~ޏCRrEN5Qg忓.tAz]A$tjLn=*Z1ُclpJČI^W3J9 _Ѽ=]a3eRrJ5`cLTQI8Ո*Rh34g%f[ d'[$TImJ6d ! vQ_ptssT\rr@v=WɮMFvSI.)t|9Mr45Nԝ5%(^fK_pVy(oAm`o.YPΛ^Z6~b vQ|)dRBe”8g2{ vyHۈc+:K!Kt.!Xr6ąK$ k0 $2R8CϷWRIx/`T鶵2 " p $--v(1H%hm" ^1G$lX'*f :߲wECv01@aWpCՐx6HP94wB_f(DȎTC;~Nr!TM*Ym=eۅ|5*;e,M{PP CnfU`[vڋP*&LgsԾ4ZjNv%tSj(WM5%rB0=nm5κ(&Ӧ:ƔSES=^RHbUO!Mxɚ_Ii zk8=WBIщ g-.mWQlZ*~ɲsIF/7bpyHiћE:]c K!=G=s57IsmׯvsFHLr݅p-Nlӷ!@a7U{$`6Bdguޟ,u> wodwouyOą4V^YvN[yT @gg~sW~a~#\]RCe"7t=--]x.dqO8'l\Nd^S a^xpרt:o'.74%\,].Rz3o23p׼tM=@UҲRmm`Wo*HԮԹ`HLoxt_3Oxj_f o%{kke[9d~usF'n0ZZ;;/s$44-ݝ$Y ,Rժ_pIx4Xd)@kKIT4f,lakp!yj ʜ ^ 6IҎ׶-X 2kN*ul6)p*Y"*~Ӓ17ADrkM,zB{?CYejR1WvxOt\m.0wa@>g!@p>C:i-ݘ8:;NfW-ƶfԡMЋ5Tm4Pw (-]&فnNH쥝h{H5M=+n҅vd܃t4d*HILvs_5TW6{[P#ͦK] o!"g!uM(ً!o&̲գAَY='y,GDZqndW~;2@X"uCt5(+vB<\ҧho IɳJu씟jO!d݇NnyTlN OIK7SП^-l;mG*=zXEuѢbEpVxu1aa]hgGV}Jnu()ІKlԾtQJ#â5 bR-,JIvH:!('jmt>ޝ_)< -0,t!H3c2Y6/܍E:%ND gkSv-N4!>g޸F,ۯ=WAJ w4*ftn'%ae' fKuhkNMh5β$:N2ې S^%beXJ} 'ңoцf0m{AJ&M bniG|Ӂb7H 1'@2Tٶ,9/pـʹ h$z'Q]Xyע*c"]ZVaȝJ2sV]d+LE=,˂&Hr&+ze늯h2fZ-οl}ҴuCB|I;-y^L3V>Eì; {Ƙ>U(p9ik4"YFXN +NW'Mx\JPHD үN +OWW0'7BYmE4o,Ҥz·Km- u4c'eu_) }dm7; t(g* rygPG`SSyUTS+@J醏rgN 8#½qCK[r _'#T  p<x|Y>fl͙7G?ݛ3؛y}h-/ĪBgBRVw)Y;Z, +6!L9Qie~Ђ3 D~+RLIQMg%*3t4d5ei@^ )Ѓ^ZynTW-(\*90mBpjf(}&lo!(5!"܄zz(1CDE} {22q&2Ԅs:]JuHPSР+ ?s?%}b]!@"M3m7 u5a +3[|=s#m&jz #ȵq(uwC!U΋STqs.V񲷸s[|"Сn!ސC(W*snܐ5L̓لK,b߀ d/f?.7pLA͢EP!:1(";H +UT/fǰvjC̎akQ&I-~Jl0`Qc,邓tMOBТE8\(*^ Hu.Nɺ]@=YBYŏ&pP Y_%I uj7o8^iR(+"[6'r3ԣF.vC^I0m1#č'}S6N Ѵ28bTy-)t gD=`Kx~]߈2f6ѴD0(&HJL%:#L7 y`:+I$$&eH=A%iRw\If[ O/gzH44TֆYC XyJI!lWATMf,B|wI'PfzC\I.^t"%)~:3N e-А$z\lCP$\IfoTQ5;X+sILG(d Ydi1hrLR,lIR'IHl%w#'MЈxR䞌h]TIK/*s,P>"[BJ±x))CVnl|SyY.LbIY}rJ wkԦ_TA}96?);3SGSVgWY*3kP}XR,PXj5F+ewEOPoi|[iӚM)/S\UJK `3 dS|fJJ-'&fmT EvTBY&y+8MA'FŹkol͈N\$Ț Ț^r<,ex)O犍ZEG=+6n^ ޴by[NJڼ7&bzryLHM1A{m~#Ҙqڜ=t,W}O5ot2W+nJI(g+.e8u_9VNqЌUJB 7S! cv) X$tB@TS 9N˖MM?0%4PBO2EM$t?-Z,IP,*UK t"Y\ xE}m(gGu7G H\S,j3Unrh#5m@(Yɕ̷c]H+5![TOHXxMll.0[oK 40"&/~&8 >j~%X3_7$KSdS $,Vq*ґZrFW)hb 7gqͧQE,2S`}qE,MW&X-Lcsx3VKW'e:m"\2Cު30Bĭ=ųWHdxNٵv!_aN~pB-gu Ov)Z~*!1˯`gh^TS:}Rvz N!i!XBK t'yEc$xWn:_y!XɧٖB0P&/ʖ־EGmF/")>SpЄin2\NA9اN;Ǖ[}&rި~K}?GQ4/n[_7 )M~ +ᶔPOj|0PM*eR䃅mC[rmZCۿ/Jz$]JRCMK3!xKs=!۴$9-^_'@[n_9@R2 dϾŒ(Z- ZuHާ N Oߘp"`z/;ۍs3e0e6%E=2d)ӧz S8{=C>Ho4z1$%MqR73`jCr'lcwO5k%!n";|ikQFHl* ) 28MBx3ۓܒZF99;KF($q([핟$3 n?Pb ȦN*W?6B\aɹtBI_7.TvW3Q]bYqTv|px#Y޴(KBe}4JnMS$%5WQvHndy &CJbIR?I 0PilB|r[+n ɆFH&+Z[BZ9$ԏW:ޒ2f$`0ozںbե\;eiϊ)X>t]ܚK=vʔhEi[rI3TQݚ |æI4TF {_Lj&Ca r%Q7TB]Z Rk1(ly[/,6cKjDz-,6Wo֦GdJzzB, 6FJҞqN bqӦ2?7TBuS)= k-3oa z. r7@_+'PY`xΆ`7e mqAa_IY\$(&hLo篣x9Z[fؚ 2,_붟MgIfx޷6k߾n[>Չ{.nT:0cG (!y=,6b58x; kfkaZ[SW++{;V١¹km[S e`u |~nbo3svD6Hah΅vuN\E03qzHgև%[&NKiORIz]]]vV_|=}6ǵ ?6ڲ-+o?"/vՖhANrEBti9!{8HBABo/ijj{XWs,c=<ٳͺbBxZ^S<] 9[!+tl追 pE! Ƕz6w(K6VF囃onsD,uLNT]aH &s0&Gd4yhs UBՓ4gSfd%&{dMrH{f4ylB<)$VRVLM*+l%yo:|-]on­. d:,DJ[IЛkהdIV"L|ŬZӑãK?Y&f2K?  %W 3No-;N.R`e\1:З53f9m(n({s$P>tI$+kA;͒c mKdWBqTingzm(n@eyxG/ɝvt6yLf T4V+HuJ tVQ8YW ]j#T0 I2hj#Z?ݧ)j:(vA\U`sXh]nuSТSOh=LhV P{}wӚU#)NN&@89X1=qvwq{wsA*,P|}Om :7Yk~7wm p/z~wmTTPV?qn>fI‰lh?fvF@{!~7ݏ\P'{kDim붎.DOt<`t/'|WEfF@uxZY/Ӻ>52-Qer$5Or$3<; DF @(Ea>)(a|n@0wVJX!(a '% O_SK?PK:IldA@=-?(=:II)=-kA>u&EnJ>.(g͆e[oD('M5:렙'LlEBڬ^(coxs4rقx\n^gLуwwd]=7׬%d/wk -=xOEz|Kr3k ih&8%4ZYr+x/(V p3A#^zeurhC!ɜ}=!KvK7v{d_A 1>k]ND>x+˭ xO[a((tj{iTpޘH콂V؜ V2A-]IG؊ඨk[![vhi?`c^dul>Sj}QN3U(>qfՈWC KE8e[dp5rUJa=c@&(` "[^2}_g>F 2q -dk kh0MP,6(\bK%+@Jzq3 CEqj=cs 2j6@z(QXY&$&\R=_6A H_%Mb#sBsÛ@*Ƕz n= V'ywb҇gieb*}tyA1mYCU[#ޙe^B 0u_'\8Hx`^p^lS`N⋘#i2Ca$գmÐwe(!^XV!τ5o ^ LFq PBCrb</^8@(lWG&`<:9_: q0bV]_즲}sL@ae4/n/%P%-dL rt KPe2łpa؉8LJ>LrXzza5K7fҞRn2M \IK,Ѱk*t&ثG>hGTyG^ewSBCrNn(;ì[t|Ә4: +<+C&ͧ®3{XCX,MQO\Nc9e)"rj S֡Tl4b /s?6>.’].„->fz-ۣv/¾fZG=^,r Ӧ}ƣx- ᐒPV/sj4R:5*p| 4Gsl3vtq3m՘ؖg}NX샱hJW'AanyO[%OAXZÞ0Ir9 <)] $1'ЫL0oBaK]6QzeYo@ڸYzep2ڬ(w/ATѭ2rwvVyYf@Ҭw]*jpC8nWVgPxw+g(LTRw4 Of`+QCg.M[UulZP/-5.D{׸w17-ljj]ibZlwst"raU32bk_7=7N-r$EHnFJ4*"Дhb?L:OkjY$6C_t$!]iUI[BT]DH@nv#\fvoN@Jr{syFʹۑ.<+F5-n4XvUX`zQrO2g4[{?3ab WK901Ḧ!mi1+b1DB mUs7B`34'+ }mBʟA.zBe5j8#]J󡍷N>mpNCE@raX};W4D9yI_&ʷ´W5D:{GU)p,r^@h9X'm'V% >]tMc7,lK5(t~ b/=Czxefj'q\+I^-,MJ8k(Ѣ_m%țRsizok;33'e@89$"(ɝo&R-!sɆV*& mZHM# >0Zv_RzMr# ӑaVaGhi|dW8Ob9K~$ s {IgiKx^0à4P@T[*$a]ӊ-xhq L;Rb,jا֊Zܧ,>71k5fxeXiK&Jr >–}?f/LJ o[1ᡶzw,44)7B~.i+I]p;]$$N>?V,Ӌ/;b8sTb{8>ʩầު0H[{=oOU}ca6{:MN=u^^6?uxjVػ-il&n/m CX1),o{OTn;LpIBNՔG@%fa$ݔӂh6HUzSSN f}HVgyѩCb HeJSdadƪb5Յ D}bdbg%r2A`=k;rR& <-k<*@fؗ5%bܶ/I6;e%oVn{ۛFh.p幵c~VfbOlMcZ7[έSsA9uM8!371LVixV7H&<-c+Eah١[(Ƃ$3}JLs^M7iSUOѹr__ףe& Kz~̜_RoT>9/i.p@GS!VKwSyt'lX/e_v QԜ^*]ӗp7K{HXؗ l}Ż/-]jݧN1ET JxL!ZHhZY,=I;ɩlCƎtՕUT<I;.הDT lqris pȞy9̛F<1='F#z2Xi"MdM v 9kXpgh|(TLcT1yĚ!!JkAdɺʎTC54Bi'3M"˦Gp{9nRL*Vh{\f3Z!mB0ŀ&=X @)*(ip }v/QOZHoZ~(&ʹ/E*?Dp%C>xB)DVGIN1mHPYzh!G=O,?H@%>\YZ+/^հcco3!$i nhQZKbvK#/ъNqS6'UL]p)_2*,)D?ZK]"MB2a[YR.ĝWR"+ȦAt"4IVDbՍwx+Oj5юLu+[Zն UOȤVMW'g2LQ *eN­SLQ=W7.I  [3џBjn oܒؑ+AhIrk+ f#K -Cp4՛oEQe,KhJP> hR{ :[_KPxHf%M C J$XGjumhewW &m]5)QMrpÕKmk_|2ImRȻQo֖U?Z4vHsϖ\=lقkO,oz< ޢ_qڲ!CnW_irڲk迲KՖ `ؙꫧժ.VmrW\-]]&@aVy8=[ҦJI oXyx7OW*ʖJz+߮eCʗaazLI%Ί'}-;vrCȑ~>Bv?YyWxy! [@wB#wld=&pzQUOl]_.IEFcZtz&0gD-Ze(3\50NOc@**j~7m|qt7L= JEQmQ1*WҒU׀%$ |*$/ic kD %54 oMӅK#ڰHy Y M5P-)[xE[%WʤͪVub>m ())U%iQ%f-xT- `BC\N\%еW?Zj#wVSǂ},lVےD]/vpIz-P{u `g@KIi৤ʊ,ԃt.=Y |PE^WDHU=lFpD![{EVSՏ Q>uwEš(k;7#kw{p)shJ =v0f21r6$Ðv$K!Ʉ&7GTt5b"sӬ Mt}^VS*/l(ꍷYjUICQ7^52e9L.ZĸP*2\Nvrtr[fߙKzrJt24'.vDѿ8 e\HV]Zx>X༿f4y^>O+EvYTd۟,o7u?,'haQٍӦ*,S2 ,kd󜬰Zν3g`iB'ZѻqS 2$cIbTbJj\NzuS;H$Ty!(bV}D^tAe] 9(WJY r[BUm4R,{K#e%{>UYw2L,tR $tI$705&-ڏ[!=g" OMyn#]/fbAAFSlDp\0P}68##vƔZ* 4 nmVTIye6<25!a=AY2sU؉y9V圈B`~Z{/YjHP") u q(>=LI`PWq|Pk/Aj mC3١Uc̦ *, < Qn Pn{Ž^dMI"'m"CkAyZEj}!zEj{!lG-zE6w'QV, ^DM'#'(²yEREaCoiArn+h6C(;nY& TjP(l }L6c7;~-&'_3pJm3vn -vEh&K-Ǥ;L/|AK ՛FlkO"LD%qk=,m?d{oCF]Snv2 |쨢lUZtl@?5HС]]M%/:PJی٠P'K18>9$e~I"R(irhڼerC*t%i;# >) 37qtCX#%YE?L^pzF,A#WM>-'p6}U{D=vs00bؠ2q ƶ2z z?27en6$Li ? :FMKz >-w"a:34cU)sZg^Z!s^N[DpAVRL0PZZ0M1G/rj!6v3Q^`G-l}\!iS/VI^ &0%GSu1?~m x-CB䋧]BsiwE O[ih' VXb\WZRkqImvJ5ѴCzi)ƛm6 ZiIm6!yh̦0BY;z*˦:B=^T}P4N$\ngPjJ`H=6c2ҊhWQRCVe)aK)t"+pxDhrj:mZ]}Ud{A\ MԱ4mIZ+%n"Τm8K.ォ |HE[[hU8{g}/! Yrs!RqU{LcI4\yVAz4e WiBڎS̘f khy+{CQSB+CTlƝ5UMkV,:tYZ6.gy,ZoNр#[W.x,~榓(l$e4R6Ic F %ZJUqq64NH+#Rrp?6d~JdL^*8Z!`%vZu-\N1Inir Wnq՜%JT0D~+8-rGdY1; ) H=Rq6,uٝ!WI+x pq9ZBfU*.[)qϑ;BG*U!۫Y5˦yD& T -X稰T^x~L.}(m!ەeӔL5mhI KBnXI+C8Mʲչ- 3,> E|E+muPƢ6%2u1~pyWӫg6BX]<>8[ uzpP ǠT#V ,*&8i ďF3hS :dh/lC'D=eY S y 'h(l%l([FQY7s1W"$*Jj`MMp=zY۔@֪/-IU_1^ ۦ@eZ5Mt6ː3.LB쎩q9$αlLJ}򛏇zq{s \ً:b/JG9#'M+u_mq`T 9#J&;,^s~XMAZ}Iax1َw>2eo1]W~׏cF_cRVc9j2Paq?!|hm|{`&4+Z!j2Hr 2bɧj CuγT^eX+SY0WЂ/F$Us =bvlI48K /Z:.ص%|\~>tʵ RNy6VӰi->Y:^aVM[yG3^MWK5qXU3 O:Ȓ26+$P#}4H5U:OeP0JfSJZ*r} MVSn .pPfmP&̘FӢFVs ڣkQh$tZ׀46]uY2 D0@@Ȧ84Z)g JiraiOh8mrg=½HH16-rg=5-弦'0Yr:شfv&qJsؐ#6uzkR )P]By=kI&(MJu9lS=?N̔ÚzZm6zաfb]ӂ#kED!ҹᶲf d8(o5Cgga Td5NUHVYZ\kżaԃ3W=dye.r5Ng6*KN 橦,9RU:+HNJ,nHJh pj|O\b+ \է.Jު+jh/tIe؂/sҢJ],'2 eN+ ?<'V9Mbg@o>R>*h#8VjpǓr'ca|K5ʹk zx+,?n × ~܌n@@zV\zd#j0=7x817kR>nSj[|87i_anz1g s3֊9(C*7\=0N,*ZM '9lu|&-k3A8 `M"1[hmG4FkirMCpZǣ8CnW|Lg@ 6)>М)-gJg=n(&.͸!Sa&ĈK\P*5%\Q\症KڷRuQ>Lk&]no6"DuM n[tbeː%X~F)eÒ,F '|%}W8QHѿ,Wme!xkxԼ.[iҕFH=AMZшk%cC4BЖmf3]!2BUS@KR4Y-Rv&rA+yPvPrA{2|G Def6]2]"T~2ۧŻ#Mq8)l ș |_ԛiIjuϻv箇3MkT$9e0~p5UƔQ7k"Tm[/nXt{یvfj xiM {)|))-X[UoqF*T ?JOhň qg*ХįJCeqƩB,Cq.ƩG(-*^qk*Jbuq)8oB*.T 9r>"_YHQ{X(&%q*B ƍ ڣ-ʡI|s-f ou>&Y⩚f;H$2'P*(A@l}R!=m#lyשnI䐹MBFȅ'u~pN>yu~KN >/du]Jur3$c#/) ڜcdRR[W@ gUUo9l2HzrMs m3K@jh>)^ 3W1Z9Px,g(4qN*U%h&A% yIHّUq9vV[#w nDŽXg҂qk P Xf ̙nS.H+aŘa4@ kɋ%jh,/[F*i V[Җh7cɌÆgu|}TVuaYaWKSBc*MqY͘[? cVVT>d_lc·)|Ⱦrfd-r5"fLiF} #WXV1mH5O"E#hHp<C;΄qV, Ovҥzԝ?1FtJ9;G x1GcsFW[zCjx$UŊi]6Q81C0>ٜu xd!3.x[^$VXrŏEeRujR Ny NNgA ?jJzkE0#4Ni9Df4)"jYopwɎGi O~#L{vn7 'T/< RC.:~T$~}rID]i?]\2yЧLԦ0G| (l/-&2qhQR`CA`SOO cql(- #eMm$CS2irZc>O?iKS==݄Χ_H cGAΧ _WWZYV!u/@"M#yi욖Z^Ifri36A-cpܦ.J FP*LƦNdNAe>J3q98a4(]AVWyt h)نbm_-*:)1 ҼEQsiu8 STH.s˧Kx1gͧat}4WYSBeUdqJhA]Uv]B#_-H"rX~wy.ʽ-⮫Wxqd?y1a2PwTA|cF_<.bʲ(DJf vTW.P&fMrB0פ9g+w<Y]j:C!u-o lx\n߬1,Y;isV3ť仕.7U4Ȑ']Rd{ɨ&=մ-a6@ҪI"r¥蒇ʱ" Tw ^#Tw a&ITvxqr5c&Q<'ZT _a@ﰆ:jzPY薼/IhkqDߛmϰƂ65$l##~:v} {:_FqU+R%pp z`l8Y : sHyUOYmU cr*r6=(m[/U/U-2* 6}M1J]s {{m";oSyʱ)rKpTbacstMt_*n5s5$)[~[1_s>)|#tZ{˱ I8wѽrS[={~yyHmJ 93Q4}g7G]- P)RWX'wvM'a+%tW68UdB!ߔJ a,WH߄.0oŗB$}Y#4nV[7wz dR[b>eu@MyBxXaBjaƱ[ jK)?B3 e}Hott6 zZs!MWa!f;)EL`cܺh!^&2J?u]'$f@bämJӑ*uXXRBEuuQeR1@7 )I h5!-iE4enA%<=MP5 }G>*C]l ^qN PtgpiV{m@it,U oǤ3Ip4w_.w /u\i|]X)u2T .@Vm oSur$eBE^ɯdI3Ḵ{eG9y7m)+đb\Q[yA,@TL~ Hm5F\RC^=RaTEʿl_-jR~N5E8eSM-\u21kʽW/z暫D:Jto|\.Uu·>{ hIJTbnMU((R[7_\%rW&0[`.'&Ǽ׃.lbMefe:hEV`a&:1QMªB]8L1UcunDHikuDHzS̩qLV81G&gBIpZV2#D; ƕ%E*SBeܾ Z);C|u !]WI:0P.\ځ߆Yłx("|O<,SbNherbQ=Ij$T:Ѽ5= ~ЪK ӣ)hnMz6eR(kx-SRѤz[H}-,M)eR6A=$[{h~۰Ż[t|XO ]&^u}9KP5~.)h\=H2Yfv':frW/I==qz\Rj( yW_i{8/)S8 ;@Yd>MwBcbwhɚ֦P~RJ! epZ jt!K?Љ:l2ͯOtnɶbB#i@L6WwIġt\CbTܞ?nJ>]iL]8g!="x> 3$juNjjG]xqN*}А}*}Q "Բΐ徨RЯg%b ͜_:P *ۘĎ@~8"#Q'l^.oqeFCaL*x(Z08-5i ]yw>ɹ5mf*Ȼ-˳p* jSM6EW@޽q_vK6VtUwOYR{H֯nv} d)NM$ɤZuOaT})j34lqij3jf ijOcO2mWYZg9-Lэ"`Q3bN"`qV 7M81~3vrڽf )DSTqCK93( 8vm6 PSn,ϲXڴ-dT.aCt=J,0 W%QIH1bÛI81RrّdO9n=oV97A_n=ǯae&GCÜ*w0"@yHiΒS'!I$L^q[saЋRz)zXS/ /J9ԻRYPD dGsA򬖀9L῭Ey A) RωϨ["=MX .ڒv\ByMK0;8yْ?rif8vj,^u nףtؔOhK~%X'*vpT0kO95P/-"%WX'+*KU0il1R҃B?} p!氠fW^C"{T5$Uœ9%^%MY*S ׭MU ^<+RBދFja=ƁHR/<5k5 Agͮ$-Jt0R1~5Fa(fz%XʽȚG.2.]u֘/SFćaꙜ$qtkDyh W5D]V!_"GT)V3’Yep&: g(?+B"=+@ n硭5RbQAX֒ j7a@/ YDD/F<d*SZdc}lU?[6GثF !s |b:xT^B'3>ZrPe._ xUO8h*V!<֠ *V>zkVѼ%x4ni0~D&NmUҗ"='XFp;+<;Mg{ZAt&P<Ԥj5$և'oΩqKzzv% j'\`$j4q:?zJ\mPzVخ1Gz+~Fr;Dط2ٸwE7E);w̔qtE߱ͼ?~;U15b3#?#-4ZO;]Ӂ`RSX4«Z#?]f )o)i~;1HA ?<f|Ke#:HZ/T>ۈ"T! dS[G|w"JhC7w8:N58KQ94nUwQiCdwܛ: .!)͹KS2Ґm YVAJS0ϳJ?L ^~v U_[SғPIKNor>oDlzv}ԐF:CdYqN sYhHk*ɀsyvΎ,r-S59ּ<%=9k[XNKZrz׌ nIONVB[)C׫'*E@׫'7N~~ߠcȋ{%uTk*FqƍG,"ejMї =;1?T?^4CUZ!jU stZjj*wt%!^m7E/T#_8$"4,u.j<|]x҇vi@D >DŕBObqSԁ 'PÃV*^!`GH!7I&! FrdɝxEDQfעi1iʬH窃IK'UU \u#sy-d+^p-v giQmvԄ3Sq˹W{r*At2aѷxEל.Rro %zN$90\4ޤ4": % xtO J wtN-]M y^؉ԚwVF=V*MBT72s[w2f2eB/LyI[TYΝ"7Es'ـ1-L̈́TuZ;L6iKO% "2tǙ:Kŵ";|u{ nj2~w?J](š `ǀWvRLݨap4ldU~uh fOI$š`CRHqI6q_sb#Ѿ5Y/MYWH !K/ZtA} u,6嘈O+A%ִs~{;9(AFw;n?rLշT=}Tu=\V:0e_qua3 #UbN<܉}ޥ2QusUdRc!bF*Υ03X:oRE.xN(P8 ^G_әs V[#?+"ζ[+{8Rjb ;b)F#(wŊS%9l;ۅ!C)9\\|V\+BKRr.'y\|_1_Va5{ [95Loy/hcZ0\ --Sd+8xT?L*ۦ24j CE5e[[#zƹm,"NW0t_.ȕ_K.*\]snOH=]%_ݭhĆG,J)Ji}yZw{ } IHDNhKt)>8'2P.n  _fG%m"1m [)ՆD(=DlvTd%vs=u(-Q'a݌K!*qKd֓upu,U.4h$),4g#R:JqzWz, pZW\J Mm8UݔYOMLm-\O)bi?v{uYX9;ϮԴ $.o{%iWIK%SA*%`L-+ǫ#}w3DIboD|{vP@K1UwM]tcƂJُUx"vm!ިjG}O)gOXbxt (UP8اšFFCL58 DcyQ.G' IO&y]T3$j3I'R`w e.IQD2UvNkvcR`?KgYU IFvVInѪYۏ4w*so%~LpJin7~__H8I)#"vH!wHW.3 i#p(jfݪ!vYkZ}1C$~/5 :j 4sGC >YUA W֪36YZP$#ySfP%!HA 0~^IE`Ky}!&֦@+Cyѓ ֦%v<?CL^YIB6I vV 7/L6Y{a?SD~rg;Bq%y`8UM+%' UqJOB޵k%eX5Mx(m "Q\Tª5,VEFӥݵ_V}px^NJ'\_ w;%2H꯾Gn3DDbߟsy1?C"OG&gfJfÖF.gx#lݗ'O35lj ?v܂~95AV@NR~DVFƋoTyKy幦i+e{Wj̩k[l/]Ż(QZ`+^vQm( 㚪_LNImgŶWBq۾9.n-vP;)D4)NsZ:sbP뢤s;-ym MI'Jaw4ߗP2'%*5iKo[OZ0R҉R&t.,MHI'K9|JDh6oT/UKojזȐzfˑ[=Pmvr%=PvYłP:l6z opZ7a2œ-?>iŮenA3N;&ڢ*wq j%G@Ěok2k3LJ opcLצ(zC_7:K%gK Uu6T&qK>QyޏE6Ps'I1uJ)F( ( NyR5P$l5))IZOF"5JS"J F,FjF D3ɏC+;~ؐlgOg؁JwOENd3'Q]&?lQ6)q2gThFS;HNجlT KY&jUfLAPҊG͇a: ZWBL&Ug.%M?zURhbEqU:Qݩ}hR :dR}X\ЯMElsfBYᴭ!`:䔑enY :UNiYJ榣  yU\fY]ռb"*ۊh^B/{"WUnZAgwbc^s5aؽ]Gk)m^#H^sC`D505li~T\(Չ^"KY@Zͼ,_lPvSQBD4p57G֖VtMJ8(X,KJ`(#_;UEptGQz韴U-yMY_ik=]챶}CŪVRZwg暜T#&d}$BuQCh"f$H60 GMf̒kjODՠzpw)՞|%7T% o] ڥF%7Q|ծOw]|].WJ[o(Tc }5^^2}b7 #j_0I%'ע*#'(|{, ݣ&&|, Ы&&|d,Fֱ}F9 p@ NӋ1ҀOǂebP %)+=fJIUø4rj./LiUdK;iHQ J:lpX(Y4HT:(y\h%lR1a#-oq86 ߲[\8+[[DKp=2)5o/mP5usUuMc17um3}_TU=Sl:FOX:S0a;] YW9D0拕WUDhOkr)lH]4+d)*Pg^Tٶl'6Mt,fDT7Vd9-#! r.%@`@gr(M+U})HoƠZ4d4_IUE"MW]ԔDX*|WKW,0u׫ЉV;4hD8J`!<4852H1sFOYFҧV*I AV1@&QM8pNmCBLJI S2|H۲KgkY:]J*%bA֬%xS3*KɲHB AUO.a(Y_PCbBU6fFHQ-šU_2Q ? Qվ[+ \['4Zb] _Qک V?Vjt+fܨ!iYV A"O2aؓr._)Zi^2X=6 GeQFL<*#qh9^ [_lGdf';u]B䭈yxף4䭈nyO2EՇ,=ymFlv5#[΁9>#=g #$mUF~ <7nZEU F^BږdA5P#_K*mJCSO* l -Kuds9^Eնv\T(oஉem_EUjȪ/QasR-7*"qpҘb!^Z2Zdcㅼ潰-{E\Ex[$qMZ$ulŜMa{0n3/~Jnli+fDG6 II(/!#C(#Э(GeM>q(-*>!b;! ,:(w6e2lTçK7wzTvu)?nDݏ)$h?ӭsmY| <0H'ENI %} l䢽 k?SƑgrZ9fD8`x}jZ{+u%)ܗFYK!MYFUTf2gY9zrp G6sf)>d6/3F7O$zf3MˇIVX.ftJB`r1ߗPJG+Qb OdrN}$␄NeR'V,E.;LJߘzuU ꭳ$²׉W,h|Ï٬_':_Uckt"bOv_c% |TckҚH֐é+B_^6q|F&=,"ISEէ9RK+B(1jp 6\gը ˲/U8o*QCI3>S>PFޝeH͝o$F$FU) F3.wܶx5uY)A4wյ'Id/&YR0ViJ)5k|`*+.n >jQ3 f @B$CQ ݛ=MR"ǞimZQ*ڍI t2eb[ʐ{8ZFlj"ݖ{8ӂnerk=iZ33ʼnC$sgZ>gD~=硦 C^`WZ*\MV6JKCSViBğ]i)DSƲ,[͔ѬfqOɽZ}R 3lzyz35&2hy i] &̒#5Tm.,9"oCD/,9A"o%%)H?PwY} S0K`c#nK/Kd`[0Kh_KeѬD6?eѸ/Y*}(S h 8oY4k࢜EbDPz_B5eP+cԔg$jL!=lC`nޗ]<*G f#OC|)ڴZshLpTbC0/I|䲒5x jԎ>;,A֠dQ\*ZKmru9:Rjb4ZuS/D"u!d'Ľ⾉C+' CY5P)0N:w̸ob\W.1yHHMB/\WQ&B-'X\Ѩy_ȮYh?Y}&'杰ۈE U٪ LJ9WOE!UG{DٕTuJ’/:SvU6+fXT|R?I'>ˮK?jP|$@DcߺG%ľC5m5n7^~GDkqMk$\E&bE(Ae[*E(A4~_bX*:XLx,Kr89Mj!) p7_5oH?7LyNa}\*o446L'p CC;=d"GYa:k)Zͮ@ ^P"=Rmj3Z \.ƞ:kw ]͠HwU=&sEq+G!V,}oڮTYė؝{ԨRSA2^S<۠P"^הn\hK/ b-)ٙ{P+ came\pݕ8 +^xU7K^ [D_!}T \Iw)OҭvBcy۩r\8jjhHܪ ˜ׇg0X5ZgYǧM)Ρ,gSOH*1 `)v+h$LtلfUEjM0eZRU1L!MSb@8 ,7 +I1`̧c}ub袃[nNaAFR#dAb?S~OnƖwY꽆2l?K+J 8FfKA`тi`CBQ$aV(EB߬[kh" [- >"9sQ,T[dkiα%aK#[ -T"^4vty ?6F* Nȝy_,Z-!&4[4Rn,)B4>ߗȢ߾)!)$)KF¡/7k)f*;bO裡 K%3jV@Gtd̖T$BY# e\ /#l%>J}05%-ߗ{c>U%%. #v̠3׎ H# .@Վy XC).nit!2"uSӄ:6DfQζSG#~N䏩FM2oƪѰ$Aζ-.L/lKp̣ҖL$I3SLmVE7J 2lKpLL=Q $Sa!iӬBd*71)viaocWr5 5 th}uu0ĭi*kʙabjDM~ij3dڤN*=N|eoK::hE2x1Q *dX ֐ޯv~C%-X)4 &UU5e#->BP nGK"uO nGFR}k*-MT(VJMه}h x+vI] ~@ ֩yUnzTKG[rx*kHVA܊Ҕ+]܊ݲ5WVV݂UeWb`K5[r+wPVESOA/e8Rz'٨"@OTuI3*2LTQ4KXKR'ѩD%k+΅@X! PB}أC 쁡PQH9UQɌ$$h*[ve+$49E/W! 1:h]@B;c/;/| ]=UwC$D弪mŽ֢ܴ drcQr *:5_9͢0 VjϺz_dI/o*,N$WNem]DAXŽȵX@&M-K<,πVO,rҜ@ a;90aB砷qKu+~`q3" 4F,뤉 ͨWVd1'Mdh qC%7(Yy (RЪ,EUG䥇 \9k)&:LNIJ;TΞdXf:രhUxO'[ ?D#qQD2#dw F @Dɒ{x#9/ԏ[f#U 3uU5F\$iSc*~Q`:T y8WFpVK~ mT3]2NmV]U{)JS2۝2wy4rPͬ]pˬTӭՇFxnz+7GL}xCQE3%9e]6CS&*Hvi!OD~A?OT)x{HDvjǹxͯm VbY8355+"c"ӏƖālY0>nx% k [gƺдNI~ǺM ,q!&[p֬ jztIdY O mq A\5Ʊ/Hj&,#m#"HHJ zYdTJ1-TuLH2EBAHΙt.R?w#NIQJx.&PRzOO1T:$d$Yzg{a9+$#EqWg_ 3>|Bɀpaix-y%' xTed$yHQtJv;?$) x fdHLjwZ:9m1Z639zFۚ:$SDHPv#WLms^(zUwai< )aQCjAUwW+4ʆzUxuQP挄ՀE^h&SzhZ#'( 5nv4ázr 91b ɥ8[)EaR%3"HX6JSk>lKOP1E* jɶ˰K*@Bx%+IBRP ̆bvx FZ>Kj'1l$eX@+Lܷ#H$ QBy?pNaSQ @>VX)('SC":fQr;5)ZI^XB1d Aۤ6C] (ZҴlYQN'0҅q7jr; (z]ibpJ֗t)(nJs#J]sChRIL rt( v"oܤ}G#G2UNz5t@e*vbM^R!viK(:RLqvM  =zР) $<)4gt [z 8#BG:#WA(5:@O8v 'AK\QB\|ސd EtƖă:=ɰj/3;dN%Nx=bEފ!g->2y AQ|(Z͈`# K`eNU` RQbV 6OGi栏æpX ",ʹpشK1H)1%&q'E #_]0WRS;I4R/(iKK>L/ ;#L[SUI|uCnenTSUHtu=nR\*NbAY^p) fܲoR̔}+"< R27f5nczԤ3 nۘ 05L9)Ko)Ǚ L:oI{Ew7fr/La{uzz˺ԧ4jst񤓕+tَkWwW_m 1\i=hcJ7,Lr=+dS1lI;Y܎a+M//i'&fq#p5x:Q+J1"#sOc<`~$ r`NMFΞ '9&#G1'#YC16Z.Ѫ^ZjYl6Ր8GT2hD_ij~*ژx)N*"iuhcM8i]D)o)BE)T1'zR-]|AVAo{]a(/hlaV-`P`sGHXè֝9o+I@Y^TxkVoxnݶOuuyߨjY.-.PFVD7C6!-EіZqd,jSg\S*oԌM"ZCk@e4ʟLxZzP9KgWU.|/ʗ\U8T.jP4o9 z?뺸Voa9iu&<*smS'QE_&jʡ:*XTMa[3ԈuMGj7\Segypr bij}abTԲMPI6j*y%M9);24 UlWÞ{T!=2VhRlnWeV9ik[V0/W@bm|jخz['?瀖J8p3s6vnHFFf@ZIv!g#nI-D%t≲*ISe#D)CWGq(]O+WڀCxpIƗ\=|I~\ YIL9Χ&FoX5d#-fNQzF]F,@ؤtnh֤ɴbZ:rMf!{I;Z)93eF)ᣫ݉)VPl0K!qrג2Ը6,V)-YFBN$56 ?x8*ןiQVdj=/ ̬ן`NAsd6=/PNȮ ̴DT@>AþM}d+:2U]G߮s.p3[1a ~z։Q*@#{kBp. s@po,`5J%FpS'+~;Kw{#GT$AYNcmdֱוƂ #>MLiSF~[-rD uQ:o[-l9Z-3C)^;' !e0u+% :Ķ>fs<S!ַ4D7Ppͦ|[]* H"$wCQ c(4-S># ĖErZ(}"G/Ϊ3ZjmG#I9ZUQ6WEw_E"GoJpq @%MRT\gԤYi.RMSmf e_mǝ'_Rq(:V\(;5-C,-oTt#ᦹ1Xi96#(;OΕs&vP8yҐ8 M2R%3mP~NA!"q&n:Wɔ1D#4ߦQ7l n{u9*S8F[{VJs)cZxvwh>o2lnjnV7J| CN5GݢM2O~Ob2a5O}]Ҝ ݐ.I-.\ JxCuHÅBA_K1jYC^/vGI- JV2M( sYT 6EEnzYإ&vЪ 8" -Q@?y_6:*)_"?t-&/hznp`Tg'jn6$uײ+34E`4̾. 95M@)gB1FrY՘65)6?X=Th!KJ̇?JM:D}ah髧 ) I_%ИZp$EJ䀑50Xx'aa` (fWïiu~ i\ AjV.ˮ݊5- rJq1J's֯% lx1GvOY(5Ih~y_M"uҪIs1'dX1T!ˣD]ݚi4++WlU"&bz4JCd>pPKTEߗpWi4"=r;[\Vv"Q=uDÏC9"RA}`{D("oɱ0w*9I"u`2bȤ怔 "Ce* V33*^Q;kHtPBߏ q4DB1eg IEo7qmOBPv0-&~$M<}PR[>9ge; %GrJL[e$Ƹ,]19wȐ[*pLM^R~Y~8JIL~E? zj"?X"lTEKa/%Gy4h9Uc|7xΌ,1gYkofptuet{v06ʴ_o7T$d-yU~hV'3hcfq:0*,vJH֓yP97-Sx<@<3jNb #Dk!|&~ iYt!_K<=f$94h)P:7`!]-G7}M0;Zn.Do¬ũG.u` qSGB9O6cX1nD(giI5#R10"n!<QL]$Lӂ:*c/'wm*4%I (sq_smNj*rWj޵97wNeyGF}uY6E gGm)zw&e3ijfk[}=#9 ݁Xb*`a8ǼYf+(9Wu Q\zSyqBS%:Bl2awK՜ `*^AH5?>Q歌;6 ߽ٖ>Ya!_\UH'R_Pr ]"UcgvQ)@1-k.RJ}b }=GDh(P"flt7"DCTl,iDrP!/Ib"ؗBZbJOXښO^QTa3$YDH\Uˎ@6)ސ Z PYNJrfi⚙[vS|P>"hN $ԏ6 ֫斮eT!^WB%[ _e_eu%r4>e˺]P_Wn+WB; QI]H@  v!݉FqYꮔL})rQo9+čQ>qd2niey96)-&0 NI4 G1YWzeTT%L?/pk| |rYaZ~RJR5zQڿՌǨ?J}.EnɎQBM}[Tj#m 老j S]yPNuĪ0yVm/XW ћ[D0 ZNy JȢSեks-깝*M^?G.njU= CD(c 4voȋ']nw$u^*`IO||=Α7Nhȉ{7.!y~KQt^\`\݉\dXϹ.Z l[RWi{ku@M&D $MU=4nWP'3j;0s]֑Yb FYfː㊰kt=I߫QzĤYQ;(}WuQPNn7wGA |]6G! T+7t+wp׫ 1Fi]>(JMtFOͯzd5}ҙr{ŧЊj4:zXlYi oi4Zbv* yཥvl ⨰̄yhW#W ӻouk8,\$0G|ԅKgƹSo{[ p2هQjv.FqwC %zKB6Ȗh*cmhH%<#Pks1Z`gբe]OEsiU-jGٗ T\yP;b MЋ2mWhJV9PE/3/gw/mAYPx[ݟ)p;MVZh4E<+hQjEѧ.'虆c]~Zg- ̓kVZ$8{9`-\QaI<+Ą~LJ )cc~ZJi${v SKrVa1Q`}miEL3%dbMyleai`exK-ck/i/-1,2CicXy-5NYo#xI2z A\meYd[ 2,LEЕVzFoAWA@&@V3% ԖW(CO&U-}nv0k'2@j,c* npڎL6(Un閁gj 7u jjkVF7@1 5@gdF_1*/4{jJ’'2qnJ$![ff˃O^1*2suͰM\ -e2Nm2 $S<ҦA76Y,,8RnM +NZjCN2R 2;}z:H}0,>#'ŁTJ`w$bzc(1M˺mhGMQ "lP}P ŢTͺ#=k zgz\|DBq:tjJ މ\[:vgo>cɋ Iv`R!se@m>dĻPPY mSKړ.nC2ER\[d9ДSYgJ:k/J-nCUiU2AR9ҕ2Pj˿x0 u¹-oZOA =˨@M*ɾ] ߐFꂲO<>(8SE4Z| tT/\^Շ->^yo88{F [E!4TmSȣMᆉ25@Tr^r)9elzn:)Cz⇎NJi1Lo;ϸS H)+6}|696;ZblHj!|t$O%3tFڝ 賂fVҵ*yy|Z.ӤkU>dPI x:P֤CCatkn 3LM˘𾘅Z&/>IKŻot04"j0<6iY,K@߬Pq~c iɡ־>^`N[g<ŨM`NC1*q|մ*v.y}U\x(o&%@>fcʟ3+.(6r>h.BA|vA'\f/,8>nG:SX+Յ Ka` BXj+ER{T-]NiBOvEKwݽW?^\s>›_&"Tlfp}C/Mrz9?![d<' >* /N##PCQ"|(|yl}eq~lSHBxξ' om_v _ex@ԪOeIl@=$S킲IVOlǔ2?^c Y*Ԉ^d@ٛBPY$^Da}L ) -ekIrei>f):ERBM!P7p`ټ*ϊ&zPr<zfOrcz0K1K%IJm ?ʘ_ 0S4?b̕0~%_-?6{)%(@%nHZwV X:6h0 =FJ *yǷ֢0=~i1f.:;]&#cT_  (#5ʼeFTK#5%ʘuG*B$Sm(_*26zAUIz6\KZE`Zu aV?eEWWG=>˦6WX's¨uڡ Olep|5LM/(A Bo(J`Q'\MZS Ex] &Y v',fBl2ݱ_Slg>~4iηfdx٬uKpŞ zÖuڊ)ݴ%;@V~mQJ<J }k iwEh#͌%Gx1 h<+EG7!-g$ZZI5K2$Rul\cRLQpLtʾàXHXQnZ&3 WiG0#faE[DhL׏c8Ӭvy cJؽsҕE?[bEhIHsZ[pXۘv^i,_߿ #x&e5]kc<zIw\'=鎍b'RG㉦LGeJ}ҙZYNQ21zx:K'=9oiy1)Ji=p8!, ::c|98? h='\Ic4ոIT]R^K'o.jS9C8ZuJn MF?Zw2T7XDS )6ڴ~,kŘb?54V#.3L* e'VFFU%7mmUӊҒSRUcmr |y{TDB;eI:{ہbN`5 iLXGk&mr%Y g){B?٤ /taiٮ+*IKɐMeղ8Ak_&h\ࡸ/GT&h:(%vYuLVXBoUȐ&$-I7QPG4 AZbpȣ-dpj$rI:<-ʥCjBod[匲{H TFVǒ G X HMd Vt1rW#N#]YBGeEF5Q흂U ^[Z , L`T ZPԖivi#ŧiSTуFm0Zm*cF^$ݵjj@z2P 9+[6GBqn(*GNb"H(uD5eע:t*YoVgPQ/o)UЫ ӗ:Ǽa3y>ef^% 4)؛B׺-rkcMn}݈Uo3ɀ "y$MfR9#6ӥbxL$=Eͣoz1/%%zT~Wײ(7- T~u=ܶ\ߡDpzhOs^[Uis-4uUWd LY&u瑮_*[պn*jQA HPƖs4R,5(Fn9bWVR@fQ bl f SDRr#*Uc9e)E鉊jp~T5({rJ!ZOI*'c~Ա/kˡ xI~B~nE6}͇r>oPntWW% y2v9U)1!{oѬήz4ȡ{~z2a1+Z/rUEy8U:N/J˫{lh0L-lhfiЅ1pHO͈}j35("L2Kރio/hx%V1;@JNFJ^7[tagVU5Ӓ#Ӓ6!88@Rh?j7ěe?Tvj*څߪSMzzZJTVCR՛13OsIKz:PZ6kzMH|U5l7aNM<$ ' ۾([h*a;9bN(u{$b~+ b~ʕq已H!gh$A]y&ba M"ׅߒwT>K2/G n2PKn9T]A䇭p9 ]%J G^hyji!/ē*瘼 _~_@頫}Tx}y}AA7}AT*eL|cn/@}Qy@p5|!$d:itAB4l Na qTƆÊ yvv]PK.<iKD7B|fٺi^JԓyMݬtoܞsΰ`h=n;R.I?dͺ8hGqbb=`GrA=RAw!jZfuL"MM\l5µ #B#b$\ᶩO=GuD1,v4] N4_PX %:*-; N$. Wz謐d|/c - I]*vh+45辒e+SY|)*TtC"-=5,iJ^Y!%!x3u5>70Vf +#u5ѕ)*8= AJT^ӲBM'$PJgNEb 5`IJ}E s#&xVxTUdh(F2VdaN-/BINԯB9IZ ŴN7 $执KOWiKi=$ҽjz-FG=OJݦpF5NR:͋^th,HMЖ_q.Rop'GUu9FKa>] Rd6´0RW]/e@g0S[UNAtňʡyp:50iqWjkIF.׺{Yt6!,r'/5'|E$*O59! ,87w+2gQN.p뤥,Q@gKg΢շsB \Vs whDW ń/ sY[.lS0+ jϹrB:xTaUUgn6cl%ފ}Es;Y'guZBRY/FO ԺRe#ɜZ~ZjP|;Dr"T%BVi&RSv;.(EMi;-RtGtz&OFe\m]mI9*Tte$ M ֕t>Fļ!VRC:!tEӉ0Ы ޫvqh: & }~+$TEreiQt9M!+(y_6,xz#I A=aN"/] *b 3a0 hq5 $s6t%SD~|(p PDg9|!}a}]\g֐`W堅!aHG P;fѤMtJ',ڳEM˃m&D|juixezěBdɘo]N nwuȯtVz;t1mt" } S+YnKI-`o֮1[T dQIw֩Q|Ěԩ"t"or"8 2hg%xq$2 gjjFh-M D~6^.݆7Mi?E;E\':g} ¤P=YpWG9չx>)kY;˵Ňˁ(5t)=5 9fZ~v*MzcR}! 呸f4(8 Ҡa`$\pKJjyKvK>qҥ L>au sٱ't4@l;ޗ: Xpi ܛ c%P!I+7UE6-EB2FiIgS0e%DQ46#3ӲN<k/\:B ;io-desTU2 y+c+u.? y+eGlF/=)DZ#3Ԩ#GESz0A@X&2͂3:]"en#b6'I#~jO[ҳqڵfsݚKJ&Iljך-";%;[uJi46`+M0N~q(L`q[MpNv(;֡"-A6 :]c,4Hw\z6˅:JWJN$kXm1uԣ2N7nߴ!PPV$YErQFZwaJ0]k3k!0Ii ꘅ0aNяCXkC4_DX<,2вȢl#Qxb`WTn&<捜J[W+ ojQq&|ס5qm>8N{%#HDoVi+V춝yc [(M]ty $!<׻'@uӜ "Z:xT 0itx?l$(J曤>\}!L>'8N1@HTs z#M,oTTucESMI2&yc3Q%o; lr:RUsK!:):LUls79zydϟ.Dh7l:=D^ 4sRG}e݄j#c['5IY1U mO1QnmRݔͦ౻ŏ)\n5Qi̯SȍȷWҡ'tʬݪB=vzlT7[¸j8lY&x%2"#>iF 22Ej#2\mbjLRй"ƶ,HfP~$?z^IK9$8cBZHZ=_ /P J+a RZ;hr<1 $^"'i, ,y%D6l諸^ɯi .;fSdդw,{2MfZΝLZI0is(g)pi8e$ 0_(c3\HN'di344#$J8[}c6ߌ|Yy40#m4 i4Dpd-}^eL9Q=^SJiq8Ny-'+a}"TN !㲡MiUʒCo1s6Uqs6])?:r6e\eT;*TKr6Ep˵r6uh#]gS+gpHHԫbMFH*J)QyEXGA9`= ''Ѫjv9p(Tݍ6G' =Uu9CBvA89`VM3>KFΙƤz11F-?6fJ Vws[9dSn CU`ID#(h*vuJ7ćޡĵ GSoDl\uĉJt""0])7E}.d*NӹhȱMi Ԝx^` B ZA%">ޢD8z!'T8D`MH$t49Ǡ o6zݳPN9~qK8$J [qx\LңyM`YJ:4E.)y)8#Lq , :sq؃45SR@ Hx/Ӗ#FʺzW. ^=ϨJ:bidhTW.UI@z=BTW=L5xX&W<{=@>Zzv[sf.EMvy We]߫J/dI @8$E2A^e q)#H6%r棥2A>-v-{lGHXKL$ Epx%jС:lV&:ir0!/T=mĠ8hZ !3ΦY@KSIdzT!tDZ:IHfj74U OG:pYGIUD&,ng(RRQ>ia1#.qJfg(Ӡ:St8HhP ].Ӳc -RRY3J3eh=)՚Ƥa 5[MELUfM^fZ b.DhEl#%#5+/Bb_0-[rWlT4= ؐ-^߲_ȶrFoGJ>2fW0EM'NW#4%SV;yAiQ49ğrS~Y]&Fj6\7wS+ &٦%z[tH8P;l3 5P85T-Gf7Pҍqsq,Ɋ^\.B%l+2T@" {̈́P.vn0BV.pA vj FL__ U 6B!_mU}a#'pJ?=97|8&Ӵwg"k$WP:9X'Th6.qJ@Mil>żD7ąxh-eRc.euv^n#ʹ+'TrsBi6鐲Z.M-zS.9)K?WF x2{}tD4C0TDfr8Oɇ"Onˆ^ a U-ﱧ\{p:rf(+,B$PQP \f6XesRMhٌlE!j0C.7}RLO5#1Ayj&(f@4^ruʁBC6 nQ \Rs ObwKM޲D<cJnd 䖑04n@SMmQLd3%.y )i jm(QD2$耮anuз aSf ki%PjRk-ˎZܔr^9#Pt;pf{ =7:j5G6CJV3Y52Z`ghZCtkJ3\ d-%>}kے#Cmk]ٙ2}H\&RۺʹfTCBⓦKg9Ր$^}]AxEZͿ?u3Qt 4 %]CRr3X іu^w |adk(FK451&!ІBTmOo3Azs6IG[xHUG" \EӵD&hri~dTCjtT5K8> ֵrp)~[ӭH%7؏b좰F{4MyOGh(ූGFuQ-uZ/Et^)~[#Vph.-}>|~c5#',L{4PN&>o}|QFv-|(7.#мMI[e FF}%ic_`% }H_3;[n="-EnC7CPuEiB.&\>t(&vV[Q?71pk>R{>M^ K8^2`tk*W lѮ~ȟ~ tgv:Uݣi4;4;e4*6?i H̭=)%ԤRR+i G7їS4VC piU&V.!4MVʻIzknqg瘜=X%ſNSHV@s%t;e'i+0AG=S~̥gOa˫(F8cg);ˎf/܂4ĔB+B]qg\m.ŕ*.\He}ۣLz"sLJ&EC`]"(gዠ׳q5Y7O0h<|yo (Zj6z4 E}Jˮv ;Q0Q"-J)J3p^0)J44:Jc_B  E|[;)XC١WQSlf z5 Iߟ)ybٵWXml7?.QP)!ٔzokj;#Mr~- GwL]W(@{ ޚʩm%i[OMWRKVxUܺ]_ڞZxU5@Yfs /Yf)1@ja*|s~/[3Oj5UAUTO5|UR=k'w:l<)者E];#者kN\ h;.ٜtd"u#ک 6P#~{jN^z2ӝocLhdFX—:sjC~F*B7{SjC#>GgT4GgQD6>){e#3Rnp4~Wrf%SN#7~\zoiTV_Nii0姇|?mi.ws}M=O5ZQZ[<"5cl@M'7{^͞QA`f;Ձ)ɰ޴R/s"N{/4+[|*a.tBK]ZKJΞ*|kM#⣆>!98,ml$6[pu}릿q]Gs#޴;Wx}_1wD~i_>w#Ķw'œ۝qEEcNe9\=UDjEeoWzTj//V-P M&1h>lĴ:֗Ocɹ|V-X56.|v| #Iž<,ul@@ޗVc_وDt_f#UF&K3^S.YJU.2 YQ (Wcwoӯ.=Ƀ ,Rvg' Bn9$FEN2f)Tǁ7DX+.],ҨX+ 8tyPy|춇h\ӐBET#,rjyi4g=nif:z>ni֋ud7qK#qhqK=hg{]uOֶcauw6eC8;9w#cyOVLFM>v7nKw?;-mj9QdnlQY`5]%ttuԝL{ciӿ]*_v]r*-yItؾ,"4o<w rx}HLt[7AIE)|sB9zKGU~#B5 ?O0ΚPXb ^g+vNPYH3}c `—MxDڐcY!mpNx #rN<} l q}ڊ Epӡ~їtH QyTl<5] ZͣN GQwoS3cl٣;q+Anl 턶5#BeA#!ml;p@]9ޖi+]R,' { T'b${X N2ˆy6?IY!na ccz8had/V{<dKر tý244;IWLj K{xHCĄXWEt䋦Wȷycˇ@F- /GE;mxwg$S(yb[> uxp厕)'t:.wWTV} iv dk* 7~䄉[TV$JNQCA}B.8|< _Jj~]@OS.!й*,`P]J ]5ڊ6RTjN^?U(VL{Mj=|5QQ3OO-Mk>4j9A</. !!^1r= sp E{<&aPL?  ^ b[tܿ>vFe8ǭW@XTj\=*)z!Rc8UZM_J֦,Ql߆.VlDW*ׂUGC5b D8Iy+X(2#ԉ-NbR/8^NM{&RBWz w)K} =μYj:Mh6aWsFC<]rǒr\j Va TPKņu(ICؑh8pOy/*eQy( -Jp>7+F"EsT"$s%z(oNj~ve㤄-ECKD $W^I]Tͽ%T6İvL +Xy`T/">J+UFiSIjtǔgT" .xJIƪ?ұKgeh'EM w*EjDܩ; Ez)2뵺ċH-.֏ީ<?T;UI?"OG~l3$? }w?:i˗4lKA~ܯ~+ fOۖBɍxLTv] &m DWʕoIɬ!N-(qiy^ (C02k+S]a@kI,2]*5J[~+(;1=%3[lj׫:YqXjё!R]-ETQ9@~-fڬyreR?GmkqyK+8R$d;ًǔǂvGZBӣ R^FQ<-ZAEG?&jק|yUh٠'öݫCRJhtBz |bץ*yjnlf>%PK;$IEY vq֡bOQ2,KK㍡ADo 6zBFX LH֍IP_d38hZ7 ]tM гn}\J#&H@:4&] ZO1Ա')r  W†^$vʐbeen д+_]%>$hiμOr'kzH -[w^kuyt,Sr#a} |Kk>tp-+hV!)skK?ҡ8#zn0FF\f GapžK(mD$pYhPWޛ"(. Խ ϴ mjX5T}#.8o]7mn B?/i+Qjd5f6@/%7'y Pޢ[g7A_ -mVA4Q D hMCk%_yA5LiPAy?5,tQzC Vuz X]Eˏnpw7o;FvՉ=( Tvs?'" E7fZ 6JMĬfo߾#޴W|ޠv#*J7Q,BK6l (f~dlIkTzIjdl4J6x?oѰ* 5 H}- P: [,0~_CW<YnTLv<$E+]sF:;[i6oƒoޝKOnޝK OC~%ܧB*x -@, !T,| KUB2z-K9R ɄH,"#|hη1Sl)-GL>y/$7?GfFݙV1* 5Btd0ۙ%UeQZqi0V5k$16΀Ȕj,WMs0>/u(@"=E&[krW"h0=zK侴FWE|\\rV3{0@7U<4Vqm2m#^/.ڶAz$6 =Ůi2Dͽ<5 M0 u g_b|ەH! u^nWJĊ<ȡδ Y<[4!3IrV@ޔCTY&ĎI\uLu&P[9yС4r1?4JGKo;*$#*\vo!|[*rCDZ[ju&iq:!Ԧ\m:0D Mݨw6x1t;CM 5vuCK)ͽa0x_(Qp0M/9ORkobU/Uo=ORnBwGsKnv2HGu[ojvXRoM/9TjU˃[. =z+cIh~ɵnJ"vT xoV^EQҀ@:ʀFNC 6GhFs.uRZKbS(QSs^T[+UGP!L՝ <8㹰uL"OM}-]F4#D8mRgn4f4VkTVbZtUӈv:鴊kVyNkYRD*!gf rb¶4i-O (Q r(PcJJ;R+y}]WP,Y K)s WHw\ g*%2~]|#W5-cT s*irSQ4#ʌ)?4]9|t&T|Ҩ~H"._v^G3]V^TM>6Bӹ@ɹNU15{}-izx-jsF)k/ָC9_k^-E2OZo_i2aV/u?*gimY- o+Z ƟjC c:hGd(fiA@͡g},?G&i'u1`j|#?G+,hUI1ԬMOObG[m'3C;/U[_^$hAxjy0! Mf~x=MQ" ~|̼f_xĢ7_I)RεiDFǐ3W.]Q^:R1%qP<)'/Miz ytE%Fdz_g uyK!ҡ[Rјa( LyDt*8T~}N[fhi_$mq>2Pq7E)[ cXZ odthfc$jܶAptt=Œ)UVM#hlE*CɪNP*+tFTTP`Rr DL(5@0,q[2P94'qUCD6GkѫT K .~e, R},V*_Jv-chcG5+tA"tř,8BC5R` , 36K!k0PHbvy4Uj8r9'Z-p;aZl$Ny*byF^/8PaE'O\MXomCe ;6? te[tD#)ЦMS73\SӐtx'_mJQ6\r?7lg|eTsj,ʋJ/W:JP`Sa\Wb/wNMAdϏ!Zjhn?~l(ݐtuɁl\ӞM>̗]q9n&{\/͕ݚWY]6n.np֥&(UhhG|} \4#!] qB~*5.mOժx.U#>֍Uf^h@b8*%bjZERk|L#,A^/H+Ii>.eS[Ju%RP?D=kj).C2iehicY-ZSJ-D=oJ.BKS?^Wz]҄U}*)ݨ-5De;ǒLu,@v[ZV7󮰵 @](4:@#\s3B1 |yR5WW ̲X ^z %?.HhkT_ mXH}t(:iH4M xpR7_"F9fѽ)1*Pk]ƥSǷ&UMP=Yal>Tdgv`'Ƌj9]SBy ƢQ7b, 0VSGd]v $o"is6 ozRl TnPW -s4"%. VPEXf\!dCZWj85Ƨ~[Jd/" XA]E,4oU rP!dU ݜ" YɫEQ>"]ʣg-[HSNh,f" 0+vݬ)TzZBĖ&γ&SiGk TrzK^|)"&;8:p[p:Ui;pбe%[G[=#$dkBibh[pw%]ж|u:v 8@MpuB=x貝=>>psް}  oL=d2u @q;q6LERNP]%#B i@%…$,{H l]DuB*,w ;`yo;;=~xD tE&!d6z,bۤG$Bu㨍$ Ң mJQp YP [j2 ƫPi %.zE|zxG-*D:hw֙dI#Yp杻#`+QFMWL B?b<߼ޒ} !nWKK ZnӵYpհ҇羚g$/s_m47Z=tȠ N͇g~w tI*Ne条rTۉgҎUM9e$Qlvh$:}³mMFu_5¤=fP Ց;tLe[Rrte]!UfNEnb]u§;X] 6rIwP$ta÷:ʒ_&.avI PmIÆwH2}krN=lxzG>qXP|4i"t*Qht_UMZ]8ќ)0U2506|aNwVsKS0PFeM5rM'QpC% @񴹽WwɦiTth cAc(l"Kl` `Pg#h]{P'C#_/PuK5,葡=!e?8?Lr,uЄi뉌Efw6&zaoW$ys:呒KH(ӛNLrEڈ639#jC]:%AnᷠaZq ҧ=Ke!ugB|Z2,6xchJ~y]I89J'^/?y=zi=o&5q=a?TuXHot\?F},p\=-IZ-R= *ϤzQƦFqnQ8Szz>-|zSDQ mL(O`m*Wt'㨈0/=ы_7G*JtEg=6FO/tPC+#wئ QR"u/"gr5=P}\. GQ$lmŭ;Av^l]T[.nݚ~Tz%b BҶRJ- ^d}w翤;q|_!M(GlNʦ! m9S5 1ģi)gtSg Uiz24fSF$FsZE3 C_玘V ^.=ILe]hIr{buLP˅:ۯgF|JTVڰ<%Fv%[HjA㘉x: ;j+%9\@' Lq>N.L1[c4@(S&)؈ Ū< T.XD7/VQX(r!"zWHF?`UR.:]TA׎"ݗ6"Mvl7F:ƿscs5(Qhnc[}i3"Ўˣޗ!vlq٘RNCgdL:'h2^Q4r[Ow`z?)GjF|z0Fg*J[mt#hNR^<> 1vjg1k;LS֩ 9[@-,@(Flj ӾT@VzUFڀ_GR/ 9=%āmu?]q̓/H/ Z8=9oHWiG{nYK~,3 C R]fR" R-gڨZ!);m5MR-3@gfa,` VU7Ih䆻UXPhVUsKh䉻at$k[)^&8Օsʰ7dt_ kO;9e+ ֛T-LAFWB5YKܧFzp 7.*J!%}S1H75"V)2Y[2y9\P"ΠVzИ,5Q۪eaW}.Z~>~ݿ{GBg\KO3fw32Fy,Vkqy7XReҬޠϩR@nZVX҄뛖E`&fF"=2ߔ,eF {~ D \G__Kp PyrmIۆp P Hw2nH߆H;4ˡ@S5%_vzC\ogpϩX_kpt5/oՇSA&?ܜup^;G35cT^8F?9eT%^SNS{EexwlS>{}FelS{ᾣ{F/~Ք)fzwS;T+!]wr.)[j"˨!=E\ʬsd~V.SpII{Vua+[ԖЈIچ" 'B:эs8Vݪ .Ga)GyjT"-TOyA`Iwև9gSڡ&=˯(NlxBPaQޔSb UOwct`6C]wccO0>s8gM2֡&=R;ٲLrIf##Bw,&pA b'rLJPiJ7e:7vhzpF'"s[xn??< MMSE ӻNs(״ݢ*w矔˝*GK-ڟry/ ;|tϔ=O )x47݀j)U,c))L uvr7kڍ=ͯÕ~ϟ8m\m+̓&XBy\5Ov'uv'vQ/…tӞs5SHE%2}aAWY5)4Euczf~ф=v)|uc.:b|fZQvˡmE U ]hbuvtv"sq5!h5#ЍNFZ3V鑨uP81w2OD}twPHxAOFZv-i\/?FccZY_[@.Q_ZkzshXK(*0=F@mVKZ( x\>(Bƪ^z?(NSFL ~ލ*)2@, n+=$j@R"[A} Sd' A~XNʩ:zбV7lp[ڹx43a{>2)K6u8wyj[ h-HtuۼVzG&${]=uņ.i-T re{ 2cC״`jSY>1 ZdvthftO:QPgzy[ nO'gv&>~$zG!rD~GB%Д_bV# Ql|1ԡ2?ӴM^_MDsӱ=]ǫgtt{ 2RtJlS8?I2L%V*Ä}_U)fTѲvz+ēQ@xz=)g1[ۓɟ|u!%f|JᏜҞDD*IۼY*RYJzZ)2YJ1 NK_喲ERzAR5tpj ?RVxTWXJ\d֐K~Ld*40TfA͎1KZSUr:I6'Iv:OXC' =el-fIL~,M*t3fI5f0Adȶ/U =_/Z4q{Ijr E,ke\|Rׁt;b ~g2۵!<5=QE'wXr]_QT1T_ WdL68%}WW_i?Z [Hp5Q@`Әuz;%SGBr"H4y<=> 3 \^dG[${]UbsburVi}#^mG!n͚@``N)!'ttX}/9t3ktXq /Q9PkV B/ZEXI6: N0+Js%?_Vz M* R fsY4*h崭*kܡ¹Slܬ0E6m%W+ ęd~B Fs=e[Y컑N*q B}/AoR9&Htb( ,iDYHdnǂ詚tq&%Mh &:b^(D32]OEA;煉bjd%j|ۃ"Ҟ[?ؖ^\˫dSsV 3Le+H?x* 3Ȫ0ɤ&4 Z&jYEBO!QW('PW? OLO%M Q妚~]G*Mᤂw9-97֧No5t}4]HK: /2yy`zUPaUIz=!/}ejJߚnb:e^Ӂ H2=ysp;>mN }?ޛeyY$r!_p[5Fӳn |# 8Z]'R+B^skM9PᶊKGG҄Hɍa;/ `N/}0lFR8 Ntx^0 ޽$X8Z1@CAi:N=X%C9WspQBWY-nT|k5[nvC RVf+f)RFOT['{Bo7r(^[ev;->9W@R }b ^}+/m(ϐl @I*t>FheW/Yrf?6` J3?KNܾFo-5TFc~E=8?r"0xbC_}m 4SPJCMNcֵc (xN ]t- ~Y %d_oS.lIՇ}iCuȻUr·J*Tv͋jlF S*)M?B#0%$Q3x3&A鿩-L,g:x 3 Ma]d0?ab̊{%zr U[.Kj1PrM|d`REpUBN pMSÊuhp"UBδ~BV/6Gunm0Cs9ʀg(c1oHc@iye(`R*S_}PRnNvKMNM]R,SSH-l SxD~=plMc tV4=-t U}S#|Ұ(Q)<{Ӣ#]'gOOZ= 7 (%]s ޴,&Uk$޴ԯj[y핪k^ktI<Ӊ+Uqo'PB\Y=ihP6*Yv_zm2 bK 1˲Bl4/e/ ae(K+0Jiu!A q?Ơ*im(wLC_i*mLg)̯qZscIAMh:ţWzB,4Iu Rj*P3(Aۯohr:(xFSlЧe aSni/P7k 1 'Jr6?H<bVI 3DR&C]Ƥ =`KP FDz2%E Er1ް Zc%JسHaQe,\=#t,Gzb~HN"shj 2*Ζa.|.Lʙ7V Tq' QӛB ћغ[zWڊm,/`EBaUE3@:X^W>,WɠFQfƊE!e:TrCgtZ޵[HI3.SyeB=9ltt[180VXDQ Sod8扼;Fhi',-?E9A25XPUJ?u#iUR*uaj'kXt{zzXcMmVdT?i"HI,//fSe4Ge GY}Y bMGq] 3>J=Rk ydTf S^(])QnAi&(Jj}T^AFګ D:,ڻ*6jYPHQEX'zR)<vRԙ"ljNͺ `?U*^m.C/ƥQ낢xY6z ,Y ݻ #u;@W{dun#^z hY jۥA"d>한#5U,D%E(3 ݑ<lWGkP|.\7OFS*7LxTAXcs~.@FmLݴXKJQsWN2!Oе<ߑj[_z[TF6RɣT<2]3(2HIܩVR2/j}ԳP*hu-nGʳ&2/rDҖ1ӑ:h8ltIno;yDV}Y=vg;-ɪSni I>w3Ý>U^Tsv͛a44:5 :Jv]CXA^F~,Af5D%k5笗fQFj0N>C(Nctfs:ޜ<VV(Id;U~ L"9u~)4nuE>Ko~I[=:Ic J[=: Jc_Lޣ2R1Ne*Ʃ {~?b>p7g( {Cgk O]/ y4x O]/1ԵټNU9?I#Lw-owmh"[hw4D_Pz uCHU0^N3GEMKzڑAqH@uLޗcWAiH,fap4,B` _rO2R6}BNr LtR<hrTNBR0ӅbIPiXտ2v*lrPyx.і=,c(s< 4PZx-lE0`os:YyI6l f ˄Җ+ Pbmms5@!kX9\P 'itbv=~MF5GK>*\rkTiK:iqw`JV)1DDdu?ÔFkpi(2^LiTj)W!ff)wcTs/`4Ulf\BfFg4e-*+m[ /:.QB_6yi@*JHA&HwZ]-eL[-讣w?5w"m2{I152Y(sf3yCcB>5-^Ǯ DRhV % ^cNEjk^|4[B9/k Cj-T,,+k$HYXTuj}A}qb㢺53&_}_q3"M;DˎVҿxes]4_ڑ0P-g'ätЎd peIu+/l|5 82:jHDj2BuI ]i5LV綦M/IaxtS;mVrپ|n#yl2Wi0@Rt# N;ܛ@tp*4\qNz]ǘzf5 H " u0j;Ȇ&$N Q0`tj֛N`^l42Bd$S2XYb!MBSr0R<%upj'Ul @扇YT?j"j$&U[S\d)&_܊ťJcG> O}1RҴSM=*D'Dg3֡4vJDAAEZ2D"ړ`Ξ/?[6:9A}zn$F~PNN:TrE mCa) UxNXF'V=Y^4CE6 01:1g-ՐE@sx/\*z@TqpP~^XG:bPٶ+Bm XyNcL(b!kTqK SO07ʖT@vxCW!}=6#;ɧͱD;K@ߦSQX2tua ,u+5U_޺OK +_Hd6멑`)AZ8t]dVB_AUp ^V^5֡l|s!e3jXJ)PWZY2j"oNтdtM4$1R睢Mczy QeSsMC(V[ZӇi#Pv~-pnAH@"6X}k_)-Y`Be!ME3(e;V;RξJ㧁j¼8TDRtI*l46Wi*QBߗ*zoJ1N)ȡٍKgD/>ܵ8?ܭ4ҍx1KƭW.C7t~2OjSbRvLKZoܬs&T^tܪՄ XԂ> 1fӄRغgAIfBfΜR3ҞSt6j}6}Nz C9h)ن gdtc2Z_I=U?Pql)΅ ; ecgʯUH~)-@GAlDazwTkz&P'wk^aupГ0r/N~aT`#V]cOWe{ )/*mi$n~-~3dQʌqJ7ִեL8jտSUҜH/^tS,ln:˸n E̽6M"N!W*Xc!S#ի~xg+0nfWfᕥ8Jm6-vxc$,Dnyju ᅥ@Kj)!k+hƪIC?׹j:T]mj«U .?TFXwK*s iK1*c3e?!KrQC SeF.2~.9e1.'ś=\esskbvywF"B 8 9۝I(X'G;I7:<`jg%O|k%;}A< 630PyliPQad3'!ס0F uh`4<8.rL':M+AL3@˨G-$̛ބb,| JJ)G WV/ ݀x3H@\fuHw8@ r 2 Gң C@Ўp[CVM(⋙i4 &2!h ^tA=}ysvSCzvI;uXip} $_c qD4&=m\JeJa]IrXawGȥJj1vi䶏6Û:<.>S37 Z3+Xcrtsa}8p{C>yoڟӽv !&#ALV 6/U󾷣nU3ۯ-{}&2mn u}JZ\OΕ솛26G5meVߕ|tحinٕ5maW v?kj+a$lkZ mnMtI[ݰԶܯiԕnwنaʬ-F:O3ޘId䅹di?U:Б+Gfщ(Hk_].GpI>E#(k_=Bl5HL)b\\ͭo(iwx$1U3(;%)3lb xd,U< =E1t*!Pfâ":dF7 j\%xMYsB) 4g^q:)/\S m" >4)[SFˬ),g^y)Q>GQO9 h*3;RB<ͨ8R[A@7ꀉ=UBy ms,1G: O6miRSH[1%W± VSE_逵U4!ÜVچ33a|nhmtB6A!՘c쑔T}_KB<7 jeGyxJcנ\.?D8N(}xC,V?9Rkp}: kXf,F(A҄AKP#T: xx~5J'Yg޺T9y_jʭmkLw-6۶^mE rIg+HT$ GA9$R噣3]wVK mbԼ`֕ifc.zTOۭJ&s1Q+[Ԙ=pUKs1ڡTv"ix}Tb/H8v)ewKiR T]mjB:RY/$s@͏k"}^Ozn \qo/Da.> - ?Z(& pqJwa='5(/w0wQr;h2*d8iFP 8$b2t@-ɹV*l 4C=D}(RaX&e}|(RբL}tn 锊± TwʥdY|@`t_dOڧ%gPB53(ږ% ?ÑAB~מ~ zKgRl$#W9V]X棯!ys+RFpZ$[ rrǥypl$\>dzhvLYӴM/dgwEerq4z6 ~.HMh5P%ގU]hΔpZڲ B4qjq6Frg>d.rH|&&SB{/)o_`G;FCS2ANlȚq"d njHqB1 Q2Ȩ1S:{#3p8, BtB]3|G?Y~>3 u#vi;aBd]=* KhNf+ݠ)~~Y\oemx \ 뷵oq4k:8nj#wu͜x۰:t!^˵z}Z;OWe);LA$Z{xaiy~Jn/GQn/5MMs9_Wz_|^pϸ/I%7L΄>FhKr_=Շ>P>~!}QA1EK@[73o燮؍_쇥X=G(?rz*eo{e3]BD.43mwSk2e>KQ?StNb1mx͛R8+fB_L2m*&SE:#*aLanj3T#6a*x{k@LN%)7ÉWpŹ0My!i'[,WgڰUU 6pr @59!F@ YM82Q?dh' }{z4dR]|_J?ZFͦ#>EΨvN1F2p`oQpa3pTշ PeB.*8kuIJ@nAzq Ja&9̙N1R9`M?aLEmgY &GVs4,-c_)GC6Rt^Ȩ3s{Dƙ:IPZ4[Aۿd,XL-S y).BJ }y_"Sx6[G_BzGAJ2/|efX&$d b9UBq}Yc5kjyr>*^P@PyK:yzt\3pzt\ЉKqg;Wѥ-;.,4w+w~tvyj tor[J[0OQMXKvb1o(pٷ@m )6ҵY s "~ t;xj[Oљ'{8x _ lLAt s ..۶h귋V6QHXooˇ"N@8KqZ(Kni8S 忄X63n1MI#Db:^&H* `@&e S<,V*K_ws8D6R:2jS$/sGUc$ V lo&y=Ud&a-Ș)km1)gNkL ʂ&E\OkN&jV?L/9a㝖p h0`/< i H't%Xvԡ^9/3?*فm1t֍1lĻeD<>=W߀t#!􀋛~CiblUlzoRzϮovVͶ)D D;&z<~P[Q9 =)IQ[5!։5=SXD|EJ׮Bưyp`Odiu~.2𡍼vtZٿHT6w/_ p{8ㆂ ~fk)x@#ɩ=/6Zo2x\rj@Kczs-lMΛ,_ʁEiRTIsmX8zjLGz˶?XdyS2JMþmk24TI ꘭Vw-Wpd~j^ysʥ = re6u5 KD+aF!Kc=c(nʦА;[?e= ( 鱾S ݰ;|( Z>%fU̕al/jʊY(D-r(^wR+UH\5dtbp,TFVƅXtĂʨjLwѵʥ*Bsy* Пa2_d@QيA\T9B[ZR0 U$<`h-HVX)//>ҡR0 |K~}ȬIG, TZdSf/U.UYq@ ;%YJ1P6*Oi5(.Vn,4{x!@XFI8#x).r!yk,rz*z(ZCX"2,w&qshNv&]}9k0Ij8tu%j̫%[U}wJK$E{YxEKG 7*zaFݨjnZy[s9`& G  WoTU{ʮUtWi1g#H5YMڋ$"Qc2E崅4<\3V u.IglIuhd--][s$sMIEx3E@{j$l}n7e {TGcQoѩM#eԷ lusyC$?P&]_0&IIΔ ./ h5:%%x$z2*H@^6@6,*]dJfoJr)i޵۾P#`b lY[@j=U{yi:M?$LCg1'M5' J5: 0WdK۵'E{HPR¯d4yJ'O0'iB(t|4iB$Pw0wEBv(+' &bA|xP޿bd8L"W|Q }R'&eXy})EKVSn"^7D mwB )3Q:\w3k"T="vʼ;J\ fwe=SzJW|եX u})-N鏥.J(tuh.N.j:"LyRt]GD/yJ^`W}*Z44:%+5}IVGwpW5ϥ9(t+|j6R@4E c4j}R ` :pӭY~N9)t%eQ/PF_ڨSi-8°J^\2S~/)<]ehpW/uJI2 ec$;}ST!:2;Mɫ& dBJ^:1q $P#RPTr1=ɋИݮ!4>2mr;gSd ɇaXƛ=_ޛLx|ݤq̖iܸ3fTD x@EA{g!32kQ% c^i,xZU45kN[or(c2UkS5d\ڏ?J賏*imz4TMc- Ad6F |eN;].'iz`QSB6pj3jyp)ɲΰl,Z MuRߙβHRi|s,h/&{g+^Ix2RЋ %v Obճ\Y~ MxT(d26"d8a~B'UWXiVҞoJdtY|A[VTȺR5] ͰUŴ1Z];'?~ڲ6xIJ98E_RV=s;?RuKOImlEg뷆=۝TmުC3_NhUil7eC1<> ɆV8)i?#IZS;.{M=fΓC_4kSfgܹTpY\JԆ.ir[9ϭn/Kz$=Y*>yrn.fp'aDBinFs_[E>1Li%IF1J T#rn3`f*U{Ԗ[Q{I4rY_KCM!hO S*\<ax>ySwQ)cxY<L4xadMS,&zں. (qoiqtJ0f녱 |NNF2 c)F:w#qx"pSW=RʷsRhn")TK<4șu$WQBwj;uIxvVCУ]@յR뢼Z{r3=;1o*z9kB;F6rdڽ!>1MYoW;Ek-{HDY ^WOR6u(vǒ4z{T<`X-2#Q5h.Z5d|3,B`X,C ݱla_3FU0e<+Iz:]WFc]*ng`3F4Ղ\/x^[O(&+-]EiZ-acSo]J4rIڏ-{ /}Jk23ti-;Q-8d 6/ڶz4:°L˰M#UDGDE< TyIچ2;O%%$][UԜ#r4-$~xsP&xDr^]'L=:9-Ƕqn#.FΥ1=Ƕpo`.J&]!XThƁ^]4UG--t35YBF9V* Em4 6؇[=Ahb w$T"4u .~%H#D ?]MKhZ&H U77Y91.!bsswPHojԱb[E? BIZQI3"BBF/P {&C&Tz}h6/4xP Fl`6 ,fž.(n Wsr U^/h<,(1 Ce|!S@>mQF%Yf,~+SPXa,JS=l<0aT8e8B'{|Uh+@yV9l8X2Cht;kh>vMm17 i'] 4t T :=Q2b_['ש2mcCkzLL2f仴qE׽#2j}MOIuW-/gi+jj51h*LXUG K TVDk 5bj{&' _])p4aZLϱ!6AK`uRf0>hM UKO#CݷG *6kt~ڃÒ$+iآ*y@|p!--S+V7\%}6{O$3pk}t =}6p(7;Ovi[<|wTDQXp>/JriP)M8U_@S4 P0N4EM+LT3W kTKT BCsf G9?#&p7MB{NŸS )MmXЄH?+d!$kMI[&1̩.EuE~/fbɩ8,D@hgSM BGpjtA>鷽_4 uAJ  Z=݆FZ$GM1hG,p0њ8:ҟʭ@pH#,ZyoTI eNb̢S&}I,+gC-B*I{~gc'A݄ןdu^ܰM !oX;/X+>b%ϳ$umt3<},鿙lIf)3ˉnEK`>s0-x9IId$ 8N,S I/)RJƺ}[$P݌Ra9uD]")T|8ciTՈtt!|j1V  M]s+vA3|-M(.W (I]hɵzhV,=Út+<0Mդa( 4Ghd#u*?2QuI i/gKm- z*%WɹԱ]6_ 1|2VDys Njdש7`gI,!˪m9\0MتԛB(Л sQ5^.rsn~7k0TgK, meI}֪ܨJϢosWV}usuhTnkkqڭ!yמ7+uZC_L\0tE"#'CUђ9kjf,й'qn59휉Pk~nIQ{&o5w/>-etrD516*xfCn錟_$f 4]GB:R'n$_ԡK+O*qu"GX }cpğYHn*~8#k:;kKָq|_ 5Y{U櫝 ^1ug Ȫ"qR[ꡤ+wm֠m}EDcp|_U8 enj5#EFN<#W̩?zG(S7sއCh*&sF4`҂H1 )ؽfBb{̀f=(f?k0RgHk*;<wV3 =.4Nn3)&9H+qغǫF0LOST_R`DV?UIе&_CrTfU$5!R9ixoIY+y@h!c<\HgmIMMLjٌQ:tD&Fh<4խ3Gզ^?BxltƱD-ofڣK`Cf?Jkű[!L{q&΅O͕N5q3@:Nx+rrLr;8v QvVuă9v|>Y0KO/;-Sw1啣0eNr`| ymX +MwR*{9fPKhcc{#USڰR^;dm!A#ܲ{:5KobY2ek{atKz3f0)]V Q,:̰5 IYLꂜ9>3M9Uckw c/%Z\YZu1A SJhhp fiViC²VxfRR&4!m;7-2`  ͬ22VxUX" Z]l<4ĥ]y\U]kʻӹ<WU-̈́PD¢7;-נZj&խ^0spj,T^Ukbq'hR["`x3Uٙ#2^WL7'hXGZfr3j=;0K2 ;G#4vq_R18&rKRPPNYSz;Er65rĀ9J I3__fobqq9}_#QO NL8 mVV`Pf3cQb7畨R-X5H6-/*fYF$Qe&SUڑChLcUYTeurv*Z. qUaݐ,Yf㪶ӾF-dHe&U]U}33%G媢h$[ *Wx|? JRy: JA :g]@b?`E}ʻ ^e'R۩UIOw&ǝN&Dp2$uֈRM/3RZA;f2%(R $Y2'&:STGQ+38A&2)0Joq ؊u҃]&'S3ٹґTA mԠ:Rޒ\Ӡ>URA DKwf[MSPzAsX}PTrXE>Ja'`0%ˤ;|_~(6d*?5)+UnegPg5ا+9{| Rh3S[]U_>keR4VƱ/Y Sk5,pnrl9V: @nQ{|.})FkLtEil+>kfVW%^gG gfGw% 㔸3kC=ZaMϟ贗H4ZE)T-A~ӯIdxSrᗴ\GJ<~:[a-|~ Z /b^uam 59,n-gb(rݮDjiWRrN Qѻ]9-}(Ȑr#@,}}-w"Zj(HԆ-S6qX>DoZj jI;Pڢ ;5FSzy׼/VnBg0=Apn@AjHAQ[i5HE߲䙩]%I 'VRyJ{O ŗ[wp/D5t[ޡ\\n m=hK[!#%Uk񓓐G 2@nUZB*%_BN Ry;(ri(ڌVOJ7JfS9Z3Z%_r +%* VPI(O7G{rjKXLN`Md ҈2L- *ѯ2$rR'kQ%ȷ- r,E*γ/Xr%!rH1# Fb~߰DJz6gd%ޚ$j+;<#e0dã9Z W|*"+<"2?w" FEK\ZG>$IE1[O긌F@K<$xq-Y.\b䠎~WQVȝ]o-rMy}iz SggLW쫰p_wDZ o0e3`9u~Qn4GeY~ sJ0ݼ7c">[L`I@I zqUPEںlhP7KkcIV/-%^d-bqv2hxcۓW7h_^Q̂i([ۓ2 gҝ7k{ToÀɶ'ƎdDhr6dh*Q V(Dtuqksh(F=ORtMvʔq}% 7*EBpf,8hrXGjr_M)Ad4@S\ Z49:̒`qtM`rAfz|LXrBӽ^i #0 #9gPK2LkQϓ{՗!Ӌb`gnz--+vM`&SRguO|r?/X% FtfhNUZǸC(}q'iLL%?NBi ^oųSzEiYFmW /ٌCxȣ^T<͉H#G7FJljG&q ˱?׸iA(r Ѐ˱?H7a#S[(H:! O;ej)*IÆTsRC׻4]3IseCs~.$v{ONGV>6jiˍOIϑOKxɉ QQ;M +x~(̓+)&I1cYS{Sԓ3yt]gOj0z@tݯh|MC,{]dcv9pWUZ-u9DxQFB W8殍T[0˿;SKg"IUf@K8P즭}#b4#H-VH>΢V[y23XgC(V})V3"[1h|qF͓hϼ+D~rESKushT?Ɋ/*hՇƭ7K%u+dhW؈T+T%.bDQgL>ddT2M"hEHѨ(]8%r`7 ]j+pE}Kȵ)73 CNKUeAUgB+)W2ͧQʅpW4?|BQs./ջOh->Q^5L1_!BbMP%9e5!u56m'si|h-+"Sixhr81GS褺ܣ^gB\_ۻ)O`ѿ jMhJ9u_ `-'2/Шo0ݨUVR^3PWaLZy(A&.f$?ڤ AT TtkNDg_DENAT PTpI=;hq??mMzؕ6Y$7yڄ6lJ֥"~Ze5xqp3 K4IӔ]γUw'83Co ,܍l]xj5oDE'^gHD1/Ҁ:l; gM~03JC/gN5W¼<؈@EEWh!̻mH .CP,j;?\uI1Ĝyrn@4$2ÕIa[̊wH eVHa5iez[2V a_Dr4{RoM$x593Y z<8Bĕ+fB)\ĕf0id]6{k٧]Vz|kۧEڸL m$IZT]k縢+&[׆aSN=Bzy+ۆaSAd@7.zYO :֠R$Ul}h=XRjmԆ hJ Α}R nH@lU^J=}^T+м=Lܫp{̽<57$M=5^UґgI~C{03a~=YA-C^XsUμVeUbi`F[URFYpբdD3~  ˄}I,b(L7V<#.kj,k%yzvf5I\oUΊ=t#yOW$W5}'eTnLBx`v$4PLH< gL]/;ݑlLϬĪAX|8Rso(2 nnًĦBcv1}B tj=_=OSK^LJY_nvwTPvDP޾D[ \Ӧ_&yr dҔ5tGQZb"Np] kle"Hy#Ņ?EJ 8(,B@*u͞ǟK|J*Uecj v\L9FV) 1r Mh nuüpۂ39 Ҷ=)|$:AUō: Ұ |.fpKLVK玝A{u<']'  Y4Ra…XR@ ǰ;Rc+P~f܀anOjܭw\:iAV e>}zcOMg>ιx= RZO(6;ۤOITmҼf4( GJ#}uoUQ>WT f>ѷOU:B)jNSםi>$IT%Q(K>m+"ѷ)᫈mügQ|irnjӷ_9[ L^Eo]Zotl>:8D5l~jn[TVٕ\EmmؙSKpK涋<50@v vu֒2_o_մUEDdfҭ#|%ymdko]^M.Svʬ&7ҧ:cw9pWIJU ]pԊdU&4]Ritz8xҎHω[ifQs',J5 0]s |8Ǒ2y?ǣTCY;ɀ;1}QMmJIBc83y IOhPҠV )Ѓ1ZˋD"1t͸+JΘb%Q-!Qwr=\r8 :xԺ<5NHծ 2P.B㐃;2Pc-:D#ű3!vhm A:S&kĀ e]:ZWt 2_}6ud143Jv _ve\CTF#|u%>CzFbŦ M 2CSN0PҰl㺓fm14ଯʹdSR8ү-m?JBA0%]2Ijs ֎ rSD!neȴQB{ꃨ\Ӵ,VCH嗌Ii܌AGg惤Yfk|`4+vh-7WX,ehXZ= zK -1iL>o!-EKQ[Kzz1 U0u^}a,WY5*#C1"@陷U2bC M **:MȕPDsȥӮ ;V_iXe&Qr40%PWq۷4r^5e^M,jSv;p\+۸mk*\C|=9oi5w8W4:Z4_oi^OIMy |= Z_Tp+IMSW^%" ߅La6 W \I`A4m@$P!rB`i,*`IB)G eyR +9nPRc0*H!ęqTIhMjseFē. f^[\n3$4 T=I:X=}b6uy^iK̦sw.z~iA?#&2}>Ry,ؕ)z >״pvoK9gqd -?Wďix|Ne+?%RP>T6MgyLݰuئ=R'׊=o1iҸT@@.קݾntdiq׍Kz0f`2Fup$k:4 ЎCK0$|$ PTif38C3-J_f "$IM!Q -U4`Q0%X( ¢κQ)PB cM{hDIHS\[VBB0H z͍D:LA&l YUo5L;I*~s:kYQ )VR]UF0I=?Hdi}n"<u&+iBm %&KV^ԃ<@l `TR*W! :`cjoYV+Oz.J8oqwVOCGp~gΣN~Q;9ŸmV9hz,ƅ?`M4; 1. 5 k*)uqih |p(=t>udѺ.b>>EС~ IdǗ̓uSO(Ʊ: .f ١t Y4zkMp-Eϡ$ c&A:4zjM-Ρ` Ic45jČ&ȖbPZ , DL Ge[ܜBq*e΅* [d)h6\(2bA);TU{x9?ܠJPA4*~eqR;!WP!TS :K${ҥ$A֏N$H-hWY$8M#s:8Ń~hDw2c4 fD c,>,+=F۹Efݥ]Ld+ݛFeޥ &&]2kY>xyCXS2j*Z_fPbA[43)eBWoE qYti tHɲ=/)|F4M-dȴׂKރt(Kϗ)|V4 ?rq|NCo7tק =^:t;Z4? 8k Qܥ-tzf\Z ]t\؟)b~׹\%BpKo6Qhh"#Z^rġ>EI)[P/GjNS,_#a9 Baҩs rG{hLJ8_8ffdhKQ+ӑg1Y}i,8CRSK@{#+z..9}3bI{$Wbdu/ ͖@ "YPϪb N5d9NF 10 :YHBV bNM7V0]۲C@L8Kq 樥{L~9,# bi"`ȅa8c5MSgʇҜeq_ֺ|9jİC6I?(Oeخ+I!PήcPvJ ѢV1.:Ȗ?Ћ_ix  JoŇ5Jd*l9C"kN%2|>xѡ3X"SSl$\thdЌgrDŋ6E@>Jd*+0VN92,Fv <2AT+x$zbA)UNvNVޤ0^n8@NPstI# cr-WNW6ijàaB!+F[uLuM=d>0dn+fw!k r=na" ykW'$hL{IkW1$h((lvfiA<ğ3c173]/qۈ3}' ߝ][a7}őɎA UWO״t˪ʊd.e2ju窖f<ۃ Jzn;*QgMCӼf/ ˂-=XRXݚ+[uYzx)W# b=#j49jn/=#0x@6:Sk*˖l.(А*$ʨ Aw9~m .vL8xRHs hd.Ns4mgܾ\?/wԝ8买}ޭ&Pv1 wRqTפ,S@mZ ( :cݰd1PY+aYtLMvnA?8Hg7ۢ_1M8pjx[+ӡ% :)*Ӂ$޴ $G2]EMӬ)`ǾEzul6S܂߬{8У)>6SsQFcjINR~7]#FW _`h=Ҧ 4ޚI̛z#ѼkI"K!@tcGziyӦ4%fpJM,F:ue¯6uUaH0U3T7u|E_֥& =gU˦/2m`a%ˠiܗT 08L.jkv8oS+,q_,DMchf˿O V9SjO ^y!6lM/#,НN~Oԟ˪?sΥ}2ѩtXBhiG>z.Qtӓ| }BDM'Xeӟ#sIZzut1*hndBnM KeSMMWW!1 D-PSDvW#C jp6qܕn، 9lNsoNeah*q2j졶ڇ!:0RMq$nudjq61GJ\Тa t(وJIɓIO5jYĚt<əzѾ94`RX-T+}dLؗa@֦)M5%9m°WzR[HlӬ]zn7j6[h`H~zy?gIV uCHoFÒ/'&W3;VyGWvVߔZ.uc^)N;y--kd͟`g+)jύXgNiAQTꭻ؎T- }JӠ{ oX"Ss|7o䍦qʋ@ި[1Ҡdp7F8 __ ĘrDD%iAߨ$v:UPI4w*酼2šM9 n"7fwvCQ7?r/ JivoPҐNk!z|% N*IdOu*94\\4o zTHC@o'eyr?bݗ|մVoIy/;RX~u6_\ŵy?%?ʟ4S>5Dw~%<J %uSWLuxG\(!O(=G`(ᓔO(Ii!j#Wl&24?B8NNv#MSkL!+̐Hx0G<)+(Fڧҁ&a 4ӡwX!DR5yHUC o욒jCSB os [#>L+J=L-B}<ӐQO#KyH 7}j`ic_$>u0]fRսO"kͽO/ylJ*' $PPb'{Ra@q!&1MqHҥި6p0f/F}7lF 3 h@%>&iP+ vS_pAM])q@NTѕ s]ڮkuTnI!2AM]V ]#>ftdg_1S.\6*ŽbtN$+'5I%kV^9 I;ʊ:'Q."O:Ï?f/rҶ C0<٦-|c۴"9 C5n}Qh1VBrQaɞ!R>tt7jzQBmL^Ñp4t/:8qjufD69f w9xaooÙ>vG[n#á%[á$ڈ0vɄ9B=Ga8tcKGcc~J X{ .{Gߧga`}t*|*zYc N!<–/VSO@ax/5Co1T%ciS_ṙH*’|.?f*44𥨙迷a!=Σ|=DZ\"V2$fjDz|#ЧzZ0{dЦR̿O8Xl_(WqTs>:Ȼ,m)*1Ԃc'g8E8kts;=ѓ+uأCK50Kc z}nS\L C6s GxqshTer۪{r ,M Msj칙P|.]9;d>$ةd)O2(r]Գ2,8~]zV&9j߯y@ypG9Qd?CCzTZψ؍;BL#?7U>q⩲;uOѵ9TOkFʩYx|l2MtNT.Sej2۫(~+qҬJhP=hGum[J 3۟wU`H L fm0zVWȰ ]u L26_5]kC8 o C-@W7P2YZrk ٮH3$0a$c?֜ByCuc)Lf72ݡnԋ)}=Pu_EDSRlѵ 襋!ӯmvmztO~+}~,UJ |JhA  M>q3[ܙ,:" |X?):$':ڙӻMI/bJhUzJ:Vagv=n^޾!&yUIHOh;ARxq~FI k&te@˯Zv$(}i'@t"W ӤY//V4(=.Debn!̫%{=) AGv[N@" WvzT‘A|9 dj(Ca9DDsdleB=CpR0W]H>-H9z\!fV+K֑\4 |%7+M<-w,՛rM <xNe(ޖaӵ/ nbD>YL:DTT-3\e\NV2b׻)sdjhuv>kjܭƧ'm*﷪xiIJݾ/-WLVzɞV. 2VUFfJbEUq ǔM ΐftQ#IB\1_ɉ܊*9?](;̚ rE%qw]U++=a]>Bt?(;.-SVWdC]37EAOgX~+ҋdDMUxml7S-[ ){*){zp,_6e'eF&eV&™/8oΡXK}Q"\6%{KlM-nŅ;liͷR \xozXK*vՏ#4%@HR\kD\ҸtU g* -M%) Jq-t4 -Mu^mޫM>Ǹ\%9seaj'.jimѢLhI ۆ.ޛ2΂x ?o,׹=뼷4%#3Y,wK򕌫U?פh ygĭ ¥}Myrknp)9evp{k@./N8ŀ'r¨+%G35'[+l)ğN_9Uy`\7~s? rr51P:BD(T55c)٠+Ɏ 8j56]@%pR4 6?&_ܪ*u͞ǟK|J*Uecj v\L9FV) 1r Mh nuüpۂ39 Ҷ=)|$:AUō: Ұ |.fpKLVK玝A{u<']'  Y4Ra…XR@ ǰ;Rc+P~f܀anOjܭw\:iAV e>}zcOMg>ιx= RZO(6;ۤOITmҼf4( GJ#}uoUQ>WT f>ѷOU:B)jNSםi>$IT%Q(K>m+"ѷ)᫈mügQ|irnjӷ_9[ L^Eo]ZotlMatrices/R2D10000/nd.1000.64.etreef.gz010064400020550007177000000321550654276030100176440ustar00clevecompmath000004000000065nd.1000.64.etreef]m㺎Uds-ٖG[X" >]%<,l3O?}9+~^{ܟ;e/~?m^kSϓ<~jg]>j?{G=[Usiw m6{ܿlG;Uۋ?9[fӦ=~lx-拭z־m=c-qnr߯=fkKz`ߏ\fCdzOO>-mD>Cyaضū$7ۣu_W+(IJ=yK<Іu纹>c}Zgikږ[=6'-vk`T759NW'{:Z_>juNwX;k3ӧt6(V]+gp߶yz派@s8[*uYxͲïh r|hЖk 4k^kĵ<lWǙO5p[3,B}1*py(~"pygqOoy~;po?^5q&Z-2-A8|ZT V דKWMSϺaӝ Pn7Ӽ[FiYb"s-S}jg^ :l0e2,ڏtc-"{[~| R' ڧv5'H#>2N}ey/ibMq҄LJwv@Oœ.B+^J\{/$^>ɉEw$tΗSD67gmTNT_-crS<%TG0A9~__E3dF/Wl؜5\i6Ow,\4+hYo |ׯ* d~D§0n5'sl^2@ IV07k!-iS_0?4)oHƃouKp<s?k8|p 7"e?3-XK84~䉱O=$/K4^W$,yh!K ~?V>? z-2x \pb/GK"*s%絯>NaBa.:axߍ X1O"O\7D nS!/.{W;}D1h_*{ fPp-v}\Sp@2d"Okp8@{|mN| eFQ0\LhP|,&qAn%@a zRd㯾4_1 ^\6~M)ra>v0 C#KF9e|^Y]\R]Sy;}l~`?GD+^}>PA~[tlhSj\;kVc\9mj_/?u~O׾.ğm1ט'L94*.2'q 9~ܼBſoǗNk&\6U:h|mc$Kў/U \VŜ[fБ( g7i}|%>t.ɝVq) ō+kY|rw7KQJǸ=JpBfn,2"BnZu%/AvӲ_囻e͈SnZ{hϾ[O0)[8=>e"`Ͷ"53'n\-b@ :Z1 ^,b;,+牄RvR0`"v0hdE#c_ah˾솑'Ia~ <?)˸ JH5ϸ鋬;҅ɨ9$f"KX?=LU0>}#k<1<'ግsM6kL4kk) [,l$N,3> 2H!~Ar&p\D/&x{5@EM>K&E^˩>im3 gpO&'1%)X92)`T0Y\r,0L 0jLі:ˌ`RyaF|k1GhX,r7lX m6ZC)[[v_agnǂ'0tnDo &D2{#{L@ƾ{Q|6#_`H\dap]yil,%huȀUYJrr_7AaFin .ާ`@Z̄0Fo]L{2lh^63}qV3lyI݇9W(ٖ[6Td-#i.Q8jӆ̃ !FsZŁ~UxxXvتPbidyJ L>ۮ B24gj Y,q0bo, M7 )|S,h"aCor˯Lq|E~jur\H,1nޗpDpkŸ^"1@0C&wI$.olEȼ4&eAJ"G}}SޒnP9ed;Uϯ"~+ 7:##{xƤH ^nkhQ![nq 0]:G#(oJь=I>̒ ۭ]\}"%zL} T?}LJf?ÄF'2A0MGA? A7UG!X*=8 .°٨BU'j¯C#"*dݔXUn}n2ֹڮAV5コV [K1ioآ^x'Y]"׀O ]Uke۾b,2(4] KrYDN g |Q聺䨫AV`A1]/Z7moP& 8 z1܅ζGd$9`*k o|T=) 6*5HXN>8 X_ktP7} qd!̥7k*3}E?824Qc,[K}^E8/@0̛G\ȸlI@|34PA2fu^SljI՘m,c|Ic[==.R$xb3fCm"GMTcB@cS6c?K"4rks=,d#|3C^>Ҏ/m]6 h-:`Px9zs t Ύ;+ t-.ɋe:>dž"uZ}Co7m uƌrXw A\0%6 q|BxM nʷauW*`_ʳ:B1reWz"!DavF'"h+bS+0)"3pܥ #tӴtEJ0ֈࡓj.晦͍R=_X%?3muJR[Q OB,l27,1ZCw'.CiF9 [ԈrLʭ.6WDy%x7"&2.40c:a@]$9>ThNsԙ IEbs) ` ag8e2(u mwü>2)),c@扸B/x_1T[o9r 6cudC*A|q!z}9u崆I!*NL ,s"tv,Z;{Y#42C 3\.:΅<)qOa\2Y7lm_qH bWe/l| VfsIbq?w< Kz xUʀr .B%|yh ZJ/若Fz #ubY1a}8Ң79풧e9}PJxe6w҈j$+[3sG Ш (TT]% SƎIl%ʔ B,Bbr_ymsk*Xo_8_dȼ6To $(4d (6#B)Z yڕDxUZ0Dn'l{e?impyЇs)e1 3+E ׁWH,H*f=U} #諃S){|3Nqޤ9La=$KG9Y5/(*7 Ah{E4F`tS40D=tpƙ|J0ͳf{S*2B v-y\'lu%~@K# fѤUlN]O@8Csހ[am*&K"|_T+lTYB% 0xXF,!fRutG~e8N!8#%x(崣LʎP=J!4" 06l_X8rCL)d\"d%DI9<vf,gf{ۃ7_єtl'h +7lڌ-!ul,<t ZdڐJ\h&d:\WJer3>l ěgc c)wпJZ?1җ {;$(/*(Tϐ1P6z5va1f70V sL#*A)fQ;׃Byki}}NѺHWt02rax@z*zsCi"ؕiR(ᑅ J8I8ӎ]0vG2sƒlI%s+#7 ] |*2`^La5xlIy@x0*X{E1Mr K6ټy9[%:ر;(#ҍ~|ٓ%džp3h!! q a"ƻB&!JcJ?.fԂG)$Y@w$'yfTWuЙ3k]ى oSEI^ 8+or<#Na3*P+T $tcKrz!DZpr٦FP>_:B \ߋ1U**fJ ( 7VdmFmkf4ǐ+,Йsz5t>h;GD50mab 38L- q`ٜa0 /'!?ӌ=C 2~OWHIfO?u֝¸{X)DGH졩MoeJ"E{䮑833GH =y?_.ʿ&J2=HVrSݪ3} Uڌr=[(N|.g rL:+$';`#rU,J,(8(;>, 1Y TV&+p\`z0* OJo3e`Rk%H!+RC)%`DWYJu.hN6#kr zt  &Af b&F2\į95Lr ~0(x ;41eazִqf琽ȳW44_bQ +o]ҸL@^0aR:,)0*#\W-:P$"h }^XȦcʰ7w0J֐sa 5g,]X88BW%k[JÃ<e4e-W S\ 7A$! aIz*]yQ?ݶ3^*UF]#*\ % 6v|aDV C'ۼ`bʞCۘQ܊3*\VټE!RZy1DWf=J+["8Hj*tqA>JuՓ#_HUO`IT#TV*I\TհESr{plTtT} UW`26?`t0P/T!;UMVʃ;ϥZߵEGHL#[&;-6]s`"=]lh"-\Jhz]1,D9_kst|X ?$e\ , M0(ڤ@rL}/m\JxC¾Ub섲IFY`[ Px<ψB@JZwpUi5RNݸ 4a9C X2 ͺM/u"5O6$~ pGiTBCՄLfEN#dm"ɥ4U]fU8P*۱R34ʏN$4qfXI1MZ8\-Zo8hS\Э`WB[vг9JC#9Tf;%ӇUl U,fpukU|B>k: |.Ph{//|{dtevַhe;X>e.ѥJQg/?{E8UHRkiH,]gkKiELSY=yIY%!)z_+KGZ%|+ ]{=77;^"h;@h"ICQ9Y3x)c)״]e%f]%IJq1:E2]dyt+/%迧zRwZJ%(_*\% >IҠ7PTUQSeߏ"M(9Ƹz6eӖGL- D,!bdFc,F2Lҗ_uV!)ggG|G:\9?L;~+kqXq"$b]|l:&tXBIv}F{zŠդQ%hD pvo%,I"$gNG@j!vCk} 83+,y=9=v^ǖH+llNdFVe]j y63j%(;ǠH:*Foc&,v݄dJzQ_YnuKIn8Of,,njR b3 mjiOjsIڱ= o=,]oQݬl!$hXef(/uU']( (͵nEFҿgz(^U?H_ZШ&$jII)`r): C'`PiaiRN6ZՂOqjw+o+#5GnҀ Ѵޕfp@5_W*A*Re:2WvZ Ej[8kN5e^h0۠Xo*2!v2VkZ)s. |`Tԭ%' :d8 ` ~:|fH%f\y.*.-GcW= Y{C`tI؛${\laj[ѭq&:$M}&WwVQup<*h=,HlKrǻ.^ay GUKD#w$!:VbgMG$>k622бguݎT9Si2Ͷ(RI%_%&c X R#B\'6RB*OGZWBjvpt+ܫ*voM&4Cӻ_C(ޗtsb$iNjLC9{?AsfI"Bb,/t+ ?+\#KA:[ct ~6%E/9َPu(zisRdEfqD 48"hZпGbϩpɣp{RI / \y!ӎeh*<+3CFnmVdnvgцxvJO Xk[į(Y v\aFԣޜΥuKkxv_gnbFRQ񢼚wb)]{9Z"y֛˴7D^uZxn*_5 ]^-Tl(v uwYw2 Y'9!ۉUL+h7\2ߗk>K۫WgW)=Pt{?su7_u蒐EU&Dm⎩;}vHetfn͕wi2QORJ6O&O_M7NR&&~/w> q/C7[e? hlt9dKgg7\m1'S^{-삓ie\ow*lvZS>%y멸fyWG+ȹ󎞣x L%;s>#R;DgX6-(aB:?5CP6E??Ğ|dzP?_-VnxnSW~veiOӿ|si=sU#PD,RSL}HͮF+A}cA{>ъR\gvASl+bժȬ ϯ{6(u_uݓsw7HEvS]7 6I߿ԀӪK';lKr2\ 8 *3B37`.)dxGl3ne,*XsH+ĝ,;e1v. `.e$S) t'GKHuktgXityI0a$ۧ4 PssݯE%Mݸec@/R )GG \/TfQe"5yS>d([@[F: S6hhYM UL(:wB|d,`½ϏqG%ZA^x+Pڰ\]4-p, "PҮl=3ibM Noģ _,WM!VQfU.sHQhG/RTy6%9dZxa7ҭ܊êci+b)TQ.l1ד.Bgv^aSY7 m(l6䕣{MHo|F*Y{:A%,C:~6c9}5ӗx6uk3U$kv~ѳ5UX:}O3u#w~Matrices/R3D4096/004275500020550007177000000000000653602325000145615ustar00clevecompmath00000400000006Matrices/R3D4096/grid.coordsf.gz010064400020550007177000001024250653602325000175050ustar00clevecompmath00000400000006|2grid.coordsf]I*o61WjDx~?g.w7k>x?|`0wO&g0t2<ߑU}|~|:}z0uۿꯛznu4_D~z;)1%s8>L?UۥLՏ)/$S_i o^U6Mi^ c2>w_&9tcs]pk". ~渗pcn#q5I\CUำ1_DgFߍHGaVO_ח-IيMfô.G1&/AmVh"Y$lG+@@fF@f`>z(mhFR|]gDa/FO^|%wc-93|Wu%~̤W" @-uf$H4WŗzX=#p"OgxpZ@TO?1\mi*Ҥ Wz[4rjj޶shkƕޅۍuj'ujkw^pc-)m v5+`\հ>'絥7kxߏ ϙ \o:hf WY,DmU6V,ZoقF٢M\Tm-oʷ i3}3Y[Q-|[tz PZnܧw ad|&HOp26v,.[93L %w//MF|] !/{,G1svP\Odˡ2-1ʧxO+nc_+z h w4jϗczs5TuEzu=MkU 0dď&W>ךnGCm+w\[B4)2?]ȣȰ-E6oc$v>u["i1Jmk"WFF+zڧ/8-oqj}()+w.H;7jd7Fѫ~͹I_osNì~F@ ovA:_E-iB-ﯷBmv$}ڒU[2}p{1K{Wɥc2A6ԫ&6q٬f'B\qw\1ܝ0)Aİz#2rK}mwg-m{tL%psVѮI1tO'oS|\8L,w1(˯~4{ #҆WU#kl`qn=T#ILMD gE1fElQv'xZwZvabj5xT/pb`-}B.vT̽9 o3sIP~{{ꊧa^$s>[~ pZZQL?6njd۸鑽\ *"6z"& ׁNB,iAGOk1`(FSĬub] EWv{r[u¿ _F:ôq<&N],? 1+aotMOJsbj>ޚeY_(F_ueN7-n2(zU}Y|z掬Lv .{U_qWUog+=~IPZy> nhYj~`U~6۵V¯ԏ)/SorfO&kWeVNY s\6MRz(|O#=RɦڕV =v\=pcԮN#߬`X؋QH3eqL}+cN_|Lc$ޯ܁ Fzͪ)%[U"QO|45p'ae=wσN1_޽HΐtM=E`4 "Frŧ&qia[_72t4ϭ+b-[ŗ (`ˣ4!9tkVݪBK'k wp/p n(ŨX0>lyP@Nynk?dUK67͋"Jncp2#+O&1HߝNŏ5|i'NV琅L$[Oj36nG ,NrNOM4-g2}tnCE'i鉸ͪ'Pb~kd. H. HۖHۆHG}0 aGiՖHDF @f@vI9 m @/3 uÊlmSG!ق놋2v2ENNֺaa6,}0C*릥i ]o> ux.q93BA4\ NAa t5+NQ5,3w&g7锻ʈYifu: f)ndu@=YXL8zfzͪ8gz5Tp_50jCSFi0\]ԦۊLވ&1hzɚ)pz/՗ e (JLI˾z9NJ\>Bv3 }7 Ȏu9|픅^UvB^ÌFimռQz\,d{,]X8R23ҟsFw,8l:S0*Jz^o&R0NmDP*zcJt_oʠeUPXi9uΨq$qyQqfVK%etO젴ʬ揌ڕxΐ )7 }t /MgA\ӫZ qб$J/j+IWgo<Pvjȧ;i|5R677Wђ!dol!PU- hTcYB?g-sѬ4|Z vo6 4)Lұ6'.ʐH7$UɭcMCu׎׷8=1 j69rqz"A'UsGW6ԳlMV7hS /`-zMxY'S ώMLN2be9\9'9#SFO/$ͭn }em-F<>aaٶY^wUh(CI6vJOJx@72R Lo!O#~>G1*rGVV7<=0x1A ' va _4ܞY6)Ga-j1CQIU[l9څҎgF 7{26# L^GP4a8ƽ@ =2/5[u(vdWSf3sʊ:e˭{I^֮FR>O.v}ܽܟ\Tf(^ /Vk@VkGj-(thyk8<郹GUt.ҏ)>")I8فklY"des{RxlX1(1X:d:=R[\_aV}xVctdp'MZ-y:o y, 7i͛aR΂QڌCHg+ȫZaW)hH1yue["L{e&& :ZLKm{Y= u>Hiz ו[40ֻ'5SdM'mzO~J0rRۧG#|ɖin#p6r';pSk䀧H<}ƱʧQH4N=ͬnTGhd> w@{/ekStu#i`Oo5nZՑ+[L;L~a\ dæۖG= 24דLF9驰*ct>Cy߄= e2M uNPO \xG jB=AXQ-WS^LxƧ>L:(|V@Nxz6\plU~ 1OeQd"QO+};*=50"%-8/zȧQ6l^UIm>ʐ=Wt8;$]::S `zJ}bK Br&Y^Z!bS [Òbv$h)jH,oMDe$E*zcX=0hap 6"ˏCd`TDx\ RϺpj aNX7m#alXV%ݬpa*/#[Q2O%+d^jJ='TyˬΠi񨋈%V}YgQ>zϐG./.I@TIxe\}Rrt_FY ʞ~"{d{b^dGhdw=8F=B̝zH?f58ف4TC6V35oq9')/&:@z%zh=NPws&bmbb"͝;B8aG̝dArZjk"W6|޴;!3io$^=x&FFhKn$<ʭ@!J `ZP94@0k&;pQ̲F 6J郹 y<^8Hwn+YWthå36Ma_5BejԆG ~i):"tF^r=B}eN{dY:u`_Y !X$яB5+beM2-5oe:N22Mc|d1=#dPLoދ]A?S&jPA߰ }#C?١>Ni'89k* !@<ܝ! Ŧ|(tʺ˥{Ŭ̩3.zn@S':%Sz;qBy(̻\ob=)gtzf!o<i\/\9qN}H X^ʦXAÒ@~kNf<@3(޽5T8Rf+Ɓ֎2( 4&TYAr&ڻ饬\Hu'.J Z0GAKIFa qJvl)mqwB+;M=?ځhPn*#lb |KrTIM1"( - ;ez)*z( @eREI+STqH0M"ԏ0 YepAh)77FK\#!;УV^Lh#iBz4G5@~V7cC?32򆼅R}cVC Wajhq\QJt㪌Ձi8(Qy Y$qXW_RD7p5L@͂6::IjdUTiFF`524c%Ă]F쫪:}UqfbK1_RcizUKA}}?GPC#NCtFb 8ԾdpUJ/Mbx6PmԄHebJӡlC#Tr]#bXO0#\ͪ*hJ 41*w1rk-T PA}U RTMf(3XHjfta,K.UAbI$S J U&Y+A,${xeQ{jsJ uk|amXIKc$aOBUJ U0 bFar_[a2 X~LV5ӛ̲HutP@ ?IhPI5P}p.7ipl Rm=hS-A3(ԷKSm=3oҧ ڙTee!=>Y㐇^?fGZ(ЃWAi{fЊEq"={|T? 塚vB村 v&ݱ7s†f)>HnacoR 5( b4(-rabR^"CuN*7I\xnj%!8#e|߲V8 33z|{0q=Wʮ GT_Z. @WMEE ц}h|ySݙw 7u0 [ /Oo1Fp v.FYi,:]D3bw53Z:j! ~n/@LUOJ:1em'i썉=Qٺ=u/ݪ/ @e4>Q-dL+.%ٺɵGN;Szr%ǮzYp6z6A~nL ),-z0JIE90pXrLnvE~&HݕVYlVn_{W7rdh2{"b ƙ 6k޼0OߥLqxKCZ6<%w2R4E%7 13q%Y 6>&+ 'V6pn#9 y3x#˧S`XKp p Kt+I }0;JXqu+gi E wR(qf20Z30q.v˃Z 6i^V)yv!/pˌZ5w52 ę2Q=Gg`qKbn_#kv8ټnxL0;eİnI@sF=q&L4K_ce 3dfnJ ~{(lIMnKAi2nX&I呗YEt+ ( C'%"g~rå4>ZF&(Цr.RxtO lZNәXdYCFTEw,}&8sGp`wʧSmL\=9Bx43F0fLnL6,hQ(:;+UQ5/p ##ᚬc#Z[Bbr423תUp8AO! z8)&]za %-쾲]JZ.K6>͈_glh}BM&f䉾n?daXdoȸEh E}ܮ%? gch]\:Óyi ?Eg gND3 8cNvu:kzҖفq6aL1x3[S$~"D̀M#m w[n#))4BJ3(== WQ7&zh!S,(s0}iK|T 6=33A?m{ʺ@D93B6ßu |jgsEڦu3@H_7j}V<(H|\.\]6Yq;CldIYkNFVR@|=p/qLjK;d'@j: npDqk3½]tX)~>?bzs"dEu빬OL4xF߬3"Lړ X1VR Ik4Ϛ[Y(Z ~G|n>Q"+MV{@b`^Mt=:eB`C;>\~V-;Y<(Ƕ$܏^EmKkP!ҘeՅ E7*Th UOH"x|dwezqQjDwYW <`zFKqHo\d.=@4 ٹʭ*LD`Zmg[u t`O/Oc Hpc n\eT4…Nox΁x֔L^bctZaȘqWcNͰ,/rl Pw̛-^ǢO<=vĴsXz wo6F| =@ ! 0[uZ_d^l rUM8O,mH@oU4pl)\C3}ݳ~ّ؂Jbtֵ1A\E~bXNjv[WhI1kPd a/c"z&N٦j!h-w_O.5T#'N.5T 7N.v=8%"zlxaFq򘄝V2J43y98Dd{.tfijCj' 4Jik EOUY~=t@XlxI0 n7){:NpQw0h`apJO 3s[&=r<:Ǧ䝕B+>v =}tz끙7 wdgW{JĿZһkMՈa$J!G`ti΁+BGA=ݫnp  =5>yW neOV*{NYX#zivɸWFψaKs Hك2o+HAYcŪ1n8N=y>۴t_۠7F8d\L/bdfjȧ-EC5pťխݟm#Q9ƕ_}e%_݆n94^(K0SJ!8 'o #Ts~gS.KI6 I/mcaՑIGDK@i8N*ft,N0xY겑uO>tYkdu~u˃lN>]P Wyﳉ2MJ*mrO_-Q*F.<H1EoIWL结Sd߻ž^ub3#ȑVrǵDЁ>{ji.R >Z^ +S)PQ#0zJ=:# [] dѿP KR E\sq[&{ʁT"6j 8>.]DS4(]\`nHoEʛU"05[*jGbUս2ٴ:ehM̖qjjc%C-MTPQ;:PC_wQ #J(V%)*?Px#u%fx!׽!Ҫt%}t%׽*i&/gGpUdUIPxwUnt%]B݉BCVfP/~5"_Y:و7=H(mjDNOG ?&Pl? 5iœK=ᰋ#ҢE o?s.J#*uF?!Q/J'J RJ'ԧ?BQpٷR:#HRmmdе~4%fF_7=/U}kO=exƊjԞ.Qskȃd%+3W$ߤb_j#dԡߤUA?錄P cz brJ&Ժ `LNɄRUGBLN~RU{zhVH n*Oj%kӄq\%I\3 *!Oa_%J}xykpp+!O! '!ot8u+6`FIXSg+Mj6{up( kj~{1PH) kjDI jDKԶQš @65Q7c!5ۜ`OIX6xӦ6hӦ6n`D@϶F1AMjjo/v5$h荒&iˆG-Mb e0jDIM kWg ȦI-'*mK&2~`pTjݤ}Tmʴ^:#R)j6466eNxn\)gh_,U4m Vg?u7 pgO[rUhlT%W}>bЩ:znaCۤO?F}" $Nyh=TSz U2m FfڸjTj&e` F༊u!{NZ}=+d-p%TꤝH^u4]OOU'ӶufzGXJ1md(A8eQ w1rv@(qi@\gL+L+3^tT3#9Iz*6!+RWY&d%BJ!h*JZ#B.f)g\ [RF-R3Eԗ+MJ@]JRDcVDRJ@5F&hW"QAi*VrĔAiYXA5$k+Ůb^L6鮈Vۻ6q2^}5z0XMRCk̿ +; *q-6q`lK)=]i)GqG tP\si:=P2]I9HF?@ݧ'ɣj |tTʕ} @\y M^ }SoؠKhqrEB6+A)LV48-IhU^uV*\S cl']n2JR45w`? | ]v辇[*e8"Jl,՗B@ʁD2ߤ"8Ipt. Q2$c1|>d(H$o˧G ^B87gi6*-bt!vOJ(9?UA?uX\Ks#!o-]2ݞ(4QX7(\_ps -|SQ nhy0 -ӃDRX1۬M$uSA] TgRY$ vqa8}/}Z6i˄ ^d-A1{@n:}Zq*{vm(Hm5~$%Ȯݒ/駢(#qGy-8Ux۸ϫ/OER$xih8 o_MJIͪ/3φ]_"J+" f (#I1Ϩ8G[.MH͍3JUt Ymp~#\kӶ~L*}k99}@G\O16TtiqW\ɽk1y-y(}7 ҐO;L 匰k5)͟ OG,U5$$B>J"i~]7;$Ujo~D#۶`D4o\5D=|*m%RͯU QFy)Qi:Y@< XXdҒ~Ly\Џi>YTI V w;2ʧ+U"12\ JAg-D1TTz&ֆ!iNCQ$*IeUӳA( xfUigNAX@igN +"*Z9E) =i[ qp$պk[YdBIBoPdB^[VA61pp*JUP#Ѻ`n#[rĤ0fPR=8BCreG:fL$$H9&ie*9b#ȕ;&[ nepSnh[|9T/fJiuza Lz3Zx6ϫi km/2(V,2KՃ+-PbJZWy5YM2,bi[)N˫!H㷑`^KZMo^Ĺ+>"OJ+08ݳLj%7̛iܔ<F8Dӧ-8N2RnF}[5MJfy .=LM-y/M(KT[sK`#oYTti|+5׹54+v)ڹ jvkimyzUTmV=-bЪKvh/:;vb u%$ܺ{=={l3Im%3\Mh8bXg2a-kk(buE:#poxvHml3PY‚&`Ul".2u~~PCu(.C|1v(>}b9Ҳ.u(. Z z^%Zi Յ4J AgAvіÞRűrxKQWU$1bgy~ՉʀKebKҳe!Qm@4X3z|yzzF9J̐jg<yp{q^~CSUU GRdps&L1q^zzx]2YO7h&愚49gZ︞^T#n+EG[} "f Z4f@QGzZz.FbQaދhUU.Ux_7hŚg<& X>@MFoHGt;JeaȔjb=4<=MЫd,N+1NӠ:*p^P>F&H;<ac5Fӈ˧ӬOKܯzP :nrKU a< t.hAlPiPBf\~t}nZ @5扺l6Gi0gmd ΃n1=:g#d5{ͥSF\MJtr-α+BjM{12,E2³tЭycmh(Ȱ6(ЙNU]1] L` YȬsPG}m3 +#AN.Mep-6[E S&F p]Y6P<]k{n/Z̃Q,E, gym"g܎V|t׼19fQl;adYmV 撋~*|c εDPnfx4MI^r~릕=469ܪö$yqi7Fw?mY@4x]fPd:Ren.B&΃H49﹜ r3oN`c=lO4a/K,Z7p8*Egaz{fUԎLߛQ;2L/i1 Wgow_#@Yk׿TEZ]߭Ǚrt(0mc:5׿b|vdd\^M#ZvrU̯HtTދ<"a\aGJPղc7[)oVɎ$=qg F*TVAJ!HkxoBb*BO bH,nϨ,Lg3UM10\jcR!2_1p@vl#qU<,* io) }d 6Jnft Xq'3:*0LR?oUD%#d 5`JWL^-ق} 1qdc{oG&;*&TwHHo5Q^ڻcJbɞj|L L b;&[ǁWm#,=qHqҽ2t3{eW~my`<2th#Оӹ{NrcȬC2ؐr6Do7MeFd>J.䔻@Vnc]廐Bxw}x"\pCB Z.*!~Bѫ#WM}I}? 0c2'a_tɠok#*p@S =yHc7`3=* GiH uO_*zbd(s ?8 7*I_#0ƆTOT[2Ag-= d!t3#~*N\#aݲrT|OòoTy2[{&*B2ق:C OCmј@~7 d]}ry_w7A^lCd>k @݆fJotIw-p0e?ʪ %+28`Ũ~}_0_Otbi;:ę[^c\VwXb;yi{_,U3 8S9O5iE\|Έ"uK6Yu9[bًЭK+RKsF=ދxJ\s"/i n%ެȿ^U'/_cW/pi }!8v)V|ug u5[>FkTG "ۨVG5M"p9yO1L)=I~.R* G-oa8z+8#{60w3p Zv&hf+(e[Y!GjCܴSU1@z)7%: r>d퐕!ǜY<3]- G_b8{x) l X7ToY!J<䦙 S7#_.@V%LȞ~;Y j-gb-lZ[H1,ݟJ~usf"D9e]D+UB ;Y2A#sPl,;,8^U>۔ < 3t)P Zy՝,Xd3} 2] ӻT[ưgtMբnpVG0x+*-lod{ƥ}9 קq3n1 {/>f}LW=\#R 0x@d2^ѸKרЬϭ;B'3!; ޜ27!9!3?rK0YKp+&bVmYxtr&2|N^i7#+\lY_w@ ~-bNz;*v p mk}P25eb3Is??t>'oLͲpWe4gJ gIMy Wcm%Z^ u3O1Y,9H9g.(0+ fV Oh`_pŗc62 ]VYH^aVG;o.ٰ{K=s5TCĕkE&2̑"N.e}6"sen (F7(Nzik5:Rog `D#cQcwvݐ/c,,액zcf^V>r*Xjzyޅ]y}~\ͼ}ܦCv( ^iT?+ @ǃlJ(psI=@eG>f~]/SARȣ,g|< )3u!\-y$EҸx}23pstUb(КR7f3KzhPa=vƥsҽ-:L^UQiܺ(V( W7i\FA WjuC֖;As5|ztE"eUU|4_hyD/~ nw{%3x6XRL|ݸbxzjz{Vyy]+|eg1E@ޮ~\Ʃ-EhP?fDjᒗiJ:K9nvP5mܫ„КnV*d|]hvϏ m VVPV{;|qp=-n2[t:$ S c.X$@fmbn#P̓, h5σ{um= pV%QZ8 m>mL᪜PȬRNFڟidafXWkÂ83϶<,8u Ϛ$Li;̪f/_y-4Toxh~/i12bdJ kn-sQY{)W{kI8}H`,Zs3(,/fG vE Y窗'W +G9\LS_jD|Ge膧>jӬ\Kψͪ񲶓;E)P7pF(ӹ4yNY U[J8M>79{+]Nv~ZHwuM)Žj8@Rʂn=b w7c)x s P;kQCY%KO4CܽfJN!3]J <#K'9J3}vPt fz$yr/x%'0j"QJ I\|$SWRН@Xtri5(V @Pz5Ź>myUs(5s)Q$jk5l8?In3@km~O7rI:TO| j-8.EuA6f j;FP2vl0lgt?(&Q*N&{[/Rir|YkftrTJc'K0AXg ,*qlJ#_Fe!b^q9q6Ӹp{g{ØƐ9X^)JSt@nWe( OmCU^%+c5`23NHY;08cb= ICAd$vdH?*YL> b ,w 2&axFrFumI% 1N{`J`<)& U=gdž pGlw"^KNhϫ(tLF 4UHtu{\* L(fXU:UPhD!PR,SoG1ˑ|##S<2i&zȩg(,rR+̏b1(= ٩{PbK]n?kC.n^Gf( wrQGQXO^a'9+nu Uŭxq Kh~><]LB Pm/gPj6Tz1 *EFBy; W0:G['l= *OHFˆ2ca 3X偉?)=BdZln&64Άa(/R W2Ɩ %;Xer mݦ BT*Lr~iA] %XG!Ԛ* ntQQgw,HWql_+=ce_f`UlbU3j?"8r#v%PH4CЕ+) =yhPa̹rLYpUMI.X233ҲNqS`l:^NS6ߣK4Louւ49V@UZSFT54AWe0sƖZ"0U5ڸc*|Uoʆ#ڻcq`HVLT8izu,EV OTz )F6NjϠa&*YZڡ;'vhV#i V&0Sq1:_,WTnFTC1Pʩ4͊PǞlxF`PWTK9#>۬^2CU&mE$Q K OF$QL[㣺(oK'CNߦ$tլic1Ҹao5|=8q+z+C^gOxXp 6d(rB/; Vs|)]j֡Q 0xI&wEGos^=X)`ྱ`3,RwTamRwO Z+09F,pI`C{SIP:])w{A-*tPP]D*i?xY`/S] 0^uCemu@0Ju`dӲ٬k]uןr7WVxIL5CW\c}c#euCK EyZsp1ZOa(a|r'yP>Pai\g},r2%BfrF`k=Fsx+SZn.n߮D!nbKj5;r!- \iz=2herrXclt˒|y(#VS 'W{Д=Beѷ2b$T ?L nVceRߋxu!n2}r36I'%uA~pep@SaW KV|&g2oڲz`g@FzX&BS0X@BnX{~>u_xdHļSE M5U ݂ H((N:eCe ue˧Ӎ{}va5,ź+ȧ 6X!v*1xz5C0a:Q Ϸ eQ^h&>{O/Z2") j,%߫} _Ʉ~') }u Ziꪯ~x_b ^MR X .J Ogb󁋷ztW}RB!bO+ߪh]QOAlup~d Af ~O& ,،wWu9fV>MP][:{q}*v븮R^ t[MU]Y<t6@ݓ#~y(H\YԭZ2qgn WY''%~{us24> *ON]s=ifv΅kMɧoh>|i<+dRLrbu ڧut> oCѮy>t{+P qxG\;g, YadUpB I[Mז5(Doyw%AOܴ){ WMy/,FO]eN}bcOOFQDLn}XN.>,8,o$YvѹHLeM0n7ʙMߥ[zVQ=1m tۛ& yO-5$_N.f6zqBRU!`}cĹ"mpװ9ӻhArz&42Ӗ!oC?2x52F [zƕmHl6WW![+0_oK]ҏu\6tţ߃ NqYcHbda/ J<֟r}ͮ2#,y#~̴r4,k C5 2־'(շpqmy(ţfk_V %Zdw܀69ɛ ^}_ac'Z#J'7VS:glE-N\OϾȧS;qL}]fp_ (Dk `nFUxS׻{[]ݱlTܽڻc3 fXs cw9Epp/嫆W&(%I#;Uo*tRӒ3SJ~Lud$MW5' (OʯXgvPT30@Lo IEמFfɣ[m$ c=Eд?3 %Y(֜y5Zqg\|PhjUozuT†xKxu*'b7FHy]rX[dH#OXkI}\mhn2\'gs'tU tUin%5ZPMŖIXlM7w):t_<\P;$Jl> :B:B*3TW2@ GV:Q3 # $E,.{{i7+2M}+{{H'p2s Mi#!:4skA F?ji&7Z`w ]÷|-5|g|w]|W=|w]|W绂4}$廆o[k7 绂{+ 绂{iH=5|w ]÷|-o=|w]|W=|w]|W=$]÷|-5|w o -ߴRV 7|+ -ߴ~7iHo&VSi?|?7?#w~;|GMG{+ 绂~~;|G?#w4}$ 绂{+~7?#w~;|GMG{+ 绂þ|G7?#w$8]|W=|w?#w~;|G?iH|w]|W-W嘯^x~{yG~Nf;O' y\2g ~7x ~7` nȜ7 7x 7 ~sF~#s7 ~7x ^~ F~7 bn7x 7x .n~7[|#sFFFFFFFFuV"[|oW12G ~7x ~7dn~7`.Un7x 7x .y7 .y#s7 ~7x ^~KF7 ~ Fk;7 7x g nK12G ~7x ~7dn~78g?+~W~#G] i:ȿ+~?·Wr\W:2 Gy#<{F=#OYG3D)3|_g3 Gy#>M_gu[g>r"|d}}䞑g>r3|_g34}m}䞑=#?|9{F=#}}䞑g>ruV{F~o#Tk{F=#}}䞑g>r3|_gi:=#?{F~#s#<{F=#}}䞑ߧn#GA̒3 Gy#<{F~3|[gI>2g>r3|_g3 G}>rm}䞑!Ȝ=#}}䞑g>r3|_gi:=#?"o83|_-B7|_-B7|_-B7|_-B~!FbځG>#|_y`<0Gy>3|[y`YP<0Gy#<F~<0 Gy&#s#<F#}}䁑n#<÷F#}}䁑G>#|_y`i:#m}䁑_<F#}}䁑G>uVF=#Ct+#C}$?G"<?G"PC}$MYG*>R eڎ{F* g{F* guV-#5|H 2RmGFT=#|H3RT=#|H3i:[Fjeok#{F* g{F* g4}-#5|H 2R÷ Q=#|H3RT=#|H3Rsꖑeo[F}7- gw{F}ouVn-#[{F}7 g߷߿MY2ۿ?·Ws{F}?7 gs6M_guȿ2_ߠ g7h {F}7ߠ4}-#A#|ȿoކ/s6g{ !ٜ"93[=g}{SkFGF"H#~`$D?0i:{F* gj##~`$D?0F"H4}=#|H3RTCA?0F"H#~`$kꞑ g{Fڡ H#~`$D?0F5M_guH3RT}5WFj4~FC j4~FCi:j4W)M{Fk=#?gڟ3|}i:[Fk>]Bڟ3|}g 3r_s2r_e*o{Fk=#?gڟ3|}ڟ-#?7|c 3r_s9{Fk>|o#?gڟ3|}g 3r_e|}L9{Fk=#?gڟ-#?[Fk}g 3r_s9|o2r_wS7Fk=#?gڟ3|}g|}ڟ?×: -B#"چ!ק7ߦ~>E"=#?gڟ3m~` ?0r[}ꞑڟ=#?9Fnk#?gڟuV|m~` ?0r[s9|g|m폆ok#?gڟ3m~`4}=#?{F]&)\  +G9\LS_jD|Ge膧>jӬ\Kψͪ񲶓;E)P7pF(ӹ4yNY U[J8M>79{+]Nv~ZHwuM)Žj8@Rʂn=b w7cMatrices/R3D4096/orig0.graphf.gz010064400020550007177000003312750653602325000174170ustar00clevecompmath00000400000006|2orig0.graphf|Y8Dy .XSgT˔Tges 責zl?oYwǹe_#iϙ~?ߟ?-P6){k~Ɵ_/?/?Z^쥟ofu!W~~oJ_}q>N8?*Z~h{<2(D៝ާ+mkzOo/^EյH|Sj|\W>;>4>?I M?ĒwPsI?';sFSZ<77>?Jޒ׳=U\"}U|*Z.sZwo]ӳ.܏p 'oM_,3oY{;K9{2X1K=>/} ڴ|N{[~lywgzc{>8麮xĵ)2Myz~_}O?Ǽ7#_@9.S\ǿDsKy—X8;?o`>|%ۼbq1[jY׾Pʴ ۦW:1z ̛H 'LgeO~_rJ6Xu[bwgf%ksU=\c#FB)˒?渔w76r{qsz}c+*uk~!<>|sxNPwu\{t}B#K&sG4o׻ojz|kz=qH7{1}%~1}s/g==7A5c~E rb~~!n}z p(V)-x/(R/zKiM#;G8UYeĻ|sLbݷ}xgz~N囇ud|߾At̐ZiA{/:'j\Og^tsئ<25q+kszg>;O >tK2\J3HWb\2=~Ng?O\Eh:g}W:wcqx~W_w}sM_ɜź՟cz꿼g 5~LgQU2([[_=|?[ަsJ#b *o-6o/ z[:V2ȗU d=-ރ;mZS|}ٕO_d,9幧]S9+w|7yYdϽ>scȳLWczߣAu]9LsDv<^KYM9ߧK29LF]=WI5Ⱦ딢GmɅ9EiMpv~~j_zg{>6k+~/+/3;w5sH>칒otBp_zy}uMPX8NLaoj ?N-zb{#aq)?oqeʈGVhf}WQO%{OOɞ^$tbh>zo\2e})jn~N3lge|/̉Ls' -~wgE'2%h>6(JnZ] 71VϽw7LwtLL'I;S\9+h0gd]~|p}1o_No_\?>,wezǸө}QS9ׯ~V~zYzzG&s߶,[*]zrSV6m}jǩ?y73yy>Kϒ_OG<N_{|ϝBm~Ow^?u;쟝]ny\ 9ƎWZ<WPzrMoh6g&+/16ߞ?+a_KeKj{W6z??;Dž;XHu'K"5Ab޲'^Eeb듟we[zNnH#}K?fָsdOȨj6TdEV3G9O1OFR7eFA3=~G/`1}x'}⼧1* 3/PD?dzLt>G~ǹ-5k)^?3#W⷟|{f0..@x㱶y6}{nml~5=C֊87'C{mڪ匿iy?<{e.ԏ[O-"٣sV ߯޿yyu~zEcTT㽹q=EGikij\::V5{/@O}W[}Ȧ+ z,MoR)BGqGqo5\gLupҠV\z3=Uh]xg%~nzJ,ci_ %ir =wu_h/֩^GqZzrh]p.u%%}_ݗ}HwhW{pu&Ev`*]?ѭZ?{g?o:nz# T̡?ѢmZ磷}*& ֫]_V^੭ԴO VshgUˤJ6y?SBv޽vQ:[.bϮ2..65DS9*ؠR|qZMO~}h"ND,?p[qz!δ@=Koj-ZbԭԼZ |鰾ޫт|h>l%=CSJ-*mRԬs=K{w0ADrcuUn:.fM}"VV\3K(vO}@ޅ^ܴ7Z6@r^"ϡ?zz?EE%rUO@KvQzCo*bz_s5>~E]*TSŝЃyWV(3@Fh6w]\boϻRslUԳw(YmB0D-۳r8R z.7N5*mo{02ֻڈABF}.8o´n򄍳X;a+ֱ^>gc(7tfk}jY&RPSR),&E]g9ڃ߾M׹X6F;:^ʩɝz݉Nȹ+\pP4A[P8tz, ox9r]:x^):v.BSyq ;)$@XY]6t詿aT΄_aUuFkzZo49uw ţh'psJB)Wq+h7r&_ւS#H\ :e/{M*]XI*î]#<εVu "̱\ LU ұ썠W5*ui}uWwm[zJA\~/6xjwuh_ U}(AZFuC]MoXGHmś}jTRh_Q!< Xzp9cޓw<ʤyMZ4. *zW;|vEj7swlSRzgMztPn?^v;G)FSOTz8ZwBeGZeNwߜ*o&}jBQ=иpEBA>tzqǭxFPSʤY+ 8o*jZ({~-87Z-$bv"KqU,l .4j.7K]y<;Q{:7Z<_y܊ Eաܴ}XŻNY>A{Q(mgUMW!K7d%~vT(xZa^2B>GŽ]e (k3M8tgyH޵IHЧz>M/ {хұD)8!=ݪcPI"xjT6׋^Pׯl.-`%z:ߌEUZyuMzݛvrr(YǮmp)6f{(:56ϻҘ}YIB@:^R\ 1?VRF&WREvL~QXN8[ڣR-۝m\OVs*ְ]*)Jg >Qww We[6ӮFQN_+{-Yz4 E{x1wv]Q~w~f榤~6"Kѯ}MC)qZH{u}_.ӟg(ϒKY{};4ywGbt?vuzTFOW;sǩt/߅FEEyqG]nRyx4Mh{i%:[D5ؤ'%8!mJ^!byy}OWi+,EK͚;R/鵼{H?yV5λ]YrZJ hxk)+|oԖ'/ UJ\V a 5ZovtKU|dx*JCAfw e҅vL)sR o ,Nצ.VO{zAJTxVx$7gR¢נ⡝tһ;o=P נ` )Ӆjc(֢:6G2Lk̮y?Gju!Ɩ-]YkkP]5-UP+Y,(G.y^1Yኑ⛹+e"s[^dԺx;LĩvÔ}\*sV9LPۼsP﵍!MLTsZT\\><jKVٛ^jcU{&AWPȭFIE+(=%_nGkC®HkO%km UJI/ZJedk+\#-pMBRvqP*^ */PO@Apj}?,Wɲii29Q&StߪP.[}59BPFLN"Ⱥ=᷊WONC7*STacWmn8hj:?0y?}r+:4Ħ\PD+7;o7 퉭Vu7k Th2L!MαUUAYw4T_*.%x@qU~Pj@{w~h˰/>vڰMQ&YxG]z= *d}ZHIoVU43)E;Q]Mu5PX? ZԞ/MOZU;tPE}M()P!>Q3E)$5jB_g.1<Cƕ ) Ÿo=KOW_`qi]–7*f'%fh9QV{wr3 #6n!nD宄R0PHyO|rލ~kߢ,ic?/Mwclpe,4Z6n)ZUǺU : wOi{=l+(jQ\Q;JWyK`Tq8'ΓD.YHQy0/$CYZ8lE6ΎOnye߸QVc[>ʋ*fC( 6~yVŦm^ׯ8\vj-"EVyFU_5rHi+jtͦ\scY(U3[CŐQ[N8Rǝ>zoDsE]ulBF7y]ZbJ1H4'U;(m jսT=$O%맂AylfL -W-]k(+ B7ZZܞ-)+4-@V@ZZ*CFaʗT]j~x:gZ2i(x`;g҉wn󣝑[(|ͷ^Z'3i6vHՏ(QI-:1B{f/^:z* MeՕaٰt n^c;}G%S9[W@qlGw&}mlĴSO'өvd@]:~تqv_@ @V(7FG]mh(wWMԂ&ATSx}Q`lO^-P'[ 0y<}r7qW6vd--_Q"Wf"87,1jPDV9g$h{:夙updErH=Lzj{֊12ϙ[O{N<$xŢ8rDDgg$LvƀД҃FndM75{א>nlguvohZׄBoN:ة;*Ocof/vՃ#H=g;اf ;pϸQdh'vNZ@ERzdjOy!lEFhU܉*U Z^̈́Jn=KGE~U^ՎxQ]m>t;3ǘA拦Ua-~9tfj h.>ökf I~UVblL^qI 9\=c S{)3V,#L=ta*RWZU8/j(:T ~uwek&aQ?f ţ1,6dC ZsjhM R('E4nހyfOs+=P5@mGaS fNaQэb'A+hi{0j2 ,+h 763=O#_v@(*\8+Z5 evs{zM>`(It.IzT>dzJTjK vyEE4^}sv0KÔ˜T#4iV͵A`9mu>h1wh.G=Uj 'd I}{-QSj'8R teZt@,gh&!(b 0!M==Lu>!cPXKGĽ ]ȞG}!3 TƈFmNG|Rzb2OfPFA*$We"ZόFت:B_uS.\Y*i6#caoZ;L>-AsÔRDTl9Je 0V~׊? FQ{h'ĴKA|Fg@ FXJa4FYji)P_ PQ6H pOOrft0=CeR{KyeIjbijV.izAп[ɚ]'մO~+y*'1d7䉮 cq!Fx"A*@eA DGn8wslGd^"*+h'?k|"%Bʪ^je.Oͪqn^9NΪpjaLۜV CVthBZܴ1tS}NW ! S<1CWSAB'(x[(s-(=Ub Drf ɪ'PF±Q@ Շ~vPF雊@R6k/d3ܮcnj5;ߺOtE4x`*ߣA l;hpe^-l4vN((S0dHOPt= MtnpN}Ul U3P] J6LU`lfy>.G=sAa ZH+\`OxlA\ ? dDm;F51¾Cmj5Ϝ;׷"rl @o>4CIS! k9 頭GX:IjkJʑ^Nٗ6*s*8WªmL<*hť>v5r Ϊz&H!S̵Xyek cvõ*G pdZ)a{xl,FL!Lk@t_ D{` 6f =ӊ*ొHa՚;=XP`'Z zse5^]z"3m{G +94a@h ]+=fu ^M@9FjvF`9KkJF@9׭_S{;@Q/Bc* {0f4 (>gV4\5h<{xX5՚IN!Xݯaf`BW|54pSAfe@MjNjZpH6sC Jw <&rvai>/ث M29XERqIY %=g΅a )Y=ԍct4hfѷ8vopI tDJn"nUI)jhuf!*p<;nA9Aù@Oos.TAI]nwHS9qJƴ6Kcۨ (Fu-6w@ I41`j^TWUƀCs@1Yc;H=Ί]%4}H5R^ ޷Y .Gh>x֕avUU9B~fT`h{=D=&C ꄺܕft `L ^ @뱃zE1O9mvm);0dTlNWlZ@;!K=05l>Aj"ؚ[5P,xϭ ьǓ P^Sfh‡ Cux}p$t݁\$mr5^ik-<36ߙfcr#O3 (V \FRH`)3\'pHTsˇA~ʂP:Pe)h٠.9q N45Ց @Fbe TBWZ.R4ɠXJH]) Oq'B5Q>B+P.3WK4@9x'rYo^ v eT&`-lC f/ o*') 2qHw%FJ"+תpj)1")_`1yLe:WMLF@w/ʒJìuӦmLyDpB -y.c<u VFq^A"gQ1ƅ3H#JGKZAWz|X.~HQ=' 0%<*yz2VL>6cRNk ~d LЏ3ޠ2dF|$&HwQ1Xj 졐P%+tw&Me  [^?wzY \X;G[}T[+= ځn6Q++NC7 pH5C!I,3nh  6Y{B0>g Z)7UPG+%!#ע:v-Zܫ# tw Z[`zX)6Kl>+0]́ ^$isGB8F"R&4e`hS/=0_L|;l+Q4]h$`ޕ4A8>48#K0@j=gP(k\e5 , Zt Xɨ)) dG &4u PN5cKFeP @d\t$s+u7q }]M'=5YC^6($Ա 󃷢  MD-,2H_DA,P,~D&2@MHAn^TJ" 0Z?d?4$A!U­#%> PV9RUy*e7ȡwV8UR;DbjgHr"m=쁥M]D:glzN:,ш‡GжQQRO\5G9n\bl~=(fR%肨 [8vAx? ˭j" dޠ]ˀC,)LS 4> 0l]{ X8ʡC.Q،|H$eU>Mt5cP)FHva 9}*ZS5}hۗ:t!,@(>!(8u5QWN!$+  \ u)Nzs TsO{">w-`q1 CT:({7zI;k/5,H.R> jEUbUf TqK= &ڬP:Q=>REĵ$$Gv-jXQAhGAD5". ;a[).ceڗa,B_Q"+UuqUa[)Od(tv\_ ztKg!TBȰXŢ'z"L4ՄFERD5EW3,q;+:Xw$npAxdC@nIHÂ~CWQ>3@>u3 bP\_wQJ_6 ^97+AN%xA@c>o$_9RCPcLPb2@Xf^wWE& ܧ"s=Wx4S> ]Ϫ(Y AH}I2UErV,~&0zN\rKͤ]ܽ$7JkpE"c=yo`b< 4K.qMyyYG# 8ƋB⤧N>i‡@Ł2\G?jT$&z) ĀI qU"iU)pId봁%QsK]uSZ3(Q0 ,O*wk~5-n8,mf$kwMOV1iXl).҇OXE%On_36\QS 6ˎ,C=XӋ <$D,TذG@W${"x16\S#V*,[0t ͥT8N;4o*gujZCÐ J[&PŘ uH6")H (ъ23 f ;@EK! {2K ,sm8 &04 /V:.K5A̐f&Z*:<,8蛍Q -v;H ,D:]kl21q&$f%3Zb nhc,PQ]x0$@}32D^ a# bKgCRd )%Vl )% 6v=+ZMp(8ke&nCi5(nB!5 FԤ֤ y1(Z)]tGHC vK)e)ǻG?6r4D?W;2 3ӴC8S/zaI 3S~р %i9t2Il# D6,Y8ӍY/R\fgفR7Ֆ$]MXٔ tc"nH\~!3P?T&B@Ҙqcqs\`=ct1o|?yPWe wLU&&eog52PɳhZa\ĴDf}vDߖi%9A(`IYv!?2c184`_M$)mc D8 nbz⬦;H+2Z'{PV>HJAt}c'0ci3,80 &D$B#HīB,aN"7@ZkCN@T׬jmb{ ړyInis I熿sqkvѶ]D[s?߷0L=oANK:Z'~H m~pi ~aZ1?+$!7;u62^寀 ӍȍO@oR,!8s> mcnm,gIlkxJYn}~ҧS Ժ%n+jj_O=,[՘&:ı&  AxcڐWƉ5ԙP7rT ̌{b, ;ߍj9JL<4K8lfԀ1ttv2*}@Ȏ A,*SmvACXNy' 2|W>])P'Kjl;C]X^vɮ1 ^M d*3 5ڮv2<V,tvQ,{~֦Na]=N ѥm 3`jxPéĐ aa*C!f:Vu˕=I,8X8S[6PVz^u}FR?n^'ŸWvy$> u8hs#$+0 !^ɉ9SZ S>"| 2֤XS?`cg| /`ѹAc {D?C?bFaO HLmmd p%ntU#Wqόro9ɡ csU܇,7᠔Ͳşt<4^BԵ`̜~4;] et5 Ob]o%s~׬Y PlLm_4FFU5h }}:eBթE?:fb S%=<D?cNjb{N'hcV=^qGnQ w*m9Z,J38igiީ]:w3 L3 ̳-4@L qԝXplg,=+h̩fuS4.#_uhZ?Q/XؗUOV*Dtiׇ(, ~ƣ0"$uAHYB۔'ۀ͞YI?_,1KSL_> QZ=NR%PL(+yWG`!!z4zFZ*XPZL:TM1{nUzAvRн=QHGn 49 @]NsgٙWZ;yYO ,"ԜwT Tbv]`ޗ, b`B;Xܖ!(7 6Dž-zKj{ukƪbyTcdDR~A*{dvʇuJ>4CTX ˂z h Xt Y6N\9U3FU|7IPP6eT,-IJ=}F=|[ ۉ?ڷ]֒ёgs͸.y-^\UYĖ~1@$\HR5농x{7;hbG}-~ =m9c`sM-DȚ$/xⷥPj=O OK̆ 'Z_`9@ܮu&ƺvZ Dqh6~<6.jӲT`zp@-]i!8ߴ?āҴ,OJGEd ^ﰗgG[0%TGE-3Wcqօ0R"QUid`*!9N2&;<$?ǟY%fLn먞(q6Jϣޖ$.p]uLEEWXW6? -ǰ>"]@_iéh5V]z*rYTkWWb9gd Io~#]|尩",R]ے% v*!7K Hfax%.i2B6Lm_(آ^b*PSPfbǣrn#z\ Qgh#x\b9U?l,edآW. pE?6+ >kdؔ'%]u'  xj jw0'|/1 ((ݛNizJB B&&TвU@B߁*-HDeAvqfkVUOUIbz}@踦s ^0/!2S}6AB){ܠ06%m zSIxopvCTzNXv"NCVGQW em6%3{T:,T'g&]BԄM6Ow~X̡ghxi4o3U%dYe~u?jۨ.зawBi:_SC6 tCWOe؄",Ԑ!PՋFq_\m1Ԋ H _i͂$уDD&2$ȄqQgF qwL_z'of Qd56$g%K .)e;gcjˊi9|,X"xEϱ̬.<7h1@0-T7F ݯe<] $JMS'96a aܗ.³0JWt Ikms[9,R 6!U1![]X1UuߜewsXݭ52?0`v/ )݅ UO_qc!_f~IP6AC)$eycDl;$7Ae|Kk`7 Wt0ڲRfS#Ry-D]zo^ѭ`\LnUH30<|au[&Hȴ- TgY)d.]ϖPn yV5. $)׼9Vz͸=ljd6b`$2"}&Jx8LrWCm^T5n_W0[]gTkYP"**fEq`noEۆYHF|HS8 hI}j ؇~;2mĒU$qKjQt'}ZޱK>>i| Ȱ7@?L^Buu6L{@aJ m  C4ri_K^:hقG ɄdI$^tK+Ŷ!GTR#P<6JG(m.潬IOqݓ@r5P9O@6f4쐃b2Q]xX-G@v*F/hHD²萰A6XFU]LjU,]:\a2l~=Z vF) ,T!~"۝Qv@qHG%y0=Mؠ}FPA1թiWoyj˕En=V.uDUZ⏵t[_&+]h!:JCSR%.zJ3 :2C\T&%vwO i W#Wl2&ϗ D%*5sA, 6ྍ1_m^o_!Sm" Od}G-[LQh.r؏!솼I;"*}-C9`v$|[`R[ ( *P[TR`uT$ܼ1Y{G#XvШz~>`-ay9b{1M?KLpiDddBZF4=A2mHR&?˚I|B{q’aa` a pJdi_"Rx,p0/[Au ,xZ;ǐ(B{ Fyv-Tnj"͍bBlT_W{YGT)lTРs__G=zrPE 3AڳA{X-.2(&gO [kXb9X?WAdy_Ri/ғ5!#dogcZ=Į_I1A;gI=y ~&!ϸSM&-'$@RAx(|=ߙBƼ%HjJKjlYD 6w>q`n߲#۹ڰv3+UVV_\VyD׿ f=:dDCG>:"4op_-+qInxaL ӎU[.hZj5Twy*!f̵?c;~yEEESRQu㏫ѧ&c 3BQ;s r3aSlZ5Z˨#V(Lr9p$в8#A‡J,,cUU)Yut.VLx4]fRdfhMlcT}crP=81eӝlSf+qbЁpӸNc g*H!b8\\5 LfCzG˜XN) R WC Bԕjcrת[ s76`+pV1tO*\閦U69a+[`i0hM١'l)a}{ v!DI*]O, ?  >7Qшrx7DV$OJҐB絞VgK@6| B}=P3 &YS3kTn&'-T&JC'wO" R2*fRF"X'_ (e]:AjW4\t`Xd@b&2ĉ6RBt1? F;jы_tmߛQS,B4,+nU9iUAQ 0m@lekB=ȟp1Xe;v4"v2Vic 3S8Rw)pxb#nA\Q@+cU^ķϼF(:dBHʃ*]FD*(԰{PCl@lj[oMzB_tl(W7QB dh6VoM9 \R@X|N|t4YAEB)`[:mG tvN ݥ4 8YM1ξHqx6%X.@LP$HO. h*] Q<Ɩ}O#GNi .((1A381ch3HT@7r1hQ2;Pv:@Q| i׳gAnľw[;<[UQ@NvWEiIÌ=OSN߅72"g"3mFv50k)>W7jnT=K;uo>m̲etA. LxziuZf]aK> R_Eog߽O9Ij԰6ӒvBՉZ=`5䯰>A0>#2٘|:m ˪jUM/W)'U 2WIΔ/Xnag*XNǪe /C;C΄."0C*u1eܓfAO"H 2.*H3a+yK Dh0 !Nțxg! TuжID?ls2>Xف7Ԇ%uw6gB$hn_4i\hnBB ٘Cth \J.'DZ5b1S~tmrO `Zb)G:`s]J/p+9f냴7 yEyk >B<- D ޘh˞3Nf"ktLYq8xK?Za;bÚBACPDzPb1.IDSGVnHUHzb)T]^\?^Mu~JYB!+Qqx靟E2 @rG44A] ~c)tD#lx:5kL ~@IpC nˌ|IrC8s~F]31p4!`9@Z=ܿQ['hQ@.J ))v^1CUx5GƵv?d[PJvLO#)0 <.f".eOBGbcb5p`BuT}X[h{Ss*>am#T[$V8^J2&@~`@&Z Ѷ݁n9nW{&%=Yf^dD9<]zf|g<:uC2G=/;Sǚ6u-xVQdxb.*B+R+;_t~?:xyt{ Hdꃇ}O,dB\Ѕ=] 27BL# !CYpc% zEX94V3$FY҇H#x\hU{rlupƫlh2shRV}Oq\m AWG _Zx%[݉f2n&|[$~X%DA\AdŤ胈QkI&3M$ޝ)#dJ\rwaYRU{ΠQ0; Pv2z'r@gl&Lᅑ ;"`QqPF7Ie= E*7!XwARtW@|OrI H3 Y2Q|Qr[4|^ @i'%E1 Ӧ@a~Z` I3Tp|(}$0&@^c#Cb`1ZmG|[{[DUVUWÂbv nh:i4dn '='HX|ltCplmx wuTF[ `]j?'/ךDž~'[sxZ\nS3˙p=rd]h%H ōN>ӯY|Ct\\=HD"N&@a{c֫*VdAz*6{% 7aw# I.ִh%aru( Sk/s<+S@Qzk Ď<^Y,bwz/Ӫ=p ˰Ok_7 /HIC?s[,=\bƗY+aq'9 `Q~ыHLOM,]@c&(A}۪@m0`W9-G]2ϠUgѠꬻ|K~NPp@eT-oDlL~~Wwߦ ];%( |#<<É .f1(A.iH+dXn8.'nJzk-`2g]!ZY%Kf++ #X$8RC< f ^^WC^m} \pdS3q68n_ /ˮ@Vu/1gu*wM:4r ]B,D#K%)+Y<*}ZUI2{g/,)p,/XTuËdH!qtͥ-lIH r%:y"-S4Gdb7ǣMD[6ElL{L7yfR.Hrx?=ğ·RUg0i.( >C8{/ s*.9,]'R}]=^g'ͲPqu։!>s1/ԇg`-jTX؛j ô..CA7xڶDHg Aˊ 1P{$҈p X+O6g͊Jَ?j +@3j/x4yEぢeY3PHKZx-g+֓XU,[* 7G銐Ɩ"Km"g"dJ; PvR/Zv;ՃۺzIAxTi8BBD\uS:}= lI{@5jBΉ@m<] 4,z׌:#1"pg'* "vFJfbD$CY0DNO4LZ>gW+-9S/N'S=WQ6 r[yCqO)M48Jntgp:`C7*s, sѦ>0zU϶6aW f33RSׂWHOmL0hh aUTaFK; cmPl` yY{:>lȮh?Ci*]0Dt؂*9шZK^\3m/PKq( =TWJbjRc_:\W g}!@ ^B,!>(@@!7ȷYPu6-0Vڑҵ월 TDɆHJfĜ׎; L!2^L;l+*žCOv`okcM(P>*l:JP-ESV$8vЅ7+A5+[uNqD &.iݣī=BB}ES,#>ʨʡŏ^ E<'m1htvFS7?*2q7U ƃ Ud?+F h[P ,u(`,z{M f,H LfWfF"I @3"n`D8>]xFi~9çͺ:7=fEY#C9.JCWrIE6g‡ 42B !sn+2hu0xyai" 'u,gw,iṸo^'<Tq1"a Ȑlqٜ -"Б-(y$$@4A4IKn#H :)Un.iBTJf7Q 7 rCRKрpKGv Z1PԢ K@GcMt8b L?N'}BI"(xP8w / 㪣DP( " udѵ8?pϪ[Y<(nmA;*-C ڊ8ZE"D@w M9L_Qgt9Q5̙:+Ւ ?/H+ [#<6:A/p&H'<$Y ?P ZmLUzΡUl6qP%I"ѧME ȥ{6aKbN#~JCRlG܂%5όzw/Li_ܜt>:?\Ud%0JFB85 g#j*CAR#$⎒km?wPbՇkX( `cFrj i*lHàK?h@'G '1H[` inL96q:TVQi9ph8>|j3{(5iKEg)WohAok|`> p8PUyX.!Ls LVY@6A,Taw,dN2J\*i]づ鎖RsU9z+#7Q[vRw0|4CSnG` G -\Oss7F"GJȎNGٴ·s3?"SBW2iNNu61fA*s5&7 U,S >/tLC~XΙPc.2%?7:tU[U:O状 S,T]1} @R05T"P *6`}jhB}o9X)BA#5-xDV10`mԞoh:a| -fD@ZCH,2E7Ը07߅hgP }i_eN%:l\Êb?9lLF7S7kxA'RItFSd;ltӍLtCe) 9!/\.1>zz{3;yS?ͪDk"RQxSi9 ۍiwO(}5LUѫތע1zN,&/>  gOi s558^m WuvDZm_S1@w[kSNmȴAC>AS@ 9[!;h'i~H[2OAkDw\DNI%_/w(F7^ r{M.# _.& XohRFb ]׮ec/3XUpvqE<ؚ ѱقkQ 否,;a(>QT2Öa޵BǮJPscoGE~Wu|"# + يiNPX-*ZaFEAp5+Ow:)tV[ AnR;g]M OysX':4wA!XXHK `& ~X= r]& Cj!PRgm"aJ;"L+px#jXɾRKwuD =(Bܒ',G)Zq/6ػb##9`@"JFdCEH{Z7W eDG88V^G [&ZT(RPRM`u2y  @Yi|j=ShfPi)j5^aIa'mh& /{e W3'kp.Qb/oR禙6`@xHy+$n |3>|c{0"$ڃ6LJRC>ax%$%Zr"j=g] ceJA쯵@0v|hb"yZvZoM)DJoMgOKQb6 M/_~bv6"̃Е<t0JХCΰ: ;Sü7ou544h5/)K% V!ܠW@&#";zSԻlI_S>zCRSx%&C$ JowH0opG, FT$g4~Ў%U[:oxLOcf %ye("Rۡ*⇌SSYv0@XL2I,!Q چ'Ԝ|BasGI0O5ec@N_t;d^2" Smmgm34K-̈D`@a;}/L 2/?.S#i\[fig) }a`2(țGNM(ڞ!ٔ@dC (- Q$$s ͼJ9os$#K8T-Y(vohQ#d58%2F/ELF 5ՎI@?\lNɟHZaH*d{w?mR(7̨rLW4 1RGj][fhu@?׮f W[d]T{5aR"mÐ&둔.oT[u-:fg+PTkz'x`/sJ [JB0QB$@6n:F)b4<6 W6&ןSP^!io116&cB wCܲg@ hg[r}A-؄TDY;&lWa>Z&ʚ[g,aU]xCVP61GNyYXI˲r%wL~C`qyOy kvRQl ~<]1)4tb]?0EZK}kUQ\.<ĭҀЪF>x>Dl%I8)l )Tc_M_4W- =+Dڢ1 `BjK䈒1;ASbܩ`h[@^i39lY`w:14N*8#bfFkP{Љ3ѕ1>S(Iy58g,ə H0g[0e4!v_UY+||C^ |:]s:T8=h4Pq8/Yx.=ed=BjՄe/<$FQpGL+Иaa_ raUŻ7bwEm%s%0mqA%vD 'Gdv@@`eM #2 +5غ(6C9Ln4o|2xs210dx{Ô/tY;r?z j~0Kɔd/I3aTlT4@TәfӒ]ltOU!-8S@eV0b_EZyYPxhB8ehHi6PW+N]d(ں(vD=@{Ϊ&U{nû)lE%VV6+$0(\vMڣf~Z1lk7jC ! 3TRۢ Lj%}/H _V%f+&N17pK!D(\Y-X}0^iи.nMRd.dPU3NFxcflB&bhCz&H$N>6Q02`؄jjR*ZUW&Su0Aٱ7.Ѯ8~D; #1 D-2kO8 'itѶ~>>|>kSr3NǏ  8B4)Ǫ'J +.XңpPʛ sm*m՜f;3á,HSF%6hsѱ8`pmHQ>"7Pw~@))oO.5C(m7I6 A0 P(FZIj y0 AA(c66A:z87#r? !i* V@5j&qndTx&Ӕ1N6LC]0=`Ԇt;| Z|C|Ryo Lm $jj9Â3N]Q(JiڶJ$ms1SF y!K+CT{JD/ib[0; ]JդKا4)ɛ"Ɖ&w+wN4`p"@VW$8ث;G :'}ǂA:pB+7{M@Z7!zpZ͊h 75y7ց"ܲ./h UJ_x |1SND?4>eJcB(ƬY{J^[IBkG{LC`h4TiC&]e#v:-d\;KCnq<܍1vnkXk8kaq&Kgvbu[q3X./×Z; :4<.2Z@Oh bzvN8Mp^N497i=J*H`ҽ+ΒX`v{A vJlROQOlSZ$eR&C&*Q7YN%9E8 }d29\T)PpPDB]x_@$}KwoSk²h\ њ b l'>)? l؁ ljV0Cagre&ݺ2G a':v-aPQ-;aD 3}gbS+pJ kU1XLp2K Z6g;~M}i8;R8,tƳ-r4ORGN^o6xT X=`r 5heZvBbi;LF:mlA;=+<*[ٖ>8sQ!J pmPMFS_4R?LJN )^Uv*=qU)|HTm%ND _꣝+j`NcYiIs'tGv(WXreη'IwUQZHb|z6>r,J=\7| r0YC҆ O!(5w(\td qt%,lcJu q_f75L? i:(b#أDV0|*H9S%3mb;IԔIr4x(*)svRñG_yJ\`(6ck8{B@ruj HTz֦ + HBI*7rET߱N^֪"B:rùۼWY(T b]R1!*TE*TeU}*6LՑV9Pp4g he*:+v+Zt5{3;Qk0/M}&F CN(k{Pd^|)ֆ5nEud .N]MG0ѥuq]#/2G뒔0b`MMl͙5MPrjJEMʱA 4s LNa"Jc]Gcb滛WAȂ (N\jc 'gUtPaUQ)ajgrj7e''YӳJ)S%7-mР7 wcӓ>x7H@gh8wQO%sVp1DI $SSlE/-1vH ňx՚Z}aqȱ%}ŵT ]CaA8>+ _]?qSb#^(OzD1|ƞ4T@y {lH3VƧRL*Q}t 2:xN7?rU{]6XMCR=+μ4 A~X#֯#`ͻ+`' ҅NSi?urII&['E#ܭH'-3 "% O,LiV1T1Rܳg!Өk<"0L l[LYaT:ohzް\G 0Լ=4Pc(?CIoNgw@g*(DFMã*NLDaAVmcSj;Zx5KEV4>;18DIeX) نgSmÑ(6QϤIPM*ǍA_Dg8Y (8E܁:@Jh"$-l0hC0@) jj"ְf_wd3)B+i4IO{v" ~"?r}R_K>J'0eqYgl  y X}7-#L1B+B@F'fXlE9B7G%.f>ԛ~^Z>pQg_鐆 ~W~M!C3dHADhL/žB _G_cvTUYhZMnvIn gV-Zq/ZZo~|l3F-nW^A-Ѿ vn; 0~,2\l Ar丐eRz`WMTIZ'ZpV}ҎP QOc*p=:6B5@}[i&`1 O@UaZ5%IGjvZpvl,wfX2xLxWOs*׆\a H#;cc"lHnul9Uȕ1ikGIJI\m.:cnnf$d ]nYl\q ز4N mqz)B=2` SY{hX` jаdW-CtL^O Siʂ5 ZU@0 4Nu%wc>G*L.D'H LSchVl1"dBryigji@jYLU#s>mf=J}Lv{ Ϝ x䢓HQvFk 2-l^|_@T@ƄAؽԏFoJhwQA1x~c`򠙼aLQbB5b$40NRqf/ɊB> O/P6qz/glSVQ\f%T ډ,>3Cd 8>*8 ɃPDE,Ϫ䢱:% {aKl0kc3lHЬe])nt\`.†!B}/gj95(bC/aI% mM=P@Xw @5fR a)3@*q,rrg ?':ih|5F|F)<:c&~Ԩbt)3 il2%V (K'̌4'a?^xaY2rfpiLD,!6tﳣqrpMG⓯`zA}Ǒ>Gb 71 xv0jzNL44W80+E~muxh \0n miFGwVp>M4C v :vJvfGlzMn VLN9}̑Iºq9$ư'dϝS^Srud".ZC Hv \;5(sP 7?K*|Ej*R_1W_3HEywH˃G =-DF$"FsC;FEkLÎ/9Ŀnvx_0S-SJ6^K 3 R0e>cb#%aX4qQ}NrRFLkCzb?G[ ~xy 6nҎ }FSڏ'CJ!NmuzK0إ?d'JB!3i+è`GéS-ƣ]&Cww6&_LA3$ Nq4L|Lz!az8Yz%`p-A^53uخ ͅ:Ŧ!lʤOn"wp~i` O+:t}r*#WyE7 '5lekMDaE-s HpikO%Bq5V%`8.AN[Sg&4>!uj{7&G``탕j(x6e'|"L)%4f1l`bivV]v%{eFCjH y<Bh.лo-z?u%ĉEHm֪X+NҝGuD-נǨ @rf9Pж҅W;IQO/ ep7XvӉ P{Ch16OF̎??b;xnv0,% SìOzU/i}!tP7k4gP$.[bF&Z+rgn塠S]<bL1T Q@"2,|5~Ps|U-H\ٲJ\^&јn@ē4qz@.EKV?CoQIocmhwn-9%*_Lz;"Ř3eD]AnۙZxw7 2Phfq"@ۊIgG7g@c)aqsn;{Gz!5-)oJ"2r+ n -Z]"n,"b=+fm̤?-OpЃWHdԝMQ{]p Ju5 9]0>\Z97u $SyMgk00B`67p*&J']7Ou2*Հ8?4^tFdMD 1g ZOV*2Ia$jHd/pr9в|m9-3NOo=<6hExّT3;Tl*|I= &&dz 0xT IP9lwa>y!;Q^?nWX0@>(A@DV'Te7% L#UCCZl:#RtEwW M `'%PdUGͭwmk8Vk0xӨGL!cIKW>q*ONw MzKBgԷWҺw\W>ʪ3biOÏ1Mi>Ŭ% ] 1A@n8 ؝($uh/ w^,v:;@ϙ5(!~r̉͒aJ<ΊwR[zY{IެvZuzw7uz?}v$M Jۨ4n4QY k k(jzK#y(UQ r;9tԋk] ]C PM.h:*sӒsF TeAh>G@Y4DL{t!Y(rz(PsLvI~ k &;-`Fh1"NcZ P0i iٺ%Z̧)tBѹxygrgI]|J=_K Ku8kEGYKI}Iϊݿ ʶ -WoC[ƼZLVSLm>CRgx% cJkI&IGsf[F2VT]Xq*k7tw_vvn=x74Ver$t :堖vWPīh%Z Vv-]%sĤ (ZU(ş{k1ѳ/ PXFȤTH r]QcR JjFJr2-GzJ@z!pD.fw;i]Ǿ4B] ¨hE+kz3HvxV]9̴Q܎^N~ Ǡbnf=?ӆt׈C# NUU'EgrfԆ+뤈G4qU&Z{uv+gD v I.q* ?uVh655>~ZN,@ CD," sibh#{ Ea +L==мJu> T$Jլ+=5:=,=x)@^*Y>H<<6lZFt ߮!a4d/az,P F;@@z8`[0c#k*dF@*NH.siM{ѫQ6l x8^W%S^,vAo%ϝ2ޡ txw #B  .݉V{YͅcuCIxg;`v nI$hEaӚ@ɞRÌ6T+I!%FP]RC.-Ki @WJVa'j㗤R0;*,Ɩ.;U-.SpR[,vYcsSVjqc ~4 /6>P))% 3.b:(B {(.^qBƽ1+9X2XZub27& '`cB5O?)meB0mx@g^`![Z|K@(fhg.eN0PAD@.IyG7ì!61I;M4f,~Γ:wICyΤhY@0eȔdwHFy7y!œrUY 1].y*z؎@GlҾMYv ZO4؋%ӻNm$4ꛀpMU=KJz`K.QS^? kwq äW ~`#"UhRfjdCMO"42#&~ (<ՉSR A(WT*#<YaD'KNù T1~HP\F7_塷|Y~a# wO\+'"E /u6Xj`W jYy% TK *Yn MbJ0u=S)?6ݭ+)K ѧ3褡|v%:6QRcްgč[1;>LUa]<q?A+zȘ%0Ae35H XyN/>ބ(@T{x`! BL@fNЭٰ AP#pݘI4܉IְsEt\E]9jBZEs: sMnWH Xh0 %n pvKo-@}iZkB=~h&w4$^M \@㌊'\ pVX1fg+E\ #ih1dt`!B9*\#܇@ߴ?wNA[? 9V8bPkHPP MTzG@IEkC|s># qIb%ez BYfL|]UcfNW% >\4 _'k{IѪQN6t"+ڋŅe#?'d:N LT?֢Jsdi)2x AF`iNelR%0Y3!l[qD$gLA ® $v6 hc@l4I'HߍPRK7AOP7.dhdd顊y țH46'rJF"OAySޅCSͱ)㳊+6-Q3y)n؝pMHG\JkXgUu#,ڶ4»Ȣ^jq2iv N$c$A8i}?zRڜC>t 1xrNN @Fv42T?<*}*Bi *uM6i$X"rH}Rɠé*EGrhqHV ڲj0_mx֧llwyx@i 6vsW.'Dho_m n+V=/] i[JtG0+Y'{9':E!2)jֳ1%#%>xgJ?c6ϸ;𓊿u}JτU~&-\ 2I 80gsInf:l|~pp8L P7]E[rfd rȥ̚e`&M3j|18b<9rfɣD0r ͭɜIppH؎ ÎQMg ?}Cs2<"{r|̎kuyk8%^4í7Nc 1|x[bhl ?5_潼# |hw: )owcMYM+ cK#O>M gA P`YʲGݜa`?OMTѠ s!Q:HowZ*PYb Dx4CQ77xPsBD]Ԙ`u}kce1" M\ZRp3_c=Aqt76#9(9r;6hC{6$7 u wm1m7z24B~h'@xqZENj;J,M @}ssM]w"<=&g1&1A[<6 fć@4|FtQ‰8xW֧ړhcC7ZoOT{ w: fY#t u5h! \ un@㢠%%8Z2I%Dڰ}/C dZ^GcijkRhZ5 Mg[kYZft\=HC3 a5q`'cj6llE%{sR=;0SAvCM|iSxK[Bmp]qzn+I:% 4IQ/\mA4}?^Qxƾzr` :Tʆ- =?,׆]=0n5ъ7Y^ze$zĉ%B=Q$ZeC^tr%XШ;ȳnVToTRLHph 9{~<5Ĩ8 rZj!c.FWw0@`bBV &0*FcYJ Yh*Ig:uB>@Z4U'moJߦ  pMi5"ᏡȤM9D&z1m`@1jDB*Pċ2!|70H$HGPUIx/c`FԀ2MH/kS) \)ѻ(;<{y9]">ot둪Ce !>@:I-mP\ѻ kO/U?,6fZ ڄL=<^% 'Vn(aQuQGyAxl2VgΥaZ@*]MjYg*i$h$$e(\FO ؗzL j>dRL54g .&eQ@rh0TU_iV͠КIv4ô(ͤeZ/cr NY_;H=CLf؍?t_蒜L]`|tA0o_fv׆ 7\RAʥ%=g0>s{NT S 6%a9AcN({-7y/6#z1I0QM$b6*ɞyֻrߜ6\'š6{ WI%S$oynfpVBK Y@謾4M`'_' 0EV@2=l0KpH6#+Ѹ+e+֧ a-ԁS0DXV1hut%ݼyЫ]{D5%F b$L-T[0Z(֡39% [i} {qDܟYjEQYA9=Qzrz=^ϲN:$Ccɏ2՘jA$xajtB†JH]%3?Z2]aG+P-<.o=hP'&*4/exִ)r6ʻʆ51^AlLLFP;JDzڰ:*rb|QфJ 8dedV:"M-LI˒8̲]1rsF@.fs 0rjvTM0 }S] ߊ/,sq2hhyz).+Xzcw=~ YGǪ!%NOHqcC?ŔϠ͒6bK'|܍tn(!7"?nꝜ|~CElCG ^v9ܦ#% dS?gbɉ'/$WI#*`HQشӻAv"hOaB2OGz!1w)S{ƀh@xBB6g5abWӉRP4UAtyӗ;Zˣ7MM*'ԃߥ x'ۀM4Su?b&%$ :C- vtDh%%W˺LZ ]$8ŧaJ [k"]Al|Ȕ h18w,B[knq4D&&McEAASRp`^銘MoUU.kΐv2 6BFON.}I%슘Sc:0&j \.r&Q*{:=2Y -lcXu x7 > @x  {IPK(QY0}ՂT&IVQqm4rӈ2H'6./F@1y@*Ƃ3! [jm7zczi{"~GN5'$H2{&^C4]AP >z *D i!䈮NQ\S%}g5ۨ_R(IAybA 2tECu> eIFsc,ǞGl{9^=1i6%WqZZEcv<{o94x :gb\p:v-_(}{Է#2c?yz;bްI %|,YJ3jT Ynb\tCsbI v9RT'n8+'I&0Qx̰N r 01Л%ZuDzz yv߲ U ); $8QЯ]J$*0d"=4DV@<4`|PK/ {`9c5ׂH#Yᓥs@_cV(s14K=t þ?@s?G#ʂ0^;l[L&ЂzfY,L #;@nƪנI(4L*RgIjOG1|!nЇ}nTw@--YF>yKy}(j7w{ډvM{SyGPlmn3ogf%wK TlH ְ}F*U3h@UHFG ;b~m#: =n +b\8_AS*rgO3fq09Pg*R۬2Lʻ|xHMNJZ#KW3h8jH4q5< UaH6/2uGܑyIu/]_ϼ8C9zZb{3P#}4_3gʘ1ڝu Y( }e.H|.c7 gsڒVe9EG S&Wp|OiT+R!Q_ 0gUmCؑT ԅ3pUb~X?Mpvo 8mÎ \2s Ŀ86.;E_W-wq!~#=ih:pv*+ptsoۯz.zO&Va;Ӕ't;n9S{8P8~b[;rٺF8#$SC#@B\Xjp4iʌi-I?mjK,E? w#-qwKA$i,cjӲϲG׼;blIݠ pDPM/zNj Gi)Àiwd#mXyZ2: ^}q7MDWͰRAwH#qȱt!4 VI ,PIM6\ܹb.i6F9J@bJ, AGʒIdf*5 )>r?MVZDK >=Hst#hIB`rZhuwZDGOt &=1!e^Ź@ n3z+A)u2ŏJc,al_v00-@9۝İ0H$C@MMh3=Go* 64h1_X6Uᅆ)ʝܪBCA2NnkɭNrx zvnmM)V^;7hW^70-چ c:dF"M Yrl^uiv'8'4ͫt4HV eNy>PpbDiK3"΁gI<7hRuՇWؙU;/(se1 bD HYҔ}N{w2Y%(n7|wCӊ^RD۠U QۡS+FS̺=̿2&\KS;o^BI~?ȘkC!QwAsax:`>cV.{LeUQi0}{a!9/<`NA9E%ZBmA#?ZDJHr. TzVkzpѫ҈À 2얈<-+}jnz歎I7wi9Bgolinۆ`7Q1(kX*Vf@) %*O[`QlEsx8 xD}J{#~୯_m}!YEm3_AEobIb-ZV"_'stc{6"+bZcD%ƨ9Z 4k%?FUr4%&\Ci0Czׅ5 VS2`)D +p>!n:ZWB&4Pr\@ӇXjϚQe90KwCh3>(=Gk9FGqemGvJ)D:x7jK ='Sh;ʆ=KX[G#lYgW>3k~\סUѼBK= ?Pc#c=D%C zlqZC'r2;v\yÊ M kszbE' AI pZ]$,S3Ԑn[`Hxa|EWnGۺDl q|v o&k[ g|C}4h!A-Ls\Jͧ{XrMv=: _@zPw|%" &;]w9lb`ޘyv^cgo mU;->4F#P1|m#܊r}%$ZI̤ Wd4FErhtSUfzⱑt(9Q63sQCC4NjÎ A<\vVޕB[#g,C >A;S􂈂',2°M^x.z P<v!{k> I ]?4k} jOzPR^z:$(T{ṝON!HJ\vdv>|KjOySJ|BL,ƕlSN`O݈IxBIUumV $aʹ-cC&-3h#Ǿb('1x;閭,aQqVoHDw D7Z@jJ .r[Kw f_hdѰn'"t6G@i>[. &#qg sP~I۲㖾r` &x=uiåehS>@8FWztDݒ3,#Ε&aK^JukO=TzTHJ.BYb N=K9?$$iJ4 b|=󳂈@=++Wj_`TP0 v:L,pWEC$]J :sԅ~ 8-f)AYWbf:IN{*lUxzibzQ2ve .9ߘCJ>x PVgLާZpcHcOխVD$]hZna3R:ņȓ Ep?2<سU0$:aDXhX6x |]!w+=Ng@< ֿ* (vM@aL}*L6i#OěacЮ1K@E+Jsϴ/~x3}[oS7 XmzpzPO"cY|%FOuh/3`4{KؑË 0 zN p37? ݫ;{\D>=ԯ>6JB"Toq #jmxmF&"RJVӉ?~'IjڛVhA' +i[Í={ݏCqx)w_%T gS8 v;mh9QA~#5ʐF4'Zθ2AGCƄO@DP}[ uGebs̷jU؋-qJ"Ԡ1OQh1ՈdJZ2n7ܝ̞6ziHDٚPW{oHQ6hn|E6 11 ˾SRzl+u'-NOgH/ .qVsa \0)\ifcĔhٺc#C00c^(s5&3LmϢ{ˡʅT3HnUę,:C;f7˛{S)hEmAWt vkQY@ YoBqhAu#\ E푁q8z}NU)OifMIY ^r07كL672֎+CB"_Ȟun:i2;i"xbBv2OZTWe @:xH$kpQ#*dDC>!>Ɇ B)LHqw9.Cf 9f ZSjW7:hfUCp iaƧTK%11ǰp O/B 0N 9Ox:Ä`Q.hWЀ뫐/L/s4ߦGYm!\n\` 1O‘ E:Zɕ]#5z3@DZn:TiWN;de遆j1FS1fEZ'.HL,V DLeZJ4O4Yk^L2JLǕ{6D PN?7Hic2_*Y W|f_*1 ?J |%hrDMiShYbHׯFVi)&BV3{1UW _QQzOX1' ,Zp5! >nBLo*N7p%S[́NG5V^˱@1P|p~-V ќydi9.p&%VmJ|6l)uk ^anB*Qsl4;iD 4S '5h >4th3EA5NX0;qAN ޿UYVac ܈e`TvS[J=]JNQޭ6+^ϘVOAl;t3ͬ-}TȎ1= "8^3j e?j e(XĠz$Kp's|h09οs*o eK@ Gl:TV;~ْ~zSA_i#hH{B-3ݫv#\VQ \~vOijRf6E$_L iWh!reTPTvFaX[:_zfUt0j"aL@ӄS'K85%vNi4^-l+";(ܠCsv#@^HT%ȡrH@5zR#LAA{I5 ,G=5qQ?#aQdUٰ਎Vј uZ:k P.ZgFդ"&7#smiʏvdӚ9/M:Lrhy^Y]Y5ʢE{ع%ЈݨI / R {;-)FwLhG1֩8p\op"EIZlb5R=PU]&*/.Xu.xIT~;oBs"|3#kc8L9)v{SB,kוl/]O߂uO,j̦B}(&|g43kebrACA HYe ĩ#`3L2jủtyp0{4TS0st,>V~"9lBUC`TYcPw |tN3a*npM),^L)U4CvF-V^ :+;Ph :O=%|n %aOakћ~RY$I@0W\Vq{ז 7~sYDf, d>ɬs1'(ArqXOwxi8 >>"Ȇ8Y \2)Bp_DXK`9 VOsQS Q"f垥˒ln0)nyw@Q˰C!bj?=Ϡmh ~uϨ+þTiX9v02.Z;Ip<2Z5A!cT,oS`>!Qހ e>م%qwk9.~S.1md‹N?Z;)-ݼ#Y?f'oIS)x(Q M#?;'x¤;@v=m棁-믲YS^ Rݽ PM^?:Ó-zV|#/]ߔćz+Ĥ'Y _?eAprVO_u B*t}Fv}@T yPZHtÇ7I}O{`^x)?.AüO.DPM}VegM „(6q[ w>c T.<]><S;O9E*#Stƽw0gٳ8en~\nҾ˦dC k6Aou7,ml*z맓C1Gs\'(m iޤo3g3Ѣow,-|->?CH >dyY}yBc@%NZUqWݾEs9epzZ\Gq]N z7:E9@t}䛶G;4@%vnY:w+ g;v%9k;FdbZ& *ʭL9-v?ڡgq1k2=ZWj`m;8bBZ4i ns"ek?hՃʠ98 Vrs!n3UݸMqt.4xY RBy8W}}.p< -WWUAeF9gxn 0d3"AKr SJA{.MڳLOMLtm]9&ѝ[^GZ^BH0=0:'šj,^"9VME^ GNaa赴#l\t0I)LR;F Z=]=J!RV #S'i>F<9!=^"8UF'|3əkSi&JBiY71w4Z2~A8VO['k6:4kq<6SyjգCuYVwRˣ EgӮ;ꦌӦbiSJ[m"Byip]MުdMcGuOzש}arb)xdm1+`! Uvr7jl#=-W ݙ:>9'r,ׄ8eTiCn dPjZq'(PзZj3lzCuj/JɊnJxmd 3nb ye(^hS(F=Lt93ZPVL1aE6EX+j"n\f #ae"4# XIHr1}@bLvJBJ3g10晲ZgQ ' ̯^p-_<#chdL'cAXO'hj-SsTCmt8_&:9zq[3IZiy,7]YaS6{<-uqnar 47M*Ҩ^Ryy΢g-*t9@aik΃f3l?>4!&4)keJ]ƥW%4 =i95hgِs6DT·@B !Pr4DPbIyýʫ.hVH.{v}_Zgk ?t8Kc4g%ҡ)U ,4 Y DNdiR`Luzr:fi Ra a*ł3NZ )$JtTO; <R.r]FBñKмW^oUJ9liaw$ ̓*jנyhWC 14Oc@\# ѨN [NN醹ϫiM|:+MDM+V5U&EZB8LSi?KtNUC^ҳL4Lt{ߧP~Ba=d7ժCp91ӄPǴ6YVEnX͜isZ녰Ě6+ާMݨ(!Ш4D٫$'uKUP^Prva'3W0_,`ꩾǣ,ߣVPL+Ub T枲ZMz,CúhxFg~ז.FG@ Hi~6;>颫]֣_KB4ALfҩbxme4cvi~T5R4,V4 ^CW۸R;Xt~L%KZίBZ3ISTAfٶwl.sNZ{iJ ^S !S^iP9N v V&62gڹ f#L+@SV89ߞlYE'$;o&[SVuX5A(4,UՏ0Sq^=2'2b$nQT5֖^oc€\F_vXa8:ͤKcm#>lUQJ_lM:z#E͎!KNzԵpPB)(F''cR\60GVT9'PoZPùE%ujy'/rn?լ+ݢ U: UDH\d*KeӤ_zSI#)ыTx[)x`>?i܀BuLS 8=mϿүꤚgFM+=8@AİQ"c'9vQgMϨ4F8.$5g#J=MJ*-PCRqoA3~5A=sB%hA5э %R.l=`J~zGF9- Yd Y j'nWi΀~Ls4be/%t%ǩ{Х'(mN8)TiJzxPZt[6iJDefZk#ZM5J%XbvIck ^3P u"Z *QQj O4g[(tZE:OՑVcj-=6PC՞f7h?|M'b'M|"=`Ğ901PȮ+2/C,%-J_f\̷N9kp5H5Ʊ[ΚvAP3;j),F>̤!mdSbK0 Xl.,=TEn8khQ\ӎ*MC !4_[!m }y2ϩ¨{;`QM-GnḴp^7y.oBeq_wO|F)k_ZX,,zJ>h@SE}wtG^ wfCv컱OfiXCԩ:4ahikg4קNLr+V0blsg$hJkSOc̢:6ttW 8 } 1ti''0Cҙ%[aF]O'F`+nWxIL[`56}aQQ3(n=:)b G,|S/eG71 ZS9^l$D[BS*JS6kяV'Ϯ^9rZ91'Ϝ²ѝ귄>Y!' itmO^zu3]v8LBajqr($/ɵg[vaeqrՉKD>|`_L''K_q*(82ayUNlPپWr0O4974ߧ)}DuŪ=X(F3ԵЙa1qf|la4d69d$fheX+eVeP b r3ʌL5T9UGij៵V-MUШvZtR8'Toqی&crΜƳj^.*l#͢]G{Zna`*] ȑl_j~mle1O` EnHq\"2&BN!}#ؑv֙y`NbW詨hq֐):הq#8V\(i௺d,9&#٢S%q>^/"\׭uԮƹ'|\gtl)Q6vL§»AԏA;miʬR Х+# CJ`?\w=ÎN$TmGX&ERJx4! pghX0}=CJ&/3#HsO pʝ.t䁁#np-6#=m{kQKyfjwu 'Bq`",w[y*y%ni4Էt?UC^D *i_Tܿqq)*fٛ=[aasz: l^S YC1G/C|ʓWUF09-tQ8!f KѢkZ Se`i56^[}MykV1ՆYeAǯפTIxV&=S3qD9s.<挥W tlSyNckOPnjk~e~Sߨiz0W=%$S-K}iRt9X+A"Cd՘WQ\b@iWmM!/~WM[-6 OO\j^ I82٦dO܆kb7 mDMG5TzP'i,2!hN~QܿmPIBWhɈB*zY0jISkk}t ^MpcbVKq{|Xwq'X<5'hB21HOaFN(t6z1ft 6i}7m \בFti;rpL0r|2/ /Mf`L=^ŁdWS1bw1hO }Mvs؋;}/zX}!9C<˯ ̽ =$7mmHG#ou7__c"03\[QBEY=E#W >1*fo,)y1S$ϩ˖l 8:Tub xb8Hܥ8OIQrrVCڰaG5.:nL\h=JGi{n_9 mT.WazK9zЍcUuDϢgɋ7 "ya맇!OɵXmr1sEXCe!Q0 t&q ZGF,k:V|gAOrG=gvkAfJYC@xAYuТO0_vTJ7-LG jXՂGTQ,:ekD {)YOSw9td3;E P]??j> 4 sapRJZB2%ZkyX.@Mтb(C>tfG~fi/2HYѠzgV~7I[L5Z:g/A6BCXh 6N djd &WDY^_bMq{;;9cmffiX}卤C !+bFo ClÀ33 @1@seؕ UˎʳB%ChgsӷJo1 Mkm[Ь>D*&@Q[oS/6m p&њfNeѐGe2tȣ´Zw^zX\BdAJ9a҃SUm>M̔@>EIMRil>hNK%~7.[c@jHOH}ZXQoY|laE%IcPTǎ*'op3Xv?M*j&Tf`TG*VEQ4?/]7_mkqb5>8i7?| զjtp6gc ۡ:PQ\:09 k6ezMQMnEaba1}:kv츀*GA!{=9gаD6CsO=,8|#RN]܏>$R4i4oq`,v\Vjj#6qu2T/pF)w!d-?h&LP~Qum 3 °#UbnЯBe ݙaΩ'z0CϊL7E n"m +TP9d 9^/(Ms_?2 ^ӴM)"G"OahrTb%7PG~tJ,T99g-nso#ThF{=1P>7 Kv&5_$tp*t&Z| ?m98jh/\T~Pz}h3^Ew*|DWY?7g;o0@,:Amp:^;hSҩ+;Ý6jC0Z CxM:"\5>+OUNw̃KiACL'OHcO jb+V/4W1x IfʠVq5'Uk1Hd 7f S/s2ZtgQ9\ mLa|bc]J-ZKVW-Uhv27v㈑53*VGW: ܈AmR>Jաm&QIO9s9^K4&UB@v0@O` ݼk9U5Vjbm]dς`CV\F ^Bp$ZoLt*4+-|mYtՙ&WmţqU,ujZM r肋,v 2 )kmM RLBJHQѴuIQ 9!ڸ**ix-Iz ppl*󶘂^CR*>7 D/~4r*sf=Ov{[&&`~K(y(LjL3FEVƬcHYj f Z55&U"|o=vˆ6З9k6-A}v&5e΍chO2{/>BbuJJԸ*@p!e~cP<]51 jԫ_`Z>RM(-Yܯ 2l6Ρo0wV,-O^kj&h[<<it=ÒCb@9ٱ2kEwTn H +1TZu*T qTҜ$k D^T@5ju T?h%^wgl>[&nbmlh >*1G Oy(d,#ؤp^iګSHׄ;j?,*祝mJPO.ʠM'#xYEТhUMҦۄ·39XU*t(cQ+f)PU@Sh<:X['n.эmF,xaTMxu&[WTڷ.m1}ؒpl[ձu(1oٚ b9E2I3$μY*tL+ LMdI'Ħ'2wf H .I}*No1<ҌMޚ(#V\D U;jf1~2!zlb#R :7hؐUQb&zt{kaQZ?GjX7 8I) 0zJܧsYmY5 WW(pP񡊔0*=&xL gTB$ɢ#<ڕ̋LCwy:3MV,`z^(ȊXJ$S=nZ}ȇztPѿ[et-״䯐lp ƂM)UPaέf6Ə1Yu]F weHj\j =G+)Ԝ.ׯьC;QCvp 5Q07UyVٺ{}vF8]=xsp4oQnRBIj1W#OqdEhI1q~b;AɍnXfOD$>PRn(Wb1JB"s%Jwq/bx>["]! Ccbܑ 69-Z`Kx*Jᜥ#"ȴӏlCbJaGwruf: k214[2wUWq:!%J2dcŘ ӽΦ !gqP,ұ 2Ov0 ~{W[kdh\SP>v&|<G6ț-9/Nh#W2B#ћC& Ca.ֆcjRa46Q f O:z4koI2B'pU7>TlAAwT%D:93RVEu)+Z*:P$@MUS^kċwY5c.6Gnjdm:v"[PC+>5vOr]f*J,!(5+A.9.;%_N@6j5L,r|18G.:wjWnd¾Uکӭ6(e@RGvCb Ou[d<"j CJ/w7NV^Nw8G,NA*/Y0~ORhx ގ*c.o+Ce:+$ݎRKƅZ#L5y$-eigW̛ M)[꙱+k2SѰJe%xRAٺ]'OTcȫӕZPYD)(!Q봓UcJ~`GCU{r2'GH۳(xR{;Ix)UTH#9Mב׹zW:e@Y:iYaΘZsRQO HFG.Q01ꕨ5ڝݬzPLu|M|Ωi&mE"Q"+UJ>W7|~(39F]AM3`yҝ -_M|쭈e5)[v acFq)j.R[bt'9\=&셃#=qƘlxŠ5p^T՘oȫЮm6ɋ)-CYQ9Ac!L_,Ϲǃ ZC-7Jok>3i zL_೚DI0XP3ucNt/y7eh,1 p!OCZ|J~Œ7t졁U5'ШN}t=,ޠ$P ]yXDKYQ݁E1\fNBkS8uWimچ4k Q =~FѬAI P0]f,/]U6` v=v"ba6nHu~3zą NitBa1*~6q_LeH^1/\! =͊f.m p7r᪨.4$C":{ZO?x!Vw5UiMr_0wf>JF7 lӰ!ؿpfW&$Sfv`uAN?\-as{9hF7buT,:[مs1t &Qt:U[~+cEW:؂?w *;}G9AZeuYgWc^t,湮1['h=U>n=(mԔgayYQ2op謥<PƄGBy t m򡓯1޽nE:@m҅Y;_j:L0Rд5cNc;le}Km l9#i j&x?.{CP8h<$jk; .j#S5*GM"q"9v}6gx93uTtgLejW _z)A7Tbvj]+ iϛm#`/mIgc{H=,}?ёaX MKd뉄/T^; eBg,Bz!Ŭi1p`u)4{1&%4V]^aC%̚&jDl):ty+g(4˜6*hyOffJ*֝SsJvP CDW?Q+riEH~;[`RAFTAk5fI. g&0H65e\("l3s)gz3@JoL(a,p+2Ʊwc>6)F n;W7'‡G}UI.|s-sQIPsmxA>;yG+_BBj ۳Ii >ڹM=blq _#'+7۩KށaQDe%{ 1wGENRKG_]^~B^8tH29a9ñVU^ ł>L /k c!VI.:͡\y:TUTI (D{ )  jY$ I Lh~Cm a9 zzBjP4# @ƙV˛Su^,qM9 &nƽa\zL31nΤ4[A9 ᝩOM^5gna/oDF<4o Uozx^e+jTe:ɪu(U[n! G{=F>snۯjͥS &if.F!& ZGP %Kt%ӔU5Vס9DJU)Ȣ6,VM+EsM1I.L nx`*:ʜ2iy`ty,TvY)_H. &flb7NkX\{ndK pJ Ӣ5%b Rk8=έ_lm9O.i6V\15&ڀA1{FU&榴uUѣU3M8x$E[gra}`xgrͥ,QF5 gBlpTGƁH!{>kGd`9sWH$`(L D :+GiTG3{h<`WuhM"Ǣ:FOX!F%{P M3éE5%YKL'3xy }-.lje{תu֧q'{Jy*6nto4,G,߬x(#+-Fݐ6D5tֳ_F^ԋ0ˆ1s *ۧ); )cPբYQ7ڨ$FC4吘@h`K>{ IX6Ѡ(6=PECgo6L`tP=3M6tJ+SAs7cwLM6\/ޮ`k!~axS"&C䳟1C[@湥R=ۑ*;2yYuz 1(;KY6V1D%7RV\;4eK=xׁ hs ,pC|@~CAOxB6Zc ]DZnHg*)WN㆛1ΐٞ1_*ZB#AܡjhM]H mJ?%SD)u>Cb 򷞙:ª>tP`7[9ߴ997xyc@^4"L[fT`V/7_2yhՈ$1NǧQ'푷2Yjh7km%l۞,:G-vA"\e7;Tm<> )<,(~#*a8lM6 'lxPq5hbÈ +A.3O=x? TFpy섺?Y)~ӖC=>: ؙ uc;T|iHC{UEC> 糾]# 5wSUQVu5Sdm52OmmNsh#N4-D+Jv(>y3惟鴑DW08 ɳaBRJ]5`[)8ޝF? ݔ@<1dt! Hµ)ZCR!iN<!ⓧIm2f[ZakGeM m_2 9N>JSVaH~؊ZxF?|b6=W'Lwa"sznSB]4YzֳխG01@ ]>8Jf͎0KLGMamhHWI='i$3(}lDғ;_5bl-ƺ6  [.|ЏpT.p`R"a=+; i˧z1 :P^ִS|\ 282RJ4ԑuS֎فyV$ƳB{t Ty_V{ף}hսaw_Uܒ v!-o1~@h>׭ŝefP= zoB`psW摻Jܶ@Yj?Mljj K6EϢA:8aON4j'K:ԇM]^ly4g0N4CMӡ!<{cW vf)+9bG!JACL2&: *Ioԭ'l!0sc_S-DHBCB+G:CkˈE tp L]3H"Q9ۜ@ \0[E0pϦے|0-ڍD u#;SaV!я>3in<>h Ih4ke+Qb͕/t1҆f4*i)xG,$G:?$(ƪ"zP'buSE!D I2GC)88px^Y[ e284ʚ2Y_NofW/7;C,Sh2+ J /BUk,ߵ:bK*alz75?먆TNvLܵoթ4"=3zF)ITaTN/[!`ywNiUQRTme'U`Nd|hM*\ģ9nlP=M~~ o55iVSWZrZc*Eמʆ,fSڭ&J-C⪧2>Lm9ky#K]8'ӨWc,y*ÞV;pgcUV;ȋ?H'DcV<0=UU|??IJ}{x*aĦ80+ qMoIfЫg尫\zQ;MO~TLYq l6aZN5amf"i*GAhiGJrb8gFl߹EpP̔ &oX4u'3U:hݾ7b_㽆b+.;V)Ғ' /=45O2S6 ޛͻDRբZ8Iѧl]sk!^maHBgl/nvRݺL1vwNOZҥa;<ũL -y*3B `i[i56eU]U]h2-@fk=f X,,z-jQߣoV(Z8X`⿊+w6?gJ,<4gPP2lLQR @&7t ^0ՃZ '_bL1<8f;6'=UMS˴گ&U͔'9lؐqm0[ܽn{?Ygv6@G:9끌Gb֚CM!:A!3(LF۲%3Ϩr7׉y KqaVt5)EZKͦFKV :4ُ sn%㑠=z,.ƆU$ŭ065\,gVm\HOYaI R_JT+QCQEe .D5THw_$|j;0&q!sgi>TzY\ %ܕ5bV`^|;m%&LZ'Յný IɅ j?u,js=9dωR' I*<'OGTA)iC{_uRd<@{a ˉӊͬO5&;V:w3D u! P_ne˖:a[ayؤ-H; UJ*I=`RSA{ty⫱J.YT^8<_K-El-Θy;LE 8 f3\ͺ9zN:un9-w&~ k@vs E^5yJZ/+X'Lv}E CS8zf˕qra9ޙ,lhV(P`E1~˭Ŏpt7ǵ8*p6<\rE>,E&Z`ˌC:ȵ(-Zs&284MH. JgEଽy@^"i7S¬ Ry7a|xtqs^ Ù4fƓo^3YU A'mTWRKfi΢Pxa!ڻ"G'XEtyY)YZMq\;.nc`q&O Lr6SLuCLwe\P2 ],hs+h a$dR8{ o7E<49KJ /W>LonUĀW4YYz=y HCbo,0TjK :*Z,eїT8" c6ˑ:gj;k4o3kzYPaSceNm)Wa\e<) @d_LS*p2 UJAe+ 375q90` DP2ǬbUŮj&QixU8a8݋uMox6;[YJ ']ABT*) g(WFhUIR\|xLCD}FQ+JNE..v>(^ϞBcôGdqcaQJt' `Bv"Mˮjڹُ%~KX`DSU}S;?yjҾMe=dWۭ D*C}['ijU8/QaHyHS2Jc&#47 %QY)Zp"+ 7P/ԋ(ӯ Y8! 2J`jȤT#5 T0 Uer] 4ynĺ{"aPUfxɭ{asru9 ewؒ "FrЍf:`83%MYFٿ*PlD605᪦*\Wf:RS`Jo`|`N l#ᴍ@ sU}Ÿ:nj=UIfmbG3ۚ`[2@-vHJS{Ԓ46E*TaRU1.}Vϵ]>i(k4ZEӪ)ځ17UL>2A-ov\ƍ͜inδ$&^ P 46NرX!6?H8t JDiSMt VlviLҫ>tLIpv*c *KvU|hnSe#eRd0eCFnivpӃL38mP\Œ zذu b+n EWCi.eѣ߽wcaP!K`xR`_qk""5Z+ҢGܴ6>?sꌊBY<P L}jGVYNE3K)35YZ?TT,'=m@ {SU1J^ <s<2ӛ6c%}8ՏVʲ4qǤhH͡޷,CxQ.E:vV_н*k᛾oQ-z.Jc:rNI~0rt4I(6i%)”~U:hiI8YU+Xٍq`MqXEC 3шֻ3[X8`紏N@N]v#ױN̤ ܩ&Q3YAni̋>EKlh4:=CS][F<99f4ޕ6,QU*Ѭ{jәyN6oACcJwr#<q\h]Rq6嫫N'fMuQ:LxvX;i.I N)i,H֪) z+0¤I6nbJ=A10t(h\(Z"#ChK܌q:7(x!x-L\PFtW.;btx pȋm?Hȍڜғ3;S / f26'\OK(\{0Wa.3 ^U&t8T]S4@fk. 9Kl*oW>ذ7RH=WiX†YVLTZspg(u)q Lz@"g;K/AU iXLsaJΜj:7Ѝn&U4)Łg=GJW>'eQ:Sne @o)O(~yu:3yx2)uAiP&׭Nqk0cf*ts%k.(*=LRP\MVyMiZPЙB#fAA)&xj:%.WF|gmW]LOB$'iW*௥PKz"R1 A6o4l5zoiKՠѣ{iR7f 1-n  X!\2`;bNJ&ީ!rd XfɒmҍF%TWƒFt;qJҝM&Tq1C {IwbkI8Qt^n<9(4ϩgkTYOI*Qnub-(OX;Bw4Vt EG 춈Kh]{;T] CU^)ħcnR|vl.wWѵP`avsf0GekL2{W˺PDaR1~Y%pmE柉ZgeFCPzѾ-mUKn-Uv e[eRLҬ5NA_W]Bm?LzNc,W?[k9TLG05h,U! L%s2"{,-V.2Ό>ZVmcȭOC <)Xv7p.(&h'1&HdR l`SB>?wZ1~m-*?)Eь6+P#HQЧ^ON5*;|_\kL~Ӡ*x !#0a8\F{d.]֚ 7X}-꒼-|606 qE&խЅ ZG?;g_ւ0eHU٭Pژ}ȭrr{^uEb( yzgY(%׹'O k?9#tC'IlǓsƞD ؞<ؘ_-R$y3&@ąFЙxBXkn8((ö'Ȁ٭lem ' >ϲ)ab,x_R I@='|\̻xHu9v [$Vu{tͅo\z #g)L;!!qT'O4'`=11FvQ.jD^lB}գ`i nvuAj -$7EFgBs~}ݧ1Ad BhC Jhl ?C53oU:`0B?}0o?@4xOJ0rPfѕK7œQ HsosτO@{ hU'^oX6,tiQ[Q;y9(~s,(WXxnAnCi] B\'q㭇]j P,?2>CKM$%[P5 e6M >+GcBk+V{NE~hؘ'vlP++IzXsK 1ÂOL]DXus~~XtՓXH. @q;&Jv8gf^Q^Ϯ_Tc10tӋ iXRTffE$ ϱ';pDTҶX{",eD1QF_rZ\#yު6wkܢ?`!>u?0kWף ς6ԍN9nՎA)MmS%No뀣0͛6AX n  ˧iE'FtxxYYգ5 WG xtA/P]]0l- ǚP03"ݷx2hP@-V{`X<5rVo}X;4 #{ɵ7< ͧX:ʒ z%?em Xekk&NlcqE~N*{iUCły e 9U`6/[ m)܁yb ?0ڡwo\+dd. J:+P(wd劾z_KVHj>@ЗTF쌴hm9 _6d.N#t \6&(R/("4UB%iohu MBJ6Ђ'̵o^-8iwѐEj_],*vn30R 5<I#e@ {ehI1m1b93{ +.X/6.LGPd2Ra[n R gQdy*@-ue]4.몕,\)xpռ ,f-+4e=vs09fTN hVRr*IuuUdWWI6BjPٮy135-FH.\; 3Ovm j6Հ%OhHD<X*BBøEh,kQ6R9|L_|{,~ZO@BqhDٟ\-uxŗe4(GLzu /΢L:xJF==׼4l^C`]P ]hWh>/2ی@ؼX* ^m3'wk/A4!kD(ȪyM`!q{5SU&[kcPv?.QZJTs6,%'_UxRQYʪ|kjn  \W \Fx+B/:`{f#;1p^;e],7Es@e1!$dqch<jˍ\^0*Ktz v~l&Bak8xYjbo=W=;Ua#\̉k c]ՃZ \WuZ,k+Bw.h\:lޠlA̒a@#O;bwןO {Qrd[Db=t}]jc B\;G 8Xp\t(Frds~wVz\# ȍ&j9ϥ? L|GE)m7rE"$@Lށ` /o0zK,U<И'$/Gk("7ϖQvTD/E;=0m\GiѦvL~zl U^lbM)ƐZ[`TV@ :>U/,;T!7U̍P4rCLQ1A qo|Ҷȱ-i53&9vz^`\lv1*".d0X!=*hSPDXӵ_"W4GpųgܞcP5\ܾ8ڡb)t0}Q87Ngd϶qyӁZ us#s1WglB*/豙 ҺbJl%Sq umS2΂$E~/ zxyxnmxXF1^`G*xmZ_4 #W,NtvSVEc@}AME{g=xJ> ecxr#,[ %ڀN oJ1^j)q8U8Txda/#M,[X wp<͋k-J)ș@Z5V8ڪ(;}FAOH{?u:y*/^2"| -4%:A^PXK~X _}M٭R_2ep W4v;mzm9w.z?;v];!nsehU^ؓup/U%_mA:[~]E䚞s_;b=.Qrk-~Pn^:%uڅ*qa]su`exPmW\#bLth+gLDi/*SKKm FE]3d{YM3V;(v6/`3i+*{ _l .p> wEw\2 O+"9ɚ[>t ϸ~ٸ}↝:9;I7:o5 E§m?#.xއo+K;nm=sfT6Rz!e #p*fc=? *^T4n:;Ղ0u/a9܈1:^ 顽Ќa[2iKu>L5#l|̓O!,@;Yr 2CFH*aoyƀGf_205}xZjtKe|yn T_٣B3c) ~Eid^  7C'X 5J9 Jݷ_U`u3+9#dYPgj2,^'sN{ߜ&~TS?$;אX^p&1\E̞9'Ty|K8ȕtrպ</!2KJ6$ ս?slEH-Y@;Slȿg K윗33(>s掺'r)$r ٖJM/bsJW02ŌwR :o٢-w2&HיizM"v2)Mb1 y-^v2STE^4qME#d4ӆn-dAY7'Ֆk .dW~}M* t4'&\,VkޝX8mWBZ˳’ 6$4D}4ǭ! )C2V]gT5ՆԿrײ)8yp_?$$JKK#+$g'2 ֘/ԖA 2ݺ>9䊓fi]zzIJE^ztPxvv"dNPG9ظno8fOG,:dN32{`[c D3[ (%W[Mx9d;o*5ͬ9RL-DZ"5o׀XCha0!r7ȋ`oިaA{  0ijzp}1"_a8 Os#2qB$)M}RMg~!J3RE>հtn^2hǻ #$"-"K#"m+5Lu 9@Kʂ1Uu<>7 ERq.2Hs]1jdZLE /ޱ)S/#Lڝ,+d\!hJJ}"beYm?,BjҒbqm|!x RROj$23}$CGl3U.wMPbZއvh'Sp9@/B (3п.ƃI |{H(U;ľo%8hTHd"~e)N.R $-; s[:\fVң>- Q"'L,VKѥ WwMȂzwIA #[<I " EXkca1 șP8. yT5}yxFmYKwQu/Qs:TK,P僕SB7==] [ۿ;8L2:;<10uDmY ?f\{QL L4Gc 'M D飭FDDaGfI"C 獵s)}. % ?[!V[PfgXf@(xj^g4NnkN6w1-h]I- 3_-iFXxq%nԴP#䘲-YE6XivE2շGZ(ٙ75H2Q)"b8kU㾦)R oJ3o6u!3EC*F\27lkFhVhfGLap˧t]v眖P^+I銥I8 7@̩+5 $Їc}8Γ27IgXX%&%}aUуV)#kf|L>k@0?97zٞH(|ei"e4d@%AmK3J >\Fni?RK1Stݝ ae$7`ka_rO"qhtip.~PdXX2ZLiiҔLwS^C6pd WVN[jΨC||kȟG+:vz&JzOSN&+=YY$T+uuY]qaGZQH>\S]Z1L ",J;%e^UnV]d8<2 dCZKYD$8Z/'DWM*OI)Kr2ڲ'k 8u%/k΍/:0H5IbȄ5RŲ~GaβP}P)wU 6ljb_OŦ+CYׄfͿjO(<ܻcb=bkP \օ#_ p[3@y}7c%j9 wu*ry_`Lu5*ŗC~0braQ6:[/RSP1lϥ uOLC^yPfSP8&a:0myb,v0X S11Nb̏E6kOcƿz6g0]G6 `! uV2D+hЈǖUӰH&X~+rv]p֫c*X%տʅ`KԌaCT\ ,QŷѰ$U7|YsfW^Ra׫{8q4WFD!F!C*rpBL* IPf0W8'S xL55$KzÃ(cgX:\w\{{^v:f$]{ qֆMz,#c9/)0ފ8ƒ{cxT?{WyMoF-ҵ] d/vt]/p4_%@۬R,Gρ((eݓ#~ƭdj@ -[a9LZOJ#"OeU9od <ёM;1'x6VqsҝvB.i c2Fʚ8+JOLBJS s:n mSմ-_8AUxput@jdž5Sm t<`^.+n[^ziCk[ Q ^ m^%>=sug ++g𺞓`Az^@!(x*l ISB 轇%\MMFMV"%$&&Yɒ A:h<:4ZmLe Dy7LQ|NR ֤&:Uli~/ilW 29m7<\aldss0(XwCl|?qnb@:-e1C Iu# -/2 [6crx_@E/akhs,YCDH[ B( k 1"lĔpi:N#lr[7Vp1{d&h4l{|I4vʚoTqG`39% {CLd)q8;iq\45o{} K^F<+ uKZE)ɻ}t~+gb"X7u+4e@PTgXy[ ߾hlp/=JP?et#6zגt푠@C`/@A8ef .@#pβBAφEgܬOH/=r)Z' '^gHu5a1 T3) ]=ӳD>֨5YI*:.WJ"GNf쮍'0rٱ )$!/#ݧq[zgtw\1Lf[^6٪I:&'' z~}c&kxŅ?vw3Omi3J+m738~ײd+u;usl[e^guE5_y=6WFNޣmL\,ÿ"aLK߿/>Å(aނ]W^1.!ǶP=z`ukv|0>AneNo.[g咩Mok$%_NllPڝ+t+zFF縤\gzvؽ3rgz;ñ]ǔήk_1Y[Ī[YIK^Kbo۫@6S׎tu6XE07$ 1Bjݕ~lx eUm+'rаjqjS o5|2"[/wix{SjGhnX$%wHϻ# jD4-7, mH(#[ 2pYc}︦ &y̐Q# zd>(߈Zx-+a4qPhCz,wm݆શlZ>Ўm5;JOz>)kAX&=s)8Xol~ bӭ 8׳ةT`ZL7SJ+ߌ6H~OܻytH¹-16.ZQ[k6؞eRv)s9139L"Dy !kJ0 c\ o섅Jd!1(,#P;%un!1OOnyx;;4TdM޳ xK6y WFdG~?y\Q4$#puAII ""o.Lr6Irm2YZoԬ1(\=? |d1LKrPj0 \>[vBv[VCvPg_x*cz]\^%s7Y/L+cǑ̋eV7iSbgq@8щݱtct׬QQd265­k̏ Sr1ԱPh8?$ {xG#[Cd&\AoTkWJGl-v0~Xzla-(̵#/~72g5TX?UPf]՛.`ciFSg`S(}M RRcvA h ]0{ep =VEFAKoU_b{F ~@ >z@yVa0/w >M4]g̡O/(](#IGR:|q.<%o> L=~Yh]%j dž \^vahEl?iu8fXck1 -M?T 㭾۷x/ &OR41}iru9K8#++3&X@'.Pƨ~a߹HޡSg omn/A= Ģu['s 3mzPt<m aU @=6('VP~e$|W>,0U̠O(+&NXV}ɻmXKNO0siTAA;"w`MFmXB݅Ds8@9>/$ %5A >%L=~[, knymIڃo}WJ \|\F*Iw֢'.;>@ [܃:VB  /q &1"&I]0YphO>uoTj(c0vμ&.PQ!|E[$tɄXLmU$\: #N=?i ٝ!eLz+KMyWi;$=Alɨ>pu-G^Wx #n07_5z|`,L~m|b VH?`eI{zOa\k+ڷy7 }Bt<>=&zv jck׋:!l}zI~D3oj؅[ sטE  ḘHL5jlY^W֚ PJц+|:r=]"x]pK={äK^vWt-SA~Xm!!CTd G8`h%mZ6[H7sLjW-; &g8O#-3>8杀kْ[˾$No9f͛5ߏJN? cB0ԟ?Q0̘2.d! սL  =ՇGȗ*1%mR`z枀ePj^ѐ*6sQ 7C7  B '&|13l[XuPsO"5}2ɘt.M' r& [R{LYu %6U<"9r'~87h[\'{ZmN[XNw[#pĊ93ǐ4GN`LE1t>xNab.(߇W(p1~L@˓{/)% ȭċhfʴhRL)܌V"j>N0BCZ8t}fGQ}/]p8)uI`JaHgi~nnY@W~LݢǺzi_m=]B&ΫɋAŵ$ !V(U%~@OB_Q{xb,/?Sblo 7;SO@[ c dr`/ÉygZ!pJmë j( _"{e8T,%Z헄/lbKJ/Hb+Sk1lq2z.Q'U/}DE 4{-w0X7LϺEQumvg(aYhͱO>Nԙs}kf_\P>^϶jbڹ0)^6gәٝa<)_cwCq@y_ƙѱVX4LSPHۮR0~j|a6{ \#H7 z3?~-3uFrJ:GQ7D=vXV,bmCR-Dp2aȃ ˵ sbԭ\io! 7cDz}̘b&C`,cU %`@h!5d{%ˆF_ ;oӝFMˀ(X2B-ǩP]Kw㬇3E>R`fG3xC  ȀKt"^PMbjO/96l%aXзx~j0,>K ~"(װUc`*j-^Pܹ}~0H8>xQ F˾J2 6&-ס%?G))3 Wu9Ǒ<~e? KHҹni/'6s'\h #vl~|ЪSn* p*91ŶРAb!۲-a½Kl>b'Ŧ[$TlLu5l\xºOW<5T9r>bU}(`=6XQN:T5,ѣ>w TncwDyAWln'z0%YZAoM%s< VpT9gu7[QBB/B a4q`@h3T'ڦO盖>iy0AZfnˑP=:a=vgձ0lKPTן*`kXeT*0g87,j81 P=G_XBb劘,1mǹg:4*=1LM]^c^FLmr~zx0KU84Aal{MC@9䋵k]b[ij6,1Ϥnƫ% ;fa1M=^gT`cń$sf(Sk)vhBc!vR3p hX0ʵ`ȮϬA'$".`Qx)P`Ⱥ&:h"um0fd=w` {i0m }:!` yEymHzX owp'Gni\fT;%RmC]b|xh4.+|tt 2U Cn/vL Ar17HXLd{?@QBrq/B9 x列_xSҏ@Gb$`lw?s{toET8^z 0ϨQ-79TGКi4o2@J\0NQd`g(B'1-18%N!v&H{~1&㷽Zgw ;1{DCW8|D+5퟿̞|nZ/.2”|kY3wJMz,'懛)5$ʤXL~U[FRXHBǙkV^Oߟ`o/DW#DСT87Y1Pks hE H?l8/LO>褄N*r>"ud^|2sM^"@k H.?./EzٺbnW)^s>.c<%@$~{kv`sKcZf /p`6n GWorH{-_owG^ Fomq^P&_H{@ސ8KTݜDIS9/ 7^w577^}dƪ\h5Ì=1^ /2ڇ55Ea&4 }xxE73/2R1KG{IT`[V:u/Y10p zq^U.&A@7gXTsoiO+Zs:{hLjv[U S҅ʼnݒ1ӟ -l -^M/i3 Zn1ٿ@.] dkD͚].ɐ)^!>]D''laU }dQRe<`W?Zb)Q > `1LUZ\bV26;4;½%ptp9 K߰ I)s*!FD{}oծ4b feʇlsU?-qm e( -`0|ߔ*xJwDH>q(G(! oR?p*p\[v ]IUIAqWu >!!>Q"QHC4=]0:0@rPtIVp~#nˆ 2PCK⤧XZCqtobЈ!T ،wz\͎@Ck8O1!_sEF]zU3mqy>B"x3̓F*$ ?ZtXE,X7$ UG5Ǭ4J?Tb]ɠՋ?RC۶zFlߴـ{qRijdND> sEU䚢//Rl"Sp"YߴYq9*]ZܚPTLj!c:}Me7xLߜӂsI. Bg=v$sÔ!W[Ց-8މ!K-i *LY:ԷU|3Uu#lc๜ m4dwC?!i ݯ߃R/ Hr8P{E>G˘,lP@e<~qXh B#1~,/R s[\6t+zfRSU'e pBMD4KV3`$r5Wyz8޿>" ݗeZ;0 *ᘖ-=08@`;-9,N?0JwMXHUoda8ЌTj<rKnc?@XEDL0'JxT~w\ 4(Wm3?E כX@n\ރ?]Kx=O4 feS`3" VڊR"ULx ,.O. /2ML;jEh*W; _ʀϖAzMu+}J}ڔ(~7 O:G ۧ|C^XM Jz4XS1X5(˸[C20l^/o7/f4'c% VcҲqEy[&ũ?5,=VNkZhnNӧ ?bՙ<^v |Y%Љ=kVY;`a7 b\Ym9}n{u ɿ,'V_>ysd I٣6VXta\tce{Ozc:~]laGP$(aMK%*\፰ĺQp8T;% lgj:}F7O5̕Aj;ݖgyk9u֘\7n٭,^'&Γzz,L4̛ ^~p Na=s OmNpD(G*VwQUѣhlR~ftYDVn>Oz5F6^~kHO0,֡&9E: `et`Ef5G@ ӑ;rHٚϸ-1pݶ}#֍'=-VM\XMڰ^T1~p;1 ~/:|i^7~e#'X|2/cSu = F⡆1e07y,Xq_c.oK>Y1K)}?.HP*$7 UH~鍡,Yo\1380ېZ,(e/o?+t{HV.߅$55S†)*\߰51x o|ׇmY]=buȩ7_S]þW1B"aE0C &oz...+h;=QrU~OdmmyسnU^BHה>54ƾ>UGZQ]Q&0DKL a5,l{"+0 t{ >'p~!ٵ2W^~OPJWy⵲BYf9:M}`=lXE4"?p'}%&۰=?2 ͽ~|`t;)G @(u@~7=+!Җ1&&_SUxNENn~g܈ n4 S Ap }ۣ(: "%1(n. R1Ut,Ls`~!닥ߑ(у*RLp%Aa66@2=6$<Prn >oi_zˍQ즃ꆝ9#$OL)7h3*T ) RL$R3\p3нb1j?$\P'LUK V5 >$BCxABqBçls`fEli|SR8{z}_;\,vE" VE{x]BL:X2B8`$&XM sPF+JH]Fx^4UY*KkAJoB@̀X4_^S*ҶɡׂD*5;%XB-F(k~aEXNyiz$Ă=`SH V%Lg:l;@Uskؓ'Y8XC[6G1gԿԗF=pC.+Yz42Kd@$&5LL^"b0甁ԾxJ  $3#\[ׅduL][r*ޤ>1gZZEx+n3d_|~Hq Iߨ.]ګZnںǔNj׼a0t*oK6/ᢓOxv2yK wOWj6 HxՆ]!?S25Ѷ{dDY_e՘-__F3éf\ _q06 M,Su͝SW4gW3,3K?\ Z-aw"7eAyRAI;\ o@GdTi1đ ŏ.(CB#IJ[G6lؑ7I5E盎Q5(Q o5/ռN+p-)h^i}BdLY9 )5$qXӸlcʛӻ!D2:̵kK`шȤsx٣1,4l*N-fsX %yk)#3WNt1Rv@tFt Y36Wf6IMPlP\@%uo!q^"(G7sנ|o);0"H-2/v]8J5fLÎg.qp%mi%=It5st|&/ٜ_vM2])jË'$ɏCЯaq}:oɠ$0/AHp@e=Y$D=S6uCi:,"TjwEǹ/S-![j5=>` ,qOm1?v^Rp׏3d娌G#D?mXnIcÅO<,)aބMDPOgSM! ,DHk^rH.DZ>eSf\ϰ"`>DPtGYĊ \a1ww-"i$* Sy7W[.qa_Nz8#1nH{蝆oG?(\SV6GShhv$<[sj93,p̩+/]=8 ;W; 6:S7hk6*riSzldVEzH63zp#8Rpz̼vpF13 N?-noOJP+H|ub;~@Ӕ]ݵ0T7❃2cXeݩ"jpucf/\uʖfWX>a>`(:/l8 Dު`_$;!HR6"_ټ8}XD>_yvFo Qk[#P27ڥ7o85ğGak߫?\(cd<`+ֵ'JBLP(\p()eTt()eʇ RreVveQqhieUuhieڇSseaL;' 3rP8P1qQ8XqNI8T iqY0$sq0\.K3e.WpWj\kq 7f܂[qnpHhXxLpW^܇@&C#`*cxOIz| >؄؂ _`]v=3?9 ~oOw2_ !EQEQ Q%Q QeQQQ Q%ꨁڨhhhhhhhh耎肮GOD&ѯIkD&ѯItkD&ѧIti= @D&ўI4gDc&іI4e-DC&юI<ыItb}D&Ct`D%}It_ݗD%yy<vI]mD%vIt] D%tI4\D%jI4Zm\MܔKn 2[mhdxfFbT1c11wN܅q}`"&a2Cx` Q<S阁 9F|6a3`+K|`N|]؝|#~7?'ػ? RPEPP%PPePPJ*jZ:zhFh&hfhhVh6hvhN.ytE7tG~胾@qa80GHq q8'DqJbN`3p&sp."\Kp).W*\kp-7&܌[04av (8܁;q=~F|6a3`+K|`c'.|#~7?'ػ>P"(((((GYCyT@ETBeTAUTCu@MBmA]C}4@C4Bc4AS4Cs@KBkA[C{tȣ#:3+;z'C/F8 Cp(8G(cp,8!qN)8pt3qsqb\Kq.Wj\kq 1p3nP í c8F`$Fa4`,a<&܉p7L$LƃxL<cxOI:|)63|/ [ _+|v|;va7{~/w?}_ !EQEQ Q"(((򨀊ʨꨁڨhhhhhhhG[C{t@GtBgtAWtCw@O^>q?A8P1qQ8{ED{D;CB;BA;A@:i4Fh4Z>Oh4Z=Di4y-Fո:Dsitu=FGP í c8F`$Fa4`,a<& F;irFip NDo͛FѸimMNTDѭijFѥ4L DѡigݙFoљ, 42L#41}sa>ӷ oc1&L ˱c%Va5>|1l؈]~M،-؊m2~;-v;<{~/w?}"IPQ)r("(b((R(2(r\t^b6+QUPP5PPuPP M-m] }?@?ǁ8p8` 8 Gpqg3<_ W-Sռz3_xlن?պ\ռVʬa' A?VJW5LboPņ{g[Yk]ef VsL,gA= YPςzԳ,gA= zf~[WYsk枕?[XUkzfY9s*Uqש~b}ff~Jt͊f8XVW}VQ ]՚f׹vgk{+ViN9Y!X+ֶDmle5ښ}ږ;sN=dg':[Z2^>k.>'p=_ۮ'L,OAMO8qYPR]>祥^+JLx =^ݰW/k&׿c\?S/xHܷɅ_a<گ݋=?/k2Ax352uB56 nZs{qJ}׿;yZ{}52km޿UlY+f}fDk:6gڽo>܃7y.a ޽63XpC3}SAᙾA6/XL`QhONm+}=]xtxb0z1"}rfy{fffx<,3 <=3 l(2#h=0ToS{<҄[i:fq6 `|lO̗)9=-3Ҍ2gyxNF?6lᱥV59Qɽ9Ή4 4Jj|ڠ鬴UM,SOxlYTlIn>@S65hhiOwt*~"g2=E\z<;+;΄tK0'Ǯ٩fPӃ_tME=eA/Y{|<{[{|<_9y c?o|W9xp go<&n£?ܥ}L{,{ *=_0_jc_6|ȥQs>mK՜;V:Ma{q5Wܞ:8$(SozJjQQm>=A5hN-#2Tls$Yo>iO8&OuWiWsG;yZϤg \mOKI<s=γ{ܛ;4. 4JgEZ6h_by5h\t2g֩;"dCh_aą5h\t*3TX?LOs[rך~qiM+As6;13;܁y~z<"TB&ʚ.4ooL?H=tosw;3h {'={(=m1{噝y\׀js>s>kP졞mii7Gv;9Dxܛ;4 4Jgƿik=31=ys}HVtz +Z}uJ+{3{HJQSXc5Rjvgu#-T5u:;kzYfEd^:;똼iAN{YcL?}4't驸fECHtshw60yO=҂N0_aOίPef'쐧쐧>y:OG9"Od^:/;#MUZG)St،_3 t_xu<'pόofB^w :OVSx|cSg)!G<6mxָǖ[Yk{q=K&?fw}=t[k֞Oz|Z[|ౣ/oHkg}XLZN6޾Lsl~ -hb}gPOg= Dd |,!9?]k2z걛}npy|ָ:C{Y?{fB\scҵL$9ጴ /Lp~3k{y|O:߸kTΥZ:Am{Y8f{}p<1 },8gu_ 9τ{#kUOpvJ-1kT$\3iھ:f}㜛M98?Ñ)ԠH<&|03k_/Tm7rVɴޝPzV$=4M[yИN.T$_[ؿ3c7{Iz8wѿ}+'yOMzXnqh!sK].Fwؘ5NP8~ٿ1k{8ߍh{B1{}p;8bZOi{7!ב怚4mpJrƸa:47;9 \M+o4r5NRA7>\M` m}O*Ug !kr߱:hc~6}*<=4qkXև9 ľsIx'a[`=F}'5ψ?ɿ'qlM'1_O8npnl!?&OzBMO2ywZ̟LƻUz&q.0/DGlk;ۦw>C?8'o.g36YAejs1I]:aj?+k:и?IihYyt[g̣06=7ή].Rk~FP2{sFij\q%EGA*tqu~<]5ȬSK"ϵd^93}|yM=-yӞqcy~驺dE_+{ɨо=5h̯'LkdfԽ63?u<#TI|}{k:{+ga>A?Y{`>AX{{&D^_M\Ӂ߬H}=?*3o6oSfk{v;9s?ɽ9ގ4 4Jjߤڠy4:2Zf*cVyn>@5T^o'==~Maىf<݇gf'26tl}$|}ɼ=҂N}to^>|@y4N zZ8)OY?z<'+ڧtqj0oǏ2SyNNel6;9=3?d gGOLk:8tNrO=f>A=f>A=f>AY{<<y ۧtq;c*o3ͼ6lM;)c3j0> 9sbro#Koz\FjQ8; ?7/@`%NyǕu֋Ab|<3^yyzKy ڽ%Mt*R/S?>yzLm7Dަsyη!s3%=-Dz֘XܛHBQY+zDj8; ڽMt**: ju֋<ɺΎ&H :Fo͠N{[cL?EfD:zAޣ2>yzDdl=&gX#/A8y{JSM=&6"oӹMېÙ]k{D'Yc{S{sihx{<עpvT{0GZЩ4zϜo=|*c"O9ΎsMt*x;i/SdlO0SYo"cCby{J`~N{2yz/Ndl6;"3?J2OB*y{J+N{k5f>;5f>;5f>;5f;mb7#-@VY>yzLm7Dަsyη!s3%=mZc=ox;7ۡ;oxǻH-gA&H :xOoZ{=ޗYt~n>@&H :8igd)26'|(SiogScÞC&H :,_g#gf'26ltvȳef~"c9"VdgGMk:tNǬ=f>A[{|CvSQTcg]H- gGA5h:w\f*c"ɺΎMj:#iӞ~cL?UfD/fz26-Ezpvsht޵x;ߗ=Nel6;73;gTfsDy*_5@cy;_yn16 h16 d16 |&K>t޻CݩUfSyGm UfmL{_7=8̚3w=EvqDQTHoZΎjQa5h:Nf*c"wɺΎcM#j:8.iӞ~L?UfD2=UyN$=V8;9o:o]ӁIJ'gf26򜒙lvsjf~*c9"<Ύ tq鼝zt[{|Kux;]e֩26[/[оt޾+x;We26'\جs Qϡ y4 Wt~y\lvsCfv*c!ύ<$T8;/e:o_QӁMvꕛ=~m16 clcl3;#/AVyښ4f~/ݩUfSyGm UfmL{T~꟬9sп{sihx;՘=ԿZΎjM?tq{ou֋<$V8;4o@_AOKtwجLOUfEHΎz^it޾Si;J̯ef26٩MfA3^Qxyy #-T_&~CDަyzCm:w|2w8Sޣp aKx,i~O)ɽގ4ޞrڠ_diA:+zYl_[b2oSiW zZA2>yDdl?"gH#/A(y{Jپԇ"oSM#6t"o6dpGx@Ly{J=-v=26'{26-X?diA __DfC3y/Odl6G鿔ShdiAA2>yDdl&gZ#/ݭ:y{hފܝPm1TfPy]m:߆Δ:\Cػ7z3=yF oo 4 =Ko##-@: =kxWf"c"ϻɺ#-@AO =x"c~"2=y6&=8;9?h2oMx{>ifv"c!χ3y6Odl:G|ɼ=҂40gyeK5Ʀ>AZkM}<[[kM}EvCQTcGOZΎjgLk:)XguKf*c"gɺΎ]Mj:-iӞ~~x; 'ff26|?3;TfsDy*'tq鼝zTZ{|3ݩUfSyGm UfmL{R?8˚3w=~FvqNQT\H- gGA|y4.Ytz\Yls1YQ}}NM=-v<~جsy*c" gG=5h\̯&3;٩fA2>QyDel,33XxGKA<<y ڃ#-TLPm1Dަy]m:߆Δ:\C{Gz<3w=ߛHc@۳4ڠ=xɼ=҂N1xux;]IOTyO׭pvhj2oSi 6%N{:x3x?UfD3yOUfE+ڃg#-T̞_ <>;g|>;gDfsD <Ύ Lt*x;%/Ddl,OgODf>A+2^yy$8;2GZЩ4|1c"o3ͼ6lM;)cu5x=F7yc#k⍴Vyhg8}xǻ\o!k~5!{=~9>౱~ x|(?q 7%c?챙GL#˓c -)fG3s&9!֙Y{yFȿ kf1{lk~X4v},|S^zyvBEO ߎڞH&/{`,챋ǢCZk{,;Zc}|Yk{CFCϛ/&i|+Ϩ'?cRg͹-)۫TF٫==豗Ǘ<>F-j7޲I}=WF޹Zo}Gǩa<֠qӪKz:hLbƃ 82iG3{==NhJs{̷^ #D{ԠqSL.Q߯?8{>kJ3yO[Q;C{q~qZK5Mw\M5s7ZW}ߗ~&';>yW6wyo ջD 3uD3kQ:׸*_}mv~=d[Y{'j{d{޻GyNcYEM{ȜoQ˟樞yV~g>RJs+e8Js}i{S6shRN}?<&M}Enr)wxc5.#ZjM_kLJgi1!8gQ?Qmzg!]Jgi0'< 1f;!79 f}9ҝU33C2>QiOgxPg/o^Pa'l >3\\<;}XZg3#A>yYks.~y5 XRޘȓåyFܧ0 ߈>w؋0!?ϐkGЭ4O c3<ע/ڠ=|t*gH9|s:ս[/ [_D}&3FZЩ4/zZg=E~{ O8Sqoz<× =H :e {t~×{"3;q_f҂4~d)8]/lL-0yhd6iA=-~cL?EDgz*8-lFz,0yshd6iA+mefv"!VىOv3 '=&g^A=&g^AOZ{<|N;[s.߳gɽ9&4v 4JLj9RQmLsM,1y="_ƒST8NS}T8GNS{9NS48N|48GNz9'{dߵSߣ8?pj#?pꏜipZ#8#'{F'wo_黷r?9}?{i>r?9}?VMݪɟ~U?9w&rVM;߭w[5|j'nONݪɟ١>W|x;'~Qƫy g=Ny}}q*[?>;慻r"r>ZFflW+/\ H/u ?{)0.kͥSN`<Z`'g-kztb}Ç_u}x~8eP֫cD~t}ۅ'(+gk]RNpg (j^Ʉb8|&)x~2P)OU*RVYի}ۗ&+U(})iW(OrRn9jќ7]6?r"%"{zt+]xz_-`[]_8M PdnWGN悜Bʎkk hAٮ9 Wxs&  5றFNS(ߵ/L7kf诎Sp k4@vm WaQdHl NE$B ꮨ rhkj9sj9ԹORUm+#'R:ufCjSE6DKi'JҚBzFaZz)&IvDz=/??&a=s =-hFx+J+"nOAc &ᇶ=;GGk(epO}|Je{ 7lr*xWU7`P2(m}~Uc4\k$/ = p/B]Uf#,#h *RZ!Zʒ~b0)*ewu1oPKҧ/iG hw]QL-K=R$zjQw+tHƻ5S{Mpju=j9r ӢBImB]c?eGVX _pg#<*Ocy8-4Pvu|'rp y)8rru>k/ro+y 9 @ѕ~ )Q]tϜHQPmTRnE'˓kӘk~ć[W <;P(L̊nȷJOJD| zuE:uEҨuת)e>Sk~7|7p6  w9n!O@C,r;gN:?w$(>Ɍ9:n+*z k)?r*5>i⾿Vb䴄R@2ݱހUP\g1{&:-/) h^\KxK_WRsW Eef/w+|(_UVҿKoܥy,|&&;݊n{|[lx-^1y hB<\~>Agx|Sӛo[/{i6W?Y5C'r{^{s3G.G7DUmj/eBTR_Rox_Pt/\it!E)k-> Btnя'7ݢPXU_D}'6ESD_ ׺Փ6KǠM} NUZ rćLqdu)cDeG 8ſ7qޑ[kYDm>~oX.5)fĽNn)!ىDۧBNnwn\\#ќ\+̢ld_ey;߹@N> ;S>w ^ov@̹OvZc' xVs3&MvI'e{7ɀxDN+R,\9+yJ9 T*_jPmUԹ:Ո)j/u.8%LFa}ǜ}.U$^:{)kJ S:u˅NUhZ3w?n6(gl7_.K:x'FNJB9X[iCfO.ȩˈRo#!Y@IT {e[Ba7$ #/#"xJ]z %wzHYlw;>*7Ȍ8N-d;~Te@2h߶(/\0nBBKDUP\;^wO*}ir_U__SdP˴Spr஋G  <梅XOހG+0bzf ݮUv<)ƛT=㴻V] ]KpY孯 񸹲/yW}x/@ٺxc*ΟY(pQ_A稐Nīg:5"Iɠ.pO)*npYOvkW}~}ށBe/T#MwOΙ2Fxe_U=p@yU]YpgCfɄR@>}ʜisaGN{,m?<`De':9 #L%8*ٽC٭Ӟ34ܳ1t~Ns`ħʄHэP(jS)dirٻNjܜaw&9 ,P[K wxtAiH'9EtC&(b| i6hSNdP}nnikmPKm7 R%V`ɴ)Mp ?#ev&zynNrBMǸ Gʗx s0髿9I=_EpnۢWϪ~r\wd:{s|Y|?|Rmyd\*YٽY\nmYsm)Uws|7˙鎬{vϏ stY0o>?}rl'|[bߝˊ dluTvZge}~dfnG3|.9#O `]n5?"w&fBpzy4֯[w3̢ϕ]ygb'h;)OgkQ3wX\֬}9I HYr&ŬҰsీxYrYkcgs)۟<dža2%dYO3J! a>0q}3˜wt"VwbEf>oɆÚ'4-eڿ1Rd>SHl}9ןqhNjtfϞsgnszszn_\ƥfi& nȅ7stR3Xov>d㲙qUe@9ZXYÚ:yoͱtH'j|`.w1][y8knxg$o6"w>cky|7>"s'fgascތ{Lbsld";/S^D,ɜ2iqֳW#@ `9Y,XVd9 ɗGٝa𣏕Ɲf&XP'D)q!F֦3@<9 _d,3śu I\U89m:=tp>qCqGdwiZCpΝxسbY ]/3&bG Y)l7~)n8$$ !y_`K 1cL8櫙΃.|#XC1M}3~gT,6tfqcs.͔ߧv.YXWPf\jgu7acKb8ls[c+`Y,da/'8[hAIY$KN.ue8gOdG89 OGg%tysm uSgvrrO{КYG"^][\eB'} ~0bvrk4L!#źX㉳ x炡9FyNظ<s"'^Jt r[3c`C9YwfnN'w=9i6XCyKd3>/"i8v#'O9I>|op@v5?\@(cegLB,AV>#Aҋ}*'> ,x?ɏG d|3x.԰EY991 5{#\a൐4G|5ć/ "#u"v0_4IALc],P~7z |b զ_|.Ao>GK: b9dKжk0"2uy,qh6@τW"7 d &e8:a9$ j_t N=s2OS Gܙŋϩ9h[yXFD8$ LjI6H#u%N:ay1YIX<Ӈhs p`E>X5'~r'g3N—A$ m+4]4iȘZwveuK-=L[g/y ]'OuVfO1і HLx͵i mRd><Ǵ{oxEiǎm"Kn_fϝIFv|B"z9͹862u%iq6\t/i l%ͧzX4K<ܱG899\gNH7%c 1̘z';kǥ8.vV'0- >Xy.xqc?YqGdQs ~B͍`|yKv~+Q5@/hc3nLg# gn&6c|EĀC\rxApo-!H.ծׇk =~,!&WD<aHIkY{8$>74בƏ,bF^(:fpp ~i;9?N M]#ğ 8 x@ћkt%E &nr;X]wp #5{wwn2^[ wQ˚m?e& }t_= Z]}^y.rͬCH HXx $YIףI^$P[T$K^'X9:2mx ĚL1JX8I٘r#L'Ix<+0bΉeiA;ln&)?jk2<<(x2] X(ońi!^3d\'۝A2r>D(r~}AƧFAlg']1Q%1L(ֆxBAҷS7-l^Z ^1 ?K W9zgB);Js1nfh31s2$qh0 pZ/dI\5q8t\ڭhG/>!I0'dn3Ȃ?HhIE=& Cꌣ{9@dpWBñY 1-"2}%HP7sa&+^ 4X]%}טx ržXAl*Z* $x0Ј&1k>XXI$M1%c!jP0X0Lhqĝ\~[l$&;8E,ʝle@@`WX_N > ,X_80 E(sOhGplQo ΪT(v$щ{>\3Pɠ|[ iő8k k{^k^$2GTIq"o5d2)Ko9OH ȱ$ wɧKق%“ iYoc#I&p -UiQv1~? _a"jyrB5|MӢ~0֥ʵٮ*߯҅t4uݯgv3G9A+<|\`Cc)5vɷ`47zD4TfA# sL& .ۇn!xplM6j?aH2Ǫ;G&?h)'N 4+Iˆӆ_߁֢6 8Z2lg}{cwčYהOh[K(:٬Q\Vܔa#VRq v] b!CS9$7VPWPS WyaNf +sM;]'zAWz)uQzɜ214|~va[t;84O n6'm$سh%@hn /2-AF1†aw .! l1kmb|c`S*=sPw @P,R%5RٓA@_g? \qi§t$O/ T8<)Nd`q|BDToB2'HH1ܒR5K$ зbq=]5*#_G!U^,w+-a q@1 (xT\P ͽxN&oJ2]C$P5pdgֺ *j O+zePـ9) kkW* Hd ,a 9DN ?ej$jM_LV/C'%@StyVRuƃl" "^TS7>VwShȜ_c7]+fy<t \e  wwls-s71+~Ok n1ѰDoW/Gn=yq TJb Jl(^BeX1HEPw":O!SEV/'cb%n!KE-u60xZ AI}uSD4vuJȐQhE ye|{f78I &B%],E1c5"Z C7$RsHzzA+mC C'U( bgTx'Qah/p z C9A,44 _v? ˘MnPHQ2%~8]60ʼ@ ڭ:JcbSL=LG6q1SY%s+v!Kp)SHeQ#:.e+|`*8J=jrOҭ">2(@"g yĻ )8]ަ. /4 `#@W^Ӻ L '<;e&BҢ^%eF#rШ]h MĽ2>+U(L)vJ-F>mCZ\X&|DTZdQ%#YGX3<2yg~do ==B2e0j 6#?lnerQ;8!"|""GCֳKxx◩i_?$w\9!`g:T  T؅Gё*??PqEacMIR兢a)RIԀ%jIn(w)~0_8\Ŗ;4 97XtJ`m[Nlbh3L,떘Y?זk_*BOSf[ ƅaŸݤf_ftLnLv߷t杻[X n^^5]D`۰LۼB$g :Cġ4[Hap 5J5ɻ)@}#F2J<4ptnq~/Oڈ_y.u _@^IM|!>T )}"/Ro) $,hCأaH,6IT4vpӅmڬGTS p9Z=* LV *fJ=:'ujg~ )?3k㥰 ȊREZ~Y},5VrA݌W#i 0BAK]rp$q%h ]^jhDO.Cګ9MD3xnCh)\֔*Cʥͩr ͤ"!ǜE_LbI"YIŵiRQ Qꘪ/:]vs;,I抢*qcLզ_lY5R}߶WEQ`*+)xdC;CcΒMbE(-p˭>\nUkҡA* $^AVa^džrgg)-o5d592/#*Xj2>6 )nޫ9 ꥠ1{56!Fk»'Y F@) ЛB,c0 @͑j$@K}ZLQE5#V7̠K.謁;J!LD*NxA7SXw5-asmzUϣt(Z=ǀmv>cTծȶȿVlꍏ$F EO,5GBkXH>0&%jպ Qe+fJxY@vh(ecdզrݭW֮,[82q_Q5Wd֜'W:=8Op-*9TE(q tij,qY@ZPؘuT^[LVmŤӟ/Uy=ݻY'[C ple$jFӘf#Jf3rm@A趑ڕE>JC 8Yh/g|$3jb"-fV-fkABs5TC· \,&@V+6}U|]6X[z!D6EoU|CŗÉ \\;DW9,ӏl良? 1 g xfsaxBN}9[uMYcua\)^BSׂL-{Wmı];c~c* F|Xx9*1>&Äz૕~ZG\/9L l{3߽#eM]2晡Fs1(br&iAksmI4Wy6ǏԥQîF-gP_xQ=KVzҿA{sߒ ^h0zwؤyzǨ10cŁo W濛y2P>϶jwU^h`Ug_%v*ͭՎ=ƵpE~NxN x[Ԭu;fEP˙ݾf>BNqzy,*o:CE.f@c5%láq8ڷв2abc RCPSWCC{;x8 ,!ñ,`² uQ|Q[Hws~Ť&d|~nhYQ]хjz%T׃N\Y\o&zӲ6,n3E[w" ~u fu;8eiTꬷ1&vᵇ|.V~s۞Q,92ζ֔Ϋl&jc߹=t`^EYZ >{RDؕ,EMCqGrD~3W;cDy`c!Z(6KH'R@M[Up 8~ٟ U,nW13AD$˛P_T H؁tl!d\itflx)Eqz4"﭂7/RX_YK I"#0,ˬ5{KpiJ/zaLw>dȣqSv"Uhtxuezū$CA*^۶n@O UR4J: dzƷ<4Sdն Y]:oz:m1z.1! p}r[dTdqad3cDחR OuUG&zjOZwU?U_ߚ}FS7ev+UPN`:u `(XQel^s@pߏ\0GrJ uZUd``zԕ]J,:A WK94q<Nz7TmP7lWt,ܪBxG!OU@s_AEA_/[Pr~8./kRgC?عdavϏ stY0o>?}rl'|[bߝˊ dluTvZge}~dfnG3|.9#O `]n5?"w&fBpMatrices/R2D961/orig0.graphf.gz010064400020550007177000000233360654525664700173510ustar00clevecompmath00000400000006]5orig0.graphf[뺎D5=Ksk@Qs#:v&ʖ3I8ǿuWW+~ZwuwWۻ3zo÷޿x; _[o7֛|o9>lߎ>#uS׿}3c Vq_y|x_??0nncynF>Ywjw~wOy}4w[#uϳ~8xO 硭;Zo12]~ߵ0'|Cε>^. ?dw.}=_z{i߿쳊a,7o]]Y5iw{/'P̿}l}%gĢ{ȏcvp)}K5U.x]Ժۭu}W7c-Kʯ^7uzyъW}m_gTTi^[SѲgg\7]yhejS7G w+E=޺.u4n= ޺:.ەhw55Ѻlԟwu :[-c_gS᳓Χq]/^77nBcz̓7e3@UeFҰfƸmOz؈ zWh6$)e#;?V_QZWJW٨y؊c5m* wj{ꥎJ*OGkx` zU-2jMNNfjt:oթƴM-w{ZOu;G\lAe~3~VZڧ7wX6BW=6uj>KIoW/51 oֿlC-]:ͦ=-Quв^kjYX1l/{WZ㧎n[^ڧӺ%j4hl XWнC-[;FћӶfSGٚ-@j՜/_e=6<4-еڿK}ۧm4'y:-eo8NB2 i}]}ޫ}r~پUop{9mٟi=WMa٭>9~Qo>"XcN;@g>;9'oNAa >cN[>}%>2bN-ܪ#`qLV6iam490+E\`o.B3C^$œSaao}lpa8l|'gഘ|1xj7vL~{[cedTyޘu=l>gamlx\NHʾ>KצbT pA~8_ތX䌝nu{N4~v۞EũNza_l}pT60HQApXxvWG5.[k= uLe+gF6-[NvЯp3 _3t'I.[%~6NۣY`N<#+Gxޤk5Dȶ1h`陳fcwm*ǁ{ހ|}g3`c6:jy{l_6n/I8ky"~x9n"X˓!`Dޔ ą~ . 5Psful@Rg1m~0Ǟn_~ 3FвHU]3_uFlNolKh |>f~"^c?Obm^P#V٤.7lox3@pDFDmf˾$"ڇ[eO i6nhb˸j>mlؔG7m'dw=ML$=%ژIrW2>6)p4W3d5a!d5f3osΡ [!Lz'u@~yp7tgGzd߈I+ںӊ6{ZJ .ӝp 2%iFHyc3#+ |BXAa0s( axj*#}qQơQ|kIfÂ$h_fmZNQg/mbC%Oxkܾ57Lb&j>~GRB"0ˀž=3aI/Ѷ䀐sa@@ ,)7EH<6,L{2< b+؊@WQ~A!1읯bƢF) ` {v@58't~lU\PnHP j+D8Àhr(/bM"aCM$-7;dxM${&2DԜSS jsz֦{=?gw0~ØyoE ]tX6 %-Ǟ x ׭V0{6VV=mܪ-Nq 9ؗƬ*$ t]>=T>=D:Jw``ڐ_Pl_~_V! Ptr>L61 a-q5@i$p 'RY6^.MLeڐLB4!Hf-ДOt"T${ִ*BZBI|xtpk}LziU T[6UL>_dmn`N696 4s%COAf29qar`T{ ]֚ؕ6Ko@ ocD n(L G5$q s,bj*gz<|zQa}CQ0\{8c [M( |ErjWH5qSĆֶ@8Q) 1FOv5%h_]@&Ah/zH5Cd-5owl6w<5q'dn![کy|c 9Ͼz!@\8?Z3du~9?!+bdBMΊ :yBl\zD)]0FU8/ iO=O<08Y$& #WN'IY, m@ok]sCv6}"f5^ ]U" ,((p"8)L pBFE3ȀБK@f2m!z 9=]N܉":Z5i e SM:㖘3X,<ÉXyǡxZ,ML粑ALZ2EVw3p,hndz{E7 jzY$32zm|TIe I& |5b(y?)4YL*;X~_?}k9}E{\*P/iATa$EuYh>InY>Iɒc9ctm D_xlf'@(PMjZP!([&|E\kEk~1myGz EuՉ=Dt-V0蟔lOF#Ky!Eǀ!~dpcr-;o,>(bOPs'rQ]#rn#f6l$NЎ[(lKutW?!dѝ~hհ2;MJ#3 jɋA@ns"s1U+iA(zW;4" g0~P?鉓 IgDa`_Ҙ_2v8$g,%[YSSt RP ׳)3ж$J2BbX !$J͞Lx&%YJۈTV(h6RcM)퓿8rDq(H ϼ4s#VJc|Ŋp`W0XjI6`:j !R|RT8ZcSkIZ/5Q z'k^v$+L%Oi ROV9??J s,Hs_{79: :ꮨdI YP 呰u)؅2g田{D-ogJ%sxk%KABik] 5 2'p?Y dN3@)WFњS4 c=ʈ4#*F6+so2:'(9R^eOJkO4x<*qUq<FnYnRFt*#ɢRdR܋pf꼔 ̆8[$)/X$|mɻ/;_;D2'('`,)Ҩtb6, !+)4*<.p51J@@J$D"L ;D΢hXH V(RL By2`CM$j`P!q.Crj$;7)Qɭʍ"J$(ʑfI`@\~QNOeWCC#[yZ d8t@R(ӥH׭ɂ0~J}5W~کڟ#DjL# O zk!z195\3Ћ/Ѵ\ "ͩcswk׈Z!ng^T~aWW@/ϱr00,E<|i?g/=HnR  YoQSt/CFL< a xғ>95|h9:͗l9xвtvQw=n^ao-|x.w-05TPTA,78wړcRDtNχF"SV ╙ dj/WC2o_]>?RS7qJo@; 3+gT|4ze( g[4tJKǏ5L?hiPo7eZX@quxچ&E2RUÆgA73iL=P: l~[6?hsK+@T55]eP5b5m-NSm `3|d$Д=_[V&O662zR#zyߓǸpfLMN$?)x. .ܱN2& 6afgq8%_Xb4[x/AGsBbVf)wޜRN<8O#4.?OJEhY #KB7(ܟLaQ?ٺAb7&LJ~XyʳYx~x>1H4~N"7_q$; }ped6+_™! Lb'}GP+2v(2[׎B rlnK\1Rǘl|T@8E77$fnx8T)C8k/"cUu#2$up,fԕQ=5$9m)d|w2\AyETYkz (2&H-~3w2K1xxLN |D6`ta\wkXAX~t'%o-F&8blVt!=K!ZU<Ig]j|EtC~ɓԑ0t"B} VK(s'bU$d} ۋvf2C_, "!j%+n}؀ѱuin귏P6w6'c˻H_"Dpnğo[Mm7jM~i.CKS^zhd2UX!aa}{*-v޳V#\"٪4*{({J/ 7RϾ`[rcK(–01tH["ż!M//KMZ ,*PX.J^ȴz-|E-c'輟cZҺQ+ tTA 3(q â6/ږcD"cTQBء_ KǢ2sf/ex%\.J!^=e+, #~'zeB؝+TS=6TĽIIⲒeA\P{#HzrGtޯC1K]6Я|KXS#Ͳ96C!vZ>SHKbWp ) V)Qב ^H܎0nFRv?2MJ*R"R0`w䐹x U@6RzP hn8߅嶛=}7U~n w쵙*ѯn9ZS. {㧼|y\`aɾVF $Lۧ|I'K|>螮9ԧԐ/|G Qyes0|Qn"Td<?n,O]*&V}gG<7hf2e~'ťM$Y ceb-ɖʫ,.ؤ=dɳe)B m 6)QCG ݀zr([sQ2K;lp/b9+#lURѽ"ۨz}QH^glOuOڱ^Ȋ^hPD#)1{9rbGIUMPxwRY6, ؕ9O+%(M=|^1W"r ?!p_H5=> ߊ#i[GpgVAVՐU1$ʓc'$ZIj_{dLj_lVkϖU2UqdQW^>V<&7w\u!Tt^nqAkMBqS'T܍2"+}3Ie& ԏUcLLϮ ,4Zb׸N*8cE+1xyurɲ|K\\N,W7/]#);P0JF\&HsKIoW/51 oֿlC-]:ͦ=-Quв^kjYX1l/{Matrices/GRD7x7/004275500020550007177000000000000663677706700146575ustar00clevecompmath00000400000006Matrices/GRD7x7/GRD7x7.coordsf.gz010064400020550007177000000003160653602325100176060ustar00clevecompmath00000400000006’4GRD7x7.coordsfA0 }(_U8#DN6Z̬\{ܮ}AzO_oHINW)]5$kf}vE?L-ͦX HINs Ca ):z6$ Q4_w]@=2K7"EMatrices/GRD7x7/AIJ1.inpmtxb.gz010064400020550007177000000065520654275707500173610ustar00clevecompmath00000400000006=ދ5AIJ1.inpmtxbŘy4G"SJ*[H%Q!zUtVZhC -Z-P(ҢZi\[$}7fcF{~s9oyyy)Bs!{!H a =qBb +rb / BP(1Pb0IB,S@M Lt! 1-1!艁1-9+C!0?s?sx@MV6V&'P Ԥj 5~t_+'UD8D>d>nd}9y^d&‹̧"su^d>nd}9y/2EZ"\[v#0/2E"|/27EFGsL"y"H"p#݄sַ^7/ _ӓ2|_t"&Cs+ ͇V5vW d<=JIɌ6EX,̞{;k~zWrj76UdDnm[n4 y]OMO`',EEr &_co8}u2'c=KZV`hJ7 .=*fAūe˱]c{>`ǹ/z=^Ȕ=Y5h}dȓuM˰^n:,Dօ zjE= ]q~w9V硾n#,io,!8aҝ~)gCMP2Г3"AQ`;3[9;ja$`h{z- {fwHg=Պ.3vԙ@;6mZ r۝Q+b}eE?2_fu'/ž!a~ ;,6~[7CBەrCs`.?}ړ%w]Wَ?^,f߭n07P*to{R98!׽> Ki[)\+h- Ş}1_[McQyvMp:ەAB]Y Wݡ[Xf~32|k-7&(\|#ᲮU꩓Ҷ;),kkҙ-N2)}ܶ̕Z_c3^ߟ~4p 22c_/Iڵ9N9q {8QsLi:  !_FG:Ki$>f3r6R")h?Ҡ{}j-D'=:zE \QVn>n2M!`FY.z#~ϐ">6s}>}ǭr4wr箺2ۢ-Ěq&srÖhGlk )/frvp#zGd툸X!&׷TTN+6ӊC8 cIʭ>;:X o%FJopg49 ȮQku׾ybێbˮ-ѼfD8c_?XWTDb5ӭ)& oѺUYV7=_Ph`']Z-=OAK# 'ck7cxxީgXy aYuP9g‡yГ_Jźf:qxNr%no1Ay Vdb|I}pI=o*0(XSGGme\>T6tHEޖ-φBCtPχ;].c/299t;!p;*ah[A E&[F&чT}t4= ~Gs?z4=Z]5YEtkt˛u8o/V׼0b{^?29ȷy &zyae@Y#S򖊕uݤAh;vȏ̍^NPyz8<,}͹5sGul8ݙRQ ^t06|ߔ?"v83Er~"m[KN=cs=PNa냪54tK߆+,ll `}ETm0ۨt^ejuam%rӃU<+ԾZo>p ދ.?"2Oߐܠ89 eGɴm+#+qK W˪Rxu(AI.ߓGo-~92Ϸݸ70,8-1kʃLP95=u?3v$oCu\vo@)j>Y킓41sPԃօ$m\nBd]V][-3.H7NhȕirΨFnc.CVAVy3_GDgt oi:]mQnSvKӇcou?MRаcXd O MgHUCvpc2X8:/-ߖ|Z!'>)KL㿐`)- &m; | B"b $< xB AC z z z ޟ0%"& _‰`-уу$?iMatrices/GRD7x7/AIJ1.raw.gz010064400020550007177000000112520654275707600164630ustar00clevecompmath00000400000006>ދ5AIJ1.rawɎdGrE <4 Hf %* 5zs{dZR+Hyӟ [y+[?]1be˻pF^Kj!(`ӏ]~-g5'\Z)rtr19 ظޭAמJ9c̻G'{9'رVcqLg3`͚z˼nn;`X΂gƺa0B`#gl^gRx,ٺE|'F!\+V)z p}ʻkL=Tn~1cv1_6ҺH 3H0*?7: #]ﴒGqVgJŜnQΘ=Zv_PbO}Ę_>uwP<ʺ9ް̐ge}P#ŰM+5 o;4خBIR#}y7 Hiռ+S33V8I -ӲY1V^$A Q={ywPr9c;k|n[vS|"3_| b: 7ϢyNH^<9I$lg[g3C?!%`$~!>>{rz!Rœgj0z^<װX8G>Z(@[4ZDAEXl]0E`i#'FDaopwPfbRYYbQ(dVnoؤ9^*;Fh }1ecvjL|#q<sߨ ]v/1千G4 %= {}-ر|2)Q !Gabv175Xԟe$no6uUDb4C_%P(ԗ3V(X̱ʹ%oLP fIުHDIlmk˲W6ؤ}.|*E;7]u w7XzϜ^GqFA4:\6AYc;cqځ&6rƪK4{Ԁ~ m?cM0y 6]zR:Lj!U0y\ ce(lbh'Q|Jo{0KCD=y+KH_qFrXIG.TEIyL9!آ;c8CgKqp0z(,}H86ث1X"Qύ(rٺ 3nulo{GbXzU16}Wgi&dr1d[F o۴^ %9CS4< LH_ -1v^73FQl]?75WN%s oؤy25!sYlfS Oվf V P>$MqhJ kH՞yB%3VS$Gؤw3}b:RW,C@aH>kS n<~]~WGzB޾+grSTk2mG-'i?j~Nr,͠}i>zB?]mX垼XlY(Sչn]<\]f <*0(sj`6o}#;Jʠ_X>| `sX6rdMznQ5)j?JZ Kub5.o:/-Jڟ,L3V}0T;[tAnYak2U>IT,rVDg)sCSʣNRC`%;T<`!dz%sqYy|,{ 4N{ݡjj]mwiUWLS&YXl r8?Xy2MXl%QHyj?J(WCbGlQ0!=xno3A7|bz<̣<(Zp"gf+Cԡs%Cy4HD$?bSd:2ڄq gảՑ?!)~.uR[,Nw,VgF~ObžTC({,Z^f f^QʍX=!3D]+<4ro]ӞBc} V\#|}"|-X`5a۹}(G^j} 'XWG?(q O bE/Who?iSeSZ wHxOElTh؊L<n=!a l`I :>bŋ dxd]IqאN7lO@*ߢud UطTe"O1d)C;7h]( *Z!Gʁ$}vChrU7sb~<>gy(|.y9`247cʣs$;U=TYw,O:R*i1z(iAUB`dAF[ !%z>UN+cGţ5c<9gQRءC,p>-V{WWFHz}a:'=ZR0bPSoc\Xlj lدy%^wҐb'ؾmr2!ͤ[X-Z~n+i> }Lcܧ|In 3WQZPXQ][ 2<9\Ŋ}ws [{([ K$kQ䛩2~jOW  ʣP7R]& X=cMK=~5E.ds&UL v0XCP[﫯>|_^^aW͇yd|"B?.}~_7c/[ ܖD/@ٺ 3nulo{GbXzU16}Wgi&dr1d[F o۴^ %9CS4< LH_ -1v^73FQl]?75WN%s oؤy25!sYlfS Oվf V P>$MqhJ kH՞yB%3VS$Gؤw3}b:RW,C@aH>kS n<~]~WGzB޾+grSTk2mG-'i?j~Nr,Matrices/GRD7x7/AIJ2.inpmtxb.gz010064400020550007177000000141150654275707600173550ustar00clevecompmath00000400000006>ދ5AIJ2.inpmtxbŚy8-D%]TΊ($iAZ$p+K) )P:d̘1f1hyy~f?|_uy ru&ApfL$Ii : LIi 9 Ny`4X0 R = NihNIX< Ki ? Mi|VLi8 4PVO$IИ7Ow@g ڬ mmMt&4A3AMx׿&KNQ+ϟ;E<x)׿&NL/"ϗ"ϗlT|_`|O _1޹tY׻)YH%+cQ}W4Ҹhn'-%Cgd(Uj#RH ;ti;~ޯ Rj`ݾ lNm^::dLO 4>+kDM9Ю^d3y/!]NTD,sۊW =(nC8Fj"mʛ#:Ps)y:ߌj݂ '(H׻p:@1պ:MP¹1 #=2o@SӖ=o [w&`L͐f[%5 ƚ$-eZվ<]Ʈ^uXeHr[.Nؚ?rGػ=MW805rȌ&N3Qq_*2Bƌ`s+z@RPCkD/6dh7`Ϙa`Ҿq!@UMG)h[wfrܲ^}E E[u{5 鴁CԀ*eON ~γ Z|-R''dWXYJ_=ڃcJ$U}xQ8w>Ɩ g1nR|!&ϏIAF٣#HVl D.ґ21D[rޱ:ЛVj4 2,)@IWx}ƣzeN@a✄LGm3îd;W)lV.wًP隿rފ ؜'ᑥފ-+jf 0<'{P2'>p) 7^12{Z= #۷#cهπkPc :+c%78ݬ{( [Ia#wȋy@JևzD6rYHE9frڶiBUCi̐4cY;#O~5昸~6fHw SvQo "_l,rO42=ZqkQQ5!!"AEI`/U(85Pp"?ƴL>nmYv=I}2.lWTZFs8g.M_ FaPf.Zt9d-Z-tƺdcA߿C€_:V͠k/kj|$nZ̝ϪmDz"%s味~`"Ahf i6'Aa xΏ)ÆhDaoCol]#AoOW JZD`Rݖ/܊<%d.Nt4i6WP=ѐ槽Jo$u tt/{]_`mqJ"%T0CbA75bE55@0p`>26[/ yƱ+򐖣!`e W> igBE_IB;5tӯ/zш*R.Vhv̌wjzt k *7.Dm/P?GOv)Y_.3piaػ` tcW%m FB䈻}Z`7~Yl>bK&溷guRx`d?R )H=[F cHy#NzfgSG6bO.n&+bv@lܦkhk;cxģ™Sн$7#Oj3ƏdY|q#vGs$pԞY\tAf7-h f-2^9~\U· KDH^v$NGZƁ@r~RX.#I @Un׫yy"'ntpFm`߾qF4g8@w S {^]]<ː-O_ ˯~2hHrYR¡m̅fe*#ua@ʉu7?5 MBUOD%㤛gaez;KX5 ͛K Ñ>u83LHZ#DFm`mj'߬(C%ḤuhڏhF}`>5P ~uɻб8`xɎg/tNs?Xhkn-:^iroMDeqwBܰ)̈́4B䴹ǖ}$_F#57{P\IuH ?׸+ao)P_ku68v7mg=ű/s|v|`Ϭ\)C;wZ:$ ;vZ3ooOZ{`ɢOm*Ro|_rgSkAg-0ª/UEHH=5wʳ{wpYSjVvwq^y,*(Nu-Ik*)’˗**44Ɠ""sj3}_`kT~~CRn]7 UG빿붽8CMV.G(A8 ZnϋX ;[F^ǾvJ^d?kM[DsHqIaCc@(MѲYw᩷͝bJ1|?~nǖV#/ܠzOH쑾i }[JM`sBdisiez-Ő'"}'d .7).rҼnބ|".':-}!-j<Hm^]_?$dJe$`˯YNt@+ {T[>Κ#vW@,,6Fom|?TۃLJ*2B 9sq'R/ ZDPv(0511 ^vmIv/^\I7Ȳ)!|u/|>Tu=>-IP(fi{…lOQBgBQU V]:ꋄSO%8HeH]|y֫2}bMqŢ,LQ\rXo vn8:2\Qay@lw 4}<ayF]#Q*]PuoU|%,J'hu ^dB[ aP+Vk _t bZ8IlOe0REWIeŸ9YX3BjRw:(8@%U 5}W:+Vp.D6v%lw_h 8W*_O?*hByߐ1jK 䓟aݟ x'HUUdRchoKۺQ=g9nWzg#UmD4_j'(U{T9Vir?zFO Pգ^H^2pAWԟjT4BԦXpm1 Z-+g^̀U,m7Xk @>xFo%Z$Es7zl;|s"UM PNwz>zNнRV3,=W7$};BM] y+JB`gL\щ+R#%Go:&| {lTJqN,f,?Mڽ5ȢPy# J?6hÐzX,_o@}R$-}7x}K+Z$A1ZR$q֫ٿCcH0rbd$cа҃pS(XK/T΂AilNKG,LЛF>$ +;͹gb]ˣA'1ժfhbmPȇf!%g̰T| ż^ũ_reZmR.p26 |j@'YPp2zR+_935VzRs`ƭ зX:dR&@+)ho.{|V/PiKxgtb^Z)_X6J@kc^Kذ=5vAԟ?9\^Z֔oTˠs>, OH2BhaS3IoU-gbuJ~.nN²1u*x}$v"E֥D|*??ׂ"1cl([X(*wP@ P Q_kSԴ o/zmS1l͌!l[xl{C}z5=lN:ڜwؙﯲZ s9VoL }b,#ݐtj;O#&rqΟc,3+'P}WՏf#쑯 (Bo`k5?#y!kv P/UVf_S(R}mqBh:x=mb LFr ȱ)IRFߑPU̿n@*t R =)!Qd-Y;zBr}Z=G }qTk֟5_VDSCգzދ5AIJ2.raw}iv8U TÂ_SNW:#)C e-߿ƈ!YJK_}jI-6{r qZc'c :OQ.g~\{*;w3{yXhs깂s_cqL=.?6k-1V6_l״ bc_~FƧY@ qck71~M lD0@u6 B0as@8R-46؃q o:f| /Kua3:0s/ rq0TrfzPsa-qMPbO}Ę 0? vacjiVRy KLj-Δ|dQXp[Kqffc ΏYs%=&,]'I,ڃCy#0>F4cY%`6S\n׉APXV5N4 0&ktRybb |B䳜Sh2=ǜL!VP`q!&b`d11<{/E$HYGpٙx@\X ma i8v&ֆxMKOq-]h6@> `mZ`['@5]"1Q  d# a 3k)Y^δ=i:#e:h'#$} :tzcvg!œ1 UGpf2,6fyLyʂ ?3֑~˝'l r(`D~HbL`\T }iE݈Q&n(nr8O U`ިUu1nfM?O~&> y{)8~d lY,i;,Spʦq!N}Fe׆0Uq?\ WәƏyR"|BQM p3Xb.iC`d~"% U?sXS <;$պ*Q?h_z+;݈ @Z(EƑ[r@^8ĜB"=F=Q+:u2dR,  Vlj" pInH }*X\D5접H]8uaᬮ:`ۙHijH<1}"'&?+T$<;΅8ɡd@1P}W<rHH\1xAS;(R8R Мβe*XyQ5Ӡ`ۙ\S0RyEp ew)D[!£YtyZLZ1F* W4B},qY?PҏDeYzV;W SR%Ƒmp)YLF;OLH-g^,%=~B'u##!!r KeH]7'`#/ĞJ{4ԢY_? Q {|L2P-V!  }YO!kVC*W8 ],T_@}WT@6YuH!HzBFğ[d4ySXpfxrO1M !˧ԟa(Dí!ޙK[$ rЬ ` /K^MMN<ŷxhH|m`~ @ql$c":ҚN6ʨH0 uӼkH (R@|mKWvK$YF܈ Kz %AH9T~6Cmb>9WZmRfSOf\$X߃djB*ú2]lxlo9>SYَ@; T-bOtDO*UKy98ݔ+81:Ÿ,`gq UW۶ _JJ]ځ66zJ<):1)Nܰ<M*5Sz0fLg1Y# j>C(#֠ Mi@I,lbЋ=C[Pp$0 ݥ/T5#f; BIdOwզ*dPpxZn6e辺#QMWHsWTm;`Cuq\!=}& [?S4$Z,Nyɻai͢1t8eFDЈ@7WѨ{եxegpA]}o.ʄjkk$ivr`NK,Y8zq OuݧVp`* u*HAǙȅ5SPL*,EPv7g"9-X4 VqIc!kTYN!)'WF; L]'R:>xwj+|Ng.!8]g\jU)UO!e?I0ȕtZ  Q62d@vv]RcuTjHgRy =T@yHrёZP,|;B=RFD#´PȪ:<lj<>fT:S UB+:-B#Vnc׍ɰX~&<47SUC>.aspDt맴 ʳ';S{S}L.'#HQdS0$9ɵX6QzQY,'zUD|yh9^]_`=WpMqEuؐ'$٤ʾ Jse,#x8wީC]{ dfUZw ēvui%E mjύ5%]ep)D3|pWjgéz6IX3Uu+^SɁf0A/lEsزctc=BÕE.j{ZP-=nӺ tQ*V,I=]dR-Z%S k+~ C>Dy Lskqyej/پLdXQxcZjs"b xx:3,;'UiM4Y3@_{@bS@9o%L5kәM@~C2wP:$5˱ÈvKqm`N_poC3jSbT;׼mOghfő@5hibU[H}Q覚+@6IY 5 M &v=@gdƢZ/²j-;%c )'9C#es^999p;W)Y7W.BXZ{ՍN)Q4|IDkwHj X>XUdgKBr<,/7yP*nrJa҄{ۙf'ؔVUs)Q Q 8'D]g&<Ƈ`Sq5O4 awbY+IeDp:cHJRTJz.U%]s -i=PJV:wTAfT%:UHP楤kKjgRÀG=@p_ͫpШW>nw'#, Q6O6*)m(WĔĭKn&HRׄkTj).'bŲq^? 'xQ̮K(!O뜘Qu0ogf9[ޕ4!A ;ҤUJj٦~/*@=Q[`e %M]w/1 K(eT~=scvZ5&]Mwt` I +pQѓΉ(`lSLܓ08hWlِն,$EBMP,HGw&=T31>¡Ė+5  $Ȼɽ)r #.`U[gWx(ct]zg=ת8dr M4gn5l\4W=j$oUukv3hT鉺-ҕ4vls  GTŢ1_FO^:Z=>+VawxV 2`R1\lXT{sOŒ596@7fI6r0,Y]hf晦jMl\ce);ciyFV!;u5b_q.&rlm#k2n]d 5fJ.q<70hJ  QvWV)獄i̓<\SKݏ0Zw!RӾ8?5Kbk&`=SP۩ ?5QeGpFTT I:XO8o{>E,V0zJЄM,V&O%Q_q*S3;yF6&%nE-pP%h1nCHTxb8kNDުn( ]?Ks%Q"MQ׻6 +>vii6̣9E(4J(ZmT2 4dzShVJDUWKcvx8QyDS 7Qv8b0u Esf;TDK:Ζv0-wV={,HY3aDvZ}*+2PX~:un!:1U/9ϋ& 4 %=ਙ28@a],I +,I*z]H,NoC.\[kL+j/E\qjXw&ec1宋f|-@I)`a;6_/X*NKK4LiPE,qFe`X4Ҫk174촭IN]㹂A 2y*Y/݄ջnm (`}E(Z\DԊoW5⸲Su }M*}IPs{i&Mqf4\ [o G3"9pr; `WEBe)ل8xRD<^s(J,誶Gul8[#[Matrices/GRD7x7/AIJ.raw.gz010064400020550007177000000014740654275707500164060ustar00clevecompmath00000400000006=ދ5AIJ.rawum$A ѻ "Cm7IxX ݕտy߿t68u2Gs:?g<|Hp:s+<|Hp9o1#>  >Ϗs8_# 8[y$A\̋W88([yoogϽN[ H>L:*̋3)|G@rN칓-U\έ%wrh| .ʵysn񥁷q#7sʫGnp8Gn.nq|s+`] :-s:?V%x;{ ӹ[|=waNKR|-2/2&*`o$:?1#:?V#>rog9^M\1;Gpǟ},l_I! ~s$ {`Matrices/GRD7x7/nd.permf.gz010064400020550007177000000002540654275736100167150ustar00clevecompmath00000400000006q3nd.permf- 0 ;Gi;= 0ĒkTAnI6.wM~ I/iWF Lо&{SA9{P\a {8 c%0z2 Hd@X甌 6qil9?OMatrices/GRD7x7/AIJ0.inpmtxb.gz010064400020550007177000000010300654275707500173420ustar00clevecompmath00000400000006=ދ5AIJ0.inpmtxbŖ)LQRmZ+ "!AP ŢPX,EX,ߦ? /;qlb{v$ Id.ХQ*t+"zz9w0 `PaHaAAAQ1q&L9(;VQu0栮0`eU5u M .QZVD[AQ//?WEo%Á|4ō؍Kb>ax14O^ˆ7c7/͋żbx1^kzżax1o^ /K7c71͋|bax14oi>ַ֫_K59w伐3ς=\OxM\:&kw|&ωzڙ:'Gޅw֤ !8 Kp w}}8Ἔ ^>9Gӹ[Gy+`<|H HQ o~:?(gyp8/[y{ch ^[y \9˹s6ӹ |=wpy;9{ IQ# :?e^䭼™A\# x;98_7l:?7N:rϹGn^ :-s:?V x;{ .trNVf@qfQ9oe^yL9o<s:?gϝ| h| NrnDGnp9o칓D1^#7x;칓D1>Vx;Ξ;Ds9o:{Qu弝 ^=wqh| NrnD1<Ky$3 :92/Q㠎s+/ UP^WyH~;&9)`׾$9 E7>s`0t"N]~AGLWc0C5Fj|C)f0p5TFEMR3 g `[55@HL`2ŎB8PRQSͧw7M~i]jCQ{xn9xa#3OKxǝ})anߺ8Y״e_FT`֔j߄ ?,62 6]٘4~"q֖bU㪡hQ#TN= a]?^\ 땦EP4 cp+XTb?&tyrF#mL`m\.JṜ`6bGe7gBw9(,c:,BғQ aD~}MJq0lVmd4o1X'ކ]noLa= 3w KnX>2+~` ^':Ax$>ncx {lyhy7^2]i,x4>>g :> x;VƁkY7_g Q@*xB?R7> }j 'RF2@v9(De}ƳĹsT ONq)}~w|eGErЈHЛJ-oƚU*y17j9*I+Y-?3'yLn-iJBG x.8GEɻLh\^ׇr˭<=gEOWeCEC--,v$?!{z@'b,A9\|7]VPcrG7$  6x۷`<ӛ̘%" Uhh=k&yfPRv TzeeŠx1P"ڷ1e?.1 WeZ02b:dd/ELty@r0v{Q\IjʭɛX7vdT\DZ>+S@u÷)zfS?Xb%I4v(M52WX\VM.E:(v?t_6;WٲQxU7i|hPmݷ7bkNacH|:6:5We?rTTjceHnQQ4:*K3V#?wàvT.G\ފs.д"Fd~x>:-ׇ[ݧ82?2̜G6ᥗ3v]?f5Ӑ b`}fL@4J>|__=[*2p9.nF=5ه"GIBF6}(Ӟ-S &<+ g1 f#Gqq^,1*7/gNQ_bG|fuν9.tn`5=E˱SZv:oSnIV[x삔 j[fƓ3O IiW=:BkfF]:MMkOkM'*n=?[L]j8zGK8UQGu|15NKe?tB.΄ 1`> XK# DL&"("H$Dq8E!%n"6(# >QITBUyƞB!dg*{}.Nn)r+e_5oޖK([8r娇-W=-=$YcJcjըGբGŏ=%=@֤HRҶnm\Q~MuncF֣FӣUn3Qm=Fm+V#Džoq(?/80P0)R24A5H5&qɀp $7‹L%"B:UH}P2\Br & 2R4$&uMH^ roȈĸ)HИ Olf6A䞛d&mAHj(@,lYZ"l(B"h@X!jf`$!hKD$" BTIĊ^%!iBMH 4,ƁJ֔?,]?K ID0LIfiBJ?p.'"YZD!A8!ԋ4B"di IdiaidI" $x4"Ì I#Yr/3݊4!qi( "I˸Vb!* a" BHf D8N" "D<!a"Ý4'Zz'D:J_ĈC n~WJ5 ^]!T*CxA4D)!$,PA  "\1DK KWID.aUGh_ Bp&W2o2֪aHa)E d* BH:ΥBqBnY4BdLu"1*cVӰ4be2!$!4bHf4%#w?FL(1!$,5DLI3X'!DN K7Br+ӰWETLC($RZ 3w54I6@GɤIITf&-Yi}#dɼK_iqFzL,A.04bEL)ժYCV2nG2dlۥE"=E² ^z$A"]yEmfCaE$?!$R䄐0M i.bB$a԰j^۱j a9z)2Rt!K'b"<"' .rBd-:!"^X]䣯n4!sݐ!:DL 5A3>A dQC4,!uHQHXf!"FH" Dci^P2iBcN>"F/"#~ĐnHrWe4,IiB?A˜NJN@)yb" 8LiEnEHhLSZapFՀ%Ż4'!"+VdJqR"1i٠,aيA2k0,N!dJ)EDdbॐAkl(zc"jaᨎ"AkBAQLFܱ,'̀i}EaIUF3RfAT PEȀF,ɒRD.a%dfXR@ a%SBcEdƁ e%ʸ$:S$+eX> qߗ4 ! akFd'B ܔ,Kj& QP& *R-RxIJ#RIiҜFUyijѾ',-4['mY8oJƲ Xzi0i"ΦbѴK6Mx.p߱]+FSv}4K}tb%mmW\;$)7}4͛"ew<\ɞX;O5{nKW.*^#J>fɠN_wOI2{E"TW%?Y˶LU<4UwwbY{RE䡪:>۷KUK7C`${Mv]T{fa3ͻ*gHxypDhi;bKJUG&S f(/*!xWC԰ݪ?-҉we*'=>T7;.S.HiezMy%;^{9auQ5~ztvVBtDגTgmlKUR'#:gQUgͯPwڝ.uI͹Ш,-{+ymDPTkՇ#xFfRUyyB9Q9dn^;qNL8mH*k4wↇP'CӇ~w&5,:pRiЇ6A%Φ_!o_ߨtUݼK6T|*HT}ΒKkO͔ݝhNsQ=w9] :/tXPaG{5~ϼ4Rowet_4GK]NʇՎ},te'CC{vc#u>wrc&$Dv)Qw R_#$72fq˻T]gGTUa"4+!]jjN |i7ϫ7<&TS_,|c%jGg>O%Ѳn8/aSR5PN;Ư)?K}rӻCN;9nJ O<6z'҉G)#1MOtVIlL2-)#0D*} Myr׾K* _މWJSi:ema塺BRD/īIWKQtyYX꣝Ѕ6[>>,]yftT`^^Cơ/cGQ9Z!D5}'j pvЛWN7_mЎPڙ6]o2XpA7> 갩\OWm0S0rDPage~[T.2hN;- 5Z`ԭ*h-{my0 ;X:#`^\0mKQ76S?1A/nދal(hܼȡX>ӈYll3 Kՠ:̗hͼh >L3kh0ZՆYO\\:|9vrVE0^OSjK)ًi^,X4#atEUA+ 7j>L;h0Jiÿ(|Z[{khx&A~?|L%xe~﫾& )T]nhȹcJ{/)1%w=ٮJ:xO?p=GB;PNz{B;jQsYIQ֣?ZWEp+*史6WFGZᗊWŴA\4scǝ&DJx/ȳŲ,IFZzLebx؀]19mS>a^W$/\ނӃ sP3/%拒;!h@A=  K^[ԳCu#9 ?r7d4˒C}h6lwv(ňS2<nc3g1[ #‰̧^bU'0.JȌSl+M=y.%'c sT(RɬFFl 0Gۏm' 2sJW$QTpI.4H[HN2r6r1n7.Sn҃L6WK;rC[g[CRGr5imp$HF=SXbș>i{ZpCϩfeN;}(en5UJO]2=;Ij Ko0v44v '"^ "Q]%ptC6lL_Ѐ րA=*{;oHdwȭdGcOcn.pC2w?,C_D8 PذSqipJFVAM[DsdgcGcͮ02\V`'U[ E.Ģkejim?&2wG,:ܝHOtk&sg Ǎʎ.0Ltˤd?R%ߥT=-E67ĺRwُ9AJ%e)ՇLNyv1A_K)UĀ c?+#9ܱZŭar_]H rJ9؇b.#g#ǽ lv59 O)pR ]P_ҲE^Ӽ%' 07|a]هs̬WpN'Ȟ;elhr%,`K/6g6ϯ_ [g/{OoLN+,Ý\^Ǝw+W:NF-`gf{mPmJ^w>.eeΏπjlݲ^F!73$?]b?"|A_b?Vܟ'RJI}UJ'Fe~D?ɽur'rN_Hd_؛\'j"po` 2rbP6W!]gX[}¾iA2p^]Ґ=Ɏke] >G>Mwh:%Vs8<λo_}$/pCv1v2Ven$Ksew{&/u0>{Qc>Di?ꂐoY;Fnܛs{!zF>,tCed`@e?N~NSH۞G2u'$/h Re8}`pv?0Q3h)LKa`FPUPmdߌ25>$o̺'S1};,z3u!g<oTECۮl p3R+c8ZGr4vlfbS,IYP>^ɡ+u=T&}+V O_=cI|őo;35^.!zhXD nǴO$?tr■ ׮:2eHBUwLaX ͊XSȞBH:wMatrices/GRD15x15x15/orig0.graphf.gz010064400020550007177000001575160654276113000201710ustar00clevecompmath00000400000006X5orig0.graphfm#;V%olHP$yt~EOeL9P!m;y?'^G䧧?0S_2n-5%O^{/ K?OOHu#F;~Jju=N?0ݿs87?Ā2oz?y-v߀ZK߀s^}ee7f? +@2 lP'_V7dws߀G//nP؟cؠO7~G<Ï@7OPnPٙƿPO_~Gꗩw{Pǯ龜z|X;>/k'k#{/ߋ/u9yC[K Nck_L{]Lv|4wA.|{sGS6F}$_mopÔkw韷oQ/<㖷YLl7\gxn+w3M/87 nOL/syڽvr7_x7{i;1_|J{>ߋO6׾sp#kO 1 ׾Xo|9 o[ތK܉'{1=@ozy;1tA8t܉ϖgw]v n3_mv7bw!{swf_]zs|܅KJԝ/ ۻ{s7"_mvKg#k{nrΊz#拯]ʵ[\:;1_|wat{[ŗas~{񊯻ˏ67c/nވ;1_pw!Jkt7"]p۷avKg#[܅avKgs'~o|m߅[zgUgp'o.,nqak!|`܅-.^x۾ ˵[\:1_{׻mXYXo|gx"ߋu׏}#~/ߌ׏Db{/-vߏ׏y?˷}wdtǾ%ۛo|qޗ^|맿5n]rPys[\7g|h_?=Qr-^-ʷٖ6탻\zwiz;镨#oreߨ-ͽ/Ge寗}˷or7_/-oqCݴ%ݴ`k-^/EͰeux }~l}]X2^ݛZH Fsytpqy^!b WM\l靝\2} q/ Dm{+ [\i݌|C}37ÖޥЯK^o.E9.!f}]2lqշv^ߚ [xwwI̛5_/9^ۋs";{$ym-H9tn o|$KrKf%ɶWfIP.;_ W|56v_odo˼˅ͼSPx|I{#%۾$ymmI9KǾI{3>7c%ɖ>9@MIчu@̀G@IO-$|;J-}(o@I? @M 'AIه1^HI^s$[)= J-}b HȘ%v~aXj굿fh  _{7 (Ij>&OJIPlmo̞%v 5rq$(Ieo  'AI]os$t$ٮM (I^$ٮAPnooJu M]u$It'AI^=bP--Ɠ&y Hi E0x%ԥ74{Uw3= ^&&!Y AP @Itΐu5ɖ6'AI^=~VJx$)aNuڃ`?i< Jio_zII;%$ʟs%+A;JOZy@Luʕ%'roo)Wv$tn}M:IPAII;x&yI@7vI_^4i^ uW? >飣:=Mr+A;JOZy@Luɕ%'roo%Wv$tnMIPAII;x&y]I@_II;1bPeNv~c|sd$(I>i7Aj$x$$(I>i77Ix40%' (I^w&AII;$yb@Lvf%hAIAI>ioVv${8@7vIyӀ/À1'>9u/zl0 JOAP:Mvf%hAI %'J MMI;$y MI;u$s&t${|ҷqSOǓ&y؃#%IPA7ҋ֘%$ד&`$%'9IPJV~$yȕ%g4{Sw_0|}Ü9 J$r1IP_s$&AI~ɕ%'< &AI~ɕ%'rooK (I>&A%'AN|}|o 7=8I&ۻ$(I>i7cI_!N֘%' & p$$y @7 Jnb9 ?~Ct7uSc7uZMO( K^lA,n63n-v2n!u]#WwqG Ћz囯 x!w/`~~~ ϸx<髢9g#u^9'羗^9'l4?˥tU5Oڕk\>qהO|^|=ݤiB}6^Ϙ=d=4]=d=Deӥ]/<~Ư^FO:Y8իWsv^zNcNc#O֓N߫?Ү<\HϪ a>moO\;?W\k"O!ZrIX U>X=&e\ݳݓU&\G!y7mHk? ֓g'Io쟫{dzr|9Ju> 1j?>铚\+?楧9Io'{dto~tBx ͚%=>:ٳ_ גCpAzN!&oy^FOOz,Q>j ޒV8ZUc|*IDž ~%'}N6}U? 9,C}6%N<+h.NǪ?=jIƌFqɿS7q=kMOg,]}Lɚ%eރj V ,LJ\@.tdfr󧈭\?xQov,c{zTۣ@.w;8iR`/|5K=}sr ~YL@揯 T9)h?}z5?9m O>Pk {X~|{z65K=kcρ}}V%N9zՔuh'r):WCj({zחg2RԍM ${Ώn {Bu7gOl\ Gx |$~Z> {/>|c 6YC<{H5D`&=/rʏ[#*|`  f2#'-"+` |83ꃞ@R R@LHk0rz6*4Ŋ,'r.'/>@ ?ЃLV#-qs,b˪ķh_##4*DWmY o=bPќ$+I|  =tHS5ѥĞ4c|-֘ӣeƞ1|n~O~Fu)'ĮdM|`Za-G4'bּjDi?W7%k{i?'.%ܡ&7o=f:=\ufvC Rd\]aݞ`k~"{%Nxrx0U+=ݻxxeR= z#0eA^icEZ(%)V"zyX=y}ٚrbQ:1Gz)Gh5^ǒ)`/Uo$vp4e+LWF5K=m> @bMotE\ b=o|eR=+B/5K=ݨǪ =pmzB{zxo1v}B{Z*Dz2/_IYs0Nʑ7h[*U{DUX׳PšN[C7*zCϕBrViq0JzRh<ΞTOFVL Txz[((v?Q4o=#&r>|, B{HHhTjXHӡ9UVb(-e9voP i/ŃXxńRh$- co!h(J;'S 0G,&B;-( 5Q`WHs?Lń#* ĆڂQV=i-J#Hby'IJ#MRz- ZHD-Lb1:hLh$T"Ti-ZR6i&@H4J AK섑)b1[(oF/P:JAK#( Ze Б^UuzL(J};|Yk C Б3T$"a0ґ(Z&P\8yH_Wi@CGu-RvGJXj8JV".%Dr&@@T:˒Z*XL(D X"i Dish Бw᱀ńR r"_; yJɄ\%0 Б[HD70QC')f1:hI2*y(;f1HocJ-)ciHZ&B-)~Yd',ɾ隡 4`StK'|L